From f5f7c20eed01072fbb1960c2002906e28faca908 Mon Sep 17 00:00:00 2001 From: Angelelz Date: Wed, 10 Jan 2024 19:25:21 -0500 Subject: [PATCH 001/492] Postgres-js: Added json and jsonb to the list of bypassed types on postgres.js driver --- drizzle-orm/src/postgres-js/driver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index ae1b48a21..2b2523e25 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -23,7 +23,7 @@ export function drizzle = Record val; // Override postgres.js default date parsers: https://github.com/porsager/postgres/discussions/761 - for (const type of ['1184', '1082', '1083', '1114']) { + for (const type of ['1184', '1082', '1083', '1114', '114', '3802']) { client.options.parsers[type as any] = transparentParser; client.options.serializers[type as any] = transparentParser; } From fcc8be7d8b27ea9a9299c3bdc24d31c53968c2e9 Mon Sep 17 00:00:00 2001 From: Angelelz Date: Wed, 10 Jan 2024 19:26:29 -0500 Subject: [PATCH 002/492] [Pg] Added simple tests to pg and postgres-js integration tests for json and jsonb columns --- integration-tests/tests/pg.test.ts | 37 +++++++++++++++++++++ integration-tests/tests/postgres.js.test.ts | 37 +++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/integration-tests/tests/pg.test.ts b/integration-tests/tests/pg.test.ts index 3b31d7d60..e88a01833 100644 --- a/integration-tests/tests/pg.test.ts +++ b/integration-tests/tests/pg.test.ts @@ -49,6 +49,7 @@ import { intersect, intersectAll, interval, + json, jsonb, macaddr, macaddr8, @@ -2839,6 +2840,42 @@ test.serial('test mode string for timestamp with timezone in different timezone' await db.execute(sql`drop table if exists ${table}`); }); +test.serial('proper json and jsonb handling', async (t) => { + const { db } = t.context; + + const jsonTable = pgTable('json_table', { + json: json('json').$type<{ name: string; age: number }>(), + jsonb: jsonb('jsonb').$type<{ name: string; age: number }>(), + }); + + await db.execute(sql`drop table if exists ${jsonTable}`); + + db.execute(sql`create table ${jsonTable} (json json, jsonb jsonb)`); + + await db.insert(jsonTable).values({ json: { name: 'Tom', age: 75 }, jsonb: { name: 'Pete', age: 23 } }); + + const result = await db.select().from(jsonTable); + + const justNames = await db.select({ + name1: sql`${jsonTable.json}->>'name'`.as('name1'), + name2: sql`${jsonTable.jsonb}->>'name'`.as('name2'), + }).from(jsonTable); + + t.deepEqual(result, [ + { + json: { name: 'Tom', age: 75 }, + jsonb: { name: 'Pete', age: 23 }, + }, + ]); + + t.deepEqual(justNames, [ + { + name1: 'Tom', + name2: 'Pete', + }, + ]); +}); + test.serial('orderBy with aliased column', (t) => { const { db } = t.context; diff --git a/integration-tests/tests/postgres.js.test.ts b/integration-tests/tests/postgres.js.test.ts index 0fd0c45ea..d23b294b4 100644 --- a/integration-tests/tests/postgres.js.test.ts +++ b/integration-tests/tests/postgres.js.test.ts @@ -31,6 +31,7 @@ import { getViewConfig, integer, interval, + json, jsonb, type PgColumn, pgEnum, @@ -1812,6 +1813,42 @@ test.serial('select from enum', async (t) => { await db.execute(sql`drop type ${name(categoryEnum.enumName)}`); }); +test.serial('proper json and jsonb handling', async (t) => { + const { db } = t.context; + + const jsonTable = pgTable('json_table', { + json: json('json').$type<{ name: string; age: number }>(), + jsonb: jsonb('jsonb').$type<{ name: string; age: number }>(), + }); + + await db.execute(sql`drop table if exists ${jsonTable}`); + + db.execute(sql`create table ${jsonTable} (json json, jsonb jsonb)`); + + await db.insert(jsonTable).values({ json: { name: 'Tom', age: 75 }, jsonb: { name: 'Pete', age: 23 } }); + + const result = await db.select().from(jsonTable); + + const justNames = await db.select({ + name1: sql`${jsonTable.json}->>'name'`.as('name1'), + name2: sql`${jsonTable.jsonb}->>'name'`.as('name2'), + }).from(jsonTable); + + t.deepEqual(result, [ + { + json: { name: 'Tom', age: 75 }, + jsonb: { name: 'Pete', age: 23 }, + }, + ]); + + t.deepEqual(justNames, [ + { + name1: 'Tom', + name2: 'Pete', + }, + ]); +}); + test.serial('orderBy with aliased column', (t) => { const { db } = t.context; From dd5835868cf88f0e9c38359e186d1584a00aa7da Mon Sep 17 00:00:00 2001 From: Angelelz Date: Wed, 10 Jan 2024 21:27:40 -0500 Subject: [PATCH 003/492] fix: bypassing the tranformation is only needed in the parser, not the serializer --- drizzle-orm/src/postgres-js/driver.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index 2b2523e25..2c4031c83 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -23,10 +23,12 @@ export function drizzle = Record val; // Override postgres.js default date parsers: https://github.com/porsager/postgres/discussions/761 - for (const type of ['1184', '1082', '1083', '1114', '114', '3802']) { - client.options.parsers[type as any] = transparentParser; + for (const type of ['1184', '1082', '1083', '1114']) { + if (type !== '114' && type !== '3802') client.options.parsers[type as any] = transparentParser; client.options.serializers[type as any] = transparentParser; } + client.options.parsers['114'] = transparentParser; + client.options.parsers['3802'] = transparentParser; const dialect = new PgDialect(); let logger; From ca792625fc64ca696cacafce1da32b0902b843ad Mon Sep 17 00:00:00 2001 From: Angelelz Date: Wed, 10 Jan 2024 21:32:52 -0500 Subject: [PATCH 004/492] Added additional tests to postgres-js integration tests --- integration-tests/tests/postgres.js.test.ts | 127 ++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/integration-tests/tests/postgres.js.test.ts b/integration-tests/tests/postgres.js.test.ts index d23b294b4..3382f24e2 100644 --- a/integration-tests/tests/postgres.js.test.ts +++ b/integration-tests/tests/postgres.js.test.ts @@ -94,6 +94,12 @@ const orders = pgTable('orders', { quantity: integer('quantity').notNull(), }); +const jsonTestTable = pgTable('jsontest', { + id: serial('id').primaryKey(), + json: json('json').$type<{ string: string; number: number }>(), + jsonb: jsonb('jsonb').$type<{ string: string; number: number }>(), +}); + const usersMigratorTable = pgTable('users12', { id: serial('id').primaryKey(), name: text('name').notNull(), @@ -234,6 +240,15 @@ test.beforeEach(async (t) => { ) `, ); + await ctx.db.execute( + sql` + create table jsontest ( + id serial primary key, + json json, + jsonb jsonb + ) + `, + ); }); test.serial('select all fields', async (t) => { @@ -422,6 +437,118 @@ test.serial('json insert', async (t) => { t.deepEqual(result, [{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); }); +test.serial('set json/jsonb fields with objects and retrieve with the ->> operator', async (t) => { + const { db } = t.context; + + const obj = { string: 'test', number: 123 }; + const { string: testString, number: testNumber } = obj; + + await db.insert(jsonTestTable).values({ + json: obj, + jsonb: obj, + }); + + const result = await db.select({ + jsonStringField: sql`${jsonTestTable.json}->>'string'`, + jsonNumberField: sql`${jsonTestTable.json}->>'number'`, + jsonbStringField: sql`${jsonTestTable.jsonb}->>'string'`, + jsonbNumberField: sql`${jsonTestTable.jsonb}->>'number'`, + }).from(jsonTestTable); + + t.deepEqual(result, [{ + jsonStringField: testString, + jsonNumberField: String(testNumber), + jsonbStringField: testString, + jsonbNumberField: String(testNumber), + }]); + + await db.execute(sql`drop table ${jsonTestTable}`); +}); + +test.serial('set json/jsonb fields with strings and retrieve with the ->> operator', async (t) => { + const { db } = t.context; + + const obj = { string: 'test', number: 123 }; + const { string: testString, number: testNumber } = obj; + + await db.insert(jsonTestTable).values({ + json: sql`${JSON.stringify(obj)}`, + jsonb: sql`${JSON.stringify(obj)}`, + }); + + const result = await db.select({ + jsonStringField: sql`${jsonTestTable.json}->>'string'`, + jsonNumberField: sql`${jsonTestTable.json}->>'number'`, + jsonbStringField: sql`${jsonTestTable.jsonb}->>'string'`, + jsonbNumberField: sql`${jsonTestTable.jsonb}->>'number'`, + }).from(jsonTestTable); + + t.deepEqual(result, [{ + jsonStringField: testString, + jsonNumberField: String(testNumber), + jsonbStringField: testString, + jsonbNumberField: String(testNumber), + }]); + + await db.execute(sql`drop table ${jsonTestTable}`); +}); + +test.serial('set json/jsonb fields with objects and retrieve with the -> operator', async (t) => { + const { db } = t.context; + + const obj = { string: 'test', number: 123 }; + const { string: testString, number: testNumber } = obj; + + await db.insert(jsonTestTable).values({ + json: obj, + jsonb: obj, + }); + + const result = await db.select({ + jsonStringField: sql`${jsonTestTable.json}->'string'`, + jsonNumberField: sql`${jsonTestTable.json}->'number'`, + jsonbStringField: sql`${jsonTestTable.jsonb}->'string'`, + jsonbNumberField: sql`${jsonTestTable.jsonb}->'number'`, + }).from(jsonTestTable); + + t.deepEqual(result, [{ + jsonStringField: testString, + jsonNumberField: testNumber, + jsonbStringField: testString, + jsonbNumberField: testNumber, + }]); + + await db.execute(sql`drop table ${jsonTestTable}`); +}); + +test.serial('set json/jsonb fields with strings and retrieve with the -> operator', async (t) => { + const { db } = t.context; + + const obj = { string: 'test', number: 123 }; + const { string: testString, number: testNumber } = obj; + + await db.insert(jsonTestTable).values({ + json: sql`${JSON.stringify(obj)}`, + jsonb: sql`${JSON.stringify(obj)}`, + }); + + const result = await db.select({ + jsonStringField: sql`${jsonTestTable.json}->'string'`, + jsonNumberField: sql`${jsonTestTable.json}->'number'`, + jsonbStringField: sql`${jsonTestTable.jsonb}->'string'`, + jsonbNumberField: sql`${jsonTestTable.jsonb}->'number'`, + }).from(jsonTestTable); + + t.deepEqual(result, [{ + jsonStringField: testString, + jsonNumberField: testNumber, + jsonbStringField: testString, + jsonbNumberField: testNumber, + }]); + + await db.execute(sql`drop table ${jsonTestTable}`); +}); + test.serial('insert with overridden default values', async (t) => { const { db } = t.context; From 562c25bb28cdd8243a28b1970b6c25b004b7d3d8 Mon Sep 17 00:00:00 2001 From: Angelelz Date: Wed, 10 Jan 2024 22:06:18 -0500 Subject: [PATCH 005/492] fixed parsing properly --- drizzle-orm/src/postgres-js/driver.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index 2c4031c83..7f44344e8 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -24,11 +24,11 @@ export function drizzle = Record Date: Sat, 27 Jan 2024 09:58:04 -0800 Subject: [PATCH 006/492] fix: $with for withReplicas --- drizzle-orm/src/pg-core/db.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index a5050ce53..b19ac3a25 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -400,7 +400,8 @@ export const withReplicas = < const select: Q['select'] = (...args: []) => getReplica(replicas).select(...args); const selectDistinct: Q['selectDistinct'] = (...args: []) => getReplica(replicas).selectDistinct(...args); const selectDistinctOn: Q['selectDistinctOn'] = (...args: [any]) => getReplica(replicas).selectDistinctOn(...args); - const $with: Q['with'] = (...args: any) => getReplica(replicas).with(...args); + const _with: Q['with'] = (...args: any) => getReplica(replicas).with(...args); + const $with: Q['$with'] = (arg: any) => getReplica(replicas).$with(arg); const update: Q['update'] = (...args: [any]) => primary.update(...args); const insert: Q['insert'] = (...args: [any]) => primary.insert(...args); @@ -422,7 +423,8 @@ export const withReplicas = < select, selectDistinct, selectDistinctOn, - with: $with, + $with, + with: _with, get query() { return getReplica(replicas).query; }, From 84af90eecda3c26b2714005e5df329d4553ab017 Mon Sep 17 00:00:00 2001 From: Akash Date: Sun, 31 Mar 2024 21:16:07 +0530 Subject: [PATCH 007/492] fix transaction --- drizzle-orm/src/mysql-core/session.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/mysql-core/session.ts b/drizzle-orm/src/mysql-core/session.ts index 528782d7b..1daa14638 100644 --- a/drizzle-orm/src/mysql-core/session.ts +++ b/drizzle-orm/src/mysql-core/session.ts @@ -95,7 +95,7 @@ export abstract class MySqlSession< parts.push(`isolation level ${config.isolationLevel}`); } - return parts.length ? sql.join(['set transaction ', parts.join(' ')]) : undefined; + return parts.length ? sql`set transaction ${sql.raw(parts.join(" "))}` : undefined; } protected getStartTransactionSQL(config: MySqlTransactionConfig): SQL | undefined { @@ -109,7 +109,7 @@ export abstract class MySqlSession< parts.push(config.accessMode); } - return parts.length ? sql.join(['start transaction ', parts.join(' ')]) : undefined; + return parts.length ? sql`start transaction ${sql.raw(parts.join(" "))}` : undefined; } } From b6716baabe8c31cae40e69b27ecd7c709c87a45f Mon Sep 17 00:00:00 2001 From: Akash Date: Sun, 31 Mar 2024 21:33:26 +0530 Subject: [PATCH 008/492] use single quotes --- drizzle-orm/src/mysql-core/session.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/mysql-core/session.ts b/drizzle-orm/src/mysql-core/session.ts index 1daa14638..77b003db6 100644 --- a/drizzle-orm/src/mysql-core/session.ts +++ b/drizzle-orm/src/mysql-core/session.ts @@ -95,7 +95,7 @@ export abstract class MySqlSession< parts.push(`isolation level ${config.isolationLevel}`); } - return parts.length ? sql`set transaction ${sql.raw(parts.join(" "))}` : undefined; + return parts.length ? sql`set transaction ${sql.raw(parts.join(' '))}` : undefined; } protected getStartTransactionSQL(config: MySqlTransactionConfig): SQL | undefined { @@ -109,7 +109,7 @@ export abstract class MySqlSession< parts.push(config.accessMode); } - return parts.length ? sql`start transaction ${sql.raw(parts.join(" "))}` : undefined; + return parts.length ? sql`start transaction ${sql.raw(parts.join(' '))}` : undefined; } } From c94e4931ccdda06889be3f440a2290453529ea20 Mon Sep 17 00:00:00 2001 From: Anton Stasyuk <33395021+anstapol@users.noreply.github.com> Date: Thu, 18 Jul 2024 13:51:33 +0200 Subject: [PATCH 009/492] forwaring dependencies within useLiveQuery Add support for dynamic query dependencies in hooks This update enables the use of dynamic values in query conditions within hooks, ensuring that queries are properly updated when their dependencies change. Example Using dynamic values in the where clause: ```ts const todos = useLiveQuery( db.query.todos.findMany({ where: between(schema.todos.created_at, from, to), }) ) ``` This enhancement is particularly useful for scenarios where the query depends on a set of changing dependencies, allowing for more flexible and responsive data fetching. --- drizzle-orm/src/expo-sqlite/query.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drizzle-orm/src/expo-sqlite/query.ts b/drizzle-orm/src/expo-sqlite/query.ts index f687efb54..28d2ed5b2 100644 --- a/drizzle-orm/src/expo-sqlite/query.ts +++ b/drizzle-orm/src/expo-sqlite/query.ts @@ -7,6 +7,7 @@ import { SQLiteRelationalQuery } from '~/sqlite-core/query-builders/query.ts'; export const useLiveQuery = | SQLiteRelationalQuery<'sync', unknown>>( query: T, + deps: unknown[] = [] ) => { const [data, setData] = useState>( (is(query, SQLiteRelationalQuery) && query.mode === 'first' ? undefined : []) as Awaited, @@ -43,7 +44,7 @@ export const useLiveQuery = | SQL return () => { listener?.remove(); }; - }, []); + }, deps); return { data, From 7925385e69ba691de1f47702bf869de455e9fb09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20H=C3=A1jek?= Date: Sun, 21 Jul 2024 19:10:52 +0200 Subject: [PATCH 010/492] Fix isTable helper function by adding IsDrizzleTable Symbol to Table base class --- drizzle-orm/src/table.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drizzle-orm/src/table.ts b/drizzle-orm/src/table.ts index 3db9d5559..8632dd35c 100644 --- a/drizzle-orm/src/table.ts +++ b/drizzle-orm/src/table.ts @@ -107,6 +107,9 @@ export class Table implements SQLWrapper { /** @internal */ [IsAlias] = false; + /** @internal */ + [IsDrizzleTable] = true; + /** @internal */ [ExtraConfigBuilder]: ((self: any) => Record) | undefined = undefined; From f4c3dde765d1b30fe04602dbce0fb0a3d5f6e2df Mon Sep 17 00:00:00 2001 From: Akash Date: Mon, 22 Jul 2024 17:38:17 +0530 Subject: [PATCH 011/492] add test for mysql transaction with options --- integration-tests/tests/mysql/mysql-common.ts | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index db1486270..b0863b3cd 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -2030,6 +2030,45 @@ export function tests(driver?: string) { await db.execute(sql`drop table ${products}`); }); + test('transaction with options (set isolationLevel)', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users_transactions', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + const products = mysqlTable('products_transactions', { + id: serial('id').primaryKey(), + price: int('price').notNull(), + stock: int('stock').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop table if exists ${products}`); + + await db.execute(sql`create table users_transactions (id serial not null primary key, balance int not null)`); + await db.execute( + sql`create table products_transactions (id serial not null primary key, price int not null, stock int not null)`, + ); + + const [{ insertId: userId }] = await db.insert(users).values({ balance: 100 }); + const user = await db.select().from(users).where(eq(users.id, userId)).then((rows) => rows[0]!); + const [{ insertId: productId }] = await db.insert(products).values({ price: 10, stock: 10 }); + const product = await db.select().from(products).where(eq(products.id, productId)).then((rows) => rows[0]!); + + await db.transaction(async (tx) => { + await tx.update(users).set({ balance: user.balance - product.price }).where(eq(users.id, user.id)); + await tx.update(products).set({ stock: product.stock - 1 }).where(eq(products.id, product.id)); + }, { isolationLevel: "serializable" }); + + const result = await db.select().from(users); + + expect(result).toEqual([{ id: 1, balance: 90 }]); + + await db.execute(sql`drop table ${users}`); + await db.execute(sql`drop table ${products}`); + }); + test('transaction rollback', async (ctx) => { const { db } = ctx.mysql; From bf5d6cc89e7bf2e587a4ed87e4b0fc76bc380fa7 Mon Sep 17 00:00:00 2001 From: Akash Date: Tue, 23 Jul 2024 21:06:29 +0530 Subject: [PATCH 012/492] format with dprint --- drizzle-orm/src/mysql-core/session.ts | 4 ++-- integration-tests/tests/mysql/mysql-common.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/mysql-core/session.ts b/drizzle-orm/src/mysql-core/session.ts index 093f8bfc5..6b6269639 100644 --- a/drizzle-orm/src/mysql-core/session.ts +++ b/drizzle-orm/src/mysql-core/session.ts @@ -98,7 +98,7 @@ export abstract class MySqlSession< parts.push(`isolation level ${config.isolationLevel}`); } - return parts.length ? sql`set transaction ${sql.raw(parts.join(' '))}` : undefined; + return parts.length ? sql`set transaction ${sql.raw(parts.join(' '))}` : undefined; } protected getStartTransactionSQL(config: MySqlTransactionConfig): SQL | undefined { @@ -112,7 +112,7 @@ export abstract class MySqlSession< parts.push(config.accessMode); } - return parts.length ? sql`start transaction ${sql.raw(parts.join(' '))}` : undefined; + return parts.length ? sql`start transaction ${sql.raw(parts.join(' '))}` : undefined; } } diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index fe6d5b1d8..87a989c39 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -2059,7 +2059,7 @@ export function tests(driver?: string) { await db.transaction(async (tx) => { await tx.update(users).set({ balance: user.balance - product.price }).where(eq(users.id, user.id)); await tx.update(products).set({ stock: product.stock - 1 }).where(eq(products.id, product.id)); - }, { isolationLevel: "serializable" }); + }, { isolationLevel: 'serializable' }); const result = await db.select().from(users); From 5a8713549189e79934c2ed383a258994ec0274e4 Mon Sep 17 00:00:00 2001 From: Aria <85405932+veloii@users.noreply.github.com> Date: Tue, 23 Jul 2024 20:25:05 +0100 Subject: [PATCH 013/492] fix: export type AnySQLiteUpdate --- drizzle-orm/src/sqlite-core/query-builders/update.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/sqlite-core/query-builders/update.ts b/drizzle-orm/src/sqlite-core/query-builders/update.ts index 7b25c090a..0238b748f 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/update.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/update.ts @@ -134,7 +134,7 @@ export type SQLiteUpdate< TReturning extends Record | undefined = Record | undefined, > = SQLiteUpdateBase; -type AnySQLiteUpdate = SQLiteUpdateBase; +export type AnySQLiteUpdate = SQLiteUpdateBase; export interface SQLiteUpdateBase< TTable extends SQLiteTable = SQLiteTable, From 8cc707a1413c215ca624a0e32eb5d2929b687650 Mon Sep 17 00:00:00 2001 From: Anton Stasyuk <33395021+anstapol@users.noreply.github.com> Date: Wed, 24 Jul 2024 11:44:56 +0200 Subject: [PATCH 014/492] dprint formatting expo-sqlite/query.ts --- drizzle-orm/src/expo-sqlite/query.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/expo-sqlite/query.ts b/drizzle-orm/src/expo-sqlite/query.ts index 28d2ed5b2..db467ce2c 100644 --- a/drizzle-orm/src/expo-sqlite/query.ts +++ b/drizzle-orm/src/expo-sqlite/query.ts @@ -7,7 +7,7 @@ import { SQLiteRelationalQuery } from '~/sqlite-core/query-builders/query.ts'; export const useLiveQuery = | SQLiteRelationalQuery<'sync', unknown>>( query: T, - deps: unknown[] = [] + deps: unknown[] = [], ) => { const [data, setData] = useState>( (is(query, SQLiteRelationalQuery) && query.mode === 'first' ? undefined : []) as Awaited, From 9e9d8ddb0ab2a7d92a489cbf7869ce4c223628f3 Mon Sep 17 00:00:00 2001 From: Akash Date: Wed, 24 Jul 2024 16:10:08 +0530 Subject: [PATCH 015/492] skip transaction tests for unsupported mysql drivers --- integration-tests/tests/mysql/mysql-planetscale.test.ts | 1 + integration-tests/tests/mysql/mysql-proxy.test.ts | 1 + integration-tests/tests/mysql/tidb-serverless.test.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/integration-tests/tests/mysql/mysql-planetscale.test.ts b/integration-tests/tests/mysql/mysql-planetscale.test.ts index 8c7e74543..763b9c8e6 100644 --- a/integration-tests/tests/mysql/mysql-planetscale.test.ts +++ b/integration-tests/tests/mysql/mysql-planetscale.test.ts @@ -59,6 +59,7 @@ skipTests([ // to redefine in this file 'utc config for datetime', 'transaction', + 'transaction with options (set isolationLevel)', 'having', 'select count()', 'insert via db.execute w/ query builder', diff --git a/integration-tests/tests/mysql/mysql-proxy.test.ts b/integration-tests/tests/mysql/mysql-proxy.test.ts index cb8e4b758..1cf8345c4 100644 --- a/integration-tests/tests/mysql/mysql-proxy.test.ts +++ b/integration-tests/tests/mysql/mysql-proxy.test.ts @@ -129,6 +129,7 @@ skipTests([ 'nested transaction', 'transaction rollback', 'transaction', + 'transaction with options (set isolationLevel)', 'migrator', ]); diff --git a/integration-tests/tests/mysql/tidb-serverless.test.ts b/integration-tests/tests/mysql/tidb-serverless.test.ts index 8187882af..9121c31de 100644 --- a/integration-tests/tests/mysql/tidb-serverless.test.ts +++ b/integration-tests/tests/mysql/tidb-serverless.test.ts @@ -66,6 +66,7 @@ skipTests([ 'select iterator w/ prepared statement', 'select iterator', 'transaction', + 'transaction with options (set isolationLevel)', 'Insert all defaults in multiple rows', 'Insert all defaults in 1 row', '$default with empty array', From 848e1360ee813208528e4c0a6716bfc6e80bf123 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 25 Jul 2024 14:56:35 +0300 Subject: [PATCH 016/492] Add none typings for basic case --- drizzle-orm/src/sql/sql.ts | 4 +- integration-tests/package.json | 2 +- integration-tests/tests/pg/awsdatapi.test.ts | 961 +++++++++++++------ 3 files changed, 669 insertions(+), 298 deletions(-) diff --git a/drizzle-orm/src/sql/sql.ts b/drizzle-orm/src/sql/sql.ts index f5b3f30b4..244a95d5d 100644 --- a/drizzle-orm/src/sql/sql.ts +++ b/drizzle-orm/src/sql/sql.ts @@ -213,7 +213,7 @@ export class SQL implements SQLWrapper { return { sql: this.mapInlineParam(mappedValue, config), params: [] }; } - let typings: QueryTypingsValue[] | undefined; + let typings: QueryTypingsValue[] = ['none']; if (prepareTyping) { typings = [prepareTyping(chunk.encoder)]; } @@ -263,7 +263,7 @@ export class SQL implements SQLWrapper { return { sql: this.mapInlineParam(chunk, config), params: [] }; } - return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk] }; + return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ['none'] }; })); } diff --git a/integration-tests/package.json b/integration-tests/package.json index 20c2d1fc3..a4fcab0b2 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -8,7 +8,7 @@ "test": "pnpm test:vitest", "test:vitest": "vitest run", "test:esm": "node tests/imports.test.mjs && node tests/imports.test.cjs", - "test:data-api": "sst shell vitest run tests/awsdatapi.test.ts" + "test:data-api": "sst shell vitest run tests/pg/awsdatapi.test.ts" }, "keywords": [], "author": "Drizzle Team", diff --git a/integration-tests/tests/pg/awsdatapi.test.ts b/integration-tests/tests/pg/awsdatapi.test.ts index 22ad8e770..87f20386c 100644 --- a/integration-tests/tests/pg/awsdatapi.test.ts +++ b/integration-tests/tests/pg/awsdatapi.test.ts @@ -2,7 +2,7 @@ import 'dotenv/config'; import { RDSDataClient } from '@aws-sdk/client-rds-data'; import * as dotenv from 'dotenv'; -import { asc, eq, inArray, notInArray, sql, TransactionRollbackError } from 'drizzle-orm'; +import { asc, eq, inArray, notInArray, relations, sql, TransactionRollbackError } from 'drizzle-orm'; import type { AwsDataApiPgDatabase } from 'drizzle-orm/aws-data-api/pg'; import { drizzle } from 'drizzle-orm/aws-data-api/pg'; import { migrate } from 'drizzle-orm/aws-data-api/pg/migrator'; @@ -18,6 +18,7 @@ import { text, time, timestamp, + uuid, } from 'drizzle-orm/pg-core'; import { Resource } from 'sst'; import { afterAll, beforeAll, beforeEach, expect, expectTypeOf, test } from 'vitest'; @@ -34,8 +35,13 @@ const usersTable = pgTable('users', { name: text('name').notNull(), verified: boolean('verified').notNull().default(false), jsonb: jsonb('jsonb').$type(), - bestTexts: text('best_texts').array().default(sql`'{}'`).notNull(), - createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), + bestTexts: text('best_texts') + .array() + .default(sql`'{}'`) + .notNull(), + createdAt: timestamp('created_at', { withTimezone: true }) + .notNull() + .defaultNow(), }); const usersMigratorTable = pgTable('users12', { @@ -44,7 +50,51 @@ const usersMigratorTable = pgTable('users12', { email: text('email').notNull(), }); -let db: AwsDataApiPgDatabase; +const todo = pgTable('todo', { + id: uuid('id').primaryKey(), + title: text('title').notNull(), + description: text('description'), +}); + +const todoRelations = relations(todo, (ctx) => ({ + user: ctx.many(todoUser), +})); + +const user = pgTable('user', { + id: uuid('id').primaryKey(), + email: text('email').notNull(), +}); + +const userRelations = relations(user, (ctx) => ({ + todos: ctx.many(todoUser), +})); + +const todoUser = pgTable('todo_user', { + todoId: uuid('todo_id').references(() => todo.id), + userId: uuid('user_id').references(() => user.id), +}); + +const todoToGroupRelations = relations(todoUser, (ctx) => ({ + todo: ctx.one(todo, { + fields: [todoUser.todoId], + references: [todo.id], + }), + user: ctx.one(user, { + fields: [todoUser.userId], + references: [user.id], + }), +})); + +const schema = { + todo, + todoRelations, + user, + userRelations, + todoUser, + todoToGroupRelations, +}; + +let db: AwsDataApiPgDatabase; beforeAll(async () => { const rdsClient = new RDSDataClient(); @@ -57,6 +107,7 @@ beforeAll(async () => { // @ts-ignore resourceArn: Resource.Postgres.clusterArn, logger: ENABLE_LOGGING, + schema, }); }); @@ -75,6 +126,35 @@ beforeEach(async () => { ) `, ); + + await db.execute( + sql` + create table todo ( + id uuid primary key, + title text not null, + description text + ) + `, + ); + + await db.execute( + sql` + create table "user" ( + id uuid primary key, + email text not null + ) + + `, + ); + + await db.execute( + sql` + create table todo_user ( + todo_id uuid references todo(id), + user_id uuid references "user"(id) + ) + `, + ); }); test('select all fields', async () => { @@ -86,56 +166,68 @@ test('select all fields', async () => { expect(result[0]!.createdAt).toBeInstanceOf(Date); // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 100); - expect(result).toEqual([{ - bestTexts: [], - id: 1, - name: 'John', - verified: false, - jsonb: null, - createdAt: result[0]!.createdAt, - }]); + expect(result).toEqual([ + { + bestTexts: [], + id: 1, + name: 'John', + verified: false, + jsonb: null, + createdAt: result[0]!.createdAt, + }, + ]); }); test('select sql', async () => { await db.insert(usersTable).values({ name: 'John' }); - const users = await db.select({ - name: sql`upper(${usersTable.name})`, - }).from(usersTable); + const users = await db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable); expect(users).toEqual([{ name: 'JOHN' }]); }); test('select with empty array in inArray', async () => { - await db.insert(usersTable).values([ - { name: 'John' }, - { name: 'Jane' }, - { name: 'Jane' }, - ]); - const users = await db.select({ - name: sql`upper(${usersTable.name})`, - }).from(usersTable).where(inArray(usersTable.id, [])); + await db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + const users = await db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(inArray(usersTable.id, [])); expect(users).toEqual([]); }); test('select with empty array in notInArray', async () => { - await db.insert(usersTable).values([ - { name: 'John' }, - { name: 'Jane' }, - { name: 'Jane' }, - ]); - const result = await db.select({ - name: sql`upper(${usersTable.name})`, - }).from(usersTable).where(notInArray(usersTable.id, [])); + await db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + const result = await db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(notInArray(usersTable.id, [])); - expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + expect(result).toEqual([ + { name: 'JOHN' }, + { name: 'JANE' }, + { name: 'JANE' }, + ]); }); test('select typed sql', async () => { await db.insert(usersTable).values({ name: 'John' }); - const users = await db.select({ - name: sql`upper(${usersTable.name})`, - }).from(usersTable); + const users = await db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable); expect(users).toEqual([{ name: 'JOHN' }]); }); @@ -147,7 +239,9 @@ test('select distinct', async () => { }); await db.execute(sql`drop table if exists ${usersDistinctTable}`); - await db.execute(sql`create table ${usersDistinctTable} (id integer, name text)`); + await db.execute( + sql`create table ${usersDistinctTable} (id integer, name text)`, + ); await db.insert(usersDistinctTable).values([ { id: 1, name: 'John' }, @@ -155,20 +249,28 @@ test('select distinct', async () => { { id: 2, name: 'John' }, { id: 1, name: 'Jane' }, ]); - const users1 = await db.selectDistinct().from(usersDistinctTable).orderBy( - usersDistinctTable.id, - usersDistinctTable.name, - ); - const users2 = await db.selectDistinctOn([usersDistinctTable.id]).from(usersDistinctTable).orderBy( - usersDistinctTable.id, - ); - const users3 = await db.selectDistinctOn([usersDistinctTable.name], { name: usersDistinctTable.name }).from( - usersDistinctTable, - ).orderBy(usersDistinctTable.name); + const users1 = await db + .selectDistinct() + .from(usersDistinctTable) + .orderBy(usersDistinctTable.id, usersDistinctTable.name); + const users2 = await db + .selectDistinctOn([usersDistinctTable.id]) + .from(usersDistinctTable) + .orderBy(usersDistinctTable.id); + const users3 = await db + .selectDistinctOn([usersDistinctTable.name], { + name: usersDistinctTable.name, + }) + .from(usersDistinctTable) + .orderBy(usersDistinctTable.name); await db.execute(sql`drop table ${usersDistinctTable}`); - expect(users1).toEqual([{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); + expect(users1).toEqual([ + { id: 1, name: 'Jane' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + ]); expect(users2.length).toEqual(2); expect(users2[0]?.id).toEqual(1); @@ -180,79 +282,107 @@ test('select distinct', async () => { }); test('insert returning sql', async () => { - const users = await db.insert(usersTable).values({ name: 'John' }).returning({ - name: sql`upper(${usersTable.name})`, - }); + const users = await db + .insert(usersTable) + .values({ name: 'John' }) + .returning({ + name: sql`upper(${usersTable.name})`, + }); expect(users).toEqual([{ name: 'JOHN' }]); }); test('delete returning sql', async () => { await db.insert(usersTable).values({ name: 'John' }); - const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')).returning({ - name: sql`upper(${usersTable.name})`, - }); + const users = await db + .delete(usersTable) + .where(eq(usersTable.name, 'John')) + .returning({ + name: sql`upper(${usersTable.name})`, + }); expect(users).toEqual([{ name: 'JOHN' }]); }); test('update returning sql', async () => { await db.insert(usersTable).values({ name: 'John' }); - const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')).returning({ - name: sql`upper(${usersTable.name})`, - }); + const users = await db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning({ + name: sql`upper(${usersTable.name})`, + }); expect(users).toEqual([{ name: 'JANE' }]); }); test('update with returning all fields', async () => { await db.insert(usersTable).values({ name: 'John' }); - const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')).returning(); + const users = await db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning(); expect(users[0]!.createdAt).toBeInstanceOf(Date); // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 100); - expect(users).toEqual([{ - id: 1, - bestTexts: [], - name: 'Jane', - verified: false, - jsonb: null, - createdAt: users[0]!.createdAt, - }]); + expect(users).toEqual([ + { + id: 1, + bestTexts: [], + name: 'Jane', + verified: false, + jsonb: null, + createdAt: users[0]!.createdAt, + }, + ]); }); test('update with returning partial', async () => { await db.insert(usersTable).values({ name: 'John' }); - const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')).returning({ - id: usersTable.id, - name: usersTable.name, - }); + const users = await db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning({ + id: usersTable.id, + name: usersTable.name, + }); expect(users).toEqual([{ id: 1, name: 'Jane' }]); }); test('delete with returning all fields', async () => { await db.insert(usersTable).values({ name: 'John' }); - const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')).returning(); + const users = await db + .delete(usersTable) + .where(eq(usersTable.name, 'John')) + .returning(); expect(users[0]!.createdAt).toBeInstanceOf(Date); // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 100); - expect(users).toEqual([{ - bestTexts: [], - id: 1, - name: 'John', - verified: false, - jsonb: null, - createdAt: users[0]!.createdAt, - }]); + expect(users).toEqual([ + { + bestTexts: [], + id: 1, + name: 'John', + verified: false, + jsonb: null, + createdAt: users[0]!.createdAt, + }, + ]); }); test('delete with returning partial', async () => { await db.insert(usersTable).values({ name: 'John' }); - const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')).returning({ - id: usersTable.id, - name: usersTable.name, - }); + const users = await db + .delete(usersTable) + .where(eq(usersTable.name, 'John')) + .returning({ + id: usersTable.id, + name: usersTable.name, + }); expect(users).toEqual([{ id: 1, name: 'John' }]); }); @@ -260,30 +390,48 @@ test('delete with returning partial', async () => { test('insert + select', async () => { await db.insert(usersTable).values({ name: 'John' }); const result = await db.select().from(usersTable); - expect(result).toEqual([{ - bestTexts: [], - id: 1, - name: 'John', - verified: false, - jsonb: null, - createdAt: result[0]!.createdAt, - }]); + expect(result).toEqual([ + { + bestTexts: [], + id: 1, + name: 'John', + verified: false, + jsonb: null, + createdAt: result[0]!.createdAt, + }, + ]); await db.insert(usersTable).values({ name: 'Jane' }); const result2 = await db.select().from(usersTable); expect(result2).toEqual([ - { bestTexts: [], id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, - { bestTexts: [], id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + { + bestTexts: [], + id: 1, + name: 'John', + verified: false, + jsonb: null, + createdAt: result2[0]!.createdAt, + }, + { + bestTexts: [], + id: 2, + name: 'Jane', + verified: false, + jsonb: null, + createdAt: result2[1]!.createdAt, + }, ]); }); test('json insert', async () => { await db.insert(usersTable).values({ name: 'John', jsonb: ['foo', 'bar'] }); - const result = await db.select({ - id: usersTable.id, - name: usersTable.name, - jsonb: usersTable.jsonb, - }).from(usersTable); + const result = await db + .select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }) + .from(usersTable); expect(result).toEqual([{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); }); @@ -292,29 +440,35 @@ test('insert with overridden default values', async () => { await db.insert(usersTable).values({ name: 'John', verified: true }); const result = await db.select().from(usersTable); - expect(result).toEqual([{ - bestTexts: [], - id: 1, - name: 'John', - verified: true, - jsonb: null, - createdAt: result[0]!.createdAt, - }]); + expect(result).toEqual([ + { + bestTexts: [], + id: 1, + name: 'John', + verified: true, + jsonb: null, + createdAt: result[0]!.createdAt, + }, + ]); }); test('insert many', async () => { - await db.insert(usersTable).values([ - { name: 'John' }, - { name: 'Bruce', jsonb: ['foo', 'bar'] }, - { name: 'Jane' }, - { name: 'Austin', verified: true }, - ]); - const result = await db.select({ - id: usersTable.id, - name: usersTable.name, - jsonb: usersTable.jsonb, - verified: usersTable.verified, - }).from(usersTable); + await db + .insert(usersTable) + .values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + const result = await db + .select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }) + .from(usersTable); expect(result).toEqual([ { id: 1, name: 'John', jsonb: null, verified: false }, @@ -325,12 +479,14 @@ test('insert many', async () => { }); test('insert many with returning', async () => { - const result = await db.insert(usersTable).values([ - { name: 'John' }, - { name: 'Bruce', jsonb: ['foo', 'bar'] }, - { name: 'Jane' }, - { name: 'Austin', verified: true }, - ]) + const result = await db + .insert(usersTable) + .values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]) .returning({ id: usersTable.id, name: usersTable.name, @@ -347,45 +503,73 @@ test('insert many with returning', async () => { }); test('select with group by as field', async () => { - await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + await db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); - const result = await db.select({ name: usersTable.name }).from(usersTable) + const result = await db + .select({ name: usersTable.name }) + .from(usersTable) .groupBy(usersTable.name); expect(result).toEqual([{ name: 'Jane' }, { name: 'John' }]); }); test('select with group by as sql', async () => { - await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + await db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); - const result = await db.select({ name: usersTable.name }).from(usersTable) + const result = await db + .select({ name: usersTable.name }) + .from(usersTable) .groupBy(sql`${usersTable.name}`); expect(result).toEqual([{ name: 'Jane' }, { name: 'John' }]); }); test('select with group by as sql + column', async () => { - await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + await db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); - const result = await db.select({ name: usersTable.name }).from(usersTable) + const result = await db + .select({ name: usersTable.name }) + .from(usersTable) .groupBy(sql`${usersTable.name}`, usersTable.id); - expect(result).toEqual([{ name: 'Jane' }, { name: 'Jane' }, { name: 'John' }]); + expect(result).toEqual([ + { name: 'Jane' }, + { name: 'Jane' }, + { name: 'John' }, + ]); }); test('select with group by as column + sql', async () => { - await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + await db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); - const result = await db.select({ name: usersTable.name }).from(usersTable) + const result = await db + .select({ name: usersTable.name }) + .from(usersTable) .groupBy(usersTable.id, sql`${usersTable.name}`); - expect(result).toEqual([{ name: 'Jane' }, { name: 'Jane' }, { name: 'John' }]); + expect(result).toEqual([ + { name: 'Jane' }, + { name: 'Jane' }, + { name: 'John' }, + ]); }); test('select with group by complex query', async () => { - await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + await db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); - const result = await db.select({ name: usersTable.name }).from(usersTable) + const result = await db + .select({ name: usersTable.name }) + .from(usersTable) .groupBy(usersTable.id, sql`${usersTable.name}`) .orderBy(asc(usersTable.name)) .limit(1); @@ -394,7 +578,9 @@ test('select with group by complex query', async () => { }); test('build query', async () => { - const query = db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable) + const query = db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable) .groupBy(usersTable.id, usersTable.name) .toSQL(); @@ -407,14 +593,19 @@ test('build query', async () => { test('insert sql', async () => { await db.insert(usersTable).values({ name: sql`${'John'}` }); - const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + const result = await db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable); expect(result).toEqual([{ id: 1, name: 'John' }]); }); test('partial join with alias', async () => { const customerAlias = alias(usersTable, 'customer'); - await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + await db.insert(usersTable).values([ + { id: 10, name: 'Ivan' }, + { id: 11, name: 'Hans' }, + ]); const result = await db .select({ user: { @@ -425,44 +616,53 @@ test('partial join with alias', async () => { id: customerAlias.id, name: customerAlias.name, }, - }).from(usersTable) + }) + .from(usersTable) .leftJoin(customerAlias, eq(customerAlias.id, 11)) .where(eq(usersTable.id, 10)); - expect(result).toEqual([{ - user: { id: 10, name: 'Ivan' }, - customer: { id: 11, name: 'Hans' }, - }]); + expect(result).toEqual([ + { + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }, + ]); }); test('full join with alias', async () => { const customerAlias = alias(usersTable, 'customer'); - await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + await db.insert(usersTable).values([ + { id: 10, name: 'Ivan' }, + { id: 11, name: 'Hans' }, + ]); const result = await db - .select().from(usersTable) + .select() + .from(usersTable) .leftJoin(customerAlias, eq(customerAlias.id, 11)) .where(eq(usersTable.id, 10)); - expect(result).toEqual([{ - users: { - id: 10, - bestTexts: [], - name: 'Ivan', - verified: false, - jsonb: null, - createdAt: result[0]!.users.createdAt, - }, - customer: { - bestTexts: [], - id: 11, - name: 'Hans', - verified: false, - jsonb: null, - createdAt: result[0]!.customer!.createdAt, + expect(result).toEqual([ + { + users: { + id: 10, + bestTexts: [], + name: 'Ivan', + verified: false, + jsonb: null, + createdAt: result[0]!.users.createdAt, + }, + customer: { + bestTexts: [], + id: 11, + name: 'Hans', + verified: false, + jsonb: null, + createdAt: result[0]!.customer!.createdAt, + }, }, - }]); + ]); }); test('select from alias', async () => { @@ -474,35 +674,44 @@ test('select from alias', async () => { }); await db.execute(sql`drop table if exists ${users}`); - await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + await db.execute( + sql`create table ${users} (id serial primary key, name text not null)`, + ); const user = alias(users, 'user'); const customers = alias(users, 'customer'); - await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + await db.insert(users).values([ + { id: 10, name: 'Ivan' }, + { id: 11, name: 'Hans' }, + ]); const result = await db .select() .from(user) .leftJoin(customers, eq(customers.id, 11)) .where(eq(user.id, 10)); - expect(result).toEqual([{ - user: { - id: 10, - name: 'Ivan', - }, - customer: { - id: 11, - name: 'Hans', + expect(result).toEqual([ + { + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, }, - }]); + ]); await db.execute(sql`drop table ${users}`); }); test('insert with spaces', async () => { await db.insert(usersTable).values({ name: sql`'Jo h n'` }); - const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + const result = await db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable); expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); }); @@ -522,20 +731,25 @@ test('prepared statement', async () => { }); test('prepared statement reuse', async () => { - const stmt = db.insert(usersTable).values({ - verified: true, - name: sql.placeholder('name'), - }).prepare('stmt2'); + const stmt = db + .insert(usersTable) + .values({ + verified: true, + name: sql.placeholder('name'), + }) + .prepare('stmt2'); for (let i = 0; i < 10; i++) { await stmt.execute({ name: `John ${i}` }); } - const result = await db.select({ - id: usersTable.id, - name: usersTable.name, - verified: usersTable.verified, - }).from(usersTable); + const result = await db + .select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }) + .from(usersTable); expect(result).toEqual([ { id: 1, name: 'John 0', verified: true }, @@ -590,10 +804,15 @@ test('migrator : migrate with custom schema', async () => { await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); - await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsSchema: customSchema }); + await migrate(db, { + migrationsFolder: './drizzle2/pg', + migrationsSchema: customSchema, + }); // test if the custom migrations table was created - const { rows } = await db.execute(sql`select * from ${sql.identifier(customSchema)}."__drizzle_migrations";`); + const { rows } = await db.execute( + sql`select * from ${sql.identifier(customSchema)}."__drizzle_migrations";`, + ); expect(rows).toBeTruthy(); expect(rows!.length).toBeGreaterThan(0); @@ -604,7 +823,9 @@ test('migrator : migrate with custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); - await db.execute(sql`drop table ${sql.identifier(customSchema)}."__drizzle_migrations"`); + await db.execute( + sql`drop table ${sql.identifier(customSchema)}."__drizzle_migrations"`, + ); }); test('migrator : migrate with custom table', async () => { @@ -613,10 +834,15 @@ test('migrator : migrate with custom table', async () => { await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); - await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsTable: customTable }); + await migrate(db, { + migrationsFolder: './drizzle2/pg', + migrationsTable: customTable, + }); // test if the custom migrations table was created - const { rows } = await db.execute(sql`select * from "drizzle".${sql.identifier(customTable)};`); + const { rows } = await db.execute( + sql`select * from "drizzle".${sql.identifier(customTable)};`, + ); expect(rows).toBeTruthy(); expect(rows!.length).toBeGreaterThan(0); @@ -645,7 +871,11 @@ test('migrator : migrate with custom table and custom schema', async () => { // test if the custom migrations table was created const { rows } = await db.execute( - sql`select * from ${sql.identifier(customSchema)}.${sql.identifier(customTable)};`, + sql`select * from ${sql.identifier(customSchema)}.${ + sql.identifier( + customTable, + ) + };`, ); expect(rows).toBeTruthy(); expect(rows!.length).toBeGreaterThan(0); @@ -657,13 +887,27 @@ test('migrator : migrate with custom table and custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); - await db.execute(sql`drop table ${sql.identifier(customSchema)}.${sql.identifier(customTable)}`); + await db.execute( + sql`drop table ${sql.identifier(customSchema)}.${ + sql.identifier( + customTable, + ) + }`, + ); }); test('insert via db.execute + select via db.execute', async () => { - await db.execute(sql`insert into ${usersTable} (${sql.identifier(usersTable.name.name)}) values (${'John'})`); + await db.execute( + sql`insert into ${usersTable} (${ + sql.identifier( + usersTable.name.name, + ) + }) values (${'John'})`, + ); - const result = await db.execute<{ id: number; name: string }>(sql`select id, name from "users"`); + const result = await db.execute<{ id: number; name: string }>( + sql`select id, name from "users"`, + ); expectTypeOf(result.rows).toEqualTypeOf<{ id: number; name: string }[]>(); expect(result.rows).toEqual([{ id: 1, name: 'John' }]); }); @@ -671,7 +915,9 @@ test('insert via db.execute + select via db.execute', async () => { test('insert via db.execute + returning', async () => { const inserted = await db.execute( sql`insert into ${usersTable} (${ - sql.identifier(usersTable.name.name) + sql.identifier( + usersTable.name.name, + ) }) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, ); expect(inserted.rows).toEqual([{ id: 1, name: 'John' }]); @@ -679,13 +925,17 @@ test('insert via db.execute + returning', async () => { test('insert via db.execute w/ query builder', async () => { const inserted = await db.execute( - db.insert(usersTable).values({ name: 'John' }).returning({ id: usersTable.id, name: usersTable.name }), + db + .insert(usersTable) + .values({ name: 'John' }) + .returning({ id: usersTable.id, name: usersTable.name }), ); expect(inserted.rows).toEqual([{ id: 1, name: 'John' }]); }); test('build query insert with onConflict do update', async () => { - const query = db.insert(usersTable) + const query = db + .insert(usersTable) .values({ name: 'John', jsonb: ['foo', 'bar'] }) .onConflictDoUpdate({ target: usersTable.id, set: { name: 'John1' } }) .toSQL(); @@ -699,9 +949,13 @@ test('build query insert with onConflict do update', async () => { }); test('build query insert with onConflict do update / multiple columns', async () => { - const query = db.insert(usersTable) + const query = db + .insert(usersTable) .values({ name: 'John', jsonb: ['foo', 'bar'] }) - .onConflictDoUpdate({ target: [usersTable.id, usersTable.name], set: { name: 'John1' } }) + .onConflictDoUpdate({ + target: [usersTable.id, usersTable.name], + set: { name: 'John1' }, + }) .toSQL(); expect(query).toEqual({ @@ -713,7 +967,8 @@ test('build query insert with onConflict do update / multiple columns', async () }); test('build query insert with onConflict do nothing', async () => { - const query = db.insert(usersTable) + const query = db + .insert(usersTable) .values({ name: 'John', jsonb: ['foo', 'bar'] }) .onConflictDoNothing() .toSQL(); @@ -727,7 +982,8 @@ test('build query insert with onConflict do nothing', async () => { }); test('build query insert with onConflict do nothing + target', async () => { - const query = db.insert(usersTable) + const query = db + .insert(usersTable) .values({ name: 'John', jsonb: ['foo', 'bar'] }) .onConflictDoNothing({ target: usersTable.id }) .toSQL(); @@ -741,46 +997,49 @@ test('build query insert with onConflict do nothing + target', async () => { }); test('insert with onConflict do update', async () => { - await db.insert(usersTable) - .values({ name: 'John' }); + await db.insert(usersTable).values({ name: 'John' }); - await db.insert(usersTable) + await db + .insert(usersTable) .values({ id: 1, name: 'John' }) .onConflictDoUpdate({ target: usersTable.id, set: { name: 'John1' } }); - const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( - eq(usersTable.id, 1), - ); + const res = await db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable) + .where(eq(usersTable.id, 1)); expect(res).toEqual([{ id: 1, name: 'John1' }]); }); test('insert with onConflict do nothing', async () => { - await db.insert(usersTable) - .values({ name: 'John' }); + await db.insert(usersTable).values({ name: 'John' }); - await db.insert(usersTable) + await db + .insert(usersTable) .values({ id: 1, name: 'John' }) .onConflictDoNothing(); - const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( - eq(usersTable.id, 1), - ); + const res = await db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable) + .where(eq(usersTable.id, 1)); expect(res).toEqual([{ id: 1, name: 'John' }]); }); test('insert with onConflict do nothing + target', async () => { - await db.insert(usersTable) - .values({ name: 'John' }); + await db.insert(usersTable).values({ name: 'John' }); - await db.insert(usersTable) + await db + .insert(usersTable) .values({ id: 1, name: 'John' }) .onConflictDoNothing({ target: usersTable.id }); - const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( - eq(usersTable.id, 1), - ); + const res = await db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable) + .where(eq(usersTable.id, 1)); expect(res).toEqual([{ id: 1, name: 'John' }]); }); @@ -799,17 +1058,33 @@ test('transaction', async () => { await db.execute(sql`drop table if exists ${users}`); await db.execute(sql`drop table if exists ${products}`); - await db.execute(sql`create table users_transactions (id serial not null primary key, balance integer not null)`); + await db.execute( + sql`create table users_transactions (id serial not null primary key, balance integer not null)`, + ); await db.execute( sql`create table products_transactions (id serial not null primary key, price integer not null, stock integer not null)`, ); - const user = await db.insert(users).values({ balance: 100 }).returning().then((rows) => rows[0]!); - const product = await db.insert(products).values({ price: 10, stock: 10 }).returning().then((rows) => rows[0]!); + const user = await db + .insert(users) + .values({ balance: 100 }) + .returning() + .then((rows) => rows[0]!); + const product = await db + .insert(products) + .values({ price: 10, stock: 10 }) + .returning() + .then((rows) => rows[0]!); await db.transaction(async (tx) => { - await tx.update(users).set({ balance: user.balance - product.price }).where(eq(users.id, user.id)); - await tx.update(products).set({ stock: product.stock - 1 }).where(eq(products.id, product.id)); + await tx + .update(users) + .set({ balance: user.balance - product.price }) + .where(eq(users.id, user.id)); + await tx + .update(products) + .set({ stock: product.stock - 1 }) + .where(eq(products.id, product.id)); }); const result = await db.select().from(users); @@ -906,81 +1181,109 @@ test('nested transaction rollback', async () => { test('select from raw sql', async () => { const result = await db.execute(sql`select 1 as id, 'John' as name`); - expect(result.rows).toEqual([ - { id: 1, name: 'John' }, - ]); + expect(result.rows).toEqual([{ id: 1, name: 'John' }]); }); test('select from raw sql with mapped values', async () => { - const result = await db.select({ - id: sql`id`, - name: sql`name`, - }).from(sql`(select 1 as id, 'John' as name) as users`); + const result = await db + .select({ + id: sql`id`, + name: sql`name`, + }) + .from(sql`(select 1 as id, 'John' as name) as users`); - expect(result).toEqual([ - { id: 1, name: 'John' }, - ]); + expect(result).toEqual([{ id: 1, name: 'John' }]); }); test('insert with array values works', async () => { const bestTexts = ['text1', 'text2', 'text3']; - const [insertResult] = await db.insert(usersTable).values({ - name: 'John', - bestTexts, - }).returning(); + const [insertResult] = await db + .insert(usersTable) + .values({ + name: 'John', + bestTexts, + }) + .returning(); expect(insertResult?.bestTexts).toEqual(bestTexts); }); test('update with array values works', async () => { - const [newUser] = await db.insert(usersTable).values({ name: 'John' }).returning(); + const [newUser] = await db + .insert(usersTable) + .values({ name: 'John' }) + .returning(); const bestTexts = ['text4', 'text5', 'text6']; - const [insertResult] = await db.update(usersTable).set({ - bestTexts, - }).where(eq(usersTable.id, newUser!.id)).returning(); + const [insertResult] = await db + .update(usersTable) + .set({ + bestTexts, + }) + .where(eq(usersTable.id, newUser!.id)) + .returning(); expect(insertResult?.bestTexts).toEqual(bestTexts); }); test('insert with array values works', async () => { const bestTexts = ['text1', 'text2', 'text3']; - const [insertResult] = await db.insert(usersTable).values({ - name: 'John', - bestTexts, - }).returning(); + const [insertResult] = await db + .insert(usersTable) + .values({ + name: 'John', + bestTexts, + }) + .returning(); expect(insertResult?.bestTexts).toEqual(bestTexts); }); test('update with array values works', async () => { - const [newUser] = await db.insert(usersTable).values({ name: 'John' }).returning(); + const [newUser] = await db + .insert(usersTable) + .values({ name: 'John' }) + .returning(); const bestTexts = ['text4', 'text5', 'text6']; - const [insertResult] = await db.update(usersTable).set({ - bestTexts, - }).where(eq(usersTable.id, newUser!.id)).returning(); + const [insertResult] = await db + .update(usersTable) + .set({ + bestTexts, + }) + .where(eq(usersTable.id, newUser!.id)) + .returning(); expect(insertResult?.bestTexts).toEqual(bestTexts); }); test('insert with array values works', async () => { const bestTexts = ['text1', 'text2', 'text3']; - const [insertResult] = await db.insert(usersTable).values({ - name: 'John', - bestTexts, - }).returning(); + const [insertResult] = await db + .insert(usersTable) + .values({ + name: 'John', + bestTexts, + }) + .returning(); expect(insertResult?.bestTexts).toEqual(bestTexts); }); test('update with array values works', async () => { - const [newUser] = await db.insert(usersTable).values({ name: 'John' }).returning(); + const [newUser] = await db + .insert(usersTable) + .values({ name: 'John' }) + .returning(); const bestTexts = ['text4', 'text5', 'text6']; - const [insertResult] = await db.update(usersTable).set({ - bestTexts, - }).where(eq(usersTable.id, newUser!.id)).returning(); + const [insertResult] = await db + .update(usersTable) + .set({ + bestTexts, + }) + .where(eq(usersTable.id, newUser!.id)) + .returning(); expect(insertResult?.bestTexts).toEqual(bestTexts); }); @@ -993,7 +1296,10 @@ test('all date and time columns', async () => { datetime: timestamp('datetime').notNull(), // datetimeWTZ: timestamp('datetime_wtz', { withTimezone: true }).notNull(), datetimeString: timestamp('datetime_string', { mode: 'string' }).notNull(), - datetimeFullPrecision: timestamp('datetime_full_precision', { precision: 6, mode: 'string' }).notNull(), + datetimeFullPrecision: timestamp('datetime_full_precision', { + precision: 6, + mode: 'string', + }).notNull(), // datetimeWTZString: timestamp('datetime_wtz_string', { withTimezone: true, mode: 'string' }).notNull(), }); @@ -1029,29 +1335,35 @@ test('all date and time columns', async () => { const result = await db.select().from(table); Expect< - Equal<{ - id: number; - dateString: string; - time: string; - datetime: Date; - // datetimeWTZ: Date; - datetimeString: string; - datetimeFullPrecision: string; - // datetimeWTZString: string; - }[], typeof result> + Equal< + { + id: number; + dateString: string; + time: string; + datetime: Date; + // datetimeWTZ: Date; + datetimeString: string; + datetimeFullPrecision: string; + // datetimeWTZString: string; + }[], + typeof result + > >; Expect< - Equal<{ - dateString: string; - time: string; - datetime: Date; - // datetimeWTZ: Date; - datetimeString: string; - datetimeFullPrecision: string; - // datetimeWTZString: string; - id?: number | undefined; - }, typeof table.$inferInsert> + Equal< + { + dateString: string; + time: string; + datetime: Date; + // datetimeWTZ: Date; + datetimeString: string; + datetimeFullPrecision: string; + // datetimeWTZString: string; + id?: number | undefined; + }, + typeof table.$inferInsert + > >; expect(result).toEqual([ @@ -1073,9 +1385,19 @@ test('all date and time columns', async () => { test.skip('all date and time columns with timezone', async () => { const table = pgTable('all_columns', { id: serial('id').primaryKey(), - timestamp: timestamp('timestamp_string', { mode: 'string', withTimezone: true, precision: 6 }).notNull(), - timestampAsDate: timestamp('timestamp_date', { withTimezone: true, precision: 3 }).notNull(), - timestampTimeZones: timestamp('timestamp_date_2', { withTimezone: true, precision: 3 }).notNull(), + timestamp: timestamp('timestamp_string', { + mode: 'string', + withTimezone: true, + precision: 6, + }).notNull(), + timestampAsDate: timestamp('timestamp_date', { + withTimezone: true, + precision: 3, + }).notNull(), + timestampTimeZones: timestamp('timestamp_date_2', { + withTimezone: true, + precision: 3, + }).notNull(), }); await db.execute(sql`drop table if exists ${table}`); @@ -1098,8 +1420,16 @@ test.skip('all date and time columns with timezone', async () => { const timestampDateWTZ2 = new Date('2022-01-01 00:00:00.123 +0200'); await db.insert(table).values([ - { timestamp: timestampString, timestampAsDate: timestampDate, timestampTimeZones: timestampDateWTZ }, - { timestamp: timestampString2, timestampAsDate: timestampDate2, timestampTimeZones: timestampDateWTZ2 }, + { + timestamp: timestampString, + timestampAsDate: timestampDate, + timestampTimeZones: timestampDateWTZ, + }, + { + timestamp: timestampString2, + timestampAsDate: timestampDate2, + timestampTimeZones: timestampDateWTZ2, + }, ]); const result = await db.select().from(table); @@ -1132,18 +1462,21 @@ test.skip('all date and time columns with timezone', async () => { id: 1, timestamp_string: '2022-01-01 02:00:00.123456+00', timestamp_date: timestampDate.toISOString().replace('T', ' ').replace('Z', '') + '+00', - timestamp_date_2: timestampDateWTZ.toISOString().replace('T', ' ').replace('Z', '') + '+00', + timestamp_date_2: timestampDateWTZ.toISOString().replace('T', ' ').replace('Z', '') + + '+00', }, { id: 2, timestamp_string: '2022-01-01 04:00:00.123456+00', timestamp_date: timestampDate2.toISOString().replace('T', ' ').replace('Z', '') + '+00', - timestamp_date_2: timestampDateWTZ2.toISOString().replace('T', ' ').replace('Z', '') + '+00', + timestamp_date_2: timestampDateWTZ2.toISOString().replace('T', ' ').replace('Z', '') + + '+00', }, ]); - expect(result[0]?.timestampTimeZones.getTime()) - .toEqual(new Date((result2.rows?.[0] as any).timestamp_date_2 as any).getTime()); + expect(result[0]?.timestampTimeZones.getTime()).toEqual( + new Date((result2.rows?.[0] as any).timestamp_date_2 as any).getTime(), + ); await db.execute(sql`drop table if exists ${table}`); }); @@ -1151,8 +1484,14 @@ test.skip('all date and time columns with timezone', async () => { test('all date and time columns without timezone', async () => { const table = pgTable('all_columns', { id: serial('id').primaryKey(), - timestampString: timestamp('timestamp_string', { mode: 'string', precision: 6 }).notNull(), - timestampString2: timestamp('timestamp_string2', { precision: 3, mode: 'string' }).notNull(), + timestampString: timestamp('timestamp_string', { + mode: 'string', + precision: 6, + }).notNull(), + timestampString2: timestamp('timestamp_string2', { + precision: 3, + mode: 'string', + }).notNull(), timestampDate: timestamp('timestamp_date', { precision: 3 }).notNull(), }); @@ -1180,7 +1519,11 @@ test('all date and time columns without timezone', async () => { await db.insert(table).values([ { timestampString, timestampString2, timestampDate }, - { timestampString: timestampString_2, timestampString2: timestampString2_2, timestampDate: timestampDate2 }, + { + timestampString: timestampString_2, + timestampString2: timestampString2_2, + timestampDate: timestampDate2, + }, ]); const result = await db.select().from(table); @@ -1213,26 +1556,54 @@ test('all date and time columns without timezone', async () => { id: 1, timestamp_string: timestampString, timestamp_string2: '2022-01-02 00:00:00.123', - timestamp_date: timestampDate.toISOString().replace('T', ' ').replace('Z', ''), + timestamp_date: timestampDate + .toISOString() + .replace('T', ' ') + .replace('Z', ''), }, { id: 2, timestamp_string: timestampString_2, timestamp_string2: '2022-01-01 00:00:00.123', - timestamp_date: timestampDate2.toISOString().replace('T', ' ').replace('Z', ''), + timestamp_date: timestampDate2 + .toISOString() + .replace('T', ' ') + .replace('Z', ''), }, ]); - expect((result2.rows?.[0] as any).timestamp_string).toEqual('2022-01-01 00:00:00.123456'); - // need to add the 'Z', otherwise javascript assumes it's in local time - expect(new Date((result2.rows?.[0] as any).timestamp_date + 'Z' as any).getTime()).toEqual( - timestampDate.getTime(), + expect((result2.rows?.[0] as any).timestamp_string).toEqual( + '2022-01-01 00:00:00.123456', ); + // need to add the 'Z', otherwise javascript assumes it's in local time + expect( + new Date(((result2.rows?.[0] as any).timestamp_date + 'Z') as any).getTime(), + ).toEqual(timestampDate.getTime()); await db.execute(sql`drop table if exists ${table}`); }); +test('Typehints mix for RQB', async () => { + const uuid = 'd997d46d-5769-4c78-9a35-93acadbe6076'; + + const res = await db.query.user.findMany({ + where: eq(user.id, uuid), + with: { + todos: { + with: { + todo: true, + }, + }, + }, + }); + + console.log(res); +}); + afterAll(async () => { await db.execute(sql`drop table if exists "users"`); + await db.execute(sql`drop table if exists "todo_user"`); + await db.execute(sql`drop table if exists "user"`); + await db.execute(sql`drop table if exists "todo"`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); }); From ff3f1660106b366a4919fb7b4f51bf9604837bbc Mon Sep 17 00:00:00 2001 From: RemiPe Date: Thu, 25 Jul 2024 17:54:00 +0200 Subject: [PATCH 017/492] Update inArray and notInArray documentation remove the throws part since both methods do not throw anymore --- drizzle-orm/src/sql/expressions/conditions.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drizzle-orm/src/sql/expressions/conditions.ts b/drizzle-orm/src/sql/expressions/conditions.ts index 0a911e1ff..ba0e21fbc 100644 --- a/drizzle-orm/src/sql/expressions/conditions.ts +++ b/drizzle-orm/src/sql/expressions/conditions.ts @@ -256,11 +256,6 @@ export const lte: BinaryOperator = (left: SQLWrapper, right: unknown): SQL => { * Test whether the first parameter, a column or expression, * has a value from a list passed as the second argument. * - * ## Throws - * - * The argument passed in the second array can't be empty: - * if an empty is provided, this method will throw. - * * ## Examples * * ```ts @@ -302,11 +297,6 @@ export function inArray( * has a value that is not present in a list passed as the * second argument. * - * ## Throws - * - * The argument passed in the second array can't be empty: - * if an empty is provided, this method will throw. - * * ## Examples * * ```ts From c352347aeb1e0f31985dd107c8f5d4f110273d0b Mon Sep 17 00:00:00 2001 From: Kravets <57632712+kravetsone@users.noreply.github.com> Date: Thu, 1 Aug 2024 17:44:37 +0300 Subject: [PATCH 018/492] Replace `zx` with native `child_process` --- drizzle-kit/src/utils/certs.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drizzle-kit/src/utils/certs.ts b/drizzle-kit/src/utils/certs.ts index b9a6d4de8..a3c80ab61 100644 --- a/drizzle-kit/src/utils/certs.ts +++ b/drizzle-kit/src/utils/certs.ts @@ -1,19 +1,25 @@ import envPaths from 'env-paths'; import { mkdirSync } from 'fs'; import { access, readFile } from 'fs/promises'; +import { exec, ExecOptions } from 'node:child_process'; import { join } from 'path'; -import { $ } from 'zx'; const p = envPaths('drizzle-studio', { suffix: '', }); -$.verbose = false; -$.cwd = p.data; mkdirSync(p.data, { recursive: true }); +export function runCommand(command: string, options: ExecOptions = {}) { + return new Promise<{ exitCode: number }>((resolve, reject) => { + exec(command, options, (error, stdout, stderr) => { + return resolve({ exitCode: error?.code ?? 0 }); + }); + }); +} + export const certs = async () => { - const res = await $`mkcert --help`.nothrow(); + const res = await runCommand(`mkcert --help`, { cwd: p.data }); // ~/.local/share/drizzle-studio const keyPath = join(p.data, 'localhost-key.pem'); @@ -23,7 +29,7 @@ export const certs = async () => { try { await Promise.all([access(keyPath), access(certPath)]); } catch (e) { - await $`mkcert localhost`.nothrow(); + await runCommand(`mkcert localhost`, { cwd: p.data }); } const [key, cert] = await Promise.all([ readFile(keyPath, { encoding: 'utf-8' }), From 5510112de88b5550f911e4d236a4d5a38b487f39 Mon Sep 17 00:00:00 2001 From: Karibash Date: Thu, 1 Aug 2024 23:13:36 +0900 Subject: [PATCH 019/492] bugfix: Fix a bug with default values for columns of type string --- drizzle-kit/src/serializer/mysqlSerializer.ts | 2 +- drizzle-kit/tests/introspect/mysql.test.ts | 44 ++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index eb18743fb..14e867128 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -481,7 +481,7 @@ export const fromDatabase = async ( default: columnDefault === null ? undefined : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) - && !columnType.startsWith('decimal') + && !['decimal', 'char', 'varchar'].some((type) => columnType.startsWith(type)) ? Number(columnDefault) : isDefaultAnExpression ? clearDefaults(columnDefault, collation) diff --git a/drizzle-kit/tests/introspect/mysql.test.ts b/drizzle-kit/tests/introspect/mysql.test.ts index 23cd28a16..e35b34f40 100644 --- a/drizzle-kit/tests/introspect/mysql.test.ts +++ b/drizzle-kit/tests/introspect/mysql.test.ts @@ -1,6 +1,6 @@ import Docker from 'dockerode'; import { SQL, sql } from 'drizzle-orm'; -import { int, mysqlTable, text } from 'drizzle-orm/mysql-core'; +import { char, int, mysqlTable, text, varchar } from 'drizzle-orm/mysql-core'; import * as fs from 'fs'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; @@ -123,3 +123,45 @@ test('generated always column virtual: link to another column', async () => { await client.query(`drop table users;`); }); + +test('Default value of character type column: char', async () => { + const schema = { + users: mysqlTable('users', { + id: int('id'), + sortKey: char('sortKey', { length: 255 }).default('0'), + }), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'default-value-char-column', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`drop table users;`); +}); + +test('Default value of character type column: varchar', async () => { + const schema = { + users: mysqlTable('users', { + id: int('id'), + sortKey: varchar('sortKey', { length: 255 }).default('0'), + }), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'default-value-varchar-column', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`drop table users;`); +}); From 19c8926a98e64b012803c8a14e9b42e46b0e005e Mon Sep 17 00:00:00 2001 From: Karibash Date: Thu, 1 Aug 2024 23:25:49 +0900 Subject: [PATCH 020/492] bugfix: Fix a bug that import statements for columns of type double are not inserted --- drizzle-kit/src/introspect-mysql.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index fb1c71428..21be79654 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -153,6 +153,7 @@ export const schemaToTypeScript = ( patched = patched.startsWith('datetime(') ? 'datetime' : patched; patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; patched = patched.startsWith('int(') ? 'int' : patched; + patched = patched.startsWith('double(') ? 'double' : patched; return patched; }) .filter((type) => { From c340413f52e7d6308a1bbba902d0cdeadb82672d Mon Sep 17 00:00:00 2001 From: Mario564 Date: Thu, 1 Aug 2024 16:50:25 -0700 Subject: [PATCH 021/492] Initial implementation for optional column alias in PG --- drizzle-orm/src/column-builder.ts | 7 +++- drizzle-orm/src/pg-core/columns/bigserial.ts | 16 +++++-- drizzle-orm/src/pg-core/columns/boolean.ts | 8 ++-- drizzle-orm/src/pg-core/columns/common.ts | 6 +++ drizzle-orm/src/pg-core/columns/varchar.ts | 13 +++++- drizzle-orm/src/pg-core/table.ts | 2 + drizzle-orm/src/utils.ts | 11 +++++ integration-tests/tests/pg/pg-common.ts | 44 ++++++++++++++++++++ 8 files changed, 96 insertions(+), 11 deletions(-) diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index 4a19a79a9..ba0d3bb78 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -4,7 +4,7 @@ import type { MySqlColumn } from './mysql-core/index.ts'; import type { ExtraConfigColumn, PgColumn, PgSequenceOptions } from './pg-core/index.ts'; import type { SQL } from './sql/sql.ts'; import type { SQLiteColumn } from './sqlite-core/index.ts'; -import type { Simplify } from './utils.ts'; +import type { Assume, Simplify } from './utils.ts'; export type ColumnDataType = | 'string' @@ -322,7 +322,10 @@ export type BuildColumns< TDialect extends Dialect, > = & { - [Key in keyof TConfigMap]: BuildColumn; + [Key in keyof TConfigMap]: BuildColumn & + { name: TConfigMap[Key]['_']['name'] extends '' ? Assume : TConfigMap[Key]['_']['name'] } + }, TDialect>; } & {}; diff --git a/drizzle-orm/src/pg-core/columns/bigserial.ts b/drizzle-orm/src/pg-core/columns/bigserial.ts index 0cca21577..40ccdfcec 100644 --- a/drizzle-orm/src/pg-core/columns/bigserial.ts +++ b/drizzle-orm/src/pg-core/columns/bigserial.ts @@ -9,6 +9,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '../table.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type PgBigSerial53BuilderInitial = NotNull< HasDefault< @@ -113,13 +114,20 @@ interface PgBigSerialConfig mode: T; } +export function bigserial( + config: PgBigSerialConfig, +): TMode extends 'number' ? PgBigSerial53BuilderInitial<''> : PgBigSerial64BuilderInitial<''>; export function bigserial( name: TName, config: PgBigSerialConfig, ): TMode extends 'number' ? PgBigSerial53BuilderInitial : PgBigSerial64BuilderInitial; -export function bigserial(name: string, { mode }: PgBigSerialConfig) { - if (mode === 'number') { - return new PgBigSerial53Builder(name); +export function bigserial( + a: TName | PgBigSerialConfig, + b?: PgBigSerialConfig +): TMode extends 'number' ? PgBigSerial53BuilderInitial : PgBigSerial64BuilderInitial { + const { name, config } = getColumnNameAndConfig>(a, b); + if (config.mode === 'number') { + return new PgBigSerial53Builder(name) as any; } - return new PgBigSerial64Builder(name); + return new PgBigSerial64Builder(name) as any; } diff --git a/drizzle-orm/src/pg-core/columns/boolean.ts b/drizzle-orm/src/pg-core/columns/boolean.ts index f4670f1a6..a82fa5da4 100644 --- a/drizzle-orm/src/pg-core/columns/boolean.ts +++ b/drizzle-orm/src/pg-core/columns/boolean.ts @@ -17,7 +17,7 @@ export type PgBooleanBuilderInitial = PgBooleanBuilder<{ export class PgBooleanBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgBooleanBuilder'; - constructor(name: T['name']) { + constructor(name: string) { super(name, 'boolean', 'PgBoolean'); } @@ -37,6 +37,8 @@ export class PgBoolean> exten } } -export function boolean(name: TName): PgBooleanBuilderInitial { - return new PgBooleanBuilder(name); +export function boolean(): PgBooleanBuilderInitial<''>; +export function boolean(name: TName): PgBooleanBuilderInitial +export function boolean(name?: TName): PgBooleanBuilderInitial { + return new PgBooleanBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index a7440e24c..ff313bea3 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -126,6 +126,12 @@ export abstract class PgColumnBuilder< ): ExtraConfigColumn { return new ExtraConfigColumn(table, this.config); } + + /** @internal Sets the name of the column to the key within the table definition if a name was not given. */ + setName(name: string) { + if (this.config.name !== '') return; + this.config.name = name; + } } // To understand how to use `PgColumn` and `PgColumn`, see `Column` and `AnyColumn` documentation. diff --git a/drizzle-orm/src/pg-core/columns/varchar.ts b/drizzle-orm/src/pg-core/columns/varchar.ts index 84283d40e..dedcb758a 100644 --- a/drizzle-orm/src/pg-core/columns/varchar.ts +++ b/drizzle-orm/src/pg-core/columns/varchar.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import type { Writable } from '~/utils.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; export type PgVarcharBuilderInitial = PgVarcharBuilder<{ @@ -53,9 +53,18 @@ export interface PgVarcharConfig; +export function varchar>( + config?: PgVarcharConfig>, +): PgVarcharBuilderInitial<'', Writable>; export function varchar>( name: TName, - config: PgVarcharConfig> = {}, + config?: PgVarcharConfig>, +): PgVarcharBuilderInitial>; +export function varchar>( + a?: TName | PgVarcharConfig>, + b: PgVarcharConfig> = {}, ): PgVarcharBuilderInitial> { + const { name, config } = getColumnNameAndConfig>>(a, b); return new PgVarcharBuilder(name, config); } diff --git a/drizzle-orm/src/pg-core/table.ts b/drizzle-orm/src/pg-core/table.ts index 78cd52019..cfa13082d 100644 --- a/drizzle-orm/src/pg-core/table.ts +++ b/drizzle-orm/src/pg-core/table.ts @@ -73,6 +73,7 @@ export function pgTableWithSchema< const builtColumns = Object.fromEntries( Object.entries(columns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as PgColumnBuilder; + colBuilder.setName(name); const column = colBuilder.build(rawTable); rawTable[InlineForeignKeys].push(...colBuilder.buildForeignKeys(column, rawTable)); return [name, column]; @@ -82,6 +83,7 @@ export function pgTableWithSchema< const builtColumnsForExtraConfig = Object.fromEntries( Object.entries(columns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as PgColumnBuilder; + colBuilder.setName(name); const column = colBuilder.buildExtraConfigColumn(rawTable); return [name, column]; }), diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index 54bd44325..4ca6ee326 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -223,3 +223,14 @@ export type KnownKeysOnly = { }; export type IsAny = 0 extends (1 & T) ? true : false; + +/** @internal */ +export function getColumnNameAndConfig< + TName extends string, + TConfig extends Record | undefined +>(a: TName | TConfig | undefined, b: TConfig | undefined) { + return { + name: typeof a === 'string' && a.length > 0 ? a : '' as TName, + config: typeof a === 'object' ? a : b as TConfig, + }; +} diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index fb69c5877..b09f034ad 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -70,6 +70,7 @@ import { uniqueKeyName, uuid as pgUuid, varchar, + bigserial, } from 'drizzle-orm/pg-core'; import getPort from 'get-port'; import { v4 as uuidV4 } from 'uuid'; @@ -4481,5 +4482,48 @@ export function tests() { expect(users.length).toBeGreaterThan(0); }); + + test('Object keys as column names', async (ctx) => { + const { db } = ctx.pg; + + // Tests the following: + // Column with required config + // Column with optional config without providing a value + // Column with optional config providing a value + // Column without config + const users = pgTable('users', { + id: bigserial({ mode: 'number' }).primaryKey(), + firstName: varchar(), + lastName: varchar({ length: 50 }), + admin: boolean() + }); + + await db.execute(sql`drop table if exists users`); + await db.execute( + sql` + create table users ( + "id" bigserial primary key, + "firstName" varchar, + "lastName" varchar(50), + "admin" boolean + ) + ` + ); + + await db.insert(users).values([ + { firstName: 'John', lastName: 'Doe', admin: true }, + { firstName: 'Jane', lastName: 'Smith', admin: false }, + ]); + const result = await db + .select({ id: users.id, firstName: users.firstName, lastName: users.lastName }) + .from(users) + .where(eq(users.admin, true)); + + expect(result).toEqual([ + { id: 1, firstName: 'John', lastName: 'Doe' }, + ]); + + await db.execute(sql`drop table users`); + }) }); } From e2e7c3817b970d84e7a0ebe0aa2a6dd6271cb1ad Mon Sep 17 00:00:00 2001 From: Mario564 Date: Thu, 1 Aug 2024 16:54:17 -0700 Subject: [PATCH 022/492] Move line and point types into `postgis_extensions` folder --- drizzle-orm/src/pg-core/columns/{ => postgis_extension}/line.ts | 2 +- .../src/pg-core/columns/{ => postgis_extension}/point.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename drizzle-orm/src/pg-core/columns/{ => postgis_extension}/line.ts (98%) rename drizzle-orm/src/pg-core/columns/{ => postgis_extension}/point.ts (98%) diff --git a/drizzle-orm/src/pg-core/columns/line.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts similarity index 98% rename from drizzle-orm/src/pg-core/columns/line.ts rename to drizzle-orm/src/pg-core/columns/postgis_extension/line.ts index bf4e653ad..e3eb5db22 100644 --- a/drizzle-orm/src/pg-core/columns/line.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts @@ -4,7 +4,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import type { Equal } from '~/utils.ts'; -import { PgColumn, PgColumnBuilder } from './common.ts'; +import { PgColumn, PgColumnBuilder } from '../common.ts'; export type PgLineBuilderInitial = PgLineBuilder<{ name: TName; diff --git a/drizzle-orm/src/pg-core/columns/point.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts similarity index 98% rename from drizzle-orm/src/pg-core/columns/point.ts rename to drizzle-orm/src/pg-core/columns/postgis_extension/point.ts index 7bff25e55..f38f7532f 100644 --- a/drizzle-orm/src/pg-core/columns/point.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts @@ -4,7 +4,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import type { Equal } from '~/utils.ts'; -import { PgColumn, PgColumnBuilder } from './common.ts'; +import { PgColumn, PgColumnBuilder } from '../common.ts'; export type PgPointTupleBuilderInitial = PgPointTupleBuilder<{ name: TName; From 0da77f5777f4282a0753be284c9d0aee16d9da90 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Thu, 1 Aug 2024 16:56:44 -0700 Subject: [PATCH 023/492] Update PG column exports --- drizzle-orm/src/pg-core/columns/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/pg-core/columns/index.ts b/drizzle-orm/src/pg-core/columns/index.ts index 881f53e33..8be5dbea7 100644 --- a/drizzle-orm/src/pg-core/columns/index.ts +++ b/drizzle-orm/src/pg-core/columns/index.ts @@ -13,12 +13,12 @@ export * from './integer.ts'; export * from './interval.ts'; export * from './json.ts'; export * from './jsonb.ts'; -export * from './line.ts'; export * from './macaddr.ts'; export * from './macaddr8.ts'; export * from './numeric.ts'; -export * from './point.ts'; export * from './postgis_extension/geometry.ts'; +export * from './postgis_extension/line.ts'; +export * from './postgis_extension/point.ts'; export * from './real.ts'; export * from './serial.ts'; export * from './smallint.ts'; From 7b34f11e07356b8862f146e34e11677143334f29 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Thu, 1 Aug 2024 17:02:33 -0700 Subject: [PATCH 024/492] Update PG column types that don't have config param --- drizzle-orm/src/pg-core/columns/double-precision.ts | 8 +++++--- drizzle-orm/src/pg-core/columns/inet.ts | 8 +++++--- drizzle-orm/src/pg-core/columns/integer.ts | 8 +++++--- drizzle-orm/src/pg-core/columns/json.ts | 8 +++++--- drizzle-orm/src/pg-core/columns/jsonb.ts | 8 +++++--- drizzle-orm/src/pg-core/columns/macaddr.ts | 8 +++++--- drizzle-orm/src/pg-core/columns/macaddr8.ts | 8 +++++--- drizzle-orm/src/pg-core/columns/real.ts | 6 ++++-- drizzle-orm/src/pg-core/columns/serial.ts | 6 ++++-- drizzle-orm/src/pg-core/columns/smallint.ts | 8 +++++--- drizzle-orm/src/pg-core/columns/smallserial.ts | 6 ++++-- drizzle-orm/src/pg-core/columns/uuid.ts | 8 +++++--- 12 files changed, 57 insertions(+), 33 deletions(-) diff --git a/drizzle-orm/src/pg-core/columns/double-precision.ts b/drizzle-orm/src/pg-core/columns/double-precision.ts index 879c25ccb..466dc58b4 100644 --- a/drizzle-orm/src/pg-core/columns/double-precision.ts +++ b/drizzle-orm/src/pg-core/columns/double-precision.ts @@ -19,7 +19,7 @@ export class PgDoublePrecisionBuilder(name: TName): PgDoublePrecisionBuilderInitial { - return new PgDoublePrecisionBuilder(name); +export function doublePrecision(): PgDoublePrecisionBuilderInitial<''>; +export function doublePrecision(name: TName): PgDoublePrecisionBuilderInitial; +export function doublePrecision(name?: TName): PgDoublePrecisionBuilderInitial { + return new PgDoublePrecisionBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/inet.ts b/drizzle-orm/src/pg-core/columns/inet.ts index f8e473de7..d9ce18690 100644 --- a/drizzle-orm/src/pg-core/columns/inet.ts +++ b/drizzle-orm/src/pg-core/columns/inet.ts @@ -17,7 +17,7 @@ export type PgInetBuilderInitial = PgInetBuilder<{ export class PgInetBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgInetBuilder'; - constructor(name: T['name']) { + constructor(name: string) { super(name, 'string', 'PgInet'); } @@ -37,6 +37,8 @@ export class PgInet> extends PgCo } } -export function inet(name: TName): PgInetBuilderInitial { - return new PgInetBuilder(name); +export function inet(): PgInetBuilderInitial<''>; +export function inet(name: TName): PgInetBuilderInitial; +export function inet(name?: TName): PgInetBuilderInitial { + return new PgInetBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/integer.ts b/drizzle-orm/src/pg-core/columns/integer.ts index 2c35c1e29..8344d7253 100644 --- a/drizzle-orm/src/pg-core/columns/integer.ts +++ b/drizzle-orm/src/pg-core/columns/integer.ts @@ -20,7 +20,7 @@ export class PgIntegerBuilder> extend } } -export function integer(name: TName): PgIntegerBuilderInitial { - return new PgIntegerBuilder(name); +export function integer(): PgIntegerBuilderInitial<''>; +export function integer(name: TName): PgIntegerBuilderInitial; +export function integer(name?: TName): PgIntegerBuilderInitial { + return new PgIntegerBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/json.ts b/drizzle-orm/src/pg-core/columns/json.ts index ddb97b67e..34def405b 100644 --- a/drizzle-orm/src/pg-core/columns/json.ts +++ b/drizzle-orm/src/pg-core/columns/json.ts @@ -19,7 +19,7 @@ export class PgJsonBuilder> > { static readonly [entityKind]: string = 'PgJsonBuilder'; - constructor(name: T['name']) { + constructor(name: string) { super(name, 'json', 'PgJson'); } @@ -58,6 +58,8 @@ export class PgJson> extends PgColu } } -export function json(name: TName): PgJsonBuilderInitial { - return new PgJsonBuilder(name); +export function json(): PgJsonBuilderInitial<''>; +export function json(name: TName): PgJsonBuilderInitial; +export function json(name?: TName): PgJsonBuilderInitial { + return new PgJsonBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/jsonb.ts b/drizzle-orm/src/pg-core/columns/jsonb.ts index a44b26fd0..8c9e3dfde 100644 --- a/drizzle-orm/src/pg-core/columns/jsonb.ts +++ b/drizzle-orm/src/pg-core/columns/jsonb.ts @@ -17,7 +17,7 @@ export type PgJsonbBuilderInitial = PgJsonbBuilder<{ export class PgJsonbBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgJsonbBuilder'; - constructor(name: T['name']) { + constructor(name: string) { super(name, 'json', 'PgJsonb'); } @@ -56,6 +56,8 @@ export class PgJsonb> extends PgCo } } -export function jsonb(name: TName): PgJsonbBuilderInitial { - return new PgJsonbBuilder(name); +export function jsonb(): PgJsonbBuilderInitial<''>; +export function jsonb(name: TName): PgJsonbBuilderInitial; +export function jsonb(name?: TName): PgJsonbBuilderInitial { + return new PgJsonbBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/macaddr.ts b/drizzle-orm/src/pg-core/columns/macaddr.ts index edc27f7c0..1a0000d72 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr.ts @@ -17,7 +17,7 @@ export type PgMacaddrBuilderInitial = PgMacaddrBuilder<{ export class PgMacaddrBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgMacaddrBuilder'; - constructor(name: T['name']) { + constructor(name: string) { super(name, 'string', 'PgMacaddr'); } @@ -37,6 +37,8 @@ export class PgMacaddr> extend } } -export function macaddr(name: TName): PgMacaddrBuilderInitial { - return new PgMacaddrBuilder(name); +export function macaddr(): PgMacaddrBuilderInitial<''> +export function macaddr(name: TName): PgMacaddrBuilderInitial +export function macaddr(name?: TName): PgMacaddrBuilderInitial { + return new PgMacaddrBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/macaddr8.ts b/drizzle-orm/src/pg-core/columns/macaddr8.ts index fc611d063..73e353c97 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr8.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr8.ts @@ -17,7 +17,7 @@ export type PgMacaddr8BuilderInitial = PgMacaddr8Builder<{ export class PgMacaddr8Builder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgMacaddr8Builder'; - constructor(name: T['name']) { + constructor(name: string) { super(name, 'string', 'PgMacaddr8'); } @@ -37,6 +37,8 @@ export class PgMacaddr8> exte } } -export function macaddr8(name: TName): PgMacaddr8BuilderInitial { - return new PgMacaddr8Builder(name); +export function macaddr8(): PgMacaddr8BuilderInitial<''> +export function macaddr8(name: TName): PgMacaddr8BuilderInitial +export function macaddr8(name?: TName): PgMacaddr8BuilderInitial { + return new PgMacaddr8Builder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/real.ts b/drizzle-orm/src/pg-core/columns/real.ts index 6abe81441..45ac9ba86 100644 --- a/drizzle-orm/src/pg-core/columns/real.ts +++ b/drizzle-orm/src/pg-core/columns/real.ts @@ -52,6 +52,8 @@ export class PgReal> extends PgCo }; } -export function real(name: TName): PgRealBuilderInitial { - return new PgRealBuilder(name); +export function real(): PgRealBuilderInitial<''>; +export function real(name: TName): PgRealBuilderInitial; +export function real(name?: TName): PgRealBuilderInitial { + return new PgRealBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/serial.ts b/drizzle-orm/src/pg-core/columns/serial.ts index a15619a87..0a8eaf223 100644 --- a/drizzle-orm/src/pg-core/columns/serial.ts +++ b/drizzle-orm/src/pg-core/columns/serial.ts @@ -49,6 +49,8 @@ export class PgSerial> extends } } -export function serial(name: TName): PgSerialBuilderInitial { - return new PgSerialBuilder(name) as PgSerialBuilderInitial; +export function serial(): PgSerialBuilderInitial<''>; +export function serial(name: TName): PgSerialBuilderInitial +export function serial(name?: TName): PgSerialBuilderInitial { + return new PgSerialBuilder(name ?? '') as PgSerialBuilderInitial; } diff --git a/drizzle-orm/src/pg-core/columns/smallint.ts b/drizzle-orm/src/pg-core/columns/smallint.ts index 4a500bf5c..d22ef42b2 100644 --- a/drizzle-orm/src/pg-core/columns/smallint.ts +++ b/drizzle-orm/src/pg-core/columns/smallint.ts @@ -20,7 +20,7 @@ export class PgSmallIntBuilder> exte }; } -export function smallint(name: TName): PgSmallIntBuilderInitial { - return new PgSmallIntBuilder(name); +export function smallint(): PgSmallIntBuilderInitial<''>; +export function smallint(name: TName): PgSmallIntBuilderInitial; +export function smallint(name?: TName): PgSmallIntBuilderInitial { + return new PgSmallIntBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/smallserial.ts b/drizzle-orm/src/pg-core/columns/smallserial.ts index 02acbb87f..27dc27e17 100644 --- a/drizzle-orm/src/pg-core/columns/smallserial.ts +++ b/drizzle-orm/src/pg-core/columns/smallserial.ts @@ -54,6 +54,8 @@ export class PgSmallSerial } } -export function smallserial(name: TName): PgSmallSerialBuilderInitial { - return new PgSmallSerialBuilder(name) as PgSmallSerialBuilderInitial; +export function smallserial(): PgSmallSerialBuilderInitial<''> +export function smallserial(name: TName): PgSmallSerialBuilderInitial; +export function smallserial(name?: TName): PgSmallSerialBuilderInitial { + return new PgSmallSerialBuilder(name ?? '') as PgSmallSerialBuilderInitial; } diff --git a/drizzle-orm/src/pg-core/columns/uuid.ts b/drizzle-orm/src/pg-core/columns/uuid.ts index 24907ce99..b42e1c030 100644 --- a/drizzle-orm/src/pg-core/columns/uuid.ts +++ b/drizzle-orm/src/pg-core/columns/uuid.ts @@ -18,7 +18,7 @@ export type PgUUIDBuilderInitial = PgUUIDBuilder<{ export class PgUUIDBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgUUIDBuilder'; - constructor(name: T['name']) { + constructor(name: string) { super(name, 'string', 'PgUUID'); } @@ -45,6 +45,8 @@ export class PgUUID> extends PgCo } } -export function uuid(name: TName): PgUUIDBuilderInitial { - return new PgUUIDBuilder(name); +export function uuid(): PgUUIDBuilderInitial<''>; +export function uuid(name: TName): PgUUIDBuilderInitial; +export function uuid(name?: TName): PgUUIDBuilderInitial { + return new PgUUIDBuilder(name ?? ''); } From 2ff73363db9aec5f05669d36906db4dced8f228f Mon Sep 17 00:00:00 2001 From: Mario564 Date: Thu, 1 Aug 2024 20:11:47 -0700 Subject: [PATCH 025/492] Update postgis column types --- .../columns/postgis_extension/geometry.ts | 19 ++++++++++----- .../pg-core/columns/postgis_extension/line.ts | 20 ++++++++++++---- .../columns/postgis_extension/point.ts | 23 ++++++++++++++----- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts index 5dc2b8955..f0d6739bc 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import type { Equal } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; import { parseEWKB } from './utils.ts'; @@ -104,14 +104,21 @@ interface PgGeometryConfig { srid?: number; } +export function geometry(): PgGeometryBuilderInitial<''>; +export function geometry( + config?: PgGeometryConfig, +): Equal extends true ? PgGeometryObjectBuilderInitial<''> : PgGeometryBuilderInitial<''>; export function geometry( name: TName, config?: PgGeometryConfig, -): Equal extends true ? PgGeometryObjectBuilderInitial - : PgGeometryBuilderInitial; -export function geometry(name: string, config?: PgGeometryConfig) { +): Equal extends true ? PgGeometryObjectBuilderInitial : PgGeometryBuilderInitial; +export function geometry( + a?: TName | PgGeometryConfig, + b?: PgGeometryConfig, +): Equal extends true ? PgGeometryObjectBuilderInitial : PgGeometryBuilderInitial { + const { name, config } = getColumnNameAndConfig>(a, b); if (!config?.mode || config.mode === 'tuple') { - return new PgGeometryBuilder(name); + return new PgGeometryBuilder(name) as any; } - return new PgGeometryObjectBuilder(name); + return new PgGeometryObjectBuilder(name) as any; } diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts index e3eb5db22..54201af22 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import type { Equal } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; export type PgLineBuilderInitial = PgLineBuilder<{ @@ -100,15 +100,25 @@ export interface PgLineTypeConfig { mode?: T; } +export function line(): PgLineBuilderInitial<''>; +export function line( + config?: PgLineTypeConfig, +): Equal extends true ? PgLineABCBuilderInitial<''> + : PgLineBuilderInitial<''>; export function line( name: TName, config?: PgLineTypeConfig, ): Equal extends true ? PgLineABCBuilderInitial : PgLineBuilderInitial; -export function line(name: string, config?: PgLineTypeConfig) { +export function line( + a?: TName | PgLineTypeConfig, + b?: PgLineTypeConfig, +): Equal extends true ? PgLineABCBuilderInitial + : PgLineBuilderInitial +{ + const { name, config } = getColumnNameAndConfig>(a, b); if (!config?.mode || config.mode === 'tuple') { - return new PgLineBuilder(name); + return new PgLineBuilder(name) as any; } - - return new PgLineABCBuilder(name); + return new PgLineABCBuilder(name) as any; } diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts index f38f7532f..d408e1c7f 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import type { Equal } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; export type PgPointTupleBuilderInitial = PgPointTupleBuilder<{ @@ -21,7 +21,7 @@ export class PgPointTupleBuilder { mode?: T; } +export function point(): PgPointTupleBuilderInitial<''>; +export function point( + config?: PgPointConfig, +): Equal extends true ? PgPointObjectBuilderInitial<''> + : PgPointTupleBuilderInitial<''>; export function point( name: TName, config?: PgPointConfig, ): Equal extends true ? PgPointObjectBuilderInitial : PgPointTupleBuilderInitial; -export function point(name: string, config?: PgPointConfig) { +export function point( + a?: TName | PgPointConfig, + b?: PgPointConfig, +): Equal extends true ? PgPointObjectBuilderInitial + : PgPointTupleBuilderInitial +{ + const { name, config } = getColumnNameAndConfig>(a, b); if (!config?.mode || config.mode === 'tuple') { - return new PgPointTupleBuilder(name); + return new PgPointTupleBuilder(name) as any; } - return new PgPointObjectBuilder(name); + return new PgPointObjectBuilder(name) as any; } From 03ed297a954e6c7e1999f7ace2061af53cb9fa8d Mon Sep 17 00:00:00 2001 From: Mario564 Date: Thu, 1 Aug 2024 20:35:44 -0700 Subject: [PATCH 026/492] Update PG vector column types --- drizzle-orm/src/pg-core/columns/vector_extension/bit.ts | 9 +++++++++ .../src/pg-core/columns/vector_extension/halfvec.ts | 9 +++++++++ .../src/pg-core/columns/vector_extension/sparsevec.ts | 9 +++++++++ .../src/pg-core/columns/vector_extension/vector.ts | 9 +++++++++ 4 files changed, 36 insertions(+) diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts index 95d60e7d8..97d1a30d2 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type PgBinaryVectorBuilderInitial = PgBinaryVectorBuilder<{ name: TName; @@ -54,9 +55,17 @@ export interface PgBinaryVectorConfig { dimensions: number; } +export function bit( + config: PgBinaryVectorConfig, +): PgBinaryVectorBuilderInitial<''>; export function bit( name: TName, config: PgBinaryVectorConfig, +): PgBinaryVectorBuilderInitial; +export function bit( + a: TName | PgBinaryVectorConfig, + b?: PgBinaryVectorConfig, ): PgBinaryVectorBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new PgBinaryVectorBuilder(name, config); } diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts index 182beda7e..65fe6d501 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type PgHalfVectorBuilderInitial = PgHalfVectorBuilder<{ name: TName; @@ -63,9 +64,17 @@ export interface PgHalfVectorConfig { dimensions: number; } +export function halfvec( + config: PgHalfVectorConfig, +): PgHalfVectorBuilderInitial<''>; export function halfvec( name: TName, config: PgHalfVectorConfig, +): PgHalfVectorBuilderInitial; +export function halfvec( + a: TName | PgHalfVectorConfig, + b?: PgHalfVectorConfig, ): PgHalfVectorBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new PgHalfVectorBuilder(name, config); } diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts index 060003bc6..3da6e49e8 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type PgSparseVectorBuilderInitial = PgSparseVectorBuilder<{ name: TName; @@ -54,9 +55,17 @@ export interface PgSparseVectorConfig { dimensions: number; } +export function sparsevec( + config: PgSparseVectorConfig, +): PgSparseVectorBuilderInitial<''>; export function sparsevec( name: TName, config: PgSparseVectorConfig, +): PgSparseVectorBuilderInitial; +export function sparsevec( + a: TName | PgSparseVectorConfig, + b?: PgSparseVectorConfig, ): PgSparseVectorBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new PgSparseVectorBuilder(name, config); } diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts index c7099b5dc..ff5eb7485 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type PgVectorBuilderInitial = PgVectorBuilder<{ name: TName; @@ -60,9 +61,17 @@ export interface PgVectorConfig { dimensions: number; } +export function vector( + config: PgVectorConfig, +): PgVectorBuilderInitial<''>; export function vector( name: TName, config: PgVectorConfig, +): PgVectorBuilderInitial; +export function vector( + a: TName | PgVectorConfig, + b?: PgVectorConfig, ): PgVectorBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new PgVectorBuilder(name, config); } From 0f17114bc7283c623c7fe00dda669abace955f3e Mon Sep 17 00:00:00 2001 From: Mario564 Date: Thu, 1 Aug 2024 20:51:09 -0700 Subject: [PATCH 027/492] Update the rest of PG columns --- drizzle-orm/src/pg-core/columns/bigint.ts | 14 ++++++-- drizzle-orm/src/pg-core/columns/char.ts | 13 ++++++-- drizzle-orm/src/pg-core/columns/cidr.ts | 8 +++-- drizzle-orm/src/pg-core/columns/custom.ts | 35 ++++++++++++-------- drizzle-orm/src/pg-core/columns/date.ts | 19 ++++++++--- drizzle-orm/src/pg-core/columns/enum.ts | 6 ++-- drizzle-orm/src/pg-core/columns/interval.ts | 12 ++++++- drizzle-orm/src/pg-core/columns/numeric.ts | 25 ++++++++++++++ drizzle-orm/src/pg-core/columns/text.ts | 15 +++++++-- drizzle-orm/src/pg-core/columns/time.ts | 9 +++-- drizzle-orm/src/pg-core/columns/timestamp.ts | 19 +++++++---- 11 files changed, 135 insertions(+), 40 deletions(-) diff --git a/drizzle-orm/src/pg-core/columns/bigint.ts b/drizzle-orm/src/pg-core/columns/bigint.ts index 81f40d4e9..8fb8262fd 100644 --- a/drizzle-orm/src/pg-core/columns/bigint.ts +++ b/drizzle-orm/src/pg-core/columns/bigint.ts @@ -5,6 +5,7 @@ import type { AnyPgTable } from '~/pg-core/table.ts'; import { PgColumn } from './common.ts'; import { PgIntColumnBaseBuilder } from './int.common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type PgBigInt53BuilderInitial = PgBigInt53Builder<{ name: TName; @@ -95,13 +96,20 @@ interface PgBigIntConfig { mode: T; } +export function bigint( + config: PgBigIntConfig, +): TMode extends 'number' ? PgBigInt53BuilderInitial<''> : PgBigInt64BuilderInitial<''>; export function bigint( name: TName, config: PgBigIntConfig, ): TMode extends 'number' ? PgBigInt53BuilderInitial : PgBigInt64BuilderInitial; -export function bigint(name: string, config: PgBigIntConfig) { +export function bigint( + a: TName | PgBigIntConfig, + b?: PgBigIntConfig, +): TMode extends 'number' ? PgBigInt53BuilderInitial : PgBigInt64BuilderInitial { + const { name, config } = getColumnNameAndConfig>(a, b); if (config.mode === 'number') { - return new PgBigInt53Builder(name); + return new PgBigInt53Builder(name) as any; } - return new PgBigInt64Builder(name); + return new PgBigInt64Builder(name) as any; } diff --git a/drizzle-orm/src/pg-core/columns/char.ts b/drizzle-orm/src/pg-core/columns/char.ts index 9f33de4ae..e510805a7 100644 --- a/drizzle-orm/src/pg-core/columns/char.ts +++ b/drizzle-orm/src/pg-core/columns/char.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import type { Writable } from '~/utils.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; export type PgCharBuilderInitial = PgCharBuilder<{ @@ -53,9 +53,18 @@ export interface PgCharConfig; +export function char>( + config?: PgCharConfig>, +): PgCharBuilderInitial<'', Writable>; export function char>( name: TName, - config: PgCharConfig> = {}, + config?: PgCharConfig>, +): PgCharBuilderInitial>; +export function char>( + a?: TName | PgCharConfig>, + b: PgCharConfig> = {}, ): PgCharBuilderInitial> { + const { name, config } = getColumnNameAndConfig>>(a, b); return new PgCharBuilder(name, config); } diff --git a/drizzle-orm/src/pg-core/columns/cidr.ts b/drizzle-orm/src/pg-core/columns/cidr.ts index 9c2e9e19f..08093eb2b 100644 --- a/drizzle-orm/src/pg-core/columns/cidr.ts +++ b/drizzle-orm/src/pg-core/columns/cidr.ts @@ -17,7 +17,7 @@ export type PgCidrBuilderInitial = PgCidrBuilder<{ export class PgCidrBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgCidrBuilder'; - constructor(name: T['name']) { + constructor(name: string) { super(name, 'string', 'PgCidr'); } @@ -37,6 +37,8 @@ export class PgCidr> extends PgCo } } -export function cidr(name: TName): PgCidrBuilderInitial { - return new PgCidrBuilder(name); +export function cidr(): PgCidrBuilderInitial<''>; +export function cidr(name: TName): PgCidrBuilderInitial; +export function cidr(name?: TName): PgCidrBuilderInitial { + return new PgCidrBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/custom.ts b/drizzle-orm/src/pg-core/columns/custom.ts index 4249e326c..c6c1d4540 100644 --- a/drizzle-orm/src/pg-core/columns/custom.ts +++ b/drizzle-orm/src/pg-core/columns/custom.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import type { SQL } from '~/sql/sql.ts'; -import type { Equal } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; export type ConvertCustomConfig> = @@ -108,7 +108,7 @@ export type CustomTypeValues = { /** * What config type should be used for {@link CustomTypeParams} `dataType` generation */ - config?: unknown; + config?: Record; /** * Whether the config argument should be required or not @@ -203,19 +203,28 @@ export interface CustomTypeParams { */ export function customType( customTypeParams: CustomTypeParams, -): Equal extends true ? ( - dbName: TName, - fieldConfig: T['config'], - ) => PgCustomColumnBuilder> - : ( - dbName: TName, - fieldConfig?: T['config'], - ) => PgCustomColumnBuilder> +): Equal extends true ? { + & T['config']>( + fieldConfig: TConfig, + ): PgCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig: T['config'], + ): PgCustomColumnBuilder>; + } : { + (): PgCustomColumnBuilder>; + (fieldConfig?: T['config']): PgCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig?: T['config'], + ): PgCustomColumnBuilder>; + } { return ( - dbName: TName, - fieldConfig?: T['config'], + a?: TName | T['config'], + b?: T['config'], ): PgCustomColumnBuilder> => { - return new PgCustomColumnBuilder(dbName as ConvertCustomConfig['name'], fieldConfig, customTypeParams); + const { name, config } = getColumnNameAndConfig(a, b); + return new PgCustomColumnBuilder(name as ConvertCustomConfig['name'], config, customTypeParams); }; } diff --git a/drizzle-orm/src/pg-core/columns/date.ts b/drizzle-orm/src/pg-core/columns/date.ts index 3c0107c3c..04ebac791 100644 --- a/drizzle-orm/src/pg-core/columns/date.ts +++ b/drizzle-orm/src/pg-core/columns/date.ts @@ -4,6 +4,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import { PgColumn } from './common.ts'; import { PgDateColumnBaseBuilder } from './date.common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type PgDateBuilderInitial = PgDateBuilder<{ name: TName; @@ -84,14 +85,24 @@ export class PgDateString> } } +export function date(): PgDateStringBuilderInitial<''>; +export function date(config?: { mode: 'string' }): PgDateStringBuilderInitial<''>; +export function date(config?: { mode: 'date' }): PgDateBuilderInitial<''>; export function date( name: TName, config?: { mode: 'string' }, ): PgDateStringBuilderInitial; -export function date(TName: TName, config?: { mode: 'date' }): PgDateBuilderInitial; -export function date(name: TName, config?: { mode: 'date' | 'string' }) { +export function date( + name: TName, + config?: { mode: 'date' } +): PgDateBuilderInitial; +export function date( + a?: TName | { mode: 'date' | 'string' }, + b?: { mode: 'date' | 'string' } +): PgDateBuilderInitial | PgDateStringBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); if (config?.mode === 'date') { - return new PgDateBuilder(name); + return new PgDateBuilder(name) as any; } - return new PgDateStringBuilder(name); + return new PgDateStringBuilder(name) as any; } diff --git a/drizzle-orm/src/pg-core/columns/enum.ts b/drizzle-orm/src/pg-core/columns/enum.ts index 9fbdc15c1..2c4821933 100644 --- a/drizzle-orm/src/pg-core/columns/enum.ts +++ b/drizzle-orm/src/pg-core/columns/enum.ts @@ -18,7 +18,9 @@ export type PgEnumColumnBuilderInitial { + (): PgEnumColumnBuilderInitial<'', TValues>; (name: TName): PgEnumColumnBuilderInitial; + (name?: TName): PgEnumColumnBuilderInitial; readonly enumName: string; readonly enumValues: TValues; @@ -88,8 +90,8 @@ export function pgEnumWithSchema> { const enumInstance: PgEnum> = Object.assign( - (name: TName): PgEnumColumnBuilderInitial> => - new PgEnumColumnBuilder(name, enumInstance), + (name?: TName): PgEnumColumnBuilderInitial> => + new PgEnumColumnBuilder(name ?? '', enumInstance), { enumName, enumValues: values, diff --git a/drizzle-orm/src/pg-core/columns/interval.ts b/drizzle-orm/src/pg-core/columns/interval.ts index c70dd0c04..9730d43e1 100644 --- a/drizzle-orm/src/pg-core/columns/interval.ts +++ b/drizzle-orm/src/pg-core/columns/interval.ts @@ -4,6 +4,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; import type { Precision } from './timestamp.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type PgIntervalBuilderInitial = PgIntervalBuilder<{ name: TName; @@ -69,9 +70,18 @@ export interface IntervalConfig { precision?: Precision; } +export function interval(): PgIntervalBuilderInitial<''>; +export function interval( + config?: IntervalConfig, +): PgIntervalBuilderInitial<''>; export function interval( name: TName, - config: IntervalConfig = {}, + config?: IntervalConfig, +): PgIntervalBuilderInitial; +export function interval( + a?: TName | IntervalConfig, + b: IntervalConfig = {}, ): PgIntervalBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new PgIntervalBuilder(name, config); } diff --git a/drizzle-orm/src/pg-core/columns/numeric.ts b/drizzle-orm/src/pg-core/columns/numeric.ts index d740c1a4a..e84b0eb46 100644 --- a/drizzle-orm/src/pg-core/columns/numeric.ts +++ b/drizzle-orm/src/pg-core/columns/numeric.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type PgNumericBuilderInitial = PgNumericBuilder<{ name: TName; @@ -60,13 +61,37 @@ export class PgNumeric> extend } } +export function numeric(): PgNumericBuilderInitial<''>; +export function numeric( + config?: + | { precision: number; scale?: number } + | { precision?: number; scale: number } + | { precision: number; scale: number }, +): PgNumericBuilderInitial<''>; export function numeric( name: TName, config?: | { precision: number; scale?: number } | { precision?: number; scale: number } | { precision: number; scale: number }, +): PgNumericBuilderInitial; +export function numeric( + a?: + | TName + | { precision: number; scale?: number } + | { precision?: number; scale: number } + | { precision: number; scale: number }, + b?: + | { precision: number; scale?: number } + | { precision?: number; scale: number } + | { precision: number; scale: number }, ): PgNumericBuilderInitial { + const { name, config } = getColumnNameAndConfig< + TName, + | { precision: number; scale?: number } + | { precision?: number; scale: number } + | { precision: number; scale: number } + >(a, b); return new PgNumericBuilder(name, config?.precision, config?.scale); } diff --git a/drizzle-orm/src/pg-core/columns/text.ts b/drizzle-orm/src/pg-core/columns/text.ts index 47c3c9045..75ecac69d 100644 --- a/drizzle-orm/src/pg-core/columns/text.ts +++ b/drizzle-orm/src/pg-core/columns/text.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import type { Writable } from '~/utils.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; type PgTextBuilderInitial = PgTextBuilder<{ @@ -21,7 +21,7 @@ export class PgTextBuilder< static readonly [entityKind]: string = 'PgTextBuilder'; constructor( - name: T['name'], + name: string, config: PgTextConfig, ) { super(name, 'string', 'PgText'); @@ -52,9 +52,18 @@ export interface PgTextConfig; +export function text>( + config?: PgTextConfig>, +): PgTextBuilderInitial<'', Writable>; export function text>( name: TName, - config: PgTextConfig> = {}, + config?: PgTextConfig>, +): PgTextBuilderInitial>; +export function text>( + a?: TName | PgTextConfig>, + b: PgTextConfig> = {}, ): PgTextBuilderInitial> { + const { name, config } = getColumnNameAndConfig>>(a, b); return new PgTextBuilder(name, config); } diff --git a/drizzle-orm/src/pg-core/columns/time.ts b/drizzle-orm/src/pg-core/columns/time.ts index fe82c9142..8ab669f64 100644 --- a/drizzle-orm/src/pg-core/columns/time.ts +++ b/drizzle-orm/src/pg-core/columns/time.ts @@ -5,6 +5,7 @@ import type { AnyPgTable } from '~/pg-core/table.ts'; import { PgColumn } from './common.ts'; import { PgDateColumnBaseBuilder } from './date.common.ts'; import type { Precision } from './timestamp.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type PgTimeBuilderInitial = PgTimeBuilder<{ name: TName; @@ -23,7 +24,7 @@ export class PgTimeBuilder static readonly [entityKind]: string = 'PgTimeBuilder'; constructor( - name: T['name'], + name: string, readonly withTimezone: boolean, readonly precision: number | undefined, ) { @@ -63,6 +64,10 @@ export interface TimeConfig { withTimezone?: boolean; } -export function time(name: TName, config: TimeConfig = {}): PgTimeBuilderInitial { +export function time(): PgTimeBuilderInitial<''>; +export function time(config?: TimeConfig): PgTimeBuilderInitial<''>; +export function time(name: TName, config?: TimeConfig): PgTimeBuilderInitial; +export function time(a?: TName, b: TimeConfig = {}): PgTimeBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new PgTimeBuilder(name, config.withTimezone ?? false, config.precision); } diff --git a/drizzle-orm/src/pg-core/columns/timestamp.ts b/drizzle-orm/src/pg-core/columns/timestamp.ts index 8293f9472..cd4d03421 100644 --- a/drizzle-orm/src/pg-core/columns/timestamp.ts +++ b/drizzle-orm/src/pg-core/columns/timestamp.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import type { Equal } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; import { PgColumn } from './common.ts'; import { PgDateColumnBaseBuilder } from './date.common.ts'; @@ -133,16 +133,21 @@ export interface PgTimestampConfig; +export function timestamp( + config?: PgTimestampConfig, +): Equal extends true ? PgTimestampStringBuilderInitial<''> : PgTimestampBuilderInitial<''>; export function timestamp( name: TName, config?: PgTimestampConfig, ): Equal extends true ? PgTimestampStringBuilderInitial : PgTimestampBuilderInitial; -export function timestamp( - name: string, - config: PgTimestampConfig = {}, -) { +export function timestamp( + a?: TName | PgTimestampConfig, + b: PgTimestampConfig = {}, +): Equal extends true ? PgTimestampStringBuilderInitial : PgTimestampBuilderInitial { + const { name, config } = getColumnNameAndConfig>(a, b); if (config.mode === 'string') { - return new PgTimestampStringBuilder(name, config.withTimezone ?? false, config.precision); + return new PgTimestampStringBuilder(name, config.withTimezone ?? false, config.precision) as any; } - return new PgTimestampBuilder(name, config.withTimezone ?? false, config.precision); + return new PgTimestampBuilder(name, config.withTimezone ?? false, config.precision) as any; } From 190a29b6ec073acbc9a1977c6a9d5e324b3ec61a Mon Sep 17 00:00:00 2001 From: Mario564 Date: Thu, 1 Aug 2024 21:09:57 -0700 Subject: [PATCH 028/492] Improve types --- drizzle-orm/src/pg-core/columns/bigint.ts | 2 +- drizzle-orm/src/pg-core/columns/bigserial.ts | 2 +- drizzle-orm/src/pg-core/columns/date.ts | 31 ++++++++--------- drizzle-orm/src/pg-core/columns/numeric.ts | 33 ++++++------------- .../columns/postgis_extension/geometry.ts | 2 +- 5 files changed, 29 insertions(+), 41 deletions(-) diff --git a/drizzle-orm/src/pg-core/columns/bigint.ts b/drizzle-orm/src/pg-core/columns/bigint.ts index 8fb8262fd..f6a53c28b 100644 --- a/drizzle-orm/src/pg-core/columns/bigint.ts +++ b/drizzle-orm/src/pg-core/columns/bigint.ts @@ -92,7 +92,7 @@ export class PgBigInt64> exte } } -interface PgBigIntConfig { +export interface PgBigIntConfig { mode: T; } diff --git a/drizzle-orm/src/pg-core/columns/bigserial.ts b/drizzle-orm/src/pg-core/columns/bigserial.ts index 40ccdfcec..8c53fb686 100644 --- a/drizzle-orm/src/pg-core/columns/bigserial.ts +++ b/drizzle-orm/src/pg-core/columns/bigserial.ts @@ -110,7 +110,7 @@ export class PgBigSerial64 } } -interface PgBigSerialConfig { +export interface PgBigSerialConfig { mode: T; } diff --git a/drizzle-orm/src/pg-core/columns/date.ts b/drizzle-orm/src/pg-core/columns/date.ts index 04ebac791..d3caf5442 100644 --- a/drizzle-orm/src/pg-core/columns/date.ts +++ b/drizzle-orm/src/pg-core/columns/date.ts @@ -4,7 +4,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import { PgColumn } from './common.ts'; import { PgDateColumnBaseBuilder } from './date.common.ts'; -import { getColumnNameAndConfig } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; export type PgDateBuilderInitial = PgDateBuilder<{ name: TName; @@ -85,22 +85,23 @@ export class PgDateString> } } +export interface PgDateConfig { + mode: T; +} + export function date(): PgDateStringBuilderInitial<''>; -export function date(config?: { mode: 'string' }): PgDateStringBuilderInitial<''>; -export function date(config?: { mode: 'date' }): PgDateBuilderInitial<''>; -export function date( - name: TName, - config?: { mode: 'string' }, -): PgDateStringBuilderInitial; -export function date( +export function date( + config?: PgDateConfig, +): Equal extends true ? PgDateBuilderInitial<''> : PgDateStringBuilderInitial<''>; +export function date( name: TName, - config?: { mode: 'date' } -): PgDateBuilderInitial; -export function date( - a?: TName | { mode: 'date' | 'string' }, - b?: { mode: 'date' | 'string' } -): PgDateBuilderInitial | PgDateStringBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); + config?: PgDateConfig, +): Equal extends true ? PgDateBuilderInitial : PgDateStringBuilderInitial; +export function date( + a?: TName | PgDateConfig, + b?: PgDateConfig, +): Equal extends true ? PgDateBuilderInitial : PgDateStringBuilderInitial { + const { name, config } = getColumnNameAndConfig>(a, b); if (config?.mode === 'date') { return new PgDateBuilder(name) as any; } diff --git a/drizzle-orm/src/pg-core/columns/numeric.ts b/drizzle-orm/src/pg-core/columns/numeric.ts index e84b0eb46..5834b3cbc 100644 --- a/drizzle-orm/src/pg-core/columns/numeric.ts +++ b/drizzle-orm/src/pg-core/columns/numeric.ts @@ -61,37 +61,24 @@ export class PgNumeric> extend } } +export type PgNumericConfig = + | { precision: number; scale?: number } + | { precision?: number; scale: number } + | { precision: number; scale: number }; + export function numeric(): PgNumericBuilderInitial<''>; export function numeric( - config?: - | { precision: number; scale?: number } - | { precision?: number; scale: number } - | { precision: number; scale: number }, + config?: PgNumericConfig, ): PgNumericBuilderInitial<''>; export function numeric( name: TName, - config?: - | { precision: number; scale?: number } - | { precision?: number; scale: number } - | { precision: number; scale: number }, + config?: PgNumericConfig, ): PgNumericBuilderInitial; export function numeric( - a?: - | TName - | { precision: number; scale?: number } - | { precision?: number; scale: number } - | { precision: number; scale: number }, - b?: - | { precision: number; scale?: number } - | { precision?: number; scale: number } - | { precision: number; scale: number }, + a?: TName | PgNumericConfig, + b?: PgNumericConfig, ): PgNumericBuilderInitial { - const { name, config } = getColumnNameAndConfig< - TName, - | { precision: number; scale?: number } - | { precision?: number; scale: number } - | { precision: number; scale: number } - >(a, b); + const { name, config } = getColumnNameAndConfig(a, b); return new PgNumericBuilder(name, config?.precision, config?.scale); } diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts index f0d6739bc..756b43282 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts @@ -98,7 +98,7 @@ export class PgGeometryObject { +export interface PgGeometryConfig { mode?: T; type?: 'point' | (string & {}); srid?: number; From 66fd97ca257663c37a8310d3984275e046d8e806 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Thu, 1 Aug 2024 21:10:40 -0700 Subject: [PATCH 029/492] Add type tests --- drizzle-orm/type-tests/pg/tables.ts | 132 +++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index 5faca5d7b..20d3e56b2 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -6,6 +6,7 @@ import { eq, gt } from '~/expressions.ts'; import { bigint, bigserial, + bit, boolean, char, check, @@ -15,11 +16,14 @@ import { decimal, doublePrecision, foreignKey, + geometry, + halfvec, index, inet, integer, json, jsonb, + line, macaddr, macaddr8, numeric, @@ -27,17 +31,20 @@ import { pgEnum, pgTable, type PgTableWithColumns, + point, primaryKey, real, serial, smallint, smallserial, + sparsevec, text, time, timestamp, uniqueIndex, uuid, varchar, + vector, } from '~/pg-core/index.ts'; import { pgSchema } from '~/pg-core/schema.ts'; import { @@ -872,8 +879,11 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); }); customTextRequired('t', { length: 10 }); + customTextRequired({ length: 10 }); // @ts-expect-error - config is required customTextRequired('t'); + // @ts-expect-error - config is required + customTextRequired(); } { @@ -900,6 +910,8 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); customTextOptional('t', { length: 10 }); customTextOptional('t'); + customTextOptional({ length: 10 }); + customTextOptional(); } { @@ -1180,7 +1192,11 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); } { + const enum_ = pgEnum('enum', ['a', 'b', 'c']); + pgTable('all_columns', { + enum: enum_('enum'), + enumdef: enum_('enumdef').default('a'), sm: smallint('smallint'), smdef: smallint('smallint_def').default(10), int: integer('integer'), @@ -1212,13 +1228,125 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); jsonbdef: jsonb('jsonbdef').$type<{ attr: string }>().default({ attr: 'value' }), time: time('time'), time2: time('time2', { precision: 6, withTimezone: true }), + timedef: time('timedef').default('00:00:00'), timedefnow: time('timedefnow').defaultNow(), timestamp: timestamp('timestamp'), timestamp2: timestamp('timestamp2', { precision: 6, withTimezone: true }), timestamp3: timestamp('timestamp3', { withTimezone: true }), timestamp4: timestamp('timestamp4', { precision: 4 }), - timestampdef: timestamp('timestampdef').defaultNow(), + timestampdef: timestamp('timestampdef').default(new Date()), date: date('date', { mode: 'date' }), - datedef: date('datedef').defaultNow(), + datedef: date('datedef').default('2024-01-01'), + datedefnow: date('datedefnow').defaultNow(), + }); + + pgTable('all_postgis_columns', { + geometry: geometry('geometry'), + geometry2: geometry('geometry2', { srid: 2, mode: 'xy' }), + geometry3: geometry('geometry3', { srid: 3, mode: 'tuple' }), + geometry4: geometry('geometry4', { mode: 'tuple' }), + geometrydef: geometry('geometrydef').default([1, 2]), + point: point('point'), + point2: point('point2', { mode: 'xy' }), + pointdef: point('pointdef').default([1, 2]), + line: line('line'), + line2: line('line2', { mode: 'abc' }), + linedef: line('linedef').default([1, 2, 3]), + }); + + pgTable('all_vector_columns', { + bit: bit('bit', { dimensions: 1 }), + bitdef: bit('bitdef', { dimensions: 1 }).default('1'), + halfvec: halfvec('halfvec', { dimensions: 1 }), + halfvecdef: halfvec('halfvecdef', { dimensions: 1 }).default([1]), + sparsevec: sparsevec('sparsevec', { dimensions: 1 }), + sparsevecdef: sparsevec('sparsevecdef', { dimensions: 1 }).default('{1:1}/1'), + vector: vector('vector', { dimensions: 1 }), + vectordef: vector('vectordef', { dimensions: 1 }).default([1]), + }); +} + +{ + const keysAsColumnNames = pgTable('a', { + id: serial(), + name: text() }); + + Expect>; + Expect>; } + +{ + const enum_ = pgEnum('enum', ['a', 'b', 'c']); + + pgTable('all_columns_without_name', { + enum: enum_(), + enumdef: enum_().default('a'), + sm: smallint(), + smdef: smallint().default(10), + int: integer(), + intdef: integer().default(10), + numeric: numeric(), + numeric2: numeric({ precision: 5 }), + numeric3: numeric({ scale: 2 }), + numeric4: numeric({ precision: 5, scale: 2 }), + numericdef: numeric().default('100'), + bigint: bigint({ mode: 'number' }), + bigintdef: bigint({ mode: 'number' }).default(100), + bool: boolean(), + booldef: boolean().default(true), + text: text(), + textdef: text().default('text'), + varchar: varchar(), + varchardef: varchar().default('text'), + serial: serial(), + bigserial: bigserial({ mode: 'number' }), + decimal: decimal({ precision: 100, scale: 2 }), + decimaldef: decimal({ precision: 100, scale: 2 }).default('100.0'), + doublePrecision: doublePrecision(), + doublePrecisiondef: doublePrecision().default(100), + real: real(), + realdef: real().default(100), + json: json().$type<{ attr: string }>(), + jsondef: json().$type<{ attr: string }>().default({ attr: 'value' }), + jsonb: jsonb().$type<{ attr: string }>(), + jsonbdef: jsonb().$type<{ attr: string }>().default({ attr: 'value' }), + time: time(), + time2: time({ precision: 6, withTimezone: true }), + timedef: time().default('00:00:00'), + timedefnow: time().defaultNow(), + timestamp: timestamp(), + timestamp2: timestamp({ precision: 6, withTimezone: true }), + timestamp3: timestamp({ withTimezone: true }), + timestamp4: timestamp({ precision: 4 }), + timestampdef: timestamp().default(new Date()), + date: date({ mode: 'date' }), + datedef: date().default('2024-01-01'), + datedefnow: date().defaultNow(), + }); + + pgTable('all_postgis_columns', { + geometry: geometry(), + geometry2: geometry({ srid: 2, mode: 'xy' }), + geometry3: geometry({ srid: 3, mode: 'tuple' }), + geometry4: geometry({ mode: 'tuple' }), + geometrydef: geometry().default([1, 2]), + point: point(), + point2: point({ mode: 'xy' }), + pointdef: point().default([1, 2]), + line: line(), + line2: line({ mode: 'abc' }), + linedef: line().default([1, 2, 3]), + }); + + pgTable('all_vector_columns', { + bit: bit({ dimensions: 1 }), + bitdef: bit({ dimensions: 1 }).default('1'), + halfvec: halfvec({ dimensions: 1 }), + halfvecdef: halfvec({ dimensions: 1 }).default([1]), + sparsevec: sparsevec({ dimensions: 1 }), + sparsevecdef: sparsevec({ dimensions: 1 }).default('{1:1}/1'), + vector: vector({ dimensions: 1 }), + vectordef: vector({ dimensions: 1 }).default([1]), + }); +} \ No newline at end of file From d538929c051c2f404376b7d2688096dc993c80f8 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Sun, 4 Aug 2024 12:27:55 -0700 Subject: [PATCH 030/492] Update MySQL columns --- drizzle-orm/src/mysql-core/columns/bigint.ts | 18 ++++++-- drizzle-orm/src/mysql-core/columns/binary.ts | 14 +++++- drizzle-orm/src/mysql-core/columns/boolean.ts | 8 ++-- drizzle-orm/src/mysql-core/columns/char.ts | 13 +++++- drizzle-orm/src/mysql-core/columns/common.ts | 6 +++ drizzle-orm/src/mysql-core/columns/custom.ts | 37 +++++++++------ drizzle-orm/src/mysql-core/columns/date.ts | 16 +++++-- .../src/mysql-core/columns/datetime.ts | 16 +++++-- drizzle-orm/src/mysql-core/columns/decimal.ts | 12 ++++- drizzle-orm/src/mysql-core/columns/double.ts | 10 ++++ drizzle-orm/src/mysql-core/columns/enum.ts | 11 ++++- drizzle-orm/src/mysql-core/columns/float.ts | 8 ++-- drizzle-orm/src/mysql-core/columns/int.ts | 17 ++++++- drizzle-orm/src/mysql-core/columns/json.ts | 8 ++-- .../src/mysql-core/columns/mediumint.ts | 10 ++++ drizzle-orm/src/mysql-core/columns/real.ts | 15 +++++- drizzle-orm/src/mysql-core/columns/serial.ts | 8 ++-- .../src/mysql-core/columns/smallint.ts | 10 ++++ drizzle-orm/src/mysql-core/columns/text.ts | 46 +++++++++++++++++-- drizzle-orm/src/mysql-core/columns/time.ts | 15 +++++- .../src/mysql-core/columns/timestamp.ts | 19 ++++++-- drizzle-orm/src/mysql-core/columns/tinyint.ts | 15 +++++- .../src/mysql-core/columns/varbinary.ts | 13 +++++- drizzle-orm/src/mysql-core/columns/varchar.ts | 10 +++- drizzle-orm/src/mysql-core/columns/year.ts | 8 ++-- drizzle-orm/src/mysql-core/table.ts | 1 + 26 files changed, 300 insertions(+), 64 deletions(-) diff --git a/drizzle-orm/src/mysql-core/columns/bigint.ts b/drizzle-orm/src/mysql-core/columns/bigint.ts index ca1eedb3f..20af5131e 100644 --- a/drizzle-orm/src/mysql-core/columns/bigint.ts +++ b/drizzle-orm/src/mysql-core/columns/bigint.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlBigInt53BuilderInitial = MySqlBigInt53Builder<{ name: TName; @@ -67,7 +68,7 @@ export class MySqlBigInt64Builder } } -interface MySqlBigIntConfig { +export interface MySqlBigIntConfig { mode: T; unsigned?: boolean; } +export function bigint( + config: MySqlBigIntConfig, +): TMode extends 'number' ? MySqlBigInt53BuilderInitial<''> : MySqlBigInt64BuilderInitial<''>; export function bigint( name: TName, config: MySqlBigIntConfig, ): TMode extends 'number' ? MySqlBigInt53BuilderInitial : MySqlBigInt64BuilderInitial; -export function bigint(name: string, config: MySqlBigIntConfig) { +export function bigint( + a?: TName | MySqlBigIntConfig, + b?: MySqlBigIntConfig, +): TMode extends 'number' ? MySqlBigInt53BuilderInitial : MySqlBigInt64BuilderInitial { + const { name, config } = getColumnNameAndConfig>(a, b); if (config.mode === 'number') { - return new MySqlBigInt53Builder(name, config.unsigned); + return new MySqlBigInt53Builder(name, config.unsigned) as any; } - return new MySqlBigInt64Builder(name, config.unsigned); + return new MySqlBigInt64Builder(name, config.unsigned) as any; } diff --git a/drizzle-orm/src/mysql-core/columns/binary.ts b/drizzle-orm/src/mysql-core/columns/binary.ts index 87a8e0f8c..4c70def14 100644 --- a/drizzle-orm/src/mysql-core/columns/binary.ts +++ b/drizzle-orm/src/mysql-core/columns/binary.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlBinaryBuilderInitial = MySqlBinaryBuilder<{ name: TName; @@ -20,7 +21,7 @@ export class MySqlBinaryBuilder { static readonly [entityKind]: string = 'MySqlBinaryBuilder'; - constructor(name: T['name'], length: number | undefined) { + constructor(name: string, length: number | undefined) { super(name, 'string', 'MySqlBinary'); this.config.length = length; } @@ -50,9 +51,18 @@ export interface MySqlBinaryConfig { length?: number; } +export function binary(): MySqlBinaryBuilderInitial<''>; +export function binary( + config?: MySqlBinaryConfig, +): MySqlBinaryBuilderInitial<''>; export function binary( name: TName, - config: MySqlBinaryConfig = {}, + config?: MySqlBinaryConfig, +): MySqlBinaryBuilderInitial; +export function binary( + a?: TName | MySqlBinaryConfig, + b: MySqlBinaryConfig = {}, ): MySqlBinaryBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlBinaryBuilder(name, config.length); } diff --git a/drizzle-orm/src/mysql-core/columns/boolean.ts b/drizzle-orm/src/mysql-core/columns/boolean.ts index 3a915e673..1e01b1cc6 100644 --- a/drizzle-orm/src/mysql-core/columns/boolean.ts +++ b/drizzle-orm/src/mysql-core/columns/boolean.ts @@ -19,7 +19,7 @@ export class MySqlBooleanBuilder> } } -export function boolean(name: TName): MySqlBooleanBuilderInitial { - return new MySqlBooleanBuilder(name); +export function boolean(): MySqlBooleanBuilderInitial<''>; +export function boolean(name: TName): MySqlBooleanBuilderInitial; +export function boolean(name?: TName): MySqlBooleanBuilderInitial { + return new MySqlBooleanBuilder(name ?? ''); } diff --git a/drizzle-orm/src/mysql-core/columns/char.ts b/drizzle-orm/src/mysql-core/columns/char.ts index f871796a5..cbd3285a3 100644 --- a/drizzle-orm/src/mysql-core/columns/char.ts +++ b/drizzle-orm/src/mysql-core/columns/char.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import type { Writable } from '~/utils.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlCharBuilderInitial = MySqlCharBuilder<{ @@ -56,9 +56,18 @@ export interface MySqlCharConfig; +export function char>( + config?: MySqlCharConfig>, +): MySqlCharBuilderInitial<'', Writable>; export function char>( name: TName, - config: MySqlCharConfig> = {}, + config?: MySqlCharConfig>, +): MySqlCharBuilderInitial>; +export function char>( + a?: TName | MySqlCharConfig>, + b: MySqlCharConfig> = {}, ): MySqlCharBuilderInitial> { + const { name, config } = getColumnNameAndConfig>>(a, b); return new MySqlCharBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/common.ts b/drizzle-orm/src/mysql-core/columns/common.ts index a0a192477..c3cf184f7 100644 --- a/drizzle-orm/src/mysql-core/columns/common.ts +++ b/drizzle-orm/src/mysql-core/columns/common.ts @@ -94,6 +94,12 @@ export abstract class MySqlColumnBuilder< abstract build( table: AnyMySqlTable<{ name: TTableName }>, ): MySqlColumn>; + + /** @internal Sets the name of the column to the key within the table definition if a name was not given. */ + setName(name: string) { + if (this.config.name !== '') return; + this.config.name = name; + } } // To understand how to use `MySqlColumn` and `AnyMySqlColumn`, see `Column` and `AnyColumn` documentation. diff --git a/drizzle-orm/src/mysql-core/columns/custom.ts b/drizzle-orm/src/mysql-core/columns/custom.ts index 1c5e2603f..c42a6ca82 100644 --- a/drizzle-orm/src/mysql-core/columns/custom.ts +++ b/drizzle-orm/src/mysql-core/columns/custom.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import type { SQL } from '~/sql/sql.ts'; -import type { Equal } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type ConvertCustomConfig> = @@ -108,7 +108,7 @@ export type CustomTypeValues = { /** * What config type should be used for {@link CustomTypeParams} `dataType` generation */ - config?: unknown; + config?: Record; /** * Whether the config argument should be required or not @@ -203,19 +203,30 @@ export interface CustomTypeParams { */ export function customType( customTypeParams: CustomTypeParams, -): Equal extends true ? ( - dbName: TName, - fieldConfig: T['config'], - ) => MySqlCustomColumnBuilder> - : ( - dbName: TName, - fieldConfig?: T['config'], - ) => MySqlCustomColumnBuilder> +): Equal extends true ? { + & T['config']>( + fieldConfig: TConfig, + ): MySqlCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig: T['config'], + ): MySqlCustomColumnBuilder>; + } : { + (): MySqlCustomColumnBuilder>; + & T['config']>( + fieldConfig?: TConfig, + ): MySqlCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig?: T['config'], + ): MySqlCustomColumnBuilder>; + } { return ( - dbName: TName, - fieldConfig?: T['config'], + a?: TName | T['config'], + b?: T['config'], ): MySqlCustomColumnBuilder> => { - return new MySqlCustomColumnBuilder(dbName as ConvertCustomConfig['name'], fieldConfig, customTypeParams); + const { name, config } = getColumnNameAndConfig(a, b); + return new MySqlCustomColumnBuilder(name as ConvertCustomConfig['name'], config, customTypeParams); }; } diff --git a/drizzle-orm/src/mysql-core/columns/date.ts b/drizzle-orm/src/mysql-core/columns/date.ts index d7e2c409e..14c3e2ba5 100644 --- a/drizzle-orm/src/mysql-core/columns/date.ts +++ b/drizzle-orm/src/mysql-core/columns/date.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import type { Equal } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlDateBuilderInitial = MySqlDateBuilder<{ @@ -98,13 +98,21 @@ export interface MySqlDateConfig; +export function date( + config?: MySqlDateConfig, +): Equal extends true ? MySqlDateStringBuilderInitial<''> : MySqlDateBuilderInitial<''>; export function date( name: TName, config?: MySqlDateConfig, ): Equal extends true ? MySqlDateStringBuilderInitial : MySqlDateBuilderInitial; -export function date(name: string, config: MySqlDateConfig = {}) { +export function date( + a?: TName | MySqlDateConfig, + b?: MySqlDateConfig, +): Equal extends true ? MySqlDateStringBuilderInitial : MySqlDateBuilderInitial { + const { name, config } = getColumnNameAndConfig>(a, b); if (config.mode === 'string') { - return new MySqlDateStringBuilder(name); + return new MySqlDateStringBuilder(name) as any; } - return new MySqlDateBuilder(name); + return new MySqlDateBuilder(name) as any; } diff --git a/drizzle-orm/src/mysql-core/columns/datetime.ts b/drizzle-orm/src/mysql-core/columns/datetime.ts index 040c57130..32c898436 100644 --- a/drizzle-orm/src/mysql-core/columns/datetime.ts +++ b/drizzle-orm/src/mysql-core/columns/datetime.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import type { Equal } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlDateTimeBuilderInitial = MySqlDateTimeBuilder<{ @@ -120,13 +120,21 @@ export interface MySqlDatetimeConfig; +export function datetime( + config?: MySqlDatetimeConfig, +): Equal extends true ? MySqlDateTimeStringBuilderInitial<''> : MySqlDateTimeBuilderInitial<''>; export function datetime( name: TName, config?: MySqlDatetimeConfig, ): Equal extends true ? MySqlDateTimeStringBuilderInitial : MySqlDateTimeBuilderInitial; -export function datetime(name: string, config: MySqlDatetimeConfig = {}) { +export function datetime( + a?: TName | MySqlDatetimeConfig, + b?: MySqlDatetimeConfig, +): Equal extends true ? MySqlDateTimeStringBuilderInitial : MySqlDateTimeBuilderInitial { + const { name, config } = getColumnNameAndConfig>(a, b); if (config.mode === 'string') { - return new MySqlDateTimeStringBuilder(name, config); + return new MySqlDateTimeStringBuilder(name, config) as any; } - return new MySqlDateTimeBuilder(name, config); + return new MySqlDateTimeBuilder(name, config) as any; } diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index fa25d9cdb..c6e0dff91 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlDecimalBuilderInitial = MySqlDecimalBuilder<{ name: TName; @@ -60,9 +61,18 @@ export interface MySqlDecimalConfig { scale?: number; } +export function decimal(): MySqlDecimalBuilderInitial<''>; +export function decimal( + config: MySqlDecimalConfig, +): MySqlDecimalBuilderInitial<''>; export function decimal( name: TName, - config: MySqlDecimalConfig = {}, + config?: MySqlDecimalConfig, +): MySqlDecimalBuilderInitial; +export function decimal( + a?: TName | MySqlDecimalConfig, + b: MySqlDecimalConfig = {}, ): MySqlDecimalBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlDecimalBuilder(name, config.precision, config.scale); } diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index dd349cf27..43d95dc1b 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlDoubleBuilderInitial = MySqlDoubleBuilder<{ name: TName; @@ -57,9 +58,18 @@ export interface MySqlDoubleConfig { scale?: number; } +export function double(): MySqlDoubleBuilderInitial<''>; +export function double( + config?: MySqlDoubleConfig, +): MySqlDoubleBuilderInitial<''>; export function double( name: TName, config?: MySqlDoubleConfig, +): MySqlDoubleBuilderInitial; +export function double( + a?: TName | MySqlDoubleConfig, + b?: MySqlDoubleConfig, ): MySqlDoubleBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlDoubleBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/enum.ts b/drizzle-orm/src/mysql-core/columns/enum.ts index 1d8b4c1f5..3df8cbf32 100644 --- a/drizzle-orm/src/mysql-core/columns/enum.ts +++ b/drizzle-orm/src/mysql-core/columns/enum.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import type { Writable } from '~/utils.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlEnumColumnBuilderInitial = @@ -49,10 +49,19 @@ export class MySqlEnumColumn>( + values: T | Writable, +): MySqlEnumColumnBuilderInitial<'', Writable>; export function mysqlEnum>( name: TName, values: T | Writable, +): MySqlEnumColumnBuilderInitial>; +export function mysqlEnum>( + a?: TName | T | Writable, + b?: T | Writable, ): MySqlEnumColumnBuilderInitial> { + const { name, config: values } = getColumnNameAndConfig>(a, b); + if (values.length === 0) { throw new Error(`You have an empty array for "${name}" enum values`); } diff --git a/drizzle-orm/src/mysql-core/columns/float.ts b/drizzle-orm/src/mysql-core/columns/float.ts index b66f1e05a..a7dae67be 100644 --- a/drizzle-orm/src/mysql-core/columns/float.ts +++ b/drizzle-orm/src/mysql-core/columns/float.ts @@ -19,7 +19,7 @@ export class MySqlFloatBuilder> exte } } -export function float(name: TName): MySqlFloatBuilderInitial { - return new MySqlFloatBuilder(name); +export function float(): MySqlFloatBuilderInitial<''>; +export function float(name: TName): MySqlFloatBuilderInitial; +export function float(name?: TName): MySqlFloatBuilderInitial { + return new MySqlFloatBuilder(name ?? ''); } diff --git a/drizzle-orm/src/mysql-core/columns/int.ts b/drizzle-orm/src/mysql-core/columns/int.ts index dbfb85760..9b231c2fe 100644 --- a/drizzle-orm/src/mysql-core/columns/int.ts +++ b/drizzle-orm/src/mysql-core/columns/int.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlIntBuilderInitial = MySqlIntBuilder<{ name: TName; @@ -19,7 +20,7 @@ export class MySqlIntBuilder(name: TName, config?: MySqlIntConfig): MySqlIntBuilderInitial { +export function int(): MySqlIntBuilderInitial<''>; +export function int( + config?: MySqlIntConfig, +): MySqlIntBuilderInitial<''>; +export function int( + name: TName, + config?: MySqlIntConfig, +): MySqlIntBuilderInitial; +export function int( + a?: TName | MySqlIntConfig, + b?: MySqlIntConfig, +): MySqlIntBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/json.ts b/drizzle-orm/src/mysql-core/columns/json.ts index f30ea1534..686852089 100644 --- a/drizzle-orm/src/mysql-core/columns/json.ts +++ b/drizzle-orm/src/mysql-core/columns/json.ts @@ -17,7 +17,7 @@ export type MySqlJsonBuilderInitial = MySqlJsonBuilder<{ export class MySqlJsonBuilder> extends MySqlColumnBuilder { static readonly [entityKind]: string = 'MySqlJsonBuilder'; - constructor(name: T['name']) { + constructor(name: string) { super(name, 'json', 'MySqlJson'); } @@ -41,6 +41,8 @@ export class MySqlJson> extends } } -export function json(name: TName): MySqlJsonBuilderInitial { - return new MySqlJsonBuilder(name); +export function json(): MySqlJsonBuilderInitial<''>; +export function json(name: TName): MySqlJsonBuilderInitial; +export function json(name?: TName): MySqlJsonBuilderInitial { + return new MySqlJsonBuilder(name ?? ''); } diff --git a/drizzle-orm/src/mysql-core/columns/mediumint.ts b/drizzle-orm/src/mysql-core/columns/mediumint.ts index 268028b44..60d9ce388 100644 --- a/drizzle-orm/src/mysql-core/columns/mediumint.ts +++ b/drizzle-orm/src/mysql-core/columns/mediumint.ts @@ -4,6 +4,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; import type { MySqlIntConfig } from './int.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlMediumIntBuilderInitial = MySqlMediumIntBuilder<{ name: TName; @@ -53,9 +54,18 @@ export class MySqlMediumInt; +export function mediumint( + config?: MySqlIntConfig, +): MySqlMediumIntBuilderInitial<''>; export function mediumint( name: TName, config?: MySqlIntConfig, +): MySqlMediumIntBuilderInitial; +export function mediumint( + a?: TName | MySqlIntConfig, + b?: MySqlIntConfig, ): MySqlMediumIntBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlMediumIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/real.ts b/drizzle-orm/src/mysql-core/columns/real.ts index 7dd41dda0..f96d65651 100644 --- a/drizzle-orm/src/mysql-core/columns/real.ts +++ b/drizzle-orm/src/mysql-core/columns/real.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlRealBuilderInitial = MySqlRealBuilder<{ name: TName; @@ -61,6 +62,18 @@ export interface MySqlRealConfig { scale?: number; } -export function real(name: TName, config: MySqlRealConfig = {}): MySqlRealBuilderInitial { +export function real(): MySqlRealBuilderInitial<''>; +export function real( + config?: MySqlRealConfig, +): MySqlRealBuilderInitial<''>; +export function real( + name: TName, + config?: MySqlRealConfig, +): MySqlRealBuilderInitial; +export function real( + a?: TName | MySqlRealConfig, + b: MySqlRealConfig = {}, +): MySqlRealBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlRealBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/serial.ts b/drizzle-orm/src/mysql-core/columns/serial.ts index 0f87f0bf5..4a5b877a0 100644 --- a/drizzle-orm/src/mysql-core/columns/serial.ts +++ b/drizzle-orm/src/mysql-core/columns/serial.ts @@ -35,7 +35,7 @@ export class MySqlSerialBuilder(name: TName): MySqlSerialBuilderInitial { - return new MySqlSerialBuilder(name) as MySqlSerialBuilderInitial; +export function serial(): MySqlSerialBuilderInitial<''>; +export function serial(name: TName): MySqlSerialBuilderInitial; +export function serial(name?: TName): MySqlSerialBuilderInitial { + return new MySqlSerialBuilder(name ?? '') as MySqlSerialBuilderInitial; } diff --git a/drizzle-orm/src/mysql-core/columns/smallint.ts b/drizzle-orm/src/mysql-core/columns/smallint.ts index fc1dd0d55..9a20d164a 100644 --- a/drizzle-orm/src/mysql-core/columns/smallint.ts +++ b/drizzle-orm/src/mysql-core/columns/smallint.ts @@ -4,6 +4,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; import type { MySqlIntConfig } from './int.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlSmallIntBuilderInitial = MySqlSmallIntBuilder<{ name: TName; @@ -53,9 +54,18 @@ export class MySqlSmallInt } } +export function smallint(): MySqlSmallIntBuilderInitial<''>; +export function smallint( + config?: MySqlIntConfig, +): MySqlSmallIntBuilderInitial<''>; export function smallint( name: TName, config?: MySqlIntConfig, +): MySqlSmallIntBuilderInitial; +export function smallint( + a?: TName | MySqlIntConfig, + b?: MySqlIntConfig, ): MySqlSmallIntBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlSmallIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/text.ts b/drizzle-orm/src/mysql-core/columns/text.ts index 72c232e16..5a49f4b1f 100644 --- a/drizzle-orm/src/mysql-core/columns/text.ts +++ b/drizzle-orm/src/mysql-core/columns/text.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import type { Writable } from '~/utils.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlTextColumnType = 'tinytext' | 'text' | 'mediumtext' | 'longtext'; @@ -55,30 +55,66 @@ export interface MySqlTextConfig; +export function text>( + config?: MySqlTextConfig>, +): MySqlTextBuilderInitial<'', Writable>; export function text>( name: TName, - config: MySqlTextConfig> = {}, + config?: MySqlTextConfig>, +): MySqlTextBuilderInitial>; +export function text>( + a?: TName | MySqlTextConfig>, + b: MySqlTextConfig> = {}, ): MySqlTextBuilderInitial> { + const { name, config } = getColumnNameAndConfig>>(a, b); return new MySqlTextBuilder(name, 'text', config); } +export function tinytext(): MySqlTextBuilderInitial<'', [string, ...string[]]>; +export function tinytext>( + config?: MySqlTextConfig>, +): MySqlTextBuilderInitial<'', Writable>; export function tinytext>( name: TName, - config: MySqlTextConfig> = {}, + config?: MySqlTextConfig>, +): MySqlTextBuilderInitial>; +export function tinytext>( + a?: TName | MySqlTextConfig>, + b: MySqlTextConfig> = {}, ): MySqlTextBuilderInitial> { + const { name, config } = getColumnNameAndConfig>>(a, b); return new MySqlTextBuilder(name, 'tinytext', config); } +export function mediumtext(): MySqlTextBuilderInitial<'', [string, ...string[]]>; +export function mediumtext>( + config?: MySqlTextConfig>, +): MySqlTextBuilderInitial<'', Writable>; export function mediumtext>( name: TName, - config: MySqlTextConfig> = {}, + config?: MySqlTextConfig>, +): MySqlTextBuilderInitial>; +export function mediumtext>( + a?: TName | MySqlTextConfig>, + b: MySqlTextConfig> = {}, ): MySqlTextBuilderInitial> { + const { name, config } = getColumnNameAndConfig>>(a, b); return new MySqlTextBuilder(name, 'mediumtext', config); } +export function longtext(): MySqlTextBuilderInitial<'', [string, ...string[]]>; +export function longtext>( + config?: MySqlTextConfig>, +): MySqlTextBuilderInitial<'', Writable>; export function longtext>( name: TName, - config: MySqlTextConfig> = {}, + config?: MySqlTextConfig>, +): MySqlTextBuilderInitial>; +export function longtext>( + a?: TName | MySqlTextConfig>, + b: MySqlTextConfig> = {}, ): MySqlTextBuilderInitial> { + const { name, config } = getColumnNameAndConfig>>(a, b); return new MySqlTextBuilder(name, 'longtext', config); } diff --git a/drizzle-orm/src/mysql-core/columns/time.ts b/drizzle-orm/src/mysql-core/columns/time.ts index ae2251bda..509ac80de 100644 --- a/drizzle-orm/src/mysql-core/columns/time.ts +++ b/drizzle-orm/src/mysql-core/columns/time.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlTimeBuilderInitial = MySqlTimeBuilder<{ name: TName; @@ -53,6 +54,18 @@ export type TimeConfig = { fsp?: 0 | 1 | 2 | 3 | 4 | 5 | 6; }; -export function time(name: TName, config?: TimeConfig): MySqlTimeBuilderInitial { +export function time(): MySqlTimeBuilderInitial<''>; +export function time( + config?: TimeConfig, +): MySqlTimeBuilderInitial<''>; +export function time( + name: TName, + config?: TimeConfig, +): MySqlTimeBuilderInitial; +export function time( + a?: TName | TimeConfig, + b?: TimeConfig, +): MySqlTimeBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlTimeBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/timestamp.ts b/drizzle-orm/src/mysql-core/columns/timestamp.ts index 24e3b2650..0ea410d10 100644 --- a/drizzle-orm/src/mysql-core/columns/timestamp.ts +++ b/drizzle-orm/src/mysql-core/columns/timestamp.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import type { Equal } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; import { MySqlDateBaseColumn, MySqlDateColumnBaseBuilder } from './date.common.ts'; export type MySqlTimestampBuilderInitial = MySqlTimestampBuilder<{ @@ -108,14 +108,25 @@ export interface MySqlTimestampConfig; +export function timestamp( + config?: MySqlTimestampConfig, +): Equal extends true ? MySqlTimestampStringBuilderInitial<''> + : MySqlTimestampBuilderInitial<''>; export function timestamp( name: TName, config?: MySqlTimestampConfig, ): Equal extends true ? MySqlTimestampStringBuilderInitial : MySqlTimestampBuilderInitial; -export function timestamp(name: string, config: MySqlTimestampConfig = {}) { +export function timestamp( + a?: TName | MySqlTimestampConfig, + b: MySqlTimestampConfig = {}, +): Equal extends true ? MySqlTimestampStringBuilderInitial + : MySqlTimestampBuilderInitial +{ + const { name, config } = getColumnNameAndConfig>(a, b); if (config.mode === 'string') { - return new MySqlTimestampStringBuilder(name, config); + return new MySqlTimestampStringBuilder(name, config) as any; } - return new MySqlTimestampBuilder(name, config); + return new MySqlTimestampBuilder(name, config) as any; } diff --git a/drizzle-orm/src/mysql-core/columns/tinyint.ts b/drizzle-orm/src/mysql-core/columns/tinyint.ts index c749e6da8..adc6d5774 100644 --- a/drizzle-orm/src/mysql-core/columns/tinyint.ts +++ b/drizzle-orm/src/mysql-core/columns/tinyint.ts @@ -4,6 +4,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; import type { MySqlIntConfig } from './int.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuilder<{ name: TName; @@ -53,6 +54,18 @@ export class MySqlTinyInt> } } -export function tinyint(name: TName, config?: MySqlIntConfig): MySqlTinyIntBuilderInitial { +export function tinyint(): MySqlTinyIntBuilderInitial<''>; +export function tinyint( + config?: MySqlIntConfig, +): MySqlTinyIntBuilderInitial<''>; +export function tinyint( + name: TName, + config?: MySqlIntConfig, +): MySqlTinyIntBuilderInitial; +export function tinyint( + a?: TName | MySqlIntConfig, + b?: MySqlIntConfig, +): MySqlTinyIntBuilderInitial { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlTinyIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/varbinary.ts b/drizzle-orm/src/mysql-core/columns/varbinary.ts index be0a89cf6..201580235 100644 --- a/drizzle-orm/src/mysql-core/columns/varbinary.ts +++ b/drizzle-orm/src/mysql-core/columns/varbinary.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlVarBinaryBuilderInitial = MySqlVarBinaryBuilder<{ name: TName; @@ -52,9 +53,17 @@ export interface MySqlVarbinaryOptions { length: number; } +export function varbinary( + config: MySqlVarbinaryOptions, +): MySqlVarBinaryBuilderInitial<''>; export function varbinary( name: TName, - options: MySqlVarbinaryOptions, + config: MySqlVarbinaryOptions, +): MySqlVarBinaryBuilderInitial; +export function varbinary( + a?: TName | MySqlVarbinaryOptions, + b?: MySqlVarbinaryOptions, ): MySqlVarBinaryBuilderInitial { - return new MySqlVarBinaryBuilder(name, options); + const { name, config } = getColumnNameAndConfig(a, b); + return new MySqlVarBinaryBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/varchar.ts b/drizzle-orm/src/mysql-core/columns/varchar.ts index b692bf789..72f63dbeb 100644 --- a/drizzle-orm/src/mysql-core/columns/varchar.ts +++ b/drizzle-orm/src/mysql-core/columns/varchar.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import type { Writable } from '~/utils.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlVarCharBuilderInitial = MySqlVarCharBuilder< @@ -59,9 +59,17 @@ export interface MySqlVarCharConfig>( + config: MySqlVarCharConfig>, +): MySqlVarCharBuilderInitial<'', Writable>; export function varchar>( name: TName, config: MySqlVarCharConfig>, +): MySqlVarCharBuilderInitial>; +export function varchar>( + a?: TName | MySqlVarCharConfig>, + b?: MySqlVarCharConfig>, ): MySqlVarCharBuilderInitial> { + const { name, config } = getColumnNameAndConfig>>(a, b); return new MySqlVarCharBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/year.ts b/drizzle-orm/src/mysql-core/columns/year.ts index 224de12e9..a54d7eeb8 100644 --- a/drizzle-orm/src/mysql-core/columns/year.ts +++ b/drizzle-orm/src/mysql-core/columns/year.ts @@ -17,7 +17,7 @@ export type MySqlYearBuilderInitial = MySqlYearBuilder<{ export class MySqlYearBuilder> extends MySqlColumnBuilder { static readonly [entityKind]: string = 'MySqlYearBuilder'; - constructor(name: T['name']) { + constructor(name: string) { super(name, 'number', 'MySqlYear'); } @@ -39,6 +39,8 @@ export class MySqlYear< } } -export function year(name: TName): MySqlYearBuilderInitial { - return new MySqlYearBuilder(name); +export function year(): MySqlYearBuilderInitial<''>; +export function year(name: TName): MySqlYearBuilderInitial; +export function year(name?: TName): MySqlYearBuilderInitial { + return new MySqlYearBuilder(name ?? ''); } diff --git a/drizzle-orm/src/mysql-core/table.ts b/drizzle-orm/src/mysql-core/table.ts index 3b1d4c3a3..152198a14 100644 --- a/drizzle-orm/src/mysql-core/table.ts +++ b/drizzle-orm/src/mysql-core/table.ts @@ -80,6 +80,7 @@ export function mysqlTableWithSchema< const builtColumns = Object.fromEntries( Object.entries(columns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as MySqlColumnBuilder; + colBuilder.setName(name); const column = colBuilder.build(rawTable); rawTable[InlineForeignKeys].push(...colBuilder.buildForeignKeys(column, rawTable)); return [name, column]; From a8cb8f953b07ba2ea936b6010d688677deb31e30 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Sun, 4 Aug 2024 12:28:34 -0700 Subject: [PATCH 031/492] Update PG custom column --- drizzle-orm/src/pg-core/columns/custom.ts | 4 +++- drizzle-orm/type-tests/pg/tables.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/pg-core/columns/custom.ts b/drizzle-orm/src/pg-core/columns/custom.ts index c6c1d4540..2ac3f356e 100644 --- a/drizzle-orm/src/pg-core/columns/custom.ts +++ b/drizzle-orm/src/pg-core/columns/custom.ts @@ -213,7 +213,9 @@ export function customType( ): PgCustomColumnBuilder>; } : { (): PgCustomColumnBuilder>; - (fieldConfig?: T['config']): PgCustomColumnBuilder>; + & T['config']>( + fieldConfig?: TConfig, + ): PgCustomColumnBuilder>; ( dbName: TName, fieldConfig?: T['config'], diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index 20d3e56b2..06a7d9598 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -1267,7 +1267,7 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); } { - const keysAsColumnNames = pgTable('a', { + const keysAsColumnNames = pgTable('test', { id: serial(), name: text() }); From ba370a8a6684bd833b27a2f5210cca4e2455a312 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Sun, 4 Aug 2024 13:08:44 -0700 Subject: [PATCH 032/492] Fix issue with undefined config --- drizzle-orm/src/mysql-core/columns/date.ts | 4 ++-- drizzle-orm/src/mysql-core/columns/datetime.ts | 4 ++-- drizzle-orm/src/mysql-core/columns/timestamp.ts | 4 ++-- drizzle-orm/src/pg-core/columns/timestamp.ts | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drizzle-orm/src/mysql-core/columns/date.ts b/drizzle-orm/src/mysql-core/columns/date.ts index 14c3e2ba5..8ef069003 100644 --- a/drizzle-orm/src/mysql-core/columns/date.ts +++ b/drizzle-orm/src/mysql-core/columns/date.ts @@ -110,8 +110,8 @@ export function date, b?: MySqlDateConfig, ): Equal extends true ? MySqlDateStringBuilderInitial : MySqlDateBuilderInitial { - const { name, config } = getColumnNameAndConfig>(a, b); - if (config.mode === 'string') { + const { name, config } = getColumnNameAndConfig | undefined>(a, b); + if (config?.mode === 'string') { return new MySqlDateStringBuilder(name) as any; } return new MySqlDateBuilder(name) as any; diff --git a/drizzle-orm/src/mysql-core/columns/datetime.ts b/drizzle-orm/src/mysql-core/columns/datetime.ts index 32c898436..fa4245af8 100644 --- a/drizzle-orm/src/mysql-core/columns/datetime.ts +++ b/drizzle-orm/src/mysql-core/columns/datetime.ts @@ -132,8 +132,8 @@ export function datetime, b?: MySqlDatetimeConfig, ): Equal extends true ? MySqlDateTimeStringBuilderInitial : MySqlDateTimeBuilderInitial { - const { name, config } = getColumnNameAndConfig>(a, b); - if (config.mode === 'string') { + const { name, config } = getColumnNameAndConfig | undefined>(a, b); + if (config?.mode === 'string') { return new MySqlDateTimeStringBuilder(name, config) as any; } return new MySqlDateTimeBuilder(name, config) as any; diff --git a/drizzle-orm/src/mysql-core/columns/timestamp.ts b/drizzle-orm/src/mysql-core/columns/timestamp.ts index 0ea410d10..97031fc89 100644 --- a/drizzle-orm/src/mysql-core/columns/timestamp.ts +++ b/drizzle-orm/src/mysql-core/columns/timestamp.ts @@ -124,8 +124,8 @@ export function timestamp extends true ? MySqlTimestampStringBuilderInitial : MySqlTimestampBuilderInitial { - const { name, config } = getColumnNameAndConfig>(a, b); - if (config.mode === 'string') { + const { name, config } = getColumnNameAndConfig | undefined>(a, b); + if (config?.mode === 'string') { return new MySqlTimestampStringBuilder(name, config) as any; } return new MySqlTimestampBuilder(name, config) as any; diff --git a/drizzle-orm/src/pg-core/columns/timestamp.ts b/drizzle-orm/src/pg-core/columns/timestamp.ts index cd4d03421..1ef73ce8b 100644 --- a/drizzle-orm/src/pg-core/columns/timestamp.ts +++ b/drizzle-orm/src/pg-core/columns/timestamp.ts @@ -145,9 +145,9 @@ export function timestamp, b: PgTimestampConfig = {}, ): Equal extends true ? PgTimestampStringBuilderInitial : PgTimestampBuilderInitial { - const { name, config } = getColumnNameAndConfig>(a, b); - if (config.mode === 'string') { + const { name, config } = getColumnNameAndConfig | undefined>(a, b); + if (config?.mode === 'string') { return new PgTimestampStringBuilder(name, config.withTimezone ?? false, config.precision) as any; } - return new PgTimestampBuilder(name, config.withTimezone ?? false, config.precision) as any; + return new PgTimestampBuilder(name, config?.withTimezone ?? false, config?.precision) as any; } From 324b35612c9af205ae4bf71918af84b9c61de39b Mon Sep 17 00:00:00 2001 From: Mario564 Date: Sun, 4 Aug 2024 13:13:41 -0700 Subject: [PATCH 033/492] Add MySQL type and integration tests --- drizzle-orm/type-tests/mysql/tables.ts | 254 ++++++++++++++++++ integration-tests/tests/mysql/mysql-common.ts | 49 ++++ integration-tests/tests/pg/pg-common.ts | 2 +- 3 files changed, 304 insertions(+), 1 deletion(-) diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index eac796e6f..4522cb752 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -3,29 +3,40 @@ import { eq, gt } from '~/expressions.ts'; import type { BuildColumn, InferSelectModel, Simplify } from '~/index.ts'; import { bigint, + binary, + boolean, char, check, customType, date, datetime, decimal, + double, + float, foreignKey, index, int, json, longtext, + mediumint, mediumtext, type MySqlColumn, mysqlEnum, mysqlTable, primaryKey, + real, serial, + smallint, text, + time, timestamp, + tinyint, tinytext, unique, uniqueIndex, + varbinary, varchar, + year, } from '~/mysql-core/index.ts'; import { mysqlSchema } from '~/mysql-core/schema.ts'; import { mysqlView, type MySqlViewWithSelection } from '~/mysql-core/view.ts'; @@ -760,3 +771,246 @@ Expect< }, typeof emailLog.$inferInsert> >; } + +{ + const customRequiredConfig = customType<{ + data: string; + driverData: string; + config: { length: number }; + configRequired: true; + }>({ + dataType(config) { + Expect>; + return `varchar(${config.length})`; + }, + + toDriver(value) { + Expect>(); + return value; + }, + + fromDriver(value) { + Expect>(); + return value; + }, + }); + + customRequiredConfig('t', { length: 10 }); + customRequiredConfig({ length: 10 }); + // @ts-expect-error - config is required + customRequiredConfig('t'); + // @ts-expect-error - config is required + customRequiredConfig(); +} + +{ + const customOptionalConfig = customType<{ + data: string; + driverData: string; + config: { length: number }; + }>({ + dataType(config) { + Expect>; + return config ? `varchar(${config.length})` : `text`; + }, + + toDriver(value) { + Expect>(); + return value; + }, + + fromDriver(value) { + Expect>(); + return value; + }, + }); + + customOptionalConfig('t', { length: 10 }); + customOptionalConfig('t'); + customOptionalConfig({ length: 10 }); + customOptionalConfig(); +} + +{ + mysqlTable('all_columns', { + bigint: bigint('bigint', { mode: 'number' }), + bigint2: bigint('bigint', { mode: 'number', unsigned: true }), + bigintdef: bigint('bigintdef', { mode: 'number' }).default(0), + binary: binary('binary'), + binary1: binary('binary1', { length: 1 }), + binarydef: binary('binarydef').default(''), + boolean: boolean('boolean'), + booleandef: boolean('booleandef').default(false), + char: char('char'), + char2: char('char2', { length: 1 }), + char3: char('char3', { enum: ['a', 'b', 'c'] }), + char4: char('char4', { length: 1, enum: ['a', 'b', 'c'] }), + chardef: char('chardef').default(''), + date: date('date'), + date2: date('date2', { mode: 'string' }), + datedef: date('datedef').default(new Date()), + datetime: datetime('datetime'), + datetime2: datetime('datetime2', { mode: 'string' }), + datetime3: datetime('datetime3', { mode: 'string', fsp: 3 }), + datetimedef: datetime('datetimedef').default(new Date()), + decimal: decimal('decimal'), + decimal2: decimal('decimal2', { precision: 10 }), + decimal3: decimal('decimal3', { scale: 2 }), + decimal4: decimal('decimal4', { precision: 10, scale: 2 }), + decimaldef: decimal('decimaldef').default('0'), + double: double('double'), + double2: double('double2', { precision: 10 }), + double3: double('double3', { scale: 2 }), + double4: double('double4', { precision: 10, scale: 2 }), + doubledef: double('doubledef').default(0), + enum: mysqlEnum('enum', ['a', 'b', 'c']), + enumdef: mysqlEnum('enumdef', ['a', 'b', 'c']).default('a'), + float: float('float'), + floatdef: float('floatdef').default(0), + int: int('int'), + int2: int('int2', { unsigned: true }), + intdef: int('intdef').default(0), + json: json('json'), + jsondef: json('jsondef').default({}), + mediumint: mediumint('mediumint'), + mediumint2: mediumint('mediumint2', { unsigned: true }), + mediumintdef: mediumint('mediumintdef').default(0), + real: real('real'), + real2: real('real2', { precision: 10 }), + real3: real('real3', { scale: 2 }), + real4: real('real4', { precision: 10, scale: 2 }), + realdef: real('realdef').default(0), + serial: serial('serial'), + serialdef: serial('serialdef').default(0), + smallint: smallint('smallint'), + smallint2: smallint('smallint2', { unsigned: true }), + smallintdef: smallint('smallintdef').default(0), + text: text('text'), + text2: text('text2', { enum: ['a', 'b', 'c'] }), + textdef: text('textdef').default(''), + tinytext: tinytext('tinytext'), + tinytext2: tinytext('tinytext2', { enum: ['a', 'b', 'c'] }), + tinytextdef: tinytext('tinytextdef').default(''), + mediumtext: mediumtext('mediumtext'), + mediumtext2: mediumtext('mediumtext2', { enum: ['a', 'b', 'c'] }), + mediumtextdef: mediumtext('mediumtextdef').default(''), + longtext: longtext('longtext'), + longtext2: longtext('longtext2', { enum: ['a', 'b', 'c'] }), + longtextdef: longtext('longtextdef').default(''), + time: time('time'), + time2: time('time2', { fsp: 1 }), + timedef: time('timedef').default('00:00:00'), + timestamp: timestamp('timestamp'), + timestamp2: timestamp('timestamp2', { mode: 'string' }), + timestamp3: timestamp('timestamp3', { mode: 'string', fsp: 1 }), + timestamp4: timestamp('timestamp4', { fsp: 1 }), + timestampdef: timestamp('timestampdef').default(new Date()), + tinyint: tinyint('tinyint'), + tinyint2: tinyint('tinyint2', { unsigned: true }), + tinyintdef: tinyint('tinyintdef').default(0), + varbinary: varbinary('varbinary', { length: 1 }), + varbinarydef: varbinary('varbinarydef', { length: 1 }).default(''), + varchar: varchar('varchar', { length: 1 }), + varchar2: varchar('varchar2', { length: 1, enum: ['a', 'b', 'c'] }), + varchardef: varchar('varchardef', { length: 1 }).default(''), + year: year('year'), + yeardef: year('yeardef').default(0), + }); +} + +{ + const keysAsColumnNames = mysqlTable('test', { + id: int(), + name: text() + }); + + Expect>; + Expect>; +} + +{ + mysqlTable('all_columns_without_name', { + bigint: bigint({ mode: 'number' }), + bigint2: bigint({ mode: 'number', unsigned: true }), + bigintdef: bigint({ mode: 'number' }).default(0), + binary: binary(), + binrary1: binary({ length: 1 }), + binarydef: binary().default(''), + boolean: boolean(), + booleandef: boolean().default(false), + char: char(), + char2: char({ length: 1 }), + char3: char({ enum: ['a', 'b', 'c'] }), + char4: char({ length: 1, enum: ['a', 'b', 'c'] }), + chardef: char().default(''), + date: date(), + date2: date({ mode: 'string' }), + datedef: date('datedef').default(new Date()), + datetime: datetime(), + datetime2: datetime({ mode: 'string' }), + datetime3: datetime({ mode: 'string', fsp: 3 }), + datetimedef: datetime('datetimedef').default(new Date()), + decimal: decimal(), + decimal2: decimal({ precision: 10 }), + decimal3: decimal({ scale: 2 }), + decimal4: decimal({ precision: 10, scale: 2 }), + decimaldef: decimal('decimaldef').default('0'), + double: double(), + double2: double({ precision: 10 }), + double3: double({ scale: 2 }), + double4: double({ precision: 10, scale: 2 }), + doubledef: double().default(0), + enum: mysqlEnum(['a', 'b', 'c']), + enumdef: mysqlEnum(['a', 'b', 'c']).default('a'), + float: float(), + floatdef: float().default(0), + int: int(), + int2: int({ unsigned: true }), + intdef: int().default(0), + json: json(), + jsondef: json().default({}), + mediumint: mediumint(), + mediumint2: mediumint({ unsigned: true }), + mediumintdef: mediumint().default(0), + real: real(), + real2: real({ precision: 10 }), + real3: real({ scale: 2 }), + real4: real({ precision: 10, scale: 2 }), + realdef: real().default(0), + serial: serial(), + serialdef: serial().default(0), + smallint: smallint(), + smallint2: smallint({ unsigned: true }), + smallintdef: smallint().default(0), + text: text(), + text2: text({ enum: ['a', 'b', 'c'] }), + textdef: text().default(''), + tinytext: tinytext(), + tinytext2: tinytext({ enum: ['a', 'b', 'c'] }), + tinytextdef: tinytext().default(''), + mediumtext: mediumtext(), + mediumtext2: mediumtext({ enum: ['a', 'b', 'c'] }), + mediumtextdef: mediumtext().default(''), + longtext: longtext(), + longtext2: longtext({ enum: ['a', 'b', 'c'] }), + longtextdef: longtext().default(''), + time: time(), + time2: time({ fsp: 1 }), + timedef: time().default('00:00:00'), + timestamp: timestamp(), + timestamp2: timestamp({ mode: 'string' }), + timestamp3: timestamp({ mode: 'string', fsp: 1 }), + timestamp4: timestamp({ fsp: 1 }), + timestampdef: timestamp().default(new Date()), + tinyint: tinyint(), + tinyint2: tinyint({ unsigned: true }), + tinyintdef: tinyint().default(0), + varbinary: varbinary({ length: 1 }), + varbinarydef: varbinary({ length: 1 }).default(''), + varchar: varchar({ length: 1 }), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }), + varchardef: varchar({ length: 1 }).default(''), + year: year(), + yeardef: year().default(0), + }); +} diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index c96ae9319..5cc22ed4d 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3539,4 +3539,53 @@ export function tests(driver?: string) { expect(users.length).toBeGreaterThan(0); }); + + test('Object keys as column names', async (ctx) => { + const { db } = ctx.mysql; + + // Tests the following: + // Column with required config + // Column with optional config without providing a value + // Column with optional config providing a value + // Column without config + const users = mysqlTable('users', { + id: bigint({ mode: 'number' }).autoincrement().primaryKey(), + createdAt: timestamp(), + updatedAt: timestamp({ fsp: 3 }), + admin: boolean() + }); + + await db.execute(sql`drop table if exists users`); + await db.execute( + sql` + create table users ( + \`id\` bigint auto_increment primary key, + \`createdAt\` timestamp, + \`updatedAt\` timestamp(3), + \`admin\` boolean + ) + ` + ); + + await db.insert(users).values([ + { createdAt: sql`now() - interval 30 day`, updatedAt: sql`now() - interval 1 day`, admin: true }, + { createdAt: sql`now() - interval 1 day`, updatedAt: sql`now() - interval 30 day`, admin: true }, + { createdAt: sql`now() - interval 1 day`, updatedAt: sql`now() - interval 1 day`, admin: false }, + ]); + const result = await db + .select({ id: users.id, admin: users.admin }) + .from(users) + .where( + and( + gt(users.createdAt, sql`now() - interval 7 day`), + gt(users.updatedAt, sql`now() - interval 7 day`), + ) + ); + + expect(result).toEqual([ + { id: 3, admin: false }, + ]); + + await db.execute(sql`drop table users`); + }); } diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index b09f034ad..314c3b173 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4524,6 +4524,6 @@ export function tests() { ]); await db.execute(sql`drop table users`); - }) + }); }); } From acc3547d967bb7ccd915a0056138fa88eaab88ce Mon Sep 17 00:00:00 2001 From: Mario564 Date: Sun, 4 Aug 2024 14:25:31 -0700 Subject: [PATCH 034/492] Update SQLite columns --- drizzle-orm/src/sqlite-core/columns/blob.ts | 11 +++++- drizzle-orm/src/sqlite-core/columns/custom.ts | 39 ++++++++++++------- .../src/sqlite-core/columns/integer.ts | 11 +++++- .../src/sqlite-core/columns/numeric.ts | 6 ++- drizzle-orm/src/sqlite-core/columns/real.ts | 6 ++- drizzle-orm/src/sqlite-core/columns/text.ts | 31 +++++++++------ 6 files changed, 71 insertions(+), 33 deletions(-) diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index 7371eb299..c20211dea 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySQLiteTable } from '~/sqlite-core/table.ts'; -import type { Equal } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; type BlobMode = 'buffer' | 'json' | 'bigint'; @@ -141,13 +141,20 @@ export interface BlobConfig { * * https://www.sqlite.org/json1.html */ +export function blob(): SQLiteBlobJsonBuilderInitial<''>; +export function blob( + config?: BlobConfig, +): Equal extends true ? SQLiteBigIntBuilderInitial<''> + : Equal extends true ? SQLiteBlobBufferBuilderInitial<''> + : SQLiteBlobJsonBuilderInitial<''>; export function blob( name: TName, config?: BlobConfig, ): Equal extends true ? SQLiteBigIntBuilderInitial : Equal extends true ? SQLiteBlobBufferBuilderInitial : SQLiteBlobJsonBuilderInitial; -export function blob(name: string, config?: BlobConfig) { +export function blob(a?: string | BlobConfig,b?: BlobConfig) { + const { name, config } = getColumnNameAndConfig(a, b); if (config?.mode === 'json') { return new SQLiteBlobJsonBuilder(name); } diff --git a/drizzle-orm/src/sqlite-core/columns/custom.ts b/drizzle-orm/src/sqlite-core/columns/custom.ts index 513f380e0..109b4f0e1 100644 --- a/drizzle-orm/src/sqlite-core/columns/custom.ts +++ b/drizzle-orm/src/sqlite-core/columns/custom.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { SQL } from '~/sql/sql.ts'; import type { AnySQLiteTable } from '~/sqlite-core/table.ts'; -import type { Equal } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; export type ConvertCustomConfig> = @@ -108,7 +108,7 @@ export type CustomTypeValues = { /** * What config type should be used for {@link CustomTypeParams} `dataType` generation */ - config?: unknown; + config?: Record; /** * Whether the config argument should be required or not @@ -203,22 +203,33 @@ export interface CustomTypeParams { */ export function customType( customTypeParams: CustomTypeParams, -): Equal extends true ? ( - dbName: TName, - fieldConfig: T['config'], - ) => SQLiteCustomColumnBuilder> - : ( - dbName: TName, - fieldConfig?: T['config'], - ) => SQLiteCustomColumnBuilder> +): Equal extends true ? { + & T['config']>( + fieldConfig: TConfig, + ): SQLiteCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig: T['config'], + ): SQLiteCustomColumnBuilder>; + } : { + (): SQLiteCustomColumnBuilder>; + & T['config']>( + fieldConfig?: TConfig, + ): SQLiteCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig?: T['config'], + ): SQLiteCustomColumnBuilder>; + } { return ( - dbName: TName, - fieldConfig?: T['config'], + a?: TName | T['config'], + b?: T['config'], ): SQLiteCustomColumnBuilder> => { + const { name, config } = getColumnNameAndConfig(a, b); return new SQLiteCustomColumnBuilder( - dbName as ConvertCustomConfig['name'], - fieldConfig, + name as ConvertCustomConfig['name'], + config, customTypeParams, ); }; diff --git a/drizzle-orm/src/sqlite-core/columns/integer.ts b/drizzle-orm/src/sqlite-core/columns/integer.ts index 1c839837d..c7052fdc6 100644 --- a/drizzle-orm/src/sqlite-core/columns/integer.ts +++ b/drizzle-orm/src/sqlite-core/columns/integer.ts @@ -11,7 +11,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import { sql } from '~/sql/sql.ts'; import type { OnConflict } from '~/sqlite-core/utils.ts'; -import type { Equal, Or } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal, type Or } from '~/utils.ts'; import type { AnySQLiteTable } from '../table.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; @@ -214,13 +214,20 @@ export interface IntegerConfig< mode: TMode; } +export function integer(): SQLiteIntegerBuilderInitial<''>; +export function integer( + config?: IntegerConfig, +): Or, Equal> extends true ? SQLiteTimestampBuilderInitial<''> + : Equal extends true ? SQLiteBooleanBuilderInitial<''> + : SQLiteIntegerBuilderInitial<''>; export function integer( name: TName, config?: IntegerConfig, ): Or, Equal> extends true ? SQLiteTimestampBuilderInitial : Equal extends true ? SQLiteBooleanBuilderInitial : SQLiteIntegerBuilderInitial; -export function integer(name: string, config?: IntegerConfig) { +export function integer(a?: string | IntegerConfig, b?: IntegerConfig) { + const { name, config } = getColumnNameAndConfig(a, b); if (config?.mode === 'timestamp' || config?.mode === 'timestamp_ms') { return new SQLiteTimestampBuilder(name, config.mode); } diff --git a/drizzle-orm/src/sqlite-core/columns/numeric.ts b/drizzle-orm/src/sqlite-core/columns/numeric.ts index 5cd29f78f..331547736 100644 --- a/drizzle-orm/src/sqlite-core/columns/numeric.ts +++ b/drizzle-orm/src/sqlite-core/columns/numeric.ts @@ -42,6 +42,8 @@ export class SQLiteNumeric } } -export function numeric(name: TName): SQLiteNumericBuilderInitial { - return new SQLiteNumericBuilder(name); +export function numeric(): SQLiteNumericBuilderInitial<''>; +export function numeric(name: TName): SQLiteNumericBuilderInitial; +export function numeric(name?: string) { + return new SQLiteNumericBuilder(name ?? ''); } diff --git a/drizzle-orm/src/sqlite-core/columns/real.ts b/drizzle-orm/src/sqlite-core/columns/real.ts index c04cb1be3..693780e9d 100644 --- a/drizzle-orm/src/sqlite-core/columns/real.ts +++ b/drizzle-orm/src/sqlite-core/columns/real.ts @@ -39,6 +39,8 @@ export class SQLiteReal> exte } } -export function real(name: TName): SQLiteRealBuilderInitial { - return new SQLiteRealBuilder(name); +export function real(): SQLiteRealBuilderInitial<''>; +export function real(name: TName): SQLiteRealBuilderInitial; +export function real(name?: string) { + return new SQLiteRealBuilder(name ?? ''); } diff --git a/drizzle-orm/src/sqlite-core/columns/text.ts b/drizzle-orm/src/sqlite-core/columns/text.ts index 7eecf1d1f..a9b6b2441 100644 --- a/drizzle-orm/src/sqlite-core/columns/text.ts +++ b/drizzle-orm/src/sqlite-core/columns/text.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySQLiteTable } from '~/sqlite-core/table.ts'; -import type { Equal, Writable } from '~/utils.ts'; +import { getColumnNameAndConfig, type Equal, type Writable } from '~/utils.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; export type SQLiteTextBuilderInitial = SQLiteTextBuilder<{ @@ -105,8 +105,8 @@ export class SQLiteTextJson } export type SQLiteTextConfig< - TMode extends 'text' | 'json', - TEnum extends readonly string[] | string[] | undefined, + TMode extends 'text' | 'json' = 'text' | 'json', + TEnum extends readonly string[] | string[] | undefined = string[] | string[] | undefined, > = TMode extends 'text' ? { mode?: TMode; length?: number; @@ -116,6 +116,15 @@ export type SQLiteTextConfig< mode?: TMode; }; +export function text(): SQLiteTextBuilderInitial<'', [string, ...string[]]>; +export function text< + U extends string, + T extends Readonly<[U, ...U[]]>, + TMode extends 'text' | 'json' = 'text' | 'json', +>( + config?: SQLiteTextConfig>, +): Equal extends true ? SQLiteTextJsonBuilderInitial<''> + : SQLiteTextBuilderInitial<'', Writable>; export function text< TName extends string, U extends string, @@ -123,13 +132,13 @@ export function text< TMode extends 'text' | 'json' = 'text' | 'json', >( name: TName, - config: SQLiteTextConfig> = {} as SQLiteTextConfig>, + config?: SQLiteTextConfig>, ): Equal extends true ? SQLiteTextJsonBuilderInitial - : SQLiteTextBuilderInitial> -{ - return (config.mode === 'json' - ? new SQLiteTextJsonBuilder(name) - : new SQLiteTextBuilder(name, config as SQLiteTextConfig<'text', Writable>)) as Equal extends true - ? SQLiteTextJsonBuilderInitial - : SQLiteTextBuilderInitial>; + : SQLiteTextBuilderInitial>; +export function text(a?: string | SQLiteTextConfig, b: SQLiteTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + if (config.mode === 'json') { + return new SQLiteTextJsonBuilder(name); + } + return new SQLiteTextBuilder(name, config as any); } From c51d4073950bf90836bc38a6af044c08d1aad76d Mon Sep 17 00:00:00 2001 From: Mario564 Date: Sun, 4 Aug 2024 14:45:47 -0700 Subject: [PATCH 035/492] Eliminate duplicate code --- drizzle-orm/src/column-builder.ts | 6 ++++++ drizzle-orm/src/mysql-core/columns/common.ts | 6 ------ drizzle-orm/src/pg-core/columns/common.ts | 6 ------ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index ba0d3bb78..f6426812b 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -293,6 +293,12 @@ export abstract class ColumnBuilder< as: SQL | T['data'] | (() => SQL), config?: Partial>, ): HasGenerated; + + /** @internal Sets the name of the column to the key within the table definition if a name was not given. */ + setName(name: string) { + if (this.config.name !== '') return; + this.config.name = name; + } } export type BuildColumn< diff --git a/drizzle-orm/src/mysql-core/columns/common.ts b/drizzle-orm/src/mysql-core/columns/common.ts index c3cf184f7..a0a192477 100644 --- a/drizzle-orm/src/mysql-core/columns/common.ts +++ b/drizzle-orm/src/mysql-core/columns/common.ts @@ -94,12 +94,6 @@ export abstract class MySqlColumnBuilder< abstract build( table: AnyMySqlTable<{ name: TTableName }>, ): MySqlColumn>; - - /** @internal Sets the name of the column to the key within the table definition if a name was not given. */ - setName(name: string) { - if (this.config.name !== '') return; - this.config.name = name; - } } // To understand how to use `MySqlColumn` and `AnyMySqlColumn`, see `Column` and `AnyColumn` documentation. diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index ff313bea3..a7440e24c 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -126,12 +126,6 @@ export abstract class PgColumnBuilder< ): ExtraConfigColumn { return new ExtraConfigColumn(table, this.config); } - - /** @internal Sets the name of the column to the key within the table definition if a name was not given. */ - setName(name: string) { - if (this.config.name !== '') return; - this.config.name = name; - } } // To understand how to use `PgColumn` and `PgColumn`, see `Column` and `AnyColumn` documentation. From 4eb8dda4822ed11365ba91f6c42a809bc9547727 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Sun, 4 Aug 2024 14:46:26 -0700 Subject: [PATCH 036/492] Add type and integration tests to SQLite --- drizzle-orm/src/sqlite-core/table.ts | 1 + drizzle-orm/type-tests/sqlite/tables.ts | 115 ++++++++++++++++++ .../tests/sqlite/sqlite-common.ts | 40 ++++++ 3 files changed, 156 insertions(+) diff --git a/drizzle-orm/src/sqlite-core/table.ts b/drizzle-orm/src/sqlite-core/table.ts index 8f787d98c..7749b69af 100644 --- a/drizzle-orm/src/sqlite-core/table.ts +++ b/drizzle-orm/src/sqlite-core/table.ts @@ -94,6 +94,7 @@ function sqliteTableBase< const builtColumns = Object.fromEntries( Object.entries(columns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as SQLiteColumnBuilder; + colBuilder.setName(name); const column = colBuilder.build(rawTable); rawTable[InlineForeignKeys].push(...colBuilder.buildForeignKeys(column, rawTable)); return [name, column]; diff --git a/drizzle-orm/type-tests/sqlite/tables.ts b/drizzle-orm/type-tests/sqlite/tables.ts index 01419b27a..595d115cc 100644 --- a/drizzle-orm/type-tests/sqlite/tables.ts +++ b/drizzle-orm/type-tests/sqlite/tables.ts @@ -4,11 +4,15 @@ import { eq, gt } from '~/expressions.ts'; import { sql } from '~/sql/sql.ts'; import { alias, + blob, check, + customType, foreignKey, index, integer, + numeric, primaryKey, + real, type SQLiteColumn, sqliteTable, text, @@ -460,3 +464,114 @@ Expect< Expect>; Expect>; } + +{ + const customRequiredConfig = customType<{ + data: string; + driverData: string; + config: { length: number }; + configRequired: true; + }>({ + dataType(config) { + Expect>; + return `varchar(${config.length})`; + }, + + toDriver(value) { + Expect>(); + return value; + }, + + fromDriver(value) { + Expect>(); + return value; + }, + }); + + customRequiredConfig('t', { length: 10 }); + customRequiredConfig({ length: 10 }); + // @ts-expect-error - config is required + customRequiredConfig('t'); + // @ts-expect-error - config is required + customRequiredConfig(); +} + +{ + const customOptionalConfig = customType<{ + data: string; + driverData: string; + config: { length: number }; + }>({ + dataType(config) { + Expect>; + return config ? `varchar(${config.length})` : `text`; + }, + + toDriver(value) { + Expect>(); + return value; + }, + + fromDriver(value) { + Expect>(); + return value; + }, + }); + + customOptionalConfig('t', { length: 10 }); + customOptionalConfig('t'); + customOptionalConfig({ length: 10 }); + customOptionalConfig(); +} + +{ + sqliteTable('all_columns', { + blob: blob('blob'), + blob2: blob('blob2', { mode: 'bigint' }), + blobdef: blob('blobdef').default(0), + integer: integer('integer'), + integer2: integer('integer2', { mode: 'boolean' }), + integerdef: integer('integerdef').default(0), + numeric: numeric('numeric'), + numericdef: numeric('numericdef').default(''), + real: real('real'), + realdef: real('realdef').default(0), + text: text('text'), + text2: text('text2', { enum: ['a', 'b', 'c'] }), + text3: text('text3', { length: 1 }), + text4: text('text4', { length: 1, enum: ['a', 'b', 'c'] }), + text5: text('text5', { mode: 'json' }), + textdef: text('textdef').default('') + }); +} + +{ + const keysAsColumnNames = sqliteTable('test', { + id: integer(), + name: text() + }); + + Expect>; + Expect>; +} + +{ + sqliteTable('all_columns_without_name', { + blob: blob(), + blob2: blob({ mode: 'bigint' }), + blobdef: blob().default(0), + integer: integer(), + integer2: integer({ mode: 'boolean' }), + integerdef: integer().default(0), + numeric: numeric(), + numericdef: numeric().default(''), + real: real(), + realdef: real().default(0), + text: text(), + text2: text({ enum: ['a', 'b', 'c'] }), + text3: text({ length: 1 }), + text4: text({ length: 1, enum: ['a', 'b', 'c'] }), + text5: text({ mode: 'json' }), + textdef: text().default('') + }); +} diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 49c609941..0a89be68b 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2734,4 +2734,44 @@ export function tests() { expect(users.length).toBeGreaterThan(0); }); + + test('Object keys as column names', async (ctx) => { + const { db } = ctx.sqlite; + + // Tests the following: + // Column with optional config without providing a value + // Column with optional config providing a value + // Column without config + const users = sqliteTable('users', { + id: integer().primaryKey({ autoIncrement: true }), + createdAt: integer({ mode: 'timestamp' }), + name: text() + }); + + await db.run(sql`drop table if exists users`); + await db.run( + sql` + create table users ( + \`id\` integer primary key autoincrement, + \`createdAt\` integer, + \`name\` text + ) + ` + ); + + await db.insert(users).values([ + { createdAt: new Date(new Date().getTime() - 2592000000), name: 'John' }, + { createdAt: new Date(new Date().getTime() - 86400000), name: 'Jane' } + ]); + const result = await db + .select({ id: users.id, name: users.name }) + .from(users) + .where(gt(users.createdAt, new Date(new Date().getTime() - 2592000000))); + + expect(result).toEqual([ + { id: 2, name: 'Jane' }, + ]); + + await db.run(sql`drop table users`); + }); } From b911c5afc4add44cff54dc5fed357d1467782ca4 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Sun, 4 Aug 2024 15:40:32 -0700 Subject: [PATCH 037/492] Slightly simplify column type definitions --- drizzle-orm/src/mysql-core/columns/bigint.ts | 9 ++--- drizzle-orm/src/mysql-core/columns/binary.ts | 9 ++--- drizzle-orm/src/mysql-core/columns/boolean.ts | 4 +- drizzle-orm/src/mysql-core/columns/char.ts | 11 ++---- drizzle-orm/src/mysql-core/columns/custom.ts | 2 +- drizzle-orm/src/mysql-core/columns/date.ts | 11 ++---- .../src/mysql-core/columns/datetime.ts | 11 ++---- drizzle-orm/src/mysql-core/columns/decimal.ts | 7 +--- drizzle-orm/src/mysql-core/columns/double.ts | 7 +--- drizzle-orm/src/mysql-core/columns/enum.ts | 12 +++--- drizzle-orm/src/mysql-core/columns/float.ts | 4 +- drizzle-orm/src/mysql-core/columns/int.ts | 9 ++--- drizzle-orm/src/mysql-core/columns/json.ts | 4 +- .../src/mysql-core/columns/mediumint.ts | 7 +--- drizzle-orm/src/mysql-core/columns/real.ts | 7 +--- drizzle-orm/src/mysql-core/columns/serial.ts | 6 +-- .../src/mysql-core/columns/smallint.ts | 7 +--- drizzle-orm/src/mysql-core/columns/text.ts | 38 +++++++------------ drizzle-orm/src/mysql-core/columns/time.ts | 7 +--- .../src/mysql-core/columns/timestamp.ts | 13 ++----- drizzle-orm/src/mysql-core/columns/tinyint.ts | 7 +--- .../src/mysql-core/columns/varbinary.ts | 7 +--- drizzle-orm/src/mysql-core/columns/varchar.ts | 11 ++---- drizzle-orm/src/mysql-core/columns/year.ts | 4 +- drizzle-orm/src/pg-core/columns/bigint.ts | 7 +--- drizzle-orm/src/pg-core/columns/bigserial.ts | 11 ++---- drizzle-orm/src/pg-core/columns/boolean.ts | 4 +- drizzle-orm/src/pg-core/columns/char.ts | 13 +++---- drizzle-orm/src/pg-core/columns/cidr.ts | 4 +- drizzle-orm/src/pg-core/columns/custom.ts | 2 +- drizzle-orm/src/pg-core/columns/date.ts | 11 ++---- .../src/pg-core/columns/double-precision.ts | 4 +- drizzle-orm/src/pg-core/columns/enum.ts | 4 +- drizzle-orm/src/pg-core/columns/inet.ts | 4 +- drizzle-orm/src/pg-core/columns/integer.ts | 4 +- drizzle-orm/src/pg-core/columns/interval.ts | 7 +--- drizzle-orm/src/pg-core/columns/json.ts | 4 +- drizzle-orm/src/pg-core/columns/jsonb.ts | 4 +- drizzle-orm/src/pg-core/columns/macaddr.ts | 4 +- drizzle-orm/src/pg-core/columns/macaddr8.ts | 4 +- drizzle-orm/src/pg-core/columns/numeric.ts | 9 ++--- .../columns/postgis_extension/geometry.ts | 11 ++---- .../pg-core/columns/postgis_extension/line.ts | 13 ++----- .../columns/postgis_extension/point.ts | 13 ++----- drizzle-orm/src/pg-core/columns/real.ts | 4 +- drizzle-orm/src/pg-core/columns/serial.ts | 6 +-- drizzle-orm/src/pg-core/columns/smallint.ts | 4 +- .../src/pg-core/columns/smallserial.ts | 6 +-- drizzle-orm/src/pg-core/columns/text.ts | 13 +++---- drizzle-orm/src/pg-core/columns/time.ts | 6 +-- drizzle-orm/src/pg-core/columns/timestamp.ts | 15 +++----- drizzle-orm/src/pg-core/columns/uuid.ts | 4 +- drizzle-orm/src/pg-core/columns/varchar.ts | 13 +++---- .../pg-core/columns/vector_extension/bit.ts | 7 +--- .../columns/vector_extension/halfvec.ts | 7 +--- .../columns/vector_extension/sparsevec.ts | 7 +--- .../columns/vector_extension/vector.ts | 7 +--- drizzle-orm/src/sqlite-core/columns/blob.ts | 2 +- drizzle-orm/src/sqlite-core/columns/custom.ts | 2 +- .../src/sqlite-core/columns/integer.ts | 2 +- drizzle-orm/src/sqlite-core/columns/text.ts | 4 +- drizzle-orm/src/utils.ts | 5 +-- 62 files changed, 175 insertions(+), 290 deletions(-) diff --git a/drizzle-orm/src/mysql-core/columns/bigint.ts b/drizzle-orm/src/mysql-core/columns/bigint.ts index 20af5131e..8c5e4f0b5 100644 --- a/drizzle-orm/src/mysql-core/columns/bigint.ts +++ b/drizzle-orm/src/mysql-core/columns/bigint.ts @@ -68,7 +68,7 @@ export class MySqlBigInt64Builder, ): TMode extends 'number' ? MySqlBigInt53BuilderInitial : MySqlBigInt64BuilderInitial; -export function bigint( - a?: TName | MySqlBigIntConfig, - b?: MySqlBigIntConfig, -): TMode extends 'number' ? MySqlBigInt53BuilderInitial : MySqlBigInt64BuilderInitial { - const { name, config } = getColumnNameAndConfig>(a, b); +export function bigint(a?: string | MySqlBigIntConfig, b?: MySqlBigIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); if (config.mode === 'number') { return new MySqlBigInt53Builder(name, config.unsigned) as any; } diff --git a/drizzle-orm/src/mysql-core/columns/binary.ts b/drizzle-orm/src/mysql-core/columns/binary.ts index 4c70def14..e9bcf5859 100644 --- a/drizzle-orm/src/mysql-core/columns/binary.ts +++ b/drizzle-orm/src/mysql-core/columns/binary.ts @@ -21,7 +21,7 @@ export class MySqlBinaryBuilder { static readonly [entityKind]: string = 'MySqlBinaryBuilder'; - constructor(name: string, length: number | undefined) { + constructor(name: T['name'], length: number | undefined) { super(name, 'string', 'MySqlBinary'); this.config.length = length; } @@ -59,10 +59,7 @@ export function binary( name: TName, config?: MySqlBinaryConfig, ): MySqlBinaryBuilderInitial; -export function binary( - a?: TName | MySqlBinaryConfig, - b: MySqlBinaryConfig = {}, -): MySqlBinaryBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function binary(a?: string | MySqlBinaryConfig, b: MySqlBinaryConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlBinaryBuilder(name, config.length); } diff --git a/drizzle-orm/src/mysql-core/columns/boolean.ts b/drizzle-orm/src/mysql-core/columns/boolean.ts index 1e01b1cc6..d1df78570 100644 --- a/drizzle-orm/src/mysql-core/columns/boolean.ts +++ b/drizzle-orm/src/mysql-core/columns/boolean.ts @@ -19,7 +19,7 @@ export class MySqlBooleanBuilder> export function boolean(): MySqlBooleanBuilderInitial<''>; export function boolean(name: TName): MySqlBooleanBuilderInitial; -export function boolean(name?: TName): MySqlBooleanBuilderInitial { +export function boolean(name?: string) { return new MySqlBooleanBuilder(name ?? ''); } diff --git a/drizzle-orm/src/mysql-core/columns/char.ts b/drizzle-orm/src/mysql-core/columns/char.ts index cbd3285a3..5c4424946 100644 --- a/drizzle-orm/src/mysql-core/columns/char.ts +++ b/drizzle-orm/src/mysql-core/columns/char.ts @@ -51,7 +51,7 @@ export class MySqlChar> } } -export interface MySqlCharConfig { +export interface MySqlCharConfig { length?: number; enum?: TEnum; } @@ -64,10 +64,7 @@ export function char>, ): MySqlCharBuilderInitial>; -export function char>( - a?: TName | MySqlCharConfig>, - b: MySqlCharConfig> = {}, -): MySqlCharBuilderInitial> { - const { name, config } = getColumnNameAndConfig>>(a, b); - return new MySqlCharBuilder(name, config); +export function char(a?: string | MySqlCharConfig, b: MySqlCharConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new MySqlCharBuilder(name, config as any); } diff --git a/drizzle-orm/src/mysql-core/columns/custom.ts b/drizzle-orm/src/mysql-core/columns/custom.ts index c42a6ca82..fcd89622a 100644 --- a/drizzle-orm/src/mysql-core/columns/custom.ts +++ b/drizzle-orm/src/mysql-core/columns/custom.ts @@ -226,7 +226,7 @@ export function customType( a?: TName | T['config'], b?: T['config'], ): MySqlCustomColumnBuilder> => { - const { name, config } = getColumnNameAndConfig(a, b); + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlCustomColumnBuilder(name as ConvertCustomConfig['name'], config, customTypeParams); }; } diff --git a/drizzle-orm/src/mysql-core/columns/date.ts b/drizzle-orm/src/mysql-core/columns/date.ts index 8ef069003..d5d29c8f9 100644 --- a/drizzle-orm/src/mysql-core/columns/date.ts +++ b/drizzle-orm/src/mysql-core/columns/date.ts @@ -106,13 +106,10 @@ export function date, ): Equal extends true ? MySqlDateStringBuilderInitial : MySqlDateBuilderInitial; -export function date( - a?: TName | MySqlDateConfig, - b?: MySqlDateConfig, -): Equal extends true ? MySqlDateStringBuilderInitial : MySqlDateBuilderInitial { - const { name, config } = getColumnNameAndConfig | undefined>(a, b); +export function date(a?: string | MySqlDateConfig, b?: MySqlDateConfig) { + const { name, config } = getColumnNameAndConfig(a, b); if (config?.mode === 'string') { - return new MySqlDateStringBuilder(name) as any; + return new MySqlDateStringBuilder(name); } - return new MySqlDateBuilder(name) as any; + return new MySqlDateBuilder(name); } diff --git a/drizzle-orm/src/mysql-core/columns/datetime.ts b/drizzle-orm/src/mysql-core/columns/datetime.ts index fa4245af8..5b6aa0104 100644 --- a/drizzle-orm/src/mysql-core/columns/datetime.ts +++ b/drizzle-orm/src/mysql-core/columns/datetime.ts @@ -128,13 +128,10 @@ export function datetime, ): Equal extends true ? MySqlDateTimeStringBuilderInitial : MySqlDateTimeBuilderInitial; -export function datetime( - a?: TName | MySqlDatetimeConfig, - b?: MySqlDatetimeConfig, -): Equal extends true ? MySqlDateTimeStringBuilderInitial : MySqlDateTimeBuilderInitial { - const { name, config } = getColumnNameAndConfig | undefined>(a, b); +export function datetime(a?: string | MySqlDatetimeConfig, b?: MySqlDatetimeConfig) { + const { name, config } = getColumnNameAndConfig(a, b); if (config?.mode === 'string') { - return new MySqlDateTimeStringBuilder(name, config) as any; + return new MySqlDateTimeStringBuilder(name, config); } - return new MySqlDateTimeBuilder(name, config) as any; + return new MySqlDateTimeBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index c6e0dff91..adc97650b 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -69,10 +69,7 @@ export function decimal( name: TName, config?: MySqlDecimalConfig, ): MySqlDecimalBuilderInitial; -export function decimal( - a?: TName | MySqlDecimalConfig, - b: MySqlDecimalConfig = {}, -): MySqlDecimalBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function decimal(a?: string | MySqlDecimalConfig, b: MySqlDecimalConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlDecimalBuilder(name, config.precision, config.scale); } diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index 43d95dc1b..6d33531e0 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -66,10 +66,7 @@ export function double( name: TName, config?: MySqlDoubleConfig, ): MySqlDoubleBuilderInitial; -export function double( - a?: TName | MySqlDoubleConfig, - b?: MySqlDoubleConfig, -): MySqlDoubleBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function double(a?: string | MySqlDoubleConfig, b?: MySqlDoubleConfig) { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlDoubleBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/enum.ts b/drizzle-orm/src/mysql-core/columns/enum.ts index 3df8cbf32..e73bec04c 100644 --- a/drizzle-orm/src/mysql-core/columns/enum.ts +++ b/drizzle-orm/src/mysql-core/columns/enum.ts @@ -56,15 +56,15 @@ export function mysqlEnum, ): MySqlEnumColumnBuilderInitial>; -export function mysqlEnum>( - a?: TName | T | Writable, - b?: T | Writable, -): MySqlEnumColumnBuilderInitial> { - const { name, config: values } = getColumnNameAndConfig>(a, b); +export function mysqlEnum( + a?: string | readonly [string, ...string[]] | [string, ...string[]], + b?: readonly [string, ...string[]] | [string, ...string[]] +): any { + const { name, config: values } = getColumnNameAndConfig(a, b); if (values.length === 0) { throw new Error(`You have an empty array for "${name}" enum values`); } - return new MySqlEnumColumnBuilder(name, values); + return new MySqlEnumColumnBuilder(name, values as any); } diff --git a/drizzle-orm/src/mysql-core/columns/float.ts b/drizzle-orm/src/mysql-core/columns/float.ts index a7dae67be..88b989077 100644 --- a/drizzle-orm/src/mysql-core/columns/float.ts +++ b/drizzle-orm/src/mysql-core/columns/float.ts @@ -19,7 +19,7 @@ export class MySqlFloatBuilder> exte export function float(): MySqlFloatBuilderInitial<''>; export function float(name: TName): MySqlFloatBuilderInitial; -export function float(name?: TName): MySqlFloatBuilderInitial { +export function float(name?: string) { return new MySqlFloatBuilder(name ?? ''); } diff --git a/drizzle-orm/src/mysql-core/columns/int.ts b/drizzle-orm/src/mysql-core/columns/int.ts index 9b231c2fe..15d0fa154 100644 --- a/drizzle-orm/src/mysql-core/columns/int.ts +++ b/drizzle-orm/src/mysql-core/columns/int.ts @@ -20,7 +20,7 @@ export class MySqlIntBuilder( name: TName, config?: MySqlIntConfig, ): MySqlIntBuilderInitial; -export function int( - a?: TName | MySqlIntConfig, - b?: MySqlIntConfig, -): MySqlIntBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function int(a?: string | MySqlIntConfig, b?: MySqlIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/json.ts b/drizzle-orm/src/mysql-core/columns/json.ts index 686852089..d57cf963c 100644 --- a/drizzle-orm/src/mysql-core/columns/json.ts +++ b/drizzle-orm/src/mysql-core/columns/json.ts @@ -17,7 +17,7 @@ export type MySqlJsonBuilderInitial = MySqlJsonBuilder<{ export class MySqlJsonBuilder> extends MySqlColumnBuilder { static readonly [entityKind]: string = 'MySqlJsonBuilder'; - constructor(name: string) { + constructor(name: T['name']) { super(name, 'json', 'MySqlJson'); } @@ -43,6 +43,6 @@ export class MySqlJson> extends export function json(): MySqlJsonBuilderInitial<''>; export function json(name: TName): MySqlJsonBuilderInitial; -export function json(name?: TName): MySqlJsonBuilderInitial { +export function json(name?: string) { return new MySqlJsonBuilder(name ?? ''); } diff --git a/drizzle-orm/src/mysql-core/columns/mediumint.ts b/drizzle-orm/src/mysql-core/columns/mediumint.ts index 60d9ce388..808304f64 100644 --- a/drizzle-orm/src/mysql-core/columns/mediumint.ts +++ b/drizzle-orm/src/mysql-core/columns/mediumint.ts @@ -62,10 +62,7 @@ export function mediumint( name: TName, config?: MySqlIntConfig, ): MySqlMediumIntBuilderInitial; -export function mediumint( - a?: TName | MySqlIntConfig, - b?: MySqlIntConfig, -): MySqlMediumIntBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function mediumint(a?: string | MySqlIntConfig, b?: MySqlIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlMediumIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/real.ts b/drizzle-orm/src/mysql-core/columns/real.ts index f96d65651..7ab6309d8 100644 --- a/drizzle-orm/src/mysql-core/columns/real.ts +++ b/drizzle-orm/src/mysql-core/columns/real.ts @@ -70,10 +70,7 @@ export function real( name: TName, config?: MySqlRealConfig, ): MySqlRealBuilderInitial; -export function real( - a?: TName | MySqlRealConfig, - b: MySqlRealConfig = {}, -): MySqlRealBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function real(a?: string | MySqlRealConfig, b: MySqlRealConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlRealBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/serial.ts b/drizzle-orm/src/mysql-core/columns/serial.ts index 4a5b877a0..43af900a1 100644 --- a/drizzle-orm/src/mysql-core/columns/serial.ts +++ b/drizzle-orm/src/mysql-core/columns/serial.ts @@ -35,7 +35,7 @@ export class MySqlSerialBuilder; export function serial(name: TName): MySqlSerialBuilderInitial; -export function serial(name?: TName): MySqlSerialBuilderInitial { - return new MySqlSerialBuilder(name ?? '') as MySqlSerialBuilderInitial; +export function serial(name?: string) { + return new MySqlSerialBuilder(name ?? ''); } diff --git a/drizzle-orm/src/mysql-core/columns/smallint.ts b/drizzle-orm/src/mysql-core/columns/smallint.ts index 9a20d164a..b7a6174e9 100644 --- a/drizzle-orm/src/mysql-core/columns/smallint.ts +++ b/drizzle-orm/src/mysql-core/columns/smallint.ts @@ -62,10 +62,7 @@ export function smallint( name: TName, config?: MySqlIntConfig, ): MySqlSmallIntBuilderInitial; -export function smallint( - a?: TName | MySqlIntConfig, - b?: MySqlIntConfig, -): MySqlSmallIntBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function smallint(a?: string | MySqlIntConfig, b?: MySqlIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlSmallIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/text.ts b/drizzle-orm/src/mysql-core/columns/text.ts index 5a49f4b1f..8a486d5a4 100644 --- a/drizzle-orm/src/mysql-core/columns/text.ts +++ b/drizzle-orm/src/mysql-core/columns/text.ts @@ -51,7 +51,7 @@ export class MySqlText> } } -export interface MySqlTextConfig { +export interface MySqlTextConfig { enum?: TEnum; } @@ -63,12 +63,9 @@ export function text>, ): MySqlTextBuilderInitial>; -export function text>( - a?: TName | MySqlTextConfig>, - b: MySqlTextConfig> = {}, -): MySqlTextBuilderInitial> { - const { name, config } = getColumnNameAndConfig>>(a, b); - return new MySqlTextBuilder(name, 'text', config); +export function text(a?: string | MySqlTextConfig, b: MySqlTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new MySqlTextBuilder(name, 'text', config as any); } export function tinytext(): MySqlTextBuilderInitial<'', [string, ...string[]]>; @@ -79,12 +76,9 @@ export function tinytext>, ): MySqlTextBuilderInitial>; -export function tinytext>( - a?: TName | MySqlTextConfig>, - b: MySqlTextConfig> = {}, -): MySqlTextBuilderInitial> { - const { name, config } = getColumnNameAndConfig>>(a, b); - return new MySqlTextBuilder(name, 'tinytext', config); +export function tinytext(a?: string | MySqlTextConfig, b: MySqlTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new MySqlTextBuilder(name, 'tinytext', config as any); } export function mediumtext(): MySqlTextBuilderInitial<'', [string, ...string[]]>; @@ -95,12 +89,9 @@ export function mediumtext>, ): MySqlTextBuilderInitial>; -export function mediumtext>( - a?: TName | MySqlTextConfig>, - b: MySqlTextConfig> = {}, -): MySqlTextBuilderInitial> { - const { name, config } = getColumnNameAndConfig>>(a, b); - return new MySqlTextBuilder(name, 'mediumtext', config); +export function mediumtext(a?: string | MySqlTextConfig, b: MySqlTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new MySqlTextBuilder(name, 'mediumtext', config as any); } export function longtext(): MySqlTextBuilderInitial<'', [string, ...string[]]>; @@ -111,10 +102,7 @@ export function longtext>, ): MySqlTextBuilderInitial>; -export function longtext>( - a?: TName | MySqlTextConfig>, - b: MySqlTextConfig> = {}, -): MySqlTextBuilderInitial> { - const { name, config } = getColumnNameAndConfig>>(a, b); - return new MySqlTextBuilder(name, 'longtext', config); +export function longtext(a?: string | MySqlTextConfig, b: MySqlTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new MySqlTextBuilder(name, 'longtext', config as any); } diff --git a/drizzle-orm/src/mysql-core/columns/time.ts b/drizzle-orm/src/mysql-core/columns/time.ts index 509ac80de..66941f585 100644 --- a/drizzle-orm/src/mysql-core/columns/time.ts +++ b/drizzle-orm/src/mysql-core/columns/time.ts @@ -62,10 +62,7 @@ export function time( name: TName, config?: TimeConfig, ): MySqlTimeBuilderInitial; -export function time( - a?: TName | TimeConfig, - b?: TimeConfig, -): MySqlTimeBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function time(a?: string | TimeConfig, b?: TimeConfig) { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlTimeBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/timestamp.ts b/drizzle-orm/src/mysql-core/columns/timestamp.ts index 97031fc89..4c5ca3a17 100644 --- a/drizzle-orm/src/mysql-core/columns/timestamp.ts +++ b/drizzle-orm/src/mysql-core/columns/timestamp.ts @@ -118,15 +118,10 @@ export function timestamp, ): Equal extends true ? MySqlTimestampStringBuilderInitial : MySqlTimestampBuilderInitial; -export function timestamp( - a?: TName | MySqlTimestampConfig, - b: MySqlTimestampConfig = {}, -): Equal extends true ? MySqlTimestampStringBuilderInitial - : MySqlTimestampBuilderInitial -{ - const { name, config } = getColumnNameAndConfig | undefined>(a, b); +export function timestamp(a?: string | MySqlTimestampConfig, b: MySqlTimestampConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); if (config?.mode === 'string') { - return new MySqlTimestampStringBuilder(name, config) as any; + return new MySqlTimestampStringBuilder(name, config); } - return new MySqlTimestampBuilder(name, config) as any; + return new MySqlTimestampBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/tinyint.ts b/drizzle-orm/src/mysql-core/columns/tinyint.ts index adc6d5774..df1999889 100644 --- a/drizzle-orm/src/mysql-core/columns/tinyint.ts +++ b/drizzle-orm/src/mysql-core/columns/tinyint.ts @@ -62,10 +62,7 @@ export function tinyint( name: TName, config?: MySqlIntConfig, ): MySqlTinyIntBuilderInitial; -export function tinyint( - a?: TName | MySqlIntConfig, - b?: MySqlIntConfig, -): MySqlTinyIntBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function tinyint(a?: string | MySqlIntConfig, b?: MySqlIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlTinyIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/varbinary.ts b/drizzle-orm/src/mysql-core/columns/varbinary.ts index 201580235..d90b02faa 100644 --- a/drizzle-orm/src/mysql-core/columns/varbinary.ts +++ b/drizzle-orm/src/mysql-core/columns/varbinary.ts @@ -60,10 +60,7 @@ export function varbinary( name: TName, config: MySqlVarbinaryOptions, ): MySqlVarBinaryBuilderInitial; -export function varbinary( - a?: TName | MySqlVarbinaryOptions, - b?: MySqlVarbinaryOptions, -): MySqlVarBinaryBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function varbinary(a?: string | MySqlVarbinaryOptions, b?: MySqlVarbinaryOptions) { + const { name, config } = getColumnNameAndConfig(a, b); return new MySqlVarBinaryBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/varchar.ts b/drizzle-orm/src/mysql-core/columns/varchar.ts index 72f63dbeb..fdb0a5fb0 100644 --- a/drizzle-orm/src/mysql-core/columns/varchar.ts +++ b/drizzle-orm/src/mysql-core/columns/varchar.ts @@ -54,7 +54,7 @@ export class MySqlVarChar> } } -export interface MySqlVarCharConfig { +export interface MySqlVarCharConfig { length: number; enum?: TEnum; } @@ -66,10 +66,7 @@ export function varchar>, ): MySqlVarCharBuilderInitial>; -export function varchar>( - a?: TName | MySqlVarCharConfig>, - b?: MySqlVarCharConfig>, -): MySqlVarCharBuilderInitial> { - const { name, config } = getColumnNameAndConfig>>(a, b); - return new MySqlVarCharBuilder(name, config); +export function varchar(a?: string | MySqlVarCharConfig, b?: MySqlVarCharConfig): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new MySqlVarCharBuilder(name, config as any); } diff --git a/drizzle-orm/src/mysql-core/columns/year.ts b/drizzle-orm/src/mysql-core/columns/year.ts index a54d7eeb8..27a81f887 100644 --- a/drizzle-orm/src/mysql-core/columns/year.ts +++ b/drizzle-orm/src/mysql-core/columns/year.ts @@ -17,7 +17,7 @@ export type MySqlYearBuilderInitial = MySqlYearBuilder<{ export class MySqlYearBuilder> extends MySqlColumnBuilder { static readonly [entityKind]: string = 'MySqlYearBuilder'; - constructor(name: string) { + constructor(name: T['name']) { super(name, 'number', 'MySqlYear'); } @@ -41,6 +41,6 @@ export class MySqlYear< export function year(): MySqlYearBuilderInitial<''>; export function year(name: TName): MySqlYearBuilderInitial; -export function year(name?: TName): MySqlYearBuilderInitial { +export function year(name?: string) { return new MySqlYearBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/bigint.ts b/drizzle-orm/src/pg-core/columns/bigint.ts index f6a53c28b..20fbcce47 100644 --- a/drizzle-orm/src/pg-core/columns/bigint.ts +++ b/drizzle-orm/src/pg-core/columns/bigint.ts @@ -103,11 +103,8 @@ export function bigint, ): TMode extends 'number' ? PgBigInt53BuilderInitial : PgBigInt64BuilderInitial; -export function bigint( - a: TName | PgBigIntConfig, - b?: PgBigIntConfig, -): TMode extends 'number' ? PgBigInt53BuilderInitial : PgBigInt64BuilderInitial { - const { name, config } = getColumnNameAndConfig>(a, b); +export function bigint(a: string | PgBigIntConfig, b?: PgBigIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); if (config.mode === 'number') { return new PgBigInt53Builder(name) as any; } diff --git a/drizzle-orm/src/pg-core/columns/bigserial.ts b/drizzle-orm/src/pg-core/columns/bigserial.ts index 8c53fb686..d41fdbeb7 100644 --- a/drizzle-orm/src/pg-core/columns/bigserial.ts +++ b/drizzle-orm/src/pg-core/columns/bigserial.ts @@ -121,13 +121,10 @@ export function bigserial, ): TMode extends 'number' ? PgBigSerial53BuilderInitial : PgBigSerial64BuilderInitial; -export function bigserial( - a: TName | PgBigSerialConfig, - b?: PgBigSerialConfig -): TMode extends 'number' ? PgBigSerial53BuilderInitial : PgBigSerial64BuilderInitial { - const { name, config } = getColumnNameAndConfig>(a, b); +export function bigserial(a: string | PgBigSerialConfig, b?: PgBigSerialConfig) { + const { name, config } = getColumnNameAndConfig(a, b); if (config.mode === 'number') { - return new PgBigSerial53Builder(name) as any; + return new PgBigSerial53Builder(name); } - return new PgBigSerial64Builder(name) as any; + return new PgBigSerial64Builder(name); } diff --git a/drizzle-orm/src/pg-core/columns/boolean.ts b/drizzle-orm/src/pg-core/columns/boolean.ts index a82fa5da4..fc24197ce 100644 --- a/drizzle-orm/src/pg-core/columns/boolean.ts +++ b/drizzle-orm/src/pg-core/columns/boolean.ts @@ -17,7 +17,7 @@ export type PgBooleanBuilderInitial = PgBooleanBuilder<{ export class PgBooleanBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgBooleanBuilder'; - constructor(name: string) { + constructor(name: T['name']) { super(name, 'boolean', 'PgBoolean'); } @@ -39,6 +39,6 @@ export class PgBoolean> exten export function boolean(): PgBooleanBuilderInitial<''>; export function boolean(name: TName): PgBooleanBuilderInitial -export function boolean(name?: TName): PgBooleanBuilderInitial { +export function boolean(name?: string) { return new PgBooleanBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/char.ts b/drizzle-orm/src/pg-core/columns/char.ts index e510805a7..b772c8718 100644 --- a/drizzle-orm/src/pg-core/columns/char.ts +++ b/drizzle-orm/src/pg-core/columns/char.ts @@ -21,7 +21,7 @@ export class PgCharBuilder > { static readonly [entityKind]: string = 'PgCharBuilder'; - constructor(name: string, config: PgCharConfig) { + constructor(name: T['name'], config: PgCharConfig) { super(name, 'string', 'PgChar'); this.config.length = config.length; this.config.enumValues = config.enum; @@ -48,7 +48,7 @@ export class PgChar> } } -export interface PgCharConfig { +export interface PgCharConfig { length?: number; enum?: TEnum; } @@ -61,10 +61,7 @@ export function char>, ): PgCharBuilderInitial>; -export function char>( - a?: TName | PgCharConfig>, - b: PgCharConfig> = {}, -): PgCharBuilderInitial> { - const { name, config } = getColumnNameAndConfig>>(a, b); - return new PgCharBuilder(name, config); +export function char(a?: string | PgCharConfig, b: PgCharConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new PgCharBuilder(name, config as any); } diff --git a/drizzle-orm/src/pg-core/columns/cidr.ts b/drizzle-orm/src/pg-core/columns/cidr.ts index 08093eb2b..8ab375ba1 100644 --- a/drizzle-orm/src/pg-core/columns/cidr.ts +++ b/drizzle-orm/src/pg-core/columns/cidr.ts @@ -17,7 +17,7 @@ export type PgCidrBuilderInitial = PgCidrBuilder<{ export class PgCidrBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgCidrBuilder'; - constructor(name: string) { + constructor(name: T['name']) { super(name, 'string', 'PgCidr'); } @@ -39,6 +39,6 @@ export class PgCidr> extends PgCo export function cidr(): PgCidrBuilderInitial<''>; export function cidr(name: TName): PgCidrBuilderInitial; -export function cidr(name?: TName): PgCidrBuilderInitial { +export function cidr(name?: string) { return new PgCidrBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/custom.ts b/drizzle-orm/src/pg-core/columns/custom.ts index 2ac3f356e..6d34985a9 100644 --- a/drizzle-orm/src/pg-core/columns/custom.ts +++ b/drizzle-orm/src/pg-core/columns/custom.ts @@ -226,7 +226,7 @@ export function customType( a?: TName | T['config'], b?: T['config'], ): PgCustomColumnBuilder> => { - const { name, config } = getColumnNameAndConfig(a, b); + const { name, config } = getColumnNameAndConfig(a, b); return new PgCustomColumnBuilder(name as ConvertCustomConfig['name'], config, customTypeParams); }; } diff --git a/drizzle-orm/src/pg-core/columns/date.ts b/drizzle-orm/src/pg-core/columns/date.ts index d3caf5442..a8c5fcc4a 100644 --- a/drizzle-orm/src/pg-core/columns/date.ts +++ b/drizzle-orm/src/pg-core/columns/date.ts @@ -97,13 +97,10 @@ export function date, ): Equal extends true ? PgDateBuilderInitial : PgDateStringBuilderInitial; -export function date( - a?: TName | PgDateConfig, - b?: PgDateConfig, -): Equal extends true ? PgDateBuilderInitial : PgDateStringBuilderInitial { - const { name, config } = getColumnNameAndConfig>(a, b); +export function date(a?: string | PgDateConfig, b?: PgDateConfig) { + const { name, config } = getColumnNameAndConfig(a, b); if (config?.mode === 'date') { - return new PgDateBuilder(name) as any; + return new PgDateBuilder(name); } - return new PgDateStringBuilder(name) as any; + return new PgDateStringBuilder(name); } diff --git a/drizzle-orm/src/pg-core/columns/double-precision.ts b/drizzle-orm/src/pg-core/columns/double-precision.ts index 466dc58b4..8e454169f 100644 --- a/drizzle-orm/src/pg-core/columns/double-precision.ts +++ b/drizzle-orm/src/pg-core/columns/double-precision.ts @@ -19,7 +19,7 @@ export class PgDoublePrecisionBuilder; export function doublePrecision(name: TName): PgDoublePrecisionBuilderInitial; -export function doublePrecision(name?: TName): PgDoublePrecisionBuilderInitial { +export function doublePrecision(name?: string) { return new PgDoublePrecisionBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/enum.ts b/drizzle-orm/src/pg-core/columns/enum.ts index 2c4821933..d35ec89d9 100644 --- a/drizzle-orm/src/pg-core/columns/enum.ts +++ b/drizzle-orm/src/pg-core/columns/enum.ts @@ -38,7 +38,7 @@ export class PgEnumColumnBuilder< > extends PgColumnBuilder }> { static readonly [entityKind]: string = 'PgEnumColumnBuilder'; - constructor(name: string, enumInstance: PgEnum) { + constructor(name: T['name'], enumInstance: PgEnum) { super(name, 'string', 'PgEnumColumn'); this.config.enum = enumInstance; } @@ -91,7 +91,7 @@ export function pgEnumWithSchema> { const enumInstance: PgEnum> = Object.assign( (name?: TName): PgEnumColumnBuilderInitial> => - new PgEnumColumnBuilder(name ?? '', enumInstance), + new PgEnumColumnBuilder(name ?? '' as TName, enumInstance), { enumName, enumValues: values, diff --git a/drizzle-orm/src/pg-core/columns/inet.ts b/drizzle-orm/src/pg-core/columns/inet.ts index d9ce18690..a675359b3 100644 --- a/drizzle-orm/src/pg-core/columns/inet.ts +++ b/drizzle-orm/src/pg-core/columns/inet.ts @@ -17,7 +17,7 @@ export type PgInetBuilderInitial = PgInetBuilder<{ export class PgInetBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgInetBuilder'; - constructor(name: string) { + constructor(name: T['name']) { super(name, 'string', 'PgInet'); } @@ -39,6 +39,6 @@ export class PgInet> extends PgCo export function inet(): PgInetBuilderInitial<''>; export function inet(name: TName): PgInetBuilderInitial; -export function inet(name?: TName): PgInetBuilderInitial { +export function inet(name?: string) { return new PgInetBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/integer.ts b/drizzle-orm/src/pg-core/columns/integer.ts index 8344d7253..0feb388f3 100644 --- a/drizzle-orm/src/pg-core/columns/integer.ts +++ b/drizzle-orm/src/pg-core/columns/integer.ts @@ -20,7 +20,7 @@ export class PgIntegerBuilder> extend export function integer(): PgIntegerBuilderInitial<''>; export function integer(name: TName): PgIntegerBuilderInitial; -export function integer(name?: TName): PgIntegerBuilderInitial { +export function integer(name?: string) { return new PgIntegerBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/interval.ts b/drizzle-orm/src/pg-core/columns/interval.ts index 9730d43e1..1e7a96a7a 100644 --- a/drizzle-orm/src/pg-core/columns/interval.ts +++ b/drizzle-orm/src/pg-core/columns/interval.ts @@ -78,10 +78,7 @@ export function interval( name: TName, config?: IntervalConfig, ): PgIntervalBuilderInitial; -export function interval( - a?: TName | IntervalConfig, - b: IntervalConfig = {}, -): PgIntervalBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function interval(a?: string | IntervalConfig, b: IntervalConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); return new PgIntervalBuilder(name, config); } diff --git a/drizzle-orm/src/pg-core/columns/json.ts b/drizzle-orm/src/pg-core/columns/json.ts index 34def405b..7e232db5e 100644 --- a/drizzle-orm/src/pg-core/columns/json.ts +++ b/drizzle-orm/src/pg-core/columns/json.ts @@ -19,7 +19,7 @@ export class PgJsonBuilder> > { static readonly [entityKind]: string = 'PgJsonBuilder'; - constructor(name: string) { + constructor(name: T['name']) { super(name, 'json', 'PgJson'); } @@ -60,6 +60,6 @@ export class PgJson> extends PgColu export function json(): PgJsonBuilderInitial<''>; export function json(name: TName): PgJsonBuilderInitial; -export function json(name?: TName): PgJsonBuilderInitial { +export function json(name?: string) { return new PgJsonBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/jsonb.ts b/drizzle-orm/src/pg-core/columns/jsonb.ts index 8c9e3dfde..89d1be86a 100644 --- a/drizzle-orm/src/pg-core/columns/jsonb.ts +++ b/drizzle-orm/src/pg-core/columns/jsonb.ts @@ -17,7 +17,7 @@ export type PgJsonbBuilderInitial = PgJsonbBuilder<{ export class PgJsonbBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgJsonbBuilder'; - constructor(name: string) { + constructor(name: T['name']) { super(name, 'json', 'PgJsonb'); } @@ -58,6 +58,6 @@ export class PgJsonb> extends PgCo export function jsonb(): PgJsonbBuilderInitial<''>; export function jsonb(name: TName): PgJsonbBuilderInitial; -export function jsonb(name?: TName): PgJsonbBuilderInitial { +export function jsonb(name?: string) { return new PgJsonbBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/macaddr.ts b/drizzle-orm/src/pg-core/columns/macaddr.ts index 1a0000d72..876c2d841 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr.ts @@ -17,7 +17,7 @@ export type PgMacaddrBuilderInitial = PgMacaddrBuilder<{ export class PgMacaddrBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgMacaddrBuilder'; - constructor(name: string) { + constructor(name: T['name']) { super(name, 'string', 'PgMacaddr'); } @@ -39,6 +39,6 @@ export class PgMacaddr> extend export function macaddr(): PgMacaddrBuilderInitial<''> export function macaddr(name: TName): PgMacaddrBuilderInitial -export function macaddr(name?: TName): PgMacaddrBuilderInitial { +export function macaddr(name?: string) { return new PgMacaddrBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/macaddr8.ts b/drizzle-orm/src/pg-core/columns/macaddr8.ts index 73e353c97..5ba1324b7 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr8.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr8.ts @@ -17,7 +17,7 @@ export type PgMacaddr8BuilderInitial = PgMacaddr8Builder<{ export class PgMacaddr8Builder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgMacaddr8Builder'; - constructor(name: string) { + constructor(name: T['name']) { super(name, 'string', 'PgMacaddr8'); } @@ -39,6 +39,6 @@ export class PgMacaddr8> exte export function macaddr8(): PgMacaddr8BuilderInitial<''> export function macaddr8(name: TName): PgMacaddr8BuilderInitial -export function macaddr8(name?: TName): PgMacaddr8BuilderInitial { +export function macaddr8(name?: string) { return new PgMacaddr8Builder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/numeric.ts b/drizzle-orm/src/pg-core/columns/numeric.ts index 5834b3cbc..fafe10481 100644 --- a/drizzle-orm/src/pg-core/columns/numeric.ts +++ b/drizzle-orm/src/pg-core/columns/numeric.ts @@ -24,7 +24,7 @@ export class PgNumericBuilder { static readonly [entityKind]: string = 'PgNumericBuilder'; - constructor(name: string, precision?: number, scale?: number) { + constructor(name: T['name'], precision?: number, scale?: number) { super(name, 'string', 'PgNumeric'); this.config.precision = precision; this.config.scale = scale; @@ -74,11 +74,8 @@ export function numeric( name: TName, config?: PgNumericConfig, ): PgNumericBuilderInitial; -export function numeric( - a?: TName | PgNumericConfig, - b?: PgNumericConfig, -): PgNumericBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function numeric(a?: string | PgNumericConfig, b?: PgNumericConfig) { + const { name, config } = getColumnNameAndConfig(a, b); return new PgNumericBuilder(name, config?.precision, config?.scale); } diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts index 756b43282..25b355022 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts @@ -112,13 +112,10 @@ export function geometry, ): Equal extends true ? PgGeometryObjectBuilderInitial : PgGeometryBuilderInitial; -export function geometry( - a?: TName | PgGeometryConfig, - b?: PgGeometryConfig, -): Equal extends true ? PgGeometryObjectBuilderInitial : PgGeometryBuilderInitial { - const { name, config } = getColumnNameAndConfig>(a, b); +export function geometry(a?: string | PgGeometryConfig, b?: PgGeometryConfig) { + const { name, config } = getColumnNameAndConfig(a, b); if (!config?.mode || config.mode === 'tuple') { - return new PgGeometryBuilder(name) as any; + return new PgGeometryBuilder(name); } - return new PgGeometryObjectBuilder(name) as any; + return new PgGeometryObjectBuilder(name); } diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts index 54201af22..a47b6aaa7 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts @@ -110,15 +110,10 @@ export function line, ): Equal extends true ? PgLineABCBuilderInitial : PgLineBuilderInitial; -export function line( - a?: TName | PgLineTypeConfig, - b?: PgLineTypeConfig, -): Equal extends true ? PgLineABCBuilderInitial - : PgLineBuilderInitial -{ - const { name, config } = getColumnNameAndConfig>(a, b); +export function line(a?: string | PgLineTypeConfig, b?: PgLineTypeConfig) { + const { name, config } = getColumnNameAndConfig(a, b); if (!config?.mode || config.mode === 'tuple') { - return new PgLineBuilder(name) as any; + return new PgLineBuilder(name); } - return new PgLineABCBuilder(name) as any; + return new PgLineABCBuilder(name); } diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts index d408e1c7f..5e3ee2409 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts @@ -120,15 +120,10 @@ export function point, ): Equal extends true ? PgPointObjectBuilderInitial : PgPointTupleBuilderInitial; -export function point( - a?: TName | PgPointConfig, - b?: PgPointConfig, -): Equal extends true ? PgPointObjectBuilderInitial - : PgPointTupleBuilderInitial -{ - const { name, config } = getColumnNameAndConfig>(a, b); +export function point(a?: string | PgPointConfig, b?: PgPointConfig) { + const { name, config } = getColumnNameAndConfig(a, b); if (!config?.mode || config.mode === 'tuple') { - return new PgPointTupleBuilder(name) as any; + return new PgPointTupleBuilder(name); } - return new PgPointObjectBuilder(name) as any; + return new PgPointObjectBuilder(name); } diff --git a/drizzle-orm/src/pg-core/columns/real.ts b/drizzle-orm/src/pg-core/columns/real.ts index 45ac9ba86..f39527a45 100644 --- a/drizzle-orm/src/pg-core/columns/real.ts +++ b/drizzle-orm/src/pg-core/columns/real.ts @@ -20,7 +20,7 @@ export class PgRealBuilder > { static readonly [entityKind]: string = 'PgRealBuilder'; - constructor(name: string, length?: number) { + constructor(name: T['name'], length?: number) { super(name, 'number', 'PgReal'); this.config.length = length; } @@ -54,6 +54,6 @@ export class PgReal> extends PgCo export function real(): PgRealBuilderInitial<''>; export function real(name: TName): PgRealBuilderInitial; -export function real(name?: TName): PgRealBuilderInitial { +export function real(name?: string) { return new PgRealBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/serial.ts b/drizzle-orm/src/pg-core/columns/serial.ts index 0a8eaf223..195c000d3 100644 --- a/drizzle-orm/src/pg-core/columns/serial.ts +++ b/drizzle-orm/src/pg-core/columns/serial.ts @@ -27,7 +27,7 @@ export type PgSerialBuilderInitial = NotNull< export class PgSerialBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgSerialBuilder'; - constructor(name: string) { + constructor(name: T['name']) { super(name, 'number', 'PgSerial'); this.config.hasDefault = true; this.config.notNull = true; @@ -51,6 +51,6 @@ export class PgSerial> extends export function serial(): PgSerialBuilderInitial<''>; export function serial(name: TName): PgSerialBuilderInitial -export function serial(name?: TName): PgSerialBuilderInitial { - return new PgSerialBuilder(name ?? '') as PgSerialBuilderInitial; +export function serial(name?: string) { + return new PgSerialBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/smallint.ts b/drizzle-orm/src/pg-core/columns/smallint.ts index d22ef42b2..20204cd3c 100644 --- a/drizzle-orm/src/pg-core/columns/smallint.ts +++ b/drizzle-orm/src/pg-core/columns/smallint.ts @@ -20,7 +20,7 @@ export class PgSmallIntBuilder> exte export function smallint(): PgSmallIntBuilderInitial<''>; export function smallint(name: TName): PgSmallIntBuilderInitial; -export function smallint(name?: TName): PgSmallIntBuilderInitial { +export function smallint(name?: string) { return new PgSmallIntBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/smallserial.ts b/drizzle-orm/src/pg-core/columns/smallserial.ts index 27dc27e17..8f4e56d5c 100644 --- a/drizzle-orm/src/pg-core/columns/smallserial.ts +++ b/drizzle-orm/src/pg-core/columns/smallserial.ts @@ -29,7 +29,7 @@ export class PgSmallSerialBuilder export function smallserial(): PgSmallSerialBuilderInitial<''> export function smallserial(name: TName): PgSmallSerialBuilderInitial; -export function smallserial(name?: TName): PgSmallSerialBuilderInitial { - return new PgSmallSerialBuilder(name ?? '') as PgSmallSerialBuilderInitial; +export function smallserial(name?: string) { + return new PgSmallSerialBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/text.ts b/drizzle-orm/src/pg-core/columns/text.ts index 75ecac69d..c5a393005 100644 --- a/drizzle-orm/src/pg-core/columns/text.ts +++ b/drizzle-orm/src/pg-core/columns/text.ts @@ -21,7 +21,7 @@ export class PgTextBuilder< static readonly [entityKind]: string = 'PgTextBuilder'; constructor( - name: string, + name: T['name'], config: PgTextConfig, ) { super(name, 'string', 'PgText'); @@ -48,7 +48,7 @@ export class PgText> } } -export interface PgTextConfig { +export interface PgTextConfig { enum?: TEnum; } @@ -60,10 +60,7 @@ export function text>, ): PgTextBuilderInitial>; -export function text>( - a?: TName | PgTextConfig>, - b: PgTextConfig> = {}, -): PgTextBuilderInitial> { - const { name, config } = getColumnNameAndConfig>>(a, b); - return new PgTextBuilder(name, config); +export function text(a?: string | PgTextConfig, b: PgTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new PgTextBuilder(name, config as any); } diff --git a/drizzle-orm/src/pg-core/columns/time.ts b/drizzle-orm/src/pg-core/columns/time.ts index 8ab669f64..d67616491 100644 --- a/drizzle-orm/src/pg-core/columns/time.ts +++ b/drizzle-orm/src/pg-core/columns/time.ts @@ -24,7 +24,7 @@ export class PgTimeBuilder static readonly [entityKind]: string = 'PgTimeBuilder'; constructor( - name: string, + name: T['name'], readonly withTimezone: boolean, readonly precision: number | undefined, ) { @@ -67,7 +67,7 @@ export interface TimeConfig { export function time(): PgTimeBuilderInitial<''>; export function time(config?: TimeConfig): PgTimeBuilderInitial<''>; export function time(name: TName, config?: TimeConfig): PgTimeBuilderInitial; -export function time(a?: TName, b: TimeConfig = {}): PgTimeBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function time(a?: string | TimeConfig, b: TimeConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); return new PgTimeBuilder(name, config.withTimezone ?? false, config.precision); } diff --git a/drizzle-orm/src/pg-core/columns/timestamp.ts b/drizzle-orm/src/pg-core/columns/timestamp.ts index 1ef73ce8b..d89697213 100644 --- a/drizzle-orm/src/pg-core/columns/timestamp.ts +++ b/drizzle-orm/src/pg-core/columns/timestamp.ts @@ -25,7 +25,7 @@ export class PgTimestampBuilder, ): Equal extends true ? PgTimestampStringBuilderInitial : PgTimestampBuilderInitial; -export function timestamp( - a?: TName | PgTimestampConfig, - b: PgTimestampConfig = {}, -): Equal extends true ? PgTimestampStringBuilderInitial : PgTimestampBuilderInitial { - const { name, config } = getColumnNameAndConfig | undefined>(a, b); +export function timestamp(a?: string | PgTimestampConfig, b: PgTimestampConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); if (config?.mode === 'string') { - return new PgTimestampStringBuilder(name, config.withTimezone ?? false, config.precision) as any; + return new PgTimestampStringBuilder(name, config.withTimezone ?? false, config.precision); } - return new PgTimestampBuilder(name, config?.withTimezone ?? false, config?.precision) as any; + return new PgTimestampBuilder(name, config?.withTimezone ?? false, config?.precision); } diff --git a/drizzle-orm/src/pg-core/columns/uuid.ts b/drizzle-orm/src/pg-core/columns/uuid.ts index b42e1c030..851036d8d 100644 --- a/drizzle-orm/src/pg-core/columns/uuid.ts +++ b/drizzle-orm/src/pg-core/columns/uuid.ts @@ -18,7 +18,7 @@ export type PgUUIDBuilderInitial = PgUUIDBuilder<{ export class PgUUIDBuilder> extends PgColumnBuilder { static readonly [entityKind]: string = 'PgUUIDBuilder'; - constructor(name: string) { + constructor(name: T['name']) { super(name, 'string', 'PgUUID'); } @@ -47,6 +47,6 @@ export class PgUUID> extends PgCo export function uuid(): PgUUIDBuilderInitial<''>; export function uuid(name: TName): PgUUIDBuilderInitial; -export function uuid(name?: TName): PgUUIDBuilderInitial { +export function uuid(name?: string) { return new PgUUIDBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/varchar.ts b/drizzle-orm/src/pg-core/columns/varchar.ts index dedcb758a..454b2834c 100644 --- a/drizzle-orm/src/pg-core/columns/varchar.ts +++ b/drizzle-orm/src/pg-core/columns/varchar.ts @@ -21,7 +21,7 @@ export class PgVarcharBuilder { static readonly [entityKind]: string = 'PgVarcharBuilder'; - constructor(name: string, config: PgVarcharConfig) { + constructor(name: T['name'], config: PgVarcharConfig) { super(name, 'string', 'PgVarchar'); this.config.length = config.length; this.config.enumValues = config.enum; @@ -48,7 +48,7 @@ export class PgVarchar> } } -export interface PgVarcharConfig { +export interface PgVarcharConfig { length?: number; enum?: TEnum; } @@ -61,10 +61,7 @@ export function varchar>, ): PgVarcharBuilderInitial>; -export function varchar>( - a?: TName | PgVarcharConfig>, - b: PgVarcharConfig> = {}, -): PgVarcharBuilderInitial> { - const { name, config } = getColumnNameAndConfig>>(a, b); - return new PgVarcharBuilder(name, config); +export function varchar(a?: string | PgVarcharConfig, b: PgVarcharConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new PgVarcharBuilder(name, config as any); } diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts index 97d1a30d2..28d26447c 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts @@ -62,10 +62,7 @@ export function bit( name: TName, config: PgBinaryVectorConfig, ): PgBinaryVectorBuilderInitial; -export function bit( - a: TName | PgBinaryVectorConfig, - b?: PgBinaryVectorConfig, -): PgBinaryVectorBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function bit(a: string | PgBinaryVectorConfig, b?: PgBinaryVectorConfig) { + const { name, config } = getColumnNameAndConfig(a, b); return new PgBinaryVectorBuilder(name, config); } diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts index 65fe6d501..a8a3f240f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts @@ -71,10 +71,7 @@ export function halfvec( name: TName, config: PgHalfVectorConfig, ): PgHalfVectorBuilderInitial; -export function halfvec( - a: TName | PgHalfVectorConfig, - b?: PgHalfVectorConfig, -): PgHalfVectorBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function halfvec(a: string | PgHalfVectorConfig, b?: PgHalfVectorConfig) { + const { name, config } = getColumnNameAndConfig(a, b); return new PgHalfVectorBuilder(name, config); } diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts index 3da6e49e8..e06efd7a7 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts @@ -62,10 +62,7 @@ export function sparsevec( name: TName, config: PgSparseVectorConfig, ): PgSparseVectorBuilderInitial; -export function sparsevec( - a: TName | PgSparseVectorConfig, - b?: PgSparseVectorConfig, -): PgSparseVectorBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function sparsevec(a: string | PgSparseVectorConfig, b?: PgSparseVectorConfig) { + const { name, config } = getColumnNameAndConfig(a, b); return new PgSparseVectorBuilder(name, config); } diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts index ff5eb7485..2e8724bdf 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts @@ -68,10 +68,7 @@ export function vector( name: TName, config: PgVectorConfig, ): PgVectorBuilderInitial; -export function vector( - a: TName | PgVectorConfig, - b?: PgVectorConfig, -): PgVectorBuilderInitial { - const { name, config } = getColumnNameAndConfig(a, b); +export function vector(a: string | PgVectorConfig, b?: PgVectorConfig) { + const { name, config } = getColumnNameAndConfig(a, b); return new PgVectorBuilder(name, config); } diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index c20211dea..b680fd166 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -154,7 +154,7 @@ export function blob( : Equal extends true ? SQLiteBlobBufferBuilderInitial : SQLiteBlobJsonBuilderInitial; export function blob(a?: string | BlobConfig,b?: BlobConfig) { - const { name, config } = getColumnNameAndConfig(a, b); + const { name, config } = getColumnNameAndConfig(a, b); if (config?.mode === 'json') { return new SQLiteBlobJsonBuilder(name); } diff --git a/drizzle-orm/src/sqlite-core/columns/custom.ts b/drizzle-orm/src/sqlite-core/columns/custom.ts index 109b4f0e1..c190ab2b1 100644 --- a/drizzle-orm/src/sqlite-core/columns/custom.ts +++ b/drizzle-orm/src/sqlite-core/columns/custom.ts @@ -226,7 +226,7 @@ export function customType( a?: TName | T['config'], b?: T['config'], ): SQLiteCustomColumnBuilder> => { - const { name, config } = getColumnNameAndConfig(a, b); + const { name, config } = getColumnNameAndConfig(a, b); return new SQLiteCustomColumnBuilder( name as ConvertCustomConfig['name'], config, diff --git a/drizzle-orm/src/sqlite-core/columns/integer.ts b/drizzle-orm/src/sqlite-core/columns/integer.ts index c7052fdc6..bec642ff6 100644 --- a/drizzle-orm/src/sqlite-core/columns/integer.ts +++ b/drizzle-orm/src/sqlite-core/columns/integer.ts @@ -227,7 +227,7 @@ export function integer extends true ? SQLiteBooleanBuilderInitial : SQLiteIntegerBuilderInitial; export function integer(a?: string | IntegerConfig, b?: IntegerConfig) { - const { name, config } = getColumnNameAndConfig(a, b); + const { name, config } = getColumnNameAndConfig(a, b); if (config?.mode === 'timestamp' || config?.mode === 'timestamp_ms') { return new SQLiteTimestampBuilder(name, config.mode); } diff --git a/drizzle-orm/src/sqlite-core/columns/text.ts b/drizzle-orm/src/sqlite-core/columns/text.ts index a9b6b2441..d00ce2da4 100644 --- a/drizzle-orm/src/sqlite-core/columns/text.ts +++ b/drizzle-orm/src/sqlite-core/columns/text.ts @@ -106,7 +106,7 @@ export class SQLiteTextJson export type SQLiteTextConfig< TMode extends 'text' | 'json' = 'text' | 'json', - TEnum extends readonly string[] | string[] | undefined = string[] | string[] | undefined, + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, > = TMode extends 'text' ? { mode?: TMode; length?: number; @@ -136,7 +136,7 @@ export function text< ): Equal extends true ? SQLiteTextJsonBuilderInitial : SQLiteTextBuilderInitial>; export function text(a?: string | SQLiteTextConfig, b: SQLiteTextConfig = {}): any { - const { name, config } = getColumnNameAndConfig(a, b); + const { name, config } = getColumnNameAndConfig(a, b); if (config.mode === 'json') { return new SQLiteTextJsonBuilder(name); } diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index 4ca6ee326..372c3816f 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -226,11 +226,10 @@ export type IsAny = 0 extends (1 & T) ? true : false; /** @internal */ export function getColumnNameAndConfig< - TName extends string, TConfig extends Record | undefined ->(a: TName | TConfig | undefined, b: TConfig | undefined) { +>(a: string | TConfig | undefined, b: TConfig | undefined) { return { - name: typeof a === 'string' && a.length > 0 ? a : '' as TName, + name: typeof a === 'string' && a.length > 0 ? a : '' as string, config: typeof a === 'object' ? a : b as TConfig, }; } From 05c33df7f5da5b5c9c35d121cc7d48ef92e0a08a Mon Sep 17 00:00:00 2001 From: Mario564 Date: Sun, 4 Aug 2024 15:44:31 -0700 Subject: [PATCH 038/492] Remove unnecessary `any` casts --- drizzle-orm/src/mysql-core/columns/bigint.ts | 4 ++-- drizzle-orm/src/pg-core/columns/bigint.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drizzle-orm/src/mysql-core/columns/bigint.ts b/drizzle-orm/src/mysql-core/columns/bigint.ts index 8c5e4f0b5..1a8ab68fe 100644 --- a/drizzle-orm/src/mysql-core/columns/bigint.ts +++ b/drizzle-orm/src/mysql-core/columns/bigint.ts @@ -114,7 +114,7 @@ export function bigint(a, b); if (config.mode === 'number') { - return new MySqlBigInt53Builder(name, config.unsigned) as any; + return new MySqlBigInt53Builder(name, config.unsigned); } - return new MySqlBigInt64Builder(name, config.unsigned) as any; + return new MySqlBigInt64Builder(name, config.unsigned); } diff --git a/drizzle-orm/src/pg-core/columns/bigint.ts b/drizzle-orm/src/pg-core/columns/bigint.ts index 20fbcce47..df6c93f5e 100644 --- a/drizzle-orm/src/pg-core/columns/bigint.ts +++ b/drizzle-orm/src/pg-core/columns/bigint.ts @@ -106,7 +106,7 @@ export function bigint(a, b); if (config.mode === 'number') { - return new PgBigInt53Builder(name) as any; + return new PgBigInt53Builder(name); } - return new PgBigInt64Builder(name) as any; + return new PgBigInt64Builder(name); } From de831e1a5de73d358c5344b67ee04a2074d383dc Mon Sep 17 00:00:00 2001 From: Mario564 Date: Sun, 4 Aug 2024 16:07:09 -0700 Subject: [PATCH 039/492] Fix lint error --- integration-tests/tests/sqlite/sqlite-common.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 0a89be68b..60f41e8d8 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2760,13 +2760,13 @@ export function tests() { ); await db.insert(users).values([ - { createdAt: new Date(new Date().getTime() - 2592000000), name: 'John' }, - { createdAt: new Date(new Date().getTime() - 86400000), name: 'Jane' } + { createdAt: new Date(Date.now() - 2592000000), name: 'John' }, + { createdAt: new Date(Date.now() - 86400000), name: 'Jane' } ]); const result = await db .select({ id: users.id, name: users.name }) .from(users) - .where(gt(users.createdAt, new Date(new Date().getTime() - 2592000000))); + .where(gt(users.createdAt, new Date(Date.now() - 2592000000))); expect(result).toEqual([ { id: 2, name: 'Jane' }, From e2b450fcd6d7b84f513102763f3ed3f14d6b4215 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Sun, 4 Aug 2024 16:20:44 -0700 Subject: [PATCH 040/492] Format --- drizzle-orm/src/column-builder.ts | 5 +++-- drizzle-orm/src/mysql-core/columns/bigint.ts | 2 +- drizzle-orm/src/mysql-core/columns/binary.ts | 2 +- drizzle-orm/src/mysql-core/columns/char.ts | 4 +++- drizzle-orm/src/mysql-core/columns/custom.ts | 5 +++-- drizzle-orm/src/mysql-core/columns/date.ts | 2 +- drizzle-orm/src/mysql-core/columns/datetime.ts | 2 +- drizzle-orm/src/mysql-core/columns/decimal.ts | 2 +- drizzle-orm/src/mysql-core/columns/double.ts | 2 +- drizzle-orm/src/mysql-core/columns/enum.ts | 2 +- drizzle-orm/src/mysql-core/columns/int.ts | 2 +- drizzle-orm/src/mysql-core/columns/mediumint.ts | 2 +- drizzle-orm/src/mysql-core/columns/real.ts | 2 +- drizzle-orm/src/mysql-core/columns/smallint.ts | 2 +- drizzle-orm/src/mysql-core/columns/text.ts | 4 +++- drizzle-orm/src/mysql-core/columns/time.ts | 2 +- drizzle-orm/src/mysql-core/columns/timestamp.ts | 2 +- drizzle-orm/src/mysql-core/columns/tinyint.ts | 2 +- drizzle-orm/src/mysql-core/columns/varbinary.ts | 2 +- drizzle-orm/src/mysql-core/columns/varchar.ts | 4 +++- drizzle-orm/src/pg-core/columns/bigint.ts | 2 +- drizzle-orm/src/pg-core/columns/bigserial.ts | 2 +- drizzle-orm/src/pg-core/columns/boolean.ts | 2 +- drizzle-orm/src/pg-core/columns/char.ts | 4 +++- drizzle-orm/src/pg-core/columns/custom.ts | 5 +++-- drizzle-orm/src/pg-core/columns/date.ts | 2 +- drizzle-orm/src/pg-core/columns/interval.ts | 2 +- drizzle-orm/src/pg-core/columns/macaddr.ts | 4 ++-- drizzle-orm/src/pg-core/columns/macaddr8.ts | 4 ++-- drizzle-orm/src/pg-core/columns/numeric.ts | 2 +- .../src/pg-core/columns/postgis_extension/geometry.ts | 2 +- drizzle-orm/src/pg-core/columns/postgis_extension/line.ts | 2 +- .../src/pg-core/columns/postgis_extension/point.ts | 2 +- drizzle-orm/src/pg-core/columns/serial.ts | 2 +- drizzle-orm/src/pg-core/columns/smallserial.ts | 2 +- drizzle-orm/src/pg-core/columns/text.ts | 4 +++- drizzle-orm/src/pg-core/columns/time.ts | 2 +- drizzle-orm/src/pg-core/columns/timestamp.ts | 2 +- drizzle-orm/src/pg-core/columns/varchar.ts | 4 +++- drizzle-orm/src/pg-core/columns/vector_extension/bit.ts | 2 +- .../src/pg-core/columns/vector_extension/halfvec.ts | 2 +- .../src/pg-core/columns/vector_extension/sparsevec.ts | 2 +- .../src/pg-core/columns/vector_extension/vector.ts | 2 +- drizzle-orm/src/sqlite-core/columns/blob.ts | 4 ++-- drizzle-orm/src/sqlite-core/columns/custom.ts | 5 +++-- drizzle-orm/src/sqlite-core/columns/integer.ts | 2 +- drizzle-orm/src/sqlite-core/columns/text.ts | 2 +- drizzle-orm/src/utils.ts | 2 +- drizzle-orm/type-tests/mysql/tables.ts | 4 ++-- drizzle-orm/type-tests/pg/tables.ts | 4 ++-- drizzle-orm/type-tests/sqlite/tables.ts | 8 ++++---- integration-tests/tests/mysql/mysql-common.ts | 6 +++--- integration-tests/tests/pg/pg-common.ts | 6 +++--- integration-tests/tests/sqlite/sqlite-common.ts | 6 +++--- 54 files changed, 88 insertions(+), 72 deletions(-) diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index f6426812b..b4ebf31c2 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -329,8 +329,9 @@ export type BuildColumns< > = & { [Key in keyof TConfigMap]: BuildColumn & - { name: TConfigMap[Key]['_']['name'] extends '' ? Assume : TConfigMap[Key]['_']['name'] } + _: + & Omit + & { name: TConfigMap[Key]['_']['name'] extends '' ? Assume : TConfigMap[Key]['_']['name'] }; }, TDialect>; } & {}; diff --git a/drizzle-orm/src/mysql-core/columns/bigint.ts b/drizzle-orm/src/mysql-core/columns/bigint.ts index 1a8ab68fe..5882b1025 100644 --- a/drizzle-orm/src/mysql-core/columns/bigint.ts +++ b/drizzle-orm/src/mysql-core/columns/bigint.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; export type MySqlBigInt53BuilderInitial = MySqlBigInt53Builder<{ name: TName; diff --git a/drizzle-orm/src/mysql-core/columns/binary.ts b/drizzle-orm/src/mysql-core/columns/binary.ts index e9bcf5859..7297d7b0a 100644 --- a/drizzle-orm/src/mysql-core/columns/binary.ts +++ b/drizzle-orm/src/mysql-core/columns/binary.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlBinaryBuilderInitial = MySqlBinaryBuilder<{ name: TName; diff --git a/drizzle-orm/src/mysql-core/columns/char.ts b/drizzle-orm/src/mysql-core/columns/char.ts index 5c4424946..019c035ba 100644 --- a/drizzle-orm/src/mysql-core/columns/char.ts +++ b/drizzle-orm/src/mysql-core/columns/char.ts @@ -51,7 +51,9 @@ export class MySqlChar> } } -export interface MySqlCharConfig { +export interface MySqlCharConfig< + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, +> { length?: number; enum?: TEnum; } diff --git a/drizzle-orm/src/mysql-core/columns/custom.ts b/drizzle-orm/src/mysql-core/columns/custom.ts index fcd89622a..35ca19d3d 100644 --- a/drizzle-orm/src/mysql-core/columns/custom.ts +++ b/drizzle-orm/src/mysql-core/columns/custom.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import type { SQL } from '~/sql/sql.ts'; -import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type ConvertCustomConfig> = @@ -211,7 +211,8 @@ export function customType( dbName: TName, fieldConfig: T['config'], ): MySqlCustomColumnBuilder>; - } : { + } + : { (): MySqlCustomColumnBuilder>; & T['config']>( fieldConfig?: TConfig, diff --git a/drizzle-orm/src/mysql-core/columns/date.ts b/drizzle-orm/src/mysql-core/columns/date.ts index d5d29c8f9..17ad8d8be 100644 --- a/drizzle-orm/src/mysql-core/columns/date.ts +++ b/drizzle-orm/src/mysql-core/columns/date.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlDateBuilderInitial = MySqlDateBuilder<{ diff --git a/drizzle-orm/src/mysql-core/columns/datetime.ts b/drizzle-orm/src/mysql-core/columns/datetime.ts index 5b6aa0104..39b0bae32 100644 --- a/drizzle-orm/src/mysql-core/columns/datetime.ts +++ b/drizzle-orm/src/mysql-core/columns/datetime.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlDateTimeBuilderInitial = MySqlDateTimeBuilder<{ diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index adc97650b..3b01923e4 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; export type MySqlDecimalBuilderInitial = MySqlDecimalBuilder<{ name: TName; diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index 6d33531e0..0324025b8 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; export type MySqlDoubleBuilderInitial = MySqlDoubleBuilder<{ name: TName; diff --git a/drizzle-orm/src/mysql-core/columns/enum.ts b/drizzle-orm/src/mysql-core/columns/enum.ts index e73bec04c..de1d41cdd 100644 --- a/drizzle-orm/src/mysql-core/columns/enum.ts +++ b/drizzle-orm/src/mysql-core/columns/enum.ts @@ -58,7 +58,7 @@ export function mysqlEnum>; export function mysqlEnum( a?: string | readonly [string, ...string[]] | [string, ...string[]], - b?: readonly [string, ...string[]] | [string, ...string[]] + b?: readonly [string, ...string[]] | [string, ...string[]], ): any { const { name, config: values } = getColumnNameAndConfig(a, b); diff --git a/drizzle-orm/src/mysql-core/columns/int.ts b/drizzle-orm/src/mysql-core/columns/int.ts index 15d0fa154..4902bc593 100644 --- a/drizzle-orm/src/mysql-core/columns/int.ts +++ b/drizzle-orm/src/mysql-core/columns/int.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; export type MySqlIntBuilderInitial = MySqlIntBuilder<{ name: TName; diff --git a/drizzle-orm/src/mysql-core/columns/mediumint.ts b/drizzle-orm/src/mysql-core/columns/mediumint.ts index 808304f64..237090179 100644 --- a/drizzle-orm/src/mysql-core/columns/mediumint.ts +++ b/drizzle-orm/src/mysql-core/columns/mediumint.ts @@ -2,9 +2,9 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; import type { MySqlIntConfig } from './int.ts'; -import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlMediumIntBuilderInitial = MySqlMediumIntBuilder<{ name: TName; diff --git a/drizzle-orm/src/mysql-core/columns/real.ts b/drizzle-orm/src/mysql-core/columns/real.ts index 7ab6309d8..2a921f1aa 100644 --- a/drizzle-orm/src/mysql-core/columns/real.ts +++ b/drizzle-orm/src/mysql-core/columns/real.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; export type MySqlRealBuilderInitial = MySqlRealBuilder<{ name: TName; diff --git a/drizzle-orm/src/mysql-core/columns/smallint.ts b/drizzle-orm/src/mysql-core/columns/smallint.ts index b7a6174e9..e6801e214 100644 --- a/drizzle-orm/src/mysql-core/columns/smallint.ts +++ b/drizzle-orm/src/mysql-core/columns/smallint.ts @@ -2,9 +2,9 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; import type { MySqlIntConfig } from './int.ts'; -import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlSmallIntBuilderInitial = MySqlSmallIntBuilder<{ name: TName; diff --git a/drizzle-orm/src/mysql-core/columns/text.ts b/drizzle-orm/src/mysql-core/columns/text.ts index 8a486d5a4..c90362dc5 100644 --- a/drizzle-orm/src/mysql-core/columns/text.ts +++ b/drizzle-orm/src/mysql-core/columns/text.ts @@ -51,7 +51,9 @@ export class MySqlText> } } -export interface MySqlTextConfig { +export interface MySqlTextConfig< + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, +> { enum?: TEnum; } diff --git a/drizzle-orm/src/mysql-core/columns/time.ts b/drizzle-orm/src/mysql-core/columns/time.ts index 66941f585..e862d9fa3 100644 --- a/drizzle-orm/src/mysql-core/columns/time.ts +++ b/drizzle-orm/src/mysql-core/columns/time.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlTimeBuilderInitial = MySqlTimeBuilder<{ name: TName; diff --git a/drizzle-orm/src/mysql-core/columns/timestamp.ts b/drizzle-orm/src/mysql-core/columns/timestamp.ts index 4c5ca3a17..07649ba94 100644 --- a/drizzle-orm/src/mysql-core/columns/timestamp.ts +++ b/drizzle-orm/src/mysql-core/columns/timestamp.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { MySqlDateBaseColumn, MySqlDateColumnBaseBuilder } from './date.common.ts'; export type MySqlTimestampBuilderInitial = MySqlTimestampBuilder<{ diff --git a/drizzle-orm/src/mysql-core/columns/tinyint.ts b/drizzle-orm/src/mysql-core/columns/tinyint.ts index df1999889..a9d7e967b 100644 --- a/drizzle-orm/src/mysql-core/columns/tinyint.ts +++ b/drizzle-orm/src/mysql-core/columns/tinyint.ts @@ -2,9 +2,9 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; import type { MySqlIntConfig } from './int.ts'; -import { getColumnNameAndConfig } from '~/utils.ts'; export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuilder<{ name: TName; diff --git a/drizzle-orm/src/mysql-core/columns/varbinary.ts b/drizzle-orm/src/mysql-core/columns/varbinary.ts index d90b02faa..ed6b90b7a 100644 --- a/drizzle-orm/src/mysql-core/columns/varbinary.ts +++ b/drizzle-orm/src/mysql-core/columns/varbinary.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlVarBinaryBuilderInitial = MySqlVarBinaryBuilder<{ name: TName; diff --git a/drizzle-orm/src/mysql-core/columns/varchar.ts b/drizzle-orm/src/mysql-core/columns/varchar.ts index fdb0a5fb0..b05cf7523 100644 --- a/drizzle-orm/src/mysql-core/columns/varchar.ts +++ b/drizzle-orm/src/mysql-core/columns/varchar.ts @@ -54,7 +54,9 @@ export class MySqlVarChar> } } -export interface MySqlVarCharConfig { +export interface MySqlVarCharConfig< + TEnum extends string[] | readonly string[] | undefined = string[] | readonly string[] | undefined, +> { length: number; enum?: TEnum; } diff --git a/drizzle-orm/src/pg-core/columns/bigint.ts b/drizzle-orm/src/pg-core/columns/bigint.ts index df6c93f5e..ef6be9eff 100644 --- a/drizzle-orm/src/pg-core/columns/bigint.ts +++ b/drizzle-orm/src/pg-core/columns/bigint.ts @@ -3,9 +3,9 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn } from './common.ts'; import { PgIntColumnBaseBuilder } from './int.common.ts'; -import { getColumnNameAndConfig } from '~/utils.ts'; export type PgBigInt53BuilderInitial = PgBigInt53Builder<{ name: TName; diff --git a/drizzle-orm/src/pg-core/columns/bigserial.ts b/drizzle-orm/src/pg-core/columns/bigserial.ts index d41fdbeb7..775234cb2 100644 --- a/drizzle-orm/src/pg-core/columns/bigserial.ts +++ b/drizzle-orm/src/pg-core/columns/bigserial.ts @@ -7,9 +7,9 @@ import type { } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; import type { AnyPgTable } from '../table.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; -import { getColumnNameAndConfig } from '~/utils.ts'; export type PgBigSerial53BuilderInitial = NotNull< HasDefault< diff --git a/drizzle-orm/src/pg-core/columns/boolean.ts b/drizzle-orm/src/pg-core/columns/boolean.ts index fc24197ce..19139243a 100644 --- a/drizzle-orm/src/pg-core/columns/boolean.ts +++ b/drizzle-orm/src/pg-core/columns/boolean.ts @@ -38,7 +38,7 @@ export class PgBoolean> exten } export function boolean(): PgBooleanBuilderInitial<''>; -export function boolean(name: TName): PgBooleanBuilderInitial +export function boolean(name: TName): PgBooleanBuilderInitial; export function boolean(name?: string) { return new PgBooleanBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/char.ts b/drizzle-orm/src/pg-core/columns/char.ts index b772c8718..a3b8853be 100644 --- a/drizzle-orm/src/pg-core/columns/char.ts +++ b/drizzle-orm/src/pg-core/columns/char.ts @@ -48,7 +48,9 @@ export class PgChar> } } -export interface PgCharConfig { +export interface PgCharConfig< + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, +> { length?: number; enum?: TEnum; } diff --git a/drizzle-orm/src/pg-core/columns/custom.ts b/drizzle-orm/src/pg-core/columns/custom.ts index 6d34985a9..44fdec1b2 100644 --- a/drizzle-orm/src/pg-core/columns/custom.ts +++ b/drizzle-orm/src/pg-core/columns/custom.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import type { SQL } from '~/sql/sql.ts'; -import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; export type ConvertCustomConfig> = @@ -211,7 +211,8 @@ export function customType( dbName: TName, fieldConfig: T['config'], ): PgCustomColumnBuilder>; - } : { + } + : { (): PgCustomColumnBuilder>; & T['config']>( fieldConfig?: TConfig, diff --git a/drizzle-orm/src/pg-core/columns/date.ts b/drizzle-orm/src/pg-core/columns/date.ts index a8c5fcc4a..812ec4e92 100644 --- a/drizzle-orm/src/pg-core/columns/date.ts +++ b/drizzle-orm/src/pg-core/columns/date.ts @@ -2,9 +2,9 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn } from './common.ts'; import { PgDateColumnBaseBuilder } from './date.common.ts'; -import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; export type PgDateBuilderInitial = PgDateBuilder<{ name: TName; diff --git a/drizzle-orm/src/pg-core/columns/interval.ts b/drizzle-orm/src/pg-core/columns/interval.ts index 1e7a96a7a..3ae6557a3 100644 --- a/drizzle-orm/src/pg-core/columns/interval.ts +++ b/drizzle-orm/src/pg-core/columns/interval.ts @@ -2,9 +2,9 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; import type { Precision } from './timestamp.ts'; -import { getColumnNameAndConfig } from '~/utils.ts'; export type PgIntervalBuilderInitial = PgIntervalBuilder<{ name: TName; diff --git a/drizzle-orm/src/pg-core/columns/macaddr.ts b/drizzle-orm/src/pg-core/columns/macaddr.ts index 876c2d841..b43d4ab40 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr.ts @@ -37,8 +37,8 @@ export class PgMacaddr> extend } } -export function macaddr(): PgMacaddrBuilderInitial<''> -export function macaddr(name: TName): PgMacaddrBuilderInitial +export function macaddr(): PgMacaddrBuilderInitial<''>; +export function macaddr(name: TName): PgMacaddrBuilderInitial; export function macaddr(name?: string) { return new PgMacaddrBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/macaddr8.ts b/drizzle-orm/src/pg-core/columns/macaddr8.ts index 5ba1324b7..00af8c031 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr8.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr8.ts @@ -37,8 +37,8 @@ export class PgMacaddr8> exte } } -export function macaddr8(): PgMacaddr8BuilderInitial<''> -export function macaddr8(name: TName): PgMacaddr8BuilderInitial +export function macaddr8(): PgMacaddr8BuilderInitial<''>; +export function macaddr8(name: TName): PgMacaddr8BuilderInitial; export function macaddr8(name?: string) { return new PgMacaddr8Builder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/numeric.ts b/drizzle-orm/src/pg-core/columns/numeric.ts index fafe10481..a661df21e 100644 --- a/drizzle-orm/src/pg-core/columns/numeric.ts +++ b/drizzle-orm/src/pg-core/columns/numeric.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { PgColumn, PgColumnBuilder } from './common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { PgColumn, PgColumnBuilder } from './common.ts'; export type PgNumericBuilderInitial = PgNumericBuilder<{ name: TName; diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts index 25b355022..18e6c946d 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; import { parseEWKB } from './utils.ts'; diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts index a47b6aaa7..f43ab09fe 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; export type PgLineBuilderInitial = PgLineBuilder<{ diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts index 5e3ee2409..52d531a56 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; export type PgPointTupleBuilderInitial = PgPointTupleBuilder<{ diff --git a/drizzle-orm/src/pg-core/columns/serial.ts b/drizzle-orm/src/pg-core/columns/serial.ts index 195c000d3..a4d7f8e30 100644 --- a/drizzle-orm/src/pg-core/columns/serial.ts +++ b/drizzle-orm/src/pg-core/columns/serial.ts @@ -50,7 +50,7 @@ export class PgSerial> extends } export function serial(): PgSerialBuilderInitial<''>; -export function serial(name: TName): PgSerialBuilderInitial +export function serial(name: TName): PgSerialBuilderInitial; export function serial(name?: string) { return new PgSerialBuilder(name ?? ''); } diff --git a/drizzle-orm/src/pg-core/columns/smallserial.ts b/drizzle-orm/src/pg-core/columns/smallserial.ts index 8f4e56d5c..ec2204034 100644 --- a/drizzle-orm/src/pg-core/columns/smallserial.ts +++ b/drizzle-orm/src/pg-core/columns/smallserial.ts @@ -54,7 +54,7 @@ export class PgSmallSerial } } -export function smallserial(): PgSmallSerialBuilderInitial<''> +export function smallserial(): PgSmallSerialBuilderInitial<''>; export function smallserial(name: TName): PgSmallSerialBuilderInitial; export function smallserial(name?: string) { return new PgSmallSerialBuilder(name ?? ''); diff --git a/drizzle-orm/src/pg-core/columns/text.ts b/drizzle-orm/src/pg-core/columns/text.ts index c5a393005..522135e5c 100644 --- a/drizzle-orm/src/pg-core/columns/text.ts +++ b/drizzle-orm/src/pg-core/columns/text.ts @@ -48,7 +48,9 @@ export class PgText> } } -export interface PgTextConfig { +export interface PgTextConfig< + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, +> { enum?: TEnum; } diff --git a/drizzle-orm/src/pg-core/columns/time.ts b/drizzle-orm/src/pg-core/columns/time.ts index d67616491..e2b29f1f7 100644 --- a/drizzle-orm/src/pg-core/columns/time.ts +++ b/drizzle-orm/src/pg-core/columns/time.ts @@ -2,10 +2,10 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn } from './common.ts'; import { PgDateColumnBaseBuilder } from './date.common.ts'; import type { Precision } from './timestamp.ts'; -import { getColumnNameAndConfig } from '~/utils.ts'; export type PgTimeBuilderInitial = PgTimeBuilder<{ name: TName; diff --git a/drizzle-orm/src/pg-core/columns/timestamp.ts b/drizzle-orm/src/pg-core/columns/timestamp.ts index d89697213..08474bf68 100644 --- a/drizzle-orm/src/pg-core/columns/timestamp.ts +++ b/drizzle-orm/src/pg-core/columns/timestamp.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn } from './common.ts'; import { PgDateColumnBaseBuilder } from './date.common.ts'; diff --git a/drizzle-orm/src/pg-core/columns/varchar.ts b/drizzle-orm/src/pg-core/columns/varchar.ts index 454b2834c..bc9d1b160 100644 --- a/drizzle-orm/src/pg-core/columns/varchar.ts +++ b/drizzle-orm/src/pg-core/columns/varchar.ts @@ -48,7 +48,9 @@ export class PgVarchar> } } -export interface PgVarcharConfig { +export interface PgVarcharConfig< + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, +> { length?: number; enum?: TEnum; } diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts index 28d26447c..a841c28e5 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { PgColumn, PgColumnBuilder } from '../common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { PgColumn, PgColumnBuilder } from '../common.ts'; export type PgBinaryVectorBuilderInitial = PgBinaryVectorBuilder<{ name: TName; diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts index a8a3f240f..7218f8114 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { PgColumn, PgColumnBuilder } from '../common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { PgColumn, PgColumnBuilder } from '../common.ts'; export type PgHalfVectorBuilderInitial = PgHalfVectorBuilder<{ name: TName; diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts index e06efd7a7..2bdbf1ac3 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { PgColumn, PgColumnBuilder } from '../common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { PgColumn, PgColumnBuilder } from '../common.ts'; export type PgSparseVectorBuilderInitial = PgSparseVectorBuilder<{ name: TName; diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts index 2e8724bdf..b6ad9caff 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { PgColumn, PgColumnBuilder } from '../common.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; +import { PgColumn, PgColumnBuilder } from '../common.ts'; export type PgVectorBuilderInitial = PgVectorBuilder<{ name: TName; diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index b680fd166..96e8d7f69 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySQLiteTable } from '~/sqlite-core/table.ts'; -import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; type BlobMode = 'buffer' | 'json' | 'bigint'; @@ -153,7 +153,7 @@ export function blob( ): Equal extends true ? SQLiteBigIntBuilderInitial : Equal extends true ? SQLiteBlobBufferBuilderInitial : SQLiteBlobJsonBuilderInitial; -export function blob(a?: string | BlobConfig,b?: BlobConfig) { +export function blob(a?: string | BlobConfig, b?: BlobConfig) { const { name, config } = getColumnNameAndConfig(a, b); if (config?.mode === 'json') { return new SQLiteBlobJsonBuilder(name); diff --git a/drizzle-orm/src/sqlite-core/columns/custom.ts b/drizzle-orm/src/sqlite-core/columns/custom.ts index c190ab2b1..293dd09ad 100644 --- a/drizzle-orm/src/sqlite-core/columns/custom.ts +++ b/drizzle-orm/src/sqlite-core/columns/custom.ts @@ -3,7 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { SQL } from '~/sql/sql.ts'; import type { AnySQLiteTable } from '~/sqlite-core/table.ts'; -import { getColumnNameAndConfig, type Equal } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; export type ConvertCustomConfig> = @@ -211,7 +211,8 @@ export function customType( dbName: TName, fieldConfig: T['config'], ): SQLiteCustomColumnBuilder>; - } : { + } + : { (): SQLiteCustomColumnBuilder>; & T['config']>( fieldConfig?: TConfig, diff --git a/drizzle-orm/src/sqlite-core/columns/integer.ts b/drizzle-orm/src/sqlite-core/columns/integer.ts index bec642ff6..449c6357d 100644 --- a/drizzle-orm/src/sqlite-core/columns/integer.ts +++ b/drizzle-orm/src/sqlite-core/columns/integer.ts @@ -11,7 +11,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import { sql } from '~/sql/sql.ts'; import type { OnConflict } from '~/sqlite-core/utils.ts'; -import { getColumnNameAndConfig, type Equal, type Or } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig, type Or } from '~/utils.ts'; import type { AnySQLiteTable } from '../table.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/sqlite-core/columns/text.ts b/drizzle-orm/src/sqlite-core/columns/text.ts index d00ce2da4..033c2cb99 100644 --- a/drizzle-orm/src/sqlite-core/columns/text.ts +++ b/drizzle-orm/src/sqlite-core/columns/text.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySQLiteTable } from '~/sqlite-core/table.ts'; -import { getColumnNameAndConfig, type Equal, type Writable } from '~/utils.ts'; +import { type Equal, getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; export type SQLiteTextBuilderInitial = SQLiteTextBuilder<{ diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index 372c3816f..cec81e78a 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -226,7 +226,7 @@ export type IsAny = 0 extends (1 & T) ? true : false; /** @internal */ export function getColumnNameAndConfig< - TConfig extends Record | undefined + TConfig extends Record | undefined, >(a: string | TConfig | undefined, b: TConfig | undefined) { return { name: typeof a === 'string' && a.length > 0 ? a : '' as string, diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index 4522cb752..ffd50da29 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -813,7 +813,7 @@ Expect< Expect>; return config ? `varchar(${config.length})` : `text`; }, - + toDriver(value) { Expect>(); return value; @@ -921,7 +921,7 @@ Expect< { const keysAsColumnNames = mysqlTable('test', { id: int(), - name: text() + name: text(), }); Expect>; diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index 06a7d9598..f25f473c5 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -1269,7 +1269,7 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); { const keysAsColumnNames = pgTable('test', { id: serial(), - name: text() + name: text(), }); Expect>; @@ -1349,4 +1349,4 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); vector: vector({ dimensions: 1 }), vectordef: vector({ dimensions: 1 }).default([1]), }); -} \ No newline at end of file +} diff --git a/drizzle-orm/type-tests/sqlite/tables.ts b/drizzle-orm/type-tests/sqlite/tables.ts index 595d115cc..5d2287320 100644 --- a/drizzle-orm/type-tests/sqlite/tables.ts +++ b/drizzle-orm/type-tests/sqlite/tables.ts @@ -506,7 +506,7 @@ Expect< Expect>; return config ? `varchar(${config.length})` : `text`; }, - + toDriver(value) { Expect>(); return value; @@ -541,14 +541,14 @@ Expect< text3: text('text3', { length: 1 }), text4: text('text4', { length: 1, enum: ['a', 'b', 'c'] }), text5: text('text5', { mode: 'json' }), - textdef: text('textdef').default('') + textdef: text('textdef').default(''), }); } { const keysAsColumnNames = sqliteTable('test', { id: integer(), - name: text() + name: text(), }); Expect>; @@ -572,6 +572,6 @@ Expect< text3: text({ length: 1 }), text4: text({ length: 1, enum: ['a', 'b', 'c'] }), text5: text({ mode: 'json' }), - textdef: text().default('') + textdef: text().default(''), }); } diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 5cc22ed4d..d434993e6 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3552,7 +3552,7 @@ export function tests(driver?: string) { id: bigint({ mode: 'number' }).autoincrement().primaryKey(), createdAt: timestamp(), updatedAt: timestamp({ fsp: 3 }), - admin: boolean() + admin: boolean(), }); await db.execute(sql`drop table if exists users`); @@ -3564,7 +3564,7 @@ export function tests(driver?: string) { \`updatedAt\` timestamp(3), \`admin\` boolean ) - ` + `, ); await db.insert(users).values([ @@ -3579,7 +3579,7 @@ export function tests(driver?: string) { and( gt(users.createdAt, sql`now() - interval 7 day`), gt(users.updatedAt, sql`now() - interval 7 day`), - ) + ), ); expect(result).toEqual([ diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 314c3b173..b5d7ac0fe 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -34,6 +34,7 @@ import type { NeonHttpDatabase } from 'drizzle-orm/neon-http'; import type { PgColumn, PgDatabase, PgQueryResultHKT } from 'drizzle-orm/pg-core'; import { alias, + bigserial, boolean, char, cidr, @@ -70,7 +71,6 @@ import { uniqueKeyName, uuid as pgUuid, varchar, - bigserial, } from 'drizzle-orm/pg-core'; import getPort from 'get-port'; import { v4 as uuidV4 } from 'uuid'; @@ -4495,7 +4495,7 @@ export function tests() { id: bigserial({ mode: 'number' }).primaryKey(), firstName: varchar(), lastName: varchar({ length: 50 }), - admin: boolean() + admin: boolean(), }); await db.execute(sql`drop table if exists users`); @@ -4507,7 +4507,7 @@ export function tests() { "lastName" varchar(50), "admin" boolean ) - ` + `, ); await db.insert(users).values([ diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 60f41e8d8..68360ef5e 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2745,7 +2745,7 @@ export function tests() { const users = sqliteTable('users', { id: integer().primaryKey({ autoIncrement: true }), createdAt: integer({ mode: 'timestamp' }), - name: text() + name: text(), }); await db.run(sql`drop table if exists users`); @@ -2756,12 +2756,12 @@ export function tests() { \`createdAt\` integer, \`name\` text ) - ` + `, ); await db.insert(users).values([ { createdAt: new Date(Date.now() - 2592000000), name: 'John' }, - { createdAt: new Date(Date.now() - 86400000), name: 'Jane' } + { createdAt: new Date(Date.now() - 86400000), name: 'Jane' }, ]); const result = await db .select({ id: users.id, name: users.name }) From 91e8e325a2dc755385d477e74a333404880a2c88 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 5 Aug 2024 16:18:28 +0300 Subject: [PATCH 041/492] Add findOne test for aws --- integration-tests/tests/pg/awsdatapi.test.ts | 50 ++++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/integration-tests/tests/pg/awsdatapi.test.ts b/integration-tests/tests/pg/awsdatapi.test.ts index 87f20386c..a23fabcf1 100644 --- a/integration-tests/tests/pg/awsdatapi.test.ts +++ b/integration-tests/tests/pg/awsdatapi.test.ts @@ -871,11 +871,10 @@ test('migrator : migrate with custom table and custom schema', async () => { // test if the custom migrations table was created const { rows } = await db.execute( - sql`select * from ${sql.identifier(customSchema)}.${ - sql.identifier( - customTable, - ) - };`, + sql`select * from ${sql.identifier(customSchema)}.${sql.identifier( + customTable, + ) + };`, ); expect(rows).toBeTruthy(); expect(rows!.length).toBeGreaterThan(0); @@ -888,21 +887,19 @@ test('migrator : migrate with custom table and custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); await db.execute( - sql`drop table ${sql.identifier(customSchema)}.${ - sql.identifier( - customTable, - ) - }`, + sql`drop table ${sql.identifier(customSchema)}.${sql.identifier( + customTable, + ) + }`, ); }); test('insert via db.execute + select via db.execute', async () => { await db.execute( - sql`insert into ${usersTable} (${ - sql.identifier( - usersTable.name.name, - ) - }) values (${'John'})`, + sql`insert into ${usersTable} (${sql.identifier( + usersTable.name.name, + ) + }) values (${'John'})`, ); const result = await db.execute<{ id: number; name: string }>( @@ -914,11 +911,10 @@ test('insert via db.execute + select via db.execute', async () => { test('insert via db.execute + returning', async () => { const inserted = await db.execute( - sql`insert into ${usersTable} (${ - sql.identifier( - usersTable.name.name, - ) - }) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, + sql`insert into ${usersTable} (${sql.identifier( + usersTable.name.name, + ) + }) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, ); expect(inserted.rows).toEqual([{ id: 1, name: 'John' }]); }); @@ -1597,7 +1593,19 @@ test('Typehints mix for RQB', async () => { }, }); - console.log(res); + expect(res).toStrictEqual([]) +}); + +test('Typehints mix for findFirst', async () => { + const uuid = 'd997d46d-5769-4c78-9a35-93acadbe6076'; + + await db.insert(user).values({ id: uuid, email: 'd' }) + + const res = await db.query.user.findFirst({ + where: eq(user.id, uuid) + }); + + expect(res).toStrictEqual({ id: 'd997d46d-5769-4c78-9a35-93acadbe6076', email: 'd' }) }); afterAll(async () => { From befec2316bf5bf9da4085f989613961cb48610c8 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 5 Aug 2024 16:30:43 +0300 Subject: [PATCH 042/492] Format with dprint --- integration-tests/tests/pg/awsdatapi.test.ts | 44 +++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/integration-tests/tests/pg/awsdatapi.test.ts b/integration-tests/tests/pg/awsdatapi.test.ts index a23fabcf1..8ee39cf12 100644 --- a/integration-tests/tests/pg/awsdatapi.test.ts +++ b/integration-tests/tests/pg/awsdatapi.test.ts @@ -871,10 +871,11 @@ test('migrator : migrate with custom table and custom schema', async () => { // test if the custom migrations table was created const { rows } = await db.execute( - sql`select * from ${sql.identifier(customSchema)}.${sql.identifier( - customTable, - ) - };`, + sql`select * from ${sql.identifier(customSchema)}.${ + sql.identifier( + customTable, + ) + };`, ); expect(rows).toBeTruthy(); expect(rows!.length).toBeGreaterThan(0); @@ -887,19 +888,21 @@ test('migrator : migrate with custom table and custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); await db.execute( - sql`drop table ${sql.identifier(customSchema)}.${sql.identifier( - customTable, - ) - }`, + sql`drop table ${sql.identifier(customSchema)}.${ + sql.identifier( + customTable, + ) + }`, ); }); test('insert via db.execute + select via db.execute', async () => { await db.execute( - sql`insert into ${usersTable} (${sql.identifier( - usersTable.name.name, - ) - }) values (${'John'})`, + sql`insert into ${usersTable} (${ + sql.identifier( + usersTable.name.name, + ) + }) values (${'John'})`, ); const result = await db.execute<{ id: number; name: string }>( @@ -911,10 +914,11 @@ test('insert via db.execute + select via db.execute', async () => { test('insert via db.execute + returning', async () => { const inserted = await db.execute( - sql`insert into ${usersTable} (${sql.identifier( - usersTable.name.name, - ) - }) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, + sql`insert into ${usersTable} (${ + sql.identifier( + usersTable.name.name, + ) + }) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, ); expect(inserted.rows).toEqual([{ id: 1, name: 'John' }]); }); @@ -1593,19 +1597,19 @@ test('Typehints mix for RQB', async () => { }, }); - expect(res).toStrictEqual([]) + expect(res).toStrictEqual([]); }); test('Typehints mix for findFirst', async () => { const uuid = 'd997d46d-5769-4c78-9a35-93acadbe6076'; - await db.insert(user).values({ id: uuid, email: 'd' }) + await db.insert(user).values({ id: uuid, email: 'd' }); const res = await db.query.user.findFirst({ - where: eq(user.id, uuid) + where: eq(user.id, uuid), }); - expect(res).toStrictEqual({ id: 'd997d46d-5769-4c78-9a35-93acadbe6076', email: 'd' }) + expect(res).toStrictEqual({ id: 'd997d46d-5769-4c78-9a35-93acadbe6076', email: 'd' }); }); afterAll(async () => { From 7d2ae842da5e57ea161aa708ea567fb4afc4911c Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 5 Aug 2024 18:08:58 +0300 Subject: [PATCH 043/492] Added 0.32.2 release notes --- changelogs/drizzle-orm/0.32.2.md | 4 ++++ drizzle-orm/package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changelogs/drizzle-orm/0.32.2.md diff --git a/changelogs/drizzle-orm/0.32.2.md b/changelogs/drizzle-orm/0.32.2.md new file mode 100644 index 000000000..9ce68473c --- /dev/null +++ b/changelogs/drizzle-orm/0.32.2.md @@ -0,0 +1,4 @@ +- Fix AWS Data API type hints bugs in RQB +- Fix set transactions in MySQL bug - thanks @roguesherlock +- Add forwaring dependencies within useLiveQuery, fixes [#2651](https://github.com/drizzle-team/drizzle-orm/issues/2651) - thanks @anstapol +- Export additional types from SQLite package, like `AnySQLiteUpdate` - thanks @veloii \ No newline at end of file diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 74c3726f7..9b0db78bc 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.32.1", + "version": "0.32.2", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { From ce1643f56c9f09b55f12aef91f0983d9c79ce545 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 5 Aug 2024 23:27:13 -0700 Subject: [PATCH 044/492] Improve default value generation for array columns in PG --- drizzle-kit/src/serializer/pgSerializer.ts | 44 ++++ drizzle-kit/tests/pg-array.test.ts | 255 +++++++++++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 drizzle-kit/tests/pg-array.test.ts diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 4ab37a0ae..4c4831e8f 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -75,6 +75,43 @@ function stringFromDatabaseIdentityProperty(field: any): string | undefined { : String(field); } +function buildArrayString(array: any[], sqlType: string): string { + sqlType = sqlType.split('[')[0]; + const values = array + .map((value) => { + if (typeof value === 'number' || typeof value === 'bigint') { + return value.toString(); + } else if (typeof value === 'boolean') { + return value ? 'true' : 'false'; + } else if (Array.isArray(value)) { + return buildArrayString(value, sqlType); + } else if (value instanceof Date) { + if (sqlType === 'date') { + return `"${value.toISOString().split('T')[0]}"`; + } else if (sqlType === 'timestamp') { + return `"${ + value.toISOString() + .replace('T', ' ') + .slice(0, 23) + }"`; + } else { + return `"${value.toISOString()}"`; + } + } else if (typeof value === 'object') { + return `"${ + JSON + .stringify(value) + .replaceAll('"', '\\"') + }"`; + } + + return `"${value}"`; + }) + .join(','); + + return `{${values}}`; +} + export const generatePgSnapshot = ( tables: AnyPgTable[], enums: PgEnum[], @@ -226,6 +263,13 @@ export const generatePgSnapshot = ( } else { columnToSet.default = `'${column.default.toISOString()}'`; } + } else if (sqlTypeLowered.match(/.*\[\d*\].*|.*\[\].*/g) !== null && Array.isArray(column.default)) { + columnToSet.default = `'${ + buildArrayString( + column.default, + sqlTypeLowered, + ) + }'::${sqlTypeLowered}`; } else { // Should do for all types // columnToSet.default = `'${column.default}'::${sqlTypeLowered}`; diff --git a/drizzle-kit/tests/pg-array.test.ts b/drizzle-kit/tests/pg-array.test.ts new file mode 100644 index 000000000..273d7cfcc --- /dev/null +++ b/drizzle-kit/tests/pg-array.test.ts @@ -0,0 +1,255 @@ +import { bigint, boolean, date, integer, json, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemas } from './schemaDiffer'; + +test('array #1: empty array default', async (t) => { + const from = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().default([]), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'::integer[]" }, + }); +}); + +test('array #2: integer array default', async (t) => { + const from = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().default([1, 2, 3]), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'::integer[]" }, + }); +}); + +test('array #3: bigint array default', async (t) => { + const from = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: bigint('values', { mode: 'bigint' }).array().default([BigInt(1), BigInt(2), BigInt(3)]), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { name: 'values', type: 'bigint[]', primaryKey: false, notNull: false, default: "'{1,2,3}'::bigint[]" }, + }); +}); + +test('array #4: boolean array default', async (t) => { + const from = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: boolean('values').array().default([true, false, true]), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { + name: 'values', + type: 'boolean[]', + primaryKey: false, + notNull: false, + default: "'{true,false,true}'::boolean[]", + }, + }); +}); + +test('array #5: multi-dimensional array default', async (t) => { + const from = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().array().default([[1, 2], [3, 4]]), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { + name: 'values', + type: 'integer[][]', + primaryKey: false, + notNull: false, + default: "'{{1,2},{3,4}}'::integer[][]", + }, + }); +}); + +test('array #6: date array default', async (t) => { + const from = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: date('values').array().default(['2024-08-06', '2024-08-07']), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { + name: 'values', + type: 'date[]', + primaryKey: false, + notNull: false, + default: '\'{"2024-08-06","2024-08-07"}\'::date[]', + }, + }); +}); + +test('array #7: timestamp array default', async (t) => { + const from = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: timestamp('values').array().default([new Date('2024-08-06'), new Date('2024-08-07')]), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { + name: 'values', + type: 'timestamp[]', + primaryKey: false, + notNull: false, + default: '\'{"2024-08-06 00:00:00.000","2024-08-07 00:00:00.000"}\'::timestamp[]', + }, + }); +}); + +test('array #8: json array default', async (t) => { + const from = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: json('values').array().default([{ a: 1 }, { b: 2 }]), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { + name: 'values', + type: 'json[]', + primaryKey: false, + notNull: false, + default: '\'{"{\\"a\\":1}","{\\"b\\":2}"}\'::json[]', + }, + }); +}); + +test('array #9: text array default', async (t) => { + const from = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: text('values').array().default(['abc', 'def']), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { + name: 'values', + type: 'text[]', + primaryKey: false, + notNull: false, + default: '\'{"abc","def"}\'::text[]', + }, + }); +}); From b290f42b4f00d469b5825f3c33fa194ed77c87e6 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 6 Aug 2024 14:27:46 +0300 Subject: [PATCH 045/492] Add tests to pg-common --- integration-tests/tests/pg/pg-common.ts | 169 +++++++++++++++++++++++- 1 file changed, 162 insertions(+), 7 deletions(-) diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index fb69c5877..df1582bea 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -70,6 +70,7 @@ import { uniqueKeyName, uuid as pgUuid, varchar, + json, } from 'drizzle-orm/pg-core'; import getPort from 'get-port'; import { v4 as uuidV4 } from 'uuid'; @@ -199,6 +200,12 @@ const users2MySchemaTable = mySchema.table('users2', { cityId: integer('city_id').references(() => citiesTable.id), }); +const jsonTestTable = pgTable('jsontest', { + id: serial('id').primaryKey(), + json: json('json').$type<{ string: string; number: number }>(), + jsonb: jsonb('jsonb').$type<{ string: string; number: number }>(), +}); + let pgContainer: Docker.Container; export async function createDockerDB(): Promise<{ connectionString: string; container: Docker.Container }> { @@ -358,6 +365,16 @@ export function tests() { ) `, ); + + await db.execute( + sql` + create table jsontest ( + id serial primary key, + json json, + jsonb jsonb + ) + `, + ); }); async function setupSetOperationTest(db: PgDatabase) { @@ -2347,9 +2364,8 @@ export function tests() { await db.execute(sql`drop type if exists ${sql.identifier(categoryEnum.enumName)}`); await db.execute( - sql`create type ${ - sql.identifier(muscleEnum.enumName) - } as enum ('abdominals', 'hamstrings', 'adductors', 'quadriceps', 'biceps', 'shoulders', 'chest', 'middle_back', 'calves', 'glutes', 'lower_back', 'lats', 'triceps', 'traps', 'forearms', 'neck', 'abductors')`, + sql`create type ${sql.identifier(muscleEnum.enumName) + } as enum ('abdominals', 'hamstrings', 'adductors', 'quadriceps', 'biceps', 'shoulders', 'chest', 'middle_back', 'calves', 'glutes', 'lower_back', 'lats', 'triceps', 'traps', 'forearms', 'neck', 'abductors')`, ); await db.execute( sql`create type ${sql.identifier(forceEnum.enumName)} as enum ('isometric', 'isotonic', 'isokinetic')`, @@ -2359,9 +2375,8 @@ export function tests() { ); await db.execute(sql`create type ${sql.identifier(mechanicEnum.enumName)} as enum ('compound', 'isolation')`); await db.execute( - sql`create type ${ - sql.identifier(equipmentEnum.enumName) - } as enum ('barbell', 'dumbbell', 'bodyweight', 'machine', 'cable', 'kettlebell')`, + sql`create type ${sql.identifier(equipmentEnum.enumName) + } as enum ('barbell', 'dumbbell', 'bodyweight', 'machine', 'cable', 'kettlebell')`, ); await db.execute( sql`create type ${sql.identifier(categoryEnum.enumName)} as enum ('upper_body', 'lower_body', 'full_body')`, @@ -4481,5 +4496,145 @@ export function tests() { expect(users.length).toBeGreaterThan(0); }); + + test('proper json and jsonb handling', async (ctx) => { + const { db } = ctx.pg; + + const jsonTable = pgTable('json_table', { + json: json('json').$type<{ name: string; age: number }>(), + jsonb: jsonb('jsonb').$type<{ name: string; age: number }>(), + }); + + await db.execute(sql`drop table if exists ${jsonTable}`); + + db.execute(sql`create table ${jsonTable} (json json, jsonb jsonb)`); + + await db.insert(jsonTable).values({ json: { name: 'Tom', age: 75 }, jsonb: { name: 'Pete', age: 23 } }); + + const result = await db.select().from(jsonTable); + + const justNames = await db.select({ + name1: sql`${jsonTable.json}->>'name'`.as('name1'), + name2: sql`${jsonTable.jsonb}->>'name'`.as('name2'), + }).from(jsonTable); + + expect(result).toStrictEqual([ + { + json: { name: 'Tom', age: 75 }, + jsonb: { name: 'Pete', age: 23 }, + }, + ]); + + expect(justNames).toStrictEqual([ + { + name1: 'Tom', + name2: 'Pete', + }, + ]); + }); + + test('set json/jsonb fields with objects and retrieve with the ->> operator', async (ctx) => { + const { db } = ctx.pg; + + const obj = { string: 'test', number: 123 }; + const { string: testString, number: testNumber } = obj; + + await db.insert(jsonTestTable).values({ + json: obj, + jsonb: obj, + }); + + const result = await db.select({ + jsonStringField: sql`${jsonTestTable.json}->>'string'`, + jsonNumberField: sql`${jsonTestTable.json}->>'number'`, + jsonbStringField: sql`${jsonTestTable.jsonb}->>'string'`, + jsonbNumberField: sql`${jsonTestTable.jsonb}->>'number'`, + }).from(jsonTestTable); + + expect(result).toStrictEqual([{ + jsonStringField: testString, + jsonNumberField: String(testNumber), + jsonbStringField: testString, + jsonbNumberField: String(testNumber), + }]) + }); + + test('set json/jsonb fields with strings and retrieve with the ->> operator', async (ctx) => { + const { db } = ctx.pg; + + const obj = { string: 'test', number: 123 }; + const { string: testString, number: testNumber } = obj; + + await db.insert(jsonTestTable).values({ + json: sql`${JSON.stringify(obj)}`, + jsonb: sql`${JSON.stringify(obj)}`, + }); + + const result = await db.select({ + jsonStringField: sql`${jsonTestTable.json}->>'string'`, + jsonNumberField: sql`${jsonTestTable.json}->>'number'`, + jsonbStringField: sql`${jsonTestTable.jsonb}->>'string'`, + jsonbNumberField: sql`${jsonTestTable.jsonb}->>'number'`, + }).from(jsonTestTable); + + expect(result).toStrictEqual([{ + jsonStringField: testString, + jsonNumberField: String(testNumber), + jsonbStringField: testString, + jsonbNumberField: String(testNumber), + }]) + }); + + test('set json/jsonb fields with objects and retrieve with the -> operator', async (ctx) => { + const { db } = ctx.pg; + + const obj = { string: 'test', number: 123 }; + const { string: testString, number: testNumber } = obj; + + await db.insert(jsonTestTable).values({ + json: obj, + jsonb: obj, + }); + + const result = await db.select({ + jsonStringField: sql`${jsonTestTable.json}->'string'`, + jsonNumberField: sql`${jsonTestTable.json}->'number'`, + jsonbStringField: sql`${jsonTestTable.jsonb}->'string'`, + jsonbNumberField: sql`${jsonTestTable.jsonb}->'number'`, + }).from(jsonTestTable); + + expect(result).toStrictEqual([{ + jsonStringField: testString, + jsonNumberField: testNumber, + jsonbStringField: testString, + jsonbNumberField: testNumber, + }]) + }); + + test('set json/jsonb fields with strings and retrieve with the -> operator', async (ctx) => { + const { db } = ctx.pg; + + const obj = { string: 'test', number: 123 }; + const { string: testString, number: testNumber } = obj; + + await db.insert(jsonTestTable).values({ + json: sql`${JSON.stringify(obj)}`, + jsonb: sql`${JSON.stringify(obj)}`, + }); + + const result = await db.select({ + jsonStringField: sql`${jsonTestTable.json}->'string'`, + jsonNumberField: sql`${jsonTestTable.json}->'number'`, + jsonbStringField: sql`${jsonTestTable.jsonb}->'string'`, + jsonbNumberField: sql`${jsonTestTable.jsonb}->'number'`, + }).from(jsonTestTable); + + expect(result).toStrictEqual([{ + jsonStringField: testString, + jsonNumberField: testNumber, + jsonbStringField: testString, + jsonbNumberField: testNumber, + }]) + }); }); -} +} \ No newline at end of file From 0accd97a853294f7ed9916673aee974f06419e2e Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 6 Aug 2024 14:51:08 +0300 Subject: [PATCH 046/492] Use dprint --- integration-tests/tests/pg/pg-common.ts | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index df1582bea..0b2b48769 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -49,6 +49,7 @@ import { intersect, intersectAll, interval, + json, jsonb, macaddr, macaddr8, @@ -70,7 +71,6 @@ import { uniqueKeyName, uuid as pgUuid, varchar, - json, } from 'drizzle-orm/pg-core'; import getPort from 'get-port'; import { v4 as uuidV4 } from 'uuid'; @@ -2364,8 +2364,9 @@ export function tests() { await db.execute(sql`drop type if exists ${sql.identifier(categoryEnum.enumName)}`); await db.execute( - sql`create type ${sql.identifier(muscleEnum.enumName) - } as enum ('abdominals', 'hamstrings', 'adductors', 'quadriceps', 'biceps', 'shoulders', 'chest', 'middle_back', 'calves', 'glutes', 'lower_back', 'lats', 'triceps', 'traps', 'forearms', 'neck', 'abductors')`, + sql`create type ${ + sql.identifier(muscleEnum.enumName) + } as enum ('abdominals', 'hamstrings', 'adductors', 'quadriceps', 'biceps', 'shoulders', 'chest', 'middle_back', 'calves', 'glutes', 'lower_back', 'lats', 'triceps', 'traps', 'forearms', 'neck', 'abductors')`, ); await db.execute( sql`create type ${sql.identifier(forceEnum.enumName)} as enum ('isometric', 'isotonic', 'isokinetic')`, @@ -2375,8 +2376,9 @@ export function tests() { ); await db.execute(sql`create type ${sql.identifier(mechanicEnum.enumName)} as enum ('compound', 'isolation')`); await db.execute( - sql`create type ${sql.identifier(equipmentEnum.enumName) - } as enum ('barbell', 'dumbbell', 'bodyweight', 'machine', 'cable', 'kettlebell')`, + sql`create type ${ + sql.identifier(equipmentEnum.enumName) + } as enum ('barbell', 'dumbbell', 'bodyweight', 'machine', 'cable', 'kettlebell')`, ); await db.execute( sql`create type ${sql.identifier(categoryEnum.enumName)} as enum ('upper_body', 'lower_body', 'full_body')`, @@ -4507,7 +4509,7 @@ export function tests() { await db.execute(sql`drop table if exists ${jsonTable}`); - db.execute(sql`create table ${jsonTable} (json json, jsonb jsonb)`); + await db.execute(sql`create table ${jsonTable} (json json, jsonb jsonb)`); await db.insert(jsonTable).values({ json: { name: 'Tom', age: 75 }, jsonb: { name: 'Pete', age: 23 } }); @@ -4556,7 +4558,7 @@ export function tests() { jsonNumberField: String(testNumber), jsonbStringField: testString, jsonbNumberField: String(testNumber), - }]) + }]); }); test('set json/jsonb fields with strings and retrieve with the ->> operator', async (ctx) => { @@ -4582,7 +4584,7 @@ export function tests() { jsonNumberField: String(testNumber), jsonbStringField: testString, jsonbNumberField: String(testNumber), - }]) + }]); }); test('set json/jsonb fields with objects and retrieve with the -> operator', async (ctx) => { @@ -4608,7 +4610,7 @@ export function tests() { jsonNumberField: testNumber, jsonbStringField: testString, jsonbNumberField: testNumber, - }]) + }]); }); test('set json/jsonb fields with strings and retrieve with the -> operator', async (ctx) => { @@ -4634,7 +4636,7 @@ export function tests() { jsonNumberField: testNumber, jsonbStringField: testString, jsonbNumberField: testNumber, - }]) + }]); }); }); -} \ No newline at end of file +} From f74f8f3cf3bc172cdf5a3d3e95be92f0bc798954 Mon Sep 17 00:00:00 2001 From: veloii <85405932+veloii@users.noreply.github.com> Date: Tue, 6 Aug 2024 18:26:31 +0100 Subject: [PATCH 047/492] Add tests for SQLite using `type: boolean` with prepared statements --- integration-tests/tests/sqlite/sqlite-common.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 49c609941..4f84f7111 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -845,12 +845,12 @@ export function tests() { const { db } = ctx.sqlite; const stmt = db.insert(usersTable).values({ - verified: true, + verified: sql.placeholder("verified"), name: sql.placeholder('name'), }).prepare(); for (let i = 0; i < 10; i++) { - await stmt.run({ name: `John ${i}` }); + await stmt.run({ name: `John ${i}`, verified: i % 2 === 0 }); } const result = await db.select({ @@ -861,15 +861,15 @@ export function tests() { expect(result).toEqual([ { id: 1, name: 'John 0', verified: true }, - { id: 2, name: 'John 1', verified: true }, + { id: 2, name: 'John 1', verified: false }, { id: 3, name: 'John 2', verified: true }, - { id: 4, name: 'John 3', verified: true }, + { id: 4, name: 'John 3', verified: false }, { id: 5, name: 'John 4', verified: true }, - { id: 6, name: 'John 5', verified: true }, + { id: 6, name: 'John 5', verified: false }, { id: 7, name: 'John 6', verified: true }, - { id: 8, name: 'John 7', verified: true }, + { id: 8, name: 'John 7', verified: false }, { id: 9, name: 'John 8', verified: true }, - { id: 10, name: 'John 9', verified: true }, + { id: 10, name: 'John 9', verified: false }, ]); }); From 9ff80929afcbe1642e5a97fe7412a7005f4abbd8 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 6 Aug 2024 21:39:26 +0300 Subject: [PATCH 048/492] Do not sort pks in sqlite --- .../src/serializer/sqliteSerializer.ts | 107 ++++++++---------- 1 file changed, 48 insertions(+), 59 deletions(-) diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index c673daafb..2dfdedcea 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -65,8 +65,8 @@ export const generateSqliteSnapshot = ( as: is(generated.as, SQL) ? `(${dialect.sqlToQuery(generated.as as SQL, 'indexes').sql})` : typeof generated.as === 'function' - ? `(${dialect.sqlToQuery(generated.as() as SQL, 'indexes').sql})` - : `(${generated.as as any})`, + ? `(${dialect.sqlToQuery(generated.as() as SQL, 'indexes').sql})` + : `(${generated.as as any})`, type: generated.mode ?? 'virtual', } : undefined, @@ -79,9 +79,9 @@ export const generateSqliteSnapshot = ( columnToSet.default = typeof column.default === 'string' ? `'${column.default}'` : typeof column.default === 'object' - || Array.isArray(column.default) - ? `'${JSON.stringify(column.default)}'` - : column.default; + || Array.isArray(column.default) + ? `'${JSON.stringify(column.default)}'` + : column.default; } } columnsObject[column.name] = columnToSet; @@ -90,24 +90,19 @@ export const generateSqliteSnapshot = ( const existingUnique = indexesObject[column.uniqueName!]; if (typeof existingUnique !== 'undefined') { console.log( - `\n${ - withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ - chalk.underline.blue( - tableName, - ) + `\n${withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${chalk.underline.blue( + tableName, + ) } table. - The unique constraint ${ - chalk.underline.blue( - column.uniqueName, - ) - } on the ${ - chalk.underline.blue( - column.name, - ) - } column is confilcting with a unique constraint name already defined for ${ - chalk.underline.blue( - existingUnique.columns.join(','), - ) + The unique constraint ${chalk.underline.blue( + column.uniqueName, + ) + } on the ${chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${chalk.underline.blue( + existingUnique.columns.join(','), + ) } columns\n`) }`, ); @@ -202,26 +197,21 @@ export const generateSqliteSnapshot = ( const existingUnique = indexesObject[name]; if (typeof existingUnique !== 'undefined') { console.log( - `\n${ - withStyle.errorWarning( - `We\'ve found duplicated unique constraint names in ${ - chalk.underline.blue( - tableName, - ) - } table. \nThe unique constraint ${ - chalk.underline.blue( - name, - ) - } on the ${ - chalk.underline.blue( - columnNames.join(','), - ) - } columns is confilcting with a unique constraint name already defined for ${ - chalk.underline.blue( - existingUnique.columns.join(','), - ) - } columns\n`, + `\n${withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${chalk.underline.blue( + tableName, + ) + } table. \nThe unique constraint ${chalk.underline.blue( + name, + ) + } on the ${chalk.underline.blue( + columnNames.join(','), ) + } columns is confilcting with a unique constraint name already defined for ${chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`, + ) }`, ); process.exit(1); @@ -237,7 +227,7 @@ export const generateSqliteSnapshot = ( primaryKeys.forEach((it) => { if (it.columns.length > 1) { primaryKeysObject[it.getName()] = { - columns: it.columns.map((it) => it.name).sort(), + columns: it.columns.map((it) => it.name), name: it.getName(), }; } else { @@ -464,26 +454,26 @@ export const fromDatabase = async ( default: columnDefault === null ? undefined : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) - ? Number(columnDefault) - : ['CURRENT_TIME', 'CURRENT_DATE', 'CURRENT_TIMESTAMP'].includes( + ? Number(columnDefault) + : ['CURRENT_TIME', 'CURRENT_DATE', 'CURRENT_TIMESTAMP'].includes( columnDefault, ) - ? `(${columnDefault})` - : columnDefault === 'false' - ? false - : columnDefault === 'true' - ? true - : columnDefault.startsWith("'") && columnDefault.endsWith("'") - ? columnDefault - // ? columnDefault.substring(1, columnDefault.length - 1) - : `(${columnDefault})`, + ? `(${columnDefault})` + : columnDefault === 'false' + ? false + : columnDefault === 'true' + ? true + : columnDefault.startsWith("'") && columnDefault.endsWith("'") + ? columnDefault + // ? columnDefault.substring(1, columnDefault.length - 1) + : `(${columnDefault})`, autoincrement: isAutoincrement, name: columnName, type: mapSqlToSqliteType(columnType), primaryKey: false, notNull: isNotNull, generated: tableToGeneratedColumnsInfo[tableName] - && tableToGeneratedColumnsInfo[tableName][columnName] + && tableToGeneratedColumnsInfo[tableName][columnName] ? { type: tableToGeneratedColumnsInfo[tableName][columnName].type, as: tableToGeneratedColumnsInfo[tableName][columnName].expression, @@ -580,11 +570,10 @@ export const fromDatabase = async ( const columnsTo = fkByTableName[`${tableName}_${id}`].columnsTo; fkByTableName[ `${tableName}_${id}` - ].name = `${tableName}_${ - columnsFrom.join( - '_', - ) - }_${refTableName}_${columnsTo.join('_')}_fk`; + ].name = `${tableName}_${columnsFrom.join( + '_', + ) + }_${refTableName}_${columnsTo.join('_')}_fk`; } for (const idx of Object.keys(fkByTableName)) { From ae5b5b67e06c23ad601234fd6407228a7dab3cb8 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 6 Aug 2024 16:13:32 -0700 Subject: [PATCH 049/492] Moved `line` and `point` back to `columns` folder in PG --- drizzle-orm/src/pg-core/columns/index.ts | 4 ++-- .../src/pg-core/columns/{postgis_extension => }/line.ts | 2 +- .../src/pg-core/columns/{postgis_extension => }/point.ts | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename drizzle-orm/src/pg-core/columns/{postgis_extension => }/line.ts (98%) rename drizzle-orm/src/pg-core/columns/{postgis_extension => }/point.ts (100%) diff --git a/drizzle-orm/src/pg-core/columns/index.ts b/drizzle-orm/src/pg-core/columns/index.ts index 8be5dbea7..881f53e33 100644 --- a/drizzle-orm/src/pg-core/columns/index.ts +++ b/drizzle-orm/src/pg-core/columns/index.ts @@ -13,12 +13,12 @@ export * from './integer.ts'; export * from './interval.ts'; export * from './json.ts'; export * from './jsonb.ts'; +export * from './line.ts'; export * from './macaddr.ts'; export * from './macaddr8.ts'; export * from './numeric.ts'; +export * from './point.ts'; export * from './postgis_extension/geometry.ts'; -export * from './postgis_extension/line.ts'; -export * from './postgis_extension/point.ts'; export * from './real.ts'; export * from './serial.ts'; export * from './smallint.ts'; diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts b/drizzle-orm/src/pg-core/columns/line.ts similarity index 98% rename from drizzle-orm/src/pg-core/columns/postgis_extension/line.ts rename to drizzle-orm/src/pg-core/columns/line.ts index f43ab09fe..cd4b70a66 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/line.ts +++ b/drizzle-orm/src/pg-core/columns/line.ts @@ -4,7 +4,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; -import { PgColumn, PgColumnBuilder } from '../common.ts'; +import { PgColumn, PgColumnBuilder } from './common.ts'; export type PgLineBuilderInitial = PgLineBuilder<{ name: TName; diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/point.ts b/drizzle-orm/src/pg-core/columns/point.ts similarity index 100% rename from drizzle-orm/src/pg-core/columns/postgis_extension/point.ts rename to drizzle-orm/src/pg-core/columns/point.ts From 39c1419298c1f8b33d8436709e0fc9735f10c64e Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 6 Aug 2024 19:00:47 -0700 Subject: [PATCH 050/492] Add more tests --- drizzle-kit/src/serializer/pgSerializer.ts | 4 +- drizzle-kit/src/utils.ts | 4 + drizzle-kit/tests/pg-array.test.ts | 115 ++++++++++++++++++++- drizzle-kit/tests/push/pg.test.ts | 74 +++++++++++++ 4 files changed, 194 insertions(+), 3 deletions(-) diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 4c4831e8f..6470cf1ff 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -30,7 +30,7 @@ import type { Table, UniqueConstraint, } from '../serializer/pgSchema'; -import type { DB } from '../utils'; +import { type DB, isPgArrayType } from '../utils'; import { sqlToStr } from '.'; const dialect = new PgDialect(); @@ -263,7 +263,7 @@ export const generatePgSnapshot = ( } else { columnToSet.default = `'${column.default.toISOString()}'`; } - } else if (sqlTypeLowered.match(/.*\[\d*\].*|.*\[\].*/g) !== null && Array.isArray(column.default)) { + } else if (isPgArrayType(sqlTypeLowered) && Array.isArray(column.default)) { columnToSet.default = `'${ buildArrayString( column.default, diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 279520ea6..6a7faff45 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -327,3 +327,7 @@ export const normaliseSQLiteUrl = ( assertUnreachable(type); }; + +export function isPgArrayType(sqlType: string) { + return sqlType.match(/.*\[\d*\].*|.*\[\].*/g) !== null; +} diff --git a/drizzle-kit/tests/pg-array.test.ts b/drizzle-kit/tests/pg-array.test.ts index 273d7cfcc..a35411adb 100644 --- a/drizzle-kit/tests/pg-array.test.ts +++ b/drizzle-kit/tests/pg-array.test.ts @@ -1,4 +1,16 @@ -import { bigint, boolean, date, integer, json, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; +import { + bigint, + boolean, + date, + integer, + json, + pgEnum, + pgTable, + serial, + text, + timestamp, + uuid, +} from 'drizzle-orm/pg-core'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; @@ -253,3 +265,104 @@ test('array #9: text array default', async (t) => { }, }); }); + +test('array #10: uuid array default', async (t) => { + const from = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: uuid('values').array().default([ + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', + 'b0eebc99-9c0b-4ef8-bb6d-cbb9bd380a11', + ]), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { + name: 'values', + type: 'uuid[]', + primaryKey: false, + notNull: false, + default: '\'{"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11","b0eebc99-9c0b-4ef8-bb6d-cbb9bd380a11"}\'::uuid[]', + }, + }); +}); + +test('array #11: enum array default', async (t) => { + const testEnum = pgEnum('test_enum', ['a', 'b', 'c']); + + const from = { + enum: testEnum, + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + enum: testEnum, + test: pgTable('test', { + id: serial('id').primaryKey(), + values: testEnum('values').array().default(['a', 'b', 'c']), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { + name: 'values', + type: 'test_enum[]', + primaryKey: false, + notNull: false, + default: '\'{"a","b","c"}\'::test_enum[]', + }, + }); +}); + +test('array #12: enum empty array default', async (t) => { + const testEnum = pgEnum('test_enum', ['a', 'b', 'c']); + + const from = { + enum: testEnum, + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const to = { + enum: testEnum, + test: pgTable('test', { + id: serial('id').primaryKey(), + values: testEnum('values').array().default([]), + }), + }; + + const { statements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { + name: 'values', + type: 'test_enum[]', + primaryKey: false, + notNull: false, + default: "'{}'::test_enum[]", + }, + }); +}); diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 1439d864e..cd5908bad 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -2162,3 +2162,77 @@ test('add identity to column - few params', async () => { // await client.query(st); // } }); + +test('add array column - empty array default', async () => { + const client = new PGlite(); + + const schema1 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const schema2 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().default([]), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'::integer[]" }, + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{}\'::integer[];', + ]); +}); + +test('add array column - default', async () => { + const client = new PGlite(); + + const schema1 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const schema2 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().default([1, 2, 3]), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'::integer[]" }, + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\'::integer[];', + ]); +}); From 0816942753a3fd3680396172f6f44c2bb5f59fc3 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 6 Aug 2024 19:10:03 -0700 Subject: [PATCH 051/492] Fix import --- drizzle-orm/src/pg-core/columns/point.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/pg-core/columns/point.ts b/drizzle-orm/src/pg-core/columns/point.ts index 52d531a56..584e395f9 100644 --- a/drizzle-orm/src/pg-core/columns/point.ts +++ b/drizzle-orm/src/pg-core/columns/point.ts @@ -4,7 +4,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; -import { PgColumn, PgColumnBuilder } from '../common.ts'; +import { PgColumn, PgColumnBuilder } from './common.ts'; export type PgPointTupleBuilderInitial = PgPointTupleBuilder<{ name: TName; From 06107e4932f3e642a642926abae9bd51efafa479 Mon Sep 17 00:00:00 2001 From: veloii <85405932+veloii@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:36:44 +0100 Subject: [PATCH 052/492] Fix placeholders being mapped to it's driver value instead of the value --- drizzle-orm/src/sql/sql.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drizzle-orm/src/sql/sql.ts b/drizzle-orm/src/sql/sql.ts index 244a95d5d..3814c9aaa 100644 --- a/drizzle-orm/src/sql/sql.ts +++ b/drizzle-orm/src/sql/sql.ts @@ -203,7 +203,11 @@ export class SQL implements SQLWrapper { } if (is(chunk, Param)) { - const mappedValue = (chunk.value === null) ? null : chunk.encoder.mapToDriverValue(chunk.value); + if (is(chunk.value, Placeholder)) { + return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ['none'] }; + } + + const mappedValue = chunk.value === null ? null : chunk.encoder.mapToDriverValue(chunk.value); if (is(mappedValue, SQL)) { return this.buildQueryFromSourceParams([mappedValue], config); @@ -583,9 +587,18 @@ export function fillPlaceholders(params: unknown[], values: Record Date: Wed, 7 Aug 2024 12:51:32 +0100 Subject: [PATCH 053/492] style: use tabs instead of spaces --- integration-tests/tests/sqlite/sqlite-common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 4f84f7111..7a2485582 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -845,7 +845,7 @@ export function tests() { const { db } = ctx.sqlite; const stmt = db.insert(usersTable).values({ - verified: sql.placeholder("verified"), + verified: sql.placeholder("verified"), name: sql.placeholder('name'), }).prepare(); From cc8d53bfed5a5bfda040f1c5ebf33e33d503d3b9 Mon Sep 17 00:00:00 2001 From: veloii <85405932+veloii@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:54:17 +0100 Subject: [PATCH 054/492] style: use ' instead of " --- integration-tests/tests/sqlite/sqlite-common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 7a2485582..8a40f3df9 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -845,7 +845,7 @@ export function tests() { const { db } = ctx.sqlite; const stmt = db.insert(usersTable).values({ - verified: sql.placeholder("verified"), + verified: sql.placeholder('verified'), name: sql.placeholder('name'), }).prepare(); From 94cf6e90c3b66058cfe22f8fe76ad07b65e36026 Mon Sep 17 00:00:00 2001 From: veloii <85405932+veloii@users.noreply.github.com> Date: Wed, 7 Aug 2024 14:51:40 +0100 Subject: [PATCH 055/492] revert sqlite prepared statement test --- .../tests/sqlite/sqlite-common.ts | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 8a40f3df9..3e25247a8 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -844,32 +844,28 @@ export function tests() { test('prepared statement reuse', async (ctx) => { const { db } = ctx.sqlite; - const stmt = db.insert(usersTable).values({ - verified: sql.placeholder('verified'), - name: sql.placeholder('name'), - }).prepare(); + const stmt = db.insert(usersTable).values({ name: sql.placeholder('name') }).prepare(); for (let i = 0; i < 10; i++) { - await stmt.run({ name: `John ${i}`, verified: i % 2 === 0 }); + await stmt.run({ name: `John ${i}` }); } const result = await db.select({ id: usersTable.id, name: usersTable.name, - verified: usersTable.verified, }).from(usersTable).all(); expect(result).toEqual([ - { id: 1, name: 'John 0', verified: true }, - { id: 2, name: 'John 1', verified: false }, - { id: 3, name: 'John 2', verified: true }, - { id: 4, name: 'John 3', verified: false }, - { id: 5, name: 'John 4', verified: true }, - { id: 6, name: 'John 5', verified: false }, - { id: 7, name: 'John 6', verified: true }, - { id: 8, name: 'John 7', verified: false }, - { id: 9, name: 'John 8', verified: true }, - { id: 10, name: 'John 9', verified: false }, + { id: 1, name: 'John 0' }, + { id: 2, name: 'John 1' }, + { id: 3, name: 'John 2' }, + { id: 4, name: 'John 3' }, + { id: 5, name: 'John 4' }, + { id: 6, name: 'John 5' }, + { id: 7, name: 'John 6' }, + { id: 8, name: 'John 7' }, + { id: 9, name: 'John 8' }, + { id: 10, name: 'John 9' }, ]); }); From b988d36da5343920fc704f56f587e7f1a63ce40f Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 7 Aug 2024 17:10:40 +0300 Subject: [PATCH 056/492] Up pg snapshots starting from v5 to latest(v7) --- drizzle-kit/src/api.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 06f6dc1c0..9334c84b6 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -12,7 +12,7 @@ import { } from './cli/commands/migrate'; import { pgPushIntrospect } from './cli/commands/pgIntrospect'; import { pgSuggestions } from './cli/commands/pgPushUtils'; -import { updateUpToV6 as upPgV6 } from './cli/commands/pgUp'; +import { updateUpToV6 as upPgV6, updateUpToV7 as upPgV7 } from './cli/commands/pgUp'; import { sqlitePushIntrospect } from './cli/commands/sqliteIntrospect'; import { logSuggestionsAndReturn } from './cli/commands/sqlitePushUtils'; import { originUUID } from './global'; @@ -194,7 +194,7 @@ export const pushSQLiteSchema = async ( }, run: async (query: string) => { return Promise.resolve(drizzleInstance.run(sql.raw(query))).then( - () => {}, + () => { }, ); }, }; @@ -341,5 +341,11 @@ export const pushMySQLSchema = async ( }; export const upPgSnapshot = (snapshot: Record) => { - return upPgV6(snapshot); + if (snapshot.version === '5') { + return upPgV7(upPgV6(snapshot)) + } + if (snapshot.version === '6') { + return upPgV7(snapshot); + } + return snapshot; }; From ab77a45fcc729f3ad9da7be36ddc370e1f92cf07 Mon Sep 17 00:00:00 2001 From: veloii <85405932+veloii@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:25:21 +0100 Subject: [PATCH 057/492] add 'insert: placeholders on columns with encoder' tests --- integration-tests/tests/mysql/mysql-common.ts | 24 +++++++++++++++++++ integration-tests/tests/pg/pg-common.ts | 24 ++++++++++++++++++- .../tests/sqlite/sqlite-common.ts | 22 +++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 47a60c7c8..ce459e1b7 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -1155,6 +1155,30 @@ export function tests(driver?: string) { expect(result).toEqual([{ id: 1, name: 'John' }]); }); + test('insert: placeholders on columns with encoder', async (ctx) => { + const { db } = ctx.mysql; + + const date = new Date(); + + const statement = db.insert(usersTable).values({ + name: 'John', + createdAt: sql.placeholder('createdAt'), + }).prepare(); + + await statement.execute({ createdAt: date }); + + const result = await db + .select({ + id: usersTable.id, + createdAt: usersTable.createdAt, + }) + .from(usersTable); + + expect(result).toEqual([ + { id: 1, createdAt: date }, + ]); + }); + test('prepared statement reuse', async (ctx) => { const { db } = ctx.mysql; diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index fb69c5877..6332894e7 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -246,7 +246,7 @@ export function tests() { create table users ( id serial primary key, name text not null, - verified boolean not null default false, + verified boolean not null default false, jsonb jsonb, created_at timestamptz not null default now() ) @@ -1116,6 +1116,28 @@ export function tests() { expect(result).toEqual([{ id: 1, name: 'John' }]); }); + test('insert: placeholders on columns with encoder', async (ctx) => { + const { db } = ctx.pg; + + const statement = db.insert(usersTable).values({ + name: 'John', + jsonb: sql.placeholder('jsonb'), + }).prepare('encoder_statement'); + + await statement.execute({ jsonb: ['foo', 'bar'] }); + + const result = await db + .select({ + id: usersTable.id, + jsonb: usersTable.jsonb, + }) + .from(usersTable); + + expect(result).toEqual([ + { id: 1, jsonb: ['foo', 'bar'] }, + ]); + }); + test('prepared statement reuse', async (ctx) => { const { db } = ctx.pg; diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 3e25247a8..be452bcf1 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -869,6 +869,28 @@ export function tests() { ]); }); + test('insert: placeholders on columns with encoder', async (ctx) => { + const { db } = ctx.sqlite; + + const stmt = db.insert(usersTable).values({ + name: 'John', + verified: sql.placeholder('verified'), + }).prepare(); + + await stmt.run({ verified: true }); + await stmt.run({ verified: false }); + + const result = await db.select({ + id: usersTable.id, + verified: usersTable.verified, + }).from(usersTable).all(); + + expect(result).toEqual([ + { id: 1, verified: true }, + { id: 2, verified: false }, + ]); + }); + test('prepared statement with placeholder in .where', async (ctx) => { const { db } = ctx.sqlite; From 75fb0e3e52ea78ed8310f0a652271fa8147d3ede Mon Sep 17 00:00:00 2001 From: veloii <85405932+veloii@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:35:13 +0100 Subject: [PATCH 058/492] specify date epoch for mysql placeholder test --- integration-tests/tests/mysql/mysql-common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index ce459e1b7..70cc0e10c 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -1158,7 +1158,7 @@ export function tests(driver?: string) { test('insert: placeholders on columns with encoder', async (ctx) => { const { db } = ctx.mysql; - const date = new Date(); + const date = new Date(1723041271); const statement = db.insert(usersTable).values({ name: 'John', From 497e9da587afe734d69512120d4bfb833646e712 Mon Sep 17 00:00:00 2001 From: veloii <85405932+veloii@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:42:01 +0100 Subject: [PATCH 059/492] remove precision from date in placeholder encoder mysql test --- integration-tests/tests/mysql/mysql-common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 70cc0e10c..07dab7dda 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -1158,7 +1158,7 @@ export function tests(driver?: string) { test('insert: placeholders on columns with encoder', async (ctx) => { const { db } = ctx.mysql; - const date = new Date(1723041271); + const date = new Date("2024-08-07T15:30:00Z"); const statement = db.insert(usersTable).values({ name: 'John', From df9e5962b301b3bac1554b389edb8c10720c8abd Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 7 Aug 2024 17:42:17 +0300 Subject: [PATCH 060/492] Format with dprint --- drizzle-kit/src/api.ts | 4 +- .../src/serializer/sqliteSerializer.ts | 105 ++++++++++-------- 2 files changed, 60 insertions(+), 49 deletions(-) diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 9334c84b6..00cdb1b61 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -194,7 +194,7 @@ export const pushSQLiteSchema = async ( }, run: async (query: string) => { return Promise.resolve(drizzleInstance.run(sql.raw(query))).then( - () => { }, + () => {}, ); }, }; @@ -342,7 +342,7 @@ export const pushMySQLSchema = async ( export const upPgSnapshot = (snapshot: Record) => { if (snapshot.version === '5') { - return upPgV7(upPgV6(snapshot)) + return upPgV7(upPgV6(snapshot)); } if (snapshot.version === '6') { return upPgV7(snapshot); diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 2dfdedcea..da4492278 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -65,8 +65,8 @@ export const generateSqliteSnapshot = ( as: is(generated.as, SQL) ? `(${dialect.sqlToQuery(generated.as as SQL, 'indexes').sql})` : typeof generated.as === 'function' - ? `(${dialect.sqlToQuery(generated.as() as SQL, 'indexes').sql})` - : `(${generated.as as any})`, + ? `(${dialect.sqlToQuery(generated.as() as SQL, 'indexes').sql})` + : `(${generated.as as any})`, type: generated.mode ?? 'virtual', } : undefined, @@ -79,9 +79,9 @@ export const generateSqliteSnapshot = ( columnToSet.default = typeof column.default === 'string' ? `'${column.default}'` : typeof column.default === 'object' - || Array.isArray(column.default) - ? `'${JSON.stringify(column.default)}'` - : column.default; + || Array.isArray(column.default) + ? `'${JSON.stringify(column.default)}'` + : column.default; } } columnsObject[column.name] = columnToSet; @@ -90,19 +90,24 @@ export const generateSqliteSnapshot = ( const existingUnique = indexesObject[column.uniqueName!]; if (typeof existingUnique !== 'undefined') { console.log( - `\n${withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${chalk.underline.blue( - tableName, - ) + `\n${ + withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) } table. - The unique constraint ${chalk.underline.blue( - column.uniqueName, - ) - } on the ${chalk.underline.blue( - column.name, - ) - } column is confilcting with a unique constraint name already defined for ${chalk.underline.blue( - existingUnique.columns.join(','), - ) + The unique constraint ${ + chalk.underline.blue( + column.uniqueName, + ) + } on the ${ + chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) } columns\n`) }`, ); @@ -197,21 +202,26 @@ export const generateSqliteSnapshot = ( const existingUnique = indexesObject[name]; if (typeof existingUnique !== 'undefined') { console.log( - `\n${withStyle.errorWarning( - `We\'ve found duplicated unique constraint names in ${chalk.underline.blue( - tableName, - ) - } table. \nThe unique constraint ${chalk.underline.blue( - name, - ) - } on the ${chalk.underline.blue( - columnNames.join(','), + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. \nThe unique constraint ${ + chalk.underline.blue( + name, + ) + } on the ${ + chalk.underline.blue( + columnNames.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`, ) - } columns is confilcting with a unique constraint name already defined for ${chalk.underline.blue( - existingUnique.columns.join(','), - ) - } columns\n`, - ) }`, ); process.exit(1); @@ -454,26 +464,26 @@ export const fromDatabase = async ( default: columnDefault === null ? undefined : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) - ? Number(columnDefault) - : ['CURRENT_TIME', 'CURRENT_DATE', 'CURRENT_TIMESTAMP'].includes( + ? Number(columnDefault) + : ['CURRENT_TIME', 'CURRENT_DATE', 'CURRENT_TIMESTAMP'].includes( columnDefault, ) - ? `(${columnDefault})` - : columnDefault === 'false' - ? false - : columnDefault === 'true' - ? true - : columnDefault.startsWith("'") && columnDefault.endsWith("'") - ? columnDefault - // ? columnDefault.substring(1, columnDefault.length - 1) - : `(${columnDefault})`, + ? `(${columnDefault})` + : columnDefault === 'false' + ? false + : columnDefault === 'true' + ? true + : columnDefault.startsWith("'") && columnDefault.endsWith("'") + ? columnDefault + // ? columnDefault.substring(1, columnDefault.length - 1) + : `(${columnDefault})`, autoincrement: isAutoincrement, name: columnName, type: mapSqlToSqliteType(columnType), primaryKey: false, notNull: isNotNull, generated: tableToGeneratedColumnsInfo[tableName] - && tableToGeneratedColumnsInfo[tableName][columnName] + && tableToGeneratedColumnsInfo[tableName][columnName] ? { type: tableToGeneratedColumnsInfo[tableName][columnName].type, as: tableToGeneratedColumnsInfo[tableName][columnName].expression, @@ -570,10 +580,11 @@ export const fromDatabase = async ( const columnsTo = fkByTableName[`${tableName}_${id}`].columnsTo; fkByTableName[ `${tableName}_${id}` - ].name = `${tableName}_${columnsFrom.join( - '_', - ) - }_${refTableName}_${columnsTo.join('_')}_fk`; + ].name = `${tableName}_${ + columnsFrom.join( + '_', + ) + }_${refTableName}_${columnsTo.join('_')}_fk`; } for (const idx of Object.keys(fkByTableName)) { From 6158d8ba6baa08fa0a8a780de7910164b35983c6 Mon Sep 17 00:00:00 2001 From: veloii <85405932+veloii@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:45:58 +0100 Subject: [PATCH 061/492] lint --- integration-tests/tests/mysql/mysql-common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 07dab7dda..58f7a1e2c 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -1158,7 +1158,7 @@ export function tests(driver?: string) { test('insert: placeholders on columns with encoder', async (ctx) => { const { db } = ctx.mysql; - const date = new Date("2024-08-07T15:30:00Z"); + const date = new Date('2024-08-07T15:30:00Z'); const statement = db.insert(usersTable).values({ name: 'John', From 86a8714f97ebde2d249952faf43e072717fab71c Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 8 Aug 2024 16:03:10 +0300 Subject: [PATCH 062/492] Add release notes --- changelogs/drizzle-kit/0.24.0.md | 24 ++++ changelogs/drizzle-orm/0.33.0.md | 60 ++++++++++ drizzle-kit/package.json | 2 +- .../src/serializer/sqliteSerializer.ts | 106 ++++++++---------- drizzle-orm/package.json | 2 +- 5 files changed, 133 insertions(+), 61 deletions(-) create mode 100644 changelogs/drizzle-kit/0.24.0.md create mode 100644 changelogs/drizzle-orm/0.33.0.md diff --git a/changelogs/drizzle-kit/0.24.0.md b/changelogs/drizzle-kit/0.24.0.md new file mode 100644 index 000000000..b766e018b --- /dev/null +++ b/changelogs/drizzle-kit/0.24.0.md @@ -0,0 +1,24 @@ +## Breaking changes (for SQLite users) + +#### Fixed [Composite primary key order is not consistent](https://github.com/drizzle-team/drizzle-kit-mirror/issues/342) by removing `sort` in SQLite and to be consistant with the same logic in PostgreSQL and MySQL + +The issue that may arise for SQLite users with any driver using composite primary keys is that the order in the database may differ from the Drizzle schema. + +- If you are using `push`, you **MAY** be prompted to update your table with a new order of columns in the composite primary key. You will need to either change it manually in the database or push the changes, but this may lead to data loss, etc. + +- If you are using `generate`, you **MAY** also be prompted to update your table with a new order of columns in the composite primary key. You can either keep that migration or skip it by emptying the SQL migration file. + +If nothing works for you and you are blocked, please reach out to me @AndriiSherman. I will try to help you! + + +## Bug fixes + +- [[BUG] When using double type columns, import is not inserted](https://github.com/drizzle-team/drizzle-kit-mirror/issues/403) - thanks @Karibash +- [[BUG] A number value is specified as the default for a column of type char](https://github.com/drizzle-team/drizzle-kit-mirror/issues/404) - thanks @Karibash +- [[BUG]: Array default in migrations are wrong](https://github.com/drizzle-team/drizzle-orm/issues/2621) - thanks @L-Mario564 +- [[FEATURE]: Simpler default array fields](https://github.com/drizzle-team/drizzle-orm/issues/2709) - thanks @L-Mario564 +- [[BUG]: drizzle-kit generate succeeds but generates invalid SQL for default([]) - Postgres](https://github.com/drizzle-team/drizzle-orm/issues/2432) - thanks @L-Mario564 +- [[BUG]: Incorrect type for array column default value](https://github.com/drizzle-team/drizzle-orm/issues/2334) - thanks @L-Mario564 +- [[BUG]: error: column is of type integer[] but default expression is of type integer](https://github.com/drizzle-team/drizzle-orm/issues/2224) - thanks @L-Mario564 +- [[BUG]: Default value in array generating wrong migration file](https://github.com/drizzle-team/drizzle-orm/issues/1003) - thanks @L-Mario564 +- [[BUG]: enum as array, not possible?](https://github.com/drizzle-team/drizzle-orm/issues/1564) - thanks @L-Mario564 \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.33.0.md b/changelogs/drizzle-orm/0.33.0.md new file mode 100644 index 000000000..e8fa5a6c8 --- /dev/null +++ b/changelogs/drizzle-orm/0.33.0.md @@ -0,0 +1,60 @@ +## Breaking changes (for some of postgres.js users) + +#### Bugs fixed for this breaking change + +- [Open +[BUG]: jsonb always inserted as a json string when using postgres-js](https://github.com/drizzle-team/drizzle-orm/issues/724) +- [[BUG]: jsonb type on postgres implement incorrectly](https://github.com/drizzle-team/drizzle-orm/issues/1511) + +If you were using `postgres-js` with `jsonb` fields, you might have seen stringified objects in your database, while drizzle insert and select operations were working as expected. + +You need to convert those fields from strings to actual JSON objects. To do this, you can use the following query to update your database: + +**if you are using jsonb:** +```sql +update table_name +set jsonb_column = (jsonb_column #>> '{}')::jsonb; +``` + +**if you are using json:** +```sql +update table_name +set json_column = (json_column #>> '{}')::json; +``` + +We've tested it in several cases, and it worked well, but only if all stringified objects are arrays or objects. If you have primitives like strings, numbers, booleans, etc., you can use this query to update all the fields + +**if you are using jsonb:** +```sql +UPDATE table_name +SET jsonb_column = CASE + -- Convert to JSONB if it is a valid JSON object or array + WHEN jsonb_column #>> '{}' LIKE '{%' OR jsonb_column #>> '{}' LIKE '[%' THEN + (jsonb_column #>> '{}')::jsonb + ELSE + jsonb_column +END +WHERE + jsonb_column IS NOT NULL; +``` + +**if you are using json:** +```sql +UPDATE table_name +SET json_column = CASE + -- Convert to JSON if it is a valid JSON object or array + WHEN json_column #>> '{}' LIKE '{%' OR json_column #>> '{}' LIKE '[%' THEN + (json_column #>> '{}')::json + ELSE + json_column +END +WHERE json_column IS NOT NULL; +``` + +If nothing works for you and you are blocked, please reach out to me @AndriiSherman. I will try to help you! + +## Bug Fixes + +- [[BUG]: boolean mode not working with prepared statements (bettersqlite)](https://github.com/drizzle-team/drizzle-orm/issues/2568) - thanks @veloii +- [[BUG]: isTable helper function is not working](https://github.com/drizzle-team/drizzle-orm/issues/2672) - thanks @hajek-raven +- [[BUG]: Documentation is outdated on inArray and notInArray Methods](https://github.com/drizzle-team/drizzle-orm/issues/2690) - thanks @RemiPeruto \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index c3f885722..25297e5b9 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.23.2", + "version": "0.24.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index c673daafb..d9fcc63f7 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -65,8 +65,8 @@ export const generateSqliteSnapshot = ( as: is(generated.as, SQL) ? `(${dialect.sqlToQuery(generated.as as SQL, 'indexes').sql})` : typeof generated.as === 'function' - ? `(${dialect.sqlToQuery(generated.as() as SQL, 'indexes').sql})` - : `(${generated.as as any})`, + ? `(${dialect.sqlToQuery(generated.as() as SQL, 'indexes').sql})` + : `(${generated.as as any})`, type: generated.mode ?? 'virtual', } : undefined, @@ -79,9 +79,9 @@ export const generateSqliteSnapshot = ( columnToSet.default = typeof column.default === 'string' ? `'${column.default}'` : typeof column.default === 'object' - || Array.isArray(column.default) - ? `'${JSON.stringify(column.default)}'` - : column.default; + || Array.isArray(column.default) + ? `'${JSON.stringify(column.default)}'` + : column.default; } } columnsObject[column.name] = columnToSet; @@ -90,24 +90,19 @@ export const generateSqliteSnapshot = ( const existingUnique = indexesObject[column.uniqueName!]; if (typeof existingUnique !== 'undefined') { console.log( - `\n${ - withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ - chalk.underline.blue( - tableName, - ) + `\n${withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${chalk.underline.blue( + tableName, + ) } table. - The unique constraint ${ - chalk.underline.blue( - column.uniqueName, - ) - } on the ${ - chalk.underline.blue( - column.name, - ) - } column is confilcting with a unique constraint name already defined for ${ - chalk.underline.blue( - existingUnique.columns.join(','), - ) + The unique constraint ${chalk.underline.blue( + column.uniqueName, + ) + } on the ${chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${chalk.underline.blue( + existingUnique.columns.join(','), + ) } columns\n`) }`, ); @@ -202,26 +197,21 @@ export const generateSqliteSnapshot = ( const existingUnique = indexesObject[name]; if (typeof existingUnique !== 'undefined') { console.log( - `\n${ - withStyle.errorWarning( - `We\'ve found duplicated unique constraint names in ${ - chalk.underline.blue( - tableName, - ) - } table. \nThe unique constraint ${ - chalk.underline.blue( - name, - ) - } on the ${ - chalk.underline.blue( - columnNames.join(','), - ) - } columns is confilcting with a unique constraint name already defined for ${ - chalk.underline.blue( - existingUnique.columns.join(','), - ) - } columns\n`, + `\n${withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${chalk.underline.blue( + tableName, + ) + } table. \nThe unique constraint ${chalk.underline.blue( + name, + ) + } on the ${chalk.underline.blue( + columnNames.join(','), ) + } columns is confilcting with a unique constraint name already defined for ${chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`, + ) }`, ); process.exit(1); @@ -237,7 +227,7 @@ export const generateSqliteSnapshot = ( primaryKeys.forEach((it) => { if (it.columns.length > 1) { primaryKeysObject[it.getName()] = { - columns: it.columns.map((it) => it.name).sort(), + columns: it.columns.map((it) => it.name), name: it.getName(), }; } else { @@ -464,26 +454,26 @@ export const fromDatabase = async ( default: columnDefault === null ? undefined : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) - ? Number(columnDefault) - : ['CURRENT_TIME', 'CURRENT_DATE', 'CURRENT_TIMESTAMP'].includes( + ? Number(columnDefault) + : ['CURRENT_TIME', 'CURRENT_DATE', 'CURRENT_TIMESTAMP'].includes( columnDefault, ) - ? `(${columnDefault})` - : columnDefault === 'false' - ? false - : columnDefault === 'true' - ? true - : columnDefault.startsWith("'") && columnDefault.endsWith("'") - ? columnDefault - // ? columnDefault.substring(1, columnDefault.length - 1) - : `(${columnDefault})`, + ? `(${columnDefault})` + : columnDefault === 'false' + ? false + : columnDefault === 'true' + ? true + : columnDefault.startsWith("'") && columnDefault.endsWith("'") + ? columnDefault + // ? columnDefault.substring(1, columnDefault.length - 1) + : `(${columnDefault})`, autoincrement: isAutoincrement, name: columnName, type: mapSqlToSqliteType(columnType), primaryKey: false, notNull: isNotNull, generated: tableToGeneratedColumnsInfo[tableName] - && tableToGeneratedColumnsInfo[tableName][columnName] + && tableToGeneratedColumnsInfo[tableName][columnName] ? { type: tableToGeneratedColumnsInfo[tableName][columnName].type, as: tableToGeneratedColumnsInfo[tableName][columnName].expression, @@ -509,7 +499,6 @@ export const fromDatabase = async ( for (const [key, value] of Object.entries(tableToPk)) { if (value.length > 1) { - value.sort(); result[key].compositePrimaryKeys = { [`${key}_${value.join('_')}_pk`]: { columns: value, @@ -580,10 +569,9 @@ export const fromDatabase = async ( const columnsTo = fkByTableName[`${tableName}_${id}`].columnsTo; fkByTableName[ `${tableName}_${id}` - ].name = `${tableName}_${ - columnsFrom.join( - '_', - ) + ].name = `${tableName}_${columnsFrom.join( + '_', + ) }_${refTableName}_${columnsTo.join('_')}_fk`; } diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 9b0db78bc..888f7efcb 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.32.2", + "version": "0.33.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { From 6205f018f5667092bc0daec56cd0e8c7131048c3 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 8 Aug 2024 16:12:11 +0300 Subject: [PATCH 063/492] Use dprint --- .../src/serializer/sqliteSerializer.ts | 103 ++++++++++-------- 1 file changed, 57 insertions(+), 46 deletions(-) diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index d9fcc63f7..ce544235b 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -65,8 +65,8 @@ export const generateSqliteSnapshot = ( as: is(generated.as, SQL) ? `(${dialect.sqlToQuery(generated.as as SQL, 'indexes').sql})` : typeof generated.as === 'function' - ? `(${dialect.sqlToQuery(generated.as() as SQL, 'indexes').sql})` - : `(${generated.as as any})`, + ? `(${dialect.sqlToQuery(generated.as() as SQL, 'indexes').sql})` + : `(${generated.as as any})`, type: generated.mode ?? 'virtual', } : undefined, @@ -79,9 +79,9 @@ export const generateSqliteSnapshot = ( columnToSet.default = typeof column.default === 'string' ? `'${column.default}'` : typeof column.default === 'object' - || Array.isArray(column.default) - ? `'${JSON.stringify(column.default)}'` - : column.default; + || Array.isArray(column.default) + ? `'${JSON.stringify(column.default)}'` + : column.default; } } columnsObject[column.name] = columnToSet; @@ -90,19 +90,24 @@ export const generateSqliteSnapshot = ( const existingUnique = indexesObject[column.uniqueName!]; if (typeof existingUnique !== 'undefined') { console.log( - `\n${withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${chalk.underline.blue( - tableName, - ) + `\n${ + withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) } table. - The unique constraint ${chalk.underline.blue( - column.uniqueName, - ) - } on the ${chalk.underline.blue( - column.name, - ) - } column is confilcting with a unique constraint name already defined for ${chalk.underline.blue( - existingUnique.columns.join(','), - ) + The unique constraint ${ + chalk.underline.blue( + column.uniqueName, + ) + } on the ${ + chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) } columns\n`) }`, ); @@ -197,21 +202,26 @@ export const generateSqliteSnapshot = ( const existingUnique = indexesObject[name]; if (typeof existingUnique !== 'undefined') { console.log( - `\n${withStyle.errorWarning( - `We\'ve found duplicated unique constraint names in ${chalk.underline.blue( - tableName, - ) - } table. \nThe unique constraint ${chalk.underline.blue( - name, - ) - } on the ${chalk.underline.blue( - columnNames.join(','), + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. \nThe unique constraint ${ + chalk.underline.blue( + name, + ) + } on the ${ + chalk.underline.blue( + columnNames.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`, ) - } columns is confilcting with a unique constraint name already defined for ${chalk.underline.blue( - existingUnique.columns.join(','), - ) - } columns\n`, - ) }`, ); process.exit(1); @@ -454,26 +464,26 @@ export const fromDatabase = async ( default: columnDefault === null ? undefined : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) - ? Number(columnDefault) - : ['CURRENT_TIME', 'CURRENT_DATE', 'CURRENT_TIMESTAMP'].includes( + ? Number(columnDefault) + : ['CURRENT_TIME', 'CURRENT_DATE', 'CURRENT_TIMESTAMP'].includes( columnDefault, ) - ? `(${columnDefault})` - : columnDefault === 'false' - ? false - : columnDefault === 'true' - ? true - : columnDefault.startsWith("'") && columnDefault.endsWith("'") - ? columnDefault - // ? columnDefault.substring(1, columnDefault.length - 1) - : `(${columnDefault})`, + ? `(${columnDefault})` + : columnDefault === 'false' + ? false + : columnDefault === 'true' + ? true + : columnDefault.startsWith("'") && columnDefault.endsWith("'") + ? columnDefault + // ? columnDefault.substring(1, columnDefault.length - 1) + : `(${columnDefault})`, autoincrement: isAutoincrement, name: columnName, type: mapSqlToSqliteType(columnType), primaryKey: false, notNull: isNotNull, generated: tableToGeneratedColumnsInfo[tableName] - && tableToGeneratedColumnsInfo[tableName][columnName] + && tableToGeneratedColumnsInfo[tableName][columnName] ? { type: tableToGeneratedColumnsInfo[tableName][columnName].type, as: tableToGeneratedColumnsInfo[tableName][columnName].expression, @@ -569,9 +579,10 @@ export const fromDatabase = async ( const columnsTo = fkByTableName[`${tableName}_${id}`].columnsTo; fkByTableName[ `${tableName}_${id}` - ].name = `${tableName}_${columnsFrom.join( - '_', - ) + ].name = `${tableName}_${ + columnsFrom.join( + '_', + ) }_${refTableName}_${columnsTo.join('_')}_fk`; } From f2a2b5f17b5a01819cb0dcbe319a0678064331bc Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 8 Aug 2024 16:53:05 +0300 Subject: [PATCH 064/492] Update release notes --- changelogs/drizzle-orm/0.33.0.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelogs/drizzle-orm/0.33.0.md b/changelogs/drizzle-orm/0.33.0.md index e8fa5a6c8..0093c9d05 100644 --- a/changelogs/drizzle-orm/0.33.0.md +++ b/changelogs/drizzle-orm/0.33.0.md @@ -6,6 +6,10 @@ [BUG]: jsonb always inserted as a json string when using postgres-js](https://github.com/drizzle-team/drizzle-orm/issues/724) - [[BUG]: jsonb type on postgres implement incorrectly](https://github.com/drizzle-team/drizzle-orm/issues/1511) +> As we are doing with other drivers, we've changed the behavior of PostgreSQL-JS to pass raw JSON values, the same as you see them in the database. So if you are using the PostgreSQL-JS driver and passing data to Drizzle elsewhere, please check the new behavior of the client after it is passed to Drizzle. + +> We will update it to ensure it does not override driver behaviors, but this will be done as a complex task for everything in Drizzle in other releases + If you were using `postgres-js` with `jsonb` fields, you might have seen stringified objects in your database, while drizzle insert and select operations were working as expected. You need to convert those fields from strings to actual JSON objects. To do this, you can use the following query to update your database: From 1e1d4e028b1269c84f1320aed78e651f44d9e0ae Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 12 Aug 2024 12:40:27 +0300 Subject: [PATCH 065/492] LibSQL improvements Added: - handling alteting columns in libsql - new json statement for recreation table for sqlite and libsql - push updated for sqlite and libsql - tests --- .../src/cli/commands/libSqlPushUtils.ts | 327 +++++ drizzle-kit/src/cli/commands/migrate.ts | 94 +- drizzle-kit/src/cli/commands/push.ts | 123 +- .../src/cli/commands/sqlitePushUtils.ts | 300 ++-- drizzle-kit/src/cli/commands/utils.ts | 5 + drizzle-kit/src/cli/schema.ts | 12 +- drizzle-kit/src/cli/validations/cli.ts | 3 +- drizzle-kit/src/jsonStatements.ts | 200 ++- drizzle-kit/src/snapshotsDiffer.ts | 432 +++++- drizzle-kit/src/sqlgenerator.ts | 390 +++++- drizzle-kit/src/statementCombiner.ts | 387 ++++++ drizzle-kit/src/utils.ts | 10 + drizzle-kit/tests/libsql-statements.test.ts | 835 +++++++++++ drizzle-kit/tests/push/libsql.test.ts | 744 ++++++++++ drizzle-kit/tests/push/sqlite.test.ts | 1233 ++++++++++++----- drizzle-kit/tests/schemaDiffer.ts | 273 +++- .../libsql-statements-combiner.test.ts | 1209 ++++++++++++++++ .../sqilte-statements-combiner.test.ts | 778 +++++++++++ 18 files changed, 6758 insertions(+), 597 deletions(-) create mode 100644 drizzle-kit/src/cli/commands/libSqlPushUtils.ts create mode 100644 drizzle-kit/src/statementCombiner.ts create mode 100644 drizzle-kit/tests/libsql-statements.test.ts create mode 100644 drizzle-kit/tests/push/libsql.test.ts create mode 100644 drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts create mode 100644 drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts diff --git a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts new file mode 100644 index 000000000..537eee0a5 --- /dev/null +++ b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts @@ -0,0 +1,327 @@ +import chalk from 'chalk'; + +import { JsonStatement } from 'src/jsonStatements'; +import { findAddedAndRemoved, SQLiteDB } from 'src/utils'; +import { SQLiteSchemaInternal, SQLiteSchemaSquashed, SQLiteSquasher } from '../../serializer/sqliteSchema'; +import { + CreateSqliteIndexConvertor, + fromJson, + LibSQLModifyColumn, + SQLiteCreateTableConvertor, + SQLiteDropTableConvertor, + SqliteRenameTableConvertor, +} from '../../sqlgenerator'; + +export const getOldTableName = ( + tableName: string, + meta: SQLiteSchemaInternal['_meta'], +) => { + for (const key of Object.keys(meta.tables)) { + const value = meta.tables[key]; + if (`"${tableName}"` === value) { + return key.substring(1, key.length - 1); + } + } + return tableName; +}; + +export const _moveDataStatements = ( + tableName: string, + json: SQLiteSchemaSquashed, + dataLoss: boolean = false, +) => { + const statements: string[] = []; + + statements.push( + new SqliteRenameTableConvertor().convert({ + type: 'rename_table', + tableNameFrom: tableName, + tableNameTo: `__old_push_${tableName}`, + fromSchema: '', + toSchema: '', + }), + ); + + const tableColumns = Object.values(json.tables[tableName].columns); + const referenceData = Object.values(json.tables[tableName].foreignKeys); + const compositePKs = Object.values( + json.tables[tableName].compositePrimaryKeys, + ).map((it) => SQLiteSquasher.unsquashPK(it)); + + statements.push( + new SQLiteCreateTableConvertor().convert({ + type: 'sqlite_create_table', + tableName: tableName, + columns: tableColumns, + referenceData: referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)), + compositePKs, + }), + ); + + if (!dataLoss) { + const columns = Object.keys(json.tables[tableName].columns).map( + (c) => `"${c}"`, + ); + + statements.push( + `INSERT INTO \`${tableName}\`(${ + columns.join( + ', ', + ) + }) SELECT (${columns.join(', ')}) FROM \`__old_push_${tableName}\`;`, + ); + } + + statements.push( + new SQLiteDropTableConvertor().convert({ + type: 'drop_table', + tableName: `__old_push_${tableName}`, + schema: '', + }), + ); + + for (const idx of Object.values(json.tables[tableName].indexes)) { + statements.push( + new CreateSqliteIndexConvertor().convert({ + type: 'create_index', + tableName: tableName, + schema: '', + data: idx, + }), + ); + } + + return statements; +}; + +export const libSqlLogSuggestionsAndReturn = async ( + connection: SQLiteDB, + statements: JsonStatement[], + json1: SQLiteSchemaSquashed, + json2: SQLiteSchemaSquashed, + meta: SQLiteSchemaInternal['_meta'], +) => { + let shouldAskForApprove = false; + const statementsToExecute: string[] = []; + const infoToPrint: string[] = []; + + const tablesToRemove: string[] = []; + const columnsToRemove: string[] = []; + const tablesToTruncate: string[] = []; + + for (const statement of statements) { + if (statement.type === 'drop_table') { + const res = await connection.query<{ count: string }>( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.tableName, + ) + } table with ${count} items`, + ); + tablesToRemove.push(statement.tableName); + shouldAskForApprove = true; + } + const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else if (statement.type === 'alter_table_drop_column') { + const tableName = statement.tableName; + + const res = await connection.query<{ count: string }>( + `select count(*) as count from \`${tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.columnName, + ) + } column in ${tableName} table with ${count} items`, + ); + columnsToRemove.push(`${tableName}_${statement.columnName}`); + shouldAskForApprove = true; + } + + const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else if ( + statement.type === 'sqlite_alter_table_add_column' + && statement.column.notNull + && !statement.column.default + ) { + const newTableName = statement.tableName; + const res = await connection.query<{ count: string }>( + `select count(*) as count from \`${newTableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + statement.column.name, + ) + } column without default value, which contains ${count} items`, + ); + + tablesToTruncate.push(newTableName); + statementsToExecute.push(`delete from ${newTableName};`); + + shouldAskForApprove = true; + } + + const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else if (statement.type === 'alter_table_alter_column_set_notnull') { + const tableName = statement.tableName; + + if ( + statement.type === 'alter_table_alter_column_set_notnull' + && typeof statement.columnDefault === 'undefined' + ) { + const res = await connection.query<{ count: string }>( + `select count(*) as count from \`${tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to add not-null constraint to ${ + chalk.underline( + statement.columnName, + ) + } column without default value, which contains ${count} items`, + ); + + tablesToTruncate.push(tableName); + statementsToExecute.push(`delete from \`${tableName}\``); + shouldAskForApprove = true; + } + } + + const modifyStatements = new LibSQLModifyColumn().convert(statement, json2); + + statementsToExecute.push( + ...(Array.isArray(modifyStatements) ? modifyStatements : [modifyStatements]), + ); + } else if (statement.type === 'recreate_table') { + const tableName = statement.tableName; + + const oldTableName = getOldTableName(tableName, meta); + + const prevColumnNames = Object.keys(json1.tables[oldTableName].columns); + const currentColumnNames = Object.keys(json2.tables[tableName].columns); + const { removedColumns, addedColumns } = findAddedAndRemoved( + prevColumnNames, + currentColumnNames, + ); + + if (removedColumns.length) { + for (const removedColumn of removedColumns) { + const res = await connection.query<{ count: string }>( + `select count(\`${tableName}\`.\`${removedColumn}\`) as count from \`${tableName}\``, + ); + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + removedColumn, + ) + } column in ${tableName} table with ${count} items`, + ); + columnsToRemove.push(removedColumn); + shouldAskForApprove = true; + } + } + } + + if (addedColumns.length) { + for (const addedColumn of addedColumns) { + const [res] = await connection.query<{ count: string }>( + `select count(\`${tableName}\`.\`${addedColumn}\`) as count from \`${tableName}\``, + ); + + const columnConf = json2.tables[tableName].columns[addedColumn]; + + const count = Number(res.count); + if (count > 0 && columnConf.notNull && !columnConf.default) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + addedColumn, + ) + } column without default value, which contains ${count} items`, + ); + shouldAskForApprove = true; + tablesToTruncate.push(tableName); + } + } + } + + statementsToExecute.push(..._moveDataStatements(tableName, json2)); + + const tablesReferencingCurrent: string[] = []; + + for (const table of Object.values(json2.tables)) { + const tablesRefs = Object.values(json2.tables[table.name].foreignKeys) + .filter((t) => SQLiteSquasher.unsquashPushFK(t).tableTo === tableName) + .map((it) => SQLiteSquasher.unsquashPushFK(it).tableFrom); + + tablesReferencingCurrent.push(...tablesRefs); + } + + const uniqueTableRefs = [...new Set(tablesReferencingCurrent)]; + + for (const table of uniqueTableRefs) { + statementsToExecute.push(..._moveDataStatements(table, json2)); + } + } else if (statement.type === 'alter_table_alter_column_set_generated') { + const tableName = statement.tableName; + + const res = await connection.query<{ count: string }>( + `select count("${statement.columnName}") as count from \`${tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.columnName, + ) + } column in ${tableName} table with ${count} items`, + ); + columnsToRemove.push(`${tableName}_${statement.columnName}`); + shouldAskForApprove = true; + } + const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else { + const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } + } + + return { + statementsToExecute: [...new Set(statementsToExecute)], + shouldAskForApprove, + infoToPrint, + columnsToRemove: [...new Set(columnsToRemove)], + tablesToTruncate: [...new Set(tablesToTruncate)], + tablesToRemove: [...new Set(tablesToRemove)], + }; +}; diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 8ef469fa1..5fe64ce6c 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -11,12 +11,14 @@ import { import chalk from 'chalk'; import { render } from 'hanji'; import path, { join } from 'path'; +import { JsonStatement } from 'src/jsonStatements'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme } from '../../serializer/mysqlSchema'; import { PgSchema, pgSchema, squashPgScheme } from '../../serializer/pgSchema'; import { SQLiteSchema, sqliteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; import { + applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, applySqliteSnapshotsDiff, @@ -32,7 +34,7 @@ import { } from '../../snapshotsDiffer'; import { assertV1OutFolder, Journal, prepareMigrationFolder } from '../../utils'; import { prepareMigrationMetadata } from '../../utils/words'; -import { Prefix } from '../validations/common'; +import { Driver, Prefix } from '../validations/common'; import { withStyle } from '../validations/outputs'; import { isRenamePromptItem, @@ -394,6 +396,7 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; + const driver = config.driver; try { assertV1OutFolder(outFolder); @@ -425,14 +428,34 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const squashedPrev = squashSqliteScheme(validatedPrev); const squashedCur = squashSqliteScheme(validatedCur); - const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( - squashedPrev, - squashedCur, - tablesResolver, - columnsResolver, - validatedPrev, - validatedCur, - ); + let sqlStatements: string[]; + let _meta: + | { + schemas: {}; + tables: {}; + columns: {}; + } + | undefined; + + if (driver === 'turso') { + ({ sqlStatements, _meta } = await applyLibSQLSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + )); + } else { + ({ sqlStatements, _meta } = await applySqliteSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + )); + } writeResult({ cur, @@ -453,6 +476,57 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { export const prepareSQLitePush = async ( schemaPath: string | string[], snapshot: SQLiteSchema, + driver?: Driver, +) => { + const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath); + + const validatedPrev = sqliteSchema.parse(prev); + const validatedCur = sqliteSchema.parse(cur); + + const squashedPrev = squashSqliteScheme(validatedPrev, 'push'); + const squashedCur = squashSqliteScheme(validatedCur, 'push'); + + let sqlStatements: string[]; + let statements: JsonStatement[]; + let _meta: { + schemas: {}; + tables: {}; + columns: {}; + } | undefined; + if (driver === 'turso') { + ({ sqlStatements, statements, _meta } = await applyLibSQLSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + )); + } else { + ({ sqlStatements, statements, _meta } = await applySqliteSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + )); + } + + return { + sqlStatements, + statements, + squashedPrev, + squashedCur, + meta: _meta, + }; +}; + +export const prepareLibSQLPush = async ( + schemaPath: string | string[], + snapshot: SQLiteSchema, ) => { const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath); @@ -462,7 +536,7 @@ export const prepareSQLitePush = async ( const squashedPrev = squashSqliteScheme(validatedPrev, 'push'); const squashedCur = squashSqliteScheme(validatedCur, 'push'); - const { sqlStatements, statements, _meta } = await applySqliteSnapshotsDiff( + const { sqlStatements, statements, _meta } = await applyLibSQLSnapshotsDiff( squashedPrev, squashedCur, tablesResolver, diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index e48a5da9e..a342f48fc 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -6,6 +6,7 @@ import type { MysqlCredentials } from '../validations/mysql'; import { withStyle } from '../validations/outputs'; import type { PostgresCredentials } from '../validations/postgres'; import type { SqliteCredentials } from '../validations/sqlite'; +import { libSqlLogSuggestionsAndReturn } from './libSqlPushUtils'; import { filterStatements, logSuggestionsAndReturn } from './mysqlPushUtils'; import { pgSuggestions } from './pgPushUtils'; import { logSuggestionsAndReturn as sqliteSuggestions } from './sqlitePushUtils'; @@ -68,8 +69,6 @@ export const mysqlPush = async ( }); if (verbose) { - console.log(); - // console.log(chalk.gray('Verbose logs:')); console.log( withStyle.warning('You are about to execute current statements:'), ); @@ -291,8 +290,128 @@ export const sqlitePush = async ( } = await sqliteSuggestions( db, statements.statements, + statements.squashedPrev, statements.squashedCur, + statements.meta!, + ); + + if (verbose && statementsToExecute.length > 0) { + console.log(); + console.log( + withStyle.warning('You are about to execute current statements:'), + ); + console.log(); + console.log(statementsToExecute.map((s) => chalk.blue(s)).join('\n')); + console.log(); + } + + if (!force && strict) { + if (!shouldAskForApprove) { + const { status, data } = await render( + new Select(['No, abort', `Yes, I want to execute all statements`]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + } + + if (!force && shouldAskForApprove) { + console.log(withStyle.warning('Found data-loss statements:')); + console.log(infoToPrint.join('\n')); + console.log(); + console.log( + chalk.red.bold( + 'THIS ACTION WILL CAUSE DATA LOSS AND CANNOT BE REVERTED\n', + ), + ); + + console.log(chalk.white('Do you still want to push changes?')); + + const { status, data } = await render( + new Select([ + 'No, abort', + `Yes, I want to${ + tablesToRemove.length > 0 + ? ` remove ${tablesToRemove.length} ${tablesToRemove.length > 1 ? 'tables' : 'table'},` + : ' ' + }${ + columnsToRemove.length > 0 + ? ` remove ${columnsToRemove.length} ${columnsToRemove.length > 1 ? 'columns' : 'column'},` + : ' ' + }${ + tablesToTruncate.length > 0 + ? ` truncate ${tablesToTruncate.length} ${tablesToTruncate.length > 1 ? 'tables' : 'table'}` + : '' + }` + .trimEnd() + .replace(/(^,)|(,$)/g, '') + .replace(/ +(?= )/g, ''), + ]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + + if (statementsToExecute.length === 0) { + render(`\n[${chalk.blue('i')}] No changes detected`); + } else { + if (!('driver' in credentials)) { + await db.query('begin'); + try { + for (const dStmnt of statementsToExecute) { + await db.query(dStmnt); + } + await db.query('commit'); + } catch (e) { + console.error(e); + await db.query('rollback'); + process.exit(1); + } + } else if (credentials.driver === 'turso') { + await db.batch!(statementsToExecute.map((it) => ({ query: it }))); + } + render(`[${chalk.green('✓')}] Changes applied`); + } + } +}; + +export const libSQLPush = async ( + schemaPath: string | string[], + verbose: boolean, + strict: boolean, + credentials: SqliteCredentials, + tablesFilter: string[], + force: boolean, +) => { + const { connectToSQLite } = await import('../connections'); + const { sqlitePushIntrospect } = await import('./sqliteIntrospect'); + + const db = await connectToSQLite(credentials); + const { schema } = await sqlitePushIntrospect(db, tablesFilter); + + const { prepareLibSQLPush } = await import('./migrate'); + + const statements = await prepareLibSQLPush(schemaPath, schema); + + if (statements.sqlStatements.length === 0) { + render(`\n[${chalk.blue('i')}] No changes detected`); + } else { + const { + shouldAskForApprove, + statementsToExecute, + columnsToRemove, + tablesToRemove, + tablesToTruncate, + infoToPrint, + } = await libSqlLogSuggestionsAndReturn( + db, + statements.statements, statements.squashedPrev, + statements.squashedCur, statements.meta!, ); diff --git a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts index 451f035a7..e04546157 100644 --- a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts +++ b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts @@ -10,7 +10,7 @@ import { } from '../../sqlgenerator'; import type { JsonStatement } from '../../jsonStatements'; -import type { DB, SQLiteDB } from '../../utils'; +import { findAddedAndRemoved, type SQLiteDB } from '../../utils'; export const _moveDataStatements = ( tableName: string, @@ -51,8 +51,16 @@ export const _moveDataStatements = ( // move data if (!dataLoss) { + const columns = Object.keys(json.tables[tableName].columns).map( + (c) => `"${c}"`, + ); + statements.push( - `INSERT INTO "${tableName}" SELECT * FROM "__old_push_${tableName}";`, + `INSERT INTO \`${tableName}\`(${ + columns.join( + ', ', + ) + }) SELECT (${columns.join(', ')}) FROM \`__old_push_${tableName}\`;`, ); } // drop table with name __old_${tablename} @@ -120,8 +128,6 @@ export const logSuggestionsAndReturn = async ( const schemasToRemove: string[] = []; const tablesToTruncate: string[] = []; - const tablesContext: Record = {}; - for (const statement of statements) { if (statement.type === 'drop_table') { const res = await connection.query<{ count: string }>( @@ -139,248 +145,144 @@ export const logSuggestionsAndReturn = async ( tablesToRemove.push(statement.tableName); shouldAskForApprove = true; } - const stmnt = fromJson([statement], 'sqlite')[0]; - statementsToExecute.push(stmnt); - } else if (statement.type === 'alter_table_drop_column') { - const newTableName = getOldTableName(statement.tableName, meta); - const columnIsPartOfPk = Object.values( - json1.tables[newTableName].compositePrimaryKeys, - ).find((c) => SQLiteSquasher.unsquashPK(c).includes(statement.columnName)); - - const columnIsPartOfIndex = Object.values( - json1.tables[newTableName].indexes, - ).find((c) => SQLiteSquasher.unsquashIdx(c).columns.includes(statement.columnName)); - - const columnIsPk = json1.tables[newTableName].columns[statement.columnName].primaryKey; - - const columnIsPartOfFk = Object.values( - json1.tables[newTableName].foreignKeys, - ).find((t) => - SQLiteSquasher.unsquashPushFK(t).columnsFrom.includes( - statement.columnName, - ) + const fromJsonStatement = fromJson([statement], 'sqlite', 'push'); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); + } else if (statement.type === 'alter_table_drop_column') { + const tableName = statement.tableName; + const columnName = statement.columnName; const res = await connection.query<{ count: string }>( - `select count(*) as count from \`${newTableName}\``, + `select count(\`${tableName}\`.\`${columnName}\`) as count from \`${tableName}\``, ); const count = Number(res[0].count); if (count > 0) { infoToPrint.push( `· You're about to delete ${ chalk.underline( - statement.columnName, + columnName, ) - } column in ${newTableName} table with ${count} items`, + } column in ${tableName} table with ${count} items`, ); - columnsToRemove.push(`${newTableName}_${statement.columnName}`); + columnsToRemove.push(`${tableName}_${statement.columnName}`); shouldAskForApprove = true; } - if ( - columnIsPk - || columnIsPartOfPk - || columnIsPartOfIndex - || columnIsPartOfFk - ) { - tablesContext[newTableName] = [ - ..._moveDataStatements(statement.tableName, json2, true), - ]; - // check table that have fk to this table - - const tablesReferncingCurrent: string[] = []; - - for (const table of Object.values(json1.tables)) { - const tablesRefs = Object.values(json1.tables[table.name].foreignKeys) - .filter( - (t) => SQLiteSquasher.unsquashPushFK(t).tableTo === newTableName, + const fromJsonStatement = fromJson([statement], 'sqlite', 'push'); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else if ( + statement.type === 'sqlite_alter_table_add_column' + && (statement.column.notNull && !statement.column.default) + ) { + const tableName = statement.tableName; + const columnName = statement.column.name; + const res = await connection.query<{ count: string }>( + `select count(*) as count from \`${tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + columnName, ) - .map((t) => SQLiteSquasher.unsquashPushFK(t).tableFrom); - - tablesReferncingCurrent.push(...tablesRefs); - } - - const uniqueTableRefs = [...new Set(tablesReferncingCurrent)]; - - for (const table of uniqueTableRefs) { - if (typeof tablesContext[table] === 'undefined') { - tablesContext[table] = [..._moveDataStatements(table, json2)]; - } - } - } else { - if (typeof tablesContext[newTableName] === 'undefined') { - const stmnt = fromJson([statement], 'sqlite')[0]; - statementsToExecute.push(stmnt); - } - } - } else if (statement.type === 'sqlite_alter_table_add_column') { - const newTableName = getOldTableName(statement.tableName, meta); - if (statement.column.notNull && !statement.column.default) { - const res = await connection.query<{ count: string }>( - `select count(*) as count from \`${newTableName}\``, + } column without default value, which contains ${count} items`, ); - const count = Number(res[0].count); - if (count > 0) { - infoToPrint.push( - `· You're about to add not-null ${ - chalk.underline( - statement.column.name, - ) - } column without default value, which contains ${count} items`, - ); - tablesToTruncate.push(newTableName); - statementsToExecute.push(`delete from ${newTableName};`); + tablesToTruncate.push(tableName); + statementsToExecute.push(`delete from ${tableName};`); - shouldAskForApprove = true; - } + shouldAskForApprove = true; } - if (statement.column.primaryKey) { - tablesContext[newTableName] = [ - ..._moveDataStatements(statement.tableName, json2, true), - ]; - const tablesReferncingCurrent: string[] = []; - - for (const table of Object.values(json1.tables)) { - const tablesRefs = Object.values(json1.tables[table.name].foreignKeys) - .filter( - (t) => SQLiteSquasher.unsquashPushFK(t).tableTo === newTableName, - ) - .map((t) => SQLiteSquasher.unsquashPushFK(t).tableFrom); - tablesReferncingCurrent.push(...tablesRefs); - } - - const uniqueTableRefs = [...new Set(tablesReferncingCurrent)]; + const fromJsonStatement = fromJson([statement], 'sqlite', 'push'); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); + } else if (statement.type === 'recreate_table') { + const tableName = statement.tableName; + const oldTableName = getOldTableName(tableName, meta); + + const prevColumnNames = Object.keys(json1.tables[oldTableName].columns); + const currentColumnNames = Object.keys(json2.tables[tableName].columns); + const { removedColumns, addedColumns } = findAddedAndRemoved( + prevColumnNames, + currentColumnNames, + ); - for (const table of uniqueTableRefs) { - if (typeof tablesContext[table] === 'undefined') { - tablesContext[table] = [..._moveDataStatements(table, json2)]; - } - } - } else { - if (typeof tablesContext[newTableName] === 'undefined') { - const stmnt = fromJson([statement], 'sqlite')[0]; - statementsToExecute.push(stmnt); - } - } - } else if ( - statement.type === 'alter_table_alter_column_set_type' - || statement.type === 'alter_table_alter_column_set_default' - || statement.type === 'alter_table_alter_column_drop_default' - || statement.type === 'alter_table_alter_column_set_notnull' - || statement.type === 'alter_table_alter_column_drop_notnull' - || statement.type === 'alter_table_alter_column_drop_autoincrement' - || statement.type === 'alter_table_alter_column_set_autoincrement' - || statement.type === 'alter_table_alter_column_drop_pk' - || statement.type === 'alter_table_alter_column_set_pk' - ) { - if ( - !( - statement.type === 'alter_table_alter_column_set_notnull' - && statement.columnPk - ) - ) { - const newTableName = getOldTableName(statement.tableName, meta); - if ( - statement.type === 'alter_table_alter_column_set_notnull' - && typeof statement.columnDefault === 'undefined' - ) { + if (removedColumns.length) { + for (const removedColumn of removedColumns) { const res = await connection.query<{ count: string }>( - `select count(*) as count from \`${newTableName}\``, + `select count(\`${tableName}\`.\`${removedColumn}\`) as count from \`${tableName}\``, ); + const count = Number(res[0].count); if (count > 0) { infoToPrint.push( - `· You're about to add not-null constraint to ${ + `· You're about to delete ${ chalk.underline( - statement.columnName, + removedColumn, ) - } column without default value, which contains ${count} items`, + } column in ${tableName} table with ${count} items`, ); - - tablesToTruncate.push(newTableName); + columnsToRemove.push(removedColumn); shouldAskForApprove = true; } - tablesContext[newTableName] = _moveDataStatements( - statement.tableName, - json1, - true, + } + } + + if (addedColumns.length) { + for (const addedColumn of addedColumns) { + const [res] = await connection.query<{ count: string }>( + `select count(*) as count from \`${tableName}\``, ); - } else { - if (typeof tablesContext[newTableName] === 'undefined') { - tablesContext[newTableName] = _moveDataStatements( - statement.tableName, - json1, + + const columnConf = json2.tables[tableName].columns[addedColumn]; + + const count = Number(res.count); + if (count > 0 && columnConf.notNull && !columnConf.default) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + addedColumn, + ) + } column without default value to table, which contains ${count} items`, ); + shouldAskForApprove = true; + tablesToTruncate.push(tableName); } } + } - const tablesReferncingCurrent: string[] = []; + statementsToExecute.push(..._moveDataStatements(tableName, json2)); - for (const table of Object.values(json1.tables)) { - const tablesRefs = Object.values(json1.tables[table.name].foreignKeys) - .filter( - (t) => SQLiteSquasher.unsquashPushFK(t).tableTo === newTableName, - ) - .map((t) => { - return getNewTableName( - SQLiteSquasher.unsquashPushFK(t).tableFrom, - meta, - ); - }); - - tablesReferncingCurrent.push(...tablesRefs); - } + const tablesReferencingCurrent: string[] = []; - const uniqueTableRefs = [...new Set(tablesReferncingCurrent)]; + for (const table of Object.values(json2.tables)) { + const tablesRefs = Object.values(json2.tables[table.name].foreignKeys) + .filter((t) => SQLiteSquasher.unsquashPushFK(t).tableTo === tableName) + .map((it) => SQLiteSquasher.unsquashPushFK(it).tableFrom); - for (const table of uniqueTableRefs) { - if (typeof tablesContext[table] === 'undefined') { - tablesContext[table] = [..._moveDataStatements(table, json1)]; - } - } + tablesReferencingCurrent.push(...tablesRefs); } - } else if ( - statement.type === 'create_reference' - || statement.type === 'delete_reference' - || statement.type === 'alter_reference' - ) { - const fk = SQLiteSquasher.unsquashPushFK(statement.data); - if (typeof tablesContext[statement.tableName] === 'undefined') { - tablesContext[statement.tableName] = _moveDataStatements( - statement.tableName, - json2, - ); - } - } else if ( - statement.type === 'create_composite_pk' - || statement.type === 'alter_composite_pk' - || statement.type === 'delete_composite_pk' - || statement.type === 'create_unique_constraint' - || statement.type === 'delete_unique_constraint' - ) { - const newTableName = getOldTableName(statement.tableName, meta); - if (typeof tablesContext[newTableName] === 'undefined') { - tablesContext[newTableName] = _moveDataStatements( - statement.tableName, - json2, - ); + const uniqueTableRefs = [...new Set(tablesReferencingCurrent)]; + + for (const table of uniqueTableRefs) { + statementsToExecute.push(..._moveDataStatements(table, json2)); } } else { - const stmnt = fromJson([statement], 'sqlite'); - if (typeof stmnt !== 'undefined') { - statementsToExecute.push(...stmnt); - } + const fromJsonStatement = fromJson([statement], 'sqlite', 'push'); + statementsToExecute.push( + ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), + ); } } - for (const context of Object.values(tablesContext)) { - statementsToExecute.push(...context); - } - return { statementsToExecute, shouldAskForApprove, diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 9f65318a6..0ee100ee1 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -122,6 +122,7 @@ export type GenerateConfig = { prefix: Prefix; custom: boolean; bundle: boolean; + driver?: Driver; }; export const prepareGenerateConfig = async ( @@ -168,6 +169,7 @@ export const prepareGenerateConfig = async ( schema: schema, out: out || 'drizzle', bundle: driver === 'expo', + driver, }; }; @@ -210,6 +212,7 @@ export const preparePushConfig = async ( | { dialect: 'sqlite'; credentials: SqliteCredentials; + driver?: Driver; } ) & { schemaPath: string | string[]; @@ -226,6 +229,7 @@ export const preparePushConfig = async ( : options, ); + raw.driver ||= options.driver; raw.verbose ||= options.verbose; // if provided in cli to debug raw.strict ||= options.strict; // if provided in cli only @@ -324,6 +328,7 @@ export const preparePushConfig = async ( credentials: parsed.data, tablesFilter, schemasFilter, + driver: config.driver, }; } diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 642344bda..b7efc65ee 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -278,7 +278,7 @@ export const push = command({ schemasFilter, force, ); - } else if (dialect === 'sqlite') { + } else if (dialect === 'sqlite' && !('driver' in credentials)) { const { sqlitePush } = await import('./commands/push'); await sqlitePush( schemaPath, @@ -288,6 +288,16 @@ export const push = command({ tablesFilter, force, ); + } else if (dialect === 'sqlite' && ('driver' in credentials && credentials.driver === 'turso')) { + const { libSQLPush } = await import('./commands/push'); + await libSQLPush( + schemaPath, + verbose, + strict, + credentials, + tablesFilter, + force, + ); } else { assertUnreachable(dialect); } diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index 67e118a98..2e11b2672 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -1,6 +1,6 @@ import { boolean, intersection, literal, object, string, TypeOf, union } from 'zod'; import { dialect } from '../../schemaValidator'; -import { casing, prefix } from './common'; +import { casing, driver, prefix } from './common'; export const cliConfigGenerate = object({ dialect: dialect.optional(), @@ -25,6 +25,7 @@ export const pushParams = object({ extensionsFilters: literal('postgis').array().optional(), verbose: boolean().optional(), strict: boolean().optional(), + driver: driver, }).passthrough(); export type PushParams = TypeOf; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index ad2afea7f..01da7a129 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -1,10 +1,15 @@ import chalk from 'chalk'; -import { table } from 'console'; +import { getNewTableName, getOldTableName } from './cli/commands/sqlitePushUtils'; import { warning } from './cli/views'; import { CommonSquashedSchema, Dialect } from './schemaValidator'; import { MySqlKitInternals, MySqlSchema, MySqlSquasher } from './serializer/mysqlSchema'; import { Index, PgSchema, PgSquasher } from './serializer/pgSchema'; -import { SQLiteKitInternals, SQLiteSquasher } from './serializer/sqliteSchema'; +import { + SQLiteKitInternals, + SQLiteSchemaInternal, + SQLiteSchemaSquashed, + SQLiteSquasher, +} from './serializer/sqliteSchema'; import { AlteredColumn, Column, Sequence, Table } from './snapshotsDiffer'; export interface JsonSqliteCreateTableStatement { @@ -35,6 +40,23 @@ export interface JsonCreateTableStatement { internals?: MySqlKitInternals; } +export interface JsonRecreateTableStatement { + type: 'recreate_table'; + tableName: string; + columns: Column[]; + referenceData: { + name: string; + tableFrom: string; + columnsFrom: string[]; + tableTo: string; + columnsTo: string[]; + onUpdate?: string | undefined; + onDelete?: string | undefined; + }[]; + compositePKs: string[][]; + uniqueConstraints?: string[]; +} + export interface JsonDropTableStatement { type: 'drop_table'; tableName: string; @@ -173,6 +195,10 @@ export interface JsonReferenceStatement { data: string; schema: string; tableName: string; + isMulticolumn?: boolean; + columnNotNull?: boolean; + columnDefault?: string; + columnType?: string; // fromTable: string; // fromColumns: string[]; // toTable: string; @@ -519,6 +545,7 @@ export type JsonAlterColumnStatement = | JsonAlterColumnDropIdentityStatement; export type JsonStatement = + | JsonRecreateTableStatement | JsonAlterColumnStatement | JsonCreateTableStatement | JsonDropTableStatement @@ -1610,6 +1637,7 @@ export const prepareSqliteAlterColumns = ( columns: AlteredColumn[], // TODO: remove? json2: CommonSquashedSchema, + driver?: 'turso', ): JsonAlterColumnStatement[] => { let statements: JsonAlterColumnStatement[] = []; let dropPkStatements: JsonAlterColumnDropPrimaryKeyStatement[] = []; @@ -1637,6 +1665,55 @@ export const prepareSqliteAlterColumns = ( `${tableName}_${columnName}` ]; + if (column.autoincrement?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'changed') { + const type = column.autoincrement.new + ? 'alter_table_alter_column_set_autoincrement' + : 'alter_table_alter_column_drop_autoincrement'; + + statements.push({ + type, + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + if (typeof column.name !== 'string') { statements.push({ type: 'alter_table_rename_column', @@ -1944,6 +2021,54 @@ export const prepareCreateReferencesJson = ( }; }); }; +export const prepareLibSQLCreateReferencesJson = ( + tableName: string, + schema: string, + foreignKeys: Record, + json2: SQLiteSchemaSquashed, + action?: 'push', +): JsonCreateReferenceStatement[] => { + return Object.values(foreignKeys).map((fkData) => { + const { columnsFrom, tableFrom, columnsTo } = action === 'push' + ? SQLiteSquasher.unsquashPushFK(fkData) + : SQLiteSquasher.unsquashFK(fkData); + + // When trying to alter table in lib sql it is necessary to pass all config for column like "NOT NULL", "DEFAULT", etc. + // If it is multicolumn reference it is not possible to pass this data for all columns + // Pass multicolumn flag for sql statements to not generate migration + let isMulticolumn = false; + + if (columnsFrom.length > 1 || columnsTo.length > 1) { + isMulticolumn = true; + + return { + type: 'create_reference', + tableName, + data: fkData, + schema, + isMulticolumn, + }; + } + + const columnFrom = columnsFrom[0]; + + const { + notNull: columnNotNull, + default: columnDefault, + type: columnType, + } = json2.tables[tableFrom].columns[columnFrom]; + + return { + type: 'create_reference', + tableName, + data: fkData, + schema, + columnNotNull, + columnDefault, + columnType, + }; + }); +}; export const prepareDropReferencesJson = ( tableName: string, @@ -1959,6 +2084,77 @@ export const prepareDropReferencesJson = ( }; }); }; +export const prepareLibSQLDropReferencesJson = ( + tableName: string, + schema: string, + foreignKeys: Record, + json2: SQLiteSchemaSquashed, + meta: SQLiteSchemaInternal['_meta'], + action?: 'push', +): JsonDeleteReferenceStatement[] => { + const statements = Object.values(foreignKeys).map((fkData) => { + const { columnsFrom, tableFrom, columnsTo, name, tableTo, onDelete, onUpdate } = action === 'push' + ? SQLiteSquasher.unsquashPushFK(fkData) + : SQLiteSquasher.unsquashFK(fkData); + + // If all columns from where were references were deleted -> skip this logic + // Drop colums will cover this scenario + const keys = Object.keys(json2.tables[tableName].columns); + const filtered = columnsFrom.filter((it) => keys.includes(it)); + const fullDrop = filtered.length === 0; + if (fullDrop) return; + + // When trying to alter table in lib sql it is necessary to pass all config for column like "NOT NULL", "DEFAULT", etc. + // If it is multicolumn reference it is not possible to pass this data for all columns + // Pass multicolumn flag for sql statements to not generate migration + let isMulticolumn = false; + + if (columnsFrom.length > 1 || columnsTo.length > 1) { + isMulticolumn = true; + + return { + type: 'delete_reference', + tableName, + data: fkData, + schema, + isMulticolumn, + }; + } + + const columnFrom = columnsFrom[0]; + const newTableName = getNewTableName(tableFrom, meta); + + const { + notNull: columnNotNull, + default: columnDefault, + type: columnType, + } = json2.tables[newTableName].columns[columnFrom]; + + const fkToSquash = { + columnsFrom, + columnsTo, + name, + tableFrom: newTableName, + tableTo, + onDelete, + onUpdate, + }; + const foreignKey = action === 'push' + ? SQLiteSquasher.squashPushFK(fkToSquash) + : SQLiteSquasher.squashFK(fkToSquash); + return { + type: 'delete_reference', + tableName, + data: foreignKey, + schema, + columnNotNull, + columnDefault, + columnType, + }; + }); + + return statements.filter((it) => it) as JsonDeleteReferenceStatement[]; +}; // alter should create 2 statements. It's important to make only 1 sql per statement(for breakpoints) export const prepareAlterReferencesJson = ( diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 9ad2d9e32..0978f5695 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -60,6 +60,8 @@ import { prepareDropReferencesJson, prepareDropSequenceJson, prepareDropTableJson, + prepareLibSQLCreateReferencesJson, + prepareLibSQLDropReferencesJson, prepareMoveEnumJson, prepareMoveSequenceJson, prepareMySqlCreateTableJson, @@ -78,8 +80,9 @@ import { import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher } from './serializer/mysqlSchema'; -import { PgSchema, PgSchemaSquashed, PgSquasher, sequenceSchema, sequenceSquashed } from './serializer/pgSchema'; +import { PgSchema, PgSchemaSquashed, sequenceSquashed } from './serializer/pgSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; +import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; import { copy, prepareMigrationMeta } from './utils'; const makeChanged = (schema: T) => { @@ -2044,7 +2047,8 @@ export const applySqliteSnapshotsDiff = async ( jsonStatements.push(...jsonAlteredUniqueConstraints); - const sqlStatements = fromJson(jsonStatements, 'sqlite'); + const combinedJsonStatements = sqliteCombineStatements(jsonStatements, json2, action); + const sqlStatements = fromJson(combinedJsonStatements, 'sqlite'); const uniqueSqlStatements: string[] = []; sqlStatements.forEach((ss) => { @@ -2060,7 +2064,429 @@ export const applySqliteSnapshotsDiff = async ( const _meta = prepareMigrationMeta([], rTables, rColumns); return { - statements: jsonStatements, + statements: combinedJsonStatements, + sqlStatements: uniqueSqlStatements, + _meta, + }; +}; + +export const applyLibSQLSnapshotsDiff = async ( + json1: SQLiteSchemaSquashed, + json2: SQLiteSchemaSquashed, + tablesResolver: ( + input: ResolverInput, + ) => Promise>, + columnsResolver: ( + input: ColumnsResolverInput, + ) => Promise>, + prevFull: SQLiteSchema, + curFull: SQLiteSchema, + action?: 'push', +): Promise<{ + statements: JsonStatement[]; + sqlStatements: string[]; + _meta: + | { + schemas: {}; + tables: {}; + columns: {}; + } + | undefined; +}> => { + const tablesDiff = diffSchemasOrTables(json1.tables, json2.tables); + const { + created: createdTables, + deleted: deletedTables, + renamed: renamedTables, + } = await tablesResolver({ + created: tablesDiff.added, + deleted: tablesDiff.deleted, + }); + + const tablesPatchedSnap1 = copy(json1); + tablesPatchedSnap1.tables = mapEntries(tablesPatchedSnap1.tables, (_, it) => { + const { name } = nameChangeFor(it, renamedTables); + it.name = name; + return [name, it]; + }); + + const res = diffColumns(tablesPatchedSnap1.tables, json2.tables); + + const columnRenames = [] as { + table: string; + renames: { from: Column; to: Column }[]; + }[]; + + const columnCreates = [] as { + table: string; + columns: Column[]; + }[]; + + const columnDeletes = [] as { + table: string; + columns: Column[]; + }[]; + + for (let entry of Object.values(res)) { + const { renamed, created, deleted } = await columnsResolver({ + tableName: entry.name, + schema: entry.schema, + deleted: entry.columns.deleted, + created: entry.columns.added, + }); + + if (created.length > 0) { + columnCreates.push({ + table: entry.name, + columns: created, + }); + } + + if (deleted.length > 0) { + columnDeletes.push({ + table: entry.name, + columns: deleted, + }); + } + + if (renamed.length > 0) { + columnRenames.push({ + table: entry.name, + renames: renamed, + }); + } + } + + const columnRenamesDict = columnRenames.reduce( + (acc, it) => { + acc[it.table] = it.renames; + return acc; + }, + {} as Record< + string, + { + from: Named; + to: Named; + }[] + >, + ); + + const columnsPatchedSnap1 = copy(tablesPatchedSnap1); + columnsPatchedSnap1.tables = mapEntries( + columnsPatchedSnap1.tables, + (tableKey, tableValue) => { + const patchedColumns = mapKeys( + tableValue.columns, + (columnKey, column) => { + const rens = columnRenamesDict[tableValue.name] || []; + const newName = columnChangeFor(columnKey, rens); + column.name = newName; + return newName; + }, + ); + + tableValue.columns = patchedColumns; + return [tableKey, tableValue]; + }, + ); + + const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + + const typedResult = diffResultSchemeSQLite.parse(diffResult); + + // Map array of objects to map + const tablesMap: { + [key: string]: (typeof typedResult.alteredTablesWithColumns)[number]; + } = {}; + + typedResult.alteredTablesWithColumns.forEach((obj) => { + tablesMap[obj.name] = obj; + }); + + const jsonCreateTables = createdTables.map((it) => { + return prepareSQLiteCreateTable(it, action); + }); + + const jsonCreateIndexesForCreatedTables = createdTables + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.indexes, + curFull.internal, + ); + }) + .flat(); + + const jsonDropTables = deletedTables.map((it) => { + return prepareDropTableJson(it); + }); + + const jsonRenameTables = renamedTables.map((it) => { + return prepareRenameTableJson(it.from, it.to); + }); + + const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames + .map((it) => prepareRenameColumns(it.table, '', it.renames)) + .flat(); + + const jsonDropColumnsStatemets: JsonDropColumnStatement[] = columnDeletes + .map((it) => _prepareDropColumns(it.table, '', it.columns)) + .flat(); + + const jsonAddColumnsStatemets: JsonSqliteAddColumnStatement[] = columnCreates + .map((it) => { + return _prepareSqliteAddColumns( + it.table, + it.columns, + tablesMap[it.table] && tablesMap[it.table].addedForeignKeys + ? Object.values(tablesMap[it.table].addedForeignKeys) + : [], + ); + }) + .flat(); + + const rColumns = jsonRenameColumnsStatements.map((it) => { + const tableName = it.tableName; + const schema = it.schema; + return { + from: { schema, table: tableName, column: it.oldColumnName }, + to: { schema, table: tableName, column: it.newColumnName }, + }; + }); + + const rTables = renamedTables.map((it) => { + return { from: it.from, to: it.to }; + }); + + const _meta = prepareMigrationMeta([], rTables, rColumns); + + const allAltered = typedResult.alteredTablesWithColumns; + + const jsonAddedCompositePKs: JsonCreateCompositePK[] = []; + const jsonDeletedCompositePKs: JsonDeleteCompositePK[] = []; + const jsonAlteredCompositePKs: JsonAlterCompositePK[] = []; + + const jsonAddedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + allAltered.forEach((it) => { + // This part is needed to make sure that same columns in a table are not triggered for change + // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name + // We double-check that pk with same set of columns are both in added and deleted diffs + let addedColumns: string[] = []; + for (const addedPkName of Object.keys(it.addedCompositePKs)) { + const addedPkColumns = it.addedCompositePKs[addedPkName]; + addedColumns = SQLiteSquasher.unsquashPK(addedPkColumns); + } + + let deletedColumns: string[] = []; + for (const deletedPkName of Object.keys(it.deletedCompositePKs)) { + const deletedPkColumns = it.deletedCompositePKs[deletedPkName]; + deletedColumns = SQLiteSquasher.unsquashPK(deletedPkColumns); + } + + // Don't need to sort, but need to add tests for it + // addedColumns.sort(); + // deletedColumns.sort(); + + const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); + + let addedCompositePKs: JsonCreateCompositePK[] = []; + let deletedCompositePKs: JsonDeleteCompositePK[] = []; + let alteredCompositePKs: JsonAlterCompositePK[] = []; + if (doPerformDeleteAndCreate) { + addedCompositePKs = prepareAddCompositePrimaryKeySqlite( + it.name, + it.addedCompositePKs, + ); + deletedCompositePKs = prepareDeleteCompositePrimaryKeySqlite( + it.name, + it.deletedCompositePKs, + ); + } + alteredCompositePKs = prepareAlterCompositePrimaryKeySqlite( + it.name, + it.alteredCompositePKs, + ); + + // add logic for unique constraints + let addedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + addedUniqueConstraints = prepareAddUniqueConstraint( + it.name, + it.schema, + it.addedUniqueConstraints, + ); + + deletedUniqueConstraints = prepareDeleteUniqueConstraint( + it.name, + it.schema, + it.deletedUniqueConstraints, + ); + if (it.alteredUniqueConstraints) { + const added: Record = {}; + const deleted: Record = {}; + for (const k of Object.keys(it.alteredUniqueConstraints)) { + added[k] = it.alteredUniqueConstraints[k].__new; + deleted[k] = it.alteredUniqueConstraints[k].__old; + } + addedUniqueConstraints.push( + ...prepareAddUniqueConstraint(it.name, it.schema, added), + ); + deletedUniqueConstraints.push( + ...prepareDeleteUniqueConstraint(it.name, it.schema, deleted), + ); + } + + jsonAddedCompositePKs.push(...addedCompositePKs); + jsonDeletedCompositePKs.push(...deletedCompositePKs); + jsonAlteredCompositePKs.push(...alteredCompositePKs); + + jsonAddedUniqueConstraints.push(...addedUniqueConstraints); + jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); + jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + }); + + const jsonTableAlternations = allAltered + .map((it) => { + return prepareSqliteAlterColumns(it.name, it.schema, it.altered, json2); + }) + .flat(); + + const jsonCreateIndexesForAllAlteredTables = allAltered + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.addedIndexes || {}, + curFull.internal, + ); + }) + .flat(); + + const jsonDropIndexesForAllAlteredTables = allAltered + .map((it) => { + return prepareDropIndexesJson( + it.name, + it.schema, + it.deletedIndexes || {}, + ); + }) + .flat(); + + allAltered.forEach((it) => { + const droppedIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__old; + return current; + }, + {} as Record, + ); + const createdIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__new; + return current; + }, + {} as Record, + ); + + jsonCreateIndexesForAllAlteredTables.push( + ...prepareCreateIndexesJson( + it.name, + it.schema, + createdIndexes || {}, + curFull.internal, + ), + ); + jsonDropIndexesForAllAlteredTables.push( + ...prepareDropIndexesJson(it.name, it.schema, droppedIndexes || {}), + ); + }); + + const jsonReferencesForAllAlteredTables: JsonReferenceStatement[] = allAltered + .map((it) => { + const forAdded = prepareLibSQLCreateReferencesJson( + it.name, + it.schema, + it.addedForeignKeys, + json2, + action, + ); + + const forAltered = prepareLibSQLDropReferencesJson( + it.name, + it.schema, + it.deletedForeignKeys, + json2, + _meta, + action, + ); + + const alteredFKs = prepareAlterReferencesJson(it.name, it.schema, it.alteredForeignKeys); + + return [...forAdded, ...forAltered, ...alteredFKs]; + }) + .flat(); + + const jsonCreatedReferencesForAlteredTables = jsonReferencesForAllAlteredTables.filter( + (t) => t.type === 'create_reference', + ); + const jsonDroppedReferencesForAlteredTables = jsonReferencesForAllAlteredTables.filter( + (t) => t.type === 'delete_reference', + ); + + const jsonStatements: JsonStatement[] = []; + jsonStatements.push(...jsonCreateTables); + + jsonStatements.push(...jsonDropTables); + jsonStatements.push(...jsonRenameTables); + jsonStatements.push(...jsonRenameColumnsStatements); + + jsonStatements.push(...jsonDroppedReferencesForAlteredTables); + + // Will need to drop indexes before changing any columns in table + // Then should go column alternations and then index creation + jsonStatements.push(...jsonDropIndexesForAllAlteredTables); + + jsonStatements.push(...jsonDeletedCompositePKs); + jsonStatements.push(...jsonTableAlternations); + jsonStatements.push(...jsonAddedCompositePKs); + jsonStatements.push(...jsonAddColumnsStatemets); + + jsonStatements.push(...jsonCreateIndexesForCreatedTables); + jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); + + jsonStatements.push(...jsonCreatedReferencesForAlteredTables); + + jsonStatements.push(...jsonDropColumnsStatemets); + + jsonStatements.push(...jsonAlteredCompositePKs); + + jsonStatements.push(...jsonAlteredUniqueConstraints); + + const combinedJsonStatements = libSQLCombineStatements(jsonStatements, json2, action); + + const sqlStatements = fromJson( + combinedJsonStatements, + 'sqlite', + action, + 'turso', + json2, + ); + + const uniqueSqlStatements: string[] = []; + sqlStatements.forEach((ss) => { + if (!uniqueSqlStatements.includes(ss)) { + uniqueSqlStatements.push(ss); + } + }); + + return { + statements: combinedJsonStatements, sqlStatements: uniqueSqlStatements, _meta, }; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 769da7c5a..179ca4176 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -1,4 +1,5 @@ import { BREAKPOINT } from './cli/commands/migrate'; +import { Driver } from './cli/validations/common'; import { JsonAddColumnStatement, JsonAddValueToEnumStatement, @@ -25,7 +26,6 @@ import { JsonAlterTableRemoveFromSchema, JsonAlterTableSetNewSchema, JsonAlterTableSetSchema, - JsonAlterUniqueConstraint, JsonCreateCompositePK, JsonCreateEnumStatement, JsonCreateIndexStatement, @@ -43,6 +43,7 @@ import { JsonDropTableStatement, JsonMoveSequenceStatement, JsonPgCreateIndexStatement, + JsonRecreateTableStatement, JsonRenameColumnStatement, JsonRenameSchema, JsonRenameSequenceStatement, @@ -54,7 +55,7 @@ import { import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; import { PgSquasher } from './serializer/pgSchema'; -import { SQLiteSquasher } from './serializer/sqliteSchema'; +import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; export const pgNativeTypes = new Set([ 'uuid', @@ -126,8 +127,16 @@ const isPgNativeType = (it: string) => { }; abstract class Convertor { - abstract can(statement: JsonStatement, dialect: Dialect): boolean; - abstract convert(statement: JsonStatement): string | string[]; + abstract can( + statement: JsonStatement, + dialect: Dialect, + driver?: Driver, + ): boolean; + abstract convert( + statement: JsonStatement, + json2?: SQLiteSchemaSquashed, + action?: 'push', + ): string | string[]; } class PgCreateTableConvertor extends Convertor { @@ -866,7 +875,7 @@ class SQLiteAlterTableRenameColumnConvertor extends Convertor { convert(statement: JsonRenameColumnStatement) { const { tableName, oldColumnName, newColumnName } = statement; - return `ALTER TABLE \`${tableName}\` RENAME COLUMN \`${oldColumnName}\` TO \`${newColumnName}\`;`; + return `ALTER TABLE \`${tableName}\` RENAME COLUMN "${oldColumnName}" TO "${newColumnName}";`; } } @@ -1061,10 +1070,11 @@ class PgAlterTableAlterColumnSetTypeConvertor extends Convertor { } class SQLiteAlterTableAlterColumnSetTypeConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( statement.type === 'alter_table_alter_column_set_type' && dialect === 'sqlite' + && !driver ); } @@ -1503,6 +1513,119 @@ class MySqlAlterTableDropPk extends Convertor { } } +type LibSQLModifyColumnStatement = + | JsonAlterColumnTypeStatement + | JsonAlterColumnDropNotNullStatement + | JsonAlterColumnSetNotNullStatement + | JsonAlterColumnSetDefaultStatement + | JsonAlterColumnDropDefaultStatement + | JsonAlterColumnSetGeneratedStatement + | JsonAlterColumnDropGeneratedStatement; + +export class LibSQLModifyColumn extends Convertor { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + (statement.type === 'alter_table_alter_column_set_type' + || statement.type === 'alter_table_alter_column_drop_notnull' + || statement.type === 'alter_table_alter_column_set_notnull' + || statement.type === 'alter_table_alter_column_set_default' + || statement.type === 'alter_table_alter_column_drop_default') + && dialect === 'sqlite' + && driver === 'turso' + ); + } + + convert(statement: LibSQLModifyColumnStatement, json2: SQLiteSchemaSquashed) { + const { tableName, columnName } = statement; + + let columnType = ``; + let columnDefault: any = ''; + let columnNotNull = ''; + + switch (statement.type) { + case 'alter_table_alter_column_set_type': + columnType = ` ${statement.newDataType}`; + + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + + break; + case 'alter_table_alter_column_drop_notnull': + columnType = ` ${statement.newDataType}`; + + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + + columnNotNull = ''; + break; + case 'alter_table_alter_column_set_notnull': + columnType = ` ${statement.newDataType}`; + + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + + columnNotNull = ` NOT NULL`; + break; + case 'alter_table_alter_column_set_default': + columnType = ` ${statement.newDataType}`; + + columnDefault = ` DEFAULT ${statement.newDefaultValue}`; + + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + break; + case 'alter_table_alter_column_drop_default': + columnType = ` ${statement.newDataType}`; + + columnDefault = ''; + + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + break; + case 'alter_table_alter_column_drop_generated': + columnType = ` ${statement.newDataType}`; + + columnDefault = ''; + + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + break; + case 'alter_table_alter_column_set_generated': + return [ + new SQLiteAlterTableDropColumnConvertor().convert({ + type: 'alter_table_drop_column', + tableName: statement.tableName, + columnName: statement.columnName, + schema: '', + }), + new SQLiteAlterTableAddColumnConvertor().convert({ + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull: statement.columnNotNull, + default: statement.columnDefault, + onUpdate: statement.columnOnUpdate, + autoincrement: statement.columnAutoIncrement, + primaryKey: statement.columnPk, + generated: statement.columnGenerated, + }, + type: 'sqlite_alter_table_add_column', + }), + ]; + } + + // Seems like getting value from simple json2 shanpshot makes dates be dates + columnDefault = columnDefault instanceof Date + ? columnDefault.toISOString() + : columnDefault; + + return `ALTER TABLE \`${tableName}\` ALTER COLUMN "${columnName}" TO "${columnName}"${columnType}${columnNotNull}${columnDefault};`; + } +} + type MySqlModifyColumnStatement = | JsonAlterColumnDropNotNullStatement | JsonAlterColumnSetNotNullStatement @@ -1775,7 +1898,6 @@ class PgAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { }");`; } } - class PgAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'delete_composite_pk' && dialect === 'postgresql'; @@ -2000,10 +2122,11 @@ class PgAlterTableAlterColumnSetNotNullConvertor extends Convertor { } class SqliteAlterTableAlterColumnSetNotNullConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( statement.type === 'alter_table_alter_column_set_notnull' && dialect === 'sqlite' + && !driver ); } @@ -2020,10 +2143,11 @@ class SqliteAlterTableAlterColumnSetNotNullConvertor extends Convertor { } class SqliteAlterTableAlterColumnSetAutoincrementConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( statement.type === 'alter_table_alter_column_set_autoincrement' && dialect === 'sqlite' + && !driver ); } @@ -2040,10 +2164,11 @@ class SqliteAlterTableAlterColumnSetAutoincrementConvertor extends Convertor { } class SqliteAlterTableAlterColumnDropAutoincrementConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( statement.type === 'alter_table_alter_column_drop_autoincrement' && dialect === 'sqlite' + && !driver ); } @@ -2079,10 +2204,11 @@ class PgAlterTableAlterColumnDropNotNullConvertor extends Convertor { } class SqliteAlterTableAlterColumnDropNotNullConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( statement.type === 'alter_table_alter_column_drop_notnull' && dialect === 'sqlite' + && !driver ); } @@ -2141,8 +2267,10 @@ class PgCreateForeignKeyConvertor extends Convertor { } class SqliteCreateForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_reference' && dialect === 'sqlite'; + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'create_reference' && dialect === 'sqlite' && !driver + ); } convert(statement: JsonCreateReferenceStatement): string { @@ -2156,6 +2284,50 @@ class SqliteCreateForeignKeyConvertor extends Convertor { } } +class LibSQLCreateForeignKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'create_reference' + && dialect === 'sqlite' + && driver === 'turso' + ); + } + + convert( + statement: JsonCreateReferenceStatement, + json2?: SQLiteSchemaSquashed, + action?: 'push', + ): string { + const { columnsFrom, columnsTo, tableFrom, onDelete, onUpdate, tableTo } = action === 'push' + ? SQLiteSquasher.unsquashPushFK(statement.data) + : SQLiteSquasher.unsquashFK(statement.data); + const { columnDefault, columnNotNull, columnType, isMulticolumn } = statement; + + if (isMulticolumn) { + return ( + '/*\n LibSQL does not support "Creating foreign key on multiple columns" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' + ); + } + + const onDeleteStatement = onDelete ? ` ON DELETE ${onDelete}` : ''; + const onUpdateStatement = onUpdate ? ` ON UPDATE ${onUpdate}` : ''; + const columnsDefaultValue = columnDefault + ? ` DEFAULT ${columnDefault}` + : ''; + const columnNotNullValue = columnNotNull ? ` NOT NULL` : ''; + const columnTypeValue = columnType ? ` ${columnType}` : ''; + + const columnFrom = columnsFrom[0]; + const columnTo = columnsTo[0]; + + return `ALTER TABLE \`${tableFrom}\` ALTER COLUMN "${columnFrom}" TO "${columnFrom}"${columnTypeValue}${columnNotNullValue}${columnsDefaultValue} REFERENCES ${tableTo}(${columnTo})${onDeleteStatement}${onUpdateStatement};`; + } +} + class MySqlCreateForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_reference' && dialect === 'mysql'; @@ -2261,8 +2433,10 @@ class PgDeleteForeignKeyConvertor extends Convertor { } class SqliteDeleteForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'delete_reference' && dialect === 'sqlite'; + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'delete_reference' && dialect === 'sqlite' && !driver + ); } convert(statement: JsonDeleteReferenceStatement): string { @@ -2276,6 +2450,48 @@ class SqliteDeleteForeignKeyConvertor extends Convertor { } } +class LibSQLDeleteForeignKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'delete_reference' + && dialect === 'sqlite' + && driver === 'turso' + ); + } + + convert( + statement: JsonDeleteReferenceStatement, + json2?: SQLiteSchemaSquashed, + action?: 'push', + ): string { + const { columnsFrom, tableFrom } = action === 'push' + ? SQLiteSquasher.unsquashPushFK(statement.data) + : SQLiteSquasher.unsquashFK(statement.data); + + const { columnDefault, columnNotNull, columnType, isMulticolumn } = statement; + + if (isMulticolumn) { + return ( + '/*\n LibSQL does not support "Creating foreign key on multiple columns" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' + ); + } + + const columnsDefaultValue = columnDefault + ? ` DEFAULT ${columnDefault}` + : ''; + const columnNotNullValue = columnNotNull ? ` NOT NULL` : ''; + const columnTypeValue = columnType ? ` ${columnType}` : ''; + + const columnFrom = columnsFrom[0]; + + return `ALTER TABLE \`${tableFrom}\` ALTER COLUMN "${columnFrom}" TO "${columnFrom}"${columnTypeValue}${columnNotNullValue}${columnsDefaultValue};`; + } +} + class MySqlDeleteForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'delete_reference' && dialect === 'mysql'; @@ -2513,10 +2729,122 @@ class MySqlDropIndexConvertor extends Convertor { } } +class SQLiteRecreateTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'recreate_table' && dialect === 'sqlite' && !driver + ); + } + + convert(statement: JsonRecreateTableStatement): string | string[] { + const { tableName, columns, compositePKs, referenceData } = statement; + + const columnNames = columns.map((it) => `"${it.name}"`).join(', '); + + const sqlStatements: string[] = []; + + // rename table + sqlStatements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: tableName, + tableNameTo: `__old__generate_${tableName}`, + toSchema: '', + type: 'rename_table', + }), + ); + + // create new table + sqlStatements.push( + new SQLiteCreateTableConvertor().convert({ + type: 'sqlite_create_table', + tableName, + columns, + referenceData, + compositePKs, + }), + ); + + // migrate data + sqlStatements.push( + `INSERT INTO \`${tableName}\`(${columnNames}) SELECT ${columnNames} FROM \`__old__generate_${tableName}\`;`, + ); + + // migrate data + sqlStatements.push( + new SQLiteDropTableConvertor().convert({ + type: 'drop_table', + tableName: `__old__generate_${tableName}`, + schema: '', + }), + ); + + return sqlStatements; + } +} + +class LibSQLRecreateTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + return ( + statement.type === 'recreate_table' + && dialect === 'sqlite' + && driver === 'turso' + ); + } + + convert(statement: JsonRecreateTableStatement): string[] { + const { tableName, columns, compositePKs, referenceData } = statement; + + const columnNames = columns.map((it) => `"${it.name}"`).join(', '); + + const sqlStatements: string[] = []; + + // rename table + sqlStatements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: tableName, + tableNameTo: `__old__generate_${tableName}`, + toSchema: '', + type: 'rename_table', + }), + ); + + // create new table + sqlStatements.push( + new SQLiteCreateTableConvertor().convert({ + type: 'sqlite_create_table', + tableName, + columns, + referenceData, + compositePKs, + }), + ); + + // migrate data + sqlStatements.push( + `INSERT INTO \`${tableName}\`(${columnNames}) SELECT ${columnNames} FROM \`__old__generate_${tableName}\`;`, + ); + + // migrate data + sqlStatements.push( + new SQLiteDropTableConvertor().convert({ + type: 'drop_table', + tableName: `__old__generate_${tableName}`, + schema: '', + }), + ); + + return sqlStatements; + } +} + const convertors: Convertor[] = []; convertors.push(new PgCreateTableConvertor()); convertors.push(new MySqlCreateTableConvertor()); convertors.push(new SQLiteCreateTableConvertor()); +convertors.push(new SQLiteRecreateTableConvertor()); +convertors.push(new LibSQLRecreateTableConvertor()); convertors.push(new CreateTypeEnumConvertor()); @@ -2583,6 +2911,7 @@ convertors.push(new SqliteAlterTableAlterColumnAlterGeneratedConvertor()); convertors.push(new SqliteAlterTableAlterColumnSetExpressionConvertor()); convertors.push(new MySqlModifyColumn()); +convertors.push(new LibSQLModifyColumn()); // convertors.push(new MySqlAlterTableAlterColumnSetDefaultConvertor()); // convertors.push(new MySqlAlterTableAlterColumnDropDefaultConvertor()); @@ -2605,7 +2934,9 @@ convertors.push(new PgAlterTableRemoveFromSchemaConvertor()); convertors.push(new SQLiteAlterTableAlterColumnSetTypeConvertor()); convertors.push(new SqliteAlterForeignKeyConvertor()); convertors.push(new SqliteDeleteForeignKeyConvertor()); +convertors.push(new LibSQLDeleteForeignKeyConvertor()); convertors.push(new SqliteCreateForeignKeyConvertor()); +convertors.push(new LibSQLCreateForeignKeyConvertor()); convertors.push(new SQLiteAlterTableAddUniqueConstraintConvertor()); convertors.push(new SQLiteAlterTableDropUniqueConstraintConvertor()); @@ -2636,26 +2967,43 @@ convertors.push(new MySqlAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new MySqlAlterTableAddPk()); convertors.push(new MySqlAlterTableAlterCompositePrimaryKeyConvertor()); -export const fromJson = (statements: JsonStatement[], dialect: Dialect) => { +// overloads for turso driver +export function fromJson( + statements: JsonStatement[], + dialect: Exclude, +): string[]; +export function fromJson( + statements: JsonStatement[], + dialect: 'sqlite', + action?: 'push', + driver?: Driver, + json2?: SQLiteSchemaSquashed, +): string[]; + +export function fromJson( + statements: JsonStatement[], + dialect: Dialect, + action?: 'push', + driver?: Driver, + json2?: SQLiteSchemaSquashed, +) { const result = statements .flatMap((statement) => { const filtered = convertors.filter((it) => { - // console.log(statement, dialect) - return it.can(statement, dialect); + return it.can(statement, dialect, driver); }); const convertor = filtered.length === 1 ? filtered[0] : undefined; if (!convertor) { - // console.log("no convertor:", statement.type, dialect); return ''; } - return convertor.convert(statement); + return convertor.convert(statement, json2, action); }) .filter((it) => it !== ''); return result; -}; +} // blog.yo1.dog/updating-enum-values-in-postgresql-the-safe-and-easy-way/ // test case for enum altering diff --git a/drizzle-kit/src/statementCombiner.ts b/drizzle-kit/src/statementCombiner.ts new file mode 100644 index 000000000..21cc86b38 --- /dev/null +++ b/drizzle-kit/src/statementCombiner.ts @@ -0,0 +1,387 @@ +import { + JsonCreateIndexStatement, + JsonRecreateTableStatement, + JsonStatement, + prepareCreateIndexesJson, +} from './jsonStatements'; +import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; + +export const prepareLibSQLRecreateTable = ( + table: SQLiteSchemaSquashed['tables'][keyof SQLiteSchemaSquashed['tables']], + action?: 'push', +): (JsonRecreateTableStatement | JsonCreateIndexStatement)[] => { + const { name, columns, uniqueConstraints, indexes } = table; + + const composites: string[][] = Object.values(table.compositePrimaryKeys).map( + (it) => SQLiteSquasher.unsquashPK(it), + ); + + const references: string[] = Object.values(table.foreignKeys); + const fks = references.map((it) => + action === 'push' ? SQLiteSquasher.unsquashPushFK(it) : SQLiteSquasher.unsquashFK(it) + ); + + const statements: (JsonRecreateTableStatement | JsonCreateIndexStatement)[] = [ + { + type: 'recreate_table', + tableName: name, + columns: Object.values(columns), + compositePKs: composites, + referenceData: fks, + uniqueConstraints: Object.values(uniqueConstraints), + }, + ]; + + if (Object.keys(indexes).length) { + statements.push(...prepareCreateIndexesJson(name, '', indexes)); + } + return statements; +}; + +export const prepareSQLiteRecreateTable = ( + table: SQLiteSchemaSquashed['tables'][keyof SQLiteSchemaSquashed['tables']], + action?: 'push', +): JsonStatement[] => { + const { name, columns, uniqueConstraints, indexes } = table; + + const composites: string[][] = Object.values(table.compositePrimaryKeys).map( + (it) => SQLiteSquasher.unsquashPK(it), + ); + + const references: string[] = Object.values(table.foreignKeys); + const fks = references.map((it) => + action === 'push' ? SQLiteSquasher.unsquashPushFK(it) : SQLiteSquasher.unsquashFK(it) + ); + + const statements: JsonStatement[] = [ + { + type: 'recreate_table', + tableName: name, + columns: Object.values(columns), + compositePKs: composites, + referenceData: fks, + uniqueConstraints: Object.values(uniqueConstraints), + }, + ]; + + if (Object.keys(indexes).length) { + statements.push(...prepareCreateIndexesJson(name, '', indexes)); + } + return statements; +}; + +export const libSQLCombineStatements = ( + statements: JsonStatement[], + json2: SQLiteSchemaSquashed, + action?: 'push', +) => { + // const tablesContext: Record = {}; + const newStatements: Record = {}; + for (const statement of statements) { + if ( + statement.type === 'alter_table_alter_column_drop_autoincrement' + || statement.type === 'alter_table_alter_column_set_autoincrement' + || statement.type === 'alter_table_alter_column_drop_pk' + || statement.type === 'alter_table_alter_column_set_pk' + || statement.type === 'create_composite_pk' + || statement.type === 'alter_composite_pk' + || statement.type === 'delete_composite_pk' + ) { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + if ( + statement.type === 'alter_table_alter_column_set_type' + || statement.type === 'alter_table_alter_column_drop_notnull' + || statement.type === 'alter_table_alter_column_set_notnull' + || statement.type === 'alter_table_alter_column_set_default' + || statement.type === 'alter_table_alter_column_drop_default' + ) { + const { tableName, columnName, columnPk } = statement; + + const columnIsPartOfUniqueIndex = Object.values( + json2.tables[tableName].indexes, + ).some((it) => { + const unsquashIndex = SQLiteSquasher.unsquashIdx(it); + + return ( + unsquashIndex.columns.includes(columnName) && unsquashIndex.isUnique + ); + }); + + const columnIsPartOfForeignKey = Object.values( + json2.tables[tableName].foreignKeys, + ).some((it) => { + const unsquashFk = action === 'push' ? SQLiteSquasher.unsquashPushFK(it) : SQLiteSquasher.unsquashFK(it); + + return ( + unsquashFk.columnsFrom.includes(columnName) + ); + }); + + const statementsForTable = newStatements[tableName]; + + if ( + !statementsForTable && (columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + ) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if ( + statementsForTable && (columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + ) { + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + } + continue; + } + if ( + statementsForTable && !(columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + ) { + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + newStatements[tableName].push(statement); + } + continue; + } + + newStatements[tableName] = [statement]; + + continue; + } + + if (statement.type === 'create_reference' && statement.isMulticolumn) { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + if (statement.type === 'delete_reference') { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + if (statement.type === 'sqlite_alter_table_add_column' && statement.column.primaryKey) { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + const tableName = statement.type === 'rename_table' + ? statement.tableNameTo + : (statement as { tableName: string }).tableName; + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = [statement]; + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + newStatements[tableName].push(statement); + } + } + + const combinedStatements = Object.values(newStatements).flat(); + const renamedTables = combinedStatements.filter((it) => it.type === 'rename_table'); + const renamedColumns = combinedStatements.filter((it) => it.type === 'alter_table_rename_column'); + + const rest = combinedStatements.filter((it) => it.type !== 'rename_table' && it.type !== 'alter_table_rename_column'); + + return [...renamedTables, ...renamedColumns, ...rest]; +}; + +export const sqliteCombineStatements = ( + statements: JsonStatement[], + json2: SQLiteSchemaSquashed, + action?: 'push', +) => { + // const tablesContext: Record = {}; + const newStatements: Record = {}; + for (const statement of statements) { + if ( + statement.type === 'alter_table_alter_column_set_type' + || statement.type === 'alter_table_alter_column_set_default' + || statement.type === 'alter_table_alter_column_drop_default' + || statement.type === 'alter_table_alter_column_set_notnull' + || statement.type === 'alter_table_alter_column_drop_notnull' + || statement.type === 'alter_table_alter_column_drop_autoincrement' + || statement.type === 'alter_table_alter_column_set_autoincrement' + || statement.type === 'alter_table_alter_column_drop_pk' + || statement.type === 'alter_table_alter_column_set_pk' + || statement.type === 'create_reference' + || statement.type === 'delete_reference' + || statement.type === 'alter_reference' + || statement.type === 'create_composite_pk' + || statement.type === 'alter_composite_pk' + || statement.type === 'delete_composite_pk' + || statement.type === 'create_unique_constraint' + || statement.type === 'delete_unique_constraint' + ) { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + if (statement.type === 'sqlite_alter_table_add_column' && statement.column.primaryKey) { + const tableName = statement.tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + + const tableName = statement.type === 'rename_table' + ? statement.tableNameTo + : (statement as { tableName: string }).tableName; + + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = [statement]; + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + newStatements[tableName].push(statement); + } + } + + const combinedStatements = Object.values(newStatements).flat(); + + const renamedTables = combinedStatements.filter((it) => it.type === 'rename_table'); + const renamedColumns = combinedStatements.filter((it) => it.type === 'alter_table_rename_column'); + + const rest = combinedStatements.filter((it) => it.type !== 'rename_table' && it.type !== 'alter_table_rename_column'); + + return [...renamedTables, ...renamedColumns, ...rest]; +}; diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 279520ea6..ac3ab21eb 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -327,3 +327,13 @@ export const normaliseSQLiteUrl = ( assertUnreachable(type); }; + +export function findAddedAndRemoved(columnNames1: string[], columnNames2: string[]) { + const set1 = new Set(columnNames1); + const set2 = new Set(columnNames2); + + const addedColumns = columnNames2.filter((it) => !set1.has(it)); + const removedColumns = columnNames1.filter((it) => !set2.has(it)); + + return { addedColumns, removedColumns }; +} diff --git a/drizzle-kit/tests/libsql-statements.test.ts b/drizzle-kit/tests/libsql-statements.test.ts new file mode 100644 index 000000000..adf354458 --- /dev/null +++ b/drizzle-kit/tests/libsql-statements.test.ts @@ -0,0 +1,835 @@ +import { foreignKey, int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { JsonRecreateTableStatement } from 'src/jsonStatements'; +import { expect, test } from 'vitest'; +import { diffTestSchemasLibSQL } from './schemaDiffer'; + +test('drop autoincrement', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + }), + }; + + const { statements } = await diffTestSchemasLibSQL(schema1, schema2, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [{ + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); +}); + +test('set autoincrement', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }), + }; + + const { statements } = await diffTestSchemasLibSQL(schema1, schema2, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [{ + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); +}); + +test('set not null', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_set_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text NOT NULL;`, + ); +}); + +test('drop not null', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_drop_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`, + ); +}); + +test('set default. set not null. add column', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull().default('name'), + age: int('age').notNull(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(3); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_set_default', + tableName: 'users', + columnName: 'name', + newDefaultValue: "'name'", + schema: '', + newDataType: 'text', + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + }); + expect(statements[1]).toStrictEqual({ + type: 'alter_table_alter_column_set_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: "'name'", + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + }); + expect(statements[2]).toStrictEqual({ + type: 'sqlite_alter_table_add_column', + tableName: 'users', + referenceData: undefined, + column: { + name: 'age', + type: 'integer', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text NOT NULL DEFAULT 'name';`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`users\` ADD \`age\` integer NOT NULL;`, + ); +}); + +test('drop default. drop not null', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull().default('name'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_drop_default', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + expect(statements[1]).toStrictEqual({ + type: 'alter_table_alter_column_drop_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`, + ); +}); + +test('set data type. set default', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: int('name').default(123), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_set_type', + tableName: 'users', + columnName: 'name', + newDataType: 'integer', + oldDataType: 'text', + schema: '', + columnDefault: 123, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + expect(statements[1]).toStrictEqual({ + type: 'alter_table_alter_column_set_default', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'integer', + newDefaultValue: 123, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" integer DEFAULT 123;`, + ); +}); + +test('add foriegn key', async (t) => { + const schema = { + table: sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id').references(() => schema.table.id), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_reference', + tableName: 'users', + data: 'users_table_id_table_id_fk;users;table_id;table;id;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "table_id" TO "table_id" integer REFERENCES table(id) ON DELETE no action ON UPDATE no action;`, + ); +}); + +test('drop foriegn key', async (t) => { + const schema = { + table: sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id').references(() => schema.table.id, { + onDelete: 'cascade', + }), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'table_id', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, + ); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`table_id\` integer +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`users\`("id", "table_id") SELECT "id", "table_id" FROM \`__old__generate_users\`;`, + ); + expect(sqlStatements[3]).toBe( + `DROP TABLE \`__old__generate_users\`;`, + ); +}); + +test('alter foriegn key', async (t) => { + const tableRef = sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }); + const tableRef2 = sqliteTable('table2', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id').references(() => tableRef.id, { + onDelete: 'cascade', + }), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + tableId: int('table_id').references(() => tableRef2.id), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'table_id', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [ + { + columnsFrom: [ + 'table_id', + ], + columnsTo: [ + 'id', + ], + name: 'users_table_id_table2_id_fk', + onDelete: 'no action', + onUpdate: 'no action', + tableFrom: 'users', + tableTo: 'table2', + }, + ], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + 'ALTER TABLE `users` RENAME TO `__old__generate_users`;', + ); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`table_id\` integer, +\tFOREIGN KEY (\`table_id\`) REFERENCES \`table2\`(\`id\`) ON UPDATE no action ON DELETE no action +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`users\`("id", "table_id") SELECT "id", "table_id" FROM \`__old__generate_users\`;`, + ); + expect(sqlStatements[3]).toBe( + `DROP TABLE \`__old__generate_users\`;`, + ); +}); + +test('add foriegn key for multiple columns', async (t) => { + const tableRef = sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + age: int('age'), + age1: int('age_1'), + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }), + tableRef, + }; + + const schema2 = { + tableRef, + users: sqliteTable( + 'users', + { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }, + (table) => ({ + foreignKey: foreignKey({ + columns: [table.column, table.column1], + foreignColumns: [tableRef.age, tableRef.age1], + }), + }), + ), + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column', + notNull: false, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column_1', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [ + { + columnsFrom: [ + 'column', + 'column_1', + ], + columnsTo: [ + 'age', + 'age_1', + ], + name: 'users_column_column_1_table_age_age_1_fk', + onDelete: 'no action', + onUpdate: 'no action', + tableFrom: 'users', + tableTo: 'table', + }, + ], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + } as JsonRecreateTableStatement); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`column\` integer, +\t\`column_1\` integer, +\tFOREIGN KEY (\`column\`,\`column_1\`) REFERENCES \`table\`(\`age\`,\`age_1\`) ON UPDATE no action ON DELETE no action +); +`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, + ); + expect(sqlStatements[3]).toBe( + `DROP TABLE \`__old__generate_users\`;`, + ); +}); + +test('drop foriegn key for multiple columns', async (t) => { + const tableRef = sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + age: int('age'), + age1: int('age_1'), + }); + + const schema1 = { + users: sqliteTable( + 'users', + { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }, + (table) => ({ + foreignKey: foreignKey({ + columns: [table.column, table.column1], + foreignColumns: [tableRef.age, tableRef.age1], + }), + }), + ), + tableRef, + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }), + tableRef, + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column', + notNull: false, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column_1', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`column\` integer, +\t\`column_1\` integer +); +`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, + ); + expect(sqlStatements[3]).toBe( + `DROP TABLE \`__old__generate_users\`;`, + ); +}); + +test('drop foriegn key for multiple columns', async (t) => { + const tableRef = sqliteTable('table', { + id: int('id').primaryKey({ autoIncrement: true }), + age: int('age'), + age1: int('age_1'), + }); + + const schema1 = { + users: sqliteTable( + 'users', + { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }, + (table) => ({ + foreignKey: foreignKey({ + columns: [table.column, table.column1], + foreignColumns: [tableRef.age, tableRef.age1], + }), + }), + ), + tableRef, + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + column: int('column'), + column1: int('column_1'), + }), + tableRef, + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column', + notNull: false, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'column_1', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`column\` integer, +\t\`column_1\` integer +); +`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, + ); + expect(sqlStatements[3]).toBe( + `DROP TABLE \`__old__generate_users\`;`, + ); +}); diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts new file mode 100644 index 000000000..205f31f0b --- /dev/null +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -0,0 +1,744 @@ +import { createClient } from '@libsql/client'; +import chalk from 'chalk'; +import { + blob, + foreignKey, + getTableConfig, + int, + integer, + numeric, + real, + sqliteTable, + text, + uniqueIndex, +} from 'drizzle-orm/sqlite-core'; +import { diffTestSchemasPushLibSQL } from 'tests/schemaDiffer'; +import { expect, test } from 'vitest'; + +test('nothing changed in schema', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const users = sqliteTable('users', { + id: integer('id').primaryKey().notNull(), + name: text('name').notNull(), + email: text('email'), + textJson: text('text_json', { mode: 'json' }), + blobJon: blob('blob_json', { mode: 'json' }), + blobBigInt: blob('blob_bigint', { mode: 'bigint' }), + numeric: numeric('numeric'), + createdAt: integer('created_at', { mode: 'timestamp' }), + createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { length: 255 }), + role: text('role', { enum: ['admin', 'user'] }).default('user'), + isConfirmed: integer('is_confirmed', { + mode: 'boolean', + }), + }); + + const schema1 = { + users, + + customers: sqliteTable('customers', { + id: integer('id').primaryKey(), + address: text('address').notNull(), + isConfirmed: integer('is_confirmed', { mode: 'boolean' }), + registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) + .notNull() + .$defaultFn(() => new Date()), + userId: integer('user_id') + .references(() => users.id) + .notNull(), + }), + + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL(turso, schema1, schema1, [], false); + expect(sqlStatements.length).toBe(0); + expect(statements.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); +}); + +test('added, dropped index', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const users = sqliteTable('users', { + id: integer('id').primaryKey().notNull(), + name: text('name').notNull(), + email: text('email'), + textJson: text('text_json', { mode: 'json' }), + blobJon: blob('blob_json', { mode: 'json' }), + blobBigInt: blob('blob_bigint', { mode: 'bigint' }), + numeric: numeric('numeric'), + createdAt: integer('created_at', { mode: 'timestamp' }), + createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { length: 255 }), + role: text('role', { enum: ['admin', 'user'] }).default('user'), + isConfirmed: integer('is_confirmed', { + mode: 'boolean', + }), + }); + + const schema1 = { + users, + customers: sqliteTable( + 'customers', + { + id: integer('id').primaryKey(), + address: text('address').notNull(), + isConfirmed: integer('is_confirmed', { mode: 'boolean' }), + registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) + .notNull() + .$defaultFn(() => new Date()), + userId: integer('user_id').notNull(), + }, + (table) => ({ + uniqueIndex: uniqueIndex('customers_address_unique').on(table.address), + }), + ), + + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; + + const schema2 = { + users, + customers: sqliteTable( + 'customers', + { + id: integer('id').primaryKey(), + address: text('address').notNull(), + isConfirmed: integer('is_confirmed', { mode: 'boolean' }), + registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) + .notNull() + .$defaultFn(() => new Date()), + userId: integer('user_id').notNull(), + }, + (table) => ({ + uniqueIndex: uniqueIndex('customers_is_confirmed_unique').on( + table.isConfirmed, + ), + }), + ), + + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL(turso, schema1, schema2, [], false); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'drop_index', + tableName: 'customers', + data: 'customers_address_unique;address;true;', + schema: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_index', + tableName: 'customers', + data: 'customers_is_confirmed_unique;is_confirmed;true;', + schema: '', + internal: { indexes: {} }, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `DROP INDEX IF EXISTS \`customers_address_unique\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE UNIQUE INDEX \`customers_is_confirmed_unique\` ON \`customers\` (\`is_confirmed\`);`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('added column not null and without default to table with data', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + age: integer('age').notNull(), + }), + }; + + const table = getTableConfig(schema1.companies); + const seedStatements = [ + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ("drizzle");`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ("turso");`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_alter_table_add_column', + tableName: 'companies', + column: { + name: 'age', + type: 'integer', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + referenceData: undefined, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`delete from companies;`); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`companies\` ADD \`age\` integer NOT NULL;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to add not-null ${ + chalk.underline( + 'age', + ) + } column without default value, which contains 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(1); + expect(tablesToTruncate![0]).toBe('companies'); +}); + +test('added column not null and without default to table without data', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + age: integer('age').notNull(), + }), + }; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL(turso, schema1, schema2, [], false); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_alter_table_add_column', + tableName: 'companies', + column: { + name: 'age', + type: 'integer', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + referenceData: undefined, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` ADD \`age\` integer NOT NULL;`, + ); + + expect(infoToPrint!.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop autoincrement. drop column with data', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: false }), + }), + }; + + const table = getTableConfig(schema1.companies); + const seedStatements = [ + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (1, "drizzle");`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (2, "turso");`, + ]; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + tableName: 'companies', + columns: [ + { + name: 'id', + type: 'integer', + autoincrement: false, + notNull: true, + primaryKey: true, + generated: undefined, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL +);\n`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + ); + + expect(columnsToRemove!.length).toBe(1); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to delete ${ + chalk.underline( + 'name', + ) + } column in companies table with 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('change autoincrement. table is part of foreign key', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const companies1 = sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: true }), + }); + const users1 = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').unique(), + companyId: text('company_id').references(() => companies1.id), + }); + const schema1 = { + companies: companies1, + users: users1, + }; + + const companies2 = sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: false }), + }); + const users2 = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').unique(), + companyId: text('company_id').references(() => companies1.id), + }); + const schema2 = { + companies: companies2, + users: users2, + }; + + const { name: usersTableName } = getTableConfig(users1); + const { name: companiesTableName } = getTableConfig(companies1); + const seedStatements = [ + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("drizzle");`, + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("turso");`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ("1");`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ("2");`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + tableName: 'companies', + columns: [ + { + name: 'id', + type: 'integer', + autoincrement: false, + notNull: true, + primaryKey: true, + generated: undefined, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(9); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL +); +`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`__old_push_companies\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`, + ); + expect(sqlStatements[5]).toBe( + `CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`name\` text, +\t\`company_id\` text, +\tFOREIGN KEY (\`company_id\`) REFERENCES \`companies\`(\`id\`) ON UPDATE no action ON DELETE no action +); +`, + ); + expect(sqlStatements[6]).toBe( + `INSERT INTO \`users\`("id", "name", "company_id") SELECT ("id", "name", "company_id") FROM \`__old_push_users\`;`, + ); + expect(sqlStatements[7]).toBe(`DROP TABLE \`__old_push_users\`;`); + expect(sqlStatements[8]).toBe( + `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('create table with custom name references', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }); + + const schema1 = { + users, + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + (t) => ({ + fk: foreignKey({ + columns: [t.id], + foreignColumns: [users.id], + name: 'custom_name_fk', + }), + }), + ), + }; + + const schema2 = { + users, + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + (t) => ({ + fk: foreignKey({ + columns: [t.id], + foreignColumns: [users.id], + name: 'custom_name_fk', + }), + }), + ), + }; + + const { sqlStatements } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(sqlStatements!.length).toBe(0); +}); + +test('drop not null, add not null', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }), + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + ), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + userId: int('user_id'), + }, + ), + }; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(2); + expect(statements![0]).toStrictEqual({ + columnAutoIncrement: false, + columnDefault: undefined, + columnName: 'name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_notnull', + }); + expect(statements![1]).toStrictEqual({ + columnAutoIncrement: false, + columnDefault: undefined, + columnName: 'name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'posts', + type: 'alter_table_alter_column_set_notnull', + }); + expect(sqlStatements!.length).toBe(2); + expect(sqlStatements![0]).toBe(`ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`); + expect(sqlStatements![1]).toBe(`ALTER TABLE \`posts\` ALTER COLUMN "name" TO "name" text NOT NULL;`); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop table with data', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }), + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + ), + }; + + const schema2 = { + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + ), + }; + + const seedStatements = [ + `INSERT INTO \`users\` ("name") VALUES ("drizzle")`, + ]; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + schema: undefined, + tableName: 'users', + type: 'drop_table', + }); + + expect(sqlStatements!.length).toBe(1); + expect(sqlStatements![0]).toBe(`DROP TABLE \`users\`;`); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe(`· You're about to delete ${chalk.underline('users')} table with 1 items`); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(1); + expect(tablesToRemove![0]).toBe('users'); + expect(tablesToTruncate!.length).toBe(0); +}); diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index cf468d3ec..d0c3cb05e 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -1,384 +1,529 @@ import Database from 'better-sqlite3'; -import { SQL, sql } from 'drizzle-orm'; -import { blob, foreignKey, int, integer, numeric, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import chalk from 'chalk'; +import { + blob, + foreignKey, + getTableConfig, + int, + integer, + numeric, + real, + sqliteTable, + text, + uniqueIndex, +} from 'drizzle-orm/sqlite-core'; import { diffTestSchemasPushSqlite } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; -import { DialectSuite, run } from './common'; - -const sqliteSuite: DialectSuite = { - addBasicIndexes: function(context?: any): Promise { - return {} as any; - }, - changeIndexFields: function(context?: any): Promise { - return {} as any; - }, - dropIndex: function(context?: any): Promise { - return {} as any; - }, - - async allTypes() { - const sqlite = new Database(':memory:'); - - const Users = sqliteTable('users', { - id: integer('id').primaryKey().notNull(), - name: text('name').notNull(), - email: text('email'), - textJson: text('text_json', { mode: 'json' }), - blobJon: blob('blob_json', { mode: 'json' }), - blobBigInt: blob('blob_bigint', { mode: 'bigint' }), - numeric: numeric('numeric'), - createdAt: integer('created_at', { mode: 'timestamp' }), - createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }), - real: real('real'), - text: text('text', { length: 255 }), - role: text('role', { enum: ['admin', 'user'] }).default('user'), - isConfirmed: integer('is_confirmed', { - mode: 'boolean', - }), - }); - const schema1 = { - Users, +test('nothing changed in schema', async (t) => { + const client = new Database(':memory:'); + + const users = sqliteTable('users', { + id: integer('id').primaryKey().notNull(), + name: text('name').notNull(), + email: text('email'), + textJson: text('text_json', { mode: 'json' }), + blobJon: blob('blob_json', { mode: 'json' }), + blobBigInt: blob('blob_bigint', { mode: 'bigint' }), + numeric: numeric('numeric'), + createdAt: integer('created_at', { mode: 'timestamp' }), + createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { length: 255 }), + role: text('role', { enum: ['admin', 'user'] }).default('user'), + isConfirmed: integer('is_confirmed', { + mode: 'boolean', + }), + }); + + const schema1 = { + users, - Customers: sqliteTable('customers', { + customers: sqliteTable('customers', { + id: integer('id').primaryKey(), + address: text('address').notNull(), + isConfirmed: integer('is_confirmed', { mode: 'boolean' }), + registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) + .notNull() + .$defaultFn(() => new Date()), + userId: integer('user_id') + .references(() => users.id) + .notNull(), + }), + + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite(client, schema1, schema1, [], false); + expect(sqlStatements.length).toBe(0); + expect(statements.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); +}); + +test('dropped, added unique index', async (t) => { + const client = new Database(':memory:'); + + const users = sqliteTable('users', { + id: integer('id').primaryKey().notNull(), + name: text('name').notNull(), + email: text('email'), + textJson: text('text_json', { mode: 'json' }), + blobJon: blob('blob_json', { mode: 'json' }), + blobBigInt: blob('blob_bigint', { mode: 'bigint' }), + numeric: numeric('numeric'), + createdAt: integer('created_at', { mode: 'timestamp' }), + createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { length: 255 }), + role: text('role', { enum: ['admin', 'user'] }).default('user'), + isConfirmed: integer('is_confirmed', { + mode: 'boolean', + }), + }); + + const schema1 = { + users, + + customers: sqliteTable( + 'customers', + { id: integer('id').primaryKey(), - address: text('address').notNull(), + address: text('address').notNull().unique(), isConfirmed: integer('is_confirmed', { mode: 'boolean' }), registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) .notNull() .$defaultFn(() => new Date()), - userId: integer('user_id') - .references(() => Users.id) - .notNull(), + userId: integer('user_id').notNull(), + }, + (table) => ({ + uniqueIndex: uniqueIndex('customers_address_unique').on(table.address), }), + ), - Posts: sqliteTable('posts', { - id: integer('id').primaryKey(), - content: text('content'), - authorId: integer('author_id'), - }), - }; - - const { statements } = await diffTestSchemasPushSqlite( - sqlite, - schema1, - schema1, - [], - false, - ); - expect(statements.length).toBe(0); - }, - indexesToBeNotTriggered: function(context?: any): Promise { - return {} as any; - }, - indexesTestCase1: function(context?: any): Promise { - return {} as any; - }, - async case1(): Promise { - const sqlite = new Database(':memory:'); - - const schema1 = { - users: sqliteTable('users', { - id: text('id').notNull().primaryKey(), - firstName: text('first_name').notNull(), - lastName: text('last_name').notNull(), - username: text('username').notNull().unique(), - email: text('email').notNull().unique(), - password: text('password').notNull(), - avatarUrl: text('avatar_url').notNull(), - postsCount: integer('posts_count').notNull().default(0), - followersCount: integer('followers_count').notNull().default(0), - followingsCount: integer('followings_count').notNull().default(0), - createdAt: integer('created_at').notNull(), - }), - }; - - const schema2 = { - users: sqliteTable('users', { - id: text('id').notNull().primaryKey(), - firstName: text('first_name').notNull(), - lastName: text('last_name').notNull(), - username: text('username').notNull().unique(), - email: text('email').notNull().unique(), - password: text('password').notNull(), - avatarUrl: text('avatar_url').notNull(), - followersCount: integer('followers_count').notNull().default(0), - followingsCount: integer('followings_count').notNull().default(0), - createdAt: integer('created_at').notNull(), - }), - }; - - const { statements } = await diffTestSchemasPushSqlite( - sqlite, - schema1, - schema2, - [], - false, - ); - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'alter_table_drop_column', - tableName: 'users', - columnName: 'posts_count', - schema: '', - }); - }, - addNotNull: function(context?: any): Promise { - return {} as any; - }, - addNotNullWithDataNoRollback: function(context?: any): Promise { - return {} as any; - }, - addBasicSequences: function(context?: any): Promise { - return {} as any; - }, - // --- - addGeneratedColumn: async function(context?: any): Promise { - const sqlite = new Database(':memory:'); - - const from = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - }), - }; - const to = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'stored' }, - ), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSqlite( - sqlite, - from, - to, - [], - ); - - expect(statements).toStrictEqual([]); - expect(sqlStatements).toStrictEqual([]); - }, - addGeneratedToColumn: async function(context?: any): Promise { - const sqlite = new Database(':memory:'); - - const from = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').notNull(), - generatedName1: text('gen_name1'), - }), - }; - const to = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name') - .notNull() - .generatedAlwaysAs((): SQL => sql`${to.users.name} || 'hello'`, { - mode: 'stored', - }), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; - const { statements, sqlStatements } = await diffTestSchemasPushSqlite( - sqlite, - from, - to, - [], - ); + const schema2 = { + users, - expect(statements).toStrictEqual([ + customers: sqliteTable( + 'customers', { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: { - as: '("name" || \'hello\')', - type: 'virtual', - }, - columnName: 'gen_name1', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_set_generated', + id: integer('id').primaryKey(), + address: text('address').notNull(), + isConfirmed: integer('is_confirmed', { mode: 'boolean' }), + registrationDate: integer('registration_date', { mode: 'timestamp_ms' }) + .notNull() + .$defaultFn(() => new Date()), + userId: integer('user_id').notNull(), }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', - 'ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS ("name" || \'hello\') VIRTUAL;', - ]); - - for (const st of sqlStatements) { - sqlite.exec(st); - } - }, - dropGeneratedConstraint: async function(context?: any): Promise { - const sqlite = new Database(':memory:'); - - const from = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'stored' }, + (table) => ({ + uniqueIndex: uniqueIndex('customers_is_confirmed_unique').on( + table.isConfirmed, ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; - const to = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name'), - generatedName1: text('gen_name1'), }), - }; + ), - const { statements, sqlStatements } = await diffTestSchemasPushSqlite( - sqlite, - from, - to, - [], - ); + posts: sqliteTable('posts', { + id: integer('id').primaryKey(), + content: text('content'), + authorId: integer('author_id'), + }), + }; - expect(statements).toStrictEqual([ - { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: undefined, - columnName: 'gen_name', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_generated', - }, + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite(client, schema1, schema2, [], false); + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'drop_index', + tableName: 'customers', + data: 'customers_address_unique;address;true;', + schema: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_index', + tableName: 'customers', + data: 'customers_is_confirmed_unique;is_confirmed;true;', + schema: '', + internal: { + indexes: {}, + }, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `DROP INDEX IF EXISTS \`customers_address_unique\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE UNIQUE INDEX \`customers_is_confirmed_unique\` ON \`customers\` (\`is_confirmed\`);`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('added column not null and without default to table with data', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + age: integer('age').notNull(), + }), + }; + + const table = getTableConfig(schema1.companies); + const seedStatements = [ + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ('drizzle');`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ('turso');`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_alter_table_add_column', + tableName: 'companies', + column: { + name: 'age', + type: 'integer', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + referenceData: undefined, + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`delete from companies;`); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`companies\` ADD \`age\` integer NOT NULL;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to add not-null ${ + chalk.underline( + 'age', + ) + } column without default value, which contains 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(1); + expect(tablesToTruncate![0]).toBe('companies'); +}); + +test('added column not null and without default to table without data', async (t) => { + const turso = new Database(':memory:'); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + age: integer('age').notNull(), + }), + }; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite(turso, schema1, schema2, [], false); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_alter_table_add_column', + tableName: 'companies', + column: { + name: 'age', + type: 'integer', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + referenceData: undefined, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` ADD \`age\` integer NOT NULL;`, + ); + + expect(infoToPrint!.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop autoincrement. drop column with data', async (t) => { + const turso = new Database(':memory:'); + + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: false }), + }), + }; + + const table = getTableConfig(schema1.companies); + const seedStatements = [ + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (1, 'drizzle');`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (2, 'turso');`, + ]; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + tableName: 'companies', + columns: [ { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: undefined, - columnName: 'gen_name1', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_generated', + name: 'id', + type: 'integer', + autoincrement: false, + notNull: true, + primaryKey: true, + generated: undefined, }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `users` DROP COLUMN `gen_name`;', - 'ALTER TABLE `users` ADD `gen_name` text;', - 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', - 'ALTER TABLE `users` ADD `gen_name1` text;', - ]); - - for (const st of sqlStatements) { - sqlite.exec(st); - } - }, - alterGeneratedConstraint: async function(context?: any): Promise { - const sqlite = new Database(':memory:'); - - const from = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${to.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; - const to = { - users: sqliteTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${to.users.name}`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${to.users.name}`, - { mode: 'virtual' }, - ), - }), - }; + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL +);\n`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + ); + + expect(columnsToRemove!.length).toBe(1); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to delete ${ + chalk.underline( + 'name', + ) + } column in companies table with 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); - const { statements, sqlStatements } = await diffTestSchemasPushSqlite( - sqlite, - from, - to, - [], - ); +test('change autoincrement. table is part of foreign key', async (t) => { + const client = new Database(':memory:'); - expect(statements).toStrictEqual([ + const companies1 = sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: true }), + }); + const users1 = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').unique(), + companyId: text('company_id').references(() => companies1.id), + }); + const schema1 = { + companies: companies1, + users: users1, + }; + + const companies2 = sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: false }), + }); + const users2 = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').unique(), + companyId: text('company_id').references(() => companies1.id), + }); + const schema2 = { + companies: companies2, + users: users2, + }; + + const { name: usersTableName } = getTableConfig(users1); + const { name: companiesTableName } = getTableConfig(companies1); + const seedStatements = [ + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ('drizzle');`, + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ('turso');`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ('1');`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ('2');`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + tableName: 'companies', + columns: [ { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: { - as: '("name")', - type: 'virtual', - }, - columnName: 'gen_name1', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_alter_generated', + name: 'id', + type: 'integer', + autoincrement: false, + notNull: true, + primaryKey: true, + generated: undefined, }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', - 'ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS ("name") VIRTUAL;', - ]); - - for (const st of sqlStatements) { - sqlite.exec(st); - } - }, - createTableWithGeneratedConstraint: function(context?: any): Promise { - return {} as any; - }, -}; - -run(sqliteSuite); + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(9); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE TABLE \`companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL +); +`, + ); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`__old_push_companies\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`, + ); + expect(sqlStatements[5]).toBe( + `CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`name\` text, +\t\`company_id\` text, +\tFOREIGN KEY (\`company_id\`) REFERENCES \`companies\`(\`id\`) ON UPDATE no action ON DELETE no action +); +`, + ); + expect(sqlStatements[6]).toBe( + `INSERT INTO \`users\`("id", "name", "company_id") SELECT ("id", "name", "company_id") FROM \`__old_push_users\`;`, + ); + expect(sqlStatements[7]).toBe(`DROP TABLE \`__old_push_users\`;`); + expect(sqlStatements[8]).toBe( + `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); test('create table with custom name references', async (t) => { - const sqlite = new Database(':memory:'); + const client = new Database(':memory:'); const users = sqliteTable('users', { id: int('id').primaryKey({ autoIncrement: true }), @@ -424,7 +569,7 @@ test('create table with custom name references', async (t) => { }; const { sqlStatements } = await diffTestSchemasPushSqlite( - sqlite, + client, schema1, schema2, [], @@ -432,3 +577,383 @@ test('create table with custom name references', async (t) => { expect(sqlStatements!.length).toBe(0); }); + +test('drop not null, add not null', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }), + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }, + ), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + posts: sqliteTable( + 'posts', + { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + userId: int('user_id'), + }, + ), + }; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(2); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + expect(statements![1]).toStrictEqual({ + columns: [ + { + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'name', + notNull: true, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + generated: undefined, + name: 'user_id', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'posts', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(8); + expect(sqlStatements![0]).toBe(`ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`name\` text +);\n`); + expect(sqlStatements![2]).toBe( + `INSERT INTO \`users\`("id", "name") SELECT ("id", "name") FROM \`__old_push_users\`;`, + ); + expect(sqlStatements![3]).toBe(`DROP TABLE \`__old_push_users\`;`); + + expect(sqlStatements![4]).toBe(`ALTER TABLE \`posts\` RENAME TO \`__old_push_posts\`;`); + expect(sqlStatements![5]).toBe(`CREATE TABLE \`posts\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`name\` text NOT NULL, +\t\`user_id\` integer +);\n`); + expect(sqlStatements![6]).toBe( + `INSERT INTO \`posts\`("id", "name", "user_id") SELECT ("id", "name", "user_id") FROM \`__old_push_posts\`;`, + ); + expect(sqlStatements![7]).toBe(`DROP TABLE \`__old_push_posts\`;`); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('rename table and change data type', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('old_users', { + id: int('id').primaryKey({ autoIncrement: true }), + age: text('age'), + }), + }; + + const schema2 = { + users: sqliteTable('new_users', { + id: int('id').primaryKey({ autoIncrement: true }), + age: integer('age'), + }), + }; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + ['public.old_users->public.new_users'], + ); + + expect(statements!.length).toBe(2); + expect(statements![0]).toStrictEqual({ + fromSchema: undefined, + tableNameFrom: 'old_users', + tableNameTo: 'new_users', + toSchema: undefined, + type: 'rename_table', + }); + expect(statements![1]).toStrictEqual({ + columns: [ + { + autoincrement: true, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'new_users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(5); + expect(sqlStatements![0]).toBe(`ALTER TABLE \`old_users\` RENAME TO \`new_users\`;`); + expect(sqlStatements![1]).toBe(`ALTER TABLE \`new_users\` RENAME TO \`__old_push_new_users\`;`); + expect(sqlStatements![2]).toBe(`CREATE TABLE \`new_users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`age\` integer +);\n`); + expect(sqlStatements![3]).toBe( + `INSERT INTO \`new_users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_new_users\`;`, + ); + expect(sqlStatements![4]).toBe(`DROP TABLE \`__old_push_new_users\`;`); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('rename table and change data type', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('old_users', { + id: int('id').primaryKey({ autoIncrement: true }), + age: text('age'), + }), + }; + + const schema2 = { + users: sqliteTable('new_users', { + id: int('id').primaryKey({ autoIncrement: true }), + age: integer('age'), + }), + }; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + ['public.old_users->public.new_users'], + ); + + expect(statements!.length).toBe(2); + expect(statements![0]).toStrictEqual({ + fromSchema: undefined, + tableNameFrom: 'old_users', + tableNameTo: 'new_users', + toSchema: undefined, + type: 'rename_table', + }); + expect(statements![1]).toStrictEqual({ + columns: [ + { + autoincrement: true, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'new_users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(5); + expect(sqlStatements![0]).toBe(`ALTER TABLE \`old_users\` RENAME TO \`new_users\`;`); + expect(sqlStatements![1]).toBe(`ALTER TABLE \`new_users\` RENAME TO \`__old_push_new_users\`;`); + expect(sqlStatements![2]).toBe(`CREATE TABLE \`new_users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`age\` integer +);\n`); + expect(sqlStatements![3]).toBe( + `INSERT INTO \`new_users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_new_users\`;`, + ); + expect(sqlStatements![4]).toBe(`DROP TABLE \`__old_push_new_users\`;`); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('rename column and change data type', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + age: integer('age'), + }), + }; + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + ['public.users.name->public.users.age'], + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: true, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, +\t\`age\` integer +);\n`); + expect(sqlStatements![2]).toBe( + `INSERT INTO \`users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_users\`;`, + ); + expect(sqlStatements![3]).toBe(`DROP TABLE \`__old_push_users\`;`); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 4a14d920b..3a2a47b6b 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -1,4 +1,5 @@ import { PGlite } from '@electric-sql/pglite'; +import { Client } from '@libsql/client/.'; import { Database } from 'better-sqlite3'; import { is } from 'drizzle-orm'; import { MySqlSchema, MySqlTable } from 'drizzle-orm/mysql-core'; @@ -6,6 +7,7 @@ import { isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable } from 'd import { SQLiteTable } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; +import { libSqlLogSuggestionsAndReturn } from 'src/cli/commands/libSqlPushUtils'; import { columnsResolver, enumsResolver, @@ -30,6 +32,7 @@ import { sqliteSchema, squashSqliteScheme } from 'src/serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase } from 'src/serializer/sqliteSerializer'; import { generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; import { + applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, applySqliteSnapshotsDiff, @@ -841,11 +844,18 @@ export const diffTestSchemasPushSqlite = async ( right: SqliteSchema, renamesArr: string[], cli: boolean = false, + seedStatements: string[] = [], ) => { const { sqlStatements } = await applySqliteDiffs(left, 'push'); + for (const st of sqlStatements) { client.exec(st); } + + for (const st of seedStatements) { + client.exec(st); + } + // do introspect into PgSchemaInternal const introspectedSchema = await fromSqliteDatabase( { @@ -859,9 +869,9 @@ export const diffTestSchemasPushSqlite = async ( undefined, ); - const leftTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized2 = generateSqliteSnapshot(leftTables); + const serialized2 = generateSqliteSnapshot(rightTables); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -898,7 +908,15 @@ export const diffTestSchemasPushSqlite = async ( 'push', ); - const { statementsToExecute } = await logSuggestionsAndReturn( + const { + statementsToExecute, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await logSuggestionsAndReturn( { query: async (sql: string, params: any[] = []) => { return client.prepare(sql).bind(params).all() as T[]; @@ -913,7 +931,16 @@ export const diffTestSchemasPushSqlite = async ( _meta!, ); - return { sqlStatements: statementsToExecute, statements }; + return { + sqlStatements: statementsToExecute, + statements, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + }; } else { const { sqlStatements, statements } = await applySqliteSnapshotsDiff( sn1, @@ -928,6 +955,136 @@ export const diffTestSchemasPushSqlite = async ( } }; +export async function diffTestSchemasPushLibSQL( + client: Client, + left: SqliteSchema, + right: SqliteSchema, + renamesArr: string[], + cli: boolean = false, + seedStatements: string[] = [], +) { + const { sqlStatements } = await applyLibSQLDiffs(left, 'push'); + + for (const st of sqlStatements) { + await client.execute(st); + } + + for (const st of seedStatements) { + await client.execute(st); + } + + const introspectedSchema = await fromSqliteDatabase( + { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); + }, + batch: async ( + queries: { query: string; values?: any[] | undefined }[], + ) => { + await client.batch( + queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), + ); + }, + }, + undefined, + ); + + const leftTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + + const serialized2 = generateSqliteSnapshot(leftTables); + + const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashSqliteScheme(sch1, 'push'); + const sn2 = squashSqliteScheme(sch2, 'push'); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements, _meta } = await applyLibSQLSnapshotsDiff( + sn1, + sn2, + testTablesResolver(renames), + testColumnsResolver(renames), + sch1, + sch2, + 'push', + ); + + const { + statementsToExecute, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await libSqlLogSuggestionsAndReturn( + { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); + }, + batch: async ( + queries: { query: string; values?: any[] | undefined }[], + ) => { + await client.batch( + queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), + ); + }, + }, + statements, + sn1, + sn2, + _meta!, + ); + + return { + sqlStatements: statementsToExecute, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + }; + } else { + const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + sch1, + sch2, + 'push', + ); + return { sqlStatements, statements }; + } +} + export const applySqliteDiffs = async ( sn: SqliteSchema, action?: 'push' | undefined, @@ -976,6 +1133,54 @@ export const applySqliteDiffs = async ( return { sqlStatements, statements }; }; +export const applyLibSQLDiffs = async ( + sn: SqliteSchema, + action?: 'push' | undefined, +) => { + const dryRun = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + tables: {}, + enums: {}, + schemas: {}, + _meta: { + schemas: {}, + tables: {}, + columns: {}, + }, + } as const; + + const tables = Object.values(sn).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + + const serialized1 = generateSqliteSnapshot(tables); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + + const sch1 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sn1 = squashSqliteScheme(sch1, action); + + const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff( + dryRun, + sn1, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + dryRun, + sch1, + action, + ); + + return { sqlStatements, statements }; +}; + export const diffTestSchemasSqlite = async ( left: SqliteSchema, right: SqliteSchema, @@ -1036,6 +1241,66 @@ export const diffTestSchemasSqlite = async ( return { sqlStatements, statements }; }; +export const diffTestSchemasLibSQL = async ( + left: SqliteSchema, + right: SqliteSchema, + renamesArr: string[], + cli: boolean = false, +) => { + const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + + const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + + const serialized1 = generateSqliteSnapshot(leftTables); + const serialized2 = generateSqliteSnapshot(rightTables); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashSqliteScheme(sch1); + const sn2 = squashSqliteScheme(sch2); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff( + sn1, + sn2, + testTablesResolver(renames), + testColumnsResolver(renames), + sch1, + sch2, + ); + return { sqlStatements, statements }; + } + + const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + sch1, + sch2, + ); + return { sqlStatements, statements }; +}; + // --- Introspect to file helpers --- export const introspectPgToFile = async ( diff --git a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts new file mode 100644 index 000000000..012ea1eac --- /dev/null +++ b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts @@ -0,0 +1,1209 @@ +import { JsonStatement } from 'src/jsonStatements'; +import { SQLiteSchemaSquashed } from 'src/serializer/sqliteSchema'; +import { libSQLCombineStatements } from 'src/statementCombiner'; +import { expect, test } from 'vitest'; + +/** + * ! before: + * + * user: { + * id INT; + * first_name INT; + * iq INT; + * PRIMARY KEY (id, iq) + * INDEXES: { + * UNIQUE id; + * } + * } + * + * ! after: + * + * new_user: { + * id INT; + * first_name INT; + * iq INT; + * PRIMARY KEY (id, iq) + * INDEXES: {} + * } + * + * rename table and drop unique index + * expect to get "rename_table" statement and then "recreate_table" + */ +test(`rename table and drop index`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'rename_table', + fromSchema: '', + toSchema: '', + tableNameFrom: 'user', + tableNameTo: 'new_user', + }, + { + type: 'drop_index', + tableName: 'new_user', + data: 'user_first_name_unique;first_name;true;', + schema: '', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + first_name: { + name: 'first_name', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + iq: { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: { + user_first_name_unique: 'user_first_name_unique;first_name;true;', + }, + foreignKeys: {}, + compositePrimaryKeys: { + user_id_iq_pk: 'id,iq', + }, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + new_user: { + name: 'new_user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + first_name: { + name: 'first_name', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + iq: { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: { + new_user_id_iq_pk: 'id,iq', + }, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'rename_table', + fromSchema: '', + toSchema: '', + tableNameFrom: 'user', + tableNameTo: 'new_user', + }, + { + type: 'drop_index', + tableName: 'new_user', + data: 'user_first_name_unique;first_name;true;', + schema: '', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +/** + * ! before: + * + * autoincrement1: { + * id INT PRIMARY KEY; + * } + * + * autoincrement2: { + * id INT PRIMARY KEY AUTOINCREMENT; + * } + * + * dropNotNull: { + * id INT NOT NULL; + * } + * + * ! after: + * + * autoincrement1: { + * id INT PRIMARY KEY AUTOINCREMENT; + * } + * + * autoincrement2: { + * id INT PRI { + const statements: JsonStatement[] = [ + { + type: 'alter_table_alter_column_set_autoincrement', + tableName: 'autoincrement1', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: true, + columnPk: true, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_drop_autoincrement', + tableName: 'autoincrement2', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: true, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_drop_notnull', + tableName: 'dropNotNull', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + autoincrement1: { + name: 'autoincrement1', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + autoincrement2: { + name: 'autoincrement2', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: false, + autoincrement: true, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + dropNotNull: { + name: 'dropNotNull', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + autoincrement1: { + name: 'autoincrement1', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: true, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + autoincrement2: { + name: 'autoincrement2', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + dropNotNull: { + name: 'dropNotNull', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'recreate_table', + tableName: 'autoincrement1', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: true, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'recreate_table', + tableName: 'autoincrement2', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'alter_table_alter_column_drop_notnull', + tableName: 'dropNotNull', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +/** + * ! before: + * + * pk1: { + * id INT; + * } + * + * pk2: { + * id INT PRIMARY KEY; + * } + * + * ref_table: { + * id INT; + * } + * + * create_reference: { + * id INT; + * } + * + * ! after: + * + * pk1: { + * id INT PRIMARY KEY; + * } + * + * pk2: { + * id INT; + * } + * + * ref_table: { + * id INT; + * } + * + * create_reference: { + * id INT -> ref_table INT; + * } + * + * drop primary key for pk2 + * set primary key for pk1 + * "create_reference" reference on "ref_table" + * + * expect to: + * - "recreate_table" statement for pk1 + * - "recreate_table" statement for pk2 + * - "create_reference" statement for create_reference + */ +test(`drop and set primary key. create reference`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'alter_table_alter_column_set_pk', + tableName: 'pk1', + schema: '', + columnName: 'id', + }, + { + type: 'alter_table_alter_column_set_notnull', + tableName: 'pk1', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: true, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_drop_pk', + tableName: 'pk2', + columnName: 'id', + schema: '', + }, + { + type: 'alter_table_alter_column_drop_notnull', + tableName: 'pk2', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + { + type: 'create_reference', + tableName: 'create_reference', + data: 'create_reference_id_ref_table_id_fk;create_reference;id;ref_table;id;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'int', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + create_reference: { + name: 'create_reference', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + pk1: { + name: 'pk1', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + pk2: { + name: 'pk2', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + ref_table: { + name: 'ref_table', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + create_reference: { + name: 'create_reference', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + create_reference_id_ref_table_id_fk: + 'create_reference_id_ref_table_id_fk;create_reference;id;ref_table;id;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + pk1: { + name: 'pk1', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + pk2: { + name: 'pk2', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + ref_table: { + name: 'ref_table', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'recreate_table', + tableName: 'pk1', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'recreate_table', + tableName: 'pk2', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'create_reference', + tableName: 'create_reference', + data: 'create_reference_id_ref_table_id_fk;create_reference;id;ref_table;id;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'int', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +/** + * ! before: + * + * fk1: { + * fk_id INT; + * fk_id1 INT; + * } + * + * fk2: { + * fk2_id INT; -> composite reference on ref_table id INT + * fk2_id1 INT; -> composite reference on ref_table id1 INT + * } + * + * ref_table: { + * id INT; + * id1 INT; + * } + * + * ! after: + * + * fk1: { + * fk_id INT; -> composite reference on ref_table id INT + * fk_id1 INT; -> composite reference on ref_table id1 INT + * } + * + * fk2: { + * fk2_id INT; + * fk2_id1 INT; + * } + * + * ref_table: { + * id INT; + * id1 INT; + * } + * + * set multi column reference for fk1 + * drop multi column reference for fk2 + * + * expect to: + * - "recreate_table" statement for fk1 + * - "recreate_table" statement for fk2 + */ +test(`set and drop multiple columns reference`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'delete_reference', + tableName: 'fk1', + data: 'fk1_fk_id_fk_id1_ref_table_id_id1_fk;fk1;fk_id,fk_id1;ref_table;id,id1;no action;no action', + schema: '', + isMulticolumn: true, + }, + { + type: 'create_reference', + tableName: 'fk2', + data: 'fk2_fk2_id_fk2_id1_ref_table_id_id1_fk;fk2;fk2_id,fk2_id1;ref_table;id,id1;no action;no action', + schema: '', + isMulticolumn: true, + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + fk1: { + name: 'fk1', + columns: { + fk_id: { + name: 'fk_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + fk_id1: { + name: 'fk_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + fk1_fk_id_fk_id1_ref_table_id_id1_fk: + 'fk1_fk_id_fk_id1_ref_table_id_id1_fk;fk1;fk_id,fk_id1;ref_table;id,id1;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + fk2: { + name: 'fk2', + columns: { + fk2_id: { + name: 'fk2_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + fk2_id1: { + name: 'fk2_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + ref_table: { + name: 'ref_table', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + id1: { + name: 'id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + fk1: { + name: 'fk1', + columns: { + fk_id: { + name: 'fk_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + fk_id1: { + name: 'fk_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + fk2: { + name: 'fk2', + columns: { + fk2_id: { + name: 'fk2_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + fk2_id1: { + name: 'fk2_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + fk2_fk2_id_fk2_id1_ref_table_id_id1_fk: + 'fk2_fk2_id_fk2_id1_ref_table_id_id1_fk;fk2;fk2_id,fk2_id1;ref_table;id,id1;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + ref_table: { + name: 'ref_table', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + id1: { + name: 'id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'recreate_table', + tableName: 'fk1', + columns: [ + { + name: 'fk_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + { + name: 'fk_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'recreate_table', + tableName: 'fk2', + columns: [ + { + name: 'fk2_id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + { + name: 'fk2_id1', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [ + { + name: 'fk2_fk2_id_fk2_id1_ref_table_id_id1_fk', + tableFrom: 'fk2', + tableTo: 'ref_table', + columnsFrom: ['fk2_id', 'fk2_id1'], + columnsTo: ['id', 'id1'], + onDelete: 'no action', + onUpdate: 'no action', + }, + ], + uniqueConstraints: [], + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +/** + * ! before: + * + * pk: { + * pk TEXT PRIMARY KEY; + * } + * + * simple: { + * simple TEXT; + * } + * + * unique: { + * unique INT UNIQUE; + * } + * + * ! after: + * + * pk: { + * pk INT PRIMARY KEY; + * } + * + * simple: { + * simple INT; + * } + * + * unique: { + * unique TEXT UNIQUE; + * } + * + * set new type for primary key column + * set new type for unique column + * set new type for column without pk or unique + * + * expect to: + * - "recreate_table" statement for pk + * - "recreate_table" statement for unique + * - "alter_table_alter_column_set_type" statement for simple + * - "create_index" statement for unique + */ +test(`set new type for primary key, unique and normal column`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'alter_table_alter_column_set_type', + tableName: 'pk', + columnName: 'pk', + newDataType: 'int', + oldDataType: 'text', + schema: '', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: true, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_set_type', + tableName: 'simple', + columnName: 'simple', + newDataType: 'int', + oldDataType: 'text', + schema: '', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_set_type', + tableName: 'unique', + columnName: 'unique', + newDataType: 'text', + oldDataType: 'int', + schema: '', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + pk: { + name: 'pk', + columns: { + pk: { + name: 'pk', + type: 'text', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + simple: { + name: 'simple', + columns: { + simple: { + name: 'simple', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + unique: { + name: 'unique', + columns: { + unique: { + name: 'unique', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: { + unique_unique_unique: 'unique_unique_unique;unique;true;', + }, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + pk: { + name: 'pk', + columns: { + pk: { + name: 'pk', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + simple: { + name: 'simple', + columns: { + simple: { + name: 'simple', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + unique: { + name: 'unique', + columns: { + unique: { + name: 'unique', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: { + unique_unique_unique: 'unique_unique_unique;unique;true;', + }, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'recreate_table', + tableName: 'pk', + columns: [ + { + name: 'pk', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + type: 'alter_table_alter_column_set_type', + tableName: 'simple', + columnName: 'simple', + newDataType: 'int', + oldDataType: 'text', + schema: '', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }, + { + type: 'recreate_table', + tableName: 'unique', + columns: [ + { + name: 'unique', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + { + data: 'unique_unique_unique;unique;true;', + internal: undefined, + schema: '', + tableName: 'unique', + type: 'create_index', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); diff --git a/drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts new file mode 100644 index 000000000..517343d9b --- /dev/null +++ b/drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts @@ -0,0 +1,778 @@ +import { JsonStatement } from 'src/jsonStatements'; +import { SQLiteSchemaSquashed } from 'src/serializer/sqliteSchema'; +import { sqliteCombineStatements } from 'src/statementCombiner'; +import { expect, test } from 'vitest'; + +test(`renamed column and altered this column type`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'alter_table_rename_column', + tableName: 'user', + oldColumnName: 'lastName', + newColumnName: 'lastName123', + schema: '', + }, + { + type: 'alter_table_alter_column_set_type', + tableName: 'user', + columnName: 'lastName123', + newDataType: 'int', + oldDataType: 'text', + schema: '', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + columnIsUnique: false, + } as unknown as JsonStatement, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + firstName: { + name: 'firstName', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + lastName: { + name: 'lastName', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + firstName: { + name: 'firstName', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + lastName: { + name: 'lastName123', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'recreate_table', + tableName: 'user', + columns: [ + { + name: 'firstName', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + { + name: 'lastName123', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + { + name: 'test', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + ]; + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`renamed column and droped column "test"`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'alter_table_rename_column', + tableName: 'user', + oldColumnName: 'lastName', + newColumnName: 'lastName123', + schema: '', + }, + { + type: 'alter_table_drop_column', + tableName: 'user', + columnName: 'test', + schema: '', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + firstName: { + name: 'firstName', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + lastName: { + name: 'lastName', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + firstName: { + name: 'firstName', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + lastName: { + name: 'lastName123', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements: JsonStatement[] = [ + { + type: 'alter_table_rename_column', + tableName: 'user', + oldColumnName: 'lastName', + newColumnName: 'lastName123', + schema: '', + }, + { + type: 'alter_table_drop_column', + tableName: 'user', + columnName: 'test', + schema: '', + }, + ]; + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`droped column that is part of composite pk`, async (t) => { + const statements: JsonStatement[] = [ + { type: 'delete_composite_pk', tableName: 'user', data: 'id,iq' }, + { + type: 'alter_table_alter_column_set_pk', + tableName: 'user', + schema: '', + columnName: 'id', + }, + { + type: 'alter_table_drop_column', + tableName: 'user', + columnName: 'iq', + schema: '', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + first_nam: { + name: 'first_nam', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + iq: { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: { + user_id_iq_pk: 'id,iq', + }, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + user: { + name: 'user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: false, + autoincrement: false, + }, + first_nam: { + name: 'first_nam', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements: JsonStatement[] = [ + { + type: 'recreate_table', + tableName: 'user', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: true, + notNull: false, + autoincrement: false, + }, + { + name: 'first_nam', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + ]; + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`drop column "ref"."name", rename column "ref"."age". dropped primary key "user"."id". Set not null to "user"."iq"`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'alter_table_rename_column', + tableName: 'ref', + oldColumnName: 'age', + newColumnName: 'age1', + schema: '', + }, + { + type: 'alter_table_alter_column_drop_pk', + tableName: 'user', + columnName: 'id', + schema: '', + }, + { + type: 'alter_table_alter_column_drop_autoincrement', + tableName: 'user', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_drop_notnull', + tableName: 'user', + columnName: 'id', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + { + type: 'alter_table_alter_column_set_notnull', + tableName: 'user', + columnName: 'iq', + schema: '', + newDataType: 'int', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + } as unknown as JsonStatement, + { + type: 'alter_table_drop_column', + tableName: 'ref', + columnName: 'text', + schema: '', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: true, + }, + user_iq: { + name: 'user_iq', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + name: { + name: 'name', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + age: { + name: 'age', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_user_iq_user_iq_fk: 'ref_user_iq_user_iq_fk;ref;user_iq;user;iq;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: true, + }, + first_name: { + name: 'first_name', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + iq: { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + user_iq: { + name: 'user_iq', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + age1: { + name: 'age1', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_user_iq_user_iq_fk: 'ref_user_iq_user_iq_fk;ref;user_iq;user;iq;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id: { + name: 'id', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + first_name: { + name: 'first_name', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + iq: { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements: JsonStatement[] = [ + { + type: 'alter_table_rename_column', + tableName: 'ref', + oldColumnName: 'age', + newColumnName: 'age1', + schema: '', + }, + { + type: 'alter_table_drop_column', + tableName: 'ref', + columnName: 'text', + schema: '', + }, + { + type: 'recreate_table', + tableName: 'user', + columns: [ + { + name: 'id', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + { + name: 'first_name', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + { + name: 'iq', + type: 'int', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [], + uniqueConstraints: [], + }, + ]; + + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`create reference on exising column (table includes unique index). expect to recreate column and recreate index`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'create_reference', + tableName: 'unique', + data: 'unique_ref_pk_pk_pk_fk;unique;ref_pk;pk;pk;no action;no action', + schema: '', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + pk: { + name: 'pk', + columns: { + pk: { + name: 'pk', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + unique: { + name: 'unique', + columns: { + unique: { + name: 'unique', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ref_pk: { + name: 'ref_pk', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: { + unique_unique_unique: 'unique_unique_unique;unique;true;', + }, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + pk: { + name: 'pk', + columns: { + pk: { + name: 'pk', + type: 'int', + primaryKey: true, + notNull: true, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + unique: { + name: 'unique', + columns: { + unique: { + name: 'unique', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ref_pk: { + name: 'ref_pk', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: { + unique_unique_unique: 'unique_unique_unique;unique;true;', + }, + foreignKeys: { + unique_ref_pk_pk_pk_fk: 'unique_ref_pk_pk_pk_fk;unique;ref_pk;pk;pk;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements: JsonStatement[] = [ + { + type: 'recreate_table', + tableName: 'unique', + columns: [ + { + name: 'unique', + type: 'text', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + { + name: 'ref_pk', + type: 'int', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + ], + compositePKs: [], + referenceData: [ + { + name: 'unique_ref_pk_pk_pk_fk', + tableFrom: 'unique', + tableTo: 'pk', + columnsFrom: ['ref_pk'], + columnsTo: ['pk'], + onDelete: 'no action', + onUpdate: 'no action', + }, + ], + uniqueConstraints: [], + }, + { + data: 'unique_unique_unique;unique;true;', + internal: undefined, + schema: '', + tableName: 'unique', + type: 'create_index', + }, + ]; + + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); From 38d6dabc451b70f57b79654313e038da3c08a54f Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 12 Aug 2024 18:14:08 +0300 Subject: [PATCH 066/492] - updated tests - added handling create reference and create column for sqlite and libsql --- drizzle-kit/src/cli/validations/cli.ts | 2 +- drizzle-kit/src/jsonStatements.ts | 1 - drizzle-kit/src/sqlgenerator.ts | 34 +- drizzle-kit/src/statementCombiner.ts | 83 ++- drizzle-kit/tests/cli-generate.test.ts | 10 + drizzle-kit/tests/cli-push.test.ts | 2 + drizzle-kit/tests/libsql-statements.test.ts | 41 ++ drizzle-kit/tests/sqlite-columns.test.ts | 271 ++++++--- drizzle-kit/tests/sqlite-tables.test.ts | 14 +- .../libsql-statements-combiner.test.ts | 552 +++++++++++++++++- ....ts => sqlite-statements-combiner.test.ts} | 392 +++++++++++++ 11 files changed, 1265 insertions(+), 137 deletions(-) rename drizzle-kit/tests/statements-combiner/{sqilte-statements-combiner.test.ts => sqlite-statements-combiner.test.ts} (66%) diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index 2e11b2672..789551e4c 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -25,7 +25,7 @@ export const pushParams = object({ extensionsFilters: literal('postgis').array().optional(), verbose: boolean().optional(), strict: boolean().optional(), - driver: driver, + driver: driver.optional(), }).passthrough(); export type PushParams = TypeOf; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 01da7a129..278b2ffc1 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -1637,7 +1637,6 @@ export const prepareSqliteAlterColumns = ( columns: AlteredColumn[], // TODO: remove? json2: CommonSquashedSchema, - driver?: 'turso', ): JsonAlterColumnStatement[] => { let statements: JsonAlterColumnStatement[] = []; let dropPkStatements: JsonAlterColumnDropPrimaryKeyStatement[] = []; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 179ca4176..baf9e2727 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -1518,9 +1518,7 @@ type LibSQLModifyColumnStatement = | JsonAlterColumnDropNotNullStatement | JsonAlterColumnSetNotNullStatement | JsonAlterColumnSetDefaultStatement - | JsonAlterColumnDropDefaultStatement - | JsonAlterColumnSetGeneratedStatement - | JsonAlterColumnDropGeneratedStatement; + | JsonAlterColumnDropDefaultStatement; export class LibSQLModifyColumn extends Convertor { can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { @@ -1585,36 +1583,6 @@ export class LibSQLModifyColumn extends Convertor { columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; break; - case 'alter_table_alter_column_drop_generated': - columnType = ` ${statement.newDataType}`; - - columnDefault = ''; - - columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; - break; - case 'alter_table_alter_column_set_generated': - return [ - new SQLiteAlterTableDropColumnConvertor().convert({ - type: 'alter_table_drop_column', - tableName: statement.tableName, - columnName: statement.columnName, - schema: '', - }), - new SQLiteAlterTableAddColumnConvertor().convert({ - tableName, - column: { - name: columnName, - type: statement.newDataType, - notNull: statement.columnNotNull, - default: statement.columnDefault, - onUpdate: statement.columnOnUpdate, - autoincrement: statement.columnAutoIncrement, - primaryKey: statement.columnPk, - generated: statement.columnGenerated, - }, - type: 'sqlite_alter_table_add_column', - }), - ]; } // Seems like getting value from simple json2 shanpshot makes dates be dates diff --git a/drizzle-kit/src/statementCombiner.ts b/drizzle-kit/src/statementCombiner.ts index 21cc86b38..549457cf1 100644 --- a/drizzle-kit/src/statementCombiner.ts +++ b/drizzle-kit/src/statementCombiner.ts @@ -180,29 +180,54 @@ export const libSQLCombineStatements = ( continue; } - if (statement.type === 'create_reference' && statement.isMulticolumn) { + if (statement.type === 'create_reference') { const tableName = statement.tableName; + const data = action === 'push' + ? SQLiteSquasher.unsquashPushFK(statement.data) + : SQLiteSquasher.unsquashFK(statement.data); + const statementsForTable = newStatements[tableName]; if (!statementsForTable) { - newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + newStatements[tableName] = statement.isMulticolumn + ? prepareLibSQLRecreateTable(json2.tables[tableName], action) + : newStatements[tableName] = [statement]; + continue; } - if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { - const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); - const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + // if add column with reference -> skip create_reference statement + if ( + !statement.isMulticolumn + && statementsForTable.some((st) => + st.type === 'sqlite_alter_table_add_column' && st.column.name === data.columnsFrom[0] + ) + ) { + continue; + } - if (wasRename) { - newStatements[tableName].push(...preparedStatements); - } else { - newStatements[tableName] = preparedStatements; + if (statement.isMulticolumn) { + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; } continue; } + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + newStatements[tableName].push(statement); + } + continue; } @@ -300,7 +325,6 @@ export const sqliteCombineStatements = ( || statement.type === 'alter_table_alter_column_set_autoincrement' || statement.type === 'alter_table_alter_column_drop_pk' || statement.type === 'alter_table_alter_column_set_pk' - || statement.type === 'create_reference' || statement.type === 'delete_reference' || statement.type === 'alter_reference' || statement.type === 'create_composite_pk' @@ -360,6 +384,45 @@ export const sqliteCombineStatements = ( continue; } + if (statement.type === 'create_reference') { + const tableName = statement.tableName; + + const data = action === 'push' + ? SQLiteSquasher.unsquashPushFK(statement.data) + : SQLiteSquasher.unsquashFK(statement.data); + const statementsForTable = newStatements[tableName]; + + if (!statementsForTable) { + newStatements[tableName] = prepareSQLiteRecreateTable(json2.tables[tableName], action); + continue; + } + + // if add column with reference -> skip create_reference statement + if ( + data.columnsFrom.length === 1 + && statementsForTable.some((st) => + st.type === 'sqlite_alter_table_add_column' && st.column.name === data.columnsFrom[0] + ) + ) { + continue; + } + + if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { + const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); + const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + + if (wasRename) { + newStatements[tableName].push(...preparedStatements); + } else { + newStatements[tableName] = preparedStatements; + } + + continue; + } + + continue; + } + const tableName = statement.type === 'rename_table' ? statement.tableNameTo : (statement as { tableName: string }).tableName; diff --git a/drizzle-kit/tests/cli-generate.test.ts b/drizzle-kit/tests/cli-generate.test.ts index 3e5c0fc22..6eece0249 100644 --- a/drizzle-kit/tests/cli-generate.test.ts +++ b/drizzle-kit/tests/cli-generate.test.ts @@ -38,6 +38,7 @@ test('generate #1', async (t) => { schema: 'schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -57,11 +58,13 @@ test('generate #2', async (t) => { schema: 'schema.ts', out: 'out', bundle: false, + driver: undefined, }); }); test('generate #3', async (t) => { const res = await brotest(generate, ''); + if (res.type !== 'handler') assert.fail(res.type, 'handler'); expect(res.options).toStrictEqual({ dialect: 'postgresql', @@ -72,6 +75,7 @@ test('generate #3', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -89,6 +93,7 @@ test('generate #4', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -105,6 +110,7 @@ test('generate #5', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -121,6 +127,7 @@ test('generate #6', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -140,6 +147,7 @@ test('generate #7', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + driver: undefined, }); }); @@ -157,6 +165,7 @@ test('generate #8', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: true, // expo driver + driver: 'expo', }); }); @@ -177,6 +186,7 @@ test('generate #9', async (t) => { schema: 'schema.ts', out: 'out', bundle: false, + driver: undefined, }); }); diff --git a/drizzle-kit/tests/cli-push.test.ts b/drizzle-kit/tests/cli-push.test.ts index 1a4bde66d..fb1ed3a11 100644 --- a/drizzle-kit/tests/cli-push.test.ts +++ b/drizzle-kit/tests/cli-push.test.ts @@ -46,6 +46,7 @@ test('push #2', async (t) => { tablesFilter: [], strict: false, verbose: false, + driver: 'turso', }); }); @@ -66,6 +67,7 @@ test('push #3', async (t) => { tablesFilter: [], strict: false, verbose: false, + driver: 'd1-http', }); }); diff --git a/drizzle-kit/tests/libsql-statements.test.ts b/drizzle-kit/tests/libsql-statements.test.ts index adf354458..927411e44 100644 --- a/drizzle-kit/tests/libsql-statements.test.ts +++ b/drizzle-kit/tests/libsql-statements.test.ts @@ -833,3 +833,44 @@ test('drop foriegn key for multiple columns', async (t) => { `DROP TABLE \`__old__generate_users\`;`, ); }); + +test('alter column drop generated', async (t) => { + const from = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').generatedAlwaysAs('drizzle is the best').notNull(), + }), + }; + + const to = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').notNull(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + from, + to, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'table', + type: 'alter_table_alter_column_drop_generated', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TABLE \`table\` DROP COLUMN \`name\`;`); + expect(sqlStatements[1]).toBe(`ALTER TABLE \`table\` ADD \`name\` text NOT NULL;`); +}); diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index 8a258072a..e71b95e01 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -8,6 +8,7 @@ import { sqliteTable, text, } from 'drizzle-orm/sqlite-core'; +import { JsonRecreateTableStatement } from 'src/jsonStatements'; import { expect, test } from 'vitest'; import { diffTestSchemasSqlite } from './schemaDiffer'; @@ -223,7 +224,7 @@ test('add columns #5', async (t) => { const { statements } = await diffTestSchemasSqlite(schema1, schema2, []); // TODO: Fix here - expect(statements.length).toBe(2); + expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'sqlite_alter_table_add_column', tableName: 'users', @@ -332,12 +333,38 @@ test('add foreign key #1', async (t) => { const { statements } = await diffTestSchemasSqlite(schema1, schema2, []); expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'create_reference', - tableName: 'users', - schema: '', - data: 'users_report_to_users_id_fk;users;report_to;users;id;no action;no action', - }); + expect(statements[0]).toStrictEqual( + { + type: 'recreate_table', + columns: [{ + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, { + autoincrement: false, + generated: undefined, + name: 'report_to', + notNull: false, + primaryKey: false, + type: 'integer', + }], + compositePKs: [], + referenceData: [{ + columnsFrom: ['report_to'], + columnsTo: ['id'], + name: 'users_report_to_users_id_fk', + tableFrom: 'users', + tableTo: 'users', + onDelete: 'no action', + onUpdate: 'no action', + }], + tableName: 'users', + uniqueConstraints: [], + } as JsonRecreateTableStatement, + ); }); test('add foreign key #2', async (t) => { @@ -371,11 +398,35 @@ test('add foreign key #2', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'create_reference', + type: 'recreate_table', + columns: [{ + autoincrement: true, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, { + autoincrement: false, + generated: undefined, + name: 'report_to', + notNull: false, + primaryKey: false, + type: 'integer', + }], + compositePKs: [], + referenceData: [{ + columnsFrom: ['report_to'], + columnsTo: ['id'], + name: 'reportee_fk', + tableFrom: 'users', + tableTo: 'users', + onDelete: 'no action', + onUpdate: 'no action', + }], tableName: 'users', - schema: '', - data: 'reportee_fk;users;report_to;users;id;no action;no action', - }); + uniqueConstraints: [], + } as JsonRecreateTableStatement); }); test('alter column change name #1', async (t) => { @@ -513,9 +564,26 @@ test('alter table add composite pk', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'create_composite_pk', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'id1', + notNull: false, + primaryKey: false, + type: 'integer', + }, { + autoincrement: false, + generated: undefined, + name: 'id2', + notNull: false, + primaryKey: false, + type: 'integer', + }], + compositePKs: [['id1', 'id2']], + referenceData: [], tableName: 'table', - data: 'id1,id2', + uniqueConstraints: [], }); }); @@ -540,16 +608,19 @@ test('alter column drop not null', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'alter_table_alter_column_drop_notnull', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + }], + compositePKs: [], + referenceData: [], tableName: 'table', - columnName: 'name', - schema: '', - newDataType: 'text', - columnDefault: undefined, - columnOnUpdate: undefined, - columnNotNull: false, - columnAutoIncrement: false, - columnPk: false, + uniqueConstraints: [], }); }); @@ -574,16 +645,19 @@ test('alter column add not null', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'alter_table_alter_column_set_notnull', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: true, + primaryKey: false, + type: 'text', + }], + compositePKs: [], + referenceData: [], tableName: 'table', - columnName: 'name', - schema: '', - newDataType: 'text', - columnDefault: undefined, - columnOnUpdate: undefined, - columnNotNull: true, - columnAutoIncrement: false, - columnPk: false, + uniqueConstraints: [], }); }); @@ -608,16 +682,20 @@ test('alter column add default', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'alter_table_alter_column_set_default', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + default: "'dan'", + }], + compositePKs: [], + referenceData: [], tableName: 'table', - columnName: 'name', - schema: '', - newDataType: 'text', - columnNotNull: false, - columnOnUpdate: undefined, - columnAutoIncrement: false, - newDefaultValue: "'dan'", - columnPk: false, + uniqueConstraints: [], }); }); @@ -642,16 +720,19 @@ test('alter column drop default', async (t) => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - type: 'alter_table_alter_column_drop_default', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + }], + compositePKs: [], + referenceData: [], tableName: 'table', - columnName: 'name', - schema: '', - newDataType: 'text', - columnNotNull: false, - columnOnUpdate: undefined, - columnDefault: undefined, - columnAutoIncrement: false, - columnPk: false, + uniqueConstraints: [], }); }); @@ -674,31 +755,22 @@ test('alter column add default not null', async (t) => { [], ); - expect(statements.length).toBe(2); - expect(statements[0]).toStrictEqual({ - columnAutoIncrement: false, - columnName: 'name', - columnNotNull: true, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - newDefaultValue: "'dan'", - schema: '', - tableName: 'table', - type: 'alter_table_alter_column_set_default', - }); - + expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - columnAutoIncrement: false, - columnName: 'name', - columnNotNull: true, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - newDefaultValue: "'dan'", - schema: '', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: true, + primaryKey: false, + type: 'text', + default: "'dan'", + }], + compositePKs: [], + referenceData: [], tableName: 'table', - type: 'alter_table_alter_column_set_default', + uniqueConstraints: [], }); }); @@ -721,30 +793,61 @@ test('alter column drop default not null', async (t) => { [], ); - expect(statements.length).toBe(2); + expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - columnAutoIncrement: false, - columnDefault: undefined, - columnName: 'name', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + }], + compositePKs: [], + referenceData: [], tableName: 'table', - type: 'alter_table_alter_column_drop_default', + uniqueConstraints: [], }); +}); +test('alter column drop generated', async (t) => { + const from = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').generatedAlwaysAs('drizzle is the best').notNull(), + }), + }; + + const to = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').notNull(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite( + from, + to, + [], + ); + + expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ columnAutoIncrement: false, columnDefault: undefined, + columnGenerated: undefined, columnName: 'name', - columnNotNull: false, + columnNotNull: true, columnOnUpdate: undefined, columnPk: false, newDataType: 'text', schema: '', tableName: 'table', - type: 'alter_table_alter_column_drop_default', + type: 'alter_table_alter_column_drop_generated', }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TABLE \`table\` DROP COLUMN \`name\`;`); + expect(sqlStatements[1]).toBe(`ALTER TABLE \`table\` ADD \`name\` text NOT NULL;`); }); diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index d7781f150..aa44908ba 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -162,6 +162,13 @@ test('add table #7', async () => { expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ + type: 'rename_table', + tableNameFrom: 'users1', + tableNameTo: 'users2', + fromSchema: undefined, + toSchema: undefined, + }); + expect(statements[1]).toStrictEqual({ type: 'sqlite_create_table', tableName: 'users', columns: [], @@ -169,13 +176,6 @@ test('add table #7', async () => { uniqueConstraints: [], referenceData: [], }); - expect(statements[1]).toStrictEqual({ - type: 'rename_table', - tableNameFrom: 'users1', - tableNameTo: 'users2', - fromSchema: undefined, - toSchema: undefined, - }); }); test('add table #8', async () => { diff --git a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts index 012ea1eac..342e55232 100644 --- a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts @@ -1,5 +1,6 @@ -import { JsonStatement } from 'src/jsonStatements'; +import { JsonAddColumnStatement, JsonSqliteAddColumnStatement, JsonStatement } from 'src/jsonStatements'; import { SQLiteSchemaSquashed } from 'src/serializer/sqliteSchema'; +import { SQLiteAlterTableAddColumnConvertor } from 'src/sqlgenerator'; import { libSQLCombineStatements } from 'src/statementCombiner'; import { expect, test } from 'vitest'; @@ -1207,3 +1208,552 @@ test(`set new type for primary key, unique and normal column`, async (t) => { newJsonStatements, ); }); + +test(`add columns. set fk`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_new_age_user_new_age_fk: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`add column and fk`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_test1_user_new_age_fk: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_new_age_user_new_age_fk: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`add column and fk`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_test1_user_new_age_fk: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_new_age_user_new_age_fk: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + ]; + expect(libSQLCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); diff --git a/drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts similarity index 66% rename from drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts rename to drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts index 517343d9b..2fcaf6436 100644 --- a/drizzle-kit/tests/statements-combiner/sqilte-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts @@ -776,3 +776,395 @@ test(`create reference on exising column (table includes unique index). expect t newJsonStatements, ); }); + +test(`add columns. set fk`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: undefined, + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_new_age_user_new_age_fk: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + columns: [ + { + autoincrement: false, + name: 'id1', + notNull: true, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'new_age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + name: 'test', + notNull: false, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + name: 'test1', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [ + { + columnsFrom: [ + 'new_age', + ], + columnsTo: [ + 'new_age', + ], + name: 'ref_new_age_user_new_age_fk', + onDelete: 'no action', + onUpdate: 'no action', + tableFrom: 'ref', + tableTo: 'user', + }, + ], + tableName: 'ref', + type: 'recreate_table', + uniqueConstraints: [], + }, + ]; + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); + +test(`add column and fk`, async (t) => { + const statements: JsonStatement[] = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + { + type: 'create_reference', + tableName: 'ref', + data: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + schema: '', + columnNotNull: false, + columnDefault: undefined, + columnType: 'integer', + }, + ]; + const json1: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_test1_user_new_age_fk: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + const json2: SQLiteSchemaSquashed = { + version: '6', + dialect: 'sqlite', + tables: { + ref: { + name: 'ref', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test: { + name: 'test', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + test1: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: { + ref_new_age_user_new_age_fk: 'ref_new_age_user_new_age_fk;ref;new_age;user;new_age;no action;no action', + }, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + user: { + name: 'user', + columns: { + id1: { + name: 'id1', + type: 'text', + primaryKey: false, + notNull: true, + autoincrement: false, + }, + new_age: { + name: 'new_age', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + }, + indexes: {}, + foreignKeys: {}, + compositePrimaryKeys: {}, + uniqueConstraints: {}, + }, + }, + enums: {}, + }; + + const newJsonStatements = [ + { + type: 'sqlite_alter_table_add_column', + tableName: 'ref', + column: { + name: 'test1', + type: 'integer', + primaryKey: false, + notNull: false, + autoincrement: false, + }, + referenceData: 'ref_test1_user_new_age_fk;ref;test1;user;new_age;no action;no action', + }, + ]; + expect(sqliteCombineStatements(statements, json2)).toStrictEqual( + newJsonStatements, + ); +}); From 0c182cdcce5d8e7a0822695ad29da0fadd34e52b Mon Sep 17 00:00:00 2001 From: Alex Blokh Date: Tue, 13 Aug 2024 19:10:55 +0300 Subject: [PATCH 067/492] update brocli version --- drizzle-kit/package.json | 4 +- drizzle-kit/src/cli/index.ts | 1 + pnpm-lock.yaml | 452 ++++++++++++++--------------------- 3 files changed, 185 insertions(+), 272 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 25297e5b9..f94d41375 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -42,7 +42,7 @@ "publish": "npm publish package.tgz" }, "dependencies": { - "@drizzle-team/brocli": "^0.8.2", + "@drizzle-team/brocli": "^0.10.0", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.19.7", "esbuild-register": "^3.5.0" @@ -92,7 +92,7 @@ "hono": "^4.1.5", "json-diff": "1.0.6", "minimatch": "^7.4.3", - "mysql2": "2.3.3", + "mysql2": "3.3.3", "node-fetch": "^3.3.2", "pg": "^8.11.5", "pluralize": "^8.0.0", diff --git a/drizzle-kit/src/cli/index.ts b/drizzle-kit/src/cli/index.ts index a7272ffef..21e52e116 100644 --- a/drizzle-kit/src/cli/index.ts +++ b/drizzle-kit/src/cli/index.ts @@ -43,5 +43,6 @@ const legacy = [ ]; run([generate, migrate, pull, push, studio, up, check, drop, ...legacy], { + name: "drizzle-kit", version: version, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2fb00d93d..28a7e0c9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.6.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@10.0.0)(bun-types@1.0.3)(knex@3.1.0(better-sqlite3@10.0.0)(mysql2@3.9.8)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.27.3)(mysql2@3.9.8)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -78,7 +78,7 @@ importers: version: 0.8.16(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) tsx: specifier: ^4.10.5 version: 4.10.5 @@ -92,8 +92,8 @@ importers: drizzle-kit: dependencies: '@drizzle-team/brocli': - specifier: ^0.8.2 - version: 0.8.2 + specifier: ^0.10.0 + version: 0.10.0 '@esbuild-kit/esm-loader': specifier: ^2.5.5 version: 2.5.5 @@ -237,8 +237,8 @@ importers: specifier: ^7.4.3 version: 7.4.6 mysql2: - specifier: 2.3.3 - version: 2.3.3 + specifier: 3.3.3 + version: 3.3.3 node-fetch: specifier: ^3.3.2 version: 3.3.2 @@ -310,7 +310,7 @@ importers: version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -358,7 +358,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -1974,8 +1974,8 @@ packages: cpu: [x64] os: [win32] - '@drizzle-team/brocli@0.8.2': - resolution: {integrity: sha512-zTrFENsqGvOkBOuHDC1pXCkDXNd2UhP4lI3gYGhQ1R1SPeAAfqzPsV1dcpMy4uNU6kB5VpU5NGhvwxVNETR02A==} + '@drizzle-team/brocli@0.10.0': + resolution: {integrity: sha512-razqxuTZizzm14gtockWvc3L0m320QuuzTgeNmX3e32dE5JWQ5jhb5tjnFpdkHFQGoYSDXrhEQgRPZ74kB+8cw==} '@drizzle-team/studio@0.0.5': resolution: {integrity: sha512-ps5qF0tMxWRVu+V5gvCRrQNqlY92aTnIKdq27gm9LZMSdaKYZt6AVvSK1dlUMzs6Rt0Jm80b+eWct6xShBKhIw==} @@ -3084,18 +3084,12 @@ packages: '@libsql/client@0.5.6': resolution: {integrity: sha512-UBjmDoxz75Z2sHdP+ETCROpeLA/77VMesiff8R4UWK1rnaWbh6/YoCLDILMJL3Rh0udQeKxjL8MjXthqohax+g==} - '@libsql/client@0.6.0': - resolution: {integrity: sha512-qhQzTG/y2IEVbL3+9PULDvlQFWJ/RnjFXECr/Nc3nRngGiiMysDaOV5VUzYk7DulUX98EA4wi+z3FspKrUplUA==} - '@libsql/core@0.4.3': resolution: {integrity: sha512-r28iYBtaLBW9RRgXPFh6cGCsVI/rwRlOzSOpAu/1PVTm6EJ3t233pUf97jETVHU0vjdr1d8VvV6fKAvJkokqCw==} '@libsql/core@0.5.6': resolution: {integrity: sha512-3vicUAydq6jPth410n4AsHHm1n2psTwvkSf94nfJlSXutGSZsl0updn2N/mJBgqUHkbuFoWZtlMifF0SwBj1xQ==} - '@libsql/core@0.6.0': - resolution: {integrity: sha512-affAB8vSqQwqI9NBDJ5uJCVaHoOAS2pOpbv1kWConh1SBbmJBnHHd4KG73RAJ2sgd2+NbT9WA+XJBqxgp28YSw==} - '@libsql/darwin-arm64@0.2.0': resolution: {integrity: sha512-+qyT2W/n5CFH1YZWv2mxW4Fsoo4dX9Z9M/nvbQqZ7H84J8hVegvVAsIGYzcK8xAeMEcpU5yGKB1Y9NoDY4hOSQ==} cpu: [arm64] @@ -3119,15 +3113,9 @@ packages: '@libsql/hrana-client@0.5.6': resolution: {integrity: sha512-mjQoAmejZ1atG+M3YR2ZW+rg6ceBByH/S/h17ZoYZkqbWrvohFhXyz2LFxj++ARMoY9m6w3RJJIRdJdmnEUlFg==} - '@libsql/hrana-client@0.6.0': - resolution: {integrity: sha512-k+fqzdjqg3IvWfKmVJK5StsbjeTcyNAXFelUbXbGNz3yH1gEVT9mZ6kmhsIXP30ZSyVV0AE1Gi25p82mxC9hwg==} - '@libsql/isomorphic-fetch@0.1.12': resolution: {integrity: sha512-MRo4UcmjAGAa3ac56LoD5OE13m2p0lu0VEtZC2NZMcogM/jc5fU9YtMQ3qbPjFJ+u2BBjFZgMPkQaLS1dlMhpg==} - '@libsql/isomorphic-fetch@0.2.1': - resolution: {integrity: sha512-Sv07QP1Aw8A5OOrmKgRUBKe2fFhF2hpGJhtHe3d1aRnTESZCGkn//0zDycMKTGamVWb3oLYRroOsCV8Ukes9GA==} - '@libsql/isomorphic-ws@0.1.5': resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} @@ -4642,6 +4630,10 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + aws-ssl-profiles@1.1.1: + resolution: {integrity: sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==} + engines: {node: '>= 6.0.0'} + axios@1.6.8: resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} @@ -4687,9 +4679,6 @@ packages: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} - better-sqlite3@10.0.0: - resolution: {integrity: sha512-rOz0JY8bt9oMgrFssP7GnvA5R3yln73y/NizzWqy3WlFth8Ux8+g4r/N9fjX97nn4X1YX6MTER2doNpTu5pqiA==} - better-sqlite3@8.7.0: resolution: {integrity: sha512-99jZU4le+f3G6aIl6PmmV0cxUIWqKieHxsiF7G34CVFiE+/UabpYqkU0NJIkY/96mQKikHeBjtR27vFfs5JpEw==} @@ -7091,42 +7080,10 @@ packages: tedious: optional: true - knex@3.1.0: - resolution: {integrity: sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw==} - engines: {node: '>=16'} - hasBin: true - peerDependencies: - better-sqlite3: '*' - mysql: '*' - mysql2: '*' - pg: '*' - pg-native: '*' - sqlite3: '*' - tedious: '*' - peerDependenciesMeta: - better-sqlite3: - optional: true - mysql: - optional: true - mysql2: - optional: true - pg: - optional: true - pg-native: - optional: true - sqlite3: - optional: true - tedious: - optional: true - kysely@0.25.0: resolution: {integrity: sha512-srn0efIMu5IoEBk0tBmtGnoUss4uwvxtbFQWG/U2MosfqIace1l43IFP1PmEpHRDp+Z79xIcKEqmHH3dAvQdQA==} engines: {node: '>=14.0.0'} - kysely@0.27.3: - resolution: {integrity: sha512-lG03Ru+XyOJFsjH3OMY6R/9U38IjDPfnOfDgO3ynhbDr+Dz8fak+X6L62vqu3iybQnj+lG84OttBuU9KY3L9kA==} - engines: {node: '>=14.0.0'} - leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -7323,9 +7280,6 @@ packages: resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==} hasBin: true - long@4.0.0: - resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} - long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} @@ -7672,18 +7626,14 @@ packages: resolution: {integrity: sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==} engines: {node: '>=0.8.0'} - mysql2@2.3.3: - resolution: {integrity: sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==} + mysql2@3.11.0: + resolution: {integrity: sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==} engines: {node: '>= 8.0'} mysql2@3.3.3: resolution: {integrity: sha512-MxDQJztArk4JFX1PKVjDhIXRzAmVJfuqZrVU+my6NeYBAA/XZRaDw5q7vga8TNvgyy3Lv3rivBFBBuJFbsdjaw==} engines: {node: '>= 8.0'} - mysql2@3.9.8: - resolution: {integrity: sha512-+5JKNjPuks1FNMoy9TYpl77f+5frbTklz7eb3XDwbpsERRLEeXiW2PDEkakYF50UuKU2qwfGnyXpKYvukv8mGA==} - engines: {node: '>= 8.0'} - mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -8118,9 +8068,6 @@ packages: pg-connection-string@2.6.1: resolution: {integrity: sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==} - pg-connection-string@2.6.2: - resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} - pg-connection-string@2.6.4: resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} @@ -10347,6 +10294,52 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0)': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/core': 3.567.0 + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/middleware-host-header': 3.567.0 + '@aws-sdk/middleware-logger': 3.568.0 + '@aws-sdk/middleware-recursion-detection': 3.567.0 + '@aws-sdk/middleware-user-agent': 3.567.0 + '@aws-sdk/region-config-resolver': 3.567.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@aws-sdk/util-user-agent-browser': 3.567.0 + '@aws-sdk/util-user-agent-node': 3.568.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/client-sts' + - aws-crt + '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 @@ -10570,9 +10563,9 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.569.0 + '@aws-sdk/client-sso-oidc': 3.569.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 '@aws-sdk/middleware-logger': 3.568.0 '@aws-sdk/middleware-recursion-detection': 3.567.0 @@ -10611,52 +10604,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - '@aws-sdk/client-sts@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 @@ -10801,13 +10748,13 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))(@aws-sdk/client-sts@3.569.0)': dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/client-sts': 3.569.0 '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10820,7 +10767,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/client-sts': 3.569.0 '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) @@ -10835,13 +10782,13 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0)': dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/client-sts': 3.569.0 '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10885,14 +10832,14 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))(@aws-sdk/client-sts@3.569.0) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10923,14 +10870,14 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10997,6 +10944,19 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))': + dependencies: + '@aws-sdk/client-sso': 3.568.0 + '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0)) + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)': dependencies: '@aws-sdk/client-sso': 3.568.0 @@ -11043,14 +11003,6 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/client-sts': 3.569.0 @@ -11071,15 +11023,15 @@ snapshots: dependencies: '@aws-sdk/client-cognito-identity': 3.569.0 '@aws-sdk/client-sso': 3.568.0 - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/client-sts': 3.569.0 '@aws-sdk/credential-provider-cognito-identity': 3.569.0 '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -11251,6 +11203,15 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))': + dependencies: + '@aws-sdk/client-sso-oidc': 3.569.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.6.2 + '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)': dependencies: '@aws-sdk/client-sso-oidc': 3.569.0 @@ -12411,7 +12372,7 @@ snapshots: '@dprint/win32-x64@0.46.3': optional: true - '@drizzle-team/brocli@0.8.2': {} + '@drizzle-team/brocli@0.10.0': {} '@drizzle-team/studio@0.0.5': {} @@ -12943,7 +12904,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -12961,7 +12922,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13404,17 +13365,6 @@ snapshots: - encoding - utf-8-validate - '@libsql/client@0.6.0': - dependencies: - '@libsql/core': 0.6.0 - '@libsql/hrana-client': 0.6.0 - js-base64: 3.7.7 - libsql: 0.3.18 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - optional: true - '@libsql/core@0.4.3': dependencies: js-base64: 3.7.7 @@ -13423,11 +13373,6 @@ snapshots: dependencies: js-base64: 3.7.7 - '@libsql/core@0.6.0': - dependencies: - js-base64: 3.7.7 - optional: true - '@libsql/darwin-arm64@0.2.0': optional: true @@ -13451,17 +13396,6 @@ snapshots: - encoding - utf-8-validate - '@libsql/hrana-client@0.6.0': - dependencies: - '@libsql/isomorphic-fetch': 0.2.1 - '@libsql/isomorphic-ws': 0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3) - js-base64: 3.7.7 - node-fetch: 3.3.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - optional: true - '@libsql/isomorphic-fetch@0.1.12(encoding@0.1.13)': dependencies: '@types/node-fetch': 2.6.11 @@ -13469,9 +13403,6 @@ snapshots: transitivePeerDependencies: - encoding - '@libsql/isomorphic-fetch@0.2.1': - optional: true - '@libsql/isomorphic-ws@0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: '@types/ws': 8.5.11 @@ -13587,10 +13518,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) '@opentelemetry/api@1.8.0': {} @@ -13727,7 +13658,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13737,7 +13668,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13764,14 +13695,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13860,16 +13791,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13884,7 +13815,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13898,7 +13829,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13921,12 +13852,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) optionalDependencies: '@types/react': 18.3.1 @@ -15508,6 +15439,9 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 + aws-ssl-profiles@1.1.1: + optional: true + axios@1.6.8: dependencies: follow-redirects: 1.15.6 @@ -15580,12 +15514,6 @@ snapshots: dependencies: open: 8.4.2 - better-sqlite3@10.0.0: - dependencies: - bindings: 1.5.0 - prebuild-install: 7.1.2 - optional: true - better-sqlite3@8.7.0: dependencies: bindings: 1.5.0 @@ -16399,11 +16327,11 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.6.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@10.0.0)(bun-types@1.0.3)(knex@3.1.0(better-sqlite3@10.0.0)(mysql2@3.9.8)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.27.3)(mysql2@3.9.8)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 '@cloudflare/workers-types': 4.20240524.0 - '@libsql/client': 0.6.0 + '@libsql/client': 0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@neondatabase/serverless': 0.9.3 '@opentelemetry/api': 1.8.0 '@planetscale/database': 1.18.0 @@ -16411,11 +16339,11 @@ snapshots: '@types/pg': 8.11.6 '@types/sql.js': 1.4.9 '@vercel/postgres': 0.8.0 - better-sqlite3: 10.0.0 + better-sqlite3: 9.6.0 bun-types: 1.0.3 - knex: 3.1.0(better-sqlite3@10.0.0)(mysql2@3.9.8)(pg@8.11.5)(sqlite3@5.1.7) - kysely: 0.27.3 - mysql2: 3.9.8 + knex: 2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7) + kysely: 0.25.0 + mysql2: 3.11.0 pg: 8.11.5 postgres: 3.4.4 sql.js: 1.10.3 @@ -17240,35 +17168,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) expo-modules-autolinking@1.11.1: dependencies: @@ -17282,24 +17210,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -18406,7 +18334,7 @@ snapshots: transitivePeerDependencies: - supports-color - knex@3.1.0(better-sqlite3@10.0.0)(mysql2@3.9.8)(pg@8.11.5)(sqlite3@5.1.7): + knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7): dependencies: colorette: 2.0.19 commander: 10.0.1 @@ -18417,14 +18345,14 @@ snapshots: getopts: 2.3.0 interpret: 2.2.0 lodash: 4.17.21 - pg-connection-string: 2.6.2 + pg-connection-string: 2.6.1 rechoir: 0.8.0 resolve-from: 5.0.0 tarn: 3.0.2 tildify: 2.0.0 optionalDependencies: - better-sqlite3: 10.0.0 - mysql2: 3.9.8 + better-sqlite3: 9.6.0 + mysql2: 3.11.0 pg: 8.11.5 sqlite3: 5.1.7 transitivePeerDependencies: @@ -18433,9 +18361,6 @@ snapshots: kysely@0.25.0: {} - kysely@0.27.3: - optional: true - leven@3.1.0: {} levn@0.4.1: @@ -18613,8 +18538,6 @@ snapshots: dayjs: 1.11.11 yargs: 15.4.1 - long@4.0.0: {} - long@5.2.3: {} loose-envify@1.4.0: @@ -18780,12 +18703,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18861,13 +18784,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18881,7 +18804,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -18907,7 +18830,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -18915,7 +18838,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -18924,7 +18847,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -19079,19 +19002,9 @@ snapshots: rimraf: 2.4.5 optional: true - mysql2@2.3.3: - dependencies: - denque: 2.1.0 - generate-function: 2.3.1 - iconv-lite: 0.6.3 - long: 4.0.0 - lru-cache: 6.0.0 - named-placeholders: 1.1.3 - seq-queue: 0.0.5 - sqlstring: 2.3.3 - - mysql2@3.3.3: + mysql2@3.11.0: dependencies: + aws-ssl-profiles: 1.1.1 denque: 2.1.0 generate-function: 2.3.1 iconv-lite: 0.6.3 @@ -19100,8 +19013,9 @@ snapshots: named-placeholders: 1.1.3 seq-queue: 0.0.5 sqlstring: 2.3.3 + optional: true - mysql2@3.9.8: + mysql2@3.3.3: dependencies: denque: 2.1.0 generate-function: 2.3.1 @@ -19111,7 +19025,6 @@ snapshots: named-placeholders: 1.1.3 seq-queue: 0.0.5 sqlstring: 2.3.3 - optional: true mz@2.7.0: dependencies: @@ -19541,9 +19454,6 @@ snapshots: pg-connection-string@2.6.1: {} - pg-connection-string@2.6.2: - optional: true - pg-connection-string@2.6.4: {} pg-int8@1.0.1: {} @@ -19631,7 +19541,7 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))): dependencies: lilconfig: 2.1.0 yaml: 2.3.1 @@ -19821,10 +19731,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8): + react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19837,19 +19747,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19868,14 +19778,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8) + react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -20890,7 +20800,7 @@ snapshots: tslib@2.6.2: {} - tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): dependencies: bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 @@ -20900,7 +20810,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))) resolve-from: 5.0.0 rollup: 3.27.2 source-map: 0.8.0-beta.0 @@ -21728,15 +21638,17 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8): + ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8): + ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From 169e795ea4e0c9a1bfd707ce3b852ef87730894d Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 14 Aug 2024 11:22:25 +0300 Subject: [PATCH 068/492] Fix introspect checks --- drizzle-kit/src/cli/commands/utils.ts | 6 +++--- drizzle-kit/src/cli/validations/cli.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 9f65318a6..4957816c8 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -412,7 +412,7 @@ export const preparePullConfig = async ( credentials: parsed.data, tablesFilter, schemasFilter, - prefix: config.database?.prefix || 'index', + prefix: config.migrations?.prefix || 'index', }; } @@ -430,7 +430,7 @@ export const preparePullConfig = async ( credentials: parsed.data, tablesFilter, schemasFilter, - prefix: config.database?.prefix || 'index', + prefix: config.migrations?.prefix || 'index', }; } @@ -448,7 +448,7 @@ export const preparePullConfig = async ( credentials: parsed.data, tablesFilter, schemasFilter, - prefix: config.database?.prefix || 'index', + prefix: config.migrations?.prefix || 'index', }; } diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index 67e118a98..53e8dadb8 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -40,7 +40,7 @@ export const pullParams = object({ extensionsFilters: literal('postgis').array().optional(), introspectCasing: casing, breakpoints: boolean().optional().default(true), - database: object({ + migrations: object({ prefix: prefix.optional().default('index'), }).optional(), }).passthrough(); From f599a9ccdf1b21c29488a52160524a6fc318f65e Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 14 Aug 2024 11:25:37 +0300 Subject: [PATCH 069/492] Fix formatting --- drizzle-kit/src/cli/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-kit/src/cli/index.ts b/drizzle-kit/src/cli/index.ts index 21e52e116..86bffdf3d 100644 --- a/drizzle-kit/src/cli/index.ts +++ b/drizzle-kit/src/cli/index.ts @@ -43,6 +43,6 @@ const legacy = [ ]; run([generate, migrate, pull, push, studio, up, check, drop, ...legacy], { - name: "drizzle-kit", + name: 'drizzle-kit', version: version, }); From 6386ea9d1236d3d1b326c365a5c99bcf52d4a1b4 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 14 Aug 2024 11:26:08 +0300 Subject: [PATCH 070/492] Upgrade brocli --- drizzle-kit/package.json | 2 +- pnpm-lock.yaml | 300 ++++++++++++++++++--------------------- 2 files changed, 143 insertions(+), 159 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index f94d41375..676a7f1d4 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -42,7 +42,7 @@ "publish": "npm publish package.tgz" }, "dependencies": { - "@drizzle-team/brocli": "^0.10.0", + "@drizzle-team/brocli": "^0.10.1", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.19.7", "esbuild-register": "^3.5.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28a7e0c9f..83948e4cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.5.6)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -78,7 +78,7 @@ importers: version: 0.8.16(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) tsx: specifier: ^4.10.5 version: 4.10.5 @@ -92,8 +92,8 @@ importers: drizzle-kit: dependencies: '@drizzle-team/brocli': - specifier: ^0.10.0 - version: 0.10.0 + specifier: ^0.10.1 + version: 0.10.1 '@esbuild-kit/esm-loader': specifier: ^2.5.5 version: 2.5.5 @@ -310,7 +310,7 @@ importers: version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -358,7 +358,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -1974,8 +1974,8 @@ packages: cpu: [x64] os: [win32] - '@drizzle-team/brocli@0.10.0': - resolution: {integrity: sha512-razqxuTZizzm14gtockWvc3L0m320QuuzTgeNmX3e32dE5JWQ5jhb5tjnFpdkHFQGoYSDXrhEQgRPZ74kB+8cw==} + '@drizzle-team/brocli@0.10.1': + resolution: {integrity: sha512-AHy0vjc+n/4w/8Mif+w86qpppHuF3AyXbcWW+R/W7GNA3F5/p2nuhlkCJaTXSLZheB4l1rtHzOfr9A7NwoR/Zg==} '@drizzle-team/studio@0.0.5': resolution: {integrity: sha512-ps5qF0tMxWRVu+V5gvCRrQNqlY92aTnIKdq27gm9LZMSdaKYZt6AVvSK1dlUMzs6Rt0Jm80b+eWct6xShBKhIw==} @@ -10294,52 +10294,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0)': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.569.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sts' - - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 @@ -10563,9 +10517,9 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.569.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/client-sso-oidc': 3.569.0 '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 '@aws-sdk/middleware-logger': 3.568.0 '@aws-sdk/middleware-recursion-detection': 3.567.0 @@ -10604,6 +10558,52 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.569.0 + '@aws-sdk/core': 3.567.0 + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/middleware-host-header': 3.567.0 + '@aws-sdk/middleware-logger': 3.568.0 + '@aws-sdk/middleware-recursion-detection': 3.567.0 + '@aws-sdk/middleware-user-agent': 3.567.0 + '@aws-sdk/region-config-resolver': 3.567.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@aws-sdk/util-user-agent-browser': 3.567.0 + '@aws-sdk/util-user-agent-node': 3.568.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + '@aws-sdk/client-sts@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 @@ -10748,13 +10748,13 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))(@aws-sdk/client-sts@3.569.0)': + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0)) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10767,7 +10767,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) @@ -10782,13 +10782,13 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0)': + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10832,14 +10832,14 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))(@aws-sdk/client-sts@3.569.0)': + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0)) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10870,14 +10870,14 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0)': + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10944,19 +10944,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))': - dependencies: - '@aws-sdk/client-sso': 3.568.0 - '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)': dependencies: '@aws-sdk/client-sso': 3.568.0 @@ -11003,6 +10990,14 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 + '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + dependencies: + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.6.2 + '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/client-sts': 3.569.0 @@ -11023,15 +11018,15 @@ snapshots: dependencies: '@aws-sdk/client-cognito-identity': 3.569.0 '@aws-sdk/client-sso': 3.568.0 - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/credential-provider-cognito-identity': 3.569.0 '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -11203,15 +11198,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.569.0(@aws-sdk/client-sts@3.569.0))': - dependencies: - '@aws-sdk/client-sso-oidc': 3.569.0(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)': dependencies: '@aws-sdk/client-sso-oidc': 3.569.0 @@ -12372,7 +12358,7 @@ snapshots: '@dprint/win32-x64@0.46.3': optional: true - '@drizzle-team/brocli@0.10.0': {} + '@drizzle-team/brocli@0.10.1': {} '@drizzle-team/studio@0.0.5': {} @@ -12904,7 +12890,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -12922,7 +12908,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13518,10 +13504,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) '@opentelemetry/api@1.8.0': {} @@ -13658,7 +13644,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13668,7 +13654,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -13695,14 +13681,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13791,16 +13777,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13815,7 +13801,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13829,7 +13815,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -13852,12 +13838,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) optionalDependencies: '@types/react': 18.3.1 @@ -16327,7 +16313,7 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.5.6)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 '@cloudflare/workers-types': 4.20240524.0 @@ -17168,35 +17154,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) expo-modules-autolinking@1.11.1: dependencies: @@ -17210,24 +17196,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -18703,12 +18689,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18784,13 +18770,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18804,7 +18790,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -18830,7 +18816,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -18838,7 +18824,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -18847,7 +18833,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -19541,7 +19527,7 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))): dependencies: lilconfig: 2.1.0 yaml: 2.3.1 @@ -19731,10 +19717,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + react-devtools-core@5.2.0(bufferutil@4.0.8): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19747,19 +19733,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19778,14 +19764,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + react-devtools-core: 5.2.0(bufferutil@4.0.8) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -20800,7 +20786,7 @@ snapshots: tslib@2.6.2: {} - tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): dependencies: bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 @@ -20810,7 +20796,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))) resolve-from: 5.0.0 rollup: 3.27.2 source-map: 0.8.0-beta.0 @@ -21638,17 +21624,15 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@6.2.2(bufferutil@4.0.8): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@7.5.9(bufferutil@4.0.8): optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From bb966f75f4ce676beb36f094f4dda5350c51de64 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 15 Aug 2024 18:21:10 +0300 Subject: [PATCH 071/492] - handled foreign keys for recreate table - handled alter column with unique keys - made more tests - updated recreate sql statements order --- drizzle-kit/package.json | 2 +- .../src/cli/commands/libSqlPushUtils.ts | 74 ++- .../src/cli/commands/sqlitePushUtils.ts | 58 +- drizzle-kit/src/jsonStatements.ts | 2 +- drizzle-kit/src/sqlgenerator.ts | 486 +++------------ drizzle-kit/src/statementCombiner.ts | 24 +- drizzle-kit/tests/libsql-statements.test.ts | 335 +++++++---- drizzle-kit/tests/push/libsql.test.ts | 438 ++++++++++++-- drizzle-kit/tests/push/sqlite.test.ts | 554 ++++++++++++++---- drizzle-kit/tests/sqlite-columns.test.ts | 141 ++++- .../libsql-statements-combiner.test.ts | 28 +- 11 files changed, 1388 insertions(+), 754 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 25297e5b9..cdb0ab941 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -38,7 +38,7 @@ "build": "rm -rf ./dist && tsx build.ts && cp package.json dist/ && attw --pack dist", "build:dev": "rm -rf ./dist && tsx build.dev.ts && tsc -p tsconfig.cli-types.json && chmod +x ./dist/index.cjs", "pack": "cp package.json README.md dist/ && (cd dist && npm pack --pack-destination ..) && rm -f package.tgz && mv *.tgz package.tgz", - "tsc": "tsc -p tsconfig.build.json", + "tsc": "tsc -p tsconfig.cli-types.json", "publish": "npm publish package.tgz" }, "dependencies": { diff --git a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts index 537eee0a5..3bc9e8225 100644 --- a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts +++ b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts @@ -32,54 +32,62 @@ export const _moveDataStatements = ( ) => { const statements: string[] = []; - statements.push( - new SqliteRenameTableConvertor().convert({ - type: 'rename_table', - tableNameFrom: tableName, - tableNameTo: `__old_push_${tableName}`, - fromSchema: '', - toSchema: '', - }), - ); + const newTableName = `__new_${tableName}`; + // create table statement from a new json2 with proper name const tableColumns = Object.values(json.tables[tableName].columns); const referenceData = Object.values(json.tables[tableName].foreignKeys); const compositePKs = Object.values( json.tables[tableName].compositePrimaryKeys, ).map((it) => SQLiteSquasher.unsquashPK(it)); + const fks = referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)); + + // create new table statements.push( new SQLiteCreateTableConvertor().convert({ type: 'sqlite_create_table', - tableName: tableName, + tableName: newTableName, columns: tableColumns, - referenceData: referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)), + referenceData: fks, compositePKs, }), ); + // move data if (!dataLoss) { const columns = Object.keys(json.tables[tableName].columns).map( (c) => `"${c}"`, ); statements.push( - `INSERT INTO \`${tableName}\`(${ + `INSERT INTO \`${newTableName}\`(${ columns.join( ', ', ) - }) SELECT (${columns.join(', ')}) FROM \`__old_push_${tableName}\`;`, + }) SELECT ${columns.join(', ')} FROM \`${tableName}\`;`, ); } statements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', - tableName: `__old_push_${tableName}`, + tableName: tableName, schema: '', }), ); + // rename table + statements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: newTableName, + tableNameTo: tableName, + toSchema: '', + type: 'rename_table', + }), + ); + for (const idx of Object.values(json.tables[tableName].indexes)) { statements.push( new CreateSqliteIndexConvertor().convert({ @@ -90,7 +98,6 @@ export const _moveDataStatements = ( }), ); } - return statements; }; @@ -216,6 +223,8 @@ export const libSqlLogSuggestionsAndReturn = async ( } else if (statement.type === 'recreate_table') { const tableName = statement.tableName; + let dataLoss = false; + const oldTableName = getOldTableName(tableName, meta); const prevColumnNames = Object.keys(json1.tables[oldTableName].columns); @@ -249,28 +258,31 @@ export const libSqlLogSuggestionsAndReturn = async ( if (addedColumns.length) { for (const addedColumn of addedColumns) { const [res] = await connection.query<{ count: string }>( - `select count(\`${tableName}\`.\`${addedColumn}\`) as count from \`${tableName}\``, + `select count(*) as count from \`${tableName}\``, ); const columnConf = json2.tables[tableName].columns[addedColumn]; const count = Number(res.count); if (count > 0 && columnConf.notNull && !columnConf.default) { + dataLoss = true; + infoToPrint.push( `· You're about to add not-null ${ chalk.underline( addedColumn, ) - } column without default value, which contains ${count} items`, + } column without default value to table, which contains ${count} items`, ); shouldAskForApprove = true; tablesToTruncate.push(tableName); + + statementsToExecute.push(`DELETE FROM \`${tableName}\`;`); } } } - statementsToExecute.push(..._moveDataStatements(tableName, json2)); - + // check if some tables referencing current for pragma const tablesReferencingCurrent: string[] = []; for (const table of Object.values(json2.tables)) { @@ -281,12 +293,26 @@ export const libSqlLogSuggestionsAndReturn = async ( tablesReferencingCurrent.push(...tablesRefs); } - const uniqueTableRefs = [...new Set(tablesReferencingCurrent)]; - - for (const table of uniqueTableRefs) { - statementsToExecute.push(..._moveDataStatements(table, json2)); + if (!tablesReferencingCurrent.length) { + statementsToExecute.push(..._moveDataStatements(tableName, json2, dataLoss)); + continue; } - } else if (statement.type === 'alter_table_alter_column_set_generated') { + + // ! for libsql it will break + const [{ foreign_keys: pragmaState }] = await connection.query<{ + foreign_keys: number; + }>(`PRAGMA foreign_keys;`); + + if (pragmaState) statementsToExecute.push(`PRAGMA foreign_keys=OFF;`); + // recreate table + statementsToExecute.push( + ..._moveDataStatements(tableName, json2, dataLoss), + ); + if (pragmaState) statementsToExecute.push(`PRAGMA foreign_keys=ON;`); + } else if ( + statement.type === 'alter_table_alter_column_set_generated' + || statement.type === 'alter_table_alter_column_drop_generated' + ) { const tableName = statement.tableName; const res = await connection.query<{ count: string }>( diff --git a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts index e04546157..bcc2d19db 100644 --- a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts +++ b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts @@ -19,16 +19,7 @@ export const _moveDataStatements = ( ) => { const statements: string[] = []; - // rename table to __old_${tablename} - statements.push( - new SqliteRenameTableConvertor().convert({ - type: 'rename_table', - tableNameFrom: tableName, - tableNameTo: `__old_push_${tableName}`, - fromSchema: '', - toSchema: '', - }), - ); + const newTableName = `__new_${tableName}`; // create table statement from a new json2 with proper name const tableColumns = Object.values(json.tables[tableName].columns); @@ -39,10 +30,11 @@ export const _moveDataStatements = ( const fks = referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)); + // create new table statements.push( new SQLiteCreateTableConvertor().convert({ type: 'sqlite_create_table', - tableName: tableName, + tableName: newTableName, columns: tableColumns, referenceData: fks, compositePKs, @@ -56,22 +48,33 @@ export const _moveDataStatements = ( ); statements.push( - `INSERT INTO \`${tableName}\`(${ + `INSERT INTO \`${newTableName}\`(${ columns.join( ', ', ) - }) SELECT (${columns.join(', ')}) FROM \`__old_push_${tableName}\`;`, + }) SELECT ${columns.join(', ')} FROM \`${tableName}\`;`, ); } - // drop table with name __old_${tablename} + statements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', - tableName: `__old_push_${tableName}`, + tableName: tableName, schema: '', }), ); + // rename table + statements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: newTableName, + tableNameTo: tableName, + toSchema: '', + type: 'rename_table', + }), + ); + for (const idx of Object.values(json.tables[tableName].indexes)) { statements.push( new CreateSqliteIndexConvertor().convert({ @@ -207,6 +210,8 @@ export const logSuggestionsAndReturn = async ( const tableName = statement.tableName; const oldTableName = getOldTableName(tableName, meta); + let dataLoss = false; + const prevColumnNames = Object.keys(json1.tables[oldTableName].columns); const currentColumnNames = Object.keys(json2.tables[tableName].columns); const { removedColumns, addedColumns } = findAddedAndRemoved( @@ -245,6 +250,7 @@ export const logSuggestionsAndReturn = async ( const count = Number(res.count); if (count > 0 && columnConf.notNull && !columnConf.default) { + dataLoss = true; infoToPrint.push( `· You're about to add not-null ${ chalk.underline( @@ -254,12 +260,13 @@ export const logSuggestionsAndReturn = async ( ); shouldAskForApprove = true; tablesToTruncate.push(tableName); + + statementsToExecute.push(`DELETE FROM \`${tableName}\`;`); } } } - statementsToExecute.push(..._moveDataStatements(tableName, json2)); - + // check if some tables referencing current for pragma const tablesReferencingCurrent: string[] = []; for (const table of Object.values(json2.tables)) { @@ -270,10 +277,21 @@ export const logSuggestionsAndReturn = async ( tablesReferencingCurrent.push(...tablesRefs); } - const uniqueTableRefs = [...new Set(tablesReferencingCurrent)]; + if (!tablesReferencingCurrent.length) { + statementsToExecute.push(..._moveDataStatements(tableName, json2, dataLoss)); + continue; + } + + const [{ foreign_keys: pragmaState }] = await connection.query<{ + foreign_keys: number; + }>(`PRAGMA foreign_keys;`); - for (const table of uniqueTableRefs) { - statementsToExecute.push(..._moveDataStatements(table, json2)); + if (pragmaState) { + statementsToExecute.push(`PRAGMA foreign_keys=OFF;`); + } + statementsToExecute.push(..._moveDataStatements(tableName, json2, dataLoss)); + if (pragmaState) { + statementsToExecute.push(`PRAGMA foreign_keys=ON;`); } } else { const fromJsonStatement = fromJson([statement], 'sqlite', 'push'); diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 278b2ffc1..47cb08908 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -2097,7 +2097,7 @@ export const prepareLibSQLDropReferencesJson = ( : SQLiteSquasher.unsquashFK(fkData); // If all columns from where were references were deleted -> skip this logic - // Drop colums will cover this scenario + // Drop columns will cover this scenario const keys = Object.keys(json2.tables[tableName].columns); const filtered = columnsFrom.filter((it) => keys.includes(it)); const fullDrop = filtered.length === 0; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index baf9e2727..b0e1f8980 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -599,38 +599,6 @@ class MySQLAlterTableDropUniqueConstraintConvertor extends Convertor { } } -class SQLiteAlterTableAddUniqueConstraintConvertor extends Convertor { - can(statement: JsonCreateUniqueConstraint, dialect: Dialect): boolean { - return ( - statement.type === 'create_unique_constraint' && dialect === 'sqlite' - ); - } - convert(statement: JsonCreateUniqueConstraint): string { - return ( - '/*\n SQLite does not support "Adding unique constraint to an existing table" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/unique.php' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - -class SQLiteAlterTableDropUniqueConstraintConvertor extends Convertor { - can(statement: JsonDeleteUniqueConstraint, dialect: Dialect): boolean { - return ( - statement.type === 'delete_unique_constraint' && dialect === 'sqlite' - ); - } - convert(statement: JsonDeleteUniqueConstraint): string { - return ( - '/*\n SQLite does not support "Dropping unique constraint from an existing table" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/unique.php' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class CreatePgSequenceConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_sequence' && dialect === 'postgresql'; @@ -1069,27 +1037,6 @@ class PgAlterTableAlterColumnSetTypeConvertor extends Convertor { } } -class SQLiteAlterTableAlterColumnSetTypeConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'alter_table_alter_column_set_type' - && dialect === 'sqlite' - && !driver - ); - } - - convert(statement: JsonAlterColumnTypeStatement) { - return ( - '/*\n SQLite does not support "Changing existing column type" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class PgAlterTableAlterColumnSetDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1109,26 +1056,6 @@ class PgAlterTableAlterColumnSetDefaultConvertor extends Convertor { } } -class SqliteAlterTableAlterColumnSetDefaultConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return ( - statement.type === 'alter_table_alter_column_set_default' - && dialect === 'sqlite' - ); - } - - convert(statement: JsonAlterColumnSetDefaultStatement) { - return ( - '/*\n SQLite does not support "Set default to column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class PgAlterTableAlterColumnDropDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1533,13 +1460,31 @@ export class LibSQLModifyColumn extends Convertor { ); } - convert(statement: LibSQLModifyColumnStatement, json2: SQLiteSchemaSquashed) { + convert(statement: LibSQLModifyColumnStatement, json2: SQLiteSchemaSquashed, action?: 'push') { const { tableName, columnName } = statement; let columnType = ``; let columnDefault: any = ''; let columnNotNull = ''; + const sqlStatements: string[] = []; + + // collect index info + const indexes: { + name: string; + tableName: string; + columns: string[]; + isUnique: boolean; + where?: string | undefined; + }[] = []; + for (const table of Object.values(json2.tables)) { + for (const index of Object.values(table.indexes)) { + const unsquashed = SQLiteSquasher.unsquashIdx(index); + sqlStatements.push(`DROP INDEX IF EXISTS "${unsquashed.name}";`); + indexes.push({ ...unsquashed, tableName: table.name }); + } + } + switch (statement.type) { case 'alter_table_alter_column_set_type': columnType = ` ${statement.newDataType}`; @@ -1590,7 +1535,22 @@ export class LibSQLModifyColumn extends Convertor { ? columnDefault.toISOString() : columnDefault; - return `ALTER TABLE \`${tableName}\` ALTER COLUMN "${columnName}" TO "${columnName}"${columnType}${columnNotNull}${columnDefault};`; + sqlStatements.push( + `ALTER TABLE \`${tableName}\` ALTER COLUMN "${columnName}" TO "${columnName}"${columnType}${columnNotNull}${columnDefault};`, + ); + + for (const index of indexes) { + const indexPart = index.isUnique ? 'UNIQUE INDEX' : 'INDEX'; + const whereStatement = index.where ? ` WHERE ${index.where}` : ''; + const uniqueString = index.columns.map((it) => `\`${it}\``).join(','); + const tableName = index.tableName; + + sqlStatements.push( + `CREATE ${indexPart} \`${index.name}\` ON \`${tableName}\` (${uniqueString})${whereStatement};`, + ); + } + + return sqlStatements; } } @@ -1829,26 +1789,6 @@ class MySqlModifyColumn extends Convertor { } } -class SqliteAlterTableAlterColumnDropDefaultConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return ( - statement.type === 'alter_table_alter_column_drop_default' - && dialect === 'sqlite' - ); - } - - convert(statement: JsonAlterColumnDropDefaultStatement) { - return ( - '/*\n SQLite does not support "Drop default from column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class PgAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_composite_pk' && dialect === 'postgresql'; @@ -1939,89 +1879,6 @@ class MySqlAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { } } -class SqliteAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_composite_pk' && dialect === 'sqlite'; - } - - convert(statement: JsonCreateCompositePK) { - let msg = '/*\n'; - msg += `You're trying to add PRIMARY KEY(${statement.data}) to '${statement.tableName}' table\n`; - msg += 'SQLite does not support adding primary key to an already created table\n'; - msg += 'You can do it in 3 steps with drizzle orm:\n'; - msg += ' - create new mirror table with needed pk, rename current table to old_table, generate SQL\n'; - msg += ' - migrate old data from one table to another\n'; - msg += ' - delete old_table in schema, generate sql\n\n'; - msg += 'or create manual migration like below:\n\n'; - msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; - msg += 'CREATE TABLE table_name (\n'; - msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; - msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; - msg += '\t...\n'; - msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; - msg += ' );\n'; - msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; - msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; - msg += '*/\n'; - return msg; - } -} -class SqliteAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'delete_composite_pk' && dialect === 'sqlite'; - } - - convert(statement: JsonDeleteCompositePK) { - let msg = '/*\n'; - msg += `You're trying to delete PRIMARY KEY(${statement.data}) from '${statement.tableName}' table\n`; - msg += 'SQLite does not supportprimary key deletion from existing table\n'; - msg += 'You can do it in 3 steps with drizzle orm:\n'; - msg += ' - create new mirror table table without pk, rename current table to old_table, generate SQL\n'; - msg += ' - migrate old data from one table to another\n'; - msg += ' - delete old_table in schema, generate sql\n\n'; - msg += 'or create manual migration like below:\n\n'; - msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; - msg += 'CREATE TABLE table_name (\n'; - msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; - msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; - msg += '\t...\n'; - msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; - msg += ' );\n'; - msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; - msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; - msg += '*/\n'; - return msg; - } -} - -class SqliteAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_composite_pk' && dialect === 'sqlite'; - } - - convert(statement: JsonAlterCompositePK) { - let msg = '/*\n'; - msg += 'SQLite does not support altering primary key\n'; - msg += 'You can do it in 3 steps with drizzle orm:\n'; - msg += ' - create new mirror table with needed pk, rename current table to old_table, generate SQL\n'; - msg += ' - migrate old data from one table to another\n'; - msg += ' - delete old_table in schema, generate sql\n\n'; - msg += 'or create manual migration like below:\n\n'; - msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; - msg += 'CREATE TABLE table_name (\n'; - msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; - msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; - msg += '\t...\n'; - msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; - msg += ' );\n'; - msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; - msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; - msg += '*/\n'; - - return msg; - } -} - class PgAlterTableAlterColumnSetPrimaryKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2089,69 +1946,6 @@ class PgAlterTableAlterColumnSetNotNullConvertor extends Convertor { } } -class SqliteAlterTableAlterColumnSetNotNullConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'alter_table_alter_column_set_notnull' - && dialect === 'sqlite' - && !driver - ); - } - - convert(statement: JsonAlterColumnSetNotNullStatement) { - return ( - '/*\n SQLite does not support "Set not null to column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - -class SqliteAlterTableAlterColumnSetAutoincrementConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'alter_table_alter_column_set_autoincrement' - && dialect === 'sqlite' - && !driver - ); - } - - convert(statement: JsonAlterColumnSetAutoincrementStatement) { - return ( - '/*\n SQLite does not support "Set autoincrement to a column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - -class SqliteAlterTableAlterColumnDropAutoincrementConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'alter_table_alter_column_drop_autoincrement' - && dialect === 'sqlite' - && !driver - ); - } - - convert(statement: JsonAlterColumnDropAutoincrementStatement) { - return ( - '/*\n SQLite does not support "Drop autoincrement from a column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class PgAlterTableAlterColumnDropNotNullConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2171,27 +1965,6 @@ class PgAlterTableAlterColumnDropNotNullConvertor extends Convertor { } } -class SqliteAlterTableAlterColumnDropNotNullConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'alter_table_alter_column_drop_notnull' - && dialect === 'sqlite' - && !driver - ); - } - - convert(statement: JsonAlterColumnDropNotNullStatement) { - return ( - '/*\n SQLite does not support "Drop not null from column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - // FK class PgCreateForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { @@ -2234,24 +2007,6 @@ class PgCreateForeignKeyConvertor extends Convertor { } } -class SqliteCreateForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'create_reference' && dialect === 'sqlite' && !driver - ); - } - - convert(statement: JsonCreateReferenceStatement): string { - return ( - '/*\n SQLite does not support "Creating foreign key on existing column" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class LibSQLCreateForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { return ( @@ -2269,17 +2024,7 @@ class LibSQLCreateForeignKeyConvertor extends Convertor { const { columnsFrom, columnsTo, tableFrom, onDelete, onUpdate, tableTo } = action === 'push' ? SQLiteSquasher.unsquashPushFK(statement.data) : SQLiteSquasher.unsquashFK(statement.data); - const { columnDefault, columnNotNull, columnType, isMulticolumn } = statement; - - if (isMulticolumn) { - return ( - '/*\n LibSQL does not support "Creating foreign key on multiple columns" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } + const { columnDefault, columnNotNull, columnType } = statement; const onDeleteStatement = onDelete ? ` ON DELETE ${onDelete}` : ''; const onUpdateStatement = onUpdate ? ` ON UPDATE ${onUpdate}` : ''; @@ -2367,22 +2112,6 @@ class PgAlterForeignKeyConvertor extends Convertor { } } -class SqliteAlterForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_reference' && dialect === 'sqlite'; - } - - convert(statement: JsonAlterReferenceStatement): string { - return ( - '/*\n SQLite does not support "Changing existing foreign key" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - class PgDeleteForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'delete_reference' && dialect === 'postgresql'; @@ -2400,66 +2129,6 @@ class PgDeleteForeignKeyConvertor extends Convertor { } } -class SqliteDeleteForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'delete_reference' && dialect === 'sqlite' && !driver - ); - } - - convert(statement: JsonDeleteReferenceStatement): string { - return ( - '/*\n SQLite does not support "Dropping foreign key" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } -} - -class LibSQLDeleteForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { - return ( - statement.type === 'delete_reference' - && dialect === 'sqlite' - && driver === 'turso' - ); - } - - convert( - statement: JsonDeleteReferenceStatement, - json2?: SQLiteSchemaSquashed, - action?: 'push', - ): string { - const { columnsFrom, tableFrom } = action === 'push' - ? SQLiteSquasher.unsquashPushFK(statement.data) - : SQLiteSquasher.unsquashFK(statement.data); - - const { columnDefault, columnNotNull, columnType, isMulticolumn } = statement; - - if (isMulticolumn) { - return ( - '/*\n LibSQL does not support "Creating foreign key on multiple columns" out of the box, we do not generate automatic migration for that, so it has to be done manually' - + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' - + '\n https://www.sqlite.org/lang_altertable.html' - + "\n\n Due to that we don't generate migration automatically and it has to be done manually" - + '\n*/' - ); - } - - const columnsDefaultValue = columnDefault - ? ` DEFAULT ${columnDefault}` - : ''; - const columnNotNullValue = columnNotNull ? ` NOT NULL` : ''; - const columnTypeValue = columnType ? ` ${columnType}` : ''; - - const columnFrom = columnsFrom[0]; - - return `ALTER TABLE \`${tableFrom}\` ALTER COLUMN "${columnFrom}" TO "${columnFrom}"${columnTypeValue}${columnNotNullValue}${columnsDefaultValue};`; - } -} - class MySqlDeleteForeignKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'delete_reference' && dialect === 'mysql'; @@ -2708,25 +2377,17 @@ class SQLiteRecreateTableConvertor extends Convertor { const { tableName, columns, compositePKs, referenceData } = statement; const columnNames = columns.map((it) => `"${it.name}"`).join(', '); + const newTableName = `__new_${tableName}`; const sqlStatements: string[] = []; - // rename table - sqlStatements.push( - new SqliteRenameTableConvertor().convert({ - fromSchema: '', - tableNameFrom: tableName, - tableNameTo: `__old__generate_${tableName}`, - toSchema: '', - type: 'rename_table', - }), - ); + sqlStatements.push(`PRAGMA foreign_keys=OFF;`); // create new table sqlStatements.push( new SQLiteCreateTableConvertor().convert({ type: 'sqlite_create_table', - tableName, + tableName: newTableName, columns, referenceData, compositePKs, @@ -2735,18 +2396,31 @@ class SQLiteRecreateTableConvertor extends Convertor { // migrate data sqlStatements.push( - `INSERT INTO \`${tableName}\`(${columnNames}) SELECT ${columnNames} FROM \`__old__generate_${tableName}\`;`, + `INSERT INTO \`${newTableName}\`(${columnNames}) SELECT ${columnNames} FROM \`${tableName}\`;`, ); // migrate data sqlStatements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', - tableName: `__old__generate_${tableName}`, + tableName: tableName, schema: '', }), ); + // rename table + sqlStatements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: newTableName, + tableNameTo: tableName, + toSchema: '', + type: 'rename_table', + }), + ); + + sqlStatements.push(`PRAGMA foreign_keys=ON;`); + return sqlStatements; } } @@ -2764,25 +2438,17 @@ class LibSQLRecreateTableConvertor extends Convertor { const { tableName, columns, compositePKs, referenceData } = statement; const columnNames = columns.map((it) => `"${it.name}"`).join(', '); + const newTableName = `__new_${tableName}`; const sqlStatements: string[] = []; - // rename table - sqlStatements.push( - new SqliteRenameTableConvertor().convert({ - fromSchema: '', - tableNameFrom: tableName, - tableNameTo: `__old__generate_${tableName}`, - toSchema: '', - type: 'rename_table', - }), - ); + sqlStatements.push(`PRAGMA foreign_keys=OFF;`); // create new table sqlStatements.push( new SQLiteCreateTableConvertor().convert({ type: 'sqlite_create_table', - tableName, + tableName: newTableName, columns, referenceData, compositePKs, @@ -2791,18 +2457,31 @@ class LibSQLRecreateTableConvertor extends Convertor { // migrate data sqlStatements.push( - `INSERT INTO \`${tableName}\`(${columnNames}) SELECT ${columnNames} FROM \`__old__generate_${tableName}\`;`, + `INSERT INTO \`${newTableName}\`(${columnNames}) SELECT ${columnNames} FROM \`${tableName}\`;`, ); // migrate data sqlStatements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', - tableName: `__old__generate_${tableName}`, + tableName: tableName, schema: '', }), ); + // rename table + sqlStatements.push( + new SqliteRenameTableConvertor().convert({ + fromSchema: '', + tableNameFrom: newTableName, + tableNameTo: tableName, + toSchema: '', + type: 'rename_table', + }), + ); + + sqlStatements.push(`PRAGMA foreign_keys=ON;`); + return sqlStatements; } } @@ -2898,33 +2577,12 @@ convertors.push(new PgAlterTableSetSchemaConvertor()); convertors.push(new PgAlterTableSetNewSchemaConvertor()); convertors.push(new PgAlterTableRemoveFromSchemaConvertor()); -// Unhandled sqlite queries, so they will appear last -convertors.push(new SQLiteAlterTableAlterColumnSetTypeConvertor()); -convertors.push(new SqliteAlterForeignKeyConvertor()); -convertors.push(new SqliteDeleteForeignKeyConvertor()); -convertors.push(new LibSQLDeleteForeignKeyConvertor()); -convertors.push(new SqliteCreateForeignKeyConvertor()); convertors.push(new LibSQLCreateForeignKeyConvertor()); -convertors.push(new SQLiteAlterTableAddUniqueConstraintConvertor()); -convertors.push(new SQLiteAlterTableDropUniqueConstraintConvertor()); - convertors.push(new PgAlterTableAlterColumnDropGenerated()); convertors.push(new PgAlterTableAlterColumnSetGenerated()); convertors.push(new PgAlterTableAlterColumnAlterGenerated()); -convertors.push(new SqliteAlterTableAlterColumnSetNotNullConvertor()); -convertors.push(new SqliteAlterTableAlterColumnDropNotNullConvertor()); -convertors.push(new SqliteAlterTableAlterColumnSetDefaultConvertor()); -convertors.push(new SqliteAlterTableAlterColumnDropDefaultConvertor()); - -convertors.push(new SqliteAlterTableAlterColumnSetAutoincrementConvertor()); -convertors.push(new SqliteAlterTableAlterColumnDropAutoincrementConvertor()); - -convertors.push(new SqliteAlterTableCreateCompositePrimaryKeyConvertor()); -convertors.push(new SqliteAlterTableDeleteCompositePrimaryKeyConvertor()); -convertors.push(new SqliteAlterTableAlterCompositePrimaryKeyConvertor()); - convertors.push(new PgAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new PgAlterTableDeleteCompositePrimaryKeyConvertor()); convertors.push(new PgAlterTableAlterCompositePrimaryKeyConvertor()); diff --git a/drizzle-kit/src/statementCombiner.ts b/drizzle-kit/src/statementCombiner.ts index 549457cf1..2f7b6ddbe 100644 --- a/drizzle-kit/src/statementCombiner.ts +++ b/drizzle-kit/src/statementCombiner.ts @@ -122,15 +122,15 @@ export const libSQLCombineStatements = ( ) { const { tableName, columnName, columnPk } = statement; - const columnIsPartOfUniqueIndex = Object.values( - json2.tables[tableName].indexes, - ).some((it) => { - const unsquashIndex = SQLiteSquasher.unsquashIdx(it); + // const columnIsPartOfUniqueIndex = Object.values( + // json2.tables[tableName].indexes, + // ).some((it) => { + // const unsquashIndex = SQLiteSquasher.unsquashIdx(it); - return ( - unsquashIndex.columns.includes(columnName) && unsquashIndex.isUnique - ); - }); + // return ( + // unsquashIndex.columns.includes(columnName) && unsquashIndex.isUnique + // ); + // }); const columnIsPartOfForeignKey = Object.values( json2.tables[tableName].foreignKeys, @@ -145,14 +145,14 @@ export const libSQLCombineStatements = ( const statementsForTable = newStatements[tableName]; if ( - !statementsForTable && (columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + !statementsForTable && (columnIsPartOfForeignKey || columnPk) ) { newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); continue; } if ( - statementsForTable && (columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + statementsForTable && (columnIsPartOfForeignKey || columnPk) ) { if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); @@ -167,7 +167,7 @@ export const libSQLCombineStatements = ( continue; } if ( - statementsForTable && !(columnIsPartOfUniqueIndex || columnIsPartOfForeignKey || columnPk) + statementsForTable && !(columnIsPartOfForeignKey || columnPk) ) { if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { newStatements[tableName].push(statement); @@ -192,7 +192,7 @@ export const libSQLCombineStatements = ( if (!statementsForTable) { newStatements[tableName] = statement.isMulticolumn ? prepareLibSQLRecreateTable(json2.tables[tableName], action) - : newStatements[tableName] = [statement]; + : [statement]; continue; } diff --git a/drizzle-kit/tests/libsql-statements.test.ts b/drizzle-kit/tests/libsql-statements.test.ts index 927411e44..e18e41950 100644 --- a/drizzle-kit/tests/libsql-statements.test.ts +++ b/drizzle-kit/tests/libsql-statements.test.ts @@ -1,4 +1,5 @@ -import { foreignKey, int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { sql } from 'drizzle-orm'; +import { foreignKey, index, int, integer, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'; import { JsonRecreateTableStatement } from 'src/jsonStatements'; import { expect, test } from 'vitest'; import { diffTestSchemasLibSQL } from './schemaDiffer'; @@ -429,20 +430,20 @@ test('drop foriegn key', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(4); - expect(sqlStatements[0]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, - ); - expect(sqlStatements[1]).toBe(`CREATE TABLE \`users\` ( + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`table_id\` integer );\n`); expect(sqlStatements[2]).toBe( - `INSERT INTO \`users\`("id", "table_id") SELECT "id", "table_id" FROM \`__old__generate_users\`;`, + `INSERT INTO \`__new_users\`("id", "table_id") SELECT "id", "table_id" FROM \`users\`;`, ); - expect(sqlStatements[3]).toBe( - `DROP TABLE \`__old__generate_users\`;`, + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); test('alter foriegn key', async (t) => { @@ -500,12 +501,8 @@ test('alter foriegn key', async (t) => { compositePKs: [], referenceData: [ { - columnsFrom: [ - 'table_id', - ], - columnsTo: [ - 'id', - ], + columnsFrom: ['table_id'], + columnsTo: ['id'], name: 'users_table_id_table2_id_fk', onDelete: 'no action', onUpdate: 'no action', @@ -518,21 +515,23 @@ test('alter foriegn key', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(4); - expect(sqlStatements[0]).toBe( - 'ALTER TABLE `users` RENAME TO `__old__generate_users`;', - ); - expect(sqlStatements[1]).toBe(`CREATE TABLE \`users\` ( + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`table_id\` integer, \tFOREIGN KEY (\`table_id\`) REFERENCES \`table2\`(\`id\`) ON UPDATE no action ON DELETE no action );\n`); expect(sqlStatements[2]).toBe( - `INSERT INTO \`users\`("id", "table_id") SELECT "id", "table_id" FROM \`__old__generate_users\`;`, + `INSERT INTO \`__new_users\`("id", "table_id") SELECT "id", "table_id" FROM \`users\`;`, ); expect(sqlStatements[3]).toBe( - `DROP TABLE \`__old__generate_users\`;`, + 'DROP TABLE `users`;', + ); + expect(sqlStatements[4]).toBe( + 'ALTER TABLE `__new_users` RENAME TO `users`;', ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); test('add foriegn key for multiple columns', async (t) => { @@ -605,14 +604,8 @@ test('add foriegn key for multiple columns', async (t) => { compositePKs: [], referenceData: [ { - columnsFrom: [ - 'column', - 'column_1', - ], - columnsTo: [ - 'age', - 'age_1', - ], + columnsFrom: ['column', 'column_1'], + columnsTo: ['age', 'age_1'], name: 'users_column_column_1_table_age_age_1_fk', onDelete: 'no action', onUpdate: 'no action', @@ -625,25 +618,24 @@ test('add foriegn key for multiple columns', async (t) => { uniqueConstraints: [], } as JsonRecreateTableStatement); - expect(sqlStatements.length).toBe(4); - expect(sqlStatements[0]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, - ); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`users\` ( + `CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`column\` integer, \t\`column_1\` integer, \tFOREIGN KEY (\`column\`,\`column_1\`) REFERENCES \`table\`(\`age\`,\`age_1\`) ON UPDATE no action ON DELETE no action -); -`, +);\n`, ); expect(sqlStatements[2]).toBe( - `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, + `INSERT INTO \`__new_users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`users\`;`, ); - expect(sqlStatements[3]).toBe( - `DROP TABLE \`__old__generate_users\`;`, + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); test('drop foriegn key for multiple columns', async (t) => { @@ -720,59 +712,106 @@ test('drop foriegn key for multiple columns', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(4); - expect(sqlStatements[0]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, - ); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`users\` ( + `CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`column\` integer, \t\`column_1\` integer -); -`, +);\n`, ); expect(sqlStatements[2]).toBe( - `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, + `INSERT INTO \`__new_users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`users\`;`, ); - expect(sqlStatements[3]).toBe( - `DROP TABLE \`__old__generate_users\`;`, + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); -test('drop foriegn key for multiple columns', async (t) => { - const tableRef = sqliteTable('table', { - id: int('id').primaryKey({ autoIncrement: true }), - age: int('age'), - age1: int('age_1'), +test('alter column drop generated', async (t) => { + const from = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').generatedAlwaysAs('drizzle is the best').notNull(), + }), + }; + + const to = { + users: sqliteTable('table', { + id: int('id').primaryKey().notNull(), + name: text('name').notNull(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + from, + to, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'table', + type: 'alter_table_alter_column_drop_generated', }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TABLE \`table\` DROP COLUMN \`name\`;`); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`table\` ADD \`name\` text NOT NULL;`, + ); +}); + +test('recreate table with nested references', async (t) => { + let users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: integer('age'), + }); + let subscriptions = sqliteTable('subscriptions', { + id: int('id').primaryKey({ autoIncrement: true }), + userId: integer('user_id').references(() => users.id), + customerId: text('customer_id'), + }); const schema1 = { - users: sqliteTable( - 'users', - { - id: int('id').primaryKey({ autoIncrement: true }), - column: int('column'), - column1: int('column_1'), - }, - (table) => ({ - foreignKey: foreignKey({ - columns: [table.column, table.column1], - foreignColumns: [tableRef.age, tableRef.age1], - }), - }), - ), - tableRef, + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), + }), }; + users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }); const schema2 = { - users: sqliteTable('users', { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { id: int('id').primaryKey({ autoIncrement: true }), - column: int('column'), - column1: int('column_1'), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), }), - tableRef, }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL( schema1, schema2, @@ -783,7 +822,7 @@ test('drop foriegn key for multiple columns', async (t) => { expect(statements[0]).toStrictEqual({ columns: [ { - autoincrement: true, + autoincrement: false, generated: undefined, name: 'id', notNull: true, @@ -793,15 +832,15 @@ test('drop foriegn key for multiple columns', async (t) => { { autoincrement: false, generated: undefined, - name: 'column', + name: 'name', notNull: false, primaryKey: false, - type: 'integer', + type: 'text', }, { autoincrement: false, generated: undefined, - name: 'column_1', + name: 'age', notNull: false, primaryKey: false, type: 'integer', @@ -814,63 +853,131 @@ test('drop foriegn key for multiple columns', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(4); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`__new_users\`("id", "name", "age") SELECT "id", "name", "age" FROM \`users\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('set not null with index', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }, (table) => ({ + someIndex: index('users_name_index').on(table.name), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }, (table) => ({ + someIndex: index('users_name_index').on(table.name), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_set_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(3); expect(sqlStatements[0]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old__generate_users\`;`, + `DROP INDEX IF EXISTS "users_name_index";`, ); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`users\` ( -\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, -\t\`column\` integer, -\t\`column_1\` integer -); -`, + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text NOT NULL;`, ); expect(sqlStatements[2]).toBe( - `INSERT INTO \`users\`("id", "column", "column_1") SELECT "id", "column", "column_1" FROM \`__old__generate_users\`;`, - ); - expect(sqlStatements[3]).toBe( - `DROP TABLE \`__old__generate_users\`;`, + `CREATE INDEX \`users_name_index\` ON \`users\` (\`name\`);`, ); }); -test('alter column drop generated', async (t) => { - const from = { - users: sqliteTable('table', { - id: int('id').primaryKey().notNull(), - name: text('name').generatedAlwaysAs('drizzle is the best').notNull(), - }), +test('drop not null with two indexes', async (t) => { + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + age: int('age').notNull(), + }, (table) => ({ + someUniqeIndex: uniqueIndex('users_name_unique').on(table.name), + someIndex: index('users_age_index').on(table.age), + })), }; - const to = { - users: sqliteTable('table', { - id: int('id').primaryKey().notNull(), - name: text('name').notNull(), - }), + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: int('age').notNull(), + }, (table) => ({ + someUniqeIndex: uniqueIndex('users_name_unique').on(table.name), + someIndex: index('users_age_index').on(table.age), + })), }; const { statements, sqlStatements } = await diffTestSchemasLibSQL( - from, - to, + schema1, + schema2, [], ); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: undefined, + type: 'alter_table_alter_column_drop_notnull', + tableName: 'users', columnName: 'name', - columnNotNull: true, + schema: '', + newDataType: 'text', + columnDefault: undefined, columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'table', - type: 'alter_table_alter_column_drop_generated', }); - expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`ALTER TABLE \`table\` DROP COLUMN \`name\`;`); - expect(sqlStatements[1]).toBe(`ALTER TABLE \`table\` ADD \`name\` text NOT NULL;`); + expect(sqlStatements.length).toBe(5); + expect(sqlStatements[0]).toBe( + `DROP INDEX IF EXISTS "users_name_unique";`, + ); + expect(sqlStatements[1]).toBe( + `DROP INDEX IF EXISTS "users_age_index";`, + ); + expect(sqlStatements[2]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`, + ); + expect(sqlStatements[3]).toBe( + `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + ); + expect(sqlStatements[4]).toBe( + `CREATE INDEX \`users_age_index\` ON \`users\` (\`age\`);`, + ); }); diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 205f31f0b..3506cef32 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -1,9 +1,11 @@ import { createClient } from '@libsql/client'; import chalk from 'chalk'; +import { sql } from 'drizzle-orm'; import { blob, foreignKey, getTableConfig, + index, int, integer, numeric, @@ -390,15 +392,14 @@ test('drop autoincrement. drop column with data', async (t) => { expect(sqlStatements.length).toBe(4); expect(sqlStatements[0]).toBe( - `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, - ); - expect(sqlStatements[1]).toBe( - `CREATE TABLE \`companies\` ( + `CREATE TABLE \`__new_companies\` ( \t\`id\` integer PRIMARY KEY NOT NULL );\n`, ); - expect(sqlStatements[2]).toBe( - `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + expect(sqlStatements[1]).toBe(`INSERT INTO \`__new_companies\`("id") SELECT "id" FROM \`companies\`;`); + expect(sqlStatements[2]).toBe(`DROP TABLE \`companies\`;`); + expect(sqlStatements[3]).toBe( + `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, ); expect(columnsToRemove!.length).toBe(1); @@ -426,7 +427,7 @@ test('change autoincrement. table is part of foreign key', async (t) => { const users1 = sqliteTable('users', { id: integer('id').primaryKey({ autoIncrement: true }), name: text('name').unique(), - companyId: text('company_id').references(() => companies1.id), + companyId: integer('company_id').references(() => companies1.id), }); const schema1 = { companies: companies1, @@ -439,7 +440,7 @@ test('change autoincrement. table is part of foreign key', async (t) => { const users2 = sqliteTable('users', { id: integer('id').primaryKey({ autoIncrement: true }), name: text('name').unique(), - companyId: text('company_id').references(() => companies1.id), + companyId: integer('company_id').references(() => companies2.id), }); const schema2 = { companies: companies2, @@ -451,8 +452,8 @@ test('change autoincrement. table is part of foreign key', async (t) => { const seedStatements = [ `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("drizzle");`, `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("turso");`, - `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ("1");`, - `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES ("2");`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES (1);`, + `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES (2);`, ]; const { @@ -491,39 +492,21 @@ test('change autoincrement. table is part of foreign key', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(9); - expect(sqlStatements[0]).toBe( - `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, - ); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`companies\` ( + `CREATE TABLE \`__new_companies\` ( \t\`id\` integer PRIMARY KEY NOT NULL -); -`, +);\n`, ); expect(sqlStatements[2]).toBe( - `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + `INSERT INTO \`__new_companies\`("id") SELECT "id" FROM \`companies\`;`, ); - expect(sqlStatements[3]).toBe(`DROP TABLE \`__old_push_companies\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`companies\`;`); expect(sqlStatements[4]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`, - ); - expect(sqlStatements[5]).toBe( - `CREATE TABLE \`users\` ( -\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, -\t\`name\` text, -\t\`company_id\` text, -\tFOREIGN KEY (\`company_id\`) REFERENCES \`companies\`(\`id\`) ON UPDATE no action ON DELETE no action -); -`, - ); - expect(sqlStatements[6]).toBe( - `INSERT INTO \`users\`("id", "name", "company_id") SELECT ("id", "name", "company_id") FROM \`__old_push_users\`;`, - ); - expect(sqlStatements[7]).toBe(`DROP TABLE \`__old_push_users\`;`); - expect(sqlStatements[8]).toBe( - `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -742,3 +725,386 @@ test('drop table with data', async (t) => { expect(tablesToRemove![0]).toBe('users'); expect(tablesToTruncate!.length).toBe(0); }); + +test('recreate table with nested references', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + let users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: integer('age'), + }); + let subscriptions = sqliteTable('subscriptions', { + id: int('id').primaryKey({ autoIncrement: true }), + userId: integer('user_id').references(() => users.id), + customerId: text('customer_id'), + }); + const schema1 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), + }), + }; + + users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }); + const schema2 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), + }), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL(turso, schema1, schema2, []); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer +);\n`); + expect(sqlStatements![2]).toBe( + `INSERT INTO \`__new_users\`("id", "name", "age") SELECT "id", "name", "age" FROM \`users\`;`, + ); + expect(sqlStatements![3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + expect(sqlStatements[5]).toBe('PRAGMA foreign_keys=ON;'); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('recreate table with added column not null and without default', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: integer('age'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + newColumn: text('new_column').notNull(), + }), + }; + + const seedStatements = [ + `INSERT INTO \`users\` ("name", "age") VALUES ('drizzle', 12)`, + `INSERT INTO \`users\` ("name", "age") VALUES ('turso', 12)`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + name: 'new_column', + notNull: true, + generated: undefined, + primaryKey: false, + type: 'text', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements[0]).toBe('DELETE FROM \`users\`;'); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer, +\t\`new_column\` text NOT NULL +);\n`); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to add not-null ${ + chalk.underline('new_column') + } column without default value to table, which contains 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(1); + expect(tablesToTruncate![0]).toBe('users'); +}); + +test('set not null with index', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + }, (table) => ({ + someIndex: index('users_name_index').on(table.name), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }, (table) => ({ + someIndex: index('users_name_index').on(table.name), + })), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columnAutoIncrement: false, + columnDefault: undefined, + columnName: 'name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_notnull', + }); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_set_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: true, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(3); + expect(sqlStatements[0]).toBe( + `DROP INDEX IF EXISTS "users_name_index";`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text NOT NULL;`, + ); + expect(sqlStatements[2]).toBe( + `CREATE INDEX \`users_name_index\` ON \`users\` (\`name\`);`, + ); + expect(columnsToRemove!.length).toBe(0), expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop not null with two indexes', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + age: int('age').notNull(), + }, (table) => ({ + someUniqeIndex: uniqueIndex('users_name_unique').on(table.name), + someIndex: index('users_age_index').on(table.age), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: int('age').notNull(), + }, (table) => ({ + someUniqeIndex: uniqueIndex('users_name_unique').on(table.name), + someIndex: index('users_age_index').on(table.age), + })), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_table_alter_column_drop_notnull', + tableName: 'users', + columnName: 'name', + schema: '', + newDataType: 'text', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, + }); + + expect(sqlStatements.length).toBe(5); + expect(sqlStatements[0]).toBe( + `DROP INDEX IF EXISTS "users_name_unique";`, + ); + expect(sqlStatements[1]).toBe( + `DROP INDEX IF EXISTS "users_age_index";`, + ); + expect(sqlStatements[2]).toBe( + `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`, + ); + expect(sqlStatements[3]).toBe( + `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + ); + expect(sqlStatements[4]).toBe( + `CREATE INDEX \`users_age_index\` ON \`users\` (\`age\`);`, + ); + expect(columnsToRemove!.length).toBe(0), expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index d0c3cb05e..e52559256 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -382,15 +382,133 @@ test('drop autoincrement. drop column with data', async (t) => { expect(sqlStatements.length).toBe(4); expect(sqlStatements[0]).toBe( - `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, + `CREATE TABLE \`__new_companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL +);\n`, ); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`companies\` ( -\t\`id\` integer PRIMARY KEY NOT NULL + `INSERT INTO \`__new_companies\`("id") SELECT "id" FROM \`companies\`;`, + ); + expect(sqlStatements[2]).toBe(`DROP TABLE \`companies\`;`); + expect(sqlStatements[3]).toBe( + `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, + ); + + expect(columnsToRemove!.length).toBe(1); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to delete ${ + chalk.underline( + 'name', + ) + } column in companies table with 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop autoincrement. drop column with data with pragma off', async (t) => { + const client = new Database(':memory:'); + + client.exec('PRAGMA foreign_keys=OFF;'); + + const users = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + }); + const schema1 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name'), + user_id: integer('user_id').references(() => users.id), + }), + }; + + const schema2 = { + companies: sqliteTable('companies', { + id: integer('id').primaryKey({ autoIncrement: false }), + user_id: integer('user_id').references(() => users.id), + }), + }; + + const table = getTableConfig(schema1.companies); + const seedStatements = [ + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (1, 'drizzle');`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (2, 'turso');`, + ]; + + const { + sqlStatements, + statements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + tableName: 'companies', + columns: [ + { + name: 'id', + type: 'integer', + autoincrement: false, + notNull: true, + primaryKey: true, + generated: undefined, + }, + { + name: 'user_id', + type: 'integer', + autoincrement: false, + notNull: false, + primaryKey: false, + generated: undefined, + }, + ], + compositePKs: [], + referenceData: [ + { + columnsFrom: [ + 'user_id', + ], + columnsTo: [ + 'id', + ], + name: '', + onDelete: 'no action', + onUpdate: 'no action', + tableFrom: 'companies', + tableTo: 'users', + }, + ], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `CREATE TABLE \`__new_companies\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`user_id\` integer, +\tFOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE no action );\n`, ); - expect(sqlStatements[2]).toBe( - `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + expect(sqlStatements[1]).toBe( + `INSERT INTO \`__new_companies\`("id", "user_id") SELECT "id", "user_id" FROM \`companies\`;`, + ); + expect(sqlStatements[2]).toBe(`DROP TABLE \`companies\`;`); + expect(sqlStatements[3]).toBe( + `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, ); expect(columnsToRemove!.length).toBe(1); @@ -407,7 +525,7 @@ test('drop autoincrement. drop column with data', async (t) => { expect(tablesToTruncate!.length).toBe(0); }); -test('change autoincrement. table is part of foreign key', async (t) => { +test('change autoincrement. other table references current', async (t) => { const client = new Database(':memory:'); const companies1 = sqliteTable('companies', { @@ -481,39 +599,21 @@ test('change autoincrement. table is part of foreign key', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(9); - expect(sqlStatements[0]).toBe( - `ALTER TABLE \`companies\` RENAME TO \`__old_push_companies\`;`, - ); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); expect(sqlStatements[1]).toBe( - `CREATE TABLE \`companies\` ( + `CREATE TABLE \`__new_companies\` ( \t\`id\` integer PRIMARY KEY NOT NULL -); -`, +);\n`, ); expect(sqlStatements[2]).toBe( - `INSERT INTO \`companies\`("id") SELECT ("id") FROM \`__old_push_companies\`;`, + `INSERT INTO \`__new_companies\`("id") SELECT "id" FROM \`companies\`;`, ); - expect(sqlStatements[3]).toBe(`DROP TABLE \`__old_push_companies\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`companies\`;`); expect(sqlStatements[4]).toBe( - `ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`, - ); - expect(sqlStatements[5]).toBe( - `CREATE TABLE \`users\` ( -\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, -\t\`name\` text, -\t\`company_id\` text, -\tFOREIGN KEY (\`company_id\`) REFERENCES \`companies\`(\`id\`) ON UPDATE no action ON DELETE no action -); -`, - ); - expect(sqlStatements[6]).toBe( - `INSERT INTO \`users\`("id", "name", "company_id") SELECT ("id", "name", "company_id") FROM \`__old_push_users\`;`, - ); - expect(sqlStatements[7]).toBe(`DROP TABLE \`__old_push_users\`;`); - expect(sqlStatements[8]).toBe( - `CREATE UNIQUE INDEX \`users_name_unique\` ON \`users\` (\`name\`);`, + `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, ); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -586,14 +686,11 @@ test('drop not null, add not null', async (t) => { id: int('id').primaryKey({ autoIncrement: true }), name: text('name').notNull(), }), - posts: sqliteTable( - 'posts', - { - id: int('id').primaryKey({ autoIncrement: true }), - name: text('name'), - userId: int('user_id'), - }, - ), + posts: sqliteTable('posts', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + userId: int('user_id'), + }), }; const schema2 = { @@ -601,14 +698,11 @@ test('drop not null, add not null', async (t) => { id: int('id').primaryKey({ autoIncrement: true }), name: text('name'), }), - posts: sqliteTable( - 'posts', - { - id: int('id').primaryKey({ autoIncrement: true }), - name: text('name').notNull(), - userId: int('user_id'), - }, - ), + posts: sqliteTable('posts', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + userId: int('user_id'), + }), }; const { statements, @@ -618,12 +712,7 @@ test('drop not null, add not null', async (t) => { shouldAskForApprove, tablesToRemove, tablesToTruncate, - } = await diffTestSchemasPushSqlite( - client, - schema1, - schema2, - [], - ); + } = await diffTestSchemasPushSqlite(client, schema1, schema2, []); expect(statements!.length).toBe(2); expect(statements![0]).toStrictEqual({ @@ -685,27 +774,31 @@ test('drop not null, add not null', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements!.length).toBe(8); - expect(sqlStatements![0]).toBe(`ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`); - expect(sqlStatements![1]).toBe(`CREATE TABLE \`users\` ( + expect(sqlStatements.length).toBe(8); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`name\` text );\n`); - expect(sqlStatements![2]).toBe( - `INSERT INTO \`users\`("id", "name") SELECT ("id", "name") FROM \`__old_push_users\`;`, + expect(sqlStatements[1]).toBe( + `INSERT INTO \`__new_users\`("id", "name") SELECT "id", "name" FROM \`users\`;`, + ); + expect(sqlStatements[2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); - expect(sqlStatements![3]).toBe(`DROP TABLE \`__old_push_users\`;`); - expect(sqlStatements![4]).toBe(`ALTER TABLE \`posts\` RENAME TO \`__old_push_posts\`;`); - expect(sqlStatements![5]).toBe(`CREATE TABLE \`posts\` ( + expect(sqlStatements![4]).toBe(`CREATE TABLE \`__new_posts\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`name\` text NOT NULL, \t\`user_id\` integer );\n`); - expect(sqlStatements![6]).toBe( - `INSERT INTO \`posts\`("id", "name", "user_id") SELECT ("id", "name", "user_id") FROM \`__old_push_posts\`;`, + expect(sqlStatements![5]).toBe( + `INSERT INTO \`__new_posts\`("id", "name", "user_id") SELECT "id", "name", "user_id" FROM \`posts\`;`, + ); + expect(sqlStatements![6]).toBe(`DROP TABLE \`posts\`;`); + expect(sqlStatements![7]).toBe( + `ALTER TABLE \`__new_posts\` RENAME TO \`posts\`;`, ); - expect(sqlStatements![7]).toBe(`DROP TABLE \`__old_push_posts\`;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -738,12 +831,9 @@ test('rename table and change data type', async (t) => { shouldAskForApprove, tablesToRemove, tablesToTruncate, - } = await diffTestSchemasPushSqlite( - client, - schema1, - schema2, - ['public.old_users->public.new_users'], - ); + } = await diffTestSchemasPushSqlite(client, schema1, schema2, [ + 'public.old_users->public.new_users', + ]); expect(statements!.length).toBe(2); expect(statements![0]).toStrictEqual({ @@ -780,16 +870,20 @@ test('rename table and change data type', async (t) => { }); expect(sqlStatements!.length).toBe(5); - expect(sqlStatements![0]).toBe(`ALTER TABLE \`old_users\` RENAME TO \`new_users\`;`); - expect(sqlStatements![1]).toBe(`ALTER TABLE \`new_users\` RENAME TO \`__old_push_new_users\`;`); - expect(sqlStatements![2]).toBe(`CREATE TABLE \`new_users\` ( + expect(sqlStatements![0]).toBe( + `ALTER TABLE \`old_users\` RENAME TO \`new_users\`;`, + ); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`age\` integer );\n`); - expect(sqlStatements![3]).toBe( - `INSERT INTO \`new_users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_new_users\`;`, + expect(sqlStatements![2]).toBe( + `INSERT INTO \`__new_new_users\`("id", "age") SELECT "id", "age" FROM \`new_users\`;`, + ); + expect(sqlStatements![3]).toBe(`DROP TABLE \`new_users\`;`); + expect(sqlStatements![4]).toBe( + `ALTER TABLE \`__new_new_users\` RENAME TO \`new_users\`;`, ); - expect(sqlStatements![4]).toBe(`DROP TABLE \`__old_push_new_users\`;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -798,18 +892,18 @@ test('rename table and change data type', async (t) => { expect(tablesToTruncate!.length).toBe(0); }); -test('rename table and change data type', async (t) => { +test('rename column and change data type', async (t) => { const client = new Database(':memory:'); const schema1 = { - users: sqliteTable('old_users', { + users: sqliteTable('users', { id: int('id').primaryKey({ autoIncrement: true }), - age: text('age'), + name: text('name'), }), }; const schema2 = { - users: sqliteTable('new_users', { + users: sqliteTable('users', { id: int('id').primaryKey({ autoIncrement: true }), age: integer('age'), }), @@ -822,22 +916,12 @@ test('rename table and change data type', async (t) => { shouldAskForApprove, tablesToRemove, tablesToTruncate, - } = await diffTestSchemasPushSqlite( - client, - schema1, - schema2, - ['public.old_users->public.new_users'], - ); + } = await diffTestSchemasPushSqlite(client, schema1, schema2, [ + 'public.users.name->public.users.age', + ]); - expect(statements!.length).toBe(2); + expect(statements!.length).toBe(1); expect(statements![0]).toStrictEqual({ - fromSchema: undefined, - tableNameFrom: 'old_users', - tableNameTo: 'new_users', - toSchema: undefined, - type: 'rename_table', - }); - expect(statements![1]).toStrictEqual({ columns: [ { autoincrement: true, @@ -858,22 +942,23 @@ test('rename table and change data type', async (t) => { ], compositePKs: [], referenceData: [], - tableName: 'new_users', + tableName: 'users', type: 'recreate_table', uniqueConstraints: [], }); - expect(sqlStatements!.length).toBe(5); - expect(sqlStatements![0]).toBe(`ALTER TABLE \`old_users\` RENAME TO \`new_users\`;`); - expect(sqlStatements![1]).toBe(`ALTER TABLE \`new_users\` RENAME TO \`__old_push_new_users\`;`); - expect(sqlStatements![2]).toBe(`CREATE TABLE \`new_users\` ( + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, \t\`age\` integer );\n`); + expect(sqlStatements![1]).toBe( + `INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`, + ); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); expect(sqlStatements![3]).toBe( - `INSERT INTO \`new_users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_new_users\`;`, + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); - expect(sqlStatements![4]).toBe(`DROP TABLE \`__old_push_new_users\`;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -882,22 +967,247 @@ test('rename table and change data type', async (t) => { expect(tablesToTruncate!.length).toBe(0); }); -test('rename column and change data type', async (t) => { +test('recreate table with nested references', async (t) => { + const client = new Database(':memory:'); + + let users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: integer('age'), + }); + let subscriptions = sqliteTable('subscriptions', { + id: int('id').primaryKey({ autoIncrement: true }), + userId: integer('user_id').references(() => users.id), + customerId: text('customer_id'), + }); + const schema1 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), + }), + }; + + users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }); + const schema2 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references( + () => subscriptions.id, + ), + }), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite(client, schema1, schema2, [ + 'public.users.name->public.users.age', + ]); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer +);\n`); + expect(sqlStatements![2]).toBe( + `INSERT INTO \`__new_users\`("id", "name", "age") SELECT "id", "name", "age" FROM \`users\`;`, + ); + expect(sqlStatements![3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![4]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + expect(sqlStatements[5]).toBe('PRAGMA foreign_keys=ON;'); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('recreate table with added column not null and without default with data', async (t) => { const client = new Database(':memory:'); const schema1 = { users: sqliteTable('users', { id: int('id').primaryKey({ autoIncrement: true }), name: text('name'), + age: integer('age'), }), }; const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + newColumn: text('new_column').notNull(), + }), + }; + + const seedStatements = [ + `INSERT INTO \`users\` ("name", "age") VALUES ('drizzle', 12)`, + `INSERT INTO \`users\` ("name", "age") VALUES ('turso', 12)`, + ]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + false, + seedStatements, + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + { + autoincrement: false, + name: 'new_column', + notNull: true, + generated: undefined, + primaryKey: false, + type: 'text', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements[0]).toBe('DELETE FROM \`users\`;'); + expect(sqlStatements![1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer, +\t\`new_column\` text NOT NULL +);\n`); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe( + `· You're about to add not-null ${ + chalk.underline('new_column') + } column without default value to table, which contains 2 items`, + ); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(1); + expect(tablesToTruncate![0]).toBe('users'); +}); + +test('recreate table with added column not null and without default with data', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { users: sqliteTable('users', { id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), age: integer('age'), }), }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + newColumn: text('new_column').notNull(), + }), + }; + const { statements, sqlStatements, @@ -910,20 +1220,28 @@ test('rename column and change data type', async (t) => { client, schema1, schema2, - ['public.users.name->public.users.age'], + [], ); expect(statements!.length).toBe(1); expect(statements![0]).toStrictEqual({ columns: [ { - autoincrement: true, + autoincrement: false, name: 'id', notNull: true, generated: undefined, primaryKey: true, type: 'integer', }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, { autoincrement: false, name: 'age', @@ -932,6 +1250,14 @@ test('rename column and change data type', async (t) => { primaryKey: false, type: 'integer', }, + { + autoincrement: false, + name: 'new_column', + notNull: true, + generated: undefined, + primaryKey: false, + type: 'text', + }, ], compositePKs: [], referenceData: [], @@ -941,15 +1267,19 @@ test('rename column and change data type', async (t) => { }); expect(sqlStatements!.length).toBe(4); - expect(sqlStatements![0]).toBe(`ALTER TABLE \`users\` RENAME TO \`__old_push_users\`;`); - expect(sqlStatements![1]).toBe(`CREATE TABLE \`users\` ( -\t\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, -\t\`age\` integer + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer, +\t\`new_column\` text NOT NULL );\n`); - expect(sqlStatements![2]).toBe( - `INSERT INTO \`users\`("id", "age") SELECT ("id", "age") FROM \`__old_push_users\`;`, + expect(sqlStatements[1]).toBe( + 'INSERT INTO `__new_users`("id", "name", "age", "new_column") SELECT "id", "name", "age", "new_column" FROM `users`;', + ); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); - expect(sqlStatements![3]).toBe(`DROP TABLE \`__old_push_users\`;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index e71b95e01..7329db7c9 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -8,7 +8,7 @@ import { sqliteTable, text, } from 'drizzle-orm/sqlite-core'; -import { JsonRecreateTableStatement } from 'src/jsonStatements'; +import { JsonCreateIndexStatement, JsonRecreateTableStatement } from 'src/jsonStatements'; import { expect, test } from 'vitest'; import { diffTestSchemasSqlite } from './schemaDiffer'; @@ -774,6 +774,55 @@ test('alter column add default not null', async (t) => { }); }); +test('alter column add default not null with indexes', async (t) => { + const from = { + users: sqliteTable('table', { + name: text('name'), + }, (table) => ({ + someIndex: index('index_name').on(table.name), + })), + }; + + const to = { + users: sqliteTable('table', { + name: text('name').notNull().default('dan'), + }, (table) => ({ + someIndex: index('index_name').on(table.name), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite( + from, + to, + [], + ); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'recreate_table', + columns: [{ + autoincrement: false, + generated: undefined, + name: 'name', + notNull: true, + primaryKey: false, + type: 'text', + default: "'dan'", + }], + compositePKs: [], + referenceData: [], + tableName: 'table', + uniqueConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + data: 'index_name;name;false;', + schema: '', + tableName: 'table', + type: 'create_index', + internal: undefined, + }); +}); + test('alter column drop default not null', async (t) => { const from = { users: sqliteTable('table', { @@ -851,3 +900,93 @@ test('alter column drop generated', async (t) => { expect(sqlStatements[0]).toBe(`ALTER TABLE \`table\` DROP COLUMN \`name\`;`); expect(sqlStatements[1]).toBe(`ALTER TABLE \`table\` ADD \`name\` text NOT NULL;`); }); + +test('recreate table with nested references', async (t) => { + let users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + name: text('name'), + age: integer('age'), + }); + let subscriptions = sqliteTable('subscriptions', { + id: int('id').primaryKey({ autoIncrement: true }), + userId: integer('user_id').references(() => users.id), + customerId: text('customer_id'), + }); + const schema1 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references(() => subscriptions.id), + }), + }; + + users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }); + const schema2 = { + users: users, + subscriptions: subscriptions, + subscriptionMetadata: sqliteTable('subscriptions_metadata', { + id: int('id').primaryKey({ autoIncrement: true }), + subscriptionId: text('subscription_id').references(() => subscriptions.id), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite( + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'name', + notNull: false, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`__new_users\`("id", "name", "age") SELECT "id", "name", "age" FROM \`users\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); diff --git a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts index 342e55232..47447decd 100644 --- a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts @@ -1181,27 +1181,17 @@ test(`set new type for primary key, unique and normal column`, async (t) => { columnPk: false, }, { - type: 'recreate_table', + type: 'alter_table_alter_column_set_type', tableName: 'unique', - columns: [ - { - name: 'unique', - type: 'text', - primaryKey: false, - notNull: false, - autoincrement: false, - }, - ], - compositePKs: [], - referenceData: [], - uniqueConstraints: [], - }, - { - data: 'unique_unique_unique;unique;true;', - internal: undefined, + columnName: 'unique', + newDataType: 'text', + oldDataType: 'int', schema: '', - tableName: 'unique', - type: 'create_index', + columnDefault: undefined, + columnOnUpdate: undefined, + columnNotNull: false, + columnAutoIncrement: false, + columnPk: false, }, ]; expect(libSQLCombineStatements(statements, json2)).toStrictEqual( From f71baf706af52f999195e056193f8de951a27302 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 15 Aug 2024 19:04:29 +0300 Subject: [PATCH 072/492] changed package json to prev state --- drizzle-kit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index cdb0ab941..25297e5b9 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -38,7 +38,7 @@ "build": "rm -rf ./dist && tsx build.ts && cp package.json dist/ && attw --pack dist", "build:dev": "rm -rf ./dist && tsx build.dev.ts && tsc -p tsconfig.cli-types.json && chmod +x ./dist/index.cjs", "pack": "cp package.json README.md dist/ && (cd dist && npm pack --pack-destination ..) && rm -f package.tgz && mv *.tgz package.tgz", - "tsc": "tsc -p tsconfig.cli-types.json", + "tsc": "tsc -p tsconfig.build.json", "publish": "npm publish package.tgz" }, "dependencies": { From 7e35ccf7e52e885fe09341e799cea7d360faf6e4 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 16 Aug 2024 11:14:25 +0300 Subject: [PATCH 073/492] Update introspect cases --- drizzle-kit/package.json | 1 + drizzle-kit/src/introspect-pg.ts | 156 ++++++++++++--------- drizzle-kit/src/serializer/pgSchema.ts | 7 +- drizzle-kit/src/serializer/pgSerializer.ts | 128 ++++++++++++----- pnpm-lock.yaml | 8 ++ 5 files changed, 193 insertions(+), 107 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 25297e5b9..ddf468e44 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -98,6 +98,7 @@ "pluralize": "^8.0.0", "postgres": "^3.4.4", "prettier": "^2.8.1", + "pure-rand": "^6.1.0", "semver": "^7.5.4", "superjson": "^2.2.1", "tsup": "^8.0.2", diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index d20a96562..8bfb40f59 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -140,6 +140,14 @@ const intervalConfig = (str: string) => { return statement; }; +const mapColumnDefault = (defaultValue: any, isExpression?: boolean) => { + if (isExpression) { + return `sql\`${defaultValue}\``; + } + + return defaultValue; +}; + const importsPatch = { 'double precision': 'doublePrecision', 'timestamp without time zone': 'timestamp', @@ -384,13 +392,14 @@ export const schemaToTypeScript = ( statement += '}'; // more than 2 fields or self reference or cyclic - const filteredFKs = Object.values(table.foreignKeys).filter((it) => { - return it.columnsFrom.length > 1 || isSelf(it); - }); + // Andrii: I switched this one off until we will get custom names in .references() + // const filteredFKs = Object.values(table.foreignKeys).filter((it) => { + // return it.columnsFrom.length > 1 || isSelf(it); + // }); if ( Object.keys(table.indexes).length > 0 - || filteredFKs.length > 0 + || Object.values(table.foreignKeys).length > 0 || Object.keys(table.compositePrimaryKeys).length > 0 || Object.keys(table.uniqueConstraints).length > 0 ) { @@ -402,7 +411,7 @@ export const schemaToTypeScript = ( Object.values(table.indexes), casing, ); - statement += createTableFKs(Object.values(filteredFKs), schemas, casing); + statement += createTableFKs(Object.values(table.foreignKeys), schemas, casing); statement += createTablePKs( Object.values(table.compositePrimaryKeys), casing, @@ -468,7 +477,20 @@ const column = ( defaultValue?: any, internals?: PgKitInternals, ) => { + const isExpression = internals?.tables[tableName]?.columns[name]?.isDefaultAnExpression ?? false; const lowered = type.toLowerCase(); + + if (enumTypes.has(type)) { + let out = `${withCasing(name, casing)}: ${ + withCasing( + type, + casing, + ) + }("${name}")`; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return out; + } + if (lowered.startsWith('serial')) { return `${withCasing(name, casing)}: serial("${name}")`; } @@ -488,38 +510,38 @@ const column = ( if (lowered.startsWith('integer')) { let out = `${withCasing(name, casing)}: integer("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('smallint')) { let out = `${withCasing(name, casing)}: smallint("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('bigint')) { let out = `// You can use { mode: "bigint" } if numbers are exceeding js number limitations\n\t`; out += `${withCasing(name, casing)}: bigint("${name}", { mode: "number" })`; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('boolean')) { let out = `${withCasing(name, casing)}: boolean("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('double precision')) { let out = `${withCasing(name, casing)}: doublePrecision("${name}")`; - out += defaultValue ? `.default(${defaultValue})` : ''; + out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('real')) { let out = `${withCasing(name, casing)}: real("${name}")`; - out += defaultValue ? `.default(${defaultValue})` : ''; + out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } @@ -555,7 +577,7 @@ const column = ( ? defaultValue.substring(1, defaultValue.length - 1) : defaultValue : undefined; - out += defaultValue ? `.default('${defaultValue}')` : ''; + out += defaultValue ? `.default('${mapColumnDefault(defaultValue, isExpression)}')` : ''; return out; } @@ -590,10 +612,12 @@ const column = ( // ? defaultValue.substring(0, defaultValue.length - 26) // : defaultValue; - defaultValue = defaultValue === 'now()' || defaultValue === 'CURRENT_TIMESTAMP' + defaultValue = defaultValue === 'now()' ? '.defaultNow()' + : defaultValue === 'CURRENT_TIMESTAMP' + ? '.default(sql\`CURRENT_TIMESTAMP\`)' : defaultValue - ? `.default(${defaultValue})` + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; out += defaultValue; @@ -621,7 +645,7 @@ const column = ( defaultValue = defaultValue === 'now()' ? '.defaultNow()' : defaultValue - ? `.default(${defaultValue})` + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; out += defaultValue; @@ -640,7 +664,7 @@ const column = ( ? `${withCasing(name, casing)}: interval("${name}", ${params})` : `${withCasing(name, casing)}: interval("${name}")`; - out += defaultValue ? `.default(${defaultValue})` : ''; + out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } @@ -699,7 +723,7 @@ const column = ( // ? defaultValue.substring(0, defaultValue.length - 6) // : defaultValue; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } @@ -710,7 +734,7 @@ const column = ( // ? defaultValue.substring(0, defaultValue.length - 6) // : defaultValue; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } @@ -721,7 +745,7 @@ const column = ( // ? defaultValue.substring(0, defaultValue.length - 9) // : defaultValue; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } @@ -732,7 +756,7 @@ const column = ( // ? defaultValue.substring(0, defaultValue.length - 10) // : defaultValue; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } @@ -760,21 +784,21 @@ const column = ( // ? defaultValue.substring(0, defaultValue.length - 19) // : defaultValue; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('point')) { let out: string = `${withCasing(name, casing)}: point("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('line')) { let out: string = `${withCasing(name, casing)}: point("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } @@ -798,7 +822,7 @@ const column = ( out = `${withCasing(name, casing)}: geometry("${name}")`; } - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; if (isGeoUnknown) { let unknown = @@ -829,7 +853,7 @@ const column = ( out = `${withCasing(name, casing)}: vector("${name}")`; } - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } @@ -857,7 +881,7 @@ const column = ( // ? defaultValue.substring(0, defaultValue.length - 8) // : defaultValue; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } @@ -876,22 +900,11 @@ const column = ( casing, ) }("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } } - if (enumTypes.has(type)) { - let out = `${withCasing(name, casing)}: ${ - withCasing( - type, - casing, - ) - }("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; - return out; - } - let unknown = `// TODO: failed to parse database type '${type}'\n`; unknown += `\t${withCasing(name, casing)}: unknown("${name}")`; return unknown; @@ -985,37 +998,38 @@ const createTableColumns = ( ? `.generatedAlwaysAs(sql\`${it.generated.as}\`)` : ''; - const fks = fkByColumnName[it.name]; - if (fks) { - const fksStatement = fks - .map((it) => { - const onDelete = it.onDelete && it.onDelete !== 'no action' ? it.onDelete : null; - const onUpdate = it.onUpdate && it.onUpdate !== 'no action' ? it.onUpdate : null; - const params = { onDelete, onUpdate }; - - const typeSuffix = isCyclic(it) ? ': AnyPgColumn' : ''; - - const paramsStr = objToStatement2(params); - const tableSchema = schemas[it.schemaTo || '']; - const paramName = paramNameFor(it.tableTo, tableSchema); - if (paramsStr) { - return `.references(()${typeSuffix} => ${ - withCasing( - paramName, - casing, - ) - }.${withCasing(it.columnsTo[0], casing)}, ${paramsStr} )`; - } - return `.references(()${typeSuffix} => ${ - withCasing( - paramName, - casing, - ) - }.${withCasing(it.columnsTo[0], casing)})`; - }) - .join(''); - statement += fksStatement; - } + // const fks = fkByColumnName[it.name]; + // Andrii: I switched it off until we will get a custom naem setting in references + // if (fks) { + // const fksStatement = fks + // .map((it) => { + // const onDelete = it.onDelete && it.onDelete !== 'no action' ? it.onDelete : null; + // const onUpdate = it.onUpdate && it.onUpdate !== 'no action' ? it.onUpdate : null; + // const params = { onDelete, onUpdate }; + + // const typeSuffix = isCyclic(it) ? ': AnyPgColumn' : ''; + + // const paramsStr = objToStatement2(params); + // const tableSchema = schemas[it.schemaTo || '']; + // const paramName = paramNameFor(it.tableTo, tableSchema); + // if (paramsStr) { + // return `.references(()${typeSuffix} => ${ + // withCasing( + // paramName, + // casing, + // ) + // }.${withCasing(it.columnsTo[0], casing)}, ${paramsStr} )`; + // } + // return `.references(()${typeSuffix} => ${ + // withCasing( + // paramName, + // casing, + // ) + // }.${withCasing(it.columnsTo[0], casing)})`; + // }) + // .join(''); + // statement += fksStatement; + // } statement += ',\n'; }); @@ -1058,7 +1072,9 @@ const createTableIndexes = ( if (it.isExpression) { return `sql\`${it.expression}\``; } else { - return `table.${withCasing(it.expression, casing)}${ + return `table.${withCasing(it.expression, casing)}${it.asc ? '.asc()' : '.desc()'}${ + it.nulls === 'first' ? '.nullsFirst()' : '.nullsLast()' + }${ it.opclass && vectorOps.includes(it.opclass) ? `.op("${it.opclass}")` : '' diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index 7e4a55afd..5860a6fef 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -1,3 +1,4 @@ +import { vectorOps } from 'src/extensions/vector'; import { mapValues, originUUID, snapshotVersion } from '../global'; import { any, array, boolean, enum as enumType, literal, number, object, record, string, TypeOf, union } from 'zod'; @@ -282,6 +283,7 @@ export const kitInternals = object({ isArray: boolean().optional(), dimensions: number().optional(), rawType: string().optional(), + isDefaultAnExpression: boolean().optional(), }).optional(), ), }).optional(), @@ -464,7 +466,10 @@ export const PgSquasher = { return `${idx.name};${ idx.columns .map( - (c) => `${c.expression}--${c.isExpression}--${c.asc}--${c.nulls}--${c.opclass}`, + (c) => + `${c.expression}--${c.isExpression}--${c.asc}--${c.nulls}--${ + c.opclass && vectorOps.includes(c.opclass) ? c.opclass : '' + }`, ) .join(',,') };${idx.isUnique};${idx.concurrently};${idx.method};${idx.where};${JSON.stringify(idx.with)}`; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 6470cf1ff..1daf9437d 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -772,30 +772,42 @@ export const fromDatabase = async ( const tableForeignKeys = await db.query( `SELECT - tc.table_schema, - tc.constraint_name, - tc.table_name, - kcu.column_name, - ( - SELECT ccu.table_schema - FROM information_schema.constraint_column_usage ccu - WHERE ccu.constraint_name = tc.constraint_name - LIMIT 1 - ) AS foreign_table_schema, - ccu.table_name AS foreign_table_name, - ccu.column_name AS foreign_column_name, - rc.delete_rule, - rc.update_rule - FROM - information_schema.table_constraints AS tc - JOIN information_schema.key_column_usage AS kcu - ON tc.constraint_name = kcu.constraint_name - AND tc.table_schema = kcu.table_schema - JOIN information_schema.constraint_column_usage AS ccu - ON ccu.constraint_name = tc.constraint_name - JOIN information_schema.referential_constraints AS rc - ON ccu.constraint_name = rc.constraint_name - WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_name='${tableName}' and tc.table_schema='${tableSchema}';`, + con.contype AS constraint_type, + nsp.nspname AS constraint_schema, + con.conname AS constraint_name, + rel.relname AS table_name, + att.attname AS column_name, + fnsp.nspname AS foreign_table_schema, + frel.relname AS foreign_table_name, + fatt.attname AS foreign_column_name, + CASE con.confupdtype + WHEN 'a' THEN 'NO ACTION' + WHEN 'r' THEN 'RESTRICT' + WHEN 'n' THEN 'SET NULL' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + END AS update_rule, + CASE con.confdeltype + WHEN 'a' THEN 'NO ACTION' + WHEN 'r' THEN 'RESTRICT' + WHEN 'n' THEN 'SET NULL' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + END AS delete_rule + FROM + pg_catalog.pg_constraint con + JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + JOIN pg_catalog.pg_namespace nsp ON nsp.oid = con.connamespace + LEFT JOIN pg_catalog.pg_attribute att ON att.attnum = ANY (con.conkey) + AND att.attrelid = con.conrelid + LEFT JOIN pg_catalog.pg_class frel ON frel.oid = con.confrelid + LEFT JOIN pg_catalog.pg_namespace fnsp ON fnsp.oid = frel.relnamespace + LEFT JOIN pg_catalog.pg_attribute fatt ON fatt.attnum = ANY (con.confkey) + AND fatt.attrelid = con.confrelid + WHERE + nsp.nspname = '${tableSchema}' + AND rel.relname = '${tableName}' + AND con.contype IN ('f');`, ); foreignKeysCount += tableForeignKeys.length; @@ -903,6 +915,30 @@ export const fromDatabase = async ( } const defaultValue = defaultForColumn(columnResponse); + if (defaultValue === 'NULL') { + if (typeof internals!.tables![tableName] === 'undefined') { + internals!.tables![tableName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, + }, + }; + } else { + if ( + typeof internals!.tables![tableName]!.columns[columnName] + === 'undefined' + ) { + internals!.tables![tableName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![tableName]!.columns[ + columnName + ]!.isDefaultAnExpression = true; + } + } + } const isSerial = columnType === 'serial'; @@ -1173,11 +1209,11 @@ export const fromDatabase = async ( const columnToDefault: Record = { 'numeric(': '::numeric', // text: "::text", - // "character varying": "::character varying", + 'character varying': '::character varying', // "double precision": "::double precision", // "time with time zone": "::time with time zone", 'time without time zone': '::time without time zone', - // "timestamp with time zone": "::timestamp with time zone", + // 'timestamp with time zone': '::timestamp with time zone', 'timestamp without time zone': '::timestamp without time zone', 'timestamp(': '::timestamp without time zone', // date: "::date", @@ -1192,6 +1228,13 @@ const columnToDefault: Record = { 'character(': '::bpchar', }; +const columnEnumNameToDefault: Record = { + timestamptz: '::timestamp with time zone', + timestmap: '::time without time zone', + time: '::time without time zone', + timetz: '::time with time zone', +}; + const defaultForColumn = (column: any) => { if (column.column_default === null) { return undefined; @@ -1206,15 +1249,24 @@ const defaultForColumn = (column: any) => { } const hasDifferentDefaultCast = Object.keys(columnToDefault).find((it) => column.data_type.startsWith(it)); + const hasDifferentDefaultCastForEnum = Object.keys(columnEnumNameToDefault).find((it) => + column.enum_name.startsWith(it) + ); const columnDefaultAsString: string = column.column_default.toString(); + const endsWithEnumName = columnDefaultAsString.endsWith( + hasDifferentDefaultCastForEnum + ? columnEnumNameToDefault[hasDifferentDefaultCastForEnum] + : (column.data_type as string), + ); + + const endsWithTypeName = columnDefaultAsString.endsWith( + hasDifferentDefaultCast ? columnToDefault[hasDifferentDefaultCast] : (column.data_type as string), + ); + if ( - columnDefaultAsString.endsWith( - hasDifferentDefaultCast - ? columnToDefault[hasDifferentDefaultCast] - : (column.data_type as string), - ) + endsWithTypeName || endsWithEnumName ) { const nonPrefixPart = column.column_default.length - (hasDifferentDefaultCast @@ -1222,9 +1274,7 @@ const defaultForColumn = (column: any) => { : `::${column.data_type as string}`).length - 1; - const rt = column.column_default - .toString() - .substring(1, nonPrefixPart) as string; + const rt = column.column_default.toString().substring(0, nonPrefixPart + 1) as string; if ( /^-?[\d.]+(?:e-?\d+)?$/.test(rt) @@ -1240,8 +1290,12 @@ const defaultForColumn = (column: any) => { }`; } else if (column.data_type === 'boolean') { return column.column_default === 'true'; + } else if (rt === 'NULL') { + return `NULL`; + } else if (rt.startsWith("'") && rt.endsWith("'")) { + return rt; } else { - return `'${rt}'`; + return `\'${rt}\'`; } } else { if ( @@ -1251,8 +1305,10 @@ const defaultForColumn = (column: any) => { return Number(columnDefaultAsString); } else if (column.data_type === 'boolean') { return column.column_default === 'true'; + } else if (columnDefaultAsString === 'NULL') { + return `NULL`; } else { - return `${columnDefaultAsString}`; + return `${columnDefaultAsString.replace(/\\/g, '\`\\')}`; } } }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2fb00d93d..c0e69af3c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -254,6 +254,9 @@ importers: prettier: specifier: ^2.8.1 version: 2.8.8 + pure-rand: + specifier: ^6.1.0 + version: 6.1.0 semver: specifier: ^7.5.4 version: 7.6.2 @@ -8395,6 +8398,9 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qrcode-terminal@0.11.0: resolution: {integrity: sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==} hasBin: true @@ -19787,6 +19793,8 @@ snapshots: punycode@2.3.1: {} + pure-rand@6.1.0: {} + qrcode-terminal@0.11.0: {} qs@6.11.0: From bddd9522f5ca67310914f1305a5ef075824e4d19 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Fri, 16 Aug 2024 12:17:23 +0300 Subject: [PATCH 074/492] updated tests --- drizzle-kit/tests/push/libsql.test.ts | 58 ------------------------ drizzle-kit/tests/push/sqlite.test.ts | 1 + drizzle-kit/tests/sqlite-columns.test.ts | 23 ++++++++++ 3 files changed, 24 insertions(+), 58 deletions(-) diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 3506cef32..482caa995 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -515,64 +515,6 @@ test('change autoincrement. table is part of foreign key', async (t) => { expect(tablesToTruncate!.length).toBe(0); }); -test('create table with custom name references', async (t) => { - const turso = createClient({ - url: ':memory:', - }); - - const users = sqliteTable('users', { - id: int('id').primaryKey({ autoIncrement: true }), - name: text('name').notNull(), - }); - - const schema1 = { - users, - posts: sqliteTable( - 'posts', - { - id: int('id').primaryKey({ autoIncrement: true }), - name: text('name'), - userId: int('user_id'), - }, - (t) => ({ - fk: foreignKey({ - columns: [t.id], - foreignColumns: [users.id], - name: 'custom_name_fk', - }), - }), - ), - }; - - const schema2 = { - users, - posts: sqliteTable( - 'posts', - { - id: int('id').primaryKey({ autoIncrement: true }), - name: text('name'), - userId: int('user_id'), - }, - (t) => ({ - fk: foreignKey({ - columns: [t.id], - foreignColumns: [users.id], - name: 'custom_name_fk', - }), - }), - ), - }; - - const { sqlStatements } = await diffTestSchemasPushLibSQL( - turso, - schema1, - schema2, - [], - ); - - expect(sqlStatements!.length).toBe(0); -}); - test('drop not null, add not null', async (t) => { const turso = createClient({ url: ':memory:', diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index e52559256..aea5cd379 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -395,6 +395,7 @@ test('drop autoincrement. drop column with data', async (t) => { ); expect(columnsToRemove!.length).toBe(1); + expect(columnsToRemove![0]).toBe('name'); expect(infoToPrint!.length).toBe(1); expect(infoToPrint![0]).toBe( `· You're about to delete ${ diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index 7329db7c9..04dbb940c 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -821,6 +821,18 @@ test('alter column add default not null with indexes', async (t) => { type: 'create_index', internal: undefined, }); + expect(sqlStatements.length).toBe(7); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_table\` ( +\t\`name\` text DEFAULT 'dan' NOT NULL +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`__new_table\`("name") SELECT "name" FROM \`table\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`table\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_table\` RENAME TO \`table\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); + expect(sqlStatements[6]).toBe(`CREATE INDEX \`index_name\` ON \`table\` (\`name\`);`); }); test('alter column drop default not null', async (t) => { @@ -858,6 +870,17 @@ test('alter column drop default not null', async (t) => { tableName: 'table', uniqueConstraints: [], }); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_table\` ( +\t\`name\` text +);\n`); + expect(sqlStatements[2]).toBe( + `INSERT INTO \`__new_table\`("name") SELECT "name" FROM \`table\`;`, + ); + expect(sqlStatements[3]).toBe(`DROP TABLE \`table\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_table\` RENAME TO \`table\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); test('alter column drop generated', async (t) => { From 733887a45dbdd6f9a4858a4a7202e8c8f7d754f1 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 19 Aug 2024 16:57:21 +0300 Subject: [PATCH 075/492] Handle enums propely in postgres --- drizzle-kit/src/introspect-mysql.ts | 15 ++++++--- drizzle-kit/src/introspect-pg.ts | 37 ++++++++++++++++------ drizzle-kit/src/introspect-sqlite.ts | 13 ++++++-- drizzle-kit/src/serializer/pgSerializer.ts | 8 +++-- 4 files changed, 54 insertions(+), 19 deletions(-) diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index 21be79654..f206935a3 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -101,15 +101,22 @@ const importsPatch = { const relations = new Set(); +const escapeColumnKey = (value: string) => { + if (/^(?![a-zA-Z_$][a-zA-Z0-9_$]*$).+$/.test(value)) { + return `"${value}"`; + } + return value; +}; + const prepareCasing = (casing?: Casing) => (value: string) => { - if (typeof casing === 'undefined') { - return value; + if (casing === 'preserve') { + return escapeColumnKey(value); } if (casing === 'camel') { - return value.camelCase(); + return escapeColumnKey(value.camelCase()); } - return value; + return escapeColumnKey(value); }; export const schemaToTypeScript = ( diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index 8bfb40f59..208939457 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -158,12 +158,19 @@ const importsPatch = { const relations = new Set(); +const escapeColumnKey = (value: string) => { + if (/^(?![a-zA-Z_$][a-zA-Z0-9_$]*$).+$/.test(value)) { + return `"${value}"`; + } + return value; +}; + const withCasing = (value: string, casing: Casing) => { if (casing === 'preserve') { - return value; + return escapeColumnKey(value); } if (casing === 'camel') { - return value.camelCase(); + return escapeColumnKey(value.camelCase()); } assertUnreachable(casing); @@ -298,7 +305,13 @@ export const schemaToTypeScript = ( }), ); - const enumTypes = new Set(Object.values(schema.enums).map((it) => it.name)); + const enumTypes = Object.values(schema.enums).reduce( + (acc, cur) => { + acc.add(`${cur.schema}.${cur.name}`); + return acc; + }, + new Set(), + ); const imports = Object.values(schema.tables).reduce( (res, it) => { @@ -325,10 +338,6 @@ export const schemaToTypeScript = ( res.pg.push(...pkImports); res.pg.push(...uniqueImports); - if (enumTypes.size > 0) { - res.pg.push('pgEnum'); - } - const columnImports = Object.values(it.columns) .map((col) => { let patched: string = importsPatch[col.type] || col.type; @@ -351,6 +360,14 @@ export const schemaToTypeScript = ( { pg: [] as string[] }, ); + Object.values(schema.enums).forEach((it) => { + if (it.schema && it.schema !== 'public' && it.schema !== '') { + imports.pg.push('pgSchema'); + } else if (it.schema === 'public') { + imports.pg.push('pgEnum'); + } + }); + const enumStatements = Object.values(schema.enums) .map((it) => { const enumSchema = schemas[it.schema]; @@ -473,6 +490,7 @@ const column = ( type: string, name: string, enumTypes: Set, + typeSchema: string, casing: Casing, defaultValue?: any, internals?: PgKitInternals, @@ -480,10 +498,10 @@ const column = ( const isExpression = internals?.tables[tableName]?.columns[name]?.isDefaultAnExpression ?? false; const lowered = type.toLowerCase(); - if (enumTypes.has(type)) { + if (enumTypes.has(`${typeSchema}.${type}`)) { let out = `${withCasing(name, casing)}: ${ withCasing( - type, + paramNameFor(type, typeSchema), casing, ) }("${name}")`; @@ -950,6 +968,7 @@ const createTableColumns = ( it.type, it.name, enumTypes, + it.typeSchema ?? 'public', casing, it.default, internals, diff --git a/drizzle-kit/src/introspect-sqlite.ts b/drizzle-kit/src/introspect-sqlite.ts index 9ff119ce6..b4a729f4c 100644 --- a/drizzle-kit/src/introspect-sqlite.ts +++ b/drizzle-kit/src/introspect-sqlite.ts @@ -38,12 +38,19 @@ const objToStatement2 = (json: any) => { const relations = new Set(); +const escapeColumnKey = (value: string) => { + if (/^(?![a-zA-Z_$][a-zA-Z0-9_$]*$).+$/.test(value)) { + return `"${value}"`; + } + return value; +}; + const withCasing = (value: string, casing?: Casing) => { - if (typeof casing === 'undefined') { - return value; + if (casing === 'preserve') { + return escapeColumnKey(value); } if (casing === 'camel') { - return value.camelCase(); + return escapeColumnKey(value.camelCase()); } return value; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 1daf9437d..7e5db78ad 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -739,7 +739,7 @@ export const fromDatabase = async ( WHEN 'int2'::regtype THEN 'smallserial' END ELSE format_type(a.atttypid, a.atttypmod) - END AS data_type, INFORMATION_SCHEMA.COLUMNS.table_name, + END AS data_type, INFORMATION_SCHEMA.COLUMNS.table_name, ns.nspname as type_schema, pg_get_serial_sequence('"${tableSchema}"."${tableName}"', a.attname)::regclass as seq_name, INFORMATION_SCHEMA.COLUMNS.column_name, INFORMATION_SCHEMA.COLUMNS.column_default, INFORMATION_SCHEMA.COLUMNS.data_type as additional_dt, INFORMATION_SCHEMA.COLUMNS.udt_name as enum_name, @@ -750,6 +750,7 @@ export const fromDatabase = async ( INFORMATION_SCHEMA.COLUMNS.identity_cycle FROM pg_attribute a JOIN INFORMATION_SCHEMA.COLUMNS ON INFORMATION_SCHEMA.COLUMNS.column_name = a.attname + JOIN pg_type t ON t.oid = a.atttypid LEFT JOIN pg_namespace ns ON ns.oid = t.typnamespace WHERE a.attrelid = '"${tableSchema}"."${tableName}"'::regclass and INFORMATION_SCHEMA.COLUMNS.table_name = '${tableName}' and INFORMATION_SCHEMA.COLUMNS.table_schema = '${tableSchema}' AND a.attnum > 0 AND NOT a.attisdropped @@ -875,6 +876,7 @@ export const fromDatabase = async ( const columnDimensions = columnResponse.array_dimensions; const enumType: string = columnResponse.enum_name; let columnType: string = columnResponse.data_type; + const typeSchema = columnResponse.type_schema; const isGenerated = columnResponse.is_generated === 'ALWAYS'; const generationExpression = columnResponse.generation_expression; @@ -1002,8 +1004,8 @@ export const fromDatabase = async ( && !['vector', 'geometry'].includes(enumType) ? enumType : columnTypeMapped, - typeSchema: enumsToReturn[`${tableSchema}.${enumType}`] !== undefined - ? enumsToReturn[`${tableSchema}.${enumType}`].schema + typeSchema: enumsToReturn[`${typeSchema}.${enumType}`] !== undefined + ? enumsToReturn[`${typeSchema}.${enumType}`].schema : undefined, primaryKey: primaryKey.length === 1 && cprimaryKey.length < 2, // default: isSerial ? undefined : defaultValue, From 8d865121982f439c70236ec86a73d0996fef2dfc Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 20 Aug 2024 17:28:11 +0300 Subject: [PATCH 076/492] Add fixes after tests failed --- drizzle-kit/src/serializer/pgSerializer.ts | 5 ++++- drizzle-kit/tests/indexes/pg.test.ts | 12 ++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 7e5db78ad..aa75100f8 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -1276,7 +1276,7 @@ const defaultForColumn = (column: any) => { : `::${column.data_type as string}`).length - 1; - const rt = column.column_default.toString().substring(0, nonPrefixPart + 1) as string; + let rt = column.column_default.toString().substring(0, nonPrefixPart + 1) as string; if ( /^-?[\d.]+(?:e-?\d+)?$/.test(rt) @@ -1284,6 +1284,9 @@ const defaultForColumn = (column: any) => { ) { return Number(rt); } else if (column.data_type === 'json' || column.data_type === 'jsonb') { + if (rt.startsWith("'")) { + rt = rt.slice(1, -1); + } const jsonWithoutSpaces = JSON.stringify(JSON.parse(rt)); return `'${jsonWithoutSpaces}'${ hasDifferentDefaultCast diff --git a/drizzle-kit/tests/indexes/pg.test.ts b/drizzle-kit/tests/indexes/pg.test.ts index 8419fd765..9958a2356 100644 --- a/drizzle-kit/tests/indexes/pg.test.ts +++ b/drizzle-kit/tests/indexes/pg.test.ts @@ -125,12 +125,12 @@ const pgSuite: DialectSuite = { expect(sqlStatements).toStrictEqual([ 'DROP INDEX IF EXISTS "indx";', 'DROP INDEX IF EXISTS "indx1";', - 'DROP INDEX IF EXISTS "indx2";', + // 'DROP INDEX IF EXISTS "indx2";', 'DROP INDEX IF EXISTS "indx3";', 'CREATE INDEX IF NOT EXISTS "indx4" ON "users" USING btree (lower(id)) WHERE true;', 'CREATE INDEX IF NOT EXISTS "indx" ON "users" USING btree ("name" DESC NULLS LAST);', 'CREATE INDEX IF NOT EXISTS "indx1" ON "users" USING btree ("name" DESC NULLS LAST) WHERE false;', - 'CREATE INDEX IF NOT EXISTS "indx2" ON "users" USING btree ("name" test) WHERE true;', + // 'CREATE INDEX IF NOT EXISTS "indx2" ON "users" USING btree ("name" test) WHERE true;', 'CREATE INDEX IF NOT EXISTS "indx3" ON "users" USING btree (lower("id")) WHERE true;', ]); }, @@ -180,14 +180,14 @@ const pgSuite: DialectSuite = { expression: 'name', isExpression: false, nulls: 'last', - opclass: undefined, + opclass: '', }, { asc: true, expression: 'id', isExpression: false, nulls: 'last', - opclass: undefined, + opclass: '', }, ], concurrently: false, @@ -212,14 +212,14 @@ const pgSuite: DialectSuite = { expression: 'name', isExpression: false, nulls: 'last', - opclass: undefined, + opclass: '', }, { asc: true, expression: '"name"', isExpression: true, nulls: 'last', - opclass: undefined, + opclass: '', }, ], concurrently: false, From cf99e712b55ddc9e116e3f525c3bff7d0a6ae5f9 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 21 Aug 2024 21:17:06 +0300 Subject: [PATCH 077/492] Update all cases for defaults in postgres --- drizzle-kit/src/introspect-pg.ts | 454 +++++++++++++-------- drizzle-kit/src/serializer/pgSerializer.ts | 225 +++++----- drizzle-kit/src/sqlgenerator.ts | 1 + drizzle-kit/tests/introspect/pg.test.ts | 221 +++++++++- drizzle-kit/tests/pg-array.test.ts | 24 +- drizzle-kit/tests/push/pg.test.ts | 8 +- 6 files changed, 621 insertions(+), 312 deletions(-) diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index 208939457..bae1e488c 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -282,6 +282,33 @@ export const relationsToTypeScriptForStudio = ( return result; }; +function generateIdentityParams(identity: Column['identity']) { + let paramsObj = `{ name: "${identity!.name}"`; + if (identity?.startWith) { + paramsObj += `, startWith: ${identity.startWith}`; + } + if (identity?.increment) { + paramsObj += `, increment: ${identity.increment}`; + } + if (identity?.minValue) { + paramsObj += `, minValue: ${identity.minValue}`; + } + if (identity?.maxValue) { + paramsObj += `, maxValue: ${identity.maxValue}`; + } + if (identity?.cache) { + paramsObj += `, cache: ${identity.cache}`; + } + if (identity?.cycle) { + paramsObj += `, cycle: true`; + } + paramsObj += ' }'; + if (identity?.type === 'always') { + return `.generatedAlwaysAsIdentity(${paramsObj})`; + } + return `.generatedByDefaultAsIdentity(${paramsObj})`; +} + export const paramNameFor = (name: string, schema?: string) => { const schemaSuffix = schema && schema !== 'public' ? `In${schema.capitalise()}` : ''; return `${name}${schemaSuffix}`; @@ -340,7 +367,8 @@ export const schemaToTypeScript = ( const columnImports = Object.values(it.columns) .map((col) => { - let patched: string = importsPatch[col.type] || col.type; + let patched: string = (importsPatch[col.type] || col.type).replace('[]', ''); + patched = patched === 'double precision' ? 'doublePrecision' : patched; patched = patched.startsWith('varchar(') ? 'varchar' : patched; patched = patched.startsWith('char(') ? 'char' : patched; patched = patched.startsWith('numeric(') ? 'numeric' : patched; @@ -360,6 +388,14 @@ export const schemaToTypeScript = ( { pg: [] as string[] }, ); + Object.values(schema.sequences).forEach((it) => { + if (it.schema && it.schema !== 'public' && it.schema !== '') { + imports.pg.push('pgSchema'); + } else if (it.schema === 'public') { + imports.pg.push('pgSequence'); + } + }); + Object.values(schema.enums).forEach((it) => { if (it.schema && it.schema !== 'public' && it.schema !== '') { imports.pg.push('pgSchema'); @@ -384,6 +420,43 @@ export const schemaToTypeScript = ( .join('') .concat('\n'); + const sequencesStatements = Object.values(schema.sequences) + .map((it) => { + const seqSchema = schemas[it.schema]; + const paramName = paramNameFor(it.name, seqSchema); + + const func = seqSchema ? `${seqSchema}.sequence` : 'pgSequence'; + + let params = ''; + + if (it.startWith) { + params += `, startWith: "${it.startWith}"`; + } + if (it.increment) { + params += `, increment: "${it.increment}"`; + } + if (it.minValue) { + params += `, minValue: "${it.minValue}"`; + } + if (it.maxValue) { + params += `, maxValue: "${it.maxValue}"`; + } + if (it.cache) { + params += `, cache: "${it.cache}"`; + } + if (it.cycle) { + params += `, cycle: true`; + } else { + params += `, cycle: false`; + } + + return `export const ${withCasing(paramName, casing)} = ${func}("${it.name}"${ + params ? `, { ${params.trimChar(',')} }` : '' + })\n`; + }) + .join('') + .concat('\n'); + const schemaStatements = Object.entries(schemas) // .filter((it) => it[0] !== "public") .map((it) => { @@ -456,6 +529,7 @@ export const schemaToTypeScript = ( let decalrations = schemaStatements; decalrations += enumStatements; + decalrations += sequencesStatements; decalrations += '\n'; decalrations += tableStatements.join('\n\n'); @@ -485,6 +559,188 @@ const isSelf = (fk: ForeignKey) => { return fk.tableFrom === fk.tableTo; }; +const buildArrayDefault = (defaultValue: string, typeName: string): string => { + if (typeof defaultValue === 'string' && !(defaultValue.startsWith('{') || defaultValue.startsWith("'{"))) { + return `sql\`${defaultValue}\``; + } + defaultValue = defaultValue.substring(2, defaultValue.length - 2); + return `[${ + defaultValue + .split(/\s*,\s*/g) + .map((value) => { + // if (['integer', 'smallint', 'bigint', 'double precision', 'real'].includes(typeName)) { + // return value; + // } else if (typeName === 'interval') { + // return value.replaceAll('"', "'"); + // } else if (typeName === 'boolean') { + // return value === 't' ? 'true' : 'false'; + if (typeName === 'json' || typeName === 'jsonb') { + return value + .substring(1, value.length - 1) + .replaceAll('\\', ''); + } + return value; + // } + }) + .join(', ') + }]`; +}; + +const mapDefault = ( + tableName: string, + type: string, + name: string, + enumTypes: Set, + typeSchema: string, + defaultValue?: any, + internals?: PgKitInternals, +) => { + const isExpression = internals?.tables[tableName]?.columns[name]?.isDefaultAnExpression ?? false; + const isArray = internals?.tables[tableName]?.columns[name]?.isArray ?? false; + const lowered = type.toLowerCase().replace('[]', ''); + + if (isArray) { + return typeof defaultValue !== 'undefined' ? `.default(${buildArrayDefault(defaultValue, lowered)})` : ''; + } + + if (enumTypes.has(`${typeSchema}.${type.replace('[]', '')}`)) { + return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + } + + if (lowered.startsWith('integer')) { + return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + } + + if (lowered.startsWith('smallint')) { + return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + } + + if (lowered.startsWith('bigint')) { + return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + } + + if (lowered.startsWith('boolean')) { + return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + } + + if (lowered.startsWith('double precision')) { + return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + } + + if (lowered.startsWith('real')) { + return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + } + + if (lowered.startsWith('uuid')) { + return defaultValue === 'gen_random_uuid()' + ? '.defaultRandom()' + : defaultValue + ? `.default(sql\`${defaultValue}\`)` + : ''; + } + + if (lowered.startsWith('numeric')) { + defaultValue = defaultValue + ? defaultValue.startsWith(`'`) && defaultValue.endsWith(`'`) + ? defaultValue.substring(1, defaultValue.length - 1) + : defaultValue + : undefined; + return defaultValue ? `.default('${mapColumnDefault(defaultValue, isExpression)}')` : ''; + } + + if (lowered.startsWith('timestamp')) { + return defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue === 'CURRENT_TIMESTAMP' + ? '.default(sql\`CURRENT_TIMESTAMP\`)' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + } + + if (lowered.startsWith('time')) { + return defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + } + + if (lowered.startsWith('interval')) { + return defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + } + + if (lowered === 'date') { + return defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue === 'CURRENT_DATE' + ? `.default(sql\`${defaultValue}\`)` + : defaultValue + ? `.default(${defaultValue})` + : ''; + } + + if (lowered.startsWith('text')) { + return typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + } + + if (lowered.startsWith('jsonb')) { + const def = typeof defaultValue !== 'undefined' + ? defaultValue.replace(/::(.*?)(? { const isExpression = internals?.tables[tableName]?.columns[name]?.isDefaultAnExpression ?? false; - const lowered = type.toLowerCase(); + const lowered = type.toLowerCase().replace('[]', ''); - if (enumTypes.has(`${typeSchema}.${type}`)) { + if (enumTypes.has(`${typeSchema}.${type.replace('[]', '')}`)) { let out = `${withCasing(name, casing)}: ${ withCasing( - paramNameFor(type, typeSchema), + paramNameFor(type.replace('[]', ''), typeSchema), casing, ) }("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } @@ -528,49 +783,38 @@ const column = ( if (lowered.startsWith('integer')) { let out = `${withCasing(name, casing)}: integer("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('smallint')) { let out = `${withCasing(name, casing)}: smallint("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('bigint')) { let out = `// You can use { mode: "bigint" } if numbers are exceeding js number limitations\n\t`; out += `${withCasing(name, casing)}: bigint("${name}", { mode: "number" })`; - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('boolean')) { let out = `${withCasing(name, casing)}: boolean("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('double precision')) { let out = `${withCasing(name, casing)}: doublePrecision("${name}")`; - out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('real')) { let out = `${withCasing(name, casing)}: real("${name}")`; - out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('uuid')) { let out = `${withCasing(name, casing)}: uuid("${name}")`; - out += defaultValue === 'gen_random_uuid()' - ? '.defaultRandom()' - : defaultValue - ? `.default(sql\`${defaultValue}\`)` - : ''; return out; } @@ -590,13 +834,6 @@ const column = ( ? `${withCasing(name, casing)}: numeric("${name}", ${timeConfig(params)})` : `${withCasing(name, casing)}: numeric("${name}")`; - defaultValue = defaultValue - ? defaultValue.startsWith(`'`) && defaultValue.endsWith(`'`) - ? defaultValue.substring(1, defaultValue.length - 1) - : defaultValue - : undefined; - out += defaultValue ? `.default('${mapColumnDefault(defaultValue, isExpression)}')` : ''; - return out; } @@ -622,23 +859,6 @@ const column = ( ? `${withCasing(name, casing)}: timestamp("${name}", ${params})` : `${withCasing(name, casing)}: timestamp("${name}")`; - // defaultValue = defaultValue?.endsWith("::timestamp without time zone") - // ? defaultValue.substring(0, defaultValue.length - 29) - // : defaultValue; - - // defaultValue = defaultValue?.endsWith("::timestamp with time zone") - // ? defaultValue.substring(0, defaultValue.length - 26) - // : defaultValue; - - defaultValue = defaultValue === 'now()' - ? '.defaultNow()' - : defaultValue === 'CURRENT_TIMESTAMP' - ? '.default(sql\`CURRENT_TIMESTAMP\`)' - : defaultValue - ? `.default(${mapColumnDefault(defaultValue, isExpression)})` - : ''; - - out += defaultValue; return out; } @@ -660,13 +880,6 @@ const column = ( ? `${withCasing(name, casing)}: time("${name}", ${params})` : `${withCasing(name, casing)}: time("${name}")`; - defaultValue = defaultValue === 'now()' - ? '.defaultNow()' - : defaultValue - ? `.default(${mapColumnDefault(defaultValue, isExpression)})` - : ''; - - out += defaultValue; return out; } @@ -682,105 +895,51 @@ const column = ( ? `${withCasing(name, casing)}: interval("${name}", ${params})` : `${withCasing(name, casing)}: interval("${name}")`; - out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered === 'date') { let out = `${withCasing(name, casing)}: date("${name}")`; - defaultValue = defaultValue === 'now()' - ? '.defaultNow()' - : defaultValue === 'CURRENT_DATE' - ? `.default(sql\`${defaultValue}\`)` - : defaultValue - ? `.default(${defaultValue})` - : ''; - - out += defaultValue; return out; } if (lowered.startsWith('text')) { let out = `${withCasing(name, casing)}: text("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; return out; } - if (lowered === 'json') { - let out = `${withCasing(name, casing)}: json("${name}")`; - // defaultValue = defaultValue?.replace("::json", ""); - - defaultValue = defaultValue?.endsWith('::json') - ? defaultValue.substring(1, defaultValue.length - 7) - : defaultValue; - // const def = defaultValue ? objToStatement(JSON.parse(defaultValue)) : null; - const def = defaultValue ? defaultValue : null; - - out += typeof defaultValue !== 'undefined' ? `.default(${def})` : ''; + if (lowered.startsWith('jsonb')) { + let out = `${withCasing(name, casing)}: jsonb("${name}")`; return out; } - if (lowered === 'jsonb') { - let out = `${withCasing(name, casing)}: jsonb("${name}")`; - - defaultValue = defaultValue?.endsWith('::jsonb') - ? defaultValue.substring(1, defaultValue.length - 8) - : defaultValue; - // const def = defaultValue ? objToStatement(JSON.parse(defaultValue)) : null; - const def = typeof defaultValue !== 'undefined' ? defaultValue : null; - - out += defaultValue ? `.default(${def})` : ''; + if (lowered.startsWith('json')) { + let out = `${withCasing(name, casing)}: json("${name}")`; return out; } if (lowered.startsWith('inet')) { let out = `${withCasing(name, casing)}: inet("${name}")`; - - // defaultValue = defaultValue?.endsWith("::inet") - // ? defaultValue.substring(0, defaultValue.length - 6) - // : defaultValue; - - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('cidr')) { let out = `${withCasing(name, casing)}: cidr("${name}")`; - - // defaultValue = defaultValue?.endsWith("::cidr") - // ? defaultValue.substring(0, defaultValue.length - 6) - // : defaultValue; - - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; - return out; - } - - if (lowered.startsWith('macaddr')) { - let out = `${withCasing(name, casing)}: macaddr("${name}")`; - - // defaultValue = defaultValue?.endsWith("::macaddr") - // ? defaultValue.substring(0, defaultValue.length - 9) - // : defaultValue; - - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('macaddr8')) { let out = `${withCasing(name, casing)}: macaddr8("${name}")`; + return out; + } - // defaultValue = defaultValue?.endsWith("::macaddr8") - // ? defaultValue.substring(0, defaultValue.length - 10) - // : defaultValue; - - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + if (lowered.startsWith('macaddr')) { + let out = `${withCasing(name, casing)}: macaddr("${name}")`; return out; } if (lowered.startsWith('varchar')) { - const split = lowered.split(' '); - let out: string; if (lowered.length !== 7) { out = `${ @@ -798,25 +957,16 @@ const column = ( out = `${withCasing(name, casing)}: varchar("${name}")`; } - // defaultValue = defaultValue?.endsWith("::character varying") - // ? defaultValue.substring(0, defaultValue.length - 19) - // : defaultValue; - - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('point')) { let out: string = `${withCasing(name, casing)}: point("${name}")`; - - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('line')) { let out: string = `${withCasing(name, casing)}: point("${name}")`; - - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } @@ -840,8 +990,6 @@ const column = ( out = `${withCasing(name, casing)}: geometry("${name}")`; } - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; - if (isGeoUnknown) { let unknown = `// TODO: failed to parse geometry type because found more than 2 options inside geometry function '${type}'\n// Introspect is currently supporting only type and srid options\n`; @@ -852,8 +1000,6 @@ const column = ( } if (lowered.startsWith('vector')) { - const split = lowered.split(' '); - let out: string; if (lowered.length !== 6) { out = `${ @@ -871,13 +1017,10 @@ const column = ( out = `${withCasing(name, casing)}: vector("${name}")`; } - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } if (lowered.startsWith('char')) { - // const split = lowered.split(" "); - let out: string; if (lowered.length !== 4) { out = `${ @@ -895,34 +1038,9 @@ const column = ( out = `${withCasing(name, casing)}: char("${name}")`; } - // defaultValue = defaultValue?.endsWith("::bpchar") - // ? defaultValue.substring(0, defaultValue.length - 8) - // : defaultValue; - - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } - // if internal has this column - use it - const columnInternals = internals?.tables[tableName]?.columns[name]; - if (typeof columnInternals !== 'undefined') { - // it means there is enum as array case - if ( - columnInternals.isArray - && columnInternals.rawType - && enumTypes.has(columnInternals.rawType) - ) { - let out = `${withCasing(columnInternals.rawType, casing)}: ${ - withCasing( - columnInternals.rawType, - casing, - ) - }("${name}")`; - out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; - return out; - } - } - let unknown = `// TODO: failed to parse database type '${type}'\n`; unknown += `\t${withCasing(name, casing)}: unknown("${name}")`; return unknown; @@ -981,36 +1099,18 @@ const createTableColumns = ( internals?.tables[tableName]?.columns[it.name]?.dimensions, ); } + statement += mapDefault( + tableName, + it.type, + it.name, + enumTypes, + it.typeSchema ?? 'public', + it.default, + internals, + ); statement += it.primaryKey ? '.primaryKey()' : ''; statement += it.notNull && !it.identity ? '.notNull()' : ''; - function generateIdentityParams(identity: Column['identity']) { - let paramsObj = `{ name: "${identity!.name}"`; - if (identity?.startWith) { - paramsObj += `, startWith: ${identity.startWith}`; - } - if (identity?.increment) { - paramsObj += `, increment: ${identity.increment}`; - } - if (identity?.minValue) { - paramsObj += `, minValue: ${identity.minValue}`; - } - if (identity?.maxValue) { - paramsObj += `, maxValue: ${identity.maxValue}`; - } - if (identity?.cache) { - paramsObj += `, cache: ${identity.cache}`; - } - if (identity?.cycle) { - paramsObj += `, cycle: true`; - } - paramsObj += ' }'; - if (identity?.type === 'always') { - return `.generatedAlwaysAsIdentity(${paramsObj})`; - } - return `.generatedByDefaultAsIdentity(${paramsObj})`; - } - statement += it.identity ? generateIdentityParams(it.identity) : ''; statement += it.generated diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index aa75100f8..32e045f5c 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -269,7 +269,7 @@ export const generatePgSnapshot = ( column.default, sqlTypeLowered, ) - }'::${sqlTypeLowered}`; + }'`; } else { // Should do for all types // columnToSet.default = `'${column.default}'::${sqlTypeLowered}`; @@ -916,40 +916,8 @@ export const fromDatabase = async ( }; } - const defaultValue = defaultForColumn(columnResponse); - if (defaultValue === 'NULL') { - if (typeof internals!.tables![tableName] === 'undefined') { - internals!.tables![tableName] = { - columns: { - [columnName]: { - isDefaultAnExpression: true, - }, - }, - }; - } else { - if ( - typeof internals!.tables![tableName]!.columns[columnName] - === 'undefined' - ) { - internals!.tables![tableName]!.columns[columnName] = { - isDefaultAnExpression: true, - }; - } else { - internals!.tables![tableName]!.columns[ - columnName - ]!.isDefaultAnExpression = true; - } - } - } - - const isSerial = columnType === 'serial'; - let columnTypeMapped = columnType; - if (columnTypeMapped.startsWith('numeric(')) { - columnTypeMapped = columnTypeMapped.replace(',', ', '); - } - // Set default to internal object if (columnAdditionalDT === 'ARRAY') { if (typeof internals.tables[tableName] === 'undefined') { @@ -982,6 +950,42 @@ export const fromDatabase = async ( } } + const defaultValue = defaultForColumn( + columnResponse, + internals, + tableName, + ); + if (defaultValue === 'NULL') { + if (typeof internals!.tables![tableName] === 'undefined') { + internals!.tables![tableName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, + }, + }; + } else { + if ( + typeof internals!.tables![tableName]!.columns[columnName] + === 'undefined' + ) { + internals!.tables![tableName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![tableName]!.columns[ + columnName + ]!.isDefaultAnExpression = true; + } + } + } + + const isSerial = columnType === 'serial'; + + if (columnTypeMapped.startsWith('numeric(')) { + columnTypeMapped = columnTypeMapped.replace(',', ', '); + } + if (columnAdditionalDT === 'ARRAY') { for (let i = 1; i < Number(columnDimensions); i++) { columnTypeMapped += '[]'; @@ -1208,36 +1212,10 @@ export const fromDatabase = async ( }; }; -const columnToDefault: Record = { - 'numeric(': '::numeric', - // text: "::text", - 'character varying': '::character varying', - // "double precision": "::double precision", - // "time with time zone": "::time with time zone", - 'time without time zone': '::time without time zone', - // 'timestamp with time zone': '::timestamp with time zone', - 'timestamp without time zone': '::timestamp without time zone', - 'timestamp(': '::timestamp without time zone', - // date: "::date", - // interval: "::interval", - // character: "::bpchar", - // macaddr8: "::macaddr8", - // macaddr: "::macaddr", - // inet: "::inet", - // cidr: "::cidr", - // jsonb: "::jsonb", - // json: "::json", - 'character(': '::bpchar', -}; - -const columnEnumNameToDefault: Record = { - timestamptz: '::timestamp with time zone', - timestmap: '::time without time zone', - time: '::time without time zone', - timetz: '::time with time zone', -}; +const defaultForColumn = (column: any, internals: PgKitInternals, tableName: string) => { + const columnName = column.attname; + const isArray = internals?.tables[tableName]?.columns[columnName]?.isArray ?? false; -const defaultForColumn = (column: any) => { if (column.column_default === null) { return undefined; } @@ -1250,70 +1228,81 @@ const defaultForColumn = (column: any) => { return undefined; } - const hasDifferentDefaultCast = Object.keys(columnToDefault).find((it) => column.data_type.startsWith(it)); - const hasDifferentDefaultCastForEnum = Object.keys(columnEnumNameToDefault).find((it) => - column.enum_name.startsWith(it) - ); + if (column.column_default.endsWith('[]')) { + column.column_default = column.column_default.slice(0, -2); + } - const columnDefaultAsString: string = column.column_default.toString(); + // if ( + // !['integer', 'smallint', 'bigint', 'double precision', 'real'].includes(column.data_type) + // ) { + column.column_default = column.column_default.replace(/::(.*?)(? { + if (['integer', 'smallint', 'bigint', 'double precision', 'real'].includes(column.data_type.slice(0, -2))) { + return value; + } else if (column.data_type.startsWith('timestamp')) { + return `${value}`; + } else if (column.data_type.slice(0, -2) === 'interval') { + return value.replaceAll('"', `\"`); + } else if (column.data_type.slice(0, -2) === 'boolean') { + return value === 't' ? 'true' : 'false'; + } else if (['json', 'jsonb'].includes(column.data_type.slice(0, -2))) { + return JSON.stringify(JSON.stringify(JSON.parse(JSON.parse(value)), null, 0)); + } else { + return `\"${value}\"`; + } + }) + .join(',') + }}'`; + } if ( - endsWithTypeName || endsWithEnumName + ['integer', 'smallint', 'bigint', 'double precision', 'real'].includes(column.data_type) ) { - const nonPrefixPart = column.column_default.length - - (hasDifferentDefaultCast - ? columnToDefault[hasDifferentDefaultCast] - : `::${column.data_type as string}`).length - - 1; - - let rt = column.column_default.toString().substring(0, nonPrefixPart + 1) as string; - - if ( - /^-?[\d.]+(?:e-?\d+)?$/.test(rt) - && !column.data_type.startsWith('numeric') - ) { - return Number(rt); - } else if (column.data_type === 'json' || column.data_type === 'jsonb') { - if (rt.startsWith("'")) { - rt = rt.slice(1, -1); - } - const jsonWithoutSpaces = JSON.stringify(JSON.parse(rt)); - return `'${jsonWithoutSpaces}'${ - hasDifferentDefaultCast - ? columnToDefault[hasDifferentDefaultCast] - : `::${column.data_type as string}` - }`; - } else if (column.data_type === 'boolean') { - return column.column_default === 'true'; - } else if (rt === 'NULL') { - return `NULL`; - } else if (rt.startsWith("'") && rt.endsWith("'")) { - return rt; - } else { - return `\'${rt}\'`; - } - } else { - if ( - /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefaultAsString) - && !column.data_type.startsWith('numeric') - ) { + if (/^-?[\d.]+(?:e-?\d+)?$/.test(columnDefaultAsString)) { return Number(columnDefaultAsString); - } else if (column.data_type === 'boolean') { - return column.column_default === 'true'; - } else if (columnDefaultAsString === 'NULL') { - return `NULL`; } else { - return `${columnDefaultAsString.replace(/\\/g, '\`\\')}`; + if (typeof internals!.tables![tableName] === 'undefined') { + internals!.tables![tableName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, + }, + }; + } else { + if ( + typeof internals!.tables![tableName]!.columns[columnName] + === 'undefined' + ) { + internals!.tables![tableName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![tableName]!.columns[ + columnName + ]!.isDefaultAnExpression = true; + } + } + return columnDefaultAsString; } + } else if (column.data_type === 'json' || column.data_type === 'jsonb') { + const jsonWithoutSpaces = JSON.stringify(JSON.parse(columnDefaultAsString.slice(1, -1))); + return `'${jsonWithoutSpaces}'::${column.data_type}`; + } else if (column.data_type === 'boolean') { + return column.column_default === 'true'; + } else if (columnDefaultAsString === 'NULL') { + return `NULL`; + } else if (columnDefaultAsString.startsWith("'") && columnDefaultAsString.endsWith("'")) { + return columnDefaultAsString; + } else { + return `${columnDefaultAsString.replace(/\\/g, '\`\\')}`; } }; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 769da7c5a..30517d0f2 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -106,6 +106,7 @@ const isPgNativeType = (it: string) => { || toCheck.startsWith('char(') || toCheck.startsWith('numeric(') || toCheck.startsWith('timestamp(') + || toCheck.startsWith('doubleprecision[') || toCheck.startsWith('intervalyear(') || toCheck.startsWith('intervalmonth(') || toCheck.startsWith('intervalday(') diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index 40b06187f..3efb57d7e 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -1,6 +1,34 @@ import { PGlite } from '@electric-sql/pglite'; import { SQL, sql } from 'drizzle-orm'; -import { integer, pgTable, text } from 'drizzle-orm/pg-core'; +import { + bigint, + bigserial, + boolean, + char, + cidr, + date, + doublePrecision, + inet, + integer, + interval, + json, + jsonb, + macaddr, + macaddr8, + numeric, + pgEnum, + pgSchema, + pgTable, + real, + serial, + smallint, + smallserial, + text, + time, + timestamp, + uuid, + varchar, +} from 'drizzle-orm/pg-core'; import { introspectPgToFile } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; @@ -186,3 +214,194 @@ test('generated column: link to another column', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('instrospect all column types', async () => { + const client = new PGlite(); + + const myEnum = pgEnum('my_enum', ['a', 'b', 'c']); + const schema = { + enum_: myEnum, + // NOTE: Types from extensions aren't tested due to PGLite not supporting at the moment + columns: pgTable('columns', { + enum: myEnum('my_enum').default('a'), + smallint: smallint('smallint').default(10), + integer: integer('integer').default(10), + numeric: numeric('numeric', { precision: 3, scale: 1 }).default('99.9'), + bigint: bigint('bigint', { mode: 'number' }).default(100), + boolean: boolean('boolean').default(true), + text: text('test').default('abc'), + varchar: varchar('varchar', { length: 25 }).default('abc'), + char: char('char', { length: 3 }).default('abc'), + serial: serial('serial'), + bigserial: bigserial('bigserial', { mode: 'number' }), + smallserial: smallserial('smallserial'), + doublePrecision: doublePrecision('doublePrecision').default(100), + real: real('real').default(100), + json: json('json').$type<{ attr: string }>().default({ attr: 'value' }), + jsonb: jsonb('jsonb').$type<{ attr: string }>().default({ attr: 'value' }), + time1: time('time1').default('00:00:00'), + time2: time('time2').defaultNow(), + timestamp1: timestamp('timestamp1', { withTimezone: true, precision: 6 }).default(new Date()), + timestamp2: timestamp('timestamp2', { withTimezone: true, precision: 6 }).defaultNow(), + date1: date('date1').default('2024-01-01'), + date2: date('date2').defaultNow(), + uuid1: uuid('uuid1').default('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'), + uuid2: uuid('uuid2').defaultRandom(), + inet: inet('inet').default('127.0.0.1'), + cidr: cidr('cidr').default('127.0.0.1/32'), + macaddr: macaddr('macaddr').default('00:00:00:00:00:00'), + macaddr8: macaddr8('macaddr8').default('00:00:00:ff:fe:00:00:00'), + interval: interval('interval').default('1 day 01:00:00'), + }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-all-columns-types', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('instrospect all column array types', async () => { + const client = new PGlite(); + + const myEnum = pgEnum('my_enum', ['a', 'b', 'c']); + const schema = { + enum_: myEnum, + // NOTE: Types from extensions aren't tested due to PGLite not supporting at the moment + columns: pgTable('columns', { + enum: myEnum('my_enum').array().default(['a', 'b']), + smallint: smallint('smallint').array().default([10, 20]), + integer: integer('integer').array().default([10, 20]), + numeric: numeric('numeric', { precision: 3, scale: 1 }).array().default(['99.9', '88.8']), + bigint: bigint('bigint', { mode: 'number' }).array().default([100, 200]), + boolean: boolean('boolean').array().default([true, false]), + text: text('test').array().default(['abc', 'def']), + varchar: varchar('varchar', { length: 25 }).array().default(['abc', 'def']), + char: char('char', { length: 3 }).array().default(['abc', 'def']), + doublePrecision: doublePrecision('doublePrecision').array().default([100, 200]), + real: real('real').array().default([100, 200]), + json: json('json').$type<{ attr: string }>().array().default([{ attr: 'value1' }, { attr: 'value2' }]), + jsonb: jsonb('jsonb').$type<{ attr: string }>().array().default([{ attr: 'value1' }, { attr: 'value2' }]), + time: time('time').array().default(['00:00:00', '01:00:00']), + timestamp: timestamp('timestamp', { withTimezone: true, precision: 6 }) + .array() + .default([new Date(), new Date()]), + date: date('date').array().default(['2024-01-01', '2024-01-02']), + uuid: uuid('uuid').array().default([ + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', + 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12', + ]), + inet: inet('inet').array().default(['127.0.0.1', '127.0.0.2']), + cidr: cidr('cidr').array().default(['127.0.0.1/32', '127.0.0.2/32']), + macaddr: macaddr('macaddr').array().default(['00:00:00:00:00:00', '00:00:00:00:00:01']), + macaddr8: macaddr8('macaddr8').array().default(['00:00:00:ff:fe:00:00:00', '00:00:00:ff:fe:00:00:01']), + interval: interval('interval').array().default(['1 day 01:00:00', '1 day 02:00:00']), + }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-all-columns-array-types', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect columns with name with non-alphanumeric characters', async () => { + const client = new PGlite(); + const schema = { + users: pgTable('users', { + 'not:allowed': integer('not:allowed'), + 'nuh--uh': integer('nuh-uh'), + '1_nope': integer('1_nope'), + valid: integer('valid'), + }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-column-with-name-with-non-alphanumeric-characters', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect enum from different schema', async () => { + const client = new PGlite(); + + const schema2 = pgSchema('schema2'); + const myEnumInSchema2 = schema2.enum('my_enum', ['a', 'b', 'c']); + const schema = { + schema2, + myEnumInSchema2, + users: pgTable('users', { + col: myEnumInSchema2('col'), + }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-enum-from-different-schema', + ['public', 'schema2'], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect enum with same names across different schema', async () => { + const client = new PGlite(); + + const schema2 = pgSchema('schema2'); + const myEnumInSchema2 = schema2.enum('my_enum', ['a', 'b', 'c']); + const myEnum = pgEnum('my_enum', ['a', 'b', 'c']); + const schema = { + schema2, + myEnumInSchema2, + myEnum, + users: pgTable('users', { + col1: myEnumInSchema2('col1'), + col2: myEnum('col2'), + }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-enum-with-same-names-across-different-schema', + ['public', 'schema2'], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect enum with similar name to native type', async () => { + const client = new PGlite(); + + const timeLeft = pgEnum('time_left', ['short', 'medium', 'long']); + const schema = { + timeLeft, + auction: pgTable('auction', { + col: timeLeft('col1'), + }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-enum-with-similar-name-to-native-type', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/pg-array.test.ts b/drizzle-kit/tests/pg-array.test.ts index a35411adb..e6c06d535 100644 --- a/drizzle-kit/tests/pg-array.test.ts +++ b/drizzle-kit/tests/pg-array.test.ts @@ -34,7 +34,7 @@ test('array #1: empty array default', async (t) => { type: 'alter_table_add_column', tableName: 'test', schema: '', - column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'::integer[]" }, + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'" }, }); }); @@ -58,7 +58,7 @@ test('array #2: integer array default', async (t) => { type: 'alter_table_add_column', tableName: 'test', schema: '', - column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'::integer[]" }, + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'" }, }); }); @@ -82,7 +82,7 @@ test('array #3: bigint array default', async (t) => { type: 'alter_table_add_column', tableName: 'test', schema: '', - column: { name: 'values', type: 'bigint[]', primaryKey: false, notNull: false, default: "'{1,2,3}'::bigint[]" }, + column: { name: 'values', type: 'bigint[]', primaryKey: false, notNull: false, default: "'{1,2,3}'" }, }); }); @@ -111,7 +111,7 @@ test('array #4: boolean array default', async (t) => { type: 'boolean[]', primaryKey: false, notNull: false, - default: "'{true,false,true}'::boolean[]", + default: "'{true,false,true}'", }, }); }); @@ -141,7 +141,7 @@ test('array #5: multi-dimensional array default', async (t) => { type: 'integer[][]', primaryKey: false, notNull: false, - default: "'{{1,2},{3,4}}'::integer[][]", + default: "'{{1,2},{3,4}}'", }, }); }); @@ -171,7 +171,7 @@ test('array #6: date array default', async (t) => { type: 'date[]', primaryKey: false, notNull: false, - default: '\'{"2024-08-06","2024-08-07"}\'::date[]', + default: '\'{"2024-08-06","2024-08-07"}\'', }, }); }); @@ -201,7 +201,7 @@ test('array #7: timestamp array default', async (t) => { type: 'timestamp[]', primaryKey: false, notNull: false, - default: '\'{"2024-08-06 00:00:00.000","2024-08-07 00:00:00.000"}\'::timestamp[]', + default: '\'{"2024-08-06 00:00:00.000","2024-08-07 00:00:00.000"}\'', }, }); }); @@ -231,7 +231,7 @@ test('array #8: json array default', async (t) => { type: 'json[]', primaryKey: false, notNull: false, - default: '\'{"{\\"a\\":1}","{\\"b\\":2}"}\'::json[]', + default: '\'{"{\\"a\\":1}","{\\"b\\":2}"}\'', }, }); }); @@ -261,7 +261,7 @@ test('array #9: text array default', async (t) => { type: 'text[]', primaryKey: false, notNull: false, - default: '\'{"abc","def"}\'::text[]', + default: '\'{"abc","def"}\'', }, }); }); @@ -294,7 +294,7 @@ test('array #10: uuid array default', async (t) => { type: 'uuid[]', primaryKey: false, notNull: false, - default: '\'{"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11","b0eebc99-9c0b-4ef8-bb6d-cbb9bd380a11"}\'::uuid[]', + default: '\'{"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11","b0eebc99-9c0b-4ef8-bb6d-cbb9bd380a11"}\'', }, }); }); @@ -328,7 +328,7 @@ test('array #11: enum array default', async (t) => { type: 'test_enum[]', primaryKey: false, notNull: false, - default: '\'{"a","b","c"}\'::test_enum[]', + default: '\'{"a","b","c"}\'', }, }); }); @@ -362,7 +362,7 @@ test('array #12: enum empty array default', async (t) => { type: 'test_enum[]', primaryKey: false, notNull: false, - default: "'{}'::test_enum[]", + default: "'{}'", }, }); }); diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index cd5908bad..cb1a97122 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -2192,11 +2192,11 @@ test('add array column - empty array default', async () => { type: 'alter_table_add_column', tableName: 'test', schema: '', - column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'::integer[]" }, + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'" }, }, ]); expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{}\'::integer[];', + 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{}\';', ]); }); @@ -2229,10 +2229,10 @@ test('add array column - default', async () => { type: 'alter_table_add_column', tableName: 'test', schema: '', - column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'::integer[]" }, + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'" }, }, ]); expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\'::integer[];', + 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\';', ]); }); From 5df8253eb4601ddd23750e81ebec5f086a38d3ef Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 22 Aug 2024 12:27:33 +0300 Subject: [PATCH 078/492] Fix xata expressions --- drizzle-kit/src/introspect-pg.ts | 2 +- drizzle-kit/src/serializer/pgSerializer.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index bae1e488c..b7a52b735 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -681,7 +681,7 @@ const mapDefault = ( } if (lowered.startsWith('text')) { - return typeof defaultValue !== 'undefined' ? `.default(${defaultValue})` : ''; + return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; } if (lowered.startsWith('jsonb')) { diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 32e045f5c..11fb325e8 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -877,6 +877,7 @@ export const fromDatabase = async ( const enumType: string = columnResponse.enum_name; let columnType: string = columnResponse.data_type; const typeSchema = columnResponse.type_schema; + const defaultValueRes: string = columnResponse.column_default; const isGenerated = columnResponse.is_generated === 'ALWAYS'; const generationExpression = columnResponse.generation_expression; @@ -955,7 +956,10 @@ export const fromDatabase = async ( internals, tableName, ); - if (defaultValue === 'NULL') { + if ( + defaultValue === 'NULL' + || (defaultValueRes && defaultValueRes.startsWith('(') && defaultValueRes.endsWith(')')) + ) { if (typeof internals!.tables![tableName] === 'undefined') { internals!.tables![tableName] = { columns: { From 781dea05b41de2bee323e2ee9d000b7b5e25091b Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 22 Aug 2024 15:38:20 +0300 Subject: [PATCH 079/492] Add 0.24.1 release notes --- changelogs/drizzle-kit/0.24.1.md | 32 ++++++++++++++++++++++ drizzle-kit/package.json | 3 +- drizzle-kit/src/cli/commands/utils.ts | 6 ++-- drizzle-kit/src/cli/validations/cli.ts | 2 +- drizzle-kit/src/serializer/pgSerializer.ts | 11 ++++++-- pnpm-lock.yaml | 30 ++++++++------------ 6 files changed, 56 insertions(+), 28 deletions(-) create mode 100644 changelogs/drizzle-kit/0.24.1.md diff --git a/changelogs/drizzle-kit/0.24.1.md b/changelogs/drizzle-kit/0.24.1.md new file mode 100644 index 000000000..d70f6ebbe --- /dev/null +++ b/changelogs/drizzle-kit/0.24.1.md @@ -0,0 +1,32 @@ +## Bug fixes + +> Big thanks to @L-Mario564 for his [PR](https://github.com/drizzle-team/drizzle-orm/pull/2804). It conflicted in most cases with a PR that was merged, but we incorporated some of his logic. Merging it would have caused more problems and taken more time to resolve, so we just took a few things from his PR, like removing "::" mappings in introspect and some array type default handlers + +### What was fixed + +1. The Drizzle Kit CLI was not working properly for the `introspect` command. +2. Added the ability to use column names with special characters for all dialects. +3. Included PostgreSQL sequences in the introspection process. +4. Reworked array type introspection and added all test cases. +5. Fixed all (we hope) default issues in PostgreSQL, where `::` was included in the introspected output. +6. `preserve` casing option was broken + +### Tickets that were closed + +- [[BUG]: invalid schema generation with drizzle-kit introspect:pg](https://github.com/drizzle-team/drizzle-orm/issues/1210) +- [[BUG][mysql introspection]: TS error when introspect column including colon](https://github.com/drizzle-team/drizzle-orm/issues/1928) +- [[BUG]: Unhandled defaults when introspecting postgres db](https://github.com/drizzle-team/drizzle-orm/issues/1625) +- [[BUG]: PostgreSQL Enum Naming and Schema Typing Issue](https://github.com/drizzle-team/drizzle-orm/issues/2315) +- [[BUG]: drizzle-kit instrospect command generates syntax error on varchar column types](https://github.com/drizzle-team/drizzle-orm/issues/2714) +- [[BUG]: Introspecting varchar[] type produces syntactically invalid schema.ts](https://github.com/drizzle-team/drizzle-orm/issues/1633) +- [[BUG]: introspect:pg column not using generated enum name](https://github.com/drizzle-team/drizzle-orm/issues/1648) +- [[BUG]: drizzle-kit introspect casing "preserve" config not working](https://github.com/drizzle-team/drizzle-orm/issues/2773) +- [[BUG]: drizzle-kit introspect fails on required param that is defined](https://github.com/drizzle-team/drizzle-orm/issues/2719) +- [[BUG]: Error when running npx drizzle-kit introspect: "Expected object, received string"](https://github.com/drizzle-team/drizzle-orm/issues/2657) +- [[BUG]: Missing index names when running introspect command [MYSQL]](https://github.com/drizzle-team/drizzle-orm/issues/2525) +- [[BUG]: drizzle-kit introspect TypeError: Cannot read properties of undefined (reading 'toLowerCase')](https://github.com/drizzle-team/drizzle-orm/issues/2338) +- [[BUG]: Wrong column name when using PgEnum.array()](https://github.com/drizzle-team/drizzle-orm/issues/2100) +- [[BUG]: Incorrect Schema Generated when introspecting extisting pg database](https://github.com/drizzle-team/drizzle-orm/issues/1985) +- [[⚠️🐞BUG]: index() missing argument after introspection, causes tsc error that fails the build](https://github.com/drizzle-team/drizzle-orm/issues/1870) +- [[BUG]: drizzle-kit introspect small errors](https://github.com/drizzle-team/drizzle-orm/issues/1738) +- [[BUG]: Missing bigint import in drizzle-kit introspect](https://github.com/drizzle-team/drizzle-orm/issues/1020) \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 19370cc2c..b2e780e1a 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.24.0", + "version": "0.24.1", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", @@ -98,7 +98,6 @@ "pluralize": "^8.0.0", "postgres": "^3.4.4", "prettier": "^2.8.1", - "pure-rand": "^6.1.0", "semver": "^7.5.4", "superjson": "^2.2.1", "tsup": "^8.0.2", diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 4957816c8..7cf503248 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -408,7 +408,7 @@ export const preparePullConfig = async ( dialect: 'postgresql', out: config.out, breakpoints: config.breakpoints, - casing: config.introspectCasing, + casing: config.casing, credentials: parsed.data, tablesFilter, schemasFilter, @@ -426,7 +426,7 @@ export const preparePullConfig = async ( dialect: 'mysql', out: config.out, breakpoints: config.breakpoints, - casing: config.introspectCasing, + casing: config.casing, credentials: parsed.data, tablesFilter, schemasFilter, @@ -444,7 +444,7 @@ export const preparePullConfig = async ( dialect: 'sqlite', out: config.out, breakpoints: config.breakpoints, - casing: config.introspectCasing, + casing: config.casing, credentials: parsed.data, tablesFilter, schemasFilter, diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index 53e8dadb8..c4bbbe530 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -38,7 +38,7 @@ export const pullParams = object({ .optional() .default(['public']), extensionsFilters: literal('postgis').array().optional(), - introspectCasing: casing, + casing, breakpoints: boolean().optional().default(true), migrations: object({ prefix: prefix.optional().default('index'), diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 11fb325e8..b479e59e2 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -822,8 +822,8 @@ export const fromDatabase = async ( const columnTo: string = fk.foreign_column_name; const schemaTo: string = fk.foreign_table_schema; const foreignKeyName = fk.constraint_name; - const onUpdate = fk.update_rule.toLowerCase(); - const onDelete = fk.delete_rule.toLowerCase(); + const onUpdate = fk.update_rule?.toLowerCase(); + const onDelete = fk.delete_rule?.toLowerCase(); if (typeof foreignKeysToReturn[foreignKeyName] !== 'undefined') { foreignKeysToReturn[foreignKeyName].columnsFrom.push(columnFrom); @@ -1041,7 +1041,12 @@ export const fromDatabase = async ( }; if (identityName) { - delete sequencesToReturn[`${tableSchema}.${identityName}`]; + // remove "" from sequence name + delete sequencesToReturn[ + `${tableSchema}.${ + identityName.startsWith('"') && identityName.endsWith('"') ? identityName.slice(1, -1) : identityName + }` + ]; delete sequencesToReturn[identityName]; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed56f743e..d2d091ad6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -254,9 +254,6 @@ importers: prettier: specifier: ^2.8.1 version: 2.8.8 - pure-rand: - specifier: ^6.1.0 - version: 6.1.0 semver: specifier: ^7.5.4 version: 7.6.2 @@ -8345,9 +8342,6 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - qrcode-terminal@0.11.0: resolution: {integrity: sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==} hasBin: true @@ -10216,7 +10210,7 @@ snapshots: '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10306,7 +10300,7 @@ snapshots: '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10616,7 +10610,7 @@ snapshots: '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10805,12 +10799,12 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.0.0 @@ -10895,13 +10889,13 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-http': 3.582.0 - '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.0.0 @@ -10976,10 +10970,10 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-sso@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/credential-provider-sso@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': dependencies: '@aws-sdk/client-sso': 3.583.0 - '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -11222,7 +11216,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': dependencies: '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 @@ -19689,8 +19683,6 @@ snapshots: punycode@2.3.1: {} - pure-rand@6.1.0: {} - qrcode-terminal@0.11.0: {} qs@6.11.0: From c6dcf2bd3279f54535dd569aa439bd0b49931ff7 Mon Sep 17 00:00:00 2001 From: juliusmarminge Date: Thu, 22 Aug 2024 17:32:10 +0200 Subject: [PATCH 080/492] change order --- drizzle-kit/src/sqlgenerator.ts | 22 +++++++++------------- package.json | 3 ++- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 30517d0f2..ec1a2d69e 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -163,7 +163,7 @@ class PgCreateTableConvertor extends Convertor { : `${schemaPrefix}"${column.type}"`; const generated = column.generated; - const generatedStatement = ` GENERATED ALWAYS AS (${generated?.as}) STORED`; + const generatedStatement = generated ? ` GENERATED ALWAYS AS (${generated?.as}) STORED` : ''; const unsquashedIdentity = column.identity ? PgSquasher.unsquashIdentity(column.identity) @@ -198,9 +198,7 @@ class PgCreateTableConvertor extends Convertor { : ''; statement += '\t' - + `"${column.name}" ${type}${primaryKeyStatement}${defaultStatement}${notNullStatement}${uniqueConstraint}${ - generated ? generatedStatement : '' - }${identity}`; + + `"${column.name}" ${type}${primaryKeyStatement}${defaultStatement}${generatedStatement}${notNullStatement}${uniqueConstraint}${identity}`; statement += i === columns.length - 1 ? '' : ',\n'; } @@ -268,7 +266,7 @@ class MySqlCreateTableConvertor extends Convertor { : ''; statement += '\t' - + `\`${column.name}\` ${column.type}${autoincrementStatement}${primaryKeyStatement}${notNullStatement}${defaultStatement}${onUpdateStatement}${generatedStatement}`; + + `\`${column.name}\` ${column.type}${autoincrementStatement}${primaryKeyStatement}${generatedStatement}${notNullStatement}${defaultStatement}${onUpdateStatement}`; statement += i === columns.length - 1 ? '' : ',\n'; } @@ -340,7 +338,7 @@ export class SQLiteCreateTableConvertor extends Convertor { statement += '\t'; statement += - `\`${column.name}\` ${column.type}${primaryKeyStatement}${autoincrementStatement}${defaultStatement}${notNullStatement}${generatedStatement}`; + `\`${column.name}\` ${column.type}${primaryKeyStatement}${autoincrementStatement}${defaultStatement}${generatedStatement}${notNullStatement}`; statement += i === columns.length - 1 ? '' : ',\n'; } @@ -972,11 +970,9 @@ class PgAlterTableAddColumnConvertor extends Convertor { })` : ''; - const generatedStatement = ` GENERATED ALWAYS AS (${generated?.as}) STORED`; + const generatedStatement = generated ? ` GENERATED ALWAYS AS (${generated?.as}) STORED` : ''; - return `ALTER TABLE ${tableNameWithSchema} ADD COLUMN "${name}" ${fixedType}${primaryKeyStatement}${defaultStatement}${notNullStatement}${ - generated ? generatedStatement : '' - }${identityStatement};`; + return `ALTER TABLE ${tableNameWithSchema} ADD COLUMN "${name}" ${fixedType}${primaryKeyStatement}${defaultStatement}${generatedStatement}${notNullStatement}${identityStatement};`; } } @@ -1007,7 +1003,7 @@ class MySqlAlterTableAddColumnConvertor extends Convertor { ? ` GENERATED ALWAYS AS (${generated?.as}) ${generated?.type.toUpperCase()}` : ''; - return `ALTER TABLE \`${tableName}\` ADD \`${name}\` ${type}${primaryKeyStatement}${autoincrementStatement}${defaultStatement}${notNullStatement}${onUpdateStatement}${generatedStatement};`; + return `ALTER TABLE \`${tableName}\` ADD \`${name}\` ${type}${primaryKeyStatement}${autoincrementStatement}${defaultStatement}${generatedStatement}${notNullStatement}${onUpdateStatement};`; } } @@ -1038,7 +1034,7 @@ export class SQLiteAlterTableAddColumnConvertor extends Convertor { ? ` GENERATED ALWAYS AS ${generated.as} ${generated.type.toUpperCase()}` : ''; - return `ALTER TABLE \`${tableName}\` ADD \`${name}\` ${type}${primaryKeyStatement}${defaultStatement}${notNullStatement}${generatedStatement}${referenceStatement};`; + return `ALTER TABLE \`${tableName}\` ADD \`${name}\` ${type}${primaryKeyStatement}${defaultStatement}${generatedStatement}${notNullStatement}${referenceStatement};`; } } @@ -1735,7 +1731,7 @@ class MySqlModifyColumn extends Convertor { ? columnDefault.toISOString() : columnDefault; - return `ALTER TABLE \`${tableName}\` MODIFY COLUMN \`${columnName}\`${columnType}${columnAutoincrement}${columnNotNull}${columnDefault}${columnOnUpdate}${columnGenerated};`; + return `ALTER TABLE \`${tableName}\` MODIFY COLUMN \`${columnName}\`${columnType}${columnAutoincrement}${columnGenerated}${columnNotNull}${columnDefault}${columnOnUpdate};`; } } diff --git a/package.json b/package.json index 3327aad18..4e7bd4e91 100755 --- a/package.json +++ b/package.json @@ -41,5 +41,6 @@ "patchedDependencies": { "typescript@5.4.5": "patches/typescript@5.4.5.patch" } - } + }, + "packageManager": "pnpm@9.7.0" } From 46b60e64f4cb6fcc46c15ec52eeac41dd420878c Mon Sep 17 00:00:00 2001 From: juliusmarminge Date: Thu, 22 Aug 2024 17:44:34 +0200 Subject: [PATCH 081/492] update tests --- drizzle-kit/tests/mysql-generated.test.ts | 12 ++++++------ drizzle-kit/tests/pg-generated.test.ts | 6 +++--- drizzle-kit/tests/sqlite-generated.test.ts | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drizzle-kit/tests/mysql-generated.test.ts b/drizzle-kit/tests/mysql-generated.test.ts index c7365f7e3..3531582d0 100644 --- a/drizzle-kit/tests/mysql-generated.test.ts +++ b/drizzle-kit/tests/mysql-generated.test.ts @@ -99,7 +99,7 @@ test('generated as callback: add generated constraint to an exisiting column as }, ]); expect(sqlStatements).toStrictEqual([ - "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED NOT NULL;", ]); }); @@ -151,7 +151,7 @@ test('generated as callback: add generated constraint to an exisiting column as ]); expect(sqlStatements).toStrictEqual([ 'ALTER TABLE `users` DROP COLUMN `gen_name`;', - "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL NOT NULL;", ]); }); @@ -530,7 +530,7 @@ test('generated as sql: add generated constraint to an exisiting column as store }, ]); expect(sqlStatements).toStrictEqual([ - "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED NOT NULL;", ]); }); @@ -582,7 +582,7 @@ test('generated as sql: add generated constraint to an exisiting column as virtu ]); expect(sqlStatements).toStrictEqual([ 'ALTER TABLE `users` DROP COLUMN `gen_name`;', - "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL NOT NULL;", ]); }); @@ -961,7 +961,7 @@ test('generated as string: add generated constraint to an exisiting column as st }, ]); expect(sqlStatements).toStrictEqual([ - "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED NOT NULL;", ]); }); @@ -1013,7 +1013,7 @@ test('generated as string: add generated constraint to an exisiting column as vi ]); expect(sqlStatements).toStrictEqual([ 'ALTER TABLE `users` DROP COLUMN `gen_name`;', - "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL NOT NULL;", ]); }); diff --git a/drizzle-kit/tests/pg-generated.test.ts b/drizzle-kit/tests/pg-generated.test.ts index 2f7f58491..e9f294891 100644 --- a/drizzle-kit/tests/pg-generated.test.ts +++ b/drizzle-kit/tests/pg-generated.test.ts @@ -87,7 +87,7 @@ test('generated as callback: add generated constraint to an exisiting column', a ]); expect(sqlStatements).toStrictEqual([ 'ALTER TABLE "users" drop column "gen_name";', - 'ALTER TABLE "users" ADD COLUMN "gen_name" text NOT NULL GENERATED ALWAYS AS ("users"."name" || \'to add\') STORED;', + 'ALTER TABLE "users" ADD COLUMN "gen_name" text GENERATED ALWAYS AS ("users"."name" || \'to add\') STORED NOT NULL;', ]); }); @@ -262,7 +262,7 @@ test('generated as sql: add generated constraint to an exisiting column', async ]); expect(sqlStatements).toStrictEqual([ 'ALTER TABLE "users" drop column "gen_name";', - 'ALTER TABLE "users" ADD COLUMN "gen_name" text NOT NULL GENERATED ALWAYS AS ("users"."name" || \'to add\') STORED;', + 'ALTER TABLE "users" ADD COLUMN "gen_name" text GENERATED ALWAYS AS ("users"."name" || \'to add\') STORED NOT NULL;', ]); }); @@ -437,7 +437,7 @@ test('generated as string: add generated constraint to an exisiting column', asy ]); expect(sqlStatements).toStrictEqual([ 'ALTER TABLE "users" drop column "gen_name";', - 'ALTER TABLE "users" ADD COLUMN "gen_name" text NOT NULL GENERATED ALWAYS AS ("users"."name" || \'to add\') STORED;', + 'ALTER TABLE "users" ADD COLUMN "gen_name" text GENERATED ALWAYS AS ("users"."name" || \'to add\') STORED NOT NULL;', ]); }); diff --git a/drizzle-kit/tests/sqlite-generated.test.ts b/drizzle-kit/tests/sqlite-generated.test.ts index 3e1129be4..749dde825 100644 --- a/drizzle-kit/tests/sqlite-generated.test.ts +++ b/drizzle-kit/tests/sqlite-generated.test.ts @@ -171,7 +171,7 @@ test('generated as callback: add generated constraint to an exisiting column as ]); expect(sqlStatements).toStrictEqual([ 'ALTER TABLE `users` DROP COLUMN `gen_name`;', - 'ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS ("name" || \'to add\') VIRTUAL;', + 'ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS ("name" || \'to add\') VIRTUAL NOT NULL;', ]); }); @@ -744,7 +744,7 @@ test('generated as sql: add generated constraint to an exisiting column as virtu ]); expect(sqlStatements).toStrictEqual([ 'ALTER TABLE `users` DROP COLUMN `gen_name`;', - 'ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS ("users"."name" || \'to add\') VIRTUAL;', + 'ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS ("users"."name" || \'to add\') VIRTUAL NOT NULL;', ]); }); @@ -1312,7 +1312,7 @@ test('generated as string: add generated constraint to an exisiting column as vi ]); expect(sqlStatements).toStrictEqual([ 'ALTER TABLE `users` DROP COLUMN `gen_name`;', - 'ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS ("users"."name" || \'to add\') VIRTUAL;', + 'ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS ("users"."name" || \'to add\') VIRTUAL NOT NULL;', ]); }); From 626cc956102d3a62746390b44439e18e5fd090de Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 23 Aug 2024 17:55:43 +0300 Subject: [PATCH 082/492] feat: Add pglite support for kit --- drizzle-kit/build.ts | 1 + drizzle-kit/src/cli/commands/utils.ts | 2 +- drizzle-kit/src/cli/connections.ts | 64 ++++++++++++++++++++- drizzle-kit/src/cli/schema.ts | 48 +++++++++++++--- drizzle-kit/src/cli/validations/common.ts | 9 ++- drizzle-kit/src/cli/validations/postgres.ts | 4 ++ drizzle-kit/src/index.ts | 13 ++++- drizzle-kit/src/serializer/studio.ts | 10 ++-- drizzle-kit/src/utils.ts | 10 ++++ drizzle-kit/tests/introspect/pg.test.ts | 4 +- drizzle-kit/tests/validations.test.ts | 32 +++++++++++ 11 files changed, 174 insertions(+), 23 deletions(-) diff --git a/drizzle-kit/build.ts b/drizzle-kit/build.ts index 8616112fd..701e9c84c 100644 --- a/drizzle-kit/build.ts +++ b/drizzle-kit/build.ts @@ -9,6 +9,7 @@ const driversPackages = [ 'postgres', '@vercel/postgres', '@neondatabase/serverless', + '@electric-sql/pglite', // mysql drivers 'mysql2', '@planetscale/database', diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 7cf503248..fbfeede70 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -79,7 +79,7 @@ export const safeRegister = async () => { export const prepareCheckParams = async ( options: { config?: string; - dialect: Dialect; + dialect?: Dialect; out?: string; }, from: 'cli' | 'config', diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 02f3e8411..ba741bfed 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -5,7 +5,7 @@ import fetch from 'node-fetch'; import ws from 'ws'; import { assertUnreachable } from '../global'; import type { ProxyParams } from '../serializer/studio'; -import { type DB, normaliseSQLiteUrl, type Proxy, type SQLiteDB, type SqliteProxy } from '../utils'; +import { type DB, normalisePGliteUrl, normaliseSQLiteUrl, type Proxy, type SQLiteDB, type SqliteProxy } from '../utils'; import { assertPackages, checkPackage } from './utils'; import type { MysqlCredentials } from './validations/mysql'; import { withStyle } from './validations/outputs'; @@ -21,7 +21,8 @@ export const preparePostgresDB = async ( } > => { if ('driver' in credentials) { - if (credentials.driver === 'aws-data-api') { + const { driver } = credentials; + if (driver === 'aws-data-api') { assertPackages('@aws-sdk/client-rds-data'); const { RDSDataClient, ExecuteStatementCommand, TypeHint } = await import( '@aws-sdk/client-rds-data' @@ -92,7 +93,45 @@ export const preparePostgresDB = async ( }; } - assertUnreachable(credentials.driver); + if (driver === 'pglite') { + assertPackages('@electric-sql/pglite'); + const { PGlite } = await import('@electric-sql/pglite'); + const { drizzle } = await import('drizzle-orm/pglite'); + const { migrate } = await import('drizzle-orm/pglite/migrator'); + + const pglite = new PGlite(normalisePGliteUrl(credentials.url)); + await pglite.waitReady; + const drzl = drizzle(pglite); + const migrateFn = async (config: MigrationConfig) => { + return migrate(drzl, config); + }; + + const query = async (sql: string, params: any[] = []) => { + const result = await pglite.query(sql, params); + return result.rows as T[]; + }; + + const proxy = async (params: ProxyParams) => { + const preparedParams = preparePGliteParams(params.params); + if ( + params.method === 'values' + || params.method === 'get' + || params.method === 'all' + ) { + const result = await pglite.query(params.sql, preparedParams, { + rowMode: params.mode, + }); + return result.rows; + } + + const result = await pglite.query(params.sql, preparedParams); + return result.rows; + }; + + return { query, proxy, migrate: migrateFn }; + } + + assertUnreachable(driver); } if (await checkPackage('pg')) { @@ -415,6 +454,25 @@ const prepareSqliteParams = (params: any[], driver?: string) => { }); }; +const preparePGliteParams = (params: any[]) => { + return params.map((param) => { + if ( + param + && typeof param === 'object' + && 'type' in param + && 'value' in param + && param.type === 'binary' + ) { + const value = typeof param.value === 'object' + ? JSON.stringify(param.value) + : (param.value as string); + + return value; + } + return param; + }); +}; + export const connectToSQLite = async ( credentials: SqliteCredentials, ): Promise< diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 642344bda..4da8af0ac 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -108,15 +108,23 @@ export const migrate = command({ try { if (dialect === 'postgresql') { if ('driver' in credentials) { - if (credentials.driver === 'aws-data-api') { + const { driver } = credentials; + if (driver === 'aws-data-api') { if (!(await ormVersionGt('0.30.10'))) { console.log( "To use 'aws-data-api' driver - please update drizzle-orm to the latest version", ); process.exit(1); } + } else if (driver === 'pglite') { + if (!(await ormVersionGt('0.30.6'))) { + console.log( + "To use 'pglite' driver - please update drizzle-orm to the latest version", + ); + process.exit(1); + } } else { - assertUnreachable(credentials.driver); + assertUnreachable(driver); } } const { preparePostgresDB } = await import('./connections'); @@ -256,15 +264,23 @@ export const push = command({ ); } else if (dialect === 'postgresql') { if ('driver' in credentials) { - if (credentials.driver === 'aws-data-api') { + const { driver } = credentials; + if (driver === 'aws-data-api') { if (!(await ormVersionGt('0.30.10'))) { console.log( "To use 'aws-data-api' driver - please update drizzle-orm to the latest version", ); process.exit(1); } + } else if (driver === 'pglite') { + if (!(await ormVersionGt('0.30.6'))) { + console.log( + "To use 'pglite' driver - please update drizzle-orm to the latest version", + ); + process.exit(1); + } } else { - assertUnreachable(credentials.driver); + assertUnreachable(driver); } } @@ -417,15 +433,23 @@ export const pull = command({ try { if (dialect === 'postgresql') { if ('driver' in credentials) { - if (credentials.driver === 'aws-data-api') { + const { driver } = credentials; + if (driver === 'aws-data-api') { if (!(await ormVersionGt('0.30.10'))) { console.log( "To use 'aws-data-api' driver - please update drizzle-orm to the latest version", ); process.exit(1); } + } else if (driver === 'pglite') { + if (!(await ormVersionGt('0.30.6'))) { + console.log( + "To use 'pglite' driver - please update drizzle-orm to the latest version", + ); + process.exit(1); + } } else { - assertUnreachable(credentials.driver); + assertUnreachable(driver); } } @@ -525,15 +549,23 @@ export const studio = command({ try { if (dialect === 'postgresql') { if ('driver' in credentials) { - if (credentials.driver === 'aws-data-api') { + const { driver } = credentials; + if (driver === 'aws-data-api') { if (!(await ormVersionGt('0.30.10'))) { console.log( "To use 'aws-data-api' driver - please update drizzle-orm to the latest version", ); process.exit(1); } + } else if (driver === 'pglite') { + if (!(await ormVersionGt('0.30.6'))) { + console.log( + "To use 'pglite' driver - please update drizzle-orm to the latest version", + ); + process.exit(1); + } } else { - assertUnreachable(credentials.driver); + assertUnreachable(driver); } } diff --git a/drizzle-kit/src/cli/validations/common.ts b/drizzle-kit/src/cli/validations/common.ts index e800afbc5..a7307f4d6 100644 --- a/drizzle-kit/src/cli/validations/common.ts +++ b/drizzle-kit/src/cli/validations/common.ts @@ -66,6 +66,11 @@ export const sqliteDriversLiterals = [ literal('expo'), ] as const; +export const postgresqlDriversLiterals = [ + literal('aws-data-api'), + literal('pglite'), +] as const; + export const prefixes = [ 'index', 'timestamp', @@ -81,7 +86,7 @@ export type Prefix = (typeof prefixes)[number]; } export const sqliteDriver = union(sqliteDriversLiterals); -export const postgresDriver = literal('aws-data-api'); +export const postgresDriver = union(postgresqlDriversLiterals); export const driver = union([sqliteDriver, postgresDriver]); export const configMigrations = object({ @@ -151,7 +156,7 @@ export const configPushSchema = object({ }); export type CliConfig = TypeOf; -export const drivers = ['turso', 'd1-http', 'expo', 'aws-data-api'] as const; +export const drivers = ['turso', 'd1-http', 'expo', 'aws-data-api', 'pglite'] as const; export type Driver = (typeof drivers)[number]; const _: Driver = '' as TypeOf; diff --git a/drizzle-kit/src/cli/validations/postgres.ts b/drizzle-kit/src/cli/validations/postgres.ts index 3dd02b4f3..658760c61 100644 --- a/drizzle-kit/src/cli/validations/postgres.ts +++ b/drizzle-kit/src/cli/validations/postgres.ts @@ -35,6 +35,10 @@ export const postgresCredentials = union([ secretArn: string().min(1), resourceArn: string().min(1), }), + object({ + driver: literal('pglite'), + url: string().min(1), + }), ]); export type PostgresCredentials = TypeOf; diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 08c302ac3..3d29b5c85 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -40,7 +40,7 @@ type Verify = U; * * --- * `driver` - optional param that is responsible for explicitly providing a driver to use when accessing a database - * *Possible values*: `aws-data-api`, `d1-http`, `expo`, `turso` + * *Possible values*: `aws-data-api`, `d1-http`, `expo`, `turso`, `pglite` * If you don't use AWS Data API, D1, Turso or Expo - ypu don't need this driver. You can check a driver strategy choice here: https://orm.drizzle.team/kit-docs/upgrade-21 * * See https://orm.drizzle.team/kit-docs/config-reference#driver @@ -136,7 +136,7 @@ export type Config = }; } | { - dialect: 'sqlite'; + dialect: Verify; dbCredentials: { url: string; }; @@ -171,6 +171,13 @@ export type Config = resourceArn: string; }; } + | { + dialect: Verify; + driver: Verify; + dbCredentials: { + url: string; + }; + } | { dialect: Verify; dbCredentials: @@ -226,7 +233,7 @@ export type Config = * * --- * `driver` - optional param that is responsible for explicitly providing a driver to use when accessing a database - * *Possible values*: `aws-data-api`, `d1-http`, `expo`, `turso` + * *Possible values*: `aws-data-api`, `d1-http`, `expo`, `turso`, `pglite` * If you don't use AWS Data API, D1, Turso or Expo - ypu don't need this driver. You can check a driver strategy choice here: https://orm.drizzle.team/kit-docs/upgrade-21 * * See https://orm.drizzle.team/kit-docs/config-reference#driver diff --git a/drizzle-kit/src/serializer/studio.ts b/drizzle-kit/src/serializer/studio.ts index 4b7b12c1e..dc78c6c2c 100644 --- a/drizzle-kit/src/serializer/studio.ts +++ b/drizzle-kit/src/serializer/studio.ts @@ -44,7 +44,7 @@ type SchemaFile = { export type Setup = { dbHash: string; dialect: 'postgresql' | 'mysql' | 'sqlite'; - driver?: 'aws-data-api' | 'd1-http' | 'turso'; + driver?: 'aws-data-api' | 'd1-http' | 'turso' | 'pglite'; proxy: (params: ProxyParams) => Promise; customDefaults: CustomDefault[]; schema: Record>>; @@ -218,11 +218,13 @@ export const drizzleForPostgres = async ( let dbUrl: string; if ('driver' in credentials) { - // aws-data-api - if (credentials.driver === 'aws-data-api') { + const { driver } = credentials; + if (driver === 'aws-data-api') { dbUrl = `aws-data-api://${credentials.database}/${credentials.secretArn}/${credentials.resourceArn}`; + } else if (driver === 'pglite') { + dbUrl = credentials.url; } else { - assertUnreachable(credentials.driver); + assertUnreachable(driver); } } else if ('url' in credentials) { dbUrl = credentials.url; diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 6a7faff45..7b363a9d3 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -328,6 +328,16 @@ export const normaliseSQLiteUrl = ( assertUnreachable(type); }; +export const normalisePGliteUrl = ( + it: string, +) => { + if (it.startsWith('file:')) { + return it.substring(5); + } + + return it; +}; + export function isPgArrayType(sqlType: string) { return sqlType.match(/.*\[\d*\].*|.*\[\].*/g) !== null; } diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index 3efb57d7e..e65c0f904 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -221,7 +221,7 @@ test('instrospect all column types', async () => { const myEnum = pgEnum('my_enum', ['a', 'b', 'c']); const schema = { enum_: myEnum, - // NOTE: Types from extensions aren't tested due to PGLite not supporting at the moment + // NOTE: Types from extensions aren't tested due to PGlite not supporting at the moment columns: pgTable('columns', { enum: myEnum('my_enum').default('a'), smallint: smallint('smallint').default(10), @@ -271,7 +271,7 @@ test('instrospect all column array types', async () => { const myEnum = pgEnum('my_enum', ['a', 'b', 'c']); const schema = { enum_: myEnum, - // NOTE: Types from extensions aren't tested due to PGLite not supporting at the moment + // NOTE: Types from extensions aren't tested due to PGlite not supporting at the moment columns: pgTable('columns', { enum: myEnum('my_enum').array().default(['a', 'b']), smallint: smallint('smallint').array().default([10, 20]), diff --git a/drizzle-kit/tests/validations.test.ts b/drizzle-kit/tests/validations.test.ts index 04d0096ff..82731ee25 100644 --- a/drizzle-kit/tests/validations.test.ts +++ b/drizzle-kit/tests/validations.test.ts @@ -270,6 +270,38 @@ test('AWS Data API #8', () => { }).toThrowError(); }); +test('PGlite #1', () => { + expect( + postgresCredentials.parse({ + dialect: 'postgres', + driver: 'pglite', + url: './my.db', + }), + ).toStrictEqual({ + driver: 'pglite', + url: './my.db', + }); +}); + +test('PGlite #2', () => { + expect(() => { + postgresCredentials.parse({ + dialect: 'postgres', + driver: 'pglite', + url: '', + }); + }).toThrowError(); +}); + +test('PGlite #3', () => { + expect(() => { + postgresCredentials.parse({ + dialect: 'postgres', + driver: 'pglite', + }); + }).toThrowError(); +}); + test('postgres #1', () => { expect( postgresCredentials.parse({ From fee53be59466ec41c995387614b49be68d58a6da Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 26 Aug 2024 10:22:19 +0300 Subject: [PATCH 083/492] Test implementation --- drizzle-orm/src/monodriver.ts | 81 +++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 drizzle-orm/src/monodriver.ts diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts new file mode 100644 index 000000000..c1b2b4df1 --- /dev/null +++ b/drizzle-orm/src/monodriver.ts @@ -0,0 +1,81 @@ +import type { ClientConfig as NeonHttpConfig, PoolConfig as NeonServerlessConfig } from '@neondatabase/serverless'; +import type { VercelPostgresPoolConfig } from '@vercel/postgres'; +import type { PoolConfig } from 'pg'; +import type { Options, PostgresType } from 'postgres'; +import type { NodePgDatabase } from './node-postgres'; +import type { DrizzleConfig } from './utils'; + +type DatabaseClientType = + | 'node-postgres' + | 'postgres.js' + | 'neon-serverless' + | 'neon-http' + | 'vercel-postgres' + | 'aws-data-api' + | 'planetscale' + | 'mysql2' + | 'tidb-serverless' + | 'libsql' + | 'd1' + | 'bun-sqlite' + | 'better-sqlite3'; + +type ClientConfigMap = { + 'node-postgres': PoolConfig; + 'postgres.js': Options>; + 'neon-serverless': NeonServerlessConfig; + 'neon-http': NeonHttpConfig; + 'vercel-postgres': {}; + 'aws-data-api': {}; + planetscale: {}; + mysql2: {}; + 'tidb-serverless': {}; + 'mysql-http-proxy': {}; + libsql: {}; + d1: {}; + 'bun-sqlite': {}; + 'better-sqlite3': {}; + 'sqlite-http-proxy': {}; +}; + +type ClientDrizzleInstanceMap> = { + 'node-postgres': NodePgDatabase; + 'postgres.js': {}; + 'neon-serverless': {}; + 'neon-http': {}; + 'vercel-postgres': {}; + 'aws-data-api': {}; + planetscale: {}; + mysql2: {}; + 'tidb-serverless': {}; + 'mysql-http-proxy': {}; + libsql: {}; + d1: {}; + 'bun-sqlite': {}; + 'better-sqlite3': {}; + 'sqlite-http-proxy': {}; +}; + +type ClientParams = ClientConfigMap[TClientType]; + +type InitializerParams< + TClientType extends DatabaseClientType, + TSchema extends Record = Record, +> = { + client: TClientType; + connection: ClientParams; +} & DrizzleConfig; + +type DetermineClient< + TParams extends InitializerParams, + TSchema extends Record = TParams['schema'] extends Record ? TParams['schema'] + : Record, +> = ClientDrizzleInstanceMap[TParams['client']]; + +export const drizzle = < + TClientType extends DatabaseClientType, + TSchema extends Record, + TParams extends InitializerParams, +>(params: TParams): DetermineClient => { + return {} as any; +}; From e4717d47b313e959c0829b8f4882ede05bb40eff Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 26 Aug 2024 11:06:47 +0300 Subject: [PATCH 084/492] Type-level implementation --- drizzle-orm/src/monodriver.ts | 114 +++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 31 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index c1b2b4df1..bc31f6893 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,9 +1,60 @@ +import type { RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; +import type { Config as LibsqlConfig } from '@libsql/client'; import type { ClientConfig as NeonHttpConfig, PoolConfig as NeonServerlessConfig } from '@neondatabase/serverless'; -import type { VercelPostgresPoolConfig } from '@vercel/postgres'; -import type { PoolConfig } from 'pg'; -import type { Options, PostgresType } from 'postgres'; +import type { Config as PlanetscaleConfig } from '@planetscale/database'; +import type { Config as TiDBServerlessConfig } from '@tidbcloud/serverless'; +import type { VercelPostgresPoolConfig as VercelPostgresConfig } from '@vercel/postgres'; +import type { Options as BetterSQLite3Options } from 'better-sqlite3'; +import type { ConnectionConfig as Mysql2Config } from 'mysql2'; +import type { PoolConfig as NodePGPoolConfig } from 'pg'; +import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType } from 'postgres'; +import type { AwsDataApiPgDatabase } from './aws-data-api/pg'; +import type { BetterSQLite3Database } from './better-sqlite3'; +import type { BunSQLiteDatabase } from './bun-sqlite'; +import type { DrizzleD1Database } from './d1'; +import type { LibSQLDatabase } from './libsql'; +import type { MySql2Database } from './mysql2'; +import type { NeonHttpDatabase } from './neon-http'; +import type { NeonDatabase } from './neon-serverless'; import type { NodePgDatabase } from './node-postgres'; +import type { PlanetScaleDatabase } from './planetscale-serverless'; +import type { PostgresJsDatabase } from './postgres-js'; +import type { TiDBServerlessDatabase } from './tidb-serverless'; import type { DrizzleConfig } from './utils'; +import type { VercelPgDatabase } from './vercel-postgres'; + +type BunSqliteDatabaseOptions = + | number + | { + /** + * Open the database as read-only (no write operations, no create). + * + * Equivalent to {@link constants.SQLITE_OPEN_READONLY} + */ + readonly?: boolean; + /** + * Allow creating a new database + * + * Equivalent to {@link constants.SQLITE_OPEN_CREATE} + */ + create?: boolean; + /** + * Open the database as read-write + * + * Equivalent to {@link constants.SQLITE_OPEN_READWRITE} + */ + readwrite?: boolean; + }; + +type BunSqliteDatabaseConfig = { + filename?: string; + options?: BunSqliteDatabaseOptions; +}; + +type BetterSQLite3DatabaseConfig = { + filename?: string | Buffer; + options?: BetterSQLite3Options; +}; type DatabaseClientType = | 'node-postgres' @@ -21,39 +72,35 @@ type DatabaseClientType = | 'better-sqlite3'; type ClientConfigMap = { - 'node-postgres': PoolConfig; - 'postgres.js': Options>; + 'node-postgres': NodePGPoolConfig; + 'postgres.js': PostgresJSOptions>; 'neon-serverless': NeonServerlessConfig; 'neon-http': NeonHttpConfig; - 'vercel-postgres': {}; - 'aws-data-api': {}; - planetscale: {}; - mysql2: {}; - 'tidb-serverless': {}; - 'mysql-http-proxy': {}; - libsql: {}; - d1: {}; - 'bun-sqlite': {}; - 'better-sqlite3': {}; - 'sqlite-http-proxy': {}; + 'vercel-postgres': VercelPostgresConfig; + 'aws-data-api': RDSConfig; + planetscale: PlanetscaleConfig; + mysql2: Mysql2Config; + 'tidb-serverless': TiDBServerlessConfig; + libsql: LibsqlConfig; + d1: D1Database; + 'bun-sqlite': BunSqliteDatabaseConfig; + 'better-sqlite3': BetterSQLite3DatabaseConfig; }; type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; - 'postgres.js': {}; - 'neon-serverless': {}; - 'neon-http': {}; - 'vercel-postgres': {}; - 'aws-data-api': {}; - planetscale: {}; - mysql2: {}; - 'tidb-serverless': {}; - 'mysql-http-proxy': {}; - libsql: {}; - d1: {}; - 'bun-sqlite': {}; - 'better-sqlite3': {}; - 'sqlite-http-proxy': {}; + 'postgres.js': PostgresJsDatabase; + 'neon-serverless': NeonDatabase; + 'neon-http': NeonHttpDatabase; + 'vercel-postgres': VercelPgDatabase; + 'aws-data-api': AwsDataApiPgDatabase; + planetscale: PlanetScaleDatabase; + mysql2: MySql2Database; + 'tidb-serverless': TiDBServerlessDatabase; + libsql: LibSQLDatabase; + d1: DrizzleD1Database; + 'bun-sqlite': BunSQLiteDatabase; + 'better-sqlite3': BetterSQLite3Database; }; type ClientParams = ClientConfigMap[TClientType]; @@ -76,6 +123,11 @@ export const drizzle = < TClientType extends DatabaseClientType, TSchema extends Record, TParams extends InitializerParams, ->(params: TParams): DetermineClient => { +>({ + client, + connection, + logger, + schema, +}: TParams): DetermineClient => { return {} as any; }; From fe9c04365c90df5325bbdf311c4c621d3f0d2a44 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 26 Aug 2024 12:26:50 +0300 Subject: [PATCH 085/492] Added functional runtimes for node-pg, aws-data-api-pg [custom drizzle config WIP] --- drizzle-orm/src/monodriver.ts | 70 +++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index bc31f6893..298d9be34 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -8,7 +8,7 @@ import type { Options as BetterSQLite3Options } from 'better-sqlite3'; import type { ConnectionConfig as Mysql2Config } from 'mysql2'; import type { PoolConfig as NodePGPoolConfig } from 'pg'; import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType } from 'postgres'; -import type { AwsDataApiPgDatabase } from './aws-data-api/pg'; +import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg'; import type { BetterSQLite3Database } from './better-sqlite3'; import type { BunSQLiteDatabase } from './bun-sqlite'; import type { DrizzleD1Database } from './d1'; @@ -62,7 +62,7 @@ type DatabaseClientType = | 'neon-serverless' | 'neon-http' | 'vercel-postgres' - | 'aws-data-api' + | 'aws-data-api-pg' | 'planetscale' | 'mysql2' | 'tidb-serverless' @@ -71,13 +71,13 @@ type DatabaseClientType = | 'bun-sqlite' | 'better-sqlite3'; -type ClientConfigMap = { +type ClientConnectionConfigMap = { 'node-postgres': NodePGPoolConfig; 'postgres.js': PostgresJSOptions>; 'neon-serverless': NeonServerlessConfig; 'neon-http': NeonHttpConfig; 'vercel-postgres': VercelPostgresConfig; - 'aws-data-api': RDSConfig; + 'aws-data-api-pg': RDSConfig; planetscale: PlanetscaleConfig; mysql2: Mysql2Config; 'tidb-serverless': TiDBServerlessConfig; @@ -87,13 +87,29 @@ type ClientConfigMap = { 'better-sqlite3': BetterSQLite3DatabaseConfig; }; +// type ClientDrizzleConfigMap> = { +// 'node-postgres': DrizzleConfig; +// 'postgres.js': DrizzleConfig; +// 'neon-serverless': DrizzleConfig; +// 'neon-http': DrizzleConfig; +// 'vercel-postgres': DrizzleConfig; +// 'aws-data-api-pg': DrizzleAwsDataApiPgConfig; +// planetscale: DrizzleConfig; +// mysql2: DrizzleConfig; +// 'tidb-serverless': DrizzleConfig; +// libsql: DrizzleConfig; +// d1: DrizzleConfig; +// 'bun-sqlite': DrizzleConfig; +// 'better-sqlite3': DrizzleConfig; +// }; + type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; 'postgres.js': PostgresJsDatabase; 'neon-serverless': NeonDatabase; 'neon-http': NeonHttpDatabase; 'vercel-postgres': VercelPgDatabase; - 'aws-data-api': AwsDataApiPgDatabase; + 'aws-data-api-pg': AwsDataApiPgDatabase; planetscale: PlanetScaleDatabase; mysql2: MySql2Database; 'tidb-serverless': TiDBServerlessDatabase; @@ -103,7 +119,7 @@ type ClientDrizzleInstanceMap> = { 'better-sqlite3': BetterSQLite3Database; }; -type ClientParams = ClientConfigMap[TClientType]; +type ClientParams = ClientConnectionConfigMap[TClientType]; type InitializerParams< TClientType extends DatabaseClientType, @@ -115,19 +131,41 @@ type InitializerParams< type DetermineClient< TParams extends InitializerParams, - TSchema extends Record = TParams['schema'] extends Record ? TParams['schema'] + TSchema extends Record = TParams extends { schema: Record } ? TParams['schema'] : Record, -> = ClientDrizzleInstanceMap[TParams['client']]; +> = TParams extends { client: DatabaseClientType } ? ClientDrizzleInstanceMap[TParams['client']] + : never; + +import { drizzle as rdsPgDrizzle } from './aws-data-api/pg/index.ts'; +import { drizzle as pgDrizzle } from './node-postgres/index.ts'; -export const drizzle = < +export const drizzle = async < TClientType extends DatabaseClientType, TSchema extends Record, TParams extends InitializerParams, ->({ - client, - connection, - logger, - schema, -}: TParams): DetermineClient => { - return {} as any; +>(params: TParams): Promise> => { + const { client, connection } = params; + const drizzleConfig = params as Omit; + // @ts-expect-error + delete drizzleConfig.client; + // @ts-expect-error + delete drizzleConfig.connection; + + switch (client) { + case 'node-postgres': { + const { Pool } = await import('pg'); + const instance = new Pool(connection as NodePGPoolConfig); + + return pgDrizzle(instance, drizzleConfig) as any; + } + case 'aws-data-api-pg': { + const { RDSDataClient } = await import('@aws-sdk/client-rds-data'); + const instance = new RDSDataClient(connection); + + return rdsPgDrizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; + } + } + + // @ts-ignore + return {}; }; From 3169e6a8956a4a9195e6fb6381a74d1370af7f11 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 26 Aug 2024 13:51:44 +0300 Subject: [PATCH 086/492] Resolved bun type related build issues --- drizzle-kit/build.ts | 3 +++ drizzle-kit/package.json | 1 + 2 files changed, 4 insertions(+) diff --git a/drizzle-kit/build.ts b/drizzle-kit/build.ts index 8616112fd..bb761cc59 100644 --- a/drizzle-kit/build.ts +++ b/drizzle-kit/build.ts @@ -1,3 +1,4 @@ +/// import * as esbuild from 'esbuild'; import { readFileSync, writeFileSync } from 'node:fs'; import * as tsup from 'tsup'; @@ -15,6 +16,7 @@ const driversPackages = [ // sqlite drivers '@libsql/client', 'better-sqlite3', + 'bun:sqlite', ]; esbuild.buildSync({ @@ -81,6 +83,7 @@ const main = async () => { await tsup.build({ entryPoints: ['./src/index.ts', './src/api.ts'], outDir: './dist', + external: ['bun:sqlite'], splitting: false, dts: true, format: ['cjs', 'esm'], diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index b2e780e1a..e6a4aa5ea 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -74,6 +74,7 @@ "@vercel/postgres": "^0.8.0", "ava": "^5.1.0", "better-sqlite3": "^9.4.3", + "bun-types": "^0.6.6", "camelcase": "^7.0.1", "chalk": "^5.2.0", "commander": "^12.1.0", From 87d7704b6dfb868d7a43b47bf5297354a2241155 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 26 Aug 2024 13:52:00 +0300 Subject: [PATCH 087/492] Implemented extra drivers --- drizzle-orm/src/index.ts | 1 + drizzle-orm/src/monodriver.ts | 93 ++++++++++++++++++++++++----------- pnpm-lock.yaml | 25 +++++----- 3 files changed, 78 insertions(+), 41 deletions(-) diff --git a/drizzle-orm/src/index.ts b/drizzle-orm/src/index.ts index bc72260b9..5cabdb0d8 100644 --- a/drizzle-orm/src/index.ts +++ b/drizzle-orm/src/index.ts @@ -5,6 +5,7 @@ export * from './entity.ts'; export * from './errors.ts'; export * from './expressions.ts'; export * from './logger.ts'; +export * from './monodriver.ts'; export * from './operations.ts'; export * from './query-promise.ts'; export * from './relations.ts'; diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 298d9be34..b6b48c91b 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,3 +1,4 @@ +/// import type { RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; import type { Config as LibsqlConfig } from '@libsql/client'; import type { ClientConfig as NeonHttpConfig, PoolConfig as NeonServerlessConfig } from '@neondatabase/serverless'; @@ -8,20 +9,20 @@ import type { Options as BetterSQLite3Options } from 'better-sqlite3'; import type { ConnectionConfig as Mysql2Config } from 'mysql2'; import type { PoolConfig as NodePGPoolConfig } from 'pg'; import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType } from 'postgres'; -import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg'; -import type { BetterSQLite3Database } from './better-sqlite3'; -import type { BunSQLiteDatabase } from './bun-sqlite'; -import type { DrizzleD1Database } from './d1'; -import type { LibSQLDatabase } from './libsql'; -import type { MySql2Database } from './mysql2'; -import type { NeonHttpDatabase } from './neon-http'; -import type { NeonDatabase } from './neon-serverless'; -import type { NodePgDatabase } from './node-postgres'; -import type { PlanetScaleDatabase } from './planetscale-serverless'; -import type { PostgresJsDatabase } from './postgres-js'; -import type { TiDBServerlessDatabase } from './tidb-serverless'; -import type { DrizzleConfig } from './utils'; -import type { VercelPgDatabase } from './vercel-postgres'; +import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg/index.ts'; +import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; +import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; +import type { DrizzleD1Database } from './d1/index.ts'; +import type { LibSQLDatabase } from './libsql/index.ts'; +import type { MySql2Database } from './mysql2/index.ts'; +import type { NeonHttpDatabase } from './neon-http/index.ts'; +import type { NeonDatabase } from './neon-serverless/index.ts'; +import type { NodePgDatabase } from './node-postgres/index.ts'; +import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; +import type { PostgresJsDatabase } from './postgres-js/index.ts'; +import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; +import type { DrizzleConfig } from './utils.ts'; +import type { VercelPgDatabase } from './vercel-postgres/index.ts'; type BunSqliteDatabaseOptions = | number @@ -87,22 +88,6 @@ type ClientConnectionConfigMap = { 'better-sqlite3': BetterSQLite3DatabaseConfig; }; -// type ClientDrizzleConfigMap> = { -// 'node-postgres': DrizzleConfig; -// 'postgres.js': DrizzleConfig; -// 'neon-serverless': DrizzleConfig; -// 'neon-http': DrizzleConfig; -// 'vercel-postgres': DrizzleConfig; -// 'aws-data-api-pg': DrizzleAwsDataApiPgConfig; -// planetscale: DrizzleConfig; -// mysql2: DrizzleConfig; -// 'tidb-serverless': DrizzleConfig; -// libsql: DrizzleConfig; -// d1: DrizzleConfig; -// 'bun-sqlite': DrizzleConfig; -// 'better-sqlite3': DrizzleConfig; -// }; - type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; 'postgres.js': PostgresJsDatabase; @@ -137,7 +122,18 @@ type DetermineClient< : never; import { drizzle as rdsPgDrizzle } from './aws-data-api/pg/index.ts'; +import { drizzle as betterSqliteDrizzle } from './better-sqlite3/index.ts'; +import { drizzle as bunSqliteDrizzle } from './bun-sqlite/index.ts'; +import { drizzle as d1Drizzle } from './d1/index.ts'; +import { drizzle as libsqlDrizzle } from './libsql/index.ts'; +// import { drizzle as mysql2Drizzle } from './mysql2/index.ts'; +// import { drizzle as neonHttpDrizzle } from './neon-http/index.ts'; +// import { drizzle as neonDrizzle } from './neon-serverless/index.ts'; import { drizzle as pgDrizzle } from './node-postgres/index.ts'; +// import { drizzle as planetscaleDrizzle } from './planetscale-serverless/index.ts'; +// import { drizzle as postgresJSDrizzle } from './postgres-js/index.ts'; +// import { drizzle as tidbDrizzle } from './tidb-serverless/index.ts'; +// import { drizzle as vercelDrizzle } from './vercel-postgres/index.ts'; export const drizzle = async < TClientType extends DatabaseClientType, @@ -164,6 +160,43 @@ export const drizzle = async < return rdsPgDrizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } + case 'better-sqlite3': { + const { default: Client } = await import('better-sqlite3'); + const { filename, options } = connection as BetterSQLite3DatabaseConfig; + const instance = new Client(filename, options); + + return betterSqliteDrizzle(instance, drizzleConfig) as any; + } + case 'bun-sqlite': { + const { Database: Client } = await import('bun:sqlite'); + const { filename, options } = connection as BunSqliteDatabaseConfig; + const instance = new Client(filename, options); + + return bunSqliteDrizzle(instance, drizzleConfig) as any; + } + case 'd1': { + return d1Drizzle(connection as D1Database, drizzleConfig) as any; + } + case 'libsql': { + const { createClient } = await import('@libsql/client'); + const instance = createClient(connection as LibsqlConfig); + + return libsqlDrizzle(instance, drizzleConfig) as any; + } + // case 'mysql2': { + // } + // case 'neon-http': { + // } + // case 'neon-serverless': { + // } + // case 'planetscale': { + // } + // case 'postgres.js': { + // } + // case 'tidb-serverless': { + // } + // case 'vercel-postgres': { + // } } // @ts-ignore diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2d091ad6..209d2db3b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -182,6 +182,9 @@ importers: better-sqlite3: specifier: ^9.4.3 version: 9.6.0 + bun-types: + specifier: ^0.6.6 + version: 0.6.14 camelcase: specifier: ^7.0.1 version: 7.0.1 @@ -10210,7 +10213,7 @@ snapshots: '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10300,7 +10303,7 @@ snapshots: '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10610,7 +10613,7 @@ snapshots: '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10799,12 +10802,12 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.0.0 @@ -10889,13 +10892,13 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-http': 3.582.0 - '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.0.0 @@ -10970,10 +10973,10 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-sso@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/credential-provider-sso@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-sso': 3.583.0 - '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -11216,7 +11219,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 From 30e766128beb5ad3006b75754e0d8fda1eaa04c1 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 26 Aug 2024 14:47:48 +0300 Subject: [PATCH 088/492] Bump kit version --- .github/workflows/release-feature-branch.yaml | 6 --- .github/workflows/release-latest.yaml | 6 --- changelogs/drizzle-kit/0.24.2.md | 24 +++++++++++ drizzle-kit/package.json | 2 +- integration-tests/tests/prisma/.gitignore | 2 - .../tests/prisma/mysql/prisma.test.ts | 30 -------------- .../tests/prisma/mysql/schema.prisma | 20 --------- .../tests/prisma/pg/prisma.test.ts | 29 ------------- .../tests/prisma/pg/schema.prisma | 20 --------- .../tests/prisma/sqlite/.gitignore | 1 - .../tests/prisma/sqlite/prisma.test.ts | 41 ------------------- .../tests/prisma/sqlite/schema.prisma | 20 --------- 12 files changed, 25 insertions(+), 176 deletions(-) create mode 100644 changelogs/drizzle-kit/0.24.2.md delete mode 100644 integration-tests/tests/prisma/.gitignore delete mode 100644 integration-tests/tests/prisma/mysql/prisma.test.ts delete mode 100644 integration-tests/tests/prisma/mysql/schema.prisma delete mode 100644 integration-tests/tests/prisma/pg/prisma.test.ts delete mode 100644 integration-tests/tests/prisma/pg/schema.prisma delete mode 100644 integration-tests/tests/prisma/sqlite/.gitignore delete mode 100644 integration-tests/tests/prisma/sqlite/prisma.test.ts delete mode 100644 integration-tests/tests/prisma/sqlite/schema.prisma diff --git a/.github/workflows/release-feature-branch.yaml b/.github/workflows/release-feature-branch.yaml index d0e0240c0..5c2d76fb7 100644 --- a/.github/workflows/release-feature-branch.yaml +++ b/.github/workflows/release-feature-branch.yaml @@ -136,12 +136,6 @@ jobs: cd drizzle-orm pnpm prisma generate --schema src/prisma/schema.prisma ) - ( - cd integration-tests - pnpm prisma generate --schema tests/prisma/pg/schema.prisma - pnpm prisma generate --schema tests/prisma/mysql/schema.prisma - pnpm prisma generate --schema tests/prisma/sqlite/schema.prisma - ) pnpm build - name: Run tests diff --git a/.github/workflows/release-latest.yaml b/.github/workflows/release-latest.yaml index ce194530f..d81a0bcab 100644 --- a/.github/workflows/release-latest.yaml +++ b/.github/workflows/release-latest.yaml @@ -139,12 +139,6 @@ jobs: cd drizzle-orm pnpm prisma generate --schema src/prisma/schema.prisma ) - ( - cd integration-tests - pnpm prisma generate --schema tests/prisma/pg/schema.prisma - pnpm prisma generate --schema tests/prisma/mysql/schema.prisma - pnpm prisma generate --schema tests/prisma/sqlite/schema.prisma - ) pnpm build - name: Run tests diff --git a/changelogs/drizzle-kit/0.24.2.md b/changelogs/drizzle-kit/0.24.2.md new file mode 100644 index 000000000..962a29acc --- /dev/null +++ b/changelogs/drizzle-kit/0.24.2.md @@ -0,0 +1,24 @@ +## New Features + +### 🎉 Support for `pglite` driver + +You can now use pglite with all drizzle-kit commands, including Drizzle Studio! + +```ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "postgresql", + driver: "pglite", + schema: "./schema.ts", + dbCredentials: { + url: "local-pg.db", + }, + verbose: true, + strict: true, +}); +``` + +## Bug fixes + +- mysql-kit: fix GENERATED ALWAYS AS ... NOT NULL - [#2824](https://github.com/drizzle-team/drizzle-orm/pull/2824) \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index b2e780e1a..9d9e1d227 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.24.1", + "version": "0.24.2", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/integration-tests/tests/prisma/.gitignore b/integration-tests/tests/prisma/.gitignore deleted file mode 100644 index 794cddf53..000000000 --- a/integration-tests/tests/prisma/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*/client -*/drizzle diff --git a/integration-tests/tests/prisma/mysql/prisma.test.ts b/integration-tests/tests/prisma/mysql/prisma.test.ts deleted file mode 100644 index ee5511a25..000000000 --- a/integration-tests/tests/prisma/mysql/prisma.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import 'dotenv/config'; -import 'zx/globals'; - -import type { PrismaMySqlDatabase } from 'drizzle-orm/prisma/mysql'; -import { drizzle } from 'drizzle-orm/prisma/mysql'; -import { beforeAll, expect, expectTypeOf, test } from 'vitest'; - -import { PrismaClient } from './client'; -import { User } from './drizzle/schema.ts'; - -const ENABLE_LOGGING = false; - -let db: PrismaMySqlDatabase; - -beforeAll(async () => { - await $`prisma generate --schema tests/prisma/mysql/schema.prisma`.quiet(); - await $`prisma db push --force-reset --schema tests/prisma/mysql/schema.prisma`.quiet(); - const prisma = new PrismaClient().$extends(drizzle({ logger: ENABLE_LOGGING })); - db = prisma.$drizzle; -}); - -test('extension works', async () => { - const insert = await db.insert(User).values({ email: 'test@test.com' }); - expectTypeOf(insert).toEqualTypeOf<[]>(); - expect(insert).toEqual([]); - - const result = await db.select().from(User); - expectTypeOf(result).toEqualTypeOf(); - expect(result).toEqual([{ id: 1, email: 'test@test.com', name: null }]); -}); diff --git a/integration-tests/tests/prisma/mysql/schema.prisma b/integration-tests/tests/prisma/mysql/schema.prisma deleted file mode 100644 index 5bb496dcb..000000000 --- a/integration-tests/tests/prisma/mysql/schema.prisma +++ /dev/null @@ -1,20 +0,0 @@ -generator client { - provider = "prisma-client-js" - output = "./client" -} - -generator drizzle { - provider = "drizzle-prisma-generator" - output = "./drizzle" -} - -datasource db { - provider = "mysql" - url = env("MYSQL_CONNECTION_STRING") -} - -model User { - id Int @id @default(autoincrement()) - email String @unique - name String? -} diff --git a/integration-tests/tests/prisma/pg/prisma.test.ts b/integration-tests/tests/prisma/pg/prisma.test.ts deleted file mode 100644 index 16c5ce106..000000000 --- a/integration-tests/tests/prisma/pg/prisma.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import 'dotenv/config'; -import 'zx/globals'; - -import { drizzle } from 'drizzle-orm/prisma/pg'; -import type { PrismaPgDatabase } from 'drizzle-orm/prisma/pg'; -import { beforeAll, expect, expectTypeOf, test } from 'vitest'; - -import { PrismaClient } from './client'; -import { User } from './drizzle/schema.ts'; - -const ENABLE_LOGGING = false; - -let db: PrismaPgDatabase; - -beforeAll(async () => { - await $`prisma db push --force-reset --schema tests/prisma/pg/schema.prisma`.quiet(); - const prisma = new PrismaClient().$extends(drizzle({ logger: ENABLE_LOGGING })); - db = prisma.$drizzle; -}); - -test('extension works', async () => { - const insert = await db.insert(User).values({ email: 'test@test.com' }); - expectTypeOf(insert).toEqualTypeOf<[]>(); - expect(insert).toEqual([]); - - const result = await db.select().from(User); - expectTypeOf(result).toEqualTypeOf(); - expect(result).toEqual([{ id: 1, email: 'test@test.com', name: null }]); -}); diff --git a/integration-tests/tests/prisma/pg/schema.prisma b/integration-tests/tests/prisma/pg/schema.prisma deleted file mode 100644 index a5345d047..000000000 --- a/integration-tests/tests/prisma/pg/schema.prisma +++ /dev/null @@ -1,20 +0,0 @@ -generator client { - provider = "prisma-client-js" - output = "./client" -} - -generator drizzle { - provider = "drizzle-prisma-generator" - output = "./drizzle" -} - -datasource db { - provider = "postgresql" - url = env("PG_CONNECTION_STRING") -} - -model User { - id Int @id @default(autoincrement()) - email String @unique - name String? -} diff --git a/integration-tests/tests/prisma/sqlite/.gitignore b/integration-tests/tests/prisma/sqlite/.gitignore deleted file mode 100644 index 2fa69c243..000000000 --- a/integration-tests/tests/prisma/sqlite/.gitignore +++ /dev/null @@ -1 +0,0 @@ -db.sqlite diff --git a/integration-tests/tests/prisma/sqlite/prisma.test.ts b/integration-tests/tests/prisma/sqlite/prisma.test.ts deleted file mode 100644 index 4e8979cb8..000000000 --- a/integration-tests/tests/prisma/sqlite/prisma.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import 'dotenv/config'; -import 'zx/globals'; - -import { drizzle } from 'drizzle-orm/prisma/sqlite'; -import type { PrismaSQLiteDatabase } from 'drizzle-orm/prisma/sqlite'; -import { beforeAll, expect, expectTypeOf, test } from 'vitest'; - -import { PrismaClient } from './client'; -import { User } from './drizzle/schema.ts'; - -const ENABLE_LOGGING = false; - -let db: PrismaSQLiteDatabase; - -beforeAll(async () => { - await $`prisma db push --force-reset --schema tests/prisma/sqlite/schema.prisma`.quiet(); - const prisma = new PrismaClient().$extends(drizzle({ logger: ENABLE_LOGGING })); - db = prisma.$drizzle; -}); - -test('extension works', async () => { - const insert = await db.insert(User).values({ email: 'test@test.com' }); - expectTypeOf(insert).toEqualTypeOf<[]>(); - expect(insert).toEqual([]); - - const result = await db.select().from(User); - expectTypeOf(result).toEqualTypeOf(); - expect(result).toEqual([{ id: 1, email: 'test@test.com', name: null }]); - - const all = await db.select().from(User).all(); - expectTypeOf(all).toEqualTypeOf(); - expect(all).toEqual([{ id: 1, email: 'test@test.com', name: null }]); - - const get = await db.select().from(User).get(); - expectTypeOf(get).toEqualTypeOf(); - expect(get).toEqual({ id: 1, email: 'test@test.com', name: null }); - - const run = await db.insert(User).values({ email: 'test2@test.com' }).run(); - expectTypeOf(run).toEqualTypeOf<[]>(); - expect(run).toEqual([]); -}); diff --git a/integration-tests/tests/prisma/sqlite/schema.prisma b/integration-tests/tests/prisma/sqlite/schema.prisma deleted file mode 100644 index 6dbf2643e..000000000 --- a/integration-tests/tests/prisma/sqlite/schema.prisma +++ /dev/null @@ -1,20 +0,0 @@ -generator client { - provider = "prisma-client-js" - output = "./client" -} - -generator drizzle { - provider = "drizzle-prisma-generator" - output = "./drizzle" -} - -datasource db { - provider = "sqlite" - url = "file:./db.sqlite" -} - -model User { - id Int @id @default(autoincrement()) - email String @unique - name String? -} From fb3b39a729afef9a5a5e6b0be64467b0eec69a27 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 26 Aug 2024 10:37:20 -0700 Subject: [PATCH 089/492] Setup common casing config --- drizzle-orm/src/casing.ts | 84 +++++++++++++++++++++++++ drizzle-orm/src/column-builder.ts | 2 + drizzle-orm/src/column.ts | 3 + drizzle-orm/src/sql/sql.ts | 8 ++- drizzle-orm/src/utils.ts | 3 + drizzle-orm/tests/casing/casing.test.ts | 28 +++++++++ 6 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 drizzle-orm/src/casing.ts create mode 100644 drizzle-orm/tests/casing/casing.test.ts diff --git a/drizzle-orm/src/casing.ts b/drizzle-orm/src/casing.ts new file mode 100644 index 000000000..e370fa6c1 --- /dev/null +++ b/drizzle-orm/src/casing.ts @@ -0,0 +1,84 @@ +import { Table } from './table.ts'; +import { Casing, entityKind, type Column } from './index.ts'; + +/** @internal */ +export function toSnakeCase(input: string) { + const words = input + .replace(/['\u2019]/g, '') + .match(/[a-z0-9]+|[A-Z]+(?![a-z])|[A-Z][a-z0-9]+/g) ?? []; + + return words.map((word) => word.toLowerCase()).join('_'); +} + +/** @internal */ +export function toCamelCase(input: string) { + const words = input + .replace(/['\u2019]/g, '') + .match(/[a-z0-9]+|[A-Z]+(?![a-z])|[A-Z][a-z0-9]+/g) ?? []; + + return words.reduce((acc, word, i) => { + const formattedWord = i === 0 ? word.toLowerCase() : `${word[0]!.toUpperCase()}${word.slice(1)}`; + return acc + formattedWord; + }, ''); +} + +function noopCase(input: string) { + return input; +} + +export class CasingCache { + static readonly [entityKind]: string = 'CasingCache'; + + /** @internal */ + cache: Record = {}; + /** @internal */ + cachedTables: Record = {}; + private convert: (input: string) => string + + constructor(casing?: Casing) { + this.convert = casing === 'snake_case' + ? toSnakeCase + : casing === 'camelCase' + ? toCamelCase + : noopCase + } + + getColumnCasing(column: Column): string { + if (!column.keyAsName) return column.name; + + const schema = column.table[Table.Symbol.Schema] ?? 'public'; + const tableName = column.table[Table.Symbol.OriginalName]; + const key = `${schema}.${tableName}.${column.name}`; + + if (!this.cache[key]) { + this.cacheTable(column.table); + } + return this.cache[key]!; + } + + cacheTable(table: Table) { + const schema = table[Table.Symbol.Schema] ?? 'public'; + const tableName = table[Table.Symbol.OriginalName]; + const tableKey = `${schema}.${tableName}`; + + if (!this.cachedTables[tableKey]) { + for (const column of Object.values(table[Table.Symbol.Columns])) { + const columnKey = `${tableKey}.${column.name}`; + this.cache[columnKey] = this.convert(column.name); + } + this.cachedTables[tableKey] = true; + } + } + + /** @internal */ + isTableCached(table: Table) { + const schema = table[Table.Symbol.Schema] ?? 'public'; + const tableName = table[Table.Symbol.OriginalName]; + return this.cachedTables[`${schema}.${tableName}`]; + } + + clearCache() { + this.cache = {}; + this.cachedTables = {}; + } +} \ No newline at end of file diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index b4ebf31c2..fb7da9ef6 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -89,6 +89,7 @@ export type ColumnBuilderTypeConfig< export type ColumnBuilderRuntimeConfig = { name: string; + keyAsName: boolean; notNull: boolean; default: TData | SQL | undefined; defaultFn: (() => TData | SQL) | undefined; @@ -185,6 +186,7 @@ export abstract class ColumnBuilder< constructor(name: T['name'], dataType: T['dataType'], columnType: T['columnType']) { this.config = { name, + keyAsName: name === '', notNull: false, default: undefined, hasDefault: false, diff --git a/drizzle-orm/src/column.ts b/drizzle-orm/src/column.ts index e740acaa0..b0d6fb9a4 100644 --- a/drizzle-orm/src/column.ts +++ b/drizzle-orm/src/column.ts @@ -68,6 +68,8 @@ export abstract class Column< declare readonly _: ColumnTypeConfig; + /** @internal */ + readonly keyAsName: boolean; readonly name: string; readonly primary: boolean; readonly notNull: boolean; @@ -92,6 +94,7 @@ export abstract class Column< ) { this.config = config; this.name = config.name; + this.keyAsName = config.keyAsName; this.notNull = config.notNull; this.default = config.default; this.defaultFn = config.defaultFn; diff --git a/drizzle-orm/src/sql/sql.ts b/drizzle-orm/src/sql/sql.ts index 244a95d5d..17f6a7a52 100644 --- a/drizzle-orm/src/sql/sql.ts +++ b/drizzle-orm/src/sql/sql.ts @@ -7,6 +7,7 @@ import { ViewBaseConfig } from '~/view-common.ts'; import type { AnyColumn } from '../column.ts'; import { Column } from '../column.ts'; import { Table } from '../table.ts'; +import type { CasingCache } from '~/casing.ts'; /** * This class is used to indicate a primitive param value that is used in `sql` tag. @@ -28,6 +29,7 @@ export type Chunk = | SQL; export interface BuildQueryConfig { + casing: CasingCache; escapeName(name: string): string; escapeParam(num: number, value: unknown): string; escapeString(str: string): string; @@ -134,6 +136,7 @@ export class SQL implements SQLWrapper { }); const { + casing, escapeName, escapeParam, prepareTyping, @@ -185,10 +188,11 @@ export class SQL implements SQLWrapper { } if (is(chunk, Column)) { + const columnName = casing.getColumnCasing(chunk); if (_config.invokeSource === 'indexes') { - return { sql: escapeName(chunk.name), params: [] }; + return { sql: escapeName(columnName), params: [] }; } - return { sql: escapeName(chunk.table[Table.Symbol.Name]) + '.' + escapeName(chunk.name), params: [] }; + return { sql: escapeName(chunk.table[Table.Symbol.Name]) + '.' + escapeName(columnName), params: [] }; } if (is(chunk, View)) { diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index cec81e78a..7225a0f8a 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -207,9 +207,12 @@ export type ColumnsWithTable< TColumns extends AnyColumn<{ tableName: TTableName }>[], > = { [Key in keyof TColumns]: AnyColumn<{ tableName: TForeignTableName }> }; +export type Casing = 'snake_case' | 'camelCase'; + export interface DrizzleConfig = Record> { logger?: boolean | Logger; schema?: TSchema; + casing?: Casing; } export type ValidateShape = T extends ValidShape ? Exclude extends never ? TResult diff --git a/drizzle-orm/tests/casing/casing.test.ts b/drizzle-orm/tests/casing/casing.test.ts new file mode 100644 index 000000000..9a813f447 --- /dev/null +++ b/drizzle-orm/tests/casing/casing.test.ts @@ -0,0 +1,28 @@ +import { describe, it } from 'vitest'; +import { toSnakeCase, toCamelCase } from '~/casing'; + +describe.concurrent('casing', () => { + it('transforms to snake case', ({ expect }) => { + expect(toSnakeCase('drizzleKit')).toEqual('drizzle_kit'); + }); + + it('transforms an uppercase acronym/abbreviation to snake case', ({ expect }) => { + expect(toSnakeCase('drizzleORM')).toEqual('drizzle_orm'); + }); + + it('transforms a camel case acronym/abbreviation to snake case', ({ expect }) => { + expect(toSnakeCase('drizzleOrm')).toEqual('drizzle_orm'); + }); + + it('transforms an uppercase acronym/abbreviation followed by a word to snake case', ({ expect }) => { + expect(toSnakeCase('drizzleORMAndKit')).toEqual('drizzle_orm_and_kit'); + }); + + it('transforms a camel case acronym/abbreviation followed by a word to snake case', ({ expect }) => { + expect(toSnakeCase('drizzleOrmAndKit')).toEqual('drizzle_orm_and_kit'); + }); + + it('transforms to camel case 1', ({ expect }) => { + expect(toCamelCase('drizzle_kit')).toEqual('drizzleKit'); + }); +}); From b352b955ee1a332906cd1bbe62157061f0e7aa45 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 26 Aug 2024 11:11:09 -0700 Subject: [PATCH 090/492] Implement casing cache in PG --- drizzle-orm/src/casing.ts | 10 +- drizzle-orm/src/pg-core/db.ts | 3 +- drizzle-orm/src/pg-core/dialect.ts | 25 ++- .../src/pg-core/query-builders/delete.ts | 1 + .../src/pg-core/query-builders/insert.ts | 4 +- .../pg-core/query-builders/query-builder.ts | 12 +- .../src/pg-core/query-builders/select.ts | 4 + .../src/pg-core/query-builders/update.ts | 4 +- drizzle-orm/src/postgres-js/driver.ts | 2 +- drizzle-orm/tests/casing/pg-camel.test.ts | 143 ++++++++++++++++++ drizzle-orm/tests/casing/pg-snake.test.ts | 143 ++++++++++++++++++ 11 files changed, 330 insertions(+), 21 deletions(-) create mode 100644 drizzle-orm/tests/casing/pg-camel.test.ts create mode 100644 drizzle-orm/tests/casing/pg-snake.test.ts diff --git a/drizzle-orm/src/casing.ts b/drizzle-orm/src/casing.ts index e370fa6c1..cac657080 100644 --- a/drizzle-orm/src/casing.ts +++ b/drizzle-orm/src/casing.ts @@ -31,8 +31,7 @@ export class CasingCache { /** @internal */ cache: Record = {}; - /** @internal */ - cachedTables: Record = {}; + private cachedTables: Record = {}; private convert: (input: string) => string constructor(casing?: Casing) { @@ -70,13 +69,6 @@ export class CasingCache { } } - /** @internal */ - isTableCached(table: Table) { - const schema = table[Table.Symbol.Schema] ?? 'public'; - const tableName = table[Table.Symbol.OriginalName]; - return this.cachedTables[`${schema}.${tableName}`]; - } - clearCache() { this.cache = {}; this.cachedTables = {}; diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index 4e8d2f354..69a9e0962 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -119,12 +119,13 @@ export class PgDatabase< * ``` */ $with(alias: TAlias) { + const self = this; return { as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), ): WithSubqueryWithSelection { if (typeof qb === 'function') { - qb = qb(new QueryBuilder()); + qb = qb(new QueryBuilder(self.dialect)); } return new Proxy( diff --git a/drizzle-orm/src/pg-core/dialect.ts b/drizzle-orm/src/pg-core/dialect.ts index fff2ce65a..fb7ad95a1 100644 --- a/drizzle-orm/src/pg-core/dialect.ts +++ b/drizzle-orm/src/pg-core/dialect.ts @@ -48,15 +48,27 @@ import { } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { getTableName, getTableUniqueName, Table } from '~/table.ts'; -import { orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { PgSession } from './session.ts'; import { PgViewBase } from './view-base.ts'; import type { PgMaterializedView } from './view.ts'; +import { CasingCache } from '~/casing.ts'; + +export interface PgDialectConfig { + casing?: Casing; +} export class PgDialect { static readonly [entityKind]: string = 'PgDialect'; + /** @internal */ + readonly casing: CasingCache; + + constructor(config?: PgDialectConfig) { + this.casing = new CasingCache(config?.casing); + } + async migrate(migrations: MigrationMeta[], session: PgSession, config: string | MigrationConfig): Promise { const migrationsTable = typeof config === 'string' ? '__drizzle_migrations' @@ -148,7 +160,7 @@ export class PgDialect { const col = tableColumns[colName]!; const value = set[colName] ?? sql.param(col.onUpdateFn!(), col); - const res = sql`${sql.identifier(col.name)} = ${value}`; + const res = sql`${sql.identifier(this.casing.getColumnCasing(col))} = ${value}`; if (i < setSize - 1) { return [res, sql.raw(', ')]; @@ -202,7 +214,7 @@ export class PgDialect { new SQL( query.queryChunks.map((c) => { if (is(c, PgColumn)) { - return sql.identifier(c.name); + return sql.identifier(this.casing.getColumnCasing(c)); } return c; }), @@ -217,7 +229,7 @@ export class PgDialect { } } else if (is(field, Column)) { if (isSingleTable) { - chunk.push(sql.identifier(field.name)); + chunk.push(sql.identifier(this.casing.getColumnCasing(field))); } else { chunk.push(field); } @@ -462,7 +474,9 @@ export class PgDialect { const colEntries: [string, PgColumn][] = Object.entries(columns).filter(([_, col]) => !col.shouldDisableInsert()); - const insertOrder = colEntries.map(([, column]) => sql.identifier(column.name)); + const insertOrder = colEntries.map( + ([, column]) => sql.identifier(this.casing.getColumnCasing(column)) + ); for (const [valueIndex, value] of values.entries()) { const valueList: (SQLChunk | SQL)[] = []; @@ -535,6 +549,7 @@ export class PgDialect { sqlToQuery(sql: SQL, invokeSource?: 'indexes' | undefined): QueryWithTypings { return sql.toQuery({ + casing: this.casing, escapeName: this.escapeName, escapeParam: this.escapeParam, escapeString: this.escapeString, diff --git a/drizzle-orm/src/pg-core/query-builders/delete.ts b/drizzle-orm/src/pg-core/query-builders/delete.ts index dc127f167..bf0f4ea14 100644 --- a/drizzle-orm/src/pg-core/query-builders/delete.ts +++ b/drizzle-orm/src/pg-core/query-builders/delete.ts @@ -139,6 +139,7 @@ export class PgDeleteBase< withList?: Subquery[], ) { super(); + this.dialect.casing.cacheTable(table); this.config = { table, withList }; } diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index c27f8ce9b..00b9e26d6 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -44,7 +44,9 @@ export class PgInsertBuilder): PgInsertBase; values(values: PgInsertValue[]): PgInsertBase; diff --git a/drizzle-orm/src/pg-core/query-builders/query-builder.ts b/drizzle-orm/src/pg-core/query-builders/query-builder.ts index fd29ee10d..7dc40ef0d 100644 --- a/drizzle-orm/src/pg-core/query-builders/query-builder.ts +++ b/drizzle-orm/src/pg-core/query-builders/query-builder.ts @@ -1,5 +1,5 @@ -import { entityKind } from '~/entity.ts'; -import { PgDialect } from '~/pg-core/dialect.ts'; +import { entityKind, is } from '~/entity.ts'; +import { PgDialect, PgDialectConfig } from '~/pg-core/dialect.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; @@ -13,6 +13,12 @@ export class QueryBuilder { static readonly [entityKind]: string = 'PgQueryBuilder'; private dialect: PgDialect | undefined; + private dialectConfig: PgDialectConfig | undefined; + + constructor(dialect?: PgDialect | PgDialectConfig) { + this.dialect = is(dialect, PgDialect) ? dialect : undefined; + this.dialectConfig = !is(dialect, PgDialect) ? dialect : undefined; + } $with(alias: TAlias) { const queryBuilder = this; @@ -121,7 +127,7 @@ export class QueryBuilder { // Lazy load dialect to avoid circular dependency private getDialect() { if (!this.dialect) { - this.dialect = new PgDialect(); + this.dialect = new PgDialect(this.dialectConfig); } return this.dialect; diff --git a/drizzle-orm/src/pg-core/query-builders/select.ts b/drizzle-orm/src/pg-core/query-builders/select.ts index d2406995b..1d79ec085 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.ts @@ -112,6 +112,7 @@ export class PgSelectBuilder< } else if (is(source, SQL)) { fields = {}; } else { + this.dialect.casing.cacheTable(source); fields = getTableColumns(source); } @@ -214,6 +215,9 @@ export abstract class PgSelectQueryBuilderBase< }; } if (typeof tableName === 'string' && !is(table, SQL)) { + if (is(table, Table)) { + this.dialect.casing.cacheTable(table); + } const selection = is(table, Subquery) ? table._.selectedFields : is(table, View) diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index ec404ac22..2054e40fc 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -47,7 +47,9 @@ export class PgUpdateBuilder): PgUpdateBase { return new PgUpdateBase( diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index ae1b48a21..590732590 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -28,7 +28,7 @@ export function drizzle = Record users.id), + usesDrizzleORM: boolean().notNull(), +}); +const devs = alias(developers, 'devs'); + +const usersCache = { + 'public.users.id': 'id', + 'public.users.firstName': 'first_name', + 'public.users.lastName': 'last_name', + 'public.users.AGE': 'age', +}; +const developersCache = { + 'test.developers.userId': 'user_id', + 'test.developers.usesDrizzleORM': 'uses_drizzle_orm', +}; +const cache = { + ...usersCache, + ...developersCache, +}; + +const fullName = sql`${users.firstName} || ' ' || ${users.lastName}`.as('name'); + +describe('postgres camel case to snake case ', () => { + beforeEach(() => { + db.dialect.casing.clearCache(); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.userId)) + .orderBy(asc(users.firstName)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."user_id" order by "users"."first_name" asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .leftJoin(devs, eq(users.id, devs.userId)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."first_name" from "users" left join "test"."developers" "devs" on "users"."id" = "devs"."user_id"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('insert', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into "users" ("id", "first_name", "last_name", "AGE") values (default, $1, $2, $3) returning "first_name", "AGE"', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ firstName: 'John', lastName: 'Doe', age: 30 }) + .where(eq(users.id, 1)) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'update "users" set "first_name" = $1, "last_name" = $2, "AGE" = $3 where "users"."id" = $4 returning "first_name", "AGE"', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'delete from "users" where "users"."id" = $1 returning "first_name", "AGE"', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('raw', ({ expect }) => { + const query = db.execute(sql`select ${users.firstName} from ${users}`); + + expect(query.getQuery()).toEqual({ + sql: 'select "users"."first_name" from "users"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); +}); diff --git a/drizzle-orm/tests/casing/pg-snake.test.ts b/drizzle-orm/tests/casing/pg-snake.test.ts new file mode 100644 index 000000000..c32bc2d46 --- /dev/null +++ b/drizzle-orm/tests/casing/pg-snake.test.ts @@ -0,0 +1,143 @@ +import { beforeEach, describe, it } from 'vitest'; +import { drizzle } from '~/postgres-js'; +import { alias, boolean, integer, pgSchema, pgTable, serial, text } from '~/pg-core'; +import { asc, eq, sql } from '~/sql'; +import postgres from 'postgres'; + +const db = drizzle(postgres(''), { casing: 'camelCase' }); + +const testSchema = pgSchema('test'); +const users = pgTable('users', { + id: serial().primaryKey(), + first_name: text().notNull(), + last_name: text().notNull(), + // Test that custom aliases remain + age: integer('AGE') +}); +const developers = testSchema.table('developers', { + user_id: serial().primaryKey().references(() => users.id), + uses_drizzle_orm: boolean().notNull(), +}); +const devs = alias(developers, 'devs'); + +const usersCache = { + 'public.users.id': 'id', + 'public.users.first_name': 'firstName', + 'public.users.last_name': 'lastName', + 'public.users.AGE': 'age', +}; +const developersCache = { + 'test.developers.user_id': 'userId', + 'test.developers.uses_drizzle_orm': 'usesDrizzleOrm', +}; +const cache = { + ...usersCache, + ...developersCache, +}; + +const fullName = sql`${users.first_name} || ' ' || ${users.last_name}`.as('name'); + +describe('postgres snake case to camel case ', () => { + beforeEach(() => { + db.dialect.casing.clearCache(); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.user_id)) + .orderBy(asc(users.first_name)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."userId" order by "users"."firstName" asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ first_name: users.first_name }) + .from(users) + .leftJoin(devs, eq(users.id, devs.user_id)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."firstName" from "users" left join "test"."developers" "devs" on "users"."id" = "devs"."userId"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('insert', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into "users" ("id", "firstName", "lastName", "AGE") values (default, $1, $2, $3) returning "firstName", "AGE"', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ first_name: 'John', last_name: 'Doe', age: 30 }) + .where(eq(users.id, 1)) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'update "users" set "firstName" = $1, "lastName" = $2, "AGE" = $3 where "users"."id" = $4 returning "firstName", "AGE"', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'delete from "users" where "users"."id" = $1 returning "firstName", "AGE"', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('raw', ({ expect }) => { + const query = db.execute(sql`select ${users.first_name} from ${users}`); + + expect(query.getQuery()).toEqual({ + sql: 'select "users"."firstName" from "users"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); +}); From e72e31c19032de292a3273ca0a50de3a0b2baa85 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 26 Aug 2024 11:13:46 -0700 Subject: [PATCH 091/492] Update PG driver configs and inits --- drizzle-orm/src/neon-http/driver.ts | 2 +- drizzle-orm/src/neon-serverless/driver.ts | 2 +- drizzle-orm/src/node-postgres/driver.ts | 2 +- drizzle-orm/src/pg-proxy/driver.ts | 2 +- drizzle-orm/src/pglite/driver.ts | 2 +- drizzle-orm/src/vercel-postgres/driver.ts | 2 +- drizzle-orm/src/xata-http/driver.ts | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index 81a66c69b..6be47a15b 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -59,7 +59,7 @@ export function drizzle = Record, config: DrizzleConfig = {}, ): NeonHttpDatabase { - const dialect = new PgDialect(); + const dialect = new PgDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index 8a15dd678..19141d849 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -51,7 +51,7 @@ export function drizzle = Record = {}, ): NeonDatabase { - const dialect = new PgDialect(); + const dialect = new PgDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index 4c233f891..4bb2fcabf 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -53,7 +53,7 @@ export function drizzle = Record = {}, ): NodePgDatabase { - const dialect = new PgDialect(); + const dialect = new PgDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/pg-proxy/driver.ts b/drizzle-orm/src/pg-proxy/driver.ts index cdffa15c1..a6c7c4b3e 100644 --- a/drizzle-orm/src/pg-proxy/driver.ts +++ b/drizzle-orm/src/pg-proxy/driver.ts @@ -24,7 +24,7 @@ export type RemoteCallback = ( export function drizzle = Record>( callback: RemoteCallback, config: DrizzleConfig = {}, - _dialect: () => PgDialect = () => new PgDialect(), + _dialect: () => PgDialect = () => new PgDialect({ casing: config.casing }), ): PgRemoteDatabase { const dialect = _dialect(); let logger; diff --git a/drizzle-orm/src/pglite/driver.ts b/drizzle-orm/src/pglite/driver.ts index 7de2ce110..3e446da0f 100644 --- a/drizzle-orm/src/pglite/driver.ts +++ b/drizzle-orm/src/pglite/driver.ts @@ -42,7 +42,7 @@ export function drizzle = Record = {}, ): PgliteDatabase { - const dialect = new PgDialect(); + const dialect = new PgDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 07e73c732..2579eab01 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -50,7 +50,7 @@ export function drizzle = Record = {}, ): VercelPgDatabase { - const dialect = new PgDialect(); + const dialect = new PgDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/xata-http/driver.ts b/drizzle-orm/src/xata-http/driver.ts index 9838083aa..2895a5ea7 100644 --- a/drizzle-orm/src/xata-http/driver.ts +++ b/drizzle-orm/src/xata-http/driver.ts @@ -50,7 +50,7 @@ export function drizzle = Record = {}, ): XataHttpDatabase { - const dialect = new PgDialect(); + const dialect = new PgDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); From 0f5fdd942d85e7fa21a0fb50f09fe2304b11f6fc Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 26 Aug 2024 11:31:40 -0700 Subject: [PATCH 092/492] Update AWS Data API driver --- drizzle-orm/src/aws-data-api/pg/driver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index 5174c24d0..662b61f9e 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -91,7 +91,7 @@ export function drizzle = Record, ): AwsDataApiPgDatabase { - const dialect = new AwsPgDialect(); + const dialect = new AwsPgDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); From c929e5fe827f7b1f4a728d2b944a0065143ce191 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 26 Aug 2024 11:46:27 -0700 Subject: [PATCH 093/492] Add additional PG tests --- .../src/pg-core/query-builders/insert.ts | 8 ++++---- drizzle-orm/tests/casing/pg-camel.test.ts | 19 +++++++++++++++++-- drizzle-orm/tests/casing/pg-snake.test.ts | 19 +++++++++++++++++-- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index 00b9e26d6..af2446bad 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -244,8 +244,8 @@ export class PgInsertBase< } else { let targetColumn = ''; targetColumn = Array.isArray(config.target) - ? config.target.map((it) => this.dialect.escapeName(it.name)).join(',') - : this.dialect.escapeName(config.target.name); + ? config.target.map((it) => this.dialect.escapeName(this.dialect.casing.getColumnCasing(it))).join(',') + : this.dialect.escapeName(this.dialect.casing.getColumnCasing(config.target)); const whereSql = config.where ? sql` where ${config.where}` : undefined; this.config.onConflict = sql`(${sql.raw(targetColumn)})${whereSql} do nothing`; @@ -296,8 +296,8 @@ export class PgInsertBase< const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set)); let targetColumn = ''; targetColumn = Array.isArray(config.target) - ? config.target.map((it) => this.dialect.escapeName(it.name)).join(',') - : this.dialect.escapeName(config.target.name); + ? config.target.map((it) => this.dialect.escapeName(this.dialect.casing.getColumnCasing(it))).join(',') + : this.dialect.escapeName(this.dialect.casing.getColumnCasing(config.target)); this.config.onConflict = sql`(${ sql.raw(targetColumn) })${targetWhereSql} do update set ${setSql}${whereSql}${setWhereSql}`; diff --git a/drizzle-orm/tests/casing/pg-camel.test.ts b/drizzle-orm/tests/casing/pg-camel.test.ts index 90846e76c..c4976e850 100644 --- a/drizzle-orm/tests/casing/pg-camel.test.ts +++ b/drizzle-orm/tests/casing/pg-camel.test.ts @@ -91,19 +91,34 @@ describe('postgres camel case to snake case ', () => { expect(db.dialect.casing.cache).toEqual(cache); }); - it('insert', ({ expect }) => { + it('insert (on conflict do nothing)', ({ expect }) => { const query = db .insert(users) .values({ firstName: 'John', lastName: 'Doe', age: 30 }) + .onConflictDoNothing({ target: users.firstName }) .returning({ firstName: users.firstName, age: users.age }); expect(query.toSQL()).toEqual({ - sql: 'insert into "users" ("id", "first_name", "last_name", "AGE") values (default, $1, $2, $3) returning "first_name", "AGE"', + sql: 'insert into "users" ("id", "first_name", "last_name", "AGE") values (default, $1, $2, $3) on conflict ("first_name") do nothing returning "first_name", "AGE"', params: ['John', 'Doe', 30], }); expect(db.dialect.casing.cache).toEqual(usersCache); }); + it('insert (on conflict do update)', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }) + .onConflictDoUpdate({ target: users.firstName, set: { age: 31 } }) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into "users" ("id", "first_name", "last_name", "AGE") values (default, $1, $2, $3) on conflict ("first_name") do update set "AGE" = $4 returning "first_name", "AGE"', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + it('update', ({ expect }) => { const query = db .update(users) diff --git a/drizzle-orm/tests/casing/pg-snake.test.ts b/drizzle-orm/tests/casing/pg-snake.test.ts index c32bc2d46..3723b51aa 100644 --- a/drizzle-orm/tests/casing/pg-snake.test.ts +++ b/drizzle-orm/tests/casing/pg-snake.test.ts @@ -91,19 +91,34 @@ describe('postgres snake case to camel case ', () => { expect(db.dialect.casing.cache).toEqual(cache); }); - it('insert', ({ expect }) => { + it('insert (on conflict do nothing)', ({ expect }) => { const query = db .insert(users) .values({ first_name: 'John', last_name: 'Doe', age: 30 }) + .onConflictDoNothing({ target: users.first_name }) .returning({ first_name: users.first_name, age: users.age }); expect(query.toSQL()).toEqual({ - sql: 'insert into "users" ("id", "firstName", "lastName", "AGE") values (default, $1, $2, $3) returning "firstName", "AGE"', + sql: 'insert into "users" ("id", "firstName", "lastName", "AGE") values (default, $1, $2, $3) on conflict ("firstName") do nothing returning "firstName", "AGE"', params: ['John', 'Doe', 30], }); expect(db.dialect.casing.cache).toEqual(usersCache); }); + it('insert (on conflict do update)', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }) + .onConflictDoUpdate({ target: users.first_name, set: { age: 31 } }) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into "users" ("id", "firstName", "lastName", "AGE") values (default, $1, $2, $3) on conflict ("firstName") do update set "AGE" = $4 returning "firstName", "AGE"', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + it('update', ({ expect }) => { const query = db .update(users) From c15d455895da34c4306b098906628ab5c0ca73ef Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 26 Aug 2024 11:50:59 -0700 Subject: [PATCH 094/492] Remove raw SQL test cases from PG --- drizzle-orm/tests/casing/pg-camel.test.ts | 10 ---------- drizzle-orm/tests/casing/pg-snake.test.ts | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/drizzle-orm/tests/casing/pg-camel.test.ts b/drizzle-orm/tests/casing/pg-camel.test.ts index c4976e850..2356c496a 100644 --- a/drizzle-orm/tests/casing/pg-camel.test.ts +++ b/drizzle-orm/tests/casing/pg-camel.test.ts @@ -145,14 +145,4 @@ describe('postgres camel case to snake case ', () => { }); expect(db.dialect.casing.cache).toEqual(usersCache); }); - - it('raw', ({ expect }) => { - const query = db.execute(sql`select ${users.firstName} from ${users}`); - - expect(query.getQuery()).toEqual({ - sql: 'select "users"."first_name" from "users"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); }); diff --git a/drizzle-orm/tests/casing/pg-snake.test.ts b/drizzle-orm/tests/casing/pg-snake.test.ts index 3723b51aa..7e202894e 100644 --- a/drizzle-orm/tests/casing/pg-snake.test.ts +++ b/drizzle-orm/tests/casing/pg-snake.test.ts @@ -145,14 +145,4 @@ describe('postgres snake case to camel case ', () => { }); expect(db.dialect.casing.cache).toEqual(usersCache); }); - - it('raw', ({ expect }) => { - const query = db.execute(sql`select ${users.first_name} from ${users}`); - - expect(query.getQuery()).toEqual({ - sql: 'select "users"."firstName" from "users"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); }); From 969cb67be9f7721a4d71ad03aec33af0852b7a4b Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 26 Aug 2024 12:22:25 -0700 Subject: [PATCH 095/492] Add set operator tests to PG --- drizzle-orm/tests/casing/pg-camel.test.ts | 28 ++++++++++++++++++++++- drizzle-orm/tests/casing/pg-snake.test.ts | 28 ++++++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/tests/casing/pg-camel.test.ts b/drizzle-orm/tests/casing/pg-camel.test.ts index 2356c496a..1fb2edd60 100644 --- a/drizzle-orm/tests/casing/pg-camel.test.ts +++ b/drizzle-orm/tests/casing/pg-camel.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, it } from 'vitest'; import { drizzle } from '~/postgres-js'; -import { alias, boolean, integer, pgSchema, pgTable, serial, text } from '~/pg-core'; +import { alias, boolean, integer, pgSchema, pgTable, serial, text, union } from '~/pg-core'; import { asc, eq, sql } from '~/sql'; import postgres from 'postgres'; @@ -64,6 +64,32 @@ describe('postgres camel case to snake case ', () => { expect(db.dialect.casing.cache).toEqual(usersCache); }); + it('set operator', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .union(db.select({ firstName: users.firstName }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: '(select "first_name" from "users") union (select "first_name" from "users")', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ firstName: users.firstName }).from(users), + db.select({ firstName: users.firstName }).from(users) + ); + + expect(query.toSQL()).toEqual({ + sql: '(select "first_name" from "users") union (select "first_name" from "users")', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + it('select', ({ expect }) => { const query = db .select({ name: fullName, age: users.age }) diff --git a/drizzle-orm/tests/casing/pg-snake.test.ts b/drizzle-orm/tests/casing/pg-snake.test.ts index 7e202894e..219d3b237 100644 --- a/drizzle-orm/tests/casing/pg-snake.test.ts +++ b/drizzle-orm/tests/casing/pg-snake.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, it } from 'vitest'; import { drizzle } from '~/postgres-js'; -import { alias, boolean, integer, pgSchema, pgTable, serial, text } from '~/pg-core'; +import { alias, boolean, integer, pgSchema, pgTable, serial, text, union } from '~/pg-core'; import { asc, eq, sql } from '~/sql'; import postgres from 'postgres'; @@ -64,6 +64,32 @@ describe('postgres snake case to camel case ', () => { expect(db.dialect.casing.cache).toEqual(usersCache); }); + it('set operator', ({ expect }) => { + const query = db + .select({ first_name: users.first_name }) + .from(users) + .union(db.select({ first_name: users.first_name }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: '(select "firstName" from "users") union (select "firstName" from "users")', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ first_name: users.first_name }).from(users), + db.select({ first_name: users.first_name }).from(users) + ); + + expect(query.toSQL()).toEqual({ + sql: '(select "firstName" from "users") union (select "firstName" from "users")', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + it('select', ({ expect }) => { const query = db .select({ name: fullName, age: users.age }) From c7a8298e0048058e80bb63bf24284779db01e6ee Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 26 Aug 2024 12:25:52 -0700 Subject: [PATCH 096/492] Rename PG test files --- .../tests/casing/{pg-snake.test.ts => pg-to-camel.test.ts} | 0 .../tests/casing/{pg-camel.test.ts => pg-to-snake.test.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename drizzle-orm/tests/casing/{pg-snake.test.ts => pg-to-camel.test.ts} (100%) rename drizzle-orm/tests/casing/{pg-camel.test.ts => pg-to-snake.test.ts} (100%) diff --git a/drizzle-orm/tests/casing/pg-snake.test.ts b/drizzle-orm/tests/casing/pg-to-camel.test.ts similarity index 100% rename from drizzle-orm/tests/casing/pg-snake.test.ts rename to drizzle-orm/tests/casing/pg-to-camel.test.ts diff --git a/drizzle-orm/tests/casing/pg-camel.test.ts b/drizzle-orm/tests/casing/pg-to-snake.test.ts similarity index 100% rename from drizzle-orm/tests/casing/pg-camel.test.ts rename to drizzle-orm/tests/casing/pg-to-snake.test.ts From ca0878fbf553394f5c1d4b1082dfe2f19aa786ac Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 26 Aug 2024 12:30:29 -0700 Subject: [PATCH 097/492] Implement MySQL casing cache --- drizzle-orm/src/mysql-core/db.ts | 3 +- drizzle-orm/src/mysql-core/dialect.ts | 27 ++- .../src/mysql-core/query-builders/delete.ts | 1 + .../src/mysql-core/query-builders/insert.ts | 4 +- .../query-builders/query-builder.ts | 12 +- .../src/mysql-core/query-builders/select.ts | 4 + .../src/mysql-core/query-builders/update.ts | 4 +- .../src/planetscale-serverless/driver.ts | 2 +- .../tests/casing/mysql-to-camel.test.ts | 169 ++++++++++++++++++ .../tests/casing/mysql-to-snake.test.ts | 169 ++++++++++++++++++ 10 files changed, 381 insertions(+), 14 deletions(-) create mode 100644 drizzle-orm/tests/casing/mysql-to-camel.test.ts create mode 100644 drizzle-orm/tests/casing/mysql-to-snake.test.ts diff --git a/drizzle-orm/src/mysql-core/db.ts b/drizzle-orm/src/mysql-core/db.ts index 8df6ff343..b37dfa254 100644 --- a/drizzle-orm/src/mysql-core/db.ts +++ b/drizzle-orm/src/mysql-core/db.ts @@ -118,12 +118,13 @@ export class MySqlDatabase< * ``` */ $with(alias: TAlias) { + const self = this; return { as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), ): WithSubqueryWithSelection { if (typeof qb === 'function') { - qb = qb(new QueryBuilder()); + qb = qb(new QueryBuilder(self.dialect)); } return new Proxy( diff --git a/drizzle-orm/src/mysql-core/dialect.ts b/drizzle-orm/src/mysql-core/dialect.ts index 4a72d9c5f..f2deef49a 100644 --- a/drizzle-orm/src/mysql-core/dialect.ts +++ b/drizzle-orm/src/mysql-core/dialect.ts @@ -20,7 +20,7 @@ import { Param, SQL, sql, View } from '~/sql/sql.ts'; import type { Name, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { getTableName, getTableUniqueName, Table } from '~/table.ts'; -import { orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import { MySqlColumn } from './columns/common.ts'; import type { MySqlDeleteConfig } from './query-builders/delete.ts'; @@ -30,10 +30,22 @@ import type { MySqlUpdateConfig } from './query-builders/update.ts'; import type { MySqlSession } from './session.ts'; import { MySqlTable } from './table.ts'; import { MySqlViewBase } from './view-base.ts'; +import { CasingCache } from '~/casing.ts'; + +export interface MySqlDialectConfig { + casing?: Casing; +} export class MySqlDialect { static readonly [entityKind]: string = 'MySqlDialect'; + /** @internal */ + readonly casing: CasingCache; + + constructor(config?: MySqlDialectConfig) { + this.casing = new CasingCache(config?.casing); + } + async migrate( migrations: MigrationMeta[], session: MySqlSession, @@ -124,7 +136,7 @@ export class MySqlDialect { const col = tableColumns[colName]!; const value = set[colName] ?? sql.param(col.onUpdateFn!(), col); - const res = sql`${sql.identifier(col.name)} = ${value}`; + const res = sql`${sql.identifier(this.casing.getColumnCasing(col))} = ${value}`; if (i < setSize - 1) { return [res, sql.raw(', ')]; @@ -178,7 +190,7 @@ export class MySqlDialect { new SQL( query.queryChunks.map((c) => { if (is(c, MySqlColumn)) { - return sql.identifier(c.name); + return sql.identifier(this.casing.getColumnCasing(c)); } return c; }), @@ -193,7 +205,7 @@ export class MySqlDialect { } } else if (is(field, Column)) { if (isSingleTable) { - chunk.push(sql.identifier(field.name)); + chunk.push(sql.identifier(this.casing.getColumnCasing(field))); } else { chunk.push(field); } @@ -386,13 +398,13 @@ export class MySqlDialect { // which is invalid MySql syntax, Table from one of the SELECTs cannot be used in global ORDER clause for (const orderByUnit of orderBy) { if (is(orderByUnit, MySqlColumn)) { - orderByValues.push(sql.identifier(orderByUnit.name)); + orderByValues.push(sql.identifier(this.casing.getColumnCasing(orderByUnit))); } else if (is(orderByUnit, SQL)) { for (let i = 0; i < orderByUnit.queryChunks.length; i++) { const chunk = orderByUnit.queryChunks[i]; if (is(chunk, MySqlColumn)) { - orderByUnit.queryChunks[i] = sql.identifier(chunk.name); + orderByUnit.queryChunks[i] = sql.identifier(this.casing.getColumnCasing(chunk)); } } @@ -426,7 +438,7 @@ export class MySqlDialect { !col.shouldDisableInsert() ); - const insertOrder = colEntries.map(([, column]) => sql.identifier(column.name)); + const insertOrder = colEntries.map(([, column]) => sql.identifier(this.casing.getColumnCasing(column))); const generatedIdsResponse: Record[] = []; for (const [valueIndex, value] of values.entries()) { @@ -479,6 +491,7 @@ export class MySqlDialect { sqlToQuery(sql: SQL, invokeSource?: 'indexes' | undefined): QueryWithTypings { return sql.toQuery({ + casing: this.casing, escapeName: this.escapeName, escapeParam: this.escapeParam, escapeString: this.escapeString, diff --git a/drizzle-orm/src/mysql-core/query-builders/delete.ts b/drizzle-orm/src/mysql-core/query-builders/delete.ts index e9a48da8e..8cdec4bb7 100644 --- a/drizzle-orm/src/mysql-core/query-builders/delete.ts +++ b/drizzle-orm/src/mysql-core/query-builders/delete.ts @@ -97,6 +97,7 @@ export class MySqlDeleteBase< withList?: Subquery[], ) { super(); + this.dialect.casing.cacheTable(table); this.config = { table, withList }; } diff --git a/drizzle-orm/src/mysql-core/query-builders/insert.ts b/drizzle-orm/src/mysql-core/query-builders/insert.ts index 97e61de74..b8dbe12fe 100644 --- a/drizzle-orm/src/mysql-core/query-builders/insert.ts +++ b/drizzle-orm/src/mysql-core/query-builders/insert.ts @@ -50,7 +50,9 @@ export class MySqlInsertBuilder< private table: TTable, private session: MySqlSession, private dialect: MySqlDialect, - ) {} + ) { + this.dialect.casing.cacheTable(table); + } ignore(): this { this.shouldIgnore = true; diff --git a/drizzle-orm/src/mysql-core/query-builders/query-builder.ts b/drizzle-orm/src/mysql-core/query-builders/query-builder.ts index f5d9cacc4..16f5447a1 100644 --- a/drizzle-orm/src/mysql-core/query-builders/query-builder.ts +++ b/drizzle-orm/src/mysql-core/query-builders/query-builder.ts @@ -1,5 +1,5 @@ -import { entityKind } from '~/entity.ts'; -import { MySqlDialect } from '~/mysql-core/dialect.ts'; +import { entityKind, is } from '~/entity.ts'; +import { MySqlDialect, MySqlDialectConfig } from '~/mysql-core/dialect.ts'; import type { WithSubqueryWithSelection } from '~/mysql-core/subquery.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; @@ -12,6 +12,12 @@ export class QueryBuilder { static readonly [entityKind]: string = 'MySqlQueryBuilder'; private dialect: MySqlDialect | undefined; + private dialectConfig: MySqlDialectConfig | undefined; + + constructor(dialect?: MySqlDialect | MySqlDialectConfig) { + this.dialect = is(dialect, MySqlDialect) ? dialect : undefined; + this.dialectConfig = !is(dialect, MySqlDialect) ? dialect : undefined; + } $with(alias: TAlias) { const queryBuilder = this; @@ -95,7 +101,7 @@ export class QueryBuilder { // Lazy load dialect to avoid circular dependency private getDialect() { if (!this.dialect) { - this.dialect = new MySqlDialect(); + this.dialect = new MySqlDialect(this.dialectConfig); } return this.dialect; diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index a5a0ca69a..ef6a59ab0 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -102,6 +102,7 @@ export class MySqlSelectBuilder< } else if (is(source, SQL)) { fields = {}; } else { + this.dialect.casing.cacheTable(source); fields = getTableColumns(source); } @@ -206,6 +207,9 @@ export abstract class MySqlSelectQueryBuilderBase< }; } if (typeof tableName === 'string' && !is(table, SQL)) { + if (is(table, Table)) { + this.dialect.casing.cacheTable(table); + } const selection = is(table, Subquery) ? table._.selectedFields : is(table, View) diff --git a/drizzle-orm/src/mysql-core/query-builders/update.ts b/drizzle-orm/src/mysql-core/query-builders/update.ts index 7884599cf..426d18168 100644 --- a/drizzle-orm/src/mysql-core/query-builders/update.ts +++ b/drizzle-orm/src/mysql-core/query-builders/update.ts @@ -49,7 +49,9 @@ export class MySqlUpdateBuilder< private session: MySqlSession, private dialect: MySqlDialect, private withList?: Subquery[], - ) {} + ) { + this.dialect.casing.cacheTable(table); + } set(values: MySqlUpdateSetSource): MySqlUpdateBase { return new MySqlUpdateBase(this.table, mapUpdateSet(this.table, values), this.session, this.dialect, this.withList); diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index b1d2d6e6f..c34789e43 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -60,7 +60,7 @@ Starting from version 0.30.0, you will encounter an error if you attempt to use `); } - const dialect = new MySqlDialect(); + const dialect = new MySqlDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/tests/casing/mysql-to-camel.test.ts b/drizzle-orm/tests/casing/mysql-to-camel.test.ts new file mode 100644 index 000000000..2f8a0d810 --- /dev/null +++ b/drizzle-orm/tests/casing/mysql-to-camel.test.ts @@ -0,0 +1,169 @@ +import { beforeEach, describe, it } from 'vitest'; +import { drizzle } from '~/planetscale-serverless'; +import { alias, boolean, int, mysqlSchema, mysqlTable, serial, text, union } from '~/mysql-core'; +import { asc, eq, sql } from '~/sql'; +import { Client } from '@planetscale/database'; + +const db = drizzle(new Client({}), { casing: 'camelCase' }); + +const testSchema = mysqlSchema('test'); +const users = mysqlTable('users', { + id: serial().primaryKey(), + first_name: text().notNull(), + last_name: text().notNull(), + // Test that custom aliases remain + age: int('AGE') +}); +const developers = testSchema.table('developers', { + user_id: serial().primaryKey().references(() => users.id), + uses_drizzle_orm: boolean().notNull(), +}); +const devs = alias(developers, 'devs'); + +const usersCache = { + 'public.users.id': 'id', + 'public.users.first_name': 'firstName', + 'public.users.last_name': 'lastName', + 'public.users.AGE': 'age', +}; +const developersCache = { + 'test.developers.user_id': 'userId', + 'test.developers.uses_drizzle_orm': 'usesDrizzleOrm', +}; +const cache = { + ...usersCache, + ...developersCache, +}; + +const fullName = sql`${users.first_name} || ' ' || ${users.last_name}`.as('name'); + +describe('mysql camel case to snake case ', () => { + beforeEach(() => { + db.dialect.casing.clearCache(); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with `cte` as (select `firstName` || \' \' || `lastName` as `name` from `users`) select `name` from `cte`', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with `cte` as (select `firstName` || \' \' || `lastName` as `name` from `users`) select `name` from `cte`', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator', ({ expect }) => { + const query = db + .select({ firstName: users.first_name }) + .from(users) + .union(db.select({ firstName: users.first_name }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: '(select `firstName` from `users`) union (select `firstName` from `users`)', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ firstName: users.first_name }).from(users), + db.select({ firstName: users.first_name }).from(users) + ); + + expect(query.toSQL()).toEqual({ + sql: '(select `firstName` from `users`) union (select `firstName` from `users`)', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.user_id)) + .orderBy(asc(users.first_name)); + + expect(query.toSQL()).toEqual({ + sql: 'select `users`.`firstName` || \' \' || `users`.`lastName` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`userId` order by `users`.`firstName` asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ firstName: users.first_name }) + .from(users) + .leftJoin(devs, eq(users.id, devs.user_id)); + + expect(query.toSQL()).toEqual({ + sql: 'select `users`.`firstName` from `users` left join `test`.`developers` `devs` on `users`.`id` = `devs`.`userId`', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('insert', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into `users` (`id`, `firstName`, `lastName`, `AGE`) values (default, ?, ?, ?)', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('insert (on duplicate key update)', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }) + .onDuplicateKeyUpdate({ set: { age: 31 } }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into `users` (`id`, `firstName`, `lastName`, `AGE`) values (default, ?, ?, ?) on duplicate key update `AGE` = ?', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ first_name: 'John', last_name: 'Doe', age: 30 }) + .where(eq(users.id, 1)); + + expect(query.toSQL()).toEqual({ + sql: 'update `users` set `firstName` = ?, `lastName` = ?, `AGE` = ? where `users`.`id` = ?', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)); + + expect(query.toSQL()).toEqual({ + sql: 'delete from `users` where `users`.`id` = ?', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); +}); diff --git a/drizzle-orm/tests/casing/mysql-to-snake.test.ts b/drizzle-orm/tests/casing/mysql-to-snake.test.ts new file mode 100644 index 000000000..cabac4001 --- /dev/null +++ b/drizzle-orm/tests/casing/mysql-to-snake.test.ts @@ -0,0 +1,169 @@ +import { beforeEach, describe, it } from 'vitest'; +import { drizzle } from '~/planetscale-serverless'; +import { alias, boolean, int, mysqlSchema, mysqlTable, serial, text, union } from '~/mysql-core'; +import { asc, eq, sql } from '~/sql'; +import { Client } from '@planetscale/database'; + +const db = drizzle(new Client({}), { casing: 'snake_case' }); + +const testSchema = mysqlSchema('test'); +const users = mysqlTable('users', { + id: serial().primaryKey(), + firstName: text().notNull(), + lastName: text().notNull(), + // Test that custom aliases remain + age: int('AGE') +}); +const developers = testSchema.table('developers', { + userId: serial().primaryKey().references(() => users.id), + usesDrizzleORM: boolean().notNull(), +}); +const devs = alias(developers, 'devs'); + +const usersCache = { + 'public.users.id': 'id', + 'public.users.firstName': 'first_name', + 'public.users.lastName': 'last_name', + 'public.users.AGE': 'age', +}; +const developersCache = { + 'test.developers.userId': 'user_id', + 'test.developers.usesDrizzleORM': 'uses_drizzle_orm', +}; +const cache = { + ...usersCache, + ...developersCache, +}; + +const fullName = sql`${users.firstName} || ' ' || ${users.lastName}`.as('name'); + +describe('mysql camel case to snake case ', () => { + beforeEach(() => { + db.dialect.casing.clearCache(); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with `cte` as (select `first_name` || \' \' || `last_name` as `name` from `users`) select `name` from `cte`', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with `cte` as (select `first_name` || \' \' || `last_name` as `name` from `users`) select `name` from `cte`', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .union(db.select({ firstName: users.firstName }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: '(select `first_name` from `users`) union (select `first_name` from `users`)', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ firstName: users.firstName }).from(users), + db.select({ firstName: users.firstName }).from(users) + ); + + expect(query.toSQL()).toEqual({ + sql: '(select `first_name` from `users`) union (select `first_name` from `users`)', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.userId)) + .orderBy(asc(users.firstName)); + + expect(query.toSQL()).toEqual({ + sql: 'select `users`.`first_name` || \' \' || `users`.`last_name` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`user_id` order by `users`.`first_name` asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .leftJoin(devs, eq(users.id, devs.userId)); + + expect(query.toSQL()).toEqual({ + sql: 'select `users`.`first_name` from `users` left join `test`.`developers` `devs` on `users`.`id` = `devs`.`user_id`', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('insert', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into `users` (`id`, `first_name`, `last_name`, `AGE`) values (default, ?, ?, ?)', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('insert (on duplicate key update)', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }) + .onDuplicateKeyUpdate({ set: { age: 31 } }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into `users` (`id`, `first_name`, `last_name`, `AGE`) values (default, ?, ?, ?) on duplicate key update `AGE` = ?', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ firstName: 'John', lastName: 'Doe', age: 30 }) + .where(eq(users.id, 1)); + + expect(query.toSQL()).toEqual({ + sql: 'update `users` set `first_name` = ?, `last_name` = ?, `AGE` = ? where `users`.`id` = ?', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)); + + expect(query.toSQL()).toEqual({ + sql: 'delete from `users` where `users`.`id` = ?', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); +}); From 27c77929a2595d5941d5b8d523bb6b41ea946def Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 26 Aug 2024 12:31:42 -0700 Subject: [PATCH 098/492] Update MySQL drivers config and init --- drizzle-orm/src/mysql-proxy/driver.ts | 2 +- drizzle-orm/src/mysql2/driver.ts | 2 +- drizzle-orm/src/tidb-serverless/driver.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/mysql-proxy/driver.ts b/drizzle-orm/src/mysql-proxy/driver.ts index 574db42c1..28e200856 100644 --- a/drizzle-orm/src/mysql-proxy/driver.ts +++ b/drizzle-orm/src/mysql-proxy/driver.ts @@ -24,7 +24,7 @@ export function drizzle = Record = {}, ): MySqlRemoteDatabase { - const dialect = new MySqlDialect(); + const dialect = new MySqlDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index 3b21bf11d..6516d9108 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -52,7 +52,7 @@ export function drizzle = Record = {}, ): MySql2Database { - const dialect = new MySqlDialect(); + const dialect = new MySqlDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/tidb-serverless/driver.ts b/drizzle-orm/src/tidb-serverless/driver.ts index bdd5324db..c79429600 100644 --- a/drizzle-orm/src/tidb-serverless/driver.ts +++ b/drizzle-orm/src/tidb-serverless/driver.ts @@ -25,7 +25,7 @@ export function drizzle = Record = {}, ): TiDBServerlessDatabase { - const dialect = new MySqlDialect(); + const dialect = new MySqlDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); From bd912ace3b6971aad9fb44b23378514f3025d46d Mon Sep 17 00:00:00 2001 From: Mario564 Date: Mon, 26 Aug 2024 12:34:53 -0700 Subject: [PATCH 099/492] Expose casing transformation functions --- drizzle-orm/src/casing.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drizzle-orm/src/casing.ts b/drizzle-orm/src/casing.ts index cac657080..73bfe0648 100644 --- a/drizzle-orm/src/casing.ts +++ b/drizzle-orm/src/casing.ts @@ -1,7 +1,6 @@ import { Table } from './table.ts'; import { Casing, entityKind, type Column } from './index.ts'; -/** @internal */ export function toSnakeCase(input: string) { const words = input .replace(/['\u2019]/g, '') @@ -10,7 +9,7 @@ export function toSnakeCase(input: string) { return words.map((word) => word.toLowerCase()).join('_'); } -/** @internal */ + export function toCamelCase(input: string) { const words = input .replace(/['\u2019]/g, '') From cd8ef2a04c1049c30eedd58dfc03e80baabd8137 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 27 Aug 2024 02:43:07 +0300 Subject: [PATCH 100/492] Complete runtime implementations [TO BE TESTED] --- drizzle-orm/src/monodriver.ts | 110 +++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 35 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index b6b48c91b..33c9bddbe 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,10 +1,11 @@ -/// import type { RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; import type { Config as LibsqlConfig } from '@libsql/client'; -import type { ClientConfig as NeonHttpConfig, PoolConfig as NeonServerlessConfig } from '@neondatabase/serverless'; +import type { + HTTPTransactionOptions as NeonHttpConfig, + PoolConfig as NeonServerlessConfig, +} from '@neondatabase/serverless'; import type { Config as PlanetscaleConfig } from '@planetscale/database'; import type { Config as TiDBServerlessConfig } from '@tidbcloud/serverless'; -import type { VercelPostgresPoolConfig as VercelPostgresConfig } from '@vercel/postgres'; import type { Options as BetterSQLite3Options } from 'better-sqlite3'; import type { ConnectionConfig as Mysql2Config } from 'mysql2'; import type { PoolConfig as NodePGPoolConfig } from 'pg'; @@ -14,7 +15,7 @@ import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; import type { DrizzleD1Database } from './d1/index.ts'; import type { LibSQLDatabase } from './libsql/index.ts'; -import type { MySql2Database } from './mysql2/index.ts'; +import type { MySql2Database, MySql2DrizzleConfig } from './mysql2/index.ts'; import type { NeonHttpDatabase } from './neon-http/index.ts'; import type { NeonDatabase } from './neon-serverless/index.ts'; import type { NodePgDatabase } from './node-postgres/index.ts'; @@ -57,6 +58,15 @@ type BetterSQLite3DatabaseConfig = { options?: BetterSQLite3Options; }; +type MonodriverMysql2Config = Mysql2Config & { + mode?: MySql2DrizzleConfig['mode']; +}; + +type MonodriverNeonHttpConfig = { + connectionString: string; + options?: NeonHttpConfig; +}; + type DatabaseClientType = | 'node-postgres' | 'postgres.js' @@ -76,11 +86,11 @@ type ClientConnectionConfigMap = { 'node-postgres': NodePGPoolConfig; 'postgres.js': PostgresJSOptions>; 'neon-serverless': NeonServerlessConfig; - 'neon-http': NeonHttpConfig; - 'vercel-postgres': VercelPostgresConfig; + 'neon-http': MonodriverNeonHttpConfig; + 'vercel-postgres': never; 'aws-data-api-pg': RDSConfig; planetscale: PlanetscaleConfig; - mysql2: Mysql2Config; + mysql2: MonodriverMysql2Config; 'tidb-serverless': TiDBServerlessConfig; libsql: LibsqlConfig; d1: D1Database; @@ -126,14 +136,14 @@ import { drizzle as betterSqliteDrizzle } from './better-sqlite3/index.ts'; import { drizzle as bunSqliteDrizzle } from './bun-sqlite/index.ts'; import { drizzle as d1Drizzle } from './d1/index.ts'; import { drizzle as libsqlDrizzle } from './libsql/index.ts'; -// import { drizzle as mysql2Drizzle } from './mysql2/index.ts'; -// import { drizzle as neonHttpDrizzle } from './neon-http/index.ts'; -// import { drizzle as neonDrizzle } from './neon-serverless/index.ts'; +import { drizzle as mysql2Drizzle } from './mysql2/index.ts'; +import { drizzle as neonHttpDrizzle } from './neon-http/index.ts'; +import { drizzle as neonDrizzle } from './neon-serverless/index.ts'; import { drizzle as pgDrizzle } from './node-postgres/index.ts'; -// import { drizzle as planetscaleDrizzle } from './planetscale-serverless/index.ts'; -// import { drizzle as postgresJSDrizzle } from './postgres-js/index.ts'; -// import { drizzle as tidbDrizzle } from './tidb-serverless/index.ts'; -// import { drizzle as vercelDrizzle } from './vercel-postgres/index.ts'; +import { drizzle as planetscaleDrizzle } from './planetscale-serverless/index.ts'; +import { drizzle as postgresJSDrizzle } from './postgres-js/index.ts'; +import { drizzle as tidbDrizzle } from './tidb-serverless/index.ts'; +import { drizzle as vercelDrizzle } from './vercel-postgres/index.ts'; export const drizzle = async < TClientType extends DatabaseClientType, @@ -141,11 +151,10 @@ export const drizzle = async < TParams extends InitializerParams, >(params: TParams): Promise> => { const { client, connection } = params; - const drizzleConfig = params as Omit; - // @ts-expect-error - delete drizzleConfig.client; - // @ts-expect-error - delete drizzleConfig.connection; + const drizzleConfig = { + logger: params.logger, + schema: params.schema, + }; switch (client) { case 'node-postgres': { @@ -183,22 +192,53 @@ export const drizzle = async < return libsqlDrizzle(instance, drizzleConfig) as any; } - // case 'mysql2': { - // } - // case 'neon-http': { - // } - // case 'neon-serverless': { - // } - // case 'planetscale': { - // } - // case 'postgres.js': { - // } - // case 'tidb-serverless': { - // } - // case 'vercel-postgres': { - // } + case 'mysql2': { + const { createConnection } = await import('mysql2/promise'); + const instance = await createConnection(connection as MonodriverMysql2Config); + const mode = (connection as MonodriverMysql2Config).mode ?? 'default'; + + return mysql2Drizzle(instance, { logger: params.logger, schema: params.schema, mode }) as any; + } + case 'neon-http': { + const { neon } = await import('@neondatabase/serverless'); + const { connectionString, options } = connection as MonodriverNeonHttpConfig; + const instance = neon(connectionString, options); + + return neonHttpDrizzle(instance, drizzleConfig) as any; + } + case 'neon-serverless': { + const { Pool } = await import('@neondatabase/serverless'); + const instance = new Pool(connection as NeonServerlessConfig); + + return neonDrizzle(instance, drizzleConfig) as any; + } + case 'planetscale': { + const { Client } = await import('@planetscale/database'); + const instance = new Client( + connection as PlanetscaleConfig, + ); + + return planetscaleDrizzle(instance, drizzleConfig) as any; + } + case 'postgres.js': { + const { default: client } = await import('postgres'); + const instance = client(connection as PostgresJSOptions>); + + return postgresJSDrizzle(instance, drizzleConfig) as any; + } + case 'tidb-serverless': { + const { connect } = await import('@tidbcloud/serverless'); + const instance = connect(connection as TiDBServerlessConfig); + + return tidbDrizzle(instance, drizzleConfig) as any; + } + case 'vercel-postgres': { + const { sql } = await import('@vercel/postgres'); + + return vercelDrizzle(sql, drizzleConfig) as any; + } } - // @ts-ignore - return {}; + // Shouldn't reach that point, but Typescript fails to infer that + return {} as any; }; From 3c128582c3b8c81a486d06214db9f92579628a5c Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 27 Aug 2024 13:09:28 +0300 Subject: [PATCH 101/492] Prototype implementation --- drizzle-orm/src/monodriver.ts | 160 ++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 75 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 33c9bddbe..6fe6de8a0 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -6,8 +6,9 @@ import type { } from '@neondatabase/serverless'; import type { Config as PlanetscaleConfig } from '@planetscale/database'; import type { Config as TiDBServerlessConfig } from '@tidbcloud/serverless'; +import type { VercelPool } from '@vercel/postgres'; import type { Options as BetterSQLite3Options } from 'better-sqlite3'; -import type { ConnectionConfig as Mysql2Config } from 'mysql2'; +import type { PoolOptions as Mysql2Config } from 'mysql2'; import type { PoolConfig as NodePGPoolConfig } from 'pg'; import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType } from 'postgres'; import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg/index.ts'; @@ -58,46 +59,11 @@ type BetterSQLite3DatabaseConfig = { options?: BetterSQLite3Options; }; -type MonodriverMysql2Config = Mysql2Config & { - mode?: MySql2DrizzleConfig['mode']; -}; - type MonodriverNeonHttpConfig = { connectionString: string; options?: NeonHttpConfig; }; -type DatabaseClientType = - | 'node-postgres' - | 'postgres.js' - | 'neon-serverless' - | 'neon-http' - | 'vercel-postgres' - | 'aws-data-api-pg' - | 'planetscale' - | 'mysql2' - | 'tidb-serverless' - | 'libsql' - | 'd1' - | 'bun-sqlite' - | 'better-sqlite3'; - -type ClientConnectionConfigMap = { - 'node-postgres': NodePGPoolConfig; - 'postgres.js': PostgresJSOptions>; - 'neon-serverless': NeonServerlessConfig; - 'neon-http': MonodriverNeonHttpConfig; - 'vercel-postgres': never; - 'aws-data-api-pg': RDSConfig; - planetscale: PlanetscaleConfig; - mysql2: MonodriverMysql2Config; - 'tidb-serverless': TiDBServerlessConfig; - libsql: LibsqlConfig; - d1: D1Database; - 'bun-sqlite': BunSqliteDatabaseConfig; - 'better-sqlite3': BetterSQLite3DatabaseConfig; -}; - type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; 'postgres.js': PostgresJsDatabase; @@ -106,7 +72,7 @@ type ClientDrizzleInstanceMap> = { 'vercel-postgres': VercelPgDatabase; 'aws-data-api-pg': AwsDataApiPgDatabase; planetscale: PlanetScaleDatabase; - mysql2: MySql2Database; + mysql2: Promise>; 'tidb-serverless': TiDBServerlessDatabase; libsql: LibSQLDatabase; d1: DrizzleD1Database; @@ -114,22 +80,65 @@ type ClientDrizzleInstanceMap> = { 'better-sqlite3': BetterSQLite3Database; }; -type ClientParams = ClientConnectionConfigMap[TClientType]; - type InitializerParams< - TClientType extends DatabaseClientType, TSchema extends Record = Record, -> = { - client: TClientType; - connection: ClientParams; -} & DrizzleConfig; +> = + | ({ + client: 'node-postgres'; + connection: NodePGPoolConfig; + } & DrizzleConfig) + | ({ + client: 'postgres.js'; + connection: PostgresJSOptions>; + } & DrizzleConfig) + | ({ + client: 'neon-serverless'; + connection: NeonServerlessConfig; + } & DrizzleConfig) + | ({ + client: 'neon-http'; + connection: MonodriverNeonHttpConfig; + } & DrizzleConfig) + | ({ + client: 'vercel-postgres'; + connection: VercelPool; + } & DrizzleConfig) + | ({ + client: 'aws-data-api-pg'; + connection: RDSConfig; + } & DrizzleAwsDataApiPgConfig) + | ({ + client: 'planetscale'; + connection: PlanetscaleConfig; + } & DrizzleConfig) + | ({ + client: 'mysql2'; + connection: Mysql2Config; + } & MySql2DrizzleConfig) + | ({ + client: 'tidb-serverless'; + connection: TiDBServerlessConfig; + } & DrizzleConfig) + | ({ + client: 'libsql'; + connection: LibsqlConfig; + } & DrizzleConfig) + | ({ + client: 'd1'; + connection: D1Database; + } & DrizzleConfig) + | ({ + client: 'bun-sqlite'; + connection: BunSqliteDatabaseConfig; + } & DrizzleConfig) + | ({ + client: 'better-sqlite3'; + connection: BetterSQLite3DatabaseConfig; + } & DrizzleConfig); type DetermineClient< - TParams extends InitializerParams, - TSchema extends Record = TParams extends { schema: Record } ? TParams['schema'] - : Record, -> = TParams extends { client: DatabaseClientType } ? ClientDrizzleInstanceMap[TParams['client']] - : never; + TParams extends InitializerParams, +> = ClientDrizzleInstanceMap[TParams['client']]; import { drizzle as rdsPgDrizzle } from './aws-data-api/pg/index.ts'; import { drizzle as betterSqliteDrizzle } from './better-sqlite3/index.ts'; @@ -145,39 +154,37 @@ import { drizzle as postgresJSDrizzle } from './postgres-js/index.ts'; import { drizzle as tidbDrizzle } from './tidb-serverless/index.ts'; import { drizzle as vercelDrizzle } from './vercel-postgres/index.ts'; -export const drizzle = async < - TClientType extends DatabaseClientType, +export const drizzle = < TSchema extends Record, - TParams extends InitializerParams, + TParams extends InitializerParams, >(params: TParams): Promise> => { const { client, connection } = params; - const drizzleConfig = { - logger: params.logger, - schema: params.schema, - }; + const drizzleConfig = params as DrizzleConfig; + delete ( drizzleConfig).client; + delete ( drizzleConfig).connection; switch (client) { case 'node-postgres': { - const { Pool } = await import('pg'); + const { Pool } = require('pg') as typeof import('pg'); const instance = new Pool(connection as NodePGPoolConfig); return pgDrizzle(instance, drizzleConfig) as any; } case 'aws-data-api-pg': { - const { RDSDataClient } = await import('@aws-sdk/client-rds-data'); + const { RDSDataClient } = require('@aws-sdk/client-rds-data') as typeof import('@aws-sdk/client-rds-data'); const instance = new RDSDataClient(connection); return rdsPgDrizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } case 'better-sqlite3': { - const { default: Client } = await import('better-sqlite3'); + const Client = require('better-sqlite3') as typeof import('better-sqlite3'); const { filename, options } = connection as BetterSQLite3DatabaseConfig; const instance = new Client(filename, options); return betterSqliteDrizzle(instance, drizzleConfig) as any; } case 'bun-sqlite': { - const { Database: Client } = await import('bun:sqlite'); + const { Database: Client } = require('bun:sqlite') as typeof import('bun:sqlite'); const { filename, options } = connection as BunSqliteDatabaseConfig; const instance = new Client(filename, options); @@ -187,33 +194,39 @@ export const drizzle = async < return d1Drizzle(connection as D1Database, drizzleConfig) as any; } case 'libsql': { - const { createClient } = await import('@libsql/client'); + const { createClient } = require('@libsql/client') as typeof import('@libsql/client'); const instance = createClient(connection as LibsqlConfig); return libsqlDrizzle(instance, drizzleConfig) as any; } case 'mysql2': { - const { createConnection } = await import('mysql2/promise'); - const instance = await createConnection(connection as MonodriverMysql2Config); - const mode = (connection as MonodriverMysql2Config).mode ?? 'default'; - - return mysql2Drizzle(instance, { logger: params.logger, schema: params.schema, mode }) as any; + const { createConnection } = require('mysql2/promise') as typeof import('mysql2/promise'); + + return new Promise((res, rej) => { + createConnection(connection as Mysql2Config).then((instance) => { + try { + res(mysql2Drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any); + } catch (e) { + rej(e); + } + }).catch((e) => rej(e)); + }); } case 'neon-http': { - const { neon } = await import('@neondatabase/serverless'); + const { neon } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); const { connectionString, options } = connection as MonodriverNeonHttpConfig; const instance = neon(connectionString, options); return neonHttpDrizzle(instance, drizzleConfig) as any; } case 'neon-serverless': { - const { Pool } = await import('@neondatabase/serverless'); + const { Pool } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); const instance = new Pool(connection as NeonServerlessConfig); return neonDrizzle(instance, drizzleConfig) as any; } case 'planetscale': { - const { Client } = await import('@planetscale/database'); + const { Client } = require('@planetscale/database') as typeof import('@planetscale/database'); const instance = new Client( connection as PlanetscaleConfig, ); @@ -221,24 +234,21 @@ export const drizzle = async < return planetscaleDrizzle(instance, drizzleConfig) as any; } case 'postgres.js': { - const { default: client } = await import('postgres'); + const client = require('postgres') as typeof import('postgres'); const instance = client(connection as PostgresJSOptions>); return postgresJSDrizzle(instance, drizzleConfig) as any; } case 'tidb-serverless': { - const { connect } = await import('@tidbcloud/serverless'); + const { connect } = require('@tidbcloud/serverless') as typeof import('@tidbcloud/serverless'); const instance = connect(connection as TiDBServerlessConfig); return tidbDrizzle(instance, drizzleConfig) as any; } case 'vercel-postgres': { - const { sql } = await import('@vercel/postgres'); + const { sql } = require('@vercel/postgres') as typeof import('@vercel/postgres'); return vercelDrizzle(sql, drizzleConfig) as any; } } - - // Shouldn't reach that point, but Typescript fails to infer that - return {} as any; }; From 25af8ee924cf58087c6de7479f1630bd93d55dcf Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 27 Aug 2024 14:25:50 +0300 Subject: [PATCH 102/492] switched bun to dynamic imports --- drizzle-orm/src/monodriver.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 6fe6de8a0..50106e4e9 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -76,7 +76,7 @@ type ClientDrizzleInstanceMap> = { 'tidb-serverless': TiDBServerlessDatabase; libsql: LibSQLDatabase; d1: DrizzleD1Database; - 'bun-sqlite': BunSQLiteDatabase; + 'bun-sqlite': Promise>; 'better-sqlite3': BetterSQLite3Database; }; @@ -184,11 +184,18 @@ export const drizzle = < return betterSqliteDrizzle(instance, drizzleConfig) as any; } case 'bun-sqlite': { - const { Database: Client } = require('bun:sqlite') as typeof import('bun:sqlite'); - const { filename, options } = connection as BunSqliteDatabaseConfig; - const instance = new Client(filename, options); + return new Promise((res, rej) => { + import('bun:sqlite').then(({ Database: Client }) => { + try { + const { filename, options } = connection as BunSqliteDatabaseConfig; + const instance = new Client(filename, options); - return bunSqliteDrizzle(instance, drizzleConfig) as any; + res(bunSqliteDrizzle(instance, drizzleConfig) as any); + } catch (e) { + rej(e); + } + }).catch((e) => rej(e)); + }); } case 'd1': { return d1Drizzle(connection as D1Database, drizzleConfig) as any; From 766f76f386ac6ab3ef12f8369e0dc9d8c3fa2008 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 27 Aug 2024 15:50:03 +0300 Subject: [PATCH 103/492] Removed static imports, removed promise wrapper --- drizzle-orm/src/monodriver.ts | 66 +++++++++++++++++------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 50106e4e9..81e7b7396 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,3 +1,4 @@ +/* eslint-disable import/extensions */ import type { RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; import type { Config as LibsqlConfig } from '@libsql/client'; import type { @@ -66,7 +67,7 @@ type MonodriverNeonHttpConfig = { type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; - 'postgres.js': PostgresJsDatabase; + 'postgres-js': PostgresJsDatabase; 'neon-serverless': NeonDatabase; 'neon-http': NeonHttpDatabase; 'vercel-postgres': VercelPgDatabase; @@ -88,7 +89,7 @@ type InitializerParams< connection: NodePGPoolConfig; } & DrizzleConfig) | ({ - client: 'postgres.js'; + client: 'postgres-js'; connection: PostgresJSOptions>; } & DrizzleConfig) | ({ @@ -140,24 +141,10 @@ type DetermineClient< TParams extends InitializerParams, > = ClientDrizzleInstanceMap[TParams['client']]; -import { drizzle as rdsPgDrizzle } from './aws-data-api/pg/index.ts'; -import { drizzle as betterSqliteDrizzle } from './better-sqlite3/index.ts'; -import { drizzle as bunSqliteDrizzle } from './bun-sqlite/index.ts'; -import { drizzle as d1Drizzle } from './d1/index.ts'; -import { drizzle as libsqlDrizzle } from './libsql/index.ts'; -import { drizzle as mysql2Drizzle } from './mysql2/index.ts'; -import { drizzle as neonHttpDrizzle } from './neon-http/index.ts'; -import { drizzle as neonDrizzle } from './neon-serverless/index.ts'; -import { drizzle as pgDrizzle } from './node-postgres/index.ts'; -import { drizzle as planetscaleDrizzle } from './planetscale-serverless/index.ts'; -import { drizzle as postgresJSDrizzle } from './postgres-js/index.ts'; -import { drizzle as tidbDrizzle } from './tidb-serverless/index.ts'; -import { drizzle as vercelDrizzle } from './vercel-postgres/index.ts'; - export const drizzle = < TSchema extends Record, TParams extends InitializerParams, ->(params: TParams): Promise> => { +>(params: TParams): DetermineClient => { const { client, connection } = params; const drizzleConfig = params as DrizzleConfig; delete ( drizzleConfig).client; @@ -166,45 +153,51 @@ export const drizzle = < switch (client) { case 'node-postgres': { const { Pool } = require('pg') as typeof import('pg'); + const { drizzle } = require('./node-postgres') as typeof import('./node-postgres'); const instance = new Pool(connection as NodePGPoolConfig); - return pgDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'aws-data-api-pg': { const { RDSDataClient } = require('@aws-sdk/client-rds-data') as typeof import('@aws-sdk/client-rds-data'); + const { drizzle } = require('./aws-data-api/pg') as typeof import('./aws-data-api/pg'); const instance = new RDSDataClient(connection); - return rdsPgDrizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; + return drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } case 'better-sqlite3': { const Client = require('better-sqlite3') as typeof import('better-sqlite3'); const { filename, options } = connection as BetterSQLite3DatabaseConfig; + const { drizzle } = require('./better-sqlite3') as typeof import('./better-sqlite3'); const instance = new Client(filename, options); - return betterSqliteDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'bun-sqlite': { return new Promise((res, rej) => { import('bun:sqlite').then(({ Database: Client }) => { try { const { filename, options } = connection as BunSqliteDatabaseConfig; + const { drizzle } = require('./bun-sqlite') as typeof import('./bun-sqlite'); const instance = new Client(filename, options); - res(bunSqliteDrizzle(instance, drizzleConfig) as any); + res(drizzle(instance, drizzleConfig) as any); } catch (e) { rej(e); } }).catch((e) => rej(e)); - }); + }) as any; } case 'd1': { - return d1Drizzle(connection as D1Database, drizzleConfig) as any; + const { drizzle } = require('./d1') as typeof import('./d1'); + return drizzle(connection as D1Database, drizzleConfig) as any; } case 'libsql': { const { createClient } = require('@libsql/client') as typeof import('@libsql/client'); + const { drizzle } = require('./libsql') as typeof import('./libsql'); const instance = createClient(connection as LibsqlConfig); - return libsqlDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'mysql2': { const { createConnection } = require('mysql2/promise') as typeof import('mysql2/promise'); @@ -212,50 +205,57 @@ export const drizzle = < return new Promise((res, rej) => { createConnection(connection as Mysql2Config).then((instance) => { try { - res(mysql2Drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any); + const { drizzle } = require('./mysql2') as typeof import('./mysql2'); + res(drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any); } catch (e) { rej(e); } }).catch((e) => rej(e)); - }); + }) as any; } case 'neon-http': { const { neon } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); const { connectionString, options } = connection as MonodriverNeonHttpConfig; + const { drizzle } = require('./neon-http') as typeof import('./neon-http'); const instance = neon(connectionString, options); - return neonHttpDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'neon-serverless': { const { Pool } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); + const { drizzle } = require('./neon-serverless') as typeof import('./neon-serverless'); const instance = new Pool(connection as NeonServerlessConfig); - return neonDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'planetscale': { const { Client } = require('@planetscale/database') as typeof import('@planetscale/database'); + const { drizzle } = require('./planetscale-serverless') as typeof import('./planetscale-serverless'); const instance = new Client( connection as PlanetscaleConfig, ); - return planetscaleDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } - case 'postgres.js': { + case 'postgres-js': { const client = require('postgres') as typeof import('postgres'); + const { drizzle } = require('./postgres-js') as typeof import('./postgres-js'); const instance = client(connection as PostgresJSOptions>); - return postgresJSDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'tidb-serverless': { const { connect } = require('@tidbcloud/serverless') as typeof import('@tidbcloud/serverless'); + const { drizzle } = require('./tidb-serverless') as typeof import('./tidb-serverless'); const instance = connect(connection as TiDBServerlessConfig); - return tidbDrizzle(instance, drizzleConfig) as any; + return drizzle(instance, drizzleConfig) as any; } case 'vercel-postgres': { const { sql } = require('@vercel/postgres') as typeof import('@vercel/postgres'); + const { drizzle } = require('./vercel-postgres') as typeof import('./vercel-postgres'); - return vercelDrizzle(sql, drizzleConfig) as any; + return drizzle(sql, drizzleConfig) as any; } } }; From 9140d23108c0c7159ed1d910e995b6e2c0e952f1 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 27 Aug 2024 16:33:41 +0300 Subject: [PATCH 104/492] Returned async imports due to conflicts --- drizzle-orm/src/monodriver.ts | 82 +++++++++++++++-------------------- 1 file changed, 34 insertions(+), 48 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 81e7b7396..8729ec92d 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -73,11 +73,11 @@ type ClientDrizzleInstanceMap> = { 'vercel-postgres': VercelPgDatabase; 'aws-data-api-pg': AwsDataApiPgDatabase; planetscale: PlanetScaleDatabase; - mysql2: Promise>; + mysql2: MySql2Database; 'tidb-serverless': TiDBServerlessDatabase; libsql: LibSQLDatabase; d1: DrizzleD1Database; - 'bun-sqlite': Promise>; + 'bun-sqlite': BunSQLiteDatabase; 'better-sqlite3': BetterSQLite3Database; }; @@ -141,10 +141,10 @@ type DetermineClient< TParams extends InitializerParams, > = ClientDrizzleInstanceMap[TParams['client']]; -export const drizzle = < +export const drizzle = async < TSchema extends Record, TParams extends InitializerParams, ->(params: TParams): DetermineClient => { +>(params: TParams): Promise> => { const { client, connection } = params; const drizzleConfig = params as DrizzleConfig; delete ( drizzleConfig).client; @@ -152,85 +152,71 @@ export const drizzle = < switch (client) { case 'node-postgres': { - const { Pool } = require('pg') as typeof import('pg'); - const { drizzle } = require('./node-postgres') as typeof import('./node-postgres'); + const { Pool } = await import('pg'); + const { drizzle } = await import('./node-postgres'); const instance = new Pool(connection as NodePGPoolConfig); return drizzle(instance, drizzleConfig) as any; } case 'aws-data-api-pg': { - const { RDSDataClient } = require('@aws-sdk/client-rds-data') as typeof import('@aws-sdk/client-rds-data'); - const { drizzle } = require('./aws-data-api/pg') as typeof import('./aws-data-api/pg'); + const { RDSDataClient } = await import('@aws-sdk/client-rds-data'); + const { drizzle } = await import('./aws-data-api/pg'); const instance = new RDSDataClient(connection); return drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } case 'better-sqlite3': { - const Client = require('better-sqlite3') as typeof import('better-sqlite3'); + const { default: Client } = await import('better-sqlite3'); const { filename, options } = connection as BetterSQLite3DatabaseConfig; - const { drizzle } = require('./better-sqlite3') as typeof import('./better-sqlite3'); + const { drizzle } = await import('./better-sqlite3'); const instance = new Client(filename, options); return drizzle(instance, drizzleConfig) as any; } case 'bun-sqlite': { - return new Promise((res, rej) => { - import('bun:sqlite').then(({ Database: Client }) => { - try { - const { filename, options } = connection as BunSqliteDatabaseConfig; - const { drizzle } = require('./bun-sqlite') as typeof import('./bun-sqlite'); - const instance = new Client(filename, options); + const { Database: Client } = await import('bun:sqlite'); + const { filename, options } = connection as BunSqliteDatabaseConfig; + const { drizzle } = await import('./bun-sqlite'); + const instance = new Client(filename, options); - res(drizzle(instance, drizzleConfig) as any); - } catch (e) { - rej(e); - } - }).catch((e) => rej(e)); - }) as any; + return drizzle(instance, drizzleConfig) as any; } case 'd1': { - const { drizzle } = require('./d1') as typeof import('./d1'); + const { drizzle } = await import('./d1'); return drizzle(connection as D1Database, drizzleConfig) as any; } case 'libsql': { - const { createClient } = require('@libsql/client') as typeof import('@libsql/client'); - const { drizzle } = require('./libsql') as typeof import('./libsql'); + const { createClient } = await import('@libsql/client'); + const { drizzle } = await import('./libsql'); const instance = createClient(connection as LibsqlConfig); return drizzle(instance, drizzleConfig) as any; } case 'mysql2': { - const { createConnection } = require('mysql2/promise') as typeof import('mysql2/promise'); + const { createConnection } = await import('mysql2/promise'); + const instance = await createConnection(connection as Mysql2Config); + const { drizzle } = await import('./mysql2'); - return new Promise((res, rej) => { - createConnection(connection as Mysql2Config).then((instance) => { - try { - const { drizzle } = require('./mysql2') as typeof import('./mysql2'); - res(drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any); - } catch (e) { - rej(e); - } - }).catch((e) => rej(e)); - }) as any; + return drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any; } case 'neon-http': { - const { neon } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); + const { neon } = await import('@neondatabase/serverless'); const { connectionString, options } = connection as MonodriverNeonHttpConfig; - const { drizzle } = require('./neon-http') as typeof import('./neon-http'); + const { drizzle } = await import('./neon-http'); const instance = neon(connectionString, options); return drizzle(instance, drizzleConfig) as any; } case 'neon-serverless': { - const { Pool } = require('@neondatabase/serverless') as typeof import('@neondatabase/serverless'); - const { drizzle } = require('./neon-serverless') as typeof import('./neon-serverless'); + const { Pool } = await import('@neondatabase/serverless'); + const { drizzle } = await import('./neon-serverless'); const instance = new Pool(connection as NeonServerlessConfig); return drizzle(instance, drizzleConfig) as any; } case 'planetscale': { - const { Client } = require('@planetscale/database') as typeof import('@planetscale/database'); - const { drizzle } = require('./planetscale-serverless') as typeof import('./planetscale-serverless'); + const { Client } = await import('@planetscale/database'); + const { drizzle } = await import('./planetscale-serverless'); const instance = new Client( connection as PlanetscaleConfig, ); @@ -238,22 +224,22 @@ export const drizzle = < return drizzle(instance, drizzleConfig) as any; } case 'postgres-js': { - const client = require('postgres') as typeof import('postgres'); - const { drizzle } = require('./postgres-js') as typeof import('./postgres-js'); + const { default: client } = await import('postgres'); + const { drizzle } = await import('./postgres-js'); const instance = client(connection as PostgresJSOptions>); return drizzle(instance, drizzleConfig) as any; } case 'tidb-serverless': { - const { connect } = require('@tidbcloud/serverless') as typeof import('@tidbcloud/serverless'); - const { drizzle } = require('./tidb-serverless') as typeof import('./tidb-serverless'); + const { connect } = await import('@tidbcloud/serverless'); + const { drizzle } = await import('./tidb-serverless'); const instance = connect(connection as TiDBServerlessConfig); return drizzle(instance, drizzleConfig) as any; } case 'vercel-postgres': { - const { sql } = require('@vercel/postgres') as typeof import('@vercel/postgres'); - const { drizzle } = require('./vercel-postgres') as typeof import('./vercel-postgres'); + const { sql } = await import('@vercel/postgres'); + const { drizzle } = await import('./vercel-postgres'); return drizzle(sql, drizzleConfig) as any; } From 8db0aa4364da81110e50c6bf48efe8af49bf4c15 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 27 Aug 2024 18:16:08 +0300 Subject: [PATCH 105/492] More comnprehensive import errors --- drizzle-orm/src/monodriver.ts | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 8729ec92d..2f9557b01 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -141,6 +141,12 @@ type DetermineClient< TParams extends InitializerParams, > = ClientDrizzleInstanceMap[TParams['client']]; +const importError = (libName: string) => { + throw new Error( + `Drizzle init error: unable to import selected database driver library '${libName}' - make sure it is installed.`, + ); +}; + export const drizzle = async < TSchema extends Record, TParams extends InitializerParams, @@ -152,21 +158,23 @@ export const drizzle = async < switch (client) { case 'node-postgres': { - const { Pool } = await import('pg'); + const { Pool } = await import('pg').catch(() => importError('pg')); const { drizzle } = await import('./node-postgres'); const instance = new Pool(connection as NodePGPoolConfig); return drizzle(instance, drizzleConfig) as any; } case 'aws-data-api-pg': { - const { RDSDataClient } = await import('@aws-sdk/client-rds-data'); + const { RDSDataClient } = await import('@aws-sdk/client-rds-data').catch(() => + importError('@aws-sdk/client-rds-data') + ); const { drizzle } = await import('./aws-data-api/pg'); const instance = new RDSDataClient(connection); return drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } case 'better-sqlite3': { - const { default: Client } = await import('better-sqlite3'); + const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); const { filename, options } = connection as BetterSQLite3DatabaseConfig; const { drizzle } = await import('./better-sqlite3'); const instance = new Client(filename, options); @@ -174,7 +182,7 @@ export const drizzle = async < return drizzle(instance, drizzleConfig) as any; } case 'bun-sqlite': { - const { Database: Client } = await import('bun:sqlite'); + const { Database: Client } = await import('bun:sqlite').catch(() => importError('bun:sqlite')); const { filename, options } = connection as BunSqliteDatabaseConfig; const { drizzle } = await import('./bun-sqlite'); const instance = new Client(filename, options); @@ -186,21 +194,21 @@ export const drizzle = async < return drizzle(connection as D1Database, drizzleConfig) as any; } case 'libsql': { - const { createClient } = await import('@libsql/client'); + const { createClient } = await import('@libsql/client').catch(() => importError('@libsql/client')); const { drizzle } = await import('./libsql'); const instance = createClient(connection as LibsqlConfig); return drizzle(instance, drizzleConfig) as any; } case 'mysql2': { - const { createConnection } = await import('mysql2/promise'); + const { createConnection } = await import('mysql2/promise').catch(() => importError('mysql2/promise')); const instance = await createConnection(connection as Mysql2Config); const { drizzle } = await import('./mysql2'); return drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any; } case 'neon-http': { - const { neon } = await import('@neondatabase/serverless'); + const { neon } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); const { connectionString, options } = connection as MonodriverNeonHttpConfig; const { drizzle } = await import('./neon-http'); const instance = neon(connectionString, options); @@ -208,14 +216,14 @@ export const drizzle = async < return drizzle(instance, drizzleConfig) as any; } case 'neon-serverless': { - const { Pool } = await import('@neondatabase/serverless'); + const { Pool } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); const { drizzle } = await import('./neon-serverless'); const instance = new Pool(connection as NeonServerlessConfig); return drizzle(instance, drizzleConfig) as any; } case 'planetscale': { - const { Client } = await import('@planetscale/database'); + const { Client } = await import('@planetscale/database').catch(() => importError('@planetscale/database')); const { drizzle } = await import('./planetscale-serverless'); const instance = new Client( connection as PlanetscaleConfig, @@ -224,21 +232,21 @@ export const drizzle = async < return drizzle(instance, drizzleConfig) as any; } case 'postgres-js': { - const { default: client } = await import('postgres'); + const { default: client } = await import('postgres').catch(() => importError('postgres')); const { drizzle } = await import('./postgres-js'); const instance = client(connection as PostgresJSOptions>); return drizzle(instance, drizzleConfig) as any; } case 'tidb-serverless': { - const { connect } = await import('@tidbcloud/serverless'); + const { connect } = await import('@tidbcloud/serverless').catch(() => importError('@tidbcloud/serverless')); const { drizzle } = await import('./tidb-serverless'); const instance = connect(connection as TiDBServerlessConfig); return drizzle(instance, drizzleConfig) as any; } case 'vercel-postgres': { - const { sql } = await import('@vercel/postgres'); + const { sql } = await import('@vercel/postgres').catch(() => importError('@vercel/postgres')); const { drizzle } = await import('./vercel-postgres'); return drizzle(sql, drizzleConfig) as any; From 6b8833ea7ae38d203ef5772bac228e0cdebe7210 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 27 Aug 2024 12:43:13 -0700 Subject: [PATCH 106/492] Add additional MySQL and PG tests --- drizzle-orm/src/casing.ts | 1 - drizzle-orm/src/mysql-core/dialect.ts | 2 +- .../tests/casing/mysql-to-camel.test.ts | 159 ++++++++++++++++-- .../tests/casing/mysql-to-snake.test.ts | 159 ++++++++++++++++-- drizzle-orm/tests/casing/pg-to-camel.test.ts | 99 +++++++++-- drizzle-orm/tests/casing/pg-to-snake.test.ts | 99 +++++++++-- 6 files changed, 447 insertions(+), 72 deletions(-) diff --git a/drizzle-orm/src/casing.ts b/drizzle-orm/src/casing.ts index 73bfe0648..b14fa3fa0 100644 --- a/drizzle-orm/src/casing.ts +++ b/drizzle-orm/src/casing.ts @@ -9,7 +9,6 @@ export function toSnakeCase(input: string) { return words.map((word) => word.toLowerCase()).join('_'); } - export function toCamelCase(input: string) { const words = input .replace(/['\u2019]/g, '') diff --git a/drizzle-orm/src/mysql-core/dialect.ts b/drizzle-orm/src/mysql-core/dialect.ts index f2deef49a..a067ca394 100644 --- a/drizzle-orm/src/mysql-core/dialect.ts +++ b/drizzle-orm/src/mysql-core/dialect.ts @@ -1003,7 +1003,7 @@ export class MySqlDialect { let field = sql`json_array(${ sql.join( selection.map(({ field }) => - is(field, MySqlColumn) ? sql.identifier(field.name) : is(field, SQL.Aliased) ? field.sql : field + is(field, MySqlColumn) ? sql.identifier(this.casing.getColumnCasing(field)) : is(field, SQL.Aliased) ? field.sql : field ), sql`, `, ) diff --git a/drizzle-orm/tests/casing/mysql-to-camel.test.ts b/drizzle-orm/tests/casing/mysql-to-camel.test.ts index 2f8a0d810..6c30c3a5d 100644 --- a/drizzle-orm/tests/casing/mysql-to-camel.test.ts +++ b/drizzle-orm/tests/casing/mysql-to-camel.test.ts @@ -1,10 +1,11 @@ import { beforeEach, describe, it } from 'vitest'; -import { drizzle } from '~/planetscale-serverless'; +import { drizzle as planetscale } from '~/planetscale-serverless'; +import { drizzle as mysql } from '~/tidb-serverless'; import { alias, boolean, int, mysqlSchema, mysqlTable, serial, text, union } from '~/mysql-core'; import { asc, eq, sql } from '~/sql'; +import { relations } from '~/relations'; import { Client } from '@planetscale/database'; - -const db = drizzle(new Client({}), { casing: 'camelCase' }); +import { connect } from '@tidbcloud/serverless'; const testSchema = mysqlSchema('test'); const users = mysqlTable('users', { @@ -14,11 +15,24 @@ const users = mysqlTable('users', { // Test that custom aliases remain age: int('AGE') }); +const usersRelations = relations(users, ({ one }) => ({ + developers: one(developers), +})); const developers = testSchema.table('developers', { user_id: serial().primaryKey().references(() => users.id), uses_drizzle_orm: boolean().notNull(), }); +const developersRelations = relations(developers, ({ one }) => ({ + user: one(users, { + fields: [developers.user_id], + references: [users.id], + }), +})); const devs = alias(developers, 'devs'); +const schema = { users, usersRelations, developers, developersRelations }; + +const db = mysql(connect({}), { schema, casing: 'camelCase' }); +const ps = planetscale(new Client({}), { schema, casing: 'camelCase' }); const usersCache = { 'public.users.id': 'id', @@ -39,9 +53,37 @@ const fullName = sql`${users.first_name} || ' ' || ${users.last_name}`.as('name' describe('mysql camel case to snake case ', () => { beforeEach(() => { + ps.dialect.casing.clearCache(); db.dialect.casing.clearCache(); }); + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.user_id)) + .orderBy(asc(users.first_name)); + + expect(query.toSQL()).toEqual({ + sql: 'select `users`.`firstName` || \' \' || `users`.`lastName` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`userId` order by `users`.`firstName` asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ firstName: users.first_name }) + .from(users) + .leftJoin(devs, eq(users.id, devs.user_id)); + + expect(query.toSQL()).toEqual({ + sql: 'select `users`.`firstName` from `users` left join `test`.`developers` `devs` on `users`.`id` = `devs`.`userId`', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + it('with CTE', ({ expect }) => { const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); const query = db.with(cte).select().from(cte); @@ -90,33 +132,114 @@ describe('mysql camel case to snake case ', () => { expect(db.dialect.casing.cache).toEqual(usersCache); }); - it('select', ({ expect }) => { - const query = db - .select({ name: fullName, age: users.age }) - .from(users) - .leftJoin(developers, eq(users.id, developers.user_id)) - .orderBy(asc(users.first_name)); + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true + } + } + } + }); expect(query.toSQL()).toEqual({ - sql: 'select `users`.`firstName` || \' \' || `users`.`lastName` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`userId` order by `users`.`firstName` asc', - params: [], + sql: 'select `users`.`id`, `users`.`AGE`, `users`.`firstName` || \' \' || `users`.`lastName` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`usesDrizzleOrm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ? limit ?', + params: [1, 1, 1], + typings: ['none', 'none', 'none'] }); expect(db.dialect.casing.cache).toEqual(cache); }); - it('select (with alias)', ({ expect }) => { - const query = db - .select({ firstName: users.first_name }) - .from(users) - .leftJoin(devs, eq(users.id, devs.user_id)); + it('query (find first, planetscale)', ({ expect }) => { + const query = ps.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true + } + } + } + }); expect(query.toSQL()).toEqual({ - sql: 'select `users`.`firstName` from `users` left join `test`.`developers` `devs` on `users`.`id` = `devs`.`userId`', - params: [], + sql: 'select `id`, `AGE`, `firstName` || \' \' || `lastName` as `name`, (select json_array(`usesDrizzleOrm`) from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ? limit ?', + params: [1, 1, 1], + typings: ['none', 'none', 'none'] + }); + expect(ps.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true + } + } + } + }); + + expect(query.toSQL()).toEqual({ + sql: 'select `users`.`id`, `users`.`AGE`, `users`.`firstName` || \' \' || `users`.`lastName` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`usesDrizzleOrm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ?', + params: [1, 1], + typings: ['none', 'none'] }); expect(db.dialect.casing.cache).toEqual(cache); }); + it('query (find many, planetscale)', ({ expect }) => { + const query = ps.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true + } + } + } + }); + + expect(query.toSQL()).toEqual({ + sql: 'select `id`, `AGE`, `firstName` || \' \' || `lastName` as `name`, (select json_array(`usesDrizzleOrm`) from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ?', + params: [1, 1], + typings: ['none', 'none'] + }); + expect(ps.dialect.casing.cache).toEqual(cache); + }); + it('insert', ({ expect }) => { const query = db .insert(users) diff --git a/drizzle-orm/tests/casing/mysql-to-snake.test.ts b/drizzle-orm/tests/casing/mysql-to-snake.test.ts index cabac4001..c54c9f2bf 100644 --- a/drizzle-orm/tests/casing/mysql-to-snake.test.ts +++ b/drizzle-orm/tests/casing/mysql-to-snake.test.ts @@ -1,10 +1,11 @@ import { beforeEach, describe, it } from 'vitest'; -import { drizzle } from '~/planetscale-serverless'; +import { drizzle as planetscale } from '~/planetscale-serverless'; +import { drizzle as mysql } from '~/tidb-serverless'; import { alias, boolean, int, mysqlSchema, mysqlTable, serial, text, union } from '~/mysql-core'; import { asc, eq, sql } from '~/sql'; +import { relations } from '~/relations'; import { Client } from '@planetscale/database'; - -const db = drizzle(new Client({}), { casing: 'snake_case' }); +import { connect } from '@tidbcloud/serverless'; const testSchema = mysqlSchema('test'); const users = mysqlTable('users', { @@ -14,11 +15,24 @@ const users = mysqlTable('users', { // Test that custom aliases remain age: int('AGE') }); +const usersRelations = relations(users, ({ one }) => ({ + developers: one(developers), +})); const developers = testSchema.table('developers', { userId: serial().primaryKey().references(() => users.id), usesDrizzleORM: boolean().notNull(), }); +const developersRelations = relations(developers, ({ one }) => ({ + user: one(users, { + fields: [developers.userId], + references: [users.id], + }), +})); const devs = alias(developers, 'devs'); +const schema = { users, usersRelations, developers, developersRelations }; + +const db = mysql(connect({}), { schema, casing: 'snake_case' }); +const ps = planetscale(new Client({}), { schema, casing: 'snake_case' }); const usersCache = { 'public.users.id': 'id', @@ -40,6 +54,34 @@ const fullName = sql`${users.firstName} || ' ' || ${users.lastName}`.as('name'); describe('mysql camel case to snake case ', () => { beforeEach(() => { db.dialect.casing.clearCache(); + ps.dialect.casing.clearCache(); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.userId)) + .orderBy(asc(users.firstName)); + + expect(query.toSQL()).toEqual({ + sql: 'select `users`.`first_name` || \' \' || `users`.`last_name` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`user_id` order by `users`.`first_name` asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .leftJoin(devs, eq(users.id, devs.userId)); + + expect(query.toSQL()).toEqual({ + sql: 'select `users`.`first_name` from `users` left join `test`.`developers` `devs` on `users`.`id` = `devs`.`user_id`', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); }); it('with CTE', ({ expect }) => { @@ -90,33 +132,114 @@ describe('mysql camel case to snake case ', () => { expect(db.dialect.casing.cache).toEqual(usersCache); }); - it('select', ({ expect }) => { - const query = db - .select({ name: fullName, age: users.age }) - .from(users) - .leftJoin(developers, eq(users.id, developers.userId)) - .orderBy(asc(users.firstName)); + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true + } + } + } + }); expect(query.toSQL()).toEqual({ - sql: 'select `users`.`first_name` || \' \' || `users`.`last_name` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`user_id` order by `users`.`first_name` asc', - params: [], + sql: 'select `users`.`id`, `users`.`AGE`, `users`.`first_name` || \' \' || `users`.`last_name` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`uses_drizzle_orm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ? limit ?', + params: [1, 1, 1], + typings: ['none', 'none', 'none'] }); expect(db.dialect.casing.cache).toEqual(cache); }); - it('select (with alias)', ({ expect }) => { - const query = db - .select({ firstName: users.firstName }) - .from(users) - .leftJoin(devs, eq(users.id, devs.userId)); + it('query (find first, planetscale)', ({ expect }) => { + const query = ps.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true + } + } + } + }); expect(query.toSQL()).toEqual({ - sql: 'select `users`.`first_name` from `users` left join `test`.`developers` `devs` on `users`.`id` = `devs`.`user_id`', - params: [], + sql: 'select `id`, `AGE`, `first_name` || \' \' || `last_name` as `name`, (select json_array(`uses_drizzle_orm`) from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ? limit ?', + params: [1, 1, 1], + typings: ['none', 'none', 'none'] + }); + expect(ps.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true + } + } + } + }); + + expect(query.toSQL()).toEqual({ + sql: 'select `users`.`id`, `users`.`AGE`, `users`.`first_name` || \' \' || `users`.`last_name` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`uses_drizzle_orm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ?', + params: [1, 1], + typings: ['none', 'none'] }); expect(db.dialect.casing.cache).toEqual(cache); }); + it('query (find many, planetscale)', ({ expect }) => { + const query = ps.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true + } + } + } + }); + + expect(query.toSQL()).toEqual({ + sql: 'select `id`, `AGE`, `first_name` || \' \' || `last_name` as `name`, (select json_array(`uses_drizzle_orm`) from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ?', + params: [1, 1], + typings: ['none', 'none'] + }); + expect(ps.dialect.casing.cache).toEqual(cache); + }); + it('insert', ({ expect }) => { const query = db .insert(users) diff --git a/drizzle-orm/tests/casing/pg-to-camel.test.ts b/drizzle-orm/tests/casing/pg-to-camel.test.ts index 219d3b237..1b8b5b675 100644 --- a/drizzle-orm/tests/casing/pg-to-camel.test.ts +++ b/drizzle-orm/tests/casing/pg-to-camel.test.ts @@ -2,10 +2,9 @@ import { beforeEach, describe, it } from 'vitest'; import { drizzle } from '~/postgres-js'; import { alias, boolean, integer, pgSchema, pgTable, serial, text, union } from '~/pg-core'; import { asc, eq, sql } from '~/sql'; +import { relations } from '~/relations'; import postgres from 'postgres'; -const db = drizzle(postgres(''), { casing: 'camelCase' }); - const testSchema = pgSchema('test'); const users = pgTable('users', { id: serial().primaryKey(), @@ -14,11 +13,23 @@ const users = pgTable('users', { // Test that custom aliases remain age: integer('AGE') }); +const usersRelations = relations(users, ({ one }) => ({ + developers: one(developers), +})); const developers = testSchema.table('developers', { user_id: serial().primaryKey().references(() => users.id), uses_drizzle_orm: boolean().notNull(), }); +const developersRelations = relations(developers, ({ one }) => ({ + user: one(users, { + fields: [developers.user_id], + references: [users.id], + }), +})); const devs = alias(developers, 'devs'); +const schema = { users, usersRelations, developers, developersRelations }; + +const db = drizzle(postgres(''), { schema, casing: 'camelCase' }); const usersCache = { 'public.users.id': 'id', @@ -42,6 +53,33 @@ describe('postgres snake case to camel case ', () => { db.dialect.casing.clearCache(); }); + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.user_id)) + .orderBy(asc(users.first_name)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."userId" order by "users"."firstName" asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ first_name: users.first_name }) + .from(users) + .leftJoin(devs, eq(users.id, devs.user_id)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."firstName" from "users" left join "test"."developers" "devs" on "users"."id" = "devs"."userId"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + it('with CTE', ({ expect }) => { const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); const query = db.with(cte).select().from(cte); @@ -90,29 +128,56 @@ describe('postgres snake case to camel case ', () => { expect(db.dialect.casing.cache).toEqual(usersCache); }); - it('select', ({ expect }) => { - const query = db - .select({ name: fullName, age: users.age }) - .from(users) - .leftJoin(developers, eq(users.id, developers.user_id)) - .orderBy(asc(users.first_name)); + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true + } + } + } + }); expect(query.toSQL()).toEqual({ - sql: 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."userId" order by "users"."firstName" asc', - params: [], + sql: 'select "users"."id", "users"."AGE", "users"."firstName" || \' \' || "users"."lastName" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."usesDrizzleOrm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."userId" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2 limit $3', + params: [1, 1, 1], + typings: ['none', 'none', 'none'] }); expect(db.dialect.casing.cache).toEqual(cache); }); - it('select (with alias)', ({ expect }) => { - const query = db - .select({ first_name: users.first_name }) - .from(users) - .leftJoin(devs, eq(users.id, devs.user_id)); + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true + } + } + } + }); expect(query.toSQL()).toEqual({ - sql: 'select "users"."firstName" from "users" left join "test"."developers" "devs" on "users"."id" = "devs"."userId"', - params: [], + sql: 'select "users"."id", "users"."AGE", "users"."firstName" || \' \' || "users"."lastName" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."usesDrizzleOrm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."userId" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2', + params: [1, 1], + typings: ['none', 'none'] }); expect(db.dialect.casing.cache).toEqual(cache); }); diff --git a/drizzle-orm/tests/casing/pg-to-snake.test.ts b/drizzle-orm/tests/casing/pg-to-snake.test.ts index 1fb2edd60..7908adf11 100644 --- a/drizzle-orm/tests/casing/pg-to-snake.test.ts +++ b/drizzle-orm/tests/casing/pg-to-snake.test.ts @@ -2,10 +2,9 @@ import { beforeEach, describe, it } from 'vitest'; import { drizzle } from '~/postgres-js'; import { alias, boolean, integer, pgSchema, pgTable, serial, text, union } from '~/pg-core'; import { asc, eq, sql } from '~/sql'; +import { relations } from '~/relations'; import postgres from 'postgres'; -const db = drizzle(postgres(''), { casing: 'snake_case' }); - const testSchema = pgSchema('test'); const users = pgTable('users', { id: serial().primaryKey(), @@ -14,11 +13,23 @@ const users = pgTable('users', { // Test that custom aliases remain age: integer('AGE') }); +const usersRelations = relations(users, ({ one }) => ({ + developers: one(developers), +})); const developers = testSchema.table('developers', { userId: serial().primaryKey().references(() => users.id), usesDrizzleORM: boolean().notNull(), }); +const developersRelations = relations(developers, ({ one }) => ({ + user: one(users, { + fields: [developers.userId], + references: [users.id], + }), +})); const devs = alias(developers, 'devs'); +const schema = { users, usersRelations, developers, developersRelations }; + +const db = drizzle(postgres(''), { schema, casing: 'snake_case' }); const usersCache = { 'public.users.id': 'id', @@ -42,6 +53,33 @@ describe('postgres camel case to snake case ', () => { db.dialect.casing.clearCache(); }); + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.userId)) + .orderBy(asc(users.firstName)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."user_id" order by "users"."first_name" asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .leftJoin(devs, eq(users.id, devs.userId)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."first_name" from "users" left join "test"."developers" "devs" on "users"."id" = "devs"."user_id"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + it('with CTE', ({ expect }) => { const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); const query = db.with(cte).select().from(cte); @@ -90,29 +128,56 @@ describe('postgres camel case to snake case ', () => { expect(db.dialect.casing.cache).toEqual(usersCache); }); - it('select', ({ expect }) => { - const query = db - .select({ name: fullName, age: users.age }) - .from(users) - .leftJoin(developers, eq(users.id, developers.userId)) - .orderBy(asc(users.firstName)); + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true + } + } + } + }); expect(query.toSQL()).toEqual({ - sql: 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."user_id" order by "users"."first_name" asc', - params: [], + sql: 'select "users"."id", "users"."AGE", "users"."first_name" || \' \' || "users"."last_name" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."uses_drizzle_orm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2 limit $3', + params: [1, 1, 1], + typings: ['none', 'none', 'none'] }); expect(db.dialect.casing.cache).toEqual(cache); }); - it('select (with alias)', ({ expect }) => { - const query = db - .select({ firstName: users.firstName }) - .from(users) - .leftJoin(devs, eq(users.id, devs.userId)); + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true + } + } + } + }); expect(query.toSQL()).toEqual({ - sql: 'select "users"."first_name" from "users" left join "test"."developers" "devs" on "users"."id" = "devs"."user_id"', - params: [], + sql: 'select "users"."id", "users"."AGE", "users"."first_name" || \' \' || "users"."last_name" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."uses_drizzle_orm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2', + params: [1, 1], + typings: ['none', 'none'] }); expect(db.dialect.casing.cache).toEqual(cache); }); From d4e42484376e5a3ff2b03ac9b5367e858802075d Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 27 Aug 2024 13:00:05 -0700 Subject: [PATCH 107/492] Update SQLite drivers --- drizzle-orm/src/better-sqlite3/driver.ts | 2 +- drizzle-orm/src/bun-sqlite/driver.ts | 2 +- drizzle-orm/src/d1/driver.ts | 2 +- drizzle-orm/src/expo-sqlite/driver.ts | 2 +- drizzle-orm/src/libsql/driver.ts | 2 +- drizzle-orm/src/op-sqlite/driver.ts | 2 +- drizzle-orm/src/sql-js/driver.ts | 2 +- drizzle-orm/src/sqlite-core/dialect.ts | 15 ++++++++++++++- drizzle-orm/src/sqlite-proxy/driver.ts | 2 +- 9 files changed, 22 insertions(+), 9 deletions(-) diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 728586e57..399100e8c 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -19,7 +19,7 @@ export function drizzle = Record = {}, ): BetterSQLite3Database { - const dialect = new SQLiteSyncDialect(); + const dialect = new SQLiteSyncDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index 0d196ff03..fa79d77e4 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -21,7 +21,7 @@ export function drizzle = Record = {}, ): BunSQLiteDatabase { - const dialect = new SQLiteSyncDialect(); + const dialect = new SQLiteSyncDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/d1/driver.ts b/drizzle-orm/src/d1/driver.ts index 46fc8ec8e..f2ab88994 100644 --- a/drizzle-orm/src/d1/driver.ts +++ b/drizzle-orm/src/d1/driver.ts @@ -33,7 +33,7 @@ export function drizzle = Record = {}, ): DrizzleD1Database { - const dialect = new SQLiteAsyncDialect(); + const dialect = new SQLiteAsyncDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/expo-sqlite/driver.ts b/drizzle-orm/src/expo-sqlite/driver.ts index ae8ce6577..b19c5a7de 100644 --- a/drizzle-orm/src/expo-sqlite/driver.ts +++ b/drizzle-orm/src/expo-sqlite/driver.ts @@ -19,7 +19,7 @@ export function drizzle = Record = {}, ): ExpoSQLiteDatabase { - const dialect = new SQLiteSyncDialect(); + const dialect = new SQLiteSyncDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/libsql/driver.ts b/drizzle-orm/src/libsql/driver.ts index 3acff2893..a5080ffaf 100644 --- a/drizzle-orm/src/libsql/driver.ts +++ b/drizzle-orm/src/libsql/driver.ts @@ -32,7 +32,7 @@ export class LibSQLDatabase< export function drizzle< TSchema extends Record = Record, >(client: Client, config: DrizzleConfig = {}): LibSQLDatabase { - const dialect = new SQLiteAsyncDialect(); + const dialect = new SQLiteAsyncDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/op-sqlite/driver.ts b/drizzle-orm/src/op-sqlite/driver.ts index 24c663abf..bb2f76203 100644 --- a/drizzle-orm/src/op-sqlite/driver.ts +++ b/drizzle-orm/src/op-sqlite/driver.ts @@ -19,7 +19,7 @@ export function drizzle = Record = {}, ): OPSQLiteDatabase { - const dialect = new SQLiteAsyncDialect(); + const dialect = new SQLiteAsyncDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/sql-js/driver.ts b/drizzle-orm/src/sql-js/driver.ts index 2e7080721..994d80bc8 100644 --- a/drizzle-orm/src/sql-js/driver.ts +++ b/drizzle-orm/src/sql-js/driver.ts @@ -19,7 +19,7 @@ export function drizzle = Record = {}, ): SQLJsDatabase { - const dialect = new SQLiteSyncDialect(); + const dialect = new SQLiteSyncDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); diff --git a/drizzle-orm/src/sqlite-core/dialect.ts b/drizzle-orm/src/sqlite-core/dialect.ts index 645e15592..97c989e79 100644 --- a/drizzle-orm/src/sqlite-core/dialect.ts +++ b/drizzle-orm/src/sqlite-core/dialect.ts @@ -24,7 +24,7 @@ import type { SQLiteDeleteConfig, SQLiteInsertConfig, SQLiteUpdateConfig } from import { SQLiteTable } from '~/sqlite-core/table.ts'; import { Subquery } from '~/subquery.ts'; import { getTableName, getTableUniqueName, Table } from '~/table.ts'; -import { orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { SelectedFieldsOrdered, @@ -33,10 +33,22 @@ import type { } from './query-builders/select.types.ts'; import type { SQLiteSession } from './session.ts'; import { SQLiteViewBase } from './view-base.ts'; +import { CasingCache } from '~/casing.ts'; + +export interface SQLiteDialectConfig { + casing?: Casing; +} export abstract class SQLiteDialect { static readonly [entityKind]: string = 'SQLiteDialect'; + /** @internal */ + readonly casing: CasingCache; + + constructor(config?: SQLiteDialectConfig) { + this.casing = new CasingCache(config?.casing); + } + escapeName(name: string): string { return `"${name}"`; } @@ -434,6 +446,7 @@ export abstract class SQLiteDialect { sqlToQuery(sql: SQL, invokeSource?: 'indexes' | undefined): QueryWithTypings { return sql.toQuery({ + casing: this.casing, escapeName: this.escapeName, escapeParam: this.escapeParam, escapeString: this.escapeString, diff --git a/drizzle-orm/src/sqlite-proxy/driver.ts b/drizzle-orm/src/sqlite-proxy/driver.ts index b7444efc0..e3f2b2af7 100644 --- a/drizzle-orm/src/sqlite-proxy/driver.ts +++ b/drizzle-orm/src/sqlite-proxy/driver.ts @@ -55,7 +55,7 @@ export function drizzle = Record, config?: DrizzleConfig, ): SqliteRemoteDatabase { - const dialect = new SQLiteAsyncDialect(); + const dialect = new SQLiteAsyncDialect({ casing: config?.casing }); let logger; let _batchCallback: AsyncBatchRemoteCallback | undefined; let _config: DrizzleConfig = {}; From 18791925f3daec5d12ab8589a2e1aa7b2cf8fade Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 27 Aug 2024 13:12:18 -0700 Subject: [PATCH 108/492] Remove manual casing caching --- drizzle-orm/src/casing.ts | 2 +- drizzle-orm/src/mysql-core/query-builders/delete.ts | 1 - drizzle-orm/src/mysql-core/query-builders/insert.ts | 4 +--- drizzle-orm/src/mysql-core/query-builders/select.ts | 4 ---- drizzle-orm/src/mysql-core/query-builders/update.ts | 4 +--- drizzle-orm/src/pg-core/query-builders/delete.ts | 1 - drizzle-orm/src/pg-core/query-builders/insert.ts | 4 +--- drizzle-orm/src/pg-core/query-builders/select.ts | 4 ---- drizzle-orm/src/pg-core/query-builders/update.ts | 4 +--- 9 files changed, 5 insertions(+), 23 deletions(-) diff --git a/drizzle-orm/src/casing.ts b/drizzle-orm/src/casing.ts index b14fa3fa0..6e5cca990 100644 --- a/drizzle-orm/src/casing.ts +++ b/drizzle-orm/src/casing.ts @@ -53,7 +53,7 @@ export class CasingCache { return this.cache[key]!; } - cacheTable(table: Table) { + private cacheTable(table: Table) { const schema = table[Table.Symbol.Schema] ?? 'public'; const tableName = table[Table.Symbol.OriginalName]; const tableKey = `${schema}.${tableName}`; diff --git a/drizzle-orm/src/mysql-core/query-builders/delete.ts b/drizzle-orm/src/mysql-core/query-builders/delete.ts index 8cdec4bb7..e9a48da8e 100644 --- a/drizzle-orm/src/mysql-core/query-builders/delete.ts +++ b/drizzle-orm/src/mysql-core/query-builders/delete.ts @@ -97,7 +97,6 @@ export class MySqlDeleteBase< withList?: Subquery[], ) { super(); - this.dialect.casing.cacheTable(table); this.config = { table, withList }; } diff --git a/drizzle-orm/src/mysql-core/query-builders/insert.ts b/drizzle-orm/src/mysql-core/query-builders/insert.ts index b8dbe12fe..97e61de74 100644 --- a/drizzle-orm/src/mysql-core/query-builders/insert.ts +++ b/drizzle-orm/src/mysql-core/query-builders/insert.ts @@ -50,9 +50,7 @@ export class MySqlInsertBuilder< private table: TTable, private session: MySqlSession, private dialect: MySqlDialect, - ) { - this.dialect.casing.cacheTable(table); - } + ) {} ignore(): this { this.shouldIgnore = true; diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index ef6a59ab0..a5a0ca69a 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -102,7 +102,6 @@ export class MySqlSelectBuilder< } else if (is(source, SQL)) { fields = {}; } else { - this.dialect.casing.cacheTable(source); fields = getTableColumns(source); } @@ -207,9 +206,6 @@ export abstract class MySqlSelectQueryBuilderBase< }; } if (typeof tableName === 'string' && !is(table, SQL)) { - if (is(table, Table)) { - this.dialect.casing.cacheTable(table); - } const selection = is(table, Subquery) ? table._.selectedFields : is(table, View) diff --git a/drizzle-orm/src/mysql-core/query-builders/update.ts b/drizzle-orm/src/mysql-core/query-builders/update.ts index 426d18168..7884599cf 100644 --- a/drizzle-orm/src/mysql-core/query-builders/update.ts +++ b/drizzle-orm/src/mysql-core/query-builders/update.ts @@ -49,9 +49,7 @@ export class MySqlUpdateBuilder< private session: MySqlSession, private dialect: MySqlDialect, private withList?: Subquery[], - ) { - this.dialect.casing.cacheTable(table); - } + ) {} set(values: MySqlUpdateSetSource): MySqlUpdateBase { return new MySqlUpdateBase(this.table, mapUpdateSet(this.table, values), this.session, this.dialect, this.withList); diff --git a/drizzle-orm/src/pg-core/query-builders/delete.ts b/drizzle-orm/src/pg-core/query-builders/delete.ts index bf0f4ea14..dc127f167 100644 --- a/drizzle-orm/src/pg-core/query-builders/delete.ts +++ b/drizzle-orm/src/pg-core/query-builders/delete.ts @@ -139,7 +139,6 @@ export class PgDeleteBase< withList?: Subquery[], ) { super(); - this.dialect.casing.cacheTable(table); this.config = { table, withList }; } diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index af2446bad..02bcb972c 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -44,9 +44,7 @@ export class PgInsertBuilder): PgInsertBase; values(values: PgInsertValue[]): PgInsertBase; diff --git a/drizzle-orm/src/pg-core/query-builders/select.ts b/drizzle-orm/src/pg-core/query-builders/select.ts index 1d79ec085..d2406995b 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.ts @@ -112,7 +112,6 @@ export class PgSelectBuilder< } else if (is(source, SQL)) { fields = {}; } else { - this.dialect.casing.cacheTable(source); fields = getTableColumns(source); } @@ -215,9 +214,6 @@ export abstract class PgSelectQueryBuilderBase< }; } if (typeof tableName === 'string' && !is(table, SQL)) { - if (is(table, Table)) { - this.dialect.casing.cacheTable(table); - } const selection = is(table, Subquery) ? table._.selectedFields : is(table, View) diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index 2054e40fc..ec404ac22 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -47,9 +47,7 @@ export class PgUpdateBuilder): PgUpdateBase { return new PgUpdateBase( From 906b8368f558558124a3503517442ea8eab0672e Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 27 Aug 2024 13:17:04 -0700 Subject: [PATCH 109/492] Update test names --- drizzle-orm/tests/casing/mysql-to-camel.test.ts | 2 +- drizzle-orm/tests/casing/mysql-to-snake.test.ts | 2 +- drizzle-orm/tests/casing/pg-to-camel.test.ts | 2 +- drizzle-orm/tests/casing/pg-to-snake.test.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drizzle-orm/tests/casing/mysql-to-camel.test.ts b/drizzle-orm/tests/casing/mysql-to-camel.test.ts index 6c30c3a5d..a5825d6f8 100644 --- a/drizzle-orm/tests/casing/mysql-to-camel.test.ts +++ b/drizzle-orm/tests/casing/mysql-to-camel.test.ts @@ -51,7 +51,7 @@ const cache = { const fullName = sql`${users.first_name} || ' ' || ${users.last_name}`.as('name'); -describe('mysql camel case to snake case ', () => { +describe('mysql to snake case', () => { beforeEach(() => { ps.dialect.casing.clearCache(); db.dialect.casing.clearCache(); diff --git a/drizzle-orm/tests/casing/mysql-to-snake.test.ts b/drizzle-orm/tests/casing/mysql-to-snake.test.ts index c54c9f2bf..9a9655f37 100644 --- a/drizzle-orm/tests/casing/mysql-to-snake.test.ts +++ b/drizzle-orm/tests/casing/mysql-to-snake.test.ts @@ -51,7 +51,7 @@ const cache = { const fullName = sql`${users.firstName} || ' ' || ${users.lastName}`.as('name'); -describe('mysql camel case to snake case ', () => { +describe('mysql to snake case', () => { beforeEach(() => { db.dialect.casing.clearCache(); ps.dialect.casing.clearCache(); diff --git a/drizzle-orm/tests/casing/pg-to-camel.test.ts b/drizzle-orm/tests/casing/pg-to-camel.test.ts index 1b8b5b675..431ddc883 100644 --- a/drizzle-orm/tests/casing/pg-to-camel.test.ts +++ b/drizzle-orm/tests/casing/pg-to-camel.test.ts @@ -48,7 +48,7 @@ const cache = { const fullName = sql`${users.first_name} || ' ' || ${users.last_name}`.as('name'); -describe('postgres snake case to camel case ', () => { +describe('postgres to camel case', () => { beforeEach(() => { db.dialect.casing.clearCache(); }); diff --git a/drizzle-orm/tests/casing/pg-to-snake.test.ts b/drizzle-orm/tests/casing/pg-to-snake.test.ts index 7908adf11..8ffe231de 100644 --- a/drizzle-orm/tests/casing/pg-to-snake.test.ts +++ b/drizzle-orm/tests/casing/pg-to-snake.test.ts @@ -48,7 +48,7 @@ const cache = { const fullName = sql`${users.firstName} || ' ' || ${users.lastName}`.as('name'); -describe('postgres camel case to snake case ', () => { +describe('postgres to snake case', () => { beforeEach(() => { db.dialect.casing.clearCache(); }); From b5c7eefb3bef003028defbd5eb34aa7ebef62cd3 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 27 Aug 2024 13:40:33 -0700 Subject: [PATCH 110/492] Implement SQLite casing cache --- drizzle-orm/src/sqlite-core/db.ts | 3 +- drizzle-orm/src/sqlite-core/dialect.ts | 15 +- .../query-builders/query-builder.ts | 14 +- .../tests/casing/sqlite-to-camel.test.ts | 238 ++++++++++++++++++ .../tests/casing/sqlite-to-snake.test.ts | 238 ++++++++++++++++++ 5 files changed, 495 insertions(+), 13 deletions(-) create mode 100644 drizzle-orm/tests/casing/sqlite-to-camel.test.ts create mode 100644 drizzle-orm/tests/casing/sqlite-to-snake.test.ts diff --git a/drizzle-orm/src/sqlite-core/db.ts b/drizzle-orm/src/sqlite-core/db.ts index 65f807d08..f6b1185c9 100644 --- a/drizzle-orm/src/sqlite-core/db.ts +++ b/drizzle-orm/src/sqlite-core/db.ts @@ -118,12 +118,13 @@ export class BaseSQLiteDatabase< * ``` */ $with(alias: TAlias) { + const self = this; return { as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), ): WithSubqueryWithSelection { if (typeof qb === 'function') { - qb = qb(new QueryBuilder()); + qb = qb(new QueryBuilder(self.dialect)); } return new Proxy( diff --git a/drizzle-orm/src/sqlite-core/dialect.ts b/drizzle-orm/src/sqlite-core/dialect.ts index 97c989e79..562c89286 100644 --- a/drizzle-orm/src/sqlite-core/dialect.ts +++ b/drizzle-orm/src/sqlite-core/dialect.ts @@ -99,7 +99,7 @@ export abstract class SQLiteDialect { const col = tableColumns[colName]!; const value = set[colName] ?? sql.param(col.onUpdateFn!(), col); - const res = sql`${sql.identifier(col.name)} = ${value}`; + const res = sql`${sql.identifier(this.casing.getColumnCasing(col))} = ${value}`; if (i < setSize - 1) { return [res, sql.raw(', ')]; @@ -153,7 +153,7 @@ export abstract class SQLiteDialect { new SQL( query.queryChunks.map((c) => { if (is(c, Column)) { - return sql.identifier(c.name); + return sql.identifier(this.casing.getColumnCasing(c)); } return c; }), @@ -168,11 +168,10 @@ export abstract class SQLiteDialect { } } else if (is(field, Column)) { const tableName = field.table[Table.Symbol.Name]; - const columnName = field.name; if (isSingleTable) { - chunk.push(sql.identifier(columnName)); + chunk.push(sql.identifier(this.casing.getColumnCasing(field))); } else { - chunk.push(sql`${sql.identifier(tableName)}.${sql.identifier(columnName)}`); + chunk.push(sql`${sql.identifier(tableName)}.${sql.identifier(this.casing.getColumnCasing(field))}`); } } @@ -363,7 +362,7 @@ export abstract class SQLiteDialect { const chunk = singleOrderBy.queryChunks[i]; if (is(chunk, SQLiteColumn)) { - singleOrderBy.queryChunks[i] = sql.identifier(chunk.name); + singleOrderBy.queryChunks[i] = sql.identifier(this.casing.getColumnCasing(chunk)); } } @@ -395,7 +394,7 @@ export abstract class SQLiteDialect { const colEntries: [string, SQLiteColumn][] = Object.entries(columns).filter(([_, col]) => !col.shouldDisableInsert() ); - const insertOrder = colEntries.map(([, column]) => sql.identifier(column.name)); + const insertOrder = colEntries.map(([, column]) => sql.identifier(this.casing.getColumnCasing(column))); for (const [valueIndex, value] of values.entries()) { const valueList: (SQLChunk | SQL)[] = []; @@ -658,7 +657,7 @@ export abstract class SQLiteDialect { let field = sql`json_array(${ sql.join( selection.map(({ field }) => - is(field, SQLiteColumn) ? sql.identifier(field.name) : is(field, SQL.Aliased) ? field.sql : field + is(field, SQLiteColumn) ? sql.identifier(this.casing.getColumnCasing(field)) : is(field, SQL.Aliased) ? field.sql : field ), sql`, `, ) diff --git a/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts b/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts index 43000fc10..49e448ee8 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts @@ -1,8 +1,8 @@ -import { entityKind } from '~/entity.ts'; +import { entityKind, is } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { ColumnsSelection } from '~/sql/sql.ts'; -import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; +import { SQLiteDialect, SQLiteDialectConfig, SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { WithSubqueryWithSelection } from '~/sqlite-core/subquery.ts'; import { WithSubquery } from '~/subquery.ts'; import { SQLiteSelectBuilder } from './select.ts'; @@ -11,7 +11,13 @@ import type { SelectedFields } from './select.types.ts'; export class QueryBuilder { static readonly [entityKind]: string = 'SQLiteQueryBuilder'; - private dialect: SQLiteSyncDialect | undefined; + private dialect: SQLiteDialect | undefined; + private dialectConfig: SQLiteDialectConfig | undefined; + + constructor(dialect?: SQLiteDialect | SQLiteDialectConfig) { + this.dialect = is(dialect, SQLiteDialect) ? dialect : undefined; + this.dialectConfig = !is(dialect, SQLiteDialect) ? dialect : undefined; + } $with(alias: TAlias) { const queryBuilder = this; @@ -97,7 +103,7 @@ export class QueryBuilder { // Lazy load dialect to avoid circular dependency private getDialect() { if (!this.dialect) { - this.dialect = new SQLiteSyncDialect(); + this.dialect = new SQLiteSyncDialect(this.dialectConfig); } return this.dialect; diff --git a/drizzle-orm/tests/casing/sqlite-to-camel.test.ts b/drizzle-orm/tests/casing/sqlite-to-camel.test.ts new file mode 100644 index 000000000..edab894b2 --- /dev/null +++ b/drizzle-orm/tests/casing/sqlite-to-camel.test.ts @@ -0,0 +1,238 @@ +import { beforeEach, describe, it } from 'vitest'; +import { drizzle } from '~/better-sqlite3'; +import { alias, integer, sqliteTable, text, union } from '~/sqlite-core'; +import { asc, eq, sql } from '~/sql'; +import { relations } from '~/relations'; +import Database from 'better-sqlite3'; + +const users = sqliteTable('users', { + id: integer().primaryKey({ autoIncrement: true }), + first_name: text().notNull(), + last_name: text().notNull(), + // Test that custom aliases remain + age: integer('AGE') +}); +const usersRelations = relations(users, ({ one }) => ({ + developers: one(developers), +})); +const developers = sqliteTable('developers', { + user_id: integer().primaryKey().references(() => users.id), + uses_drizzle_orm: integer({ mode: 'boolean' }).notNull(), +}); +const developersRelations = relations(developers, ({ one }) => ({ + user: one(users, { + fields: [developers.user_id], + references: [users.id], + }), +})); +const devs = alias(developers, 'devs'); +const schema = { users, usersRelations, developers, developersRelations }; + +const db = drizzle(new Database(':memory:'), { schema, casing: 'camelCase' }); + +const usersCache = { + 'public.users.id': 'id', + 'public.users.first_name': 'firstName', + 'public.users.last_name': 'lastName', + 'public.users.AGE': 'age', +}; +const developersCache = { + 'public.developers.user_id': 'userId', + 'public.developers.uses_drizzle_orm': 'usesDrizzleOrm', +}; +const cache = { + ...usersCache, + ...developersCache, +}; + +const fullName = sql`${users.first_name} || ' ' || ${users.last_name}`.as('name'); + +describe('sqlite to camel case', () => { + beforeEach(() => { + db.dialect.casing.clearCache(); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.user_id)) + .orderBy(asc(users.first_name)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "developers" on "users"."id" = "developers"."userId" order by "users"."firstName" asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ first_name: users.first_name }) + .from(users) + .leftJoin(devs, eq(users.id, devs.user_id)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."firstName" from "users" left join "developers" "devs" on "users"."id" = "devs"."userId"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator', ({ expect }) => { + const query = db + .select({ first_name: users.first_name }) + .from(users) + .union(db.select({ first_name: users.first_name }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: 'select "firstName" from "users" union select "firstName" from "users"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ first_name: users.first_name }).from(users), + db.select({ first_name: users.first_name }).from(users) + ); + + expect(query.toSQL()).toEqual({ + sql: 'select "firstName" from "users" union select "firstName" from "users"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true + } + } + } + }); + + expect(query.toSQL()).toEqual({ + sql: 'select "id", "AGE", "firstName" || \' \' || "lastName" as "name", (select json_array("usesDrizzleOrm") as "data" from (select * from "developers" "users_developers" where "users_developers"."userId" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ? limit ?', + params: [1, 1, 1], + typings: ['none', 'none', 'none'] + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true + } + } + } + }); + + expect(query.toSQL()).toEqual({ + sql: 'select "id", "AGE", "firstName" || \' \' || "lastName" as "name", (select json_array("usesDrizzleOrm") as "data" from (select * from "developers" "users_developers" where "users_developers"."userId" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ?', + params: [1, 1], + typings: ['none', 'none'] + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('insert (on conflict do nothing)', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }) + .onConflictDoNothing({ target: users.first_name }) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into "users" ("id", "firstName", "lastName", "AGE") values (null, ?, ?, ?) on conflict ("users"."firstName") do nothing returning "firstName", "AGE"', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('insert (on conflict do update)', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }) + .onConflictDoUpdate({ target: users.first_name, set: { age: 31 } }) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into "users" ("id", "firstName", "lastName", "AGE") values (null, ?, ?, ?) on conflict ("users"."firstName") do update set "AGE" = ? returning "firstName", "AGE"', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ first_name: 'John', last_name: 'Doe', age: 30 }) + .where(eq(users.id, 1)) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'update "users" set "firstName" = ?, "lastName" = ?, "AGE" = ? where "users"."id" = ? returning "firstName", "AGE"', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'delete from "users" where "users"."id" = ? returning "firstName", "AGE"', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); +}); diff --git a/drizzle-orm/tests/casing/sqlite-to-snake.test.ts b/drizzle-orm/tests/casing/sqlite-to-snake.test.ts new file mode 100644 index 000000000..2a8d5f6a8 --- /dev/null +++ b/drizzle-orm/tests/casing/sqlite-to-snake.test.ts @@ -0,0 +1,238 @@ +import { beforeEach, describe, it } from 'vitest'; +import { drizzle } from '~/better-sqlite3'; +import { alias, integer, sqliteTable, text, union } from '~/sqlite-core'; +import { asc, eq, sql } from '~/sql'; +import { relations } from '~/relations'; +import Database from 'better-sqlite3'; + +const users = sqliteTable('users', { + id: integer().primaryKey({ autoIncrement: true }), + firstName: text().notNull(), + lastName: text().notNull(), + // Test that custom aliases remain + age: integer('AGE') +}); +const usersRelations = relations(users, ({ one }) => ({ + developers: one(developers), +})); +const developers = sqliteTable('developers', { + userId: integer().primaryKey().references(() => users.id), + usesDrizzleORM: integer({ mode: 'boolean' }).notNull(), +}); +const developersRelations = relations(developers, ({ one }) => ({ + user: one(users, { + fields: [developers.userId], + references: [users.id], + }), +})); +const devs = alias(developers, 'devs'); +const schema = { users, usersRelations, developers, developersRelations }; + +const db = drizzle(new Database(':memory:'), { schema, casing: 'snake_case' }); + +const usersCache = { + 'public.users.id': 'id', + 'public.users.firstName': 'first_name', + 'public.users.lastName': 'last_name', + 'public.users.AGE': 'age', +}; +const developersCache = { + 'public.developers.userId': 'user_id', + 'public.developers.usesDrizzleORM': 'uses_drizzle_orm', +}; +const cache = { + ...usersCache, + ...developersCache, +}; + +const fullName = sql`${users.firstName} || ' ' || ${users.lastName}`.as('name'); + +describe('sqlite to camel case', () => { + beforeEach(() => { + db.dialect.casing.clearCache(); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.userId)) + .orderBy(asc(users.firstName)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "developers" on "users"."id" = "developers"."user_id" order by "users"."first_name" asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .leftJoin(devs, eq(users.id, devs.userId)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."first_name" from "users" left join "developers" "devs" on "users"."id" = "devs"."user_id"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .union(db.select({ firstName: users.firstName }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: 'select "first_name" from "users" union select "first_name" from "users"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ firstName: users.firstName }).from(users), + db.select({ firstName: users.firstName }).from(users) + ); + + expect(query.toSQL()).toEqual({ + sql: 'select "first_name" from "users" union select "first_name" from "users"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true + } + } + } + }); + + expect(query.toSQL()).toEqual({ + sql: 'select "id", "AGE", "first_name" || \' \' || "last_name" as "name", (select json_array("uses_drizzle_orm") as "data" from (select * from "developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ? limit ?', + params: [1, 1, 1], + typings: ['none', 'none', 'none'] + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true + } + } + } + }); + + expect(query.toSQL()).toEqual({ + sql: 'select "id", "AGE", "first_name" || \' \' || "last_name" as "name", (select json_array("uses_drizzle_orm") as "data" from (select * from "developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ?', + params: [1, 1], + typings: ['none', 'none'] + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('insert (on conflict do nothing)', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }) + .onConflictDoNothing({ target: users.firstName }) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into "users" ("id", "first_name", "last_name", "AGE") values (null, ?, ?, ?) on conflict ("users"."first_name") do nothing returning "first_name", "AGE"', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('insert (on conflict do update)', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }) + .onConflictDoUpdate({ target: users.firstName, set: { age: 31 } }) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into "users" ("id", "first_name", "last_name", "AGE") values (null, ?, ?, ?) on conflict ("users"."first_name") do update set "AGE" = ? returning "first_name", "AGE"', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ firstName: 'John', lastName: 'Doe', age: 30 }) + .where(eq(users.id, 1)) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'update "users" set "first_name" = ?, "last_name" = ?, "AGE" = ? where "users"."id" = ? returning "first_name", "AGE"', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)) + .returning({ first_name: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'delete from "users" where "users"."id" = ? returning "first_name", "AGE"', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); +}); From 64f1bf7764810ac3839c90488a29a36b516357e8 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 27 Aug 2024 15:20:31 -0700 Subject: [PATCH 111/492] Add ability to define column types without imports (callback fn) --- drizzle-orm/src/mysql-core/columns/all.ts | 55 +++++++ drizzle-orm/src/mysql-core/table.ts | 21 ++- drizzle-orm/src/pg-core/columns/all.ts | 71 +++++++++ drizzle-orm/src/pg-core/table.ts | 23 ++- drizzle-orm/src/sqlite-core/columns/all.ts | 19 +++ drizzle-orm/src/sqlite-core/table.ts | 21 ++- drizzle-orm/type-tests/mysql/tables.ts | 4 +- drizzle-orm/type-tests/pg/tables.ts | 158 +++++++++++---------- drizzle-orm/type-tests/sqlite/tables.ts | 4 +- 9 files changed, 288 insertions(+), 88 deletions(-) create mode 100644 drizzle-orm/src/mysql-core/columns/all.ts create mode 100644 drizzle-orm/src/pg-core/columns/all.ts create mode 100644 drizzle-orm/src/sqlite-core/columns/all.ts diff --git a/drizzle-orm/src/mysql-core/columns/all.ts b/drizzle-orm/src/mysql-core/columns/all.ts new file mode 100644 index 000000000..e0435cead --- /dev/null +++ b/drizzle-orm/src/mysql-core/columns/all.ts @@ -0,0 +1,55 @@ +import { bigint } from './bigint'; +import { binary } from './binary'; +import { boolean } from './boolean'; +import { char } from './char'; +import { customType } from './custom'; +import { date } from './date'; +import { datetime } from './datetime'; +import { decimal } from './decimal'; +import { double } from './double'; +import { mysqlEnum } from './enum'; +import { float } from './float'; +import { int } from './int'; +import { json } from './json'; +import { mediumint } from './mediumint'; +import { real } from './real'; +import { serial } from './serial'; +import { smallint } from './smallint'; +import { text } from './text'; +import { time } from './time'; +import { timestamp } from './timestamp'; +import { tinyint } from './tinyint'; +import { varbinary } from './varbinary'; +import { varchar } from './varchar'; +import { year } from './year'; + +export function getMySqlColumnBuilders() { + return { + bigint, + binary, + boolean, + char, + customType, + date, + datetime, + decimal, + double, + mysqlEnum, + float, + int, + json, + mediumint, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year + }; +} + +export type MySqlColumnBuilders = ReturnType; diff --git a/drizzle-orm/src/mysql-core/table.ts b/drizzle-orm/src/mysql-core/table.ts index 152198a14..e442166a3 100644 --- a/drizzle-orm/src/mysql-core/table.ts +++ b/drizzle-orm/src/mysql-core/table.ts @@ -7,6 +7,7 @@ import type { ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; +import { getMySqlColumnBuilders, type MySqlColumnBuilders } from './columns/all.ts'; export type MySqlTableExtraConfig = Record< string, @@ -60,7 +61,7 @@ export function mysqlTableWithSchema< TColumnsMap extends Record, >( name: TTableName, - columns: TColumnsMap, + columns: TColumnsMap | ((columnTypes: MySqlColumnBuilders) => TColumnsMap), extraConfig: ((self: BuildColumns) => MySqlTableExtraConfig) | undefined, schema: TSchemaName, baseName = name, @@ -77,8 +78,10 @@ export function mysqlTableWithSchema< dialect: 'mysql'; }>(name, schema, baseName); + const parsedColumns: TColumnsMap = typeof columns === 'function' ? columns(getMySqlColumnBuilders()) : columns; + const builtColumns = Object.fromEntries( - Object.entries(columns).map(([name, colBuilderBase]) => { + Object.entries(parsedColumns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as MySqlColumnBuilder; colBuilder.setName(name); const column = colBuilder.build(rawTable); @@ -119,6 +122,20 @@ export interface MySqlTableFn; dialect: 'mysql'; }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: MySqlColumnBuilders) => TColumnsMap, + extraConfig?: (self: BuildColumns) => MySqlTableExtraConfig, + ): MySqlTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'mysql'; + }>; } export const mysqlTable: MySqlTableFn = (name, columns, extraConfig) => { diff --git a/drizzle-orm/src/pg-core/columns/all.ts b/drizzle-orm/src/pg-core/columns/all.ts new file mode 100644 index 000000000..0bdb4b519 --- /dev/null +++ b/drizzle-orm/src/pg-core/columns/all.ts @@ -0,0 +1,71 @@ +import { bigint } from './bigint.ts'; +import { bigserial } from './bigserial.ts'; +import { boolean } from './boolean.ts'; +import { char } from './char.ts'; +import { cidr } from './cidr.ts'; +import { customType } from './custom.ts'; +import { date } from './date.ts'; +import { doublePrecision } from './double-precision.ts'; +import { inet } from './inet.ts'; +import { integer } from './integer.ts'; +import { interval } from './interval.ts'; +import { json } from './json.ts'; +import { jsonb } from './jsonb.ts'; +import { line } from './line.ts'; +import { macaddr } from './macaddr.ts'; +import { macaddr8 } from './macaddr8.ts'; +import { numeric } from './numeric.ts'; +import { point } from './point.ts'; +import { geometry } from './postgis_extension/geometry.ts'; +import { real } from './real.ts'; +import { serial } from './serial.ts'; +import { smallint } from './smallint.ts'; +import { smallserial } from './smallserial.ts'; +import { text } from './text.ts'; +import { time } from './time.ts'; +import { timestamp } from './timestamp.ts'; +import { uuid } from './uuid.ts'; +import { varchar } from './varchar.ts'; +import { bit } from './vector_extension/bit.ts'; +import { halfvec } from './vector_extension/halfvec.ts'; +import { sparsevec } from './vector_extension/sparsevec.ts'; +import { vector } from './vector_extension/vector.ts'; + +export function getPgColumnBuilders() { + return { + bigint, + bigserial, + boolean, + char, + cidr, + customType, + date, + doublePrecision, + inet, + integer, + interval, + json, + jsonb, + line, + macaddr, + macaddr8, + numeric, + point, + geometry, + real, + serial, + smallint, + smallserial, + text, + time, + timestamp, + uuid, + varchar, + bit, + halfvec, + sparsevec, + vector + }; +} + +export type PgColumnsBuilders = ReturnType; diff --git a/drizzle-orm/src/pg-core/table.ts b/drizzle-orm/src/pg-core/table.ts index cfa13082d..e5a4677af 100644 --- a/drizzle-orm/src/pg-core/table.ts +++ b/drizzle-orm/src/pg-core/table.ts @@ -7,6 +7,7 @@ import type { ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; +import { getPgColumnBuilders, type PgColumnsBuilders } from './columns/all.ts'; export type PgTableExtraConfig = Record< string, @@ -53,7 +54,7 @@ export function pgTableWithSchema< TColumnsMap extends Record, >( name: TTableName, - columns: TColumnsMap, + columns: TColumnsMap | ((columnTypes: PgColumnsBuilders) => TColumnsMap), extraConfig: ((self: BuildExtraConfigColumns) => PgTableExtraConfig) | undefined, schema: TSchemaName, baseName = name, @@ -70,8 +71,10 @@ export function pgTableWithSchema< dialect: 'pg'; }>(name, schema, baseName); + const parsedColumns: TColumnsMap = typeof columns === 'function' ? columns(getPgColumnBuilders()) : columns; + const builtColumns = Object.fromEntries( - Object.entries(columns).map(([name, colBuilderBase]) => { + Object.entries(parsedColumns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as PgColumnBuilder; colBuilder.setName(name); const column = colBuilder.build(rawTable); @@ -81,7 +84,7 @@ export function pgTableWithSchema< ) as unknown as BuildColumns; const builtColumnsForExtraConfig = Object.fromEntries( - Object.entries(columns).map(([name, colBuilderBase]) => { + Object.entries(parsedColumns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as PgColumnBuilder; colBuilder.setName(name); const column = colBuilder.buildExtraConfigColumn(rawTable); @@ -115,6 +118,20 @@ export interface PgTableFn { columns: BuildColumns; dialect: 'pg'; }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: PgColumnsBuilders) => TColumnsMap, + extraConfig?: (self: BuildExtraConfigColumns) => PgTableExtraConfig, + ): PgTableWithColumns<{ + name: TTableName; + schema: TSchema; + columns: BuildColumns; + dialect: 'pg'; + }>; } export const pgTable: PgTableFn = (name, columns, extraConfig) => { diff --git a/drizzle-orm/src/sqlite-core/columns/all.ts b/drizzle-orm/src/sqlite-core/columns/all.ts new file mode 100644 index 000000000..449e123cf --- /dev/null +++ b/drizzle-orm/src/sqlite-core/columns/all.ts @@ -0,0 +1,19 @@ +import { blob } from './blob'; +import { customType } from './custom'; +import { integer } from './integer'; +import { numeric } from './numeric'; +import { real } from './real'; +import { text } from './text'; + +export function getSQLiteColumnBuilders() { + return { + blob, + customType, + integer, + numeric, + real, + text, + }; +} + +export type SQLiteColumnBuilders = ReturnType; diff --git a/drizzle-orm/src/sqlite-core/table.ts b/drizzle-orm/src/sqlite-core/table.ts index 7749b69af..63084b9c5 100644 --- a/drizzle-orm/src/sqlite-core/table.ts +++ b/drizzle-orm/src/sqlite-core/table.ts @@ -7,6 +7,7 @@ import type { ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; import type { IndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; +import { getSQLiteColumnBuilders, type SQLiteColumnBuilders } from './columns/all.ts'; export type SQLiteTableExtraConfig = Record< string, @@ -66,6 +67,20 @@ export interface SQLiteTableFn { columns: BuildColumns; dialect: 'sqlite'; }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: SQLiteColumnBuilders) => TColumnsMap, + extraConfig?: (self: BuildColumns) => SQLiteTableExtraConfig, + ): SQLiteTableWithColumns<{ + name: TTableName; + schema: TSchema; + columns: BuildColumns; + dialect: 'sqlite'; + }>; } function sqliteTableBase< @@ -74,7 +89,7 @@ function sqliteTableBase< TSchema extends string | undefined, >( name: TTableName, - columns: TColumnsMap, + columns: TColumnsMap | ((columnTypes: SQLiteColumnBuilders) => TColumnsMap), extraConfig?: (self: BuildColumns) => SQLiteTableExtraConfig, schema?: TSchema, baseName = name, @@ -91,8 +106,10 @@ function sqliteTableBase< dialect: 'sqlite'; }>(name, schema, baseName); + const parsedColumns: TColumnsMap = typeof columns === 'function' ? columns(getSQLiteColumnBuilders()) : columns; + const builtColumns = Object.fromEntries( - Object.entries(columns).map(([name, colBuilderBase]) => { + Object.entries(parsedColumns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as SQLiteColumnBuilder; colBuilder.setName(name); const column = colBuilder.build(rawTable); diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index ffd50da29..620f648c1 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -170,11 +170,11 @@ export const citiesCustom = customSchema.table('cities_table', { Expect>; -export const classes = mysqlTable('classes_table', { +export const classes = mysqlTable('classes_table', ({ serial, text }) => ({ id: serial('id').primaryKey(), class: text('class', { enum: ['A', 'C'] }), subClass: text('sub_class', { enum: ['B', 'D'] }).notNull(), -}); +})); /* export const classes2 = mysqlTable('classes_table', { id: serial().primaryKey(), diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index f25f473c5..068f8fcf6 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -915,89 +915,93 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); } { - const cities = pgTable('cities_table', { + const cities1 = pgTable('cities_table', { id: serial('id').primaryKey(), name: text('name').notNull().primaryKey(), role: text('role', { enum: ['admin', 'user'] }).default('user').notNull(), population: integer('population').default(0), }); + const cities2 = pgTable('cities_table', ({ serial, text, integer }) => ({ + id: serial('id').primaryKey(), + name: text('name').notNull().primaryKey(), + role: text('role', { enum: ['admin', 'user'] }).default('user').notNull(), + population: integer('population').default(0), + })); + + type Expected = PgTableWithColumns<{ + name: 'cities_table'; + schema: undefined; + dialect: 'pg'; + columns: { + id: PgColumn<{ + tableName: 'cities_table'; + name: 'id'; + dataType: 'number'; + columnType: 'PgSerial'; + data: number; + driverParam: number; + hasDefault: true; + notNull: true; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + name: PgColumn<{ + tableName: 'cities_table'; + name: 'name'; + dataType: 'string'; + columnType: 'PgText'; + data: string; + driverParam: string; + hasDefault: false; + enumValues: [string, ...string[]]; + notNull: true; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + role: PgColumn<{ + tableName: 'cities_table'; + name: 'role'; + dataType: 'string'; + columnType: 'PgText'; + data: 'admin' | 'user'; + driverParam: string; + hasDefault: true; + enumValues: ['admin', 'user']; + notNull: true; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + population: PgColumn<{ + tableName: 'cities_table'; + name: 'population'; + dataType: 'number'; + columnType: 'PgInteger'; + data: number; + driverParam: string | number; + notNull: false; + hasDefault: true; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }; + }>; - Expect< - Equal< - PgTableWithColumns<{ - name: 'cities_table'; - schema: undefined; - dialect: 'pg'; - columns: { - id: PgColumn<{ - tableName: 'cities_table'; - name: 'id'; - dataType: 'number'; - columnType: 'PgSerial'; - data: number; - driverParam: number; - hasDefault: true; - notNull: true; - enumValues: undefined; - baseColumn: never; - generated: undefined; - isPrimaryKey: true; - isAutoincrement: false; - hasRuntimeDefault: false; - }>; - name: PgColumn<{ - tableName: 'cities_table'; - name: 'name'; - dataType: 'string'; - columnType: 'PgText'; - data: string; - driverParam: string; - hasDefault: false; - enumValues: [string, ...string[]]; - notNull: true; - baseColumn: never; - generated: undefined; - isPrimaryKey: true; - isAutoincrement: false; - hasRuntimeDefault: false; - }>; - role: PgColumn<{ - tableName: 'cities_table'; - name: 'role'; - dataType: 'string'; - columnType: 'PgText'; - data: 'admin' | 'user'; - driverParam: string; - hasDefault: true; - enumValues: ['admin', 'user']; - notNull: true; - baseColumn: never; - generated: undefined; - isPrimaryKey: false; - isAutoincrement: false; - hasRuntimeDefault: false; - }>; - population: PgColumn<{ - tableName: 'cities_table'; - name: 'population'; - dataType: 'number'; - columnType: 'PgInteger'; - data: number; - driverParam: string | number; - notNull: false; - hasDefault: true; - enumValues: undefined; - baseColumn: never; - generated: undefined; - isPrimaryKey: false; - isAutoincrement: false; - hasRuntimeDefault: false; - }>; - }; - }>, - typeof cities - > - >; + Expect>; + Expect>; } { diff --git a/drizzle-orm/type-tests/sqlite/tables.ts b/drizzle-orm/type-tests/sqlite/tables.ts index 5d2287320..02a6e840a 100644 --- a/drizzle-orm/type-tests/sqlite/tables.ts +++ b/drizzle-orm/type-tests/sqlite/tables.ts @@ -95,11 +95,11 @@ Expect< }> >; -export const cities = sqliteTable('cities_table', { +export const cities = sqliteTable('cities_table', ({ integer, text }) => ({ id: integer('id').primaryKey(), name: text('name').notNull(), population: integer('population').default(0), -}); +})); export type City = typeof cities.$inferSelect; Expect< From b6ae7a24205b59ea5aad6bafc556feea77746467 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 27 Aug 2024 15:22:04 -0700 Subject: [PATCH 112/492] Format --- drizzle-orm/src/casing.ts | 104 ++-- drizzle-orm/src/mysql-core/columns/all.ts | 52 +- drizzle-orm/src/mysql-core/dialect.ts | 8 +- drizzle-orm/src/mysql-core/table.ts | 2 +- drizzle-orm/src/pg-core/columns/all.ts | 68 +-- drizzle-orm/src/pg-core/dialect.ts | 4 +- drizzle-orm/src/pg-core/table.ts | 2 +- drizzle-orm/src/sql/sql.ts | 2 +- drizzle-orm/src/sqlite-core/columns/all.ts | 16 +- drizzle-orm/src/sqlite-core/dialect.ts | 8 +- drizzle-orm/src/sqlite-core/table.ts | 2 +- drizzle-orm/tests/casing/casing.test.ts | 38 +- .../tests/casing/mysql-to-camel.test.ts | 531 +++++++++--------- .../tests/casing/mysql-to-snake.test.ts | 531 +++++++++--------- drizzle-orm/tests/casing/pg-to-camel.test.ts | 427 +++++++------- drizzle-orm/tests/casing/pg-to-snake.test.ts | 429 +++++++------- .../tests/casing/sqlite-to-camel.test.ts | 426 +++++++------- .../tests/casing/sqlite-to-snake.test.ts | 428 +++++++------- 18 files changed, 1565 insertions(+), 1513 deletions(-) diff --git a/drizzle-orm/src/casing.ts b/drizzle-orm/src/casing.ts index 6e5cca990..f09348de0 100644 --- a/drizzle-orm/src/casing.ts +++ b/drizzle-orm/src/casing.ts @@ -1,74 +1,74 @@ +import { Casing, type Column, entityKind } from './index.ts'; import { Table } from './table.ts'; -import { Casing, entityKind, type Column } from './index.ts'; export function toSnakeCase(input: string) { - const words = input - .replace(/['\u2019]/g, '') - .match(/[a-z0-9]+|[A-Z]+(?![a-z])|[A-Z][a-z0-9]+/g) ?? []; + const words = input + .replace(/['\u2019]/g, '') + .match(/[a-z0-9]+|[A-Z]+(?![a-z])|[A-Z][a-z0-9]+/g) ?? []; - return words.map((word) => word.toLowerCase()).join('_'); + return words.map((word) => word.toLowerCase()).join('_'); } export function toCamelCase(input: string) { - const words = input - .replace(/['\u2019]/g, '') - .match(/[a-z0-9]+|[A-Z]+(?![a-z])|[A-Z][a-z0-9]+/g) ?? []; + const words = input + .replace(/['\u2019]/g, '') + .match(/[a-z0-9]+|[A-Z]+(?![a-z])|[A-Z][a-z0-9]+/g) ?? []; - return words.reduce((acc, word, i) => { - const formattedWord = i === 0 ? word.toLowerCase() : `${word[0]!.toUpperCase()}${word.slice(1)}`; - return acc + formattedWord; - }, ''); + return words.reduce((acc, word, i) => { + const formattedWord = i === 0 ? word.toLowerCase() : `${word[0]!.toUpperCase()}${word.slice(1)}`; + return acc + formattedWord; + }, ''); } function noopCase(input: string) { - return input; + return input; } export class CasingCache { - static readonly [entityKind]: string = 'CasingCache'; + static readonly [entityKind]: string = 'CasingCache'; - /** @internal */ - cache: Record = {}; - private cachedTables: Record = {}; - private convert: (input: string) => string + /** @internal */ + cache: Record = {}; + private cachedTables: Record = {}; + private convert: (input: string) => string; - constructor(casing?: Casing) { - this.convert = casing === 'snake_case' - ? toSnakeCase - : casing === 'camelCase' - ? toCamelCase - : noopCase - } + constructor(casing?: Casing) { + this.convert = casing === 'snake_case' + ? toSnakeCase + : casing === 'camelCase' + ? toCamelCase + : noopCase; + } - getColumnCasing(column: Column): string { - if (!column.keyAsName) return column.name; + getColumnCasing(column: Column): string { + if (!column.keyAsName) return column.name; - const schema = column.table[Table.Symbol.Schema] ?? 'public'; - const tableName = column.table[Table.Symbol.OriginalName]; - const key = `${schema}.${tableName}.${column.name}`; + const schema = column.table[Table.Symbol.Schema] ?? 'public'; + const tableName = column.table[Table.Symbol.OriginalName]; + const key = `${schema}.${tableName}.${column.name}`; - if (!this.cache[key]) { - this.cacheTable(column.table); - } - return this.cache[key]!; - } + if (!this.cache[key]) { + this.cacheTable(column.table); + } + return this.cache[key]!; + } - private cacheTable(table: Table) { - const schema = table[Table.Symbol.Schema] ?? 'public'; - const tableName = table[Table.Symbol.OriginalName]; - const tableKey = `${schema}.${tableName}`; + private cacheTable(table: Table) { + const schema = table[Table.Symbol.Schema] ?? 'public'; + const tableName = table[Table.Symbol.OriginalName]; + const tableKey = `${schema}.${tableName}`; - if (!this.cachedTables[tableKey]) { - for (const column of Object.values(table[Table.Symbol.Columns])) { - const columnKey = `${tableKey}.${column.name}`; - this.cache[columnKey] = this.convert(column.name); - } - this.cachedTables[tableKey] = true; - } - } + if (!this.cachedTables[tableKey]) { + for (const column of Object.values(table[Table.Symbol.Columns])) { + const columnKey = `${tableKey}.${column.name}`; + this.cache[columnKey] = this.convert(column.name); + } + this.cachedTables[tableKey] = true; + } + } - clearCache() { - this.cache = {}; - this.cachedTables = {}; - } -} \ No newline at end of file + clearCache() { + this.cache = {}; + this.cachedTables = {}; + } +} diff --git a/drizzle-orm/src/mysql-core/columns/all.ts b/drizzle-orm/src/mysql-core/columns/all.ts index e0435cead..8559fd204 100644 --- a/drizzle-orm/src/mysql-core/columns/all.ts +++ b/drizzle-orm/src/mysql-core/columns/all.ts @@ -24,32 +24,32 @@ import { varchar } from './varchar'; import { year } from './year'; export function getMySqlColumnBuilders() { - return { - bigint, - binary, - boolean, - char, - customType, - date, - datetime, - decimal, - double, - mysqlEnum, - float, - int, - json, - mediumint, - real, - serial, - smallint, - text, - time, - timestamp, - tinyint, - varbinary, - varchar, - year - }; + return { + bigint, + binary, + boolean, + char, + customType, + date, + datetime, + decimal, + double, + mysqlEnum, + float, + int, + json, + mediumint, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, + }; } export type MySqlColumnBuilders = ReturnType; diff --git a/drizzle-orm/src/mysql-core/dialect.ts b/drizzle-orm/src/mysql-core/dialect.ts index a067ca394..e82212827 100644 --- a/drizzle-orm/src/mysql-core/dialect.ts +++ b/drizzle-orm/src/mysql-core/dialect.ts @@ -1,4 +1,5 @@ import { aliasedTable, aliasedTableColumn, mapColumnsInAliasedSQLToAlias, mapColumnsInSQLToAlias } from '~/alias.ts'; +import { CasingCache } from '~/casing.ts'; import { Column } from '~/column.ts'; import { entityKind, is } from '~/entity.ts'; import { DrizzleError } from '~/errors.ts'; @@ -30,7 +31,6 @@ import type { MySqlUpdateConfig } from './query-builders/update.ts'; import type { MySqlSession } from './session.ts'; import { MySqlTable } from './table.ts'; import { MySqlViewBase } from './view-base.ts'; -import { CasingCache } from '~/casing.ts'; export interface MySqlDialectConfig { casing?: Casing; @@ -1003,7 +1003,11 @@ export class MySqlDialect { let field = sql`json_array(${ sql.join( selection.map(({ field }) => - is(field, MySqlColumn) ? sql.identifier(this.casing.getColumnCasing(field)) : is(field, SQL.Aliased) ? field.sql : field + is(field, MySqlColumn) + ? sql.identifier(this.casing.getColumnCasing(field)) + : is(field, SQL.Aliased) + ? field.sql + : field ), sql`, `, ) diff --git a/drizzle-orm/src/mysql-core/table.ts b/drizzle-orm/src/mysql-core/table.ts index e442166a3..36c366d61 100644 --- a/drizzle-orm/src/mysql-core/table.ts +++ b/drizzle-orm/src/mysql-core/table.ts @@ -2,12 +2,12 @@ import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts' import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; import type { CheckBuilder } from './checks.ts'; +import { getMySqlColumnBuilders, type MySqlColumnBuilders } from './columns/all.ts'; import type { MySqlColumn, MySqlColumnBuilder, MySqlColumnBuilderBase } from './columns/common.ts'; import type { ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; -import { getMySqlColumnBuilders, type MySqlColumnBuilders } from './columns/all.ts'; export type MySqlTableExtraConfig = Record< string, diff --git a/drizzle-orm/src/pg-core/columns/all.ts b/drizzle-orm/src/pg-core/columns/all.ts index 0bdb4b519..e45828067 100644 --- a/drizzle-orm/src/pg-core/columns/all.ts +++ b/drizzle-orm/src/pg-core/columns/all.ts @@ -32,40 +32,40 @@ import { sparsevec } from './vector_extension/sparsevec.ts'; import { vector } from './vector_extension/vector.ts'; export function getPgColumnBuilders() { - return { - bigint, - bigserial, - boolean, - char, - cidr, - customType, - date, - doublePrecision, - inet, - integer, - interval, - json, - jsonb, - line, - macaddr, - macaddr8, - numeric, - point, - geometry, - real, - serial, - smallint, - smallserial, - text, - time, - timestamp, - uuid, - varchar, - bit, - halfvec, - sparsevec, - vector - }; + return { + bigint, + bigserial, + boolean, + char, + cidr, + customType, + date, + doublePrecision, + inet, + integer, + interval, + json, + jsonb, + line, + macaddr, + macaddr8, + numeric, + point, + geometry, + real, + serial, + smallint, + smallserial, + text, + time, + timestamp, + uuid, + varchar, + bit, + halfvec, + sparsevec, + vector, + }; } export type PgColumnsBuilders = ReturnType; diff --git a/drizzle-orm/src/pg-core/dialect.ts b/drizzle-orm/src/pg-core/dialect.ts index fb7ad95a1..badd8b755 100644 --- a/drizzle-orm/src/pg-core/dialect.ts +++ b/drizzle-orm/src/pg-core/dialect.ts @@ -1,4 +1,5 @@ import { aliasedTable, aliasedTableColumn, mapColumnsInAliasedSQLToAlias, mapColumnsInSQLToAlias } from '~/alias.ts'; +import { CasingCache } from '~/casing.ts'; import { Column } from '~/column.ts'; import { entityKind, is } from '~/entity.ts'; import { DrizzleError } from '~/errors.ts'; @@ -53,7 +54,6 @@ import { ViewBaseConfig } from '~/view-common.ts'; import type { PgSession } from './session.ts'; import { PgViewBase } from './view-base.ts'; import type { PgMaterializedView } from './view.ts'; -import { CasingCache } from '~/casing.ts'; export interface PgDialectConfig { casing?: Casing; @@ -475,7 +475,7 @@ export class PgDialect { const colEntries: [string, PgColumn][] = Object.entries(columns).filter(([_, col]) => !col.shouldDisableInsert()); const insertOrder = colEntries.map( - ([, column]) => sql.identifier(this.casing.getColumnCasing(column)) + ([, column]) => sql.identifier(this.casing.getColumnCasing(column)), ); for (const [valueIndex, value] of values.entries()) { diff --git a/drizzle-orm/src/pg-core/table.ts b/drizzle-orm/src/pg-core/table.ts index e5a4677af..c09a56233 100644 --- a/drizzle-orm/src/pg-core/table.ts +++ b/drizzle-orm/src/pg-core/table.ts @@ -2,12 +2,12 @@ import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts' import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; import type { CheckBuilder } from './checks.ts'; +import { getPgColumnBuilders, type PgColumnsBuilders } from './columns/all.ts'; import type { PgColumn, PgColumnBuilder, PgColumnBuilderBase } from './columns/common.ts'; import type { ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; -import { getPgColumnBuilders, type PgColumnsBuilders } from './columns/all.ts'; export type PgTableExtraConfig = Record< string, diff --git a/drizzle-orm/src/sql/sql.ts b/drizzle-orm/src/sql/sql.ts index 17f6a7a52..5ff8cf80f 100644 --- a/drizzle-orm/src/sql/sql.ts +++ b/drizzle-orm/src/sql/sql.ts @@ -1,3 +1,4 @@ +import type { CasingCache } from '~/casing.ts'; import { entityKind, is } from '~/entity.ts'; import type { SelectedFields } from '~/operations.ts'; import { isPgEnum } from '~/pg-core/columns/enum.ts'; @@ -7,7 +8,6 @@ import { ViewBaseConfig } from '~/view-common.ts'; import type { AnyColumn } from '../column.ts'; import { Column } from '../column.ts'; import { Table } from '../table.ts'; -import type { CasingCache } from '~/casing.ts'; /** * This class is used to indicate a primitive param value that is used in `sql` tag. diff --git a/drizzle-orm/src/sqlite-core/columns/all.ts b/drizzle-orm/src/sqlite-core/columns/all.ts index 449e123cf..28ca6fb55 100644 --- a/drizzle-orm/src/sqlite-core/columns/all.ts +++ b/drizzle-orm/src/sqlite-core/columns/all.ts @@ -6,14 +6,14 @@ import { real } from './real'; import { text } from './text'; export function getSQLiteColumnBuilders() { - return { - blob, - customType, - integer, - numeric, - real, - text, - }; + return { + blob, + customType, + integer, + numeric, + real, + text, + }; } export type SQLiteColumnBuilders = ReturnType; diff --git a/drizzle-orm/src/sqlite-core/dialect.ts b/drizzle-orm/src/sqlite-core/dialect.ts index 562c89286..eac6cf5b3 100644 --- a/drizzle-orm/src/sqlite-core/dialect.ts +++ b/drizzle-orm/src/sqlite-core/dialect.ts @@ -1,4 +1,5 @@ import { aliasedTable, aliasedTableColumn, mapColumnsInAliasedSQLToAlias, mapColumnsInSQLToAlias } from '~/alias.ts'; +import { CasingCache } from '~/casing.ts'; import type { AnyColumn } from '~/column.ts'; import { Column } from '~/column.ts'; import { entityKind, is } from '~/entity.ts'; @@ -33,7 +34,6 @@ import type { } from './query-builders/select.types.ts'; import type { SQLiteSession } from './session.ts'; import { SQLiteViewBase } from './view-base.ts'; -import { CasingCache } from '~/casing.ts'; export interface SQLiteDialectConfig { casing?: Casing; @@ -657,7 +657,11 @@ export abstract class SQLiteDialect { let field = sql`json_array(${ sql.join( selection.map(({ field }) => - is(field, SQLiteColumn) ? sql.identifier(this.casing.getColumnCasing(field)) : is(field, SQL.Aliased) ? field.sql : field + is(field, SQLiteColumn) + ? sql.identifier(this.casing.getColumnCasing(field)) + : is(field, SQL.Aliased) + ? field.sql + : field ), sql`, `, ) diff --git a/drizzle-orm/src/sqlite-core/table.ts b/drizzle-orm/src/sqlite-core/table.ts index 63084b9c5..c223e2d6f 100644 --- a/drizzle-orm/src/sqlite-core/table.ts +++ b/drizzle-orm/src/sqlite-core/table.ts @@ -2,12 +2,12 @@ import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts' import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; import type { CheckBuilder } from './checks.ts'; +import { getSQLiteColumnBuilders, type SQLiteColumnBuilders } from './columns/all.ts'; import type { SQLiteColumn, SQLiteColumnBuilder, SQLiteColumnBuilderBase } from './columns/common.ts'; import type { ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; import type { IndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; -import { getSQLiteColumnBuilders, type SQLiteColumnBuilders } from './columns/all.ts'; export type SQLiteTableExtraConfig = Record< string, diff --git a/drizzle-orm/tests/casing/casing.test.ts b/drizzle-orm/tests/casing/casing.test.ts index 9a813f447..f43f404a8 100644 --- a/drizzle-orm/tests/casing/casing.test.ts +++ b/drizzle-orm/tests/casing/casing.test.ts @@ -1,28 +1,28 @@ import { describe, it } from 'vitest'; -import { toSnakeCase, toCamelCase } from '~/casing'; +import { toCamelCase, toSnakeCase } from '~/casing'; describe.concurrent('casing', () => { - it('transforms to snake case', ({ expect }) => { - expect(toSnakeCase('drizzleKit')).toEqual('drizzle_kit'); - }); + it('transforms to snake case', ({ expect }) => { + expect(toSnakeCase('drizzleKit')).toEqual('drizzle_kit'); + }); - it('transforms an uppercase acronym/abbreviation to snake case', ({ expect }) => { - expect(toSnakeCase('drizzleORM')).toEqual('drizzle_orm'); - }); + it('transforms an uppercase acronym/abbreviation to snake case', ({ expect }) => { + expect(toSnakeCase('drizzleORM')).toEqual('drizzle_orm'); + }); - it('transforms a camel case acronym/abbreviation to snake case', ({ expect }) => { - expect(toSnakeCase('drizzleOrm')).toEqual('drizzle_orm'); - }); + it('transforms a camel case acronym/abbreviation to snake case', ({ expect }) => { + expect(toSnakeCase('drizzleOrm')).toEqual('drizzle_orm'); + }); - it('transforms an uppercase acronym/abbreviation followed by a word to snake case', ({ expect }) => { - expect(toSnakeCase('drizzleORMAndKit')).toEqual('drizzle_orm_and_kit'); - }); + it('transforms an uppercase acronym/abbreviation followed by a word to snake case', ({ expect }) => { + expect(toSnakeCase('drizzleORMAndKit')).toEqual('drizzle_orm_and_kit'); + }); - it('transforms a camel case acronym/abbreviation followed by a word to snake case', ({ expect }) => { - expect(toSnakeCase('drizzleOrmAndKit')).toEqual('drizzle_orm_and_kit'); - }); + it('transforms a camel case acronym/abbreviation followed by a word to snake case', ({ expect }) => { + expect(toSnakeCase('drizzleOrmAndKit')).toEqual('drizzle_orm_and_kit'); + }); - it('transforms to camel case 1', ({ expect }) => { - expect(toCamelCase('drizzle_kit')).toEqual('drizzleKit'); - }); + it('transforms to camel case 1', ({ expect }) => { + expect(toCamelCase('drizzle_kit')).toEqual('drizzleKit'); + }); }); diff --git a/drizzle-orm/tests/casing/mysql-to-camel.test.ts b/drizzle-orm/tests/casing/mysql-to-camel.test.ts index a5825d6f8..651365485 100644 --- a/drizzle-orm/tests/casing/mysql-to-camel.test.ts +++ b/drizzle-orm/tests/casing/mysql-to-camel.test.ts @@ -1,32 +1,32 @@ +import { Client } from '@planetscale/database'; +import { connect } from '@tidbcloud/serverless'; import { beforeEach, describe, it } from 'vitest'; -import { drizzle as planetscale } from '~/planetscale-serverless'; -import { drizzle as mysql } from '~/tidb-serverless'; import { alias, boolean, int, mysqlSchema, mysqlTable, serial, text, union } from '~/mysql-core'; -import { asc, eq, sql } from '~/sql'; +import { drizzle as planetscale } from '~/planetscale-serverless'; import { relations } from '~/relations'; -import { Client } from '@planetscale/database'; -import { connect } from '@tidbcloud/serverless'; +import { asc, eq, sql } from '~/sql'; +import { drizzle as mysql } from '~/tidb-serverless'; const testSchema = mysqlSchema('test'); const users = mysqlTable('users', { - id: serial().primaryKey(), - first_name: text().notNull(), - last_name: text().notNull(), - // Test that custom aliases remain - age: int('AGE') + id: serial().primaryKey(), + first_name: text().notNull(), + last_name: text().notNull(), + // Test that custom aliases remain + age: int('AGE'), }); const usersRelations = relations(users, ({ one }) => ({ - developers: one(developers), + developers: one(developers), })); const developers = testSchema.table('developers', { - user_id: serial().primaryKey().references(() => users.id), - uses_drizzle_orm: boolean().notNull(), + user_id: serial().primaryKey().references(() => users.id), + uses_drizzle_orm: boolean().notNull(), }); const developersRelations = relations(developers, ({ one }) => ({ - user: one(users, { - fields: [developers.user_id], - references: [users.id], - }), + user: one(users, { + fields: [developers.user_id], + references: [users.id], + }), })); const devs = alias(developers, 'devs'); const schema = { users, usersRelations, developers, developersRelations }; @@ -35,258 +35,265 @@ const db = mysql(connect({}), { schema, casing: 'camelCase' }); const ps = planetscale(new Client({}), { schema, casing: 'camelCase' }); const usersCache = { - 'public.users.id': 'id', - 'public.users.first_name': 'firstName', - 'public.users.last_name': 'lastName', - 'public.users.AGE': 'age', + 'public.users.id': 'id', + 'public.users.first_name': 'firstName', + 'public.users.last_name': 'lastName', + 'public.users.AGE': 'age', }; const developersCache = { - 'test.developers.user_id': 'userId', - 'test.developers.uses_drizzle_orm': 'usesDrizzleOrm', + 'test.developers.user_id': 'userId', + 'test.developers.uses_drizzle_orm': 'usesDrizzleOrm', }; const cache = { - ...usersCache, - ...developersCache, + ...usersCache, + ...developersCache, }; const fullName = sql`${users.first_name} || ' ' || ${users.last_name}`.as('name'); describe('mysql to snake case', () => { - beforeEach(() => { - ps.dialect.casing.clearCache(); - db.dialect.casing.clearCache(); - }); - - it('select', ({ expect }) => { - const query = db - .select({ name: fullName, age: users.age }) - .from(users) - .leftJoin(developers, eq(users.id, developers.user_id)) - .orderBy(asc(users.first_name)); - - expect(query.toSQL()).toEqual({ - sql: 'select `users`.`firstName` || \' \' || `users`.`lastName` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`userId` order by `users`.`firstName` asc', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('select (with alias)', ({ expect }) => { - const query = db - .select({ firstName: users.first_name }) - .from(users) - .leftJoin(devs, eq(users.id, devs.user_id)); - - expect(query.toSQL()).toEqual({ - sql: 'select `users`.`firstName` from `users` left join `test`.`developers` `devs` on `users`.`id` = `devs`.`userId`', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('with CTE', ({ expect }) => { - const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with `cte` as (select `firstName` || \' \' || `lastName` as `name` from `users`) select `name` from `cte`', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('with CTE (with query builder)', ({ expect }) => { - const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with `cte` as (select `firstName` || \' \' || `lastName` as `name` from `users`) select `name` from `cte`', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator', ({ expect }) => { - const query = db - .select({ firstName: users.first_name }) - .from(users) - .union(db.select({ firstName: users.first_name }).from(users)); - - expect(query.toSQL()).toEqual({ - sql: '(select `firstName` from `users`) union (select `firstName` from `users`)', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator (function)', ({ expect }) => { - const query = union( - db.select({ firstName: users.first_name }).from(users), - db.select({ firstName: users.first_name }).from(users) - ); - - expect(query.toSQL()).toEqual({ - sql: '(select `firstName` from `users`) union (select `firstName` from `users`)', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('query (find first)', ({ expect }) => { - const query = db.query.users.findFirst({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - uses_drizzle_orm: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select `users`.`id`, `users`.`AGE`, `users`.`firstName` || \' \' || `users`.`lastName` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`usesDrizzleOrm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ? limit ?', - params: [1, 1, 1], - typings: ['none', 'none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('query (find first, planetscale)', ({ expect }) => { - const query = ps.query.users.findFirst({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - uses_drizzle_orm: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select `id`, `AGE`, `firstName` || \' \' || `lastName` as `name`, (select json_array(`usesDrizzleOrm`) from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ? limit ?', - params: [1, 1, 1], - typings: ['none', 'none', 'none'] - }); - expect(ps.dialect.casing.cache).toEqual(cache); - }); - - it('query (find many)', ({ expect }) => { - const query = db.query.users.findMany({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - uses_drizzle_orm: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select `users`.`id`, `users`.`AGE`, `users`.`firstName` || \' \' || `users`.`lastName` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`usesDrizzleOrm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ?', - params: [1, 1], - typings: ['none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('query (find many, planetscale)', ({ expect }) => { - const query = ps.query.users.findMany({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - uses_drizzle_orm: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select `id`, `AGE`, `firstName` || \' \' || `lastName` as `name`, (select json_array(`usesDrizzleOrm`) from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ?', - params: [1, 1], - typings: ['none', 'none'] - }); - expect(ps.dialect.casing.cache).toEqual(cache); - }); - - it('insert', ({ expect }) => { - const query = db - .insert(users) - .values({ first_name: 'John', last_name: 'Doe', age: 30 }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into `users` (`id`, `firstName`, `lastName`, `AGE`) values (default, ?, ?, ?)', - params: ['John', 'Doe', 30], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('insert (on duplicate key update)', ({ expect }) => { - const query = db - .insert(users) - .values({ first_name: 'John', last_name: 'Doe', age: 30 }) - .onDuplicateKeyUpdate({ set: { age: 31 } }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into `users` (`id`, `firstName`, `lastName`, `AGE`) values (default, ?, ?, ?) on duplicate key update `AGE` = ?', - params: ['John', 'Doe', 30, 31], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('update', ({ expect }) => { - const query = db - .update(users) - .set({ first_name: 'John', last_name: 'Doe', age: 30 }) - .where(eq(users.id, 1)); - - expect(query.toSQL()).toEqual({ - sql: 'update `users` set `firstName` = ?, `lastName` = ?, `AGE` = ? where `users`.`id` = ?', - params: ['John', 'Doe', 30, 1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('delete', ({ expect }) => { - const query = db - .delete(users) - .where(eq(users.id, 1)); - - expect(query.toSQL()).toEqual({ - sql: 'delete from `users` where `users`.`id` = ?', - params: [1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); + beforeEach(() => { + ps.dialect.casing.clearCache(); + db.dialect.casing.clearCache(); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.user_id)) + .orderBy(asc(users.first_name)); + + expect(query.toSQL()).toEqual({ + sql: + "select `users`.`firstName` || ' ' || `users`.`lastName` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`userId` order by `users`.`firstName` asc", + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ firstName: users.first_name }) + .from(users) + .leftJoin(devs, eq(users.id, devs.user_id)); + + expect(query.toSQL()).toEqual({ + sql: + 'select `users`.`firstName` from `users` left join `test`.`developers` `devs` on `users`.`id` = `devs`.`userId`', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: "with `cte` as (select `firstName` || ' ' || `lastName` as `name` from `users`) select `name` from `cte`", + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: "with `cte` as (select `firstName` || ' ' || `lastName` as `name` from `users`) select `name` from `cte`", + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator', ({ expect }) => { + const query = db + .select({ firstName: users.first_name }) + .from(users) + .union(db.select({ firstName: users.first_name }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: '(select `firstName` from `users`) union (select `firstName` from `users`)', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ firstName: users.first_name }).from(users), + db.select({ firstName: users.first_name }).from(users), + ); + + expect(query.toSQL()).toEqual({ + sql: '(select `firstName` from `users`) union (select `firstName` from `users`)', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + "select `users`.`id`, `users`.`AGE`, `users`.`firstName` || ' ' || `users`.`lastName` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`usesDrizzleOrm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ? limit ?", + params: [1, 1, 1], + typings: ['none', 'none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('query (find first, planetscale)', ({ expect }) => { + const query = ps.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + "select `id`, `AGE`, `firstName` || ' ' || `lastName` as `name`, (select json_array(`usesDrizzleOrm`) from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ? limit ?", + params: [1, 1, 1], + typings: ['none', 'none', 'none'], + }); + expect(ps.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + "select `users`.`id`, `users`.`AGE`, `users`.`firstName` || ' ' || `users`.`lastName` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`usesDrizzleOrm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ?", + params: [1, 1], + typings: ['none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many, planetscale)', ({ expect }) => { + const query = ps.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + "select `id`, `AGE`, `firstName` || ' ' || `lastName` as `name`, (select json_array(`usesDrizzleOrm`) from (select * from `developers` `users_developers` where `users_developers`.`userId` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ?", + params: [1, 1], + typings: ['none', 'none'], + }); + expect(ps.dialect.casing.cache).toEqual(cache); + }); + + it('insert', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into `users` (`id`, `firstName`, `lastName`, `AGE`) values (default, ?, ?, ?)', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('insert (on duplicate key update)', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }) + .onDuplicateKeyUpdate({ set: { age: 31 } }); + + expect(query.toSQL()).toEqual({ + sql: + 'insert into `users` (`id`, `firstName`, `lastName`, `AGE`) values (default, ?, ?, ?) on duplicate key update `AGE` = ?', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ first_name: 'John', last_name: 'Doe', age: 30 }) + .where(eq(users.id, 1)); + + expect(query.toSQL()).toEqual({ + sql: 'update `users` set `firstName` = ?, `lastName` = ?, `AGE` = ? where `users`.`id` = ?', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)); + + expect(query.toSQL()).toEqual({ + sql: 'delete from `users` where `users`.`id` = ?', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); }); diff --git a/drizzle-orm/tests/casing/mysql-to-snake.test.ts b/drizzle-orm/tests/casing/mysql-to-snake.test.ts index 9a9655f37..8ce65e2f9 100644 --- a/drizzle-orm/tests/casing/mysql-to-snake.test.ts +++ b/drizzle-orm/tests/casing/mysql-to-snake.test.ts @@ -1,32 +1,32 @@ +import { Client } from '@planetscale/database'; +import { connect } from '@tidbcloud/serverless'; import { beforeEach, describe, it } from 'vitest'; -import { drizzle as planetscale } from '~/planetscale-serverless'; -import { drizzle as mysql } from '~/tidb-serverless'; import { alias, boolean, int, mysqlSchema, mysqlTable, serial, text, union } from '~/mysql-core'; -import { asc, eq, sql } from '~/sql'; +import { drizzle as planetscale } from '~/planetscale-serverless'; import { relations } from '~/relations'; -import { Client } from '@planetscale/database'; -import { connect } from '@tidbcloud/serverless'; +import { asc, eq, sql } from '~/sql'; +import { drizzle as mysql } from '~/tidb-serverless'; const testSchema = mysqlSchema('test'); const users = mysqlTable('users', { - id: serial().primaryKey(), - firstName: text().notNull(), - lastName: text().notNull(), - // Test that custom aliases remain - age: int('AGE') + id: serial().primaryKey(), + firstName: text().notNull(), + lastName: text().notNull(), + // Test that custom aliases remain + age: int('AGE'), }); const usersRelations = relations(users, ({ one }) => ({ - developers: one(developers), + developers: one(developers), })); const developers = testSchema.table('developers', { - userId: serial().primaryKey().references(() => users.id), - usesDrizzleORM: boolean().notNull(), + userId: serial().primaryKey().references(() => users.id), + usesDrizzleORM: boolean().notNull(), }); const developersRelations = relations(developers, ({ one }) => ({ - user: one(users, { - fields: [developers.userId], - references: [users.id], - }), + user: one(users, { + fields: [developers.userId], + references: [users.id], + }), })); const devs = alias(developers, 'devs'); const schema = { users, usersRelations, developers, developersRelations }; @@ -35,258 +35,265 @@ const db = mysql(connect({}), { schema, casing: 'snake_case' }); const ps = planetscale(new Client({}), { schema, casing: 'snake_case' }); const usersCache = { - 'public.users.id': 'id', - 'public.users.firstName': 'first_name', - 'public.users.lastName': 'last_name', - 'public.users.AGE': 'age', + 'public.users.id': 'id', + 'public.users.firstName': 'first_name', + 'public.users.lastName': 'last_name', + 'public.users.AGE': 'age', }; const developersCache = { - 'test.developers.userId': 'user_id', - 'test.developers.usesDrizzleORM': 'uses_drizzle_orm', + 'test.developers.userId': 'user_id', + 'test.developers.usesDrizzleORM': 'uses_drizzle_orm', }; const cache = { - ...usersCache, - ...developersCache, + ...usersCache, + ...developersCache, }; const fullName = sql`${users.firstName} || ' ' || ${users.lastName}`.as('name'); describe('mysql to snake case', () => { - beforeEach(() => { - db.dialect.casing.clearCache(); - ps.dialect.casing.clearCache(); - }); - - it('select', ({ expect }) => { - const query = db - .select({ name: fullName, age: users.age }) - .from(users) - .leftJoin(developers, eq(users.id, developers.userId)) - .orderBy(asc(users.firstName)); - - expect(query.toSQL()).toEqual({ - sql: 'select `users`.`first_name` || \' \' || `users`.`last_name` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`user_id` order by `users`.`first_name` asc', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('select (with alias)', ({ expect }) => { - const query = db - .select({ firstName: users.firstName }) - .from(users) - .leftJoin(devs, eq(users.id, devs.userId)); - - expect(query.toSQL()).toEqual({ - sql: 'select `users`.`first_name` from `users` left join `test`.`developers` `devs` on `users`.`id` = `devs`.`user_id`', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('with CTE', ({ expect }) => { - const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with `cte` as (select `first_name` || \' \' || `last_name` as `name` from `users`) select `name` from `cte`', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('with CTE (with query builder)', ({ expect }) => { - const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with `cte` as (select `first_name` || \' \' || `last_name` as `name` from `users`) select `name` from `cte`', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator', ({ expect }) => { - const query = db - .select({ firstName: users.firstName }) - .from(users) - .union(db.select({ firstName: users.firstName }).from(users)); - - expect(query.toSQL()).toEqual({ - sql: '(select `first_name` from `users`) union (select `first_name` from `users`)', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator (function)', ({ expect }) => { - const query = union( - db.select({ firstName: users.firstName }).from(users), - db.select({ firstName: users.firstName }).from(users) - ); - - expect(query.toSQL()).toEqual({ - sql: '(select `first_name` from `users`) union (select `first_name` from `users`)', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('query (find first)', ({ expect }) => { - const query = db.query.users.findFirst({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - usesDrizzleORM: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select `users`.`id`, `users`.`AGE`, `users`.`first_name` || \' \' || `users`.`last_name` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`uses_drizzle_orm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ? limit ?', - params: [1, 1, 1], - typings: ['none', 'none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('query (find first, planetscale)', ({ expect }) => { - const query = ps.query.users.findFirst({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - usesDrizzleORM: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select `id`, `AGE`, `first_name` || \' \' || `last_name` as `name`, (select json_array(`uses_drizzle_orm`) from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ? limit ?', - params: [1, 1, 1], - typings: ['none', 'none', 'none'] - }); - expect(ps.dialect.casing.cache).toEqual(cache); - }); - - it('query (find many)', ({ expect }) => { - const query = db.query.users.findMany({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - usesDrizzleORM: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select `users`.`id`, `users`.`AGE`, `users`.`first_name` || \' \' || `users`.`last_name` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`uses_drizzle_orm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ?', - params: [1, 1], - typings: ['none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('query (find many, planetscale)', ({ expect }) => { - const query = ps.query.users.findMany({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - usesDrizzleORM: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select `id`, `AGE`, `first_name` || \' \' || `last_name` as `name`, (select json_array(`uses_drizzle_orm`) from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ?', - params: [1, 1], - typings: ['none', 'none'] - }); - expect(ps.dialect.casing.cache).toEqual(cache); - }); - - it('insert', ({ expect }) => { - const query = db - .insert(users) - .values({ firstName: 'John', lastName: 'Doe', age: 30 }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into `users` (`id`, `first_name`, `last_name`, `AGE`) values (default, ?, ?, ?)', - params: ['John', 'Doe', 30], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('insert (on duplicate key update)', ({ expect }) => { - const query = db - .insert(users) - .values({ firstName: 'John', lastName: 'Doe', age: 30 }) - .onDuplicateKeyUpdate({ set: { age: 31 } }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into `users` (`id`, `first_name`, `last_name`, `AGE`) values (default, ?, ?, ?) on duplicate key update `AGE` = ?', - params: ['John', 'Doe', 30, 31], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('update', ({ expect }) => { - const query = db - .update(users) - .set({ firstName: 'John', lastName: 'Doe', age: 30 }) - .where(eq(users.id, 1)); - - expect(query.toSQL()).toEqual({ - sql: 'update `users` set `first_name` = ?, `last_name` = ?, `AGE` = ? where `users`.`id` = ?', - params: ['John', 'Doe', 30, 1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('delete', ({ expect }) => { - const query = db - .delete(users) - .where(eq(users.id, 1)); - - expect(query.toSQL()).toEqual({ - sql: 'delete from `users` where `users`.`id` = ?', - params: [1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); + beforeEach(() => { + db.dialect.casing.clearCache(); + ps.dialect.casing.clearCache(); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.userId)) + .orderBy(asc(users.firstName)); + + expect(query.toSQL()).toEqual({ + sql: + "select `users`.`first_name` || ' ' || `users`.`last_name` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`user_id` order by `users`.`first_name` asc", + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .leftJoin(devs, eq(users.id, devs.userId)); + + expect(query.toSQL()).toEqual({ + sql: + 'select `users`.`first_name` from `users` left join `test`.`developers` `devs` on `users`.`id` = `devs`.`user_id`', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: "with `cte` as (select `first_name` || ' ' || `last_name` as `name` from `users`) select `name` from `cte`", + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: "with `cte` as (select `first_name` || ' ' || `last_name` as `name` from `users`) select `name` from `cte`", + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .union(db.select({ firstName: users.firstName }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: '(select `first_name` from `users`) union (select `first_name` from `users`)', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ firstName: users.firstName }).from(users), + db.select({ firstName: users.firstName }).from(users), + ); + + expect(query.toSQL()).toEqual({ + sql: '(select `first_name` from `users`) union (select `first_name` from `users`)', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + "select `users`.`id`, `users`.`AGE`, `users`.`first_name` || ' ' || `users`.`last_name` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`uses_drizzle_orm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ? limit ?", + params: [1, 1, 1], + typings: ['none', 'none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('query (find first, planetscale)', ({ expect }) => { + const query = ps.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + "select `id`, `AGE`, `first_name` || ' ' || `last_name` as `name`, (select json_array(`uses_drizzle_orm`) from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ? limit ?", + params: [1, 1, 1], + typings: ['none', 'none', 'none'], + }); + expect(ps.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + "select `users`.`id`, `users`.`AGE`, `users`.`first_name` || ' ' || `users`.`last_name` as `name`, `users_developers`.`data` as `developers` from `users` left join lateral (select json_array(`users_developers`.`uses_drizzle_orm`) as `data` from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) `users_developers` on true where `users`.`id` = ?", + params: [1, 1], + typings: ['none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many, planetscale)', ({ expect }) => { + const query = ps.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + "select `id`, `AGE`, `first_name` || ' ' || `last_name` as `name`, (select json_array(`uses_drizzle_orm`) from (select * from `developers` `users_developers` where `users_developers`.`user_id` = `users`.`id` limit ?) `users_developers`) as `developers` from `users` where `users`.`id` = ?", + params: [1, 1], + typings: ['none', 'none'], + }); + expect(ps.dialect.casing.cache).toEqual(cache); + }); + + it('insert', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }); + + expect(query.toSQL()).toEqual({ + sql: 'insert into `users` (`id`, `first_name`, `last_name`, `AGE`) values (default, ?, ?, ?)', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('insert (on duplicate key update)', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }) + .onDuplicateKeyUpdate({ set: { age: 31 } }); + + expect(query.toSQL()).toEqual({ + sql: + 'insert into `users` (`id`, `first_name`, `last_name`, `AGE`) values (default, ?, ?, ?) on duplicate key update `AGE` = ?', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ firstName: 'John', lastName: 'Doe', age: 30 }) + .where(eq(users.id, 1)); + + expect(query.toSQL()).toEqual({ + sql: 'update `users` set `first_name` = ?, `last_name` = ?, `AGE` = ? where `users`.`id` = ?', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)); + + expect(query.toSQL()).toEqual({ + sql: 'delete from `users` where `users`.`id` = ?', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); }); diff --git a/drizzle-orm/tests/casing/pg-to-camel.test.ts b/drizzle-orm/tests/casing/pg-to-camel.test.ts index 431ddc883..8d4420403 100644 --- a/drizzle-orm/tests/casing/pg-to-camel.test.ts +++ b/drizzle-orm/tests/casing/pg-to-camel.test.ts @@ -1,30 +1,30 @@ +import postgres from 'postgres'; import { beforeEach, describe, it } from 'vitest'; -import { drizzle } from '~/postgres-js'; import { alias, boolean, integer, pgSchema, pgTable, serial, text, union } from '~/pg-core'; -import { asc, eq, sql } from '~/sql'; +import { drizzle } from '~/postgres-js'; import { relations } from '~/relations'; -import postgres from 'postgres'; +import { asc, eq, sql } from '~/sql'; const testSchema = pgSchema('test'); const users = pgTable('users', { - id: serial().primaryKey(), - first_name: text().notNull(), - last_name: text().notNull(), - // Test that custom aliases remain - age: integer('AGE') + id: serial().primaryKey(), + first_name: text().notNull(), + last_name: text().notNull(), + // Test that custom aliases remain + age: integer('AGE'), }); const usersRelations = relations(users, ({ one }) => ({ - developers: one(developers), + developers: one(developers), })); const developers = testSchema.table('developers', { - user_id: serial().primaryKey().references(() => users.id), - uses_drizzle_orm: boolean().notNull(), + user_id: serial().primaryKey().references(() => users.id), + uses_drizzle_orm: boolean().notNull(), }); const developersRelations = relations(developers, ({ one }) => ({ - user: one(users, { - fields: [developers.user_id], - references: [users.id], - }), + user: one(users, { + fields: [developers.user_id], + references: [users.id], + }), })); const devs = alias(developers, 'devs'); const schema = { users, usersRelations, developers, developersRelations }; @@ -32,208 +32,215 @@ const schema = { users, usersRelations, developers, developersRelations }; const db = drizzle(postgres(''), { schema, casing: 'camelCase' }); const usersCache = { - 'public.users.id': 'id', - 'public.users.first_name': 'firstName', - 'public.users.last_name': 'lastName', - 'public.users.AGE': 'age', + 'public.users.id': 'id', + 'public.users.first_name': 'firstName', + 'public.users.last_name': 'lastName', + 'public.users.AGE': 'age', }; const developersCache = { - 'test.developers.user_id': 'userId', - 'test.developers.uses_drizzle_orm': 'usesDrizzleOrm', + 'test.developers.user_id': 'userId', + 'test.developers.uses_drizzle_orm': 'usesDrizzleOrm', }; const cache = { - ...usersCache, - ...developersCache, + ...usersCache, + ...developersCache, }; const fullName = sql`${users.first_name} || ' ' || ${users.last_name}`.as('name'); describe('postgres to camel case', () => { - beforeEach(() => { - db.dialect.casing.clearCache(); - }); - - it('select', ({ expect }) => { - const query = db - .select({ name: fullName, age: users.age }) - .from(users) - .leftJoin(developers, eq(users.id, developers.user_id)) - .orderBy(asc(users.first_name)); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."userId" order by "users"."firstName" asc', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('select (with alias)', ({ expect }) => { - const query = db - .select({ first_name: users.first_name }) - .from(users) - .leftJoin(devs, eq(users.id, devs.user_id)); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."firstName" from "users" left join "test"."developers" "devs" on "users"."id" = "devs"."userId"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('with CTE', ({ expect }) => { - const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('with CTE (with query builder)', ({ expect }) => { - const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator', ({ expect }) => { - const query = db - .select({ first_name: users.first_name }) - .from(users) - .union(db.select({ first_name: users.first_name }).from(users)); - - expect(query.toSQL()).toEqual({ - sql: '(select "firstName" from "users") union (select "firstName" from "users")', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator (function)', ({ expect }) => { - const query = union( - db.select({ first_name: users.first_name }).from(users), - db.select({ first_name: users.first_name }).from(users) - ); - - expect(query.toSQL()).toEqual({ - sql: '(select "firstName" from "users") union (select "firstName" from "users")', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('query (find first)', ({ expect }) => { - const query = db.query.users.findFirst({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - uses_drizzle_orm: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."id", "users"."AGE", "users"."firstName" || \' \' || "users"."lastName" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."usesDrizzleOrm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."userId" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2 limit $3', - params: [1, 1, 1], - typings: ['none', 'none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('query (find many)', ({ expect }) => { - const query = db.query.users.findMany({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - uses_drizzle_orm: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."id", "users"."AGE", "users"."firstName" || \' \' || "users"."lastName" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."usesDrizzleOrm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."userId" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2', - params: [1, 1], - typings: ['none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('insert (on conflict do nothing)', ({ expect }) => { - const query = db - .insert(users) - .values({ first_name: 'John', last_name: 'Doe', age: 30 }) - .onConflictDoNothing({ target: users.first_name }) - .returning({ first_name: users.first_name, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into "users" ("id", "firstName", "lastName", "AGE") values (default, $1, $2, $3) on conflict ("firstName") do nothing returning "firstName", "AGE"', - params: ['John', 'Doe', 30], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('insert (on conflict do update)', ({ expect }) => { - const query = db - .insert(users) - .values({ first_name: 'John', last_name: 'Doe', age: 30 }) - .onConflictDoUpdate({ target: users.first_name, set: { age: 31 } }) - .returning({ first_name: users.first_name, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into "users" ("id", "firstName", "lastName", "AGE") values (default, $1, $2, $3) on conflict ("firstName") do update set "AGE" = $4 returning "firstName", "AGE"', - params: ['John', 'Doe', 30, 31], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('update', ({ expect }) => { - const query = db - .update(users) - .set({ first_name: 'John', last_name: 'Doe', age: 30 }) - .where(eq(users.id, 1)) - .returning({ first_name: users.first_name, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'update "users" set "firstName" = $1, "lastName" = $2, "AGE" = $3 where "users"."id" = $4 returning "firstName", "AGE"', - params: ['John', 'Doe', 30, 1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('delete', ({ expect }) => { - const query = db - .delete(users) - .where(eq(users.id, 1)) - .returning({ first_name: users.first_name, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'delete from "users" where "users"."id" = $1 returning "firstName", "AGE"', - params: [1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); + beforeEach(() => { + db.dialect.casing.clearCache(); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.user_id)) + .orderBy(asc(users.first_name)); + + expect(query.toSQL()).toEqual({ + sql: + 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."userId" order by "users"."firstName" asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ first_name: users.first_name }) + .from(users) + .leftJoin(devs, eq(users.id, devs.user_id)); + + expect(query.toSQL()).toEqual({ + sql: + 'select "users"."firstName" from "users" left join "test"."developers" "devs" on "users"."id" = "devs"."userId"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator', ({ expect }) => { + const query = db + .select({ first_name: users.first_name }) + .from(users) + .union(db.select({ first_name: users.first_name }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: '(select "firstName" from "users") union (select "firstName" from "users")', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ first_name: users.first_name }).from(users), + db.select({ first_name: users.first_name }).from(users), + ); + + expect(query.toSQL()).toEqual({ + sql: '(select "firstName" from "users") union (select "firstName" from "users")', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + 'select "users"."id", "users"."AGE", "users"."firstName" || \' \' || "users"."lastName" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."usesDrizzleOrm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."userId" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2 limit $3', + params: [1, 1, 1], + typings: ['none', 'none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + 'select "users"."id", "users"."AGE", "users"."firstName" || \' \' || "users"."lastName" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."usesDrizzleOrm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."userId" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2', + params: [1, 1], + typings: ['none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('insert (on conflict do nothing)', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }) + .onConflictDoNothing({ target: users.first_name }) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'insert into "users" ("id", "firstName", "lastName", "AGE") values (default, $1, $2, $3) on conflict ("firstName") do nothing returning "firstName", "AGE"', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('insert (on conflict do update)', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }) + .onConflictDoUpdate({ target: users.first_name, set: { age: 31 } }) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'insert into "users" ("id", "firstName", "lastName", "AGE") values (default, $1, $2, $3) on conflict ("firstName") do update set "AGE" = $4 returning "firstName", "AGE"', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ first_name: 'John', last_name: 'Doe', age: 30 }) + .where(eq(users.id, 1)) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'update "users" set "firstName" = $1, "lastName" = $2, "AGE" = $3 where "users"."id" = $4 returning "firstName", "AGE"', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'delete from "users" where "users"."id" = $1 returning "firstName", "AGE"', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); }); diff --git a/drizzle-orm/tests/casing/pg-to-snake.test.ts b/drizzle-orm/tests/casing/pg-to-snake.test.ts index 8ffe231de..0384e70ca 100644 --- a/drizzle-orm/tests/casing/pg-to-snake.test.ts +++ b/drizzle-orm/tests/casing/pg-to-snake.test.ts @@ -1,30 +1,30 @@ +import postgres from 'postgres'; import { beforeEach, describe, it } from 'vitest'; -import { drizzle } from '~/postgres-js'; import { alias, boolean, integer, pgSchema, pgTable, serial, text, union } from '~/pg-core'; -import { asc, eq, sql } from '~/sql'; +import { drizzle } from '~/postgres-js'; import { relations } from '~/relations'; -import postgres from 'postgres'; +import { asc, eq, sql } from '~/sql'; const testSchema = pgSchema('test'); const users = pgTable('users', { - id: serial().primaryKey(), - firstName: text().notNull(), - lastName: text().notNull(), - // Test that custom aliases remain - age: integer('AGE') + id: serial().primaryKey(), + firstName: text().notNull(), + lastName: text().notNull(), + // Test that custom aliases remain + age: integer('AGE'), }); const usersRelations = relations(users, ({ one }) => ({ - developers: one(developers), + developers: one(developers), })); const developers = testSchema.table('developers', { - userId: serial().primaryKey().references(() => users.id), - usesDrizzleORM: boolean().notNull(), + userId: serial().primaryKey().references(() => users.id), + usesDrizzleORM: boolean().notNull(), }); const developersRelations = relations(developers, ({ one }) => ({ - user: one(users, { - fields: [developers.userId], - references: [users.id], - }), + user: one(users, { + fields: [developers.userId], + references: [users.id], + }), })); const devs = alias(developers, 'devs'); const schema = { users, usersRelations, developers, developersRelations }; @@ -32,208 +32,217 @@ const schema = { users, usersRelations, developers, developersRelations }; const db = drizzle(postgres(''), { schema, casing: 'snake_case' }); const usersCache = { - 'public.users.id': 'id', - 'public.users.firstName': 'first_name', - 'public.users.lastName': 'last_name', - 'public.users.AGE': 'age', + 'public.users.id': 'id', + 'public.users.firstName': 'first_name', + 'public.users.lastName': 'last_name', + 'public.users.AGE': 'age', }; const developersCache = { - 'test.developers.userId': 'user_id', - 'test.developers.usesDrizzleORM': 'uses_drizzle_orm', + 'test.developers.userId': 'user_id', + 'test.developers.usesDrizzleORM': 'uses_drizzle_orm', }; const cache = { - ...usersCache, - ...developersCache, + ...usersCache, + ...developersCache, }; const fullName = sql`${users.firstName} || ' ' || ${users.lastName}`.as('name'); describe('postgres to snake case', () => { - beforeEach(() => { - db.dialect.casing.clearCache(); - }); - - it('select', ({ expect }) => { - const query = db - .select({ name: fullName, age: users.age }) - .from(users) - .leftJoin(developers, eq(users.id, developers.userId)) - .orderBy(asc(users.firstName)); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."user_id" order by "users"."first_name" asc', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('select (with alias)', ({ expect }) => { - const query = db - .select({ firstName: users.firstName }) - .from(users) - .leftJoin(devs, eq(users.id, devs.userId)); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."first_name" from "users" left join "test"."developers" "devs" on "users"."id" = "devs"."user_id"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('with CTE', ({ expect }) => { - const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('with CTE (with query builder)', ({ expect }) => { - const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator', ({ expect }) => { - const query = db - .select({ firstName: users.firstName }) - .from(users) - .union(db.select({ firstName: users.firstName }).from(users)); - - expect(query.toSQL()).toEqual({ - sql: '(select "first_name" from "users") union (select "first_name" from "users")', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator (function)', ({ expect }) => { - const query = union( - db.select({ firstName: users.firstName }).from(users), - db.select({ firstName: users.firstName }).from(users) - ); - - expect(query.toSQL()).toEqual({ - sql: '(select "first_name" from "users") union (select "first_name" from "users")', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('query (find first)', ({ expect }) => { - const query = db.query.users.findFirst({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - usesDrizzleORM: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."id", "users"."AGE", "users"."first_name" || \' \' || "users"."last_name" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."uses_drizzle_orm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2 limit $3', - params: [1, 1, 1], - typings: ['none', 'none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('query (find many)', ({ expect }) => { - const query = db.query.users.findMany({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - usesDrizzleORM: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."id", "users"."AGE", "users"."first_name" || \' \' || "users"."last_name" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."uses_drizzle_orm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2', - params: [1, 1], - typings: ['none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('insert (on conflict do nothing)', ({ expect }) => { - const query = db - .insert(users) - .values({ firstName: 'John', lastName: 'Doe', age: 30 }) - .onConflictDoNothing({ target: users.firstName }) - .returning({ firstName: users.firstName, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into "users" ("id", "first_name", "last_name", "AGE") values (default, $1, $2, $3) on conflict ("first_name") do nothing returning "first_name", "AGE"', - params: ['John', 'Doe', 30], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('insert (on conflict do update)', ({ expect }) => { - const query = db - .insert(users) - .values({ firstName: 'John', lastName: 'Doe', age: 30 }) - .onConflictDoUpdate({ target: users.firstName, set: { age: 31 } }) - .returning({ firstName: users.firstName, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into "users" ("id", "first_name", "last_name", "AGE") values (default, $1, $2, $3) on conflict ("first_name") do update set "AGE" = $4 returning "first_name", "AGE"', - params: ['John', 'Doe', 30, 31], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('update', ({ expect }) => { - const query = db - .update(users) - .set({ firstName: 'John', lastName: 'Doe', age: 30 }) - .where(eq(users.id, 1)) - .returning({ firstName: users.firstName, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'update "users" set "first_name" = $1, "last_name" = $2, "AGE" = $3 where "users"."id" = $4 returning "first_name", "AGE"', - params: ['John', 'Doe', 30, 1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('delete', ({ expect }) => { - const query = db - .delete(users) - .where(eq(users.id, 1)) - .returning({ firstName: users.firstName, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'delete from "users" where "users"."id" = $1 returning "first_name", "AGE"', - params: [1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); + beforeEach(() => { + db.dialect.casing.clearCache(); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.userId)) + .orderBy(asc(users.firstName)); + + expect(query.toSQL()).toEqual({ + sql: + 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."user_id" order by "users"."first_name" asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .leftJoin(devs, eq(users.id, devs.userId)); + + expect(query.toSQL()).toEqual({ + sql: + 'select "users"."first_name" from "users" left join "test"."developers" "devs" on "users"."id" = "devs"."user_id"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: + 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: + 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .union(db.select({ firstName: users.firstName }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: '(select "first_name" from "users") union (select "first_name" from "users")', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ firstName: users.firstName }).from(users), + db.select({ firstName: users.firstName }).from(users), + ); + + expect(query.toSQL()).toEqual({ + sql: '(select "first_name" from "users") union (select "first_name" from "users")', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + 'select "users"."id", "users"."AGE", "users"."first_name" || \' \' || "users"."last_name" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."uses_drizzle_orm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2 limit $3', + params: [1, 1, 1], + typings: ['none', 'none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + 'select "users"."id", "users"."AGE", "users"."first_name" || \' \' || "users"."last_name" as "name", "users_developers"."data" as "developers" from "users" left join lateral (select json_build_array("users_developers"."uses_drizzle_orm") as "data" from (select * from "test"."developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit $1) "users_developers") "users_developers" on true where "users"."id" = $2', + params: [1, 1], + typings: ['none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('insert (on conflict do nothing)', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }) + .onConflictDoNothing({ target: users.firstName }) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'insert into "users" ("id", "first_name", "last_name", "AGE") values (default, $1, $2, $3) on conflict ("first_name") do nothing returning "first_name", "AGE"', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('insert (on conflict do update)', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }) + .onConflictDoUpdate({ target: users.firstName, set: { age: 31 } }) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'insert into "users" ("id", "first_name", "last_name", "AGE") values (default, $1, $2, $3) on conflict ("first_name") do update set "AGE" = $4 returning "first_name", "AGE"', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ firstName: 'John', lastName: 'Doe', age: 30 }) + .where(eq(users.id, 1)) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'update "users" set "first_name" = $1, "last_name" = $2, "AGE" = $3 where "users"."id" = $4 returning "first_name", "AGE"', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'delete from "users" where "users"."id" = $1 returning "first_name", "AGE"', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); }); diff --git a/drizzle-orm/tests/casing/sqlite-to-camel.test.ts b/drizzle-orm/tests/casing/sqlite-to-camel.test.ts index edab894b2..acfb55226 100644 --- a/drizzle-orm/tests/casing/sqlite-to-camel.test.ts +++ b/drizzle-orm/tests/casing/sqlite-to-camel.test.ts @@ -1,29 +1,29 @@ +import Database from 'better-sqlite3'; import { beforeEach, describe, it } from 'vitest'; import { drizzle } from '~/better-sqlite3'; -import { alias, integer, sqliteTable, text, union } from '~/sqlite-core'; -import { asc, eq, sql } from '~/sql'; import { relations } from '~/relations'; -import Database from 'better-sqlite3'; +import { asc, eq, sql } from '~/sql'; +import { alias, integer, sqliteTable, text, union } from '~/sqlite-core'; const users = sqliteTable('users', { - id: integer().primaryKey({ autoIncrement: true }), - first_name: text().notNull(), - last_name: text().notNull(), - // Test that custom aliases remain - age: integer('AGE') + id: integer().primaryKey({ autoIncrement: true }), + first_name: text().notNull(), + last_name: text().notNull(), + // Test that custom aliases remain + age: integer('AGE'), }); const usersRelations = relations(users, ({ one }) => ({ - developers: one(developers), + developers: one(developers), })); const developers = sqliteTable('developers', { - user_id: integer().primaryKey().references(() => users.id), - uses_drizzle_orm: integer({ mode: 'boolean' }).notNull(), + user_id: integer().primaryKey().references(() => users.id), + uses_drizzle_orm: integer({ mode: 'boolean' }).notNull(), }); const developersRelations = relations(developers, ({ one }) => ({ - user: one(users, { - fields: [developers.user_id], - references: [users.id], - }), + user: one(users, { + fields: [developers.user_id], + references: [users.id], + }), })); const devs = alias(developers, 'devs'); const schema = { users, usersRelations, developers, developersRelations }; @@ -31,208 +31,214 @@ const schema = { users, usersRelations, developers, developersRelations }; const db = drizzle(new Database(':memory:'), { schema, casing: 'camelCase' }); const usersCache = { - 'public.users.id': 'id', - 'public.users.first_name': 'firstName', - 'public.users.last_name': 'lastName', - 'public.users.AGE': 'age', + 'public.users.id': 'id', + 'public.users.first_name': 'firstName', + 'public.users.last_name': 'lastName', + 'public.users.AGE': 'age', }; const developersCache = { - 'public.developers.user_id': 'userId', - 'public.developers.uses_drizzle_orm': 'usesDrizzleOrm', + 'public.developers.user_id': 'userId', + 'public.developers.uses_drizzle_orm': 'usesDrizzleOrm', }; const cache = { - ...usersCache, - ...developersCache, + ...usersCache, + ...developersCache, }; const fullName = sql`${users.first_name} || ' ' || ${users.last_name}`.as('name'); describe('sqlite to camel case', () => { - beforeEach(() => { - db.dialect.casing.clearCache(); - }); - - it('select', ({ expect }) => { - const query = db - .select({ name: fullName, age: users.age }) - .from(users) - .leftJoin(developers, eq(users.id, developers.user_id)) - .orderBy(asc(users.first_name)); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "developers" on "users"."id" = "developers"."userId" order by "users"."firstName" asc', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('select (with alias)', ({ expect }) => { - const query = db - .select({ first_name: users.first_name }) - .from(users) - .leftJoin(devs, eq(users.id, devs.user_id)); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."firstName" from "users" left join "developers" "devs" on "users"."id" = "devs"."userId"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('with CTE', ({ expect }) => { - const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('with CTE (with query builder)', ({ expect }) => { - const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator', ({ expect }) => { - const query = db - .select({ first_name: users.first_name }) - .from(users) - .union(db.select({ first_name: users.first_name }).from(users)); - - expect(query.toSQL()).toEqual({ - sql: 'select "firstName" from "users" union select "firstName" from "users"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator (function)', ({ expect }) => { - const query = union( - db.select({ first_name: users.first_name }).from(users), - db.select({ first_name: users.first_name }).from(users) - ); - - expect(query.toSQL()).toEqual({ - sql: 'select "firstName" from "users" union select "firstName" from "users"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('query (find first)', ({ expect }) => { - const query = db.query.users.findFirst({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - uses_drizzle_orm: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select "id", "AGE", "firstName" || \' \' || "lastName" as "name", (select json_array("usesDrizzleOrm") as "data" from (select * from "developers" "users_developers" where "users_developers"."userId" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ? limit ?', - params: [1, 1, 1], - typings: ['none', 'none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('query (find many)', ({ expect }) => { - const query = db.query.users.findMany({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - uses_drizzle_orm: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select "id", "AGE", "firstName" || \' \' || "lastName" as "name", (select json_array("usesDrizzleOrm") as "data" from (select * from "developers" "users_developers" where "users_developers"."userId" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ?', - params: [1, 1], - typings: ['none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('insert (on conflict do nothing)', ({ expect }) => { - const query = db - .insert(users) - .values({ first_name: 'John', last_name: 'Doe', age: 30 }) - .onConflictDoNothing({ target: users.first_name }) - .returning({ first_name: users.first_name, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into "users" ("id", "firstName", "lastName", "AGE") values (null, ?, ?, ?) on conflict ("users"."firstName") do nothing returning "firstName", "AGE"', - params: ['John', 'Doe', 30], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('insert (on conflict do update)', ({ expect }) => { - const query = db - .insert(users) - .values({ first_name: 'John', last_name: 'Doe', age: 30 }) - .onConflictDoUpdate({ target: users.first_name, set: { age: 31 } }) - .returning({ first_name: users.first_name, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into "users" ("id", "firstName", "lastName", "AGE") values (null, ?, ?, ?) on conflict ("users"."firstName") do update set "AGE" = ? returning "firstName", "AGE"', - params: ['John', 'Doe', 30, 31], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('update', ({ expect }) => { - const query = db - .update(users) - .set({ first_name: 'John', last_name: 'Doe', age: 30 }) - .where(eq(users.id, 1)) - .returning({ first_name: users.first_name, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'update "users" set "firstName" = ?, "lastName" = ?, "AGE" = ? where "users"."id" = ? returning "firstName", "AGE"', - params: ['John', 'Doe', 30, 1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('delete', ({ expect }) => { - const query = db - .delete(users) - .where(eq(users.id, 1)) - .returning({ first_name: users.first_name, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'delete from "users" where "users"."id" = ? returning "firstName", "AGE"', - params: [1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); + beforeEach(() => { + db.dialect.casing.clearCache(); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.user_id)) + .orderBy(asc(users.first_name)); + + expect(query.toSQL()).toEqual({ + sql: + 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "developers" on "users"."id" = "developers"."userId" order by "users"."firstName" asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ first_name: users.first_name }) + .from(users) + .leftJoin(devs, eq(users.id, devs.user_id)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."firstName" from "users" left join "developers" "devs" on "users"."id" = "devs"."userId"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: 'with "cte" as (select "firstName" || \' \' || "lastName" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator', ({ expect }) => { + const query = db + .select({ first_name: users.first_name }) + .from(users) + .union(db.select({ first_name: users.first_name }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: 'select "firstName" from "users" union select "firstName" from "users"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ first_name: users.first_name }).from(users), + db.select({ first_name: users.first_name }).from(users), + ); + + expect(query.toSQL()).toEqual({ + sql: 'select "firstName" from "users" union select "firstName" from "users"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + 'select "id", "AGE", "firstName" || \' \' || "lastName" as "name", (select json_array("usesDrizzleOrm") as "data" from (select * from "developers" "users_developers" where "users_developers"."userId" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ? limit ?', + params: [1, 1, 1], + typings: ['none', 'none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + uses_drizzle_orm: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + 'select "id", "AGE", "firstName" || \' \' || "lastName" as "name", (select json_array("usesDrizzleOrm") as "data" from (select * from "developers" "users_developers" where "users_developers"."userId" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ?', + params: [1, 1], + typings: ['none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('insert (on conflict do nothing)', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }) + .onConflictDoNothing({ target: users.first_name }) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'insert into "users" ("id", "firstName", "lastName", "AGE") values (null, ?, ?, ?) on conflict ("users"."firstName") do nothing returning "firstName", "AGE"', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('insert (on conflict do update)', ({ expect }) => { + const query = db + .insert(users) + .values({ first_name: 'John', last_name: 'Doe', age: 30 }) + .onConflictDoUpdate({ target: users.first_name, set: { age: 31 } }) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'insert into "users" ("id", "firstName", "lastName", "AGE") values (null, ?, ?, ?) on conflict ("users"."firstName") do update set "AGE" = ? returning "firstName", "AGE"', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ first_name: 'John', last_name: 'Doe', age: 30 }) + .where(eq(users.id, 1)) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'update "users" set "firstName" = ?, "lastName" = ?, "AGE" = ? where "users"."id" = ? returning "firstName", "AGE"', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)) + .returning({ first_name: users.first_name, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'delete from "users" where "users"."id" = ? returning "firstName", "AGE"', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); }); diff --git a/drizzle-orm/tests/casing/sqlite-to-snake.test.ts b/drizzle-orm/tests/casing/sqlite-to-snake.test.ts index 2a8d5f6a8..d8f2a71a2 100644 --- a/drizzle-orm/tests/casing/sqlite-to-snake.test.ts +++ b/drizzle-orm/tests/casing/sqlite-to-snake.test.ts @@ -1,29 +1,29 @@ +import Database from 'better-sqlite3'; import { beforeEach, describe, it } from 'vitest'; import { drizzle } from '~/better-sqlite3'; -import { alias, integer, sqliteTable, text, union } from '~/sqlite-core'; -import { asc, eq, sql } from '~/sql'; import { relations } from '~/relations'; -import Database from 'better-sqlite3'; +import { asc, eq, sql } from '~/sql'; +import { alias, integer, sqliteTable, text, union } from '~/sqlite-core'; const users = sqliteTable('users', { - id: integer().primaryKey({ autoIncrement: true }), - firstName: text().notNull(), - lastName: text().notNull(), - // Test that custom aliases remain - age: integer('AGE') + id: integer().primaryKey({ autoIncrement: true }), + firstName: text().notNull(), + lastName: text().notNull(), + // Test that custom aliases remain + age: integer('AGE'), }); const usersRelations = relations(users, ({ one }) => ({ - developers: one(developers), + developers: one(developers), })); const developers = sqliteTable('developers', { - userId: integer().primaryKey().references(() => users.id), - usesDrizzleORM: integer({ mode: 'boolean' }).notNull(), + userId: integer().primaryKey().references(() => users.id), + usesDrizzleORM: integer({ mode: 'boolean' }).notNull(), }); const developersRelations = relations(developers, ({ one }) => ({ - user: one(users, { - fields: [developers.userId], - references: [users.id], - }), + user: one(users, { + fields: [developers.userId], + references: [users.id], + }), })); const devs = alias(developers, 'devs'); const schema = { users, usersRelations, developers, developersRelations }; @@ -31,208 +31,216 @@ const schema = { users, usersRelations, developers, developersRelations }; const db = drizzle(new Database(':memory:'), { schema, casing: 'snake_case' }); const usersCache = { - 'public.users.id': 'id', - 'public.users.firstName': 'first_name', - 'public.users.lastName': 'last_name', - 'public.users.AGE': 'age', + 'public.users.id': 'id', + 'public.users.firstName': 'first_name', + 'public.users.lastName': 'last_name', + 'public.users.AGE': 'age', }; const developersCache = { - 'public.developers.userId': 'user_id', - 'public.developers.usesDrizzleORM': 'uses_drizzle_orm', + 'public.developers.userId': 'user_id', + 'public.developers.usesDrizzleORM': 'uses_drizzle_orm', }; const cache = { - ...usersCache, - ...developersCache, + ...usersCache, + ...developersCache, }; const fullName = sql`${users.firstName} || ' ' || ${users.lastName}`.as('name'); describe('sqlite to camel case', () => { - beforeEach(() => { - db.dialect.casing.clearCache(); - }); - - it('select', ({ expect }) => { - const query = db - .select({ name: fullName, age: users.age }) - .from(users) - .leftJoin(developers, eq(users.id, developers.userId)) - .orderBy(asc(users.firstName)); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "developers" on "users"."id" = "developers"."user_id" order by "users"."first_name" asc', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('select (with alias)', ({ expect }) => { - const query = db - .select({ firstName: users.firstName }) - .from(users) - .leftJoin(devs, eq(users.id, devs.userId)); - - expect(query.toSQL()).toEqual({ - sql: 'select "users"."first_name" from "users" left join "developers" "devs" on "users"."id" = "devs"."user_id"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('with CTE', ({ expect }) => { - const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('with CTE (with query builder)', ({ expect }) => { - const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); - const query = db.with(cte).select().from(cte); - - expect(query.toSQL()).toEqual({ - sql: 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator', ({ expect }) => { - const query = db - .select({ firstName: users.firstName }) - .from(users) - .union(db.select({ firstName: users.firstName }).from(users)); - - expect(query.toSQL()).toEqual({ - sql: 'select "first_name" from "users" union select "first_name" from "users"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('set operator (function)', ({ expect }) => { - const query = union( - db.select({ firstName: users.firstName }).from(users), - db.select({ firstName: users.firstName }).from(users) - ); - - expect(query.toSQL()).toEqual({ - sql: 'select "first_name" from "users" union select "first_name" from "users"', - params: [], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('query (find first)', ({ expect }) => { - const query = db.query.users.findFirst({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - usesDrizzleORM: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select "id", "AGE", "first_name" || \' \' || "last_name" as "name", (select json_array("uses_drizzle_orm") as "data" from (select * from "developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ? limit ?', - params: [1, 1, 1], - typings: ['none', 'none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('query (find many)', ({ expect }) => { - const query = db.query.users.findMany({ - columns: { - id: true, - age: true, - }, - extras: { - fullName - }, - where: eq(users.id, 1), - with: { - developers: { - columns: { - usesDrizzleORM: true - } - } - } - }); - - expect(query.toSQL()).toEqual({ - sql: 'select "id", "AGE", "first_name" || \' \' || "last_name" as "name", (select json_array("uses_drizzle_orm") as "data" from (select * from "developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ?', - params: [1, 1], - typings: ['none', 'none'] - }); - expect(db.dialect.casing.cache).toEqual(cache); - }); - - it('insert (on conflict do nothing)', ({ expect }) => { - const query = db - .insert(users) - .values({ firstName: 'John', lastName: 'Doe', age: 30 }) - .onConflictDoNothing({ target: users.firstName }) - .returning({ firstName: users.firstName, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into "users" ("id", "first_name", "last_name", "AGE") values (null, ?, ?, ?) on conflict ("users"."first_name") do nothing returning "first_name", "AGE"', - params: ['John', 'Doe', 30], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('insert (on conflict do update)', ({ expect }) => { - const query = db - .insert(users) - .values({ firstName: 'John', lastName: 'Doe', age: 30 }) - .onConflictDoUpdate({ target: users.firstName, set: { age: 31 } }) - .returning({ firstName: users.firstName, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'insert into "users" ("id", "first_name", "last_name", "AGE") values (null, ?, ?, ?) on conflict ("users"."first_name") do update set "AGE" = ? returning "first_name", "AGE"', - params: ['John', 'Doe', 30, 31], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('update', ({ expect }) => { - const query = db - .update(users) - .set({ firstName: 'John', lastName: 'Doe', age: 30 }) - .where(eq(users.id, 1)) - .returning({ firstName: users.firstName, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'update "users" set "first_name" = ?, "last_name" = ?, "AGE" = ? where "users"."id" = ? returning "first_name", "AGE"', - params: ['John', 'Doe', 30, 1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); - - it('delete', ({ expect }) => { - const query = db - .delete(users) - .where(eq(users.id, 1)) - .returning({ first_name: users.firstName, age: users.age }); - - expect(query.toSQL()).toEqual({ - sql: 'delete from "users" where "users"."id" = ? returning "first_name", "AGE"', - params: [1], - }); - expect(db.dialect.casing.cache).toEqual(usersCache); - }); + beforeEach(() => { + db.dialect.casing.clearCache(); + }); + + it('select', ({ expect }) => { + const query = db + .select({ name: fullName, age: users.age }) + .from(users) + .leftJoin(developers, eq(users.id, developers.userId)) + .orderBy(asc(users.firstName)); + + expect(query.toSQL()).toEqual({ + sql: + 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "developers" on "users"."id" = "developers"."user_id" order by "users"."first_name" asc', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('select (with alias)', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .leftJoin(devs, eq(users.id, devs.userId)); + + expect(query.toSQL()).toEqual({ + sql: 'select "users"."first_name" from "users" left join "developers" "devs" on "users"."id" = "devs"."user_id"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('with CTE', ({ expect }) => { + const cte = db.$with('cte').as(db.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: + 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('with CTE (with query builder)', ({ expect }) => { + const cte = db.$with('cte').as((qb) => qb.select({ name: fullName }).from(users)); + const query = db.with(cte).select().from(cte); + + expect(query.toSQL()).toEqual({ + sql: + 'with "cte" as (select "first_name" || \' \' || "last_name" as "name" from "users") select "name" from "cte"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator', ({ expect }) => { + const query = db + .select({ firstName: users.firstName }) + .from(users) + .union(db.select({ firstName: users.firstName }).from(users)); + + expect(query.toSQL()).toEqual({ + sql: 'select "first_name" from "users" union select "first_name" from "users"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('set operator (function)', ({ expect }) => { + const query = union( + db.select({ firstName: users.firstName }).from(users), + db.select({ firstName: users.firstName }).from(users), + ); + + expect(query.toSQL()).toEqual({ + sql: 'select "first_name" from "users" union select "first_name" from "users"', + params: [], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('query (find first)', ({ expect }) => { + const query = db.query.users.findFirst({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + 'select "id", "AGE", "first_name" || \' \' || "last_name" as "name", (select json_array("uses_drizzle_orm") as "data" from (select * from "developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ? limit ?', + params: [1, 1, 1], + typings: ['none', 'none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('query (find many)', ({ expect }) => { + const query = db.query.users.findMany({ + columns: { + id: true, + age: true, + }, + extras: { + fullName, + }, + where: eq(users.id, 1), + with: { + developers: { + columns: { + usesDrizzleORM: true, + }, + }, + }, + }); + + expect(query.toSQL()).toEqual({ + sql: + 'select "id", "AGE", "first_name" || \' \' || "last_name" as "name", (select json_array("uses_drizzle_orm") as "data" from (select * from "developers" "users_developers" where "users_developers"."user_id" = "users"."id" limit ?) "users_developers") as "developers" from "users" where "users"."id" = ?', + params: [1, 1], + typings: ['none', 'none'], + }); + expect(db.dialect.casing.cache).toEqual(cache); + }); + + it('insert (on conflict do nothing)', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }) + .onConflictDoNothing({ target: users.firstName }) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'insert into "users" ("id", "first_name", "last_name", "AGE") values (null, ?, ?, ?) on conflict ("users"."first_name") do nothing returning "first_name", "AGE"', + params: ['John', 'Doe', 30], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('insert (on conflict do update)', ({ expect }) => { + const query = db + .insert(users) + .values({ firstName: 'John', lastName: 'Doe', age: 30 }) + .onConflictDoUpdate({ target: users.firstName, set: { age: 31 } }) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'insert into "users" ("id", "first_name", "last_name", "AGE") values (null, ?, ?, ?) on conflict ("users"."first_name") do update set "AGE" = ? returning "first_name", "AGE"', + params: ['John', 'Doe', 30, 31], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('update', ({ expect }) => { + const query = db + .update(users) + .set({ firstName: 'John', lastName: 'Doe', age: 30 }) + .where(eq(users.id, 1)) + .returning({ firstName: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: + 'update "users" set "first_name" = ?, "last_name" = ?, "AGE" = ? where "users"."id" = ? returning "first_name", "AGE"', + params: ['John', 'Doe', 30, 1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); + + it('delete', ({ expect }) => { + const query = db + .delete(users) + .where(eq(users.id, 1)) + .returning({ first_name: users.firstName, age: users.age }); + + expect(query.toSQL()).toEqual({ + sql: 'delete from "users" where "users"."id" = ? returning "first_name", "AGE"', + params: [1], + }); + expect(db.dialect.casing.cache).toEqual(usersCache); + }); }); From 8948f1942aeb66683216464347511bce5a5e4987 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 28 Aug 2024 13:08:09 +0300 Subject: [PATCH 113/492] Changed error messge --- drizzle-orm/src/monodriver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 2f9557b01..2b9a8c2b5 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -143,7 +143,7 @@ type DetermineClient< const importError = (libName: string) => { throw new Error( - `Drizzle init error: unable to import selected database driver library '${libName}' - make sure it is installed.`, + `Please install '${libName}' for Drizzle ORM to connect to database`, ); }; From 85fac7e716f3cc90307e04108311fce25d106365 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Thu, 29 Aug 2024 13:02:32 +0300 Subject: [PATCH 114/492] Improved params destructurization --- drizzle-orm/src/monodriver.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 2b9a8c2b5..b2b82af3f 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -151,10 +151,7 @@ export const drizzle = async < TSchema extends Record, TParams extends InitializerParams, >(params: TParams): Promise> => { - const { client, connection } = params; - const drizzleConfig = params as DrizzleConfig; - delete ( drizzleConfig).client; - delete ( drizzleConfig).connection; + const { client, connection, ...drizzleConfig } = params; switch (client) { case 'node-postgres': { From 23c2e899eee08c85dbf3a5095c97d172c054ebcc Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Mon, 2 Sep 2024 05:10:29 +0300 Subject: [PATCH 115/492] Functional prototype of SQLite $count --- drizzle-orm/src/operations.ts | 1 + drizzle-orm/src/sqlite-core/db.ts | 11 ++- .../src/sqlite-core/query-builders/count.ts | 78 +++++++++++++++++++ .../sqlite-core/query-builders/count.types.ts | 8 ++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 drizzle-orm/src/sqlite-core/query-builders/count.ts create mode 100644 drizzle-orm/src/sqlite-core/query-builders/count.types.ts diff --git a/drizzle-orm/src/operations.ts b/drizzle-orm/src/operations.ts index 492bb3f2a..6fb5cbd2e 100644 --- a/drizzle-orm/src/operations.ts +++ b/drizzle-orm/src/operations.ts @@ -21,6 +21,7 @@ export type OptionalKeyOnly< : T['_']['generated'] extends object ? T['_']['generated']['type'] extends 'byDefault' ? TKey : never : never; +// TODO: SQL -> SQLWrapper export type SelectedFieldsFlat = Record< string, TColumn | SQL | SQL.Aliased diff --git a/drizzle-orm/src/sqlite-core/db.ts b/drizzle-orm/src/sqlite-core/db.ts index 65f807d08..97347977c 100644 --- a/drizzle-orm/src/sqlite-core/db.ts +++ b/drizzle-orm/src/sqlite-core/db.ts @@ -2,7 +2,7 @@ import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import type { ColumnsSelection, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteAsyncDialect, SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import { QueryBuilder, @@ -21,10 +21,12 @@ import type { import type { SQLiteTable } from '~/sqlite-core/table.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; +import { SQLiteCountBuilderAsync } from './query-builders/count.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; import { SQLiteRaw } from './query-builders/raw.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; +import type { SQLiteViewBase } from './view-base.ts'; export class BaseSQLiteDatabase< TResultKind extends 'sync' | 'async', @@ -134,6 +136,13 @@ export class BaseSQLiteDatabase< }; } + $count( + source: TSource, + filters?: SQL, + ) { + return new SQLiteCountBuilderAsync({ source, filters, dialect: this.dialect, session: this.session }); + } + /** * Incorporates a previously defined CTE (using `$with`) into the main query. * diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts new file mode 100644 index 000000000..6d6f16e78 --- /dev/null +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -0,0 +1,78 @@ +import { entityKind, sql } from '~/index.ts'; +import type { SQLWrapper } from '~/sql/sql.ts'; +import { SQL } from '~/sql/sql.ts'; +import type { SQLiteDialect } from '../dialect.ts'; +import type { SQLiteSession } from '../session.ts'; +import type { SQLiteTable } from '../table.ts'; + +export class SQLiteCountBuilderAsync< + TSession extends SQLiteSession<'async' | 'sync', any, any, any>, +> extends SQL implements Promise, SQLWrapper { + private sql: SQL; + + static readonly [entityKind] = 'SQLiteCountBuilderAsync'; + [Symbol.toStringTag] = 'SQLiteCountBuilderAsync'; + + private session: TSession; + + private static buildEmbeddedCount( + source: SQLiteTable | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; + } + + private static buildCount( + source: SQLiteTable | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters}`; + } + + constructor( + readonly params: { + source: SQLiteTable | SQL | SQLWrapper; + filters?: SQL; + dialect: SQLiteDialect; + session: TSession; + }, + ) { + super(SQLiteCountBuilderAsync.buildEmbeddedCount(params.source, params.filters).queryChunks); + + this.session = params.session; + + this.sql = SQLiteCountBuilderAsync.buildCount( + params.source, + params.filters, + ); + } + + then( + onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, + ): Promise { + return Promise.resolve(this.session.values(this.sql)).then((it) => it![0]![0] as number).then( + onfulfilled, + onrejected, + ); + } + + catch( + onRejected?: ((reason: any) => never | PromiseLike) | null | undefined, + ): Promise { + return this.then(undefined, onRejected); + } + + finally(onFinally?: (() => void) | null | undefined): Promise { + return this.then( + (value) => { + onFinally?.(); + return value; + }, + (reason) => { + onFinally?.(); + throw reason; + }, + ); + } +} diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.types.ts b/drizzle-orm/src/sqlite-core/query-builders/count.types.ts new file mode 100644 index 000000000..d346c187c --- /dev/null +++ b/drizzle-orm/src/sqlite-core/query-builders/count.types.ts @@ -0,0 +1,8 @@ +import type { SQL, SQLWrapper } from '~/index'; +import type { SQLiteTable } from '../table'; +import type { SQLiteViewBase } from '../view-base'; + +export type SQLiteCountConfig = { + source: SQLiteTable | SQLiteViewBase | SQL | SQLWrapper; + filters?: SQL; +}; From 5b9600e1b63fe8b7df752cfb9ced3264ee26a57f Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 2 Sep 2024 14:29:41 +0300 Subject: [PATCH 116/492] Added pg, mysql; Added tests, type tests for $count --- drizzle-orm/src/mysql-core/db.ts | 11 ++- .../src/mysql-core/query-builders/count.ts | 82 +++++++++++++++++++ drizzle-orm/src/pg-core/db.ts | 11 ++- .../src/pg-core/query-builders/count.ts | 81 ++++++++++++++++++ drizzle-orm/src/sqlite-core/db.ts | 8 +- .../src/sqlite-core/query-builders/count.ts | 17 ++-- .../sqlite-core/query-builders/count.types.ts | 8 -- drizzle-orm/type-tests/mysql/count.ts | 61 ++++++++++++++ drizzle-orm/type-tests/pg/count.ts | 61 ++++++++++++++ drizzle-orm/type-tests/sqlite/count.ts | 61 ++++++++++++++ 10 files changed, 379 insertions(+), 22 deletions(-) create mode 100644 drizzle-orm/src/mysql-core/query-builders/count.ts create mode 100644 drizzle-orm/src/pg-core/query-builders/count.ts delete mode 100644 drizzle-orm/src/sqlite-core/query-builders/count.types.ts create mode 100644 drizzle-orm/type-tests/mysql/count.ts create mode 100644 drizzle-orm/type-tests/pg/count.ts create mode 100644 drizzle-orm/type-tests/sqlite/count.ts diff --git a/drizzle-orm/src/mysql-core/db.ts b/drizzle-orm/src/mysql-core/db.ts index 8df6ff343..419359022 100644 --- a/drizzle-orm/src/mysql-core/db.ts +++ b/drizzle-orm/src/mysql-core/db.ts @@ -3,10 +3,11 @@ import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import type { ColumnsSelection, SQL, SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; import type { MySqlDialect } from './dialect.ts'; +import { MySqlCountBuilder } from './query-builders/count.ts'; import { MySqlDeleteBase, MySqlInsertBuilder, @@ -27,6 +28,7 @@ import type { } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; import type { MySqlTable } from './table.ts'; +import type { MySqlViewBase } from './view-base.ts'; export class MySqlDatabase< TQueryResult extends MySqlQueryResultHKT, @@ -134,6 +136,13 @@ export class MySqlDatabase< }; } + $count( + source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, + filters?: SQL, + ) { + return new MySqlCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); + } + /** * Incorporates a previously defined CTE (using `$with`) into the main query. * diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts new file mode 100644 index 000000000..751ba61c7 --- /dev/null +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -0,0 +1,82 @@ +import { entityKind, sql } from '~/index.ts'; +import type { SQLWrapper } from '~/sql/sql.ts'; +import { SQL } from '~/sql/sql.ts'; +import type { MySqlDialect } from '../dialect.ts'; +import type { MySqlSession } from '../session.ts'; +import type { MySqlTable } from '../table.ts'; +import type { MySqlViewBase } from '../view-base.ts'; + +export class MySqlCountBuilder< + TSession extends MySqlSession, +> extends SQL implements Promise, SQLWrapper { + private sql: SQL; + + static readonly [entityKind] = 'MySqlCountBuilder'; + [Symbol.toStringTag] = 'MySqlCountBuilder'; + + private session: TSession; + + private static buildEmbeddedCount( + source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; + } + + private static buildCount( + source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters}`; + } + + constructor( + readonly params: { + source: MySqlTable | MySqlViewBase | SQL | SQLWrapper; + filters?: SQL; + dialect: MySqlDialect; + session: TSession; + }, + ) { + super(MySqlCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); + + this.session = params.session; + + this.sql = MySqlCountBuilder.buildCount( + params.source, + params.filters, + ); + } + + then( + onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, + ): Promise { + return Promise.resolve(this.session.all(this.sql)).then((it) => { + return (<[{ 'count(*)': number }]> it)[0]['count(*)']; + }) + .then( + onfulfilled, + onrejected, + ); + } + + catch( + onRejected?: ((reason: any) => never | PromiseLike) | null | undefined, + ): Promise { + return this.then(undefined, onRejected); + } + + finally(onFinally?: (() => void) | null | undefined): Promise { + return this.then( + (value) => { + onFinally?.(); + return value; + }, + (reason) => { + onFinally?.(); + throw reason; + }, + ); + } +} diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index 4e8d2f354..3c8da44f1 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -19,15 +19,17 @@ import type { PgTable } from '~/pg-core/table.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import type { ColumnsSelection, SQL, SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; import type { PgColumn } from './columns/index.ts'; +import { PgCountBuilder } from './query-builders/count.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; import { PgRaw } from './query-builders/raw.ts'; import { PgRefreshMaterializedView } from './query-builders/refresh-materialized-view.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; +import type { PgViewBase } from './view-base.ts'; import type { PgMaterializedView } from './view.ts'; export class PgDatabase< @@ -135,6 +137,13 @@ export class PgDatabase< }; } + $count( + source: PgTable | PgViewBase | SQL | SQLWrapper, + filters?: SQL, + ) { + return new PgCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); + } + /** * Incorporates a previously defined CTE (using `$with`) into the main query. * diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts new file mode 100644 index 000000000..7ccd722a0 --- /dev/null +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -0,0 +1,81 @@ +import { entityKind, sql } from '~/index.ts'; +import type { SQLWrapper } from '~/sql/sql.ts'; +import { SQL } from '~/sql/sql.ts'; +import type { PgDialect } from '../dialect.ts'; +import type { PgSession } from '../session.ts'; +import type { PgTable } from '../table.ts'; + +export class PgCountBuilder< + TSession extends PgSession, +> extends SQL implements Promise, SQLWrapper { + private sql: SQL; + + static readonly [entityKind] = 'PgCountBuilder'; + [Symbol.toStringTag] = 'PgCountBuilder'; + + private session: TSession; + + private static buildEmbeddedCount( + source: PgTable | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`(select count(*)::int from ${source}${sql.raw(' where ').if(filters)}${filters})`; + } + + private static buildCount( + source: PgTable | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`select count(*)::int from ${source}${sql.raw(' where ').if(filters)}${filters};`; + } + + constructor( + readonly params: { + source: PgTable | SQL | SQLWrapper; + filters?: SQL; + dialect: PgDialect; + session: TSession; + }, + ) { + super(PgCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); + + this.session = params.session; + + this.sql = PgCountBuilder.buildCount( + params.source, + params.filters, + ); + } + + then( + onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, + ): Promise { + return Promise.resolve(this.session.all(this.sql)).then((it) => { + return (<[{ count: number }]> it)[0]['count'] as number; + }) + .then( + onfulfilled, + onrejected, + ); + } + + catch( + onRejected?: ((reason: any) => never | PromiseLike) | null | undefined, + ): Promise { + return this.then(undefined, onRejected); + } + + finally(onFinally?: (() => void) | null | undefined): Promise { + return this.then( + (value) => { + onFinally?.(); + return value; + }, + (reason) => { + onFinally?.(); + throw reason; + }, + ); + } +} diff --git a/drizzle-orm/src/sqlite-core/db.ts b/drizzle-orm/src/sqlite-core/db.ts index 97347977c..75b088f6d 100644 --- a/drizzle-orm/src/sqlite-core/db.ts +++ b/drizzle-orm/src/sqlite-core/db.ts @@ -21,7 +21,7 @@ import type { import type { SQLiteTable } from '~/sqlite-core/table.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; -import { SQLiteCountBuilderAsync } from './query-builders/count.ts'; +import { SQLiteCountBuilder } from './query-builders/count.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; import { SQLiteRaw } from './query-builders/raw.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; @@ -136,11 +136,11 @@ export class BaseSQLiteDatabase< }; } - $count( - source: TSource, + $count( + source: SQLiteTable | SQLiteViewBase | SQL | SQLWrapper, filters?: SQL, ) { - return new SQLiteCountBuilderAsync({ source, filters, dialect: this.dialect, session: this.session }); + return new SQLiteCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); } /** diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index 6d6f16e78..ed6cd9a1d 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -4,9 +4,10 @@ import { SQL } from '~/sql/sql.ts'; import type { SQLiteDialect } from '../dialect.ts'; import type { SQLiteSession } from '../session.ts'; import type { SQLiteTable } from '../table.ts'; +import type { SQLiteView } from '../view.ts'; -export class SQLiteCountBuilderAsync< - TSession extends SQLiteSession<'async' | 'sync', any, any, any>, +export class SQLiteCountBuilder< + TSession extends SQLiteSession, > extends SQL implements Promise, SQLWrapper { private sql: SQL; @@ -16,14 +17,14 @@ export class SQLiteCountBuilderAsync< private session: TSession; private static buildEmbeddedCount( - source: SQLiteTable | SQL | SQLWrapper, + source: SQLiteTable | SQLiteView | SQL | SQLWrapper, filters?: SQL, ): SQL { return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; } private static buildCount( - source: SQLiteTable | SQL | SQLWrapper, + source: SQLiteTable | SQLiteView | SQL | SQLWrapper, filters?: SQL, ): SQL { return sql`select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters}`; @@ -31,17 +32,17 @@ export class SQLiteCountBuilderAsync< constructor( readonly params: { - source: SQLiteTable | SQL | SQLWrapper; + source: SQLiteTable | SQLiteView | SQL | SQLWrapper; filters?: SQL; dialect: SQLiteDialect; session: TSession; }, ) { - super(SQLiteCountBuilderAsync.buildEmbeddedCount(params.source, params.filters).queryChunks); + super(SQLiteCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); this.session = params.session; - this.sql = SQLiteCountBuilderAsync.buildCount( + this.sql = SQLiteCountBuilder.buildCount( params.source, params.filters, ); @@ -51,7 +52,7 @@ export class SQLiteCountBuilderAsync< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.values(this.sql)).then((it) => it![0]![0] as number).then( + return Promise.resolve(this.session.values(this.sql)).then((it) => it[0]![0] as number).then( onfulfilled, onrejected, ); diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.types.ts b/drizzle-orm/src/sqlite-core/query-builders/count.types.ts deleted file mode 100644 index d346c187c..000000000 --- a/drizzle-orm/src/sqlite-core/query-builders/count.types.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { SQL, SQLWrapper } from '~/index'; -import type { SQLiteTable } from '../table'; -import type { SQLiteViewBase } from '../view-base'; - -export type SQLiteCountConfig = { - source: SQLiteTable | SQLiteViewBase | SQL | SQLWrapper; - filters?: SQL; -}; diff --git a/drizzle-orm/type-tests/mysql/count.ts b/drizzle-orm/type-tests/mysql/count.ts new file mode 100644 index 000000000..d9b9ba9ff --- /dev/null +++ b/drizzle-orm/type-tests/mysql/count.ts @@ -0,0 +1,61 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, gt, ne } from '~/expressions.ts'; +import { int, mysqlTable, serial, text } from '~/mysql-core/index.ts'; +import type { Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = mysqlTable('names', { + id: serial('id').primaryKey(), + name: text('name'), + authorId: int('author_id'), +}); + +const separate = await db.$count(names); + +const separateFilters = await db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))); + +const embedded = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names).as('count1'), + }) + .from(names); + +const embeddedFilters = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))).as('count1'), + }) + .from(names); + +Expect>; + +Expect>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embedded + > +>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embeddedFilters + > +>; diff --git a/drizzle-orm/type-tests/pg/count.ts b/drizzle-orm/type-tests/pg/count.ts new file mode 100644 index 000000000..9ed5eeaf9 --- /dev/null +++ b/drizzle-orm/type-tests/pg/count.ts @@ -0,0 +1,61 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, gt, ne } from '~/expressions.ts'; +import { integer, pgTable, serial, text } from '~/pg-core/index.ts'; +import type { Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = pgTable('names', { + id: serial('id').primaryKey(), + name: text('name'), + authorId: integer('author_id'), +}); + +const separate = await db.$count(names); + +const separateFilters = await db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))); + +const embedded = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names).as('count1'), + }) + .from(names); + +const embeddedFilters = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))).as('count1'), + }) + .from(names); + +Expect>; + +Expect>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embedded + > +>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embeddedFilters + > +>; diff --git a/drizzle-orm/type-tests/sqlite/count.ts b/drizzle-orm/type-tests/sqlite/count.ts new file mode 100644 index 000000000..04350f000 --- /dev/null +++ b/drizzle-orm/type-tests/sqlite/count.ts @@ -0,0 +1,61 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, gt, ne } from '~/expressions.ts'; +import { integer, sqliteTable, text } from '~/sqlite-core/index.ts'; +import type { Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = sqliteTable('names', { + id: integer('id').primaryKey(), + name: text('name'), + authorId: integer('author_id'), +}); + +const separate = await db.$count(names); + +const separateFilters = await db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))); + +const embedded = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names).as('count1'), + }) + .from(names); + +const embeddedFilters = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))).as('count1'), + }) + .from(names); + +Expect>; + +Expect>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embedded + > +>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embeddedFilters + > +>; From 5c04794c00ae496c0bfe3292a073bbc21d4d5ba5 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 2 Sep 2024 15:51:05 +0300 Subject: [PATCH 117/492] Added alternate config for better-sqlite3, bun:sqlite; Renamed bun-sqlite to bun:sqlite; Fixed schema inferrence issue (no schema would resrresult in `unknown`, expected: `Record`) --- drizzle-orm/src/monodriver.ts | 56 +++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index b2b82af3f..db7ac1ddd 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -50,15 +50,21 @@ type BunSqliteDatabaseOptions = readwrite?: boolean; }; -type BunSqliteDatabaseConfig = { - filename?: string; - options?: BunSqliteDatabaseOptions; -}; +type BunSqliteDatabaseConfig = + | { + filename?: string; + options?: BunSqliteDatabaseOptions; + } + | string + | undefined; -type BetterSQLite3DatabaseConfig = { - filename?: string | Buffer; - options?: BetterSQLite3Options; -}; +type BetterSQLite3DatabaseConfig = + | { + filename?: string | Buffer; + options?: BetterSQLite3Options; + } + | string + | undefined; type MonodriverNeonHttpConfig = { connectionString: string; @@ -77,7 +83,7 @@ type ClientDrizzleInstanceMap> = { 'tidb-serverless': TiDBServerlessDatabase; libsql: LibSQLDatabase; d1: DrizzleD1Database; - 'bun-sqlite': BunSQLiteDatabase; + 'bun:sqlite': BunSQLiteDatabase; 'better-sqlite3': BetterSQLite3Database; }; @@ -129,7 +135,7 @@ type InitializerParams< connection: D1Database; } & DrizzleConfig) | ({ - client: 'bun-sqlite'; + client: 'bun:sqlite'; connection: BunSqliteDatabaseConfig; } & DrizzleConfig) | ({ @@ -139,7 +145,9 @@ type InitializerParams< type DetermineClient< TParams extends InitializerParams, -> = ClientDrizzleInstanceMap[TParams['client']]; +> = ClientDrizzleInstanceMap< + TParams['schema'] extends Record ? TParams['schema'] : Record +>[TParams['client']]; const importError = (libName: string) => { throw new Error( @@ -172,17 +180,33 @@ export const drizzle = async < } case 'better-sqlite3': { const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); - const { filename, options } = connection as BetterSQLite3DatabaseConfig; const { drizzle } = await import('./better-sqlite3'); - const instance = new Client(filename, options); + + if (typeof connection === 'object') { + const { filename, options } = connection as Exclude; + + const instance = new Client(filename, options); + + return drizzle(instance, drizzleConfig) as any; + } + + const instance = new Client(connection); return drizzle(instance, drizzleConfig) as any; } - case 'bun-sqlite': { + case 'bun:sqlite': { const { Database: Client } = await import('bun:sqlite').catch(() => importError('bun:sqlite')); - const { filename, options } = connection as BunSqliteDatabaseConfig; const { drizzle } = await import('./bun-sqlite'); - const instance = new Client(filename, options); + + if (typeof connection === 'object') { + const { filename, options } = connection as Exclude; + + const instance = new Client(filename, options); + + return drizzle(instance, drizzleConfig) as any; + } + + const instance = new Client(connection); return drizzle(instance, drizzleConfig) as any; } From 6fc3992be4bb591985c8f4329dec71975a89f852 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 2 Sep 2024 16:05:10 +0300 Subject: [PATCH 118/492] - moved 'turso' driver to dialect - rewrote tests --- drizzle-kit/package.json | 2 +- drizzle-kit/schema.ts | 0 drizzle-kit/src/cli/commands/introspect.ts | 112 +++++ .../src/cli/commands/libSqlPushUtils.ts | 10 +- drizzle-kit/src/cli/commands/migrate.ts | 132 +++--- drizzle-kit/src/cli/commands/push.ts | 25 +- drizzle-kit/src/cli/commands/utils.ts | 81 +++- drizzle-kit/src/cli/connections.ts | 162 +++---- drizzle-kit/src/cli/schema.ts | 39 +- drizzle-kit/src/cli/validations/common.ts | 3 +- drizzle-kit/src/cli/validations/libsql.ts | 27 ++ drizzle-kit/src/cli/validations/sqlite.ts | 5 - drizzle-kit/src/index.ts | 3 +- drizzle-kit/src/schemaValidator.ts | 2 +- drizzle-kit/src/serializer/studio.ts | 29 +- drizzle-kit/src/snapshotsDiffer.ts | 3 +- drizzle-kit/src/sqlgenerator.ts | 55 ++- drizzle-kit/src/utils.ts | 8 + drizzle-kit/tests/cli-generate.test.ts | 9 - drizzle-kit/tests/cli-migrate.test.ts | 3 +- drizzle-kit/tests/cli-push.test.ts | 5 +- drizzle-kit/tests/cli/turso.config.ts | 3 +- drizzle-kit/tests/push/libsql.test.ts | 15 +- drizzle-orm/package.json | 2 +- pnpm-lock.yaml | 401 +++++++++++------- 25 files changed, 735 insertions(+), 401 deletions(-) delete mode 100644 drizzle-kit/schema.ts create mode 100644 drizzle-kit/src/cli/validations/libsql.ts diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 9d9e1d227..3be9c7330 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -54,7 +54,7 @@ "@electric-sql/pglite": "^0.1.5", "@hono/node-server": "^1.9.0", "@hono/zod-validator": "^0.2.1", - "@libsql/client": "^0.4.2", + "@libsql/client": "^0.10.0", "@neondatabase/serverless": "^0.9.1", "@originjs/vite-plugin-commonjs": "^1.0.3", "@planetscale/database": "^1.16.0", diff --git a/drizzle-kit/schema.ts b/drizzle-kit/schema.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 61ba0b44a..285264ffc 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -17,6 +17,7 @@ import { fromDatabase as fromSqliteDatabase } from '../../serializer/sqliteSeria import { applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, applySqliteSnapshotsDiff } from '../../snapshotsDiffer'; import { prepareOutFolder } from '../../utils'; import type { Casing, Prefix } from '../validations/common'; +import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; import type { PostgresCredentials } from '../validations/postgres'; import type { SqliteCredentials } from '../validations/sqlite'; @@ -365,6 +366,117 @@ export const introspectSqlite = async ( process.exit(0); }; +export const introspectLibSQL = async ( + casing: Casing, + out: string, + breakpoints: boolean, + credentials: LibSQLCredentials, + tablesFilter: string[], + prefix: Prefix, +) => { + const { connectToLibSQL } = await import('../connections'); + const db = await connectToLibSQL(credentials); + + const matchers = tablesFilter.map((it) => { + return new Minimatch(it); + }); + + const filter = (tableName: string) => { + if (matchers.length === 0) return true; + + let flags: boolean[] = []; + + for (let matcher of matchers) { + if (matcher.negate) { + if (!matcher.match(tableName)) { + flags.push(false); + } + } + + if (matcher.match(tableName)) { + flags.push(true); + } + } + + if (flags.length > 0) { + return flags.every(Boolean); + } + return false; + }; + + const progress = new IntrospectProgress(); + const res = await renderWithTask( + progress, + fromSqliteDatabase(db, filter, (stage, count, status) => { + progress.update(stage, count, status); + }), + ); + + const schema = { id: originUUID, prevId: '', ...res } as SQLiteSchema; + const ts = sqliteSchemaToTypeScript(schema, casing); + const relationsTs = relationsToTypeScript(schema, casing); + + // check orm and orm-pg api version + + const schemaFile = join(out, 'schema.ts'); + writeFileSync(schemaFile, ts.file); + const relationsFile = join(out, 'relations.ts'); + writeFileSync(relationsFile, relationsTs.file); + console.log(); + + const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + + if (snapshots.length === 0) { + const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( + squashSqliteScheme(drySQLite), + squashSqliteScheme(schema), + tablesResolver, + columnsResolver, + drySQLite, + schema, + ); + + writeResult({ + cur: schema, + sqlStatements, + journal, + _meta, + outFolder: out, + breakpoints, + type: 'introspect', + prefixMode: prefix, + }); + } else { + render( + `[${ + chalk.blue( + 'i', + ) + }] No SQL generated, you already have migrations in project`, + ); + } + + render( + `[${ + chalk.green( + '✓', + ) + }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + ); + render( + `[${ + chalk.green( + '✓', + ) + }] You relations file is ready ➜ ${ + chalk.bold.underline.blue( + relationsFile, + ) + } 🚀`, + ); + process.exit(0); +}; + const withCasing = (value: string, casing: Casing) => { if (casing === 'preserve') { return value; diff --git a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts index 3bc9e8225..98c95f089 100644 --- a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts +++ b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts @@ -133,7 +133,7 @@ export const libSqlLogSuggestionsAndReturn = async ( tablesToRemove.push(statement.tableName); shouldAskForApprove = true; } - const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + const fromJsonStatement = fromJson([statement], 'turso', 'push', json2); statementsToExecute.push( ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); @@ -156,7 +156,7 @@ export const libSqlLogSuggestionsAndReturn = async ( shouldAskForApprove = true; } - const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + const fromJsonStatement = fromJson([statement], 'turso', 'push', json2); statementsToExecute.push( ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); @@ -185,7 +185,7 @@ export const libSqlLogSuggestionsAndReturn = async ( shouldAskForApprove = true; } - const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + const fromJsonStatement = fromJson([statement], 'turso', 'push', json2); statementsToExecute.push( ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); @@ -330,12 +330,12 @@ export const libSqlLogSuggestionsAndReturn = async ( columnsToRemove.push(`${tableName}_${statement.columnName}`); shouldAskForApprove = true; } - const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + const fromJsonStatement = fromJson([statement], 'turso', 'push', json2); statementsToExecute.push( ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); } else { - const fromJsonStatement = fromJson([statement], 'sqlite', 'push', 'turso', json2); + const fromJsonStatement = fromJson([statement], 'turso', 'push', json2); statementsToExecute.push( ...(Array.isArray(fromJsonStatement) ? fromJsonStatement : [fromJsonStatement]), ); diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 5fe64ce6c..d93ddb154 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -396,7 +396,6 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; - const driver = config.driver; try { assertV1OutFolder(outFolder); @@ -428,35 +427,74 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const squashedPrev = squashSqliteScheme(validatedPrev); const squashedCur = squashSqliteScheme(validatedCur); - let sqlStatements: string[]; - let _meta: - | { - schemas: {}; - tables: {}; - columns: {}; - } - | undefined; - - if (driver === 'turso') { - ({ sqlStatements, _meta } = await applyLibSQLSnapshotsDiff( - squashedPrev, - squashedCur, - tablesResolver, - columnsResolver, - validatedPrev, - validatedCur, - )); - } else { - ({ sqlStatements, _meta } = await applySqliteSnapshotsDiff( - squashedPrev, - squashedCur, - tablesResolver, - columnsResolver, - validatedPrev, - validatedCur, - )); + const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + ); + + writeResult({ + cur, + sqlStatements, + journal, + _meta, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + bundle: config.bundle, + prefixMode: config.prefix, + }); + } catch (e) { + console.error(e); + } +}; + +export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => { + const outFolder = config.out; + const schemaPath = config.schema; + + try { + assertV1OutFolder(outFolder); + + const { snapshots, journal } = prepareMigrationFolder(outFolder, 'sqlite'); + const { prev, cur, custom } = await prepareSqliteMigrationSnapshot( + snapshots, + schemaPath, + ); + + const validatedPrev = sqliteSchema.parse(prev); + const validatedCur = sqliteSchema.parse(cur); + + if (config.custom) { + writeResult({ + cur: custom, + sqlStatements: [], + journal, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + bundle: config.bundle, + type: 'custom', + prefixMode: config.prefix, + }); + return; } + const squashedPrev = squashSqliteScheme(validatedPrev); + const squashedCur = squashSqliteScheme(validatedCur); + + const { sqlStatements, _meta } = await applyLibSQLSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + ); + writeResult({ cur, sqlStatements, @@ -476,7 +514,6 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { export const prepareSQLitePush = async ( schemaPath: string | string[], snapshot: SQLiteSchema, - driver?: Driver, ) => { const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath); @@ -486,34 +523,15 @@ export const prepareSQLitePush = async ( const squashedPrev = squashSqliteScheme(validatedPrev, 'push'); const squashedCur = squashSqliteScheme(validatedCur, 'push'); - let sqlStatements: string[]; - let statements: JsonStatement[]; - let _meta: { - schemas: {}; - tables: {}; - columns: {}; - } | undefined; - if (driver === 'turso') { - ({ sqlStatements, statements, _meta } = await applyLibSQLSnapshotsDiff( - squashedPrev, - squashedCur, - tablesResolver, - columnsResolver, - validatedPrev, - validatedCur, - 'push', - )); - } else { - ({ sqlStatements, statements, _meta } = await applySqliteSnapshotsDiff( - squashedPrev, - squashedCur, - tablesResolver, - columnsResolver, - validatedPrev, - validatedCur, - 'push', - )); - } + const { sqlStatements, statements, _meta } = await applySqliteSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + ); return { sqlStatements, diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index a342f48fc..2d3df5fba 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -2,6 +2,7 @@ import chalk from 'chalk'; import { render } from 'hanji'; import { fromJson } from '../../sqlgenerator'; import { Select } from '../selector-ui'; +import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; import { withStyle } from '../validations/outputs'; import type { PostgresCredentials } from '../validations/postgres'; @@ -371,8 +372,6 @@ export const sqlitePush = async ( await db.query('rollback'); process.exit(1); } - } else if (credentials.driver === 'turso') { - await db.batch!(statementsToExecute.map((it) => ({ query: it }))); } render(`[${chalk.green('✓')}] Changes applied`); } @@ -383,14 +382,14 @@ export const libSQLPush = async ( schemaPath: string | string[], verbose: boolean, strict: boolean, - credentials: SqliteCredentials, + credentials: LibSQLCredentials, tablesFilter: string[], force: boolean, ) => { - const { connectToSQLite } = await import('../connections'); + const { connectToLibSQL } = await import('../connections'); const { sqlitePushIntrospect } = await import('./sqliteIntrospect'); - const db = await connectToSQLite(credentials); + const db = await connectToLibSQL(credentials); const { schema } = await sqlitePushIntrospect(db, tablesFilter); const { prepareLibSQLPush } = await import('./migrate'); @@ -479,21 +478,7 @@ export const libSQLPush = async ( if (statementsToExecute.length === 0) { render(`\n[${chalk.blue('i')}] No changes detected`); } else { - if (!('driver' in credentials)) { - await db.query('begin'); - try { - for (const dStmnt of statementsToExecute) { - await db.query(dStmnt); - } - await db.query('commit'); - } catch (e) { - console.error(e); - await db.query('rollback'); - process.exit(1); - } - } else if (credentials.driver === 'turso') { - await db.batch!(statementsToExecute.map((it) => ({ query: it }))); - } + await db.batchWithPragma!(statementsToExecute); render(`[${chalk.green('✓')}] Changes applied`); } } diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 677db0665..d19c04b3e 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -16,6 +16,8 @@ import { Prefix, wrapParam, } from '../validations/common'; +import { LibSQLCredentials, libSQLCredentials } from '../validations/libsql'; +import { printConfigConnectionIssues as printIssuesLibSql } from '../validations/libsql'; import { MysqlCredentials, mysqlCredentials, @@ -122,7 +124,6 @@ export type GenerateConfig = { prefix: Prefix; custom: boolean; bundle: boolean; - driver?: Driver; }; export const prepareGenerateConfig = async ( @@ -169,7 +170,6 @@ export const prepareGenerateConfig = async ( schema: schema, out: out || 'drizzle', bundle: driver === 'expo', - driver, }; }; @@ -212,7 +212,10 @@ export const preparePushConfig = async ( | { dialect: 'sqlite'; credentials: SqliteCredentials; - driver?: Driver; + } + | { + dialect: 'turso'; + credentials: LibSQLCredentials; } ) & { schemaPath: string | string[]; @@ -328,7 +331,24 @@ export const preparePushConfig = async ( credentials: parsed.data, tablesFilter, schemasFilter, - driver: config.driver, + }; + } + + if (config.dialect === 'turso') { + const parsed = libSQLCredentials.safeParse(config); + if (!parsed.success) { + printIssuesSqlite(config, 'pull'); + process.exit(1); + } + return { + dialect: 'turso', + schemaPath: config.schema, + strict: config.strict ?? false, + verbose: config.verbose ?? false, + force: (options.force as boolean) ?? false, + credentials: parsed.data, + tablesFilter, + schemasFilter, }; } @@ -352,6 +372,10 @@ export const preparePullConfig = async ( dialect: 'sqlite'; credentials: SqliteCredentials; } + | { + dialect: 'turso'; + credentials: LibSQLCredentials; + } ) & { out: string; breakpoints: boolean; @@ -457,6 +481,24 @@ export const preparePullConfig = async ( }; } + if (dialect === 'turso') { + const parsed = libSQLCredentials.safeParse(config); + if (!parsed.success) { + printIssuesLibSql(config, 'pull'); + process.exit(1); + } + return { + dialect: 'sqlite', + out: config.out, + breakpoints: config.breakpoints, + casing: config.casing, + credentials: parsed.data, + tablesFilter, + schemasFilter, + prefix: config.migrations?.prefix || 'index', + }; + } + assertUnreachable(dialect); }; @@ -526,6 +568,22 @@ export const prepareStudioConfig = async (options: Record) => { }; } + if (dialect === 'turso') { + const parsed = libSQLCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesLibSql(flattened as Record, 'studio'); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + schema, + host, + port, + credentials, + }; + } + assertUnreachable(dialect); }; @@ -594,6 +652,21 @@ export const prepareMigrateConfig = async (configPath: string | undefined) => { table, }; } + if (dialect === 'turso') { + const parsed = libSQLCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesLibSql(flattened as Record, 'migrate'); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + out, + credentials, + schema, + table, + }; + } assertUnreachable(dialect); }; diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index ba741bfed..ee0ce04c3 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -5,8 +5,17 @@ import fetch from 'node-fetch'; import ws from 'ws'; import { assertUnreachable } from '../global'; import type { ProxyParams } from '../serializer/studio'; -import { type DB, normalisePGliteUrl, normaliseSQLiteUrl, type Proxy, type SQLiteDB, type SqliteProxy } from '../utils'; +import { + type DB, + LibSQLDB, + normalisePGliteUrl, + normaliseSQLiteUrl, + type Proxy, + type SQLiteDB, + type SqliteProxy, +} from '../utils'; import { assertPackages, checkPackage } from './utils'; +import { LibSQLCredentials } from './validations/libsql'; import type { MysqlCredentials } from './validations/mysql'; import { withStyle } from './validations/outputs'; import type { PostgresCredentials } from './validations/postgres'; @@ -482,56 +491,7 @@ export const connectToSQLite = async ( > => { if ('driver' in credentials) { const { driver } = credentials; - if (driver === 'turso') { - assertPackages('@libsql/client'); - const { createClient } = await import('@libsql/client'); - const { drizzle } = await import('drizzle-orm/libsql'); - const { migrate } = await import('drizzle-orm/libsql/migrator'); - - const client = createClient({ - url: credentials.url, - authToken: credentials.authToken, - }); - - const drzl = drizzle(client); - const migrateFn = async (config: MigrationConfig) => { - return migrate(drzl, config); - }; - - const db: SQLiteDB = { - query: async (sql: string, params?: any[]) => { - const res = await client.execute({ sql, args: params || [] }); - return res.rows as T[]; - }, - run: async (query: string) => { - await client.execute(query); - }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, - }; - const proxy: SqliteProxy = { - proxy: async (params: ProxyParams) => { - const preparedParams = prepareSqliteParams(params.params); - const result = await client.execute({ - sql: params.sql, - args: preparedParams, - }); - - if (params.mode === 'array') { - return result.rows.map((row) => Object.values(row)); - } else { - return result.rows; - } - }, - }; - - return { ...db, ...proxy, migrate: migrateFn }; - } else if (driver === 'd1-http') { + if (driver === 'd1-http') { const { drizzle } = await import('drizzle-orm/sqlite-proxy'); const { migrate } = await import('drizzle-orm/sqlite-proxy/migrator'); @@ -625,48 +585,6 @@ export const connectToSQLite = async ( } } - if (await checkPackage('@libsql/client')) { - const { createClient } = await import('@libsql/client'); - const { drizzle } = await import('drizzle-orm/libsql'); - const { migrate } = await import('drizzle-orm/libsql/migrator'); - - const client = createClient({ - url: normaliseSQLiteUrl(credentials.url, 'libsql'), - }); - const drzl = drizzle(client); - const migrateFn = async (config: MigrationConfig) => { - return migrate(drzl, config); - }; - - const db: SQLiteDB = { - query: async (sql: string, params?: any[]) => { - const res = await client.execute({ sql, args: params || [] }); - return res.rows as T[]; - }, - run: async (query: string) => { - await client.execute(query); - }, - }; - - const proxy: SqliteProxy = { - proxy: async (params: ProxyParams) => { - const preparedParams = prepareSqliteParams(params.params); - const result = await client.execute({ - sql: params.sql, - args: preparedParams, - }); - - if (params.mode === 'array') { - return result.rows.map((row) => Object.values(row)); - } else { - return result.rows; - } - }, - }; - - return { ...db, ...proxy, migrate: migrateFn }; - } - if (await checkPackage('better-sqlite3')) { const { default: Database } = await import('better-sqlite3'); const { drizzle } = await import('drizzle-orm/better-sqlite3'); @@ -709,7 +627,63 @@ export const connectToSQLite = async ( return { ...db, ...proxy, migrate: migrateFn }; } console.log( - "Please install either 'better-sqlite3' or '@libsql/client' for Drizzle Kit to connect to SQLite databases", + "Please install 'better-sqlite3' for Drizzle Kit to connect to SQLite databases", + ); + process.exit(1); +}; + +export const connectToLibSQL = async (credentials: LibSQLCredentials): Promise< + & LibSQLDB + & SqliteProxy + & { migrate: (config: MigrationConfig) => Promise } +> => { + if (await checkPackage('@libsql/client')) { + const { createClient } = await import('@libsql/client'); + const { drizzle } = await import('drizzle-orm/libsql'); + const { migrate } = await import('drizzle-orm/libsql/migrator'); + + const client = createClient({ + url: normaliseSQLiteUrl(credentials.url, 'libsql'), + }); + const drzl = drizzle(client); + const migrateFn = async (config: MigrationConfig) => { + return migrate(drzl, config); + }; + + const db: LibSQLDB = { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); + }, + batchWithPragma: async (queries: string[]) => { + await client.migrate(queries); + }, + }; + + const proxy: SqliteProxy = { + proxy: async (params: ProxyParams) => { + const preparedParams = prepareSqliteParams(params.params); + const result = await client.execute({ + sql: params.sql, + args: preparedParams, + }); + + if (params.mode === 'array') { + return result.rows.map((row) => Object.values(row)); + } else { + return result.rows; + } + }, + }; + + return { ...db, ...proxy, migrate: migrateFn }; + } + + console.log( + "Please install '@libsql/client' for Drizzle Kit to connect to LibSQL databases", ); process.exit(1); }; diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index bf825d3e3..c7d5b88f3 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -24,13 +24,13 @@ import { mkdirSync } from 'fs'; import { renderWithTask } from 'hanji'; import { dialects } from 'src/schemaValidator'; import { assertUnreachable } from '../global'; -import type { Setup } from '../serializer/studio'; +import { drizzleForLibSQL, type Setup } from '../serializer/studio'; import { certs } from '../utils/certs'; import { grey, MigrateProgress } from './views'; const optionDialect = string('dialect') .enum(...dialects) - .desc(`Database dialect: 'postgresql', 'mysql' or 'sqlite'`); + .desc(`Database dialect: 'postgresql', 'mysql', 'sqlite' or 'turso'`); const optionOut = string().desc("Output folder, 'drizzle' by default"); const optionConfig = string().desc('Path to drizzle config file'); const optionBreakpoints = boolean().desc( @@ -77,6 +77,7 @@ export const generate = command({ prepareAndMigratePg, prepareAndMigrateMysql, prepareAndMigrateSqlite, + prepareAndMigrateLibSQL, } = await import('./commands/migrate'); const dialect = opts.dialect; @@ -86,6 +87,8 @@ export const generate = command({ await prepareAndMigrateMysql(opts); } else if (dialect === 'sqlite') { await prepareAndMigrateSqlite(opts); + } else if (dialect === 'turso') { + await prepareAndMigrateLibSQL(opts); } else { assertUnreachable(dialect); } @@ -159,6 +162,17 @@ export const migrate = command({ migrationsSchema: schema, }), ); + } else if (dialect === 'turso') { + const { connectToLibSQL } = await import('./connections'); + const { migrate } = await connectToLibSQL(credentials); + await renderWithTask( + new MigrateProgress(), + migrate({ + migrationsFolder: opts.out, + migrationsTable: table, + migrationsSchema: schema, + }), + ); } else { assertUnreachable(dialect); } @@ -294,7 +308,7 @@ export const push = command({ schemasFilter, force, ); - } else if (dialect === 'sqlite' && !('driver' in credentials)) { + } else if (dialect === 'sqlite') { const { sqlitePush } = await import('./commands/push'); await sqlitePush( schemaPath, @@ -304,7 +318,7 @@ export const push = command({ tablesFilter, force, ); - } else if (dialect === 'sqlite' && ('driver' in credentials && credentials.driver === 'turso')) { + } else if (dialect === 'turso') { const { libSQLPush } = await import('./commands/push'); await libSQLPush( schemaPath, @@ -369,7 +383,7 @@ export const up = command({ upMysqlHandler(out); } - if (dialect === 'sqlite') { + if (dialect === 'sqlite' || dialect === 'turso') { upSqliteHandler(out); } }, @@ -493,6 +507,16 @@ export const pull = command({ tablesFilter, prefix, ); + } else if (dialect === 'turso') { + const { introspectLibSQL } = await import('./commands/introspect'); + await introspectLibSQL( + casing, + out, + breakpoints, + credentials, + tablesFilter, + prefix, + ); } else { assertUnreachable(dialect); } @@ -593,6 +617,11 @@ export const studio = command({ ? await prepareSQLiteSchema(schemaPath) : { schema: {}, relations: {}, files: [] }; setup = await drizzleForSQLite(credentials, schema, relations, files); + } else if (dialect === 'turso') { + const { schema, relations, files } = schemaPath + ? await prepareSQLiteSchema(schemaPath) + : { schema: {}, relations: {}, files: [] }; + setup = await drizzleForLibSQL(credentials, schema, relations, files); } else { assertUnreachable(dialect); } diff --git a/drizzle-kit/src/cli/validations/common.ts b/drizzle-kit/src/cli/validations/common.ts index a7307f4d6..3a2701e37 100644 --- a/drizzle-kit/src/cli/validations/common.ts +++ b/drizzle-kit/src/cli/validations/common.ts @@ -61,7 +61,6 @@ export const assertCollisions = < }; export const sqliteDriversLiterals = [ - literal('turso'), literal('d1-http'), literal('expo'), ] as const; @@ -156,7 +155,7 @@ export const configPushSchema = object({ }); export type CliConfig = TypeOf; -export const drivers = ['turso', 'd1-http', 'expo', 'aws-data-api', 'pglite'] as const; +export const drivers = ['d1-http', 'expo', 'aws-data-api', 'pglite'] as const; export type Driver = (typeof drivers)[number]; const _: Driver = '' as TypeOf; diff --git a/drizzle-kit/src/cli/validations/libsql.ts b/drizzle-kit/src/cli/validations/libsql.ts new file mode 100644 index 000000000..a9b03c168 --- /dev/null +++ b/drizzle-kit/src/cli/validations/libsql.ts @@ -0,0 +1,27 @@ +import { softAssertUnreachable } from 'src/global'; +import { object, string, TypeOf } from 'zod'; +import { error } from '../views'; +import { wrapParam } from './common'; + +export const libSQLCredentials = object({ + url: string().min(1), + authToken: string().min(1).optional(), +}); + +export type LibSQLCredentials = { + url: string; + authToken?: string; +}; + +const _: LibSQLCredentials = {} as TypeOf; + +export const printConfigConnectionIssues = ( + options: Record, + command: 'generate' | 'migrate' | 'push' | 'pull' | 'studio', +) => { + let text = `Please provide required params for 'turso' dialect:\n`; + console.log(error(text)); + console.log(wrapParam('url', options.url)); + console.log(wrapParam('authToken', options.authToken, true, 'secret')); + process.exit(1); +}; diff --git a/drizzle-kit/src/cli/validations/sqlite.ts b/drizzle-kit/src/cli/validations/sqlite.ts index b6ad062d5..54178fd4a 100644 --- a/drizzle-kit/src/cli/validations/sqlite.ts +++ b/drizzle-kit/src/cli/validations/sqlite.ts @@ -25,11 +25,6 @@ export const sqliteCredentials = union([ ]); export type SqliteCredentials = - | { - driver: 'turso'; - url: string; - authToken: string; - } | { driver: 'd1-http'; accountId: string; diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 3d29b5c85..183b335ce 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -128,8 +128,7 @@ export type Config = } & ( | { - dialect: Verify; - driver: Verify; + dialect: Verify; dbCredentials: { url: string; authToken?: string; diff --git a/drizzle-kit/src/schemaValidator.ts b/drizzle-kit/src/schemaValidator.ts index 9c1f4dcfc..6ad29a544 100644 --- a/drizzle-kit/src/schemaValidator.ts +++ b/drizzle-kit/src/schemaValidator.ts @@ -3,7 +3,7 @@ import { mysqlSchema, mysqlSchemaSquashed } from './serializer/mysqlSchema'; import { pgSchema, pgSchemaSquashed } from './serializer/pgSchema'; import { sqliteSchema, SQLiteSchemaSquashed } from './serializer/sqliteSchema'; -export const dialects = ['postgresql', 'mysql', 'sqlite'] as const; +export const dialects = ['postgresql', 'mysql', 'sqlite', 'turso'] as const; export const dialect = enumType(dialects); export type Dialect = (typeof dialects)[number]; diff --git a/drizzle-kit/src/serializer/studio.ts b/drizzle-kit/src/serializer/studio.ts index dc78c6c2c..e83bd21a2 100644 --- a/drizzle-kit/src/serializer/studio.ts +++ b/drizzle-kit/src/serializer/studio.ts @@ -20,6 +20,7 @@ import fs from 'fs'; import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { createServer } from 'node:https'; +import { LibSQLCredentials } from 'src/cli/validations/libsql'; import { assertUnreachable } from 'src/global'; import superjson from 'superjson'; import { z } from 'zod'; @@ -297,8 +298,6 @@ export const drizzleForSQLite = async ( const { driver } = credentials; if (driver === 'd1-http') { dbUrl = `d1-http://${credentials.accountId}/${credentials.databaseId}/${credentials.token}`; - } else if (driver === 'turso') { - dbUrl = `turso://${credentials.url}/${credentials.authToken}`; } else { assertUnreachable(driver); } @@ -319,6 +318,32 @@ export const drizzleForSQLite = async ( schemaFiles, }; }; +export const drizzleForLibSQL = async ( + credentials: LibSQLCredentials, + sqliteSchema: Record>, + relations: Record, + schemaFiles?: SchemaFile[], +): Promise => { + const { connectToLibSQL } = await import('../cli/connections'); + + const sqliteDB = await connectToLibSQL(credentials); + const customDefaults = getCustomDefaults(sqliteSchema); + + let dbUrl: string = `turso://${credentials.url}/${credentials.authToken}`; + + const dbHash = createHash('sha256').update(dbUrl).digest('hex'); + + return { + dbHash, + dialect: 'sqlite', + driver: undefined, + proxy: sqliteDB.proxy, + customDefaults, + schema: sqliteSchema, + relations, + schemaFiles, + }; +}; export const extractRelations = (tablesConfig: { tables: TablesRelationalConfig; diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 0978f5695..64ea8e465 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -2472,9 +2472,8 @@ export const applyLibSQLSnapshotsDiff = async ( const sqlStatements = fromJson( combinedJsonStatements, - 'sqlite', - action, 'turso', + action, json2, ); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 12d11284d..02c3fb427 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -316,7 +316,7 @@ class MySqlCreateTableConvertor extends Convertor { export class SQLiteCreateTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'sqlite_create_table' && dialect === 'sqlite'; + return statement.type === 'sqlite_create_table' && (dialect === 'sqlite' || dialect === 'turso'); } convert(st: JsonSqliteCreateTableStatement) { @@ -756,7 +756,7 @@ class MySQLDropTableConvertor extends Convertor { export class SQLiteDropTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'drop_table' && dialect === 'sqlite'; + return statement.type === 'drop_table' && (dialect === 'sqlite' || dialect === 'turso'); } convert(statement: JsonDropTableStatement) { @@ -782,7 +782,7 @@ class PgRenameTableConvertor extends Convertor { export class SqliteRenameTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'rename_table' && dialect === 'sqlite'; + return statement.type === 'rename_table' && (dialect === 'sqlite' || dialect === 'turso'); } convert(statement: JsonRenameTableStatement) { @@ -836,7 +836,7 @@ class MySqlAlterTableRenameColumnConvertor extends Convertor { class SQLiteAlterTableRenameColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( - statement.type === 'alter_table_rename_column' && dialect === 'sqlite' + statement.type === 'alter_table_rename_column' && (dialect === 'sqlite' || dialect === 'turso') ); } @@ -877,7 +877,7 @@ class MySqlAlterTableDropColumnConvertor extends Convertor { class SQLiteAlterTableDropColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_table_drop_column' && dialect === 'sqlite'; + return statement.type === 'alter_table_drop_column' && (dialect === 'sqlite' || dialect === 'turso'); } convert(statement: JsonDropColumnStatement) { @@ -987,7 +987,7 @@ class MySqlAlterTableAddColumnConvertor extends Convertor { export class SQLiteAlterTableAddColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( - statement.type === 'sqlite_alter_table_add_column' && dialect === 'sqlite' + statement.type === 'sqlite_alter_table_add_column' && (dialect === 'sqlite' || dialect === 'turso') ); } @@ -1192,7 +1192,7 @@ class SqliteAlterTableAlterColumnDropGeneratedConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( statement.type === 'alter_table_alter_column_drop_generated' - && dialect === 'sqlite' + && (dialect === 'sqlite' || dialect === 'turso') ); } @@ -1241,7 +1241,7 @@ class SqliteAlterTableAlterColumnSetExpressionConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( statement.type === 'alter_table_alter_column_set_generated' - && dialect === 'sqlite' + && (dialect === 'sqlite' || dialect === 'turso') ); } @@ -1290,7 +1290,7 @@ class SqliteAlterTableAlterColumnAlterGeneratedConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( statement.type === 'alter_table_alter_column_alter_generated' - && dialect === 'sqlite' + && (dialect === 'sqlite' || dialect === 'turso') ); } @@ -1445,19 +1445,18 @@ type LibSQLModifyColumnStatement = | JsonAlterColumnDropDefaultStatement; export class LibSQLModifyColumn extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + can(statement: JsonStatement, dialect: Dialect): boolean { return ( (statement.type === 'alter_table_alter_column_set_type' || statement.type === 'alter_table_alter_column_drop_notnull' || statement.type === 'alter_table_alter_column_set_notnull' || statement.type === 'alter_table_alter_column_set_default' || statement.type === 'alter_table_alter_column_drop_default') - && dialect === 'sqlite' - && driver === 'turso' + && dialect === 'turso' ); } - convert(statement: LibSQLModifyColumnStatement, json2: SQLiteSchemaSquashed, action?: 'push') { + convert(statement: LibSQLModifyColumnStatement, json2: SQLiteSchemaSquashed) { const { tableName, columnName } = statement; let columnType = ``; @@ -2005,11 +2004,10 @@ class PgCreateForeignKeyConvertor extends Convertor { } class LibSQLCreateForeignKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + can(statement: JsonStatement, dialect: Dialect): boolean { return ( statement.type === 'create_reference' - && dialect === 'sqlite' - && driver === 'turso' + && dialect === 'turso' ); } @@ -2221,7 +2219,7 @@ class CreateMySqlIndexConvertor extends Convertor { export class CreateSqliteIndexConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_index' && dialect === 'sqlite'; + return statement.type === 'create_index' && (dialect === 'sqlite' || dialect === 'turso'); } convert(statement: JsonCreateIndexStatement): string { @@ -2343,7 +2341,7 @@ class PgAlterTableRemoveFromSchemaConvertor extends Convertor { export class SqliteDropIndexConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'drop_index' && dialect === 'sqlite'; + return statement.type === 'drop_index' && (dialect === 'sqlite' || dialect === 'turso'); } convert(statement: JsonDropIndexStatement): string { @@ -2364,9 +2362,9 @@ class MySqlDropIndexConvertor extends Convertor { } class SQLiteRecreateTableConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + can(statement: JsonStatement, dialect: Dialect): boolean { return ( - statement.type === 'recreate_table' && dialect === 'sqlite' && !driver + statement.type === 'recreate_table' && dialect === 'sqlite' ); } @@ -2396,7 +2394,7 @@ class SQLiteRecreateTableConvertor extends Convertor { `INSERT INTO \`${newTableName}\`(${columnNames}) SELECT ${columnNames} FROM \`${tableName}\`;`, ); - // migrate data + // drop table sqlStatements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', @@ -2423,11 +2421,10 @@ class SQLiteRecreateTableConvertor extends Convertor { } class LibSQLRecreateTableConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect, driver?: Driver): boolean { + can(statement: JsonStatement, dialect: Dialect): boolean { return ( statement.type === 'recreate_table' - && dialect === 'sqlite' - && driver === 'turso' + && dialect === 'turso' ); } @@ -2457,7 +2454,7 @@ class LibSQLRecreateTableConvertor extends Convertor { `INSERT INTO \`${newTableName}\`(${columnNames}) SELECT ${columnNames} FROM \`${tableName}\`;`, ); - // migrate data + // drop table sqlStatements.push( new SQLiteDropTableConvertor().convert({ type: 'drop_table', @@ -2593,13 +2590,12 @@ convertors.push(new MySqlAlterTableAlterCompositePrimaryKeyConvertor()); // overloads for turso driver export function fromJson( statements: JsonStatement[], - dialect: Exclude, + dialect: Exclude, ): string[]; export function fromJson( statements: JsonStatement[], - dialect: 'sqlite', + dialect: 'sqlite' | 'turso', action?: 'push', - driver?: Driver, json2?: SQLiteSchemaSquashed, ): string[]; @@ -2607,13 +2603,12 @@ export function fromJson( statements: JsonStatement[], dialect: Dialect, action?: 'push', - driver?: Driver, json2?: SQLiteSchemaSquashed, ) { const result = statements .flatMap((statement) => { const filtered = convertors.filter((it) => { - return it.can(statement, dialect, driver); + return it.can(statement, dialect); }); const convertor = filtered.length === 1 ? filtered[0] : undefined; diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 6f82b831c..9a199e573 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -30,6 +30,12 @@ export type SQLiteDB = { ): Promise; }; +export type LibSQLDB = { + query: (sql: string, params?: any[]) => Promise; + run(query: string): Promise; + batchWithPragma?(queries: string[]): Promise; +}; + export const copy = (it: T): T => { return JSON.parse(JSON.stringify(it)); }; @@ -115,6 +121,8 @@ const validatorForDialect = (dialect: Dialect) => { return { validator: backwardCompatiblePgSchema, version: 7 }; case 'sqlite': return { validator: backwardCompatibleSqliteSchema, version: 6 }; + case 'turso': + return { validator: backwardCompatibleSqliteSchema, version: 6 }; case 'mysql': return { validator: backwardCompatibleMysqlSchema, version: 5 }; } diff --git a/drizzle-kit/tests/cli-generate.test.ts b/drizzle-kit/tests/cli-generate.test.ts index 6eece0249..56a3a0d04 100644 --- a/drizzle-kit/tests/cli-generate.test.ts +++ b/drizzle-kit/tests/cli-generate.test.ts @@ -38,7 +38,6 @@ test('generate #1', async (t) => { schema: 'schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -58,7 +57,6 @@ test('generate #2', async (t) => { schema: 'schema.ts', out: 'out', bundle: false, - driver: undefined, }); }); @@ -75,7 +73,6 @@ test('generate #3', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -93,7 +90,6 @@ test('generate #4', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -110,7 +106,6 @@ test('generate #5', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -127,7 +122,6 @@ test('generate #6', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -147,7 +141,6 @@ test('generate #7', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, - driver: undefined, }); }); @@ -165,7 +158,6 @@ test('generate #8', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: true, // expo driver - driver: 'expo', }); }); @@ -186,7 +178,6 @@ test('generate #9', async (t) => { schema: 'schema.ts', out: 'out', bundle: false, - driver: undefined, }); }); diff --git a/drizzle-kit/tests/cli-migrate.test.ts b/drizzle-kit/tests/cli-migrate.test.ts index a4ffec2f0..1425691f0 100644 --- a/drizzle-kit/tests/cli-migrate.test.ts +++ b/drizzle-kit/tests/cli-migrate.test.ts @@ -31,11 +31,10 @@ test('migrate #2', async (t) => { const res = await brotest(migrate, '--config=turso.config.ts'); if (res.type !== 'handler') assert.fail(res.type, 'handler'); expect(res.options).toStrictEqual({ - dialect: 'sqlite', + dialect: 'turso', out: 'drizzle', credentials: { authToken: 'token', - driver: 'turso', url: 'turso.dev', }, schema: undefined, // drizzle migrations table schema diff --git a/drizzle-kit/tests/cli-push.test.ts b/drizzle-kit/tests/cli-push.test.ts index fb1ed3a11..f5b84fdce 100644 --- a/drizzle-kit/tests/cli-push.test.ts +++ b/drizzle-kit/tests/cli-push.test.ts @@ -34,10 +34,9 @@ test('push #2', async (t) => { const res = await brotest(push, '--config=turso.config.ts'); if (res.type !== 'handler') assert.fail(res.type, 'handler'); expect(res.options).toStrictEqual({ - dialect: 'sqlite', + dialect: 'turso', credentials: { authToken: 'token', - driver: 'turso', url: 'turso.dev', }, force: false, @@ -46,7 +45,6 @@ test('push #2', async (t) => { tablesFilter: [], strict: false, verbose: false, - driver: 'turso', }); }); @@ -67,7 +65,6 @@ test('push #3', async (t) => { tablesFilter: [], strict: false, verbose: false, - driver: 'd1-http', }); }); diff --git a/drizzle-kit/tests/cli/turso.config.ts b/drizzle-kit/tests/cli/turso.config.ts index 089e4d216..85efe5934 100644 --- a/drizzle-kit/tests/cli/turso.config.ts +++ b/drizzle-kit/tests/cli/turso.config.ts @@ -2,8 +2,7 @@ import { defineConfig } from '../../src'; export default defineConfig({ schema: './schema.ts', - dialect: 'sqlite', - driver: 'turso', + dialect: 'turso', dbCredentials: { url: 'turso.dev', authToken: 'token', diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 482caa995..5799b1fe3 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -217,9 +217,10 @@ test('added column not null and without default to table with data', async (t) = }; const table = getTableConfig(schema1.companies); + const seedStatements = [ - `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ("drizzle");`, - `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ("turso");`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ('drizzle');`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.name.name}") VALUES ('turso');`, ]; const { @@ -350,8 +351,8 @@ test('drop autoincrement. drop column with data', async (t) => { const table = getTableConfig(schema1.companies); const seedStatements = [ - `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (1, "drizzle");`, - `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (2, "turso");`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (1, 'drizzle');`, + `INSERT INTO \`${table.name}\` ("${schema1.companies.id.name}", "${schema1.companies.name.name}") VALUES (2, 'turso');`, ]; const { @@ -450,8 +451,8 @@ test('change autoincrement. table is part of foreign key', async (t) => { const { name: usersTableName } = getTableConfig(users1); const { name: companiesTableName } = getTableConfig(companies1); const seedStatements = [ - `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("drizzle");`, - `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ("turso");`, + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ('drizzle');`, + `INSERT INTO \`${usersTableName}\` ("${schema1.users.name.name}") VALUES ('turso');`, `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES (1);`, `INSERT INTO \`${companiesTableName}\` ("${schema1.companies.id.name}") VALUES (2);`, ]; @@ -631,7 +632,7 @@ test('drop table with data', async (t) => { }; const seedStatements = [ - `INSERT INTO \`users\` ("name") VALUES ("drizzle")`, + `INSERT INTO \`users\` ("name") VALUES ('drizzle')`, ]; const { statements, diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 888f7efcb..7568c6e11 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -161,7 +161,7 @@ "@aws-sdk/client-rds-data": "^3.549.0", "@cloudflare/workers-types": "^4.20230904.0", "@electric-sql/pglite": "^0.1.1", - "@libsql/client": "^0.5.6", + "@libsql/client": "^0.10.0", "@neondatabase/serverless": "^0.9.0", "@op-engineering/op-sqlite": "^2.0.16", "@opentelemetry/api": "^1.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2d091ad6..d2a4ff122 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.5.6)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -123,8 +123,8 @@ importers: specifier: ^0.2.1 version: 0.2.2(hono@4.5.0)(zod@3.23.7) '@libsql/client': - specifier: ^0.4.2 - version: 0.4.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + specifier: ^0.10.0 + version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': specifier: ^0.9.1 version: 0.9.3 @@ -303,14 +303,14 @@ importers: specifier: ^0.1.1 version: 0.1.5 '@libsql/client': - specifier: ^0.5.6 - version: 0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + specifier: ^0.10.0 + version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': specifier: ^0.9.0 version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -358,7 +358,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -2974,10 +2974,12 @@ packages: '@humanwhocodes/config-array@0.11.11': resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.13': resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} @@ -2990,9 +2992,11 @@ packages: '@humanwhocodes/object-schema@1.2.1': resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.1': resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} @@ -3078,31 +3082,31 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@libsql/client@0.4.3': - resolution: {integrity: sha512-AUYKnSPqAsFBVWBvmtrb4dG3pQlvTKT92eztAest9wQU2iJkabH8WzHLDb3dKFWKql7/kiCqvBQUVpozDwhekQ==} + '@libsql/client@0.10.0': + resolution: {integrity: sha512-2ERn08T4XOVx34yBtUPq0RDjAdd9TJ5qNH/izugr208ml2F94mk92qC64kXyDVQINodWJvp3kAdq6P4zTtCZ7g==} '@libsql/client@0.5.6': resolution: {integrity: sha512-UBjmDoxz75Z2sHdP+ETCROpeLA/77VMesiff8R4UWK1rnaWbh6/YoCLDILMJL3Rh0udQeKxjL8MjXthqohax+g==} - '@libsql/core@0.4.3': - resolution: {integrity: sha512-r28iYBtaLBW9RRgXPFh6cGCsVI/rwRlOzSOpAu/1PVTm6EJ3t233pUf97jETVHU0vjdr1d8VvV6fKAvJkokqCw==} + '@libsql/core@0.10.0': + resolution: {integrity: sha512-rqynAXGaiSpTsykOZdBtI1N4z4O+KZ6mt33K/aHeXAY0gSIfK/ctxuWa0Y1Bjo4FMz1idBTCXz4Ps5kITOvZZw==} '@libsql/core@0.5.6': resolution: {integrity: sha512-3vicUAydq6jPth410n4AsHHm1n2psTwvkSf94nfJlSXutGSZsl0updn2N/mJBgqUHkbuFoWZtlMifF0SwBj1xQ==} - '@libsql/darwin-arm64@0.2.0': - resolution: {integrity: sha512-+qyT2W/n5CFH1YZWv2mxW4Fsoo4dX9Z9M/nvbQqZ7H84J8hVegvVAsIGYzcK8xAeMEcpU5yGKB1Y9NoDY4hOSQ==} + '@libsql/darwin-arm64@0.3.18': + resolution: {integrity: sha512-Zt49dt+cwhPCkuoWgvjbQd4ckNfCJR5xzIAyhgHl3CBZqZaEuaXTOGKLNQT7bnFRPuQcdLt5PBT1cenKu2N6pA==} cpu: [arm64] os: [darwin] - '@libsql/darwin-arm64@0.3.18': - resolution: {integrity: sha512-Zt49dt+cwhPCkuoWgvjbQd4ckNfCJR5xzIAyhgHl3CBZqZaEuaXTOGKLNQT7bnFRPuQcdLt5PBT1cenKu2N6pA==} + '@libsql/darwin-arm64@0.3.19': + resolution: {integrity: sha512-rmOqsLcDI65zzxlUOoEiPJLhqmbFsZF6p4UJQ2kMqB+Kc0Rt5/A1OAdOZ/Wo8fQfJWjR1IbkbpEINFioyKf+nQ==} cpu: [arm64] os: [darwin] - '@libsql/darwin-x64@0.2.0': - resolution: {integrity: sha512-hwmO2mF1n8oDHKFrUju6Jv+n9iFtTf5JUK+xlnIE3Td0ZwGC/O1R/Z/btZTd9nD+vsvakC8SJT7/Q6YlWIkhEw==} - cpu: [x64] + '@libsql/darwin-arm64@0.4.1': + resolution: {integrity: sha512-XICT9/OyU8Aa9Iv1xZIHgvM09n/1OQUk3VC+s5uavzdiGHrDMkOWzN47JN7/FiMa/NWrcgoEiDMk3+e7mE53Ig==} + cpu: [arm64] os: [darwin] '@libsql/darwin-x64@0.3.18': @@ -3110,27 +3114,44 @@ packages: cpu: [x64] os: [darwin] + '@libsql/darwin-x64@0.3.19': + resolution: {integrity: sha512-q9O55B646zU+644SMmOQL3FIfpmEvdWpRpzubwFc2trsa+zoBlSkHuzU9v/C+UNoPHQVRMP7KQctJ455I/h/xw==} + cpu: [x64] + os: [darwin] + + '@libsql/darwin-x64@0.4.1': + resolution: {integrity: sha512-pSKxhRrhu4SsTD+IBRZXcs1SkwMdeAG1tv6Z/Ctp/sOEYrgkU8MDKLqkOr9NsmwpK4S0+JdwjkLMyhTkct/5TQ==} + cpu: [x64] + os: [darwin] + '@libsql/hrana-client@0.5.6': resolution: {integrity: sha512-mjQoAmejZ1atG+M3YR2ZW+rg6ceBByH/S/h17ZoYZkqbWrvohFhXyz2LFxj++ARMoY9m6w3RJJIRdJdmnEUlFg==} + '@libsql/hrana-client@0.6.2': + resolution: {integrity: sha512-MWxgD7mXLNf9FXXiM0bc90wCjZSpErWKr5mGza7ERy2FJNNMXd7JIOv+DepBA1FQTIfI8TFO4/QDYgaQC0goNw==} + '@libsql/isomorphic-fetch@0.1.12': resolution: {integrity: sha512-MRo4UcmjAGAa3ac56LoD5OE13m2p0lu0VEtZC2NZMcogM/jc5fU9YtMQ3qbPjFJ+u2BBjFZgMPkQaLS1dlMhpg==} + '@libsql/isomorphic-fetch@0.2.5': + resolution: {integrity: sha512-8s/B2TClEHms2yb+JGpsVRTPBfy1ih/Pq6h6gvyaNcYnMVJvgQRY7wAa8U2nD0dppbCuDU5evTNMEhrQ17ZKKg==} + engines: {node: '>=18.0.0'} + '@libsql/isomorphic-ws@0.1.5': resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} - '@libsql/linux-arm64-gnu@0.2.0': - resolution: {integrity: sha512-1w2lPXIYtnBaK5t/Ej5E8x7lPiE+jP3KATI/W4yei5Z/ONJh7jQW5PJ7sYU95vTME3hWEM1FXN6kvzcpFAte7w==} + '@libsql/linux-arm64-gnu@0.3.18': + resolution: {integrity: sha512-5m9xtDAhoyLSV54tho9uQ2ZIDeJWc0vU3Xpe/VK4+6bpURISs23qNhXiCrZnnq3oV0hFlBfcIgQUIATmb6jD2A==} cpu: [arm64] os: [linux] - '@libsql/linux-arm64-gnu@0.3.18': - resolution: {integrity: sha512-5m9xtDAhoyLSV54tho9uQ2ZIDeJWc0vU3Xpe/VK4+6bpURISs23qNhXiCrZnnq3oV0hFlBfcIgQUIATmb6jD2A==} + '@libsql/linux-arm64-gnu@0.3.19': + resolution: {integrity: sha512-mgeAUU1oqqh57k7I3cQyU6Trpdsdt607eFyEmH5QO7dv303ti+LjUvh1pp21QWV6WX7wZyjeJV1/VzEImB+jRg==} cpu: [arm64] os: [linux] - '@libsql/linux-arm64-musl@0.2.0': - resolution: {integrity: sha512-lkblBEJ7xuNiWNjP8DDq0rqoWccszfkUS7Efh5EjJ+GDWdCBVfh08mPofIZg0fZVLWQCY3j+VZCG1qZfATBizg==} + '@libsql/linux-arm64-gnu@0.4.1': + resolution: {integrity: sha512-9lpvb24tO2qZd9nq5dlq3ESA3hSKYWBIK7lJjfiCM6f7a70AUwBY9QoPJV9q4gILIyVnR1YBGrlm50nnb+dYgw==} cpu: [arm64] os: [linux] @@ -3139,9 +3160,14 @@ packages: cpu: [arm64] os: [linux] - '@libsql/linux-x64-gnu@0.2.0': - resolution: {integrity: sha512-+x/d289KeJydwOhhqSxKT+6MSQTCfLltzOpTzPccsvdt5fxg8CBi+gfvEJ4/XW23Sa+9bc7zodFP0i6MOlxX7w==} - cpu: [x64] + '@libsql/linux-arm64-musl@0.3.19': + resolution: {integrity: sha512-VEZtxghyK6zwGzU9PHohvNxthruSxBEnRrX7BSL5jQ62tN4n2JNepJ6SdzXp70pdzTfwroOj/eMwiPt94gkVRg==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-arm64-musl@0.4.1': + resolution: {integrity: sha512-lyxi+lFxE+NcBRDMQCxCtDg3c4WcKAbc9u63d5+B23Vm+UgphD9XY4seu+tGrBy1MU2tuNVix7r9S7ECpAaVrA==} + cpu: [arm64] os: [linux] '@libsql/linux-x64-gnu@0.3.18': @@ -3149,8 +3175,13 @@ packages: cpu: [x64] os: [linux] - '@libsql/linux-x64-musl@0.2.0': - resolution: {integrity: sha512-5Xn0c5A6vKf9D1ASpgk7mef//FuY7t5Lktj/eiU4n3ryxG+6WTpqstTittJUgepVjcleLPYxIhQAYeYwTYH1IQ==} + '@libsql/linux-x64-gnu@0.3.19': + resolution: {integrity: sha512-2t/J7LD5w2f63wGihEO+0GxfTyYIyLGEvTFEsMO16XI5o7IS9vcSHrxsvAJs4w2Pf907uDjmc7fUfMg6L82BrQ==} + cpu: [x64] + os: [linux] + + '@libsql/linux-x64-gnu@0.4.1': + resolution: {integrity: sha512-psvuQ3UFBEmDFV8ZHG+WkUHIJiWv+elZ+zIPvOVedlIKdxG1O+8WthWUAhFHOGnbiyzc4sAZ4c3de1oCvyHxyQ==} cpu: [x64] os: [linux] @@ -3159,16 +3190,31 @@ packages: cpu: [x64] os: [linux] - '@libsql/win32-x64-msvc@0.2.0': - resolution: {integrity: sha512-rpK+trBIpRST15m3cMYg5aPaX7kvCIottxY7jZPINkKAaScvfbn9yulU/iZUM9YtuK96Y1ZmvwyVIK/Y5DzoMQ==} + '@libsql/linux-x64-musl@0.3.19': + resolution: {integrity: sha512-BLsXyJaL8gZD8+3W2LU08lDEd9MIgGds0yPy5iNPp8tfhXx3pV/Fge2GErN0FC+nzt4DYQtjL+A9GUMglQefXQ==} cpu: [x64] - os: [win32] + os: [linux] + + '@libsql/linux-x64-musl@0.4.1': + resolution: {integrity: sha512-PDidJ3AhGDqosGg3OAZzGxMFIbnuOALya4BoezJKl667AFv3x7BBQ30H81Mngsq3Fh8RkJkXSdWfL91+Txb1iA==} + cpu: [x64] + os: [linux] '@libsql/win32-x64-msvc@0.3.18': resolution: {integrity: sha512-9EEIHz+e8tTbx9TMkb8ByZnzxc0pYFirK1nSbqC6cFEST95fiY0NCfQ/zAzJxe90KckbjifX6BbO69eWIi3TAg==} cpu: [x64] os: [win32] + '@libsql/win32-x64-msvc@0.3.19': + resolution: {integrity: sha512-ay1X9AobE4BpzG0XPw1gplyLZPGHIgJOovvW23gUrukRegiUP62uzhpRbKNogLlUOynyXeq//prHgPXiebUfWg==} + cpu: [x64] + os: [win32] + + '@libsql/win32-x64-msvc@0.4.1': + resolution: {integrity: sha512-IdODVqV/PrdOnHA/004uWyorZQuRsB7U7bCRCE3vXgABj3eJLJGc6cv2C6ksEaEoVxJbD8k53H4VVAGrtYwXzQ==} + cpu: [x64] + os: [win32] + '@miniflare/core@2.14.2': resolution: {integrity: sha512-n/smm5ZTg7ilGM4fxO7Gxhbe573oc8Za06M3b2fO+lPWqF6NJcEKdCC+sJntVFbn3Cbbd2G1ChISmugPfmlCkQ==} engines: {node: '>=16.13'} @@ -4509,6 +4555,7 @@ packages: are-we-there-yet@3.0.1: resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -6275,6 +6322,7 @@ packages: gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. generate-function@2.3.1: resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} @@ -7092,13 +7140,19 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - libsql@0.2.0: - resolution: {integrity: sha512-ELBRqhpJx5Dap0187zKQnntZyk4EjlDHSrjIVL8t+fQ5e8IxbQTeYgZgigMjB1EvrETdkm0Y0VxBGhzPQ+t0Jg==} - cpu: [x64, arm64] - os: [darwin, linux, win32] - libsql@0.3.18: resolution: {integrity: sha512-lvhKr7WV3NLWRbXkjn/MeKqXOAqWKU0PX9QYrvDh7fneukapj+iUQ4qgJASrQyxcCrEsClXCQiiK5W6OoYPAlA==} + cpu: [x64, arm64, wasm32] + os: [darwin, linux, win32] + + libsql@0.3.19: + resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} + cpu: [x64, arm64, wasm32] + os: [darwin, linux, win32] + + libsql@0.4.1: + resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -7785,6 +7839,7 @@ packages: npmlog@6.0.2: resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. npx-import@1.1.4: resolution: {integrity: sha512-3ShymTWOgqGyNlh5lMJAejLuIv3W1K3fbI5Ewc6YErZU3Sp0PqsNs8UIU1O8z5+KVl/Du5ag56Gza9vdorGEoA==} @@ -8302,6 +8357,9 @@ packages: bluebird: optional: true + promise-limit@2.7.0: + resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} + promise-retry@2.0.1: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} @@ -8598,6 +8656,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@5.0.0: @@ -10207,10 +10266,10 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10294,13 +10353,13 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/client-sso-oidc@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10337,7 +10396,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.478.0': @@ -10604,13 +10662,13 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0': + '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10647,6 +10705,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/core@3.477.0': @@ -10799,12 +10858,12 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.0.0 @@ -10889,13 +10948,13 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-http': 3.582.0 - '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.0.0 @@ -10970,10 +11029,10 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-sso@3.583.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/credential-provider-sso@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-sso': 3.583.0 - '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -11008,7 +11067,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -11209,16 +11268,16 @@ snapshots: '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -12890,7 +12949,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -12908,7 +12967,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13328,16 +13387,15 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - '@libsql/client@0.4.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: - '@libsql/core': 0.4.3 - '@libsql/hrana-client': 0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@libsql/core': 0.10.0 + '@libsql/hrana-client': 0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) js-base64: 3.7.7 - optionalDependencies: - libsql: 0.2.0 + libsql: 0.4.1 + promise-limit: 2.7.0 transitivePeerDependencies: - bufferutil - - encoding - utf-8-validate '@libsql/client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': @@ -13351,7 +13409,7 @@ snapshots: - encoding - utf-8-validate - '@libsql/core@0.4.3': + '@libsql/core@0.10.0': dependencies: js-base64: 3.7.7 @@ -13359,18 +13417,24 @@ snapshots: dependencies: js-base64: 3.7.7 - '@libsql/darwin-arm64@0.2.0': + '@libsql/darwin-arm64@0.3.18': optional: true - '@libsql/darwin-arm64@0.3.18': + '@libsql/darwin-arm64@0.3.19': optional: true - '@libsql/darwin-x64@0.2.0': + '@libsql/darwin-arm64@0.4.1': optional: true '@libsql/darwin-x64@0.3.18': optional: true + '@libsql/darwin-x64@0.3.19': + optional: true + + '@libsql/darwin-x64@0.4.1': + optional: true + '@libsql/hrana-client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@libsql/isomorphic-fetch': 0.1.12(encoding@0.1.13) @@ -13382,6 +13446,16 @@ snapshots: - encoding - utf-8-validate + '@libsql/hrana-client@0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)': + dependencies: + '@libsql/isomorphic-fetch': 0.2.5 + '@libsql/isomorphic-ws': 0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3) + js-base64: 3.7.7 + node-fetch: 3.3.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@libsql/isomorphic-fetch@0.1.12(encoding@0.1.13)': dependencies: '@types/node-fetch': 2.6.11 @@ -13389,6 +13463,8 @@ snapshots: transitivePeerDependencies: - encoding + '@libsql/isomorphic-fetch@0.2.5': {} + '@libsql/isomorphic-ws@0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: '@types/ws': 8.5.11 @@ -13397,36 +13473,51 @@ snapshots: - bufferutil - utf-8-validate - '@libsql/linux-arm64-gnu@0.2.0': + '@libsql/linux-arm64-gnu@0.3.18': optional: true - '@libsql/linux-arm64-gnu@0.3.18': + '@libsql/linux-arm64-gnu@0.3.19': optional: true - '@libsql/linux-arm64-musl@0.2.0': + '@libsql/linux-arm64-gnu@0.4.1': optional: true '@libsql/linux-arm64-musl@0.3.18': optional: true - '@libsql/linux-x64-gnu@0.2.0': + '@libsql/linux-arm64-musl@0.3.19': + optional: true + + '@libsql/linux-arm64-musl@0.4.1': optional: true '@libsql/linux-x64-gnu@0.3.18': optional: true - '@libsql/linux-x64-musl@0.2.0': + '@libsql/linux-x64-gnu@0.3.19': + optional: true + + '@libsql/linux-x64-gnu@0.4.1': optional: true '@libsql/linux-x64-musl@0.3.18': optional: true - '@libsql/win32-x64-msvc@0.2.0': + '@libsql/linux-x64-musl@0.3.19': + optional: true + + '@libsql/linux-x64-musl@0.4.1': optional: true '@libsql/win32-x64-msvc@0.3.18': optional: true + '@libsql/win32-x64-msvc@0.3.19': + optional: true + + '@libsql/win32-x64-msvc@0.4.1': + optional: true + '@miniflare/core@2.14.2': dependencies: '@iarna/toml': 2.2.5 @@ -13504,10 +13595,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) '@opentelemetry/api@1.8.0': {} @@ -13644,7 +13735,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13654,7 +13745,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13681,14 +13772,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13777,16 +13868,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13801,7 +13892,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13815,7 +13906,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13838,12 +13929,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) optionalDependencies: '@types/react': 18.3.1 @@ -15124,7 +15215,7 @@ snapshots: pathe: 1.1.2 picocolors: 1.0.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + vitest: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) '@vitest/utils@1.6.0': dependencies: @@ -16313,11 +16404,11 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.5.6)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 '@cloudflare/workers-types': 4.20240524.0 - '@libsql/client': 0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@libsql/client': 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': 0.9.3 '@opentelemetry/api': 1.8.0 '@planetscale/database': 1.18.0 @@ -17154,35 +17245,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) expo-modules-autolinking@1.11.1: dependencies: @@ -17196,24 +17287,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -18354,24 +18445,11 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - libsql@0.2.0: - dependencies: - '@neon-rs/load': 0.0.4 - detect-libc: 2.0.2 - optionalDependencies: - '@libsql/darwin-arm64': 0.2.0 - '@libsql/darwin-x64': 0.2.0 - '@libsql/linux-arm64-gnu': 0.2.0 - '@libsql/linux-arm64-musl': 0.2.0 - '@libsql/linux-x64-gnu': 0.2.0 - '@libsql/linux-x64-musl': 0.2.0 - '@libsql/win32-x64-msvc': 0.2.0 - optional: true - libsql@0.3.18: dependencies: '@neon-rs/load': 0.0.4 detect-libc: 2.0.2 + libsql: 0.3.19 optionalDependencies: '@libsql/darwin-arm64': 0.3.18 '@libsql/darwin-x64': 0.3.18 @@ -18381,6 +18459,33 @@ snapshots: '@libsql/linux-x64-musl': 0.3.18 '@libsql/win32-x64-msvc': 0.3.18 + libsql@0.3.19: + dependencies: + '@neon-rs/load': 0.0.4 + detect-libc: 2.0.2 + optionalDependencies: + '@libsql/darwin-arm64': 0.3.19 + '@libsql/darwin-x64': 0.3.19 + '@libsql/linux-arm64-gnu': 0.3.19 + '@libsql/linux-arm64-musl': 0.3.19 + '@libsql/linux-x64-gnu': 0.3.19 + '@libsql/linux-x64-musl': 0.3.19 + '@libsql/win32-x64-msvc': 0.3.19 + + libsql@0.4.1: + dependencies: + '@neon-rs/load': 0.0.4 + detect-libc: 2.0.2 + libsql: 0.3.19 + optionalDependencies: + '@libsql/darwin-arm64': 0.4.1 + '@libsql/darwin-x64': 0.4.1 + '@libsql/linux-arm64-gnu': 0.4.1 + '@libsql/linux-arm64-musl': 0.4.1 + '@libsql/linux-x64-gnu': 0.4.1 + '@libsql/linux-x64-musl': 0.4.1 + '@libsql/win32-x64-msvc': 0.4.1 + lighthouse-logger@1.4.2: dependencies: debug: 2.6.9 @@ -18689,12 +18794,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18770,13 +18875,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18790,7 +18895,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -18816,7 +18921,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -18824,7 +18929,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -18833,7 +18938,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -19638,6 +19743,8 @@ snapshots: promise-inflight@1.0.1: optional: true + promise-limit@2.7.0: {} + promise-retry@2.0.1: dependencies: err-code: 2.0.3 @@ -19717,10 +19824,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8): + react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19733,19 +19840,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19764,14 +19871,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8) + react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -21624,15 +21731,17 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8): + ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8): + ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From 5be80aa02c41cf91126af8259271db19f61081b1 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 2 Sep 2024 16:18:02 +0300 Subject: [PATCH 119/492] fixed dialects in introspect musql, psql, sqlite updated packages --- drizzle-kit/src/cli/commands/introspect.ts | 6 +- drizzle-orm/package.json | 2 +- integration-tests/package.json | 2 +- pnpm-lock.yaml | 334 +++++++++------------ 4 files changed, 143 insertions(+), 201 deletions(-) diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 285264ffc..acd569dea 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -202,7 +202,7 @@ export const introspectMysql = async ( writeFileSync(relationsFile, relationsTs.file); console.log(); - const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + const { snapshots, journal } = prepareOutFolder(out, 'mysql'); if (snapshots.length === 0) { const { sqlStatements, _meta } = await applyMysqlSnapshotsDiff( @@ -313,7 +313,7 @@ export const introspectSqlite = async ( writeFileSync(relationsFile, relationsTs.file); console.log(); - const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + const { snapshots, journal } = prepareOutFolder(out, 'sqlite'); if (snapshots.length === 0) { const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( @@ -424,7 +424,7 @@ export const introspectLibSQL = async ( writeFileSync(relationsFile, relationsTs.file); console.log(); - const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + const { snapshots, journal } = prepareOutFolder(out, 'sqlite'); if (snapshots.length === 0) { const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 7568c6e11..11970a77e 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -46,7 +46,7 @@ "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=3", "@electric-sql/pglite": ">=0.1.1", - "@libsql/client": "*", + "@libsql/client": ">=0.10.0", "@neondatabase/serverless": ">=0.1", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", diff --git a/integration-tests/package.json b/integration-tests/package.json index a4fcab0b2..78f36fe30 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -15,6 +15,7 @@ "license": "Apache-2.0", "private": true, "devDependencies": { + "@libsql/client": "^0.10.0", "@neondatabase/serverless": "0.9.0", "@originjs/vite-plugin-commonjs": "^1.0.3", "@paralleldrive/cuid2": "^2.2.2", @@ -41,7 +42,6 @@ "@aws-sdk/client-rds-data": "^3.549.0", "@aws-sdk/credential-providers": "^3.549.0", "@electric-sql/pglite": "^0.1.1", - "@libsql/client": "^0.5.6", "@miniflare/d1": "^2.14.2", "@miniflare/shared": "^2.14.2", "@planetscale/database": "^1.16.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2a4ff122..0036fd37e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -310,7 +310,7 @@ importers: version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -358,7 +358,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -551,9 +551,6 @@ importers: '@electric-sql/pglite': specifier: ^0.1.1 version: 0.1.5 - '@libsql/client': - specifier: ^0.5.6 - version: 0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@miniflare/d1': specifier: ^2.14.2 version: 2.14.2 @@ -645,6 +642,9 @@ importers: specifier: ^3.20.2 version: 3.23.7 devDependencies: + '@libsql/client': + specifier: ^0.10.0 + version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': specifier: 0.9.0 version: 0.9.0 @@ -3085,20 +3085,9 @@ packages: '@libsql/client@0.10.0': resolution: {integrity: sha512-2ERn08T4XOVx34yBtUPq0RDjAdd9TJ5qNH/izugr208ml2F94mk92qC64kXyDVQINodWJvp3kAdq6P4zTtCZ7g==} - '@libsql/client@0.5.6': - resolution: {integrity: sha512-UBjmDoxz75Z2sHdP+ETCROpeLA/77VMesiff8R4UWK1rnaWbh6/YoCLDILMJL3Rh0udQeKxjL8MjXthqohax+g==} - '@libsql/core@0.10.0': resolution: {integrity: sha512-rqynAXGaiSpTsykOZdBtI1N4z4O+KZ6mt33K/aHeXAY0gSIfK/ctxuWa0Y1Bjo4FMz1idBTCXz4Ps5kITOvZZw==} - '@libsql/core@0.5.6': - resolution: {integrity: sha512-3vicUAydq6jPth410n4AsHHm1n2psTwvkSf94nfJlSXutGSZsl0updn2N/mJBgqUHkbuFoWZtlMifF0SwBj1xQ==} - - '@libsql/darwin-arm64@0.3.18': - resolution: {integrity: sha512-Zt49dt+cwhPCkuoWgvjbQd4ckNfCJR5xzIAyhgHl3CBZqZaEuaXTOGKLNQT7bnFRPuQcdLt5PBT1cenKu2N6pA==} - cpu: [arm64] - os: [darwin] - '@libsql/darwin-arm64@0.3.19': resolution: {integrity: sha512-rmOqsLcDI65zzxlUOoEiPJLhqmbFsZF6p4UJQ2kMqB+Kc0Rt5/A1OAdOZ/Wo8fQfJWjR1IbkbpEINFioyKf+nQ==} cpu: [arm64] @@ -3109,11 +3098,6 @@ packages: cpu: [arm64] os: [darwin] - '@libsql/darwin-x64@0.3.18': - resolution: {integrity: sha512-faq6HUGDaNaueeqPei5cypHaD/hhazUyfHo094CXiEeRZq6ZKtNl5PHdlr8jE/Uw8USNpVVQaLdnvSgKcpRPHw==} - cpu: [x64] - os: [darwin] - '@libsql/darwin-x64@0.3.19': resolution: {integrity: sha512-q9O55B646zU+644SMmOQL3FIfpmEvdWpRpzubwFc2trsa+zoBlSkHuzU9v/C+UNoPHQVRMP7KQctJ455I/h/xw==} cpu: [x64] @@ -3124,15 +3108,9 @@ packages: cpu: [x64] os: [darwin] - '@libsql/hrana-client@0.5.6': - resolution: {integrity: sha512-mjQoAmejZ1atG+M3YR2ZW+rg6ceBByH/S/h17ZoYZkqbWrvohFhXyz2LFxj++ARMoY9m6w3RJJIRdJdmnEUlFg==} - '@libsql/hrana-client@0.6.2': resolution: {integrity: sha512-MWxgD7mXLNf9FXXiM0bc90wCjZSpErWKr5mGza7ERy2FJNNMXd7JIOv+DepBA1FQTIfI8TFO4/QDYgaQC0goNw==} - '@libsql/isomorphic-fetch@0.1.12': - resolution: {integrity: sha512-MRo4UcmjAGAa3ac56LoD5OE13m2p0lu0VEtZC2NZMcogM/jc5fU9YtMQ3qbPjFJ+u2BBjFZgMPkQaLS1dlMhpg==} - '@libsql/isomorphic-fetch@0.2.5': resolution: {integrity: sha512-8s/B2TClEHms2yb+JGpsVRTPBfy1ih/Pq6h6gvyaNcYnMVJvgQRY7wAa8U2nD0dppbCuDU5evTNMEhrQ17ZKKg==} engines: {node: '>=18.0.0'} @@ -3140,11 +3118,6 @@ packages: '@libsql/isomorphic-ws@0.1.5': resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} - '@libsql/linux-arm64-gnu@0.3.18': - resolution: {integrity: sha512-5m9xtDAhoyLSV54tho9uQ2ZIDeJWc0vU3Xpe/VK4+6bpURISs23qNhXiCrZnnq3oV0hFlBfcIgQUIATmb6jD2A==} - cpu: [arm64] - os: [linux] - '@libsql/linux-arm64-gnu@0.3.19': resolution: {integrity: sha512-mgeAUU1oqqh57k7I3cQyU6Trpdsdt607eFyEmH5QO7dv303ti+LjUvh1pp21QWV6WX7wZyjeJV1/VzEImB+jRg==} cpu: [arm64] @@ -3155,11 +3128,6 @@ packages: cpu: [arm64] os: [linux] - '@libsql/linux-arm64-musl@0.3.18': - resolution: {integrity: sha512-oYD5+oM2gPEalp+EoR5DVQBRtdGjLsocjsRbQs5O2m4WOBJKER7VUfDYZHsifLGZoBSc11Yo6s9IR9rjGWy20w==} - cpu: [arm64] - os: [linux] - '@libsql/linux-arm64-musl@0.3.19': resolution: {integrity: sha512-VEZtxghyK6zwGzU9PHohvNxthruSxBEnRrX7BSL5jQ62tN4n2JNepJ6SdzXp70pdzTfwroOj/eMwiPt94gkVRg==} cpu: [arm64] @@ -3170,11 +3138,6 @@ packages: cpu: [arm64] os: [linux] - '@libsql/linux-x64-gnu@0.3.18': - resolution: {integrity: sha512-QDSSP60nS8KIldGE7H3bpEflQHiL1erwED6huoVJdmDFxsyDJX2CYdWUWW8Za0ZUOvUbnEWAOyMhp6j1dBbZqw==} - cpu: [x64] - os: [linux] - '@libsql/linux-x64-gnu@0.3.19': resolution: {integrity: sha512-2t/J7LD5w2f63wGihEO+0GxfTyYIyLGEvTFEsMO16XI5o7IS9vcSHrxsvAJs4w2Pf907uDjmc7fUfMg6L82BrQ==} cpu: [x64] @@ -3185,11 +3148,6 @@ packages: cpu: [x64] os: [linux] - '@libsql/linux-x64-musl@0.3.18': - resolution: {integrity: sha512-5SXwTlaLCUPzxYyq+P0c7Ko7tcEjpd1X6RZKe1DuRFmJPg6f7j2+LrPEhMSIbqKcrl5ACUUAyoKmGZqNYwz23w==} - cpu: [x64] - os: [linux] - '@libsql/linux-x64-musl@0.3.19': resolution: {integrity: sha512-BLsXyJaL8gZD8+3W2LU08lDEd9MIgGds0yPy5iNPp8tfhXx3pV/Fge2GErN0FC+nzt4DYQtjL+A9GUMglQefXQ==} cpu: [x64] @@ -3200,11 +3158,6 @@ packages: cpu: [x64] os: [linux] - '@libsql/win32-x64-msvc@0.3.18': - resolution: {integrity: sha512-9EEIHz+e8tTbx9TMkb8ByZnzxc0pYFirK1nSbqC6cFEST95fiY0NCfQ/zAzJxe90KckbjifX6BbO69eWIi3TAg==} - cpu: [x64] - os: [win32] - '@libsql/win32-x64-msvc@0.3.19': resolution: {integrity: sha512-ay1X9AobE4BpzG0XPw1gplyLZPGHIgJOovvW23gUrukRegiUP62uzhpRbKNogLlUOynyXeq//prHgPXiebUfWg==} cpu: [x64] @@ -4102,9 +4055,6 @@ packages: '@types/minimist@1.2.2': resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} - '@types/node-fetch@2.6.11': - resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} - '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} @@ -7140,11 +7090,6 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - libsql@0.3.18: - resolution: {integrity: sha512-lvhKr7WV3NLWRbXkjn/MeKqXOAqWKU0PX9QYrvDh7fneukapj+iUQ4qgJASrQyxcCrEsClXCQiiK5W6OoYPAlA==} - cpu: [x64, arm64, wasm32] - os: [darwin, linux, win32] - libsql@0.3.19: resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} cpu: [x64, arm64, wasm32] @@ -10267,7 +10212,7 @@ snapshots: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.583.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10357,9 +10302,9 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -10662,7 +10607,7 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/client-sts@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 @@ -10704,6 +10649,51 @@ snapshots: '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/core': 3.582.0 + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)) + '@aws-sdk/middleware-host-header': 3.577.0 + '@aws-sdk/middleware-logger': 3.577.0 + '@aws-sdk/middleware-recursion-detection': 3.577.0 + '@aws-sdk/middleware-user-agent': 3.583.0 + '@aws-sdk/region-config-resolver': 3.577.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-endpoints': 3.583.0 + '@aws-sdk/util-user-agent-browser': 3.577.0 + '@aws-sdk/util-user-agent-node': 3.577.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 + '@smithy/fetch-http-handler': 3.0.1 + '@smithy/hash-node': 3.0.0 + '@smithy/invalid-dependency': 3.0.0 + '@smithy/middleware-content-length': 3.0.0 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 + '@smithy/middleware-serde': 3.0.0 + '@smithy/middleware-stack': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/node-http-handler': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + '@smithy/url-parser': 3.0.0 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 + '@smithy/util-middleware': 3.0.0 + '@smithy/util-retry': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.2 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -10860,7 +10850,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -10948,6 +10938,25 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt + '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0))': + dependencies: + '@aws-sdk/credential-provider-env': 3.577.0 + '@aws-sdk/credential-provider-http': 3.582.0 + '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-process': 3.577.0 + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)) + '@aws-sdk/types': 3.577.0 + '@smithy/credential-provider-imds': 3.0.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 + '@smithy/types': 3.0.0 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/credential-provider-env': 3.577.0 @@ -11065,7 +11074,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0))': dependencies: '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 @@ -11073,6 +11082,14 @@ snapshots: '@smithy/types': 3.0.0 tslib: 2.6.2 + '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': + dependencies: + '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/types': 3.577.0 + '@smithy/property-provider': 3.0.0 + '@smithy/types': 3.0.0 + tslib: 2.6.2 + '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-cognito-identity': 3.569.0 @@ -12949,7 +12966,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -12967,7 +12984,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13398,54 +13415,22 @@ snapshots: - bufferutil - utf-8-validate - '@libsql/client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': - dependencies: - '@libsql/core': 0.5.6 - '@libsql/hrana-client': 0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - js-base64: 3.7.7 - libsql: 0.3.18 - transitivePeerDependencies: - - bufferutil - - encoding - - utf-8-validate - '@libsql/core@0.10.0': dependencies: js-base64: 3.7.7 - '@libsql/core@0.5.6': - dependencies: - js-base64: 3.7.7 - - '@libsql/darwin-arm64@0.3.18': - optional: true - '@libsql/darwin-arm64@0.3.19': optional: true '@libsql/darwin-arm64@0.4.1': optional: true - '@libsql/darwin-x64@0.3.18': - optional: true - '@libsql/darwin-x64@0.3.19': optional: true '@libsql/darwin-x64@0.4.1': optional: true - '@libsql/hrana-client@0.5.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': - dependencies: - '@libsql/isomorphic-fetch': 0.1.12(encoding@0.1.13) - '@libsql/isomorphic-ws': 0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3) - js-base64: 3.7.7 - node-fetch: 3.3.2 - transitivePeerDependencies: - - bufferutil - - encoding - - utf-8-validate - '@libsql/hrana-client@0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: '@libsql/isomorphic-fetch': 0.2.5 @@ -13456,62 +13441,40 @@ snapshots: - bufferutil - utf-8-validate - '@libsql/isomorphic-fetch@0.1.12(encoding@0.1.13)': - dependencies: - '@types/node-fetch': 2.6.11 - node-fetch: 2.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding - '@libsql/isomorphic-fetch@0.2.5': {} '@libsql/isomorphic-ws@0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: '@types/ws': 8.5.11 - ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate - '@libsql/linux-arm64-gnu@0.3.18': - optional: true - '@libsql/linux-arm64-gnu@0.3.19': optional: true '@libsql/linux-arm64-gnu@0.4.1': optional: true - '@libsql/linux-arm64-musl@0.3.18': - optional: true - '@libsql/linux-arm64-musl@0.3.19': optional: true '@libsql/linux-arm64-musl@0.4.1': optional: true - '@libsql/linux-x64-gnu@0.3.18': - optional: true - '@libsql/linux-x64-gnu@0.3.19': optional: true '@libsql/linux-x64-gnu@0.4.1': optional: true - '@libsql/linux-x64-musl@0.3.18': - optional: true - '@libsql/linux-x64-musl@0.3.19': optional: true '@libsql/linux-x64-musl@0.4.1': optional: true - '@libsql/win32-x64-msvc@0.3.18': - optional: true - '@libsql/win32-x64-msvc@0.3.19': optional: true @@ -13595,10 +13558,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) '@opentelemetry/api@1.8.0': {} @@ -13735,7 +13698,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13745,7 +13708,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -13772,14 +13735,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13868,16 +13831,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13892,7 +13855,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13906,7 +13869,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -13929,12 +13892,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) optionalDependencies: '@types/react': 18.3.1 @@ -14775,11 +14738,6 @@ snapshots: '@types/minimist@1.2.2': {} - '@types/node-fetch@2.6.11': - dependencies: - '@types/node': 20.12.12 - form-data: 4.0.0 - '@types/node-forge@1.3.11': dependencies: '@types/node': 20.12.12 @@ -17245,35 +17203,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) expo-modules-autolinking@1.11.1: dependencies: @@ -17287,24 +17245,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -18445,20 +18403,6 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - libsql@0.3.18: - dependencies: - '@neon-rs/load': 0.0.4 - detect-libc: 2.0.2 - libsql: 0.3.19 - optionalDependencies: - '@libsql/darwin-arm64': 0.3.18 - '@libsql/darwin-x64': 0.3.18 - '@libsql/linux-arm64-gnu': 0.3.18 - '@libsql/linux-arm64-musl': 0.3.18 - '@libsql/linux-x64-gnu': 0.3.18 - '@libsql/linux-x64-musl': 0.3.18 - '@libsql/win32-x64-msvc': 0.3.18 - libsql@0.3.19: dependencies: '@neon-rs/load': 0.0.4 @@ -18794,12 +18738,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18875,13 +18819,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18895,7 +18839,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -18921,7 +18865,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -18929,7 +18873,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -18938,7 +18882,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -19824,10 +19768,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + react-devtools-core@5.2.0(bufferutil@4.0.8): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19840,19 +19784,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19871,14 +19815,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + react-devtools-core: 5.2.0(bufferutil@4.0.8) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -21731,17 +21675,15 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@6.2.2(bufferutil@4.0.8): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@7.5.9(bufferutil@4.0.8): optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From b351b91b428d4a2047d6aa6bc45f45122190b767 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 2 Sep 2024 17:28:57 +0300 Subject: [PATCH 120/492] updated tests and removed pragma from push in libsql --- .../src/cli/commands/libSqlPushUtils.ts | 7 ------ drizzle-kit/src/cli/connections.ts | 1 + .../src/serializer/sqliteSerializer.ts | 3 ++- drizzle-kit/tests/push/libsql.test.ts | 24 ++++++++----------- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts index 98c95f089..01bb61334 100644 --- a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts +++ b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts @@ -298,17 +298,10 @@ export const libSqlLogSuggestionsAndReturn = async ( continue; } - // ! for libsql it will break - const [{ foreign_keys: pragmaState }] = await connection.query<{ - foreign_keys: number; - }>(`PRAGMA foreign_keys;`); - - if (pragmaState) statementsToExecute.push(`PRAGMA foreign_keys=OFF;`); // recreate table statementsToExecute.push( ..._moveDataStatements(tableName, json2, dataLoss), ); - if (pragmaState) statementsToExecute.push(`PRAGMA foreign_keys=ON;`); } else if ( statement.type === 'alter_table_alter_column_set_generated' || statement.type === 'alter_table_alter_column_drop_generated' diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index ee0ce04c3..2e329d40c 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -644,6 +644,7 @@ export const connectToLibSQL = async (credentials: LibSQLCredentials): Promise< const client = createClient({ url: normaliseSQLiteUrl(credentials.url, 'libsql'), + authToken: credentials.authToken, }); const drzl = drizzle(client); const migrateFn = async (config: MigrationConfig) => { diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index ce544235b..81c633cb2 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -363,7 +363,6 @@ export const fromDatabase = async ( ) => void, ): Promise => { const result: Record = {}; - const columns = await db.query<{ tableName: string; columnName: string; @@ -389,6 +388,8 @@ export const fromDatabase = async ( `, ); + console.log('HERE'); + const tablesWithSeq: string[] = []; const seq = await db.query<{ diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 5799b1fe3..89ec008ca 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -493,21 +493,19 @@ test('change autoincrement. table is part of foreign key', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements.length).toBe(6); - expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); - expect(sqlStatements[1]).toBe( + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( `CREATE TABLE \`__new_companies\` ( \t\`id\` integer PRIMARY KEY NOT NULL );\n`, ); - expect(sqlStatements[2]).toBe( + expect(sqlStatements[1]).toBe( `INSERT INTO \`__new_companies\`("id") SELECT "id" FROM \`companies\`;`, ); - expect(sqlStatements[3]).toBe(`DROP TABLE \`companies\`;`); - expect(sqlStatements[4]).toBe( + expect(sqlStatements[2]).toBe(`DROP TABLE \`companies\`;`); + expect(sqlStatements[3]).toBe( `ALTER TABLE \`__new_companies\` RENAME TO \`companies\`;`, ); - expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); @@ -756,21 +754,19 @@ test('recreate table with nested references', async (t) => { uniqueConstraints: [], }); - expect(sqlStatements!.length).toBe(6); - expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); - expect(sqlStatements![1]).toBe(`CREATE TABLE \`__new_users\` ( + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY NOT NULL, \t\`name\` text, \t\`age\` integer );\n`); - expect(sqlStatements![2]).toBe( + expect(sqlStatements![1]).toBe( `INSERT INTO \`__new_users\`("id", "name", "age") SELECT "id", "name", "age" FROM \`users\`;`, ); - expect(sqlStatements![3]).toBe(`DROP TABLE \`users\`;`); - expect(sqlStatements![4]).toBe( + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, ); - expect(sqlStatements[5]).toBe('PRAGMA foreign_keys=ON;'); expect(columnsToRemove!.length).toBe(0); expect(infoToPrint!.length).toBe(0); From 807aa5b3418be6195eb471a76f77ad5190be766a Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 2 Sep 2024 17:55:02 +0300 Subject: [PATCH 121/492] removed console.log --- drizzle-kit/src/serializer/sqliteSerializer.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 81c633cb2..41edd78a9 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -388,8 +388,6 @@ export const fromDatabase = async ( `, ); - console.log('HERE'); - const tablesWithSeq: string[] = []; const seq = await db.query<{ From ab3b46d2936a8d6362df798995616210d04135bd Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 2 Sep 2024 18:33:42 +0300 Subject: [PATCH 122/492] Added monomigrator --- drizzle-orm/src/index.ts | 1 + drizzle-orm/src/monomigrator.ts | 266 ++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 drizzle-orm/src/monomigrator.ts diff --git a/drizzle-orm/src/index.ts b/drizzle-orm/src/index.ts index 5cabdb0d8..469f5713e 100644 --- a/drizzle-orm/src/index.ts +++ b/drizzle-orm/src/index.ts @@ -6,6 +6,7 @@ export * from './errors.ts'; export * from './expressions.ts'; export * from './logger.ts'; export * from './monodriver.ts'; +export * from './monomigrator.ts'; export * from './operations.ts'; export * from './query-promise.ts'; export * from './relations.ts'; diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts new file mode 100644 index 000000000..b82a1ea0b --- /dev/null +++ b/drizzle-orm/src/monomigrator.ts @@ -0,0 +1,266 @@ +/* eslint-disable import/extensions */ +import type { AwsDataApiPgDatabase } from './aws-data-api/pg/index.ts'; +import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; +import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; +import type { DrizzleD1Database } from './d1/index.ts'; +import type { ExpoSQLiteDatabase } from './expo-sqlite/index.ts'; +import type { LibSQLDatabase } from './libsql/index.ts'; +import type { MigrationConfig } from './migrator.ts'; +import type { MySqlRemoteDatabase } from './mysql-proxy/index.ts'; +import type { ProxyMigrator as MySqlProxyMigrator } from './mysql-proxy/migrator.ts'; +import type { MySql2Database } from './mysql2/index.ts'; +import type { NeonHttpDatabase } from './neon-http/index.ts'; +import type { NeonDatabase } from './neon-serverless/index.ts'; +import type { NodePgDatabase } from './node-postgres/index.ts'; +import type { OPSQLiteDatabase } from './op-sqlite/index.ts'; +import type { PgRemoteDatabase } from './pg-proxy/index.ts'; +import type { ProxyMigrator as PgProxyMigrator } from './pg-proxy/migrator.ts'; +import type { PgliteDatabase } from './pglite/index.ts'; +import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; +import type { ProxyMigrator as SQLiteProxyMigrator } from './sqlite-proxy/migrator.ts'; +import type { VercelPgDatabase } from './vercel-postgres/index.ts'; +import type { XataHttpDatabase } from './xata-http/index.ts'; +import type { MigrationConfig as XataHttpMigrationConfig } from './xata-http/migrator.ts'; + +type OPSQLiteMigrationConfig = { + journal: { + entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; + }; + migrations: Record; +}; + +type ExpoSQLiteMigrationConfig = { + journal: { + entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; + }; + migrations: Record; +}; + +type DatabaseType = + | 'aws-data-api-pg' + | 'better-sqlite3' + | 'bun:sqlite' + | 'd1' + | 'expo-sqlite' + | 'libsql' + | 'mysql-proxy' + | 'mysql2' + | 'neon-http' + | 'neon-serverless' + | 'node-postgres' + | 'op-sqlite' + | 'pg-proxy' + | 'pglite' + | 'planetscale' + | 'postgres-js' + | 'sqlite-proxy' + | 'tidb-serverless' + | 'vercel-postgres' + | 'xata-http'; + +export async function migrate( + type: 'aws-data-api-pg', + db: AwsDataApiPgDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'better-sqlite3', + db: BetterSQLite3Database, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'bun:sqlite', + db: BunSQLiteDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate(type: 'd1', db: DrizzleD1Database, config: string | MigrationConfig): Promise; +export async function migrate( + type: 'expo-sqlite', + db: ExpoSQLiteDatabase, + config: ExpoSQLiteMigrationConfig, +): Promise; +export async function migrate(type: 'libsql', db: LibSQLDatabase, config: MigrationConfig): Promise; +export async function migrate( + type: 'mysql-proxy', + db: MySqlRemoteDatabase, + callback: MySqlProxyMigrator, + config: MigrationConfig, +): Promise; +export async function migrate(type: 'mysql2', db: MySql2Database, config: MigrationConfig): Promise; +export async function migrate( + type: 'neon-http', + db: NeonHttpDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'neon-serverless', + db: NeonDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'node-postgres', + db: NodePgDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'op-sqlite', + db: OPSQLiteDatabase, + config: OPSQLiteMigrationConfig, +): Promise; +export async function migrate( + type: 'pg-proxy', + db: PgRemoteDatabase, + callback: PgProxyMigrator, + config: string | MigrationConfig, +): Promise; +export async function migrate(type: 'pglite', db: PgliteDatabase, config: string | MigrationConfig): Promise; +export async function migrate( + type: 'planetscale', + db: PlanetScaleDatabase, + config: MigrationConfig, +): Promise; +export async function migrate( + type: 'postgres-js', + db: PlanetScaleDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'sqlite-proxy', + db: PgRemoteDatabase, + callback: SQLiteProxyMigrator, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'tidb-serverless', + db: PlanetScaleDatabase, + config: MigrationConfig, +): Promise; +export async function migrate( + type: 'vercel-postgres', + db: VercelPgDatabase, + config: string | MigrationConfig, +): Promise; +export async function migrate( + type: 'xata-http', + db: XataHttpDatabase, + config: string | XataHttpMigrationConfig, +): Promise; +export async function migrate( + type: DatabaseType, + db: any, + config: + | string + | MigrationConfig + | ExpoSQLiteMigrationConfig + | OPSQLiteMigrationConfig + | XataHttpMigrationConfig + | PgProxyMigrator + | MySqlProxyMigrator + | SQLiteProxyMigrator, + extraConfig?: string | MigrationConfig | undefined, +) { + const rest = [db, config, extraConfig]; + + switch (type) { + case 'aws-data-api-pg': { + const { migrate } = await import('./aws-data-api/pg/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'better-sqlite3': { + const { migrate } = await import('./better-sqlite3/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'bun:sqlite': { + const { migrate } = await import('./bun-sqlite/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'd1': { + const { migrate } = await import('./d1/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'expo-sqlite': { + const { migrate } = await import('./expo-sqlite/migrator'); + + return migrate(rest[0], rest[1] as ExpoSQLiteMigrationConfig); + } + case 'libsql': { + const { migrate } = await import('./libsql/migrator'); + + return migrate(rest[0], rest[1] as MigrationConfig); + } + case 'mysql-proxy': { + const { migrate } = await import('./mysql-proxy/migrator'); + + return migrate(rest[0], rest[1] as MySqlProxyMigrator, rest[2] as MigrationConfig); + } + case 'mysql2': { + const { migrate } = await import('./mysql2/migrator'); + + return migrate(rest[0], rest[1] as MigrationConfig); + } + case 'neon-http': { + const { migrate } = await import('./neon-http/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'neon-serverless': { + const { migrate } = await import('./neon-serverless/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'node-postgres': { + const { migrate } = await import('./node-postgres/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'op-sqlite': { + const { migrate } = await import('./op-sqlite/migrator'); + + return migrate(rest[0], rest[1] as OPSQLiteMigrationConfig); + } + case 'pg-proxy': { + const { migrate } = await import('./pg-proxy/migrator'); + + return migrate(rest[0], rest[1] as PgProxyMigrator, rest[2] as string | MigrationConfig); + } + case 'pglite': { + const { migrate } = await import('./pglite/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'planetscale': { + const { migrate } = await import('./planetscale-serverless/migrator'); + + return migrate(rest[0], rest[1] as MigrationConfig); + } + case 'postgres-js': { + const { migrate } = await import('./postgres-js/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'sqlite-proxy': { + const { migrate } = await import('./sqlite-proxy/migrator'); + + return migrate(rest[0], rest[1] as SQLiteProxyMigrator, rest[2] as string | MigrationConfig); + } + case 'tidb-serverless': { + const { migrate } = await import('./tidb-serverless/migrator'); + + return migrate(rest[0], rest[1] as MigrationConfig); + } + case 'vercel-postgres': { + const { migrate } = await import('./vercel-postgres/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + case 'xata-http': { + const { migrate } = await import('./xata-http/migrator'); + + return migrate(rest[0], rest[1] as string | MigrationConfig); + } + } +} From 5f32787735d13e1e4e3b089cf1a30fb17140ee7c Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 3 Sep 2024 12:47:31 +0300 Subject: [PATCH 123/492] Changed style of monodriver, monomigrator function args --- drizzle-orm/src/better-sqlite3/driver.ts | 11 +- drizzle-orm/src/bun-sqlite/driver.ts | 9 +- drizzle-orm/src/expo-sqlite/driver.ts | 11 +- drizzle-orm/src/monodriver.ts | 120 ++++++++++++---- drizzle-orm/src/monomigrator.ts | 132 ++++++------------ drizzle-orm/src/mysql-proxy/driver.ts | 9 +- drizzle-orm/src/neon-serverless/driver.ts | 8 +- drizzle-orm/src/op-sqlite/driver.ts | 9 +- drizzle-orm/src/pg-proxy/driver.ts | 9 +- drizzle-orm/src/pglite/driver.ts | 8 +- .../src/planetscale-serverless/driver.ts | 9 +- drizzle-orm/src/postgres-js/driver.ts | 9 +- drizzle-orm/src/tidb-serverless/driver.ts | 9 +- drizzle-orm/src/vercel-postgres/driver.ts | 8 +- 14 files changed, 213 insertions(+), 148 deletions(-) diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 728586e57..8d19cd8ab 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -1,4 +1,5 @@ import type { Database, RunResult } from 'better-sqlite3'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { createTableRelationsHelpers, @@ -11,9 +12,11 @@ import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { BetterSQLiteSession } from './session.ts'; -export type BetterSQLite3Database< - TSchema extends Record = Record, -> = BaseSQLiteDatabase<'sync', RunResult, TSchema>; +export class BetterSQLite3Database> + extends BaseSQLiteDatabase<'sync', RunResult, TSchema> +{ + static readonly [entityKind]: string = 'BetterSQLite3Database'; +} export function drizzle = Record>( client: Database, @@ -41,5 +44,5 @@ export function drizzle = Record; + return new BetterSQLite3Database('sync', dialect, session, schema) as BetterSQLite3Database; } diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index 0d196ff03..5771bd371 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -1,6 +1,7 @@ /// import type { Database } from 'bun:sqlite'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { createTableRelationsHelpers, @@ -13,9 +14,11 @@ import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { SQLiteBunSession } from './session.ts'; -export type BunSQLiteDatabase< +export class BunSQLiteDatabase< TSchema extends Record = Record, -> = BaseSQLiteDatabase<'sync', void, TSchema>; +> extends BaseSQLiteDatabase<'sync', void, TSchema> { + static readonly [entityKind]: string = 'BunSQLiteDatabase'; +} export function drizzle = Record>( client: Database, @@ -43,5 +46,5 @@ export function drizzle = Record; + return new BunSQLiteDatabase('sync', dialect, session, schema) as BunSQLiteDatabase; } diff --git a/drizzle-orm/src/expo-sqlite/driver.ts b/drizzle-orm/src/expo-sqlite/driver.ts index ae8ce6577..51cb1a204 100644 --- a/drizzle-orm/src/expo-sqlite/driver.ts +++ b/drizzle-orm/src/expo-sqlite/driver.ts @@ -1,4 +1,5 @@ import type { SQLiteDatabase, SQLiteRunResult } from 'expo-sqlite/next'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { createTableRelationsHelpers, @@ -11,9 +12,11 @@ import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { ExpoSQLiteSession } from './session.ts'; -export type ExpoSQLiteDatabase< - TSchema extends Record = Record, -> = BaseSQLiteDatabase<'sync', SQLiteRunResult, TSchema>; +export class ExpoSQLiteDatabase> + extends BaseSQLiteDatabase<'sync', SQLiteRunResult, TSchema> +{ + static readonly [entityKind]: string = 'ExpoSQLiteDatabase'; +} export function drizzle = Record>( client: SQLiteDatabase, @@ -41,5 +44,5 @@ export function drizzle = Record; + return new ExpoSQLiteDatabase('sync', dialect, session, schema) as ExpoSQLiteDatabase; } diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index db7ac1ddd..41bb202e8 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,5 +1,5 @@ /* eslint-disable import/extensions */ -import type { RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; +import type { RDSDataClientConfig, RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; import type { Config as LibsqlConfig } from '@libsql/client'; import type { HTTPTransactionOptions as NeonHttpConfig, @@ -71,6 +71,21 @@ type MonodriverNeonHttpConfig = { options?: NeonHttpConfig; }; +type DatabaseVendor = + | 'node-postgres' + | 'postgres-js' + | 'neon-serverless' + | 'neon-http' + | 'vercel-postgres' + | 'aws-data-api-pg' + | 'planetscale' + | 'mysql2' + | 'tidb-serverless' + | 'libsql' + | 'd1' + | 'bun:sqlite' + | 'better-sqlite3'; + type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; 'postgres-js': PostgresJsDatabase; @@ -91,63 +106,51 @@ type InitializerParams< TSchema extends Record = Record, > = | ({ - client: 'node-postgres'; connection: NodePGPoolConfig; } & DrizzleConfig) | ({ - client: 'postgres-js'; connection: PostgresJSOptions>; } & DrizzleConfig) | ({ - client: 'neon-serverless'; connection: NeonServerlessConfig; } & DrizzleConfig) | ({ - client: 'neon-http'; connection: MonodriverNeonHttpConfig; } & DrizzleConfig) | ({ - client: 'vercel-postgres'; connection: VercelPool; } & DrizzleConfig) | ({ - client: 'aws-data-api-pg'; connection: RDSConfig; } & DrizzleAwsDataApiPgConfig) | ({ - client: 'planetscale'; connection: PlanetscaleConfig; } & DrizzleConfig) | ({ - client: 'mysql2'; connection: Mysql2Config; } & MySql2DrizzleConfig) | ({ - client: 'tidb-serverless'; connection: TiDBServerlessConfig; } & DrizzleConfig) | ({ - client: 'libsql'; connection: LibsqlConfig; } & DrizzleConfig) | ({ - client: 'd1'; connection: D1Database; } & DrizzleConfig) | ({ - client: 'bun:sqlite'; - connection: BunSqliteDatabaseConfig; + connection?: BunSqliteDatabaseConfig; } & DrizzleConfig) | ({ - client: 'better-sqlite3'; - connection: BetterSQLite3DatabaseConfig; + connection?: BetterSQLite3DatabaseConfig; } & DrizzleConfig); type DetermineClient< - TParams extends InitializerParams, + TVendor extends DatabaseVendor, + TSchema extends Record, > = ClientDrizzleInstanceMap< - TParams['schema'] extends Record ? TParams['schema'] : Record ->[TParams['client']]; + TSchema +>[TVendor]; const importError = (libName: string) => { throw new Error( @@ -155,11 +158,75 @@ const importError = (libName: string) => { ); }; -export const drizzle = async < +const removeKey = , TKey extends keyof TRecord>( + obj: TRecord, + key: TKey, +): Omit => { + if (!(key in obj)) return obj; + + delete ( obj).key; + return obj; +}; + +export async function drizzle = Record>( + client: 'node-postgres', + params: { connection: NodePGPoolConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'postgres-js', + params: { connection: string | PostgresJSOptions> } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'neon-serverless', + params: { connection: NeonServerlessConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'neon-http', + params: { connection: MonodriverNeonHttpConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'vercel-postgres', + params: { connection: VercelPool } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'aws-data-api-pg', + params?: { connection?: RDSConfig } & DrizzleAwsDataApiPgConfig, +): Promise>; +export async function drizzle = Record>( + client: 'planetscale', + params: { connection: PlanetscaleConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'mysql2', + params: { connection: Mysql2Config | string } & MySql2DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'tidb-serverless', + params: { connection: TiDBServerlessConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'libsql', + params: { connection: LibsqlConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'd1', + params: { connection: D1Database } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'bun:sqlite', + params?: { connection?: BunSqliteDatabaseConfig } & DrizzleConfig, +): Promise>; +export async function drizzle = Record>( + client: 'better-sqlite3', + params?: { connection?: BetterSQLite3DatabaseConfig } & DrizzleConfig, +): Promise>; +export async function drizzle< + TVendor extends DatabaseVendor, TSchema extends Record, TParams extends InitializerParams, ->(params: TParams): Promise> => { - const { client, connection, ...drizzleConfig } = params; +>(client: TVendor, params?: TParams): Promise> { + const connection = params?.connection; + const drizzleConfig = params ? removeKey(params, 'connection') : undefined; switch (client) { case 'node-postgres': { @@ -174,7 +241,7 @@ export const drizzle = async < importError('@aws-sdk/client-rds-data') ); const { drizzle } = await import('./aws-data-api/pg'); - const instance = new RDSDataClient(connection); + const instance = new RDSDataClient(connection as RDSDataClientConfig); return drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; } @@ -272,5 +339,10 @@ export const drizzle = async < return drizzle(sql, drizzleConfig) as any; } + default: { + throw new Error( + `Unsupported vendor for Drizzle ORM monodriver: '${client}'. Use dedicated drizzle initializer instead.`, + ); + } } -}; +} diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index b82a1ea0b..eec37bbdf 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -3,6 +3,7 @@ import type { AwsDataApiPgDatabase } from './aws-data-api/pg/index.ts'; import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; import type { DrizzleD1Database } from './d1/index.ts'; +import { entityKind } from './entity.ts'; import type { ExpoSQLiteDatabase } from './expo-sqlite/index.ts'; import type { LibSQLDatabase } from './libsql/index.ts'; import type { MigrationConfig } from './migrator.ts'; @@ -36,117 +37,78 @@ type ExpoSQLiteMigrationConfig = { migrations: Record; }; -type DatabaseType = - | 'aws-data-api-pg' - | 'better-sqlite3' - | 'bun:sqlite' - | 'd1' - | 'expo-sqlite' - | 'libsql' - | 'mysql-proxy' - | 'mysql2' - | 'neon-http' - | 'neon-serverless' - | 'node-postgres' - | 'op-sqlite' - | 'pg-proxy' - | 'pglite' - | 'planetscale' - | 'postgres-js' - | 'sqlite-proxy' - | 'tidb-serverless' - | 'vercel-postgres' - | 'xata-http'; - export async function migrate( - type: 'aws-data-api-pg', db: AwsDataApiPgDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'better-sqlite3', db: BetterSQLite3Database, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'bun:sqlite', db: BunSQLiteDatabase, config: string | MigrationConfig, ): Promise; -export async function migrate(type: 'd1', db: DrizzleD1Database, config: string | MigrationConfig): Promise; +export async function migrate(db: DrizzleD1Database, config: string | MigrationConfig): Promise; export async function migrate( - type: 'expo-sqlite', db: ExpoSQLiteDatabase, config: ExpoSQLiteMigrationConfig, ): Promise; -export async function migrate(type: 'libsql', db: LibSQLDatabase, config: MigrationConfig): Promise; +export async function migrate(db: LibSQLDatabase, config: MigrationConfig): Promise; export async function migrate( - type: 'mysql-proxy', db: MySqlRemoteDatabase, callback: MySqlProxyMigrator, config: MigrationConfig, ): Promise; -export async function migrate(type: 'mysql2', db: MySql2Database, config: MigrationConfig): Promise; +export async function migrate(db: MySql2Database, config: MigrationConfig): Promise; export async function migrate( - type: 'neon-http', db: NeonHttpDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'neon-serverless', db: NeonDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'node-postgres', db: NodePgDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'op-sqlite', db: OPSQLiteDatabase, config: OPSQLiteMigrationConfig, ): Promise; export async function migrate( - type: 'pg-proxy', db: PgRemoteDatabase, callback: PgProxyMigrator, config: string | MigrationConfig, ): Promise; -export async function migrate(type: 'pglite', db: PgliteDatabase, config: string | MigrationConfig): Promise; +export async function migrate(db: PgliteDatabase, config: string | MigrationConfig): Promise; export async function migrate( - type: 'planetscale', db: PlanetScaleDatabase, config: MigrationConfig, ): Promise; export async function migrate( - type: 'postgres-js', db: PlanetScaleDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'sqlite-proxy', db: PgRemoteDatabase, callback: SQLiteProxyMigrator, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'tidb-serverless', db: PlanetScaleDatabase, config: MigrationConfig, ): Promise; export async function migrate( - type: 'vercel-postgres', db: VercelPgDatabase, config: string | MigrationConfig, ): Promise; export async function migrate( - type: 'xata-http', db: XataHttpDatabase, config: string | XataHttpMigrationConfig, ): Promise; export async function migrate( - type: DatabaseType, db: any, config: | string @@ -159,108 +121,106 @@ export async function migrate( | SQLiteProxyMigrator, extraConfig?: string | MigrationConfig | undefined, ) { - const rest = [db, config, extraConfig]; - - switch (type) { - case 'aws-data-api-pg': { + switch (db[entityKind]) { + case 'AwsDataApiPgDatabase': { const { migrate } = await import('./aws-data-api/pg/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'better-sqlite3': { + case 'BetterSQLite3Database': { const { migrate } = await import('./better-sqlite3/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'bun:sqlite': { + case 'BunSQLiteDatabase': { const { migrate } = await import('./bun-sqlite/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'd1': { + case 'D1Database': { const { migrate } = await import('./d1/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'expo-sqlite': { + case 'ExpoSQLiteDatabase': { const { migrate } = await import('./expo-sqlite/migrator'); - return migrate(rest[0], rest[1] as ExpoSQLiteMigrationConfig); + return migrate(db, config as ExpoSQLiteMigrationConfig); } - case 'libsql': { + case 'LibSQLDatabase': { const { migrate } = await import('./libsql/migrator'); - return migrate(rest[0], rest[1] as MigrationConfig); + return migrate(db, config as MigrationConfig); } - case 'mysql-proxy': { + case 'MySqlRemoteDatabase': { const { migrate } = await import('./mysql-proxy/migrator'); - return migrate(rest[0], rest[1] as MySqlProxyMigrator, rest[2] as MigrationConfig); + return migrate(db, config as MySqlProxyMigrator, extraConfig as MigrationConfig); } - case 'mysql2': { + case 'MySql2Driver': { const { migrate } = await import('./mysql2/migrator'); - return migrate(rest[0], rest[1] as MigrationConfig); + return migrate(db, config as MigrationConfig); } - case 'neon-http': { + case 'NeonHttpDatabase': { const { migrate } = await import('./neon-http/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'neon-serverless': { + case 'NeonServerlessDatabase': { const { migrate } = await import('./neon-serverless/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'node-postgres': { + case 'NodePgDriver': { const { migrate } = await import('./node-postgres/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'op-sqlite': { + case 'OPSQLiteDatabase': { const { migrate } = await import('./op-sqlite/migrator'); - return migrate(rest[0], rest[1] as OPSQLiteMigrationConfig); + return migrate(db, config as OPSQLiteMigrationConfig); } - case 'pg-proxy': { + case 'PgRemoteDatabase': { const { migrate } = await import('./pg-proxy/migrator'); - return migrate(rest[0], rest[1] as PgProxyMigrator, rest[2] as string | MigrationConfig); + return migrate(db, config as PgProxyMigrator, extraConfig as string | MigrationConfig); } - case 'pglite': { + case 'PgliteDatabase': { const { migrate } = await import('./pglite/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'planetscale': { + case 'PlanetScaleDatabase': { const { migrate } = await import('./planetscale-serverless/migrator'); - return migrate(rest[0], rest[1] as MigrationConfig); + return migrate(db, config as MigrationConfig); } - case 'postgres-js': { + case 'PostgresJsDatabase': { const { migrate } = await import('./postgres-js/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'sqlite-proxy': { + case 'SqliteRemoteDatabase': { const { migrate } = await import('./sqlite-proxy/migrator'); - return migrate(rest[0], rest[1] as SQLiteProxyMigrator, rest[2] as string | MigrationConfig); + return migrate(db, config as SQLiteProxyMigrator, extraConfig as string | MigrationConfig); } - case 'tidb-serverless': { + case 'TiDBServerlessDatabase': { const { migrate } = await import('./tidb-serverless/migrator'); - return migrate(rest[0], rest[1] as MigrationConfig); + return migrate(db, config as MigrationConfig); } - case 'vercel-postgres': { + case 'VercelPgDatabase': { const { migrate } = await import('./vercel-postgres/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } - case 'xata-http': { + case 'XataHttpDatabase': { const { migrate } = await import('./xata-http/migrator'); - return migrate(rest[0], rest[1] as string | MigrationConfig); + return migrate(db, config as string | MigrationConfig); } } } diff --git a/drizzle-orm/src/mysql-proxy/driver.ts b/drizzle-orm/src/mysql-proxy/driver.ts index 574db42c1..dfbf69cc9 100644 --- a/drizzle-orm/src/mysql-proxy/driver.ts +++ b/drizzle-orm/src/mysql-proxy/driver.ts @@ -1,3 +1,4 @@ +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { MySqlDatabase } from '~/mysql-core/db.ts'; import { MySqlDialect } from '~/mysql-core/dialect.ts'; @@ -10,9 +11,11 @@ import { import type { DrizzleConfig } from '~/utils.ts'; import { type MySqlRemotePreparedQueryHKT, type MySqlRemoteQueryResultHKT, MySqlRemoteSession } from './session.ts'; -export type MySqlRemoteDatabase< +export class MySqlRemoteDatabase< TSchema extends Record = Record, -> = MySqlDatabase; +> extends MySqlDatabase { + static readonly [entityKind]: string = 'MySqlRemoteDatabase'; +} export type RemoteCallback = ( sql: string, @@ -46,5 +49,5 @@ export function drizzle = Record; + return new MySqlRemoteDatabase(dialect, session, schema as any, 'default') as MySqlRemoteDatabase; } diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index 8a15dd678..7f42cfeb3 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -43,9 +43,11 @@ export class NeonDriver { } } -export type NeonDatabase< +export class NeonDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'NeonServerlessDatabase'; +} export function drizzle = Record>( client: NeonClient, @@ -74,5 +76,5 @@ export function drizzle = Record; + return new NeonDatabase(dialect, session, schema as any) as NeonDatabase; } diff --git a/drizzle-orm/src/op-sqlite/driver.ts b/drizzle-orm/src/op-sqlite/driver.ts index 24c663abf..94ee6e866 100644 --- a/drizzle-orm/src/op-sqlite/driver.ts +++ b/drizzle-orm/src/op-sqlite/driver.ts @@ -1,4 +1,5 @@ import type { OPSQLiteConnection, QueryResult } from '@op-engineering/op-sqlite'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { createTableRelationsHelpers, @@ -11,9 +12,11 @@ import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { OPSQLiteSession } from './session.ts'; -export type OPSQLiteDatabase< +export class OPSQLiteDatabase< TSchema extends Record = Record, -> = BaseSQLiteDatabase<'async', QueryResult, TSchema>; +> extends BaseSQLiteDatabase<'async', QueryResult, TSchema> { + static readonly [entityKind]: string = 'OPSQLiteDatabase'; +} export function drizzle = Record>( client: OPSQLiteConnection, @@ -41,5 +44,5 @@ export function drizzle = Record; + return new OPSQLiteDatabase('async', dialect, session, schema) as OPSQLiteDatabase; } diff --git a/drizzle-orm/src/pg-proxy/driver.ts b/drizzle-orm/src/pg-proxy/driver.ts index cdffa15c1..d82e86962 100644 --- a/drizzle-orm/src/pg-proxy/driver.ts +++ b/drizzle-orm/src/pg-proxy/driver.ts @@ -1,3 +1,4 @@ +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; @@ -10,9 +11,11 @@ import { import type { DrizzleConfig } from '~/utils.ts'; import { type PgRemoteQueryResultHKT, PgRemoteSession } from './session.ts'; -export type PgRemoteDatabase< +export class PgRemoteDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'PgRemoteDatabase'; +} export type RemoteCallback = ( sql: string, @@ -48,5 +51,5 @@ export function drizzle = Record; + return new PgRemoteDatabase(dialect, session, schema as any) as PgRemoteDatabase; } diff --git a/drizzle-orm/src/pglite/driver.ts b/drizzle-orm/src/pglite/driver.ts index 7de2ce110..a801005d8 100644 --- a/drizzle-orm/src/pglite/driver.ts +++ b/drizzle-orm/src/pglite/driver.ts @@ -34,9 +34,11 @@ export class PgliteDriver { } } -export type PgliteDatabase< +export class PgliteDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'PgliteDatabase'; +} export function drizzle = Record>( client: PgliteClient, @@ -65,5 +67,5 @@ export function drizzle = Record; + return new PgliteDatabase(dialect, session, schema as any) as PgliteDatabase; } diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index b1d2d6e6f..fd1327bbc 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -1,5 +1,6 @@ import type { Connection } from '@planetscale/database'; import { Client } from '@planetscale/database'; +import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; import { MySqlDatabase } from '~/mysql-core/db.ts'; @@ -18,9 +19,11 @@ export interface PlanetscaleSDriverOptions { logger?: Logger; } -export type PlanetScaleDatabase< +export class PlanetScaleDatabase< TSchema extends Record = Record, -> = MySqlDatabase; +> extends MySqlDatabase { + static readonly [entityKind]: string = 'PlanetScaleDatabase'; +} export function drizzle = Record>( client: Client | Connection, @@ -82,5 +85,5 @@ Starting from version 0.30.0, you will encounter an error if you attempt to use } const session = new PlanetscaleSession(client, dialect, undefined, schema, { logger }); - return new MySqlDatabase(dialect, session, schema, 'planetscale') as PlanetScaleDatabase; + return new PlanetScaleDatabase(dialect, session, schema as any, 'planetscale') as PlanetScaleDatabase; } diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index 7f44344e8..6714cff8d 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -1,4 +1,5 @@ import type { Sql } from 'postgres'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; @@ -12,9 +13,11 @@ import type { DrizzleConfig } from '~/utils.ts'; import type { PostgresJsQueryResultHKT } from './session.ts'; import { PostgresJsSession } from './session.ts'; -export type PostgresJsDatabase< +export class PostgresJsDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'PostgresJsDatabase'; +} export function drizzle = Record>( client: Sql, @@ -52,5 +55,5 @@ export function drizzle = Record; + return new PostgresJsDatabase(dialect, session, schema as any) as PostgresJsDatabase; } diff --git a/drizzle-orm/src/tidb-serverless/driver.ts b/drizzle-orm/src/tidb-serverless/driver.ts index bdd5324db..b762bd889 100644 --- a/drizzle-orm/src/tidb-serverless/driver.ts +++ b/drizzle-orm/src/tidb-serverless/driver.ts @@ -1,4 +1,5 @@ import type { Connection } from '@tidbcloud/serverless'; +import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; import { MySqlDatabase } from '~/mysql-core/db.ts'; @@ -17,9 +18,11 @@ export interface TiDBServerlessSDriverOptions { logger?: Logger; } -export type TiDBServerlessDatabase< +export class TiDBServerlessDatabase< TSchema extends Record = Record, -> = MySqlDatabase; +> extends MySqlDatabase { + static readonly [entityKind]: string = 'TiDBServerlessDatabase'; +} export function drizzle = Record>( client: Connection, @@ -47,5 +50,5 @@ export function drizzle = Record; + return new TiDBServerlessDatabase(dialect, session, schema as any, 'default') as TiDBServerlessDatabase; } diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 07e73c732..bc990d0b3 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -42,9 +42,11 @@ export class VercelPgDriver { } } -export type VercelPgDatabase< +export class VercelPgDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'VercelPgDatabase'; +} export function drizzle = Record>( client: VercelPgClient, @@ -73,5 +75,5 @@ export function drizzle = Record; + return new VercelPgDatabase(dialect, session, schema as any) as VercelPgDatabase; } From 3c165977690b66b586b865c100d4699593806929 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 3 Sep 2024 12:51:09 +0300 Subject: [PATCH 124/492] Fixed overload order for better autocomplete --- drizzle-orm/src/monodriver.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 41bb202e8..0eb2214ee 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -168,6 +168,14 @@ const removeKey = , TKey extends keyof TReco return obj; }; +export async function drizzle = Record>( + client: 'aws-data-api-pg', + params: { connection?: RDSConfig } & DrizzleAwsDataApiPgConfig, +): Promise>; +export async function drizzle = Record>( + client: 'mysql2', + params: { connection: Mysql2Config | string } & MySql2DrizzleConfig, +): Promise>; export async function drizzle = Record>( client: 'node-postgres', params: { connection: NodePGPoolConfig } & DrizzleConfig, @@ -188,18 +196,10 @@ export async function drizzle = Record, ): Promise>; -export async function drizzle = Record>( - client: 'aws-data-api-pg', - params?: { connection?: RDSConfig } & DrizzleAwsDataApiPgConfig, -): Promise>; export async function drizzle = Record>( client: 'planetscale', params: { connection: PlanetscaleConfig } & DrizzleConfig, ): Promise>; -export async function drizzle = Record>( - client: 'mysql2', - params: { connection: Mysql2Config | string } & MySql2DrizzleConfig, -): Promise>; export async function drizzle = Record>( client: 'tidb-serverless', params: { connection: TiDBServerlessConfig } & DrizzleConfig, @@ -346,3 +346,9 @@ export async function drizzle< } } } + +const db = await drizzle('aws-data-api-pg', { + database: '', + resourceArn: '', + secretArn: '', +}); From 88479501251d7defa415807eb1058a21148efeeb Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 3 Sep 2024 12:51:30 +0300 Subject: [PATCH 125/492] Removed garbage --- drizzle-orm/src/monodriver.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 0eb2214ee..05c676157 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -346,9 +346,3 @@ export async function drizzle< } } } - -const db = await drizzle('aws-data-api-pg', { - database: '', - resourceArn: '', - secretArn: '', -}); From ff1dcd90266f2f964f41ffeca32575f2b28a5db2 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Tue, 3 Sep 2024 13:23:48 +0300 Subject: [PATCH 126/492] updated pull config update migrate function in drizzle-orm --- drizzle-kit/src/cli/commands/utils.ts | 2 +- drizzle-kit/src/cli/connections.ts | 46 +++++++++++++++ drizzle-kit/src/cli/utils.ts | 2 +- drizzle-kit/tests/libsql-statements.test.ts | 1 - drizzle-kit/tests/migrate/libsq-schema.ts | 6 ++ .../tests/migrate/libsql-migrate.test.ts | 58 +++++++++++++++++++ .../migrations/0000_little_blizzard.sql | 4 ++ .../migrations/0001_nebulous_storm.sql | 10 ++++ .../migrations/meta/0000_snapshot.json | 40 +++++++++++++ .../migrations/meta/0001_snapshot.json | 40 +++++++++++++ .../migrate/migrations/meta/_journal.json | 20 +++++++ drizzle-orm/src/libsql/migrator.ts | 2 +- drizzle-orm/src/libsql/session.ts | 15 +++++ drizzle-orm/src/version.ts | 2 +- 14 files changed, 243 insertions(+), 5 deletions(-) create mode 100644 drizzle-kit/tests/migrate/libsq-schema.ts create mode 100644 drizzle-kit/tests/migrate/libsql-migrate.test.ts create mode 100644 drizzle-kit/tests/migrate/migrations/0000_little_blizzard.sql create mode 100644 drizzle-kit/tests/migrate/migrations/0001_nebulous_storm.sql create mode 100644 drizzle-kit/tests/migrate/migrations/meta/0000_snapshot.json create mode 100644 drizzle-kit/tests/migrate/migrations/meta/0001_snapshot.json create mode 100644 drizzle-kit/tests/migrate/migrations/meta/_journal.json diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index d19c04b3e..114088920 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -488,7 +488,7 @@ export const preparePullConfig = async ( process.exit(1); } return { - dialect: 'sqlite', + dialect, out: config.out, breakpoints: config.breakpoints, casing: config.casing, diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 2e329d40c..878b85cdc 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -585,6 +585,51 @@ export const connectToSQLite = async ( } } + if (await checkPackage('@libsql/client')) { + const { createClient } = await import('@libsql/client'); + const { drizzle } = await import('drizzle-orm/libsql'); + const { migrate } = await import('drizzle-orm/libsql/migrator'); + + const client = createClient({ + url: credentials.url, + }); + const drzl = drizzle(client); + const migrateFn = async (config: MigrationConfig) => { + return migrate(drzl, config); + }; + + const db: LibSQLDB = { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); + }, + batchWithPragma: async (queries: string[]) => { + await client.migrate(queries); + }, + }; + + const proxy: SqliteProxy = { + proxy: async (params: ProxyParams) => { + const preparedParams = prepareSqliteParams(params.params); + const result = await client.execute({ + sql: params.sql, + args: preparedParams, + }); + + if (params.mode === 'array') { + return result.rows.map((row) => Object.values(row)); + } else { + return result.rows; + } + }, + }; + + return { ...db, ...proxy, migrate: migrateFn }; + } + if (await checkPackage('better-sqlite3')) { const { default: Database } = await import('better-sqlite3'); const { drizzle } = await import('drizzle-orm/better-sqlite3'); @@ -626,6 +671,7 @@ export const connectToSQLite = async ( }; return { ...db, ...proxy, migrate: migrateFn }; } + console.log( "Please install 'better-sqlite3' for Drizzle Kit to connect to SQLite databases", ); diff --git a/drizzle-kit/src/cli/utils.ts b/drizzle-kit/src/cli/utils.ts index f7e7a2ae9..0a5d7862e 100644 --- a/drizzle-kit/src/cli/utils.ts +++ b/drizzle-kit/src/cli/utils.ts @@ -74,7 +74,7 @@ export const assertEitherPackage = async ( process.exit(1); }; -const requiredApiVersion = 7; +const requiredApiVersion = 8; export const assertOrmCoreVersion = async () => { try { const { compatibilityVersion } = await import('drizzle-orm/version'); diff --git a/drizzle-kit/tests/libsql-statements.test.ts b/drizzle-kit/tests/libsql-statements.test.ts index e18e41950..8221e52e0 100644 --- a/drizzle-kit/tests/libsql-statements.test.ts +++ b/drizzle-kit/tests/libsql-statements.test.ts @@ -1,4 +1,3 @@ -import { sql } from 'drizzle-orm'; import { foreignKey, index, int, integer, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'; import { JsonRecreateTableStatement } from 'src/jsonStatements'; import { expect, test } from 'vitest'; diff --git a/drizzle-kit/tests/migrate/libsq-schema.ts b/drizzle-kit/tests/migrate/libsq-schema.ts new file mode 100644 index 000000000..5cb344d51 --- /dev/null +++ b/drizzle-kit/tests/migrate/libsq-schema.ts @@ -0,0 +1,6 @@ +import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const users = sqliteTable('users', { + id: integer('id').primaryKey().notNull(), + name: text('name').notNull(), +}); diff --git a/drizzle-kit/tests/migrate/libsql-migrate.test.ts b/drizzle-kit/tests/migrate/libsql-migrate.test.ts new file mode 100644 index 000000000..b937b644f --- /dev/null +++ b/drizzle-kit/tests/migrate/libsql-migrate.test.ts @@ -0,0 +1,58 @@ +import { createClient } from '@libsql/client'; +import { connectToLibSQL } from 'src/cli/connections'; +import { expect, test } from 'vitest'; + +test('validate migrate function', async () => { + const credentials = { + url: ':memory:', + }; + const { migrate, query } = await connectToLibSQL(credentials); + + await migrate({ migrationsFolder: 'tests/migrate/migrations' }); + + const res = await query(`PRAGMA table_info("users");`); + + expect(res).toStrictEqual([{ + cid: 0, + name: 'id', + type: 'INTEGER', + notnull: 0, + dflt_value: null, + pk: 0, + }, { + cid: 1, + name: 'name', + type: 'INTEGER', + notnull: 1, + dflt_value: null, + pk: 0, + }]); +}); + +// test('validate migrate function', async () => { +// const credentials = { +// url: '', +// authToken: '', +// }; +// const { migrate, query } = await connectToLibSQL(credentials); + +// await migrate({ migrationsFolder: 'tests/migrate/migrations' }); + +// const res = await query(`PRAGMA table_info("users");`); + +// expect(res).toStrictEqual([{ +// cid: 0, +// name: 'id', +// type: 'INTEGER', +// notnull: 0, +// dflt_value: null, +// pk: 0, +// }, { +// cid: 1, +// name: 'name', +// type: 'INTEGER', +// notnull: 1, +// dflt_value: null, +// pk: 0, +// }]); +// }); diff --git a/drizzle-kit/tests/migrate/migrations/0000_little_blizzard.sql b/drizzle-kit/tests/migrate/migrations/0000_little_blizzard.sql new file mode 100644 index 000000000..9de0a139d --- /dev/null +++ b/drizzle-kit/tests/migrate/migrations/0000_little_blizzard.sql @@ -0,0 +1,4 @@ +CREATE TABLE `users` ( + `id` integer PRIMARY KEY NOT NULL, + `name` text NOT NULL +); diff --git a/drizzle-kit/tests/migrate/migrations/0001_nebulous_storm.sql b/drizzle-kit/tests/migrate/migrations/0001_nebulous_storm.sql new file mode 100644 index 000000000..4309a05c2 --- /dev/null +++ b/drizzle-kit/tests/migrate/migrations/0001_nebulous_storm.sql @@ -0,0 +1,10 @@ +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_users` ( + `id` integer, + `name` integer NOT NULL +); +--> statement-breakpoint +INSERT INTO `__new_users`("id", "name") SELECT "id", "name" FROM `users`;--> statement-breakpoint +DROP TABLE `users`;--> statement-breakpoint +ALTER TABLE `__new_users` RENAME TO `users`;--> statement-breakpoint +PRAGMA foreign_keys=ON; \ No newline at end of file diff --git a/drizzle-kit/tests/migrate/migrations/meta/0000_snapshot.json b/drizzle-kit/tests/migrate/migrations/meta/0000_snapshot.json new file mode 100644 index 000000000..599d02b91 --- /dev/null +++ b/drizzle-kit/tests/migrate/migrations/meta/0000_snapshot.json @@ -0,0 +1,40 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "2bd46776-9e41-4a6c-b617-5c600bb176f2", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle-kit/tests/migrate/migrations/meta/0001_snapshot.json b/drizzle-kit/tests/migrate/migrations/meta/0001_snapshot.json new file mode 100644 index 000000000..e3b26ba14 --- /dev/null +++ b/drizzle-kit/tests/migrate/migrations/meta/0001_snapshot.json @@ -0,0 +1,40 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "6c0ec455-42fd-47fd-a22c-4bb4551e1358", + "prevId": "2bd46776-9e41-4a6c-b617-5c600bb176f2", + "tables": { + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle-kit/tests/migrate/migrations/meta/_journal.json b/drizzle-kit/tests/migrate/migrations/meta/_journal.json new file mode 100644 index 000000000..c836eb194 --- /dev/null +++ b/drizzle-kit/tests/migrate/migrations/meta/_journal.json @@ -0,0 +1,20 @@ +{ + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1725358702427, + "tag": "0000_little_blizzard", + "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1725358713033, + "tag": "0001_nebulous_storm", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/drizzle-orm/src/libsql/migrator.ts b/drizzle-orm/src/libsql/migrator.ts index 58bcc9e05..aa262bc2d 100644 --- a/drizzle-orm/src/libsql/migrator.ts +++ b/drizzle-orm/src/libsql/migrator.ts @@ -47,5 +47,5 @@ export async function migrate>( } } - await db.session.batch(statementToBatch); + await db.session.migrate(statementToBatch); } diff --git a/drizzle-orm/src/libsql/session.ts b/drizzle-orm/src/libsql/session.ts index 29e4e268f..640977734 100644 --- a/drizzle-orm/src/libsql/session.ts +++ b/drizzle-orm/src/libsql/session.ts @@ -76,6 +76,21 @@ export class LibSQLSession< return batchResults.map((result, i) => preparedQueries[i]!.mapResult(result, true)); } + async migrate[] | readonly BatchItem<'sqlite'>[]>(queries: T) { + const preparedQueries: PreparedQuery[] = []; + const builtQueries: InStatement[] = []; + + for (const query of queries) { + const preparedQuery = query._prepare(); + const builtQuery = preparedQuery.getQuery(); + preparedQueries.push(preparedQuery); + builtQueries.push({ sql: builtQuery.sql, args: builtQuery.params as InArgs }); + } + + const batchResults = await this.client.migrate(builtQueries); + return batchResults.map((result, i) => preparedQueries[i]!.mapResult(result, true)); + } + override async transaction( transaction: (db: LibSQLTransaction) => T | Promise, _config?: SQLiteTransactionConfig, diff --git a/drizzle-orm/src/version.ts b/drizzle-orm/src/version.ts index 0c11937c8..d670a0575 100644 --- a/drizzle-orm/src/version.ts +++ b/drizzle-orm/src/version.ts @@ -1,4 +1,4 @@ // @ts-ignore - imported using Rollup json plugin export { version as npmVersion } from '../package.json'; // In version 7, we changed the PostgreSQL indexes API -export const compatibilityVersion = 7; +export const compatibilityVersion = 8; From c5d1196edf57933b73fe2f3a97a11edd442c1413 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Tue, 3 Sep 2024 14:58:14 +0300 Subject: [PATCH 127/492] removed driver --- drizzle-kit/src/cli/commands/migrate.ts | 3 +-- drizzle-kit/src/cli/commands/utils.ts | 1 - drizzle-kit/src/cli/validations/cli.ts | 3 +-- drizzle-kit/src/sqlgenerator.ts | 2 -- 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index d93ddb154..2bcd72cab 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -11,7 +11,6 @@ import { import chalk from 'chalk'; import { render } from 'hanji'; import path, { join } from 'path'; -import { JsonStatement } from 'src/jsonStatements'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme } from '../../serializer/mysqlSchema'; @@ -34,7 +33,7 @@ import { } from '../../snapshotsDiffer'; import { assertV1OutFolder, Journal, prepareMigrationFolder } from '../../utils'; import { prepareMigrationMetadata } from '../../utils/words'; -import { Driver, Prefix } from '../validations/common'; +import { Prefix } from '../validations/common'; import { withStyle } from '../validations/outputs'; import { isRenamePromptItem, diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 114088920..320b17652 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -232,7 +232,6 @@ export const preparePushConfig = async ( : options, ); - raw.driver ||= options.driver; raw.verbose ||= options.verbose; // if provided in cli to debug raw.strict ||= options.strict; // if provided in cli only diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index 9d580fbe4..c4bbbe530 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -1,6 +1,6 @@ import { boolean, intersection, literal, object, string, TypeOf, union } from 'zod'; import { dialect } from '../../schemaValidator'; -import { casing, driver, prefix } from './common'; +import { casing, prefix } from './common'; export const cliConfigGenerate = object({ dialect: dialect.optional(), @@ -25,7 +25,6 @@ export const pushParams = object({ extensionsFilters: literal('postgis').array().optional(), verbose: boolean().optional(), strict: boolean().optional(), - driver: driver.optional(), }).passthrough(); export type PushParams = TypeOf; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 02c3fb427..374b30581 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -131,7 +131,6 @@ abstract class Convertor { abstract can( statement: JsonStatement, dialect: Dialect, - driver?: Driver, ): boolean; abstract convert( statement: JsonStatement, @@ -2587,7 +2586,6 @@ convertors.push(new MySqlAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new MySqlAlterTableAddPk()); convertors.push(new MySqlAlterTableAlterCompositePrimaryKeyConvertor()); -// overloads for turso driver export function fromJson( statements: JsonStatement[], dialect: Exclude, From 24f8ade6b2ece840a440d760a271e065c91b49df Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 3 Sep 2024 15:37:53 +0300 Subject: [PATCH 128/492] Added missing postgres.js to monomigrator --- drizzle-orm/src/monomigrator.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index eec37bbdf..1fc9dbc71 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -18,6 +18,7 @@ import type { PgRemoteDatabase } from './pg-proxy/index.ts'; import type { ProxyMigrator as PgProxyMigrator } from './pg-proxy/migrator.ts'; import type { PgliteDatabase } from './pglite/index.ts'; import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; +import type { PostgresJsDatabase } from './postgres-js/driver.ts'; import type { ProxyMigrator as SQLiteProxyMigrator } from './sqlite-proxy/migrator.ts'; import type { VercelPgDatabase } from './vercel-postgres/index.ts'; import type { XataHttpDatabase } from './xata-http/index.ts'; @@ -83,6 +84,7 @@ export async function migrate( config: string | MigrationConfig, ): Promise; export async function migrate(db: PgliteDatabase, config: string | MigrationConfig): Promise; +export async function migrate(db: PostgresJsDatabase, config: string | MigrationConfig): Promise; export async function migrate( db: PlanetScaleDatabase, config: MigrationConfig, From 3e27645accdb61fe8861129e1c4f200ea0f31c0e Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Tue, 3 Sep 2024 15:54:02 +0300 Subject: [PATCH 129/492] Fixed missing defaults in templates --- drizzle-orm/src/better-sqlite3/driver.ts | 2 +- drizzle-orm/src/expo-sqlite/driver.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 8d19cd8ab..8fe7c00fb 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -12,7 +12,7 @@ import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { BetterSQLiteSession } from './session.ts'; -export class BetterSQLite3Database> +export class BetterSQLite3Database = Record> extends BaseSQLiteDatabase<'sync', RunResult, TSchema> { static readonly [entityKind]: string = 'BetterSQLite3Database'; diff --git a/drizzle-orm/src/expo-sqlite/driver.ts b/drizzle-orm/src/expo-sqlite/driver.ts index 51cb1a204..fb858e482 100644 --- a/drizzle-orm/src/expo-sqlite/driver.ts +++ b/drizzle-orm/src/expo-sqlite/driver.ts @@ -12,7 +12,7 @@ import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { DrizzleConfig } from '~/utils.ts'; import { ExpoSQLiteSession } from './session.ts'; -export class ExpoSQLiteDatabase> +export class ExpoSQLiteDatabase = Record> extends BaseSQLiteDatabase<'sync', SQLiteRunResult, TSchema> { static readonly [entityKind]: string = 'ExpoSQLiteDatabase'; From 1321cf994078d5ebc8b1f1373504db98d8465712 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 4 Sep 2024 11:48:57 +0300 Subject: [PATCH 130/492] updated sqlite connection to libsql --- drizzle-kit/src/cli/connections.ts | 7 ++----- drizzle-kit/src/utils.ts | 3 --- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 878b85cdc..7d4435b55 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -591,14 +591,14 @@ export const connectToSQLite = async ( const { migrate } = await import('drizzle-orm/libsql/migrator'); const client = createClient({ - url: credentials.url, + url: normaliseSQLiteUrl(credentials.url, 'libsql'), }); const drzl = drizzle(client); const migrateFn = async (config: MigrationConfig) => { return migrate(drzl, config); }; - const db: LibSQLDB = { + const db: SQLiteDB = { query: async (sql: string, params?: any[]) => { const res = await client.execute({ sql, args: params || [] }); return res.rows as T[]; @@ -606,9 +606,6 @@ export const connectToSQLite = async ( run: async (query: string) => { await client.execute(query); }, - batchWithPragma: async (queries: string[]) => { - await client.migrate(queries); - }, }; const proxy: SqliteProxy = { diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 9a199e573..f26624969 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -25,9 +25,6 @@ export type DB = { export type SQLiteDB = { query: (sql: string, params?: any[]) => Promise; run(query: string): Promise; - batch?( - queries: { query: string; values?: any[] | undefined }[], - ): Promise; }; export type LibSQLDB = { From 3ff6cb092bc0279fa8e7a38ecbf347b854d45048 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 13:00:44 +0300 Subject: [PATCH 131/492] Improved types, matched supported instances of monodriver and monomigrator, fixed pg withReplicas type's schema inferrence, fixed lack of [entityKind] on some instances, fixed migrators not accepting string as a config --- drizzle-orm/src/libsql/migrator.ts | 2 +- drizzle-orm/src/monodriver.ts | 134 ++++-------- drizzle-orm/src/monomigrator.ts | 190 +++--------------- drizzle-orm/src/mysql2/driver.ts | 8 +- drizzle-orm/src/mysql2/migrator.ts | 11 +- drizzle-orm/src/node-postgres/driver.ts | 8 +- drizzle-orm/src/pg-core/db.ts | 6 +- .../src/planetscale-serverless/migrator.ts | 11 +- 8 files changed, 110 insertions(+), 260 deletions(-) diff --git a/drizzle-orm/src/libsql/migrator.ts b/drizzle-orm/src/libsql/migrator.ts index 58bcc9e05..4d7df1683 100644 --- a/drizzle-orm/src/libsql/migrator.ts +++ b/drizzle-orm/src/libsql/migrator.ts @@ -5,7 +5,7 @@ import type { LibSQLDatabase } from './driver.ts'; export async function migrate>( db: LibSQLDatabase, - config: MigrationConfig, + config: MigrationConfig | string, ) { const migrations = readMigrationFiles(config); const migrationsTable = config === undefined diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 05c676157..d2b86848b 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -71,7 +71,7 @@ type MonodriverNeonHttpConfig = { options?: NeonHttpConfig; }; -type DatabaseVendor = +type DatabaseClient = | 'node-postgres' | 'postgres-js' | 'neon-serverless' @@ -102,51 +102,50 @@ type ClientDrizzleInstanceMap> = { 'better-sqlite3': BetterSQLite3Database; }; -type InitializerParams< - TSchema extends Record = Record, -> = - | ({ +type InitializerParams = { + 'node-postgres': { connection: NodePGPoolConfig; - } & DrizzleConfig) - | ({ - connection: PostgresJSOptions>; - } & DrizzleConfig) - | ({ + }; + 'postgres-js': { + connection: string | PostgresJSOptions>; + }; + 'neon-serverless': { connection: NeonServerlessConfig; - } & DrizzleConfig) - | ({ + }; + 'neon-http': { connection: MonodriverNeonHttpConfig; - } & DrizzleConfig) - | ({ + }; + 'vercel-postgres': { connection: VercelPool; - } & DrizzleConfig) - | ({ - connection: RDSConfig; - } & DrizzleAwsDataApiPgConfig) - | ({ + }; + 'aws-data-api-pg': { + connection?: RDSConfig; + }; + planetscale: { connection: PlanetscaleConfig; - } & DrizzleConfig) - | ({ - connection: Mysql2Config; - } & MySql2DrizzleConfig) - | ({ + }; + mysql2: { + connection: Mysql2Config | string; + }; + 'tidb-serverless': { connection: TiDBServerlessConfig; - } & DrizzleConfig) - | ({ + }; + libsql: { connection: LibsqlConfig; - } & DrizzleConfig) - | ({ + }; + d1: { connection: D1Database; - } & DrizzleConfig) - | ({ + }; + 'bun:sqlite': { connection?: BunSqliteDatabaseConfig; - } & DrizzleConfig) - | ({ + }; + 'better-sqlite3': { connection?: BetterSQLite3DatabaseConfig; - } & DrizzleConfig); + }; +}; type DetermineClient< - TVendor extends DatabaseVendor, + TVendor extends DatabaseClient, TSchema extends Record, > = ClientDrizzleInstanceMap< TSchema @@ -167,64 +166,17 @@ const removeKey = , TKey extends keyof TReco delete ( obj).key; return obj; }; - -export async function drizzle = Record>( - client: 'aws-data-api-pg', - params: { connection?: RDSConfig } & DrizzleAwsDataApiPgConfig, -): Promise>; -export async function drizzle = Record>( - client: 'mysql2', - params: { connection: Mysql2Config | string } & MySql2DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'node-postgres', - params: { connection: NodePGPoolConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'postgres-js', - params: { connection: string | PostgresJSOptions> } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'neon-serverless', - params: { connection: NeonServerlessConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'neon-http', - params: { connection: MonodriverNeonHttpConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'vercel-postgres', - params: { connection: VercelPool } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'planetscale', - params: { connection: PlanetscaleConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'tidb-serverless', - params: { connection: TiDBServerlessConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'libsql', - params: { connection: LibsqlConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'd1', - params: { connection: D1Database } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'bun:sqlite', - params?: { connection?: BunSqliteDatabaseConfig } & DrizzleConfig, -): Promise>; -export async function drizzle = Record>( - client: 'better-sqlite3', - params?: { connection?: BetterSQLite3DatabaseConfig } & DrizzleConfig, -): Promise>; export async function drizzle< - TVendor extends DatabaseVendor, - TSchema extends Record, - TParams extends InitializerParams, ->(client: TVendor, params?: TParams): Promise> { + TClient extends DatabaseClient, + TSchema extends Record = Record, +>( + client: TClient, + params: + & InitializerParams[TClient] + & (TClient extends 'mysql2' ? MySql2DrizzleConfig + : TClient extends 'aws-data-api-pg' ? DrizzleAwsDataApiPgConfig + : DrizzleConfig), +): Promise> { const connection = params?.connection; const drizzleConfig = params ? removeKey(params, 'connection') : undefined; diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index 1fc9dbc71..aa590c8d7 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -4,225 +4,101 @@ import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; import type { DrizzleD1Database } from './d1/index.ts'; import { entityKind } from './entity.ts'; -import type { ExpoSQLiteDatabase } from './expo-sqlite/index.ts'; import type { LibSQLDatabase } from './libsql/index.ts'; import type { MigrationConfig } from './migrator.ts'; -import type { MySqlRemoteDatabase } from './mysql-proxy/index.ts'; -import type { ProxyMigrator as MySqlProxyMigrator } from './mysql-proxy/migrator.ts'; import type { MySql2Database } from './mysql2/index.ts'; import type { NeonHttpDatabase } from './neon-http/index.ts'; import type { NeonDatabase } from './neon-serverless/index.ts'; import type { NodePgDatabase } from './node-postgres/index.ts'; -import type { OPSQLiteDatabase } from './op-sqlite/index.ts'; -import type { PgRemoteDatabase } from './pg-proxy/index.ts'; -import type { ProxyMigrator as PgProxyMigrator } from './pg-proxy/migrator.ts'; -import type { PgliteDatabase } from './pglite/index.ts'; import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; -import type { PostgresJsDatabase } from './postgres-js/driver.ts'; -import type { ProxyMigrator as SQLiteProxyMigrator } from './sqlite-proxy/migrator.ts'; +import type { PostgresJsDatabase } from './postgres-js/index.ts'; +import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; import type { VercelPgDatabase } from './vercel-postgres/index.ts'; -import type { XataHttpDatabase } from './xata-http/index.ts'; -import type { MigrationConfig as XataHttpMigrationConfig } from './xata-http/migrator.ts'; -type OPSQLiteMigrationConfig = { - journal: { - entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; - }; - migrations: Record; -}; - -type ExpoSQLiteMigrationConfig = { - journal: { - entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; - }; - migrations: Record; -}; - -export async function migrate( - db: AwsDataApiPgDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: BetterSQLite3Database, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: BunSQLiteDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate(db: DrizzleD1Database, config: string | MigrationConfig): Promise; -export async function migrate( - db: ExpoSQLiteDatabase, - config: ExpoSQLiteMigrationConfig, -): Promise; -export async function migrate(db: LibSQLDatabase, config: MigrationConfig): Promise; -export async function migrate( - db: MySqlRemoteDatabase, - callback: MySqlProxyMigrator, - config: MigrationConfig, -): Promise; -export async function migrate(db: MySql2Database, config: MigrationConfig): Promise; -export async function migrate( - db: NeonHttpDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: NeonDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: NodePgDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: OPSQLiteDatabase, - config: OPSQLiteMigrationConfig, -): Promise; -export async function migrate( - db: PgRemoteDatabase, - callback: PgProxyMigrator, - config: string | MigrationConfig, -): Promise; -export async function migrate(db: PgliteDatabase, config: string | MigrationConfig): Promise; -export async function migrate(db: PostgresJsDatabase, config: string | MigrationConfig): Promise; -export async function migrate( - db: PlanetScaleDatabase, - config: MigrationConfig, -): Promise; -export async function migrate( - db: PlanetScaleDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: PgRemoteDatabase, - callback: SQLiteProxyMigrator, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: PlanetScaleDatabase, - config: MigrationConfig, -): Promise; export async function migrate( - db: VercelPgDatabase, - config: string | MigrationConfig, -): Promise; -export async function migrate( - db: XataHttpDatabase, - config: string | XataHttpMigrationConfig, -): Promise; -export async function migrate( - db: any, + db: + | AwsDataApiPgDatabase + | BetterSQLite3Database + | BunSQLiteDatabase + | DrizzleD1Database + | LibSQLDatabase + | MySql2Database + | NeonHttpDatabase + | NeonDatabase + | NodePgDatabase + | PlanetScaleDatabase + | PostgresJsDatabase + | VercelPgDatabase + | TiDBServerlessDatabase, config: | string - | MigrationConfig - | ExpoSQLiteMigrationConfig - | OPSQLiteMigrationConfig - | XataHttpMigrationConfig - | PgProxyMigrator - | MySqlProxyMigrator - | SQLiteProxyMigrator, - extraConfig?: string | MigrationConfig | undefined, + | MigrationConfig, ) { - switch (db[entityKind]) { + switch (( db)[entityKind]) { case 'AwsDataApiPgDatabase': { const { migrate } = await import('./aws-data-api/pg/migrator'); - return migrate(db, config as string | MigrationConfig); + return migrate(db as AwsDataApiPgDatabase, config as string | MigrationConfig); } case 'BetterSQLite3Database': { const { migrate } = await import('./better-sqlite3/migrator'); - return migrate(db, config as string | MigrationConfig); + return migrate(db as BetterSQLite3Database, config as string | MigrationConfig); } case 'BunSQLiteDatabase': { const { migrate } = await import('./bun-sqlite/migrator'); - return migrate(db, config as string | MigrationConfig); + return migrate(db as BunSQLiteDatabase, config as string | MigrationConfig); } case 'D1Database': { const { migrate } = await import('./d1/migrator'); - return migrate(db, config as string | MigrationConfig); - } - case 'ExpoSQLiteDatabase': { - const { migrate } = await import('./expo-sqlite/migrator'); - - return migrate(db, config as ExpoSQLiteMigrationConfig); + return migrate(db as DrizzleD1Database, config as string | MigrationConfig); } case 'LibSQLDatabase': { const { migrate } = await import('./libsql/migrator'); - return migrate(db, config as MigrationConfig); + return migrate(db as LibSQLDatabase, config as string | MigrationConfig); } - case 'MySqlRemoteDatabase': { - const { migrate } = await import('./mysql-proxy/migrator'); - - return migrate(db, config as MySqlProxyMigrator, extraConfig as MigrationConfig); - } - case 'MySql2Driver': { + case 'MySql2Database': { const { migrate } = await import('./mysql2/migrator'); - return migrate(db, config as MigrationConfig); + return migrate(db as MySql2Database, config as string | MigrationConfig); } case 'NeonHttpDatabase': { const { migrate } = await import('./neon-http/migrator'); - return migrate(db, config as string | MigrationConfig); + return migrate(db as NeonHttpDatabase, config as string | MigrationConfig); } case 'NeonServerlessDatabase': { const { migrate } = await import('./neon-serverless/migrator'); - return migrate(db, config as string | MigrationConfig); + return migrate(db as NeonDatabase, config as string | MigrationConfig); } - case 'NodePgDriver': { + case 'NodePgDatabase': { const { migrate } = await import('./node-postgres/migrator'); - return migrate(db, config as string | MigrationConfig); - } - case 'OPSQLiteDatabase': { - const { migrate } = await import('./op-sqlite/migrator'); - - return migrate(db, config as OPSQLiteMigrationConfig); - } - case 'PgRemoteDatabase': { - const { migrate } = await import('./pg-proxy/migrator'); - - return migrate(db, config as PgProxyMigrator, extraConfig as string | MigrationConfig); - } - case 'PgliteDatabase': { - const { migrate } = await import('./pglite/migrator'); - - return migrate(db, config as string | MigrationConfig); + return migrate(db as NodePgDatabase, config as string | MigrationConfig); } case 'PlanetScaleDatabase': { const { migrate } = await import('./planetscale-serverless/migrator'); - return migrate(db, config as MigrationConfig); + return migrate(db as PlanetScaleDatabase, config as string | MigrationConfig); } case 'PostgresJsDatabase': { const { migrate } = await import('./postgres-js/migrator'); - return migrate(db, config as string | MigrationConfig); - } - case 'SqliteRemoteDatabase': { - const { migrate } = await import('./sqlite-proxy/migrator'); - - return migrate(db, config as SQLiteProxyMigrator, extraConfig as string | MigrationConfig); + return migrate(db as PostgresJsDatabase, config as string | MigrationConfig); } case 'TiDBServerlessDatabase': { const { migrate } = await import('./tidb-serverless/migrator'); - return migrate(db, config as MigrationConfig); + return migrate(db as TiDBServerlessDatabase, config as MigrationConfig); } case 'VercelPgDatabase': { const { migrate } = await import('./vercel-postgres/migrator'); - return migrate(db, config as string | MigrationConfig); - } - case 'XataHttpDatabase': { - const { migrate } = await import('./xata-http/migrator'); - - return migrate(db, config as string | MigrationConfig); + return migrate(db as VercelPgDatabase, config as string | MigrationConfig); } } } diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index 3b21bf11d..a8fb65c3b 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -40,9 +40,11 @@ export class MySql2Driver { export { MySqlDatabase } from '~/mysql-core/db.ts'; -export type MySql2Database< +export class MySql2Database< TSchema extends Record = Record, -> = MySqlDatabase; +> extends MySqlDatabase { + static readonly [entityKind]: string = 'MySql2Database'; +} export type MySql2DrizzleConfig = Record> = & Omit, 'schema'> @@ -87,7 +89,7 @@ export function drizzle = Record; + return new MySql2Database(dialect, session, schema as any, mode) as MySql2Database; } interface CallbackClient { diff --git a/drizzle-orm/src/mysql2/migrator.ts b/drizzle-orm/src/mysql2/migrator.ts index 2f3c9c3dc..ae56e01f1 100644 --- a/drizzle-orm/src/mysql2/migrator.ts +++ b/drizzle-orm/src/mysql2/migrator.ts @@ -4,8 +4,15 @@ import type { MySql2Database } from './driver.ts'; export async function migrate>( db: MySql2Database, - config: MigrationConfig, + config: MigrationConfig | string, ) { const migrations = readMigrationFiles(config); - await db.dialect.migrate(migrations, db.session, config); + + const preparedConfig = typeof config === 'string' + ? { + migrationsFolder: config, + } + : config; + + await db.dialect.migrate(migrations, db.session, preparedConfig); } diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index 4c233f891..15ac8fc06 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -45,9 +45,11 @@ export class NodePgDriver { } } -export type NodePgDatabase< +export class NodePgDatabase< TSchema extends Record = Record, -> = PgDatabase; +> extends PgDatabase { + static readonly [entityKind]: string = 'NodePgDatabase'; +} export function drizzle = Record>( client: NodePgClient, @@ -76,5 +78,5 @@ export function drizzle = Record; + return new NodePgDatabase(dialect, session, schema as any) as NodePgDatabase; } diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index 4e8d2f354..0d923d7ee 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -622,7 +622,11 @@ export const withReplicas = < HKT extends PgQueryResultHKT, TFullSchema extends Record, TSchema extends TablesRelationalConfig, - Q extends PgDatabase, + Q extends PgDatabase< + HKT, + TFullSchema, + TSchema extends Record ? ExtractTablesWithRelations : TSchema + >, >( primary: Q, replicas: [Q, ...Q[]], diff --git a/drizzle-orm/src/planetscale-serverless/migrator.ts b/drizzle-orm/src/planetscale-serverless/migrator.ts index 5a668ae01..8b3713602 100644 --- a/drizzle-orm/src/planetscale-serverless/migrator.ts +++ b/drizzle-orm/src/planetscale-serverless/migrator.ts @@ -4,8 +4,15 @@ import type { PlanetScaleDatabase } from './driver.ts'; export async function migrate>( db: PlanetScaleDatabase, - config: MigrationConfig, + config: MigrationConfig | string, ) { const migrations = readMigrationFiles(config); - await db.dialect.migrate(migrations, db.session, config); + + const preparedConfig = typeof config === 'string' + ? { + migrationsFolder: config, + } + : config; + + await db.dialect.migrate(migrations, db.session, preparedConfig); } From 14ce2401e52c66ee8b50a3dc9f0b535b655c1a98 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 13:10:27 +0300 Subject: [PATCH 132/492] Fixed invalid [entityKind] call --- drizzle-orm/src/monomigrator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index aa590c8d7..bee18ad46 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -34,7 +34,7 @@ export async function migrate( | string | MigrationConfig, ) { - switch (( db)[entityKind]) { + switch (( db).constructor[entityKind]) { case 'AwsDataApiPgDatabase': { const { migrate } = await import('./aws-data-api/pg/migrator'); From ed173fa5a4bb6dbeadb6890c3bdb77675e04fb39 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 13:31:23 +0300 Subject: [PATCH 133/492] Added `:memory:` autocomplete --- drizzle-orm/src/monodriver.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index d2b86848b..d7955a585 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -52,18 +52,23 @@ type BunSqliteDatabaseOptions = type BunSqliteDatabaseConfig = | { - filename?: string; + filename?: ':memory:' | (string & {}); options?: BunSqliteDatabaseOptions; } - | string + | ':memory:' + | (string & {}) | undefined; type BetterSQLite3DatabaseConfig = | { - filename?: string | Buffer; + filename?: + | ':memory:' + | (string & {}) + | Buffer; options?: BetterSQLite3Options; } - | string + | ':memory:' + | (string & {}) | undefined; type MonodriverNeonHttpConfig = { From 3c3ccca814db796e4df9d4b6bb0123daf010719a Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 14:11:25 +0300 Subject: [PATCH 134/492] Removed leftover code from overloads, added `assertUnreachable` --- drizzle-orm/src/monodriver.ts | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index d7955a585..eb259e028 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -162,15 +162,10 @@ const importError = (libName: string) => { ); }; -const removeKey = , TKey extends keyof TRecord>( - obj: TRecord, - key: TKey, -): Omit => { - if (!(key in obj)) return obj; - - delete ( obj).key; - return obj; -}; +function assertUnreachable(_: never | undefined): never { + throw new Error("Didn't expect to get here"); +} + export async function drizzle< TClient extends DatabaseClient, TSchema extends Record = Record, @@ -182,8 +177,7 @@ export async function drizzle< : TClient extends 'aws-data-api-pg' ? DrizzleAwsDataApiPgConfig : DrizzleConfig), ): Promise> { - const connection = params?.connection; - const drizzleConfig = params ? removeKey(params, 'connection') : undefined; + const { connection, ...drizzleConfig } = params; switch (client) { case 'node-postgres': { @@ -296,10 +290,7 @@ export async function drizzle< return drizzle(sql, drizzleConfig) as any; } - default: { - throw new Error( - `Unsupported vendor for Drizzle ORM monodriver: '${client}'. Use dedicated drizzle initializer instead.`, - ); - } } + + assertUnreachable(client); } From 6f159743c4a38500602c5c612a37b67821384931 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 14:28:04 +0300 Subject: [PATCH 135/492] Added missing runtime tests --- integration-tests/tests/mysql/mysql-common.ts | 209 ++++++++++++++++++ integration-tests/tests/pg/pg-common.ts | 209 ++++++++++++++++++ .../tests/sqlite/sqlite-common.ts | 209 ++++++++++++++++++ 3 files changed, 627 insertions(+) diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 58f7a1e2c..05c69cada 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3577,6 +3577,215 @@ export function tests(driver?: string) { await db.execute(sql`drop view ${newYorkers1}`); }); + + test('$count separate', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(4); + }); + + test('$count embedded', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + }); + + test('$count separate reuse', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.$count(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual(4); + expect(count2).toStrictEqual(5); + expect(count3).toStrictEqual(6); + }); + + test('$count embedded reuse', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.execute(sql`drop table ${countTestTable}`); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + expect(count2).toStrictEqual([ + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + ]); + expect(count3).toStrictEqual([ + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + ]); + }); + + test('$count separate with filters', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable, gt(countTestTable.id, 1)); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(3); + }); + + test('$count embedded with filters', async (ctx) => { + const { db } = ctx.mysql; + + const countTestTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable, gt(countTestTable.id, 1)), + }).from(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 3 }, + { count: 3 }, + { count: 3 }, + ]); + }); }); test('limit 0', async (ctx) => { diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index c48a533f9..3f3dd75cc 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4660,5 +4660,214 @@ export function tests() { jsonbNumberField: testNumber, }]); }); + + test('$count separate', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(4); + }); + + test('$count embedded', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + }); + + test('$count separate reuse', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.$count(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual(4); + expect(count2).toStrictEqual(5); + expect(count3).toStrictEqual(6); + }); + + test('$count embedded reuse', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.execute(sql`drop table ${countTestTable}`); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + expect(count2).toStrictEqual([ + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + ]); + expect(count3).toStrictEqual([ + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + ]); + }); + + test('$count separate with filters', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable, gt(countTestTable.id, 1)); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(3); + }); + + test('$count embedded with filters', async (ctx) => { + const { db } = ctx.pg; + + const countTestTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${countTestTable}`); + await db.execute(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable, gt(countTestTable.id, 1)), + }).from(countTestTable); + + await db.execute(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 3 }, + { count: 3 }, + { count: 3 }, + ]); + }); }); } diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index be452bcf1..ed13f5b7b 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2679,6 +2679,215 @@ export function tests() { expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); } }); + + test('$count separate', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable); + + await db.run(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(4); + }); + + test('$count embedded', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + await db.run(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + }); + + test('$count separate reuse', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.$count(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.run(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual(4); + expect(count2).toStrictEqual(5); + expect(count3).toStrictEqual(6); + }); + + test('$count embedded reuse', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = db.select({ + count: db.$count(countTestTable), + }).from(countTestTable); + + const count1 = await count; + + await db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + await db.run(sql`drop table ${countTestTable}`); + + await db.run(sql`drop table ${countTestTable}`); + + expect(count1).toStrictEqual([ + { count: 4 }, + { count: 4 }, + { count: 4 }, + { count: 4 }, + ]); + expect(count2).toStrictEqual([ + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + { count: 5 }, + ]); + expect(count3).toStrictEqual([ + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + { count: 6 }, + ]); + }); + + test('$count separate with filters', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.$count(countTestTable, gt(countTestTable.id, 1)); + + await db.run(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual(3); + }); + + test('$count embedded with filters', async (ctx) => { + const { db } = ctx.sqlite; + + const countTestTable = sqliteTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists ${countTestTable}`); + await db.run(sql`create table ${countTestTable} (id int, name text)`); + + await db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await db.select({ + count: db.$count(countTestTable, gt(countTestTable.id, 1)), + }).from(countTestTable); + + await db.run(sql`drop table ${countTestTable}`); + + expect(count).toStrictEqual([ + { count: 3 }, + { count: 3 }, + { count: 3 }, + ]); + }); }); test('table configs: unique third param', () => { From b3add68ac10428d56c377f20f6c9897f8014261e Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 15:39:49 +0300 Subject: [PATCH 136/492] Exposed db drivers from monodriver --- drizzle-orm/src/monodriver.ts | 144 ++++++++++++++++++++++++++-------- 1 file changed, 112 insertions(+), 32 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index eb259e028..47e1881e1 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,19 +1,26 @@ /* eslint-disable import/extensions */ -import type { RDSDataClientConfig, RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; -import type { Config as LibsqlConfig } from '@libsql/client'; +import type { RDSDataClient, RDSDataClientConfig, RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; +import type { Client as LibsqlClient, Config as LibsqlConfig } from '@libsql/client'; import type { HTTPTransactionOptions as NeonHttpConfig, + NeonQueryFunction, + Pool as NeonServerlessPool, PoolConfig as NeonServerlessConfig, } from '@neondatabase/serverless'; -import type { Config as PlanetscaleConfig } from '@planetscale/database'; -import type { Config as TiDBServerlessConfig } from '@tidbcloud/serverless'; -import type { VercelPool } from '@vercel/postgres'; -import type { Options as BetterSQLite3Options } from 'better-sqlite3'; -import type { PoolOptions as Mysql2Config } from 'mysql2'; -import type { PoolConfig as NodePGPoolConfig } from 'pg'; -import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType } from 'postgres'; +import type { Client as PlanetscaleClient, Config as PlanetscaleConfig } from '@planetscale/database'; +import type { Config as TiDBServerlessConfig, Connection as TiDBConnection } from '@tidbcloud/serverless'; +import type { QueryResult, QueryResultRow, VercelPool } from '@vercel/postgres'; +import type { Database as BetterSQLite3Database, Options as BetterSQLite3Options } from 'better-sqlite3'; +import type { Database as BunDatabase } from 'bun:sqlite'; +import type { Pool as Mysql2Pool, PoolOptions as Mysql2Config } from 'mysql2'; +import type { Pool as NodePgPool, PoolConfig as NodePGPoolConfig } from 'pg'; +import type { + Options as PostgresJSOptions, + PostgresType as PostgresJSPostgresType, + Sql as PostgresJsClient, +} from 'postgres'; import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg/index.ts'; -import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; +import type { BetterSQLite3Database as DrizzleBetterSQLite3Database } from './better-sqlite3/index.ts'; import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; import type { DrizzleD1Database } from './d1/index.ts'; import type { LibSQLDatabase } from './libsql/index.ts'; @@ -76,6 +83,8 @@ type MonodriverNeonHttpConfig = { options?: NeonHttpConfig; }; +type VercelPrimitive = string | number | boolean | undefined | null; + type DatabaseClient = | 'node-postgres' | 'postgres-js' @@ -104,7 +113,28 @@ type ClientDrizzleInstanceMap> = { libsql: LibSQLDatabase; d1: DrizzleD1Database; 'bun:sqlite': BunSQLiteDatabase; - 'better-sqlite3': BetterSQLite3Database; + 'better-sqlite3': DrizzleBetterSQLite3Database; +}; + +type ClientInstanceMap = { + 'node-postgres': NodePgPool; + 'postgres-js': PostgresJsClient; + 'neon-serverless': NeonServerlessPool; + 'neon-http': NeonQueryFunction; + 'vercel-postgres': + & VercelPool + & (( + strings: TemplateStringsArray, + ...values: VercelPrimitive[] + ) => Promise>); + 'aws-data-api-pg': RDSDataClient; + planetscale: PlanetscaleClient; + mysql2: Mysql2Pool; + 'tidb-serverless': TiDBConnection; + libsql: LibsqlClient; + d1: D1Database; + 'bun:sqlite': BunDatabase; + 'better-sqlite3': BetterSQLite3Database; }; type InitializerParams = { @@ -150,11 +180,15 @@ type InitializerParams = { }; type DetermineClient< - TVendor extends DatabaseClient, + TClient extends DatabaseClient, TSchema extends Record, -> = ClientDrizzleInstanceMap< - TSchema ->[TVendor]; +> = + & ClientDrizzleInstanceMap< + TSchema + >[TClient] + & { + $client: ClientInstanceMap[TClient]; + }; const importError = (libName: string) => { throw new Error( @@ -185,7 +219,10 @@ export async function drizzle< const { drizzle } = await import('./node-postgres'); const instance = new Pool(connection as NodePGPoolConfig); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'aws-data-api-pg': { const { RDSDataClient } = await import('@aws-sdk/client-rds-data').catch(() => @@ -194,7 +231,10 @@ export async function drizzle< const { drizzle } = await import('./aws-data-api/pg'); const instance = new RDSDataClient(connection as RDSDataClientConfig); - return drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; + const db = drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; + db.$client = instance; + + return db; } case 'better-sqlite3': { const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); @@ -205,12 +245,18 @@ export async function drizzle< const instance = new Client(filename, options); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } const instance = new Client(connection); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'bun:sqlite': { const { Database: Client } = await import('bun:sqlite').catch(() => importError('bun:sqlite')); @@ -221,30 +267,46 @@ export async function drizzle< const instance = new Client(filename, options); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } const instance = new Client(connection); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'd1': { const { drizzle } = await import('./d1'); - return drizzle(connection as D1Database, drizzleConfig) as any; + + const db = drizzle(connection as D1Database, drizzleConfig) as any; + db.$client = connection; + + return db; } case 'libsql': { const { createClient } = await import('@libsql/client').catch(() => importError('@libsql/client')); const { drizzle } = await import('./libsql'); const instance = createClient(connection as LibsqlConfig); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'mysql2': { - const { createConnection } = await import('mysql2/promise').catch(() => importError('mysql2/promise')); - const instance = await createConnection(connection as Mysql2Config); + const { createPool } = await import('mysql2/promise').catch(() => importError('mysql2/promise')); + const instance = createPool(connection as Mysql2Config); const { drizzle } = await import('./mysql2'); - return drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any; + const db = drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any; + db.$client = instance; + + return db; } case 'neon-http': { const { neon } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); @@ -252,14 +314,20 @@ export async function drizzle< const { drizzle } = await import('./neon-http'); const instance = neon(connectionString, options); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'neon-serverless': { const { Pool } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); const { drizzle } = await import('./neon-serverless'); const instance = new Pool(connection as NeonServerlessConfig); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'planetscale': { const { Client } = await import('@planetscale/database').catch(() => importError('@planetscale/database')); @@ -268,27 +336,39 @@ export async function drizzle< connection as PlanetscaleConfig, ); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'postgres-js': { const { default: client } = await import('postgres').catch(() => importError('postgres')); const { drizzle } = await import('./postgres-js'); const instance = client(connection as PostgresJSOptions>); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'tidb-serverless': { const { connect } = await import('@tidbcloud/serverless').catch(() => importError('@tidbcloud/serverless')); const { drizzle } = await import('./tidb-serverless'); const instance = connect(connection as TiDBServerlessConfig); - return drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } case 'vercel-postgres': { const { sql } = await import('@vercel/postgres').catch(() => importError('@vercel/postgres')); const { drizzle } = await import('./vercel-postgres'); - return drizzle(sql, drizzleConfig) as any; + const db = drizzle(sql, drizzleConfig) as any; + db.$client = sql; + + return db; } } From 12dd7e524efccb288997e8ce7bd1f01852e329a1 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 16:50:20 +0300 Subject: [PATCH 137/492] Fixed test tables using already existing names --- integration-tests/tests/mysql/mysql-common.ts | 12 ++++++------ integration-tests/tests/pg/pg-common.ts | 12 ++++++------ integration-tests/tests/sqlite/sqlite-common.ts | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 05c69cada..7a02a251d 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3581,7 +3581,7 @@ export function tests(driver?: string) { test('$count separate', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -3606,7 +3606,7 @@ export function tests(driver?: string) { test('$count embedded', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -3638,7 +3638,7 @@ export function tests(driver?: string) { test('$count separate reuse', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -3675,7 +3675,7 @@ export function tests(driver?: string) { test('$count embedded reuse', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -3734,7 +3734,7 @@ export function tests(driver?: string) { test('$count separate with filters', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -3759,7 +3759,7 @@ export function tests(driver?: string) { test('$count embedded with filters', async (ctx) => { const { db } = ctx.mysql; - const countTestTable = mysqlTable('users_distinct', { + const countTestTable = mysqlTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 3f3dd75cc..384c3dab3 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4664,7 +4664,7 @@ export function tests() { test('$count separate', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); @@ -4689,7 +4689,7 @@ export function tests() { test('$count embedded', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); @@ -4721,7 +4721,7 @@ export function tests() { test('$count separate reuse', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); @@ -4758,7 +4758,7 @@ export function tests() { test('$count embedded reuse', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); @@ -4817,7 +4817,7 @@ export function tests() { test('$count separate with filters', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); @@ -4842,7 +4842,7 @@ export function tests() { test('$count embedded with filters', async (ctx) => { const { db } = ctx.pg; - const countTestTable = pgTable('users_distinct', { + const countTestTable = pgTable('count_test', { id: integer('id').notNull(), name: text('name').notNull(), }); diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index ed13f5b7b..5711b5d1d 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2683,7 +2683,7 @@ export function tests() { test('$count separate', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -2708,7 +2708,7 @@ export function tests() { test('$count embedded', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -2740,7 +2740,7 @@ export function tests() { test('$count separate reuse', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -2777,7 +2777,7 @@ export function tests() { test('$count embedded reuse', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -2836,7 +2836,7 @@ export function tests() { test('$count separate with filters', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); @@ -2861,7 +2861,7 @@ export function tests() { test('$count embedded with filters', async (ctx) => { const { db } = ctx.sqlite; - const countTestTable = sqliteTable('users_distinct', { + const countTestTable = sqliteTable('count_test', { id: int('id').notNull(), name: text('name').notNull(), }); From 01106be364569a2e515d77b33614dc8c25547e09 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 17:52:29 +0300 Subject: [PATCH 138/492] Fixed faulty test cases; Fixed lack of count type conversion in mysql; added all method functionality to pg proxy driver; added websocket instance to monodriver neon serverless config --- drizzle-orm/src/monodriver.ts | 15 +++++++++++++-- .../src/mysql-core/query-builders/count.ts | 6 ++++-- drizzle-orm/src/pg-proxy/session.ts | 4 +++- integration-tests/tests/mysql/mysql-common.ts | 3 +-- integration-tests/tests/pg/pg-common.ts | 3 +-- integration-tests/tests/sqlite/sqlite-common.ts | 3 +-- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 47e1881e1..0706f271a 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -209,9 +209,14 @@ export async function drizzle< & InitializerParams[TClient] & (TClient extends 'mysql2' ? MySql2DrizzleConfig : TClient extends 'aws-data-api-pg' ? DrizzleAwsDataApiPgConfig + : TClient extends 'neon-serverless' ? DrizzleConfig & { + ws?: any; + } : DrizzleConfig), ): Promise> { - const { connection, ...drizzleConfig } = params; + const { connection, ws, ...drizzleConfig } = params as typeof params & { + ws?: any; + }; switch (client) { case 'node-postgres': { @@ -320,10 +325,16 @@ export async function drizzle< return db; } case 'neon-serverless': { - const { Pool } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); + const { Pool, neonConfig } = await import('@neondatabase/serverless').catch(() => + importError('@neondatabase/serverless') + ); const { drizzle } = await import('./neon-serverless'); const instance = new Pool(connection as NeonServerlessConfig); + if (ws) { + neonConfig.webSocketConstructor = ws; + } + const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index 751ba61c7..b69d92777 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -27,7 +27,9 @@ export class MySqlCountBuilder< source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters}`; + return sql`select cast(count(*) as UNSIGNED) as count from ${source}${ + sql.raw(' where ').if(filters) + }${filters}`; } constructor( @@ -53,7 +55,7 @@ export class MySqlCountBuilder< onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { return Promise.resolve(this.session.all(this.sql)).then((it) => { - return (<[{ 'count(*)': number }]> it)[0]['count(*)']; + return (<[{ count: number }]> it)[0]['count']; }) .then( onfulfilled, diff --git a/drizzle-orm/src/pg-proxy/session.ts b/drizzle-orm/src/pg-proxy/session.ts index eb6a1b1a3..b5adad36c 100644 --- a/drizzle-orm/src/pg-proxy/session.ts +++ b/drizzle-orm/src/pg-proxy/session.ts @@ -130,7 +130,9 @@ export class PreparedQuery extends PreparedQueryB }); } - async all() {} + async all() { + return this.execute(); + } /** @internal */ isResponseInArrayMode(): boolean { diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 7a02a251d..7224b06f4 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3706,8 +3706,6 @@ export function tests(driver?: string) { await db.execute(sql`drop table ${countTestTable}`); - await db.execute(sql`drop table ${countTestTable}`); - expect(count1).toStrictEqual([ { count: 4 }, { count: 4 }, @@ -3784,6 +3782,7 @@ export function tests(driver?: string) { { count: 3 }, { count: 3 }, { count: 3 }, + { count: 3 }, ]); }); }); diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 384c3dab3..b4afdcf64 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4789,8 +4789,6 @@ export function tests() { await db.execute(sql`drop table ${countTestTable}`); - await db.execute(sql`drop table ${countTestTable}`); - expect(count1).toStrictEqual([ { count: 4 }, { count: 4 }, @@ -4867,6 +4865,7 @@ export function tests() { { count: 3 }, { count: 3 }, { count: 3 }, + { count: 3 }, ]); }); }); diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 5711b5d1d..e8ddb86e6 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2808,8 +2808,6 @@ export function tests() { await db.run(sql`drop table ${countTestTable}`); - await db.run(sql`drop table ${countTestTable}`); - expect(count1).toStrictEqual([ { count: 4 }, { count: 4 }, @@ -2886,6 +2884,7 @@ export function tests() { { count: 3 }, { count: 3 }, { count: 3 }, + { count: 3 }, ]); }); }); From 6cd6d78619aff0f2ff33dd0117edaa1ea8e15423 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 18:06:26 +0300 Subject: [PATCH 139/492] Switched mysql count to execute --- drizzle-orm/src/mysql-core/query-builders/count.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index b69d92777..a54a9eaf8 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -54,7 +54,7 @@ export class MySqlCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.all(this.sql)).then((it) => { + return Promise.resolve(this.session.execute(this.sql)).then((it) => { return (<[{ count: number }]> it)[0]['count']; }) .then( From dab63b85aefbc0931ffd1730eb172d47395f5da6 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 4 Sep 2024 18:08:50 +0300 Subject: [PATCH 140/492] Added cast to embedded --- drizzle-orm/src/mysql-core/query-builders/count.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index a54a9eaf8..01f9dfcd0 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -20,7 +20,7 @@ export class MySqlCountBuilder< source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; + return sql`(select cast(count(*) as UNSIGNED) from ${source}${sql.raw(' where ').if(filters)}${filters})`; } private static buildCount( From 218cddb87ae3ba640b434bc8381bb034e0d543a5 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Thu, 5 Sep 2024 12:55:11 +0300 Subject: [PATCH 141/492] Switched to `.execute` for mysql, pg; reverted pg proxy session changes; fixed misplaced mysql tests; removed unused args --- drizzle-orm/src/mysql-core/db.ts | 2 +- .../src/mysql-core/query-builders/count.ts | 4 +-- drizzle-orm/src/pg-core/db.ts | 2 +- .../src/pg-core/query-builders/count.ts | 6 ++-- drizzle-orm/src/pg-proxy/session.ts | 1 - drizzle-orm/src/sqlite-core/db.ts | 2 +- .../src/sqlite-core/query-builders/count.ts | 2 -- integration-tests/tests/mysql/mysql-common.ts | 36 +++++++++---------- 8 files changed, 24 insertions(+), 31 deletions(-) diff --git a/drizzle-orm/src/mysql-core/db.ts b/drizzle-orm/src/mysql-core/db.ts index 419359022..8934c0edf 100644 --- a/drizzle-orm/src/mysql-core/db.ts +++ b/drizzle-orm/src/mysql-core/db.ts @@ -140,7 +140,7 @@ export class MySqlDatabase< source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, filters?: SQL, ) { - return new MySqlCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); + return new MySqlCountBuilder({ source, filters, session: this.session }); } /** diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index 01f9dfcd0..1d5ac2a57 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -1,7 +1,6 @@ import { entityKind, sql } from '~/index.ts'; import type { SQLWrapper } from '~/sql/sql.ts'; import { SQL } from '~/sql/sql.ts'; -import type { MySqlDialect } from '../dialect.ts'; import type { MySqlSession } from '../session.ts'; import type { MySqlTable } from '../table.ts'; import type { MySqlViewBase } from '../view-base.ts'; @@ -36,7 +35,6 @@ export class MySqlCountBuilder< readonly params: { source: MySqlTable | MySqlViewBase | SQL | SQLWrapper; filters?: SQL; - dialect: MySqlDialect; session: TSession; }, ) { @@ -55,7 +53,7 @@ export class MySqlCountBuilder< onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { return Promise.resolve(this.session.execute(this.sql)).then((it) => { - return (<[{ count: number }]> it)[0]['count']; + return (<[[{ count: number }]]> it)[0][0]['count']; }) .then( onfulfilled, diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index 85dc797c9..62b64fb8f 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -141,7 +141,7 @@ export class PgDatabase< source: PgTable | PgViewBase | SQL | SQLWrapper, filters?: SQL, ) { - return new PgCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); + return new PgCountBuilder({ source, filters, session: this.session }); } /** diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index 7ccd722a0..cfc4d583b 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -1,7 +1,6 @@ import { entityKind, sql } from '~/index.ts'; import type { SQLWrapper } from '~/sql/sql.ts'; import { SQL } from '~/sql/sql.ts'; -import type { PgDialect } from '../dialect.ts'; import type { PgSession } from '../session.ts'; import type { PgTable } from '../table.ts'; @@ -26,14 +25,13 @@ export class PgCountBuilder< source: PgTable | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`select count(*)::int from ${source}${sql.raw(' where ').if(filters)}${filters};`; + return sql`select count(*)::int as count from ${source}${sql.raw(' where ').if(filters)}${filters};`; } constructor( readonly params: { source: PgTable | SQL | SQLWrapper; filters?: SQL; - dialect: PgDialect; session: TSession; }, ) { @@ -51,7 +49,7 @@ export class PgCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.all(this.sql)).then((it) => { + return Promise.resolve(this.session.execute(this.sql)).then((it) => { return (<[{ count: number }]> it)[0]['count'] as number; }) .then( diff --git a/drizzle-orm/src/pg-proxy/session.ts b/drizzle-orm/src/pg-proxy/session.ts index b5adad36c..1a30c0a3c 100644 --- a/drizzle-orm/src/pg-proxy/session.ts +++ b/drizzle-orm/src/pg-proxy/session.ts @@ -131,7 +131,6 @@ export class PreparedQuery extends PreparedQueryB } async all() { - return this.execute(); } /** @internal */ diff --git a/drizzle-orm/src/sqlite-core/db.ts b/drizzle-orm/src/sqlite-core/db.ts index 75b088f6d..7ae2736e0 100644 --- a/drizzle-orm/src/sqlite-core/db.ts +++ b/drizzle-orm/src/sqlite-core/db.ts @@ -140,7 +140,7 @@ export class BaseSQLiteDatabase< source: SQLiteTable | SQLiteViewBase | SQL | SQLWrapper, filters?: SQL, ) { - return new SQLiteCountBuilder({ source, filters, dialect: this.dialect, session: this.session }); + return new SQLiteCountBuilder({ source, filters, session: this.session }); } /** diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index ed6cd9a1d..f6434ee81 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -1,7 +1,6 @@ import { entityKind, sql } from '~/index.ts'; import type { SQLWrapper } from '~/sql/sql.ts'; import { SQL } from '~/sql/sql.ts'; -import type { SQLiteDialect } from '../dialect.ts'; import type { SQLiteSession } from '../session.ts'; import type { SQLiteTable } from '../table.ts'; import type { SQLiteView } from '../view.ts'; @@ -34,7 +33,6 @@ export class SQLiteCountBuilder< readonly params: { source: SQLiteTable | SQLiteView | SQL | SQLWrapper; filters?: SQL; - dialect: SQLiteDialect; session: TSession; }, ) { diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 7224b06f4..8a2fb768b 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3785,29 +3785,29 @@ export function tests(driver?: string) { { count: 3 }, ]); }); - }); - test('limit 0', async (ctx) => { - const { db } = ctx.mysql; + test('limit 0', async (ctx) => { + const { db } = ctx.mysql; - await db.insert(usersTable).values({ name: 'John' }); - const users = await db - .select() - .from(usersTable) - .limit(0); + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .select() + .from(usersTable) + .limit(0); - expect(users).toEqual([]); - }); + expect(users).toEqual([]); + }); - test('limit -1', async (ctx) => { - const { db } = ctx.mysql; + test('limit -1', async (ctx) => { + const { db } = ctx.mysql; - await db.insert(usersTable).values({ name: 'John' }); - const users = await db - .select() - .from(usersTable) - .limit(-1); + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .select() + .from(usersTable) + .limit(-1); - expect(users.length).toBeGreaterThan(0); + expect(users.length).toBeGreaterThan(0); + }); }); } From 5b27b324bfd4961ed4da0885063fcfdf39f605b7 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Thu, 5 Sep 2024 14:03:27 +0300 Subject: [PATCH 142/492] Moved type conversion drom db to ORM; improved types --- drizzle-orm/src/mysql-core/query-builders/count.ts | 12 ++++++------ drizzle-orm/src/pg-core/query-builders/count.ts | 10 ++++++---- drizzle-orm/src/sqlite-core/query-builders/count.ts | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index 1d5ac2a57..cf6188c2b 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -19,16 +19,14 @@ export class MySqlCountBuilder< source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`(select cast(count(*) as UNSIGNED) from ${source}${sql.raw(' where ').if(filters)}${filters})`; + return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; } private static buildCount( source: MySqlTable | MySqlViewBase | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`select cast(count(*) as UNSIGNED) as count from ${source}${ - sql.raw(' where ').if(filters) - }${filters}`; + return sql`select count(*) as count from ${source}${sql.raw(' where ').if(filters)}${filters}`; } constructor( @@ -40,6 +38,8 @@ export class MySqlCountBuilder< ) { super(MySqlCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); + this.mapWith(Number); + this.session = params.session; this.sql = MySqlCountBuilder.buildCount( @@ -52,8 +52,8 @@ export class MySqlCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.execute(this.sql)).then((it) => { - return (<[[{ count: number }]]> it)[0][0]['count']; + return Promise.resolve(this.session.execute<[[{ count: string }]]>(this.sql)).then((it) => { + return Number(it[0][0]['count']); }) .then( onfulfilled, diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index cfc4d583b..ca1f6b61d 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -18,14 +18,14 @@ export class PgCountBuilder< source: PgTable | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`(select count(*)::int from ${source}${sql.raw(' where ').if(filters)}${filters})`; + return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; } private static buildCount( source: PgTable | SQL | SQLWrapper, filters?: SQL, ): SQL { - return sql`select count(*)::int as count from ${source}${sql.raw(' where ').if(filters)}${filters};`; + return sql`select count(*) as count from ${source}${sql.raw(' where ').if(filters)}${filters};`; } constructor( @@ -37,6 +37,8 @@ export class PgCountBuilder< ) { super(PgCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); + this.mapWith(Number); + this.session = params.session; this.sql = PgCountBuilder.buildCount( @@ -49,8 +51,8 @@ export class PgCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.execute(this.sql)).then((it) => { - return (<[{ count: number }]> it)[0]['count'] as number; + return Promise.resolve(this.session.execute<[{ count: string }]>(this.sql)).then((it) => { + return Number(it[0]['count']); }) .then( onfulfilled, diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index f6434ee81..073562b8b 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -50,7 +50,7 @@ export class SQLiteCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.values(this.sql)).then((it) => it[0]![0] as number).then( + return Promise.resolve(this.session.values<[[number]]>(this.sql)).then((it) => it[0][0]).then( onfulfilled, onrejected, ); From d79ccef65e96c471e200a2d7d7cfd4f827a74daa Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Thu, 5 Sep 2024 15:39:48 +0300 Subject: [PATCH 143/492] Moved pg, mysql counts to sessions to resolve return shape conflicts --- drizzle-orm/src/mysql-core/query-builders/count.ts | 4 ++-- drizzle-orm/src/mysql-core/session.ts | 8 ++++++++ drizzle-orm/src/neon-http/session.ts | 10 +++++++++- drizzle-orm/src/node-postgres/session.ts | 9 ++++++++- drizzle-orm/src/pg-core/query-builders/count.ts | 4 ++-- drizzle-orm/src/pg-core/session.ts | 8 ++++++++ drizzle-orm/src/pglite/session.ts | 9 ++++++++- drizzle-orm/src/tidb-serverless/session.ts | 8 ++++++++ 8 files changed, 53 insertions(+), 7 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index cf6188c2b..4e734135f 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -52,8 +52,8 @@ export class MySqlCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.execute<[[{ count: string }]]>(this.sql)).then((it) => { - return Number(it[0][0]['count']); + return Promise.resolve(this.session.count(this.sql)).then((it) => { + return it; }) .then( onfulfilled, diff --git a/drizzle-orm/src/mysql-core/session.ts b/drizzle-orm/src/mysql-core/session.ts index 6b6269639..021d4276d 100644 --- a/drizzle-orm/src/mysql-core/session.ts +++ b/drizzle-orm/src/mysql-core/session.ts @@ -86,6 +86,14 @@ export abstract class MySqlSession< abstract all(query: SQL): Promise; + async count(sql: SQL): Promise { + const res = await this.execute<[[{ count: string }]]>(sql); + + return Number( + res[0][0]['count'], + ); + } + abstract transaction( transaction: (tx: MySqlTransaction) => Promise, config?: MySqlTransactionConfig, diff --git a/drizzle-orm/src/neon-http/session.ts b/drizzle-orm/src/neon-http/session.ts index 6d7685116..a36b7222b 100644 --- a/drizzle-orm/src/neon-http/session.ts +++ b/drizzle-orm/src/neon-http/session.ts @@ -10,7 +10,7 @@ import type { PgQueryResultHKT, PgTransactionConfig, PreparedQueryConfig } from import { PgPreparedQuery as PgPreparedQuery, PgSession } from '~/pg-core/session.ts'; import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import type { PreparedQuery } from '~/session.ts'; -import { fillPlaceholders, type Query } from '~/sql/sql.ts'; +import { fillPlaceholders, type Query, type SQL } from '~/sql/sql.ts'; import { mapResultRow } from '~/utils.ts'; export type NeonHttpClient = NeonQueryFunction; @@ -161,6 +161,14 @@ export class NeonHttpSession< return this.client(query, params, { arrayMode: false, fullResults: true }); } + override async count(sql: SQL): Promise { + const res = await this.execute<[{ count: string }]>(sql); + + return Number( + res[0]['count'], + ); + } + override async transaction( _transaction: (tx: NeonTransaction) => Promise, // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/drizzle-orm/src/node-postgres/session.ts b/drizzle-orm/src/node-postgres/session.ts index 91a21312a..ef6779354 100644 --- a/drizzle-orm/src/node-postgres/session.ts +++ b/drizzle-orm/src/node-postgres/session.ts @@ -8,7 +8,7 @@ import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.type import type { PgQueryResultHKT, PgTransactionConfig, PreparedQueryConfig } from '~/pg-core/session.ts'; import { PgPreparedQuery, PgSession } from '~/pg-core/session.ts'; import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; +import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; @@ -164,6 +164,13 @@ export class NodePgSession< } } } + + override async count(sql: SQL): Promise { + const res = await this.execute<{ rows: [{ count: string }] }>(sql); + return Number( + res['rows'][0]['count'], + ); + } } export class NodePgTransaction< diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index ca1f6b61d..6867b0950 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -51,8 +51,8 @@ export class PgCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.execute<[{ count: string }]>(this.sql)).then((it) => { - return Number(it[0]['count']); + return Promise.resolve(this.session.count(this.sql)).then((it) => { + return it; }) .then( onfulfilled, diff --git a/drizzle-orm/src/pg-core/session.ts b/drizzle-orm/src/pg-core/session.ts index 434ebc086..ea820f2d8 100644 --- a/drizzle-orm/src/pg-core/session.ts +++ b/drizzle-orm/src/pg-core/session.ts @@ -86,6 +86,14 @@ export abstract class PgSession< ).all(); } + async count(sql: SQL): Promise { + const res = await this.execute<[{ count: string }]>(sql); + + return Number( + res[0]['count'], + ); + } + abstract transaction( transaction: (tx: PgTransaction) => Promise, config?: PgTransactionConfig, diff --git a/drizzle-orm/src/pglite/session.ts b/drizzle-orm/src/pglite/session.ts index c7a1dbb5d..ebf7701a6 100644 --- a/drizzle-orm/src/pglite/session.ts +++ b/drizzle-orm/src/pglite/session.ts @@ -7,7 +7,7 @@ import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.type import type { PgQueryResultHKT, PgTransactionConfig, PreparedQueryConfig } from '~/pg-core/session.ts'; import { PgPreparedQuery, PgSession } from '~/pg-core/session.ts'; import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; +import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; import { types } from '@electric-sql/pglite'; @@ -140,6 +140,13 @@ export class PgliteSession< return transaction(tx); }) as Promise; } + + override async count(sql: SQL): Promise { + const res = await this.execute<{ rows: [{ count: string }] }>(sql); + return Number( + res['rows'][0]['count'], + ); + } } export class PgliteTransaction< diff --git a/drizzle-orm/src/tidb-serverless/session.ts b/drizzle-orm/src/tidb-serverless/session.ts index 64a8d61d7..b01b9f948 100644 --- a/drizzle-orm/src/tidb-serverless/session.ts +++ b/drizzle-orm/src/tidb-serverless/session.ts @@ -139,6 +139,14 @@ export class TiDBServerlessSession< return this.client.execute(querySql.sql, querySql.params) as Promise; } + override async count(sql: SQL): Promise { + const res = await this.execute<{ rows: [{ count: string }] }>(sql); + + return Number( + res['rows'][0]['count'], + ); + } + override async transaction( transaction: (tx: TiDBServerlessTransaction) => Promise, ): Promise { From 10639c23ea7f683d5c31271935a013aa0f525de5 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 5 Sep 2024 16:23:19 +0300 Subject: [PATCH 144/492] Check for Pg: -added check constraints to migrate, pull, push - added tests --- drizzle-kit/src/introspect-pg.ts | 30 ++- drizzle-kit/src/jsonDiffer.js | 22 ++ drizzle-kit/src/jsonStatements.ts | 52 +++- drizzle-kit/src/serializer/pgSchema.ts | 27 ++ drizzle-kit/src/serializer/pgSerializer.ts | 199 +++++++++++---- drizzle-kit/src/snapshotsDiffer.ts | 51 +++- drizzle-kit/src/sqlgenerator.ts | 51 +++- drizzle-kit/tests/introspect/pg.test.ts | 83 ++++++ drizzle-kit/tests/pg-checks.test.ts | 280 +++++++++++++++++++++ drizzle-kit/tests/push/pg.test.ts | 126 ++++++++++ 10 files changed, 866 insertions(+), 55 deletions(-) create mode 100644 drizzle-kit/tests/pg-checks.test.ts diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index b7a52b735..08ade834d 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -8,12 +8,12 @@ import { Relation, Relations, } from 'drizzle-orm/relations'; -import { plural, singular } from 'pluralize'; import './@types/utils'; import { Casing } from './cli/validations/common'; import { vectorOps } from './extensions/vector'; import { assertUnreachable } from './global'; import { + CheckConstraint, Column, ForeignKey, Index, @@ -356,6 +356,10 @@ export const schemaToTypeScript = ( (it) => 'unique', ); + const checkImports = Object.values(it.checkConstraints).map( + (it) => 'check', + ); + if (it.schema && it.schema !== 'public' && it.schema !== '') { res.pg.push('pgSchema'); } @@ -364,6 +368,7 @@ export const schemaToTypeScript = ( res.pg.push(...fkImpots); res.pg.push(...pkImports); res.pg.push(...uniqueImports); + res.pg.push(...checkImports); const columnImports = Object.values(it.columns) .map((col) => { @@ -492,6 +497,7 @@ export const schemaToTypeScript = ( || Object.values(table.foreignKeys).length > 0 || Object.keys(table.compositePrimaryKeys).length > 0 || Object.keys(table.uniqueConstraints).length > 0 + || Object.keys(table.checkConstraints).length > 0 ) { statement += ',\n'; statement += '(table) => {\n'; @@ -510,6 +516,10 @@ export const schemaToTypeScript = ( Object.values(table.uniqueConstraints), casing, ); + statement += createTableChecks( + Object.values(table.checkConstraints), + casing, + ); statement += '\t}\n'; statement += '}'; } @@ -1272,6 +1282,24 @@ const createTableUniques = ( return statement; }; +const createTableChecks = ( + checkConstraints: CheckConstraint[], + casing: Casing, +) => { + let statement = ''; + + checkConstraints.forEach((it) => { + const checkKey = withCasing(it.name, casing); + statement += `\t\t${checkKey}: `; + statement += 'check('; + statement += `"${it.name}", `; + statement += `sql\`${it.value}\`)`; + statement += `,\n`; + }); + + return statement; +}; + const createTableFKs = ( fks: ForeignKey[], schemas: Record, diff --git a/drizzle-kit/src/jsonDiffer.js b/drizzle-kit/src/jsonDiffer.js index 113d7e0a4..1ca195c85 100644 --- a/drizzle-kit/src/jsonDiffer.js +++ b/drizzle-kit/src/jsonDiffer.js @@ -346,6 +346,24 @@ const findAlternationsInTable = (table) => { }), ); + const addedCheckConstraints = Object.fromEntries( + Object.entries(table.checkConstraints || {}).filter((it) => { + return it[0].endsWith('__added'); + }), + ); + + const deletedCheckConstraints = Object.fromEntries( + Object.entries(table.checkConstraints || {}).filter((it) => { + return it[0].endsWith('__deleted'); + }), + ); + + const alteredCheckConstraints = Object.fromEntries( + Object.entries(table.checkConstraints || {}).filter((it) => { + return !it[0].endsWith('__deleted') && !it[0].endsWith('__added'); + }), + ); + const mappedAltered = altered.map((it) => alternationsInColumn(it)).filter(Boolean); return { @@ -364,11 +382,15 @@ const findAlternationsInTable = (table) => { addedUniqueConstraints, deletedUniqueConstraints, alteredUniqueConstraints, + addedCheckConstraints, + deletedCheckConstraints, + alteredCheckConstraints, }; }; const alternationsInColumn = (column) => { const altered = [column]; + const result = altered .filter((it) => { if ('type' in it && it.type.__old.replace(' (', '(') === it.type.__new.replace(' (', '(')) { diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index ad2afea7f..a3a831217 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -32,6 +32,7 @@ export interface JsonCreateTableStatement { compositePKs: string[]; compositePkName?: string; uniqueConstraints?: string[]; + checkConstraints?: string[]; internals?: MySqlKitInternals; } @@ -208,6 +209,20 @@ export interface JsonAlterUniqueConstraint { newConstraintName?: string; } +export interface JsonCreateCheckConstraint { + type: 'create_check_constraint'; + tableName: string; + data: string; + schema?: string; +} + +export interface JsonDeleteCheckConstraint { + type: 'delete_check_constraint'; + tableName: string; + data: string; + schema?: string; +} + export interface JsonCreateCompositePK { type: 'create_composite_pk'; tableName: string; @@ -555,14 +570,16 @@ export type JsonStatement = | JsonDropSequenceStatement | JsonCreateSequenceStatement | JsonMoveSequenceStatement - | JsonRenameSequenceStatement; + | JsonRenameSequenceStatement + | JsonCreateCheckConstraint + | JsonDeleteCheckConstraint; export const preparePgCreateTableJson = ( table: Table, // TODO: remove? json2: PgSchema, ): JsonCreateTableStatement => { - const { name, schema, columns, compositePrimaryKeys, uniqueConstraints } = table; + const { name, schema, columns, compositePrimaryKeys, uniqueConstraints, checkConstraints } = table; const tableKey = `${schema || 'public'}.${name}`; // TODO: @AndriiSherman. We need this, will add test cases @@ -580,6 +597,7 @@ export const preparePgCreateTableJson = ( compositePKs: Object.values(compositePrimaryKeys), compositePkName: compositePkName, uniqueConstraints: Object.values(uniqueConstraints), + checkConstraints: Object.values(checkConstraints), }; }; @@ -2136,6 +2154,36 @@ export const prepareDeleteUniqueConstraintPg = ( }); }; +export const prepareAddCheckConstraintPg = ( + tableName: string, + schema: string, + check: Record, +): JsonCreateCheckConstraint[] => { + return Object.values(check).map((it) => { + return { + type: 'create_check_constraint', + tableName, + data: it, + schema, + } as JsonCreateCheckConstraint; + }); +}; + +export const prepareDeleteCheckConstraintPg = ( + tableName: string, + schema: string, + check: Record, +): JsonDeleteCheckConstraint[] => { + return Object.values(check).map((it) => { + return { + type: 'delete_check_constraint', + tableName, + data: PgSquasher.unsquashCheck(it).name, // only name needed + schema, + } as JsonDeleteCheckConstraint; + }); +}; + // add create table changes // add handler to make drop and add and not alter(looking at __old and __new) // add serializer for mysql and sqlite + types diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index 5860a6fef..db8b9647c 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -185,6 +185,11 @@ const column = object({ .optional(), }).strict(); +const checkConstraint = object({ + name: string(), + value: string(), +}).strict(); + const columnSquashed = object({ name: string(), type: string(), @@ -266,6 +271,7 @@ const table = object({ foreignKeys: record(string(), fk), compositePrimaryKeys: record(string(), compositePK), uniqueConstraints: record(string(), uniqueConstraint).default({}), + checkConstraints: record(string(), checkConstraint).default({}), }).strict(); const schemaHash = object({ @@ -385,6 +391,7 @@ const tableSquashed = object({ foreignKeys: record(string(), string()), compositePrimaryKeys: record(string(), string()), uniqueConstraints: record(string(), string()), + checkConstraints: record(string(), string()), }).strict(); const tableSquashedV4 = object({ @@ -446,6 +453,7 @@ export type ForeignKey = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; export type PgKitInternals = TypeOf; +export type CheckConstraint = TypeOf; export type PgSchemaV1 = TypeOf; export type PgSchemaV2 = TypeOf; @@ -627,6 +635,17 @@ export const PgSquasher = { cycle: splitted[7] === 'true', }; }, + squashCheck: (check: CheckConstraint) => { + return `${check.name};${check.value}`; + }, + unsquashCheck: (input: string): CheckConstraint => { + const [ + name, + value, + ] = input.split(';'); + + return { name, value }; + }, }; export const squashPgScheme = ( @@ -671,6 +690,13 @@ export const squashPgScheme = ( }, ); + const squashedChecksContraints = mapValues( + it[1].checkConstraints, + (check) => { + return PgSquasher.squashCheck(check); + }, + ); + return [ it[0], { @@ -681,6 +707,7 @@ export const squashPgScheme = ( foreignKeys: squashedFKs, compositePrimaryKeys: squashedPKs, uniqueConstraints: squashedUniqueConstraints, + checkConstraints: squashedChecksContraints, }, ]; }), diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index b479e59e2..48f002b51 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -4,11 +4,9 @@ import { AnyPgTable, ExtraConfigColumn, IndexedColumn, - PgColumn, PgDialect, PgEnum, PgEnumColumn, - PgInteger, PgSchema, PgSequence, uniqueKeyName, @@ -18,6 +16,7 @@ import { vectorOps } from 'src/extensions/vector'; import { withStyle } from '../cli/validations/outputs'; import type { IntrospectStage, IntrospectStatus } from '../cli/views'; import type { + CheckConstraint, Column as Column, Enum, ForeignKey, @@ -127,6 +126,10 @@ export const generatePgSnapshot = ( const indexesInSchema: Record = {}; for (const table of tables) { + // This object stores unique names for checks and will be used to detect if you have the same names for checks + // within the same PostgreSQL table + const checksInTable: Record = {}; + const { name: tableName, columns, @@ -144,6 +147,7 @@ export const generatePgSnapshot = ( const columnsObject: Record = {}; const indexesObject: Record = {}; + const checksObject: Record = {}; const foreignKeysObject: Record = {}; const primaryKeysObject: Record = {}; const uniqueConstraintObject: Record = {}; @@ -492,6 +496,43 @@ export const generatePgSnapshot = ( }; }); + checks.forEach((check) => { + const checkName = check.name; + + if (typeof checksInTable[`"${schema ?? 'public'}"."${tableName}"`] !== 'undefined') { + if (checksInTable[`"${schema ?? 'public'}"."${tableName}"`].includes(check.name)) { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated check constraint name across ${ + chalk.underline.blue( + schema ?? 'public', + ) + } schema in ${ + chalk.underline.blue( + tableName, + ) + }. Please rename your check constraint in either the ${ + chalk.underline.blue( + tableName, + ) + } table or the table with the duplicated check contraint name`, + ) + }`, + ); + process.exit(1); + } + checksInTable[`"${schema ?? 'public'}"."${tableName}"`].push(checkName); + } else { + checksInTable[`"${schema ?? 'public'}"."${tableName}"`] = [check.name]; + } + + checksObject[checkName] = { + name: checkName, + value: dialect.sqlToQuery(check.value).sql, + }; + }); + const tableKey = `${schema ?? 'public'}.${tableName}`; result[tableKey] = { @@ -502,6 +543,7 @@ export const generatePgSnapshot = ( foreignKeys: foreignKeysObject, compositePrimaryKeys: primaryKeysObject, uniqueConstraints: uniqueConstraintObject, + checkConstraints: checksObject, }; } @@ -718,7 +760,8 @@ export const fromDatabase = async ( const indexToReturn: Record = {}; const foreignKeysToReturn: Record = {}; const primaryKeys: Record = {}; - const uniqueConstrains: Record = {}; + const uniqueConstraints: Record = {}; + const checkConstraints: Record = {}; const tableResponse = await db.query( `SELECT a.attrelid::regclass::text, a.attname, is_nullable, a.attndims as array_dimensions @@ -758,14 +801,57 @@ export const fromDatabase = async ( ); const tableConstraints = await db.query( - `SELECT c.column_name, c.data_type, constraint_type, constraint_name, constraint_schema - FROM information_schema.table_constraints tc - JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name) - JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema - AND tc.table_name = c.table_name AND ccu.column_name = c.column_name - WHERE tc.table_name = '${tableName}' and constraint_schema = '${tableSchema}';`, + `SELECT c.column_name, + c.data_type, + tc.constraint_type, + tc.constraint_name, + tc.constraint_schema, + pg_get_constraintdef(con.oid) AS check_constraint_definition + FROM information_schema.table_constraints tc + JOIN information_schema.constraint_column_usage AS ccu + USING (constraint_schema, constraint_name) + JOIN information_schema.columns AS c + ON c.table_schema = tc.constraint_schema + AND tc.table_name = c.table_name + AND ccu.column_name = c.column_name + JOIN pg_constraint con + ON con.conname = tc.constraint_name + AND con.conrelid = ( + SELECT oid + FROM pg_class + WHERE relname = tc.table_name + AND relnamespace = ( + SELECT oid + FROM pg_namespace + WHERE nspname = tc.constraint_schema + ) + ) + WHERE tc.table_name = '${tableName}' AND tc.constraint_schema = '${tableSchema}';`, ); + const tableChecks = await db.query(`SELECT + tc.constraint_name, + tc.constraint_type, + pg_get_constraintdef(con.oid) AS constraint_definition + FROM + information_schema.table_constraints AS tc + JOIN pg_constraint AS con + ON tc.constraint_name = con.conname + AND con.conrelid = ( + SELECT oid + FROM pg_class + WHERE relname = tc.table_name + AND relnamespace = ( + SELECT oid + FROM pg_namespace + WHERE nspname = tc.constraint_schema + ) + ) + WHERE + tc.table_name = '${tableName}' + AND tc.constraint_schema = '${tableSchema}' + AND tc.constraint_type = 'CHECK';`); + columnsCount += tableResponse.length; if (progressCallback) { progressCallback('columns', columnsCount, 'fetching'); @@ -773,42 +859,42 @@ export const fromDatabase = async ( const tableForeignKeys = await db.query( `SELECT - con.contype AS constraint_type, - nsp.nspname AS constraint_schema, - con.conname AS constraint_name, - rel.relname AS table_name, - att.attname AS column_name, - fnsp.nspname AS foreign_table_schema, - frel.relname AS foreign_table_name, - fatt.attname AS foreign_column_name, - CASE con.confupdtype - WHEN 'a' THEN 'NO ACTION' - WHEN 'r' THEN 'RESTRICT' - WHEN 'n' THEN 'SET NULL' - WHEN 'c' THEN 'CASCADE' - WHEN 'd' THEN 'SET DEFAULT' - END AS update_rule, - CASE con.confdeltype - WHEN 'a' THEN 'NO ACTION' - WHEN 'r' THEN 'RESTRICT' - WHEN 'n' THEN 'SET NULL' - WHEN 'c' THEN 'CASCADE' - WHEN 'd' THEN 'SET DEFAULT' - END AS delete_rule - FROM - pg_catalog.pg_constraint con - JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid - JOIN pg_catalog.pg_namespace nsp ON nsp.oid = con.connamespace - LEFT JOIN pg_catalog.pg_attribute att ON att.attnum = ANY (con.conkey) - AND att.attrelid = con.conrelid - LEFT JOIN pg_catalog.pg_class frel ON frel.oid = con.confrelid - LEFT JOIN pg_catalog.pg_namespace fnsp ON fnsp.oid = frel.relnamespace - LEFT JOIN pg_catalog.pg_attribute fatt ON fatt.attnum = ANY (con.confkey) - AND fatt.attrelid = con.confrelid - WHERE - nsp.nspname = '${tableSchema}' - AND rel.relname = '${tableName}' - AND con.contype IN ('f');`, + con.contype AS constraint_type, + nsp.nspname AS constraint_schema, + con.conname AS constraint_name, + rel.relname AS table_name, + att.attname AS column_name, + fnsp.nspname AS foreign_table_schema, + frel.relname AS foreign_table_name, + fatt.attname AS foreign_column_name, + CASE con.confupdtype + WHEN 'a' THEN 'NO ACTION' + WHEN 'r' THEN 'RESTRICT' + WHEN 'n' THEN 'SET NULL' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + END AS update_rule, + CASE con.confdeltype + WHEN 'a' THEN 'NO ACTION' + WHEN 'r' THEN 'RESTRICT' + WHEN 'n' THEN 'SET NULL' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + END AS delete_rule + FROM + pg_catalog.pg_constraint con + JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + JOIN pg_catalog.pg_namespace nsp ON nsp.oid = con.connamespace + LEFT JOIN pg_catalog.pg_attribute att ON att.attnum = ANY (con.conkey) + AND att.attrelid = con.conrelid + LEFT JOIN pg_catalog.pg_class frel ON frel.oid = con.confrelid + LEFT JOIN pg_catalog.pg_namespace fnsp ON fnsp.oid = frel.relnamespace + LEFT JOIN pg_catalog.pg_attribute fatt ON fatt.attnum = ANY (con.confkey) + AND fatt.attrelid = con.confrelid + WHERE + nsp.nspname = '${tableSchema}' + AND rel.relname = '${tableName}' + AND con.contype IN ('f');`, ); foreignKeysCount += tableForeignKeys.length; @@ -859,10 +945,10 @@ export const fromDatabase = async ( const columnName: string = unqs.column_name; const constraintName: string = unqs.constraint_name; - if (typeof uniqueConstrains[constraintName] !== 'undefined') { - uniqueConstrains[constraintName].columns.push(columnName); + if (typeof uniqueConstraints[constraintName] !== 'undefined') { + uniqueConstraints[constraintName].columns.push(columnName); } else { - uniqueConstrains[constraintName] = { + uniqueConstraints[constraintName] = { columns: [columnName], nullsNotDistinct: false, name: constraintName, @@ -870,6 +956,20 @@ export const fromDatabase = async ( } } + for (const checks of tableChecks) { + // CHECK (((email)::text <> 'test@gmail.com'::text)) + // Where (email) is column in table + let checkValue: string = checks.constraint_definition; + const constraintName: string = checks.constraint_name; + + checkValue = checkValue.replace(/^CHECK\s*\(\(/, '').replace(/\)\)\s*$/, ''); + + checkConstraints[constraintName] = { + name: constraintName, + value: checkValue, + }; + } + for (const columnResponse of tableResponse) { const columnName = columnResponse.attname; const columnAdditionalDT = columnResponse.additional_dt; @@ -1180,7 +1280,8 @@ export const fromDatabase = async ( indexes: indexToReturn, foreignKeys: foreignKeysToReturn, compositePrimaryKeys: primaryKeys, - uniqueConstraints: uniqueConstrains, + uniqueConstraints: uniqueConstraints, + checkConstraints: checkConstraints, }; } catch (e) { rej(e); diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 9ad2d9e32..29bf4cd15 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -24,9 +24,11 @@ import { JsonAlterCompositePK, JsonAlterTableSetSchema, JsonAlterUniqueConstraint, + JsonCreateCheckConstraint, JsonCreateCompositePK, JsonCreateReferenceStatement, JsonCreateUniqueConstraint, + JsonDeleteCheckConstraint, JsonDeleteCompositePK, JsonDeleteUniqueConstraint, JsonDropColumnStatement, @@ -34,6 +36,7 @@ import { JsonRenameColumnStatement, JsonSqliteAddColumnStatement, JsonStatement, + prepareAddCheckConstraintPg, prepareAddCompositePrimaryKeyMySql, prepareAddCompositePrimaryKeyPg, prepareAddCompositePrimaryKeySqlite, @@ -50,6 +53,7 @@ import { prepareCreateReferencesJson, prepareCreateSchemasJson, prepareCreateSequenceJson, + prepareDeleteCheckConstraintPg, prepareDeleteCompositePrimaryKeyMySql, prepareDeleteCompositePrimaryKeyPg, prepareDeleteCompositePrimaryKeySqlite, @@ -78,7 +82,7 @@ import { import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher } from './serializer/mysqlSchema'; -import { PgSchema, PgSchemaSquashed, PgSquasher, sequenceSchema, sequenceSquashed } from './serializer/pgSchema'; +import { PgSchema, PgSchemaSquashed, PgSquasher, sequenceSquashed } from './serializer/pgSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; import { copy, prepareMigrationMeta } from './utils'; @@ -204,6 +208,7 @@ const tableScheme = object({ foreignKeys: record(string(), string()), compositePrimaryKeys: record(string(), string()).default({}), uniqueConstraints: record(string(), string()).default({}), + checkConstraints: record(string(), string()).default({}), }).strict(); export const alteredTableScheme = object({ @@ -246,6 +251,21 @@ export const alteredTableScheme = object({ __old: string(), }), ), + addedCheckConstraints: record( + string(), + string(), + ), + deletedCheckConstraints: record( + string(), + string(), + ), + alteredCheckConstraints: record( + string(), + object({ + __new: string(), + __old: string(), + }), + ), }).strict(); export const diffResultScheme = object({ @@ -788,6 +808,9 @@ export const applyPgSnapshotsDiff = async ( }); } + const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + const jsonCreatedCheckConstraints: JsonCreateCheckConstraint[] = []; + for (let it of alteredTables) { // This part is needed to make sure that same columns in a table are not triggered for change // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name @@ -838,6 +861,8 @@ export const applyPgSnapshotsDiff = async ( let addedUniqueConstraints: JsonCreateUniqueConstraint[] = []; let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + let createCheckConstraints: JsonCreateCheckConstraint[] = []; + let deleteCheckConstraints: JsonDeleteCheckConstraint[] = []; addedUniqueConstraints = prepareAddUniqueConstraint( it.name, @@ -864,6 +889,28 @@ export const applyPgSnapshotsDiff = async ( ); } + createCheckConstraints = prepareAddCheckConstraintPg(it.name, it.schema, it.addedCheckConstraints); + deleteCheckConstraints = prepareDeleteCheckConstraintPg( + it.name, + it.schema, + it.deletedCheckConstraints, + ); + + if (it.alteredCheckConstraints && action !== 'push') { + const added: Record = {}; + const deleted: Record = {}; + + for (const k of Object.keys(it.alteredCheckConstraints)) { + added[k] = it.alteredCheckConstraints[k].__new; + deleted[k] = it.alteredCheckConstraints[k].__old; + } + createCheckConstraints.push(...prepareAddCheckConstraintPg(it.name, it.schema, added)); + deleteCheckConstraints.push(...prepareDeleteCheckConstraintPg(it.name, it.schema, deleted)); + } + + jsonCreatedCheckConstraints.push(...createCheckConstraints); + jsonDeletedCheckConstraints.push(...deleteCheckConstraints); + jsonAddedCompositePKs.push(...addedCompositePKs); jsonDeletedCompositePKs.push(...deletedCompositePKs); jsonAlteredCompositePKs.push(...alteredCompositePKs); @@ -1108,6 +1155,7 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...jsonRenameColumnsStatements); jsonStatements.push(...jsonDeletedUniqueConstraints); + jsonStatements.push(...jsonDeletedCheckConstraints); jsonStatements.push(...jsonDroppedReferencesForAlteredTables); @@ -1130,6 +1178,7 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...jsonAlteredCompositePKs); jsonStatements.push(...jsonAddedUniqueConstraints); + jsonStatements.push(...jsonCreatedCheckConstraints); jsonStatements.push(...jsonAlteredUniqueConstraints); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index ec1a2d69e..c66e0e915 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -25,7 +25,7 @@ import { JsonAlterTableRemoveFromSchema, JsonAlterTableSetNewSchema, JsonAlterTableSetSchema, - JsonAlterUniqueConstraint, + JsonCreateCheckConstraint, JsonCreateCompositePK, JsonCreateEnumStatement, JsonCreateIndexStatement, @@ -34,6 +34,7 @@ import { JsonCreateSequenceStatement, JsonCreateTableStatement, JsonCreateUniqueConstraint, + JsonDeleteCheckConstraint, JsonDeleteCompositePK, JsonDeleteReferenceStatement, JsonDeleteUniqueConstraint, @@ -137,7 +138,7 @@ class PgCreateTableConvertor extends Convertor { } convert(st: JsonCreateTableStatement) { - const { tableName, schema, columns, compositePKs, uniqueConstraints } = st; + const { tableName, schema, columns, compositePKs, uniqueConstraints, checkConstraints } = st; let statement = ''; const name = schema ? `"${schema}"."${tableName}"` : `"${tableName}"`; @@ -222,6 +223,15 @@ class PgCreateTableConvertor extends Convertor { // statement += `\n`; } } + + if (typeof checkConstraints !== 'undefined' && checkConstraints.length > 0) { + for (const checkConstraint of checkConstraints) { + statement += ',\n'; + const unsquashedCheck = PgSquasher.unsquashCheck(checkConstraint); + statement += `\tCONSTRAINT "${unsquashedCheck.name}" CHECK (${unsquashedCheck.value})`; + } + } + statement += `\n);`; statement += `\n`; @@ -565,6 +575,40 @@ class PgAlterTableDropUniqueConstraintConvertor extends Convertor { } } +class PgAlterTableAddCheckConstraintConvertor extends Convertor { + can(statement: JsonCreateCheckConstraint, dialect: Dialect): boolean { + return ( + statement.type === 'create_check_constraint' && dialect === 'postgresql' + ); + } + convert(statement: JsonCreateCheckConstraint): string { + const unsquashed = PgSquasher.unsquashCheck(statement.data); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${unsquashed.name}" CHECK (${unsquashed.value});`; + } +} + +class PgAlterTableDeleteCheckConstraintConvertor extends Convertor { + can(statement: JsonDeleteCheckConstraint, dialect: Dialect): boolean { + return ( + statement.type === 'delete_check_constraint' && dialect === 'postgresql' + ); + } + convert(statement: JsonDeleteCheckConstraint): string { + const unsquashed = PgSquasher.unsquashCheck(statement.data); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${unsquashed.name}";`; + } +} + class MySQLAlterTableAddUniqueConstraintConvertor extends Convertor { can(statement: JsonCreateUniqueConstraint, dialect: Dialect): boolean { return statement.type === 'create_unique_constraint' && dialect === 'mysql'; @@ -2548,6 +2592,9 @@ convertors.push(new PgAlterTableAlterColumnSetTypeConvertor()); convertors.push(new PgAlterTableAddUniqueConstraintConvertor()); convertors.push(new PgAlterTableDropUniqueConstraintConvertor()); +convertors.push(new PgAlterTableAddCheckConstraintConvertor()); +convertors.push(new PgAlterTableDeleteCheckConstraintConvertor()); + convertors.push(new MySQLAlterTableAddUniqueConstraintConvertor()); convertors.push(new MySQLAlterTableDropUniqueConstraintConvertor()); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index e65c0f904..542340fab 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -5,6 +5,7 @@ import { bigserial, boolean, char, + check, cidr, date, doublePrecision, @@ -405,3 +406,85 @@ test('introspect enum with similar name to native type', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('introspect check', async () => { + const client = new PGlite(); + + const schema = { + users: pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('name').notNull(), + age: integer('age'), + }, (table) => ({ + minimumAgeCheck: check('public_users_minimum_age_check', sql`${table.age} > 21`), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-check', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect check for different schema', async () => { + const client = new PGlite(); + + const schema2 = pgSchema('schema2'); + const schema = { + schema2, + users: schema2.table('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('name').notNull(), + age: integer('age'), + }, (table) => ({ + minimumAgeCheck: check('schema2_users_minimum_age_check', sql`${table.age} > 21`), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-check-for-different-schema', + ['schema2'], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect checks with same names across different schema', async () => { + const client = new PGlite(); + + const schema2 = pgSchema('schema2'); + const schema = { + schema2, + usersInSchema2: schema2.table('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('name').notNull(), + age: integer('age'), + }, (table) => ({ + minimumAgeCheck: check('public_users_minimum_age_check', sql`${table.age} > 21`), + })), + usersInPublic: pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('name').notNull(), + age: integer('age'), + }, (table) => ({ + minimumAgeCheck: check('public_users_minimum_age_check', sql`${table.age} > 21`), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-checks-with-same-names-across-different-schema', + ['schema2', 'public'], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/pg-checks.test.ts b/drizzle-kit/tests/pg-checks.test.ts new file mode 100644 index 000000000..1f12e76a3 --- /dev/null +++ b/drizzle-kit/tests/pg-checks.test.ts @@ -0,0 +1,280 @@ +import { sql } from 'drizzle-orm'; +import { check, integer, pgTable, serial, varchar } from 'drizzle-orm/pg-core'; +import { JsonCreateTableStatement } from 'src/jsonStatements'; +import { expect, test } from 'vitest'; +import { diffTestSchemas } from './schemaDiffer'; + +test('create table with check', async (t) => { + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [ + { + name: 'id', + type: 'serial', + notNull: true, + primaryKey: true, + }, + { + name: 'age', + type: 'integer', + notNull: false, + primaryKey: false, + }, + ], + compositePKs: [], + checkConstraints: ['some_check_name;"users"."age" > 21'], + compositePkName: '', + uniqueConstraints: [], + } as JsonCreateTableStatement); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" serial PRIMARY KEY NOT NULL, +\t"age" integer, +\tCONSTRAINT "some_check_name" CHECK ("users"."age" > 21) +);\n`); +}); + +test('add check contraint to existing table', async (t) => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }), + }; + + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemas(from, to, []); + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_check_constraint', + tableName: 'users', + schema: '', + data: 'some_check_name;"users"."age" > 21', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "users" ADD CONSTRAINT "some_check_name" CHECK ("users"."age" > 21);`, + ); +}); + +test('drop check contraint in existing table', async (t) => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }), + }; + + const { sqlStatements, statements } = await diffTestSchemas(from, to, []); + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'delete_check_constraint', + tableName: 'users', + schema: '', + data: 'some_check_name;"users"."age" > 21', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "users" DROP CONSTRAINT "some_check_name";`, + ); +}); + +test('rename check constraint', async (t) => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('new_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemas(from, to, []); + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + data: 'some_check_name;"users"."age" > 21', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + data: 'new_check_name;"users"."age" > 21', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "users" DROP CONSTRAINT "some_check_name";`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE "users" ADD CONSTRAINT "new_check_name" CHECK ("users"."age" > 21);`, + ); +}); + +test('alter check constraint', async (t) => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('new_check_name', sql`${table.age} > 10`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemas(from, to, []); + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + data: 'some_check_name;"users"."age" > 21', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + data: 'new_check_name;"users"."age" > 10', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "users" DROP CONSTRAINT "some_check_name";`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE "users" ADD CONSTRAINT "new_check_name" CHECK ("users"."age" > 10);`, + ); +}); + +test('alter multiple check constraints', async (t) => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + name: varchar('name'), + }, (table) => ({ + checkConstraint1: check('some_check_name_1', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name_2', sql`${table.name} != 'Alex'`), + })), + }; + + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + name: varchar('name'), + }, (table) => ({ + checkConstraint1: check('some_check_name_3', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name_4', sql`${table.name} != 'Alex'`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemas(from, to, []); + expect(statements.length).toBe(4); + expect(statements[0]).toStrictEqual({ + data: 'some_check_name_1;"users"."age" > 21', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + data: 'some_check_name_2;"users"."name" != \'Alex\'', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[2]).toStrictEqual({ + data: 'some_check_name_3;"users"."age" > 21', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + expect(statements[3]).toStrictEqual({ + data: 'some_check_name_4;"users"."name" != \'Alex\'', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "users" DROP CONSTRAINT "some_check_name_1";`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE "users" DROP CONSTRAINT "some_check_name_2";`, + ); + expect(sqlStatements[2]).toBe( + `ALTER TABLE "users" ADD CONSTRAINT "some_check_name_3" CHECK ("users"."age" > 21);`, + ); + expect(sqlStatements[3]).toBe( + `ALTER TABLE "users" ADD CONSTRAINT "some_check_name_4" CHECK ("users"."name" != \'Alex\');`, + ); +}); + +test('create checks with same names', async (t) => { + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + name: varchar('name'), + }, (table) => ({ + checkConstraint1: check('some_check_name', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name', sql`${table.name} != 'Alex'`), + })), + }; + + await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); +}); diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index cb1a97122..1cb5d716c 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -4,6 +4,7 @@ import { bigserial, boolean, char, + check, date, doublePrecision, index, @@ -620,6 +621,7 @@ const pgSuite: DialectSuite = { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1388,6 +1390,7 @@ test('create table: identity always/by default - no params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1455,6 +1458,7 @@ test('create table: identity always/by default - few params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1528,6 +1532,7 @@ test('create table: identity always/by default - all params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -2236,3 +2241,124 @@ test('add array column - default', async () => { 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\';', ]); }); + +test('add check constraint to table', async () => { + const client = new PGlite(); + + const schema1 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().default([1, 2, 3]), + }), + }; + const schema2 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().default([1, 2, 3]), + }, (table) => ({ + checkConstraint1: check('some_check1', sql`${table.values} < 100`), + checkConstraint2: check('some_check2', sql`'test' < 100`), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'create_check_constraint', + tableName: 'test', + schema: '', + data: 'some_check1;"test"."values" < 100', + }, + { + data: "some_check2;'test' < 100", + schema: '', + tableName: 'test', + type: 'create_check_constraint', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "test" ADD CONSTRAINT "some_check1" CHECK ("test"."values" < 100);', + `ALTER TABLE "test" ADD CONSTRAINT "some_check2" CHECK ('test' < 100);`, + ]); +}); + +test('drop check constraint', async () => { + const client = new PGlite(); + + const schema1 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').default(1), + }, (table) => ({ + checkConstraint: check('some_check', sql`${table.values} < 100`), + })), + }; + const schema2 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').default(1), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'delete_check_constraint', + tableName: 'test', + schema: '', + data: 'some_check', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "test" DROP CONSTRAINT "some_check";', + ]); +}); + +test('db has checks. Push with same names', async () => { + const client = new PGlite(); + + const schema1 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').default(1), + }, (table) => ({ + checkConstraint: check('some_check', sql`${table.values} < 100`), + })), + }; + const schema2 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').default(1), + }, (table) => ({ + checkConstraint: check('some_check', sql`some new value`), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); +}); From 8cf7a6104e23c3d619b2dae989e63956cb8e7d24 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Thu, 5 Sep 2024 16:26:58 +0300 Subject: [PATCH 145/492] Fixed neon-http, planetscale; removed leftover lines; switched sqlite to session-based count --- drizzle-orm/src/mysql-core/query-builders/count.ts | 4 +--- drizzle-orm/src/neon-http/session.ts | 4 ++-- drizzle-orm/src/pg-core/query-builders/count.ts | 4 +--- drizzle-orm/src/planetscale-serverless/session.ts | 8 ++++++++ drizzle-orm/src/sqlite-core/query-builders/count.ts | 2 +- drizzle-orm/src/sqlite-core/session.ts | 6 ++++++ 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index 4e734135f..645bb4753 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -52,9 +52,7 @@ export class MySqlCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.count(this.sql)).then((it) => { - return it; - }) + return Promise.resolve(this.session.count(this.sql)) .then( onfulfilled, onrejected, diff --git a/drizzle-orm/src/neon-http/session.ts b/drizzle-orm/src/neon-http/session.ts index a36b7222b..4dd768d3e 100644 --- a/drizzle-orm/src/neon-http/session.ts +++ b/drizzle-orm/src/neon-http/session.ts @@ -162,10 +162,10 @@ export class NeonHttpSession< } override async count(sql: SQL): Promise { - const res = await this.execute<[{ count: string }]>(sql); + const res = await this.execute<{ rows: [{ count: string }] }>(sql); return Number( - res[0]['count'], + res['rows'][0]['count'], ); } diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index 6867b0950..c93cbb18d 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -51,9 +51,7 @@ export class PgCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.count(this.sql)).then((it) => { - return it; - }) + return Promise.resolve(this.session.count(this.sql)) .then( onfulfilled, onrejected, diff --git a/drizzle-orm/src/planetscale-serverless/session.ts b/drizzle-orm/src/planetscale-serverless/session.ts index f2275b7f2..987529d7c 100644 --- a/drizzle-orm/src/planetscale-serverless/session.ts +++ b/drizzle-orm/src/planetscale-serverless/session.ts @@ -164,6 +164,14 @@ export class PlanetscaleSession< ) => eQuery.rows as T[]); } + override async count(sql: SQL): Promise { + const res = await this.execute<{ rows: [{ count: string }] }>(sql); + + return Number( + res['rows'][0]['count'], + ); + } + override transaction( transaction: (tx: PlanetScaleTransaction) => Promise, ): Promise { diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index 073562b8b..1b19eed07 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -50,7 +50,7 @@ export class SQLiteCountBuilder< onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.values<[[number]]>(this.sql)).then((it) => it[0][0]).then( + return Promise.resolve(this.session.count(this.sql)).then( onfulfilled, onrejected, ); diff --git a/drizzle-orm/src/sqlite-core/session.ts b/drizzle-orm/src/sqlite-core/session.ts index 4ac987b4a..d291b6fdf 100644 --- a/drizzle-orm/src/sqlite-core/session.ts +++ b/drizzle-orm/src/sqlite-core/session.ts @@ -187,6 +187,12 @@ export abstract class SQLiteSession< >; } + async count(sql: SQL) { + const result = await this.values(sql) as [[number]]; + + return result[0][0]; + } + /** @internal */ extractRawValuesValueFromBatchResult(_result: unknown): unknown { throw new Error('Not implemented'); From d5c11a47f5401dcdb40fe66470d2014af8b7d241 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 5 Sep 2024 17:34:50 +0300 Subject: [PATCH 146/492] changed console.log outputs for connection to Sqlite returned removed console.log in mysql push --- drizzle-kit/src/cli/commands/push.ts | 1 + drizzle-kit/src/cli/connections.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 2d3df5fba..404000608 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -70,6 +70,7 @@ export const mysqlPush = async ( }); if (verbose) { + console.log(); console.log( withStyle.warning('You are about to execute current statements:'), ); diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 7d4435b55..6c4b44634 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -670,7 +670,7 @@ export const connectToSQLite = async ( } console.log( - "Please install 'better-sqlite3' for Drizzle Kit to connect to SQLite databases", + "Please install either 'better-sqlite3' or '@libsql/client' for Drizzle Kit to connect to SQLite databases", ); process.exit(1); }; From fe0c760ad8eaff3891b3c0a2c8834a68e42ba800 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 6 Sep 2024 16:02:15 +0300 Subject: [PATCH 147/492] Add draft for beta release --- changelogs/drizzle-kit/0.25.0.md | 0 changelogs/drizzle-orm/0.34.0.md | 141 +++++++++++++++++++ drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- integration-tests/tests/pg/awsdatapi.test.ts | 14 +- integration-tests/tests/pg/neon-http.test.ts | 14 +- integration-tests/tests/pg/pg-common.ts | 8 +- integration-tests/tests/pg/vercel-pg.test.ts | 14 +- 8 files changed, 168 insertions(+), 27 deletions(-) create mode 100644 changelogs/drizzle-kit/0.25.0.md create mode 100644 changelogs/drizzle-orm/0.34.0.md diff --git a/changelogs/drizzle-kit/0.25.0.md b/changelogs/drizzle-kit/0.25.0.md new file mode 100644 index 000000000..e69de29bb diff --git a/changelogs/drizzle-orm/0.34.0.md b/changelogs/drizzle-orm/0.34.0.md new file mode 100644 index 000000000..4ceb1a630 --- /dev/null +++ b/changelogs/drizzle-orm/0.34.0.md @@ -0,0 +1,141 @@ +// Libsql and Sqlite migration updates + +SQLite generate statements updates. Starting from this release, we won't generate comments like this: + +```sql + '/*\n SQLite does not support "Changing existing column type" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' +``` + +We will generate a set of statements instead and you will decide if it's good to make data moving statements instead. Here is an example of generated sql file you'll get now: + +```sql +``` + +LibSQL generate statements updates. As long as libsql support more alter statements than SQLite we can generate more statements without recreating you schema and moving all the data, which can be potentially dangeourose for production envs + +LibSQL and Turso will now get a separate dialect in drizzle config file, means, that we will evolve Turso and LibSQL separately from SQLite and will try to support as much features Turso/LibSQL would have as possible + +Breaking change! All the users, who wants to get max from Turso and LibSQL DDL statements, shouls remove `driver: turso` from drizzle.config and add `dialect: turso` instead + +With updated LibSQL migrartion staretegy you would have a possibility to: + +- **Change Data Type**: You can set a new data type for existing columns. +- **Set and Drop Default Values**: You can add or remove default values for existing columns. +- **Set and Drop Not Null Constraint**: You can add or remov the `NOT NULL` constraint on existing columns. +- **Add References to Existing Columns**: You can add foreign key references to existing columns. + + +### Code Example: + +```sql +PRAGMA foreign_keys=OFF; + +CREATE TABLE `__new_table` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `name` text NOT NULL +); + +INSERT INTO `__new_table`("id", "name") SELECT "id", "name" FROM `table`; + +DROP TABLE `table`; + +ALTER TABLE `__new_table` RENAME TO `table`; + +PRAGMA foreign_keys=ON; +``` + +### LIMITATIONS + +- Dropping or altering index will cause table recreation + +This is because LibSQL does not support dropping this type of index: + +```sql +CREATE TABLE `users` ( + `id` integer NOT NULL, + `name` integer, + `age` integer PRIMARY KEY NOT NULL + FOREIGN KEY (`name`) REFERENCES `users1`("id") ON UPDATE no action ON DELETE no action +); +``` + +- If the table has indexes, altering columns will cause table recreation. + Drizzle-Kit will drop those indexes, modify the columns, and then recreate the indexes. +- Adding or dropping `composite foreign keys` is not supported and will cause table recreation. + +### NOTES: + +- You can create reference on any column type, but if you want to insert values than primary column should have unique index or primary key + +```sql +CREATE TABLE parent(a PRIMARY KEY, b UNIQUE, c, d, e, f); +CREATE UNIQUE INDEX i1 ON parent(c, d); +CREATE INDEX i2 ON parent(e); +CREATE UNIQUE INDEX i3 ON parent(f COLLATE nocase); + +CREATE TABLE child1(f, g REFERENCES parent(a)); -- Ok +CREATE TABLE child2(h, i REFERENCES parent(b)); -- Ok +CREATE TABLE child3(j, k, FOREIGN KEY(j, k) REFERENCES parent(c, d)); -- Ok +CREATE TABLE child4(l, m REFERENCES parent(e)); -- Error! +CREATE TABLE child5(n, o REFERENCES parent(f)); -- Error! +CREATE TABLE child6(p, q, FOREIGN KEY(p, q) REFERENCES parent(b, c)); -- Error! +CREATE TABLE child7(r REFERENCES parent(c)); -- Error! +``` + +> NOTE: The foreign key for table *child5* is an error because even though the parent key column has a unique index, the index uses a different collating sequence + +See more: https://www.sqlite.org/foreignkeys.html + +// monodriver + +before on example with node-postgres + +```ts +const client = new Pool({ url: '' }); +drizzle(client, { logger: true }); +``` + +will become + +```ts +await drizzle('', { client: '', logger: true }) +await drizzle('', { client: {}, logger: true }) +``` + +> Note that first example with client is still available and not deprecated. You ca use it, if you don't want to await drizzle object. New way of defining drizzle is done to make it easiser to import from 1 place and get an autocmplete with all the possible clients + +// db count feature + +to count entities in table you would need to do this +```ts +const res = await db.select({ count: sql`count(*)` }).from(users); +const count = res[0].count; +``` + +a new api will look like +```ts +// how many users are in the database +const count: number = await db.$count(users); + +// how many users with the name "Dan" are in the database +const count: number = await db.$count(users, eq(name, "Dan")); +``` + +This can also work as a subquery and inside relational queries +```ts +const users = await db.select({ + ...users, + postsCount: db.$count(posts, eq(posts.authorId, users.id)) +}); + +const users = await db.query.users.findMany({ + extras: { + postsCount: db.$count(posts, eq(posts.authorId, users.id)) + } +}) +``` diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 75c3d65dc..66f19e6be 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.24.2", + "version": "0.25.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 11970a77e..333521a48 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.33.0", + "version": "0.34.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { diff --git a/integration-tests/tests/pg/awsdatapi.test.ts b/integration-tests/tests/pg/awsdatapi.test.ts index 8ee39cf12..3bb884c0c 100644 --- a/integration-tests/tests/pg/awsdatapi.test.ts +++ b/integration-tests/tests/pg/awsdatapi.test.ts @@ -799,19 +799,18 @@ test('migrator : default migration strategy', async () => { }); test('migrator : migrate with custom schema', async () => { - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); await migrate(db, { migrationsFolder: './drizzle2/pg', - migrationsSchema: customSchema, + migrationsSchema: 'custom_migrations', }); // test if the custom migrations table was created const { rows } = await db.execute( - sql`select * from ${sql.identifier(customSchema)}."__drizzle_migrations";`, + sql`select * from custom_migrations."__drizzle_migrations";`, ); expect(rows).toBeTruthy(); expect(rows!.length).toBeGreaterThan(0); @@ -824,7 +823,7 @@ test('migrator : migrate with custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); await db.execute( - sql`drop table ${sql.identifier(customSchema)}."__drizzle_migrations"`, + sql`drop table custom_migrations."__drizzle_migrations"`, ); }); @@ -858,7 +857,6 @@ test('migrator : migrate with custom table', async () => { test('migrator : migrate with custom table and custom schema', async () => { const customTable = randomString(); - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); @@ -866,12 +864,12 @@ test('migrator : migrate with custom table and custom schema', async () => { await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsTable: customTable, - migrationsSchema: customSchema, + migrationsSchema: 'custom_migrations', }); // test if the custom migrations table was created const { rows } = await db.execute( - sql`select * from ${sql.identifier(customSchema)}.${ + sql`select * from custom_migrations.${ sql.identifier( customTable, ) @@ -888,7 +886,7 @@ test('migrator : migrate with custom table and custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); await db.execute( - sql`drop table ${sql.identifier(customSchema)}.${ + sql`drop table custom_migrations.${ sql.identifier( customTable, ) diff --git a/integration-tests/tests/pg/neon-http.test.ts b/integration-tests/tests/pg/neon-http.test.ts index 1476e9628..319c84f40 100644 --- a/integration-tests/tests/pg/neon-http.test.ts +++ b/integration-tests/tests/pg/neon-http.test.ts @@ -68,15 +68,14 @@ test('migrator : default migration strategy', async () => { }); test('migrator : migrate with custom schema', async () => { - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); - await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsSchema: customSchema }); + await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsSchema: 'custom_migrations' }); // test if the custom migrations table was created - const { rowCount } = await db.execute(sql`select * from ${sql.identifier(customSchema)}."__drizzle_migrations";`); + const { rowCount } = await db.execute(sql`select * from custom_migrations."__drizzle_migrations";`); expect(rowCount && rowCount > 0).toBeTruthy(); // test if the migrated table are working as expected @@ -86,7 +85,7 @@ test('migrator : migrate with custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); - await db.execute(sql`drop table ${sql.identifier(customSchema)}."__drizzle_migrations"`); + await db.execute(sql`drop table custom_migrations."__drizzle_migrations"`); }); test('migrator : migrate with custom table', async () => { @@ -113,7 +112,6 @@ test('migrator : migrate with custom table', async () => { test('migrator : migrate with custom table and custom schema', async () => { const customTable = randomString(); - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); @@ -121,12 +119,12 @@ test('migrator : migrate with custom table and custom schema', async () => { await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsTable: customTable, - migrationsSchema: customSchema, + migrationsSchema: 'custom_migrations', }); // test if the custom migrations table was created const { rowCount } = await db.execute( - sql`select * from ${sql.identifier(customSchema)}.${sql.identifier(customTable)};`, + sql`select * from custom_migrations.${sql.identifier(customTable)};`, ); expect(rowCount && rowCount > 0).toBeTruthy(); @@ -137,7 +135,7 @@ test('migrator : migrate with custom table and custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); - await db.execute(sql`drop table ${sql.identifier(customSchema)}.${sql.identifier(customTable)}`); + await db.execute(sql`drop table custom_migrations.${sql.identifier(customTable)}`); }); test('all date and time columns without timezone first case mode string', async () => { diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index b4afdcf64..8550f5ae4 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -74,7 +74,7 @@ import { } from 'drizzle-orm/pg-core'; import getPort from 'get-port'; import { v4 as uuidV4 } from 'uuid'; -import { afterAll, beforeEach, describe, expect, test } from 'vitest'; +import { afterAll, afterEach, beforeEach, describe, expect, test } from 'vitest'; import { Expect } from '~/utils'; import type { schema } from './neon-http-batch.test'; // eslint-disable-next-line @typescript-eslint/no-import-type-side-effects @@ -246,6 +246,7 @@ export function tests() { await db.execute(sql`drop schema if exists public cascade`); await db.execute(sql`drop schema if exists ${mySchema} cascade`); await db.execute(sql`create schema public`); + await db.execute(sql`create schema if not exists custom_migrations`); await db.execute(sql`create schema ${mySchema}`); // public users await db.execute( @@ -377,6 +378,11 @@ export function tests() { ); }); + afterEach(async (ctx) => { + const { db } = ctx.pg; + await db.execute(sql`drop schema if exists custom_migrations cascade`); + }); + async function setupSetOperationTest(db: PgDatabase) { await db.execute(sql`drop table if exists users2`); await db.execute(sql`drop table if exists cities`); diff --git a/integration-tests/tests/pg/vercel-pg.test.ts b/integration-tests/tests/pg/vercel-pg.test.ts index 3f1248d9b..ecf1d22ac 100644 --- a/integration-tests/tests/pg/vercel-pg.test.ts +++ b/integration-tests/tests/pg/vercel-pg.test.ts @@ -77,15 +77,14 @@ test('migrator : default migration strategy', async () => { }); test('migrator : migrate with custom schema', async () => { - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); - await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsSchema: customSchema }); + await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsSchema: 'custom_migrations' }); // test if the custom migrations table was created - const { rowCount } = await db.execute(sql`select * from ${sql.identifier(customSchema)}."__drizzle_migrations";`); + const { rowCount } = await db.execute(sql`select * from custom_migrations."__drizzle_migrations";`); expect(rowCount && rowCount > 0).toBeTruthy(); // test if the migrated table are working as expected @@ -95,7 +94,7 @@ test('migrator : migrate with custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); - await db.execute(sql`drop table ${sql.identifier(customSchema)}."__drizzle_migrations"`); + await db.execute(sql`drop table custom_migrations."__drizzle_migrations"`); }); test('migrator : migrate with custom table', async () => { @@ -122,7 +121,6 @@ test('migrator : migrate with custom table', async () => { test('migrator : migrate with custom table and custom schema', async () => { const customTable = randomString(); - const customSchema = randomString(); await db.execute(sql`drop table if exists all_columns`); await db.execute(sql`drop table if exists users12`); await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); @@ -130,12 +128,12 @@ test('migrator : migrate with custom table and custom schema', async () => { await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsTable: customTable, - migrationsSchema: customSchema, + migrationsSchema: 'custom_migrations', }); // test if the custom migrations table was created const { rowCount } = await db.execute( - sql`select * from ${sql.identifier(customSchema)}.${sql.identifier(customTable)};`, + sql`select * from custom_migrations.${sql.identifier(customTable)};`, ); expect(rowCount && rowCount > 0).toBeTruthy(); @@ -146,7 +144,7 @@ test('migrator : migrate with custom table and custom schema', async () => { await db.execute(sql`drop table all_columns`); await db.execute(sql`drop table users12`); - await db.execute(sql`drop table ${sql.identifier(customSchema)}.${sql.identifier(customTable)}`); + await db.execute(sql`drop table custom_migrations.${sql.identifier(customTable)}`); }); test('all date and time columns without timezone first case mode string', async () => { From 7075a0fe7693745fa5ce4bf348fd18ca3f01dd78 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Fri, 6 Sep 2024 16:16:36 +0300 Subject: [PATCH 148/492] added check constraints to mysql added some tests --- drizzle-kit/src/introspect-mysql.ts | 29 +++ drizzle-kit/src/jsonDiffer.js | 27 +++ drizzle-kit/src/jsonStatements.ts | 11 +- drizzle-kit/src/serializer/mysqlSchema.ts | 22 +- drizzle-kit/src/serializer/mysqlSerializer.ts | 72 +++++++ drizzle-kit/src/snapshotsDiffer.ts | 44 +++- drizzle-kit/src/sqlgenerator.ts | 43 +++- drizzle-kit/tests/introspect/pg.test.ts | 82 ------- drizzle-kit/tests/push/mysql-push.test.ts | 202 ++++++++++++++++++ drizzle-kit/tests/schemaDiffer.ts | 14 -- 10 files changed, 435 insertions(+), 111 deletions(-) create mode 100644 drizzle-kit/tests/push/mysql-push.test.ts diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index f206935a3..39c26f93c 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -2,6 +2,7 @@ import './@types/utils'; import type { Casing } from './cli/validations/common'; import { + CheckConstraint, Column, ForeignKey, Index, @@ -142,11 +143,15 @@ export const schemaToTypeScript = ( const uniqueImports = Object.values(it.uniqueConstraints).map( (it) => 'unique', ); + const checkImports = Object.values(it.checkConstraint).map( + (it) => 'check', + ); res.mysql.push(...idxImports); res.mysql.push(...fkImpots); res.mysql.push(...pkImports); res.mysql.push(...uniqueImports); + res.mysql.push(...checkImports); const columnImports = Object.values(it.columns) .map((col) => { @@ -203,6 +208,7 @@ export const schemaToTypeScript = ( || filteredFKs.length > 0 || Object.keys(table.compositePrimaryKeys).length > 0 || Object.keys(table.uniqueConstraints).length > 0 + || Object.keys(table.checkConstraint).length > 0 ) { statement += ',\n'; statement += '(table) => {\n'; @@ -221,6 +227,10 @@ export const schemaToTypeScript = ( Object.values(table.uniqueConstraints), withCasing, ); + statement += createTableChecks( + Object.values(table.checkConstraint), + withCasing, + ); statement += '\t}\n'; statement += '}'; } @@ -816,6 +826,25 @@ const createTableUniques = ( return statement; }; +const createTableChecks = ( + checks: CheckConstraint[], + casing: (value: string) => string, +): string => { + let statement = ''; + + checks.forEach((it) => { + const checkKey = casing(it.name); + + statement += `\t\t${checkKey}: `; + statement += 'check('; + statement += `"${it.name}", `; + statement += `sql\`${it.value.replace(/`/g, '\\`')}\`)`; + statement += `,\n`; + }); + + return statement; +}; + const createTablePKs = ( pks: PrimaryKey[], casing: (value: string) => string, diff --git a/drizzle-kit/src/jsonDiffer.js b/drizzle-kit/src/jsonDiffer.js index 1ca195c85..7ef6515f6 100644 --- a/drizzle-kit/src/jsonDiffer.js +++ b/drizzle-kit/src/jsonDiffer.js @@ -654,6 +654,33 @@ const alternationsInColumn = (column) => { } return it; }) + .map((it) => { + if ('' in it) { + return { + ...it, + autoincrement: { + type: 'changed', + old: it.autoincrement.__old, + new: it.autoincrement.__new, + }, + }; + } + if ('autoincrement__added' in it) { + const { autoincrement__added, ...others } = it; + return { + ...others, + autoincrement: { type: 'added', value: it.autoincrement__added }, + }; + } + if ('autoincrement__deleted' in it) { + const { autoincrement__deleted, ...others } = it; + return { + ...others, + autoincrement: { type: 'deleted', value: it.autoincrement__deleted }, + }; + } + return it; + }) .filter(Boolean); return result[0]; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 8e86be09e..6bdaf059d 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -245,7 +245,7 @@ export interface JsonCreateCheckConstraint { export interface JsonDeleteCheckConstraint { type: 'delete_check_constraint'; tableName: string; - data: string; + constraintName: string; schema?: string; } @@ -637,7 +637,7 @@ export const prepareMySqlCreateTableJson = ( // if previously it was an expression or column internals: MySqlKitInternals, ): JsonCreateTableStatement => { - const { name, schema, columns, compositePrimaryKeys, uniqueConstraints } = table; + const { name, schema, columns, compositePrimaryKeys, uniqueConstraints, checkConstraints } = table; return { type: 'create_table', @@ -653,6 +653,7 @@ export const prepareMySqlCreateTableJson = ( : '', uniqueConstraints: Object.values(uniqueConstraints), internals, + checkConstraints: Object.values(checkConstraints), }; }; @@ -2349,7 +2350,7 @@ export const prepareDeleteUniqueConstraintPg = ( }); }; -export const prepareAddCheckConstraintPg = ( +export const prepareAddCheckConstraint = ( tableName: string, schema: string, check: Record, @@ -2364,7 +2365,7 @@ export const prepareAddCheckConstraintPg = ( }); }; -export const prepareDeleteCheckConstraintPg = ( +export const prepareDeleteCheckConstraint = ( tableName: string, schema: string, check: Record, @@ -2373,7 +2374,7 @@ export const prepareDeleteCheckConstraintPg = ( return { type: 'delete_check_constraint', tableName, - data: PgSquasher.unsquashCheck(it).name, // only name needed + constraintName: PgSquasher.unsquashCheck(it).name, schema, } as JsonDeleteCheckConstraint; }); diff --git a/drizzle-kit/src/serializer/mysqlSchema.ts b/drizzle-kit/src/serializer/mysqlSchema.ts index 5bc62ab2f..731fd579b 100644 --- a/drizzle-kit/src/serializer/mysqlSchema.ts +++ b/drizzle-kit/src/serializer/mysqlSchema.ts @@ -1,5 +1,5 @@ import { any, boolean, enum as enumType, literal, object, record, string, TypeOf, union } from 'zod'; -import { mapValues, originUUID, snapshotVersion } from '../global'; +import { mapValues, originUUID } from '../global'; // ------- V3 -------- const index = object({ @@ -52,6 +52,11 @@ const uniqueConstraint = object({ columns: string().array(), }).strict(); +const checkConstraint = object({ + name: string(), + value: string(), +}).strict(); + const tableV4 = object({ name: string(), schema: string().optional(), @@ -67,6 +72,7 @@ const table = object({ foreignKeys: record(string(), fk), compositePrimaryKeys: record(string(), compositePK), uniqueConstraints: record(string(), uniqueConstraint).default({}), + checkConstraint: record(string(), checkConstraint).default({}), }).strict(); export const kitInternals = object({ @@ -186,6 +192,7 @@ export type Index = TypeOf; export type ForeignKey = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; +export type CheckConstraint = TypeOf; export const MySqlSquasher = { squashIdx: (idx: Index) => { @@ -247,6 +254,14 @@ export const MySqlSquasher = { }); return result; }, + squashCheck: (input: CheckConstraint): string => { + return `${input.name};${input.value}`; + }, + unsquashCheck: (input: string): CheckConstraint => { + const [name, value] = input.split(';'); + + return { name, value }; + }, }; export const squashMysqlSchemeV4 = ( @@ -304,6 +319,10 @@ export const squashMysqlScheme = (json: MySqlSchema): MySqlSchemaSquashed => { }, ); + const squashedCheckConstraints = mapValues(it[1].checkConstraint, (check) => { + return MySqlSquasher.squashCheck(check); + }); + return [ it[0], { @@ -313,6 +332,7 @@ export const squashMysqlScheme = (json: MySqlSchema): MySqlSchemaSquashed => { foreignKeys: squashedFKs, compositePrimaryKeys: squashedPKs, uniqueConstraints: squashedUniqueConstraints, + checkConstraints: squashedCheckConstraints, }, ]; }), diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 14e867128..a5bdf7c6f 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -7,6 +7,7 @@ import { RowDataPacket } from 'mysql2/promise'; import { withStyle } from '../cli/validations/outputs'; import { IntrospectStage, IntrospectStatus } from '../cli/views'; import { + CheckConstraint, Column, ForeignKey, Index, @@ -39,14 +40,20 @@ export const generateMySqlSnapshot = ( indexes, foreignKeys, schema, + checks, primaryKeys, uniqueConstraints, } = getTableConfig(table); + const columnsObject: Record = {}; const indexesObject: Record = {}; const foreignKeysObject: Record = {}; const primaryKeysObject: Record = {}; const uniqueConstraintObject: Record = {}; + const checkConstraintObject: Record = {}; + + // this object will help to identify same check names + let checksInTable: Record = {}; columns.forEach((column) => { const notNull: boolean = column.notNull; @@ -322,6 +329,39 @@ export const generateMySqlSnapshot = ( }; }); + checks.forEach((check) => { + check; + const checkName = check.name; + if (typeof checksInTable[tableName] !== 'undefined') { + if (checksInTable[tableName].includes(check.name)) { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated check constraint name in ${ + chalk.underline.blue( + tableName, + ) + }. Please rename your check constraint in the ${ + chalk.underline.blue( + tableName, + ) + } table`, + ) + }`, + ); + process.exit(1); + } + checksInTable[tableName].push(checkName); + } else { + checksInTable[tableName] = [check.name]; + } + + checkConstraintObject[checkName] = { + name: checkName, + value: dialect.sqlToQuery(check.value).sql, + }; + }); + // only handle tables without schemas if (!schema) { result[tableName] = { @@ -331,6 +371,7 @@ export const generateMySqlSnapshot = ( foreignKeys: foreignKeysObject, compositePrimaryKeys: primaryKeysObject, uniqueConstraints: uniqueConstraintObject, + checkConstraint: checkConstraintObject, }; } } @@ -536,6 +577,7 @@ export const fromDatabase = async ( indexes: {}, foreignKeys: {}, uniqueConstraints: {}, + checkConstraint: {}, }; } else { result[tableName]!.columns[columnName] = newColumn; @@ -715,6 +757,36 @@ export const fromDatabase = async ( progressCallback('enums', 0, 'done'); } + const checkConstraints = await db.query( + `SELECT + tc.table_name, + tc.constraint_name, + cc.check_clause +FROM + information_schema.table_constraints tc +JOIN + information_schema.check_constraints cc + ON tc.constraint_name = cc.constraint_name +WHERE + tc.constraint_schema = '${inputSchema}' +AND + tc.constraint_type = 'CHECK';`, + ); + + for (const checkConstraintRow of checkConstraints) { + const constraintName = checkConstraintRow['CONSTRAINT_NAME']; + const constraintValue = checkConstraintRow['CHECK_CLAUSE']; + const tableName = checkConstraintRow['TABLE_NAME']; + + const tableInResult = result[tableName]; + // if (typeof tableInResult === 'undefined') continue; + + tableInResult.checkConstraint[constraintName] = { + name: constraintName, + value: constraintValue, + }; + } + return { version: '5', dialect: 'mysql', diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 1702c5e1d..5ef68153a 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -36,7 +36,7 @@ import { JsonRenameColumnStatement, JsonSqliteAddColumnStatement, JsonStatement, - prepareAddCheckConstraintPg, + prepareAddCheckConstraint, prepareAddCompositePrimaryKeyMySql, prepareAddCompositePrimaryKeyPg, prepareAddCompositePrimaryKeySqlite, @@ -53,7 +53,7 @@ import { prepareCreateReferencesJson, prepareCreateSchemasJson, prepareCreateSequenceJson, - prepareDeleteCheckConstraintPg, + prepareDeleteCheckConstraint, prepareDeleteCompositePrimaryKeyMySql, prepareDeleteCompositePrimaryKeyPg, prepareDeleteCompositePrimaryKeySqlite, @@ -892,8 +892,8 @@ export const applyPgSnapshotsDiff = async ( ); } - createCheckConstraints = prepareAddCheckConstraintPg(it.name, it.schema, it.addedCheckConstraints); - deleteCheckConstraints = prepareDeleteCheckConstraintPg( + createCheckConstraints = prepareAddCheckConstraint(it.name, it.schema, it.addedCheckConstraints); + deleteCheckConstraints = prepareDeleteCheckConstraint( it.name, it.schema, it.deletedCheckConstraints, @@ -907,8 +907,8 @@ export const applyPgSnapshotsDiff = async ( added[k] = it.alteredCheckConstraints[k].__new; deleted[k] = it.alteredCheckConstraints[k].__old; } - createCheckConstraints.push(...prepareAddCheckConstraintPg(it.name, it.schema, added)); - deleteCheckConstraints.push(...prepareDeleteCheckConstraintPg(it.name, it.schema, deleted)); + createCheckConstraints.push(...prepareAddCheckConstraint(it.name, it.schema, added)); + deleteCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); } jsonCreatedCheckConstraints.push(...createCheckConstraints); @@ -1436,6 +1436,9 @@ export const applyMysqlSnapshotsDiff = async ( const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + const jsonAddedCheckConstraints: JsonCreateCheckConstraint[] = []; + const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames .map((it) => prepareRenameColumns(it.table, '', it.renames)) .flat(); @@ -1497,6 +1500,9 @@ export const applyMysqlSnapshotsDiff = async ( let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + let createdCheckConstraints: JsonCreateCheckConstraint[] = []; + let deletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + addedUniqueConstraints = prepareAddUniqueConstraint( it.name, it.schema, @@ -1522,6 +1528,26 @@ export const applyMysqlSnapshotsDiff = async ( ); } + createdCheckConstraints = prepareAddCheckConstraint(it.name, it.schema, it.addedCheckConstraints); + deletedCheckConstraints = prepareDeleteCheckConstraint( + it.name, + it.schema, + it.deletedCheckConstraints, + ); + + // skip for push + if (it.alteredCheckConstraints && action !== 'push') { + const added: Record = {}; + const deleted: Record = {}; + + for (const k of Object.keys(it.alteredCheckConstraints)) { + added[k] = it.alteredCheckConstraints[k].__new; + deleted[k] = it.alteredCheckConstraints[k].__old; + } + createdCheckConstraints.push(...prepareAddCheckConstraint(it.name, it.schema, added)); + deletedCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); + } + jsonAddedCompositePKs.push(...addedCompositePKs); jsonDeletedCompositePKs.push(...deletedCompositePKs); jsonAlteredCompositePKs.push(...alteredCompositePKs); @@ -1529,6 +1555,9 @@ export const applyMysqlSnapshotsDiff = async ( jsonAddedUniqueConstraints.push(...addedUniqueConstraints); jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + + jsonAddedCheckConstraints.push(...createdCheckConstraints); + jsonDeletedCheckConstraints.push(...deletedCheckConstraints); }); const rColumns = jsonRenameColumnsStatements.map((it) => { @@ -1663,6 +1692,9 @@ export const applyMysqlSnapshotsDiff = async ( jsonStatements.push(...jsonAddedUniqueConstraints); jsonStatements.push(...jsonDeletedUniqueConstraints); + jsonStatements.push(...jsonAddedCheckConstraints); + jsonStatements.push(...jsonDeletedCheckConstraints); + jsonStatements.push(...jsonAddColumnsStatemets); jsonStatements.push(...jsonCreateReferencesForCreatedTables); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index ec42eff9c..0ae0f782c 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -258,6 +258,7 @@ class MySqlCreateTableConvertor extends Convertor { tableName, columns, schema, + checkConstraints, compositePKs, uniqueConstraints, internals, @@ -318,6 +319,15 @@ class MySqlCreateTableConvertor extends Convertor { } } + if (typeof checkConstraints !== 'undefined' && checkConstraints.length > 0) { + for (const checkConstraint of checkConstraints) { + statement += ',\n'; + const unsquashedCheck = MySqlSquasher.unsquashCheck(checkConstraint); + + statement += `\tCONSTRAINT \`${unsquashedCheck.name}\` CHECK(${unsquashedCheck.value})`; + } + } + statement += `\n);`; statement += `\n`; return statement; @@ -608,13 +618,11 @@ class PgAlterTableDeleteCheckConstraintConvertor extends Convertor { ); } convert(statement: JsonDeleteCheckConstraint): string { - const unsquashed = PgSquasher.unsquashCheck(statement.data); - const tableNameWithSchema = statement.schema ? `"${statement.schema}"."${statement.tableName}"` : `"${statement.tableName}"`; - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${unsquashed.name}";`; + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.constraintName}";`; } } @@ -642,6 +650,33 @@ class MySQLAlterTableDropUniqueConstraintConvertor extends Convertor { } } +class MySqlAlterTableAddCheckConstraintConvertor extends Convertor { + can(statement: JsonCreateCheckConstraint, dialect: Dialect): boolean { + return ( + statement.type === 'create_check_constraint' && dialect === 'mysql' + ); + } + convert(statement: JsonCreateCheckConstraint): string { + const unsquashed = MySqlSquasher.unsquashCheck(statement.data); + const { tableName } = statement; + + return `ALTER TABLE \`${tableName}\` ADD CONSTRAINT \`${unsquashed.name}\` CHECK (${unsquashed.value});`; + } +} + +class MySqlAlterTableDeleteCheckConstraintConvertor extends Convertor { + can(statement: JsonDeleteCheckConstraint, dialect: Dialect): boolean { + return ( + statement.type === 'delete_check_constraint' && dialect === 'mysql' + ); + } + convert(statement: JsonDeleteCheckConstraint): string { + const { tableName } = statement; + + return `ALTER TABLE \`${tableName}\` DROP CONSTRAINT \`${statement.constraintName}\`;`; + } +} + class CreatePgSequenceConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_sequence' && dialect === 'postgresql'; @@ -2566,6 +2601,8 @@ convertors.push(new PgAlterTableDropUniqueConstraintConvertor()); convertors.push(new PgAlterTableAddCheckConstraintConvertor()); convertors.push(new PgAlterTableDeleteCheckConstraintConvertor()); +convertors.push(new MySqlAlterTableAddCheckConstraintConvertor()); +convertors.push(new MySqlAlterTableDeleteCheckConstraintConvertor()); convertors.push(new MySQLAlterTableAddUniqueConstraintConvertor()); convertors.push(new MySQLAlterTableDropUniqueConstraintConvertor()); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index 542340fab..509411f84 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -406,85 +406,3 @@ test('introspect enum with similar name to native type', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); - -test('introspect check', async () => { - const client = new PGlite(); - - const schema = { - users: pgTable('users', { - id: serial('id').primaryKey().notNull(), - name: varchar('name').notNull(), - age: integer('age'), - }, (table) => ({ - minimumAgeCheck: check('public_users_minimum_age_check', sql`${table.age} > 21`), - })), - }; - - const { statements, sqlStatements } = await introspectPgToFile( - client, - schema, - 'introspect-check', - ); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); - -test('introspect check for different schema', async () => { - const client = new PGlite(); - - const schema2 = pgSchema('schema2'); - const schema = { - schema2, - users: schema2.table('users', { - id: serial('id').primaryKey().notNull(), - name: varchar('name').notNull(), - age: integer('age'), - }, (table) => ({ - minimumAgeCheck: check('schema2_users_minimum_age_check', sql`${table.age} > 21`), - })), - }; - - const { statements, sqlStatements } = await introspectPgToFile( - client, - schema, - 'introspect-check-for-different-schema', - ['schema2'], - ); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); - -test('introspect checks with same names across different schema', async () => { - const client = new PGlite(); - - const schema2 = pgSchema('schema2'); - const schema = { - schema2, - usersInSchema2: schema2.table('users', { - id: serial('id').primaryKey().notNull(), - name: varchar('name').notNull(), - age: integer('age'), - }, (table) => ({ - minimumAgeCheck: check('public_users_minimum_age_check', sql`${table.age} > 21`), - })), - usersInPublic: pgTable('users', { - id: serial('id').primaryKey().notNull(), - name: varchar('name').notNull(), - age: integer('age'), - }, (table) => ({ - minimumAgeCheck: check('public_users_minimum_age_check', sql`${table.age} > 21`), - })), - }; - - const { statements, sqlStatements } = await introspectPgToFile( - client, - schema, - 'introspect-checks-with-same-names-across-different-schema', - ['schema2', 'public'], - ); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); diff --git a/drizzle-kit/tests/push/mysql-push.test.ts b/drizzle-kit/tests/push/mysql-push.test.ts new file mode 100644 index 000000000..0f7863fa5 --- /dev/null +++ b/drizzle-kit/tests/push/mysql-push.test.ts @@ -0,0 +1,202 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import { check, int, mysqlTable } from 'drizzle-orm/mysql-core'; +import fs from 'fs'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { diffTestSchemasPushMysql } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, expect, test } from 'vitest'; + +let client: Connection; +let mysqlContainer: Docker.Container; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +beforeAll(async () => { + const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +if (!fs.existsSync('tests/push/mysql')) { + fs.mkdirSync('tests/push/mysql'); +} + +test('add check constraint to table', async () => { + const schema1 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + const schema2 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }, (table) => ({ + checkConstraint1: check('some_check1', sql`${table.values} < 100`), + checkConstraint2: check('some_check2', sql`'test' < 100`), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'create_check_constraint', + tableName: 'test', + schema: '', + data: 'some_check1;\`test\`.\`values\` < 100', + }, + { + data: "some_check2;'test' < 100", + schema: '', + tableName: 'test', + type: 'create_check_constraint', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE \`test\` ADD CONSTRAINT \`some_check1\` CHECK (\`test\`.\`values\` < 100);', + `ALTER TABLE \`test\` ADD CONSTRAINT \`some_check2\` CHECK ('test' < 100);`, + ]); + + await client.query(`DROP TABLE \`test\``); +}); + +test('drop check constraint to table', async () => { + const schema1 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }, (table) => ({ + checkConstraint1: check('some_check1', sql`${table.values} < 100`), + checkConstraint2: check('some_check2', sql`'test' < 100`), + })), + }; + const schema2 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'delete_check_constraint', + tableName: 'test', + schema: '', + constraintName: 'some_check1', + }, + { + constraintName: 'some_check2', + schema: '', + tableName: 'test', + type: 'delete_check_constraint', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE \`test\` DROP CONSTRAINT \`some_check1\`;', + `ALTER TABLE \`test\` DROP CONSTRAINT \`some_check2\`;`, + ]); + + await client.query(`DROP TABLE \`test\``); +}); + +test('db has checks. Push with same names', async () => { + const schema1 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values').default(1), + }, (table) => ({ + checkConstraint: check('some_check', sql`${table.values} < 100`), + })), + }; + const schema2 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values').default(1), + }, (table) => ({ + checkConstraint: check('some_check', sql`some new value`), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 3a2a47b6b..0b261f3da 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -982,13 +982,6 @@ export async function diffTestSchemasPushLibSQL( run: async (query: string) => { await client.execute(query); }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, }, undefined, ); @@ -1048,13 +1041,6 @@ export async function diffTestSchemasPushLibSQL( run: async (query: string) => { await client.execute(query); }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, }, statements, sn1, From 1a53914770052ec0dd7e26efbf25a824f1be6314 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Sat, 7 Sep 2024 10:53:31 +0300 Subject: [PATCH 149/492] Improved types optional params arg where connection isn ot required; fixed vercel instance asking for client --- drizzle-orm/src/monodriver.ts | 140 +++++++++++++++++++++++++--------- 1 file changed, 106 insertions(+), 34 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 0706f271a..bacdb9a90 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -9,7 +9,6 @@ import type { } from '@neondatabase/serverless'; import type { Client as PlanetscaleClient, Config as PlanetscaleConfig } from '@planetscale/database'; import type { Config as TiDBServerlessConfig, Connection as TiDBConnection } from '@tidbcloud/serverless'; -import type { QueryResult, QueryResultRow, VercelPool } from '@vercel/postgres'; import type { Database as BetterSQLite3Database, Options as BetterSQLite3Options } from 'better-sqlite3'; import type { Database as BunDatabase } from 'bun:sqlite'; import type { Pool as Mysql2Pool, PoolOptions as Mysql2Config } from 'mysql2'; @@ -83,8 +82,6 @@ type MonodriverNeonHttpConfig = { options?: NeonHttpConfig; }; -type VercelPrimitive = string | number | boolean | undefined | null; - type DatabaseClient = | 'node-postgres' | 'postgres-js' @@ -121,12 +118,7 @@ type ClientInstanceMap = { 'postgres-js': PostgresJsClient; 'neon-serverless': NeonServerlessPool; 'neon-http': NeonQueryFunction; - 'vercel-postgres': - & VercelPool - & (( - strings: TemplateStringsArray, - ...values: VercelPrimitive[] - ) => Promise>); + 'vercel-postgres': undefined; 'aws-data-api-pg': RDSDataClient; planetscale: PlanetscaleClient; mysql2: Mysql2Pool; @@ -150,9 +142,7 @@ type InitializerParams = { 'neon-http': { connection: MonodriverNeonHttpConfig; }; - 'vercel-postgres': { - connection: VercelPool; - }; + 'vercel-postgres': {}; 'aws-data-api-pg': { connection?: RDSConfig; }; @@ -205,21 +195,40 @@ export async function drizzle< TSchema extends Record = Record, >( client: TClient, - params: - & InitializerParams[TClient] - & (TClient extends 'mysql2' ? MySql2DrizzleConfig - : TClient extends 'aws-data-api-pg' ? DrizzleAwsDataApiPgConfig - : TClient extends 'neon-serverless' ? DrizzleConfig & { - ws?: any; - } - : DrizzleConfig), + ...params: TClient extends 'bun:sqlite' | 'better-sqlite3' ? ([ + [] | [ + ( + & InitializerParams[TClient] + & DrizzleConfig + ), + ] | [ + ':memory:', + ] | [ + (string & {}), + ], + ]) + : TClient extends 'vercel-postgres' ? ([] | [ + ( + & InitializerParams[TClient] + & DrizzleConfig + ), + ]) + : [ + ( + & InitializerParams[TClient] + & (TClient extends 'mysql2' ? MySql2DrizzleConfig + : TClient extends 'aws-data-api-pg' ? DrizzleAwsDataApiPgConfig + : TClient extends 'neon-serverless' ? DrizzleConfig & { + ws?: any; + } + : DrizzleConfig) + ), + ] ): Promise> { - const { connection, ws, ...drizzleConfig } = params as typeof params & { - ws?: any; - }; - switch (client) { case 'node-postgres': { + const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { Pool } = await import('pg').catch(() => importError('pg')); const { drizzle } = await import('./node-postgres'); const instance = new Pool(connection as NodePGPoolConfig); @@ -230,6 +239,8 @@ export async function drizzle< return db; } case 'aws-data-api-pg': { + const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { RDSDataClient } = await import('@aws-sdk/client-rds-data').catch(() => importError('@aws-sdk/client-rds-data') ); @@ -245,10 +256,23 @@ export async function drizzle< const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); const { drizzle } = await import('./better-sqlite3'); - if (typeof connection === 'object') { - const { filename, options } = connection as Exclude; + const paramType = typeof params[0]; + + if (paramType === 'object') { + const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + + if (typeof connection === 'object') { + const { filename, options } = connection as Exclude; - const instance = new Client(filename, options); + const instance = new Client(filename, options); + + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; + } + + const instance = new Client(connection); const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; @@ -256,9 +280,18 @@ export async function drizzle< return db; } - const instance = new Client(connection); + if (paramType === 'string') { + const instance = new Client(params[0] as string); - const db = drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance) as any; + db.$client = instance; + + return db; + } + + const instance = new Client(); + + const db = drizzle(instance) as any; db.$client = instance; return db; @@ -267,10 +300,23 @@ export async function drizzle< const { Database: Client } = await import('bun:sqlite').catch(() => importError('bun:sqlite')); const { drizzle } = await import('./bun-sqlite'); - if (typeof connection === 'object') { - const { filename, options } = connection as Exclude; + const paramType = typeof params[0]; + + if (paramType === 'object') { + const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; - const instance = new Client(filename, options); + if (typeof connection === 'object') { + const { filename, options } = connection as Exclude; + + const instance = new Client(filename, options); + + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; + } + + const instance = new Client(connection); const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; @@ -278,14 +324,25 @@ export async function drizzle< return db; } - const instance = new Client(connection); + if (paramType === 'string') { + const instance = new Client(params[0] as string); - const db = drizzle(instance, drizzleConfig) as any; + const db = drizzle(instance) as any; + db.$client = instance; + + return db; + } + + const instance = new Client(); + + const db = drizzle(instance) as any; db.$client = instance; return db; } case 'd1': { + const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { drizzle } = await import('./d1'); const db = drizzle(connection as D1Database, drizzleConfig) as any; @@ -294,6 +351,8 @@ export async function drizzle< return db; } case 'libsql': { + const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { createClient } = await import('@libsql/client').catch(() => importError('@libsql/client')); const { drizzle } = await import('./libsql'); const instance = createClient(connection as LibsqlConfig); @@ -304,6 +363,8 @@ export async function drizzle< return db; } case 'mysql2': { + const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { createPool } = await import('mysql2/promise').catch(() => importError('mysql2/promise')); const instance = createPool(connection as Mysql2Config); const { drizzle } = await import('./mysql2'); @@ -314,6 +375,8 @@ export async function drizzle< return db; } case 'neon-http': { + const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { neon } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); const { connectionString, options } = connection as MonodriverNeonHttpConfig; const { drizzle } = await import('./neon-http'); @@ -325,6 +388,8 @@ export async function drizzle< return db; } case 'neon-serverless': { + const { connection, ws, ...drizzleConfig } = params as any as { connection: any; ws: any } & DrizzleConfig; + const { Pool, neonConfig } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless') ); @@ -341,6 +406,8 @@ export async function drizzle< return db; } case 'planetscale': { + const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { Client } = await import('@planetscale/database').catch(() => importError('@planetscale/database')); const { drizzle } = await import('./planetscale-serverless'); const instance = new Client( @@ -353,6 +420,8 @@ export async function drizzle< return db; } case 'postgres-js': { + const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { default: client } = await import('postgres').catch(() => importError('postgres')); const { drizzle } = await import('./postgres-js'); const instance = client(connection as PostgresJSOptions>); @@ -363,6 +432,8 @@ export async function drizzle< return db; } case 'tidb-serverless': { + const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { connect } = await import('@tidbcloud/serverless').catch(() => importError('@tidbcloud/serverless')); const { drizzle } = await import('./tidb-serverless'); const instance = connect(connection as TiDBServerlessConfig); @@ -373,6 +444,7 @@ export async function drizzle< return db; } case 'vercel-postgres': { + const drizzleConfig = params[0] as DrizzleConfig | undefined; const { sql } = await import('@vercel/postgres').catch(() => importError('@vercel/postgres')); const { drizzle } = await import('./vercel-postgres'); From cbf2f07a81d41ca4215053c8d0f6cda35085b5e2 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Sat, 7 Sep 2024 13:54:27 +0300 Subject: [PATCH 150/492] Improved types, added `Turso` alias for `libsql` --- drizzle-orm/src/monodriver.ts | 223 ++++++++++++++++++++++------------ 1 file changed, 142 insertions(+), 81 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index bacdb9a90..c20cb9252 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -80,7 +80,7 @@ type BetterSQLite3DatabaseConfig = type MonodriverNeonHttpConfig = { connectionString: string; options?: NeonHttpConfig; -}; +} | string; type DatabaseClient = | 'node-postgres' @@ -93,6 +93,7 @@ type DatabaseClient = | 'mysql2' | 'tidb-serverless' | 'libsql' + | 'turso' | 'd1' | 'bun:sqlite' | 'better-sqlite3'; @@ -108,6 +109,7 @@ type ClientDrizzleInstanceMap> = { mysql2: MySql2Database; 'tidb-serverless': TiDBServerlessDatabase; libsql: LibSQLDatabase; + turso: LibSQLDatabase; d1: DrizzleD1Database; 'bun:sqlite': BunSQLiteDatabase; 'better-sqlite3': DrizzleBetterSQLite3Database; @@ -124,6 +126,7 @@ type ClientInstanceMap = { mysql2: Mysql2Pool; 'tidb-serverless': TiDBConnection; libsql: LibsqlClient; + turso: LibsqlClient; d1: D1Database; 'bun:sqlite': BunDatabase; 'better-sqlite3': BetterSQLite3Database; @@ -137,7 +140,7 @@ type InitializerParams = { connection: string | PostgresJSOptions>; }; 'neon-serverless': { - connection: NeonServerlessConfig; + connection?: NeonServerlessConfig; }; 'neon-http': { connection: MonodriverNeonHttpConfig; @@ -158,6 +161,9 @@ type InitializerParams = { libsql: { connection: LibsqlConfig; }; + turso: { + connection: LibsqlConfig; + }; d1: { connection: D1Database; }; @@ -195,7 +201,7 @@ export async function drizzle< TSchema extends Record = Record, >( client: TClient, - ...params: TClient extends 'bun:sqlite' | 'better-sqlite3' ? ([ + ...params: TClient extends 'bun:sqlite' | 'better-sqlite3' ? ( [] | [ ( & InitializerParams[TClient] @@ -205,49 +211,79 @@ export async function drizzle< ':memory:', ] | [ (string & {}), - ], - ]) + ] + ) : TClient extends 'vercel-postgres' ? ([] | [ ( & InitializerParams[TClient] & DrizzleConfig ), ]) + : TClient extends 'postgres-js' ? ( + [ + ( + & InitializerParams[TClient] + & DrizzleConfig + ), + ] | [ + string, + ] + ) + : TClient extends 'mysql2' ? ( + [ + ( + & InitializerParams[TClient] + & MySql2DrizzleConfig + ), + ] | [ + string, + ] + ) + : TClient extends 'aws-data-api-pg' ? [ + InitializerParams[TClient] & DrizzleAwsDataApiPgConfig, + ] + : TClient extends 'neon-serverless' ? ([ + InitializerParams[TClient] & DrizzleConfig & { + ws?: any; + }, + ] | []) + : TClient extends 'neon-http' ? ([ + InitializerParams[TClient] & DrizzleConfig, + ] | [ + string, + ]) : [ ( & InitializerParams[TClient] - & (TClient extends 'mysql2' ? MySql2DrizzleConfig - : TClient extends 'aws-data-api-pg' ? DrizzleAwsDataApiPgConfig - : TClient extends 'neon-serverless' ? DrizzleConfig & { - ws?: any; - } - : DrizzleConfig) + & DrizzleConfig ), ] ): Promise> { switch (client) { case 'node-postgres': { - const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { connection, ...drizzleConfig } = params[0] as { connection: NodePGPoolConfig } & DrizzleConfig; const { Pool } = await import('pg').catch(() => importError('pg')); const { drizzle } = await import('./node-postgres'); - const instance = new Pool(connection as NodePGPoolConfig); + const instance = new Pool(connection); const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; return db; } case 'aws-data-api-pg': { - const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { connection, ...drizzleConfig } = params[0] as + & { connection: RDSDataClientConfig | undefined } + & DrizzleAwsDataApiPgConfig; const { RDSDataClient } = await import('@aws-sdk/client-rds-data').catch(() => importError('@aws-sdk/client-rds-data') ); const { drizzle } = await import('./aws-data-api/pg'); - const instance = new RDSDataClient(connection as RDSDataClientConfig); - const db = drizzle(instance, drizzleConfig as any as DrizzleAwsDataApiPgConfig) as any; + const instance = connection ? new RDSDataClient(connection) : new RDSDataClient(); + const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; return db; @@ -256,16 +292,15 @@ export async function drizzle< const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); const { drizzle } = await import('./better-sqlite3'); - const paramType = typeof params[0]; - - if (paramType === 'object') { - const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as { + connection: BetterSQLite3DatabaseConfig; + } & DrizzleConfig; if (typeof connection === 'object') { - const { filename, options } = connection as Exclude; + const { filename, options } = connection; const instance = new Client(filename, options); - const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; @@ -273,24 +308,13 @@ export async function drizzle< } const instance = new Client(connection); - const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; return db; } - if (paramType === 'string') { - const instance = new Client(params[0] as string); - - const db = drizzle(instance) as any; - db.$client = instance; - - return db; - } - - const instance = new Client(); - + const instance = new Client(params[0]); const db = drizzle(instance) as any; db.$client = instance; @@ -300,16 +324,15 @@ export async function drizzle< const { Database: Client } = await import('bun:sqlite').catch(() => importError('bun:sqlite')); const { drizzle } = await import('./bun-sqlite'); - const paramType = typeof params[0]; - - if (paramType === 'object') { - const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as { + connection: BunSqliteDatabaseConfig | string | undefined; + } & DrizzleConfig; if (typeof connection === 'object') { - const { filename, options } = connection as Exclude; + const { filename, options } = connection; const instance = new Client(filename, options); - const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; @@ -317,127 +340,165 @@ export async function drizzle< } const instance = new Client(connection); - const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; return db; } - if (paramType === 'string') { - const instance = new Client(params[0] as string); - - const db = drizzle(instance) as any; - db.$client = instance; - - return db; - } - - const instance = new Client(); - + const instance = new Client(params[0]); const db = drizzle(instance) as any; db.$client = instance; return db; } case 'd1': { - const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { connection, ...drizzleConfig } = params[0] as { connection: D1Database } & DrizzleConfig; const { drizzle } = await import('./d1'); - const db = drizzle(connection as D1Database, drizzleConfig) as any; + const db = drizzle(connection, drizzleConfig) as any; db.$client = connection; return db; } - case 'libsql': { - const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + case 'libsql': + case 'turso': { + const { connection, ...drizzleConfig } = params[0] as any as { connection: LibsqlConfig } & DrizzleConfig; const { createClient } = await import('@libsql/client').catch(() => importError('@libsql/client')); const { drizzle } = await import('./libsql'); - const instance = createClient(connection as LibsqlConfig); + const instance = createClient(connection); const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; return db; } case 'mysql2': { - const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; - const { createPool } = await import('mysql2/promise').catch(() => importError('mysql2/promise')); - const instance = createPool(connection as Mysql2Config); const { drizzle } = await import('./mysql2'); - const db = drizzle(instance, drizzleConfig as MySql2DrizzleConfig) as any; + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as { connection: Mysql2Config } & MySql2DrizzleConfig; + + const instance = createPool(connection); + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; + } + + const connectionString = params[0]!; + const instance = createPool(connectionString); + + const db = drizzle(instance) as any; db.$client = instance; return db; } case 'neon-http': { - const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; - const { neon } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); - const { connectionString, options } = connection as MonodriverNeonHttpConfig; const { drizzle } = await import('./neon-http'); - const instance = neon(connectionString, options); - const db = drizzle(instance, drizzleConfig) as any; + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as { connection: MonodriverNeonHttpConfig } & DrizzleConfig; + + if (typeof connection === 'object') { + const { connectionString, options } = connection; + + const instance = neon(connectionString, options); + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; + } + + const instance = neon(connection); + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; + } + + const instance = neon(params[0]!); + const db = drizzle(instance) as any; db.$client = instance; return db; } case 'neon-serverless': { - const { connection, ws, ...drizzleConfig } = params as any as { connection: any; ws: any } & DrizzleConfig; - const { Pool, neonConfig } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless') ); const { drizzle } = await import('./neon-serverless'); - const instance = new Pool(connection as NeonServerlessConfig); + if (params[0]) { + const { connection, ws, ...drizzleConfig } = params[0] as { + connection?: NeonServerlessConfig; + ws?: any; + } & DrizzleConfig; + + const instance = new Pool(connection); + if (ws) { + neonConfig.webSocketConstructor = ws; + } - if (ws) { - neonConfig.webSocketConstructor = ws; + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; } - const db = drizzle(instance, drizzleConfig) as any; + const instance = new Pool(); + const db = drizzle(instance) as any; db.$client = instance; return db; } case 'planetscale': { - const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { connection, ...drizzleConfig } = params[0] as { connection: PlanetscaleConfig } & DrizzleConfig; const { Client } = await import('@planetscale/database').catch(() => importError('@planetscale/database')); const { drizzle } = await import('./planetscale-serverless'); + const instance = new Client( - connection as PlanetscaleConfig, + connection, ); - const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; return db; } case 'postgres-js': { - const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; - const { default: client } = await import('postgres').catch(() => importError('postgres')); const { drizzle } = await import('./postgres-js'); - const instance = client(connection as PostgresJSOptions>); - const db = drizzle(instance, drizzleConfig) as any; + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as { + connection: PostgresJSOptions>; + } & DrizzleConfig; + + const instance = client(connection); + + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; + } + + const instance = client(params[0]!); + const db = drizzle(instance) as any; db.$client = instance; return db; } case 'tidb-serverless': { - const { connection, ...drizzleConfig } = params as any as { connection: any } & DrizzleConfig; + const { connection, ...drizzleConfig } = params[0] as { connection: TiDBServerlessConfig } & DrizzleConfig; const { connect } = await import('@tidbcloud/serverless').catch(() => importError('@tidbcloud/serverless')); const { drizzle } = await import('./tidb-serverless'); - const instance = connect(connection as TiDBServerlessConfig); + const instance = connect(connection); const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; From 93428753bcd5464f5abb8736f8f3811406cfea4f Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Sat, 7 Sep 2024 18:38:19 +0300 Subject: [PATCH 151/492] Fixed incorrect order of ws assignment on neon-serverless, added ability to specify connection as string to multiple drivers that didn't support it by assigning passed string as connectionString or url inside the driver --- drizzle-orm/src/monodriver.ts | 149 ++++++++++++++++++++++++++-------- 1 file changed, 115 insertions(+), 34 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index c20cb9252..ab46de72d 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -6,9 +6,12 @@ import type { NeonQueryFunction, Pool as NeonServerlessPool, PoolConfig as NeonServerlessConfig, + QueryResult, + QueryResultRow, } from '@neondatabase/serverless'; import type { Client as PlanetscaleClient, Config as PlanetscaleConfig } from '@planetscale/database'; import type { Config as TiDBServerlessConfig, Connection as TiDBConnection } from '@tidbcloud/serverless'; +import type { VercelPool } from '@vercel/postgres'; import type { Database as BetterSQLite3Database, Options as BetterSQLite3Options } from 'better-sqlite3'; import type { Database as BunDatabase } from 'bun:sqlite'; import type { Pool as Mysql2Pool, PoolOptions as Mysql2Config } from 'mysql2'; @@ -115,12 +118,16 @@ type ClientDrizzleInstanceMap> = { 'better-sqlite3': DrizzleBetterSQLite3Database; }; +type Primitive = string | number | boolean | undefined | null; + type ClientInstanceMap = { 'node-postgres': NodePgPool; 'postgres-js': PostgresJsClient; 'neon-serverless': NeonServerlessPool; 'neon-http': NeonQueryFunction; - 'vercel-postgres': undefined; + 'vercel-postgres': + & VercelPool + & ((strings: TemplateStringsArray, ...values: Primitive[]) => Promise>); 'aws-data-api-pg': RDSDataClient; planetscale: PlanetscaleClient; mysql2: Mysql2Pool; @@ -140,7 +147,7 @@ type InitializerParams = { connection: string | PostgresJSOptions>; }; 'neon-serverless': { - connection?: NeonServerlessConfig; + connection?: string | NeonServerlessConfig; }; 'neon-http': { connection: MonodriverNeonHttpConfig; @@ -150,19 +157,19 @@ type InitializerParams = { connection?: RDSConfig; }; planetscale: { - connection: PlanetscaleConfig; + connection: PlanetscaleConfig | string; }; mysql2: { connection: Mysql2Config | string; }; 'tidb-serverless': { - connection: TiDBServerlessConfig; + connection: TiDBServerlessConfig | string; }; libsql: { - connection: LibsqlConfig; + connection: LibsqlConfig | string; }; turso: { - connection: LibsqlConfig; + connection: LibsqlConfig | string; }; d1: { connection: D1Database; @@ -219,7 +226,7 @@ export async function drizzle< & DrizzleConfig ), ]) - : TClient extends 'postgres-js' ? ( + : TClient extends 'postgres-js' | 'node-postgres' | 'tidb-serverless' | 'libsql' | 'turso' | 'planetscale' ? ( [ ( & InitializerParams[TClient] @@ -242,11 +249,15 @@ export async function drizzle< : TClient extends 'aws-data-api-pg' ? [ InitializerParams[TClient] & DrizzleAwsDataApiPgConfig, ] - : TClient extends 'neon-serverless' ? ([ - InitializerParams[TClient] & DrizzleConfig & { - ws?: any; - }, - ] | []) + : TClient extends 'neon-serverless' ? ( + | [ + InitializerParams[TClient] & DrizzleConfig & { + ws?: any; + }, + ] + | [string] + | [] + ) : TClient extends 'neon-http' ? ([ InitializerParams[TClient] & DrizzleConfig, ] | [ @@ -261,13 +272,23 @@ export async function drizzle< ): Promise> { switch (client) { case 'node-postgres': { - const { connection, ...drizzleConfig } = params[0] as { connection: NodePGPoolConfig } & DrizzleConfig; - - const { Pool } = await import('pg').catch(() => importError('pg')); + const pg = await import('pg').catch(() => importError('pg')); const { drizzle } = await import('./node-postgres'); - const instance = new Pool(connection); - const db = drizzle(instance, drizzleConfig) as any; + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as { connection: NodePGPoolConfig } & DrizzleConfig; + + const instance = new pg.Pool(connection); + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; + } + + const instance = new pg.Pool({ + connectionString: params[0]!, + }); + const db = drizzle(instance) as any; db.$client = instance; return db; @@ -364,12 +385,22 @@ export async function drizzle< } case 'libsql': case 'turso': { - const { connection, ...drizzleConfig } = params[0] as any as { connection: LibsqlConfig } & DrizzleConfig; - const { createClient } = await import('@libsql/client').catch(() => importError('@libsql/client')); const { drizzle } = await import('./libsql'); - const instance = createClient(connection); + if (typeof params[0] === 'string') { + const instance = createClient({ + url: params[0], + }); + const db = drizzle(instance) as any; + db.$client = instance; + + return db; + } + + const { connection, ...drizzleConfig } = params[0] as any as { connection: LibsqlConfig } & DrizzleConfig; + + const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection); const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; @@ -380,9 +411,11 @@ export async function drizzle< const { drizzle } = await import('./mysql2'); if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { connection: Mysql2Config } & MySql2DrizzleConfig; + const { connection, ...drizzleConfig } = params[0] as + & { connection: Mysql2Config | string } + & MySql2DrizzleConfig; - const instance = createPool(connection); + const instance = createPool(connection as Mysql2Config); const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; @@ -432,17 +465,33 @@ export async function drizzle< importError('@neondatabase/serverless') ); const { drizzle } = await import('./neon-serverless'); - if (params[0]) { + if (typeof params[0] === 'string') { + const instance = new Pool({ + connectionString: params[0], + }); + + const db = drizzle(instance) as any; + db.$client = instance; + + return db; + } + + if (typeof params[0] === 'object') { const { connection, ws, ...drizzleConfig } = params[0] as { - connection?: NeonServerlessConfig; + connection?: NeonServerlessConfig | string; ws?: any; } & DrizzleConfig; - const instance = new Pool(connection); if (ws) { neonConfig.webSocketConstructor = ws; } + const instance = typeof connection === 'string' + ? new Pool({ + connectionString: connection, + }) + : new Pool(connection); + const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; @@ -456,15 +505,31 @@ export async function drizzle< return db; } case 'planetscale': { - const { connection, ...drizzleConfig } = params[0] as { connection: PlanetscaleConfig } & DrizzleConfig; - const { Client } = await import('@planetscale/database').catch(() => importError('@planetscale/database')); const { drizzle } = await import('./planetscale-serverless'); - const instance = new Client( - connection, - ); - const db = drizzle(instance, drizzleConfig) as any; + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as + & { connection: PlanetscaleConfig | string } + & DrizzleConfig; + + const instance = typeof connection === 'string' + ? new Client({ + url: connection, + }) + : new Client( + connection, + ); + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; + } + + const instance = new Client({ + url: params[0], + }); + const db = drizzle(instance) as any; db.$client = instance; return db; @@ -493,12 +558,28 @@ export async function drizzle< return db; } case 'tidb-serverless': { - const { connection, ...drizzleConfig } = params[0] as { connection: TiDBServerlessConfig } & DrizzleConfig; - const { connect } = await import('@tidbcloud/serverless').catch(() => importError('@tidbcloud/serverless')); const { drizzle } = await import('./tidb-serverless'); - const instance = connect(connection); + if (typeof params[0] === 'string') { + const instance = connect({ + url: params[0], + }); + const db = drizzle(instance) as any; + db.$client = instance; + + return db; + } + + const { connection, ...drizzleConfig } = params[0] as + & { connection: TiDBServerlessConfig | string } + & DrizzleConfig; + + const instance = typeof connection === 'string' + ? connect({ + url: connection, + }) + : connect(connection); const db = drizzle(instance, drizzleConfig) as any; db.$client = instance; From cd1f68cb957752abe6bef585b617a5b007e9c971 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Sat, 7 Sep 2024 18:40:04 +0300 Subject: [PATCH 152/492] Removed monodriver node-pg due to incompatibility with import() --- drizzle-orm/src/monodriver.ts | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index ab46de72d..b0dabca8e 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -15,7 +15,6 @@ import type { VercelPool } from '@vercel/postgres'; import type { Database as BetterSQLite3Database, Options as BetterSQLite3Options } from 'better-sqlite3'; import type { Database as BunDatabase } from 'bun:sqlite'; import type { Pool as Mysql2Pool, PoolOptions as Mysql2Config } from 'mysql2'; -import type { Pool as NodePgPool, PoolConfig as NodePGPoolConfig } from 'pg'; import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType, @@ -29,7 +28,6 @@ import type { LibSQLDatabase } from './libsql/index.ts'; import type { MySql2Database, MySql2DrizzleConfig } from './mysql2/index.ts'; import type { NeonHttpDatabase } from './neon-http/index.ts'; import type { NeonDatabase } from './neon-serverless/index.ts'; -import type { NodePgDatabase } from './node-postgres/index.ts'; import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; import type { PostgresJsDatabase } from './postgres-js/index.ts'; import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; @@ -86,7 +84,6 @@ type MonodriverNeonHttpConfig = { } | string; type DatabaseClient = - | 'node-postgres' | 'postgres-js' | 'neon-serverless' | 'neon-http' @@ -102,7 +99,6 @@ type DatabaseClient = | 'better-sqlite3'; type ClientDrizzleInstanceMap> = { - 'node-postgres': NodePgDatabase; 'postgres-js': PostgresJsDatabase; 'neon-serverless': NeonDatabase; 'neon-http': NeonHttpDatabase; @@ -121,7 +117,6 @@ type ClientDrizzleInstanceMap> = { type Primitive = string | number | boolean | undefined | null; type ClientInstanceMap = { - 'node-postgres': NodePgPool; 'postgres-js': PostgresJsClient; 'neon-serverless': NeonServerlessPool; 'neon-http': NeonQueryFunction; @@ -140,9 +135,6 @@ type ClientInstanceMap = { }; type InitializerParams = { - 'node-postgres': { - connection: NodePGPoolConfig; - }; 'postgres-js': { connection: string | PostgresJSOptions>; }; @@ -226,7 +218,7 @@ export async function drizzle< & DrizzleConfig ), ]) - : TClient extends 'postgres-js' | 'node-postgres' | 'tidb-serverless' | 'libsql' | 'turso' | 'planetscale' ? ( + : TClient extends 'postgres-js' | 'tidb-serverless' | 'libsql' | 'turso' | 'planetscale' ? ( [ ( & InitializerParams[TClient] @@ -271,28 +263,6 @@ export async function drizzle< ] ): Promise> { switch (client) { - case 'node-postgres': { - const pg = await import('pg').catch(() => importError('pg')); - const { drizzle } = await import('./node-postgres'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { connection: NodePGPoolConfig } & DrizzleConfig; - - const instance = new pg.Pool(connection); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; - - return db; - } - - const instance = new pg.Pool({ - connectionString: params[0]!, - }); - const db = drizzle(instance) as any; - db.$client = instance; - - return db; - } case 'aws-data-api-pg': { const { connection, ...drizzleConfig } = params[0] as & { connection: RDSDataClientConfig | undefined } From 239cfa98cf08ab63feb37131a6b0fdf3773a62e4 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 9 Sep 2024 11:17:29 +0300 Subject: [PATCH 153/492] Add release notes for orm and kit --- changelogs/drizzle-kit/0.25.0.md | 95 ++++++++++++++++++++++++++++ changelogs/drizzle-orm/0.34.0.md | 103 +++++++++++++++++-------------- 2 files changed, 153 insertions(+), 45 deletions(-) diff --git a/changelogs/drizzle-kit/0.25.0.md b/changelogs/drizzle-kit/0.25.0.md index e69de29bb..0c1c5ea6e 100644 --- a/changelogs/drizzle-kit/0.25.0.md +++ b/changelogs/drizzle-kit/0.25.0.md @@ -0,0 +1,95 @@ +## Libsql and Sqlite migration updates + +### SQLite "generate" and "push" statements updates + +Starting from this release, we will no longer generate comments like this: + +```sql + '/*\n SQLite does not support "Changing existing column type" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' +``` + +We will generate a set of statements, and you can decide if it's appropriate to create data-moving statements instead. Here is an example of the SQL file you'll receive now: + +```sql +PRAGMA foreign_keys=OFF; +--> statement-breakpoint +CREATE TABLE `__new_worker` ( + `id` integer PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `salary` text NOT NULL, + `job_id` integer, + FOREIGN KEY (`job_id`) REFERENCES `job`(`id`) ON UPDATE no action ON DELETE no action +); +--> statement-breakpoint +INSERT INTO `__new_worker`("id", "name", "salary", "job_id") SELECT "id", "name", "salary", "job_id" FROM `worker`; +--> statement-breakpoint +DROP TABLE `worker`; +--> statement-breakpoint +ALTER TABLE `__new_worker` RENAME TO `worker`; +--> statement-breakpoint +PRAGMA foreign_keys=ON; +``` + +### LibSQL "generate" and "push" statements updates + +Since LibSQL supports more ALTER statements than SQLite, we can generate more statements without recreating your schema and moving all the data, which can be potentially dangerous for production environments. + +LibSQL and Turso will now have a separate dialect in the Drizzle config file, meaning that we will evolve Turso and LibSQL independently from SQLite and will aim to support as many features as Turso/LibSQL offer. + +> **Breaking change!** All users who want to get the most out of Turso and LibSQL DDL statements should remove `driver: turso` from the `drizzle.config` file and add `dialect: turso` instead + +With the updated LibSQL migration strategy, you will have the ability to: + +- **Change Data Type**: Set a new data type for existing columns. +- **Set and Drop Default Values**: Add or remove default values for existing columns. +- **Set and Drop NOT NULL**: Add or remove the NOT NULL constraint on existing columns. +- **Add References to Existing Columns**: Add foreign key references to existing columns + +You can find more information in the [LibSQL documentation](https://github.com/tursodatabase/libsql/blob/main/libsql-sqlite3/doc/libsql_extensions.md#altering-columns) + +### LIMITATIONS + +- Dropping or altering an index will cause table recreation. + +This is because LibSQL does not support dropping this type of index. + +```sql +CREATE TABLE `users` ( + `id` integer NOT NULL, + `name` integer, + `age` integer PRIMARY KEY NOT NULL + FOREIGN KEY (`name`) REFERENCES `users1`("id") ON UPDATE no action ON DELETE no action +); +``` + +- If the table has indexes, altering columns will cause table recreation. +- Drizzle-Kit will drop the indexes, modify the columns, and then recreate the indexes. +- Adding or dropping composite foreign keys is not supported and will cause table recreation + +### NOTES: + +- You can create a reference on any column type, but if you want to insert values, the referenced column must have a unique index or primary key. + +```sql +CREATE TABLE parent(a PRIMARY KEY, b UNIQUE, c, d, e, f); +CREATE UNIQUE INDEX i1 ON parent(c, d); +CREATE INDEX i2 ON parent(e); +CREATE UNIQUE INDEX i3 ON parent(f COLLATE nocase); + +CREATE TABLE child1(f, g REFERENCES parent(a)); -- Ok +CREATE TABLE child2(h, i REFERENCES parent(b)); -- Ok +CREATE TABLE child3(j, k, FOREIGN KEY(j, k) REFERENCES parent(c, d)); -- Ok +CREATE TABLE child4(l, m REFERENCES parent(e)); -- Error! +CREATE TABLE child5(n, o REFERENCES parent(f)); -- Error! +CREATE TABLE child6(p, q, FOREIGN KEY(p, q) REFERENCES parent(b, c)); -- Error! +CREATE TABLE child7(r REFERENCES parent(c)); -- Error! +``` + +> **NOTE**: The foreign key for the table child5 is an error because, although the parent key column has a unique index, the index uses a different collating sequence. + +See more: https://www.sqlite.org/foreignkeys.html \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.34.0.md b/changelogs/drizzle-orm/0.34.0.md index 4ceb1a630..55eb0411f 100644 --- a/changelogs/drizzle-orm/0.34.0.md +++ b/changelogs/drizzle-orm/0.34.0.md @@ -1,6 +1,8 @@ -// Libsql and Sqlite migration updates +## Libsql and Sqlite migration updates -SQLite generate statements updates. Starting from this release, we won't generate comments like this: +### SQLite "generate" and "push" statements updates + +Starting from this release, we will no longer generate comments like this: ```sql '/*\n SQLite does not support "Changing existing column type" out of the box, we do not generate automatic migration for that, so it has to be done manually' @@ -11,66 +13,67 @@ SQLite generate statements updates. Starting from this release, we won't generat + '\n*/' ``` -We will generate a set of statements instead and you will decide if it's good to make data moving statements instead. Here is an example of generated sql file you'll get now: +We will generate a set of statements, and you can decide if it's appropriate to create data-moving statements instead. Here is an example of the SQL file you'll receive now: ```sql +PRAGMA foreign_keys=OFF; +--> statement-breakpoint +CREATE TABLE `__new_worker` ( + `id` integer PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `salary` text NOT NULL, + `job_id` integer, + FOREIGN KEY (`job_id`) REFERENCES `job`(`id`) ON UPDATE no action ON DELETE no action +); +--> statement-breakpoint +INSERT INTO `__new_worker`("id", "name", "salary", "job_id") SELECT "id", "name", "salary", "job_id" FROM `worker`; +--> statement-breakpoint +DROP TABLE `worker`; +--> statement-breakpoint +ALTER TABLE `__new_worker` RENAME TO `worker`; +--> statement-breakpoint +PRAGMA foreign_keys=ON; ``` -LibSQL generate statements updates. As long as libsql support more alter statements than SQLite we can generate more statements without recreating you schema and moving all the data, which can be potentially dangeourose for production envs - -LibSQL and Turso will now get a separate dialect in drizzle config file, means, that we will evolve Turso and LibSQL separately from SQLite and will try to support as much features Turso/LibSQL would have as possible - -Breaking change! All the users, who wants to get max from Turso and LibSQL DDL statements, shouls remove `driver: turso` from drizzle.config and add `dialect: turso` instead - -With updated LibSQL migrartion staretegy you would have a possibility to: - -- **Change Data Type**: You can set a new data type for existing columns. -- **Set and Drop Default Values**: You can add or remove default values for existing columns. -- **Set and Drop Not Null Constraint**: You can add or remov the `NOT NULL` constraint on existing columns. -- **Add References to Existing Columns**: You can add foreign key references to existing columns. - +### LibSQL "generate" and "push" statements updates -### Code Example: +Since LibSQL supports more ALTER statements than SQLite, we can generate more statements without recreating your schema and moving all the data, which can be potentially dangerous for production environments. -```sql -PRAGMA foreign_keys=OFF; - -CREATE TABLE `__new_table` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `name` text NOT NULL -); +LibSQL and Turso will now have a separate dialect in the Drizzle config file, meaning that we will evolve Turso and LibSQL independently from SQLite and will aim to support as many features as Turso/LibSQL offer. -INSERT INTO `__new_table`("id", "name") SELECT "id", "name" FROM `table`; +> **Breaking change!** All users who want to get the most out of Turso and LibSQL DDL statements should remove `driver: turso` from the `drizzle.config` file and add `dialect: turso` instead -DROP TABLE `table`; +With the updated LibSQL migration strategy, you will have the ability to: -ALTER TABLE `__new_table` RENAME TO `table`; +- **Change Data Type**: Set a new data type for existing columns. +- **Set and Drop Default Values**: Add or remove default values for existing columns. +- **Set and Drop NOT NULL**: Add or remove the NOT NULL constraint on existing columns. +- **Add References to Existing Columns**: Add foreign key references to existing columns -PRAGMA foreign_keys=ON; -``` +You can find more information in the [LibSQL documentation](https://github.com/tursodatabase/libsql/blob/main/libsql-sqlite3/doc/libsql_extensions.md#altering-columns) ### LIMITATIONS -- Dropping or altering index will cause table recreation +- Dropping or altering an index will cause table recreation. -This is because LibSQL does not support dropping this type of index: +This is because LibSQL does not support dropping this type of index. ```sql CREATE TABLE `users` ( - `id` integer NOT NULL, - `name` integer, - `age` integer PRIMARY KEY NOT NULL - FOREIGN KEY (`name`) REFERENCES `users1`("id") ON UPDATE no action ON DELETE no action + `id` integer NOT NULL, + `name` integer, + `age` integer PRIMARY KEY NOT NULL + FOREIGN KEY (`name`) REFERENCES `users1`("id") ON UPDATE no action ON DELETE no action ); ``` - If the table has indexes, altering columns will cause table recreation. - Drizzle-Kit will drop those indexes, modify the columns, and then recreate the indexes. -- Adding or dropping `composite foreign keys` is not supported and will cause table recreation. +- Drizzle-Kit will drop the indexes, modify the columns, and then recreate the indexes. +- Adding or dropping composite foreign keys is not supported and will cause table recreation ### NOTES: -- You can create reference on any column type, but if you want to insert values than primary column should have unique index or primary key +- You can create a reference on any column type, but if you want to insert values, the referenced column must have a unique index or primary key. ```sql CREATE TABLE parent(a PRIMARY KEY, b UNIQUE, c, d, e, f); @@ -87,17 +90,27 @@ CREATE TABLE child6(p, q, FOREIGN KEY(p, q) REFERENCES parent(b, c)); -- Error! CREATE TABLE child7(r REFERENCES parent(c)); -- Error! ``` -> NOTE: The foreign key for table *child5* is an error because even though the parent key column has a unique index, the index uses a different collating sequence +> **NOTE**: The foreign key for the table child5 is an error because, although the parent key column has a unique index, the index uses a different collating sequence. See more: https://www.sqlite.org/foreignkeys.html -// monodriver +## A new and easy way to start using drizzle before on example with node-postgres ```ts +// 1, current const client = new Pool({ url: '' }); drizzle(client, { logger: true }); + +// 2 +await drizzle('neon', { client: 'postgresql://...', logger: true }) + +// 3 +await drizzle('neon', { client: { url: 'postgresql://...' }, logger: true }) + +// 4 +await drizzle('neon', 'postgresql://...') ``` will become @@ -107,17 +120,17 @@ await drizzle('', { client: '', logger: true }) await drizzle('', { client: {}, logger: true }) ``` -> Note that first example with client is still available and not deprecated. You ca use it, if you don't want to await drizzle object. New way of defining drizzle is done to make it easiser to import from 1 place and get an autocmplete with all the possible clients +> Note that the first example with the client is still available and not deprecated. You can use it if you don't want to await the drizzle object. The new way of defining drizzle is designed to make it easier to import from one place and get autocomplete for all the available clients -// db count feature +## New "count" API -to count entities in table you would need to do this +Befor this release to count entities in a table, you would need to do this: ```ts const res = await db.select({ count: sql`count(*)` }).from(users); const count = res[0].count; ``` -a new api will look like +The new API will look like this: ```ts // how many users are in the database const count: number = await db.$count(users); @@ -126,7 +139,7 @@ const count: number = await db.$count(users); const count: number = await db.$count(users, eq(name, "Dan")); ``` -This can also work as a subquery and inside relational queries +This can also work as a subquery and within relational queries ```ts const users = await db.select({ ...users, From 86140ad9deea5269cdc4b2e0cb6d1bf4de6f1db4 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Mon, 9 Sep 2024 13:48:52 +0300 Subject: [PATCH 154/492] Returned node-postgres --- drizzle-orm/src/monodriver.ts | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index b0dabca8e..121b6b470 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -15,6 +15,7 @@ import type { VercelPool } from '@vercel/postgres'; import type { Database as BetterSQLite3Database, Options as BetterSQLite3Options } from 'better-sqlite3'; import type { Database as BunDatabase } from 'bun:sqlite'; import type { Pool as Mysql2Pool, PoolOptions as Mysql2Config } from 'mysql2'; +import type { Pool as NodePgPool, PoolConfig as NodePgPoolConfig } from 'pg'; import type { Options as PostgresJSOptions, PostgresType as PostgresJSPostgresType, @@ -28,6 +29,7 @@ import type { LibSQLDatabase } from './libsql/index.ts'; import type { MySql2Database, MySql2DrizzleConfig } from './mysql2/index.ts'; import type { NeonHttpDatabase } from './neon-http/index.ts'; import type { NeonDatabase } from './neon-serverless/index.ts'; +import type { NodePgDatabase } from './node-postgres/driver.ts'; import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; import type { PostgresJsDatabase } from './postgres-js/index.ts'; import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; @@ -84,6 +86,7 @@ type MonodriverNeonHttpConfig = { } | string; type DatabaseClient = + | 'node-postgres' | 'postgres-js' | 'neon-serverless' | 'neon-http' @@ -99,6 +102,7 @@ type DatabaseClient = | 'better-sqlite3'; type ClientDrizzleInstanceMap> = { + 'node-postgres': NodePgDatabase; 'postgres-js': PostgresJsDatabase; 'neon-serverless': NeonDatabase; 'neon-http': NeonHttpDatabase; @@ -117,6 +121,7 @@ type ClientDrizzleInstanceMap> = { type Primitive = string | number | boolean | undefined | null; type ClientInstanceMap = { + 'node-postgres': NodePgPool; 'postgres-js': PostgresJsClient; 'neon-serverless': NeonServerlessPool; 'neon-http': NeonQueryFunction; @@ -135,6 +140,9 @@ type ClientInstanceMap = { }; type InitializerParams = { + 'node-postgres': { + connection?: string | NodePgPoolConfig; + }; 'postgres-js': { connection: string | PostgresJSOptions>; }; @@ -218,6 +226,16 @@ export async function drizzle< & DrizzleConfig ), ]) + : TClient extends 'node-postgres' ? ( + [ + ( + & InitializerParams[TClient] + & DrizzleConfig + ), + ] | [ + string, + ] + ) : TClient extends 'postgres-js' | 'tidb-serverless' | 'libsql' | 'turso' | 'planetscale' ? ( [ ( @@ -263,6 +281,36 @@ export async function drizzle< ] ): Promise> { switch (client) { + case 'node-postgres': { + const defpg = await import('pg'); + const { drizzle } = await import('./node-postgres'); + + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as + & { connection: NodePgPoolConfig | string } + & DrizzleConfig; + + const instance = typeof connection === 'string' + ? new defpg.default.Pool({ + connectionString: connection, + }) + : new defpg.default.Pool(connection); + const db = drizzle(instance, drizzleConfig) as any; + db.$client = instance; + + return db; + } + + const instance = typeof params[0] === 'string' + ? new defpg.default.Pool({ + connectionString: params[0], + }) + : new defpg.default.Pool(params[0]); + const db = drizzle(instance) as any; + db.$client = instance; + + return db; + } case 'aws-data-api-pg': { const { connection, ...drizzleConfig } = params[0] as & { connection: RDSDataClientConfig | undefined } From c6528edef7f5b9938c3da7e1a739b986cd3a1c15 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Mon, 9 Sep 2024 14:39:27 +0300 Subject: [PATCH 155/492] Removed outdated migration config string type --- drizzle-orm/src/aws-data-api/pg/migrator.ts | 2 +- drizzle-orm/src/better-sqlite3/migrator.ts | 2 +- drizzle-orm/src/bun-sqlite/migrator.ts | 2 +- drizzle-orm/src/d1/migrator.ts | 8 ++---- drizzle-orm/src/libsql/migrator.ts | 8 ++---- drizzle-orm/src/migrator.ts | 16 ++--------- drizzle-orm/src/monomigrator.ts | 28 +++++++++---------- drizzle-orm/src/mysql2/migrator.ts | 11 ++------ drizzle-orm/src/neon-http/migrator.ts | 8 ++---- drizzle-orm/src/neon-serverless/migrator.ts | 2 +- drizzle-orm/src/node-postgres/migrator.ts | 2 +- drizzle-orm/src/pg-proxy/migrator.ts | 2 +- drizzle-orm/src/pglite/migrator.ts | 2 +- .../src/planetscale-serverless/migrator.ts | 10 ++----- drizzle-orm/src/postgres-js/migrator.ts | 2 +- drizzle-orm/src/sql-js/migrator.ts | 2 +- drizzle-orm/src/sqlite-proxy/migrator.ts | 2 +- drizzle-orm/src/vercel-postgres/migrator.ts | 2 +- drizzle-orm/src/xata-http/migrator.ts | 6 ++-- 19 files changed, 39 insertions(+), 78 deletions(-) diff --git a/drizzle-orm/src/aws-data-api/pg/migrator.ts b/drizzle-orm/src/aws-data-api/pg/migrator.ts index 2afa79412..c58ba7ab1 100644 --- a/drizzle-orm/src/aws-data-api/pg/migrator.ts +++ b/drizzle-orm/src/aws-data-api/pg/migrator.ts @@ -4,7 +4,7 @@ import type { AwsDataApiPgDatabase } from './driver.ts'; export async function migrate>( db: AwsDataApiPgDatabase, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); await db.dialect.migrate(migrations, db.session, config); diff --git a/drizzle-orm/src/better-sqlite3/migrator.ts b/drizzle-orm/src/better-sqlite3/migrator.ts index 1cbd2fe56..cea198257 100644 --- a/drizzle-orm/src/better-sqlite3/migrator.ts +++ b/drizzle-orm/src/better-sqlite3/migrator.ts @@ -4,7 +4,7 @@ import type { BetterSQLite3Database } from './driver.ts'; export function migrate>( db: BetterSQLite3Database, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); db.dialect.migrate(migrations, db.session, config); diff --git a/drizzle-orm/src/bun-sqlite/migrator.ts b/drizzle-orm/src/bun-sqlite/migrator.ts index ee248fd3e..785dabae9 100644 --- a/drizzle-orm/src/bun-sqlite/migrator.ts +++ b/drizzle-orm/src/bun-sqlite/migrator.ts @@ -4,7 +4,7 @@ import type { BunSQLiteDatabase } from './driver.ts'; export function migrate>( db: BunSQLiteDatabase, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); db.dialect.migrate(migrations, db.session, config); diff --git a/drizzle-orm/src/d1/migrator.ts b/drizzle-orm/src/d1/migrator.ts index 9a137136d..2259516bf 100644 --- a/drizzle-orm/src/d1/migrator.ts +++ b/drizzle-orm/src/d1/migrator.ts @@ -5,14 +5,10 @@ import type { DrizzleD1Database } from './driver.ts'; export async function migrate>( db: DrizzleD1Database, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); - const migrationsTable = config === undefined - ? '__drizzle_migrations' - : typeof config === 'string' - ? '__drizzle_migrations' - : config.migrationsTable ?? '__drizzle_migrations'; + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; const migrationTableCreate = sql` CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} ( diff --git a/drizzle-orm/src/libsql/migrator.ts b/drizzle-orm/src/libsql/migrator.ts index d362a2e4d..373a8aab4 100644 --- a/drizzle-orm/src/libsql/migrator.ts +++ b/drizzle-orm/src/libsql/migrator.ts @@ -5,14 +5,10 @@ import type { LibSQLDatabase } from './driver.ts'; export async function migrate>( db: LibSQLDatabase, - config: MigrationConfig | string, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); - const migrationsTable = config === undefined - ? '__drizzle_migrations' - : typeof config === 'string' - ? '__drizzle_migrations' - : config.migrationsTable ?? '__drizzle_migrations'; + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; const migrationTableCreate = sql` CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} ( diff --git a/drizzle-orm/src/migrator.ts b/drizzle-orm/src/migrator.ts index 946f3269d..8b7636a44 100644 --- a/drizzle-orm/src/migrator.ts +++ b/drizzle-orm/src/migrator.ts @@ -1,6 +1,5 @@ import crypto from 'node:crypto'; import fs from 'node:fs'; -import path from 'node:path'; export interface KitConfig { out: string; @@ -20,19 +19,8 @@ export interface MigrationMeta { bps: boolean; } -export function readMigrationFiles(config: string | MigrationConfig): MigrationMeta[] { - let migrationFolderTo: string | undefined; - if (typeof config === 'string') { - const configAsString = fs.readFileSync(path.resolve('.', config), 'utf8'); - const jsonConfig = JSON.parse(configAsString) as KitConfig; - migrationFolderTo = jsonConfig.out; - } else { - migrationFolderTo = config.migrationsFolder; - } - - if (!migrationFolderTo) { - throw new Error('no migration folder defined'); - } +export function readMigrationFiles(config: MigrationConfig): MigrationMeta[] { + const migrationFolderTo = config.migrationsFolder; const migrationQueries: MigrationMeta[] = []; diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index bee18ad46..77d1c8da4 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -30,65 +30,63 @@ export async function migrate( | PostgresJsDatabase | VercelPgDatabase | TiDBServerlessDatabase, - config: - | string - | MigrationConfig, + config: MigrationConfig, ) { switch (( db).constructor[entityKind]) { case 'AwsDataApiPgDatabase': { const { migrate } = await import('./aws-data-api/pg/migrator'); - return migrate(db as AwsDataApiPgDatabase, config as string | MigrationConfig); + return migrate(db as AwsDataApiPgDatabase, config as MigrationConfig); } case 'BetterSQLite3Database': { const { migrate } = await import('./better-sqlite3/migrator'); - return migrate(db as BetterSQLite3Database, config as string | MigrationConfig); + return migrate(db as BetterSQLite3Database, config as MigrationConfig); } case 'BunSQLiteDatabase': { const { migrate } = await import('./bun-sqlite/migrator'); - return migrate(db as BunSQLiteDatabase, config as string | MigrationConfig); + return migrate(db as BunSQLiteDatabase, config as MigrationConfig); } case 'D1Database': { const { migrate } = await import('./d1/migrator'); - return migrate(db as DrizzleD1Database, config as string | MigrationConfig); + return migrate(db as DrizzleD1Database, config as MigrationConfig); } case 'LibSQLDatabase': { const { migrate } = await import('./libsql/migrator'); - return migrate(db as LibSQLDatabase, config as string | MigrationConfig); + return migrate(db as LibSQLDatabase, config as MigrationConfig); } case 'MySql2Database': { const { migrate } = await import('./mysql2/migrator'); - return migrate(db as MySql2Database, config as string | MigrationConfig); + return migrate(db as MySql2Database, config as MigrationConfig); } case 'NeonHttpDatabase': { const { migrate } = await import('./neon-http/migrator'); - return migrate(db as NeonHttpDatabase, config as string | MigrationConfig); + return migrate(db as NeonHttpDatabase, config as MigrationConfig); } case 'NeonServerlessDatabase': { const { migrate } = await import('./neon-serverless/migrator'); - return migrate(db as NeonDatabase, config as string | MigrationConfig); + return migrate(db as NeonDatabase, config as MigrationConfig); } case 'NodePgDatabase': { const { migrate } = await import('./node-postgres/migrator'); - return migrate(db as NodePgDatabase, config as string | MigrationConfig); + return migrate(db as NodePgDatabase, config as MigrationConfig); } case 'PlanetScaleDatabase': { const { migrate } = await import('./planetscale-serverless/migrator'); - return migrate(db as PlanetScaleDatabase, config as string | MigrationConfig); + return migrate(db as PlanetScaleDatabase, config as MigrationConfig); } case 'PostgresJsDatabase': { const { migrate } = await import('./postgres-js/migrator'); - return migrate(db as PostgresJsDatabase, config as string | MigrationConfig); + return migrate(db as PostgresJsDatabase, config as MigrationConfig); } case 'TiDBServerlessDatabase': { const { migrate } = await import('./tidb-serverless/migrator'); @@ -98,7 +96,7 @@ export async function migrate( case 'VercelPgDatabase': { const { migrate } = await import('./vercel-postgres/migrator'); - return migrate(db as VercelPgDatabase, config as string | MigrationConfig); + return migrate(db as VercelPgDatabase, config as MigrationConfig); } } } diff --git a/drizzle-orm/src/mysql2/migrator.ts b/drizzle-orm/src/mysql2/migrator.ts index ae56e01f1..2f3c9c3dc 100644 --- a/drizzle-orm/src/mysql2/migrator.ts +++ b/drizzle-orm/src/mysql2/migrator.ts @@ -4,15 +4,8 @@ import type { MySql2Database } from './driver.ts'; export async function migrate>( db: MySql2Database, - config: MigrationConfig | string, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); - - const preparedConfig = typeof config === 'string' - ? { - migrationsFolder: config, - } - : config; - - await db.dialect.migrate(migrations, db.session, preparedConfig); + await db.dialect.migrate(migrations, db.session, config); } diff --git a/drizzle-orm/src/neon-http/migrator.ts b/drizzle-orm/src/neon-http/migrator.ts index b5c6d363a..db8784248 100644 --- a/drizzle-orm/src/neon-http/migrator.ts +++ b/drizzle-orm/src/neon-http/migrator.ts @@ -13,13 +13,11 @@ import type { NeonHttpDatabase } from './driver.ts'; */ export async function migrate>( db: NeonHttpDatabase, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); - const migrationsTable = typeof config === 'string' - ? '__drizzle_migrations' - : config.migrationsTable ?? '__drizzle_migrations'; - const migrationsSchema = typeof config === 'string' ? 'drizzle' : config.migrationsSchema ?? 'drizzle'; + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; + const migrationsSchema = config.migrationsSchema ?? 'drizzle'; const migrationTableCreate = sql` CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsSchema)}.${sql.identifier(migrationsTable)} ( id SERIAL PRIMARY KEY, diff --git a/drizzle-orm/src/neon-serverless/migrator.ts b/drizzle-orm/src/neon-serverless/migrator.ts index 63b675563..9948f245c 100644 --- a/drizzle-orm/src/neon-serverless/migrator.ts +++ b/drizzle-orm/src/neon-serverless/migrator.ts @@ -4,7 +4,7 @@ import type { NeonDatabase } from './driver.ts'; export async function migrate>( db: NeonDatabase, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); await db.dialect.migrate(migrations, db.session, config); diff --git a/drizzle-orm/src/node-postgres/migrator.ts b/drizzle-orm/src/node-postgres/migrator.ts index fa6d508d0..933e5a486 100644 --- a/drizzle-orm/src/node-postgres/migrator.ts +++ b/drizzle-orm/src/node-postgres/migrator.ts @@ -4,7 +4,7 @@ import type { NodePgDatabase } from './driver.ts'; export async function migrate>( db: NodePgDatabase, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); await db.dialect.migrate(migrations, db.session, config); diff --git a/drizzle-orm/src/pg-proxy/migrator.ts b/drizzle-orm/src/pg-proxy/migrator.ts index 5ca49ca43..68214ca58 100644 --- a/drizzle-orm/src/pg-proxy/migrator.ts +++ b/drizzle-orm/src/pg-proxy/migrator.ts @@ -8,7 +8,7 @@ export type ProxyMigrator = (migrationQueries: string[]) => Promise; export async function migrate>( db: PgRemoteDatabase, callback: ProxyMigrator, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); diff --git a/drizzle-orm/src/pglite/migrator.ts b/drizzle-orm/src/pglite/migrator.ts index 83c26cf3d..f43d9f618 100644 --- a/drizzle-orm/src/pglite/migrator.ts +++ b/drizzle-orm/src/pglite/migrator.ts @@ -4,7 +4,7 @@ import type { PgliteDatabase } from './driver.ts'; export async function migrate>( db: PgliteDatabase, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); await db.dialect.migrate(migrations, db.session, config); diff --git a/drizzle-orm/src/planetscale-serverless/migrator.ts b/drizzle-orm/src/planetscale-serverless/migrator.ts index 8b3713602..c6b964051 100644 --- a/drizzle-orm/src/planetscale-serverless/migrator.ts +++ b/drizzle-orm/src/planetscale-serverless/migrator.ts @@ -4,15 +4,9 @@ import type { PlanetScaleDatabase } from './driver.ts'; export async function migrate>( db: PlanetScaleDatabase, - config: MigrationConfig | string, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); - const preparedConfig = typeof config === 'string' - ? { - migrationsFolder: config, - } - : config; - - await db.dialect.migrate(migrations, db.session, preparedConfig); + await db.dialect.migrate(migrations, db.session, config); } diff --git a/drizzle-orm/src/postgres-js/migrator.ts b/drizzle-orm/src/postgres-js/migrator.ts index 881381e83..7930129f4 100644 --- a/drizzle-orm/src/postgres-js/migrator.ts +++ b/drizzle-orm/src/postgres-js/migrator.ts @@ -4,7 +4,7 @@ import type { PostgresJsDatabase } from './driver.ts'; export async function migrate>( db: PostgresJsDatabase, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); await db.dialect.migrate(migrations, db.session, config); diff --git a/drizzle-orm/src/sql-js/migrator.ts b/drizzle-orm/src/sql-js/migrator.ts index 2b6f128f8..1b3d5faa3 100644 --- a/drizzle-orm/src/sql-js/migrator.ts +++ b/drizzle-orm/src/sql-js/migrator.ts @@ -4,7 +4,7 @@ import type { SQLJsDatabase } from './driver.ts'; export function migrate>( db: SQLJsDatabase, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); db.dialect.migrate(migrations, db.session, config); diff --git a/drizzle-orm/src/sqlite-proxy/migrator.ts b/drizzle-orm/src/sqlite-proxy/migrator.ts index ccce912aa..cc4a7f71c 100644 --- a/drizzle-orm/src/sqlite-proxy/migrator.ts +++ b/drizzle-orm/src/sqlite-proxy/migrator.ts @@ -8,7 +8,7 @@ export type ProxyMigrator = (migrationQueries: string[]) => Promise; export async function migrate>( db: SqliteRemoteDatabase, callback: ProxyMigrator, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); diff --git a/drizzle-orm/src/vercel-postgres/migrator.ts b/drizzle-orm/src/vercel-postgres/migrator.ts index a2ae29a08..88c922271 100644 --- a/drizzle-orm/src/vercel-postgres/migrator.ts +++ b/drizzle-orm/src/vercel-postgres/migrator.ts @@ -4,7 +4,7 @@ import type { VercelPgDatabase } from './driver.ts'; export async function migrate>( db: VercelPgDatabase, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); await db.dialect.migrate(migrations, db.session, config); diff --git a/drizzle-orm/src/xata-http/migrator.ts b/drizzle-orm/src/xata-http/migrator.ts index 569b756d9..0eb261d88 100644 --- a/drizzle-orm/src/xata-http/migrator.ts +++ b/drizzle-orm/src/xata-http/migrator.ts @@ -16,12 +16,10 @@ export interface MigrationConfig { * @param config - path to migration folder generated by drizzle-kit */ export async function migrate>( db: XataHttpDatabase, - config: string | MigrationConfig, + config: MigrationConfig, ) { const migrations = readMigrationFiles(config); - const migrationsTable = typeof config === 'string' - ? '__drizzle_migrations' - : config.migrationsTable ?? '__drizzle_migrations'; + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; const migrationTableCreate = sql` CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} ( id SERIAL PRIMARY KEY, From e3cc54eacd412594a3a63a92d46f505cef5a3ac2 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Tue, 10 Sep 2024 15:38:11 +0300 Subject: [PATCH 156/492] - added sqlite, turso checks - added and updated tests --- .../src/cli/commands/libSqlPushUtils.ts | 9 + .../src/cli/commands/sqlitePushUtils.ts | 9 + drizzle-kit/src/introspect-sqlite.ts | 28 ++ drizzle-kit/src/jsonStatements.ts | 5 +- drizzle-kit/src/serializer/mysqlSchema.ts | 1 + drizzle-kit/src/serializer/sqliteSchema.ts | 29 +- .../src/serializer/sqliteSerializer.ts | 89 +++++ drizzle-kit/src/snapshotsDiffer.ts | 101 +++++- drizzle-kit/src/sqlgenerator.ts | 35 +- drizzle-kit/src/statementCombiner.ts | 30 +- drizzle-kit/tests/libsql-checks.test.ts | 308 ++++++++++++++++++ drizzle-kit/tests/libsql-statements.test.ts | 7 + drizzle-kit/tests/mysql-checks.test.ts | 291 +++++++++++++++++ drizzle-kit/tests/mysql-schemas.test.ts | 1 + drizzle-kit/tests/mysql.test.ts | 8 + drizzle-kit/tests/pg-checks.test.ts | 10 +- drizzle-kit/tests/pg-identity.test.ts | 3 + drizzle-kit/tests/pg-tables.test.ts | 10 + drizzle-kit/tests/push/libsql.test.ts | 246 ++++++++++++++ drizzle-kit/tests/push/pg.test.ts | 2 +- drizzle-kit/tests/push/sqlite.test.ts | 166 +++++++++- drizzle-kit/tests/sqlite-checks.test.ts | 308 ++++++++++++++++++ drizzle-kit/tests/sqlite-columns.test.ts | 12 + drizzle-kit/tests/sqlite-generated.test.ts | 6 + drizzle-kit/tests/sqlite-tables.test.ts | 9 + .../libsql-statements-combiner.test.ts | 47 +++ .../sqlite-statements-combiner.test.ts | 27 ++ 27 files changed, 1753 insertions(+), 44 deletions(-) create mode 100644 drizzle-kit/tests/libsql-checks.test.ts create mode 100644 drizzle-kit/tests/mysql-checks.test.ts create mode 100644 drizzle-kit/tests/sqlite-checks.test.ts diff --git a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts index 01bb61334..31e90c872 100644 --- a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts +++ b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts @@ -40,9 +40,17 @@ export const _moveDataStatements = ( const compositePKs = Object.values( json.tables[tableName].compositePrimaryKeys, ).map((it) => SQLiteSquasher.unsquashPK(it)); + const checkConstraints = Object.values(json.tables[tableName].checkConstraints); const fks = referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)); + const mappedCheckConstraints: string[] = checkConstraints.map((it) => + it.replaceAll(`"${tableName}".`, `"${newTableName}".`) + .replaceAll(`\`${tableName}\`.`, `\`${newTableName}\`.`) + .replaceAll(`${tableName}.`, `${newTableName}.`) + .replaceAll(`'${tableName}'.`, `\`${newTableName}\`.`) + ); + // create new table statements.push( new SQLiteCreateTableConvertor().convert({ @@ -51,6 +59,7 @@ export const _moveDataStatements = ( columns: tableColumns, referenceData: fks, compositePKs, + checkConstraints: mappedCheckConstraints, }), ); diff --git a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts index bcc2d19db..a18b36945 100644 --- a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts +++ b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts @@ -27,6 +27,14 @@ export const _moveDataStatements = ( const compositePKs = Object.values( json.tables[tableName].compositePrimaryKeys, ).map((it) => SQLiteSquasher.unsquashPK(it)); + const checkConstraints = Object.values(json.tables[tableName].checkConstraints); + + const mappedCheckConstraints: string[] = checkConstraints.map((it) => + it.replaceAll(`"${tableName}".`, `"${newTableName}".`) + .replaceAll(`\`${tableName}\`.`, `\`${newTableName}\`.`) + .replaceAll(`${tableName}.`, `${newTableName}.`) + .replaceAll(`'${tableName}'.`, `\`${newTableName}\`.`) + ); const fks = referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)); @@ -38,6 +46,7 @@ export const _moveDataStatements = ( columns: tableColumns, referenceData: fks, compositePKs, + checkConstraints: mappedCheckConstraints, }), ); diff --git a/drizzle-kit/src/introspect-sqlite.ts b/drizzle-kit/src/introspect-sqlite.ts index b4a729f4c..fe1a5f250 100644 --- a/drizzle-kit/src/introspect-sqlite.ts +++ b/drizzle-kit/src/introspect-sqlite.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-argument */ import './@types/utils'; import type { Casing } from './cli/validations/common'; +import { CheckConstraint } from './serializer/mysqlSchema'; import type { Column, ForeignKey, @@ -78,11 +79,15 @@ export const schemaToTypeScript = ( const uniqueImports = Object.values(it.uniqueConstraints).map( (it) => 'unique', ); + const checkImports = Object.values(it.checkConstraints).map( + (it) => 'check', + ); res.sqlite.push(...idxImports); res.sqlite.push(...fkImpots); res.sqlite.push(...pkImports); res.sqlite.push(...uniqueImports); + res.sqlite.push(...checkImports); const columnImports = Object.values(it.columns) .map((col) => { @@ -127,6 +132,7 @@ export const schemaToTypeScript = ( || filteredFKs.length > 0 || Object.keys(table.compositePrimaryKeys).length > 0 || Object.keys(table.uniqueConstraints).length > 0 + || Object.keys(table.checkConstraints).length > 0 ) { statement += ',\n'; statement += '(table) => {\n'; @@ -145,6 +151,10 @@ export const schemaToTypeScript = ( Object.values(table.uniqueConstraints), casing, ); + statement += createTableChecks( + Object.values(table.checkConstraints), + casing, + ); statement += '\t}\n'; statement += '}'; } @@ -401,6 +411,24 @@ const createTableUniques = ( return statement; }; +const createTableChecks = ( + checks: CheckConstraint[], + casing: Casing, +): string => { + let statement = ''; + + checks.forEach((it) => { + const checkKey = withCasing(it.name, casing); + + statement += `\t\t${checkKey}: `; + statement += 'check('; + statement += `"${it.name}", `; + statement += `sql\`${it.value}\`)`; + statement += `,\n`; + }); + + return statement; +}; const createTablePKs = (pks: PrimaryKey[], casing: Casing): string => { let statement = ''; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 6bdaf059d..4546dd78d 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -27,6 +27,7 @@ export interface JsonSqliteCreateTableStatement { }[]; compositePKs: string[][]; uniqueConstraints?: string[]; + checkConstraints?: string[]; } export interface JsonCreateTableStatement { @@ -56,6 +57,7 @@ export interface JsonRecreateTableStatement { }[]; compositePKs: string[][]; uniqueConstraints?: string[]; + checkConstraints: string[]; } export interface JsonDropTableStatement { @@ -661,7 +663,7 @@ export const prepareSQLiteCreateTable = ( table: Table, action?: 'push' | undefined, ): JsonSqliteCreateTableStatement => { - const { name, columns, uniqueConstraints } = table; + const { name, columns, uniqueConstraints, checkConstraints } = table; const references: string[] = Object.values(table.foreignKeys); @@ -682,6 +684,7 @@ export const prepareSQLiteCreateTable = ( referenceData: fks, compositePKs: composites, uniqueConstraints: Object.values(uniqueConstraints), + checkConstraints: Object.values(checkConstraints), }; }; diff --git a/drizzle-kit/src/serializer/mysqlSchema.ts b/drizzle-kit/src/serializer/mysqlSchema.ts index 731fd579b..17fd8c6f9 100644 --- a/drizzle-kit/src/serializer/mysqlSchema.ts +++ b/drizzle-kit/src/serializer/mysqlSchema.ts @@ -161,6 +161,7 @@ const tableSquashed = object({ foreignKeys: record(string(), string()), compositePrimaryKeys: record(string(), string()), uniqueConstraints: record(string(), string()).default({}), + checkConstraints: record(string(), string()).default({}), }).strict(); export const schemaSquashed = object({ diff --git a/drizzle-kit/src/serializer/sqliteSchema.ts b/drizzle-kit/src/serializer/sqliteSchema.ts index a8114e3a8..c728d4cc5 100644 --- a/drizzle-kit/src/serializer/sqliteSchema.ts +++ b/drizzle-kit/src/serializer/sqliteSchema.ts @@ -1,5 +1,5 @@ import { any, boolean, enum as enumType, literal, object, record, string, TypeOf, union } from 'zod'; -import { customMapEntries, mapEntries, mapValues, originUUID } from '../global'; +import { customMapEntries, mapValues, originUUID } from '../global'; // ------- V3 -------- const index = object({ @@ -49,6 +49,11 @@ const uniqueConstraint = object({ columns: string().array(), }).strict(); +const checkConstraint = object({ + name: string(), + value: string(), +}).strict(); + const table = object({ name: string(), columns: record(string(), column), @@ -56,6 +61,7 @@ const table = object({ foreignKeys: record(string(), fk), compositePrimaryKeys: record(string(), compositePK), uniqueConstraints: record(string(), uniqueConstraint).default({}), + checkConstraints: record(string(), checkConstraint).default({}), }).strict(); // use main dialect @@ -128,6 +134,7 @@ const tableSquashed = object({ foreignKeys: record(string(), string()), compositePrimaryKeys: record(string(), string()), uniqueConstraints: record(string(), string()).default({}), + checkConstraints: record(string(), string()).default({}), }).strict(); export const schemaSquashed = object({ @@ -150,6 +157,7 @@ export type Index = TypeOf; export type ForeignKey = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; +export type CheckConstraint = TypeOf; export const SQLiteSquasher = { squashIdx: (idx: Index) => { @@ -233,6 +241,17 @@ export const SQLiteSquasher = { unsquashPK: (pk: string) => { return pk.split(','); }, + squashCheck: (check: CheckConstraint) => { + return `${check.name};${check.value}`; + }, + unsquashCheck: (input: string): CheckConstraint => { + const [ + name, + value, + ] = input.split(';'); + + return { name, value }; + }, }; export const squashSqliteScheme = ( @@ -268,6 +287,13 @@ export const squashSqliteScheme = ( }, ); + const squashedCheckConstraints = mapValues( + it[1].checkConstraints, + (check) => { + return SQLiteSquasher.squashCheck(check); + }, + ); + return [ it[0], { @@ -277,6 +303,7 @@ export const squashSqliteScheme = ( foreignKeys: squashedFKs, compositePrimaryKeys: squashedPKs, uniqueConstraints: squashedUniqueConstraints, + checkConstraints: squashedCheckConstraints, }, ]; }), diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 41edd78a9..e8ca76269 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -11,6 +11,7 @@ import { import { withStyle } from '../cli/validations/outputs'; import type { IntrospectStage, IntrospectStatus } from '../cli/views'; import type { + CheckConstraint, Column, ForeignKey, Index, @@ -37,11 +38,15 @@ export const generateSqliteSnapshot = ( const foreignKeysObject: Record = {}; const primaryKeysObject: Record = {}; const uniqueConstraintObject: Record = {}; + const checkConstraintObject: Record = {}; + + const checksInTable: Record = {}; const { name: tableName, columns, indexes, + checks, foreignKeys: tableForeignKeys, primaryKeys, uniqueConstraints, @@ -245,6 +250,38 @@ export const generateSqliteSnapshot = ( } }); + checks.forEach((check) => { + const checkName = check.name; + if (typeof checksInTable[tableName] !== 'undefined') { + if (checksInTable[tableName].includes(check.name)) { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated check constraint name in ${ + chalk.underline.blue( + tableName, + ) + }. Please rename your check constraint in the ${ + chalk.underline.blue( + tableName, + ) + } table`, + ) + }`, + ); + process.exit(1); + } + checksInTable[tableName].push(checkName); + } else { + checksInTable[tableName] = [check.name]; + } + + checkConstraintObject[checkName] = { + name: checkName, + value: dialect.sqlToQuery(check.value).sql, + }; + }); + result[tableName] = { name: tableName, columns: columnsObject, @@ -252,6 +289,7 @@ export const generateSqliteSnapshot = ( foreignKeys: foreignKeysObject, compositePrimaryKeys: primaryKeysObject, uniqueConstraints: uniqueConstraintObject, + checkConstraints: checkConstraintObject, }; } @@ -500,6 +538,7 @@ export const fromDatabase = async ( indexes: {}, foreignKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }; } else { result[tableName]!.columns[columnName] = newColumn; @@ -670,6 +709,56 @@ WHERE progressCallback('enums', 0, 'done'); } + const namedCheckPattern = /CONSTRAINT\s*["']?(\w+)["']?\s*CHECK\s*\((.*?)\)/gi; + const unnamedCheckPattern = /CHECK\s*\((.*?)\)/gi; + let checkCounter = 0; + const checkConstraints: Record = {}; + const checks = await db.query<{ tableName: string; sql: string }>(`SELECT name as "tableName", sql as "sql" + FROM sqlite_master + WHERE type = 'table' AND name != 'sqlite_sequence';`); + for (const check of checks) { + if (!tablesFilter(check.tableName)) continue; + + const { tableName, sql } = check; + + // Find named CHECK constraints + let namedChecks = [...sql.matchAll(namedCheckPattern)]; + if (namedChecks.length > 0) { + namedChecks.forEach(([_, checkName, checkValue]) => { + checkConstraints[checkName] = { + name: checkName, + value: checkValue.trim(), + }; + }); + } else { + // If no named constraints, find unnamed CHECK constraints and assign names + let unnamedChecks = [...sql.matchAll(unnamedCheckPattern)]; + unnamedChecks.forEach(([_, checkValue]) => { + let checkName = `${tableName}_check_${++checkCounter}`; + checkConstraints[checkName] = { + name: checkName, + value: checkValue.trim(), + }; + }); + } + + const table = result[tableName]; + + if (!table) { + result[tableName] = { + name: tableName, + columns: {}, + compositePrimaryKeys: {}, + indexes: {}, + foreignKeys: {}, + uniqueConstraints: {}, + checkConstraints: checkConstraints, + }; + } else { + result[tableName]!.checkConstraints = checkConstraints; + } + } + return { version: '6', dialect: 'sqlite', diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 5ef68153a..a15d8b613 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -1436,7 +1436,7 @@ export const applyMysqlSnapshotsDiff = async ( const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; - const jsonAddedCheckConstraints: JsonCreateCheckConstraint[] = []; + const jsonCreatedCheckConstraints: JsonCreateCheckConstraint[] = []; const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames @@ -1556,7 +1556,7 @@ export const applyMysqlSnapshotsDiff = async ( jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); - jsonAddedCheckConstraints.push(...createdCheckConstraints); + jsonCreatedCheckConstraints.push(...createdCheckConstraints); jsonDeletedCheckConstraints.push(...deletedCheckConstraints); }); @@ -1678,6 +1678,7 @@ export const applyMysqlSnapshotsDiff = async ( jsonStatements.push(...jsonRenameColumnsStatements); jsonStatements.push(...jsonDeletedUniqueConstraints); + jsonStatements.push(...jsonDeletedCheckConstraints); jsonStatements.push(...jsonDroppedReferencesForAlteredTables); @@ -1692,13 +1693,11 @@ export const applyMysqlSnapshotsDiff = async ( jsonStatements.push(...jsonAddedUniqueConstraints); jsonStatements.push(...jsonDeletedUniqueConstraints); - jsonStatements.push(...jsonAddedCheckConstraints); - jsonStatements.push(...jsonDeletedCheckConstraints); - jsonStatements.push(...jsonAddColumnsStatemets); jsonStatements.push(...jsonCreateReferencesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForCreatedTables); + jsonStatements.push(...jsonCreatedCheckConstraints); jsonStatements.push(...jsonCreatedReferencesForAlteredTables); jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); @@ -1709,8 +1708,6 @@ export const applyMysqlSnapshotsDiff = async ( // jsonStatements.push(...jsonAddedCompositePKs); jsonStatements.push(...jsonAlteredCompositePKs); - jsonStatements.push(...jsonAddedUniqueConstraints); - jsonStatements.push(...jsonAlteredUniqueConstraints); const sqlStatements = fromJson(jsonStatements, 'mysql'); @@ -1922,6 +1919,9 @@ export const applySqliteSnapshotsDiff = async ( const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + const jsonCreatedCheckConstraints: JsonCreateCheckConstraint[] = []; + allAltered.forEach((it) => { // This part is needed to make sure that same columns in a table are not triggered for change // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name @@ -1992,6 +1992,54 @@ export const applySqliteSnapshotsDiff = async ( ); } + let createdCheckConstraints: JsonCreateCheckConstraint[] = []; + let deletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + + addedUniqueConstraints = prepareAddUniqueConstraint( + it.name, + it.schema, + it.addedUniqueConstraints, + ); + deletedUniqueConstraints = prepareDeleteUniqueConstraint( + it.name, + it.schema, + it.deletedUniqueConstraints, + ); + if (it.alteredUniqueConstraints) { + const added: Record = {}; + const deleted: Record = {}; + for (const k of Object.keys(it.alteredUniqueConstraints)) { + added[k] = it.alteredUniqueConstraints[k].__new; + deleted[k] = it.alteredUniqueConstraints[k].__old; + } + addedUniqueConstraints.push( + ...prepareAddUniqueConstraint(it.name, it.schema, added), + ); + deletedUniqueConstraints.push( + ...prepareDeleteUniqueConstraint(it.name, it.schema, deleted), + ); + } + + createdCheckConstraints = prepareAddCheckConstraint(it.name, it.schema, it.addedCheckConstraints); + deletedCheckConstraints = prepareDeleteCheckConstraint( + it.name, + it.schema, + it.deletedCheckConstraints, + ); + + // skip for push + if (it.alteredCheckConstraints && action !== 'push') { + const added: Record = {}; + const deleted: Record = {}; + + for (const k of Object.keys(it.alteredCheckConstraints)) { + added[k] = it.alteredCheckConstraints[k].__new; + deleted[k] = it.alteredCheckConstraints[k].__old; + } + createdCheckConstraints.push(...prepareAddCheckConstraint(it.name, it.schema, added)); + deletedCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); + } + jsonAddedCompositePKs.push(...addedCompositePKs); jsonDeletedCompositePKs.push(...deletedCompositePKs); jsonAlteredCompositePKs.push(...alteredCompositePKs); @@ -1999,6 +2047,9 @@ export const applySqliteSnapshotsDiff = async ( jsonAddedUniqueConstraints.push(...addedUniqueConstraints); jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + + jsonCreatedCheckConstraints.push(...createdCheckConstraints); + jsonDeletedCheckConstraints.push(...deletedCheckConstraints); }); const rColumns = jsonRenameColumnsStatements.map((it) => { @@ -2105,6 +2156,7 @@ export const applySqliteSnapshotsDiff = async ( jsonStatements.push(...jsonRenameColumnsStatements); jsonStatements.push(...jsonDroppedReferencesForAlteredTables); + jsonStatements.push(...jsonDeletedCheckConstraints); // Will need to drop indexes before changing any columns in table // Then should go column alternations and then index creation @@ -2118,6 +2170,8 @@ export const applySqliteSnapshotsDiff = async ( jsonStatements.push(...jsonCreateIndexesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); + jsonStatements.push(...jsonCreatedCheckConstraints); + jsonStatements.push(...jsonCreatedReferencesForAlteredTables); jsonStatements.push(...jsonDropColumnsStatemets); @@ -2352,6 +2406,9 @@ export const applyLibSQLSnapshotsDiff = async ( const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + const jsonCreatedCheckConstraints: JsonCreateCheckConstraint[] = []; + allAltered.forEach((it) => { // This part is needed to make sure that same columns in a table are not triggered for change // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name @@ -2397,6 +2454,9 @@ export const applyLibSQLSnapshotsDiff = async ( let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + let createdCheckConstraints: JsonCreateCheckConstraint[] = []; + let deletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + addedUniqueConstraints = prepareAddUniqueConstraint( it.name, it.schema, @@ -2423,6 +2483,26 @@ export const applyLibSQLSnapshotsDiff = async ( ); } + createdCheckConstraints = prepareAddCheckConstraint(it.name, it.schema, it.addedCheckConstraints); + deletedCheckConstraints = prepareDeleteCheckConstraint( + it.name, + it.schema, + it.deletedCheckConstraints, + ); + + // skip for push + if (it.alteredCheckConstraints && action !== 'push') { + const added: Record = {}; + const deleted: Record = {}; + + for (const k of Object.keys(it.alteredCheckConstraints)) { + added[k] = it.alteredCheckConstraints[k].__new; + deleted[k] = it.alteredCheckConstraints[k].__old; + } + createdCheckConstraints.push(...prepareAddCheckConstraint(it.name, it.schema, added)); + deletedCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); + } + jsonAddedCompositePKs.push(...addedCompositePKs); jsonDeletedCompositePKs.push(...deletedCompositePKs); jsonAlteredCompositePKs.push(...alteredCompositePKs); @@ -2430,6 +2510,9 @@ export const applyLibSQLSnapshotsDiff = async ( jsonAddedUniqueConstraints.push(...addedUniqueConstraints); jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + + jsonCreatedCheckConstraints.push(...createdCheckConstraints); + jsonDeletedCheckConstraints.push(...deletedCheckConstraints); }); const jsonTableAlternations = allAltered @@ -2529,6 +2612,8 @@ export const applyLibSQLSnapshotsDiff = async ( jsonStatements.push(...jsonDroppedReferencesForAlteredTables); + jsonStatements.push(...jsonDeletedCheckConstraints); + // Will need to drop indexes before changing any columns in table // Then should go column alternations and then index creation jsonStatements.push(...jsonDropIndexesForAllAlteredTables); @@ -2541,6 +2626,8 @@ export const applyLibSQLSnapshotsDiff = async ( jsonStatements.push(...jsonCreateIndexesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); + jsonStatements.push(...jsonCreatedCheckConstraints); + jsonStatements.push(...jsonCreatedReferencesForAlteredTables); jsonStatements.push(...jsonDropColumnsStatemets); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 0ae0f782c..39355683b 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -346,6 +346,7 @@ export class SQLiteCreateTableConvertor extends Convertor { referenceData, compositePKs, uniqueConstraints, + checkConstraints, } = st; let statement = ''; @@ -405,11 +406,22 @@ export class SQLiteCreateTableConvertor extends Convertor { ) { for (const uniqueConstraint of uniqueConstraints) { statement += ',\n'; - const unsquashedUnique = MySqlSquasher.unsquashUnique(uniqueConstraint); + const unsquashedUnique = SQLiteSquasher.unsquashUnique(uniqueConstraint); statement += `\tCONSTRAINT ${unsquashedUnique.name} UNIQUE(\`${unsquashedUnique.columns.join(`\`,\``)}\`)`; } } + if ( + typeof checkConstraints !== 'undefined' + && checkConstraints.length > 0 + ) { + for (const check of checkConstraints) { + statement += ',\n'; + const { value, name } = SQLiteSquasher.unsquashCheck(check); + statement += `\tCONSTRAINT "${name}" CHECK(${value})`; + } + } + statement += `\n`; statement += `);`; statement += `\n`; @@ -1530,7 +1542,9 @@ export class LibSQLModifyColumn extends Convertor { || statement.type === 'alter_table_alter_column_drop_notnull' || statement.type === 'alter_table_alter_column_set_notnull' || statement.type === 'alter_table_alter_column_set_default' - || statement.type === 'alter_table_alter_column_drop_default') + || statement.type === 'alter_table_alter_column_drop_default' + || statement.type === 'create_check_constraint' + || statement.type === 'delete_check_constraint') && dialect === 'turso' ); } @@ -2448,7 +2462,7 @@ class SQLiteRecreateTableConvertor extends Convertor { } convert(statement: JsonRecreateTableStatement): string | string[] { - const { tableName, columns, compositePKs, referenceData } = statement; + const { tableName, columns, compositePKs, referenceData, checkConstraints } = statement; const columnNames = columns.map((it) => `"${it.name}"`).join(', '); const newTableName = `__new_${tableName}`; @@ -2457,6 +2471,12 @@ class SQLiteRecreateTableConvertor extends Convertor { sqlStatements.push(`PRAGMA foreign_keys=OFF;`); + // map all possible variants + const mappedCheckConstraints: string[] = checkConstraints.map((it) => + it.replaceAll(`"${tableName}".`, `"${newTableName}".`).replaceAll(`\`${tableName}\`.`, `\`${newTableName}\`.`) + .replaceAll(`${tableName}.`, `${newTableName}.`).replaceAll(`'${tableName}'.`, `'${newTableName}'.`) + ); + // create new table sqlStatements.push( new SQLiteCreateTableConvertor().convert({ @@ -2465,6 +2485,7 @@ class SQLiteRecreateTableConvertor extends Convertor { columns, referenceData, compositePKs, + checkConstraints: mappedCheckConstraints, }), ); @@ -2508,13 +2529,18 @@ class LibSQLRecreateTableConvertor extends Convertor { } convert(statement: JsonRecreateTableStatement): string[] { - const { tableName, columns, compositePKs, referenceData } = statement; + const { tableName, columns, compositePKs, referenceData, checkConstraints } = statement; const columnNames = columns.map((it) => `"${it.name}"`).join(', '); const newTableName = `__new_${tableName}`; const sqlStatements: string[] = []; + const mappedCheckConstraints: string[] = checkConstraints.map((it) => + it.replaceAll(`"${tableName}".`, `"${newTableName}".`).replaceAll(`\`${tableName}\`.`, `\`${newTableName}\`.`) + .replaceAll(`${tableName}.`, `${newTableName}.`).replaceAll(`'${tableName}'.`, `\`${newTableName}\`.`) + ); + sqlStatements.push(`PRAGMA foreign_keys=OFF;`); // create new table @@ -2525,6 +2551,7 @@ class LibSQLRecreateTableConvertor extends Convertor { columns, referenceData, compositePKs, + checkConstraints: mappedCheckConstraints, }), ); diff --git a/drizzle-kit/src/statementCombiner.ts b/drizzle-kit/src/statementCombiner.ts index 2f7b6ddbe..f3ca9789c 100644 --- a/drizzle-kit/src/statementCombiner.ts +++ b/drizzle-kit/src/statementCombiner.ts @@ -10,7 +10,7 @@ export const prepareLibSQLRecreateTable = ( table: SQLiteSchemaSquashed['tables'][keyof SQLiteSchemaSquashed['tables']], action?: 'push', ): (JsonRecreateTableStatement | JsonCreateIndexStatement)[] => { - const { name, columns, uniqueConstraints, indexes } = table; + const { name, columns, uniqueConstraints, indexes, checkConstraints } = table; const composites: string[][] = Object.values(table.compositePrimaryKeys).map( (it) => SQLiteSquasher.unsquashPK(it), @@ -29,6 +29,7 @@ export const prepareLibSQLRecreateTable = ( compositePKs: composites, referenceData: fks, uniqueConstraints: Object.values(uniqueConstraints), + checkConstraints: Object.values(checkConstraints), }, ]; @@ -42,7 +43,7 @@ export const prepareSQLiteRecreateTable = ( table: SQLiteSchemaSquashed['tables'][keyof SQLiteSchemaSquashed['tables']], action?: 'push', ): JsonStatement[] => { - const { name, columns, uniqueConstraints, indexes } = table; + const { name, columns, uniqueConstraints, indexes, checkConstraints } = table; const composites: string[][] = Object.values(table.compositePrimaryKeys).map( (it) => SQLiteSquasher.unsquashPK(it), @@ -61,6 +62,7 @@ export const prepareSQLiteRecreateTable = ( compositePKs: composites, referenceData: fks, uniqueConstraints: Object.values(uniqueConstraints), + checkConstraints: Object.values(checkConstraints), }, ]; @@ -86,6 +88,8 @@ export const libSQLCombineStatements = ( || statement.type === 'create_composite_pk' || statement.type === 'alter_composite_pk' || statement.type === 'delete_composite_pk' + || statement.type === 'create_check_constraint' + || statement.type === 'delete_check_constraint' ) { const tableName = statement.tableName; @@ -122,16 +126,6 @@ export const libSQLCombineStatements = ( ) { const { tableName, columnName, columnPk } = statement; - // const columnIsPartOfUniqueIndex = Object.values( - // json2.tables[tableName].indexes, - // ).some((it) => { - // const unsquashIndex = SQLiteSquasher.unsquashIdx(it); - - // return ( - // unsquashIndex.columns.includes(columnName) && unsquashIndex.isUnique - // ); - // }); - const columnIsPartOfForeignKey = Object.values( json2.tables[tableName].foreignKeys, ).some((it) => { @@ -332,19 +326,21 @@ export const sqliteCombineStatements = ( || statement.type === 'delete_composite_pk' || statement.type === 'create_unique_constraint' || statement.type === 'delete_unique_constraint' + || statement.type === 'create_check_constraint' + || statement.type === 'delete_check_constraint' ) { const tableName = statement.tableName; const statementsForTable = newStatements[tableName]; if (!statementsForTable) { - newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + newStatements[tableName] = prepareSQLiteRecreateTable(json2.tables[tableName], action); continue; } if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); - const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + const preparedStatements = prepareSQLiteRecreateTable(json2.tables[tableName], action); if (wasRename) { newStatements[tableName].push(...preparedStatements); @@ -364,13 +360,13 @@ export const sqliteCombineStatements = ( const statementsForTable = newStatements[tableName]; if (!statementsForTable) { - newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + newStatements[tableName] = prepareSQLiteRecreateTable(json2.tables[tableName], action); continue; } if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); - const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + const preparedStatements = prepareSQLiteRecreateTable(json2.tables[tableName], action); if (wasRename) { newStatements[tableName].push(...preparedStatements); @@ -409,7 +405,7 @@ export const sqliteCombineStatements = ( if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); - const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + const preparedStatements = prepareSQLiteRecreateTable(json2.tables[tableName], action); if (wasRename) { newStatements[tableName].push(...preparedStatements); diff --git a/drizzle-kit/tests/libsql-checks.test.ts b/drizzle-kit/tests/libsql-checks.test.ts new file mode 100644 index 000000000..2a3abf2dc --- /dev/null +++ b/drizzle-kit/tests/libsql-checks.test.ts @@ -0,0 +1,308 @@ +import { sql } from 'drizzle-orm'; +import { check, int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasLibSQL } from './schemaDiffer'; + +test('create table with check', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasLibSQL({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_create_table', + tableName: 'users', + columns: [ + { + name: 'id', + type: 'integer', + notNull: true, + primaryKey: true, + autoincrement: false, + }, + { + name: 'age', + type: 'integer', + notNull: false, + primaryKey: false, + autoincrement: false, + }, + ], + compositePKs: [], + checkConstraints: ['some_check_name;"users"."age" > 21'], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("users"."age" > 21) +);\n`); +}); + +test('add check contraint to existing table', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }), + }; + + const { sqlStatements, statements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: ['some_check_name;"users"."age" > 21'], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('drop check contraint to existing table', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }), + }; + + const { sqlStatements, statements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('rename check constraint', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('new_some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [`new_some_check_name;"users"."age" > 21`], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "new_some_check_name" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('rename check constraint', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 10`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [`some_check_name;"users"."age" > 10`], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("__new_users"."age" > 10) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('create checks with same names', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + name: text('name'), + }, (table) => ({ + checkConstraint1: check('some_check_name', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name', sql`${table.name} != 'Alex'`), + })), + }; + + await expect(diffTestSchemasLibSQL({}, to, [])).rejects.toThrowError(); +}); diff --git a/drizzle-kit/tests/libsql-statements.test.ts b/drizzle-kit/tests/libsql-statements.test.ts index 8221e52e0..a7cbc0602 100644 --- a/drizzle-kit/tests/libsql-statements.test.ts +++ b/drizzle-kit/tests/libsql-statements.test.ts @@ -33,6 +33,7 @@ test('drop autoincrement', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -66,6 +67,7 @@ test('set autoincrement', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -427,6 +429,7 @@ test('drop foriegn key', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); @@ -512,6 +515,7 @@ test('alter foriegn key', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); @@ -615,6 +619,7 @@ test('add foriegn key for multiple columns', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], } as JsonRecreateTableStatement); expect(sqlStatements.length).toBe(6); @@ -709,6 +714,7 @@ test('drop foriegn key for multiple columns', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); @@ -850,6 +856,7 @@ test('recreate table with nested references', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); diff --git a/drizzle-kit/tests/mysql-checks.test.ts b/drizzle-kit/tests/mysql-checks.test.ts new file mode 100644 index 000000000..82e7a5104 --- /dev/null +++ b/drizzle-kit/tests/mysql-checks.test.ts @@ -0,0 +1,291 @@ +import { sql } from 'drizzle-orm'; +import { check, int, mysqlTable, serial, varchar } from 'drizzle-orm/mysql-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasMysql } from './schemaDiffer'; + +test('create table with check', async (t) => { + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + columns: [ + { + name: 'id', + type: 'serial', + notNull: true, + primaryKey: false, + autoincrement: true, + }, + { + name: 'age', + type: 'int', + notNull: false, + primaryKey: false, + autoincrement: false, + }, + ], + compositePKs: [ + 'users_id;id', + ], + checkConstraints: ['some_check_name;\`users\`.\`age\` > 21'], + compositePkName: 'users_id', + uniqueConstraints: [], + schema: undefined, + internals: { + tables: {}, + indexes: {}, + }, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` serial AUTO_INCREMENT NOT NULL, +\t\`age\` int, +\tCONSTRAINT \`users_id\` PRIMARY KEY(\`id\`), +\tCONSTRAINT \`some_check_name\` CHECK(\`users\`.\`age\` > 21) +);\n`); +}); + +test('add check contraint to existing table', async (t) => { + const from = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }), + }; + + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_check_constraint', + tableName: 'users', + data: 'some_check_name;\`users\`.\`age\` > 21', + schema: '', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ADD CONSTRAINT \`some_check_name\` CHECK (\`users\`.\`age\` > 21);`, + ); +}); + +test('drop check contraint in existing table', async (t) => { + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }), + }; + + const from = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'delete_check_constraint', + tableName: 'users', + schema: '', + constraintName: 'some_check_name', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` DROP CONSTRAINT \`some_check_name\`;`, + ); +}); + +test('rename check constraint', async (t) => { + const from = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('new_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + constraintName: 'some_check_name', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + data: 'new_check_name;\`users\`.\`age\` > 21', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` DROP CONSTRAINT \`some_check_name\`;`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`users\` ADD CONSTRAINT \`new_check_name\` CHECK (\`users\`.\`age\` > 21);`, + ); +}); + +test('alter check constraint', async (t) => { + const from = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('new_check_name', sql`${table.age} > 10`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql(from, to, []); + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + constraintName: 'some_check_name', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + data: 'new_check_name;\`users\`.\`age\` > 10', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` DROP CONSTRAINT \`some_check_name\`;`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`users\` ADD CONSTRAINT \`new_check_name\` CHECK (\`users\`.\`age\` > 10);`, + ); +}); + +test('alter multiple check constraints', async (t) => { + const from = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + name: varchar('name', { length: 255 }), + }, (table) => ({ + checkConstraint1: check('some_check_name_1', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name_2', sql`${table.name} != 'Alex'`), + })), + }; + + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + name: varchar('name', { length: 255 }), + }, (table) => ({ + checkConstraint1: check('some_check_name_3', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name_4', sql`${table.name} != 'Alex'`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql(from, to, []); + expect(statements.length).toBe(4); + expect(statements[0]).toStrictEqual({ + constraintName: 'some_check_name_1', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + constraintName: 'some_check_name_2', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[2]).toStrictEqual({ + data: 'some_check_name_3;\`users\`.\`age\` > 21', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + expect(statements[3]).toStrictEqual({ + data: "some_check_name_4;\`users\`.\`name\` != 'Alex'", + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` DROP CONSTRAINT \`some_check_name_1\`;`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`users\` DROP CONSTRAINT \`some_check_name_2\`;`, + ); + expect(sqlStatements[2]).toBe( + `ALTER TABLE \`users\` ADD CONSTRAINT \`some_check_name_3\` CHECK (\`users\`.\`age\` > 21);`, + ); + expect(sqlStatements[3]).toBe( + `ALTER TABLE \`users\` ADD CONSTRAINT \`some_check_name_4\` CHECK (\`users\`.\`name\` != \'Alex\');`, + ); +}); + +test('create checks with same names', async (t) => { + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + name: varchar('name', { length: 255 }), + }, (table) => ({ + checkConstraint1: check('some_check_name', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name', sql`${table.name} != 'Alex'`), + })), + }; + + await expect(diffTestSchemasMysql({}, to, [])).rejects.toThrowError(); +}); diff --git a/drizzle-kit/tests/mysql-schemas.test.ts b/drizzle-kit/tests/mysql-schemas.test.ts index 826585d86..6776700e3 100644 --- a/drizzle-kit/tests/mysql-schemas.test.ts +++ b/drizzle-kit/tests/mysql-schemas.test.ts @@ -129,6 +129,7 @@ test('add table to schema #3', async () => { }, compositePkName: '', compositePKs: [], + checkConstraints: [], }); }); diff --git a/drizzle-kit/tests/mysql.test.ts b/drizzle-kit/tests/mysql.test.ts index e7b0b32a5..37e9ccb56 100644 --- a/drizzle-kit/tests/mysql.test.ts +++ b/drizzle-kit/tests/mysql.test.ts @@ -23,6 +23,7 @@ test('add table #1', async () => { }, uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); }); @@ -52,6 +53,7 @@ test('add table #2', async () => { compositePKs: ['users_id;id'], compositePkName: 'users_id', uniqueConstraints: [], + checkConstraints: [], internals: { tables: {}, indexes: {}, @@ -96,6 +98,7 @@ test('add table #3', async () => { compositePKs: ['users_pk;id'], uniqueConstraints: [], compositePkName: 'users_pk', + checkConstraints: [], internals: { tables: {}, indexes: {}, @@ -124,6 +127,7 @@ test('add table #4', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'create_table', @@ -137,6 +141,7 @@ test('add table #4', async () => { }, uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); }); @@ -180,6 +185,7 @@ test('add table #6', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'drop_table', @@ -215,6 +221,7 @@ test('add table #7', async () => { indexes: {}, }, compositePkName: '', + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'rename_table', @@ -304,6 +311,7 @@ test('change table schema #2', async () => { uniqueConstraints: [], compositePkName: '', compositePKs: [], + checkConstraints: [], internals: { tables: {}, indexes: {}, diff --git a/drizzle-kit/tests/pg-checks.test.ts b/drizzle-kit/tests/pg-checks.test.ts index 1f12e76a3..1f5e5e1c5 100644 --- a/drizzle-kit/tests/pg-checks.test.ts +++ b/drizzle-kit/tests/pg-checks.test.ts @@ -104,7 +104,7 @@ test('drop check contraint in existing table', async (t) => { type: 'delete_check_constraint', tableName: 'users', schema: '', - data: 'some_check_name;"users"."age" > 21', + constraintName: 'some_check_name', }); expect(sqlStatements.length).toBe(1); @@ -135,7 +135,7 @@ test('rename check constraint', async (t) => { const { sqlStatements, statements } = await diffTestSchemas(from, to, []); expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ - data: 'some_check_name;"users"."age" > 21', + constraintName: 'some_check_name', schema: '', tableName: 'users', type: 'delete_check_constraint', @@ -178,7 +178,7 @@ test('alter check constraint', async (t) => { const { sqlStatements, statements } = await diffTestSchemas(from, to, []); expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ - data: 'some_check_name;"users"."age" > 21', + constraintName: 'some_check_name', schema: '', tableName: 'users', type: 'delete_check_constraint', @@ -225,13 +225,13 @@ test('alter multiple check constraints', async (t) => { const { sqlStatements, statements } = await diffTestSchemas(from, to, []); expect(statements.length).toBe(4); expect(statements[0]).toStrictEqual({ - data: 'some_check_name_1;"users"."age" > 21', + constraintName: 'some_check_name_1', schema: '', tableName: 'users', type: 'delete_check_constraint', }); expect(statements[1]).toStrictEqual({ - data: 'some_check_name_2;"users"."name" != \'Alex\'', + constraintName: 'some_check_name_2', schema: '', tableName: 'users', type: 'delete_check_constraint', diff --git a/drizzle-kit/tests/pg-identity.test.ts b/drizzle-kit/tests/pg-identity.test.ts index 906d812d4..7e0854b67 100644 --- a/drizzle-kit/tests/pg-identity.test.ts +++ b/drizzle-kit/tests/pg-identity.test.ts @@ -48,6 +48,7 @@ test('create table: identity always/by default - no params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -86,6 +87,7 @@ test('create table: identity always/by default - few params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -128,6 +130,7 @@ test('create table: identity always/by default - all params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index 4171af333..83d8e16ee 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -32,6 +32,7 @@ test('add table #1', async () => { columns: [], compositePKs: [], uniqueConstraints: [], + checkConstraints: [], compositePkName: '', }); }); @@ -60,6 +61,7 @@ test('add table #2', async () => { ], compositePKs: [], uniqueConstraints: [], + checkConstraints: [], compositePkName: '', }); }); @@ -99,6 +101,7 @@ test('add table #3', async () => { ], compositePKs: ['id;users_pk'], uniqueConstraints: [], + checkConstraints: [], compositePkName: 'users_pk', }); }); @@ -119,6 +122,7 @@ test('add table #4', async () => { columns: [], compositePKs: [], uniqueConstraints: [], + checkConstraints: [], compositePkName: '', }); expect(statements[1]).toStrictEqual({ @@ -128,6 +132,7 @@ test('add table #4', async () => { columns: [], compositePKs: [], uniqueConstraints: [], + checkConstraints: [], compositePkName: '', }); }); @@ -154,6 +159,7 @@ test('add table #5', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); }); @@ -177,6 +183,7 @@ test('add table #6', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'drop_table', @@ -208,6 +215,7 @@ test('add table #7', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'rename_table', @@ -264,6 +272,7 @@ test('multiproject schema add table #1', async () => { compositePKs: [], compositePkName: '', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -357,6 +366,7 @@ test('add schema + table #1', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); }); diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 89ec008ca..476faa4f9 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -3,6 +3,7 @@ import chalk from 'chalk'; import { sql } from 'drizzle-orm'; import { blob, + check, foreignKey, getTableConfig, index, @@ -389,6 +390,7 @@ test('drop autoincrement. drop column with data', async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(4); @@ -491,6 +493,7 @@ test('change autoincrement. table is part of foreign key', async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(4); @@ -752,6 +755,7 @@ test('recreate table with nested references', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(4); @@ -860,6 +864,7 @@ test('recreate table with added column not null and without default', async (t) tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(4); @@ -1047,3 +1052,244 @@ test('drop not null with two indexes', async (t) => { expect(tablesToRemove!.length).toBe(0); expect(tablesToTruncate!.length).toBe(0); }); + +test('add check constraint to table', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: ['some_check;"users"."age" > 21'], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer, +\tCONSTRAINT "some_check" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[1]).toBe( + 'INSERT INTO `__new_users`("id", "name", "age") SELECT "id", "name", "age" FROM `users`;', + ); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop check constraint', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer +);\n`); + expect(sqlStatements[1]).toBe( + 'INSERT INTO `__new_users`("id", "name", "age") SELECT "id", "name", "age" FROM `users`;', + ); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('db has checks. Push with same names', async () => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`some new value`), + })), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + [], + ); + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 1cb5d716c..93c401109 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -2322,7 +2322,7 @@ test('drop check constraint', async () => { type: 'delete_check_constraint', tableName: 'test', schema: '', - data: 'some_check', + constraintName: 'some_check', }, ]); expect(sqlStatements).toStrictEqual([ diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index aea5cd379..26b43f13f 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -1,7 +1,9 @@ import Database from 'better-sqlite3'; import chalk from 'chalk'; +import { sql } from 'drizzle-orm'; import { blob, + check, foreignKey, getTableConfig, int, @@ -67,6 +69,7 @@ test('nothing changed in schema', async (t) => { tablesToRemove, tablesToTruncate, } = await diffTestSchemasPushSqlite(client, schema1, schema1, [], false); + expect(sqlStatements.length).toBe(0); expect(statements.length).toBe(0); expect(columnsToRemove!.length).toBe(0); @@ -361,6 +364,8 @@ test('drop autoincrement. drop column with data', async (t) => { seedStatements, ); + console.log('statements: ', statements); + expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'recreate_table', @@ -378,6 +383,7 @@ test('drop autoincrement. drop column with data', async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(4); @@ -494,6 +500,7 @@ test('drop autoincrement. drop column with data with pragma off', async (t) => { }, ], uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(4); @@ -598,6 +605,7 @@ test('change autoincrement. other table references current', async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); @@ -717,6 +725,7 @@ test('drop not null, add not null', async (t) => { expect(statements!.length).toBe(2); expect(statements![0]).toStrictEqual({ + checkConstraints: [], columns: [ { autoincrement: true, @@ -742,6 +751,7 @@ test('drop not null, add not null', async (t) => { uniqueConstraints: [], }); expect(statements![1]).toStrictEqual({ + checkConstraints: [], columns: [ { autoincrement: true, @@ -868,6 +878,7 @@ test('rename table and change data type', async (t) => { tableName: 'new_users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(5); @@ -946,6 +957,7 @@ test('rename column and change data type', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(4); @@ -1053,6 +1065,7 @@ test('recreate table with nested references', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(6); @@ -1161,6 +1174,7 @@ test('recreate table with added column not null and without default with data', tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(4); @@ -1189,12 +1203,12 @@ test('recreate table with added column not null and without default with data', expect(tablesToTruncate![0]).toBe('users'); }); -test('recreate table with added column not null and without default with data', async (t) => { +test('add check constraint to table', async (t) => { const client = new Database(':memory:'); const schema1 = { users: sqliteTable('users', { - id: int('id').primaryKey({ autoIncrement: true }), + id: int('id').primaryKey({ autoIncrement: false }), name: text('name'), age: integer('age'), }), @@ -1205,8 +1219,9 @@ test('recreate table with added column not null and without default with data', id: int('id').primaryKey({ autoIncrement: false }), name: text('name'), age: integer('age'), - newColumn: text('new_column').notNull(), - }), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), }; const { @@ -1251,31 +1266,117 @@ test('recreate table with added column not null and without default with data', primaryKey: false, type: 'integer', }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: ['some_check;"users"."age" > 21'], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer, +\tCONSTRAINT "some_check" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[1]).toBe( + 'INSERT INTO `__new_users`("id", "name", "age") SELECT "id", "name", "age" FROM `users`;', + ); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop check constraint', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ { autoincrement: false, - name: 'new_column', + name: 'id', notNull: true, generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, primaryKey: false, type: 'text', }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, ], compositePKs: [], referenceData: [], tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(4); expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY NOT NULL, \t\`name\` text, -\t\`age\` integer, -\t\`new_column\` text NOT NULL +\t\`age\` integer );\n`); expect(sqlStatements[1]).toBe( - 'INSERT INTO `__new_users`("id", "name", "age", "new_column") SELECT "id", "name", "age", "new_column" FROM `users`;', + 'INSERT INTO `__new_users`("id", "name", "age") SELECT "id", "name", "age" FROM `users`;', ); expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); expect(sqlStatements![3]).toBe( @@ -1288,3 +1389,52 @@ test('recreate table with added column not null and without default with data', expect(tablesToRemove!.length).toBe(0); expect(tablesToTruncate!.length).toBe(0); }); + +test('db has checks. Push with same names', async () => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`some new value`), + })), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + false, + [], + ); + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); diff --git a/drizzle-kit/tests/sqlite-checks.test.ts b/drizzle-kit/tests/sqlite-checks.test.ts new file mode 100644 index 000000000..d1824e441 --- /dev/null +++ b/drizzle-kit/tests/sqlite-checks.test.ts @@ -0,0 +1,308 @@ +import { sql } from 'drizzle-orm'; +import { check, int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSqlite } from './schemaDiffer'; + +test('create table with check', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasSqlite({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_create_table', + tableName: 'users', + columns: [ + { + name: 'id', + type: 'integer', + notNull: true, + primaryKey: true, + autoincrement: false, + }, + { + name: 'age', + type: 'integer', + notNull: false, + primaryKey: false, + autoincrement: false, + }, + ], + compositePKs: [], + checkConstraints: ['some_check_name;"users"."age" > 21'], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("users"."age" > 21) +);\n`); +}); + +test('add check contraint to existing table', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }), + }; + + const { sqlStatements, statements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: ['some_check_name;"users"."age" > 21'], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('drop check contraint to existing table', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }), + }; + + const { sqlStatements, statements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('rename check constraint', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('new_some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [`new_some_check_name;"users"."age" > 21`], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "new_some_check_name" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('rename check constraint', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 10`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [`some_check_name;"users"."age" > 10`], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("__new_users"."age" > 10) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('create checks with same names', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + name: text('name'), + }, (table) => ({ + checkConstraint1: check('some_check_name', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name', sql`${table.name} != 'Alex'`), + })), + }; + + await expect(diffTestSchemasSqlite({}, to, [])).rejects.toThrowError(); +}); diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index 04dbb940c..b7b4c7f6b 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -37,6 +37,7 @@ test('create table with id', async (t) => { uniqueConstraints: [], referenceData: [], compositePKs: [], + checkConstraints: [], }); }); @@ -363,6 +364,7 @@ test('add foreign key #1', async (t) => { }], tableName: 'users', uniqueConstraints: [], + checkConstraints: [], } as JsonRecreateTableStatement, ); }); @@ -426,6 +428,7 @@ test('add foreign key #2', async (t) => { }], tableName: 'users', uniqueConstraints: [], + checkConstraints: [], } as JsonRecreateTableStatement); }); @@ -584,6 +587,7 @@ test('alter table add composite pk', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -621,6 +625,7 @@ test('alter column drop not null', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -658,6 +663,7 @@ test('alter column add not null', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -696,6 +702,7 @@ test('alter column add default', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -733,6 +740,7 @@ test('alter column drop default', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -771,6 +779,7 @@ test('alter column add default not null', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -813,6 +822,7 @@ test('alter column add default not null with indexes', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ data: 'index_name;name;false;', @@ -869,6 +879,7 @@ test('alter column drop default not null', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); @@ -997,6 +1008,7 @@ test('recreate table with nested references', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); diff --git a/drizzle-kit/tests/sqlite-generated.test.ts b/drizzle-kit/tests/sqlite-generated.test.ts index 749dde825..2d3ceed97 100644 --- a/drizzle-kit/tests/sqlite-generated.test.ts +++ b/drizzle-kit/tests/sqlite-generated.test.ts @@ -508,6 +508,7 @@ test('generated as callback: add table with column with stored generated constra tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -576,6 +577,7 @@ test('generated as callback: add table with column with virtual generated constr tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1076,6 +1078,7 @@ test('generated as sql: add table with column with stored generated constraint', tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1144,6 +1147,7 @@ test('generated as sql: add table with column with virtual generated constraint' tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1644,6 +1648,7 @@ test('generated as string: add table with column with stored generated constrain tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1712,6 +1717,7 @@ test('generated as string: add table with column with virtual generated constrai tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index aa44908ba..828806b88 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -18,6 +18,7 @@ test('add table #1', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); }); @@ -46,6 +47,7 @@ test('add table #2', async () => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }); }); @@ -85,6 +87,7 @@ test('add table #3', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); }); @@ -104,6 +107,7 @@ test('add table #4', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'sqlite_create_table', @@ -112,6 +116,7 @@ test('add table #4', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); }); @@ -138,6 +143,7 @@ test('add table #6', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'drop_table', @@ -175,6 +181,7 @@ test('add table #7', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); }); @@ -212,6 +219,7 @@ test('add table #8', async () => { ], compositePKs: [], uniqueConstraints: [], + checkConstraints: [], referenceData: [ { columnsFrom: ['reportee_id'], @@ -267,6 +275,7 @@ test('add table #9', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ diff --git a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts index 47447decd..ffd2319d1 100644 --- a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts @@ -83,6 +83,7 @@ test(`rename table and drop index`, async (t) => { user_id_iq_pk: 'id,iq', }, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -122,6 +123,7 @@ test(`rename table and drop index`, async (t) => { new_user_id_iq_pk: 'id,iq', }, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -242,6 +244,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, autoincrement2: { name: 'autoincrement2', @@ -258,6 +261,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, dropNotNull: { name: 'dropNotNull', @@ -274,6 +278,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -297,6 +302,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, autoincrement2: { name: 'autoincrement2', @@ -313,6 +319,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, dropNotNull: { name: 'dropNotNull', @@ -329,6 +336,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -350,6 +358,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'recreate_table', @@ -366,6 +375,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'alter_table_alter_column_drop_notnull', @@ -498,6 +508,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, pk1: { name: 'pk1', @@ -514,6 +525,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, pk2: { name: 'pk2', @@ -530,6 +542,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, ref_table: { name: 'ref_table', @@ -546,6 +559,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -572,6 +586,7 @@ test(`drop and set primary key. create reference`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, pk1: { name: 'pk1', @@ -588,6 +603,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, pk2: { name: 'pk2', @@ -604,6 +620,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, ref_table: { name: 'ref_table', @@ -620,6 +637,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -641,6 +659,7 @@ test(`drop and set primary key. create reference`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'recreate_table', @@ -657,6 +676,7 @@ test(`drop and set primary key. create reference`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'create_reference', @@ -761,6 +781,7 @@ test(`set and drop multiple columns reference`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, fk2: { name: 'fk2', @@ -784,6 +805,7 @@ test(`set and drop multiple columns reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, ref_table: { name: 'ref_table', @@ -807,6 +829,7 @@ test(`set and drop multiple columns reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -837,6 +860,7 @@ test(`set and drop multiple columns reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, fk2: { name: 'fk2', @@ -863,6 +887,7 @@ test(`set and drop multiple columns reference`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, ref_table: { name: 'ref_table', @@ -886,6 +911,7 @@ test(`set and drop multiple columns reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -914,6 +940,7 @@ test(`set and drop multiple columns reference`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'recreate_table', @@ -947,6 +974,7 @@ test(`set and drop multiple columns reference`, async (t) => { }, ], uniqueConstraints: [], + checkConstraints: [], }, ]; expect(libSQLCombineStatements(statements, json2)).toStrictEqual( @@ -1054,6 +1082,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, simple: { name: 'simple', @@ -1070,6 +1099,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, unique: { name: 'unique', @@ -1088,6 +1118,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -1111,6 +1142,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, simple: { name: 'simple', @@ -1127,6 +1159,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, unique: { name: 'unique', @@ -1145,6 +1178,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -1166,6 +1200,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'alter_table_alter_column_set_type', @@ -1261,6 +1296,7 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1284,6 +1320,7 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -1330,6 +1367,7 @@ test(`add columns. set fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1353,6 +1391,7 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -1457,6 +1496,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1480,6 +1520,7 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -1526,6 +1567,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1549,6 +1591,7 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -1632,6 +1675,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1655,6 +1699,7 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -1701,6 +1746,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1724,6 +1770,7 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, diff --git a/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts index 2fcaf6436..79c8be267 100644 --- a/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts @@ -60,6 +60,7 @@ test(`renamed column and altered this column type`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -97,6 +98,7 @@ test(`renamed column and altered this column type`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -132,6 +134,7 @@ test(`renamed column and altered this column type`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, ]; expect(sqliteCombineStatements(statements, json2)).toStrictEqual( @@ -188,6 +191,7 @@ test(`renamed column and droped column "test"`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -225,6 +229,7 @@ test(`renamed column and droped column "test"`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -301,6 +306,7 @@ test(`droped column that is part of composite pk`, async (t) => { user_id_iq_pk: 'id,iq', }, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -331,6 +337,7 @@ test(`droped column that is part of composite pk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -359,6 +366,7 @@ test(`droped column that is part of composite pk`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, ]; expect(sqliteCombineStatements(statements, json2)).toStrictEqual( @@ -466,6 +474,7 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -496,6 +505,7 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -535,6 +545,7 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -565,6 +576,7 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -613,6 +625,7 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, ]; @@ -649,6 +662,7 @@ test(`create reference on exising column (table includes unique index). expect t foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, unique: { name: 'unique', @@ -674,6 +688,7 @@ test(`create reference on exising column (table includes unique index). expect t foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -697,6 +712,7 @@ test(`create reference on exising column (table includes unique index). expect t foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, unique: { name: 'unique', @@ -724,6 +740,7 @@ test(`create reference on exising column (table includes unique index). expect t }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -762,6 +779,7 @@ test(`create reference on exising column (table includes unique index). expect t }, ], uniqueConstraints: [], + checkConstraints: [], }, { data: 'unique_unique_unique;unique;true;', @@ -839,6 +857,7 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -862,6 +881,7 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -908,6 +928,7 @@ test(`add columns. set fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -931,6 +952,7 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -987,6 +1009,7 @@ test(`add columns. set fk`, async (t) => { tableName: 'ref', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }, ]; expect(sqliteCombineStatements(statements, json2)).toStrictEqual( @@ -1053,6 +1076,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1076,6 +1100,7 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, @@ -1122,6 +1147,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1145,6 +1171,7 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, From 9d6930f574c61c527dca2e0f3661f597b800beb2 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 11 Sep 2024 12:03:26 +0300 Subject: [PATCH 157/492] Update release notes --- changelogs/drizzle-kit/0.25.0.md | 61 ++++++++++++-- changelogs/drizzle-orm/0.34.0.md | 135 +++++++++++++++++++++++++++---- 2 files changed, 173 insertions(+), 23 deletions(-) diff --git a/changelogs/drizzle-kit/0.25.0.md b/changelogs/drizzle-kit/0.25.0.md index 0c1c5ea6e..fc4b36c83 100644 --- a/changelogs/drizzle-kit/0.25.0.md +++ b/changelogs/drizzle-kit/0.25.0.md @@ -1,4 +1,55 @@ -## Libsql and Sqlite migration updates +## Breaking changes and migrate guide for Turso users + +If you are using Turso and libsql, you will need to upgrade your `drizzle.config` and `@libsql/client` package. + +1. This version of drizzle-orm will only work with `@libsql/client@0.10.0` or higher if you are using the `migrate` function. For other use cases, you can continue using previous versions(But the suggestion is to upgrade) +To install the latest version, use the command: + +```bash +npm i @libsql/client@latest +``` + +2. Previously, we had a common `drizzle.config` for SQLite and Turso users, which allowed a shared strategy for both dialects. Starting with this release, we are introducing the turso dialect in drizzle-kit. We will evolve and improve Turso as a separate dialect with its own migration strategies. + +**Before** + +```ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "sqlite", + schema: "./schema.ts", + out: "./drizzle", + dbCredentials: { + url: "database.db", + }, + breakpoints: true, + verbose: true, + strict: true, +}); +``` + +**After** + +```ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "turso", + schema: "./schema.ts", + out: "./drizzle", + dbCredentials: { + url: "database.db", + }, + breakpoints: true, + verbose: true, + strict: true, +}); +``` + +If you are using only SQLite, you can use `dialect: "sqlite"` + +## LibSQL/Turso and Sqlite migration updates ### SQLite "generate" and "push" statements updates @@ -35,14 +86,12 @@ ALTER TABLE `__new_worker` RENAME TO `worker`; PRAGMA foreign_keys=ON; ``` -### LibSQL "generate" and "push" statements updates +### LibSQL/Turso "generate" and "push" statements updates Since LibSQL supports more ALTER statements than SQLite, we can generate more statements without recreating your schema and moving all the data, which can be potentially dangerous for production environments. LibSQL and Turso will now have a separate dialect in the Drizzle config file, meaning that we will evolve Turso and LibSQL independently from SQLite and will aim to support as many features as Turso/LibSQL offer. -> **Breaking change!** All users who want to get the most out of Turso and LibSQL DDL statements should remove `driver: turso` from the `drizzle.config` file and add `dialect: turso` instead - With the updated LibSQL migration strategy, you will have the ability to: - **Change Data Type**: Set a new data type for existing columns. @@ -56,7 +105,7 @@ You can find more information in the [LibSQL documentation](https://github.com/t - Dropping or altering an index will cause table recreation. -This is because LibSQL does not support dropping this type of index. +This is because LibSQL/Turso does not support dropping this type of index. ```sql CREATE TABLE `users` ( @@ -71,7 +120,7 @@ CREATE TABLE `users` ( - Drizzle-Kit will drop the indexes, modify the columns, and then recreate the indexes. - Adding or dropping composite foreign keys is not supported and will cause table recreation -### NOTES: +### NOTES - You can create a reference on any column type, but if you want to insert values, the referenced column must have a unique index or primary key. diff --git a/changelogs/drizzle-orm/0.34.0.md b/changelogs/drizzle-orm/0.34.0.md index 55eb0411f..490422628 100644 --- a/changelogs/drizzle-orm/0.34.0.md +++ b/changelogs/drizzle-orm/0.34.0.md @@ -1,4 +1,55 @@ -## Libsql and Sqlite migration updates +## Breaking changes and migrate guide for Turso users + +If you are using Turso and libsql, you will need to upgrade your `drizzle.config` and `@libsql/client` package. + +1. This version of drizzle-orm will only work with `@libsql/client@0.10.0` or higher if you are using the `migrate` function. For other use cases, you can continue using previous versions(But the suggestion is to upgrade) +To install the latest version, use the command: + +```bash +npm i @libsql/client@latest +``` + +2. Previously, we had a common `drizzle.config` for SQLite and Turso users, which allowed a shared strategy for both dialects. Starting with this release, we are introducing the turso dialect in drizzle-kit. We will evolve and improve Turso as a separate dialect with its own migration strategies. + +**Before** + +```ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "sqlite", + schema: "./schema.ts", + out: "./drizzle", + dbCredentials: { + url: "database.db", + }, + breakpoints: true, + verbose: true, + strict: true, +}); +``` + +**After** + +```ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "turso", + schema: "./schema.ts", + out: "./drizzle", + dbCredentials: { + url: "database.db", + }, + breakpoints: true, + verbose: true, + strict: true, +}); +``` + +If you are using only SQLite, you can use `dialect: "sqlite"` + +## LibSQL/Turso and Sqlite migration updates ### SQLite "generate" and "push" statements updates @@ -35,14 +86,12 @@ ALTER TABLE `__new_worker` RENAME TO `worker`; PRAGMA foreign_keys=ON; ``` -### LibSQL "generate" and "push" statements updates +### LibSQL/Turso "generate" and "push" statements updates Since LibSQL supports more ALTER statements than SQLite, we can generate more statements without recreating your schema and moving all the data, which can be potentially dangerous for production environments. LibSQL and Turso will now have a separate dialect in the Drizzle config file, meaning that we will evolve Turso and LibSQL independently from SQLite and will aim to support as many features as Turso/LibSQL offer. -> **Breaking change!** All users who want to get the most out of Turso and LibSQL DDL statements should remove `driver: turso` from the `drizzle.config` file and add `dialect: turso` instead - With the updated LibSQL migration strategy, you will have the ability to: - **Change Data Type**: Set a new data type for existing columns. @@ -56,7 +105,7 @@ You can find more information in the [LibSQL documentation](https://github.com/t - Dropping or altering an index will cause table recreation. -This is because LibSQL does not support dropping this type of index. +This is because LibSQL/Turso does not support dropping this type of index. ```sql CREATE TABLE `users` ( @@ -71,7 +120,7 @@ CREATE TABLE `users` ( - Drizzle-Kit will drop the indexes, modify the columns, and then recreate the indexes. - Adding or dropping composite foreign keys is not supported and will cause table recreation -### NOTES: +### NOTES - You can create a reference on any column type, but if you want to insert values, the referenced column must have a unique index or primary key. @@ -96,28 +145,77 @@ See more: https://www.sqlite.org/foreignkeys.html ## A new and easy way to start using drizzle -before on example with node-postgres +Current and the only way to do, is to define client yourself and pass it to drizzle ```ts -// 1, current const client = new Pool({ url: '' }); drizzle(client, { logger: true }); +``` + +But we want to introduce you to a new API, which is a simplified method in addition to the existing one. + +Most clients will have a few options to connect, starting with the easiest and most common one, and allowing you to control your client connection as needed. -// 2 -await drizzle('neon', { client: 'postgresql://...', logger: true }) +Let's use `node-postgres` as an example, but the same pattern can be applied to all other clients -// 3 -await drizzle('neon', { client: { url: 'postgresql://...' }, logger: true }) +```ts +// Finally, one import for all available clients and dialects! +import { drizzle } from 'drizzle-orm' + +// Choose a client and use a connection URL — nothing else is needed! +const db1 = await drizzle("node-postgres", process.env.POSTGRES_URL); + +// If you need to pass a logger, schema, or other configurations, you can use an object and specify the client-specific URL in the connection +const db2 = await drizzle("node-postgres", { + connection: process.env.POSTGRES_URL, + logger: true +}); + +// And finally, if you need to use full client/driver-specific types in connections, you can use a URL or host/port/etc. as an object inferred from the underlying client connection types +const db3 = await drizzle("node-postgres", { + connection: { + connectionString: process.env.POSTGRES_URL, + }, +}); -// 4 -await drizzle('neon', 'postgresql://...') +const db4 = await drizzle("node-postgres", { + connection: { + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + host: process.env.DB_HOST, + port: process.env.DB_PORT, + database: process.env.DB_NAME, + ssl: true, + }, +}); ``` -will become +A few clients will have a slightly different API due to their specific behavior. Let's take a look at them: + +For `aws-data-api-pg`, Drizzle will require `resourceArn`, `database`, and `secretArn`, along with any other AWS Data API client types for the connection, such as credentials, region, etc. ```ts -await drizzle('', { client: '', logger: true }) -await drizzle('', { client: {}, logger: true }) +drizzle("aws-data-api-pg", { + connection: { + resourceArn: "", + database: "", + secretArn: "", + }, +}); +``` + +For `d1`, the Cloudflare Worker types as described in the [documentation](https://developers.cloudflare.com/d1/get-started/) here will be required. + +```ts +drizzle("d1", { + connection: env.DB // Cloudflare Worker Types +}) +``` + +For `vercel-postgres`, nothing is needed since Vercel automatically retrieves the `POSTGRES_URL` from the `.env` file. You can check this [documentation](https://vercel.com/docs/storage/vercel-postgres/quickstart) for more info + +```ts +drizzle("vercel-postgres") ``` > Note that the first example with the client is still available and not deprecated. You can use it if you don't want to await the drizzle object. The new way of defining drizzle is designed to make it easier to import from one place and get autocomplete for all the available clients @@ -125,12 +223,14 @@ await drizzle('', { client: {}, logger: true }) ## New "count" API Befor this release to count entities in a table, you would need to do this: + ```ts const res = await db.select({ count: sql`count(*)` }).from(users); const count = res[0].count; ``` The new API will look like this: + ```ts // how many users are in the database const count: number = await db.$count(users); @@ -140,6 +240,7 @@ const count: number = await db.$count(users, eq(name, "Dan")); ``` This can also work as a subquery and within relational queries + ```ts const users = await db.select({ ...users, From d11d7bbd1bc5de084d85ac05bb74a85e1da1b4c3 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 11 Sep 2024 17:21:43 +0300 Subject: [PATCH 158/492] Monodriver improvements, added $client to all compatible drizzle instances, fixed Drizzle D1 not accepting miniflare D1 on type level --- drizzle-orm/package.json | 3 +- drizzle-orm/src/aws-data-api/pg/driver.ts | 9 +- drizzle-orm/src/better-sqlite3/driver.ts | 9 +- drizzle-orm/src/bun-sqlite/driver.ts | 9 +- drizzle-orm/src/d1/driver.ts | 27 +- drizzle-orm/src/expo-sqlite/driver.ts | 9 +- drizzle-orm/src/libsql/driver.ts | 9 +- drizzle-orm/src/monodriver.ts | 379 +++++++++--------- drizzle-orm/src/mysql2/driver.ts | 23 +- drizzle-orm/src/neon-http/driver.ts | 16 +- drizzle-orm/src/neon-serverless/driver.ts | 16 +- drizzle-orm/src/node-postgres/driver.ts | 16 +- drizzle-orm/src/op-sqlite/driver.ts | 9 +- drizzle-orm/src/pglite/driver.ts | 9 +- .../src/planetscale-serverless/driver.ts | 16 +- drizzle-orm/src/postgres-js/driver.ts | 9 +- drizzle-orm/src/tidb-serverless/driver.ts | 9 +- drizzle-orm/src/utils.ts | 2 + drizzle-orm/src/vercel-postgres/driver.ts | 9 +- drizzle-orm/src/xata-http/driver.ts | 9 +- .../tests/sqlite/d1-batch.test.ts | 2 +- integration-tests/tests/sqlite/d1.test.ts | 2 +- pnpm-lock.yaml | 141 +++---- 23 files changed, 430 insertions(+), 312 deletions(-) diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 333521a48..a86983f3e 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.34.0", + "version": "0.33.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -162,6 +162,7 @@ "@cloudflare/workers-types": "^4.20230904.0", "@electric-sql/pglite": "^0.1.1", "@libsql/client": "^0.10.0", + "@miniflare/d1": "^2.14.2", "@neondatabase/serverless": "^0.9.0", "@op-engineering/op-sqlite": "^2.0.16", "@opentelemetry/api": "^1.4.1", diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index 5174c24d0..bf3e68439 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -90,7 +90,9 @@ export class AwsPgDialect extends PgDialect { export function drizzle = Record>( client: AwsDataApiClient, config: DrizzleAwsDataApiPgConfig, -): AwsDataApiPgDatabase { +): AwsDataApiPgDatabase & { + $client: AwsDataApiClient; +} { const dialect = new AwsPgDialect(); let logger; if (config.logger === true) { @@ -113,5 +115,8 @@ export function drizzle = Record; + const db = new AwsDataApiPgDatabase(dialect, session, schema as any); + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 8fe7c00fb..8af9d49d6 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -21,7 +21,9 @@ export class BetterSQLite3Database = Rec export function drizzle = Record>( client: Database, config: DrizzleConfig = {}, -): BetterSQLite3Database { +): BetterSQLite3Database & { + $client: Database; +} { const dialect = new SQLiteSyncDialect(); let logger; if (config.logger === true) { @@ -44,5 +46,8 @@ export function drizzle = Record; + const db = new BetterSQLite3Database('sync', dialect, session, schema); + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index 5771bd371..2e928d466 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -23,7 +23,9 @@ export class BunSQLiteDatabase< export function drizzle = Record>( client: Database, config: DrizzleConfig = {}, -): BunSQLiteDatabase { +): BunSQLiteDatabase & { + $client: Database; +} { const dialect = new SQLiteSyncDialect(); let logger; if (config.logger === true) { @@ -46,5 +48,8 @@ export function drizzle = Record; + const db = new BunSQLiteDatabase('sync', dialect, session, schema) as BunSQLiteDatabase; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/d1/driver.ts b/drizzle-orm/src/d1/driver.ts index 46fc8ec8e..3f81a618c 100644 --- a/drizzle-orm/src/d1/driver.ts +++ b/drizzle-orm/src/d1/driver.ts @@ -1,4 +1,5 @@ /// +import type { D1Database as MiniflareD1Database } from '@miniflare/d1'; import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -11,9 +12,15 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported } from '~/utils.ts'; import { SQLiteD1Session } from './session.ts'; +export type AnyD1Database = IfNotImported< + D1Database, + MiniflareD1Database, + D1Database | IfNotImported +>; + export class DrizzleD1Database< TSchema extends Record = Record, > extends BaseSQLiteDatabase<'async', D1Result, TSchema> { @@ -29,10 +36,15 @@ export class DrizzleD1Database< } } -export function drizzle = Record>( - client: D1Database, +export function drizzle< + TSchema extends Record = Record, + TClient extends AnyD1Database = AnyD1Database, +>( + client: TClient, config: DrizzleConfig = {}, -): DrizzleD1Database { +): DrizzleD1Database & { + $client: TClient; +} { const dialect = new SQLiteAsyncDialect(); let logger; if (config.logger === true) { @@ -54,6 +66,9 @@ export function drizzle = Record; + const session = new SQLiteD1Session(client as D1Database, dialect, schema, { logger }); + const db = new DrizzleD1Database('async', dialect, session, schema) as DrizzleD1Database; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/expo-sqlite/driver.ts b/drizzle-orm/src/expo-sqlite/driver.ts index fb858e482..68781e5ef 100644 --- a/drizzle-orm/src/expo-sqlite/driver.ts +++ b/drizzle-orm/src/expo-sqlite/driver.ts @@ -21,7 +21,9 @@ export class ExpoSQLiteDatabase = Record export function drizzle = Record>( client: SQLiteDatabase, config: DrizzleConfig = {}, -): ExpoSQLiteDatabase { +): ExpoSQLiteDatabase & { + $client: SQLiteDatabase; +} { const dialect = new SQLiteSyncDialect(); let logger; if (config.logger === true) { @@ -44,5 +46,8 @@ export function drizzle = Record; + const db = new ExpoSQLiteDatabase('sync', dialect, session, schema) as ExpoSQLiteDatabase; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/libsql/driver.ts b/drizzle-orm/src/libsql/driver.ts index 3acff2893..a088e8612 100644 --- a/drizzle-orm/src/libsql/driver.ts +++ b/drizzle-orm/src/libsql/driver.ts @@ -31,7 +31,9 @@ export class LibSQLDatabase< export function drizzle< TSchema extends Record = Record, ->(client: Client, config: DrizzleConfig = {}): LibSQLDatabase { +>(client: Client, config: DrizzleConfig = {}): LibSQLDatabase & { + $client: Client; +} { const dialect = new SQLiteAsyncDialect(); let logger; if (config.logger === true) { @@ -54,5 +56,8 @@ export function drizzle< } const session = new LibSQLSession(client, dialect, schema, { logger }, undefined); - return new LibSQLDatabase('async', dialect, session, schema) as LibSQLDatabase; + const db = new LibSQLDatabase('async', dialect, session, schema) as LibSQLDatabase; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 121b6b470..c748707af 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,5 +1,5 @@ /* eslint-disable import/extensions */ -import type { RDSDataClient, RDSDataClientConfig, RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; +import type { RDSDataClient, RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; import type { Client as LibsqlClient, Config as LibsqlConfig } from '@libsql/client'; import type { HTTPTransactionOptions as NeonHttpConfig, @@ -24,7 +24,7 @@ import type { import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg/index.ts'; import type { BetterSQLite3Database as DrizzleBetterSQLite3Database } from './better-sqlite3/index.ts'; import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; -import type { DrizzleD1Database } from './d1/index.ts'; +import type { AnyD1Database, DrizzleD1Database } from './d1/index.ts'; import type { LibSQLDatabase } from './libsql/index.ts'; import type { MySql2Database, MySql2DrizzleConfig } from './mysql2/index.ts'; import type { NeonHttpDatabase } from './neon-http/index.ts'; @@ -33,62 +33,58 @@ import type { NodePgDatabase } from './node-postgres/driver.ts'; import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; import type { PostgresJsDatabase } from './postgres-js/index.ts'; import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; -import type { DrizzleConfig } from './utils.ts'; +import type { DrizzleConfig, IfNotImported } from './utils.ts'; import type { VercelPgDatabase } from './vercel-postgres/index.ts'; -type BunSqliteDatabaseOptions = - | number - | { - /** - * Open the database as read-only (no write operations, no create). - * - * Equivalent to {@link constants.SQLITE_OPEN_READONLY} - */ - readonly?: boolean; - /** - * Allow creating a new database - * - * Equivalent to {@link constants.SQLITE_OPEN_CREATE} - */ - create?: boolean; - /** - * Open the database as read-write - * - * Equivalent to {@link constants.SQLITE_OPEN_READWRITE} - */ - readwrite?: boolean; - }; +type BunSqliteDatabaseOptions = { + /** + * Open the database as read-only (no write operations, no create). + * + * Equivalent to {@link constants.SQLITE_OPEN_READONLY} + */ + readonly?: boolean; + /** + * Allow creating a new database + * + * Equivalent to {@link constants.SQLITE_OPEN_CREATE} + */ + create?: boolean; + /** + * Open the database as read-write + * + * Equivalent to {@link constants.SQLITE_OPEN_READWRITE} + */ + readwrite?: boolean; +}; type BunSqliteDatabaseConfig = - | { - filename?: ':memory:' | (string & {}); - options?: BunSqliteDatabaseOptions; - } - | ':memory:' - | (string & {}) + | ({ + source?: string; + } & BunSqliteDatabaseOptions) + | string | undefined; type BetterSQLite3DatabaseConfig = - | { - filename?: - | ':memory:' - | (string & {}) + | ({ + source?: + | string | Buffer; - options?: BetterSQLite3Options; - } - | ':memory:' - | (string & {}) + } & BetterSQLite3Options) + | string | undefined; -type MonodriverNeonHttpConfig = { - connectionString: string; - options?: NeonHttpConfig; -} | string; +type MonodriverNeonHttpConfig = + | ({ + connectionString: string; + } & NeonHttpConfig) + | string; + +type AwsDataApiConnectionConfig = RDSConfig & Omit; type DatabaseClient = | 'node-postgres' | 'postgres-js' - | 'neon-serverless' + | 'neon-websocket' | 'neon-http' | 'vercel-postgres' | 'aws-data-api-pg' @@ -104,7 +100,7 @@ type DatabaseClient = type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; 'postgres-js': PostgresJsDatabase; - 'neon-serverless': NeonDatabase; + 'neon-websocket': NeonDatabase; 'neon-http': NeonHttpDatabase; 'vercel-postgres': VercelPgDatabase; 'aws-data-api-pg': AwsDataApiPgDatabase; @@ -123,7 +119,7 @@ type Primitive = string | number | boolean | undefined | null; type ClientInstanceMap = { 'node-postgres': NodePgPool; 'postgres-js': PostgresJsClient; - 'neon-serverless': NeonServerlessPool; + 'neon-websocket': NeonServerlessPool; 'neon-http': NeonQueryFunction; 'vercel-postgres': & VercelPool @@ -134,27 +130,47 @@ type ClientInstanceMap = { 'tidb-serverless': TiDBConnection; libsql: LibsqlClient; turso: LibsqlClient; - d1: D1Database; + d1: AnyD1Database; 'bun:sqlite': BunDatabase; 'better-sqlite3': BetterSQLite3Database; }; +type ClientTypeImportErrorMap = { + 'node-postgres': 'pg`, `@types/pg'; + 'postgres-js': 'postgres'; + 'neon-websocket': '@neondatabase/serverless'; + 'neon-http': '@neondatabase/serverless'; + 'vercel-postgres': '@vercel/postgres'; + 'aws-data-api-pg': '@aws-sdk/client-rds-data'; + planetscale: '@planetscale/database'; + mysql2: 'mysql2'; + 'tidb-serverless': '@tidbcloud/serverless'; + libsql: '@libsql/client'; + turso: '@libsql/client'; + d1: '@cloudflare/workers-types` or `@miniflare/d1'; + 'bun:sqlite': 'bun-types'; + 'better-sqlite3': 'better-sqlite3'; +}; + +type ImportTypeError = + `Please install \`${ClientTypeImportErrorMap[TClient]}\` for Drizzle ORM to connect to database`; + type InitializerParams = { 'node-postgres': { - connection?: string | NodePgPoolConfig; + connection: string | NodePgPoolConfig; }; 'postgres-js': { - connection: string | PostgresJSOptions>; + connection: string | ({ url?: string } & PostgresJSOptions>); }; - 'neon-serverless': { - connection?: string | NeonServerlessConfig; + 'neon-websocket': { + connection: string | NeonServerlessConfig; }; 'neon-http': { connection: MonodriverNeonHttpConfig; }; 'vercel-postgres': {}; 'aws-data-api-pg': { - connection?: RDSConfig; + connection: AwsDataApiConnectionConfig; }; planetscale: { connection: PlanetscaleConfig | string; @@ -172,7 +188,7 @@ type InitializerParams = { connection: LibsqlConfig | string; }; d1: { - connection: D1Database; + connection: AnyD1Database; }; 'bun:sqlite': { connection?: BunSqliteDatabaseConfig; @@ -211,78 +227,78 @@ export async function drizzle< ...params: TClient extends 'bun:sqlite' | 'better-sqlite3' ? ( [] | [ ( - & InitializerParams[TClient] + & IfNotImported< + ClientInstanceMap[TClient], + { connection: ImportTypeError }, + InitializerParams[TClient] + > & DrizzleConfig ), - ] | [ - ':memory:', - ] | [ - (string & {}), - ] + ] | [string] ) : TClient extends 'vercel-postgres' ? ([] | [ ( - & InitializerParams[TClient] + & IfNotImported< + ClientInstanceMap[TClient], + { connection: ImportTypeError }, + InitializerParams[TClient] + > & DrizzleConfig ), ]) - : TClient extends 'node-postgres' ? ( + : TClient extends + 'postgres-js' | 'tidb-serverless' | 'libsql' | 'turso' | 'planetscale' | 'neon-http' | 'node-postgres' ? ( [ ( - & InitializerParams[TClient] + & IfNotImported< + ClientInstanceMap[TClient], + { connection: ImportTypeError }, + InitializerParams[TClient] + > & DrizzleConfig ), - ] | [ - string, - ] - ) - : TClient extends 'postgres-js' | 'tidb-serverless' | 'libsql' | 'turso' | 'planetscale' ? ( - [ - ( - & InitializerParams[TClient] - & DrizzleConfig - ), - ] | [ - string, - ] + ] | [string] ) : TClient extends 'mysql2' ? ( [ ( - & InitializerParams[TClient] + & IfNotImported< + ClientInstanceMap[TClient], + { connection: ImportTypeError }, + InitializerParams[TClient] + > & MySql2DrizzleConfig ), - ] | [ - string, - ] + ] | [string] ) - : TClient extends 'aws-data-api-pg' ? [ - InitializerParams[TClient] & DrizzleAwsDataApiPgConfig, - ] - : TClient extends 'neon-serverless' ? ( + : TClient extends 'neon-websocket' ? ( | [ - InitializerParams[TClient] & DrizzleConfig & { + & IfNotImported< + ClientInstanceMap[TClient], + { connection: ImportTypeError }, + InitializerParams[TClient] + > + & DrizzleConfig + & { ws?: any; }, ] | [string] - | [] ) - : TClient extends 'neon-http' ? ([ - InitializerParams[TClient] & DrizzleConfig, - ] | [ - string, - ]) : [ ( - & InitializerParams[TClient] + & IfNotImported< + ClientInstanceMap[TClient], + { connection: ImportTypeError }, + InitializerParams[TClient] + > & DrizzleConfig ), ] ): Promise> { switch (client) { case 'node-postgres': { - const defpg = await import('pg'); + const defpg = await import('pg').catch(() => importError('pg')); const { drizzle } = await import('./node-postgres'); if (typeof params[0] === 'object') { @@ -295,10 +311,9 @@ export async function drizzle< connectionString: connection, }) : new defpg.default.Pool(connection); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } const instance = typeof params[0] === 'string' @@ -306,26 +321,25 @@ export async function drizzle< connectionString: params[0], }) : new defpg.default.Pool(params[0]); - const db = drizzle(instance) as any; - db.$client = instance; + const db = drizzle(instance); - return db; + return db as any; } case 'aws-data-api-pg': { - const { connection, ...drizzleConfig } = params[0] as - & { connection: RDSDataClientConfig | undefined } - & DrizzleAwsDataApiPgConfig; + const { connection, ...drizzleConfig } = params[0] as { + connection: AwsDataApiConnectionConfig; + } & DrizzleConfig; + const { resourceArn, database, secretArn, ...rdsConfig } = connection; const { RDSDataClient } = await import('@aws-sdk/client-rds-data').catch(() => importError('@aws-sdk/client-rds-data') ); const { drizzle } = await import('./aws-data-api/pg'); - const instance = connection ? new RDSDataClient(connection) : new RDSDataClient(); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const instance = new RDSDataClient(rdsConfig); + const db = drizzle(instance, { resourceArn, database, secretArn, ...drizzleConfig }); - return db; + return db as any; } case 'better-sqlite3': { const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); @@ -337,30 +351,29 @@ export async function drizzle< } & DrizzleConfig; if (typeof connection === 'object') { - const { filename, options } = connection; + const { source, ...options } = connection; - const instance = new Client(filename, options); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const instance = new Client(source, options); + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } const instance = new Client(connection); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } const instance = new Client(params[0]); - const db = drizzle(instance) as any; - db.$client = instance; + const db = drizzle(instance); - return db; + return db as any; } case 'bun:sqlite': { - const { Database: Client } = await import('bun:sqlite').catch(() => importError('bun:sqlite')); + const { Database: Client } = await import('bun:sqlite').catch(() => { + throw new Error(`Please use bun to use 'bun:sqlite' for Drizzle ORM to connect to database`); + }); const { drizzle } = await import('./bun-sqlite'); if (typeof params[0] === 'object') { @@ -369,37 +382,35 @@ export async function drizzle< } & DrizzleConfig; if (typeof connection === 'object') { - const { filename, options } = connection; + const { source, ...opts } = connection; + + const options = Object.values(opts).filter((v) => v !== undefined).length ? opts : undefined; - const instance = new Client(filename, options); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const instance = new Client(source, options); + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } const instance = new Client(connection); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } const instance = new Client(params[0]); - const db = drizzle(instance) as any; - db.$client = instance; + const db = drizzle(instance); - return db; + return db as any; } case 'd1': { - const { connection, ...drizzleConfig } = params[0] as { connection: D1Database } & DrizzleConfig; + const { connection, ...drizzleConfig } = params[0] as { connection: AnyD1Database } & DrizzleConfig; const { drizzle } = await import('./d1'); - const db = drizzle(connection, drizzleConfig) as any; - db.$client = connection; + const db = drizzle(connection, drizzleConfig); - return db; + return db as any; } case 'libsql': case 'turso': { @@ -410,22 +421,20 @@ export async function drizzle< const instance = createClient({ url: params[0], }); - const db = drizzle(instance) as any; - db.$client = instance; + const db = drizzle(instance); - return db; + return db as any; } const { connection, ...drizzleConfig } = params[0] as any as { connection: LibsqlConfig } & DrizzleConfig; const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } case 'mysql2': { - const { createPool } = await import('mysql2/promise').catch(() => importError('mysql2/promise')); + const { createPool } = await import('mysql2/promise').catch(() => importError('mysql2')); const { drizzle } = await import('./mysql2'); if (typeof params[0] === 'object') { @@ -434,19 +443,17 @@ export async function drizzle< & MySql2DrizzleConfig; const instance = createPool(connection as Mysql2Config); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } const connectionString = params[0]!; const instance = createPool(connectionString); - const db = drizzle(instance) as any; - db.$client = instance; + const db = drizzle(instance); - return db; + return db as any; } case 'neon-http': { const { neon } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); @@ -456,29 +463,26 @@ export async function drizzle< const { connection, ...drizzleConfig } = params[0] as { connection: MonodriverNeonHttpConfig } & DrizzleConfig; if (typeof connection === 'object') { - const { connectionString, options } = connection; + const { connectionString, ...options } = connection; const instance = neon(connectionString, options); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } const instance = neon(connection); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } const instance = neon(params[0]!); - const db = drizzle(instance) as any; - db.$client = instance; + const db = drizzle(instance); - return db; + return db as any; } - case 'neon-serverless': { + case 'neon-websocket': { const { Pool, neonConfig } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless') ); @@ -488,10 +492,9 @@ export async function drizzle< connectionString: params[0], }); - const db = drizzle(instance) as any; - db.$client = instance; + const db = drizzle(instance); - return db; + return db as any; } if (typeof params[0] === 'object') { @@ -510,17 +513,15 @@ export async function drizzle< }) : new Pool(connection); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } const instance = new Pool(); - const db = drizzle(instance) as any; - db.$client = instance; + const db = drizzle(instance); - return db; + return db as any; } case 'planetscale': { const { Client } = await import('@planetscale/database').catch(() => importError('@planetscale/database')); @@ -538,19 +539,16 @@ export async function drizzle< : new Client( connection, ); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; - - return db; + const db = drizzle(instance, drizzleConfig); + return db as any; } const instance = new Client({ url: params[0], }); - const db = drizzle(instance) as any; - db.$client = instance; + const db = drizzle(instance); - return db; + return db as any; } case 'postgres-js': { const { default: client } = await import('postgres').catch(() => importError('postgres')); @@ -558,22 +556,28 @@ export async function drizzle< if (typeof params[0] === 'object') { const { connection, ...drizzleConfig } = params[0] as { - connection: PostgresJSOptions>; + connection: { url?: string } & PostgresJSOptions>; } & DrizzleConfig; - const instance = client(connection); + if (typeof connection === 'object' && connection.url !== undefined) { + const { url, ...config } = connection; + + const instance = client(url, config); + const db = drizzle(instance, drizzleConfig); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + return db as any; + } + + const instance = client(connection); + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } const instance = client(params[0]!); - const db = drizzle(instance) as any; - db.$client = instance; + const db = drizzle(instance); - return db; + return db as any; } case 'tidb-serverless': { const { connect } = await import('@tidbcloud/serverless').catch(() => importError('@tidbcloud/serverless')); @@ -583,10 +587,9 @@ export async function drizzle< const instance = connect({ url: params[0], }); - const db = drizzle(instance) as any; - db.$client = instance; + const db = drizzle(instance); - return db; + return db as any; } const { connection, ...drizzleConfig } = params[0] as @@ -598,20 +601,18 @@ export async function drizzle< url: connection, }) : connect(connection); - const db = drizzle(instance, drizzleConfig) as any; - db.$client = instance; + const db = drizzle(instance, drizzleConfig); - return db; + return db as any; } case 'vercel-postgres': { const drizzleConfig = params[0] as DrizzleConfig | undefined; const { sql } = await import('@vercel/postgres').catch(() => importError('@vercel/postgres')); const { drizzle } = await import('./vercel-postgres'); - const db = drizzle(sql, drizzleConfig) as any; - db.$client = sql; + const db = drizzle(sql, drizzleConfig); - return db; + return db as any; } } diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index a8fb65c3b..fc55c3f91 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -50,10 +50,15 @@ export type MySql2DrizzleConfig = Record & Omit, 'schema'> & ({ schema: TSchema; mode: Mode } | { schema?: undefined; mode?: Mode }); -export function drizzle = Record>( - client: MySql2Client | CallbackConnection | CallbackPool, +export function drizzle< + TSchema extends Record = Record, + TClient extends MySql2Client | CallbackConnection | CallbackPool = MySql2Client | CallbackConnection | CallbackPool, +>( + client: TClient, config: MySql2DrizzleConfig = {}, -): MySql2Database { +): MySql2Database & { + $client: TClient; +} { const dialect = new MySqlDialect(); let logger; if (config.logger === true) { @@ -61,9 +66,8 @@ export function drizzle = Record | undefined; if (config.schema) { @@ -87,9 +91,12 @@ export function drizzle = Record; + const db = new MySql2Database(dialect, session, schema as any, mode) as MySql2Database; + ( db).$client = client; + + return db as any; } interface CallbackClient { diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index 81a66c69b..6f7cc0833 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -55,10 +55,15 @@ export class NeonHttpDatabase< } } -export function drizzle = Record>( - client: NeonQueryFunction, +export function drizzle< + TSchema extends Record = Record, + TClient extends NeonQueryFunction = NeonQueryFunction, +>( + client: TClient, config: DrizzleConfig = {}, -): NeonHttpDatabase { +): NeonHttpDatabase & { + $client: TClient; +} { const dialect = new PgDialect(); let logger; if (config.logger === true) { @@ -83,9 +88,12 @@ export function drizzle = Record> | undefined, ); + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index 7f42cfeb3..c59d6dccd 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -49,10 +49,15 @@ export class NeonDatabase< static readonly [entityKind]: string = 'NeonServerlessDatabase'; } -export function drizzle = Record>( - client: NeonClient, +export function drizzle< + TSchema extends Record = Record, + TClient extends NeonClient = NeonClient, +>( + client: TClient, config: DrizzleConfig = {}, -): NeonDatabase { +): NeonDatabase & { + $client: TClient; +} { const dialect = new PgDialect(); let logger; if (config.logger === true) { @@ -76,5 +81,8 @@ export function drizzle = Record; + const db = new NeonDatabase(dialect, session, schema as any) as NeonDatabase; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index 15ac8fc06..254f0374c 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -51,10 +51,15 @@ export class NodePgDatabase< static readonly [entityKind]: string = 'NodePgDatabase'; } -export function drizzle = Record>( - client: NodePgClient, +export function drizzle< + TSchema extends Record = Record, + TClient extends NodePgClient = NodePgClient, +>( + client: TClient, config: DrizzleConfig = {}, -): NodePgDatabase { +): NodePgDatabase & { + $client: TClient; +} { const dialect = new PgDialect(); let logger; if (config.logger === true) { @@ -78,5 +83,8 @@ export function drizzle = Record; + const db = new NodePgDatabase(dialect, session, schema as any) as NodePgDatabase; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/op-sqlite/driver.ts b/drizzle-orm/src/op-sqlite/driver.ts index 94ee6e866..31316e55a 100644 --- a/drizzle-orm/src/op-sqlite/driver.ts +++ b/drizzle-orm/src/op-sqlite/driver.ts @@ -21,7 +21,9 @@ export class OPSQLiteDatabase< export function drizzle = Record>( client: OPSQLiteConnection, config: DrizzleConfig = {}, -): OPSQLiteDatabase { +): OPSQLiteDatabase & { + $client: OPSQLiteConnection; +} { const dialect = new SQLiteAsyncDialect(); let logger; if (config.logger === true) { @@ -44,5 +46,8 @@ export function drizzle = Record; + const db = new OPSQLiteDatabase('async', dialect, session, schema) as OPSQLiteDatabase; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/pglite/driver.ts b/drizzle-orm/src/pglite/driver.ts index a801005d8..d6c4e4ad3 100644 --- a/drizzle-orm/src/pglite/driver.ts +++ b/drizzle-orm/src/pglite/driver.ts @@ -43,7 +43,9 @@ export class PgliteDatabase< export function drizzle = Record>( client: PgliteClient, config: DrizzleConfig = {}, -): PgliteDatabase { +): PgliteDatabase & { + $client: PgliteClient; +} { const dialect = new PgDialect(); let logger; if (config.logger === true) { @@ -67,5 +69,8 @@ export function drizzle = Record; + const db = new PgliteDatabase(dialect, session, schema as any) as PgliteDatabase; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index fd1327bbc..77311d506 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -25,10 +25,15 @@ export class PlanetScaleDatabase< static readonly [entityKind]: string = 'PlanetScaleDatabase'; } -export function drizzle = Record>( - client: Client | Connection, +export function drizzle< + TSchema extends Record = Record, + TClient extends Client | Connection = Client | Connection, +>( + client: TClient, config: DrizzleConfig = {}, -): PlanetScaleDatabase { +): PlanetScaleDatabase & { + $client: TClient; +} { // Client is not Drizzle Object, so we can ignore this rule here // eslint-disable-next-line no-instanceof/no-instanceof if (!(client instanceof Client)) { @@ -85,5 +90,8 @@ Starting from version 0.30.0, you will encounter an error if you attempt to use } const session = new PlanetscaleSession(client, dialect, undefined, schema, { logger }); - return new PlanetScaleDatabase(dialect, session, schema as any, 'planetscale') as PlanetScaleDatabase; + const db = new PlanetScaleDatabase(dialect, session, schema as any, 'planetscale') as PlanetScaleDatabase; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index 6714cff8d..6a72afefb 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -22,7 +22,9 @@ export class PostgresJsDatabase< export function drizzle = Record>( client: Sql, config: DrizzleConfig = {}, -): PostgresJsDatabase { +): PostgresJsDatabase & { + $client: Sql; +} { const transparentParser = (val: any) => val; // Override postgres.js default date parsers: https://github.com/porsager/postgres/discussions/761 @@ -55,5 +57,8 @@ export function drizzle = Record; + const db = new PostgresJsDatabase(dialect, session, schema as any) as PostgresJsDatabase; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/tidb-serverless/driver.ts b/drizzle-orm/src/tidb-serverless/driver.ts index b762bd889..59843a670 100644 --- a/drizzle-orm/src/tidb-serverless/driver.ts +++ b/drizzle-orm/src/tidb-serverless/driver.ts @@ -27,7 +27,9 @@ export class TiDBServerlessDatabase< export function drizzle = Record>( client: Connection, config: DrizzleConfig = {}, -): TiDBServerlessDatabase { +): TiDBServerlessDatabase & { + $client: Connection; +} { const dialect = new MySqlDialect(); let logger; if (config.logger === true) { @@ -50,5 +52,8 @@ export function drizzle = Record; + const db = new TiDBServerlessDatabase(dialect, session, schema as any, 'default') as TiDBServerlessDatabase; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index 54bd44325..b58de63c3 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -223,3 +223,5 @@ export type KnownKeysOnly = { }; export type IsAny = 0 extends (1 & T) ? true : false; + +export type IfNotImported = unknown extends T ? Y : N; diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index bc990d0b3..ae369453e 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -51,7 +51,9 @@ export class VercelPgDatabase< export function drizzle = Record>( client: VercelPgClient, config: DrizzleConfig = {}, -): VercelPgDatabase { +): VercelPgDatabase & { + $client: VercelPgClient; +} { const dialect = new PgDialect(); let logger; if (config.logger === true) { @@ -75,5 +77,8 @@ export function drizzle = Record; + const db = new VercelPgDatabase(dialect, session, schema as any) as VercelPgDatabase; + ( db).$client = client; + + return db as any; } diff --git a/drizzle-orm/src/xata-http/driver.ts b/drizzle-orm/src/xata-http/driver.ts index 9838083aa..74f6f8600 100644 --- a/drizzle-orm/src/xata-http/driver.ts +++ b/drizzle-orm/src/xata-http/driver.ts @@ -49,7 +49,9 @@ export class XataHttpDatabase = Record = Record>( client: XataHttpClient, config: DrizzleConfig = {}, -): XataHttpDatabase { +): XataHttpDatabase & { + $client: XataHttpClient; +} { const dialect = new PgDialect(); let logger; if (config.logger === true) { @@ -71,9 +73,12 @@ export function drizzle = Record> | undefined, ); + ( db).$client = client; + + return db as any; } diff --git a/integration-tests/tests/sqlite/d1-batch.test.ts b/integration-tests/tests/sqlite/d1-batch.test.ts index 7ca1dff0f..2c46a6fe4 100644 --- a/integration-tests/tests/sqlite/d1-batch.test.ts +++ b/integration-tests/tests/sqlite/d1-batch.test.ts @@ -139,7 +139,7 @@ let db: DrizzleD1Database; beforeAll(async () => { const sqliteDb = await createSQLiteDB(':memory:'); const d1db = new D1Database(new D1DatabaseAPI(sqliteDb)); - db = drizzle(d1db as any, { logger: ENABLE_LOGGING, schema }); + db = drizzle(d1db, { logger: ENABLE_LOGGING, schema }); }); beforeEach(async () => { diff --git a/integration-tests/tests/sqlite/d1.test.ts b/integration-tests/tests/sqlite/d1.test.ts index 20e9e9d14..8c0863c5c 100644 --- a/integration-tests/tests/sqlite/d1.test.ts +++ b/integration-tests/tests/sqlite/d1.test.ts @@ -16,7 +16,7 @@ let db: DrizzleD1Database; beforeAll(async () => { const sqliteDb = await createSQLiteDB(':memory:'); const d1db = new D1Database(new D1DatabaseAPI(sqliteDb)); - db = drizzle(d1db as any, { logger: ENABLE_LOGGING }); + db = drizzle(d1db, { logger: ENABLE_LOGGING }); }); beforeEach((ctx) => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 313676e09..961f667f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -308,12 +308,15 @@ importers: '@libsql/client': specifier: ^0.10.0 version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + '@miniflare/d1': + specifier: ^2.14.2 + version: 2.14.2 '@neondatabase/serverless': specifier: ^0.9.0 version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -361,7 +364,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -10204,8 +10207,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10291,11 +10294,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/client-sso-oidc@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10334,7 +10337,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.478.0': @@ -10601,11 +10603,11 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0': + '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10644,6 +10646,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/core@3.477.0': @@ -10798,7 +10801,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -11005,7 +11008,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -11206,7 +11209,7 @@ snapshots: '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11215,7 +11218,7 @@ snapshots: '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -12887,7 +12890,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -12905,7 +12908,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13479,10 +13482,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) '@opentelemetry/api@1.8.0': {} @@ -13619,7 +13622,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13629,7 +13632,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13656,14 +13659,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13752,16 +13755,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13776,7 +13779,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13790,7 +13793,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13813,12 +13816,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) optionalDependencies: '@types/react': 18.3.1 @@ -15094,7 +15097,7 @@ snapshots: pathe: 1.1.2 picocolors: 1.0.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + vitest: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) '@vitest/utils@1.6.0': dependencies: @@ -17124,35 +17127,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) expo-modules-autolinking@1.11.1: dependencies: @@ -17166,24 +17169,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -18659,12 +18662,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18740,13 +18743,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18760,7 +18763,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -18786,7 +18789,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -18794,7 +18797,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -18803,7 +18806,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -19689,10 +19692,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8): + react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19705,19 +19708,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19736,14 +19739,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8) + react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -21596,15 +21599,17 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8): + ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8): + ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From ba1160649db63536f34e557e93f73973ccd14c67 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 11 Sep 2024 19:13:55 +0300 Subject: [PATCH 159/492] Add kit casing for pg --- drizzle-kit/src/introspect-pg.ts | 95 +++++++++++-------- drizzle-orm/src/casing.ts | 6 +- drizzle-orm/src/mysql-core/columns/all.ts | 48 +++++----- drizzle-orm/src/mysql-core/dialect.ts | 2 +- .../query-builders/query-builder.ts | 5 +- drizzle-orm/src/pg-core/dialect.ts | 2 +- .../pg-core/query-builders/query-builder.ts | 5 +- drizzle-orm/src/pg-core/unique-constraint.ts | 5 +- drizzle-orm/src/sqlite-core/columns/all.ts | 12 +-- drizzle-orm/src/sqlite-core/dialect.ts | 2 +- .../query-builders/query-builder.ts | 5 +- integration-tests/tests/pg/pg-common.ts | 2 +- 12 files changed, 103 insertions(+), 86 deletions(-) diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index b7a52b735..d83d1f9f8 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -8,8 +8,8 @@ import { Relation, Relations, } from 'drizzle-orm/relations'; -import { plural, singular } from 'pluralize'; import './@types/utils'; +import { toCamelCase } from 'drizzle-orm/casing'; import { Casing } from './cli/validations/common'; import { vectorOps } from './extensions/vector'; import { assertUnreachable } from './global'; @@ -176,6 +176,17 @@ const withCasing = (value: string, casing: Casing) => { assertUnreachable(casing); }; +const dbColumnName = ({ name, casing, withMode = false }: { name: string; casing: Casing; withMode?: boolean }) => { + if (casing === 'preserve') { + return ''; + } + if (casing === 'camel') { + return toCamelCase(name) === name ? '' : withMode ? `"${name}", ` : `"${name}"`; + } + + assertUnreachable(casing); +}; + export const relationsToTypeScriptForStudio = ( schema: Record>>, relations: Record>>>, @@ -760,16 +771,16 @@ const column = ( paramNameFor(type.replace('[]', ''), typeSchema), casing, ) - }("${name}")`; + }(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('serial')) { - return `${withCasing(name, casing)}: serial("${name}")`; + return `${withCasing(name, casing)}: serial(${dbColumnName({ name, casing })})`; } if (lowered.startsWith('smallserial')) { - return `${withCasing(name, casing)}: smallserial("${name}")`; + return `${withCasing(name, casing)}: smallserial(${dbColumnName({ name, casing })})`; } if (lowered.startsWith('bigserial')) { @@ -778,42 +789,42 @@ const column = ( name, casing, ) - }: bigserial("${name}", { mode: "bigint" })`; + }: bigserial(${dbColumnName({ name, casing, withMode: true })}{ mode: "bigint" })`; } if (lowered.startsWith('integer')) { - let out = `${withCasing(name, casing)}: integer("${name}")`; + let out = `${withCasing(name, casing)}: integer(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('smallint')) { - let out = `${withCasing(name, casing)}: smallint("${name}")`; + let out = `${withCasing(name, casing)}: smallint(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('bigint')) { let out = `// You can use { mode: "bigint" } if numbers are exceeding js number limitations\n\t`; - out += `${withCasing(name, casing)}: bigint("${name}", { mode: "number" })`; + out += `${withCasing(name, casing)}: bigint(${dbColumnName({ name, casing, withMode: true })}{ mode: "number" })`; return out; } if (lowered.startsWith('boolean')) { - let out = `${withCasing(name, casing)}: boolean("${name}")`; + let out = `${withCasing(name, casing)}: boolean(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('double precision')) { - let out = `${withCasing(name, casing)}: doublePrecision("${name}")`; + let out = `${withCasing(name, casing)}: doublePrecision(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('real')) { - let out = `${withCasing(name, casing)}: real("${name}")`; + let out = `${withCasing(name, casing)}: real(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('uuid')) { - let out = `${withCasing(name, casing)}: uuid("${name}")`; + let out = `${withCasing(name, casing)}: uuid(${dbColumnName({ name, casing })})`; return out; } @@ -831,8 +842,8 @@ const column = ( } let out = params - ? `${withCasing(name, casing)}: numeric("${name}", ${timeConfig(params)})` - : `${withCasing(name, casing)}: numeric("${name}")`; + ? `${withCasing(name, casing)}: numeric(${dbColumnName({ name, casing, withMode: true })}${timeConfig(params)})` + : `${withCasing(name, casing)}: numeric(${dbColumnName({ name, casing })})`; return out; } @@ -856,8 +867,8 @@ const column = ( }); let out = params - ? `${withCasing(name, casing)}: timestamp("${name}", ${params})` - : `${withCasing(name, casing)}: timestamp("${name}")`; + ? `${withCasing(name, casing)}: timestamp(${dbColumnName({ name, casing, withMode: true })}, ${params})` + : `${withCasing(name, casing)}: timestamp(${dbColumnName({ name, casing })})`; return out; } @@ -877,8 +888,8 @@ const column = ( const params = timeConfig({ precision, withTimezone }); let out = params - ? `${withCasing(name, casing)}: time("${name}", ${params})` - : `${withCasing(name, casing)}: time("${name}")`; + ? `${withCasing(name, casing)}: time(${dbColumnName({ name, casing, withMode: true })}, ${params})` + : `${withCasing(name, casing)}: time(${dbColumnName({ name, casing })})`; return out; } @@ -892,50 +903,50 @@ const column = ( const params = intervalConfig(lowered); let out = params - ? `${withCasing(name, casing)}: interval("${name}", ${params})` - : `${withCasing(name, casing)}: interval("${name}")`; + ? `${withCasing(name, casing)}: interval(${dbColumnName({ name, casing, withMode: true })}, ${params})` + : `${withCasing(name, casing)}: interval(${dbColumnName({ name, casing })})`; return out; } if (lowered === 'date') { - let out = `${withCasing(name, casing)}: date("${name}")`; + let out = `${withCasing(name, casing)}: date(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('text')) { - let out = `${withCasing(name, casing)}: text("${name}")`; + let out = `${withCasing(name, casing)}: text(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('jsonb')) { - let out = `${withCasing(name, casing)}: jsonb("${name}")`; + let out = `${withCasing(name, casing)}: jsonb(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('json')) { - let out = `${withCasing(name, casing)}: json("${name}")`; + let out = `${withCasing(name, casing)}: json(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('inet')) { - let out = `${withCasing(name, casing)}: inet("${name}")`; + let out = `${withCasing(name, casing)}: inet(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('cidr')) { - let out = `${withCasing(name, casing)}: cidr("${name}")`; + let out = `${withCasing(name, casing)}: cidr(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('macaddr8')) { - let out = `${withCasing(name, casing)}: macaddr8("${name}")`; + let out = `${withCasing(name, casing)}: macaddr8(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('macaddr')) { - let out = `${withCasing(name, casing)}: macaddr("${name}")`; + let out = `${withCasing(name, casing)}: macaddr(${dbColumnName({ name, casing })})`; return out; } @@ -947,26 +958,26 @@ const column = ( name, casing, ) - }: varchar("${name}", { length: ${ + }: varchar(${dbColumnName({ name, casing, withMode: true })}, { length: ${ lowered.substring( 8, lowered.length - 1, ) } })`; } else { - out = `${withCasing(name, casing)}: varchar("${name}")`; + out = `${withCasing(name, casing)}: varchar(${dbColumnName({ name, casing })})`; } return out; } if (lowered.startsWith('point')) { - let out: string = `${withCasing(name, casing)}: point("${name}")`; + let out: string = `${withCasing(name, casing)}: point(${dbColumnName({ name, casing })})`; return out; } if (lowered.startsWith('line')) { - let out: string = `${withCasing(name, casing)}: point("${name}")`; + let out: string = `${withCasing(name, casing)}: point(${dbColumnName({ name, casing })})`; return out; } @@ -978,16 +989,18 @@ const column = ( if (lowered.length !== 8) { const geometryOptions = lowered.slice(9, -1).split(','); if (geometryOptions.length === 1 && geometryOptions[0] !== '') { - out = `${withCasing(name, casing)}: geometry("${name}", { type: "${geometryOptions[0]}" })`; + out = `${withCasing(name, casing)}: geometry(${dbColumnName({ name, casing, withMode: true })}, { type: "${ + geometryOptions[0] + }" })`; } else if (geometryOptions.length === 2) { - out = `${withCasing(name, casing)}: geometry("${name}", { type: "${geometryOptions[0]}", srid: ${ - geometryOptions[1] - } })`; + out = `${withCasing(name, casing)}: geometry(${dbColumnName({ name, casing, withMode: true })}, { type: "${ + geometryOptions[0] + }", srid: ${geometryOptions[1]} })`; } else { isGeoUnknown = true; } } else { - out = `${withCasing(name, casing)}: geometry("${name}")`; + out = `${withCasing(name, casing)}: geometry(${dbColumnName({ name, casing })})`; } if (isGeoUnknown) { @@ -1007,14 +1020,14 @@ const column = ( name, casing, ) - }: vector("${name}", { dimensions: ${ + }: vector(${dbColumnName({ name, casing, withMode: true })}, { dimensions: ${ lowered.substring( 7, lowered.length - 1, ) } })`; } else { - out = `${withCasing(name, casing)}: vector("${name}")`; + out = `${withCasing(name, casing)}: vector(${dbColumnName({ name, casing })})`; } return out; @@ -1028,14 +1041,14 @@ const column = ( name, casing, ) - }: char("${name}", { length: ${ + }: char(${dbColumnName({ name, casing, withMode: true })}, { length: ${ lowered.substring( 5, lowered.length - 1, ) } })`; } else { - out = `${withCasing(name, casing)}: char("${name}")`; + out = `${withCasing(name, casing)}: char(${dbColumnName({ name, casing })})`; } return out; diff --git a/drizzle-orm/src/casing.ts b/drizzle-orm/src/casing.ts index f09348de0..1603acd38 100644 --- a/drizzle-orm/src/casing.ts +++ b/drizzle-orm/src/casing.ts @@ -1,10 +1,10 @@ -import { Casing, type Column, entityKind } from './index.ts'; +import { type Casing, type Column, entityKind } from './index.ts'; import { Table } from './table.ts'; export function toSnakeCase(input: string) { const words = input .replace(/['\u2019]/g, '') - .match(/[a-z0-9]+|[A-Z]+(?![a-z])|[A-Z][a-z0-9]+/g) ?? []; + .match(/[\da-z]+|[A-Z]+(?![a-z])|[A-Z][\da-z]+/g) ?? []; return words.map((word) => word.toLowerCase()).join('_'); } @@ -12,7 +12,7 @@ export function toSnakeCase(input: string) { export function toCamelCase(input: string) { const words = input .replace(/['\u2019]/g, '') - .match(/[a-z0-9]+|[A-Z]+(?![a-z])|[A-Z][a-z0-9]+/g) ?? []; + .match(/[\da-z]+|[A-Z]+(?![a-z])|[A-Z][\da-z]+/g) ?? []; return words.reduce((acc, word, i) => { const formattedWord = i === 0 ? word.toLowerCase() : `${word[0]!.toUpperCase()}${word.slice(1)}`; diff --git a/drizzle-orm/src/mysql-core/columns/all.ts b/drizzle-orm/src/mysql-core/columns/all.ts index 8559fd204..428b3c330 100644 --- a/drizzle-orm/src/mysql-core/columns/all.ts +++ b/drizzle-orm/src/mysql-core/columns/all.ts @@ -1,27 +1,27 @@ -import { bigint } from './bigint'; -import { binary } from './binary'; -import { boolean } from './boolean'; -import { char } from './char'; -import { customType } from './custom'; -import { date } from './date'; -import { datetime } from './datetime'; -import { decimal } from './decimal'; -import { double } from './double'; -import { mysqlEnum } from './enum'; -import { float } from './float'; -import { int } from './int'; -import { json } from './json'; -import { mediumint } from './mediumint'; -import { real } from './real'; -import { serial } from './serial'; -import { smallint } from './smallint'; -import { text } from './text'; -import { time } from './time'; -import { timestamp } from './timestamp'; -import { tinyint } from './tinyint'; -import { varbinary } from './varbinary'; -import { varchar } from './varchar'; -import { year } from './year'; +import { bigint } from './bigint.ts'; +import { binary } from './binary.ts'; +import { boolean } from './boolean.ts'; +import { char } from './char.ts'; +import { customType } from './custom.ts'; +import { date } from './date.ts'; +import { datetime } from './datetime.ts'; +import { decimal } from './decimal.ts'; +import { double } from './double.ts'; +import { mysqlEnum } from './enum.ts'; +import { float } from './float.ts'; +import { int } from './int.ts'; +import { json } from './json.ts'; +import { mediumint } from './mediumint.ts'; +import { real } from './real.ts'; +import { serial } from './serial.ts'; +import { smallint } from './smallint.ts'; +import { text } from './text.ts'; +import { time } from './time.ts'; +import { timestamp } from './timestamp.ts'; +import { tinyint } from './tinyint.ts'; +import { varbinary } from './varbinary.ts'; +import { varchar } from './varchar.ts'; +import { year } from './year.ts'; export function getMySqlColumnBuilders() { return { diff --git a/drizzle-orm/src/mysql-core/dialect.ts b/drizzle-orm/src/mysql-core/dialect.ts index e82212827..ee28af04d 100644 --- a/drizzle-orm/src/mysql-core/dialect.ts +++ b/drizzle-orm/src/mysql-core/dialect.ts @@ -21,7 +21,7 @@ import { Param, SQL, sql, View } from '~/sql/sql.ts'; import type { Name, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { getTableName, getTableUniqueName, Table } from '~/table.ts'; -import { Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { type Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import { MySqlColumn } from './columns/common.ts'; import type { MySqlDeleteConfig } from './query-builders/delete.ts'; diff --git a/drizzle-orm/src/mysql-core/query-builders/query-builder.ts b/drizzle-orm/src/mysql-core/query-builders/query-builder.ts index 16f5447a1..95b3d6cdd 100644 --- a/drizzle-orm/src/mysql-core/query-builders/query-builder.ts +++ b/drizzle-orm/src/mysql-core/query-builders/query-builder.ts @@ -1,5 +1,6 @@ import { entityKind, is } from '~/entity.ts'; -import { MySqlDialect, MySqlDialectConfig } from '~/mysql-core/dialect.ts'; +import type { MySqlDialectConfig } from '~/mysql-core/dialect.ts'; +import { MySqlDialect } from '~/mysql-core/dialect.ts'; import type { WithSubqueryWithSelection } from '~/mysql-core/subquery.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; @@ -16,7 +17,7 @@ export class QueryBuilder { constructor(dialect?: MySqlDialect | MySqlDialectConfig) { this.dialect = is(dialect, MySqlDialect) ? dialect : undefined; - this.dialectConfig = !is(dialect, MySqlDialect) ? dialect : undefined; + this.dialectConfig = is(dialect, MySqlDialect) ? undefined : dialect; } $with(alias: TAlias) { diff --git a/drizzle-orm/src/pg-core/dialect.ts b/drizzle-orm/src/pg-core/dialect.ts index badd8b755..bc3d4cf52 100644 --- a/drizzle-orm/src/pg-core/dialect.ts +++ b/drizzle-orm/src/pg-core/dialect.ts @@ -49,7 +49,7 @@ import { } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { getTableName, getTableUniqueName, Table } from '~/table.ts'; -import { Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { type Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { PgSession } from './session.ts'; import { PgViewBase } from './view-base.ts'; diff --git a/drizzle-orm/src/pg-core/query-builders/query-builder.ts b/drizzle-orm/src/pg-core/query-builders/query-builder.ts index 7dc40ef0d..9f08f642d 100644 --- a/drizzle-orm/src/pg-core/query-builders/query-builder.ts +++ b/drizzle-orm/src/pg-core/query-builders/query-builder.ts @@ -1,5 +1,6 @@ import { entityKind, is } from '~/entity.ts'; -import { PgDialect, PgDialectConfig } from '~/pg-core/dialect.ts'; +import type { PgDialectConfig } from '~/pg-core/dialect.ts'; +import { PgDialect } from '~/pg-core/dialect.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; @@ -17,7 +18,7 @@ export class QueryBuilder { constructor(dialect?: PgDialect | PgDialectConfig) { this.dialect = is(dialect, PgDialect) ? dialect : undefined; - this.dialectConfig = !is(dialect, PgDialect) ? dialect : undefined; + this.dialectConfig = is(dialect, PgDialect) ? undefined : dialect; } $with(alias: TAlias) { diff --git a/drizzle-orm/src/pg-core/unique-constraint.ts b/drizzle-orm/src/pg-core/unique-constraint.ts index 339fa604e..83d010548 100644 --- a/drizzle-orm/src/pg-core/unique-constraint.ts +++ b/drizzle-orm/src/pg-core/unique-constraint.ts @@ -1,13 +1,14 @@ import { entityKind } from '~/entity.ts'; +import { TableName } from '~/index.ts'; import type { PgColumn } from './columns/index.ts'; -import { PgTable } from './table.ts'; +import type { PgTable } from './table.ts'; export function unique(name?: string): UniqueOnConstraintBuilder { return new UniqueOnConstraintBuilder(name); } export function uniqueKeyName(table: PgTable, columns: string[]) { - return `${table[PgTable.Symbol.Name]}_${columns.join('_')}_unique`; + return `${table[TableName]}_${columns.join('_')}_unique`; } export class UniqueConstraintBuilder { diff --git a/drizzle-orm/src/sqlite-core/columns/all.ts b/drizzle-orm/src/sqlite-core/columns/all.ts index 28ca6fb55..a30ba3eac 100644 --- a/drizzle-orm/src/sqlite-core/columns/all.ts +++ b/drizzle-orm/src/sqlite-core/columns/all.ts @@ -1,9 +1,9 @@ -import { blob } from './blob'; -import { customType } from './custom'; -import { integer } from './integer'; -import { numeric } from './numeric'; -import { real } from './real'; -import { text } from './text'; +import { blob } from './blob.ts'; +import { customType } from './custom.ts'; +import { integer } from './integer.ts'; +import { numeric } from './numeric.ts'; +import { real } from './real.ts'; +import { text } from './text.ts'; export function getSQLiteColumnBuilders() { return { diff --git a/drizzle-orm/src/sqlite-core/dialect.ts b/drizzle-orm/src/sqlite-core/dialect.ts index eac6cf5b3..d3822be5e 100644 --- a/drizzle-orm/src/sqlite-core/dialect.ts +++ b/drizzle-orm/src/sqlite-core/dialect.ts @@ -25,7 +25,7 @@ import type { SQLiteDeleteConfig, SQLiteInsertConfig, SQLiteUpdateConfig } from import { SQLiteTable } from '~/sqlite-core/table.ts'; import { Subquery } from '~/subquery.ts'; import { getTableName, getTableUniqueName, Table } from '~/table.ts'; -import { Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { type Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { SelectedFieldsOrdered, diff --git a/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts b/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts index 49e448ee8..d2df0cf99 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts @@ -2,7 +2,8 @@ import { entityKind, is } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { ColumnsSelection } from '~/sql/sql.ts'; -import { SQLiteDialect, SQLiteDialectConfig, SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; +import type { SQLiteDialectConfig } from '~/sqlite-core/dialect.ts'; +import { SQLiteDialect, SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { WithSubqueryWithSelection } from '~/sqlite-core/subquery.ts'; import { WithSubquery } from '~/subquery.ts'; import { SQLiteSelectBuilder } from './select.ts'; @@ -16,7 +17,7 @@ export class QueryBuilder { constructor(dialect?: SQLiteDialect | SQLiteDialectConfig) { this.dialect = is(dialect, SQLiteDialect) ? dialect : undefined; - this.dialectConfig = !is(dialect, SQLiteDialect) ? dialect : undefined; + this.dialectConfig = is(dialect, SQLiteDialect) ? undefined : dialect; } $with(alias: TAlias) { diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index c031586c7..0ea8f250f 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4569,7 +4569,7 @@ export function tests() { ]); await db.execute(sql`drop table users`); - }) + }); test('proper json and jsonb handling', async (ctx) => { const { db } = ctx.pg; From 7c91f55bccd4c45ec551d5abbd1969cab4568e4a Mon Sep 17 00:00:00 2001 From: Mario564 Date: Wed, 11 Sep 2024 09:44:07 -0700 Subject: [PATCH 160/492] Export `int.common.ts` in `columns/index.ts` --- drizzle-orm/src/pg-core/columns/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/drizzle-orm/src/pg-core/columns/index.ts b/drizzle-orm/src/pg-core/columns/index.ts index 881f53e33..79afc74c6 100644 --- a/drizzle-orm/src/pg-core/columns/index.ts +++ b/drizzle-orm/src/pg-core/columns/index.ts @@ -9,6 +9,7 @@ export * from './date.ts'; export * from './double-precision.ts'; export * from './enum.ts'; export * from './inet.ts'; +export * from './int.common.ts'; export * from './integer.ts'; export * from './interval.ts'; export * from './json.ts'; From cd0b1a29b6988e4c79d6dd7af86d159a2dce2365 Mon Sep 17 00:00:00 2001 From: sukairo-02 Date: Wed, 11 Sep 2024 20:54:33 +0300 Subject: [PATCH 161/492] String as execute input --- drizzle-orm/src/aws-data-api/pg/driver.ts | 2 +- drizzle-orm/src/mysql-core/db.ts | 6 ++-- drizzle-orm/src/pg-core/db.ts | 10 +++--- drizzle-orm/src/sqlite-core/db.ts | 42 +++++++++++------------ 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index bf3e68439..cd7eb9d7e 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -40,7 +40,7 @@ export class AwsDataApiPgDatabase< override execute< TRow extends Record = Record, - >(query: SQLWrapper): PgRaw> { + >(query: SQLWrapper | string): PgRaw> { return super.execute(query); } } diff --git a/drizzle-orm/src/mysql-core/db.ts b/drizzle-orm/src/mysql-core/db.ts index 8934c0edf..12945ac37 100644 --- a/drizzle-orm/src/mysql-core/db.ts +++ b/drizzle-orm/src/mysql-core/db.ts @@ -3,7 +3,7 @@ import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, SQL, SQLWrapper } from '~/sql/sql.ts'; +import { type ColumnsSelection, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; import type { MySqlDialect } from './dialect.ts'; @@ -460,9 +460,9 @@ export class MySqlDatabase< } execute( - query: SQLWrapper, + query: SQLWrapper | string, ): Promise> { - return this.session.execute(query.getSQL()); + return this.session.execute(typeof query === 'string' ? sql.raw(query) : query.getSQL()); } transaction( diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index 62b64fb8f..30421e60d 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -19,7 +19,7 @@ import type { PgTable } from '~/pg-core/table.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, SQL, SQLWrapper } from '~/sql/sql.ts'; +import { type ColumnsSelection, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; import type { PgColumn } from './columns/index.ts'; @@ -597,10 +597,10 @@ export class PgDatabase< } execute = Record>( - query: SQLWrapper, + query: SQLWrapper | string, ): PgRaw> { - const sql = query.getSQL(); - const builtQuery = this.dialect.sqlToQuery(sql); + const sequel = typeof query === 'string' ? sql.raw(query) : query.getSQL(); + const builtQuery = this.dialect.sqlToQuery(sequel); const prepared = this.session.prepareQuery< PreparedQueryConfig & { execute: PgQueryResultKind } >( @@ -611,7 +611,7 @@ export class PgDatabase< ); return new PgRaw( () => prepared.execute(), - sql, + sequel, builtQuery, (result) => prepared.mapResult(result, true), ); diff --git a/drizzle-orm/src/sqlite-core/db.ts b/drizzle-orm/src/sqlite-core/db.ts index 7ae2736e0..fc31207c1 100644 --- a/drizzle-orm/src/sqlite-core/db.ts +++ b/drizzle-orm/src/sqlite-core/db.ts @@ -2,7 +2,7 @@ import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, SQL, SQLWrapper } from '~/sql/sql.ts'; +import { type ColumnsSelection, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteAsyncDialect, SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import { QueryBuilder, @@ -518,60 +518,60 @@ export class BaseSQLiteDatabase< return new SQLiteDeleteBase(from, this.session, this.dialect); } - run(query: SQLWrapper): DBResult { - const sql = query.getSQL(); + run(query: SQLWrapper | string): DBResult { + const sequel = typeof query === 'string' ? sql.raw(query) : query.getSQL(); if (this.resultKind === 'async') { return new SQLiteRaw( - async () => this.session.run(sql), - () => sql, + async () => this.session.run(sequel), + () => sequel, 'run', this.dialect as SQLiteAsyncDialect, this.session.extractRawRunValueFromBatchResult.bind(this.session), ) as DBResult; } - return this.session.run(sql) as DBResult; + return this.session.run(sequel) as DBResult; } - all(query: SQLWrapper): DBResult { - const sql = query.getSQL(); + all(query: SQLWrapper | string): DBResult { + const sequel = typeof query === 'string' ? sql.raw(query) : query.getSQL(); if (this.resultKind === 'async') { return new SQLiteRaw( - async () => this.session.all(sql), - () => sql, + async () => this.session.all(sequel), + () => sequel, 'all', this.dialect as SQLiteAsyncDialect, this.session.extractRawAllValueFromBatchResult.bind(this.session), ) as any; } - return this.session.all(sql) as DBResult; + return this.session.all(sequel) as DBResult; } - get(query: SQLWrapper): DBResult { - const sql = query.getSQL(); + get(query: SQLWrapper | string): DBResult { + const sequel = typeof query === 'string' ? sql.raw(query) : query.getSQL(); if (this.resultKind === 'async') { return new SQLiteRaw( - async () => this.session.get(sql), - () => sql, + async () => this.session.get(sequel), + () => sequel, 'get', this.dialect as SQLiteAsyncDialect, this.session.extractRawGetValueFromBatchResult.bind(this.session), ) as DBResult; } - return this.session.get(sql) as DBResult; + return this.session.get(sequel) as DBResult; } - values(query: SQLWrapper): DBResult { - const sql = query.getSQL(); + values(query: SQLWrapper | string): DBResult { + const sequel = typeof query === 'string' ? sql.raw(query) : query.getSQL(); if (this.resultKind === 'async') { return new SQLiteRaw( - async () => this.session.values(sql), - () => sql, + async () => this.session.values(sequel), + () => sequel, 'values', this.dialect as SQLiteAsyncDialect, this.session.extractRawValuesValueFromBatchResult.bind(this.session), ) as any; } - return this.session.values(sql) as DBResult; + return this.session.values(sequel) as DBResult; } transaction( From 4bc156f326fb1bfcbd3f4dcbbcb95a57ab3ddb44 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Wed, 11 Sep 2024 11:00:01 -0700 Subject: [PATCH 162/492] Remove cirucular deps --- drizzle-orm/src/aws-data-api/pg/driver.ts | 3 ++- drizzle-orm/src/casing.ts | 4 +++- drizzle-orm/src/mysql-core/foreign-keys.ts | 7 ++++--- drizzle-orm/src/mysql-core/query-builders/count.ts | 4 ++-- drizzle-orm/src/mysql-core/unique-constraint.ts | 5 +++-- drizzle-orm/src/mysql2/driver.ts | 2 +- drizzle-orm/src/pg-core/foreign-keys.ts | 7 ++++--- drizzle-orm/src/pg-core/query-builders/count.ts | 4 ++-- drizzle-orm/src/pg-core/unique-constraint.ts | 2 +- drizzle-orm/src/sqlite-core/foreign-keys.ts | 7 ++++--- drizzle-orm/src/sqlite-core/query-builders/count.ts | 4 ++-- drizzle-orm/src/sqlite-core/unique-constraint.ts | 5 +++-- drizzle-orm/src/table.ts | 4 +--- drizzle-orm/src/table.utils.ts | 2 ++ 14 files changed, 34 insertions(+), 26 deletions(-) create mode 100644 drizzle-orm/src/table.utils.ts diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index 662b61f9e..638e9f7ad 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -1,6 +1,7 @@ import { entityKind, is } from '~/entity.ts'; import type { SQL, SQLWrapper } from '~/index.ts'; -import { Param, sql, Table } from '~/index.ts'; +import { Param, sql } from '~/sql/sql.ts'; +import { Table } from '~/table.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; import { PgDatabase } from '~/pg-core/db.ts'; diff --git a/drizzle-orm/src/casing.ts b/drizzle-orm/src/casing.ts index 1603acd38..f2e697c9d 100644 --- a/drizzle-orm/src/casing.ts +++ b/drizzle-orm/src/casing.ts @@ -1,5 +1,7 @@ -import { type Casing, type Column, entityKind } from './index.ts'; +import { entityKind } from './entity.ts'; import { Table } from './table.ts'; +import type { Casing } from './utils.ts'; +import type { Column } from '~/column.ts'; export function toSnakeCase(input: string) { const words = input diff --git a/drizzle-orm/src/mysql-core/foreign-keys.ts b/drizzle-orm/src/mysql-core/foreign-keys.ts index 957e1f15c..3619af8ba 100644 --- a/drizzle-orm/src/mysql-core/foreign-keys.ts +++ b/drizzle-orm/src/mysql-core/foreign-keys.ts @@ -1,6 +1,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyMySqlColumn, MySqlColumn } from './columns/index.ts'; -import { MySqlTable } from './table.ts'; +import type { MySqlTable } from './table.ts'; +import { TableName } from '~/table.utils.ts'; export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; @@ -80,9 +81,9 @@ export class ForeignKey { const columnNames = columns.map((column) => column.name); const foreignColumnNames = foreignColumns.map((column) => column.name); const chunks = [ - this.table[MySqlTable.Symbol.Name], + this.table[TableName], ...columnNames, - foreignColumns[0]!.table[MySqlTable.Symbol.Name], + foreignColumns[0]!.table[TableName], ...foreignColumnNames, ]; return name ?? `${chunks.join('_')}_fk`; diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index 645bb4753..c47672232 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -1,6 +1,6 @@ -import { entityKind, sql } from '~/index.ts'; +import { entityKind } from '~/entity.ts'; import type { SQLWrapper } from '~/sql/sql.ts'; -import { SQL } from '~/sql/sql.ts'; +import { SQL, sql } from '~/sql/sql.ts'; import type { MySqlSession } from '../session.ts'; import type { MySqlTable } from '../table.ts'; import type { MySqlViewBase } from '../view-base.ts'; diff --git a/drizzle-orm/src/mysql-core/unique-constraint.ts b/drizzle-orm/src/mysql-core/unique-constraint.ts index 66ed65198..571ab414b 100644 --- a/drizzle-orm/src/mysql-core/unique-constraint.ts +++ b/drizzle-orm/src/mysql-core/unique-constraint.ts @@ -1,13 +1,14 @@ import { entityKind } from '~/entity.ts'; import type { MySqlColumn } from './columns/index.ts'; -import { MySqlTable } from './table.ts'; +import type { MySqlTable } from './table.ts'; +import { TableName } from '~/table.utils.ts'; export function unique(name?: string): UniqueOnConstraintBuilder { return new UniqueOnConstraintBuilder(name); } export function uniqueKeyName(table: MySqlTable, columns: string[]) { - return `${table[MySqlTable.Symbol.Name]}_${columns.join('_')}_unique`; + return `${table[TableName]}_${columns.join('_')}_unique`; } export class UniqueConstraintBuilder { diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index 7fbede1d9..f60f4146d 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -12,7 +12,7 @@ import { type TablesRelationalConfig, } from '~/relations.ts'; import type { DrizzleConfig } from '~/utils.ts'; -import { DrizzleError } from '../index.ts'; +import { DrizzleError } from '../errors.ts'; import type { MySql2Client, MySql2PreparedQueryHKT, MySql2QueryResultHKT } from './session.ts'; import { MySql2Session } from './session.ts'; diff --git a/drizzle-orm/src/pg-core/foreign-keys.ts b/drizzle-orm/src/pg-core/foreign-keys.ts index 841ac4aa8..341edd312 100644 --- a/drizzle-orm/src/pg-core/foreign-keys.ts +++ b/drizzle-orm/src/pg-core/foreign-keys.ts @@ -1,6 +1,7 @@ import { entityKind } from '~/entity.ts'; import type { AnyPgColumn, PgColumn } from './columns/index.ts'; -import { PgTable } from './table.ts'; +import type { PgTable } from './table.ts'; +import { TableName } from '~/table.utils.ts'; export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; @@ -80,9 +81,9 @@ export class ForeignKey { const columnNames = columns.map((column) => column.name); const foreignColumnNames = foreignColumns.map((column) => column.name); const chunks = [ - this.table[PgTable.Symbol.Name], + this.table[TableName], ...columnNames, - foreignColumns[0]!.table[PgTable.Symbol.Name], + foreignColumns[0]!.table[TableName], ...foreignColumnNames, ]; return name ?? `${chunks.join('_')}_fk`; diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index c93cbb18d..837967d77 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -1,6 +1,6 @@ -import { entityKind, sql } from '~/index.ts'; +import { entityKind } from '~/entity.ts'; import type { SQLWrapper } from '~/sql/sql.ts'; -import { SQL } from '~/sql/sql.ts'; +import { SQL, sql } from '~/sql/sql.ts'; import type { PgSession } from '../session.ts'; import type { PgTable } from '../table.ts'; diff --git a/drizzle-orm/src/pg-core/unique-constraint.ts b/drizzle-orm/src/pg-core/unique-constraint.ts index 83d010548..1a1d8a21d 100644 --- a/drizzle-orm/src/pg-core/unique-constraint.ts +++ b/drizzle-orm/src/pg-core/unique-constraint.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; -import { TableName } from '~/index.ts'; import type { PgColumn } from './columns/index.ts'; import type { PgTable } from './table.ts'; +import { TableName } from '~/table.utils.ts'; export function unique(name?: string): UniqueOnConstraintBuilder { return new UniqueOnConstraintBuilder(name); diff --git a/drizzle-orm/src/sqlite-core/foreign-keys.ts b/drizzle-orm/src/sqlite-core/foreign-keys.ts index 9cc14072f..21d330837 100644 --- a/drizzle-orm/src/sqlite-core/foreign-keys.ts +++ b/drizzle-orm/src/sqlite-core/foreign-keys.ts @@ -1,6 +1,7 @@ import { entityKind } from '~/entity.ts'; import type { AnySQLiteColumn, SQLiteColumn } from './columns/index.ts'; -import { SQLiteTable } from './table.ts'; +import type { SQLiteTable } from './table.ts'; +import { TableName } from '~/table.utils.ts'; export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; @@ -83,9 +84,9 @@ export class ForeignKey { const columnNames = columns.map((column) => column.name); const foreignColumnNames = foreignColumns.map((column) => column.name); const chunks = [ - this.table[SQLiteTable.Symbol.Name], + this.table[TableName], ...columnNames, - foreignColumns[0]!.table[SQLiteTable.Symbol.Name], + foreignColumns[0]!.table[TableName], ...foreignColumnNames, ]; return name ?? `${chunks.join('_')}_fk`; diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index 1b19eed07..d219edb78 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -1,6 +1,6 @@ -import { entityKind, sql } from '~/index.ts'; +import { entityKind } from '~/entity.ts'; import type { SQLWrapper } from '~/sql/sql.ts'; -import { SQL } from '~/sql/sql.ts'; +import { SQL, sql } from '~/sql/sql.ts'; import type { SQLiteSession } from '../session.ts'; import type { SQLiteTable } from '../table.ts'; import type { SQLiteView } from '../view.ts'; diff --git a/drizzle-orm/src/sqlite-core/unique-constraint.ts b/drizzle-orm/src/sqlite-core/unique-constraint.ts index 83dfcebdd..683a717fe 100644 --- a/drizzle-orm/src/sqlite-core/unique-constraint.ts +++ b/drizzle-orm/src/sqlite-core/unique-constraint.ts @@ -1,9 +1,10 @@ import { entityKind } from '~/entity.ts'; import type { SQLiteColumn } from './columns/common.ts'; -import { SQLiteTable } from './table.ts'; +import type { SQLiteTable } from './table.ts'; +import { TableName } from '~/table.utils.ts'; export function uniqueKeyName(table: SQLiteTable, columns: string[]) { - return `${table[SQLiteTable.Symbol.Name]}_${columns.join('_')}_unique`; + return `${table[TableName]}_${columns.join('_')}_unique`; } export function unique(name?: string): UniqueOnConstraintBuilder { diff --git a/drizzle-orm/src/table.ts b/drizzle-orm/src/table.ts index 8632dd35c..0ac2b9e32 100644 --- a/drizzle-orm/src/table.ts +++ b/drizzle-orm/src/table.ts @@ -4,6 +4,7 @@ import type { OptionalKeyOnly, RequiredKeyOnly } from './operations.ts'; import type { ExtraConfigColumn } from './pg-core/index.ts'; import type { SQLWrapper } from './sql/sql.ts'; import type { Simplify, Update } from './utils.ts'; +import { TableName } from './table.utils.ts'; export interface TableConfig> { name: string; @@ -16,9 +17,6 @@ export type UpdateTableConfig >; -/** @internal */ -export const TableName = Symbol.for('drizzle:Name'); - /** @internal */ export const Schema = Symbol.for('drizzle:Schema'); diff --git a/drizzle-orm/src/table.utils.ts b/drizzle-orm/src/table.utils.ts new file mode 100644 index 000000000..4e0278c05 --- /dev/null +++ b/drizzle-orm/src/table.utils.ts @@ -0,0 +1,2 @@ +/** @internal */ +export const TableName = Symbol.for('drizzle:Name'); From e3fdcefb4c93d3a2b0ab304471ffe416d1ed36e0 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Wed, 11 Sep 2024 11:03:56 -0700 Subject: [PATCH 163/492] Format --- drizzle-orm/src/aws-data-api/pg/driver.ts | 4 ++-- drizzle-orm/src/casing.ts | 2 +- drizzle-orm/src/mysql-core/foreign-keys.ts | 2 +- drizzle-orm/src/mysql-core/unique-constraint.ts | 2 +- drizzle-orm/src/pg-core/foreign-keys.ts | 2 +- drizzle-orm/src/pg-core/unique-constraint.ts | 2 +- drizzle-orm/src/sqlite-core/foreign-keys.ts | 2 +- drizzle-orm/src/sqlite-core/unique-constraint.ts | 2 +- drizzle-orm/src/table.ts | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index 638e9f7ad..d667a34b1 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -1,7 +1,5 @@ import { entityKind, is } from '~/entity.ts'; import type { SQL, SQLWrapper } from '~/index.ts'; -import { Param, sql } from '~/sql/sql.ts'; -import { Table } from '~/table.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; import { PgDatabase } from '~/pg-core/db.ts'; @@ -15,6 +13,8 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; +import { Param, sql } from '~/sql/sql.ts'; +import { Table } from '~/table.ts'; import type { DrizzleConfig, UpdateSet } from '~/utils.ts'; import type { AwsDataApiClient, AwsDataApiPgQueryResult, AwsDataApiPgQueryResultHKT } from './session.ts'; import { AwsDataApiSession } from './session.ts'; diff --git a/drizzle-orm/src/casing.ts b/drizzle-orm/src/casing.ts index f2e697c9d..8372227b3 100644 --- a/drizzle-orm/src/casing.ts +++ b/drizzle-orm/src/casing.ts @@ -1,7 +1,7 @@ +import type { Column } from '~/column.ts'; import { entityKind } from './entity.ts'; import { Table } from './table.ts'; import type { Casing } from './utils.ts'; -import type { Column } from '~/column.ts'; export function toSnakeCase(input: string) { const words = input diff --git a/drizzle-orm/src/mysql-core/foreign-keys.ts b/drizzle-orm/src/mysql-core/foreign-keys.ts index 3619af8ba..c8c34d6fd 100644 --- a/drizzle-orm/src/mysql-core/foreign-keys.ts +++ b/drizzle-orm/src/mysql-core/foreign-keys.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; +import { TableName } from '~/table.utils.ts'; import type { AnyMySqlColumn, MySqlColumn } from './columns/index.ts'; import type { MySqlTable } from './table.ts'; -import { TableName } from '~/table.utils.ts'; export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; diff --git a/drizzle-orm/src/mysql-core/unique-constraint.ts b/drizzle-orm/src/mysql-core/unique-constraint.ts index 571ab414b..01a3c36c2 100644 --- a/drizzle-orm/src/mysql-core/unique-constraint.ts +++ b/drizzle-orm/src/mysql-core/unique-constraint.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; +import { TableName } from '~/table.utils.ts'; import type { MySqlColumn } from './columns/index.ts'; import type { MySqlTable } from './table.ts'; -import { TableName } from '~/table.utils.ts'; export function unique(name?: string): UniqueOnConstraintBuilder { return new UniqueOnConstraintBuilder(name); diff --git a/drizzle-orm/src/pg-core/foreign-keys.ts b/drizzle-orm/src/pg-core/foreign-keys.ts index 341edd312..f8ba0b862 100644 --- a/drizzle-orm/src/pg-core/foreign-keys.ts +++ b/drizzle-orm/src/pg-core/foreign-keys.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; +import { TableName } from '~/table.utils.ts'; import type { AnyPgColumn, PgColumn } from './columns/index.ts'; import type { PgTable } from './table.ts'; -import { TableName } from '~/table.utils.ts'; export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; diff --git a/drizzle-orm/src/pg-core/unique-constraint.ts b/drizzle-orm/src/pg-core/unique-constraint.ts index 1a1d8a21d..ceb860b6f 100644 --- a/drizzle-orm/src/pg-core/unique-constraint.ts +++ b/drizzle-orm/src/pg-core/unique-constraint.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; +import { TableName } from '~/table.utils.ts'; import type { PgColumn } from './columns/index.ts'; import type { PgTable } from './table.ts'; -import { TableName } from '~/table.utils.ts'; export function unique(name?: string): UniqueOnConstraintBuilder { return new UniqueOnConstraintBuilder(name); diff --git a/drizzle-orm/src/sqlite-core/foreign-keys.ts b/drizzle-orm/src/sqlite-core/foreign-keys.ts index 21d330837..1c947f7f5 100644 --- a/drizzle-orm/src/sqlite-core/foreign-keys.ts +++ b/drizzle-orm/src/sqlite-core/foreign-keys.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; +import { TableName } from '~/table.utils.ts'; import type { AnySQLiteColumn, SQLiteColumn } from './columns/index.ts'; import type { SQLiteTable } from './table.ts'; -import { TableName } from '~/table.utils.ts'; export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; diff --git a/drizzle-orm/src/sqlite-core/unique-constraint.ts b/drizzle-orm/src/sqlite-core/unique-constraint.ts index 683a717fe..e9c47e7d3 100644 --- a/drizzle-orm/src/sqlite-core/unique-constraint.ts +++ b/drizzle-orm/src/sqlite-core/unique-constraint.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; +import { TableName } from '~/table.utils.ts'; import type { SQLiteColumn } from './columns/common.ts'; import type { SQLiteTable } from './table.ts'; -import { TableName } from '~/table.utils.ts'; export function uniqueKeyName(table: SQLiteTable, columns: string[]) { return `${table[TableName]}_${columns.join('_')}_unique`; diff --git a/drizzle-orm/src/table.ts b/drizzle-orm/src/table.ts index 0ac2b9e32..0bf08fb3b 100644 --- a/drizzle-orm/src/table.ts +++ b/drizzle-orm/src/table.ts @@ -3,8 +3,8 @@ import { entityKind } from './entity.ts'; import type { OptionalKeyOnly, RequiredKeyOnly } from './operations.ts'; import type { ExtraConfigColumn } from './pg-core/index.ts'; import type { SQLWrapper } from './sql/sql.ts'; -import type { Simplify, Update } from './utils.ts'; import { TableName } from './table.utils.ts'; +import type { Simplify, Update } from './utils.ts'; export interface TableConfig> { name: string; From dcbd5e6f0cb222a42bf1917f8aa6ac143be0eb8e Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 12 Sep 2024 10:55:49 +0300 Subject: [PATCH 164/492] removed console.log merged beta to branch --- drizzle-kit/tests/push/sqlite.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index 26b43f13f..cd030486a 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -364,8 +364,6 @@ test('drop autoincrement. drop column with data', async (t) => { seedStatements, ); - console.log('statements: ', statements); - expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'recreate_table', From 692da61bd462d20070e340a022b8a95afc4b0aa1 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Thu, 12 Sep 2024 12:31:27 +0300 Subject: [PATCH 165/492] Fixed version --- drizzle-orm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index a86983f3e..b4952f2c4 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.33.0", + "version": "0.34.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { From f48d7d6dbe03d6191db03772b4991c4551e01740 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 12 Sep 2024 12:34:53 +0300 Subject: [PATCH 166/492] rewrote introspect tests added introspect tests for checks --- drizzle-kit/tests/introspect/mysql.test.ts | 24 +++++- drizzle-kit/tests/introspect/pg.test.ts | 54 ++++++++++++ drizzle-kit/tests/introspect/sqlite.test.ts | 25 +++++- drizzle-kit/tests/schemaDiffer.ts | 92 ++++++++------------- 4 files changed, 135 insertions(+), 60 deletions(-) diff --git a/drizzle-kit/tests/introspect/mysql.test.ts b/drizzle-kit/tests/introspect/mysql.test.ts index e35b34f40..9bf22d759 100644 --- a/drizzle-kit/tests/introspect/mysql.test.ts +++ b/drizzle-kit/tests/introspect/mysql.test.ts @@ -1,6 +1,6 @@ import Docker from 'dockerode'; import { SQL, sql } from 'drizzle-orm'; -import { char, int, mysqlTable, text, varchar } from 'drizzle-orm/mysql-core'; +import { char, check, int, mysqlTable, serial, text, varchar } from 'drizzle-orm/mysql-core'; import * as fs from 'fs'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; @@ -165,3 +165,25 @@ test('Default value of character type column: varchar', async () => { await client.query(`drop table users;`); }); + +test('introspect checks', async () => { + const schema = { + users: mysqlTable('users', { + id: serial('id'), + name: varchar('name', { length: 255 }), + age: int('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'introspect-checks', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index 509411f84..f8ece6236 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -406,3 +406,57 @@ test('introspect enum with similar name to native type', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('introspect checks', async () => { + const client = new PGlite(); + + const schema = { + users: pgTable('users', { + id: serial('id'), + name: varchar('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-checks', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect checks from different schemas with same names', async () => { + const client = new PGlite(); + + const mySchema = pgSchema('schema2'); + const schema = { + mySchema, + users: pgTable('users', { + id: serial('id'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + usersInMySchema: mySchema.table('users', { + id: serial('id'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} < 1`), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-checks', + ['public', 'schema2'], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/introspect/sqlite.test.ts b/drizzle-kit/tests/introspect/sqlite.test.ts index 18473e87b..986b75bff 100644 --- a/drizzle-kit/tests/introspect/sqlite.test.ts +++ b/drizzle-kit/tests/introspect/sqlite.test.ts @@ -1,6 +1,6 @@ import Database from 'better-sqlite3'; import { SQL, sql } from 'drizzle-orm'; -import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { check, int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { introspectSQLiteToFile } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; @@ -55,3 +55,26 @@ test('generated always column virtual: link to another column', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('introspect checks', async () => { + const sqlite = new Database(':memory:'); + + const schema = { + users: sqliteTable('users', { + id: int('id'), + name: text('name'), + age: int('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const { statements, sqlStatements } = await introspectSQLiteToFile( + sqlite, + schema, + 'introspect-checks', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 0b261f3da..a18b89328 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -20,6 +20,11 @@ import { logSuggestionsAndReturn } from 'src/cli/commands/sqlitePushUtils'; import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql'; import { schemaToTypeScript } from 'src/introspect-pg'; import { schemaToTypeScript as schemaToTypeScriptSQLite } from 'src/introspect-sqlite'; +import { + prepareMySqlMigrationSnapshot, + preparePgMigrationSnapshot, + prepareSqliteMigrationSnapshot, +} from 'src/migrationPreparator'; import { prepareFromMySqlImports } from 'src/serializer/mysqlImports'; import { mysqlSchema, squashMysqlScheme } from 'src/serializer/mysqlSchema'; import { generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; @@ -1341,50 +1346,33 @@ export const introspectPgToFile = async ( const sn2AfterIm = squashPgScheme(sch2); const validatedCurAfterImport = pgSchema.parse(sch2); - const leftTables = Object.values(initSchema).filter((it) => is(it, PgTable)) as PgTable[]; - - const leftSchemas = Object.values(initSchema).filter((it) => is(it, PgSchema)) as PgSchema[]; - - const leftEnums = Object.values(initSchema).filter((it) => isPgEnum(it)) as PgEnum[]; + // save snapshot + fs.writeFileSync(`tests/introspect/postgres/${testName}.json`, JSON.stringify(validatedCurAfterImport)); - const leftSequences = Object.values(initSchema).filter((it) => isPgSequence(it)) as PgSequence[]; - - const initSnapshot = generatePgSnapshot( - leftTables, - leftEnums, - leftSchemas, - leftSequences, + const { cur } = await preparePgMigrationSnapshot( + [`tests/introspect/${testName}.json`], + `tests/introspect/${testName}.ts`, ); - const { version: initV, dialect: initD, ...initRest } = initSnapshot; - - const initSch = { - version: '7', - dialect: 'postgresql', - id: '0', - prevId: '0', - ...initRest, - } as const; - - const initSn = squashPgScheme(initSch); - const validatedCur = pgSchema.parse(initSch); + const squashedCurr = squashPgScheme(cur); const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements, } = await applyPgSnapshotsDiff( sn2AfterIm, - initSn, + squashedCurr, testSchemasResolver(new Set()), testEnumsResolver(new Set()), testSequencesResolver(new Set()), testTablesResolver(new Set()), testColumnsResolver(new Set()), validatedCurAfterImport, - validatedCur, + cur, ); fs.rmSync(`tests/introspect/${testName}.ts`); + fs.rmSync(`tests/introspect/${testName}.json`); return { sqlStatements: afterFileSqlStatements, @@ -1438,36 +1426,30 @@ export const introspectMySQLToFile = async ( const sn2AfterIm = squashMysqlScheme(sch2); const validatedCurAfterImport = mysqlSchema.parse(sch2); - const leftTables = Object.values(initSchema).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - - const initSnapshot = generateMySqlSnapshot(leftTables); - - const { version: initV, dialect: initD, ...initRest } = initSnapshot; + // save snapshot + fs.writeFileSync(`tests/introspect/mysql/${testName}.json`, JSON.stringify(validatedCurAfterImport)); - const initSch = { - version: '5', - dialect: 'mysql', - id: '0', - prevId: '0', - ...initRest, - } as const; + const { cur } = await prepareMySqlMigrationSnapshot( + [`tests/introspect/mysql/${testName}.json`], + `tests/introspect/mysql/${testName}.ts`, + ); - const initSn = squashMysqlScheme(initSch); - const validatedCur = mysqlSchema.parse(initSch); + const squashedCurr = squashMysqlScheme(cur); const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements, } = await applyMysqlSnapshotsDiff( sn2AfterIm, - initSn, + squashedCurr, testTablesResolver(new Set()), testColumnsResolver(new Set()), validatedCurAfterImport, - validatedCur, + cur, ); fs.rmSync(`tests/introspect/mysql/${testName}.ts`); + fs.rmSync(`tests/introspect/mysql/${testName}.json`); return { sqlStatements: afterFileSqlStatements, @@ -1522,36 +1504,30 @@ export const introspectSQLiteToFile = async ( const sn2AfterIm = squashSqliteScheme(sch2); const validatedCurAfterImport = sqliteSchema.parse(sch2); - const leftTables = Object.values(initSchema).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - - const initSnapshot = generateSqliteSnapshot(leftTables); + // save snapshot + fs.writeFileSync(`tests/introspect/sqlite/${testName}.json`, JSON.stringify(validatedCurAfterImport)); - const { version: initV, dialect: initD, ...initRest } = initSnapshot; - - const initSch = { - version: '6', - dialect: 'sqlite', - id: '0', - prevId: '0', - ...initRest, - } as const; + const { cur } = await prepareSqliteMigrationSnapshot( + [`tests/introspect/sqlite/${testName}.json`], + `tests/introspect/sqlite/${testName}.ts`, + ); - const initSn = squashSqliteScheme(initSch); - const validatedCur = sqliteSchema.parse(initSch); + const squashedCurr = squashSqliteScheme(cur); const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements, } = await applySqliteSnapshotsDiff( sn2AfterIm, - initSn, + squashedCurr, testTablesResolver(new Set()), testColumnsResolver(new Set()), validatedCurAfterImport, - validatedCur, + cur, ); fs.rmSync(`tests/introspect/sqlite/${testName}.ts`); + fs.rmSync(`tests/introspect/sqlite/${testName}.json`); return { sqlStatements: afterFileSqlStatements, From af54b5246aefb57cbf68f882c72144c8b72b7c46 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 12 Sep 2024 13:24:43 +0300 Subject: [PATCH 167/492] added progress callbacks for introspect with checks --- drizzle-kit/src/cli/views.ts | 7 +++++++ drizzle-kit/src/serializer/mysqlSerializer.ts | 9 +++++++++ drizzle-kit/src/serializer/pgSerializer.ts | 6 ++++++ drizzle-kit/src/serializer/sqliteSerializer.ts | 10 ++++++++++ 4 files changed, 32 insertions(+) diff --git a/drizzle-kit/src/cli/views.ts b/drizzle-kit/src/cli/views.ts index 56e0331df..8edb805cc 100644 --- a/drizzle-kit/src/cli/views.ts +++ b/drizzle-kit/src/cli/views.ts @@ -330,6 +330,7 @@ export type IntrospectStage = | 'columns' | 'enums' | 'indexes' + | 'checks' | 'fks'; type IntrospectState = { [key in IntrospectStage]: { @@ -369,6 +370,11 @@ export class IntrospectProgress extends TaskView { name: 'foreign keys', status: 'fetching', }, + checks: { + count: 0, + name: 'check constraints', + status: 'fetching', + }, }; constructor(private readonly hasEnums: boolean = false) { @@ -422,6 +428,7 @@ export class IntrospectProgress extends TaskView { info += this.hasEnums ? this.statusText(spin, this.state.enums) : ''; info += this.statusText(spin, this.state.indexes); info += this.statusText(spin, this.state.fks); + info += this.statusText(spin, this.state.checks); return info; } } diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index a5bdf7c6f..297ea400f 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -434,6 +434,7 @@ export const fromDatabase = async ( let tablesCount = new Set(); let indexesCount = 0; let foreignKeysCount = 0; + let checksCount = 0; const idxs = await db.query( `select * from INFORMATION_SCHEMA.STATISTICS @@ -773,6 +774,10 @@ AND tc.constraint_type = 'CHECK';`, ); + checksCount += checkConstraints.length; + if (progressCallback) { + progressCallback('checks', checksCount, 'fetching'); + } for (const checkConstraintRow of checkConstraints) { const constraintName = checkConstraintRow['CONSTRAINT_NAME']; const constraintValue = checkConstraintRow['CHECK_CLAUSE']; @@ -787,6 +792,10 @@ AND }; } + if (progressCallback) { + progressCallback('checks', checksCount, 'done'); + } + return { version: '5', dialect: 'mysql', diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 48f002b51..f1aaab088 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -674,6 +674,7 @@ export const fromDatabase = async ( let indexesCount = 0; let foreignKeysCount = 0; let tableCount = 0; + let checksCount = 0; const sequencesToReturn: Record = {}; @@ -956,6 +957,10 @@ export const fromDatabase = async ( } } + checksCount += tableChecks.length; + if (progressCallback) { + progressCallback('checks', checksCount, 'fetching'); + } for (const checks of tableChecks) { // CHECK (((email)::text <> 'test@gmail.com'::text)) // Where (email) is column in table @@ -1302,6 +1307,7 @@ export const fromDatabase = async ( progressCallback('columns', columnsCount, 'done'); progressCallback('indexes', indexesCount, 'done'); progressCallback('fks', foreignKeysCount, 'done'); + progressCallback('checks', checksCount, 'done'); } const schemasObject = Object.fromEntries([...schemas].map((it) => [it, it])); diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index e8ca76269..653c2cb65 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -447,6 +447,7 @@ export const fromDatabase = async ( let tablesCount = new Set(); let indexesCount = 0; let foreignKeysCount = 0; + let checksCount = 0; // append primaryKeys by table const tableToPk: { [tname: string]: string[] } = {}; @@ -742,6 +743,11 @@ WHERE }); } + checksCount += Object.values(checkConstraints).length; + if (progressCallback) { + progressCallback('checks', checksCount, 'fetching'); + } + const table = result[tableName]; if (!table) { @@ -759,6 +765,10 @@ WHERE } } + if (progressCallback) { + progressCallback('checks', checksCount, 'done'); + } + return { version: '6', dialect: 'sqlite', From 017859141f83ac29d46af17ccd2a55fe31e90dba Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 12 Sep 2024 14:23:44 +0300 Subject: [PATCH 168/492] updated tests for introspect --- drizzle-kit/tests/introspect/mysql.test.ts | 2 ++ drizzle-kit/tests/introspect/pg.test.ts | 5 +++ drizzle-kit/tests/push/mysql-push.test.ts | 6 ++-- drizzle-kit/tests/schemaDiffer.ts | 39 ++++++++++++++-------- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/drizzle-kit/tests/introspect/mysql.test.ts b/drizzle-kit/tests/introspect/mysql.test.ts index 9bf22d759..959304857 100644 --- a/drizzle-kit/tests/introspect/mysql.test.ts +++ b/drizzle-kit/tests/introspect/mysql.test.ts @@ -186,4 +186,6 @@ test('introspect checks', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); + + await client.query(`drop table users;`); }); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index f8ece6236..fc2221499 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -30,9 +30,14 @@ import { uuid, varchar, } from 'drizzle-orm/pg-core'; +import fs from 'fs'; import { introspectPgToFile } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; +if (!fs.existsSync('tests/introspect/postgres')) { + fs.mkdirSync('tests/introspect/postgres'); +} + test('basic introspect test', async () => { const client = new PGlite(); diff --git a/drizzle-kit/tests/push/mysql-push.test.ts b/drizzle-kit/tests/push/mysql-push.test.ts index 0f7863fa5..baa834b5d 100644 --- a/drizzle-kit/tests/push/mysql-push.test.ts +++ b/drizzle-kit/tests/push/mysql-push.test.ts @@ -120,7 +120,7 @@ test('add check constraint to table', async () => { `ALTER TABLE \`test\` ADD CONSTRAINT \`some_check2\` CHECK ('test' < 100);`, ]); - await client.query(`DROP TABLE \`test\``); + await client.query(`DROP TABLE \`test\`;`); }); test('drop check constraint to table', async () => { @@ -168,7 +168,7 @@ test('drop check constraint to table', async () => { `ALTER TABLE \`test\` DROP CONSTRAINT \`some_check2\`;`, ]); - await client.query(`DROP TABLE \`test\``); + await client.query(`DROP TABLE \`test\`;`); }); test('db has checks. Push with same names', async () => { @@ -199,4 +199,6 @@ test('db has checks. Push with same names', async () => { expect(statements).toStrictEqual([]); expect(sqlStatements).toStrictEqual([]); + + await client.query(`DROP TABLE \`test\`;`); }); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index a18b89328..e214ef006 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -1,6 +1,7 @@ import { PGlite } from '@electric-sql/pglite'; import { Client } from '@libsql/client/.'; import { Database } from 'better-sqlite3'; +import { randomUUID } from 'crypto'; import { is } from 'drizzle-orm'; import { MySqlSchema, MySqlTable } from 'drizzle-orm/mysql-core'; import { isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable } from 'drizzle-orm/pg-core'; @@ -1320,10 +1321,10 @@ export const introspectPgToFile = async ( const file = schemaToTypeScript(introspectedSchema, 'camel'); - fs.writeFileSync(`tests/introspect/${testName}.ts`, file.file); + fs.writeFileSync(`tests/introspect/postgres/${testName}.ts`, file.file); const response = await prepareFromPgImports([ - `tests/introspect/${testName}.ts`, + `tests/introspect/postgres/${testName}.ts`, ]); const afterFileImports = generatePgSnapshot( @@ -1349,11 +1350,15 @@ export const introspectPgToFile = async ( // save snapshot fs.writeFileSync(`tests/introspect/postgres/${testName}.json`, JSON.stringify(validatedCurAfterImport)); - const { cur } = await preparePgMigrationSnapshot( - [`tests/introspect/${testName}.json`], - `tests/introspect/${testName}.ts`, + const prevSnapshot = pgSchema.parse( + JSON.parse(fs.readFileSync(`tests/introspect/postgres/${testName}.json`).toString()), + ); + const { tables, enums, sequences, schemas: schemaImports } = await prepareFromPgImports( + [`tests/introspect/postgres/${testName}.ts`], ); + const serialized = generatePgSnapshot(tables, enums, schemaImports, sequences, schemas); + const cur = { id: randomUUID(), ...serialized, prevId: prevSnapshot.id }; const squashedCurr = squashPgScheme(cur); const { @@ -1371,8 +1376,8 @@ export const introspectPgToFile = async ( cur, ); - fs.rmSync(`tests/introspect/${testName}.ts`); - fs.rmSync(`tests/introspect/${testName}.json`); + fs.rmSync(`tests/introspect/postgres/${testName}.ts`); + fs.rmSync(`tests/introspect/postgres/${testName}.json`); return { sqlStatements: afterFileSqlStatements, @@ -1429,11 +1434,15 @@ export const introspectMySQLToFile = async ( // save snapshot fs.writeFileSync(`tests/introspect/mysql/${testName}.json`, JSON.stringify(validatedCurAfterImport)); - const { cur } = await prepareMySqlMigrationSnapshot( - [`tests/introspect/mysql/${testName}.json`], - `tests/introspect/mysql/${testName}.ts`, + const prevSnapshot = mysqlSchema.parse( + JSON.parse(fs.readFileSync(`tests/introspect/mysql/${testName}.json`).toString()), + ); + const { tables } = await prepareFromMySqlImports( + [`tests/introspect/mysql/${testName}.ts`], ); + const serialized = generateMySqlSnapshot(tables); + const cur = { id: randomUUID(), ...serialized, prevId: prevSnapshot.id }; const squashedCurr = squashMysqlScheme(cur); const { @@ -1507,11 +1516,15 @@ export const introspectSQLiteToFile = async ( // save snapshot fs.writeFileSync(`tests/introspect/sqlite/${testName}.json`, JSON.stringify(validatedCurAfterImport)); - const { cur } = await prepareSqliteMigrationSnapshot( - [`tests/introspect/sqlite/${testName}.json`], - `tests/introspect/sqlite/${testName}.ts`, + const prevSnapshot = sqliteSchema.parse( + JSON.parse(fs.readFileSync(`tests/introspect/sqlite/${testName}.json`).toString()), + ); + const { tables } = await prepareFromSqliteImports( + [`tests/introspect/sqlite/${testName}.ts`], ); + const serialized = generateSqliteSnapshot(tables); + const cur = { id: randomUUID(), ...serialized, prevId: prevSnapshot.id }; const squashedCurr = squashSqliteScheme(cur); const { From dd5d7a4c93614545d45ebcf7a2c447e628492ba6 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 12 Sep 2024 14:54:03 +0300 Subject: [PATCH 169/492] Update introspect pg --- drizzle-kit/src/introspect-pg.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index d83d1f9f8..8eed3d35f 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -867,7 +867,7 @@ const column = ( }); let out = params - ? `${withCasing(name, casing)}: timestamp(${dbColumnName({ name, casing, withMode: true })}, ${params})` + ? `${withCasing(name, casing)}: timestamp(${dbColumnName({ name, casing, withMode: true })}${params})` : `${withCasing(name, casing)}: timestamp(${dbColumnName({ name, casing })})`; return out; @@ -888,7 +888,7 @@ const column = ( const params = timeConfig({ precision, withTimezone }); let out = params - ? `${withCasing(name, casing)}: time(${dbColumnName({ name, casing, withMode: true })}, ${params})` + ? `${withCasing(name, casing)}: time(${dbColumnName({ name, casing, withMode: true })}${params})` : `${withCasing(name, casing)}: time(${dbColumnName({ name, casing })})`; return out; @@ -903,7 +903,7 @@ const column = ( const params = intervalConfig(lowered); let out = params - ? `${withCasing(name, casing)}: interval(${dbColumnName({ name, casing, withMode: true })}, ${params})` + ? `${withCasing(name, casing)}: interval(${dbColumnName({ name, casing, withMode: true })}${params})` : `${withCasing(name, casing)}: interval(${dbColumnName({ name, casing })})`; return out; @@ -958,7 +958,7 @@ const column = ( name, casing, ) - }: varchar(${dbColumnName({ name, casing, withMode: true })}, { length: ${ + }: varchar(${dbColumnName({ name, casing, withMode: true })}{ length: ${ lowered.substring( 8, lowered.length - 1, @@ -989,11 +989,11 @@ const column = ( if (lowered.length !== 8) { const geometryOptions = lowered.slice(9, -1).split(','); if (geometryOptions.length === 1 && geometryOptions[0] !== '') { - out = `${withCasing(name, casing)}: geometry(${dbColumnName({ name, casing, withMode: true })}, { type: "${ + out = `${withCasing(name, casing)}: geometry(${dbColumnName({ name, casing, withMode: true })}{ type: "${ geometryOptions[0] }" })`; } else if (geometryOptions.length === 2) { - out = `${withCasing(name, casing)}: geometry(${dbColumnName({ name, casing, withMode: true })}, { type: "${ + out = `${withCasing(name, casing)}: geometry(${dbColumnName({ name, casing, withMode: true })}{ type: "${ geometryOptions[0] }", srid: ${geometryOptions[1]} })`; } else { @@ -1020,7 +1020,7 @@ const column = ( name, casing, ) - }: vector(${dbColumnName({ name, casing, withMode: true })}, { dimensions: ${ + }: vector(${dbColumnName({ name, casing, withMode: true })}{ dimensions: ${ lowered.substring( 7, lowered.length - 1, @@ -1041,7 +1041,7 @@ const column = ( name, casing, ) - }: char(${dbColumnName({ name, casing, withMode: true })}, { length: ${ + }: char(${dbColumnName({ name, casing, withMode: true })}{ length: ${ lowered.substring( 5, lowered.length - 1, From ab9cab87aeceea9b7e37364dc1004fe576c1310b Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 12 Sep 2024 14:54:27 +0300 Subject: [PATCH 170/492] Update roadmap --- changelogs/drizzle-orm/0.34.0.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/changelogs/drizzle-orm/0.34.0.md b/changelogs/drizzle-orm/0.34.0.md index 490422628..4d2cc5cd2 100644 --- a/changelogs/drizzle-orm/0.34.0.md +++ b/changelogs/drizzle-orm/0.34.0.md @@ -253,3 +253,21 @@ const users = await db.query.users.findMany({ } }) ``` + +## Ability to execute raw strings instead of using SQL templates for raw queries + +Previously, you would have needed to do this to execute a raw query with Drizzle + +```ts +import { sql } from 'drizzle-orm' + +db.execute(sql`select * from ${users}`); +// or +db.execute(sql.raw(`select * from ${users}`)); +``` + +You can now do this as well + +```ts +db.execute('select * from users') +``` From 02be89680290b186ce1e6323af81e19b96d4fa77 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 13 Sep 2024 12:42:12 +0300 Subject: [PATCH 171/492] Add introspect for cases to mysql and sqlite --- drizzle-kit/src/introspect-mysql.ts | 107 ++++++++++++++++++--------- drizzle-kit/src/introspect-sqlite.ts | 28 +++++-- 2 files changed, 95 insertions(+), 40 deletions(-) diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index f206935a3..8c1aa3a76 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -1,6 +1,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-argument */ +import { toCamelCase } from 'drizzle-orm/casing'; import './@types/utils'; import type { Casing } from './cli/validations/common'; +import { assertUnreachable } from './global'; import { Column, ForeignKey, @@ -116,7 +118,18 @@ const prepareCasing = (casing?: Casing) => (value: string) => { return escapeColumnKey(value.camelCase()); } - return escapeColumnKey(value); + assertUnreachable(casing); +}; + +const dbColumnName = ({ name, casing, withMode = false }: { name: string; casing: Casing; withMode?: boolean }) => { + if (casing === 'preserve') { + return ''; + } + if (casing === 'camel') { + return toCamelCase(name) === name ? '' : withMode ? `"${name}", ` : `"${name}"`; + } + + assertUnreachable(casing); }; export const schemaToTypeScript = ( @@ -188,6 +201,7 @@ export const schemaToTypeScript = ( Object.values(table.columns), Object.values(table.foreignKeys), withCasing, + casing, table.name, schema, ); @@ -298,6 +312,7 @@ const column = ( type: string, name: string, casing: (value: string) => string, + rawCasing: Casing, defaultValue?: any, autoincrement?: boolean, onUpdate?: boolean, @@ -309,12 +324,14 @@ const column = ( } if (lowered === 'serial') { - return `${casing(name)}: serial("${name}")`; + return `${casing(name)}: serial(${dbColumnName({ name, casing: rawCasing })})`; } if (lowered.startsWith('int')) { const isUnsigned = lowered.startsWith('int unsigned'); - let out = `${casing(name)}: int("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + let out = `${casing(name)}: int(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ + isUnsigned ? '{ unsigned: true }' : '' + })`; out += autoincrement ? `.autoincrement()` : ''; out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -325,7 +342,9 @@ const column = ( if (lowered.startsWith('tinyint')) { const isUnsigned = lowered.startsWith('tinyint unsigned'); // let out = `${name.camelCase()}: tinyint("${name}")`; - let out: string = `${casing(name)}: tinyint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + let out: string = `${casing(name)}: tinyint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ + isUnsigned ? ', { unsigned: true }' : '' + })`; out += autoincrement ? `.autoincrement()` : ''; out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -335,7 +354,9 @@ const column = ( if (lowered.startsWith('smallint')) { const isUnsigned = lowered.startsWith('smallint unsigned'); - let out = `${casing(name)}: smallint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + let out = `${casing(name)}: smallint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ + isUnsigned ? ', { unsigned: true }' : '' + })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -345,7 +366,9 @@ const column = ( if (lowered.startsWith('mediumint')) { const isUnsigned = lowered.startsWith('mediumint unsigned'); - let out = `${casing(name)}: mediumint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + let out = `${casing(name)}: mediumint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ + isUnsigned ? ', { unsigned: true }' : '' + })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -355,7 +378,9 @@ const column = ( if (lowered.startsWith('bigint')) { const isUnsigned = lowered.startsWith('bigint unsigned'); - let out = `${casing(name)}: bigint("${name}", { mode: "number"${isUnsigned ? ', unsigned: true' : ''} })`; + let out = `${casing(name)}: bigint(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: "number"${ + isUnsigned ? ', unsigned: true' : '' + } })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -364,7 +389,7 @@ const column = ( } if (lowered === 'boolean') { - let out = `${casing(name)}: boolean("${name}")`; + let out = `${casing(name)}: boolean(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -383,9 +408,13 @@ const column = ( params = { precision, scale }; } + const timeConfigParams = params ? timeConfig(params) : undefined; + let out = params - ? `${casing(name)}: double("${name}", ${timeConfig(params)})` - : `${casing(name)}: double("${name}")`; + ? `${casing(name)}: double(${ + dbColumnName({ name, casing: rawCasing, withMode: timeConfigParams !== undefined }) + }${timeConfig(params)})` + : `${casing(name)}: double(${dbColumnName({ name, casing: rawCasing })})`; // let out = `${name.camelCase()}: double("${name}")`; out += defaultValue @@ -395,7 +424,7 @@ const column = ( } if (lowered === 'float') { - let out = `${casing(name)}: float("${name}")`; + let out = `${casing(name)}: float(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -403,7 +432,7 @@ const column = ( } if (lowered === 'real') { - let out = `${casing(name)}: real("${name}")`; + let out = `${casing(name)}: real(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -420,8 +449,10 @@ const column = ( const params = timeConfig({ fsp, mode: "'string'" }); let out = params - ? `${casing(name)}: timestamp("${name}", ${params})` - : `${casing(name)}: timestamp("${name}")`; + ? `${casing(name)}: timestamp(${ + dbColumnName({ name, casing: rawCasing, withMode: params !== undefined }) + }${params})` + : `${casing(name)}: timestamp(${dbColumnName({ name, casing: rawCasing })})`; // mysql has only CURRENT_TIMESTAMP, as I found from docs. But will leave now() for just a case defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' @@ -448,8 +479,8 @@ const column = ( const params = timeConfig({ fsp }); let out = params - ? `${casing(name)}: time("${name}", ${params})` - : `${casing(name)}: time("${name}")`; + ? `${casing(name)}: time(${dbColumnName({ name, casing: rawCasing, withMode: params !== undefined })}${params})` + : `${casing(name)}: time(${dbColumnName({ name, casing: rawCasing })})`; defaultValue = defaultValue === 'now()' ? '.defaultNow()' @@ -466,7 +497,7 @@ const column = ( casing( name, ) - }: date("${name}", { mode: 'string' })`; + }: date(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: 'string' })`; defaultValue = defaultValue === 'now()' ? '.defaultNow()' @@ -480,7 +511,7 @@ const column = ( // in mysql text can't have default value. Will leave it in case smth ;) if (lowered === 'text') { - let out = `${casing(name)}: text("${name}")`; + let out = `${casing(name)}: text(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -489,7 +520,7 @@ const column = ( // in mysql text can't have default value. Will leave it in case smth ;) if (lowered === 'tinytext') { - let out = `${casing(name)}: tinytext("${name}")`; + let out = `${casing(name)}: tinytext(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -498,7 +529,7 @@ const column = ( // in mysql text can't have default value. Will leave it in case smth ;) if (lowered === 'mediumtext') { - let out = `${casing(name)}: mediumtext("${name}")`; + let out = `${casing(name)}: mediumtext(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -507,7 +538,7 @@ const column = ( // in mysql text can't have default value. Will leave it in case smth ;) if (lowered === 'longtext') { - let out = `${casing(name)}: longtext("${name}")`; + let out = `${casing(name)}: longtext(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -515,7 +546,7 @@ const column = ( } if (lowered === 'year') { - let out = `${casing(name)}: year("${name}")`; + let out = `${casing(name)}: year(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -524,7 +555,7 @@ const column = ( // in mysql json can't have default value. Will leave it in case smth ;) if (lowered === 'json') { - let out = `${casing(name)}: json("${name}")`; + let out = `${casing(name)}: json(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefaultForJson(defaultValue)})` @@ -538,7 +569,7 @@ const column = ( casing( name, ) - }: varchar("${name}", { length: ${ + }: varchar(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ length: ${ lowered.substring( 'varchar'.length + 1, lowered.length - 1, @@ -556,7 +587,7 @@ const column = ( casing( name, ) - }: char("${name}", { length: ${ + }: char(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ length: ${ lowered.substring( 'char'.length + 1, lowered.length - 1, @@ -581,13 +612,13 @@ const column = ( casing( name, ) - }: datetime("${name}", { mode: 'string', fsp: ${ + }: datetime(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: 'string', fsp: ${ lowered.substring( 'datetime'.length + 1, lowered.length - 1, ) } })` - : `${casing(name)}: datetime("${name}", { mode: 'string'})`; + : `${casing(name)}: datetime(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: 'string'})`; defaultValue = defaultValue === 'now()' ? '.defaultNow()' @@ -611,9 +642,13 @@ const column = ( params = { precision, scale }; } + const timeConfigParams = params ? timeConfig(params) : undefined; + let out = params - ? `${casing(name)}: decimal("${name}", ${timeConfig(params)})` - : `${casing(name)}: decimal("${name}")`; + ? `${casing(name)}: decimal(${ + dbColumnName({ name, casing: rawCasing, withMode: timeConfigParams !== undefined }) + }${timeConfigParams})` + : `${casing(name)}: decimal(${dbColumnName({ name, casing: rawCasing })})`; defaultValue = typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -633,8 +668,8 @@ const column = ( const params = binaryConfig({ length }); let out = params - ? `${casing(name)}: binary("${name}", ${params})` - : `${casing(name)}: binary("${name}")`; + ? `${casing(name)}: binary(${dbColumnName({ name, casing: rawCasing, withMode: params !== undefined })}${params})` + : `${casing(name)}: binary(${dbColumnName({ name, casing: rawCasing })})`; defaultValue = defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -646,7 +681,7 @@ const column = ( if (lowered.startsWith('enum')) { const values = lowered.substring('enum'.length + 1, lowered.length - 1); - let out = `${casing(name)}: mysqlEnum("${name}", [${values}])`; + let out = `${casing(name)}: mysqlEnum(${dbColumnName({ name, casing: rawCasing, withMode: true })}[${values}])`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -663,8 +698,10 @@ const column = ( const params = binaryConfig({ length }); let out = params - ? `${casing(name)}: varbinary("${name}", ${params})` - : `${casing(name)}: varbinary("${name}")`; + ? `${casing(name)}: varbinary(${ + dbColumnName({ name, casing: rawCasing, withMode: params !== undefined }) + }${params})` + : `${casing(name)}: varbinary(${dbColumnName({ name, casing: rawCasing })})`; defaultValue = defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -682,6 +719,7 @@ const createTableColumns = ( columns: Column[], fks: ForeignKey[], casing: (val: string) => string, + rawCasing: Casing, tableName: string, schema: MySqlSchemaInternal, ): string => { @@ -707,6 +745,7 @@ const createTableColumns = ( it.type, it.name, casing, + rawCasing, it.default, it.autoincrement, it.onUpdate, diff --git a/drizzle-kit/src/introspect-sqlite.ts b/drizzle-kit/src/introspect-sqlite.ts index b4a729f4c..422e58f86 100644 --- a/drizzle-kit/src/introspect-sqlite.ts +++ b/drizzle-kit/src/introspect-sqlite.ts @@ -1,6 +1,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-argument */ +import { toCamelCase } from 'drizzle-orm/casing'; import './@types/utils'; import type { Casing } from './cli/validations/common'; +import { assertUnreachable } from './global'; import type { Column, ForeignKey, @@ -56,6 +58,17 @@ const withCasing = (value: string, casing?: Casing) => { return value; }; +const dbColumnName = ({ name, casing, withMode = false }: { name: string; casing: Casing; withMode?: boolean }) => { + if (casing === 'preserve') { + return ''; + } + if (casing === 'camel') { + return toCamelCase(name) === name ? '' : withMode ? `"${name}", ` : `"${name}"`; + } + + assertUnreachable(casing); +}; + export const schemaToTypeScript = ( schema: SQLiteSchemaInternal, casing: Casing, @@ -226,9 +239,10 @@ const column = ( casing?: Casing, ) => { let lowered = type; + casing = casing!; if (lowered === 'integer') { - let out = `${withCasing(name, casing)}: integer("${name}")`; + let out = `${withCasing(name, casing)}: integer(${dbColumnName({ name, casing })})`; // out += autoincrement ? `.autoincrement()` : ""; out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue)})` @@ -237,7 +251,7 @@ const column = ( } if (lowered === 'real') { - let out = `${withCasing(name, casing)}: real("${name}")`; + let out = `${withCasing(name, casing)}: real(${dbColumnName({ name, casing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue)})` : ''; return out; } @@ -247,9 +261,11 @@ const column = ( let out: string; if (match) { - out = `${withCasing(name, casing)}: text("${name}", { length: ${match[0]} })`; + out = `${withCasing(name, casing)}: text(${dbColumnName({ name, casing, withMode: true })}{ length: ${ + match[0] + } })`; } else { - out = `${withCasing(name, casing)}: text("${name}")`; + out = `${withCasing(name, casing)}: text(${dbColumnName({ name, casing })})`; } out += defaultValue ? `.default("${mapColumnDefault(defaultValue)}")` : ''; @@ -257,13 +273,13 @@ const column = ( } if (lowered === 'blob') { - let out = `${withCasing(name, casing)}: blob("${name}")`; + let out = `${withCasing(name, casing)}: blob(${dbColumnName({ name, casing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue)})` : ''; return out; } if (lowered === 'numeric') { - let out = `${withCasing(name, casing)}: numeric("${name}")`; + let out = `${withCasing(name, casing)}: numeric(${dbColumnName({ name, casing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue)})` : ''; return out; } From f026b0e905dc747ebc32ec549522fe2c6ee11365 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Sun, 15 Sep 2024 13:24:17 +0300 Subject: [PATCH 172/492] Add pglite to monodriver --- drizzle-orm/src/monodriver.ts | 43 +++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index c748707af..e32443198 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -1,5 +1,6 @@ /* eslint-disable import/extensions */ import type { RDSDataClient, RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; +import type { PGlite, PGliteOptions } from '@electric-sql/pglite'; import type { Client as LibsqlClient, Config as LibsqlConfig } from '@libsql/client'; import type { HTTPTransactionOptions as NeonHttpConfig, @@ -30,6 +31,7 @@ import type { MySql2Database, MySql2DrizzleConfig } from './mysql2/index.ts'; import type { NeonHttpDatabase } from './neon-http/index.ts'; import type { NeonDatabase } from './neon-serverless/index.ts'; import type { NodePgDatabase } from './node-postgres/driver.ts'; +import type { PgliteDatabase } from './pglite/driver.ts'; import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; import type { PostgresJsDatabase } from './postgres-js/index.ts'; import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; @@ -95,7 +97,8 @@ type DatabaseClient = | 'turso' | 'd1' | 'bun:sqlite' - | 'better-sqlite3'; + | 'better-sqlite3' + | 'pglite'; type ClientDrizzleInstanceMap> = { 'node-postgres': NodePgDatabase; @@ -112,6 +115,7 @@ type ClientDrizzleInstanceMap> = { d1: DrizzleD1Database; 'bun:sqlite': BunSQLiteDatabase; 'better-sqlite3': DrizzleBetterSQLite3Database; + pglite: PgliteDatabase; }; type Primitive = string | number | boolean | undefined | null; @@ -133,6 +137,7 @@ type ClientInstanceMap = { d1: AnyD1Database; 'bun:sqlite': BunDatabase; 'better-sqlite3': BetterSQLite3Database; + pglite: PGlite; }; type ClientTypeImportErrorMap = { @@ -150,6 +155,7 @@ type ClientTypeImportErrorMap = { d1: '@cloudflare/workers-types` or `@miniflare/d1'; 'bun:sqlite': 'bun-types'; 'better-sqlite3': 'better-sqlite3'; + pglite: '@electric-sql/pglite'; }; type ImportTypeError = @@ -196,6 +202,9 @@ type InitializerParams = { 'better-sqlite3': { connection?: BetterSQLite3DatabaseConfig; }; + pglite: { + connection?: (PGliteOptions & { dataDir?: string }) | string; + }; }; type DetermineClient< @@ -224,7 +233,7 @@ export async function drizzle< TSchema extends Record = Record, >( client: TClient, - ...params: TClient extends 'bun:sqlite' | 'better-sqlite3' ? ( + ...params: TClient extends 'bun:sqlite' | 'better-sqlite3' | 'pglite' ? ( [] | [ ( & IfNotImported< @@ -614,6 +623,36 @@ export async function drizzle< return db as any; } + + case 'pglite': { + const { PGlite } = await import('@electric-sql/pglite').catch(() => importError('@electric-sql/pglite')); + const { drizzle } = await import('./pglite'); + + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as { + connection: PGliteOptions & { dataDir: string }; + } & DrizzleConfig; + + if (typeof connection === 'object') { + const { dataDir, ...options } = connection; + + const instance = new PGlite(dataDir, options); + const db = drizzle(instance, drizzleConfig); + + return db as any; + } + + const instance = new PGlite(connection); + const db = drizzle(instance, drizzleConfig); + + return db as any; + } + + const instance = new PGlite(params[0]); + const db = drizzle(instance); + + return db as any; + } } assertUnreachable(client); From 8dece561f9b4068cb7e1db4a2b761262bfcd68b1 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 16 Sep 2024 12:13:30 +0300 Subject: [PATCH 173/492] Add pglite to monomigrator --- drizzle-orm/src/monomigrator.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index 77d1c8da4..1736e415e 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -10,6 +10,7 @@ import type { MySql2Database } from './mysql2/index.ts'; import type { NeonHttpDatabase } from './neon-http/index.ts'; import type { NeonDatabase } from './neon-serverless/index.ts'; import type { NodePgDatabase } from './node-postgres/index.ts'; +import type { PgliteDatabase } from './pglite/driver.ts'; import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; import type { PostgresJsDatabase } from './postgres-js/index.ts'; import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; @@ -29,7 +30,8 @@ export async function migrate( | PlanetScaleDatabase | PostgresJsDatabase | VercelPgDatabase - | TiDBServerlessDatabase, + | TiDBServerlessDatabase + | PgliteDatabase, config: MigrationConfig, ) { switch (( db).constructor[entityKind]) { @@ -98,5 +100,10 @@ export async function migrate( return migrate(db as VercelPgDatabase, config as MigrationConfig); } + case 'PgliteDatabase': { + const { migrate } = await import('./pglite/migrator'); + + return migrate(db as PgliteDatabase, config as MigrationConfig); + } } } From ff1e9a5f8cfca3d53b9c1251a0139b3f45653d10 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 16 Sep 2024 12:56:27 +0300 Subject: [PATCH 174/492] Fix language --- drizzle-orm/src/monodriver.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index e32443198..7acdb5806 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -159,7 +159,7 @@ type ClientTypeImportErrorMap = { }; type ImportTypeError = - `Please install \`${ClientTypeImportErrorMap[TClient]}\` for Drizzle ORM to connect to database`; + `Please install \`${ClientTypeImportErrorMap[TClient]}\`to allow Drizzle ORM to connect to the database`; type InitializerParams = { 'node-postgres': { @@ -220,7 +220,7 @@ type DetermineClient< const importError = (libName: string) => { throw new Error( - `Please install '${libName}' for Drizzle ORM to connect to database`, + `Please install '${libName}' to allow Drizzle ORM to connect to the database`, ); }; From e348b8cdead27ead9c5728b62bca36a6c6bc2701 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 17 Sep 2024 10:14:13 -0700 Subject: [PATCH 175/492] Implement limit and order by in MySQL --- drizzle-orm/src/mysql-core/dialect.ts | 42 ++++++++++++------- .../src/mysql-core/query-builders/delete.ts | 39 ++++++++++++++++- .../src/mysql-core/query-builders/update.ts | 40 +++++++++++++++++- drizzle-orm/type-tests/mysql/delete.ts | 4 ++ drizzle-orm/type-tests/mysql/update.ts | 4 ++ integration-tests/tests/mysql/mysql-common.ts | 19 +++++++++ 6 files changed, 129 insertions(+), 19 deletions(-) diff --git a/drizzle-orm/src/mysql-core/dialect.ts b/drizzle-orm/src/mysql-core/dialect.ts index 4a72d9c5f..0e3fe3d23 100644 --- a/drizzle-orm/src/mysql-core/dialect.ts +++ b/drizzle-orm/src/mysql-core/dialect.ts @@ -17,7 +17,7 @@ import { type TablesRelationalConfig, } from '~/relations.ts'; import { Param, SQL, sql, View } from '~/sql/sql.ts'; -import type { Name, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; +import type { Name, Placeholder, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { getTableName, getTableUniqueName, Table } from '~/table.ts'; import { orderSelectedFields, type UpdateSet } from '~/utils.ts'; @@ -100,7 +100,7 @@ export class MySqlDialect { return sql.join(withSqlChunks); } - buildDeleteQuery({ table, where, returning, withList }: MySqlDeleteConfig): SQL { + buildDeleteQuery({ table, where, returning, withList, limit, orderBy }: MySqlDeleteConfig): SQL { const withSql = this.buildWithCTE(withList); const returningSql = returning @@ -109,7 +109,11 @@ export class MySqlDialect { const whereSql = where ? sql` where ${where}` : undefined; - return sql`${withSql}delete from ${table}${whereSql}${returningSql}`; + const orderBySql = this.buildOrderBy(orderBy); + + const limitSql = this.buildLimit(limit); + + return sql`${withSql}delete from ${table}${whereSql}${orderBySql}${limitSql}${returningSql}`; } buildUpdateSet(table: MySqlTable, set: UpdateSet): SQL { @@ -133,7 +137,7 @@ export class MySqlDialect { })); } - buildUpdateQuery({ table, set, where, returning, withList }: MySqlUpdateConfig): SQL { + buildUpdateQuery({ table, set, where, returning, withList, limit, orderBy }: MySqlUpdateConfig): SQL { const withSql = this.buildWithCTE(withList); const setSql = this.buildUpdateSet(table, set); @@ -144,7 +148,11 @@ export class MySqlDialect { const whereSql = where ? sql` where ${where}` : undefined; - return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}`; + const orderBySql = this.buildOrderBy(orderBy); + + const limitSql = this.buildLimit(limit); + + return sql`${withSql}update ${table} set ${setSql}${whereSql}${orderBySql}${limitSql}${returningSql}`; } /** @@ -209,6 +217,16 @@ export class MySqlDialect { return sql.join(chunks); } + private buildLimit(limit: number | Placeholder | undefined): SQL | undefined { + return typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined + } + + private buildOrderBy(orderBy: (MySqlColumn | SQL | SQL.Aliased)[] | undefined): SQL | undefined { + return orderBy ? sql` order by ${sql.join(orderBy, sql`, `)}` : undefined + } + buildSelectQuery( { withList, @@ -316,19 +334,11 @@ export class MySqlDialect { const havingSql = having ? sql` having ${having}` : undefined; - let orderBySql; - if (orderBy && orderBy.length > 0) { - orderBySql = sql` order by ${sql.join(orderBy, sql`, `)}`; - } + const orderBySql = this.buildOrderBy(orderBy); - let groupBySql; - if (groupBy && groupBy.length > 0) { - groupBySql = sql` group by ${sql.join(groupBy, sql`, `)}`; - } + const groupBySql = groupBy && groupBy.length > 0 ? sql` group by ${sql.join(groupBy, sql`, `)}` : undefined; - const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) - ? sql` limit ${limit}` - : undefined; + const limitSql = this.buildLimit(limit); const offsetSql = offset ? sql` offset ${offset}` : undefined; diff --git a/drizzle-orm/src/mysql-core/query-builders/delete.ts b/drizzle-orm/src/mysql-core/query-builders/delete.ts index e9a48da8e..7b5d22624 100644 --- a/drizzle-orm/src/mysql-core/query-builders/delete.ts +++ b/drizzle-orm/src/mysql-core/query-builders/delete.ts @@ -11,9 +11,13 @@ import type { } from '~/mysql-core/session.ts'; import type { MySqlTable } from '~/mysql-core/table.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import { Table } from '~/table.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; +import type { MySqlColumn } from '../columns/common.ts'; +import type { ValueOrArray } from '~/utils.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; export type MySqlDeleteWithout< T extends AnyMySqlDeleteBase, @@ -39,6 +43,8 @@ export type MySqlDelete< export interface MySqlDeleteConfig { where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (MySqlColumn | SQL | SQL.Aliased)[]; table: MySqlTable; returning?: SelectedFieldsOrdered; withList?: Subquery[]; @@ -134,6 +140,37 @@ export class MySqlDeleteBase< return this as any; } + orderBy( + builder: (updateTable: TTable) => ValueOrArray, + ): MySqlDeleteWithout; + orderBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): MySqlDeleteWithout; + orderBy( + ...columns: + | [(updateTable: TTable) => ValueOrArray] + | (MySqlColumn | SQL | SQL.Aliased)[] + ): MySqlDeleteWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (MySqlColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): MySqlDeleteWithout { + this.config.limit = limit; + return this as any; + } + /** @internal */ getSQL(): SQL { return this.dialect.buildDeleteQuery(this.config); diff --git a/drizzle-orm/src/mysql-core/query-builders/update.ts b/drizzle-orm/src/mysql-core/query-builders/update.ts index 7884599cf..8a86c748b 100644 --- a/drizzle-orm/src/mysql-core/query-builders/update.ts +++ b/drizzle-orm/src/mysql-core/query-builders/update.ts @@ -12,13 +12,18 @@ import type { } from '~/mysql-core/session.ts'; import type { MySqlTable } from '~/mysql-core/table.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; -import { mapUpdateSet, type UpdateSet } from '~/utils.ts'; +import { mapUpdateSet, type ValueOrArray, type UpdateSet } from '~/utils.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; +import type { MySqlColumn } from '../columns/common.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import { Table } from '~/table.ts'; export interface MySqlUpdateConfig { where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (MySqlColumn | SQL | SQL.Aliased)[]; set: UpdateSet; table: MySqlTable; returning?: SelectedFieldsOrdered; @@ -173,6 +178,37 @@ export class MySqlUpdateBase< return this as any; } + orderBy( + builder: (updateTable: TTable) => ValueOrArray, + ): MySqlUpdateWithout; + orderBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): MySqlUpdateWithout; + orderBy( + ...columns: + | [(updateTable: TTable) => ValueOrArray] + | (MySqlColumn | SQL | SQL.Aliased)[] + ): MySqlUpdateWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (MySqlColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): MySqlUpdateWithout { + this.config.limit = limit; + return this as any; + } + /** @internal */ getSQL(): SQL { return this.dialect.buildUpdateQuery(this.config); diff --git a/drizzle-orm/type-tests/mysql/delete.ts b/drizzle-orm/type-tests/mysql/delete.ts index c3e5afbb2..84c827ba8 100644 --- a/drizzle-orm/type-tests/mysql/delete.ts +++ b/drizzle-orm/type-tests/mysql/delete.ts @@ -59,3 +59,7 @@ Expect>; .where(sql``) .where(sql``); } + +{ + db.delete(users).where(sql``).limit(1).orderBy(sql``); +} diff --git a/drizzle-orm/type-tests/mysql/update.ts b/drizzle-orm/type-tests/mysql/update.ts index dc6967f44..abb127b5d 100644 --- a/drizzle-orm/type-tests/mysql/update.ts +++ b/drizzle-orm/type-tests/mysql/update.ts @@ -24,3 +24,7 @@ import { users } from './tables.ts'; // @ts-expect-error method was already called .where(sql``); } + +{ + db.update(users).set({}).where(sql``).limit(1).orderBy(sql``); +} diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 8a2fb768b..cdee0a1d3 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3809,5 +3809,24 @@ export function tests(driver?: string) { expect(users.length).toBeGreaterThan(0); }); + + test('update with limit and order by', async (ctx) => { + const { db } = ctx.mysql; + + await db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); + + const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy(asc(usersTable.name)); + expect(result).toStrictEqual([ + { name: 'Alan', verified: true }, + { name: 'Barry', verified: true }, + { name: 'Carl', verified: false }, + ]); + }); }); } From 004c8eb566f3ec4d6ba9b92c39a6d328de694ac4 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 17 Sep 2024 10:34:13 -0700 Subject: [PATCH 176/492] Add limit and order by to update and delete in SQLite --- drizzle-orm/src/mysql-core/dialect.ts | 2 +- .../src/mysql-core/query-builders/delete.ts | 4 +- drizzle-orm/src/sqlite-core/dialect.ts | 57 ++++++++++++------- .../src/sqlite-core/query-builders/delete.ts | 39 ++++++++++++- .../src/sqlite-core/query-builders/update.ts | 39 ++++++++++++- drizzle-orm/type-tests/sqlite/delete.ts | 4 ++ drizzle-orm/type-tests/sqlite/update.ts | 4 ++ .../tests/sqlite/sqlite-common.ts | 19 +++++++ 8 files changed, 141 insertions(+), 27 deletions(-) diff --git a/drizzle-orm/src/mysql-core/dialect.ts b/drizzle-orm/src/mysql-core/dialect.ts index 0e3fe3d23..91b0a93fd 100644 --- a/drizzle-orm/src/mysql-core/dialect.ts +++ b/drizzle-orm/src/mysql-core/dialect.ts @@ -224,7 +224,7 @@ export class MySqlDialect { } private buildOrderBy(orderBy: (MySqlColumn | SQL | SQL.Aliased)[] | undefined): SQL | undefined { - return orderBy ? sql` order by ${sql.join(orderBy, sql`, `)}` : undefined + return orderBy && orderBy.length > 0 ? sql` order by ${sql.join(orderBy, sql`, `)}` : undefined } buildSelectQuery( diff --git a/drizzle-orm/src/mysql-core/query-builders/delete.ts b/drizzle-orm/src/mysql-core/query-builders/delete.ts index 7b5d22624..fe9c5ac8d 100644 --- a/drizzle-orm/src/mysql-core/query-builders/delete.ts +++ b/drizzle-orm/src/mysql-core/query-builders/delete.ts @@ -141,12 +141,12 @@ export class MySqlDeleteBase< } orderBy( - builder: (updateTable: TTable) => ValueOrArray, + builder: (deleteTable: TTable) => ValueOrArray, ): MySqlDeleteWithout; orderBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): MySqlDeleteWithout; orderBy( ...columns: - | [(updateTable: TTable) => ValueOrArray] + | [(deleteTable: TTable) => ValueOrArray] | (MySqlColumn | SQL | SQL.Aliased)[] ): MySqlDeleteWithout { if (typeof columns[0] === 'function') { diff --git a/drizzle-orm/src/sqlite-core/dialect.ts b/drizzle-orm/src/sqlite-core/dialect.ts index 645e15592..b7638b5e9 100644 --- a/drizzle-orm/src/sqlite-core/dialect.ts +++ b/drizzle-orm/src/sqlite-core/dialect.ts @@ -16,7 +16,7 @@ import { type TableRelationalConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { Name } from '~/sql/index.ts'; +import type { Name, Placeholder } from '~/sql/index.ts'; import { and, eq } from '~/sql/index.ts'; import { Param, type QueryWithTypings, SQL, sql, type SQLChunk } from '~/sql/sql.ts'; import { SQLiteColumn } from '~/sqlite-core/columns/index.ts'; @@ -63,7 +63,7 @@ export abstract class SQLiteDialect { return sql.join(withSqlChunks); } - buildDeleteQuery({ table, where, returning, withList }: SQLiteDeleteConfig): SQL { + buildDeleteQuery({ table, where, returning, withList, limit, orderBy }: SQLiteDeleteConfig): SQL { const withSql = this.buildWithCTE(withList); const returningSql = returning @@ -72,7 +72,11 @@ export abstract class SQLiteDialect { const whereSql = where ? sql` where ${where}` : undefined; - return sql`${withSql}delete from ${table}${whereSql}${returningSql}`; + const orderBySql = this.buildOrderBy(orderBy); + + const limitSql = this.buildLimit(limit); + + return sql`${withSql}delete from ${table}${whereSql}${returningSql}${orderBySql}${limitSql}`; } buildUpdateSet(table: SQLiteTable, set: UpdateSet): SQL { @@ -96,7 +100,7 @@ export abstract class SQLiteDialect { })); } - buildUpdateQuery({ table, set, where, returning, withList }: SQLiteUpdateConfig): SQL { + buildUpdateQuery({ table, set, where, returning, withList, limit, orderBy }: SQLiteUpdateConfig): SQL { const withSql = this.buildWithCTE(withList); const setSql = this.buildUpdateSet(table, set); @@ -107,7 +111,11 @@ export abstract class SQLiteDialect { const whereSql = where ? sql` where ${where}` : undefined; - return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}`; + const orderBySql = this.buildOrderBy(orderBy); + + const limitSql = this.buildLimit(limit); + + return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}${orderBySql}${limitSql}`; } /** @@ -174,6 +182,28 @@ export abstract class SQLiteDialect { return sql.join(chunks); } + private buildLimit(limit: number | Placeholder | undefined): SQL | undefined { + return typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined + } + + private buildOrderBy(orderBy: (SQLiteColumn | SQL | SQL.Aliased)[] | undefined): SQL | undefined { + const orderByList: (SQLiteColumn | SQL | SQL.Aliased)[] = []; + + if (orderBy) { + for (const [index, orderByValue] of orderBy.entries()) { + orderByList.push(orderByValue); + + if (index < orderBy.length - 1) { + orderByList.push(sql`, `); + } + } + } + + return orderByList.length > 0 ? sql` order by ${sql.join(orderByList)}` : undefined + } + buildSelectQuery( { withList, @@ -269,17 +299,6 @@ export abstract class SQLiteDialect { const havingSql = having ? sql` having ${having}` : undefined; - const orderByList: (SQLiteColumn | SQL | SQL.Aliased)[] = []; - if (orderBy) { - for (const [index, orderByValue] of orderBy.entries()) { - orderByList.push(orderByValue); - - if (index < orderBy.length - 1) { - orderByList.push(sql`, `); - } - } - } - const groupByList: (SQL | AnyColumn | SQL.Aliased)[] = []; if (groupBy) { for (const [index, groupByValue] of groupBy.entries()) { @@ -293,11 +312,9 @@ export abstract class SQLiteDialect { const groupBySql = groupByList.length > 0 ? sql` group by ${sql.join(groupByList)}` : undefined; - const orderBySql = orderByList.length > 0 ? sql` order by ${sql.join(orderByList)}` : undefined; + const orderBySql = this.buildOrderBy(orderBy); - const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) - ? sql` limit ${limit}` - : undefined; + const limitSql = this.buildLimit(limit); const offsetSql = offset ? sql` offset ${offset}` : undefined; diff --git a/drizzle-orm/src/sqlite-core/query-builders/delete.ts b/drizzle-orm/src/sqlite-core/query-builders/delete.ts index 1a028c09a..cf0b6bd7a 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/delete.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/delete.ts @@ -2,14 +2,16 @@ import { entityKind } from '~/entity.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteDialect } from '~/sqlite-core/dialect.ts'; import type { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; import type { Subquery } from '~/subquery.ts'; -import { type DrizzleTypeError, orderSelectedFields } from '~/utils.ts'; +import { type DrizzleTypeError, orderSelectedFields, type ValueOrArray } from '~/utils.ts'; import type { SQLiteColumn } from '../columns/common.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import { Table } from '~/table.ts'; export type SQLiteDeleteWithout< T extends AnySQLiteDeleteBase, @@ -37,6 +39,8 @@ export type SQLiteDelete< export interface SQLiteDeleteConfig { where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (SQLiteColumn | SQL | SQL.Aliased)[]; table: SQLiteTable; returning?: SelectedFieldsOrdered; withList?: Subquery[]; @@ -185,6 +189,37 @@ export class SQLiteDeleteBase< return this as any; } + orderBy( + builder: (deleteTable: TTable) => ValueOrArray, + ): SQLiteDeleteWithout; + orderBy(...columns: (SQLiteColumn | SQL | SQL.Aliased)[]): SQLiteDeleteWithout; + orderBy( + ...columns: + | [(deleteTable: TTable) => ValueOrArray] + | (SQLiteColumn | SQL | SQL.Aliased)[] + ): SQLiteDeleteWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (SQLiteColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): SQLiteDeleteWithout { + this.config.limit = limit; + return this as any; + } + /** * Adds a `returning` clause to the query. * diff --git a/drizzle-orm/src/sqlite-core/query-builders/update.ts b/drizzle-orm/src/sqlite-core/query-builders/update.ts index 0238b748f..9d4543f26 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/update.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/update.ts @@ -3,17 +3,21 @@ import { entityKind } from '~/entity.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteDialect } from '~/sqlite-core/dialect.ts'; import type { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; import type { Subquery } from '~/subquery.ts'; -import { type DrizzleTypeError, mapUpdateSet, orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { type DrizzleTypeError, mapUpdateSet, orderSelectedFields, type UpdateSet, type ValueOrArray } from '~/utils.ts'; import type { SQLiteColumn } from '../columns/common.ts'; import type { SelectedFields, SelectedFieldsOrdered } from './select.types.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import { Table } from '~/table.ts'; export interface SQLiteUpdateConfig { where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (SQLiteColumn | SQL | SQL.Aliased)[]; set: UpdateSet; table: SQLiteTable; returning?: SelectedFieldsOrdered; @@ -223,6 +227,37 @@ export class SQLiteUpdateBase< return this as any; } + orderBy( + builder: (updateTable: TTable) => ValueOrArray, + ): SQLiteUpdateWithout; + orderBy(...columns: (SQLiteColumn | SQL | SQL.Aliased)[]): SQLiteUpdateWithout; + orderBy( + ...columns: + | [(updateTable: TTable) => ValueOrArray] + | (SQLiteColumn | SQL | SQL.Aliased)[] + ): SQLiteUpdateWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (SQLiteColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): SQLiteUpdateWithout { + this.config.limit = limit; + return this as any; + } + /** * Adds a `returning` clause to the query. * diff --git a/drizzle-orm/type-tests/sqlite/delete.ts b/drizzle-orm/type-tests/sqlite/delete.ts index fcc754740..cc6539d98 100644 --- a/drizzle-orm/type-tests/sqlite/delete.ts +++ b/drizzle-orm/type-tests/sqlite/delete.ts @@ -152,3 +152,7 @@ Expect>; // @ts-expect-error method was already called .returning(); } + +{ + db.delete(users).where(sql``).limit(1).orderBy(sql``); +} \ No newline at end of file diff --git a/drizzle-orm/type-tests/sqlite/update.ts b/drizzle-orm/type-tests/sqlite/update.ts index aa1f8051f..ab60b5d61 100644 --- a/drizzle-orm/type-tests/sqlite/update.ts +++ b/drizzle-orm/type-tests/sqlite/update.ts @@ -133,3 +133,7 @@ Expect>; // @ts-expect-error method was already called .where(sql``); } + +{ + db.update(users).set({}).where(sql``).limit(1).orderBy(sql``); +} \ No newline at end of file diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index e8ddb86e6..2de18bd8f 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2887,6 +2887,25 @@ export function tests() { { count: 3 }, ]); }); + + test('update with limit and order by', async (ctx) => { + const { db } = ctx.sqlite; + + await db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); + + const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy(asc(usersTable.name)); + expect(result).toStrictEqual([ + { name: 'Alan', verified: true }, + { name: 'Barry', verified: true }, + { name: 'Carl', verified: false }, + ]); + }); }); test('table configs: unique third param', () => { From 82b91cff760afabdfe750020cee4e319fd67335f Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 17 Sep 2024 10:38:23 -0700 Subject: [PATCH 177/492] Format --- drizzle-orm/src/mysql-core/dialect.ts | 4 ++-- drizzle-orm/src/mysql-core/query-builders/delete.ts | 8 ++++---- drizzle-orm/src/mysql-core/query-builders/update.ts | 8 ++++---- drizzle-orm/src/sqlite-core/dialect.ts | 6 +++--- drizzle-orm/src/sqlite-core/query-builders/delete.ts | 4 ++-- drizzle-orm/src/sqlite-core/query-builders/update.ts | 12 +++++++++--- drizzle-orm/type-tests/sqlite/delete.ts | 2 +- drizzle-orm/type-tests/sqlite/update.ts | 2 +- integration-tests/tests/mysql/mysql-common.ts | 4 +++- integration-tests/tests/sqlite/sqlite-common.ts | 10 ++++++---- 10 files changed, 35 insertions(+), 25 deletions(-) diff --git a/drizzle-orm/src/mysql-core/dialect.ts b/drizzle-orm/src/mysql-core/dialect.ts index 91b0a93fd..4df694b77 100644 --- a/drizzle-orm/src/mysql-core/dialect.ts +++ b/drizzle-orm/src/mysql-core/dialect.ts @@ -220,11 +220,11 @@ export class MySqlDialect { private buildLimit(limit: number | Placeholder | undefined): SQL | undefined { return typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) ? sql` limit ${limit}` - : undefined + : undefined; } private buildOrderBy(orderBy: (MySqlColumn | SQL | SQL.Aliased)[] | undefined): SQL | undefined { - return orderBy && orderBy.length > 0 ? sql` order by ${sql.join(orderBy, sql`, `)}` : undefined + return orderBy && orderBy.length > 0 ? sql` order by ${sql.join(orderBy, sql`, `)}` : undefined; } buildSelectQuery( diff --git a/drizzle-orm/src/mysql-core/query-builders/delete.ts b/drizzle-orm/src/mysql-core/query-builders/delete.ts index fe9c5ac8d..66ea5d2f4 100644 --- a/drizzle-orm/src/mysql-core/query-builders/delete.ts +++ b/drizzle-orm/src/mysql-core/query-builders/delete.ts @@ -11,13 +11,13 @@ import type { } from '~/mysql-core/session.ts'; import type { MySqlTable } from '~/mysql-core/table.ts'; import { QueryPromise } from '~/query-promise.ts'; -import { Table } from '~/table.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; -import type { SelectedFieldsOrdered } from './select.types.ts'; -import type { MySqlColumn } from '../columns/common.ts'; +import { Table } from '~/table.ts'; import type { ValueOrArray } from '~/utils.ts'; -import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { MySqlColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; export type MySqlDeleteWithout< T extends AnyMySqlDeleteBase, diff --git a/drizzle-orm/src/mysql-core/query-builders/update.ts b/drizzle-orm/src/mysql-core/query-builders/update.ts index 8a86c748b..1cc1f43ec 100644 --- a/drizzle-orm/src/mysql-core/query-builders/update.ts +++ b/drizzle-orm/src/mysql-core/query-builders/update.ts @@ -12,13 +12,13 @@ import type { } from '~/mysql-core/session.ts'; import type { MySqlTable } from '~/mysql-core/table.ts'; import { QueryPromise } from '~/query-promise.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; -import { mapUpdateSet, type ValueOrArray, type UpdateSet } from '~/utils.ts'; -import type { SelectedFieldsOrdered } from './select.types.ts'; -import type { MySqlColumn } from '../columns/common.ts'; -import { SelectionProxyHandler } from '~/selection-proxy.ts'; import { Table } from '~/table.ts'; +import { mapUpdateSet, type UpdateSet, type ValueOrArray } from '~/utils.ts'; +import type { MySqlColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; export interface MySqlUpdateConfig { where?: SQL | undefined; diff --git a/drizzle-orm/src/sqlite-core/dialect.ts b/drizzle-orm/src/sqlite-core/dialect.ts index b7638b5e9..5e2162975 100644 --- a/drizzle-orm/src/sqlite-core/dialect.ts +++ b/drizzle-orm/src/sqlite-core/dialect.ts @@ -185,7 +185,7 @@ export abstract class SQLiteDialect { private buildLimit(limit: number | Placeholder | undefined): SQL | undefined { return typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) ? sql` limit ${limit}` - : undefined + : undefined; } private buildOrderBy(orderBy: (SQLiteColumn | SQL | SQL.Aliased)[] | undefined): SQL | undefined { @@ -200,8 +200,8 @@ export abstract class SQLiteDialect { } } } - - return orderByList.length > 0 ? sql` order by ${sql.join(orderByList)}` : undefined + + return orderByList.length > 0 ? sql` order by ${sql.join(orderByList)}` : undefined; } buildSelectQuery( diff --git a/drizzle-orm/src/sqlite-core/query-builders/delete.ts b/drizzle-orm/src/sqlite-core/query-builders/delete.ts index cf0b6bd7a..b89d22c3f 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/delete.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/delete.ts @@ -2,16 +2,16 @@ import { entityKind } from '~/entity.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteDialect } from '~/sqlite-core/dialect.ts'; import type { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; import type { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; import { type DrizzleTypeError, orderSelectedFields, type ValueOrArray } from '~/utils.ts'; import type { SQLiteColumn } from '../columns/common.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; -import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import { Table } from '~/table.ts'; export type SQLiteDeleteWithout< T extends AnySQLiteDeleteBase, diff --git a/drizzle-orm/src/sqlite-core/query-builders/update.ts b/drizzle-orm/src/sqlite-core/query-builders/update.ts index 9d4543f26..7d25c9921 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/update.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/update.ts @@ -3,16 +3,22 @@ import { entityKind } from '~/entity.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteDialect } from '~/sqlite-core/dialect.ts'; import type { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; import type { Subquery } from '~/subquery.ts'; -import { type DrizzleTypeError, mapUpdateSet, orderSelectedFields, type UpdateSet, type ValueOrArray } from '~/utils.ts'; +import { Table } from '~/table.ts'; +import { + type DrizzleTypeError, + mapUpdateSet, + orderSelectedFields, + type UpdateSet, + type ValueOrArray, +} from '~/utils.ts'; import type { SQLiteColumn } from '../columns/common.ts'; import type { SelectedFields, SelectedFieldsOrdered } from './select.types.ts'; -import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import { Table } from '~/table.ts'; export interface SQLiteUpdateConfig { where?: SQL | undefined; diff --git a/drizzle-orm/type-tests/sqlite/delete.ts b/drizzle-orm/type-tests/sqlite/delete.ts index cc6539d98..d943077c8 100644 --- a/drizzle-orm/type-tests/sqlite/delete.ts +++ b/drizzle-orm/type-tests/sqlite/delete.ts @@ -155,4 +155,4 @@ Expect>; { db.delete(users).where(sql``).limit(1).orderBy(sql``); -} \ No newline at end of file +} diff --git a/drizzle-orm/type-tests/sqlite/update.ts b/drizzle-orm/type-tests/sqlite/update.ts index ab60b5d61..cea386b98 100644 --- a/drizzle-orm/type-tests/sqlite/update.ts +++ b/drizzle-orm/type-tests/sqlite/update.ts @@ -136,4 +136,4 @@ Expect>; { db.update(users).set({}).where(sql``).limit(1).orderBy(sql``); -} \ No newline at end of file +} diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index cdee0a1d3..3a804d101 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3821,7 +3821,9 @@ export function tests(driver?: string) { await db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); - const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy(asc(usersTable.name)); + const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy( + asc(usersTable.name), + ); expect(result).toStrictEqual([ { name: 'Alan', verified: true }, { name: 'Barry', verified: true }, diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 2de18bd8f..e637fcb49 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2890,16 +2890,18 @@ export function tests() { test('update with limit and order by', async (ctx) => { const { db } = ctx.sqlite; - + await db.insert(usersTable).values([ { name: 'Barry', verified: false }, { name: 'Alan', verified: false }, { name: 'Carl', verified: false }, ]); - + await db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); - - const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy(asc(usersTable.name)); + + const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy( + asc(usersTable.name), + ); expect(result).toStrictEqual([ { name: 'Alan', verified: true }, { name: 'Barry', verified: true }, From 0d7eeaaa796e999d624d80c66a0cde8fdc3157dc Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 17 Sep 2024 10:59:26 -0700 Subject: [PATCH 178/492] Update SQLite test --- .../tests/sqlite/sqlite-common.ts | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index e637fcb49..8e0adfad4 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2890,23 +2890,14 @@ export function tests() { test('update with limit and order by', async (ctx) => { const { db } = ctx.sqlite; + // Limit and order by may not be supported by all SQLite databases, so we just verify that the query is correct - await db.insert(usersTable).values([ - { name: 'Barry', verified: false }, - { name: 'Alan', verified: false }, - { name: 'Carl', verified: false }, - ]); - - await db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); - - const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy( - asc(usersTable.name), - ); - expect(result).toStrictEqual([ - { name: 'Alan', verified: true }, - { name: 'Barry', verified: true }, - { name: 'Carl', verified: false }, - ]); + const query = db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)).toSQL(); + + expect(query).toStrictEqual({ + sql: 'update "users" set "verified" = ? order by "users"."name" asc limit ?', + params: [1, 2], + }); }); }); From 37c9c7eae9f6fb238c77d1ed76283540a6bc84a1 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 17 Sep 2024 10:59:43 -0700 Subject: [PATCH 179/492] Format --- integration-tests/tests/sqlite/sqlite-common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 8e0adfad4..d9831226b 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2893,7 +2893,7 @@ export function tests() { // Limit and order by may not be supported by all SQLite databases, so we just verify that the query is correct const query = db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)).toSQL(); - + expect(query).toStrictEqual({ sql: 'update "users" set "verified" = ? order by "users"."name" asc limit ?', params: [1, 2], From 2f4fccb38ddda8455dbe9b87707c18b8a6f70592 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 18 Sep 2024 12:20:01 +0300 Subject: [PATCH 180/492] added postgresql generate handling for views --- drizzle-kit/src/cli/commands/migrate.ts | 29 +- drizzle-kit/src/cli/views.ts | 2 +- drizzle-kit/src/jsonDiffer.js | 31 ++ drizzle-kit/src/jsonStatements.ts | 154 ++++- drizzle-kit/src/serializer/index.ts | 4 +- drizzle-kit/src/serializer/pgImports.ts | 13 +- drizzle-kit/src/serializer/pgSchema.ts | 59 ++ drizzle-kit/src/serializer/pgSerializer.ts | 177 +++++- drizzle-kit/src/snapshotsDiffer.ts | 129 ++++- drizzle-kit/src/sqlgenerator.ts | 126 +++++ drizzle-kit/tests/pg-views.test.ts | 619 +++++++++++++++++++++ drizzle-kit/tests/schemaDiffer.ts | 108 +++- 12 files changed, 1419 insertions(+), 32 deletions(-) create mode 100644 drizzle-kit/tests/pg-views.test.ts diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 2bcd72cab..86db4a91a 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -14,7 +14,7 @@ import path, { join } from 'path'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme } from '../../serializer/mysqlSchema'; -import { PgSchema, pgSchema, squashPgScheme } from '../../serializer/pgSchema'; +import { PgSchema, pgSchema, squashPgScheme, View } from '../../serializer/pgSchema'; import { SQLiteSchema, sqliteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; import { applyLibSQLSnapshotsDiff, @@ -30,6 +30,7 @@ import { ResolverOutputWithMoved, Sequence, Table, + ViewSquashed, } from '../../snapshotsDiffer'; import { assertV1OutFolder, Journal, prepareMigrationFolder } from '../../utils'; import { prepareMigrationMetadata } from '../../utils/words'; @@ -92,6 +93,28 @@ export const tablesResolver = async ( } }; +export const viewsResolver = async ( + input: ResolverInput, +): Promise> => { + try { + const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict( + input.created, + input.deleted, + 'view', + ); + + return { + created: created, + deleted: deleted, + moved: moved, + renamed: renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; + export const sequencesResolver = async ( input: ResolverInput, ): Promise> => { @@ -198,6 +221,7 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => { sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, ); @@ -241,6 +265,7 @@ export const preparePgPush = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, 'push', @@ -651,7 +676,7 @@ export const promptColumnsConflicts = async ( export const promptNamedWithSchemasConflict = async ( newItems: T[], missingItems: T[], - entity: 'table' | 'enum' | 'sequence', + entity: 'table' | 'enum' | 'sequence' | 'view', ): Promise<{ created: T[]; renamed: { from: T; to: T }[]; diff --git a/drizzle-kit/src/cli/views.ts b/drizzle-kit/src/cli/views.ts index 56e0331df..6b1ff671e 100644 --- a/drizzle-kit/src/cli/views.ts +++ b/drizzle-kit/src/cli/views.ts @@ -166,7 +166,7 @@ export class ResolveSelect extends Prompt< constructor( private readonly base: T, data: (RenamePropmtItem | T)[], - private readonly entityType: 'table' | 'enum' | 'sequence', + private readonly entityType: 'table' | 'enum' | 'sequence' | 'view', ) { super(); this.on('attach', (terminal) => terminal.toggleCursor('hide')); diff --git a/drizzle-kit/src/jsonDiffer.js b/drizzle-kit/src/jsonDiffer.js index 113d7e0a4..2a75138a3 100644 --- a/drizzle-kit/src/jsonDiffer.js +++ b/drizzle-kit/src/jsonDiffer.js @@ -158,6 +158,7 @@ export function applyJsonDiff(json1, json2) { difference.tables = difference.tables || {}; difference.enums = difference.enums || {}; difference.sequences = difference.sequences || {}; + difference.views = difference.views || {}; // remove added/deleted schemas const schemaKeys = Object.keys(difference.schemas); @@ -239,6 +240,35 @@ export function applyJsonDiff(json1, json2) { return json2.sequences[it[0]]; }); + const viewsEntries = Object.entries(difference.views); + + const alteredViews = viewsEntries.filter((it) => !(it[0].includes('__added') || it[0].includes('__deleted'))).map( + ([name, view]) => { + const deletedWithOption = view.with__deleted; + + const addedWithOption = view.with__added; + + const alteredWith = view.with; + + const alteredSchema = view.schema; + + const alteredDefinition = view.definition; + + const alteredExisting = view.isExisting; + + return { + name: name, + schema: json2.views[name].schema, + deletedWithOption, + addedWithOption, + alteredWith, + alteredSchema, + alteredDefinition, + alteredExisting, + }; + }, + ); + const alteredTablesWithColumns = Object.values(difference.tables).map( (table) => { return findAlternationsInTable(table); @@ -249,6 +279,7 @@ export function applyJsonDiff(json1, json2) { alteredTablesWithColumns, alteredEnums, alteredSequences, + alteredViews, }; } diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 47cb08908..a6d2051d1 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -1,9 +1,9 @@ import chalk from 'chalk'; -import { getNewTableName, getOldTableName } from './cli/commands/sqlitePushUtils'; +import { getNewTableName } from './cli/commands/sqlitePushUtils'; import { warning } from './cli/views'; import { CommonSquashedSchema, Dialect } from './schemaValidator'; import { MySqlKitInternals, MySqlSchema, MySqlSquasher } from './serializer/mysqlSchema'; -import { Index, PgSchema, PgSquasher } from './serializer/pgSchema'; +import { Index, PgSchema, PgSquasher, View, ViewWithOption } from './serializer/pgSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, @@ -524,6 +524,60 @@ export interface JsonRenameSchema { to: string; } +export interface JsonCreateViewStatement { + type: 'create_view'; + name: string; + schema: string; + definition: string; + with: ViewWithOption; +} + +export interface JsonDropViewStatement { + type: 'drop_view'; + name: string; + schema: string; +} + +export interface JsonRenameViewStatement { + type: 'rename_view'; + nameTo: string; + nameFrom: string; + schema: string; +} + +export interface JsonAlterViewAlterSchemaStatement { + type: 'alter_view_alter_schema'; + fromSchema: string; + toSchema: string; + name: string; +} + +export interface JsonAlterViewAlterWithOptionStatement { + type: 'alter_view_alter_with_option'; + schema: string; + name: string; + with: Exclude; +} + +export interface JsonAlterViewAddWithOptionStatement { + type: 'alter_view_add_with_option'; + schema: string; + name: string; + with: Exclude; +} + +export interface JsonAlterViewDropWithOptionStatement { + type: 'alter_view_drop_with_option'; + schema: string; + name: string; +} + +export type JsonAlterViewStatement = + | JsonAlterViewAlterSchemaStatement + | JsonAlterViewAlterWithOptionStatement + | JsonAlterViewAddWithOptionStatement + | JsonAlterViewDropWithOptionStatement; + export type JsonAlterColumnStatement = | JsonRenameColumnStatement | JsonAlterColumnTypeStatement @@ -582,7 +636,11 @@ export type JsonStatement = | JsonDropSequenceStatement | JsonCreateSequenceStatement | JsonMoveSequenceStatement - | JsonRenameSequenceStatement; + | JsonRenameSequenceStatement + | JsonCreateViewStatement + | JsonDropViewStatement + | JsonRenameViewStatement + | JsonAlterViewStatement; export const preparePgCreateTableJson = ( table: Table, @@ -2425,3 +2483,93 @@ export const prepareAlterCompositePrimaryKeyMySql = ( } as JsonAlterCompositePK; }); }; + +export const preparePgCreateViewJson = ( + name: string, + schema: string, + definition: string, + withClause?: string, +): JsonCreateViewStatement => { + const unsquashedWith = withClause ? PgSquasher.unsquashViewWith(withClause) : undefined; + return { + type: 'create_view', + name, + schema, + definition, + with: unsquashedWith, + }; +}; + +export const preparePgDropViewJson = ( + name: string, + schema: string, +): JsonDropViewStatement => { + return { + type: 'drop_view', + name, + schema, + }; +}; + +export const preparePgRenameViewJson = ( + to: string, + from: string, + schema: string, +): JsonRenameViewStatement => { + return { + type: 'rename_view', + nameTo: to, + nameFrom: from, + schema, + }; +}; + +export const preparePgAlterViewAlterSchemaJson = ( + to: string, + from: string, + name: string, +): JsonAlterViewAlterSchemaStatement => { + return { + type: 'alter_view_alter_schema', + fromSchema: from, + toSchema: to, + name, + }; +}; + +export const preparePgAlterViewAddWithOptionJson = ( + name: string, + schema: string, + withOption: string, +): JsonAlterViewAddWithOptionStatement => { + return { + type: 'alter_view_add_with_option', + name, + schema, + with: PgSquasher.unsquashViewWith(withOption), + }; +}; + +export const preparePgAlterViewAlterWithOptionJson = ( + name: string, + schema: string, + withOption: string, +): JsonAlterViewAlterWithOptionStatement => { + return { + type: 'alter_view_alter_with_option', + name, + schema, + with: PgSquasher.unsquashViewWith(withOption), + }; +}; + +export const preparePgAlterViewDropWithOptionJson = ( + name: string, + schema: string, +): JsonAlterViewDropWithOptionStatement => { + return { + type: 'alter_view_drop_with_option', + name, + schema, + }; +}; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index 214ca38c7..e90acc8dd 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -60,11 +60,11 @@ export const serializePg = async ( const { prepareFromPgImports } = await import('./pgImports'); const { generatePgSnapshot } = await import('./pgSerializer'); - const { tables, enums, schemas, sequences } = await prepareFromPgImports( + const { tables, enums, schemas, sequences, views } = await prepareFromPgImports( filenames, ); - return generatePgSnapshot(tables, enums, schemas, sequences, schemaFilter); + return generatePgSnapshot(tables, enums, schemas, sequences, views, schemaFilter); }; export const serializeSQLite = async ( diff --git a/drizzle-kit/src/serializer/pgImports.ts b/drizzle-kit/src/serializer/pgImports.ts index ffedd084c..b7b82db3e 100644 --- a/drizzle-kit/src/serializer/pgImports.ts +++ b/drizzle-kit/src/serializer/pgImports.ts @@ -1,5 +1,5 @@ import { is } from 'drizzle-orm'; -import { AnyPgTable, isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable } from 'drizzle-orm/pg-core'; +import { AnyPgTable, isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable, PgView } from 'drizzle-orm/pg-core'; import { safeRegister } from '../cli/commands/utils'; export const prepareFromExports = (exports: Record) => { @@ -7,6 +7,7 @@ export const prepareFromExports = (exports: Record) => { const enums: PgEnum[] = []; const schemas: PgSchema[] = []; const sequences: PgSequence[] = []; + const views: PgView[] = []; const i0values = Object.values(exports); i0values.forEach((t) => { @@ -22,12 +23,16 @@ export const prepareFromExports = (exports: Record) => { schemas.push(t); } + if (is(t, PgView)) { + views.push(t); + } + if (isPgSequence(t)) { sequences.push(t); } }); - return { tables, enums, schemas, sequences }; + return { tables, enums, schemas, sequences, views }; }; export const prepareFromPgImports = async (imports: string[]) => { @@ -35,6 +40,7 @@ export const prepareFromPgImports = async (imports: string[]) => { let enums: PgEnum[] = []; let schemas: PgSchema[] = []; let sequences: PgSequence[] = []; + let views: PgView[] = []; const { unregister } = await safeRegister(); for (let i = 0; i < imports.length; i++) { @@ -47,8 +53,9 @@ export const prepareFromPgImports = async (imports: string[]) => { enums.push(...prepared.enums); schemas.push(...prepared.schemas); sequences.push(...prepared.sequences); + views.push(...prepared.views); } unregister(); - return { tables: Array.from(new Set(tables)), enums, schemas, sequences }; + return { tables: Array.from(new Set(tables)), enums, schemas, sequences, views }; }; diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index 5860a6fef..1af5cbda1 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -220,6 +220,32 @@ const uniqueConstraint = object({ nullsNotDistinct: boolean(), }).strict(); +const viewWithOption = object({ + checkOption: enumType(['cascaded', 'local']), + securityBarrier: boolean(), + securityInvoker: boolean(), +}).strict().optional(); + +export const view = object({ + name: string(), + schema: string(), + columns: record(string(), column), + definition: string().optional(), + materialized: boolean().optional(), + with: viewWithOption, + isExisting: boolean(), +}).strict(); + +export const viewSquashed = object({ + name: string(), + schema: string(), + columns: record(string(), column), + definition: string().optional(), + materialized: boolean().optional(), + with: string().optional(), + isExisting: boolean(), +}); + const tableV4 = object({ name: string(), schema: string(), @@ -368,6 +394,7 @@ export const pgSchemaInternal = object({ tables: record(string(), table), enums: record(string(), enumSchema), schemas: record(string(), string()), + views: record(string(), view).default({}), sequences: record(string(), sequenceSchema).default({}), _meta: object({ schemas: record(string(), string()), @@ -417,6 +444,7 @@ export const pgSchemaSquashed = object({ tables: record(string(), tableSquashed), enums: record(string(), enumSchema), schemas: record(string(), string()), + views: record(string(), viewSquashed), sequences: record(string(), sequenceSquashed), }).strict(); @@ -445,6 +473,8 @@ export type Index = TypeOf; export type ForeignKey = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; +export type View = TypeOf; +export type ViewWithOption = TypeOf; export type PgKitInternals = TypeOf; export type PgSchemaV1 = TypeOf; @@ -627,6 +657,17 @@ export const PgSquasher = { cycle: splitted[7] === 'true', }; }, + squashViewWith: (withOption: Exclude): string => { + return `${withOption.checkOption};${withOption.securityBarrier};${withOption.securityInvoker}`; + }, + unsquashViewWith: (squashed: string): Exclude => { + const [checkOption, securityBarrier, securityInvoker] = squashed.split(';'); + return { + checkOption: checkOption as 'cascaded' | 'local', + securityBarrier: securityBarrier === 'true', + securityInvoker: securityInvoker === 'true', + }; + }, }; export const squashPgScheme = ( @@ -699,12 +740,30 @@ export const squashPgScheme = ( }), ); + const mappedViews = Object.fromEntries( + Object.entries(json.views).map((it) => { + return [ + it[0], + { + name: it[1].name, + columns: it[1].columns, + definition: it[1].definition, + isExisting: it[1].isExisting, + with: it[1].with ? PgSquasher.squashViewWith(it[1].with) : undefined, + schema: it[1].schema, + materialized: it[1].materialized, + }, + ]; + }), + ); + return { version: '7', dialect: json.dialect, tables: mappedTables, enums: json.enums, schemas: json.schemas, + views: mappedViews, sequences: mappedSequences, }; }; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index b479e59e2..f19909ef7 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -3,14 +3,15 @@ import { getTableName, is, SQL } from 'drizzle-orm'; import { AnyPgTable, ExtraConfigColumn, + getViewConfig, IndexedColumn, PgColumn, PgDialect, PgEnum, PgEnumColumn, - PgInteger, PgSchema, PgSequence, + PgView, uniqueKeyName, } from 'drizzle-orm/pg-core'; import { getTableConfig } from 'drizzle-orm/pg-core'; @@ -29,6 +30,7 @@ import type { Sequence, Table, UniqueConstraint, + View, } from '../serializer/pgSchema'; import { type DB, isPgArrayType } from '../utils'; import { sqlToStr } from '.'; @@ -117,9 +119,11 @@ export const generatePgSnapshot = ( enums: PgEnum[], schemas: PgSchema[], sequences: PgSequence[], + views: PgView[], schemaFilter?: string[], ): PgSchemaInternal => { const result: Record = {}; + const resultViews: Record = {}; const sequencesToReturn: Record = {}; // This object stores unique names for indexes and will be used to detect if you have the same names for indexes @@ -535,6 +539,175 @@ export const generatePgSnapshot = ( } } + for (const view of views) { + const { name: viewName, schema, query, selectedFields, isExisting, with: viewWithOptions } = getViewConfig(view); + + const columnsObject: Record = {}; + const uniqueConstraintObject: Record = {}; + + const existingView = resultViews[viewName]; + if (typeof existingView !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated view name across ${ + chalk.underline.blue( + schema ?? 'public', + ) + } schema. Please rename your view`, + ) + }`, + ); + process.exit(1); + } + + for (const key in selectedFields) { + if (is(selectedFields[key], PgColumn)) { + const column = selectedFields[key]; + + const notNull: boolean = column.notNull; + const primaryKey: boolean = column.primary; + const sqlTypeLowered = column.getSQLType().toLowerCase(); + + const typeSchema = is(column, PgEnumColumn) + ? column.enum.schema || 'public' + : undefined; + const generated = column.generated; + const identity = column.generatedIdentity; + + const increment = stringFromIdentityProperty(identity?.sequenceOptions?.increment) ?? '1'; + const minValue = stringFromIdentityProperty(identity?.sequenceOptions?.minValue) + ?? (parseFloat(increment) < 0 + ? minRangeForIdentityBasedOn(column.columnType) + : '1'); + const maxValue = stringFromIdentityProperty(identity?.sequenceOptions?.maxValue) + ?? (parseFloat(increment) < 0 + ? '-1' + : maxRangeForIdentityBasedOn(column.getSQLType())); + const startWith = stringFromIdentityProperty(identity?.sequenceOptions?.startWith) + ?? (parseFloat(increment) < 0 ? maxValue : minValue); + const cache = stringFromIdentityProperty(identity?.sequenceOptions?.cache) ?? '1'; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + typeSchema: typeSchema, + primaryKey, + notNull, + generated: generated + ? { + as: is(generated.as, SQL) + ? dialect.sqlToQuery(generated.as as SQL).sql + : typeof generated.as === 'function' + ? dialect.sqlToQuery(generated.as() as SQL).sql + : (generated.as as any), + type: 'stored', + } + : undefined, + identity: identity + ? { + type: identity.type, + name: identity.sequenceName ?? `${viewName}_${column.name}_seq`, + schema: schema ?? 'public', + increment, + startWith, + minValue, + maxValue, + cache, + cycle: identity?.sequenceOptions?.cycle ?? false, + } + : undefined, + }; + + if (column.isUnique) { + const existingUnique = uniqueConstraintObject[column.uniqueName!]; + if (typeof existingUnique !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + viewName, + ) + } table. + The unique constraint ${ + chalk.underline.blue( + column.uniqueName, + ) + } on the ${ + chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`) + }`, + ); + process.exit(1); + } + uniqueConstraintObject[column.uniqueName!] = { + name: column.uniqueName!, + nullsNotDistinct: column.uniqueType === 'not distinct', + columns: [columnToSet.name], + }; + } + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default); + } else { + if (typeof column.default === 'string') { + columnToSet.default = `'${column.default}'`; + } else { + if (sqlTypeLowered === 'jsonb' || sqlTypeLowered === 'json') { + columnToSet.default = `'${ + JSON.stringify( + column.default, + ) + }'::${sqlTypeLowered}`; + } else if (column.default instanceof Date) { + if (sqlTypeLowered === 'date') { + columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; + } else if (sqlTypeLowered === 'timestamp') { + columnToSet.default = `'${ + column.default + .toISOString() + .replace('T', ' ') + .slice(0, 23) + }'`; + } else { + columnToSet.default = `'${column.default.toISOString()}'`; + } + } else if (isPgArrayType(sqlTypeLowered) && Array.isArray(column.default)) { + columnToSet.default = `'${ + buildArrayString( + column.default, + sqlTypeLowered, + ) + }'`; + } else { + // Should do for all types + // columnToSet.default = `'${column.default}'::${sqlTypeLowered}`; + columnToSet.default = column.default; + } + } + } + } + columnsObject[column.name] = columnToSet; + } + } + + resultViews[viewName] = { + columns: columnsObject, + definition: isExisting ? undefined : dialect.sqlToQuery(query!).sql, + name: viewName, + schema: schema ?? 'public', + isExisting, + with: viewWithOptions, + }; + } + const enumsToReturn: Record = enums.reduce<{ [key: string]: Enum; }>((map, obj) => { @@ -569,6 +742,7 @@ export const generatePgSnapshot = ( enums: enumsToReturn, schemas: schemasObject, sequences: sequencesToReturn, + views: resultViews, _meta: { schemas: {}, tables: {}, @@ -1212,6 +1386,7 @@ export const fromDatabase = async ( enums: enumsToReturn, schemas: schemasObject, sequences: sequencesToReturn, + views: {}, _meta: { schemas: {}, tables: {}, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 64ea8e465..7bf30fc0a 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -24,14 +24,18 @@ import { JsonAlterCompositePK, JsonAlterTableSetSchema, JsonAlterUniqueConstraint, + JsonAlterViewStatement, JsonCreateCompositePK, JsonCreateReferenceStatement, JsonCreateUniqueConstraint, + JsonCreateViewStatement, JsonDeleteCompositePK, JsonDeleteUniqueConstraint, JsonDropColumnStatement, + JsonDropViewStatement, JsonReferenceStatement, JsonRenameColumnStatement, + JsonRenameViewStatement, JsonSqliteAddColumnStatement, JsonStatement, prepareAddCompositePrimaryKeyMySql, @@ -66,8 +70,15 @@ import { prepareMoveSequenceJson, prepareMySqlCreateTableJson, preparePgAlterColumns, + preparePgAlterViewAddWithOptionJson, + preparePgAlterViewAlterSchemaJson, + preparePgAlterViewAlterWithOptionJson, + preparePgAlterViewDropWithOptionJson, preparePgCreateIndexesJson, preparePgCreateTableJson, + preparePgCreateViewJson, + preparePgDropViewJson, + preparePgRenameViewJson, prepareRenameColumns, prepareRenameEnumJson, prepareRenameSchemasJson, @@ -80,7 +91,7 @@ import { import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher } from './serializer/mysqlSchema'; -import { PgSchema, PgSchemaSquashed, sequenceSquashed } from './serializer/pgSchema'; +import { PgSchema, PgSchemaSquashed, sequenceSquashed, viewSquashed } from './serializer/pgSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; import { copy, prepareMigrationMeta } from './utils'; @@ -251,10 +262,34 @@ export const alteredTableScheme = object({ ), }).strict(); +export const alteredViewSchema = object({ + name: string(), + schema: string(), + deletedWithOption: string().optional(), + addedWithOption: string().optional(), + alteredWith: object({ + __old: string(), + __new: string(), + }).strict().optional(), + alteredSchema: object({ + __old: string(), + __new: string(), + }).strict().optional(), + alteredDefinition: object({ + __old: string(), + __new: string(), + }).strict().optional(), + alteredExisting: object({ + __old: boolean(), + __new: boolean(), + }).strict().optional(), +}).strict(); + export const diffResultScheme = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: changedEnumSchema.array(), alteredSequences: sequenceSquashed.array(), + alteredViews: alteredViewSchema.array(), }).strict(); export const diffResultSchemeMysql = object({ @@ -272,6 +307,7 @@ export type AlteredColumn = TypeOf; export type Enum = TypeOf; export type Sequence = TypeOf; export type Table = TypeOf; +export type ViewSquashed = TypeOf; export type AlteredTable = TypeOf; export type DiffResult = TypeOf; export type DiffResultMysql = TypeOf; @@ -390,6 +426,9 @@ export const applyPgSnapshotsDiff = async ( columnsResolver: ( input: ColumnsResolverInput, ) => Promise>, + viewsResolver: ( + input: ResolverInput, + ) => Promise>, prevFull: PgSchema, curFull: PgSchema, action?: 'push' | undefined, @@ -720,11 +759,19 @@ export const applyPgSnapshotsDiff = async ( }, ); - const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + const viewsDiff = diffSchemasOrTables(json1.views, json2.views); - // no diffs + const { + created: createdViews, + deleted: deletedViews, + renamed: renamedViews, + } = await viewsResolver({ + created: viewsDiff.added, + deleted: viewsDiff.deleted, + }); + + const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); const typedResult: DiffResult = diffResultScheme.parse(diffResult); - // const typedResult: DiffResult = {}; const jsonStatements: JsonStatement[] = []; @@ -1091,6 +1138,74 @@ export const applyPgSnapshotsDiff = async ( return preparePgCreateTableJson(it, curFull); }); + const createViews: JsonCreateViewStatement[] = []; + const dropViews: JsonDropViewStatement[] = []; + const renameViews: JsonRenameViewStatement[] = []; + const alterViews: JsonAlterViewStatement[] = []; + + createViews.push( + ...createdViews.filter((it) => !it.isExisting).map((it) => { + return preparePgCreateViewJson(it.name, it.schema, it.definition!, it.with); + }), + ); + + dropViews.push( + ...deletedViews.filter((it) => !it.isExisting).map((it) => { + return preparePgDropViewJson(it.name, it.schema); + }), + ); + + renameViews.push( + ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { + return preparePgRenameViewJson(it.to.name, it.from.name, it.to.schema); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[it.name].isExisting); + for (const alteredView of alteredViews) { + if (alteredView.alteredExisting || alteredView.alteredDefinition) { + dropViews.push(preparePgDropViewJson(alteredView.name, alteredView.schema)); + + createViews.push( + preparePgCreateViewJson( + alteredView.name, + alteredView.schema, + json2.views[alteredView.name].definition!, + json2.views[alteredView.name].with, + ), + ); + continue; + } + + if (alteredView.deletedWithOption) { + alterViews.push( + preparePgAlterViewDropWithOptionJson(alteredView.name, alteredView.schema), + ); + } + + if (alteredView.addedWithOption) { + alterViews.push( + preparePgAlterViewAddWithOptionJson(alteredView.name, alteredView.schema, alteredView.addedWithOption), + ); + } + + if (alteredView.alteredSchema) { + alterViews.push( + preparePgAlterViewAlterSchemaJson( + alteredView.alteredSchema.__new, + alteredView.alteredSchema.__old, + alteredView.name, + ), + ); + } + + if (alteredView.alteredWith) { + alterViews.push( + preparePgAlterViewAlterWithOptionJson(alteredView.name, alteredView.schema, alteredView.alteredWith.__new), + ); + } + } + jsonStatements.push(...createSchemas); jsonStatements.push(...renameSchemas); jsonStatements.push(...createEnums); @@ -1105,6 +1220,10 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...createTables); + jsonStatements.push(...dropViews); + jsonStatements.push(...renameViews); + jsonStatements.push(...alterViews); + jsonStatements.push(...jsonDropTables); jsonStatements.push(...jsonSetTableSchemas); jsonStatements.push(...jsonRenameTables); @@ -1136,6 +1255,8 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...jsonAlteredUniqueConstraints); + jsonStatements.push(...createViews); + jsonStatements.push(...dropEnums); jsonStatements.push(...dropSequences); jsonStatements.push(...dropSchemas); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 374b30581..4fafd1ede 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -26,6 +26,10 @@ import { JsonAlterTableRemoveFromSchema, JsonAlterTableSetNewSchema, JsonAlterTableSetSchema, + JsonAlterViewAddWithOptionStatement, + JsonAlterViewAlterSchemaStatement, + JsonAlterViewAlterWithOptionStatement, + JsonAlterViewDropWithOptionStatement, JsonCreateCompositePK, JsonCreateEnumStatement, JsonCreateIndexStatement, @@ -34,6 +38,7 @@ import { JsonCreateSequenceStatement, JsonCreateTableStatement, JsonCreateUniqueConstraint, + JsonCreateViewStatement, JsonDeleteCompositePK, JsonDeleteReferenceStatement, JsonDeleteUniqueConstraint, @@ -41,6 +46,7 @@ import { JsonDropIndexStatement, JsonDropSequenceStatement, JsonDropTableStatement, + JsonDropViewStatement, JsonMoveSequenceStatement, JsonPgCreateIndexStatement, JsonRecreateTableStatement, @@ -48,6 +54,7 @@ import { JsonRenameSchema, JsonRenameSequenceStatement, JsonRenameTableStatement, + JsonRenameViewStatement, JsonSqliteAddColumnStatement, JsonSqliteCreateTableStatement, JsonStatement, @@ -396,6 +403,117 @@ export class SQLiteCreateTableConvertor extends Convertor { } } +class PgCreateViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_view' && dialect === 'postgresql'; + } + + convert(st: JsonCreateViewStatement) { + const { definition, name: viewName, schema, with: withClause } = st; + + const name = schema ? `"${schema}"."${viewName}"` : `"${viewName}"`; + + let statement = `CREATE VIEW ${name}`; + statement += withClause + ? ` WITH (check_option = ${withClause.checkOption}, security_barrier = ${withClause.securityBarrier}, security_invoker = ${withClause.securityInvoker})` + : ''; + statement += ` AS (${definition});`; + + return statement; + } +} + +class PgDropViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_view' && dialect === 'postgresql'; + } + + convert(st: JsonDropViewStatement) { + const { name: viewName, schema } = st; + + const name = schema ? `"${schema}"."${viewName}"` : `"${viewName}"`; + + const statement = `DROP VIEW ${name};`; + + return statement; + } +} + +class PgRenameViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'rename_view' && dialect === 'postgresql'; + } + + convert(st: JsonRenameViewStatement) { + const { nameFrom: from, nameTo: to, schema } = st; + + const nameFrom = schema ? `"${schema}"."${from}"` : `"${from}"`; + const nameTo = schema ? `"${schema}"."${to}"` : `"${to}"`; + + const statement = `ALTER VIEW ${nameFrom} RENAME TO ${nameTo};`; + + return statement; + } +} + +class PgAlterViewSchemaConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_view_alter_schema' && dialect === 'postgresql'; + } + + convert(st: JsonAlterViewAlterSchemaStatement) { + const { fromSchema, toSchema, name } = st; + + const statement = `ALTER VIEW "${fromSchema}"."${name}" SET SCHEMA "${toSchema}";`; + + return statement; + } +} + +class PgAlterViewAlterWithOptionConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_view_alter_with_option' && dialect === 'postgresql'; + } + + convert(st: JsonAlterViewAlterWithOptionStatement) { + const { schema, with: withOption, name } = st; + + const statement = + `ALTER VIEW "${schema}"."${name}" SET (check_option = ${withOption.checkOption}, security_barrier = ${withOption.securityBarrier}, security_invoker = ${withOption.securityInvoker});`; + + return statement; + } +} + +class PgAlterViewAddWithOptionConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_view_add_with_option' && dialect === 'postgresql'; + } + + convert(st: JsonAlterViewAddWithOptionStatement) { + const { schema, with: withOption, name } = st; + + const statement = + `ALTER VIEW "${schema}"."${name}" SET (check_option = ${withOption.checkOption}, security_barrier = ${withOption.securityBarrier}, security_invoker = ${withOption.securityInvoker});`; + + return statement; + } +} + +class PgAlterViewDropWithOptionConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_view_drop_with_option' && dialect === 'postgresql'; + } + + convert(st: JsonAlterViewDropWithOptionStatement) { + const { schema, name } = st; + + const statement = `ALTER VIEW "${schema}"."${name}" RESET (check_option, security_barrier, security_invoker);`; + + return statement; + } +} + class PgAlterTableAlterColumnSetGenerated extends Convertor { override can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2486,6 +2604,14 @@ convertors.push(new SQLiteCreateTableConvertor()); convertors.push(new SQLiteRecreateTableConvertor()); convertors.push(new LibSQLRecreateTableConvertor()); +convertors.push(new PgCreateViewConvertor()); +convertors.push(new PgDropViewConvertor()); +convertors.push(new PgRenameViewConvertor()); +convertors.push(new PgAlterViewSchemaConvertor()); +convertors.push(new PgAlterViewAlterWithOptionConvertor()); +convertors.push(new PgAlterViewAddWithOptionConvertor()); +convertors.push(new PgAlterViewDropWithOptionConvertor()); + convertors.push(new CreateTypeEnumConvertor()); convertors.push(new CreatePgSequenceConvertor()); diff --git a/drizzle-kit/tests/pg-views.test.ts b/drizzle-kit/tests/pg-views.test.ts new file mode 100644 index 000000000..76ef63bbf --- /dev/null +++ b/drizzle-kit/tests/pg-views.test.ts @@ -0,0 +1,619 @@ +import { eq, sql } from 'drizzle-orm'; +import { integer, pgSchema, pgTable, pgView } from 'drizzle-orm/pg-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemas } from './schemaDiffer'; + +test('create table and view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view: pgView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view', + definition: `select "id" from "users"`, + schema: 'public', + with: undefined, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (select "id" from "users");`); +}); + +test('create table and view #2', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view', + definition: `SELECT * FROM "users"`, + schema: 'public', + with: undefined, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (SELECT * FROM "users");`); +}); + +test('create table and view #3', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgView('some_view1', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }).as(sql`SELECT * FROM ${users}`), + view2: pgView('some_view2').with({ + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(3); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view1', + definition: `SELECT * FROM "users"`, + schema: 'public', + with: { + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }, + }); + expect(statements[2]).toStrictEqual({ + type: 'create_view', + name: 'some_view2', + definition: `select "id" from "users"`, + schema: 'public', + with: { + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }, + }); + + expect(sqlStatements.length).toBe(3); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe( + `CREATE VIEW "public"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "users");`, + ); + expect(sqlStatements[2]).toBe( + `CREATE VIEW "public"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "users");`, + ); +}); + +test('create table and view #4', async () => { + const schema = pgSchema('new_schema'); + + const users = schema.table('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + schema, + users: users, + view1: schema.view('some_view1', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }).as(sql`SELECT * FROM ${users}`), + view2: schema.view('some_view2').with({ + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(4); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: 'new_schema', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[2]).toStrictEqual({ + type: 'create_view', + name: 'some_view1', + definition: `SELECT * FROM "new_schema"."users"`, + schema: 'new_schema', + with: { + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }, + }); + expect(statements[3]).toStrictEqual({ + type: 'create_view', + name: 'some_view2', + definition: `select "id" from "new_schema"."users"`, + schema: 'new_schema', + with: { + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }, + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); + expect(sqlStatements[1]).toBe(`CREATE TABLE IF NOT EXISTS "new_schema"."users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[2]).toBe( + `CREATE VIEW "new_schema"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "new_schema"."users");`, + ); + expect(sqlStatements[3]).toBe( + `CREATE VIEW "new_schema"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "new_schema"."users");`, + ); +}); + +test('create table and view #5', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + view2: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); +}); + +test('drop view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view', + schema: 'public', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP VIEW "public"."some_view";`); +}); + +test('drop view #2', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').as((qb) => qb.select().from(users)), + }; + + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view', + schema: 'public', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP VIEW "public"."some_view";`); +}); + +test('drop view #3', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view1: pgView('some_view1').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as(( + qb, + ) => qb.select().from(users)), + view2: pgView('some_view2', { id: integer('id') }).with({ + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: true, + }).as(sql`SELECT * FROM ${users}`), + }; + + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view1', + schema: 'public', + }); + expect(statements[1]).toStrictEqual({ + type: 'drop_view', + name: 'some_view2', + schema: 'public', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP VIEW "public"."some_view1";`); + expect(sqlStatements[1]).toBe(`DROP VIEW "public"."some_view2";`); +}); + +test('drop view #4', async () => { + const schema = pgSchema('new_schema'); + + const users = schema.table('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + schema, + view1: schema.view('some_view1').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as( + (qb) => qb.select().from(users), + ), + view2: schema.view('some_view2', { id: integer('id') }).with({ + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: true, + }).as(sql`SELECT * FROM ${users}`), + }; + + const to = { + schema, + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view1', + schema: 'new_schema', + }); + expect(statements[1]).toStrictEqual({ + type: 'drop_view', + name: 'some_view2', + schema: 'new_schema', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP VIEW "new_schema"."some_view1";`); + expect(sqlStatements[1]).toBe(`DROP VIEW "new_schema"."some_view2";`); +}); + +test('rename view #1', async () => { + const from = { + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + view: pgView('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + schema: 'public', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER VIEW "public"."some_view" RENAME TO "public"."new_some_view";`); +}); + +test('rename view #2', async () => { + const schema = pgSchema('new_schema'); + + const from = { + view: schema.view('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + view: schema.view('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ + 'new_schema.some_view->new_schema.new_some_view', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + schema: 'new_schema', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER VIEW "new_schema"."some_view" RENAME TO "new_schema"."new_some_view";`); +}); + +test('view alter schema', async () => { + const schema = pgSchema('new_schema'); + + const from = { + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + schema, + view: schema.view('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.new_some_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(statements[1]).toStrictEqual({ + type: 'alter_view_alter_schema', + toSchema: 'new_schema', + fromSchema: 'public', + name: 'some_view', + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); + expect(sqlStatements[1]).toBe(`ALTER VIEW "public"."some_view" SET SCHEMA "new_schema";`); +}); + +test('add with option to view', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').as((qb) => qb.select().from(users)), + }; + + const to = { + users, + view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users) + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_add_with_option', + with: { + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: true, + }, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER VIEW "public"."some_view" SET (check_option = cascaded, security_barrier = true, security_invoker = true);`, + ); +}); + +test('drop with option to view', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_drop_with_option', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER VIEW "public"."some_view" RESET (check_option, security_barrier, security_invoker);`, + ); +}); + +test('alter with option in view', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').with({ checkOption: 'local', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users) + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_view_alter_with_option', + name: 'some_view', + schema: 'public', + with: { + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: true, + }, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER VIEW "public"."some_view" SET (check_option = cascaded, security_barrier = true, security_invoker = true);`, + ); +}); + +test('alter view', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').with({ checkOption: 'local', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users).where(eq(users.id, 1)) + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view', + schema: 'public', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view', + schema: 'public', + definition: `select "id" from "users" where "users"."id" = 1`, + with: { + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: true, + }, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `DROP VIEW "public"."some_view";`, + ); + expect(sqlStatements[1]).toBe( + `CREATE VIEW "public"."some_view" WITH (check_option = cascaded, security_barrier = true, security_invoker = true) AS (select "id" from "users" where "users"."id" = 1);`, + ); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 3a2a47b6b..24350204b 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -3,7 +3,7 @@ import { Client } from '@libsql/client/.'; import { Database } from 'better-sqlite3'; import { is } from 'drizzle-orm'; import { MySqlSchema, MySqlTable } from 'drizzle-orm/mysql-core'; -import { isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable } from 'drizzle-orm/pg-core'; +import { isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable, PgView } from 'drizzle-orm/pg-core'; import { SQLiteTable } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; @@ -15,6 +15,7 @@ import { schemasResolver, sequencesResolver, tablesResolver, + viewsResolver, } from 'src/cli/commands/migrate'; import { logSuggestionsAndReturn } from 'src/cli/commands/sqlitePushUtils'; import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql'; @@ -45,11 +46,12 @@ import { ResolverOutputWithMoved, Sequence, Table, + ViewSquashed, } from 'src/snapshotsDiffer'; export type PostgresSchema = Record< string, - PgTable | PgEnum | PgSchema | PgSequence + PgTable | PgEnum | PgSchema | PgSequence | PgView >; export type MysqlSchema = Record | MySqlSchema>; export type SqliteSchema = Record>; @@ -405,6 +407,82 @@ async ( } }; +export const testViewsResolver = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } + + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; + + const result: { + created: ViewSquashed[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: ViewSquashed; to: ViewSquashed }[]; + deleted: ViewSquashed[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; + }); + + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, + }); + } + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } + } + + result.created = createdViews; + result.deleted = deletedViews; + + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + export const diffTestSchemasPush = async ( client: PGlite, left: PostgresSchema, @@ -559,6 +637,10 @@ export const applyPgDiffs = async (sn: PostgresSchema) => { return { sqlStatements, statements }; }; +export function isPgView(obj: unknown): obj is PgView { + return is(obj, PgView); +} + export const diffTestSchemas = async ( left: PostgresSchema, right: PostgresSchema, @@ -581,17 +663,23 @@ export const diffTestSchemas = async ( const rightSequences = Object.values(right).filter((it) => isPgSequence(it)) as PgSequence[]; + const leftViews = Object.values(left).filter((it) => isPgView(it)) as PgView[]; + + const rightViews = Object.values(right).filter((it) => isPgView(it)) as PgView[]; + const serialized1 = generatePgSnapshot( leftTables, leftEnums, leftSchemas, leftSequences, + leftViews, ); const serialized2 = generatePgSnapshot( rightTables, rightEnums, rightSchemas, rightSequences, + rightViews, ); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -630,6 +718,7 @@ export const diffTestSchemas = async ( testSequencesResolver(renames), testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolver(renames), validatedPrev, validatedCur, ); @@ -643,6 +732,7 @@ export const diffTestSchemas = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, ); @@ -982,13 +1072,6 @@ export async function diffTestSchemasPushLibSQL( run: async (query: string) => { await client.execute(query); }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, }, undefined, ); @@ -1048,13 +1131,6 @@ export async function diffTestSchemasPushLibSQL( run: async (query: string) => { await client.execute(query); }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, }, statements, sn1, From d0205b2933f62b823a41f24904087cf1ddef1936 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 23 Sep 2024 18:39:13 +0300 Subject: [PATCH 181/492] added support for views and materialized views in postgres (push + introspect + generate) --- drizzle-kit/src/@types/utils.ts | 6 + drizzle-kit/src/cli/commands/introspect.ts | 2 + drizzle-kit/src/cli/commands/migrate.ts | 5 +- drizzle-kit/src/introspect-pg.ts | 66 + drizzle-kit/src/jsonDiffer.js | 48 +- drizzle-kit/src/jsonStatements.ts | 124 +- drizzle-kit/src/serializer/index.ts | 4 +- drizzle-kit/src/serializer/pgImports.ts | 37 +- drizzle-kit/src/serializer/pgSchema.ts | 82 +- drizzle-kit/src/serializer/pgSerializer.ts | 471 +++- drizzle-kit/src/snapshotsDiffer.ts | 135 +- drizzle-kit/src/sqlgenerator.ts | 111 +- drizzle-kit/tests/introspect/pg.test.ts | 189 ++ drizzle-kit/tests/pg-views.test.ts | 2250 ++++++++++++++------ drizzle-kit/tests/push/pg.test.ts | 2175 +++++++++++-------- drizzle-kit/tests/schemaDiffer.ts | 103 +- drizzle-orm/src/pg-core/view.ts | 52 +- drizzle-orm/src/utils.ts | 4 + 18 files changed, 4102 insertions(+), 1762 deletions(-) diff --git a/drizzle-kit/src/@types/utils.ts b/drizzle-kit/src/@types/utils.ts index 3f14151a4..04e7e125f 100644 --- a/drizzle-kit/src/@types/utils.ts +++ b/drizzle-kit/src/@types/utils.ts @@ -4,6 +4,8 @@ declare global { squashSpaces(): string; capitalise(): string; camelCase(): string; + snake_case(): string; + concatIf(it: string, condition: boolean): string; } @@ -44,6 +46,10 @@ String.prototype.concatIf = function(it: string, condition: boolean) { return condition ? `${this}${it}` : String(this); }; +String.prototype.snake_case = function() { + return this && this.length > 0 ? `${this.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)}` : String(this); +}; + Array.prototype.random = function() { return this[~~(Math.random() * this.length)]; }; diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index acd569dea..7f67315fa 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -28,6 +28,7 @@ import { schemasResolver, sequencesResolver, tablesResolver, + viewsResolver, writeResult, } from './migrate'; @@ -100,6 +101,7 @@ export const introspectPostgres = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, dryPg, schema, ); diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 86db4a91a..b6c28edb7 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -30,7 +30,6 @@ import { ResolverOutputWithMoved, Sequence, Table, - ViewSquashed, } from '../../snapshotsDiffer'; import { assertV1OutFolder, Journal, prepareMigrationFolder } from '../../utils'; import { prepareMigrationMetadata } from '../../utils/words'; @@ -94,8 +93,8 @@ export const tablesResolver = async ( }; export const viewsResolver = async ( - input: ResolverInput, -): Promise> => { + input: ResolverInput, +): Promise> => { try { const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict( input.created, diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index b7a52b735..f7af006c5 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -388,6 +388,35 @@ export const schemaToTypeScript = ( { pg: [] as string[] }, ); + Object.values(schema.views).forEach((it) => { + if (it.schema && it.schema !== 'public' && it.schema !== '') { + imports.pg.push('pgSchema'); + } else if (it.schema === 'public') { + it.materialized ? imports.pg.push('pgMaterializedView') : imports.pg.push('pgView'); + } + + Object.values(it.columns).forEach(() => { + const columnImports = Object.values(it.columns) + .map((col) => { + let patched: string = (importsPatch[col.type] || col.type).replace('[]', ''); + patched = patched === 'double precision' ? 'doublePrecision' : patched; + patched = patched.startsWith('varchar(') ? 'varchar' : patched; + patched = patched.startsWith('char(') ? 'char' : patched; + patched = patched.startsWith('numeric(') ? 'numeric' : patched; + patched = patched.startsWith('time(') ? 'time' : patched; + patched = patched.startsWith('timestamp(') ? 'timestamp' : patched; + patched = patched.startsWith('vector(') ? 'vector' : patched; + patched = patched.startsWith('geometry(') ? 'geometry' : patched; + return patched; + }) + .filter((type) => { + return pgImportsList.has(type); + }); + + imports.pg.push(...columnImports); + }); + }); + Object.values(schema.sequences).forEach((it) => { if (it.schema && it.schema !== 'public' && it.schema !== '') { imports.pg.push('pgSchema'); @@ -518,6 +547,41 @@ export const schemaToTypeScript = ( return statement; }); + const viewsStatements = Object.values(schema.views) + .map((it) => { + const viewSchema = schemas[it.schema]; + + const paramName = paramNameFor(it.name, viewSchema); + + const func = viewSchema + ? (it.materialized ? `${viewSchema}.materializedView` : `${viewSchema}.view`) + : (it.materialized ? 'pgMaterializedView' : 'pgView'); + + const withOption = it.with ?? ''; + + const as = `sql\`${it.definition}\``; + + const tablespace = it.tablespace ?? ''; + + const columns = createTableColumns( + '', + Object.values(it.columns), + [], + enumTypes, + schemas, + casing, + schema.internal, + ); + + let statement = `export const ${withCasing(paramName, casing)} = ${func}("${it.name}", {${columns}})`; + statement += tablespace ? `.tablespace("${tablespace}")` : ''; + statement += withOption ? `.with(${JSON.stringify(withOption)})` : ''; + statement += `.as(${as});`; + + return statement; + }) + .join('\n\n'); + const uniquePgImports = ['pgTable', ...new Set(imports.pg)]; const importsTs = `import { ${ @@ -532,6 +596,8 @@ export const schemaToTypeScript = ( decalrations += sequencesStatements; decalrations += '\n'; decalrations += tableStatements.join('\n\n'); + decalrations += '\n'; + decalrations += viewsStatements; const file = importsTs + decalrations; diff --git a/drizzle-kit/src/jsonDiffer.js b/drizzle-kit/src/jsonDiffer.js index 2a75138a3..7073bb136 100644 --- a/drizzle-kit/src/jsonDiffer.js +++ b/drizzle-kit/src/jsonDiffer.js @@ -243,12 +243,32 @@ export function applyJsonDiff(json1, json2) { const viewsEntries = Object.entries(difference.views); const alteredViews = viewsEntries.filter((it) => !(it[0].includes('__added') || it[0].includes('__deleted'))).map( - ([name, view]) => { + ([nameWithSchema, view]) => { const deletedWithOption = view.with__deleted; const addedWithOption = view.with__added; - const alteredWith = view.with; + const deletedWith = Object.fromEntries( + Object.entries(view.with || {}).filter((it) => it[0].endsWith('__deleted')).map(([key, value]) => { + return [key.replace('__deleted', ''), value]; + }), + ); + + const addedWith = Object.fromEntries( + Object.entries(view.with || {}).filter((it) => it[0].endsWith('__added')).map(([key, value]) => { + return [key.replace('__added', ''), value]; + }), + ); + + const alterWith = Object.fromEntries( + Object.entries(view.with || {}).filter((it) => + typeof it[1].__old !== 'undefined' && typeof it[1].__new !== 'undefined' + ).map( + (it) => { + return [it[0], it[1].__new]; + }, + ), + ); const alteredSchema = view.schema; @@ -256,15 +276,29 @@ export function applyJsonDiff(json1, json2) { const alteredExisting = view.isExisting; + const addedTablespace = view.tablespace__added; + const droppedTablespace = view.tablespace__deleted; + const alterTablespaceTo = view.tablespace; + + let alteredTablespace; + if (addedTablespace) alteredTablespace = { __new: addedTablespace, __old: 'pg_default' }; + if (droppedTablespace) alteredTablespace = { __new: 'pg_default', __old: droppedTablespace }; + if (alterTablespaceTo) alteredTablespace = alterTablespaceTo; + return { - name: name, - schema: json2.views[name].schema, - deletedWithOption, - addedWithOption, - alteredWith, + name: json2.views[nameWithSchema].name, + schema: json2.views[nameWithSchema].schema, + deletedWithOption: deletedWithOption, + addedWithOption: addedWithOption, + alteredWith: { + deletedWith: Object.keys(deletedWith).length ? deletedWith : undefined, + addedWith: Object.keys(addedWith).length ? addedWith : undefined, + alterWith: Object.keys(alterWith).length ? alterWith : undefined, + }, alteredSchema, alteredDefinition, alteredExisting, + alteredTablespace, }; }, ); diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index a6d2051d1..2b374e7e2 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -1,9 +1,9 @@ import chalk from 'chalk'; import { getNewTableName } from './cli/commands/sqlitePushUtils'; import { warning } from './cli/views'; -import { CommonSquashedSchema, Dialect } from './schemaValidator'; +import { CommonSquashedSchema } from './schemaValidator'; import { MySqlKitInternals, MySqlSchema, MySqlSquasher } from './serializer/mysqlSchema'; -import { Index, PgSchema, PgSquasher, View, ViewWithOption } from './serializer/pgSchema'; +import { Index, MatViewWithOption, PgSchema, PgSquasher, View, ViewWithOption } from './serializer/pgSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, @@ -524,18 +524,15 @@ export interface JsonRenameSchema { to: string; } -export interface JsonCreateViewStatement { +export type JsonCreateViewStatement = { type: 'create_view'; - name: string; - schema: string; - definition: string; - with: ViewWithOption; -} +} & Omit; export interface JsonDropViewStatement { type: 'drop_view'; name: string; schema: string; + materialized: boolean; } export interface JsonRenameViewStatement { @@ -543,6 +540,7 @@ export interface JsonRenameViewStatement { nameTo: string; nameFrom: string; schema: string; + materialized: boolean; } export interface JsonAlterViewAlterSchemaStatement { @@ -550,33 +548,50 @@ export interface JsonAlterViewAlterSchemaStatement { fromSchema: string; toSchema: string; name: string; + materialized: boolean; } -export interface JsonAlterViewAlterWithOptionStatement { - type: 'alter_view_alter_with_option'; - schema: string; - name: string; - with: Exclude; -} +export type JsonAlterViewAddWithOptionStatement = + & { + type: 'alter_view_add_with_option'; + schema: string; + name: string; + } + & ({ + materialized: true; + with: MatViewWithOption; + } | { + materialized: false; + with: ViewWithOption; + }); -export interface JsonAlterViewAddWithOptionStatement { - type: 'alter_view_add_with_option'; - schema: string; - name: string; - with: Exclude; -} +export type JsonAlterViewDropWithOptionStatement = + & { + type: 'alter_view_drop_with_option'; + schema: string; + name: string; + } + & ({ + materialized: true; + with: MatViewWithOption; + } | { + materialized: false; + with: ViewWithOption; + }); -export interface JsonAlterViewDropWithOptionStatement { - type: 'alter_view_drop_with_option'; - schema: string; +export interface JsonAlterViewAlterTablespaceStatement { + type: 'alter_view_alter_tablespace'; + toTablespace: string; name: string; + schema: string; + materialized: true; } export type JsonAlterViewStatement = | JsonAlterViewAlterSchemaStatement - | JsonAlterViewAlterWithOptionStatement | JsonAlterViewAddWithOptionStatement - | JsonAlterViewDropWithOptionStatement; + | JsonAlterViewDropWithOptionStatement + | JsonAlterViewAlterTablespaceStatement; export type JsonAlterColumnStatement = | JsonRenameColumnStatement @@ -2488,26 +2503,35 @@ export const preparePgCreateViewJson = ( name: string, schema: string, definition: string, - withClause?: string, + materialized: boolean, + withNoData: boolean = false, + withOption?: any, + using?: string, + tablespace?: string, ): JsonCreateViewStatement => { - const unsquashedWith = withClause ? PgSquasher.unsquashViewWith(withClause) : undefined; return { type: 'create_view', - name, - schema, - definition, - with: unsquashedWith, + name: name, + schema: schema, + definition: definition, + with: withOption, + materialized: materialized, + withNoData, + using, + tablespace, }; }; export const preparePgDropViewJson = ( name: string, schema: string, + materialized: boolean, ): JsonDropViewStatement => { return { type: 'drop_view', name, schema, + materialized, }; }; @@ -2515,12 +2539,14 @@ export const preparePgRenameViewJson = ( to: string, from: string, schema: string, + materialized: boolean, ): JsonRenameViewStatement => { return { type: 'rename_view', nameTo: to, nameFrom: from, schema, + materialized, }; }; @@ -2528,48 +2554,58 @@ export const preparePgAlterViewAlterSchemaJson = ( to: string, from: string, name: string, + materialized: boolean, ): JsonAlterViewAlterSchemaStatement => { return { type: 'alter_view_alter_schema', fromSchema: from, toSchema: to, name, + materialized, }; }; export const preparePgAlterViewAddWithOptionJson = ( name: string, schema: string, - withOption: string, + materialized: boolean, + withOption: MatViewWithOption | ViewWithOption, ): JsonAlterViewAddWithOptionStatement => { return { type: 'alter_view_add_with_option', name, schema, - with: PgSquasher.unsquashViewWith(withOption), - }; + materialized: materialized, + with: withOption, + } as JsonAlterViewAddWithOptionStatement; }; -export const preparePgAlterViewAlterWithOptionJson = ( +export const preparePgAlterViewDropWithOptionJson = ( name: string, schema: string, - withOption: string, -): JsonAlterViewAlterWithOptionStatement => { + materialized: boolean, + withOption: MatViewWithOption | ViewWithOption, +): JsonAlterViewDropWithOptionStatement => { return { - type: 'alter_view_alter_with_option', + type: 'alter_view_drop_with_option', name, schema, - with: PgSquasher.unsquashViewWith(withOption), - }; + materialized: materialized, + with: withOption, + } as JsonAlterViewDropWithOptionStatement; }; -export const preparePgAlterViewDropWithOptionJson = ( +export const preparePgAlterViewAlterTablespaceOptionJson = ( name: string, schema: string, -): JsonAlterViewDropWithOptionStatement => { + materialized: boolean, + to: string, +): JsonAlterViewAlterTablespaceStatement => { return { - type: 'alter_view_drop_with_option', + type: 'alter_view_alter_tablespace', name, schema, - }; + materialized: materialized, + toTablespace: to, + } as JsonAlterViewAlterTablespaceStatement; }; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index e90acc8dd..f1f20ebf5 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -60,11 +60,11 @@ export const serializePg = async ( const { prepareFromPgImports } = await import('./pgImports'); const { generatePgSnapshot } = await import('./pgSerializer'); - const { tables, enums, schemas, sequences, views } = await prepareFromPgImports( + const { tables, enums, schemas, sequences, views, matViews } = await prepareFromPgImports( filenames, ); - return generatePgSnapshot(tables, enums, schemas, sequences, views, schemaFilter); + return generatePgSnapshot(tables, enums, schemas, sequences, views, matViews, schemaFilter); }; export const serializeSQLite = async ( diff --git a/drizzle-kit/src/serializer/pgImports.ts b/drizzle-kit/src/serializer/pgImports.ts index b7b82db3e..e0b3fb743 100644 --- a/drizzle-kit/src/serializer/pgImports.ts +++ b/drizzle-kit/src/serializer/pgImports.ts @@ -1,5 +1,17 @@ import { is } from 'drizzle-orm'; -import { AnyPgTable, isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable, PgView } from 'drizzle-orm/pg-core'; +import { + AnyPgTable, + isPgEnum, + isPgMaterializedView, + isPgSequence, + isPgView, + PgEnum, + PgMaterializedView, + PgSchema, + PgSequence, + PgTable, + PgView, +} from 'drizzle-orm/pg-core'; import { safeRegister } from '../cli/commands/utils'; export const prepareFromExports = (exports: Record) => { @@ -8,6 +20,7 @@ export const prepareFromExports = (exports: Record) => { const schemas: PgSchema[] = []; const sequences: PgSequence[] = []; const views: PgView[] = []; + const matViews: PgMaterializedView[] = []; const i0values = Object.values(exports); i0values.forEach((t) => { @@ -23,24 +36,29 @@ export const prepareFromExports = (exports: Record) => { schemas.push(t); } - if (is(t, PgView)) { + if (isPgView(t)) { views.push(t); } + if (isPgMaterializedView(t)) { + matViews.push(t); + } + if (isPgSequence(t)) { sequences.push(t); } }); - return { tables, enums, schemas, sequences, views }; + return { tables, enums, schemas, sequences, views, matViews }; }; export const prepareFromPgImports = async (imports: string[]) => { - let tables: AnyPgTable[] = []; - let enums: PgEnum[] = []; - let schemas: PgSchema[] = []; - let sequences: PgSequence[] = []; - let views: PgView[] = []; + const tables: AnyPgTable[] = []; + const enums: PgEnum[] = []; + const schemas: PgSchema[] = []; + const sequences: PgSequence[] = []; + const views: PgView[] = []; + const matViews: PgMaterializedView[] = []; const { unregister } = await safeRegister(); for (let i = 0; i < imports.length; i++) { @@ -54,8 +72,9 @@ export const prepareFromPgImports = async (imports: string[]) => { schemas.push(...prepared.schemas); sequences.push(...prepared.sequences); views.push(...prepared.views); + matViews.push(...prepared.matViews); } unregister(); - return { tables: Array.from(new Set(tables)), enums, schemas, sequences, views }; + return { tables: Array.from(new Set(tables)), enums, schemas, sequences, views, matViews }; }; diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index 1af5cbda1..515658d2d 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -221,31 +221,47 @@ const uniqueConstraint = object({ }).strict(); const viewWithOption = object({ - checkOption: enumType(['cascaded', 'local']), - securityBarrier: boolean(), - securityInvoker: boolean(), -}).strict().optional(); + checkOption: enumType(['local', 'cascaded']).optional(), + securityBarrier: boolean().optional(), + securityInvoker: boolean().optional(), +}).strict(); + +const matViewWithOption = object({ + fillfactor: number().optional(), + toastTupleTarget: number().optional(), + parallelWorkers: number().optional(), + autovacuumEnabled: boolean().optional(), + vacuumIndexCleanup: enumType(['auto', 'off', 'on']).optional(), + vacuumTruncate: boolean().optional(), + autovacuumVacuumThreshold: number().optional(), + autovacuumVacuumScaleFactor: number().optional(), + autovacuumVacuumCostDelay: number().optional(), + autovacuumVacuumCostLimit: number().optional(), + autovacuumFreezeMinAge: number().optional(), + autovacuumFreezeMaxAge: number().optional(), + autovacuumFreezeTableAge: number().optional(), + autovacuumMultixactFreezeMinAge: number().optional(), + autovacuumMultixactFreezeMaxAge: number().optional(), + autovacuumMultixactFreezeTableAge: number().optional(), + logAutovacuumMinDuration: number().optional(), + userCatalogTable: boolean().optional(), +}).strict(); + +export const mergedViewWithOption = viewWithOption.merge(matViewWithOption); export const view = object({ name: string(), schema: string(), columns: record(string(), column), definition: string().optional(), - materialized: boolean().optional(), - with: viewWithOption, + materialized: boolean(), + with: mergedViewWithOption.optional(), isExisting: boolean(), + withNoData: boolean().optional(), + using: string().optional(), + tablespace: string().optional(), }).strict(); -export const viewSquashed = object({ - name: string(), - schema: string(), - columns: record(string(), column), - definition: string().optional(), - materialized: boolean().optional(), - with: string().optional(), - isExisting: boolean(), -}); - const tableV4 = object({ name: string(), schema: string(), @@ -444,7 +460,7 @@ export const pgSchemaSquashed = object({ tables: record(string(), tableSquashed), enums: record(string(), enumSchema), schemas: record(string(), string()), - views: record(string(), viewSquashed), + views: record(string(), view), sequences: record(string(), sequenceSquashed), }).strict(); @@ -474,7 +490,9 @@ export type ForeignKey = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; export type View = TypeOf; +export type MatViewWithOption = TypeOf; export type ViewWithOption = TypeOf; + export type PgKitInternals = TypeOf; export type PgSchemaV1 = TypeOf; @@ -657,17 +675,6 @@ export const PgSquasher = { cycle: splitted[7] === 'true', }; }, - squashViewWith: (withOption: Exclude): string => { - return `${withOption.checkOption};${withOption.securityBarrier};${withOption.securityInvoker}`; - }, - unsquashViewWith: (squashed: string): Exclude => { - const [checkOption, securityBarrier, securityInvoker] = squashed.split(';'); - return { - checkOption: checkOption as 'cascaded' | 'local', - securityBarrier: securityBarrier === 'true', - securityInvoker: securityInvoker === 'true', - }; - }, }; export const squashPgScheme = ( @@ -740,30 +747,13 @@ export const squashPgScheme = ( }), ); - const mappedViews = Object.fromEntries( - Object.entries(json.views).map((it) => { - return [ - it[0], - { - name: it[1].name, - columns: it[1].columns, - definition: it[1].definition, - isExisting: it[1].isExisting, - with: it[1].with ? PgSquasher.squashViewWith(it[1].with) : undefined, - schema: it[1].schema, - materialized: it[1].materialized, - }, - ]; - }), - ); - return { version: '7', dialect: json.dialect, tables: mappedTables, enums: json.enums, schemas: json.schemas, - views: mappedViews, + views: json.views, sequences: mappedSequences, }; }; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index f19909ef7..8e4fe0bc6 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -3,12 +3,14 @@ import { getTableName, is, SQL } from 'drizzle-orm'; import { AnyPgTable, ExtraConfigColumn, + getMaterializedViewConfig, getViewConfig, IndexedColumn, PgColumn, PgDialect, PgEnum, PgEnumColumn, + PgMaterializedView, PgSchema, PgSequence, PgView, @@ -120,6 +122,7 @@ export const generatePgSnapshot = ( schemas: PgSchema[], sequences: PgSequence[], views: PgView[], + matViews: PgMaterializedView[], schemaFilter?: string[], ): PgSchemaInternal => { const result: Record = {}; @@ -539,13 +542,38 @@ export const generatePgSnapshot = ( } } - for (const view of views) { - const { name: viewName, schema, query, selectedFields, isExisting, with: viewWithOptions } = getViewConfig(view); + const combinedViews = [...views, ...matViews]; + for (const view of combinedViews) { + let viewName; + let schema; + let query; + let selectedFields; + let isExisting; + let withOption; + let tablespace; + let using; + let withNoData; + let materialized: boolean = false; + + if (is(view, PgView)) { + ({ name: viewName, schema, query, selectedFields, isExisting, with: withOption } = getViewConfig(view)); + } else { + ({ name: viewName, schema, query, selectedFields, isExisting, with: withOption, tablespace, using, withNoData } = + getMaterializedViewConfig( + view, + )); + + materialized = true; + } + + const viewSchema = schema ?? 'public'; + + const viewKey = `${viewSchema}.${viewName}`; const columnsObject: Record = {}; const uniqueConstraintObject: Record = {}; - const existingView = resultViews[viewName]; + const existingView = resultViews[viewKey]; if (typeof existingView !== 'undefined') { console.log( `\n${ @@ -698,13 +726,17 @@ export const generatePgSnapshot = ( } } - resultViews[viewName] = { + resultViews[viewKey] = { columns: columnsObject, definition: isExisting ? undefined : dialect.sqlToQuery(query!).sql, name: viewName, - schema: schema ?? 'public', + schema: viewSchema, isExisting, - with: viewWithOptions, + with: withOption, + withNoData, + materialized, + tablespace, + using, }; } @@ -775,12 +807,27 @@ export const fromDatabase = async ( ) => void, ): Promise => { const result: Record = {}; + const views: Record = {}; const internals: PgKitInternals = { tables: {} }; - const where = schemaFilters.map((t) => `table_schema = '${t}'`).join(' or '); - - const allTables = await db.query( - `SELECT table_schema, table_name FROM information_schema.tables${where === '' ? '' : ` WHERE ${where}`};`, + const where = schemaFilters.map((t) => `n.nspname = '${t}'`).join(' or '); + + const allTables = await db.query<{ table_schema: string; table_name: string; type: string }>( + `SELECT + n.nspname AS table_schema, + c.relname AS table_name, + CASE + WHEN c.relkind = 'r' THEN 'table' + WHEN c.relkind = 'v' THEN 'view' + WHEN c.relkind = 'm' THEN 'materialized_view' + END AS type +FROM + pg_catalog.pg_class c +JOIN + pg_catalog.pg_namespace n ON n.oid = c.relnamespace +WHERE + c.relkind IN ('r', 'v', 'm') + ${where === '' ? '' : ` AND ${where}`};`, ); const schemas = new Set(allTables.map((it) => it.table_schema)); @@ -880,7 +927,7 @@ export const fromDatabase = async ( const sequencesInColumns: string[] = []; - const all = allTables.map((row) => { + const all = allTables.filter((it) => it.type === 'table').map((row) => { return new Promise(async (res, rej) => { const tableName = row.table_name as string; if (!tablesFilter(tableName)) return res(''); @@ -1371,6 +1418,406 @@ export const fromDatabase = async ( for await (const _ of all) { } + const allViews = allTables.filter((it) => it.type === 'view' || it.type === 'materialized_view').map((row) => { + return new Promise(async (res, rej) => { + const viewName = row.table_name as string; + if (!tablesFilter(viewName)) return res(''); + tableCount += 1; + const viewSchema = row.table_schema; + + try { + const columnToReturn: Record = {}; + + const viewResponses = await db.query(`WITH view_columns AS ( + SELECT DISTINCT + nv.nspname::information_schema.sql_identifier AS view_schema, + v.relname::information_schema.sql_identifier AS view_name, + nt.nspname::information_schema.sql_identifier AS table_schema, + t.relname::information_schema.sql_identifier AS table_name, + a.attname::information_schema.sql_identifier AS column_name + FROM pg_namespace nv + JOIN pg_class v ON nv.oid = v.relnamespace + JOIN pg_depend dv ON v.oid = dv.refobjid + JOIN pg_depend dt ON dv.objid = dt.objid + JOIN pg_class t ON dt.refobjid = t.oid + JOIN pg_namespace nt ON t.relnamespace = nt.oid + JOIN pg_attribute a ON t.oid = a.attrelid + WHERE (v.relkind = 'v'::"char" OR v.relkind = 'm'::"char") + AND dv.refclassid = 'pg_class'::regclass::oid + AND dv.classid = 'pg_rewrite'::regclass::oid + AND dv.deptype = 'i'::"char" + AND dv.objid = dt.objid + AND dv.refobjid <> dt.refobjid + AND dt.classid = 'pg_rewrite'::regclass::oid + AND dt.refclassid = 'pg_class'::regclass::oid + AND t.relkind = ANY (ARRAY['r'::"char", 'v'::"char", 'f'::"char", 'p'::"char"]) + AND dt.refobjsubid = a.attnum + AND pg_has_role(t.relowner, 'USAGE'::text) + AND nv.nspname::information_schema.sql_identifier = '${viewSchema}' + AND v.relname::information_schema.sql_identifier = '${viewName}' +), +column_descriptions AS ( + SELECT DISTINCT + a.attrelid::regclass::text AS table_name, + a.attname AS column_name, + c.is_nullable, + a.attndims AS array_dimensions, + CASE + WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[]) AND EXISTS ( + SELECT FROM pg_attrdef ad + WHERE ad.adrelid = a.attrelid + AND ad.adnum = a.attnum + AND pg_get_expr(ad.adbin, ad.adrelid) = 'nextval(''' || pg_get_serial_sequence(a.attrelid::regclass::text, a.attname)::regclass || '''::regclass)' + ) + THEN CASE a.atttypid + WHEN 'int'::regtype THEN 'serial' + WHEN 'int8'::regtype THEN 'bigserial' + WHEN 'int2'::regtype THEN 'smallserial' + END + ELSE format_type(a.atttypid, a.atttypmod) + END AS data_type, + pg_get_serial_sequence('"' || c.table_schema || '"."' || c.table_name || '"', a.attname)::regclass AS seq_name, + c.column_default, + c.data_type AS additional_dt, + c.udt_name AS enum_name, + c.is_generated, + c.generation_expression, + c.is_identity, + c.identity_generation, + c.identity_start, + c.identity_increment, + c.identity_maximum, + c.identity_minimum, + c.identity_cycle + FROM pg_attribute a + JOIN information_schema.columns c ON c.column_name = a.attname + JOIN pg_type t ON t.oid = a.atttypid + LEFT JOIN pg_namespace ns ON ns.oid = t.typnamespace + WHERE a.attnum > 0 + AND NOT a.attisdropped +), +table_constraints AS ( + SELECT DISTINCT ON (ccu.column_name) + ccu.column_name, + c.data_type, + tc.constraint_type, + tc.constraint_name, + tc.constraint_schema, + tc.table_name + FROM information_schema.table_constraints tc + JOIN information_schema.constraint_column_usage ccu USING (constraint_schema, constraint_name) + JOIN information_schema.columns c ON c.table_schema = tc.constraint_schema + AND tc.table_name = c.table_name + AND ccu.column_name = c.column_name +), +additional_column_info AS ( + SELECT DISTINCT + a.attrelid::regclass::text AS table_name, + a.attname AS column_name, + is_nullable, + a.attndims AS array_dimensions, + CASE + WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[]) AND EXISTS ( + SELECT FROM pg_attrdef ad + WHERE ad.adrelid = a.attrelid + AND ad.adnum = a.attnum + AND pg_get_expr(ad.adbin, ad.adrelid) = 'nextval(''' || pg_get_serial_sequence(a.attrelid::regclass::text, a.attname)::regclass || '''::regclass)' + ) + THEN CASE a.atttypid + WHEN 'int'::regtype THEN 'serial' + WHEN 'int8'::regtype THEN 'bigserial' + WHEN 'int2'::regtype THEN 'smallserial' + END + ELSE format_type(a.atttypid, a.atttypmod) + END AS data_type, + pg_get_serial_sequence('"' || c.table_schema || '"."' || c.table_name || '"', a.attname)::regclass AS seq_name, + c.column_default, + c.data_type AS additional_dt, + c.udt_name AS enum_name, + c.is_generated, + generation_expression, + is_identity, + identity_generation, + identity_start, + identity_increment, + identity_maximum, + identity_minimum, + identity_cycle + FROM pg_attribute a + JOIN information_schema.columns c ON c.column_name = a.attname + LEFT JOIN pg_type t ON t.oid = a.atttypid + LEFT JOIN pg_namespace ns ON ns.oid = t.typnamespace + WHERE a.attnum > 0 + AND NOT a.attisdropped +) +SELECT DISTINCT ON (vc.table_name, vc.column_name) + vc.view_schema, + vc.view_name, + vc.table_schema, + vc.table_name, + vc.column_name, + COALESCE(cd.data_type, aci.data_type) AS data_type, + tc.constraint_type, + tc.constraint_name, + aci.is_nullable, + aci.array_dimensions, + aci.seq_name, + aci.column_default, + aci.additional_dt, + aci.enum_name, + aci.is_generated, + aci.generation_expression, + aci.is_identity, + aci.identity_generation, + aci.identity_start, + aci.identity_increment, + aci.identity_maximum, + aci.identity_minimum, + aci.identity_cycle +FROM view_columns vc +LEFT JOIN column_descriptions cd ON vc.table_name = cd.table_name AND vc.column_name = cd.column_name +LEFT JOIN table_constraints tc ON vc.table_name = tc.table_name AND vc.column_name = tc.column_name +LEFT JOIN additional_column_info aci ON vc.table_name = aci.table_name AND vc.column_name = aci.column_name +ORDER BY vc.table_name, vc.column_name;`); + + for (const viewResponse of viewResponses) { + const columnName = viewResponse.column_name; + const columnAdditionalDT = viewResponse.additional_dt; + const columnDimensions = viewResponse.array_dimensions; + const enumType: string = viewResponse.enum_name; + let columnType: string = viewResponse.data_type; + const typeSchema = viewResponse.type_schema; + // const defaultValueRes: string = viewResponse.column_default; + + const isGenerated = viewResponse.is_generated === 'ALWAYS'; + const generationExpression = viewResponse.generation_expression; + const isIdentity = viewResponse.is_identity === 'YES'; + const identityGeneration = viewResponse.identity_generation === 'ALWAYS' + ? 'always' + : 'byDefault'; + const identityStart = viewResponse.identity_start; + const identityIncrement = viewResponse.identity_increment; + const identityMaximum = viewResponse.identity_maximum; + const identityMinimum = viewResponse.identity_minimum; + const identityCycle = viewResponse.identity_cycle === 'YES'; + const identityName = viewResponse.seq_name; + const defaultValueRes = viewResponse.column_default; + + const primaryKey = viewResponse.constraint_type === 'PRIMARY KEY'; + + let columnTypeMapped = columnType; + + // Set default to internal object + if (columnAdditionalDT === 'ARRAY') { + if (typeof internals.tables[viewName] === 'undefined') { + internals.tables[viewName] = { + columns: { + [columnName]: { + isArray: true, + dimensions: columnDimensions, + rawType: columnTypeMapped.substring( + 0, + columnTypeMapped.length - 2, + ), + }, + }, + }; + } else { + if ( + typeof internals.tables[viewName]!.columns[columnName] + === 'undefined' + ) { + internals.tables[viewName]!.columns[columnName] = { + isArray: true, + dimensions: columnDimensions, + rawType: columnTypeMapped.substring( + 0, + columnTypeMapped.length - 2, + ), + }; + } + } + } + + const defaultValue = defaultForColumn( + viewResponse, + internals, + viewName, + ); + if ( + defaultValue === 'NULL' + || (defaultValueRes && defaultValueRes.startsWith('(') && defaultValueRes.endsWith(')')) + ) { + if (typeof internals!.tables![viewName] === 'undefined') { + internals!.tables![viewName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, + }, + }; + } else { + if ( + typeof internals!.tables![viewName]!.columns[columnName] + === 'undefined' + ) { + internals!.tables![viewName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![viewName]!.columns[ + columnName + ]!.isDefaultAnExpression = true; + } + } + } + + const isSerial = columnType === 'serial'; + + if (columnTypeMapped.startsWith('numeric(')) { + columnTypeMapped = columnTypeMapped.replace(',', ', '); + } + + if (columnAdditionalDT === 'ARRAY') { + for (let i = 1; i < Number(columnDimensions); i++) { + columnTypeMapped += '[]'; + } + } + + columnTypeMapped = columnTypeMapped + .replace('character varying', 'varchar') + .replace(' without time zone', '') + // .replace("timestamp without time zone", "timestamp") + .replace('character', 'char'); + + columnTypeMapped = trimChar(columnTypeMapped, '"'); + + columnToReturn[columnName] = { + name: columnName, + type: + // filter vectors, but in future we should filter any extension that was installed by user + columnAdditionalDT === 'USER-DEFINED' + && !['vector', 'geometry'].includes(enumType) + ? enumType + : columnTypeMapped, + typeSchema: enumsToReturn[`${typeSchema}.${enumType}`] !== undefined + ? enumsToReturn[`${typeSchema}.${enumType}`].schema + : undefined, + primaryKey: primaryKey, + notNull: viewResponse.is_nullable === 'NO', + generated: isGenerated + ? { as: generationExpression, type: 'stored' } + : undefined, + identity: isIdentity + ? { + type: identityGeneration, + name: identityName, + increment: stringFromDatabaseIdentityProperty(identityIncrement), + minValue: stringFromDatabaseIdentityProperty(identityMinimum), + maxValue: stringFromDatabaseIdentityProperty(identityMaximum), + startWith: stringFromDatabaseIdentityProperty(identityStart), + cache: sequencesToReturn[identityName]?.cache + ? sequencesToReturn[identityName]?.cache + : sequencesToReturn[`${viewSchema}.${identityName}`]?.cache + ? sequencesToReturn[`${viewSchema}.${identityName}`]?.cache + : undefined, + cycle: identityCycle, + schema: viewSchema, + } + : undefined, + }; + + if (identityName) { + // remove "" from sequence name + delete sequencesToReturn[ + `${viewSchema}.${ + identityName.startsWith('"') && identityName.endsWith('"') ? identityName.slice(1, -1) : identityName + }` + ]; + delete sequencesToReturn[identityName]; + } + + if (!isSerial && typeof defaultValue !== 'undefined') { + columnToReturn[columnName].default = defaultValue; + } + } + + const [viewInfo] = await db.query< + { + view_name: string; + schema_name: string; + definition: string; + tablespace_name: string | null; + options: string[] | null; + location: string | null; + } + >(` + SELECT + c.relname AS view_name, + n.nspname AS schema_name, + pg_get_viewdef(c.oid, true) AS definition, + ts.spcname AS tablespace_name, + c.reloptions AS options, + pg_tablespace_location(ts.oid) AS location +FROM + pg_class c +JOIN + pg_namespace n ON c.relnamespace = n.oid +LEFT JOIN + pg_tablespace ts ON c.reltablespace = ts.oid +WHERE + (c.relkind = 'm' OR c.relkind = 'v') + AND n.nspname = '${viewSchema}' + AND c.relname = '${viewName}';`); + + const resultWith: { [key: string]: string | boolean | number } = {}; + if (viewInfo.options) { + viewInfo.options.forEach((pair) => { + const splitted = pair.split('='); + const key = splitted[0]; + const value = splitted[1]; + + if (value === 'true') { + resultWith[key] = true; + } else if (value === 'false') { + resultWith[key] = false; + } else if (!isNaN(Number(value))) { + resultWith[key] = Number(value); + } else { + resultWith[key] = value; + } + }); + } + + const definition = viewInfo.definition.replace(/\s+/g, ' ').replace(';', '').trim(); + // { "check_option":"cascaded","security_barrier":true} -> // { "checkOption":"cascaded","securityBarrier":true} + const withOption = Object.values(resultWith).length + ? Object.fromEntries(Object.entries(resultWith).map(([key, value]) => [key.camelCase(), value])) + : undefined; + + const materialized = row.type === 'materialized_view'; + + views[`${viewSchema}.${viewName}`] = { + name: viewName, + schema: viewSchema, + columns: columnToReturn, + isExisting: false, + definition: definition, + materialized: materialized, + with: withOption, + tablespace: viewInfo.tablespace_name ?? undefined, + }; + } catch (e) { + rej(e); + return; + } + res(''); + }); + }); + + for await (const _ of allViews) { + } + if (progressCallback) { progressCallback('columns', columnsCount, 'done'); progressCallback('indexes', indexesCount, 'done'); @@ -1386,7 +1833,7 @@ export const fromDatabase = async ( enums: enumsToReturn, schemas: schemasObject, sequences: sequencesToReturn, - views: {}, + views: views, _meta: { schemas: {}, tables: {}, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 7bf30fc0a..ab50c135c 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -5,7 +5,6 @@ import { enum as enumType, literal, never, - number, object, record, string, @@ -72,7 +71,7 @@ import { preparePgAlterColumns, preparePgAlterViewAddWithOptionJson, preparePgAlterViewAlterSchemaJson, - preparePgAlterViewAlterWithOptionJson, + preparePgAlterViewAlterTablespaceOptionJson, preparePgAlterViewDropWithOptionJson, preparePgCreateIndexesJson, preparePgCreateTableJson, @@ -91,7 +90,7 @@ import { import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher } from './serializer/mysqlSchema'; -import { PgSchema, PgSchemaSquashed, sequenceSquashed, viewSquashed } from './serializer/pgSchema'; +import { mergedViewWithOption, PgSchema, PgSchemaSquashed, sequenceSquashed, View } from './serializer/pgSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; import { copy, prepareMigrationMeta } from './utils'; @@ -265,12 +264,13 @@ export const alteredTableScheme = object({ export const alteredViewSchema = object({ name: string(), schema: string(), - deletedWithOption: string().optional(), - addedWithOption: string().optional(), + deletedWithOption: mergedViewWithOption.optional(), + addedWithOption: mergedViewWithOption.optional(), alteredWith: object({ - __old: string(), - __new: string(), - }).strict().optional(), + addedWith: mergedViewWithOption.optional(), + deletedWith: mergedViewWithOption.optional(), + alterWith: mergedViewWithOption.optional(), + }).strict(), alteredSchema: object({ __old: string(), __new: string(), @@ -283,6 +283,10 @@ export const alteredViewSchema = object({ __old: boolean(), __new: boolean(), }).strict().optional(), + alteredTablespace: object({ + __old: string(), + __new: string(), + }).strict().optional(), }).strict(); export const diffResultScheme = object({ @@ -307,7 +311,6 @@ export type AlteredColumn = TypeOf; export type Enum = TypeOf; export type Sequence = TypeOf; export type Table = TypeOf; -export type ViewSquashed = TypeOf; export type AlteredTable = TypeOf; export type DiffResult = TypeOf; export type DiffResultMysql = TypeOf; @@ -427,8 +430,8 @@ export const applyPgSnapshotsDiff = async ( input: ColumnsResolverInput, ) => Promise>, viewsResolver: ( - input: ResolverInput, - ) => Promise>, + input: ResolverInput, + ) => Promise>, prevFull: PgSchema, curFull: PgSchema, action?: 'push' | undefined, @@ -765,6 +768,7 @@ export const applyPgSnapshotsDiff = async ( created: createdViews, deleted: deletedViews, renamed: renamedViews, + moved: movedViews, } = await viewsResolver({ created: viewsDiff.added, deleted: viewsDiff.deleted, @@ -1145,63 +1149,132 @@ export const applyPgSnapshotsDiff = async ( createViews.push( ...createdViews.filter((it) => !it.isExisting).map((it) => { - return preparePgCreateViewJson(it.name, it.schema, it.definition!, it.with); + return preparePgCreateViewJson( + it.name, + it.schema, + it.definition!, + it.materialized, + it.withNoData, + it.with, + it.using, + it.tablespace, + ); }), ); dropViews.push( ...deletedViews.filter((it) => !it.isExisting).map((it) => { - return preparePgDropViewJson(it.name, it.schema); + return preparePgDropViewJson(it.name, it.schema, it.materialized); }), ); renameViews.push( ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { - return preparePgRenameViewJson(it.to.name, it.from.name, it.to.schema); + return preparePgRenameViewJson(it.to.name, it.from.name, it.to.schema, it.to.materialized); }), ); - const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[it.name].isExisting); + alterViews.push( + ...movedViews.filter((it) => !json2.views[`${it.schemaTo}.${it.name}`].isExisting).map((it) => { + return preparePgAlterViewAlterSchemaJson( + it.schemaTo, + it.schemaFrom, + it.name, + json2.views[`${it.schemaTo}.${it.name}`].materialized, + ); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[`${it.schema}.${it.name}`].isExisting); + for (const alteredView of alteredViews) { - if (alteredView.alteredExisting || alteredView.alteredDefinition) { - dropViews.push(preparePgDropViewJson(alteredView.name, alteredView.schema)); + const viewKey = `${alteredView.schema}.${alteredView.name}`; + + const { materialized, with: withOption, definition, withNoData, using, tablespace } = json2.views[viewKey]; + + if (alteredView.alteredExisting || (alteredView.alteredDefinition && action !== 'push')) { + dropViews.push(preparePgDropViewJson(alteredView.name, alteredView.schema, materialized)); createViews.push( preparePgCreateViewJson( alteredView.name, alteredView.schema, - json2.views[alteredView.name].definition!, - json2.views[alteredView.name].with, + definition!, + materialized, + withNoData, + withOption, + using, + tablespace, ), ); continue; } - if (alteredView.deletedWithOption) { - alterViews.push( - preparePgAlterViewDropWithOptionJson(alteredView.name, alteredView.schema), - ); - } - if (alteredView.addedWithOption) { alterViews.push( - preparePgAlterViewAddWithOptionJson(alteredView.name, alteredView.schema, alteredView.addedWithOption), + preparePgAlterViewAddWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.addedWithOption, + ), ); } - if (alteredView.alteredSchema) { + if (alteredView.deletedWithOption) { alterViews.push( - preparePgAlterViewAlterSchemaJson( - alteredView.alteredSchema.__new, - alteredView.alteredSchema.__old, + preparePgAlterViewDropWithOptionJson( alteredView.name, + alteredView.schema, + materialized, + alteredView.deletedWithOption, ), ); } if (alteredView.alteredWith) { + if (alteredView.alteredWith.addedWith) { + alterViews.push( + preparePgAlterViewAddWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.alteredWith.addedWith, + ), + ); + } + + if (alteredView.alteredWith.deletedWith) { + alterViews.push( + preparePgAlterViewDropWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.alteredWith.deletedWith, + ), + ); + } + + if (alteredView.alteredWith.alterWith) { + alterViews.push( + preparePgAlterViewAddWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.alteredWith.alterWith, + ), + ); + } + } + + if (alteredView.alteredTablespace) { alterViews.push( - preparePgAlterViewAlterWithOptionJson(alteredView.name, alteredView.schema, alteredView.alteredWith.__new), + preparePgAlterViewAlterTablespaceOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.alteredTablespace.__new, + ), ); } } diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 4fafd1ede..054a0c51e 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -1,5 +1,4 @@ import { BREAKPOINT } from './cli/commands/migrate'; -import { Driver } from './cli/validations/common'; import { JsonAddColumnStatement, JsonAddValueToEnumStatement, @@ -28,7 +27,7 @@ import { JsonAlterTableSetSchema, JsonAlterViewAddWithOptionStatement, JsonAlterViewAlterSchemaStatement, - JsonAlterViewAlterWithOptionStatement, + JsonAlterViewAlterTablespaceStatement, JsonAlterViewDropWithOptionStatement, JsonCreateCompositePK, JsonCreateEnumStatement, @@ -409,15 +408,36 @@ class PgCreateViewConvertor extends Convertor { } convert(st: JsonCreateViewStatement) { - const { definition, name: viewName, schema, with: withClause } = st; + const { definition, name: viewName, schema, with: withOption, materialized, withNoData, tablespace, using } = st; const name = schema ? `"${schema}"."${viewName}"` : `"${viewName}"`; - let statement = `CREATE VIEW ${name}`; - statement += withClause - ? ` WITH (check_option = ${withClause.checkOption}, security_barrier = ${withClause.securityBarrier}, security_invoker = ${withClause.securityInvoker})` - : ''; - statement += ` AS (${definition});`; + let statement = materialized ? `CREATE MATERIALIZED VIEW ${name}` : `CREATE VIEW ${name}`; + + if (using) statement += ` USING "${using}"`; + + const options: string[] = []; + if (withOption) { + statement += ` WITH (`; + + Object.entries(withOption).forEach(([key, value]) => { + if (typeof value === 'undefined') return; + + options.push(`${key.snake_case()} = ${value}`); + }); + + statement += options.join(', '); + + statement += `)`; + } + + if (tablespace) statement += ` TABLESPACE ${tablespace}`; + + statement += ` AS (${definition})`; + + if (withNoData) statement += ` WITH NO DATA`; + + statement += `;`; return statement; } @@ -429,13 +449,11 @@ class PgDropViewConvertor extends Convertor { } convert(st: JsonDropViewStatement) { - const { name: viewName, schema } = st; + const { name: viewName, schema, materialized } = st; const name = schema ? `"${schema}"."${viewName}"` : `"${viewName}"`; - const statement = `DROP VIEW ${name};`; - - return statement; + return `DROP${materialized ? ' MATERIALIZED' : ''} VIEW ${name};`; } } @@ -445,14 +463,11 @@ class PgRenameViewConvertor extends Convertor { } convert(st: JsonRenameViewStatement) { - const { nameFrom: from, nameTo: to, schema } = st; + const { nameFrom: from, nameTo: to, schema, materialized } = st; - const nameFrom = schema ? `"${schema}"."${from}"` : `"${from}"`; - const nameTo = schema ? `"${schema}"."${to}"` : `"${to}"`; + const nameFrom = `"${schema}"."${from}"`; - const statement = `ALTER VIEW ${nameFrom} RENAME TO ${nameTo};`; - - return statement; + return `ALTER${materialized ? ' MATERIALIZED' : ''} VIEW ${nameFrom} RENAME TO "${to}";`; } } @@ -462,53 +477,73 @@ class PgAlterViewSchemaConvertor extends Convertor { } convert(st: JsonAlterViewAlterSchemaStatement) { - const { fromSchema, toSchema, name } = st; + const { fromSchema, toSchema, name, materialized } = st; - const statement = `ALTER VIEW "${fromSchema}"."${name}" SET SCHEMA "${toSchema}";`; + const statement = `ALTER${ + materialized ? ' MATERIALIZED' : '' + } VIEW "${fromSchema}"."${name}" SET SCHEMA "${toSchema}";`; return statement; } } -class PgAlterViewAlterWithOptionConvertor extends Convertor { +class PgAlterViewAddWithOptionConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_view_alter_with_option' && dialect === 'postgresql'; + return statement.type === 'alter_view_add_with_option' && dialect === 'postgresql'; } - convert(st: JsonAlterViewAlterWithOptionStatement) { - const { schema, with: withOption, name } = st; + convert(st: JsonAlterViewAddWithOptionStatement) { + const { schema, with: withOption, name, materialized } = st; + + let statement = `ALTER${materialized ? ' MATERIALIZED' : ''} VIEW "${schema}"."${name}" SET (`; + + const options: string[] = []; + + Object.entries(withOption).forEach(([key, value]) => { + options.push(`${key.snake_case()} = ${value}`); + }); + + statement += options.join(', '); - const statement = - `ALTER VIEW "${schema}"."${name}" SET (check_option = ${withOption.checkOption}, security_barrier = ${withOption.securityBarrier}, security_invoker = ${withOption.securityInvoker});`; + statement += `);`; return statement; } } -class PgAlterViewAddWithOptionConvertor extends Convertor { +class PgAlterViewDropWithOptionConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_view_add_with_option' && dialect === 'postgresql'; + return statement.type === 'alter_view_drop_with_option' && dialect === 'postgresql'; } - convert(st: JsonAlterViewAddWithOptionStatement) { - const { schema, with: withOption, name } = st; + convert(st: JsonAlterViewDropWithOptionStatement) { + const { schema, name, materialized, with: withOptions } = st; + + let statement = `ALTER${materialized ? ' MATERIALIZED' : ''} VIEW "${schema}"."${name}" RESET (`; + + const options: string[] = []; + + Object.entries(withOptions).forEach(([key, value]) => { + options.push(`${key.snake_case()}`); + }); + + statement += options.join(', '); - const statement = - `ALTER VIEW "${schema}"."${name}" SET (check_option = ${withOption.checkOption}, security_barrier = ${withOption.securityBarrier}, security_invoker = ${withOption.securityInvoker});`; + statement += ');'; return statement; } } -class PgAlterViewDropWithOptionConvertor extends Convertor { +class PgAlterViewAlterTablespaceConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_view_drop_with_option' && dialect === 'postgresql'; + return statement.type === 'alter_view_alter_tablespace' && dialect === 'postgresql'; } - convert(st: JsonAlterViewDropWithOptionStatement) { - const { schema, name } = st; + convert(st: JsonAlterViewAlterTablespaceStatement) { + const { schema, name, toTablespace } = st; - const statement = `ALTER VIEW "${schema}"."${name}" RESET (check_option, security_barrier, security_invoker);`; + const statement = `ALTER MATERIALIZED VIEW "${schema}"."${name}" SET TABLESPACE ${toTablespace};`; return statement; } @@ -2608,9 +2643,9 @@ convertors.push(new PgCreateViewConvertor()); convertors.push(new PgDropViewConvertor()); convertors.push(new PgRenameViewConvertor()); convertors.push(new PgAlterViewSchemaConvertor()); -convertors.push(new PgAlterViewAlterWithOptionConvertor()); convertors.push(new PgAlterViewAddWithOptionConvertor()); convertors.push(new PgAlterViewDropWithOptionConvertor()); +convertors.push(new PgAlterViewAlterTablespaceConvertor()); convertors.push(new CreateTypeEnumConvertor()); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index e65c0f904..5415f3956 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -17,8 +17,10 @@ import { macaddr8, numeric, pgEnum, + pgMaterializedView, pgSchema, pgTable, + pgView, real, serial, smallint, @@ -29,9 +31,14 @@ import { uuid, varchar, } from 'drizzle-orm/pg-core'; +import fs from 'fs'; import { introspectPgToFile } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; +if (!fs.existsSync('tests/introspect/postgres')) { + fs.mkdirSync('tests/introspect/postgres'); +} + test('basic introspect test', async () => { const client = new PGlite(); @@ -405,3 +412,185 @@ test('introspect enum with similar name to native type', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('introspect view #1', async () => { + const client = new PGlite(); + + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = pgView('some_view').as((qb) => qb.select().from(users)); + const schema = { + view, + users, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-view', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect view #2', async () => { + const client = new PGlite(); + + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = pgView('some_view', { id: integer('asd') }).with({ checkOption: 'cascaded' }).as( + sql`SELECT * FROM ${users}`, + ); + const schema = { + view, + users, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-view-#2', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect view in other schema', async () => { + const client = new PGlite(); + + const newSchema = pgSchema('new_schema'); + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = newSchema.view('some_view', { id: integer('asd') }).with({ checkOption: 'cascaded' }).as( + sql`SELECT * FROM ${users}`, + ); + const schema = { + view, + users, + newSchema, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-view-in-other-schema', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect materialized view in other schema', async () => { + const client = new PGlite(); + + const newSchema = pgSchema('new_schema'); + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = newSchema.materializedView('some_view', { id: integer('asd') }).with({ autovacuumEnabled: true }).as( + sql`SELECT * FROM ${users}`, + ); + const schema = { + view, + users, + newSchema, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-view-in-other-schema', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect materialized view #1', async () => { + const client = new PGlite(); + + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = pgMaterializedView('some_view').using('heap').withNoData().as((qb) => qb.select().from(users)); + const schema = { + view, + users, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-materialized-view', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect view #2', async () => { + const client = new PGlite(); + + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = pgView('some_view', { id: integer('asd') }).with({ checkOption: 'cascaded' }).as( + sql`SELECT * FROM ${users}`, + ); + const schema = { + view, + users, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-view-#2', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect materialized view #2', async () => { + const client = new PGlite(); + + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = pgMaterializedView('some_view', { id: integer('asd') }).with({ autovacuumFreezeMinAge: 1 }).as( + sql`SELECT * FROM ${users}`, + ); + const schema = { + view, + users, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-materialized-view-#2', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/pg-views.test.ts b/drizzle-kit/tests/pg-views.test.ts index 76ef63bbf..984380187 100644 --- a/drizzle-kit/tests/pg-views.test.ts +++ b/drizzle-kit/tests/pg-views.test.ts @@ -1,619 +1,1671 @@ import { eq, sql } from 'drizzle-orm'; -import { integer, pgSchema, pgTable, pgView } from 'drizzle-orm/pg-core'; +import { integer, pgMaterializedView, pgSchema, pgTable, pgView } from 'drizzle-orm/pg-core'; +import { JsonAlterViewAlterTablespaceStatement } from 'src/jsonStatements'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; -test('create table and view #1', async () => { - const users = pgTable('users', { - id: integer('id').primaryKey().notNull(), - }); - const to = { - users: users, - view: pgView('some_view').as((qb) => qb.select().from(users)), - }; - - const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - - expect(statements.length).toBe(2); - expect(statements[0]).toStrictEqual({ - type: 'create_table', - tableName: 'users', - schema: '', - columns: [{ - name: 'id', - notNull: true, - primaryKey: true, - type: 'integer', - }], - compositePKs: [], - uniqueConstraints: [], - compositePkName: '', - }); - expect(statements[1]).toStrictEqual({ - type: 'create_view', - name: 'some_view', - definition: `select "id" from "users"`, - schema: 'public', - with: undefined, - }); - - expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( -\t"id" integer PRIMARY KEY NOT NULL -);\n`); - expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (select "id" from "users");`); -}); - -test('create table and view #2', async () => { - const users = pgTable('users', { - id: integer('id').primaryKey().notNull(), - }); - const to = { - users: users, - view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), - }; - - const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - - expect(statements.length).toBe(2); - expect(statements[0]).toStrictEqual({ - type: 'create_table', - tableName: 'users', - schema: '', - columns: [{ - name: 'id', - notNull: true, - primaryKey: true, - type: 'integer', - }], - compositePKs: [], - uniqueConstraints: [], - compositePkName: '', - }); - expect(statements[1]).toStrictEqual({ - type: 'create_view', - name: 'some_view', - definition: `SELECT * FROM "users"`, - schema: 'public', - with: undefined, - }); - - expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( -\t"id" integer PRIMARY KEY NOT NULL -);\n`); - expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (SELECT * FROM "users");`); -}); - -test('create table and view #3', async () => { - const users = pgTable('users', { - id: integer('id').primaryKey().notNull(), - }); - const to = { - users: users, - view1: pgView('some_view1', { id: integer('id') }).with({ - checkOption: 'local', - securityBarrier: false, - securityInvoker: true, - }).as(sql`SELECT * FROM ${users}`), - view2: pgView('some_view2').with({ - checkOption: 'cascaded', - securityBarrier: true, - securityInvoker: false, - }).as((qb) => qb.select().from(users)), - }; - - const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - - expect(statements.length).toBe(3); - expect(statements[0]).toStrictEqual({ - type: 'create_table', - tableName: 'users', - schema: '', - columns: [{ - name: 'id', - notNull: true, - primaryKey: true, - type: 'integer', - }], - compositePKs: [], - uniqueConstraints: [], - compositePkName: '', - }); - expect(statements[1]).toStrictEqual({ - type: 'create_view', - name: 'some_view1', - definition: `SELECT * FROM "users"`, - schema: 'public', - with: { - checkOption: 'local', - securityBarrier: false, - securityInvoker: true, - }, - }); - expect(statements[2]).toStrictEqual({ - type: 'create_view', - name: 'some_view2', - definition: `select "id" from "users"`, - schema: 'public', - with: { - checkOption: 'cascaded', - securityBarrier: true, - securityInvoker: false, - }, - }); - - expect(sqlStatements.length).toBe(3); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( -\t"id" integer PRIMARY KEY NOT NULL -);\n`); - expect(sqlStatements[1]).toBe( - `CREATE VIEW "public"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "users");`, - ); - expect(sqlStatements[2]).toBe( - `CREATE VIEW "public"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "users");`, - ); -}); - -test('create table and view #4', async () => { - const schema = pgSchema('new_schema'); - - const users = schema.table('users', { - id: integer('id').primaryKey().notNull(), - }); - const to = { - schema, - users: users, - view1: schema.view('some_view1', { id: integer('id') }).with({ - checkOption: 'local', - securityBarrier: false, - securityInvoker: true, - }).as(sql`SELECT * FROM ${users}`), - view2: schema.view('some_view2').with({ - checkOption: 'cascaded', - securityBarrier: true, - securityInvoker: false, - }).as((qb) => qb.select().from(users)), - }; - - const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - - expect(statements.length).toBe(4); - expect(statements[0]).toStrictEqual({ - type: 'create_schema', - name: 'new_schema', - }); - expect(statements[1]).toStrictEqual({ - type: 'create_table', - tableName: 'users', - schema: 'new_schema', - columns: [{ - name: 'id', - notNull: true, - primaryKey: true, - type: 'integer', - }], - compositePKs: [], - uniqueConstraints: [], - compositePkName: '', - }); - expect(statements[2]).toStrictEqual({ - type: 'create_view', - name: 'some_view1', - definition: `SELECT * FROM "new_schema"."users"`, - schema: 'new_schema', - with: { - checkOption: 'local', - securityBarrier: false, - securityInvoker: true, - }, - }); - expect(statements[3]).toStrictEqual({ - type: 'create_view', - name: 'some_view2', - definition: `select "id" from "new_schema"."users"`, - schema: 'new_schema', - with: { - checkOption: 'cascaded', - securityBarrier: true, - securityInvoker: false, - }, - }); - - expect(sqlStatements.length).toBe(4); - expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); - expect(sqlStatements[1]).toBe(`CREATE TABLE IF NOT EXISTS "new_schema"."users" ( -\t"id" integer PRIMARY KEY NOT NULL -);\n`); - expect(sqlStatements[2]).toBe( - `CREATE VIEW "new_schema"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "new_schema"."users");`, - ); - expect(sqlStatements[3]).toBe( - `CREATE VIEW "new_schema"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "new_schema"."users");`, - ); -}); - -test('create table and view #5', async () => { - const users = pgTable('users', { - id: integer('id').primaryKey().notNull(), - }); - const to = { - users: users, - view1: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), - view2: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), - }; - - await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); -}); - -test('drop view #1', async () => { +// test('create table and view #1', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); +// const to = { +// users: users, +// view: pgView('some_view').as((qb) => qb.select().from(users)), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + +// expect(statements.length).toBe(2); +// expect(statements[0]).toStrictEqual({ +// type: 'create_table', +// tableName: 'users', +// schema: '', +// columns: [{ +// name: 'id', +// notNull: true, +// primaryKey: true, +// type: 'integer', +// }], +// compositePKs: [], +// uniqueConstraints: [], +// compositePkName: '', +// }); +// expect(statements[1]).toStrictEqual({ +// type: 'create_view', +// name: 'some_view', +// definition: `select "id" from "users"`, +// schema: 'public', +// with: undefined, +// materialized: false, +// tablespace: undefined, +// using: undefined, +// withNoData: false, +// }); + +// expect(sqlStatements.length).toBe(2); +// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +// \t"id" integer PRIMARY KEY NOT NULL +// );\n`); +// expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (select "id" from "users");`); +// }); + +// test('create table and view #2', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); +// const to = { +// users: users, +// view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + +// expect(statements.length).toBe(2); +// expect(statements[0]).toStrictEqual({ +// type: 'create_table', +// tableName: 'users', +// schema: '', +// columns: [{ +// name: 'id', +// notNull: true, +// primaryKey: true, +// type: 'integer', +// }], +// compositePKs: [], +// uniqueConstraints: [], +// compositePkName: '', +// }); +// expect(statements[1]).toStrictEqual({ +// type: 'create_view', +// name: 'some_view', +// definition: `SELECT * FROM "users"`, +// schema: 'public', +// with: undefined, +// materialized: false, +// tablespace: undefined, +// using: undefined, +// withNoData: false, +// }); + +// expect(sqlStatements.length).toBe(2); +// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +// \t"id" integer PRIMARY KEY NOT NULL +// );\n`); +// expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (SELECT * FROM "users");`); +// }); + +// test('create table and view #3', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); +// const to = { +// users: users, +// view1: pgView('some_view1', { id: integer('id') }).with({ +// checkOption: 'local', +// securityBarrier: false, +// securityInvoker: true, +// }).as(sql`SELECT * FROM ${users}`), +// view2: pgView('some_view2').with({ +// checkOption: 'cascaded', +// securityBarrier: true, +// securityInvoker: false, +// }).as((qb) => qb.select().from(users)), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + +// expect(statements.length).toBe(3); +// expect(statements[0]).toStrictEqual({ +// type: 'create_table', +// tableName: 'users', +// schema: '', +// columns: [{ +// name: 'id', +// notNull: true, +// primaryKey: true, +// type: 'integer', +// }], +// compositePKs: [], +// uniqueConstraints: [], +// compositePkName: '', +// }); +// expect(statements[1]).toStrictEqual({ +// type: 'create_view', +// name: 'some_view1', +// definition: `SELECT * FROM "users"`, +// schema: 'public', +// with: { +// checkOption: 'local', +// securityBarrier: false, +// securityInvoker: true, +// }, +// materialized: false, +// tablespace: undefined, +// using: undefined, +// withNoData: false, +// }); +// expect(statements[2]).toStrictEqual({ +// type: 'create_view', +// name: 'some_view2', +// definition: `select "id" from "users"`, +// schema: 'public', +// with: { +// checkOption: 'cascaded', +// securityBarrier: true, +// securityInvoker: false, +// }, +// materialized: false, +// tablespace: undefined, +// using: undefined, +// withNoData: false, +// }); + +// expect(sqlStatements.length).toBe(3); +// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +// \t"id" integer PRIMARY KEY NOT NULL +// );\n`); +// expect(sqlStatements[1]).toBe( +// `CREATE VIEW "public"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "users");`, +// ); +// expect(sqlStatements[2]).toBe( +// `CREATE VIEW "public"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "users");`, +// ); +// }); + +// test('create table and view #4', async () => { +// const schema = pgSchema('new_schema'); + +// const users = schema.table('users', { +// id: integer('id').primaryKey().notNull(), +// }); +// const to = { +// schema, +// users: users, +// view1: schema.view('some_view1', { id: integer('id') }).with({ +// checkOption: 'local', +// securityBarrier: false, +// securityInvoker: true, +// }).as(sql`SELECT * FROM ${users}`), +// view2: schema.view('some_view2').with({ +// checkOption: 'cascaded', +// securityBarrier: true, +// securityInvoker: false, +// }).as((qb) => qb.select().from(users)), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + +// expect(statements.length).toBe(4); +// expect(statements[0]).toStrictEqual({ +// type: 'create_schema', +// name: 'new_schema', +// }); +// expect(statements[1]).toStrictEqual({ +// type: 'create_table', +// tableName: 'users', +// schema: 'new_schema', +// columns: [{ +// name: 'id', +// notNull: true, +// primaryKey: true, +// type: 'integer', +// }], +// compositePKs: [], +// uniqueConstraints: [], +// compositePkName: '', +// }); +// expect(statements[2]).toStrictEqual({ +// type: 'create_view', +// name: 'some_view1', +// definition: `SELECT * FROM "new_schema"."users"`, +// schema: 'new_schema', +// with: { +// checkOption: 'local', +// securityBarrier: false, +// securityInvoker: true, +// }, +// materialized: false, +// tablespace: undefined, +// using: undefined, +// withNoData: false, +// }); +// expect(statements[3]).toStrictEqual({ +// type: 'create_view', +// name: 'some_view2', +// definition: `select "id" from "new_schema"."users"`, +// schema: 'new_schema', +// with: { +// checkOption: 'cascaded', +// securityBarrier: true, +// securityInvoker: false, +// }, +// materialized: false, +// tablespace: undefined, +// using: undefined, +// withNoData: false, +// }); + +// expect(sqlStatements.length).toBe(4); +// expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); +// expect(sqlStatements[1]).toBe(`CREATE TABLE IF NOT EXISTS "new_schema"."users" ( +// \t"id" integer PRIMARY KEY NOT NULL +// );\n`); +// expect(sqlStatements[2]).toBe( +// `CREATE VIEW "new_schema"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "new_schema"."users");`, +// ); +// expect(sqlStatements[3]).toBe( +// `CREATE VIEW "new_schema"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "new_schema"."users");`, +// ); +// }); + +// test('create table and view #5', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); +// const to = { +// users: users, +// view1: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), +// view2: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), +// }; + +// await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); +// }); + +// test('create table and view #6', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); +// const to = { +// users: users, +// view1: pgView('some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).as(sql`SELECT * FROM ${users}`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + +// expect(statements.length).toBe(2); +// expect(statements[0]).toStrictEqual({ +// columns: [ +// { +// name: 'id', +// notNull: true, +// primaryKey: true, +// type: 'integer', +// }, +// ], +// compositePKs: [], +// compositePkName: '', +// schema: '', +// tableName: 'users', +// type: 'create_table', +// uniqueConstraints: [], +// }); +// expect(statements[1]).toStrictEqual({ +// definition: 'SELECT * FROM "users"', +// name: 'some_view', +// schema: 'public', +// type: 'create_view', +// with: { +// checkOption: 'cascaded', +// }, +// materialized: false, +// tablespace: undefined, +// using: undefined, +// withNoData: false, +// }); + +// expect(sqlStatements.length).toBe(2); +// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +// \t"id" integer PRIMARY KEY NOT NULL +// );\n`); +// expect(sqlStatements[1]).toBe( +// `CREATE VIEW "public"."some_view" WITH (check_option = cascaded) AS (SELECT * FROM "users");`, +// ); +// }); + +// test('create view with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// }; + +// const to = { +// users: users, +// view1: pgView('some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('create table and materialized view #1', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); +// const to = { +// users: users, +// view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + +// expect(statements.length).toBe(2); +// expect(statements[0]).toStrictEqual({ +// type: 'create_table', +// tableName: 'users', +// schema: '', +// columns: [{ +// name: 'id', +// notNull: true, +// primaryKey: true, +// type: 'integer', +// }], +// compositePKs: [], +// uniqueConstraints: [], +// compositePkName: '', +// }); +// expect(statements[1]).toStrictEqual({ +// type: 'create_view', +// name: 'some_view', +// definition: `select "id" from "users"`, +// schema: 'public', +// with: undefined, +// materialized: true, +// tablespace: undefined, +// using: undefined, +// withNoData: false, +// }); + +// expect(sqlStatements.length).toBe(2); +// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +// \t"id" integer PRIMARY KEY NOT NULL +// );\n`); +// expect(sqlStatements[1]).toBe(`CREATE MATERIALIZED VIEW "public"."some_view" AS (select "id" from "users");`); +// }); + +// test('create table and materialized view #2', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); +// const to = { +// users: users, +// view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + +// expect(statements.length).toBe(2); +// expect(statements[0]).toStrictEqual({ +// type: 'create_table', +// tableName: 'users', +// schema: '', +// columns: [{ +// name: 'id', +// notNull: true, +// primaryKey: true, +// type: 'integer', +// }], +// compositePKs: [], +// uniqueConstraints: [], +// compositePkName: '', +// }); +// expect(statements[1]).toStrictEqual({ +// type: 'create_view', +// name: 'some_view', +// definition: `SELECT * FROM "users"`, +// schema: 'public', +// with: undefined, +// materialized: true, +// tablespace: undefined, +// using: undefined, +// withNoData: false, +// }); + +// expect(sqlStatements.length).toBe(2); +// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +// \t"id" integer PRIMARY KEY NOT NULL +// );\n`); +// expect(sqlStatements[1]).toBe(`CREATE MATERIALIZED VIEW "public"."some_view" AS (SELECT * FROM "users");`); +// }); + +// test('create table and materialized view #3', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); +// const to = { +// users: users, +// view1: pgMaterializedView('some_view1', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), +// view2: pgMaterializedView('some_view2').tablespace('some_tablespace').using('heap').withNoData().with({ +// autovacuumEnabled: true, +// autovacuumFreezeMaxAge: 1, +// autovacuumFreezeMinAge: 1, +// autovacuumFreezeTableAge: 1, +// autovacuumMultixactFreezeMaxAge: 1, +// autovacuumMultixactFreezeMinAge: 1, +// autovacuumMultixactFreezeTableAge: 1, +// autovacuumVacuumCostDelay: 1, +// autovacuumVacuumCostLimit: 1, +// autovacuumVacuumScaleFactor: 1, +// autovacuumVacuumThreshold: 1, +// fillfactor: 1, +// logAutovacuumMinDuration: 1, +// parallelWorkers: 1, +// toastTupleTarget: 1, +// userCatalogTable: true, +// vacuumIndexCleanup: 'off', +// vacuumTruncate: false, +// }).as((qb) => qb.select().from(users)), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + +// expect(statements.length).toBe(3); +// expect(statements[0]).toStrictEqual({ +// type: 'create_table', +// tableName: 'users', +// schema: '', +// columns: [{ +// name: 'id', +// notNull: true, +// primaryKey: true, +// type: 'integer', +// }], +// compositePKs: [], +// uniqueConstraints: [], +// compositePkName: '', +// }); +// expect(statements[1]).toStrictEqual({ +// type: 'create_view', +// name: 'some_view1', +// definition: `SELECT * FROM "users"`, +// schema: 'public', +// with: undefined, +// materialized: true, +// withNoData: false, +// using: undefined, +// tablespace: undefined, +// }); +// expect(statements[2]).toStrictEqual({ +// type: 'create_view', +// name: 'some_view2', +// definition: `select "id" from "users"`, +// schema: 'public', +// with: { +// autovacuumEnabled: true, +// autovacuumFreezeMaxAge: 1, +// autovacuumFreezeMinAge: 1, +// autovacuumFreezeTableAge: 1, +// autovacuumMultixactFreezeMaxAge: 1, +// autovacuumMultixactFreezeMinAge: 1, +// autovacuumMultixactFreezeTableAge: 1, +// autovacuumVacuumCostDelay: 1, +// autovacuumVacuumCostLimit: 1, +// autovacuumVacuumScaleFactor: 1, +// autovacuumVacuumThreshold: 1, +// fillfactor: 1, +// logAutovacuumMinDuration: 1, +// parallelWorkers: 1, +// toastTupleTarget: 1, +// userCatalogTable: true, +// vacuumIndexCleanup: 'off', +// vacuumTruncate: false, +// }, +// materialized: true, +// tablespace: 'some_tablespace', +// using: 'heap', +// withNoData: true, +// }); + +// expect(sqlStatements.length).toBe(3); +// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +// \t"id" integer PRIMARY KEY NOT NULL +// );\n`); +// expect(sqlStatements[1]).toBe( +// `CREATE MATERIALIZED VIEW "public"."some_view1" AS (SELECT * FROM "users");`, +// ); +// expect(sqlStatements[2]).toBe( +// `CREATE MATERIALIZED VIEW "public"."some_view2" USING "heap" WITH (autovacuum_enabled = true, autovacuum_freeze_max_age = 1, autovacuum_freeze_min_age = 1, autovacuum_freeze_table_age = 1, autovacuum_multixact_freeze_max_age = 1, autovacuum_multixact_freeze_min_age = 1, autovacuum_multixact_freeze_table_age = 1, autovacuum_vacuum_cost_delay = 1, autovacuum_vacuum_cost_limit = 1, autovacuum_vacuum_scale_factor = 1, autovacuum_vacuum_threshold = 1, fillfactor = 1, log_autovacuum_min_duration = 1, parallel_workers = 1, toast_tuple_target = 1, user_catalog_table = true, vacuum_index_cleanup = off, vacuum_truncate = false) TABLESPACE some_tablespace AS (select "id" from "users") WITH NO DATA;`, +// ); +// }); + +// test('create table and materialized view #4', async () => { +// // same names +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); +// const to = { +// users: users, +// view1: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), +// view2: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), +// }; + +// await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); +// }); + +// test('create table and materialized view #5', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); +// const to = { +// users: users, +// view1: pgMaterializedView('some_view', { id: integer('id') }).with({ autovacuumFreezeMinAge: 14 }).as( +// sql`SELECT * FROM ${users}`, +// ), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + +// expect(statements.length).toBe(2); +// expect(statements[0]).toStrictEqual({ +// columns: [ +// { +// name: 'id', +// notNull: true, +// primaryKey: true, +// type: 'integer', +// }, +// ], +// compositePKs: [], +// compositePkName: '', +// schema: '', +// tableName: 'users', +// type: 'create_table', +// uniqueConstraints: [], +// }); +// expect(statements[1]).toEqual({ +// definition: 'SELECT * FROM "users"', +// name: 'some_view', +// schema: 'public', +// type: 'create_view', +// with: { +// autovacuumFreezeMinAge: 14, +// }, +// materialized: true, +// tablespace: undefined, +// using: undefined, +// withNoData: false, +// }); + +// expect(sqlStatements.length).toBe(2); +// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +// \t"id" integer PRIMARY KEY NOT NULL +// );\n`); +// expect(sqlStatements[1]).toBe( +// `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_freeze_min_age = 14) AS (SELECT * FROM "users");`, +// ); +// }); + +// test('create materialized view with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// }; + +// const to = { +// users: users, +// view1: pgMaterializedView('some_view', { id: integer('id') }).with({ autovacuumEnabled: true }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('drop view #1', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), +// }; + +// const to = { +// users: users, +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// type: 'drop_view', +// name: 'some_view', +// schema: 'public', +// materialized: false, +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe(`DROP VIEW "public"."some_view";`); +// }); + +// test('drop view with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgView('some_view', { id: integer('id') }).existing(), +// }; + +// const to = { +// users: users, +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('drop materialized view #1', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), +// }; + +// const to = { +// users: users, +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// type: 'drop_view', +// name: 'some_view', +// schema: 'public', +// materialized: true, +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."some_view";`); +// }); + +// test('drop materialized view with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).existing(), +// }; + +// const to = { +// users: users, +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('rename view #1', async () => { +// const from = { +// view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), +// }; + +// const to = { +// view: pgView('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// type: 'rename_view', +// nameFrom: 'some_view', +// nameTo: 'new_some_view', +// schema: 'public', +// materialized: false, +// }); +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe(`ALTER VIEW "public"."some_view" RENAME TO "new_some_view";`); +// }); + +// test('rename view with existing flag', async () => { +// const from = { +// view: pgView('some_view', { id: integer('id') }).existing(), +// }; + +// const to = { +// view: pgView('new_some_view', { id: integer('id') }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('rename materialized view #1', async () => { +// const from = { +// view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), +// }; + +// const to = { +// view: pgMaterializedView('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// type: 'rename_view', +// nameFrom: 'some_view', +// nameTo: 'new_some_view', +// schema: 'public', +// materialized: true, +// }); +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe(`ALTER MATERIALIZED VIEW "public"."some_view" RENAME TO "new_some_view";`); +// }); + +// test('rename materialized view with existing flag', async () => { +// const from = { +// view: pgMaterializedView('some_view', { id: integer('id') }).existing(), +// }; + +// const to = { +// view: pgMaterializedView('new_some_view', { id: integer('id') }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('view alter schema', async () => { +// const schema = pgSchema('new_schema'); + +// const from = { +// view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), +// }; + +// const to = { +// schema, +// view: schema.view('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + +// expect(statements.length).toBe(2); +// expect(statements[0]).toStrictEqual({ +// type: 'create_schema', +// name: 'new_schema', +// }); +// expect(statements[1]).toStrictEqual({ +// type: 'alter_view_alter_schema', +// toSchema: 'new_schema', +// fromSchema: 'public', +// name: 'some_view', +// materialized: false, +// }); +// expect(sqlStatements.length).toBe(2); +// expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); +// expect(sqlStatements[1]).toBe(`ALTER VIEW "public"."some_view" SET SCHEMA "new_schema";`); +// }); + +// test('view alter schema with existing flag', async () => { +// const schema = pgSchema('new_schema'); + +// const from = { +// view: pgView('some_view', { id: integer('id') }).existing(), +// }; + +// const to = { +// schema, +// view: schema.view('some_view', { id: integer('id') }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// type: 'create_schema', +// name: 'new_schema', +// }); +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); +// }); + +// test('view alter schema for materialized', async () => { +// const schema = pgSchema('new_schema'); + +// const from = { +// view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), +// }; + +// const to = { +// schema, +// view: schema.materializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + +// expect(statements.length).toBe(2); +// expect(statements[0]).toStrictEqual({ +// type: 'create_schema', +// name: 'new_schema', +// }); +// expect(statements[1]).toStrictEqual({ +// type: 'alter_view_alter_schema', +// toSchema: 'new_schema', +// fromSchema: 'public', +// name: 'some_view', +// materialized: true, +// }); +// expect(sqlStatements.length).toBe(2); +// expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); +// expect(sqlStatements[1]).toBe(`ALTER MATERIALIZED VIEW "public"."some_view" SET SCHEMA "new_schema";`); +// }); + +// test('view alter schema for materialized with existing flag', async () => { +// const schema = pgSchema('new_schema'); + +// const from = { +// view: pgMaterializedView('some_view', { id: integer('id') }).existing(), +// }; + +// const to = { +// schema, +// view: schema.materializedView('some_view', { id: integer('id') }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// type: 'create_schema', +// name: 'new_schema', +// }); +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); +// }); + +// test('add with option to view #1', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgView('some_view').as((qb) => qb.select().from(users)), +// }; + +// const to = { +// users, +// view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true }).as((qb) => +// qb.select().from(users) +// ), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// name: 'some_view', +// schema: 'public', +// type: 'alter_view_add_with_option', +// with: { +// checkOption: 'cascaded', +// securityBarrier: true, +// }, +// materialized: false, +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe( +// `ALTER VIEW "public"."some_view" SET (check_option = cascaded, security_barrier = true);`, +// ); +// }); + +// test('add with option to view with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgView('some_view', {}).existing(), +// }; + +// const to = { +// users, +// view: pgView('some_view', {}).with({ checkOption: 'cascaded', securityBarrier: true }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('add with option to materialized view #1', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view').with({ autovacuumMultixactFreezeMaxAge: 3 }).as((qb) => +// qb.select().from(users) +// ), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// name: 'some_view', +// schema: 'public', +// type: 'alter_view_add_with_option', +// with: { +// autovacuumMultixactFreezeMaxAge: 3, +// }, +// materialized: true, +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe( +// `ALTER MATERIALIZED VIEW "public"."some_view" SET (autovacuum_multixact_freeze_max_age = 3);`, +// ); +// }); + +// test('add with option to materialized view with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view', {}).existing(), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view', {}).with({ autovacuumMultixactFreezeMaxAge: 3 }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('drop with option from view #1', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => +// qb.select().from(users) +// ), +// }; + +// const to = { +// users, +// view: pgView('some_view').as((qb) => qb.select().from(users)), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// name: 'some_view', +// schema: 'public', +// type: 'alter_view_drop_with_option', +// materialized: false, +// with: { +// checkOption: 'cascaded', +// securityBarrier: true, +// securityInvoker: true, +// }, +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe( +// `ALTER VIEW "public"."some_view" RESET (check_option, security_barrier, security_invoker);`, +// ); +// }); + +// test('drop with option from view with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgView('some_view', {}).with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }) +// .existing(), +// }; + +// const to = { +// users, +// view: pgView('some_view', {}).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('drop with option from materialized view #1', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, autovacuumFreezeMaxAge: 10 }).as((qb) => +// qb.select().from(users) +// ), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// name: 'some_view', +// schema: 'public', +// type: 'alter_view_drop_with_option', +// materialized: true, +// with: { +// autovacuumEnabled: true, +// autovacuumFreezeMaxAge: 10, +// }, +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe( +// `ALTER MATERIALIZED VIEW "public"."some_view" RESET (autovacuum_enabled, autovacuum_freeze_max_age);`, +// ); +// }); + +// test('drop with option from materialized view with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true, autovacuumFreezeMaxAge: 10 }).existing(), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view', {}).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('alter with option in view #1', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgView('some_view').with({ securityBarrier: true, securityInvoker: true }).as((qb) => +// qb.select().from(users) +// ), +// }; + +// const to = { +// users, +// view: pgView('some_view').with({ securityBarrier: true }).as((qb) => qb.select().from(users)), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// name: 'some_view', +// schema: 'public', +// type: 'alter_view_drop_with_option', +// with: { +// securityInvoker: true, +// }, +// materialized: false, +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe( +// `ALTER VIEW "public"."some_view" RESET (security_invoker);`, +// ); +// }); + +// test('alter with option in view with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgView('some_view', {}).with({ securityBarrier: true, securityInvoker: true }).existing(), +// }; + +// const to = { +// users, +// view: pgView('some_view', {}).with({ securityBarrier: true }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('alter with option in materialized view #1', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, autovacuumVacuumScaleFactor: 1 }).as((qb) => +// qb.select().from(users) +// ), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view').with({ autovacuumEnabled: true }).as((qb) => qb.select().from(users)), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// name: 'some_view', +// schema: 'public', +// type: 'alter_view_drop_with_option', +// with: { +// autovacuumVacuumScaleFactor: 1, +// }, +// materialized: true, +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe( +// `ALTER MATERIALIZED VIEW "public"."some_view" RESET (autovacuum_vacuum_scale_factor);`, +// ); +// }); + +// test('alter with option in materialized view with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true, autovacuumVacuumScaleFactor: 1 }) +// .existing(), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('alter with option in view #2', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgView('some_view').with({ checkOption: 'local', securityBarrier: true, securityInvoker: true }).as((qb) => +// qb.select().from(users) +// ), +// }; + +// const to = { +// users, +// view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => +// qb.select().from(users) +// ), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// type: 'alter_view_add_with_option', +// name: 'some_view', +// schema: 'public', +// with: { +// checkOption: 'cascaded', +// }, +// materialized: false, +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe( +// `ALTER VIEW "public"."some_view" SET (check_option = cascaded);`, +// ); +// }); + +// test('alter with option in materialized view #2', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, fillfactor: 1 }).as((qb) => +// qb.select().from(users) +// ), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view').with({ autovacuumEnabled: false, fillfactor: 1 }).as((qb) => +// qb.select().from(users) +// ), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toStrictEqual({ +// type: 'alter_view_add_with_option', +// name: 'some_view', +// schema: 'public', +// with: { +// autovacuumEnabled: false, +// }, +// materialized: true, +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe( +// `ALTER MATERIALIZED VIEW "public"."some_view" SET (autovacuum_enabled = false);`, +// ); +// }); + +// test('alter view ".as" value', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgView('some_view', { id: integer('id') }).with({ +// checkOption: 'local', +// securityBarrier: true, +// securityInvoker: true, +// }).as(sql`SELECT '123'`), +// }; + +// const to = { +// users, +// view: pgView('some_view', { id: integer('id') }).with({ +// checkOption: 'local', +// securityBarrier: true, +// securityInvoker: true, +// }).as(sql`SELECT '1234'`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(2); +// expect(statements[0]).toStrictEqual( +// { +// name: 'some_view', +// schema: 'public', +// type: 'drop_view', +// materialized: false, +// }, +// ); +// expect(statements[1]).toStrictEqual( +// { +// definition: "SELECT '1234'", +// name: 'some_view', +// schema: 'public', +// type: 'create_view', +// with: { +// checkOption: 'local', +// securityBarrier: true, +// securityInvoker: true, +// }, +// materialized: false, +// withNoData: false, +// tablespace: undefined, +// using: undefined, +// }, +// ); +// expect(sqlStatements.length).toBe(2); +// expect(sqlStatements[0]).toBe('DROP VIEW "public"."some_view";'); +// expect(sqlStatements[1]).toBe( +// `CREATE VIEW "public"."some_view" WITH (check_option = local, security_barrier = true, security_invoker = true) AS (SELECT '1234');`, +// ); +// }); + +// test('alter view ".as" value with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgView('some_view', { id: integer('id') }).with({ +// checkOption: 'local', +// securityBarrier: true, +// securityInvoker: true, +// }).existing(), +// }; + +// const to = { +// users, +// view: pgView('some_view', { id: integer('id') }).with({ +// checkOption: 'local', +// securityBarrier: true, +// securityInvoker: true, +// }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('alter materialized view ".as" value', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).with({ +// autovacuumVacuumCostLimit: 1, +// }).as(sql`SELECT '123'`), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).with({ +// autovacuumVacuumCostLimit: 1, +// }).as(sql`SELECT '1234'`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(2); +// expect(statements[0]).toStrictEqual( +// { +// name: 'some_view', +// schema: 'public', +// type: 'drop_view', +// materialized: true, +// }, +// ); +// expect(statements[1]).toStrictEqual( +// { +// definition: "SELECT '1234'", +// name: 'some_view', +// schema: 'public', +// type: 'create_view', +// with: { +// autovacuumVacuumCostLimit: 1, +// }, +// materialized: true, +// withNoData: false, +// tablespace: undefined, +// using: undefined, +// }, +// ); +// expect(sqlStatements.length).toBe(2); +// expect(sqlStatements[0]).toBe('DROP MATERIALIZED VIEW "public"."some_view";'); +// expect(sqlStatements[1]).toBe( +// `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_vacuum_cost_limit = 1) AS (SELECT '1234');`, +// ); +// }); + +// test('alter materialized view ".as" value with existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).with({ +// autovacuumVacuumCostLimit: 1, +// }).existing(), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).with({ +// autovacuumVacuumCostLimit: 1, +// }).existing(), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); +// }); + +// test('create view with dropped existing flag', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).with({ +// autovacuumVacuumCostLimit: 1, +// }).existing(), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).with({ +// autovacuumVacuumCostLimit: 1, +// }).as(sql`SELECT 'asd'`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(2); +// expect(statements[0]).toEqual({ +// type: 'drop_view', +// name: 'some_view', +// schema: 'public', +// materialized: true, +// }); +// expect(statements[1]).toEqual({ +// definition: "SELECT 'asd'", +// materialized: true, +// name: 'some_view', +// schema: 'public', +// tablespace: undefined, +// type: 'create_view', +// using: undefined, +// with: { +// autovacuumVacuumCostLimit: 1, +// }, +// withNoData: false, +// }); +// expect(sqlStatements.length).toBe(2); +// expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."some_view";`); +// expect(sqlStatements[1]).toBe( +// `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_vacuum_cost_limit = 1) AS (SELECT 'asd');`, +// ); +// }); + +// test('alter tablespace - materialize', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('some_tablespace').with({ +// autovacuumVacuumCostLimit: 1, +// }).as(sql`SELECT 'asd'`), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ +// autovacuumVacuumCostLimit: 1, +// }).as(sql`SELECT 'asd'`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toEqual({ +// type: 'alter_view_alter_tablespace', +// name: 'some_view', +// schema: 'public', +// materialized: true, +// toTablespace: 'new_tablespace', +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe( +// `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE new_tablespace;`, +// ); +// }); + +// test('set tablespace - materialize', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).with({ +// autovacuumVacuumCostLimit: 1, +// }).as(sql`SELECT 'asd'`), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ +// autovacuumVacuumCostLimit: 1, +// }).as(sql`SELECT 'asd'`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toEqual({ +// type: 'alter_view_alter_tablespace', +// name: 'some_view', +// schema: 'public', +// materialized: true, +// toTablespace: 'new_tablespace', +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe( +// `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE new_tablespace;`, +// ); +// }); + +// test('drop tablespace - materialize', async () => { +// const users = pgTable('users', { +// id: integer('id').primaryKey().notNull(), +// }); + +// const from = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ +// autovacuumVacuumCostLimit: 1, +// }).as(sql`SELECT 'asd'`), +// }; + +// const to = { +// users, +// view: pgMaterializedView('some_view', { id: integer('id') }).with({ +// autovacuumVacuumCostLimit: 1, +// }).as(sql`SELECT 'asd'`), +// }; + +// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + +// expect(statements.length).toBe(1); +// expect(statements[0]).toEqual({ +// type: 'alter_view_alter_tablespace', +// name: 'some_view', +// schema: 'public', +// materialized: true, +// toTablespace: 'pg_default', +// }); + +// expect(sqlStatements.length).toBe(1); +// expect(sqlStatements[0]).toBe( +// `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE pg_default;`, +// ); +// }); + +test('set existing', async () => { const users = pgTable('users', { id: integer('id').primaryKey().notNull(), }); const from = { users, - view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), }; const to = { - users: users, - }; - - const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'drop_view', - name: 'some_view', - schema: 'public', - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`DROP VIEW "public"."some_view";`); -}); - -test('drop view #2', async () => { - const users = pgTable('users', { - id: integer('id').primaryKey().notNull(), - }); - - const from = { users, - view: pgView('some_view').as((qb) => qb.select().from(users)), - }; - - const to = { - users: users, - }; - - const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'drop_view', - name: 'some_view', - schema: 'public', - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`DROP VIEW "public"."some_view";`); -}); - -test('drop view #3', async () => { - const users = pgTable('users', { - id: integer('id').primaryKey().notNull(), - }); - - const from = { - users, - view1: pgView('some_view1').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as(( - qb, - ) => qb.select().from(users)), - view2: pgView('some_view2', { id: integer('id') }).with({ - checkOption: 'cascaded', - securityBarrier: true, - securityInvoker: true, - }).as(sql`SELECT * FROM ${users}`), - }; - - const to = { - users: users, - }; - - const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - - expect(statements.length).toBe(2); - expect(statements[0]).toStrictEqual({ - type: 'drop_view', - name: 'some_view1', - schema: 'public', - }); - expect(statements[1]).toStrictEqual({ - type: 'drop_view', - name: 'some_view2', - schema: 'public', - }); - - expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`DROP VIEW "public"."some_view1";`); - expect(sqlStatements[1]).toBe(`DROP VIEW "public"."some_view2";`); -}); - -test('drop view #4', async () => { - const schema = pgSchema('new_schema'); - - const users = schema.table('users', { - id: integer('id').primaryKey().notNull(), - }); - - const from = { - users, - schema, - view1: schema.view('some_view1').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as( - (qb) => qb.select().from(users), - ), - view2: schema.view('some_view2', { id: integer('id') }).with({ - checkOption: 'cascaded', - securityBarrier: true, - securityInvoker: true, - }).as(sql`SELECT * FROM ${users}`), - }; - - const to = { - schema, - users: users, - }; - - const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - - expect(statements.length).toBe(2); - expect(statements[0]).toStrictEqual({ - type: 'drop_view', - name: 'some_view1', - schema: 'new_schema', - }); - expect(statements[1]).toStrictEqual({ - type: 'drop_view', - name: 'some_view2', - schema: 'new_schema', - }); - - expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`DROP VIEW "new_schema"."some_view1";`); - expect(sqlStatements[1]).toBe(`DROP VIEW "new_schema"."some_view2";`); -}); - -test('rename view #1', async () => { - const from = { - view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), - }; - - const to = { - view: pgView('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + view: pgMaterializedView('new_some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + autovacuumFreezeMinAge: 1, + }).withNoData().existing(), }; const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'rename_view', - nameFrom: 'some_view', - nameTo: 'new_some_view', - schema: 'public', - }); - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`ALTER VIEW "public"."some_view" RENAME TO "public"."new_some_view";`); -}); - -test('rename view #2', async () => { - const schema = pgSchema('new_schema'); - - const from = { - view: schema.view('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), - }; - - const to = { - view: schema.view('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), - }; - - const { statements, sqlStatements } = await diffTestSchemas(from, to, [ - 'new_schema.some_view->new_schema.new_some_view', - ]); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'rename_view', - nameFrom: 'some_view', - nameTo: 'new_some_view', - schema: 'new_schema', - }); - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`ALTER VIEW "new_schema"."some_view" RENAME TO "new_schema"."new_some_view";`); -}); - -test('view alter schema', async () => { - const schema = pgSchema('new_schema'); - - const from = { - view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), - }; - - const to = { - schema, - view: schema.view('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), - }; - - const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.new_some_view']); - - expect(statements.length).toBe(2); - expect(statements[0]).toStrictEqual({ - type: 'create_schema', - name: 'new_schema', - }); - expect(statements[1]).toStrictEqual({ - type: 'alter_view_alter_schema', - toSchema: 'new_schema', - fromSchema: 'public', - name: 'some_view', - }); - expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); - expect(sqlStatements[1]).toBe(`ALTER VIEW "public"."some_view" SET SCHEMA "new_schema";`); -}); - -test('add with option to view', async () => { - const users = pgTable('users', { - id: integer('id').primaryKey().notNull(), - }); - - const from = { - users, - view: pgView('some_view').as((qb) => qb.select().from(users)), - }; - - const to = { - users, - view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => - qb.select().from(users) - ), - }; - - const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - name: 'some_view', - schema: 'public', - type: 'alter_view_add_with_option', - with: { - checkOption: 'cascaded', - securityBarrier: true, - securityInvoker: true, - }, - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe( - `ALTER VIEW "public"."some_view" SET (check_option = cascaded, security_barrier = true, security_invoker = true);`, - ); -}); - -test('drop with option to view', async () => { - const users = pgTable('users', { - id: integer('id').primaryKey().notNull(), - }); - - const from = { - users, - view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => - qb.select().from(users) - ), - }; - - const to = { - users, - view: pgView('some_view').as((qb) => qb.select().from(users)), - }; - - const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - name: 'some_view', - schema: 'public', - type: 'alter_view_drop_with_option', - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe( - `ALTER VIEW "public"."some_view" RESET (check_option, security_barrier, security_invoker);`, - ); -}); - -test('alter with option in view', async () => { - const users = pgTable('users', { - id: integer('id').primaryKey().notNull(), - }); - - const from = { - users, - view: pgView('some_view').with({ checkOption: 'local', securityBarrier: true, securityInvoker: true }).as((qb) => - qb.select().from(users) - ), - }; - - const to = { - users, - view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => - qb.select().from(users) - ), - }; - - const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'alter_view_alter_with_option', - name: 'some_view', - schema: 'public', - with: { - checkOption: 'cascaded', - securityBarrier: true, - securityInvoker: true, - }, - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe( - `ALTER VIEW "public"."some_view" SET (check_option = cascaded, security_barrier = true, security_invoker = true);`, - ); -}); - -test('alter view', async () => { - const users = pgTable('users', { - id: integer('id').primaryKey().notNull(), - }); - - const from = { - users, - view: pgView('some_view').with({ checkOption: 'local', securityBarrier: true, securityInvoker: true }).as((qb) => - qb.select().from(users) - ), - }; - - const to = { - users, - view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => - qb.select().from(users).where(eq(users.id, 1)) - ), - }; - - const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - - expect(statements.length).toBe(2); - expect(statements[0]).toStrictEqual({ - type: 'drop_view', - name: 'some_view', - schema: 'public', - }); - expect(statements[1]).toStrictEqual({ - type: 'create_view', - name: 'some_view', - schema: 'public', - definition: `select "id" from "users" where "users"."id" = 1`, - with: { - checkOption: 'cascaded', - securityBarrier: true, - securityInvoker: true, - }, - }); + expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe( - `DROP VIEW "public"."some_view";`, - ); - expect(sqlStatements[1]).toBe( - `CREATE VIEW "public"."some_view" WITH (check_option = cascaded, security_barrier = true, security_invoker = true) AS (select "id" from "users" where "users"."id" = 1);`, - ); + expect(sqlStatements.length).toBe(0); }); diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index cb1a97122..951420c74 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -13,9 +13,11 @@ import { jsonb, numeric, pgEnum, + pgMaterializedView, pgSchema, pgSequence, pgTable, + pgView, real, serial, smallint, @@ -28,10 +30,10 @@ import { vector, } from 'drizzle-orm/pg-core'; import { drizzle } from 'drizzle-orm/pglite'; -import { SQL, sql } from 'drizzle-orm/sql'; +import { eq, SQL, sql } from 'drizzle-orm/sql'; import { pgSuggestions } from 'src/cli/commands/pgPushUtils'; import { diffTestSchemasPush } from 'tests/schemaDiffer'; -import { afterEach, expect, test } from 'vitest'; +import { expect, test } from 'vitest'; import { DialectSuite, run } from './common'; const pgSuite: DialectSuite = { @@ -1116,73 +1118,1140 @@ const pgSuite: DialectSuite = { }, }; -run(pgSuite); - -test('full sequence: no changes', async () => { +// run(pgSuite); + +// test('full sequence: no changes', async () => { +// const client = new PGlite(); + +// const schema1 = { +// seq: pgSequence('my_seq', { +// startWith: 100, +// maxValue: 10000, +// minValue: 100, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// }; + +// const schema2 = { +// seq: pgSequence('my_seq', { +// startWith: 100, +// maxValue: 10000, +// minValue: 100, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements.length).toBe(0); +// expect(sqlStatements.length).toBe(0); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('basic sequence: change fields', async () => { +// const client = new PGlite(); + +// const schema1 = { +// seq: pgSequence('my_seq', { +// startWith: 100, +// maxValue: 10000, +// minValue: 100, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// }; + +// const schema2 = { +// seq: pgSequence('my_seq', { +// startWith: 100, +// maxValue: 100000, +// minValue: 100, +// cycle: true, +// cache: 10, +// increment: 4, +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// type: 'alter_sequence', +// schema: 'public', +// name: 'my_seq', +// values: { +// minValue: '100', +// maxValue: '100000', +// increment: '4', +// startWith: '100', +// cache: '10', +// cycle: true, +// }, +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'ALTER SEQUENCE "public"."my_seq" INCREMENT BY 4 MINVALUE 100 MAXVALUE 100000 START WITH 100 CACHE 10 CYCLE;', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('basic sequence: change name', async () => { +// const client = new PGlite(); + +// const schema1 = { +// seq: pgSequence('my_seq', { +// startWith: 100, +// maxValue: 10000, +// minValue: 100, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// }; + +// const schema2 = { +// seq: pgSequence('my_seq2', { +// startWith: 100, +// maxValue: 10000, +// minValue: 100, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// ['public.my_seq->public.my_seq2'], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// nameFrom: 'my_seq', +// nameTo: 'my_seq2', +// schema: 'public', +// type: 'rename_sequence', +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('basic sequence: change name and fields', async () => { +// const client = new PGlite(); + +// const schema1 = { +// seq: pgSequence('my_seq', { +// startWith: 100, +// maxValue: 10000, +// minValue: 100, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// }; + +// const schema2 = { +// seq: pgSequence('my_seq2', { +// startWith: 100, +// maxValue: 10000, +// minValue: 100, +// cycle: true, +// cache: 10, +// increment: 4, +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// ['public.my_seq->public.my_seq2'], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// nameFrom: 'my_seq', +// nameTo: 'my_seq2', +// schema: 'public', +// type: 'rename_sequence', +// }, +// { +// name: 'my_seq2', +// schema: 'public', +// type: 'alter_sequence', +// values: { +// cache: '10', +// cycle: true, +// increment: '4', +// maxValue: '10000', +// minValue: '100', +// startWith: '100', +// }, +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";', +// 'ALTER SEQUENCE "public"."my_seq2" INCREMENT BY 4 MINVALUE 100 MAXVALUE 10000 START WITH 100 CACHE 10 CYCLE;', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// // identity push tests +// test('create table: identity always/by default - no params', async () => { +// const client = new PGlite(); + +// const schema1 = {}; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity(), +// id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity(), +// id2: smallint('id2').generatedByDefaultAsIdentity(), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// columns: [ +// { +// identity: 'users_id_seq;byDefault;1;2147483647;1;1;1;false', +// name: 'id', +// notNull: true, +// primaryKey: false, +// type: 'integer', +// }, +// { +// identity: 'users_id1_seq;byDefault;1;9223372036854775807;1;1;1;false', +// name: 'id1', +// notNull: true, +// primaryKey: false, +// type: 'bigint', +// }, +// { +// identity: 'users_id2_seq;byDefault;1;32767;1;1;1;false', +// name: 'id2', +// notNull: true, +// primaryKey: false, +// type: 'smallint', +// }, +// ], +// compositePKs: [], +// compositePkName: '', +// schema: '', +// tableName: 'users', +// type: 'create_table', +// uniqueConstraints: [], +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1)\n);\n', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('create table: identity always/by default - few params', async () => { +// const client = new PGlite(); + +// const schema1 = {}; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ increment: 4 }), +// id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity({ +// startWith: 120, +// maxValue: 17000, +// }), +// id2: smallint('id2').generatedByDefaultAsIdentity({ cycle: true }), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// columns: [ +// { +// identity: 'users_id_seq;byDefault;1;2147483647;4;1;1;false', +// name: 'id', +// notNull: true, +// primaryKey: false, +// type: 'integer', +// }, +// { +// identity: 'users_id1_seq;byDefault;1;17000;1;120;1;false', +// name: 'id1', +// notNull: true, +// primaryKey: false, +// type: 'bigint', +// }, +// { +// identity: 'users_id2_seq;byDefault;1;32767;1;1;1;true', +// name: 'id2', +// notNull: true, +// primaryKey: false, +// type: 'smallint', +// }, +// ], +// compositePKs: [], +// compositePkName: '', +// schema: '', +// tableName: 'users', +// type: 'create_table', +// uniqueConstraints: [], +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('create table: identity always/by default - all params', async () => { +// const client = new PGlite(); + +// const schema1 = {}; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ +// increment: 4, +// minValue: 100, +// }), +// id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity({ +// startWith: 120, +// maxValue: 17000, +// increment: 3, +// cycle: true, +// cache: 100, +// }), +// id2: smallint('id2').generatedByDefaultAsIdentity({ cycle: true }), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// columns: [ +// { +// identity: 'users_id_seq;byDefault;100;2147483647;4;100;1;false', +// name: 'id', +// notNull: true, +// primaryKey: false, +// type: 'integer', +// }, +// { +// identity: 'users_id1_seq;byDefault;1;17000;3;120;100;true', +// name: 'id1', +// notNull: true, +// primaryKey: false, +// type: 'bigint', +// }, +// { +// identity: 'users_id2_seq;byDefault;1;32767;1;1;1;true', +// name: 'id2', +// notNull: true, +// primaryKey: false, +// type: 'smallint', +// }, +// ], +// compositePKs: [], +// compositePkName: '', +// schema: '', +// tableName: 'users', +// type: 'create_table', +// uniqueConstraints: [], +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 100 MAXVALUE 2147483647 START WITH 100 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 3 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 100 CYCLE),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('no diff: identity always/by default - no params', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity(), +// id2: integer('id2').generatedAlwaysAsIdentity(), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity(), +// id2: integer('id2').generatedAlwaysAsIdentity(), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([]); +// expect(sqlStatements).toStrictEqual([]); +// }); + +// test('no diff: identity always/by default - few params', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ +// name: 'custom_name', +// }), +// id2: integer('id2').generatedAlwaysAsIdentity({ +// increment: 1, +// startWith: 3, +// }), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ +// name: 'custom_name', +// }), +// id2: integer('id2').generatedAlwaysAsIdentity({ +// increment: 1, +// startWith: 3, +// }), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([]); +// expect(sqlStatements).toStrictEqual([]); +// }); + +// test('no diff: identity always/by default - all params', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ +// name: 'custom_name', +// startWith: 10, +// minValue: 10, +// maxValue: 1000, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// id2: integer('id2').generatedAlwaysAsIdentity({ +// startWith: 10, +// minValue: 10, +// maxValue: 1000, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ +// name: 'custom_name', +// startWith: 10, +// minValue: 10, +// maxValue: 1000, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// id2: integer('id2').generatedAlwaysAsIdentity({ +// startWith: 10, +// minValue: 10, +// maxValue: 1000, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([]); +// expect(sqlStatements).toStrictEqual([]); +// }); + +// test('drop identity from a column - no params', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity(), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id'), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// columnName: 'id', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_drop_identity', +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('drop identity from a column - few params', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), +// id1: integer('id1').generatedByDefaultAsIdentity({ +// name: 'custom_name1', +// increment: 4, +// }), +// id2: integer('id2').generatedAlwaysAsIdentity({ +// name: 'custom_name2', +// increment: 4, +// }), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id'), +// id1: integer('id1'), +// id2: integer('id2'), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// columnName: 'id', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_drop_identity', +// }, +// { +// columnName: 'id1', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_drop_identity', +// }, +// { +// columnName: 'id2', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_drop_identity', +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, +// 'ALTER TABLE "users" ALTER COLUMN "id1" DROP IDENTITY;', +// 'ALTER TABLE "users" ALTER COLUMN "id2" DROP IDENTITY;', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('drop identity from a column - all params', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity(), +// id1: integer('id1').generatedByDefaultAsIdentity({ +// name: 'custom_name1', +// startWith: 10, +// minValue: 10, +// maxValue: 1000, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// id2: integer('id2').generatedAlwaysAsIdentity({ +// name: 'custom_name2', +// startWith: 10, +// minValue: 10, +// maxValue: 1000, +// cycle: true, +// cache: 10, +// increment: 2, +// }), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id'), +// id1: integer('id1'), +// id2: integer('id2'), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// columnName: 'id', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_drop_identity', +// }, +// { +// columnName: 'id1', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_drop_identity', +// }, +// { +// columnName: 'id2', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_drop_identity', +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, +// 'ALTER TABLE "users" ALTER COLUMN "id1" DROP IDENTITY;', +// 'ALTER TABLE "users" ALTER COLUMN "id2" DROP IDENTITY;', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('alter identity from a column - no params', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity(), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// columnName: 'id', +// identity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', +// oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;1;1;false', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_change_identity', +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'ALTER TABLE "users" ALTER COLUMN "id" SET START WITH 100;', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('alter identity from a column - few params', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ +// startWith: 100, +// increment: 4, +// maxValue: 10000, +// }), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// columnName: 'id', +// identity: 'users_id_seq;byDefault;1;10000;4;100;1;false', +// oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_change_identity', +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', +// 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('alter identity from a column - by default to always', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id').generatedAlwaysAsIdentity({ +// startWith: 100, +// increment: 4, +// maxValue: 10000, +// }), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// columnName: 'id', +// identity: 'users_id_seq;always;1;10000;4;100;1;false', +// oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_change_identity', +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'ALTER TABLE "users" ALTER COLUMN "id" SET GENERATED ALWAYS;', +// 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', +// 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('alter identity from a column - always to by default', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// id: integer('id').generatedAlwaysAsIdentity({ startWith: 100 }), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ +// startWith: 100, +// increment: 4, +// maxValue: 10000, +// cycle: true, +// cache: 100, +// }), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// columnName: 'id', +// identity: 'users_id_seq;byDefault;1;10000;4;100;100;true', +// oldIdentity: 'users_id_seq;always;1;2147483647;1;100;1;false', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_change_identity', +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'ALTER TABLE "users" ALTER COLUMN "id" SET GENERATED BY DEFAULT;', +// 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', +// 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', +// 'ALTER TABLE "users" ALTER COLUMN "id" SET CACHE 100;', +// 'ALTER TABLE "users" ALTER COLUMN "id" SET CYCLE;', +// ]); + +// for (const st of sqlStatements) { +// await client.query(st); +// } +// }); + +// test('add column with identity - few params', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// email: text('email'), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// email: text('email'), +// id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), +// id1: integer('id1').generatedAlwaysAsIdentity({ +// name: 'custom_name1', +// increment: 4, +// }), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// column: { +// identity: 'custom_name;byDefault;1;2147483647;1;1;1;false', +// name: 'id', +// notNull: true, +// primaryKey: false, +// type: 'integer', +// }, +// schema: '', +// tableName: 'users', +// type: 'alter_table_add_column', +// }, +// { +// column: { +// identity: 'custom_name1;always;1;2147483647;4;1;1;false', +// name: 'id1', +// notNull: true, +// primaryKey: false, +// type: 'integer', +// }, +// schema: '', +// tableName: 'users', +// type: 'alter_table_add_column', +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'ALTER TABLE "users" ADD COLUMN "id" integer NOT NULL GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_name" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', +// 'ALTER TABLE "users" ADD COLUMN "id1" integer NOT NULL GENERATED ALWAYS AS IDENTITY (sequence name "custom_name1" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', +// ]); + +// // for (const st of sqlStatements) { +// // await client.query(st); +// // } +// }); + +// test('add identity to column - few params', async () => { +// const client = new PGlite(); + +// const schema1 = { +// users: pgTable('users', { +// id: integer('id'), +// id1: integer('id1'), +// }), +// }; + +// const schema2 = { +// users: pgTable('users', { +// id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), +// id1: integer('id1').generatedAlwaysAsIdentity({ +// name: 'custom_name1', +// increment: 4, +// }), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// columnName: 'id', +// identity: 'custom_name;byDefault;1;2147483647;1;1;1;false', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_set_identity', +// }, +// { +// columnName: 'id1', +// identity: 'custom_name1;always;1;2147483647;4;1;1;false', +// schema: '', +// tableName: 'users', +// type: 'alter_table_alter_column_set_identity', +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'ALTER TABLE "users" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_name" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', +// 'ALTER TABLE "users" ALTER COLUMN "id1" ADD GENERATED ALWAYS AS IDENTITY (sequence name "custom_name1" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', +// ]); + +// // for (const st of sqlStatements) { +// // await client.query(st); +// // } +// }); + +// test('add array column - empty array default', async () => { +// const client = new PGlite(); + +// const schema1 = { +// test: pgTable('test', { +// id: serial('id').primaryKey(), +// }), +// }; +// const schema2 = { +// test: pgTable('test', { +// id: serial('id').primaryKey(), +// values: integer('values').array().default([]), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// type: 'alter_table_add_column', +// tableName: 'test', +// schema: '', +// column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'" }, +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{}\';', +// ]); +// }); + +// test('add array column - default', async () => { +// const client = new PGlite(); + +// const schema1 = { +// test: pgTable('test', { +// id: serial('id').primaryKey(), +// }), +// }; +// const schema2 = { +// test: pgTable('test', { +// id: serial('id').primaryKey(), +// values: integer('values').array().default([1, 2, 3]), +// }), +// }; + +// const { statements, sqlStatements } = await diffTestSchemasPush( +// client, +// schema1, +// schema2, +// [], +// false, +// ['public'], +// ); + +// expect(statements).toStrictEqual([ +// { +// type: 'alter_table_add_column', +// tableName: 'test', +// schema: '', +// column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'" }, +// }, +// ]); +// expect(sqlStatements).toStrictEqual([ +// 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\';', +// ]); +// }); + +test('create view', async () => { const client = new PGlite(); + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); const schema1 = { - seq: pgSequence('my_seq', { - startWith: 100, - maxValue: 10000, - minValue: 100, - cycle: true, - cache: 10, - increment: 2, - }), + test: table, }; const schema2 = { - seq: pgSequence('my_seq', { - startWith: 100, - maxValue: 10000, - minValue: 100, - cycle: true, - cache: 10, - increment: 2, - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); - - for (const st of sqlStatements) { - await client.query(st); - } -}); - -test('basic sequence: change fields', async () => { - const client = new PGlite(); - - const schema1 = { - seq: pgSequence('my_seq', { - startWith: 100, - maxValue: 10000, - minValue: 100, - cycle: true, - cache: 10, - increment: 2, - }), - }; - - const schema2 = { - seq: pgSequence('my_seq', { - startWith: 100, - maxValue: 100000, - minValue: 100, - cycle: true, - cache: 10, - increment: 4, - }), + test: table, + view: pgView('view').as((qb) => qb.selectDistinct().from(table)), }; const { statements, sqlStatements } = await diffTestSchemasPush( @@ -1196,156 +2265,77 @@ test('basic sequence: change fields', async () => { expect(statements).toStrictEqual([ { - type: 'alter_sequence', + definition: 'select distinct "id" from "test"', + name: 'view', schema: 'public', - name: 'my_seq', - values: { - minValue: '100', - maxValue: '100000', - increment: '4', - startWith: '100', - cache: '10', - cycle: true, - }, + type: 'create_view', + with: undefined, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, }, ]); expect(sqlStatements).toStrictEqual([ - 'ALTER SEQUENCE "public"."my_seq" INCREMENT BY 4 MINVALUE 100 MAXVALUE 100000 START WITH 100 CACHE 10 CYCLE;', + 'CREATE VIEW "public"."view" AS (select distinct "id" from "test");', ]); - - for (const st of sqlStatements) { - await client.query(st); - } }); -test('basic sequence: change name', async () => { +test('create materialized view', async () => { const client = new PGlite(); + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); const schema1 = { - seq: pgSequence('my_seq', { - startWith: 100, - maxValue: 10000, - minValue: 100, - cycle: true, - cache: 10, - increment: 2, - }), + test: table, }; const schema2 = { - seq: pgSequence('my_seq2', { - startWith: 100, - maxValue: 10000, - minValue: 100, - cycle: true, - cache: 10, - increment: 2, - }), + test: table, + view: pgMaterializedView('view').withNoData().using('heap').as((qb) => qb.selectDistinct().from(table)), }; const { statements, sqlStatements } = await diffTestSchemasPush( client, schema1, schema2, - ['public.my_seq->public.my_seq2'], + [], false, ['public'], ); expect(statements).toStrictEqual([ { - nameFrom: 'my_seq', - nameTo: 'my_seq2', + definition: 'select distinct "id" from "test"', + name: 'view', schema: 'public', - type: 'rename_sequence', + type: 'create_view', + with: undefined, + materialized: true, + tablespace: undefined, + using: 'heap', + withNoData: true, }, ]); expect(sqlStatements).toStrictEqual([ - 'ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";', + 'CREATE MATERIALIZED VIEW "public"."view" USING "heap" AS (select distinct "id" from "test") WITH NO DATA;', ]); - - for (const st of sqlStatements) { - await client.query(st); - } }); -test('basic sequence: change name and fields', async () => { +test('drop view', async () => { const client = new PGlite(); + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); const schema1 = { - seq: pgSequence('my_seq', { - startWith: 100, - maxValue: 10000, - minValue: 100, - cycle: true, - cache: 10, - increment: 2, - }), + test: table, + view: pgView('view').as((qb) => qb.selectDistinct().from(table)), }; const schema2 = { - seq: pgSequence('my_seq2', { - startWith: 100, - maxValue: 10000, - minValue: 100, - cycle: true, - cache: 10, - increment: 4, - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - ['public.my_seq->public.my_seq2'], - false, - ['public'], - ); - - expect(statements).toStrictEqual([ - { - nameFrom: 'my_seq', - nameTo: 'my_seq2', - schema: 'public', - type: 'rename_sequence', - }, - { - name: 'my_seq2', - schema: 'public', - type: 'alter_sequence', - values: { - cache: '10', - cycle: true, - increment: '4', - maxValue: '10000', - minValue: '100', - startWith: '100', - }, - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";', - 'ALTER SEQUENCE "public"."my_seq2" INCREMENT BY 4 MINVALUE 100 MAXVALUE 10000 START WITH 100 CACHE 10 CYCLE;', - ]); - - for (const st of sqlStatements) { - await client.query(st); - } -}); - -// identity push tests -test('create table: identity always/by default - no params', async () => { - const client = new PGlite(); - - const schema1 = {}; - - const schema2 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity(), - id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity(), - id2: smallint('id2').generatedByDefaultAsIdentity(), - }), + test: table, }; const { statements, sqlStatements } = await diffTestSchemasPush( @@ -1359,133 +2349,30 @@ test('create table: identity always/by default - no params', async () => { expect(statements).toStrictEqual([ { - columns: [ - { - identity: 'users_id_seq;byDefault;1;2147483647;1;1;1;false', - name: 'id', - notNull: true, - primaryKey: false, - type: 'integer', - }, - { - identity: 'users_id1_seq;byDefault;1;9223372036854775807;1;1;1;false', - name: 'id1', - notNull: true, - primaryKey: false, - type: 'bigint', - }, - { - identity: 'users_id2_seq;byDefault;1;32767;1;1;1;false', - name: 'id2', - notNull: true, - primaryKey: false, - type: 'smallint', - }, - ], - compositePKs: [], - compositePkName: '', - schema: '', - tableName: 'users', - type: 'create_table', - uniqueConstraints: [], + name: 'view', + schema: 'public', + type: 'drop_view', + materialized: false, }, ]); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1)\n);\n', + 'DROP VIEW "public"."view";', ]); - - for (const st of sqlStatements) { - await client.query(st); - } }); -test('create table: identity always/by default - few params', async () => { +test('drop materialized view', async () => { const client = new PGlite(); - const schema1 = {}; - - const schema2 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ increment: 4 }), - id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity({ - startWith: 120, - maxValue: 17000, - }), - id2: smallint('id2').generatedByDefaultAsIdentity({ cycle: true }), - }), + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgMaterializedView('view').as((qb) => qb.selectDistinct().from(table)), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); - - expect(statements).toStrictEqual([ - { - columns: [ - { - identity: 'users_id_seq;byDefault;1;2147483647;4;1;1;false', - name: 'id', - notNull: true, - primaryKey: false, - type: 'integer', - }, - { - identity: 'users_id1_seq;byDefault;1;17000;1;120;1;false', - name: 'id1', - notNull: true, - primaryKey: false, - type: 'bigint', - }, - { - identity: 'users_id2_seq;byDefault;1;32767;1;1;1;true', - name: 'id2', - notNull: true, - primaryKey: false, - type: 'smallint', - }, - ], - compositePKs: [], - compositePkName: '', - schema: '', - tableName: 'users', - type: 'create_table', - uniqueConstraints: [], - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', - ]); - - for (const st of sqlStatements) { - await client.query(st); - } -}); - -test('create table: identity always/by default - all params', async () => { - const client = new PGlite(); - - const schema1 = {}; - const schema2 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ - increment: 4, - minValue: 100, - }), - id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity({ - startWith: 120, - maxValue: 17000, - increment: 3, - cycle: true, - cache: 100, - }), - id2: smallint('id2').generatedByDefaultAsIdentity({ cycle: true }), - }), + test: table, }; const { statements, sqlStatements } = await diffTestSchemasPush( @@ -1499,61 +2386,31 @@ test('create table: identity always/by default - all params', async () => { expect(statements).toStrictEqual([ { - columns: [ - { - identity: 'users_id_seq;byDefault;100;2147483647;4;100;1;false', - name: 'id', - notNull: true, - primaryKey: false, - type: 'integer', - }, - { - identity: 'users_id1_seq;byDefault;1;17000;3;120;100;true', - name: 'id1', - notNull: true, - primaryKey: false, - type: 'bigint', - }, - { - identity: 'users_id2_seq;byDefault;1;32767;1;1;1;true', - name: 'id2', - notNull: true, - primaryKey: false, - type: 'smallint', - }, - ], - compositePKs: [], - compositePkName: '', - schema: '', - tableName: 'users', - type: 'create_table', - uniqueConstraints: [], + name: 'view', + schema: 'public', + type: 'drop_view', + materialized: true, }, ]); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 100 MAXVALUE 2147483647 START WITH 100 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 3 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 100 CYCLE),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', + 'DROP MATERIALIZED VIEW "public"."view";', ]); - - for (const st of sqlStatements) { - await client.query(st); - } }); -test('no diff: identity always/by default - no params', async () => { +test('push view with same name', async () => { const client = new PGlite(); + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); const schema1 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity(), - id2: integer('id2').generatedAlwaysAsIdentity(), - }), + test: table, + view: pgView('view').as((qb) => qb.selectDistinct().from(table)), }; const schema2 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity(), - id2: integer('id2').generatedAlwaysAsIdentity(), - }), + test: table, + view: pgView('view').as((qb) => qb.selectDistinct().from(table).where(eq(table.id, 1))), }; const { statements, sqlStatements } = await diffTestSchemasPush( @@ -1569,31 +2426,20 @@ test('no diff: identity always/by default - no params', async () => { expect(sqlStatements).toStrictEqual([]); }); -test('no diff: identity always/by default - few params', async () => { +test('push materialized view with same name', async () => { const client = new PGlite(); + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); const schema1 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ - name: 'custom_name', - }), - id2: integer('id2').generatedAlwaysAsIdentity({ - increment: 1, - startWith: 3, - }), - }), + test: table, + view: pgMaterializedView('view').as((qb) => qb.selectDistinct().from(table)), }; const schema2 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ - name: 'custom_name', - }), - id2: integer('id2').generatedAlwaysAsIdentity({ - increment: 1, - startWith: 3, - }), - }), + test: table, + view: pgMaterializedView('view').as((qb) => qb.selectDistinct().from(table).where(eq(table.id, 1))), }; const { statements, sqlStatements } = await diffTestSchemasPush( @@ -1609,205 +2455,22 @@ test('no diff: identity always/by default - few params', async () => { expect(sqlStatements).toStrictEqual([]); }); -test('no diff: identity always/by default - all params', async () => { - const client = new PGlite(); - - const schema1 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ - name: 'custom_name', - startWith: 10, - minValue: 10, - maxValue: 1000, - cycle: true, - cache: 10, - increment: 2, - }), - id2: integer('id2').generatedAlwaysAsIdentity({ - startWith: 10, - minValue: 10, - maxValue: 1000, - cycle: true, - cache: 10, - increment: 2, - }), - }), - }; - - const schema2 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ - name: 'custom_name', - startWith: 10, - minValue: 10, - maxValue: 1000, - cycle: true, - cache: 10, - increment: 2, - }), - id2: integer('id2').generatedAlwaysAsIdentity({ - startWith: 10, - minValue: 10, - maxValue: 1000, - cycle: true, - cache: 10, - increment: 2, - }), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); - - expect(statements).toStrictEqual([]); - expect(sqlStatements).toStrictEqual([]); -}); - -test('drop identity from a column - no params', async () => { - const client = new PGlite(); - - const schema1 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity(), - }), - }; - - const schema2 = { - users: pgTable('users', { - id: integer('id'), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); - - expect(statements).toStrictEqual([ - { - columnName: 'id', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_identity', - }, - ]); - expect(sqlStatements).toStrictEqual([ - `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, - ]); - - for (const st of sqlStatements) { - await client.query(st); - } -}); - -test('drop identity from a column - few params', async () => { - const client = new PGlite(); - - const schema1 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), - id1: integer('id1').generatedByDefaultAsIdentity({ - name: 'custom_name1', - increment: 4, - }), - id2: integer('id2').generatedAlwaysAsIdentity({ - name: 'custom_name2', - increment: 4, - }), - }), - }; - - const schema2 = { - users: pgTable('users', { - id: integer('id'), - id1: integer('id1'), - id2: integer('id2'), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); - - expect(statements).toStrictEqual([ - { - columnName: 'id', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_identity', - }, - { - columnName: 'id1', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_identity', - }, - { - columnName: 'id2', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_identity', - }, - ]); - expect(sqlStatements).toStrictEqual([ - `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, - 'ALTER TABLE "users" ALTER COLUMN "id1" DROP IDENTITY;', - 'ALTER TABLE "users" ALTER COLUMN "id2" DROP IDENTITY;', - ]); - - for (const st of sqlStatements) { - await client.query(st); - } -}); - -test('drop identity from a column - all params', async () => { +test('add with options for materialized view', async () => { const client = new PGlite(); + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); const schema1 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity(), - id1: integer('id1').generatedByDefaultAsIdentity({ - name: 'custom_name1', - startWith: 10, - minValue: 10, - maxValue: 1000, - cycle: true, - cache: 10, - increment: 2, - }), - id2: integer('id2').generatedAlwaysAsIdentity({ - name: 'custom_name2', - startWith: 10, - minValue: 10, - maxValue: 1000, - cycle: true, - cache: 10, - increment: 2, - }), - }), + test: table, + view: pgMaterializedView('view').as((qb) => qb.selectDistinct().from(table)), }; const schema2 = { - users: pgTable('users', { - id: integer('id'), - id1: integer('id1'), - id2: integer('id2'), - }), + test: table, + view: pgMaterializedView('view').with({ autovacuumFreezeTableAge: 1, autovacuumEnabled: false }).as((qb) => + qb.selectDistinct().from(table) + ), }; const { statements, sqlStatements } = await diffTestSchemasPush( @@ -1819,97 +2482,39 @@ test('drop identity from a column - all params', async () => { ['public'], ); - expect(statements).toStrictEqual([ - { - columnName: 'id', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_identity', + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'view', + schema: 'public', + type: 'alter_view_add_with_option', + with: { + autovacuumFreezeTableAge: 1, + autovacuumEnabled: false, }, - { - columnName: 'id1', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_identity', - }, - { - columnName: 'id2', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_identity', - }, - ]); - expect(sqlStatements).toStrictEqual([ - `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, - 'ALTER TABLE "users" ALTER COLUMN "id1" DROP IDENTITY;', - 'ALTER TABLE "users" ALTER COLUMN "id2" DROP IDENTITY;', - ]); - - for (const st of sqlStatements) { - await client.query(st); - } -}); - -test('alter identity from a column - no params', async () => { - const client = new PGlite(); - - const schema1 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity(), - }), - }; - - const schema2 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], + materialized: true, + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."view" SET (autovacuum_enabled = false, autovacuum_freeze_table_age = 1);`, ); - - expect(statements).toStrictEqual([ - { - columnName: 'id', - identity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', - oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;1;1;false', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_change_identity', - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "users" ALTER COLUMN "id" SET START WITH 100;', - ]); - - for (const st of sqlStatements) { - await client.query(st); - } }); -test('alter identity from a column - few params', async () => { +test('add with options to materialized', async () => { const client = new PGlite(); + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); const schema1 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), - }), + test: table, + view: pgMaterializedView('view').as((qb) => qb.selectDistinct().from(table)), }; const schema2 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ - startWith: 100, - increment: 4, - maxValue: 10000, - }), - }), + test: table, + view: pgMaterializedView('view').with({ autovacuumVacuumCostDelay: 100, vacuumTruncate: false }).as((qb) => + qb.selectDistinct().from(table) + ), }; const { statements, sqlStatements } = await diffTestSchemasPush( @@ -1921,94 +2526,37 @@ test('alter identity from a column - few params', async () => { ['public'], ); - expect(statements).toStrictEqual([ - { - columnName: 'id', - identity: 'users_id_seq;byDefault;1;10000;4;100;1;false', - oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_change_identity', + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'view', + schema: 'public', + type: 'alter_view_add_with_option', + with: { + autovacuumVacuumCostDelay: 100, + vacuumTruncate: false, }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', - 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', - ]); - - for (const st of sqlStatements) { - await client.query(st); - } -}); - -test('alter identity from a column - by default to always', async () => { - const client = new PGlite(); - - const schema1 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), - }), - }; - - const schema2 = { - users: pgTable('users', { - id: integer('id').generatedAlwaysAsIdentity({ - startWith: 100, - increment: 4, - maxValue: 10000, - }), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], + materialized: true, + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."view" SET (vacuum_truncate = false, autovacuum_vacuum_cost_delay = 100);`, ); - - expect(statements).toStrictEqual([ - { - columnName: 'id', - identity: 'users_id_seq;always;1;10000;4;100;1;false', - oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_change_identity', - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "users" ALTER COLUMN "id" SET GENERATED ALWAYS;', - 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', - 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', - ]); - - for (const st of sqlStatements) { - await client.query(st); - } }); -test('alter identity from a column - always to by default', async () => { +test('add with options to materialized with existing option', async () => { const client = new PGlite(); + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); const schema1 = { - users: pgTable('users', { - id: integer('id').generatedAlwaysAsIdentity({ startWith: 100 }), - }), + test: table, + view: pgMaterializedView('view', {}).existing(), }; const schema2 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ - startWith: 100, - increment: 4, - maxValue: 10000, - cycle: true, - cache: 100, - }), - }), + test: table, + view: pgMaterializedView('view', {}).with({ autovacuumVacuumCostDelay: 100, vacuumTruncate: false }).existing(), }; const { statements, sqlStatements } = await diffTestSchemasPush( @@ -2020,219 +2568,6 @@ test('alter identity from a column - always to by default', async () => { ['public'], ); - expect(statements).toStrictEqual([ - { - columnName: 'id', - identity: 'users_id_seq;byDefault;1;10000;4;100;100;true', - oldIdentity: 'users_id_seq;always;1;2147483647;1;100;1;false', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_change_identity', - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "users" ALTER COLUMN "id" SET GENERATED BY DEFAULT;', - 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', - 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', - 'ALTER TABLE "users" ALTER COLUMN "id" SET CACHE 100;', - 'ALTER TABLE "users" ALTER COLUMN "id" SET CYCLE;', - ]); - - for (const st of sqlStatements) { - await client.query(st); - } -}); - -test('add column with identity - few params', async () => { - const client = new PGlite(); - - const schema1 = { - users: pgTable('users', { - email: text('email'), - }), - }; - - const schema2 = { - users: pgTable('users', { - email: text('email'), - id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), - id1: integer('id1').generatedAlwaysAsIdentity({ - name: 'custom_name1', - increment: 4, - }), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); - - expect(statements).toStrictEqual([ - { - column: { - identity: 'custom_name;byDefault;1;2147483647;1;1;1;false', - name: 'id', - notNull: true, - primaryKey: false, - type: 'integer', - }, - schema: '', - tableName: 'users', - type: 'alter_table_add_column', - }, - { - column: { - identity: 'custom_name1;always;1;2147483647;4;1;1;false', - name: 'id1', - notNull: true, - primaryKey: false, - type: 'integer', - }, - schema: '', - tableName: 'users', - type: 'alter_table_add_column', - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "users" ADD COLUMN "id" integer NOT NULL GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_name" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', - 'ALTER TABLE "users" ADD COLUMN "id1" integer NOT NULL GENERATED ALWAYS AS IDENTITY (sequence name "custom_name1" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', - ]); - - // for (const st of sqlStatements) { - // await client.query(st); - // } -}); - -test('add identity to column - few params', async () => { - const client = new PGlite(); - - const schema1 = { - users: pgTable('users', { - id: integer('id'), - id1: integer('id1'), - }), - }; - - const schema2 = { - users: pgTable('users', { - id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), - id1: integer('id1').generatedAlwaysAsIdentity({ - name: 'custom_name1', - increment: 4, - }), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); - - expect(statements).toStrictEqual([ - { - columnName: 'id', - identity: 'custom_name;byDefault;1;2147483647;1;1;1;false', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_set_identity', - }, - { - columnName: 'id1', - identity: 'custom_name1;always;1;2147483647;4;1;1;false', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_set_identity', - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "users" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_name" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', - 'ALTER TABLE "users" ALTER COLUMN "id1" ADD GENERATED ALWAYS AS IDENTITY (sequence name "custom_name1" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', - ]); - - // for (const st of sqlStatements) { - // await client.query(st); - // } -}); - -test('add array column - empty array default', async () => { - const client = new PGlite(); - - const schema1 = { - test: pgTable('test', { - id: serial('id').primaryKey(), - }), - }; - const schema2 = { - test: pgTable('test', { - id: serial('id').primaryKey(), - values: integer('values').array().default([]), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); - - expect(statements).toStrictEqual([ - { - type: 'alter_table_add_column', - tableName: 'test', - schema: '', - column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'" }, - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{}\';', - ]); -}); - -test('add array column - default', async () => { - const client = new PGlite(); - - const schema1 = { - test: pgTable('test', { - id: serial('id').primaryKey(), - }), - }; - const schema2 = { - test: pgTable('test', { - id: serial('id').primaryKey(), - values: integer('values').array().default([1, 2, 3]), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); - - expect(statements).toStrictEqual([ - { - type: 'alter_table_add_column', - tableName: 'test', - schema: '', - column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'" }, - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\';', - ]); + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); }); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 24350204b..b7fff13a8 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -1,9 +1,21 @@ import { PGlite } from '@electric-sql/pglite'; import { Client } from '@libsql/client/.'; import { Database } from 'better-sqlite3'; +import { randomUUID } from 'crypto'; import { is } from 'drizzle-orm'; import { MySqlSchema, MySqlTable } from 'drizzle-orm/mysql-core'; -import { isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable, PgView } from 'drizzle-orm/pg-core'; +import { + isPgEnum, + isPgMaterializedView, + isPgSequence, + isPgView, + PgEnum, + PgMaterializedView, + PgSchema, + PgSequence, + PgTable, + PgView, +} from 'drizzle-orm/pg-core'; import { SQLiteTable } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; @@ -26,7 +38,7 @@ import { mysqlSchema, squashMysqlScheme } from 'src/serializer/mysqlSchema'; import { generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; import { fromDatabase as fromMySqlDatabase } from 'src/serializer/mysqlSerializer'; import { prepareFromPgImports } from 'src/serializer/pgImports'; -import { pgSchema, squashPgScheme } from 'src/serializer/pgSchema'; +import { pgSchema, squashPgScheme, View } from 'src/serializer/pgSchema'; import { fromDatabase, generatePgSnapshot } from 'src/serializer/pgSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; import { sqliteSchema, squashSqliteScheme } from 'src/serializer/sqliteSchema'; @@ -46,12 +58,11 @@ import { ResolverOutputWithMoved, Sequence, Table, - ViewSquashed, } from 'src/snapshotsDiffer'; export type PostgresSchema = Record< string, - PgTable | PgEnum | PgSchema | PgSequence | PgView + PgTable | PgEnum | PgSchema | PgSequence | PgView | PgMaterializedView >; export type MysqlSchema = Record | MySqlSchema>; export type SqliteSchema = Record>; @@ -409,8 +420,8 @@ async ( export const testViewsResolver = (renames: Set) => async ( - input: ResolverInput, -): Promise> => { + input: ResolverInput, +): Promise> => { try { if ( input.created.length === 0 @@ -429,10 +440,10 @@ async ( let deletedViews = [...input.deleted]; const result: { - created: ViewSquashed[]; + created: View[]; moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: ViewSquashed; to: ViewSquashed }[]; - deleted: ViewSquashed[]; + renamed: { from: View; to: View }[]; + deleted: View[]; } = { created: [], renamed: [], deleted: [], moved: [] }; for (let rename of renames) { @@ -516,11 +527,17 @@ export const diffTestSchemasPush = async ( const leftSequences = Object.values(right).filter((it) => isPgSequence(it)) as PgSequence[]; + const leftViews = Object.values(right).filter((it) => isPgView(it)) as PgView[]; + + const leftMaterializedViews = Object.values(right).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; + const serialized2 = generatePgSnapshot( leftTables, leftEnums, leftSchemas, leftSequences, + leftViews, + leftMaterializedViews, ); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; @@ -559,6 +576,7 @@ export const diffTestSchemasPush = async ( testSequencesResolver(renames), testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolver(renames), validatedPrev, validatedCur, 'push', @@ -573,6 +591,7 @@ export const diffTestSchemasPush = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, 'push', @@ -589,6 +608,7 @@ export const applyPgDiffs = async (sn: PostgresSchema) => { prevId: '0', tables: {}, enums: {}, + views: {}, schemas: {}, sequences: {}, _meta: { @@ -606,7 +626,11 @@ export const applyPgDiffs = async (sn: PostgresSchema) => { const sequences = Object.values(sn).filter((it) => isPgSequence(it)) as PgSequence[]; - const serialized1 = generatePgSnapshot(tables, enums, schemas, sequences); + const views = Object.values(sn).filter((it) => isPgView(it)) as PgView[]; + + const materializedViews = Object.values(sn).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; + + const serialized1 = generatePgSnapshot(tables, enums, schemas, sequences, views, materializedViews); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -631,16 +655,13 @@ export const applyPgDiffs = async (sn: PostgresSchema) => { testSequencesResolver(new Set()), testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolver(new Set()), validatedPrev, validatedCur, ); return { sqlStatements, statements }; }; -export function isPgView(obj: unknown): obj is PgView { - return is(obj, PgView); -} - export const diffTestSchemas = async ( left: PostgresSchema, right: PostgresSchema, @@ -667,12 +688,17 @@ export const diffTestSchemas = async ( const rightViews = Object.values(right).filter((it) => isPgView(it)) as PgView[]; + const leftMaterializedViews = Object.values(left).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; + + const rightMaterializedViews = Object.values(right).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; + const serialized1 = generatePgSnapshot( leftTables, leftEnums, leftSchemas, leftSequences, leftViews, + leftMaterializedViews, ); const serialized2 = generatePgSnapshot( rightTables, @@ -680,6 +706,7 @@ export const diffTestSchemas = async ( rightSchemas, rightSequences, rightViews, + rightMaterializedViews, ); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -1405,10 +1432,10 @@ export const introspectPgToFile = async ( const file = schemaToTypeScript(introspectedSchema, 'camel'); - fs.writeFileSync(`tests/introspect/${testName}.ts`, file.file); + fs.writeFileSync(`tests/introspect/postgres/${testName}.ts`, file.file); const response = await prepareFromPgImports([ - `tests/introspect/${testName}.ts`, + `tests/introspect/postgres/${testName}.ts`, ]); const afterFileImports = generatePgSnapshot( @@ -1416,6 +1443,8 @@ export const introspectPgToFile = async ( response.enums, response.schemas, response.sequences, + response.views, + response.matViews, ); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -1431,50 +1460,38 @@ export const introspectPgToFile = async ( const sn2AfterIm = squashPgScheme(sch2); const validatedCurAfterImport = pgSchema.parse(sch2); - const leftTables = Object.values(initSchema).filter((it) => is(it, PgTable)) as PgTable[]; + // save snapshot + fs.writeFileSync(`tests/introspect/postgres/${testName}.json`, JSON.stringify(validatedCurAfterImport)); - const leftSchemas = Object.values(initSchema).filter((it) => is(it, PgSchema)) as PgSchema[]; - - const leftEnums = Object.values(initSchema).filter((it) => isPgEnum(it)) as PgEnum[]; - - const leftSequences = Object.values(initSchema).filter((it) => isPgSequence(it)) as PgSequence[]; - - const initSnapshot = generatePgSnapshot( - leftTables, - leftEnums, - leftSchemas, - leftSequences, + const prevSnapshot = pgSchema.parse( + JSON.parse(fs.readFileSync(`tests/introspect/postgres/${testName}.json`).toString()), + ); + const { tables, enums, sequences, schemas: schemaImports, views, matViews } = await prepareFromPgImports( + [`tests/introspect/postgres/${testName}.ts`], ); - const { version: initV, dialect: initD, ...initRest } = initSnapshot; - - const initSch = { - version: '7', - dialect: 'postgresql', - id: '0', - prevId: '0', - ...initRest, - } as const; - - const initSn = squashPgScheme(initSch); - const validatedCur = pgSchema.parse(initSch); + const serialized = generatePgSnapshot(tables, enums, schemaImports, sequences, views, matViews, schemas); + const cur = { id: randomUUID(), ...serialized, prevId: prevSnapshot.id }; + const squashedCurr = squashPgScheme(cur); const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements, } = await applyPgSnapshotsDiff( sn2AfterIm, - initSn, + squashedCurr, testSchemasResolver(new Set()), testEnumsResolver(new Set()), testSequencesResolver(new Set()), testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolver(new Set()), validatedCurAfterImport, - validatedCur, + cur, ); - fs.rmSync(`tests/introspect/${testName}.ts`); + fs.rmSync(`tests/introspect/postgres/${testName}.ts`); + fs.rmSync(`tests/introspect/postgres/${testName}.json`); return { sqlStatements: afterFileSqlStatements, diff --git a/drizzle-orm/src/pg-core/view.ts b/drizzle-orm/src/pg-core/view.ts index 22c510dce..6dcc98736 100644 --- a/drizzle-orm/src/pg-core/view.ts +++ b/drizzle-orm/src/pg-core/view.ts @@ -1,10 +1,11 @@ import type { BuildColumns } from '~/column-builder.ts'; -import { entityKind } from '~/entity.ts'; +import { entityKind, is } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { ColumnsSelection, SQL } from '~/sql/sql.ts'; import { getTableColumns } from '~/utils.ts'; +import type { RequireAtLeastOne } from '~/utils.ts'; import type { PgColumn, PgColumnBuilderBase } from './columns/common.ts'; import { QueryBuilder } from './query-builders/query-builder.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; @@ -12,11 +13,11 @@ import { pgTable } from './table.ts'; import { PgViewBase } from './view-base.ts'; import { PgViewConfig } from './view-common.ts'; -export interface ViewWithConfig { +export type ViewWithConfig = RequireAtLeastOne<{ checkOption: 'local' | 'cascaded'; securityBarrier: boolean; securityInvoker: boolean; -} +}>; export class DefaultViewBuilderCore { static readonly [entityKind]: string = 'PgDefaultViewBuilderCore'; @@ -130,9 +131,26 @@ export class ManualViewBuilder< } } -export interface PgMaterializedViewWithConfig { - [Key: string]: string | number | boolean | SQL; -} +export type PgMaterializedViewWithConfig = RequireAtLeastOne<{ + fillfactor: number; + toastTupleTarget: number; + parallelWorkers: number; + autovacuumEnabled: boolean; + vacuumIndexCleanup: 'auto' | 'off' | 'on'; + vacuumTruncate: boolean; + autovacuumVacuumThreshold: number; + autovacuumVacuumScaleFactor: number; + autovacuumVacuumCostDelay: number; + autovacuumVacuumCostLimit: number; + autovacuumFreezeMinAge: number; + autovacuumFreezeMaxAge: number; + autovacuumFreezeTableAge: number; + autovacuumMultixactFreezeMinAge: number; + autovacuumMultixactFreezeMaxAge: number; + autovacuumMultixactFreezeTableAge: number; + logAutovacuumMinDuration: number; + userCatalogTable: boolean; +}>; export class MaterializedViewBuilderCore { static readonly [entityKind]: string = 'PgMaterializedViewBuilderCore'; @@ -233,7 +251,12 @@ export class ManualMaterializedViewBuilder< existing(): PgMaterializedViewWithSelection> { return new Proxy( new PgMaterializedView({ - pgConfig: undefined, + pgConfig: { + tablespace: this.config.tablespace, + using: this.config.using, + with: this.config.with, + withNoData: this.config.withNoData, + }, config: { name: this.name, schema: this.schema, @@ -253,7 +276,12 @@ export class ManualMaterializedViewBuilder< as(query: SQL): PgMaterializedViewWithSelection> { return new Proxy( new PgMaterializedView({ - pgConfig: undefined, + pgConfig: { + tablespace: this.config.tablespace, + using: this.config.using, + with: this.config.with, + withNoData: this.config.withNoData, + }, config: { name: this.name, schema: this.schema, @@ -398,3 +426,11 @@ export function pgMaterializedView( ): MaterializedViewBuilder | ManualMaterializedViewBuilder { return pgMaterializedViewWithSchema(name, columns, undefined); } + +export function isPgView(obj: unknown): obj is PgView { + return is(obj, PgView); +} + +export function isPgMaterializedView(obj: unknown): obj is PgMaterializedView { + return is(obj, PgMaterializedView); +} diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index b58de63c3..c58c66f48 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -225,3 +225,7 @@ export type KnownKeysOnly = { export type IsAny = 0 extends (1 & T) ? true : false; export type IfNotImported = unknown extends T ? Y : N; + +export type RequireAtLeastOne = Keys extends any + ? Required> & Partial> + : never; From 05b9e35601eb81dcfeab86d137618f2c9165bf7b Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 23 Sep 2024 18:54:55 +0300 Subject: [PATCH 182/492] fixed build errors --- drizzle-kit/src/api.ts | 5 +++++ drizzle-orm/type-tests/pg/tables.ts | 16 ++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 00cdb1b61..742647952 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -9,6 +9,7 @@ import { schemasResolver, sequencesResolver, tablesResolver, + viewsResolver, } from './cli/commands/migrate'; import { pgPushIntrospect } from './cli/commands/pgIntrospect'; import { pgSuggestions } from './cli/commands/pgPushUtils'; @@ -43,6 +44,8 @@ export const generateDrizzleJson = ( prepared.enums, prepared.schemas, prepared.sequences, + prepared.views, + prepared.matViews, schemaFilters, ); @@ -73,6 +76,7 @@ export const generateMigration = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, ); @@ -116,6 +120,7 @@ export const pushSchema = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, 'push', diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index 068f8fcf6..0ae1d8488 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -506,8 +506,8 @@ export const newYorkers2 = pgMaterializedView('new_yorkers') .using('btree') .with({ fillfactor: 90, - toast_tuple_target: 0.5, - autovacuum_enabled: true, + toastTupleTarget: 0.5, + autovacuumEnabled: true, }) .tablespace('custom_tablespace') .withNoData() @@ -568,8 +568,8 @@ Expect< .using('btree') .with({ fillfactor: 90, - toast_tuple_target: 0.5, - autovacuum_enabled: true, + toastTupleTarget: 0.5, + autovacuumEnabled: true, }) .tablespace('custom_tablespace') .withNoData() @@ -634,8 +634,8 @@ Expect< .using('btree') .with({ fillfactor: 90, - toast_tuple_target: 0.5, - autovacuum_enabled: true, + toastTupleTarget: 0.5, + autovacuumEnabled: true, }) .tablespace('custom_tablespace') .withNoData() @@ -694,8 +694,8 @@ Expect< .using('btree') .with({ fillfactor: 90, - toast_tuple_target: 0.5, - autovacuum_enabled: true, + toastTupleTarget: 0.5, + autovacuumEnabled: true, }) .tablespace('custom_tablespace') .withNoData() From a5a41e09b8507ed7cb775a7feee663ea1c0e80ab Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 23 Sep 2024 19:43:40 +0300 Subject: [PATCH 183/492] added alter for using --- drizzle-kit/src/jsonDiffer.js | 10 + drizzle-kit/src/jsonStatements.ts | 28 +- drizzle-kit/src/snapshotsDiffer.ts | 20 +- drizzle-kit/src/sqlgenerator.ts | 16 + drizzle-kit/tests/pg-views.test.ts | 3386 ++++++++++++++-------------- 5 files changed, 1818 insertions(+), 1642 deletions(-) diff --git a/drizzle-kit/src/jsonDiffer.js b/drizzle-kit/src/jsonDiffer.js index 7073bb136..fcdd533f5 100644 --- a/drizzle-kit/src/jsonDiffer.js +++ b/drizzle-kit/src/jsonDiffer.js @@ -285,6 +285,15 @@ export function applyJsonDiff(json1, json2) { if (droppedTablespace) alteredTablespace = { __new: 'pg_default', __old: droppedTablespace }; if (alterTablespaceTo) alteredTablespace = alterTablespaceTo; + const addedUsing = view.using__added; + const droppedUsing = view.using__deleted; + const alterUsingTo = view.using; + + let alteredUsing; + if (addedUsing) alteredUsing = { __new: addedUsing, __old: 'heap' }; + if (droppedUsing) alteredUsing = { __new: 'heap', __old: droppedUsing }; + if (alterUsingTo) alteredUsing = alterUsingTo; + return { name: json2.views[nameWithSchema].name, schema: json2.views[nameWithSchema].schema, @@ -299,6 +308,7 @@ export function applyJsonDiff(json1, json2) { alteredDefinition, alteredExisting, alteredTablespace, + alteredUsing, }; }, ); diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 2b374e7e2..a604aa0e0 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -587,11 +587,20 @@ export interface JsonAlterViewAlterTablespaceStatement { materialized: true; } +export interface JsonAlterViewAlterUsingStatement { + type: 'alter_view_alter_using'; + toUsing: string; + name: string; + schema: string; + materialized: true; +} + export type JsonAlterViewStatement = | JsonAlterViewAlterSchemaStatement | JsonAlterViewAddWithOptionStatement | JsonAlterViewDropWithOptionStatement - | JsonAlterViewAlterTablespaceStatement; + | JsonAlterViewAlterTablespaceStatement + | JsonAlterViewAlterUsingStatement; export type JsonAlterColumnStatement = | JsonRenameColumnStatement @@ -2595,7 +2604,7 @@ export const preparePgAlterViewDropWithOptionJson = ( } as JsonAlterViewDropWithOptionStatement; }; -export const preparePgAlterViewAlterTablespaceOptionJson = ( +export const preparePgAlterViewAlterTablespaceJson = ( name: string, schema: string, materialized: boolean, @@ -2609,3 +2618,18 @@ export const preparePgAlterViewAlterTablespaceOptionJson = ( toTablespace: to, } as JsonAlterViewAlterTablespaceStatement; }; + +export const preparePgAlterViewAlterUsingJson = ( + name: string, + schema: string, + materialized: boolean, + to: string, +): JsonAlterViewAlterUsingStatement => { + return { + type: 'alter_view_alter_using', + name, + schema, + materialized: materialized, + toUsing: to, + } as JsonAlterViewAlterUsingStatement; +}; diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index ab50c135c..d9eaea1b5 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -71,7 +71,8 @@ import { preparePgAlterColumns, preparePgAlterViewAddWithOptionJson, preparePgAlterViewAlterSchemaJson, - preparePgAlterViewAlterTablespaceOptionJson, + preparePgAlterViewAlterTablespaceJson, + preparePgAlterViewAlterUsingJson, preparePgAlterViewDropWithOptionJson, preparePgCreateIndexesJson, preparePgCreateTableJson, @@ -287,6 +288,10 @@ export const alteredViewSchema = object({ __old: string(), __new: string(), }).strict().optional(), + alteredUsing: object({ + __old: string(), + __new: string(), + }).strict().optional(), }).strict(); export const diffResultScheme = object({ @@ -1269,7 +1274,7 @@ export const applyPgSnapshotsDiff = async ( if (alteredView.alteredTablespace) { alterViews.push( - preparePgAlterViewAlterTablespaceOptionJson( + preparePgAlterViewAlterTablespaceJson( alteredView.name, alteredView.schema, materialized, @@ -1277,6 +1282,17 @@ export const applyPgSnapshotsDiff = async ( ), ); } + + if (alteredView.alteredUsing) { + alterViews.push( + preparePgAlterViewAlterUsingJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.alteredUsing.__new, + ), + ); + } } jsonStatements.push(...createSchemas); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 054a0c51e..709740d11 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -28,6 +28,7 @@ import { JsonAlterViewAddWithOptionStatement, JsonAlterViewAlterSchemaStatement, JsonAlterViewAlterTablespaceStatement, + JsonAlterViewAlterUsingStatement, JsonAlterViewDropWithOptionStatement, JsonCreateCompositePK, JsonCreateEnumStatement, @@ -549,6 +550,20 @@ class PgAlterViewAlterTablespaceConvertor extends Convertor { } } +class PgAlterViewAlterUsingConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_view_alter_using' && dialect === 'postgresql'; + } + + convert(st: JsonAlterViewAlterUsingStatement) { + const { schema, name, toUsing } = st; + + const statement = `ALTER MATERIALIZED VIEW "${schema}"."${name}" SET ACCESS METHOD "${toUsing}";`; + + return statement; + } +} + class PgAlterTableAlterColumnSetGenerated extends Convertor { override can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2646,6 +2661,7 @@ convertors.push(new PgAlterViewSchemaConvertor()); convertors.push(new PgAlterViewAddWithOptionConvertor()); convertors.push(new PgAlterViewDropWithOptionConvertor()); convertors.push(new PgAlterViewAlterTablespaceConvertor()); +convertors.push(new PgAlterViewAlterUsingConvertor()); convertors.push(new CreateTypeEnumConvertor()); diff --git a/drizzle-kit/tests/pg-views.test.ts b/drizzle-kit/tests/pg-views.test.ts index 984380187..160948963 100644 --- a/drizzle-kit/tests/pg-views.test.ts +++ b/drizzle-kit/tests/pg-views.test.ts @@ -4,1644 +4,1644 @@ import { JsonAlterViewAlterTablespaceStatement } from 'src/jsonStatements'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; -// test('create table and view #1', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); -// const to = { -// users: users, -// view: pgView('some_view').as((qb) => qb.select().from(users)), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - -// expect(statements.length).toBe(2); -// expect(statements[0]).toStrictEqual({ -// type: 'create_table', -// tableName: 'users', -// schema: '', -// columns: [{ -// name: 'id', -// notNull: true, -// primaryKey: true, -// type: 'integer', -// }], -// compositePKs: [], -// uniqueConstraints: [], -// compositePkName: '', -// }); -// expect(statements[1]).toStrictEqual({ -// type: 'create_view', -// name: 'some_view', -// definition: `select "id" from "users"`, -// schema: 'public', -// with: undefined, -// materialized: false, -// tablespace: undefined, -// using: undefined, -// withNoData: false, -// }); - -// expect(sqlStatements.length).toBe(2); -// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( -// \t"id" integer PRIMARY KEY NOT NULL -// );\n`); -// expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (select "id" from "users");`); -// }); - -// test('create table and view #2', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); -// const to = { -// users: users, -// view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - -// expect(statements.length).toBe(2); -// expect(statements[0]).toStrictEqual({ -// type: 'create_table', -// tableName: 'users', -// schema: '', -// columns: [{ -// name: 'id', -// notNull: true, -// primaryKey: true, -// type: 'integer', -// }], -// compositePKs: [], -// uniqueConstraints: [], -// compositePkName: '', -// }); -// expect(statements[1]).toStrictEqual({ -// type: 'create_view', -// name: 'some_view', -// definition: `SELECT * FROM "users"`, -// schema: 'public', -// with: undefined, -// materialized: false, -// tablespace: undefined, -// using: undefined, -// withNoData: false, -// }); - -// expect(sqlStatements.length).toBe(2); -// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( -// \t"id" integer PRIMARY KEY NOT NULL -// );\n`); -// expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (SELECT * FROM "users");`); -// }); - -// test('create table and view #3', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); -// const to = { -// users: users, -// view1: pgView('some_view1', { id: integer('id') }).with({ -// checkOption: 'local', -// securityBarrier: false, -// securityInvoker: true, -// }).as(sql`SELECT * FROM ${users}`), -// view2: pgView('some_view2').with({ -// checkOption: 'cascaded', -// securityBarrier: true, -// securityInvoker: false, -// }).as((qb) => qb.select().from(users)), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - -// expect(statements.length).toBe(3); -// expect(statements[0]).toStrictEqual({ -// type: 'create_table', -// tableName: 'users', -// schema: '', -// columns: [{ -// name: 'id', -// notNull: true, -// primaryKey: true, -// type: 'integer', -// }], -// compositePKs: [], -// uniqueConstraints: [], -// compositePkName: '', -// }); -// expect(statements[1]).toStrictEqual({ -// type: 'create_view', -// name: 'some_view1', -// definition: `SELECT * FROM "users"`, -// schema: 'public', -// with: { -// checkOption: 'local', -// securityBarrier: false, -// securityInvoker: true, -// }, -// materialized: false, -// tablespace: undefined, -// using: undefined, -// withNoData: false, -// }); -// expect(statements[2]).toStrictEqual({ -// type: 'create_view', -// name: 'some_view2', -// definition: `select "id" from "users"`, -// schema: 'public', -// with: { -// checkOption: 'cascaded', -// securityBarrier: true, -// securityInvoker: false, -// }, -// materialized: false, -// tablespace: undefined, -// using: undefined, -// withNoData: false, -// }); - -// expect(sqlStatements.length).toBe(3); -// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( -// \t"id" integer PRIMARY KEY NOT NULL -// );\n`); -// expect(sqlStatements[1]).toBe( -// `CREATE VIEW "public"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "users");`, -// ); -// expect(sqlStatements[2]).toBe( -// `CREATE VIEW "public"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "users");`, -// ); -// }); - -// test('create table and view #4', async () => { -// const schema = pgSchema('new_schema'); - -// const users = schema.table('users', { -// id: integer('id').primaryKey().notNull(), -// }); -// const to = { -// schema, -// users: users, -// view1: schema.view('some_view1', { id: integer('id') }).with({ -// checkOption: 'local', -// securityBarrier: false, -// securityInvoker: true, -// }).as(sql`SELECT * FROM ${users}`), -// view2: schema.view('some_view2').with({ -// checkOption: 'cascaded', -// securityBarrier: true, -// securityInvoker: false, -// }).as((qb) => qb.select().from(users)), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - -// expect(statements.length).toBe(4); -// expect(statements[0]).toStrictEqual({ -// type: 'create_schema', -// name: 'new_schema', -// }); -// expect(statements[1]).toStrictEqual({ -// type: 'create_table', -// tableName: 'users', -// schema: 'new_schema', -// columns: [{ -// name: 'id', -// notNull: true, -// primaryKey: true, -// type: 'integer', -// }], -// compositePKs: [], -// uniqueConstraints: [], -// compositePkName: '', -// }); -// expect(statements[2]).toStrictEqual({ -// type: 'create_view', -// name: 'some_view1', -// definition: `SELECT * FROM "new_schema"."users"`, -// schema: 'new_schema', -// with: { -// checkOption: 'local', -// securityBarrier: false, -// securityInvoker: true, -// }, -// materialized: false, -// tablespace: undefined, -// using: undefined, -// withNoData: false, -// }); -// expect(statements[3]).toStrictEqual({ -// type: 'create_view', -// name: 'some_view2', -// definition: `select "id" from "new_schema"."users"`, -// schema: 'new_schema', -// with: { -// checkOption: 'cascaded', -// securityBarrier: true, -// securityInvoker: false, -// }, -// materialized: false, -// tablespace: undefined, -// using: undefined, -// withNoData: false, -// }); - -// expect(sqlStatements.length).toBe(4); -// expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); -// expect(sqlStatements[1]).toBe(`CREATE TABLE IF NOT EXISTS "new_schema"."users" ( -// \t"id" integer PRIMARY KEY NOT NULL -// );\n`); -// expect(sqlStatements[2]).toBe( -// `CREATE VIEW "new_schema"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "new_schema"."users");`, -// ); -// expect(sqlStatements[3]).toBe( -// `CREATE VIEW "new_schema"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "new_schema"."users");`, -// ); -// }); - -// test('create table and view #5', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); -// const to = { -// users: users, -// view1: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), -// view2: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), -// }; - -// await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); -// }); - -// test('create table and view #6', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); -// const to = { -// users: users, -// view1: pgView('some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).as(sql`SELECT * FROM ${users}`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - -// expect(statements.length).toBe(2); -// expect(statements[0]).toStrictEqual({ -// columns: [ -// { -// name: 'id', -// notNull: true, -// primaryKey: true, -// type: 'integer', -// }, -// ], -// compositePKs: [], -// compositePkName: '', -// schema: '', -// tableName: 'users', -// type: 'create_table', -// uniqueConstraints: [], -// }); -// expect(statements[1]).toStrictEqual({ -// definition: 'SELECT * FROM "users"', -// name: 'some_view', -// schema: 'public', -// type: 'create_view', -// with: { -// checkOption: 'cascaded', -// }, -// materialized: false, -// tablespace: undefined, -// using: undefined, -// withNoData: false, -// }); - -// expect(sqlStatements.length).toBe(2); -// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( -// \t"id" integer PRIMARY KEY NOT NULL -// );\n`); -// expect(sqlStatements[1]).toBe( -// `CREATE VIEW "public"."some_view" WITH (check_option = cascaded) AS (SELECT * FROM "users");`, -// ); -// }); - -// test('create view with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// }; - -// const to = { -// users: users, -// view1: pgView('some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('create table and materialized view #1', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); -// const to = { -// users: users, -// view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - -// expect(statements.length).toBe(2); -// expect(statements[0]).toStrictEqual({ -// type: 'create_table', -// tableName: 'users', -// schema: '', -// columns: [{ -// name: 'id', -// notNull: true, -// primaryKey: true, -// type: 'integer', -// }], -// compositePKs: [], -// uniqueConstraints: [], -// compositePkName: '', -// }); -// expect(statements[1]).toStrictEqual({ -// type: 'create_view', -// name: 'some_view', -// definition: `select "id" from "users"`, -// schema: 'public', -// with: undefined, -// materialized: true, -// tablespace: undefined, -// using: undefined, -// withNoData: false, -// }); - -// expect(sqlStatements.length).toBe(2); -// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( -// \t"id" integer PRIMARY KEY NOT NULL -// );\n`); -// expect(sqlStatements[1]).toBe(`CREATE MATERIALIZED VIEW "public"."some_view" AS (select "id" from "users");`); -// }); - -// test('create table and materialized view #2', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); -// const to = { -// users: users, -// view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - -// expect(statements.length).toBe(2); -// expect(statements[0]).toStrictEqual({ -// type: 'create_table', -// tableName: 'users', -// schema: '', -// columns: [{ -// name: 'id', -// notNull: true, -// primaryKey: true, -// type: 'integer', -// }], -// compositePKs: [], -// uniqueConstraints: [], -// compositePkName: '', -// }); -// expect(statements[1]).toStrictEqual({ -// type: 'create_view', -// name: 'some_view', -// definition: `SELECT * FROM "users"`, -// schema: 'public', -// with: undefined, -// materialized: true, -// tablespace: undefined, -// using: undefined, -// withNoData: false, -// }); - -// expect(sqlStatements.length).toBe(2); -// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( -// \t"id" integer PRIMARY KEY NOT NULL -// );\n`); -// expect(sqlStatements[1]).toBe(`CREATE MATERIALIZED VIEW "public"."some_view" AS (SELECT * FROM "users");`); -// }); - -// test('create table and materialized view #3', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); -// const to = { -// users: users, -// view1: pgMaterializedView('some_view1', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), -// view2: pgMaterializedView('some_view2').tablespace('some_tablespace').using('heap').withNoData().with({ -// autovacuumEnabled: true, -// autovacuumFreezeMaxAge: 1, -// autovacuumFreezeMinAge: 1, -// autovacuumFreezeTableAge: 1, -// autovacuumMultixactFreezeMaxAge: 1, -// autovacuumMultixactFreezeMinAge: 1, -// autovacuumMultixactFreezeTableAge: 1, -// autovacuumVacuumCostDelay: 1, -// autovacuumVacuumCostLimit: 1, -// autovacuumVacuumScaleFactor: 1, -// autovacuumVacuumThreshold: 1, -// fillfactor: 1, -// logAutovacuumMinDuration: 1, -// parallelWorkers: 1, -// toastTupleTarget: 1, -// userCatalogTable: true, -// vacuumIndexCleanup: 'off', -// vacuumTruncate: false, -// }).as((qb) => qb.select().from(users)), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - -// expect(statements.length).toBe(3); -// expect(statements[0]).toStrictEqual({ -// type: 'create_table', -// tableName: 'users', -// schema: '', -// columns: [{ -// name: 'id', -// notNull: true, -// primaryKey: true, -// type: 'integer', -// }], -// compositePKs: [], -// uniqueConstraints: [], -// compositePkName: '', -// }); -// expect(statements[1]).toStrictEqual({ -// type: 'create_view', -// name: 'some_view1', -// definition: `SELECT * FROM "users"`, -// schema: 'public', -// with: undefined, -// materialized: true, -// withNoData: false, -// using: undefined, -// tablespace: undefined, -// }); -// expect(statements[2]).toStrictEqual({ -// type: 'create_view', -// name: 'some_view2', -// definition: `select "id" from "users"`, -// schema: 'public', -// with: { -// autovacuumEnabled: true, -// autovacuumFreezeMaxAge: 1, -// autovacuumFreezeMinAge: 1, -// autovacuumFreezeTableAge: 1, -// autovacuumMultixactFreezeMaxAge: 1, -// autovacuumMultixactFreezeMinAge: 1, -// autovacuumMultixactFreezeTableAge: 1, -// autovacuumVacuumCostDelay: 1, -// autovacuumVacuumCostLimit: 1, -// autovacuumVacuumScaleFactor: 1, -// autovacuumVacuumThreshold: 1, -// fillfactor: 1, -// logAutovacuumMinDuration: 1, -// parallelWorkers: 1, -// toastTupleTarget: 1, -// userCatalogTable: true, -// vacuumIndexCleanup: 'off', -// vacuumTruncate: false, -// }, -// materialized: true, -// tablespace: 'some_tablespace', -// using: 'heap', -// withNoData: true, -// }); - -// expect(sqlStatements.length).toBe(3); -// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( -// \t"id" integer PRIMARY KEY NOT NULL -// );\n`); -// expect(sqlStatements[1]).toBe( -// `CREATE MATERIALIZED VIEW "public"."some_view1" AS (SELECT * FROM "users");`, -// ); -// expect(sqlStatements[2]).toBe( -// `CREATE MATERIALIZED VIEW "public"."some_view2" USING "heap" WITH (autovacuum_enabled = true, autovacuum_freeze_max_age = 1, autovacuum_freeze_min_age = 1, autovacuum_freeze_table_age = 1, autovacuum_multixact_freeze_max_age = 1, autovacuum_multixact_freeze_min_age = 1, autovacuum_multixact_freeze_table_age = 1, autovacuum_vacuum_cost_delay = 1, autovacuum_vacuum_cost_limit = 1, autovacuum_vacuum_scale_factor = 1, autovacuum_vacuum_threshold = 1, fillfactor = 1, log_autovacuum_min_duration = 1, parallel_workers = 1, toast_tuple_target = 1, user_catalog_table = true, vacuum_index_cleanup = off, vacuum_truncate = false) TABLESPACE some_tablespace AS (select "id" from "users") WITH NO DATA;`, -// ); -// }); - -// test('create table and materialized view #4', async () => { -// // same names -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); -// const to = { -// users: users, -// view1: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), -// view2: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), -// }; - -// await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); -// }); - -// test('create table and materialized view #5', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); -// const to = { -// users: users, -// view1: pgMaterializedView('some_view', { id: integer('id') }).with({ autovacuumFreezeMinAge: 14 }).as( -// sql`SELECT * FROM ${users}`, -// ), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas({}, to, []); - -// expect(statements.length).toBe(2); -// expect(statements[0]).toStrictEqual({ -// columns: [ -// { -// name: 'id', -// notNull: true, -// primaryKey: true, -// type: 'integer', -// }, -// ], -// compositePKs: [], -// compositePkName: '', -// schema: '', -// tableName: 'users', -// type: 'create_table', -// uniqueConstraints: [], -// }); -// expect(statements[1]).toEqual({ -// definition: 'SELECT * FROM "users"', -// name: 'some_view', -// schema: 'public', -// type: 'create_view', -// with: { -// autovacuumFreezeMinAge: 14, -// }, -// materialized: true, -// tablespace: undefined, -// using: undefined, -// withNoData: false, -// }); - -// expect(sqlStatements.length).toBe(2); -// expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( -// \t"id" integer PRIMARY KEY NOT NULL -// );\n`); -// expect(sqlStatements[1]).toBe( -// `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_freeze_min_age = 14) AS (SELECT * FROM "users");`, -// ); -// }); - -// test('create materialized view with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// }; - -// const to = { -// users: users, -// view1: pgMaterializedView('some_view', { id: integer('id') }).with({ autovacuumEnabled: true }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('drop view #1', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), -// }; - -// const to = { -// users: users, -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// type: 'drop_view', -// name: 'some_view', -// schema: 'public', -// materialized: false, -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe(`DROP VIEW "public"."some_view";`); -// }); - -// test('drop view with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgView('some_view', { id: integer('id') }).existing(), -// }; - -// const to = { -// users: users, -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('drop materialized view #1', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), -// }; - -// const to = { -// users: users, -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// type: 'drop_view', -// name: 'some_view', -// schema: 'public', -// materialized: true, -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."some_view";`); -// }); - -// test('drop materialized view with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).existing(), -// }; - -// const to = { -// users: users, -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('rename view #1', async () => { -// const from = { -// view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), -// }; - -// const to = { -// view: pgView('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// type: 'rename_view', -// nameFrom: 'some_view', -// nameTo: 'new_some_view', -// schema: 'public', -// materialized: false, -// }); -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe(`ALTER VIEW "public"."some_view" RENAME TO "new_some_view";`); -// }); - -// test('rename view with existing flag', async () => { -// const from = { -// view: pgView('some_view', { id: integer('id') }).existing(), -// }; - -// const to = { -// view: pgView('new_some_view', { id: integer('id') }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('rename materialized view #1', async () => { -// const from = { -// view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), -// }; - -// const to = { -// view: pgMaterializedView('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// type: 'rename_view', -// nameFrom: 'some_view', -// nameTo: 'new_some_view', -// schema: 'public', -// materialized: true, -// }); -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe(`ALTER MATERIALIZED VIEW "public"."some_view" RENAME TO "new_some_view";`); -// }); - -// test('rename materialized view with existing flag', async () => { -// const from = { -// view: pgMaterializedView('some_view', { id: integer('id') }).existing(), -// }; - -// const to = { -// view: pgMaterializedView('new_some_view', { id: integer('id') }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('view alter schema', async () => { -// const schema = pgSchema('new_schema'); - -// const from = { -// view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), -// }; - -// const to = { -// schema, -// view: schema.view('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); - -// expect(statements.length).toBe(2); -// expect(statements[0]).toStrictEqual({ -// type: 'create_schema', -// name: 'new_schema', -// }); -// expect(statements[1]).toStrictEqual({ -// type: 'alter_view_alter_schema', -// toSchema: 'new_schema', -// fromSchema: 'public', -// name: 'some_view', -// materialized: false, -// }); -// expect(sqlStatements.length).toBe(2); -// expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); -// expect(sqlStatements[1]).toBe(`ALTER VIEW "public"."some_view" SET SCHEMA "new_schema";`); -// }); - -// test('view alter schema with existing flag', async () => { -// const schema = pgSchema('new_schema'); - -// const from = { -// view: pgView('some_view', { id: integer('id') }).existing(), -// }; - -// const to = { -// schema, -// view: schema.view('some_view', { id: integer('id') }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// type: 'create_schema', -// name: 'new_schema', -// }); -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); -// }); - -// test('view alter schema for materialized', async () => { -// const schema = pgSchema('new_schema'); - -// const from = { -// view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), -// }; - -// const to = { -// schema, -// view: schema.materializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); - -// expect(statements.length).toBe(2); -// expect(statements[0]).toStrictEqual({ -// type: 'create_schema', -// name: 'new_schema', -// }); -// expect(statements[1]).toStrictEqual({ -// type: 'alter_view_alter_schema', -// toSchema: 'new_schema', -// fromSchema: 'public', -// name: 'some_view', -// materialized: true, -// }); -// expect(sqlStatements.length).toBe(2); -// expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); -// expect(sqlStatements[1]).toBe(`ALTER MATERIALIZED VIEW "public"."some_view" SET SCHEMA "new_schema";`); -// }); - -// test('view alter schema for materialized with existing flag', async () => { -// const schema = pgSchema('new_schema'); - -// const from = { -// view: pgMaterializedView('some_view', { id: integer('id') }).existing(), -// }; - -// const to = { -// schema, -// view: schema.materializedView('some_view', { id: integer('id') }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// type: 'create_schema', -// name: 'new_schema', -// }); -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); -// }); - -// test('add with option to view #1', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgView('some_view').as((qb) => qb.select().from(users)), -// }; - -// const to = { -// users, -// view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true }).as((qb) => -// qb.select().from(users) -// ), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// name: 'some_view', -// schema: 'public', -// type: 'alter_view_add_with_option', -// with: { -// checkOption: 'cascaded', -// securityBarrier: true, -// }, -// materialized: false, -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe( -// `ALTER VIEW "public"."some_view" SET (check_option = cascaded, security_barrier = true);`, -// ); -// }); - -// test('add with option to view with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgView('some_view', {}).existing(), -// }; - -// const to = { -// users, -// view: pgView('some_view', {}).with({ checkOption: 'cascaded', securityBarrier: true }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('add with option to materialized view #1', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view').with({ autovacuumMultixactFreezeMaxAge: 3 }).as((qb) => -// qb.select().from(users) -// ), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// name: 'some_view', -// schema: 'public', -// type: 'alter_view_add_with_option', -// with: { -// autovacuumMultixactFreezeMaxAge: 3, -// }, -// materialized: true, -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe( -// `ALTER MATERIALIZED VIEW "public"."some_view" SET (autovacuum_multixact_freeze_max_age = 3);`, -// ); -// }); - -// test('add with option to materialized view with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view', {}).existing(), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view', {}).with({ autovacuumMultixactFreezeMaxAge: 3 }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('drop with option from view #1', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => -// qb.select().from(users) -// ), -// }; - -// const to = { -// users, -// view: pgView('some_view').as((qb) => qb.select().from(users)), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// name: 'some_view', -// schema: 'public', -// type: 'alter_view_drop_with_option', -// materialized: false, -// with: { -// checkOption: 'cascaded', -// securityBarrier: true, -// securityInvoker: true, -// }, -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe( -// `ALTER VIEW "public"."some_view" RESET (check_option, security_barrier, security_invoker);`, -// ); -// }); - -// test('drop with option from view with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgView('some_view', {}).with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }) -// .existing(), -// }; - -// const to = { -// users, -// view: pgView('some_view', {}).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('drop with option from materialized view #1', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, autovacuumFreezeMaxAge: 10 }).as((qb) => -// qb.select().from(users) -// ), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// name: 'some_view', -// schema: 'public', -// type: 'alter_view_drop_with_option', -// materialized: true, -// with: { -// autovacuumEnabled: true, -// autovacuumFreezeMaxAge: 10, -// }, -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe( -// `ALTER MATERIALIZED VIEW "public"."some_view" RESET (autovacuum_enabled, autovacuum_freeze_max_age);`, -// ); -// }); - -// test('drop with option from materialized view with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true, autovacuumFreezeMaxAge: 10 }).existing(), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view', {}).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('alter with option in view #1', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgView('some_view').with({ securityBarrier: true, securityInvoker: true }).as((qb) => -// qb.select().from(users) -// ), -// }; - -// const to = { -// users, -// view: pgView('some_view').with({ securityBarrier: true }).as((qb) => qb.select().from(users)), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// name: 'some_view', -// schema: 'public', -// type: 'alter_view_drop_with_option', -// with: { -// securityInvoker: true, -// }, -// materialized: false, -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe( -// `ALTER VIEW "public"."some_view" RESET (security_invoker);`, -// ); -// }); - -// test('alter with option in view with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgView('some_view', {}).with({ securityBarrier: true, securityInvoker: true }).existing(), -// }; - -// const to = { -// users, -// view: pgView('some_view', {}).with({ securityBarrier: true }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('alter with option in materialized view #1', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, autovacuumVacuumScaleFactor: 1 }).as((qb) => -// qb.select().from(users) -// ), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view').with({ autovacuumEnabled: true }).as((qb) => qb.select().from(users)), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// name: 'some_view', -// schema: 'public', -// type: 'alter_view_drop_with_option', -// with: { -// autovacuumVacuumScaleFactor: 1, -// }, -// materialized: true, -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe( -// `ALTER MATERIALIZED VIEW "public"."some_view" RESET (autovacuum_vacuum_scale_factor);`, -// ); -// }); - -// test('alter with option in materialized view with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true, autovacuumVacuumScaleFactor: 1 }) -// .existing(), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('alter with option in view #2', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgView('some_view').with({ checkOption: 'local', securityBarrier: true, securityInvoker: true }).as((qb) => -// qb.select().from(users) -// ), -// }; - -// const to = { -// users, -// view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => -// qb.select().from(users) -// ), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// type: 'alter_view_add_with_option', -// name: 'some_view', -// schema: 'public', -// with: { -// checkOption: 'cascaded', -// }, -// materialized: false, -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe( -// `ALTER VIEW "public"."some_view" SET (check_option = cascaded);`, -// ); -// }); - -// test('alter with option in materialized view #2', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, fillfactor: 1 }).as((qb) => -// qb.select().from(users) -// ), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view').with({ autovacuumEnabled: false, fillfactor: 1 }).as((qb) => -// qb.select().from(users) -// ), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toStrictEqual({ -// type: 'alter_view_add_with_option', -// name: 'some_view', -// schema: 'public', -// with: { -// autovacuumEnabled: false, -// }, -// materialized: true, -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe( -// `ALTER MATERIALIZED VIEW "public"."some_view" SET (autovacuum_enabled = false);`, -// ); -// }); - -// test('alter view ".as" value', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgView('some_view', { id: integer('id') }).with({ -// checkOption: 'local', -// securityBarrier: true, -// securityInvoker: true, -// }).as(sql`SELECT '123'`), -// }; - -// const to = { -// users, -// view: pgView('some_view', { id: integer('id') }).with({ -// checkOption: 'local', -// securityBarrier: true, -// securityInvoker: true, -// }).as(sql`SELECT '1234'`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(2); -// expect(statements[0]).toStrictEqual( -// { -// name: 'some_view', -// schema: 'public', -// type: 'drop_view', -// materialized: false, -// }, -// ); -// expect(statements[1]).toStrictEqual( -// { -// definition: "SELECT '1234'", -// name: 'some_view', -// schema: 'public', -// type: 'create_view', -// with: { -// checkOption: 'local', -// securityBarrier: true, -// securityInvoker: true, -// }, -// materialized: false, -// withNoData: false, -// tablespace: undefined, -// using: undefined, -// }, -// ); -// expect(sqlStatements.length).toBe(2); -// expect(sqlStatements[0]).toBe('DROP VIEW "public"."some_view";'); -// expect(sqlStatements[1]).toBe( -// `CREATE VIEW "public"."some_view" WITH (check_option = local, security_barrier = true, security_invoker = true) AS (SELECT '1234');`, -// ); -// }); - -// test('alter view ".as" value with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgView('some_view', { id: integer('id') }).with({ -// checkOption: 'local', -// securityBarrier: true, -// securityInvoker: true, -// }).existing(), -// }; - -// const to = { -// users, -// view: pgView('some_view', { id: integer('id') }).with({ -// checkOption: 'local', -// securityBarrier: true, -// securityInvoker: true, -// }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('alter materialized view ".as" value', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).with({ -// autovacuumVacuumCostLimit: 1, -// }).as(sql`SELECT '123'`), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).with({ -// autovacuumVacuumCostLimit: 1, -// }).as(sql`SELECT '1234'`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(2); -// expect(statements[0]).toStrictEqual( -// { -// name: 'some_view', -// schema: 'public', -// type: 'drop_view', -// materialized: true, -// }, -// ); -// expect(statements[1]).toStrictEqual( -// { -// definition: "SELECT '1234'", -// name: 'some_view', -// schema: 'public', -// type: 'create_view', -// with: { -// autovacuumVacuumCostLimit: 1, -// }, -// materialized: true, -// withNoData: false, -// tablespace: undefined, -// using: undefined, -// }, -// ); -// expect(sqlStatements.length).toBe(2); -// expect(sqlStatements[0]).toBe('DROP MATERIALIZED VIEW "public"."some_view";'); -// expect(sqlStatements[1]).toBe( -// `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_vacuum_cost_limit = 1) AS (SELECT '1234');`, -// ); -// }); - -// test('alter materialized view ".as" value with existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).with({ -// autovacuumVacuumCostLimit: 1, -// }).existing(), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).with({ -// autovacuumVacuumCostLimit: 1, -// }).existing(), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); -// }); - -// test('create view with dropped existing flag', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).with({ -// autovacuumVacuumCostLimit: 1, -// }).existing(), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).with({ -// autovacuumVacuumCostLimit: 1, -// }).as(sql`SELECT 'asd'`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(2); -// expect(statements[0]).toEqual({ -// type: 'drop_view', -// name: 'some_view', -// schema: 'public', -// materialized: true, -// }); -// expect(statements[1]).toEqual({ -// definition: "SELECT 'asd'", -// materialized: true, -// name: 'some_view', -// schema: 'public', -// tablespace: undefined, -// type: 'create_view', -// using: undefined, -// with: { -// autovacuumVacuumCostLimit: 1, -// }, -// withNoData: false, -// }); -// expect(sqlStatements.length).toBe(2); -// expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."some_view";`); -// expect(sqlStatements[1]).toBe( -// `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_vacuum_cost_limit = 1) AS (SELECT 'asd');`, -// ); -// }); - -// test('alter tablespace - materialize', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('some_tablespace').with({ -// autovacuumVacuumCostLimit: 1, -// }).as(sql`SELECT 'asd'`), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ -// autovacuumVacuumCostLimit: 1, -// }).as(sql`SELECT 'asd'`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toEqual({ -// type: 'alter_view_alter_tablespace', -// name: 'some_view', -// schema: 'public', -// materialized: true, -// toTablespace: 'new_tablespace', -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe( -// `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE new_tablespace;`, -// ); -// }); - -// test('set tablespace - materialize', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).with({ -// autovacuumVacuumCostLimit: 1, -// }).as(sql`SELECT 'asd'`), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ -// autovacuumVacuumCostLimit: 1, -// }).as(sql`SELECT 'asd'`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toEqual({ -// type: 'alter_view_alter_tablespace', -// name: 'some_view', -// schema: 'public', -// materialized: true, -// toTablespace: 'new_tablespace', -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe( -// `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE new_tablespace;`, -// ); -// }); - -// test('drop tablespace - materialize', async () => { -// const users = pgTable('users', { -// id: integer('id').primaryKey().notNull(), -// }); - -// const from = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ -// autovacuumVacuumCostLimit: 1, -// }).as(sql`SELECT 'asd'`), -// }; - -// const to = { -// users, -// view: pgMaterializedView('some_view', { id: integer('id') }).with({ -// autovacuumVacuumCostLimit: 1, -// }).as(sql`SELECT 'asd'`), -// }; - -// const { statements, sqlStatements } = await diffTestSchemas(from, to, []); - -// expect(statements.length).toBe(1); -// expect(statements[0]).toEqual({ -// type: 'alter_view_alter_tablespace', -// name: 'some_view', -// schema: 'public', -// materialized: true, -// toTablespace: 'pg_default', -// }); - -// expect(sqlStatements.length).toBe(1); -// expect(sqlStatements[0]).toBe( -// `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE pg_default;`, -// ); -// }); +test('create table and view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view: pgView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view', + definition: `select "id" from "users"`, + schema: 'public', + with: undefined, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (select "id" from "users");`); +}); + +test('create table and view #2', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view', + definition: `SELECT * FROM "users"`, + schema: 'public', + with: undefined, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (SELECT * FROM "users");`); +}); + +test('create table and view #3', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgView('some_view1', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }).as(sql`SELECT * FROM ${users}`), + view2: pgView('some_view2').with({ + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(3); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view1', + definition: `SELECT * FROM "users"`, + schema: 'public', + with: { + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + expect(statements[2]).toStrictEqual({ + type: 'create_view', + name: 'some_view2', + definition: `select "id" from "users"`, + schema: 'public', + with: { + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(3); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe( + `CREATE VIEW "public"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "users");`, + ); + expect(sqlStatements[2]).toBe( + `CREATE VIEW "public"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "users");`, + ); +}); + +test('create table and view #4', async () => { + const schema = pgSchema('new_schema'); + + const users = schema.table('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + schema, + users: users, + view1: schema.view('some_view1', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }).as(sql`SELECT * FROM ${users}`), + view2: schema.view('some_view2').with({ + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(4); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: 'new_schema', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[2]).toStrictEqual({ + type: 'create_view', + name: 'some_view1', + definition: `SELECT * FROM "new_schema"."users"`, + schema: 'new_schema', + with: { + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + expect(statements[3]).toStrictEqual({ + type: 'create_view', + name: 'some_view2', + definition: `select "id" from "new_schema"."users"`, + schema: 'new_schema', + with: { + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); + expect(sqlStatements[1]).toBe(`CREATE TABLE IF NOT EXISTS "new_schema"."users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[2]).toBe( + `CREATE VIEW "new_schema"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "new_schema"."users");`, + ); + expect(sqlStatements[3]).toBe( + `CREATE VIEW "new_schema"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "new_schema"."users");`, + ); +}); + +test('create table and view #5', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + view2: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); +}); + +test('create table and view #6', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgView('some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + columns: [ + { + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + ], + compositePKs: [], + compositePkName: '', + schema: '', + tableName: 'users', + type: 'create_table', + uniqueConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + definition: 'SELECT * FROM "users"', + name: 'some_view', + schema: 'public', + type: 'create_view', + with: { + checkOption: 'cascaded', + }, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe( + `CREATE VIEW "public"."some_view" WITH (check_option = cascaded) AS (SELECT * FROM "users");`, + ); +}); + +test('create view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + }; + + const to = { + users: users, + view1: pgView('some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('create table and materialized view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view', + definition: `select "id" from "users"`, + schema: 'public', + with: undefined, + materialized: true, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe(`CREATE MATERIALIZED VIEW "public"."some_view" AS (select "id" from "users");`); +}); + +test('create table and materialized view #2', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view', + definition: `SELECT * FROM "users"`, + schema: 'public', + with: undefined, + materialized: true, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe(`CREATE MATERIALIZED VIEW "public"."some_view" AS (SELECT * FROM "users");`); +}); + +test('create table and materialized view #3', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgMaterializedView('some_view1', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + view2: pgMaterializedView('some_view2').tablespace('some_tablespace').using('heap').withNoData().with({ + autovacuumEnabled: true, + autovacuumFreezeMaxAge: 1, + autovacuumFreezeMinAge: 1, + autovacuumFreezeTableAge: 1, + autovacuumMultixactFreezeMaxAge: 1, + autovacuumMultixactFreezeMinAge: 1, + autovacuumMultixactFreezeTableAge: 1, + autovacuumVacuumCostDelay: 1, + autovacuumVacuumCostLimit: 1, + autovacuumVacuumScaleFactor: 1, + autovacuumVacuumThreshold: 1, + fillfactor: 1, + logAutovacuumMinDuration: 1, + parallelWorkers: 1, + toastTupleTarget: 1, + userCatalogTable: true, + vacuumIndexCleanup: 'off', + vacuumTruncate: false, + }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(3); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view1', + definition: `SELECT * FROM "users"`, + schema: 'public', + with: undefined, + materialized: true, + withNoData: false, + using: undefined, + tablespace: undefined, + }); + expect(statements[2]).toStrictEqual({ + type: 'create_view', + name: 'some_view2', + definition: `select "id" from "users"`, + schema: 'public', + with: { + autovacuumEnabled: true, + autovacuumFreezeMaxAge: 1, + autovacuumFreezeMinAge: 1, + autovacuumFreezeTableAge: 1, + autovacuumMultixactFreezeMaxAge: 1, + autovacuumMultixactFreezeMinAge: 1, + autovacuumMultixactFreezeTableAge: 1, + autovacuumVacuumCostDelay: 1, + autovacuumVacuumCostLimit: 1, + autovacuumVacuumScaleFactor: 1, + autovacuumVacuumThreshold: 1, + fillfactor: 1, + logAutovacuumMinDuration: 1, + parallelWorkers: 1, + toastTupleTarget: 1, + userCatalogTable: true, + vacuumIndexCleanup: 'off', + vacuumTruncate: false, + }, + materialized: true, + tablespace: 'some_tablespace', + using: 'heap', + withNoData: true, + }); + + expect(sqlStatements.length).toBe(3); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe( + `CREATE MATERIALIZED VIEW "public"."some_view1" AS (SELECT * FROM "users");`, + ); + expect(sqlStatements[2]).toBe( + `CREATE MATERIALIZED VIEW "public"."some_view2" USING "heap" WITH (autovacuum_enabled = true, autovacuum_freeze_max_age = 1, autovacuum_freeze_min_age = 1, autovacuum_freeze_table_age = 1, autovacuum_multixact_freeze_max_age = 1, autovacuum_multixact_freeze_min_age = 1, autovacuum_multixact_freeze_table_age = 1, autovacuum_vacuum_cost_delay = 1, autovacuum_vacuum_cost_limit = 1, autovacuum_vacuum_scale_factor = 1, autovacuum_vacuum_threshold = 1, fillfactor = 1, log_autovacuum_min_duration = 1, parallel_workers = 1, toast_tuple_target = 1, user_catalog_table = true, vacuum_index_cleanup = off, vacuum_truncate = false) TABLESPACE some_tablespace AS (select "id" from "users") WITH NO DATA;`, + ); +}); + +test('create table and materialized view #4', async () => { + // same names + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + view2: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); +}); + +test('create table and materialized view #5', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgMaterializedView('some_view', { id: integer('id') }).with({ autovacuumFreezeMinAge: 14 }).as( + sql`SELECT * FROM ${users}`, + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + columns: [ + { + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + ], + compositePKs: [], + compositePkName: '', + schema: '', + tableName: 'users', + type: 'create_table', + uniqueConstraints: [], + }); + expect(statements[1]).toEqual({ + definition: 'SELECT * FROM "users"', + name: 'some_view', + schema: 'public', + type: 'create_view', + with: { + autovacuumFreezeMinAge: 14, + }, + materialized: true, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe( + `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_freeze_min_age = 14) AS (SELECT * FROM "users");`, + ); +}); + +test('create materialized view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + }; + + const to = { + users: users, + view1: pgMaterializedView('some_view', { id: integer('id') }).with({ autovacuumEnabled: true }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view', + schema: 'public', + materialized: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP VIEW "public"."some_view";`); +}); + +test('drop view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop materialized view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view', + schema: 'public', + materialized: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."some_view";`); +}); + +test('drop materialized view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view #1', async () => { + const from = { + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + view: pgView('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + schema: 'public', + materialized: false, + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER VIEW "public"."some_view" RENAME TO "new_some_view";`); +}); + +test('rename view with existing flag', async () => { + const from = { + view: pgView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + view: pgView('new_some_view', { id: integer('id') }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename materialized view #1', async () => { + const from = { + view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + view: pgMaterializedView('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + schema: 'public', + materialized: true, + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER MATERIALIZED VIEW "public"."some_view" RENAME TO "new_some_view";`); +}); + +test('rename materialized view with existing flag', async () => { + const from = { + view: pgMaterializedView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + view: pgMaterializedView('new_some_view', { id: integer('id') }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('view alter schema', async () => { + const schema = pgSchema('new_schema'); + + const from = { + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + schema, + view: schema.view('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(statements[1]).toStrictEqual({ + type: 'alter_view_alter_schema', + toSchema: 'new_schema', + fromSchema: 'public', + name: 'some_view', + materialized: false, + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); + expect(sqlStatements[1]).toBe(`ALTER VIEW "public"."some_view" SET SCHEMA "new_schema";`); +}); + +test('view alter schema with existing flag', async () => { + const schema = pgSchema('new_schema'); + + const from = { + view: pgView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + schema, + view: schema.view('some_view', { id: integer('id') }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); +}); + +test('view alter schema for materialized', async () => { + const schema = pgSchema('new_schema'); + + const from = { + view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + schema, + view: schema.materializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(statements[1]).toStrictEqual({ + type: 'alter_view_alter_schema', + toSchema: 'new_schema', + fromSchema: 'public', + name: 'some_view', + materialized: true, + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); + expect(sqlStatements[1]).toBe(`ALTER MATERIALIZED VIEW "public"."some_view" SET SCHEMA "new_schema";`); +}); + +test('view alter schema for materialized with existing flag', async () => { + const schema = pgSchema('new_schema'); + + const from = { + view: pgMaterializedView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + schema, + view: schema.materializedView('some_view', { id: integer('id') }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); +}); + +test('add with option to view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').as((qb) => qb.select().from(users)), + }; + + const to = { + users, + view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true }).as((qb) => + qb.select().from(users) + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_add_with_option', + with: { + checkOption: 'cascaded', + securityBarrier: true, + }, + materialized: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER VIEW "public"."some_view" SET (check_option = cascaded, security_barrier = true);`, + ); +}); + +test('add with option to view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', {}).existing(), + }; + + const to = { + users, + view: pgView('some_view', {}).with({ checkOption: 'cascaded', securityBarrier: true }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('add with option to materialized view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), + }; + + const to = { + users, + view: pgMaterializedView('some_view').with({ autovacuumMultixactFreezeMaxAge: 3 }).as((qb) => + qb.select().from(users) + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_add_with_option', + with: { + autovacuumMultixactFreezeMaxAge: 3, + }, + materialized: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET (autovacuum_multixact_freeze_max_age = 3);`, + ); +}); + +test('add with option to materialized view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', {}).existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', {}).with({ autovacuumMultixactFreezeMaxAge: 3 }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop with option from view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_drop_with_option', + materialized: false, + with: { + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: true, + }, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER VIEW "public"."some_view" RESET (check_option, security_barrier, security_invoker);`, + ); +}); + +test('drop with option from view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', {}).with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }) + .existing(), + }; + + const to = { + users, + view: pgView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop with option from materialized view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, autovacuumFreezeMaxAge: 10 }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_drop_with_option', + materialized: true, + with: { + autovacuumEnabled: true, + autovacuumFreezeMaxAge: 10, + }, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" RESET (autovacuum_enabled, autovacuum_freeze_max_age);`, + ); +}); + +test('drop with option from materialized view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true, autovacuumFreezeMaxAge: 10 }).existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter with option in view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').with({ securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgView('some_view').with({ securityBarrier: true }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_drop_with_option', + with: { + securityInvoker: true, + }, + materialized: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER VIEW "public"."some_view" RESET (security_invoker);`, + ); +}); + +test('alter with option in view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', {}).with({ securityBarrier: true, securityInvoker: true }).existing(), + }; + + const to = { + users, + view: pgView('some_view', {}).with({ securityBarrier: true }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter with option in materialized view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, autovacuumVacuumScaleFactor: 1 }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgMaterializedView('some_view').with({ autovacuumEnabled: true }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_drop_with_option', + with: { + autovacuumVacuumScaleFactor: 1, + }, + materialized: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" RESET (autovacuum_vacuum_scale_factor);`, + ); +}); + +test('alter with option in materialized view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true, autovacuumVacuumScaleFactor: 1 }) + .existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter with option in view #2', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').with({ checkOption: 'local', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users) + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_view_add_with_option', + name: 'some_view', + schema: 'public', + with: { + checkOption: 'cascaded', + }, + materialized: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER VIEW "public"."some_view" SET (check_option = cascaded);`, + ); +}); + +test('alter with option in materialized view #2', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, fillfactor: 1 }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgMaterializedView('some_view').with({ autovacuumEnabled: false, fillfactor: 1 }).as((qb) => + qb.select().from(users) + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_view_add_with_option', + name: 'some_view', + schema: 'public', + with: { + autovacuumEnabled: false, + }, + materialized: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET (autovacuum_enabled = false);`, + ); +}); + +test('alter view ".as" value', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: true, + securityInvoker: true, + }).as(sql`SELECT '123'`), + }; + + const to = { + users, + view: pgView('some_view', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: true, + securityInvoker: true, + }).as(sql`SELECT '1234'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual( + { + name: 'some_view', + schema: 'public', + type: 'drop_view', + materialized: false, + }, + ); + expect(statements[1]).toStrictEqual( + { + definition: "SELECT '1234'", + name: 'some_view', + schema: 'public', + type: 'create_view', + with: { + checkOption: 'local', + securityBarrier: true, + securityInvoker: true, + }, + materialized: false, + withNoData: false, + tablespace: undefined, + using: undefined, + }, + ); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe('DROP VIEW "public"."some_view";'); + expect(sqlStatements[1]).toBe( + `CREATE VIEW "public"."some_view" WITH (check_option = local, security_barrier = true, security_invoker = true) AS (SELECT '1234');`, + ); +}); + +test('alter view ".as" value with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: true, + securityInvoker: true, + }).existing(), + }; + + const to = { + users, + view: pgView('some_view', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: true, + securityInvoker: true, + }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter materialized view ".as" value', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT '123'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT '1234'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual( + { + name: 'some_view', + schema: 'public', + type: 'drop_view', + materialized: true, + }, + ); + expect(statements[1]).toStrictEqual( + { + definition: "SELECT '1234'", + name: 'some_view', + schema: 'public', + type: 'create_view', + with: { + autovacuumVacuumCostLimit: 1, + }, + materialized: true, + withNoData: false, + tablespace: undefined, + using: undefined, + }, + ); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe('DROP MATERIALIZED VIEW "public"."some_view";'); + expect(sqlStatements[1]).toBe( + `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_vacuum_cost_limit = 1) AS (SELECT '1234');`, + ); +}); + +test('alter materialized view ".as" value with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('create view with dropped existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toEqual({ + type: 'drop_view', + name: 'some_view', + schema: 'public', + materialized: true, + }); + expect(statements[1]).toEqual({ + definition: "SELECT 'asd'", + materialized: true, + name: 'some_view', + schema: 'public', + tablespace: undefined, + type: 'create_view', + using: undefined, + with: { + autovacuumVacuumCostLimit: 1, + }, + withNoData: false, + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."some_view";`); + expect(sqlStatements[1]).toBe( + `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_vacuum_cost_limit = 1) AS (SELECT 'asd');`, + ); +}); + +test('alter tablespace - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('some_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_tablespace', + name: 'some_view', + schema: 'public', + materialized: true, + toTablespace: 'new_tablespace', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE new_tablespace;`, + ); +}); + +test('set tablespace - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_tablespace', + name: 'some_view', + schema: 'public', + materialized: true, + toTablespace: 'new_tablespace', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE new_tablespace;`, + ); +}); + +test('drop tablespace - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_tablespace', + name: 'some_view', + schema: 'public', + materialized: true, + toTablespace: 'pg_default', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE pg_default;`, + ); +}); test('set existing', async () => { const users = pgTable('users', { @@ -1669,3 +1669,113 @@ test('set existing', async () => { expect(sqlStatements.length).toBe(0); }); + +test('alter using - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('some_tablespace').using('some_using').with( + { + autovacuumVacuumCostLimit: 1, + }, + ).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('some_tablespace').using('new_using').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_using', + name: 'some_view', + schema: 'public', + materialized: true, + toUsing: 'new_using', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET ACCESS METHOD "new_using";`, + ); +}); + +test('set using - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).using('new_using').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_using', + name: 'some_view', + schema: 'public', + materialized: true, + toUsing: 'new_using', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET ACCESS METHOD "new_using";`, + ); +}); + +test('drop using - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).using('new_using').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_using', + name: 'some_view', + schema: 'public', + materialized: true, + toUsing: 'heap', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET ACCESS METHOD "heap";`, + ); +}); From f5f3e490dde01b125f091eaace53165bafd61993 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Tue, 24 Sep 2024 12:34:08 +0300 Subject: [PATCH 184/492] added psql rename views and change schema handlings --- drizzle-kit/src/snapshotsDiffer.ts | 31 ++++++++- drizzle-kit/tests/pg-views.test.ts | 101 ++++++++++++++++++++++++++++- 2 files changed, 130 insertions(+), 2 deletions(-) diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index d9eaea1b5..0a6880a8b 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -779,7 +779,36 @@ export const applyPgSnapshotsDiff = async ( deleted: viewsDiff.deleted, }); - const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + const renamesViewDic: Record = {}; + renamedViews.forEach((it) => { + renamesViewDic[`${it.from.schema}.${it.from.name}`] = { to: it.to.name, from: it.from.name }; + }); + + const movedViewDic: Record = {}; + movedViews.forEach((it) => { + movedViewDic[`${it.schemaFrom}.${it.name}`] = { to: it.schemaTo, from: it.schemaFrom }; + }); + + const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + viewsPatchedSnap1.views = mapEntries( + viewsPatchedSnap1.views, + (viewKey, viewValue) => { + const rename = renamesViewDic[`${viewValue.schema}.${viewValue.name}`]; + const moved = movedViewDic[`${viewValue.schema}.${viewValue.name}`]; + + if (rename) { + viewValue.name = rename.to; + viewKey = `${viewValue.schema}.${viewValue.name}`; + } + + if (moved) viewKey = `${moved.to}.${viewValue.name}`; + + return [viewKey, viewValue]; + }, + ); + + const diffResult = applyJsonDiff(viewsPatchedSnap1, json2); + const typedResult: DiffResult = diffResultScheme.parse(diffResult); const jsonStatements: JsonStatement[] = []; diff --git a/drizzle-kit/tests/pg-views.test.ts b/drizzle-kit/tests/pg-views.test.ts index 160948963..0665f0c84 100644 --- a/drizzle-kit/tests/pg-views.test.ts +++ b/drizzle-kit/tests/pg-views.test.ts @@ -1,6 +1,5 @@ import { eq, sql } from 'drizzle-orm'; import { integer, pgMaterializedView, pgSchema, pgTable, pgView } from 'drizzle-orm/pg-core'; -import { JsonAlterViewAlterTablespaceStatement } from 'src/jsonStatements'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; @@ -1670,6 +1669,33 @@ test('set existing', async () => { expect(sqlStatements.length).toBe(0); }); +test('set existing', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', { id: integer('id') }).with({ + checkOption: 'cascaded', + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgView('new_some_view', { id: integer('id') }).with({ + checkOption: 'cascaded', + securityBarrier: true, + }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(0); + + expect(sqlStatements.length).toBe(0); +}); + test('alter using - materialize', async () => { const users = pgTable('users', { id: integer('id').primaryKey().notNull(), @@ -1779,3 +1805,76 @@ test('drop using - materialize', async () => { `ALTER MATERIALIZED VIEW "public"."some_view" SET ACCESS METHOD "heap";`, ); }); + +test('rename view and alter view', async () => { + const from = { + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + view: pgView('new_some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).as( + sql`SELECT * FROM "users"`, + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + schema: 'public', + materialized: false, + }); + expect(statements[1]).toStrictEqual({ + materialized: false, + name: 'new_some_view', + schema: 'public', + type: 'alter_view_add_with_option', + with: { + checkOption: 'cascaded', + }, + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER VIEW "public"."some_view" RENAME TO "new_some_view";`); + expect(sqlStatements[1]).toBe(`ALTER VIEW "public"."new_some_view" SET (check_option = cascaded);`); +}); + +test('moved schema and alter view', async () => { + const schema = pgSchema('my_schema'); + const from = { + schema, + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + schema, + view: schema.view('some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).as( + sql`SELECT * FROM "users"`, + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->my_schema.some_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + fromSchema: 'public', + materialized: false, + name: 'some_view', + toSchema: 'my_schema', + type: 'alter_view_alter_schema', + }); + expect(statements[1]).toStrictEqual({ + materialized: false, + name: 'some_view', + schema: 'my_schema', + type: 'alter_view_add_with_option', + with: { + checkOption: 'cascaded', + }, + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER VIEW "public"."some_view" SET SCHEMA "my_schema";`); + expect(sqlStatements[1]).toBe(`ALTER VIEW "my_schema"."some_view" SET (check_option = cascaded);`); +}); From 86d19b1e6949ca1f78d0254a29ac2ff5a5c24e30 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 24 Sep 2024 09:10:06 -0700 Subject: [PATCH 185/492] Serialize with casing --- drizzle-kit/src/cli/commands/migrate.ts | 20 ++++++++++-- drizzle-kit/src/cli/commands/push.ts | 13 +++++--- drizzle-kit/src/cli/commands/utils.ts | 11 ++++++- drizzle-kit/src/cli/schema.ts | 12 ++++++- drizzle-kit/src/cli/validations/cli.ts | 3 +- drizzle-kit/src/cli/validations/common.ts | 5 +++ drizzle-kit/src/index.ts | 1 + drizzle-kit/src/migrationPreparator.ts | 19 +++++++---- drizzle-kit/src/serializer/index.ts | 19 +++++++---- drizzle-kit/src/serializer/mysqlSerializer.ts | 32 +++++++++++-------- drizzle-kit/src/serializer/pgSerializer.ts | 32 +++++++++++-------- .../src/serializer/sqliteSerializer.ts | 26 ++++++++------- drizzle-kit/src/utils.ts | 11 +++++++ drizzle-orm/src/column.ts | 3 +- drizzle-orm/src/pg-core/columns/common.ts | 3 ++ drizzle-orm/src/pg-core/indexes.ts | 6 ++-- 16 files changed, 150 insertions(+), 66 deletions(-) diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 2bcd72cab..ce0f85a40 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -33,7 +33,7 @@ import { } from '../../snapshotsDiffer'; import { assertV1OutFolder, Journal, prepareMigrationFolder } from '../../utils'; import { prepareMigrationMetadata } from '../../utils/words'; -import { Prefix } from '../validations/common'; +import { CasingType, Prefix } from '../validations/common'; import { withStyle } from '../validations/outputs'; import { isRenamePromptItem, @@ -156,6 +156,7 @@ export const columnsResolver = async ( export const prepareAndMigratePg = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; + const casing = config.casing; try { assertV1OutFolder(outFolder); @@ -168,6 +169,7 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => { const { prev, cur, custom } = await preparePgMigrationSnapshot( snapshots, schemaPath, + casing ); const validatedPrev = pgSchema.parse(prev); @@ -220,10 +222,12 @@ export const preparePgPush = async ( schemaPath: string | string[], snapshot: PgSchema, schemaFilter: string[], + casing: CasingType | undefined ) => { const { prev, cur } = await preparePgDbPushSnapshot( snapshot, schemaPath, + casing, schemaFilter, ); @@ -304,11 +308,13 @@ function mysqlSchemaSuggestions( export const prepareMySQLPush = async ( schemaPath: string | string[], snapshot: MySqlSchema, + casing: CasingType | undefined, ) => { try { const { prev, cur } = await prepareMySqlDbPushSnapshot( snapshot, schemaPath, + casing ); const validatedPrev = mysqlSchema.parse(prev); @@ -337,6 +343,7 @@ export const prepareMySQLPush = async ( export const prepareAndMigrateMysql = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; + const casing = config.casing; try { // TODO: remove @@ -346,6 +353,7 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { const { prev, cur, custom } = await prepareMySqlMigrationSnapshot( snapshots, schemaPath, + casing ); const validatedPrev = mysqlSchema.parse(prev); @@ -395,6 +403,7 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; + const casing = config.casing; try { assertV1OutFolder(outFolder); @@ -403,6 +412,7 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const { prev, cur, custom } = await prepareSqliteMigrationSnapshot( snapshots, schemaPath, + casing ); const validatedPrev = sqliteSchema.parse(prev); @@ -454,6 +464,7 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; + const casing = config.casing; try { assertV1OutFolder(outFolder); @@ -462,6 +473,7 @@ export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => { const { prev, cur, custom } = await prepareSqliteMigrationSnapshot( snapshots, schemaPath, + casing ); const validatedPrev = sqliteSchema.parse(prev); @@ -513,8 +525,9 @@ export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => { export const prepareSQLitePush = async ( schemaPath: string | string[], snapshot: SQLiteSchema, + casing: CasingType | undefined ) => { - const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath); + const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath, casing); const validatedPrev = sqliteSchema.parse(prev); const validatedCur = sqliteSchema.parse(cur); @@ -544,8 +557,9 @@ export const prepareSQLitePush = async ( export const prepareLibSQLPush = async ( schemaPath: string | string[], snapshot: SQLiteSchema, + casing: CasingType | undefined ) => { - const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath); + const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath, casing); const validatedPrev = sqliteSchema.parse(prev); const validatedCur = sqliteSchema.parse(cur); diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 404000608..b37a6dc1e 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -11,6 +11,7 @@ import { libSqlLogSuggestionsAndReturn } from './libSqlPushUtils'; import { filterStatements, logSuggestionsAndReturn } from './mysqlPushUtils'; import { pgSuggestions } from './pgPushUtils'; import { logSuggestionsAndReturn as sqliteSuggestions } from './sqlitePushUtils'; +import { CasingType } from '../validations/common'; export const mysqlPush = async ( schemaPath: string | string[], @@ -19,6 +20,7 @@ export const mysqlPush = async ( strict: boolean, verbose: boolean, force: boolean, + casing: CasingType | undefined ) => { const { connectToMySQL } = await import('../connections'); const { mysqlPushIntrospect } = await import('./mysqlIntrospect'); @@ -28,7 +30,7 @@ export const mysqlPush = async ( const { schema } = await mysqlPushIntrospect(db, database, tablesFilter); const { prepareMySQLPush } = await import('./migrate'); - const statements = await prepareMySQLPush(schemaPath, schema); + const statements = await prepareMySQLPush(schemaPath, schema, casing); const filteredStatements = filterStatements( statements.statements ?? [], @@ -159,6 +161,7 @@ export const pgPush = async ( tablesFilter: string[], schemasFilter: string[], force: boolean, + casing: CasingType | undefined ) => { const { preparePostgresDB } = await import('../connections'); const { pgPushIntrospect } = await import('./pgIntrospect'); @@ -168,7 +171,7 @@ export const pgPush = async ( const { preparePgPush } = await import('./migrate'); - const statements = await preparePgPush(schemaPath, schema, schemasFilter); + const statements = await preparePgPush(schemaPath, schema, schemasFilter, casing); try { if (statements.sqlStatements.length === 0) { @@ -268,6 +271,7 @@ export const sqlitePush = async ( credentials: SqliteCredentials, tablesFilter: string[], force: boolean, + casing: CasingType | undefined ) => { const { connectToSQLite } = await import('../connections'); const { sqlitePushIntrospect } = await import('./sqliteIntrospect'); @@ -276,7 +280,7 @@ export const sqlitePush = async ( const { schema } = await sqlitePushIntrospect(db, tablesFilter); const { prepareSQLitePush } = await import('./migrate'); - const statements = await prepareSQLitePush(schemaPath, schema); + const statements = await prepareSQLitePush(schemaPath, schema, casing); if (statements.sqlStatements.length === 0) { render(`\n[${chalk.blue('i')}] No changes detected`); @@ -386,6 +390,7 @@ export const libSQLPush = async ( credentials: LibSQLCredentials, tablesFilter: string[], force: boolean, + casing: CasingType | undefined ) => { const { connectToLibSQL } = await import('../connections'); const { sqlitePushIntrospect } = await import('./sqliteIntrospect'); @@ -395,7 +400,7 @@ export const libSQLPush = async ( const { prepareLibSQLPush } = await import('./migrate'); - const statements = await prepareLibSQLPush(schemaPath, schema); + const statements = await prepareLibSQLPush(schemaPath, schema, casing); if (statements.sqlStatements.length === 0) { render(`\n[${chalk.blue('i')}] No changes detected`); diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 320b17652..c9e78ab54 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -9,6 +9,7 @@ import { prepareFilenames } from '../../serializer'; import { pullParams, pushParams } from '../validations/cli'; import { Casing, + CasingType, CliConfig, configCommonSchema, configMigrations, @@ -124,6 +125,7 @@ export type GenerateConfig = { prefix: Prefix; custom: boolean; bundle: boolean; + casing?: CasingType; }; export const prepareGenerateConfig = async ( @@ -137,12 +139,13 @@ export const prepareGenerateConfig = async ( dialect?: Dialect; driver?: Driver; prefix?: Prefix; + casing?: CasingType }, from: 'config' | 'cli', ): Promise => { const config = from === 'config' ? await drizzleConfigFromFile(options.config) : options; - const { schema, out, breakpoints, dialect, driver } = config; + const { schema, out, breakpoints, dialect, driver, casing } = config; if (!schema || !dialect) { console.log(error('Please provide required params:')); @@ -170,6 +173,7 @@ export const prepareGenerateConfig = async ( schema: schema, out: out || 'drizzle', bundle: driver === 'expo', + casing }; }; @@ -224,6 +228,7 @@ export const preparePushConfig = async ( force: boolean; tablesFilter: string[]; schemasFilter: string[]; + casing?: CasingType; } > => { const raw = flattenDatabaseCredentials( @@ -292,6 +297,7 @@ export const preparePushConfig = async ( verbose: config.verbose ?? false, force: (options.force as boolean) ?? false, credentials: parsed.data, + casing: config.casing, tablesFilter, schemasFilter, }; @@ -310,6 +316,7 @@ export const preparePushConfig = async ( verbose: config.verbose ?? false, force: (options.force as boolean) ?? false, credentials: parsed.data, + casing: config.casing, tablesFilter, schemasFilter, }; @@ -328,6 +335,7 @@ export const preparePushConfig = async ( verbose: config.verbose ?? false, force: (options.force as boolean) ?? false, credentials: parsed.data, + casing: config.casing, tablesFilter, schemasFilter, }; @@ -346,6 +354,7 @@ export const preparePushConfig = async ( verbose: config.verbose ?? false, force: (options.force as boolean) ?? false, credentials: parsed.data, + casing: config.casing, tablesFilter, schemasFilter, }; diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index c7d5b88f3..e47d58a69 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -41,12 +41,15 @@ const optionDriver = string() .enum(...drivers) .desc('Database driver'); +const optionCasing = string().enum('camel', 'snake').desc('Casing for serialization'); + export const generate = command({ name: 'generate', options: { config: optionConfig, dialect: optionDialect, driver: optionDriver, + casing: optionCasing, schema: string().desc('Path to a schema file or folder'), out: optionOut, name: string().desc('Migration file name'), @@ -63,7 +66,7 @@ export const generate = command({ 'generate', opts, ['prefix', 'name', 'custom'], - ['driver', 'breakpoints', 'schema', 'out', 'dialect'], + ['driver', 'breakpoints', 'schema', 'out', 'dialect', 'casing'], ); return prepareGenerateConfig(opts, from); }, @@ -212,6 +215,7 @@ export const push = command({ options: { config: optionConfig, dialect: optionDialect, + casing: optionCasing, schema: string().desc('Path to a schema file or folder'), ...optionsFilters, ...optionsDatabaseCredentials, @@ -245,6 +249,7 @@ export const push = command({ 'schemaFilters', 'extensionsFilters', 'tablesFilter', + 'casing' ], ); @@ -263,6 +268,7 @@ export const push = command({ tablesFilter, schemasFilter, force, + casing, } = config; try { @@ -275,6 +281,7 @@ export const push = command({ strict, verbose, force, + casing, ); } else if (dialect === 'postgresql') { if ('driver' in credentials) { @@ -307,6 +314,7 @@ export const push = command({ tablesFilter, schemasFilter, force, + casing, ); } else if (dialect === 'sqlite') { const { sqlitePush } = await import('./commands/push'); @@ -317,6 +325,7 @@ export const push = command({ credentials, tablesFilter, force, + casing, ); } else if (dialect === 'turso') { const { libSQLPush } = await import('./commands/push'); @@ -327,6 +336,7 @@ export const push = command({ credentials, tablesFilter, force, + casing, ); } else { assertUnreachable(dialect); diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index c4bbbe530..219ddc4b6 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -1,6 +1,6 @@ import { boolean, intersection, literal, object, string, TypeOf, union } from 'zod'; import { dialect } from '../../schemaValidator'; -import { casing, prefix } from './common'; +import { casing, casingType, prefix } from './common'; export const cliConfigGenerate = object({ dialect: dialect.optional(), @@ -17,6 +17,7 @@ export type CliConfigGenerate = TypeOf; export const pushParams = object({ dialect: dialect, + casing: casingType, schema: union([string(), string().array()]), tablesFilter: union([string(), string().array()]).optional(), schemaFilter: union([string(), string().array()]) diff --git a/drizzle-kit/src/cli/validations/common.ts b/drizzle-kit/src/cli/validations/common.ts index 3a2701e37..0b64b4dc2 100644 --- a/drizzle-kit/src/cli/validations/common.ts +++ b/drizzle-kit/src/cli/validations/common.ts @@ -84,6 +84,10 @@ export type Prefix = (typeof prefixes)[number]; const _: Prefix = '' as TypeOf; } +export const casingTypes = ['snake', 'camel'] as const; +export const casingType = enum_(casingTypes); +export type CasingType = (typeof casingTypes)[number]; + export const sqliteDriver = union(sqliteDriversLiterals); export const postgresDriver = union(postgresqlDriversLiterals); export const driver = union([sqliteDriver, postgresDriver]); @@ -105,6 +109,7 @@ export const configCommonSchema = object({ schemaFilter: union([string(), string().array()]).default(['public']), migrations: configMigrations, dbCredentials: any().optional(), + casing: casingType }).passthrough(); export const casing = union([literal('camel'), literal('preserve')]).default( diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 183b335ce..009eb2846 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -117,6 +117,7 @@ export type Config = schema?: string | string[]; verbose?: boolean; strict?: boolean; + casing: 'camel' | 'snake'; migrations?: { table?: string; schema?: string; diff --git a/drizzle-kit/src/migrationPreparator.ts b/drizzle-kit/src/migrationPreparator.ts index 687cfdb7c..322ebed44 100644 --- a/drizzle-kit/src/migrationPreparator.ts +++ b/drizzle-kit/src/migrationPreparator.ts @@ -4,12 +4,14 @@ import { serializeMySql, serializePg, serializeSQLite } from './serializer'; import { dryMySql, MySqlSchema, mysqlSchema } from './serializer/mysqlSchema'; import { dryPg, PgSchema, pgSchema, PgSchemaInternal } from './serializer/pgSchema'; import { drySQLite, SQLiteSchema, sqliteSchema } from './serializer/sqliteSchema'; +import { CasingType } from './cli/validations/common'; export const prepareMySqlDbPushSnapshot = async ( prev: MySqlSchema, schemaPath: string | string[], + casing: CasingType | undefined, ): Promise<{ prev: MySqlSchema; cur: MySqlSchema }> => { - const serialized = await serializeMySql(schemaPath); + const serialized = await serializeMySql(schemaPath, casing); const id = randomUUID(); const idPrev = prev.id; @@ -23,8 +25,9 @@ export const prepareMySqlDbPushSnapshot = async ( export const prepareSQLiteDbPushSnapshot = async ( prev: SQLiteSchema, schemaPath: string | string[], + casing: CasingType | undefined, ): Promise<{ prev: SQLiteSchema; cur: SQLiteSchema }> => { - const serialized = await serializeSQLite(schemaPath); + const serialized = await serializeSQLite(schemaPath, casing); const id = randomUUID(); const idPrev = prev.id; @@ -44,9 +47,10 @@ export const prepareSQLiteDbPushSnapshot = async ( export const preparePgDbPushSnapshot = async ( prev: PgSchema, schemaPath: string | string[], + casing: CasingType | undefined, schemaFilter: string[] = ['public'], ): Promise<{ prev: PgSchema; cur: PgSchema }> => { - const serialized = await serializePg(schemaPath, schemaFilter); + const serialized = await serializePg(schemaPath, casing, schemaFilter); const id = randomUUID(); const idPrev = prev.id; @@ -60,11 +64,12 @@ export const preparePgDbPushSnapshot = async ( export const prepareMySqlMigrationSnapshot = async ( migrationFolders: string[], schemaPath: string | string[], + casing: CasingType | undefined, ): Promise<{ prev: MySqlSchema; cur: MySqlSchema; custom: MySqlSchema }> => { const prevSnapshot = mysqlSchema.parse( preparePrevSnapshot(migrationFolders, dryMySql), ); - const serialized = await serializeMySql(schemaPath); + const serialized = await serializeMySql(schemaPath, casing); const id = randomUUID(); const idPrev = prevSnapshot.id; @@ -87,11 +92,12 @@ export const prepareMySqlMigrationSnapshot = async ( export const prepareSqliteMigrationSnapshot = async ( snapshots: string[], schemaPath: string | string[], + casing: CasingType | undefined, ): Promise<{ prev: SQLiteSchema; cur: SQLiteSchema; custom: SQLiteSchema }> => { const prevSnapshot = sqliteSchema.parse( preparePrevSnapshot(snapshots, drySQLite), ); - const serialized = await serializeSQLite(schemaPath); + const serialized = await serializeSQLite(schemaPath, casing); const id = randomUUID(); const idPrev = prevSnapshot.id; @@ -133,9 +139,10 @@ export const fillPgSnapshot = ({ export const preparePgMigrationSnapshot = async ( snapshots: string[], schemaPath: string | string[], + casing: CasingType | undefined ): Promise<{ prev: PgSchema; cur: PgSchema; custom: PgSchema }> => { const prevSnapshot = pgSchema.parse(preparePrevSnapshot(snapshots, dryPg)); - const serialized = await serializePg(schemaPath); + const serialized = await serializePg(schemaPath, casing); const id = randomUUID(); const idPrev = prevSnapshot.id; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index 214ca38c7..4b8d673d5 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -1,5 +1,5 @@ import chalk from 'chalk'; -import type { SQL } from 'drizzle-orm'; +import { SQL, Table } from 'drizzle-orm'; import fs from 'fs'; import * as glob from 'glob'; import Path from 'path'; @@ -7,8 +7,10 @@ import { error } from '../cli/views'; import type { MySqlSchemaInternal } from './mysqlSchema'; import type { PgSchemaInternal } from './pgSchema'; import type { SQLiteSchemaInternal } from './sqliteSchema'; +import { CasingType } from 'src/cli/validations/common'; +import { CasingCache } from 'drizzle-orm/casing'; -export const sqlToStr = (sql: SQL) => { +export const sqlToStr = (sql: SQL, casing: CasingType | undefined) => { return sql.toQuery({ escapeName: () => { throw new Error("we don't support params for `sql` default values"); @@ -19,10 +21,11 @@ export const sqlToStr = (sql: SQL) => { escapeString: () => { throw new Error("we don't support params for `sql` default values"); }, + casing: new CasingCache(casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined) }).sql; }; -export const sqlToStrGenerated = (sql: SQL) => { +export const sqlToStrGenerated = (sql: SQL, casing: CasingType | undefined) => { return sql.toQuery({ escapeName: () => { throw new Error("we don't support params for `sql` default values"); @@ -33,11 +36,13 @@ export const sqlToStrGenerated = (sql: SQL) => { escapeString: () => { throw new Error("we don't support params for `sql` default values"); }, + casing: new CasingCache(casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined) }).sql; }; export const serializeMySql = async ( path: string | string[], + casing: CasingType | undefined, ): Promise => { const filenames = prepareFilenames(path); @@ -48,11 +53,12 @@ export const serializeMySql = async ( const { tables } = await prepareFromMySqlImports(filenames); - return generateMySqlSnapshot(tables); + return generateMySqlSnapshot(tables, casing); }; export const serializePg = async ( path: string | string[], + casing: CasingType | undefined, schemaFilter?: string[], ): Promise => { const filenames = prepareFilenames(path); @@ -64,18 +70,19 @@ export const serializePg = async ( filenames, ); - return generatePgSnapshot(tables, enums, schemas, sequences, schemaFilter); + return generatePgSnapshot(tables, enums, schemas, sequences, casing, schemaFilter); }; export const serializeSQLite = async ( path: string | string[], + casing: CasingType | undefined, ): Promise => { const filenames = prepareFilenames(path); const { prepareFromSqliteImports } = await import('./sqliteImports'); const { generateSqliteSnapshot } = await import('./sqliteSerializer'); const { tables } = await prepareFromSqliteImports(filenames); - return generateSqliteSnapshot(tables); + return generateSqliteSnapshot(tables, casing); }; export const prepareFilenames = (path: string | string[]) => { diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 14e867128..0b6e48de4 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -16,8 +16,10 @@ import { Table, UniqueConstraint, } from '../serializer/mysqlSchema'; -import type { DB } from '../utils'; +import { getColumnCasing, type DB } from '../utils'; import { sqlToStr } from '.'; +import { CasingType } from 'src/cli/validations/common'; +import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; // import { MySqlColumnWithAutoIncrement } from "drizzle-orm/mysql-core"; // import { MySqlDateBaseColumn } from "drizzle-orm/mysql-core"; @@ -29,6 +31,7 @@ export const indexName = (tableName: string, columns: string[]) => { export const generateMySqlSnapshot = ( tables: AnyMySqlTable[], + casing: CasingType | undefined, ): MySqlSchemaInternal => { const result: Record = {}; const internal: MySqlKitInternals = { tables: {}, indexes: {} }; @@ -49,6 +52,7 @@ export const generateMySqlSnapshot = ( const uniqueConstraintObject: Record = {}; columns.forEach((column) => { + const name = getColumnCasing(column, casing); const notNull: boolean = column.notNull; const sqlTypeLowered = column.getSQLType().toLowerCase(); const autoIncrement = typeof (column as any).autoIncrement === 'undefined' @@ -58,7 +62,7 @@ export const generateMySqlSnapshot = ( const generated = column.generated; const columnToSet: Column = { - name: column.name, + name, type: column.getSQLType(), primaryKey: false, // If field is autoincrement it's notNull by default @@ -79,9 +83,9 @@ export const generateMySqlSnapshot = ( }; if (column.primary) { - primaryKeysObject[`${tableName}_${column.name}`] = { - name: `${tableName}_${column.name}`, - columns: [column.name], + primaryKeysObject[`${tableName}_${name}`] = { + name: `${tableName}_${name}`, + columns: [name], }; } @@ -101,7 +105,7 @@ export const generateMySqlSnapshot = ( ) } on the ${ chalk.underline.blue( - column.name, + name, ) } column is confilcting with a unique constraint name already defined for ${ chalk.underline.blue( @@ -120,7 +124,7 @@ export const generateMySqlSnapshot = ( if (column.default !== undefined) { if (is(column.default, SQL)) { - columnToSet.default = sqlToStr(column.default); + columnToSet.default = sqlToStr(column.default, casing); } else { if (typeof column.default === 'string') { columnToSet.default = `'${column.default}'`; @@ -150,11 +154,11 @@ export const generateMySqlSnapshot = ( } } } - columnsObject[column.name] = columnToSet; + columnsObject[name] = columnToSet; }); primaryKeys.map((pk: PrimaryKeyORM) => { - const columnNames = pk.columns.map((c: any) => c.name); + const columnNames = pk.columns.map((c: any) => getColumnCasing(c, casing)); primaryKeysObject[pk.getName()] = { name: pk.getName(), columns: columnNames, @@ -162,12 +166,12 @@ export const generateMySqlSnapshot = ( // all composite pk's should be treated as notNull for (const column of pk.columns) { - columnsObject[column.name].notNull = true; + columnsObject[getColumnCasing(column, casing)].notNull = true; } }); uniqueConstraints?.map((unq) => { - const columnNames = unq.columns.map((c) => c.name); + const columnNames = unq.columns.map((c) => getColumnCasing(c, casing)); const name = unq.name ?? uniqueKeyName(table, columnNames); @@ -216,8 +220,8 @@ export const generateMySqlSnapshot = ( // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const tableTo = getTableName(referenceFT); - const columnsFrom = reference.columns.map((it) => it.name); - const columnsTo = reference.foreignColumns.map((it) => it.name); + const columnsFrom = reference.columns.map((it) => getColumnCasing(it, casing)); + const columnsTo = reference.foreignColumns.map((it) => getColumnCasing(it, casing)); return { name, tableFrom, @@ -259,7 +263,7 @@ export const generateMySqlSnapshot = ( } return sql; } else { - return `${it.name}`; + return `${getColumnCasing(it, casing)}`; } }); diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index b479e59e2..712cab5df 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -30,8 +30,9 @@ import type { Table, UniqueConstraint, } from '../serializer/pgSchema'; -import { type DB, isPgArrayType } from '../utils'; +import { type DB, getColumnCasing, isPgArrayType } from '../utils'; import { sqlToStr } from '.'; +import { CasingType } from 'src/cli/validations/common'; const dialect = new PgDialect(); @@ -117,6 +118,7 @@ export const generatePgSnapshot = ( enums: PgEnum[], schemas: PgSchema[], sequences: PgSequence[], + casing: CasingType | undefined, schemaFilter?: string[], ): PgSchemaInternal => { const result: Record = {}; @@ -149,6 +151,7 @@ export const generatePgSnapshot = ( const uniqueConstraintObject: Record = {}; columns.forEach((column) => { + const name = getColumnCasing(column, casing); const notNull: boolean = column.notNull; const primaryKey: boolean = column.primary; const sqlTypeLowered = column.getSQLType().toLowerCase(); @@ -173,7 +176,7 @@ export const generatePgSnapshot = ( const cache = stringFromIdentityProperty(identity?.sequenceOptions?.cache) ?? '1'; const columnToSet: Column = { - name: column.name, + name, type: column.getSQLType(), typeSchema: typeSchema, primaryKey, @@ -191,7 +194,7 @@ export const generatePgSnapshot = ( identity: identity ? { type: identity.type, - name: identity.sequenceName ?? `${tableName}_${column.name}_seq`, + name: identity.sequenceName ?? `${tableName}_${name}_seq`, schema: schema ?? 'public', increment, startWith, @@ -219,7 +222,7 @@ export const generatePgSnapshot = ( ) } on the ${ chalk.underline.blue( - column.name, + name, ) } column is confilcting with a unique constraint name already defined for ${ chalk.underline.blue( @@ -239,7 +242,7 @@ export const generatePgSnapshot = ( if (column.default !== undefined) { if (is(column.default, SQL)) { - columnToSet.default = sqlToStr(column.default); + columnToSet.default = sqlToStr(column.default, casing); } else { if (typeof column.default === 'string') { columnToSet.default = `'${column.default}'`; @@ -278,11 +281,11 @@ export const generatePgSnapshot = ( } } } - columnsObject[column.name] = columnToSet; + columnsObject[name] = columnToSet; }); primaryKeys.map((pk) => { - const columnNames = pk.columns.map((c) => c.name); + const columnNames = pk.columns.map((c) => getColumnCasing(c, casing)); primaryKeysObject[pk.getName()] = { name: pk.getName(), columns: columnNames, @@ -290,7 +293,7 @@ export const generatePgSnapshot = ( }); uniqueConstraints?.map((unq) => { - const columnNames = unq.columns.map((c) => c.name); + const columnNames = unq.columns.map((c) => getColumnCasing(c, casing)); const name = unq.name ?? uniqueKeyName(table, columnNames); @@ -340,8 +343,8 @@ export const generatePgSnapshot = ( // getTableConfig(reference.foreignTable).schema || "public"; const schemaTo = getTableConfig(reference.foreignTable).schema; - const columnsFrom = reference.columns.map((it) => it.name); - const columnsTo = reference.foreignColumns.map((it) => it.name); + const columnsFrom = reference.columns.map((it) => getColumnCasing(it, casing)); + const columnsTo = reference.foreignColumns.map((it) => getColumnCasing(it, casing)); return { name, @@ -383,6 +386,7 @@ export const generatePgSnapshot = ( } } it = it as IndexedColumn; + const name = getColumnCasing(it as IndexedColumn, casing); if ( !is(it, SQL) && it.type! === 'PgVector' @@ -393,7 +397,7 @@ export const generatePgSnapshot = ( withStyle.errorWarning( `You are specifying an index on the ${ chalk.blueBright( - it.name, + name, ) } column inside the ${ chalk.blueBright( @@ -411,7 +415,7 @@ export const generatePgSnapshot = ( ) }].\n\nYou can specify it using current syntax: ${ chalk.underline( - `index("${value.config.name}").using("${value.config.method}", table.${it.name}.op("${ + `index("${value.config.name}").using("${value.config.method}", table.${name}.op("${ vectorOps[0] }"))`, ) @@ -421,7 +425,7 @@ export const generatePgSnapshot = ( ); process.exit(1); } - indexColumnNames.push((it as ExtraConfigColumn).name); + indexColumnNames.push(name); }); const name = value.config.name @@ -440,7 +444,7 @@ export const generatePgSnapshot = ( } else { it = it as IndexedColumn; return { - expression: it.name!, + expression: getColumnCasing(it as IndexedColumn, casing), isExpression: false, asc: it.indexConfig?.order === 'asc', nulls: it.indexConfig?.nulls diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 41edd78a9..b648b5aac 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -20,13 +20,16 @@ import type { Table, UniqueConstraint, } from '../serializer/sqliteSchema'; -import type { SQLiteDB } from '../utils'; +import { getColumnCasing, type SQLiteDB } from '../utils'; import { sqlToStr } from '.'; +import { CasingType } from 'src/cli/validations/common'; +import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; const dialect = new SQLiteSyncDialect(); export const generateSqliteSnapshot = ( tables: AnySQLiteTable[], + casing: CasingType | undefined, ): SQLiteSchemaInternal => { const result: Record = {}; const internal: SQLiteKitInternals = { indexes: {} }; @@ -48,12 +51,13 @@ export const generateSqliteSnapshot = ( } = getTableConfig(table); columns.forEach((column) => { + const name = getColumnCasing(column, casing); const notNull: boolean = column.notNull; const primaryKey: boolean = column.primary; const generated = column.generated; const columnToSet: Column = { - name: column.name, + name, type: column.getSQLType(), primaryKey, notNull, @@ -74,7 +78,7 @@ export const generateSqliteSnapshot = ( if (column.default !== undefined) { if (is(column.default, SQL)) { - columnToSet.default = sqlToStr(column.default); + columnToSet.default = sqlToStr(column.default, casing); } else { columnToSet.default = typeof column.default === 'string' ? `'${column.default}'` @@ -84,7 +88,7 @@ export const generateSqliteSnapshot = ( : column.default; } } - columnsObject[column.name] = columnToSet; + columnsObject[name] = columnToSet; if (column.isUnique) { const existingUnique = indexesObject[column.uniqueName!]; @@ -102,7 +106,7 @@ export const generateSqliteSnapshot = ( ) } on the ${ chalk.underline.blue( - column.name, + name, ) } column is confilcting with a unique constraint name already defined for ${ chalk.underline.blue( @@ -132,8 +136,8 @@ export const generateSqliteSnapshot = ( // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const tableTo = getTableName(referenceFT); - const columnsFrom = reference.columns.map((it) => it.name); - const columnsTo = reference.foreignColumns.map((it) => it.name); + const columnsFrom = reference.columns.map((it) => getColumnCasing(it, casing)); + const columnsTo = reference.foreignColumns.map((it) => getColumnCasing(it, casing)); return { name, tableFrom, @@ -175,7 +179,7 @@ export const generateSqliteSnapshot = ( } return sql; } else { - return it.name; + return getColumnCasing(it, casing); } }); @@ -195,7 +199,7 @@ export const generateSqliteSnapshot = ( }); uniqueConstraints?.map((unq) => { - const columnNames = unq.columns.map((c) => c.name); + const columnNames = unq.columns.map((c) => getColumnCasing(c, casing)); const name = unq.name ?? uniqueKeyName(table, columnNames); @@ -237,11 +241,11 @@ export const generateSqliteSnapshot = ( primaryKeys.forEach((it) => { if (it.columns.length > 1) { primaryKeysObject[it.getName()] = { - columns: it.columns.map((it) => it.name), + columns: it.columns.map((it) => getColumnCasing(it, casing)), name: it.getName(), }; } else { - columnsObject[it.columns[0].name].primaryKey = true; + columnsObject[getColumnCasing(it.columns[0], casing)].primaryKey = true; } }); diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index f26624969..83dead60b 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -11,6 +11,8 @@ import { backwardCompatibleMysqlSchema } from './serializer/mysqlSchema'; import { backwardCompatiblePgSchema } from './serializer/pgSchema'; import { backwardCompatibleSqliteSchema } from './serializer/sqliteSchema'; import type { ProxyParams } from './serializer/studio'; +import { CasingType } from './cli/validations/common'; +import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; export type Proxy = (params: ProxyParams) => Promise; @@ -356,3 +358,12 @@ export function findAddedAndRemoved(columnNames1: string[], columnNames2: string return { addedColumns, removedColumns }; } + +export function getColumnCasing(column: { keyAsName: boolean; name: string | undefined; }, casing: CasingType | undefined) { + if (!column.name) return ''; + return !column.keyAsName || casing === undefined + ? column.name + : casing === 'camel' + ? toCamelCase(column.name) + : toSnakeCase(column.name) +} diff --git a/drizzle-orm/src/column.ts b/drizzle-orm/src/column.ts index b0d6fb9a4..79ba17f12 100644 --- a/drizzle-orm/src/column.ts +++ b/drizzle-orm/src/column.ts @@ -68,9 +68,8 @@ export abstract class Column< declare readonly _: ColumnTypeConfig; - /** @internal */ - readonly keyAsName: boolean; readonly name: string; + readonly keyAsName: boolean; readonly primary: boolean; readonly notNull: boolean; readonly default: T['data'] | SQL | undefined; diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index a7440e24c..374736e73 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -228,15 +228,18 @@ export class IndexedColumn { static readonly [entityKind]: string = 'IndexedColumn'; constructor( name: string | undefined, + keyAsName: boolean, type: string, indexConfig: IndexedExtraConfigType, ) { this.name = name; + this.keyAsName = keyAsName; this.type = type; this.indexConfig = indexConfig; } name: string | undefined; + keyAsName: boolean; type: string; indexConfig: IndexedExtraConfigType; } diff --git a/drizzle-orm/src/pg-core/indexes.ts b/drizzle-orm/src/pg-core/indexes.ts index c0e0888c9..bf53a56ce 100644 --- a/drizzle-orm/src/pg-core/indexes.ts +++ b/drizzle-orm/src/pg-core/indexes.ts @@ -118,7 +118,7 @@ export class IndexBuilderOn { return it; } it = it as ExtraConfigColumn; - const clonedIndexedColumn = new IndexedColumn(it.name, it.columnType!, it.indexConfig!); + const clonedIndexedColumn = new IndexedColumn(it.name, !!it.keyAsName, it.columnType!, it.indexConfig!); it.indexConfig = JSON.parse(JSON.stringify(it.defaultConfig)); return clonedIndexedColumn; }), @@ -135,7 +135,7 @@ export class IndexBuilderOn { return it; } it = it as ExtraConfigColumn; - const clonedIndexedColumn = new IndexedColumn(it.name, it.columnType!, it.indexConfig!); + const clonedIndexedColumn = new IndexedColumn(it.name, !!it.keyAsName, it.columnType!, it.indexConfig!); it.indexConfig = it.defaultConfig; return clonedIndexedColumn; }), @@ -166,7 +166,7 @@ export class IndexBuilderOn { return it; } it = it as ExtraConfigColumn; - const clonedIndexedColumn = new IndexedColumn(it.name, it.columnType!, it.indexConfig!); + const clonedIndexedColumn = new IndexedColumn(it.name, !!it.keyAsName, it.columnType!, it.indexConfig!); it.indexConfig = JSON.parse(JSON.stringify(it.defaultConfig)); return clonedIndexedColumn; }), From 90fd148760bef937018c69b268e1bedc46fcbaea Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 24 Sep 2024 10:38:15 -0700 Subject: [PATCH 186/492] Add PG casing tests --- drizzle-kit/src/serializer/pgSerializer.ts | 32 +++- drizzle-kit/tests/pg-tables.test.ts | 199 +++++++++++++++++++++ 2 files changed, 226 insertions(+), 5 deletions(-) diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 712cab5df..2af10a161 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -33,8 +33,7 @@ import type { import { type DB, getColumnCasing, isPgArrayType } from '../utils'; import { sqlToStr } from '.'; import { CasingType } from 'src/cli/validations/common'; - -const dialect = new PgDialect(); +import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; @@ -121,6 +120,9 @@ export const generatePgSnapshot = ( casing: CasingType | undefined, schemaFilter?: string[], ): PgSchemaInternal => { + const dialect = new PgDialect({ + casing: casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined, + }); const result: Record = {}; const sequencesToReturn: Record = {}; @@ -285,9 +287,18 @@ export const generatePgSnapshot = ( }); primaryKeys.map((pk) => { + const originalColumnNames = pk.columns.map((c) => c.name); const columnNames = pk.columns.map((c) => getColumnCasing(c, casing)); - primaryKeysObject[pk.getName()] = { - name: pk.getName(), + + let name = pk.getName(); + if (casing !== undefined) { + for (let i = 0; i < originalColumnNames.length; i++) { + name = name.replace(originalColumnNames[i], columnNames[i]); + } + } + + primaryKeysObject[name] = { + name, columns: columnNames, }; }); @@ -332,7 +343,6 @@ export const generatePgSnapshot = ( }); const fks: ForeignKey[] = foreignKeys.map((fk) => { - const name = fk.getName(); const tableFrom = tableName; const onDelete = fk.onDelete; const onUpdate = fk.onUpdate; @@ -343,9 +353,21 @@ export const generatePgSnapshot = ( // getTableConfig(reference.foreignTable).schema || "public"; const schemaTo = getTableConfig(reference.foreignTable).schema; + const originalColumnsFrom = reference.columns.map((it) => it.name); const columnsFrom = reference.columns.map((it) => getColumnCasing(it, casing)); + const originalColumnsTo = reference.foreignColumns.map((it) => it.name); const columnsTo = reference.foreignColumns.map((it) => getColumnCasing(it, casing)); + let name = fk.getName(); + if (casing !== undefined) { + for (let i = 0; i < originalColumnsFrom.length; i++) { + name = name.replace(originalColumnsFrom[i], columnsFrom[i]); + } + for (let i = 0; i < originalColumnsTo.length; i++) { + name = name.replace(originalColumnsTo[i], columnsTo[i]); + } + } + return { name, tableFrom, diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index 4171af333..a1481c3a6 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -1,6 +1,7 @@ import { sql } from 'drizzle-orm'; import { AnyPgColumn, + foreignKey, geometry, index, integer, @@ -12,6 +13,8 @@ import { primaryKey, serial, text, + unique, + uniqueIndex, vector, } from 'drizzle-orm/pg-core'; import { expect, test } from 'vitest'; @@ -639,3 +642,199 @@ test('create table with tsvector', async () => { `CREATE INDEX IF NOT EXISTS "title_search_index" ON "posts" USING gin (to_tsvector('english', "title"));`, ]); }); + +test('optional db aliases (snake case)', async () => { + const from = {}; + + const t1 = pgTable( + 't1', + { + t1Id1: integer().notNull().primaryKey(), + t1Col2: integer().notNull(), + t1Col3: integer().notNull(), + t2Ref: integer().notNull().references(() => t2.t2Id), + t1Uni: integer().notNull(), + t1UniIdx: integer().notNull(), + t1Idx: integer().notNull(), + }, + (table) => ({ + uni: unique('t1_uni').on(table.t1Uni), + uniIdx: uniqueIndex('t1_uni_idx').on(table.t1UniIdx), + idx: index('t1_idx').on(table.t1Idx).where(sql`${table.t1Idx} > 0`), + fk: foreignKey({ + columns: [table.t1Col2, table.t1Col3], + foreignColumns: [t3.t3Id1, t3.t3Id2], + }), + }), + ) + + const t2 = pgTable( + 't2', + { + t2Id: serial().primaryKey() + } + ); + + const t3 = pgTable( + 't3', + { + t3Id1: integer(), + t3Id2: integer(), + }, + (table) => ({ + pk: primaryKey({ + columns: [table.t3Id1, table.t3Id2], + }), + }), + ); + + const to = { + t1, + t2, + t3 + }; + + const { sqlStatements } = await diffTestSchemas(from, to, [], false, 'snake'); + + const st1 = `CREATE TABLE IF NOT EXISTS "t1" ( + "t1_id1" integer PRIMARY KEY NOT NULL, + "t1_col2" integer NOT NULL, + "t1_col3" integer NOT NULL, + "t2_ref" integer NOT NULL, + "t1_uni" integer NOT NULL, + "t1_uni_idx" integer NOT NULL, + "t1_idx" integer NOT NULL, + CONSTRAINT "t1_uni" UNIQUE("t1_uni") +); +`; + + const st2 = `CREATE TABLE IF NOT EXISTS "t2" ( + "t2_id" serial PRIMARY KEY NOT NULL +); +`; + + const st3 = `CREATE TABLE IF NOT EXISTS "t3" ( + "t3_id1" integer, + "t3_id2" integer, + CONSTRAINT "t3_t3_id1_t3_id2_pk" PRIMARY KEY("t3_id1","t3_id2") +); +`; + + const st4 = `DO $$ BEGIN + ALTER TABLE "t1" ADD CONSTRAINT "t1_t2_ref_t2_t2_id_fk" FOREIGN KEY ("t2_ref") REFERENCES "public"."t2"("t2_id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +`; + + const st5 = `DO $$ BEGIN + ALTER TABLE "t1" ADD CONSTRAINT "t1_t1_col2_t1_col3_t3_t3_id1_t3_id2_fk" FOREIGN KEY ("t1_col2","t1_col3") REFERENCES "public"."t3"("t3_id1","t3_id2") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +`; + + const st6 = `CREATE UNIQUE INDEX IF NOT EXISTS "t1_uni_idx" ON "t1" USING btree ("t1_uni_idx");`; + + const st7 = `CREATE INDEX IF NOT EXISTS "t1_idx" ON "t1" USING btree ("t1_idx") WHERE "t1"."t1_idx" > 0;`; + + expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6, st7]); +}); + +test('optional db aliases (camel case)', async () => { + const from = {}; + + const t1 = pgTable( + 't1', + { + t1_id1: integer().notNull().primaryKey(), + t1_col2: integer().notNull(), + t1_col3: integer().notNull(), + t2_ref: integer().notNull().references(() => t2.t2_id), + t1_uni: integer().notNull(), + t1_uni_idx: integer().notNull(), + t1_idx: integer().notNull(), + }, + (table) => ({ + uni: unique('t1Uni').on(table.t1_uni), + uni_idx: uniqueIndex('t1UniIdx').on(table.t1_uni_idx), + idx: index('t1Idx').on(table.t1_idx).where(sql`${table.t1_idx} > 0`), + fk: foreignKey({ + columns: [table.t1_col2, table.t1_col3], + foreignColumns: [t3.t3_id1, t3.t3_id2], + }), + }), + ) + + const t2 = pgTable( + 't2', + { + t2_id: serial().primaryKey() + } + ); + + const t3 = pgTable( + 't3', + { + t3_id1: integer(), + t3_id2: integer(), + }, + (table) => ({ + pk: primaryKey({ + columns: [table.t3_id1, table.t3_id2], + }), + }), + ); + + const to = { + t1, + t2, + t3 + }; + + const { sqlStatements } = await diffTestSchemas(from, to, [], false, 'camel'); + + const st1 = `CREATE TABLE IF NOT EXISTS "t1" ( + "t1Id1" integer PRIMARY KEY NOT NULL, + "t1Col2" integer NOT NULL, + "t1Col3" integer NOT NULL, + "t2Ref" integer NOT NULL, + "t1Uni" integer NOT NULL, + "t1UniIdx" integer NOT NULL, + "t1Idx" integer NOT NULL, + CONSTRAINT "t1Uni" UNIQUE("t1Uni") +); +`; + + const st2 = `CREATE TABLE IF NOT EXISTS "t2" ( + "t2Id" serial PRIMARY KEY NOT NULL +); +`; + + const st3 = `CREATE TABLE IF NOT EXISTS "t3" ( + "t3Id1" integer, + "t3Id2" integer, + CONSTRAINT "t3_t3Id1_t3Id2_pk" PRIMARY KEY("t3Id1","t3Id2") +); +`; + + const st4 = `DO $$ BEGIN + ALTER TABLE "t1" ADD CONSTRAINT "t1_t2Ref_t2_t2Id_fk" FOREIGN KEY ("t2Ref") REFERENCES "public"."t2"("t2Id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +`; + + const st5 = `DO $$ BEGIN + ALTER TABLE "t1" ADD CONSTRAINT "t1_t1Col2_t1Col3_t3_t3Id1_t3Id2_fk" FOREIGN KEY ("t1Col2","t1Col3") REFERENCES "public"."t3"("t3Id1","t3Id2") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +`; + + const st6 = `CREATE UNIQUE INDEX IF NOT EXISTS "t1UniIdx" ON "t1" USING btree ("t1UniIdx");`; + + const st7 = `CREATE INDEX IF NOT EXISTS "t1Idx" ON "t1" USING btree ("t1Idx") WHERE "t1"."t1Idx" > 0;`; + + expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6, st7]); +}); \ No newline at end of file From b1d6006829bc126fc2b0cd71270d04c58bef09c5 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 24 Sep 2024 10:38:51 -0700 Subject: [PATCH 187/492] Update schemaDiffer.ts file --- drizzle-kit/tests/schemaDiffer.ts | 65 ++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 3a2a47b6b..4f6ed2457 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -17,6 +17,7 @@ import { tablesResolver, } from 'src/cli/commands/migrate'; import { logSuggestionsAndReturn } from 'src/cli/commands/sqlitePushUtils'; +import { CasingType } from 'src/cli/validations/common'; import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql'; import { schemaToTypeScript } from 'src/introspect-pg'; import { schemaToTypeScript as schemaToTypeScriptSQLite } from 'src/introspect-sqlite'; @@ -412,8 +413,9 @@ export const diffTestSchemasPush = async ( renamesArr: string[], cli: boolean = false, schemas: string[] = ['public'], + casing?: CasingType | undefined ) => { - const { sqlStatements } = await applyPgDiffs(left); + const { sqlStatements } = await applyPgDiffs(left, casing); for (const st of sqlStatements) { await client.query(st); } @@ -443,6 +445,7 @@ export const diffTestSchemasPush = async ( leftEnums, leftSchemas, leftSequences, + casing ); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; @@ -503,7 +506,7 @@ export const diffTestSchemasPush = async ( } }; -export const applyPgDiffs = async (sn: PostgresSchema) => { +export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | undefined) => { const dryRun = { version: '7', dialect: 'postgresql', @@ -528,7 +531,7 @@ export const applyPgDiffs = async (sn: PostgresSchema) => { const sequences = Object.values(sn).filter((it) => isPgSequence(it)) as PgSequence[]; - const serialized1 = generatePgSnapshot(tables, enums, schemas, sequences); + const serialized1 = generatePgSnapshot(tables, enums, schemas, sequences, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -564,6 +567,7 @@ export const diffTestSchemas = async ( right: PostgresSchema, renamesArr: string[], cli: boolean = false, + casing?: CasingType | undefined ) => { const leftTables = Object.values(left).filter((it) => is(it, PgTable)) as PgTable[]; @@ -586,12 +590,14 @@ export const diffTestSchemas = async ( leftEnums, leftSchemas, leftSequences, + casing ); const serialized2 = generatePgSnapshot( rightTables, rightEnums, rightSchemas, rightSequences, + casing ); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -657,8 +663,9 @@ export const diffTestSchemasPushMysql = async ( renamesArr: string[], schema: string, cli: boolean = false, + casing?: CasingType | undefined ) => { - const { sqlStatements } = await applyMySqlDiffs(left); + const { sqlStatements } = await applyMySqlDiffs(left, casing); for (const st of sqlStatements) { await client.query(st); } @@ -675,7 +682,7 @@ export const diffTestSchemasPushMysql = async ( const leftTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - const serialized2 = generateMySqlSnapshot(leftTables); + const serialized2 = generateMySqlSnapshot(leftTables, casing); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -729,7 +736,7 @@ export const diffTestSchemasPushMysql = async ( } }; -export const applyMySqlDiffs = async (sn: MysqlSchema) => { +export const applyMySqlDiffs = async (sn: MysqlSchema, casing: CasingType | undefined) => { const dryRun = { version: '5', dialect: 'mysql', @@ -747,7 +754,7 @@ export const applyMySqlDiffs = async (sn: MysqlSchema) => { const tables = Object.values(sn).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - const serialized1 = generateMySqlSnapshot(tables); + const serialized1 = generateMySqlSnapshot(tables, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -780,13 +787,14 @@ export const diffTestSchemasMysql = async ( right: MysqlSchema, renamesArr: string[], cli: boolean = false, + casing?: CasingType | undefined ) => { const leftTables = Object.values(left).filter((it) => is(it, MySqlTable)) as MySqlTable[]; const rightTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - const serialized1 = generateMySqlSnapshot(leftTables); - const serialized2 = generateMySqlSnapshot(rightTables); + const serialized1 = generateMySqlSnapshot(leftTables, casing); + const serialized2 = generateMySqlSnapshot(rightTables, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -845,6 +853,7 @@ export const diffTestSchemasPushSqlite = async ( renamesArr: string[], cli: boolean = false, seedStatements: string[] = [], + casing?: CasingType | undefined ) => { const { sqlStatements } = await applySqliteDiffs(left, 'push'); @@ -871,7 +880,7 @@ export const diffTestSchemasPushSqlite = async ( const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized2 = generateSqliteSnapshot(rightTables); + const serialized2 = generateSqliteSnapshot(rightTables, casing); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -962,6 +971,7 @@ export async function diffTestSchemasPushLibSQL( renamesArr: string[], cli: boolean = false, seedStatements: string[] = [], + casing?: CasingType | undefined ) { const { sqlStatements } = await applyLibSQLDiffs(left, 'push'); @@ -995,7 +1005,7 @@ export async function diffTestSchemasPushLibSQL( const leftTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized2 = generateSqliteSnapshot(leftTables); + const serialized2 = generateSqliteSnapshot(leftTables, casing); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1088,6 +1098,7 @@ export async function diffTestSchemasPushLibSQL( export const applySqliteDiffs = async ( sn: SqliteSchema, action?: 'push' | undefined, + casing?: CasingType | undefined, ) => { const dryRun = { version: '6', @@ -1106,7 +1117,7 @@ export const applySqliteDiffs = async ( const tables = Object.values(sn).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(tables); + const serialized1 = generateSqliteSnapshot(tables, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -1136,6 +1147,7 @@ export const applySqliteDiffs = async ( export const applyLibSQLDiffs = async ( sn: SqliteSchema, action?: 'push' | undefined, + casing?: CasingType | undefined, ) => { const dryRun = { version: '6', @@ -1154,7 +1166,7 @@ export const applyLibSQLDiffs = async ( const tables = Object.values(sn).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(tables); + const serialized1 = generateSqliteSnapshot(tables, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -1186,13 +1198,14 @@ export const diffTestSchemasSqlite = async ( right: SqliteSchema, renamesArr: string[], cli: boolean = false, + casing?: CasingType | undefined ) => { const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(leftTables); - const serialized2 = generateSqliteSnapshot(rightTables); + const serialized1 = generateSqliteSnapshot(leftTables, casing); + const serialized2 = generateSqliteSnapshot(rightTables, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1246,13 +1259,14 @@ export const diffTestSchemasLibSQL = async ( right: SqliteSchema, renamesArr: string[], cli: boolean = false, + casing?: CasingType | undefined ) => { const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(leftTables); - const serialized2 = generateSqliteSnapshot(rightTables); + const serialized1 = generateSqliteSnapshot(leftTables, casing); + const serialized2 = generateSqliteSnapshot(rightTables, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1308,9 +1322,10 @@ export const introspectPgToFile = async ( initSchema: PostgresSchema, testName: string, schemas: string[] = ['public'], + casing?: CasingType | undefined ) => { // put in db - const { sqlStatements } = await applyPgDiffs(initSchema); + const { sqlStatements } = await applyPgDiffs(initSchema, casing); for (const st of sqlStatements) { await client.query(st); } @@ -1340,6 +1355,7 @@ export const introspectPgToFile = async ( response.enums, response.schemas, response.sequences, + casing ); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -1368,6 +1384,7 @@ export const introspectPgToFile = async ( leftEnums, leftSchemas, leftSequences, + casing ); const { version: initV, dialect: initD, ...initRest } = initSnapshot; @@ -1411,9 +1428,10 @@ export const introspectMySQLToFile = async ( initSchema: MysqlSchema, testName: string, schema: string, + casing?: CasingType | undefined ) => { // put in db - const { sqlStatements } = await applyMySqlDiffs(initSchema); + const { sqlStatements } = await applyMySqlDiffs(initSchema, casing); for (const st of sqlStatements) { await client.query(st); } @@ -1437,7 +1455,7 @@ export const introspectMySQLToFile = async ( `tests/introspect/mysql/${testName}.ts`, ]); - const afterFileImports = generateMySqlSnapshot(response.tables); + const afterFileImports = generateMySqlSnapshot(response.tables, casing); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -1454,7 +1472,7 @@ export const introspectMySQLToFile = async ( const leftTables = Object.values(initSchema).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - const initSnapshot = generateMySqlSnapshot(leftTables); + const initSnapshot = generateMySqlSnapshot(leftTables, casing); const { version: initV, dialect: initD, ...initRest } = initSnapshot; @@ -1493,6 +1511,7 @@ export const introspectSQLiteToFile = async ( client: Database, initSchema: SqliteSchema, testName: string, + casing?: CasingType | undefined ) => { // put in db const { sqlStatements } = await applySqliteDiffs(initSchema); @@ -1521,7 +1540,7 @@ export const introspectSQLiteToFile = async ( `tests/introspect/sqlite/${testName}.ts`, ]); - const afterFileImports = generateSqliteSnapshot(response.tables); + const afterFileImports = generateSqliteSnapshot(response.tables, casing); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -1538,7 +1557,7 @@ export const introspectSQLiteToFile = async ( const leftTables = Object.values(initSchema).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const initSnapshot = generateSqliteSnapshot(leftTables); + const initSnapshot = generateSqliteSnapshot(leftTables, casing); const { version: initV, dialect: initD, ...initRest } = initSnapshot; From db2a55c1e5c3bf41d10f739e1be288192e9990d3 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 24 Sep 2024 10:53:59 -0700 Subject: [PATCH 188/492] Add casing tests to MySQL --- drizzle-kit/src/serializer/mysqlSerializer.ts | 33 +++- drizzle-kit/tests/mysql.test.ts | 180 +++++++++++++++++- 2 files changed, 207 insertions(+), 6 deletions(-) diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 0b6e48de4..6ff3f2bd0 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -23,8 +23,6 @@ import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; // import { MySqlColumnWithAutoIncrement } from "drizzle-orm/mysql-core"; // import { MySqlDateBaseColumn } from "drizzle-orm/mysql-core"; -const dialect = new MySqlDialect(); - export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; }; @@ -33,6 +31,9 @@ export const generateMySqlSnapshot = ( tables: AnyMySqlTable[], casing: CasingType | undefined, ): MySqlSchemaInternal => { + const dialect = new MySqlDialect({ + casing: casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined, + }); const result: Record = {}; const internal: MySqlKitInternals = { tables: {}, indexes: {} }; for (const table of tables) { @@ -158,9 +159,18 @@ export const generateMySqlSnapshot = ( }); primaryKeys.map((pk: PrimaryKeyORM) => { + const originalColumnNames = pk.columns.map((c) => c.name); const columnNames = pk.columns.map((c: any) => getColumnCasing(c, casing)); - primaryKeysObject[pk.getName()] = { - name: pk.getName(), + + let name = pk.getName(); + if (casing !== undefined) { + for (let i = 0; i < originalColumnNames.length; i++) { + name = name.replace(originalColumnNames[i], columnNames[i]); + } + } + + primaryKeysObject[name] = { + name, columns: columnNames, }; @@ -210,7 +220,6 @@ export const generateMySqlSnapshot = ( }); const fks: ForeignKey[] = foreignKeys.map((fk) => { - const name = fk.getName(); const tableFrom = tableName; const onDelete = fk.onDelete ?? 'no action'; const onUpdate = fk.onUpdate ?? 'no action'; @@ -220,8 +229,22 @@ export const generateMySqlSnapshot = ( // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const tableTo = getTableName(referenceFT); + + const originalColumnsFrom = reference.columns.map((it) => it.name); const columnsFrom = reference.columns.map((it) => getColumnCasing(it, casing)); + const originalColumnsTo = reference.foreignColumns.map((it) => it.name); const columnsTo = reference.foreignColumns.map((it) => getColumnCasing(it, casing)); + + let name = fk.getName(); + if (casing !== undefined) { + for (let i = 0; i < originalColumnsFrom.length; i++) { + name = name.replace(originalColumnsFrom[i], columnsFrom[i]); + } + for (let i = 0; i < originalColumnsTo.length; i++) { + name = name.replace(originalColumnsTo[i], columnsTo[i]); + } + } + return { name, tableFrom, diff --git a/drizzle-kit/tests/mysql.test.ts b/drizzle-kit/tests/mysql.test.ts index e7b0b32a5..d34811ced 100644 --- a/drizzle-kit/tests/mysql.test.ts +++ b/drizzle-kit/tests/mysql.test.ts @@ -1,5 +1,5 @@ import { sql } from 'drizzle-orm'; -import { index, json, mysqlSchema, mysqlTable, primaryKey, serial, text, uniqueIndex } from 'drizzle-orm/mysql-core'; +import { foreignKey, index, int, json, mysqlSchema, mysqlTable, primaryKey, serial, text, unique, uniqueIndex } from 'drizzle-orm/mysql-core'; import { expect, test } from 'vitest'; import { diffTestSchemasMysql } from './schemaDiffer'; @@ -555,3 +555,181 @@ test('add table with indexes', async () => { 'CREATE INDEX `indexColExpr` ON `users` ((lower(`email`)),`email`);', ]); }); + +test('optional db aliases (snake case)', async () => { + const from = {}; + + const t1 = mysqlTable( + 't1', + { + t1Id1: int().notNull().primaryKey(), + t1Col2: int().notNull(), + t1Col3: int().notNull(), + t2Ref: int().notNull().references(() => t2.t2Id), + t1Uni: int().notNull(), + t1UniIdx: int().notNull(), + t1Idx: int().notNull(), + }, + (table) => ({ + uni: unique('t1_uni').on(table.t1Uni), + uniIdx: uniqueIndex('t1_uni_idx').on(table.t1UniIdx), + idx: index('t1_idx').on(table.t1Idx), + fk: foreignKey({ + columns: [table.t1Col2, table.t1Col3], + foreignColumns: [t3.t3Id1, t3.t3Id2], + }), + }), + ) + + const t2 = mysqlTable( + 't2', + { + t2Id: serial().primaryKey() + } + ); + + const t3 = mysqlTable( + 't3', + { + t3Id1: int(), + t3Id2: int(), + }, + (table) => ({ + pk: primaryKey({ + columns: [table.t3Id1, table.t3Id2], + }), + }), + ); + + const to = { + t1, + t2, + t3 + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, [], false, 'snake'); + + const st1 = `CREATE TABLE \`t1\` ( + \`t1_id1\` int NOT NULL, + \`t1_col2\` int NOT NULL, + \`t1_col3\` int NOT NULL, + \`t2_ref\` int NOT NULL, + \`t1_uni\` int NOT NULL, + \`t1_uni_idx\` int NOT NULL, + \`t1_idx\` int NOT NULL, + CONSTRAINT \`t1_t1_id1\` PRIMARY KEY(\`t1_id1\`), + CONSTRAINT \`t1_uni\` UNIQUE(\`t1_uni\`), + CONSTRAINT \`t1_uni_idx\` UNIQUE(\`t1_uni_idx\`) +); +`; + + const st2 = `CREATE TABLE \`t2\` ( + \`t2_id\` serial AUTO_INCREMENT NOT NULL, + CONSTRAINT \`t2_t2_id\` PRIMARY KEY(\`t2_id\`) +); +`; + + const st3 = `CREATE TABLE \`t3\` ( + \`t3_id1\` int NOT NULL, + \`t3_id2\` int NOT NULL, + CONSTRAINT \`t3_t3_id1_t3_id2_pk\` PRIMARY KEY(\`t3_id1\`,\`t3_id2\`) +); +`; + + const st4 = `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t2_ref_t2_t2_id_fk\` FOREIGN KEY (\`t2_ref\`) REFERENCES \`t2\`(\`t2_id\`) ON DELETE no action ON UPDATE no action;`; + + const st5 = `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t1_col2_t1_col3_t3_t3_id1_t3_id2_fk\` FOREIGN KEY (\`t1_col2\`,\`t1_col3\`) REFERENCES \`t3\`(\`t3_id1\`,\`t3_id2\`) ON DELETE no action ON UPDATE no action;`; + + const st6 = `CREATE INDEX \`t1_idx\` ON \`t1\` (\`t1_idx\`);`; + + expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6]); +}); + +test('optional db aliases (camel case)', async () => { + const from = {}; + + const t1 = mysqlTable( + 't1', + { + t1_id1: int().notNull().primaryKey(), + t1_col2: int().notNull(), + t1_col3: int().notNull(), + t2_ref: int().notNull().references(() => t2.t2_id), + t1_uni: int().notNull(), + t1_uni_idx: int().notNull(), + t1_idx: int().notNull(), + }, + (table) => ({ + uni: unique('t1Uni').on(table.t1_uni), + uni_idx: uniqueIndex('t1UniIdx').on(table.t1_uni_idx), + idx: index('t1Idx').on(table.t1_idx), + fk: foreignKey({ + columns: [table.t1_col2, table.t1_col3], + foreignColumns: [t3.t3_id1, t3.t3_id2], + }), + }), + ) + + const t2 = mysqlTable( + 't2', + { + t2_id: serial().primaryKey() + } + ); + + const t3 = mysqlTable( + 't3', + { + t3_id1: int(), + t3_id2: int(), + }, + (table) => ({ + pk: primaryKey({ + columns: [table.t3_id1, table.t3_id2], + }), + }), + ); + + const to = { + t1, + t2, + t3 + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, [], false, 'camel'); + + const st1 = `CREATE TABLE \`t1\` ( + \`t1Id1\` int NOT NULL, + \`t1Col2\` int NOT NULL, + \`t1Col3\` int NOT NULL, + \`t2Ref\` int NOT NULL, + \`t1Uni\` int NOT NULL, + \`t1UniIdx\` int NOT NULL, + \`t1Idx\` int NOT NULL, + CONSTRAINT \`t1_t1Id1\` PRIMARY KEY(\`t1Id1\`), + CONSTRAINT \`t1Uni\` UNIQUE(\`t1Uni\`), + CONSTRAINT \`t1UniIdx\` UNIQUE(\`t1UniIdx\`) +); +`; + + const st2 = `CREATE TABLE \`t2\` ( + \`t2Id\` serial AUTO_INCREMENT NOT NULL, + CONSTRAINT \`t2_t2Id\` PRIMARY KEY(\`t2Id\`) +); +`; + + const st3 = `CREATE TABLE \`t3\` ( + \`t3Id1\` int NOT NULL, + \`t3Id2\` int NOT NULL, + CONSTRAINT \`t3_t3Id1_t3Id2_pk\` PRIMARY KEY(\`t3Id1\`,\`t3Id2\`) +); +`; + + const st4 = `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t2Ref_t2_t2Id_fk\` FOREIGN KEY (\`t2Ref\`) REFERENCES \`t2\`(\`t2Id\`) ON DELETE no action ON UPDATE no action;`; + + const st5 = `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t1Col2_t1Col3_t3_t3Id1_t3Id2_fk\` FOREIGN KEY (\`t1Col2\`,\`t1Col3\`) REFERENCES \`t3\`(\`t3Id1\`,\`t3Id2\`) ON DELETE no action ON UPDATE no action;`; + + const st6 = `CREATE INDEX \`t1Idx\` ON \`t1\` (\`t1Idx\`);`; + + expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6]); +}); \ No newline at end of file From 6936c4bbe501e98b4ebe5baf9a6044dcb6dd833b Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 24 Sep 2024 11:09:25 -0700 Subject: [PATCH 189/492] Add SQLite casing serialization tests --- .../src/serializer/sqliteSerializer.ts | 36 +++- drizzle-kit/tests/sqlite-tables.test.ts | 176 +++++++++++++++++- 2 files changed, 205 insertions(+), 7 deletions(-) diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index b648b5aac..3d0eb013a 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -25,12 +25,13 @@ import { sqlToStr } from '.'; import { CasingType } from 'src/cli/validations/common'; import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; -const dialect = new SQLiteSyncDialect(); - export const generateSqliteSnapshot = ( tables: AnySQLiteTable[], casing: CasingType | undefined, ): SQLiteSchemaInternal => { + const dialect = new SQLiteSyncDialect({ + casing: casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined, + }); const result: Record = {}; const internal: SQLiteKitInternals = { indexes: {} }; for (const table of tables) { @@ -126,7 +127,6 @@ export const generateSqliteSnapshot = ( }); const foreignKeys: ForeignKey[] = tableForeignKeys.map((fk) => { - const name = fk.getName(); const tableFrom = tableName; const onDelete = fk.onDelete ?? 'no action'; const onUpdate = fk.onUpdate ?? 'no action'; @@ -136,8 +136,22 @@ export const generateSqliteSnapshot = ( // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const tableTo = getTableName(referenceFT); + + const originalColumnsFrom = reference.columns.map((it) => it.name); const columnsFrom = reference.columns.map((it) => getColumnCasing(it, casing)); + const originalColumnsTo = reference.foreignColumns.map((it) => it.name); const columnsTo = reference.foreignColumns.map((it) => getColumnCasing(it, casing)); + + let name = fk.getName(); + if (casing !== undefined) { + for (let i = 0; i < originalColumnsFrom.length; i++) { + name = name.replace(originalColumnsFrom[i], columnsFrom[i]); + } + for (let i = 0; i < originalColumnsTo.length; i++) { + name = name.replace(originalColumnsTo[i], columnsTo[i]); + } + } + return { name, tableFrom, @@ -240,9 +254,19 @@ export const generateSqliteSnapshot = ( primaryKeys.forEach((it) => { if (it.columns.length > 1) { - primaryKeysObject[it.getName()] = { - columns: it.columns.map((it) => getColumnCasing(it, casing)), - name: it.getName(), + const originalColumnNames = it.columns.map((c) => c.name); + const columnNames = it.columns.map((c) => getColumnCasing(c, casing)); + + let name = it.getName(); + if (casing !== undefined) { + for (let i = 0; i < originalColumnNames.length; i++) { + name = name.replace(originalColumnNames[i], columnNames[i]); + } + } + + primaryKeysObject[name] = { + columns: columnNames, + name }; } else { columnsObject[getColumnCasing(it.columns[0], casing)].primaryKey = true; diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index aa44908ba..358e1a53d 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -1,5 +1,5 @@ import { sql } from 'drizzle-orm'; -import { AnySQLiteColumn, index, int, primaryKey, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'; +import { AnySQLiteColumn, foreignKey, index, int, primaryKey, sqliteTable, text, unique, uniqueIndex } from 'drizzle-orm/sqlite-core'; import { expect, test } from 'vitest'; import { diffTestSchemasSqlite } from './schemaDiffer'; @@ -397,3 +397,177 @@ test('add table with indexes', async () => { 'CREATE INDEX `indexColExpr` ON `users` ((lower("email")),`email`);', ]); }); + +test('optional db aliases (snake case)', async () => { + const from = {}; + + const t1 = sqliteTable( + 't1', + { + t1Id1: int().notNull().primaryKey(), + t1Col2: int().notNull(), + t1Col3: int().notNull(), + t2Ref: int().notNull().references(() => t2.t2Id), + t1Uni: int().notNull(), + t1UniIdx: int().notNull(), + t1Idx: int().notNull(), + }, + (table) => ({ + uni: unique('t1_uni').on(table.t1Uni), + uniIdx: uniqueIndex('t1_uni_idx').on(table.t1UniIdx), + idx: index('t1_idx').on(table.t1Idx), + fk: foreignKey({ + columns: [table.t1Col2, table.t1Col3], + foreignColumns: [t3.t3Id1, t3.t3Id2], + }), + }), + ) + + const t2 = sqliteTable( + 't2', + { + t2Id: int().primaryKey({ autoIncrement: true }) + } + ); + + const t3 = sqliteTable( + 't3', + { + t3Id1: int(), + t3Id2: int(), + }, + (table) => ({ + pk: primaryKey({ + columns: [table.t3Id1, table.t3Id2], + }), + }), + ); + + const to = { + t1, + t2, + t3 + }; + + const { sqlStatements } = await diffTestSchemasSqlite(from, to, [], false, 'snake'); + + const st1 = `CREATE TABLE \`t1\` ( + \`t1_id1\` integer PRIMARY KEY NOT NULL, + \`t1_col2\` integer NOT NULL, + \`t1_col3\` integer NOT NULL, + \`t2_ref\` integer NOT NULL, + \`t1_uni\` integer NOT NULL, + \`t1_uni_idx\` integer NOT NULL, + \`t1_idx\` integer NOT NULL, + FOREIGN KEY (\`t2_ref\`) REFERENCES \`t2\`(\`t2_id\`) ON UPDATE no action ON DELETE no action, + FOREIGN KEY (\`t1_col2\`,\`t1_col3\`) REFERENCES \`t3\`(\`t3_id1\`,\`t3_id2\`) ON UPDATE no action ON DELETE no action +); +`; + + const st2 = `CREATE UNIQUE INDEX \`t1_uni_idx\` ON \`t1\` (\`t1_uni_idx\`);`; + + const st3 = `CREATE INDEX \`t1_idx\` ON \`t1\` (\`t1_idx\`);`; + + const st4 = `CREATE UNIQUE INDEX \`t1_uni\` ON \`t1\` (\`t1_uni\`);`; + + const st5 = `CREATE TABLE \`t2\` ( + \`t2_id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL +); +`; + + const st6 = `CREATE TABLE \`t3\` ( + \`t3_id1\` integer, + \`t3_id2\` integer, + PRIMARY KEY(\`t3_id1\`, \`t3_id2\`) +); +`; + + expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6]); +}); + +test('optional db aliases (camel case)', async () => { + const from = {}; + + const t1 = sqliteTable( + 't1', + { + t1_id1: int().notNull().primaryKey(), + t1_col2: int().notNull(), + t1_col3: int().notNull(), + t2_ref: int().notNull().references(() => t2.t2_id), + t1_uni: int().notNull(), + t1_uni_idx: int().notNull(), + t1_idx: int().notNull(), + }, + (table) => ({ + uni: unique('t1Uni').on(table.t1_uni), + uni_idx: uniqueIndex('t1UniIdx').on(table.t1_uni_idx), + idx: index('t1Idx').on(table.t1_idx), + fk: foreignKey({ + columns: [table.t1_col2, table.t1_col3], + foreignColumns: [t3.t3_id1, t3.t3_id2], + }), + }), + ) + + const t2 = sqliteTable( + 't2', + { + t2_id: int().primaryKey({ autoIncrement: true }) + } + ); + + const t3 = sqliteTable( + 't3', + { + t3_id1: int(), + t3_id2: int(), + }, + (table) => ({ + pk: primaryKey({ + columns: [table.t3_id1, table.t3_id2], + }), + }), + ); + + const to = { + t1, + t2, + t3 + }; + + const { sqlStatements } = await diffTestSchemasSqlite(from, to, [], false, 'camel'); + + const st1 = `CREATE TABLE \`t1\` ( + \`t1Id1\` integer PRIMARY KEY NOT NULL, + \`t1Col2\` integer NOT NULL, + \`t1Col3\` integer NOT NULL, + \`t2Ref\` integer NOT NULL, + \`t1Uni\` integer NOT NULL, + \`t1UniIdx\` integer NOT NULL, + \`t1Idx\` integer NOT NULL, + FOREIGN KEY (\`t2Ref\`) REFERENCES \`t2\`(\`t2Id\`) ON UPDATE no action ON DELETE no action, + FOREIGN KEY (\`t1Col2\`,\`t1Col3\`) REFERENCES \`t3\`(\`t3Id1\`,\`t3Id2\`) ON UPDATE no action ON DELETE no action +); +`; + + const st2 = `CREATE UNIQUE INDEX \`t1UniIdx\` ON \`t1\` (\`t1UniIdx\`);`; + + const st3 = `CREATE INDEX \`t1Idx\` ON \`t1\` (\`t1Idx\`);`; + + const st4 = `CREATE UNIQUE INDEX \`t1Uni\` ON \`t1\` (\`t1Uni\`);`; + + const st5 = `CREATE TABLE \`t2\` ( + \`t2Id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL +); +`; + + const st6 = `CREATE TABLE \`t3\` ( + \`t3Id1\` integer, + \`t3Id2\` integer, + PRIMARY KEY(\`t3Id1\`, \`t3Id2\`) +); +`; + + expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6]); +}); \ No newline at end of file From f21204e0cb0165a1db6cabd60dca0bfa1ccc540d Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 24 Sep 2024 11:17:35 -0700 Subject: [PATCH 190/492] Format --- drizzle-kit/src/cli/commands/migrate.ts | 16 +++---- drizzle-kit/src/cli/commands/push.ts | 10 ++--- drizzle-kit/src/cli/commands/utils.ts | 4 +- drizzle-kit/src/cli/schema.ts | 2 +- drizzle-kit/src/cli/validations/common.ts | 2 +- drizzle-kit/src/migrationPreparator.ts | 4 +- drizzle-kit/src/serializer/index.ts | 8 ++-- drizzle-kit/src/serializer/mysqlSerializer.ts | 6 +-- drizzle-kit/src/serializer/pgSerializer.ts | 6 +-- .../src/serializer/sqliteSerializer.ts | 6 +-- drizzle-kit/src/utils.ts | 15 ++++--- drizzle-kit/tests/mysql.test.ts | 44 +++++++++++++------ drizzle-kit/tests/pg-tables.test.ts | 18 ++++---- drizzle-kit/tests/schemaDiffer.ts | 32 +++++++------- drizzle-kit/tests/sqlite-tables.test.ts | 30 ++++++++----- 15 files changed, 116 insertions(+), 87 deletions(-) diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index ce0f85a40..b24fa77bc 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -169,7 +169,7 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => { const { prev, cur, custom } = await preparePgMigrationSnapshot( snapshots, schemaPath, - casing + casing, ); const validatedPrev = pgSchema.parse(prev); @@ -222,7 +222,7 @@ export const preparePgPush = async ( schemaPath: string | string[], snapshot: PgSchema, schemaFilter: string[], - casing: CasingType | undefined + casing: CasingType | undefined, ) => { const { prev, cur } = await preparePgDbPushSnapshot( snapshot, @@ -314,7 +314,7 @@ export const prepareMySQLPush = async ( const { prev, cur } = await prepareMySqlDbPushSnapshot( snapshot, schemaPath, - casing + casing, ); const validatedPrev = mysqlSchema.parse(prev); @@ -353,7 +353,7 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { const { prev, cur, custom } = await prepareMySqlMigrationSnapshot( snapshots, schemaPath, - casing + casing, ); const validatedPrev = mysqlSchema.parse(prev); @@ -412,7 +412,7 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const { prev, cur, custom } = await prepareSqliteMigrationSnapshot( snapshots, schemaPath, - casing + casing, ); const validatedPrev = sqliteSchema.parse(prev); @@ -473,7 +473,7 @@ export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => { const { prev, cur, custom } = await prepareSqliteMigrationSnapshot( snapshots, schemaPath, - casing + casing, ); const validatedPrev = sqliteSchema.parse(prev); @@ -525,7 +525,7 @@ export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => { export const prepareSQLitePush = async ( schemaPath: string | string[], snapshot: SQLiteSchema, - casing: CasingType | undefined + casing: CasingType | undefined, ) => { const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath, casing); @@ -557,7 +557,7 @@ export const prepareSQLitePush = async ( export const prepareLibSQLPush = async ( schemaPath: string | string[], snapshot: SQLiteSchema, - casing: CasingType | undefined + casing: CasingType | undefined, ) => { const { prev, cur } = await prepareSQLiteDbPushSnapshot(snapshot, schemaPath, casing); diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index b37a6dc1e..d4bd70d08 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -2,6 +2,7 @@ import chalk from 'chalk'; import { render } from 'hanji'; import { fromJson } from '../../sqlgenerator'; import { Select } from '../selector-ui'; +import { CasingType } from '../validations/common'; import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; import { withStyle } from '../validations/outputs'; @@ -11,7 +12,6 @@ import { libSqlLogSuggestionsAndReturn } from './libSqlPushUtils'; import { filterStatements, logSuggestionsAndReturn } from './mysqlPushUtils'; import { pgSuggestions } from './pgPushUtils'; import { logSuggestionsAndReturn as sqliteSuggestions } from './sqlitePushUtils'; -import { CasingType } from '../validations/common'; export const mysqlPush = async ( schemaPath: string | string[], @@ -20,7 +20,7 @@ export const mysqlPush = async ( strict: boolean, verbose: boolean, force: boolean, - casing: CasingType | undefined + casing: CasingType | undefined, ) => { const { connectToMySQL } = await import('../connections'); const { mysqlPushIntrospect } = await import('./mysqlIntrospect'); @@ -161,7 +161,7 @@ export const pgPush = async ( tablesFilter: string[], schemasFilter: string[], force: boolean, - casing: CasingType | undefined + casing: CasingType | undefined, ) => { const { preparePostgresDB } = await import('../connections'); const { pgPushIntrospect } = await import('./pgIntrospect'); @@ -271,7 +271,7 @@ export const sqlitePush = async ( credentials: SqliteCredentials, tablesFilter: string[], force: boolean, - casing: CasingType | undefined + casing: CasingType | undefined, ) => { const { connectToSQLite } = await import('../connections'); const { sqlitePushIntrospect } = await import('./sqliteIntrospect'); @@ -390,7 +390,7 @@ export const libSQLPush = async ( credentials: LibSQLCredentials, tablesFilter: string[], force: boolean, - casing: CasingType | undefined + casing: CasingType | undefined, ) => { const { connectToLibSQL } = await import('../connections'); const { sqlitePushIntrospect } = await import('./sqliteIntrospect'); diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index c9e78ab54..c5b1de8ca 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -139,7 +139,7 @@ export const prepareGenerateConfig = async ( dialect?: Dialect; driver?: Driver; prefix?: Prefix; - casing?: CasingType + casing?: CasingType; }, from: 'config' | 'cli', ): Promise => { @@ -173,7 +173,7 @@ export const prepareGenerateConfig = async ( schema: schema, out: out || 'drizzle', bundle: driver === 'expo', - casing + casing, }; }; diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index e47d58a69..e1baa73cd 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -249,7 +249,7 @@ export const push = command({ 'schemaFilters', 'extensionsFilters', 'tablesFilter', - 'casing' + 'casing', ], ); diff --git a/drizzle-kit/src/cli/validations/common.ts b/drizzle-kit/src/cli/validations/common.ts index 0b64b4dc2..c583f6ef3 100644 --- a/drizzle-kit/src/cli/validations/common.ts +++ b/drizzle-kit/src/cli/validations/common.ts @@ -109,7 +109,7 @@ export const configCommonSchema = object({ schemaFilter: union([string(), string().array()]).default(['public']), migrations: configMigrations, dbCredentials: any().optional(), - casing: casingType + casing: casingType, }).passthrough(); export const casing = union([literal('camel'), literal('preserve')]).default( diff --git a/drizzle-kit/src/migrationPreparator.ts b/drizzle-kit/src/migrationPreparator.ts index 322ebed44..d61f804ca 100644 --- a/drizzle-kit/src/migrationPreparator.ts +++ b/drizzle-kit/src/migrationPreparator.ts @@ -1,10 +1,10 @@ import { randomUUID } from 'crypto'; import fs from 'fs'; +import { CasingType } from './cli/validations/common'; import { serializeMySql, serializePg, serializeSQLite } from './serializer'; import { dryMySql, MySqlSchema, mysqlSchema } from './serializer/mysqlSchema'; import { dryPg, PgSchema, pgSchema, PgSchemaInternal } from './serializer/pgSchema'; import { drySQLite, SQLiteSchema, sqliteSchema } from './serializer/sqliteSchema'; -import { CasingType } from './cli/validations/common'; export const prepareMySqlDbPushSnapshot = async ( prev: MySqlSchema, @@ -139,7 +139,7 @@ export const fillPgSnapshot = ({ export const preparePgMigrationSnapshot = async ( snapshots: string[], schemaPath: string | string[], - casing: CasingType | undefined + casing: CasingType | undefined, ): Promise<{ prev: PgSchema; cur: PgSchema; custom: PgSchema }> => { const prevSnapshot = pgSchema.parse(preparePrevSnapshot(snapshots, dryPg)); const serialized = await serializePg(schemaPath, casing); diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index 4b8d673d5..5a67d1aec 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -1,14 +1,14 @@ import chalk from 'chalk'; import { SQL, Table } from 'drizzle-orm'; +import { CasingCache } from 'drizzle-orm/casing'; import fs from 'fs'; import * as glob from 'glob'; import Path from 'path'; +import { CasingType } from 'src/cli/validations/common'; import { error } from '../cli/views'; import type { MySqlSchemaInternal } from './mysqlSchema'; import type { PgSchemaInternal } from './pgSchema'; import type { SQLiteSchemaInternal } from './sqliteSchema'; -import { CasingType } from 'src/cli/validations/common'; -import { CasingCache } from 'drizzle-orm/casing'; export const sqlToStr = (sql: SQL, casing: CasingType | undefined) => { return sql.toQuery({ @@ -21,7 +21,7 @@ export const sqlToStr = (sql: SQL, casing: CasingType | undefined) => { escapeString: () => { throw new Error("we don't support params for `sql` default values"); }, - casing: new CasingCache(casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined) + casing: new CasingCache(casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined), }).sql; }; @@ -36,7 +36,7 @@ export const sqlToStrGenerated = (sql: SQL, casing: CasingType | undefined) => { escapeString: () => { throw new Error("we don't support params for `sql` default values"); }, - casing: new CasingCache(casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined) + casing: new CasingCache(casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined), }).sql; }; diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 6ff3f2bd0..83512991f 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -1,9 +1,11 @@ import chalk from 'chalk'; import { getTableName, is } from 'drizzle-orm'; import { SQL } from 'drizzle-orm'; +import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; import { AnyMySqlTable, MySqlDialect, type PrimaryKey as PrimaryKeyORM, uniqueKeyName } from 'drizzle-orm/mysql-core'; import { getTableConfig } from 'drizzle-orm/mysql-core'; import { RowDataPacket } from 'mysql2/promise'; +import { CasingType } from 'src/cli/validations/common'; import { withStyle } from '../cli/validations/outputs'; import { IntrospectStage, IntrospectStatus } from '../cli/views'; import { @@ -16,10 +18,8 @@ import { Table, UniqueConstraint, } from '../serializer/mysqlSchema'; -import { getColumnCasing, type DB } from '../utils'; +import { type DB, getColumnCasing } from '../utils'; import { sqlToStr } from '.'; -import { CasingType } from 'src/cli/validations/common'; -import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; // import { MySqlColumnWithAutoIncrement } from "drizzle-orm/mysql-core"; // import { MySqlDateBaseColumn } from "drizzle-orm/mysql-core"; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 2af10a161..bfa9ece19 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -1,5 +1,6 @@ import chalk from 'chalk'; import { getTableName, is, SQL } from 'drizzle-orm'; +import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; import { AnyPgTable, ExtraConfigColumn, @@ -14,6 +15,7 @@ import { uniqueKeyName, } from 'drizzle-orm/pg-core'; import { getTableConfig } from 'drizzle-orm/pg-core'; +import { CasingType } from 'src/cli/validations/common'; import { vectorOps } from 'src/extensions/vector'; import { withStyle } from '../cli/validations/outputs'; import type { IntrospectStage, IntrospectStatus } from '../cli/views'; @@ -32,8 +34,6 @@ import type { } from '../serializer/pgSchema'; import { type DB, getColumnCasing, isPgArrayType } from '../utils'; import { sqlToStr } from '.'; -import { CasingType } from 'src/cli/validations/common'; -import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; @@ -289,7 +289,7 @@ export const generatePgSnapshot = ( primaryKeys.map((pk) => { const originalColumnNames = pk.columns.map((c) => c.name); const columnNames = pk.columns.map((c) => getColumnCasing(c, casing)); - + let name = pk.getName(); if (casing !== undefined) { for (let i = 0; i < originalColumnNames.length; i++) { diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 3d0eb013a..e56050882 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -1,5 +1,6 @@ import chalk from 'chalk'; import { getTableName, is, SQL } from 'drizzle-orm'; +import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; import { // AnySQLiteColumnBuilder, AnySQLiteTable, @@ -8,6 +9,7 @@ import { SQLiteSyncDialect, uniqueKeyName, } from 'drizzle-orm/sqlite-core'; +import { CasingType } from 'src/cli/validations/common'; import { withStyle } from '../cli/validations/outputs'; import type { IntrospectStage, IntrospectStatus } from '../cli/views'; import type { @@ -22,8 +24,6 @@ import type { } from '../serializer/sqliteSchema'; import { getColumnCasing, type SQLiteDB } from '../utils'; import { sqlToStr } from '.'; -import { CasingType } from 'src/cli/validations/common'; -import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; export const generateSqliteSnapshot = ( tables: AnySQLiteTable[], @@ -266,7 +266,7 @@ export const generateSqliteSnapshot = ( primaryKeysObject[name] = { columns: columnNames, - name + name, }; } else { columnsObject[getColumnCasing(it.columns[0], casing)].primaryKey = true; diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 83dead60b..9cad8f9cc 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -1,9 +1,11 @@ import type { RunResult } from 'better-sqlite3'; import chalk from 'chalk'; +import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs'; import { join } from 'path'; import { parse } from 'url'; import type { NamedWithSchema } from './cli/commands/migrate'; +import { CasingType } from './cli/validations/common'; import { info } from './cli/views'; import { assertUnreachable, snapshotVersion } from './global'; import type { Dialect } from './schemaValidator'; @@ -11,8 +13,6 @@ import { backwardCompatibleMysqlSchema } from './serializer/mysqlSchema'; import { backwardCompatiblePgSchema } from './serializer/pgSchema'; import { backwardCompatibleSqliteSchema } from './serializer/sqliteSchema'; import type { ProxyParams } from './serializer/studio'; -import { CasingType } from './cli/validations/common'; -import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; export type Proxy = (params: ProxyParams) => Promise; @@ -359,11 +359,14 @@ export function findAddedAndRemoved(columnNames1: string[], columnNames2: string return { addedColumns, removedColumns }; } -export function getColumnCasing(column: { keyAsName: boolean; name: string | undefined; }, casing: CasingType | undefined) { +export function getColumnCasing( + column: { keyAsName: boolean; name: string | undefined }, + casing: CasingType | undefined, +) { if (!column.name) return ''; return !column.keyAsName || casing === undefined - ? column.name - : casing === 'camel' + ? column.name + : casing === 'camel' ? toCamelCase(column.name) - : toSnakeCase(column.name) + : toSnakeCase(column.name); } diff --git a/drizzle-kit/tests/mysql.test.ts b/drizzle-kit/tests/mysql.test.ts index d34811ced..b6d1b4b57 100644 --- a/drizzle-kit/tests/mysql.test.ts +++ b/drizzle-kit/tests/mysql.test.ts @@ -1,5 +1,17 @@ import { sql } from 'drizzle-orm'; -import { foreignKey, index, int, json, mysqlSchema, mysqlTable, primaryKey, serial, text, unique, uniqueIndex } from 'drizzle-orm/mysql-core'; +import { + foreignKey, + index, + int, + json, + mysqlSchema, + mysqlTable, + primaryKey, + serial, + text, + unique, + uniqueIndex, +} from 'drizzle-orm/mysql-core'; import { expect, test } from 'vitest'; import { diffTestSchemasMysql } from './schemaDiffer'; @@ -579,13 +591,13 @@ test('optional db aliases (snake case)', async () => { foreignColumns: [t3.t3Id1, t3.t3Id2], }), }), - ) + ); const t2 = mysqlTable( 't2', { - t2Id: serial().primaryKey() - } + t2Id: serial().primaryKey(), + }, ); const t3 = mysqlTable( @@ -604,7 +616,7 @@ test('optional db aliases (snake case)', async () => { const to = { t1, t2, - t3 + t3, }; const { sqlStatements } = await diffTestSchemasMysql(from, to, [], false, 'snake'); @@ -636,9 +648,11 @@ test('optional db aliases (snake case)', async () => { ); `; - const st4 = `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t2_ref_t2_t2_id_fk\` FOREIGN KEY (\`t2_ref\`) REFERENCES \`t2\`(\`t2_id\`) ON DELETE no action ON UPDATE no action;`; + const st4 = + `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t2_ref_t2_t2_id_fk\` FOREIGN KEY (\`t2_ref\`) REFERENCES \`t2\`(\`t2_id\`) ON DELETE no action ON UPDATE no action;`; - const st5 = `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t1_col2_t1_col3_t3_t3_id1_t3_id2_fk\` FOREIGN KEY (\`t1_col2\`,\`t1_col3\`) REFERENCES \`t3\`(\`t3_id1\`,\`t3_id2\`) ON DELETE no action ON UPDATE no action;`; + const st5 = + `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t1_col2_t1_col3_t3_t3_id1_t3_id2_fk\` FOREIGN KEY (\`t1_col2\`,\`t1_col3\`) REFERENCES \`t3\`(\`t3_id1\`,\`t3_id2\`) ON DELETE no action ON UPDATE no action;`; const st6 = `CREATE INDEX \`t1_idx\` ON \`t1\` (\`t1_idx\`);`; @@ -668,13 +682,13 @@ test('optional db aliases (camel case)', async () => { foreignColumns: [t3.t3_id1, t3.t3_id2], }), }), - ) + ); const t2 = mysqlTable( 't2', { - t2_id: serial().primaryKey() - } + t2_id: serial().primaryKey(), + }, ); const t3 = mysqlTable( @@ -693,7 +707,7 @@ test('optional db aliases (camel case)', async () => { const to = { t1, t2, - t3 + t3, }; const { sqlStatements } = await diffTestSchemasMysql(from, to, [], false, 'camel'); @@ -725,11 +739,13 @@ test('optional db aliases (camel case)', async () => { ); `; - const st4 = `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t2Ref_t2_t2Id_fk\` FOREIGN KEY (\`t2Ref\`) REFERENCES \`t2\`(\`t2Id\`) ON DELETE no action ON UPDATE no action;`; + const st4 = + `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t2Ref_t2_t2Id_fk\` FOREIGN KEY (\`t2Ref\`) REFERENCES \`t2\`(\`t2Id\`) ON DELETE no action ON UPDATE no action;`; - const st5 = `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t1Col2_t1Col3_t3_t3Id1_t3Id2_fk\` FOREIGN KEY (\`t1Col2\`,\`t1Col3\`) REFERENCES \`t3\`(\`t3Id1\`,\`t3Id2\`) ON DELETE no action ON UPDATE no action;`; + const st5 = + `ALTER TABLE \`t1\` ADD CONSTRAINT \`t1_t1Col2_t1Col3_t3_t3Id1_t3Id2_fk\` FOREIGN KEY (\`t1Col2\`,\`t1Col3\`) REFERENCES \`t3\`(\`t3Id1\`,\`t3Id2\`) ON DELETE no action ON UPDATE no action;`; const st6 = `CREATE INDEX \`t1Idx\` ON \`t1\` (\`t1Idx\`);`; expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6]); -}); \ No newline at end of file +}); diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index a1481c3a6..a9face31f 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -666,13 +666,13 @@ test('optional db aliases (snake case)', async () => { foreignColumns: [t3.t3Id1, t3.t3Id2], }), }), - ) + ); const t2 = pgTable( 't2', { - t2Id: serial().primaryKey() - } + t2Id: serial().primaryKey(), + }, ); const t3 = pgTable( @@ -691,7 +691,7 @@ test('optional db aliases (snake case)', async () => { const to = { t1, t2, - t3 + t3, }; const { sqlStatements } = await diffTestSchemas(from, to, [], false, 'snake'); @@ -764,13 +764,13 @@ test('optional db aliases (camel case)', async () => { foreignColumns: [t3.t3_id1, t3.t3_id2], }), }), - ) + ); const t2 = pgTable( 't2', { - t2_id: serial().primaryKey() - } + t2_id: serial().primaryKey(), + }, ); const t3 = pgTable( @@ -789,7 +789,7 @@ test('optional db aliases (camel case)', async () => { const to = { t1, t2, - t3 + t3, }; const { sqlStatements } = await diffTestSchemas(from, to, [], false, 'camel'); @@ -837,4 +837,4 @@ END $$; const st7 = `CREATE INDEX IF NOT EXISTS "t1Idx" ON "t1" USING btree ("t1Idx") WHERE "t1"."t1Idx" > 0;`; expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6, st7]); -}); \ No newline at end of file +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 4f6ed2457..22a79ef72 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -413,7 +413,7 @@ export const diffTestSchemasPush = async ( renamesArr: string[], cli: boolean = false, schemas: string[] = ['public'], - casing?: CasingType | undefined + casing?: CasingType | undefined, ) => { const { sqlStatements } = await applyPgDiffs(left, casing); for (const st of sqlStatements) { @@ -445,7 +445,7 @@ export const diffTestSchemasPush = async ( leftEnums, leftSchemas, leftSequences, - casing + casing, ); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; @@ -567,7 +567,7 @@ export const diffTestSchemas = async ( right: PostgresSchema, renamesArr: string[], cli: boolean = false, - casing?: CasingType | undefined + casing?: CasingType | undefined, ) => { const leftTables = Object.values(left).filter((it) => is(it, PgTable)) as PgTable[]; @@ -590,14 +590,14 @@ export const diffTestSchemas = async ( leftEnums, leftSchemas, leftSequences, - casing + casing, ); const serialized2 = generatePgSnapshot( rightTables, rightEnums, rightSchemas, rightSequences, - casing + casing, ); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -663,7 +663,7 @@ export const diffTestSchemasPushMysql = async ( renamesArr: string[], schema: string, cli: boolean = false, - casing?: CasingType | undefined + casing?: CasingType | undefined, ) => { const { sqlStatements } = await applyMySqlDiffs(left, casing); for (const st of sqlStatements) { @@ -787,7 +787,7 @@ export const diffTestSchemasMysql = async ( right: MysqlSchema, renamesArr: string[], cli: boolean = false, - casing?: CasingType | undefined + casing?: CasingType | undefined, ) => { const leftTables = Object.values(left).filter((it) => is(it, MySqlTable)) as MySqlTable[]; @@ -853,7 +853,7 @@ export const diffTestSchemasPushSqlite = async ( renamesArr: string[], cli: boolean = false, seedStatements: string[] = [], - casing?: CasingType | undefined + casing?: CasingType | undefined, ) => { const { sqlStatements } = await applySqliteDiffs(left, 'push'); @@ -971,7 +971,7 @@ export async function diffTestSchemasPushLibSQL( renamesArr: string[], cli: boolean = false, seedStatements: string[] = [], - casing?: CasingType | undefined + casing?: CasingType | undefined, ) { const { sqlStatements } = await applyLibSQLDiffs(left, 'push'); @@ -1198,7 +1198,7 @@ export const diffTestSchemasSqlite = async ( right: SqliteSchema, renamesArr: string[], cli: boolean = false, - casing?: CasingType | undefined + casing?: CasingType | undefined, ) => { const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; @@ -1259,7 +1259,7 @@ export const diffTestSchemasLibSQL = async ( right: SqliteSchema, renamesArr: string[], cli: boolean = false, - casing?: CasingType | undefined + casing?: CasingType | undefined, ) => { const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; @@ -1322,7 +1322,7 @@ export const introspectPgToFile = async ( initSchema: PostgresSchema, testName: string, schemas: string[] = ['public'], - casing?: CasingType | undefined + casing?: CasingType | undefined, ) => { // put in db const { sqlStatements } = await applyPgDiffs(initSchema, casing); @@ -1355,7 +1355,7 @@ export const introspectPgToFile = async ( response.enums, response.schemas, response.sequences, - casing + casing, ); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -1384,7 +1384,7 @@ export const introspectPgToFile = async ( leftEnums, leftSchemas, leftSequences, - casing + casing, ); const { version: initV, dialect: initD, ...initRest } = initSnapshot; @@ -1428,7 +1428,7 @@ export const introspectMySQLToFile = async ( initSchema: MysqlSchema, testName: string, schema: string, - casing?: CasingType | undefined + casing?: CasingType | undefined, ) => { // put in db const { sqlStatements } = await applyMySqlDiffs(initSchema, casing); @@ -1511,7 +1511,7 @@ export const introspectSQLiteToFile = async ( client: Database, initSchema: SqliteSchema, testName: string, - casing?: CasingType | undefined + casing?: CasingType | undefined, ) => { // put in db const { sqlStatements } = await applySqliteDiffs(initSchema); diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index 358e1a53d..0f87c44e4 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -1,5 +1,15 @@ import { sql } from 'drizzle-orm'; -import { AnySQLiteColumn, foreignKey, index, int, primaryKey, sqliteTable, text, unique, uniqueIndex } from 'drizzle-orm/sqlite-core'; +import { + AnySQLiteColumn, + foreignKey, + index, + int, + primaryKey, + sqliteTable, + text, + unique, + uniqueIndex, +} from 'drizzle-orm/sqlite-core'; import { expect, test } from 'vitest'; import { diffTestSchemasSqlite } from './schemaDiffer'; @@ -421,13 +431,13 @@ test('optional db aliases (snake case)', async () => { foreignColumns: [t3.t3Id1, t3.t3Id2], }), }), - ) + ); const t2 = sqliteTable( 't2', { - t2Id: int().primaryKey({ autoIncrement: true }) - } + t2Id: int().primaryKey({ autoIncrement: true }), + }, ); const t3 = sqliteTable( @@ -446,7 +456,7 @@ test('optional db aliases (snake case)', async () => { const to = { t1, t2, - t3 + t3, }; const { sqlStatements } = await diffTestSchemasSqlite(from, to, [], false, 'snake'); @@ -508,13 +518,13 @@ test('optional db aliases (camel case)', async () => { foreignColumns: [t3.t3_id1, t3.t3_id2], }), }), - ) + ); const t2 = sqliteTable( 't2', { - t2_id: int().primaryKey({ autoIncrement: true }) - } + t2_id: int().primaryKey({ autoIncrement: true }), + }, ); const t3 = sqliteTable( @@ -533,7 +543,7 @@ test('optional db aliases (camel case)', async () => { const to = { t1, t2, - t3 + t3, }; const { sqlStatements } = await diffTestSchemasSqlite(from, to, [], false, 'camel'); @@ -570,4 +580,4 @@ test('optional db aliases (camel case)', async () => { `; expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6]); -}); \ No newline at end of file +}); From cc61485de7362c16c6bc4846064f5d8c4c904e2a Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 24 Sep 2024 11:27:26 -0700 Subject: [PATCH 191/492] Fix api.ts file errors --- drizzle-kit/src/api.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 00cdb1b61..51e5dfcfc 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -15,6 +15,7 @@ import { pgSuggestions } from './cli/commands/pgPushUtils'; import { updateUpToV6 as upPgV6, updateUpToV7 as upPgV7 } from './cli/commands/pgUp'; import { sqlitePushIntrospect } from './cli/commands/sqliteIntrospect'; import { logSuggestionsAndReturn } from './cli/commands/sqlitePushUtils'; +import type { CasingType } from './cli/validations/common'; import { originUUID } from './global'; import { fillPgSnapshot } from './migrationPreparator'; import { MySqlSchema as MySQLSchemaKit, mysqlSchema, squashMysqlScheme } from './serializer/mysqlSchema'; @@ -33,6 +34,7 @@ export const generateDrizzleJson = ( imports: Record, prevId?: string, schemaFilters?: string[], + casing?: CasingType, ): PgSchemaKit => { const prepared = prepareFromExports(imports); @@ -43,6 +45,7 @@ export const generateDrizzleJson = ( prepared.enums, prepared.schemas, prepared.sequences, + casing, schemaFilters, ); @@ -140,6 +143,7 @@ export const pushSchema = async ( export const generateSQLiteDrizzleJson = async ( imports: Record, prevId?: string, + casing?: CasingType, ): Promise => { const { prepareFromExports } = await import('./serializer/sqliteImports'); @@ -147,7 +151,7 @@ export const generateSQLiteDrizzleJson = async ( const id = randomUUID(); - const snapshot = generateSqliteSnapshot(prepared.tables); + const snapshot = generateSqliteSnapshot(prepared.tables, casing); return { ...snapshot, @@ -243,6 +247,7 @@ export const pushSQLiteSchema = async ( export const generateMySQLDrizzleJson = async ( imports: Record, prevId?: string, + casing?: CasingType, ): Promise => { const { prepareFromExports } = await import('./serializer/mysqlImports'); @@ -250,7 +255,7 @@ export const generateMySQLDrizzleJson = async ( const id = randomUUID(); - const snapshot = generateMySqlSnapshot(prepared.tables); + const snapshot = generateMySqlSnapshot(prepared.tables, casing); return { ...snapshot, From c7d9b41585ea6e04314bc7ab7fb2f01b1ef71446 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 24 Sep 2024 11:39:03 -0700 Subject: [PATCH 192/492] Update tests --- drizzle-kit/tests/cli-generate.test.ts | 9 +++++++++ drizzle-kit/tests/cli-migrate.test.ts | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/drizzle-kit/tests/cli-generate.test.ts b/drizzle-kit/tests/cli-generate.test.ts index 56a3a0d04..6c8cae09e 100644 --- a/drizzle-kit/tests/cli-generate.test.ts +++ b/drizzle-kit/tests/cli-generate.test.ts @@ -38,6 +38,7 @@ test('generate #1', async (t) => { schema: 'schema.ts', out: 'drizzle', bundle: false, + casing: undefined, }); }); @@ -57,6 +58,7 @@ test('generate #2', async (t) => { schema: 'schema.ts', out: 'out', bundle: false, + casing: undefined, }); }); @@ -73,6 +75,7 @@ test('generate #3', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + casing: undefined, }); }); @@ -90,6 +93,7 @@ test('generate #4', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + casing: undefined, }); }); @@ -106,6 +110,7 @@ test('generate #5', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + casing: undefined, }); }); @@ -122,6 +127,7 @@ test('generate #6', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + casing: undefined, }); }); @@ -141,6 +147,7 @@ test('generate #7', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: false, + casing: undefined, }); }); @@ -158,6 +165,7 @@ test('generate #8', async (t) => { schema: './schema.ts', out: 'drizzle', bundle: true, // expo driver + casing: undefined, }); }); @@ -178,6 +186,7 @@ test('generate #9', async (t) => { schema: 'schema.ts', out: 'out', bundle: false, + casing: undefined, }); }); diff --git a/drizzle-kit/tests/cli-migrate.test.ts b/drizzle-kit/tests/cli-migrate.test.ts index 1425691f0..67d593f7f 100644 --- a/drizzle-kit/tests/cli-migrate.test.ts +++ b/drizzle-kit/tests/cli-migrate.test.ts @@ -24,6 +24,7 @@ test('migrate #1', async (t) => { }, schema: undefined, // drizzle migrations table schema table: undefined, // drizzle migrations table name + casing: undefined, }); }); @@ -39,6 +40,7 @@ test('migrate #2', async (t) => { }, schema: undefined, // drizzle migrations table schema table: undefined, // drizzle migrations table name + casing: undefined, }); }); @@ -56,6 +58,7 @@ test('migrate #3', async (t) => { }, schema: undefined, // drizzle migrations table schema table: undefined, // drizzle migrations table name + casing: undefined, }); }); @@ -74,6 +77,7 @@ test('migrate #4', async (t) => { }, schema: undefined, // drizzle migrations table schema table: undefined, // drizzle migrations table name + casing: undefined, }); }); @@ -93,6 +97,7 @@ test('migrate #5', async (t) => { }, schema: 'custom', // drizzle migrations table schema table: 'custom', // drizzle migrations table name + casing: undefined, }); }); From f79698063b7176f407851ee059febb7cb3d1abad Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 24 Sep 2024 12:08:42 -0700 Subject: [PATCH 193/492] Update tests --- drizzle-kit/src/cli/commands/utils.ts | 1 + drizzle-kit/src/cli/validations/common.ts | 2 +- drizzle-kit/src/index.ts | 2 +- drizzle-kit/tests/cli-migrate.test.ts | 5 ----- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index c5b1de8ca..e58e23435 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -720,6 +720,7 @@ export const drizzleConfigFromFile = async ( // --- get response and then check by each dialect independently const res = configCommonSchema.safeParse(content); if (!res.success) { + console.log(res.error); if (!('dialect' in content)) { console.log(error("Please specify 'dialect' param in config file")); } diff --git a/drizzle-kit/src/cli/validations/common.ts b/drizzle-kit/src/cli/validations/common.ts index c583f6ef3..c54edfaf5 100644 --- a/drizzle-kit/src/cli/validations/common.ts +++ b/drizzle-kit/src/cli/validations/common.ts @@ -109,7 +109,7 @@ export const configCommonSchema = object({ schemaFilter: union([string(), string().array()]).default(['public']), migrations: configMigrations, dbCredentials: any().optional(), - casing: casingType, + casing: casingType.optional(), }).passthrough(); export const casing = union([literal('camel'), literal('preserve')]).default( diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 009eb2846..41373faba 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -117,7 +117,7 @@ export type Config = schema?: string | string[]; verbose?: boolean; strict?: boolean; - casing: 'camel' | 'snake'; + casing?: 'camel' | 'snake'; migrations?: { table?: string; schema?: string; diff --git a/drizzle-kit/tests/cli-migrate.test.ts b/drizzle-kit/tests/cli-migrate.test.ts index 67d593f7f..1425691f0 100644 --- a/drizzle-kit/tests/cli-migrate.test.ts +++ b/drizzle-kit/tests/cli-migrate.test.ts @@ -24,7 +24,6 @@ test('migrate #1', async (t) => { }, schema: undefined, // drizzle migrations table schema table: undefined, // drizzle migrations table name - casing: undefined, }); }); @@ -40,7 +39,6 @@ test('migrate #2', async (t) => { }, schema: undefined, // drizzle migrations table schema table: undefined, // drizzle migrations table name - casing: undefined, }); }); @@ -58,7 +56,6 @@ test('migrate #3', async (t) => { }, schema: undefined, // drizzle migrations table schema table: undefined, // drizzle migrations table name - casing: undefined, }); }); @@ -77,7 +74,6 @@ test('migrate #4', async (t) => { }, schema: undefined, // drizzle migrations table schema table: undefined, // drizzle migrations table name - casing: undefined, }); }); @@ -97,7 +93,6 @@ test('migrate #5', async (t) => { }, schema: 'custom', // drizzle migrations table schema table: 'custom', // drizzle migrations table name - casing: undefined, }); }); From 542eb12db3e6352d6bf3bbaff1e9b575fe9bdbe8 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 24 Sep 2024 12:19:01 -0700 Subject: [PATCH 194/492] Update tests --- drizzle-kit/src/cli/validations/cli.ts | 2 +- drizzle-kit/tests/cli-push.test.ts | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index 219ddc4b6..aa92f7c6d 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -17,7 +17,7 @@ export type CliConfigGenerate = TypeOf; export const pushParams = object({ dialect: dialect, - casing: casingType, + casing: casingType.optional(), schema: union([string(), string().array()]), tablesFilter: union([string(), string().array()]).optional(), schemaFilter: union([string(), string().array()]) diff --git a/drizzle-kit/tests/cli-push.test.ts b/drizzle-kit/tests/cli-push.test.ts index f5b84fdce..961b08a2d 100644 --- a/drizzle-kit/tests/cli-push.test.ts +++ b/drizzle-kit/tests/cli-push.test.ts @@ -15,6 +15,7 @@ import { push } from '../src/cli/schema'; test('push #1', async (t) => { const res = await brotest(push, ''); + console.log(res); if (res.type !== 'handler') assert.fail(res.type, 'handler'); expect(res.options).toStrictEqual({ dialect: 'postgresql', @@ -27,6 +28,7 @@ test('push #1', async (t) => { tablesFilter: [], strict: false, verbose: false, + casing: undefined, }); }); @@ -45,6 +47,7 @@ test('push #2', async (t) => { tablesFilter: [], strict: false, verbose: false, + casing: undefined, }); }); @@ -65,6 +68,7 @@ test('push #3', async (t) => { tablesFilter: [], strict: false, verbose: false, + casing: undefined, }); }); @@ -86,6 +90,7 @@ test('push #4', async (t) => { tablesFilter: [], strict: false, verbose: false, + casing: undefined, }); }); @@ -108,6 +113,7 @@ test('push #5', async (t) => { strict: false, force: false, verbose: false, + casing: undefined, }); }); From c0d0181411a0f687d61fb071bc57d33c44b168d6 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 25 Sep 2024 12:58:24 +0300 Subject: [PATCH 195/492] added generate for mysql views --- drizzle-kit/src/api.ts | 6 +- drizzle-kit/src/cli/commands/migrate.ts | 26 ++- drizzle-kit/src/jsonDiffer.js | 8 +- drizzle-kit/src/jsonStatements.ts | 71 +++++-- drizzle-kit/src/serializer/index.ts | 4 +- drizzle-kit/src/serializer/mysqlImports.ts | 13 +- drizzle-kit/src/serializer/mysqlSchema.ts | 57 ++++++ drizzle-kit/src/serializer/mysqlSerializer.ts | 130 ++++++++++++- drizzle-kit/src/snapshotsDiffer.ts | 182 ++++++++++++++---- drizzle-kit/src/sqlgenerator.ts | 53 ++++- drizzle-kit/tests/pg-views.test.ts | 29 ++- 11 files changed, 514 insertions(+), 65 deletions(-) diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 742647952..cd133e97b 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -1,11 +1,11 @@ import { randomUUID } from 'crypto'; -import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; import { LibSQLDatabase } from 'drizzle-orm/libsql'; import type { MySql2Database } from 'drizzle-orm/mysql2'; import { PgDatabase } from 'drizzle-orm/pg-core'; import { columnsResolver, enumsResolver, + mySqlViewsResolver, schemasResolver, sequencesResolver, tablesResolver, @@ -255,7 +255,7 @@ export const generateMySQLDrizzleJson = async ( const id = randomUUID(); - const snapshot = generateMySqlSnapshot(prepared.tables); + const snapshot = generateMySqlSnapshot(prepared.tables, prepared.views); return { ...snapshot, @@ -281,6 +281,7 @@ export const generateMySQLMigration = async ( squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, ); @@ -322,6 +323,7 @@ export const pushMySQLSchema = async ( squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, 'push', diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index b6c28edb7..02bd64d8b 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -13,7 +13,7 @@ import { render } from 'hanji'; import path, { join } from 'path'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; -import { MySqlSchema, mysqlSchema, squashMysqlScheme } from '../../serializer/mysqlSchema'; +import { MySqlSchema, mysqlSchema, squashMysqlScheme, ViewSquashed } from '../../serializer/mysqlSchema'; import { PgSchema, pgSchema, squashPgScheme, View } from '../../serializer/pgSchema'; import { SQLiteSchema, sqliteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; import { @@ -114,6 +114,28 @@ export const viewsResolver = async ( } }; +export const mySqlViewsResolver = async ( + input: ResolverInput, +): Promise> => { + try { + const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict( + input.created, + input.deleted, + 'view', + ); + + return { + created: created, + deleted: deleted, + moved: moved, + renamed: renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; + export const sequencesResolver = async ( input: ResolverInput, ): Promise> => { @@ -346,6 +368,7 @@ export const prepareMySQLPush = async ( squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, 'push', @@ -397,6 +420,7 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, ); diff --git a/drizzle-kit/src/jsonDiffer.js b/drizzle-kit/src/jsonDiffer.js index fcdd533f5..9d6ee782b 100644 --- a/drizzle-kit/src/jsonDiffer.js +++ b/drizzle-kit/src/jsonDiffer.js @@ -294,9 +294,12 @@ export function applyJsonDiff(json1, json2) { if (droppedUsing) alteredUsing = { __new: 'heap', __old: droppedUsing }; if (alterUsingTo) alteredUsing = alterUsingTo; + const alteredMeta = view.meta; + return { name: json2.views[nameWithSchema].name, schema: json2.views[nameWithSchema].schema, + // pg deletedWithOption: deletedWithOption, addedWithOption: addedWithOption, alteredWith: { @@ -305,10 +308,13 @@ export function applyJsonDiff(json1, json2) { alterWith: Object.keys(alterWith).length ? alterWith : undefined, }, alteredSchema, - alteredDefinition, alteredExisting, alteredTablespace, alteredUsing, + // mysql + alteredMeta, + // common + alteredDefinition, }; }, ); diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index a604aa0e0..6fbec50cc 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -2,8 +2,8 @@ import chalk from 'chalk'; import { getNewTableName } from './cli/commands/sqlitePushUtils'; import { warning } from './cli/views'; import { CommonSquashedSchema } from './schemaValidator'; -import { MySqlKitInternals, MySqlSchema, MySqlSquasher } from './serializer/mysqlSchema'; -import { Index, MatViewWithOption, PgSchema, PgSquasher, View, ViewWithOption } from './serializer/pgSchema'; +import { MySqlKitInternals, MySqlSchema, MySqlSquasher, View as MySqlView } from './serializer/mysqlSchema'; +import { Index, MatViewWithOption, PgSchema, PgSquasher, View as PgView, ViewWithOption } from './serializer/pgSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, @@ -524,15 +524,19 @@ export interface JsonRenameSchema { to: string; } -export type JsonCreateViewStatement = { +export type JsonCreatePgViewStatement = { type: 'create_view'; -} & Omit; +} & Omit; + +export type JsonCreateMySqlViewStatement = { + type: 'mysql_create_view'; +} & Omit; export interface JsonDropViewStatement { type: 'drop_view'; name: string; schema: string; - materialized: boolean; + materialized?: boolean; } export interface JsonRenameViewStatement { @@ -540,7 +544,15 @@ export interface JsonRenameViewStatement { nameTo: string; nameFrom: string; schema: string; - materialized: boolean; + materialized?: boolean; +} + +export interface JsonRenameMySqlViewStatement { + type: 'rename_view'; + nameTo: string; + nameFrom: string; + schema: string; + materialized?: boolean; } export interface JsonAlterViewAlterSchemaStatement { @@ -595,6 +607,10 @@ export interface JsonAlterViewAlterUsingStatement { materialized: true; } +export type JsonAlterMySqlViewStatement = { + type: 'alter_mysql_view'; +} & Omit; + export type JsonAlterViewStatement = | JsonAlterViewAlterSchemaStatement | JsonAlterViewAddWithOptionStatement @@ -661,10 +677,12 @@ export type JsonStatement = | JsonCreateSequenceStatement | JsonMoveSequenceStatement | JsonRenameSequenceStatement - | JsonCreateViewStatement + | JsonCreatePgViewStatement | JsonDropViewStatement | JsonRenameViewStatement - | JsonAlterViewStatement; + | JsonAlterViewStatement + | JsonCreateMySqlViewStatement + | JsonAlterMySqlViewStatement; export const preparePgCreateTableJson = ( table: Table, @@ -2517,7 +2535,7 @@ export const preparePgCreateViewJson = ( withOption?: any, using?: string, tablespace?: string, -): JsonCreateViewStatement => { +): JsonCreatePgViewStatement => { return { type: 'create_view', name: name, @@ -2531,10 +2549,27 @@ export const preparePgCreateViewJson = ( }; }; -export const preparePgDropViewJson = ( +export const prepareMySqlCreateViewJson = ( name: string, - schema: string, - materialized: boolean, + definition: string, + meta: string, +): JsonCreateMySqlViewStatement => { + const { algorithm, definer, sqlSecurity, withCheckOption } = MySqlSquasher.unsquashView(meta); + return { + type: 'mysql_create_view', + name: name, + definition: definition, + algorithm, + definer, + sqlSecurity, + withCheckOption, + }; +}; + +export const prepareDropViewJson = ( + name: string, + schema: string = '', + materialized: boolean = false, ): JsonDropViewStatement => { return { type: 'drop_view', @@ -2544,11 +2579,11 @@ export const preparePgDropViewJson = ( }; }; -export const preparePgRenameViewJson = ( +export const prepareRenameViewJson = ( to: string, from: string, - schema: string, - materialized: boolean, + schema: string = '', + materialized: boolean = false, ): JsonRenameViewStatement => { return { type: 'rename_view', @@ -2633,3 +2668,9 @@ export const preparePgAlterViewAlterUsingJson = ( toUsing: to, } as JsonAlterViewAlterUsingStatement; }; + +export const prepareMySqlAlterView = ( + view: Omit, +): JsonAlterMySqlViewStatement => { + return view as JsonAlterMySqlViewStatement; +}; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index f1f20ebf5..ad557dd03 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -46,9 +46,9 @@ export const serializeMySql = async ( const { prepareFromMySqlImports } = await import('./mysqlImports'); const { generateMySqlSnapshot } = await import('./mysqlSerializer'); - const { tables } = await prepareFromMySqlImports(filenames); + const { tables, views } = await prepareFromMySqlImports(filenames); - return generateMySqlSnapshot(tables); + return generateMySqlSnapshot(tables, views); }; export const serializePg = async ( diff --git a/drizzle-kit/src/serializer/mysqlImports.ts b/drizzle-kit/src/serializer/mysqlImports.ts index d9899026b..a8e8ead39 100644 --- a/drizzle-kit/src/serializer/mysqlImports.ts +++ b/drizzle-kit/src/serializer/mysqlImports.ts @@ -1,22 +1,28 @@ import { is } from 'drizzle-orm'; -import { AnyMySqlTable, MySqlTable } from 'drizzle-orm/mysql-core'; +import { AnyMySqlTable, MySqlTable, MySqlView } from 'drizzle-orm/mysql-core'; import { safeRegister } from '../cli/commands/utils'; export const prepareFromExports = (exports: Record) => { const tables: AnyMySqlTable[] = []; + const views: MySqlView[] = []; const i0values = Object.values(exports); i0values.forEach((t) => { if (is(t, MySqlTable)) { tables.push(t); } + + if (is(t, MySqlView)) { + views.push(t); + } }); - return { tables }; + return { tables, views }; }; export const prepareFromMySqlImports = async (imports: string[]) => { const tables: AnyMySqlTable[] = []; + const views: MySqlView[] = []; const { unregister } = await safeRegister(); for (let i = 0; i < imports.length; i++) { @@ -25,7 +31,8 @@ export const prepareFromMySqlImports = async (imports: string[]) => { const prepared = prepareFromExports(i0); tables.push(...prepared.tables); + views.push(...prepared.views); } unregister(); - return { tables: Array.from(new Set(tables)) }; + return { tables: Array.from(new Set(tables)), views }; }; diff --git a/drizzle-kit/src/serializer/mysqlSchema.ts b/drizzle-kit/src/serializer/mysqlSchema.ts index 5bc62ab2f..f4caf7038 100644 --- a/drizzle-kit/src/serializer/mysqlSchema.ts +++ b/drizzle-kit/src/serializer/mysqlSchema.ts @@ -69,6 +69,21 @@ const table = object({ uniqueConstraints: record(string(), uniqueConstraint).default({}), }).strict(); +const viewMeta = object({ + definer: string().optional(), + algorithm: enumType(['undefined', 'merge', 'temptable']).optional(), + sqlSecurity: enumType(['definer', 'invoker']).optional(), + withCheckOption: enumType(['local', 'cascaded']).optional(), +}).strict(); + +export const view = object({ + name: string(), + columns: record(string(), column), + definition: string().optional(), + isExisting: boolean(), +}).strict().merge(viewMeta); +type ViewMeta = TypeOf; + export const kitInternals = object({ tables: record( string(), @@ -128,6 +143,7 @@ export const schemaInternal = object({ version: literal('5'), dialect: dialect, tables: record(string(), table), + views: record(string(), view), _meta: object({ tables: record(string(), string()), columns: record(string(), string()), @@ -157,10 +173,18 @@ const tableSquashed = object({ uniqueConstraints: record(string(), string()).default({}), }).strict(); +const viewSquashed = view.omit({ + algorithm: true, + definer: true, + sqlSecurity: true, + withCheckOption: true, +}).extend({ meta: string() }); + export const schemaSquashed = object({ version: literal('5'), dialect: dialect, tables: record(string(), tableSquashed), + views: record(string(), viewSquashed), }).strict(); export const schemaSquashedV4 = object({ @@ -186,6 +210,8 @@ export type Index = TypeOf; export type ForeignKey = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; +export type View = TypeOf; +export type ViewSquashed = TypeOf; export const MySqlSquasher = { squashIdx: (idx: Index) => { @@ -247,6 +273,20 @@ export const MySqlSquasher = { }); return result; }, + squashView: (view: View): string => { + return `${view.algorithm};${view.definer};${view.sqlSecurity};${view.withCheckOption}`; + }, + unsquashView: (meta: string): ViewMeta => { + const [algorithm, definer, sqlSecurity, withCheckOption] = meta.split(';'); + const toReturn = { + algorithm: algorithm !== 'undefined' ? algorithm : undefined, + definer: definer !== 'undefined' ? definer : undefined, + sqlSecurity: sqlSecurity !== 'undefined' ? sqlSecurity : undefined, + withCheckOption: withCheckOption !== 'undefined' ? withCheckOption : undefined, + }; + + return viewMeta.parse(toReturn); + }, }; export const squashMysqlSchemeV4 = ( @@ -317,10 +357,26 @@ export const squashMysqlScheme = (json: MySqlSchema): MySqlSchemaSquashed => { ]; }), ); + + const mappedViews = Object.fromEntries( + Object.entries(json.views).map(([key, value]) => { + const meta = MySqlSquasher.squashView(value); + + return [key, { + name: value.name, + isExisting: value.isExisting, + columns: value.columns, + definition: value.definition, + meta, + }]; + }), + ); + return { version: '5', dialect: json.dialect, tables: mappedTables, + views: mappedViews, }; }; @@ -340,6 +396,7 @@ export const dryMySql = mysqlSchema.parse({ prevId: '', tables: {}, schemas: {}, + views: {}, _meta: { schemas: {}, tables: {}, diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 14e867128..1388b2fda 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -1,7 +1,15 @@ import chalk from 'chalk'; import { getTableName, is } from 'drizzle-orm'; import { SQL } from 'drizzle-orm'; -import { AnyMySqlTable, MySqlDialect, type PrimaryKey as PrimaryKeyORM, uniqueKeyName } from 'drizzle-orm/mysql-core'; +import { + AnyMySqlTable, + getViewConfig, + MySqlColumn, + MySqlDialect, + MySqlView, + type PrimaryKey as PrimaryKeyORM, + uniqueKeyName, +} from 'drizzle-orm/mysql-core'; import { getTableConfig } from 'drizzle-orm/mysql-core'; import { RowDataPacket } from 'mysql2/promise'; import { withStyle } from '../cli/validations/outputs'; @@ -15,11 +23,10 @@ import { PrimaryKey, Table, UniqueConstraint, + View, } from '../serializer/mysqlSchema'; import type { DB } from '../utils'; import { sqlToStr } from '.'; -// import { MySqlColumnWithAutoIncrement } from "drizzle-orm/mysql-core"; -// import { MySqlDateBaseColumn } from "drizzle-orm/mysql-core"; const dialect = new MySqlDialect(); @@ -29,9 +36,12 @@ export const indexName = (tableName: string, columns: string[]) => { export const generateMySqlSnapshot = ( tables: AnyMySqlTable[], + views: MySqlView[], ): MySqlSchemaInternal => { const result: Record = {}; + const resultViews: Record = {}; const internal: MySqlKitInternals = { tables: {}, indexes: {} }; + for (const table of tables) { const { name: tableName, @@ -335,10 +345,123 @@ export const generateMySqlSnapshot = ( } } + for (const view of views) { + const { + isExisting, + name, + query, + schema, + selectedFields, + algorithm, + definer, + sqlSecurity, + withCheckOption, + } = getViewConfig(view); + + const columnsObject: Record = {}; + + const existingView = resultViews[name]; + if (typeof existingView !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated view name across ${ + chalk.underline.blue( + schema ?? 'public', + ) + } schema. Please rename your view`, + ) + }`, + ); + process.exit(1); + } + + for (const key in selectedFields) { + if (is(selectedFields[key], MySqlColumn)) { + const column = selectedFields[key]; + + const notNull: boolean = column.notNull; + const sqlTypeLowered = column.getSQLType().toLowerCase(); + const autoIncrement = typeof (column as any).autoIncrement === 'undefined' + ? false + : (column as any).autoIncrement; + + const generated = column.generated; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + primaryKey: false, + // If field is autoincrement it's notNull by default + // notNull: autoIncrement ? true : notNull, + notNull, + autoincrement: autoIncrement, + onUpdate: (column as any).hasOnUpdateNow, + generated: generated + ? { + as: is(generated.as, SQL) + ? dialect.sqlToQuery(generated.as as SQL).sql + : typeof generated.as === 'function' + ? dialect.sqlToQuery(generated.as() as SQL).sql + : (generated.as as any), + type: generated.mode ?? 'stored', + } + : undefined, + }; + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default); + } else { + if (typeof column.default === 'string') { + columnToSet.default = `'${column.default}'`; + } else { + if (sqlTypeLowered === 'json') { + columnToSet.default = `'${JSON.stringify(column.default)}'`; + } else if (column.default instanceof Date) { + if (sqlTypeLowered === 'date') { + columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; + } else if ( + sqlTypeLowered.startsWith('datetime') + || sqlTypeLowered.startsWith('timestamp') + ) { + columnToSet.default = `'${ + column.default + .toISOString() + .replace('T', ' ') + .slice(0, 23) + }'`; + } + } else { + columnToSet.default = column.default; + } + } + if (['blob', 'text', 'json'].includes(column.getSQLType())) { + columnToSet.default = `(${columnToSet.default})`; + } + } + } + columnsObject[column.name] = columnToSet; + } + } + + resultViews[name] = { + columns: columnsObject, + name, + isExisting, + definition: isExisting ? undefined : dialect.sqlToQuery(query!).sql, + withCheckOption, + definer, + algorithm, + sqlSecurity, + }; + } + return { version: '5', dialect: 'mysql', tables: result, + views: resultViews, _meta: { tables: {}, columns: {}, @@ -719,6 +842,7 @@ export const fromDatabase = async ( version: '5', dialect: 'mysql', tables: result, + views: {}, _meta: { tables: {}, columns: {}, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 0a6880a8b..93e7fd85b 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -21,13 +21,15 @@ import { _prepareSqliteAddColumns, JsonAddColumnStatement, JsonAlterCompositePK, + JsonAlterMySqlViewStatement, JsonAlterTableSetSchema, JsonAlterUniqueConstraint, JsonAlterViewStatement, JsonCreateCompositePK, + JsonCreateMySqlViewStatement, + JsonCreatePgViewStatement, JsonCreateReferenceStatement, JsonCreateUniqueConstraint, - JsonCreateViewStatement, JsonDeleteCompositePK, JsonDeleteUniqueConstraint, JsonDropColumnStatement, @@ -63,11 +65,14 @@ import { prepareDropReferencesJson, prepareDropSequenceJson, prepareDropTableJson, + prepareDropViewJson, prepareLibSQLCreateReferencesJson, prepareLibSQLDropReferencesJson, prepareMoveEnumJson, prepareMoveSequenceJson, + prepareMySqlAlterView, prepareMySqlCreateTableJson, + prepareMySqlCreateViewJson, preparePgAlterColumns, preparePgAlterViewAddWithOptionJson, preparePgAlterViewAlterSchemaJson, @@ -77,20 +82,19 @@ import { preparePgCreateIndexesJson, preparePgCreateTableJson, preparePgCreateViewJson, - preparePgDropViewJson, - preparePgRenameViewJson, prepareRenameColumns, prepareRenameEnumJson, prepareRenameSchemasJson, prepareRenameSequenceJson, prepareRenameTableJson, + prepareRenameViewJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, } from './jsonStatements'; import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; -import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher } from './serializer/mysqlSchema'; +import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher, ViewSquashed } from './serializer/mysqlSchema'; import { mergedViewWithOption, PgSchema, PgSchemaSquashed, sequenceSquashed, View } from './serializer/pgSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; @@ -262,48 +266,63 @@ export const alteredTableScheme = object({ ), }).strict(); -export const alteredViewSchema = object({ +const alteredViewCommon = object({ name: string(), - schema: string(), - deletedWithOption: mergedViewWithOption.optional(), - addedWithOption: mergedViewWithOption.optional(), - alteredWith: object({ - addedWith: mergedViewWithOption.optional(), - deletedWith: mergedViewWithOption.optional(), - alterWith: mergedViewWithOption.optional(), - }).strict(), - alteredSchema: object({ - __old: string(), - __new: string(), - }).strict().optional(), alteredDefinition: object({ __old: string(), __new: string(), }).strict().optional(), - alteredExisting: object({ - __old: boolean(), - __new: boolean(), - }).strict().optional(), - alteredTablespace: object({ - __old: string(), - __new: string(), - }).strict().optional(), - alteredUsing: object({ - __old: string(), - __new: string(), - }).strict().optional(), -}).strict(); +}); + +export const alteredPgViewSchema = alteredViewCommon.merge( + object({ + schema: string(), + deletedWithOption: mergedViewWithOption.optional(), + addedWithOption: mergedViewWithOption.optional(), + alteredWith: object({ + addedWith: mergedViewWithOption.optional(), + deletedWith: mergedViewWithOption.optional(), + alterWith: mergedViewWithOption.optional(), + }).strict(), + alteredSchema: object({ + __old: string(), + __new: string(), + }).strict().optional(), + alteredExisting: object({ + __old: boolean(), + __new: boolean(), + }).strict().optional(), + alteredTablespace: object({ + __old: string(), + __new: string(), + }).strict().optional(), + alteredUsing: object({ + __old: string(), + __new: string(), + }).strict().optional(), + }).strict(), +); + +export const alteredMySqlViewSchema = alteredViewCommon.merge( + object({ + alteredMeta: object({ + __old: string(), + __new: string(), + }).strict().optional(), + }).strict(), +); export const diffResultScheme = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: changedEnumSchema.array(), alteredSequences: sequenceSquashed.array(), - alteredViews: alteredViewSchema.array(), + alteredViews: alteredPgViewSchema.array(), }).strict(); export const diffResultSchemeMysql = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: never().array(), + alteredViews: alteredMySqlViewSchema.array(), }); export const diffResultSchemeSQLite = object({ @@ -1176,7 +1195,7 @@ export const applyPgSnapshotsDiff = async ( return preparePgCreateTableJson(it, curFull); }); - const createViews: JsonCreateViewStatement[] = []; + const createViews: JsonCreatePgViewStatement[] = []; const dropViews: JsonDropViewStatement[] = []; const renameViews: JsonRenameViewStatement[] = []; const alterViews: JsonAlterViewStatement[] = []; @@ -1198,13 +1217,13 @@ export const applyPgSnapshotsDiff = async ( dropViews.push( ...deletedViews.filter((it) => !it.isExisting).map((it) => { - return preparePgDropViewJson(it.name, it.schema, it.materialized); + return prepareDropViewJson(it.name, it.schema, it.materialized); }), ); renameViews.push( ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { - return preparePgRenameViewJson(it.to.name, it.from.name, it.to.schema, it.to.materialized); + return prepareRenameViewJson(it.to.name, it.from.name, it.to.schema, it.to.materialized); }), ); @@ -1227,7 +1246,7 @@ export const applyPgSnapshotsDiff = async ( const { materialized, with: withOption, definition, withNoData, using, tablespace } = json2.views[viewKey]; if (alteredView.alteredExisting || (alteredView.alteredDefinition && action !== 'push')) { - dropViews.push(preparePgDropViewJson(alteredView.name, alteredView.schema, materialized)); + dropViews.push(prepareDropViewJson(alteredView.name, alteredView.schema, materialized)); createViews.push( preparePgCreateViewJson( @@ -1444,6 +1463,9 @@ export const applyMysqlSnapshotsDiff = async ( columnsResolver: ( input: ColumnsResolverInput, ) => Promise>, + viewsResolver: ( + input: ResolverInput, + ) => Promise>, prevFull: MySqlSchema, curFull: MySqlSchema, action?: 'push' | undefined, @@ -1591,6 +1613,36 @@ export const applyMysqlSnapshotsDiff = async ( }, ); + const viewsDiff = diffSchemasOrTables(json1.views, json2.views); + + const { + created: createdViews, + deleted: deletedViews, + renamed: renamedViews, // renamed or moved + } = await viewsResolver({ + created: viewsDiff.added, + deleted: viewsDiff.deleted, + }); + + const renamesViewDic: Record = {}; + renamedViews.forEach((it) => { + renamesViewDic[`${it.from.schema}.${it.from.name}`] = { to: it.to.name, from: it.from.name }; + }); + + const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + viewsPatchedSnap1.views = mapEntries( + viewsPatchedSnap1.views, + (viewKey, viewValue) => { + const rename = renamesViewDic[viewValue.name]; + + if (rename) { + viewValue.name = rename.to; + } + + return [viewKey, viewValue]; + }, + ); + const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); const typedResult: DiffResultMysql = diffResultSchemeMysql.parse(diffResult); @@ -1832,12 +1884,70 @@ export const applyMysqlSnapshotsDiff = async ( curFull.internal, ); }); + + const createViews: JsonCreateMySqlViewStatement[] = []; + const dropViews: JsonDropViewStatement[] = []; + const renameViews: JsonRenameViewStatement[] = []; + const alterViews: JsonAlterMySqlViewStatement[] = []; + + createViews.push( + ...createdViews.filter((it) => !it.isExisting).map((it) => { + return prepareMySqlCreateViewJson( + it.name, + it.definition!, + it.meta, + ); + }), + ); + + dropViews.push( + ...deletedViews.filter((it) => !it.isExisting).map((it) => { + return prepareDropViewJson(it.name); + }), + ); + + renameViews.push( + ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { + return prepareRenameViewJson(it.to.name, it.from.name); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[it.name].isExisting); + + for (const alteredView of alteredViews) { + const { definition, meta } = json2.views[alteredView.name]; + + if (alteredView.alteredDefinition && action !== 'push') { + dropViews.push(prepareDropViewJson(alteredView.name)); + + createViews.push( + prepareMySqlCreateViewJson( + alteredView.name, + definition!, + meta, + ), + ); + continue; + } + + if (alteredView.alteredMeta) { + const view = { ...json2['views'][alteredView.name], isExisting: undefined }; + alterViews.push( + prepareMySqlAlterView(view), + ); + } + } + jsonStatements.push(...jsonMySqlCreateTables); jsonStatements.push(...jsonDropTables); jsonStatements.push(...jsonRenameTables); jsonStatements.push(...jsonRenameColumnsStatements); + jsonStatements.push(...dropViews); + jsonStatements.push(...renameViews); + jsonStatements.push(...alterViews); + jsonStatements.push(...jsonDeletedUniqueConstraints); jsonStatements.push(...jsonDroppedReferencesForAlteredTables); @@ -1869,6 +1979,8 @@ export const applyMysqlSnapshotsDiff = async ( jsonStatements.push(...jsonAddedUniqueConstraints); + jsonStatements.push(...createViews); + jsonStatements.push(...jsonAlteredUniqueConstraints); const sqlStatements = fromJson(jsonStatements, 'mysql'); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 709740d11..f70cd2964 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -33,12 +33,13 @@ import { JsonCreateCompositePK, JsonCreateEnumStatement, JsonCreateIndexStatement, + JsonCreateMySqlViewStatement, + JsonCreatePgViewStatement, JsonCreateReferenceStatement, JsonCreateSchema, JsonCreateSequenceStatement, JsonCreateTableStatement, JsonCreateUniqueConstraint, - JsonCreateViewStatement, JsonDeleteCompositePK, JsonDeleteReferenceStatement, JsonDeleteUniqueConstraint, @@ -408,7 +409,7 @@ class PgCreateViewConvertor extends Convertor { return statement.type === 'create_view' && dialect === 'postgresql'; } - convert(st: JsonCreateViewStatement) { + convert(st: JsonCreatePgViewStatement) { const { definition, name: viewName, schema, with: withOption, materialized, withNoData, tablespace, using } = st; const name = schema ? `"${schema}"."${viewName}"` : `"${viewName}"`; @@ -444,6 +445,26 @@ class PgCreateViewConvertor extends Convertor { } } +class MySqlCreateViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'mysql_create_view' && dialect === 'mysql'; + } + + convert(st: JsonCreateMySqlViewStatement) { + const { definition, name, algorithm, definer, sqlSecurity, withCheckOption } = st; + + let statement = `CREATE `; + statement += algorithm ? `ALGORITHM = ${algorithm}\n` : ''; + statement += definer ? `DEFINER = ${definer}\n` : ''; + statement += sqlSecurity ? `SQL SECURITY ${sqlSecurity}\n` : ''; + statement += `VIEW \`${name}\` AS ${definition}`; + statement += withCheckOption ? `\nWITH ${withCheckOption} CHECK OPTION` : ''; + + statement += ';'; + + return statement; + } +} class PgDropViewConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'drop_view' && dialect === 'postgresql'; @@ -458,6 +479,18 @@ class PgDropViewConvertor extends Convertor { } } +class MySqlDropViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_view' && dialect === 'mysql'; + } + + convert(st: JsonDropViewStatement) { + const { name } = st; + + return `DROP VIEW ${name};`; + } +} + class PgRenameViewConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'rename_view' && dialect === 'postgresql'; @@ -472,6 +505,18 @@ class PgRenameViewConvertor extends Convertor { } } +class MySqlRenameViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'rename_view' && dialect === 'mysql'; + } + + convert(st: JsonRenameViewStatement) { + const { nameFrom: from, nameTo: to } = st; + + return `RENAME TABLE \`${from}\` RENAME TO \`${to}\`;`; + } +} + class PgAlterViewSchemaConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'alter_view_alter_schema' && dialect === 'postgresql'; @@ -2663,6 +2708,10 @@ convertors.push(new PgAlterViewDropWithOptionConvertor()); convertors.push(new PgAlterViewAlterTablespaceConvertor()); convertors.push(new PgAlterViewAlterUsingConvertor()); +convertors.push(new MySqlCreateViewConvertor()); +convertors.push(new MySqlDropViewConvertor()); +convertors.push(new MySqlRenameViewConvertor()); + convertors.push(new CreateTypeEnumConvertor()); convertors.push(new CreatePgSequenceConvertor()); diff --git a/drizzle-kit/tests/pg-views.test.ts b/drizzle-kit/tests/pg-views.test.ts index 0665f0c84..3179aa373 100644 --- a/drizzle-kit/tests/pg-views.test.ts +++ b/drizzle-kit/tests/pg-views.test.ts @@ -1642,7 +1642,7 @@ test('drop tablespace - materialize', async () => { ); }); -test('set existing', async () => { +test('set existing - materialized', async () => { const users = pgTable('users', { id: integer('id').primaryKey().notNull(), }); @@ -1669,6 +1669,33 @@ test('set existing', async () => { expect(sqlStatements.length).toBe(0); }); +test('drop existing - materialized', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + autovacuumFreezeMinAge: 1, + }).withNoData().as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(2); + + expect(sqlStatements.length).toBe(2); +}); + test('set existing', async () => { const users = pgTable('users', { id: integer('id').primaryKey().notNull(), From c7f100fb6340ea856d9debb4e696e9ee445ec6c0 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 25 Sep 2024 15:43:49 +0300 Subject: [PATCH 196/492] added introspect for mysql views --- drizzle-kit/src/cli/commands/introspect.ts | 2 + drizzle-kit/src/introspect-mysql.ts | 59 +++++++++++++++ drizzle-kit/src/jsonDiffer.js | 36 +++++----- drizzle-kit/src/jsonStatements.ts | 2 +- drizzle-kit/src/serializer/mysqlSerializer.ts | 35 ++++++++- drizzle-kit/src/serializer/pgSchema.ts | 2 +- drizzle-kit/src/snapshotsDiffer.ts | 72 +++++++++---------- drizzle-kit/src/sqlgenerator.ts | 23 ++++++ 8 files changed, 172 insertions(+), 59 deletions(-) diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 7f67315fa..5d1722a7e 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -25,6 +25,7 @@ import { IntrospectProgress } from '../views'; import { columnsResolver, enumsResolver, + mySqlViewsResolver, schemasResolver, sequencesResolver, tablesResolver, @@ -212,6 +213,7 @@ export const introspectMysql = async ( squashMysqlScheme(schema), tablesResolver, columnsResolver, + mySqlViewsResolver, dryMySql, schema, ); diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index 8c1aa3a76..a97118a2d 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -186,6 +186,31 @@ export const schemaToTypeScript = ( { mysql: [] as string[] }, ); + Object.values(schema.views).forEach((it) => { + imports.mysql.push('mysqlView'); + + Object.values(it.columns).forEach(() => { + const columnImports = Object.values(it.columns) + .map((col) => { + let patched: string = (importsPatch[col.type] || col.type).replace('[]', ''); + patched = patched === 'double precision' ? 'doublePrecision' : patched; + patched = patched.startsWith('varchar(') ? 'varchar' : patched; + patched = patched.startsWith('char(') ? 'char' : patched; + patched = patched.startsWith('numeric(') ? 'numeric' : patched; + patched = patched.startsWith('time(') ? 'time' : patched; + patched = patched.startsWith('timestamp(') ? 'timestamp' : patched; + patched = patched.startsWith('vector(') ? 'vector' : patched; + patched = patched.startsWith('geometry(') ? 'geometry' : patched; + return patched; + }) + .filter((type) => { + return mysqlImportsList.has(type); + }); + + imports.mysql.push(...columnImports); + }); + }); + const tableStatements = Object.values(schema.tables).map((table) => { const func = 'mysqlTable'; let statement = ''; @@ -243,6 +268,38 @@ export const schemaToTypeScript = ( return statement; }); + const viewsStatements = Object.values(schema.views).map((view) => { + const { columns, name, algorithm, definer, definition, sqlSecurity, withCheckOption } = view; + const func = 'mysqlView'; + let statement = ''; + + if (imports.mysql.includes(withCasing(name))) { + statement = `// Table name is in conflict with ${ + withCasing( + view.name, + ) + } import.\n// Please change to any other name, that is not in imports list\n`; + } + statement += `export const ${withCasing(name)} = ${func}("${name}", {\n`; + statement += createTableColumns( + Object.values(columns), + [], + withCasing, + casing, + name, + schema, + ); + statement += '})'; + + statement += algorithm ? `.algorithm("${algorithm}")` : ''; + statement += definer ? `.definer("${definer}")` : ''; + statement += sqlSecurity ? `.sqlSecurity("${sqlSecurity}")` : ''; + statement += withCheckOption ? `.withCheckOption("${withCheckOption}")` : ''; + statement += `.as(sql\`${definition?.replaceAll('`', '\\`')}\`);`; + + return statement; + }); + const uniqueMySqlImports = [ 'mysqlTable', 'mysqlSchema', @@ -257,6 +314,8 @@ export const schemaToTypeScript = ( let decalrations = ''; decalrations += tableStatements.join('\n\n'); + decalrations += '\n'; + decalrations += viewsStatements.join('\n\n'); const file = importsTs + decalrations; diff --git a/drizzle-kit/src/jsonDiffer.js b/drizzle-kit/src/jsonDiffer.js index 9d6ee782b..41af18868 100644 --- a/drizzle-kit/src/jsonDiffer.js +++ b/drizzle-kit/src/jsonDiffer.js @@ -296,26 +296,26 @@ export function applyJsonDiff(json1, json2) { const alteredMeta = view.meta; - return { - name: json2.views[nameWithSchema].name, - schema: json2.views[nameWithSchema].schema, - // pg - deletedWithOption: deletedWithOption, - addedWithOption: addedWithOption, - alteredWith: { + return Object.fromEntries( + Object.entries({ + name: json2.views[nameWithSchema].name, + schema: json2.views[nameWithSchema].schema, + // pg + deletedWithOption: deletedWithOption, + addedWithOption: addedWithOption, deletedWith: Object.keys(deletedWith).length ? deletedWith : undefined, addedWith: Object.keys(addedWith).length ? addedWith : undefined, - alterWith: Object.keys(alterWith).length ? alterWith : undefined, - }, - alteredSchema, - alteredExisting, - alteredTablespace, - alteredUsing, - // mysql - alteredMeta, - // common - alteredDefinition, - }; + alteredWith: Object.keys(alterWith).length ? alterWith : undefined, + alteredSchema, + alteredExisting, + alteredTablespace, + alteredUsing, + // mysql + alteredMeta, + // common + alteredDefinition, + }).filter(([_, value]) => value !== undefined), + ); }, ); diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 6fbec50cc..bf456efca 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -2672,5 +2672,5 @@ export const preparePgAlterViewAlterUsingJson = ( export const prepareMySqlAlterView = ( view: Omit, ): JsonAlterMySqlViewStatement => { - return view as JsonAlterMySqlViewStatement; + return { type: 'alter_mysql_view', ...view }; }; diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 1388b2fda..92db9bfa9 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -832,6 +832,39 @@ export const fromDatabase = async ( } } + const views = await db.query( + `select * from INFORMATION_SCHEMA.VIEWS WHERE table_schema = '${inputSchema}';`, + ); + + const resultViews: Record = {}; + + for await (const view of views) { + const viewName = view['TABLE_NAME']; + const definition = view['VIEW_DEFINITION']; + + const withCheckOption = view['CHECK_OPTION'] === 'NONE' ? undefined : view['CHECK_OPTION'].toLowerCase(); + const definer = view['DEFINER'].split('@').map((it: string) => `'${it}'`).join('@'); + const sqlSecurity = view['SECURITY_TYPE'].toLowerCase(); + + const [createSqlStatement] = await db.query(`SHOW CREATE VIEW \`${viewName}\`;`); + const algorithmMatch = createSqlStatement['Create View'].match(/ALGORITHM=([^ ]+)/); + const algorithm = algorithmMatch ? algorithmMatch[1].toLowerCase() : undefined; + + const columns = result[viewName].columns; + delete result[viewName]; + + resultViews[viewName] = { + columns: columns, + isExisting: false, + name: viewName, + definer, + algorithm, + definition, + sqlSecurity, + withCheckOption, + }; + } + if (progressCallback) { progressCallback('indexes', indexesCount, 'done'); // progressCallback("enums", 0, "fetching"); @@ -842,7 +875,7 @@ export const fromDatabase = async ( version: '5', dialect: 'mysql', tables: result, - views: {}, + views: resultViews, _meta: { tables: {}, columns: {}, diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index 515658d2d..8168600b7 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -247,7 +247,7 @@ const matViewWithOption = object({ userCatalogTable: boolean().optional(), }).strict(); -export const mergedViewWithOption = viewWithOption.merge(matViewWithOption); +export const mergedViewWithOption = viewWithOption.merge(matViewWithOption).strict(); export const view = object({ name: string(), diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 93e7fd85b..9758538cc 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -279,11 +279,9 @@ export const alteredPgViewSchema = alteredViewCommon.merge( schema: string(), deletedWithOption: mergedViewWithOption.optional(), addedWithOption: mergedViewWithOption.optional(), - alteredWith: object({ - addedWith: mergedViewWithOption.optional(), - deletedWith: mergedViewWithOption.optional(), - alterWith: mergedViewWithOption.optional(), - }).strict(), + addedWith: mergedViewWithOption.optional(), + deletedWith: mergedViewWithOption.optional(), + alterWith: mergedViewWithOption.optional(), alteredSchema: object({ __old: string(), __new: string(), @@ -1285,39 +1283,37 @@ export const applyPgSnapshotsDiff = async ( ); } - if (alteredView.alteredWith) { - if (alteredView.alteredWith.addedWith) { - alterViews.push( - preparePgAlterViewAddWithOptionJson( - alteredView.name, - alteredView.schema, - materialized, - alteredView.alteredWith.addedWith, - ), - ); - } + if (alteredView.addedWith) { + alterViews.push( + preparePgAlterViewAddWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.addedWith, + ), + ); + } - if (alteredView.alteredWith.deletedWith) { - alterViews.push( - preparePgAlterViewDropWithOptionJson( - alteredView.name, - alteredView.schema, - materialized, - alteredView.alteredWith.deletedWith, - ), - ); - } + if (alteredView.deletedWith) { + alterViews.push( + preparePgAlterViewDropWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.deletedWith, + ), + ); + } - if (alteredView.alteredWith.alterWith) { - alterViews.push( - preparePgAlterViewAddWithOptionJson( - alteredView.name, - alteredView.schema, - materialized, - alteredView.alteredWith.alterWith, - ), - ); - } + if (alteredView.alterWith) { + alterViews.push( + preparePgAlterViewAddWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.alterWith, + ), + ); } if (alteredView.alteredTablespace) { @@ -1643,7 +1639,7 @@ export const applyMysqlSnapshotsDiff = async ( }, ); - const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + const diffResult = applyJsonDiff(viewsPatchedSnap1, json2); const typedResult: DiffResultMysql = diffResultSchemeMysql.parse(diffResult); @@ -1931,7 +1927,7 @@ export const applyMysqlSnapshotsDiff = async ( } if (alteredView.alteredMeta) { - const view = { ...json2['views'][alteredView.name], isExisting: undefined }; + const view = { ...curFull['views'][alteredView.name], isExisting: undefined }; alterViews.push( prepareMySqlAlterView(view), ); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index f70cd2964..43992166a 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -20,6 +20,7 @@ import { JsonAlterColumnSetPrimaryKeyStatement, JsonAlterColumnTypeStatement, JsonAlterCompositePK, + JsonAlterMySqlViewStatement, JsonAlterReferenceStatement, JsonAlterSequenceStatement, JsonAlterTableRemoveFromSchema, @@ -491,6 +492,27 @@ class MySqlDropViewConvertor extends Convertor { } } +class MySqlAlterViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_mysql_view' && dialect === 'mysql'; + } + + convert(st: JsonAlterMySqlViewStatement) { + const { name, algorithm, definer, definition, sqlSecurity, withCheckOption } = st; + + let statement = `ALTER `; + statement += algorithm ? `ALGORITHM = ${algorithm}\n` : ''; + statement += definer ? `DEFINER = ${definer}\n` : ''; + statement += sqlSecurity ? `SQL SECURITY ${sqlSecurity}\n` : ''; + statement += `VIEW \`${name}\` AS ${definition}`; + statement += withCheckOption ? `\nWITH ${withCheckOption} CHECK OPTION` : ''; + + statement += ';'; + + return statement; + } +} + class PgRenameViewConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'rename_view' && dialect === 'postgresql'; @@ -2711,6 +2733,7 @@ convertors.push(new PgAlterViewAlterUsingConvertor()); convertors.push(new MySqlCreateViewConvertor()); convertors.push(new MySqlDropViewConvertor()); convertors.push(new MySqlRenameViewConvertor()); +convertors.push(new MySqlAlterViewConvertor()); convertors.push(new CreateTypeEnumConvertor()); From dcc742cc550f98f46ec778d70ec4eb452ff29cc1 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 26 Sep 2024 12:36:17 +0300 Subject: [PATCH 197/492] Added sqlite and libsql view handling --- drizzle-kit/src/cli/commands/introspect.ts | 3 + drizzle-kit/src/cli/commands/migrate.ts | 30 ++- drizzle-kit/src/introspect-mysql.ts | 40 ++-- drizzle-kit/src/introspect-sqlite.ts | 42 +++- drizzle-kit/src/jsonStatements.ts | 22 ++- drizzle-kit/src/serializer/index.ts | 4 +- drizzle-kit/src/serializer/sqliteImports.ts | 14 +- drizzle-kit/src/serializer/sqliteSchema.ts | 13 ++ .../src/serializer/sqliteSerializer.ts | 116 ++++++++++- drizzle-kit/src/snapshotsDiffer.ts | 183 +++++++++++++++++- drizzle-kit/src/sqlgenerator.ts | 32 ++- drizzle-orm/src/sqlite-core/utils.ts | 3 +- drizzle-orm/src/sqlite-core/view.ts | 18 +- 13 files changed, 469 insertions(+), 51 deletions(-) diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 5d1722a7e..f033a6900 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -28,6 +28,7 @@ import { mySqlViewsResolver, schemasResolver, sequencesResolver, + sqliteViewsResolver, tablesResolver, viewsResolver, writeResult, @@ -325,6 +326,7 @@ export const introspectSqlite = async ( squashSqliteScheme(schema), tablesResolver, columnsResolver, + sqliteViewsResolver, drySQLite, schema, ); @@ -436,6 +438,7 @@ export const introspectLibSQL = async ( squashSqliteScheme(schema), tablesResolver, columnsResolver, + sqliteViewsResolver, drySQLite, schema, ); diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 02bd64d8b..5018c56b2 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -15,7 +15,7 @@ import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme, ViewSquashed } from '../../serializer/mysqlSchema'; import { PgSchema, pgSchema, squashPgScheme, View } from '../../serializer/pgSchema'; -import { SQLiteSchema, sqliteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; +import { SQLiteSchema, sqliteSchema, squashSqliteScheme, View as SQLiteView } from '../../serializer/sqliteSchema'; import { applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, @@ -116,7 +116,29 @@ export const viewsResolver = async ( export const mySqlViewsResolver = async ( input: ResolverInput, -): Promise> => { +): Promise> => { + try { + const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict( + input.created, + input.deleted, + 'view', + ); + + return { + created: created, + deleted: deleted, + moved: moved, + renamed: renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const sqliteViewsResolver = async ( + input: ResolverInput, +): Promise> => { try { const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict( input.created, @@ -479,6 +501,7 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, ); @@ -538,6 +561,7 @@ export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => { squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, ); @@ -575,6 +599,7 @@ export const prepareSQLitePush = async ( squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, 'push', @@ -606,6 +631,7 @@ export const prepareLibSQLPush = async ( squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, 'push', diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index a97118a2d..af19fc2cf 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -189,26 +189,26 @@ export const schemaToTypeScript = ( Object.values(schema.views).forEach((it) => { imports.mysql.push('mysqlView'); - Object.values(it.columns).forEach(() => { - const columnImports = Object.values(it.columns) - .map((col) => { - let patched: string = (importsPatch[col.type] || col.type).replace('[]', ''); - patched = patched === 'double precision' ? 'doublePrecision' : patched; - patched = patched.startsWith('varchar(') ? 'varchar' : patched; - patched = patched.startsWith('char(') ? 'char' : patched; - patched = patched.startsWith('numeric(') ? 'numeric' : patched; - patched = patched.startsWith('time(') ? 'time' : patched; - patched = patched.startsWith('timestamp(') ? 'timestamp' : patched; - patched = patched.startsWith('vector(') ? 'vector' : patched; - patched = patched.startsWith('geometry(') ? 'geometry' : patched; - return patched; - }) - .filter((type) => { - return mysqlImportsList.has(type); - }); - - imports.mysql.push(...columnImports); - }); + const columnImports = Object.values(it.columns) + .map((col) => { + let patched = importsPatch[col.type] ?? col.type; + patched = patched.startsWith('varchar(') ? 'varchar' : patched; + patched = patched.startsWith('char(') ? 'char' : patched; + patched = patched.startsWith('binary(') ? 'binary' : patched; + patched = patched.startsWith('decimal(') ? 'decimal' : patched; + patched = patched.startsWith('smallint(') ? 'smallint' : patched; + patched = patched.startsWith('enum(') ? 'mysqlEnum' : patched; + patched = patched.startsWith('datetime(') ? 'datetime' : patched; + patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; + patched = patched.startsWith('int(') ? 'int' : patched; + patched = patched.startsWith('double(') ? 'double' : patched; + return patched; + }) + .filter((type) => { + return mysqlImportsList.has(type); + }); + + imports.mysql.push(...columnImports); }); const tableStatements = Object.values(schema.tables).map((table) => { diff --git a/drizzle-kit/src/introspect-sqlite.ts b/drizzle-kit/src/introspect-sqlite.ts index 422e58f86..2fa95f9af 100644 --- a/drizzle-kit/src/introspect-sqlite.ts +++ b/drizzle-kit/src/introspect-sqlite.ts @@ -111,6 +111,20 @@ export const schemaToTypeScript = ( { sqlite: [] as string[] }, ); + Object.values(schema.views).forEach((it) => { + imports.sqlite.push('sqliteView'); + + const columnImports = Object.values(it.columns) + .map((col) => { + return col.type; + }) + .filter((type) => { + return sqliteImportsList.has(type); + }); + + imports.sqlite.push(...columnImports); + }); + const tableStatements = Object.values(schema.tables).map((table) => { const func = 'sqliteTable'; let statement = ''; @@ -166,6 +180,30 @@ export const schemaToTypeScript = ( return statement; }); + const viewsStatements = Object.values(schema.views).map((view) => { + const func = 'sqliteView'; + + let statement = ''; + if (imports.sqlite.includes(withCasing(view.name, casing))) { + statement = `// Table name is in conflict with ${ + withCasing( + view.name, + casing, + ) + } import.\n// Please change to any other name, that is not in imports list\n`; + } + statement += `export const ${withCasing(view.name, casing)} = ${func}("${view.name}", {\n`; + statement += createTableColumns( + Object.values(view.columns), + [], + casing, + ); + statement += '})'; + statement += `.as(sql\`${view.definition?.replaceAll('`', '\\`')}\`);`; + + return statement; + }); + const uniqueSqliteImports = [ 'sqliteTable', 'AnySQLiteColumn', @@ -179,7 +217,9 @@ export const schemaToTypeScript = ( } } from "drizzle-orm/sqlite-core" import { sql } from "drizzle-orm"\n\n`; - const decalrations = tableStatements.join('\n\n'); + let decalrations = tableStatements.join('\n\n'); + decalrations += '\n\n'; + decalrations += viewsStatements.join('\n\n'); const file = importsTs + decalrations; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index bf456efca..73f125d87 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -9,6 +9,7 @@ import { SQLiteSchemaInternal, SQLiteSchemaSquashed, SQLiteSquasher, + View as SqliteView, } from './serializer/sqliteSchema'; import { AlteredColumn, Column, Sequence, Table } from './snapshotsDiffer'; @@ -530,8 +531,13 @@ export type JsonCreatePgViewStatement = { export type JsonCreateMySqlViewStatement = { type: 'mysql_create_view'; + replace: boolean; } & Omit; +export type JsonCreateSqliteViewStatement = { + type: 'sqlite_create_view'; +} & Omit; + export interface JsonDropViewStatement { type: 'drop_view'; name: string; @@ -682,7 +688,8 @@ export type JsonStatement = | JsonRenameViewStatement | JsonAlterViewStatement | JsonCreateMySqlViewStatement - | JsonAlterMySqlViewStatement; + | JsonAlterMySqlViewStatement + | JsonCreateSqliteViewStatement; export const preparePgCreateTableJson = ( table: Table, @@ -2553,6 +2560,7 @@ export const prepareMySqlCreateViewJson = ( name: string, definition: string, meta: string, + replace: boolean = false, ): JsonCreateMySqlViewStatement => { const { algorithm, definer, sqlSecurity, withCheckOption } = MySqlSquasher.unsquashView(meta); return { @@ -2563,6 +2571,18 @@ export const prepareMySqlCreateViewJson = ( definer, sqlSecurity, withCheckOption, + replace, + }; +}; + +export const prepareSqliteCreateViewJson = ( + name: string, + definition: string, +): JsonCreateSqliteViewStatement => { + return { + type: 'sqlite_create_view', + name: name, + definition: definition, }; }; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index ad557dd03..aac321580 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -74,8 +74,8 @@ export const serializeSQLite = async ( const { prepareFromSqliteImports } = await import('./sqliteImports'); const { generateSqliteSnapshot } = await import('./sqliteSerializer'); - const { tables } = await prepareFromSqliteImports(filenames); - return generateSqliteSnapshot(tables); + const { tables, views } = await prepareFromSqliteImports(filenames); + return generateSqliteSnapshot(tables, views); }; export const prepareFilenames = (path: string | string[]) => { diff --git a/drizzle-kit/src/serializer/sqliteImports.ts b/drizzle-kit/src/serializer/sqliteImports.ts index 534427e47..0164604d1 100644 --- a/drizzle-kit/src/serializer/sqliteImports.ts +++ b/drizzle-kit/src/serializer/sqliteImports.ts @@ -1,21 +1,28 @@ import { is } from 'drizzle-orm'; -import { AnySQLiteTable, SQLiteTable } from 'drizzle-orm/sqlite-core'; +import { AnySQLiteTable, SQLiteTable, SQLiteView } from 'drizzle-orm/sqlite-core'; import { safeRegister } from '../cli/commands/utils'; export const prepareFromExports = (exports: Record) => { const tables: AnySQLiteTable[] = []; + const views: SQLiteView[] = []; + const i0values = Object.values(exports); i0values.forEach((t) => { if (is(t, SQLiteTable)) { tables.push(t); } + + if (is(t, SQLiteView)) { + views.push(t); + } }); - return { tables }; + return { tables, views }; }; export const prepareFromSqliteImports = async (imports: string[]) => { const tables: AnySQLiteTable[] = []; + const views: SQLiteView[] = []; const { unregister } = await safeRegister(); for (let i = 0; i < imports.length; i++) { @@ -25,9 +32,10 @@ export const prepareFromSqliteImports = async (imports: string[]) => { const prepared = prepareFromExports(i0); tables.push(...prepared.tables); + views.push(...prepared.views); } unregister(); - return { tables: Array.from(new Set(tables)) }; + return { tables: Array.from(new Set(tables)), views }; }; diff --git a/drizzle-kit/src/serializer/sqliteSchema.ts b/drizzle-kit/src/serializer/sqliteSchema.ts index a8114e3a8..7ab97f566 100644 --- a/drizzle-kit/src/serializer/sqliteSchema.ts +++ b/drizzle-kit/src/serializer/sqliteSchema.ts @@ -58,6 +58,13 @@ const table = object({ uniqueConstraints: record(string(), uniqueConstraint).default({}), }).strict(); +export const view = object({ + name: string(), + columns: record(string(), column), + definition: string().optional(), + isExisting: boolean(), +}).strict(); + // use main dialect const dialect = enumType(['sqlite']); @@ -77,6 +84,7 @@ export const schemaInternalV4 = object({ version: literal('4'), dialect: dialect, tables: record(string(), table), + views: record(string(), view), enums: object({}), }).strict(); @@ -108,6 +116,7 @@ export const schemaInternal = object({ version: latestVersion, dialect: dialect, tables: record(string(), table), + views: record(string(), view), enums: object({}), _meta: object({ tables: record(string(), string()), @@ -134,6 +143,7 @@ export const schemaSquashed = object({ version: latestVersion, dialect: dialect, tables: record(string(), tableSquashed), + views: record(string(), view), enums: any(), }).strict(); @@ -150,6 +160,7 @@ export type Index = TypeOf; export type ForeignKey = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; +export type View = TypeOf; export const SQLiteSquasher = { squashIdx: (idx: Index) => { @@ -286,6 +297,7 @@ export const squashSqliteScheme = ( version: '6', dialect: json.dialect, tables: mappedTables, + views: json.views, enums: json.enums, }; }; @@ -296,6 +308,7 @@ export const drySQLite = schema.parse({ id: originUUID, prevId: '', tables: {}, + views: {}, enums: {}, _meta: { tables: {}, diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 41edd78a9..9292edc15 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -4,8 +4,11 @@ import { // AnySQLiteColumnBuilder, AnySQLiteTable, getTableConfig, + getViewConfig, SQLiteBaseInteger, + SQLiteColumn, SQLiteSyncDialect, + SQLiteView, uniqueKeyName, } from 'drizzle-orm/sqlite-core'; import { withStyle } from '../cli/validations/outputs'; @@ -19,6 +22,7 @@ import type { SQLiteSchemaInternal, Table, UniqueConstraint, + View, } from '../serializer/sqliteSchema'; import type { SQLiteDB } from '../utils'; import { sqlToStr } from '.'; @@ -27,8 +31,11 @@ const dialect = new SQLiteSyncDialect(); export const generateSqliteSnapshot = ( tables: AnySQLiteTable[], + views: SQLiteView[], ): SQLiteSchemaInternal => { const result: Record = {}; + const resultViews: Record = {}; + const internal: SQLiteKitInternals = { indexes: {} }; for (const table of tables) { // const tableName = getTableName(table); @@ -255,10 +262,83 @@ export const generateSqliteSnapshot = ( }; } + for (const view of views) { + const { name, isExisting, selectedFields, query, schema } = getViewConfig(view); + + const columnsObject: Record = {}; + + const existingView = resultViews[name]; + if (typeof existingView !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated view name across ${ + chalk.underline.blue( + schema ?? 'public', + ) + } schema. Please rename your view`, + ) + }`, + ); + process.exit(1); + } + + for (const key in selectedFields) { + if (is(selectedFields[key], SQLiteColumn)) { + const column = selectedFields[key]; + const notNull: boolean = column.notNull; + const primaryKey: boolean = column.primary; + const generated = column.generated; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + primaryKey, + notNull, + autoincrement: is(column, SQLiteBaseInteger) + ? column.autoIncrement + : false, + generated: generated + ? { + as: is(generated.as, SQL) + ? `(${dialect.sqlToQuery(generated.as as SQL, 'indexes').sql})` + : typeof generated.as === 'function' + ? `(${dialect.sqlToQuery(generated.as() as SQL, 'indexes').sql})` + : `(${generated.as as any})`, + type: generated.mode ?? 'virtual', + } + : undefined, + }; + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default); + } else { + columnToSet.default = typeof column.default === 'string' + ? `'${column.default}'` + : typeof column.default === 'object' + || Array.isArray(column.default) + ? `'${JSON.stringify(column.default)}'` + : column.default; + } + } + columnsObject[column.name] = columnToSet; + } + } + + resultViews[name] = { + columns: columnsObject, + name, + isExisting, + definition: isExisting ? undefined : dialect.sqlToQuery(query!).sql, + }; + } + return { version: '6', dialect: 'sqlite', tables: result, + views: resultViews, enums: {}, _meta: { tables: {}, @@ -363,6 +443,8 @@ export const fromDatabase = async ( ) => void, ): Promise => { const result: Record = {}; + const resultViews: Record = {}; + const columns = await db.query<{ tableName: string; columnName: string; @@ -377,7 +459,7 @@ export const fromDatabase = async ( `SELECT m.name as "tableName", p.name as "columnName", p.type as "columnType", p."notnull" as "notNull", p.dflt_value as "defaultValue", p.pk as pk, p.hidden as hidden, m.sql FROM sqlite_master AS m JOIN pragma_table_xinfo(m.name) AS p - WHERE m.type = 'table' + WHERE m.type = 'table' and m.tbl_name != 'sqlite_sequence' and m.tbl_name != 'sqlite_stat1' and m.tbl_name != '_litestream_seq' @@ -670,10 +752,42 @@ WHERE progressCallback('enums', 0, 'done'); } + const views = await db.query( + `SELECT name AS view_name, sql AS sql FROM sqlite_master WHERE type = 'view';`, + ); + + for (const view of views) { + const viewName = view['view_name']; + const sql = view['sql']; + + const regex = new RegExp(`\\bAS\\b\\s+(SELECT.+)$`, 'i'); + const match = sql.match(regex); + + if (!match) { + console.log('Could not process view'); + process.exit(1); + } + + const viewDefinition = match[1] as string; + + const viewOriginalTableRegex = sql.match(/FROM\s+([^\s;]+)/i); // Matches the table name after 'FROM' + let sourceTable = viewOriginalTableRegex ? viewOriginalTableRegex[1] as string : undefined; + + const columns = sourceTable ? result[sourceTable] ? result[sourceTable].columns : {} : {}; + + resultViews[viewName] = { + columns: columns, + isExisting: false, + name: viewName, + definition: viewDefinition, + }; + } + return { version: '6', dialect: 'sqlite', tables: result, + views: resultViews, enums: {}, _meta: { tables: {}, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 9758538cc..58cab8ced 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -29,6 +29,7 @@ import { JsonCreateMySqlViewStatement, JsonCreatePgViewStatement, JsonCreateReferenceStatement, + JsonCreateSqliteViewStatement, JsonCreateUniqueConstraint, JsonDeleteCompositePK, JsonDeleteUniqueConstraint, @@ -90,13 +91,14 @@ import { prepareRenameViewJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, + prepareSqliteCreateViewJson, } from './jsonStatements'; import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher, ViewSquashed } from './serializer/mysqlSchema'; import { mergedViewWithOption, PgSchema, PgSchemaSquashed, sequenceSquashed, View } from './serializer/pgSchema'; -import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; +import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher, View as SqliteView } from './serializer/sqliteSchema'; import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; import { copy, prepareMigrationMeta } from './utils'; @@ -301,7 +303,7 @@ export const alteredPgViewSchema = alteredViewCommon.merge( }).strict(), ); -export const alteredMySqlViewSchema = alteredViewCommon.merge( +const alteredMySqlViewSchema = alteredViewCommon.merge( object({ alteredMeta: object({ __old: string(), @@ -326,6 +328,7 @@ export const diffResultSchemeMysql = object({ export const diffResultSchemeSQLite = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: never().array(), + alteredViews: alteredViewCommon.array(), }); export type Column = TypeOf; @@ -1461,7 +1464,7 @@ export const applyMysqlSnapshotsDiff = async ( ) => Promise>, viewsResolver: ( input: ResolverInput, - ) => Promise>, + ) => Promise>, prevFull: MySqlSchema, curFull: MySqlSchema, action?: 'push' | undefined, @@ -1622,7 +1625,7 @@ export const applyMysqlSnapshotsDiff = async ( const renamesViewDic: Record = {}; renamedViews.forEach((it) => { - renamesViewDic[`${it.from.schema}.${it.from.name}`] = { to: it.to.name, from: it.from.name }; + renamesViewDic[it.from.name] = { to: it.to.name, from: it.from.name }; }); const viewsPatchedSnap1 = copy(columnsPatchedSnap1); @@ -1914,16 +1917,14 @@ export const applyMysqlSnapshotsDiff = async ( const { definition, meta } = json2.views[alteredView.name]; if (alteredView.alteredDefinition && action !== 'push') { - dropViews.push(prepareDropViewJson(alteredView.name)); - createViews.push( prepareMySqlCreateViewJson( alteredView.name, definition!, meta, + true, ), ); - continue; } if (alteredView.alteredMeta) { @@ -2010,6 +2011,9 @@ export const applySqliteSnapshotsDiff = async ( columnsResolver: ( input: ColumnsResolverInput, ) => Promise>, + viewsResolver: ( + input: ResolverInput, + ) => Promise>, prevFull: SQLiteSchema, curFull: SQLiteSchema, action?: 'push' | undefined, @@ -2122,7 +2126,37 @@ export const applySqliteSnapshotsDiff = async ( }, ); - const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + const viewsDiff = diffSchemasOrTables(json1.views, json2.views); + + const { + created: createdViews, + deleted: deletedViews, + renamed: renamedViews, // renamed or moved + } = await viewsResolver({ + created: viewsDiff.added, + deleted: viewsDiff.deleted, + }); + + const renamesViewDic: Record = {}; + renamedViews.forEach((it) => { + renamesViewDic[it.from.name] = { to: it.to.name, from: it.from.name }; + }); + + const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + viewsPatchedSnap1.views = mapEntries( + viewsPatchedSnap1.views, + (viewKey, viewValue) => { + const rename = renamesViewDic[viewValue.name]; + + if (rename) { + viewValue.name = rename.to; + } + + return [viewKey, viewValue]; + }, + ); + + const diffResult = applyJsonDiff(viewsPatchedSnap1, json2); const typedResult = diffResultSchemeSQLite.parse(diffResult); @@ -2363,6 +2397,52 @@ export const applySqliteSnapshotsDiff = async ( (t) => t.type === 'delete_reference', ); + const createViews: JsonCreateSqliteViewStatement[] = []; + const dropViews: JsonDropViewStatement[] = []; + + createViews.push( + ...createdViews.filter((it) => !it.isExisting).map((it) => { + return prepareSqliteCreateViewJson( + it.name, + it.definition!, + ); + }), + ); + + dropViews.push( + ...deletedViews.filter((it) => !it.isExisting).map((it) => { + return prepareDropViewJson(it.name); + }), + ); + + dropViews.push( + ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { + return prepareDropViewJson(it.from.name); + }), + ); + createViews.push( + ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { + return prepareSqliteCreateViewJson(it.to.name, it.to.definition!); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[it.name].isExisting); + + for (const alteredView of alteredViews) { + const { definition } = json2.views[alteredView.name]; + + if (alteredView.alteredDefinition && action !== 'push') { + dropViews.push(prepareDropViewJson(alteredView.name)); + + createViews.push( + prepareSqliteCreateViewJson( + alteredView.name, + definition!, + ), + ); + } + } + const jsonStatements: JsonStatement[] = []; jsonStatements.push(...jsonCreateTables); @@ -2394,6 +2474,9 @@ export const applySqliteSnapshotsDiff = async ( jsonStatements.push(...jsonAlteredUniqueConstraints); + jsonStatements.push(...dropViews); + jsonStatements.push(...createViews); + const combinedJsonStatements = sqliteCombineStatements(jsonStatements, json2, action); const sqlStatements = fromJson(combinedJsonStatements, 'sqlite'); @@ -2426,6 +2509,9 @@ export const applyLibSQLSnapshotsDiff = async ( columnsResolver: ( input: ColumnsResolverInput, ) => Promise>, + viewsResolver: ( + input: ResolverInput, + ) => Promise>, prevFull: SQLiteSchema, curFull: SQLiteSchema, action?: 'push', @@ -2537,7 +2623,37 @@ export const applyLibSQLSnapshotsDiff = async ( }, ); - const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + const viewsDiff = diffSchemasOrTables(json1.views, json2.views); + + const { + created: createdViews, + deleted: deletedViews, + renamed: renamedViews, // renamed or moved + } = await viewsResolver({ + created: viewsDiff.added, + deleted: viewsDiff.deleted, + }); + + const renamesViewDic: Record = {}; + renamedViews.forEach((it) => { + renamesViewDic[it.from.name] = { to: it.to.name, from: it.from.name }; + }); + + const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + viewsPatchedSnap1.views = mapEntries( + viewsPatchedSnap1.views, + (viewKey, viewValue) => { + const rename = renamesViewDic[viewValue.name]; + + if (rename) { + viewValue.name = rename.to; + } + + return [viewKey, viewValue]; + }, + ); + + const diffResult = applyJsonDiff(viewsPatchedSnap1, json2); const typedResult = diffResultSchemeSQLite.parse(diffResult); @@ -2786,6 +2902,52 @@ export const applyLibSQLSnapshotsDiff = async ( (t) => t.type === 'delete_reference', ); + const createViews: JsonCreateSqliteViewStatement[] = []; + const dropViews: JsonDropViewStatement[] = []; + + createViews.push( + ...createdViews.filter((it) => !it.isExisting).map((it) => { + return prepareSqliteCreateViewJson( + it.name, + it.definition!, + ); + }), + ); + + dropViews.push( + ...deletedViews.filter((it) => !it.isExisting).map((it) => { + return prepareDropViewJson(it.name); + }), + ); + + dropViews.push( + ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { + return prepareDropViewJson(it.from.name); + }), + ); + createViews.push( + ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { + return prepareSqliteCreateViewJson(it.to.name, it.to.definition!); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[it.name].isExisting); + + for (const alteredView of alteredViews) { + const { definition } = json2.views[alteredView.name]; + + if (alteredView.alteredDefinition && action !== 'push') { + dropViews.push(prepareDropViewJson(alteredView.name)); + + createViews.push( + prepareSqliteCreateViewJson( + alteredView.name, + definition!, + ), + ); + } + } + const jsonStatements: JsonStatement[] = []; jsonStatements.push(...jsonCreateTables); @@ -2807,6 +2969,9 @@ export const applyLibSQLSnapshotsDiff = async ( jsonStatements.push(...jsonCreateIndexesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); + jsonStatements.push(...dropViews); + jsonStatements.push(...createViews); + jsonStatements.push(...jsonCreatedReferencesForAlteredTables); jsonStatements.push(...jsonDropColumnsStatemets); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 43992166a..21f16f0f4 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -39,6 +39,7 @@ import { JsonCreateReferenceStatement, JsonCreateSchema, JsonCreateSequenceStatement, + JsonCreateSqliteViewStatement, JsonCreateTableStatement, JsonCreateUniqueConstraint, JsonDeleteCompositePK, @@ -452,9 +453,10 @@ class MySqlCreateViewConvertor extends Convertor { } convert(st: JsonCreateMySqlViewStatement) { - const { definition, name, algorithm, definer, sqlSecurity, withCheckOption } = st; + const { definition, name, algorithm, definer, sqlSecurity, withCheckOption, replace } = st; let statement = `CREATE `; + statement += replace ? `OR REPLACE` : ''; statement += algorithm ? `ALGORITHM = ${algorithm}\n` : ''; statement += definer ? `DEFINER = ${definer}\n` : ''; statement += sqlSecurity ? `SQL SECURITY ${sqlSecurity}\n` : ''; @@ -466,6 +468,19 @@ class MySqlCreateViewConvertor extends Convertor { return statement; } } + +class SqliteCreateViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'sqlite_create_view' && (dialect === 'sqlite' || dialect === 'turso'); + } + + convert(st: JsonCreateSqliteViewStatement) { + const { definition, name } = st; + + return `CREATE VIEW \`${name}\` AS ${definition};`; + } +} + class PgDropViewConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'drop_view' && dialect === 'postgresql'; @@ -492,6 +507,18 @@ class MySqlDropViewConvertor extends Convertor { } } +class SqliteDropViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_view' && (dialect === 'sqlite' || dialect === 'turso'); + } + + convert(st: JsonDropViewStatement) { + const { name } = st; + + return `DROP VIEW \`${name}\`;`; + } +} + class MySqlAlterViewConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'alter_mysql_view' && dialect === 'mysql'; @@ -2735,6 +2762,9 @@ convertors.push(new MySqlDropViewConvertor()); convertors.push(new MySqlRenameViewConvertor()); convertors.push(new MySqlAlterViewConvertor()); +convertors.push(new SqliteCreateViewConvertor()); +convertors.push(new SqliteDropViewConvertor()); + convertors.push(new CreateTypeEnumConvertor()); convertors.push(new CreatePgSequenceConvertor()); diff --git a/drizzle-orm/src/sqlite-core/utils.ts b/drizzle-orm/src/sqlite-core/utils.ts index 2312466c4..33ae2c248 100644 --- a/drizzle-orm/src/sqlite-core/utils.ts +++ b/drizzle-orm/src/sqlite-core/utils.ts @@ -11,7 +11,6 @@ import type { PrimaryKey } from './primary-keys.ts'; import { PrimaryKeyBuilder } from './primary-keys.ts'; import { SQLiteTable } from './table.ts'; import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; -import { SQLiteViewConfig } from './view-common.ts'; import type { SQLiteView } from './view.ts'; export function getTableConfig(table: TTable) { @@ -61,6 +60,6 @@ export function getViewConfig< >(view: SQLiteView) { return { ...view[ViewBaseConfig], - ...view[SQLiteViewConfig], + // ...view[SQLiteViewConfig], }; } diff --git a/drizzle-orm/src/sqlite-core/view.ts b/drizzle-orm/src/sqlite-core/view.ts index d1f11969e..7fc6a7b29 100644 --- a/drizzle-orm/src/sqlite-core/view.ts +++ b/drizzle-orm/src/sqlite-core/view.ts @@ -10,7 +10,7 @@ import { QueryBuilder } from './query-builders/query-builder.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import { sqliteTable } from './table.ts'; import { SQLiteViewBase } from './view-base.ts'; -import { SQLiteViewConfig } from './view-common.ts'; +// import { SQLiteViewConfig } from './view-common.ts'; export interface ViewBuilderConfig { algorithm?: 'undefined' | 'merge' | 'temptable'; @@ -55,7 +55,7 @@ export class ViewBuilder extends ViewBuilderCore< const aliasedSelectedFields = qb.getSelectedFields(); return new Proxy( new SQLiteView({ - sqliteConfig: this.config, + // sqliteConfig: this.config, config: { name: this.name, schema: undefined, @@ -89,7 +89,7 @@ export class ManualViewBuilder< existing(): SQLiteViewWithSelection> { return new Proxy( new SQLiteView({ - sqliteConfig: undefined, + // sqliteConfig: undefined, config: { name: this.name, schema: undefined, @@ -109,7 +109,7 @@ export class ManualViewBuilder< as(query: SQL): SQLiteViewWithSelection> { return new Proxy( new SQLiteView({ - sqliteConfig: this.config, + // sqliteConfig: this.config, config: { name: this.name, schema: undefined, @@ -134,11 +134,11 @@ export class SQLiteView< > extends SQLiteViewBase { static readonly [entityKind]: string = 'SQLiteView'; - /** @internal */ - [SQLiteViewConfig]: ViewBuilderConfig | undefined; + // /** @internal */ + // [SQLiteViewConfig]: ViewBuilderConfig | undefined; - constructor({ sqliteConfig, config }: { - sqliteConfig: ViewBuilderConfig | undefined; + constructor({ config }: { + // sqliteConfig: ViewBuilderConfig | undefined; config: { name: TName; schema: string | undefined; @@ -147,7 +147,7 @@ export class SQLiteView< }; }) { super(config); - this[SQLiteViewConfig] = sqliteConfig; + // this[SQLiteViewConfig] = sqliteConfig; } } From 14316344c4a72e95e24e421003c6c35d489f00cc Mon Sep 17 00:00:00 2001 From: Mario564 Date: Fri, 27 Sep 2024 09:01:52 -0700 Subject: [PATCH 198/492] Change literals for CasingType type --- drizzle-kit/src/cli/schema.ts | 2 +- drizzle-kit/src/cli/validations/common.ts | 2 +- drizzle-kit/src/serializer/index.ts | 4 ++-- drizzle-kit/src/serializer/mysqlSerializer.ts | 4 +--- drizzle-kit/src/serializer/pgSerializer.ts | 4 +--- drizzle-kit/src/serializer/sqliteSerializer.ts | 4 +--- drizzle-kit/src/utils.ts | 2 +- drizzle-kit/tests/cli-push.test.ts | 1 - 8 files changed, 8 insertions(+), 15 deletions(-) diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index e1baa73cd..aaded5cdf 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -41,7 +41,7 @@ const optionDriver = string() .enum(...drivers) .desc('Database driver'); -const optionCasing = string().enum('camel', 'snake').desc('Casing for serialization'); +const optionCasing = string().enum('camelCase', 'snake_case').desc('Casing for serialization'); export const generate = command({ name: 'generate', diff --git a/drizzle-kit/src/cli/validations/common.ts b/drizzle-kit/src/cli/validations/common.ts index c54edfaf5..1662e87bb 100644 --- a/drizzle-kit/src/cli/validations/common.ts +++ b/drizzle-kit/src/cli/validations/common.ts @@ -84,7 +84,7 @@ export type Prefix = (typeof prefixes)[number]; const _: Prefix = '' as TypeOf; } -export const casingTypes = ['snake', 'camel'] as const; +export const casingTypes = ['snake_case', 'camelCase'] as const; export const casingType = enum_(casingTypes); export type CasingType = (typeof casingTypes)[number]; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index 5a67d1aec..8f2543d61 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -21,7 +21,7 @@ export const sqlToStr = (sql: SQL, casing: CasingType | undefined) => { escapeString: () => { throw new Error("we don't support params for `sql` default values"); }, - casing: new CasingCache(casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined), + casing: new CasingCache(casing), }).sql; }; @@ -36,7 +36,7 @@ export const sqlToStrGenerated = (sql: SQL, casing: CasingType | undefined) => { escapeString: () => { throw new Error("we don't support params for `sql` default values"); }, - casing: new CasingCache(casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined), + casing: new CasingCache(casing), }).sql; }; diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 83512991f..da52ac2fb 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -31,9 +31,7 @@ export const generateMySqlSnapshot = ( tables: AnyMySqlTable[], casing: CasingType | undefined, ): MySqlSchemaInternal => { - const dialect = new MySqlDialect({ - casing: casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined, - }); + const dialect = new MySqlDialect({ casing }); const result: Record = {}; const internal: MySqlKitInternals = { tables: {}, indexes: {} }; for (const table of tables) { diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index bfa9ece19..957727dc1 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -120,9 +120,7 @@ export const generatePgSnapshot = ( casing: CasingType | undefined, schemaFilter?: string[], ): PgSchemaInternal => { - const dialect = new PgDialect({ - casing: casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined, - }); + const dialect = new PgDialect({ casing }); const result: Record = {}; const sequencesToReturn: Record = {}; diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index e56050882..f1d28f759 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -29,9 +29,7 @@ export const generateSqliteSnapshot = ( tables: AnySQLiteTable[], casing: CasingType | undefined, ): SQLiteSchemaInternal => { - const dialect = new SQLiteSyncDialect({ - casing: casing === 'camel' ? 'camelCase' : casing === 'snake' ? 'snake_case' : undefined, - }); + const dialect = new SQLiteSyncDialect({ casing }); const result: Record = {}; const internal: SQLiteKitInternals = { indexes: {} }; for (const table of tables) { diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 9cad8f9cc..c13467da3 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -366,7 +366,7 @@ export function getColumnCasing( if (!column.name) return ''; return !column.keyAsName || casing === undefined ? column.name - : casing === 'camel' + : casing === 'camelCase' ? toCamelCase(column.name) : toSnakeCase(column.name); } diff --git a/drizzle-kit/tests/cli-push.test.ts b/drizzle-kit/tests/cli-push.test.ts index 961b08a2d..e6f26eeb5 100644 --- a/drizzle-kit/tests/cli-push.test.ts +++ b/drizzle-kit/tests/cli-push.test.ts @@ -15,7 +15,6 @@ import { push } from '../src/cli/schema'; test('push #1', async (t) => { const res = await brotest(push, ''); - console.log(res); if (res.type !== 'handler') assert.fail(res.type, 'handler'); expect(res.options).toStrictEqual({ dialect: 'postgresql', From 805dc4f53c24fd99001e00a07dd487f51598c611 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Fri, 27 Sep 2024 09:08:35 -0700 Subject: [PATCH 199/492] Update tests --- drizzle-kit/tests/mysql.test.ts | 4 ++-- drizzle-kit/tests/pg-tables.test.ts | 4 ++-- drizzle-kit/tests/sqlite-tables.test.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drizzle-kit/tests/mysql.test.ts b/drizzle-kit/tests/mysql.test.ts index b6d1b4b57..b7e8cc1cf 100644 --- a/drizzle-kit/tests/mysql.test.ts +++ b/drizzle-kit/tests/mysql.test.ts @@ -619,7 +619,7 @@ test('optional db aliases (snake case)', async () => { t3, }; - const { sqlStatements } = await diffTestSchemasMysql(from, to, [], false, 'snake'); + const { sqlStatements } = await diffTestSchemasMysql(from, to, [], false, 'snake_case'); const st1 = `CREATE TABLE \`t1\` ( \`t1_id1\` int NOT NULL, @@ -710,7 +710,7 @@ test('optional db aliases (camel case)', async () => { t3, }; - const { sqlStatements } = await diffTestSchemasMysql(from, to, [], false, 'camel'); + const { sqlStatements } = await diffTestSchemasMysql(from, to, [], false, 'camelCase'); const st1 = `CREATE TABLE \`t1\` ( \`t1Id1\` int NOT NULL, diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index a9face31f..79a21a695 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -694,7 +694,7 @@ test('optional db aliases (snake case)', async () => { t3, }; - const { sqlStatements } = await diffTestSchemas(from, to, [], false, 'snake'); + const { sqlStatements } = await diffTestSchemas(from, to, [], false, 'snake_case'); const st1 = `CREATE TABLE IF NOT EXISTS "t1" ( "t1_id1" integer PRIMARY KEY NOT NULL, @@ -792,7 +792,7 @@ test('optional db aliases (camel case)', async () => { t3, }; - const { sqlStatements } = await diffTestSchemas(from, to, [], false, 'camel'); + const { sqlStatements } = await diffTestSchemas(from, to, [], false, 'camelCase'); const st1 = `CREATE TABLE IF NOT EXISTS "t1" ( "t1Id1" integer PRIMARY KEY NOT NULL, diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index 0f87c44e4..81ac7f100 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -459,7 +459,7 @@ test('optional db aliases (snake case)', async () => { t3, }; - const { sqlStatements } = await diffTestSchemasSqlite(from, to, [], false, 'snake'); + const { sqlStatements } = await diffTestSchemasSqlite(from, to, [], false, 'snake_case'); const st1 = `CREATE TABLE \`t1\` ( \`t1_id1\` integer PRIMARY KEY NOT NULL, @@ -546,7 +546,7 @@ test('optional db aliases (camel case)', async () => { t3, }; - const { sqlStatements } = await diffTestSchemasSqlite(from, to, [], false, 'camel'); + const { sqlStatements } = await diffTestSchemasSqlite(from, to, [], false, 'camelCase'); const st1 = `CREATE TABLE \`t1\` ( \`t1Id1\` integer PRIMARY KEY NOT NULL, From 1fba8751544a49b112482cef90f24e5da7949f2a Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 1 Oct 2024 15:26:29 +0300 Subject: [PATCH 200/492] Fixed count builders imports importing modules from index instead of dedicated locations --- drizzle-orm/src/mysql-core/query-builders/count.ts | 5 ++--- drizzle-orm/src/pg-core/query-builders/count.ts | 5 ++--- drizzle-orm/src/sqlite-core/query-builders/count.ts | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index 645bb4753..e61b27011 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -1,6 +1,5 @@ -import { entityKind, sql } from '~/index.ts'; -import type { SQLWrapper } from '~/sql/sql.ts'; -import { SQL } from '~/sql/sql.ts'; +import { entityKind } from '~/entity.ts'; +import { SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import type { MySqlSession } from '../session.ts'; import type { MySqlTable } from '../table.ts'; import type { MySqlViewBase } from '../view-base.ts'; diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index c93cbb18d..c823f7c6f 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -1,6 +1,5 @@ -import { entityKind, sql } from '~/index.ts'; -import type { SQLWrapper } from '~/sql/sql.ts'; -import { SQL } from '~/sql/sql.ts'; +import { entityKind } from '~/entity.ts'; +import { SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import type { PgSession } from '../session.ts'; import type { PgTable } from '../table.ts'; diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index 1b19eed07..424276825 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -1,6 +1,5 @@ -import { entityKind, sql } from '~/index.ts'; -import type { SQLWrapper } from '~/sql/sql.ts'; -import { SQL } from '~/sql/sql.ts'; +import { entityKind } from '~/entity.ts'; +import { SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteSession } from '../session.ts'; import type { SQLiteTable } from '../table.ts'; import type { SQLiteView } from '../view.ts'; From 8a9059390fc8950cd2b1f9a6637a5ad2050cdd9c Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 1 Oct 2024 15:43:57 +0300 Subject: [PATCH 201/492] Additional import fixes --- drizzle-orm/src/aws-data-api/pg/driver.ts | 5 +++-- drizzle-orm/src/expo-sqlite/query.ts | 4 +++- drizzle-orm/src/pg-core/columns/common.ts | 2 +- drizzle-orm/src/sql/functions/vector.ts | 2 +- drizzle-orm/src/sqlite-core/query-builders/raw.ts | 2 +- drizzle-orm/type-tests/mysql/tables.ts | 4 +++- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index cd7eb9d7e..33016c5d1 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -1,6 +1,4 @@ import { entityKind, is } from '~/entity.ts'; -import type { SQL, SQLWrapper } from '~/index.ts'; -import { Param, sql, Table } from '~/index.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; import { PgDatabase } from '~/pg-core/db.ts'; @@ -14,6 +12,9 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; +import { Param, sql } from '~/sql/sql.ts'; +import type { SQL, SQLWrapper } from '~/sql/sql.ts'; +import { Table } from '~/table.ts'; import type { DrizzleConfig, UpdateSet } from '~/utils.ts'; import type { AwsDataApiClient, AwsDataApiPgQueryResult, AwsDataApiPgQueryResultHKT } from './session.ts'; import { AwsDataApiSession } from './session.ts'; diff --git a/drizzle-orm/src/expo-sqlite/query.ts b/drizzle-orm/src/expo-sqlite/query.ts index db467ce2c..8d9c5e4d9 100644 --- a/drizzle-orm/src/expo-sqlite/query.ts +++ b/drizzle-orm/src/expo-sqlite/query.ts @@ -1,9 +1,11 @@ import { addDatabaseChangeListener } from 'expo-sqlite/next'; import { useEffect, useState } from 'react'; -import { is, SQL, Subquery } from '~/index.ts'; +import { is } from '~/entity.ts'; +import { SQL } from '~/sql/sql.ts'; import type { AnySQLiteSelect } from '~/sqlite-core/index.ts'; import { getTableConfig, getViewConfig, SQLiteTable, SQLiteView } from '~/sqlite-core/index.ts'; import { SQLiteRelationalQuery } from '~/sqlite-core/query-builders/query.ts'; +import { Subquery } from '~/subquery.ts'; export const useLiveQuery = | SQLiteRelationalQuery<'sync', unknown>>( query: T, diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index a7440e24c..30021ba82 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -14,10 +14,10 @@ import { Column } from '~/column.ts'; import { entityKind, is } from '~/entity.ts'; import type { Update } from '~/utils.ts'; -import type { SQL } from '~/index.ts'; import type { ForeignKey, UpdateDeleteAction } from '~/pg-core/foreign-keys.ts'; import { ForeignKeyBuilder } from '~/pg-core/foreign-keys.ts'; import type { AnyPgTable, PgTable } from '~/pg-core/table.ts'; +import type { SQL } from '~/sql/sql.ts'; import { iife } from '~/tracing-utils.ts'; import type { PgIndexOpClass } from '../indexes.ts'; import { uniqueKeyName } from '../unique-constraint.ts'; diff --git a/drizzle-orm/src/sql/functions/vector.ts b/drizzle-orm/src/sql/functions/vector.ts index 1b8f62451..fb0eadfc7 100644 --- a/drizzle-orm/src/sql/functions/vector.ts +++ b/drizzle-orm/src/sql/functions/vector.ts @@ -1,4 +1,4 @@ -import type { AnyColumn } from '~/index.ts'; +import type { AnyColumn } from '~/column.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import { type SQL, sql, type SQLWrapper } from '../sql.ts'; diff --git a/drizzle-orm/src/sqlite-core/query-builders/raw.ts b/drizzle-orm/src/sqlite-core/query-builders/raw.ts index 48fc5fbf9..10ddb38bd 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/raw.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/raw.ts @@ -1,8 +1,8 @@ import { entityKind } from '~/entity.ts'; -import type { SQL, SQLWrapper } from '~/index.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; import type { PreparedQuery } from '~/session.ts'; +import type { SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteAsyncDialect } from '../dialect.ts'; type SQLiteRawAction = 'all' | 'get' | 'values' | 'run'; diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index eac796e6f..d34587983 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -1,6 +1,6 @@ import { type Equal, Expect } from 'type-tests/utils.ts'; +import type { BuildColumn } from '~/column-builder.ts'; import { eq, gt } from '~/expressions.ts'; -import type { BuildColumn, InferSelectModel, Simplify } from '~/index.ts'; import { bigint, char, @@ -30,6 +30,8 @@ import { import { mysqlSchema } from '~/mysql-core/schema.ts'; import { mysqlView, type MySqlViewWithSelection } from '~/mysql-core/view.ts'; import { sql } from '~/sql/sql.ts'; +import type { InferSelectModel } from '~/table.ts'; +import type { Simplify } from '~/utils.ts'; import { db } from './db.ts'; export const users = mysqlTable( From 30d750529c9b07a4a456a581cc51471d594adaa0 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 1 Oct 2024 15:56:01 +0300 Subject: [PATCH 202/492] Fixed type imports being imported as entities --- drizzle-orm/src/aws-data-api/pg/driver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index a5ae5acc1..479cc32fe 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -12,7 +12,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { Param, SQL, sql, SQLWrapper } from '~/sql/sql.ts'; +import { Param, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import { Table } from '~/table.ts'; import type { DrizzleConfig, UpdateSet } from '~/utils.ts'; import type { AwsDataApiClient, AwsDataApiPgQueryResult, AwsDataApiPgQueryResultHKT } from './session.ts'; From 009d67a40a3bd2052229f5bb1a79118dc8139389 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 1 Oct 2024 16:04:14 +0300 Subject: [PATCH 203/492] Removed monodriver, monomigrator to `\/connect` --- drizzle-orm/src/connect.ts | 2 ++ drizzle-orm/src/index.ts | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 drizzle-orm/src/connect.ts diff --git a/drizzle-orm/src/connect.ts b/drizzle-orm/src/connect.ts new file mode 100644 index 000000000..835dc8dcb --- /dev/null +++ b/drizzle-orm/src/connect.ts @@ -0,0 +1,2 @@ +export * from './monodriver'; +export * from './monomigrator'; diff --git a/drizzle-orm/src/index.ts b/drizzle-orm/src/index.ts index 469f5713e..bc72260b9 100644 --- a/drizzle-orm/src/index.ts +++ b/drizzle-orm/src/index.ts @@ -5,8 +5,6 @@ export * from './entity.ts'; export * from './errors.ts'; export * from './expressions.ts'; export * from './logger.ts'; -export * from './monodriver.ts'; -export * from './monomigrator.ts'; export * from './operations.ts'; export * from './query-promise.ts'; export * from './relations.ts'; From b8bf113f03da8da64afef62fa86ac4704ff57d91 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 1 Oct 2024 16:10:17 +0300 Subject: [PATCH 204/492] Fixed lack of file extensions in imports --- drizzle-orm/src/connect.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/connect.ts b/drizzle-orm/src/connect.ts index 835dc8dcb..6e26b2922 100644 --- a/drizzle-orm/src/connect.ts +++ b/drizzle-orm/src/connect.ts @@ -1,2 +1,2 @@ -export * from './monodriver'; -export * from './monomigrator'; +export * from './monodriver.ts'; +export * from './monomigrator.ts'; From b7df301c00cb146c1b1e0daf23ee63156f303e65 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 2 Oct 2024 11:21:42 +0300 Subject: [PATCH 205/492] added all tests for all dialect views. updated introspect tests --- drizzle-kit/src/api.ts | 5 +- drizzle-kit/src/cli/commands/introspect.ts | 9 +- drizzle-kit/src/introspect-mysql.ts | 3 +- drizzle-kit/src/jsonDiffer.js | 2 +- drizzle-kit/src/jsonStatements.ts | 45 +- drizzle-kit/src/serializer/mysqlSchema.ts | 19 +- drizzle-kit/src/serializer/mysqlSerializer.ts | 8 +- .../src/serializer/sqliteSerializer.ts | 7 +- drizzle-kit/src/snapshotsDiffer.ts | 47 +- drizzle-kit/src/sqlgenerator.ts | 12 +- drizzle-kit/tests/introspect/libsql.test.ts | 35 + drizzle-kit/tests/introspect/mysql.test.ts | 52 +- drizzle-kit/tests/introspect/pg.test.ts | 32 +- drizzle-kit/tests/introspect/sqlite.test.ts | 25 +- drizzle-kit/tests/libsql-views.test.ts | 212 ++ drizzle-kit/tests/mysql-views.test.ts | 553 ++++ drizzle-kit/tests/pg-views.test.ts | 19 +- drizzle-kit/tests/push/libsql.test.ts | 104 + drizzle-kit/tests/push/mysql-push.test.ts | 214 ++ drizzle-kit/tests/push/pg.test.ts | 2243 ++++++++--------- drizzle-kit/tests/push/sqlite.test.ts | 101 +- drizzle-kit/tests/schemaDiffer.ts | 384 ++- drizzle-kit/tests/sqlite-views.test.ts | 212 ++ .../libsql-statements-combiner.test.ts | 16 + .../sqlite-statements-combiner.test.ts | 14 + drizzle-orm/src/mysql-core/view.ts | 8 - 26 files changed, 3084 insertions(+), 1297 deletions(-) create mode 100644 drizzle-kit/tests/introspect/libsql.test.ts create mode 100644 drizzle-kit/tests/libsql-views.test.ts create mode 100644 drizzle-kit/tests/mysql-views.test.ts create mode 100644 drizzle-kit/tests/push/mysql-push.test.ts create mode 100644 drizzle-kit/tests/sqlite-views.test.ts diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index cd133e97b..c78fba372 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -8,6 +8,7 @@ import { mySqlViewsResolver, schemasResolver, sequencesResolver, + sqliteViewsResolver, tablesResolver, viewsResolver, } from './cli/commands/migrate'; @@ -152,7 +153,7 @@ export const generateSQLiteDrizzleJson = async ( const id = randomUUID(); - const snapshot = generateSqliteSnapshot(prepared.tables); + const snapshot = generateSqliteSnapshot(prepared.tables, prepared.views); return { ...snapshot, @@ -178,6 +179,7 @@ export const generateSQLiteMigration = async ( squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, ); @@ -218,6 +220,7 @@ export const pushSQLiteSchema = async ( squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, 'push', diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index f033a6900..257150dc0 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -14,7 +14,12 @@ import { dryPg, type PgSchema, squashPgScheme } from '../../serializer/pgSchema' import { fromDatabase as fromPostgresDatabase } from '../../serializer/pgSerializer'; import { drySQLite, type SQLiteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase } from '../../serializer/sqliteSerializer'; -import { applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, applySqliteSnapshotsDiff } from '../../snapshotsDiffer'; +import { + applyLibSQLSnapshotsDiff, + applyMysqlSnapshotsDiff, + applyPgSnapshotsDiff, + applySqliteSnapshotsDiff, +} from '../../snapshotsDiffer'; import { prepareOutFolder } from '../../utils'; import type { Casing, Prefix } from '../validations/common'; import { LibSQLCredentials } from '../validations/libsql'; @@ -433,7 +438,7 @@ export const introspectLibSQL = async ( const { snapshots, journal } = prepareOutFolder(out, 'sqlite'); if (snapshots.length === 0) { - const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( + const { sqlStatements, _meta } = await applyLibSQLSnapshotsDiff( squashSqliteScheme(drySQLite), squashSqliteScheme(schema), tablesResolver, diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index af19fc2cf..669c7b9b5 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -269,7 +269,7 @@ export const schemaToTypeScript = ( }); const viewsStatements = Object.values(schema.views).map((view) => { - const { columns, name, algorithm, definer, definition, sqlSecurity, withCheckOption } = view; + const { columns, name, algorithm, definition, sqlSecurity, withCheckOption } = view; const func = 'mysqlView'; let statement = ''; @@ -292,7 +292,6 @@ export const schemaToTypeScript = ( statement += '})'; statement += algorithm ? `.algorithm("${algorithm}")` : ''; - statement += definer ? `.definer("${definer}")` : ''; statement += sqlSecurity ? `.sqlSecurity("${sqlSecurity}")` : ''; statement += withCheckOption ? `.withCheckOption("${withCheckOption}")` : ''; statement += `.as(sql\`${definition?.replaceAll('`', '\\`')}\`);`; diff --git a/drizzle-kit/src/jsonDiffer.js b/drizzle-kit/src/jsonDiffer.js index 41af18868..25cb82bb4 100644 --- a/drizzle-kit/src/jsonDiffer.js +++ b/drizzle-kit/src/jsonDiffer.js @@ -307,13 +307,13 @@ export function applyJsonDiff(json1, json2) { addedWith: Object.keys(addedWith).length ? addedWith : undefined, alteredWith: Object.keys(alterWith).length ? alterWith : undefined, alteredSchema, - alteredExisting, alteredTablespace, alteredUsing, // mysql alteredMeta, // common alteredDefinition, + alteredExisting, }).filter(([_, value]) => value !== undefined), ); }, diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 73f125d87..98e8c5825 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -541,7 +541,7 @@ export type JsonCreateSqliteViewStatement = { export interface JsonDropViewStatement { type: 'drop_view'; name: string; - schema: string; + schema?: string; materialized?: boolean; } @@ -566,7 +566,7 @@ export interface JsonAlterViewAlterSchemaStatement { fromSchema: string; toSchema: string; name: string; - materialized: boolean; + materialized?: boolean; } export type JsonAlterViewAddWithOptionStatement = @@ -2562,13 +2562,12 @@ export const prepareMySqlCreateViewJson = ( meta: string, replace: boolean = false, ): JsonCreateMySqlViewStatement => { - const { algorithm, definer, sqlSecurity, withCheckOption } = MySqlSquasher.unsquashView(meta); + const { algorithm, sqlSecurity, withCheckOption } = MySqlSquasher.unsquashView(meta); return { type: 'mysql_create_view', name: name, definition: definition, algorithm, - definer, sqlSecurity, withCheckOption, replace, @@ -2588,45 +2587,51 @@ export const prepareSqliteCreateViewJson = ( export const prepareDropViewJson = ( name: string, - schema: string = '', - materialized: boolean = false, + schema?: string, + materialized?: boolean, ): JsonDropViewStatement => { - return { - type: 'drop_view', - name, - schema, - materialized, - }; + const resObject: JsonDropViewStatement = { name, type: 'drop_view' }; + + if (schema) resObject['schema'] = schema; + + if (materialized) resObject['materialized'] = materialized; + + return resObject; }; export const prepareRenameViewJson = ( to: string, from: string, - schema: string = '', - materialized: boolean = false, + schema?: string, + materialized?: boolean, ): JsonRenameViewStatement => { - return { + const resObject: JsonRenameViewStatement = { type: 'rename_view', nameTo: to, nameFrom: from, - schema, - materialized, }; + + if (schema) resObject['schema'] = schema; + if (materialized) resObject['materialized'] = materialized; + + return resObject; }; export const preparePgAlterViewAlterSchemaJson = ( to: string, from: string, name: string, - materialized: boolean, + materialized?: boolean, ): JsonAlterViewAlterSchemaStatement => { - return { + const returnObject: JsonAlterViewAlterSchemaStatement = { type: 'alter_view_alter_schema', fromSchema: from, toSchema: to, name, - materialized, }; + + if (materialized) returnObject['materialized'] = materialized; + return returnObject; }; export const preparePgAlterViewAddWithOptionJson = ( diff --git a/drizzle-kit/src/serializer/mysqlSchema.ts b/drizzle-kit/src/serializer/mysqlSchema.ts index f4caf7038..4932918fc 100644 --- a/drizzle-kit/src/serializer/mysqlSchema.ts +++ b/drizzle-kit/src/serializer/mysqlSchema.ts @@ -70,9 +70,8 @@ const table = object({ }).strict(); const viewMeta = object({ - definer: string().optional(), - algorithm: enumType(['undefined', 'merge', 'temptable']).optional(), - sqlSecurity: enumType(['definer', 'invoker']).optional(), + algorithm: enumType(['undefined', 'merge', 'temptable']), + sqlSecurity: enumType(['definer', 'invoker']), withCheckOption: enumType(['local', 'cascaded']).optional(), }).strict(); @@ -82,7 +81,7 @@ export const view = object({ definition: string().optional(), isExisting: boolean(), }).strict().merge(viewMeta); -type ViewMeta = TypeOf; +type SquasherViewMeta = Omit, 'definer'>; export const kitInternals = object({ tables: record( @@ -175,7 +174,6 @@ const tableSquashed = object({ const viewSquashed = view.omit({ algorithm: true, - definer: true, sqlSecurity: true, withCheckOption: true, }).extend({ meta: string() }); @@ -274,14 +272,13 @@ export const MySqlSquasher = { return result; }, squashView: (view: View): string => { - return `${view.algorithm};${view.definer};${view.sqlSecurity};${view.withCheckOption}`; + return `${view.algorithm};${view.sqlSecurity};${view.withCheckOption}`; }, - unsquashView: (meta: string): ViewMeta => { - const [algorithm, definer, sqlSecurity, withCheckOption] = meta.split(';'); + unsquashView: (meta: string): SquasherViewMeta => { + const [algorithm, sqlSecurity, withCheckOption] = meta.split(';'); const toReturn = { - algorithm: algorithm !== 'undefined' ? algorithm : undefined, - definer: definer !== 'undefined' ? definer : undefined, - sqlSecurity: sqlSecurity !== 'undefined' ? sqlSecurity : undefined, + algorithm: algorithm, + sqlSecurity: sqlSecurity, withCheckOption: withCheckOption !== 'undefined' ? withCheckOption : undefined, }; diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 92db9bfa9..7c95416a8 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -353,7 +353,6 @@ export const generateMySqlSnapshot = ( schema, selectedFields, algorithm, - definer, sqlSecurity, withCheckOption, } = getViewConfig(view); @@ -451,9 +450,8 @@ export const generateMySqlSnapshot = ( isExisting, definition: isExisting ? undefined : dialect.sqlToQuery(query!).sql, withCheckOption, - definer, - algorithm, - sqlSecurity, + algorithm: algorithm ?? 'undefined', // set default values + sqlSecurity: sqlSecurity ?? 'definer', // set default values }; } @@ -843,7 +841,6 @@ export const fromDatabase = async ( const definition = view['VIEW_DEFINITION']; const withCheckOption = view['CHECK_OPTION'] === 'NONE' ? undefined : view['CHECK_OPTION'].toLowerCase(); - const definer = view['DEFINER'].split('@').map((it: string) => `'${it}'`).join('@'); const sqlSecurity = view['SECURITY_TYPE'].toLowerCase(); const [createSqlStatement] = await db.query(`SHOW CREATE VIEW \`${viewName}\`;`); @@ -857,7 +854,6 @@ export const fromDatabase = async ( columns: columns, isExisting: false, name: viewName, - definer, algorithm, definition, sqlSecurity, diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 9292edc15..e2f865afc 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -770,8 +770,13 @@ WHERE const viewDefinition = match[1] as string; + // CREATE VIEW test_view AS SELECT * FROM users; + // CREATE VIEW test_view1 AS SELECT * FROM `users`; + // CREATE VIEW test_view2 AS SELECT * FROM "users"; const viewOriginalTableRegex = sql.match(/FROM\s+([^\s;]+)/i); // Matches the table name after 'FROM' - let sourceTable = viewOriginalTableRegex ? viewOriginalTableRegex[1] as string : undefined; + let sourceTable = viewOriginalTableRegex + ? (viewOriginalTableRegex[1] as string).replaceAll('"', '').replaceAll('`', '').replaceAll("'", '') + : undefined; const columns = sourceTable ? result[sourceTable] ? result[sourceTable].columns : {} : {}; diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 58cab8ced..81c65baf9 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -274,6 +274,10 @@ const alteredViewCommon = object({ __old: string(), __new: string(), }).strict().optional(), + alteredExisting: object({ + __old: boolean(), + __new: boolean(), + }).strict().optional(), }); export const alteredPgViewSchema = alteredViewCommon.merge( @@ -283,15 +287,11 @@ export const alteredPgViewSchema = alteredViewCommon.merge( addedWithOption: mergedViewWithOption.optional(), addedWith: mergedViewWithOption.optional(), deletedWith: mergedViewWithOption.optional(), - alterWith: mergedViewWithOption.optional(), + alteredWith: mergedViewWithOption.optional(), alteredSchema: object({ __old: string(), __new: string(), }).strict().optional(), - alteredExisting: object({ - __old: boolean(), - __new: boolean(), - }).strict().optional(), alteredTablespace: object({ __old: string(), __new: string(), @@ -1223,13 +1223,16 @@ export const applyPgSnapshotsDiff = async ( ); renameViews.push( - ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { - return prepareRenameViewJson(it.to.name, it.from.name, it.to.schema, it.to.materialized); - }), + ...renamedViews.filter((it) => !it.to.isExisting && !json1.views[`${it.from.schema}.${it.from.name}`].isExisting) + .map((it) => { + return prepareRenameViewJson(it.to.name, it.from.name, it.to.schema, it.to.materialized); + }), ); alterViews.push( - ...movedViews.filter((it) => !json2.views[`${it.schemaTo}.${it.name}`].isExisting).map((it) => { + ...movedViews.filter((it) => + !json2.views[`${it.schemaTo}.${it.name}`].isExisting && !json1.views[`${it.schemaFrom}.${it.name}`].isExisting + ).map((it) => { return preparePgAlterViewAlterSchemaJson( it.schemaTo, it.schemaFrom, @@ -1261,6 +1264,7 @@ export const applyPgSnapshotsDiff = async ( tablespace, ), ); + continue; } @@ -1308,13 +1312,13 @@ export const applyPgSnapshotsDiff = async ( ); } - if (alteredView.alterWith) { + if (alteredView.alteredWith) { alterViews.push( preparePgAlterViewAddWithOptionJson( alteredView.name, alteredView.schema, materialized, - alteredView.alterWith, + alteredView.alteredWith, ), ); } @@ -1636,6 +1640,7 @@ export const applyMysqlSnapshotsDiff = async ( if (rename) { viewValue.name = rename.to; + viewKey = rename.to; } return [viewKey, viewValue]; @@ -1906,7 +1911,7 @@ export const applyMysqlSnapshotsDiff = async ( ); renameViews.push( - ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { + ...renamedViews.filter((it) => !it.to.isExisting && !json1.views[it.from.name].isExisting).map((it) => { return prepareRenameViewJson(it.to.name, it.from.name); }), ); @@ -1916,6 +1921,20 @@ export const applyMysqlSnapshotsDiff = async ( for (const alteredView of alteredViews) { const { definition, meta } = json2.views[alteredView.name]; + if (alteredView.alteredExisting) { + dropViews.push(prepareDropViewJson(alteredView.name)); + + createViews.push( + prepareMySqlCreateViewJson( + alteredView.name, + definition!, + meta, + ), + ); + + continue; + } + if (alteredView.alteredDefinition && action !== 'push') { createViews.push( prepareMySqlCreateViewJson( @@ -1925,10 +1944,11 @@ export const applyMysqlSnapshotsDiff = async ( true, ), ); + continue; } if (alteredView.alteredMeta) { - const view = { ...curFull['views'][alteredView.name], isExisting: undefined }; + const view = curFull['views'][alteredView.name]; alterViews.push( prepareMySqlAlterView(view), ); @@ -2920,6 +2940,7 @@ export const applyLibSQLSnapshotsDiff = async ( }), ); + // renames dropViews.push( ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { return prepareDropViewJson(it.from.name); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 21f16f0f4..c825b4ac3 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -453,14 +453,13 @@ class MySqlCreateViewConvertor extends Convertor { } convert(st: JsonCreateMySqlViewStatement) { - const { definition, name, algorithm, definer, sqlSecurity, withCheckOption, replace } = st; + const { definition, name, algorithm, sqlSecurity, withCheckOption, replace } = st; let statement = `CREATE `; - statement += replace ? `OR REPLACE` : ''; + statement += replace ? `OR REPLACE ` : ''; statement += algorithm ? `ALGORITHM = ${algorithm}\n` : ''; - statement += definer ? `DEFINER = ${definer}\n` : ''; statement += sqlSecurity ? `SQL SECURITY ${sqlSecurity}\n` : ''; - statement += `VIEW \`${name}\` AS ${definition}`; + statement += `VIEW \`${name}\` AS (${definition})`; statement += withCheckOption ? `\nWITH ${withCheckOption} CHECK OPTION` : ''; statement += ';'; @@ -503,7 +502,7 @@ class MySqlDropViewConvertor extends Convertor { convert(st: JsonDropViewStatement) { const { name } = st; - return `DROP VIEW ${name};`; + return `DROP VIEW \`${name}\`;`; } } @@ -525,11 +524,10 @@ class MySqlAlterViewConvertor extends Convertor { } convert(st: JsonAlterMySqlViewStatement) { - const { name, algorithm, definer, definition, sqlSecurity, withCheckOption } = st; + const { name, algorithm, definition, sqlSecurity, withCheckOption } = st; let statement = `ALTER `; statement += algorithm ? `ALGORITHM = ${algorithm}\n` : ''; - statement += definer ? `DEFINER = ${definer}\n` : ''; statement += sqlSecurity ? `SQL SECURITY ${sqlSecurity}\n` : ''; statement += `VIEW \`${name}\` AS ${definition}`; statement += withCheckOption ? `\nWITH ${withCheckOption} CHECK OPTION` : ''; diff --git a/drizzle-kit/tests/introspect/libsql.test.ts b/drizzle-kit/tests/introspect/libsql.test.ts new file mode 100644 index 000000000..9211989ca --- /dev/null +++ b/drizzle-kit/tests/introspect/libsql.test.ts @@ -0,0 +1,35 @@ +import { createClient } from '@libsql/client'; +import { sql } from 'drizzle-orm'; +import { int, sqliteTable, sqliteView } from 'drizzle-orm/sqlite-core'; +import fs from 'fs'; +import { introspectLibSQLToFile, introspectMySQLToFile, introspectSQLiteToFile } from 'tests/schemaDiffer'; +import { expect, test } from 'vitest'; + +if (!fs.existsSync('tests/introspect/libsql')) { + fs.mkdirSync('tests/introspect/libsql'); +} + +test('view #1', async () => { + const turso = createClient({ + url: ':memory:', + }); + + const users = sqliteTable('users', { id: int('id') }); + const testView = sqliteView('some_view', { id: int('id') }).as( + sql`SELECT * FROM ${users}`, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectLibSQLToFile( + turso, + schema, + 'view-1', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/introspect/mysql.test.ts b/drizzle-kit/tests/introspect/mysql.test.ts index e35b34f40..ae7953885 100644 --- a/drizzle-kit/tests/introspect/mysql.test.ts +++ b/drizzle-kit/tests/introspect/mysql.test.ts @@ -1,6 +1,6 @@ import Docker from 'dockerode'; import { SQL, sql } from 'drizzle-orm'; -import { char, int, mysqlTable, text, varchar } from 'drizzle-orm/mysql-core'; +import { char, int, mysqlTable, mysqlView, text, varchar } from 'drizzle-orm/mysql-core'; import * as fs from 'fs'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; @@ -165,3 +165,53 @@ test('Default value of character type column: varchar', async () => { await client.query(`drop table users;`); }); + +test('view #1', async () => { + const users = mysqlTable('users', { id: int('id') }); + const testView = mysqlView('some_view', { id: int('id') }).as( + sql`select \`drizzle\`.\`users\`.\`id\` AS \`id\` from \`drizzle\`.\`users\``, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'view-1', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`drop view some_view;`); + await client.query(`drop table users;`); +}); + +test('view #2', async () => { + const users = mysqlTable('users', { id: int('id') }); + const testView = mysqlView('some_view', { id: int('id') }).algorithm('temptable').sqlSecurity('definer').as( + sql`SELECT * FROM ${users}`, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'view-2', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`drop view some_view;`); + await client.query(`drop table users;`); +}); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index 5415f3956..f47e3e2c6 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -456,7 +456,7 @@ test('introspect view #2', async () => { const { statements, sqlStatements } = await introspectPgToFile( client, schema, - 'introspect-view-#2', + 'introspect-view-2', ); expect(statements.length).toBe(0); @@ -485,6 +485,7 @@ test('introspect view in other schema', async () => { client, schema, 'introspect-view-in-other-schema', + ['new_schema'], ); expect(statements.length).toBe(0); @@ -513,6 +514,7 @@ test('introspect materialized view in other schema', async () => { client, schema, 'introspect-view-in-other-schema', + ['new_schema'], ); expect(statements.length).toBe(0); @@ -543,32 +545,6 @@ test('introspect materialized view #1', async () => { expect(sqlStatements.length).toBe(0); }); -test('introspect view #2', async () => { - const client = new PGlite(); - - const users = pgTable('users', { - id: serial('id').primaryKey().notNull(), - name: varchar('users'), - }); - - const view = pgView('some_view', { id: integer('asd') }).with({ checkOption: 'cascaded' }).as( - sql`SELECT * FROM ${users}`, - ); - const schema = { - view, - users, - }; - - const { statements, sqlStatements } = await introspectPgToFile( - client, - schema, - 'introspect-view-#2', - ); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); - test('introspect materialized view #2', async () => { const client = new PGlite(); @@ -588,7 +564,7 @@ test('introspect materialized view #2', async () => { const { statements, sqlStatements } = await introspectPgToFile( client, schema, - 'introspect-materialized-view-#2', + 'introspect-materialized-view-2', ); expect(statements.length).toBe(0); diff --git a/drizzle-kit/tests/introspect/sqlite.test.ts b/drizzle-kit/tests/introspect/sqlite.test.ts index 18473e87b..e8cfe0e68 100644 --- a/drizzle-kit/tests/introspect/sqlite.test.ts +++ b/drizzle-kit/tests/introspect/sqlite.test.ts @@ -1,6 +1,6 @@ import Database from 'better-sqlite3'; import { SQL, sql } from 'drizzle-orm'; -import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { int, sqliteTable, sqliteView, text } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { introspectSQLiteToFile } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; @@ -55,3 +55,26 @@ test('generated always column virtual: link to another column', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('view #1', async () => { + const sqlite = new Database(':memory:'); + + const users = sqliteTable('users', { id: int('id') }); + const testView = sqliteView('some_view', { id: int('id') }).as( + sql`SELECT * FROM ${users}`, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectSQLiteToFile( + sqlite, + schema, + 'view-1', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/libsql-views.test.ts b/drizzle-kit/tests/libsql-views.test.ts new file mode 100644 index 000000000..54017a3d0 --- /dev/null +++ b/drizzle-kit/tests/libsql-views.test.ts @@ -0,0 +1,212 @@ +import { sql } from 'drizzle-orm'; +import { int, sqliteTable, sqliteView } from 'drizzle-orm/sqlite-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasLibSQL } from './schemaDiffer'; + +test('create view', async () => { + const users = sqliteTable('users', { id: int('id').default(1) }); + const view = sqliteView('view').as((qb) => qb.select().from(users)); + const to = { + users: users, + testView: view, + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_create_table', + tableName: 'users', + columns: [{ + autoincrement: false, + default: 1, + name: 'id', + type: 'integer', + primaryKey: false, + notNull: false, + }], + compositePKs: [], + uniqueConstraints: [], + referenceData: [], + }); + expect(statements[1]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'view', + definition: 'select "id" from "users"', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer DEFAULT 1 +);\n`); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`view\` AS select "id" from "users";`); +}); + +test('drop view', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `DROP VIEW \`view\`;`, + ); +}); + +test('alter view', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users WHERE users.id = 1`), + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + name: 'view', + type: 'sqlite_create_view', + definition: 'SELECT * FROM users WHERE users.id = 1', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `DROP VIEW \`view\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE VIEW \`view\` AS SELECT * FROM users WHERE users.id = 1;`, + ); +}); + +test('create view with existing flag', async () => { + const view = sqliteView('view', {}).existing(); + const to = { + testView: view, + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL({}, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop view with existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view with existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).existing(), + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view and drop existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'new_view', + definition: 'SELECT * FROM users', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users;`); +}); + +test('rename view and alter ".as"', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users WHERE 1=1`), + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'new_view', + definition: 'SELECT * FROM users WHERE 1=1', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe('DROP VIEW `view`;'); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users WHERE 1=1;`); +}); diff --git a/drizzle-kit/tests/mysql-views.test.ts b/drizzle-kit/tests/mysql-views.test.ts new file mode 100644 index 000000000..9a5b5db56 --- /dev/null +++ b/drizzle-kit/tests/mysql-views.test.ts @@ -0,0 +1,553 @@ +import { sql } from 'drizzle-orm'; +import { int, mysqlTable, mysqlView } from 'drizzle-orm/mysql-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasMysql } from './schemaDiffer'; + +test('create view #1', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: mysqlView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'mysql_create_view', + name: 'some_view', + algorithm: 'undefined', + replace: false, + definition: 'select `id` from `users`', + withCheckOption: undefined, + sqlSecurity: 'definer', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE ALGORITHM = undefined +SQL SECURITY definer +VIEW \`some_view\` AS (select \`id\` from \`users\`);`); +}); + +test('create view #2', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'mysql_create_view', + name: 'some_view', + algorithm: 'merge', + replace: false, + definition: 'SELECT * FROM \`users\`', + withCheckOption: 'cascaded', + sqlSecurity: 'definer', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS (SELECT * FROM \`users\`) +WITH cascaded CHECK OPTION;`); +}); + +test('create view with existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: mysqlView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop view', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP VIEW \`some_view\`;`); +}); + +test('drop view with existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` RENAME TO \`new_some_view\`;`); +}); + +test('rename view and alter meta options', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'undefined', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'new_some_view', + sqlSecurity: 'definer', + type: 'alter_mysql_view', + withCheckOption: 'cascaded', + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` RENAME TO \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`ALTER ALGORITHM = undefined +SQL SECURITY definer +VIEW \`new_some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('rename view with existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('add meta to view', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'merge', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_mysql_view', + withCheckOption: 'cascaded', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('add meta to view with existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).existing(), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter meta to view', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'merge', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_mysql_view', + withCheckOption: 'cascaded', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('alter meta to view with existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop meta from view', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'undefined', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_mysql_view', + withCheckOption: undefined, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = undefined +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\`;`); +}); + +test('drop meta from view existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter view ".as" value', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'some_view', + sqlSecurity: 'invoker', + type: 'mysql_create_view', + withCheckOption: 'cascaded', + replace: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE OR REPLACE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); + +test('rename and alter view ".as" value', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + nameFrom: 'some_view', + nameTo: 'new_some_view', + type: 'rename_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'new_some_view', + sqlSecurity: 'invoker', + type: 'mysql_create_view', + withCheckOption: 'cascaded', + replace: true, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` RENAME TO \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`CREATE OR REPLACE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`new_some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); + +test('set existing', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop existing', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'new_some_view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'new_some_view', + sqlSecurity: 'invoker', + type: 'mysql_create_view', + withCheckOption: 'cascaded', + replace: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP VIEW \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`CREATE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`new_some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); diff --git a/drizzle-kit/tests/pg-views.test.ts b/drizzle-kit/tests/pg-views.test.ts index 3179aa373..886df2216 100644 --- a/drizzle-kit/tests/pg-views.test.ts +++ b/drizzle-kit/tests/pg-views.test.ts @@ -1,4 +1,4 @@ -import { eq, sql } from 'drizzle-orm'; +import { sql } from 'drizzle-orm'; import { integer, pgMaterializedView, pgSchema, pgTable, pgView } from 'drizzle-orm/pg-core'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; @@ -639,7 +639,6 @@ test('drop view #1', async () => { type: 'drop_view', name: 'some_view', schema: 'public', - materialized: false, }); expect(sqlStatements.length).toBe(1); @@ -731,7 +730,6 @@ test('rename view #1', async () => { nameFrom: 'some_view', nameTo: 'new_some_view', schema: 'public', - materialized: false, }); expect(sqlStatements.length).toBe(1); expect(sqlStatements[0]).toBe(`ALTER VIEW "public"."some_view" RENAME TO "new_some_view";`); @@ -814,7 +812,6 @@ test('view alter schema', async () => { toSchema: 'new_schema', fromSchema: 'public', name: 'some_view', - materialized: false, }); expect(sqlStatements.length).toBe(2); expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); @@ -1254,14 +1251,14 @@ test('alter with option in view #2', async () => { const from = { users, view: pgView('some_view').with({ checkOption: 'local', securityBarrier: true, securityInvoker: true }).as((qb) => - qb.select().from(users) + qb.selectDistinct().from(users) ), }; const to = { users, view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => - qb.select().from(users) + qb.selectDistinct().from(users) ), }; @@ -1279,6 +1276,7 @@ test('alter with option in view #2', async () => { }); expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( `ALTER VIEW "public"."some_view" SET (check_option = cascaded);`, ); @@ -1353,7 +1351,6 @@ test('alter view ".as" value', async () => { name: 'some_view', schema: 'public', type: 'drop_view', - materialized: false, }, ); expect(statements[1]).toStrictEqual( @@ -1362,12 +1359,12 @@ test('alter view ".as" value', async () => { name: 'some_view', schema: 'public', type: 'create_view', + materialized: false, with: { checkOption: 'local', securityBarrier: true, securityInvoker: true, }, - materialized: false, withNoData: false, tablespace: undefined, using: undefined, @@ -1486,7 +1483,7 @@ test('alter materialized view ".as" value with existing flag', async () => { expect(sqlStatements.length).toBe(0); }); -test('create view with dropped existing flag', async () => { +test('drop existing flag', async () => { const users = pgTable('users', { id: integer('id').primaryKey().notNull(), }); @@ -1852,7 +1849,6 @@ test('rename view and alter view', async () => { nameFrom: 'some_view', nameTo: 'new_some_view', schema: 'public', - materialized: false, }); expect(statements[1]).toStrictEqual({ materialized: false, @@ -1887,16 +1883,15 @@ test('moved schema and alter view', async () => { expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ fromSchema: 'public', - materialized: false, name: 'some_view', toSchema: 'my_schema', type: 'alter_view_alter_schema', }); expect(statements[1]).toStrictEqual({ - materialized: false, name: 'some_view', schema: 'my_schema', type: 'alter_view_add_with_option', + materialized: false, with: { checkOption: 'cascaded', }, diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 89ec008ca..dfbb17dc6 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -11,6 +11,7 @@ import { numeric, real, sqliteTable, + sqliteView, text, uniqueIndex, } from 'drizzle-orm/sqlite-core'; @@ -1047,3 +1048,106 @@ test('drop not null with two indexes', async (t) => { expect(tablesToRemove!.length).toBe(0); expect(tablesToTruncate!.length).toBe(0); }); + +test('create view', async () => { + const turso = createClient({ + url: ':memory:', + }); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + }; + + const schema2 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([ + { + definition: 'select "id" from "test"', + name: 'view', + type: 'sqlite_create_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `CREATE VIEW \`view\` AS select "id" from "test";`, + ]); +}); + +test('drop view', async () => { + const turso = createClient({ + url: ':memory:', + }); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const schema2 = { + test: table, + }; + + const { statements, sqlStatements } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([ + { + name: 'view', + type: 'drop_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'DROP VIEW \`view\`;', + ]); +}); + +test('alter view ".as"', async () => { + const turso = createClient({ + url: ':memory:', + }); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/push/mysql-push.test.ts b/drizzle-kit/tests/push/mysql-push.test.ts new file mode 100644 index 000000000..8ec5a036d --- /dev/null +++ b/drizzle-kit/tests/push/mysql-push.test.ts @@ -0,0 +1,214 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; + +import { int, mysqlTable, mysqlView } from 'drizzle-orm/mysql-core'; +import fs from 'fs'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { diffTestSchemasPushMysql } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, expect, test } from 'vitest'; + +let client: Connection; +let mysqlContainer: Docker.Container; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +beforeAll(async () => { + const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +test('create view', async () => { + const table = mysqlTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + }; + + const schema2 = { + test: table, + view: mysqlView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + definition: 'select \`id\` from \`test\`', + name: 'view', + type: 'mysql_create_view', + replace: false, + sqlSecurity: 'definer', + withCheckOption: undefined, + algorithm: 'undefined', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `CREATE ALGORITHM = undefined +SQL SECURITY definer +VIEW \`view\` AS (select \`id\` from \`test\`);`, + ]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('drop view', async () => { + const table = mysqlTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: mysqlView('view').as((qb) => qb.select().from(table)), + }; + + const schema2 = { + test: table, + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + name: 'view', + type: 'drop_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'DROP VIEW \`view\`;', + ]); + await client.query(`DROP TABLE \`test\`;`); + await client.query(`DROP VIEW \`view\`;`); +}); + +test('alter view ".as"', async () => { + const table = mysqlTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: mysqlView('view').as((qb) => qb.select().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: mysqlView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`DROP TABLE \`test\`;`); + await client.query(`DROP VIEW \`view\`;`); +}); + +test('alter meta options with distinct in definition', async () => { + const table = mysqlTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: mysqlView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('merge').as(( + qb, + ) => qb.selectDistinct().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: mysqlView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('undefined').as((qb) => + qb.selectDistinct().from(table) + ), + }; + + await expect(diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + )).rejects.toThrowError(); + + await client.query(`DROP TABLE \`test\`;`); +}); diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 951420c74..38227d463 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -1118,1126 +1118,1126 @@ const pgSuite: DialectSuite = { }, }; -// run(pgSuite); - -// test('full sequence: no changes', async () => { -// const client = new PGlite(); - -// const schema1 = { -// seq: pgSequence('my_seq', { -// startWith: 100, -// maxValue: 10000, -// minValue: 100, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// }; - -// const schema2 = { -// seq: pgSequence('my_seq', { -// startWith: 100, -// maxValue: 10000, -// minValue: 100, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements.length).toBe(0); -// expect(sqlStatements.length).toBe(0); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('basic sequence: change fields', async () => { -// const client = new PGlite(); - -// const schema1 = { -// seq: pgSequence('my_seq', { -// startWith: 100, -// maxValue: 10000, -// minValue: 100, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// }; - -// const schema2 = { -// seq: pgSequence('my_seq', { -// startWith: 100, -// maxValue: 100000, -// minValue: 100, -// cycle: true, -// cache: 10, -// increment: 4, -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// type: 'alter_sequence', -// schema: 'public', -// name: 'my_seq', -// values: { -// minValue: '100', -// maxValue: '100000', -// increment: '4', -// startWith: '100', -// cache: '10', -// cycle: true, -// }, -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'ALTER SEQUENCE "public"."my_seq" INCREMENT BY 4 MINVALUE 100 MAXVALUE 100000 START WITH 100 CACHE 10 CYCLE;', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('basic sequence: change name', async () => { -// const client = new PGlite(); - -// const schema1 = { -// seq: pgSequence('my_seq', { -// startWith: 100, -// maxValue: 10000, -// minValue: 100, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// }; - -// const schema2 = { -// seq: pgSequence('my_seq2', { -// startWith: 100, -// maxValue: 10000, -// minValue: 100, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// ['public.my_seq->public.my_seq2'], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// nameFrom: 'my_seq', -// nameTo: 'my_seq2', -// schema: 'public', -// type: 'rename_sequence', -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('basic sequence: change name and fields', async () => { -// const client = new PGlite(); - -// const schema1 = { -// seq: pgSequence('my_seq', { -// startWith: 100, -// maxValue: 10000, -// minValue: 100, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// }; - -// const schema2 = { -// seq: pgSequence('my_seq2', { -// startWith: 100, -// maxValue: 10000, -// minValue: 100, -// cycle: true, -// cache: 10, -// increment: 4, -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// ['public.my_seq->public.my_seq2'], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// nameFrom: 'my_seq', -// nameTo: 'my_seq2', -// schema: 'public', -// type: 'rename_sequence', -// }, -// { -// name: 'my_seq2', -// schema: 'public', -// type: 'alter_sequence', -// values: { -// cache: '10', -// cycle: true, -// increment: '4', -// maxValue: '10000', -// minValue: '100', -// startWith: '100', -// }, -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";', -// 'ALTER SEQUENCE "public"."my_seq2" INCREMENT BY 4 MINVALUE 100 MAXVALUE 10000 START WITH 100 CACHE 10 CYCLE;', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// // identity push tests -// test('create table: identity always/by default - no params', async () => { -// const client = new PGlite(); - -// const schema1 = {}; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity(), -// id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity(), -// id2: smallint('id2').generatedByDefaultAsIdentity(), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// columns: [ -// { -// identity: 'users_id_seq;byDefault;1;2147483647;1;1;1;false', -// name: 'id', -// notNull: true, -// primaryKey: false, -// type: 'integer', -// }, -// { -// identity: 'users_id1_seq;byDefault;1;9223372036854775807;1;1;1;false', -// name: 'id1', -// notNull: true, -// primaryKey: false, -// type: 'bigint', -// }, -// { -// identity: 'users_id2_seq;byDefault;1;32767;1;1;1;false', -// name: 'id2', -// notNull: true, -// primaryKey: false, -// type: 'smallint', -// }, -// ], -// compositePKs: [], -// compositePkName: '', -// schema: '', -// tableName: 'users', -// type: 'create_table', -// uniqueConstraints: [], -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1)\n);\n', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('create table: identity always/by default - few params', async () => { -// const client = new PGlite(); - -// const schema1 = {}; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ increment: 4 }), -// id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity({ -// startWith: 120, -// maxValue: 17000, -// }), -// id2: smallint('id2').generatedByDefaultAsIdentity({ cycle: true }), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// columns: [ -// { -// identity: 'users_id_seq;byDefault;1;2147483647;4;1;1;false', -// name: 'id', -// notNull: true, -// primaryKey: false, -// type: 'integer', -// }, -// { -// identity: 'users_id1_seq;byDefault;1;17000;1;120;1;false', -// name: 'id1', -// notNull: true, -// primaryKey: false, -// type: 'bigint', -// }, -// { -// identity: 'users_id2_seq;byDefault;1;32767;1;1;1;true', -// name: 'id2', -// notNull: true, -// primaryKey: false, -// type: 'smallint', -// }, -// ], -// compositePKs: [], -// compositePkName: '', -// schema: '', -// tableName: 'users', -// type: 'create_table', -// uniqueConstraints: [], -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('create table: identity always/by default - all params', async () => { -// const client = new PGlite(); - -// const schema1 = {}; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ -// increment: 4, -// minValue: 100, -// }), -// id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity({ -// startWith: 120, -// maxValue: 17000, -// increment: 3, -// cycle: true, -// cache: 100, -// }), -// id2: smallint('id2').generatedByDefaultAsIdentity({ cycle: true }), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// columns: [ -// { -// identity: 'users_id_seq;byDefault;100;2147483647;4;100;1;false', -// name: 'id', -// notNull: true, -// primaryKey: false, -// type: 'integer', -// }, -// { -// identity: 'users_id1_seq;byDefault;1;17000;3;120;100;true', -// name: 'id1', -// notNull: true, -// primaryKey: false, -// type: 'bigint', -// }, -// { -// identity: 'users_id2_seq;byDefault;1;32767;1;1;1;true', -// name: 'id2', -// notNull: true, -// primaryKey: false, -// type: 'smallint', -// }, -// ], -// compositePKs: [], -// compositePkName: '', -// schema: '', -// tableName: 'users', -// type: 'create_table', -// uniqueConstraints: [], -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 100 MAXVALUE 2147483647 START WITH 100 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 3 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 100 CYCLE),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('no diff: identity always/by default - no params', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity(), -// id2: integer('id2').generatedAlwaysAsIdentity(), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity(), -// id2: integer('id2').generatedAlwaysAsIdentity(), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([]); -// expect(sqlStatements).toStrictEqual([]); -// }); - -// test('no diff: identity always/by default - few params', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ -// name: 'custom_name', -// }), -// id2: integer('id2').generatedAlwaysAsIdentity({ -// increment: 1, -// startWith: 3, -// }), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ -// name: 'custom_name', -// }), -// id2: integer('id2').generatedAlwaysAsIdentity({ -// increment: 1, -// startWith: 3, -// }), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([]); -// expect(sqlStatements).toStrictEqual([]); -// }); - -// test('no diff: identity always/by default - all params', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ -// name: 'custom_name', -// startWith: 10, -// minValue: 10, -// maxValue: 1000, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// id2: integer('id2').generatedAlwaysAsIdentity({ -// startWith: 10, -// minValue: 10, -// maxValue: 1000, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ -// name: 'custom_name', -// startWith: 10, -// minValue: 10, -// maxValue: 1000, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// id2: integer('id2').generatedAlwaysAsIdentity({ -// startWith: 10, -// minValue: 10, -// maxValue: 1000, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([]); -// expect(sqlStatements).toStrictEqual([]); -// }); - -// test('drop identity from a column - no params', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity(), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id'), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// columnName: 'id', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_drop_identity', -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('drop identity from a column - few params', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), -// id1: integer('id1').generatedByDefaultAsIdentity({ -// name: 'custom_name1', -// increment: 4, -// }), -// id2: integer('id2').generatedAlwaysAsIdentity({ -// name: 'custom_name2', -// increment: 4, -// }), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id'), -// id1: integer('id1'), -// id2: integer('id2'), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// columnName: 'id', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_drop_identity', -// }, -// { -// columnName: 'id1', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_drop_identity', -// }, -// { -// columnName: 'id2', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_drop_identity', -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, -// 'ALTER TABLE "users" ALTER COLUMN "id1" DROP IDENTITY;', -// 'ALTER TABLE "users" ALTER COLUMN "id2" DROP IDENTITY;', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('drop identity from a column - all params', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity(), -// id1: integer('id1').generatedByDefaultAsIdentity({ -// name: 'custom_name1', -// startWith: 10, -// minValue: 10, -// maxValue: 1000, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// id2: integer('id2').generatedAlwaysAsIdentity({ -// name: 'custom_name2', -// startWith: 10, -// minValue: 10, -// maxValue: 1000, -// cycle: true, -// cache: 10, -// increment: 2, -// }), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id'), -// id1: integer('id1'), -// id2: integer('id2'), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// columnName: 'id', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_drop_identity', -// }, -// { -// columnName: 'id1', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_drop_identity', -// }, -// { -// columnName: 'id2', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_drop_identity', -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, -// 'ALTER TABLE "users" ALTER COLUMN "id1" DROP IDENTITY;', -// 'ALTER TABLE "users" ALTER COLUMN "id2" DROP IDENTITY;', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('alter identity from a column - no params', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity(), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// columnName: 'id', -// identity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', -// oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;1;1;false', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_change_identity', -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'ALTER TABLE "users" ALTER COLUMN "id" SET START WITH 100;', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('alter identity from a column - few params', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ -// startWith: 100, -// increment: 4, -// maxValue: 10000, -// }), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// columnName: 'id', -// identity: 'users_id_seq;byDefault;1;10000;4;100;1;false', -// oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_change_identity', -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', -// 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('alter identity from a column - by default to always', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id').generatedAlwaysAsIdentity({ -// startWith: 100, -// increment: 4, -// maxValue: 10000, -// }), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// columnName: 'id', -// identity: 'users_id_seq;always;1;10000;4;100;1;false', -// oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_change_identity', -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'ALTER TABLE "users" ALTER COLUMN "id" SET GENERATED ALWAYS;', -// 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', -// 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('alter identity from a column - always to by default', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// id: integer('id').generatedAlwaysAsIdentity({ startWith: 100 }), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ -// startWith: 100, -// increment: 4, -// maxValue: 10000, -// cycle: true, -// cache: 100, -// }), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// columnName: 'id', -// identity: 'users_id_seq;byDefault;1;10000;4;100;100;true', -// oldIdentity: 'users_id_seq;always;1;2147483647;1;100;1;false', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_change_identity', -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'ALTER TABLE "users" ALTER COLUMN "id" SET GENERATED BY DEFAULT;', -// 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', -// 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', -// 'ALTER TABLE "users" ALTER COLUMN "id" SET CACHE 100;', -// 'ALTER TABLE "users" ALTER COLUMN "id" SET CYCLE;', -// ]); - -// for (const st of sqlStatements) { -// await client.query(st); -// } -// }); - -// test('add column with identity - few params', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// email: text('email'), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// email: text('email'), -// id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), -// id1: integer('id1').generatedAlwaysAsIdentity({ -// name: 'custom_name1', -// increment: 4, -// }), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// column: { -// identity: 'custom_name;byDefault;1;2147483647;1;1;1;false', -// name: 'id', -// notNull: true, -// primaryKey: false, -// type: 'integer', -// }, -// schema: '', -// tableName: 'users', -// type: 'alter_table_add_column', -// }, -// { -// column: { -// identity: 'custom_name1;always;1;2147483647;4;1;1;false', -// name: 'id1', -// notNull: true, -// primaryKey: false, -// type: 'integer', -// }, -// schema: '', -// tableName: 'users', -// type: 'alter_table_add_column', -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'ALTER TABLE "users" ADD COLUMN "id" integer NOT NULL GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_name" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', -// 'ALTER TABLE "users" ADD COLUMN "id1" integer NOT NULL GENERATED ALWAYS AS IDENTITY (sequence name "custom_name1" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', -// ]); - -// // for (const st of sqlStatements) { -// // await client.query(st); -// // } -// }); - -// test('add identity to column - few params', async () => { -// const client = new PGlite(); - -// const schema1 = { -// users: pgTable('users', { -// id: integer('id'), -// id1: integer('id1'), -// }), -// }; - -// const schema2 = { -// users: pgTable('users', { -// id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), -// id1: integer('id1').generatedAlwaysAsIdentity({ -// name: 'custom_name1', -// increment: 4, -// }), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// columnName: 'id', -// identity: 'custom_name;byDefault;1;2147483647;1;1;1;false', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_set_identity', -// }, -// { -// columnName: 'id1', -// identity: 'custom_name1;always;1;2147483647;4;1;1;false', -// schema: '', -// tableName: 'users', -// type: 'alter_table_alter_column_set_identity', -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'ALTER TABLE "users" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_name" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', -// 'ALTER TABLE "users" ALTER COLUMN "id1" ADD GENERATED ALWAYS AS IDENTITY (sequence name "custom_name1" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', -// ]); - -// // for (const st of sqlStatements) { -// // await client.query(st); -// // } -// }); - -// test('add array column - empty array default', async () => { -// const client = new PGlite(); - -// const schema1 = { -// test: pgTable('test', { -// id: serial('id').primaryKey(), -// }), -// }; -// const schema2 = { -// test: pgTable('test', { -// id: serial('id').primaryKey(), -// values: integer('values').array().default([]), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// type: 'alter_table_add_column', -// tableName: 'test', -// schema: '', -// column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'" }, -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{}\';', -// ]); -// }); - -// test('add array column - default', async () => { -// const client = new PGlite(); - -// const schema1 = { -// test: pgTable('test', { -// id: serial('id').primaryKey(), -// }), -// }; -// const schema2 = { -// test: pgTable('test', { -// id: serial('id').primaryKey(), -// values: integer('values').array().default([1, 2, 3]), -// }), -// }; - -// const { statements, sqlStatements } = await diffTestSchemasPush( -// client, -// schema1, -// schema2, -// [], -// false, -// ['public'], -// ); - -// expect(statements).toStrictEqual([ -// { -// type: 'alter_table_add_column', -// tableName: 'test', -// schema: '', -// column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'" }, -// }, -// ]); -// expect(sqlStatements).toStrictEqual([ -// 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\';', -// ]); -// }); +run(pgSuite); + +test('full sequence: no changes', async () => { + const client = new PGlite(); + + const schema1 = { + seq: pgSequence('my_seq', { + startWith: 100, + maxValue: 10000, + minValue: 100, + cycle: true, + cache: 10, + increment: 2, + }), + }; + + const schema2 = { + seq: pgSequence('my_seq', { + startWith: 100, + maxValue: 10000, + minValue: 100, + cycle: true, + cache: 10, + increment: 2, + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('basic sequence: change fields', async () => { + const client = new PGlite(); + + const schema1 = { + seq: pgSequence('my_seq', { + startWith: 100, + maxValue: 10000, + minValue: 100, + cycle: true, + cache: 10, + increment: 2, + }), + }; + + const schema2 = { + seq: pgSequence('my_seq', { + startWith: 100, + maxValue: 100000, + minValue: 100, + cycle: true, + cache: 10, + increment: 4, + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'alter_sequence', + schema: 'public', + name: 'my_seq', + values: { + minValue: '100', + maxValue: '100000', + increment: '4', + startWith: '100', + cache: '10', + cycle: true, + }, + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER SEQUENCE "public"."my_seq" INCREMENT BY 4 MINVALUE 100 MAXVALUE 100000 START WITH 100 CACHE 10 CYCLE;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('basic sequence: change name', async () => { + const client = new PGlite(); + + const schema1 = { + seq: pgSequence('my_seq', { + startWith: 100, + maxValue: 10000, + minValue: 100, + cycle: true, + cache: 10, + increment: 2, + }), + }; + + const schema2 = { + seq: pgSequence('my_seq2', { + startWith: 100, + maxValue: 10000, + minValue: 100, + cycle: true, + cache: 10, + increment: 2, + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + ['public.my_seq->public.my_seq2'], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + nameFrom: 'my_seq', + nameTo: 'my_seq2', + schema: 'public', + type: 'rename_sequence', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('basic sequence: change name and fields', async () => { + const client = new PGlite(); + + const schema1 = { + seq: pgSequence('my_seq', { + startWith: 100, + maxValue: 10000, + minValue: 100, + cycle: true, + cache: 10, + increment: 2, + }), + }; + + const schema2 = { + seq: pgSequence('my_seq2', { + startWith: 100, + maxValue: 10000, + minValue: 100, + cycle: true, + cache: 10, + increment: 4, + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + ['public.my_seq->public.my_seq2'], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + nameFrom: 'my_seq', + nameTo: 'my_seq2', + schema: 'public', + type: 'rename_sequence', + }, + { + name: 'my_seq2', + schema: 'public', + type: 'alter_sequence', + values: { + cache: '10', + cycle: true, + increment: '4', + maxValue: '10000', + minValue: '100', + startWith: '100', + }, + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";', + 'ALTER SEQUENCE "public"."my_seq2" INCREMENT BY 4 MINVALUE 100 MAXVALUE 10000 START WITH 100 CACHE 10 CYCLE;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +// identity push tests +test('create table: identity always/by default - no params', async () => { + const client = new PGlite(); + + const schema1 = {}; + + const schema2 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity(), + id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity(), + id2: smallint('id2').generatedByDefaultAsIdentity(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + columns: [ + { + identity: 'users_id_seq;byDefault;1;2147483647;1;1;1;false', + name: 'id', + notNull: true, + primaryKey: false, + type: 'integer', + }, + { + identity: 'users_id1_seq;byDefault;1;9223372036854775807;1;1;1;false', + name: 'id1', + notNull: true, + primaryKey: false, + type: 'bigint', + }, + { + identity: 'users_id2_seq;byDefault;1;32767;1;1;1;false', + name: 'id2', + notNull: true, + primaryKey: false, + type: 'smallint', + }, + ], + compositePKs: [], + compositePkName: '', + schema: '', + tableName: 'users', + type: 'create_table', + uniqueConstraints: [], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1)\n);\n', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('create table: identity always/by default - few params', async () => { + const client = new PGlite(); + + const schema1 = {}; + + const schema2 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ increment: 4 }), + id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity({ + startWith: 120, + maxValue: 17000, + }), + id2: smallint('id2').generatedByDefaultAsIdentity({ cycle: true }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + columns: [ + { + identity: 'users_id_seq;byDefault;1;2147483647;4;1;1;false', + name: 'id', + notNull: true, + primaryKey: false, + type: 'integer', + }, + { + identity: 'users_id1_seq;byDefault;1;17000;1;120;1;false', + name: 'id1', + notNull: true, + primaryKey: false, + type: 'bigint', + }, + { + identity: 'users_id2_seq;byDefault;1;32767;1;1;1;true', + name: 'id2', + notNull: true, + primaryKey: false, + type: 'smallint', + }, + ], + compositePKs: [], + compositePkName: '', + schema: '', + tableName: 'users', + type: 'create_table', + uniqueConstraints: [], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('create table: identity always/by default - all params', async () => { + const client = new PGlite(); + + const schema1 = {}; + + const schema2 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ + increment: 4, + minValue: 100, + }), + id1: bigint('id1', { mode: 'number' }).generatedByDefaultAsIdentity({ + startWith: 120, + maxValue: 17000, + increment: 3, + cycle: true, + cache: 100, + }), + id2: smallint('id2').generatedByDefaultAsIdentity({ cycle: true }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + columns: [ + { + identity: 'users_id_seq;byDefault;100;2147483647;4;100;1;false', + name: 'id', + notNull: true, + primaryKey: false, + type: 'integer', + }, + { + identity: 'users_id1_seq;byDefault;1;17000;3;120;100;true', + name: 'id1', + notNull: true, + primaryKey: false, + type: 'bigint', + }, + { + identity: 'users_id2_seq;byDefault;1;32767;1;1;1;true', + name: 'id2', + notNull: true, + primaryKey: false, + type: 'smallint', + }, + ], + compositePKs: [], + compositePkName: '', + schema: '', + tableName: 'users', + type: 'create_table', + uniqueConstraints: [], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 100 MAXVALUE 2147483647 START WITH 100 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 3 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 100 CYCLE),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('no diff: identity always/by default - no params', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity(), + id2: integer('id2').generatedAlwaysAsIdentity(), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity(), + id2: integer('id2').generatedAlwaysAsIdentity(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); +}); + +test('no diff: identity always/by default - few params', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ + name: 'custom_name', + }), + id2: integer('id2').generatedAlwaysAsIdentity({ + increment: 1, + startWith: 3, + }), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ + name: 'custom_name', + }), + id2: integer('id2').generatedAlwaysAsIdentity({ + increment: 1, + startWith: 3, + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); +}); + +test('no diff: identity always/by default - all params', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ + name: 'custom_name', + startWith: 10, + minValue: 10, + maxValue: 1000, + cycle: true, + cache: 10, + increment: 2, + }), + id2: integer('id2').generatedAlwaysAsIdentity({ + startWith: 10, + minValue: 10, + maxValue: 1000, + cycle: true, + cache: 10, + increment: 2, + }), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ + name: 'custom_name', + startWith: 10, + minValue: 10, + maxValue: 1000, + cycle: true, + cache: 10, + increment: 2, + }), + id2: integer('id2').generatedAlwaysAsIdentity({ + startWith: 10, + minValue: 10, + maxValue: 1000, + cycle: true, + cache: 10, + increment: 2, + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); +}); + +test('drop identity from a column - no params', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity(), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + columnName: 'id', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_identity', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('drop identity from a column - few params', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), + id1: integer('id1').generatedByDefaultAsIdentity({ + name: 'custom_name1', + increment: 4, + }), + id2: integer('id2').generatedAlwaysAsIdentity({ + name: 'custom_name2', + increment: 4, + }), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id'), + id1: integer('id1'), + id2: integer('id2'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + columnName: 'id', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_identity', + }, + { + columnName: 'id1', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_identity', + }, + { + columnName: 'id2', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_identity', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, + 'ALTER TABLE "users" ALTER COLUMN "id1" DROP IDENTITY;', + 'ALTER TABLE "users" ALTER COLUMN "id2" DROP IDENTITY;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('drop identity from a column - all params', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity(), + id1: integer('id1').generatedByDefaultAsIdentity({ + name: 'custom_name1', + startWith: 10, + minValue: 10, + maxValue: 1000, + cycle: true, + cache: 10, + increment: 2, + }), + id2: integer('id2').generatedAlwaysAsIdentity({ + name: 'custom_name2', + startWith: 10, + minValue: 10, + maxValue: 1000, + cycle: true, + cache: 10, + increment: 2, + }), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id'), + id1: integer('id1'), + id2: integer('id2'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + columnName: 'id', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_identity', + }, + { + columnName: 'id1', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_identity', + }, + { + columnName: 'id2', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_identity', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, + 'ALTER TABLE "users" ALTER COLUMN "id1" DROP IDENTITY;', + 'ALTER TABLE "users" ALTER COLUMN "id2" DROP IDENTITY;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter identity from a column - no params', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity(), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + columnName: 'id', + identity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', + oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;1;1;false', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_change_identity', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ALTER COLUMN "id" SET START WITH 100;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter identity from a column - few params', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ + startWith: 100, + increment: 4, + maxValue: 10000, + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + columnName: 'id', + identity: 'users_id_seq;byDefault;1;10000;4;100;1;false', + oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_change_identity', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', + 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter identity from a column - by default to always', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ startWith: 100 }), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').generatedAlwaysAsIdentity({ + startWith: 100, + increment: 4, + maxValue: 10000, + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + columnName: 'id', + identity: 'users_id_seq;always;1;10000;4;100;1;false', + oldIdentity: 'users_id_seq;byDefault;1;2147483647;1;100;1;false', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_change_identity', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ALTER COLUMN "id" SET GENERATED ALWAYS;', + 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', + 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter identity from a column - always to by default', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').generatedAlwaysAsIdentity({ startWith: 100 }), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ + startWith: 100, + increment: 4, + maxValue: 10000, + cycle: true, + cache: 100, + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + columnName: 'id', + identity: 'users_id_seq;byDefault;1;10000;4;100;100;true', + oldIdentity: 'users_id_seq;always;1;2147483647;1;100;1;false', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_change_identity', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ALTER COLUMN "id" SET GENERATED BY DEFAULT;', + 'ALTER TABLE "users" ALTER COLUMN "id" SET MAXVALUE 10000;', + 'ALTER TABLE "users" ALTER COLUMN "id" SET INCREMENT BY 4;', + 'ALTER TABLE "users" ALTER COLUMN "id" SET CACHE 100;', + 'ALTER TABLE "users" ALTER COLUMN "id" SET CYCLE;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('add column with identity - few params', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + email: text('email'), + }), + }; + + const schema2 = { + users: pgTable('users', { + email: text('email'), + id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), + id1: integer('id1').generatedAlwaysAsIdentity({ + name: 'custom_name1', + increment: 4, + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + column: { + identity: 'custom_name;byDefault;1;2147483647;1;1;1;false', + name: 'id', + notNull: true, + primaryKey: false, + type: 'integer', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + { + column: { + identity: 'custom_name1;always;1;2147483647;4;1;1;false', + name: 'id1', + notNull: true, + primaryKey: false, + type: 'integer', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ADD COLUMN "id" integer NOT NULL GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_name" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', + 'ALTER TABLE "users" ADD COLUMN "id1" integer NOT NULL GENERATED ALWAYS AS IDENTITY (sequence name "custom_name1" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', + ]); + + // for (const st of sqlStatements) { + // await client.query(st); + // } +}); + +test('add identity to column - few params', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id'), + id1: integer('id1'), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').generatedByDefaultAsIdentity({ name: 'custom_name' }), + id1: integer('id1').generatedAlwaysAsIdentity({ + name: 'custom_name1', + increment: 4, + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + columnName: 'id', + identity: 'custom_name;byDefault;1;2147483647;1;1;1;false', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_identity', + }, + { + columnName: 'id1', + identity: 'custom_name1;always;1;2147483647;4;1;1;false', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_identity', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_name" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', + 'ALTER TABLE "users" ALTER COLUMN "id1" ADD GENERATED ALWAYS AS IDENTITY (sequence name "custom_name1" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1);', + ]); + + // for (const st of sqlStatements) { + // await client.query(st); + // } +}); + +test('add array column - empty array default', async () => { + const client = new PGlite(); + + const schema1 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const schema2 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().default([]), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'" }, + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{}\';', + ]); +}); + +test('add array column - default', async () => { + const client = new PGlite(); + + const schema1 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const schema2 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().default([1, 2, 3]), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'" }, + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\';', + ]); +}); test('create view', async () => { const client = new PGlite(); @@ -2352,7 +2352,6 @@ test('drop view', async () => { name: 'view', schema: 'public', type: 'drop_view', - materialized: false, }, ]); expect(sqlStatements).toStrictEqual([ @@ -2543,7 +2542,7 @@ test('add with options to materialized', async () => { ); }); -test('add with options to materialized with existing option', async () => { +test('add with options to materialized with existing flag', async () => { const client = new PGlite(); const table = pgTable('test', { diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index aea5cd379..e080e07ce 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -1,5 +1,6 @@ import Database from 'better-sqlite3'; import chalk from 'chalk'; +import { sql } from 'drizzle-orm'; import { blob, foreignKey, @@ -9,10 +10,11 @@ import { numeric, real, sqliteTable, + sqliteView, text, uniqueIndex, } from 'drizzle-orm/sqlite-core'; -import { diffTestSchemasPushSqlite } from 'tests/schemaDiffer'; +import { diffTestSchemasPushSqlite, introspectSQLiteToFile } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; test('nothing changed in schema', async (t) => { @@ -1288,3 +1290,100 @@ test('recreate table with added column not null and without default with data', expect(tablesToRemove!.length).toBe(0); expect(tablesToTruncate!.length).toBe(0); }); + +test('create view', async () => { + const client = new Database(':memory:'); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + }; + + const schema2 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([ + { + definition: 'select "id" from "test"', + name: 'view', + type: 'sqlite_create_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `CREATE VIEW \`view\` AS select "id" from "test";`, + ]); +}); + +test('drop view', async () => { + const client = new Database(':memory:'); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const schema2 = { + test: table, + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([ + { + name: 'view', + type: 'drop_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'DROP VIEW \`view\`;', + ]); +}); + +test('alter view ".as"', async () => { + const client = new Database(':memory:'); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index b7fff13a8..d1ccd99fa 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -1,9 +1,8 @@ import { PGlite } from '@electric-sql/pglite'; import { Client } from '@libsql/client/.'; import { Database } from 'better-sqlite3'; -import { randomUUID } from 'crypto'; import { is } from 'drizzle-orm'; -import { MySqlSchema, MySqlTable } from 'drizzle-orm/mysql-core'; +import { MySqlSchema, MySqlTable, MySqlView } from 'drizzle-orm/mysql-core'; import { isPgEnum, isPgMaterializedView, @@ -16,16 +15,18 @@ import { PgTable, PgView, } from 'drizzle-orm/pg-core'; -import { SQLiteTable } from 'drizzle-orm/sqlite-core'; +import { SQLiteTable, SQLiteView } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; import { libSqlLogSuggestionsAndReturn } from 'src/cli/commands/libSqlPushUtils'; import { columnsResolver, enumsResolver, + mySqlViewsResolver, Named, schemasResolver, sequencesResolver, + sqliteViewsResolver, tablesResolver, viewsResolver, } from 'src/cli/commands/migrate'; @@ -34,14 +35,14 @@ import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-my import { schemaToTypeScript } from 'src/introspect-pg'; import { schemaToTypeScript as schemaToTypeScriptSQLite } from 'src/introspect-sqlite'; import { prepareFromMySqlImports } from 'src/serializer/mysqlImports'; -import { mysqlSchema, squashMysqlScheme } from 'src/serializer/mysqlSchema'; +import { mysqlSchema, squashMysqlScheme, ViewSquashed } from 'src/serializer/mysqlSchema'; import { generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; import { fromDatabase as fromMySqlDatabase } from 'src/serializer/mysqlSerializer'; import { prepareFromPgImports } from 'src/serializer/pgImports'; import { pgSchema, squashPgScheme, View } from 'src/serializer/pgSchema'; import { fromDatabase, generatePgSnapshot } from 'src/serializer/pgSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; -import { sqliteSchema, squashSqliteScheme } from 'src/serializer/sqliteSchema'; +import { sqliteSchema, squashSqliteScheme, View as SqliteView } from 'src/serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase } from 'src/serializer/sqliteSerializer'; import { generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; import { @@ -64,8 +65,8 @@ export type PostgresSchema = Record< string, PgTable | PgEnum | PgSchema | PgSequence | PgView | PgMaterializedView >; -export type MysqlSchema = Record | MySqlSchema>; -export type SqliteSchema = Record>; +export type MysqlSchema = Record | MySqlSchema | MySqlView>; +export type SqliteSchema = Record | SQLiteView>; export const testSchemasResolver = (renames: Set) => async (input: ResolverInput): Promise> => { @@ -494,6 +495,150 @@ async ( } }; +export const testViewsResolverMySql = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } + + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; + + const result: { + created: ViewSquashed[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: ViewSquashed; to: ViewSquashed }[]; + deleted: ViewSquashed[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; + }); + + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, + }); + } + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } + } + + result.created = createdViews; + result.deleted = deletedViews; + + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const testViewsResolverSqlite = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } + + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; + + const result: { + created: SqliteView[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: SqliteView; to: SqliteView }[]; + deleted: SqliteView[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedViews.findIndex((it) => { + return it.name === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return it.name === to; + }); + + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } + } + + result.created = createdViews; + result.deleted = deletedViews; + + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + export const diffTestSchemasPush = async ( client: PGlite, left: PostgresSchema, @@ -792,7 +937,9 @@ export const diffTestSchemasPushMysql = async ( const leftTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - const serialized2 = generateMySqlSnapshot(leftTables); + const leftViews = Object.values(right).filter((it) => is(it, MySqlView)) as MySqlView[]; + + const serialized2 = generateMySqlSnapshot(leftTables, leftViews); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -827,6 +974,7 @@ export const diffTestSchemasPushMysql = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverMySql(renames), validatedPrev, validatedCur, 'push', @@ -838,6 +986,7 @@ export const diffTestSchemasPushMysql = async ( sn2, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, 'push', @@ -852,6 +1001,7 @@ export const applyMySqlDiffs = async (sn: MysqlSchema) => { dialect: 'mysql', id: '0', prevId: '0', + views: {}, tables: {}, enums: {}, schemas: {}, @@ -864,7 +1014,9 @@ export const applyMySqlDiffs = async (sn: MysqlSchema) => { const tables = Object.values(sn).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - const serialized1 = generateMySqlSnapshot(tables); + const views = Object.values(sn).filter((it) => is(it, MySqlView)) as MySqlView[]; + + const serialized1 = generateMySqlSnapshot(tables, views); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -886,6 +1038,7 @@ export const applyMySqlDiffs = async (sn: MysqlSchema) => { sn1, testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolverMySql(new Set()), validatedPrev, validatedCur, ); @@ -900,10 +1053,14 @@ export const diffTestSchemasMysql = async ( ) => { const leftTables = Object.values(left).filter((it) => is(it, MySqlTable)) as MySqlTable[]; + const leftViews = Object.values(left).filter((it) => is(it, MySqlView)) as MySqlView[]; + const rightTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - const serialized1 = generateMySqlSnapshot(leftTables); - const serialized2 = generateMySqlSnapshot(rightTables); + const rightViews = Object.values(right).filter((it) => is(it, MySqlView)) as MySqlView[]; + + const serialized1 = generateMySqlSnapshot(leftTables, leftViews); + const serialized2 = generateMySqlSnapshot(rightTables, rightViews); const { version: v1, dialect: d1, ...rest1 } = serialized1; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -938,6 +1095,7 @@ export const diffTestSchemasMysql = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverMySql(renames), validatedPrev, validatedCur, ); @@ -949,6 +1107,7 @@ export const diffTestSchemasMysql = async ( sn2, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, ); @@ -988,7 +1147,9 @@ export const diffTestSchemasPushSqlite = async ( const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized2 = generateSqliteSnapshot(rightTables); + const rightViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized2 = generateSqliteSnapshot(rightTables, rightViews); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1020,6 +1181,7 @@ export const diffTestSchemasPushSqlite = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverSqlite(renames), sch1, sch2, 'push', @@ -1064,6 +1226,7 @@ export const diffTestSchemasPushSqlite = async ( sn2, tablesResolver, columnsResolver, + sqliteViewsResolver, sch1, sch2, 'push', @@ -1105,7 +1268,9 @@ export async function diffTestSchemasPushLibSQL( const leftTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized2 = generateSqliteSnapshot(leftTables); + const leftViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized2 = generateSqliteSnapshot(leftTables, leftViews); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1137,6 +1302,7 @@ export async function diffTestSchemasPushLibSQL( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverSqlite(renames), sch1, sch2, 'push', @@ -1180,6 +1346,7 @@ export async function diffTestSchemasPushLibSQL( sn2, tablesResolver, columnsResolver, + sqliteViewsResolver, sch1, sch2, 'push', @@ -1199,6 +1366,7 @@ export const applySqliteDiffs = async ( prevId: '0', tables: {}, enums: {}, + views: {}, schemas: {}, _meta: { schemas: {}, @@ -1209,7 +1377,9 @@ export const applySqliteDiffs = async ( const tables = Object.values(sn).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(tables); + const views = Object.values(sn).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized1 = generateSqliteSnapshot(tables, views); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -1228,6 +1398,7 @@ export const applySqliteDiffs = async ( sn1, testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolverSqlite(new Set()), dryRun, sch1, action, @@ -1246,6 +1417,7 @@ export const applyLibSQLDiffs = async ( id: '0', prevId: '0', tables: {}, + views: {}, enums: {}, schemas: {}, _meta: { @@ -1257,7 +1429,9 @@ export const applyLibSQLDiffs = async ( const tables = Object.values(sn).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(tables); + const views = Object.values(sn).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized1 = generateSqliteSnapshot(tables, views); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -1276,6 +1450,7 @@ export const applyLibSQLDiffs = async ( sn1, testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolverSqlite(new Set()), dryRun, sch1, action, @@ -1292,10 +1467,14 @@ export const diffTestSchemasSqlite = async ( ) => { const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + const leftViews = Object.values(left).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(leftTables); - const serialized2 = generateSqliteSnapshot(rightTables); + const rightViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized1 = generateSqliteSnapshot(leftTables, leftViews); + const serialized2 = generateSqliteSnapshot(rightTables, rightViews); const { version: v1, dialect: d1, ...rest1 } = serialized1; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1327,6 +1506,7 @@ export const diffTestSchemasSqlite = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverSqlite(renames), sch1, sch2, ); @@ -1338,6 +1518,7 @@ export const diffTestSchemasSqlite = async ( sn2, tablesResolver, columnsResolver, + sqliteViewsResolver, sch1, sch2, ); @@ -1352,10 +1533,14 @@ export const diffTestSchemasLibSQL = async ( ) => { const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + const leftViews = Object.values(left).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(leftTables); - const serialized2 = generateSqliteSnapshot(rightTables); + const rightViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized1 = generateSqliteSnapshot(leftTables, leftViews); + const serialized2 = generateSqliteSnapshot(rightTables, rightViews); const { version: v1, dialect: d1, ...rest1 } = serialized1; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1387,6 +1572,7 @@ export const diffTestSchemasLibSQL = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverSqlite(renames), sch1, sch2, ); @@ -1398,6 +1584,7 @@ export const diffTestSchemasLibSQL = async ( sn2, tablesResolver, columnsResolver, + sqliteViewsResolver, sch1, sch2, ); @@ -1430,10 +1617,25 @@ export const introspectPgToFile = async ( schemas, ); + const { version: initV, dialect: initD, ...initRest } = introspectedSchema; + + const initSch = { + version: '7', + dialect: 'postgresql', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashPgScheme(initSch); + const validatedCur = pgSchema.parse(initSch); + + // write to ts file const file = schemaToTypeScript(introspectedSchema, 'camel'); fs.writeFileSync(`tests/introspect/postgres/${testName}.ts`, file.file); + // generate snapshot from ts file const response = await prepareFromPgImports([ `tests/introspect/postgres/${testName}.ts`, ]); @@ -1460,38 +1662,23 @@ export const introspectPgToFile = async ( const sn2AfterIm = squashPgScheme(sch2); const validatedCurAfterImport = pgSchema.parse(sch2); - // save snapshot - fs.writeFileSync(`tests/introspect/postgres/${testName}.json`, JSON.stringify(validatedCurAfterImport)); - - const prevSnapshot = pgSchema.parse( - JSON.parse(fs.readFileSync(`tests/introspect/postgres/${testName}.json`).toString()), - ); - const { tables, enums, sequences, schemas: schemaImports, views, matViews } = await prepareFromPgImports( - [`tests/introspect/postgres/${testName}.ts`], - ); - - const serialized = generatePgSnapshot(tables, enums, schemaImports, sequences, views, matViews, schemas); - const cur = { id: randomUUID(), ...serialized, prevId: prevSnapshot.id }; - const squashedCurr = squashPgScheme(cur); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements, } = await applyPgSnapshotsDiff( + initSn, sn2AfterIm, - squashedCurr, testSchemasResolver(new Set()), testEnumsResolver(new Set()), testSequencesResolver(new Set()), testTablesResolver(new Set()), testColumnsResolver(new Set()), testViewsResolver(new Set()), + validatedCur, validatedCurAfterImport, - cur, ); fs.rmSync(`tests/introspect/postgres/${testName}.ts`); - fs.rmSync(`tests/introspect/postgres/${testName}.json`); return { sqlStatements: afterFileSqlStatements, @@ -1522,6 +1709,19 @@ export const introspectMySQLToFile = async ( schema, ); + const { version: initV, dialect: initD, ...initRest } = introspectedSchema; + + const initSch = { + version: '5', + dialect: 'mysql', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashMysqlScheme(initSch); + const validatedCur = mysqlSchema.parse(initSch); + const file = schemaToTypeScriptMySQL(introspectedSchema, 'camel'); fs.writeFileSync(`tests/introspect/mysql/${testName}.ts`, file.file); @@ -1530,7 +1730,7 @@ export const introspectMySQLToFile = async ( `tests/introspect/mysql/${testName}.ts`, ]); - const afterFileImports = generateMySqlSnapshot(response.tables); + const afterFileImports = generateMySqlSnapshot(response.tables, response.views); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -1545,23 +1745,6 @@ export const introspectMySQLToFile = async ( const sn2AfterIm = squashMysqlScheme(sch2); const validatedCurAfterImport = mysqlSchema.parse(sch2); - const leftTables = Object.values(initSchema).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - - const initSnapshot = generateMySqlSnapshot(leftTables); - - const { version: initV, dialect: initD, ...initRest } = initSnapshot; - - const initSch = { - version: '5', - dialect: 'mysql', - id: '0', - prevId: '0', - ...initRest, - } as const; - - const initSn = squashMysqlScheme(initSch); - const validatedCur = mysqlSchema.parse(initSch); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements, @@ -1570,6 +1753,7 @@ export const introspectMySQLToFile = async ( initSn, testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolverMySql(new Set()), validatedCurAfterImport, validatedCur, ); @@ -1606,6 +1790,20 @@ export const introspectSQLiteToFile = async ( undefined, ); + const { version: initV, dialect: initD, ...initRest } = introspectedSchema; + + const initSch = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashSqliteScheme(initSch); + + const validatedCur = sqliteSchema.parse(initSch); + const file = schemaToTypeScriptSQLite(introspectedSchema, 'camel'); fs.writeFileSync(`tests/introspect/sqlite/${testName}.ts`, file.file); @@ -1614,7 +1812,7 @@ export const introspectSQLiteToFile = async ( `tests/introspect/sqlite/${testName}.ts`, ]); - const afterFileImports = generateSqliteSnapshot(response.tables); + const afterFileImports = generateSqliteSnapshot(response.tables, response.views); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -1629,11 +1827,52 @@ export const introspectSQLiteToFile = async ( const sn2AfterIm = squashSqliteScheme(sch2); const validatedCurAfterImport = sqliteSchema.parse(sch2); - const leftTables = Object.values(initSchema).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applySqliteSnapshotsDiff( + sn2AfterIm, + initSn, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + testViewsResolverSqlite(new Set()), + validatedCurAfterImport, + validatedCur, + ); - const initSnapshot = generateSqliteSnapshot(leftTables); + fs.rmSync(`tests/introspect/sqlite/${testName}.ts`); - const { version: initV, dialect: initD, ...initRest } = initSnapshot; + return { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + }; +}; + +export const introspectLibSQLToFile = async ( + client: Client, + initSchema: SqliteSchema, + testName: string, +) => { + // put in db + const { sqlStatements } = await applyLibSQLDiffs(initSchema); + for (const st of sqlStatements) { + client.execute(st); + } + + // introspect to schema + const introspectedSchema = await fromSqliteDatabase( + { + query: async (sql: string, params: any[] = []) => { + return (await client.execute({ sql, args: params })).rows as T[]; + }, + run: async (query: string) => { + client.execute(query); + }, + }, + undefined, + ); + + const { version: initV, dialect: initD, ...initRest } = introspectedSchema; const initSch = { version: '6', @@ -1644,21 +1883,46 @@ export const introspectSQLiteToFile = async ( } as const; const initSn = squashSqliteScheme(initSch); + const validatedCur = sqliteSchema.parse(initSch); + const file = schemaToTypeScriptSQLite(introspectedSchema, 'camel'); + + fs.writeFileSync(`tests/introspect/libsql/${testName}.ts`, file.file); + + const response = await prepareFromSqliteImports([ + `tests/introspect/libsql/${testName}.ts`, + ]); + + const afterFileImports = generateSqliteSnapshot(response.tables, response.views); + + const { version: v2, dialect: d2, ...rest2 } = afterFileImports; + + const sch2 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn2AfterIm = squashSqliteScheme(sch2); + const validatedCurAfterImport = sqliteSchema.parse(sch2); + const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements, - } = await applySqliteSnapshotsDiff( + } = await applyLibSQLSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolverSqlite(new Set()), validatedCurAfterImport, validatedCur, ); - fs.rmSync(`tests/introspect/sqlite/${testName}.ts`); + fs.rmSync(`tests/introspect/libsql/${testName}.ts`); return { sqlStatements: afterFileSqlStatements, diff --git a/drizzle-kit/tests/sqlite-views.test.ts b/drizzle-kit/tests/sqlite-views.test.ts new file mode 100644 index 000000000..07a77b0e1 --- /dev/null +++ b/drizzle-kit/tests/sqlite-views.test.ts @@ -0,0 +1,212 @@ +import { sql } from 'drizzle-orm'; +import { int, sqliteTable, sqliteView } from 'drizzle-orm/sqlite-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSqlite } from './schemaDiffer'; + +test('create view', async () => { + const users = sqliteTable('users', { id: int('id').default(1) }); + const view = sqliteView('view').as((qb) => qb.select().from(users)); + const to = { + users: users, + testView: view, + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_create_table', + tableName: 'users', + columns: [{ + autoincrement: false, + default: 1, + name: 'id', + type: 'integer', + primaryKey: false, + notNull: false, + }], + compositePKs: [], + uniqueConstraints: [], + referenceData: [], + }); + expect(statements[1]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'view', + definition: 'select "id" from "users"', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer DEFAULT 1 +);\n`); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`view\` AS select "id" from "users";`); +}); + +test('drop view', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `DROP VIEW \`view\`;`, + ); +}); + +test('alter view', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users WHERE users.id = 1`), + }; + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + name: 'view', + type: 'sqlite_create_view', + definition: 'SELECT * FROM users WHERE users.id = 1', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `DROP VIEW \`view\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE VIEW \`view\` AS SELECT * FROM users WHERE users.id = 1;`, + ); +}); + +test('create view with existing flag', async () => { + const view = sqliteView('view', {}).existing(); + const to = { + testView: view, + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite({}, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop view with existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view with existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).existing(), + }; + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view and drop existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'new_view', + definition: 'SELECT * FROM users', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users;`); +}); + +test('rename view and alter ".as"', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users WHERE 1=1`), + }; + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'new_view', + definition: 'SELECT * FROM users WHERE 1=1', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe('DROP VIEW `view`;'); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users WHERE 1=1;`); +}); diff --git a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts index 47447decd..88d7b5b4e 100644 --- a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts @@ -86,6 +86,7 @@ test(`rename table and drop index`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -125,6 +126,7 @@ test(`rename table and drop index`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -277,6 +279,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -332,6 +335,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -549,6 +553,7 @@ test(`drop and set primary key. create reference`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -623,6 +628,7 @@ test(`drop and set primary key. create reference`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -810,6 +816,7 @@ test(`set and drop multiple columns reference`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -889,6 +896,7 @@ test(`set and drop multiple columns reference`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -1091,6 +1099,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -1148,6 +1157,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -1287,6 +1297,7 @@ test(`add columns. set fk`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -1356,6 +1367,7 @@ test(`add columns. set fk`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -1483,6 +1495,7 @@ test(`add column and fk`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -1552,6 +1565,7 @@ test(`add column and fk`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -1658,6 +1672,7 @@ test(`add column and fk`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -1727,6 +1742,7 @@ test(`add column and fk`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements = [ diff --git a/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts index 2fcaf6436..55f67def2 100644 --- a/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts @@ -63,6 +63,7 @@ test(`renamed column and altered this column type`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -100,6 +101,7 @@ test(`renamed column and altered this column type`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -191,6 +193,7 @@ test(`renamed column and droped column "test"`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -228,6 +231,7 @@ test(`renamed column and droped column "test"`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements: JsonStatement[] = [ @@ -304,6 +308,7 @@ test(`droped column that is part of composite pk`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -334,6 +339,7 @@ test(`droped column that is part of composite pk`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements: JsonStatement[] = [ @@ -499,6 +505,7 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -568,6 +575,7 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " }, }, enums: {}, + views: {}, }; const newJsonStatements: JsonStatement[] = [ @@ -677,6 +685,7 @@ test(`create reference on exising column (table includes unique index). expect t }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -727,6 +736,7 @@ test(`create reference on exising column (table includes unique index). expect t }, }, enums: {}, + views: {}, }; const newJsonStatements: JsonStatement[] = [ @@ -865,6 +875,7 @@ test(`add columns. set fk`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -934,6 +945,7 @@ test(`add columns. set fk`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -1079,6 +1091,7 @@ test(`add column and fk`, async (t) => { }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -1148,6 +1161,7 @@ test(`add column and fk`, async (t) => { }, }, enums: {}, + views: {}, }; const newJsonStatements = [ diff --git a/drizzle-orm/src/mysql-core/view.ts b/drizzle-orm/src/mysql-core/view.ts index 4cc7d416c..57211d147 100644 --- a/drizzle-orm/src/mysql-core/view.ts +++ b/drizzle-orm/src/mysql-core/view.ts @@ -14,7 +14,6 @@ import { MySqlViewConfig } from './view-common.ts'; export interface ViewBuilderConfig { algorithm?: 'undefined' | 'merge' | 'temptable'; - definer?: string; sqlSecurity?: 'definer' | 'invoker'; withCheckOption?: 'cascaded' | 'local'; } @@ -41,13 +40,6 @@ export class ViewBuilderCore, - ): this { - this.config.definer = definer; - return this; - } - sqlSecurity( sqlSecurity: Exclude, ): this { From 89081a73ec54d9a4ca33d34a864893380bf6c746 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 2 Oct 2024 11:34:33 +0300 Subject: [PATCH 206/492] Updated introspect tests --- drizzle-kit/tests/introspect/pg.test.ts | 4 +- drizzle-kit/tests/schemaDiffer.ts | 101 +++++++++++------------- 2 files changed, 48 insertions(+), 57 deletions(-) diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index fc2221499..d7aa9dfef 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -458,10 +458,12 @@ test('introspect checks from different schemas with same names', async () => { const { statements, sqlStatements } = await introspectPgToFile( client, schema, - 'introspect-checks', + 'introspect-checks-diff-schema-same-names', ['public', 'schema2'], ); + console.log('statements: ', statements); + expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index e214ef006..75d92bc57 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -21,11 +21,6 @@ import { logSuggestionsAndReturn } from 'src/cli/commands/sqlitePushUtils'; import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql'; import { schemaToTypeScript } from 'src/introspect-pg'; import { schemaToTypeScript as schemaToTypeScriptSQLite } from 'src/introspect-sqlite'; -import { - prepareMySqlMigrationSnapshot, - preparePgMigrationSnapshot, - prepareSqliteMigrationSnapshot, -} from 'src/migrationPreparator'; import { prepareFromMySqlImports } from 'src/serializer/mysqlImports'; import { mysqlSchema, squashMysqlScheme } from 'src/serializer/mysqlSchema'; import { generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; @@ -1319,6 +1314,19 @@ export const introspectPgToFile = async ( schemas, ); + const { version: initV, dialect: initD, ...initRest } = introspectedSchema; + + const initSch = { + version: '7', + dialect: 'postgresql', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashPgScheme(initSch); + const validatedCur = pgSchema.parse(initSch); + const file = schemaToTypeScript(introspectedSchema, 'camel'); fs.writeFileSync(`tests/introspect/postgres/${testName}.ts`, file.file); @@ -1347,37 +1355,22 @@ export const introspectPgToFile = async ( const sn2AfterIm = squashPgScheme(sch2); const validatedCurAfterImport = pgSchema.parse(sch2); - // save snapshot - fs.writeFileSync(`tests/introspect/postgres/${testName}.json`, JSON.stringify(validatedCurAfterImport)); - - const prevSnapshot = pgSchema.parse( - JSON.parse(fs.readFileSync(`tests/introspect/postgres/${testName}.json`).toString()), - ); - const { tables, enums, sequences, schemas: schemaImports } = await prepareFromPgImports( - [`tests/introspect/postgres/${testName}.ts`], - ); - - const serialized = generatePgSnapshot(tables, enums, schemaImports, sequences, schemas); - const cur = { id: randomUUID(), ...serialized, prevId: prevSnapshot.id }; - const squashedCurr = squashPgScheme(cur); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements, } = await applyPgSnapshotsDiff( + initSn, sn2AfterIm, - squashedCurr, testSchemasResolver(new Set()), testEnumsResolver(new Set()), testSequencesResolver(new Set()), testTablesResolver(new Set()), testColumnsResolver(new Set()), + validatedCur, validatedCurAfterImport, - cur, ); fs.rmSync(`tests/introspect/postgres/${testName}.ts`); - fs.rmSync(`tests/introspect/postgres/${testName}.json`); return { sqlStatements: afterFileSqlStatements, @@ -1408,6 +1401,19 @@ export const introspectMySQLToFile = async ( schema, ); + const { version: initV, dialect: initD, ...initRest } = introspectedSchema; + + const initSch = { + version: '5', + dialect: 'mysql', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashMysqlScheme(initSch); + const validatedCur = mysqlSchema.parse(initSch); + const file = schemaToTypeScriptMySQL(introspectedSchema, 'camel'); fs.writeFileSync(`tests/introspect/mysql/${testName}.ts`, file.file); @@ -1431,34 +1437,19 @@ export const introspectMySQLToFile = async ( const sn2AfterIm = squashMysqlScheme(sch2); const validatedCurAfterImport = mysqlSchema.parse(sch2); - // save snapshot - fs.writeFileSync(`tests/introspect/mysql/${testName}.json`, JSON.stringify(validatedCurAfterImport)); - - const prevSnapshot = mysqlSchema.parse( - JSON.parse(fs.readFileSync(`tests/introspect/mysql/${testName}.json`).toString()), - ); - const { tables } = await prepareFromMySqlImports( - [`tests/introspect/mysql/${testName}.ts`], - ); - - const serialized = generateMySqlSnapshot(tables); - const cur = { id: randomUUID(), ...serialized, prevId: prevSnapshot.id }; - const squashedCurr = squashMysqlScheme(cur); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements, } = await applyMysqlSnapshotsDiff( + initSn, sn2AfterIm, - squashedCurr, testTablesResolver(new Set()), testColumnsResolver(new Set()), + validatedCur, validatedCurAfterImport, - cur, ); fs.rmSync(`tests/introspect/mysql/${testName}.ts`); - fs.rmSync(`tests/introspect/mysql/${testName}.json`); return { sqlStatements: afterFileSqlStatements, @@ -1490,6 +1481,19 @@ export const introspectSQLiteToFile = async ( undefined, ); + const { version: initV, dialect: initD, ...initRest } = introspectedSchema; + + const initSch = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashSqliteScheme(initSch); + const validatedCur = sqliteSchema.parse(initSch); + const file = schemaToTypeScriptSQLite(introspectedSchema, 'camel'); fs.writeFileSync(`tests/introspect/sqlite/${testName}.ts`, file.file); @@ -1513,34 +1517,19 @@ export const introspectSQLiteToFile = async ( const sn2AfterIm = squashSqliteScheme(sch2); const validatedCurAfterImport = sqliteSchema.parse(sch2); - // save snapshot - fs.writeFileSync(`tests/introspect/sqlite/${testName}.json`, JSON.stringify(validatedCurAfterImport)); - - const prevSnapshot = sqliteSchema.parse( - JSON.parse(fs.readFileSync(`tests/introspect/sqlite/${testName}.json`).toString()), - ); - const { tables } = await prepareFromSqliteImports( - [`tests/introspect/sqlite/${testName}.ts`], - ); - - const serialized = generateSqliteSnapshot(tables); - const cur = { id: randomUUID(), ...serialized, prevId: prevSnapshot.id }; - const squashedCurr = squashSqliteScheme(cur); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements, } = await applySqliteSnapshotsDiff( + initSn, sn2AfterIm, - squashedCurr, testTablesResolver(new Set()), testColumnsResolver(new Set()), validatedCurAfterImport, - cur, + validatedCur, ); fs.rmSync(`tests/introspect/sqlite/${testName}.ts`); - fs.rmSync(`tests/introspect/sqlite/${testName}.json`); return { sqlStatements: afterFileSqlStatements, From 550a333ebd6b2de22b3a1640ab8cf8d4bdc65369 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 2 Oct 2024 11:45:11 +0300 Subject: [PATCH 207/492] minor fixes --- drizzle-orm/type-tests/mysql/tables.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index 5c9f7029f..aca5c63d7 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -186,7 +186,6 @@ export const classes = mysqlTable('classes_table', ({ serial, text }) => ({ export const newYorkers = mysqlView('new_yorkers') .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as((qb) => { const sq = qb @@ -243,7 +242,6 @@ Expect< { const newYorkers = customSchema.view('new_yorkers') .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as((qb) => { const sq = qb @@ -304,7 +302,6 @@ Expect< cityId: int('city_id'), }) .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as( sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ @@ -359,7 +356,6 @@ Expect< cityId: int('city_id'), }) .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as( sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ From fa8099aca3e7ddf5fb251609832eb370e4df2a50 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 2 Oct 2024 14:11:40 +0300 Subject: [PATCH 208/492] fixed numeric introspect in pg --- drizzle-kit/src/serializer/pgSerializer.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 8e4fe0bc6..020c9a7c1 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -1924,6 +1924,8 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str } return columnDefaultAsString; } + } else if (column.data_type.includes('numeric')) { + return `'${column.column_default}'`; } else if (column.data_type === 'json' || column.data_type === 'jsonb') { const jsonWithoutSpaces = JSON.stringify(JSON.parse(columnDefaultAsString.slice(1, -1))); return `'${jsonWithoutSpaces}'::${column.data_type}`; From 822b428707b0431a69b7399e68f3432cc36703fc Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 2 Oct 2024 15:44:24 +0300 Subject: [PATCH 209/492] fixed introspect numeric in pg --- drizzle-kit/src/serializer/pgSerializer.ts | 3 ++- drizzle-kit/tests/introspect/pg.test.ts | 2 ++ drizzle-kit/tests/push/pg.test.ts | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 020c9a7c1..42b11d41d 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -1925,7 +1925,8 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str return columnDefaultAsString; } } else if (column.data_type.includes('numeric')) { - return `'${column.column_default}'`; + // if numeric(1,1) and used '99' -> psql stores like '99'::numeric + return columnDefaultAsString.includes("'") ? columnDefaultAsString : `'${columnDefaultAsString}'`; } else if (column.data_type === 'json' || column.data_type === 'jsonb') { const jsonWithoutSpaces = JSON.stringify(JSON.parse(columnDefaultAsString.slice(1, -1))); return `'${jsonWithoutSpaces}'::${column.data_type}`; diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index f47e3e2c6..2a1974fd9 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -234,6 +234,8 @@ test('instrospect all column types', async () => { smallint: smallint('smallint').default(10), integer: integer('integer').default(10), numeric: numeric('numeric', { precision: 3, scale: 1 }).default('99.9'), + numeric2: numeric('numeric2', { precision: 1, scale: 1 }).default('99.9'), + numeric3: numeric('numeric3').default('99.9'), bigint: bigint('bigint', { mode: 'number' }).default(100), boolean: boolean('boolean').default(true), text: text('test').default('abc'), diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 38227d463..7fce89e67 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -2550,7 +2550,7 @@ test('add with options to materialized with existing flag', async () => { }); const schema1 = { test: table, - view: pgMaterializedView('view', {}).existing(), + view: pgMaterializedView('view', {}).as(sql`SELECT '123'`), }; const schema2 = { From 06c725bbeeee5222a4816abc73c96c7a9a47f300 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 2 Oct 2024 15:54:14 +0300 Subject: [PATCH 210/492] fixed introspect numeric pg --- drizzle-kit/src/serializer/pgSerializer.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index f1aaab088..9a432ac11 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -1409,6 +1409,9 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str } return columnDefaultAsString; } + } else if (column.data_type.includes('numeric')) { + // if numeric(1,1) and used '99' -> psql stores like '99'::numeric + return columnDefaultAsString.includes("'") ? columnDefaultAsString : `'${columnDefaultAsString}'`; } else if (column.data_type === 'json' || column.data_type === 'jsonb') { const jsonWithoutSpaces = JSON.stringify(JSON.parse(columnDefaultAsString.slice(1, -1))); return `'${jsonWithoutSpaces}'::${column.data_type}`; From 3b8319163807060cceda147f5ff5f9aa7427044e Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 3 Oct 2024 13:07:12 +0300 Subject: [PATCH 211/492] fixed sqlite + libsql alter existing handling --- drizzle-kit/src/snapshotsDiffer.ts | 4 ++-- drizzle-kit/tests/libsql-views.test.ts | 17 +++++++++++------ drizzle-kit/tests/sqlite-views.test.ts | 17 +++++++++++------ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 81c65baf9..e77cbb788 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -2451,7 +2451,7 @@ export const applySqliteSnapshotsDiff = async ( for (const alteredView of alteredViews) { const { definition } = json2.views[alteredView.name]; - if (alteredView.alteredDefinition && action !== 'push') { + if (alteredView.alteredExisting || (alteredView.alteredDefinition && action !== 'push')) { dropViews.push(prepareDropViewJson(alteredView.name)); createViews.push( @@ -2957,7 +2957,7 @@ export const applyLibSQLSnapshotsDiff = async ( for (const alteredView of alteredViews) { const { definition } = json2.views[alteredView.name]; - if (alteredView.alteredDefinition && action !== 'push') { + if (alteredView.alteredExisting || (alteredView.alteredDefinition && action !== 'push')) { dropViews.push(prepareDropViewJson(alteredView.name)); createViews.push( diff --git a/drizzle-kit/tests/libsql-views.test.ts b/drizzle-kit/tests/libsql-views.test.ts index 54017a3d0..f066eb165 100644 --- a/drizzle-kit/tests/libsql-views.test.ts +++ b/drizzle-kit/tests/libsql-views.test.ts @@ -148,7 +148,7 @@ test('rename view with existing flag', async () => { users, testView: sqliteView('new_view', { id: int('id') }).existing(), }; - const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, ['view->new_view']); expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); @@ -167,17 +167,22 @@ test('rename view and drop existing flag', async () => { users, testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users`), }; - const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, ['view->new_view']); - expect(statements.length).toBe(1); + expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ type: 'sqlite_create_view', name: 'new_view', definition: 'SELECT * FROM users', }); - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users;`); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe('DROP VIEW `view`;'); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users;`); }); test('rename view and alter ".as"', async () => { @@ -193,7 +198,7 @@ test('rename view and alter ".as"', async () => { users, testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users WHERE 1=1`), }; - const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, ['view->new_view']); expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ diff --git a/drizzle-kit/tests/sqlite-views.test.ts b/drizzle-kit/tests/sqlite-views.test.ts index 07a77b0e1..93d6dbe83 100644 --- a/drizzle-kit/tests/sqlite-views.test.ts +++ b/drizzle-kit/tests/sqlite-views.test.ts @@ -148,7 +148,7 @@ test('rename view with existing flag', async () => { users, testView: sqliteView('new_view', { id: int('id') }).existing(), }; - const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, ['view->new_view']); expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); @@ -167,17 +167,22 @@ test('rename view and drop existing flag', async () => { users, testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users`), }; - const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, ['view->new_view']); - expect(statements.length).toBe(1); + expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ type: 'sqlite_create_view', name: 'new_view', definition: 'SELECT * FROM users', }); - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users;`); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP VIEW \`view\`;`); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users;`); }); test('rename view and alter ".as"', async () => { @@ -193,7 +198,7 @@ test('rename view and alter ".as"', async () => { users, testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users WHERE 1=1`), }; - const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, ['view->new_view']); expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ From bab52085fbb2e7b3648c4b58f2cc0be154468693 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 3 Oct 2024 15:57:38 +0300 Subject: [PATCH 212/492] Fix types for index.ts --- drizzle-kit/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 41373faba..750d491ac 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -117,7 +117,7 @@ export type Config = schema?: string | string[]; verbose?: boolean; strict?: boolean; - casing?: 'camel' | 'snake'; + casing?: 'camelCase' | 'snake_case'; migrations?: { table?: string; schema?: string; From b1faa338de6fdd4b08248052f1c7b3c6f2fde777 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 3 Oct 2024 16:04:51 +0300 Subject: [PATCH 213/492] Update release notes --- changelogs/drizzle-kit/0.25.0.md | 38 +++++++++++++++- changelogs/drizzle-orm/0.34.0.md | 78 ++++++++++++++++++++++++++++++-- 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/changelogs/drizzle-kit/0.25.0.md b/changelogs/drizzle-kit/0.25.0.md index fc4b36c83..e33879d97 100644 --- a/changelogs/drizzle-kit/0.25.0.md +++ b/changelogs/drizzle-kit/0.25.0.md @@ -141,4 +141,40 @@ CREATE TABLE child7(r REFERENCES parent(c)); -- Error! > **NOTE**: The foreign key for the table child5 is an error because, although the parent key column has a unique index, the index uses a different collating sequence. -See more: https://www.sqlite.org/foreignkeys.html \ No newline at end of file +See more: https://www.sqlite.org/foreignkeys.html + +## New `casing` param in `drizzle-orm` and `drizzle-kit` + +There are more improvements you can make to your schema definition. The most common way to name your variables in a database and in TypeScript code is usually `snake_case` in the database and `camelCase` in the code. For this case, in Drizzle, you can now define a naming strategy in your database to help Drizzle map column keys automatically. Let's take a table from the previous example and make it work with the new casing API in Drizzle + +Table can now become: +```ts +import { pgTable } from "drizzle-orm/pg-core"; + +export const ingredients = pgTable("ingredients", (t) => ({ + id: t.uuid().defaultRandom().primaryKey(), + name: t.text().notNull(), + description: t.text(), + inStock: t.boolean().default(true), +})); +``` +As you can see, `inStock` doesn't have a database name alias, but by defining the casing configuration at the connection level, all queries will automatically map it to `snake_case` + +```ts +const db = await drizzle('node-postgres', { connection: '', casing: 'snake_case' }) +``` + +For `drizzle-kit` migrations generation you should also specify `casing` param in drizzle config, so you can be sure you casing strategy will be applied to drizzle-kit as well + +```ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "postgresql", + schema: "./schema.ts", + dbCredentials: { + url: "postgresql://postgres:password@localhost:5432/db", + }, + casing: "snake_case", +}); +``` \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.34.0.md b/changelogs/drizzle-orm/0.34.0.md index 4d2cc5cd2..cfc3e4e38 100644 --- a/changelogs/drizzle-orm/0.34.0.md +++ b/changelogs/drizzle-orm/0.34.0.md @@ -204,11 +204,11 @@ drizzle("aws-data-api-pg", { }); ``` -For `d1`, the Cloudflare Worker types as described in the [documentation](https://developers.cloudflare.com/d1/get-started/) here will be required. +For `d1`, the CloudFlare Worker types as described in the [documentation](https://developers.cloudflare.com/d1/get-started/) here will be required. ```ts drizzle("d1", { - connection: env.DB // Cloudflare Worker Types + connection: env.DB // CloudFlare Worker Types }) ``` @@ -220,9 +220,81 @@ drizzle("vercel-postgres") > Note that the first example with the client is still available and not deprecated. You can use it if you don't want to await the drizzle object. The new way of defining drizzle is designed to make it easier to import from one place and get autocomplete for all the available clients +## Optional names for columns and callback in drizzle table + +We believe that schema definition in Drizzle is extremely powerful and aims to be as close to SQL as possible while adding more helper functions for JS runtime values. + +However, there are a few areas that could be improved, which we addressed in this release. These include: + +- Unnecessary database column names when TypeScript keys are essentially just copies of them +- A callback that provides all column types available for a specific table. + +Let's look at an example with PostgreSQL (this applies to all the dialects supported by Drizzle) + +**Previously** +```ts +import { boolean, pgTable, text, uuid } from "drizzle-orm/pg-core"; + +export const ingredients = pgTable("ingredients", { + id: uuid("id").defaultRandom().primaryKey(), + name: text("name").notNull(), + description: text("description"), + inStock: boolean("in_stock").default(true), +}); +``` + +The previous table definition will still be valid in the new release, but it can be replaced with this instead + +```ts +import { pgTable } from "drizzle-orm/pg-core"; + +export const ingredients = pgTable("ingredients", (t) => ({ + id: t.uuid().defaultRandom().primaryKey(), + name: t.text().notNull(), + description: t.text(), + inStock: t.boolean("in_stock").default(true), +})); +``` + +## New `casing` param in `drizzle-orm` and `drizzle-kit` + +There are more improvements you can make to your schema definition. The most common way to name your variables in a database and in TypeScript code is usually `snake_case` in the database and `camelCase` in the code. For this case, in Drizzle, you can now define a naming strategy in your database to help Drizzle map column keys automatically. Let's take a table from the previous example and make it work with the new casing API in Drizzle + +Table can now become: +```ts +import { pgTable } from "drizzle-orm/pg-core"; + +export const ingredients = pgTable("ingredients", (t) => ({ + id: t.uuid().defaultRandom().primaryKey(), + name: t.text().notNull(), + description: t.text(), + inStock: t.boolean().default(true), +})); +``` +As you can see, `inStock` doesn't have a database name alias, but by defining the casing configuration at the connection level, all queries will automatically map it to `snake_case` + +```ts +const db = await drizzle('node-postgres', { connection: '', casing: 'snake_case' }) +``` + +For `drizzle-kit` migrations generation you should also specify `casing` param in drizzle config, so you can be sure you casing strategy will be applied to drizzle-kit as well + +```ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: "postgresql", + schema: "./schema.ts", + dbCredentials: { + url: "postgresql://postgres:password@localhost:5432/db", + }, + casing: "snake_case", +}); +``` + ## New "count" API -Befor this release to count entities in a table, you would need to do this: +Before this release to count entities in a table, you would need to do this: ```ts const res = await db.select({ count: sql`count(*)` }).from(users); From 5919323e142386e44055c8e8d9335fd83c61772b Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Fri, 4 Oct 2024 16:46:38 +0300 Subject: [PATCH 214/492] updated psql introspect + sqlite introspect for views --- drizzle-kit/src/cli/commands/pgPushUtils.ts | 151 +- drizzle-kit/src/cli/commands/push.ts | 7 + drizzle-kit/src/introspect-pg.ts | 272 +-- drizzle-kit/src/serializer/pgSerializer.ts | 1541 +++++++---------- .../src/serializer/sqliteSerializer.ts | 21 +- drizzle-kit/tests/introspect/mysql.test.ts | 4 +- drizzle-kit/tests/push/pg.test.ts | 706 +++----- drizzle-kit/tests/schemaDiffer.ts | 941 +++++----- 8 files changed, 1423 insertions(+), 2220 deletions(-) diff --git a/drizzle-kit/src/cli/commands/pgPushUtils.ts b/drizzle-kit/src/cli/commands/pgPushUtils.ts index eee0dc954..a8e2570df 100644 --- a/drizzle-kit/src/cli/commands/pgPushUtils.ts +++ b/drizzle-kit/src/cli/commands/pgPushUtils.ts @@ -47,15 +47,9 @@ function tableNameWithSchemaFrom( renamedSchemas: Record, renamedTables: Record, ) { - const newSchemaName = schema - ? renamedSchemas[schema] - ? renamedSchemas[schema] - : schema - : undefined; + const newSchemaName = schema ? (renamedSchemas[schema] ? renamedSchemas[schema] : schema) : undefined; - const newTableName = renamedTables[ - concatSchemaAndTableName(newSchemaName, tableName) - ] + const newTableName = renamedTables[concatSchemaAndTableName(newSchemaName, tableName)] ? renamedTables[concatSchemaAndTableName(newSchemaName, tableName)] : tableName; @@ -71,6 +65,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { const columnsToRemove: string[] = []; const schemasToRemove: string[] = []; const tablesToTruncate: string[] = []; + const matViewsToRemove: string[] = []; let renamedSchemas: Record = {}; let renamedTables: Record = {}; @@ -79,53 +74,44 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { if (statement.type === 'rename_schema') { renamedSchemas[statement.to] = statement.from; } else if (statement.type === 'rename_table') { - renamedTables[ - concatSchemaAndTableName(statement.toSchema, statement.tableNameTo) - ] = statement.tableNameFrom; + renamedTables[concatSchemaAndTableName(statement.toSchema, statement.tableNameTo)] = statement.tableNameFrom; } else if (statement.type === 'drop_table') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); if (count > 0) { - infoToPrint.push( - `· You're about to delete ${ - chalk.underline( - statement.tableName, - ) - } table with ${count} items`, - ); + infoToPrint.push(`· You're about to delete ${chalk.underline(statement.tableName)} table with ${count} items`); // statementsToExecute.push( // `truncate table ${tableNameWithSchemaFrom(statement)} cascade;` // ); tablesToRemove.push(statement.tableName); shouldAskForApprove = true; } + } else if (statement.type === 'drop_view' && statement.materialized) { + const res = await db.query(`select count(*) as count from "${statement.schema ?? 'public'}"."${statement.name}"`); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete "${chalk.underline(statement.name)}" materialized view with ${count} items`, + ); + + matViewsToRemove.push(statement.name); + shouldAskForApprove = true; + } } else if (statement.type === 'alter_table_drop_column') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); if (count > 0) { infoToPrint.push( `· You're about to delete ${ - chalk.underline( - statement.columnName, - ) + chalk.underline(statement.columnName) } column in ${statement.tableName} table with ${count} items`, ); columnsToRemove.push(`${statement.tableName}_${statement.columnName}`); @@ -137,48 +123,30 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { ); const count = Number(res[0].count); if (count > 0) { - infoToPrint.push( - `· You're about to delete ${ - chalk.underline( - statement.name, - ) - } schema with ${count} tables`, - ); + infoToPrint.push(`· You're about to delete ${chalk.underline(statement.name)} schema with ${count} tables`); schemasToRemove.push(statement.name); shouldAskForApprove = true; } } else if (statement.type === 'alter_table_alter_column_set_type') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); if (count > 0) { infoToPrint.push( - `· You're about to change ${ - chalk.underline( - statement.columnName, - ) - } column type from ${ + `· You're about to change ${chalk.underline(statement.columnName)} column type from ${ + chalk.underline(statement.oldDataType) + } to ${ chalk.underline( - statement.oldDataType, + statement.newDataType, ) - } to ${chalk.underline(statement.newDataType)} with ${count} items`, + } with ${count} items`, ); statementsToExecute.push( `truncate table ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) } cascade;`, ); tablesToTruncate.push(statement.tableName); @@ -187,21 +155,14 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { } else if (statement.type === 'alter_table_alter_column_drop_pk') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); if (count > 0) { infoToPrint.push( `· You're about to change ${ - chalk.underline( - statement.tableName, - ) + chalk.underline(statement.tableName) } primary key. This statements may fail and you table may left without primary key`, ); @@ -219,9 +180,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { const pkNameResponse = await db.query( `SELECT constraint_name FROM information_schema.table_constraints WHERE table_schema = '${ - typeof statement.schema === 'undefined' || statement.schema === '' - ? 'public' - : statement.schema + typeof statement.schema === 'undefined' || statement.schema === '' ? 'public' : statement.schema }' AND table_name = '${statement.tableName}' AND constraint_type = 'PRIMARY KEY';`, @@ -233,39 +192,24 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { // we will generate statement for drop pk here and not after all if-else statements continue; } else if (statement.type === 'alter_table_add_column') { - if ( - statement.column.notNull - && typeof statement.column.default === 'undefined' - ) { + if (statement.column.notNull && typeof statement.column.default === 'undefined') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); if (count > 0) { infoToPrint.push( `· You're about to add not-null ${ - chalk.underline( - statement.column.name, - ) + chalk.underline(statement.column.name) } column without default value, which contains ${count} items`, ); tablesToTruncate.push(statement.tableName); statementsToExecute.push( `truncate table ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) } cascade;`, ); @@ -275,12 +219,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { } else if (statement.type === 'create_unique_constraint') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); @@ -298,21 +237,13 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { } table?\n`, ); const { status, data } = await render( - new Select([ - 'No, add the constraint without truncating the table', - `Yes, truncate the table`, - ]), + new Select(['No, add the constraint without truncating the table', `Yes, truncate the table`]), ); if (data?.index === 1) { tablesToTruncate.push(statement.tableName); statementsToExecute.push( `truncate table ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) } cascade;`, ); shouldAskForApprove = true; @@ -323,12 +254,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { if (typeof stmnt !== 'undefined') { if (statement.type === 'drop_table') { statementsToExecute.push( - `DROP TABLE ${ - concatSchemaAndTableName( - statement.schema, - statement.tableName, - ) - } CASCADE;`, + `DROP TABLE ${concatSchemaAndTableName(statement.schema, statement.tableName)} CASCADE;`, ); } else { statementsToExecute.push(...stmnt); @@ -340,6 +266,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { statementsToExecute, shouldAskForApprove, infoToPrint, + matViewsToRemove: [...new Set(matViewsToRemove)], columnsToRemove: [...new Set(columnsToRemove)], schemasToRemove: [...new Set(schemasToRemove)], tablesToTruncate: [...new Set(tablesToTruncate)], diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 404000608..1c049af69 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -180,6 +180,7 @@ export const pgPush = async ( statementsToExecute, columnsToRemove, tablesToRemove, + matViewsToRemove, tablesToTruncate, infoToPrint, schemasToRemove, @@ -235,6 +236,12 @@ export const pgPush = async ( tablesToTruncate.length > 0 ? ` truncate ${tablesToTruncate.length} ${tablesToTruncate.length > 1 ? 'tables' : 'table'}` : '' + }${ + matViewsToRemove.length > 0 + ? ` remove ${matViewsToRemove.length} ${ + matViewsToRemove.length > 1 ? 'materialized views' : 'materialize view' + },` + : ' ' }` .replace(/(^,)|(,$)/g, '') .replace(/ +(?= )/g, ''), diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index 07411263f..a12b5ae52 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -133,9 +133,7 @@ const intervalConfig = (str: string) => { if (keys.length === 0) return; let statement = '{ '; - statement += keys - .map((it: keyof typeof json) => `${it}: ${json[it]}`) - .join(', '); + statement += keys.map((it: keyof typeof json) => `${it}: ${json[it]}`).join(', '); statement += ' }'; return statement; }; @@ -207,10 +205,7 @@ export const relationsToTypeScriptForStudio = ( ...relations, }; - const relationsConfig = extractTablesRelationalConfig( - relationalSchema, - createTableRelationsHelpers, - ); + const relationsConfig = extractTablesRelationalConfig(relationalSchema, createTableRelationsHelpers); let result = ''; @@ -239,45 +234,29 @@ export const relationsToTypeScriptForStudio = ( if (is(relation, Many)) { hasMany = true; relationsObjAsStr += `\t\t${relation.fieldName}: many(${ - relationsConfig.tableNamesMap[relation.referencedTableName].split( - '.', - )[1] - }${ - typeof relation.relationName !== 'undefined' - ? `, { relationName: "${relation.relationName}"}` - : '' - }),`; + relationsConfig.tableNamesMap[relation.referencedTableName].split('.')[1] + }${typeof relation.relationName !== 'undefined' ? `, { relationName: "${relation.relationName}"}` : ''}),`; } if (is(relation, One)) { hasOne = true; relationsObjAsStr += `\t\t${relation.fieldName}: one(${ - relationsConfig.tableNamesMap[relation.referencedTableName].split( - '.', - )[1] + relationsConfig.tableNamesMap[relation.referencedTableName].split('.')[1] }, { fields: [${ relation.config?.fields.map( (c) => - `${ - relationsConfig.tableNamesMap[ - getTableName(relation.sourceTable) - ].split('.')[1] - }.${findColumnKey(relation.sourceTable, c.name)}`, + `${relationsConfig.tableNamesMap[getTableName(relation.sourceTable)].split('.')[1]}.${ + findColumnKey(relation.sourceTable, c.name) + }`, ) }], references: [${ relation.config?.references.map( (c) => - `${ - relationsConfig.tableNamesMap[ - getTableName(relation.referencedTable) - ].split('.')[1] - }.${findColumnKey(relation.referencedTable, c.name)}`, + `${relationsConfig.tableNamesMap[getTableName(relation.referencedTable)].split('.')[1]}.${ + findColumnKey(relation.referencedTable, c.name) + }`, ) - }]${ - typeof relation.relationName !== 'undefined' - ? `, relationName: "${relation.relationName}"` - : '' - }}),`; + }]${typeof relation.relationName !== 'undefined' ? `, relationName: "${relation.relationName}"` : ''}}),`; } }); @@ -325,10 +304,7 @@ export const paramNameFor = (name: string, schema?: string) => { return `${name}${schemaSuffix}`; }; -export const schemaToTypeScript = ( - schema: PgSchemaInternal, - casing: Casing, -) => { +export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => { // collectFKs Object.values(schema.tables).forEach((table) => { Object.values(table.foreignKeys).forEach((fk) => { @@ -343,29 +319,20 @@ export const schemaToTypeScript = ( }), ); - const enumTypes = Object.values(schema.enums).reduce( - (acc, cur) => { - acc.add(`${cur.schema}.${cur.name}`); - return acc; - }, - new Set(), - ); + const enumTypes = Object.values(schema.enums).reduce((acc, cur) => { + acc.add(`${cur.schema}.${cur.name}`); + return acc; + }, new Set()); const imports = Object.values(schema.tables).reduce( (res, it) => { - const idxImports = Object.values(it.indexes).map((idx) => idx.isUnique ? 'uniqueIndex' : 'index'); + const idxImports = Object.values(it.indexes).map((idx) => (idx.isUnique ? 'uniqueIndex' : 'index')); const fkImpots = Object.values(it.foreignKeys).map((it) => 'foreignKey'); - if ( - Object.values(it.foreignKeys).some((it) => isCyclic(it) && !isSelf(it)) - ) { + if (Object.values(it.foreignKeys).some((it) => isCyclic(it) && !isSelf(it))) { res.pg.push('type AnyPgColumn'); } - const pkImports = Object.values(it.compositePrimaryKeys).map( - (it) => 'primaryKey', - ); - const uniqueImports = Object.values(it.uniqueConstraints).map( - (it) => 'unique', - ); + const pkImports = Object.values(it.compositePrimaryKeys).map((it) => 'primaryKey'); + const uniqueImports = Object.values(it.uniqueConstraints).map((it) => 'unique'); if (it.schema && it.schema !== 'public' && it.schema !== '') { res.pg.push('pgSchema'); @@ -528,28 +495,16 @@ export const schemaToTypeScript = ( // }); if ( - Object.keys(table.indexes).length > 0 - || Object.values(table.foreignKeys).length > 0 - || Object.keys(table.compositePrimaryKeys).length > 0 - || Object.keys(table.uniqueConstraints).length > 0 + Object.keys(table.indexes).length > 0 || Object.values(table.foreignKeys).length > 0 + || Object.keys(table.compositePrimaryKeys).length > 0 || Object.keys(table.uniqueConstraints).length > 0 ) { statement += ',\n'; statement += '(table) => {\n'; statement += '\treturn {\n'; - statement += createTableIndexes( - table.name, - Object.values(table.indexes), - casing, - ); + statement += createTableIndexes(table.name, Object.values(table.indexes), casing); statement += createTableFKs(Object.values(table.foreignKeys), schemas, casing); - statement += createTablePKs( - Object.values(table.compositePrimaryKeys), - casing, - ); - statement += createTableUniques( - Object.values(table.uniqueConstraints), - casing, - ); + statement += createTablePKs(Object.values(table.compositePrimaryKeys), casing); + statement += createTableUniques(Object.values(table.uniqueConstraints), casing); statement += '\t}\n'; statement += '}'; } @@ -566,7 +521,9 @@ export const schemaToTypeScript = ( const func = viewSchema ? (it.materialized ? `${viewSchema}.materializedView` : `${viewSchema}.view`) - : (it.materialized ? 'pgMaterializedView' : 'pgView'); + : it.materialized + ? 'pgMaterializedView' + : 'pgView'; const withOption = it.with ?? ''; @@ -595,11 +552,7 @@ export const schemaToTypeScript = ( const uniquePgImports = ['pgTable', ...new Set(imports.pg)]; - const importsTs = `import { ${ - uniquePgImports.join( - ', ', - ) - } } from "drizzle-orm/pg-core" + const importsTs = `import { ${uniquePgImports.join(', ')} } from "drizzle-orm/pg-core" import { sql } from "drizzle-orm"\n\n`; let decalrations = schemaStatements; @@ -652,9 +605,7 @@ const buildArrayDefault = (defaultValue: string, typeName: string): string => { // } else if (typeName === 'boolean') { // return value === 't' ? 'true' : 'false'; if (typeName === 'json' || typeName === 'jsonb') { - return value - .substring(1, value.length - 1) - .replaceAll('\\', ''); + return value.substring(1, value.length - 1).replaceAll('\\', ''); } return value; // } @@ -718,9 +669,9 @@ const mapDefault = ( if (lowered.startsWith('numeric')) { defaultValue = defaultValue - ? defaultValue.startsWith(`'`) && defaultValue.endsWith(`'`) + ? (defaultValue.startsWith(`'`) && defaultValue.endsWith(`'`) ? defaultValue.substring(1, defaultValue.length - 1) - : defaultValue + : defaultValue) : undefined; return defaultValue ? `.default('${mapColumnDefault(defaultValue, isExpression)}')` : ''; } @@ -729,7 +680,7 @@ const mapDefault = ( return defaultValue === 'now()' ? '.defaultNow()' : defaultValue === 'CURRENT_TIMESTAMP' - ? '.default(sql\`CURRENT_TIMESTAMP\`)' + ? '.default(sql`CURRENT_TIMESTAMP`)' : defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -832,12 +783,9 @@ const column = ( const lowered = type.toLowerCase().replace('[]', ''); if (enumTypes.has(`${typeSchema}.${type.replace('[]', '')}`)) { - let out = `${withCasing(name, casing)}: ${ - withCasing( - paramNameFor(type.replace('[]', ''), typeSchema), - casing, - ) - }(${dbColumnName({ name, casing })})`; + let out = `${withCasing(name, casing)}: ${withCasing(paramNameFor(type.replace('[]', ''), typeSchema), casing)}(${ + dbColumnName({ name, casing }) + })`; return out; } @@ -850,12 +798,9 @@ const column = ( } if (lowered.startsWith('bigserial')) { - return `${ - withCasing( - name, - casing, - ) - }: bigserial(${dbColumnName({ name, casing, withMode: true })}{ mode: "bigint" })`; + return `${withCasing(name, casing)}: bigserial(${ + dbColumnName({ name, casing, withMode: true }) + }{ mode: "bigint" })`; } if (lowered.startsWith('integer')) { @@ -896,14 +841,10 @@ const column = ( } if (lowered.startsWith('numeric')) { - let params: - | { precision: string | undefined; scale: string | undefined } - | undefined; + let params: { precision: string | undefined; scale: string | undefined } | undefined; if (lowered.length > 7) { - const [precision, scale] = lowered - .slice(8, lowered.length - 1) - .split(','); + const [precision, scale] = lowered.slice(8, lowered.length - 1).split(','); params = { precision, scale }; } @@ -918,11 +859,7 @@ const column = ( const withTimezone = lowered.includes('with time zone'); // const split = lowered.split(" "); let precision = lowered.startsWith('timestamp(') - ? Number( - lowered - .split(' ')[0] - .substring('timestamp('.length, lowered.split(' ')[0].length - 1), - ) + ? Number(lowered.split(' ')[0].substring('timestamp('.length, lowered.split(' ')[0].length - 1)) : null; precision = precision ? precision : null; @@ -943,11 +880,7 @@ const column = ( const withTimezone = lowered.includes('with time zone'); let precision = lowered.startsWith('time(') - ? Number( - lowered - .split(' ')[0] - .substring('time('.length, lowered.split(' ')[0].length - 1), - ) + ? Number(lowered.split(' ')[0].substring('time('.length, lowered.split(' ')[0].length - 1)) : null; precision = precision ? precision : null; @@ -1019,16 +952,8 @@ const column = ( if (lowered.startsWith('varchar')) { let out: string; if (lowered.length !== 7) { - out = `${ - withCasing( - name, - casing, - ) - }: varchar(${dbColumnName({ name, casing, withMode: true })}{ length: ${ - lowered.substring( - 8, - lowered.length - 1, - ) + out = `${withCasing(name, casing)}: varchar(${dbColumnName({ name, casing, withMode: true })}{ length: ${ + lowered.substring(8, lowered.length - 1) } })`; } else { out = `${withCasing(name, casing)}: varchar(${dbColumnName({ name, casing })})`; @@ -1081,16 +1006,8 @@ const column = ( if (lowered.startsWith('vector')) { let out: string; if (lowered.length !== 6) { - out = `${ - withCasing( - name, - casing, - ) - }: vector(${dbColumnName({ name, casing, withMode: true })}{ dimensions: ${ - lowered.substring( - 7, - lowered.length - 1, - ) + out = `${withCasing(name, casing)}: vector(${dbColumnName({ name, casing, withMode: true })}{ dimensions: ${ + lowered.substring(7, lowered.length - 1) } })`; } else { out = `${withCasing(name, casing)}: vector(${dbColumnName({ name, casing })})`; @@ -1102,16 +1019,8 @@ const column = ( if (lowered.startsWith('char')) { let out: string; if (lowered.length !== 4) { - out = `${ - withCasing( - name, - casing, - ) - }: char(${dbColumnName({ name, casing, withMode: true })}{ length: ${ - lowered.substring( - 5, - lowered.length - 1, - ) + out = `${withCasing(name, casing)}: char(${dbColumnName({ name, casing, withMode: true })}{ length: ${ + lowered.substring(5, lowered.length - 1) } })`; } else { out = `${withCasing(name, casing)}: char(${dbColumnName({ name, casing })})`; @@ -1174,27 +1083,15 @@ const createTableColumns = ( statement += columnStatement; // Provide just this in column function if (internals?.tables[tableName]?.columns[it.name]?.isArray) { - statement += dimensionsInArray( - internals?.tables[tableName]?.columns[it.name]?.dimensions, - ); + statement += dimensionsInArray(internals?.tables[tableName]?.columns[it.name]?.dimensions); } - statement += mapDefault( - tableName, - it.type, - it.name, - enumTypes, - it.typeSchema ?? 'public', - it.default, - internals, - ); + statement += mapDefault(tableName, it.type, it.name, enumTypes, it.typeSchema ?? 'public', it.default, internals); statement += it.primaryKey ? '.primaryKey()' : ''; statement += it.notNull && !it.identity ? '.notNull()' : ''; statement += it.identity ? generateIdentityParams(it.identity) : ''; - statement += it.generated - ? `.generatedAlwaysAs(sql\`${it.generated.as}\`)` - : ''; + statement += it.generated ? `.generatedAlwaysAs(sql\`${it.generated.as}\`)` : ''; // const fks = fkByColumnName[it.name]; // Andrii: I switched it off until we will get a custom naem setting in references @@ -1235,21 +1132,13 @@ const createTableColumns = ( return statement; }; -const createTableIndexes = ( - tableName: string, - idxs: Index[], - casing: Casing, -): string => { +const createTableIndexes = (tableName: string, idxs: Index[], casing: Casing): string => { let statement = ''; idxs.forEach((it) => { // we have issue when index is called as table called - let idxKey = it.name.startsWith(tableName) && it.name !== tableName - ? it.name.slice(tableName.length + 1) - : it.name; - idxKey = idxKey.endsWith('_index') - ? idxKey.slice(0, -'_index'.length) + '_idx' - : idxKey; + let idxKey = it.name.startsWith(tableName) && it.name !== tableName ? it.name.slice(tableName.length + 1) : it.name; + idxKey = idxKey.endsWith('_index') ? idxKey.slice(0, -'_index'.length) + '_idx' : idxKey; idxKey = withCasing(idxKey, casing); @@ -1272,11 +1161,7 @@ const createTableIndexes = ( } else { return `table.${withCasing(it.expression, casing)}${it.asc ? '.asc()' : '.desc()'}${ it.nulls === 'first' ? '.nullsFirst()' : '.nullsLast()' - }${ - it.opclass && vectorOps.includes(it.opclass) - ? `.op("${it.opclass}")` - : '' - }`; + }${it.opclass && vectorOps.includes(it.opclass) ? `.op("${it.opclass}")` : ''}`; } }) .join(', ') @@ -1290,15 +1175,11 @@ const createTableIndexes = ( reversedString += `${key}: "${mappedWith[key]}",`; } } - reversedString = reversedString.length > 1 - ? reversedString.slice(0, reversedString.length - 1) - : reversedString; + reversedString = reversedString.length > 1 ? reversedString.slice(0, reversedString.length - 1) : reversedString; return `${reversedString}}`; } - statement += it.with && Object.keys(it.with).length > 0 - ? `.with(${reverseLogic(it.with)})` - : ''; + statement += it.with && Object.keys(it.with).length > 0 ? `.with(${reverseLogic(it.with)})` : ''; statement += `,\n`; }); @@ -1327,10 +1208,7 @@ const createTablePKs = (pks: PrimaryKey[], casing: Casing): string => { return statement; }; -const createTableUniques = ( - unqs: UniqueConstraint[], - casing: Casing, -): string => { +const createTableUniques = (unqs: UniqueConstraint[], casing: Casing): string => { let statement = ''; unqs.forEach((it) => { @@ -1339,11 +1217,7 @@ const createTableUniques = ( statement += `\t\t${idxKey}: `; statement += 'unique('; statement += `"${it.name}")`; - statement += `.on(${ - it.columns - .map((it) => `table.${withCasing(it, casing)}`) - .join(', ') - })`; + statement += `.on(${it.columns.map((it) => `table.${withCasing(it, casing)}`).join(', ')})`; statement += it.nullsNotDistinct ? `.nullsNotDistinct()` : ''; statement += `,\n`; }); @@ -1351,11 +1225,7 @@ const createTableUniques = ( return statement; }; -const createTableFKs = ( - fks: ForeignKey[], - schemas: Record, - casing: Casing, -): string => { +const createTableFKs = (fks: ForeignKey[], schemas: Record, casing: Casing): string => { let statement = ''; fks.forEach((it) => { @@ -1365,26 +1235,16 @@ const createTableFKs = ( const isSelf = it.tableTo === it.tableFrom; const tableTo = isSelf ? 'table' : `${withCasing(paramName, casing)}`; statement += `\t\t${withCasing(it.name, casing)}: foreignKey({\n`; - statement += `\t\t\tcolumns: [${ - it.columnsFrom - .map((i) => `table.${withCasing(i, casing)}`) - .join(', ') - }],\n`; + statement += `\t\t\tcolumns: [${it.columnsFrom.map((i) => `table.${withCasing(i, casing)}`).join(', ')}],\n`; statement += `\t\t\tforeignColumns: [${ - it.columnsTo - .map((i) => `${tableTo}.${withCasing(i, casing)}`) - .join(', ') + it.columnsTo.map((i) => `${tableTo}.${withCasing(i, casing)}`).join(', ') }],\n`; statement += `\t\t\tname: "${it.name}"\n`; statement += `\t\t})`; - statement += it.onUpdate && it.onUpdate !== 'no action' - ? `.onUpdate("${it.onUpdate}")` - : ''; + statement += it.onUpdate && it.onUpdate !== 'no action' ? `.onUpdate("${it.onUpdate}")` : ''; - statement += it.onDelete && it.onDelete !== 'no action' - ? `.onDelete("${it.onDelete}")` - : ''; + statement += it.onDelete && it.onDelete !== 'no action' ? `.onDelete("${it.onDelete}")` : ''; statement += `,\n`; }); diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 42b11d41d..aff781422 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -43,30 +43,16 @@ export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; }; -function stringFromIdentityProperty( - field: string | number | undefined, -): string | undefined { - return typeof field === 'string' - ? (field as string) - : typeof field === 'undefined' - ? undefined - : String(field); +function stringFromIdentityProperty(field: string | number | undefined): string | undefined { + return typeof field === 'string' ? (field as string) : typeof field === 'undefined' ? undefined : String(field); } function maxRangeForIdentityBasedOn(columnType: string) { - return columnType === 'integer' - ? '2147483647' - : columnType === 'bigint' - ? '9223372036854775807' - : '32767'; + return columnType === 'integer' ? '2147483647' : columnType === 'bigint' ? '9223372036854775807' : '32767'; } function minRangeForIdentityBasedOn(columnType: string) { - return columnType === 'integer' - ? '-2147483648' - : columnType === 'bitint' - ? '-9223372036854775808' - : '-32768'; + return columnType === 'integer' ? '-2147483648' : columnType === 'bitint' ? '-9223372036854775808' : '-32768'; } function stringFromDatabaseIdentityProperty(field: any): string | undefined { @@ -93,20 +79,12 @@ function buildArrayString(array: any[], sqlType: string): string { if (sqlType === 'date') { return `"${value.toISOString().split('T')[0]}"`; } else if (sqlType === 'timestamp') { - return `"${ - value.toISOString() - .replace('T', ' ') - .slice(0, 23) - }"`; + return `"${value.toISOString().replace('T', ' ').slice(0, 23)}"`; } else { return `"${value.toISOString()}"`; } } else if (typeof value === 'object') { - return `"${ - JSON - .stringify(value) - .replaceAll('"', '\\"') - }"`; + return `"${JSON.stringify(value).replaceAll('"', '\\"')}"`; } return `"${value}"`; @@ -134,16 +112,8 @@ export const generatePgSnapshot = ( const indexesInSchema: Record = {}; for (const table of tables) { - const { - name: tableName, - columns, - indexes, - foreignKeys, - checks, - schema, - primaryKeys, - uniqueConstraints, - } = getTableConfig(table); + const { name: tableName, columns, indexes, foreignKeys, checks, schema, primaryKeys, uniqueConstraints } = + getTableConfig(table); if (schemaFilter && !schemaFilter.includes(schema ?? 'public')) { continue; @@ -160,21 +130,15 @@ export const generatePgSnapshot = ( const primaryKey: boolean = column.primary; const sqlTypeLowered = column.getSQLType().toLowerCase(); - const typeSchema = is(column, PgEnumColumn) - ? column.enum.schema || 'public' - : undefined; + const typeSchema = is(column, PgEnumColumn) ? column.enum.schema || 'public' : undefined; const generated = column.generated; const identity = column.generatedIdentity; const increment = stringFromIdentityProperty(identity?.sequenceOptions?.increment) ?? '1'; const minValue = stringFromIdentityProperty(identity?.sequenceOptions?.minValue) - ?? (parseFloat(increment) < 0 - ? minRangeForIdentityBasedOn(column.columnType) - : '1'); + ?? (parseFloat(increment) < 0 ? minRangeForIdentityBasedOn(column.columnType) : '1'); const maxValue = stringFromIdentityProperty(identity?.sequenceOptions?.maxValue) - ?? (parseFloat(increment) < 0 - ? '-1' - : maxRangeForIdentityBasedOn(column.getSQLType())); + ?? (parseFloat(increment) < 0 ? '-1' : maxRangeForIdentityBasedOn(column.getSQLType())); const startWith = stringFromIdentityProperty(identity?.sequenceOptions?.startWith) ?? (parseFloat(increment) < 0 ? maxValue : minValue); const cache = stringFromIdentityProperty(identity?.sequenceOptions?.cache) ?? '1'; @@ -215,24 +179,16 @@ export const generatePgSnapshot = ( if (typeof existingUnique !== 'undefined') { console.log( `\n${ - withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ - chalk.underline.blue( - tableName, - ) - } table. - The unique constraint ${ - chalk.underline.blue( - column.uniqueName, - ) - } on the ${ - chalk.underline.blue( - column.name, - ) - } column is confilcting with a unique constraint name already defined for ${ - chalk.underline.blue( - existingUnique.columns.join(','), - ) - } columns\n`) + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${chalk.underline.blue(tableName)} table. + The unique constraint ${chalk.underline.blue(column.uniqueName)} on the ${ + chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue(existingUnique.columns.join(',')) + } columns\n`, + ) }`, ); process.exit(1); @@ -252,31 +208,17 @@ export const generatePgSnapshot = ( columnToSet.default = `'${column.default}'`; } else { if (sqlTypeLowered === 'jsonb' || sqlTypeLowered === 'json') { - columnToSet.default = `'${ - JSON.stringify( - column.default, - ) - }'::${sqlTypeLowered}`; + columnToSet.default = `'${JSON.stringify(column.default)}'::${sqlTypeLowered}`; } else if (column.default instanceof Date) { if (sqlTypeLowered === 'date') { columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; } else if (sqlTypeLowered === 'timestamp') { - columnToSet.default = `'${ - column.default - .toISOString() - .replace('T', ' ') - .slice(0, 23) - }'`; + columnToSet.default = `'${column.default.toISOString().replace('T', ' ').slice(0, 23)}'`; } else { columnToSet.default = `'${column.default.toISOString()}'`; } } else if (isPgArrayType(sqlTypeLowered) && Array.isArray(column.default)) { - columnToSet.default = `'${ - buildArrayString( - column.default, - sqlTypeLowered, - ) - }'`; + columnToSet.default = `'${buildArrayString(column.default, sqlTypeLowered)}'`; } else { // Should do for all types // columnToSet.default = `'${column.default}'::${sqlTypeLowered}`; @@ -305,24 +247,16 @@ export const generatePgSnapshot = ( if (typeof existingUnique !== 'undefined') { console.log( `\n${ - withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ - chalk.underline.blue( - tableName, - ) - } table. - The unique constraint ${ - chalk.underline.blue( - name, - ) - } on the ${ - chalk.underline.blue( - columnNames.join(','), - ) - } columns is confilcting with a unique constraint name already defined for ${ - chalk.underline.blue( - existingUnique.columns.join(','), - ) - } columns\n`) + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${chalk.underline.blue(tableName)} table. + The unique constraint ${chalk.underline.blue(name)} on the ${ + chalk.underline.blue( + columnNames.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue(existingUnique.columns.join(',')) + } columns\n`, + ) }`, ); process.exit(1); @@ -376,11 +310,7 @@ export const generatePgSnapshot = ( console.log( `\n${ withStyle.errorWarning( - `Please specify an index name in ${ - getTableName( - value.config.table, - ) - } table that has "${ + `Please specify an index name in ${getTableName(value.config.table)} table that has "${ dialect.sqlToQuery(it).sql }" expression. We can generate index names for indexes on columns only; for expressions in indexes, you need to specify the name yourself.`, ) @@ -390,22 +320,12 @@ export const generatePgSnapshot = ( } } it = it as IndexedColumn; - if ( - !is(it, SQL) - && it.type! === 'PgVector' - && typeof it.indexConfig!.opClass === 'undefined' - ) { + if (!is(it, SQL) && it.type! === 'PgVector' && typeof it.indexConfig!.opClass === 'undefined') { console.log( `\n${ withStyle.errorWarning( - `You are specifying an index on the ${ - chalk.blueBright( - it.name, - ) - } column inside the ${ - chalk.blueBright( - tableName, - ) + `You are specifying an index on the ${chalk.blueBright(it.name)} column inside the ${ + chalk.blueBright(tableName) } table with the ${ chalk.blueBright( 'vector', @@ -413,9 +333,7 @@ export const generatePgSnapshot = ( } type without specifying an operator class. Vector extension doesn't have a default operator class, so you need to specify one of the available options. Here is a list of available op classes for the vector extension: [${ vectorOps .map((it) => `${chalk.underline(`${it}`)}`) - .join( - ', ', - ) + .join(', ') }].\n\nYou can specify it using current syntax: ${ chalk.underline( `index("${value.config.name}").using("${value.config.method}", table.${it.name}.op("${ @@ -431,35 +349,27 @@ export const generatePgSnapshot = ( indexColumnNames.push((it as ExtraConfigColumn).name); }); - const name = value.config.name - ? value.config.name - : indexName(tableName, indexColumnNames); - - let indexColumns: IndexColumnType[] = columns.map( - (it): IndexColumnType => { - if (is(it, SQL)) { - return { - expression: dialect.sqlToQuery(it, 'indexes').sql, - asc: true, - isExpression: true, - nulls: 'last', - }; - } else { - it = it as IndexedColumn; - return { - expression: it.name!, - isExpression: false, - asc: it.indexConfig?.order === 'asc', - nulls: it.indexConfig?.nulls - ? it.indexConfig?.nulls - : it.indexConfig?.order === 'desc' - ? 'first' - : 'last', - opclass: it.indexConfig?.opClass, - }; - } - }, - ); + const name = value.config.name ? value.config.name : indexName(tableName, indexColumnNames); + + let indexColumns: IndexColumnType[] = columns.map((it): IndexColumnType => { + if (is(it, SQL)) { + return { + expression: dialect.sqlToQuery(it, 'indexes').sql, + asc: true, + isExpression: true, + nulls: 'last', + }; + } else { + it = it as IndexedColumn; + return { + expression: it.name!, + isExpression: false, + asc: it.indexConfig?.order === 'asc', + nulls: it.indexConfig?.nulls ? it.indexConfig?.nulls : it.indexConfig?.order === 'desc' ? 'first' : 'last', + opclass: it.indexConfig?.opClass, + }; + } + }); // check for index names duplicates if (typeof indexesInSchema[schema ?? 'public'] !== 'undefined') { @@ -468,9 +378,7 @@ export const generatePgSnapshot = ( `\n${ withStyle.errorWarning( `We\'ve found duplicated index name across ${ - chalk.underline.blue( - schema ?? 'public', - ) + chalk.underline.blue(schema ?? 'public') } schema. Please rename your index in either the ${ chalk.underline.blue( tableName, @@ -490,9 +398,7 @@ export const generatePgSnapshot = ( name, columns: indexColumns, isUnique: value.config.unique ?? false, - where: value.config.where - ? dialect.sqlToQuery(value.config.where).sql - : undefined, + where: value.config.where ? dialect.sqlToQuery(value.config.where).sql : undefined, concurrently: value.config.concurrently ?? false, method: value.config.method ?? 'btree', with: value.config.with ?? {}, @@ -514,10 +420,7 @@ export const generatePgSnapshot = ( for (const sequence of sequences) { const name = sequence.seqName!; - if ( - typeof sequencesToReturn[`${sequence.schema ?? 'public'}.${name}`] - === 'undefined' - ) { + if (typeof sequencesToReturn[`${sequence.schema ?? 'public'}.${name}`] === 'undefined') { const increment = stringFromIdentityProperty(sequence?.seqOptions?.increment) ?? '1'; const minValue = stringFromIdentityProperty(sequence?.seqOptions?.minValue) ?? (parseFloat(increment) < 0 ? '-9223372036854775808' : '1'); @@ -559,9 +462,7 @@ export const generatePgSnapshot = ( ({ name: viewName, schema, query, selectedFields, isExisting, with: withOption } = getViewConfig(view)); } else { ({ name: viewName, schema, query, selectedFields, isExisting, with: withOption, tablespace, using, withNoData } = - getMaterializedViewConfig( - view, - )); + getMaterializedViewConfig(view)); materialized = true; } @@ -579,9 +480,7 @@ export const generatePgSnapshot = ( `\n${ withStyle.errorWarning( `We\'ve found duplicated view name across ${ - chalk.underline.blue( - schema ?? 'public', - ) + chalk.underline.blue(schema ?? 'public') } schema. Please rename your view`, ) }`, @@ -597,21 +496,15 @@ export const generatePgSnapshot = ( const primaryKey: boolean = column.primary; const sqlTypeLowered = column.getSQLType().toLowerCase(); - const typeSchema = is(column, PgEnumColumn) - ? column.enum.schema || 'public' - : undefined; + const typeSchema = is(column, PgEnumColumn) ? column.enum.schema || 'public' : undefined; const generated = column.generated; const identity = column.generatedIdentity; const increment = stringFromIdentityProperty(identity?.sequenceOptions?.increment) ?? '1'; const minValue = stringFromIdentityProperty(identity?.sequenceOptions?.minValue) - ?? (parseFloat(increment) < 0 - ? minRangeForIdentityBasedOn(column.columnType) - : '1'); + ?? (parseFloat(increment) < 0 ? minRangeForIdentityBasedOn(column.columnType) : '1'); const maxValue = stringFromIdentityProperty(identity?.sequenceOptions?.maxValue) - ?? (parseFloat(increment) < 0 - ? '-1' - : maxRangeForIdentityBasedOn(column.getSQLType())); + ?? (parseFloat(increment) < 0 ? '-1' : maxRangeForIdentityBasedOn(column.getSQLType())); const startWith = stringFromIdentityProperty(identity?.sequenceOptions?.startWith) ?? (parseFloat(increment) < 0 ? maxValue : minValue); const cache = stringFromIdentityProperty(identity?.sequenceOptions?.cache) ?? '1'; @@ -652,24 +545,16 @@ export const generatePgSnapshot = ( if (typeof existingUnique !== 'undefined') { console.log( `\n${ - withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ - chalk.underline.blue( - viewName, - ) - } table. - The unique constraint ${ - chalk.underline.blue( - column.uniqueName, - ) - } on the ${ - chalk.underline.blue( - column.name, - ) - } column is confilcting with a unique constraint name already defined for ${ - chalk.underline.blue( - existingUnique.columns.join(','), - ) - } columns\n`) + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${chalk.underline.blue(viewName)} table. + The unique constraint ${chalk.underline.blue(column.uniqueName)} on the ${ + chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue(existingUnique.columns.join(',')) + } columns\n`, + ) }`, ); process.exit(1); @@ -689,31 +574,17 @@ export const generatePgSnapshot = ( columnToSet.default = `'${column.default}'`; } else { if (sqlTypeLowered === 'jsonb' || sqlTypeLowered === 'json') { - columnToSet.default = `'${ - JSON.stringify( - column.default, - ) - }'::${sqlTypeLowered}`; + columnToSet.default = `'${JSON.stringify(column.default)}'::${sqlTypeLowered}`; } else if (column.default instanceof Date) { if (sqlTypeLowered === 'date') { columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; } else if (sqlTypeLowered === 'timestamp') { - columnToSet.default = `'${ - column.default - .toISOString() - .replace('T', ' ') - .slice(0, 23) - }'`; + columnToSet.default = `'${column.default.toISOString().replace('T', ' ').slice(0, 23)}'`; } else { columnToSet.default = `'${column.default.toISOString()}'`; } } else if (isPgArrayType(sqlTypeLowered) && Array.isArray(column.default)) { - columnToSet.default = `'${ - buildArrayString( - column.default, - sqlTypeLowered, - ) - }'`; + columnToSet.default = `'${buildArrayString(column.default, sqlTypeLowered)}'`; } else { // Should do for all types // columnToSet.default = `'${column.default}'::${sqlTypeLowered}`; @@ -757,9 +628,7 @@ export const generatePgSnapshot = ( schemas .filter((it) => { if (schemaFilter) { - return ( - schemaFilter.includes(it.schemaName) && it.schemaName !== 'public' - ); + return schemaFilter.includes(it.schemaName) && it.schemaName !== 'public'; } else { return it.schemaName !== 'public'; } @@ -791,20 +660,14 @@ const trimChar = (str: string, char: string) => { while (end > start && str[end - 1] === char) --end; // this.toString() due to ava deep equal issue with String { "value" } - return start > 0 || end < str.length - ? str.substring(start, end) - : str.toString(); + return start > 0 || end < str.length ? str.substring(start, end) : str.toString(); }; export const fromDatabase = async ( db: DB, tablesFilter: (table: string) => boolean = () => true, schemaFilters: string[], - progressCallback?: ( - stage: IntrospectStage, - count: number, - status: IntrospectStatus, - ) => void, + progressCallback?: (stage: IntrospectStage, count: number, status: IntrospectStatus) => void, ): Promise => { const result: Record = {}; const views: Record = {}; @@ -887,9 +750,7 @@ WHERE }; } - const whereEnums = schemaFilters - .map((t) => `n.nspname = '${t}'`) - .join(' or '); + const whereEnums = schemaFilters.map((t) => `n.nspname = '${t}'`).join(' or '); const allEnums = await db.query( `select n.nspname as enum_schema, @@ -927,73 +788,40 @@ WHERE const sequencesInColumns: string[] = []; - const all = allTables.filter((it) => it.type === 'table').map((row) => { - return new Promise(async (res, rej) => { - const tableName = row.table_name as string; - if (!tablesFilter(tableName)) return res(''); - tableCount += 1; - const tableSchema = row.table_schema; - - try { - const columnToReturn: Record = {}; - const indexToReturn: Record = {}; - const foreignKeysToReturn: Record = {}; - const primaryKeys: Record = {}; - const uniqueConstrains: Record = {}; - - const tableResponse = await db.query( - `SELECT a.attrelid::regclass::text, a.attname, is_nullable, a.attndims as array_dimensions - , CASE WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[]) - AND EXISTS ( - SELECT FROM pg_attrdef ad - WHERE ad.adrelid = a.attrelid - AND ad.adnum = a.attnum - AND pg_get_expr(ad.adbin, ad.adrelid) - = 'nextval(''' - || (pg_get_serial_sequence (a.attrelid::regclass::text - , a.attname))::regclass - || '''::regclass)' - ) - THEN CASE a.atttypid - WHEN 'int'::regtype THEN 'serial' - WHEN 'int8'::regtype THEN 'bigserial' - WHEN 'int2'::regtype THEN 'smallserial' - END - ELSE format_type(a.atttypid, a.atttypmod) - END AS data_type, INFORMATION_SCHEMA.COLUMNS.table_name, ns.nspname as type_schema, - pg_get_serial_sequence('"${tableSchema}"."${tableName}"', a.attname)::regclass as seq_name, INFORMATION_SCHEMA.COLUMNS.column_name, - INFORMATION_SCHEMA.COLUMNS.column_default, INFORMATION_SCHEMA.COLUMNS.data_type as additional_dt, - INFORMATION_SCHEMA.COLUMNS.udt_name as enum_name, - INFORMATION_SCHEMA.COLUMNS.is_generated, generation_expression, - INFORMATION_SCHEMA.COLUMNS.is_identity,INFORMATION_SCHEMA.COLUMNS.identity_generation, - INFORMATION_SCHEMA.COLUMNS.identity_start, INFORMATION_SCHEMA.COLUMNS.identity_increment, - INFORMATION_SCHEMA.COLUMNS.identity_maximum, INFORMATION_SCHEMA.COLUMNS.identity_minimum, - INFORMATION_SCHEMA.COLUMNS.identity_cycle - FROM pg_attribute a - JOIN INFORMATION_SCHEMA.COLUMNS ON INFORMATION_SCHEMA.COLUMNS.column_name = a.attname - JOIN pg_type t ON t.oid = a.atttypid LEFT JOIN pg_namespace ns ON ns.oid = t.typnamespace - WHERE a.attrelid = '"${tableSchema}"."${tableName}"'::regclass and INFORMATION_SCHEMA.COLUMNS.table_name = '${tableName}' and INFORMATION_SCHEMA.COLUMNS.table_schema = '${tableSchema}' - AND a.attnum > 0 - AND NOT a.attisdropped - ORDER BY a.attnum;`, - ); - - const tableConstraints = await db.query( - `SELECT c.column_name, c.data_type, constraint_type, constraint_name, constraint_schema + const all = allTables + .filter((it) => it.type === 'table') + .map((row) => { + return new Promise(async (res, rej) => { + const tableName = row.table_name as string; + if (!tablesFilter(tableName)) return res(''); + tableCount += 1; + const tableSchema = row.table_schema; + + try { + const columnToReturn: Record = {}; + const indexToReturn: Record = {}; + const foreignKeysToReturn: Record = {}; + const primaryKeys: Record = {}; + const uniqueConstrains: Record = {}; + + const tableResponse = await getColumnsInfoQuery({ schema: tableSchema, table: tableName, db }); + + const tableConstraints = await db.query( + `SELECT c.column_name, c.data_type, constraint_type, constraint_name, constraint_schema FROM information_schema.table_constraints tc JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name) JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema AND tc.table_name = c.table_name AND ccu.column_name = c.column_name WHERE tc.table_name = '${tableName}' and constraint_schema = '${tableSchema}';`, - ); + ); - columnsCount += tableResponse.length; - if (progressCallback) { - progressCallback('columns', columnsCount, 'fetching'); - } + columnsCount += tableResponse.length; + if (progressCallback) { + progressCallback('columns', columnsCount, 'fetching'); + } - const tableForeignKeys = await db.query( - `SELECT + const tableForeignKeys = await db.query( + `SELECT con.contype AS constraint_type, nsp.nspname AS constraint_schema, con.conname AS constraint_name, @@ -1030,254 +858,223 @@ WHERE nsp.nspname = '${tableSchema}' AND rel.relname = '${tableName}' AND con.contype IN ('f');`, - ); + ); - foreignKeysCount += tableForeignKeys.length; - if (progressCallback) { - progressCallback('fks', foreignKeysCount, 'fetching'); - } - for (const fk of tableForeignKeys) { - // const tableFrom = fk.table_name; - const columnFrom: string = fk.column_name; - const tableTo = fk.foreign_table_name; - const columnTo: string = fk.foreign_column_name; - const schemaTo: string = fk.foreign_table_schema; - const foreignKeyName = fk.constraint_name; - const onUpdate = fk.update_rule?.toLowerCase(); - const onDelete = fk.delete_rule?.toLowerCase(); - - if (typeof foreignKeysToReturn[foreignKeyName] !== 'undefined') { - foreignKeysToReturn[foreignKeyName].columnsFrom.push(columnFrom); - foreignKeysToReturn[foreignKeyName].columnsTo.push(columnTo); - } else { - foreignKeysToReturn[foreignKeyName] = { - name: foreignKeyName, - tableFrom: tableName, - tableTo, - schemaTo, - columnsFrom: [columnFrom], - columnsTo: [columnTo], - onDelete, - onUpdate, - }; + foreignKeysCount += tableForeignKeys.length; + if (progressCallback) { + progressCallback('fks', foreignKeysCount, 'fetching'); } + for (const fk of tableForeignKeys) { + // const tableFrom = fk.table_name; + const columnFrom: string = fk.column_name; + const tableTo = fk.foreign_table_name; + const columnTo: string = fk.foreign_column_name; + const schemaTo: string = fk.foreign_table_schema; + const foreignKeyName = fk.constraint_name; + const onUpdate = fk.update_rule?.toLowerCase(); + const onDelete = fk.delete_rule?.toLowerCase(); + + if (typeof foreignKeysToReturn[foreignKeyName] !== 'undefined') { + foreignKeysToReturn[foreignKeyName].columnsFrom.push(columnFrom); + foreignKeysToReturn[foreignKeyName].columnsTo.push(columnTo); + } else { + foreignKeysToReturn[foreignKeyName] = { + name: foreignKeyName, + tableFrom: tableName, + tableTo, + schemaTo, + columnsFrom: [columnFrom], + columnsTo: [columnTo], + onDelete, + onUpdate, + }; + } - foreignKeysToReturn[foreignKeyName].columnsFrom = [ - ...new Set(foreignKeysToReturn[foreignKeyName].columnsFrom), - ]; + foreignKeysToReturn[foreignKeyName].columnsFrom = [ + ...new Set(foreignKeysToReturn[foreignKeyName].columnsFrom), + ]; - foreignKeysToReturn[foreignKeyName].columnsTo = [ - ...new Set(foreignKeysToReturn[foreignKeyName].columnsTo), - ]; - } + foreignKeysToReturn[foreignKeyName].columnsTo = [...new Set(foreignKeysToReturn[foreignKeyName].columnsTo)]; + } - const uniqueConstrainsRows = tableConstraints.filter( - (mapRow) => mapRow.constraint_type === 'UNIQUE', - ); + const uniqueConstrainsRows = tableConstraints.filter((mapRow) => mapRow.constraint_type === 'UNIQUE'); - for (const unqs of uniqueConstrainsRows) { - // const tableFrom = fk.table_name; - const columnName: string = unqs.column_name; - const constraintName: string = unqs.constraint_name; + for (const unqs of uniqueConstrainsRows) { + // const tableFrom = fk.table_name; + const columnName: string = unqs.column_name; + const constraintName: string = unqs.constraint_name; - if (typeof uniqueConstrains[constraintName] !== 'undefined') { - uniqueConstrains[constraintName].columns.push(columnName); - } else { - uniqueConstrains[constraintName] = { - columns: [columnName], - nullsNotDistinct: false, - name: constraintName, - }; + if (typeof uniqueConstrains[constraintName] !== 'undefined') { + uniqueConstrains[constraintName].columns.push(columnName); + } else { + uniqueConstrains[constraintName] = { + columns: [columnName], + nullsNotDistinct: false, + name: constraintName, + }; + } } - } - for (const columnResponse of tableResponse) { - const columnName = columnResponse.attname; - const columnAdditionalDT = columnResponse.additional_dt; - const columnDimensions = columnResponse.array_dimensions; - const enumType: string = columnResponse.enum_name; - let columnType: string = columnResponse.data_type; - const typeSchema = columnResponse.type_schema; - const defaultValueRes: string = columnResponse.column_default; - - const isGenerated = columnResponse.is_generated === 'ALWAYS'; - const generationExpression = columnResponse.generation_expression; - const isIdentity = columnResponse.is_identity === 'YES'; - const identityGeneration = columnResponse.identity_generation === 'ALWAYS' - ? 'always' - : 'byDefault'; - const identityStart = columnResponse.identity_start; - const identityIncrement = columnResponse.identity_increment; - const identityMaximum = columnResponse.identity_maximum; - const identityMinimum = columnResponse.identity_minimum; - const identityCycle = columnResponse.identity_cycle === 'YES'; - const identityName = columnResponse.seq_name; - - const primaryKey = tableConstraints.filter( - (mapRow) => - columnName === mapRow.column_name - && mapRow.constraint_type === 'PRIMARY KEY', - ); + for (const columnResponse of tableResponse) { + const columnName = columnResponse.attname; + const columnAdditionalDT = columnResponse.additional_dt; + const columnDimensions = columnResponse.array_dimensions; + const enumType: string = columnResponse.enum_name; + let columnType: string = columnResponse.data_type; + const typeSchema = columnResponse.type_schema; + const defaultValueRes: string = columnResponse.column_default; + + const isGenerated = columnResponse.is_generated === 'ALWAYS'; + const generationExpression = columnResponse.generation_expression; + const isIdentity = columnResponse.is_identity === 'YES'; + const identityGeneration = columnResponse.identity_generation === 'ALWAYS' ? 'always' : 'byDefault'; + const identityStart = columnResponse.identity_start; + const identityIncrement = columnResponse.identity_increment; + const identityMaximum = columnResponse.identity_maximum; + const identityMinimum = columnResponse.identity_minimum; + const identityCycle = columnResponse.identity_cycle === 'YES'; + const identityName = columnResponse.seq_name; + + const primaryKey = tableConstraints.filter((mapRow) => + columnName === mapRow.column_name && mapRow.constraint_type === 'PRIMARY KEY' + ); - const cprimaryKey = tableConstraints.filter( - (mapRow) => mapRow.constraint_type === 'PRIMARY KEY', - ); + const cprimaryKey = tableConstraints.filter((mapRow) => mapRow.constraint_type === 'PRIMARY KEY'); - if (cprimaryKey.length > 1) { - const tableCompositePkName = await db.query( - `SELECT conname AS primary_key + if (cprimaryKey.length > 1) { + const tableCompositePkName = await db.query( + `SELECT conname AS primary_key FROM pg_constraint join pg_class on (pg_class.oid = conrelid) WHERE contype = 'p' AND connamespace = $1::regnamespace AND pg_class.relname = $2;`, - [tableSchema, tableName], - ); - primaryKeys[tableCompositePkName[0].primary_key] = { - name: tableCompositePkName[0].primary_key, - columns: cprimaryKey.map((c: any) => c.column_name), - }; - } - - let columnTypeMapped = columnType; + [tableSchema, tableName], + ); + primaryKeys[tableCompositePkName[0].primary_key] = { + name: tableCompositePkName[0].primary_key, + columns: cprimaryKey.map((c: any) => c.column_name), + }; + } - // Set default to internal object - if (columnAdditionalDT === 'ARRAY') { - if (typeof internals.tables[tableName] === 'undefined') { - internals.tables[tableName] = { - columns: { - [columnName]: { - isArray: true, - dimensions: columnDimensions, - rawType: columnTypeMapped.substring( - 0, - columnTypeMapped.length - 2, - ), + let columnTypeMapped = columnType; + + // Set default to internal object + if (columnAdditionalDT === 'ARRAY') { + if (typeof internals.tables[tableName] === 'undefined') { + internals.tables[tableName] = { + columns: { + [columnName]: { + isArray: true, + dimensions: columnDimensions, + rawType: columnTypeMapped.substring(0, columnTypeMapped.length - 2), + }, }, - }, - }; - } else { - if ( - typeof internals.tables[tableName]!.columns[columnName] - === 'undefined' - ) { - internals.tables[tableName]!.columns[columnName] = { - isArray: true, - dimensions: columnDimensions, - rawType: columnTypeMapped.substring( - 0, - columnTypeMapped.length - 2, - ), }; + } else { + if (typeof internals.tables[tableName]!.columns[columnName] === 'undefined') { + internals.tables[tableName]!.columns[columnName] = { + isArray: true, + dimensions: columnDimensions, + rawType: columnTypeMapped.substring(0, columnTypeMapped.length - 2), + }; + } } } - } - const defaultValue = defaultForColumn( - columnResponse, - internals, - tableName, - ); - if ( - defaultValue === 'NULL' - || (defaultValueRes && defaultValueRes.startsWith('(') && defaultValueRes.endsWith(')')) - ) { - if (typeof internals!.tables![tableName] === 'undefined') { - internals!.tables![tableName] = { - columns: { - [columnName]: { - isDefaultAnExpression: true, + const defaultValue = defaultForColumn(columnResponse, internals, tableName); + if ( + defaultValue === 'NULL' + || (defaultValueRes && defaultValueRes.startsWith('(') && defaultValueRes.endsWith(')')) + ) { + if (typeof internals!.tables![tableName] === 'undefined') { + internals!.tables![tableName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, }, - }, - }; - } else { - if ( - typeof internals!.tables![tableName]!.columns[columnName] - === 'undefined' - ) { - internals!.tables![tableName]!.columns[columnName] = { - isDefaultAnExpression: true, }; } else { - internals!.tables![tableName]!.columns[ - columnName - ]!.isDefaultAnExpression = true; + if (typeof internals!.tables![tableName]!.columns[columnName] === 'undefined') { + internals!.tables![tableName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![tableName]!.columns[columnName]!.isDefaultAnExpression = true; + } } } - } - const isSerial = columnType === 'serial'; + const isSerial = columnType === 'serial'; - if (columnTypeMapped.startsWith('numeric(')) { - columnTypeMapped = columnTypeMapped.replace(',', ', '); - } - - if (columnAdditionalDT === 'ARRAY') { - for (let i = 1; i < Number(columnDimensions); i++) { - columnTypeMapped += '[]'; + if (columnTypeMapped.startsWith('numeric(')) { + columnTypeMapped = columnTypeMapped.replace(',', ', '); } - } - columnTypeMapped = columnTypeMapped - .replace('character varying', 'varchar') - .replace(' without time zone', '') - // .replace("timestamp without time zone", "timestamp") - .replace('character', 'char'); - - columnTypeMapped = trimChar(columnTypeMapped, '"'); - - columnToReturn[columnName] = { - name: columnName, - type: - // filter vectors, but in future we should filter any extension that was installed by user - columnAdditionalDT === 'USER-DEFINED' - && !['vector', 'geometry'].includes(enumType) - ? enumType - : columnTypeMapped, - typeSchema: enumsToReturn[`${typeSchema}.${enumType}`] !== undefined - ? enumsToReturn[`${typeSchema}.${enumType}`].schema - : undefined, - primaryKey: primaryKey.length === 1 && cprimaryKey.length < 2, - // default: isSerial ? undefined : defaultValue, - notNull: columnResponse.is_nullable === 'NO', - generated: isGenerated - ? { as: generationExpression, type: 'stored' } - : undefined, - identity: isIdentity - ? { - type: identityGeneration, - name: identityName, - increment: stringFromDatabaseIdentityProperty(identityIncrement), - minValue: stringFromDatabaseIdentityProperty(identityMinimum), - maxValue: stringFromDatabaseIdentityProperty(identityMaximum), - startWith: stringFromDatabaseIdentityProperty(identityStart), - cache: sequencesToReturn[identityName]?.cache - ? sequencesToReturn[identityName]?.cache - : sequencesToReturn[`${tableSchema}.${identityName}`]?.cache - ? sequencesToReturn[`${tableSchema}.${identityName}`]?.cache - : undefined, - cycle: identityCycle, - schema: tableSchema, + if (columnAdditionalDT === 'ARRAY') { + for (let i = 1; i < Number(columnDimensions); i++) { + columnTypeMapped += '[]'; } - : undefined, - }; + } - if (identityName) { - // remove "" from sequence name - delete sequencesToReturn[ - `${tableSchema}.${ - identityName.startsWith('"') && identityName.endsWith('"') ? identityName.slice(1, -1) : identityName - }` - ]; - delete sequencesToReturn[identityName]; - } + columnTypeMapped = columnTypeMapped + .replace('character varying', 'varchar') + .replace(' without time zone', '') + // .replace("timestamp without time zone", "timestamp") + .replace('character', 'char'); + + columnTypeMapped = trimChar(columnTypeMapped, '"'); + + columnToReturn[columnName] = { + name: columnName, + type: + // filter vectors, but in future we should filter any extension that was installed by user + columnAdditionalDT === 'USER-DEFINED' && !['vector', 'geometry'].includes(enumType) + ? enumType + : columnTypeMapped, + typeSchema: enumsToReturn[`${typeSchema}.${enumType}`] !== undefined + ? enumsToReturn[`${typeSchema}.${enumType}`].schema + : undefined, + primaryKey: primaryKey.length === 1 && cprimaryKey.length < 2, + // default: isSerial ? undefined : defaultValue, + notNull: columnResponse.is_nullable === 'NO', + generated: isGenerated ? { as: generationExpression, type: 'stored' } : undefined, + identity: isIdentity + ? { + type: identityGeneration, + name: identityName, + increment: stringFromDatabaseIdentityProperty(identityIncrement), + minValue: stringFromDatabaseIdentityProperty(identityMinimum), + maxValue: stringFromDatabaseIdentityProperty(identityMaximum), + startWith: stringFromDatabaseIdentityProperty(identityStart), + cache: sequencesToReturn[identityName]?.cache + ? sequencesToReturn[identityName]?.cache + : sequencesToReturn[`${tableSchema}.${identityName}`]?.cache + ? sequencesToReturn[`${tableSchema}.${identityName}`]?.cache + : undefined, + cycle: identityCycle, + schema: tableSchema, + } + : undefined, + }; - if (!isSerial && typeof defaultValue !== 'undefined') { - columnToReturn[columnName].default = defaultValue; + if (identityName) { + // remove "" from sequence name + delete sequencesToReturn[ + `${tableSchema}.${ + identityName.startsWith('"') && identityName.endsWith('"') ? identityName.slice(1, -1) : identityName + }` + ]; + delete sequencesToReturn[identityName]; + } + + if (!isSerial && typeof defaultValue !== 'undefined') { + columnToReturn[columnName].default = defaultValue; + } } - } - const dbIndexes = await db.query( - `SELECT DISTINCT ON (t.relname, ic.relname, k.i) t.relname as table_name, ic.relname AS indexname, + const dbIndexes = await db.query( + `SELECT DISTINCT ON (t.relname, ic.relname, k.i) t.relname as table_name, ic.relname AS indexname, k.i AS index_order, i.indisunique as is_unique, am.amname as method, @@ -1313,10 +1110,10 @@ WHERE WHERE c.nspname = '${tableSchema}' AND t.relname = '${tableName}';`, - ); + ); - const dbIndexFromConstraint = await db.query( - `SELECT + const dbIndexFromConstraint = await db.query( + `SELECT idx.indexrelname AS index_name, idx.relname AS table_name, schemaname, @@ -1327,89 +1124,89 @@ WHERE pg_constraint con ON con.conindid = idx.indexrelid WHERE idx.relname = '${tableName}' and schemaname = '${tableSchema}' group by index_name, table_name,schemaname, generated_by_constraint;`, - ); + ); - const idxsInConsteraint = dbIndexFromConstraint - .filter((it) => it.generated_by_constraint === 1) - .map((it) => it.index_name); - - for (const dbIndex of dbIndexes) { - const indexName: string = dbIndex.indexname; - const indexColumnName: string = dbIndex.column_name; - const indexIsUnique = dbIndex.is_unique; - const indexMethod = dbIndex.method; - const indexWith: string[] = dbIndex.with; - const indexWhere: string = dbIndex.where; - const opclass: string = dbIndex.opcname; - const isExpression = dbIndex.is_expression === 1; - - const desc: boolean = dbIndex.descending; - const nullsFirst: boolean = dbIndex.nulls_first; - - const mappedWith: Record = {}; - - if (indexWith !== null) { - indexWith - // .slice(1, indexWith.length - 1) - // .split(",") - .forEach((it) => { - const splitted = it.split('='); - mappedWith[splitted[0]] = splitted[1]; - }); - } + const idxsInConsteraint = dbIndexFromConstraint.filter((it) => it.generated_by_constraint === 1).map((it) => + it.index_name + ); - if (idxsInConsteraint.includes(indexName)) continue; + for (const dbIndex of dbIndexes) { + const indexName: string = dbIndex.indexname; + const indexColumnName: string = dbIndex.column_name; + const indexIsUnique = dbIndex.is_unique; + const indexMethod = dbIndex.method; + const indexWith: string[] = dbIndex.with; + const indexWhere: string = dbIndex.where; + const opclass: string = dbIndex.opcname; + const isExpression = dbIndex.is_expression === 1; + + const desc: boolean = dbIndex.descending; + const nullsFirst: boolean = dbIndex.nulls_first; + + const mappedWith: Record = {}; + + if (indexWith !== null) { + indexWith + // .slice(1, indexWith.length - 1) + // .split(",") + .forEach((it) => { + const splitted = it.split('='); + mappedWith[splitted[0]] = splitted[1]; + }); + } - if (typeof indexToReturn[indexName] !== 'undefined') { - indexToReturn[indexName].columns.push({ - expression: indexColumnName, - asc: !desc, - nulls: nullsFirst ? 'first' : 'last', - opclass, - isExpression, - }); - } else { - indexToReturn[indexName] = { - name: indexName, - columns: [ - { - expression: indexColumnName, - asc: !desc, - nulls: nullsFirst ? 'first' : 'last', - opclass, - isExpression, - }, - ], - isUnique: indexIsUnique, - // should not be a part of diff detecs - concurrently: false, - method: indexMethod, - where: indexWhere === null ? undefined : indexWhere, - with: mappedWith, - }; + if (idxsInConsteraint.includes(indexName)) continue; + + if (typeof indexToReturn[indexName] !== 'undefined') { + indexToReturn[indexName].columns.push({ + expression: indexColumnName, + asc: !desc, + nulls: nullsFirst ? 'first' : 'last', + opclass, + isExpression, + }); + } else { + indexToReturn[indexName] = { + name: indexName, + columns: [ + { + expression: indexColumnName, + asc: !desc, + nulls: nullsFirst ? 'first' : 'last', + opclass, + isExpression, + }, + ], + isUnique: indexIsUnique, + // should not be a part of diff detecs + concurrently: false, + method: indexMethod, + where: indexWhere === null ? undefined : indexWhere, + with: mappedWith, + }; + } } - } - indexesCount += Object.keys(indexToReturn).length; - if (progressCallback) { - progressCallback('indexes', indexesCount, 'fetching'); + indexesCount += Object.keys(indexToReturn).length; + if (progressCallback) { + progressCallback('indexes', indexesCount, 'fetching'); + } + result[`${tableSchema}.${tableName}`] = { + name: tableName, + schema: tableSchema !== 'public' ? tableSchema : '', + columns: columnToReturn, + indexes: indexToReturn, + foreignKeys: foreignKeysToReturn, + compositePrimaryKeys: primaryKeys, + uniqueConstraints: uniqueConstrains, + }; + } catch (e) { + rej(e); + return; } - result[`${tableSchema}.${tableName}`] = { - name: tableName, - schema: tableSchema !== 'public' ? tableSchema : '', - columns: columnToReturn, - indexes: indexToReturn, - foreignKeys: foreignKeysToReturn, - compositePrimaryKeys: primaryKeys, - uniqueConstraints: uniqueConstrains, - }; - } catch (e) { - rej(e); - return; - } - res(''); + res(''); + }); }); - }); if (progressCallback) { progressCallback('tables', tableCount, 'done'); @@ -1418,340 +1215,167 @@ WHERE for await (const _ of all) { } - const allViews = allTables.filter((it) => it.type === 'view' || it.type === 'materialized_view').map((row) => { - return new Promise(async (res, rej) => { - const viewName = row.table_name as string; - if (!tablesFilter(viewName)) return res(''); - tableCount += 1; - const viewSchema = row.table_schema; - - try { - const columnToReturn: Record = {}; - - const viewResponses = await db.query(`WITH view_columns AS ( - SELECT DISTINCT - nv.nspname::information_schema.sql_identifier AS view_schema, - v.relname::information_schema.sql_identifier AS view_name, - nt.nspname::information_schema.sql_identifier AS table_schema, - t.relname::information_schema.sql_identifier AS table_name, - a.attname::information_schema.sql_identifier AS column_name - FROM pg_namespace nv - JOIN pg_class v ON nv.oid = v.relnamespace - JOIN pg_depend dv ON v.oid = dv.refobjid - JOIN pg_depend dt ON dv.objid = dt.objid - JOIN pg_class t ON dt.refobjid = t.oid - JOIN pg_namespace nt ON t.relnamespace = nt.oid - JOIN pg_attribute a ON t.oid = a.attrelid - WHERE (v.relkind = 'v'::"char" OR v.relkind = 'm'::"char") - AND dv.refclassid = 'pg_class'::regclass::oid - AND dv.classid = 'pg_rewrite'::regclass::oid - AND dv.deptype = 'i'::"char" - AND dv.objid = dt.objid - AND dv.refobjid <> dt.refobjid - AND dt.classid = 'pg_rewrite'::regclass::oid - AND dt.refclassid = 'pg_class'::regclass::oid - AND t.relkind = ANY (ARRAY['r'::"char", 'v'::"char", 'f'::"char", 'p'::"char"]) - AND dt.refobjsubid = a.attnum - AND pg_has_role(t.relowner, 'USAGE'::text) - AND nv.nspname::information_schema.sql_identifier = '${viewSchema}' - AND v.relname::information_schema.sql_identifier = '${viewName}' -), -column_descriptions AS ( - SELECT DISTINCT - a.attrelid::regclass::text AS table_name, - a.attname AS column_name, - c.is_nullable, - a.attndims AS array_dimensions, - CASE - WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[]) AND EXISTS ( - SELECT FROM pg_attrdef ad - WHERE ad.adrelid = a.attrelid - AND ad.adnum = a.attnum - AND pg_get_expr(ad.adbin, ad.adrelid) = 'nextval(''' || pg_get_serial_sequence(a.attrelid::regclass::text, a.attname)::regclass || '''::regclass)' - ) - THEN CASE a.atttypid - WHEN 'int'::regtype THEN 'serial' - WHEN 'int8'::regtype THEN 'bigserial' - WHEN 'int2'::regtype THEN 'smallserial' - END - ELSE format_type(a.atttypid, a.atttypmod) - END AS data_type, - pg_get_serial_sequence('"' || c.table_schema || '"."' || c.table_name || '"', a.attname)::regclass AS seq_name, - c.column_default, - c.data_type AS additional_dt, - c.udt_name AS enum_name, - c.is_generated, - c.generation_expression, - c.is_identity, - c.identity_generation, - c.identity_start, - c.identity_increment, - c.identity_maximum, - c.identity_minimum, - c.identity_cycle - FROM pg_attribute a - JOIN information_schema.columns c ON c.column_name = a.attname - JOIN pg_type t ON t.oid = a.atttypid - LEFT JOIN pg_namespace ns ON ns.oid = t.typnamespace - WHERE a.attnum > 0 - AND NOT a.attisdropped -), -table_constraints AS ( - SELECT DISTINCT ON (ccu.column_name) - ccu.column_name, - c.data_type, - tc.constraint_type, - tc.constraint_name, - tc.constraint_schema, - tc.table_name - FROM information_schema.table_constraints tc - JOIN information_schema.constraint_column_usage ccu USING (constraint_schema, constraint_name) - JOIN information_schema.columns c ON c.table_schema = tc.constraint_schema - AND tc.table_name = c.table_name - AND ccu.column_name = c.column_name -), -additional_column_info AS ( - SELECT DISTINCT - a.attrelid::regclass::text AS table_name, - a.attname AS column_name, - is_nullable, - a.attndims AS array_dimensions, - CASE - WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[]) AND EXISTS ( - SELECT FROM pg_attrdef ad - WHERE ad.adrelid = a.attrelid - AND ad.adnum = a.attnum - AND pg_get_expr(ad.adbin, ad.adrelid) = 'nextval(''' || pg_get_serial_sequence(a.attrelid::regclass::text, a.attname)::regclass || '''::regclass)' - ) - THEN CASE a.atttypid - WHEN 'int'::regtype THEN 'serial' - WHEN 'int8'::regtype THEN 'bigserial' - WHEN 'int2'::regtype THEN 'smallserial' - END - ELSE format_type(a.atttypid, a.atttypmod) - END AS data_type, - pg_get_serial_sequence('"' || c.table_schema || '"."' || c.table_name || '"', a.attname)::regclass AS seq_name, - c.column_default, - c.data_type AS additional_dt, - c.udt_name AS enum_name, - c.is_generated, - generation_expression, - is_identity, - identity_generation, - identity_start, - identity_increment, - identity_maximum, - identity_minimum, - identity_cycle - FROM pg_attribute a - JOIN information_schema.columns c ON c.column_name = a.attname - LEFT JOIN pg_type t ON t.oid = a.atttypid - LEFT JOIN pg_namespace ns ON ns.oid = t.typnamespace - WHERE a.attnum > 0 - AND NOT a.attisdropped -) -SELECT DISTINCT ON (vc.table_name, vc.column_name) - vc.view_schema, - vc.view_name, - vc.table_schema, - vc.table_name, - vc.column_name, - COALESCE(cd.data_type, aci.data_type) AS data_type, - tc.constraint_type, - tc.constraint_name, - aci.is_nullable, - aci.array_dimensions, - aci.seq_name, - aci.column_default, - aci.additional_dt, - aci.enum_name, - aci.is_generated, - aci.generation_expression, - aci.is_identity, - aci.identity_generation, - aci.identity_start, - aci.identity_increment, - aci.identity_maximum, - aci.identity_minimum, - aci.identity_cycle -FROM view_columns vc -LEFT JOIN column_descriptions cd ON vc.table_name = cd.table_name AND vc.column_name = cd.column_name -LEFT JOIN table_constraints tc ON vc.table_name = tc.table_name AND vc.column_name = tc.column_name -LEFT JOIN additional_column_info aci ON vc.table_name = aci.table_name AND vc.column_name = aci.column_name -ORDER BY vc.table_name, vc.column_name;`); - - for (const viewResponse of viewResponses) { - const columnName = viewResponse.column_name; - const columnAdditionalDT = viewResponse.additional_dt; - const columnDimensions = viewResponse.array_dimensions; - const enumType: string = viewResponse.enum_name; - let columnType: string = viewResponse.data_type; - const typeSchema = viewResponse.type_schema; - // const defaultValueRes: string = viewResponse.column_default; - - const isGenerated = viewResponse.is_generated === 'ALWAYS'; - const generationExpression = viewResponse.generation_expression; - const isIdentity = viewResponse.is_identity === 'YES'; - const identityGeneration = viewResponse.identity_generation === 'ALWAYS' - ? 'always' - : 'byDefault'; - const identityStart = viewResponse.identity_start; - const identityIncrement = viewResponse.identity_increment; - const identityMaximum = viewResponse.identity_maximum; - const identityMinimum = viewResponse.identity_minimum; - const identityCycle = viewResponse.identity_cycle === 'YES'; - const identityName = viewResponse.seq_name; - const defaultValueRes = viewResponse.column_default; - - const primaryKey = viewResponse.constraint_type === 'PRIMARY KEY'; - - let columnTypeMapped = columnType; - - // Set default to internal object - if (columnAdditionalDT === 'ARRAY') { - if (typeof internals.tables[viewName] === 'undefined') { - internals.tables[viewName] = { - columns: { - [columnName]: { - isArray: true, - dimensions: columnDimensions, - rawType: columnTypeMapped.substring( - 0, - columnTypeMapped.length - 2, - ), + const allViews = allTables + .filter((it) => it.type === 'view' || it.type === 'materialized_view') + .map((row) => { + return new Promise(async (res, rej) => { + const viewName = row.table_name as string; + if (!tablesFilter(viewName)) return res(''); + tableCount += 1; + const viewSchema = row.table_schema; + + try { + const columnToReturn: Record = {}; + + const viewResponses = await getColumnsInfoQuery({ schema: viewSchema, table: viewName, db }); + + for (const viewResponse of viewResponses) { + const columnName = viewResponse.column_name; + const columnAdditionalDT = viewResponse.additional_dt; + const columnDimensions = viewResponse.array_dimensions; + const enumType: string = viewResponse.enum_name; + let columnType: string = viewResponse.data_type; + const typeSchema = viewResponse.type_schema; + // const defaultValueRes: string = viewResponse.column_default; + + const isGenerated = viewResponse.is_generated === 'ALWAYS'; + const generationExpression = viewResponse.generation_expression; + const isIdentity = viewResponse.is_identity === 'YES'; + const identityGeneration = viewResponse.identity_generation === 'ALWAYS' ? 'always' : 'byDefault'; + const identityStart = viewResponse.identity_start; + const identityIncrement = viewResponse.identity_increment; + const identityMaximum = viewResponse.identity_maximum; + const identityMinimum = viewResponse.identity_minimum; + const identityCycle = viewResponse.identity_cycle === 'YES'; + const identityName = viewResponse.seq_name; + const defaultValueRes = viewResponse.column_default; + + const primaryKey = viewResponse.constraint_type === 'PRIMARY KEY'; + + let columnTypeMapped = columnType; + + // Set default to internal object + if (columnAdditionalDT === 'ARRAY') { + if (typeof internals.tables[viewName] === 'undefined') { + internals.tables[viewName] = { + columns: { + [columnName]: { + isArray: true, + dimensions: columnDimensions, + rawType: columnTypeMapped.substring(0, columnTypeMapped.length - 2), + }, }, - }, - }; - } else { - if ( - typeof internals.tables[viewName]!.columns[columnName] - === 'undefined' - ) { - internals.tables[viewName]!.columns[columnName] = { - isArray: true, - dimensions: columnDimensions, - rawType: columnTypeMapped.substring( - 0, - columnTypeMapped.length - 2, - ), }; + } else { + if (typeof internals.tables[viewName]!.columns[columnName] === 'undefined') { + internals.tables[viewName]!.columns[columnName] = { + isArray: true, + dimensions: columnDimensions, + rawType: columnTypeMapped.substring(0, columnTypeMapped.length - 2), + }; + } } } - } - const defaultValue = defaultForColumn( - viewResponse, - internals, - viewName, - ); - if ( - defaultValue === 'NULL' - || (defaultValueRes && defaultValueRes.startsWith('(') && defaultValueRes.endsWith(')')) - ) { - if (typeof internals!.tables![viewName] === 'undefined') { - internals!.tables![viewName] = { - columns: { - [columnName]: { - isDefaultAnExpression: true, + const defaultValue = defaultForColumn(viewResponse, internals, viewName); + if ( + defaultValue === 'NULL' + || (defaultValueRes && defaultValueRes.startsWith('(') && defaultValueRes.endsWith(')')) + ) { + if (typeof internals!.tables![viewName] === 'undefined') { + internals!.tables![viewName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, }, - }, - }; - } else { - if ( - typeof internals!.tables![viewName]!.columns[columnName] - === 'undefined' - ) { - internals!.tables![viewName]!.columns[columnName] = { - isDefaultAnExpression: true, }; } else { - internals!.tables![viewName]!.columns[ - columnName - ]!.isDefaultAnExpression = true; + if (typeof internals!.tables![viewName]!.columns[columnName] === 'undefined') { + internals!.tables![viewName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![viewName]!.columns[columnName]!.isDefaultAnExpression = true; + } } } - } - - const isSerial = columnType === 'serial'; - if (columnTypeMapped.startsWith('numeric(')) { - columnTypeMapped = columnTypeMapped.replace(',', ', '); - } + const isSerial = columnType === 'serial'; - if (columnAdditionalDT === 'ARRAY') { - for (let i = 1; i < Number(columnDimensions); i++) { - columnTypeMapped += '[]'; + if (columnTypeMapped.startsWith('numeric(')) { + columnTypeMapped = columnTypeMapped.replace(',', ', '); } - } - columnTypeMapped = columnTypeMapped - .replace('character varying', 'varchar') - .replace(' without time zone', '') - // .replace("timestamp without time zone", "timestamp") - .replace('character', 'char'); - - columnTypeMapped = trimChar(columnTypeMapped, '"'); - - columnToReturn[columnName] = { - name: columnName, - type: - // filter vectors, but in future we should filter any extension that was installed by user - columnAdditionalDT === 'USER-DEFINED' - && !['vector', 'geometry'].includes(enumType) - ? enumType - : columnTypeMapped, - typeSchema: enumsToReturn[`${typeSchema}.${enumType}`] !== undefined - ? enumsToReturn[`${typeSchema}.${enumType}`].schema - : undefined, - primaryKey: primaryKey, - notNull: viewResponse.is_nullable === 'NO', - generated: isGenerated - ? { as: generationExpression, type: 'stored' } - : undefined, - identity: isIdentity - ? { - type: identityGeneration, - name: identityName, - increment: stringFromDatabaseIdentityProperty(identityIncrement), - minValue: stringFromDatabaseIdentityProperty(identityMinimum), - maxValue: stringFromDatabaseIdentityProperty(identityMaximum), - startWith: stringFromDatabaseIdentityProperty(identityStart), - cache: sequencesToReturn[identityName]?.cache - ? sequencesToReturn[identityName]?.cache - : sequencesToReturn[`${viewSchema}.${identityName}`]?.cache - ? sequencesToReturn[`${viewSchema}.${identityName}`]?.cache - : undefined, - cycle: identityCycle, - schema: viewSchema, + if (columnAdditionalDT === 'ARRAY') { + for (let i = 1; i < Number(columnDimensions); i++) { + columnTypeMapped += '[]'; } - : undefined, - }; + } - if (identityName) { - // remove "" from sequence name - delete sequencesToReturn[ - `${viewSchema}.${ - identityName.startsWith('"') && identityName.endsWith('"') ? identityName.slice(1, -1) : identityName - }` - ]; - delete sequencesToReturn[identityName]; - } + columnTypeMapped = columnTypeMapped + .replace('character varying', 'varchar') + .replace(' without time zone', '') + // .replace("timestamp without time zone", "timestamp") + .replace('character', 'char'); + + columnTypeMapped = trimChar(columnTypeMapped, '"'); + + columnToReturn[columnName] = { + name: columnName, + type: + // filter vectors, but in future we should filter any extension that was installed by user + columnAdditionalDT === 'USER-DEFINED' && !['vector', 'geometry'].includes(enumType) + ? enumType + : columnTypeMapped, + typeSchema: enumsToReturn[`${typeSchema}.${enumType}`] !== undefined + ? enumsToReturn[`${typeSchema}.${enumType}`].schema + : undefined, + primaryKey: primaryKey, + notNull: viewResponse.is_nullable === 'NO', + generated: isGenerated ? { as: generationExpression, type: 'stored' } : undefined, + identity: isIdentity + ? { + type: identityGeneration, + name: identityName, + increment: stringFromDatabaseIdentityProperty(identityIncrement), + minValue: stringFromDatabaseIdentityProperty(identityMinimum), + maxValue: stringFromDatabaseIdentityProperty(identityMaximum), + startWith: stringFromDatabaseIdentityProperty(identityStart), + cache: sequencesToReturn[identityName]?.cache + ? sequencesToReturn[identityName]?.cache + : sequencesToReturn[`${viewSchema}.${identityName}`]?.cache + ? sequencesToReturn[`${viewSchema}.${identityName}`]?.cache + : undefined, + cycle: identityCycle, + schema: viewSchema, + } + : undefined, + }; - if (!isSerial && typeof defaultValue !== 'undefined') { - columnToReturn[columnName].default = defaultValue; + if (identityName) { + // remove "" from sequence name + delete sequencesToReturn[ + `${viewSchema}.${ + identityName.startsWith('"') && identityName.endsWith('"') ? identityName.slice(1, -1) : identityName + }` + ]; + delete sequencesToReturn[identityName]; + } + + if (!isSerial && typeof defaultValue !== 'undefined') { + columnToReturn[columnName].default = defaultValue; + } } - } - const [viewInfo] = await db.query< - { + const [viewInfo] = await db.query<{ view_name: string; schema_name: string; definition: string; tablespace_name: string | null; options: string[] | null; location: string | null; - } - >(` + }>(` SELECT c.relname AS view_name, n.nspname AS schema_name, @@ -1770,50 +1394,50 @@ WHERE AND n.nspname = '${viewSchema}' AND c.relname = '${viewName}';`); - const resultWith: { [key: string]: string | boolean | number } = {}; - if (viewInfo.options) { - viewInfo.options.forEach((pair) => { - const splitted = pair.split('='); - const key = splitted[0]; - const value = splitted[1]; - - if (value === 'true') { - resultWith[key] = true; - } else if (value === 'false') { - resultWith[key] = false; - } else if (!isNaN(Number(value))) { - resultWith[key] = Number(value); - } else { - resultWith[key] = value; - } - }); - } + const resultWith: { [key: string]: string | boolean | number } = {}; + if (viewInfo.options) { + viewInfo.options.forEach((pair) => { + const splitted = pair.split('='); + const key = splitted[0]; + const value = splitted[1]; + + if (value === 'true') { + resultWith[key] = true; + } else if (value === 'false') { + resultWith[key] = false; + } else if (!isNaN(Number(value))) { + resultWith[key] = Number(value); + } else { + resultWith[key] = value; + } + }); + } - const definition = viewInfo.definition.replace(/\s+/g, ' ').replace(';', '').trim(); - // { "check_option":"cascaded","security_barrier":true} -> // { "checkOption":"cascaded","securityBarrier":true} - const withOption = Object.values(resultWith).length - ? Object.fromEntries(Object.entries(resultWith).map(([key, value]) => [key.camelCase(), value])) - : undefined; - - const materialized = row.type === 'materialized_view'; - - views[`${viewSchema}.${viewName}`] = { - name: viewName, - schema: viewSchema, - columns: columnToReturn, - isExisting: false, - definition: definition, - materialized: materialized, - with: withOption, - tablespace: viewInfo.tablespace_name ?? undefined, - }; - } catch (e) { - rej(e); - return; - } - res(''); + const definition = viewInfo.definition.replace(/\s+/g, ' ').replace(';', '').trim(); + // { "check_option":"cascaded","security_barrier":true} -> // { "checkOption":"cascaded","securityBarrier":true} + const withOption = Object.values(resultWith).length + ? Object.fromEntries(Object.entries(resultWith).map(([key, value]) => [key.camelCase(), value])) + : undefined; + + const materialized = row.type === 'materialized_view'; + + views[`${viewSchema}.${viewName}`] = { + name: viewName, + schema: viewSchema, + columns: columnToReturn, + isExisting: false, + definition: definition, + materialized: materialized, + with: withOption, + tablespace: viewInfo.tablespace_name ?? undefined, + }; + } catch (e) { + rej(e); + return; + } + res(''); + }); }); - }); for await (const _ of allViews) { } @@ -1851,11 +1475,7 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str return undefined; } - if ( - column.data_type === 'serial' - || column.data_type === 'smallserial' - || column.data_type === 'bigserial' - ) { + if (column.data_type === 'serial' || column.data_type === 'smallserial' || column.data_type === 'bigserial') { return undefined; } @@ -1873,7 +1493,8 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str if (isArray) { return `'{${ - columnDefaultAsString.slice(2, -2) + columnDefaultAsString + .slice(2, -2) .split(/\s*,\s*/g) .map((value) => { if (['integer', 'smallint', 'bigint', 'double precision', 'real'].includes(column.data_type.slice(0, -2))) { @@ -1894,9 +1515,7 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str }}'`; } - if ( - ['integer', 'smallint', 'bigint', 'double precision', 'real'].includes(column.data_type) - ) { + if (['integer', 'smallint', 'bigint', 'double precision', 'real'].includes(column.data_type)) { if (/^-?[\d.]+(?:e-?\d+)?$/.test(columnDefaultAsString)) { return Number(columnDefaultAsString); } else { @@ -1909,17 +1528,12 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str }, }; } else { - if ( - typeof internals!.tables![tableName]!.columns[columnName] - === 'undefined' - ) { + if (typeof internals!.tables![tableName]!.columns[columnName] === 'undefined') { internals!.tables![tableName]!.columns[columnName] = { isDefaultAnExpression: true, }; } else { - internals!.tables![tableName]!.columns[ - columnName - ]!.isDefaultAnExpression = true; + internals!.tables![tableName]!.columns[columnName]!.isDefaultAnExpression = true; } } return columnDefaultAsString; @@ -1937,6 +1551,45 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str } else if (columnDefaultAsString.startsWith("'") && columnDefaultAsString.endsWith("'")) { return columnDefaultAsString; } else { - return `${columnDefaultAsString.replace(/\\/g, '\`\\')}`; + return `${columnDefaultAsString.replace(/\\/g, '`\\')}`; } }; + +const getColumnsInfoQuery = ({ schema, table, db }: { schema: string; table: string; db: DB }) => { + return db.query( + `SELECT a.attrelid::regclass::text, a.attname, is_nullable, a.attndims as array_dimensions + , CASE WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[]) + AND EXISTS ( + SELECT FROM pg_attrdef ad + WHERE ad.adrelid = a.attrelid + AND ad.adnum = a.attnum + AND pg_get_expr(ad.adbin, ad.adrelid) + = 'nextval(''' + || (pg_get_serial_sequence (a.attrelid::regclass::text + , a.attname))::regclass + || '''::regclass)' + ) + THEN CASE a.atttypid + WHEN 'int'::regtype THEN 'serial' + WHEN 'int8'::regtype THEN 'bigserial' + WHEN 'int2'::regtype THEN 'smallserial' + END + ELSE format_type(a.atttypid, a.atttypmod) + END AS data_type, INFORMATION_SCHEMA.COLUMNS.table_name, ns.nspname as type_schema, + pg_get_serial_sequence('"${schema}"."${table}"', a.attname)::regclass as seq_name, INFORMATION_SCHEMA.COLUMNS.column_name, + INFORMATION_SCHEMA.COLUMNS.column_default, INFORMATION_SCHEMA.COLUMNS.data_type as additional_dt, + INFORMATION_SCHEMA.COLUMNS.udt_name as enum_name, + INFORMATION_SCHEMA.COLUMNS.is_generated, generation_expression, + INFORMATION_SCHEMA.COLUMNS.is_identity,INFORMATION_SCHEMA.COLUMNS.identity_generation, + INFORMATION_SCHEMA.COLUMNS.identity_start, INFORMATION_SCHEMA.COLUMNS.identity_increment, + INFORMATION_SCHEMA.COLUMNS.identity_maximum, INFORMATION_SCHEMA.COLUMNS.identity_minimum, + INFORMATION_SCHEMA.COLUMNS.identity_cycle +FROM pg_attribute a +JOIN INFORMATION_SCHEMA.COLUMNS ON INFORMATION_SCHEMA.COLUMNS.column_name = a.attname +JOIN pg_type t ON t.oid = a.atttypid LEFT JOIN pg_namespace ns ON ns.oid = t.typnamespace +WHERE a.attrelid = '"${schema}"."${table}"'::regclass and INFORMATION_SCHEMA.COLUMNS.table_name = '${table}' and INFORMATION_SCHEMA.COLUMNS.table_schema = '${schema}' +AND a.attnum > 0 +AND NOT a.attisdropped +ORDER BY a.attnum;`, + ); +}; diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index e2f865afc..ea443f372 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -455,11 +455,12 @@ export const fromDatabase = async ( seq: number; hidden: number; sql: string; + type: 'view' | 'table'; }>( `SELECT - m.name as "tableName", p.name as "columnName", p.type as "columnType", p."notnull" as "notNull", p.dflt_value as "defaultValue", p.pk as pk, p.hidden as hidden, m.sql + m.name as "tableName", p.name as "columnName", p.type as "columnType", p."notnull" as "notNull", p.dflt_value as "defaultValue", p.pk as pk, p.hidden as hidden, m.sql, m.type as type FROM sqlite_master AS m JOIN pragma_table_xinfo(m.name) AS p - WHERE m.type = 'table' + WHERE (m.type = 'table' OR m.type = 'view') and m.tbl_name != 'sqlite_sequence' and m.tbl_name != 'sqlite_stat1' and m.tbl_name != '_litestream_seq' @@ -503,7 +504,10 @@ export const fromDatabase = async ( for (const column of columns) { if (!tablesFilter(column.tableName)) continue; - columnsCount += 1; + // TODO + if (column.type !== 'view') { + columnsCount += 1; + } if (progressCallback) { progressCallback('columns', columnsCount, 'fetching'); } @@ -770,15 +774,8 @@ WHERE const viewDefinition = match[1] as string; - // CREATE VIEW test_view AS SELECT * FROM users; - // CREATE VIEW test_view1 AS SELECT * FROM `users`; - // CREATE VIEW test_view2 AS SELECT * FROM "users"; - const viewOriginalTableRegex = sql.match(/FROM\s+([^\s;]+)/i); // Matches the table name after 'FROM' - let sourceTable = viewOriginalTableRegex - ? (viewOriginalTableRegex[1] as string).replaceAll('"', '').replaceAll('`', '').replaceAll("'", '') - : undefined; - - const columns = sourceTable ? result[sourceTable] ? result[sourceTable].columns : {} : {}; + const columns = result[viewName].columns; + delete result[viewName]; resultViews[viewName] = { columns: columns, diff --git a/drizzle-kit/tests/introspect/mysql.test.ts b/drizzle-kit/tests/introspect/mysql.test.ts index ae7953885..d4203967a 100644 --- a/drizzle-kit/tests/introspect/mysql.test.ts +++ b/drizzle-kit/tests/introspect/mysql.test.ts @@ -192,7 +192,7 @@ test('view #1', async () => { }); test('view #2', async () => { - const users = mysqlTable('users', { id: int('id') }); + const users = mysqlTable('some_users', { id: int('id') }); const testView = mysqlView('some_view', { id: int('id') }).algorithm('temptable').sqlSecurity('definer').as( sql`SELECT * FROM ${users}`, ); @@ -213,5 +213,5 @@ test('view #2', async () => { expect(sqlStatements.length).toBe(0); await client.query(`drop view some_view;`); - await client.query(`drop table users;`); + await client.query(`drop table some_users;`); }); diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 7fce89e67..3079eb784 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -1,4 +1,5 @@ import { PGlite } from '@electric-sql/pglite'; +import chalk from 'chalk'; import { bigint, bigserial, @@ -27,7 +28,6 @@ import { uniqueIndex, uuid, varchar, - vector, } from 'drizzle-orm/pg-core'; import { drizzle } from 'drizzle-orm/pglite'; import { eq, SQL, sql } from 'drizzle-orm/sql'; @@ -42,10 +42,7 @@ const pgSuite: DialectSuite = { const customSchema = pgSchema('schemass'); - const transactionStatusEnum = customSchema.enum( - 'TransactionStatusEnum', - ['PENDING', 'FAILED', 'SUCCESS'], - ); + const transactionStatusEnum = customSchema.enum('TransactionStatusEnum', ['PENDING', 'FAILED', 'SUCCESS']); const enumname = pgEnum('enumname', ['three', 'two', 'one']); @@ -55,11 +52,7 @@ const pgSuite: DialectSuite = { enumname: pgEnum('enumname', ['three', 'two', 'one']), customSchema: customSchema, - transactionStatusEnum: customSchema.enum('TransactionStatusEnum', [ - 'PENDING', - 'FAILED', - 'SUCCESS', - ]), + transactionStatusEnum: customSchema.enum('TransactionStatusEnum', ['PENDING', 'FAILED', 'SUCCESS']), allSmallSerials: pgTable('schema_test', { columnAll: uuid('column_all').defaultRandom(), @@ -97,15 +90,9 @@ const pgSuite: DialectSuite = { withTimezone: true, mode: 'string', }).defaultNow(), - columnAll: timestamp('column_all', { mode: 'string' }).default( - '2023-03-01 12:47:29.792', - ), - column: timestamp('column', { mode: 'string' }).default( - sql`'2023-02-28 16:18:31.18'`, - ), - column2: timestamp('column2', { mode: 'string', precision: 3 }).default( - sql`'2023-02-28 16:18:31.18'`, - ), + columnAll: timestamp('column_all', { mode: 'string' }).default('2023-03-01 12:47:29.792'), + column: timestamp('column', { mode: 'string' }).default(sql`'2023-02-28 16:18:31.18'`), + column2: timestamp('column2', { mode: 'string', precision: 3 }).default(sql`'2023-02-28 16:18:31.18'`), }), allUuids: customSchema.table('all_uuids', { @@ -115,9 +102,7 @@ const pgSuite: DialectSuite = { allDates: customSchema.table('all_dates', { column_date_now: date('column_date_now').defaultNow(), - column_all: date('column_all', { mode: 'date' }) - .default(new Date()) - .notNull(), + column_all: date('column_all', { mode: 'date' }).default(new Date()).notNull(), column: date('column'), }), @@ -128,9 +113,7 @@ const pgSuite: DialectSuite = { }), allBigints: pgTable('all_bigints', { - columnAll: bigint('column_all', { mode: 'number' }) - .default(124) - .notNull(), + columnAll: bigint('column_all', { mode: 'number' }).default(124).notNull(), column: bigint('column', { mode: 'number' }), }), @@ -148,9 +131,7 @@ const pgSuite: DialectSuite = { columnMinToSec: interval('column_min_to_sec', { fields: 'minute to second', }), - columnWithoutFields: interval('column_without_fields') - .default('00:00:01') - .notNull(), + columnWithoutFields: interval('column_without_fields').default('00:00:01').notNull(), column: interval('column'), column5: interval('column5', { fields: 'minute to second', @@ -202,9 +183,7 @@ const pgSuite: DialectSuite = { }), allJsonb: customSchema.table('all_jsonb', { - columnDefaultObject: jsonb('column_default_object') - .default({ hello: 'world world' }) - .notNull(), + columnDefaultObject: jsonb('column_default_object').default({ hello: 'world world' }).notNull(), columnDefaultArray: jsonb('column_default_array').default({ hello: { 'world world': ['foo', 'bar'] }, }), @@ -212,9 +191,7 @@ const pgSuite: DialectSuite = { }), allJson: customSchema.table('all_json', { - columnDefaultObject: json('column_default_object') - .default({ hello: 'world world' }) - .notNull(), + columnDefaultObject: json('column_default_object').default({ hello: 'world world' }).notNull(), columnDefaultArray: json('column_default_array').default({ hello: { 'world world': ['foo', 'bar'] }, foo: 'bar', @@ -230,22 +207,16 @@ const pgSuite: DialectSuite = { }), allNumerics: customSchema.table('all_numerics', { - columnAll: numeric('column_all', { precision: 1, scale: 1 }) - .default('32') - .notNull(), + columnAll: numeric('column_all', { precision: 1, scale: 1 }).default('32').notNull(), column: numeric('column'), columnPrimary: numeric('column_primary').primaryKey().notNull(), }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema1, - [], - false, - ['public', 'schemass'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema1, [], false, [ + 'public', + 'schemass', + ]); expect(statements.length).toBe(0); }, @@ -278,14 +249,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ schema: '', @@ -372,20 +336,11 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema2.users.name}`), }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -429,20 +384,11 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema2.users.name}`), }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -480,9 +426,7 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema1.users.name}`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema1.users.name}`), }), }; const schema2 = { @@ -494,14 +438,7 @@ const pgSuite: DialectSuite = { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -518,9 +455,7 @@ const pgSuite: DialectSuite = { type: 'alter_table_alter_column_drop_generated', }, ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "users" ALTER COLUMN "gen_name" DROP EXPRESSION;', - ]); + expect(sqlStatements).toStrictEqual(['ALTER TABLE "users" ALTER COLUMN "gen_name" DROP EXPRESSION;']); }, async alterGeneratedConstraint() { @@ -531,9 +466,7 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema1.users.name}`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema1.users.name}`), }), }; const schema2 = { @@ -541,20 +474,11 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema2.users.name} || 'hello'`), }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([]); expect(sqlStatements).toStrictEqual([]); @@ -569,20 +493,11 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema2.users.name} || 'hello'`), }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -640,14 +555,7 @@ const pgSuite: DialectSuite = { seq: pgSequence('my_seq', { startWith: 100 }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(0); }, @@ -663,20 +571,13 @@ const pgSuite: DialectSuite = { }, (t) => ({ removeColumn: index('removeColumn').on(t.name, t.id), - addColumn: index('addColumn') - .on(t.name.desc()) - .with({ fillfactor: 70 }), + addColumn: index('addColumn').on(t.name.desc()).with({ fillfactor: 70 }), removeExpression: index('removeExpression') .on(t.name.desc(), sql`name`) .concurrently(), addExpression: index('addExpression').on(t.id.desc()), - changeExpression: index('changeExpression').on( - t.id.desc(), - sql`name`, - ), - changeName: index('changeName') - .on(t.name.desc(), t.id.asc().nullsLast()) - .with({ fillfactor: 70 }), + changeExpression: index('changeExpression').on(t.id.desc(), sql`name`), + changeName: index('changeName').on(t.name.desc(), t.id.asc().nullsLast()).with({ fillfactor: 70 }), changeWith: index('changeWith').on(t.name).with({ fillfactor: 70 }), changeUsing: index('changeUsing').on(t.name), }), @@ -692,17 +593,10 @@ const pgSuite: DialectSuite = { }, (t) => ({ removeColumn: index('removeColumn').on(t.name), - addColumn: index('addColumn') - .on(t.name.desc(), t.id.nullsLast()) - .with({ fillfactor: 70 }), - removeExpression: index('removeExpression') - .on(t.name.desc()) - .concurrently(), + addColumn: index('addColumn').on(t.name.desc(), t.id.nullsLast()).with({ fillfactor: 70 }), + removeExpression: index('removeExpression').on(t.name.desc()).concurrently(), addExpression: index('addExpression').on(t.id.desc()), - changeExpression: index('changeExpression').on( - t.id.desc(), - sql`name desc`, - ), + changeExpression: index('changeExpression').on(t.id.desc(), sql`name desc`), changeName: index('newName') .on(t.name.desc(), sql`name`) .with({ fillfactor: 70 }), @@ -712,14 +606,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(sqlStatements).toStrictEqual([ 'DROP INDEX IF EXISTS "changeName";', @@ -750,9 +637,7 @@ const pgSuite: DialectSuite = { name: text('name'), }, (t) => ({ - indx: index() - .on(t.name.desc(), t.id.asc().nullsLast()) - .with({ fillfactor: 70 }), + indx: index().on(t.name.desc(), t.id.asc().nullsLast()).with({ fillfactor: 70 }), }), ), }; @@ -764,14 +649,7 @@ const pgSuite: DialectSuite = { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ @@ -782,9 +660,7 @@ const pgSuite: DialectSuite = { }); expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe( - `DROP INDEX IF EXISTS "users_name_id_index";`, - ); + expect(sqlStatements[0]).toBe(`DROP INDEX IF EXISTS "users_name_id_index";`); }, async indexesToBeNotTriggered() { @@ -834,14 +710,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(0); }, @@ -885,14 +754,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(0); }, @@ -958,14 +820,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); const query = async (sql: string, params?: any[]) => { const result = await client.query(sql, params ?? []); return result.rows as any[]; @@ -973,9 +828,7 @@ const pgSuite: DialectSuite = { const { statementsToExecute } = await pgSuggestions({ query }, statements); - expect(statementsToExecute).toStrictEqual([ - 'ALTER TABLE "User" ALTER COLUMN "email" SET NOT NULL;', - ]); + expect(statementsToExecute).toStrictEqual(['ALTER TABLE "User" ALTER COLUMN "email" SET NOT NULL;']); }, async addNotNullWithDataNoRollback() { @@ -1040,14 +893,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); const query = async (sql: string, params?: any[]) => { const result = await client.query(sql, params ?? []); return result.rows as any[]; @@ -1055,14 +901,9 @@ const pgSuite: DialectSuite = { await db.insert(schema1.users).values({ id: 'str', email: 'email@gmail' }); - const { statementsToExecute, shouldAskForApprove } = await pgSuggestions( - { query }, - statements, - ); + const { statementsToExecute, shouldAskForApprove } = await pgSuggestions({ query }, statements); - expect(statementsToExecute).toStrictEqual([ - 'ALTER TABLE "User" ALTER COLUMN "email" SET NOT NULL;', - ]); + expect(statementsToExecute).toStrictEqual(['ALTER TABLE "User" ALTER COLUMN "email" SET NOT NULL;']); expect(shouldAskForApprove).toBeFalsy(); }, @@ -1145,14 +986,7 @@ test('full sequence: no changes', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); @@ -1187,14 +1021,7 @@ test('basic sequence: change fields', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1262,9 +1089,7 @@ test('basic sequence: change name', async () => { type: 'rename_sequence', }, ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";', - ]); + expect(sqlStatements).toStrictEqual(['ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";']); for (const st of sqlStatements) { await client.query(st); @@ -1350,14 +1175,7 @@ test('create table: identity always/by default - no params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1417,14 +1235,7 @@ test('create table: identity always/by default - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1490,14 +1301,7 @@ test('create table: identity always/by default - all params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1558,14 +1362,7 @@ test('no diff: identity always/by default - no params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([]); expect(sqlStatements).toStrictEqual([]); @@ -1598,14 +1395,7 @@ test('no diff: identity always/by default - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([]); expect(sqlStatements).toStrictEqual([]); @@ -1658,14 +1448,7 @@ test('no diff: identity always/by default - all params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([]); expect(sqlStatements).toStrictEqual([]); @@ -1686,14 +1469,7 @@ test('drop identity from a column - no params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1703,9 +1479,7 @@ test('drop identity from a column - no params', async () => { type: 'alter_table_alter_column_drop_identity', }, ]); - expect(sqlStatements).toStrictEqual([ - `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, - ]); + expect(sqlStatements).toStrictEqual([`ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`]); for (const st of sqlStatements) { await client.query(st); @@ -1737,14 +1511,7 @@ test('drop identity from a column - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1812,14 +1579,7 @@ test('drop identity from a column - all params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1867,14 +1627,7 @@ test('alter identity from a column - no params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1886,9 +1639,7 @@ test('alter identity from a column - no params', async () => { type: 'alter_table_alter_column_change_identity', }, ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "users" ALTER COLUMN "id" SET START WITH 100;', - ]); + expect(sqlStatements).toStrictEqual(['ALTER TABLE "users" ALTER COLUMN "id" SET START WITH 100;']); for (const st of sqlStatements) { await client.query(st); @@ -1914,14 +1665,7 @@ test('alter identity from a column - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1962,14 +1706,7 @@ test('alter identity from a column - by default to always', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2013,14 +1750,7 @@ test('alter identity from a column - always to by default', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2065,14 +1795,7 @@ test('add column with identity - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2130,14 +1853,7 @@ test('add identity to column - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2180,14 +1896,7 @@ test('add array column - empty array default', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2197,9 +1906,7 @@ test('add array column - empty array default', async () => { column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'" }, }, ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{}\';', - ]); + expect(sqlStatements).toStrictEqual(['ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{}\';']); }); test('add array column - default', async () => { @@ -2217,14 +1924,7 @@ test('add array column - default', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2234,9 +1934,7 @@ test('add array column - default', async () => { column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'" }, }, ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\';', - ]); + expect(sqlStatements).toStrictEqual(['ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\';']); }); test('create view', async () => { @@ -2254,14 +1952,7 @@ test('create view', async () => { view: pgView('view').as((qb) => qb.selectDistinct().from(table)), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2276,9 +1967,7 @@ test('create view', async () => { withNoData: false, }, ]); - expect(sqlStatements).toStrictEqual([ - 'CREATE VIEW "public"."view" AS (select distinct "id" from "test");', - ]); + expect(sqlStatements).toStrictEqual(['CREATE VIEW "public"."view" AS (select distinct "id" from "test");']); }); test('create materialized view', async () => { @@ -2293,17 +1982,13 @@ test('create materialized view', async () => { const schema2 = { test: table, - view: pgMaterializedView('view').withNoData().using('heap').as((qb) => qb.selectDistinct().from(table)), + view: pgMaterializedView('view') + .withNoData() + .using('heap') + .as((qb) => qb.selectDistinct().from(table)), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2338,14 +2023,7 @@ test('drop view', async () => { test: table, }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2354,9 +2032,7 @@ test('drop view', async () => { type: 'drop_view', }, ]); - expect(sqlStatements).toStrictEqual([ - 'DROP VIEW "public"."view";', - ]); + expect(sqlStatements).toStrictEqual(['DROP VIEW "public"."view";']); }); test('drop materialized view', async () => { @@ -2374,14 +2050,7 @@ test('drop materialized view', async () => { test: table, }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2391,9 +2060,7 @@ test('drop materialized view', async () => { materialized: true, }, ]); - expect(sqlStatements).toStrictEqual([ - 'DROP MATERIALIZED VIEW "public"."view";', - ]); + expect(sqlStatements).toStrictEqual(['DROP MATERIALIZED VIEW "public"."view";']); }); test('push view with same name', async () => { @@ -2412,14 +2079,7 @@ test('push view with same name', async () => { view: pgView('view').as((qb) => qb.selectDistinct().from(table).where(eq(table.id, 1))), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([]); expect(sqlStatements).toStrictEqual([]); @@ -2441,14 +2101,7 @@ test('push materialized view with same name', async () => { view: pgMaterializedView('view').as((qb) => qb.selectDistinct().from(table).where(eq(table.id, 1))), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([]); expect(sqlStatements).toStrictEqual([]); @@ -2467,19 +2120,12 @@ test('add with options for materialized view', async () => { const schema2 = { test: table, - view: pgMaterializedView('view').with({ autovacuumFreezeTableAge: 1, autovacuumEnabled: false }).as((qb) => - qb.selectDistinct().from(table) - ), + view: pgMaterializedView('view') + .with({ autovacuumFreezeTableAge: 1, autovacuumEnabled: false }) + .as((qb) => qb.selectDistinct().from(table)), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ @@ -2511,19 +2157,12 @@ test('add with options to materialized', async () => { const schema2 = { test: table, - view: pgMaterializedView('view').with({ autovacuumVacuumCostDelay: 100, vacuumTruncate: false }).as((qb) => - qb.selectDistinct().from(table) - ), + view: pgMaterializedView('view') + .with({ autovacuumVacuumCostDelay: 100, vacuumTruncate: false }) + .as((qb) => qb.selectDistinct().from(table)), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ @@ -2550,7 +2189,7 @@ test('add with options to materialized with existing flag', async () => { }); const schema1 = { test: table, - view: pgMaterializedView('view', {}).as(sql`SELECT '123'`), + view: pgMaterializedView('view', {}).as(sql`SELECT id FROM "test"`), }; const schema2 = { @@ -2558,15 +2197,168 @@ test('add with options to materialized with existing flag', async () => { view: pgMaterializedView('view', {}).with({ autovacuumVacuumCostDelay: 100, vacuumTruncate: false }).existing(), }; - const { statements, sqlStatements } = await diffTestSchemasPush( + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop mat view with data', async () => { + const client = new PGlite(); + + const table = pgTable('table', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgMaterializedView('view', {}).as(sql`SELECT * FROM ${table}`), + }; + + const schema2 = { + test: table, + }; + + const seedStatements = [`INSERT INTO "public"."table" ("id") VALUES (1), (2), (3)`]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + matViewsToRemove, + } = await diffTestSchemasPush( client, schema1, schema2, [], false, ['public'], + seedStatements, ); - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + materialized: true, + name: 'view', + schema: 'public', + type: 'drop_view', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."view";`); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe(`· You're about to delete "${chalk.underline('view')}" materialized view with 3 items`); + expect(columnsToRemove!.length).toBe(0); + expect(schemasToRemove!.length).toBe(0); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(matViewsToRemove!.length).toBe(1); +}); + +test('drop mat view without data', async () => { + const client = new PGlite(); + + const table = pgTable('table', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgMaterializedView('view', {}).as(sql`SELECT * FROM ${table}`), + }; + + const schema2 = { + test: table, + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + matViewsToRemove, + } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + [], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + materialized: true, + name: 'view', + schema: 'public', + type: 'drop_view', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."view";`); + expect(infoToPrint!.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(schemasToRemove!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(matViewsToRemove!.length).toBe(0); +}); + +test('drop view with data', async () => { + const client = new PGlite(); + + const table = pgTable('table', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgView('view', {}).as(sql`SELECT * FROM ${table}`), + }; + + const schema2 = { + test: table, + }; + + const seedStatements = [`INSERT INTO "public"."table" ("id") VALUES (1), (2), (3)`]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + matViewsToRemove, + } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + seedStatements, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'view', + schema: 'public', + type: 'drop_view', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP VIEW "public"."view";`); + expect(infoToPrint!.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(schemasToRemove!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(matViewsToRemove!.length).toBe(0); }); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index d1ccd99fa..15b779f42 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -4,6 +4,7 @@ import { Database } from 'better-sqlite3'; import { is } from 'drizzle-orm'; import { MySqlSchema, MySqlTable, MySqlView } from 'drizzle-orm/mysql-core'; import { + getMaterializedViewConfig, isPgEnum, isPgMaterializedView, isPgSequence, @@ -30,6 +31,7 @@ import { tablesResolver, viewsResolver, } from 'src/cli/commands/migrate'; +import { pgSuggestions } from 'src/cli/commands/pgPushUtils'; import { logSuggestionsAndReturn } from 'src/cli/commands/sqlitePushUtils'; import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql'; import { schemaToTypeScript } from 'src/introspect-pg'; @@ -71,11 +73,7 @@ export type SqliteSchema = Record | SQLiteView>; export const testSchemasResolver = (renames: Set) => async (input: ResolverInput): Promise> => { try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { return { created: input.created, renamed: [], @@ -127,517 +125,476 @@ export const testSchemasResolver = } }; -export const testSequencesResolver = (renames: Set) => -async ( - input: ResolverInput, -): Promise> => { - try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } - - let createdSequences = [...input.created]; - let deletedSequences = [...input.deleted]; +export const testSequencesResolver = + (renames: Set) => async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - const result: { - created: Sequence[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Sequence; to: Sequence }[]; - deleted: Sequence[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + let createdSequences = [...input.created]; + let deletedSequences = [...input.deleted]; - for (let rename of renames) { - const [from, to] = rename.split('->'); + const result: { + created: Sequence[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Sequence; to: Sequence }[]; + deleted: Sequence[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const idxFrom = deletedSequences.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; - }); + for (let rename of renames) { + const [from, to] = rename.split('->'); - if (idxFrom >= 0) { - const idxTo = createdSequences.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const idxFrom = deletedSequences.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; }); - const tableFrom = deletedSequences[idxFrom]; - const tableTo = createdSequences[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, + if (idxFrom >= 0) { + const idxTo = createdSequences.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - } - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedSequences[idxFrom], - to: createdSequences[idxTo], - }); + const tableFrom = deletedSequences[idxFrom]; + const tableTo = createdSequences[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, + }); + } + + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedSequences[idxFrom], + to: createdSequences[idxTo], + }); + } + + delete createdSequences[idxTo]; + delete deletedSequences[idxFrom]; + + createdSequences = createdSequences.filter(Boolean); + deletedSequences = deletedSequences.filter(Boolean); } - - delete createdSequences[idxTo]; - delete deletedSequences[idxFrom]; - - createdSequences = createdSequences.filter(Boolean); - deletedSequences = deletedSequences.filter(Boolean); } - } - result.created = createdSequences; - result.deleted = deletedSequences; + result.created = createdSequences; + result.deleted = deletedSequences; - return result; - } catch (e) { - console.error(e); - throw e; - } -}; - -export const testEnumsResolver = (renames: Set) => -async ( - input: ResolverInput, -): Promise> => { - try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; + return result; + } catch (e) { + console.error(e); + throw e; } + }; - let createdEnums = [...input.created]; - let deletedEnums = [...input.deleted]; +export const testEnumsResolver = + (renames: Set) => async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - const result: { - created: Enum[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Enum; to: Enum }[]; - deleted: Enum[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + let createdEnums = [...input.created]; + let deletedEnums = [...input.deleted]; - for (let rename of renames) { - const [from, to] = rename.split('->'); + const result: { + created: Enum[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Enum; to: Enum }[]; + deleted: Enum[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const idxFrom = deletedEnums.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; - }); + for (let rename of renames) { + const [from, to] = rename.split('->'); - if (idxFrom >= 0) { - const idxTo = createdEnums.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const idxFrom = deletedEnums.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; }); - const tableFrom = deletedEnums[idxFrom]; - const tableTo = createdEnums[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, + if (idxFrom >= 0) { + const idxTo = createdEnums.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - } - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedEnums[idxFrom], - to: createdEnums[idxTo], - }); + const tableFrom = deletedEnums[idxFrom]; + const tableTo = createdEnums[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, + }); + } + + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedEnums[idxFrom], + to: createdEnums[idxTo], + }); + } + + delete createdEnums[idxTo]; + delete deletedEnums[idxFrom]; + + createdEnums = createdEnums.filter(Boolean); + deletedEnums = deletedEnums.filter(Boolean); } - - delete createdEnums[idxTo]; - delete deletedEnums[idxFrom]; - - createdEnums = createdEnums.filter(Boolean); - deletedEnums = deletedEnums.filter(Boolean); } - } - - result.created = createdEnums; - result.deleted = deletedEnums; - return result; - } catch (e) { - console.error(e); - throw e; - } -}; + result.created = createdEnums; + result.deleted = deletedEnums; -export const testTablesResolver = (renames: Set) => -async ( - input: ResolverInput
, -): Promise> => { - try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; + return result; + } catch (e) { + console.error(e); + throw e; } + }; - let createdTables = [...input.created]; - let deletedTables = [...input.deleted]; +export const testTablesResolver = + (renames: Set) => async (input: ResolverInput
): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - const result: { - created: Table[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Table; to: Table }[]; - deleted: Table[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + let createdTables = [...input.created]; + let deletedTables = [...input.deleted]; - for (let rename of renames) { - const [from, to] = rename.split('->'); + const result: { + created: Table[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Table; to: Table }[]; + deleted: Table[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const idxFrom = deletedTables.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; - }); + for (let rename of renames) { + const [from, to] = rename.split('->'); - if (idxFrom >= 0) { - const idxTo = createdTables.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const idxFrom = deletedTables.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; }); - const tableFrom = deletedTables[idxFrom]; - const tableTo = createdTables[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, + if (idxFrom >= 0) { + const idxTo = createdTables.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - } - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedTables[idxFrom], - to: createdTables[idxTo], - }); + const tableFrom = deletedTables[idxFrom]; + const tableTo = createdTables[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, + }); + } + + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedTables[idxFrom], + to: createdTables[idxTo], + }); + } + + delete createdTables[idxTo]; + delete deletedTables[idxFrom]; + + createdTables = createdTables.filter(Boolean); + deletedTables = deletedTables.filter(Boolean); } - - delete createdTables[idxTo]; - delete deletedTables[idxFrom]; - - createdTables = createdTables.filter(Boolean); - deletedTables = deletedTables.filter(Boolean); } - } - - result.created = createdTables; - result.deleted = deletedTables; - return result; - } catch (e) { - console.error(e); - throw e; - } -}; + result.created = createdTables; + result.deleted = deletedTables; -export const testColumnsResolver = (renames: Set) => -async ( - input: ColumnsResolverInput, -): Promise> => { - try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { - return { - tableName: input.tableName, - schema: input.schema, - created: input.created, - renamed: [], - deleted: input.deleted, - }; + return result; + } catch (e) { + console.error(e); + throw e; } + }; - let createdColumns = [...input.created]; - let deletedColumns = [...input.deleted]; +export const testColumnsResolver = + (renames: Set) => async (input: ColumnsResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + tableName: input.tableName, + schema: input.schema, + created: input.created, + renamed: [], + deleted: input.deleted, + }; + } - const renamed: { from: Column; to: Column }[] = []; + let createdColumns = [...input.created]; + let deletedColumns = [...input.deleted]; - const schema = input.schema || 'public'; + const renamed: { from: Column; to: Column }[] = []; - for (let rename of renames) { - const [from, to] = rename.split('->'); + const schema = input.schema || 'public'; - const idxFrom = deletedColumns.findIndex((it) => { - return `${schema}.${input.tableName}.${it.name}` === from; - }); + for (let rename of renames) { + const [from, to] = rename.split('->'); - if (idxFrom >= 0) { - const idxTo = createdColumns.findIndex((it) => { - return `${schema}.${input.tableName}.${it.name}` === to; + const idxFrom = deletedColumns.findIndex((it) => { + return `${schema}.${input.tableName}.${it.name}` === from; }); - renamed.push({ - from: deletedColumns[idxFrom], - to: createdColumns[idxTo], - }); + if (idxFrom >= 0) { + const idxTo = createdColumns.findIndex((it) => { + return `${schema}.${input.tableName}.${it.name}` === to; + }); - delete createdColumns[idxTo]; - delete deletedColumns[idxFrom]; + renamed.push({ + from: deletedColumns[idxFrom], + to: createdColumns[idxTo], + }); - createdColumns = createdColumns.filter(Boolean); - deletedColumns = deletedColumns.filter(Boolean); - } - } + delete createdColumns[idxTo]; + delete deletedColumns[idxFrom]; - return { - tableName: input.tableName, - schema: input.schema, - created: createdColumns, - deleted: deletedColumns, - renamed, - }; - } catch (e) { - console.error(e); - throw e; - } -}; + createdColumns = createdColumns.filter(Boolean); + deletedColumns = deletedColumns.filter(Boolean); + } + } -export const testViewsResolver = (renames: Set) => -async ( - input: ResolverInput, -): Promise> => { - try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, + tableName: input.tableName, + schema: input.schema, + created: createdColumns, + deleted: deletedColumns, + renamed, }; + } catch (e) { + console.error(e); + throw e; } + }; - let createdViews = [...input.created]; - let deletedViews = [...input.deleted]; +export const testViewsResolver = + (renames: Set) => async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - const result: { - created: View[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: View; to: View }[]; - deleted: View[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; - for (let rename of renames) { - const [from, to] = rename.split('->'); + const result: { + created: View[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: View; to: View }[]; + deleted: View[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const idxFrom = deletedViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; - }); + for (let rename of renames) { + const [from, to] = rename.split('->'); - if (idxFrom >= 0) { - const idxTo = createdViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; }); - const viewFrom = deletedViews[idxFrom]; - const viewTo = createdViews[idxFrom]; - - if (viewFrom.schema !== viewTo.schema) { - result.moved.push({ - name: viewFrom.name, - schemaFrom: viewFrom.schema, - schemaTo: viewTo.schema, + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - } - if (viewFrom.name !== viewTo.name) { - result.renamed.push({ - from: deletedViews[idxFrom], - to: createdViews[idxTo], - }); + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, + }); + } + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); } - - delete createdViews[idxTo]; - delete deletedViews[idxFrom]; - - createdViews = createdViews.filter(Boolean); - deletedViews = deletedViews.filter(Boolean); } - } - result.created = createdViews; - result.deleted = deletedViews; + result.created = createdViews; + result.deleted = deletedViews; - return result; - } catch (e) { - console.error(e); - throw e; - } -}; - -export const testViewsResolverMySql = (renames: Set) => -async ( - input: ResolverInput, -): Promise> => { - try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; + return result; + } catch (e) { + console.error(e); + throw e; } + }; - let createdViews = [...input.created]; - let deletedViews = [...input.deleted]; +export const testViewsResolverMySql = + (renames: Set) => + async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - const result: { - created: ViewSquashed[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: ViewSquashed; to: ViewSquashed }[]; - deleted: ViewSquashed[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; - for (let rename of renames) { - const [from, to] = rename.split('->'); + const result: { + created: ViewSquashed[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: ViewSquashed; to: ViewSquashed }[]; + deleted: ViewSquashed[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const idxFrom = deletedViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; - }); + for (let rename of renames) { + const [from, to] = rename.split('->'); - if (idxFrom >= 0) { - const idxTo = createdViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; }); - const viewFrom = deletedViews[idxFrom]; - const viewTo = createdViews[idxFrom]; - - if (viewFrom.schema !== viewTo.schema) { - result.moved.push({ - name: viewFrom.name, - schemaFrom: viewFrom.schema, - schemaTo: viewTo.schema, + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - } - if (viewFrom.name !== viewTo.name) { - result.renamed.push({ - from: deletedViews[idxFrom], - to: createdViews[idxTo], - }); + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, + }); + } + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); } - - delete createdViews[idxTo]; - delete deletedViews[idxFrom]; - - createdViews = createdViews.filter(Boolean); - deletedViews = deletedViews.filter(Boolean); } - } - result.created = createdViews; - result.deleted = deletedViews; - - return result; - } catch (e) { - console.error(e); - throw e; - } -}; + result.created = createdViews; + result.deleted = deletedViews; -export const testViewsResolverSqlite = (renames: Set) => -async ( - input: ResolverInput, -): Promise> => { - try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; + return result; + } catch (e) { + console.error(e); + throw e; } + }; - let createdViews = [...input.created]; - let deletedViews = [...input.deleted]; +export const testViewsResolverSqlite = + (renames: Set) => async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - const result: { - created: SqliteView[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: SqliteView; to: SqliteView }[]; - deleted: SqliteView[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; - for (let rename of renames) { - const [from, to] = rename.split('->'); + const result: { + created: SqliteView[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: SqliteView; to: SqliteView }[]; + deleted: SqliteView[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const idxFrom = deletedViews.findIndex((it) => { - return it.name === from; - }); + for (let rename of renames) { + const [from, to] = rename.split('->'); - if (idxFrom >= 0) { - const idxTo = createdViews.findIndex((it) => { - return it.name === to; + const idxFrom = deletedViews.findIndex((it) => { + return it.name === from; }); - const viewFrom = deletedViews[idxFrom]; - const viewTo = createdViews[idxFrom]; - - if (viewFrom.name !== viewTo.name) { - result.renamed.push({ - from: deletedViews[idxFrom], - to: createdViews[idxTo], + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return it.name === to; }); - } - delete createdViews[idxTo]; - delete deletedViews[idxFrom]; + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } - createdViews = createdViews.filter(Boolean); - deletedViews = deletedViews.filter(Boolean); + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } } - } - result.created = createdViews; - result.deleted = deletedViews; + result.created = createdViews; + result.deleted = deletedViews; - return result; - } catch (e) { - console.error(e); - throw e; - } -}; + return result; + } catch (e) { + console.error(e); + throw e; + } + }; export const diffTestSchemasPush = async ( client: PGlite, @@ -646,12 +603,33 @@ export const diffTestSchemasPush = async ( renamesArr: string[], cli: boolean = false, schemas: string[] = ['public'], + seedStatements: string[] = [], ) => { const { sqlStatements } = await applyPgDiffs(left); for (const st of sqlStatements) { await client.query(st); } + for (const st of seedStatements) { + await client.exec(st); + } + + const materializedViewsForRefresh = Object.values(left).filter((it) => + isPgMaterializedView(it) + ) as PgMaterializedView[]; + + // refresh all mat views + for (const view of materializedViewsForRefresh) { + const viewConf = getMaterializedViewConfig(view); + if (viewConf.isExisting) continue; + + await client.exec( + `REFRESH MATERIALIZED VIEW "${viewConf.schema ?? 'public'}"."${viewConf.name}"${ + viewConf.withNoData ? ' WITH NO DATA;' : ';' + }`, + ); + } + // do introspect into PgSchemaInternal const introspectedSchema = await fromDatabase( { @@ -726,7 +704,36 @@ export const diffTestSchemasPush = async ( validatedCur, 'push', ); - return { sqlStatements, statements }; + + const { + shouldAskForApprove, + statementsToExecute, + columnsToRemove, + tablesToRemove, + tablesToTruncate, + infoToPrint, + schemasToRemove, + matViewsToRemove, + } = await pgSuggestions( + { + query: async (sql: string, params: any[] = []) => { + return (await client.query(sql, params)).rows as T[]; + }, + }, + statements, + ); + + return { + sqlStatements: statementsToExecute, + statements, + shouldAskForApprove, + columnsToRemove, + tablesToRemove, + tablesToTruncate, + infoToPrint, + schemasToRemove, + matViewsToRemove, + }; } else { const { sqlStatements, statements } = await applyPgSnapshotsDiff( sn1, @@ -1308,28 +1315,22 @@ export async function diffTestSchemasPushLibSQL( 'push', ); - const { - statementsToExecute, - columnsToRemove, - infoToPrint, - shouldAskForApprove, - tablesToRemove, - tablesToTruncate, - } = await libSqlLogSuggestionsAndReturn( - { - query: async (sql: string, params?: any[]) => { - const res = await client.execute({ sql, args: params || [] }); - return res.rows as T[]; + const { statementsToExecute, columnsToRemove, infoToPrint, shouldAskForApprove, tablesToRemove, tablesToTruncate } = + await libSqlLogSuggestionsAndReturn( + { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); + }, }, - run: async (query: string) => { - await client.execute(query); - }, - }, - statements, - sn1, - sn2, - _meta!, - ); + statements, + sn1, + sn2, + _meta!, + ); return { sqlStatements: statementsToExecute, @@ -1355,10 +1356,7 @@ export async function diffTestSchemasPushLibSQL( } } -export const applySqliteDiffs = async ( - sn: SqliteSchema, - action?: 'push' | undefined, -) => { +export const applySqliteDiffs = async (sn: SqliteSchema, action?: 'push' | undefined) => { const dryRun = { version: '6', dialect: 'sqlite', @@ -1407,10 +1405,7 @@ export const applySqliteDiffs = async ( return { sqlStatements, statements }; }; -export const applyLibSQLDiffs = async ( - sn: SqliteSchema, - action?: 'push' | undefined, -) => { +export const applyLibSQLDiffs = async (sn: SqliteSchema, action?: 'push' | undefined) => { const dryRun = { version: '6', dialect: 'sqlite', @@ -1636,9 +1631,7 @@ export const introspectPgToFile = async ( fs.writeFileSync(`tests/introspect/postgres/${testName}.ts`, file.file); // generate snapshot from ts file - const response = await prepareFromPgImports([ - `tests/introspect/postgres/${testName}.ts`, - ]); + const response = await prepareFromPgImports([`tests/introspect/postgres/${testName}.ts`]); const afterFileImports = generatePgSnapshot( response.tables, @@ -1662,10 +1655,7 @@ export const introspectPgToFile = async ( const sn2AfterIm = squashPgScheme(sch2); const validatedCurAfterImport = pgSchema.parse(sch2); - const { - sqlStatements: afterFileSqlStatements, - statements: afterFileStatements, - } = await applyPgSnapshotsDiff( + const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyPgSnapshotsDiff( initSn, sn2AfterIm, testSchemasResolver(new Set()), @@ -1726,9 +1716,7 @@ export const introspectMySQLToFile = async ( fs.writeFileSync(`tests/introspect/mysql/${testName}.ts`, file.file); - const response = await prepareFromMySqlImports([ - `tests/introspect/mysql/${testName}.ts`, - ]); + const response = await prepareFromMySqlImports([`tests/introspect/mysql/${testName}.ts`]); const afterFileImports = generateMySqlSnapshot(response.tables, response.views); @@ -1745,10 +1733,7 @@ export const introspectMySQLToFile = async ( const sn2AfterIm = squashMysqlScheme(sch2); const validatedCurAfterImport = mysqlSchema.parse(sch2); - const { - sqlStatements: afterFileSqlStatements, - statements: afterFileStatements, - } = await applyMysqlSnapshotsDiff( + const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyMysqlSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), @@ -1766,11 +1751,7 @@ export const introspectMySQLToFile = async ( }; }; -export const introspectSQLiteToFile = async ( - client: Database, - initSchema: SqliteSchema, - testName: string, -) => { +export const introspectSQLiteToFile = async (client: Database, initSchema: SqliteSchema, testName: string) => { // put in db const { sqlStatements } = await applySqliteDiffs(initSchema); for (const st of sqlStatements) { @@ -1808,9 +1789,7 @@ export const introspectSQLiteToFile = async ( fs.writeFileSync(`tests/introspect/sqlite/${testName}.ts`, file.file); - const response = await prepareFromSqliteImports([ - `tests/introspect/sqlite/${testName}.ts`, - ]); + const response = await prepareFromSqliteImports([`tests/introspect/sqlite/${testName}.ts`]); const afterFileImports = generateSqliteSnapshot(response.tables, response.views); @@ -1827,10 +1806,7 @@ export const introspectSQLiteToFile = async ( const sn2AfterIm = squashSqliteScheme(sch2); const validatedCurAfterImport = sqliteSchema.parse(sch2); - const { - sqlStatements: afterFileSqlStatements, - statements: afterFileStatements, - } = await applySqliteSnapshotsDiff( + const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applySqliteSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), @@ -1848,11 +1824,7 @@ export const introspectSQLiteToFile = async ( }; }; -export const introspectLibSQLToFile = async ( - client: Client, - initSchema: SqliteSchema, - testName: string, -) => { +export const introspectLibSQLToFile = async (client: Client, initSchema: SqliteSchema, testName: string) => { // put in db const { sqlStatements } = await applyLibSQLDiffs(initSchema); for (const st of sqlStatements) { @@ -1890,9 +1862,7 @@ export const introspectLibSQLToFile = async ( fs.writeFileSync(`tests/introspect/libsql/${testName}.ts`, file.file); - const response = await prepareFromSqliteImports([ - `tests/introspect/libsql/${testName}.ts`, - ]); + const response = await prepareFromSqliteImports([`tests/introspect/libsql/${testName}.ts`]); const afterFileImports = generateSqliteSnapshot(response.tables, response.views); @@ -1909,10 +1879,7 @@ export const introspectLibSQLToFile = async ( const sn2AfterIm = squashSqliteScheme(sch2); const validatedCurAfterImport = sqliteSchema.parse(sch2); - const { - sqlStatements: afterFileSqlStatements, - statements: afterFileStatements, - } = await applyLibSQLSnapshotsDiff( + const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyLibSQLSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), From cc2fcc60d6ecadb40a79a02654a11a0ef613bf4d Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 7 Oct 2024 13:50:40 +0300 Subject: [PATCH 215/492] added progress callback to views. changed query columns for materialized views --- drizzle-kit/src/cli/views.ts | 10 +- drizzle-kit/src/serializer/mysqlSerializer.ts | 6 ++ drizzle-kit/src/serializer/pgSerializer.ts | 100 ++++++++++++------ .../src/serializer/sqliteSerializer.ts | 9 ++ 4 files changed, 89 insertions(+), 36 deletions(-) diff --git a/drizzle-kit/src/cli/views.ts b/drizzle-kit/src/cli/views.ts index 6b1ff671e..e1e9ba190 100644 --- a/drizzle-kit/src/cli/views.ts +++ b/drizzle-kit/src/cli/views.ts @@ -330,7 +330,8 @@ export type IntrospectStage = | 'columns' | 'enums' | 'indexes' - | 'fks'; + | 'fks' + | 'views'; type IntrospectState = { [key in IntrospectStage]: { count: number; @@ -369,6 +370,11 @@ export class IntrospectProgress extends TaskView { name: 'foreign keys', status: 'fetching', }, + views: { + count: 0, + name: 'views', + status: 'fetching', + }, }; constructor(private readonly hasEnums: boolean = false) { @@ -422,6 +428,8 @@ export class IntrospectProgress extends TaskView { info += this.hasEnums ? this.statusText(spin, this.state.enums) : ''; info += this.statusText(spin, this.state.indexes); info += this.statusText(spin, this.state.fks); + info += this.statusText(spin, this.state.views); + return info; } } diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 7c95416a8..81c23ee26 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -514,6 +514,7 @@ export const fromDatabase = async ( let tablesCount = new Set(); let indexesCount = 0; let foreignKeysCount = 0; + let viewsCount = 0; const idxs = await db.query( `select * from INFORMATION_SCHEMA.STATISTICS @@ -836,6 +837,10 @@ export const fromDatabase = async ( const resultViews: Record = {}; + viewsCount = views.length; + if (progressCallback) { + progressCallback('views', viewsCount, 'fetching'); + } for await (const view of views) { const viewName = view['TABLE_NAME']; const definition = view['VIEW_DEFINITION']; @@ -865,6 +870,7 @@ export const fromDatabase = async ( progressCallback('indexes', indexesCount, 'done'); // progressCallback("enums", 0, "fetching"); progressCallback('enums', 0, 'done'); + progressCallback('views', viewsCount, 'done'); } return { diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index aff781422..b3b28daae 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -716,6 +716,7 @@ WHERE let indexesCount = 0; let foreignKeysCount = 0; let tableCount = 0; + let viewsCount = 0; const sequencesToReturn: Record = {}; @@ -916,7 +917,7 @@ WHERE } for (const columnResponse of tableResponse) { - const columnName = columnResponse.attname; + const columnName = columnResponse.column_name; const columnAdditionalDT = columnResponse.additional_dt; const columnDimensions = columnResponse.array_dimensions; const enumType: string = columnResponse.enum_name; @@ -1439,6 +1440,8 @@ WHERE }); }); + viewsCount = allViews.length; + for await (const _ of allViews) { } @@ -1446,6 +1449,7 @@ WHERE progressCallback('columns', columnsCount, 'done'); progressCallback('indexes', indexesCount, 'done'); progressCallback('fks', foreignKeysCount, 'done'); + progressCallback('views', viewsCount, 'done'); } const schemasObject = Object.fromEntries([...schemas].map((it) => [it, it])); @@ -1557,39 +1561,65 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str const getColumnsInfoQuery = ({ schema, table, db }: { schema: string; table: string; db: DB }) => { return db.query( - `SELECT a.attrelid::regclass::text, a.attname, is_nullable, a.attndims as array_dimensions - , CASE WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[]) - AND EXISTS ( - SELECT FROM pg_attrdef ad - WHERE ad.adrelid = a.attrelid - AND ad.adnum = a.attnum - AND pg_get_expr(ad.adbin, ad.adrelid) - = 'nextval(''' - || (pg_get_serial_sequence (a.attrelid::regclass::text - , a.attname))::regclass - || '''::regclass)' - ) - THEN CASE a.atttypid - WHEN 'int'::regtype THEN 'serial' - WHEN 'int8'::regtype THEN 'bigserial' - WHEN 'int2'::regtype THEN 'smallserial' - END - ELSE format_type(a.atttypid, a.atttypmod) - END AS data_type, INFORMATION_SCHEMA.COLUMNS.table_name, ns.nspname as type_schema, - pg_get_serial_sequence('"${schema}"."${table}"', a.attname)::regclass as seq_name, INFORMATION_SCHEMA.COLUMNS.column_name, - INFORMATION_SCHEMA.COLUMNS.column_default, INFORMATION_SCHEMA.COLUMNS.data_type as additional_dt, - INFORMATION_SCHEMA.COLUMNS.udt_name as enum_name, - INFORMATION_SCHEMA.COLUMNS.is_generated, generation_expression, - INFORMATION_SCHEMA.COLUMNS.is_identity,INFORMATION_SCHEMA.COLUMNS.identity_generation, - INFORMATION_SCHEMA.COLUMNS.identity_start, INFORMATION_SCHEMA.COLUMNS.identity_increment, - INFORMATION_SCHEMA.COLUMNS.identity_maximum, INFORMATION_SCHEMA.COLUMNS.identity_minimum, - INFORMATION_SCHEMA.COLUMNS.identity_cycle -FROM pg_attribute a -JOIN INFORMATION_SCHEMA.COLUMNS ON INFORMATION_SCHEMA.COLUMNS.column_name = a.attname -JOIN pg_type t ON t.oid = a.atttypid LEFT JOIN pg_namespace ns ON ns.oid = t.typnamespace -WHERE a.attrelid = '"${schema}"."${table}"'::regclass and INFORMATION_SCHEMA.COLUMNS.table_name = '${table}' and INFORMATION_SCHEMA.COLUMNS.table_schema = '${schema}' -AND a.attnum > 0 -AND NOT a.attisdropped -ORDER BY a.attnum;`, + `SELECT + a.attrelid::regclass::text AS table_name, -- Table, view, or materialized view name + a.attname AS column_name, -- Column name + CASE + WHEN NOT a.attisdropped THEN + CASE + WHEN a.attnotnull THEN 'NO' + ELSE 'YES' + END + ELSE NULL + END AS is_nullable, -- NULL or NOT NULL constraint + a.attndims AS array_dimensions, -- Array dimensions + CASE + WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[]) + AND EXISTS ( + SELECT FROM pg_attrdef ad + WHERE ad.adrelid = a.attrelid + AND ad.adnum = a.attnum + AND pg_get_expr(ad.adbin, ad.adrelid) = 'nextval(''' + || pg_get_serial_sequence(a.attrelid::regclass::text, a.attname)::regclass || '''::regclass)' + ) + THEN CASE a.atttypid + WHEN 'int'::regtype THEN 'serial' + WHEN 'int8'::regtype THEN 'bigserial' + WHEN 'int2'::regtype THEN 'smallserial' + END + ELSE format_type(a.atttypid, a.atttypmod) + END AS data_type, -- Column data type + ns.nspname AS type_schema, -- Schema name + pg_get_serial_sequence('"${schema}"."${table}"', a.attname)::regclass AS seq_name, -- Serial sequence (if any) + c.column_default, -- Column default value + c.data_type AS additional_data_type, -- Data type from information_schema + c.udt_name AS enum_name, -- Enum type (if applicable) + c.is_generated, -- Is it a generated column? + c.generation_expression, -- Generation expression (if generated) + c.is_identity, -- Is it an identity column? + c.identity_generation, -- Identity generation strategy (ALWAYS or BY DEFAULT) + c.identity_start, -- Start value of identity column + c.identity_increment, -- Increment for identity column + c.identity_maximum, -- Maximum value for identity column + c.identity_minimum, -- Minimum value for identity column + c.identity_cycle -- Does the identity column cycle? +FROM + pg_attribute a +JOIN + pg_class cls ON cls.oid = a.attrelid -- Join pg_class to get table/view/materialized view info +JOIN + pg_namespace ns ON ns.oid = cls.relnamespace -- Join namespace to get schema info +LEFT JOIN + information_schema.columns c ON c.column_name = a.attname + AND c.table_schema = ns.nspname + AND c.table_name = cls.relname -- Match schema and table/view name +WHERE + a.attnum > 0 -- Valid column numbers only + AND NOT a.attisdropped -- Skip dropped columns + AND cls.relkind IN ('r', 'v', 'm') -- Include regular tables ('r'), views ('v'), and materialized views ('m') + AND ns.nspname = '${schema}' -- Filter by schema + AND cls.relname = '${table}' -- Filter by table name +ORDER BY + a.attnum; -- Order by column number`, ); }; diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index ea443f372..03f5587a4 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -492,6 +492,7 @@ export const fromDatabase = async ( let tablesCount = new Set(); let indexesCount = 0; let foreignKeysCount = 0; + let viewsCount = 0; // append primaryKeys by table const tableToPk: { [tname: string]: string[] } = {}; @@ -760,6 +761,11 @@ WHERE `SELECT name AS view_name, sql AS sql FROM sqlite_master WHERE type = 'view';`, ); + viewsCount = views.length; + + if (progressCallback) { + progressCallback('views', viewsCount, 'fetching'); + } for (const view of views) { const viewName = view['view_name']; const sql = view['sql']; @@ -784,6 +790,9 @@ WHERE definition: viewDefinition, }; } + if (progressCallback) { + progressCallback('views', viewsCount, 'done'); + } return { version: '6', From 746aeed8242275abdccf53fd795d7cd4af5a0239 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 7 Oct 2024 16:07:52 +0300 Subject: [PATCH 216/492] Add Xata workaround for identity columns --- drizzle-kit/package.json | 2 +- drizzle-kit/src/serializer/pgSerializer.ts | 2 +- pnpm-lock.yaml | 155 ++++++++++----------- 3 files changed, 76 insertions(+), 83 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 66f19e6be..cf771296a 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -80,7 +80,7 @@ "commander": "^12.1.0", "dockerode": "^3.3.4", "dotenv": "^16.0.3", - "drizzle-kit": "0.21.2", + "drizzle-kit": "0.25.0-b1faa33", "drizzle-orm": "workspace:./drizzle-orm/dist", "env-paths": "^3.0.0", "esbuild-node-externals": "^1.9.0", diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 957727dc1..cc7b18725 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -1064,7 +1064,7 @@ export const fromDatabase = async ( : undefined, }; - if (identityName) { + if (identityName && typeof identityName === 'string') { // remove "" from sequence name delete sequencesToReturn[ `${tableSchema}.${ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 961f667f8..f5d886131 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -201,8 +201,8 @@ importers: specifier: ^16.0.3 version: 16.4.5 drizzle-kit: - specifier: 0.21.2 - version: 0.21.2 + specifier: 0.25.0-b1faa33 + version: 0.25.0-b1faa33 drizzle-orm: specifier: workspace:./drizzle-orm/dist version: link:drizzle-orm/dist @@ -316,7 +316,7 @@ importers: version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -364,7 +364,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -5422,8 +5422,8 @@ packages: resolution: {integrity: sha512-Rba5VW1O2JfJlwVBeZ8Zwt2E2us5oZ08PQBDiVSGlug53TOc8hzXjblZFuF+dnll9/RQEHrkzBmJFgqTvn5Rxg==} hasBin: true - drizzle-kit@0.21.2: - resolution: {integrity: sha512-U87IhZyCt/9d0ZT/Na3KFJVY31tSxtTx/n9UMcWFpW/5c2Ede39xiCG5efNV/0iimsv97UIRtDI0ldLBW5lbcg==} + drizzle-kit@0.25.0-b1faa33: + resolution: {integrity: sha512-WMRuEgxt1oTc62EPVQhGD+pGs6LiqzT8UqxuI6mKfA5SCeCEIt87nFzzJ5WlwsqbuoSgXBXc5zhsHvqXRD03DA==} hasBin: true drizzle-orm@0.27.2: @@ -10207,8 +10207,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10294,11 +10294,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0': + '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10337,6 +10337,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.478.0': @@ -10603,11 +10604,11 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/client-sts@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10646,7 +10647,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/core@3.477.0': @@ -10801,7 +10801,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -11008,7 +11008,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -11209,7 +11209,7 @@ snapshots: '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11218,7 +11218,7 @@ snapshots: '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -12890,7 +12890,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -12908,7 +12908,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13482,10 +13482,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) '@opentelemetry/api@1.8.0': {} @@ -13622,7 +13622,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13632,7 +13632,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -13659,14 +13659,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13755,16 +13755,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13779,7 +13779,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13793,7 +13793,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -13816,12 +13816,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) optionalDependencies: '@types/react': 18.3.1 @@ -15097,7 +15097,7 @@ snapshots: pathe: 1.1.2 picocolors: 1.0.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) '@vitest/utils@1.6.0': dependencies: @@ -16272,17 +16272,12 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-kit@0.21.2: + drizzle-kit@0.25.0-b1faa33: dependencies: + '@drizzle-team/brocli': 0.10.1 '@esbuild-kit/esm-loader': 2.5.5 - commander: 9.5.0 - env-paths: 3.0.0 esbuild: 0.19.12 esbuild-register: 3.5.0(esbuild@0.19.12) - glob: 8.1.0 - hanji: 0.0.5 - json-diff: 0.9.0 - zod: 3.23.7 transitivePeerDependencies: - supports-color @@ -17127,35 +17122,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) expo-modules-autolinking@1.11.1: dependencies: @@ -17169,24 +17164,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -18662,12 +18657,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18743,13 +18738,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18763,7 +18758,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -18789,7 +18784,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -18797,7 +18792,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -18806,7 +18801,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -19692,10 +19687,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + react-devtools-core@5.2.0(bufferutil@4.0.8): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19708,19 +19703,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19739,14 +19734,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + react-devtools-core: 5.2.0(bufferutil@4.0.8) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -21599,17 +21594,15 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@6.2.2(bufferutil@4.0.8): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@7.5.9(bufferutil@4.0.8): optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From e2f1b5a4618cc97f118316238f6bf8c818115555 Mon Sep 17 00:00:00 2001 From: w3cj Date: Mon, 7 Oct 2024 11:20:43 -0600 Subject: [PATCH 217/492] fix: add import extensions to async imports --- drizzle-orm/src/monodriver.ts | 28 ++++++++++++++-------------- drizzle-orm/src/monomigrator.ts | 28 ++++++++++++++-------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts index 7acdb5806..9af80db06 100644 --- a/drizzle-orm/src/monodriver.ts +++ b/drizzle-orm/src/monodriver.ts @@ -308,7 +308,7 @@ export async function drizzle< switch (client) { case 'node-postgres': { const defpg = await import('pg').catch(() => importError('pg')); - const { drizzle } = await import('./node-postgres'); + const { drizzle } = await import('./node-postgres/index.ts'); if (typeof params[0] === 'object') { const { connection, ...drizzleConfig } = params[0] as @@ -343,7 +343,7 @@ export async function drizzle< const { RDSDataClient } = await import('@aws-sdk/client-rds-data').catch(() => importError('@aws-sdk/client-rds-data') ); - const { drizzle } = await import('./aws-data-api/pg'); + const { drizzle } = await import('./aws-data-api/pg/index.ts'); const instance = new RDSDataClient(rdsConfig); const db = drizzle(instance, { resourceArn, database, secretArn, ...drizzleConfig }); @@ -352,7 +352,7 @@ export async function drizzle< } case 'better-sqlite3': { const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); - const { drizzle } = await import('./better-sqlite3'); + const { drizzle } = await import('./better-sqlite3/index.ts'); if (typeof params[0] === 'object') { const { connection, ...drizzleConfig } = params[0] as { @@ -383,7 +383,7 @@ export async function drizzle< const { Database: Client } = await import('bun:sqlite').catch(() => { throw new Error(`Please use bun to use 'bun:sqlite' for Drizzle ORM to connect to database`); }); - const { drizzle } = await import('./bun-sqlite'); + const { drizzle } = await import('./bun-sqlite/index.ts'); if (typeof params[0] === 'object') { const { connection, ...drizzleConfig } = params[0] as { @@ -415,7 +415,7 @@ export async function drizzle< case 'd1': { const { connection, ...drizzleConfig } = params[0] as { connection: AnyD1Database } & DrizzleConfig; - const { drizzle } = await import('./d1'); + const { drizzle } = await import('./d1/index.ts'); const db = drizzle(connection, drizzleConfig); @@ -424,7 +424,7 @@ export async function drizzle< case 'libsql': case 'turso': { const { createClient } = await import('@libsql/client').catch(() => importError('@libsql/client')); - const { drizzle } = await import('./libsql'); + const { drizzle } = await import('./libsql/index.ts'); if (typeof params[0] === 'string') { const instance = createClient({ @@ -444,7 +444,7 @@ export async function drizzle< } case 'mysql2': { const { createPool } = await import('mysql2/promise').catch(() => importError('mysql2')); - const { drizzle } = await import('./mysql2'); + const { drizzle } = await import('./mysql2/index.ts'); if (typeof params[0] === 'object') { const { connection, ...drizzleConfig } = params[0] as @@ -466,7 +466,7 @@ export async function drizzle< } case 'neon-http': { const { neon } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); - const { drizzle } = await import('./neon-http'); + const { drizzle } = await import('./neon-http/index.ts'); if (typeof params[0] === 'object') { const { connection, ...drizzleConfig } = params[0] as { connection: MonodriverNeonHttpConfig } & DrizzleConfig; @@ -495,7 +495,7 @@ export async function drizzle< const { Pool, neonConfig } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless') ); - const { drizzle } = await import('./neon-serverless'); + const { drizzle } = await import('./neon-serverless/index.ts'); if (typeof params[0] === 'string') { const instance = new Pool({ connectionString: params[0], @@ -534,7 +534,7 @@ export async function drizzle< } case 'planetscale': { const { Client } = await import('@planetscale/database').catch(() => importError('@planetscale/database')); - const { drizzle } = await import('./planetscale-serverless'); + const { drizzle } = await import('./planetscale-serverless/index.ts'); if (typeof params[0] === 'object') { const { connection, ...drizzleConfig } = params[0] as @@ -561,7 +561,7 @@ export async function drizzle< } case 'postgres-js': { const { default: client } = await import('postgres').catch(() => importError('postgres')); - const { drizzle } = await import('./postgres-js'); + const { drizzle } = await import('./postgres-js/index.ts'); if (typeof params[0] === 'object') { const { connection, ...drizzleConfig } = params[0] as { @@ -590,7 +590,7 @@ export async function drizzle< } case 'tidb-serverless': { const { connect } = await import('@tidbcloud/serverless').catch(() => importError('@tidbcloud/serverless')); - const { drizzle } = await import('./tidb-serverless'); + const { drizzle } = await import('./tidb-serverless/index.ts'); if (typeof params[0] === 'string') { const instance = connect({ @@ -617,7 +617,7 @@ export async function drizzle< case 'vercel-postgres': { const drizzleConfig = params[0] as DrizzleConfig | undefined; const { sql } = await import('@vercel/postgres').catch(() => importError('@vercel/postgres')); - const { drizzle } = await import('./vercel-postgres'); + const { drizzle } = await import('./vercel-postgres/index.ts'); const db = drizzle(sql, drizzleConfig); @@ -626,7 +626,7 @@ export async function drizzle< case 'pglite': { const { PGlite } = await import('@electric-sql/pglite').catch(() => importError('@electric-sql/pglite')); - const { drizzle } = await import('./pglite'); + const { drizzle } = await import('./pglite/index.ts'); if (typeof params[0] === 'object') { const { connection, ...drizzleConfig } = params[0] as { diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts index 1736e415e..9f4a748e0 100644 --- a/drizzle-orm/src/monomigrator.ts +++ b/drizzle-orm/src/monomigrator.ts @@ -36,72 +36,72 @@ export async function migrate( ) { switch (( db).constructor[entityKind]) { case 'AwsDataApiPgDatabase': { - const { migrate } = await import('./aws-data-api/pg/migrator'); + const { migrate } = await import('./aws-data-api/pg/migrator.ts'); return migrate(db as AwsDataApiPgDatabase, config as MigrationConfig); } case 'BetterSQLite3Database': { - const { migrate } = await import('./better-sqlite3/migrator'); + const { migrate } = await import('./better-sqlite3/migrator.ts'); return migrate(db as BetterSQLite3Database, config as MigrationConfig); } case 'BunSQLiteDatabase': { - const { migrate } = await import('./bun-sqlite/migrator'); + const { migrate } = await import('./bun-sqlite/migrator.ts'); return migrate(db as BunSQLiteDatabase, config as MigrationConfig); } case 'D1Database': { - const { migrate } = await import('./d1/migrator'); + const { migrate } = await import('./d1/migrator.ts'); return migrate(db as DrizzleD1Database, config as MigrationConfig); } case 'LibSQLDatabase': { - const { migrate } = await import('./libsql/migrator'); + const { migrate } = await import('./libsql/migrator.ts'); return migrate(db as LibSQLDatabase, config as MigrationConfig); } case 'MySql2Database': { - const { migrate } = await import('./mysql2/migrator'); + const { migrate } = await import('./mysql2/migrator.ts'); return migrate(db as MySql2Database, config as MigrationConfig); } case 'NeonHttpDatabase': { - const { migrate } = await import('./neon-http/migrator'); + const { migrate } = await import('./neon-http/migrator.ts'); return migrate(db as NeonHttpDatabase, config as MigrationConfig); } case 'NeonServerlessDatabase': { - const { migrate } = await import('./neon-serverless/migrator'); + const { migrate } = await import('./neon-serverless/migrator.ts'); return migrate(db as NeonDatabase, config as MigrationConfig); } case 'NodePgDatabase': { - const { migrate } = await import('./node-postgres/migrator'); + const { migrate } = await import('./node-postgres/migrator.ts'); return migrate(db as NodePgDatabase, config as MigrationConfig); } case 'PlanetScaleDatabase': { - const { migrate } = await import('./planetscale-serverless/migrator'); + const { migrate } = await import('./planetscale-serverless/migrator.ts'); return migrate(db as PlanetScaleDatabase, config as MigrationConfig); } case 'PostgresJsDatabase': { - const { migrate } = await import('./postgres-js/migrator'); + const { migrate } = await import('./postgres-js/migrator.ts'); return migrate(db as PostgresJsDatabase, config as MigrationConfig); } case 'TiDBServerlessDatabase': { - const { migrate } = await import('./tidb-serverless/migrator'); + const { migrate } = await import('./tidb-serverless/migrator.ts'); return migrate(db as TiDBServerlessDatabase, config as MigrationConfig); } case 'VercelPgDatabase': { - const { migrate } = await import('./vercel-postgres/migrator'); + const { migrate } = await import('./vercel-postgres/migrator.ts'); return migrate(db as VercelPgDatabase, config as MigrationConfig); } case 'PgliteDatabase': { - const { migrate } = await import('./pglite/migrator'); + const { migrate } = await import('./pglite/migrator.ts'); return migrate(db as PgliteDatabase, config as MigrationConfig); } From decb0c1d81a638d624e00af576be9fc89d30b7d7 Mon Sep 17 00:00:00 2001 From: Alex Blokh Date: Mon, 7 Oct 2024 21:50:48 +0300 Subject: [PATCH 218/492] fix fix-imports.ts --- drizzle-orm/scripts/fix-imports.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drizzle-orm/scripts/fix-imports.ts b/drizzle-orm/scripts/fix-imports.ts index f2035eeda..6fc63a48f 100755 --- a/drizzle-orm/scripts/fix-imports.ts +++ b/drizzle-orm/scripts/fix-imports.ts @@ -54,6 +54,12 @@ await Promise.all(cjsFiles.map(async (file) => { path.value.argument.value = resolvePathAlias(path.value.argument.value, file); this.traverse(path); }, + visitAwaitExpression(path) { + if (print(path.value).code.startsWith(`await import("./`)) { + path.value.argument.arguments[0].value = fixImportPath(path.value.argument.arguments[0].value, file, '.cjs'); + } + this.traverse(path); + }, }); await fs.writeFile(file, print(code).code); @@ -83,6 +89,12 @@ await Promise.all(esmFiles.map(async (file) => { path.value.argument.value = fixImportPath(path.value.argument.value, file, '.js'); this.traverse(path); }, + visitAwaitExpression(path) { + if (print(path.value).code.startsWith(`await import("./`)) { + path.value.argument.arguments[0].value = fixImportPath(path.value.argument.arguments[0].value, file, '.js'); + } + this.traverse(path); + }, }); await fs.writeFile(file, print(code).code); From 6974798737a2710a6dc6d37d772442d2c895c987 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 7 Oct 2024 22:08:02 +0300 Subject: [PATCH 219/492] bump to 0.34.1 --- changelogs/drizzle-orm/0.34.1.md | 1 + drizzle-orm/package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelogs/drizzle-orm/0.34.1.md diff --git a/changelogs/drizzle-orm/0.34.1.md b/changelogs/drizzle-orm/0.34.1.md new file mode 100644 index 000000000..e314b5fd2 --- /dev/null +++ b/changelogs/drizzle-orm/0.34.1.md @@ -0,0 +1 @@ +- Fixed dynamic imports for CJS and MJS in the `/connect` module \ No newline at end of file diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index b4952f2c4..829441886 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.34.0", + "version": "0.34.1", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { From aa44a9b015a4408cbcb3a4c20b289f50d4d89c78 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Tue, 8 Oct 2024 10:57:19 +0300 Subject: [PATCH 220/492] updated pg introspect columns query. updated mysql test. --- drizzle-kit/src/serializer/pgSerializer.ts | 13 +++++++++---- drizzle-kit/tests/introspect/mysql.test.ts | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index b3b28daae..200a5f3cf 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -1472,7 +1472,7 @@ WHERE }; const defaultForColumn = (column: any, internals: PgKitInternals, tableName: string) => { - const columnName = column.attname; + const columnName = column.column_name; const isArray = internals?.tables[tableName]?.columns[columnName]?.isArray ?? false; if (column.column_default === null) { @@ -1589,10 +1589,10 @@ const getColumnsInfoQuery = ({ schema, table, db }: { schema: string; table: str END ELSE format_type(a.atttypid, a.atttypmod) END AS data_type, -- Column data type - ns.nspname AS type_schema, -- Schema name +-- ns.nspname AS type_schema, -- Schema name pg_get_serial_sequence('"${schema}"."${table}"', a.attname)::regclass AS seq_name, -- Serial sequence (if any) c.column_default, -- Column default value - c.data_type AS additional_data_type, -- Data type from information_schema + c.data_type AS additional_dt, -- Data type from information_schema c.udt_name AS enum_name, -- Enum type (if applicable) c.is_generated, -- Is it a generated column? c.generation_expression, -- Generation expression (if generated) @@ -1602,7 +1602,8 @@ const getColumnsInfoQuery = ({ schema, table, db }: { schema: string; table: str c.identity_increment, -- Increment for identity column c.identity_maximum, -- Maximum value for identity column c.identity_minimum, -- Minimum value for identity column - c.identity_cycle -- Does the identity column cycle? + c.identity_cycle, -- Does the identity column cycle? + enum_ns.nspname AS type_schema -- Schema of the enum type FROM pg_attribute a JOIN @@ -1613,6 +1614,10 @@ LEFT JOIN information_schema.columns c ON c.column_name = a.attname AND c.table_schema = ns.nspname AND c.table_name = cls.relname -- Match schema and table/view name +LEFT JOIN + pg_type enum_t ON enum_t.oid = a.atttypid -- Join to get the type info +LEFT JOIN + pg_namespace enum_ns ON enum_ns.oid = enum_t.typnamespace -- Join to get the enum schema WHERE a.attnum > 0 -- Valid column numbers only AND NOT a.attisdropped -- Skip dropped columns diff --git a/drizzle-kit/tests/introspect/mysql.test.ts b/drizzle-kit/tests/introspect/mysql.test.ts index d4203967a..6b96f7324 100644 --- a/drizzle-kit/tests/introspect/mysql.test.ts +++ b/drizzle-kit/tests/introspect/mysql.test.ts @@ -192,6 +192,8 @@ test('view #1', async () => { }); test('view #2', async () => { + await client.query(`drop view some_view;`); + const users = mysqlTable('some_users', { id: int('id') }); const testView = mysqlView('some_view', { id: int('id') }).algorithm('temptable').sqlSecurity('definer').as( sql`SELECT * FROM ${users}`, @@ -212,6 +214,5 @@ test('view #2', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - await client.query(`drop view some_view;`); await client.query(`drop table some_users;`); }); From e2eb2900669b4ad8746457d2fa81f8ad67a737fd Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Tue, 8 Oct 2024 14:48:39 +0300 Subject: [PATCH 221/492] Updated enum handling for generate. Adde drop, add value, rename, set schema. Updated tests --- drizzle-kit/src/jsonStatements.ts | 42 ++++++- drizzle-kit/src/snapshotsDiffer.ts | 33 ++--- drizzle-kit/src/sqlgenerator.ts | 121 ++++++++++++++++--- drizzle-kit/tests/pg-enums.test.ts | 186 ++++++++++++++++++++++++++--- 4 files changed, 321 insertions(+), 61 deletions(-) diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 47cb08908..a3df984a2 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -106,6 +106,15 @@ export interface JsonAddValueToEnumStatement { before: string; } +export interface JsonDropValueFromEnumStatement { + type: 'alter_type_drop_value'; + name: string; + schema: string; + deletedValues: string[]; + newValues: string[]; + columnsWithEnum: { schema: string; table: string; column: string }[]; +} + export interface JsonCreateSequenceStatement { type: 'create_sequence'; name: string; @@ -582,7 +591,8 @@ export type JsonStatement = | JsonDropSequenceStatement | JsonCreateSequenceStatement | JsonMoveSequenceStatement - | JsonRenameSequenceStatement; + | JsonRenameSequenceStatement + | JsonDropValueFromEnumStatement; export const preparePgCreateTableJson = ( table: Table, @@ -717,6 +727,36 @@ export const prepareAddValuesToEnumJson = ( }); }; +export const prepareDropEnumValues = ( + name: string, + schema: string, + removedValues: string[], + json2: PgSchema, +): JsonDropValueFromEnumStatement[] => { + if (!removedValues.length) return []; + + const affectedColumns: { schema: string; table: string; column: string }[] = []; + + for (const tableKey in json2.tables) { + const table = json2.tables[tableKey]; + for (const columnKey in table.columns) { + const column = table.columns[columnKey]; + if (column.type === name && column.typeSchema === schema) { + affectedColumns.push({ schema: table.schema || 'public', table: table.name, column: column.name }); + } + } + } + + return [{ + type: 'alter_type_drop_value', + name: name, + schema: schema, + deletedValues: removedValues, + newValues: json2.enums[`${schema}.${name}`].values, + columnsWithEnum: affectedColumns, + }]; +}; + export const prepareDropEnumJson = ( name: string, schema: string, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 64ea8e465..dee245071 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -56,6 +56,7 @@ import { prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDeleteUniqueConstraintPg as prepareDeleteUniqueConstraint, prepareDropEnumJson, + prepareDropEnumValues, prepareDropIndexesJson, prepareDropReferencesJson, prepareDropSequenceJson, @@ -1002,30 +1003,6 @@ export const applyPgSnapshotsDiff = async ( // - create table with generated // - alter - should be not triggered, but should get warning - // TODO: - // let hasEnumValuesDeletions = false; - // let enumValuesDeletions: { name: string; schema: string; values: string[] }[] = - // []; - // for (let alteredEnum of typedResult.alteredEnums) { - // if (alteredEnum.deletedValues.length > 0) { - // hasEnumValuesDeletions = true; - // enumValuesDeletions.push({ - // name: alteredEnum.name, - // schema: alteredEnum.schema, - // values: alteredEnum.deletedValues, - // }); - // } - // } - // if (hasEnumValuesDeletions) { - // console.log(error("Deletion of enum values is prohibited in Postgres - see here")); - // for(let entry of enumValuesDeletions){ - // console.log(error(`You're trying to delete ${chalk.blue(`[${entry.values.join(", ")}]`)} values from ${chalk.blue(`${entry.schema}.${entry.name}`)}`)) - // } - // } - // if (hasEnumValuesDeletions && action === "push") { - // process.exit(1); - // } - const createEnums = createdEnums.map((it) => { return prepareCreateEnumJson(it.name, it.schema, it.values); }) ?? []; @@ -1042,14 +1019,17 @@ export const applyPgSnapshotsDiff = async ( return prepareRenameEnumJson(it.from.name, it.to.name, it.to.schema); }); - // todo: block enum rename, enum value rename and enun deletion for now const jsonAlterEnumsWithAddedValues = typedResult.alteredEnums .map((it) => { return prepareAddValuesToEnumJson(it.name, it.schema, it.addedValues); }) .flat() ?? []; - /////////// + const jsonAlterEnumsWithDroppedValues = typedResult.alteredEnums + .map((it) => { + return prepareDropEnumValues(it.name, it.schema, it.deletedValues, curFull); + }) + .flat() ?? []; const createSequences = createdSequences.map((it) => { return prepareCreateSequenceJson(it); @@ -1135,6 +1115,7 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...jsonAddedUniqueConstraints); jsonStatements.push(...jsonAlteredUniqueConstraints); + jsonStatements.push(...jsonAlterEnumsWithDroppedValues); jsonStatements.push(...dropEnums); jsonStatements.push(...dropSequences); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 374b30581..9adfd1b16 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -38,13 +38,17 @@ import { JsonDeleteReferenceStatement, JsonDeleteUniqueConstraint, JsonDropColumnStatement, + JsonDropEnumStatement, JsonDropIndexStatement, JsonDropSequenceStatement, JsonDropTableStatement, + JsonDropValueFromEnumStatement, + JsonMoveEnumStatement, JsonMoveSequenceStatement, JsonPgCreateIndexStatement, JsonRecreateTableStatement, JsonRenameColumnStatement, + JsonRenameEnumStatement, JsonRenameSchema, JsonRenameSequenceStatement, JsonRenameTableStatement, @@ -694,22 +698,39 @@ class CreateTypeEnumConvertor extends Convertor { convert(st: JsonCreateEnumStatement) { const { name, values, schema } = st; - const tableNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; + const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; let valuesStatement = '('; valuesStatement += values.map((it) => `'${it}'`).join(', '); valuesStatement += ')'; - let statement = 'DO $$ BEGIN'; - statement += '\n'; - statement += ` CREATE TYPE ${tableNameWithSchema} AS ENUM${valuesStatement};`; - statement += '\n'; - statement += 'EXCEPTION'; - statement += '\n'; - statement += ' WHEN duplicate_object THEN null;'; - statement += '\n'; - statement += 'END $$;'; - statement += '\n'; + // TODO do we need this? + // let statement = 'DO $$ BEGIN'; + // statement += '\n'; + let statement = `CREATE TYPE ${enumNameWithSchema} AS ENUM${valuesStatement};`; + // statement += '\n'; + // statement += 'EXCEPTION'; + // statement += '\n'; + // statement += ' WHEN duplicate_object THEN null;'; + // statement += '\n'; + // statement += 'END $$;'; + // statement += '\n'; + return statement; + } +} + +class DropTypeEnumConvertor extends Convertor { + can(statement: JsonStatement): boolean { + return statement.type === 'drop_type_enum'; + } + + convert(st: JsonDropEnumStatement) { + const { name, schema } = st; + + const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; + + let statement = `DROP TYPE ${enumNameWithSchema};`; + return statement; } } @@ -720,9 +741,74 @@ class AlterTypeAddValueConvertor extends Convertor { } convert(st: JsonAddValueToEnumStatement) { - const { name, schema, value } = st; - const schemaPrefix = schema && schema !== 'public' ? `"${schema}".` : ''; - return `ALTER TYPE ${schemaPrefix}"${name}" ADD VALUE '${value}';`; + const { name, schema, value, before } = st; + + const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; + + return `ALTER TYPE ${enumNameWithSchema} ADD VALUE '${value}'${before.length ? ` BEFORE '${before}'` : ''};`; + } +} + +class AlterTypeSetSchemaConvertor extends Convertor { + can(statement: JsonStatement): boolean { + return statement.type === 'move_type_enum'; + } + + convert(st: JsonMoveEnumStatement) { + const { name, schemaFrom, schemaTo } = st; + + const enumNameWithSchema = schemaFrom ? `"${schemaFrom}"."${name}"` : `"${name}"`; + + return `ALTER TYPE ${enumNameWithSchema} SET SCHEMA "${schemaTo}";`; + } +} + +class AlterRenameTypeConvertor extends Convertor { + can(statement: JsonStatement): boolean { + return statement.type === 'rename_type_enum'; + } + + convert(st: JsonRenameEnumStatement) { + const { nameTo, nameFrom, schema } = st; + + const enumNameWithSchema = schema ? `"${schema}"."${nameFrom}"` : `"${nameFrom}"`; + + return `ALTER TYPE ${enumNameWithSchema} RENAME TO "${nameTo}";`; + } +} + +class AlterTypeDropValueConvertor extends Convertor { + can(statement: JsonStatement): boolean { + return statement.type === 'alter_type_drop_value'; + } + + convert(st: JsonDropValueFromEnumStatement) { + const { columnsWithEnum, name, newValues, schema } = st; + + const statements: string[] = []; + + for (const withEnum of columnsWithEnum) { + statements.push( + `ALTER TABLE "${withEnum.schema}"."${withEnum.table}" ALTER COLUMN "${withEnum.column}" SET DATA TYPE text;`, + ); + } + + statements.push(new DropTypeEnumConvertor().convert({ name: name, schema, type: 'drop_type_enum' })); + + statements.push(new CreateTypeEnumConvertor().convert({ + name: name, + schema: schema, + values: newValues, + type: 'create_type_enum', + })); + + for (const withEnum of columnsWithEnum) { + statements.push( + `ALTER TABLE "${withEnum.schema}"."${withEnum.table}" ALTER COLUMN "${withEnum.column}" SET DATA TYPE "${schema}"."${name}" USING "${withEnum.column}"::"${schema}"."${name}";`, + ); + } + + return statements; } } @@ -2487,6 +2573,11 @@ convertors.push(new SQLiteRecreateTableConvertor()); convertors.push(new LibSQLRecreateTableConvertor()); convertors.push(new CreateTypeEnumConvertor()); +convertors.push(new DropTypeEnumConvertor()); +convertors.push(new AlterTypeAddValueConvertor()); +convertors.push(new AlterTypeSetSchemaConvertor()); +convertors.push(new AlterRenameTypeConvertor()); +convertors.push(new AlterTypeDropValueConvertor()); convertors.push(new CreatePgSequenceConvertor()); convertors.push(new DropPgSequenceConvertor()); @@ -2530,8 +2621,6 @@ convertors.push(new PgDropIndexConvertor()); convertors.push(new SqliteDropIndexConvertor()); convertors.push(new MySqlDropIndexConvertor()); -convertors.push(new AlterTypeAddValueConvertor()); - convertors.push(new PgAlterTableAlterColumnSetPrimaryKeyConvertor()); convertors.push(new PgAlterTableAlterColumnDropPrimaryKeyConvertor()); convertors.push(new PgAlterTableAlterColumnSetNotNullConvertor()); diff --git a/drizzle-kit/tests/pg-enums.test.ts b/drizzle-kit/tests/pg-enums.test.ts index cd8877a43..e436092d7 100644 --- a/drizzle-kit/tests/pg-enums.test.ts +++ b/drizzle-kit/tests/pg-enums.test.ts @@ -7,8 +7,10 @@ test('enums #1', async () => { enum: pgEnum('enum', ['value']), }; - const { statements } = await diffTestSchemas({}, to, []); + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value');`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ name: 'enum', @@ -24,8 +26,10 @@ test('enums #2', async () => { enum: folder.enum('enum', ['value']), }; - const { statements } = await diffTestSchemas({}, to, []); + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TYPE "folder"."enum" AS ENUM('value');`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ name: 'enum', @@ -40,8 +44,10 @@ test('enums #3', async () => { enum: pgEnum('enum', ['value']), }; - const { statements } = await diffTestSchemas(from, {}, []); + const { statements, sqlStatements } = await diffTestSchemas(from, {}, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'drop_type_enum', @@ -57,8 +63,10 @@ test('enums #4', async () => { enum: folder.enum('enum', ['value']), }; - const { statements } = await diffTestSchemas(from, {}, []); + const { statements, sqlStatements } = await diffTestSchemas(from, {}, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP TYPE "folder"."enum";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'drop_type_enum', @@ -81,8 +89,10 @@ test('enums #5', async () => { enum: folder2.enum('enum', ['value']), }; - const { statements } = await diffTestSchemas(from, to, ['folder1->folder2']); + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['folder1->folder2']); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER SCHEMA "folder1" RENAME TO "folder2";\n`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'rename_schema', @@ -107,10 +117,12 @@ test('enums #6', async () => { enum: folder2.enum('enum', ['value']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'folder1.enum->folder2.enum', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "folder1"."enum" SET SCHEMA "folder2";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -129,8 +141,10 @@ test('enums #7', async () => { enum: pgEnum('enum', ['value1', 'value2']), }; - const { statements } = await diffTestSchemas(from, to, []); + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum" ADD VALUE 'value2';`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'alter_type_add_value', @@ -150,8 +164,11 @@ test('enums #8', async () => { enum: pgEnum('enum', ['value1', 'value2', 'value3']), }; - const { statements } = await diffTestSchemas(from, to, []); + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum" ADD VALUE 'value2';`); + expect(sqlStatements[1]).toBe(`ALTER TYPE "public"."enum" ADD VALUE 'value3';`); expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ type: 'alter_type_add_value', @@ -179,8 +196,10 @@ test('enums #9', async () => { enum: pgEnum('enum', ['value1', 'value2', 'value3']), }; - const { statements } = await diffTestSchemas(from, to, []); + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum" ADD VALUE 'value2' BEFORE 'value3';`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'alter_type_add_value', @@ -201,8 +220,10 @@ test('enums #10', async () => { enum: schema.enum('enum', ['value1', 'value2']), }; - const { statements } = await diffTestSchemas(from, to, []); + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "folder"."enum" ADD VALUE 'value2';`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'alter_type_add_value', @@ -223,10 +244,12 @@ test('enums #11', async () => { enum: pgEnum('enum', ['value1']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'folder1.enum->public.enum', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "folder1"."enum" SET SCHEMA "public";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -246,10 +269,12 @@ test('enums #12', async () => { enum: schema1.enum('enum', ['value1']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'public.enum->folder1.enum', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum" SET SCHEMA "folder1";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -268,10 +293,12 @@ test('enums #13', async () => { enum: pgEnum('enum2', ['value1']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'public.enum1->public.enum2', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum1" RENAME TO "enum2";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'rename_type_enum', @@ -292,10 +319,13 @@ test('enums #14', async () => { enum: folder2.enum('enum2', ['value1']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'folder1.enum1->folder2.enum2', ]); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TYPE "folder1"."enum1" SET SCHEMA "folder2";`); + expect(sqlStatements[1]).toBe(`ALTER TYPE "folder2"."enum1" RENAME TO "enum2";`); expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -322,10 +352,16 @@ test('enums #15', async () => { enum: folder2.enum('enum2', ['value1', 'value2', 'value3', 'value4']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'folder1.enum1->folder2.enum2', ]); + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe(`ALTER TYPE "folder1"."enum1" SET SCHEMA "folder2";`); + expect(sqlStatements[1]).toBe(`ALTER TYPE "folder2"."enum1" RENAME TO "enum2";`); + expect(sqlStatements[2]).toBe(`ALTER TYPE "folder2"."enum2" ADD VALUE 'value2' BEFORE 'value4';`); + expect(sqlStatements[3]).toBe(`ALTER TYPE "folder2"."enum2" ADD VALUE 'value3' BEFORE 'value4';`); + expect(statements.length).toBe(4); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -373,10 +409,13 @@ test('enums #16', async () => { }), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'public.enum1->public.enum2', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum1" RENAME TO "enum2";`); + expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'rename_type_enum', @@ -405,10 +444,14 @@ test('enums #17', async () => { }), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'public.enum1->schema.enum1', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum1" SET SCHEMA "schema";`); + + expect(sqlStatements.length).toBe(1); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -440,10 +483,14 @@ test('enums #18', async () => { }; // change name and schema of the enum, no table changes - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'schema1.enum1->schema2.enum2', ]); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TYPE "schema1"."enum1" SET SCHEMA "schema2";`); + expect(sqlStatements[1]).toBe(`ALTER TYPE "schema2"."enum1" RENAME TO "enum2";`); + expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -458,3 +505,106 @@ test('enums #18', async () => { schema: 'schema2', }); }); + +test('drop enum value', async () => { + const enum1 = pgEnum('enum', ['value1', 'value2', 'value3']); + + const from = { + enum1, + }; + + const enum2 = pgEnum('enum', ['value1', 'value3']); + const to = { + enum2, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum";`); + expect(sqlStatements[1]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value1', 'value3');`); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columnsWithEnum: [], + deletedValues: [ + 'value2', + ], + name: 'enum', + newValues: [ + 'value1', + 'value3', + ], + schema: 'public', + type: 'alter_type_drop_value', + }); +}); + +test('drop enum value. enum is columns data type', async () => { + const enum1 = pgEnum('enum', ['value1', 'value2', 'value3']); + + const schema = pgSchema('new_schema'); + + const from = { + schema, + enum1, + table: pgTable('table', { + column: enum1('column'), + }), + table2: schema.table('table', { + column: enum1('column'), + }), + }; + + const enum2 = pgEnum('enum', ['value1', 'value3']); + const to = { + schema, + enum2, + table: pgTable('table', { + column: enum1('column'), + }), + table2: schema.table('table', { + column: enum1('column'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE text;`); + expect(sqlStatements[1]).toBe(`ALTER TABLE "new_schema"."table" ALTER COLUMN "column" SET DATA TYPE text;`); + expect(sqlStatements[2]).toBe(`DROP TYPE "public"."enum";`); + expect(sqlStatements[3]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value1', 'value3');`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE "public"."enum" USING "column"::"public"."enum";`, + ); + expect(sqlStatements[5]).toBe( + `ALTER TABLE "new_schema"."table" ALTER COLUMN "column" SET DATA TYPE "public"."enum" USING "column"::"public"."enum";`, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columnsWithEnum: [ + { + column: 'column', + schema: 'public', + table: 'table', + }, + { + column: 'column', + schema: 'new_schema', + table: 'table', + }, + ], + deletedValues: [ + 'value2', + ], + name: 'enum', + newValues: [ + 'value1', + 'value3', + ], + schema: 'public', + type: 'alter_type_drop_value', + }); +}); From cf39bf51815e59529663e976270568e982fb8988 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Tue, 8 Oct 2024 15:43:42 +0300 Subject: [PATCH 222/492] made test for enum ordering for push --- drizzle-kit/src/sqlgenerator.ts | 2 +- drizzle-kit/tests/pg-enums.test.ts | 8 +-- drizzle-kit/tests/push/pg.test.ts | 82 +++++++++++++++++++++++++++++- drizzle-kit/tests/schemaDiffer.ts | 23 +++------ 4 files changed, 93 insertions(+), 22 deletions(-) diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 9adfd1b16..b423a40ff 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -729,7 +729,7 @@ class DropTypeEnumConvertor extends Convertor { const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; - let statement = `DROP TYPE ${enumNameWithSchema};`; + let statement = `DROP TYPE ${enumNameWithSchema} CASCADE;`; return statement; } diff --git a/drizzle-kit/tests/pg-enums.test.ts b/drizzle-kit/tests/pg-enums.test.ts index e436092d7..63efe7a52 100644 --- a/drizzle-kit/tests/pg-enums.test.ts +++ b/drizzle-kit/tests/pg-enums.test.ts @@ -47,7 +47,7 @@ test('enums #3', async () => { const { statements, sqlStatements } = await diffTestSchemas(from, {}, []); expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum";`); + expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum" CASCADE;`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'drop_type_enum', @@ -66,7 +66,7 @@ test('enums #4', async () => { const { statements, sqlStatements } = await diffTestSchemas(from, {}, []); expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`DROP TYPE "folder"."enum";`); + expect(sqlStatements[0]).toBe(`DROP TYPE "folder"."enum" CASCADE;`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'drop_type_enum', @@ -521,7 +521,7 @@ test('drop enum value', async () => { const { statements, sqlStatements } = await diffTestSchemas(from, to, []); expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum";`); + expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum" CASCADE;`); expect(sqlStatements[1]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value1', 'value3');`); expect(statements.length).toBe(1); @@ -573,7 +573,7 @@ test('drop enum value. enum is columns data type', async () => { expect(sqlStatements.length).toBe(6); expect(sqlStatements[0]).toBe(`ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE text;`); expect(sqlStatements[1]).toBe(`ALTER TABLE "new_schema"."table" ALTER COLUMN "column" SET DATA TYPE text;`); - expect(sqlStatements[2]).toBe(`DROP TYPE "public"."enum";`); + expect(sqlStatements[2]).toBe(`DROP TYPE "public"."enum" CASCADE;`); expect(sqlStatements[3]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value1', 'value3');`); expect(sqlStatements[4]).toBe( `ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE "public"."enum" USING "column"::"public"."enum";`, diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index cb1a97122..7798cdc06 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -30,7 +30,7 @@ import { import { drizzle } from 'drizzle-orm/pglite'; import { SQL, sql } from 'drizzle-orm/sql'; import { pgSuggestions } from 'src/cli/commands/pgPushUtils'; -import { diffTestSchemasPush } from 'tests/schemaDiffer'; +import { diffTestSchemas, diffTestSchemasPush } from 'tests/schemaDiffer'; import { afterEach, expect, test } from 'vitest'; import { DialectSuite, run } from './common'; @@ -2236,3 +2236,83 @@ test('add array column - default', async () => { 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\';', ]); }); + +test('enums ordering', async () => { + const enum1 = pgEnum('enum_users_customer_and_ship_to_settings_roles', [ + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'custMgf', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ]); + const schema1 = {}; + + const schema2 = { + enum1, + }; + + const { sqlStatements: createEnum } = await diffTestSchemas(schema1, schema2, []); + + const enum2 = pgEnum('enum_users_customer_and_ship_to_settings_roles', [ + 'addedToTop', + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'custMgf', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ]); + const schema3 = { + enum2, + }; + + const { sqlStatements: addedValueSql } = await diffTestSchemas(schema2, schema3, []); + + const enum3 = pgEnum('enum_users_customer_and_ship_to_settings_roles', [ + 'addedToTop', + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'addedToMiddle', + 'custMgf', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ]); + const schema4 = { + enum3, + }; + + const client = new PGlite(); + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema3, + schema4, + [], + false, + ['public'], + undefined, + [...createEnum, ...addedValueSql], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + before: 'custMgf', + name: 'enum_users_customer_and_ship_to_settings_roles', + schema: 'public', + type: 'alter_type_add_value', + value: 'addedToMiddle', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TYPE "public"."enum_users_customer_and_ship_to_settings_roles" ADD VALUE 'addedToMiddle' BEFORE 'custMgf';`, + ); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 22a79ef72..5dca0c122 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -414,9 +414,14 @@ export const diffTestSchemasPush = async ( cli: boolean = false, schemas: string[] = ['public'], casing?: CasingType | undefined, + sqlStatementsToRun: string[] = [], ) => { - const { sqlStatements } = await applyPgDiffs(left, casing); - for (const st of sqlStatements) { + if (!sqlStatementsToRun.length) { + const res = await applyPgDiffs(left, casing); + sqlStatementsToRun = res.sqlStatements; + } + + for (const st of sqlStatementsToRun) { await client.query(st); } @@ -992,13 +997,6 @@ export async function diffTestSchemasPushLibSQL( run: async (query: string) => { await client.execute(query); }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, }, undefined, ); @@ -1058,13 +1056,6 @@ export async function diffTestSchemasPushLibSQL( run: async (query: string) => { await client.execute(query); }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, }, statements, sn1, From 6ef8f422c825bfab689288ff4cedd723a26fe943 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Wed, 9 Oct 2024 13:32:53 +0300 Subject: [PATCH 223/492] Added neon-serverless (websocket) tests, fixed neon-serverless session's lack of own count procedure (issue #3081) --- drizzle-orm/src/neon-serverless/session.ts | 10 +- integration-tests/package.json | 2 + .../tests/pg/neon-serverless.test.ts | 576 ++++++++++++++++++ integration-tests/vitest.config.ts | 1 + 4 files changed, 588 insertions(+), 1 deletion(-) create mode 100644 integration-tests/tests/pg/neon-serverless.test.ts diff --git a/drizzle-orm/src/neon-serverless/session.ts b/drizzle-orm/src/neon-serverless/session.ts index 82c405333..5421dc77e 100644 --- a/drizzle-orm/src/neon-serverless/session.ts +++ b/drizzle-orm/src/neon-serverless/session.ts @@ -16,7 +16,7 @@ import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.type import type { PgQueryResultHKT, PgTransactionConfig, PreparedQueryConfig } from '~/pg-core/session.ts'; import { PgPreparedQuery, PgSession } from '~/pg-core/session.ts'; import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; +import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; export type NeonClient = Pool | PoolClient | Client; @@ -143,6 +143,14 @@ export class NeonSession< return this.client.query(query, params); } + override async count(sql: SQL): Promise { + const res = await this.execute<{ rows: [{ count: string }] }>(sql); + + return Number( + res['rows'][0]['count'], + ); + } + override async transaction( transaction: (tx: NeonTransaction) => Promise, config: PgTransactionConfig = {}, diff --git a/integration-tests/package.json b/integration-tests/package.json index 78f36fe30..cedbe4895 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -28,6 +28,7 @@ "@types/pg": "^8.10.1", "@types/sql.js": "^1.4.4", "@types/uuid": "^9.0.1", + "@types/ws": "^8.5.10", "@vitest/ui": "^1.6.0", "ava": "^5.3.0", "axios": "^1.4.0", @@ -71,6 +72,7 @@ "uuid": "^9.0.0", "uvu": "^0.5.6", "vitest": "^1.6.0", + "ws": "^8.16.0", "zod": "^3.20.2" } } diff --git a/integration-tests/tests/pg/neon-serverless.test.ts b/integration-tests/tests/pg/neon-serverless.test.ts new file mode 100644 index 000000000..0f641e7a7 --- /dev/null +++ b/integration-tests/tests/pg/neon-serverless.test.ts @@ -0,0 +1,576 @@ +import { neonConfig, Pool } from '@neondatabase/serverless'; +import retry from 'async-retry'; +import { eq, sql } from 'drizzle-orm'; +import { drizzle, type NeonDatabase } from 'drizzle-orm/neon-serverless'; +import { migrate } from 'drizzle-orm/neon-serverless/migrator'; +import { boolean, jsonb, pgSchema, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import ws from 'ws'; +import { skipTests } from '~/common'; +import { randomString } from '~/utils'; +import { tests, usersMigratorTable, usersTable } from './pg-common'; + +const ENABLE_LOGGING = false; + +let db: NeonDatabase; +let client: Pool; + +beforeAll(async () => { + const connectionString = process.env['NEON_CONNECTION_STRING']; + if (!connectionString) { + throw new Error('NEON_CONNECTION_STRING is not defined'); + } + + neonConfig.webSocketConstructor = ws; + + client = await retry(async () => { + client = new Pool({ connectionString }); + + const cnt = await client.connect(); + cnt.release(); + + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); +}); + +beforeEach((ctx) => { + ctx.pg = { + db, + }; +}); + +test('migrator : default migration strategy', async () => { + await db.execute(sql`drop table if exists all_columns`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); + + await migrate(db, { migrationsFolder: './drizzle2/pg' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table all_columns`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table "drizzle"."__drizzle_migrations"`); +}); + +test('migrator : migrate with custom schema', async () => { + await db.execute(sql`drop table if exists all_columns`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); + + await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsSchema: 'custom_migrations' }); + + // test if the custom migrations table was created + const { rowCount } = await db.execute(sql`select * from custom_migrations."__drizzle_migrations";`); + expect(rowCount && rowCount > 0).toBeTruthy(); + + // test if the migrated table are working as expected + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + const result = await db.select().from(usersMigratorTable); + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table all_columns`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table custom_migrations."__drizzle_migrations"`); +}); + +test('migrator : migrate with custom table', async () => { + const customTable = randomString(); + await db.execute(sql`drop table if exists all_columns`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); + + await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsTable: customTable }); + + // test if the custom migrations table was created + const { rowCount } = await db.execute(sql`select * from "drizzle".${sql.identifier(customTable)};`); + expect(rowCount && rowCount > 0).toBeTruthy(); + + // test if the migrated table are working as expected + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + const result = await db.select().from(usersMigratorTable); + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table all_columns`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table "drizzle".${sql.identifier(customTable)}`); +}); + +test('migrator : migrate with custom table and custom schema', async () => { + const customTable = randomString(); + await db.execute(sql`drop table if exists all_columns`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); + + await migrate(db, { + migrationsFolder: './drizzle2/pg', + migrationsTable: customTable, + migrationsSchema: 'custom_migrations', + }); + + // test if the custom migrations table was created + const { rowCount } = await db.execute( + sql`select * from custom_migrations.${sql.identifier(customTable)};`, + ); + expect(rowCount && rowCount > 0).toBeTruthy(); + + // test if the migrated table are working as expected + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + const result = await db.select().from(usersMigratorTable); + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table all_columns`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table custom_migrations.${sql.identifier(customTable)}`); +}); + +test('all date and time columns without timezone first case mode string', async () => { + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'string', precision: 6 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(6) not null + ) + `); + + // 1. Insert date in string format without timezone in it + await db.insert(table).values([ + { timestamp: '2022-01-01 02:00:00.123456' }, + ]); + + // 2, Select in string format and check that values are the same + const result = await db.select().from(table); + + expect(result).toEqual([{ id: 1, timestamp: '2022-01-01 02:00:00.123456' }]); + + // 3. Select as raw query and check that values are the same + const result2 = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + expect(result2.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 02:00:00.123456' }]); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('all date and time columns without timezone second case mode string', async () => { + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'string', precision: 6 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(6) not null + ) + `); + + // 1. Insert date in string format with timezone in it + await db.insert(table).values([ + { timestamp: '2022-01-01T02:00:00.123456-02' }, + ]); + + // 2, Select as raw query and check that values are the same + const result = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + expect(result.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 02:00:00.123456' }]); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('all date and time columns without timezone third case mode date', async () => { + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'date', precision: 3 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(3) not null + ) + `); + + const insertedDate = new Date('2022-01-01 20:00:00.123+04'); + + // 1. Insert date as new date + await db.insert(table).values([ + { timestamp: insertedDate }, + ]); + + // 2, Select as raw query as string + const result = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + // 3. Compare both dates using orm mapping - Need to add 'Z' to tell JS that it is UTC + expect(new Date(result.rows[0]!.timestamp_string + 'Z').getTime()).toBe(insertedDate.getTime()); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('test mode string for timestamp with timezone', async () => { + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'string', withTimezone: true, precision: 6 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(6) with time zone not null + ) + `); + + const timestampString = '2022-01-01 00:00:00.123456-0200'; + + // 1. Insert date in string format with timezone in it + await db.insert(table).values([ + { timestamp: timestampString }, + ]); + + // 2. Select date in string format and check that the values are the same + const result = await db.select().from(table); + + // 2.1 Notice that postgres will return the date in UTC, but it is exactly the same + expect(result).toEqual([{ id: 1, timestamp: '2022-01-01 02:00:00.123456+00' }]); + + // 3. Select as raw query and checke that values are the same + const result2 = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + // 3.1 Notice that postgres will return the date in UTC, but it is exactlt the same + expect(result2.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 02:00:00.123456+00' }]); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('test mode date for timestamp with timezone', async () => { + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'date', withTimezone: true, precision: 3 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(3) with time zone not null + ) + `); + + const timestampString = new Date('2022-01-01 00:00:00.456-0200'); + + // 1. Insert date in string format with timezone in it + await db.insert(table).values([ + { timestamp: timestampString }, + ]); + + // 2. Select date in string format and check that the values are the same + const result = await db.select().from(table); + + // 2.1 Notice that postgres will return the date in UTC, but it is exactly the same + expect(result).toEqual([{ id: 1, timestamp: timestampString }]); + + // 3. Select as raw query and checke that values are the same + const result2 = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + // 3.1 Notice that postgres will return the date in UTC, but it is exactlt the same + expect(result2.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 02:00:00.456+00' }]); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('test mode string for timestamp with timezone in UTC timezone', async () => { + // get current timezone from db + const timezone = await db.execute<{ TimeZone: string }>(sql`show timezone`); + + // set timezone to UTC + await db.execute(sql`set time zone 'UTC'`); + + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'string', withTimezone: true, precision: 6 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(6) with time zone not null + ) + `); + + const timestampString = '2022-01-01 00:00:00.123456-0200'; + + // 1. Insert date in string format with timezone in it + await db.insert(table).values([ + { timestamp: timestampString }, + ]); + + // 2. Select date in string format and check that the values are the same + const result = await db.select().from(table); + + // 2.1 Notice that postgres will return the date in UTC, but it is exactly the same + expect(result).toEqual([{ id: 1, timestamp: '2022-01-01 02:00:00.123456+00' }]); + + // 3. Select as raw query and checke that values are the same + const result2 = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + // 3.1 Notice that postgres will return the date in UTC, but it is exactlt the same + expect(result2.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 02:00:00.123456+00' }]); + + await db.execute(sql`set time zone '${sql.raw(timezone.rows[0]!.TimeZone)}'`); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test.skip('test mode string for timestamp with timezone in different timezone', async () => { + // get current timezone from db + const timezone = await db.execute<{ TimeZone: string }>(sql`show timezone`); + + // set timezone to HST (UTC - 10) + await db.execute(sql`set time zone 'HST'`); + + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'string', withTimezone: true, precision: 6 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(6) with time zone not null + ) + `); + + const timestampString = '2022-01-01 00:00:00.123456-1000'; + + // 1. Insert date in string format with timezone in it + await db.insert(table).values([ + { timestamp: timestampString }, + ]); + + // 2. Select date in string format and check that the values are the same + const result = await db.select().from(table); + + expect(result).toEqual([{ id: 1, timestamp: '2022-01-01 00:00:00.123456-10' }]); + + // 3. Select as raw query and checke that values are the same + const result2 = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + expect(result2.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 00:00:00.123456+00' }]); + + await db.execute(sql`set time zone '${sql.raw(timezone.rows[0]!.TimeZone)}'`); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('select all fields', async (ctx) => { + const { db } = ctx.pg; + + const now = Date.now(); + + await db.insert(usersTable).values({ name: 'John' }); + const result = await db.select().from(usersTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + expect(Math.abs(result[0]!.createdAt.getTime() - now)).toBeLessThan(3000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('update with returning all fields', async (ctx) => { + const { db } = ctx.pg; + + const now = Date.now(); + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning(); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + expect(Math.abs(users[0]!.createdAt.getTime() - now)).toBeLessThan(3000); + expect(users).toEqual([ + { id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }, + ]); +}); + +test('delete with returning all fields', async (ctx) => { + const { db } = ctx.pg; + + const now = Date.now(); + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')).returning(); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + expect(Math.abs(users[0]!.createdAt.getTime() - now)).toBeLessThan(3000); + expect(users).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: users[0]!.createdAt }, + ]); +}); + +const mySchema = pgSchema('mySchema'); + +const usersMySchemaTable = mySchema.table('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: jsonb('jsonb').$type(), + createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), +}); + +test('mySchema :: select all fields', async (ctx) => { + const { db } = ctx.pg; + + const now = Date.now(); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const result = await db.select().from(usersMySchemaTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + expect(Math.abs(result[0]!.createdAt.getTime() - now)).toBeLessThan(3000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('mySchema :: delete with returning all fields', async (ctx) => { + const { db } = ctx.pg; + + const now = Date.now(); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const users = await db.delete(usersMySchemaTable).where(eq(usersMySchemaTable.name, 'John')).returning(); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + expect(Math.abs(users[0]!.createdAt.getTime() - now)).toBeLessThan(3000); + expect(users).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); +}); + +skipTests([ + 'migrator : default migration strategy', + 'migrator : migrate with custom schema', + 'migrator : migrate with custom table', + 'migrator : migrate with custom table and custom schema', + 'insert via db.execute + select via db.execute', + 'insert via db.execute + returning', + 'insert via db.execute w/ query builder', + 'all date and time columns without timezone first case mode string', + 'all date and time columns without timezone third case mode date', + 'test mode string for timestamp with timezone', + 'test mode date for timestamp with timezone', + 'test mode string for timestamp with timezone in UTC timezone', + 'nested transaction rollback', + 'transaction rollback', + 'nested transaction', + 'transaction', + 'timestamp timezone', + 'test $onUpdateFn and $onUpdate works as $default', + 'select all fields', + 'update with returning all fields', + 'delete with returning all fields', + 'mySchema :: select all fields', + 'mySchema :: delete with returning all fields', +]); +tests(); + +beforeEach(async () => { + await db.execute(sql`drop schema if exists public cascade`); + await db.execute(sql`create schema public`); + await db.execute( + sql` + create table users ( + id serial primary key, + name text not null, + verified boolean not null default false, + jsonb jsonb, + created_at timestamptz not null default now() + ) + `, + ); +}); + +test('insert via db.execute + select via db.execute', async () => { + await db.execute( + sql`insert into ${usersTable} (${sql.identifier(usersTable.name.name)}) values (${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>( + sql`select id, name from "users"`, + ); + expect(result.rows).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert via db.execute + returning', async () => { + const inserted = await db.execute<{ id: number; name: string }>( + sql`insert into ${usersTable} (${ + sql.identifier( + usersTable.name.name, + ) + }) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, + ); + expect(inserted.rows).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert via db.execute w/ query builder', async () => { + const inserted = await db.execute>( + db + .insert(usersTable) + .values({ name: 'John' }) + .returning({ id: usersTable.id, name: usersTable.name }), + ); + expect(inserted.rows).toEqual([{ id: 1, name: 'John' }]); +}); diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 5187d2cfc..034bad147 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -20,6 +20,7 @@ export default defineConfig({ ? [ 'tests/relational/mysql.planetscale.test.ts', 'tests/neon-http-batch.test.ts', + 'tests/neon-serverless.test.ts', 'tests/mysql/tidb-serverless.test.ts', 'tests/mysql/mysql-planetscale.test.ts', 'tests/sqlite/libsql.test.ts', From 26155b036a5f7d4b615b8dfa00a400c6a39fd093 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Wed, 9 Oct 2024 13:37:12 +0300 Subject: [PATCH 224/492] fixed lockfile --- pnpm-lock.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f5d886131..3ad04fe47 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -644,6 +644,9 @@ importers: vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + ws: + specifier: ^8.16.0 + version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) zod: specifier: ^3.20.2 version: 3.23.7 @@ -687,6 +690,9 @@ importers: '@types/uuid': specifier: ^9.0.1 version: 9.0.8 + '@types/ws': + specifier: ^8.5.10 + version: 8.5.11 '@vitest/ui': specifier: ^1.6.0 version: 1.6.0(vitest@1.6.0) From 665fa03b24ec762ed001bfe66b1d40906862256f Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Wed, 9 Oct 2024 14:00:04 +0300 Subject: [PATCH 225/492] Added leftover data deletion, imported table from common instead of re-creating locally --- .../tests/pg/neon-serverless.test.ts | 20 ++++++++----------- integration-tests/tests/pg/pg-common.ts | 2 +- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/integration-tests/tests/pg/neon-serverless.test.ts b/integration-tests/tests/pg/neon-serverless.test.ts index 0f641e7a7..309547a75 100644 --- a/integration-tests/tests/pg/neon-serverless.test.ts +++ b/integration-tests/tests/pg/neon-serverless.test.ts @@ -3,12 +3,12 @@ import retry from 'async-retry'; import { eq, sql } from 'drizzle-orm'; import { drizzle, type NeonDatabase } from 'drizzle-orm/neon-serverless'; import { migrate } from 'drizzle-orm/neon-serverless/migrator'; -import { boolean, jsonb, pgSchema, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; +import { pgTable, serial, timestamp } from 'drizzle-orm/pg-core'; import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; import ws from 'ws'; import { skipTests } from '~/common'; import { randomString } from '~/utils'; -import { tests, usersMigratorTable, usersTable } from './pg-common'; +import { tests, usersMigratorTable, usersMySchemaTable, usersTable } from './pg-common'; const ENABLE_LOGGING = false; @@ -425,6 +425,8 @@ test('select all fields', async (ctx) => { await db.insert(usersTable).values({ name: 'John' }); const result = await db.select().from(usersTable); + await db.delete(usersTable); + expect(result[0]!.createdAt).toBeInstanceOf(Date); expect(Math.abs(result[0]!.createdAt.getTime() - now)).toBeLessThan(3000); expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); @@ -442,6 +444,8 @@ test('update with returning all fields', async (ctx) => { .where(eq(usersTable.name, 'John')) .returning(); + await db.delete(usersTable); + expect(users[0]!.createdAt).toBeInstanceOf(Date); expect(Math.abs(users[0]!.createdAt.getTime() - now)).toBeLessThan(3000); expect(users).toEqual([ @@ -464,16 +468,6 @@ test('delete with returning all fields', async (ctx) => { ]); }); -const mySchema = pgSchema('mySchema'); - -const usersMySchemaTable = mySchema.table('users', { - id: serial('id').primaryKey(), - name: text('name').notNull(), - verified: boolean('verified').notNull().default(false), - jsonb: jsonb('jsonb').$type(), - createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), -}); - test('mySchema :: select all fields', async (ctx) => { const { db } = ctx.pg; @@ -482,6 +476,8 @@ test('mySchema :: select all fields', async (ctx) => { await db.insert(usersMySchemaTable).values({ name: 'John' }); const result = await db.select().from(usersMySchemaTable); + await db.delete(usersMySchemaTable); + expect(result[0]!.createdAt).toBeInstanceOf(Date); expect(Math.abs(result[0]!.createdAt.getTime() - now)).toBeLessThan(3000); expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 0ea8f250f..e8415af01 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -181,7 +181,7 @@ const aggregateTable = pgTable('aggregate_table', { // To test another schema and multischema const mySchema = pgSchema('mySchema'); -const usersMySchemaTable = mySchema.table('users', { +export const usersMySchemaTable = mySchema.table('users', { id: serial('id').primaryKey(), name: text('name').notNull(), verified: boolean('verified').notNull().default(false), From 588085ac0ccc95a0cc8dc36e12e3f58ac9a10644 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Wed, 9 Oct 2024 14:32:24 +0300 Subject: [PATCH 226/492] Fixed lack of custom schema cleanup on locally remade skipped tests of neon-serverless --- .../tests/pg/neon-serverless.test.ts | 24 +++++++++++++------ integration-tests/tests/pg/pg-common.ts | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/integration-tests/tests/pg/neon-serverless.test.ts b/integration-tests/tests/pg/neon-serverless.test.ts index 309547a75..5a77809fa 100644 --- a/integration-tests/tests/pg/neon-serverless.test.ts +++ b/integration-tests/tests/pg/neon-serverless.test.ts @@ -8,7 +8,7 @@ import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; import ws from 'ws'; import { skipTests } from '~/common'; import { randomString } from '~/utils'; -import { tests, usersMigratorTable, usersMySchemaTable, usersTable } from './pg-common'; +import { mySchema, tests, usersMigratorTable, usersMySchemaTable, usersTable } from './pg-common'; const ENABLE_LOGGING = false; @@ -425,8 +425,6 @@ test('select all fields', async (ctx) => { await db.insert(usersTable).values({ name: 'John' }); const result = await db.select().from(usersTable); - await db.delete(usersTable); - expect(result[0]!.createdAt).toBeInstanceOf(Date); expect(Math.abs(result[0]!.createdAt.getTime() - now)).toBeLessThan(3000); expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); @@ -444,8 +442,6 @@ test('update with returning all fields', async (ctx) => { .where(eq(usersTable.name, 'John')) .returning(); - await db.delete(usersTable); - expect(users[0]!.createdAt).toBeInstanceOf(Date); expect(Math.abs(users[0]!.createdAt.getTime() - now)).toBeLessThan(3000); expect(users).toEqual([ @@ -476,8 +472,6 @@ test('mySchema :: select all fields', async (ctx) => { await db.insert(usersMySchemaTable).values({ name: 'John' }); const result = await db.select().from(usersMySchemaTable); - await db.delete(usersMySchemaTable); - expect(result[0]!.createdAt).toBeInstanceOf(Date); expect(Math.abs(result[0]!.createdAt.getTime() - now)).toBeLessThan(3000); expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); @@ -525,7 +519,11 @@ tests(); beforeEach(async () => { await db.execute(sql`drop schema if exists public cascade`); + await db.execute(sql`drop schema if exists ${mySchema} cascade`); + await db.execute(sql`create schema public`); + await db.execute(sql`create schema ${mySchema}`); + await db.execute( sql` create table users ( @@ -537,6 +535,18 @@ beforeEach(async () => { ) `, ); + + await db.execute( + sql` + create table ${usersMySchemaTable} ( + id serial primary key, + name text not null, + verified boolean not null default false, + jsonb jsonb, + created_at timestamptz not null default now() + ) + `, + ); }); test('insert via db.execute + select via db.execute', async () => { diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index e8415af01..78eecf328 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -179,7 +179,7 @@ const aggregateTable = pgTable('aggregate_table', { }); // To test another schema and multischema -const mySchema = pgSchema('mySchema'); +export const mySchema = pgSchema('mySchema'); export const usersMySchemaTable = mySchema.table('users', { id: serial('id').primaryKey(), From 77aed7e48c21817d6910bb293c1cf1034145bcdd Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 9 Oct 2024 14:44:33 +0300 Subject: [PATCH 227/492] squash add + drop enum values to drop only --- drizzle-kit/src/snapshotsDiffer.ts | 22 +++++- drizzle-kit/src/sqlgenerator.ts | 2 +- drizzle-kit/tests/pg-enums.test.ts | 79 +++++++++++++++++++-- drizzle-kit/tests/push/pg.test.ts | 106 +++++++++++++++++++++++++++++ 4 files changed, 202 insertions(+), 7 deletions(-) diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index dee245071..cf7b5f793 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -1150,7 +1150,25 @@ export const applyPgSnapshotsDiff = async ( return true; }); - const sqlStatements = fromJson(filteredJsonStatements, 'postgresql'); + // enum filters + // Need to find add and drop enum values in same enum and remove add values + const filteredEnumsJsonStatements = filteredJsonStatements.filter((st) => { + if (st.type === 'alter_type_add_value') { + if ( + jsonStatements.find( + (it) => + it.type === 'alter_type_drop_value' + && it.name === st.name + && it.schema === st.schema, + ) + ) { + return false; + } + } + return true; + }); + + const sqlStatements = fromJson(filteredEnumsJsonStatements, 'postgresql'); const uniqueSqlStatements: string[] = []; sqlStatements.forEach((ss) => { @@ -1171,7 +1189,7 @@ export const applyPgSnapshotsDiff = async ( const _meta = prepareMigrationMeta(rSchemas, rTables, rColumns); return { - statements: filteredJsonStatements, + statements: filteredEnumsJsonStatements, sqlStatements: uniqueSqlStatements, _meta, }; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index b423a40ff..9adfd1b16 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -729,7 +729,7 @@ class DropTypeEnumConvertor extends Convertor { const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; - let statement = `DROP TYPE ${enumNameWithSchema} CASCADE;`; + let statement = `DROP TYPE ${enumNameWithSchema};`; return statement; } diff --git a/drizzle-kit/tests/pg-enums.test.ts b/drizzle-kit/tests/pg-enums.test.ts index 63efe7a52..2d7f44a22 100644 --- a/drizzle-kit/tests/pg-enums.test.ts +++ b/drizzle-kit/tests/pg-enums.test.ts @@ -47,7 +47,7 @@ test('enums #3', async () => { const { statements, sqlStatements } = await diffTestSchemas(from, {}, []); expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum" CASCADE;`); + expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'drop_type_enum', @@ -66,7 +66,7 @@ test('enums #4', async () => { const { statements, sqlStatements } = await diffTestSchemas(from, {}, []); expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`DROP TYPE "folder"."enum" CASCADE;`); + expect(sqlStatements[0]).toBe(`DROP TYPE "folder"."enum";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'drop_type_enum', @@ -521,7 +521,7 @@ test('drop enum value', async () => { const { statements, sqlStatements } = await diffTestSchemas(from, to, []); expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum" CASCADE;`); + expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum";`); expect(sqlStatements[1]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value1', 'value3');`); expect(statements.length).toBe(1); @@ -573,7 +573,7 @@ test('drop enum value. enum is columns data type', async () => { expect(sqlStatements.length).toBe(6); expect(sqlStatements[0]).toBe(`ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE text;`); expect(sqlStatements[1]).toBe(`ALTER TABLE "new_schema"."table" ALTER COLUMN "column" SET DATA TYPE text;`); - expect(sqlStatements[2]).toBe(`DROP TYPE "public"."enum" CASCADE;`); + expect(sqlStatements[2]).toBe(`DROP TYPE "public"."enum";`); expect(sqlStatements[3]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value1', 'value3');`); expect(sqlStatements[4]).toBe( `ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE "public"."enum" USING "column"::"public"."enum";`, @@ -608,3 +608,74 @@ test('drop enum value. enum is columns data type', async () => { type: 'alter_type_drop_value', }); }); + +test('shuffle enum values', async () => { + const enum1 = pgEnum('enum', ['value1', 'value2', 'value3']); + + const schema = pgSchema('new_schema'); + + const from = { + schema, + enum1, + table: pgTable('table', { + column: enum1('column'), + }), + table2: schema.table('table', { + column: enum1('column'), + }), + }; + + const enum2 = pgEnum('enum', ['value1', 'value3', 'value2']); + const to = { + schema, + enum2, + table: pgTable('table', { + column: enum1('column'), + }), + table2: schema.table('table', { + column: enum1('column'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE text;`); + expect(sqlStatements[1]).toBe(`ALTER TABLE "new_schema"."table" ALTER COLUMN "column" SET DATA TYPE text;`); + expect(sqlStatements[2]).toBe(`DROP TYPE "public"."enum";`); + expect(sqlStatements[3]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value1', 'value3', 'value2');`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE "public"."enum" USING "column"::"public"."enum";`, + ); + expect(sqlStatements[5]).toBe( + `ALTER TABLE "new_schema"."table" ALTER COLUMN "column" SET DATA TYPE "public"."enum" USING "column"::"public"."enum";`, + ); + + console.log('statements: ', statements); + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columnsWithEnum: [ + { + column: 'column', + schema: 'public', + table: 'table', + }, + { + column: 'column', + schema: 'new_schema', + table: 'table', + }, + ], + deletedValues: [ + 'value3', + ], + name: 'enum', + newValues: [ + 'value1', + 'value3', + 'value2', + ], + schema: 'public', + type: 'alter_type_drop_value', + }); +}); diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 7798cdc06..243e22242 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -2316,3 +2316,109 @@ test('enums ordering', async () => { `ALTER TYPE "public"."enum_users_customer_and_ship_to_settings_roles" ADD VALUE 'addedToMiddle' BEFORE 'custMgf';`, ); }); + +test('drop enum values', async () => { + const newSchema = pgSchema('mySchema'); + const enum3 = pgEnum('enum_users_customer_and_ship_to_settings_roles', [ + 'addedToTop', + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'addedToMiddle', + 'custMgf', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ]); + const schema1 = { + enum3, + table: pgTable('enum_table', { + id: enum3(), + }), + newSchema, + table1: newSchema.table('enum_table', { + id: enum3(), + }), + }; + + const enum4 = pgEnum('enum_users_customer_and_ship_to_settings_roles', [ + 'addedToTop', + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ]); + const schema2 = { + enum4, + table: pgTable('enum_table', { + id: enum4(), + }), + newSchema, + table1: newSchema.table('enum_table', { + id: enum4(), + }), + }; + + const client = new PGlite(); + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public', 'mySchema'], + undefined, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'enum_users_customer_and_ship_to_settings_roles', + schema: 'public', + type: 'alter_type_drop_value', + newValues: [ + 'addedToTop', + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ], + deletedValues: ['addedToMiddle', 'custMgf'], + columnsWithEnum: [{ + column: 'id', + schema: 'public', + table: 'enum_table', + }, { + column: 'id', + schema: 'mySchema', + table: 'enum_table', + }], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "public"."enum_table" ALTER COLUMN "id" SET DATA TYPE text;`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE "mySchema"."enum_table" ALTER COLUMN "id" SET DATA TYPE text;`, + ); + expect(sqlStatements[2]).toBe( + `DROP TYPE "public"."enum_users_customer_and_ship_to_settings_roles";`, + ); + expect(sqlStatements[3]).toBe( + `CREATE TYPE "public"."enum_users_customer_and_ship_to_settings_roles" AS ENUM('addedToTop', 'custAll', 'custAdmin', 'custClerk', 'custInvoiceManager', 'custApprover', 'custOrderWriter', 'custBuyer');`, + ); + expect(sqlStatements[4]).toBe( + `ALTER TABLE "public"."enum_table" ALTER COLUMN "id" SET DATA TYPE "public"."enum_users_customer_and_ship_to_settings_roles" USING "id"::"public"."enum_users_customer_and_ship_to_settings_roles";`, + ); + expect(sqlStatements[5]).toBe( + `ALTER TABLE "mySchema"."enum_table" ALTER COLUMN "id" SET DATA TYPE "public"."enum_users_customer_and_ship_to_settings_roles" USING "id"::"public"."enum_users_customer_and_ship_to_settings_roles";`, + ); +}); From a345cb3c34e4ff2bc37f96e75f5e945649c22a6b Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 10 Oct 2024 11:30:37 +0300 Subject: [PATCH 228/492] Upgrade to TS 5.6.3 --- drizzle-orm/package.json | 2 +- drizzle-orm/src/aws-data-api/pg/driver.ts | 4 +- drizzle-orm/src/aws-data-api/pg/session.ts | 6 +- drizzle-orm/src/better-sqlite3/driver.ts | 2 +- drizzle-orm/src/better-sqlite3/session.ts | 6 +- drizzle-orm/src/bun-sqlite/driver.ts | 2 +- drizzle-orm/src/bun-sqlite/session.ts | 6 +- drizzle-orm/src/d1/driver.ts | 2 +- drizzle-orm/src/d1/session.ts | 6 +- drizzle-orm/src/errors.ts | 2 +- drizzle-orm/src/expo-sqlite/driver.ts | 2 +- drizzle-orm/src/expo-sqlite/session.ts | 6 +- drizzle-orm/src/libsql/driver.ts | 2 +- drizzle-orm/src/libsql/session.ts | 6 +- drizzle-orm/src/mysql-core/columns/bigint.ts | 8 +- drizzle-orm/src/mysql-core/columns/binary.ts | 4 +- drizzle-orm/src/mysql-core/columns/boolean.ts | 4 +- drizzle-orm/src/mysql-core/columns/char.ts | 4 +- drizzle-orm/src/mysql-core/columns/common.ts | 8 +- drizzle-orm/src/mysql-core/columns/custom.ts | 4 +- .../src/mysql-core/columns/date.common.ts | 4 +- drizzle-orm/src/mysql-core/columns/date.ts | 8 +- .../src/mysql-core/columns/datetime.ts | 8 +- drizzle-orm/src/mysql-core/columns/decimal.ts | 4 +- drizzle-orm/src/mysql-core/columns/double.ts | 4 +- drizzle-orm/src/mysql-core/columns/enum.ts | 4 +- drizzle-orm/src/mysql-core/columns/float.ts | 4 +- drizzle-orm/src/mysql-core/columns/int.ts | 4 +- drizzle-orm/src/mysql-core/columns/json.ts | 4 +- .../src/mysql-core/columns/mediumint.ts | 4 +- drizzle-orm/src/mysql-core/columns/real.ts | 4 +- drizzle-orm/src/mysql-core/columns/serial.ts | 4 +- .../src/mysql-core/columns/smallint.ts | 4 +- drizzle-orm/src/mysql-core/columns/text.ts | 4 +- drizzle-orm/src/mysql-core/columns/time.ts | 4 +- .../src/mysql-core/columns/timestamp.ts | 8 +- drizzle-orm/src/mysql-core/columns/tinyint.ts | 4 +- .../src/mysql-core/columns/varbinary.ts | 4 +- drizzle-orm/src/mysql-core/columns/varchar.ts | 4 +- drizzle-orm/src/mysql-core/columns/year.ts | 4 +- .../src/mysql-core/query-builders/count.ts | 2 +- .../src/mysql-core/query-builders/delete.ts | 2 +- .../src/mysql-core/query-builders/insert.ts | 2 +- .../src/mysql-core/query-builders/query.ts | 2 +- .../src/mysql-core/query-builders/select.ts | 4 +- .../src/mysql-core/query-builders/update.ts | 2 +- drizzle-orm/src/mysql-core/session.ts | 2 +- drizzle-orm/src/mysql-core/table.ts | 2 +- drizzle-orm/src/mysql-core/view-base.ts | 2 +- drizzle-orm/src/mysql-core/view.ts | 6 +- drizzle-orm/src/mysql-proxy/driver.ts | 2 +- drizzle-orm/src/mysql-proxy/session.ts | 6 +- drizzle-orm/src/mysql2/driver.ts | 2 +- drizzle-orm/src/mysql2/session.ts | 6 +- drizzle-orm/src/neon-http/driver.ts | 2 +- drizzle-orm/src/neon-http/session.ts | 6 +- drizzle-orm/src/neon-serverless/driver.ts | 2 +- drizzle-orm/src/neon-serverless/session.ts | 6 +- drizzle-orm/src/node-postgres/driver.ts | 2 +- drizzle-orm/src/node-postgres/session.ts | 6 +- drizzle-orm/src/op-sqlite/driver.ts | 2 +- drizzle-orm/src/op-sqlite/session.ts | 6 +- drizzle-orm/src/pg-core/columns/bigint.ts | 8 +- drizzle-orm/src/pg-core/columns/bigserial.ts | 8 +- drizzle-orm/src/pg-core/columns/boolean.ts | 4 +- drizzle-orm/src/pg-core/columns/char.ts | 4 +- drizzle-orm/src/pg-core/columns/cidr.ts | 4 +- drizzle-orm/src/pg-core/columns/common.ts | 8 +- drizzle-orm/src/pg-core/columns/custom.ts | 4 +- .../src/pg-core/columns/date.common.ts | 2 +- drizzle-orm/src/pg-core/columns/date.ts | 8 +- .../src/pg-core/columns/double-precision.ts | 4 +- drizzle-orm/src/pg-core/columns/enum.ts | 4 +- drizzle-orm/src/pg-core/columns/inet.ts | 4 +- drizzle-orm/src/pg-core/columns/int.common.ts | 2 +- drizzle-orm/src/pg-core/columns/integer.ts | 4 +- drizzle-orm/src/pg-core/columns/interval.ts | 4 +- drizzle-orm/src/pg-core/columns/json.ts | 4 +- drizzle-orm/src/pg-core/columns/jsonb.ts | 4 +- drizzle-orm/src/pg-core/columns/line.ts | 8 +- drizzle-orm/src/pg-core/columns/macaddr.ts | 4 +- drizzle-orm/src/pg-core/columns/macaddr8.ts | 4 +- drizzle-orm/src/pg-core/columns/numeric.ts | 4 +- drizzle-orm/src/pg-core/columns/point.ts | 8 +- .../columns/postgis_extension/geometry.ts | 8 +- drizzle-orm/src/pg-core/columns/real.ts | 4 +- drizzle-orm/src/pg-core/columns/serial.ts | 4 +- drizzle-orm/src/pg-core/columns/smallint.ts | 4 +- .../src/pg-core/columns/smallserial.ts | 4 +- drizzle-orm/src/pg-core/columns/text.ts | 4 +- drizzle-orm/src/pg-core/columns/time.ts | 4 +- drizzle-orm/src/pg-core/columns/timestamp.ts | 8 +- drizzle-orm/src/pg-core/columns/uuid.ts | 4 +- drizzle-orm/src/pg-core/columns/varchar.ts | 4 +- .../pg-core/columns/vector_extension/bit.ts | 4 +- .../columns/vector_extension/halfvec.ts | 4 +- .../columns/vector_extension/sparsevec.ts | 4 +- .../columns/vector_extension/vector.ts | 4 +- .../src/pg-core/query-builders/count.ts | 2 +- .../src/pg-core/query-builders/delete.ts | 2 +- .../src/pg-core/query-builders/insert.ts | 2 +- .../src/pg-core/query-builders/query.ts | 2 +- drizzle-orm/src/pg-core/query-builders/raw.ts | 2 +- .../refresh-materialized-view.ts | 2 +- .../src/pg-core/query-builders/select.ts | 4 +- .../src/pg-core/query-builders/update.ts | 2 +- drizzle-orm/src/pg-core/session.ts | 2 +- drizzle-orm/src/pg-core/table.ts | 2 +- drizzle-orm/src/pg-core/view-base.ts | 2 +- drizzle-orm/src/pg-core/view.ts | 12 +- drizzle-orm/src/pg-proxy/driver.ts | 2 +- drizzle-orm/src/pg-proxy/session.ts | 6 +- drizzle-orm/src/pglite/driver.ts | 2 +- drizzle-orm/src/pglite/session.ts | 6 +- .../src/planetscale-serverless/driver.ts | 2 +- .../src/planetscale-serverless/session.ts | 6 +- drizzle-orm/src/postgres-js/driver.ts | 2 +- drizzle-orm/src/postgres-js/session.ts | 6 +- drizzle-orm/src/prisma/mysql/driver.ts | 2 +- drizzle-orm/src/prisma/mysql/session.ts | 4 +- drizzle-orm/src/prisma/pg/driver.ts | 2 +- drizzle-orm/src/prisma/pg/session.ts | 4 +- drizzle-orm/src/prisma/sqlite/session.ts | 4 +- drizzle-orm/src/relations.ts | 4 +- drizzle-orm/src/sql-js/session.ts | 6 +- drizzle-orm/src/sqlite-core/columns/blob.ts | 12 +- drizzle-orm/src/sqlite-core/columns/common.ts | 4 +- drizzle-orm/src/sqlite-core/columns/custom.ts | 4 +- .../src/sqlite-core/columns/integer.ts | 16 +- .../src/sqlite-core/columns/numeric.ts | 4 +- drizzle-orm/src/sqlite-core/columns/real.ts | 4 +- drizzle-orm/src/sqlite-core/columns/text.ts | 8 +- drizzle-orm/src/sqlite-core/dialect.ts | 4 +- .../src/sqlite-core/query-builders/count.ts | 2 +- .../src/sqlite-core/query-builders/delete.ts | 2 +- .../src/sqlite-core/query-builders/insert.ts | 2 +- .../src/sqlite-core/query-builders/query.ts | 4 +- .../src/sqlite-core/query-builders/raw.ts | 2 +- .../src/sqlite-core/query-builders/select.ts | 4 +- .../src/sqlite-core/query-builders/update.ts | 2 +- drizzle-orm/src/sqlite-core/session.ts | 4 +- drizzle-orm/src/sqlite-core/table.ts | 2 +- drizzle-orm/src/sqlite-core/view-base.ts | 2 +- drizzle-orm/src/sqlite-core/view.ts | 6 +- drizzle-orm/src/sqlite-proxy/driver.ts | 2 +- drizzle-orm/src/sqlite-proxy/session.ts | 6 +- drizzle-orm/src/subquery.ts | 2 +- drizzle-orm/src/tidb-serverless/driver.ts | 2 +- drizzle-orm/src/tidb-serverless/session.ts | 6 +- drizzle-orm/src/vercel-postgres/driver.ts | 2 +- drizzle-orm/src/vercel-postgres/session.ts | 6 +- drizzle-orm/src/xata-http/driver.ts | 2 +- drizzle-orm/src/xata-http/session.ts | 6 +- integration-tests/package.json | 7 +- integration-tests/tests/bun/sqlite-nw.test.ts | 1 + integration-tests/tests/bun/sqlite.test.ts | 1 + integration-tests/tests/common.ts | 2 +- .../tests/sqlite/d1-batch.test.ts | 1 + package.json | 7 +- ...ipt@5.4.5.patch => typescript@5.6.3.patch} | 0 pnpm-lock.yaml | 634 +++++++++++++----- 161 files changed, 782 insertions(+), 511 deletions(-) rename patches/{typescript@5.4.5.patch => typescript@5.6.3.patch} (100%) diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 829441886..cef1a7aef 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -162,7 +162,7 @@ "@cloudflare/workers-types": "^4.20230904.0", "@electric-sql/pglite": "^0.1.1", "@libsql/client": "^0.10.0", - "@miniflare/d1": "^2.14.2", + "@miniflare/d1": "^2.14.4", "@neondatabase/serverless": "^0.9.0", "@op-engineering/op-sqlite": "^2.0.16", "@opentelemetry/api": "^1.4.1", diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index 479cc32fe..5218766ae 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -36,7 +36,7 @@ export interface DrizzleAwsDataApiPgConfig< export class AwsDataApiPgDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'AwsDataApiPgDatabase'; + static override readonly [entityKind]: string = 'AwsDataApiPgDatabase'; override execute< TRow extends Record = Record, @@ -46,7 +46,7 @@ export class AwsDataApiPgDatabase< } export class AwsPgDialect extends PgDialect { - static readonly [entityKind]: string = 'AwsPgDialect'; + static override readonly [entityKind]: string = 'AwsPgDialect'; override escapeParam(num: number): string { return `:${num + 1}`; diff --git a/drizzle-orm/src/aws-data-api/pg/session.ts b/drizzle-orm/src/aws-data-api/pg/session.ts index 4fc43ddf6..974f6d3ff 100644 --- a/drizzle-orm/src/aws-data-api/pg/session.ts +++ b/drizzle-orm/src/aws-data-api/pg/session.ts @@ -27,7 +27,7 @@ export type AwsDataApiClient = RDSDataClient; export class AwsDataApiPreparedQuery< T extends PreparedQueryConfig & { values: AwsDataApiPgQueryResult }, > extends PgPreparedQuery { - static readonly [entityKind]: string = 'AwsDataApiPreparedQuery'; + static override readonly [entityKind]: string = 'AwsDataApiPreparedQuery'; private rawQuery: ExecuteStatementCommand; @@ -154,7 +154,7 @@ export class AwsDataApiSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'AwsDataApiSession'; + static override readonly [entityKind]: string = 'AwsDataApiSession'; /** @internal */ readonly rawQuery: AwsDataApiQueryBase; @@ -239,7 +239,7 @@ export class AwsDataApiTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'AwsDataApiTransaction'; + static override readonly [entityKind]: string = 'AwsDataApiTransaction'; override async transaction( transaction: (tx: AwsDataApiTransaction) => Promise, diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 50660e4d6..b53d2cd38 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -15,7 +15,7 @@ import { BetterSQLiteSession } from './session.ts'; export class BetterSQLite3Database = Record> extends BaseSQLiteDatabase<'sync', RunResult, TSchema> { - static readonly [entityKind]: string = 'BetterSQLite3Database'; + static override readonly [entityKind]: string = 'BetterSQLite3Database'; } export function drizzle = Record>( diff --git a/drizzle-orm/src/better-sqlite3/session.ts b/drizzle-orm/src/better-sqlite3/session.ts index 5b8d29b81..8a02eb37e 100644 --- a/drizzle-orm/src/better-sqlite3/session.ts +++ b/drizzle-orm/src/better-sqlite3/session.ts @@ -26,7 +26,7 @@ export class BetterSQLiteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'sync', RunResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'BetterSQLiteSession'; + static override readonly [entityKind]: string = 'BetterSQLiteSession'; private logger: Logger; @@ -73,7 +73,7 @@ export class BetterSQLiteTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'sync', RunResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'BetterSQLiteTransaction'; + static override readonly [entityKind]: string = 'BetterSQLiteTransaction'; override transaction(transaction: (tx: BetterSQLiteTransaction) => T): T { const savepointName = `sp${this.nestedIndex}`; @@ -93,7 +93,7 @@ export class BetterSQLiteTransaction< export class PreparedQuery extends PreparedQueryBase< { type: 'sync'; run: RunResult; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'BetterSQLitePreparedQuery'; + static override readonly [entityKind]: string = 'BetterSQLitePreparedQuery'; constructor( private stmt: Statement, diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index abcc09224..171573e78 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -17,7 +17,7 @@ import { SQLiteBunSession } from './session.ts'; export class BunSQLiteDatabase< TSchema extends Record = Record, > extends BaseSQLiteDatabase<'sync', void, TSchema> { - static readonly [entityKind]: string = 'BunSQLiteDatabase'; + static override readonly [entityKind]: string = 'BunSQLiteDatabase'; } export function drizzle = Record>( diff --git a/drizzle-orm/src/bun-sqlite/session.ts b/drizzle-orm/src/bun-sqlite/session.ts index ff4da3e6e..fd02e4f00 100644 --- a/drizzle-orm/src/bun-sqlite/session.ts +++ b/drizzle-orm/src/bun-sqlite/session.ts @@ -28,7 +28,7 @@ export class SQLiteBunSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'sync', void, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLiteBunSession'; + static override readonly [entityKind]: string = 'SQLiteBunSession'; private logger: Logger; @@ -83,7 +83,7 @@ export class SQLiteBunTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'sync', void, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLiteBunTransaction'; + static override readonly [entityKind]: string = 'SQLiteBunTransaction'; override transaction(transaction: (tx: SQLiteBunTransaction) => T): T { const savepointName = `sp${this.nestedIndex}`; @@ -103,7 +103,7 @@ export class SQLiteBunTransaction< export class PreparedQuery extends PreparedQueryBase< { type: 'sync'; run: void; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'SQLiteBunPreparedQuery'; + static override readonly [entityKind]: string = 'SQLiteBunPreparedQuery'; constructor( private stmt: Statement, diff --git a/drizzle-orm/src/d1/driver.ts b/drizzle-orm/src/d1/driver.ts index 6ec8a5294..7b4bbdfb6 100644 --- a/drizzle-orm/src/d1/driver.ts +++ b/drizzle-orm/src/d1/driver.ts @@ -24,7 +24,7 @@ export type AnyD1Database = IfNotImported< export class DrizzleD1Database< TSchema extends Record = Record, > extends BaseSQLiteDatabase<'async', D1Result, TSchema> { - static readonly [entityKind]: string = 'D1Database'; + static override readonly [entityKind]: string = 'D1Database'; /** @internal */ declare readonly session: SQLiteD1Session>; diff --git a/drizzle-orm/src/d1/session.ts b/drizzle-orm/src/d1/session.ts index 0f2989c12..61ef49315 100644 --- a/drizzle-orm/src/d1/session.ts +++ b/drizzle-orm/src/d1/session.ts @@ -28,7 +28,7 @@ export class SQLiteD1Session< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'async', D1Result, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLiteD1Session'; + static override readonly [entityKind]: string = 'SQLiteD1Session'; private logger: Logger; @@ -116,7 +116,7 @@ export class D1Transaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'async', D1Result, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'D1Transaction'; + static override readonly [entityKind]: string = 'D1Transaction'; override async transaction(transaction: (tx: D1Transaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex}`; @@ -151,7 +151,7 @@ function d1ToRawMapping(results: any) { export class D1PreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: D1Response; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'D1PreparedQuery'; + static override readonly [entityKind]: string = 'D1PreparedQuery'; /** @internal */ customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown; diff --git a/drizzle-orm/src/errors.ts b/drizzle-orm/src/errors.ts index ede6e0a59..a72615c9b 100644 --- a/drizzle-orm/src/errors.ts +++ b/drizzle-orm/src/errors.ts @@ -11,7 +11,7 @@ export class DrizzleError extends Error { } export class TransactionRollbackError extends DrizzleError { - static readonly [entityKind]: string = 'TransactionRollbackError'; + static override readonly [entityKind]: string = 'TransactionRollbackError'; constructor() { super({ message: 'Rollback' }); diff --git a/drizzle-orm/src/expo-sqlite/driver.ts b/drizzle-orm/src/expo-sqlite/driver.ts index d9cf47b01..6d9ebe375 100644 --- a/drizzle-orm/src/expo-sqlite/driver.ts +++ b/drizzle-orm/src/expo-sqlite/driver.ts @@ -15,7 +15,7 @@ import { ExpoSQLiteSession } from './session.ts'; export class ExpoSQLiteDatabase = Record> extends BaseSQLiteDatabase<'sync', SQLiteRunResult, TSchema> { - static readonly [entityKind]: string = 'ExpoSQLiteDatabase'; + static override readonly [entityKind]: string = 'ExpoSQLiteDatabase'; } export function drizzle = Record>( diff --git a/drizzle-orm/src/expo-sqlite/session.ts b/drizzle-orm/src/expo-sqlite/session.ts index d87236bc2..9fcc4b93c 100644 --- a/drizzle-orm/src/expo-sqlite/session.ts +++ b/drizzle-orm/src/expo-sqlite/session.ts @@ -26,7 +26,7 @@ export class ExpoSQLiteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'sync', SQLiteRunResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'ExpoSQLiteSession'; + static override readonly [entityKind]: string = 'ExpoSQLiteSession'; private logger: Logger; @@ -80,7 +80,7 @@ export class ExpoSQLiteTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'sync', SQLiteRunResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'ExpoSQLiteTransaction'; + static override readonly [entityKind]: string = 'ExpoSQLiteTransaction'; override transaction(transaction: (tx: ExpoSQLiteTransaction) => T): T { const savepointName = `sp${this.nestedIndex}`; @@ -100,7 +100,7 @@ export class ExpoSQLiteTransaction< export class ExpoSQLitePreparedQuery extends SQLitePreparedQuery< { type: 'sync'; run: SQLiteRunResult; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'ExpoSQLitePreparedQuery'; + static override readonly [entityKind]: string = 'ExpoSQLitePreparedQuery'; constructor( private stmt: SQLiteStatement, diff --git a/drizzle-orm/src/libsql/driver.ts b/drizzle-orm/src/libsql/driver.ts index 1e87e7555..2ff0720b1 100644 --- a/drizzle-orm/src/libsql/driver.ts +++ b/drizzle-orm/src/libsql/driver.ts @@ -17,7 +17,7 @@ import { LibSQLSession } from './session.ts'; export class LibSQLDatabase< TSchema extends Record = Record, > extends BaseSQLiteDatabase<'async', ResultSet, TSchema> { - static readonly [entityKind]: string = 'LibSQLDatabase'; + static override readonly [entityKind]: string = 'LibSQLDatabase'; /** @internal */ declare readonly session: LibSQLSession>; diff --git a/drizzle-orm/src/libsql/session.ts b/drizzle-orm/src/libsql/session.ts index 640977734..617ebe342 100644 --- a/drizzle-orm/src/libsql/session.ts +++ b/drizzle-orm/src/libsql/session.ts @@ -27,7 +27,7 @@ export class LibSQLSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'async', ResultSet, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'LibSQLSession'; + static override readonly [entityKind]: string = 'LibSQLSession'; private logger: Logger; @@ -132,7 +132,7 @@ export class LibSQLTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'async', ResultSet, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'LibSQLTransaction'; + static override readonly [entityKind]: string = 'LibSQLTransaction'; override async transaction(transaction: (tx: LibSQLTransaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex}`; @@ -152,7 +152,7 @@ export class LibSQLTransaction< export class LibSQLPreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: ResultSet; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'LibSQLPreparedQuery'; + static override readonly [entityKind]: string = 'LibSQLPreparedQuery'; constructor( private client: Client, diff --git a/drizzle-orm/src/mysql-core/columns/bigint.ts b/drizzle-orm/src/mysql-core/columns/bigint.ts index 5882b1025..7411c07ce 100644 --- a/drizzle-orm/src/mysql-core/columns/bigint.ts +++ b/drizzle-orm/src/mysql-core/columns/bigint.ts @@ -18,7 +18,7 @@ export type MySqlBigInt53BuilderInitial = MySqlBigInt53Bui export class MySqlBigInt53Builder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt53Builder'; + static override readonly [entityKind]: string = 'MySqlBigInt53Builder'; constructor(name: T['name'], unsigned: boolean = false) { super(name, 'number', 'MySqlBigInt53'); @@ -39,7 +39,7 @@ export class MySqlBigInt53Builder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt53'; + static override readonly [entityKind]: string = 'MySqlBigInt53'; getSQLType(): string { return `bigint${this.config.unsigned ? ' unsigned' : ''}`; @@ -66,7 +66,7 @@ export type MySqlBigInt64BuilderInitial = MySqlBigInt64Bui export class MySqlBigInt64Builder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt64Builder'; + static override readonly [entityKind]: string = 'MySqlBigInt64Builder'; constructor(name: T['name'], unsigned: boolean = false) { super(name, 'bigint', 'MySqlBigInt64'); @@ -87,7 +87,7 @@ export class MySqlBigInt64Builder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt64'; + static override readonly [entityKind]: string = 'MySqlBigInt64'; getSQLType(): string { return `bigint${this.config.unsigned ? ' unsigned' : ''}`; diff --git a/drizzle-orm/src/mysql-core/columns/binary.ts b/drizzle-orm/src/mysql-core/columns/binary.ts index 7297d7b0a..7031b565c 100644 --- a/drizzle-orm/src/mysql-core/columns/binary.ts +++ b/drizzle-orm/src/mysql-core/columns/binary.ts @@ -19,7 +19,7 @@ export class MySqlBinaryBuilder { - static readonly [entityKind]: string = 'MySqlBinaryBuilder'; + static override readonly [entityKind]: string = 'MySqlBinaryBuilder'; constructor(name: T['name'], length: number | undefined) { super(name, 'string', 'MySqlBinary'); @@ -38,7 +38,7 @@ export class MySqlBinary> ex T, MySqlBinaryConfig > { - static readonly [entityKind]: string = 'MySqlBinary'; + static override readonly [entityKind]: string = 'MySqlBinary'; length: number | undefined = this.config.length; diff --git a/drizzle-orm/src/mysql-core/columns/boolean.ts b/drizzle-orm/src/mysql-core/columns/boolean.ts index d1df78570..9e786b6f9 100644 --- a/drizzle-orm/src/mysql-core/columns/boolean.ts +++ b/drizzle-orm/src/mysql-core/columns/boolean.ts @@ -17,7 +17,7 @@ export type MySqlBooleanBuilderInitial = MySqlBooleanBuild export class MySqlBooleanBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlBooleanBuilder'; + static override readonly [entityKind]: string = 'MySqlBooleanBuilder'; constructor(name: T['name']) { super(name, 'boolean', 'MySqlBoolean'); @@ -35,7 +35,7 @@ export class MySqlBooleanBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlBoolean'; + static override readonly [entityKind]: string = 'MySqlBoolean'; getSQLType(): string { return 'boolean'; diff --git a/drizzle-orm/src/mysql-core/columns/char.ts b/drizzle-orm/src/mysql-core/columns/char.ts index 019c035ba..efcb7e65a 100644 --- a/drizzle-orm/src/mysql-core/columns/char.ts +++ b/drizzle-orm/src/mysql-core/columns/char.ts @@ -19,7 +19,7 @@ export class MySqlCharBuilder > { - static readonly [entityKind]: string = 'MySqlCharBuilder'; + static override readonly [entityKind]: string = 'MySqlCharBuilder'; constructor(name: T['name'], config: MySqlCharConfig) { super(name, 'string', 'MySqlChar'); @@ -41,7 +41,7 @@ export class MySqlCharBuilder> extends MySqlColumn> { - static readonly [entityKind]: string = 'MySqlChar'; + static override readonly [entityKind]: string = 'MySqlChar'; readonly length: number | undefined = this.config.length; override readonly enumValues = this.config.enum; diff --git a/drizzle-orm/src/mysql-core/columns/common.ts b/drizzle-orm/src/mysql-core/columns/common.ts index a0a192477..9babc31da 100644 --- a/drizzle-orm/src/mysql-core/columns/common.ts +++ b/drizzle-orm/src/mysql-core/columns/common.ts @@ -47,7 +47,7 @@ export abstract class MySqlColumnBuilder< > extends ColumnBuilder implements MySqlColumnBuilderBase { - static readonly [entityKind]: string = 'MySqlColumnBuilder'; + static override readonly [entityKind]: string = 'MySqlColumnBuilder'; private foreignKeyConfigs: ReferenceConfig[] = []; @@ -101,7 +101,7 @@ export abstract class MySqlColumn< T extends ColumnBaseConfig = ColumnBaseConfig, TRuntimeConfig extends object = object, > extends Column { - static readonly [entityKind]: string = 'MySqlColumn'; + static override readonly [entityKind]: string = 'MySqlColumn'; constructor( override readonly table: MySqlTable, @@ -127,7 +127,7 @@ export abstract class MySqlColumnBuilderWithAutoIncrement< TRuntimeConfig extends object = object, TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, > extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlColumnBuilderWithAutoIncrement'; + static override readonly [entityKind]: string = 'MySqlColumnBuilderWithAutoIncrement'; constructor(name: NonNullable, dataType: T['dataType'], columnType: T['columnType']) { super(name, dataType, columnType); @@ -145,7 +145,7 @@ export abstract class MySqlColumnWithAutoIncrement< T extends ColumnBaseConfig = ColumnBaseConfig, TRuntimeConfig extends object = object, > extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlColumnWithAutoIncrement'; + static override readonly [entityKind]: string = 'MySqlColumnWithAutoIncrement'; readonly autoIncrement: boolean = this.config.autoIncrement; } diff --git a/drizzle-orm/src/mysql-core/columns/custom.ts b/drizzle-orm/src/mysql-core/columns/custom.ts index 35ca19d3d..711b27813 100644 --- a/drizzle-orm/src/mysql-core/columns/custom.ts +++ b/drizzle-orm/src/mysql-core/columns/custom.ts @@ -35,7 +35,7 @@ export class MySqlCustomColumnBuilder { - static readonly [entityKind]: string = 'MySqlCustomColumnBuilder'; + static override readonly [entityKind]: string = 'MySqlCustomColumnBuilder'; constructor( name: T['name'], @@ -59,7 +59,7 @@ export class MySqlCustomColumnBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlCustomColumn'; + static override readonly [entityKind]: string = 'MySqlCustomColumn'; private sqlName: string; private mapTo?: (value: T['data']) => T['driverParam']; diff --git a/drizzle-orm/src/mysql-core/columns/date.common.ts b/drizzle-orm/src/mysql-core/columns/date.common.ts index 3fd8aa612..75faad5b8 100644 --- a/drizzle-orm/src/mysql-core/columns/date.common.ts +++ b/drizzle-orm/src/mysql-core/columns/date.common.ts @@ -18,7 +18,7 @@ export abstract class MySqlDateColumnBaseBuilder< TRuntimeConfig extends object = object, TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, > extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateColumnBuilder'; + static override readonly [entityKind]: string = 'MySqlDateColumnBuilder'; defaultNow() { return this.default(sql`(now())`); @@ -36,7 +36,7 @@ export abstract class MySqlDateBaseColumn< T extends ColumnBaseConfig, TRuntimeConfig extends object = object, > extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateColumn'; + static override readonly [entityKind]: string = 'MySqlDateColumn'; readonly hasOnUpdateNow: boolean = this.config.hasOnUpdateNow; } diff --git a/drizzle-orm/src/mysql-core/columns/date.ts b/drizzle-orm/src/mysql-core/columns/date.ts index 17ad8d8be..318fac65d 100644 --- a/drizzle-orm/src/mysql-core/columns/date.ts +++ b/drizzle-orm/src/mysql-core/columns/date.ts @@ -16,7 +16,7 @@ export type MySqlDateBuilderInitial = MySqlDateBuilder<{ }>; export class MySqlDateBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateBuilder'; + static override readonly [entityKind]: string = 'MySqlDateBuilder'; constructor(name: T['name']) { super(name, 'date', 'MySqlDate'); @@ -31,7 +31,7 @@ export class MySqlDateBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDate'; + static override readonly [entityKind]: string = 'MySqlDate'; constructor( table: AnyMySqlTable<{ name: T['tableName'] }>, @@ -62,7 +62,7 @@ export type MySqlDateStringBuilderInitial = MySqlDateStrin export class MySqlDateStringBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateStringBuilder'; + static override readonly [entityKind]: string = 'MySqlDateStringBuilder'; constructor(name: T['name']) { super(name, 'string', 'MySqlDateString'); @@ -80,7 +80,7 @@ export class MySqlDateStringBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateString'; + static override readonly [entityKind]: string = 'MySqlDateString'; constructor( table: AnyMySqlTable<{ name: T['tableName'] }>, diff --git a/drizzle-orm/src/mysql-core/columns/datetime.ts b/drizzle-orm/src/mysql-core/columns/datetime.ts index 39b0bae32..61b062e8f 100644 --- a/drizzle-orm/src/mysql-core/columns/datetime.ts +++ b/drizzle-orm/src/mysql-core/columns/datetime.ts @@ -18,7 +18,7 @@ export type MySqlDateTimeBuilderInitial = MySqlDateTimeBui export class MySqlDateTimeBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateTimeBuilder'; + static override readonly [entityKind]: string = 'MySqlDateTimeBuilder'; constructor(name: T['name'], config: MySqlDatetimeConfig | undefined) { super(name, 'date', 'MySqlDateTime'); @@ -37,7 +37,7 @@ export class MySqlDateTimeBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateTime'; + static override readonly [entityKind]: string = 'MySqlDateTime'; readonly fsp: number | undefined; @@ -76,7 +76,7 @@ export type MySqlDateTimeStringBuilderInitial = MySqlDateT export class MySqlDateTimeStringBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateTimeStringBuilder'; + static override readonly [entityKind]: string = 'MySqlDateTimeStringBuilder'; constructor(name: T['name'], config: MySqlDatetimeConfig | undefined) { super(name, 'string', 'MySqlDateTimeString'); @@ -95,7 +95,7 @@ export class MySqlDateTimeStringBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateTimeString'; + static override readonly [entityKind]: string = 'MySqlDateTimeString'; readonly fsp: number | undefined; diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index 3b01923e4..1e5f78679 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -18,7 +18,7 @@ export type MySqlDecimalBuilderInitial = MySqlDecimalBuild export class MySqlDecimalBuilder< T extends ColumnBuilderBaseConfig<'string', 'MySqlDecimal'>, > extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDecimalBuilder'; + static override readonly [entityKind]: string = 'MySqlDecimalBuilder'; constructor(name: T['name'], precision?: number, scale?: number) { super(name, 'string', 'MySqlDecimal'); @@ -40,7 +40,7 @@ export class MySqlDecimalBuilder< export class MySqlDecimal> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDecimal'; + static override readonly [entityKind]: string = 'MySqlDecimal'; readonly precision: number | undefined = this.config.precision; readonly scale: number | undefined = this.config.scale; diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index 0324025b8..c9f95fd04 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -18,7 +18,7 @@ export type MySqlDoubleBuilderInitial = MySqlDoubleBuilder export class MySqlDoubleBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDoubleBuilder'; + static override readonly [entityKind]: string = 'MySqlDoubleBuilder'; constructor(name: T['name'], config: MySqlDoubleConfig | undefined) { super(name, 'number', 'MySqlDouble'); @@ -37,7 +37,7 @@ export class MySqlDoubleBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDouble'; + static override readonly [entityKind]: string = 'MySqlDouble'; precision: number | undefined = this.config.precision; scale: number | undefined = this.config.scale; diff --git a/drizzle-orm/src/mysql-core/columns/enum.ts b/drizzle-orm/src/mysql-core/columns/enum.ts index de1d41cdd..6a586ca7c 100644 --- a/drizzle-orm/src/mysql-core/columns/enum.ts +++ b/drizzle-orm/src/mysql-core/columns/enum.ts @@ -19,7 +19,7 @@ export type MySqlEnumColumnBuilderInitial> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlEnumColumnBuilder'; + static override readonly [entityKind]: string = 'MySqlEnumColumnBuilder'; constructor(name: T['name'], values: T['enumValues']) { super(name, 'string', 'MySqlEnumColumn'); @@ -40,7 +40,7 @@ export class MySqlEnumColumnBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlEnumColumn'; + static override readonly [entityKind]: string = 'MySqlEnumColumn'; override readonly enumValues = this.config.enumValues; diff --git a/drizzle-orm/src/mysql-core/columns/float.ts b/drizzle-orm/src/mysql-core/columns/float.ts index 88b989077..d7c3e586b 100644 --- a/drizzle-orm/src/mysql-core/columns/float.ts +++ b/drizzle-orm/src/mysql-core/columns/float.ts @@ -17,7 +17,7 @@ export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ export class MySqlFloatBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlFloatBuilder'; + static override readonly [entityKind]: string = 'MySqlFloatBuilder'; constructor(name: T['name']) { super(name, 'number', 'MySqlFloat'); @@ -32,7 +32,7 @@ export class MySqlFloatBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlFloat'; + static override readonly [entityKind]: string = 'MySqlFloat'; getSQLType(): string { return 'float'; diff --git a/drizzle-orm/src/mysql-core/columns/int.ts b/drizzle-orm/src/mysql-core/columns/int.ts index 4902bc593..aca0ea61e 100644 --- a/drizzle-orm/src/mysql-core/columns/int.ts +++ b/drizzle-orm/src/mysql-core/columns/int.ts @@ -18,7 +18,7 @@ export type MySqlIntBuilderInitial = MySqlIntBuilder<{ export class MySqlIntBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlIntBuilder'; + static override readonly [entityKind]: string = 'MySqlIntBuilder'; constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlInt'); @@ -36,7 +36,7 @@ export class MySqlIntBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlInt'; + static override readonly [entityKind]: string = 'MySqlInt'; getSQLType(): string { return `int${this.config.unsigned ? ' unsigned' : ''}`; diff --git a/drizzle-orm/src/mysql-core/columns/json.ts b/drizzle-orm/src/mysql-core/columns/json.ts index d57cf963c..ecb73ed82 100644 --- a/drizzle-orm/src/mysql-core/columns/json.ts +++ b/drizzle-orm/src/mysql-core/columns/json.ts @@ -15,7 +15,7 @@ export type MySqlJsonBuilderInitial = MySqlJsonBuilder<{ }>; export class MySqlJsonBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlJsonBuilder'; + static override readonly [entityKind]: string = 'MySqlJsonBuilder'; constructor(name: T['name']) { super(name, 'json', 'MySqlJson'); @@ -30,7 +30,7 @@ export class MySqlJsonBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlJson'; + static override readonly [entityKind]: string = 'MySqlJson'; getSQLType(): string { return 'json'; diff --git a/drizzle-orm/src/mysql-core/columns/mediumint.ts b/drizzle-orm/src/mysql-core/columns/mediumint.ts index 237090179..764969d31 100644 --- a/drizzle-orm/src/mysql-core/columns/mediumint.ts +++ b/drizzle-orm/src/mysql-core/columns/mediumint.ts @@ -19,7 +19,7 @@ export type MySqlMediumIntBuilderInitial = MySqlMediumIntB export class MySqlMediumIntBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlMediumIntBuilder'; + static override readonly [entityKind]: string = 'MySqlMediumIntBuilder'; constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlMediumInt'); @@ -40,7 +40,7 @@ export class MySqlMediumIntBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlMediumInt'; + static override readonly [entityKind]: string = 'MySqlMediumInt'; getSQLType(): string { return `mediumint${this.config.unsigned ? ' unsigned' : ''}`; diff --git a/drizzle-orm/src/mysql-core/columns/real.ts b/drizzle-orm/src/mysql-core/columns/real.ts index 2a921f1aa..8b9eca794 100644 --- a/drizzle-orm/src/mysql-core/columns/real.ts +++ b/drizzle-orm/src/mysql-core/columns/real.ts @@ -21,7 +21,7 @@ export class MySqlRealBuilder { - static readonly [entityKind]: string = 'MySqlRealBuilder'; + static override readonly [entityKind]: string = 'MySqlRealBuilder'; constructor(name: T['name'], config: MySqlRealConfig | undefined) { super(name, 'number', 'MySqlReal'); @@ -41,7 +41,7 @@ export class MySqlReal> extend T, MySqlRealConfig > { - static readonly [entityKind]: string = 'MySqlReal'; + static override readonly [entityKind]: string = 'MySqlReal'; precision: number | undefined = this.config.precision; scale: number | undefined = this.config.scale; diff --git a/drizzle-orm/src/mysql-core/columns/serial.ts b/drizzle-orm/src/mysql-core/columns/serial.ts index 43af900a1..88485d6b2 100644 --- a/drizzle-orm/src/mysql-core/columns/serial.ts +++ b/drizzle-orm/src/mysql-core/columns/serial.ts @@ -33,7 +33,7 @@ export type MySqlSerialBuilderInitial = IsAutoincrement< export class MySqlSerialBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSerialBuilder'; + static override readonly [entityKind]: string = 'MySqlSerialBuilder'; constructor(name: T['name']) { super(name, 'number', 'MySqlSerial'); @@ -52,7 +52,7 @@ export class MySqlSerialBuilder, > extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSerial'; + static override readonly [entityKind]: string = 'MySqlSerial'; getSQLType(): string { return 'serial'; diff --git a/drizzle-orm/src/mysql-core/columns/smallint.ts b/drizzle-orm/src/mysql-core/columns/smallint.ts index e6801e214..482ff89ea 100644 --- a/drizzle-orm/src/mysql-core/columns/smallint.ts +++ b/drizzle-orm/src/mysql-core/columns/smallint.ts @@ -19,7 +19,7 @@ export type MySqlSmallIntBuilderInitial = MySqlSmallIntBui export class MySqlSmallIntBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSmallIntBuilder'; + static override readonly [entityKind]: string = 'MySqlSmallIntBuilder'; constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlSmallInt'); @@ -40,7 +40,7 @@ export class MySqlSmallIntBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSmallInt'; + static override readonly [entityKind]: string = 'MySqlSmallInt'; getSQLType(): string { return `smallint${this.config.unsigned ? ' unsigned' : ''}`; diff --git a/drizzle-orm/src/mysql-core/columns/text.ts b/drizzle-orm/src/mysql-core/columns/text.ts index c90362dc5..18434a532 100644 --- a/drizzle-orm/src/mysql-core/columns/text.ts +++ b/drizzle-orm/src/mysql-core/columns/text.ts @@ -21,7 +21,7 @@ export class MySqlTextBuilder { - static readonly [entityKind]: string = 'MySqlTextBuilder'; + static override readonly [entityKind]: string = 'MySqlTextBuilder'; constructor(name: T['name'], textType: MySqlTextColumnType, config: MySqlTextConfig) { super(name, 'string', 'MySqlText'); @@ -40,7 +40,7 @@ export class MySqlTextBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlText'; + static override readonly [entityKind]: string = 'MySqlText'; private textType: MySqlTextColumnType = this.config.textType; diff --git a/drizzle-orm/src/mysql-core/columns/time.ts b/drizzle-orm/src/mysql-core/columns/time.ts index e862d9fa3..408453947 100644 --- a/drizzle-orm/src/mysql-core/columns/time.ts +++ b/drizzle-orm/src/mysql-core/columns/time.ts @@ -19,7 +19,7 @@ export class MySqlTimeBuilder { - static readonly [entityKind]: string = 'MySqlTimeBuilder'; + static override readonly [entityKind]: string = 'MySqlTimeBuilder'; constructor( name: T['name'], @@ -40,7 +40,7 @@ export class MySqlTimeBuilder, > extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlTime'; + static override readonly [entityKind]: string = 'MySqlTime'; readonly fsp: number | undefined = this.config.fsp; diff --git a/drizzle-orm/src/mysql-core/columns/timestamp.ts b/drizzle-orm/src/mysql-core/columns/timestamp.ts index 07649ba94..892f8e603 100644 --- a/drizzle-orm/src/mysql-core/columns/timestamp.ts +++ b/drizzle-orm/src/mysql-core/columns/timestamp.ts @@ -18,7 +18,7 @@ export type MySqlTimestampBuilderInitial = MySqlTimestampB export class MySqlTimestampBuilder> extends MySqlDateColumnBaseBuilder { - static readonly [entityKind]: string = 'MySqlTimestampBuilder'; + static override readonly [entityKind]: string = 'MySqlTimestampBuilder'; constructor(name: T['name'], config: MySqlTimestampConfig | undefined) { super(name, 'date', 'MySqlTimestamp'); @@ -39,7 +39,7 @@ export class MySqlTimestampBuilder> extends MySqlDateBaseColumn { - static readonly [entityKind]: string = 'MySqlTimestamp'; + static override readonly [entityKind]: string = 'MySqlTimestamp'; readonly fsp: number | undefined = this.config.fsp; @@ -70,7 +70,7 @@ export type MySqlTimestampStringBuilderInitial = MySqlTime export class MySqlTimestampStringBuilder> extends MySqlDateColumnBaseBuilder { - static readonly [entityKind]: string = 'MySqlTimestampStringBuilder'; + static override readonly [entityKind]: string = 'MySqlTimestampStringBuilder'; constructor(name: T['name'], config: MySqlTimestampConfig | undefined) { super(name, 'string', 'MySqlTimestampString'); @@ -91,7 +91,7 @@ export class MySqlTimestampStringBuilder> extends MySqlDateBaseColumn { - static readonly [entityKind]: string = 'MySqlTimestampString'; + static override readonly [entityKind]: string = 'MySqlTimestampString'; readonly fsp: number | undefined = this.config.fsp; diff --git a/drizzle-orm/src/mysql-core/columns/tinyint.ts b/drizzle-orm/src/mysql-core/columns/tinyint.ts index a9d7e967b..ee4ccdaa7 100644 --- a/drizzle-orm/src/mysql-core/columns/tinyint.ts +++ b/drizzle-orm/src/mysql-core/columns/tinyint.ts @@ -19,7 +19,7 @@ export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuild export class MySqlTinyIntBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlTinyIntBuilder'; + static override readonly [entityKind]: string = 'MySqlTinyIntBuilder'; constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlTinyInt'); @@ -40,7 +40,7 @@ export class MySqlTinyIntBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlTinyInt'; + static override readonly [entityKind]: string = 'MySqlTinyInt'; getSQLType(): string { return `tinyint${this.config.unsigned ? ' unsigned' : ''}`; diff --git a/drizzle-orm/src/mysql-core/columns/varbinary.ts b/drizzle-orm/src/mysql-core/columns/varbinary.ts index ed6b90b7a..bc0dde635 100644 --- a/drizzle-orm/src/mysql-core/columns/varbinary.ts +++ b/drizzle-orm/src/mysql-core/columns/varbinary.ts @@ -18,7 +18,7 @@ export type MySqlVarBinaryBuilderInitial = MySqlVarBinaryB export class MySqlVarBinaryBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlVarBinaryBuilder'; + static override readonly [entityKind]: string = 'MySqlVarBinaryBuilder'; /** @internal */ constructor(name: T['name'], config: MySqlVarbinaryOptions) { @@ -40,7 +40,7 @@ export class MySqlVarBinaryBuilder, > extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlVarBinary'; + static override readonly [entityKind]: string = 'MySqlVarBinary'; length: number | undefined = this.config.length; diff --git a/drizzle-orm/src/mysql-core/columns/varchar.ts b/drizzle-orm/src/mysql-core/columns/varchar.ts index b05cf7523..32cfda7e9 100644 --- a/drizzle-orm/src/mysql-core/columns/varchar.ts +++ b/drizzle-orm/src/mysql-core/columns/varchar.ts @@ -20,7 +20,7 @@ export type MySqlVarCharBuilderInitial> extends MySqlColumnBuilder> { - static readonly [entityKind]: string = 'MySqlVarCharBuilder'; + static override readonly [entityKind]: string = 'MySqlVarCharBuilder'; /** @internal */ constructor(name: T['name'], config: MySqlVarCharConfig) { @@ -43,7 +43,7 @@ export class MySqlVarCharBuilder> extends MySqlColumn> { - static readonly [entityKind]: string = 'MySqlVarChar'; + static override readonly [entityKind]: string = 'MySqlVarChar'; readonly length: number | undefined = this.config.length; diff --git a/drizzle-orm/src/mysql-core/columns/year.ts b/drizzle-orm/src/mysql-core/columns/year.ts index 27a81f887..8a7a44410 100644 --- a/drizzle-orm/src/mysql-core/columns/year.ts +++ b/drizzle-orm/src/mysql-core/columns/year.ts @@ -15,7 +15,7 @@ export type MySqlYearBuilderInitial = MySqlYearBuilder<{ }>; export class MySqlYearBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlYearBuilder'; + static override readonly [entityKind]: string = 'MySqlYearBuilder'; constructor(name: T['name']) { super(name, 'number', 'MySqlYear'); @@ -32,7 +32,7 @@ export class MySqlYearBuilder, > extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlYear'; + static override readonly [entityKind]: string = 'MySqlYear'; getSQLType(): string { return `year`; diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index e61b27011..9a0241c70 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -9,7 +9,7 @@ export class MySqlCountBuilder< > extends SQL implements Promise, SQLWrapper { private sql: SQL; - static readonly [entityKind] = 'MySqlCountBuilder'; + static override readonly [entityKind] = 'MySqlCountBuilder'; [Symbol.toStringTag] = 'MySqlCountBuilder'; private session: TSession; diff --git a/drizzle-orm/src/mysql-core/query-builders/delete.ts b/drizzle-orm/src/mysql-core/query-builders/delete.ts index e9a48da8e..d9a5d0c51 100644 --- a/drizzle-orm/src/mysql-core/query-builders/delete.ts +++ b/drizzle-orm/src/mysql-core/query-builders/delete.ts @@ -86,7 +86,7 @@ export class MySqlDeleteBase< // eslint-disable-next-line @typescript-eslint/no-unused-vars TExcludedMethods extends string = never, > extends QueryPromise> implements SQLWrapper { - static readonly [entityKind]: string = 'MySqlDelete'; + static override readonly [entityKind]: string = 'MySqlDelete'; private config: MySqlDeleteConfig; diff --git a/drizzle-orm/src/mysql-core/query-builders/insert.ts b/drizzle-orm/src/mysql-core/query-builders/insert.ts index 97e61de74..fe9f7d7ba 100644 --- a/drizzle-orm/src/mysql-core/query-builders/insert.ts +++ b/drizzle-orm/src/mysql-core/query-builders/insert.ts @@ -190,7 +190,7 @@ export class MySqlInsertBase< RunnableQuery : TReturning[], 'mysql'>, SQLWrapper { - static readonly [entityKind]: string = 'MySqlInsert'; + static override readonly [entityKind]: string = 'MySqlInsert'; declare protected $table: TTable; diff --git a/drizzle-orm/src/mysql-core/query-builders/query.ts b/drizzle-orm/src/mysql-core/query-builders/query.ts index 955f73428..16d294598 100644 --- a/drizzle-orm/src/mysql-core/query-builders/query.ts +++ b/drizzle-orm/src/mysql-core/query-builders/query.ts @@ -77,7 +77,7 @@ export class MySqlRelationalQuery< TPreparedQueryHKT extends PreparedQueryHKTBase, TResult, > extends QueryPromise { - static readonly [entityKind]: string = 'MySqlRelationalQuery'; + static override readonly [entityKind]: string = 'MySqlRelationalQuery'; declare protected $brand: 'MySqlRelationalQuery'; diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index a5a0ca69a..95f67827b 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -132,7 +132,7 @@ export abstract class MySqlSelectQueryBuilderBase< TResult extends any[] = SelectResult[], TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > extends TypedQueryBuilder { - static readonly [entityKind]: string = 'MySqlSelectQueryBuilder'; + static override readonly [entityKind]: string = 'MySqlSelectQueryBuilder'; override readonly _: { readonly hkt: THKT; @@ -942,7 +942,7 @@ export class MySqlSelectBase< TResult, TSelectedFields > { - static readonly [entityKind]: string = 'MySqlSelect'; + static override readonly [entityKind]: string = 'MySqlSelect'; prepare(): MySqlSelectPrepare { if (!this.session) { diff --git a/drizzle-orm/src/mysql-core/query-builders/update.ts b/drizzle-orm/src/mysql-core/query-builders/update.ts index 7884599cf..f6d643168 100644 --- a/drizzle-orm/src/mysql-core/query-builders/update.ts +++ b/drizzle-orm/src/mysql-core/query-builders/update.ts @@ -120,7 +120,7 @@ export class MySqlUpdateBase< // eslint-disable-next-line @typescript-eslint/no-unused-vars TExcludedMethods extends string = never, > extends QueryPromise> implements SQLWrapper { - static readonly [entityKind]: string = 'MySqlUpdate'; + static override readonly [entityKind]: string = 'MySqlUpdate'; private config: MySqlUpdateConfig; diff --git a/drizzle-orm/src/mysql-core/session.ts b/drizzle-orm/src/mysql-core/session.ts index 021d4276d..326b0ad61 100644 --- a/drizzle-orm/src/mysql-core/session.ts +++ b/drizzle-orm/src/mysql-core/session.ts @@ -130,7 +130,7 @@ export abstract class MySqlTransaction< TFullSchema extends Record = Record, TSchema extends TablesRelationalConfig = Record, > extends MySqlDatabase { - static readonly [entityKind]: string = 'MySqlTransaction'; + static override readonly [entityKind]: string = 'MySqlTransaction'; constructor( dialect: MySqlDialect, diff --git a/drizzle-orm/src/mysql-core/table.ts b/drizzle-orm/src/mysql-core/table.ts index 36c366d61..e09278dc5 100644 --- a/drizzle-orm/src/mysql-core/table.ts +++ b/drizzle-orm/src/mysql-core/table.ts @@ -24,7 +24,7 @@ export type TableConfig = TableConfigBase; export const InlineForeignKeys = Symbol.for('drizzle:MySqlInlineForeignKeys'); export class MySqlTable extends Table { - static readonly [entityKind]: string = 'MySqlTable'; + static override readonly [entityKind]: string = 'MySqlTable'; declare protected $columns: T['columns']; diff --git a/drizzle-orm/src/mysql-core/view-base.ts b/drizzle-orm/src/mysql-core/view-base.ts index 46b1527d9..fa8a25cfa 100644 --- a/drizzle-orm/src/mysql-core/view-base.ts +++ b/drizzle-orm/src/mysql-core/view-base.ts @@ -7,7 +7,7 @@ export abstract class MySqlViewBase< TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, > extends View { - static readonly [entityKind]: string = 'MySqlViewBase'; + static override readonly [entityKind]: string = 'MySqlViewBase'; declare readonly _: View['_'] & { readonly viewBrand: 'MySqlViewBase'; diff --git a/drizzle-orm/src/mysql-core/view.ts b/drizzle-orm/src/mysql-core/view.ts index 4cc7d416c..3f680e39b 100644 --- a/drizzle-orm/src/mysql-core/view.ts +++ b/drizzle-orm/src/mysql-core/view.ts @@ -64,7 +64,7 @@ export class ViewBuilderCore extends ViewBuilderCore<{ name: TName }> { - static readonly [entityKind]: string = 'MySqlViewBuilder'; + static override readonly [entityKind]: string = 'MySqlViewBuilder'; as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), @@ -98,7 +98,7 @@ export class ManualViewBuilder< TName extends string = string, TColumns extends Record = Record, > extends ViewBuilderCore<{ name: TName; columns: TColumns }> { - static readonly [entityKind]: string = 'MySqlManualViewBuilder'; + static override readonly [entityKind]: string = 'MySqlManualViewBuilder'; private columns: Record; @@ -157,7 +157,7 @@ export class MySqlView< TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, > extends MySqlViewBase { - static readonly [entityKind]: string = 'MySqlView'; + static override readonly [entityKind]: string = 'MySqlView'; declare protected $MySqlViewBrand: 'MySqlView'; diff --git a/drizzle-orm/src/mysql-proxy/driver.ts b/drizzle-orm/src/mysql-proxy/driver.ts index badefb02e..bb0c21134 100644 --- a/drizzle-orm/src/mysql-proxy/driver.ts +++ b/drizzle-orm/src/mysql-proxy/driver.ts @@ -14,7 +14,7 @@ import { type MySqlRemotePreparedQueryHKT, type MySqlRemoteQueryResultHKT, MySql export class MySqlRemoteDatabase< TSchema extends Record = Record, > extends MySqlDatabase { - static readonly [entityKind]: string = 'MySqlRemoteDatabase'; + static override readonly [entityKind]: string = 'MySqlRemoteDatabase'; } export type RemoteCallback = ( diff --git a/drizzle-orm/src/mysql-proxy/session.ts b/drizzle-orm/src/mysql-proxy/session.ts index 03039cfb2..e72875e79 100644 --- a/drizzle-orm/src/mysql-proxy/session.ts +++ b/drizzle-orm/src/mysql-proxy/session.ts @@ -30,7 +30,7 @@ export class MySqlRemoteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlSession { - static readonly [entityKind]: string = 'MySqlRemoteSession'; + static override readonly [entityKind]: string = 'MySqlRemoteSession'; private logger: Logger; @@ -81,7 +81,7 @@ export class MySqlProxyTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlTransaction { - static readonly [entityKind]: string = 'MySqlProxyTransaction'; + static override readonly [entityKind]: string = 'MySqlProxyTransaction'; override async transaction( _transaction: (tx: MySqlProxyTransaction) => Promise, @@ -91,7 +91,7 @@ export class MySqlProxyTransaction< } export class PreparedQuery extends PreparedQueryBase { - static readonly [entityKind]: string = 'MySqlProxyPreparedQuery'; + static override readonly [entityKind]: string = 'MySqlProxyPreparedQuery'; constructor( private client: RemoteCallback, diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index 13e296ab9..842db2d06 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -43,7 +43,7 @@ export { MySqlDatabase } from '~/mysql-core/db.ts'; export class MySql2Database< TSchema extends Record = Record, > extends MySqlDatabase { - static readonly [entityKind]: string = 'MySql2Database'; + static override readonly [entityKind]: string = 'MySql2Database'; } export type MySql2DrizzleConfig = Record> = diff --git a/drizzle-orm/src/mysql2/session.ts b/drizzle-orm/src/mysql2/session.ts index ab11d1f17..7ca21c4a6 100644 --- a/drizzle-orm/src/mysql2/session.ts +++ b/drizzle-orm/src/mysql2/session.ts @@ -41,7 +41,7 @@ export type MySqlQueryResult< > = [T extends ResultSetHeader ? T : T[], FieldPacket[]]; export class MySql2PreparedQuery extends MySqlPreparedQuery { - static readonly [entityKind]: string = 'MySql2PreparedQuery'; + static override readonly [entityKind]: string = 'MySql2PreparedQuery'; private rawQuery: QueryOptions; private query: QueryOptions; @@ -190,7 +190,7 @@ export class MySql2Session< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlSession { - static readonly [entityKind]: string = 'MySql2Session'; + static override readonly [entityKind]: string = 'MySql2Session'; private logger: Logger; private mode: Mode; @@ -301,7 +301,7 @@ export class MySql2Transaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlTransaction { - static readonly [entityKind]: string = 'MySql2Transaction'; + static override readonly [entityKind]: string = 'MySql2Transaction'; override async transaction(transaction: (tx: MySql2Transaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex + 1}`; diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index e85204a62..cadda2da9 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -43,7 +43,7 @@ export class NeonHttpDriver { export class NeonHttpDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'NeonHttpDatabase'; + static override readonly [entityKind]: string = 'NeonHttpDatabase'; /** @internal */ declare readonly session: NeonHttpSession>; diff --git a/drizzle-orm/src/neon-http/session.ts b/drizzle-orm/src/neon-http/session.ts index 4dd768d3e..cd4a855e7 100644 --- a/drizzle-orm/src/neon-http/session.ts +++ b/drizzle-orm/src/neon-http/session.ts @@ -25,7 +25,7 @@ const queryConfig = { } as const; export class NeonHttpPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'NeonHttpPreparedQuery'; + static override readonly [entityKind]: string = 'NeonHttpPreparedQuery'; constructor( private client: NeonHttpClient, @@ -94,7 +94,7 @@ export class NeonHttpSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'NeonHttpSession'; + static override readonly [entityKind]: string = 'NeonHttpSession'; private logger: Logger; @@ -182,7 +182,7 @@ export class NeonTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'NeonHttpTransaction'; + static override readonly [entityKind]: string = 'NeonHttpTransaction'; override async transaction(_transaction: (tx: NeonTransaction) => Promise): Promise { throw new Error('No transactions support in neon-http driver'); diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index 7ee72814b..d94972e1c 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -46,7 +46,7 @@ export class NeonDriver { export class NeonDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'NeonServerlessDatabase'; + static override readonly [entityKind]: string = 'NeonServerlessDatabase'; } export function drizzle< diff --git a/drizzle-orm/src/neon-serverless/session.ts b/drizzle-orm/src/neon-serverless/session.ts index 82c405333..293050715 100644 --- a/drizzle-orm/src/neon-serverless/session.ts +++ b/drizzle-orm/src/neon-serverless/session.ts @@ -22,7 +22,7 @@ import { type Assume, mapResultRow } from '~/utils.ts'; export type NeonClient = Pool | PoolClient | Client; export class NeonPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'NeonPreparedQuery'; + static override readonly [entityKind]: string = 'NeonPreparedQuery'; private rawQueryConfig: QueryConfig; private queryConfig: QueryArrayConfig; @@ -93,7 +93,7 @@ export class NeonSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'NeonSession'; + static override readonly [entityKind]: string = 'NeonSession'; private logger: Logger; @@ -171,7 +171,7 @@ export class NeonTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'NeonTransaction'; + static override readonly [entityKind]: string = 'NeonTransaction'; override async transaction(transaction: (tx: NeonTransaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex + 1}`; diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index 79a99a3fa..9c883816b 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -48,7 +48,7 @@ export class NodePgDriver { export class NodePgDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'NodePgDatabase'; + static override readonly [entityKind]: string = 'NodePgDatabase'; } export function drizzle< diff --git a/drizzle-orm/src/node-postgres/session.ts b/drizzle-orm/src/node-postgres/session.ts index ef6779354..a886f3782 100644 --- a/drizzle-orm/src/node-postgres/session.ts +++ b/drizzle-orm/src/node-postgres/session.ts @@ -17,7 +17,7 @@ const { Pool } = pg; export type NodePgClient = pg.Pool | PoolClient | Client; export class NodePgPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'NodePgPreparedQuery'; + static override readonly [entityKind]: string = 'NodePgPreparedQuery'; private rawQueryConfig: QueryConfig; private queryConfig: QueryArrayConfig; @@ -109,7 +109,7 @@ export class NodePgSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'NodePgSession'; + static override readonly [entityKind]: string = 'NodePgSession'; private logger: Logger; @@ -177,7 +177,7 @@ export class NodePgTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'NodePgTransaction'; + static override readonly [entityKind]: string = 'NodePgTransaction'; override async transaction(transaction: (tx: NodePgTransaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex + 1}`; diff --git a/drizzle-orm/src/op-sqlite/driver.ts b/drizzle-orm/src/op-sqlite/driver.ts index ac8b1f310..06b9d57f4 100644 --- a/drizzle-orm/src/op-sqlite/driver.ts +++ b/drizzle-orm/src/op-sqlite/driver.ts @@ -15,7 +15,7 @@ import { OPSQLiteSession } from './session.ts'; export class OPSQLiteDatabase< TSchema extends Record = Record, > extends BaseSQLiteDatabase<'async', QueryResult, TSchema> { - static readonly [entityKind]: string = 'OPSQLiteDatabase'; + static override readonly [entityKind]: string = 'OPSQLiteDatabase'; } export function drizzle = Record>( diff --git a/drizzle-orm/src/op-sqlite/session.ts b/drizzle-orm/src/op-sqlite/session.ts index f7a08a56b..c1ac63071 100644 --- a/drizzle-orm/src/op-sqlite/session.ts +++ b/drizzle-orm/src/op-sqlite/session.ts @@ -26,7 +26,7 @@ export class OPSQLiteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'async', QueryResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'OPSQLiteSession'; + static override readonly [entityKind]: string = 'OPSQLiteSession'; private logger: Logger; @@ -79,7 +79,7 @@ export class OPSQLiteTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'async', QueryResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'OPSQLiteTransaction'; + static override readonly [entityKind]: string = 'OPSQLiteTransaction'; override transaction(transaction: (tx: OPSQLiteTransaction) => T): T { const savepointName = `sp${this.nestedIndex}`; @@ -99,7 +99,7 @@ export class OPSQLiteTransaction< export class OPSQLitePreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: QueryResult; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'OPSQLitePreparedQuery'; + static override readonly [entityKind]: string = 'OPSQLitePreparedQuery'; constructor( private client: OPSQLiteConnection, diff --git a/drizzle-orm/src/pg-core/columns/bigint.ts b/drizzle-orm/src/pg-core/columns/bigint.ts index ef6be9eff..23e1e7f15 100644 --- a/drizzle-orm/src/pg-core/columns/bigint.ts +++ b/drizzle-orm/src/pg-core/columns/bigint.ts @@ -20,7 +20,7 @@ export type PgBigInt53BuilderInitial = PgBigInt53Builder<{ export class PgBigInt53Builder> extends PgIntColumnBaseBuilder { - static readonly [entityKind]: string = 'PgBigInt53Builder'; + static override readonly [entityKind]: string = 'PgBigInt53Builder'; constructor(name: T['name']) { super(name, 'number', 'PgBigInt53'); @@ -35,7 +35,7 @@ export class PgBigInt53Builder> extends PgColumn { - static readonly [entityKind]: string = 'PgBigInt53'; + static override readonly [entityKind]: string = 'PgBigInt53'; getSQLType(): string { return 'bigint'; @@ -62,7 +62,7 @@ export type PgBigInt64BuilderInitial = PgBigInt64Builder<{ export class PgBigInt64Builder> extends PgIntColumnBaseBuilder { - static readonly [entityKind]: string = 'PgBigInt64Builder'; + static override readonly [entityKind]: string = 'PgBigInt64Builder'; constructor(name: T['name']) { super(name, 'bigint', 'PgBigInt64'); @@ -80,7 +80,7 @@ export class PgBigInt64Builder> extends PgColumn { - static readonly [entityKind]: string = 'PgBigInt64'; + static override readonly [entityKind]: string = 'PgBigInt64'; getSQLType(): string { return 'bigint'; diff --git a/drizzle-orm/src/pg-core/columns/bigserial.ts b/drizzle-orm/src/pg-core/columns/bigserial.ts index 775234cb2..ed4224354 100644 --- a/drizzle-orm/src/pg-core/columns/bigserial.ts +++ b/drizzle-orm/src/pg-core/columns/bigserial.ts @@ -28,7 +28,7 @@ export type PgBigSerial53BuilderInitial = NotNull< export class PgBigSerial53Builder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgBigSerial53Builder'; + static override readonly [entityKind]: string = 'PgBigSerial53Builder'; constructor(name: string) { super(name, 'number', 'PgBigSerial53'); @@ -48,7 +48,7 @@ export class PgBigSerial53Builder> extends PgColumn { - static readonly [entityKind]: string = 'PgBigSerial53'; + static override readonly [entityKind]: string = 'PgBigSerial53'; getSQLType(): string { return 'bigserial'; @@ -79,7 +79,7 @@ export type PgBigSerial64BuilderInitial = NotNull< export class PgBigSerial64Builder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgBigSerial64Builder'; + static override readonly [entityKind]: string = 'PgBigSerial64Builder'; constructor(name: string) { super(name, 'bigint', 'PgBigSerial64'); @@ -98,7 +98,7 @@ export class PgBigSerial64Builder> extends PgColumn { - static readonly [entityKind]: string = 'PgBigSerial64'; + static override readonly [entityKind]: string = 'PgBigSerial64'; getSQLType(): string { return 'bigserial'; diff --git a/drizzle-orm/src/pg-core/columns/boolean.ts b/drizzle-orm/src/pg-core/columns/boolean.ts index 19139243a..cd30895c7 100644 --- a/drizzle-orm/src/pg-core/columns/boolean.ts +++ b/drizzle-orm/src/pg-core/columns/boolean.ts @@ -15,7 +15,7 @@ export type PgBooleanBuilderInitial = PgBooleanBuilder<{ }>; export class PgBooleanBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgBooleanBuilder'; + static override readonly [entityKind]: string = 'PgBooleanBuilder'; constructor(name: T['name']) { super(name, 'boolean', 'PgBoolean'); @@ -30,7 +30,7 @@ export class PgBooleanBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgBoolean'; + static override readonly [entityKind]: string = 'PgBoolean'; getSQLType(): string { return 'boolean'; diff --git a/drizzle-orm/src/pg-core/columns/char.ts b/drizzle-orm/src/pg-core/columns/char.ts index a3b8853be..6629f08cc 100644 --- a/drizzle-orm/src/pg-core/columns/char.ts +++ b/drizzle-orm/src/pg-core/columns/char.ts @@ -19,7 +19,7 @@ export class PgCharBuilder T, { length: number | undefined; enumValues: T['enumValues'] } > { - static readonly [entityKind]: string = 'PgCharBuilder'; + static override readonly [entityKind]: string = 'PgCharBuilder'; constructor(name: T['name'], config: PgCharConfig) { super(name, 'string', 'PgChar'); @@ -38,7 +38,7 @@ export class PgCharBuilder export class PgChar> extends PgColumn { - static readonly [entityKind]: string = 'PgChar'; + static override readonly [entityKind]: string = 'PgChar'; readonly length = this.config.length; override readonly enumValues = this.config.enumValues; diff --git a/drizzle-orm/src/pg-core/columns/cidr.ts b/drizzle-orm/src/pg-core/columns/cidr.ts index 8ab375ba1..6caa3dc25 100644 --- a/drizzle-orm/src/pg-core/columns/cidr.ts +++ b/drizzle-orm/src/pg-core/columns/cidr.ts @@ -15,7 +15,7 @@ export type PgCidrBuilderInitial = PgCidrBuilder<{ }>; export class PgCidrBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgCidrBuilder'; + static override readonly [entityKind]: string = 'PgCidrBuilder'; constructor(name: T['name']) { super(name, 'string', 'PgCidr'); @@ -30,7 +30,7 @@ export class PgCidrBuilder } export class PgCidr> extends PgColumn { - static readonly [entityKind]: string = 'PgCidr'; + static override readonly [entityKind]: string = 'PgCidr'; getSQLType(): string { return 'cidr'; diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index 84118ef20..c2fbe8cb9 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -46,7 +46,7 @@ export abstract class PgColumnBuilder< { private foreignKeyConfigs: ReferenceConfig[] = []; - static readonly [entityKind]: string = 'PgColumnBuilder'; + static override readonly [entityKind]: string = 'PgColumnBuilder'; array(size?: number): PgArrayBuilder< & { @@ -134,7 +134,7 @@ export abstract class PgColumn< TRuntimeConfig extends object = {}, TTypeConfig extends object = {}, > extends Column { - static readonly [entityKind]: string = 'PgColumn'; + static override readonly [entityKind]: string = 'PgColumn'; constructor( override readonly table: PgTable, @@ -152,7 +152,7 @@ export type IndexedExtraConfigType = { order?: 'asc' | 'desc'; nulls?: 'first' | export class ExtraConfigColumn< T extends ColumnBaseConfig = ColumnBaseConfig, > extends PgColumn { - static readonly [entityKind]: string = 'ExtraConfigColumn'; + static override readonly [entityKind]: string = 'ExtraConfigColumn'; override getSQLType(): string { return this.getSQLType(); @@ -292,7 +292,7 @@ export class PgArray< > extends PgColumn { readonly size: number | undefined; - static readonly [entityKind]: string = 'PgArray'; + static override readonly [entityKind]: string = 'PgArray'; constructor( table: AnyPgTable<{ name: T['tableName'] }>, diff --git a/drizzle-orm/src/pg-core/columns/custom.ts b/drizzle-orm/src/pg-core/columns/custom.ts index 44fdec1b2..b59169ed6 100644 --- a/drizzle-orm/src/pg-core/columns/custom.ts +++ b/drizzle-orm/src/pg-core/columns/custom.ts @@ -35,7 +35,7 @@ export class PgCustomColumnBuilder { - static readonly [entityKind]: string = 'PgCustomColumnBuilder'; + static override readonly [entityKind]: string = 'PgCustomColumnBuilder'; constructor( name: T['name'], @@ -59,7 +59,7 @@ export class PgCustomColumnBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgCustomColumn'; + static override readonly [entityKind]: string = 'PgCustomColumn'; private sqlName: string; private mapTo?: (value: T['data']) => T['driverParam']; diff --git a/drizzle-orm/src/pg-core/columns/date.common.ts b/drizzle-orm/src/pg-core/columns/date.common.ts index c2a46d1ce..e8bfbf2b1 100644 --- a/drizzle-orm/src/pg-core/columns/date.common.ts +++ b/drizzle-orm/src/pg-core/columns/date.common.ts @@ -7,7 +7,7 @@ export abstract class PgDateColumnBaseBuilder< T extends ColumnBuilderBaseConfig, TRuntimeConfig extends object = object, > extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgDateColumnBaseBuilder'; + static override readonly [entityKind]: string = 'PgDateColumnBaseBuilder'; defaultNow() { return this.default(sql`now()`); diff --git a/drizzle-orm/src/pg-core/columns/date.ts b/drizzle-orm/src/pg-core/columns/date.ts index 812ec4e92..1d295b97a 100644 --- a/drizzle-orm/src/pg-core/columns/date.ts +++ b/drizzle-orm/src/pg-core/columns/date.ts @@ -17,7 +17,7 @@ export type PgDateBuilderInitial = PgDateBuilder<{ }>; export class PgDateBuilder> extends PgDateColumnBaseBuilder { - static readonly [entityKind]: string = 'PgDateBuilder'; + static override readonly [entityKind]: string = 'PgDateBuilder'; constructor(name: T['name']) { super(name, 'date', 'PgDate'); @@ -32,7 +32,7 @@ export class PgDateBuilder> } export class PgDate> extends PgColumn { - static readonly [entityKind]: string = 'PgDate'; + static override readonly [entityKind]: string = 'PgDate'; getSQLType(): string { return 'date'; @@ -60,7 +60,7 @@ export type PgDateStringBuilderInitial = PgDateStringBuild export class PgDateStringBuilder> extends PgDateColumnBaseBuilder { - static readonly [entityKind]: string = 'PgDateStringBuilder'; + static override readonly [entityKind]: string = 'PgDateStringBuilder'; constructor(name: T['name']) { super(name, 'string', 'PgDateString'); @@ -78,7 +78,7 @@ export class PgDateStringBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgDateString'; + static override readonly [entityKind]: string = 'PgDateString'; getSQLType(): string { return 'date'; diff --git a/drizzle-orm/src/pg-core/columns/double-precision.ts b/drizzle-orm/src/pg-core/columns/double-precision.ts index 8e454169f..77245ea45 100644 --- a/drizzle-orm/src/pg-core/columns/double-precision.ts +++ b/drizzle-orm/src/pg-core/columns/double-precision.ts @@ -17,7 +17,7 @@ export type PgDoublePrecisionBuilderInitial = PgDoublePrec export class PgDoublePrecisionBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgDoublePrecisionBuilder'; + static override readonly [entityKind]: string = 'PgDoublePrecisionBuilder'; constructor(name: T['name']) { super(name, 'number', 'PgDoublePrecision'); @@ -35,7 +35,7 @@ export class PgDoublePrecisionBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgDoublePrecision'; + static override readonly [entityKind]: string = 'PgDoublePrecision'; getSQLType(): string { return 'double precision'; diff --git a/drizzle-orm/src/pg-core/columns/enum.ts b/drizzle-orm/src/pg-core/columns/enum.ts index d35ec89d9..7712ca606 100644 --- a/drizzle-orm/src/pg-core/columns/enum.ts +++ b/drizzle-orm/src/pg-core/columns/enum.ts @@ -36,7 +36,7 @@ export function isPgEnum(obj: unknown): obj is PgEnum<[string, ...string[]]> { export class PgEnumColumnBuilder< T extends ColumnBuilderBaseConfig<'string', 'PgEnumColumn'> & { enumValues: [string, ...string[]] }, > extends PgColumnBuilder }> { - static readonly [entityKind]: string = 'PgEnumColumnBuilder'; + static override readonly [entityKind]: string = 'PgEnumColumnBuilder'; constructor(name: T['name'], enumInstance: PgEnum) { super(name, 'string', 'PgEnumColumn'); @@ -57,7 +57,7 @@ export class PgEnumColumnBuilder< export class PgEnumColumn & { enumValues: [string, ...string[]] }> extends PgColumn }> { - static readonly [entityKind]: string = 'PgEnumColumn'; + static override readonly [entityKind]: string = 'PgEnumColumn'; readonly enum = this.config.enum; override readonly enumValues = this.config.enum.enumValues; diff --git a/drizzle-orm/src/pg-core/columns/inet.ts b/drizzle-orm/src/pg-core/columns/inet.ts index a675359b3..6b6210fcf 100644 --- a/drizzle-orm/src/pg-core/columns/inet.ts +++ b/drizzle-orm/src/pg-core/columns/inet.ts @@ -15,7 +15,7 @@ export type PgInetBuilderInitial = PgInetBuilder<{ }>; export class PgInetBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgInetBuilder'; + static override readonly [entityKind]: string = 'PgInetBuilder'; constructor(name: T['name']) { super(name, 'string', 'PgInet'); @@ -30,7 +30,7 @@ export class PgInetBuilder } export class PgInet> extends PgColumn { - static readonly [entityKind]: string = 'PgInet'; + static override readonly [entityKind]: string = 'PgInet'; getSQLType(): string { return 'inet'; diff --git a/drizzle-orm/src/pg-core/columns/int.common.ts b/drizzle-orm/src/pg-core/columns/int.common.ts index 07c26ba9e..c473b8d04 100644 --- a/drizzle-orm/src/pg-core/columns/int.common.ts +++ b/drizzle-orm/src/pg-core/columns/int.common.ts @@ -14,7 +14,7 @@ export abstract class PgIntColumnBaseBuilder< T, { generatedIdentity: GeneratedIdentityConfig } > { - static readonly [entityKind]: string = 'PgIntColumnBaseBuilder'; + static override readonly [entityKind]: string = 'PgIntColumnBaseBuilder'; generatedAlwaysAsIdentity( sequence?: PgSequenceOptions & { name?: string }, diff --git a/drizzle-orm/src/pg-core/columns/integer.ts b/drizzle-orm/src/pg-core/columns/integer.ts index 0feb388f3..bb70f9b41 100644 --- a/drizzle-orm/src/pg-core/columns/integer.ts +++ b/drizzle-orm/src/pg-core/columns/integer.ts @@ -18,7 +18,7 @@ type PgIntegerBuilderInitial = PgIntegerBuilder<{ export class PgIntegerBuilder> extends PgIntColumnBaseBuilder { - static readonly [entityKind]: string = 'PgIntegerBuilder'; + static override readonly [entityKind]: string = 'PgIntegerBuilder'; constructor(name: T['name']) { super(name, 'number', 'PgInteger'); @@ -33,7 +33,7 @@ export class PgIntegerBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgInteger'; + static override readonly [entityKind]: string = 'PgInteger'; getSQLType(): string { return 'integer'; diff --git a/drizzle-orm/src/pg-core/columns/interval.ts b/drizzle-orm/src/pg-core/columns/interval.ts index 3ae6557a3..4d3ed4588 100644 --- a/drizzle-orm/src/pg-core/columns/interval.ts +++ b/drizzle-orm/src/pg-core/columns/interval.ts @@ -19,7 +19,7 @@ export type PgIntervalBuilderInitial = PgIntervalBuilder<{ export class PgIntervalBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgIntervalBuilder'; + static override readonly [entityKind]: string = 'PgIntervalBuilder'; constructor( name: T['name'], @@ -40,7 +40,7 @@ export class PgIntervalBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgInterval'; + static override readonly [entityKind]: string = 'PgInterval'; readonly fields: IntervalConfig['fields'] = this.config.intervalConfig.fields; readonly precision: IntervalConfig['precision'] = this.config.intervalConfig.precision; diff --git a/drizzle-orm/src/pg-core/columns/json.ts b/drizzle-orm/src/pg-core/columns/json.ts index 7e232db5e..3c440c7d2 100644 --- a/drizzle-orm/src/pg-core/columns/json.ts +++ b/drizzle-orm/src/pg-core/columns/json.ts @@ -17,7 +17,7 @@ export type PgJsonBuilderInitial = PgJsonBuilder<{ export class PgJsonBuilder> extends PgColumnBuilder< T > { - static readonly [entityKind]: string = 'PgJsonBuilder'; + static override readonly [entityKind]: string = 'PgJsonBuilder'; constructor(name: T['name']) { super(name, 'json', 'PgJson'); @@ -32,7 +32,7 @@ export class PgJsonBuilder> } export class PgJson> extends PgColumn { - static readonly [entityKind]: string = 'PgJson'; + static override readonly [entityKind]: string = 'PgJson'; constructor(table: AnyPgTable<{ name: T['tableName'] }>, config: PgJsonBuilder['config']) { super(table, config); diff --git a/drizzle-orm/src/pg-core/columns/jsonb.ts b/drizzle-orm/src/pg-core/columns/jsonb.ts index 89d1be86a..3407730db 100644 --- a/drizzle-orm/src/pg-core/columns/jsonb.ts +++ b/drizzle-orm/src/pg-core/columns/jsonb.ts @@ -15,7 +15,7 @@ export type PgJsonbBuilderInitial = PgJsonbBuilder<{ }>; export class PgJsonbBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgJsonbBuilder'; + static override readonly [entityKind]: string = 'PgJsonbBuilder'; constructor(name: T['name']) { super(name, 'json', 'PgJsonb'); @@ -30,7 +30,7 @@ export class PgJsonbBuilder } export class PgJsonb> extends PgColumn { - static readonly [entityKind]: string = 'PgJsonb'; + static override readonly [entityKind]: string = 'PgJsonb'; constructor(table: AnyPgTable<{ name: T['tableName'] }>, config: PgJsonbBuilder['config']) { super(table, config); diff --git a/drizzle-orm/src/pg-core/columns/line.ts b/drizzle-orm/src/pg-core/columns/line.ts index cd4b70a66..014140797 100644 --- a/drizzle-orm/src/pg-core/columns/line.ts +++ b/drizzle-orm/src/pg-core/columns/line.ts @@ -17,7 +17,7 @@ export type PgLineBuilderInitial = PgLineBuilder<{ }>; export class PgLineBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgLineBuilder'; + static override readonly [entityKind]: string = 'PgLineBuilder'; constructor(name: T['name']) { super(name, 'array', 'PgLine'); @@ -35,7 +35,7 @@ export class PgLineBuilder> } export class PgLineTuple> extends PgColumn { - static readonly [entityKind]: string = 'PgLine'; + static override readonly [entityKind]: string = 'PgLine'; getSQLType(): string { return 'line'; @@ -62,7 +62,7 @@ export type PgLineABCBuilderInitial = PgLineABCBuilder<{ }>; export class PgLineABCBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgLineABCBuilder'; + static override readonly [entityKind]: string = 'PgLineABCBuilder'; constructor(name: T['name']) { super(name, 'json', 'PgLineABC'); @@ -80,7 +80,7 @@ export class PgLineABCBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgLineABC'; + static override readonly [entityKind]: string = 'PgLineABC'; getSQLType(): string { return 'line'; diff --git a/drizzle-orm/src/pg-core/columns/macaddr.ts b/drizzle-orm/src/pg-core/columns/macaddr.ts index b43d4ab40..bfc4511f4 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr.ts @@ -15,7 +15,7 @@ export type PgMacaddrBuilderInitial = PgMacaddrBuilder<{ }>; export class PgMacaddrBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgMacaddrBuilder'; + static override readonly [entityKind]: string = 'PgMacaddrBuilder'; constructor(name: T['name']) { super(name, 'string', 'PgMacaddr'); @@ -30,7 +30,7 @@ export class PgMacaddrBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgMacaddr'; + static override readonly [entityKind]: string = 'PgMacaddr'; getSQLType(): string { return 'macaddr'; diff --git a/drizzle-orm/src/pg-core/columns/macaddr8.ts b/drizzle-orm/src/pg-core/columns/macaddr8.ts index 00af8c031..6c4218de0 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr8.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr8.ts @@ -15,7 +15,7 @@ export type PgMacaddr8BuilderInitial = PgMacaddr8Builder<{ }>; export class PgMacaddr8Builder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgMacaddr8Builder'; + static override readonly [entityKind]: string = 'PgMacaddr8Builder'; constructor(name: T['name']) { super(name, 'string', 'PgMacaddr8'); @@ -30,7 +30,7 @@ export class PgMacaddr8Builder> extends PgColumn { - static readonly [entityKind]: string = 'PgMacaddr8'; + static override readonly [entityKind]: string = 'PgMacaddr8'; getSQLType(): string { return 'macaddr8'; diff --git a/drizzle-orm/src/pg-core/columns/numeric.ts b/drizzle-orm/src/pg-core/columns/numeric.ts index a661df21e..efeb4ab97 100644 --- a/drizzle-orm/src/pg-core/columns/numeric.ts +++ b/drizzle-orm/src/pg-core/columns/numeric.ts @@ -22,7 +22,7 @@ export class PgNumericBuilder { - static readonly [entityKind]: string = 'PgNumericBuilder'; + static override readonly [entityKind]: string = 'PgNumericBuilder'; constructor(name: T['name'], precision?: number, scale?: number) { super(name, 'string', 'PgNumeric'); @@ -39,7 +39,7 @@ export class PgNumericBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgNumeric'; + static override readonly [entityKind]: string = 'PgNumeric'; readonly precision: number | undefined; readonly scale: number | undefined; diff --git a/drizzle-orm/src/pg-core/columns/point.ts b/drizzle-orm/src/pg-core/columns/point.ts index 584e395f9..827579ad8 100644 --- a/drizzle-orm/src/pg-core/columns/point.ts +++ b/drizzle-orm/src/pg-core/columns/point.ts @@ -19,7 +19,7 @@ export type PgPointTupleBuilderInitial = PgPointTupleBuild export class PgPointTupleBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgPointTupleBuilder'; + static override readonly [entityKind]: string = 'PgPointTupleBuilder'; constructor(name: string) { super(name, 'array', 'PgPointTuple'); @@ -37,7 +37,7 @@ export class PgPointTupleBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgPointTuple'; + static override readonly [entityKind]: string = 'PgPointTuple'; getSQLType(): string { return 'point'; @@ -69,7 +69,7 @@ export type PgPointObjectBuilderInitial = PgPointObjectBui export class PgPointObjectBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgPointObjectBuilder'; + static override readonly [entityKind]: string = 'PgPointObjectBuilder'; constructor(name: string) { super(name, 'json', 'PgPointObject'); @@ -87,7 +87,7 @@ export class PgPointObjectBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgPointObject'; + static override readonly [entityKind]: string = 'PgPointObject'; getSQLType(): string { return 'point'; diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts index 18e6c946d..853c3dff9 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts @@ -18,7 +18,7 @@ export type PgGeometryBuilderInitial = PgGeometryBuilder<{ }>; export class PgGeometryBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgGeometryBuilder'; + static override readonly [entityKind]: string = 'PgGeometryBuilder'; constructor(name: T['name']) { super(name, 'array', 'PgGeometry'); @@ -36,7 +36,7 @@ export class PgGeometryBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgGeometry'; + static override readonly [entityKind]: string = 'PgGeometry'; getSQLType(): string { return 'geometry(point)'; @@ -64,7 +64,7 @@ export type PgGeometryObjectBuilderInitial = PgGeometryObj export class PgGeometryObjectBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgGeometryObjectBuilder'; + static override readonly [entityKind]: string = 'PgGeometryObjectBuilder'; constructor(name: T['name']) { super(name, 'json', 'PgGeometryObject'); @@ -82,7 +82,7 @@ export class PgGeometryObjectBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgGeometryObject'; + static override readonly [entityKind]: string = 'PgGeometryObject'; getSQLType(): string { return 'geometry(point)'; diff --git a/drizzle-orm/src/pg-core/columns/real.ts b/drizzle-orm/src/pg-core/columns/real.ts index f39527a45..0e3de4b2e 100644 --- a/drizzle-orm/src/pg-core/columns/real.ts +++ b/drizzle-orm/src/pg-core/columns/real.ts @@ -18,7 +18,7 @@ export class PgRealBuilder T, { length: number | undefined } > { - static readonly [entityKind]: string = 'PgRealBuilder'; + static override readonly [entityKind]: string = 'PgRealBuilder'; constructor(name: T['name'], length?: number) { super(name, 'number', 'PgReal'); @@ -34,7 +34,7 @@ export class PgRealBuilder } export class PgReal> extends PgColumn { - static readonly [entityKind]: string = 'PgReal'; + static override readonly [entityKind]: string = 'PgReal'; constructor(table: AnyPgTable<{ name: T['tableName'] }>, config: PgRealBuilder['config']) { super(table, config); diff --git a/drizzle-orm/src/pg-core/columns/serial.ts b/drizzle-orm/src/pg-core/columns/serial.ts index a4d7f8e30..6a0196c38 100644 --- a/drizzle-orm/src/pg-core/columns/serial.ts +++ b/drizzle-orm/src/pg-core/columns/serial.ts @@ -25,7 +25,7 @@ export type PgSerialBuilderInitial = NotNull< >; export class PgSerialBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgSerialBuilder'; + static override readonly [entityKind]: string = 'PgSerialBuilder'; constructor(name: T['name']) { super(name, 'number', 'PgSerial'); @@ -42,7 +42,7 @@ export class PgSerialBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgSerial'; + static override readonly [entityKind]: string = 'PgSerial'; getSQLType(): string { return 'serial'; diff --git a/drizzle-orm/src/pg-core/columns/smallint.ts b/drizzle-orm/src/pg-core/columns/smallint.ts index 20204cd3c..1cdfe141f 100644 --- a/drizzle-orm/src/pg-core/columns/smallint.ts +++ b/drizzle-orm/src/pg-core/columns/smallint.ts @@ -18,7 +18,7 @@ export type PgSmallIntBuilderInitial = PgSmallIntBuilder<{ export class PgSmallIntBuilder> extends PgIntColumnBaseBuilder { - static readonly [entityKind]: string = 'PgSmallIntBuilder'; + static override readonly [entityKind]: string = 'PgSmallIntBuilder'; constructor(name: T['name']) { super(name, 'number', 'PgSmallInt'); @@ -33,7 +33,7 @@ export class PgSmallIntBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgSmallInt'; + static override readonly [entityKind]: string = 'PgSmallInt'; getSQLType(): string { return 'smallint'; diff --git a/drizzle-orm/src/pg-core/columns/smallserial.ts b/drizzle-orm/src/pg-core/columns/smallserial.ts index ec2204034..456dc47f7 100644 --- a/drizzle-orm/src/pg-core/columns/smallserial.ts +++ b/drizzle-orm/src/pg-core/columns/smallserial.ts @@ -27,7 +27,7 @@ export type PgSmallSerialBuilderInitial = NotNull< export class PgSmallSerialBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgSmallSerialBuilder'; + static override readonly [entityKind]: string = 'PgSmallSerialBuilder'; constructor(name: T['name']) { super(name, 'number', 'PgSmallSerial'); @@ -47,7 +47,7 @@ export class PgSmallSerialBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgSmallSerial'; + static override readonly [entityKind]: string = 'PgSmallSerial'; getSQLType(): string { return 'smallserial'; diff --git a/drizzle-orm/src/pg-core/columns/text.ts b/drizzle-orm/src/pg-core/columns/text.ts index 522135e5c..6845f0e74 100644 --- a/drizzle-orm/src/pg-core/columns/text.ts +++ b/drizzle-orm/src/pg-core/columns/text.ts @@ -18,7 +18,7 @@ type PgTextBuilderInitial, > extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgTextBuilder'; + static override readonly [entityKind]: string = 'PgTextBuilder'; constructor( name: T['name'], @@ -39,7 +39,7 @@ export class PgTextBuilder< export class PgText> extends PgColumn { - static readonly [entityKind]: string = 'PgText'; + static override readonly [entityKind]: string = 'PgText'; override readonly enumValues = this.config.enumValues; diff --git a/drizzle-orm/src/pg-core/columns/time.ts b/drizzle-orm/src/pg-core/columns/time.ts index e2b29f1f7..9b3ff51e0 100644 --- a/drizzle-orm/src/pg-core/columns/time.ts +++ b/drizzle-orm/src/pg-core/columns/time.ts @@ -21,7 +21,7 @@ export class PgTimeBuilder T, { withTimezone: boolean; precision: number | undefined } > { - static readonly [entityKind]: string = 'PgTimeBuilder'; + static override readonly [entityKind]: string = 'PgTimeBuilder'; constructor( name: T['name'], @@ -42,7 +42,7 @@ export class PgTimeBuilder } export class PgTime> extends PgColumn { - static readonly [entityKind]: string = 'PgTime'; + static override readonly [entityKind]: string = 'PgTime'; readonly withTimezone: boolean; readonly precision: number | undefined; diff --git a/drizzle-orm/src/pg-core/columns/timestamp.ts b/drizzle-orm/src/pg-core/columns/timestamp.ts index 08474bf68..6879106e0 100644 --- a/drizzle-orm/src/pg-core/columns/timestamp.ts +++ b/drizzle-orm/src/pg-core/columns/timestamp.ts @@ -22,7 +22,7 @@ export class PgTimestampBuilder { - static readonly [entityKind]: string = 'PgTimestampBuilder'; + static override readonly [entityKind]: string = 'PgTimestampBuilder'; constructor( name: T['name'], @@ -43,7 +43,7 @@ export class PgTimestampBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgTimestamp'; + static override readonly [entityKind]: string = 'PgTimestamp'; readonly withTimezone: boolean; readonly precision: number | undefined; @@ -84,7 +84,7 @@ export class PgTimestampStringBuilder { - static readonly [entityKind]: string = 'PgTimestampStringBuilder'; + static override readonly [entityKind]: string = 'PgTimestampStringBuilder'; constructor( name: T['name'], @@ -108,7 +108,7 @@ export class PgTimestampStringBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgTimestampString'; + static override readonly [entityKind]: string = 'PgTimestampString'; readonly withTimezone: boolean; readonly precision: number | undefined; diff --git a/drizzle-orm/src/pg-core/columns/uuid.ts b/drizzle-orm/src/pg-core/columns/uuid.ts index 851036d8d..d0e5a6830 100644 --- a/drizzle-orm/src/pg-core/columns/uuid.ts +++ b/drizzle-orm/src/pg-core/columns/uuid.ts @@ -16,7 +16,7 @@ export type PgUUIDBuilderInitial = PgUUIDBuilder<{ }>; export class PgUUIDBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgUUIDBuilder'; + static override readonly [entityKind]: string = 'PgUUIDBuilder'; constructor(name: T['name']) { super(name, 'string', 'PgUUID'); @@ -38,7 +38,7 @@ export class PgUUIDBuilder } export class PgUUID> extends PgColumn { - static readonly [entityKind]: string = 'PgUUID'; + static override readonly [entityKind]: string = 'PgUUID'; getSQLType(): string { return 'uuid'; diff --git a/drizzle-orm/src/pg-core/columns/varchar.ts b/drizzle-orm/src/pg-core/columns/varchar.ts index bc9d1b160..78ee0db96 100644 --- a/drizzle-orm/src/pg-core/columns/varchar.ts +++ b/drizzle-orm/src/pg-core/columns/varchar.ts @@ -19,7 +19,7 @@ export class PgVarcharBuilder { - static readonly [entityKind]: string = 'PgVarcharBuilder'; + static override readonly [entityKind]: string = 'PgVarcharBuilder'; constructor(name: T['name'], config: PgVarcharConfig) { super(name, 'string', 'PgVarchar'); @@ -38,7 +38,7 @@ export class PgVarcharBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgVarchar'; + static override readonly [entityKind]: string = 'PgVarchar'; readonly length = this.config.length; override readonly enumValues = this.config.enumValues; diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts index a841c28e5..81eea6b2f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts @@ -21,7 +21,7 @@ export class PgBinaryVectorBuilder { - static readonly [entityKind]: string = 'PgBinaryVectorBuilder'; + static override readonly [entityKind]: string = 'PgBinaryVectorBuilder'; constructor(name: string, config: PgBinaryVectorConfig) { super(name, 'string', 'PgBinaryVector'); @@ -42,7 +42,7 @@ export class PgBinaryVectorBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgBinaryVector'; + static override readonly [entityKind]: string = 'PgBinaryVector'; readonly dimensions = this.config.dimensions; diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts index 7218f8114..e12d0d22f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts @@ -19,7 +19,7 @@ export class PgHalfVectorBuilder { - static readonly [entityKind]: string = 'PgHalfVectorBuilder'; + static override readonly [entityKind]: string = 'PgHalfVectorBuilder'; constructor(name: string, config: PgHalfVectorConfig) { super(name, 'array', 'PgHalfVector'); @@ -40,7 +40,7 @@ export class PgHalfVectorBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgHalfVector'; + static override readonly [entityKind]: string = 'PgHalfVector'; readonly dimensions = this.config.dimensions; diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts index 2bdbf1ac3..3881b338f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts @@ -21,7 +21,7 @@ export class PgSparseVectorBuilder { - static readonly [entityKind]: string = 'PgSparseVectorBuilder'; + static override readonly [entityKind]: string = 'PgSparseVectorBuilder'; constructor(name: string, config: PgSparseVectorConfig) { super(name, 'string', 'PgSparseVector'); @@ -42,7 +42,7 @@ export class PgSparseVectorBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgSparseVector'; + static override readonly [entityKind]: string = 'PgSparseVector'; readonly dimensions = this.config.dimensions; diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts index b6ad9caff..eaac075dc 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts @@ -19,7 +19,7 @@ export class PgVectorBuilder { - static readonly [entityKind]: string = 'PgVectorBuilder'; + static override readonly [entityKind]: string = 'PgVectorBuilder'; constructor(name: string, config: PgVectorConfig) { super(name, 'array', 'PgVector'); @@ -37,7 +37,7 @@ export class PgVectorBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgVector'; + static override readonly [entityKind]: string = 'PgVector'; readonly dimensions = this.config.dimensions; diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index c823f7c6f..af16fda01 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -8,7 +8,7 @@ export class PgCountBuilder< > extends SQL implements Promise, SQLWrapper { private sql: SQL; - static readonly [entityKind] = 'PgCountBuilder'; + static override readonly [entityKind] = 'PgCountBuilder'; [Symbol.toStringTag] = 'PgCountBuilder'; private session: TSession; diff --git a/drizzle-orm/src/pg-core/query-builders/delete.ts b/drizzle-orm/src/pg-core/query-builders/delete.ts index dc127f167..b42d46711 100644 --- a/drizzle-orm/src/pg-core/query-builders/delete.ts +++ b/drizzle-orm/src/pg-core/query-builders/delete.ts @@ -128,7 +128,7 @@ export class PgDeleteBase< RunnableQuery : TReturning[], 'pg'>, SQLWrapper { - static readonly [entityKind]: string = 'PgDelete'; + static override readonly [entityKind]: string = 'PgDelete'; private config: PgDeleteConfig; diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index 02bcb972c..9f494ab50 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -166,7 +166,7 @@ export class PgInsertBase< RunnableQuery : TReturning[], 'pg'>, SQLWrapper { - static readonly [entityKind]: string = 'PgInsert'; + static override readonly [entityKind]: string = 'PgInsert'; private config: PgInsertConfig; diff --git a/drizzle-orm/src/pg-core/query-builders/query.ts b/drizzle-orm/src/pg-core/query-builders/query.ts index 17cea6cff..07f485669 100644 --- a/drizzle-orm/src/pg-core/query-builders/query.ts +++ b/drizzle-orm/src/pg-core/query-builders/query.ts @@ -65,7 +65,7 @@ export class RelationalQueryBuilder extends QueryPromise implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'PgRelationalQuery'; + static override readonly [entityKind]: string = 'PgRelationalQuery'; declare readonly _: { readonly dialect: 'pg'; diff --git a/drizzle-orm/src/pg-core/query-builders/raw.ts b/drizzle-orm/src/pg-core/query-builders/raw.ts index 871581dfb..d08c1ee14 100644 --- a/drizzle-orm/src/pg-core/query-builders/raw.ts +++ b/drizzle-orm/src/pg-core/query-builders/raw.ts @@ -9,7 +9,7 @@ export interface PgRaw extends QueryPromise, RunnableQuery extends QueryPromise implements RunnableQuery, SQLWrapper, PreparedQuery { - static readonly [entityKind]: string = 'PgRaw'; + static override readonly [entityKind]: string = 'PgRaw'; declare readonly _: { readonly dialect: 'pg'; diff --git a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts index d2bedac68..62ade9139 100644 --- a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts +++ b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts @@ -30,7 +30,7 @@ export class PgRefreshMaterializedView extends QueryPromise> implements RunnableQuery, 'pg'>, SQLWrapper { - static readonly [entityKind]: string = 'PgRefreshMaterializedView'; + static override readonly [entityKind]: string = 'PgRefreshMaterializedView'; private config: { view: PgMaterializedView; diff --git a/drizzle-orm/src/pg-core/query-builders/select.ts b/drizzle-orm/src/pg-core/query-builders/select.ts index d2406995b..6e9a961c0 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.ts @@ -139,7 +139,7 @@ export abstract class PgSelectQueryBuilderBase< TResult extends any[] = SelectResult[], TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > extends TypedQueryBuilder { - static readonly [entityKind]: string = 'PgSelectQueryBuilder'; + static override readonly [entityKind]: string = 'PgSelectQueryBuilder'; override readonly _: { readonly dialect: 'pg'; @@ -947,7 +947,7 @@ export class PgSelectBase< TResult, TSelectedFields > implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'PgSelect'; + static override readonly [entityKind]: string = 'PgSelect'; /** @internal */ _prepare(name?: string): PgSelectPrepare { diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index ec404ac22..2c63dacc0 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -159,7 +159,7 @@ export class PgUpdateBase< RunnableQuery : TReturning[], 'pg'>, SQLWrapper { - static readonly [entityKind]: string = 'PgUpdate'; + static override readonly [entityKind]: string = 'PgUpdate'; private config: PgUpdateConfig; diff --git a/drizzle-orm/src/pg-core/session.ts b/drizzle-orm/src/pg-core/session.ts index ea820f2d8..d909e82db 100644 --- a/drizzle-orm/src/pg-core/session.ts +++ b/drizzle-orm/src/pg-core/session.ts @@ -105,7 +105,7 @@ export abstract class PgTransaction< TFullSchema extends Record = Record, TSchema extends TablesRelationalConfig = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'PgTransaction'; + static override readonly [entityKind]: string = 'PgTransaction'; constructor( dialect: PgDialect, diff --git a/drizzle-orm/src/pg-core/table.ts b/drizzle-orm/src/pg-core/table.ts index c09a56233..5bf9a9895 100644 --- a/drizzle-orm/src/pg-core/table.ts +++ b/drizzle-orm/src/pg-core/table.ts @@ -24,7 +24,7 @@ export type TableConfig = TableConfigBase; export const InlineForeignKeys = Symbol.for('drizzle:PgInlineForeignKeys'); export class PgTable extends Table { - static readonly [entityKind]: string = 'PgTable'; + static override readonly [entityKind]: string = 'PgTable'; /** @internal */ static override readonly Symbol = Object.assign({}, Table.Symbol, { diff --git a/drizzle-orm/src/pg-core/view-base.ts b/drizzle-orm/src/pg-core/view-base.ts index 87f76ac24..d3f52a501 100644 --- a/drizzle-orm/src/pg-core/view-base.ts +++ b/drizzle-orm/src/pg-core/view-base.ts @@ -6,7 +6,7 @@ export abstract class PgViewBase< TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, > extends View { - static readonly [entityKind]: string = 'PgViewBase'; + static override readonly [entityKind]: string = 'PgViewBase'; declare readonly _: View['_'] & { readonly viewBrand: 'PgViewBase'; diff --git a/drizzle-orm/src/pg-core/view.ts b/drizzle-orm/src/pg-core/view.ts index 22c510dce..d6b778268 100644 --- a/drizzle-orm/src/pg-core/view.ts +++ b/drizzle-orm/src/pg-core/view.ts @@ -42,7 +42,7 @@ export class DefaultViewBuilderCore extends DefaultViewBuilderCore<{ name: TName }> { - static readonly [entityKind]: string = 'PgViewBuilder'; + static override readonly [entityKind]: string = 'PgViewBuilder'; as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), @@ -76,7 +76,7 @@ export class ManualViewBuilder< TName extends string = string, TColumns extends Record = Record, > extends DefaultViewBuilderCore<{ name: TName; columns: TColumns }> { - static readonly [entityKind]: string = 'PgManualViewBuilder'; + static override readonly [entityKind]: string = 'PgManualViewBuilder'; private columns: Record; @@ -178,7 +178,7 @@ export class MaterializedViewBuilderCore extends MaterializedViewBuilderCore<{ name: TName }> { - static readonly [entityKind]: string = 'PgMaterializedViewBuilder'; + static override readonly [entityKind]: string = 'PgMaterializedViewBuilder'; as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), @@ -217,7 +217,7 @@ export class ManualMaterializedViewBuilder< TName extends string = string, TColumns extends Record = Record, > extends MaterializedViewBuilderCore<{ name: TName; columns: TColumns }> { - static readonly [entityKind]: string = 'PgManualMaterializedViewBuilder'; + static override readonly [entityKind]: string = 'PgManualMaterializedViewBuilder'; private columns: Record; @@ -276,7 +276,7 @@ export class PgView< TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, > extends PgViewBase { - static readonly [entityKind]: string = 'PgView'; + static override readonly [entityKind]: string = 'PgView'; [PgViewConfig]: { with?: ViewWithConfig; @@ -315,7 +315,7 @@ export class PgMaterializedView< TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, > extends PgViewBase { - static readonly [entityKind]: string = 'PgMaterializedView'; + static override readonly [entityKind]: string = 'PgMaterializedView'; readonly [PgMaterializedViewConfig]: { readonly with?: PgMaterializedViewWithConfig; diff --git a/drizzle-orm/src/pg-proxy/driver.ts b/drizzle-orm/src/pg-proxy/driver.ts index 8ccd9ba02..955dc2bb4 100644 --- a/drizzle-orm/src/pg-proxy/driver.ts +++ b/drizzle-orm/src/pg-proxy/driver.ts @@ -14,7 +14,7 @@ import { type PgRemoteQueryResultHKT, PgRemoteSession } from './session.ts'; export class PgRemoteDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'PgRemoteDatabase'; + static override readonly [entityKind]: string = 'PgRemoteDatabase'; } export type RemoteCallback = ( diff --git a/drizzle-orm/src/pg-proxy/session.ts b/drizzle-orm/src/pg-proxy/session.ts index 1a30c0a3c..9d433502c 100644 --- a/drizzle-orm/src/pg-proxy/session.ts +++ b/drizzle-orm/src/pg-proxy/session.ts @@ -21,7 +21,7 @@ export class PgRemoteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'PgRemoteSession'; + static override readonly [entityKind]: string = 'PgRemoteSession'; private logger: Logger; @@ -66,7 +66,7 @@ export class PgProxyTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'PgProxyTransaction'; + static override readonly [entityKind]: string = 'PgProxyTransaction'; override async transaction( _transaction: (tx: PgProxyTransaction) => Promise, @@ -76,7 +76,7 @@ export class PgProxyTransaction< } export class PreparedQuery extends PreparedQueryBase { - static readonly [entityKind]: string = 'PgProxyPreparedQuery'; + static override readonly [entityKind]: string = 'PgProxyPreparedQuery'; constructor( private client: RemoteCallback, diff --git a/drizzle-orm/src/pglite/driver.ts b/drizzle-orm/src/pglite/driver.ts index b6cb8bd7e..c8683d540 100644 --- a/drizzle-orm/src/pglite/driver.ts +++ b/drizzle-orm/src/pglite/driver.ts @@ -37,7 +37,7 @@ export class PgliteDriver { export class PgliteDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'PgliteDatabase'; + static override readonly [entityKind]: string = 'PgliteDatabase'; } export function drizzle = Record>( diff --git a/drizzle-orm/src/pglite/session.ts b/drizzle-orm/src/pglite/session.ts index ebf7701a6..18c341fc6 100644 --- a/drizzle-orm/src/pglite/session.ts +++ b/drizzle-orm/src/pglite/session.ts @@ -15,7 +15,7 @@ import { types } from '@electric-sql/pglite'; export type PgliteClient = PGlite; export class PglitePreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'PglitePreparedQuery'; + static override readonly [entityKind]: string = 'PglitePreparedQuery'; private rawQueryConfig: QueryOptions; private queryConfig: QueryOptions; @@ -89,7 +89,7 @@ export class PgliteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'PgliteSession'; + static override readonly [entityKind]: string = 'PgliteSession'; private logger: Logger; @@ -153,7 +153,7 @@ export class PgliteTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'PgliteTransaction'; + static override readonly [entityKind]: string = 'PgliteTransaction'; override async transaction(transaction: (tx: PgliteTransaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex + 1}`; diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index 2b851f75b..69da8ce83 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -22,7 +22,7 @@ export interface PlanetscaleSDriverOptions { export class PlanetScaleDatabase< TSchema extends Record = Record, > extends MySqlDatabase { - static readonly [entityKind]: string = 'PlanetScaleDatabase'; + static override readonly [entityKind]: string = 'PlanetScaleDatabase'; } export function drizzle< diff --git a/drizzle-orm/src/planetscale-serverless/session.ts b/drizzle-orm/src/planetscale-serverless/session.ts index 987529d7c..4e6a0f432 100644 --- a/drizzle-orm/src/planetscale-serverless/session.ts +++ b/drizzle-orm/src/planetscale-serverless/session.ts @@ -18,7 +18,7 @@ import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; export class PlanetScalePreparedQuery extends MySqlPreparedQuery { - static readonly [entityKind]: string = 'PlanetScalePreparedQuery'; + static override readonly [entityKind]: string = 'PlanetScalePreparedQuery'; private rawQuery = { as: 'object' } as const; private query = { as: 'array' } as const; @@ -106,7 +106,7 @@ export class PlanetscaleSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlSession { - static readonly [entityKind]: string = 'PlanetscaleSession'; + static override readonly [entityKind]: string = 'PlanetscaleSession'; private logger: Logger; private client: Client | Transaction | Connection; @@ -191,7 +191,7 @@ export class PlanetScaleTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlTransaction { - static readonly [entityKind]: string = 'PlanetScaleTransaction'; + static override readonly [entityKind]: string = 'PlanetScaleTransaction'; constructor( dialect: MySqlDialect, diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index 641e413d0..0927e96ac 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -16,7 +16,7 @@ import { PostgresJsSession } from './session.ts'; export class PostgresJsDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'PostgresJsDatabase'; + static override readonly [entityKind]: string = 'PostgresJsDatabase'; } export function drizzle = Record>( diff --git a/drizzle-orm/src/postgres-js/session.ts b/drizzle-orm/src/postgres-js/session.ts index 05179ebdb..7509e2a00 100644 --- a/drizzle-orm/src/postgres-js/session.ts +++ b/drizzle-orm/src/postgres-js/session.ts @@ -13,7 +13,7 @@ import { tracer } from '~/tracing.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; export class PostgresJsPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'PostgresJsPreparedQuery'; + static override readonly [entityKind]: string = 'PostgresJsPreparedQuery'; constructor( private client: Sql, @@ -95,7 +95,7 @@ export class PostgresJsSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'PostgresJsSession'; + static override readonly [entityKind]: string = 'PostgresJsSession'; logger: Logger; @@ -164,7 +164,7 @@ export class PostgresJsTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'PostgresJsTransaction'; + static override readonly [entityKind]: string = 'PostgresJsTransaction'; constructor( dialect: PgDialect, diff --git a/drizzle-orm/src/prisma/mysql/driver.ts b/drizzle-orm/src/prisma/mysql/driver.ts index 586832948..c6ca143df 100644 --- a/drizzle-orm/src/prisma/mysql/driver.ts +++ b/drizzle-orm/src/prisma/mysql/driver.ts @@ -13,7 +13,7 @@ import { PrismaMySqlSession } from './session.ts'; export class PrismaMySqlDatabase extends MySqlDatabase> { - static readonly [entityKind]: string = 'PrismaMySqlDatabase'; + static override readonly [entityKind]: string = 'PrismaMySqlDatabase'; constructor(client: PrismaClient, logger: Logger | undefined) { const dialect = new MySqlDialect(); diff --git a/drizzle-orm/src/prisma/mysql/session.ts b/drizzle-orm/src/prisma/mysql/session.ts index a6b12a0c3..fc3807bc5 100644 --- a/drizzle-orm/src/prisma/mysql/session.ts +++ b/drizzle-orm/src/prisma/mysql/session.ts @@ -19,7 +19,7 @@ export class PrismaMySqlPreparedQuery extends MySqlPreparedQuery | undefined): AsyncGenerator { throw new Error('Method not implemented.'); } - static readonly [entityKind]: string = 'PrismaMySqlPreparedQuery'; + static override readonly [entityKind]: string = 'PrismaMySqlPreparedQuery'; constructor( private readonly prisma: PrismaClient, @@ -41,7 +41,7 @@ export interface PrismaMySqlSessionOptions { } export class PrismaMySqlSession extends MySqlSession { - static readonly [entityKind]: string = 'PrismaMySqlSession'; + static override readonly [entityKind]: string = 'PrismaMySqlSession'; private readonly logger: Logger; diff --git a/drizzle-orm/src/prisma/pg/driver.ts b/drizzle-orm/src/prisma/pg/driver.ts index 23678f09f..f9038d8a1 100644 --- a/drizzle-orm/src/prisma/pg/driver.ts +++ b/drizzle-orm/src/prisma/pg/driver.ts @@ -11,7 +11,7 @@ import type { PrismaPgQueryResultHKT } from './session.ts'; import { PrismaPgSession } from './session.ts'; export class PrismaPgDatabase extends PgDatabase> { - static readonly [entityKind]: string = 'PrismaPgDatabase'; + static override readonly [entityKind]: string = 'PrismaPgDatabase'; constructor(client: PrismaClient, logger: Logger | undefined) { const dialect = new PgDialect(); diff --git a/drizzle-orm/src/prisma/pg/session.ts b/drizzle-orm/src/prisma/pg/session.ts index 077326ef3..b93f6f14b 100644 --- a/drizzle-orm/src/prisma/pg/session.ts +++ b/drizzle-orm/src/prisma/pg/session.ts @@ -14,7 +14,7 @@ import type { Query, SQL } from '~/sql/sql.ts'; import { fillPlaceholders } from '~/sql/sql.ts'; export class PrismaPgPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'PrismaPgPreparedQuery'; + static override readonly [entityKind]: string = 'PrismaPgPreparedQuery'; constructor( private readonly prisma: PrismaClient, @@ -44,7 +44,7 @@ export interface PrismaPgSessionOptions { } export class PrismaPgSession extends PgSession { - static readonly [entityKind]: string = 'PrismaPgSession'; + static override readonly [entityKind]: string = 'PrismaPgSession'; private readonly logger: Logger; diff --git a/drizzle-orm/src/prisma/sqlite/session.ts b/drizzle-orm/src/prisma/sqlite/session.ts index 3dbdc6f1a..3a10fddbd 100644 --- a/drizzle-orm/src/prisma/sqlite/session.ts +++ b/drizzle-orm/src/prisma/sqlite/session.ts @@ -19,7 +19,7 @@ type PreparedQueryConfig = Omit; export class PrismaSQLitePreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: []; all: T['all']; get: T['get']; values: never; execute: T['execute'] } > { - static readonly [entityKind]: string = 'PrismaSQLitePreparedQuery'; + static override readonly [entityKind]: string = 'PrismaSQLitePreparedQuery'; constructor( private readonly prisma: PrismaClient, @@ -60,7 +60,7 @@ export interface PrismaSQLiteSessionOptions { } export class PrismaSQLiteSession extends SQLiteSession<'async', unknown, Record, Record> { - static readonly [entityKind]: string = 'PrismaSQLiteSession'; + static override readonly [entityKind]: string = 'PrismaSQLiteSession'; private readonly logger: Logger; diff --git a/drizzle-orm/src/relations.ts b/drizzle-orm/src/relations.ts index 99780897e..ed49c138f 100644 --- a/drizzle-orm/src/relations.ts +++ b/drizzle-orm/src/relations.ts @@ -66,7 +66,7 @@ export class One< TTableName extends string = string, TIsNullable extends boolean = boolean, > extends Relation { - static readonly [entityKind]: string = 'One'; + static override readonly [entityKind]: string = 'One'; declare protected $relationBrand: 'One'; @@ -98,7 +98,7 @@ export class One< } export class Many extends Relation { - static readonly [entityKind]: string = 'Many'; + static override readonly [entityKind]: string = 'Many'; declare protected $relationBrand: 'Many'; diff --git a/drizzle-orm/src/sql-js/session.ts b/drizzle-orm/src/sql-js/session.ts index 4325cd13f..0a09babbd 100644 --- a/drizzle-orm/src/sql-js/session.ts +++ b/drizzle-orm/src/sql-js/session.ts @@ -25,7 +25,7 @@ export class SQLJsSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'sync', void, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLJsSession'; + static override readonly [entityKind]: string = 'SQLJsSession'; private logger: Logger; @@ -90,7 +90,7 @@ export class SQLJsTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'sync', void, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLJsTransaction'; + static override readonly [entityKind]: string = 'SQLJsTransaction'; override transaction(transaction: (tx: SQLJsTransaction) => T): T { const savepointName = `sp${this.nestedIndex + 1}`; @@ -110,7 +110,7 @@ export class SQLJsTransaction< export class PreparedQuery extends PreparedQueryBase< { type: 'sync'; run: void; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'SQLJsPreparedQuery'; + static override readonly [entityKind]: string = 'SQLJsPreparedQuery'; constructor( private stmt: Statement, diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index 96e8d7f69..b7cd90be1 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -20,7 +20,7 @@ export type SQLiteBigIntBuilderInitial = SQLiteBigIntBuild export class SQLiteBigIntBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteBigIntBuilder'; + static override readonly [entityKind]: string = 'SQLiteBigIntBuilder'; constructor(name: T['name']) { super(name, 'bigint', 'SQLiteBigInt'); @@ -35,7 +35,7 @@ export class SQLiteBigIntBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteBigInt'; + static override readonly [entityKind]: string = 'SQLiteBigInt'; getSQLType(): string { return 'blob'; @@ -63,7 +63,7 @@ export type SQLiteBlobJsonBuilderInitial = SQLiteBlobJsonB export class SQLiteBlobJsonBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteBlobJsonBuilder'; + static override readonly [entityKind]: string = 'SQLiteBlobJsonBuilder'; constructor(name: T['name']) { super(name, 'json', 'SQLiteBlobJson'); @@ -81,7 +81,7 @@ export class SQLiteBlobJsonBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteBlobJson'; + static override readonly [entityKind]: string = 'SQLiteBlobJson'; getSQLType(): string { return 'blob'; @@ -109,7 +109,7 @@ export type SQLiteBlobBufferBuilderInitial = SQLiteBlobBuf export class SQLiteBlobBufferBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteBlobBufferBuilder'; + static override readonly [entityKind]: string = 'SQLiteBlobBufferBuilder'; constructor(name: T['name']) { super(name, 'buffer', 'SQLiteBlobBuffer'); @@ -124,7 +124,7 @@ export class SQLiteBlobBufferBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteBlobBuffer'; + static override readonly [entityKind]: string = 'SQLiteBlobBuffer'; getSQLType(): string { return 'blob'; diff --git a/drizzle-orm/src/sqlite-core/columns/common.ts b/drizzle-orm/src/sqlite-core/columns/common.ts index a0cdd755d..0fd985537 100644 --- a/drizzle-orm/src/sqlite-core/columns/common.ts +++ b/drizzle-orm/src/sqlite-core/columns/common.ts @@ -43,7 +43,7 @@ export abstract class SQLiteColumnBuilder< > extends ColumnBuilder implements SQLiteColumnBuilderBase { - static readonly [entityKind]: string = 'SQLiteColumnBuilder'; + static override readonly [entityKind]: string = 'SQLiteColumnBuilder'; private foreignKeyConfigs: ReferenceConfig[] = []; @@ -102,7 +102,7 @@ export abstract class SQLiteColumn< T extends ColumnBaseConfig = ColumnBaseConfig, TRuntimeConfig extends object = object, > extends Column { - static readonly [entityKind]: string = 'SQLiteColumn'; + static override readonly [entityKind]: string = 'SQLiteColumn'; constructor( override readonly table: SQLiteTable, diff --git a/drizzle-orm/src/sqlite-core/columns/custom.ts b/drizzle-orm/src/sqlite-core/columns/custom.ts index 293dd09ad..6ece801c5 100644 --- a/drizzle-orm/src/sqlite-core/columns/custom.ts +++ b/drizzle-orm/src/sqlite-core/columns/custom.ts @@ -35,7 +35,7 @@ export class SQLiteCustomColumnBuilder { - static readonly [entityKind]: string = 'SQLiteCustomColumnBuilder'; + static override readonly [entityKind]: string = 'SQLiteCustomColumnBuilder'; constructor( name: T['name'], @@ -59,7 +59,7 @@ export class SQLiteCustomColumnBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteCustomColumn'; + static override readonly [entityKind]: string = 'SQLiteCustomColumn'; private sqlName: string; private mapTo?: (value: T['data']) => T['driverParam']; diff --git a/drizzle-orm/src/sqlite-core/columns/integer.ts b/drizzle-orm/src/sqlite-core/columns/integer.ts index 449c6357d..10595b9a5 100644 --- a/drizzle-orm/src/sqlite-core/columns/integer.ts +++ b/drizzle-orm/src/sqlite-core/columns/integer.ts @@ -29,7 +29,7 @@ export abstract class SQLiteBaseIntegerBuilder< {}, { primaryKeyHasDefault: true } > { - static readonly [entityKind]: string = 'SQLiteBaseIntegerBuilder'; + static override readonly [entityKind]: string = 'SQLiteBaseIntegerBuilder'; constructor(name: T['name'], dataType: T['dataType'], columnType: T['columnType']) { super(name, dataType, columnType); @@ -54,7 +54,7 @@ export abstract class SQLiteBaseInteger< T extends ColumnBaseConfig, TRuntimeConfig extends object = object, > extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteBaseInteger'; + static override readonly [entityKind]: string = 'SQLiteBaseInteger'; readonly autoIncrement: boolean = this.config.autoIncrement; @@ -76,7 +76,7 @@ export type SQLiteIntegerBuilderInitial = SQLiteIntegerBui export class SQLiteIntegerBuilder> extends SQLiteBaseIntegerBuilder { - static readonly [entityKind]: string = 'SQLiteIntegerBuilder'; + static override readonly [entityKind]: string = 'SQLiteIntegerBuilder'; constructor(name: T['name']) { super(name, 'number', 'SQLiteInteger'); @@ -93,7 +93,7 @@ export class SQLiteIntegerBuilder> extends SQLiteBaseInteger { - static readonly [entityKind]: string = 'SQLiteInteger'; + static override readonly [entityKind]: string = 'SQLiteInteger'; } export type SQLiteTimestampBuilderInitial = SQLiteTimestampBuilder<{ @@ -109,7 +109,7 @@ export type SQLiteTimestampBuilderInitial = SQLiteTimestam export class SQLiteTimestampBuilder> extends SQLiteBaseIntegerBuilder { - static readonly [entityKind]: string = 'SQLiteTimestampBuilder'; + static override readonly [entityKind]: string = 'SQLiteTimestampBuilder'; constructor(name: T['name'], mode: 'timestamp' | 'timestamp_ms') { super(name, 'date', 'SQLiteTimestamp'); @@ -138,7 +138,7 @@ export class SQLiteTimestampBuilder> extends SQLiteBaseInteger { - static readonly [entityKind]: string = 'SQLiteTimestamp'; + static override readonly [entityKind]: string = 'SQLiteTimestamp'; readonly mode: 'timestamp' | 'timestamp_ms' = this.config.mode; @@ -171,7 +171,7 @@ export type SQLiteBooleanBuilderInitial = SQLiteBooleanBui export class SQLiteBooleanBuilder> extends SQLiteBaseIntegerBuilder { - static readonly [entityKind]: string = 'SQLiteBooleanBuilder'; + static override readonly [entityKind]: string = 'SQLiteBooleanBuilder'; constructor(name: T['name'], mode: 'boolean') { super(name, 'boolean', 'SQLiteBoolean'); @@ -191,7 +191,7 @@ export class SQLiteBooleanBuilder> extends SQLiteBaseInteger { - static readonly [entityKind]: string = 'SQLiteBoolean'; + static override readonly [entityKind]: string = 'SQLiteBoolean'; readonly mode: 'boolean' = this.config.mode; diff --git a/drizzle-orm/src/sqlite-core/columns/numeric.ts b/drizzle-orm/src/sqlite-core/columns/numeric.ts index 331547736..93dfc4c3d 100644 --- a/drizzle-orm/src/sqlite-core/columns/numeric.ts +++ b/drizzle-orm/src/sqlite-core/columns/numeric.ts @@ -17,7 +17,7 @@ export type SQLiteNumericBuilderInitial = SQLiteNumericBui export class SQLiteNumericBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteNumericBuilder'; + static override readonly [entityKind]: string = 'SQLiteNumericBuilder'; constructor(name: T['name']) { super(name, 'string', 'SQLiteNumeric'); @@ -35,7 +35,7 @@ export class SQLiteNumericBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteNumeric'; + static override readonly [entityKind]: string = 'SQLiteNumeric'; getSQLType(): string { return 'numeric'; diff --git a/drizzle-orm/src/sqlite-core/columns/real.ts b/drizzle-orm/src/sqlite-core/columns/real.ts index 693780e9d..cd7cf5d01 100644 --- a/drizzle-orm/src/sqlite-core/columns/real.ts +++ b/drizzle-orm/src/sqlite-core/columns/real.ts @@ -17,7 +17,7 @@ export type SQLiteRealBuilderInitial = SQLiteRealBuilder<{ export class SQLiteRealBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteRealBuilder'; + static override readonly [entityKind]: string = 'SQLiteRealBuilder'; constructor(name: T['name']) { super(name, 'number', 'SQLiteReal'); @@ -32,7 +32,7 @@ export class SQLiteRealBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteReal'; + static override readonly [entityKind]: string = 'SQLiteReal'; getSQLType(): string { return 'real'; diff --git a/drizzle-orm/src/sqlite-core/columns/text.ts b/drizzle-orm/src/sqlite-core/columns/text.ts index 033c2cb99..84c71fb20 100644 --- a/drizzle-orm/src/sqlite-core/columns/text.ts +++ b/drizzle-orm/src/sqlite-core/columns/text.ts @@ -19,7 +19,7 @@ export class SQLiteTextBuilder { - static readonly [entityKind]: string = 'SQLiteTextBuilder'; + static override readonly [entityKind]: string = 'SQLiteTextBuilder'; constructor(name: T['name'], config: SQLiteTextConfig<'text', T['enumValues']>) { super(name, 'string', 'SQLiteText'); @@ -38,7 +38,7 @@ export class SQLiteTextBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteText'; + static override readonly [entityKind]: string = 'SQLiteText'; override readonly enumValues = this.config.enumValues; @@ -69,7 +69,7 @@ export type SQLiteTextJsonBuilderInitial = SQLiteTextJsonB export class SQLiteTextJsonBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteTextJsonBuilder'; + static override readonly [entityKind]: string = 'SQLiteTextJsonBuilder'; constructor(name: T['name']) { super(name, 'json', 'SQLiteTextJson'); @@ -89,7 +89,7 @@ export class SQLiteTextJsonBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteTextJson'; + static override readonly [entityKind]: string = 'SQLiteTextJson'; getSQLType(): string { return 'text'; diff --git a/drizzle-orm/src/sqlite-core/dialect.ts b/drizzle-orm/src/sqlite-core/dialect.ts index d3822be5e..e9ac87f73 100644 --- a/drizzle-orm/src/sqlite-core/dialect.ts +++ b/drizzle-orm/src/sqlite-core/dialect.ts @@ -745,7 +745,7 @@ export abstract class SQLiteDialect { } export class SQLiteSyncDialect extends SQLiteDialect { - static readonly [entityKind]: string = 'SQLiteSyncDialect'; + static override readonly [entityKind]: string = 'SQLiteSyncDialect'; migrate( migrations: MigrationMeta[], @@ -797,7 +797,7 @@ export class SQLiteSyncDialect extends SQLiteDialect { } export class SQLiteAsyncDialect extends SQLiteDialect { - static readonly [entityKind]: string = 'SQLiteAsyncDialect'; + static override readonly [entityKind]: string = 'SQLiteAsyncDialect'; async migrate( migrations: MigrationMeta[], diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index 424276825..1c1234034 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -9,7 +9,7 @@ export class SQLiteCountBuilder< > extends SQL implements Promise, SQLWrapper { private sql: SQL; - static readonly [entityKind] = 'SQLiteCountBuilderAsync'; + static override readonly [entityKind] = 'SQLiteCountBuilderAsync'; [Symbol.toStringTag] = 'SQLiteCountBuilderAsync'; private session: TSession; diff --git a/drizzle-orm/src/sqlite-core/query-builders/delete.ts b/drizzle-orm/src/sqlite-core/query-builders/delete.ts index 1a028c09a..fe40c662f 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/delete.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/delete.ts @@ -136,7 +136,7 @@ export class SQLiteDeleteBase< > extends QueryPromise implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'SQLiteDelete'; + static override readonly [entityKind]: string = 'SQLiteDelete'; /** @internal */ config: SQLiteDeleteConfig; diff --git a/drizzle-orm/src/sqlite-core/query-builders/insert.ts b/drizzle-orm/src/sqlite-core/query-builders/insert.ts index b0861fade..4f20666c4 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/insert.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/insert.ts @@ -199,7 +199,7 @@ export class SQLiteInsertBase< > extends QueryPromise implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'SQLiteInsert'; + static override readonly [entityKind]: string = 'SQLiteInsert'; /** @internal */ config: SQLiteInsertConfig; diff --git a/drizzle-orm/src/sqlite-core/query-builders/query.ts b/drizzle-orm/src/sqlite-core/query-builders/query.ts index 9ae47f9ce..ef93e992a 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/query.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/query.ts @@ -98,7 +98,7 @@ export class RelationalQueryBuilder< export class SQLiteRelationalQuery extends QueryPromise implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'SQLiteAsyncRelationalQuery'; + static override readonly [entityKind]: string = 'SQLiteAsyncRelationalQuery'; declare readonly _: { readonly dialect: 'sqlite'; @@ -199,7 +199,7 @@ export class SQLiteRelationalQuery exte } export class SQLiteSyncRelationalQuery extends SQLiteRelationalQuery<'sync', TResult> { - static readonly [entityKind]: string = 'SQLiteSyncRelationalQuery'; + static override readonly [entityKind]: string = 'SQLiteSyncRelationalQuery'; sync(): TResult { return this.executeRaw(); diff --git a/drizzle-orm/src/sqlite-core/query-builders/raw.ts b/drizzle-orm/src/sqlite-core/query-builders/raw.ts index 10ddb38bd..488f45afe 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/raw.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/raw.ts @@ -15,7 +15,7 @@ export interface SQLiteRaw extends QueryPromise, RunnableQuery export class SQLiteRaw extends QueryPromise implements RunnableQuery, SQLWrapper, PreparedQuery { - static readonly [entityKind]: string = 'SQLiteRaw'; + static override readonly [entityKind]: string = 'SQLiteRaw'; declare readonly _: { readonly dialect: 'sqlite'; diff --git a/drizzle-orm/src/sqlite-core/query-builders/select.ts b/drizzle-orm/src/sqlite-core/query-builders/select.ts index b7f4b0465..d9fce748a 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/select.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/select.ts @@ -137,7 +137,7 @@ export abstract class SQLiteSelectQueryBuilderBase< TResult extends any[] = SelectResult[], TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > extends TypedQueryBuilder { - static readonly [entityKind]: string = 'SQLiteSelectQueryBuilder'; + static override readonly [entityKind]: string = 'SQLiteSelectQueryBuilder'; override readonly _: { readonly dialect: 'sqlite'; @@ -854,7 +854,7 @@ export class SQLiteSelectBase< TResult, TSelectedFields > implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'SQLiteSelect'; + static override readonly [entityKind]: string = 'SQLiteSelect'; /** @internal */ _prepare(isOneTimeQuery = true): SQLiteSelectPrepare { diff --git a/drizzle-orm/src/sqlite-core/query-builders/update.ts b/drizzle-orm/src/sqlite-core/query-builders/update.ts index 0238b748f..54f78845b 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/update.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/update.ts @@ -169,7 +169,7 @@ export class SQLiteUpdateBase< > extends QueryPromise implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'SQLiteUpdate'; + static override readonly [entityKind]: string = 'SQLiteUpdate'; /** @internal */ config: SQLiteUpdateConfig; diff --git a/drizzle-orm/src/sqlite-core/session.ts b/drizzle-orm/src/sqlite-core/session.ts index d291b6fdf..9e6924ca0 100644 --- a/drizzle-orm/src/sqlite-core/session.ts +++ b/drizzle-orm/src/sqlite-core/session.ts @@ -20,7 +20,7 @@ export interface PreparedQueryConfig { } export class ExecuteResultSync extends QueryPromise { - static readonly [entityKind]: string = 'ExecuteResultSync'; + static override readonly [entityKind]: string = 'ExecuteResultSync'; constructor(private resultCb: () => T) { super(); @@ -209,7 +209,7 @@ export abstract class SQLiteTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends BaseSQLiteDatabase { - static readonly [entityKind]: string = 'SQLiteTransaction'; + static override readonly [entityKind]: string = 'SQLiteTransaction'; constructor( resultType: TResultType, diff --git a/drizzle-orm/src/sqlite-core/table.ts b/drizzle-orm/src/sqlite-core/table.ts index c223e2d6f..d7c5a060b 100644 --- a/drizzle-orm/src/sqlite-core/table.ts +++ b/drizzle-orm/src/sqlite-core/table.ts @@ -24,7 +24,7 @@ export type TableConfig = TableConfigBase>; export const InlineForeignKeys = Symbol.for('drizzle:SQLiteInlineForeignKeys'); export class SQLiteTable extends Table { - static readonly [entityKind]: string = 'SQLiteTable'; + static override readonly [entityKind]: string = 'SQLiteTable'; /** @internal */ static override readonly Symbol = Object.assign({}, Table.Symbol, { diff --git a/drizzle-orm/src/sqlite-core/view-base.ts b/drizzle-orm/src/sqlite-core/view-base.ts index ac3328905..dd2f306a9 100644 --- a/drizzle-orm/src/sqlite-core/view-base.ts +++ b/drizzle-orm/src/sqlite-core/view-base.ts @@ -7,7 +7,7 @@ export abstract class SQLiteViewBase< TExisting extends boolean = boolean, TSelection extends ColumnsSelection = ColumnsSelection, > extends View { - static readonly [entityKind]: string = 'SQLiteViewBase'; + static override readonly [entityKind]: string = 'SQLiteViewBase'; declare _: View['_'] & { viewBrand: 'SQLiteView'; diff --git a/drizzle-orm/src/sqlite-core/view.ts b/drizzle-orm/src/sqlite-core/view.ts index d1f11969e..59aa249dc 100644 --- a/drizzle-orm/src/sqlite-core/view.ts +++ b/drizzle-orm/src/sqlite-core/view.ts @@ -37,7 +37,7 @@ export class ViewBuilderCore< } export class ViewBuilder extends ViewBuilderCore<{ name: TName }> { - static readonly [entityKind]: string = 'SQLiteViewBuilder'; + static override readonly [entityKind]: string = 'SQLiteViewBuilder'; as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), @@ -74,7 +74,7 @@ export class ManualViewBuilder< > extends ViewBuilderCore< { name: TName; columns: TColumns } > { - static readonly [entityKind]: string = 'SQLiteManualViewBuilder'; + static override readonly [entityKind]: string = 'SQLiteManualViewBuilder'; private columns: Record; @@ -132,7 +132,7 @@ export class SQLiteView< TExisting extends boolean = boolean, TSelection extends ColumnsSelection = ColumnsSelection, > extends SQLiteViewBase { - static readonly [entityKind]: string = 'SQLiteView'; + static override readonly [entityKind]: string = 'SQLiteView'; /** @internal */ [SQLiteViewConfig]: ViewBuilderConfig | undefined; diff --git a/drizzle-orm/src/sqlite-proxy/driver.ts b/drizzle-orm/src/sqlite-proxy/driver.ts index e3f2b2af7..e11e977c1 100644 --- a/drizzle-orm/src/sqlite-proxy/driver.ts +++ b/drizzle-orm/src/sqlite-proxy/driver.ts @@ -15,7 +15,7 @@ export interface SqliteRemoteResult { export class SqliteRemoteDatabase< TSchema extends Record = Record, > extends BaseSQLiteDatabase<'async', SqliteRemoteResult, TSchema> { - static readonly [entityKind]: string = 'SqliteRemoteDatabase'; + static override readonly [entityKind]: string = 'SqliteRemoteDatabase'; /** @internal */ declare readonly session: SQLiteRemoteSession>; diff --git a/drizzle-orm/src/sqlite-proxy/session.ts b/drizzle-orm/src/sqlite-proxy/session.ts index 398913568..93d277d69 100644 --- a/drizzle-orm/src/sqlite-proxy/session.ts +++ b/drizzle-orm/src/sqlite-proxy/session.ts @@ -27,7 +27,7 @@ export class SQLiteRemoteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'async', SqliteRemoteResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLiteRemoteSession'; + static override readonly [entityKind]: string = 'SQLiteRemoteSession'; private logger: Logger; @@ -108,7 +108,7 @@ export class SQLiteProxyTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'async', SqliteRemoteResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLiteProxyTransaction'; + static override readonly [entityKind]: string = 'SQLiteProxyTransaction'; override async transaction( transaction: (tx: SQLiteProxyTransaction) => Promise, @@ -130,7 +130,7 @@ export class SQLiteProxyTransaction< export class RemotePreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: SqliteRemoteResult; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'SQLiteProxyPreparedQuery'; + static override readonly [entityKind]: string = 'SQLiteProxyPreparedQuery'; private method: SQLiteExecuteMethod; diff --git a/drizzle-orm/src/subquery.ts b/drizzle-orm/src/subquery.ts index 320ec46e6..37fe48d86 100644 --- a/drizzle-orm/src/subquery.ts +++ b/drizzle-orm/src/subquery.ts @@ -42,5 +42,5 @@ export class WithSubquery< TAlias extends string = string, TSelection extends Record = Record, > extends Subquery { - static readonly [entityKind]: string = 'WithSubquery'; + static override readonly [entityKind]: string = 'WithSubquery'; } diff --git a/drizzle-orm/src/tidb-serverless/driver.ts b/drizzle-orm/src/tidb-serverless/driver.ts index ec82e61ff..2a7b1d986 100644 --- a/drizzle-orm/src/tidb-serverless/driver.ts +++ b/drizzle-orm/src/tidb-serverless/driver.ts @@ -21,7 +21,7 @@ export interface TiDBServerlessSDriverOptions { export class TiDBServerlessDatabase< TSchema extends Record = Record, > extends MySqlDatabase { - static readonly [entityKind]: string = 'TiDBServerlessDatabase'; + static override readonly [entityKind]: string = 'TiDBServerlessDatabase'; } export function drizzle = Record>( diff --git a/drizzle-orm/src/tidb-serverless/session.ts b/drizzle-orm/src/tidb-serverless/session.ts index b01b9f948..279c60f3b 100644 --- a/drizzle-orm/src/tidb-serverless/session.ts +++ b/drizzle-orm/src/tidb-serverless/session.ts @@ -22,7 +22,7 @@ const executeRawConfig = { fullResult: true } satisfies ExecuteOptions; const queryConfig = { arrayMode: true } satisfies ExecuteOptions; export class TiDBServerlessPreparedQuery extends MySqlPreparedQuery { - static readonly [entityKind]: string = 'TiDBPreparedQuery'; + static override readonly [entityKind]: string = 'TiDBPreparedQuery'; constructor( private client: Tx | Connection, @@ -97,7 +97,7 @@ export class TiDBServerlessSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlSession { - static readonly [entityKind]: string = 'TiDBServerlessSession'; + static override readonly [entityKind]: string = 'TiDBServerlessSession'; private logger: Logger; private client: Tx | Connection; @@ -172,7 +172,7 @@ export class TiDBServerlessTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlTransaction { - static readonly [entityKind]: string = 'TiDBServerlessTransaction'; + static override readonly [entityKind]: string = 'TiDBServerlessTransaction'; constructor( dialect: MySqlDialect, diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 52a55db2c..479f239bf 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -45,7 +45,7 @@ export class VercelPgDriver { export class VercelPgDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'VercelPgDatabase'; + static override readonly [entityKind]: string = 'VercelPgDatabase'; } export function drizzle = Record>( diff --git a/drizzle-orm/src/vercel-postgres/session.ts b/drizzle-orm/src/vercel-postgres/session.ts index 51a987905..5d16539f0 100644 --- a/drizzle-orm/src/vercel-postgres/session.ts +++ b/drizzle-orm/src/vercel-postgres/session.ts @@ -20,7 +20,7 @@ import { type Assume, mapResultRow } from '~/utils.ts'; export type VercelPgClient = VercelPool | VercelClient | VercelPoolClient; export class VercelPgPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'VercelPgPreparedQuery'; + static override readonly [entityKind]: string = 'VercelPgPreparedQuery'; private rawQuery: QueryConfig; private queryConfig: QueryArrayConfig; @@ -92,7 +92,7 @@ export class VercelPgSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'VercelPgSession'; + static override readonly [entityKind]: string = 'VercelPgSession'; private logger: Logger; @@ -170,7 +170,7 @@ export class VercelPgTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'VercelPgTransaction'; + static override readonly [entityKind]: string = 'VercelPgTransaction'; override async transaction( transaction: (tx: VercelPgTransaction) => Promise, diff --git a/drizzle-orm/src/xata-http/driver.ts b/drizzle-orm/src/xata-http/driver.ts index 82986f298..ce275a88d 100644 --- a/drizzle-orm/src/xata-http/driver.ts +++ b/drizzle-orm/src/xata-http/driver.ts @@ -40,7 +40,7 @@ export class XataHttpDriver { export class XataHttpDatabase = Record> extends PgDatabase { - static readonly [entityKind]: string = 'XataHttpDatabase'; + static override readonly [entityKind]: string = 'XataHttpDatabase'; /** @internal */ declare readonly session: XataHttpSession>; diff --git a/drizzle-orm/src/xata-http/session.ts b/drizzle-orm/src/xata-http/session.ts index c666ba09d..df4cc1003 100644 --- a/drizzle-orm/src/xata-http/session.ts +++ b/drizzle-orm/src/xata-http/session.ts @@ -22,7 +22,7 @@ export interface QueryResults { } export class XataHttpPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'XataHttpPreparedQuery'; + static override readonly [entityKind]: string = 'XataHttpPreparedQuery'; constructor( private client: XataHttpClient, @@ -84,7 +84,7 @@ export class XataHttpSession, TSchem TSchema > { - static readonly [entityKind]: string = 'XataHttpSession'; + static override readonly [entityKind]: string = 'XataHttpSession'; private logger: Logger; @@ -152,7 +152,7 @@ export class XataTransaction, TSchem TSchema > { - static readonly [entityKind]: string = 'XataHttpTransaction'; + static override readonly [entityKind]: string = 'XataHttpTransaction'; override async transaction(_transaction: (tx: XataTransaction) => Promise): Promise { throw new Error('No transactions support in Xata Http driver'); diff --git a/integration-tests/package.json b/integration-tests/package.json index 78f36fe30..f8f8bfdb8 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -15,6 +15,7 @@ "license": "Apache-2.0", "private": true, "devDependencies": { + "@cloudflare/workers-types": "^4.20241004.0", "@libsql/client": "^0.10.0", "@neondatabase/serverless": "0.9.0", "@originjs/vite-plugin-commonjs": "^1.0.3", @@ -42,8 +43,8 @@ "@aws-sdk/client-rds-data": "^3.549.0", "@aws-sdk/credential-providers": "^3.549.0", "@electric-sql/pglite": "^0.1.1", - "@miniflare/d1": "^2.14.2", - "@miniflare/shared": "^2.14.2", + "@miniflare/d1": "^2.14.4", + "@miniflare/shared": "^2.14.4", "@planetscale/database": "^1.16.0", "@prisma/client": "5.14.0", "@tidbcloud/serverless": "^0.1.1", @@ -70,7 +71,7 @@ "sst": "^3.0.4", "uuid": "^9.0.0", "uvu": "^0.5.6", - "vitest": "^1.6.0", + "vitest": "^2.1.2", "zod": "^3.20.2" } } diff --git a/integration-tests/tests/bun/sqlite-nw.test.ts b/integration-tests/tests/bun/sqlite-nw.test.ts index f6c11a698..d61d1ab4e 100644 --- a/integration-tests/tests/bun/sqlite-nw.test.ts +++ b/integration-tests/tests/bun/sqlite-nw.test.ts @@ -1,3 +1,4 @@ +/// import { Database } from 'bun:sqlite'; import { DefaultLogger, sql } from 'drizzle-orm'; import type { BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite'; diff --git a/integration-tests/tests/bun/sqlite.test.ts b/integration-tests/tests/bun/sqlite.test.ts index faa3f8eb1..0065b1928 100644 --- a/integration-tests/tests/bun/sqlite.test.ts +++ b/integration-tests/tests/bun/sqlite.test.ts @@ -1,3 +1,4 @@ +/// import { Database } from 'bun:sqlite'; import { DefaultLogger, sql } from 'drizzle-orm'; import type { BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite'; diff --git a/integration-tests/tests/common.ts b/integration-tests/tests/common.ts index 55daa43ce..0a4a61e94 100644 --- a/integration-tests/tests/common.ts +++ b/integration-tests/tests/common.ts @@ -2,7 +2,7 @@ import { beforeEach } from 'vitest'; export function skipTests(names: string[]) { beforeEach((ctx) => { - if (ctx.task.suite.name === 'common' && names.includes(ctx.task.name)) { + if (ctx.task.suite?.name === 'common' && names.includes(ctx.task.name)) { ctx.skip(); } }); diff --git a/integration-tests/tests/sqlite/d1-batch.test.ts b/integration-tests/tests/sqlite/d1-batch.test.ts index 2c46a6fe4..dba22cd4d 100644 --- a/integration-tests/tests/sqlite/d1-batch.test.ts +++ b/integration-tests/tests/sqlite/d1-batch.test.ts @@ -1,3 +1,4 @@ +/// import 'dotenv/config'; import { D1Database, D1DatabaseAPI } from '@miniflare/d1'; import { createSQLiteDB } from '@miniflare/shared'; diff --git a/package.json b/package.json index 4e7bd4e91..b0fda61c8 100755 --- a/package.json +++ b/package.json @@ -35,12 +35,7 @@ "tsup": "^7.2.0", "tsx": "^4.10.5", "turbo": "^1.10.14", - "typescript": "5.4.5" - }, - "pnpm": { - "patchedDependencies": { - "typescript@5.4.5": "patches/typescript@5.4.5.patch" - } + "typescript": "5.6.3" }, "packageManager": "pnpm@9.7.0" } diff --git a/patches/typescript@5.4.5.patch b/patches/typescript@5.6.3.patch similarity index 100% rename from patches/typescript@5.4.5.patch rename to patches/typescript@5.6.3.patch diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f5d886131..d78d24b78 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,11 +4,6 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -patchedDependencies: - typescript@5.4.5: - hash: q3iy4fwdhi5sis3wty7d4nbsme - path: patches/typescript@5.4.5.patch - importers: .: @@ -21,13 +16,13 @@ importers: version: 4.2.0(prettier@3.0.3) '@typescript-eslint/eslint-plugin': specifier: ^6.7.3 - version: 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/experimental-utils': specifier: ^5.62.0 - version: 5.62.0(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 5.62.0(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^6.7.3 - version: 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 6.7.3(eslint@8.50.0)(typescript@5.6.3) bun-types: specifier: ^1.0.3 version: 1.0.3 @@ -45,7 +40,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -54,7 +49,7 @@ importers: version: link:eslint/eslint-plugin-drizzle-internal eslint-plugin-import: specifier: ^2.28.1 - version: 2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0) + version: 2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0) eslint-plugin-no-instanceof: specifier: ^1.0.1 version: 1.0.1 @@ -63,7 +58,7 @@ importers: version: 48.0.1(eslint@8.50.0) eslint-plugin-unused-imports: specifier: ^3.0.0 - version: 3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0) + version: 3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0) glob: specifier: ^10.3.10 version: 10.3.10 @@ -75,10 +70,10 @@ importers: version: 0.23.9 resolve-tspaths: specifier: ^0.8.16 - version: 0.8.16(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 0.8.16(typescript@5.6.3) tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3) tsx: specifier: ^4.10.5 version: 4.10.5 @@ -86,8 +81,8 @@ importers: specifier: ^1.10.14 version: 1.10.14 typescript: - specifier: 5.4.5 - version: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + specifier: 5.6.3 + version: 5.6.3 drizzle-kit: dependencies: @@ -169,10 +164,10 @@ importers: version: 8.5.11 '@typescript-eslint/eslint-plugin': specifier: ^7.2.0 - version: 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/parser': specifier: ^7.2.0 - version: 7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 7.16.1(eslint@8.57.0)(typescript@5.4.5) '@vercel/postgres': specifier: ^0.8.0 version: 0.8.0 @@ -265,19 +260,19 @@ importers: version: 2.2.1 tsup: specifier: ^8.0.2 - version: 8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(yaml@2.4.2) + version: 8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.4.5)(yaml@2.4.2) tsx: specifier: ^3.12.1 version: 3.14.0 typescript: specifier: ^5.4.3 - version: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + version: 5.4.5 uuid: specifier: ^9.0.1 version: 9.0.1 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.4.5)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.4.0 version: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -309,8 +304,8 @@ importers: specifier: ^0.10.0 version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@miniflare/d1': - specifier: ^2.14.2 - version: 2.14.2 + specifier: ^2.14.4 + version: 2.14.4 '@neondatabase/serverless': specifier: ^0.9.0 version: 0.9.0 @@ -352,7 +347,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.4(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 0.29.4(typescript@5.6.3) better-sqlite3: specifier: ^8.4.0 version: 8.7.0 @@ -400,7 +395,7 @@ importers: version: 3.14.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -418,7 +413,7 @@ importers: version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.6.3) '@sinclair/typebox': specifier: ^0.29.6 version: 0.29.6 @@ -439,7 +434,7 @@ importers: version: 3.27.2 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -454,7 +449,7 @@ importers: version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 version: 18.15.10 @@ -475,7 +470,7 @@ importers: version: 0.30.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -490,7 +485,7 @@ importers: version: 0.4.1(rollup@3.20.7) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 version: 18.15.10 @@ -508,7 +503,7 @@ importers: version: 3.20.7 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -553,16 +548,16 @@ importers: version: 3.583.0 '@aws-sdk/credential-providers': specifier: ^3.549.0 - version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0) + version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@electric-sql/pglite': specifier: ^0.1.1 version: 0.1.5 '@miniflare/d1': - specifier: ^2.14.2 - version: 2.14.2 + specifier: ^2.14.4 + version: 2.14.4 '@miniflare/shared': - specifier: ^2.14.2 - version: 2.14.2 + specifier: ^2.14.4 + version: 2.14.4 '@planetscale/database': specifier: ^1.16.0 version: 1.18.0 @@ -580,7 +575,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.4(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 0.29.4(typescript@5.6.3) async-retry: specifier: ^1.3.3 version: 1.3.3 @@ -642,12 +637,15 @@ importers: specifier: ^0.5.6 version: 0.5.6 vitest: - specifier: ^1.6.0 - version: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + specifier: ^2.1.2 + version: 2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) zod: specifier: ^3.20.2 version: 3.23.7 devDependencies: + '@cloudflare/workers-types': + specifier: ^4.20241004.0 + version: 4.20241004.0 '@libsql/client': specifier: ^0.10.0 version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) @@ -689,7 +687,7 @@ importers: version: 9.0.8 '@vitest/ui': specifier: ^1.6.0 - version: 1.6.0(vitest@1.6.0) + version: 1.6.0(vitest@2.1.2) ava: specifier: ^5.3.0 version: 5.3.0(@ava/typescript@5.0.0) @@ -701,7 +699,7 @@ importers: version: 7.0.3 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 10.9.2(@types/node@20.12.12)(typescript@5.6.3) tsx: specifier: ^4.14.0 version: 4.16.2 @@ -710,7 +708,7 @@ importers: version: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) zx: specifier: ^7.2.2 version: 7.2.2 @@ -1937,6 +1935,9 @@ packages: '@cloudflare/workers-types@4.20240524.0': resolution: {integrity: sha512-GpSr4uE7y39DU9f0+wmrL76xd03wn0jy1ClITaa3ZZltKjirAV8TW1GzHrvvKyVGx6u3lekrFnB1HzVHsCYHDQ==} + '@cloudflare/workers-types@4.20241004.0': + resolution: {integrity: sha512-3LrPvtecs4umknOF1bTPNLHUG/ZjeSE6PYBQ/tbO7lwaVhjZTaTugiaCny2byrZupBlVNuubQVktcAgMfw0C1A==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -3075,6 +3076,9 @@ packages: '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/trace-mapping@0.3.18': resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} @@ -3170,24 +3174,24 @@ packages: cpu: [x64] os: [win32] - '@miniflare/core@2.14.2': - resolution: {integrity: sha512-n/smm5ZTg7ilGM4fxO7Gxhbe573oc8Za06M3b2fO+lPWqF6NJcEKdCC+sJntVFbn3Cbbd2G1ChISmugPfmlCkQ==} + '@miniflare/core@2.14.4': + resolution: {integrity: sha512-FMmZcC1f54YpF4pDWPtdQPIO8NXfgUxCoR9uyrhxKJdZu7M6n8QKopPVNuaxR40jcsdxb7yKoQoFWnHfzJD9GQ==} engines: {node: '>=16.13'} - '@miniflare/d1@2.14.2': - resolution: {integrity: sha512-3NPJyBLbFfzz9VAAdIZrDRdRpyslVCJoZHQk0/0CX3z2mJIfcQzjZhox2cYCFNH8NMJ7pRg6AeSMPYAnDKECDg==} + '@miniflare/d1@2.14.4': + resolution: {integrity: sha512-pMBVq9XWxTDdm+RRCkfXZP+bREjPg1JC8s8C0JTovA9OGmLQXqGTnFxIaS9vf1d8k3uSUGhDzPTzHr0/AUW1gA==} engines: {node: '>=16.7'} - '@miniflare/queues@2.14.2': - resolution: {integrity: sha512-OylkRs4lOWKvGnX+Azab3nx+1qwC87M36/hkgAU1RRvVDCOxOrYLvNLUczFfgmgMBwpYsmmW8YOIASlI3p4Qgw==} + '@miniflare/queues@2.14.4': + resolution: {integrity: sha512-aXQ5Ik8Iq1KGMBzGenmd6Js/jJgqyYvjom95/N9GptCGpiVWE5F0XqC1SL5rCwURbHN+aWY191o8XOFyY2nCUA==} engines: {node: '>=16.7'} - '@miniflare/shared@2.14.2': - resolution: {integrity: sha512-dDnYIztz10zDQjaFJ8Gy9UaaBWZkw3NyhFdpX6tAeyPA/2lGvkftc42MYmNi8s5ljqkZAtKgWAJnSf2K75NCJw==} + '@miniflare/shared@2.14.4': + resolution: {integrity: sha512-upl4RSB3hyCnITOFmRZjJj4A72GmkVrtfZTilkdq5Qe5TTlzsjVeDJp7AuNUM9bM8vswRo+N5jOiot6O4PVwwQ==} engines: {node: '>=16.13'} - '@miniflare/watcher@2.14.2': - resolution: {integrity: sha512-/TL0np4uYDl+6MdseDApZmDdlJ6Y7AY5iDY0TvUQJG9nyBoCjX6w0Zn4SiKDwO6660rPtSqZ5c7HzbPhGb5vsA==} + '@miniflare/watcher@2.14.4': + resolution: {integrity: sha512-PYn05ET2USfBAeXF6NZfWl0O32KVyE8ncQ/ngysrh3hoIV7l3qGGH7ubeFx+D8VWQ682qYhwGygUzQv2j1tGGg==} engines: {node: '>=16.13'} '@neon-rs/load@0.0.4': @@ -4355,15 +4359,42 @@ packages: '@vitest/expect@1.6.0': resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} + '@vitest/expect@2.1.2': + resolution: {integrity: sha512-FEgtlN8mIUSEAAnlvn7mP8vzaWhEaAEvhSXCqrsijM7K6QqjB11qoRZYEd4AKSCDz8p0/+yH5LzhZ47qt+EyPg==} + + '@vitest/mocker@2.1.2': + resolution: {integrity: sha512-ExElkCGMS13JAJy+812fw1aCv2QO/LBK6CyO4WOPAzLTmve50gydOlWhgdBJPx2ztbADUq3JVI0C5U+bShaeEA==} + peerDependencies: + '@vitest/spy': 2.1.2 + msw: ^2.3.5 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.2': + resolution: {integrity: sha512-FIoglbHrSUlOJPDGIrh2bjX1sNars5HbxlcsFKCtKzu4+5lpsRhOCVcuzp0fEhAGHkPZRIXVNzPcpSlkoZ3LuA==} + '@vitest/runner@1.6.0': resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} + '@vitest/runner@2.1.2': + resolution: {integrity: sha512-UCsPtvluHO3u7jdoONGjOSil+uON5SSvU9buQh3lP7GgUXHp78guN1wRmZDX4wGK6J10f9NUtP6pO+SFquoMlw==} + '@vitest/snapshot@1.6.0': resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} + '@vitest/snapshot@2.1.2': + resolution: {integrity: sha512-xtAeNsZ++aRIYIUsek7VHzry/9AcxeULlegBvsdLncLmNCR6tR8SRjn8BbDP4naxtccvzTqZ+L1ltZlRCfBZFA==} + '@vitest/spy@1.6.0': resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} + '@vitest/spy@2.1.2': + resolution: {integrity: sha512-GSUi5zoy+abNRJwmFhBDC0yRuVUn8WMlQscvnbbXdKLXX9dE59YbfwXxuJ/mth6eeqIzofU8BB5XDo/Ns/qK2A==} + '@vitest/ui@1.6.0': resolution: {integrity: sha512-k3Lyo+ONLOgylctiGovRKy7V4+dIN2yxstX3eY5cWFXH6WP+ooVX79YSyi0GagdTQzLmT43BF27T0s6dOIPBXA==} peerDependencies: @@ -4372,6 +4403,9 @@ packages: '@vitest/utils@1.6.0': resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} + '@vitest/utils@2.1.2': + resolution: {integrity: sha512-zMO2KdYy6mx56btx9JvAqAZ6EyS3g49krMPPrgOp1yxGZiA93HumGk+bZ5jIZtOg5/VBYl5eBmGRQHqq4FG6uQ==} + '@xata.io/client@0.29.4': resolution: {integrity: sha512-dRff4E/wINr0SYIlOHwApo0h8jzpAHVf2RcbGMkK9Xrddbe90KmCEx/gue9hLhBOoCCp6qUht2h9BsuVPruymw==} peerDependencies: @@ -4585,6 +4619,10 @@ packages: assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + ast-types@0.15.2: resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} engines: {node: '>=4'} @@ -4875,6 +4913,10 @@ packages: resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} engines: {node: '>=4'} + chai@5.1.1: + resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} + engines: {node: '>=12'} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -4897,6 +4939,10 @@ packages: check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -5271,6 +5317,15 @@ packages: supports-color: optional: true + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} @@ -5283,6 +5338,10 @@ packages: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -7287,6 +7346,9 @@ packages: loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + loupe@3.1.2: + resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} + lru-cache@10.2.2: resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} engines: {node: 14 || >=16.14} @@ -7319,6 +7381,9 @@ packages: magic-string@0.30.10: resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} + make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -8056,6 +8121,10 @@ packages: pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + pause-stream@0.0.11: resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} @@ -9205,14 +9274,32 @@ packages: tinybench@2.8.0: resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.0: + resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} + tinypool@0.8.4: resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} engines: {node: '>=14.0.0'} + tinypool@1.0.1: + resolution: {integrity: sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + tinyspy@2.2.1: resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} engines: {node: '>=14.0.0'} + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -9504,6 +9591,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + ua-parser-js@1.0.38: resolution: {integrity: sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==} @@ -9516,10 +9608,6 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici@5.28.2: - resolution: {integrity: sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==} - engines: {node: '>=14.0'} - undici@5.28.4: resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} engines: {node: '>=14.0'} @@ -9664,6 +9752,11 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true + vite-node@2.1.2: + resolution: {integrity: sha512-HPcGNN5g/7I2OtPjLqgOtCRu/qhVvBxTUD3qzitmL0SrG1cWFzxzhMDWussxSbrRYWqnKf8P2jiNhPMSN+ymsQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + vite-tsconfig-paths@4.3.2: resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} peerDependencies: @@ -9753,6 +9846,31 @@ packages: jsdom: optional: true + vitest@2.1.2: + resolution: {integrity: sha512-veNjLizOMkRrJ6xxb+pvxN6/QAWg95mzcRjtmkepXdN87FNfxAss9RKe2far/G9cQpipfgP2taqg0KiWsquj8A==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.2 + '@vitest/ui': 2.1.2 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vlq@1.0.1: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} @@ -9830,6 +9948,11 @@ packages: engines: {node: '>=8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} @@ -10782,12 +10905,12 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -10870,13 +10993,13 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -10957,10 +11080,10 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': dependencies: '@aws-sdk/client-sso': 3.568.0 - '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11014,7 +11137,7 @@ snapshots: '@smithy/types': 3.0.0 tslib: 2.6.2 - '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': dependencies: '@aws-sdk/client-cognito-identity': 3.569.0 '@aws-sdk/client-sso': 3.568.0 @@ -11022,10 +11145,10 @@ snapshots: '@aws-sdk/credential-provider-cognito-identity': 3.569.0 '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -11207,7 +11330,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': dependencies: '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.567.0 @@ -11344,7 +11467,7 @@ snapshots: '@babel/traverse': 7.24.6 '@babel/types': 7.24.6 convert-source-map: 2.0.0 - debug: 4.3.5 + debug: 4.3.7 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -11405,7 +11528,7 @@ snapshots: '@babel/core': 7.24.6 '@babel/helper-compilation-targets': 7.24.6 '@babel/helper-plugin-utils': 7.24.6 - debug: 4.3.5 + debug: 4.3.7 lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -12277,7 +12400,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - debug: 4.3.5 + debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -12330,6 +12453,8 @@ snapshots: '@cloudflare/workers-types@4.20240524.0': {} + '@cloudflare/workers-types@4.20241004.0': {} + '@colors/colors@1.5.0': optional: true @@ -12862,7 +12987,7 @@ snapshots: '@eslint/eslintrc@3.1.0': dependencies: ajv: 6.12.6 - debug: 4.3.5 + debug: 4.3.7 espree: 10.0.1 globals: 14.0.0 ignore: 5.3.1 @@ -12919,7 +13044,7 @@ snapshots: chalk: 4.1.2 ci-info: 3.9.0 connect: 3.7.0 - debug: 4.3.5 + debug: 4.3.7 env-editor: 0.4.2 fast-glob: 3.3.2 find-yarn-workspace-root: 2.0.0 @@ -12987,7 +13112,7 @@ snapshots: '@expo/plist': 0.1.3 '@expo/sdk-runtime-versions': 1.0.0 chalk: 4.1.2 - debug: 4.3.5 + debug: 4.3.7 find-up: 5.0.0 getenv: 1.0.0 glob: 7.1.6 @@ -13039,7 +13164,7 @@ snapshots: '@expo/env@0.3.0': dependencies: chalk: 4.1.2 - debug: 4.3.5 + debug: 4.3.7 dotenv: 16.4.5 dotenv-expand: 11.0.6 getenv: 1.0.0 @@ -13078,7 +13203,7 @@ snapshots: '@expo/json-file': 8.3.3 '@expo/spawn-async': 1.7.2 chalk: 4.1.2 - debug: 4.3.5 + debug: 4.3.7 find-yarn-workspace-root: 2.0.0 fs-extra: 9.1.0 getenv: 1.0.0 @@ -13124,7 +13249,7 @@ snapshots: '@expo/image-utils': 0.5.1(encoding@0.1.13) '@expo/json-file': 8.3.3 '@react-native/normalize-colors': 0.74.83 - debug: 4.3.5 + debug: 4.3.7 expo-modules-autolinking: 1.11.1 fs-extra: 9.1.0 resolve-from: 5.0.0 @@ -13313,6 +13438,8 @@ snapshots: '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/trace-mapping@0.3.18': dependencies: '@jridgewell/resolve-uri': 3.1.0 @@ -13405,38 +13532,38 @@ snapshots: '@libsql/win32-x64-msvc@0.4.1': optional: true - '@miniflare/core@2.14.2': + '@miniflare/core@2.14.4': dependencies: '@iarna/toml': 2.2.5 - '@miniflare/queues': 2.14.2 - '@miniflare/shared': 2.14.2 - '@miniflare/watcher': 2.14.2 + '@miniflare/queues': 2.14.4 + '@miniflare/shared': 2.14.4 + '@miniflare/watcher': 2.14.4 busboy: 1.6.0 dotenv: 10.0.0 kleur: 4.1.5 set-cookie-parser: 2.6.0 - undici: 5.28.2 + undici: 5.28.4 urlpattern-polyfill: 4.0.3 - '@miniflare/d1@2.14.2': + '@miniflare/d1@2.14.4': dependencies: - '@miniflare/core': 2.14.2 - '@miniflare/shared': 2.14.2 + '@miniflare/core': 2.14.4 + '@miniflare/shared': 2.14.4 - '@miniflare/queues@2.14.2': + '@miniflare/queues@2.14.4': dependencies: - '@miniflare/shared': 2.14.2 + '@miniflare/shared': 2.14.4 - '@miniflare/shared@2.14.2': + '@miniflare/shared@2.14.4': dependencies: '@types/better-sqlite3': 7.6.10 kleur: 4.1.5 npx-import: 1.1.4 picomatch: 2.3.1 - '@miniflare/watcher@2.14.2': + '@miniflare/watcher@2.14.4': dependencies: - '@miniflare/shared': 2.14.2 + '@miniflare/shared': 2.14.4 '@neon-rs/load@0.0.4': {} @@ -13852,20 +13979,20 @@ snapshots: optionalDependencies: rollup: 3.27.2 - '@rollup/plugin-typescript@11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@rollup/plugin-typescript@11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.6.3)': dependencies: '@rollup/pluginutils': 5.0.2(rollup@3.20.7) resolve: 1.22.1 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 optionalDependencies: rollup: 3.20.7 tslib: 2.6.2 - '@rollup/plugin-typescript@11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@rollup/plugin-typescript@11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.6.3)': dependencies: '@rollup/pluginutils': 5.0.2(rollup@3.27.2) resolve: 1.22.2 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 optionalDependencies: rollup: 3.27.2 tslib: 2.6.2 @@ -14753,13 +14880,13 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3)': dependencies: '@eslint-community/regexpp': 4.9.0 - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/scope-manager': 6.7.3 - '@typescript-eslint/type-utils': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) - '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/type-utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/visitor-keys': 6.7.3 debug: 4.3.4 eslint: 8.50.0 @@ -14767,33 +14894,33 @@ snapshots: ignore: 5.2.4 natural-compare: 1.4.0 semver: 7.6.2 - ts-api-utils: 1.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/scope-manager': 7.16.1 - '@typescript-eslint/type-utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) - '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/type-utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/visitor-keys': 7.16.1 eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@typescript-eslint/experimental-utils@5.62.0(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/experimental-utils@5.62.0(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/utils': 5.62.0(eslint@8.50.0)(typescript@5.6.3) eslint: 8.50.0 transitivePeerDependencies: - supports-color @@ -14812,29 +14939,29 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3)': dependencies: '@typescript-eslint/scope-manager': 6.7.3 '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) '@typescript-eslint/visitor-keys': 6.7.3 debug: 4.3.4 eslint: 8.50.0 optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@typescript-eslint/scope-manager': 7.16.1 '@typescript-eslint/types': 7.16.1 - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) '@typescript-eslint/visitor-keys': 7.16.1 debug: 4.3.4 eslint: 8.57.0 optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -14871,27 +14998,27 @@ snapshots: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/visitor-keys': 7.16.1 - '@typescript-eslint/type-utils@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/type-utils@6.7.3(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) - '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) debug: 4.3.4 eslint: 8.50.0 - ts-api-utils: 1.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/type-utils@7.16.1(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) - '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) + '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) debug: 4.3.4 eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -14903,7 +15030,7 @@ snapshots: '@typescript-eslint/types@7.16.1': {} - '@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/typescript-estree@5.62.0(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 @@ -14911,9 +15038,9 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.2 - tsutils: 3.21.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + tsutils: 3.21.0(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -14931,7 +15058,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@6.7.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/typescript-estree@6.7.3(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 6.7.3 '@typescript-eslint/visitor-keys': 6.7.3 @@ -14939,13 +15066,13 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.2 - ts-api-utils: 1.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.16.1(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/typescript-estree@7.16.1(typescript@5.4.5)': dependencies: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/visitor-keys': 7.16.1 @@ -14954,20 +15081,20 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.4 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/utils@5.62.0(eslint@8.50.0)(typescript@5.6.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) '@types/json-schema': 7.0.13 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.3) eslint: 8.50.0 eslint-scope: 5.1.1 semver: 7.6.2 @@ -14989,26 +15116,26 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/utils@6.7.3(eslint@8.50.0)(typescript@5.6.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) '@types/json-schema': 7.0.13 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 6.7.3 '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) eslint: 8.50.0 semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/utils@7.16.1(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@typescript-eslint/scope-manager': 7.16.1 '@typescript-eslint/types': 7.16.1 - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) eslint: 8.57.0 transitivePeerDependencies: - supports-color @@ -15072,22 +15199,56 @@ snapshots: '@vitest/utils': 1.6.0 chai: 4.4.1 + '@vitest/expect@2.1.2': + dependencies: + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0))': + dependencies: + '@vitest/spy': 2.1.2 + estree-walker: 3.0.3 + magic-string: 0.30.11 + optionalDependencies: + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + + '@vitest/pretty-format@2.1.2': + dependencies: + tinyrainbow: 1.2.0 + '@vitest/runner@1.6.0': dependencies: '@vitest/utils': 1.6.0 p-limit: 5.0.0 pathe: 1.1.2 + '@vitest/runner@2.1.2': + dependencies: + '@vitest/utils': 2.1.2 + pathe: 1.1.2 + '@vitest/snapshot@1.6.0': dependencies: magic-string: 0.30.10 pathe: 1.1.2 pretty-format: 29.7.0 + '@vitest/snapshot@2.1.2': + dependencies: + '@vitest/pretty-format': 2.1.2 + magic-string: 0.30.11 + pathe: 1.1.2 + '@vitest/spy@1.6.0': dependencies: tinyspy: 2.2.1 + '@vitest/spy@2.1.2': + dependencies: + tinyspy: 3.0.2 + '@vitest/ui@1.6.0(vitest@1.6.0)': dependencies: '@vitest/utils': 1.6.0 @@ -15098,6 +15259,18 @@ snapshots: picocolors: 1.0.1 sirv: 2.0.4 vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + optional: true + + '@vitest/ui@1.6.0(vitest@2.1.2)': + dependencies: + '@vitest/utils': 1.6.0 + fast-glob: 3.3.2 + fflate: 0.8.2 + flatted: 3.3.1 + pathe: 1.1.2 + picocolors: 1.0.1 + sirv: 2.0.4 + vitest: 2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) '@vitest/utils@1.6.0': dependencies: @@ -15106,9 +15279,15 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 - '@xata.io/client@0.29.4(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@vitest/utils@2.1.2': + dependencies: + '@vitest/pretty-format': 2.1.2 + loupe: 3.1.2 + tinyrainbow: 1.2.0 + + '@xata.io/client@0.29.4(typescript@5.6.3)': dependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 '@xmldom/xmldom@0.7.13': {} @@ -15322,6 +15501,8 @@ snapshots: assertion-error@1.1.0: {} + assertion-error@2.0.1: {} + ast-types@0.15.2: dependencies: tslib: 2.6.2 @@ -15715,6 +15896,14 @@ snapshots: pathval: 1.1.1 type-detect: 4.0.8 + chai@5.1.1: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.2 + pathval: 2.0.0 + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -15736,6 +15925,8 @@ snapshots: dependencies: get-func-name: 2.0.2 + check-error@2.1.1: {} + chokidar@3.5.3: dependencies: anymatch: 3.1.3 @@ -16116,6 +16307,10 @@ snapshots: dependencies: ms: 2.1.2 + debug@4.3.7: + dependencies: + ms: 2.1.3 + decamelize@1.2.0: {} decompress-response@6.0.0: @@ -16126,6 +16321,8 @@ snapshots: dependencies: type-detect: 4.0.8 + deep-eql@5.0.2: {} + deep-extend@0.6.0: {} deep-is@0.1.4: {} @@ -16281,10 +16478,10 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 - '@cloudflare/workers-types': 4.20240524.0 + '@cloudflare/workers-types': 4.20241004.0 '@libsql/client': 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': 0.9.3 '@opentelemetry/api': 1.8.0 @@ -16793,17 +16990,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0): + eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0): dependencies: array-includes: 3.1.6 array.prototype.findlastindex: 1.2.2 @@ -16813,7 +17010,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) has: 1.0.3 is-core-module: 2.13.0 is-glob: 4.0.3 @@ -16824,7 +17021,7 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.14.2 optionalDependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -16860,12 +17057,12 @@ snapshots: semver: 7.6.2 strip-indent: 3.0.0 - eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0): + eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0): dependencies: eslint: 8.50.0 eslint-rule-composer: 0.3.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3) eslint-rule-composer@0.3.0: {} @@ -18502,6 +18699,8 @@ snapshots: dependencies: get-func-name: 2.0.2 + loupe@3.1.2: {} + lru-cache@10.2.2: {} lru-cache@5.1.1: @@ -18530,6 +18729,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 + magic-string@0.30.11: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + make-dir@2.1.0: dependencies: pify: 4.0.1 @@ -19399,6 +19602,8 @@ snapshots: pathval@1.1.1: {} + pathval@2.0.0: {} + pause-stream@0.0.11: dependencies: through: 2.3.8 @@ -19495,13 +19700,13 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)): dependencies: lilconfig: 2.1.0 yaml: 2.3.1 optionalDependencies: postcss: 8.4.39 - ts-node: 10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-node: 10.9.2(@types/node@20.12.12)(typescript@5.6.3) postcss-load-config@6.0.1(postcss@8.4.39)(tsx@3.14.0)(yaml@2.4.2): dependencies: @@ -19897,12 +20102,12 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve-tspaths@0.8.16(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + resolve-tspaths@0.8.16(typescript@5.6.3): dependencies: ansi-colors: 4.1.3 commander: 11.0.0 fast-glob: 3.3.1 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 resolve.exports@2.0.2: {} @@ -20671,10 +20876,20 @@ snapshots: tinybench@2.8.0: {} + tinybench@2.9.0: {} + + tinyexec@0.3.0: {} + tinypool@0.8.4: {} + tinypool@1.0.1: {} + + tinyrainbow@1.2.0: {} + tinyspy@2.2.1: {} + tinyspy@3.0.2: {} + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -20711,19 +20926,19 @@ snapshots: dependencies: typescript: 5.2.2 - ts-api-utils@1.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + ts-api-utils@1.0.3(typescript@5.6.3): dependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 - ts-api-utils@1.3.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + ts-api-utils@1.3.0(typescript@5.4.5): dependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 ts-expose-internals-conditionally@1.0.0-empty.0: {} ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -20737,13 +20952,17 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - tsconfck@3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + tsconfck@3.0.3(typescript@5.4.5): + optionalDependencies: + typescript: 5.4.5 + + tsconfck@3.0.3(typescript@5.6.3): optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 tsconfig-paths@3.14.2: dependencies: @@ -20756,7 +20975,7 @@ snapshots: tslib@2.6.2: {} - tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3): dependencies: bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 @@ -20766,7 +20985,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)) resolve-from: 5.0.0 rollup: 3.27.2 source-map: 0.8.0-beta.0 @@ -20774,12 +20993,12 @@ snapshots: tree-kill: 1.2.2 optionalDependencies: postcss: 8.4.39 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - ts-node - tsup@8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(yaml@2.4.2): + tsup@8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.4.5)(yaml@2.4.2): dependencies: bundle-require: 5.0.0(esbuild@0.23.0) cac: 6.7.14 @@ -20798,17 +21017,17 @@ snapshots: tree-kill: 1.2.2 optionalDependencies: postcss: 8.4.39 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 transitivePeerDependencies: - jiti - supports-color - tsx - yaml - tsutils@3.21.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + tsutils@3.21.0(typescript@5.6.3): dependencies: tslib: 1.14.1 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 tsx@3.14.0: dependencies: @@ -20970,7 +21189,9 @@ snapshots: typescript@5.3.3: {} - typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme): {} + typescript@5.4.5: {} + + typescript@5.6.3: {} ua-parser-js@1.0.38: {} @@ -20985,10 +21206,6 @@ snapshots: undici-types@5.26.5: {} - undici@5.28.2: - dependencies: - '@fastify/busboy': 2.1.1 - undici@5.28.4: dependencies: '@fastify/busboy': 2.1.1 @@ -21179,33 +21396,49 @@ snapshots: - supports-color - terser - vite-tsconfig-paths@4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)): + vite-node@2.1.2(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + cac: 6.7.14 + debug: 4.3.7 + pathe: 1.1.2 + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + tsconfck: 3.0.3(typescript@5.4.5) optionalDependencies: - vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)): + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + tsconfck: 3.0.3(typescript@5.6.3) optionalDependencies: - vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)): + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + tsconfck: 3.0.3(typescript@5.6.3) optionalDependencies: vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: @@ -21436,6 +21669,40 @@ snapshots: - supports-color - terser + vitest@2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + '@vitest/expect': 2.1.2 + '@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) + '@vitest/pretty-format': 2.1.2 + '@vitest/runner': 2.1.2 + '@vitest/snapshot': 2.1.2 + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 + debug: 4.3.7 + magic-string: 0.30.11 + pathe: 1.1.2 + std-env: 3.7.0 + tinybench: 2.9.0 + tinyexec: 0.3.0 + tinypool: 1.0.1 + tinyrainbow: 1.2.0 + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + vite-node: 2.1.2(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.12.12 + '@vitest/ui': 1.6.0(vitest@2.1.2) + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - stylus + - sugarss + - supports-color + - terser + vlq@1.0.1: {} walker@1.0.8: @@ -21520,6 +21787,11 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + wide-align@1.1.5: dependencies: string-width: 4.2.3 From b789d7e6204e490bcddcb70be51f58ecb0cd0cb9 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Thu, 10 Oct 2024 11:33:53 +0300 Subject: [PATCH 229/492] removed commented code --- drizzle-orm/src/sqlite-core/view.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drizzle-orm/src/sqlite-core/view.ts b/drizzle-orm/src/sqlite-core/view.ts index 7fc6a7b29..0aec6a2e1 100644 --- a/drizzle-orm/src/sqlite-core/view.ts +++ b/drizzle-orm/src/sqlite-core/view.ts @@ -10,7 +10,6 @@ import { QueryBuilder } from './query-builders/query-builder.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import { sqliteTable } from './table.ts'; import { SQLiteViewBase } from './view-base.ts'; -// import { SQLiteViewConfig } from './view-common.ts'; export interface ViewBuilderConfig { algorithm?: 'undefined' | 'merge' | 'temptable'; @@ -89,7 +88,6 @@ export class ManualViewBuilder< existing(): SQLiteViewWithSelection> { return new Proxy( new SQLiteView({ - // sqliteConfig: undefined, config: { name: this.name, schema: undefined, @@ -109,7 +107,6 @@ export class ManualViewBuilder< as(query: SQL): SQLiteViewWithSelection> { return new Proxy( new SQLiteView({ - // sqliteConfig: this.config, config: { name: this.name, schema: undefined, @@ -134,11 +131,7 @@ export class SQLiteView< > extends SQLiteViewBase { static readonly [entityKind]: string = 'SQLiteView'; - // /** @internal */ - // [SQLiteViewConfig]: ViewBuilderConfig | undefined; - constructor({ config }: { - // sqliteConfig: ViewBuilderConfig | undefined; config: { name: TName; schema: string | undefined; @@ -147,7 +140,6 @@ export class SQLiteView< }; }) { super(config); - // this[SQLiteViewConfig] = sqliteConfig; } } From 8cac5d252a9fa2471a0b595bf784e645f89edfee Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 10 Oct 2024 17:07:27 +0300 Subject: [PATCH 230/492] Remove global set for node-postgres, neon and vercel; move to on per-query --- drizzle-orm/src/neon-serverless/driver.ts | 9 ----- drizzle-orm/src/neon-serverless/session.ts | 39 +++++++++++++++++++++ drizzle-orm/src/node-postgres/driver.ts | 11 ------ drizzle-orm/src/node-postgres/session.ts | 40 +++++++++++++++++++++- drizzle-orm/src/vercel-postgres/driver.ts | 9 ----- drizzle-orm/src/vercel-postgres/session.ts | 39 +++++++++++++++++++++ 6 files changed, 117 insertions(+), 30 deletions(-) diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index d94972e1c..985046c07 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -1,4 +1,3 @@ -import { types } from '@neondatabase/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -26,7 +25,6 @@ export class NeonDriver { private dialect: PgDialect, private options: NeonDriverOptions = {}, ) { - this.initMappers(); } createSession( @@ -34,13 +32,6 @@ export class NeonDriver { ): NeonSession, TablesRelationalConfig> { return new NeonSession(this.client, this.dialect, schema, { logger: this.options.logger }); } - - initMappers() { - types.setTypeParser(types.builtins.TIMESTAMPTZ, (val) => val); - types.setTypeParser(types.builtins.TIMESTAMP, (val) => val); - types.setTypeParser(types.builtins.DATE, (val) => val); - types.setTypeParser(types.builtins.INTERVAL, (val) => val); - } } export class NeonDatabase< diff --git a/drizzle-orm/src/neon-serverless/session.ts b/drizzle-orm/src/neon-serverless/session.ts index 293050715..2d55c8fe1 100644 --- a/drizzle-orm/src/neon-serverless/session.ts +++ b/drizzle-orm/src/neon-serverless/session.ts @@ -6,6 +6,7 @@ import { type QueryConfig, type QueryResult, type QueryResultRow, + types, } from '@neondatabase/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; @@ -41,11 +42,49 @@ export class NeonPreparedQuery extends PgPrepared this.rawQueryConfig = { name, text: queryString, + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val: any) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val: any) => val; + } + if (typeId === types.builtins.DATE) { + return (val: any) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val: any) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; this.queryConfig = { name, text: queryString, rowMode: 'array', + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val: any) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val: any) => val; + } + if (typeId === types.builtins.DATE) { + return (val: any) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val: any) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; } diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index 9c883816b..5679258de 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -1,4 +1,3 @@ -import pg from 'pg'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -14,8 +13,6 @@ import type { DrizzleConfig } from '~/utils.ts'; import type { NodePgClient, NodePgQueryResultHKT } from './session.ts'; import { NodePgSession } from './session.ts'; -const { types } = pg; - export interface PgDriverOptions { logger?: Logger; } @@ -28,7 +25,6 @@ export class NodePgDriver { private dialect: PgDialect, private options: PgDriverOptions = {}, ) { - this.initMappers(); } createSession( @@ -36,13 +32,6 @@ export class NodePgDriver { ): NodePgSession, TablesRelationalConfig> { return new NodePgSession(this.client, this.dialect, schema, { logger: this.options.logger }); } - - initMappers() { - types.setTypeParser(types.builtins.TIMESTAMPTZ, (val) => val); - types.setTypeParser(types.builtins.TIMESTAMP, (val) => val); - types.setTypeParser(types.builtins.DATE, (val) => val); - types.setTypeParser(types.builtins.INTERVAL, (val) => val); - } } export class NodePgDatabase< diff --git a/drizzle-orm/src/node-postgres/session.ts b/drizzle-orm/src/node-postgres/session.ts index a886f3782..6c63ffa8d 100644 --- a/drizzle-orm/src/node-postgres/session.ts +++ b/drizzle-orm/src/node-postgres/session.ts @@ -1,5 +1,5 @@ import type { Client, PoolClient, QueryArrayConfig, QueryConfig, QueryResult, QueryResultRow } from 'pg'; -import pg from 'pg'; +import pg, { types } from 'pg'; import { entityKind } from '~/entity.ts'; import { type Logger, NoopLogger } from '~/logger.ts'; import type { PgDialect } from '~/pg-core/dialect.ts'; @@ -36,11 +36,49 @@ export class NodePgPreparedQuery extends PgPrepar this.rawQueryConfig = { name, text: queryString, + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val) => val; + } + if (typeId === types.builtins.DATE) { + return (val) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; this.queryConfig = { name, text: queryString, rowMode: 'array', + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val) => val; + } + if (typeId === types.builtins.DATE) { + return (val) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; } diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 479f239bf..5932a9fe5 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -1,4 +1,3 @@ -import { types } from '@vercel/postgres'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -25,7 +24,6 @@ export class VercelPgDriver { private dialect: PgDialect, private options: VercelPgDriverOptions = {}, ) { - this.initMappers(); } createSession( @@ -33,13 +31,6 @@ export class VercelPgDriver { ): VercelPgSession, TablesRelationalConfig> { return new VercelPgSession(this.client, this.dialect, schema, { logger: this.options.logger }); } - - initMappers() { - types.setTypeParser(types.builtins.TIMESTAMPTZ, (val) => val); - types.setTypeParser(types.builtins.TIMESTAMP, (val) => val); - types.setTypeParser(types.builtins.DATE, (val) => val); - types.setTypeParser(types.builtins.INTERVAL, (val) => val); - } } export class VercelPgDatabase< diff --git a/drizzle-orm/src/vercel-postgres/session.ts b/drizzle-orm/src/vercel-postgres/session.ts index 5d16539f0..a901f24c8 100644 --- a/drizzle-orm/src/vercel-postgres/session.ts +++ b/drizzle-orm/src/vercel-postgres/session.ts @@ -3,6 +3,7 @@ import { type QueryConfig, type QueryResult, type QueryResultRow, + types, type VercelClient, VercelPool, type VercelPoolClient, @@ -39,11 +40,49 @@ export class VercelPgPreparedQuery extends PgPrep this.rawQuery = { name, text: queryString, + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val: any) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val: any) => val; + } + if (typeId === types.builtins.DATE) { + return (val: any) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val: any) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; this.queryConfig = { name, text: queryString, rowMode: 'array', + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val: any) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val: any) => val; + } + if (typeId === types.builtins.DATE) { + return (val: any) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val: any) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; } From b006ec30a61557a132885d54e57e1a8f532ceaeb Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 10 Oct 2024 17:41:40 +0300 Subject: [PATCH 231/492] Fix import --- drizzle-orm/src/node-postgres/session.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/node-postgres/session.ts b/drizzle-orm/src/node-postgres/session.ts index 6c63ffa8d..a925d7018 100644 --- a/drizzle-orm/src/node-postgres/session.ts +++ b/drizzle-orm/src/node-postgres/session.ts @@ -1,5 +1,5 @@ import type { Client, PoolClient, QueryArrayConfig, QueryConfig, QueryResult, QueryResultRow } from 'pg'; -import pg, { types } from 'pg'; +import pg from 'pg'; import { entityKind } from '~/entity.ts'; import { type Logger, NoopLogger } from '~/logger.ts'; import type { PgDialect } from '~/pg-core/dialect.ts'; @@ -12,7 +12,7 @@ import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; -const { Pool } = pg; +const { Pool, types } = pg; export type NodePgClient = pg.Pool | PoolClient | Client; From 172fec900e7b2b51f8027c4fe7f8b0335021ce13 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Thu, 10 Oct 2024 21:03:28 +0300 Subject: [PATCH 232/492] add drizzle-seed to monorepo --- drizzle-seed/README.md | 1141 + drizzle-seed/package.json | 72 + drizzle-seed/rollup.config.ts | 32 + drizzle-seed/scripts/build.ts | 15 + drizzle-seed/src/datasets/adjectives.ts | 4843 ++ drizzle-seed/src/datasets/cityNames.ts | 42986 +++++++++++++ .../src/datasets/companyNameSuffixes.ts | 27 + drizzle-seed/src/datasets/countries.ts | 169 + drizzle-seed/src/datasets/emailDomains.ts | 24 + drizzle-seed/src/datasets/firstNames.ts | 30276 ++++++++++ drizzle-seed/src/datasets/jobsTitles.ts | 149 + drizzle-seed/src/datasets/lastNames.ts | 50000 ++++++++++++++++ .../src/datasets/loremIpsumSentences.ts | 1636 + drizzle-seed/src/datasets/phonesInfo.ts | 871 + drizzle-seed/src/datasets/states.ts | 52 + drizzle-seed/src/datasets/streetSuffix.ts | 197 + drizzle-seed/src/index.ts | 957 + .../src/services/GeneratorsWrappers.ts | 3588 ++ drizzle-seed/src/services/SeedService.ts | 1223 + drizzle-seed/src/services/utils.ts | 94 + .../tests/benchmarks/generatorsBenchmark.ts | 142 + .../mysql/allDataTypesTest/drizzle.config.ts | 7 + .../mysql/allDataTypesTest/mysqlSchema.ts | 56 + .../mysql_all_data_types.test.ts | 121 + .../src/tests/mysql/drizzle.config.ts | 7 + .../mysql/generatorsTest/drizzle.config.ts | 7 + .../mysql/generatorsTest/generators.test.ts | 128 + .../tests/mysql/generatorsTest/mysqlSchema.ts | 9 + drizzle-seed/src/tests/mysql/mysql.test.ts | 381 + drizzle-seed/src/tests/mysql/mysqlSchema.ts | 128 + .../src/tests/northwind/mysqlSchema.ts | 128 + drizzle-seed/src/tests/northwind/mysqlTest.ts | 176 + drizzle-seed/src/tests/northwind/pgSchema.ts | 130 + drizzle-seed/src/tests/northwind/pgTest.ts | 175 + .../src/tests/northwind/sqliteSchema.ts | 131 + .../src/tests/northwind/sqliteTest.ts | 164 + .../pg/allDataTypesTest/drizzle.config.ts | 7 + .../src/tests/pg/allDataTypesTest/pgSchema.ts | 62 + .../pg_all_data_types.test.ts | 78 + drizzle-seed/src/tests/pg/drizzle.config.ts | 7 + .../tests/pg/generatorsTest/drizzle.config.ts | 7 + .../pg/generatorsTest/generators.test.ts | 1370 + .../src/tests/pg/generatorsTest/pgSchema.ts | 205 + drizzle-seed/src/tests/pg/pg.test.ts | 345 + drizzle-seed/src/tests/pg/pgSchema.ts | 130 + .../sqlite/allDataTypesTest/sqliteSchema.ts | 15 + .../sqlite_all_data_types.test.ts | 53 + drizzle-seed/src/tests/sqlite/sqlite.test.ts | 290 + drizzle-seed/src/tests/sqlite/sqliteSchema.ts | 131 + drizzle-seed/src/tests/vitest.config.ts | 25 + drizzle-seed/src/types/drizzleStudio.ts | 65 + drizzle-seed/src/types/seedService.ts | 44 + drizzle-seed/src/types/tables.ts | 35 + drizzle-seed/tsconfig.build.json | 7 + drizzle-seed/tsconfig.json | 48 + integration-tests/package.json | 1 + integration-tests/tests/seeder/firstNames.ts | 30276 ++++++++++ integration-tests/tests/seeder/lastNames.ts | 50000 ++++++++++++++++ integration-tests/tests/seeder/mysql.test.ts | 490 + integration-tests/tests/seeder/mysqlSchema.ts | 167 + integration-tests/tests/seeder/pg.test.ts | 1759 + integration-tests/tests/seeder/pgSchema.ts | 351 + integration-tests/tests/seeder/sqlite.test.ts | 322 + .../tests/seeder/sqliteSchema.ts | 122 + integration-tests/vitest.config.ts | 1 + pnpm-lock.yaml | 1788 +- pnpm-workspace.yaml | 1 + 67 files changed, 227895 insertions(+), 549 deletions(-) create mode 100644 drizzle-seed/README.md create mode 100644 drizzle-seed/package.json create mode 100644 drizzle-seed/rollup.config.ts create mode 100644 drizzle-seed/scripts/build.ts create mode 100644 drizzle-seed/src/datasets/adjectives.ts create mode 100644 drizzle-seed/src/datasets/cityNames.ts create mode 100644 drizzle-seed/src/datasets/companyNameSuffixes.ts create mode 100644 drizzle-seed/src/datasets/countries.ts create mode 100644 drizzle-seed/src/datasets/emailDomains.ts create mode 100644 drizzle-seed/src/datasets/firstNames.ts create mode 100644 drizzle-seed/src/datasets/jobsTitles.ts create mode 100644 drizzle-seed/src/datasets/lastNames.ts create mode 100644 drizzle-seed/src/datasets/loremIpsumSentences.ts create mode 100644 drizzle-seed/src/datasets/phonesInfo.ts create mode 100644 drizzle-seed/src/datasets/states.ts create mode 100644 drizzle-seed/src/datasets/streetSuffix.ts create mode 100644 drizzle-seed/src/index.ts create mode 100644 drizzle-seed/src/services/GeneratorsWrappers.ts create mode 100644 drizzle-seed/src/services/SeedService.ts create mode 100644 drizzle-seed/src/services/utils.ts create mode 100644 drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts create mode 100644 drizzle-seed/src/tests/mysql/allDataTypesTest/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/mysql/allDataTypesTest/mysqlSchema.ts create mode 100644 drizzle-seed/src/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts create mode 100644 drizzle-seed/src/tests/mysql/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/mysql/generatorsTest/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/mysql/generatorsTest/generators.test.ts create mode 100644 drizzle-seed/src/tests/mysql/generatorsTest/mysqlSchema.ts create mode 100644 drizzle-seed/src/tests/mysql/mysql.test.ts create mode 100644 drizzle-seed/src/tests/mysql/mysqlSchema.ts create mode 100644 drizzle-seed/src/tests/northwind/mysqlSchema.ts create mode 100644 drizzle-seed/src/tests/northwind/mysqlTest.ts create mode 100644 drizzle-seed/src/tests/northwind/pgSchema.ts create mode 100644 drizzle-seed/src/tests/northwind/pgTest.ts create mode 100644 drizzle-seed/src/tests/northwind/sqliteSchema.ts create mode 100644 drizzle-seed/src/tests/northwind/sqliteTest.ts create mode 100644 drizzle-seed/src/tests/pg/allDataTypesTest/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts create mode 100644 drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts create mode 100644 drizzle-seed/src/tests/pg/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/pg/generatorsTest/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts create mode 100644 drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts create mode 100644 drizzle-seed/src/tests/pg/pg.test.ts create mode 100644 drizzle-seed/src/tests/pg/pgSchema.ts create mode 100644 drizzle-seed/src/tests/sqlite/allDataTypesTest/sqliteSchema.ts create mode 100644 drizzle-seed/src/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts create mode 100644 drizzle-seed/src/tests/sqlite/sqlite.test.ts create mode 100644 drizzle-seed/src/tests/sqlite/sqliteSchema.ts create mode 100644 drizzle-seed/src/tests/vitest.config.ts create mode 100644 drizzle-seed/src/types/drizzleStudio.ts create mode 100644 drizzle-seed/src/types/seedService.ts create mode 100644 drizzle-seed/src/types/tables.ts create mode 100644 drizzle-seed/tsconfig.build.json create mode 100644 drizzle-seed/tsconfig.json create mode 100644 integration-tests/tests/seeder/firstNames.ts create mode 100644 integration-tests/tests/seeder/lastNames.ts create mode 100644 integration-tests/tests/seeder/mysql.test.ts create mode 100644 integration-tests/tests/seeder/mysqlSchema.ts create mode 100644 integration-tests/tests/seeder/pg.test.ts create mode 100644 integration-tests/tests/seeder/pgSchema.ts create mode 100644 integration-tests/tests/seeder/sqlite.test.ts create mode 100644 integration-tests/tests/seeder/sqliteSchema.ts diff --git a/drizzle-seed/README.md b/drizzle-seed/README.md new file mode 100644 index 000000000..8b659e882 --- /dev/null +++ b/drizzle-seed/README.md @@ -0,0 +1,1141 @@ +## Overview + +drizzle-seed is a typescript library that will help you generate deterministic fake realistic data and fill your database with it. + +### Determinism + +## + +#### pseudorandom number generator(pRNG) + +It's a random number generator whose randomness you can control. +It will give you the same sequence of numbers if you initialize it with the same `seed` number. + +## + +#### How it works? + +Each column will be assigned with its generator and all random events in it will be handled by pRNG. + +Each pRNG will be initialized with `seed` which will be generated from table name and column name. + +Also, there will be cases when the randomness of generators will be affected by the number of rows you want to generate. So far this only applies to unique int and number generators. + +So as long as your schema and your seeding script remain the same, Seeder will generate the same data. + +## Getting started + +`npm install drizzle-seed` + +You have to install drizzle-orm in order to use seeder. + +`npm install drizzle-orm` + +## Usage + +### Simple usage + +#### `src/main.ts` + +```ts +(async () => { + await seed(db, schema); + // await seed(db, schema, { count: 100000 }); + // await seed(db, schema, { count: 100000, seed: 1 }); +})().then(); +``` + +From the commented part of the code above, you can see that it's possible to specify the `count` property which stands for the number of rows you want to generate + +and `seed` property which represents a custom `seed` number that will be added to the one automatically generated from the table's name and column's name and then the result of addition will be fed to pRNG. +Therefore you can manage different states of your data using the `seed` property. + +#### You also can delete all data from your tables to seed your database again using the `reset` function. + +#### `src/main.ts` + +```ts +(async () => { + await reset(db, schema); + // await seed(db, schema); +})().then(); +``` + +`If db is a PgDatabase object`, we will execute sql query and delete data from your tables the following way: + +```sql +truncate tableName1, tableName2, ... cascade; +``` + +`If db is a MySqlDatabase object`, we will execute sql queries and delete data from your tables the following way: + +```sql +SET FOREIGN_KEY_CHECKS = 0; +truncate tableName1; +truncate tableName2; +. +. +. + +SET FOREIGN_KEY_CHECKS = 1; +``` + +`If db is a BaseSQLiteDatabase object`, we will execute sql queries and delete data from your tables the following way: + +```sql +PRAGMA foreign_keys = OFF; +delete from tableName1; +delete from tableName2; +. +. +. + +PRAGMA foreign_keys = ON; +``` + +### But you still need to define database schema (`schema`) and create database connection (`db`) before using `seed` or `reset` function. + +#### You can find some examples for Postgres, Mysql and Sqlite below. + +### **Postgres** + +#### `src/schema.ts` + +```ts +import { + serial, + integer, + varchar, + pgSchema, + getTableConfig as getPgTableConfig, +} from "drizzle-orm/pg-core"; + +export const schema = pgSchema("seeder_lib_pg"); + +export const users = schema.table("users", { + id: serial("id").primaryKey(), + name: varchar("name", { length: 256 }), + email: varchar("email", { length: 256 }), + phone: varchar("phone", { length: 256 }), + password: varchar("password", { length: 256 }), +}); + +export const posts = schema.table("posts", { + id: serial("id").primaryKey(), + title: varchar("title", { length: 256 }), + content: varchar("content", { length: 256 }), + userId: integer("user_id").references(() => users.id), +}); +``` + +#### `src/main.ts` + +```ts +import Pool from "pg"; +import { drizzle } from "drizzle-orm/node-postgres"; +import * as schema from "./schema"; + +const { PG_HOST, PG_PORT, PG_DATABASE, PG_USER, PG_PASSWORD } = process.env; + +const pool = new Pool({ + host: PG_HOST, + port: Number(PG_PORT) || 5432, + database: PG_DATABASE, + user: PG_USER, + password: PG_PASSWORD, + // ssl: true +}); + +const db = drizzle(pool); +``` + +### **Mysql** + +#### `src/schema.ts` + +```ts +import { serial, int, varchar, mysqlTable } from "drizzle-orm/mysql-core"; + +export const users = mysqlTable("users", { + id: int("id").autoincrement().primaryKey(), + name: varchar("name", { length: 256 }), + email: varchar("email", { length: 256 }), + phone: varchar("phone", { length: 256 }), + password: varchar("password", { length: 256 }), +}); + +export const posts = mysqlTable("posts", { + id: int("id").autoincrement().primaryKey(), + title: varchar("title", { length: 256 }), + content: varchar("content", { length: 256 }), + userId: int("user_id").references(() => users.id), +}); +``` + +#### `src/main.ts` + +```ts +import mysql from "mysql2/promise"; +import { drizzle } from "drizzle-orm/mysql2"; +import * as schema from "./schema"; + +const { Mysql_HOST, Mysql_PORT, Mysql_DATABASE, Mysql_USER, Mysql_PASSWORD } = + process.env; + +const pool = mysql.createPool({ + host: Mysql_HOST, + port: Number(Mysql_PORT) || 3306, + database: Mysql_DATABASE, + user: Mysql_USER, + password: Mysql_PASSWORD, + // ssl: { rejectUnauthorized: false } +}); + +const db = drizzle(pool); +``` + +### **Sqlite** + +#### `src/schema.ts` + +```ts +import { integer, text, sqliteTable } from "drizzle-orm/sqlite-core"; + +export const users = sqliteTable("users", { + id: integer("id").primaryKey(), + name: text("name", { length: 256 }), + email: text("email", { length: 256 }), + phone: text("phone", { length: 256 }), + password: text("password", { length: 256 }), +}); + +export const posts = sqliteTable("posts", { + id: integer("id").primaryKey(), + title: text("title", { length: 256 }), + content: text("content", { length: 256 }), + userId: integer("user_id").references(() => users.id), +}); +``` + +#### `src/main.ts` + +```ts +import betterSqlite3 from "better-sqlite3"; +import { drizzle } from "drizzle-orm/better-sqlite3"; +import * as schema from "./schema"; + +const { Sqlite_PATH } = process.env; +const sqliteDb = betterSqlite3(Sqlite_PATH); +const db = drizzle(sqliteDb); +``` + +### More complex usage examples + +#### All of the following examples will be in the context of database schema defined above. + +## + +#### You have 30 different data generators to choose from: + +- `default` +- `valuesFromArray` +- `intPrimaryKey` +- `number` +- `int` +- `boolean` +- `date` +- `time` +- `timestamp` +- `datetime` +- `year` +- `json` +- `interval` +- `string` +- `firstName` +- `lastName` +- `fullName` +- `email` +- `phoneNumber` +- `country` +- `city` +- `streetAddress` +- `jobTitle` +- `postcode` +- `state` +- `companyName` +- `loremIpsum` +- `weightedRandom` + +#### Some of them have an option to generate unique data samples which stands for property `isUnique`. + +#### Some of them can only generate unique data like `email` or `phoneNumber` generators. + +#### `src/main.ts` + +```ts +(async () => { + await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + name: funcs.firstName({ isUnique: true }), + email: funcs.email(), + phone: funcs.phoneNumber({ template: "+380 99 ###-##-##" }), + password: funcs.string({ isUnique: true }), + }, + count: 100000, + }, + posts: { + columns: { + title: funcs.valuesFromArray({ + values: ["Title1", "Title2", "Title3", "Title4", "Title5"], + }), + content: funcs.loremIpsum({ sentencesCount: 3 }), + }, + }, + })); +})().then(); +``` + +In the example above we used
+`firstName`, `string` generators that have `isUnique` property,
+`email` and `phoneNumber` which always generates unique data,
+`loremIpsum` and `default` generators that don't have `isUnique` property,
+and `valuesFromArray` which has `isUnique` property. + +Also we specified number of rows we want to generate in `users` section using property `count`. Therefore top-level `count` which equals 1000, will be rewrote with the one from `refine` and `count` for `users` table will equal 100000. + +And since we didn't specify `count` property in `posts` section it will use top-level `count` which equals 1000 and generate 1000 rows for `posts` table. + +#### Even so `valuesFromArray` generator has `isUnique` property, there is no point using it here, since we have only 5 unique elements in `values` array and want to generate 1000 titles for `posts` table. + +## + +#### You can specify how many posts each user will have, using `with` property if there is right relation in schema. + +#### Write `with: {posts: 2}` so each user will have 2 posts related to him. + +#### `src/main.ts` + +```ts +(async () => { + await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + count: 100000, + with: { + posts: 2, + }, + }, + posts: { + count: 100, + }, + })); +})().then(); +``` + +In this example overall number of posts or in other words posts `count` will be calculated like: + +{users `count`} $\times$ 2 = 100000 $\times$ 2 = 200000 + +And this posts `count` will overwrite both top-level `count` which equals to 100000 and `count` from `posts` section which equals to 100. + +## + +#### **Weighted choice** + +#### You can specify weighted number of posts for each user to have. + +```ts +with: { + posts: [ + { weight: 0.7, count: 3 }, + { weight: 0.3, count: [4, 5] } + ] +} +``` + +#### This means that each user will have 3 posts with probability 0.7 and from 4 to 5 posts with probability 0.3 . + +Number of posts for each user will be generated using pRNG and therefore remain deterministic. + +#### There also are some generators that feature select with given probability: + +- `valuesFromArray` has option to specify weighted arrays of values, +- `weightedMix` will use generators with given probabilities. + +#### `src/main.ts` + +```ts +(async () => { + await seed(db, schema).refine((funcs) => ({ + users: { + count: 100000, + with: { + posts: [ + { weight: 0.7, count: 3 }, + { weight: 0.3, count: [4, 5] }, + ], + }, + }, + posts: { + columns: { + title: funcs.valuesFromArray({ + values: [ + { weight: 0.35, values: ["Title1", "Title2"] }, + { weight: 0.5, values: ["Title3", "Title4"] }, + { weight: 0.15, values: ["Title5"] }, + ], + }), + content: funcs.weightedRandom([ + { + weight: 0.6, + value: funcs.loremIpsum({ sentencesCount: 3 }), + }, + { + weight: 0.4, + value: funcs.default({ defaultValue: "TODO" }), + }, + ]), + }, + }, + })); +})().then(); +``` + +#### Explanations of the code block above: + +- `valuesFromArray` generator
+ with probability 0.35 will pick array `["Title1", "Title2"]`,
+ with probability 0.5 will pick array `["Title3", "Title4"]`,
+ with probability 0.15 will pick array `["Title5"]`
+ and then pick value from chosen array using uniform distribution or in other words uniformly. +- `weightedMix` generator will call `loremIpsum` generator with probability 0.6 and `default` generator with probability 0.4 . + +## + +#### And you can combine all of this in one seeding script + +#### `src/main.ts` + +```ts +(async () => { + await seed(db, schema).refine((funcs) => ({ + users: { + columns: { + name: funcs.fullName(), + email: funcs.email(), + phone: funcs.phoneNumber({ template: "+380 99 ###-##-##" }), + password: funcs.string({ isUnique: true }), + }, + count: 100000, + with: { + posts: [ + { weight: 0.7, count: 3 }, + { weight: 0.3, count: [4, 5] }, + ], + }, + }, + posts: { + columns: { + title: funcs.valuesFromArray({ + values: [ + { weight: 0.35, values: ["Title1", "Title2"] }, + { weight: 0.5, values: ["Title3", "Title4"] }, + { weight: 0.15, values: ["Title5"] }, + ], + }), + content: funcs.weightedRandom([ + { + weight: 0.6, + value: funcs.loremIpsum({ sentencesCount: 3 }), + }, + { + weight: 0.4, + value: funcs.default({ defaultValue: "TODO" }), + }, + ]), + }, + }, + })); +})().then(); +``` + +### Generators Usage Examples + +## + +#### **default** + +generates same given value each time the generator is called. + +`defaultValue` - value you want to generate + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + content: funcs.default({ defaultValue: "post content" }), + }, + }, +})); +``` + +## + +#### **valuesFromArray** + +generates values from given array + +`values` - array of values you want to generate.(can be array of weighted values) + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + title: funcs.valuesFromArray({ + values: ["Title1", "Title2", "Title3", "Title4", "Title5"], + isUnique: true, + }), + }, + }, +})); +``` + +weighted values example + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + title: funcs.valuesFromArray({ + values: [ + { weight: 0.35, values: ["Title1", "Title2"] }, + { weight: 0.5, values: ["Title3", "Title4"] }, + { weight: 0.15, values: ["Title5"] }, + ], + isUnique: false, + }), + }, + }, +})); +``` + +## + +#### **intPrimaryKey** + +generates sequential integers starting with 1. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + id: funcs.intPrimaryKey(), + }, + }, +})); +``` + +## + +#### **number** + +generates numbers with floating point in given range. + +`minValue` - lower border of range. + +`maxValue` - upper border of range. + +`precision` - precision of generated number:
+precision equals 10 means that values will be accurate to one tenth (1.2, 34.6);
+precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67). + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + products: { + columns: { + unitPrice: funcs.number({ + minValue: 10, + maxValue: 120, + precision: 100, + isUnique: false, + }), + }, + }, +})); +``` + +## + +#### **int** + +generates integers with given range. + +`minValue` - lower border of range. + +`maxValue` - upper border of range. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + products: { + columns: { + unitsInStock: funcs.number({ + minValue: 0, + maxValue: 100, + isUnique: false, + }), + }, + }, +})); +``` + +## + +#### **boolean** + +generates boolean values(true or false). + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + isAvailable: funcs.boolean(), + }, + }, +})); +``` + +## + +#### **date** + +generates date within given range. + +`minDate` - lower border of range. + +`maxDate` - upper border of range. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + birthDate: funcs.date({ minDate: "1990-01-01", maxDate: "2010-12-31" }), + }, + }, +})); +``` + +## + +#### **time** + +generates time in 24 hours style. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + birthTime: funcs.time(), + }, + }, +})); +``` + +## + +#### **timestamp** + +generates timestamps. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + orders: { + columns: { + shippedDate: funcs.timestamp(), + }, + }, +})); +``` + +## + +#### **datetime** + +generates datetime objects. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + orders: { + columns: { + shippedDate: funcs.datetime(), + }, + }, +})); +``` + +## + +#### **year** + +generates years. ("2024") + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + birthYear: funcs.year(), + }, + }, +})); +``` + +## + +#### **json** + +generates json objects with fixed structure. + +json structure can equal this: + +``` +{ + email, + name, + isGraduated, + hasJob, + salary, + startedWorking, + visitedCountries, +} +``` + +or this + +``` +{ + email, + name, + isGraduated, + hasJob, + visitedCountries, +} +``` + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + metadata: funcs.json(), + }, + }, +})); +``` + +## + +#### **interval** + +generates time intervals. + +interval example: "1 years 12 days 5 minutes" + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + timeSpentOnWebsite: funcs.interval(), + }, + }, +})); +``` + +## + +#### **string** + +generates random strings. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + hashedPassword: funcs.string({ isUnique: false }), + }, + }, +})); +``` + +## + +#### **firstName** + +generates person's first names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + firstName: funcs.firstName({ isUnique: true }), + }, + }, +})); +``` + +## + +#### **lastName** + +generates person's last names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + lastName: funcs.lastName({ isUnique: false }), + }, + }, +})); +``` + +## + +#### **fullName** + +generates person's full names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + fullName: funcs.fullName({ isUnique: true }), + }, + }, +})); +``` + +## + +#### **email** + +generates unique emails. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + email: funcs.email(), + }, + }, +})); +``` + +## + +#### **phoneNumber** + +generates unique phone numbers. + +`template` - phone number template, where all '#' symbols will be substituted with generated digits. + +`prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property) + +`generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property) + +```ts +//generate phone number using template property +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + phoneNumber: funcs.phoneNumber({ template: "+(380) ###-####" }), + }, + }, +})); + +//generate phone number using prefixes and generatedDigitsNumbers properties +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + phoneNumber: funcs.phoneNumber({ + prefixes: ["+380 99", "+380 67"], + generatedDigitsNumbers: 7, + }), + }, + }, +})); + +//generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + phoneNumber: funcs.phoneNumber({ + prefixes: ["+380 99", "+380 67", "+1"], + generatedDigitsNumbers: [7, 7, 10], + }), + }, + }, +})); +``` + +## + +#### **country** + +generates country's names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + country: funcs.country({ isUnique: false }), + }, + }, +})); +``` + +## + +#### **city** + +generates city's names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + city: funcs.cityName({ isUnique: false }), + }, + }, +})); +``` + +## + +#### **streetAddress** + +generates street address. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + streetAddress: funcs.streetAddress({ isUnique: true }), + }, + }, +})); +``` + +## + +#### **jobTitle** + +generates job titles. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + jobTitle: funcs.jobTitle(), + }, + }, +})); +``` + +## + +#### **postcode** + +generates postal codes. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + postcode: funcs.postcode({ isUnique: true }), + }, + }, +})); +``` + +## + +#### **state** + +generates states of America. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + state: funcs.state(), + }, + }, +})); +``` + +## + +#### **companyName** + +generates company's names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + company: funcs.companyName({ isUnique: true }), + }, + }, +})); +``` + +## + +#### **loremIpsum** + +generates 'lorem ipsum' text sentences. + +`sentencesCount` - number of sentences you want to generate as one generated value(string). + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + content: funcs.loremIpsum({ sentencesCount: 2 }), + }, + }, +})); +``` + +## + +#### **point** + +generates 2D points within specified ranges for x and y coordinates. + +`isUnique` - property that controls if generated values gonna be unique or not. + +`minXValue` - lower bound of range for x coordinate. + +`maxXValue` - upper bound of range for x coordinate. + +`minYValue` - lower bound of range for y coordinate. + +`maxYValue` - upper bound of range for y coordinate. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + triangles: { + columns: { + pointCoords: funcs.point({ + isUnique: true, + minXValue: -5, + maxXValue: 20, + minYValue: 0, + maxYValue: 30, + }), + }, + }, +})); +``` + +## + +#### **line** + +generates 2D lines within specified ranges for a, b and c parameters of line. + +``` +line equation: a*x + b*y + c = 0 +``` + +`isUnique` - property that controls if generated values gonna be unique or not. + +`minAValue` - lower bound of range for a parameter. + +`maxAValue` - upper bound of range for x parameter. + +`minBValue` - lower bound of range for y parameter. + +`maxBValue` - upper bound of range for y parameter. + +`minCValue` - lower bound of range for y parameter. + +`maxCValue` - upper bound of range for y parameter. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + lines: { + columns: { + lineParams: funcs.point({ + isUnique: true, + minAValue: -5, + maxAValue: 20, + minBValue: 0, + maxBValue: 30, + minCValue: 0, + maxCValue: 10, + }), + }, + }, +})); +``` + +## + +#### **weightedRandom** + +gives you the opportunity to call different generators with different probabilities to generate values for one column. + +params - array of generators with probabilities you would like to call them to generate values. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + content: funcs.weightedRandom([ + { + weight: 0.6, + value: funcs.loremIpsum({ sentencesCount: 3 }), + }, + { + weight: 0.4, + value: funcs.default({ defaultValue: "TODO" }), + }, + ]), + }, + }, +})); +``` + +## + +## Limitations + +- Seeder can generate data for composite foreign keys, but it can't handle the uniqueness of composite primary keys, so using composite primary and foreign keys sometimes will end up in error for now. +- Seeder can't generate data for columns with composite unique constraint.(unique index for multiple columns) +- Not all generators have ability to generate unique data. This applies to default, date, time, timestamp, datetime, year, json, jobTitle, state, loremIpsum generators. diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json new file mode 100644 index 000000000..86edaf97b --- /dev/null +++ b/drizzle-seed/package.json @@ -0,0 +1,72 @@ +{ + "name": "drizzle-seed", + "version": "0.0.1", + "main": "index.js", + "type": "module", + "scripts": { + "build": "tsx scripts/build.ts", + "pack": "(cd dist && npm pack --pack-destination ..) && rm -f package.tgz && mv *.tgz package.tgz", + "test": "vitest --config ./src/tests/vitest.config.ts", + "generate-for-tests:pg": "drizzle-kit generate --config=./src/tests/pg/drizzle.config.ts", + "generate-for-tests:mysql": "drizzle-kit generate --config=./src/tests/mysql/drizzle.config.ts", + "generate-for-tests:sqlite": "drizzle-kit generate --config=./src/tests/sqlite/drizzle.config.ts", + "generate": "drizzle-kit generate", + "start": "npx tsx ./src/test.ts", + "start:pg": "npx tsx ./src/tests/northwind/pgTest.ts", + "start:mysql": "npx tsx ./src/tests/northwind/mysqlTest.ts", + "start:sqlite": "npx tsx ./src/tests/northwind/sqliteTest.ts", + "benchmark": "npx tsx ./src/tests/benchmarks/generatorsBenchmark.ts" + }, + "author": "", + "license": "ISC", + "description": "", + "exports": { + ".": { + "import": { + "types": "./index.d.mts", + "default": "./index.mjs" + }, + "require": { + "types": "./index.d.cjs", + "default": "./index.cjs" + }, + "types": "./index.d.ts", + "default": "./index.mjs" + } + }, + "peerDependenciesMeta": { + "drizzle-orm": { + "optional": true + } + }, + "devDependencies": { + "@arethetypeswrong/cli": "^0.16.1", + "@electric-sql/pglite": "^0.1.5", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.6", + "@types/better-sqlite3": "^7.6.11", + "@types/dockerode": "^3.3.31", + "@types/node": "^22.5.4", + "@types/pg": "^8.11.6", + "@types/uuid": "^10.0.0", + "better-sqlite3": "^11.1.2", + "cpy": "^11.1.0", + "dockerode": "^4.0.2", + "dotenv": "^16.4.5", + "drizzle-kit": "workspace:./drizzle-kit/dist", + "drizzle-orm": "workspace:./drizzle-orm/dist", + "get-port": "^7.1.0", + "mysql2": "^3.3.3", + "pg": "^8.12.0", + "resolve-tspaths": "^0.8.19", + "rollup": "^4.21.2", + "tslib": "^2.7.0", + "tsx": "^4.19.0", + "uuid": "^10.0.0", + "vitest": "^2.0.5", + "zx": "^8.1.5" + }, + "dependencies": { + "pure-rand": "^6.1.0" + } +} diff --git a/drizzle-seed/rollup.config.ts b/drizzle-seed/rollup.config.ts new file mode 100644 index 000000000..229862c75 --- /dev/null +++ b/drizzle-seed/rollup.config.ts @@ -0,0 +1,32 @@ +import terser from '@rollup/plugin-terser'; +import typescript from '@rollup/plugin-typescript'; +import { defineConfig } from 'rollup'; + +export default defineConfig([ + { + input: 'src/index.ts', + output: [ + { + format: 'esm', + dir: 'dist', + entryFileNames: '[name].mjs', + chunkFileNames: '[name]-[hash].mjs', + sourcemap: true, + }, + { + format: 'cjs', + dir: 'dist', + entryFileNames: '[name].cjs', + chunkFileNames: '[name]-[hash].cjs', + sourcemap: true, + }, + ], + external: [/^drizzle-orm\/?/, 'pure-rand'], + plugins: [ + typescript({ + tsconfig: 'tsconfig.build.json', + }), + terser(), + ], + }, +]); diff --git a/drizzle-seed/scripts/build.ts b/drizzle-seed/scripts/build.ts new file mode 100644 index 000000000..1910feac6 --- /dev/null +++ b/drizzle-seed/scripts/build.ts @@ -0,0 +1,15 @@ +#!/usr/bin/env -S pnpm tsx +import 'zx/globals'; +import cpy from 'cpy'; + +await fs.remove('dist'); +await $`rollup --config rollup.config.ts --configPlugin typescript`; +await $`resolve-tspaths`; +await fs.copy('README.md', 'dist/README.md'); +await cpy('dist/**/*.d.ts', 'dist', { + rename: (basename) => basename.replace(/\.d\.ts$/, '.d.mts'), +}); +await cpy('dist/**/*.d.ts', 'dist', { + rename: (basename) => basename.replace(/\.d\.ts$/, '.d.cts'), +}); +await fs.copy('package.json', 'dist/package.json'); diff --git a/drizzle-seed/src/datasets/adjectives.ts b/drizzle-seed/src/datasets/adjectives.ts new file mode 100644 index 000000000..256ed1cc1 --- /dev/null +++ b/drizzle-seed/src/datasets/adjectives.ts @@ -0,0 +1,4843 @@ +export default [ + 'abandoned', + 'abdominal', + 'abhorrent', + 'abiding', + 'abject', + 'able', + 'able-bodied', + 'abnormal', + 'abounding', + 'abrasive', + 'abrupt', + 'absent', + 'absentminded', + 'absolute', + 'absorbed', + 'absorbing', + 'abstracted', + 'absurd', + 'abundant', + 'abusive', + 'abysmal', + 'academic', + 'acceptable', + 'accepting', + 'accessible', + 'accidental', + 'acclaimed', + 'accommodating', + 'accompanying', + 'accountable', + 'accurate', + 'accusative', + 'accused', + 'accusing', + 'acerbic', + 'achievable', + 'aching', + 'acid', + 'acidic', + 'acknowledged', + 'acoustic', + 'acrid', + 'acrimonious', + 'acrobatic', + 'actionable', + 'active', + 'actual', + 'adhoc', + 'adamant', + 'adaptable', + 'adaptive', + 'addicted', + 'addictive', + 'additional', + 'adept', + 'adequate', + 'adhesive', + 'adjacent', + 'adjoining', + 'adjustable', + 'administrative', + 'admirable', + 'admired', + 'admiring', + 'adopted', + 'adoptive', + 'adorable', + 'adored', + 'adoring', + 'adrenalized', + 'adroit', + 'adult', + 'advanced', + 'advantageous', + 'adventurous', + 'adversarial', + 'advisable', + 'aerial', + 'affable', + 'affected', + 'affectionate', + 'affirmative', + 'affordable', + 'afraid', + 'afternoon', + 'ageless', + 'aggravated', + 'aggravating', + 'aggressive', + 'agitated', + 'agonizing', + 'agrarian', + 'agreeable', + 'aimless', + 'airline', + 'airsick', + 'ajar', + 'alarmed', + 'alarming', + 'alert', + 'algebraic', + 'alien', + 'alienated', + 'alike', + 'alive', + 'all-around', + 'alleged', + 'allowable', + 'all-purpose', + 'all-too-common', + 'alluring', + 'allusive', + 'alone', + 'aloof', + 'alterable', + 'alternating', + 'alternative', + 'amazed', + 'amazing', + 'ambiguous', + 'ambitious', + 'ambulant', + 'ambulatory', + 'amiable', + 'amicable', + 'amphibian', + 'amused', + 'amusing', + 'ancient', + 'anecdotal', + 'anemic', + 'angelic', + 'angered', + 'angry', + 'angular', + 'animal', + 'animated', + 'annoyed', + 'annoying', + 'annual', + 'anonymous', + 'another', + 'antagonistic', + 'anticipated', + 'anticlimactic', + 'anticorrosive', + 'antiquated', + 'antiseptic', + 'antisocial', + 'antsy', + 'anxious', + 'any', + 'apathetic', + 'apologetic', + 'apologizing', + 'appalling', + 'appealing', + 'appetizing', + 'applauding', + 'applicable', + 'applicative', + 'appreciative', + 'apprehensive', + 'approachable', + 'approaching', + 'appropriate', + 'approving', + 'approximate', + 'aquatic', + 'architectural', + 'ardent', + 'arduous', + 'arguable', + 'argumentative', + 'arid', + 'aristocratic', + 'aromatic', + 'arresting', + 'arrogant', + 'artful', + 'artificial', + 'artistic', + 'artless', + 'ashamed', + 'aspiring', + 'assertive', + 'assignable', + 'assorted', + 'assumable', + 'assured', + 'assuring', + 'astonished', + 'astonishing', + 'astounded', + 'astounding', + 'astringent', + 'astronomical', + 'astute', + 'asymmetrical', + 'athletic', + 'atomic', + 'atrocious', + 'attachable', + 'attainable', + 'attentive', + 'attractive', + 'attributable', + 'atypical', + 'audacious', + 'auspicious', + 'authentic', + 'authoritarian', + 'authoritative', + 'autobiographic', + 'autographed', + 'automatic', + 'autonomous', + 'available', + 'avant-garde', + 'avenging', + 'average', + 'avian', + 'avid', + 'avoidable', + 'awake', + 'awakening', + 'aware', + 'away', + 'awesome', + 'awful', + 'awkward', + 'axiomatic', + 'babbling', + 'baby', + 'background', + 'backhanded', + 'bacterial', + 'bad', + 'bad-tempered', + 'baffled', + 'baffling', + 'bald', + 'balding', + 'balmy', + 'bandaged', + 'banging', + 'bankable', + 'banned', + 'bantering', + 'barbaric', + 'barbarous', + 'barbequed', + 'barefooted', + 'barking', + 'barren', + 'bashful', + 'basic', + 'battered', + 'batty', + 'bawling', + 'beady', + 'beaming', + 'bearable', + 'beautiful', + 'beckoning', + 'bedazzled', + 'bedazzling', + 'beefy', + 'beeping', + 'befitting', + 'befuddled', + 'beginning', + 'belching', + 'believable', + 'bellicose', + 'belligerent', + 'bellowing', + 'bendable', + 'beneficial', + 'benevolent', + 'benign', + 'bent', + 'berserk', + 'best', + 'betrayed', + 'better', + 'betteroff', + 'better-late-than-never', + 'bewildered', + 'bewildering', + 'bewitched', + 'bewitching', + 'biased', + 'biblical', + 'big', + 'big-city', + 'bigger', + 'biggest', + 'big-headed', + 'bighearted', + 'bigoted', + 'bilingual', + 'billable', + 'billowy', + 'binary', + 'binding', + 'bioactive', + 'biodegradable', + 'biographical', + 'bite-sized', + 'biting', + 'bitter', + 'bizarre', + 'black', + 'black-and-blue', + 'blamable', + 'blameless', + 'bland', + 'blank', + 'blaring', + 'blasphemous', + 'blatant', + 'blazing', + 'bleached', + 'bleak', + 'bleary', + 'bleary-eyed', + 'blessed', + 'blind', + 'blindfolded', + 'blinding', + 'blissful', + 'blistering', + 'bloated', + 'blonde', + 'bloodied', + 'blood-red', + 'bloodthirsty', + 'bloody', + 'blooming', + 'blossoming', + 'blue', + 'blundering', + 'blunt', + 'blurred', + 'blurry', + 'blushing', + 'boastful', + 'bodacious', + 'bohemian', + 'boiling', + 'boisterous', + 'bold', + 'bookish', + 'booming', + 'boorish', + 'bordering', + 'bored', + 'boring', + 'born', + 'bossy', + 'both', + 'bothered', + 'bouncing', + 'bouncy', + 'boundless', + 'bountiful', + 'boyish', + 'braided', + 'brainless', + 'brainy', + 'brash', + 'brassy', + 'brave', + 'brawny', + 'brazen', + 'breakable', + 'breathable', + 'breathless', + 'breathtaking', + 'breezy', + 'bribable', + 'brick', + 'brief', + 'bright', + 'bright-eyed', + 'bright-red', + 'brilliant', + 'briny', + 'brisk', + 'bristly', + 'broad', + 'broken', + 'broken-hearted', + 'bronchial', + 'bronze', + 'bronzed', + 'brooding', + 'brown', + 'bruised', + 'brunette', + 'brutal', + 'brutish', + 'bubbly', + 'budget', + 'built-in', + 'bulky', + 'bumpy', + 'bungling', + 'buoyant', + 'bureaucratic', + 'burly', + 'burnable', + 'burning', + 'bushy', + 'busiest', + 'business', + 'bustling', + 'busy', + 'buzzing', + 'cackling', + 'caged', + 'cagey', + 'calculable', + 'calculated', + 'calculating', + 'callous', + 'calm', + 'calming', + 'camouflaged', + 'cancelled', + 'cancerous', + 'candid', + 'cantankerous', + 'capable', + 'capricious', + 'captivated', + 'captivating', + 'captive', + 'carefree', + 'careful', + 'careless', + 'caring', + 'carnivorous', + 'carpeted', + 'carsick', + 'casual', + 'catastrophic', + 'catatonic', + 'catchable', + 'caustic', + 'cautious', + 'cavalier', + 'cavernous', + 'ceaseless', + 'celebrated', + 'celestial', + 'centered', + 'central', + 'cerebral', + 'ceremonial', + 'certain', + 'certifiable', + 'certified', + 'challenged', + 'challenging', + 'chance', + 'changeable', + 'changing', + 'chanting', + 'charging', + 'charismatic', + 'charitable', + 'charmed', + 'charming', + 'chattering', + 'chatting', + 'chatty', + 'chauvinistic', + 'cheap', + 'cheapest', + 'cheeky', + 'cheerful', + 'cheering', + 'cheerless', + 'cheery', + 'chemical', + 'chewable', + 'chewy', + 'chic', + 'chicken', + 'chief', + 'childish', + 'childlike', + 'chilling', + 'chilly', + 'chivalrous', + 'choice', + 'choking', + 'choppy', + 'chronological', + 'chubby', + 'chuckling', + 'chunky', + 'cinematic', + 'circling', + 'circular', + 'circumstantial', + 'civil', + 'civilian', + 'civilized', + 'clammy', + 'clamoring', + 'clandestine', + 'clanging', + 'clapping', + 'clashing', + 'classic', + 'classical', + 'classifiable', + 'classified', + 'classy', + 'clean', + 'cleanable', + 'clear', + 'cleared', + 'clearheaded', + 'clever', + 'climatic', + 'climbable', + 'clinging', + 'clingy', + 'clinical', + 'cliquish', + 'clogged', + 'cloistered', + 'close', + 'closeable', + 'closed', + 'close-minded', + 'cloudless', + 'cloudy', + 'clownish', + 'clueless', + 'clumsy', + 'cluttered', + 'coachable', + 'coarse', + 'cockamamie', + 'cocky', + 'codified', + 'coercive', + 'cognitive', + 'coherent', + 'cohesive', + 'coincidental', + 'cold', + 'coldhearted', + 'collaborative', + 'collapsed', + 'collapsing', + 'collectable', + 'collegial', + 'colloquial', + 'colonial', + 'colorful', + 'colorless', + 'colossal', + 'combative', + 'combined', + 'comfortable', + 'comforted', + 'comforting', + 'comical', + 'commanding', + 'commemorative', + 'commendable', + 'commercial', + 'committed', + 'common', + 'communal', + 'communicable', + 'communicative', + 'communist', + 'compact', + 'comparable', + 'comparative', + 'compassionate', + 'compelling', + 'competent', + 'competitive', + 'complacent', + 'complaining', + 'complete', + 'completed', + 'complex', + 'compliant', + 'complicated', + 'complimentary', + 'compound', + 'comprehensive', + 'compulsive', + 'compulsory', + 'computer', + 'computerized', + 'concealable', + 'concealed', + 'conceited', + 'conceivable', + 'concerned', + 'concerning', + 'concerted', + 'concise', + 'concurrent', + 'condemned', + 'condensed', + 'condescending', + 'conditional', + 'confident', + 'confidential', + 'confirmable', + 'confirmed', + 'conflicted', + 'conflicting', + 'conformable', + 'confounded', + 'confused', + 'confusing', + 'congenial', + 'congested', + 'congressional', + 'congruent', + 'congruous', + 'connectable', + 'connected', + 'connecting', + 'connective', + 'conscientious', + 'conscious', + 'consecutive', + 'consensual', + 'consenting', + 'conservative', + 'considerable', + 'considerate', + 'consistent', + 'consoling', + 'conspicuous', + 'conspiratorial', + 'constant', + 'constitutional', + 'constrictive', + 'constructive', + 'consumable', + 'consummate', + 'contagious', + 'containable', + 'contemplative', + 'contemporary', + 'contemptible', + 'contemptuous', + 'content', + 'contented', + 'contentious', + 'contextual', + 'continual', + 'continuing', + 'continuous', + 'contoured', + 'contractual', + 'contradicting', + 'contradictory', + 'contrarian', + 'contrary', + 'contributive', + 'contrite', + 'controllable', + 'controlling', + 'controversial', + 'convenient', + 'conventional', + 'conversational', + 'convinced', + 'convincing', + 'convoluted', + 'convulsive', + 'cooing', + 'cooked', + 'cool', + 'coolest', + 'cooperative', + 'coordinated', + 'copious', + 'coquettish', + 'cordial', + 'corner', + 'cornered', + 'corny', + 'corporate', + 'corpulent', + 'correct', + 'correctable', + 'corrective', + 'corresponding', + 'corrosive', + 'corrupt', + 'corrupting', + 'corruptive', + 'cosmetic', + 'cosmic', + 'costly', + 'cottony', + 'coughing', + 'courageous', + 'courteous', + 'covert', + 'coveted', + 'cowardly', + 'cowering', + 'coy', + 'cozy', + 'crabby', + 'cracked', + 'crackling', + 'crafty', + 'craggy', + 'crammed', + 'cramped', + 'cranky', + 'crashing', + 'crass', + 'craven', + 'crawling', + 'crazy', + 'creaking', + 'creaky', + 'creamy', + 'creative', + 'credible', + 'creeping', + 'creepy', + 'crestfallen', + 'criminal', + 'crippled', + 'crippling', + 'crisp', + 'crispy', + 'critical', + 'crooked', + 'cropped', + 'cross', + 'crossed', + 'crotchety', + 'crowded', + 'crucial', + 'crude', + 'cruel', + 'crumbling', + 'crumbly', + 'crumply', + 'crunchable', + 'crunching', + 'crunchy', + 'crushable', + 'crushed', + 'crusty', + 'crying', + 'cryptic', + 'crystalline', + 'crystallized', + 'cuddly', + 'culpable', + 'cultural', + 'cultured', + 'cumbersome', + 'cumulative', + 'cunning', + 'curable', + 'curative', + 'curious', + 'curly', + 'current', + 'cursed', + 'curt', + 'curved', + 'curvy', + 'customary', + 'cut', + 'cute', + 'cutting', + 'cylindrical', + 'cynical', + 'daffy', + 'daft', + 'daily', + 'dainty', + 'damaged', + 'damaging', + 'damp', + 'danceable', + 'dandy', + 'dangerous', + 'dapper', + 'daring', + 'dark', + 'darkened', + 'dashing', + 'daughterly', + 'daunting', + 'dawdling', + 'day', + 'dazed', + 'dazzling', + 'dead', + 'deadly', + 'deadpan', + 'deaf', + 'deafening', + 'dear', + 'debatable', + 'debonair', + 'decadent', + 'decayed', + 'decaying', + 'deceitful', + 'deceivable', + 'deceiving', + 'decent', + 'decentralized', + 'deceptive', + 'decimated', + 'decipherable', + 'decisive', + 'declining', + 'decorative', + 'decorous', + 'decreasing', + 'decrepit', + 'dedicated', + 'deep', + 'deepening', + 'deeply', + 'defeated', + 'defective', + 'defendable', + 'defenseless', + 'defensible', + 'defensive', + 'defiant', + 'deficient', + 'definable', + 'definitive', + 'deformed', + 'degenerative', + 'degraded', + 'dehydrated', + 'dejected', + 'delectable', + 'deliberate', + 'deliberative', + 'delicate', + 'delicious', + 'delighted', + 'delightful', + 'delinquent', + 'delirious', + 'deliverable', + 'deluded', + 'demanding', + 'demented', + 'democratic', + 'demonic', + 'demonstrative', + 'demure', + 'deniable', + 'dense', + 'dependable', + 'dependent', + 'deplorable', + 'deploring', + 'depraved', + 'depressed', + 'depressing', + 'depressive', + 'deprived', + 'deranged', + 'derivative', + 'derogative', + 'derogatory', + 'descriptive', + 'deserted', + 'designer', + 'desirable', + 'desirous', + 'desolate', + 'despairing', + 'desperate', + 'despicable', + 'despised', + 'despondent', + 'destroyed', + 'destructive', + 'detachable', + 'detached', + 'detailed', + 'detectable', + 'determined', + 'detestable', + 'detrimental', + 'devastated', + 'devastating', + 'devious', + 'devoted', + 'devout', + 'dexterous', + 'diabolical', + 'diagonal', + 'didactic', + 'different', + 'difficult', + 'diffuse', + 'digestive', + 'digital', + 'dignified', + 'digressive', + 'dilapidated', + 'diligent', + 'dim', + 'diminishing', + 'diminutive', + 'dingy', + 'diplomatic', + 'dire', + 'direct', + 'direful', + 'dirty', + 'disabled', + 'disadvantaged', + 'disadvantageous', + 'disaffected', + 'disagreeable', + 'disappearing', + 'disappointed', + 'disappointing', + 'disapproving', + 'disarming', + 'disastrous', + 'discarded', + 'discernable', + 'disciplined', + 'disconnected', + 'discontented', + 'discordant', + 'discouraged', + 'discouraging', + 'discourteous', + 'discredited', + 'discreet', + 'discriminating', + 'discriminatory', + 'discussable', + 'disdainful', + 'diseased', + 'disenchanted', + 'disgraceful', + 'disgruntled', + 'disgusted', + 'disgusting', + 'disheartened', + 'disheartening', + 'dishonest', + 'dishonorable', + 'disillusioned', + 'disinclined', + 'disingenuous', + 'disinterested', + 'disjointed', + 'dislikeable', + 'disliked', + 'disloyal', + 'dismal', + 'dismissive', + 'disobedient', + 'disorderly', + 'disorganized', + 'disparaging', + 'disparate', + 'dispassionate', + 'dispensable', + 'displaced', + 'displeased', + 'displeasing', + 'disposable', + 'disproportionate', + 'disproved', + 'disputable', + 'disputatious', + 'disputed', + 'disreputable', + 'disrespectful', + 'disruptive', + 'dissatisfied', + 'dissimilar', + 'dissolvable', + 'dissolving', + 'dissonant', + 'dissuasive', + 'distant', + 'distasteful', + 'distinct', + 'distinctive', + 'distinguished', + 'distracted', + 'distracting', + 'distraught', + 'distressed', + 'distressing', + 'distrustful', + 'disturbed', + 'disturbing', + 'divergent', + 'diverging', + 'diverse', + 'diversified', + 'divided', + 'divine', + 'divisive', + 'dizzy', + 'dizzying', + 'doable', + 'documentary', + 'dogged', + 'doggish', + 'dogmatic', + 'doleful', + 'dollish', + 'domed', + 'domestic', + 'dominant', + 'domineering', + 'dorsal', + 'doting', + 'double', + 'doubtful', + 'doubting', + 'dovish', + 'dowdy', + 'down', + 'down-and-out', + 'downhearted', + 'downloadable', + 'downtown', + 'downward', + 'dozing', + 'drab', + 'drained', + 'dramatic', + 'drastic', + 'dreaded', + 'dreadful', + 'dreaming', + 'dreamy', + 'dreary', + 'drenched', + 'dress', + 'dressy', + 'dried', + 'dripping', + 'drivable', + 'driven', + 'droll', + 'drooping', + 'droopy', + 'drowsy', + 'drunk', + 'dry', + 'dual', + 'dubious', + 'due', + 'dulcet', + 'dull', + 'duplicitous', + 'durable', + 'dusty', + 'dutiful', + 'dwarfish', + 'dwindling', + 'dynamic', + 'dysfunctional', + 'each', + 'eager', + 'early', + 'earnest', + 'ear-piercing', + 'ear-splitting', + 'earthshaking', + 'earthy', + 'east', + 'eastern', + 'easy', + 'eatable', + 'eccentric', + 'echoing', + 'ecological', + 'economic', + 'economical', + 'economy', + 'ecstatic', + 'edgy', + 'editable', + 'educated', + 'educational', + 'eerie', + 'effective', + 'effervescent', + 'efficacious', + 'efficient', + 'effortless', + 'effusive', + 'egalitarian', + 'egocentric', + 'egomaniacal', + 'egotistical', + 'eight', + 'eighth', + 'either', + 'elaborate', + 'elastic', + 'elated', + 'elderly', + 'electric', + 'electrical', + 'electrifying', + 'electronic', + 'elegant', + 'elementary', + 'elevated', + 'elfish', + 'eligible', + 'elite', + 'eloquent', + 'elusive', + 'emaciated', + 'embarrassed', + 'embarrassing', + 'embattled', + 'embittered', + 'emblematic', + 'emboldened', + 'embroiled', + 'emergency', + 'eminent', + 'emotional', + 'emotionless', + 'empirical', + 'empty', + 'enamored', + 'enchanted', + 'enchanting', + 'encouraged', + 'encouraging', + 'encrusted', + 'endangered', + 'endearing', + 'endemic', + 'endless', + 'endurable', + 'enduring', + 'energetic', + 'energizing', + 'enforceable', + 'engaging', + 'engrossing', + 'enhanced', + 'enigmatic', + 'enjoyable', + 'enlarged', + 'enlightened', + 'enormous', + 'enough', + 'enraged', + 'ensuing', + 'enterprising', + 'entertained', + 'entertaining', + 'enthralled', + 'enthused', + 'enthusiastic', + 'enticing', + 'entire', + 'entranced', + 'entrepreneurial', + 'enumerable', + 'enviable', + 'envious', + 'environmental', + 'episodic', + 'equable', + 'equal', + 'equidistant', + 'equitable', + 'equivalent', + 'erasable', + 'erect', + 'eroding', + 'errant', + 'erratic', + 'erroneous', + 'eruptive', + 'escalating', + 'esoteric', + 'essential', + 'established', + 'estimated', + 'estranged', + 'eternal', + 'ethereal', + 'ethical', + 'ethnic', + 'euphemistic', + 'euphoric', + 'evasive', + 'even', + 'evenhanded', + 'evening', + 'eventful', + 'eventual', + 'everlasting', + 'every', + 'evil', + 'evocative', + 'exacerbating', + 'exact', + 'exacting', + 'exaggerated', + 'exalted', + 'exasperated', + 'exasperating', + 'excellent', + 'exceptional', + 'excessive', + 'exchangeable', + 'excitable', + 'excited', + 'exciting', + 'exclusive', + 'excruciating', + 'excusable', + 'executable', + 'exemplary', + 'exhausted', + 'exhausting', + 'exhaustive', + 'exhilarated', + 'exhilarating', + 'existing', + 'exotic', + 'expandable', + 'expanded', + 'expanding', + 'expansive', + 'expectant', + 'expected', + 'expedient', + 'expeditious', + 'expendable', + 'expensive', + 'experimental', + 'expert', + 'expired', + 'expiring', + 'explainable', + 'explicit', + 'exploding', + 'exploitative', + 'exploited', + 'explosive', + 'exponential', + 'exposed', + 'express', + 'expressionistic', + 'expressionless', + 'expressive', + 'exquisite', + 'extemporaneous', + 'extendable', + 'extended', + 'extension', + 'extensive', + 'exterior', + 'external', + 'extra', + 'extra-large', + 'extraneous', + 'extraordinary', + 'extra-small', + 'extravagant', + 'extreme', + 'exuberant', + 'eye-popping', + 'fabled', + 'fabulous', + 'facetious', + 'facial', + 'factitious', + 'factual', + 'faded', + 'fading', + 'failed', + 'faint', + 'fainthearted', + 'fair', + 'faithful', + 'faithless', + 'fallacious', + 'false', + 'falsified', + 'faltering', + 'familiar', + 'famished', + 'famous', + 'fanatical', + 'fanciful', + 'fancy', + 'fantastic', + 'far', + 'faraway', + 'farcical', + 'far-flung', + 'farsighted', + 'fascinated', + 'fascinating', + 'fascistic', + 'fashionable', + 'fast', + 'fastest', + 'fastidious', + 'fast-moving', + 'fat', + 'fatal', + 'fateful', + 'fatherly', + 'fathomable', + 'fathomless', + 'fatigued', + 'faulty', + 'favorable', + 'favorite', + 'fawning', + 'feared', + 'fearful', + 'fearless', + 'fearsome', + 'feathered', + 'feathery', + 'feckless', + 'federal', + 'feeble', + 'feebleminded', + 'feeling', + 'feigned', + 'felonious', + 'female', + 'feminine', + 'fermented', + 'ferocious', + 'fertile', + 'fervent', + 'fervid', + 'festive', + 'fetching', + 'fetid', + 'feudal', + 'feverish', + 'few,', + 'fewer', + 'fictional', + 'fictitious', + 'fidgeting', + 'fidgety', + 'fiendish', + 'fierce', + 'fiery', + 'fifth', + 'filmy', + 'filtered', + 'filthy', + 'final', + 'financial', + 'fine', + 'finicky', + 'finite', + 'fireproof', + 'firm', + 'first', + 'fiscal', + 'fishy', + 'fit', + 'fitted', + 'fitting', + 'five', + 'fixable', + 'fixed', + 'flabby', + 'flagrant', + 'flaky', + 'flamboyant', + 'flaming', + 'flammable', + 'flashy', + 'flat', + 'flattened', + 'flattered', + 'flattering', + 'flavored', + 'flavorful', + 'flavorless', + 'flawed', + 'flawless', + 'fleeting', + 'flexible', + 'flickering', + 'flimsy', + 'flippant', + 'flirtatious', + 'floating', + 'flooded', + 'floppy', + 'floral', + 'flowering', + 'flowery', + 'fluent', + 'fluffy', + 'flushed', + 'fluttering', + 'flying', + 'foamy', + 'focused', + 'foggy', + 'folded', + 'following', + 'fond', + 'foolhardy', + 'foolish', + 'forbidding', + 'forceful', + 'foreboding', + 'foregoing', + 'foreign', + 'forensic', + 'foreseeable', + 'forged', + 'forgetful', + 'forgettable', + 'forgivable', + 'forgiving', + 'forgotten', + 'forked', + 'formal', + 'formative', + 'former', + 'formidable', + 'formless', + 'formulaic', + 'forthright', + 'fortuitous', + 'fortunate', + 'forward', + 'foul', + 'foul-smelling', + 'four', + 'fourth', + 'foxy', + 'fractional', + 'fractious', + 'fragile', + 'fragmented', + 'fragrant', + 'frail', + 'frank', + 'frantic', + 'fraternal', + 'fraudulent', + 'frayed', + 'freakish', + 'freaky', + 'freckled', + 'free', + 'freezing', + 'frequent', + 'fresh', + 'fretful', + 'fried', + 'friendly', + 'frightened', + 'frightening', + 'frightful', + 'frigid', + 'frilly', + 'frisky', + 'frivolous', + 'front', + 'frosty', + 'frothy', + 'frowning', + 'frozen', + 'frugal', + 'fruitful', + 'fruitless', + 'fruity', + 'frumpy', + 'frustrated', + 'frustrating', + 'fulfilled', + 'fulfilling', + 'full', + 'fully-grown', + 'fumbling', + 'fuming', + 'fun', + 'functional', + 'fundamental', + 'fun-loving', + 'funniest', + 'funny', + 'furious', + 'furry', + 'furthest', + 'furtive', + 'fussy', + 'futile', + 'future', + 'futuristic', + 'fuzzy', + 'gabby', + 'gainful', + 'gallant', + 'galling', + 'game', + 'gangly', + 'gaping', + 'garbled', + 'gargantuan', + 'garish', + 'garrulous', + 'gaseous', + 'gasping', + 'gaudy', + 'gaunt', + 'gauzy', + 'gawky', + 'general', + 'generative', + 'generic', + 'generous', + 'genial', + 'gentle', + 'genuine', + 'geographic', + 'geologic', + 'geometric', + 'geriatric', + 'ghastly', + 'ghostly', + 'ghoulish', + 'giant', + 'giddy', + 'gifted', + 'gigantic', + 'giggling', + 'gilded', + 'giving', + 'glad', + 'glamorous', + 'glaring', + 'glass', + 'glassy', + 'gleaming', + 'glib', + 'glistening', + 'glittering', + 'global', + 'globular', + 'gloomy', + 'glorious', + 'glossy', + 'glowing', + 'gluey', + 'glum', + 'gluttonous', + 'gnarly', + 'gold', + 'golden', + 'good', + 'good-looking', + 'good-natured', + 'gooey', + 'goofy', + 'gorgeous', + 'graceful', + 'gracious', + 'gradual', + 'grainy', + 'grand', + 'grandiose', + 'graphic', + 'grateful', + 'gratified', + 'gratifying', + 'grating', + 'gratis', + 'gratuitous', + 'grave', + 'gray', + 'greasy', + 'great', + 'greatest', + 'greedy', + 'green', + 'gregarious', + 'grey', + 'grieving', + 'grim', + 'grimacing', + 'grimy', + 'grinding', + 'grinning', + 'gripping', + 'gritty', + 'grizzled', + 'groaning', + 'groggy', + 'groomed', + 'groovy', + 'gross', + 'grotesque', + 'grouchy', + 'growling', + 'grown-up', + 'grubby', + 'grueling', + 'gruesome', + 'gruff', + 'grumbling', + 'grumpy', + 'guaranteed', + 'guarded', + 'guiltless', + 'guilt-ridden', + 'guilty', + 'gullible', + 'gurgling', + 'gushing', + 'gushy', + 'gusty', + 'gutsy', + 'habitable', + 'habitual', + 'haggard', + 'hairless', + 'hairy', + 'half', + 'halfhearted', + 'hallowed', + 'halting', + 'handsome', + 'handy', + 'hanging', + 'haphazard', + 'hapless', + 'happy', + 'hard', + 'hard-to-find', + 'hardworking', + 'hardy', + 'harebrained', + 'harmful', + 'harmless', + 'harmonic', + 'harmonious', + 'harried', + 'harsh', + 'hasty', + 'hated', + 'hateful', + 'haughty', + 'haunting', + 'hawkish', + 'hazardous', + 'hazy', + 'head', + 'heady', + 'healthy', + 'heartbreaking', + 'heartbroken', + 'heartless', + 'heartrending', + 'hearty', + 'heated', + 'heavenly', + 'heavy', + 'hectic', + 'hefty', + 'heinous', + 'helpful', + 'helpless', + 'her', + 'heroic', + 'hesitant', + 'hideous', + 'high', + 'highest', + 'highfalutin', + 'high-functioning', + 'high-maintenance', + 'high-pitched', + 'high-risk', + 'hilarious', + 'his', + 'hissing', + 'historical', + 'hoarse', + 'hoggish', + 'holiday', + 'holistic', + 'hollow', + 'home', + 'homeless', + 'homely', + 'homeopathic', + 'homey', + 'homogeneous', + 'honest', + 'honking', + 'honorable', + 'hopeful', + 'hopeless', + 'horizontal', + 'hormonal', + 'horned', + 'horrendous', + 'horrible', + 'horrid', + 'horrific', + 'horrified', + 'horrifying', + 'hospitable', + 'hostile', + 'hot', + 'hotpink', + 'hot-blooded', + 'hotheaded', + 'hot-shot', + 'hot-tempered', + 'hour-long', + 'house', + 'howling', + 'huffy', + 'huge', + 'huggable', + 'hulking', + 'human', + 'humanitarian', + 'humanlike', + 'humble', + 'humdrum', + 'humid', + 'humiliated', + 'humiliating', + 'humming', + 'humongous', + 'humorless', + 'humorous', + 'hungry', + 'hurried', + 'hurt', + 'hurtful', + 'hushed', + 'husky', + 'hydraulic', + 'hydrothermal', + 'hygienic', + 'hyper-active', + 'hyperbolic', + 'hypercritical', + 'hyperirritable', + 'hypersensitive', + 'hypertensive', + 'hypnotic', + 'hypnotizable', + 'hypothetical', + 'hysterical', + 'icky', + 'iconoclastic', + 'icy', + 'icy-cold', + 'ideal', + 'idealistic', + 'identical', + 'identifiable', + 'idiosyncratic', + 'idiotic', + 'idyllic', + 'ignorable', + 'ignorant', + 'ill', + 'illegal', + 'illegible', + 'illegitimate', + 'ill-equipped', + 'ill-fated', + 'ill-humored', + 'illicit', + 'ill-informed', + 'illiterate', + 'illogical', + 'illuminating', + 'illusive', + 'illustrious', + 'imaginable', + 'imaginary', + 'imaginative', + 'imitative', + 'immaculate', + 'immanent', + 'immature', + 'immeasurable', + 'immediate', + 'immense', + 'immensurable', + 'imminent', + 'immobile', + 'immodest', + 'immoral', + 'immortal', + 'immovable', + 'impartial', + 'impassable', + 'impassioned', + 'impatient', + 'impeccable', + 'impenetrable', + 'imperative', + 'imperceptible', + 'imperceptive', + 'imperfect', + 'imperial', + 'imperialistic', + 'impermeable', + 'impersonal', + 'impertinent', + 'impervious', + 'impetuous', + 'impish', + 'implausible', + 'implicit', + 'implosive', + 'impolite', + 'imponderable', + 'important', + 'imported', + 'imposing', + 'impossible', + 'impoverished', + 'impractical', + 'imprecise', + 'impressionable', + 'impressive', + 'improbable', + 'improper', + 'improvable', + 'improved', + 'improving', + 'imprudent', + 'impulsive', + 'impure', + 'inaccessible', + 'inaccurate', + 'inactive', + 'inadequate', + 'inadmissible', + 'inadvertent', + 'inadvisable', + 'inalienable', + 'inalterable', + 'inane', + 'inanimate', + 'inapplicable', + 'inappropriate', + 'inapt', + 'inarguable', + 'inarticulate', + 'inartistic', + 'inattentive', + 'inaudible', + 'inauspicious', + 'incalculable', + 'incandescent', + 'incapable', + 'incessant', + 'incidental', + 'inclusive', + 'incoherent', + 'incomparable', + 'incompatible', + 'incompetent', + 'incomplete', + 'incomprehensible', + 'inconceivable', + 'inconclusive', + 'incongruent', + 'incongruous', + 'inconsequential', + 'inconsiderable', + 'inconsiderate', + 'inconsistent', + 'inconsolable', + 'inconspicuous', + 'incontrovertible', + 'inconvenient', + 'incorrect', + 'incorrigible', + 'incorruptible', + 'increasing', + 'incredible', + 'incredulous', + 'incremental', + 'incurable', + 'indecent', + 'indecipherable', + 'indecisive', + 'indefensible', + 'indefinable', + 'indefinite', + 'indelible', + 'independent', + 'indescribable', + 'indestructible', + 'indeterminable', + 'indeterminate', + 'indicative', + 'indifferent', + 'indigenous', + 'indignant', + 'indirect', + 'indiscreet', + 'indiscriminate', + 'indispensable', + 'indisputable', + 'indistinct', + 'individual', + 'individualistic', + 'indivisible', + 'indomitable', + 'inductive', + 'indulgent', + 'industrial', + 'industrious', + 'ineffective', + 'ineffectual', + 'inefficient', + 'inelegant', + 'ineloquent', + 'inequitable', + 'inert', + 'inescapable', + 'inevitable', + 'inexact', + 'inexcusable', + 'inexhaustible', + 'inexpedient', + 'inexpensive', + 'inexplicable', + 'inexpressible', + 'inexpressive', + 'inextricable', + 'infallible', + 'infamous', + 'infantile', + 'infatuated', + 'infected', + 'infectious', + 'inferable', + 'inferior', + 'infernal', + 'infinite', + 'infinitesimal', + 'inflamed', + 'inflammable', + 'inflammatory', + 'inflatable', + 'inflated', + 'inflexible', + 'influential', + 'informal', + 'informative', + 'informed', + 'infrequent', + 'infuriated', + 'infuriating', + 'ingenious', + 'ingenuous', + 'inglorious', + 'ingratiating', + 'inhabitable', + 'inharmonious', + 'inherent', + 'inhibited', + 'inhospitable', + 'inhuman', + 'inhumane', + 'initial', + 'injudicious', + 'injured', + 'injurious', + 'innate', + 'inner', + 'innocent', + 'innocuous', + 'innovative', + 'innumerable', + 'inoffensive', + 'inoperable', + 'inoperative', + 'inopportune', + 'inordinate', + 'inorganic', + 'inquiring', + 'inquisitive', + 'insane', + 'insatiable', + 'inscrutable', + 'insecure', + 'insensible', + 'insensitive', + 'inseparable', + 'inside', + 'insidious', + 'insightful', + 'insignificant', + 'insincere', + 'insipid', + 'insistent', + 'insolent', + 'inspirational', + 'inspired', + 'inspiring', + 'instant', + 'instantaneous', + 'instinctive', + 'instinctual', + 'institutional', + 'instructive', + 'instrumental', + 'insubordinate', + 'insufferable', + 'insufficient', + 'insulted', + 'insulting', + 'insurable', + 'insurmountable', + 'intangible', + 'integral', + 'intellectual', + 'intelligent', + 'intelligible', + 'intended', + 'intense', + 'intensive', + 'intentional', + 'interactive', + 'interchangeable', + 'interdepartmental', + 'interdependent', + 'interested', + 'interesting', + 'interior', + 'intermediate', + 'intermittent', + 'internal', + 'international', + 'interpersonal', + 'interracial', + 'intestinal', + 'intimate', + 'intimidating', + 'intolerable', + 'intolerant', + 'intravenous', + 'intrepid', + 'intricate', + 'intrigued', + 'intriguing', + 'intrinsic', + 'introductory', + 'introspective', + 'introverted', + 'intrusive', + 'intuitive', + 'invalid', + 'invaluable', + 'invasive', + 'inventive', + 'invigorating', + 'invincible', + 'invisible', + 'invited', + 'inviting', + 'involuntary', + 'involved', + 'inward', + 'irascible', + 'irate', + 'iridescent', + 'irksome', + 'iron', + 'iron-fisted', + 'ironic', + 'irrational', + 'irreconcilable', + 'irrefutable', + 'irregular', + 'irrelative', + 'irrelevant', + 'irremovable', + 'irreparable', + 'irreplaceable', + 'irrepressible', + 'irresistible', + 'irresponsible', + 'irretrievably', + 'irreverent', + 'irreversible', + 'irrevocable', + 'irritable', + 'irritated', + 'irritating', + 'isolated', + 'itchy', + 'its', + 'itty-bitty', + 'jabbering', + 'jaded', + 'jagged', + 'jarring', + 'jaundiced', + 'jazzy', + 'jealous', + 'jeering', + 'jerky', + 'jiggling', + 'jittery', + 'jobless', + 'jocular', + 'joint', + 'jolly', + 'jovial', + 'joyful', + 'joyless', + 'joyous', + 'jubilant', + 'judgmental', + 'judicious', + 'juicy', + 'jumbled', + 'jumpy', + 'junior', + 'just', + 'justifiable', + 'juvenile', + 'kaput', + 'keen', + 'key', + 'kind', + 'kindhearted', + 'kindly', + 'kinesthetic', + 'kingly', + 'kitchen', + 'knavish', + 'knightly', + 'knobbed', + 'knobby', + 'knotty', + 'knowable', + 'knowing', + 'knowledgeable', + 'known', + 'labored', + 'laborious', + 'lackadaisical', + 'lacking', + 'lacy', + 'lame', + 'lamentable', + 'languid', + 'languishing', + 'lanky', + 'larcenous', + 'large', + 'larger', + 'largest', + 'lascivious', + 'last', + 'lasting', + 'late', + 'latent', + 'later', + 'lateral', + 'latest', + 'latter', + 'laudable', + 'laughable', + 'laughing', + 'lavish', + 'lawful', + 'lawless', + 'lax', + 'lazy', + 'lead', + 'leading', + 'lean', + 'learnable', + 'learned', + 'leased', + 'least', + 'leather', + 'leathery', + 'lecherous', + 'leering', + 'left', + 'left-handed', + 'legal', + 'legendary', + 'legible', + 'legislative', + 'legitimate', + 'lengthy', + 'lenient', + 'less', + 'lesser', + 'lesser-known', + 'less-qualified', + 'lethal', + 'lethargic', + 'level', + 'liable', + 'libelous', + 'liberal', + 'licensed', + 'life', + 'lifeless', + 'lifelike', + 'lifelong', + 'light', + 'light-blue', + 'lighthearted', + 'likable', + 'likeable', + 'likely', + 'like-minded', + 'lily-livered', + 'limber', + 'limited', + 'limitless', + 'limp', + 'limping', + 'linear', + 'lined', + 'lingering', + 'linguistic', + 'liquid', + 'listless', + 'literal', + 'literary', + 'literate', + 'lithe', + 'lithographic', + 'litigious', + 'little', + 'livable', + 'live', + 'lively', + 'livid', + 'living', + 'loathsome', + 'local', + 'locatable', + 'locked', + 'lofty', + 'logarithmic', + 'logical', + 'logistic', + 'lonely', + 'long', + 'longer', + 'longest', + 'longing', + 'long-term', + 'long-winded', + 'loose', + 'lopsided', + 'loquacious', + 'lordly', + 'lost', + 'loud', + 'lousy', + 'loutish', + 'lovable', + 'loveable', + 'lovely', + 'loving', + 'low', + 'low-calorie', + 'low-carb', + 'lower', + 'low-fat', + 'lowly', + 'low-maintenance', + 'low-ranking', + 'low-risk', + 'loyal', + 'lucent', + 'lucid', + 'lucky', + 'lucrative', + 'ludicrous', + 'lukewarm', + 'lulling', + 'luminescent', + 'luminous', + 'lumpy', + 'lurid', + 'luscious', + 'lush', + 'lustrous', + 'luxurious', + 'lying', + 'lyrical', + 'macabre', + 'Machiavellian', + 'macho', + 'mad', + 'maddening', + 'magenta', + 'magic', + 'magical', + 'magnanimous', + 'magnetic', + 'magnificent', + 'maiden', + 'main', + 'maintainable', + 'majestic', + 'major', + 'makeable', + 'makeshift', + 'maladjusted', + 'male', + 'malevolent', + 'malicious', + 'malignant', + 'malleable', + 'mammoth', + 'manageable', + 'managerial', + 'mandatory', + 'maneuverable', + 'mangy', + 'maniacal', + 'manic', + 'manicured', + 'manipulative', + 'man-made', + 'manual', + 'many,', + 'marbled', + 'marginal', + 'marked', + 'marketable', + 'married', + 'marvelous', + 'masked', + 'massive', + 'master', + 'masterful', + 'matchless', + 'material', + 'materialistic', + 'maternal', + 'mathematical', + 'matronly', + 'matted', + 'mature', + 'maximum', + 'meager', + 'mean', + 'meandering', + 'meaningful', + 'meaningless', + 'mean-spirited', + 'measly', + 'measurable', + 'meat-eating', + 'meaty', + 'mechanical', + 'medical', + 'medicinal', + 'meditative', + 'medium', + 'medium-rare', + 'meek', + 'melancholy', + 'mellow', + 'melodic', + 'melodious', + 'melodramatic', + 'melted', + 'memorable', + 'menacing', + 'menial', + 'mental', + 'merciful', + 'merciless', + 'mercurial', + 'mere', + 'merry', + 'messy', + 'metabolic', + 'metallic', + 'metaphoric', + 'meteoric', + 'meticulous', + 'microscopic', + 'microwaveable', + 'middle', + 'middle-class', + 'midweek', + 'mighty', + 'mild', + 'militant', + 'militaristic', + 'military', + 'milky', + 'mincing', + 'mind-bending', + 'mindful', + 'mindless', + 'mini', + 'miniature', + 'minimal', + 'minimum', + 'minor', + 'minute', + 'miraculous', + 'mirthful', + 'miscellaneous', + 'mischievous', + 'miscreant', + 'miserable', + 'miserly', + 'misguided', + 'misleading', + 'mission', + 'mistaken', + 'mistrustful', + 'mistrusting', + 'misty', + 'mixed', + 'mnemonic', + 'moaning', + 'mobile', + 'mocking', + 'moderate', + 'modern', + 'modest', + 'modified', + 'modular', + 'moist', + 'moldy', + 'momentary', + 'momentous', + 'monetary', + 'money-grubbing', + 'monopolistic', + 'monosyllabic', + 'monotone', + 'monotonous', + 'monstrous', + 'monumental', + 'moody', + 'moral', + 'moralistic', + 'morbid', + 'mordant', + 'more', + 'moronic', + 'morose', + 'mortal', + 'mortified', + 'most', + 'mother', + 'motherly', + 'motionless', + 'motivated', + 'motivating', + 'motivational', + 'motor', + 'mountain', + 'mountainous', + 'mournful', + 'mouthwatering', + 'movable', + 'moved', + 'moving', + 'much', + 'muddled', + 'muddy', + 'muffled', + 'muggy', + 'multicultural', + 'multifaceted', + 'multipurpose', + 'multitalented', + 'mumbled', + 'mundane', + 'municipal', + 'murky', + 'muscular', + 'mushy', + 'musical', + 'musky', + 'musty', + 'mutative', + 'mute', + 'muted', + 'mutinous', + 'muttering', + 'mutual', + 'my', + 'myopic', + 'mysterious', + 'mystic', + 'mystical', + 'mystified', + 'mystifying', + 'mythical', + 'naive', + 'nameless', + 'narcissistic', + 'narrow', + 'narrow-minded', + 'nasal', + 'nasty', + 'national', + 'native', + 'natural', + 'naughty', + 'nauseating', + 'nauseous', + 'nautical', + 'navigable', + 'navy-blue', + 'near', + 'nearby', + 'nearest', + 'nearsighted', + 'neat', + 'nebulous', + 'necessary', + 'needless', + 'needy', + 'nefarious', + 'negative', + 'neglected', + 'neglectful', + 'negligent', + 'negligible', + 'negotiable', + 'neighborly', + 'neither', + 'nerve-racking', + 'nervous', + 'neurological', + 'neurotic', + 'neutral', + 'new', + 'newest', + 'next', + 'next-door', + 'nice', + 'nifty', + 'nightmarish', + 'nimble', + 'nine', + 'ninth', + 'nippy', + 'no', + 'noble', + 'nocturnal', + 'noiseless', + 'noisy', + 'nominal', + 'nonabrasive', + 'nonaggressive', + 'nonchalant', + 'noncommittal', + 'noncompetitive', + 'nonconsecutive', + 'nondescript', + 'nondestructive', + 'nonexclusive', + 'nonnegotiable', + 'nonproductive', + 'nonrefundable', + 'nonrenewable', + 'nonresponsive', + 'nonrestrictive', + 'nonreturnable', + 'nonsensical', + 'nonspecific', + 'nonstop', + 'nontransferable', + 'nonverbal', + 'nonviolent', + 'normal', + 'north', + 'northeast', + 'northerly', + 'northwest', + 'nostalgic', + 'nosy', + 'notable', + 'noticeable', + 'notorious', + 'novel', + 'noxious', + 'null', + 'numb', + 'numberless', + 'numbing', + 'numerable', + 'numeric', + 'numerous', + 'nutritional', + 'nutritious', + 'nutty', + 'oafish', + 'obedient', + 'obeisant', + 'obese', + 'objectionable', + 'objective', + 'obligatory', + 'obliging', + 'oblique', + 'oblivious', + 'oblong', + 'obnoxious', + 'obscene', + 'obscure', + 'observable', + 'observant', + 'obsessive', + 'obsolete', + 'obstinate', + 'obstructive', + 'obtainable', + 'obtrusive', + 'obtuse', + 'obvious', + 'occasional', + 'occupational', + 'occupied', + 'oceanic', + 'odd', + 'odd-looking', + 'odiferous', + 'odious', + 'odorless', + 'odorous', + 'offbeat', + 'offensive', + 'offhanded', + 'official', + 'officious', + 'oily', + 'OK', + 'okay', + 'old', + 'older', + 'oldest', + 'old-fashioned', + 'ominous', + 'omniscient', + 'omnivorous', + 'one', + 'one-hour', + 'onerous', + 'one-sided', + 'only', + 'opaque', + 'open', + 'opened', + 'openhanded', + 'openhearted', + 'opening', + 'open-minded', + 'operable', + 'operatic', + 'operational', + 'operative', + 'opinionated', + 'opportune', + 'opportunistic', + 'opposable', + 'opposed', + 'opposing', + 'opposite', + 'oppressive', + 'optimal', + 'optimistic', + 'optional', + 'opulent', + 'oral', + 'orange', + 'ordinary', + 'organic', + 'organizational', + 'original', + 'ornamental', + 'ornate', + 'ornery', + 'orphaned', + 'orthopedic', + 'ossified', + 'ostentatious', + 'other', + 'otherwise', + 'our', + 'outer', + 'outermost', + 'outgoing', + 'outlandish', + 'outraged', + 'outrageous', + 'outside', + 'outspoken', + 'outstanding', + 'outward', + 'oval', + 'overactive', + 'overaggressive', + 'overall', + 'overambitious', + 'overassertive', + 'overbearing', + 'overcast', + 'overcautious', + 'overconfident', + 'overcritical', + 'overcrowded', + 'overemotional', + 'overenthusiastic', + 'overjoyed', + 'overoptimistic', + 'overpowering', + 'overpriced', + 'overprotective', + 'overqualified', + 'overrated', + 'oversensitive', + 'oversized', + 'overt', + 'overwhelmed', + 'overwhelming', + 'overworked', + 'overwrought', + 'overzealous', + 'own', + 'oxymoronic', + 'padded', + 'painful', + 'painless', + 'painstaking', + 'palatable', + 'palatial', + 'pale', + 'pallid', + 'palpable', + 'paltry', + 'pampered', + 'panicky', + 'panoramic', + 'paradoxical', + 'parallel', + 'paranormal', + 'parasitic', + 'parched', + 'pardonable', + 'parental', + 'parenthetic', + 'parking', + 'parsimonious', + 'partial', + 'particular', + 'partisan', + 'part-time', + 'party', + 'passing', + 'passionate', + 'passive', + 'past', + 'pastoral', + 'patched', + 'patchy', + 'patented', + 'paternal', + 'paternalistic', + 'pathetic', + 'pathological', + 'patient', + 'patriotic', + 'patronizing', + 'patterned', + 'payable', + 'peaceable', + 'peaceful', + 'peculiar', + 'pedantic', + 'pedestrian', + 'peerless', + 'peeved', + 'peevish', + 'penetrable', + 'penetrating', + 'pensive', + 'peppery', + 'perceivable', + 'perceptible', + 'perceptive', + 'perceptual', + 'peremptory', + 'perennial', + 'perfect', + 'perfumed', + 'perilous', + 'period', + 'periodic', + 'peripheral', + 'perishable', + 'perky', + 'permanent', + 'permeable', + 'permissible', + 'permissive', + 'pernicious', + 'perpendicular', + 'perpetual', + 'perplexed', + 'perplexing', + 'persevering', + 'persistent', + 'personable', + 'personal', + 'persuasive', + 'pert', + 'pertinent', + 'perturbed', + 'perturbing', + 'pervasive', + 'perverse', + 'pessimistic', + 'petite', + 'pettish', + 'petty', + 'petulant', + 'pharmaceutical', + 'phenomenal', + 'philanthropic', + 'philosophical', + 'phobic', + 'phonemic', + 'phonetic', + 'phosphorescent', + 'photographic', + 'physical', + 'physiological', + 'picturesque', + 'piercing', + 'pigheaded', + 'pink', + 'pious', + 'piquant', + 'pitch-dark', + 'pitch-perfect', + 'piteous', + 'pithy', + 'pitiful', + 'pitiless', + 'pivotal', + 'placid', + 'plaid', + 'plain', + 'plane', + 'planned', + 'plastic', + 'platonic', + 'plausible', + 'playful', + 'pleading', + 'pleasant', + 'pleased', + 'pleasing', + 'pleasurable', + 'plentiful', + 'pliable', + 'plodding', + 'plopping', + 'plucky', + 'plump', + 'pluralistic', + 'plus', + 'plush', + 'pneumatic', + 'poetic', + 'poignant', + 'pointless', + 'poised', + 'poisonous', + 'polished', + 'polite', + 'political', + 'polka-dotted', + 'polluted', + 'polyunsaturated', + 'pompous', + 'ponderous', + 'poor', + 'poorer', + 'poorest', + 'popping', + 'popular', + 'populous', + 'porous', + 'portable', + 'portly', + 'positive', + 'possessive', + 'possible', + 'posthoc', + 'posthumous', + 'postoperative', + 'potable', + 'potent', + 'potential', + 'powdery', + 'powerful', + 'powerless', + 'practical', + 'pragmatic', + 'praiseworthy', + 'precarious', + 'precious', + 'precipitous', + 'precise', + 'precocious', + 'preconceived', + 'predicative', + 'predictable', + 'predisposed', + 'predominant', + 'preeminent', + 'preemptive', + 'prefabricated', + 'preferable', + 'preferential', + 'pregnant', + 'prehistoric', + 'prejudiced', + 'prejudicial', + 'preliminary', + 'premature', + 'premeditated', + 'premium', + 'prenatal', + 'preoccupied', + 'preoperative', + 'preparative', + 'prepared', + 'preposterous', + 'prescriptive', + 'present', + 'presentable', + 'presidential', + 'pressing', + 'pressurized', + 'prestigious', + 'presumable', + 'presumptive', + 'presumptuous', + 'pretend', + 'pretentious', + 'pretty', + 'prevalent', + 'preventable', + 'preventative', + 'preventive', + 'previous', + 'priceless', + 'pricey', + 'prickly', + 'prim', + 'primary', + 'primitive', + 'primordial', + 'princely', + 'principal', + 'principled', + 'prior', + 'prissy', + 'pristine', + 'private', + 'prize', + 'prized', + 'proactive', + 'probabilistic', + 'probable', + 'problematic', + 'procedural', + 'prodigious', + 'productive', + 'profane', + 'professed', + 'professional', + 'professorial', + 'proficient', + 'profitable', + 'profound', + 'profuse', + 'programmable', + 'progressive', + 'prohibitive', + 'prolific', + 'prominent', + 'promised', + 'promising', + 'prompt', + 'pronounceable', + 'pronounced', + 'proof', + 'proper', + 'prophetic', + 'proportional', + 'proportionate', + 'proportioned', + 'prospective', + 'prosperous', + 'protective', + 'prototypical', + 'proud', + 'proverbial', + 'provisional', + 'provocative', + 'provoking', + 'proximal', + 'proximate', + 'prudent', + 'prudential', + 'prying', + 'psychedelic', + 'psychiatric', + 'psychological', + 'psychosomatic', + 'psychotic', + 'public', + 'puckish', + 'puffy', + 'pugnacious', + 'pumped', + 'punctual', + 'pungent', + 'punishable', + 'punitive', + 'puny', + 'pure', + 'purified', + 'puritanical', + 'purple', + 'purported', + 'purposeful', + 'purposeless', + 'purring', + 'pushy', + 'pusillanimous', + 'putrid', + 'puzzled', + 'puzzling', + 'pyrotechnic', + 'quackish', + 'quacky', + 'quaint', + 'qualified', + 'qualitative', + 'quality', + 'quantifiable', + 'quantitative', + 'quarrelsome', + 'queasy', + 'queenly', + 'querulous', + 'questionable', + 'quick', + 'quick-acting', + 'quick-drying', + 'quickest', + 'quick-minded', + 'quick-paced', + 'quick-tempered', + 'quick-thinking', + 'quick-witted', + 'quiet', + 'quintessential', + 'quirky', + 'quivering', + 'quizzical', + 'quotable', + 'rabid', + 'racial', + 'racist', + 'radiant', + 'radical', + 'radioactive', + 'ragged', + 'raging', + 'rainbowcolored', + 'rainy', + 'rakish', + 'rambling', + 'rambunctious', + 'rampageous', + 'rampant', + 'rancid', + 'rancorous', + 'random', + 'rank', + 'rapid', + 'rapid-fire', + 'rapturous', + 'rare', + 'rascally', + 'rash', + 'rasping', + 'raspy', + 'rational', + 'ratty', + 'ravenous', + 'raving', + 'ravishing', + 'raw', + 'razor-edged', + 'reactive', + 'ready', + 'real', + 'realistic', + 'reasonable', + 'reassured', + 'reassuring', + 'rebel', + 'rebellious', + 'receding', + 'recent', + 'receptive', + 'recessive', + 'rechargeable', + 'reciprocal', + 'reckless', + 'reclusive', + 'recognizable', + 'recognized', + 'rectangular', + 'rectifiable', + 'recurrent', + 'recyclable', + 'red', + 'red-blooded', + 'reddish', + 'redeemable', + 'redolent', + 'redundant', + 'referential', + 'refillable', + 'reflective', + 'refractive', + 'refreshing', + 'refundable', + 'refurbished', + 'refutable', + 'regal', + 'regional', + 'regretful', + 'regrettable', + 'regular', + 'reigning', + 'relatable', + 'relative', + 'relaxed', + 'relaxing', + 'relentless', + 'relevant', + 'reliable', + 'relieved', + 'religious', + 'reluctant', + 'remaining', + 'remarkable', + 'remedial', + 'reminiscent', + 'remorseful', + 'remorseless', + 'remote', + 'removable', + 'renegotiable', + 'renewable', + 'rented', + 'repairable', + 'repaired', + 'repeatable', + 'repeated', + 'repentant', + 'repetitious', + 'repetitive', + 'replaceable', + 'replicable', + 'reported', + 'reprehensible', + 'representative', + 'repressive', + 'reproachful', + 'reproductive', + 'republican', + 'repugnant', + 'repulsive', + 'reputable', + 'reputed', + 'rescued', + 'resealable', + 'resentful', + 'reserved', + 'resident', + 'residential', + 'residual', + 'resilient', + 'resolute', + 'resolvable', + 'resonant', + 'resounding', + 'resourceful', + 'respectable', + 'respectful', + 'respective', + 'responsible', + 'responsive', + 'rested', + 'restful', + 'restless', + 'restored', + 'restrained', + 'restrictive', + 'retired', + 'retroactive', + 'retrogressive', + 'retrospective', + 'reusable', + 'revamped', + 'revealing', + 'revengeful', + 'reverent', + 'reverential', + 'reverse', + 'reversible', + 'reviewable', + 'reviled', + 'revisable', + 'revised', + 'revocable', + 'revolting', + 'revolutionary', + 'rewarding', + 'rhetorical', + 'rhythmic', + 'rich', + 'richer', + 'richest', + 'ridiculing', + 'ridiculous', + 'right', + 'righteous', + 'rightful', + 'right-handed', + 'rigid', + 'rigorous', + 'ringing', + 'riotous', + 'ripe', + 'rippling', + 'risky', + 'ritualistic', + 'ritzy', + 'riveting', + 'roaring', + 'roasted', + 'robotic', + 'robust', + 'rocketing', + 'roguish', + 'romantic', + 'roomy', + 'rosy', + 'rotating', + 'rotten', + 'rotting', + 'rotund', + 'rough', + 'round', + 'roundtable', + 'rousing', + 'routine', + 'rowdy', + 'royal', + 'ruddy', + 'rude', + 'rudimentary', + 'rueful', + 'rugged', + 'ruined', + 'ruinous', + 'rumbling', + 'rumpled', + 'ruptured', + 'rural', + 'rusted', + 'rustic', + 'rustling', + 'rusty', + 'ruthless', + 'rutted', + 'saccharin', + 'sacred', + 'sacrificial', + 'sacrilegious', + 'sad', + 'saddened', + 'safe', + 'saintly', + 'salacious', + 'salient', + 'salt', + 'salted', + 'salty', + 'salvageable', + 'salvaged', + 'same', + 'sanctimonious', + 'sandy', + 'sane', + 'sanguine', + 'sanitary', + 'sappy', + 'sarcastic', + 'sardonic', + 'sassy', + 'satin', + 'satiny', + 'satiric', + 'satirical', + 'satisfactory', + 'satisfied', + 'satisfying', + 'saucy', + 'savage', + 'savory', + 'savvy', + 'scalding', + 'scaly', + 'scandalous', + 'scant', + 'scanty', + 'scarce', + 'scared', + 'scarred', + 'scary', + 'scathing', + 'scattered', + 'scenic', + 'scented', + 'scheduled', + 'schematic', + 'scholarly', + 'scholastic', + 'scientific', + 'scintillating', + 'scorching', + 'scornful', + 'scrabbled', + 'scraggly', + 'scrappy', + 'scratched', + 'scratchy', + 'scrawny', + 'screaming', + 'screeching', + 'scribbled', + 'scriptural', + 'scruffy', + 'scrumptious', + 'scrupulous', + 'sculpted', + 'sculptural', + 'scummy', + 'sea', + 'sealed', + 'seamless', + 'searching', + 'searing', + 'seasick', + 'seasonable', + 'seasonal', + 'secluded', + 'second', + 'secondary', + 'second-hand', + 'secret', + 'secretive', + 'secular', + 'secure', + 'secured', + 'sedate', + 'seditious', + 'seductive', + 'seedy', + 'seeming', + 'seemly', + 'seething', + 'seismic', + 'select', + 'selected', + 'selective', + 'self-absorbed', + 'self-aggrandizing', + 'self-assured', + 'self-centered', + 'self-confident', + 'self-directed', + 'self-disciplined', + 'self-effacing', + 'self-indulgent', + 'self-interested', + 'selfish', + 'selfless', + 'self-reliant', + 'self-respect', + 'self-satisfied', + 'sellable', + 'semiconscious', + 'semiofficial', + 'semiprecious', + 'semiprofessional', + 'senior', + 'sensational', + 'senseless', + 'sensible', + 'sensitive', + 'sensual', + 'sensuous', + 'sentimental', + 'separate', + 'sequential', + 'serendipitous', + 'serene', + 'serial', + 'serious', + 'serrated', + 'serviceable', + 'seven', + 'seventh', + 'several', + 'severe', + 'shabbiest', + 'shabby', + 'shaded', + 'shadowed', + 'shadowy', + 'shady', + 'shaggy', + 'shaky', + 'shallow', + 'shamefaced', + 'shameful', + 'shameless', + 'shapeless', + 'shapely', + 'sharp', + 'sharpened', + 'shattered', + 'shattering', + 'sheepish', + 'sheer', + 'sheltered', + 'shifty', + 'shimmering', + 'shining', + 'shiny', + 'shivering', + 'shivery', + 'shocked', + 'shocking', + 'shoddy', + 'short', + 'short-lived', + 'shortsighted', + 'short-tempered', + 'short-term', + 'showy', + 'shrewd', + 'shrieking', + 'shrill', + 'shut', + 'shy', + 'sick', + 'sickened', + 'sickening', + 'sickly', + 'side-splitting', + 'signed', + 'significant', + 'silent', + 'silky', + 'silly', + 'silver', + 'silver-tongued', + 'simian', + 'similar', + 'simple', + 'simpleminded', + 'simplified', + 'simplistic', + 'simultaneous', + 'sincere', + 'sinful', + 'single', + 'single-minded', + 'singular', + 'sinister', + 'sinuous', + 'sisterly', + 'six', + 'sixth', + 'sizable', + 'sizzling', + 'skeptical', + 'sketchy', + 'skilled', + 'skillful', + 'skimpy', + 'skin-deep', + 'skinny', + 'skittish', + 'sky-blue', + 'slanderous', + 'slanted', + 'slanting', + 'sleek', + 'sleeping', + 'sleepless', + 'sleepy', + 'slender', + 'slick', + 'slight', + 'slim', + 'slimy', + 'slippery', + 'sloped', + 'sloping', + 'sloppy', + 'slothful', + 'slow', + 'slow-moving', + 'sluggish', + 'slushy', + 'sly', + 'small', + 'smaller', + 'smallest', + 'small-minded', + 'small-scale', + 'small-time', + 'small-town', + 'smarmy', + 'smart', + 'smarter', + 'smartest', + 'smashing', + 'smeared', + 'smelly', + 'smiling', + 'smoggy', + 'smoked', + 'smoky', + 'smooth', + 'smothering', + 'smudged', + 'smug', + 'snapping', + 'snappish', + 'snappy', + 'snarling', + 'sneaky', + 'snide', + 'snippy', + 'snobbish', + 'snoopy', + 'snooty', + 'snoring', + 'snotty', + 'snow-white', + 'snug', + 'snuggly', + 'soaked', + 'soaking', + 'soakingwet', + 'soaring', + 'sober', + 'sociable', + 'social', + 'socialist', + 'sociological', + 'soft', + 'softhearted', + 'soggy', + 'solar', + 'soldierly', + 'sole', + 'solemn', + 'solicitous', + 'solid', + 'solitary', + 'somatic', + 'somber', + 'some,', + 'sonic', + 'sonly', + 'soothed', + 'soothing', + 'sophisticated', + 'sordid', + 'sore', + 'sorrowful', + 'sorry', + 'soulful', + 'soulless', + 'soundless', + 'sour', + 'south', + 'southeasterly', + 'southern', + 'southwestern', + 'spacious', + 'spare', + 'sparing', + 'sparkling', + 'sparkly', + 'sparse', + 'spasmodic', + 'spastic', + 'spatial', + 'spattered', + 'special', + 'specialist', + 'specialized', + 'specific', + 'speckled', + 'spectacular', + 'spectral', + 'speculative', + 'speechless', + 'speedy', + 'spellbinding', + 'spendthrift', + 'spherical', + 'spicy', + 'spiffy', + 'spiky', + 'spinal', + 'spineless', + 'spiral', + 'spiraled', + 'spirited', + 'spiritless', + 'spiritual', + 'spiteful', + 'splashing', + 'splashy', + 'splattered', + 'splendid', + 'splintered', + 'spoiled', + 'spoken', + 'spongy', + 'spontaneous', + 'spooky', + 'sporadic', + 'sporting', + 'sportsmanly', + 'spotless', + 'spotted', + 'spotty', + 'springy', + 'sprite', + 'spry', + 'spurious', + 'squalid', + 'squandered', + 'square', + 'squashed', + 'squashy', + 'squatting', + 'squawking', + 'squealing', + 'squeamish', + 'squeezable', + 'squiggly', + 'squirming', + 'squirrelly', + 'stable', + 'stackable', + 'stacked', + 'staggering', + 'stagnant', + 'stained', + 'stale', + 'stanch', + 'standard', + 'standing', + 'standoffish', + 'starched', + 'star-crossed', + 'stark', + 'startled', + 'startling', + 'starving', + 'stately', + 'static', + 'statistical', + 'statuesque', + 'status', + 'statutory', + 'staunch', + 'steadfast', + 'steady', + 'stealth', + 'steaming', + 'steamy', + 'steel', + 'steely', + 'steep', + 'stereophonic', + 'stereotyped', + 'stereotypical', + 'sterile', + 'stern', + 'sticky', + 'stiff', + 'stifled', + 'stifling', + 'stigmatic', + 'still', + 'stilled', + 'stilted', + 'stimulating', + 'stinging', + 'stingy', + 'stinking', + 'stinky', + 'stirring', + 'stock', + 'stodgy', + 'stoic', + 'stony', + 'stormy', + 'stout', + 'straggly', + 'straight', + 'straightforward', + 'stranded', + 'strange', + 'strategic', + 'streaked', + 'street', + 'strenuous', + 'stressful', + 'stretchy', + 'strict', + 'strident', + 'striking', + 'stringent', + 'striped', + 'strong', + 'stronger', + 'strongest', + 'structural', + 'stubborn', + 'stubby', + 'stuck-up', + 'studied', + 'studious', + 'stuffed', + 'stuffy', + 'stumbling', + 'stunned', + 'stunning', + 'stupendous', + 'sturdy', + 'stuttering', + 'stylish', + 'stylistic', + 'suave', + 'subconscious', + 'subdued', + 'subject', + 'subjective', + 'sublime', + 'subliminal', + 'submissive', + 'subordinate', + 'subsequent', + 'subservient', + 'substantial', + 'substantiated', + 'substitute', + 'subterranean', + 'subtitled', + 'subtle', + 'subversive', + 'successful', + 'successive', + 'succinct', + 'succulent', + 'such', + 'sudden', + 'suffering', + 'sufficient', + 'sugary', + 'suggestive', + 'suitable', + 'sulky', + 'sullen', + 'sumptuous', + 'sunny', + 'super', + 'superabundant', + 'superb', + 'supercilious', + 'superficial', + 'superhuman', + 'superior', + 'superlative', + 'supernatural', + 'supersensitive', + 'supersonic', + 'superstitious', + 'supple', + 'supportive', + 'supposed', + 'suppressive', + 'supreme', + 'sure', + 'sure-footed', + 'surgical', + 'surly', + 'surmountable', + 'surprised', + 'surprising', + 'surrealistic', + 'survivable', + 'susceptible', + 'suspected', + 'suspicious', + 'sustainable', + 'swaggering', + 'swanky', + 'swaying', + 'sweaty', + 'sweeping', + 'sweet', + 'sweltering', + 'swift', + 'swimming', + 'swinish', + 'swishing', + 'swollen', + 'swooping', + 'syllabic', + 'syllogistic', + 'symbiotic', + 'symbolic', + 'symmetrical', + 'sympathetic', + 'symptomatic', + 'synergistic', + 'synonymous', + 'syntactic', + 'synthetic', + 'systematic', + 'taboo', + 'tacit', + 'tacky', + 'tactful', + 'tactical', + 'tactless', + 'tactual', + 'tainted', + 'take-charge', + 'talented', + 'talkative', + 'tall', + 'taller', + 'tallest', + 'tame', + 'tamed', + 'tan', + 'tangential', + 'tangible', + 'tangled', + 'tangy', + 'tanned', + 'tantalizing', + 'tapered', + 'tardy', + 'targeted', + 'tarnished', + 'tart', + 'tasteful', + 'tasteless', + 'tasty', + 'tattered', + 'taunting', + 'taut', + 'taxing', + 'teachable', + 'tearful', + 'tearing', + 'teasing', + 'technical', + 'technological', + 'tectonic', + 'tedious', + 'teenage', + 'teensy', + 'teeny', + 'teeny-tiny', + 'telegraphic', + 'telekinetic', + 'telepathic', + 'telephonic', + 'telescopic', + 'telling', + 'temperamental', + 'temperate', + 'tempestuous', + 'temporary', + 'tempted', + 'tempting', + 'ten', + 'tenable', + 'tenacious', + 'tender', + 'tenderhearted', + 'ten-minute', + 'tense', + 'tentative', + 'tenth', + 'tenuous', + 'tepid', + 'terminal', + 'terrestrial', + 'terrible', + 'terrific', + 'terrified', + 'terrifying', + 'territorial', + 'terse', + 'tested', + 'testy', + 'tetchy', + 'textual', + 'textural', + 'thankful', + 'thankless', + 'that', + 'the', + 'theatrical', + 'their', + 'thematic', + 'theological', + 'theoretical', + 'therapeutic', + 'thermal', + 'these', + 'thick', + 'thievish', + 'thin', + 'thinkable', + 'third', + 'thirsty', + 'this', + 'thorny', + 'thorough', + 'those', + 'thoughtful', + 'thoughtless', + 'thrashed', + 'threatened', + 'threatening', + 'three', + 'thriftless', + 'thrifty', + 'thrilled', + 'thrilling', + 'throbbing', + 'thumping', + 'thundering', + 'thunderous', + 'ticking', + 'tickling', + 'ticklish', + 'tidal', + 'tidy', + 'tight', + 'tightfisted', + 'time', + 'timeless', + 'timely', + 'timid', + 'timorous', + 'tiny', + 'tipsy', + 'tired', + 'tireless', + 'tiresome', + 'tiring', + 'tolerable', + 'tolerant', + 'tonal', + 'tone-deaf', + 'toneless', + 'toothsome', + 'toothy', + 'top', + 'topical', + 'topographical', + 'tormented', + 'torpid', + 'torrential', + 'torrid', + 'torturous', + 'total', + 'touched', + 'touching', + 'touchy', + 'tough', + 'towering', + 'toxic', + 'traditional', + 'tragic', + 'trainable', + 'trained', + 'training', + 'traitorous', + 'tranquil', + 'transcendent', + 'transcendental', + 'transformational', + 'transformative', + 'transformed', + 'transient', + 'transitional', + 'transitory', + 'translucent', + 'transparent', + 'transplanted', + 'trapped', + 'trashed', + 'trashy', + 'traumatic', + 'treacherous', + 'treasonable', + 'treasonous', + 'treasured', + 'treatable', + 'tremendous', + 'tremulous', + 'trenchant', + 'trendy', + 'triangular', + 'tribal', + 'trick', + 'tricky', + 'trim', + 'tripping', + 'trite', + 'triumphant', + 'trivial', + 'tropical', + 'troubled', + 'troublesome', + 'troubling', + 'truculent', + 'true', + 'trusted', + 'trustful', + 'trusting', + 'trustworthy', + 'trusty', + 'truthful', + 'trying', + 'tumultuous', + 'tuneful', + 'tuneless', + 'turbulent', + 'twinkling', + 'twinkly', + 'twisted', + 'twitchy', + 'two', + 'typical', + 'tyrannical', + 'tyrannous', + 'ubiquitous', + 'ugly', + 'ultimate', + 'ultraconservative', + 'ultrasensitive', + 'ultrasonic', + 'ultraviolet', + 'unabashed', + 'unabated', + 'unable', + 'unacceptable', + 'unaccompanied', + 'unaccountable', + 'unaccustomed', + 'unacknowledged', + 'unadorned', + 'unadulterated', + 'unadventurous', + 'unadvised', + 'unaffected', + 'unaffordable', + 'unafraid', + 'unaggressive', + 'unaided', + 'unalienable', + 'unalterable', + 'unaltered', + 'unambiguous', + 'unanimous', + 'unannounced', + 'unanswerable', + 'unanticipated', + 'unapologetic', + 'unappealing', + 'unappetizing', + 'unappreciative', + 'unapproachable', + 'unashamed', + 'unassailable', + 'unassertive', + 'unassisted', + 'unattached', + 'unattainable', + 'unattractive', + 'unauthorized', + 'unavailable', + 'unavailing', + 'unavoidable', + 'unbalanced', + 'unbearable', + 'unbeatable', + 'unbeaten', + 'unbecoming', + 'unbelievable', + 'unbelieving', + 'unbendable', + 'unbending', + 'unbiased', + 'unblemished', + 'unblinking', + 'unblushing', + 'unbounded', + 'unbreakable', + 'unbridled', + 'uncanny', + 'uncaring', + 'unceasing', + 'unceremonious', + 'uncertain', + 'unchangeable', + 'unchanging', + 'uncharacteristic', + 'uncharitable', + 'uncharted', + 'uncivil', + 'uncivilized', + 'unclassified', + 'unclean', + 'uncluttered', + 'uncomely', + 'uncomfortable', + 'uncommitted', + 'uncommon', + 'uncommunicative', + 'uncomplaining', + 'uncomprehending', + 'uncompromising', + 'unconcerned', + 'unconditional', + 'unconfirmed', + 'unconquerable', + 'unconscionable', + 'unconscious', + 'unconstitutional', + 'unconstrained', + 'unconstructive', + 'uncontainable', + 'uncontrollable', + 'unconventional', + 'unconvinced', + 'unconvincing', + 'uncooked', + 'uncooperative', + 'uncoordinated', + 'uncouth', + 'uncovered', + 'uncreative', + 'uncritical', + 'undamaged', + 'undated', + 'undaunted', + 'undeclared', + 'undefeated', + 'undefined', + 'undemocratic', + 'undeniable', + 'undependable', + 'underdeveloped', + 'underfunded', + 'underhanded', + 'underprivileged', + 'understandable', + 'understanding', + 'understated', + 'understood', + 'undeserved', + 'undesirable', + 'undetected', + 'undeterred', + 'undeveloped', + 'undeviating', + 'undifferentiated', + 'undignified', + 'undiminished', + 'undiplomatic', + 'undisciplined', + 'undiscovered', + 'undisguised', + 'undisputed', + 'undistinguished', + 'undivided', + 'undoubted', + 'unearthly', + 'uneasy', + 'uneducated', + 'unemotional', + 'unemployed', + 'unencumbered', + 'unending', + 'unendurable', + 'unenforceable', + 'unenthusiastic', + 'unenviable', + 'unequal', + 'unequaled', + 'unequivocal', + 'unerring', + 'uneven', + 'uneventful', + 'unexceptional', + 'unexcited', + 'unexpected', + 'unexplainable', + 'unexplored', + 'unexpressive', + 'unfailing', + 'unfair', + 'unfaithful', + 'unfaltering', + 'unfamiliar', + 'unfashionable', + 'unfathomable', + 'unfavorable', + 'unfeeling', + 'unfettered', + 'unfilled', + 'unflagging', + 'unflappable', + 'unflattering', + 'unflinching', + 'unfocused', + 'unforeseeable', + 'unforgettable', + 'unforgivable', + 'unforgiving', + 'unfortunate', + 'unfriendly', + 'unfulfilled', + 'ungallant', + 'ungenerous', + 'ungentlemanly', + 'unglamorous', + 'ungraceful', + 'ungracious', + 'ungrateful', + 'unguarded', + 'unhandsome', + 'unhappy', + 'unharmed', + 'unhealthy', + 'unheated', + 'unheeded', + 'unhelpful', + 'unhesitating', + 'unhurried', + 'uniform', + 'unilateral', + 'unimaginable', + 'unimaginative', + 'unimpeachable', + 'unimpeded', + 'unimpressive', + 'unincorporated', + 'uninformed', + 'uninhabitable', + 'uninhibited', + 'uninitiated', + 'uninjured', + 'uninspired', + 'uninsurable', + 'unintelligent', + 'unintelligible', + 'unintended', + 'unintentional', + 'uninterested', + 'uninterrupted', + 'uninvited', + 'unique', + 'united', + 'universal', + 'unjust', + 'unjustifiable', + 'unkempt', + 'unkind', + 'unknowing', + 'unknown', + 'unlawful', + 'unlicensed', + 'unlikable', + 'unlikely', + 'unlivable', + 'unloved', + 'unlucky', + 'unmanageable', + 'unmanly', + 'unmanned', + 'unmarketable', + 'unmasked', + 'unmatched', + 'unmemorable', + 'unmentionable', + 'unmerciful', + 'unmistakable', + 'unmitigated', + 'unmodified', + 'unmotivated', + 'unnatural', + 'unnecessary', + 'unnerved', + 'unnerving', + 'unnoticeable', + 'unobserved', + 'unobtainable', + 'unobtrusive', + 'unofficial', + 'unopened', + 'unopposed', + 'unorthodox', + 'unostentatious', + 'unpalatable', + 'unpardonable', + 'unpersuasive', + 'unperturbed', + 'unplanned', + 'unpleasant', + 'unprecedented', + 'unpredictable', + 'unpretentious', + 'unprincipled', + 'unproductive', + 'unprofessional', + 'unprofitable', + 'unpromising', + 'unpronounceable', + 'unprovoked', + 'unqualified', + 'unquantifiable', + 'unquenchable', + 'unquestionable', + 'unquestioned', + 'unquestioning', + 'unraveled', + 'unreachable', + 'unreadable', + 'unrealistic', + 'unrealized', + 'unreasonable', + 'unreceptive', + 'unrecognizable', + 'unrecognized', + 'unredeemable', + 'unregulated', + 'unrelenting', + 'unreliable', + 'unremarkable', + 'unremitting', + 'unrepentant', + 'unrepresentative', + 'unrepresented', + 'unreserved', + 'unrespectable', + 'unresponsive', + 'unrestrained', + 'unripe', + 'unrivaled', + 'unromantic', + 'unruffled', + 'unruly', + 'unsafe', + 'unsalvageable', + 'unsatisfactory', + 'unsatisfied', + 'unscheduled', + 'unscholarly', + 'unscientific', + 'unscrupulous', + 'unseasonable', + 'unseemly', + 'unselfish', + 'unsettled', + 'unsettling', + 'unshakable', + 'unshapely', + 'unsightly', + 'unsigned', + 'unsinkable', + 'unskilled', + 'unsociable', + 'unsolicited', + 'unsolvable', + 'unsolved', + 'unsophisticated', + 'unsound', + 'unsparing', + 'unspeakable', + 'unspoiled', + 'unstable', + 'unstated', + 'unsteady', + 'unstoppable', + 'unstressed', + 'unstructured', + 'unsubstantial', + 'unsubstantiated', + 'unsuccessful', + 'unsuitable', + 'unsuited', + 'unsupervised', + 'unsupported', + 'unsure', + 'unsurpassable', + 'unsurpassed', + 'unsurprising', + 'unsuspected', + 'unsuspecting', + 'unsustainable', + 'unsympathetic', + 'unsystematic', + 'untainted', + 'untamable', + 'untamed', + 'untapped', + 'untenable', + 'untested', + 'unthinkable', + 'unthinking', + 'untidy', + 'untimely', + 'untitled', + 'untouchable', + 'untraditional', + 'untrained', + 'untried', + 'untroubled', + 'untrustworthy', + 'untruthful', + 'unused', + 'unusual', + 'unverified', + 'unwary', + 'unwashed', + 'unwatchable', + 'unwavering', + 'unwholesome', + 'unwieldy', + 'unwilling', + 'unwise', + 'unwitting', + 'unworkable', + 'unworldly', + 'unworthy', + 'unwritten', + 'unyielding', + 'upbeat', + 'upmost', + 'upper', + 'uppity', + 'upright', + 'uproarious', + 'upset', + 'upsetting', + 'upstairs', + 'uptight', + 'up-to-date', + 'up-to-the-minute', + 'upward', + 'urbane', + 'urgent', + 'usable', + 'used', + 'useful', + 'useless', + 'usual', + 'utilitarian', + 'utopian', + 'utter', + 'uttermost', + 'vacant', + 'vacillating', + 'vacuous', + 'vagabond', + 'vagrant', + 'vague', + 'vain', + 'valiant', + 'valid', + 'valorous', + 'valuable', + 'vanishing', + 'vapid', + 'vaporous', + 'variable', + 'varied', + 'various', + 'varying', + 'vast', + 'vegetable', + 'vegetarian', + 'vegetative', + 'vehement', + 'velvety', + 'venal', + 'venerable', + 'vengeful', + 'venomous', + 'venturesome', + 'venturous', + 'veracious', + 'verbal', + 'verbose', + 'verdant', + 'verifiable', + 'verified', + 'veritable', + 'vernacular', + 'versatile', + 'versed', + 'vertical', + 'very', + 'vexed', + 'vexing', + 'viable', + 'vibrant', + 'vibrating', + 'vicarious', + 'vicious', + 'victorious', + 'vigilant', + 'vigorous', + 'vile', + 'villainous', + 'vindictive', + 'vinegary', + 'violent', + 'violet', + 'viperous', + 'viral', + 'virtual', + 'virtuous', + 'virulent', + 'visceral', + 'viscous', + 'visible', + 'visionary', + 'visual', + 'vital', + 'vitriolic', + 'vivacious', + 'vivid', + 'vocal', + 'vocational', + 'voiceless', + 'volatile', + 'volcanic', + 'voluminous', + 'voluntary', + 'voluptuous', + 'voracious', + 'vulgar', + 'vulnerable', + 'wacky', + 'wailing', + 'waiting', + 'wakeful', + 'wandering', + 'wanting', + 'wanton', + 'warlike', + 'warm', + 'warmest', + 'warning', + 'warring', + 'wary', + 'waspish', + 'waste', + 'wasted', + 'wasteful', + 'watchful', + 'waterlogged', + 'waterproof', + 'watertight', + 'watery', + 'wavering', + 'wax', + 'waxen', + 'weak', + 'weakened', + 'weak-willed', + 'wealthy', + 'wearisome', + 'weary', + 'wee', + 'weedy', + 'week-long', + 'weekly', + 'weightless', + 'weighty', + 'weird', + 'welcoming', + 'well', + 'well-adjusted', + 'well-argued', + 'well-aware', + 'well-balanced', + 'well-behaved', + 'well-built', + 'well-conceived', + 'well-considered', + 'well-crafted', + 'well-deserved', + 'well-developed', + 'well-done', + 'well-dressed', + 'well-educated', + 'well-equipped', + 'well-established', + 'well-founded', + 'well-groomed', + 'well-heeled', + 'well-honed', + 'well-informed', + 'well-intentioned', + 'well-kempt', + 'well-known', + 'well-liked', + 'well-lit', + 'well-made', + 'well-maintained', + 'well-mannered', + 'well-meaning', + 'well-off', + 'well-placed', + 'well-planned', + 'well-prepared', + 'well-qualified', + 'well-read', + 'well-received', + 'well-rounded', + 'well-spoken', + 'well-suited', + 'well-thought-of', + 'well-thought-out', + 'well-to-do', + 'well-traveled', + 'well-used', + 'well-versed', + 'well-worn', + 'well-written', + 'west', + 'western', + 'wet', + 'what', + 'wheezing', + 'which', + 'whimpering', + 'whimsical', + 'whining', + 'whispering', + 'whistling', + 'white', + 'whole', + 'wholehearted', + 'wholesale', + 'wholesome', + 'whooping', + 'whopping', + 'whose', + 'wicked', + 'wide', + 'wide-eyed', + 'wide-ranging', + 'widespread', + 'wiggly', + 'wild', + 'willful', + 'willing', + 'wily', + 'windy', + 'winning', + 'winsome', + 'winter', + 'wintery', + 'wiry', + 'wise', + 'wishful', + 'wispy', + 'wistful', + 'withering', + 'witless', + 'witty', + 'wizardly', + 'wobbly', + 'woeful', + 'wolfish', + 'wonderful', + 'wondrous', + 'wonted', + 'wood', + 'wooden', + 'wooing', + 'wool', + 'woolen', + 'woozy', + 'wordless', + 'wordy', + 'work', + 'workable', + 'working', + 'work-oriented', + 'worldly', + 'worn', + 'worndown', + 'wornout', + 'worried', + 'worrisome', + 'worrying', + 'worse', + 'worshipful', + 'worst', + 'worth', + 'worthless', + 'worthwhile', + 'worthy', + 'wounding', + 'wrathful', + 'wrenching', + 'wretched', + 'wriggling', + 'wriggly', + 'wrinkled', + 'wrinkly', + 'written', + 'wrong', + 'wrongful', + 'wry', + 'yawning', + 'yearly', + 'yearning', + 'yellow', + 'yelping', + 'yielding', + 'young', + 'younger', + 'youngest', + 'youthful', + 'yummy', + 'zany', + 'zealous', + 'zestful', + 'zesty', + 'zippy', + 'zonked', + 'zoological', +]; diff --git a/drizzle-seed/src/datasets/cityNames.ts b/drizzle-seed/src/datasets/cityNames.ts new file mode 100644 index 000000000..bcec411bb --- /dev/null +++ b/drizzle-seed/src/datasets/cityNames.ts @@ -0,0 +1,42986 @@ +export default [ + 'Tokyo', + 'Jakarta', + 'Delhi', + 'Guangzhou', + 'Mumbai', + 'Manila', + 'Shanghai', + 'Sao Paulo', + 'Seoul', + 'Mexico City', + 'Cairo', + 'New York', + 'Dhaka', + 'Beijing', + 'Kolkata', + 'Bangkok', + 'Shenzhen', + 'Buenos Aires', + 'Lagos', + 'Istanbul', + 'Karachi', + 'Bangalore', + 'Ho Chi Minh City', + 'Osaka', + 'Chengdu', + 'Tehran', + 'Kinshasa', + 'Rio de Janeiro', + 'Chennai', + "Xi'an", + 'Lahore', + 'Chongqing', + 'Los Angeles', + 'Baoding', + 'London', + 'Paris', + 'Linyi', + 'Dongguan', + 'Hyderabad', + 'Tianjin', + 'Lima', + 'Wuhan', + 'Nanyang', + 'Hangzhou', + 'Foshan', + 'Nagoya', + 'Tongshan', + 'Luanda', + 'Zhoukou', + 'Ganzhou', + 'Kuala Lumpur', + 'Heze', + 'Quanzhou', + 'Johannesburg', + 'Chicago', + 'Nanjing', + 'Jining', + 'Hanoi', + 'Pune', + 'Fuyang', + 'Ahmedabad', + 'Bogota', + 'Shenyang', + 'Dar es Salaam', + 'Khartoum', + 'Shangqiu', + 'Hong Kong', + 'Cangzhou', + 'Riyadh', + 'Santiago', + 'Xingtai', + 'Zhumadian', + 'Chattogram', + 'Surabaya', + 'Zhanjiang', + 'Bijie', + 'Yancheng', + 'Hengyang', + 'Zunyi', + 'Shaoyang', + 'Surat', + 'Shangrao', + 'Xinyang', + 'Madrid', + 'Baghdad', + 'Maoming', + 'Jieyang', + 'Miami', + 'Singapore', + 'Houston', + 'Liaocheng', + 'Huanggang', + 'Dalian', + 'Dallas', + 'Qingdao', + 'Yulin', + 'Douala', + 'Qujing', + 'Nangandao', + 'Philadelphia', + 'Pudong', + 'Toronto', + 'Zhengzhou', + 'Dezhou', + 'Nanchong', + 'Jinan', + 'Giza', + 'Nairobi', + 'Guadalajara', + 'Ankara', + "Tai'an", + 'Langfang', + 'Dazhou', + 'Monterrey', + 'Belo Horizonte', + 'Suzhou', + 'Yongzhou', + 'Changde', + 'Xiangyang', + 'Rangoon', + 'Atlanta', + 'Washington', + 'Zhaotong', + 'Zhangzhou', + 'Melbourne', + 'Yichun', + 'Bozhou', + 'Suqian', + 'Abidjan', + "Ji'an", + 'Guilin', + 'Pingdingshan', + 'Berlin', + 'Alexandria', + 'Mianyang', + 'Sydney', + 'Huanglongsi', + 'Barcelona', + 'Yuncheng', + 'Cape Town', + 'Changsha', + 'Jeddah', + 'Weinan', + 'Chenzhou', + 'Jiangmen', + 'Jiujiang', + 'Xinpu', + 'Yibin', + 'Huaihua', + 'Yangzhou', + 'Taizhou', + 'Kunming', + 'Yiyang', + 'Changchun', + "Lu'an", + 'Jiangguanchi', + 'Meizhou', + 'Urumqi', + 'Boston', + 'Izmir', + 'Guigang', + 'Shantou', + 'Kabul', + 'Xiaoganzhan', + 'Bamako', + 'Luzhou', + 'Hefei', + 'Hengshui', + 'Fortaleza', + 'Anqing', + 'Liuzhou', + 'Zhangjiakou', + 'Zhaoqing', + 'Shijiazhuang', + 'Ningbo', + 'Qiqihar', + 'Phoenix', + 'Fuzhou', + 'Chifeng', + 'Xiaoxita', + 'Amman', + 'Chuzhou', + 'Linfen', + 'Qingyuan', + 'Xianyang', + 'Loudi', + 'Binzhou', + 'Zhuzhou', + 'Taiyuan', + 'Nanning', + 'Harbin', + 'Abuja', + 'Yokohama', + 'Suihua', + 'Zaozhuang', + 'Detroit', + 'Xiamen', + 'Neijiang', + 'Montreal', + 'Baicheng', + 'Wuhu', + 'Yulinshi', + 'Medan', + 'Wenzhou', + 'Changzhou', + 'Puyang', + 'Jiaozuo', + 'Nanchang', + 'Seattle', + 'Ibadan', + 'Casablanca', + 'Kumasi', + 'Deyang', + 'Busan', + 'Hohhot', + 'Hechi', + 'Algiers', + 'Tangshan', + 'Shiyan', + 'Lucknow', + 'Mashhad', + 'San Francisco', + 'Boankra', + 'Dubai', + 'Anshan', + 'Baojishi', + 'Qinzhou', + 'Guiyang', + 'Bengbu', + 'Bazhou', + 'Suining', + 'Wuxi', + 'Kotla Qasim Khan', + 'Hanzhong', + 'Putian', + 'Zhenjiang', + "Guang'an", + 'Faisalabad', + 'Changzhi', + 'Tongren', + 'Leshan', + 'Santa Cruz de la Sierra', + 'Qinhuangdao', + 'Jaipur', + 'Xinzhou', + 'Lanzhou', + 'Wuzhou', + 'Athens', + 'San Diego', + 'Addis Ababa', + 'Taichung', + 'Huainan', + 'Guatemala City', + 'Kuwait City', + 'Budapest', + 'Qincheng', + 'Rizhao', + 'Quezon City', + 'Sanaa', + 'Tashkent', + 'Kyiv', + 'Meishan', + 'Incheon', + 'Birmingham', + 'Ningde', + 'Zhongshan', + 'Weihai', + 'Bursa', + 'Minneapolis', + 'Mbuji-Mayi', + 'Haikou', + 'Tongliao', + 'Chaoyang', + 'La Paz', + 'Pyongyang', + 'Tampa', + 'Shaoguan', + 'Heyuan', + 'Brasilia', + 'Omdurman', + 'Malang', + 'Stuttgart', + 'Daqing', + 'Rome', + 'Brooklyn', + 'Kaohsiung', + 'Xiangtan', + 'Longyan', + 'Baotou', + 'Handan', + 'Jinzhou', + 'Kanpur', + 'Denver', + 'Nanping', + 'Gazipura', + 'Shanwei', + 'Chaozhou', + 'Guayaquil', + 'Weifang', + "Huai'an", + 'Zibo', + 'Ankang', + 'Mogadishu', + 'Munich', + 'Gulou', + 'Taipei', + 'Bekasi', + 'Damascus', + 'Sanming', + 'Yangjiang', + 'Jiamusi', + 'Luohe', + 'Medellin', + 'Dingxi', + 'Shaoxing', + 'Yantai', + 'Huizhou', + 'Lishui', + 'Xuanzhou', + 'Khowrhesht', + 'Mirzapur', + 'Zigong', + 'Hamburg', + 'Guangyuan', + 'Cali', + 'Huangshi', + 'Xining', + 'Lusaka', + 'Ouagadougou', + 'Yaounde', + 'Zhuhai', + 'Huludao', + 'Baoshan', + 'Mecca', + 'Vancouver', + 'Lianshan', + 'Beirut', + 'Salvador', + 'Bucharest', + 'Longba', + 'Nagpur', + 'Queens', + 'Jilin', + 'Tieling', + 'Accra', + 'Yunfu', + 'Bekasi Kota', + 'Daegu', + 'Ghaziabad', + 'Luoyang', + 'Brisbane', + 'Anshun', + 'Riverside', + 'Yingkou', + 'Colombo', + 'Yanjiang', + 'Baku', + 'Antananarivo', + 'Mudanjiang', + 'Fukuoka', + "Yan'an", + 'Jincheng', + 'Nantong', + 'Lincang', + 'Yuxi', + 'Las Vegas', + 'Caracas', + 'Tangerang', + 'Laibin', + 'Konya', + 'Supaul', + 'Vienna', + 'Esfahan', + 'Baltimore', + 'Shengli', + 'Dandong', + 'Qinbaling', + 'Gaoping', + 'Awka', + "Ma'anshan", + 'Harare', + 'Perth', + 'St. Louis', + 'Phnom Penh', + 'Depok', + 'Stockholm', + 'Puning', + 'Huaibei', + 'Kowloon', + 'Cordoba', + 'Haiphong', + 'Zamboanga City', + 'Chongzuo', + 'Rawalpindi', + 'Portland', + 'Kano', + 'Yushan', + 'Havana', + 'Hezhou', + 'Pingliang', + 'Vadodara', + 'Manaus', + 'Qingyang', + 'San Antonio', + 'Rajkot', + 'Shangzhou', + 'Vishakhapatnam', + 'Sanmenxia', + 'Gujranwala', + 'Aleppo', + 'Tijuana', + 'Bamenda', + 'Minsk', + 'Indore', + 'Karaj', + 'Kananga', + 'Peshawar', + 'Sapporo', + 'Sacramento', + 'Tilburg', + 'Pingxiang', + 'Ecatepec', + 'Almaty', + 'Austin', + 'Yinchuan', + 'Santos', + 'Blantyre', + 'Thane', + 'Orlando', + 'Tainan', + 'Xiping', + 'Multan', + 'Santa Cruz', + 'Port Harcourt', + 'Jixi', + 'Fushun', + 'Warsaw', + 'Beihai', + 'Fuxin', + 'Wuwei', + 'Siping', + 'San Juan', + 'Mersin', + 'Bhopal', + 'Mosul', + 'Lubumbashi', + 'Davao', + 'Curitiba', + 'San Jose', + 'Shuyangzha', + 'Adana', + 'Quito', + 'Pittsburgh', + 'Brazzaville', + 'Hyderabad City', + 'Diyarbakir', + 'Indianapolis', + 'Pimpri-Chinchwad', + 'Masqat', + 'Montevideo', + 'Shuozhou', + 'Manhattan', + 'Cincinnati', + 'Kansas City', + 'Patna', + 'Tegucigalpa', + 'Kampala', + 'Cleveland', + 'Sanzhou', + 'Changshu', + 'Heihe', + 'Conakry', + 'Ximeicun', + 'Caloocan City', + 'Masvingo', + 'Zhongli', + 'Bilaspur', + 'Semarang', + 'Jingdezhen', + 'Ludhiana', + 'Liaoyang', + 'Chengtangcun', + 'Rajshahi', + 'Balandougou', + 'Jiangyin', + 'Valencia', + 'Agra', + 'Leon de los Aldama', + 'Puebla', + 'Columbus', + 'Yopougon', + 'Hebi', + 'Shiraz', + 'Madurai', + 'Huzhou', + 'Tabriz', + 'Jamshedpur', + 'Maracaibo', + 'Sofia', + 'Prayagraj', + 'Palembang', + 'Kawasaki', + 'Kobe', + 'Jiaxing', + 'Kigali', + 'Zhangjiajie', + 'Baiyin', + 'Guiping', + 'Lianjiang', + 'Jianguang', + 'Yucheng', + 'Xushan', + 'Panama City', + 'Nneyi-Umuleri', + 'Leizhou', + 'Gwangju', + 'Katako-Kombe', + 'Recife', + 'Nasik', + 'Onitsha', + 'Abu Dhabi', + 'Zapopan', + 'Daejeon', + 'Bronx', + 'Huazhou', + 'Jinhua', + 'Kyoto', + 'Amsterdam', + 'Pizhou', + 'Kismaayo', + 'Yangshe', + 'Virginia Beach', + 'Dakar', + 'Goiania', + 'Charlotte', + "Rui'an", + 'Muscat', + 'Kharkiv', + 'Wenling', + 'Gaozhou', + 'Faridabad', + 'Medina', + 'Khulna', + 'Ulaanbaatar', + 'Fuqing', + 'Kayseri', + 'Tel Aviv-Yafo', + 'Wuzhong', + 'Pingdu', + 'Sangereng', + 'Yangquan', + 'Samsun', + 'Yutan', + 'Copenhagen', + 'Helsinki', + 'Prague', + 'Milan', + 'Auckland', + 'Chizhou', + 'Makassar', + 'Liangshi', + 'Porto Alegre', + 'Huangshan', + 'Barranquilla', + 'Al Basrah', + 'Benxi', + 'Saitama', + 'Guarulhos', + 'Juarez', + 'Mandalay', + 'Xintai', + 'Wusong', + 'Calgary', + 'Meerut', + 'Yushu', + 'Belem', + 'Kuaidamao', + 'Baishan', + 'Adelaide', + 'Haicheng', + 'Milwaukee', + 'Providence', + 'Jacksonville', + 'Yicheng', + 'Cacuaco', + 'Porto', + 'Rosario', + 'Canagatan', + 'Soweto', + 'Bagam', + 'Jabalpur', + 'Rucheng', + 'Huaiyin', + 'Dublin', + 'Dayan', + 'Balikesir', + 'Comayaguela', + 'Laiwu', + 'Sharjah', + 'Jingling', + 'Kalyan', + 'Yongcheng', + 'Sumedang', + 'Can Tho', + 'Brussels', + 'Suwon', + 'Yiwu', + 'Beidao', + 'Vasai-Virar', + 'Xiangshui', + 'Dadukou', + 'Campinas', + 'Lingcheng', + 'Shuangyashan', + 'Mombasa', + 'Najafgarh', + 'Xinyu', + 'Qom', + 'Hargeysa', + 'Baidoa', + 'Zhangye', + 'Varanasi', + 'Hiroshima', + 'Chiang Mai', + 'Belgrade', + 'Maiduguri', + 'Batam Centre', + 'Rongcheng', + 'Mbandaka', + 'Doha', + 'Ahvaz', + 'Shymkent', + 'Tripoli', + 'Srinagar', + 'Nashville', + 'Liaoyuan', + 'Aurangabad', + 'Cilacap', + 'Salt Lake City', + 'Pikine', + 'Guankou', + 'Bandar Lampung', + 'Raleigh', + 'Lianyuan', + 'Dhanbad', + 'Nay Pyi Taw', + 'Aba', + 'Kaiyuan', + 'Zhuji', + 'Yingtan', + 'Edmonton', + 'Leiyang', + 'Ulsan', + 'Benin City', + 'Bujumbura', + 'Guyuan', + 'Xiantao', + 'Maputo', + 'Bukavu', + 'Amritsar', + 'Shagamu', + 'Yingchuan', + 'Aligarh', + 'Santo Domingo', + 'Bogor', + 'Bishkek', + 'Tbilisi', + 'Guwahati', + 'Fes', + 'Mwanza', + 'Bien Hoa', + 'Mexicali', + 'Sevilla', + 'Ikare', + 'Dongtai', + 'Dingzhou', + 'Xibeijie', + 'Tamale', + 'Yuyao', + 'Hanchuan', + 'Gongzhuling', + "N'Djamena", + 'Ubungo', + 'Cologne', + 'Zhufeng', + 'Ezhou', + 'Astana', + 'Nezahualcoyotl', + 'Nouakchott', + 'Haora', + 'Tongjin', + 'Xiashi', + 'Yerevan', + 'Ranchi', + 'Richmond', + 'Ciudad Nezahualcoyotl', + 'Gwalior', + 'Ottawa', + 'Zhongwei', + 'Oslo', + 'Goyang', + 'Sendai', + 'Mizhou', + 'Xishan', + 'Barquisimeto', + 'Hegang', + 'Chandigarh', + 'Managua', + 'Haldwani', + 'Vijayawada', + 'Fangchenggang', + 'Jiancheng', + 'Cazenga', + 'Kisangani', + 'Shouguang', + 'Memphis', + 'Sao Luis', + 'Jodhpur', + 'Matola', + 'Ogbomoso', + 'Sanya', + 'Rangapukur', + 'Ashgabat', + 'Wutong', + 'Linhai', + 'Denizli', + 'Niamey', + 'Shubra al Khaymah', + 'Wafangdian', + 'Zhongxiang', + 'Monrovia', + 'San Cristobal', + 'Islamabad', + 'Xinyi', + 'Thu Duc', + 'Morelia', + 'Odesa', + 'Raipur', + 'Changwon', + 'Arequipa', + 'Zaoyang', + 'Xingyi', + 'Shuizhai', + 'Kota', + 'Quetta', + 'Quang Ha', + 'Domaa-Ahenkro', + 'Bareilly', + 'Oklahoma City', + 'Bordeaux', + 'Xingcheng', + 'Taixing', + 'Xinhualu', + 'Lilongwe', + 'Port-au-Prince', + 'Yingcheng', + 'Al Mijlad', + 'Luocheng', + 'Pekanbaru', + 'Natal', + 'Chiba', + 'Kirkuk', + 'Hartford', + 'Huilong', + 'Wuchuan', + 'Dnipro', + 'Narayanganj', + 'Gqeberha', + 'Malaga', + 'Marrakech', + 'Cebu City', + 'Louisville', + 'Asmara', + 'Coimbatore', + 'Maceio', + 'Nada', + 'Taishan', + 'Teresina', + 'Solapur', + 'Freetown', + 'Santo Domingo Este', + 'Vientiane', + 'Tangier', + 'Anqiu', + 'Kermanshah', + 'Feicheng', + 'Kibanseke Premiere', + 'Seberang Jaya', + 'Buffalo', + 'Hubli', + 'El Alto', + 'Cankaya', + 'Hwasu-dong', + 'Setagaya', + 'Kecioren', + 'Jerusalem', + 'Khartoum North', + 'Mushin', + 'Trujillo', + 'Kitakyushu', + 'Aguascalientes', + 'New Orleans', + 'Fort Worth', + 'Taihe', + 'Riga', + "Xin'an", + 'Taihecun', + 'Kashgar', + 'Songnam', + 'Trichinopoly', + 'Cartagena', + 'Qingzhou', + 'Naples', + 'Santiago del Estero', + 'Naucalpan de Juarez', + 'Daye', + 'Hengzhou', + 'Padang', + 'Bridgeport', + 'Owerri', + 'Zhuanghe', + 'Bobo-Dioulasso', + 'Ad Dammam', + 'Quzhou', + 'Donetsk', + 'Ashmun', + 'Bunia', + 'Jiaozhou', + 'Campo Grande', + 'Wuchang', + 'Sao Goncalo', + 'Bucaramanga', + 'Merida', + 'Yangchun', + 'Osmangazi', + 'Esenyurt', + 'Moradabad', + 'Bangui', + 'Abeokuta', + 'Cancun', + 'Antipolo', + 'Dengtalu', + 'Taguig City', + 'Tabuk', + 'Zhoushan', + 'Tucson', + 'As Sulaymaniyah', + 'Chihuahua', + 'Klang', + 'Tiruppur', + 'Gurgaon', + 'Ar Ramadi', + "Hai'an", + 'Laiyang', + 'Barinas', + 'Jalandhar', + 'Marseille', + 'Kaifeng Chengguanzhen', + 'Eskisehir', + 'Gaomi', + 'Lhasa', + 'Ipoh', + 'El Paso', + 'Saltillo', + 'Dushanbe', + 'Ikeja', + 'El Dorado', + 'Cochabamba', + 'Portsmouth', + 'Southampton', + 'Hermosillo', + 'Leping', + 'Cheongju', + 'Shache', + 'Sale', + 'Hailun', + 'Macheng', + 'Akure', + 'Ilorin', + 'Erbil', + 'Kathmandu', + 'Iguacu', + 'Zijinglu', + 'Turin', + 'Yuci', + 'Dehui', + 'Pietermaritzburg', + 'Durban', + 'Bhubaneshwar', + 'Denpasar', + 'Tongchuan', + 'Joao Pessoa', + 'Samarinda', + 'Chengxiang', + 'Rongjiawan', + 'Weichanglu', + 'Sakai', + 'Renqiu', + 'Omaha', + 'Xindi', + "Wu'an", + 'Qingping', + 'Gaoyou', + 'Sao Bernardo do Campo', + 'Hejian', + 'Puxi', + 'Bhayandar', + 'Androtsy', + 'Culiacan', + 'Cucuta', + 'Danyang', + 'Dongyang', + 'Krakow', + 'Pasig City', + 'Thessaloniki', + 'Queretaro', + 'Palermo', + 'Xigaze', + 'Qamdo', + 'McAllen', + 'Libreville', + 'Seyhan', + 'San Pedro Sula', + 'Niigata', + 'Hempstead', + 'Leeds', + 'Hamamatsu', + 'Pointe-Noire', + 'Xiangxiang', + 'Chaohucun', + 'Bucheon', + 'Lubango', + 'Homs', + 'Bilbao', + 'Zouping', + 'Frankfurt', + 'San Luis Potosi', + 'Dali', + 'Khujand', + 'Korla', + 'Albuquerque', + 'Hamhung', + 'Erzurum', + 'Zagreb', + 'Al `Ayn', + 'Songzi', + 'Patiala', + 'Laixi', + 'Zhongba', + 'Bahawalpur', + 'Qingnian', + 'Kaduna', + 'Winnipeg', + 'Trabzon', + 'Guangshui', + 'Baardheere', + 'Shishgarh', + 'Nerima', + 'Sizhan', + 'Ciudad Guayana', + 'Lichuan', + 'Licheng', + 'Santo Andre', + 'Ota-ku', + 'Gaalkacyo', + 'Thiruvananthapuram', + 'Osasco', + 'Nampula', + 'Pretoria', + 'Kyaukse', + 'Chengguan', + 'Nehe', + 'Cabinda', + 'Kumamoto', + 'Kerman', + 'Zunhua', + 'Orumiyeh', + 'Wugang', + 'Bagcilar', + 'Quebec City', + 'Shuangqiao', + 'Umraniye', + 'Yanggok', + 'Tshikapa', + 'Tulsa', + 'Osogbo', + 'Comodoro Rivadavia', + 'Nottingham', + 'Hamilton', + 'Langzhong', + 'Cagayan de Oro', + "Qian'an", + 'Fresno', + 'An Najaf', + 'Cencheng', + 'Sorocaba', + 'Guli', + 'Sagamihara', + 'Pishbar', + 'Okayama', + 'Anlu', + 'Concepcion', + 'Mississauga', + 'Songyang', + 'Lviv', + 'Shihezi', + 'Vilnius', + 'Marka', + 'Enugu', + 'Valenzuela', + 'Yatou', + 'Uberlandia', + 'Xichang', + 'Zaporizhzhia', + 'Bhiwandi', + 'George Town', + 'Bristol', + 'Charleston', + 'Saharanpur', + 'Dashiqiao', + 'Yenimahalle', + 'Warangal', + 'Nampo', + 'Dasmarinas', + 'Jaboatao', + 'Chisinau', + 'Shiliguri', + 'Boosaaso', + 'Port Moresby', + 'Latakia', + 'Rochester', + 'Ribeirao Preto', + 'Edogawa', + 'Sao Jose dos Campos', + 'General Santos', + 'Hamah', + 'Qianxi', + 'Bauchi', + 'Pendik', + 'Salem', + 'Shishi', + 'Sinnuris', + 'Cocody', + 'Miluo Chengguanzhen', + 'Lokoja', + 'Guadalupe', + 'Gaizhou', + "Karbala'", + 'Borvayeh-ye Al Bu `Aziz', + 'City of Paranaque', + 'Leling', + 'Mamak', + 'Jianshe', + 'Shizuoka', + 'Jingcheng', + 'Agege', + 'Mar del Plata', + 'Zaragoza', + 'Adachi', + 'Xinmin', + 'Rasht', + 'Shanhu', + 'Zhongshu', + 'Cotonou', + 'Tasikmalaya', + 'Kochi', + 'Soledad', + 'Dhulia', + 'Acapulco de Juarez', + 'Gorakhpur', + 'Bahar', + 'Kumul', + 'Wroclaw', + 'Murcia', + 'Pinghu', + 'Lodz', + 'Guntur', + 'Bhangar', + 'Dayton', + "Ch'ongjin", + 'Qionghu', + 'Zhaodong', + 'Puyang Chengguanzhen', + 'Bulawayo', + 'Huambo', + 'Aracaju', + 'Bacoor', + 'Wenchang', + 'Rotterdam', + 'Tlaquepaque', + 'Villavicencio', + 'Shulan', + 'Banjarmasin', + 'Narela', + 'Catia La Mar', + 'Al Hufuf', + 'Jalingo', + 'Sargodha', + 'Karaikandi', + 'Bouake', + 'Lingbao Chengguanzhen', + 'Brampton', + 'Abomey-Calavi', + 'Durango', + 'Cape Coral', + 'Tondo', + 'Dayrut', + 'Tlalnepantla', + 'Ansan', + 'Hue', + 'Sanhe', + 'San Jose del Monte', + "Ch'onan", + 'Cuiaba', + 'Jieshou', + 'Erer Sata', + 'Selcuklu', + 'Suohe', + 'Guixi', + 'Honcho', + 'Wuxue', + 'Jaboatao dos Guararapes', + 'Yildirim', + 'Bhavnagar', + 'Jinghong', + 'Tengyue', + 'Mission Viejo', + 'Ruiming', + 'Qufu', + 'Sha Tin', + 'Petaling Jaya', + 'Colorado Springs', + 'Noida', + 'Xinshi', + 'Baton Rouge', + 'Manama', + 'Las Palmas', + 'Chak Forty-one', + "Jin'e", + 'Benghazi', + 'Chuxiong', + 'Makati City', + 'Dusseldorf', + 'Allentown', + 'Xinxing', + 'Tukh', + 'Glasgow', + 'Namangan', + "Bazal'tove", + 'Al Qatif', + 'Bhilai', + 'Mangalore', + 'Kaihua', + 'Meilan', + 'Ogden', + 'Turpan', + 'Jos', + 'Al Mansurah', + 'Contagem', + 'Jambi', + 'Halwan', + 'Provo', + 'Tan An', + 'Port-Bouet', + 'Pontianak', + 'Meihekou', + 'Jurong', + 'Bihta', + 'Yuhuan', + 'Joinvile', + 'Feira de Santana', + 'Leipzig', + 'Xinji', + 'Knoxville', + 'Ta`izz', + 'Etimesgut', + 'Changping', + 'Tallinn', + 'Chimalhuacan', + 'Kandahar', + 'Serang', + 'Zhangshu', + 'Grand Rapids', + 'Yukarikaraman', + 'Gothenburg', + 'Kuantan', + 'Gold Coast', + 'Kawaguchi', + 'Las Pinas City', + 'Cuttack', + 'San Miguel de Tucuman', + 'Ar Rayyan', + 'Salimpur', + 'Malanje', + 'Columbia', + 'Kryvyi Rih', + 'Djibouti', + 'Zhuozhou', + 'Tianchang', + 'Tunis', + 'Bacolod', + 'Garoua', + 'Bafoussam', + 'Haifa', + 'Raurkela', + 'Tumkur', + 'Balikpapan', + 'Somolu', + 'Al Hillah', + 'Melikgazi', + 'Kagoshima', + 'Sihui', + 'Dortmund', + 'Irapuato', + 'Al Mahallah al Kubra', + 'Sialkot City', + 'Albany', + 'Pereira', + 'Gaza', + 'Uvira', + 'Reynosa', + 'Zahedan', + 'Cimahi', + 'Mbale', + 'Wenlan', + 'Shangzhi', + 'Essen', + 'Itabashi', + 'Shah Alam', + 'Botou', + 'Suginami-ku', + 'Tenkasi', + 'Kingston', + 'Al Mafraq', + "At Ta'if", + 'Port Sudan', + 'Tuxtla', + 'Dehra Dun', + 'Xiulin', + "Fu'an", + 'Mymensingh', + 'Hachioji', + 'Iloilo', + 'Puente Alto', + 'Rabat', + 'Sincan', + 'Bakersfield', + 'Kottayam', + 'Luofeng', + 'Shibin al Qanatir', + 'Nakuru', + 'Lingyuan', + 'Tonala', + 'Bremen', + 'Abu Hummus', + 'Irbid', + 'Macau', + 'Surrey', + 'Ciudad Bolivar', + 'Durgapur', + 'Shenzhou', + 'New Haven', + 'Kuiju', + 'Zhenzhou', + 'Asansol', + 'Bokaro Steel City', + 'Dresden', + 'Bello', + 'Kolhapur', + 'Wencheng', + 'Lanxi', + 'Dangyang', + 'Nava Raipur', + 'Genoa', + 'Herat', + 'Londrina', + 'Cuautitlan Izcalli', + 'Uyo', + 'Hamadan', + 'Luanzhou', + 'Chiclayo', + 'Surakarta', + 'Ajmer', + 'Kimhae', + 'Nanded', + 'Wuhai', + 'Palma', + 'Rustenburg', + 'Amravati', + 'Des Moines', + 'Lisbon', + 'Yanji', + 'Huanghua', + 'Al Hudaydah', + 'Anyang', + 'The Hague', + 'Andijon', + 'Manchester', + 'Nellore', + 'Poznan', + 'Samarkand', + 'Wancheng', + 'Hannover', + 'Sungai Petani', + 'Valledupar', + 'Fengcheng', + 'Muntinlupa City', + 'Ghulja', + 'Ixtapaluca', + 'Fuding', + 'Heroica Matamoros', + 'Akron', + 'Mbeya', + 'An Nasiriyah', + 'Ibague', + 'Juiz de Fora', + 'City of Calamba', + 'El Geneina', + "Chang'an", + 'Florianopolis', + 'Nilufer', + 'Antwerp', + 'Kassala', + 'Aksu', + 'Salta', + 'Dispur', + 'Palm Bay', + 'Gulbarga', + 'Nansana', + 'Mingguang', + 'Concord', + 'Beira', + 'Yazd', + 'Ardabil', + 'Touba', + 'Bikaner', + 'Gaobeidian', + 'Ndola', + 'Himeji', + 'Ailan Mubage', + 'Bandar `Abbas', + 'Skopje', + 'Santa Teresa del Tuy', + 'Port Said', + 'Koto-ku', + 'Ciudad Apodaca', + 'Monteria', + 'Nuremberg', + 'Kitchener', + 'Nagercoil', + 'Agartala', + 'Soacha', + 'Buca', + 'Lyon', + 'Maipu', + 'Arak', + 'Serra', + 'Tultitlan de Mariano Escobedo', + 'Meknes', + 'Bac Ninh', + 'Anda', + 'Longzhou', + 'Al Fayyum', + 'Utsunomiya', + 'Sheffield', + 'Mixco', + 'Suez', + 'Heshan', + 'Loni', + 'Jiaji', + 'Santa Marta', + 'Ujjain', + 'Beining', + 'Abu Tisht', + 'Maturin', + 'Liverpool', + 'Macapa', + 'Benguela', + 'Al Fashn', + 'Al `Amarah', + 'Carrefour', + 'Campos', + 'Cadaado', + 'Encheng', + 'Bhilwara', + 'Biba', + 'Wichita', + 'Leicester', + 'Newcastle', + 'Hai Duong', + 'Aden', + 'Jhansi', + 'Matsuyama', + 'Ulhasnagar', + 'Nagqu', + 'Kitwe', + 'Vellore', + 'Toulouse', + 'Pohang', + 'Mesa', + 'Duisburg', + 'Jammu', + 'Ile-Ife', + "Homyel'", + 'Mazatlan', + 'Meicheng', + 'El Fasher', + 'Farah', + 'Belas', + 'Talatona', + 'Nenjiang', + 'Sukkur', + 'Hsinchu', + 'Harrisburg', + 'Hongjiang', + 'Qaraghandy', + 'Lapu-Lapu City', + 'Matsudo', + 'Johor Bahru', + 'Purnea', + 'Imus', + 'Niteroi', + 'Beipiao', + 'Dengtacun', + 'Zhijiang', + 'Suoluntun', + 'Staten Island', + 'Chengjiao', + 'Lembok', + 'Likasi', + 'Oujda-Angad', + 'Duyun', + 'Toledo', + 'Pindi Bhattian', + 'Nyala', + 'Bissau', + 'Ichikawa', + 'Kota Bharu', + 'Yuanping', + 'Higashi-osaka', + 'Larkana', + '`Ajman', + 'Vinh', + 'Ciudad Lopez Mateos', + 'Yueqing', + 'Belgaum', + 'Caerdydd', + 'Edinburgh', + 'Brookhaven', + 'Nishinomiya-hama', + 'Karamay', + 'Worcester', + 'Kawachicho', + 'Shahe', + 'Gdansk', + 'Sevastopol', + 'Garoowe', + 'Villa Nueva', + 'Dunhua', + 'Lianran', + 'Akhmim', + 'Sanliurfa', + "Az Zarqa'", + 'Malegaon', + 'Sao Jose do Rio Preto', + 'Valletta', + 'Kolwezi', + 'Jamnagar', + 'Sylhet', + 'Ananindeua', + 'East London', + 'Berbera', + 'Jiannan', + 'Chiniot', + 'Asuncion', + 'Oita', + 'Nangong', + 'Bardoli', + 'Eldoret', + 'Bratislava', + 'Kurashiki', + 'Al Jubayl', + 'Worthing', + 'Gaya', + 'Shekhupura', + 'Piura', + 'Vila Velha', + 'Ar Rusayfah', + 'Jiaojiangcun', + 'Laohekou', + 'Mykolaiv', + 'Beian', + 'Fujin', + 'Kucukcekmece', + 'Mazar-e Sharif', + 'Xiaoyi', + 'Qingzhen', + 'Ba`qubah', + 'Katlehong', + 'Jiangshan', + 'Buraydah', + 'Surab', + 'Kupang', + 'Ambattur', + 'Nakhon Ratchasima', + 'Tan Uyen', + 'Constantine', + 'Longjiang', + 'Caxias do Sul', + 'Angeles City', + 'Kuqa', + 'Kanazawa', + 'Long Beach', + 'Port St. Lucie', + 'Manado Light', + 'Kartal', + 'Cranbourne', + 'Jalgaon', + 'Porto Velho', + 'Chhatarpur', + 'Fukuyama', + 'Little Rock', + 'Juba', + 'Lanus', + 'Amagasaki', + 'Kikwit', + 'Pyeongtaek', + 'Reno', + 'Kurnool', + 'Spokane', + 'Marikina City', + "Jian'ou", + 'Huadian', + 'Melaka', + 'Manado', + 'Manizales', + 'Bornova', + 'Minzhu', + 'Demiryol', + 'Erkoklu', + 'Kota Kinabalu', + 'Katsushika-ku', + 'Madison', + 'Santiago de Cuba', + 'Udaipur', + 'Mogi das Cruzes', + 'General Trias', + 'Sirajganj', + 'Boise', + 'Bonita Springs', + 'Mariupol', + 'Eslamshahr', + 'Piraeus', + 'Tanbei', + 'Zurich', + 'Pingquan', + 'Ado-Ekiti', + 'Baisha', + 'Batman', + 'Yongji', + 'Esenler', + 'Rodriguez', + 'Ensenada', + 'Danjiangkou', + 'Chauddagram', + 'Kahramanmaras', + 'San Nicolas de los Garza', + 'Taoyuan District', + 'Ndjili', + 'Mathura', + 'Pasay City', + "Ning'an", + 'Halifax', + 'Fujisawa', + 'Denton', + 'Laval', + 'Jinchang', + 'Oakland', + 'Springfield', + 'Guangming', + 'Augusta', + 'Kagithane', + "Sunch'on", + 'Sangli', + 'Avcilar', + 'Jeju', + 'Zhuangyuan', + 'Davangere', + 'Machida', + 'Sanghar', + 'Al Maraghah', + 'Bandung', + 'Kissimmee', + 'Calicut', + 'Kenitra', + 'Windhoek', + 'Huili Chengguanzhen', + 'Sidi Bouzid', + 'Baramati', + 'Tanta', + 'Ismailia', + 'Cusco', + 'Veracruz', + 'Sokoto', + 'Winston-Salem', + 'Kashiwa', + 'Al Bajur', + 'Xunyang', + 'Malatya', + "Yan'an Beilu", + 'Mothihari', + 'Aomori', + 'Akola', + 'Mandaluyong City', + 'Aves', + 'Sihung', + 'Burco', + 'Xalapa', + 'Buenaventura', + 'Piracicaba', + 'Yogyakarta', + 'Toyota', + 'Daloa', + 'Agadir', + 'Elazig', + 'Uijeongbu', + 'Hpa-An', + 'Rahimyar Khan', + 'Ugep', + 'Hailin', + 'Mishan', + 'Sarajevo', + 'Seremban', + 'Zhengjiatun', + 'Lecheng', + 'Campina Grande', + 'Xicheng', + 'Pencheng', + 'Kowloon City', + 'Tirana', + 'Kushtia', + 'El Obeid', + 'Maua', + "Da'an", + 'Luhansk', + 'Xingren', + 'Takamatsu', + 'Arusha', + 'Fenyang', + 'Ajdabiya', + 'Callao', + 'Awsim', + 'Shinagawa-ku', + 'Paju', + 'Santa Rosa', + 'Bettiah', + 'Jhang City', + 'Altindag', + 'Tala', + 'Stockton', + 'Talkha', + 'Boa Vista', + 'Banjul', + 'Jayapura', + 'Toyama', + 'Sanandaj', + 'Khon Kaen', + 'Fangting', + 'Linghai', + 'Shorapur', + 'Koumassi', + 'Betim', + 'Tinnevelly', + 'Pasto', + 'Syracuse', + 'Bellary', + 'Bhagalpur', + 'Kisumu', + 'Zhangjiakou Shi Xuanhua Qu', + 'Maringa', + 'Kocasinan', + 'Mataram', + 'Shashemene', + 'Zaria', + 'Kumi', + 'Wanyuan', + 'Binan', + 'Chattanooga', + 'Jiexiu', + 'Baglar', + 'Padiala', + 'Da Lat', + 'Sham Shui Po', + 'Santa Fe', + 'Delhi Cantonment', + 'Cumana', + 'Barura', + 'Yuregir', + 'Nagasaki', + 'Mardan', + 'Hat Yai', + 'Qazvin', + 'Etawa', + 'Lancaster', + 'Sonipat', + 'Jundiai', + 'Greenville', + 'Toyonaka', + 'Bogra', + 'Oskemen', + 'Gifu', + 'Maungdaw', + 'Jiangjiafan', + 'Durham', + 'Dera Ghazi Khan', + 'Anapolis', + 'Pensacola', + 'Miyazaki', + 'Quilon', + 'Mulangodi', + 'Munro Turuttu', + 'Hirakata', + 'Sandakan', + 'Szczecin', + 'Brno', + 'Hejin', + 'Fayetteville', + 'Betsiboka', + 'Thies', + 'Arlington', + "Al Jahra'", + 'Kaunas', + 'Thanh Hoa', + 'Diadema', + 'Lobito', + 'Saurimo', + 'Yola', + 'Zhugang', + 'Tangail', + 'Nha Trang', + 'Khayelitsha', + 'Ad Diwaniyah', + 'Nnewi', + 'Hancheng', + 'San-Pedro', + 'Gujrat', + 'Yokosuka', + 'Tieli', + 'Asyut', + 'Gwoza', + 'Sampaloc', + 'Saki', + 'Bologna', + 'Aqtobe', + 'Cilegon', + 'Uvinza', + 'Aurora', + 'Carapicuiba', + 'Hafr al Batin', + 'Zanjan', + 'Petrolina', + 'Bairia', + 'Oyo', + 'Taytay', + 'Kisenzi', + 'Bhatpara', + 'Kukatpalli', + 'Manisa', + 'Sirur', + 'Tarlac City', + 'Okazaki', + 'Lianzhou', + 'Ceel Baraf', + 'Yidu', + 'Lingxi', + 'Ilesa', + 'Kakinada', + 'Savar', + 'Nuevo Laredo', + 'Bawshar', + 'Christchurch', + 'Gusau', + 'Zetang', + 'Palu', + 'Canberra', + 'Minamisuita', + 'Tetouan', + 'Malabon', + 'Neiva', + 'Novi Sad', + 'Huancayo', + 'Celaya', + 'Ichinomiya', + 'Caruaru', + 'Sintra', + 'Hatay', + 'Iquitos', + 'Panihati', + 'Cainta', + 'Helixi', + 'Mamou', + 'Manukau City', + 'Itaquaquecetuba', + 'Cantonment', + 'Rohtak', + 'Gaziantep', + 'Maler Kotla', + 'Bhawana', + 'Khorramabad', + 'Lipa City', + 'Butuan', + 'Dikirnis', + 'Stoke-on-Trent', + 'Takasaki', + 'Malakwal', + 'Toyohashi', + 'Chitungwiza', + 'Gebze', + 'Cibinong', + 'Lengshuijiang', + 'Panshi', + 'Az Zubayr', + 'Oxnard', + 'Vinnytsia', + 'Indio', + 'Bharatpur', + 'Petare', + 'Nagano', + 'Huichang', + 'Keelung', + 'Bauru', + 'La Florida', + 'Nicolas Romero', + 'Jinshan', + 'Baguio City', + 'Scranton', + 'Bochum', + 'Sivas', + 'Kolga', + 'Korba', + 'Qardho', + 'Rio Branco', + 'Tecamac', + 'Alanya', + 'Mandaue City', + 'Victorville', + 'Kocaeli', + 'Warri', + 'Victoria', + 'Wonsan', + 'Iligan', + 'Anguo', + "K'ebri Dehar", + 'Coventry', + 'Kayapinar', + 'Trenton', + 'Cuenca', + 'Blumenau', + 'Nanqiao', + 'Florence', + 'Buurhakaba', + 'Bengkulu', + 'Malmo', + 'Wudalianchi', + 'Shuanghe', + 'Petion-Ville', + 'Utrecht', + 'Sikar', + 'Umuahia', + 'Vitsyebsk', + 'Palmira', + 'Wuppertal', + 'Hrodna', + "Ash Shuhada'", + 'Karur', + 'Ponta Grossa', + 'Sasaram', + 'Taraz', + 'Cubal', + 'Luena', + 'Karnal', + "Yong'an", + 'Konak', + 'Minatitlan', + 'Linxia Chengguanzhen', + 'Brahmapur', + 'Chanda', + 'Caucaia', + 'Cuito', + 'Cabuyao', + 'Hongzhai', + 'Gedaref', + 'San Fernando', + 'Kawagoe', + 'Modesto', + 'Pokhara', + 'Villahermosa', + 'Van', + 'Mahilyow', + 'Wakayama', + 'Osh', + 'Kita-ku', + 'Gimpo', + 'Corrientes', + 'Franca', + 'Thari Mir Wah', + 'Nara', + 'Yakeshi', + 'Nam Dinh', + 'Sinuiju', + 'Oruro', + 'Cabimas', + 'Batangas', + 'Ibb', + 'Ahmadnagar', + 'Sarai Alamgir', + 'Semey', + 'Holguin', + 'Tungi', + 'Yingmen', + 'Sawran', + 'Olinda', + 'Praia Grande', + 'Dasarhalli', + 'Huntsville', + 'Shinjuku', + 'Alicante', + 'Cariacica', + 'Varna', + 'Honolulu', + 'Antofagasta', + 'Ambon', + 'Nice', + 'Cascavel', + 'Pamukkale', + 'Canoas', + 'Takatsuki', + 'Antonio Enes', + 'Greensboro', + 'Anaheim', + 'Plovdiv', + 'Central Coast', + 'Karsiyaka', + 'Shahjanpur', + 'Gwagwalada', + 'Alamadi', + 'Avadi', + "Tanch'on", + 'Khanapur', + 'Wad Medani', + 'Kusti', + 'Belfast', + 'Hosur', + 'Cuddapah', + 'Nakano', + 'Otsu', + 'Maseru', + 'Makiivka', + 'Pavlodar', + 'Chon Buri', + 'Naga City', + 'Sariyer', + 'Brest', + 'Meram', + 'Gomez Palacio', + 'Paulista', + 'Rajahmundry', + 'Koshigaya', + 'Vung Tau', + 'Jeonju', + 'Alwar', + 'Tokorozawa', + 'Sumqayit', + 'Vitoria da Conquista', + 'Simferopol', + 'Buon Ma Thuot', + 'Serekunda', + 'Islip', + 'Cuernavaca', + 'Markham', + 'Bielefeld', + 'Uberaba', + 'Jitpur', + 'Bydgoszcz', + 'Tangdong', + 'Chinju', + 'Corpus Christi', + 'Fort Wayne', + 'Reading', + 'Randburg', + 'Matadi', + 'Bonn', + 'Iwaki', + 'Oshawa', + 'Shah Latif Town', + 'Sambalpur', + 'Fort Collins', + 'Jackson', + 'Yingzhong', + 'Santo Domingo de los Colorados', + 'Uruapan', + 'Lublin', + 'Tampere', + 'Muzaffarpur', + 'Vina del Mar', + 'Tepic', + 'Khipro', + 'Hangu', + 'Asan', + 'Chak Jhumra', + 'Myrtle Beach', + 'Soledad de Graciano Sanchez', + 'Salalah', + 'Santarem', + 'Yanbu', + 'Maebashi', + 'Dumai', + 'Beylikduzu', + 'Ganca', + 'Asahikawa', + 'Kendari', + 'Wonju', + 'Birkat as Sab`', + 'Lafia', + 'Dahuk', + 'Finglas', + 'Kamarhati', + 'Thai Nguyen', + 'Bamiantong', + 'Nicosia', + 'Sao Vicente', + 'Ribeirao das Neves', + 'Guediawaye', + 'Ciudad Obregon', + 'Sao Jose dos Pinhais', + 'Campiernagar', + 'Phatthaya', + 'Debrecen', + 'Mirpur Mathelo', + 'Sultanbeyli', + 'Bijapur', + 'Cabanatuan City', + 'Tharad', + 'Antioch', + 'Si Racha', + 'Salamanca', + 'Ratnagiri', + 'Ulanhot', + 'Koriyama', + 'Yunzhong', + 'Roodepoort', + 'Pucallpa', + 'San Pedro', + 'Pelotas', + 'Rampur', + 'Kuching', + 'Cotabato', + 'Cimanggis', + 'Gonaives', + 'Nazret', + 'Kikuyu', + 'Kluang', + 'Mekele', + 'Binxian', + 'Nantes', + 'Vaughan', + 'Vitoria', + 'Shimoga', + 'Lansing', + 'Uige', + 'Hotan', + 'Camaguey', + 'Taourirt', + 'San Salvador de Jujuy', + 'Kashipur', + 'Thu Dau Mot', + 'Al Kut', + 'Lexington', + 'Sukabumi', + 'Munster', + 'Menongue', + 'Mobile', + 'Gode', + 'Okene', + 'Junagadh', + 'Guasavito', + 'Nukus', + "Kaech'on", + 'Tehuacan', + 'Coatzacoalcos', + 'Muhanga', + 'Youngstown', + 'Zalantun', + 'Katsina', + 'Puerto Plata', + 'Henderson', + 'Gwangmyeongni', + 'Geita', + 'Taubate', + 'An Nhon', + 'Fontibon', + 'Hapur', + 'Kot Radha Kishan', + 'Barueri', + 'San Salvador', + 'Savannah', + 'Naha', + 'Bari', + 'Xiaoli', + 'Trichur', + 'Mannheim', + 'Bor', + 'Ca Mau', + 'Saint-Denis', + 'San Miguelito', + 'Muar', + 'Kasur', + 'Usme', + 'Barddhaman', + 'Poughkeepsie', + 'Kingston upon Hull', + 'Binangonan', + 'Temara', + 'Attiecoube', + 'Jiayuguan', + 'Pasir Gudang', + 'Gorgan', + 'Tanza', + 'Panvel', + 'Santa Ana', + 'Guaruja', + 'Nizamabad', + 'Quy Nhon', + "Ha'il", + 'Datang', + 'Longquan', + 'Mitchells Plain', + 'Yokkaichi', + 'Chalco', + 'Shahriar', + 'Shahr-e Qods', + 'Ciudad del Este', + 'Ann Arbor', + 'St. Paul', + 'Karlsruhe', + 'Safi', + 'Ciudad Benito Juarez', + 'Karawang', + 'Sariwon', + 'Suzano', + 'Newark', + 'Nghi Son', + 'Parbhani', + 'Puerto Princesa', + 'Hisar', + 'Windsor', + 'Kasugai', + 'Ciudad Santa Catarina', + 'Puerto La Cruz', + 'Fatehpur', + 'Ciudad Victoria', + 'Playa del Carmen', + 'Yesilyurt', + 'Yonghetun', + 'Irvine', + 'Kashan', + 'Minna', + 'Sumbawanga', + 'Akita', + 'Kurume', + 'Az Zaqaziq', + 'Palmas', + 'Montpellier', + 'Vila Nova de Gaia', + 'Bahia Blanca', + 'Al Waqf', + 'San Bernardo', + 'San Juan del Rio', + 'Armenia', + 'Augsburg', + 'Qianzhou', + 'Popayan', + 'Al Qunfudhah', + 'Yakou', + 'Oulgaret', + 'Awasa', + 'Ingraj Bazar', + 'Oaxaca', + 'Binjai', + 'Barr Elias', + 'Khairpur Tamewah', + 'Sucre', + 'Al `Ajami', + 'Al Matariyah', + 'Bada Barabil', + 'Ash Shamiyah', + 'Oyster Bay', + 'Ar Raqqah', + 'Chakwal', + 'Oakashicho', + 'Afyonkarahisar', + 'Dod Ballapur', + 'Camacari', + 'Ciudad General Escobedo', + 'Catania', + 'Jember', + 'Al Mubarraz', + 'Pekalongan', + 'Los Mochis', + 'Toshima', + 'Pachuca', + 'Yangsan', + 'Valladolid', + 'Tampico', + 'Bihar', + 'Espoo', + 'Malabo', + 'Pilar', + 'Valparaiso', + 'Cirebon', + 'Tagum', + 'Darbhanga', + 'Comilla', + 'Battalgazi', + 'Sorong', + 'Shubrakhit', + 'Floridablanca', + 'Silang', + 'Eloy Alfaro', + 'Pondokaren', + 'Sikandarabad', + 'Kafr Saqr', + 'Vila Teixeira da Silva', + 'Panipat', + 'Rangpur', + 'Bialystok', + 'Canton', + 'Asheville', + 'Flint', + 'Vigo', + 'Coacalco', + 'Aizawl', + 'Bali', + 'Bradford', + 'Mabalacat', + 'Dexing', + 'Winter Haven', + 'Graz', + 'Palni', + 'Resistencia', + 'Chimbote', + 'Strasbourg', + 'Bergen', + 'Gatineau', + 'Surajgarha', + 'Tegal', + 'Anchorage', + 'Batna', + 'Aarhus', + 'Morioka', + 'Lincoln', + 'Hulin', + "Hong'an", + 'Karimnagar', + 'Santa Maria', + 'Dewas', + 'Gungoren', + 'Magway', + 'Farg`ona', + 'Hugli', + 'Chunchura', + 'Setif', + 'Sonpur', + 'Meguro', + 'Machala', + 'San Lorenzo', + 'Jersey City', + 'Ichalkaranji', + 'Punto Fijo', + 'Varzea Grande', + 'Tirupati', + 'Pathein', + 'Chernihiv', + 'Sincelejo', + 'Cluj-Napoca', + 'Sekondi', + 'Tacna', + 'Tin Shui Wai', + 'Juazeiro do Norte', + 'Al Qurnah', + 'Korhogo', + 'Bhatinda', + 'Katowice', + 'Jalna', + 'Foz do Iguacu', + 'Bolton', + 'San Pablo', + 'Huixquilucan', + 'Plano', + 'Qillin', + 'Croix-des-Bouquets', + 'San Juan Sacatepequez', + 'Ljubljana', + 'Fukushima', + 'Bago', + 'Delmas', + 'Fuquan', + 'Ibaraki', + 'Shreveport', + 'Ostrava', + 'Poltava', + 'Wiesbaden', + 'Satna', + 'Sannai', + 'Huozhou', + 'Temuco', + 'Ica', + 'Tongchuanshi', + 'Chuncheon', + 'Sakarya', + 'Inegol', + 'Kaura Namoda', + 'Davenport', + 'Malard', + 'Lubbock', + 'Lakeland', + 'Bukhara', + 'Sumbe', + 'Mingaora', + 'Corlu', + 'Kherson', + 'Lucena', + 'Petropolis', + 'Mamuju', + 'Mau', + 'Long Xuyen', + 'Gyeongsan', + 'Barasat', + 'South Bend', + 'Pematangsiantar', + 'Maastricht', + 'Viet Tri', + 'Sunderland', + 'Gagnoa', + 'Xingsha', + 'Dire Dawa', + 'Lashkar Gah', + 'Itagui', + 'Juliaca', + 'Chula Vista', + 'Posadas', + 'Farrukhabad', + 'Chandler', + 'Kunsan', + 'Yeosu', + 'Qarshi', + 'Saugor', + 'Khmelnytskyi', + 'Nassau', + 'Ratlam', + 'Crato', + 'Shaowu', + 'Pasarkemis', + 'Cotia', + 'Taboao da Serra', + 'San Mateo', + 'Tsu', + 'Rockford', + 'Imperatriz', + 'Los Alcarrizos', + 'Soubre', + 'Szekesfehervar', + 'Majene', + 'Sumida', + 'Chopda', + 'Gabela', + 'Dayr az Zawr', + 'Iasi', + 'Sarta', + 'Eugene', + 'Iksan', + 'My Tho', + 'Nguru', + 'Arnavutkoy', + 'Derby', + 'Mito', + "Kunp'o", + 'Gombe', + 'Bijiao', + 'Cherkasy', + 'Bayat', + 'Handwara', + 'Kunduz', + 'Drug', + 'Wilmington', + 'Monchengladbach', + 'Gijon', + 'Brahmanbaria', + 'Santa Clarita', + 'Thai Binh', + 'Ichihara', + 'Tarija', + 'Shibin al Kawm', + 'Plymouth', + 'Aswan', + 'Bimo', + 'Gilbert', + 'Maradi', + 'Xiangkhoang', + 'Anantapur', + 'Adiyaman', + 'Kutahya', + 'Maraba', + 'Saskatoon', + 'Sumare', + 'Killeen', + 'Nagaoka', + 'Djelfa', + 'Sumy', + 'Khwazakhela', + 'Chernivtsi', + 'Suncheon', + 'Kibaha', + 'Sfax', + 'Gent', + 'Gravatai', + 'Antsirabe', + 'Feni', + 'Imphal', + 'Taunggyi', + 'Nogales', + 'Ed Daein', + 'Dezful', + 'Mossoro', + 'Round Lake Beach', + 'Potosi', + 'Osmaniye', + 'Itajai', + 'North Las Vegas', + 'Taluqan', + 'Constanta', + 'Luque', + 'Yao', + 'Jalalabad', + 'Nawabshah', + 'Talisay', + 'Gelsenkirchen', + 'Jagdalpur', + 'Tchibota', + 'Kafr ad Dawwar', + 'Quilmes', + 'Wollongong', + 'Zhytomyr', + 'Volta Redonda', + 'Fukui', + 'Arrah', + 'Malolos', + 'Heroica Nogales', + 'Bariadi', + 'Hong', + 'Oume', + 'Fuchu', + 'Minato', + 'Boksburg', + 'Olongapo', + 'Quang Ngai', + 'Al Hamzah', + 'Kennewick', + 'Qo`qon', + 'Kotri', + 'St. Petersburg', + 'Misratah', + 'Aydin', + 'Singa', + 'Manta', + 'Tallahassee', + 'Kakogawacho-honmachi', + 'Isparta', + 'Siverek', + 'Ndulo', + 'Antalya', + 'Huayin', + 'Hiratsuka', + 'Raniyah', + 'Annaba', + 'Governador Valadares', + 'Ondo', + 'Etawah', + 'Siddhirganj', + 'Horlivka', + 'Indaiatuba', + 'Bloemfontein', + 'Ap Da Loi', + 'Turkmenabat', + 'Malkajgiri', + 'Vitoria-Gasteiz', + 'Germiston', + 'Nonthaburi', + 'Verona', + 'Tuzla', + 'Westminster', + 'Laredo', + 'Kuala Terengganu', + 'San Pedro Carcha', + 'Mocamedes', + 'Irving', + 'Turmero', + 'Tokushima', + 'Sao Carlos', + 'Longueuil', + 'Marilao', + 'Tuni', + 'Ash Shatrah', + 'Sab` al Bur', + 'Fort-de-France', + 'Mawlamyine', + 'Peoria', + 'Godome', + 'Rapar', + 'Samastipur', + 'Aksaray', + 'Shinozaki', + 'Parnamirim', + 'Kiziltepe', + 'Jhenida', + 'Turku', + 'Aachen', + 'Begusarai', + 'Kediri', + 'Kanggye', + 'Chiayi', + 'Cekme', + 'Hakodate', + 'Tacloban', + 'Junagarh', + 'Braunschweig', + 'Iskenderun', + 'Pecs', + 'Soka', + 'Nedumana', + 'Higuey', + 'Los Teques', + 'Montgomery', + 'Jinshi', + 'Wolverhampton', + 'Pointe-a-Pitre', + 'Al Fallujah', + 'Timisoara', + 'Bata', + 'Rach Gia', + 'Companiganj', + 'Venice', + 'Babol', + 'Sao Jose', + "Al Bayda'", + 'Natogyi', + 'Kurmuk', + 'Ras el-Barr', + 'Kalar', + 'Bojnurd', + 'Turkistan', + 'New Delhi', + 'Las Condes', + 'Goma', + 'Rishon LeZiyyon', + 'Campeche', + 'Manzhouli', + 'Tiruvottiyur', + 'Palangkaraya', + 'Chesapeake', + 'Burnaby', + 'Ramnagar', + 'Limeira', + 'Carmen', + 'Gandhidham', + 'Banikoara', + 'Chemnitz', + 'Salumbar', + 'Kyongju', + 'Glendale', + 'Sibu', + "Qa'em Shahr", + 'Parana', + 'Buyukcekmece', + 'Kiel', + 'Sahiwal', + 'A Coruna', + 'Navotas', + 'Santa Clara', + 'Mehrabpur', + 'Yamagata', + 'York', + 'Khomeyni Shahr', + 'Beykoz', + 'Tsukuba-kenkyugakuen-toshi', + 'Macae', + 'Gyor', + 'Al `Ashir min Ramadan', + 'Mahajanga', + 'Mount Lavinia', + 'Northampton', + 'Krishnarajpur', + 'Hafizabad', + 'Nelamangala', + 'Beichengqu', + 'Abertawe', + 'Rivne', + 'Gdynia', + 'Nashua', + 'Barnsley', + 'Taiping', + 'Rondonopolis', + 'Sao Jose de Ribamar', + 'Puducherry', + 'Merlo', + 'Portoviejo', + 'Damanhur', + 'Garland', + 'Kabinda', + 'Jessore', + 'Kesbewa', + 'Fuji', + 'Eindhoven', + 'Sabzevar', + 'Dourados', + 'Bahir Dar', + 'Yoshiicho-shimobaru', + 'Myitkyina', + 'Ramgundam', + 'Palanpur', + 'Tuy Hoa', + 'Sasebo', + 'Sapele', + 'Biratnagar', + 'Pandharpur', + 'Qyzylorda', + 'St. Catharines', + 'Chigasaki', + 'Araraquara', + 'Kahama', + 'Halle', + 'Americana', + 'Zhangping', + 'Man', + 'Sete Lagoas', + 'Banchpar', + 'Haeju', + 'Soyapango', + 'Masaurhi Buzurg', + 'Baruta', + 'Duzce', + 'Marilia', + 'Katihar', + 'Scottsdale', + 'Tarapoto', + 'Atushi', + 'Abi al Khasib', + 'Jacarei', + 'Anju', + 'Bunkyo-ku', + 'Byatarayanpur', + 'Ahor', + 'Diaobingshancun', + 'Magdeburg', + 'Yato', + 'Matsumoto', + 'Szeged', + 'Chimoio', + 'Kasulu', + 'Elche', + 'Tarsus', + 'Ivano-Frankivsk', + 'Chofugaoka', + 'Gonzalez Catan', + 'Nyiregyhaza', + 'Wuyishan', + 'Shenmu', + 'Tuticorin', + 'As Sib', + 'Ganganagar', + 'Brasov', + 'Lafayette', + 'Amol', + 'Stavanger', + 'Sandnes', + 'Monclova', + 'Chishui', + 'Djougou', + 'Norfolk', + 'Mirpur Khas', + 'Lille', + "P'yongsong-si", + "P'yong-dong", + 'Centurion', + 'North Hempstead', + 'Tinkhang', + 'Rewa', + 'Pakdasht', + 'Kajang', + 'Petah Tiqwa', + 'Abha', + 'Freiburg im Breisgau', + 'Al Minya', + 'Iseyin', + 'Central District', + 'Gaborone', + 'Juazeiro', + 'Zinder', + 'Bole', + 'Ganda', + 'Uluberiya', + 'Bulandshahr', + 'Banda Aceh', + 'Najafabad', + 'Shibuya-ku', + 'Bayamo', + 'Limassol', + 'Borujerd', + 'Garcia', + 'Arapiraca', + 'Miri', + 'Maracanau', + 'Oral', + 'Craiova', + 'Formosa', + 'Appleton', + 'Chauhanpatti', + 'Bo', + 'Mambere', + 'Damboa', + 'Groningen', + 'Ipswich', + 'Teluk Intan', + 'Cannanore', + 'Raichur', + 'Okara', + 'Saga', + 'Saidpur', + "Lin'an", + 'Machilipatnam', + 'Beni', + 'Nazipur', + 'Purwokerto', + 'Biyala', + 'Madan', + 'Rancagua', + 'Phu Yen', + 'Neuquen', + 'Divinopolis', + 'Qarchak', + 'Ormoc', + 'Fresnillo', + 'Granada', + 'Son Tay', + 'Singkawang', + 'Zegoua', + 'Kulai', + 'Barishal', + 'Pali', + 'Songadh', + 'Gadda Madiral', + 'Ordu', + 'Kosice', + 'Kasukabe', + 'Mirialguda', + 'Aguadilla', + 'Envigado', + 'Haridwar', + 'Rock Hill', + 'Fremont', + 'Vizianagaram', + 'Coban', + 'Khenifra', + 'Guantanamo', + 'Krefeld', + 'Sabya', + 'Fargo', + 'Raisinghnagar', + 'Usak', + 'Pathardi', + 'Mage', + 'Gulfport', + 'Neya', + 'Mel Palaiyam', + 'Novo Hamburgo', + 'Ipatinga', + 'Saqultah', + 'Choloma', + 'Kropyvnytskyi', + 'Khatima', + 'Dasoguz', + 'Khanewal', + 'Petlad', + 'Kamianske', + 'Bremerton', + 'Ageoshimo', + 'Changhua', + 'Regina', + 'Badalona', + 'Dianbu', + 'Rio Verde', + 'Meycauayan', + 'Presidente Prudente', + 'Green Bay', + 'Varamin', + 'Padangsidempuan', + 'Uacu Cungo', + 'Enterprise', + 'Hunchun', + 'Tarrasa', + 'Ternopil', + 'Kimberley', + 'Nadiad', + 'Toamasina', + 'Rennes', + 'Mutare', + 'Cikupa', + 'Ratodero', + 'Chuadanga', + 'Carlos Manuel de Cespedes', + "Nong'an", + 'Ota', + 'Itaborai', + 'Puerto Vallarta', + 'Capiata', + 'Viamao', + 'Takarazuka', + 'Chapeco', + 'Banfield', + 'Toluca', + 'Atsugicho', + 'Paramaribo', + "Cox's Bazar", + 'Bandar-e Bushehr', + 'Itapevi', + 'Probolinggo', + 'Hialeah', + 'Tanjore', + "Ji'an Shi", + 'Hachinohe', + 'Ijebu-Ode', + 'Barra do Dande', + 'Mezitli', + 'Sandton', + 'Beji', + 'Cork', + 'Dili', + 'Owo', + 'Swindon', + 'Myeik', + 'Cabo Frio', + 'Kichha', + 'Katri', + 'Saricam', + 'Gueckedou', + 'Neyshabur', + 'Sousse', + 'Tabora', + 'Soc Trang', + 'Dagarua', + 'Deltona', + 'Tchaourou', + 'Rufisque', + 'San Bernardino', + 'Duekoue', + 'Gainesville', + 'Sambhal', + 'San Felipe', + 'Saveh', + 'Mainz', + 'Santa Luzia', + 'Chi Linh', + 'La Vega', + 'Singrauliya', + 'El Jadid', + 'Kremenchuk', + 'Ashdod', + 'Prizren', + 'Spring Valley', + 'Thatta', + 'Yenisehir', + 'Al Khubar', + 'Osisioma', + 'Tacoma', + 'Tulua', + 'Zanzibar', + 'Kafue', + 'Konibodom', + 'Petrel', + 'Messina', + 'Pangkalpinang', + 'Roanoke', + 'Bitung', + 'Santo Tomas', + 'San Miguel', + 'Sabadell', + 'Lubeck', + 'Naihati', + 'Arakawa', + 'Galati', + 'Babylon', + 'Laayoune', + 'Butembo', + 'Oviedo', + 'Tapachula', + 'Porbandar', + 'Sao Leopoldo', + 'Apapa', + 'Netanya', + 'Qostanay', + 'Alor Setar', + 'Wayaobu', + 'Zielona Gora', + 'Batu', + 'Gujiao', + 'Jose C. Paz', + 'Yamunanagar', + 'Banjarbaru', + 'Ayacucho', + 'Wellington', + 'Penalolen', + 'Dongxing', + 'Lutsk', + 'La Ceiba', + 'Ar Ruseris', + 'Hortolandia', + 'Pallavaram', + 'Marg`ilon', + 'Jiutepec', + 'Brownsville', + 'Golmud', + 'San Rafael', + 'Sidi Aissa', + 'Khargone', + 'As Samawah', + 'Matrah', + 'Comalcalco', + 'Cua', + 'Almere', + 'Vantaa', + 'Mokpo', + 'La Victoria', + 'Warnes', + 'Cascais', + 'Cigli', + 'Marcory', + 'Chilas', + 'Sikasso', + 'Osan', + 'Oakville', + 'Secunderabad', + 'Sa Dec', + 'Turbat', + 'El Tigre', + 'Bhuj', + 'Sodo', + 'Isesaki', + 'Jerez de la Frontera', + 'College Station', + 'Norwich', + 'Czestochowa', + 'Monghyr', + 'Luton', + 'Chapra', + 'Sidi Bel Abbes', + 'Zhubei', + 'Tumaco', + 'Trondheim', + 'Mallawi', + 'Kure', + 'Kuje', + 'Bhadravati', + 'Taito', + '`Aqrah', + 'Cao Lanh', + 'Xigujing', + 'Irakleio', + 'Criciuma', + 'Panchkula', + 'Mirpur Bhtoro', + 'Burhanpur', + 'Olympia', + 'Oberhausen', + 'Burgas', + 'Sobral', + 'Clarksville', + 'Trece Martires City', + 'Gangneung', + 'Pagadian', + 'Quilicura', + 'Kiratot', + 'Linz', + 'Arroyo Naranjo', + 'Bukit Mertajam', + 'Dongning', + 'Rostock', + 'Kapra', + 'Yonkers', + 'Burutu', + 'Mostoles', + 'Moreno Valley', + 'Thousand Oaks', + 'Legazpi City', + 'Fontana', + 'Panabo', + 'Puerto Cabello', + "Ich'on", + 'Beersheba', + 'Bila Tserkva', + 'Santo Agostinho', + 'Oulu', + 'Luziania', + 'Ciputat', + 'Guarenas', + 'Mohammedia', + 'Babruysk', + 'Taisheng', + 'Sunyani', + 'Lubuklinggau', + 'Ashaiman', + 'Ambala', + 'Zamora', + 'Chungju', + 'Kasangati', + 'Kharagpur', + 'Farshut', + 'Monywa', + 'Nishitokyo', + 'Robertsonpet', + 'Dindigul', + 'Milton Keynes', + 'Marawi City', + 'Morogoro', + 'Raniwara Kalan', + 'Solihull', + 'Parakou', + 'Damietta', + 'Shimla', + 'Padova', + 'Banjar', + 'Cidade de Nacala', + 'Passo Fundo', + 'Dinajpur', + 'Hospet', + 'Islington', + 'Talca', + 'Hickory', + 'Amarillo', + 'Ifakara', + 'Pamplona', + 'Northcote', + 'Maldah', + 'San Carlos City', + 'Jiutai', + 'Phan Thiet', + 'Puqi', + 'Khan Yunis', + 'Ongole', + 'Brahmanpara', + 'Biskra', + 'Bingerville', + 'Betigeri', + 'Sioux Falls', + 'Mpanda', + 'Ternate', + 'Kassel', + 'Sakaka', + 'Sejong', + 'Quetzaltenango', + 'Coquimbo', + 'Tekirdag', + 'Luzhang', + 'Kodumur', + 'Kukawa', + 'Geneva', + 'Huntington', + 'Ellore', + 'Evansville', + 'Kinh Mon', + 'Birjand', + 'Barrancabermeja', + 'La Guaira', + 'Loja', + 'Mandi Burewala', + 'Lauro de Freitas', + 'Mazabuka', + 'Deoghar', + 'Tanjungpinang', + 'Phu Tu Son', + 'Chhindwara', + 'Iringa', + 'Lingampalli', + 'Waterbury', + 'Mokameh', + 'Luxor', + 'Arica', + 'Las Tunas', + 'Qal`at Bishah', + 'Frisco', + 'Ha Tinh', + 'Richmond Hill', + 'Timayy al Imdid', + 'Al Khums', + 'Charleroi', + 'Lorain', + 'Matsue', + 'Tarakan', + 'Loures', + 'Pingzhen', + 'Radom', + 'Petropavl', + 'Rio Claro', + 'Maroua', + 'Cajamarca', + 'Qina', + "Mai'Adua", + 'Hebron', + 'Puri', + 'Sidfa', + 'Soio', + 'Menemen', + 'Kalamazoo', + 'Haldia', + 'Jacobabad', + 'Khandwa', + 'Aberdeen', + 'Huacho', + 'Almeria', + 'Yachiyo', + 'Nandyal', + 'Pulimaddi', + 'Georgetown', + 'Morena', + 'Galveston', + 'Nasim Shahr', + 'Cosenza', + 'Guacara', + 'Kabankalan', + 'Nagareyama', + 'Aracatuba', + 'Vinh Long', + 'Lang Son', + 'Az Zawiyah', + 'Isanlu', + 'Rio Cuarto', + 'Lochau', + 'Karjat', + 'At Taji', + 'Spartanburg', + 'Lahad Datu', + 'Drabar', + 'Madiun', + 'Santa Tecla', + 'Santa Barbara', + 'Pristina', + 'Uripa', + 'Khowy', + 'Gbadolite', + 'Huangyan', + 'Laqtah', + 'Amroha', + 'Lunga-Lunga', + 'Trieste', + 'Sunrise Manor', + 'Torun', + 'Martapura', + 'Rani', + 'Kankan', + 'Chakradharpur', + 'Helong', + 'Segamat', + 'Bhiwani', + 'Bhind', + 'Huntington Beach', + 'Hobart', + 'Tocuyito', + 'Baure', + 'Higashi-Hiroshima', + 'Marica', + 'Grand Prairie', + 'Ciudad Madero', + 'Itami', + 'Zakhu', + 'Kodaira', + 'Rajin', + 'Alcala de Henares', + 'Parma', + 'Overland Park', + 'Huanuco', + 'Kusong', + 'Brescia', + 'Zipaquira', + 'Khammam', + 'Kouribga', + 'McKinney', + 'Madhyamgram', + 'Sinop', + 'Kajo Kaji', + 'Viransehir', + 'Ghandinagar', + 'Rzeszow', + 'Prato', + 'Waco', + 'Acarigua', + 'Myawadi', + 'Mwene-Ditu', + 'Karakopru', + 'Parachinar', + 'Koronadal', + 'La Serena', + 'Maharagama', + 'San Pedro de Macoris', + 'Liege', + 'Hagerstown', + 'Suzuka', + 'Baharampur', + 'Tchitato', + 'Malema', + "N'Zerekore", + 'Mbarara', + 'Morbi', + 'Cuautla', + 'Anseong', + 'Guanajuato', + 'Tebessa', + 'Kamirenjaku', + 'Holon', + 'Pingtung', + 'Peterborough', + 'Tanauan', + 'Nampa', + 'Suhaj', + 'Pandhurna', + 'Bene Beraq', + 'Sosnowiec', + 'Bukan', + 'Mus', + 'Kumagaya', + 'La Plata', + 'Bani Suwayf', + 'Lae', + 'Quelimane', + 'Hyesan', + 'Beni Mellal', + 'Jalapa', + 'Guanare', + 'Kaesong', + 'Nossa Senhora do Socorro', + 'Castanhal', + 'Croydon', + "Arba Minch'", + 'Rio Grande', + 'Gorontalo', + 'Florencia', + 'Fianarantsoa', + 'Tsing Yi Town', + 'Yamaguchi', + 'Iwo', + 'Rae Bareli', + 'Godoy Cruz', + 'Ciudad del Carmen', + 'Daman', + 'Valera', + 'Ouargla', + 'Cedar Rapids', + 'Manzanillo', + 'Malaybalay', + 'Isidro Casanova', + 'Chibia', + 'Leganes', + 'Hino', + 'Orai', + 'Shahr-e Kord', + 'Jhelum', + 'Mahbubnagar', + 'Pabna', + 'Cap-Haitien', + 'Nova Friburgo', + 'Saddiqabad', + 'Ngaoundere', + 'Hagen', + 'Chongju', + 'Paradise', + 'Poza Rica de Hidalgo', + 'Murtazabad', + 'Rajendranagar', + 'Las Heras', + 'Odawara', + 'Abu Ghurayb', + 'Anjomachi', + 'Araure', + 'Donostia', + 'Fuenlabrada', + 'Pinar del Rio', + 'Kenema', + 'Digos', + 'El Progreso', + 'Al Hasakah', + 'San Francisco de Macoris', + 'Taranto', + 'Prabumulih', + 'Kishiwada', + 'Iquique', + 'Dese', + 'Gharyan', + 'Kecskemet', + 'Numazu', + 'Ratanpur', + 'Bournemouth', + 'Bhusaval', + 'Tottori', + 'Alvorada', + 'Joetsu', + 'Chaedok', + 'Guatire', + 'Chilpancingo', + 'Kofu', + 'Ucu Seles', + 'Calbayog City', + 'Kirikkale', + 'Burlington', + 'Kielce', + 'Ocala', + 'Itabuna', + 'Kairouan', + 'Klerksdorp', + 'Pasuruan', + 'Bahraigh', + 'Ed Damazin', + 'Suva', + 'Basildon', + 'Getafe', + 'Cachoeiro de Itapemirim', + 'Potsdam', + "St. John's", + 'Erie', + 'Umreth', + 'Dunhuang', + 'Semnan', + 'Narsingdi', + 'Newport News', + 'Temirtau', + 'Banja Luka', + 'Ittikara', + 'Yei', + 'Mahesana', + 'Frederick', + 'Kuchlagh', + 'Murfreesboro', + 'Ferraz de Vasconcelos', + 'Bolu', + '`Unayzah', + 'Pak Kret', + 'Seixal', + 'Al Qamishli', + 'Padalarang', + 'Modena', + 'Breda', + 'Toyokawa', + 'Vinh Chau', + 'Siguiri', + 'Cuango', + 'Raiganj', + 'Fernando de la Mora', + 'Trang Bang', + 'Aqtau', + "Santa Barbara d'Oeste", + 'Batala', + 'Nis', + 'Oradea', + 'Tumpat', + 'Malumfashi', + 'Isiro', + 'Pinrang', + 'Fort Lauderdale', + 'Jaragua do Sul', + 'Sirsa', + 'Morsi', + 'Donghua', + 'Odense', + 'Noumea', + 'Dinapore', + 'Sorsogon', + 'Guarapuava', + 'Tambaram', + 'Bethelsdorp', + 'Saarbrucken', + 'Karaikkudi', + 'Shrirampur', + 'Braga', + 'Epe', + 'Kelowna', + 'Plzen', + 'Fardis', + 'Himatnagar', + 'Kindia', + 'Tachikawa', + 'Tempe', + 'Thanhlyin', + 'Turbo', + 'La Rioja', + 'Guna', + 'Hamm', + 'Nawada', + 'Cuauhtemoc', + 'Ploiesti', + 'Inisa', + 'Berazategui', + 'Ikot Ekpene', + 'Funtua', + 'Obuase', + 'Toulon', + 'Jaunpur', + 'Mbanza Kongo', + 'Edirne', + 'Longjing', + 'Geelong', + 'Lhokseumawe', + 'Mahad', + 'Madanapalle', + 'Danbury', + 'Palopo', + 'Petarukan', + 'Guri', + 'Singosari', + 'Quang Yen', + 'Tongjiang', + 'Longjin', + 'Santander de Quilichao', + 'Wadlakonda', + 'Bhachau', + 'Shivpuri', + 'Caluquembe', + "Hosa'ina", + 'Tanjungbalai', + 'Budhanilkantha', + 'Uji', + 'Mongu', + 'Divo', + 'Calabar', + 'Reims', + 'Dosquebradas', + 'Roxas City', + 'Masan', + 'Purwakarta', + 'Satara', + 'El Khroub', + 'Tiaret', + 'Cuautitlan', + 'Spring Hill', + 'Njeru', + 'Torbali', + 'Ilheus', + 'Al `Arish', + 'Langsa', + 'Gastonia', + 'Phillaur', + 'Quevedo', + 'Tebingtinggi', + 'Kandi', + 'Nijmegen', + 'Unnao', + 'Dundo', + 'Meiktila', + 'Salinas', + 'Sitapur', + 'La Pintana', + 'Ambato', + 'Almada', + 'Riobamba', + 'Kalamboli', + 'Ciudad Valles', + 'Fredericksburg', + 'Maidstone', + 'San Luis Rio Colorado', + 'Letpandan', + 'Al Juwayyidah', + 'Cianjur', + 'Ontario', + 'Ar Rahmaniyah', + 'Waraseoni', + 'Castellon de la Plana', + 'Leon', + 'Mauli', + 'Harnaut', + 'Bejaia', + 'Elk Grove', + 'Biu', + 'Arafat', + 'Rantau Prapat', + 'Catumbela', + 'Shibirghan', + 'El Bosque', + 'Santa Maria Texmelucan', + 'Matosinhos', + 'Navadwip', + 'Salatiga', + 'Maragheh', + 'Kotdwara', + 'Amadora', + 'Durres', + 'Chicoloapan', + 'Khapalu', + 'Bodrum', + 'Yangmei', + 'Pilibhit', + 'Sirjan', + 'Narashino', + 'Cary', + 'Curug', + 'Rancho Cucamonga', + 'Kangqiao', + 'Timon', + 'Burgos', + 'Dagupan City', + 'Ludwigshafen', + 'Bac Giang', + 'Alleppey', + 'Ada', + 'Habaswein', + 'Gliwice', + 'Piedras Negras', + 'Linjiang', + 'Carupano', + 'Bida', + 'Sakura', + 'Townsville', + 'Oceanside', + 'Cuddalore', + 'Patra', + 'Basel', + 'Tlemcen', + 'Lubao', + 'Mexico', + 'Gondal', + 'Shahin Shahr', + 'Deo', + 'Albacete', + 'Fenglu', + 'Keningau', + 'Akhisar', + 'Podgorica', + 'Sherbrooke', + 'Kamakurayama', + 'Ha Long', + 'Oldenburg', + 'Silchar', + 'Chirala', + 'Gadag', + 'Santander', + 'Saint-Etienne', + 'Mang La', + 'Hitachi', + 'Jabalya', + 'Polomolok', + 'Ongata Rongai', + 'Sacaba', + 'General Mariano Alvarez', + 'Mulheim', + 'Lagos de Moreno', + 'Tiruvannamalai', + 'Kindu', + 'Kaolack', + 'Bidar', + 'Baranavichy', + 'Bade', + 'Talhar', + 'Izumo', + 'Rafah', + 'Bir el Djir', + 'Ait Melloul', + 'Oeiras', + 'Alcorcon', + 'Cazanga', + 'Garden Grove', + 'Kempton Park', + 'Al Kufah', + 'Araguaina', + 'Metro', + 'Nawsari', + 'Surigao', + 'Ercis', + 'Reggio di Calabria', + 'Makurdi', + 'Bao Loc', + 'Kohat', + "Petite Riviere de l'Artibonite", + 'Hemet', + 'Pembroke Pines', + 'Ibirite', + 'Hinthada', + 'Nqutu', + 'Escuintla', + 'Fusagasuga', + 'Malayer', + 'Olsztyn', + 'Tomakomai', + 'Aplahoue', + 'Valsad', + 'Thingangyun', + 'As Suwayq', + 'Metouia', + 'San Luis', + 'Barra Mansa', + 'Cape Coast', + 'Magwe', + 'Urayasu', + 'Puerto Montt', + 'Reggio Emilia', + 'Vallejo', + 'Al Marj', + 'Sahab', + 'Medinipur', + 'Sosan', + 'Talas', + 'Minbya', + 'Chuo-ku', + 'Santa Rita', + 'Batumi', + 'Bielsko-Biala', + 'Chetumal', + 'Nishio', + 'Medford', + 'Damoh', + 'Kalale', + 'Kroonstad', + 'Toliara', + 'Bayamon', + 'Calabozo', + 'Baliuag', + 'Haripur', + 'Mahabad', + 'Neyveli', + 'Bordj Bou Arreridj', + 'Mauldin', + 'Karaman', + 'Moratuwa', + 'Francisco Morato', + "Huich'on", + 'Ilford', + 'Kasama', + 'Gondomar', + 'Malanville', + 'Baramula', + 'Porto Seguro', + 'Jamalpur', + 'Riohacha', + 'Catape', + 'Hirosaki', + 'Villa Canales', + 'Malkapur', + 'Katha', + 'Oyama', + 'Basuo', + 'Jind', + 'Angra dos Reis', + 'Phan Rang-Thap Cham', + 'Osnabruck', + 'Itapecerica da Serra', + 'Mogok', + 'Fethiye', + 'Itu', + 'Al Qurayyat', + 'Jutiapa', + 'Palmdale', + 'Chandannagar', + 'Muskegon', + 'Cerkezkoy', + 'Linhares', + 'Tiantoujiao', + 'Sampit', + 'Uppsala', + 'Villanueva', + 'Adoni', + 'Alasandigutta', + 'Tuguegarao', + 'Siirt', + 'Kuytun', + 'Leesburg', + 'Offa', + 'Ipiales', + 'Le Havre', + 'Sudbury', + 'Ratnapura', + 'Niiza', + 'Takaoka', + 'Leverkusen', + 'Kushiro', + 'Iwata', + 'Obihiro', + 'Sao Caetano do Sul', + 'Sawangan', + 'Bechar', + "K'ebri Beyah", + 'Korfez', + 'Singida', + 'Warrington', + 'Udipi', + 'Saqqez', + 'Fyzabad', + 'Kokshetau', + 'Ebo', + 'Manavgat', + 'Fukang', + 'Idlib', + 'Sawai Madhopur', + 'Lajes', + 'Tenali', + 'Cienfuegos', + 'High Point', + 'Bocoio', + 'Abengourou', + 'Tuscaloosa', + 'Conjeeveram', + 'Hadano', + 'Chillan', + 'Abu Hulayfah', + 'Madhubani', + 'Arnhem', + 'Quibala', + 'Proddatur', + 'Baubau', + 'San Martin Texmelucan de Labastida', + 'Tunja', + 'Teresopolis', + 'San Marcos', + 'Pocos de Caldas', + 'Sultanpur Mazra', + 'Visalia', + 'Wapi', + 'Blida', + 'Sidon', + 'Wau', + 'Tokat', + 'Garissa', + 'Pocheon', + 'Skikda', + 'Muridke', + 'Muzaffargarh', + 'Kebili', + 'Turgutlu', + 'Jizzax', + 'Ungaran', + 'Kyaunggon', + 'Huddersfield', + 'Ube', + 'Bandar-e Mahshahr', + 'Nazilli', + 'Simao', + 'Anaco', + 'Marysville', + 'Golcuk', + 'Haarlem', + 'Boma', + 'Tuxtepec', + 'Sullana', + 'San Andres Tuxtla', + 'Heidelberg', + 'Darmstadt', + 'Parnaiba', + 'Mukono', + 'Hala', + 'Godhra', + 'Rafsanjan', + 'Sariaya', + 'Multai', + 'Perugia', + 'Nador', + 'Tema', + 'Zemun', + 'Ndalatando', + 'Salihli', + 'Daule', + 'Rajapalaiyam', + 'Zhanlicun', + 'Pangzawl', + 'Bontang', + 'Jinggang', + 'Ash Shihaniyah', + 'Papantla de Olarte', + 'San Miguel del Padron', + 'Tulancingo', + 'Tacheng', + 'Tan Phu', + 'Naic', + 'Liancheng', + 'General Roca', + 'Zaranj', + 'Al Ghardaqah', + 'Kidapawan', + 'Chittoor', + 'Braganca Paulista', + 'Solingen', + 'Merced', + 'Pindamonhangaba', + 'Hayward', + 'Split', + 'Ziarat', + 'Giron', + 'Miyakonojo', + 'Dong Hoi', + 'Tra Vinh', + 'Khanpur', + 'Ferkessedougou', + 'Southend', + 'Ciudad Acuna', + 'Jose Maria Ezeiza', + 'Khost', + 'Koudougou', + 'Saint-Marc', + 'Ninh Binh', + 'Bingol', + 'Dhamar', + 'Sivakasi', + 'Huaycan', + 'San Nicolas de los Arroyos', + 'Osorno', + 'Milagro', + 'Ceyhan', + 'Moga', + 'Ede', + 'Ekibastuz', + 'Barreiras', + 'Enschede', + 'Newport', + 'Chirchiq', + 'Dijon', + 'Jijiga', + 'Patos de Minas', + 'Budaun', + 'Ramat Gan', + 'Uttarpara', + 'Catamarca', + 'La Laguna', + 'Daltonganj', + 'Quipungo', + 'Jequie', + 'Benoni', + 'Macuspana', + 'Zhengding', + 'Aral', + 'Cadiz', + 'Matsuzaka', + 'Klaipeda', + 'Ogaki', + 'Corona', + 'Zabrze', + 'Bharuch', + 'Ilagan', + 'Abaetetuba', + 'Guimaraes', + 'Ibarra', + 'Paterson', + 'Gojra', + 'Banha', + 'Mahlaing', + 'Calama', + "'s-Hertogenbosch", + 'Grenoble', + 'Amersfoort', + 'Erzincan', + 'Regensburg', + 'George', + 'Herne', + 'Bima', + 'Mandi Bahauddin', + 'Chau Doc', + 'Angers', + 'Itapetininga', + 'Xiaping', + 'Caxias', + 'Villeurbanne', + 'Nablus', + 'Nan Zhuang', + 'Zaanstad', + 'Guaymas', + 'Enfield', + 'Kamina', + 'Molo', + 'Macon', + 'Saharsa', + 'Chaoshan', + 'Ketou', + 'Rio das Ostras', + 'Adzope', + 'Portmore', + 'Binghamton', + 'Qalyub', + 'Danao', + 'Marbella', + 'Ghorahi', + 'Lakewood', + 'Bac Lieu', + 'Capas', + 'Cam Pha', + 'Al Miqdadiyah', + 'Vidisha', + 'Pathankot', + 'Nowgong', + 'Ravenna', + 'Ar Ramtha', + 'Borazjan', + 'Tigaraksa', + 'Kisi', + 'Esmeraldas', + 'Horad Barysaw', + 'Souk Ahras', + 'Daiwanishi', + 'Chlef', + 'Pandi', + 'Camarajibe', + 'Odessa', + 'El Eulma', + 'Salzburg', + 'Thanesar', + 'Danzao', + 'Camacupa', + 'Kishangarh', + 'Uiwang', + 'Hanam', + 'Paderborn', + 'Zango', + 'Braila', + 'Barrie', + 'Sunnyvale', + 'Saint-Louis', + 'Edremit', + 'Rudarpur', + 'Kitenkela', + 'Tindwara', + 'Bandirma', + 'Nalgonda', + 'Jinghai', + 'Hitachi-Naka', + 'Lucapa', + 'Neuss', + 'Noda', + 'Santana de Parnaiba', + 'Ambikapur', + 'Madinat as Sadis min Uktubar', + 'Dibrugarh', + 'Singaraja', + 'Moanda', + 'Seogwipo', + 'Palo Negro', + 'New Bedford', + 'Veraval', + 'Mogi Guacu', + 'Hoeryong', + 'Abbotsford', + 'Kirsehir', + 'Tochigi', + 'Betul Bazar', + 'Andong', + 'Balurghat', + 'Bytom', + 'Jorhat', + 'Poblacion', + 'Ixtlahuaca', + 'Kariya', + 'Nevsehir', + 'Krishnanagar', + 'Dutse', + 'Ueda', + 'Livorno', + 'Tete', + 'Vinh Yen', + 'Barakpur', + 'Hollywood', + 'Sinpo', + 'Pouso Alegre', + 'Ciudad Choluteca', + 'Hoa Thanh', + 'Alagoinhas', + 'Mudon', + 'Amatitlan', + 'Gulu', + 'Gwangyang', + 'South Lyon', + 'Imabari', + 'Kawashiri', + 'Oxford', + 'Bordj el Kiffan', + 'Go Cong', + 'Erdemli', + 'Gonbad-e Kavus', + 'Al Manaqil', + 'Shantipur', + 'Dila', + 'Hindupur', + 'Araucaria', + 'Matanzas', + 'Beawar', + 'Long Khanh', + 'Bhalswa Jahangirpur', + 'As Suwayhirah as Sahil', + 'Tauranga', + 'Erode', + 'Escondido', + 'Lake Charles', + 'Dahuaishu', + 'Minglanilla', + 'Chichicastenango', + 'Duc Pho', + 'Copiapo', + 'Tafeng', + 'Mahmutlu', + 'Buyuk Cakirman', + 'Bugdayli', + 'Eminabad', + 'Kragujevac', + 'Pasadena', + 'Bellevue', + 'Logrono', + 'Delicias', + 'Talcahuano', + 'Piedecuesta', + 'Higashimurayama', + 'Ipokia', + 'Jaranwala', + 'Nangloi Jat', + 'Joliet', + 'Kukichuo', + 'Badajoz', + 'Champaign', + 'Fengyicun', + 'Shahrud', + 'Mzuzu', + 'Valle de Santiago', + 'Dong Xoai', + 'Valdivia', + 'Golbasi', + 'Naogaon', + 'Kashikishi', + 'El Minie', + 'Borj Hammoud', + 'Auchi', + 'Chauk Azam', + 'Yilan', + 'Sievierodonetsk', + 'Urganch', + 'Ocumare del Tuy', + 'Willemstad', + 'Bavaro', + 'Soro', + 'Penjamo', + 'Mariveles', + 'Pomona', + 'Saumlaki', + 'Villa de Alvarez', + 'Levis', + 'Fairfield', + 'Asaba', + 'Kerch', + 'Concordia', + 'Mesquite', + 'Lashio', + 'Elkhart', + 'Bohicon', + 'Harrow', + 'Rimini', + 'Port Louis', + 'Agri', + 'Naperville', + 'Maimanah', + 'Musashino', + 'Kastamonu', + 'St. George', + 'Sagay', + 'Roseville', + '`Ajlun', + 'Marvdasht', + 'Melitopol', + 'Potchefstroom', + 'Coquitlam', + "Nek'emte", + 'Xianshuigu', + 'Nuzvid', + 'Abbottabad', + 'Larisa', + 'Ramapo', + 'Coro', + 'Sayama', + 'Taza', + 'Jean-Rabel', + 'Al `Aqabah', + 'Dundee', + 'Sitarganj', + 'Dongguazhen', + 'Topeka', + 'Al Hawiyah', + 'Cagliari', + 'Nimes', + 'Luleburgaz', + 'Consolacion', + 'Maridi', + 'Quilpue', + 'Rafael Castillo', + 'Zhangaozen', + 'Nchelenge', + 'Szombathely', + 'Kutaisi', + 'Komaki', + 'Kiambu', + 'Siem Reap', + 'Hajipur', + 'Pesqueria', + 'Mati', + 'Aix-en-Provence', + 'Malakal', + 'Chingola', + 'Milas', + 'La Lisa', + 'Kafr ash Shaykh', + 'Tipitapa', + 'Clermont-Ferrand', + 'Hung Yen', + 'Tama', + 'Dongsheng', + 'Habra', + 'Yonago', + 'Kramatorsk', + 'Pageralam', + 'Kalemie', + 'Colima', + 'Dawei', + 'Maquela do Zombo', + 'Wamba', + 'Warner Robins', + 'Cairns', + 'Xinjing', + 'Cam Ranh', + 'Bir', + 'Florencio Varela', + 'Keren', + 'Dar`a', + 'West Bromwich', + 'Derince', + 'Gandajika', + 'Colina', + 'Dadu', + 'Pleiku', + 'Amreli', + 'Taungdwingyi', + 'Narnaul', + 'Jyvaskyla', + 'Chitaldrug', + 'Calapan', + 'Franco da Rocha', + 'Mostaganem', + 'Paco do Lumiar', + 'Etah', + 'Bani', + 'Surprise', + 'Gloucester', + 'Quchan', + 'Vila Junqueiro', + 'Torrance', + 'Eregli', + 'Foggia', + 'Iruma', + 'Abohar', + 'Thanatpin', + 'Miskolc', + 'Bhandaria', + 'Teixeira de Freitas', + 'Villa de Cura', + 'Facatativa', + 'Arad', + 'Fujita', + 'Le Mans', + 'Kisaran', + "Khairpur Mir's", + 'Bukoba', + 'Kaithal', + 'Arayat', + 'Poole', + 'Comayagua', + 'Yima', + 'Moshi', + 'Saguenay', + 'Urdaneta', + 'Boca del Rio', + 'Odivelas', + 'Xintang', + 'Barranca', + 'Balasore', + 'Guelph', + 'Zhaxi', + 'Mehtar Lam', + 'Al Mukalla', + 'Dar Naim', + 'Cinere', + 'Pinetown', + 'Asaka', + 'Ramu', + 'Mallapalli', + 'Kakamigahara', + 'Aalborg', + 'Koiridih', + 'Ciego de Avila', + 'Bandundu', + 'Disuq', + 'Calabayan', + 'Coimbra', + 'Ghazni', + 'Zhaoxiang', + 'Ruse', + 'Touggourt', + 'Shillong', + 'Houma', + 'Cizre', + 'Malasiqui', + 'Lleida', + 'Sannar', + 'Rewari', + 'Paghman', + 'Birkenhead', + 'Jinjiang', + 'Tinipuka', + 'Cartago', + 'Ashikaga', + 'Stara Zagora', + 'Telford', + 'Huelva', + 'Garanhuns', + 'Hazaribagh', + 'Moundou', + 'Trindade', + 'Nizip', + 'Nawabganj', + 'Toda', + 'Fullerton', + 'Lichinga', + 'Settat', + 'Bafra', + 'Bhimavaram', + 'Negombo', + 'Olathe', + 'Okinawa', + 'Namacunde', + 'Boca Chica', + 'Altay', + 'Bahawalnagar', + 'Misato', + 'Olmaliq', + 'Moriguchi', + 'Preston', + 'Thornton', + 'Mandsaur', + 'Jahrom', + 'Bondoukou', + 'Lausanne', + 'Bocaue', + 'Khuzdar', + 'Tepatitlan de Morelos', + 'Pemba', + 'Elbistan', + 'Bilbays', + 'Pitesti', + 'Gweru', + 'Tan Chau', + 'Numan', + 'Kamalshahr', + 'Rize', + 'Subang', + 'Villupuram', + 'Ingolstadt', + 'Las Maravillas', + 'Greeley', + 'Tabaco', + 'Fukayacho', + 'Beaumont', + 'Nsele', + 'Las Cruces', + 'Porac', + 'Mejicanos', + 'Krugersdorp', + 'Middlesbrough', + 'Shizhaobi', + 'Paranagua', + "Samarra'", + 'Iguala de la Independencia', + 'Ozamiz City', + 'Harchandpur', + 'Yaritagua', + 'Midland', + 'Kumbakonam', + 'Metairie', + 'Torbat-e Heydariyeh', + 'Xiangcheng', + 'Batu Pahat', + 'Nahiyat Ghammas', + 'Peristeri', + 'Darwin', + 'Reykjavik', + 'Atbara', + 'Kanasin', + 'Gia Rai', + 'Payatas', + 'Debre Birhan', + 'La Romana', + 'Aul', + 'Masaya', + 'Malambo', + 'Momostenango', + 'Pakpattan', + 'Botucatu', + 'Jicheon', + 'Tanay', + 'Blackpool', + 'Carolina', + 'Trois-Rivieres', + 'Balneario de Camboriu', + 'Balkanabat', + 'Dos Hermanas', + 'Apeldoorn', + 'Pantanal', + 'West Valley City', + 'Ishizaki', + 'Carsamba', + 'Kuwana', + 'Orange', + 'Warren', + 'Gemena', + 'Sancti Spiritus', + 'Whitby', + 'Cambridge', + 'Kolar', + 'Grand Junction', + 'Medea', + 'Teluknaga', + 'Tarragona', + 'Koga', + 'Dipolog', + 'Dabou', + 'Tsuchiura', + 'Tyler', + 'Jacmel', + 'Chicacole', + 'Montero', + 'Koutiala', + 'Shunan', + 'Candelaria', + 'Silivri', + 'Mthatha', + 'Gaziemir', + 'Brusque', + 'Tours', + 'Igdir', + 'Gunungsitoli', + 'Negage', + 'Teofilo Otoni', + 'La Trinidad', + 'Bankura', + 'Mandya', + 'Palhoca', + 'Norrkoping', + 'Jolo', + 'Kusatsu', + 'Cunduacan', + 'Dehri', + 'Hampton', + 'Sinfra', + 'Myebon', + 'Atibaia', + 'Quillacollo', + 'Medina Estates', + 'Stockport', + 'Kanata', + 'Rangkasbitung', + 'Porto Amboim', + 'Mino', + 'Durgauti', + 'Curico', + 'Vila Franca de Xira', + 'Igboho', + 'Gingoog', + 'Phu Ly', + 'Marivan', + 'Huehuetenango', + 'Barrechid', + 'San Justo', + 'Shizuishan', + 'Mainpuri', + 'Nasugbu', + 'Bloomington', + 'Quimbele', + 'Varginha', + 'Port-Gentil', + 'Carcar', + 'Qabr as Sitt', + "Chech'on", + 'Campo Largo', + 'San Jose del Cabo', + 'Cachoeirinha', + 'Termiz', + 'Zinacantepec', + 'Batang', + 'Bacau', + 'Norzagaray', + 'Yaizu', + 'Talaivasal', + 'Kisarazu', + 'Agcabadi', + 'Birganj', + 'Disa', + 'Tobruk', + 'Elizabeth', + 'Ebina', + 'Gitega', + 'Rionegro', + 'Stamford', + 'Nkongsamba', + 'Yuma', + 'Raigarh', + 'Yalova', + 'Maia', + 'Ituzaingo', + 'Tay Ninh', + 'Kigoma', + 'Kent', + 'Miramar', + 'Andimeshk', + 'Tizi Ouzou', + 'Agboville', + 'Siwan', + 'Maldonado', + 'Ipetumodu', + 'Shahreza', + 'Zabol', + 'Inazawa', + 'Caraguatatuba', + 'Pyay', + 'Silopi', + 'Djakotome', + 'El Oued', + 'Moron', + 'Bern', + "Coeur d'Alene", + 'Ashqelon', + 'Minoo', + 'Mabacun', + 'Laghouat', + 'Salto', + 'Sibiu', + 'Brighton', + 'Zafarwal', + 'Londuimbali', + 'Cameta', + 'Vitoria de Santo Antao', + 'Dumaguete City', + 'Navoiy', + 'Marianao', + 'Luuq', + 'Ba Don', + 'Gubeng', + 'Daraga', + 'Veszprem', + 'Famalicao', + "Debre Mark'os", + 'Tiraspol', + 'Coral Springs', + 'Ruda Slaska', + 'Rybnik', + 'Idfu', + 'Tokha', + 'Sterling Heights', + 'Kalol', + 'San Andres', + 'Marituba', + 'Amiens', + 'Yunxian Chengguanzhen', + 'Ferfer', + 'Renca', + 'Segou', + 'Jau', + 'Tando Allahyar', + 'Thandwe', + 'Hagonoy', + 'Hassan', + 'Batu Gajah', + 'Matagalpa', + 'Lalitpur', + 'Conchali', + 'Santa Cruz do Sul', + 'Long Binh', + 'Pitalito', + 'Bibemi', + 'Naga', + 'Porto-Novo', + 'Yuba City', + 'Khorramshahr', + 'Tarime', + 'Male', + 'Parla', + 'Milton', + "M'Sila", + 'Sripur', + 'Kipushi', + 'Gondia', + 'Zhangmu Touwei', + 'Schaarbeek', + 'Luxembourg', + 'Rehovot', + 'San Carlos', + 'Sao Mateus', + 'Dalupura', + 'Mogaung', + 'Odemis', + 'Centro Habana', + 'Zagnanado', + 'Isahaya', + 'Yakima', + 'Adonara', + 'Talavera', + 'Rustavi', + 'Carrollton', + 'Aware', + 'Naryai ka Puri', + 'Blitar', + 'Racine', + 'Karabuk', + 'Palwal', + 'Ome', + 'Chicomba', + 'Johnson City', + 'Annecy', + 'Papeete', + 'Cubatao', + 'Conselheiro Lafaiete', + 'Ji-Parana', + 'Al Khmissat', + 'Billings', + 'Jijel', + 'Furth', + 'Buea', + 'Apopa', + 'Itapipoca', + 'Spanish Town', + 'Lam Tin', + 'Palghat', + 'Atyrau', + 'Araras', + 'Maijdi', + 'Kusadasi', + 'Vlore', + 'Quibdo', + 'Marand', + 'Bassila', + 'Thaton', + 'Zama', + 'Chittandikavundanur', + 'Iowa City', + 'Nanqiaotou', + 'Shuangcheng', + 'Surat Thani', + 'Narita', + 'Lao Cai', + 'Trinidad', + 'Innsbruck', + 'Kozan', + 'Angono', + 'Silay', + 'Anand', + 'Jiroft', + 'City of Isabela', + 'Nantou', + 'Los Guayos', + 'Inezgane', + 'Arcahaie', + 'Botad', + 'Abiko', + 'Tabarre', + 'Udon Thani', + 'Baiyashi', + 'Mojokerto', + 'Dover', + 'Onomichi', + 'Lucheng', + 'Apucarana', + 'Jamundi', + 'Ergani', + 'Relizane', + 'Polokwane', + 'Aaley', + 'Cili', + 'Battambang', + 'Taldyqorghan', + 'Huejutla de Reyes', + 'Bongaigaon', + 'Bellingham', + 'Mukerian', + 'Zwolle', + 'Girardot', + 'Vespasiano', + 'Limoges', + 'Ponnagyun', + 'Sukrah', + 'Araruama', + 'Cayirova', + 'Hanumangarh', + 'Jetpur', + 'Arcot', + 'Kokubunji', + 'Amherst', + 'Kanchrapara', + 'Parepare', + 'Cienaga', + 'Sabara', + 'Chinguar', + 'Ferrara', + 'Antsiranana', + 'Tottenham', + 'Mansa', + 'Jamaame', + 'Petapa', + 'Mataro', + 'Cholula de Rivadabia', + 'Idanre', + 'Bamban', + 'Harar', + 'Sarhari', + 'Guadalajara de Buga', + 'Dortyol', + 'Ulm', + 'Braganca', + 'Mubi', + 'Guagua', + 'Lynchburg', + 'Songnim', + 'Bat Yam', + 'Osaki', + 'Vasteras', + 'Puno', + 'Hoshangabad', + 'Tariba', + 'Saida', + 'Heilbronn', + 'Chas', + 'Apatzingan de la Constitucion', + 'Tuaran', + 'Rudnyy', + 'Khanna', + 'Ahmadpur East', + 'Wazirabad', + 'Avrankou', + 'Vihari', + 'Guasdualito', + 'Mosquera', + 'Garut', + 'Votorantim', + 'Buon Ho', + 'Abaji', + 'Salmas', + 'Pforzheim', + 'Wurzburg', + 'Jazan', + 'Norman', + 'Santa Lucia Cotzumalguapa', + 'Guimba', + 'Simi Valley', + 'Latina', + 'Zhaozhou', + 'Dessalines', + 'San Ignacio', + 'Ciudad Sandino', + 'Allada', + 'Iwakuni', + 'Nagda', + 'Bam', + 'Opole', + 'Kayes', + 'Koforidua', + 'Seto', + 'Omiyacho', + 'Misserete', + 'Koganei', + 'Salerno', + 'Torrejon de Ardoz', + 'Nahiyat Khan Bani Sa`d', + 'Angren', + 'Pakokku', + 'Leiria', + 'Sertaozinho', + 'Hardoi', + 'Nemby', + 'Kamez', + 'Unye', + 'Fuyuan', + 'Duitama', + 'Gurabo al Medio', + 'Ajax', + 'Barcarena Nova', + 'Catabola', + 'Ksar El Kebir', + 'Orebro', + 'My Drarga', + 'Fort Smith', + 'Suhum', + 'Jandira', + 'Abilene', + 'Valinhos', + 'Altamira', + 'Guntakal', + 'Mary', + 'Iizuka', + 'Pithampur', + 'Karatepe', + 'Wolfsburg', + 'Rosetta', + 'Arecibo', + 'Giresun', + 'Kombolcha', + 'Payakumbuh', + 'Patan', + 'Bonao', + 'Barbacena', + 'Zoetermeer', + 'Basirhat', + 'Resende', + 'Nzega', + 'Villa Alemana', + 'Gashua', + 'Polatli', + 'Lewisville', + 'Larache', + 'Kristiansand', + 'Az Zulfi', + 'Jilib', + 'Cerro', + 'Halisahar', + 'Magelang', + 'Jagadhri', + 'Tychy', + 'Juticalpa', + 'Jizhou', + 'Leuwiliang', + 'Koidu', + 'Guarapari', + 'Pinsk', + 'Sunam', + 'Ouahigouya', + 'Rishra', + 'Grand-Bassam', + 'Jharsugra', + 'Leeuwarden', + 'Pearland', + 'Ben Tre', + 'Lehigh Acres', + 'Glazoue', + 'Panevezys', + 'Chinautla', + 'New Mirpur', + 'Serik', + 'Chia', + 'Kenosha', + 'Noksan', + 'Bajos de Haina', + 'Magalang', + 'Exeter', + 'Bimbo', + 'Leiden', + 'Kadirli', + 'Fugu', + 'Savannakhet', + 'Khrustalnyi', + 'Magangue', + 'Kirishima', + 'Cai Lay', + 'Maicao', + 'Pobe', + 'Giugliano in Campania', + 'Algeciras', + 'Paleng', + 'Akcaabat', + 'Djidja', + 'Duma', + 'Longtian', + 'Seaside', + 'Punta Arenas', + 'Itaituba', + 'Tres Lagoas', + 'Nandgaon', + 'Orizaba', + 'Bento Goncalves', + 'Honmachi', + 'Baraki', + 'Arvada', + 'Alwal', + 'Gapan', + 'Kaya', + 'Ed Damer', + "Munch'on", + 'Gexianzhuang', + 'Kilifi', + 'Zacatecas', + 'Romford', + 'Dimapur', + 'Patnos', + 'Pati', + 'Kahta', + 'Yuanlin', + 'Bayawan', + 'Machiques', + 'Hoima', + 'San Pedro Garza Garcia', + 'Bayan Lepas', + 'Ciudad Hidalgo', + 'Behbahan', + 'Itatiba', + 'Cagua', + 'Barretos', + 'Ise', + 'Puerto Cortes', + 'Maina', + 'Indramayu', + 'Tam Ky', + 'Uruma', + 'Sarangapuram', + 'Mufulira', + 'Waldorf', + 'Independence', + 'Ciudad Ojeda', + 'Bhadrakh', + 'Gyumri', + 'Dharmavaram', + 'Colchester', + 'Monza', + 'Sivaganga', + 'Chinandega', + 'Hoi An', + 'Logan', + 'Faridpur', + 'Springs', + 'Dorud', + 'Kashiwara', + 'Kuopio', + 'Ondjiva', + 'Alberton', + 'Temperley', + 'Harlingen', + 'Waterloo', + 'Dordrecht', + 'Kamalia', + 'Berkeley', + 'Tsuruoka', + 'Lianhe', + 'Ar Rass', + 'Hoa Binh', + 'Dogubayazit', + 'Port-de-Paix', + 'Upington', + 'Wuling', + 'Samandag', + 'Chon Thanh', + 'Puruliya', + 'Mit Ghamr', + 'Kirikhan', + 'Sassari', + 'Ghazipur', + "Ch'ungmu", + 'Apartado', + 'Tumen', + 'Thanh Pho Uong Bi', + 'Jima', + 'Genhe', + 'Navojoa', + 'Porlamar', + 'Anderlecht', + 'Metz', + 'Winterveld', + 'Renala Khurd', + 'Chilapa de Alvarez', + 'Coatepeque', + 'Bagaha', + 'Gudiyattam', + 'Mahuva', + 'Catchiungo', + 'Fier', + 'Clovis', + 'Kotamobagu', + 'Gurdaspur', + 'Ky Anh', + 'Kot Addu', + 'Round Rock', + 'Barcelos', + 'Pueblo', + 'Ramos Mejia', + 'High Wycombe', + 'Gemlik', + 'Temple', + 'Soke', + 'Khurda', + 'Delgado', + 'Kandy', + 'Ban Bang Pu Mai', + 'Gateshead', + 'Guelma', + 'Unwana', + 'Ar Rustaq', + 'Baraka', + 'Ghardaia', + 'Nokha', + 'Jandrapeta', + 'Hengken', + 'Dong Hoa', + 'Gorzow Wielkopolski', + 'Terrebonne', + 'Lalo', + 'Pelabuhanratu', + 'Yelahanka', + 'Meridian', + 'Malindi', + 'Almirante Tamandare', + 'Ebetsu', + 'Boulogne-Billancourt', + 'Moncton', + 'Yuksekova', + 'Palma Soriano', + 'An', + 'Jiangna', + 'Perpignan', + 'Pleven', + 'Fulgazi', + 'Bergamo', + 'Shuixi', + 'Sanxi', + 'Nazarabad', + 'Candaba', + 'Parow', + 'Tizayuca', + 'Mohammad Shahr', + 'Silifke', + 'Port Dickson', + 'Besancon', + 'Debre Tabor', + 'Arapongas', + 'Guaratingueta', + 'Slough', + 'Aw Dheegle', + 'Tuz Khurmatu', + 'Birigui', + 'Totonicapan', + 'Gottingen', + 'Huaraz', + 'Daitocho', + 'Darjeeling', + 'Piraquara', + 'Bet Shemesh', + 'Bismil', + 'Vihiga', + 'Pescara', + 'Sopur', + 'Nowshera', + 'Duluth', + 'Bandar-e Anzali', + 'Bruges', + 'Yongqing', + 'Calumpit', + 'Bwana Mkubwa', + 'Butwal', + 'Senador Canedo', + 'The Woodlands', + 'Chikmagalur', + 'Matamoros', + 'Kadoma', + 'Guelmim', + 'Yangliuqing', + 'Xuqiaocun', + 'Soasio', + 'Kampong Cham', + 'Dinalupihan', + 'Malita', + 'Nigde', + 'Gudivada', + 'Bama', + 'Lahti', + 'Bottrop', + 'Quyang', + 'Ilobu', + 'Ligao', + 'Boulder', + 'Richardson', + 'Trento', + 'Nouadhibou', + 'Blackburn', + 'Phagwara', + 'Bage', + 'Aizuwakamatsu', + 'Lodhran', + 'Tahoua', + 'Matsubara', + 'Araguari', + 'Gogounou', + 'Agadez', + 'Pudukkottai', + 'Saanich', + 'Nobeoka', + 'Charallave', + 'Uribia', + 'West Palm Beach', + 'Luanshya', + 'Banyuwangi', + 'Reutlingen', + 'Handa', + 'Kabwe', + 'La Asuncion', + 'Salman Bak', + 'Catacamas', + 'Tangjin', + 'Midsayap', + 'Port Arthur', + 'Heroica Guaymas', + 'Munuf', + 'East Los Angeles', + 'Uruguaiana', + 'Banfora', + 'Harshin', + 'Adilabad', + 'Redding', + 'Apalit', + 'Yulu', + 'Umuarama', + 'Alcobendas', + 'Cassongue', + 'Clearwater', + 'Faqus', + 'Dabrowa Gornicza', + 'Monroe', + 'Kapakli', + 'Baripada', + 'Soreang', + 'Konosu', + 'Samal', + 'Datu Odin Sinsuat', + 'Utica', + 'Manpo', + 'Tatui', + 'St. Cloud', + 'Mandeville', + 'Chimaltenango', + 'Orleans', + 'La Granja', + 'Erlangen', + 'Yavatmal', + 'Titagarh', + 'Ikoma', + 'Lira', + 'Barnala', + 'Cheltenham', + 'Forli', + 'Chittaurgarh', + 'West Jordan', + 'Xai-Xai', + 'Gabes', + 'Tecoman', + 'Boke', + 'Coronel', + 'Narasaraopet', + 'Siracusa', + 'Himamaylan', + 'Ocana', + 'Ballarat', + 'Adigrat', + 'Dharan', + 'Smithtown', + 'Fatsa', + 'Temixco', + 'Bongao', + 'Ain Beida', + 'Karatsu', + 'Nagahama', + 'Targu-Mures', + 'Sogamoso', + 'San Tung Chung Hang', + 'Beppu', + 'Adjaouere', + "Ra's al Khaymah", + 'Valle de La Pascua', + 'Urasoe', + 'Sao Goncalo do Amarante', + 'Sri Jayewardenepura Kotte', + 'Catanduva', + 'Varzea Paulista', + 'North Charleston', + 'San Ildefonso', + 'Linkoping', + 'Tarogong', + 'Nasushiobara', + 'Nusaybin', + 'Pedro Juan Caballero', + 'Ribeirao Pires', + 'Sandvika', + 'Bremerhaven', + 'Uzhhorod', + 'Saginaw', + 'Koencho', + 'Kovilpatti', + 'Ar Rumaythah', + 'Kasese', + 'Bijnor', + 'Chelmsford', + 'Los Banos', + 'Puerto Madryn', + 'Koblenz', + 'El Pueblito', + 'Kailua', + 'Sliven', + 'Elblag', + 'Igarassu', + 'Guanabacoa', + 'Aihua', + 'Mendoza', + 'Al Mudaybi', + 'Swabi', + 'Ciudad Guzman', + 'Tlapacoyan', + "Bu'aale", + 'Turbaco', + 'Niihama', + 'Brandon', + 'Amasya', + 'Ponce', + 'Rawajaya', + 'Rawasari', + 'Sano', + 'Dam Dam', + 'Las Delicias', + 'Carlsbad', + 'Lowell', + 'Qiaotou', + 'Hatsukaichi', + 'Bijeljina', + 'Maghnia', + 'Plock', + 'Shacheng', + "Sach'on", + 'Thimphu', + 'Ariana', + 'Iriga City', + 'Boras', + 'Simoes Filho', + 'Plaridel', + 'Catalao', + 'Jaramana', + 'Kaikkudi', + 'Codo', + 'Yoju', + 'Broken Arrow', + 'Ambovombe', + 'Sakete', + 'Elgin', + 'Alphen aan den Rijn', + 'Lugazi', + 'Machakos', + 'Rouen', + 'Bintulu', + 'Petrzalka', + 'Materi', + 'Kakegawa', + 'Kuningan', + 'Helsingborg', + 'Quilengues', + 'Tawau', + 'Poa', + 'Sakiet ed Daier', + 'Iranshahr', + 'Ifanhim', + 'Euriapolis', + 'Ndali', + 'Gresham', + 'Pul-e Khumri', + 'Fujimino', + 'Comitan', + 'League City', + 'Mungo', + 'Guiguinto', + 'Midyat', + 'Itabira', + "Sa-ch'on", + 'Bukittinggi', + 'Satkhira', + 'Manolo Fortich', + 'Sloviansk', + 'Akcakale', + 'Hikone', + 'Mangaldan', + 'Hofu', + 'Mostar', + 'Tokai', + 'Downey', + 'Sokode', + 'Libmanan', + 'Hosan', + 'San Carlos de Bariloche', + 'Paulo Afonso', + 'Tecpan Guatemala', + 'Kazo', + 'Jonkoping', + 'Bergisch Gladbach', + 'Tayabas', + 'Remscheid', + 'Carora', + 'Lomas de Zamora', + 'Balangir', + 'Shegaon', + 'Macul', + 'Oshu', + 'Nkayi', + 'Higashiomi', + 'Otaru', + 'Ciudad de la Costa', + 'Badin', + 'Kisii', + 'Santa Lucia', + 'Goth Tando Sumro', + 'Shkoder', + 'Kaposvar', + 'Mahasamund', + 'Trier', + 'Rajpura', + 'Hezuo', + 'La Libertad', + 'Pochuta', + 'Dassa-Zoume', + 'Akishima', + 'Bagalkot', + 'Osmanabad', + 'Esteli', + 'Paarl', + 'Kouande', + 'Kalianpur', + 'Shujalpur', + 'Sahibganj', + 'Passos', + 'Subic', + 'Murrieta', + 'Jaen', + 'Fujimi', + 'Leominster', + 'Longview', + 'Baybay', + 'Ichinoseki', + 'Pompano Beach', + 'Colatina', + 'Bou Saada', + 'Bend', + 'Alkmaar', + 'Recklinghausen', + 'Mawanella', + 'Daet', + 'Nova Lima', + 'Araxa', + 'Laoag', + 'Miami Gardens', + 'Chilon', + 'Chiquimula', + 'Sabara Bangou', + 'Costa Mesa', + 'Baleraja', + 'Montreuil', + 'Villa Mercedes', + 'Sioux City', + 'Ghotki', + 'Jawhar', + 'Santamesa', + 'Kasempa', + 'Champdani', + 'Sao Lourenco da Mata', + 'Harad', + 'Jena', + 'Gafsa', + 'Ariquemes', + 'Kasuga', + 'Nsukka', + 'Kintampo', + 'Nandurbar', + 'Purwa Utar', + 'Kaiyun', + 'Namur', + 'Khushab', + 'Everett', + 'Puerto Barrios', + 'Fasa', + 'Gilroy', + 'Kiffa', + 'Al Ahad al Masarihah', + 'As Salamiyah', + 'Sorriso', + 'Franceville', + 'San Antonio Enchisi', + 'Quibor', + 'Socopo', + 'Ahuachapan', + 'Manzini', + 'Masindi', + 'Muktsar', + 'Martinez de la Torre', + 'San Buenaventura', + 'Changbang', + 'Empangeni', + 'Ferozepore', + 'Baneh', + 'Itele', + 'Rochdale', + 'Jeonghae', + 'Shirayamamachi', + 'Temecula', + 'Tubarao', + 'Sugar Land', + 'Omuta', + 'Chico', + 'Msaken', + 'Tinaquillo', + 'Bridgetown', + 'Wythenshawe', + 'Mancheral', + 'Qal`at Sukkar', + 'Pisco', + 'Retalhuleu', + 'Bernal', + 'Sutton Coldfield', + 'Vicenza', + 'Doncaster', + 'Winterthur', + 'Rotherham', + 'Dera Ismail Khan', + 'Esteban Echeverria', + 'Quezon', + 'Aguachica', + 'Naujan', + 'Glan', + 'Bayugan', + 'Eau Claire', + 'Brovary', + 'Gualeguaychu', + 'Delft', + 'Walthamstow', + 'Drammen', + 'Medenine', + 'Nkpor', + 'Kamagaya', + 'Tacurong', + 'Malacatan', + 'Taoyang', + 'Beja', + 'Yongju', + 'Labo', + 'Sandacho', + 'Berkane', + 'Sam Son', + 'White Rock', + 'Marugame', + 'Tangjia', + 'Sehore', + 'Soma', + 'Handeni', + 'Balombo', + 'Taitung', + 'Bangaon', + 'Thunder Bay', + 'Pulilan', + 'Maxixe', + 'Kasserine', + 'Bagu Na Mohra', + 'Matruh', + 'Baia Mare', + 'Shihuajie', + 'Tondabayashicho', + 'Ba Ria', + 'El Monte', + 'Witbank', + 'Khopoli', + 'Ferizaj', + 'Xishancun', + 'Mascara', + 'Khenchela', + 'Taungoo', + 'Mong Cai', + 'Idaho Falls', + 'Melipilla', + 'Komatsu', + 'Yasuj', + 'Khardah', + 'Cawayan', + 'Reus', + 'Mopti', + 'Delta', + 'Dearborn', + 'Toowoomba', + 'Mungeli', + 'Alto Hospicio', + 'Habikino', + 'Maramag', + 'Yevpatoriia', + 'Caen', + 'Nantang', + 'West Covina', + 'Tadpatri', + 'Birnin Kebbi', + 'Acharnes', + 'Yilong', + 'Sarh', + 'Sparks', + 'Mudanya', + 'An Nuhud', + 'Zilina', + 'Itumbiara', + 'Rijeka', + 'Douliu', + 'South Fulton', + 'Baia Farta', + 'Mazhang', + 'Castelar', + 'Villa Krause', + 'Balsas', + 'Lingayen', + 'Centennial', + 'Labe', + 'Gharbara', + 'Chaman', + 'Sultanpur', + 'Joyabaj', + 'Umm Qasr', + 'Kogon Shahri', + 'Kawit', + 'Kotmale', + 'Mineshita', + 'Shikohabad', + 'Morales', + 'Liberec', + 'Santana', + 'Shinyanga', + 'Basingstoke', + 'Jalpaiguri', + 'Manokwari', + 'Shamli', + 'Argenteuil', + 'Sandy Springs', + 'Wa', + 'Cambe', + 'Bhilai Karanja', + 'Chongshan', + 'Ilebo', + 'La Gi', + 'Ejido', + 'Emmen', + 'Edison', + 'Bante', + 'Lujan', + 'Bagong Silangan', + 'Yopal', + 'Erdenet', + 'Inglewood', + 'Suriapet', + 'Kalmunai', + 'Tajimi', + 'Chabahar', + 'Tenggarong', + 'Hillsboro', + 'Crawley', + 'Acailandia', + 'Roquetas de Mar', + 'As Safirah', + 'Wardha', + 'La Banda', + 'Catbalogan', + 'Htison', + 'Ranibennur', + 'Burbank', + 'Terni', + 'Mulhouse', + 'Nakhon Si Thammarat', + 'Berdiansk', + 'Toufen', + 'Kulob', + 'Kemalpasa', + 'Ad Dakhla', + 'Tiaong', + 'Tarnow', + 'Carmona', + 'Dagenham', + 'El Limon', + 'Barnoi', + 'Bolzano', + 'Raba', + 'Mingacevir', + 'Sitamarhi', + 'Lokossa', + 'Nanaimo', + 'Son La', + 'Sao Pedro da Aldeia', + 'Contramaestre', + 'Binh Hoa', + 'Atebubu', + 'Koszalin', + 'Idku', + 'Lo Barnechea', + 'Davie', + 'Kishanganj', + 'Song Cau', + 'Temoaya', + 'Kiryu', + 'Jatai', + 'El Cajon', + 'Erechim', + 'Tikrit', + 'Hindaun', + 'Azare', + 'Semari', + 'Jurupa Valley', + 'Lerma', + 'Tarim', + 'Nova Serrana', + 'Japeri', + 'Paragominas', + 'Gangawati', + 'Binh Long', + 'Malungun', + 'Allen', + 'Sabac', + 'Charsadda', + 'Alchevsk', + 'Robat Karim', + 'Auburn', + 'Renton', + 'Nautanwa', + 'Mazyr', + 'Xiva', + 'Moers', + 'Ash Shaykh `Uthman', + 'Lagarto', + 'Kongolo', + 'Mityana', + 'Bulan', + 'Yozgat', + 'Texcoco', + 'Nikopol', + 'Alasehir', + 'Holland', + 'Sultan Kudarat', + 'Maranguape', + 'Ndjamba', + 'Makrana', + 'Al Faw', + 'Planaltina', + 'Sheopur', + 'Kandhkot', + 'Pergamino', + 'Tagbilaran City', + 'Los Minas', + 'Parral', + 'Lavras', + 'Coronel Fabriciano', + 'Brockton', + 'Wloclawek', + 'Brantford', + 'Tenancingo', + 'Presidente Franco', + 'Tuyen Quang', + 'Olanchito', + 'Salzgitter', + 'Masbate', + 'Godollo', + 'Ballia', + 'Walbrzych', + 'Barika', + 'Rio Rancho', + 'Girona', + 'Suruc', + 'Siauliai', + 'Nancy', + 'Ourense', + 'Aquin', + 'Techiman', + 'Chorzow', + 'Tam Diep', + 'Balanga', + 'Gillingham', + 'Kanoya', + 'Ikeda', + 'Muriae', + 'Tadepallegudem', + 'Natitingou', + 'Chatham', + 'Ourinhos', + 'Sindangan', + 'Chicoutimi', + 'Bansbaria', + 'Tula de Allende', + 'Lida', + 'Toride', + 'Salford', + 'Rialto', + 'Ilopango', + 'Masaka', + 'Spokane Valley', + 'Saijo', + 'Charlottesville', + 'Kilinochchi', + 'Bacabal', + 'Menifee', + 'Orsha', + 'Daly City', + 'Uitenhage', + 'Biak', + 'Wigan', + 'Roncaglia', + 'Itacoatiara', + 'Musoma', + 'Breves', + 'Buzau', + 'Mubende', + 'Francistown', + 'Lower Hutt', + 'Woodbridge', + 'Tanga', + 'Uba', + 'Hounslow', + 'Bumba', + 'Bundi', + 'Bergama', + 'Chikushino', + 'Patos', + 'Itanhaem', + 'Aracruz', + 'Inzai', + 'Iguatu', + 'Camboriu', + 'Miryang', + 'Tanjungpandan', + 'Santo Antonio de Jesus', + 'Bendigo', + 'Bouskoura', + 'Paniqui', + 'Amaravati', + 'Parang', + 'Negapatam', + 'Sangju', + 'Buxar', + 'Wembley', + 'Caieiras', + 'Telde', + 'Kurichchi', + 'Hinche', + 'Hoyacho', + 'Guihulngan', + 'Saint Helens', + 'Gursu', + 'Jirja', + 'Kheda', + 'Siegen', + 'Tezpur', + 'Wichita Falls', + 'Riverview', + 'Piacenza', + 'Messaad', + 'Sundarnagar', + 'Houzhuang', + 'Gutersloh', + 'Mayari', + 'Seoni', + 'Ngong', + 'Ban Mangkon', + 'Mustafakemalpasa', + 'Kashmar', + 'Bahrain', + 'Jounie', + 'Ituiutaba', + 'Mositai', + 'Matehuala', + 'Rishikesh', + 'Simanggang', + 'Yishi', + 'Isehara', + 'Shibuya', + 'Sabratah', + 'Lahan', + 'Aflou', + 'Al Fqih Ben Calah', + 'Fugangcun', + 'Al Jumayl', + 'Dhangadhi', + 'Tavsanli', + 'Norwalk', + 'Shushtar', + 'Tota', + 'Tando Muhammad Khan', + 'Hildesheim', + 'Kapurthala', + 'Boryeong', + 'Al Hajar al Aswad', + 'Olomouc', + 'Zonguldak', + "Lee's Summit", + 'Dhamtari', + 'Raneswar', + 'Chishtian', + 'Longmont', + '`Ibri', + 'Vacaville', + 'Onojo', + 'Brajarajnagar', + 'Eastbourne', + 'Sujangarh', + 'Highlands Ranch', + 'Ciudad Rio Bravo', + 'Bhadreswar', + 'Pavlohrad', + 'Clarington', + 'Hengnan', + 'Assis', + 'Klagenfurt', + 'Chilakalurupet', + 'San Luis de la Paz', + 'Hanau', + 'Hikkaduwa', + 'Sungai Penuh', + 'Kingsport', + 'Chaguanas', + 'Jingping', + 'Novara', + 'Kousseri', + 'Ain Oussera', + 'Deventer', + 'San Vicente de Baracaldo', + 'Kaiserslautern', + 'KwaDukuza', + 'San Tan Valley', + 'Nga Bay', + 'Hong Ngu', + 'Jeypore', + 'Zomba', + 'Daoukro', + 'Itaperuna', + 'Oran', + 'Mporokoso', + 'Quincy', + 'Edinburg', + 'Karanja', + 'Aboisso', + 'Salavan', + 'Xirdalan', + 'Saint-Jerome', + 'Red Deer', + 'Sakado', + 'Bim Son', + 'Kefar Sava', + 'Chanwari', + 'Xinhua', + 'Sungailiat', + 'Sittwe', + 'Concepcion del Uruguay', + 'Leer', + 'Cavite City', + 'Playas de Rosarito', + 'Lynn', + 'Ahar', + 'Yen Bai', + 'Weifen', + 'Sur', + 'Port Blair', + 'Nahiyat al Iskandariyah', + 'Kalyani', + 'Masjed Soleyman', + 'Calasiao', + 'Datia', + 'Kamianets-Podilskyi', + 'Itaugua', + 'Torbat-e Jam', + 'Diourbel', + 'Madhavaram', + 'Kawachinagano', + 'Libertad', + 'Shahrisabz', + 'Gangtok', + 'Vaciamadrid', + 'Bocono', + 'San Felipe del Progreso', + 'Chust', + 'Lamitan', + 'Talipao', + 'San Angelo', + 'Sabanalarga', + 'Pyinmana', + 'Zahle', + 'Bamyan', + 'Mbanza-Ngungu', + 'Banzhuangcun', + "Ra's Gharib", + 'Gwelej', + 'Babile', + 'Dzolokpuita', + 'Suramala', + 'Navalyal', + 'Barod', + 'Vasco Da Gama', + 'Khambhaliya', + 'Abbigeri', + 'Kundli', + 'Ad Dujayl', + 'Mumias', + 'Luckeesarai', + 'Songea', + 'Pouytenga', + 'Solola', + 'Mabai', + 'Debre Zeyit', + 'Dunedin', + 'Hesperia', + 'Nabire', + 'Sundsvall', + 'Kadaiyanallur', + 'Sayaxche', + 'Ciamis', + 'Putatan', + 'Xiongzhou', + 'Urgut Shahri', + 'Fengning', + 'Bowling Green', + 'Shahdadpur', + 'Federal Way', + 'Talara', + 'Menglang', + 'Kani', + 'Cottbus', + 'Tinsukia', + 'Santa Cruz del Quiche', + 'Hualien', + 'Carmel', + 'Bismarck', + 'Campo Mourao', + 'Alaminos', + 'Xiegang', + 'Tellicherry', + 'Jinotega', + 'Itarsi', + 'Izumisano', + 'Thika', + 'Bislig', + 'Abhar', + 'Viseu', + 'Malate', + 'Ginowan', + 'Wakefield', + 'Sakata', + 'Khamis Mushayt', + 'Pili', + 'Pickering', + 'Hasilpur', + 'Trincomalee', + 'Riberalta', + 'Fishers', + 'Kohima', + 'Sisophon', + 'Tourcoing', + 'Vereeniging', + 'Mianeh', + 'Paoy Paet', + 'Weldiya', + 'Nyeri', + 'Roubaix', + 'Burzaco', + 'Espejo', + 'Kontagora', + 'Senahu', + 'Khambhat', + 'Santiago de Compostela', + 'Ixmiquilpan', + 'Caldas Novas', + 'Schwerin', + 'Salihorsk', + 'Reyhanli', + 'Itoshima', + 'Zarate', + 'Oton', + 'Manacapuru', + 'Sopron', + 'Koytendag', + 'Abreu e Lima', + 'Lorca', + 'Chipata', + 'Lethbridge', + 'Vista', + 'Chikusei', + 'Ancona', + 'Saku', + 'Silvassa', + 'Santa Cruz do Capibaribe', + 'Babahoyo', + 'Lugo', + "M'lang", + 'Leme', + 'Las Rozas de Madrid', + 'Boca Raton', + 'Moortebeek', + 'Chitose', + 'Balti', + 'Smederevo', + 'Trelew', + 'Kamloops', + 'Montego Bay', + 'Catarman', + 'Valenca', + 'Saint-Jean-sur-Richelieu', + 'Marmaris', + 'Udine', + 'Janakpur', + 'Nanxicun', + 'St. Augustine', + 'Paulinia', + 'Kambar', + 'Al Jammaliyah', + 'Itauna', + 'Ipojuca', + 'Quilenda', + 'Gambela', + 'Kallithea', + 'Deoni Buzurg', + 'Rades', + 'Mariano Roque Alonso', + 'Hammamet', + 'Asagicinik', + 'Beaverton', + 'Goodyear', + 'San Cugat del Valles', + 'Tartu', + 'Tsuyama', + 'Isulan', + 'Kalluru', + 'Konan', + 'Lajeado', + 'Adjarra', + 'Dongducheon', + 'Attock Khurd', + 'Nanterre', + 'Fanyang', + 'Yacuiba', + 'Vi Thanh', + 'Pernik', + 'Andria', + 'Para de Minas', + 'Orem', + 'Modi`in Makkabbim Re`ut', + 'Munakata', + 'Maribor', + 'Harnai', + 'Didim', + 'Colon', + 'Gavle', + 'Tumbes', + 'Es Senia', + 'Bodinayakkanur', + 'Quvasoy', + 'Paletwa', + 'Caotun', + 'Tamazunchale', + 'Arauca', + 'Tela', + 'Paraiso', + 'Do Gonbadan', + 'Sumber', + 'Kazerun', + 'Francisco Beltrao', + 'Sangolqui', + 'Iida', + 'Votuporanga', + 'Tiddim', + 'Buin', + 'Bab Ezzouar', + 'Oldham', + 'Zhudong', + 'Sunrise', + 'Omura', + 'Half Way Tree', + 'Peje', + 'Wujiaqu', + 'Harihar', + 'Ceske Budejovice', + 'Tomohon', + 'Parintins', + 'Navapolatsk', + 'Osijek', + 'Greece', + 'Corumba', + 'Arezzo', + 'Caceres', + 'Vitry-sur-Seine', + 'Doudian', + 'Lysychansk', + 'Escalante', + 'Itabaiana', + 'Charikar', + 'Arden-Arcade', + 'Harran', + 'Lawrence', + 'Muzaffarabad', + 'Bachhraon', + 'Toms River', + 'Hammersmith', + 'Amalner', + 'Balayan', + 'Sardarshahr', + 'Kalisz', + 'Witten', + 'Longkeng', + 'Vanderbijlpark', + 'Vilhena', + 'Rio Gallegos', + 'Weiyuan', + 'Caseros', + 'Cesena', + 'Tataouine', + 'Dhulian', + 'Hadera', + 'Arifwala', + 'Sandy', + 'Sao Cristovao', + 'Rayleigh', + 'Paramagudi', + 'Zerakpur', + 'Slidell', + 'Tandwa', + 'Shire', + 'Kamisu', + 'Cubuk', + 'Burdur', + 'Aliaga', + 'Pesaro', + 'Erbaa', + 'Tiruchengodu', + 'Huong Thuy', + 'Mons', + 'Pedagadi', + 'Oued Zem', + 'Boli', + 'Nagina', + 'Bogo', + "Saint-Michel de l'Atalaye", + 'Chakdaha', + 'Shimada', + 'Closepet', + 'Jiantang', + 'Dovzhansk', + 'Birecik', + 'Emmiganur', + 'Yalamakuru', + 'Balamban', + 'Siguatepeque', + 'Labuan', + 'Naxcivan', + 'Rawanduz', + 'Yumbo', + 'Vaniyambadi', + 'Al Jizah', + 'Buckeye', + 'Rubio', + 'Tiruttani', + 'Mianwali', + 'Dongping', + 'Meizichong', + 'Nahiyat al Karmah', + 'Moca', + 'Rincon de Romos', + 'Ocotlan', + 'Sibolga', + 'Esslingen', + 'Cerete', + 'Hemel Hempstead', + 'Livonia', + 'San Ramon', + 'San Martin Jilotepeque', + 'Williamsburg', + 'Bouna', + 'Legnica', + 'Kangan', + 'Suffolk', + 'Los Patios', + 'Compton', + 'Lecce', + 'Bath', + 'Behshahr', + 'Lopez', + 'Lingwala', + 'La Crosse', + 'Bhadohi', + 'Kanuma', + 'Gjakove', + 'Edmond', + 'San Joaquin', + 'Gerona', + 'Carson', + 'Allinagaram', + 'Bayan Hot', + 'Niagara Falls', + 'Villa Luzuriaga', + 'Marmagao', + 'Pingyuanjie', + 'Greenburgh', + 'Shibata', + 'Ludwigsburg', + 'Giessen', + 'Ashiya', + 'Yishui', + 'Yi Xian', + 'Tracy', + 'Paracatu', + 'Herzliyya', + 'Monkayo', + 'Ponta Pora', + 'Hayes', + 'Rio Largo', + 'Azumino', + 'Prescott Valley', + 'Dhar', + 'Qormi', + 'San Jose del Rincon Centro', + 'Middletown', + 'Valongo', + 'Alvand', + 'Lingtang', + 'Dong Ha', + 'Menderes', + 'Chiantla', + 'Simeulu', + 'Zifta', + 'Cape Breton', + 'Al Fujayrah', + 'Sanjo', + 'Fall River', + 'Gera', + 'Mairipora', + 'Lawang', + 'San German', + 'Hradec Kralove', + 'Daanbantayan', + 'Monastir', + 'Wangjia', + 'Yashio', + 'Jinbi', + 'Aksehir', + 'Yotsukaido', + 'Duren', + 'Chilliwack', + 'Santa Cruz Xoxocotlan', + 'Lemery', + 'Indanan', + 'Ramnicu Valcea', + 'Fenggang', + 'Tual', + 'Plantation', + 'Galle', + 'Mayaguez', + 'Itajuba', + 'Kwekwe', + 'Darlington', + 'New Braunfels', + 'Sidi Slimane', + 'Creteil', + 'La Marsa', + 'Ubatuba', + 'Ciudad General Belgrano', + 'Rafaela', + 'Wukari', + 'Guaiba', + 'Barra do Pirai', + 'Palimbang', + 'Nisshin', + 'Hanamaki Onsen', + 'Tubingen', + 'Boundiali', + 'La Reina', + 'Roswell', + 'Wimbledon', + 'San Sebastian de los Reyes', + 'Tatvan', + 'Kadugli', + 'Akot', + 'Tamanrasset', + 'Helmond', + 'Inagi', + 'Mtwara', + 'Rongwo', + 'Sablayan', + 'Azua', + 'Naju', + 'Mogi Mirim', + 'Flensburg', + 'Iserlohn', + 'Sao Joao da Boa Vista', + 'Oss', + 'Conroe', + 'Barletta', + 'Bedford', + 'South Gate', + 'Errachidia', + 'Tatakan', + 'Sepatan', + 'Kitakami', + 'Serra Talhada', + 'Contai', + 'Obu', + 'Teziutlan', + 'Santa Monica', + 'Pardubice', + 'Coatepec', + 'La Spezia', + 'Sao Roque', + 'Kirkland', + 'Hoover', + 'Kot Kapura', + 'Usti nad Labem', + 'Netrakona', + 'Hove', + 'Cruzeiro do Sul', + 'Satsumasendai', + 'Shabqadar', + 'Pato Branco', + "O'Fallon", + 'Higashi-Matsuyama', + 'Tultepec', + 'Kakamega', + 'Raub', + 'Turayf', + 'Southport', + 'Mijas', + 'Ouidah', + 'Goalundo Ghat', + 'Sinende', + 'Linquan', + 'Phu Tho', + 'Maracay', + 'Caycuma', + 'Niono', + 'Grahamstown', + 'Myingyan', + 'Alafaya', + 'Brossard', + 'Satu Mare', + 'Piranshahr', + 'Samalut', + 'Karwar', + 'Mizan Teferi', + 'Arzew', + 'Salaman', + 'Mandvi', + 'San Francisco Solano', + 'Tucurui', + 'Kalamaria', + 'Jauharabad', + 'Kendu Bay', + 'Hilversum', + 'Rayachoti', + 'Avare', + 'Paloncha', + 'Manhuacu', + 'Cacapava', + 'Xiancun', + 'Palm Coast', + 'Alessandria', + 'Ambohimangakely', + 'Hastings', + 'Agua Prieta', + 'Lawton', + 'Chino', + 'Lachhmangarh Sikar', + 'Maple Ridge', + 'Miaoli', + 'Mount Pleasant', + 'Tonacatepeque', + 'Grudziadz', + 'Guercif', + 'Solwezi', + 'Cisauk', + 'Caimbambo', + 'Oudtshoorn', + 'Bauan', + 'Pantukan', + 'Pongotan', + 'Ramagiri Udayagiri', + 'Cambambe', + 'Gwadar', + 'Mengdingjie', + 'Manteca', + 'Funza', + 'Zhezqazghan', + 'Canakkale', + 'Katiola', + 'Biga', + 'Eslamabad-e Gharb', + 'Chililabombwe', + 'Vanadzor', + 'Fundacion', + 'Ponnani', + 'Sahagun', + 'Arsuz', + 'Jamtara', + 'Joplin', + 'Pinamalayan', + 'Avignon', + 'Orpington', + 'Valjevo', + 'Julu', + 'Pazardzhik', + 'Vezirkopru', + 'Mandurah', + 'Watford', + 'Poitiers', + 'Sao Joao del Rei', + 'Yoshiwara', + 'Puerto Padre', + 'Caucasia', + 'Germantown', + 'Penaflor', + 'Imizucho', + 'Nasatta', + 'Abomey', + 'Pollachi', + 'Gjilan', + 'Hendek', + 'Gujar Khan', + 'Jalalpur Jattan', + 'Wajir', + 'Victorias', + 'Marudi', + 'Kavali', + 'Aubervilliers', + 'Botosani', + 'Darnah', + 'Mong Tun', + 'Richard-Toll', + 'Afmadow', + 'Barwaaqo', + 'Ma`arrat an Nu`man', + 'Luau', + 'Necochea', + 'Al Badrashayn', + 'Leogane', + 'El Ejido', + 'Mihara', + 'Compostela', + 'Presidencia Roque Saenz Pena', + 'Bayt Lahya', + 'Patrocinio', + 'El Puerto de Santa Maria', + 'Itapeva', + 'San Leandro', + 'Olavarria', + 'Dobrich', + 'Stevenage', + 'San Jose Pinula', + 'Sankeshwar', + 'Koka', + 'Glyfada', + 'Serdar', + 'Saquarema', + 'Cantaura', + 'Los Cerrillos', + 'Conda', + 'Cheektowaga', + 'Tartus', + "Town 'n' Country", + 'Clifton', + 'Waukegan', + 'Kadiri', + 'Tonghae', + 'Zhunan', + 'Ipil', + 'Prijedor', + 'Oulad Teima', + 'Nikaia', + 'Mestre', + 'Caracase', + 'Surallah', + 'Ciudad de Atlixco', + 'Pistoia', + 'Akyazi', + 'Torrevieja', + 'Pamekasan', + 'Segbana', + 'Maladzyechna', + 'Lere', + 'Avondale', + 'Maumere', + 'Phusro', + 'Polangui', + 'Banga', + 'Humpata', + 'Kalibo', + 'Atascocita', + 'Kuhdasht', + 'Jalal-Abad', + 'Kairana', + 'Jaworzno', + 'Saundatti', + 'Shwebo', + 'Hinigaran', + 'Calabanga', + 'As Salt', + 'Passi', + 'Colombes', + 'Aalst', + 'Lucca', + 'Missoula', + 'Hemei', + 'Pisa', + 'Wangqing', + 'Viana do Castelo', + 'Danli', + 'Chiclana de la Frontera', + 'Fort Myers', + 'Montelibano', + 'Ben Guerir', + 'Toviklin', + 'Chosica', + 'Paingkyon', + 'Villa Maria', + 'Rasipuram', + 'Najibabad', + 'Podujeve', + 'Barra do Corda', + 'Bayramaly', + 'Kimje', + 'Bhakkar', + 'Berisso', + 'Bertoua', + 'Newton', + 'La Grita', + 'Solana', + "Ain M'Lila", + 'Nirmal', + 'Nirala', + 'Ootacamund', + 'Echague', + 'Aroroy', + 'Mobara', + 'Ben Arous', + 'Prosperidad', + 'Alabel', + 'Ban Laem Chabang', + 'Grimsby', + 'Villingen-Schwenningen', + 'Jangipur', + 'Jaffna', + 'Janzur', + 'Leshou', + 'Muncie', + 'Sangrur', + 'Damaturu', + 'Qiantangcun', + 'Hartlepool', + 'Al Wakrah', + 'Sassandra', + 'Newmarket', + 'Jilotepec', + 'Makilala', + 'Wislane', + 'Maiquetia', + 'Mettupalaiyam', + 'Wakiso', + 'Bromley', + 'Jumri Tilaiya', + 'Rapid City', + 'Guanambi', + 'Jaguey Grande', + 'Baggao', + 'San Juan de los Morros', + 'Aruppukkottai', + 'Faridkot', + 'Calauan', + 'Ceylanpinar', + 'Ama', + 'Slupsk', + 'Madgaon', + 'Baras', + 'Gitarama', + 'Ende', + 'Koidu-Bulma', + 'Palangotu Adwar', + 'Sakiet ez Zit', + 'Western Bicutan', + 'Chester', + 'Consolacion del Sur', + 'Cipolletti', + 'Kpalime', + 'Changting', + 'Maasin', + 'San Fabian', + 'Satrovka', + 'Ratingen', + 'Midrand', + 'Denan', + 'Santa Catarina Pinula', + 'Calaca', + 'Caratinga', + 'Jamui', + 'Middelburg', + 'Camiling', + 'Nahuala', + 'Limpio', + 'Shuangshuicun', + 'Torrente', + 'Chongoroi', + 'Chimbas', + 'Bhola', + "Bi'r al `Abd", + 'Lorena', + 'Dipalpur', + 'Zwickau', + 'Troy', + 'Fulham', + 'Hounde', + 'Livermore', + 'Citrus Heights', + 'Ad Diwem', + 'Norton', + 'Wulan', + 'Hawthorne', + 'Heyunkeng', + 'Mardin', + 'Kumarapalaiyam', + 'Heerlen', + 'Mechelen', + 'Cacoal', + 'Takasagocho-takasemachi', + 'Binmaley', + 'Lunen', + 'Tangxing', + 'Campana', + 'Paredes', + 'Fukuroi', + 'Widekum', + 'Winchester', + 'Taohuajiang', + 'Longonjo', + 'Dunkerque', + 'Les Cayes', + 'Hansi', + 'Salinas Victoria', + 'Kattagan', + 'Tiflet', + 'Springdale', + 'Cardenas', + 'Shahdol', + 'Yoro', + 'Hamakita', + 'Unai', + 'Clarkstown', + 'Nuneaton', + 'Anakapalle', + 'Gravata', + 'Nabua', + 'Tucupita', + 'Tuncheng', + 'Whittier', + 'Deerfield Beach', + 'Nimbahera', + 'Nakhon Sawan', + 'Yaofeng', + 'Nachchandupatti', + 'Hassi Bahbah', + 'Loznica', + 'Kalpitiya', + 'Karanganyar', + 'Navegantes', + 'Yabelo', + 'Santa Rosa Jauregui', + 'Dingcheng', + 'Guasave', + 'Gotenba', + 'Odienne', + 'Ciudad de Melilla', + 'Bangkalan', + 'Bantayan', + 'Decatur', + 'Batticaloa', + 'Seoni Malwa', + 'Ibshaway', + 'Settsu', + 'Silvan', + 'Sarni', + 'Aulnay-sous-Bois', + 'Repentigny', + 'Khowrasgan', + 'Kitanagoya', + 'Vineland', + 'Shaoshanzhan', + 'Potiskum', + 'Sharurah', + 'Kameoka', + 'Keffi', + 'Qaracuxur', + 'Iga', + 'Chiguayante', + 'Cabiao', + 'Konstanz', + 'Kouvola', + 'Volos', + 'Guinobatan', + 'Kharian', + 'Mission', + 'Basoda', + 'Longhua', + 'Taishan Houcun', + 'San Pedro Sacatepequez', + 'Ducheng', + 'Adwa', + 'Sekimachi', + 'Maratturai', + 'Fuengirola', + 'Redencao', + 'Karakol', + 'Lake Forest', + 'El Bayadh', + 'Mukacheve', + 'Fusui', + 'Xuddur', + 'Karad', + 'Pariaman', + 'Chinnachauku', + 'Batarasa', + 'Lugang', + 'Junin', + 'Shumen', + 'Colonie', + 'Warder', + 'Caldas', + 'Velez-Malaga', + 'Pori', + 'Mitrovice', + 'Jinhe', + 'Garulia', + 'Tagaytay', + 'Apaseo el Grande', + 'General Rodriguez', + 'Chiquinquira', + 'Krishnagiri', + 'Arona', + 'Upper Darby', + 'Dapitan', + 'Takayama', + 'Grand Bourg', + 'Newport Beach', + 'Harda Khas', + 'Gurupi', + 'Maga', + 'Araripina', + 'Monte Chingolo', + 'Jastrzebie-Zdroj', + 'Puerto Maldonado', + 'Mhow', + 'Derry', + 'Santa Ines', + 'Ealing', + 'Walvisbaai', + "Bahla'", + 'Taxila', + 'Hovsan', + 'Luvungi', + 'Korgas', + 'Atakpame', + 'Woolwich', + 'Longchuan', + 'Brooklyn Park', + 'Karacabey', + 'Baabda', + 'Larnaca', + 'Presov', + 'Bryan', + 'Sayhat', + 'Westland', + 'Ilion', + 'Ciudad Mante', + 'Konotop', + 'Pandacan', + 'Chirundu', + 'Tuxpam de Rodriguez Cano', + 'Ijui', + 'Napa', + 'Mohammadia', + 'Catanzaro', + 'Sumenep', + 'Tshilenge', + 'Worms', + 'Pinheiro', + 'Treviso', + 'Madaba', + 'Khemis Miliana', + 'Yokotemachi', + 'Dhoraji', + 'Rafha', + 'Honiara', + 'Ushiku', + 'Tire', + 'Virappanchathiram', + 'Baytown', + 'Komae', + 'Santana do Livramento', + 'New Kru Town', + 'Carpina', + 'Kaizuka', + 'Nabunturan', + 'Marl', + 'Suceava', + 'Bais', + 'Villa Altagracia', + 'Science City of Munoz', + 'Athurugiriya', + 'Higashiyamato', + 'Ayase', + 'Bilwi', + 'Cicero', + 'Chigorodo', + 'Quixada', + 'Concepcion Tutuapa', + 'Wako', + 'Al Hindiyah', + 'Luancheng', + 'Darayya', + 'Sambava', + 'Kitakoriyamacho', + 'Hetauda', + 'Ath Thawrah', + 'Laharpur', + 'Diphu', + 'Bolinao', + 'Aruja', + 'El Milia', + 'Channapatna', + 'San Baudilio de Llobregat', + 'Chita', + 'Anderson', + 'Kesan', + 'Ermelo', + 'Acayucan', + 'Lucas do Rio Verde', + 'Dolisie', + 'Bhawanipatna', + 'Pilkhua', + 'Samadiala', + 'Ho', + 'Haskovo', + 'Franklin', + 'Matao', + 'Barahona', + 'Tiruppattur', + 'Hamma Bouziane', + 'Versailles', + 'Moriyama', + 'Farmington Hills', + 'Nizwa', + 'Buena Park', + 'Foumban', + 'Talavera de la Reina', + 'Lafey', + 'Galway', + 'Aylesbury', + 'Atambua', + 'Nazareth', + 'Phuc Yen', + 'Resita', + 'La Piedad', + 'Gokulgarh', + 'Sao Bento do Sul', + 'Serrinha', + 'Maco', + 'Lqoliaa', + 'Pine Hills', + 'Ashford', + 'Sirsilla', + 'Como', + 'State College', + 'Boukoumbe', + 'Habiganj', + 'Lakshmipur', + 'Picos', + 'Siaton', + 'Redwood City', + 'Minden', + 'Kampong Trach', + 'Moju', + 'Ciudad de Ceuta', + 'Lelystad', + 'La Lima', + 'Wutiancun', + 'Mingxing', + 'Mazatenango', + 'Mabinay', + 'Busto Arsizio', + 'Nantingcun', + 'David', + 'Al Hayy', + 'Louga', + 'Ufeyn', + 'Wadala Sandhuan', + 'Warwick', + 'Bayeux', + 'Stockton-on-Tees', + 'Nakatsu', + 'Brindisi', + 'Cranston', + 'Shirvan', + 'Tanjay', + 'Chingleput', + 'Jacobina', + 'Mian Channun', + 'Manfalut', + 'Rivadavia', + 'Cruzeiro', + 'Chelghoum el Aid', + 'Bhalwal', + 'Largo', + 'Calatrava', + 'Pontevedra', + 'Wuyi', + 'Chulucanas', + 'El Estor', + 'Velbert', + 'Cukai', + 'Miami Beach', + 'Sabaneta', + 'Oleksandriia', + 'Owariasahi', + 'Shikokuchuo', + 'Alhambra', + 'Deurne', + 'Omihachiman', + 'Johns Creek', + 'Puerto Iguazu', + 'Nueva Concepcion', + 'Macaiba', + 'Uman', + 'Saint Albans', + 'Mountain View', + 'Quixeramobim', + 'Bekobod', + 'Tacana', + 'Harlow', + 'Burnley', + 'Salisbury', + 'Jepara', + 'Redditch', + 'Saunda', + 'Morgantown', + 'Kongjiazhuangcun', + 'Norderstedt', + 'Ashoknagar', + 'Silver Spring', + 'Ubay', + 'Bhaktapur', + 'Banco Filipino International Village', + 'Layton', + 'Bilecik', + 'Yildiz', + 'Gurgenpinari', + 'Uzungoz', + 'Lucerne', + 'Siasi', + 'Watampone', + 'Katoya', + 'An Khe', + 'Paranavai', + 'Muroran', + 'Timoteo', + 'Apizaco', + 'Hukou', + 'Sao Sebastiao', + 'Courbevoic', + 'Purmerend', + 'Dar el Beida', + 'Imam Qasim', + 'Kentau', + 'Remedios de Escalada', + 'Xicotepec de Juarez', + 'Fiumicino', + 'Afsin', + 'Shuibian', + 'Kadi', + 'Valdemoro', + 'Chapadinha', + 'Xiedian', + 'Matalam', + 'Kimitsu', + 'Grosseto', + 'Buhi', + 'Athi River', + 'Nowy Sacz', + 'San Jose de las Lajas', + 'Pacatuba', + 'Lambunao', + 'Bulacan', + 'Mannargudi', + 'Port of Spain', + 'Orhangazi', + 'Hengkou', + 'Ita', + 'Folsom', + 'Kapalong', + 'Salina Cruz', + 'Panzos', + 'Tecate', + 'Balrampur', + 'Baalbek', + 'Hengelo', + 'Kashiwazaki', + 'Tallaght', + 'Khamanon Kalan', + 'La Louviere', + 'Launceston', + 'Madera', + 'Dera Allahyar', + 'Gonder', + 'Campo Limpo', + 'Gaoliying Ercun', + 'New Rochelle', + 'Ahenkro', + 'Yonezawa', + 'Orihuela', + 'Shiji', + 'Gobernador Galvez', + 'Malapatan', + 'Balcova', + 'Barili', + 'Wujindian', + 'Meybod', + 'Yanggao', + 'Bargarh', + 'Curvelo', + 'San Cristobal Verapaz', + 'Comitancillo', + 'Seropedica', + 'Terre Haute', + 'Bulanik', + "Sama'il", + 'Dahegam', + 'Torre del Greco', + 'Randfontein', + 'Batley', + 'Somerville', + 'Adigala', + 'Calandala', + 'Panjgur', + 'Butterworth', + 'Antehiroka', + 'Oum el Bouaghi', + 'Cabadbaran', + 'Beziers', + 'Tagoloan', + 'Kamareddipet', + 'Zuwarah', + 'Bafut', + 'Takestan', + 'Arni', + 'Echizen', + 'Maravatio de Ocampo', + 'Livingston', + 'Aquiraz', + 'Kumbo', + 'Bolpur', + 'Peruvancha', + 'Sint-Niklaas', + 'Flagstaff', + 'Taroudannt', + 'Namsan', + 'Gumla', + 'Simdega', + 'San Andres Cholula', + 'Qunghirot', + 'Cachoeira do Sul', + 'Boynton Beach', + 'Gamagori', + 'Manmad', + 'Goiana', + 'Rubi', + 'Nabatiye', + 'Masallatah', + 'Andahuaylas', + 'Kathri', + 'Jamshoro', + 'Khewra', + 'Zarzis', + 'Puerto Ayacucho', + 'San Carlos del Zulia', + 'Koktokay', + 'Piro', + 'Tall `Afar', + 'Homestead', + 'Scunthorpe', + 'Polatsk', + 'Mit Salsil', + 'Bamberg', + 'Turhal', + 'Ben Gardane', + 'Sefrou', + 'Kirklareli', + 'Patzcuaro', + 'Drobeta-Turnu Severin', + 'Sokcho', + 'Paco', + 'Kottagudem', + 'Idah', + 'Marsala', + 'Anniston', + 'Piatra Neamt', + 'Ciudad Lerdo', + 'Tissamaharama', + 'Akiruno', + 'Texarkana', + 'Patikul', + 'Ezpeleta', + 'Bani Mazar', + 'Mahdia', + 'Vila do Conde', + 'Krasnyi Luch', + 'Cianorte', + 'Tustin', + 'Belo Jardim', + 'Neumunster', + 'Xai', + 'Viana', + 'Eseka', + 'Dosemealti', + 'Robles', + 'San Martin', + 'Torres Vedras', + 'Langarud', + 'Pharr', + 'Senhor do Bonfim', + 'Afgooye', + 'Dudley', + 'San Isidro', + 'Port Huron', + 'Iwamizawa', + 'Yenakiieve', + 'Mangatarem', + 'Ban Talat Rangsit', + 'Sorgun', + 'Cacador', + 'Turlock', + 'Owendo', + 'Schiedam', + 'Yalta', + 'Ban Nong Prue', + 'Drummondville', + 'Natori-shi', + 'Kawartha Lakes', + 'Lisala', + 'Evosmos', + 'Juventino Rosas', + 'Ciudad Lazaro Cardenas', + 'Dobni Para', + 'Hanno', + 'Rancho Cordova', + 'Gokak', + 'Ceara-Mirim', + 'The Villages', + 'Tikamgarh', + 'Ikom', + 'Milpitas', + 'Bumahen', + 'Ubon Ratchathani', + 'Baharestan', + 'Araria', + 'Cuamba', + 'Huaral', + 'Madinat as Sadat', + 'Perere', + 'Alfenas', + 'Sougueur', + 'Nakatsugawa', + 'New Westminster', + 'Tiko', + 'Sesto San Giovanni', + 'Perris', + 'Bistrita', + 'Manresa', + 'Daugavpils', + 'Upland', + 'Subulussalam', + 'Tambacounda', + 'Dome', + 'Nakhon Pathom', + 'Toboali', + 'Tierralta', + 'Maizuru', + 'Bury', + 'Alton', + 'Eastleigh', + 'Elbasan', + 'Pagbilao', + 'Villa Celina', + "Ra's al Khafji", + 'Pleasanton', + 'Aligudarz', + 'Zaandam', + 'Mooka', + 'Arlit', + 'Skarzysko-Kamienna', + 'Dabakala', + 'Curepipe', + 'Dongchuan', + 'Hengbei', + 'Kuvango', + 'Brixton', + 'La Rochelle', + 'Taher', + 'Gyoda', + 'Sahuayo de Morelos', + 'Aveiro', + 'Bauang', + 'Dinga', + 'Iperu', + 'Varese', + 'Kendall', + 'Arkonam', + 'Delmenhorst', + 'Jonesboro', + 'Bandar Emam', + 'Bellflower', + 'Tres Rios', + 'Kashiba', + 'Barreiro', + 'Battle Creek', + 'Denov', + 'Pototan', + 'Qorveh', + 'Queluz', + 'Limay', + 'Manbij', + 'Pingyi', + 'Southall', + 'Huolu', + 'San Pedro Pinula', + 'Chino Hills', + 'Pehonko', + 'Viersen', + 'Cheyenne', + 'Argao', + 'Rueil-Malmaison', + 'Al Khankah', + 'Tanashicho', + 'Chitembo', + 'Chitemo', + 'Ilioupoli', + 'Macabebe', + 'Lebanon', + 'Carmichael', + 'South Jordan', + 'Kuacjok', + 'Gandia', + 'Faranah', + 'Mandiraja Kulon', + 'Baracoa', + 'Kizugawa', + 'Godawari', + 'Balqash', + 'Essaouira', + 'Tanuku', + 'Narra', + 'Koch Bihar', + 'Chengbin', + 'Pakxe', + 'Honjo', + 'Toyomamachi-teraike', + 'Fray Bartolome de Las Casas', + 'Rheine', + 'Hoofddorp', + 'Davis', + 'Marburg', + 'Villa Victoria', + 'Elizabethtown', + 'Linkou', + 'Birkhadem', + 'Kuniyamuttur', + 'Kortrijk', + 'Kambam', + 'Bir el Ater', + 'Champigny-sur-Marne', + 'Brikama', + 'Ukunda', + 'Huebampo', + 'Hasselt', + 'Bebedouro', + 'Nitra', + 'Phuket', + 'Lipjan', + 'Bodhan', + 'Schaumburg', + 'Alameda', + 'Zhongcheng', + 'Santa Catalina', + 'Grand-Lahou', + 'Stellenbosch', + 'Hermosa', + 'Fnidq', + 'Mengla', + 'Katano', + 'Hammond', + 'Tsubame', + 'Tirkakara', + 'Quatre Bornes', + 'Jelenia Gora', + 'Puli', + 'Caxito', + 'Pasco', + 'Latacunga', + 'Bracknell', + 'Ban Tha Khlong', + 'Cozumel', + 'Paisley', + 'Pattoki', + 'Harunabad', + 'Roosendaal', + 'As Suwayrah', + 'Bustos', + 'Evanston', + 'Kabacan', + 'Fukuchiyama', + 'Shush', + 'Lehi', + 'Chalandri', + 'Keratsini', + 'Umingan', + 'Pau', + 'Tecamachalco', + 'Guildford', + 'Zhlobin', + 'Talakag', + 'Nikko', + 'Nabari', + 'Balagtas', + 'Toyooka', + 'Balkh', + 'Estepona', + 'North Port', + 'Bongabong', + 'Nagua', + 'Berberati', + 'Santo Angelo', + 'Ebolowa', + 'Mao', + 'Luneburg', + 'Baj Baj', + 'Veliko Tarnovo', + 'Arlington Heights', + 'Surt', + 'Shostka', + 'El Viejo', + 'Usta Muhammad', + 'Camarillo', + 'Pyapon', + 'Wyoming', + 'Dorsten', + 'Prince George', + 'Mafra', + "E'erguna", + 'Nipani', + 'Vinhedo', + 'Tacambaro de Codallos', + 'Ait Ali', + 'Flower Mound', + 'Aira', + 'Caledon', + 'Bethlehem', + 'Cotui', + 'Alcala de Guadaira', + 'Tiangua', + 'Daxincun', + 'Dschang', + 'Idil', + 'Virac', + 'Hattiesburg', + 'Loveland', + 'Abeche', + 'Fazilka', + 'Khemis el Khechna', + 'Funing', + 'Armant', + 'Al Musayyib', + 'Shinkai', + 'Ibiuna', + 'Paysandu', + 'Pittsburg', + 'Kafr az Zayyat', + 'Crateus', + 'Ninh Hoa', + 'Siedlce', + 'Sasolburg', + 'Melton', + 'Cedar Park', + 'Palencia', + 'Pozzuoli', + 'Shajapur', + 'So-Awa', + 'Troisdorf', + 'Tuban', + 'Palmerston North', + 'Padre Hurtado', + 'Palo', + 'Keshod', + 'Infanta', + 'East Ham', + 'Daisen', + 'Nahavand', + 'Bender', + 'Wenatchee', + 'Weston-super-Mare', + 'Montepuez', + 'Esteio', + 'Southfield', + 'Kahror Pakka', + 'Lins', + 'Wilhelmshaven', + 'Fancheng', + 'Molina de Segura', + 'San Ramon de la Nueva Oran', + 'Chintamani', + 'Ryugasaki', + 'Manaoag', + 'Rochester Hills', + 'Banska Bystrica', + 'Merouana', + 'Yanam', + 'Tailai', + 'Toba Tek Singh', + 'Villa Elisa', + 'Valdosta', + 'Houmt Souk', + 'Rulin', + 'Chateauguay', + 'Gladbeck', + 'Catacaos', + 'Kengtung', + 'Ovalle', + 'Solok', + 'Sankt Gallen', + 'Espinal', + 'Benalmadena', + 'Surendranagar', + 'Stakhanov', + 'Sentani', + 'Malappuram', + 'Kargilik', + 'Merignac', + 'Cadereyta Jimenez', + 'Laiyuan', + 'Xaignabouli', + 'Lod', + 'Sidi Qacem', + 'Maghaghah', + 'Arta', + 'Sapiranga', + 'Owensboro', + 'Umea', + 'Arjona', + 'Apple Valley', + 'Jocotan', + 'Ain Temouchent', + 'Woodbury', + 'Garhi', + 'Cataguases', + 'Aviles', + 'Joensuu', + 'Jablah', + 'Ramla', + 'Tres Coracoes', + 'Landshut', + 'Saint-Maur-des-Fosses', + 'Tindivanam', + 'Carlisle', + 'Srivilliputtur', + 'Kiyose', + 'Xinglong', + 'Bhadarwah', + 'Ranaghat', + 'Cheria', + 'South Shields', + 'Kai', + 'Bonab', + 'Villa Carlos Paz', + 'Ciudad Real', + 'Ardakan', + 'Cua Lo', + 'Acacias', + 'Frontera', + 'Itapira', + 'Tissemsilt', + 'Pawtucket', + 'Lagoa Santa', + 'Dhrangadhra', + 'Kunitachi', + 'Dayr al Balah', + 'Pinamungahan', + 'Antibes', + 'East Kilbride', + 'Teyateyaneng', + 'Aracati', + 'Detmold', + 'Newcastle under Lyme', + 'Mawatagama', + 'Burton upon Trent', + 'Libon', + 'Belleville', + 'Telemaco Borba', + 'St. Joseph', + 'Gangammapeta', + 'Puqiancun', + 'Iju', + 'Wisil', + 'Al Muharraq', + 'Khejroli', + 'Tirumangalam', + 'Pardiguda', + 'Warabi', + 'Bugallon', + 'Tocumen', + 'Cherry Hill', + 'Panggezhuang', + 'Jaora', + 'Doral', + 'Gonen', + 'Fouchana', + 'Amakusa', + 'Tura', + 'Ambajogai', + 'Juchitan de Zaragoza', + 'Dabra', + 'Ubud', + 'Sasagawa', + 'Darhan', + 'Pozorrubio', + 'Toffo', + 'Tiznit', + 'Esperanza', + 'Tanguieta', + 'Tosu', + 'Moulay Abdallah', + 'Cotorro', + 'Drohobych', + 'Dalaguete', + 'Piracununga', + 'Ouro Preto', + 'Cinisello Balsamo', + 'Missouri City', + 'Dayong', + 'Bayreuth', + 'Itahari', + 'Peda-Houeyogbe', + 'Katori', + 'Kandori', + 'Shancheng', + 'Bozuyuk', + 'San Antonio de Los Altos', + 'Assab', + 'Gbawe', + 'Skelleftea', + 'Balingasag', + 'Saratoga Springs', + 'Arnsberg', + 'Wandiwash', + 'Ouake', + 'Ramhormoz', + 'Pocatello', + 'Bongouanou', + 'San Juan Opico', + 'Miki', + 'Oshkosh', + 'Uspantan', + 'Silao', + 'Brick', + 'New Britain', + 'Cinar', + 'Zlin', + 'Izumiotsu', + 'Caninde', + 'Mankono', + 'Le Kram', + 'Aprilia', + 'Okegawa', + 'Meshgin Shahr', + "Al Qa'im", + 'Airdrie', + 'Blagoevgrad', + 'Castle Rock', + 'Chalchuapa', + 'Gudur', + 'Casoria', + 'Pedro Brand', + 'Gravesend', + 'Ra`ananna', + 'Brookes Point', + 'Tatebayashi', + 'Lauderhill', + 'Kyotanabe', + 'Kahan', + 'Tatsunocho-tominaga', + 'Majalengka', + 'Broomfield', + 'Sarnia', + 'Dale City', + 'Vlaardingen', + 'Tamworth', + 'Samundri', + 'Dumangas', + 'Alicia', + 'Di An', + 'Yurihonjo', + 'Ain Oulmene', + 'Cunhinga', + 'Ajaccio', + 'Haveri', + 'Castrop-Rauxel', + 'Turkoglu', + 'Beysehir', + 'Bolingbrook', + 'Redmond', + 'Caguas', + 'El Kef', + 'Gouda', + 'Mansfield', + 'Tefe', + 'Tarn Taran', + 'Nandi Hills', + 'Hoorn', + 'Mangalagiri', + 'Joao Monlevade', + 'Brandenburg', + 'Linares', + 'Ellicott City', + 'Vriddhachalam', + 'Harrogate', + 'Copacabana', + 'Cao Bang', + 'Targu Jiu', + 'Sheboygan', + 'Xindian', + 'Kallakkurichchi', + 'Irece', + 'El Hamma', + 'Kumluca', + 'Paterna', + 'Bandar-e Genaveh', + 'Tupi', + 'Lala', + 'Kasipalaiyam', + 'Glens Falls', + 'Asti', + 'Inuyama', + 'Pancevo', + 'Jose Abad Santos', + 'Bagan Si Api-api', + 'Daytona Beach', + 'Reconquista', + 'Quillota', + 'Cannes', + 'Crewe', + 'Lodi', + 'Redlands', + 'Tan-Tan', + 'Fada Ngourma', + 'Otawara', + 'Pacajus', + 'Shakargarh', + 'Harrisonburg', + 'Ragusa', + 'Ciudadela', + 'Bula', + 'Pattukkottai', + 'Almelo', + 'Gobindgarh', + 'Nabeul', + 'Edea', + 'Brakpan', + 'Nea Smyrni', + 'Usulutan', + 'Shibukawa', + 'Lujan de Cuyo', + 'Moa', + 'Berdychiv', + 'Dothan', + 'Baghlan', + 'Chaigoubu', + 'Santa Rosa de Cabal', + 'Santa Isabel do Para', + 'Turkmenbasy', + 'Naqadeh', + 'Catalca', + 'San Vicente del Caguan', + 'Jinja', + 'Russas', + 'La Dorada', + 'Mackay', + 'Padre Las Casas', + 'Kostiantynivka', + 'Khomeyn', + 'Joyo', + 'Tocoa', + 'Mount Vernon', + 'Jingzhou', + 'Caserta', + 'Paine', + 'Catanauan', + 'Spijkenisse', + 'Sodertalje', + 'Centreville', + 'Huong Tra', + 'Amparo', + 'Yafran', + 'Lappeenranta', + 'Carles', + 'Sanwal', + 'Rio do Sul', + 'Yukuhashi', + 'Sremska Mitrovica', + 'Gaspar', + 'Myslowice', + 'Majadahonda', + 'Zhuolu', + 'San Dionisio', + 'Weligama', + 'Nepalganj', + 'Siruguppa', + 'Tangalla', + 'Bacacay', + 'Hekinan', + 'Sipalay', + 'Aschaffenburg', + 'Dazaifu', + 'Samborondon', + 'Longkoucun', + 'Alegrete', + 'Keshan', + 'Candeias', + 'Altoona', + 'Sangareddi', + 'Benidorm', + 'Zogbodome', + 'Marousi', + 'Wood Buffalo', + 'Dambulla', + 'Goya', + 'Oroquieta', + 'Virudunagar', + 'Abancay', + 'Penafiel', + 'Palin', + 'Turbana', + 'Yoshikawa', + 'Santo Antonio do Descoberto', + 'El Banco', + 'Warora', + 'Casa Nova', + 'Tibati', + 'Saint-Nazaire', + 'Sault Ste. Marie', + 'Camalig', + 'Najran', + 'Belo Tsiribihina', + 'Myaydo', + 'Al Lith', + 'Bella Vista', + 'Bailongqiaocun', + 'Chaklasi', + 'Nilanga', + 'Long My', + 'Borongan', + 'Wenping', + 'Gumaca', + 'Stara Pazova', + 'Bocholt', + 'Ararangua', + 'Esbjerg', + 'Merzifon', + 'Goianira', + 'Chiryu', + 'Cacak', + 'Quilandi', + 'Carpi', + 'Ludenscheid', + "Mun'gyong", + 'Ishioka', + 'Jabuticabal', + 'Calauag', + 'Castro', + 'Cajamar', + 'Framingham', + 'Camden', + 'Sao Sebastiao do Paraiso', + 'Bouafle', + 'Patzun', + 'Kabarore', + 'Sambrial', + 'Pila', + 'Dondo', + 'Shrewsbury', + 'Manikganj', + 'Baldwin Park', + 'Florida', + 'Rocklin', + 'Porterville', + 'Agios Dimitrios', + 'Calarca', + 'Tarin Kot', + 'Bakixanov', + 'Kawm Umbu', + 'Mandla', + 'Tamarac', + 'Palmeira dos Indios', + 'Ostend', + 'Saymayl', + 'Indaial', + 'La Estrella', + 'Sonsonate', + 'Pililla', + 'Santo Tirso', + 'Gosport', + 'Bartin', + "Dias d'Avila", + 'Lomas del Mirador', + 'Nanfengcun', + 'Salama', + 'Biankouma', + 'Lisburn', + 'Rayadrug', + 'Mamoudzou', + 'Glen Burnie', + 'Halmstad', + 'Le Bardo', + 'Binalbagan', + 'Shahrixon', + 'Bilara', + 'Villa Tunari', + 'Huanchaco', + 'Campo Formoso', + 'Goa', + 'Drancy', + 'Rayagada', + 'Blacksburg', + 'Talibon', + 'Las Piedras', + 'Ganthier', + 'Jinsha', + 'Parappanangadi', + 'Konongo', + 'Wausau', + 'Sumter', + 'Gela', + 'Placetas', + 'Janesville', + 'Melong', + 'Fernandopolis', + 'Musashimurayama', + 'Brunswick', + 'Morong', + 'San Francisco del Rincon', + 'Gibara', + 'Ratangarh', + 'Tandur', + 'Bakhmut', + 'Terme', + 'Markapur', + 'Bunbury', + 'Sihanoukville', + 'Mauban', + 'Tejupilco', + 'Alabang', + 'Goianesia', + 'Warzat', + 'Montecristi', + 'Ayvalik', + 'Nadi', + 'Zografos', + 'An Nu`maniyah', + 'Izalco', + 'Malaut', + 'Lowestoft', + 'Waukesha', + 'Samraong', + 'Kopargo', + 'Phitsanulok', + 'Kodungallur', + 'Corozal', + 'Neyyattinkara', + 'Kumanovo', + 'Fairbanks', + 'Ejura', + 'Zinjibar', + 'Sesvete', + 'Erd', + 'Zadar', + 'Fatehabad', + 'Bapatla', + 'Kalamasseri', + 'Tumauini', + 'Izmail', + 'Ostrow Wielkopolski', + 'Lakeville', + 'St. Charles', + 'Sirvan', + 'Al Qurayya', + 'Gardez', + 'Cremona', + 'Pavia', + 'Rugby', + 'Badvel', + 'Loule', + 'Redondo Beach', + 'Yinying', + 'Chiang Rai', + 'Karasu', + 'Shujaabad', + 'Stafford', + 'Valparai', + 'Yambol', + 'Djemmal', + 'Chingford', + 'Cabudare', + 'Sankaranayinar Kovil', + 'Xangongo', + 'Uxbridge', + 'Zenica', + 'Bundaberg', + 'Suratgarh', + 'Tamana', + 'Kaukhali', + 'Sig', + 'Bayonne', + 'Coari', + 'Grand Forks', + 'Baiquan', + 'Mindelo', + "Togoch'ale", + 'Noblesville', + 'Torremolinos', + "Bur Fu'ad", + 'Capanema', + 'Noisy-le-Grand', + 'Yawata-shimizui', + 'Orani', + 'Dandeli', + 'Santa Maria La Pila', + 'Minxiong', + 'Huwei', + 'Bopa', + 'Brumado', + 'Havirov', + 'Hujra Shah Muqim', + 'Sa`dah', + 'Ban Houayxay', + 'Nandura Buzurg', + 'Dimbokro', + 'Rizal', + 'Tinambac', + 'Pazarcik', + 'Guaynabo', + 'Celle', + 'Sagunto', + 'El Paso de Robles', + 'Kabirwala', + 'Thaba Nchu', + 'North Richland Hills', + 'Maple Grove', + 'Eniwa', + 'Guzhou', + 'Gaura', + 'Mineiros', + "Pan'an", + 'Tsurugashima', + 'Grajau', + 'Cahama', + 'Waingapu', + 'Kempten', + 'Passaic', + 'Blaine', + 'Lubin', + 'Luodong', + 'Thakhek', + 'Castries', + 'Nansang', + 'Al `Amirat', + 'Talamba', + 'Badhan', + 'Dien Bien Phu', + 'Phu Quoc', + 'Longtangwan', + 'Zhanggu', + '`Izbat al Burj', + 'Bijaynagar', + 'Satyamangalam', + 'Madhipura', + 'Kodoli', + 'Az Zubaydiyah', + 'Lake Elsinore', + 'Raha Tiga', + 'Raha', + 'Nikki', + 'Fulda', + 'Avaniyapuram', + 'Rogers', + 'Entebbe', + 'Imerintsiatosika', + 'Eskilstuna', + 'Aigaleo', + 'Rohri', + 'Sagaing', + 'Casas Adobes', + 'Qingquan', + 'Saint John', + 'Farroupilha', + 'Moquegua', + 'Yueshanwan', + 'Altamura', + 'Sherman', + 'Vushtrri', + 'Encarnacion', + 'Konin', + 'Novomoskovsk', + 'Kwamhlanga', + 'Ratnanagar', + 'Villa del Rosario', + 'Amstelveen', + 'Garzon', + 'San Miguel de Allende', + 'Walnut Creek', + 'Sanlucar de Barrameda', + 'San Juan de los Lagos', + 'Los Reyes de Salgado', + 'Basavakalyan', + 'Kiyosu', + 'Conway', + 'Ziguinchor', + 'Minami-Alps', + 'Uwajima', + 'Roxas', + 'Rioverde', + 'Ritto', + 'Eastvale', + 'Saint-Louis du Nord', + 'Inowroclaw', + 'Somasso', + "L'Aquila", + 'Tournai', + 'Bawku', + "Samch'ok", + 'Rhondda', + 'Union City', + 'Biguacu', + 'Michigan City', + 'Thohoyandou', + 'Poptun', + 'Soja', + 'Tripunittura', + 'Toyoake', + 'Al Qusiyah', + 'Alenquer', + 'Aqsu', + 'Chisec', + 'Kirdasah', + 'Poinciana', + 'Nowrangapur', + 'Welland', + 'Kars', + 'Bitola', + 'Planeta Rica', + 'Don Carlos', + 'Bafia', + 'Tulare', + 'Anan', + 'Limonade', + 'Limbe', + 'Shangchuankou', + 'Barra do Garcas', + 'Ongjang', + 'Cuimba', + 'Torbeck', + 'Fedosiia', + 'Gary', + 'Ad Darb', + 'Imola', + 'Necocli', + 'Mansehra', + 'Renk', + 'Mila', + 'Mocuba', + 'Dharmasagaram', + 'Granby', + 'Gaithersburg', + 'San Pascual', + 'Peruibe', + 'Kireka', + 'Kamsar', + 'Ko Samui', + 'Moriya', + 'Tanabe', + 'Mococa', + 'Piotrkow Trybunalski', + 'Varisshiyakuni', + 'Huishi', + 'Yitiaoshan', + 'Bagumbayan', + 'Liuhe', + 'Palghar', + 'La Chorrera', + 'Buenavista', + 'Lippstadt', + 'East Orange', + 'San Jose del Guaviare', + 'Queenstown', + 'Yunnanyi', + 'Aparri', + 'Assen', + 'Ixtaczoquitlan', + 'Aalen', + 'Wesley Chapel', + 'Ponta Delgada', + 'Purisima de Bustos', + 'Arcoverde', + 'Jacona de Plancarte', + 'Pakribarawan', + 'Al Ahmadi', + 'Suwalki', + "Say'un", + 'West Des Moines', + 'Yuriria', + 'Mineral de la Reforma', + 'Indang', + 'Sabae', + 'Alamada', + 'Isna', + 'Venancio Aires', + 'Pozarevac', + 'Kayankulam', + 'Velsen-Zuid', + 'Dalton', + 'Dubuque', + 'Jarabacoa', + 'Paradip Garh', + "Quartu Sant'Elena", + 'Issy-les-Moulineaux', + 'Valle Hermoso', + 'Bouira', + 'San Leonardo', + 'Ilkal', + 'Zapotlanejo', + 'Doboj', + 'Victor Larco Herrera', + 'Igbanke', + 'Nihtaur', + 'Schenectady', + 'Mamungan', + 'Cabo San Lucas', + 'Kladno', + 'Castelldefels', + 'Ankeny', + 'Sanza Pombo', + 'Tangub', + 'Anjangaon', + 'Maricopa', + 'Bardibas', + 'Cergy', + 'Puerto San Jose', + 'Ash Shihr', + 'Oriximina', + 'Adrar', + 'Eagan', + 'Matara', + 'Lodja', + 'St. Albert', + 'Otukpo', + 'Swedru', + 'Nghia Lo', + 'Tynemouth', + 'Sipocot', + 'Tuburan', + 'Villanueva y Geltru', + 'Hanford', + 'Miagao', + 'Xa Muteba', + 'Cuyapo', + 'Mbake', + 'Yorba Linda', + 'Weston', + 'Watsonville', + 'Hameenlinna', + 'Levallois-Perret', + 'Fort McMurray', + 'Lindong', + 'Renukut', + 'Nabha', + 'Ixtlahuacan de los Membrillos', + 'Putrajaya', + 'Al Buraymi', + 'San Pedro Ayampuc', + 'La Barca', + 'Yanghe', + 'Palo Alto', + 'Castillejos', + 'Antalaha', + 'Odate', + 'Siuri', + 'Boditi', + 'Januaria', + 'South Hill', + 'Chengjiao Chengguanzhen', + 'Conceicao do Coite', + 'Formiga', + 'Ksar el Boukhari', + 'Kamuli', + 'Rajsamand', + 'Longshan', + 'Bishnupur', + 'Cannock', + 'Dinslaken', + 'Pesqueira', + 'Colmar', + 'Tepotzotlan', + 'Bayombong', + "Sant'Eufemia Lamezia", + 'Apac', + 'Shashijie', + 'Pongnam', + 'Islahiye', + 'Shawnee', + 'Modasa', + 'Banepa', + 'Youssoufia', + 'Vaasa', + 'Santa Catarina Otzolotepec', + 'Heroica Caborca', + 'Molepolole', + 'Walsall', + 'Manaure', + 'Kovel', + 'Abnub', + 'Zigon', + 'Gauravaram', + 'Bergen op Zoom', + 'Aregua', + 'Ayolas', + 'Herford', + 'Sausar', + 'Yuquan', + 'Taman Senai', + 'Omidiyeh', + 'Huajing', + 'Dhenkanal', + 'Zihuatanejo', + 'Chicacao', + 'Fuefuki', + 'Urun-Islampur', + 'Rolandia', + 'Calais', + 'Stargard Szczecinski', + 'Gopalganj', + 'Itapema', + 'Ankazoabokely', + 'Capelle aan den IJssel', + 'Tome-Acu', + 'Great Falls', + 'Cuilco', + 'Tolanaro', + 'Lala Musa', + 'Russelsheim', + 'Haverhill', + 'Asela', + 'Sousa', + 'Seguela', + 'Shiojiri', + 'Kerpen', + 'Palatine', + 'Corvallis', + 'Bay', + 'Tabatinga', + 'Wanggezhuang', + 'Lushar', + 'Rockville', + 'Nea Ionia', + 'Zrenjanin', + 'Szolnok', + 'Old Bridge', + 'Dolores Hidalgo Cuna de la Independencia Nacional', + 'Liepaja', + "Sa'ada", + 'Skokie', + 'Pikit', + 'Dharapuram', + 'Guruvayur', + 'Kashima', + 'Cedeno', + 'Jagoniguda', + 'Mirpeta', + 'Nizhyn', + 'Lupon', + 'Phalodi', + 'Embu-Guacu', + 'Targoviste', + 'Nueva Guinea', + 'Acilia', + 'Veenendaal', + 'Kati', + 'Guines', + 'Beypore', + 'Casper', + 'El Seibo', + 'Grays', + 'Bongabon', + 'Kissidougou', + 'Cosmopolis', + 'Janauba', + 'Aksum', + 'Cumra', + 'Janiuay', + 'Calimera', + 'Godalming', + 'Pessac', + 'San Mateo Atenco', + 'Botolan', + 'Siddipet', + 'Bulancak', + 'Ilidza', + 'Ames', + 'Rosales', + 'Hihya', + 'Hit', + 'Kraljevo', + 'Bolgatanga', + 'Chiyoda-ku', + 'Viladecans', + 'Karlskrona', + 'Karimama', + 'La Carlota', + 'Focsani', + 'Delray Beach', + 'Nalut', + 'Katwijk', + 'Sammamish', + 'Walton upon Thames', + 'Ramos Arizpe', + 'Aflao', + 'Karakax', + 'Novi Pazar', + 'Cabedelo', + 'Koratla', + 'Saiki', + 'Damba', + 'Yachimata', + 'Zacapa', + 'Cuscatancingo', + 'Guangping', + 'Venissieux', + 'Urla', + 'Lynwood', + 'Hasanpur', + 'Opol', + 'Dundalk', + 'Bethesda', + 'Hashima', + 'Vaxjo', + 'Huquan', + 'Zanhuang', + 'Morristown', + 'Reghaia', + 'Kampung Tengah', + 'Bengkalis', + 'Virginia', + 'Juana Diaz', + 'Sahaswan', + 'Ocoyoacac', + 'Arambagh', + 'Kazanlak', + 'Piduguralla', + 'Massa', + 'Cazin', + 'Lencois Paulista', + 'Tsuruga', + 'Ilo', + 'Obera', + 'Genk', + 'Goz-Beida', + 'Chibok', + 'Ban Suan', + 'Oas', + 'Kankakee', + 'Dangbo', + 'Moita', + 'Agoo', + 'Fajardo', + 'Torreon', + 'El Carmen de Bolivar', + 'Madirovalo', + 'Taman Johor Jaya', + 'Puliyankudi', + 'Neuwied', + 'Lantapan', + 'Asenovgrad', + 'Viterbo', + 'Anamur', + 'Lahat', + 'Itapetinga', + 'Alpharetta', + 'Wilde', + 'Tatabanya', + 'Novi', + 'Martinez', + 'Kavala', + 'Karlstad', + 'Coron', + 'Zacatecoluca', + 'Finchley', + 'Thornton Heath', + 'Sangamner', + 'Chegutu', + 'Kenner', + 'Kiamba', + 'Fukutsu', + 'Wamena', + 'San Remigio', + 'Gohna', + 'Pulivendla', + 'Bay City', + 'Sakrand', + 'Santo Tome', + 'Smila', + 'Ina', + 'Collado-Villalba', + 'Surubim', + 'Menzel Temime', + 'Lutayan', + 'Tulcea', + 'Arima', + 'Weimar', + 'Angat', + 'Qiryat Gat', + 'Kirtipur', + 'Istaravshan', + 'Rio Negro', + 'South San Francisco', + 'Barreirinhas', + 'Qarqan', + 'Bom Jesus da Lapa', + 'Apex', + 'Parkersburg', + 'Xarardheere', + 'San Francisco El Alto', + 'El Prat de Llobregat', + 'San Antonio Suchitepequez', + 'Kanhangad', + 'Xiantangcun', + 'Al Minshah', + 'Los Amates', + 'Xieqiaocun', + 'Jaisalmer', + 'Sao Tome', + 'Singaparna', + 'Malden', + 'Kurabur', + 'Ain Defla', + 'Gniezno', + 'Piripiri', + 'Castro Valley', + 'Narok', + 'Rechytsa', + 'Sao Felix do Xingu', + 'Aran Bidgol', + 'Baqershahr', + 'Giddarbaha', + 'Taby', + 'Purulha', + 'Develi', + 'Villa Curuguaty', + 'Tamluk', + 'Hadjout', + 'Jamjamal', + 'Sinnar', + 'Vaijapur', + 'Jocotitlan', + 'Solano', + 'Pruszkow', + 'Bozeman', + 'Birnin Konni', + 'Tigbauan', + 'Ouricuri', + 'Torquay', + 'Jagraon', + 'Alipur Duar', + 'Pateros', + 'Dhuri', + 'Xibang', + 'Halabjah', + 'Kitamoto', + 'Guider', + 'Dormagen', + 'Villach', + 'Estancia', + 'Itaberaba', + 'Rath', + 'Villasis', + 'Zeist', + 'Mecheria', + 'Brentwood', + 'Farnborough', + 'Jiquilpan de Juarez', + 'Popondetta', + 'Saidu Sharif', + 'Bazar-e Yakawlang', + 'Patuakhali', + 'Sindelfingen', + 'Matamey', + 'Embu', + 'Caripito', + 'Sumbawa Besar', + 'Bucak', + 'Keitumkawn', + 'Autlan de Navarro', + 'Busia', + 'Ioannina', + 'La Ceja', + 'Kolonnawa', + 'Coyula', + 'Chiquimulilla', + 'Don Torcuato', + 'Nagcarlan', + 'Palaio Faliro', + 'Ladysmith', + 'Tomigusuku', + 'Clichy', + 'Igarape-Miri', + 'Bordj Menaiel', + 'Gwacheon', + 'Sabinas', + 'Acarau', + 'Ostrowiec Swietokrzyski', + 'Soloma', + 'Plauen', + "As Suwayda'", + 'Chipindo', + 'Waltham', + 'Faizabad', + 'Sangzishi', + 'Seydisehir', + 'Oued Rhiou', + 'Kensington', + 'Siemianowice Slaskie', + 'Meulaboh', + 'Marinilla', + 'Gerli', + 'Santo Domingo Tehuantepec', + 'Binga', + 'Fredericton', + 'Grevenbroich', + 'Lechang', + 'Faro', + 'Pirane', + 'Narapalli', + 'Fujioka', + 'Tulkarm', + 'Pflugerville', + 'Isabela', + 'Hilongos', + 'Arrecife', + 'Palitana', + 'Roeselare', + 'Valence', + 'Rivera', + 'Rahat', + 'Itamaraju', + 'North Little Rock', + 'Al Qurayn', + 'Dharmapuri', + 'Apaseo el Alto', + 'Sokhumi', + 'Idappadi', + 'Hiriyur', + 'Porto Nacional', + 'Paignton', + 'Potenza', + 'Rosenheim', + 'Chunian', + 'Malvar', + 'Santiago Tianguistenco', + 'Martil', + 'Waterlooville', + 'Sirsi', + 'Sibulan', + 'Povoa de Varzim', + 'Ash Shaykh Zuwayd', + 'Chervonohrad', + 'Saravia', + 'Seraing', + 'Glogow', + 'Atimonan', + 'Laguna Niguel', + 'Ambarawa', + 'Misantla', + 'Kodad', + 'San Clemente', + 'Alba Iulia', + 'Sangmelima', + 'Cienaga de Oro', + 'Bertioga', + 'Vacaria', + 'Qinggang', + 'Ghardimaou', + 'Seinajoki', + 'Tadepalle', + 'Grande Prairie', + 'Welkom', + 'Qal`ah-ye Now', + 'Yanagawa', + 'Niksar', + 'Pomezia', + 'Siuna', + 'Burnsville', + 'Teresa', + 'Randers', + 'Armur', + 'Simav', + 'Ivry-sur-Seine', + 'Horad Zhodzina', + 'Guiseley', + 'Neubrandenburg', + 'Sodegaura', + 'Tiquisate', + 'Tuao', + 'Bankra', + 'Nawalgarh', + 'Spring', + 'Tupa', + 'Port Charlotte', + 'Camocim', + 'Ferrol', + 'Bognor Regis', + 'Tohana', + 'Nieuwegein', + 'Most', + 'Penedo', + 'Inhambane', + 'Songkhla', + 'Sibalom', + 'Trnava', + 'Kangbao', + 'La Linea de la Concepcion', + 'Khagaul', + 'Tenri', + 'Dalja', + 'Ponferrada', + 'Magong', + 'Zarand', + 'Odendaalsrus', + 'Guamuchil', + 'Chakpi Karong', + 'Sundapalaiyam', + 'Fraijanes', + 'Bourges', + 'Jatani', + 'Chokwe', + 'Kurihara', + 'Zvornik', + 'Nawa', + 'Chincha Alta', + 'Jose Panganiban', + 'Chik Ballapur', + 'Guiglo', + 'Quimper', + 'Athni', + 'Eden Prairie', + 'Dedougou', + 'Fredrikstad', + 'Paphos', + 'Capao da Canoa', + 'Hornchurch', + 'Assi Bou Nif', + 'Maidenhead', + 'Greenwood', + 'Yangqingcun', + 'Benevides', + 'Lower Merion', + 'At Tall', + 'Midoun', + 'Millcreek', + 'Yattir', + 'Asahi', + 'Slatina', + 'Bhairahawa', + 'Badr Hunayn', + 'Khulays', + 'Korydallos', + 'Pokrovsk', + 'Rundu', + 'Tajumulco', + 'Akurana', + 'Mitcham', + 'Medicine Hat', + 'Pervomaisk', + 'Feltham', + 'Ito', + 'Dhuburi', + 'Fujiidera', + 'Mirassol', + 'Vittoria', + 'Prilep', + 'Stourbridge', + 'Coon Rapids', + 'Rowlett', + 'Mercedes', + 'Galgamuwa', + 'Ban Lam Sam Kaeo', + 'Abu Qurqas', + 'Kitale', + 'Cajazeiras', + 'Ouled Djellal', + 'Antony', + 'Banda del Rio Sali', + 'Anuradhapura', + 'Svyetlahorsk', + 'Tartagal', + 'Lugano', + 'Gadwal', + 'Tetovo', + 'Horsens', + 'Rockhampton', + 'Qurayyat', + 'Florence-Graham', + 'Teoloyucan', + 'Sidi Barani', + 'Granollers', + 'Nankana Sahib', + 'Visnagar', + 'Puerto Asis', + 'Nago', + 'Commerce City', + 'Vaslui', + 'Pamuru', + 'Caldiran', + 'Kasongo', + 'Kaga', + 'Batatais', + 'Bossier City', + 'Miyoshi', + 'Pabianice', + 'Halton Hills', + 'Beledweyne', + 'Dewsbury', + 'Taylor', + 'Friedrichshafen', + 'Sheikhpura', + 'Narlidere', + 'Marina di Carrara', + 'Irun', + 'Mahdasht', + 'La Habra', + 'Yurimaguas', + 'Campo Bom', + 'Balboa Heights', + 'Washim', + 'Calinog', + 'Mut', + 'Port Orange', + 'Palmela', + 'Moncada', + 'Balad', + 'Itupeva', + 'Gampaha', + 'Woking', + 'Troyes', + 'Nanpara', + 'Tan Phuoc Khanh', + 'Castellammare di Stabia', + 'La Seyne-sur-Mer', + 'Bansalan', + 'Champasak', + 'Lingshou', + 'Qoryooley', + 'Gusang', + 'Brookline', + 'Moore', + 'Koro', + 'Council Bluffs', + 'Tandag', + 'Boadilla del Monte', + 'Ico', + 'Carmen de Viboral', + 'Kapatagan', + 'Bensalem', + 'Anse a Galets', + 'Sittingbourne', + 'Leander', + 'Acton', + 'Dearborn Heights', + 'Herten', + 'Nagakute', + 'Kilis', + 'Mobarakeh', + 'Portel', + 'Ain Harrouda', + 'Rovaniemi', + 'Wenxicun', + 'Bergheim', + 'Berekum', + 'Ranipet', + 'Ambilobe', + 'Wundanyi', + 'Reston', + 'Kolding', + 'Schwabisch Gmund', + 'Kesamudram', + 'Villa Dominico', + 'Ras Tanura', + 'Puerto Penasco', + 'Bainet', + 'Riosucio', + 'Shangtangcun', + 'Boryspil', + 'Carazinho', + 'Kolda', + 'Nagari', + 'Cristalina', + 'Napier', + 'Sherkot', + 'Tighenif', + 'Camaqua', + 'Panchari Bazar', + 'Bannu', + 'Cyuve', + 'Boituva', + 'Raghogarh', + 'Chidambaram', + 'Twickenham', + 'Agia Paraskevi', + 'Analavory', + 'Figueira da Foz', + 'Narwana', + 'Vigevano', + 'North Bergen', + 'Trikala', + 'Cabaret', + 'Montebello', + 'Okha', + 'Zaraza', + 'Nova Odessa', + 'Meshkin Dasht', + 'Viedma', + 'Sihushan', + 'Bhabhua', + 'Koshizuka', + 'Manicaragua', + 'Rouiba', + 'Tendo', + 'Borj el Qoble', + 'Pontiac', + 'Arua', + 'Nanjangud', + 'Camotan', + 'Mongagua', + 'Encinitas', + 'Tagajo', + 'Yongbei', + 'Menzel Bourguiba', + 'Montauban', + 'Rayong', + 'Cambanugoy', + 'Satbayev', + 'Zengqiao', + 'Siddhapur', + 'Plato', + 'Mitoyo', + 'Derik', + 'Zory', + 'Sao Miguel dos Campos', + 'Leszno', + 'Runcorn', + 'Nakhyaungcharipara', + 'Queen Creek', + 'Nkawkaw', + 'Camabatela', + 'Hita', + 'Saraburi', + 'Morada Nova', + 'Naj` Hammadi', + 'Jhargram', + 'Afragola', + 'Santo Amaro', + 'Yangiyul', + 'Bezerros', + 'Sungo', + 'Penapolis', + 'Kapchagay', + 'Shiroi', + 'Offenburg', + 'Xiluodu', + 'Cortazar', + 'Praia', + 'Kolea', + 'San Juan Chamelco', + 'San Antonio del Tachira', + 'Karonga', + 'Wrecsam', + 'Sayyid Sadiq', + 'Valle de Bravo', + 'Hendersonville', + 'Palm Harbor', + 'Hato Mayor', + 'Extremoz', + 'Pico Rivera', + 'Cayenne', + 'May Pen', + 'Vyronas', + 'Asker', + 'Ostuncalco', + 'Ilobasco', + 'Itogon', + 'Port Coquitlam', + 'Korosten', + 'Baao', + 'La Democracia', + 'Uzunkopru', + 'Hasuda', + 'Widnes', + 'Taal', + 'Djibo', + 'Euclides da Cunha', + 'Ramanathapuram', + 'Kozluk', + 'Candon', + 'Sawahlunto', + 'Gia Nghia', + 'Marietta', + 'Hatogaya-honcho', + 'Tunasan', + 'Garbsen', + 'Wesel', + 'Vejle', + 'Tarnowskie Gory', + 'Trikonavattam', + 'Santa Catarina Ixtahuacan', + 'Sanford', + 'Kolomyia', + 'Yala', + 'Salgueiro', + 'Halvad', + 'Mateare', + 'Wels', + 'Barbalha', + 'Woodland', + 'Taua', + 'Margate', + 'Abuyog', + 'Caldwell', + 'Coyhaique', + 'Maues', + 'Huntersville', + 'Bocaranga', + 'Ar Rastan', + 'Caico', + 'Udamalpet', + 'Cabatuan', + 'Mirabel', + 'Ellesmere Port', + 'Santa Rosa de Copan', + 'Barberena', + 'Velika Gorica', + 'Hashimoto', + 'Idiofa', + 'Olbia', + 'Neu-Ulm', + 'Nordre Fale', + 'Ogoshi', + 'Bangor', + 'Iranduba', + 'Neka', + 'Tulunan', + 'Hurth', + 'Adjohon', + 'Wanparti', + 'Jupiter', + 'Tafo', + 'Aisai', + 'Tsushima', + 'Itoman', + 'Soroti', + 'Unna', + 'La Mesa', + 'Nambuangongo', + 'Los Polvorines', + 'Richland', + 'Jinoba-an', + 'Lomza', + 'Tamba', + 'Chamrajnagar', + 'Fort Portal', + 'Pantin', + 'Burhaniye', + 'Meihuacun', + 'Yamatotakada', + 'Bethal', + 'Orion', + 'Artemisa', + 'Sarandi', + 'Kresek', + 'El Wak', + 'Villamaria', + 'Shihe', + 'Puerto Limon', + 'Calulo', + 'Galapa', + 'Cubulco', + 'Mbabane', + 'Oyem', + 'Kyustendil', + 'Huatusco', + 'Castilla', + 'Laoang', + 'Oda', + 'Ibitinga', + 'Kukarmunda', + 'Kokawa', + 'Trang', + 'Viareggio', + 'Revere', + 'Yongyang', + 'Meriden', + 'Tigaon', + 'Matanao', + 'Atotonilco el Alto', + 'Taunton', + 'Dumraon', + 'Piscataway', + 'Itapecuru Mirim', + 'Elk', + 'Monterey Park', + 'Gardena', + 'Slutsk', + 'Vratsa', + 'Euless', + 'Cruz das Almas', + 'Altinozu', + 'Panruti', + 'Lalmanirhat', + 'Ambanja', + 'Ciudad Arce', + 'Velampalaiyam', + 'Laeken', + 'Gubat', + 'Wallasey', + 'Yisuhe', + 'Irvington', + 'Belladere', + 'Mizusawa', + 'Clay', + 'Tirukkoyilur', + 'San Mateo Ixtatan', + 'Parkent', + 'Paracale', + 'Yame', + 'Qoorlugud', + 'Razampeta', + 'Nedumangad', + 'Berrouaghia', + 'Zamosc', + 'Pasaje', + 'San Mariano', + 'Nioro', + 'Abyek', + 'Samut Sakhon', + 'Mbalmayo', + 'Des Plaines', + 'Jinxing', + 'Malay', + 'Souq Sebt Oulad Nemma', + 'Towada', + 'Pirojpur', + 'Manhica', + 'Horqueta', + 'Floriano', + 'Sao Borja', + 'Monte Alegre', + 'Saravan', + 'Tyre', + 'Faruka', + 'Buqda Caqable', + 'Oodweyne', + 'Guigue', + 'Hurlingham', + 'Kribi', + 'Suifenhe', + 'Consuelito', + 'Baba Hassen', + 'Meskiana', + 'Afula', + 'Nahariyya', + 'Gunupur', + 'Mehnajpur', + 'Bayji', + 'Banane', + 'Kakuma', + 'Kratie', + 'Barneveld', + 'Obando', + 'Civril', + 'Babolsar', + 'Union', + 'Thatri', + 'Rubizhne', + 'Registro', + 'Chandralapadu', + 'Legnano', + 'Loughborough', + 'San Vicente del Raspeig', + 'Ponnuru', + 'West Allis', + 'Carrara', + 'Ain Touta', + 'Arankhola', + 'Sigaboy', + 'Kathua', + 'Chambery', + 'Ilog', + 'North Miami', + 'Ozalp', + 'The Hammocks', + 'Escada', + 'Aranjuez', + 'Blainville', + 'North Lakhimpur', + 'Fano', + 'Andradina', + 'Langenfeld', + 'Skhirate', + 'Dongcun', + 'Euskirchen', + 'Ragay', + 'Khartsyzk', + 'Cupertino', + 'Uzice', + 'Lakhdaria', + 'Taylorsville', + 'Vinukonda', + 'Alexandroupoli', + 'Suhareke', + 'Huehuetoca', + 'Vicosa do Ceara', + 'Gohadi', + 'Kananya', + 'Greifswald', + 'Khagaria', + 'Hardenberg', + 'Matera', + 'Petaluma', + 'Bougouni', + 'Karamursel', + 'Huajiang', + 'Sanyo-Onoda', + 'Aguacatan', + 'Sennan', + 'Guerra', + 'Date', + 'Pachora', + 'Ouezzane', + 'Maimbung', + 'Lianzhuangcun', + 'Coroata', + 'Limoeiro do Norte', + 'Chelm', + 'Tiptur', + 'Kokomo', + 'Gopichettipalaiyam', + 'Givatayim', + 'Santee', + 'Alcoy', + 'Itanagar', + 'Esfarayen', + 'Xo`jayli Shahri', + 'Hakkari', + 'Wangzhuang', + 'Stonecrest', + 'White Plains', + 'Montenegro', + 'Yara', + 'Shimotsuke', + 'Druzhkivka', + 'Shirakawa', + 'Tomaszow Mazowiecki', + 'Los Andes', + 'Ouinhri', + 'Hua Hin', + 'Stralsund', + 'As Saff', + 'Galatsi', + 'Kesennuma', + 'Garin', + 'Ruhengeri', + 'Joso', + 'Niort', + 'Alfonso', + 'Zhoujiajing', + 'Gaibandha', + 'Uniao dos Palmares', + 'Hyuga', + 'Dhone', + 'Irosin', + 'Neuilly-sur-Seine', + 'Serres', + 'Irati', + 'Gannan', + 'Trollhattan', + 'Rajgarh', + 'Katerini', + 'San Simon', + 'Chalkida', + 'Mansalay', + 'Damghan', + 'Chichibu', + 'Umm al Qaywayn', + 'Antigua Guatemala', + 'Panna', + 'Palm Beach Gardens', + 'Barking', + 'Chivacoa', + 'Goppingen', + 'Constanza', + 'Saint-Louis du Sud', + 'Yevlax', + 'Mossel Bay', + 'El Palomar', + 'Tahara', + 'Upi', + 'Metapan', + 'Jiguani', + 'Petroupoli', + 'Huauchinango', + "Kattaqo'rg'on Shahri", + 'Anzio', + 'Motril', + 'Nirgua', + 'Chapel Hill', + 'Santa Maria Chiquimula', + 'Cruz Alta', + 'Cerro de Pasco', + 'Xikeng', + 'Lac-Brome', + 'Andoharanofotsy', + 'Gattaran', + 'Carvajal', + 'Parobe', + 'Sidi ech Chahmi', + 'Zahirabad', + 'Scheveningen', + 'Wani', + 'Binnaguri', + 'Ban Rangsit', + 'Canlaon', + 'Kalamata', + 'Beccar', + 'Manouba', + 'Upleta', + 'El Salvador', + 'Narasapur', + 'Xanthi', + 'Chikuma', + 'Hoboken', + 'Krusevac', + 'Pedro Leopoldo', + 'Parker', + 'Jaguariuna', + 'Blue Springs', + 'Calatagan', + 'Baganga', + 'Faenza', + 'Jovellanos', + 'Shoreline', + 'Dosso', + 'Baguineda', + 'Koja', + 'St. Clair Shores', + 'Kasungu', + 'Sonabedha', + 'Pasrur', + 'Wuyang', + 'Raharpur', + 'Edgware', + 'Xinfeng', + 'Alta Floresta', + 'Kas', + 'Mpondwe', + 'Tenkodogo', + 'Horizon West', + 'Osakasayama', + 'Frutal', + 'Piparia', + 'Caltanissetta', + 'Gllogovc', + 'Una', + 'Balancan', + 'Ibaan', + 'Kelibia', + 'Sardhana', + 'Sao Gabriel', + 'Hastinapur', + 'Crotone', + "Ma'erkang", + 'Tianningcun', + 'Liannong', + 'Liantangcun', + 'Sarcelles', + 'Benevento', + 'Qaskeleng', + 'Trairi', + 'Przemysl', + 'Heerhugowaard', + 'Littlehampton', + 'Sandila', + 'Orland Park', + 'Pebane', + 'Zengcun', + 'Acerra', + 'Ogori', + 'Limerick', + 'Punta Alta', + 'Palompon', + 'Abington', + 'Tiruvalur', + 'Sucun', + 'Murakami', + 'Nanjian', + 'Capenda Camulemba', + 'Ishikari', + 'Antsalova', + 'Lambayeque', + 'Doetinchem', + 'Le Blanc-Mesnil', + 'Pursat', + 'Carson City', + 'Rass el Djebel', + 'Mouscron', + 'Frankfurt (Oder)', + 'Sillod', + 'Ruislip', + 'Mielec', + 'Calarasi', + 'Savona', + 'Naval', + 'Barotac Nuevo', + 'Temascalcingo', + 'Samana', + 'Chivilcoy', + 'Halesowen', + 'Kitahiroshima', + 'Midwest City', + 'Mulbagal', + 'North Vancouver', + 'Rouissat', + 'Bakwa-Kalonji', + 'Dapaong', + 'Maisons-Alfort', + 'Felgueiras', + 'Streatham', + 'Royal Oak', + 'Timargara', + 'Ambahikily', + 'Chibuto', + 'Masantol', + 'Tczew', + 'Pradera', + 'Chornomorsk', + 'Santa Isabel', + 'Kawthoung', + 'Hunsur', + 'Panskura', + 'Nanjakkad', + 'Bowie', + "Kan'onjicho", + 'New Corella', + 'Zempoala', + 'Hameln', + 'Kolondieba', + 'Allanmyo', + 'Cogan', + 'Oued Lill', + 'Nausori', + 'Glew', + 'Lorient', + 'Rampur Hat', + 'Dumanjog', + 'Asingan', + 'Sidi Yahya Zaer', + 'Suileng', + 'Marano di Napoli', + 'Orito', + 'Xiezhou', + 'Royal Tunbridge Wells', + 'Zivinice', + 'Villejuif', + 'Avila', + 'El Attaf', + 'Hervey Bay', + 'Kettering', + 'Khandala', + 'Lonavale', + 'St. Peters', + 'Kosai', + 'General Pico', + 'Oak Lawn', + 'Mogoditshane', + 'Grand-Popo', + 'Stalowa Wola', + 'Gengzhuangqiaocun', + 'Towson', + 'Jerez de Garcia Salinas', + 'Yanguancun', + 'New Plymouth', + 'Camajuani', + 'Taquara', + 'Bilimora', + 'Kothapet', + 'Coconut Creek', + 'Maduraivayal', + 'Togane', + 'Sira', + 'Monte Plata', + 'Lucan', + 'Diriamba', + 'Milagros', + 'Choshi', + 'Palasa', + 'Tokoname', + 'Ejmiatsin', + 'Lenexa', + 'Wiwili', + 'Guarabira', + 'Bartlett', + 'Humaita', + 'Santiago Tuxtla', + 'Cosquin', + 'Chintalapalli', + 'Meerbusch', + 'Lohardaga', + 'Buluan', + 'Cuvelai', + 'Ponte Nova', + 'Richards Bay', + 'Acara', + 'South Whittier', + 'Foumbot', + 'Antsinanantsena', + 'Huaniu', + 'Qianwu', + 'Nacaome', + 'Bebington', + 'Molfetta', + 'Tieshansi', + 'Eldorado', + 'Mali', + 'Roermond', + 'Weymouth', + 'Coruripe', + 'Lake Havasu City', + 'Macherla', + 'Boac', + 'Gumushane', + 'Bimgal', + 'Nova Esperanca', + 'Icara', + 'Kandukur', + 'Tres Arroyos', + 'Saint-Hyacinthe', + 'Keonjhargarh', + 'Villa Hayes', + 'Aldershot', + 'Bilhorod-Dnistrovskyi', + 'Cupang', + 'Alangalang', + 'Samannud', + 'Belize City', + 'Bulungu', + 'Uson', + 'Boufarik', + "Ping'an", + 'Kollegal', + 'Cosamaloapan', + 'Sarapiqui', + 'Moknine', + 'Bel Air South', + 'Unjha', + 'Benslimane', + 'Uki', + 'Nonoichi', + 'Moramanga', + 'Frejus', + 'Borujen', + 'Devrek', + 'Maun', + 'Fountainebleau', + 'Wylie', + 'Mafeteng', + 'Bail-Hongal', + 'Jasaan', + 'Dehdasht', + 'Semara', + 'Alvarado', + 'Baden-Baden', + 'Lunglei', + 'Minokamo', + 'Ipele', + 'Bura', + 'Zushi', + 'Talagante', + 'Ribnita', + 'Nasirabad', + 'Cerignola', + 'Rodos', + 'Cuemba', + 'Tezonapa', + 'Ushuaia', + 'Ban Bang Kaeo', + 'Cachoeiras de Macacu', + 'Machang', + 'Huaixiangcun', + 'Kedzierzyn-Kozle', + 'Puerto Boyaca', + 'Azzaba', + 'Mora', + 'Xam Nua', + 'Limbang', + 'Dina', + 'Gudalur', + 'Ipira', + 'Caacupe', + 'Miragoane', + 'Samalkot', + 'Karimganj', + 'Acambay', + 'Pinagkaisahan', + 'Bobbili', + 'Irpin', + 'Bebandem', + 'Chinhoyi', + 'Highland', + 'Fussa', + 'Fountain Valley', + 'Bowmanville', + 'Duzici', + 'Kalna', + 'Sattenapalle', + 'Tulcan', + 'Al Hoceima', + 'Lagonoy', + 'Basey', + 'Beauvais', + 'Kudamatsu', + "Pau d'Alho", + 'Hod HaSharon', + 'Pirapora', + 'Barabai', + 'Mugla', + 'Vrindavan', + 'Chini', + 'Acambaro', + 'Diglipur', + 'Khash', + 'Beni Enzar', + 'Den Helder', + 'Forest', + 'Macclesfield', + 'Pangantocan', + 'Gorlitz', + 'Wellingborough', + 'Taybad', + 'Berwyn', + 'Ar Riqqah', + 'Lingen', + 'Ramon', + 'Ixtahuacan', + 'Limoeiro', + 'Porto Feliz', + 'Naugaon Sadat', + 'Colomba', + 'Sendhwa', + 'Athieme', + 'El Cerrito', + 'Bartolome Maso', + 'Stolberg', + 'Moyobamba', + 'Bianyang', + 'Tiwi', + 'Severn', + 'Talegaon Dabhade', + 'Rafael Calzada', + 'Wote', + 'Hassa', + 'Rolim de Moura', + 'Mocoa', + 'Boudouaou', + 'Narbonne', + 'Villarrica', + 'Binalonan', + 'Longxing', + 'Sankt Augustin', + 'Sucat', + 'National City', + 'Placer', + 'Pacos de Ferreira', + 'Rosh Ha`Ayin', + 'Korkuteli', + 'Lian', + 'Narammala', + 'Libungan', + 'Amarante', + 'Magsaysay', + 'Lacey', + 'Bihac', + 'Pelengana', + 'Esquipulas', + 'Kut-e `Abdollah', + 'Poonamallee', + 'Sarikei', + "M'diq", + 'Gangarampur', + 'Rahovec', + 'Oosterhout', + 'Hohoe', + 'Mount Prospect', + 'Arcadia', + 'Dongola', + 'Mota', + 'Mukocho', + 'Khlong Luang', + 'Tilakpur', + 'Moncalieri', + 'Castelo Branco', + 'Mizuho', + 'Diffun', + 'Cuizhuangzi', + 'Waiblingen', + 'Tiruvallur', + 'Mandapeta', + 'San Andres Villa Seca', + 'Tirur', + 'Mendi', + 'Takizawa', + 'Kimilili', + 'Eschweiler', + 'Bonga', + 'Pithoragarh', + 'Kengri', + 'Huaquillas', + 'Myaungmya', + 'Intibuca', + 'Bluefields', + 'Oke-Mesi', + 'Langtang', + 'Ropar', + 'Parsippany-Troy Hills', + 'Abu Za`bal', + 'Chiapa de Corzo', + 'Lower Bicutan', + 'General Tinio', + 'Takaishi', + 'Acul du Nord', + 'Ajodhya', + 'DeSoto', + 'Smyrna', + 'Bungoma', + 'Longmen', + 'Khan Shaykhun', + 'Changling', + 'Belampalli', + 'Kharar', + 'Viramgam', + 'Zarrin Shahr', + 'Sidi Bennour', + 'Hilden', + 'Bradenton', + 'Braintree', + 'Bambang', + 'Biswan', + 'Tsevie', + 'Rengo', + 'Gulariya', + 'Cuneo', + 'Umm Ruwaba', + 'Kannamangalam', + 'Royal Leamington Spa', + 'Azul', + 'Atchampeta', + 'Oulad Yaich', + 'New Brunswick', + 'Nogata', + 'Asadabad', + 'Tursunzoda', + 'Paombong', + 'Bedzin', + 'Zile', + 'Nawucun', + 'Siliancun', + 'Hashtgerd', + 'Nueva Loja', + 'Meaux', + 'Portimao', + 'Hoogeveen', + 'Nyenga', + 'Guliston', + 'Iba', + 'Mulanay', + 'Kuala Kapuas', + 'Tinley Park', + 'Finote Selam', + 'Ha Giang', + 'Trapani', + 'Urbiztondo', + 'Saravena', + 'Nuevo Casas Grandes', + 'Buthidaung', + 'Raxaul', + 'Pulheim', + 'Kidderminster', + 'Shendi', + 'Sankt Polten', + 'Opava', + 'Agrigento', + 'Chystiakove', + 'San Agustin Acasaguastlan', + 'Sarasota', + 'Barwani', + 'PortoAlexandre', + 'Barrow in Furness', + 'Batac', + 'Videira', + 'Qiryat Ata', + 'Hacienda Heights', + 'Chicopee', + 'Nansan', + 'Tonekabon', + 'Zalaegerszeg', + 'Biala Podlaska', + 'Xinqing', + 'Monte Mor', + 'Tatalon', + 'Ovar', + 'Sacapulas', + 'Asturias', + 'Toki', + 'Erumaippatti', + 'Khorramdarreh', + 'Langenhagen', + 'Thermi', + 'Yamasa', + 'Taliwang', + 'West Haven', + 'Winneba', + 'Harpanahalli', + 'Buta', + 'Midalt', + 'Herriman', + 'Umm el Fahm', + 'Meyerton', + 'Periya Semur', + 'Moreno', + 'Tres Pontas', + 'Wangguanzhuang Sicun', + 'Nordhorn', + 'Madhupur', + 'Foligno', + 'Perth Amboy', + 'Rijswijk', + 'Porirua', + 'Pombal', + 'Chalil', + 'Pinto', + 'Verviers', + 'Colmenar Viejo', + 'Challakere', + 'Casa Grande', + 'Wuhuang', + 'Tigard', + 'Biel/Bienne', + 'Kronjo', + 'Puthiyangadi', + 'Lazarevac', + 'Namakkal', + 'Vranje', + 'Ibipora', + 'Hyeres', + 'Stryi', + 'Mangrol', + 'Shijonawate', + 'Bekescsaba', + 'Novohrad-Volynskyi', + 'Manapla', + 'Chonthrhu', + 'Bhimunipatnam', + 'Zgierz', + 'Olimpia', + 'Eqbaliyeh', + 'Rangewala', + 'Bobigny', + 'Apopka', + 'Ucuma', + 'Lampang', + 'Falakata', + 'Uniao da Vitoria', + 'Canoinhas', + 'Agbangnizoun', + 'Bilis Qooqaani', + 'Elenga', + 'Polur', + 'Bhongir', + 'Tasgaon', + 'Bad Homburg', + 'Narutocho-mitsuishi', + 'Dompu', + 'Songjiangcun', + 'Catu', + 'Sirnak', + 'La Roche-sur-Yon', + 'Granadilla de Abona', + 'Trani', + 'Oxchuc', + 'Tequisquiapan', + 'Corby', + 'Nandod', + 'Tivoli', + 'Southaven', + 'Imaricho-ko', + 'Acipayam', + 'Luquembo', + 'Canterbury', + 'Zhushan', + 'Pithapuram', + 'Queensburgh', + 'Jelgava', + 'Minamiuonuma', + 'Bad Salzuflen', + 'Khurai', + 'Swidnica', + 'Ojok-tong', + 'Tacuarembo', + 'Punganuru', + 'Trencin', + 'Hidaka', + 'Piedade', + 'Barranqueras', + 'Chaiwu', + 'Sarpsborg', + 'Belen de Escobar', + 'Schweinfurt', + 'Phuthaditjhaba', + 'Saruhanli', + 'Carigara', + 'Sara', + 'Hattingen', + 'Chone', + 'Mikkeli', + 'Chota', + 'Gabrovo', + 'Annaka', + 'Ghatal', + 'Terneuzen', + 'Palmares', + 'Santa Elena', + 'Giurgiu', + 'Sagar', + 'Huntington Park', + 'Mundka', + 'Diamond Bar', + 'Masinloc', + 'Bentonville', + 'Clamart', + 'Buderim', + 'Ortaca', + 'Douar Ain Chkef', + 'Kampen', + 'Antanifotsy', + 'Nihonmatsu', + 'Kouri', + 'Yucaipa', + 'Capitao Poco', + 'Mbulungu', + 'Tapas', + 'Vannes', + 'Pallini', + 'Caojia', + 'Dikwella South', + 'Medianeira', + 'Plainfield', + 'Javanrud', + 'Azrou', + 'Shidong', + 'Shidongcun', + 'Sakurai', + 'Islampur', + 'Umm Qurun', + 'Ruma', + 'Belchatow', + 'Morsott', + 'Sidhi', + 'Rahuri', + 'Chelles', + 'Sado', + 'Hanyu', + 'Zarafshon Shahri', + 'San Manuel', + 'Kizilpinar', + 'Paracin', + 'Aspen Hill', + 'Rocky Mount', + 'Cornillon', + 'Valle del Guamuez', + 'Ankadinondry-Sakay', + 'Rotorua', + 'Peabody', + 'Don Bosco', + 'Frydek-Mistek', + 'Wetzlar', + 'Hashtpar', + 'Kasaragod', + 'Komotini', + 'West Sacramento', + 'Frenda', + 'Bir Ali Ben Khalifa', + 'Wayne', + 'Huesca', + 'Ixhuatlan de Madero', + 'Cajica', + 'Louang Namtha', + 'Puttur', + 'Mariano Acosta', + 'Jalor', + 'Tarma', + 'San Jacinto', + 'Cheddra', + 'Kunnamkulam', + 'Kentwood', + 'Palmaner', + 'Xihu', + 'Jalakati', + 'Deolali', + 'Lozova', + 'Prachuap Khiri Khan', + 'Ribeira do Pombal', + 'Juanjui', + 'Tagkawayan', + 'Ghoriyan', + 'Jihong', + 'Kennedy Town', + 'Titay', + 'Puerto Libertador', + 'Minalabac', + 'Neustadt', + 'Umred', + 'Sabbashahr', + 'Bandar-e Torkaman', + 'Hamura', + 'Chenab Nagar', + 'Sohna', + 'Colton', + 'Chilibre', + 'Cholet', + 'Vigan', + 'Manicore', + 'San Bartolome', + 'Chania', + 'An Nimas', + 'Passau', + 'Manfredonia', + 'Cabagan', + 'Bacaadweyn', + 'Narva', + 'Bijar', + 'Iganga', + 'Impasugong', + 'Parvatipuram', + 'Oak Park', + 'Mansala', + 'Ullal', + 'Magpet', + 'Juigalpa', + 'Kitaotao', + 'Louangphabang', + 'Dholka', + 'Ottappalam', + 'Westchester', + 'Sao Francisco do Sul', + 'Zongo', + 'A Yun Pa', + 'Cangola', + 'Funato', + 'Gazipasa', + 'Upata', + 'Wheaton', + 'Hadali', + 'Manjeri', + 'Alcobaca', + 'Kongoussi', + 'Evry', + 'Al Majaridah', + 'Ashta', + 'Sakon Nakhon', + 'Gisenyi', + 'Lower Paxton', + 'Cambundi Catembo', + 'Evora', + 'Encarnacion de Diaz', + 'Ilindu Kothi', + 'Bisceglie', + 'Aloha', + 'Kaliyaganj', + 'Jaggayyapeta', + 'Minnetonka', + 'Brits', + 'Morondava', + 'Modica', + 'Marechal Candido Rondon', + 'Ilgin', + 'Epinay-sur-Seine', + 'Travnik', + 'Extrema', + 'Howell', + 'Hongshandian', + 'Ajuy', + 'Pasacao', + 'Marco de Canavezes', + 'Popesti-Leordeni', + 'Goalpara', + 'Sibonga', + 'Dilovasi', + 'Pryluky', + 'Mutsu', + 'Kleve', + 'Liberia', + 'Yaguajay', + 'Shahpur', + 'Guiuan', + 'Tutoia', + 'Pinellas Park', + 'Ahlen', + 'Granja', + 'Tokamachi', + 'Keighley', + 'Kannapolis', + 'Gorkha', + 'Itabirito', + 'Montesilvano', + 'Tame', + 'Inhumas', + 'Paramount', + 'Dongshan', + 'Amalapuram', + 'Tokmok', + 'Acu', + 'Dangila', + 'Bakhtiyarpur', + 'Legionowo', + 'Arsikere', + 'San Vicente', + 'La Gomera', + 'Saint-Ouen', + 'Qingan', + 'Kabale', + 'Bitonto', + 'Barbosa', + 'Patancheruvu', + 'Capivari', + 'Pinotepa', + 'Barobo', + 'Rondon do Para', + 'Vikarabad', + 'Molave', + 'Baruipur', + 'Beberibe', + 'Deva', + 'Hereford', + 'Dandarah', + 'Dunfermline', + 'Lucban', + 'Texas City', + 'Sagua la Grande', + 'Itapage', + 'Novato', + 'Targovishte', + 'Edina', + 'Naka', + 'Mahmutlar', + 'Elda', + 'Piekary Slaskie', + 'Safranbolu', + 'At Tawahi', + 'Salo', + 'San Estanislao', + 'Izumi', + 'Manglaur', + 'Beloeil', + 'Saint-Quentin', + 'Phra Nakhon Si Ayutthaya', + 'Simojovel de Allende', + 'Kadiolo', + 'Bagheria', + 'Hyosha', + 'Normal', + 'Tilhar', + 'Bondy', + 'Xincheng', + 'Sao Miguel do Guama', + 'Xinguara', + 'Sultanganj', + 'Congonhas', + 'Tiruvalla', + 'Kandira', + 'Mandi Dabwali', + 'Maha Sarakham', + 'Tamiami', + '`Aliabad-e Katul', + 'Clorinda', + 'Grand Island', + 'Siena', + 'Methuen Town', + 'Frechen', + 'Gallarate', + 'Hrazdan', + 'Timbauba', + 'San Remo', + 'Elyria', + 'Lorica', + 'Usa', + 'Harrismith', + 'Sao Francisco', + 'Malkara', + 'Ksar Chellala', + 'Pigcawayan', + 'Ouenza', + 'Jette', + 'Lagoa da Prata', + 'Karak', + 'Madinat Hamad', + 'Woerden', + 'Venkatagiri', + 'Hamtic', + 'Kelaa Kebira', + 'Paracambi', + 'Corbeil-Essonnes', + 'Wolfenbuttel', + 'Bozova', + 'Kobryn', + 'North Bay', + 'Kendale Lakes', + 'Porto Ferreira', + 'Quezaltepeque', + 'San Jose Villa de Allende', + 'Bloomfield', + 'Tramandai', + 'Kahnuj', + 'Yaozhuangcun', + 'Minami-Soma', + 'Zhangjiazhuang', + 'Zhangjiazhuangcun', + 'Sihor', + 'Tizimin', + 'Imbituba', + 'Roskilde', + 'Cagnes-sur-Mer', + 'Nerkunram', + 'Jihlava', + 'Baskale', + 'Marana', + 'Guernica', + 'Bad Kreuznach', + 'Neibu', + 'Velletri', + 'Cihanbeyli', + 'President Roxas', + 'Burauen', + 'Tlacotepec', + 'An Nabk', + 'Panjakent', + 'Qabqa', + 'Bamei', + 'Thongwa', + 'Pacora', + 'Baduria', + 'Dauis', + 'El Rama', + 'Claveria', + 'Barlad', + 'Sironj', + 'Ban Om Noi', + 'San Miguel Ixtahuacan', + 'West New York', + 'Padangpanjang', + 'Ibbenburen', + 'Tonsberg', + 'Altrincham', + 'Coronel Oviedo', + 'Jangaon', + 'Miyakojima', + 'Charlottetown', + 'Marechal Deodoro', + 'Ibajay', + 'Daudnagar', + 'Paraiso do Tocantins', + 'Jiyyammavalasa', + 'Zalau', + 'Acajutla', + 'Antratsyt', + 'Mandamari', + 'Lakhminia', + 'Sison', + 'Ain Sefra', + 'Twin Falls', + 'Marondera', + 'Akbou', + 'Campo Belo', + 'Santo Estevao', + 'Delmiro Gouveia', + 'Taquaritinga', + 'Tekkekoy', + 'Enerhodar', + 'Obidos', + 'Cangandala', + 'Lautoka', + 'Pula', + 'Taxco de Alarcon', + 'Sao Jose do Rio Pardo', + 'Koraput', + 'Mudhol', + 'Avellino', + 'Pola de Siero', + 'Naguilian', + 'Horishni Plavni', + 'Florissant', + 'Alesund', + 'Uriangato', + 'Bato', + 'El Tumbador', + 'Vaulx-en-Velin', + 'Bhajani', + 'Phaltan', + 'Shiraoka', + 'Buique', + 'Glendora', + 'Acatzingo', + 'Diu', + 'Lengquancun', + 'Portici', + 'Ampanihy', + 'Todupulai', + 'Bitlis', + 'Albu Kamal', + 'Chajul', + 'Pontes e Lacerda', + 'Thomazeau', + 'Tangkak', + 'Caetite', + 'Yendi', + 'Gummersbach', + 'Ambohibary', + 'Ad Dabbah', + 'Tejen', + 'Dungu', + 'Takeo', + 'Shiogama', + 'Huamantla', + 'Ibiza', + 'San Onofre', + 'Khattan', + 'Cathedral City', + 'Vaisampakkal', + 'Kumarankari', + 'Al Kharj', + 'Ntoum', + 'Piaseczno', + 'Eilat', + 'Muban Saeng Bua Thong', + 'Santa Eulalia', + 'Mengmeng', + 'Aliso Viejo', + 'Vernon', + 'Liaquatpur', + 'Rumia', + 'San Gil', + 'Wangjiazhai', + 'El Bagre', + 'Tomiya', + 'Alytus', + 'Padre Garcia', + 'Villareal', + 'Vila Real', + 'Arwal', + 'Sevran', + 'Choma', + 'Kardzhali', + 'Melo', + 'Mollet', + 'Fontenay-sous-Bois', + 'M.A. Rasulzada', + 'Palenque', + 'Covilha', + 'Placentia', + 'Sao Gabriel da Cachoeira', + 'Crosby', + 'Sherpur', + 'Burla', + 'Hoffman Estates', + 'Gadarwara', + 'Caleta Olivia', + 'Baranoa', + 'Caldas da Rainha', + 'Caramoan', + 'Gradiska', + 'Pordenone', + 'Utrera', + 'Belle-Anse', + 'Isfara', + 'Guapimirim', + 'Tamboril', + 'Qalqilyah', + 'Kalpi', + 'Aguadulce', + 'Girardota', + 'Civitavecchia', + 'Baiao', + 'Santa Ignacia', + 'Shahr-e Babak', + 'Xanxere', + 'Mulongo', + 'Huazangsi', + 'Tijucas', + 'Irinjalakuda', + 'Menggala', + 'Kokstad', + 'Tachilek', + 'Zeralda', + 'Teramo', + 'Tirupparangunram', + 'Maubin', + 'Tulsipur', + 'Incirliova', + 'Bando', + 'Zangareddigudem', + 'Burien', + 'Barri', + 'Baham', + 'Abdul Hakim', + 'Ravensburg', + 'Ras el Oued', + 'Sombor', + 'Bantacan', + 'Boblingen', + 'Dunwoody', + 'Ensenada Berisso', + 'Susangerd', + 'Mangochi', + 'Willenhall', + 'Peine', + 'Cerca la Source', + 'El Kelaa des Srarhna', + 'Bootle', + 'Stratford', + 'Speyer', + 'Torrelavega', + 'Morrinhos', + 'Nenton', + 'Koumantou', + 'Boukadir', + 'Folkestone', + "'Ain Merane", + 'Tadmur', + 'Rastatt', + 'Samut Prakan', + 'Kalawana', + 'Sape', + 'Lankaran', + 'Rincon de la Victoria', + 'Kyzyl-Kyya', + 'Palm Desert', + 'Puerto Francisco de Orellana', + 'Cutervo', + 'Peranampattu', + 'Guarne', + 'Tamalous', + 'Raciborz', + 'Rongat', + 'Walin', + 'Dartford', + 'Dabhoi', + 'Montijo', + 'Sartrouville', + 'Herning', + 'Bargny', + 'Bhavani', + 'Puthuppariyaram', + 'Mascouche', + 'Collierville', + 'Sidlaghatta', + 'Jurmala', + 'Korce', + 'Levittown', + 'Leopoldina', + 'Martin', + 'Tsukubamirai', + 'Barra', + 'Brejo Santo', + 'Marpalli', + 'Bowringpet', + 'Knysna', + 'Sar-e Pul', + 'Ocampo', + 'San Narciso', + 'Hodal', + 'Fatwa', + 'Rosemead', + 'Rosso', + 'Kot Mumin', + 'Shimencun', + 'Segovia', + 'Kalba', + 'Iormughanlo', + 'Country Club', + 'Tucuru', + 'Massy', + 'Enid', + 'Horsham', + 'Cumbernauld', + 'Pardwal', + 'Djamaa', + 'Cuyahoga Falls', + 'Guaxupe', + 'Tobias Barreto', + 'Esher', + 'Metpalli', + 'Kalamansig', + 'Mishawaka', + 'Andover', + 'Juruti', + 'Babila', + 'Silkeborg', + 'Repalle', + 'Huaiyang', + 'Skenderaj', + 'Mabini', + 'Kyotango', + 'Miyako', + 'Pontal', + 'Campos do Jordao', + 'Teplice', + 'Summerville', + 'Vigia', + 'Nicoya', + 'Bani Walid', + 'Cermik', + 'Turtkul', + 'Geyve', + 'Kuchaiburi', + 'Vyara', + 'Whangarei', + 'Zabid', + 'Sibsagar', + 'Irondequoit', + 'Mahmudabad', + 'Elmshorn', + 'Grapevine', + 'Goshogawara', + 'Jarash', + 'Zumpango', + 'Marigot', + 'Covina', + 'Rio Tinto', + 'Ranchuelo', + 'Quirinopolis', + 'Beruniy', + 'Bikramganj', + 'Agrinio', + 'Goksun', + 'Mweka', + 'Chinchina', + 'Estancia Velha', + 'Sunamganj', + 'Milford city', + 'Neath', + 'Chinnamanur', + 'Draper', + 'Fafe', + 'Cataingan', + 'Kotka', + 'El Jem', + 'Skien', + 'Haskah Menah', + 'Jaru', + 'Metema', + 'Sakaidecho', + 'Catalina Foothills', + 'Arao', + 'Anaiyur', + 'Kosamba', + 'La Calera', + 'Clacton-on-Sea', + "Cava de' Tirreni", + 'Emden', + 'Northwich', + 'Jaspur', + 'Nichinan', + 'Acireale', + 'Susono', + 'Delano', + 'Gloria', + 'El Nido', + 'Mahmud-e Raqi', + 'Forbesganj', + 'Tebourba', + 'Hunedoara', + 'Navirai', + 'Bas Limbe', + 'Tuyserkan', + 'Laksar', + 'Youfangcun', + 'Cabreuva', + 'El Talar de Pacheco', + 'Bar Bigha', + 'Tundla', + 'Arles', + 'Boa Viagem', + 'Bangued', + 'Aringay', + 'Haverford', + 'Tanjombato', + 'Ampitatafika', + 'Plaisance', + 'Wao', + 'Myrnohrad', + 'Chbar Mon', + 'Ma`an', + 'Amulung', + 'Vargem Grande Paulista', + 'Cojutepeque', + 'Chinu', + 'Baghpat', + 'Floresti', + 'Penablanca', + 'Rho', + 'Donsol', + 'Beveren', + 'Rowley Regis', + 'Artur Nogueira', + 'Bhawanipur Rajdham', + 'Houten', + 'Yuki', + 'Goslar', + 'Ghulakandoz', + 'Gombong', + 'Nes Ziyyona', + 'Nakagawa', + 'Palpala', + 'Hamada', + 'Karvina', + 'Adeje', + 'Gopalpur', + 'Willich', + 'Cardona', + 'Qinhe', + 'Bang Bua Thong', + 'Scarborough', + 'Ercolano', + 'Sour el Ghozlane', + 'Deressia', + 'Itarare', + 'Bhadrachalam', + 'Francisco I. Madero', + 'Sfantu-Gheorghe', + 'Tubod', + 'Biaora', + 'Sojat', + 'Yerba Buena', + 'Wolossebougou', + 'Yasu', + 'Hassan Abdal', + 'Murray', + 'Mazara del Vallo', + 'Leith', + 'Heidenheim', + 'Mooresville', + 'Eger', + 'Weert', + 'Sakubva', + 'Qabb Elias', + 'El Ghaziye', + 'Aarsal', + 'Ikot Okoro', + 'Sechura', + 'Chak Thirty-six North Branch', + 'Rukan', + 'Buni', + 'Chak Sixty-one Gugera Branch', + 'Al Wajh', + 'Abu Hamad', + 'Godinlabe', + 'Ceel Dheere', + 'Tukuyu', + 'Kyaliwajjala', + 'Aqchah', + 'Krems an der Donau', + 'Bandar Seri Begawan', + 'Kahemba', + 'Gutao', + 'Xiayang', + 'Dongxishan', + 'Xiazhai', + 'Jieshangya', + 'Saoula', + "'Ain el Turk", + 'Semera', + 'Bogoso', + 'Tammampatti', + 'Sujanpur', + 'Shiv', + 'Bhattu Kolan', + 'Downers Grove', + 'Louveira', + 'Florin', + 'Al Kharjah', + 'Sihora', + 'Chatra', + 'Rovigo', + 'Parasia', + 'Satte', + 'Chake Chake', + 'Cypress', + 'Chahar Dangeh', + 'Simraungadh', + 'Porvoo', + 'Ejeda', + 'Muktagacha', + 'Janin', + 'Shankou', + "Al Ma`alla'", + 'Bigadic', + 'Erftstadt', + 'Lorrach', + 'Stouffville', + 'Hilsa', + 'Poprad', + 'Cuxhaven', + 'Tepeapulco', + 'Neyriz', + 'Pananaw', + 'Xankandi', + 'Boaco', + 'Nohar', + 'Gediz', + 'Gronau', + 'Ain El Aouda', + 'Ostersund', + 'Ostroleka', + 'Cerquilho Velho', + 'Hannan', + 'El Meghaier', + 'Novovolynsk', + 'Jeffersonville', + 'Karapinar', + 'Bhainsa', + 'North Bethesda', + 'Cine', + 'Itupiranga', + 'Selibe Phikwe', + 'Perintalmanna', + 'Padrauna', + 'Bignay', + 'Albi', + 'Gualan', + 'Azusa', + 'Yeovil', + 'Coral Gables', + 'Ridder', + 'Wagga Wagga', + 'Cangucu', + 'Nanao', + 'Zyryanovsk', + 'Perambalur', + 'Chesterfield', + 'Noshiromachi', + 'Coelho Neto', + 'Shawinigan', + 'Aversa', + 'Kandangan', + 'Pirot', + 'Cimitarra', + 'Sosua', + 'McLean', + 'San Juan del Cesar', + 'Huancavelica', + 'Saint-Herblain', + 'Kizhake Chalakudi', + 'Mojo', + 'Leonberg', + 'Dumarao', + 'Sesimbra', + 'Mpigi', + 'Sulleru', + 'St. Louis Park', + 'Arakli', + 'East Honolulu', + 'Rheda-Wiedenbruck', + 'Gao', + 'Shakhtarsk', + 'Bad Oeynhausen', + 'Peddapuram', + 'Payyoli', + 'Tomisato', + 'Maria la Baja', + 'East Brunswick', + 'Santa Lucia del Camino', + 'Kameyama', + 'Monte Alto', + 'Majalgaon', + 'Noveleta', + 'Catemaco', + 'Sao Bento do Una', + 'Villaguay', + 'Singen', + 'Battipaglia', + 'Gennevilliers', + 'Ozgon', + 'Pen-y-Bont ar Ogwr', + 'Nowshahr', + 'Prudentopolis', + 'Suzaka', + 'Prattipadu', + 'Scandicci', + 'Kiblawan', + 'Karlovac', + 'Ksar Hellal', + 'Arifiye', + 'Mulukuku', + 'Freising', + 'Sebeta', + 'Wandan', + 'San Severo', + 'Mbouda', + 'Goba', + 'Kapadvanj', + 'Mailiao', + 'Edenvale', + 'Odiongan', + 'Euclid', + 'Bergkamen', + 'Asakura', + 'Higashiura', + 'Joliette', + 'Zargar', + 'Agustin Codazzi', + 'Tuodian', + 'Tennala', + 'Fangcun', + 'Cintalapa de Figueroa', + 'Midori', + 'Ceres', + 'Samaniego', + 'Straubing', + 'Qalat', + 'Kaedi', + 'University', + 'Notse', + 'Biloxi', + 'Tunuyan', + 'Lulea', + 'Slonim', + 'Saray', + 'Suresnes', + 'Luwero', + 'Guozhen', + 'Hikari', + 'Kefamenanu', + 'Malabang', + 'Sungurlu', + 'Yamaga', + 'El Dorado Hills', + 'Nahuizalco', + 'Pio Duran', + 'Naugachhia', + 'Ardea', + 'Frankenthal', + 'Karlovy Vary', + 'Vinzons', + 'Port-Vila', + 'Bornheim', + 'Oamishirasato', + 'Misterbianco', + 'Cerritos', + 'Nizampur', + 'Farajok', + 'Song Doc', + 'Jaggisettigudem', + 'Dulag', + 'Rye', + 'Changyon', + 'Suwa', + 'Burleson', + 'Libona', + 'Eltham', + 'Fouka', + 'Portage', + 'Rimouski', + 'Al Mayadin', + 'Barnstable', + 'Courtenay', + 'Alcala', + 'Upplands Vasby', + '`Akko', + 'Kangar', + 'Panay', + 'Dumingag', + 'Nomimachi', + 'Jimenez', + 'Couva', + 'Hampstead', + 'Godda', + 'Telerghma', + 'Takeocho-takeo', + 'Empoli', + "Tajura'", + 'Badurpalle', + 'Santo Domingo Suchitepequez', + 'Saint-Priest', + 'Vertientes', + 'Waalwijk', + 'Shimotsucho-kominami', + 'Ain Fakroun', + 'Cacongo', + 'Vincennes', + 'Chikugo', + 'Jales', + 'Nikaweratiya', + 'Bastia', + 'Ocotal', + 'Sanare', + 'El`ad', + 'Sesto Fiorentino', + 'Tunglangan', + 'Tucano', + 'Poway', + 'Lal-lo', + 'Cedar Hill', + 'Harderwijk', + 'Verrettes', + 'Boucan Carre', + 'Dongzhang', + 'Takahama', + 'Mladenovac', + 'Koduvalli', + 'Garmsar', + 'Guntakal Junction', + 'Gooty', + 'Mantova', + 'Brejo da Madre de Deus', + 'Roman', + 'Stillwater', + 'Barendrecht', + 'Colcapirhua', + 'Amora', + 'Caraballeda', + 'Zajecar', + 'Bantval', + 'Barotac Viejo', + 'Angol', + 'Soest', + 'Leiktho', + 'Batajnica', + 'Titusville', + 'Namtu', + 'Yenangyaung', + 'Martigues', + 'Sao Joaquim da Barra', + 'Omitama', + 'Masagua', + 'Orangetown', + 'Cwmbran', + 'Inabanga', + 'Suzukawa', + 'Nyaungu', + 'Sutton in Ashfield', + 'Siocon', + 'Kilvisharam', + 'Begoro', + 'Liujiaxia', + 'Khairabad', + "'Ain Azel", + 'Kyle', + 'Jasdan', + 'Etterbeek', + 'Upperu', + 'Kawkareik', + 'Pedreira', + 'Chieti', + 'Mangalapadi', + 'Wakema', + 'Dollard-des-Ormeaux', + 'West Orange', + 'Babaeski', + 'Kozlu', + 'Minalin', + 'Welwyn Garden City', + 'Damavand', + 'Erlin', + 'Waterford', + 'Stade', + 'Collegno', + 'Beni Yakhlef', + 'Kalima', + 'San Pedro Mixtepec', + 'Alsdorf', + 'Alajuela', + 'Grasse', + 'IJmuiden', + 'Upper Buchanan', + 'Tuba', + 'Levakant', + 'Asuncion Mita', + 'Vite', + 'Kara-Balta', + 'Nong Khai', + 'Beypazari', + 'Jiashizhuangcun', + 'Westfield', + 'Mahayag', + 'Ishigaki', + 'Berastagi', + 'Chhagalnaiya', + 'Titao', + 'Little Elm', + 'Morden', + 'Can', + 'Duyen Hai', + 'Homnabad', + 'Joshimath', + 'Sanmu', + 'Qulicun', + 'Dachau', + 'Smethwick', + 'Hagere Hiywet', + 'Shuishang', + 'Playas', + 'Gumia', + 'Alta Gracia', + 'Finike', + 'Kirkcaldy', + 'Faya', + 'Bokaro', + 'North Highlands', + 'Ami', + 'Dornbirn', + 'Bacolor', + 'Balimbing', + 'Tuckahoe', + 'Wake Forest', + 'Scafati', + 'Minot', + 'Araci', + 'Nettuno', + 'Colonia del Sol', + 'Bocaiuva', + 'Aquidauana', + 'Kanye', + 'Hennef', + 'Tunduru', + 'Liutuancun', + 'Santangpai', + 'Nangal Township', + 'Ena', + 'Monopoli', + 'Yongping', + 'Cuetzalan', + 'Ash Shaykh Badr', + 'Kasuya', + 'Iwakura', + 'Okhtyrka', + 'Basoko', + 'Sadaseopet', + 'New Washington', + 'Hoskote', + 'Barras', + 'Clondalkin', + 'Carepa', + 'Bhamo', + 'Wauwatosa', + 'Bothell', + 'Birendranagar', + 'Glenview', + 'Vila Verde', + 'Tibigan', + 'Figueras', + 'Dyero', + 'Chong Nonsi', + 'Rockwall', + 'Baguanos', + 'Golpayegan', + 'Jalandhar Cantonment', + 'Cornwall', + 'La Reja', + 'Horsholm', + 'Pativilca', + 'Jiquilisco', + 'Monte Santo', + 'Luwuk', + 'Wilson', + 'Victoriaville', + 'Oranienburg', + 'Bhatkal', + 'Higashine', + 'Guroymak', + 'Agueda', + 'Ad Darwa', + "Al Madrah Sama'il", + 'Tremembe', + 'Dungarpur', + 'Mamburao', + 'Diamantina', + 'Rancho Santa Margarita', + 'Chandrawada', + 'Kamidani', + 'Zawiercie', + 'Monte Carmelo', + 'Ocosingo', + 'Vale de Cavalos', + 'Montrouge', + 'Amahai', + 'Ambatondrazaka', + 'Pabellon de Arteaga', + 'La Mirada', + 'Georgina', + 'Sao Benedito', + 'Tonami', + 'Antelope', + 'Hilo', + 'Invercargill', + 'Longchamps', + 'Gracias', + 'Landau', + 'Ono', + 'Yumbe', + 'Chetouane', + 'Al Aaroui', + 'Gava', + 'Hitachi-ota', + 'Dumka', + '`Amuda', + 'Yecun', + 'Kokkola', + 'Catriel', + 'Helsingor', + 'Chioggia', + 'Sogod', + 'Pampan', + 'Vich', + 'Mairena del Aljarafe', + 'Lamia', + 'San Luis Obispo', + 'Puerto Lempira', + 'Bunawan', + 'Rengam', + 'Gaocheng', + 'Okaya', + 'Buena Vista Tomatlan', + 'Azna', + 'Egg Harbor', + 'Changanacheri', + 'Dalaman', + 'Poso', + 'Dulmen', + 'Campi Bisenzio', + 'Umarkhed', + 'Serowe', + 'Liuhu', + 'Indija', + 'Zutphen', + 'Atarra', + 'Altos', + 'Osorio', + 'Chaparral', + 'Malinao', + 'Nanto', + 'Lousada', + 'Villa Constitucion', + 'Chenalho', + 'Penco', + 'Voluntari', + 'Vryheid', + 'Sanski Most', + 'Barnet', + 'Wejherowo', + 'Jobabo', + 'General Martin Miguel de Guemes', + 'Sumisip', + 'Qasbat Tadla', + 'Aubagne', + 'Kifisia', + 'Saint-Malo', + 'Azhikkod', + 'Azhikkal', + 'Rio de Mouro', + 'Loum', + 'Mentor', + 'Talghar', + 'Ocoee', + 'Evreux', + 'Sao Jose de Mipibu', + 'San Andres de Sotavento', + 'Mataquescuintla', + 'Gosen', + 'Snizhne', + 'Cunen', + 'Oued Sly', + 'Ayapel', + 'Vikramasingapuram', + 'Perinton', + 'Waspan', + 'Melle', + 'Jiaganj', + 'Manapparai', + 'Kasumbalesa', + 'As Sa`diyah', + 'Rowland Heights', + 'Zhongtanying', + 'Evesham', + 'Kikugawa', + 'Douz', + 'Decin', + 'La Courneuve', + 'Fort Pierce', + 'Albuera', + 'Rivoli', + 'Yabrud', + 'Urrao', + 'Sidrolandia', + 'Capao Bonito', + 'Cumanayagua', + 'Paderno Dugnano', + 'Ayungon', + 'Brea', + 'Cantel', + 'Sowme`eh Sara', + 'Mattanur', + 'Campobasso', + 'Zarzal', + 'Oro Valley', + 'Chaidari', + 'Dracena', + 'Hagaribommanahalli', + 'Ha Tien', + 'Pallipalaiyam', + 'Calimaya', + 'Corato', + 'East Providence', + 'Saranambana', + 'Dahutang', + 'Al Balyana', + 'Banisilan', + 'Haeryong', + 'Casalnuovo di Napoli', + 'Liulin', + 'Viti', + 'Jitaicun', + 'Cuilapa', + 'San Benedetto del Tronto', + 'Nandikotkur', + 'Herzogenrath', + 'Chomutov', + 'Tomioka', + 'Esplugas de Llobregat', + 'Selu', + 'Stretford', + 'Matay', + 'Mela Gudalur', + 'Martina Franca', + 'Boujad', + 'Campo Maior', + 'Borgne', + 'Kabasalan', + 'Neunkirchen', + 'Pocoes', + 'Lecco', + 'Banbury', + 'Beckenham', + 'Noboribetsu', + 'Blois', + 'Pearl City', + 'Joao Pinheiro', + 'Lorenskog', + 'Nanzhuangzhen', + 'Greenford', + 'Lohja', + 'Isabel', + 'Ayr', + 'Teotihuacan', + 'San Jacinto de Buena Fe', + 'Santa Ana Chiautempan', + 'Al Qusayr', + 'Araioses', + 'Wokingham', + 'Hyvinkaa', + 'Rovenky', + 'Salina', + 'Lukavac', + 'Jesus Menendez', + 'Sanuki', + 'La Jagua de Ibirico', + 'South Brunswick', + 'Taebaek', + 'Stepnogorsk', + 'Guaramirim', + 'Cologno Monzese', + 'Woodstock', + 'Punalur', + 'Kampli', + 'Bizerte', + 'Yashan', + 'Ramat HaSharon', + 'La Caleta', + 'Kuilsrivier', + 'Norala', + 'Nellikkuppam', + 'Daxiang', + 'Ridderkerk', + 'Hioki', + 'Dongnanyanfa', + 'Padra', + 'Fujiyoshida', + 'Schwerte', + 'Hof', + 'Muara Teweh', + 'Yalvac', + 'Wangtan', + 'Libertador General San Martin', + 'Puerto Villarroel', + 'Suluova', + 'Brive-la-Gaillarde', + 'Bruchsal', + 'Langford Station', + 'Beavercreek', + 'Obra', + 'Faratsiho', + 'Hajjah', + 'Nakai', + 'Quinte West', + 'Montevista', + 'Schagen', + 'Lucaya', + 'Aland', + 'Dori', + 'Tuy', + 'Winter Garden', + 'Punal', + 'Hadithah', + 'Potomac', + 'Lower Tungawan', + 'Swietochlowice', + 'Vuyyuru', + 'Cordon', + 'Kadinamkulam', + 'Corroios', + 'Manvi', + 'Jendouba', + 'Farmington', + 'San Francisco de los Romo', + 'Jeomchon', + 'Henrietta', + 'Santa Cruz do Rio Pardo', + 'Nelson', + 'Skierniewice', + 'Kita', + 'Rodgau', + 'Albstadt', + 'Rio Tercero', + 'Pakenham', + 'Alcira', + 'Sardasht', + 'La Independencia', + 'Quva', + 'Charleville-Mezieres', + 'Sao Bento', + 'Manacor', + 'Lissone', + 'Attleboro', + 'Starogard Gdanski', + 'Nilambur', + 'Shimenzhai', + 'Kilmarnock', + 'Marino', + 'Meudon', + 'Cuihua', + 'Bhalki', + 'Halle-Neustadt', + 'Pagalungan', + 'Bindura', + 'Ban Plai Bua Phatthana', + 'Starachowice', + 'Vidin', + 'Kurayoshi', + 'Farim', + 'Cobija', + 'Zhongzhai', + 'Douera', + 'Anandpur', + 'Capannori', + 'Koure', + 'Takashima', + 'Nichelino', + 'Narvacan', + 'Arandelovac', + 'Santana do Ipanema', + 'Carcassonne', + 'Izunokuni', + 'Shimeo', + 'Lawas', + 'Chitre', + 'Tingo Maria', + 'Filderstadt', + 'Labutta', + 'Puerto Tejada', + 'Strongsville', + 'Zhob', + 'Seabra', + 'Tlalmanalco', + 'Choisy-le-Roi', + 'Uniao', + 'Manono', + 'Casimiro de Abreu', + 'Eagle Mountain', + 'Noisy-le-Sec', + 'Borca', + 'Sumpango', + 'Kasaoka', + 'Bridgewater', + 'Jammalamadugu', + 'Acaxochitlan', + 'Beringen', + 'Garhwa', + 'Santurce-Antiguo', + 'San Feliu de Llobregat', + 'Prescott', + 'Sikandra Rao', + 'Cavaillon', + 'Eusebio', + 'Nova Venecia', + 'Bothaville', + 'Bunde', + 'Livry-Gargan', + 'Tomboco', + 'Nawashahr', + 'Trenque Lauquen', + 'Gotha', + 'Ranavav', + 'Mairinque', + 'Bihat', + 'Gahini', + 'Mindat', + 'Bajil', + 'Huilongcun', + 'Camp Perrin', + 'Amboasary', + 'Isiolo', + 'Harasta', + 'Ban Bang Mae Nang', + 'Kikuchi', + 'Dingle', + 'Jaguaquara', + 'Markala', + 'Coonoor', + 'Wodzislaw Slaski', + 'Thoubal', + 'Tamagawa', + 'Paraguacu Paulista', + 'Freeport City', + 'Olive Branch', + 'Ourem', + 'Haymana', + 'Lupao', + 'Donggang', + 'Hokota', + 'Lumba-a-Bayabao', + 'Fastiv', + 'Joal-Fadiout', + 'Koupela', + 'Campo Novo do Parecis', + 'Chepen', + 'Fellbach', + 'Arendal', + 'Stavroupoli', + 'Dharmaragar', + 'Juina', + 'Parys', + 'Goose Creek', + 'Memmingen', + 'Tallbisah', + 'Sicklerville', + 'Chajari', + 'Igarape', + 'Pakaur', + 'Settimo Torinese', + 'Shima', + 'Cheshunt', + 'Jablonec nad Nisou', + 'Shertallai', + 'Havant', + 'Aribinda', + 'Hexiwu', + 'Dodoma', + 'Phan Ri Cua', + 'Kaufbeuren', + 'Nawai', + 'Lubny', + 'Altamonte Springs', + 'Badrashni', + 'Haltom City', + 'Ouled Moussa', + 'Borgerhout', + 'Gollalagunta', + 'Hackensack', + 'Dongsu', + 'Tantangan', + 'Dialakorodji', + 'St. Thomas', + 'Maluso', + 'Muradiye', + 'La Goulette', + 'Changchong', + 'Yambio', + 'Santa Maria Huatulco', + 'Farrukhnagar', + 'Dendermonde', + 'Puttalam', + 'Hokuto', + 'Shangpa', + 'Rosny-sous-Bois', + 'Elmhurst', + 'Mislata', + 'Ogimachi', + 'Porangatu', + 'Jones', + 'Chattamangalam', + 'Denia', + 'Remedios', + 'Tangdukou', + 'Tindouf', + 'El Valle del Espiritu Santo', + 'Qianjiang Shequ', + 'Urbandale', + 'Kitakata', + 'Caiguantun', + 'Nueva Gerona', + 'Baiji', + 'Ascoli Piceno', + 'Kirkby', + 'Mauriti', + 'Rio Cauto', + 'Guacharachi', + 'Talagutong', + 'Kumta', + 'Busaar', + 'Littleton', + 'Cuautepec de Hinojosa', + 'Ortega', + 'Sangarebougou', + 'Veldhoven', + 'Canela', + 'Voi', + 'Warud', + 'Ashburn', + 'Lalian', + 'Bafq', + 'Surcin', + 'Labrea', + 'Kerkrade', + 'Birak', + 'Carnot', + 'Ganapathivattam', + 'East Lansing', + 'Olhao', + 'San Pelayo', + 'Fuxing', + 'West Seneca', + 'Mbulu', + 'Palayan City', + 'Jipijapa', + 'Gobardanga', + 'Barra Velha', + 'Bountiful', + 'Erith', + 'San Antonio Abad', + 'Ciudad de Huajuapam de Leon', + 'Keller', + 'Svitlovodsk', + 'Karmiel', + 'Vallenar', + 'Morgan Hill', + 'Gaoua', + 'Rieti', + 'Saint-Eustache', + 'Weinheim', + 'Pulawy', + 'Neustadt am Rubenberge', + 'Hinckley', + 'Tayug', + 'Misseni', + 'Rada`', + 'Talence', + 'Kelo', + 'Jaragua', + 'Webster', + 'Chimteppa', + 'Gracanica', + 'Sierra Vista', + 'Cornelio Procopio', + 'Vercelli', + 'Ashton', + 'Drachten', + 'Araquari', + 'Medemblik', + 'Paterno', + 'Inongo', + 'Bani `Ubayd', + 'Presidente Dutra', + 'Belfort', + 'Garango', + 'Hassi Messaoud', + 'Sayreville', + 'Basud', + 'Surbiton', + 'Numata', + 'Puertollano', + 'Marau', + 'Massigui', + 'Montemorelos', + 'Castleford', + 'Chalungalpadam', + 'Aguilar', + 'Bingmei', + 'Nova Kakhovka', + 'Inuma', + 'Krosno', + 'Arantangi', + 'Nayudupet', + 'Maracaju', + 'Caete', + 'Alfortville', + 'Haugesund', + 'Bac Kan', + 'Sundargarh', + 'Abqaiq', + 'Chalon-sur-Saone', + 'Odenton', + 'Prievidza', + 'Bilacari', + 'Heusden', + 'Slavonski Brod', + 'Shchuchinsk', + 'Lapa', + 'Cleveland Heights', + 'Pakxan', + 'Batroun', + 'Shahhat', + 'Kutum', + 'Nimule', + 'Jedeida', + 'Baba I', + 'Mlada Boleslav', + 'Rabinal', + 'Mahalingpur', + 'Bhayala', + 'Nalegaon', + 'Muddebihal', + 'Kedgaon', + 'Sachin', + 'Alamuru', + 'Qarabulaq', + 'Dig', + 'Hekou', + 'Tank', + 'Naestved', + 'Barnagar', + 'Brianka', + 'Marhanets', + 'Tres Valles', + 'Angadanan', + 'Timbo', + 'Acopiara', + 'Maria Aurora', + 'Gallatin', + 'Astaneh-ye Ashrafiyeh', + 'Yatagan', + 'Palm Springs', + 'Mount Laurel', + 'Seregno', + 'Pederneiras', + 'Catford', + 'Tarnobrzeg', + 'Port Loko', + 'Borlange', + 'Razgrad', + 'Charkhi Dadri', + 'Azarshahr', + 'Buguias', + 'Sagua de Tanamo', + 'Shangshan', + 'Shazhou', + 'Dois Vizinhos', + 'Guledagudda', + 'Al `Aziziyah', + 'Tateyama', + 'Bolivar', + 'Riverton', + 'West Lafayette', + 'Parigi', + 'Rameswaram', + 'Santiago Atitlan', + 'Meoqui', + 'Port Macquarie', + 'Lehrte', + 'Colotenango', + 'Nasipit', + '`Ayn al `Arab', + 'Barru', + 'Mochudi', + 'Merksem', + 'Falkensee', + 'Bruhl', + 'Santana do Paraiso', + 'Manjuyod', + 'Sao Lourenco', + 'Balcarce', + 'Jidd Hafs', + 'Pemangkat', + 'Zwijndrecht', + 'Chichigalpa', + 'Liuquancun', + 'Xique-Xique', + 'Cutler Bay', + 'Cascina', + 'Itaberai', + 'Worksop', + 'Salon-de-Provence', + 'San Pedro Perulapan', + 'Melur', + 'Terracina', + 'Lake Ridge', + 'Whitney', + 'Dhupgari', + 'Kafr al Battikh', + 'Sapanca', + 'Sete', + 'Pahrump', + 'Flores', + 'Yaopu', + 'Tangjiacun', + 'Soliman', + 'Katipunan', + 'Zamalka', + 'Bharella', + 'Kharan', + 'Zouerate', + 'Pyu', + 'Dowlaiswaram', + 'North Lauderdale', + 'Portugalete', + 'Dolores', + 'Conceicao do Araguaia', + 'Xiluo', + 'Jacaltenango', + 'Kitgum', + 'Sainthia', + 'Gogrial', + 'Mamanguape', + 'Grabouw', + 'Upper Bicutan', + 'Wentzville', + 'Istres', + 'Augusto Correa', + 'Tori-Bossito', + 'Alcamo', + 'Guisa', + 'Jangamguda', + 'Arboletes', + 'Cayambe', + 'Mawlaik', + 'Mantes-la-Jolie', + 'Piendamo', + 'Garca', + 'Fond du Lac', + 'Seferhisar', + 'Otwock', + 'Gori', + 'Nsawam', + 'Culasi', + 'Jalacingo', + 'Petatlan', + 'Shekhupur', + 'Masuda', + 'Tsiroanomandidy', + 'Wiener Neustadt', + 'Rohnert Park', + 'Ellenabad', + 'Banaybanay', + 'Mankato', + 'Moorhead', + 'Radomsko', + 'Morley', + 'Karvarakundu', + 'Sao Sebastiao do Passe', + 'Rapur', + 'Abu al Matamir', + 'Siyana', + 'Abovyan', + 'Angul', + 'Bacnotan', + 'Rajaldesar', + 'Robe', + 'Elmadag', + 'Tongoma', + 'Yaoquan', + 'Santo Antonio da Platina', + 'Sandefjord', + 'Bulalacao', + 'Dalli Rajhara', + 'Houbu', + 'Svishtov', + 'Nandigama', + 'Vlissingen', + 'Beigangwa', + 'San Juan y Martinez', + 'Eqlid', + 'Kolobrzeg', + 'Iwanuma', + 'Kaimana', + "Sao Miguel d'Oeste", + 'Pagsanjan', + 'Changtoushang', + 'The Colony', + 'Jisr ash Shughur', + 'Nanjo', + 'Deinze', + 'General Mamerto Natividad', + 'Cayeli', + 'Barwah', + 'Chauk', + 'Alapli', + 'Pinneberg', + 'Labangan', + 'Bom Conselho', + 'Drama', + 'Sonqor', + 'Medak', + 'Kaarst', + 'Talipparamba', + 'Huatan', + 'Manakara', + 'Iznik', + 'Jora', + 'Pattani', + 'Burke', + 'Loon', + 'Saint-Brieuc', + 'Ananipalle', + 'Erkelenz', + 'Majurwa', + 'Freeport', + 'Cateel', + 'Miliana', + 'Tiberias', + 'Maitum', + 'Regla', + 'El Centro', + 'Dikili', + 'Germencik', + 'Al `Ayyat', + 'Rio Grande da Serra', + 'Las Matas de Farfan', + 'Raisen', + 'Albufeira', + 'Harsin', + 'Turnhout', + 'Shakopee', + 'Central Signal Village', + 'Wilkes-Barre', + 'Mandaon', + 'West Vancouver', + 'Hagi', + 'Daijiazhuang', + 'Togo', + 'Tlajomulco de Zuniga', + 'Roghun', + 'Zevenaar', + 'Lompoc', + 'Hicksville', + 'Talatamaty', + 'Noordwijk', + 'Janakammapeta', + 'Oakland Park', + 'Lombard', + 'Otofuke', + 'Debica', + 'San Vicente de Tagua Tagua', + 'Guinayangan', + 'Al Midhnab', + 'Nocera Inferiore', + 'Murshidabad', + 'Senigallia', + 'Vilvoorde', + 'Boyabat', + 'Korogwe', + 'Ahmadpur', + 'Tinajdad', + 'Limache', + 'Seohara', + 'Yuchengcun', + 'Mucaba', + 'Coatbridge', + 'Tarbes', + 'New Tecumseth', + 'Casale', + 'Labason', + 'Yuanli', + 'Bakamune', + 'Goshikicho-aihara-minamidani', + 'Livramento de Nossa Senhora', + 'Comendador', + 'Ales', + 'Wankaner', + 'Loreto', + 'Wismar', + 'Chalons-en-Champagne', + 'Zongolica', + 'Etten-Leur', + 'Erkrath', + 'Addanki', + 'Hinatuan', + 'Wallsend', + 'Merthyr Tudful', + 'Yirga `Alem', + 'Nidadavole', + 'Ciudad Constitucion', + 'Beni Saf', + 'Xinjun', + 'Baler', + 'Bellinzona', + 'Varazdin', + 'Anekal', + 'Azadshahr', + 'Jaro', + 'Bietigheim-Bissingen', + 'Sugito', + 'Salto de Pirapora', + 'Himi', + 'Lubuk Sikaping', + 'Shyorongi', + 'Zabki', + 'Badian', + 'Thun', + 'Murzuq', + 'Kottangara', + 'Pittsfield', + 'Venray', + 'Kalilangan', + 'North Brunswick', + 'Takab', + 'Cameron Highlands', + 'Bushenyi', + 'Mastaga', + 'Bagneux', + 'Porsa', + 'Bodupal', + 'Krasnodon', + 'Tanghin-Dassouri', + 'Alhaurin de la Torre', + 'Puteaux', + 'Ramachandrapuram', + 'Greenacres', + 'Chembra', + 'Gifhorn', + 'Jinku', + 'Shinshiro', + 'Nijkerk', + 'Roseller Lim', + 'Villeta', + 'Caluire-et-Cuire', + 'Kumatori', + 'Uruara', + 'Cove', + 'Guambog', + 'Prostejov', + "'Ain Arnat", + 'Zhexiang', + 'Presidente Epitacio', + 'Shoranur', + 'Ksar', + 'Rheden', + 'Oakley', + 'Panambi', + 'Kiraz', + 'Jerada', + 'Cimerak', + 'Of', + 'Ponte de Lima', + 'Cesme', + 'Borken', + 'Bahia Honda', + 'Linden', + 'Heinsberg', + 'Tarauaca', + 'Campbell', + 'Moises Padilla', + 'Paoskoto', + 'Al Kiswah', + 'Danville', + 'Pedro Celestino Negrete', + 'Toboso', + 'Kikuyo', + 'Kilosa', + 'Frosinone', + 'Bolvadin', + 'Anse Rouge', + 'Puerto del Rosario', + 'Actopan', + 'De Bilt', + 'Nilothi', + 'Dounan', + 'Trelleborg', + 'Yutiancun', + 'Isla', + 'Jambusar', + 'Xihuachi', + 'Sawakin', + 'Innisfil', + 'Turda', + 'Kozani', + 'Shinas', + 'Hueyapan de Ocampo', + 'El Cua', + 'General Pacheco', + 'Kottoppadam', + 'Douar Bni Malek', + 'El Asintal', + 'Villa de Zaachila', + 'Zhongbu', + 'Lota', + 'Andes', + 'North Miami Beach', + 'Vaudreuil-Dorion', + 'Clermont', + 'Silistra', + 'Vargem Grande', + 'San Sebastian Huehuetenango', + 'Aleksinac', + 'Konarak', + 'Paso de los Libres', + 'Ocozocoautla de Espinosa', + 'Mahallat', + 'Kula', + 'Khawr Fakkan', + 'San Bruno', + 'Ambasamudram', + 'Veroia', + 'Laurel', + 'Yeola', + 'Nagaizumi', + 'Channelview', + 'Vahdat', + 'Shanshan', + 'South Upi', + 'Trujillo Alto', + 'Kapan', + 'Nagykanizsa', + 'Aguazul', + 'Darcheh', + 'Berchem', + 'Dock Sur', + 'Vergina', + 'San al Hajar al Qibliyah', + 'Sonaguera', + 'Baniyas', + 'Zhangliangcun', + 'Chicaman', + 'Cumaribo', + 'Maissade', + 'Khutubi', + 'Ormond Beach', + 'Rantepao', + 'Kayalpattanam', + 'Kobayashi', + 'Inabe', + 'Dun Dealgan', + 'Vargem Grande do Sul', + 'Sidcup', + 'Macenta', + 'Et Taiyiba', + 'Bakau', + 'Nettetal', + 'Taketoyo', + 'Huber Heights', + 'Rudauli', + 'Tesanj', + 'Dunakeszi', + 'Makinohara', + 'Kamen', + 'Alcantarilla', + 'Bron', + 'Yatomi', + 'Barhiya', + 'Woonsocket', + 'Kattivakkam', + 'Kingston upon Thames', + 'Jesus Maria', + 'Gualeguay', + 'Hillsborough', + 'Garbahaarrey', + 'Saoner', + 'Reze', + 'Yepocapa', + 'Valenciennes', + 'Abucay', + 'Periyakulam', + 'Cuchi', + 'Lai Chau', + 'Middleton', + 'Aurich', + 'Chateauroux', + 'Jatibonico', + 'Heist-op-den-Berg', + 'Santo Antonio', + 'San Cristobal Totonicapan', + 'Nandongcun', + 'Nandazhang', + 'Buffalo Grove', + 'Badulla', + 'Akdagmadeni', + 'Char Fasson', + 'Zhangcun', + 'Bairagnia', + 'Sevanagala', + 'Pirthipur', + 'Bradford West Gwillimbury', + 'Tepalcatepec', + 'Villaba', + 'Shimabara', + 'Mahbubabad', + 'Garges-les-Gonesse', + 'Fleet', + 'Kalaiya', + 'Longtoushan Jiezi', + 'Puerto Colombia', + "King's Lynn", + 'Salaberry-de-Valleyfield', + 'Chefchaouene', + 'Laguna', + 'La Mata', + 'West Babylon', + 'Ban Pet', + 'Nueva Valencia', + 'Al Badari', + 'Limbdi', + 'Catonsville', + 'Barreiros', + 'Atenco', + 'Mrirt', + 'Itarema', + 'Altadena', + 'Bukama', + 'Naranjo', + 'Ciechanow', + 'Edmonds', + 'Lokeren', + 'Gravina in Puglia', + 'Linton Hall', + 'Thol', + 'Spanish Fork', + 'Hammam Sousse', + 'Newnan', + 'Sarikamis', + 'Taniyama-chuo', + 'Musina', + 'Orlandia', + 'Meru', + 'Laatzen', + 'Castres', + 'Proper Bansud', + 'Quinhamel', + 'Vineyard', + 'Evere', + 'Mengdong', + 'Cabo Bojador', + 'Kafr al Kurdi', + 'Barpeta', + 'Jefferson City', + 'Webuye', + 'Miranda', + 'Kharik', + 'Sidi Mohamed Lahmar', + 'Mondoro', + 'El Affroun', + 'Sukheke Mandi', + 'Manassas', + 'Tecoanapa', + 'Biella', + 'Zharkent', + 'Puyallup', + 'San Francisco Menendez', + 'Fianga', + 'Arras', + 'Sibenik', + 'Awaji', + 'Salar', + 'Nyunzu', + 'Hwange', + 'Simao Dias', + 'Shuilou', + 'Vera Cruz', + 'Machali', + 'Mata de Sao Joao', + 'Panitan', + 'Jose de Freitas', + 'Thomassique', + 'Jajpur', + 'Sokoura', + 'Tamu', + 'Uruacu', + 'Alluru', + 'Schertz', + 'Guarda', + 'Amberg', + 'Maroantsetra', + 'Balabac', + 'El Charco', + 'Loufan', + 'Kadalur', + 'Coppell', + 'Itapa-Ekiti', + 'Mariel', + 'North Fort Myers', + 'San Giorgio a Cremano', + 'Jambughoda', + 'Dupnitsa', + 'Bairuo', + 'La Orotava', + 'Moline', + 'Seevetal', + 'Karsiyang', + 'Dilbeek', + 'Tucuran', + 'Singhanakhon', + 'Sanarate', + 'Carranglan', + 'San Rafael del Sur', + 'Beverly', + 'Eisenach', + 'Si Sa Ket', + 'Xidiancun', + 'Bassano del Grappa', + 'Bang Kruai', + 'Bhatpalli', + 'Alghero', + 'Balykchy', + 'Melun', + 'Kotabumi', + 'Sao Mateus do Sul', + 'Than', + 'Acatlan de Perez Figueroa', + 'Laungowal', + 'Akaiwa', + 'Shenjiatun', + 'Annandale', + 'Yaguate', + "Qa'en", + 'Ben Zakkay', + 'Rouyn-Noranda', + 'Tome', + 'Iten', + 'Xonobod', + 'Pallisa', + 'Homburg', + 'Kasai', + 'Llanera', + 'Futtsu', + 'Coachella', + 'Coronel Suarez', + 'Alerce', + 'Polanco', + 'Dreieich', + 'Maniwa', + 'Kutno', + 'Hoddesdon', + 'Myanaung', + 'Marki', + 'Akbarpur', + 'President Quirino', + 'Woodlawn', + 'Viborg', + 'Palladam', + 'Uozu', + 'Ansbach', + 'Hilvan', + 'Liloy', + 'Fareham', + 'Meadow Woods', + 'Karmegh', + 'Aritao', + 'Smederevska Palanka', + 'Sarakhs', + 'Coram', + 'Qapshaghay', + 'Jocotepec', + 'Thionville', + 'Amontada', + 'Nysa', + 'Morarano Chrome', + 'Peachtree Corners', + 'Liantang', + 'Angelholm', + 'Anakaputtur', + 'Diyadin', + 'Cortlandt', + 'Dildarnagar', + 'Jinotepe', + 'Pardes Hanna Karkur', + 'Hollister', + 'Villa Bisono', + 'Sbiba', + 'Bensheim', + 'Pratapgarh', + 'Bokhtar', + 'Coyuca de Catalan', + 'Puerto Real', + 'Paraiba do Sul', + 'Guaratuba', + 'Quesada', + 'Imperia', + 'Soran', + 'Sarab', + 'Guaraciaba do Norte', + 'Zhovti Vody', + 'Siegburg', + 'Tineghir', + 'Madridejos', + 'Mampong', + 'San Jose de Bocay', + 'Miercurea-Ciuc', + 'Holly Springs', + 'Wangyuanqiao', + 'Nathdwara', + 'Dronten', + 'Pachkhal', + 'Tinpiple', + 'Santa Rosa del Sur', + 'Stip', + 'Myedu', + 'Songhuajiangcun', + 'Qiryat Mozqin', + 'Lingquan', + 'Muttayyapuram', + 'Vawkavysk', + 'Greenock', + 'Matnog', + 'Sao Lourenco do Sul', + 'Naikankudi', + 'Puerto Galera', + 'Zhujiacun', + 'Yangcunzai', + 'Yagoua', + 'Nuevo San Carlos', + 'Hodmezovasarhely', + 'Tactic', + 'Delaware', + 'Ho Nai', + 'Santa Maria Atzompa', + 'Tiel', + 'Oizumi', + 'Kirchheim unter Teck', + 'Tororo', + 'Minamishimabara', + 'Amadeo', + 'Qiryat Ono', + 'Schwabisch Hall', + 'Kibawe', + 'Ban Wat Lak Hok', + 'Larantuka', + 'Barauli', + 'Dunaujvaros', + 'Beverwijk', + 'Macaubas', + 'Kalmar', + 'Marialva', + 'Coburg', + 'Yinggen', + 'Tadjenanet', + 'El Aioun', + 'Urmston', + 'Coyotepec', + 'Miura', + 'Rancho Palos Verdes', + 'Diamond Harbour', + 'Waxahachie', + 'Jardinopolis', + 'Civitanova Marche', + 'Tadif', + 'Koniz', + 'Uden', + 'Surampatti', + 'Velasco Ibarra', + 'Kasibu', + 'Paicandu', + 'Beitbridge', + 'Dacun', + 'Narayanpet', + 'Torres', + 'El Consejo', + 'Boucherville', + 'Fenoarivo Atsinanana', + 'Saidpur Dabra', + 'Shadegan', + 'Danderesso', + 'Bodo', + 'Alimos', + 'Campechuela', + 'Otavalo', + 'Tavas', + 'Varash', + 'Oued Fodda', + 'Billerica', + 'Tolosa', + 'Kampong Chhnang', + 'Wunstorf', + 'Hempfield', + 'Boumerdes', + 'Pueblo Nuevo', + 'Gonzaga', + 'Litian Gezhuang', + 'Blanes', + 'Bayt al Faqih', + 'Mableton', + 'Jaltipan de Morelos', + 'Prerov', + 'Fitchburg', + 'Kenge', + 'Daram', + 'Ambohitrimanjaka', + 'Yuzawa', + 'Oqtosh Shahri', + 'Shefar`am', + 'Le Cannet', + 'Berubari', + 'Ayagoz', + 'Bullhead City', + 'Su-ngai Kolok', + 'Rajgir', + 'Socorro', + 'Santa Cruz de Los Taques', + 'Shetou', + 'Sipe Sipe', + 'San Pedro Necta', + 'Dubrovnik', + 'Santa Helena', + 'Lloret de Mar', + 'Indi', + 'Amuntai', + 'Rajaori', + 'Slobozia', + 'Lindi', + 'Aguas Belas', + 'Patulul', + 'Yarumal', + 'Copan', + 'Tagudin', + 'San Dona di Piave', + 'Nalhati', + 'Ruteng', + 'Ventanas', + 'Sanand', + 'Puntarenas', + 'Bourg-en-Bresse', + 'Puerto Gaitan', + 'Barra dos Coqueiros', + 'Poti', + 'Shimotsuma', + 'Konigswinter', + 'Zugdidi', + 'Kodinar', + 'Sagauli', + 'Golaghat', + 'Pileru', + 'Sutton', + 'Marlboro', + 'Sinanpasa', + 'Llavallol', + 'Desio', + 'Nola', + 'Eberswalde', + 'Memari', + 'Bani Suhayla', + 'Tabogon', + 'Teaneck', + 'Svay Rieng', + 'Grove City', + 'Arcos', + 'Lusambo', + 'Mondragon', + 'Yakacik', + 'Maplewood', + 'Kendraparha', + 'Villa Angela', + 'Nurtingen', + 'Caerphilly', + 'Marion', + 'Nebbi', + 'Marlborough', + 'Tortuguitas', + 'San', + 'Naini Tal', + 'Erzin', + 'Maulavi Bazar', + 'Bambari', + 'Germering', + 'Kitaibaraki', + 'Sena Madureira', + 'Tuchin', + 'Narathiwat', + 'Brookfield', + 'Obita', + 'Nordhausen', + 'Tezoyuca', + 'Ramganj Mandi', + 'El Tocuyo', + 'Santo Antonio de Padua', + 'Nurdagi', + 'Currais Novos', + 'Mahalapye', + 'Meiganga', + 'Arauquita', + 'Huckelhoven', + 'Tabarka', + 'Caloundra', + 'Alcalde Diaz', + 'Bridgwater', + 'Leigh', + 'Jayamkondacholapuram', + 'Cherupulassheri', + 'Mikolow', + 'Guacimo', + 'Hatfield', + 'Wijchen', + 'Panchimalco', + 'Mersa', + 'Niquero', + 'Chaves', + 'Fredericia', + 'Rozzano', + 'French Valley', + 'Santa Eulalia del Rio', + 'Schwabach', + 'Schweizer-Reineke', + 'Maayon', + 'Lasam', + 'Mangaratiba', + 'Bacong', + 'Constitucion', + 'Shelton', + 'Tuquerres', + 'Nossa Senhora da Gloria', + 'Trikarpur North', + 'Shutayil', + 'Agar', + 'San Jose de Urquico', + 'Tanxia', + 'Zakynthos', + 'Antequera', + 'Claypole', + 'Pine Bluff', + 'Peddapalli', + 'Igualada', + 'Kearny', + 'Villa Alsina', + 'Anglet', + 'Geel', + 'Bilasipara', + 'Timmins', + 'Halfeti', + 'Guaduas', + 'Toritama', + 'Matiguas', + 'Palia Kalan', + 'Jose Marmol', + 'Halol', + 'Ganta', + 'Kallar', + 'Hallandale Beach', + 'Mambajao', + 'Huizen', + 'Angouleme', + 'Ardesen', + 'Sevilla de Niefang', + 'Rivas', + 'Ambositra', + 'Newbury', + 'Merano', + 'Bujanovac', + 'Komoro', + 'Ishaka', + 'Sumoto', + 'Tagbina', + 'Amami', + 'Pozi', + 'Arraijan', + 'Tampakan', + 'Unzen', + 'Ciudad Dario', + 'Bazar-Korgon', + 'Ciudad Vieja', + 'Upper Hutt', + 'Gatunda', + 'Sarande', + 'Dongyangshi', + 'Shengaocun', + 'Dongluocun', + 'Chambas', + 'Welling', + 'Woburn', + 'Beigang', + 'Hongfengcun', + 'Wujie', + 'Monterotondo', + 'Patti', + 'Esperantina', + 'Marikina Heights', + 'Paranaiba', + 'Drogheda', + 'Bagua Grande', + 'Nanbei', + 'Dowlatabad', + 'Maddela', + 'Lijiaxiang', + 'Reynoldsburg', + 'Yingzhou Linchang', + 'Covington', + 'Salinopolis', + 'Azemmour', + 'Famagusta', + 'Buxtehude', + 'Ciudad Piar', + 'Dhamdaha', + 'Boulogne-sur-Mer', + 'Muana', + 'Velika Plana', + 'Delijan', + 'Jalalpur Bhattian', + 'Friendswood', + 'Talukkara', + 'Meftah', + 'Penn Hills', + 'Betun', + 'Apostoles', + 'Weslaco', + 'Malilipot', + 'Patzicia', + "Land O' Lakes", + 'Essex', + 'Talcher', + 'Soe', + 'Wattrelos', + 'Cuito Cuanavale', + 'Promissao', + 'Anyuan', + 'Qadian', + 'Fourou', + 'Mobo', + 'Pamban', + 'Abadan', + 'Buchholz in der Nordheide', + 'Neumarkt', + 'Ahlat', + 'Saint-Germain-en-Laye', + 'Kitob', + 'Temsia', + 'Vallehermoso', + 'Swords', + 'Vavveru', + 'Elmali', + 'Gonabad', + 'Sidi Moussa', + 'Baichigan', + 'Lobo', + 'Sassuolo', + 'Kingswood', + 'Pie de Pato', + 'Buddh Gaya', + 'Shanhe', + 'Kato', + 'Kirkkonummi', + 'Khowrmuj', + 'Annapolis', + 'Villafranca del Panades', + 'Arys', + 'Ipiau', + 'Dunstable', + 'DeKalb', + 'Vasto', + 'Mambusao', + 'Maragondon', + 'Cedar Falls', + 'Pirmasens', + 'Itabaianinha', + 'Qeshm', + 'Tomar', + 'Sukuta', + 'Kadur', + 'Sint-Truiden', + 'Mundakkal', + 'Sherghati', + 'Nanuque', + 'Veles', + 'Bury Saint Edmunds', + 'Zoumi', + 'Avezzano', + 'Artigas', + 'Ladispoli', + 'Barra de Sao Francisco', + 'Dayr Mawas', + 'Manalapan', + 'Santa Rita do Sapucai', + 'Nabas', + 'Akyurt', + 'Evren', + 'Yangtangxu', + 'Yatangcun', + 'Njombe', + 'Douar Laouamra', + 'Samkir', + 'Porto de Moz', + 'Lemgo', + 'Pilani', + 'Remanso', + 'Siay', + 'Bayindir', + 'Santa Maria da Boa Vista', + 'Metlili Chaamba', + 'Bayburt', + 'Olgiy', + 'Bosconia', + 'Janjgir', + 'Romblon', + 'Andradas', + 'Katsuren-haebaru', + 'Lordegan', + "Villenave-d'Ornon", + 'Gap', + 'Macerata', + 'Cumbal', + 'Guariba', + 'Freiberg', + 'Erramvaripalem', + 'Corigliano Calabro', + 'Minsk Mazowiecki', + 'Crystal Lake', + 'Halberstadt', + 'Lake Oswego', + 'Severna Park', + 'Pilate', + 'Krishnarajasagara', + 'Leinfelden-Echterdingen', + 'Lakeshore', + 'Ramsgate', + 'Findlay', + 'Marakkara', + 'Huaura', + 'Aracataca', + 'Channarayapatna', + 'Montelimar', + 'Leyte', + 'Compiegne', + 'New Berlin', + 'Palampur', + 'Agano', + 'Hofheim', + 'Reguiba', + 'Almenara', + 'Jhabua', + 'Stains', + 'Vellakkovil', + 'Culver City', + 'Bouar', + 'Beyneu', + 'Curuca', + 'Balaoan', + 'La Union', + 'Rubengera', + 'Sabalgarh', + 'Sensuntepeque', + 'Molina', + 'Komono', + 'Kualaserba', + 'Indian Trail', + 'Romny', + 'Magburaka', + 'Hellevoetsluis', + 'Payabon', + 'Colinas', + 'Ampana', + 'Murtajapur', + 'Peringalam', + 'Autazes', + 'Ozu', + 'Duncanville', + 'Valley Stream', + 'Yajalon', + 'Karditsa', + 'Lohne', + 'Pinamar', + 'Tosya', + 'Ahaus', + 'Afogados da Ingazeira', + 'Majibacoa', + 'Hidirbey', + 'Fonds Verrettes', + 'Clinton', + 'Camargo', + 'Merta', + 'Uttarkashi', + 'Boa Esperanca', + 'Swinoujscie', + 'Schorndorf', + 'Kabuga', + 'Leramatang', + 'Itoigawa', + 'Secunda', + 'El Golea', + 'Havza', + 'Volklingen', + 'Maihar', + 'Begamganj', + 'Gagny', + 'Pedra Branca', + 'Jambe', + 'Santa Quiteria', + 'Tiruchendur', + 'Mokolo', + 'Sejenane', + 'La Rinconada', + 'Myrhorod', + 'The Acreage', + 'Colomiers', + 'Malalag', + 'Balud', + 'Podilsk', + 'Torre Annunziata', + 'Dohazari', + 'Taysan', + 'Taicheng', + 'Gourcy', + 'Kilakkarai', + 'Kalimpong', + 'Cihuatlan', + 'Gramado', + 'Romeoville', + 'Oroqen Zizhiqi', + 'Dingras', + 'Heroica Ciudad de Tlaxiaco', + 'Phulwaria', + 'Sisak', + 'Luebo', + 'Jarvenpaa', + 'Chiredzi', + 'Soria', + 'Longtang', + 'Raxruha', + 'Kakrala', + 'Bragadiru', + 'Zagora', + 'Menghan', + 'Hurst', + 'Altagracia de Orituco', + 'Kunigal', + 'Mailapur', + 'Varkkallai', + 'Soavinandriana', + 'Curitibanos', + 'Montana', + 'Mayyanad', + 'Panaji', + 'Poissy', + 'Sieradz', + 'Inverness', + 'Armacao dos Buzios', + 'Oraiokastro', + 'Zacualpa', + 'Post Falls', + 'Ihnasya al Madinah', + 'Jbail', + 'Matsoandakana', + 'Bukit Gambir', + 'Bandhi', + 'Safdarabad', + 'Choa Saidan Shah', + 'Ranipur', + 'Lidkoping', + 'Kambia', + 'Uchqurghon Shahri', + 'Madinat `Isa', + 'Bamessing', + 'Alashankou', + 'Strood', + "L'Asile", + 'Chikodi', + 'Sindgi', + 'Wadegaon', + 'Sardulgarh', + 'Samalkha', + 'Junnar', + 'Salaiya', + 'Tazah Khurmatu', + 'Nicastro', + 'Hutchinson', + 'Kasumigaura', + 'Lishaocun', + 'Herstal', + 'Szigetszentmiklos', + 'Fushe Kosove', + 'Visoko', + 'Kyaukme', + 'Zimapan', + 'Yian', + 'Santa Cruz del Sur', + 'Jayrud', + 'Saraqib', + 'Vyshneve', + 'Xacmaz', + 'Qiryat Bialik', + 'Brcko', + 'Zhongbai', + 'Chelsea', + 'Santiago Nonualco', + 'Barcellona-Pozzo di Gotto', + 'Ngozi', + 'Acevedo', + 'Waipahu', + 'Lynnwood', + 'Yecapixtla', + 'Sagae', + 'Winslow', + 'Kish', + 'Koumra', + 'Zvolen', + 'Ramdurg', + 'Panglao', + "Braine-l'Alleud", + 'Tago', + 'Matias Romero', + 'Baco', + 'Pinhal', + 'Maintal', + 'Kopavogur', + 'Rauma', + 'Rovereto', + 'Lincoln Park', + 'Huamachuco', + 'Ostfildern', + 'Oshnaviyeh', + 'Villamontes', + 'Sebdou', + 'Amudalavalasa', + 'Fort Lee', + "'Ain el Melh", + 'Santo Nino', + 'Cape Girardeau', + 'Atmakur', + 'Yomitan', + 'Kirkagac', + 'Palauig', + 'Montclair', + 'Hobbs', + 'Toukountouna', + 'San Nicolas', + 'Carini', + 'Benenitra', + 'Aizawa', + 'Massawa', + 'Tivaouane', + 'Maarssen', + 'Draguignan', + 'Shirone', + 'Surin', + 'Alimodian', + 'Albano Laziale', + 'Kurobeshin', + 'Cantu', + 'Veruela', + "Pomigliano d'Arco", + 'Caraga', + 'Burjasot', + 'Tianzhong', + 'Ettlingen', + 'Buldon', + 'Masaki', + 'Temascal', + 'Oshakati', + 'Talacogon', + 'Srebrenik', + 'Tabas', + 'Kovvur', + 'Libano', + 'Fonseca', + 'Carol Stream', + 'Plant City', + 'Xisa', + 'Douai', + 'Todos Santos Cuchumatan', + 'Wageningen', + 'Nakama', + 'Ninove', + 'Yomra', + 'Capelinha', + 'Aventura', + 'Despatch', + 'Basudebpur', + 'Charbagh', + 'Parnu', + 'Tafi Viejo', + 'Vendrell', + 'Samaxi', + 'Huanghuajie', + 'La Troncal', + 'Isfisor', + 'Villa del Carbon', + 'Skovde', + 'Manay', + 'Chachoengsao', + 'Villa de San Diego de Ubate', + 'Jordan', + 'Freital', + 'Djidian Kenieba', + 'Salcedo', + 'Ihosy', + 'Streamwood', + 'Jiaozishan', + 'Tucuma', + 'Fondi', + 'Kalingalan Caluang', + 'Duba', + 'Ecija', + 'Mount Juliet', + 'Fariman', + 'Sao Goncalo dos Campos', + 'Nova Vicosa', + 'Virreyes', + 'Media', + 'Ossining', + 'La Tebaida', + 'Itapolis', + 'Lilio', + 'Pachrukha', + 'Brant', + 'Siniloan', + 'Dogansehir', + 'San Jose de Ocoa', + 'San Giuliano Milanese', + 'Marratxi', + 'Asamankese', + 'Kalu Khan', + 'Lalganj', + 'Qiryat Yam', + 'Plasencia', + 'Presidente Venceslau', + 'Whanganui', + 'Xonqa', + 'Issaquah', + 'Sanjiang', + 'Parkland', + 'Guajara-Mirim', + 'Olintepeque', + 'Khachrod', + 'Zyrardow', + 'Badepalli', + 'Sijua', + 'Park Ridge', + 'Bagnolet', + 'Kaffrine', + 'Clarin', + 'Marcq-en-Baroeul', + 'Spruce Grove', + 'Placilla de Penuelas', + 'Seram', + 'Gradacac', + 'Vadasinor', + 'Abrantes', + 'Amambai', + 'Naranjal', + 'Damulog', + 'Jacarezinho', + 'Puerto Berrio', + 'Cocorote', + 'Cesano Maderno', + 'Sadiola', + 'Cacuso', + 'Tangpingcun', + 'Marovoay', + 'Istog', + 'Neu Isenburg', + 'Nueva Santa Rosa', + 'Niederkassel', + 'Jogbani', + 'Galkot', + 'Chojnice', + 'Cottage Grove', + 'Guaira', + 'Takikawa', + 'Bell Gardens', + 'Oliveira', + 'Matinhos', + 'Rio Negrinho', + 'Taraza', + 'Solan', + 'Hailakandi', + 'Al Qa`idah', + 'Magra', + 'Apan', + 'Tamba-Sasayama', + 'Erattukulakkada', + 'Koycegiz', + 'Yuzhnoukrainsk', + 'Langen', + 'Ospino', + 'Ayirapuram', + 'San Gabriel', + 'Playa Vicente', + 'Heemskerk', + 'Kampot', + 'Axochiapan', + 'Androka', + 'Guemar', + 'Baikonur', + 'Visconde do Rio Branco', + 'Cacocum', + 'Masamba', + 'Marcos Paz', + 'Mibu', + 'Bayanan', + 'Security-Widefield', + 'Iesi', + 'Manggar', + 'Mettmann', + 'Grants Pass', + 'Ilmenau', + 'Cakung', + 'Keizer', + 'Idangansalai', + 'Ciftlikkoy', + 'Ait Ourir', + 'Stendal', + 'Agoncillo', + 'Chittaranjan', + 'Sual', + 'Penfield', + 'Moatize', + 'Roy', + 'Nueva Rosita', + 'Susurluk', + 'Pirna', + 'Huanren', + 'Naron', + 'Partapnagar', + 'Sidi Bibi', + 'Weissenfels', + 'Lluchmayor', + 'Revelganj', + 'Torre-Pacheco', + 'Marinha Grande', + 'Sebekoro', + 'Camana', + 'Mitsuke', + 'Kaseda-shirakame', + 'Amla', + 'Toumodi', + 'Ambatomainty', + 'Al Malikiyah', + 'Trofa', + 'Ramallah', + 'Bettendorf', + 'Cleethorpes', + 'Nuevitas', + 'Betamcherla', + 'Ciudad Melchor Muzquiz', + 'Ancud', + 'Sidi Khaled', + 'Gornji Milanovac', + 'Varzea Alegre', + 'Nongzhangjie', + 'Tromso', + 'Pala Oua', + 'San Fernando de Henares', + 'Sciacca', + 'La Chaux-de-Fonds', + 'Gabaldon', + 'Nabaruh', + 'Goes', + 'Mafamude', + 'Sao Fidelis', + 'Sao Raimundo Nonato', + 'Dibaya-Lubwe', + 'Nallur', + 'Galeana', + 'Konigs Wusterhausen', + 'Yangfang', + 'Brumadinho', + 'Staoueli', + 'Penumur', + 'Westerville', + 'Caluya', + 'Walajapet', + 'Huangyoutang', + 'Garalo', + 'Changchunpu', + 'Juan Rodriguez Clara', + 'San Raimundo', + 'Tuvagudi', + 'Empalme', + 'Draa el Mizan', + 'Cabugao', + 'Higashimatsushima', + 'Xiwanzi', + 'Royal Palm Beach', + 'Dwarka', + 'Haverstraw', + 'Birmitrapur', + 'Apache Junction', + 'Pehowa', + 'Inashiki', + 'Taskopru', + 'Saryaghash', + 'Akcakoca', + 'Tshela', + 'Hitachiomiya', + 'Sao Mateus do Maranhao', + 'Navarre', + 'Ngororero', + 'Ain Tedeles', + 'Wheeling', + 'Ohrid', + 'Lake Stevens', + 'Skelmersdale', + 'Santa Helena de Goias', + 'Nurpur', + 'Rexburg', + 'Ermezinde', + 'Omagari', + 'Dubbo', + 'Nykoping', + 'Mehidpur', + 'Tipton', + 'Lambarene', + 'Campina Grande do Sul', + 'Ban Bang Khu Lat', + 'Eccles', + 'Gujo', + 'Fasano', + 'Urbana', + 'Aborlan', + 'Penalva', + 'Los Palacios', + 'Yoshinogawa', + 'Villepinte', + 'Ouro Branco', + 'Rosenberg', + 'Tinnanur', + 'Dzhankoi', + 'Barbacoas', + 'Cajibio', + 'Los Palacios y Villafranca', + 'Pinner', + 'Monreale', + 'Taibao', + 'Great Yarmouth', + 'Paracuru', + 'Yako', + 'Real', + 'Sakuragawa', + 'Kwai Chung', + 'Vetapalem', + 'Jamindan', + 'Kamp-Lintfort', + 'Margosatubig', + 'Tonbridge', + 'Zacatelco', + 'West Fargo', + 'Paravurkambolam', + 'Tuusula', + 'Povazska Bystrica', + 'Ilkeston', + 'Voghera', + 'Armavir', + 'Metlaoui', + 'San Jose de Las Matas', + 'Abrego', + 'La Presa', + 'Dabola', + 'Kampung Baharu Nilai', + 'Menomonee Falls', + 'Vengat', + 'Santa Maria da Vitoria', + 'Arucas', + 'Vestavia Hills', + 'Calexico', + 'Wurselen', + 'Ciampino', + 'Valrico', + 'Aketi', + 'Koge', + 'Schio', + 'Leyland', + 'Ibusuki', + 'Champerico', + 'Leribe', + 'Papenburg', + 'La Vergne', + 'Ban Na Pa', + 'Sungandiancun', + 'Vangaindrano', + 'Strangnas', + 'Achaguas', + 'Khalkhal', + 'Aziylal', + 'Glenrothes', + 'Alingsas', + 'Santa Clara del Cobre', + 'Barda', + 'Kline', + 'Rajula', + 'Atlantic City', + 'Caibarien', + 'Nishiwaki', + 'Sarikishty', + 'Al Ghizlaniyah', + 'San Felipe Orizatlan', + 'Ingeniero Pablo Nogues', + 'Emir Abdelkader', + "Saint-Martin-d'Heres", + 'Coto Brus', + 'Mahadeopur', + 'Chartres', + 'Szczecinek', + 'Minas', + 'Saronno', + 'Olutanga', + 'Lanyi', + 'Genc', + 'Buug', + 'Chorley', + 'Chacabuco', + 'Peachtree City', + 'Phenix City', + 'Sibate', + 'Melmadai', + 'Buchireddipalem', + 'Shijiazhuangnan', + 'Hammam-Lif', + 'Qiaotouyi', + 'Daraw', + 'DeLand', + 'Herne Bay', + 'Vredenburg', + 'Kaka', + 'Fribourg', + 'Miyoshidai', + 'Nindiri', + 'Bougara', + 'Misawa', + 'Atamyrat', + 'Waregem', + 'Ripollet', + 'Xiaguanying', + 'Marcianise', + 'Steyr', + 'Patnongon', + 'Mechanicsville', + 'Itaitinga', + 'Novo Horizonte', + 'Wilrijk', + 'Nigel', + 'Bayan', + 'Sarkisla', + 'Chuangjian', + 'Khairtal', + 'Mmabatho', + 'Iturama', + 'Azzano', + 'Stanton', + 'Maule', + 'Laur', + 'Taki', + 'Am-Timan', + 'Siyang', + 'Maibara', + 'Antsohihy', + 'Xiushui', + 'Ibara', + 'Barrancas', + 'Matale', + 'Brasschaat', + 'Bat Khela', + 'Citta di Castello', + 'Dicle', + 'Menglie', + 'Pitangueiras', + 'Holyoke', + 'Greven', + 'Winter Springs', + 'Americo Brasiliense', + 'Bishops Stortford', + 'Xico', + 'Mechelen-aan-de-Maas', + 'Wesseling', + 'Borbon', + 'Joue-les-Tours', + 'Naushahro Firoz', + 'Porur', + 'Pallipram', + 'Tayasan', + 'Zacualtipan', + 'Kehl', + 'Fereydun Kenar', + 'Karuvambram', + 'Matozinhos', + 'Choybalsan', + 'Bautzen', + 'Owasso', + 'Prattville', + 'Cananea', + 'East Point', + 'Campbell River', + 'Navgilem', + 'Vavuniya', + 'Quba', + 'Entre Rios', + 'Shankarpur Khawas', + 'Shengang', + 'Veghel', + 'Sabang', + 'Clifton Park', + 'Savelugu', + 'Thakraha', + 'Mapandan', + 'Prokuplje', + 'Mantingan', + 'Pacifica', + 'Bangar', + 'Dubrajpur', + 'Hot Springs', + 'Shambhunath', + 'Gudarah', + 'Aristobulo del Valle', + 'Zhongdong Shequ', + 'Rudsar', + 'Abu Qir', + 'Gurais', + 'San Pedro Jocopilas', + 'Bagabag', + 'Dengtangcun', + 'Sidi Yahia El Gharb', + 'Sama', + 'Tlapa de Comonfort', + 'Mucuri', + 'Olot', + 'Yamen', + 'Adelanto', + 'Backnang', + 'Princeton', + 'San Juan Cancuc', + 'Qaratog', + 'Northglenn', + 'Goribidnur', + 'Kenieran', + 'Ali Sabieh', + 'Tupelo', + 'Hajin', + 'Biougra', + 'La Quinta', + 'Urena', + 'Sampues', + 'San Adrian de Besos', + 'Annemasse', + 'Raalte', + 'Rusape', + 'Shakhtinsk', + 'Pedro II', + 'Bitterfeld', + 'Dhanera', + 'Guayacanes', + 'Obala', + 'Andkhoy', + 'Swidnik', + 'Giyon', + 'Luuk', + 'Celje', + 'Gampola', + 'Ameca', + 'Namlea', + 'Elmont', + 'Tlalixcoyan', + 'Cerveteri', + 'Dibulla', + 'Mission Bend', + 'Tumba', + 'Gaspar Hernandez', + 'Pen', + 'Bangkinang', + 'Mateus Leme', + 'Guira de Melena', + 'La Puente', + 'Santaluz', + 'Carpentersville', + 'Koboko', + 'Al Qaryatayn', + 'Emirdag', + 'Santa Pola', + 'Pentecoste', + 'Oleiros', + 'Cheyyar', + 'Pathanamthitta', + 'Mahanoro', + 'Kastel Stari', + 'Teijlingen', + 'Nove Zamky', + 'Tudela', + 'Ohangaron', + 'Patia', + 'Sillanwali', + 'San Antonio de Padua', + 'Charaut', + 'San Sebastian de Mariquita', + 'Kwidzyn', + 'Arnold', + 'Afua', + 'Marantao', + 'Long Eaton', + 'Prince Albert', + 'Guzelbahce', + 'Calpulalpan', + 'Karuhatan', + 'Manali', + 'Sun City', + 'Mixquiahuala de Juarez', + 'Mamun', + 'Haedo', + 'Coondapoor', + 'Hanumannagar', + 'Mombaca', + 'Gomoh', + 'Sao Francisco do Conde', + 'Matina', + 'San Marcelino', + 'Aklera', + 'Umi', + 'Apia', + 'Hilton Head Island', + 'Jacunda', + 'Melchor Ocampo', + 'Yoloten', + 'Mizunami', + 'Falavarjan', + 'Rawatbhata', + 'Satana', + 'Custodia', + 'Basavana Bagevadi', + 'Massape', + 'Galloway', + 'Vasylkiv', + 'Furstenfeldbruck', + 'Villagarcia de Arosa', + 'Basista', + 'Sanchahe', + 'Les Abricots', + 'Riviera Beach', + 'Venlo', + 'Tiete', + 'Coalville', + 'Huzurabad', + 'Yanqi', + 'Kolongo-Bozo', + 'Benjamin Constant', + 'Attingal', + 'Hatta', + 'Malbork', + 'Foothill Farms', + 'Bom Jardim', + 'Jeremoabo', + 'Taounate', + 'Warendorf', + 'Stirling', + "Su'ao", + 'Rio Brilhante', + 'Malavalli', + 'South Valley', + 'Salto del Guaira', + 'Lampa', + 'New Albany', + 'Sirinhaem', + 'Lewiston', + 'Boleslawiec', + 'Rio Branco do Sul', + 'Kranj', + 'Bamendjou', + 'Villaflores', + 'Dubno', + 'Mira', + 'Paraty', + 'Neuilly-sur-Marne', + 'Kahrizak', + 'Gabu', + 'Greenfield', + 'Franconville', + 'Bletchley', + 'Tuxpan', + 'Perote', + 'Atalaia', + 'Phonsavan', + 'El Bordo', + 'Allahabad', + 'Pokrov', + 'Baocheng', + 'Turiacu', + 'Ma`arratmisrin', + 'Itaqui', + 'Teboulba', + 'Don Benito', + 'Tambulig', + 'Bonito', + 'Leighton Buzzard', + 'Paracho de Verduzco', + 'Souma', + 'Tuttlingen', + 'Evans', + 'Pleasant Grove', + 'Oras', + 'Lovech', + 'Donji Kakanj', + 'Amargosa', + 'Cansancao', + 'Porteirinha', + 'Santa Rosa de Osos', + 'Samobor', + 'Sarangpur', + 'Sandur', + 'Kanigiri', + 'Kerou', + 'Oregon City', + 'Magallanes', + 'Gorinchem', + 'Ambatofinandrahana', + 'Trou du Nord', + 'Agudos', + 'Mabuhay', + 'Selcuk', + 'Jaito', + 'Savigny-sur-Orge', + 'Phulbani', + 'Progreso', + 'Bayur', + 'Tozeur', + 'Conchagua', + 'Grimbergen', + 'Becej', + 'Villa Gonzalez', + 'Eboli', + 'Mullaittivu', + 'Blyth', + 'Fengguangcun', + 'Beckum', + 'Besni', + 'Sitangkai', + 'Luna', + 'Ataq', + 'Bartlesville', + 'Al Hashimiyah', + 'Sanankoroba', + 'Lahar', + 'Falun', + 'Dajiecun', + 'Sao Manuel', + 'Pilibangan', + 'Tibu', + 'Mariano Escobedo', + 'Goygol', + 'Port Talbot', + 'Rock Island', + 'Landgraaf', + 'Ceska Lipa', + 'Lydenburg', + 'Gajendragarh', + 'Jale', + 'Yamoussoukro', + 'Paravur Tekkumbhagam', + 'Bouznika', + 'Jelilyuzi', + 'Mankayan', + 'Molndal', + 'Andilamena', + 'Katsuragi', + 'Melgar', + 'Kaman', + 'Hanover Park', + 'Vettur', + 'Comapa', + 'Salvatierra', + 'Rukungiri', + 'Leavenworth', + 'Mangai', + 'Moerdijk', + 'Chunar', + 'Wangsicun', + 'Tunzi', + 'Laindon', + 'Ratia', + 'Kadiyam', + 'Ciudad Manuel Doblado', + 'Minami-Boso', + 'Formia', + 'Silves', + 'Bantay', + 'Bahadurganj', + 'Imbatug', + 'Masyaf', + 'Obburdon', + 'Qulsary', + 'Adjumani', + 'Qo`ng`irot Shahri', + 'Binaqadi', + 'Languyan', + 'Boryslav', + 'Amarante do Maranhao', + 'Sittard', + 'Long Lama', + 'Kalutara', + 'Redcar', + 'Jagdispur', + 'Siribala', + 'Chorkuh', + 'Prijepolje', + 'Porsgrunn', + 'Cloppenburg', + 'Sitalkuchi', + 'Tokar', + 'Kalinkavichy', + 'Llanelli', + 'Pujali', + 'Kalihati', + 'Kampene', + 'Coesfeld', + 'Thonon-les-Bains', + 'Mol', + 'Holstebro', + 'Lagkadas', + 'Greer', + 'Suhl', + 'Bentota', + 'Mandoto', + 'Manazary', + 'Beeston', + 'Dargot', + 'Dachepalle', + 'Granadero Baigorria', + 'Tucker', + 'La Ciotat', + 'Pennsauken', + 'Baishi Airikecun', + 'Santiago Sacatepequez', + 'Dom Pedrito', + 'Stara Gora', + 'Nakodar', + 'Bucha', + 'Richmond West', + 'Nanshuicun', + 'Tabligbo', + 'Shaxi', + 'Oswiecim', + 'Lunavada', + 'Ban Doi Suthep', + 'Aourir', + 'Suhut', + 'Port-Margot', + 'Monatele', + 'Muskogee', + 'Campos Novos', + 'Guilderland', + 'Moalboal', + 'Dalkola', + 'Bindki', + 'Kankuria', + 'Chaiyaphum', + 'Netishyn', + 'Chimboy Shahri', + 'Basilisa', + 'San Enrique', + 'Segrate', + 'Vavur', + 'Pingxiangcheng', + 'Small Heath', + 'Grugliasco', + 'Penticton', + 'Dagua', + 'Claremont', + 'Manucan', + 'Siyabuswa', + 'Musiri', + 'Anosiala', + 'Aguilas', + 'Kearns', + 'East Meadow', + 'Pathri', + 'Faraskur', + 'Echirolles', + 'San Miguel Chicaj', + 'Nowa Sol', + 'Zuojiawu', + 'Pylaia', + 'Sagnay', + 'Kesavapuram', + 'Maddaloni', + 'Mahe', + 'Missao Velha', + 'Wildomar', + 'Caimito', + 'Erding', + 'Richfield', + 'Marijampole', + 'Ipueiras', + 'Agogo', + 'Elixku', + 'Qaladizay', + 'Uster', + 'Salima', + 'Camberley', + 'Kanie', + 'La Macarena', + 'Sayula', + 'Chatillon', + 'Tuensang', + 'Mulavana', + 'Kona', + 'Manoli', + 'Dargaz', + 'Koneurgench', + 'Lakshmeshwar', + 'Taxisco', + 'Vastervik', + 'Houghton le Spring', + 'Zira', + 'Wangtuan', + 'Tsubata', + 'Karamadai', + 'Torres Novas', + 'Mandaguari', + 'Esik', + 'Yasugicho', + 'Or Yehuda', + 'Enrile', + 'Michalovce', + 'Kambove', + 'Yovon', + 'Xinpo', + 'Anserma', + 'Robertsganj', + 'Esquel', + 'Beni Khiar', + 'Estero', + 'Ikongo', + 'Thana Bhawan', + 'Pande', + 'Risalpur Cantonment', + 'Sitakund', + 'Sorel-Tracy', + 'Lierre', + 'Ulan Hua', + 'Beloit', + 'Kulp', + 'Hojai', + 'Jose Bonifacio', + 'Matan', + 'Rosario do Sul', + 'Lajedo', + 'Belalcazar', + 'Esch-sur-Alzette', + 'Whitley Bay', + 'Las Navas', + 'Demirci', + 'Kannan', + 'Makan', + 'Kidangazhi', + 'Sinsheim', + 'Rossano', + "Mek'i", + 'Cantanhede', + 'Natick', + 'Schaffhausen', + 'Jaral del Progreso', + 'Sao Joao da Barra', + 'Ebebiyin', + '`Afrin', + 'Tunduma', + 'Dabutou', + 'Nemmara', + 'Chippenham', + 'Punarakh', + 'Barra do Choca', + 'Oakton', + 'Patamundai', + 'Bulicun', + 'Benapol', + 'Songo', + 'Horasan', + 'Central Islip', + 'Binde', + 'Sile', + 'Haomen', + 'Neiba', + 'Kodaikanal', + 'Dashtobod', + 'Mamfe', + 'Chelora', + 'Upper Arlington', + 'Knurow', + 'Berat', + 'Cambrils', + 'Nueve de Julio', + 'Zhetisay', + 'Ichchapuram', + 'West Bridgford', + 'Kaniama', + 'Bossangoa', + 'Guapiles', + 'Lecherias', + 'Sonson', + 'Arawa', + 'Mazidagi', + 'Zinzana', + 'Tocancipa', + 'Copperas Cove', + 'Rende', + 'Purna', + 'Liwonde', + 'Estahban', + 'Byumba', + "Anse d'Hainault", + 'Holubivske', + 'Simbahan', + 'Porta Westfalica', + 'Banaz', + 'Monaco', + 'Namakgale', + 'Maur', + 'Emsdetten', + 'Cegled', + 'Ratchaburi', + 'Sandanski', + 'Yahyali', + 'Fuchucho', + 'Borehamwood', + 'Barra Bonita', + 'Tomatlan', + 'Bjelovar', + 'Tooele', + 'Danihe', + 'Wolomin', + 'Tomelloso', + 'Jaroslaw', + 'San Juan Cotzal', + 'Mpessoba', + 'Kajaani', + 'Winsen', + 'Dinas', + 'Nargund', + 'Cabanglasan', + 'Oak Creek', + 'Cumberland', + 'Santiago Juxtlahuaca', + 'Kurtalan', + 'Spoleto', + 'Aketao', + 'Parappur', + 'Coatepec Harinas', + 'Yandian', + 'Melito di Napoli', + 'Teruel', + 'Kotma', + 'Prey Veng', + 'Tuntum', + 'San Miguel Acatan', + 'Beiya', + 'Siayan', + 'Muhlhausen', + 'Yorktown', + 'Modugno', + 'Capalonga', + 'Randallstown', + 'Athis-Mons', + 'Isla de Maipo', + 'Yejituo', + 'Merrillville', + 'Palapye', + 'Canaman', + 'Bollate', + 'Six-Fours-les-Plages', + 'Cuyotenango', + 'Goycay', + 'San Bernardo del Viento', + 'Gasan', + 'Voerde', + 'Mieres', + 'Onteniente', + 'Taastrup', + 'Ouled Beni Messous', + 'La Vallee de Jacmel', + 'Aparecida', + 'Madingou', + 'Dagami', + 'Kalaleh', + 'Nyaungdon', + 'Temple City', + 'Zacatepec', + 'Cisterna di Latina', + 'Boende', + 'Ban Mueang Na Tai', + 'Rapu-Rapu', + 'Carrollwood', + 'Nellaya', + 'Barira', + 'Petit-Trou de Nippes', + 'Pingshang', + 'Ewing', + 'Pestel', + 'Sareh Mowndeh', + 'Balarampuram', + 'Amancio', + 'Mingjian', + 'Kishmat Dhanbari', + 'Dinhata', + 'Dighwara', + 'Komatsushimacho', + 'Garhakota', + 'Meppen', + 'Guaimaro', + 'Lunsar', + 'Creil', + 'Hilliard', + 'Girau do Ponciano', + 'Chatelet', + 'Al Jabayish', + 'Frankston', + 'Apodi', + 'Gutalac', + 'Castricum', + 'Kamenice', + 'Berriozabal', + 'Sunbury', + 'El Plan', + 'East Kelowna', + 'Kanada', + 'Moorpark', + 'Maspalomas', + 'Piui', + 'Pioltello', + 'Limburg', + 'Sibuco', + 'Hillerod', + 'Tamamura', + 'Matanog', + 'Masasi', + 'Vempalle', + 'Wai', + 'Viru', + 'Bombardopolis', + 'Malpura', + 'Saparua', + 'Pihani', + 'Guayaramerin', + 'Bel-Air', + 'Zary', + 'Shirdi', + 'Ingelheim', + 'San Carlos Sija', + 'Vohipeno', + 'Ampasina-Maningory', + 'Mugumu', + 'Bugiri', + 'Farafenni', + 'Nim ka Thana', + 'Taloda', + 'Egypt Lake-Leto', + 'Ramsar', + 'Naduvattam', + 'Chekkal', + 'Krong Kep', + 'Farmers Branch', + 'Tlokweng', + 'Arroyomolinos', + 'Pandan', + 'Sarigol', + 'Seika', + 'Saint-Raphael', + 'Uto', + 'Tarikere', + 'Oued Athmenia', + 'Anloga', + 'Hellendoorn', + 'Rumonge', + 'Conflans-Sainte-Honorine', + 'Az Zahiriyah', + 'San Lorenzo de Guayubin', + 'Yangshuwa', + 'Lauderdale Lakes', + 'Villefranche-sur-Saone', + 'Mokokchung', + 'Chillum', + 'Majhaul', + 'Kakhovka', + 'Malmesbury', + 'Daiyue', + 'Hyde', + 'Dinangorou', + 'Partur', + 'Chieri', + 'Gorukle', + 'Meyzieu', + 'Santa Cruz Verapaz', + 'Hendon', + 'Caivano', + 'Dumbea', + 'Jalarpet', + 'Dar Chabanne', + 'Maragogipe', + 'Tirkadavur', + 'Olesnica', + 'Orangevale', + 'Falkirk', + 'Huzurnagar', + 'Sun Prairie', + 'Sainte-Genevieve-des-Bois', + 'Ampelokipoi', + 'Munro', + 'Jagna', + 'Agualva', + 'Pantnagar', + 'Cedar City', + 'Zaio', + 'Igarape-Acu', + 'Kattipparutti', + 'Taozhou', + 'Tambolaka', + 'Fermo', + 'Andujar', + 'Varberg', + 'La Porte', + 'Smarhon', + 'Commack', + 'Caltagirone', + 'Azogues', + 'Crailsheim', + 'Prestea', + 'Riverhead', + 'Bad Vilbel', + 'Kalakkadu', + 'Vavatenina', + 'Burriana', + 'Tam Hiep', + 'Alianca', + 'Nawan Shahr', + 'Pak Chong', + 'Leamington', + 'Guane', + 'Haguenau', + 'Kumo', + 'Camiri', + 'Norristown', + 'Calumet City', + 'South Miami Heights', + 'Vrsac', + 'Zefat', + 'Numancia', + 'Addison', + 'Ipora', + 'Macomia', + 'Collo', + 'Usuki', + 'Shiggaon', + 'Mahna', + 'Sosa', + 'Inver Grove Heights', + 'Graaff-Reinet', + 'Hole Narsipur', + 'Santiago de Tolu', + 'Camara de Lobos', + 'Miyajima', + 'Gurpinar', + 'Guacari', + 'El Mirage', + 'Goiatuba', + 'Chitapur', + 'Miranda de Ebro', + 'Port Shepstone', + 'Awa', + 'Al `Aqiq', + 'Aguelmous', + 'Setouchi', + 'Zhentang', + 'Walkden', + 'Chortoq', + 'Medchal', + 'Midvale', + 'Kendall West', + 'Casiguran', + 'Kenton', + 'Cha-am', + 'San Andres Itzapa', + 'Hoogvliet', + 'Narsampet', + 'Shangzhuangcun', + 'Isumi', + 'Uravakonda', + 'Savanur', + 'Yerkoy', + 'Bariri', + 'Niamina', + 'Freehold', + 'Pishin', + 'Sanok', + 'Sykies', + 'Rafiganj', + 'Aravankara', + 'Mahabo', + 'Pambujan', + 'Vitrolles', + 'Yangambi', + 'Sirohi', + 'Belluno', + 'Gahanna', + 'Lokbatan', + 'Savonlinna', + 'Olney', + 'Rifu', + 'Miahuatlan de Porfirio Diaz', + 'Guama Abajo', + 'Torrington', + 'Sahneh', + 'Udhampur', + 'Gigante', + 'Sungaiselam', + 'Kaneohe', + 'Villeneuve-Saint-Georges', + 'Coevorden', + 'North Ridgeville', + 'Umarga', + 'Ringsaker', + 'Hamirpur', + 'La Concordia', + 'Simiganj', + 'Cartagena del Chaira', + 'Woodley', + 'Cutral-Co', + 'Yayladagi', + 'Midlothian', + 'Tenes', + 'Accrington', + 'Pola', + 'Ofunato', + 'Lugoj', + 'Boca do Acre', + 'Tamuin', + 'Tallkalakh', + 'Sandino', + 'Savalou', + 'Spisska Nova Ves', + 'Ulliyil', + 'Fuquay-Varina', + 'Feijo', + 'Tomobe', + 'Lage', + 'Santuario', + 'Pinerolo', + 'Casalecchio di Reno', + 'Boyarka', + 'Dayr Hafir', + 'Kundian', + 'Zorgo', + 'Bou Noura', + 'Angra do Heroismo', + 'Aine Draham', + 'Pampatar', + 'Buhriz', + 'Bautista', + 'Ratnapur', + 'Baohezhuangcun', + 'Hamidiye', + 'Guskhara', + 'Samokov', + 'Morohongo', + 'Unnan', + 'Yongjing', + 'Rio Real', + 'Akcadag', + 'West Hollywood', + 'Pilao Arcado', + 'Dama', + 'Urgup', + 'La Palma', + 'Westmont', + 'Fruit Cove', + 'Timbuktu', + 'Kilimli', + 'Benton', + 'Saint-Benoit', + 'Conceicao de Jacuipe', + 'Villa Adelina', + 'Barra do Bugres', + 'Tahuna', + 'Yasynuvata', + 'Villa Ballester', + 'Juban', + 'Bedesa', + 'Kerava', + 'Morfelden-Walldorf', + 'Ciudad de Allende', + 'Cieza', + 'El Hajeb', + 'Chakapara', + 'Quimbaya', + 'Wildwood', + 'Surandai', + 'Goch', + 'Aizumi', + 'Diabali', + 'Bridlington', + 'Czechowice-Dziedzice', + 'Tangancicuaro de Arista', + 'Pansol', + 'Douglasville', + 'Chandanais', + 'Voznesensk', + 'Gandara', + 'San Javier', + 'Evergem', + 'Jieshang', + 'Azuqueca de Henares', + 'Allacapan', + 'Yecla', + 'Cento', + 'Zvishavane', + 'Roi Et', + 'Usilampatti', + 'Baturite', + 'Sankt Ingbert', + 'Kamata', + 'Bria', + 'Tilingzhai', + 'Springville', + 'Bou Salem', + 'Datteln', + 'Zaventem', + 'Praya', + 'Watertown Town', + 'Abra de Ilog', + 'Izki', + 'Bom Jesus do Itabapoana', + 'Perunad', + 'Deggendorf', + 'Billingham', + 'Aktuluk', + 'Hammam Bou Hadjar', + 'Barsinghausen', + 'Soteapan', + 'Mahasolo', + 'Sulop', + 'Giddalur', + 'Mananara Avaratra', + 'Lingig', + 'Jaguariaiva', + 'Pappinissheri', + 'Fair Oaks', + 'Tazhakara', + 'Manhattan Beach', + 'Ikalamavony', + 'Pandaul', + 'Adamantina', + 'Bibhutpur', + 'Qazax', + 'Steinfurt', + 'Rawatsar', + 'San Juan Capistrano', + 'Puerto Lopez', + 'Effia-Kuma', + 'Pulppatta', + 'Cassino', + 'Chrzanow', + 'Lebowakgomo', + 'Al Hisn', + 'Kherrata', + 'Confresa', + 'Saint-Chamond', + 'Balasan', + 'Vinces', + 'Umarkot', + 'Casilda', + 'Yellandu', + 'Suong', + "Ouro Preto d'Oeste", + 'Phatthalung', + 'Ieper', + 'Chur', + 'Tebesbest', + 'Guimbal', + 'San Luis de Since', + 'San Pedro de Ycuamandiyu', + 'Union de Reyes', + 'Munai', + 'Charqueadas', + 'Palotina', + 'Marancheri', + 'Kotah-ye `Ashro', + 'Maidan Shahr', + 'Wokha', + 'Prado', + 'Mannar', + 'Awbari', + 'Firavahana', + 'Fotadrevo', + "Ibra'", + 'Chakdarra', + 'Negotin', + 'Dulay` Rashid', + "Shaqra'", + 'Salkhad', + 'Tall Salhab', + 'Bagamoyo', + 'Magu', + 'Caucagua', + 'Guanta', + 'Maojiatang', + 'Cangxi', + 'Dikhil', + 'Winsford', + 'Bapaura', + 'Chiplun', + 'Harra', + 'Mel Nariyappanur', + 'Dulhanganj', + 'Al Hamdaniyah', + 'Shu', + 'Brugherio', + 'Owings Mills', + 'Pimenta Bueno', + 'Talanga', + 'Dimitrovgrad', + 'Oranjestad', + 'Maglaj', + 'Ngaoundal', + 'Mlimba', + 'Francavilla Fontana', + 'Padre Bernardo', + 'Cookeville', + 'Niquelandia', + 'Shenjiabang', + 'Camoapa', + 'Ez Zahra', + 'Kaizu', + 'Chipinge', + 'Payao', + 'Northbrook', + 'Karumattampatti', + 'At Turrah', + 'Fair Lawn', + 'Tenosique', + 'Foca', + 'Balingen', + 'Ypane', + 'Tarkwa', + 'Kahoku', + 'Tambe', + 'Ilhabela', + 'Esme', + 'Jiaoxi', + 'Lingsugur', + 'Dietzenbach', + 'Shiyali', + 'Iyo', + 'Campoalegre', + 'Nyamata', + 'Khodabandeh', + 'Tamura', + 'Slavuta', + 'Ekpe', + 'Posse', + 'Ikot Abasi', + 'Santa Cruz del Norte', + 'Juara', + 'Madukkarai', + 'Piskent', + 'Chatenay-Malabry', + 'Seiyo', + 'Palaiseau', + 'Jagodina', + 'Ouled Fares', + 'Ville Bonheur', + 'Mendez-Nunez', + 'Alandatte', + 'Ewell', + 'Vadigenhalli', + 'Aguai', + 'University City', + 'Cernusco sul Naviglio', + 'Sao Jose do Belmonte', + 'Kempen', + 'Hirakud', + 'Munnarkod', + 'Mannarakkat', + 'Galapagar', + 'Arsin', + 'Villajoyosa', + 'Dragash', + 'Naryn', + 'Allagadda', + 'Oswego', + 'Yarim', + 'Oildale', + 'Santa Fe do Sul', + 'Sansanne-Mango', + 'Limbiate', + 'Hammam Dalaa', + 'Khajamahalpur', + 'Uddevalla', + 'Auxerre', + 'Graham', + 'Vernier', + 'Morecambe', + 'Mason', + 'Roanne', + 'Sao Luis Gonzaga', + 'Montgomery Village', + 'Castelo', + 'Seelze', + 'Wermelskirchen', + 'Yhu', + 'Zhitiqara', + 'Hinesville', + 'Safidon', + 'Shangcaiyuan', + 'Corum', + 'Golden Glades', + 'Del Rio', + 'Kolattupuzha', + 'Saarlouis', + 'Zhujiezhen', + 'Trebic', + 'Bagre', + 'Ayutuxtepeque', + 'Sion', + 'Goshen', + 'Gladstone', + 'Simpang Renggam', + 'University Place', + 'Randolph', + 'Osimo', + 'Azazga', + 'Dhamnod', + 'Farafangana', + 'Bugasong', + 'Tienen', + 'Naranjito', + 'Rio Pardo', + 'Manamadurai', + 'Slagelse', + 'Abashiri', + 'Tortosa', + 'Butte', + 'East Gwillimbury', + 'Sarpol-e Zahab', + 'Marutharod', + 'Andapa', + 'Anse-a-Veau', + 'Medgidia', + 'Misungwi', + 'Sidi Lakhdar', + 'Dabouziya', + 'Mugnano di Napoli', + 'Falls', + 'Phokeng', + 'Duenas', + 'Tynaarlo', + 'Espiye', + 'Grantham', + 'Zhangziying', + 'Huntington Station', + 'Qasr al Qarabulli', + 'Abulug', + 'Inca', + 'Swadlincote', + 'San Juan Despi', + 'Mildura', + 'Banda', + 'Yeonil', + 'Bugojno', + 'Cativa', + 'Bonifacio', + 'Paithan', + 'Kalaa Srira', + 'Dapoli', + 'Wedel', + 'Canete', + 'Zweibrucken', + 'Viernheim', + 'Kulittalai', + 'Gisborne', + 'Pasni', + 'Bayog', + 'Baft', + 'Mogpog', + 'Skhira', + 'Ahrensburg', + 'Pleasant Hill', + 'Cote-Saint-Luc', + 'Ankola', + 'Ain Taya', + 'Lebork', + 'Manitowoc', + 'Barugo', + 'Sadda', + 'Akouda', + 'Fairborn', + 'Brzeg', + 'Ballesteros', + 'Ocuilan de Arteaga', + 'Shangzhen', + 'Bodoco', + 'Curuzu Cuatia', + 'Gerash', + 'Formigine', + 'Aloguinsan', + 'San Dimas', + 'Smolyan', + 'Nishihara', + 'Schoten', + 'Mazarron', + 'Stow', + 'Motosu', + 'Banes', + 'Madakalavaripalli', + 'Canicatti', + 'Hatibanda', + 'Bela Vista de Goias', + 'Sambir', + 'Zaidpur', + 'Sochaczew', + 'Kalasin', + 'Fort Liberte', + 'Exmouth', + 'McMinnville', + 'Ye', + 'Mnasra', + 'Goto', + 'North Shields', + 'Centenario', + 'Kuji', + 'College Park', + 'Merauke', + "Itaporanga d'Ajuda", + 'Paxtaobod', + 'Riccione Marina', + 'Navodari', + 'Meppel', + 'Toretsk', + 'Santa Ana Nextlalpan', + 'Biwong', + 'Corsico', + 'Cherchell', + 'Durazno', + 'Kiryas Joel', + 'Yihezhuang', + 'Houlong', + 'Sao Joaquim de Bicas', + 'Lakewood Ranch', + 'Kita Chauhattar', + 'Pueblo West', + 'Betafo', + 'Garibaldi', + 'Merseburg', + 'Heunghae', + 'Phra Phutthabat', + 'Same', + 'Tandubas', + 'Degana', + 'La Blanca', + 'Trinec', + 'Wavre', + 'Bathurst', + 'Tabor', + 'Swakopmund', + 'Isingiro', + 'Merritt Island', + 'Geldern', + 'Quilevo', + 'Aracuai', + 'Conegliano', + 'Nandaime', + 'Licata', + 'Sao Pedro', + 'Shinjo', + 'Almeirim', + 'Kalaruch', + 'Pinukpuk', + 'Buchanan', + 'Nova Cruz', + 'Lautaro', + 'Fuso', + 'Aiyappan Kovil', + 'Sao Desiderio', + 'Hitchin', + 'Vedaranniyam', + 'Pomerode', + 'Zhangzhengqiao', + 'Esposende', + 'Lixingcun', + 'Timberwood Park', + 'New Panamao', + 'Simunul', + 'La Huacana', + 'Sibutu', + 'Sahuarita', + 'Nazerabad', + 'Baraidih', + 'Dakota Ridge', + 'Colinas do Tocantins', + 'Atami', + 'Mosonmagyarovar', + 'General Nakar', + 'Isfana', + 'Prairieville', + 'Le Perreux-Sur-Marne', + 'Pangururan', + 'Ubeda', + 'Badiadka', + 'Shahin Dezh', + 'Sereflikochisar', + 'Karoi', + 'Toumoukro', + 'Eastchester', + 'Toon', + 'Sid', + 'Korschenbroich', + 'Curaca', + 'Orangeville', + 'Cariari', + 'Abiy Adi', + 'Tiruvur', + 'Agioi Anargyroi', + 'Lufkin', + 'Talayan', + 'Tepeji del Rio de Ocampo', + 'Tobelo', + 'Znojmo', + 'Villena', + 'Kokrajhar', + 'Risod', + 'Dimona', + 'Caldono', + 'Kornwestheim', + 'Schiltigheim', + 'Laoac East', + 'Takhemaret', + 'Almora', + 'Bogazliyan', + 'Brejo', + 'San Agustin', + 'Shiso', + 'Spalding', + 'Balarampur', + 'Uonuma', + 'Cravinhos', + 'Gyapekurom', + 'Guindulman', + 'Fungurume', + 'Pingtang', + 'Pikesville', + 'Diakon', + 'Argyroupoli', + 'Radebeul', + 'Leduc', + 'Rainham', + 'Eastpointe', + 'Beaufort West', + 'Cinarcik', + 'Honaz', + 'Portao', + 'Titlagarh', + 'Cantilan', + 'Waris Aliganj', + 'Gbarnga', + 'Deer Park', + 'Cooper City', + 'Podgorze', + 'Lommel', + 'Pagani', + 'Vac', + 'Sint-Pieters-Leeuw', + 'Palapag', + 'Sao Domingos do Maranhao', + 'Westlake', + 'Woodridge', + 'Zeghanghane', + 'Hemer', + 'Jalajala', + 'Jamkhed', + 'Spanaway', + 'San Juan Nepomuceno', + 'Minamishiro', + 'Majagual', + 'Biberach', + 'Divandarreh', + 'Onesti', + 'Quinchia', + 'Gibraltar', + 'Ankazomiriotra', + 'Maromandia', + 'Mahasoabe', + 'Lushoto', + 'Zhegaozhen', + 'Tamra', + 'Letchworth', + 'American Fork', + 'Kallidaikurichi', + 'Shariff Aguak', + 'Menen', + 'San Quintin', + 'Les Mureaux', + 'Vassouras', + 'Angri', + 'Peyziwat', + 'Milaor', + 'Kignan', + 'Cieszyn', + 'Sibagat', + 'Acatlan de Osorio', + 'Stuhr', + 'Lochem', + 'Almendralejo', + 'Kakata', + 'North Providence', + 'Lanciano', + 'Annigeri', + 'Uelzen', + 'San Jose Poaquil', + 'Uttaradit', + 'San Juan Evangelista', + 'Bassin Bleu', + 'Pulgaon', + 'Sindirgi', + 'City of Orange', + 'Starokostiantyniv', + 'Oued el Alleug', + 'Impfondo', + 'Zhuqi', + 'Curralinho', + 'Initao', + 'Mulavur', + 'Adrano', + 'Lupi Viejo', + 'Reo', + 'Navan', + 'Guying', + 'Timbio', + 'Gadsden', + 'Zhaitangcun', + 'Toda Bhim', + 'Byadgi', + 'Itiuba', + 'Lianga', + 'Tabango', + 'Desamparados', + 'Sneek', + 'Palmeira', + 'Imzouren', + 'Sao Luis de Montes Belos', + 'Selmane', + 'Baclaran', + 'Chaodongcun', + 'Nuoro', + 'Beni Tamou', + 'Oeiras do Para', + 'Bozdogan', + 'Dao', + 'Walla Walla', + 'New City', + 'Bell Ville', + 'Golungo Alto', + 'Jaslo', + 'San Martin Sacatepequez', + 'Strumica', + 'Harima', + 'Waikabubak', + 'IJsselstein', + 'Parras de la Fuente', + 'Tobias Fornier', + 'Buxin', + 'Lichfield', + 'San Antonio de los Banos', + 'Rio Verde Arriba', + 'Kearney', + 'Inhambupe', + 'Kadungapuram', + 'Somoto', + 'Xinzhancun', + 'Crema', + 'Leawood', + 'Beni Slimane', + 'Baldwin', + 'Ghazaouet', + 'Braco do Norte', + 'Vechta', + 'Puerto Rico', + 'Narsipatnam', + 'Zhmerynka', + 'Mount Lebanon', + 'Catmon', + 'Varzea da Palma', + 'Tekes', + 'Mankoeng', + 'Zacatlan', + 'Kadingilan', + 'Crown Point', + 'El Ksar', + 'Ojiya', + 'Jaguaribe', + 'Chilecito', + 'Kovin', + 'Capoocan', + 'Kaippakancheri', + 'Azezo', + 'Karaagac', + 'Leo', + 'Trappes', + 'Midsalip', + 'Fallbrook', + 'Grodzisk Mazowiecki', + 'Vemalwada', + 'Xiaotangzhuang', + 'Antiguo Cuscatlan', + 'Landi Kotal', + 'Roldanillo', + 'Somma Vesuviana', + 'Palmerston', + 'Tlanchinol', + 'Kasba', + 'Datu Paglas', + 'Kohtla-Jarve', + 'Mella', + 'Moose Jaw', + 'Batobato', + 'Upper Merion', + 'Penha', + 'Villa Riva', + 'San Antero', + 'Barhadashi', + 'Oulad Zemam', + 'San Roque', + 'Lianmuqin Kancun', + 'Englewood', + 'East Lake', + 'Aranda de Duero', + 'Macuro', + 'Koryo', + 'Chascomus', + '`Ajab Shir', + 'Binche', + 'Morro do Chapeu', + 'Batouri', + 'Koh Kong', + 'Atiquizaya', + 'Rheinfelden (Baden)', + 'Masiu', + 'Sapa Sapa', + 'Cotes de Fer', + 'Elmina', + 'Sicuani', + 'Daganbhuiya', + 'Iriba', + 'Qadsayya', + 'Maassluis', + 'Pitanga', + 'Goldsboro', + 'Ano Liosia', + 'Aleshtar', + 'Bagh', + 'Chavakkad', + 'Ixtapan de la Sal', + 'Belen', + 'Aweil', + 'Port Moody', + 'Cabarroguis', + 'Acornhoek', + 'Ayorou', + 'Columbio', + 'Manganam', + 'Saint Helier', + 'Chumphon', + 'Arteijo', + 'Sidi Okba', + 'Come', + 'Ribeirao', + 'Gorizia', + 'Ken Caryl', + 'Leticia', + 'Niangoloko', + 'Bacarra', + 'Schwedt (Oder)', + 'Warminster', + 'Manlius', + 'Corinto', + 'Chempalli', + 'Pointe-Claire', + 'Wickford', + 'Batan', + 'Fraiburgo', + 'Hlukhiv', + 'Neuchatel', + 'Cishan', + 'Nogent-sur-Marne', + 'West Little River', + 'Olkusz', + 'Dhekiajuli', + 'Coxim', + 'Badr', + 'Houilles', + 'Chimbarongo', + 'Bad Nauheim', + 'Mangalam', + 'Poco Redondo', + 'Cukurcayir', + 'Sabanagrande', + 'Monteiro', + 'Vettam', + 'Paidha', + 'Angamali', + 'Orodara', + 'Darsi', + 'Siripur', + 'Alabaster', + 'My Hoa', + 'Orillia', + 'Kacanik', + 'Shobara', + 'Ban Pak Phun', + 'Butajira', + 'Geraardsbergen', + 'Paso de Ovejas', + 'Kong', + 'Riachao do Jacuipe', + 'Namhkam', + 'Asakuchi', + 'Madikeri', + 'Bell', + 'Banate', + 'Aldaya', + 'Tulum', + 'Kondapalle', + 'Landskrona', + 'Ipero', + 'Kennesaw', + 'South Riding', + 'Loughton', + 'Bafang', + 'Montlucon', + 'Glossop', + 'Vintar', + 'Dursunbey', + "An'gang", + 'Shirakawa-tsuda', + 'Shiroishi', + 'Ronda', + 'Puyo', + 'Batcha', + 'Menlo Park', + 'Nokia', + 'Taishi', + 'Al Mindak', + 'Amparafaravola', + 'Bamaur', + 'Ziniare', + 'Dupax Del Norte', + 'Estreito', + 'Churi', + 'Kidamangalam', + 'Mohnyin', + 'Joao Camara', + 'Beidou', + 'Kolin', + 'Shanawan', + 'Buenaventura Lakes', + 'Gojo', + 'Bethel Park', + 'Nowy Targ', + 'Hisua', + 'Olawa', + 'Didouche Mourad', + 'Romainville', + 'Muconda', + 'Petersburg', + 'Radnor', + 'Cottonwood Heights', + 'Persembe', + 'Mazeikiai', + 'Zamania', + 'Barguna', + 'Capim Grosso', + 'Kampong Speu', + 'Kavundappadi', + 'Pivijay', + 'Castro-Urdiales', + 'Bragado', + 'Foster City', + "Alamat'a", + 'Ross', + 'Geiro', + 'Guarambare', + 'Kyrenia', + 'Kartarpur', + 'Obukhiv', + 'Borne', + 'Andirin', + 'Huyton', + 'Uniondale', + 'Khvaf', + 'Lower Makefield', + 'Statesboro', + 'Katiena', + 'Pandami', + 'Eirunepe', + 'Puerto Cumarebo', + 'Cranberry', + 'Julich', + 'Gillette', + 'Totana', + 'Chuhuiv', + 'Shamsabad', + 'Baja', + 'Dipaculao', + 'Palmeira das Missoes', + 'Abingdon', + 'Shikarpur', + 'Panuco', + 'Kusapin', + 'Minamikyushu', + 'Umaria', + 'Brooklyn Center', + 'Trowbridge', + 'Ben Ahmed', + 'Mukdahan', + 'Bugembe', + 'Kaarina', + 'Knokke-Heist', + 'Aosta', + 'Los Gatos', + 'Glendale Heights', + 'Tekkebhagam', + 'El Arrouch', + 'Chanderi', + 'Calape', + 'Bungoono', + 'Temascalapa', + 'Mushie', + 'Kamaishi', + 'Victoria Falls', + 'Timimoun', + 'Borba', + 'Kareli', + 'Castelfranco Emilia', + 'Tutin', + 'Ban Ang Sila', + 'Kingman', + 'Taiobeiras', + '`Ain el Hadjel', + 'Didy', + 'Kadinhani', + 'Wakabadai', + 'Harker Heights', + 'Touros', + 'Puebloviejo', + 'Las Mercedes', + 'Dana Point', + 'Lubon', + 'Jishi', + 'Shingu', + 'Hangal', + 'Sarikaya', + 'Marignane', + 'Xinbu', + 'Livingstone', + 'Ambodimanga II', + 'Vohitromby', + 'Zumbo', + 'Forbe Oroya', + 'Lome', + 'Gumdag', + 'Gyzylgaya', + 'Osvaldo Cruz', + 'Luxitun', + 'Villafranca di Verona', + 'Hinda', + 'Turkauliya', + 'Boxtel', + 'Hampden', + 'Forchheim', + 'Porto Uniao', + 'Taguasco', + 'Sao Paulo de Olivenca', + 'Sopot', + 'Shalingzicun', + 'Asse', + 'Elesvaram', + 'Bembe', + 'Dellys', + 'Ornskoldsvik', + 'Ventspils', + 'Itamarandiba', + 'Djenne', + 'Rencun', + 'Dara', + 'Dehloran', + 'Musikot-Khalanga', + 'Carapegua', + 'Biritiba-Mirim', + 'Castelfranco Veneto', + 'Saint-Georges', + 'Dumalinao', + 'Yamanashi', + 'Massango', + 'Aravan', + 'Romans-sur-Isere', + 'Baragua', + 'Saintard', + 'Fatehpur Sikri', + 'Escuque', + 'Fort Erie', + 'Moninnpebougou', + 'Patratu', + 'Sanchor', + 'Pantelimon', + 'Aksay', + 'Lampertheim', + 'Oued Zenati', + 'Kifri', + 'Clarence', + 'Tawsalun', + 'Nijar', + 'Lohagaon', + 'So', + 'Niksic', + 'Araban', + 'Watari', + 'Sanana', + 'Nevers', + 'Kollo', + 'Carache', + 'Kakira', + 'Tunceli', + 'Gostivar', + 'Urbano Santos', + 'Sertania', + 'Arumuganeri', + 'Igrejinha', + 'Tecuci', + 'Baraawe', + 'Teutonia', + 'Ticul', + 'Sighetu Marmatiei', + 'Buco Zau', + 'Parambil', + 'Tit Mellil', + 'Shaliuhe', + 'Bela Cruz', + 'Rubino', + 'Delbruck', + 'Ubajara', + 'Bocas de Satinga', + 'Sayram', + 'Xinyuan', + 'Chand Chaur', + 'Achim', + "Val-d'Or", + 'Mankada', + 'Yuzhne', + 'Puerto Escondido', + 'Balzar', + 'Pribram', + 'Baroueli', + 'Ylojarvi', + 'Kallur', + 'Sayula de Aleman', + 'LaSalle', + 'Ivaipora', + 'Rodas', + 'Geraldton', + 'Sherwood', + 'Kaysville', + 'Ansongo', + 'Vadavalli', + 'Jaguarari', + 'Yufu', + 'Debagram', + 'Falmouth', + 'Silvia', + 'Cota', + 'Arbaoua', + 'Nanjikkottai', + 'Sao Joao Batista', + 'Xiaodian', + 'Vilakkudi', + 'Zhanjia', + 'Ilawa', + 'Oguzeli', + 'Itaiba', + 'Herrenberg', + 'City Bell', + 'Furstenwalde', + 'Jamikunta', + 'Putla Villa de Guerrero', + 'Taranagar', + 'Goleta', + 'Cibolo', + 'El Dificil', + 'Belhi', + 'Frederico Westphalen', + 'Lens', + 'San Lazzaro di Savena', + 'Ain el Bya', + 'Osawa', + 'Mayantoc', + 'Arris', + 'Krasnik', + 'Motherwell', + 'Mashiki', + 'Matalom', + 'Diplahan', + 'Businga', + 'Inza', + 'Erraguntla', + 'Balindong', + 'Payshamba Shahri', + 'Sarkoy', + 'Esplanada', + 'Shimanto', + 'Ain Bessem', + 'Mateur', + 'Saint-Medard-en-Jalles', + 'Chemancheri', + 'Badoc', + 'Helena', + 'Hani', + 'I-n-Salah', + 'Salt', + 'Cacapava do Sul', + 'Lobougoula', + 'Minamisatsuma', + 'Elk Grove Village', + 'Manwat', + 'Agen', + 'Shiyeli', + 'Baiyan', + 'Garfield', + 'Yinchengpu', + 'Rethymno', + 'Nueva Italia de Ruiz', + 'Ourilandia do Norte', + 'Sotouboua', + 'Fucheng', + 'Correntina', + 'Staryy Beyneu', + 'Ferry Pass', + 'Virei', + 'Chemmaruthi', + 'Savage', + 'Turaiyur', + 'Nouna', + 'Abbiategrasso', + 'Omaezaki', + 'Lower Macungie', + 'Dioungani', + 'Vrilissia', + 'Bussum', + 'Beverly Hills', + 'Nedroma', + 'Plottier', + 'Desert Hot Springs', + 'Ketti', + 'Kameda-honcho', + 'Pierrefitte-sur-Seine', + 'Dumfries', + 'Oisterwijk', + 'Pires do Rio', + 'Chamtha', + 'Clearfield', + 'Dartmouth', + 'Brighouse', + 'Massantola', + 'Kiranomena', + 'Ingenio', + 'Yankou', + 'Redcliff', + 'Guararapes', + 'Kavlinge', + 'Pattanapuram', + 'Ire', + 'Geesthacht', + 'Lumbang', + 'La Virginia', + 'Sasthankotta', + 'Narsinghgarh', + 'San Pedro de Uraba', + 'Kalyandrug', + 'Wigston Magna', + 'Bilzen', + 'Oharu', + 'Namerikawa', + 'Chancay', + "Sant'Antimo", + 'Nagarote', + 'El Abiodh Sidi Cheikh', + 'Madinat al Habbaniyah', + 'Tattamangalam', + 'Sibiti', + 'Cachoeira Paulista', + 'Dracut', + 'Naumburg', + 'Curanilahue', + 'Venaria Reale', + 'Komarno', + 'Epinal', + 'Messamena', + 'Concon', + 'Chiche', + 'Penaranda', + 'Niena', + 'Wheat Ridge', + 'Bernburg', + 'Zarqan', + 'Zaojiao', + 'Itzehoe', + 'Jimalalud', + 'Bambadinca', + 'Boro', + 'Guanhaes', + 'North Olmsted', + 'Tafas', + 'Termoli', + 'Kangasala', + 'Jacqueville', + 'Laranjeiras do Sul', + 'Yokaichiba', + 'Sebaco', + 'Paraipaba', + 'Safita', + 'Mallig', + 'Kindi', + 'Casale Monferrato', + 'Buloqboshi', + 'Cochrane', + 'Igbaras', + 'Piombino', + 'Georgsmarienhutte', + 'Kristianstad', + 'Estrela', + 'Didcot', + 'Nagato', + 'Bramsche', + 'Massillon', + 'Gandu', + 'Ibate', + 'Xangda', + 'Catubig', + 'Matoes', + 'Maragogi', + 'Homa Bay', + 'Yorii', + 'Papendrecht', + 'Weatherford', + 'Alubijid', + 'Koungou', + 'Catende', + 'Rokhaty', + 'Sint-Amandsberg', + 'Eramala', + 'Miguel Alves', + 'Buguey', + 'Nacogdoches', + 'Kangayam', + 'Utraula', + 'Salug', + 'Shilou', + 'Douar Oulad Hssine', + 'Pojuca', + 'Pervari', + 'Ptolemaida', + 'Maputsoe', + 'Termas de Rio Hondo', + 'Caramoran', + 'Ribeira Grande', + 'Huixtla', + 'Juneau', + 'Campo Alegre', + 'Odacho-oda', + 'Rumbek', + 'Waiyuanshan', + 'Zapala', + 'Aguilares', + 'Ouro Fino', + 'Kukshi', + 'Mangur', + 'Mutki', + 'Quitilipi', + 'Sami', + 'Kovur', + 'Antsohimbondrona', + 'Radhanpur', + 'Pekin', + 'Tamparan', + 'Dhahran', + 'Ciudad Sabinas Hidalgo', + 'Radolfzell am Bodensee', + 'Sao Miguel Arcanjo', + 'Earley', + 'Canyon Lake', + 'Rahachow', + 'Munnar', + 'Chachapoyas', + 'Brasilia de Minas', + 'Wernigerode', + 'Malangas', + 'Bauko', + 'Akividu', + 'Bizen', + 'Bezons', + 'San Donato Milanese', + 'Aiken', + 'Sakaiminato', + 'Tirebolu', + 'Marrero', + 'Bandarawela', + 'Andriba', + 'Bekoratsaka', + 'Vohilava', + 'Itampolo', + 'Ambano', + 'Ghuenke', + 'Yaguaron', + 'Cabaiguan', + 'Makhdumpur', + 'Milot', + 'Aalsmeer', + 'North Cowichan', + 'Wrzesnia', + 'Youwangjie', + 'Kanzakimachi-kanzaki', + 'Arzano', + 'Levice', + 'Pullman', + 'Franklin Square', + 'Puraini', + 'Mascalucia', + 'Massafra', + 'Tholikuzhi', + 'Needham', + 'Deptford', + 'Cheb', + 'Sitges', + 'La Concepcion', + 'Mangalia', + 'Sergio Osmena Sr', + 'Nisia Floresta', + 'Landecy', + 'Ganderkesee', + 'San Carlos Alzatate', + 'Neropolis', + 'Long Branch', + 'Bexleyheath', + 'South Kingstown', + 'Quintero', + 'Bougaa', + 'Santo Antonio do Taua', + 'Araguatins', + 'Xaxim', + 'Palamel', + 'Purattur', + 'Polillo', + 'Yenice', + 'Nilka', + 'Santa Maria Capua Vetere', + 'Erdek', + 'Canuelas', + 'Cacolo', + 'Avellaneda', + 'Paso del Macho', + 'Bayaguana', + 'Centereach', + 'Turicato', + 'Maryville', + 'Aix-les-Bains', + 'Kampong Thom', + 'Jyvaskylan Maalaiskunta', + 'Alengad', + 'Paipa', + 'Dzierzoniow', + 'Oudenaarde', + 'Buu Long', + 'Bahharet Oulad Ayyad', + 'Palmeiras de Goias', + 'Guachaves', + 'Maur Kalan', + 'Cleburne', + 'El Oro de Hidalgo', + 'Domingos Martins', + 'Willingboro', + 'Exu', + 'Camaiore', + 'Atwater', + 'Sidi Ali', + 'Oer-Erkenschwick', + 'Remchi', + 'Pampanito', + 'Namegata', + 'Jhanjharpur', + 'Sao Gotardo', + 'Ortakoy', + 'Alamnagar', + 'Newburgh', + 'San Lucas Toliman', + 'Plettenberg Bay', + 'Masi-Manimba', + 'Tongxiao', + 'Stadskanaal', + 'Bagasra', + 'Gurupa', + 'San Pedro de Ribas', + 'Hassi Khelifa', + 'Gallipoli', + 'Kottaikuppam', + 'North Huntingdon', + 'Ferrenafe', + 'Montigny-le-Bretonneux', + 'Salamina', + 'Pantabangan', + 'Tubao', + 'Velliyod', + 'Komagane', + 'Bocana de Paiwas', + 'Singia', + 'General Jose de San Martin', + 'Descalvado', + 'Yildizeli', + 'Tekkekara Kizhakku', + "'Ain Abid", + 'La Mana', + 'Tredyffrin', + 'Farrokh Shahr', + 'Sadabad', + 'Amatenango de la Frontera', + 'Al `Aydabi', + 'Laramie', + 'Donggou', + 'La Uruca', + 'Maebara', + 'Kochugaon', + 'Staffanstorp', + 'Bostanici', + 'Tuljapur', + 'Kavar', + 'Santa Catarina Mita', + 'Sitionuevo', + 'El Palmar', + 'Oldenzaal', + 'Jaguaruana', + 'Dania Beach', + 'Lalgola', + 'Rushden', + 'Baraderes', + 'Sigma', + 'Amecameca de Juarez', + 'Zhaoyu', + 'Garner', + 'Jasim', + 'West Bend', + 'Bagrami', + 'Itapicuru', + 'Kumba', + 'Masur', + 'Vught', + 'Jiming', + 'Naugatuck', + 'Shimizucho', + 'Barros Blancos', + 'Nautan Dube', + 'Rumuruti', + 'Calubian', + 'Capela', + 'Siquirres', + 'Nueva Imperial', + 'Balyqshy', + 'Morro Agudo', + 'Zentsujicho', + 'Kiryandongo', + 'Tecozautla', + 'Ecclesfield', + 'Kuroishi', + 'Jalpatagua', + 'Jerez', + 'Chum Phae', + 'Favara', + 'Media Luna', + 'Chorbog', + 'Masatepe', + 'Mundelein', + 'Pruszcz Gdanski', + 'Zepce', + 'Lloydminster', + 'Nanyuki', + 'Manises', + 'Wisbech', + 'Fangyuan', + 'Darwen', + 'Holladay', + 'Lidingo', + 'Shenwan', + 'Cururupu', + 'Katagami', + 'Pehuajo', + 'Lawndale', + 'Cueto', + 'Al Khawr', + 'Thazhamel', + 'Hayama', + 'Lake Magdalene', + 'Rahatgarh', + 'Ayabe', + 'Oak Ridge', + 'I`zaz', + 'Mae Sot', + 'Milford Mill', + 'Ivrindi', + 'Puerto Wilches', + 'Prosper', + 'Kurivikod', + 'Buzovna', + 'Encrucijada', + 'Prestwich', + 'Mechraa Bel Ksiri', + 'Bunyan', + 'Charthawal', + 'Knjazevac', + 'Epsom', + 'Dialoube', + 'Colombia', + 'Qara', + 'Samdhin', + 'Dej', + 'Sejiyon', + 'Kostopil', + 'Mandaguacu', + 'Bangassou', + 'Airmadidi', + 'Parambu', + 'Save', + 'Chambly', + 'Kalisizo', + 'Nagdha Simla', + 'Jam', + 'Trebinje', + 'Forquilhinha', + 'Nauagarhi', + 'Cambrai', + 'Deori Khas', + 'Neuruppin', + 'Renkum', + 'Carballo', + 'Nieuw-Vennep', + 'Pindare-Mirim', + 'Cay', + 'Wevelgem', + 'Areka', + 'Norak', + 'Kunnatnad', + 'Neira', + 'Kolachel', + 'Cornelius', + 'Sanha', + 'Shentang', + "L'Hay-les-Roses", + 'Halden', + 'Yawatahama-shi', + 'Vellanad', + 'Ilhavo', + 'Draa Ben Khedda', + 'Buyan', + 'Navalcarnero', + 'Courcelles', + 'Plaisir', + 'Myoko', + 'New Bern', + 'Colider', + 'Bolobo', + 'Qutur', + 'Sri Madhopur', + 'Bagac', + 'Opelika', + 'Humenne', + 'Ithaca', + 'Hoyerswerda', + 'Villaricca', + 'Dasol', + 'Nicholasville', + 'Point Pedro', + 'Guamo', + 'Maralal', + 'Lumding', + 'Candido Mota', + 'Norwood', + 'Waddinxveen', + 'Dimataling', + 'Mamaroneck', + 'Wenxian Chengguanzhen', + 'Odorheiu Secuiesc', + 'Klela', + 'Diemen', + 'Hitoyoshi', + 'Monjas', + 'Rio das Pedras', + 'Gongguan', + 'Pontoise', + 'Redan', + 'Tanmen', + 'Sherpur Khurd', + 'Aracoiaba da Serra', + 'Ibanda', + 'Altenburg', + 'Netivot', + 'Imisli', + 'Magsingal', + 'Yahsihan', + 'Bel Air North', + 'Rio Bravo', + 'Zaqatala', + 'Eyvan', + 'Mahallat Damanah', + 'Mograne', + 'Shimotoba', + 'Yby Yau', + 'Port Chester', + 'Burgdorf', + 'Ennery', + 'Chatellerault', + 'Aguada de Pasajeros', + 'Ivisan', + 'Bandeirantes', + 'Vadakakarai', + 'Tiquipaya', + 'Boghni', + 'Oiso', + 'Petrovac na Mlavi', + 'Hendrik-Ido-Ambacht', + 'Inkhil', + 'Siliana', + 'Parnarama', + 'Rillieux-la-Pape', + 'Naspur', + 'Carangola', + 'La Verne', + 'Unchagao', + 'Esperanca', + 'Barrinha', + 'Changuinola', + 'Salgotarjan', + 'Valkenswaard', + 'Rosmalen', + 'Kosonsoy', + 'Pocone', + 'Itaperucu', + 'Bittou', + 'Alba', + 'Bramhapuri', + 'Pontypridd', + 'Duanshan', + 'Shepparton', + 'Kreuztal', + 'Lobos', + 'Rutherglen', + 'Sakaraha', + 'LaGrange', + 'Dar Ould Zidouh', + 'Laguna Hills', + 'Varto', + 'Paracelis', + 'Saint Neots', + 'Siraway', + 'Khanah Sur', + 'Rusera', + 'Middle River', + 'Rheinberg', + 'Asilah', + 'Ciudad del Plata', + 'Podili', + 'Yaita', + 'Tongeren', + 'Gata', + 'Ambatomiady', + 'Beidaying', + 'Orcutt', + 'Shrigonda', + 'Los Altos', + 'Fomento', + 'Ngudu', + 'Kalliyassheri', + 'West Falls Church', + 'Rosa Zarate', + 'North Royalton', + 'Tequila', + 'Espinosa', + 'Yingyangcun', + 'Lushnje', + 'Bembereke', + 'Tancitaro', + 'Chitral', + 'Danghara', + 'Khorugh', + 'Sakhnin', + 'Gevelsberg', + 'Thiais', + 'Sabana Grande de Boya', + 'Montebelluna', + 'Centre Wellington', + 'Vibo Valentia', + 'Sasaguri', + 'Bedworth', + 'Tewksbury', + 'Huangxicun', + 'Tangua', + 'San Juan Ixcoy', + 'Nantan', + 'Barreirinha', + 'Sterling', + 'Cambita Garabitos', + 'Manaratsandry', + 'Vienne', + 'Vigneux-sur-Seine', + 'Malaikkal', + 'Pompeu', + 'Werl', + 'Viry-Chatillon', + 'Petrosani', + 'Hopkinsville', + 'Tairan Camp', + 'Tummapala', + 'Mushabani', + 'Chantal', + 'Espinho', + 'Karera', + 'Konseguela', + 'Malakanagiri', + 'Rodolfo Sanchez Taboada', + 'Sao Jose do Egito', + 'Vohitrandriana', + 'Andranovory', + 'Wobulenzi', + 'Dashao', + 'Alamogordo', + 'Burlingame', + 'Iguape', + 'Diffa', + 'Itapemirim', + 'Arraial do Cabo', + 'Santa Vitoria do Palmar', + 'Bethany', + 'Gimbi', + 'Babati', + 'Lucera', + 'Yaese', + 'Lakeside', + 'Dolo Odo', + 'Irituia', + 'Arcos de la Frontera', + 'Mocimboa da Praia', + 'Tawaramoto', + 'Ballwin', + 'Tarakeswar', + 'Minas de Matahambre', + 'Wanghong Yidui', + 'Badami', + 'Husainabad', + 'Saint-Laurent-du-Var', + 'Ridley', + 'Chagne', + 'Dedza', + 'Alcazar de San Juan', + 'SeaTac', + 'Chichester', + 'Sacele', + 'Mlawa', + 'Sabirabad', + 'Deal', + 'Jeremie', + 'West Warwick', + 'Itatiaia', + 'Cicero Dantas', + 'Canavieiras', + 'West Odessa', + 'Pichanal', + 'Flores da Cunha', + 'Okagaki', + 'North Chicago', + 'Coria del Rio', + 'Kaminokawa', + 'Bairi Chak', + 'Champoton', + 'Pontefract', + 'Dreux', + 'Voorhees', + 'Sao Luis do Quitunde', + 'Leh', + 'Pattanakkad', + 'Ozd', + 'Culleredo', + 'San Antonio Ilotenango', + 'Sholinghur', + 'Dharampur', + 'Juanacatlan', + 'Bicester', + 'Manavadar', + 'Puerto de la Cruz', + 'Palaiya Ayakkudi', + 'North Andover', + 'Careiro da Varzea', + 'Lohmar', + 'Vinkovci', + 'Kalgoorlie', + 'Cholargos', + 'Capulhuac', + 'Saraykoy', + 'Zionsville', + 'Beverley', + 'Al Husayniyah', + 'Chinnalapatti', + 'Walsrode', + 'Pattittara', + 'Arlon', + 'Friedberg', + 'Korinthos', + 'Lohagara', + 'Begles', + 'Taunusstein', + 'Vitoria do Mearim', + 'Ungheni', + 'Nalchiti', + 'Ganassi', + 'Lavras da Mangabeira', + 'Qo`rg`ontepa', + 'Jonuta', + 'Careiro', + 'Escuinapa', + 'Nardo', + 'Santa Paula', + 'Rio Blanco', + 'Southlake', + 'Barao de Cocais', + 'Saratoga', + 'Weil am Rhein', + 'Carpentras', + 'Mahemdavad', + 'Alegre', + 'Pascani', + 'Andingcun', + 'Tsuruno', + 'Guaranda', + 'Gadarpur', + 'Ban Sai Ma Tai', + 'Pisek', + 'Ulliyeri', + 'Ferizli', + 'Tekkali', + 'Chak Five Hundred Seventy-five', + 'Udaypur Gadhi', + 'Einbeck', + 'San Sebastian', + 'Novoyavorovskoye', + 'Pedana', + 'Mattathur', + 'Alem Paraiba', + 'Agblangandan', + 'Juatuba', + 'Aglipay', + 'Northport', + 'Riacho de Santana', + 'Sekiyado', + 'Dois Irmaos', + 'Tekeli', + 'Pandua', + 'Nova Russas', + 'Babura', + 'Goussainville', + 'Treviglio', + 'Ciudad Melchor de Mencos', + 'Czeladz', + 'Tepetlaoxtoc', + 'Cruz del Eje', + 'Bannur', + 'Mont-de-Marsan', + 'Partinico', + 'Moche', + 'Campo Alegre de Lourdes', + 'Balatan', + 'Villiers-sur-Marne', + 'Presidente Figueiredo', + 'Gobernador Virasora', + 'Lahij', + 'Catole do Rocha', + 'Chuo', + 'Osterholz-Scharmbeck', + 'Gamu', + 'Toribio', + 'Chengam', + 'Tabuleiro do Norte', + 'Bad Hersfeld', + 'Ennepetal', + 'San Giuliano Terme', + 'Nazare da Mata', + 'Juquitiba', + 'Luis Correia', + 'Yunoshima', + 'Niles', + 'Burgess Hill', + 'Eagle', + 'Calafell', + 'Gurnee', + 'Santana do Acarau', + 'Police', + 'Mataas Na Kahoy', + 'Miami Lakes', + 'Jarinu', + 'Carapo', + 'Kaele', + 'Sao Jose da Tapera', + 'Keles', + 'Capim', + 'Taozhuangcun', + 'Diema', + 'Cachan', + 'Banamba', + 'Uzynaghash', + 'Grottaglie', + 'Talakkad', + 'Devarshola', + 'Birtouta', + 'Ain Kercha', + 'Buey Arriba', + 'Hafnarfjordhur', + 'Sarno', + 'Illescas', + 'Bay Shore', + 'Wallkill', + 'Leusden', + 'Xingang', + 'Zug', + 'Haan', + 'Sokuluk', + 'Osmancik', + 'Olopa', + 'Suzak', + 'Founougo', + 'Liptovsky Mikulas', + 'Hayrabolu', + 'Anilao', + 'Gariadhar', + 'Parkville', + 'Ouatagouna', + 'Aungban', + 'Savigny-le-Temple', + 'Westville', + 'Farsan', + 'Sankaramangalam', + 'Nagawaram', + 'Thung Song', + 'Krabi', + 'Giannitsa', + 'Stratford-upon-Avon', + 'Masho Khel', + 'Hellin', + 'Mainaguri', + "G'ijduvon Shahri", + 'Pamukova', + 'Pittsford', + 'Pau dos Ferros', + 'Gubbio', + 'North Tonawanda', + 'Torrijos', + 'Karuvakulam', + 'Mukumbura', + 'Neuburg', + 'Lawrenceville', + 'Yanai', + 'Afonso Claudio', + 'Motema', + 'Ar Ruhaybah', + 'New Smyrna Beach', + 'Besiri', + 'Tchindjendje', + 'Ash Shinan', + 'Uran', + 'Maguing', + 'Bandar-e Lengeh', + 'Mandera', + 'Tskhinvali', + 'Magdalena de Kino', + 'Camamu', + 'Pontal do Parana', + 'Quillabamba', + 'Bala Koh', + 'Carlos Barbosa', + 'Myszkow', + 'Menton', + 'Kailahun', + 'Valdepenas', + 'Karjan', + 'Okotoks', + 'Motomiya', + 'Banlung', + 'Muvattupula', + 'Austintown', + 'Salyan', + 'Manawar', + 'Avola', + 'Schonebeck', + 'Samrong', + 'Amaga', + 'Oristano', + 'Eldersburg', + 'Kuttanallur', + 'Dhari', + 'Newark upon Trent', + 'Nanyo', + 'Temascaltepec de Gonzalez', + 'Zywiec', + 'Villemomble', + 'Alma', + 'Rehli', + 'Hirakawacho', + 'Huatabampo', + 'Fengrenxu', + 'Graneros', + 'Abu Suwayr', + 'Shahpura', + 'Sallimedu', + 'Seguin', + 'Kessel-Lo', + 'Pothuhera', + 'Kurunegala', + "Al 'Attawia", + 'Telimele', + 'Segala Mba', + 'Northolt', + 'San Salvador El Seco', + 'Chimichagua', + 'To`raqo`rg`on', + 'Koni', + 'Liberty', + 'Cabrobo', + 'Malakoff', + 'Wishaw', + 'Bai Chay', + 'Chimakurti', + 'Andernach', + 'Ometepec', + 'Benguema', + 'San Gregorio de Nigua', + 'Bardejov', + 'Jima Abajo', + 'Majidpur', + 'Drexel Heights', + 'Aspropyrgos', + 'Gaggenau', + 'Jinka', + 'Pantao-Ragat', + 'Zhedao', + 'Las Nieves', + 'Harpenden', + 'Falou', + 'Huanta', + 'Salou', + 'Chabet el Ameur', + 'Taramangalam', + 'Anse-a-Foleur', + 'Best', + "Wik'ro", + 'Highland Park', + 'Lewe', + 'Uithoorn', + 'Anjad', + 'Qaratau', + 'Milford', + 'Berriane', + 'Daheba', + 'Whitstable', + 'Tsuru', + 'Crevillente', + 'Calintaan', + 'Ndora', + 'Djendel', + 'Gorna Oryahovitsa', + 'Kaipram', + 'Kibiti', + 'Bankass', + 'Claudio', + 'Yverdon-les-Bains', + 'Periyanayakkanpalaiyam', + 'Ypacarai', + 'Lievin', + 'Egra', + 'Inami', + 'Joacaba', + 'Anse a Pitre', + 'Floresta', + 'Ostuni', + 'Piagapo', + 'Tasova', + 'Kanniparamba', + 'San Giuseppe Vesuviano', + 'Candijay', + 'Marogong', + 'Mussoorie', + 'Pulupandan', + 'Planadas', + 'Mucari', + 'Gukeng', + 'Sakti', + 'Dumalag', + 'Rury', + 'Elur', + 'Balete', + 'Postmasburg', + 'Rahimpur', + 'Minudasht', + 'Rosignano Marittimo', + 'Oltu', + 'Bretten', + 'Muratli', + 'Kondarangi Kiranur', + 'Iguig', + 'Wuyuan', + 'Szekszard', + 'Monte Patria', + 'Nethirimangalam', + 'Margram', + 'Merzig', + 'Sainte-Julie', + 'Milazzo', + 'Nanchital de Lazaro Cardenas del Rio', + 'Villa Regina', + 'Sakhipur', + 'Zemoura', + 'Degeh Bur', + 'Meschede', + 'Kericho', + 'Granger', + 'Cahul', + 'Dauin', + 'Comiso', + 'Congleton', + 'Kulat', + 'Mahugaon', + 'Monterey', + 'Arda', + 'Balungao', + 'Qahderijan', + 'Chmistar', + 'El Fanar', + 'Bent Jbail', + 'Zgharta', + 'Andranomanelatra', + 'Tsitondroina', + 'Ambinanitelo', + 'Ambalavao', + 'Majuro', + 'Bourem Guindou', + 'Du Yar', + 'Kuah', + 'Dulmial', + 'Malak Abad', + 'Maleme Hodar', + 'Sali', + 'Uar Esgudud', + 'Ikoto', + 'Kafr Nubl', + 'Anew', + 'Mpwapwa', + 'Kayunga', + 'Pop', + 'Kanyobagonga', + 'Gongyefu', + 'Liaojiayuan', + 'Les Palmes', + 'Mundahal Khurd', + 'Hasanparti', + 'Ranpur', + 'Patri', + 'Salaya', + 'Edassheri', + 'Mundi', + 'Padappakara', + 'Sagwara', + 'Tirwa', + 'Kaluvaya', + 'Masabdisa', + 'Magadi', + 'Baghmari', + 'Sarpavaram', + 'Dhandhuka', + '`Aynkawah', + "Jalawla'", + 'Mutsamudu', + 'Saundhonwali', + 'Salay', + 'Parakadavu', + 'Eshtehard', + 'Dala', + 'Soledade', + 'Sombrio', + 'Koratgi', + 'Schwandorf', + 'Askoy', + 'Kamisato', + 'Winter Park', + 'Anchieta', + 'East Niles', + 'Chamblee', + 'Navapur', + 'Kaminoyama', + 'Zgorzelec', + 'Birur', + 'Aarschot', + 'Kotturu', + 'Vero Beach South', + 'San Andres del Rabanedo', + 'Holbaek', + 'Garopaba', + 'Saint-Constant', + 'Radcliffe', + 'Southgate', + 'Agno', + 'Verbania', + 'Gerakas', + 'Dalin', + 'Pind Dadan Khan', + 'Manduria', + 'La Garenne-Colombes', + 'Marhaura', + 'Banning', + 'Ragan Sur', + 'Mohyliv-Podilskyi', + 'Imbituva', + 'Galesburg', + 'Subotica', + 'Rietberg', + 'Carshalton', + 'Vyshhorod', + 'Vestal', + 'Triprangottur', + 'General Alvear', + 'Dandenong', + 'Mahon', + 'Plympton', + 'Panakkudi', + 'Serra Negra', + 'Metamorfosi', + 'Algonquin', + 'Conguaco', + 'Pinhao', + 'Mandali', + 'Mabole', + 'Campo Magro', + 'Padada', + 'Balabagan', + 'Wellesley', + 'Tacuba', + 'El Idrissia', + 'Villa Dolores', + 'Al Madad', + "Be'er Ya`aqov", + 'San Andres Xecul', + 'Xiaba', + 'Quiapo', + 'El Kseur', + 'Waslala', + 'Ozhur', + 'Kabalo', + 'Alacuas', + 'Ris-Orangis', + 'Motala', + 'Nutley', + 'Kodayattur', + 'Petite Riviere de Nippes', + 'Nanga Eboko', + 'Oosterend', + 'Shibancun', + 'Dzyarzhynsk', + 'Shetang', + 'Tiruvegapra', + 'Fleming Island', + 'Thuan Tien', + 'Krishnarajpet', + 'Kinik', + 'Bad Zwischenahn', + 'Hakha', + 'Bontoc', + 'Talwara', + 'Kaita', + 'Hengchun', + 'Antsampandrano', + 'East Windsor', + 'Puente-Genil', + 'Madavur', + 'Hengshuicun', + 'Ranai', + 'Dahana', + 'Ramnicu Sarat', + 'Puthupalli', + 'Raytown', + 'Bulwell', + 'Mount Hagen', + 'Bois-Colombes', + 'Mananasy-Tsitakondaza', + 'Charneca', + 'Ancon', + 'Nattam', + 'Atascadero', + 'Morrisville', + 'Benito Soliven', + 'Bazeh Kalagh', + 'Chahchaheh', + 'Bozmargi', + 'Kalateh-ye Mir Ab', + 'Santiago do Cacem', + 'Perico', + 'Rendsburg', + 'Reghin', + 'Sardrud', + 'Phu My', + 'Clichy-sous-Bois', + 'Atbasar', + 'Mbanga', + "Yong'ancun", + 'Tabio', + 'Decines-Charpieu', + 'Devarkonda', + 'Fridley', + 'Heesch', + 'Igarapava', + 'Saint-Cloud', + 'East Fishkill', + 'Tena', + 'Summerlin South', + 'Karahrud', + 'Makato', + 'Savanette', + 'Bayramic', + 'Kloof', + 'Nu`ayjah', + 'Orchard Park', + 'Kitaakita', + 'Parsuram', + 'Paragould', + 'Sursand', + 'Vinaroz', + 'Buriti', + 'Hosdurga', + 'Uychi', + 'Manjo', + 'Nepanagar', + 'Werve', + 'Pasuquin', + 'Newtownards', + 'Rota', + 'Hazleton', + 'Vlasotince', + 'Alushta', + 'Canguaretama', + 'Stung Treng', + 'Piraju', + 'Yingshouyingzi', + 'Rahway', + 'Pedras de Fogo', + 'Warrnambool', + 'Trutnov', + 'Toksun', + 'Bonou', + 'Synelnykove', + 'West Rembo', + 'Chatou', + 'Waltrop', + 'Oelde', + 'Monfalcone', + 'Lathrop', + 'Petrich', + 'Cruz', + 'Villa Donato Guerra', + 'Bregenz', + 'Jamai', + 'Pati do Alferes', + 'Alquizar', + 'Matthews', + 'Chikuzen', + 'Kalpatta', + 'Agdas', + 'Idar', + 'Veliyangod', + 'Villa Gesell', + 'Kendal', + 'San Agustin Chahal', + 'Dayr Abu Sa`id', + 'Mangdongshan', + 'Kollengode', + 'Gotse Delchev', + 'South Ubian', + 'Rarott', + 'Point Fortin', + 'Mashan', + 'Bourgoin-Jallieu', + 'Hajduboszormeny', + 'Tokmak', + 'Schererville', + 'Xalatlaco', + 'Lakheri', + 'Inagawa', + 'Zamboanguita', + 'Limoeiro do Ajuru', + 'Burton', + 'Pedro Betancourt', + 'Eastern Goleta Valley', + 'Antsahalava', + 'Gustrow', + 'Chiknayakanhalli', + 'Landsberg', + 'Maranga', + 'Johnston', + 'Purificacion', + 'Vandoeuvre-les-Nancy', + 'Cambui', + 'Sumilao', + 'Behror', + 'Olocuilta', + 'Temse', + 'Unterschleissheim', + 'Bra', + 'East Palo Alto', + 'Vallentuna', + 'Central', + 'Perigueux', + "Nan'ao", + 'Sevenoaks', + 'Demnat', + "N'Gaous", + 'Dongyuya', + 'Sint-Michielsgestel', + 'Duanzhuang', + 'Hutto', + 'Fountain', + 'Minad', + 'Garfield Heights', + 'Ja`ar', + 'Augustow', + 'Lalla Mimouna', + 'Kumalarang', + 'Flandes', + 'Escarcega', + 'Melrose', + 'Northfleet', + 'Arari', + 'Manticao', + 'Sankaridrug', + 'Yangshuling', + 'Fritissa', + 'Nejapa', + 'Brecht', + 'Dembi Dolo', + 'Zaltbommel', + 'Charenton-le-Pont', + 'West Windsor', + 'Northeim', + 'Tournefeuille', + 'McCandless', + 'Pirakkad', + 'Juchitepec', + 'Garchitorena', + 'Ibrahimpatnam', + 'Mudbidri', + 'Bujaru', + 'Pueblo Nuevo Vinas', + 'Vadakku Valliyur', + 'Uthal', + 'Krimpen aan den IJssel', + 'Tizi Gheniff', + 'Perafita', + 'Guyancourt', + 'Cramlington', + 'Funchal', + 'Kyegegwa', + 'Golden Gate', + 'Figuil', + "Espigao D'Oeste", + 'Budaors', + 'Pontedera', + 'Lavezares', + 'Bagong Pag-Asa', + 'Lamerd', + 'Brownsburg', + "L'Arbaa Nait Irathen", + 'Bluffton', + 'Marar', + 'Santiago de Baney', + 'Baglung', + 'Crofton', + 'Kavaje', + 'Carney', + 'Suisun City', + 'Didieni', + 'Prainha', + 'Povoa de Santa Iria', + 'Pilachikare', + "Ra's al `Ayn", + 'Gloria do Goita', + 'Casma', + 'Pattikonda', + 'Nalakadoddi', + 'Castelvetrano', + 'Madang', + 'Asipovichy', + 'Aralam', + 'Pignon', + 'Glenville', + 'Tonisvorst', + 'Shikharpur', + 'Mioveni', + 'Catarroja', + 'Guotang', + 'Pitou', + 'Kirkwood', + 'Ski', + 'Vaihingen an der Enz', + 'Swarzedz', + 'Benhao', + 'Sun City Center', + 'Arfoud', + 'Shuangtian', + 'Magna', + 'Namaacha', + 'Chalatenango', + 'Khunti', + 'Licab', + 'Riihimaki', + 'Shibushi', + 'Oakleaf Plantation', + 'Oslob', + 'Rasra', + 'Gates', + 'Garaimari', + 'Perry Hall', + 'Quivican', + 'Paratinga', + 'Cachoeira', + 'Winnenden', + 'East Lake-Orient Park', + 'Bromsgrove', + 'Koshu', + 'Fandriana', + 'Drexel Hill', + 'Le Plessis-Robinson', + 'Saalfeld', + 'Capitan Bermudez', + 'Maddagiri', + 'Orchards', + 'Fundao', + 'Tomi', + 'Cottica', + 'Dougabougou', + 'Canada de Gomez', + 'Beldanga', + 'Esmeralda', + "Bulung'ur Shahri", + 'Poas', + 'Redondela', + 'Zapotiltic', + 'Santa Cruz Cabralia', + 'Poona-Piagapo', + 'La Source', + 'Arniquet', + 'Kamphaeng Phet', + 'Aipe', + 'Irara', + 'Draveil', + "Oktyabr'sk", + 'Ath', + 'Blankenfelde', + 'Shaker Heights', + 'Horki', + 'Nieuwkoop', + 'Anadia', + 'Hinunangan', + 'Raghopur', + 'Yehud', + 'Queensbury', + 'Yomou', + 'McDonough', + 'Buhl', + 'Ulundi', + 'Pallijkarani', + 'Mahendragarh', + 'Nakrekal', + 'Takanezawa', + 'Sao Miguel do Iguacu', + 'Megara', + 'Culemborg', + 'Sopo', + 'Monitos', + 'Primero de Enero', + 'Ozumba', + 'Sankrail', + 'Springe', + 'Kelkheim (Taunus)', + 'Viacha', + 'Xiaobazi', + 'Desenzano del Garda', + 'Colgong', + 'Agde', + 'Rapallo', + 'Chili', + 'Suran', + 'Hisor', + 'Budaka', + 'Sherobod', + 'Cambuslang', + 'La Oliva', + 'Palpa', + 'Madinat Zayid', + 'Casselberry', + 'Mehlville', + 'Sonamukhi', + 'Kalappatti', + 'Baixo Guandu', + 'Zhongwangzhuang', + 'Sexmoan', + 'Riesa', + 'Teapa', + 'Marigliano', + 'Maubeuge', + 'Whitehall', + 'Boxmeer', + 'Pont-y-pwl', + 'Kitui', + 'Paripiranga', + 'Vattalkundu', + 'Chortkiv', + 'Catandica', + 'Stoughton', + 'Shiqiao', + 'Uttamapalaiyam', + 'Lugus', + 'Mirandopolis', + 'Sendjas', + 'Deodrug', + 'Johi', + 'Somotillo', + 'Tocache Nuevo', + 'Vallikunnam', + 'Kudat', + 'Togitsu', + 'Winterswijk', + 'Matouying', + 'Benavente', + 'Reforma', + 'Hendijan', + 'Ouled Haddaj', + 'Carmo do Paranaiba', + 'Meissen', + 'Pirri', + 'Ipubi', + 'Vandiyur', + 'Ponmana', + 'Dapa', + 'Ursulo Galvan', + 'Abasolo', + 'Senhora da Hora', + "Ahmer el 'Ain", + 'Ofaqim', + 'Sortobe', + 'Timizart', + 'Campina', + 'Humansdorp', + 'Ermont', + 'Pervomaiskyi', + 'Ystad', + 'Cervia', + 'Tameslouht', + 'Cruces', + 'Placheri', + 'Germi', + 'Sotteville-les-Rouen', + 'Langley', + 'Ammi Moussa', + 'Lake in the Hills', + 'Laplace', + 'Kailaras', + 'Hawtat Sudayr', + 'Hajira', + 'Limoeiro de Anadia', + 'Bochnia', + 'Tondela', + 'Russellville', + 'Hakmana', + 'Ampatuan', + 'Humberto de Campos', + 'Sibanicu', + 'Siroki Brijeg', + 'Hanawa', + 'Pucon', + 'Haines City', + 'Fabriano', + 'Siquijor', + 'Ban Phai', + 'Tabuelan', + 'Kuttuparamba', + 'Ariyalur', + 'Dalfsen', + 'Nahan', + 'Bielawa', + 'Tres Marias', + 'Coromandel', + 'Tazmalt', + 'Rosrath', + 'Karippira', + 'Ladwa', + 'Arrentela', + 'Gidri', + 'Easton', + 'Ponot', + 'Munsan', + 'Ruskin', + 'Mount Olive', + 'Mondlo', + 'Carinhanha', + 'Balakliia', + "Welk'it'e", + 'Santa Cruz das Palmeiras', + 'Pokhram', + 'Stockbridge', + 'Emmendingen', + 'Baleno', + 'Mathba', + 'Thabazimbi', + 'Bou Arfa', + 'Izegem', + 'Rehoboth', + 'Kudligi', + 'Virapandi', + 'Villiers-le-Bel', + 'Srem', + 'Duzhuang', + 'Ibaiti', + 'Las Rosas', + 'Caetes', + 'Caicedonia', + 'Takahashi', + 'Babatngon', + 'Hirado', + 'Tiruvambadi', + 'San Lucas Sacatepequez', + 'Narsimlapet', + 'Curridabat', + 'Kamalapuram', + 'Saikaicho-kobago', + 'Garupa', + 'Lepe', + 'Roseaux', + 'Yoshida', + 'Bugarama', + 'Kiskunfelegyhaza', + 'Asago', + 'Tarawa', + 'Pingdeng', + 'Bom Jesus', + 'Jeffersontown', + 'Ponmala', + 'Papa', + 'Landhaura', + 'Metu', + 'Fresnes', + 'Acatenango', + 'Manati', + 'Hanwell', + 'Premia de Mar', + 'Stanford le Hope', + 'Zighout Youcef', + 'Umrat', + 'Martorell', + 'Misilmeri', + 'West Springfield', + 'Pilon', + 'Kozhinjampara', + 'Novyi Rozdil', + 'Zhonghechang', + 'Kikinda', + 'Carauari', + 'Nongstoin', + 'Raikot', + "Sidi Smai'il", + 'Bixby', + 'Schwelm', + 'Harrison', + 'Tanglou', + 'Tantoucun', + 'Maki', + 'Chahe', + 'Hoxter', + 'Andoharanomaitso', + 'Muritiba', + 'Soissons', + 'Krotoszyn', + 'Ballymena', + 'Tibiao', + 'Karakocan', + 'Paraparaumu', + 'Pakwach', + 'Katima Mulilo', + 'Yerres', + 'Leonding', + 'Ferdows', + 'Bang Phongphang', + 'Murliganj', + 'Nauhata', + 'Souk et Tnine Jorf el Mellah', + 'Benicarlo', + 'Esztergom', + 'Jamestown', + 'Navolato', + 'Old Harbour', + 'Dona Remedios Trinidad', + 'Geislingen an der Steige', + 'Taungup', + 'Nowy Dwor Mazowiecki', + 'Esparza', + 'Mehdya', + 'Pitoa', + 'Oyabe', + 'Pattambi', + 'Sarny', + 'Mondragone', + 'Gevas', + 'Saito', + 'Kombissiri', + 'Fenoarivobe', + 'Pawayan', + 'Manga', + 'Ciudad Sahagun', + 'Neduvannur', + 'Edayikunnam', + 'Agawam', + 'Ihsaniye', + 'Jujutla', + 'Xizhou', + 'Tracuateua', + 'Laoaoba', + 'Mampikony', + 'Yangiyer', + 'Akkattettar', + 'Iuna', + 'Rancharia', + 'Simri Bakhriarpur', + 'Sottaiyampalaiyam', + 'Shangluhu', + 'Koprivnica', + 'Zhongtai', + 'Statesville', + 'Moribabougou', + 'Manampizha', + 'Munnalam', + 'Jaciara', + 'Mechernich', + 'Saugus', + 'Frome', + 'Blackrock', + 'Sabra', + 'Mouzaia', + 'El Copey', + 'Plaine du Nord', + 'Baradero', + 'Brodnica', + 'Reinbek', + 'Rudehen', + 'Basay', + 'Isnos', + 'Hattersheim', + 'Azangaro', + 'Verden', + 'Bamba', + 'Nivelles', + 'Madison Heights', + 'Amaliada', + 'Harir', + 'Monroeville', + 'Saint-Etienne-du-Rouvray', + 'Bagha Purana', + 'Losal', + 'Dubasari', + 'Ambatolampy', + 'Bin-Houye', + 'Longavi', + 'Rajpur', + 'Heerenveen', + 'Pardi', + 'Cajati', + 'Szentendre', + 'Matsubushi', + 'Samut Songkhram', + 'Izu', + 'Mendefera', + 'Frattamaggiore', + 'San Lorenzo de Esmeraldas', + 'Sue', + 'Pavugada', + 'Ilave', + 'Condega', + 'Nenmem', + 'Elanjivaliseri', + 'Venezuela', + 'Puerto Leguizamo', + 'Zhailuo', + 'Frankfort', + 'Piracuruca', + 'Wood Green', + 'Oulad Hammou', + 'Conceicao da Barra', + 'Selargius', + 'Mpika', + 'Coyaima', + 'Siraha', + 'Douar Oulad Aj-jabri', + 'Tha Yang', + 'Goio-Ere', + 'Kumru', + 'Castel Volturno', + 'Ouled Ben Abd el Kader', + 'Bonito Oriental', + 'South Laurel', + 'Forest Hills', + 'Ludwigsfelde', + 'Baishaling', + 'Bushey', + 'Saint Bernard', + 'Almus', + 'Cartama', + 'Harur', + 'Raseborg', + 'Ar Rutbah', + 'Short Pump', + 'Byaroza', + 'Jaramijo', + 'Allen Park', + 'Ogawa', + 'Yalda', + 'Banswada', + 'Mitu', + 'Conceicao das Alagoas', + 'Datu Piang', + 'Qianxucun', + 'Toli', + 'Ciro Redondo', + 'Ramanayyapeta', + 'Maharajpur', + 'Voula', + 'New Iberia', + 'Kamatero', + 'Dieppe', + 'Pongoz', + 'Nkhotakota', + 'Aioi', + 'Ban Bang Khu Wat', + 'Guararema', + 'Prata', + 'Passira', + 'General San Martin', + 'Baunatal', + 'Mannanchori', + 'Clarksburg', + 'Princes Town', + 'Toucheng', + 'Kpandu', + 'Kocani', + 'Arivonimamo', + 'Brahmana Periya Agraharam', + 'Henstedt-Ulzburg', + 'Puvali', + 'Tarana', + 'Kizhakkott', + 'Puttankulam', + 'Magog', + 'Boisbriand', + 'Taiwa', + 'Saho', + 'Mollendo', + 'Higashikagawa', + 'Srungavarapukota', + 'Glen Ellyn', + 'Karanjia', + 'Oltinko`l', + 'Ain Taoujdat', + 'Temerin', + 'Truskavets', + 'Monsey', + 'Supe', + 'Bermejo', + 'Saint-Sebastien-sur-Loire', + 'Ruy Barbosa', + 'Huanghuajing', + 'Guamal', + 'Bakhor', + 'Tablat', + 'Libacao', + 'Herentals', + 'Rio Pardo de Minas', + 'Kolambugan', + 'Adrogue', + 'Safaja', + 'Shakiso', + 'Juangriego', + 'Geilenkirchen', + 'Maravilha', + 'Qiman al `Arus', + 'Vicar', + 'Lagdo', + 'Aneho', + 'Ans', + 'Kosk', + 'Gizycko', + 'Bardaskan', + 'Altinova', + 'Kevelaer', + 'Konigsbrunn', + 'Cuitzeo del Porvenir', + 'Temescal Valley', + 'Edappalli', + 'Bergenfield', + 'Caucete', + 'Antur', + 'Eonyang', + 'Diangoute Kamara', + 'Cocal', + 'Sirsaganj', + 'Walnut', + 'Santo Antonio do Ica', + 'Vakfikebir', + 'Poggibonsi', + 'Kotagiri', + 'Zacoalco de Torres', + 'Metepec', + 'Bejucal', + 'Grimma', + 'Heywood', + 'Amircan', + 'Whitehorse', + 'Wappinger', + 'Heshancun', + 'Reda', + 'Kromeriz', + 'Ljubuski', + 'Ayun', + 'Babar', + 'Carmagnola', + 'Ouesso', + 'Agui', + 'Dobropillia', + 'Arqalyq', + 'Ciftlik', + 'Lier', + 'Chatan', + 'Eagle Pass', + 'Itabela', + 'Guma', + 'Camas', + 'Dar Bel Hamri', + 'Warin Chamrap', + 'Nalayh', + 'Villaviciosa de Odon', + 'Nirasaki', + 'Khrestivka', + 'Gaotan', + 'Saldanha', + 'Obama', + 'Carrickfergus', + 'Tetela de Ocampo', + 'Sonderborg', + 'Chennamangalam', + 'Glen Cove', + 'Pinyahan', + 'Alotenango', + 'Arnstadt', + 'Cabrican', + 'Capljina', + 'Bearsden', + 'Bhambia Bhai', + 'La Paz Centro', + 'Cabangan', + 'Ridgecrest', + 'Sangola', + 'Sheohar', + 'San Vicente dels Horts', + 'Neptune', + 'Massama', + 'Tsinjoarivo', + 'Conchal', + 'Golo-Djigbe', + 'Sesena', + 'Kakiri', + 'Maryland Heights', + 'Hazar', + 'Kuli', + 'Nallihan', + 'Gyula', + 'Xochistlahuaca', + 'Nakhal', + 'Mima', + 'Qujingpu', + 'Sueca', + 'San Vicente de Chucuri', + 'Casa Branca', + 'Po', + 'Khulm', + 'Guaimaca', + 'Wegberg', + 'Dajabon', + 'Djugu', + 'Kalwakurti', + 'East Hampton', + 'Reddish', + 'Converse', + 'Rhennouch', + 'Devanhalli', + 'Gingee', + 'Leichlingen', + 'Villazon', + 'Khust', + 'Akersberga', + 'Oakdale', + 'Vallauris', + 'Kefar Yona', + 'Bayang', + 'Nunspeet', + 'Navahrudak', + 'Mainit', + 'Vanves', + 'Mchinji', + 'Anajas', + 'Lomme', + 'Twentynine Palms', + 'Douentza', + 'Tainai', + 'Dubendorf', + 'Geldrop', + 'Qornet Chahouane', + 'Sahavato', + 'Imito', + 'Sandrandahy', + 'Ambohijanahary', + 'Masanwa', + 'Bo`ka', + 'Qianshanhong Nongchang', + 'Jiaoxiling', + 'Saila', + 'Limeil-Brevannes', + 'Karakurisshi', + 'Billericay', + 'Cuartero', + 'Langedijk', + 'Isser', + 'Almazora', + 'Lubok Antu', + 'Montfermeil', + 'San Felipe Jalapa de Diaz', + 'Pacho', + 'Belpasso', + 'Zeitz', + 'Yangyuhe', + 'Orlova', + 'Shaler', + 'San Andres Sajcabaja', + 'Kasangulu', + 'Kushtagi', + 'Gragnano', + 'Shalqar', + 'San Martin de los Andes', + 'Kanavaikuli', + 'Punceres', + 'Aron', + 'Lake Jackson', + 'Dhabauli', + 'Labasa', + 'Goriar', + 'Hamar', + 'Canosa di Puglia', + 'Vilangudi', + 'Noe', + 'Douglas', + 'Aloran', + 'Garden City', + 'Nochistlan de Mejia', + 'Bitam', + 'Ennis', + 'Malmal', + 'Iguaba Grande', + 'Sfizef', + 'Newry', + 'Danvers', + 'Mocimboa', + 'Dahmani', + 'Lukow', + 'Bouka', + 'Ash Shajarah', + 'El Sauce', + 'Reina Mercedes Viejo', + 'Reina Mercedes', + 'Bordj el Bahri', + 'Ambohitompoina', + 'Larreynaga', + 'Majayjay', + 'Caridad', + 'Gulnar', + 'Maple Valley', + 'Gyongyos', + 'Hiji', + 'Harelbeke', + 'Cecina', + 'Dingalan', + 'Melgaco', + 'Talusan', + 'Orvault', + 'Mytilini', + 'Chichaoua', + 'Zanandore', + 'Ampasimanolotra', + 'Mahaplag', + 'Quiroga', + 'Daphne', + 'Villa Luvianos', + 'Sirakorola', + 'Chalhuanca', + 'Umargam', + 'Guacui', + 'Kakuda', + 'Zolotonosha', + 'Hamtramck', + 'Barughutu', + 'Griesheim', + 'Uchturpan', + 'Muchun', + 'Sestao', + 'Sachse', + 'Traipu', + 'Wasi', + 'Mizumaki', + 'Darlaston', + 'Belmont', + 'Nibria', + 'Magdalena', + 'Motozintla', + 'Vleuten', + 'Rockledge', + 'Mattul', + 'Tualatin', + 'Wilmette', + 'Vadnagar', + 'Aci Catena', + 'Tlalpujahua de Rayon', + 'Williston', + 'Chato', + 'Ramsey', + 'Vinales', + 'Soledad de Doblado', + 'Bongor', + 'Bernards', + 'Ivanjica', + 'Tenares', + 'Ashington', + 'Chaska', + 'Mongo', + 'Fuman', + 'Ramotswa', + 'Charkhari', + 'Paivalike', + 'Williamsport', + 'Pirapozinho', + 'Immokalee', + 'Moncao', + 'Qibray', + 'Itapissuma', + 'Ouda-yamaguchi', + 'Khategaon', + 'As Sarw', + 'Gabasumdo', + 'Havran', + 'Hidrolandia', + 'Sundern', + 'Lapuyan', + 'Ocean', + 'Batken', + 'Tahla', + 'Palmar de Varela', + 'Lebrija', + 'Joao Alfredo', + 'Itacare', + 'Tudiyalur', + 'Parabiago', + 'Mogliano Veneto', + 'Dodge City', + 'San Giovanni in Persiceto', + 'Axim', + 'North Kingstown', + 'Koewarasan', + 'Borsa', + 'San Miniato', + 'Shuiding', + 'Bellaa', + 'Wajimazakimachi', + 'Teltow', + 'Spinea', + 'Santa Rosa de Lima', + 'Alatri', + 'San Pedro del Pinatar', + 'Poruvakara', + 'Porto Belo', + 'Troyan', + 'Le Chesnay', + 'Tabira', + 'Aparecida do Taboado', + 'Amarpur', + 'Brunssum', + 'Argelia', + 'Ban Chang', + 'Kitsuki', + 'New Windsor', + 'Atlautla', + 'Tuku', + 'Malargue', + 'Lagoa Vermelha', + 'Phuntsholing', + 'Tanguturu', + 'Huntley', + 'Niuchangqiao', + 'Zongdi', + 'Mukher', + 'San Juan Guichicovi', + 'Di Linh', + 'Parsa', + 'Hikawa', + 'Leon Postigo', + 'Longtan', + 'Pachor', + 'Padiyanallur', + 'Yahaba', + 'Bhimbar', + 'Theniet el Had', + 'Quijingue', + 'Shatiancun', + 'Shilan', + 'Sucy-en-Brie', + 'Mont-Dore', + 'Maracas', + 'Baesweiler', + 'Lagoa Seca', + 'Tysons', + 'Veendam', + 'Reisterstown', + 'Pilar do Sul', + 'Contla', + 'Prior Lake', + 'Assisi', + 'Soignies', + 'Ambodibonara', + 'New London', + 'Cabrero', + 'Svendborg', + 'Ouled Fayet', + 'Waddan', + 'Swatara', + 'Laojiezi', + 'Hulst', + 'Campulung', + 'Taougrite', + 'Andenne', + 'Ouled Slama Tahta', + 'Narat', + 'Wengtiancun', + 'Wangtang', + 'Karlskoga', + 'Atharan Hazari', + 'Jauja', + 'Mulchen', + 'Homewood', + 'Mazenod', + 'Conner', + 'Pombos', + 'Fortuna Foothills', + 'Wetter (Ruhr)', + 'Kantai', + 'Kobuleti', + 'Heemstede', + 'Novo Oriente', + 'Rardhu', + 'Citong', + 'Rayamangalam', + 'Haciqabul', + 'Ninomiya', + 'Patjirwa', + 'Teno', + 'Jarrow', + 'Niimi', + 'Abarkuh', + 'Millville', + 'Witney', + 'Takahagi', + 'Apaxco de Ocampo', + 'Pitogo', + 'Daulatkhan', + 'Marshalltown', + 'Marolambo', + 'Suluru', + 'Sitakili', + 'Timaru', + 'Nuwara Eliya', + 'Ipsala', + 'Triunfo', + 'Sint-Joost-ten-Node', + 'Tazoult-Lambese', + 'Fiche', + 'McHenry', + 'Nasriganj', + 'Supia', + 'Bourem', + 'Oiapoque', + 'Bandipura', + 'Lemon Grove', + 'Tongyangdao', + 'Duayaw-Nkwanta', + 'Pirai', + 'Konnur', + 'Ukiha', + 'Aguas Santas', + 'Schloss Holte-Stukenbrock', + 'Fetesti', + 'Purral', + 'Los Reyes de Juarez', + 'Toqsu', + 'Villa El Carmen', + 'Arar', + 'Vandikarai', + 'Algemesi', + 'Mandirituba', + 'Malekan', + 'Surmene', + 'Crestview', + "Mu'tah", + 'Mililani Town', + 'Cyangugu', + 'Jardim', + 'Wangen im Allgau', + 'Heilbron', + 'Ruzomberok', + 'Guastatoya', + 'Overath', + 'Caracal', + 'Sebikhotane', + 'Butzbach', + 'Oppegard', + 'Shotley Bridge', + 'Sadri', + 'Ayyagarpet', + 'Ibipetuba', + 'Nalbari', + 'Itai', + 'Penukonda', + 'Leiderdorp', + 'Itako', + 'Chicago Heights', + 'Ciudad Tecun Uman', + 'Kedu', + 'Balussheri', + 'Chillan Viejo', + "K'olito", + 'Panauti', + 'Paouignan', + 'Korgan', + 'Strausberg', + 'Jalpan', + 'Varandarapilli', + 'Green', + 'King', + 'Blerick', + 'Ikaruga', + 'Parksville', + 'Aytos', + 'Drimmelen', + 'Alvin', + 'Shtime', + 'Palanas', + 'Bihpur', + 'Balch Springs', + 'Castanos', + 'Macalelon', + 'Neenah', + 'Cueramaro', + 'Pallippurattuseri', + 'Chiavari', + 'Navrongo', + 'Zarraga', + 'Almunecar', + 'Savur', + "Piest'any", + 'Gurlan', + 'Xovos', + 'Ilchester', + 'Santo Antonio do Monte', + 'Porto Calvo', + 'Bhander', + 'Behara', + 'Corrente', + 'Ramon Magsaysay', + 'Ehingen an der Donau', + 'Santo Amaro da Imperatriz', + 'Mason City', + 'Sipacapa', + 'Haliyal', + 'Bady Bassitt', + 'Citrus Park', + 'Zalingei', + 'Grigny', + 'Pearl', + 'Choba', + 'Novi Ligure', + 'Akitakata', + 'Hamminkeln', + 'Alvares Machado', + 'New Lenox', + 'Tepehuacan de Guerrero', + 'Debiapur', + 'Hayang', + 'Kahului', + 'Moron de la Frontera', + 'Holbrook', + 'Longton', + 'Bourzanga', + 'Calimete', + 'Ezhipram', + 'Castelli', + 'Oak Forest', + 'Mocajuba', + 'Ewa Gentry', + 'West Islip', + 'Kimbe', + 'Sihecun', + 'Boralday', + 'Merrimack', + 'Kobylka', + 'El Abadia', + 'Taraka', + 'Paiporta', + 'Les Anglais', + 'Tauramena', + 'Kernersville', + 'Kupiansk', + 'Conception Bay South', + 'West Linn', + 'Melton Mowbray', + "Bo'ao", + 'Nguti', + 'Buri Ram', + 'San Juan de Uraba', + 'Dargecit', + 'Keswick', + 'Leimen', + 'Hohen Neuendorf', + 'Lindenhurst', + 'Jonava', + 'Pijnacker', + 'Thomasville', + 'Digboi', + 'Picarras', + 'Dame-Marie', + 'Cakovec', + 'Parimpudi', + 'Lambersart', + 'Aalten', + 'San Agustin Tlaxiaca', + 'Illkirch-Graffenstaden', + 'Asheboro', + 'Rappang', + 'Novi Grad', + 'Sikonge', + 'Nemuro', + "Jeffrey's Bay", + 'Awara', + 'Bretigny-sur-Orge', + 'Haiyang', + 'Rheinbach', + 'Lishanpu', + 'Pershotravensk', + 'Mirano', + 'Ambohijanaka', + "Pereyaslav-Khmel'nyts'kyy", + 'Afzalpur', + 'Fort Saskatchewan', + 'Tall Rif`at', + 'Long Thanh', + 'Liugoucun', + 'Batgram', + 'Quakers Hill', + 'Ichikikushikino', + 'Villagran', + 'Muchamiel', + 'Vittorio Veneto', + 'Lochearn', + 'Zomin Shaharchasi', + 'El Alia', + 'Minacu', + 'Irimbiliyam', + 'Agios Nikolaos', + 'Pedernales', + 'Kuzhittura', + 'Nova Olinda do Norte', + 'Nayoro', + 'Ksebia', + 'Klosterneuburg', + 'Toguere-Koumbe', + 'Harbiye', + 'Badiangan', + 'Pasinler', + 'Libenge', + 'Guanxi', + 'Nazare', + 'Wiesloch', + 'Benicia', + 'Raver', + 'Loutete', + 'Imamoglu', + 'Springettsbury', + 'Marsta', + 'Sens', + 'Leisure City', + 'Plum', + 'Santa Eugenia', + 'Nizao', + 'Thetford', + 'Amatepec', + 'Catamayo', + 'Granite City', + 'Taverny', + 'Malebennur', + 'Madhura', + 'Wooster', + 'Amangal', + 'Bagepalli', + 'Ticuantepe', + 'Alexania', + 'Pueblo Bello', + 'Chiriguana', + 'Marcos Juarez', + 'Payakaraopeta', + 'Vohipaho', + 'Tsaravary', + 'Miandrarivo', + 'Mandabe', + 'Andranomavo', + 'Antsiatsiaka', + 'Alakamisy Itenina', + 'Arandu', + 'Jaglot', + 'Haqqulobod', + 'Aragua de Barcelona', + 'Arrecifes', + 'Barbacha', + 'Paracuellos de Jarama', + 'Catio', + 'Estarreja', + 'Kriens', + 'Rapperswil-Jona', + 'Oullins', + 'Ourika Wawrmas', + 'Ambinanisakana', + 'Soanierana Ivongo', + 'Anajatuba', + 'Aldridge', + 'Basi', + 'Aripuana', + 'Kapellen', + 'Kadappuram', + 'San Sebastian de Yali', + 'Ar Rudayyif', + 'Novo Cruzeiro', + 'Nava', + 'Ternivka', + 'Uyuni', + 'Seaford', + 'Lemoore', + 'Bouguirat', + 'Potrerillos', + 'Wassenaar', + 'Zuitou', + 'Heppenheim', + 'Fidenza', + 'Sao Bernardo', + 'Pfaffenhofen', + 'Werkendam', + 'Tupanatinga', + 'Albania', + 'Farnworth', + 'Moon', + 'Ureshinomachi-shimojuku', + 'Dietikon', + 'Safashahr', + 'Nainijor', + 'Tambo', + 'Lowicz', + 'Pemberton', + 'Celendin', + 'Nelliyalam', + "Qa'emiyeh", + 'Khmilnyk', + 'Margherita', + 'Maner', + 'Pinarbasi', + 'San Andres de la Barca', + 'Kulasekharapuram', + 'Atitalaquia', + 'Kaluderica', + 'San Antonio del Monte', + 'Wahga', + 'Lobatse', + 'Acapetahua', + 'Bridgeton', + 'Barauna', + 'Al Qitena', + 'Albignasego', + 'Pappakurichchi', + 'Pamidi', + 'Idigny', + 'Miracema', + 'Kadambanad', + 'Alhaurin el Grande', + 'Lukula', + 'Kararan', + 'Sarayonu', + 'Bakhchysarai', + 'San Luis Jilotepeque', + 'Kizilcahamam', + 'Areraj', + 'Paducah', + 'Madattukkulam', + 'Kalikavu', + 'Feidh el Botma', + 'Gursarai', + 'Punch', + 'Scicli', + 'Chios', + 'Shoreview', + 'Nsanje', + 'Xima', + 'Bozyazi', + 'Clayton', + 'Caninde de Sao Francisco', + 'Majagua', + 'Vadippatti', + 'Bankapur', + 'Shencottah', + 'Villeparisis', + 'Alitagtag', + 'Temple Terrace', + 'Santa Margarita', + 'Rambouillet', + 'Ives Estates', + 'Labrador', + 'Vilyeyka', + 'Wesselsbron', + 'Cangas', + 'Ban Phonla Krang', + 'Khanabad', + 'Bamessi', + 'Magilampupuram', + 'Fortul', + 'Tuvur', + 'Srinivaspur', + 'Garbagnate Milanese', + 'Trikkunnapuzha', + 'Paracuaro', + "Mirassol d'Oeste", + 'Jumilla', + 'Lisen', + 'Cenon', + 'Solanea', + 'Tamayo', + 'Santa Maria de Jesus', + 'Sannois', + '`Abasan al Kabirah', + "Qarah Zia' od Din", + 'Thatha', + 'West Melbourne', + 'Betera', + 'Tlaxcoapan', + 'Mahina', + 'Gadhada', + 'Bidur', + 'Vernon Hills', + 'Tamorot', + 'Meppayyur', + 'Magarao', + 'Malitbog', + 'Goianinha', + 'Cormeilles-en-Parisis', + 'Upper Dublin', + 'Hennigsdorf', + 'Hukumati Baghran', + 'Soron', + 'Santa Maria Ixhuatan', + 'Megrine', + 'Alattur', + 'Miacatlan', + 'Saguiaran', + 'Bhuban', + 'Los Cordobas', + 'Circasia', + 'Kiruna', + 'Ronse', + 'Wanlaweyn', + 'Sapian', + 'Qaha', + 'Mamidalapadu', + 'Lamego', + 'Pirenopolis', + 'Miyanaga', + 'Piracaia', + 'Shelek', + 'Shangxiao', + 'Pitangui', + 'Quarrata', + 'Heiligenhaus', + 'Turrialba', + 'Nediyanad', + 'Ipu', + 'Ambodiangezoka', + 'Itamaraca', + 'Al Qutayfah', + 'Birine', + 'Bad Neuenahr-Ahrweiler', + 'Nannamukku', + 'Paiania', + 'Talaja', + 'Bien Unido', + 'Samayac', + 'Highbury', + 'Kuppadi', + 'Mizque', + 'Bugho', + 'Dalsingh Sarai', + 'South Portland', + 'Kirovsk', + 'Horn Lake', + 'Las Flores', + 'Frias', + 'Ajka', + 'Chettipalaiyam', + 'Manjacaze', + 'Betong', + 'Sun City West', + 'Sibi', + 'Buldan', + 'Manihari', + 'Cuajinicuilapa', + 'Macka', + 'Edwardsville', + 'Lauri', + 'Plainview', + 'Propria', + 'Moulay Bousselham', + 'Dar Chioukh', + 'Baytunya', + 'Aschersleben', + 'Jaguarao', + 'Chuanliaocun', + 'Newton Mearns', + 'Pantar', + 'Wieliczka', + 'Ibimirim', + 'San Benito Abad', + 'Sidi Akkacha', + 'Voinjama', + 'Ghataro Chaturbhuj', + 'Okuta', + 'South Pasadena', + 'Ratau', + 'Iheddadene', + 'Paramus', + 'Susquehanna', + 'Macrohon', + 'Lauaan', + 'Miguel Pereira', + 'Porto da Folha', + "Sofiyivs'ka Borshchahivka", + 'Bussy-Saint-Georges', + 'Jarocin', + 'Gioia del Colle', + 'Superior', + 'Iesolo', + 'Tarui', + 'La Teste-de-Buch', + 'Shahganj', + 'Molins de Rey', + 'Sanger', + 'San Alberto', + 'Lanquin', + 'Manasa', + 'Agia Varvara', + 'Dasuya', + 'Perumbalam', + 'Nyamti', + 'Cabot', + 'Zeboudja', + 'Mint Hill', + 'Mantena', + 'Sainte-Therese', + 'Etampes', + 'Deogarh', + 'Ituporanga', + 'Kantabanji', + 'Nacimiento', + 'Aleksandrovac', + 'Eureka', + 'Dois Corregos', + 'Hennaya', + 'Bubong', + 'Ahmadabad', + 'Giarre', + 'Qingshan', + 'Brawley', + 'Clarence-Rockland', + 'Uchinada', + 'Shirley', + 'Charata', + 'Neckarsulm', + 'Karumandi Chellipalaiyam', + 'Elmira', + 'Sebes', + 'Al Karnak', + 'Capao do Leao', + 'Xincun', + 'Timbiras', + 'Upper Macungie', + 'Cheadle Hulme', + 'Madalum', + 'Marapanim', + 'Achern', + 'Kayapa', + 'Langdu', + 'Blagnac', + 'Apam', + 'Quilali', + 'Agua Preta', + 'Gordes', + 'Kaisariani', + 'Wete', + 'Wall', + 'Perez', + 'Lido di Iesolo', + 'Makubetsu', + 'Apollo Beach', + 'Maski', + 'Tamarakulam', + 'Nakhon Phanom', + 'Caboolture', + 'Santa Josefa', + 'Panchla', + 'Tortona', + 'Tecolutla', + 'Peniche', + 'Mandi', + 'Mavelikara', + 'Selibaby', + 'Lauf', + 'Mauganj', + 'Gross-Gerau', + 'Newton Aycliffe', + 'Beohari', + 'Madruga', + 'Nadbai', + 'Dinokana', + 'Zemmouri', + 'La Prairie', + 'Gorlice', + 'Miramas', + 'Del Gallego', + 'Blenheim', + 'Owatonna', + 'Estoril', + 'Bina', + 'Muhlacker', + 'Dinanagar', + 'Cajuru', + 'Jinju', + 'Virakeralam', + 'Ouled Mimoun', + 'Rangia', + 'Balboa', + 'East Grinstead', + 'Elakadu', + 'Ashton in Makerfield', + 'Rezekne', + 'Zottegem', + 'Bombo', + 'Dongen', + 'Gundlupet', + 'Lagindingan', + 'East Chicago', + 'Jaltenco', + 'Vicencia', + 'Reoti', + 'Panchanandapur', + 'Pandag', + 'Batavia', + 'Incesu', + 'Yuanyangzhen', + 'Poldokhtar', + 'Wyszkow', + 'Tougan', + 'Sapouy', + 'Ilha Solteira', + 'Vogosca', + 'Bagh-e Malek', + 'Pensilvania', + 'Lichtenburg', + 'Ondokuzmayis', + 'Duptiair', + 'Eloi Mendes', + 'Cheranallur', + 'Parit Buntar', + 'Bergerac', + 'Tehuipango', + 'Weiterstadt', + 'Navabad', + 'Caririacu', + 'Clydebank', + 'Ulaangom', + 'Ubaidullahganj', + 'Werota', + 'Siquinala', + 'Wasco', + 'Walpole', + 'South Salt Lake', + 'Ibotirama', + 'Bingen am Rhein', + 'Nordenham', + 'Cotoca', + 'Koelwar', + 'Khadbari', + 'Batalha', + 'Nuevo Arraijan', + 'Aru', + 'Bozkir', + 'East Hempfield', + 'Baden', + 'Az Zabadani', + 'Fagaras', + 'Narasannapeta', + 'Rasiari', + 'Sabaa Aiyoun', + 'Beramanja', + 'Saint-Bruno-de-Montarville', + 'Kaboila', + 'Wright', + 'Yapacani', + 'As Sanamayn', + 'Ora', + 'Teustepe', + 'Pooler', + 'Laranjal Paulista', + 'Semirom', + 'Zhaicun', + 'Bayanhongor', + 'Carbonia', + 'Mirganj', + 'Mel Bhuvanagiri', + 'Paz de Ariporo', + 'Bourdoud', + 'Lamut', + 'Kudlu', + 'San Giovanni Rotondo', + 'Zirndorf', + 'Poro', + 'Colonia del Sacramento', + 'Buesaco', + 'Lainate', + 'Ganjing', + 'Tekkalakote', + 'Chivasso', + 'Rancho Grande', + 'Willebroek', + 'Kalfou', + 'Woodburn', + 'Muniz', + 'Ksour Essaf', + 'Gedera', + 'Talikota', + 'Saumur', + 'Kiskunhalas', + 'Wilmslow', + 'Ait Faska', + 'Sograha', + 'Canas', + 'Et Tira', + 'Iradan', + 'Vadakkanandal', + 'Buddayyakota', + 'Kottakota', + 'Guruzala', + 'Lunel', + 'Marimba', + 'Liushuquan', + 'Ketrzyn', + 'Rosario de la Frontera', + 'Flemalle-Haute', + 'Puerto Varas', + 'Budhlada', + 'Montemor-o-Velho', + "Sant'Anastasia", + 'Tavira', + 'Sanchez-Mira', + 'Suphan Buri', + 'Lice', + 'Selm', + 'Manito', + 'Jirwa', + 'Mankachar', + 'Iskandar', + 'Baykan', + 'Forest Grove', + 'Beuningen', + 'Mortsel', + 'Imperial Beach', + 'Mesagne', + 'Dum Duma', + 'Suar', + 'Guduru', + 'Ringas', + 'Kaous', + 'Oum Hadjer', + 'Cifuentes', + 'Perevalsk', + 'Ouled Rahmoun', + 'Dongfeng', + 'Bijbiara', + 'Pacasmayo', + 'Cankiri', + 'Wum', + 'Santiago Papasquiaro', + 'Lockport', + 'Baruni', + 'Vadakku Viravanallur', + 'Montichiari', + 'Gourma Rharous', + 'Huaquechula', + 'Itapuranga', + 'Terlizzi', + 'Kuyucak', + 'Tono', + 'Anosipatrana', + 'Campos Gerais', + 'Terrytown', + 'Misserghin', + 'Camanducaia', + 'Mzimba', + 'Sierra Bullones', + 'Tianyingcun', + 'Elangunnapuzha', + 'Phulera', + 'Requinoa', + 'Erice', + 'Terdal', + 'Tholen', + 'Konobougou', + 'Winona', + 'Elancourt', + 'Dengjiazhuang', + 'Halemba', + 'Tralee', + 'Northdale', + 'Kathu', + 'Key West', + 'Chellalat el Adhaouara', + 'Dancagan', + 'Mahates', + 'Thetford Mines', + 'Odemira', + 'Tianwei', + 'Alagoa Grande', + 'La Maquina', + 'Bad Honnef am Rhein', + 'El Hadjar', + 'Casillas', + 'Keystone', + 'Jaszbereny', + 'Mahitsy', + 'Emmeloord', + 'Dardoq', + 'Gamboma', + 'Burntwood', + 'Chuimatan', + 'Ridgewood', + 'Hercules', + 'Henin-Beaumont', + 'San Juan Atitan', + 'Renigunta', + 'Bangzha', + 'Lubbecke', + 'Barra da Estiva', + 'Hovd', + 'Skardu', + 'Bajina Basta', + 'Fort Mill', + 'Cave Spring', + 'Idhna', + 'Sandi', + 'Vertou', + 'Bresso', + 'Ambatomborona', + 'Malaimbandy', + 'Mahambo', + 'Ambatofotsy', + 'Tsarazaza', + 'Poytug`', + 'Brasileia', + 'Majiadiancun', + 'Harsewinkel', + 'Sinait', + 'Lakshmicharipara', + 'Gahmar', + 'Gaoya', + 'De Witt', + 'Rosemount', + 'Rich', + 'Dehgolan', + 'Wilsonville', + 'Upper Moreland', + 'Mangaldai', + 'Gonglang', + 'Fairland', + 'Londonderry', + 'Bom Jesus dos Perdoes', + 'Montreux', + 'Dharmapuram', + 'Puerto Piritu', + 'Istmina', + 'Queimadas', + 'Curtea de Arges', + 'Le Grand-Quevilly', + 'Tekman', + 'Binidayan', + 'Bobon', + 'Gonesse', + 'Golkoy', + 'Palm City', + 'Giussano', + 'Otake', + 'Giyani', + 'Chintalapudi', + 'Pando', + 'Big Spring', + 'Gressier', + 'Mathibestad', + 'Columbine', + 'Sao Joaquim', + 'Fleetwood', + 'Boscoreale', + 'Bournville', + 'Masrakh', + 'Elk River', + 'San Sebastian Coatan', + 'Putignano', + 'Gembloux', + 'Mannachchanellur', + 'Maevatanana', + 'Santa Perpetua de Moguda', + 'Krishnapuram', + 'Dano', + 'Jaynagar-Majilpur', + 'Cesenatico', + 'Grandview', + 'Azacualpa', + 'Hjorring', + 'Tubize', + 'La Garde', + 'Grevena', + 'Haoping', + 'Lucenec', + 'Mimoso do Sul', + 'El Jicaro', + 'Formosa do Rio Preto', + 'Gilarchat', + 'Demre', + 'Teniente Primero Manuel Irala Fernandez', + 'Chevella', + 'Bessemer', + 'El Quetzal', + 'Kibeho', + 'Noicattaro', + 'Galatina', + 'Dhrol', + 'Omachi', + 'Vimercate', + 'Colleyville', + 'Vesala', + 'Jharka', + 'Marmara Ereglisi', + 'Unterhaching', + 'Boureit', + 'Jenks', + 'Fonte Boa', + 'Chanhassen', + 'Ciempozuelos', + 'Santa Isabel do Rio Negro', + 'Perunkalattu', + 'Ban Pa Sak', + 'Kotal', + 'Port Alfred', + 'Amnat Charoen', + 'Alacam', + 'Calpe', + 'Gokarn', + 'Ciudad Altamirano', + 'Triggiano', + 'Calilabad', + 'Lindau', + 'Dondon', + 'Canarana I', + 'Artvin', + 'Yuanchang', + 'Suitland', + 'Inkster', + 'Vitez', + 'Nagai', + 'Gradignan', + 'Assemini', + 'Schleswig', + 'Andasibe', + 'San Vicente de Canete', + 'Polasara', + 'Shenley Brook End', + 'Fort Washington', + 'Karkala', + 'Lanaken', + 'Kulmbach', + 'Korkut', + 'Aurillac', + 'Vignola', + 'Vayakkalattu', + 'Maracana', + 'Consett', + 'Raman', + 'Marco', + 'Kadamalaikkundu', + 'Koko', + 'Alboraya', + 'Ladkhed', + 'Nechi', + 'Kunisakimachi-tsurugawa', + 'Le Ray', + 'Vichy', + 'Maintirano', + 'Mungaoli', + 'Chhota Udepur', + 'Tubay', + 'Rockville Centre', + 'Santo Cristo', + 'Marshfield', + 'Pura', + 'Helmstedt', + 'Karavaram', + 'Conversano', + 'Koba', + 'Arapoti', + 'Wagrowiec', + 'Bishunpur Sundar', + 'Seondha', + 'Natividad', + 'Novelda', + 'Paveh', + 'Zakopane', + 'Cherukolattur', + 'Biarritz', + 'Talisayan', + 'Chinna Salem', + 'Firmat', + 'Brevnov', + 'Vorkadi', + 'Halfmoon', + 'Koper', + 'Coffs Harbour', + 'San Antonio del Sur', + 'Horb am Neckar', + 'Ginan', + 'Tecax', + 'Villanueva de la Serena', + 'Bema', + 'Haskoy', + 'Yinajia', + 'Felipe Carrillo Puerto', + 'Lapao', + 'Arida', + 'Lourinha', + 'Tabina', + 'Nea Filadelfeia', + 'Mpophomeni', + 'Bandar-e Deylam', + 'Palm River-Clair Mel', + 'Ban Piang Luang', + 'Rinteln', + 'Klodzko', + 'New Milton', + 'Tarangnan', + 'Santeramo in Colle', + 'Lower Providence', + 'Nanpingcun', + 'Jardin America', + 'Zhutailing', + 'Mogtedo', + 'Haisyn', + 'Carahue', + 'Champs-Sur-Marne', + 'Coulsdon', + 'Nova Prata', + 'Diebougou', + 'Safipur', + 'Nagod', + 'Scandiano', + 'Huejotzingo', + 'Ellwangen', + 'Netapur Tanda', + 'Pereira Barreto', + 'Fenoarivo', + 'Malanguan', + 'Lamzoudia', + 'Fort Beaufort', + 'Santa Lucia La Reforma', + 'Tosa', + 'Batabano', + 'Friedrichsdorf', + 'Ligang', + 'Toin', + 'Pace', + 'Sagara', + 'Imatra', + 'Siqba', + 'Kanchanaburi', + 'Oulad Said', + 'Voorschoten', + 'Doba', + 'Haql', + 'Yolombo', + 'Foughala', + 'Sao Sebastiao da Boa Vista', + 'Altavas', + 'West Chicago', + 'Phulpur', + 'Nanminda', + 'Kesla', + 'Geretsried', + 'Francavilla al Mare', + 'Trussville', + 'Alegria', + 'Busuanga', + 'Tumwater', + 'Igaci', + 'Utena', + 'Kako', + 'Farnham', + 'Valdagno', + 'Migdal Ha`Emeq', + "Porto Sant'Elpidio", + 'Inaja', + 'Sliedrecht', + 'Velenje', + 'El Tarf', + 'Genet', + 'Mount Gambier', + 'Tarkeshwar', + 'Sirumugai', + 'Missour', + 'Chainpura', + 'Sankt Wendel', + 'Armentieres', + 'Staunton', + 'Sarkikaraagac', + 'Bilston', + 'Montbeliard', + 'Nagar', + 'Haiwei', + 'Pszczyna', + 'Sao Joao Nepomuceno', + 'Bandiagara', + 'Kami', + 'Raghunathpur', + 'Oliva', + 'Vijapur', + 'Jericoacoara', + 'Alencon', + 'Idstein', + 'Aracoiaba', + 'Abay', + 'Stevens Point', + 'Okemos', + 'Ipameri', + 'Onda', + 'Niramaruthur', + 'Cliffside Park', + 'Poranki', + 'Shahedshahr', + 'Karayazi', + 'Oltiariq', + 'Witham', + 'Licey al Medio', + 'Rockaway', + 'Tipo-Tipo', + 'Tougue', + 'Vaterstetten', + 'Falconara Marittima', + 'Verl', + 'Salor', + 'Mar de Ajo', + 'Saintes', + 'Ayuquitan', + 'Rottweil', + 'Enna', + 'Brilon', + 'Lopez Jaena', + 'Manyoni', + 'Nettappakkam', + 'Roseto degli Abruzzi', + 'Al `Awwamiyah', + 'Borcka', + 'Xenia', + 'Kocaali', + 'Ciying', + 'Mimasaka', + 'Fujikawaguchiko', + 'Oldbury', + 'Menaceur', + 'Treinta y Tres', + 'Wetteren', + 'Bungku', + 'Backa Palanka', + 'Fort Hood', + 'Sobradinho', + 'Astorga', + 'Mimata', + 'Mannadipattu', + 'Kalispell', + 'Salaga', + 'Oroshaza', + 'South Bradenton', + 'Mahwah', + 'Tupaciguara', + 'Veenoord', + 'Thatcham', + 'Mercer Island', + 'Vistahermosa', + 'Bilgoraj', + 'Agaro', + 'Bathnaha', + 'Bishop Auckland', + 'Kouhu', + 'Silver Springs Shores', + 'Yany Kapu', + 'Unisan', + 'San Pedro Masahuat', + 'Sao Jose do Norte', + 'West Whittier-Los Nietos', + 'Sangerhausen', + 'Moschato', + 'Pauri', + 'Tumbao', + 'Anage', + 'Tres Passos', + 'Brunoy', + 'Rocha', + 'Limonar', + 'Kiranur', + 'Omigawa', + 'Ain Aicha', + 'Nyanza', + 'Szentes', + 'Caloto', + 'Longbridge', + 'Leandro N. Alem', + 'Bloxwich', + 'Peekskill', + 'Nagtipunan', + 'Rouached', + 'Craibas', + 'Vsetin', + 'Chengannur', + 'Perama', + 'Belvidere', + 'Zawyat ech Cheikh', + 'Ohringen', + 'Miyaki', + 'Lamu', + 'Hudson', + 'Demba', + 'Jilikul', + 'Showt', + 'Newberg', + 'Coracao de Jesus', + 'Turek', + 'Luzilandia', + 'Tomares', + 'Holt', + 'Eaubonne', + 'De Pere', + 'Zhongcun', + 'Villeneuve-la-Garenne', + 'Diego Martin', + 'Cherbourg', + 'Roth', + 'Arriaga', + 'Nonahi', + 'Legnago', + 'Upminster', + 'Louis Trichardt', + 'Ottumwa', + 'Thal', + 'Yanyan', + 'Tarpon Springs', + 'Lennestadt', + 'Galt', + 'Vierzon', + 'Hazelwood', + 'Ibirapitanga', + 'San Giovanni Lupatoto', + 'Karunagapalli', + 'Busselton', + 'Norco', + 'Rakovski', + 'Pinal de Amoles', + 'Timurni', + 'Vynohradiv', + 'Jevargi', + 'Wiehl', + 'Requena', + 'Salzkotten', + 'Harbel', + 'Ulongue', + 'Obertshausen', + 'Mill Creek East', + 'Farkhor', + "Giv`at Shemu'el", + 'Lengir', + 'Oupeye', + 'Kovancilar', + 'Susehri', + 'Ula', + 'Arzignano', + 'Caledonia', + 'Belen de Umbria', + 'San Juan de Alicante', + 'Denizciler', + 'Babra', + 'Forney', + 'Camillus', + 'Budai', + 'Sebastian', + 'Tanabi', + 'Kirkby in Ashfield', + 'Kingsville', + 'Seriate', + 'Merkanam', + 'Ludinghausen', + 'Wadi', + 'Mariano Comense', + 'Choconta', + 'Weingarten', + 'Bouknadel', + 'Kawlin', + 'Albergaria-a-Velha', + 'Elkridge', + 'Acatlan', + "Topol'cany", + 'Reedley', + 'Candido Sales', + 'Delitzsch', + 'Chardonnieres', + 'Talugtug', + 'Camalaniugan', + 'Fengruncun', + 'Chiromo', + 'Barstow', + 'Ganshoren', + 'Almonte', + 'Ilaiyankudi', + 'Mudgal', + 'Atlatlahucan', + 'Pfungstadt', + 'Bacoli', + 'Miahuatlan', + 'Tipasa', + 'Mananjary', + 'Petershagen', + 'Wumayingcun', + 'Sandona', + 'Sastamala', + 'Avon Lake', + 'Apiai', + 'Workington', + 'Guene', + 'Allendale', + 'Urucui', + 'Maaseik', + 'Brodosqui', + 'Somoniyon', + 'Saranga', + 'Taquari', + 'Adra', + 'Saydnaya', + 'Uttaramerur', + 'Kingswinford', + 'Kola', + 'Villarrobledo', + 'Latehar', + 'Gole', + 'Chekfa', + 'Sarrat', + 'Erlun', + 'Piranhas', + 'Paonta Sahib', + 'Tirora', + 'Norden', + 'University Park', + 'Fish Hawk', + 'Melrose Park', + 'Banhatti', + 'Walker', + 'Espelkamp', + 'Malyn', + 'El Calafate', + 'Jutai', + 'Overijse', + 'Aridagawa', + 'Barberton', + 'Raahe', + 'Monreal', + 'El Ghiate', + 'Fatime', + 'Vasudevanallur', + 'Carteret', + 'Alamo', + 'Debila', + 'Bagno a Ripoli', + 'Moses Lake', + 'Bardsir', + 'Dedham', + 'Rhyl', + 'Gulam', + 'Kasrawad', + 'Ditzingen', + 'Wewak', + 'Panagar', + 'Aimores', + 'Campos Sales', + 'Otuzco', + 'Pallappatti', + 'North Tustin', + 'Santa Maria Tonameca', + 'Sahibpur Kamal', + 'Sohwal', + 'Rania', + 'Edgewood', + 'Dickinson', + 'Atuntaqui', + 'Torrelodones', + 'Mombin Crochu', + 'Saiha', + 'Novi Travnik', + 'Namrup', + 'Corsicana', + 'Ashkhaneh', + 'Malangawa', + 'Mequon', + 'Kadavur', + 'Baliqchi', + 'Pagudpud', + 'Iglesias', + 'Sahjanwa', + 'Rajakheri', + 'Kongsberg', + 'Vicuna', + 'Bure', + 'Ninohe', + 'Ibiapina', + 'Yapqan', + 'Jafarabad', + 'Safsaf', + 'Correggio', + 'Soccorro', + 'Muskego', + 'Beersel', + 'Duiven', + 'Oegstgeest', + 'Sumperk', + 'Shrirangapattana', + 'El Karimia', + 'Muret', + 'Armilla', + 'Bombinhas', + 'Romulus', + 'Steenbergen', + 'Seal Beach', + 'Husi', + 'Waukee', + 'Lanling', + 'Nabinagar', + 'Sohagpur', + 'Charentsavan', + 'Camaligan', + 'Wolfsberg', + 'Whitehaven', + 'Slavutych', + 'Datca', + 'Barwa Sagar', + 'Droitwich', + 'Pangil', + 'Daventry', + 'Quirino', + 'Coin', + "Saint-Ouen-l'Aumone", + 'Bousse', + 'Sao Joao dos Patos', + 'Barki Ballia', + 'Nepomuceno', + 'Simria', + 'Yarmouth', + 'Olpe', + 'Trikodi', + 'Valls', + 'Hukeri', + 'Naubatpur', + 'Ramshir', + 'Maywood', + 'Pathiyanikunnu', + 'Sonzacate', + 'Attili', + 'Paoay', + 'Hindley', + 'Khed Brahma', + 'Vangviang', + 'Ehden', + 'Ampahana', + 'Fidirana', + 'Mahatalaky', + 'Ankazomborona', + 'Antsirabe Avaratra', + 'Catembe', + 'Nijverdal', + 'Santiago de Chuco', + 'Caballococha', + 'Dainyor', + 'Pinhal Novo', + 'Baxdo', + 'Tall Shihab', + 'Zaouiet Sousse', + 'Kamonkoli', + 'Kibuku', + 'Sho`rchi', + 'Araira', + 'Higuerote', + 'Drodro', + 'Dbarwa', + 'Moyale', + 'Portishead', + 'Pitsea', + 'Tegalbuleud', + 'Ayirurpara', + 'Parner', + 'Lalru', + 'Singhana', + 'Kalamner', + 'Sojitra', + 'Madha', + 'Chanasma', + 'Vodurivandlagudem', + 'Khiria Jhansi', + 'Ladol', + 'Kali', + 'Data', + 'Malanvadi', + 'As Saqlawiyah', + 'Shaqlawah', + 'Ash Shunah ash Shamaliyah', + 'Simaria', + 'Nossa Senhora das Dores', + 'Calahorra', + "Mohale's Hoek", + 'Bethune', + 'Sultepec', + 'Ponta de Pedras', + 'Norton Shores', + 'Kabanga', + 'Sidhauli', + 'Westhoughton', + 'Tsaratanana', + 'Tapa', + 'Paduvari', + 'Mardakan', + 'Sandusky', + 'Gajwel', + 'Baindur', + 'Plettenberg', + 'Visby', + 'La Esperanza', + 'Sugar Hill', + 'Paete', + 'Rio Preto da Eva', + 'Bad Oldesloe', + 'Yuzhang', + 'Niscemi', + 'Traralgon', + 'Cuijk', + 'Portalegre', + 'Marneuli', + 'Ixchiguan', + 'Dalupo', + 'Pinillos', + 'Termini Imerese', + 'Mundargi', + 'Tres de Maio', + 'Koumia', + 'Nainpur', + 'Hunucma', + 'Elefsina', + 'Morton Grove', + 'Dimasalang', + 'Montalban', + 'Dugda', + 'Broadstairs', + 'Nogi', + 'Pezinok', + 'Sand', + 'Ixhuatlancillo', + 'Ushtobe', + 'Westchase', + 'Castelnau-le-Lez', + 'Flores Costa Cuca', + 'Minowa', + 'Quisqueya', + 'Westerlo', + 'Sora', + 'Piracanjuba', + 'Loma Linda', + 'Pedro Carbo', + 'Martinopolis', + 'Quispamsis', + 'Schmallenberg', + 'Sahasoa', + 'Meckenheim', + 'Omurtag', + 'Stein', + 'Iki', + 'Denison', + 'Villa Tapia', + 'Kobo', + 'Wasaga Beach', + 'Wujiaying', + 'Karukurti', + 'Watertown', + 'Kalavad', + 'Wyandotte', + 'Edavanakad', + 'Ishii', + 'Jabonga', + 'Perrysburg', + 'Solsona', + 'Fort Dodge', + 'Adis Zemen', + 'Rangapara', + 'Kuna', + 'Maduru', + 'Cherukara', + 'Valambur', + 'Anivorano Avaratra', + 'Liangwu', + 'Sprockhovel', + 'Kerkyra', + 'Ghoti Budrukh', + 'Santa Rita do Passa Quatro', + 'Sirmatpur', + 'Hamme', + 'Gemerek', + 'Turuttikkara', + 'Carolina Forest', + 'Avon', + 'Aso', + 'Ciudad Barrios', + 'Uherske Hradiste', + 'Collingwood', + 'Syke', + 'Basopatti', + 'Piat', + 'Madaoua', + 'General Luna', + 'Riverbank', + 'Thundersley', + 'Kuttampuzha', + 'West Milford', + 'Swiecie', + 'Icatu', + 'Zittau', + 'Khalari', + 'Baarn', + 'Corralillo', + 'Ouaoula', + 'Voorst', + 'Suchitoto', + "Sao Lourenco d'Oeste", + 'Gorleston-on-Sea', + 'Shivganj', + "Bailey's Crossroads", + 'Ardmore', + 'Salanso', + 'Tugaya', + 'Douar Olad. Salem', + 'Guarai', + 'Fontenay-aux-Roses', + 'Zanesville', + 'Pepa', + 'Pweto', + 'Dodola', + 'San Benito', + 'Beifan', + 'Galdacano', + 'San Francisco Zapotitlan', + 'Penistone', + 'Kalayaan', + 'Jamay', + 'Rudolstadt', + 'Tres Isletas', + 'Ban Khamen', + 'Meiningen', + 'Bintuni', + 'Thornaby on Tees', + 'Frederickson', + 'Scotch Plains', + 'Cambre', + 'Kulachi', + 'Patian', + 'Taquaritinga do Norte', + 'Owando', + 'Cloverleaf', + 'Bazarak', + 'Junqueiro', + 'Lutz', + 'Hertford', + 'Zumpango del Rio', + 'Brasil Novo', + 'Delfzijl', + 'Bystrc', + 'Dinuba', + 'Castro Alves', + 'Joao Lisboa', + 'Ma`bar', + 'Zhenbeibu', + 'Gouna', + 'Podaturpeta', + "G'allaorol Shahri", + 'Mairwa', + 'North Potomac', + 'Oga', + 'Saltpond', + 'Kakonko', + 'Baroy', + 'Bainbridge Island', + 'Tamilisan', + 'Raska', + 'Hinis', + 'Jacare', + 'Panapur', + 'Kajiado', + 'Naruto', + 'Patnagarh', + 'Monte Cristi', + 'Stutterheim', + 'Narasingapuram', + 'Shitan', + 'Uaua', + 'Chandili', + 'Miguel Calmon', + 'Kaga Bandoro', + 'Pasighat', + 'Dix Hills', + 'Naduvannur', + 'Eidsvoll', + 'Larvik', + 'Warstein', + 'Greenbelt', + 'Leoben', + 'Burdeos', + 'Newton in Makerfield', + 'Las Cabras', + 'Palakodu', + 'Oleshky', + 'Boquim', + 'Shamgarh', + 'Merelbeke', + 'Bielsk Podlaski', + 'Al Qubbah', + 'Bayonet Point', + 'El Milagro', + 'Ban Bang Phun', + 'Santa Maria do Para', + 'Zwevegem', + 'Ridgeland', + 'Rawson', + 'Navalgund', + 'San Borja', + 'Iacu', + 'Donggangli', + 'Waldshut-Tiengen', + 'Khashuri', + 'Madougou', + 'Pata Kalidindi', + 'Rathenow', + 'Coral Terrace', + 'Etajima', + 'Fatoma', + 'Ramdiri', + 'Oulad Tayeb', + 'Telagh', + 'Auburn Hills', + 'Darende', + 'Condado', + 'Carrascal', + 'Gorantla', + 'Irugur', + 'Selma', + 'Biharamulo', + 'Reserva', + 'Calamar', + 'Ain Kechera', + 'Ronnenberg', + 'Zion', + 'Sept-Iles', + 'Panglong', + 'Carlos A. Carrillo', + 'Bad Mergentheim', + 'Paita', + 'Takhli', + 'Isernhagen-Sud', + 'El Retorno', + 'Tuzluca', + 'Karatas', + 'Tapejara', + 'Libourne', + 'Breclav', + 'Mponela', + 'Guabiruba', + 'Stjordal', + 'Kottapeta', + 'Wierden', + 'Cheruvaranam', + 'Ravansar', + 'Sirkhandi Bhitha', + 'Westford', + 'Markkleeberg', + 'Dungra Chhota', + 'Ain Dfali', + 'Liria', + 'Watsa', + 'Chebba', + 'Cordeiropolis', + 'Amatan', + 'Centerville', + 'Homer Glen', + 'Aklvidu', + 'Zdolbuniv', + 'Qualiano', + 'Hulbuk', + 'Bereket', + 'Haren', + 'Andhra Tharhi', + 'Nij Khari', + 'Dongxiaozhai', + 'Tirumuruganpundi', + 'Parambatt Kavu', + 'Ocara', + 'Waldkraiburg', + 'Pindwara', + 'Ap Khanh Hoa', + 'Dhamnagar', + 'Mahdishahr', + 'Kaynarca', + 'Orly', + 'Hanerik', + 'Khajuraho', + 'Traun', + 'Leland', + 'San Agustin Loxicha', + 'Purwa', + 'Juayua', + 'Baar', + 'Socastee', + 'Gyal', + 'Sahaspur', + 'Cartaxo', + 'Oak Harbor', + 'Sahawar', + 'Nasukarasuyama', + 'Herndon', + 'Wetzikon', + 'Igaracu do Tiete', + 'Attendorn', + 'Zungeru', + 'Olesa de Montserrat', + 'Vinnamala', + 'Bundu', + 'Tamahu', + 'Felixstowe', + 'Ponca City', + 'Qabatiyah', + 'Channagiri', + "'Ain Boucif", + 'Vilankulo', + 'Zhuangwei', + 'Gaz', + 'Garcia Hernandez', + 'Yokadouma', + 'Landover', + 'Sao Sebastiao do Cai', + 'Tres Coroas', + 'North Augusta', + 'Zagan', + 'King of Prussia', + 'Faribault', + 'Mola di Bari', + 'Armiansk', + 'North Laurel', + 'Erandio', + 'Pedra Azul', + 'Oirase', + 'Bay Point', + 'Ramain', + 'Fray Bentos', + 'Minas Novas', + 'Ashwaraopeta', + 'Herzogenaurach', + 'Tirutturaippundi', + 'Abim', + 'Varel', + 'Garhara', + 'Panmana', + 'Itambe', + 'Siofok', + 'Rugeley', + 'Ngorkou', + 'Happy Valley', + 'Le Kremlin-Bicetre', + 'Kings Norton', + 'Tbeng Meanchey', + 'Eysines', + 'Les Irois', + 'Kazincbarcika', + 'Buzen', + 'Port St. John', + 'Benbrook', + 'Putten', + 'Valente', + 'Preah Vihear', + 'Kenndie', + 'Hirriyat Raznah', + 'Pyrgos', + 'Duncan', + 'Birkirkara', + 'Hennenman', + 'Puerto Guzman', + 'Nagarpara', + 'Ambohimasina', + 'West Memphis', + 'Taquarituba', + 'Ruvo di Puglia', + 'Nova Xavantina', + 'Paruthur', + 'Porto de Mos', + 'Le Bouscat', + 'Grombalia', + 'Sagbayan', + 'Kerrville', + 'Horquetas', + 'Canhotinho', + 'Martos', + 'Las Margaritas', + 'Ballenger Creek', + 'Singarayakonda', + 'Ladera Ranch', + 'Tadjmout', + 'Pallapatti', + 'Iringal', + 'Gose', + 'White Bear Lake', + 'Portogruaro', + 'Sarykemer', + 'Ipixuna', + 'Bijawar', + 'Qazi Ahmad', + 'Cedros', + 'Velur', + 'Echemmaia Est', + 'Bedburg', + 'Alfreton', + 'Oud-Beijerland', + 'Freudenstadt', + 'Qianwangcun', + 'Koloriang', + 'Pinheiral', + 'Curacavi', + 'Daksinkali', + 'Barnegat', + 'Ajim', + 'Collinsville', + 'Stassfurt', + 'Radauti', + 'Raisio', + 'Oulad Barhil', + 'Kien Luong', + 'Saint-Laurent-du-Maroni', + 'Saky', + 'Baheri', + 'Almansa', + 'Maharajgani', + 'Volksrust', + 'Zhuchangba', + 'Elmwood Park', + 'Satuba', + 'Nueva Paz', + 'Starkville', + 'South Plainfield', + 'Borre', + 'Carlow', + 'Katrineholm', + 'Wekiwa Springs', + 'Ayanavelikulangara Tekku', + 'Middleborough', + 'Palmetto Bay', + 'Senador Pompeu', + 'Noto', + 'Umga', + 'Zhangshanying', + 'Sao Geraldo do Araguaia', + 'Gazojak', + 'Saint-Nicolas', + 'Lukaya', + 'Tocopilla', + 'Somerset', + 'Mahaiza', + 'Fairfax', + "Douar 'Ayn Dfali", + 'El Salto', + 'Belton', + 'El Factor', + 'Mayang Imphal', + 'uMhlanga Rocks', + 'Lebedyn', + 'Carutapera', + 'Mekla', + 'Nova Soure', + 'Ganzhu', + 'Vettakkaranpudur', + 'North Lynnwood', + 'Qiaomaichuan', + 'Haaksbergen', + 'Freha', + 'Chester-le-Street', + 'Sroda Wielkopolska', + 'Pelham', + 'Jan Kempdorp', + 'El Congo', + 'Calw', + 'Los Barrios', + 'Cabrera', + 'Guatuba', + 'Gotvand', + 'Ubach-Palenberg', + 'Farnley', + 'Ambalamanasy II', + 'Great Sankey', + 'Kariba', + 'Debaltseve', + 'Rodez', + 'Canarana', + 'Calliaqua', + 'Ponneri', + 'Soure', + 'Donmatias', + 'Buwenge', + 'Uchquduq Shahri', + 'Boulsa', + 'Gelemso', + 'Aioun', + 'Feriana', + 'Yukon', + 'Marin', + 'Naravarikuppam', + 'Halikner', + 'Kauswagan', + 'Ortigueira', + 'Quatro Barras', + 'Lagonglong', + 'Fossano', + 'Maksi', + 'Mogalturru', + 'Machachi', + 'Novo Mesto', + 'Magenta', + 'Skawina', + 'Helleland', + 'Forquilha', + 'Golborne', + 'Caibiran', + 'Walcz', + 'Lop Buri', + 'Les Pavillons-sous-Bois', + 'Ukkayapalle', + 'Kosigi', + 'Jaruco', + 'Angatuba', + 'Oguchi', + 'Yoqne`am `Illit', + 'Sehnde', + 'Velingrad', + 'Macia', + 'Liushui', + 'Heiloo', + 'Meyrin', + 'Hingham', + 'Baharly', + 'Rioblanco', + 'Itapora', + 'Bir Jdid', + 'Zapresic', + 'Simpsonville', + 'Marsella', + 'Isa', + 'Setti Fatma', + 'Korostyshiv', + 'Salvaterra', + 'Eisenhuttenstadt', + 'Mairena del Alcor', + 'Loha', + 'Tiruvattar', + 'Emporia', + 'Anjozorobe', + 'Marple', + 'Vrbas', + 'Sundararaopeta', + 'Alwaye', + 'Fishkill', + 'Paraopeba', + 'Anastacio', + 'Upper Providence', + 'Tayyibat al Imam', + 'Wandlitz', + 'Plymstock', + 'Bloomingdale', + 'Espera Feliz', + 'Jaisinghpur', + 'As Sulayyil', + 'Ryde', + 'Qiloane', + 'Areia Branca', + 'Cogua', + 'Monte Siao', + 'Lagoa Grande', + 'Mirandola', + 'Deyr', + 'Montevarchi', + 'Vicente Lopez', + 'Santa Maria Colotepec', + 'Ormskirk', + 'Wadsworth', + 'Goias', + 'Sangrampur', + 'Skoura', + 'Rolling Meadows', + 'Solon', + 'Boo', + 'Mandan', + 'Senboku', + 'Arttuvattala', + 'Mina', + 'Tangcun', + 'Rita', + 'Siswa', + 'Suleswaranpatti', + 'Tegina', + 'Guapi', + 'Bellview', + 'Buritis', + 'Sanando', + 'Jasmine Estates', + 'Saint-Lin--Laurentides', + 'Kourou', + 'Independencia', + 'Pontinha', + 'Koscian', + 'Atar', + 'Veranopolis', + 'Laon', + 'Yadiki', + 'Papillion', + 'Tehri', + 'Soamanandrariny', + 'Ambatotsipihina', + 'Jequitinhonha', + 'Bcharre', + 'Ambohimandroso', + 'Lopary', + 'Antonibe', + 'Antanimieva', + 'Miarinarivo', + 'Tsiatosika', + 'Itigi', + 'Butaleja', + 'Chinobod', + 'Jalolquduq', + 'Sheghnan', + 'Tchibanga', + 'Maheshwar', + 'Payipira', + 'Caazapa', + 'Quellon', + 'Zolochiv', + 'Sikandarpur', + 'Cachoeira do Arari', + 'Cavinti', + 'Pennadam', + 'Huilongping', + 'Barnstaple', + 'Laranjeiras', + 'Plainsboro', + 'General Emilio Aguinaldo', + 'Rickmansworth', + 'Kamiamakusa', + 'Icod de los Vinos', + 'Dabaga', + 'Kyonpyaw', + 'Embarcacion', + 'Laguna Salada', + 'Sao Goncalo do Sapucai', + 'Littleover', + 'Santa Quiteria do Maranhao', + 'Wil', + 'La Valette-du-Var', + 'Goirle', + 'Neduvattur', + 'Ambohimahamasina', + 'Urucurituba', + 'Itaporanga', + 'Juchen', + 'Arbroath', + 'Tsawwassen', + 'Bulusan', + 'Sao Joao da Ponte', + 'Belo Oriente', + 'Sighisoara', + 'Mapoteng', + 'Solin', + 'Wijk bij Duurstede', + 'Puyappalli', + 'Jucas', + 'El Zulia', + 'Douar Bou Tlelis', + 'Ibi', + 'Koulikoro', + 'Manlio Fabio Altamirano', + 'Umbauba', + 'Iraucuba', + 'Usia', + 'Sendamangalam', + 'Hatonuevo', + 'Sao Joao do Paraiso', + 'Buritizeiro', + 'Pompei', + 'Alfter', + 'Zwedru', + 'Porto Franco', + 'Falticeni', + 'Tacaratu', + 'Paxtakor Shahri', + 'Brotas', + 'Mejorada del Campo', + 'Tantoyuca', + 'Tecoluca', + 'Gungu', + 'Hadzici', + 'Matabhanga', + 'Mulgund', + 'Cibitoke', + 'Caversham', + 'Vanersborg', + 'Seveso', + 'Tata', + 'Noqui', + 'Macaparana', + 'Iraquara', + 'Peringuzha', + 'Karian', + 'Strathroy-Caradoc', + 'Subaykhan', + 'Buon Trap', + 'Koilkuntla', + 'Matriz de Camarajibe', + 'Dunleary', + 'Ourikela', + 'Westerstede', + 'Lihe', + 'Herohalli', + 'Mirandela', + 'Oadby', + 'Hopa', + 'Rosemont', + 'Jurh', + 'Caras', + 'Az Zuwaydah', + 'Ksar el Hirane', + 'South Elgin', + 'Webster Groves', + 'Cranford', + 'Chanthaburi', + 'Mulakumud', + 'Limbach-Oberfrohna', + 'Cruzeiro do Oeste', + 'Honda', + 'Annur', + 'Makhmur', + 'San Miguel Ocotenco', + 'Ciudad Serdan', + 'Diest', + 'Atotonilco el Grande', + 'Pao de Acucar', + 'Willoughby', + 'Kasongo-Lunda', + 'Altea', + 'Popovo', + 'Encruzilhada do Sul', + 'Squamish', + 'Douar Ouled Ayad', + 'Novo Aripuana', + 'Thorold', + 'Firuzoba', + 'Kalawit', + 'Carandai', + 'Kuju', + 'Frontignan', + 'Hungund', + 'Kumar Khad', + 'Catigbian', + 'Hodonin', + 'Zawyat an Nwacer', + 'Montgeron', + 'Sulya', + 'Bithar', + 'Farragut', + 'Thiene', + 'Grootfontein', + 'Selydove', + 'El Maknassi', + 'Fada', + 'Gaojiayingcun', + 'Ituango', + 'Dakor', + 'Vallabh Vidyanagar', + 'Stepanavan', + 'El Tejar', + 'Agrestina', + 'Tirumala', + 'Hoh Ereg', + 'Velingara', + 'Dole', + 'Ishiki', + 'Baliguian', + 'Akwatia', + 'Basankusu', + 'Manari', + 'Dobeln', + 'Verukulambu', + 'De Aar', + 'Oldebroek', + 'Kidsgrove', + 'Cullera', + 'Candoni', + 'Santa Apolonia', + 'Limbuhan', + 'Hachimantai', + 'Starnberg', + 'Elukone', + 'East Retford', + 'Lalgudi', + 'Fountain Hills', + 'Avanigadda', + 'Vizela', + 'Birpur', + 'Nocera Superiore', + 'Husum', + 'Huntingdon', + 'Mummidivaram', + 'Stalybridge', + 'Oji', + 'Fria', + 'Pout', + 'Alice Springs', + 'San Giovanni la Punta', + 'Koscierzyna', + 'Waverly', + 'Lebu', + 'Ayancik', + 'Norresundby', + 'Puduva', + 'Dasungezhuang', + 'Devikolam', + 'Karavalur', + 'Khenichet-sur Ouerrha', + 'Rishton', + 'Korbach', + 'Tangalan', + 'Salqin', + 'Chinoz', + 'Stanmore', + 'Nesher', + 'Shama', + 'Sezze', + 'Ayt Mohamed', + 'Southold', + 'Miantso', + 'Maldegem', + 'Droylsden', + 'San Juan Cotzocon', + 'Gelnhausen', + 'Silappadi', + 'Patterson', + 'Tirukkalikkunram', + 'Anupshahr', + 'Shelbyville', + 'Cazones de Herrera', + 'Sanaur', + 'Santo Antonio do Sudoeste', + 'Muscatine', + 'Dalyoni Bolo', + 'Champlin', + 'Orleaes', + 'Conil de la Frontera', + 'Lubliniec', + 'Alangulam', + 'Yellapur', + 'Roseburg', + 'Perry Barr', + 'Conde', + 'Pirai do Sul', + 'Raritan', + 'Dunaharaszti', + 'Ahualulco de Mercado', + 'Bang Sao Thong', + 'Chandrakona', + 'Bafilo', + 'Tecali', + 'Taupo', + 'Beni Amrane', + 'Berhoum', + 'Gosforth', + 'Mannamturuttu', + 'Satun', + 'Santa Gertrudes', + 'Kenmore', + 'Yesagyo', + 'Gueznaia', + 'Mountain House', + 'Askale', + 'Tapiales', + 'Ogawara', + 'Kulgam', + 'Jacksonville Beach', + 'Truro', + 'Kyeintali', + 'Kebila', + 'Oostkamp', + 'Newton Abbot', + 'Lustenau', + 'Perungudi', + 'Dakovo', + 'San Martin Totolan', + 'Cerro Azul', + 'Amstetten', + 'San Ignacio de Velasco', + 'Monsefu', + 'Tamandare', + 'Toda Rai Singh', + 'Peravur', + 'Bauta', + 'Castiglione delle Stiviere', + 'Heverlee', + 'Gollapudi', + 'Dhing', + 'Ma`alot Tarshiha', + 'Codajas', + 'Luninyets', + 'Belsand', + 'Gerede', + 'Bambui', + 'Salzwedel', + 'Bishopbriggs', + 'Kaltenkirchen', + 'Sao Miguel', + 'Khelil', + 'Nyuzen', + 'Xiaojiangcun', + 'Jaleshwar', + 'Yangi Marg`ilon', + 'Hannoversch Munden', + 'Brookings', + 'Dumaran', + 'Honavar', + 'General Panfilo Natera', + 'Amherstburg', + 'Nixa', + 'Funes', + 'Canalete', + 'Ban Phru', + 'Cupira', + 'At Tafilah', + 'Watauga', + 'Marshall', + 'Sonneberg', + 'Loon op Zand', + 'Kaniv', + 'Mujui dos Campos', + 'Muang Sing', + 'Quarai', + 'Arukutti', + 'Suonan', + 'Nayanakulam', + 'Lisle', + 'Ringsted', + 'Pakil', + 'Port Laoise', + 'Jocotenango', + 'Cuyo', + 'Padre Burgos', + 'Gardner', + 'Cesky Tesin', + 'Griffin', + 'Mosbach', + 'Matinha', + 'Dillenburg', + 'Oued el Djemaa', + 'Koili Simra', + 'Yugawara', + 'Carmo do Cajuru', + 'Bloemendaal', + 'Chanaur', + 'Gauripur', + 'Francisco Sa', + 'Oulad Hassoune', + 'Hajduszoboszlo', + 'Kharupatia', + 'Maple Heights', + 'Maharlika Village', + 'Monte Caseros', + 'Krychaw', + 'Les Lilas', + 'Kyenjojo', + 'Bonoufla', + 'Dank', + 'Tapaktuan', + 'Muggio', + 'Sanga', + 'Brody', + 'Sinj', + 'Beni Rached', + 'Madangir', + 'Kedainiai', + 'Minamikarasuyama', + 'Chrudim', + 'Copiague', + "L'Assomption", + 'Rampura', + 'Gjirokaster', + 'Nasu', + 'Bni Frassen', + 'Elburg', + 'Pilar de la Horadada', + 'Kilindoni', + 'Badnawar', + 'Raul Soares', + 'Pissila', + 'Maychew', + 'Sattahip', + 'Kailashahar', + 'Vega Baja', + 'Pesochin', + 'Srvanampatti', + 'Santa Rosa de Viterbo', + 'Teguise', + 'Veinticinco de Mayo', + 'Senftenberg', + 'Havlickuv Brod', + 'Van Buren', + 'Burhar', + 'Galikesh', + 'Ban Thoet Thai', + 'Svilajnac', + 'Kafr Shukr', + 'Makouda', + 'Meda', + 'Sluis', + 'Teorama', + 'Ponda', + 'Albenga', + 'Akkus', + 'Giulianova', + 'Vanimel', + 'Gamay', + 'Bultfontein', + 'Netphen', + 'Canico', + 'Rock Springs', + 'Barbasa', + 'Beni Khalled', + 'Quang Tri', + 'Pottstown', + 'Dighwa', + 'Sakleshpur', + 'Montecchio Maggiore', + 'Pitea', + 'Takehara', + 'Sandwa', + 'Caglayancerit', + 'Pindoretama', + 'Leutkirch im Allgau', + 'Tazhava', + 'Madappalli', + 'Sokolo', + 'Maigo', + 'Westerly', + 'Piravanthur', + 'Saint-Ghislain', + 'Mandawa', + 'Antanimasaka', + 'Coronel Vivida', + 'Cide', + 'Cadca', + 'Dongshi', + 'Berehove', + 'Zemst', + 'Doctor Mora', + 'Warburg', + 'Collipulli', + 'Ambohimiadana', + 'Horgen', + 'Minja', + 'Sai Mai', + 'Dalmine', + 'Pelitli', + 'Capinzal', + 'Quedlinburg', + 'Ron', + 'Calbiga', + 'North Platte', + 'Bazhajiemicun', + 'Phongsali', + 'Moskva', + 'Tecumseh', + 'Tugatog', + 'Tobati', + 'Ardahan', + 'Lormont', + 'Bordj Ghdir', + 'Niskayuna', + 'Anatuya', + 'Goumori', + 'Aldeias Altas', + 'La Cruz de Rio Grande', + 'Poxoreo', + 'Carambei', + 'San Rafael Abajo', + 'Whitefield', + 'Kedavur', + 'Piastow', + 'Alhama de Murcia', + 'Rathfarnham', + 'Monteros', + 'Gersthofen', + 'Teodoro Sampaio', + 'Mulampilli', + 'Camp Springs', + 'Telica', + 'Abaete', + 'Linda', + 'Cajidiocan', + 'Tekari', + 'Martha Lake', + 'La Higuerita', + 'La Huerta', + 'Maibog', + 'Alliston', + 'Ulukisla', + 'Piritu', + 'Cockeysville', + 'Ozuluama de Mascarenas', + 'Santo Antonio de Posse', + 'Motul', + 'Mine', + 'Phetchaburi', + 'Xunjiansi', + 'Vaikam', + 'Mantua', + 'Cottage Lake', + 'Raymore', + 'Selim', + 'Kun Puhal', + 'Pickerington', + 'Calamba', + 'Loanda', + 'Nuku`alofa', + 'Samrala', + 'Mizdah', + 'Culion', + 'Kedia', + 'Sheyban', + 'Nakashunbetsu', + 'Cambara', + 'Fergus', + 'Kelishad va Sudarjan', + 'Patakakani', + 'Amarapura', + 'Sevan', + 'Manambur', + 'Touboro', + 'Wertheim', + 'Wareham', + 'Tranquebar', + 'Kazhukambalam', + 'Capoterra', + 'Bassar', + 'Rastede', + '`Ali Shahr', + 'Nova Petropolis', + 'Vilaseca de Solcina', + 'Vukovar', + 'Ponmundam', + 'Kannamangalam Tekku', + 'Union Hill-Novelty Hill', + 'Eastmont', + 'Karben', + 'Tototlan', + 'Pajapita', + 'Kouoro', + 'Tukrah', + 'Ashland', + 'Conceicao do Mato Dentro', + 'Bad Soden am Taunus', + 'Vreden', + 'Apatin', + 'Minamata', + 'Puenteareas', + 'Zarautz', + 'Sonepur', + 'Ribas do Rio Pardo', + 'Ban Bang Rin', + 'Abreus', + 'Bialogard', + 'Ravulapalem', + 'New Brighton', + 'Edgewater', + 'Planalto', + 'Easley', + 'Shuilin', + 'Bananeiras', + 'Douar Imoukkane', + 'Puerto Concordia', + 'Soledad Atzompa', + 'Neihuzhai', + 'Trotwood', + 'Litomerice', + 'Sao Mamede de Infesta', + 'Manage', + 'Mahthi', + 'Tamiahua', + 'Caba', + 'West Goshen', + 'Ottaviano', + 'Yasica Arriba', + 'Rafael Delgado', + 'Liberty Triangle', + 'Los Arabos', + 'Sansanding', + 'Singhara Buzurg', + 'Fanzeres', + 'Chantilly', + 'Calabasas', + 'Vuliyattara', + 'Cartersville', + 'Sonari', + 'Engandiyur', + 'Eustis', + 'Roxbury', + 'Tupiza', + "Qiryat Mal'akhi", + 'Hombori', + 'Uberlingen', + 'Oxkutzkab', + 'Morris', + 'Yunak', + 'Rochefort', + 'Sederot', + 'Mujiayu', + 'Khirkiyan', + 'Rucphen', + 'Siwah', + 'Maisons-Laffitte', + 'Vilachcheri', + 'Qiryat Shemona', + 'Tnine Lgharbia', + 'Apolda', + 'Vigonza', + 'Bear', + 'Saint-Dizier', + 'Pallikondai', + 'Yakinca', + 'Roissy-en-Brie', + 'Orbassano', + 'Catano', + 'Asafabad', + 'Coueron', + 'Weilheim', + 'Dom Pedro', + 'Nagykoros', + 'Lunbei', + 'Warragul', + 'Achi', + 'Koussane', + 'Velugodu', + 'Penwortham', + 'Youwarou', + 'Devonport', + 'Hopewell', + 'Dunajska Streda', + 'Auch', + 'Thiotte', + 'Buyende', + 'Upper Allen', + 'Bad Kissingen', + 'Koiri Bigha', + 'Fernley', + 'Mangidy', + 'Copertino', + 'Bataguacu', + 'Anjarkandi', + 'Oliveira do Bairro', + 'San Andres de Giles', + 'Nova Milanese', + 'Lanester', + 'Shiling', + 'Tembagapura', + 'Lysander', + 'Tubungan', + 'Curumani', + 'Kulattuppalaiyam', + 'Ladner', + 'Novy Jicin', + 'Glassboro', + 'Bad Salzungen', + 'Loos', + 'Khaira Tola', + 'Ban Bang Krang', + 'Taylors', + 'Harborne', + 'Ka-Bungeni', + 'Carletonville', + 'Majdel Aanjar', + 'Ambohitrarivo', + 'Mahela', + 'Farahalana', + 'Analamisampy', + 'Ambohitoaka', + 'Miantsoarivo', + 'Ankaramy', + 'Marovato', + 'Ankilizato', + 'Andalatanosy', + 'Kungsbacka', + 'Gyegu', + 'Zhaoling', + 'Rawtenstall', + 'Dindori', + 'Candiac', + 'Despotovac', + 'Wichian Buri', + 'Stoneham', + 'Panelas', + 'Wallenhorst', + 'Niamtougou', + 'Manlin', + 'Nagold', + 'Ivoti', + 'Mobetsu', + 'Lisse', + 'Radcliff', + 'Lengerich', + 'Vandiperiyar', + 'Lagoa', + 'Yaguachi Nuevo', + 'Tighedouine', + 'Malinalco', + 'Labuleng', + 'Essa', + 'Brent', + 'Latauna', + 'Sandviken', + 'Manuel B. Gonnet', + 'Minbu', + 'Encantado', + 'Frederikshavn', + 'Searcy', + 'Nikaho', + 'Moguer', + 'Dabeiba', + 'Crystal', + 'Las Brenas', + 'Scherpenheuvel', + 'Nocatee', + 'Kamabougou', + 'Manghit', + 'Christiansburg', + 'Friesoythe', + 'Kitzingen', + 'Muttupet', + 'Mekhe', + 'Hollola', + 'Abu', + 'Laguna Beach', + 'Molodohvardiisk', + 'Znamianka', + 'Nijlen', + 'Huaibaijie', + 'Loves Park', + 'Blue Island', + 'Swinton', + 'Peters', + 'Manosque', + 'Famailla', + 'Prairie Village', + 'Bathgate', + 'Itaocara', + 'Biancavilla', + 'Pul-e `Alam', + 'Kilkis', + 'Dafni', + 'Market Harborough', + 'Nyakrom', + 'Wulongpu', + 'Edewecht', + 'Dialakoroba', + 'Dokuchaievsk', + 'Keene', + 'Zdunska Wola', + 'Bhiraha', + 'Shurugwi', + 'Kotido', + 'Vadakarai Kil Pidagai', + 'Ayos', + 'Colorado', + 'Senden', + 'Dorohoi', + 'Fontaine', + 'Trebisov', + 'Losser', + 'Vellalur', + 'Pointe a Raquettes', + 'Ogre', + 'Garoua Boulai', + 'Zeewolde', + 'Ramos', + 'Kalat', + 'Luruaco', + 'Marcinelle', + 'Mahadebnagar', + 'Ekeren', + 'Neusass', + 'Pietrasanta', + 'Viga', + 'Baile Atha Luain', + 'Bhadas', + 'Genzano di Roma', + 'Vale de Cambra', + 'Laupheim', + 'Aracariguama', + 'Nazca', + 'Waltham Abbey', + 'Malacatancito', + 'Patacamaya', + 'Oteiza', + 'Olivet', + 'Azove', + 'Vagos', + 'Hadyach', + 'Ventimiglia', + 'Blangmangat', + 'Krnov', + 'Arcos de Valdevez', + 'Roselle', + 'Villanueva de la Canada', + 'Dammarie-le-Lys', + 'Gainsborough', + 'Machesney Park', + 'Guanajay', + 'Nayagaon', + 'Tadmait', + 'Chitarpur', + 'Naolinco de Victoria', + 'Ecoporanga', + 'Selvazzano Dentro', + 'Qatana', + 'Xinsi', + 'Ahwa', + 'Erdington', + 'Katy', + 'Millbrae', + 'Nogoya', + 'Ondangwa', + 'Pawni', + 'Torre del Mar', + 'Ataco', + 'Bressanone', + 'Gaoshu', + 'Hialeah Gardens', + 'Kagadi', + 'Balen', + 'Tadotsu', + 'Siqueira Campos', + 'Yanshanbu', + 'Barbate de Franco', + 'Camilo Ponce Enriquez', + 'Cherial', + 'Zunheboto', + 'Tomarza', + 'Pulimathu', + 'Corcoran', + 'Beek en Donk', + 'Fangliao', + 'Beshariq', + 'Haywards Heath', + 'Nahiyat al Kifl', + 'Kapfenberg', + 'Brambleton', + 'Pedra', + 'Frascati', + 'Cinco Saltos', + 'Pecan Grove', + 'Aybasti', + 'Achhnera', + 'Lumbatan', + 'Bormujos', + 'Gormi', + 'Sun Valley', + 'Butig', + 'Kungalv', + 'San Jose Ojetenam', + 'Amoucha', + 'Pariyapuram', + 'Kavallemmavu', + 'Kodarma', + 'Kaler', + 'Onondaga', + 'Baravat', + 'Saint-Lambert', + 'Kumano', + 'Herdecke', + 'Linstead', + 'Kanchika', + 'Nasrullahganj', + 'Villa Park', + 'Vernag', + 'San Feliu de Guixols', + 'San Miguel de Papasquiaro', + 'Ivato', + 'Quartier Militaire', + 'Ojinaga', + 'Gobo', + 'Vayanur', + 'Melissia', + 'Ashtown', + 'Keta', + 'Seva', + 'Junction City', + 'Boura', + 'Kulkent', + 'Chunakara Vadakku', + 'Curchorem', + 'Ayagawa', + 'Ravar', + 'Arroyito', + 'Kerur', + 'Garmdarreh', + 'Alnif', + 'Idak', + 'Rosita', + 'Asaita', + 'Byala Slatina', + 'Madira', + 'Volendam', + 'Sidi Lmokhtar', + 'Amalfi', + 'Kittanapalli', + 'Muradpur', + 'Hazel Dell', + 'Velizy-Villacoublay', + 'Ambriz', + 'Feira Grande', + 'Nakur', + 'Bulle', + 'Anthem', + 'The Crossings', + 'Candler-McAfee', + 'Kluczbork', + 'Kapolei', + 'Allison Park', + 'Jarqo`rg`on', + 'Litvinov', + 'North Plainfield', + 'Goldasht', + 'Inhapim', + 'Burg', + 'Dalan', + 'Shaomi', + 'Candelaria de La Frontera', + 'Patharia', + 'Beixingzhuang', + 'Andoany', + 'Mallasamudram', + 'Tequixquiac', + 'Tassin-la-Demi-Lune', + 'Lucala', + 'Moirang', + 'Dip', + 'Oytal', + 'Laguna de Duero', + 'Kitajima', + 'Mullingar', + 'Khaw Zar Chaung Wa', + 'Moncagua', + 'Llaillay', + 'Cudahy', + 'Nanyangcun', + 'East San Gabriel', + 'Lefkada', + 'Bagula', + 'Wednesfield', + 'Prieto Diaz', + 'Stadthagen', + 'Pullappalli', + 'Okahandja', + 'Royken', + 'Zedelgem', + 'Olindina', + 'Areia', + 'Besikduzu', + 'Valasske Mezirici', + 'Chincholi', + 'Fucecchio', + 'Manimala', + 'Morombe', + 'Oltenita', + 'Manzanares', + 'Baraki Barak', + 'Budingen', + 'Sevres', + 'Andorra la Vella', + 'Tocantinopolis', + 'Santa Fe de Antioquia', + 'Timmapur', + 'Fairhope', + 'Montigny-les-Cormeilles', + 'Lajas', + 'Savanna-la-Mar', + 'Hirpardangal', + 'Manki', + 'Abbeville', + 'Fleurus', + 'Farsley', + 'Parabcan', + 'Bouzeghaia', + 'Bonney Lake', + 'Warrenton', + 'Yahualica de Gonzalez Gallo', + 'Valmiera', + 'Furukawa', + 'Dawmat al Jandal', + 'Sardinata', + 'Strakonice', + 'Camacan', + 'Cholavandan', + 'Senador Jose Porfirio', + 'Oshwe', + 'Boriziny', + 'Los Llanos', + 'El Amria', + 'Talayolaparambu', + 'Uenohara', + 'Isperih', + 'Haar', + 'Summit', + 'Souk Tlet El Gharb', + 'Belabo', + 'Raman Mandi', + 'East Peoria', + 'Pokhuria', + 'Letterkenny', + 'Sinjar', + 'Florida Ridge', + 'Tlacolula de Matamoros', + 'Mentana', + 'Vengattur', + 'Kenilworth', + 'Horizon City', + 'Lempaala', + 'Potters Bar', + 'Kafr Batna', + 'Medjez el Bab', + 'Melila', + 'Metzingen', + 'Bobleshwar', + 'Meiwa', + 'Huautla', + 'Katangi', + 'Golhisar', + 'Sarangani', + 'Sabana de Torres', + 'Jogipet', + 'Melchor Romero', + 'Hulikal', + 'Deuil-la-Barre', + 'Mutata', + 'Nadvirna', + 'Corinth', + 'Bafata', + 'Ouani', + 'Kafr Sa`d', + 'Vilcun', + 'Zabrat', + 'Klatovy', + 'Coracao de Maria', + 'Challans', + 'Coralville', + 'San Antonio La Paz', + 'Willowbrook', + 'San Pablo Jocopilas', + 'Lazi', + 'La Madeleine', + 'Ivatsevichy', + 'Nkowakowa', + 'Chavassheri', + 'Foleshill', + 'Mount Pearl Park', + 'Piddig', + 'Yuli', + 'Chatayamangalam', + 'San Juan de Aznalfarache', + 'Emiliano Zapata', + 'Mouila', + 'Kondazhi', + 'Karnobat', + 'Cacule', + 'Baclayon', + 'Ladyzhyn', + 'Buriti Bravo', + 'Puente Nacional', + 'Gan Yavne', + 'Pullanpallikonam', + 'Naawan', + 'Torcy', + 'Esparraguera', + 'Mihama', + 'Biddeford', + 'Aymangala', + 'Moyo', + 'Albertville', + 'Pirajui', + 'Donaueschingen', + 'Naciria', + 'Ottobrunn', + 'Rancho San Diego', + 'Finnkolo', + 'Sarea Khas', + 'Junnardev', + 'Goulburn', + 'Sibut', + 'Formby', + 'Fenyuan', + 'Sipilou', + 'Maying', + 'Kasamatsucho', + 'Jebba', + 'Betsizaraina', + 'Pudsey', + 'Rixensart', + 'Kiboga', + 'Zhengtun', + 'Zurbatiyah', + 'Gujan-Mestras', + 'Macas', + 'Bermo', + 'Quissama', + 'Barreira', + 'Freire', + 'Szczytno', + 'Taishituncun', + 'Sevlievo', + 'Gonghe', + 'Hartbeespoort', + 'Kato Polemidia', + 'Mechta Ouled Oulha', + 'Lindsay', + 'Ibatiba', + 'Perundurai', + 'Montville', + 'Arouca', + 'Central Falls', + 'Rumphi', + 'Ivrea', + 'Bad Rappenau', + 'Saint-Lazare', + "Arbi'a Tighadwiyn", + 'Diriomo', + 'Gif-sur-Yvette', + "Sek'ot'a", + 'Sabuncu', + 'Cedro', + 'Waynesboro', + 'Loei', + 'Gurmatkal', + 'Carouge', + 'Lyndhurst', + 'Gilan-e Gharb', + 'Kadiria', + 'Sambhar', + 'El Tortuguero', + 'Guerou', + 'Taulaha', + 'Natagaima', + 'Bhawanigarh', + 'Ceccano', + 'Acworth', + 'Owen Sound', + 'Lyman', + 'Frauenfeld', + 'Chinameca', + 'Daxin', + 'DeBary', + 'Panniyannur', + 'El Doncello', + 'Prantij', + 'Gornji Vakuf', + 'Guia de Isora', + 'Bundibugyo', + 'Qorako`l Shahri', + 'Lochristi', + 'Piuma', + 'Phichit', + 'Montilla', + 'March', + 'Rosiori de Vede', + 'Pozega', + 'Brockville', + 'Tiverton', + 'Braine-le-Comte', + 'Laja', + 'Cayo Mambi', + 'Sanso', + 'Digor', + 'Pale', + 'Ruston', + 'Brushy Creek', + 'Bartoszyce', + 'Valenca do Piaui', + 'Monte Aprazivel', + 'Cisnadie', + 'Had Sahary', + 'Oyonnax', + 'Zhucaoying', + 'Maracena', + 'Shoeburyness', + 'Versmold', + 'Chankou', + 'Yokoshibahikari', + 'Lordelo do Ouro', + 'Palaw', + 'Ugong', + 'Palmer', + 'Tiruttangal', + 'Senekane', + 'Hillside', + 'Telsiai', + 'Edegem', + 'Aljaraque', + 'Montereau-faut-Yonne', + 'Mountain Brook', + 'Nagla', + 'Ankireddikuntapalem', + 'Bhatpuri', + 'Chausa', + 'Marina', + 'Singampunari', + 'Itsukaichi', + 'El Hermel', + 'Karacoban', + 'Athiringal', + 'Tervuren', + 'El Colegio', + 'Kihei', + 'Silvania', + 'Souahlia', + 'Alangayam', + 'Bahce', + 'Litherland', + 'Takahata', + 'Koziatyn', + 'Kheiredine', + 'Combs-la-Ville', + 'West Carson', + 'Bignona', + 'Picasent', + 'Huangzhai', + 'Yeadon', + 'Silver Firs', + 'Ibia', + 'Yahualica', + 'Kundgol', + 'Sao Filipe', + 'Sokolov', + 'Herouville-Saint-Clair', + 'Eppingen', + 'Ingabu', + 'Metekora', + 'Radevormwald', + 'Murayama', + 'Sharunah', + 'Swiebodzice', + "Saint John's", + 'Dasnapur', + 'Poggiomarino', + 'Acomb', + 'Abu Sir Bana', + 'Khorabar', + 'Bahia de Caraquez', + 'Ortona', + 'Topola', + 'Tiruverumbur', + 'Ilsede', + 'Zirapur', + 'Sunny Isles Beach', + 'Samtredia', + 'Tirat Karmel', + 'West Deptford', + 'Hillegom', + 'Rioja', + 'Guazacapan', + 'Soroca', + 'Repelon', + 'Medeiros Neto', + 'Adalhat', + 'Yavuzeli', + 'Chalmette', + "'s-Gravenzande", + 'Surdulica', + 'Sandomierz', + 'McNair', + 'Kondalampatti', + 'Phularwan', + 'Pattiyurgramam', + 'Las Torres de Cotillas', + 'Haderslev', + 'Gubbi', + 'Shabestar', + 'Granite Bay', + 'Gumushacikoy', + 'Kilkenny', + 'Bakhri', + 'Maribojoc', + 'Yabu', + 'Nova Zagora', + 'Sulmona', + 'Guabo', + 'Qarazhal', + 'Goleniow', + 'Mbaiki', + 'Jiangdi', + 'Chestermere', + 'Les Pennes-Mirabeau', + 'Salvaterra de Magos', + 'Batad', + 'Vellithiruthi', + 'Paraguari', + 'Takelsa', + 'Ghriss', + 'Sarapaka', + 'Aleksandrow Lodzki', + "Sant'Arcangelo di Romagna", + 'Ensley', + 'Vayalar', + 'Katkol', + 'Bhanvad', + 'Golden Valley', + 'West Rancho Dominguez', + 'Ban Pa Tueng', + 'World Golf Village', + 'Pirmed', + 'Waldkirch', + 'Reigate', + 'Lower', + 'Phetchabun', + 'Pingtan', + 'Bourkika', + 'Ramona', + 'Fantino', + 'Bellavista', + 'Sahil', + 'Tabursuq', + 'Talwandi Sabo', + 'Heide', + 'Livadeia', + 'Salemata', + 'Krolevets', + 'Qapqal', + 'Cunha', + 'Namayumba', + 'Caojiachuan', + 'Doutou', + 'La Cruz', + 'Palmital', + 'Hallim', + 'Smithfield', + 'Argos', + 'Peravurani', + 'Huejucar', + 'Pailitas', + 'Penarth', + 'Howli', + 'Ocatlan', + 'Muelle de los Bueyes', + 'Husnabad', + 'Hoogezand', + 'Vilnohirsk', + 'Taixi', + 'Timbiqui', + 'Horley', + 'Newquay', + 'Camborne', + 'West Puente Valley', + 'Kalchini', + 'Estcourt', + 'Eschborn', + 'Karlsfeld', + 'Yorosso', + 'Qift', + 'Palestrina', + 'Schwetzingen', + 'Imbert', + 'Parsagarhi', + 'Hamidiyeh', + 'Gardelegen', + 'Adampur', + 'Chhanera', + 'Itaiopolis', + 'Madamba', + 'Lorton', + 'Rimavska Sobota', + 'Polygyros', + 'Kalyves Polygyrou', + 'Northwood', + 'Aswapuram', + 'Khandela', + 'Karaisali', + 'Tiquisio', + 'Dongta', + 'Mondovi', + 'East Ridge', + 'Carbondale', + 'Ruwa', + 'Jizhuang', + 'Sapulpa', + 'Banbishancun', + 'Woensdrecht', + 'Jawad', + 'Naregal', + 'Dubnica nad Vahom', + 'Elsdorf', + 'Corail', + 'Dioumanzana', + 'Anini-y', + 'Taveta', + 'Comacchio', + 'Meixedo', + 'Ostrow Mazowiecka', + 'Tola', + 'Greystones', + 'Uliastay', + 'Paese', + 'Priego de Cordoba', + 'Chillicothe', + 'Epernay', + 'Jugial', + 'Ghat', + 'Manakambahiny', + 'Ambodimotso Atsimo', + 'Ampasimanjeva', + 'Iarintsena', + 'Andranovorivato', + 'Bemanonga', + 'Vohimasina', + 'Andilanatoby', + 'Alakamisy-Ambohimaha', + 'Ambalaroka', + 'Jafaro', + 'Ankiabe-Salohy', + 'Antsakabary', + 'Uch Sharif', + 'Lebane', + 'Huskvarna', + 'Kigumba', + 'Haci Zeynalabdin', + 'Aoshang', + 'Atherton', + 'Clevedon', + 'Bukkarayasamudram', + 'Machagai', + 'Unchahra', + 'God', + 'Zundert', + 'Dras', + 'Gavimane', + 'Taminango', + 'Bilthoven', + 'Al Bahah', + 'Pitrufquen', + 'Nema', + 'Pinhalzinho', + 'Khosrowshahr', + 'Ampanotokana', + 'Iracemapolis', + 'San Rafael del Yuma', + 'Djinet', + 'Robbah', + 'Arroio do Meio', + 'Kuppam', + 'Koekelberg', + 'Vertentes', + 'Koksijde', + 'Dudelange', + 'Villa de Leyva', + 'Darien', + 'Serro', + 'Valinda', + 'Glauchau', + 'Chakia', + 'Pocharam', + 'Diamantino', + 'Mundamala', + 'New Hartford', + 'Ramantali', + 'Harim', + 'Ap Phu My', + 'Robertson', + 'Tornio', + 'Nakagusuku', + 'Samba Cango', + 'Mazagao', + 'Chambersburg', + 'Sandbach', + 'Chalchihuitan', + 'Axapusco', + 'Itubera', + 'Nerja', + 'Mako', + 'Gotsucho', + 'St. Andrews', + 'Aichach', + 'Al Fuhays', + 'Krathum Baen', + 'Pascagoula', + 'Pak Tin Pa', + 'Bungotakada', + 'Membakut', + 'Sao Miguel do Araguaia', + 'Sayada', + 'Kachhari', + 'Darreh Shahr', + 'Beguedo', + 'Sao Francisco de Paula', + 'Lom', + 'Muzambinho', + 'Vanthli', + 'Kueneng', + 'Povoa de Lanhoso', + 'Pio XII', + 'Caranavi', + 'Alfafar', + 'Frameries', + 'North Salt Lake', + 'Almoradi', + 'Shinhidaka', + 'Montmorency', + 'Maghalleen', + 'Karlovo', + 'New Castle', + 'Sonthofen', + 'Sainte-Foy-les-Lyon', + 'Montigny-les-Metz', + 'Renfrew', + 'Komlo', + 'Florsheim', + 'Gigaquit', + 'Binnish', + 'Tongzhou', + 'Kafr Qasim', + 'Port Hueneme', + 'Rajauli', + 'Massapequa', + 'Mata Grande', + 'Lihuzhuang', + 'Mbandjok', + 'Otsuki', + 'Kocarli', + 'Los Palmitos', + 'Muhlenberg', + 'Machico', + 'Kepsut', + 'Mangalvedha', + 'Yoshioka', + 'Santa Teresa', + 'Danwan', + 'Puttige', + 'Belper', + 'Soyagaon', + 'Columbia Heights', + 'Hayesville', + 'Horad Smalyavichy', + 'Kizhakkemanad', + 'Ginosa', + 'Sheldon', + 'Mehnatobod', + 'De Meern', + 'Ginebra', + 'Azambuja', + 'Ouardenine', + "Ma'muniyeh", + 'Pallippuram', + 'Amtali', + 'Orobo', + 'Soltau', + 'Pueblo Juarez', + 'Amposta', + 'Muzhakkunnu', + 'Parsippany', + 'Klamath Falls', + 'Kreuzlingen', + 'Plonsk', + 'Looc', + 'Manor', + 'Palmas de Monte Alto', + 'Poco Verde', + 'Siilinjarvi', + 'Santa Lucia Utatlan', + 'Yate', + 'Morinda', + 'Polkowice', + 'Charo', + 'Ad Dabyah', + 'Ad Dali`', + 'Le Petit-Quevilly', + 'Jaynagar', + 'Puruk Cahu', + 'Tuneri', + 'Had Oulad Issa', + 'Ambatomanoina', + 'Hassi Maameche', + 'Langley Park', + 'Silverdale', + 'Sidi Amrane', + 'Surpur', + 'Bhanpura', + 'Gulsehir', + 'Geertruidenberg', + 'El Callao', + 'Chatra Gobraura', + 'Kayanza', + 'Sedalia', + 'Maniche', + 'Mailavaram', + 'Selden', + 'Seia', + 'South Euclid', + 'Zara', + 'Otopeni', + 'Notteroy', + 'Penonome', + 'Oberwingert', + 'Shendurjana', + 'Cagwait', + 'Sarai Ranjan', + 'Chapa de Mota', + 'Puerto Triunfo', + 'Eislingen', + 'Hockenheim', + 'Banapur', + 'Zoersel', + 'Guipos', + 'Bad Harzburg', + 'Chimore', + 'Anamalais', + 'Shanywathit', + 'Sori', + 'Kurikka', + 'Kalleribhagam', + 'Massarosa', + 'Vamanapuram', + 'Miguelopolis', + 'Comalapa', + 'Zabre', + 'Mezdra', + 'Yaojiazhuangcun', + 'Yaojiafen', + "Erval d'Oeste", + 'Idukki', + 'Tixtla de Guerrero', + 'Vendram', + 'Moulares', + 'Wadenswil', + 'Bankoumana', + 'Caransebes', + 'Pachino', + 'Sao Joao da Madeira', + 'Alhandra', + 'Millau', + 'Shelby', + 'Guapiacu', + 'Port Alberni', + 'Kozakai-cho', + 'Pampierstad', + 'Tidili Masfiywat', + 'Chagallu', + 'Sombrerete', + 'Springwater', + 'Eyl', + 'Saint-Jean-de-Braye', + 'Biggleswade', + 'Yucca Valley', + 'Chaumont', + 'Millburn', + 'Assare', + 'Muhldorf', + 'Paramirim', + 'Kavak', + 'Qadirganj', + 'Duarte', + 'Geseke', + 'Bad Krozingen', + 'Kadiapattanam', + 'Can-Avid', + 'Del City', + 'Pampur', + 'Al Karak', + 'Sirat', + 'Ocotlan de Morelos', + 'Tigbao', + 'San Luis Talpa', + 'Gallup', + 'Kangal', + 'Koprivnice', + 'American Canyon', + 'Senda', + 'Zantiebougou', + 'Ibicarai', + 'Lindlar', + 'Bailleston', + 'Gros Islet', + 'Nangavaram', + 'Kobilo', + 'Gokcebey', + 'Nefta', + 'Himora', + 'Papanasam', + 'Lohuti', + 'Jaipur Chuhar', + 'Anuppur', + 'Kanke', + 'Sarzana', + 'Lentini', + 'Ayamonte', + 'Raja Pakar', + 'Tiruvankod', + 'Okuchi-shinohara', + 'Riachao das Neves', + 'Kumla', + 'Howick', + 'Iisalmi', + 'Tlaltenango de Sanchez Roman', + 'Sao Miguel do Guapore', + 'Mercato San Severino', + 'Herent', + 'Orzesze', + 'Villeneuve-sur-Lot', + 'Pushkar', + 'Zarnesti', + 'Mashiko', + 'New Hope', + 'Novopokrovka', + 'Sidi Ifni', + 'Fukagawa', + 'Sainte-Suzanne', + 'Scugog', + 'Bela Vista', + 'Jiuru', + 'Nueva Granada', + 'Nerupperichchal', + 'Lakato', + 'Amarpatan', + 'Savigliano', + 'Xinzhai', + 'Paraguacu', + 'Vicente Noble', + 'Tamgrout', + 'Isla-Cristina', + 'Alliance', + 'G`azalkent', + 'Ashtarak', + 'Cuilapan de Guerrero', + 'Chapala', + 'Senaki', + 'Seynod', + "M'Chedallah", + 'Laziska Gorne', + 'Rosario de Lerma', + 'Alcala la Real', + 'Unity', + 'Bougado', + "Qal'acha", + 'Spremberg', + 'Ibiruba', + 'Marti', + 'Xanten', + 'MacArthur', + 'Salcaja', + 'Chilca', + 'Mandapam', + 'Pergine Valsugana', + 'Selouane', + 'Tukwila', + 'Elverum', + 'Seligenstadt', + 'Pakala', + 'Mandelieu-la-Napoule', + 'Rancheria Payau', + 'Santa Teresita', + 'Arcueil', + 'Kalpakathukonam', + 'Stadtallendorf', + 'Fulshear', + 'Rocky River', + 'Beni Douala', + "Colle di Val d'Elsa", + 'Pancas', + 'Galeras', + 'Mililani Mauka', + 'Cabucgayan', + 'Naranammalpuram', + 'Kontela', + 'Guimar', + 'Corciano', + 'Stowmarket', + 'Acatic', + 'Naqadah', + 'Thebes', + 'Payson', + 'Nong Bua Lamphu', + 'Lino Lakes', + 'Wexford', + 'Sermadevi', + 'Ladario', + 'Zerbst', + 'Dean Funes', + 'Cardito', + 'San Martin de las Piramides', + 'Caombo', + 'Goroka', + 'Villagarzon', + 'Eckernforde', + 'Ano Syros', + 'Chebli', + 'Bastos', + 'Aarau', + 'Alnavar', + 'Whyalla', + 'Celina', + 'Parelhas', + 'Hazebrouck', + 'Boquira', + 'North Guwahati', + 'Muthutala', + 'Tanki Leendert', + "Alta Floresta D'Oeste", + 'Holiday', + 'Jawor', + 'Nang Rong', + 'Allauch', + 'Artemida', + 'Gunzburg', + 'Harvey', + 'Chesham', + 'Puerto Natales', + 'Rees', + 'Trezzano sul Naviglio', + 'Takaba', + 'Aspe', + 'Kodikuthi', + 'Secaucus', + 'Mons-en-Baroeul', + 'Ambohitromby', + 'Hojambaz', + 'Gokdepe', + 'Fort St. John', + 'Madakasira', + 'Juli', + 'Kotli', + 'El Paujil', + 'Llorente', + 'Ozark', + 'Sihu', + 'Loncoche', + 'Beni Mered', + 'Ganapavaram', + 'Laventille', + 'Paramonga', + 'Senador Guiomard', + 'Qalansuwa', + 'East Patchogue', + 'Riehen', + "Tong'anyi", + 'Paravai', + 'Pendurti', + 'Rio Rico', + 'Osterode', + 'Bariarpur', + 'Amizmiz', + 'Waghausel', + 'Bogande', + 'Nhamunda', + 'Volnovakha', + 'Partizanske', + 'Thenia', + 'Fleury-les-Aubrais', + 'Saint-Michel-sur-Orge', + 'Jekabpils', + 'Chandlers Ford', + 'Tambau', + 'Andippatti', + 'Egil', + 'Maruturu', + 'Icapui', + 'Zossen', + 'Panagyurishte', + 'Shahbazpur', + 'Wilmot', + 'Hoogstraten', + 'Noamundi', + 'Merefa', + 'Sao Joao do Piaui', + 'Urucuca', + 'Ghanzi', + 'Puchheim', + 'Four Square Mile', + 'San Bonifacio', + 'Kutna Hora', + 'Taurage', + 'Lioua', + 'Neuilly-Plaisance', + 'Pefki', + 'Srivaikuntam', + 'Jandaia do Sul', + 'Alejandro Korn', + 'Bayi', + 'Kant', + 'Swiedbodzin', + 'Cumaral', + 'Grajewo', + 'Pamarru', + 'Shirhatti', + 'Naas', + 'Annecy-le-Vieux', + 'Inopacan', + 'Khowai', + 'Mohiuddinnagar', + 'Perdoes', + 'Afourar', + 'Los Vilos', + 'Nogent-sur-Oise', + 'Singur', + 'Kirkintilloch', + 'Gummudipundi', + 'Nedre Eiker', + 'Allende', + 'Masis', + 'Mantes-la-Ville', + 'Teteven', + 'Almaguer', + 'Palma di Montechiaro', + 'Pleasant Prairie', + 'Seymour', + 'Igreja Nova', + 'Senago', + 'Fortin de las Flores', + 'Acheres', + 'Bilohorodka', + 'Mukilteo', + 'Ambinanindrano', + 'Fukuyoshi', + 'Westborough', + 'Iguai', + 'Stange', + 'Bornem', + 'Silva Jardim', + 'Vecses', + 'Hafshejan', + 'Galugah', + 'Zambrow', + 'Tiruppuvanam', + 'Mountlake Terrace', + "Mi'eso", + 'Metahara', + 'Mundgod', + 'Dax', + 'South Lake Tahoe', + 'Hammanskraal', + 'Darton', + 'Kasumpti', + 'Padmanabhapuram', + 'Doaba', + 'Pambadi', + 'Lindenwold', + 'Vicksburg', + 'Moorestown', + 'San Antonio de Areco', + 'Somers', + 'Ulus', + 'Antilla', + 'Terrier Rouge', + 'Oum Drou', + 'Mragowo', + 'Sriperumbudur', + 'Sukhodilsk', + 'Youganning', + 'Yegainnyin', + 'Alcudia', + 'Mit Nama', + 'Winter Gardens', + 'Sondershausen', + 'Kelkit', + 'Tubbergen', + 'Armidale', + 'Sao Joao', + 'Aralik', + 'Aiud', + 'Nirmali', + 'Narippatta', + 'Wang Nam Yen', + 'Makulubita', + 'Artashat', + 'Akonolinga', + 'Casal di Principe', + 'Kaduturutti', + 'Huy', + 'Kaikalur', + 'Cacem', + 'Chagalamarri', + 'Krus na Ligas', + 'South Holland', + 'Sulphur', + 'Sevilimedu', + 'Royton', + 'Dolton', + 'Clemmons', + 'Mansourah', + 'Perry', + 'Kitcharao', + 'Carthage', + 'Gauting', + 'Mabitac', + 'Belovodskoe', + 'Yorkville', + 'Pajara', + 'Wielun', + 'Linamon', + 'Mossaka', + 'Nowa Ruda', + 'Agropoli', + 'Vialonga', + 'Almasi', + 'Dronfield', + 'Oshoba', + 'Iruttarakonam', + 'Rolante', + 'Traunstein', + 'Namagiripettai', + 'Sulejowek', + 'West Pensacola', + 'Tapalpa', + 'Asni', + 'Koduvilarpatti', + 'Carrboro', + 'Ntcheu', + 'Sanxing', + 'Suwanee', + 'Aguadas', + 'Manuel Tames', + 'Lealman', + 'Bhairi', + 'Ossett', + 'Montecristo', + 'Urk', + 'Narkher', + 'Degollado', + 'Tadikombu', + 'Fierenana', + 'Dupax del Sur', + 'Sao Sepe', + 'Pillaiyarkuppam', + 'Bobonong', + 'Kosgi', + 'Zonhoven', + 'Concepcion Huista', + 'Jiangjiadong', + 'Kontich', + 'Parasi', + 'Matsuura', + 'Rose Hill', + 'Obock', + 'Tabount', + 'Varennes', + 'Lucelia', + 'Chorwad', + 'Ratu', + 'Saint-Mande', + 'Milwaukie', + 'Caapora', + 'Rio Maior', + 'Valle Nacional', + "Qia'erbagecun", + 'Nagamangala', + 'Borgomanero', + 'Boca da Mata', + 'Rupauli', + "Sal'a", + 'Vryburg', + 'Floridia', + 'Hyde Park', + 'Shazand', + 'Belonia', + 'Gardanne', + 'Lathi', + 'Manlleu', + 'Varadero', + 'Tiburon', + 'Penzance', + 'Sarari', + 'Tinja', + 'Guasipati', + 'Khromtau', + 'Varkaus', + 'Wildeshausen', + 'Hallein', + 'Allschwil', + 'Morasar', + 'Maracacume', + 'Hancha', + 'Sapone', + 'Irakleia', + 'Kanmaki', + 'Bayou Cane', + 'Loyola Heights', + 'Kannanendal', + 'Quirima', + 'Saurh', + 'Cortona', + 'Kagizman', + 'Forbach', + 'Villeneuve-le-Roi', + 'Aguinaldo', + 'Cartaya', + 'Skegness', + 'Carlos Casares', + 'Schramberg', + 'Raksaha', + 'Adigaratti', + 'Enkoping', + 'Shark', + 'Suaza', + 'Kokofata', + 'Adet', + 'San Juan de Rio Coco', + 'Princesa Isabel', + 'Foley', + 'Wipperfurth', + 'Irukanni', + 'Hays', + 'Martellago', + 'Tullahoma', + 'Amodei', + 'Banki', + 'Conceicao de Macabu', + 'Molde', + 'Chocaman', + 'Traunreut', + 'Altepexi', + 'Wulfrath', + 'Germersheim', + 'Tehata', + 'Gorgonzola', + 'El Pinar', + 'San Isidro de Lules', + 'Oued el Aneb', + 'Itapaci', + 'Sadao', + 'Tizi-n-Bechar', + 'Sao Marcos', + 'Seria', + 'Chopinzinho', + 'Xoxocotla', + 'Furano', + 'Harstad', + 'North Bellmore', + 'Paiganapalli', + 'Sondrio', + 'Orhei', + 'Injibara', + 'North Ogden', + "Imi n'Oulaoun", + 'Xinnongcun', + 'Palmeiras', + 'Behat', + 'Caxambu', + 'Paulistana', + 'San Juan de Vilasar', + 'Makakilo', + 'Saint Austell', + 'Laje', + 'Chinchali', + 'Villapinzon', + 'Palafrugell', + 'Jangy-Nookat', + 'Ukmerge', + 'Saka', + "Saint Paul's Bay", + 'Joaquin V. Gonzalez', + 'South Whitehall', + 'Itambacuri', + 'Park Forest', + 'Nubl', + 'Oro-Medonte', + 'Jozefow', + 'Praia da Vitoria', + 'Mirador', + 'Caterham', + 'Porto Torres', + 'Wade Hampton', + 'Sao Jeronimo', + 'Gross-Umstadt', + 'Phalia', + 'Zulpich', + 'Patpara', + 'Ariano Irpino', + 'Stephenville', + 'Klaukkala', + 'San Jose de Jachal', + 'Az Zuwaytinah', + 'Timmarasanayakkanur', + 'Woodlesford', + 'Nordlingen', + 'San Victor Abajo', + 'Fatehgarh Churian', + 'Manjhi', + 'Tanhacu', + 'Samba', + 'Willmar', + 'Stratton Saint Margaret', + 'Alto-Cuilo', + 'Cuilo', + 'Daddi', + 'Mangghystau', + 'Merrick', + 'Cranendonck', + 'Sremcica', + 'Nurota', + 'Morafeno', + 'Sitampiky', + 'Ambalavato', + 'Tongobory', + 'Tsarasaotra', + 'Ambohipandrano', + 'Andolofotsy', + 'Soanindrariny', + 'Ankililoaka', + 'Tsiamalao', + 'Fiadanana', + 'Antanambao', + 'Sahamadio', + 'Miorimivalana', + 'Ambohimanambola', + 'Ampasimatera', + 'Karianga', + 'Matanga', + 'La Colonia Tovar', + 'Fengjia', + 'Dabaozi', + 'Sancoale', + 'Kudal', + 'Anah', + 'Mandza', + 'Sidi Lahssen', + 'Tufanganj', + 'Torqabeh', + 'Fredonia', + 'San Antonio Sacatepequez', + 'Vadakkum', + 'Walia', + 'Laranjeira', + 'Cassilandia', + 'Sokal', + 'Capela do Alto', + 'Agan', + 'Itapecerica', + "Welench'iti", + 'Daboh', + 'Nizampatam', + 'El Reten', + 'Suzzara', + 'Osmaneli', + 'Zele', + 'Fot', + 'Santa Vitoria', + 'Baiheqiao', + 'Thuan An', + "Saint-Cyr-l'Ecole", + 'Bugalagrande', + 'Ankaraobato', + 'Hualqui', + 'Upper St. Clair', + 'Caracarai', + 'Carmo do Rio Claro', + 'Mont-Royal', + 'Pacatu', + 'Coreau', + 'Hirekerur', + 'Quela', + 'Purranque', + 'Mineola', + 'San Cataldo', + 'Vladicin Han', + 'East Moline', + 'East Pennsboro', + 'Green Valley', + 'Ondorhaan', + 'Chaudfontaine', + 'Cuncolim', + 'Piedra Blanca', + 'Torrox', + 'Damua', + 'Punturin', + 'Saint-Genis-Laval', + 'Renens', + 'Nambiyur', + 'Cho Phuoc Hai', + 'Alagoa Nova', + 'Concepcion Chiquirichapa', + 'Urussanga', + 'Fort Walton Beach', + 'Argenta', + 'Five Corners', + 'San Guillermo', + 'Vili', + 'Leskovac', + 'Aisho', + 'Guara', + 'Jericho', + 'Bni Rzine', + 'Little Egg Harbor', + 'Mossingen', + 'Esperalvillo', + 'Vakkam', + 'Lucani', + 'Pudupattanam', + 'Kamamaung', + 'Snellville', + 'Herborn', + 'Voiron', + 'Eeklo', + 'Monte Santo de Minas', + 'Pico Truncado', + 'Battle Ground', + 'Texistepec', + 'Liubotyn', + 'Balugan', + 'Brummen', + 'Ludlow', + 'Murphy', + 'Koath', + 'Quixere', + 'Ambohimanga', + 'Normanton', + 'Mulanje', + 'Sint-Katelijne-Waver', + 'Palavur', + 'Murree', + 'Zaliohouan', + 'Kyaukpyu', + 'Saint-Gratien', + 'Sotomayor', + 'Sanchez', + 'Bordj Bounaama', + 'Bambalang', + 'Mudakkal', + 'Kara-Suu', + 'Aurad', + 'Luisiana', + 'Showa', + 'El Gara', + 'Oliveira do Hospital', + 'Sidi Abdelkader', + 'Birkerod', + 'Beni Haoua', + 'Hyattsville', + 'Amdjarass', + 'Wallington', + 'Hindang', + 'Pogradec', + 'Moniquira', + 'Ovejas', + 'Vinany', + 'Wettingen', + 'Cercado Abajo', + 'Letlhakane', + 'Musselburgh', + 'Harohalli', + 'Luckenwalde', + "Debark'", + 'Imi-n-Tanout', + 'Paldorak', + 'Wasquehal', + 'Lajinha', + 'Junqueiropolis', + 'Halluin', + 'Jindrichuv Hradec', + 'Bruchkobel', + 'Conselheiro Pena', + 'Castrovillari', + 'West St. Paul', + 'Murrysville', + 'Buckingham', + 'Karmana', + 'Sao Jose da Laje', + 'Miches', + 'Meinerzhagen', + 'Bhainsdehi', + 'Sonagazi', + 'Bourg-la-Reine', + 'Beroun', + 'Stadtlohn', + 'Devirammanahalli', + 'Mariani', + 'Grayslake', + 'Malaba', + 'Chelak', + 'Ararat', + 'Conceicao da Feira', + 'Valkeakoski', + 'Banting', + 'Schortens', + 'Mill Creek', + 'Ambondro', + 'Alta', + 'Derinkuyu', + 'Ibicoara', + 'Morsang-sur-Orge', + 'Peringanad', + 'Cordeiro', + 'Veresegyhaz', + 'Coolbaugh', + 'Croix', + 'Jicome', + 'Carcagente', + 'Wittmund', + 'Sestu', + 'Bronkhorstspruit', + 'Leek', + 'Samaca', + 'Algete', + 'Horstel', + 'Gavarr', + 'Coudekerque-Branche', + 'Barhampur', + 'Bulnes', + 'Colfontaine', + 'Ul', + 'Oliveira de Azemeis', + 'Palkonda', + 'Puduppalli Kunnam', + 'Yermal', + 'Luacano', + 'Sivasli', + 'Illapel', + 'Valljkkod', + 'Ino', + 'Bryant', + 'Banganapalle', + 'Kuknur', + 'Sivrihisar', + 'Narwar', + 'Bandar-e Gaz', + 'Mathukumnel', + 'Leigh-on-Sea', + 'Castel San Pietro Terme', + 'Sonbarsa', + 'Tittagudi', + 'Anagni', + 'Puzol', + 'Le Creusot', + 'Monsummano', + 'Zhangatas', + 'Hanahan', + 'Iriona', + 'Hexiang', + 'Gannavaram', + 'St. John', + 'Kiseljak', + 'Achampet', + 'Mohammadabad', + 'Boscombe', + 'Palestina de los Altos', + 'Beruri', + 'Arnaud', + 'Oliveira dos Brejinhos', + 'Hanmayingcun', + 'Goodlands', + 'Lebedinovka', + 'Elvas', + 'Parma Heights', + 'Enger', + 'Menaka', + "Vranov nad Topl'ou", + 'Werdau', + 'Llandudno', + 'Guaratinga', + 'Nidderau', + 'Kolaras', + 'Mae Sai', + 'Campestre', + 'Monte Azul', + 'Ati', + "Olho d'Agua das Flores", + 'Chithara', + 'Ozoir-la-Ferriere', + 'Dolyna', + 'Montecatini Terme', + 'Sao Joao de Pirabas', + 'Palma del Rio', + 'Baroda', + 'San Julian', + 'Lennox', + 'Baie-Comeau', + 'Mantsala', + 'Soye', + 'Bussolengo', + 'Pozanti', + 'Failsworth', + 'Recanati', + 'Cornaredo', + 'South Milwaukee', + 'Kremenets', + 'Kirkstall', + 'Marquette', + 'Wuustwezel', + 'Steinhagen', + 'Dzialdowo', + 'Profesor Salvador Mazza', + 'Bozoum', + 'Waxhaw', + 'Lomita', + 'Schwanewede', + 'Ismayilli', + 'Lagoa do Itaenga', + 'Sidi Chiker', + 'Muttatodi', + 'Givors', + 'Rosamond', + 'Fougeres', + 'As', + 'Banaue', + 'Los Llanos de Aridane', + 'Melena del Sur', + 'Bohumin', + 'Piazza Armerina', + 'Denain', + 'Vinjamur', + 'Kladovo', + 'Riacho das Almas', + 'El Hammadia', + 'Parramos', + 'Miandrivazo', + 'Lubalo', + 'Bagou', + 'Bad Waldsee', + 'Sidi Rahal', + 'Mitry-Mory', + 'Yanagawamachi-saiwaicho', + 'Sour', + 'Sarreguemines', + 'Arroyo Seco', + 'Longjumeau', + 'Chachahuantla', + 'Pahuatlan de Valle', + 'Bockum', + 'Isernia', + 'Kleppe', + 'Schifferstadt', + 'Hardi', + 'Manhumirim', + 'Na Klang', + 'Hurricane', + 'Dingolfing', + 'Concarneau', + 'Crowborough', + 'Adrian', + 'Tarnaveni', + 'Tan Phong', + 'Al Qays', + 'Botevgrad', + 'Celbridge', + 'Ghafurov', + 'Popasna', + 'Yakkabog`', + 'Sunbat', + 'Tepexi de Rodriguez', + 'Patuvilayi', + 'South St. Paul', + 'Somanya', + 'Nan', + 'Goris', + 'Manbengtang', + 'Campia Turzii', + 'Neufahrn bei Freising', + 'Jatara', + 'Kawambwa', + 'Gjovik', + 'Caravelas', + 'Nanuet', + 'Savda', + 'Kapay', + 'Wachtberg', + 'Mead Valley', + 'Nuenen', + 'Lillehammer', + 'Kekem', + 'Baza', + 'Chapulhuacan', + 'Buftea', + 'Rosolini', + 'Toktogul', + 'Palo del Colle', + 'Romano di Lombardia', + 'Hashtrud', + 'Mbala', + 'Qagan Us', + 'Foya Tangia', + 'Sa al Hajar', + 'Arhavi', + 'Pleasantville', + 'Dumbarton', + 'Lugait', + '`Adra', + 'Chintalapalle', + 'Hlohovec', + 'Modling', + 'Libertyville', + 'Jefferson', + 'Forest Lake', + 'Honnali', + 'La Resolana', + 'Frondenberg', + 'Zestaponi', + 'Shoreham-by-Sea', + 'Cha Grande', + 'Namioka', + 'Vakon', + 'Sunchales', + 'Gandujie', + 'Bati', + 'Colleferro', + 'Codlea', + 'Mazinde', + 'Laboulaye', + 'Guadalupe Nuevo', + 'Sultanhisar', + 'Carmen de Patagones', + 'Quemado de Guines', + 'Aomar', + 'Maniyamturuttu', + 'Torhout', + 'Bothell West', + 'Bladel', + 'Lami', + 'Sonkach', + 'Hernani', + 'Hythe', + 'Vadamadurai', + 'Madipakkam', + 'Chennimalai', + 'Bala', + "Zd'ar nad Sazavou", + 'Cobourg', + 'Ohara', + 'Mustang', + 'Northfield', + 'Atoyac de Alvarez', + 'Station des Essais M.V.A.', + 'Eruh', + 'Elko', + 'Coswig', + 'Colonia General Felipe Angeles', + 'Cauto Cristo', + 'Carquefou', + 'Trecate', + 'Ijevan', + 'Nishigo', + 'Bibai', + 'Banolas', + 'Baskil', + 'Horten', + 'Muhammadabad', + 'Pendembu', + 'Tielt', + 'Shimogamo', + 'Cranbrook', + 'Nellimarla', + 'Lubartow', + 'Grottaferrata', + 'Binondo', + 'Seydi', + 'Sapang Dalaga', + 'Nahorkatiya', + 'Khvansar', + 'Sceaux', + 'Stevenson Ranch', + 'Hatvan', + 'Peritoro', + 'Saint-Pol-sur-Mer', + 'Lower Southampton', + 'Posusje', + 'Becerril', + 'La Celle-Saint-Cloud', + 'Hailsham', + 'Bhojpur Kadim', + 'Uetze', + 'Kurshab', + 'Recani', + 'Dulken', + 'Nadikude', + 'Timana', + 'Mindouli', + 'Sant Just Desvern', + 'Golden', + 'Omagh', + 'Kizhattur', + 'Ain Cheggag', + 'Kawayan', + 'Otsego', + 'Bourne', + 'Costas de Cao', + 'Caparica', + 'Taslicay', + 'Muong Lay', + 'Saco', + 'Paraisopolis', + 'Puerto Quito', + 'Maghull', + 'Piqua', + 'Keevallur', + "'Ain el Bell", + 'Fara', + 'Sidi Jaber', + 'Imperial', + 'Susaki', + 'Mealhada', + 'Cinfaes', + 'Jarajus', + 'Vyskov', + 'Pak Phanang', + 'Huercal-Overa', + 'Itatira', + 'Baud', + 'Aigio', + 'Chepo', + 'Sandwich', + 'Koipadi', + 'Yasothon', + 'Lambari', + 'Joinville-le-Pont', + 'Kuala Pembuang', + 'Bouguenais', + 'Jaboticatubas', + 'Dereli', + 'Pariyaram', + 'Reggane', + "'Ain el Hammam", + 'Iztapa', + 'Hauppauge', + 'Follonica', + 'Greiz', + 'Montrose', + 'West Hempstead', + 'North Liberty', + 'Zaghouan', + 'Hassloch', + 'Old Jamestown', + 'Painesville', + 'Sandhurst', + 'Chokkampatti', + 'Beforona', + 'Kolo', + 'Longbangcun', + 'La Canada Flintridge', + 'Naraura', + 'Jaguaruna', + 'Barki Saria', + 'Ramnagar Farsahi', + 'Samboan', + 'Porto Real', + 'Reichenbach/Vogtland', + 'Alatsinainy-Bakaro', + 'Kuttampala', + 'Feltre', + 'San Pablo Tacachico', + 'Kanaya', + 'Yangping', + 'Tewkesbury', + 'Cormano', + 'Rothwell', + 'Karaiyampudur', + 'Froyland', + 'Hoyland', + 'Marblehead', + 'Sidney', + 'Kihihi', + 'Blankenberge', + 'Sartalillo', + 'Altamont', + 'Lannion', + 'Cugnaux', + 'Harpalpur', + 'Bratunac', + 'Neustrelitz', + 'Middle', + 'Yellowknife', + 'Makhtal', + 'Westbrook', + 'Mundra', + 'Tala Yfassene', + 'Huanuni', + 'North Amityville', + 'Kashkar-Kyshtak', + 'Dan Gorayo', + 'Grande-Synthe', + 'La Chapelle-sur-Erdre', + 'Trentola', + 'Santa Maria Chilchotla', + 'Chevilly-Larue', + 'Dharmkot', + 'Nesoddtangen', + 'Farashband', + 'Fangasso', + 'Farum', + 'Baihar', + 'Salmon Creek', + 'Rawicz', + 'Katakos', + 'Senta', + 'Khowrzuq', + 'Las Vigas de Ramirez', + 'Chandragiri', + 'Lynbrook', + 'Gryfino', + 'Selendi', + 'Bellshill', + 'Tobe', + 'East Northport', + 'Duderstadt', + 'San Martin De Porres', + 'Sao Felipe', + 'Marion Oaks', + 'Oroville', + 'Lalin', + 'Salgado', + 'Inirida', + 'Candido Mendes', + 'Shisui', + 'Chorozinho', + 'Nyon', + 'Teculutan', + 'Simiti', + 'Tenjo', + 'Minturno', + 'Whitpain', + 'Gopavaram', + 'Cilimli', + 'Lingolsheim', + 'Devrukh', + 'Kokopo', + 'East Hemet', + 'Pulicat', + 'Rumoi', + 'Wodonga', + 'Luperon', + 'Parkal', + 'Ely', + 'Ervalia', + 'Rovira', + 'Bad Schwartau', + 'Vico Equense', + 'Sbeitla', + 'Chodavaram', + 'Hazlet', + 'Husainpur', + "Mar''ina Horka", + 'Mosta', + 'South Burlington', + 'Blieskastel', + 'Jdour', + 'Aguas Zarcas', + 'Touna', + 'Raipura', + 'Abano Terme', + 'Palisades Park', + 'Ochtrup', + 'Samthar', + 'Asosa', + 'Belur', + 'Xionglin', + 'Telgte', + 'Pinan', + 'Edakkunnam', + 'Le Plessis-Trevise', + 'Khilchipur', + 'Lichtenfels', + 'Gyomro', + 'Kortenberg', + 'Ban Tha Pha', + 'Yaraka', + 'Lower Allen', + 'Gostyn', + 'Sessa Aurunca', + 'Le Mee-sur-Seine', + 'Chandpur', + 'Entroncamento', + 'Ypsilanti', + 'Rhenen', + 'Pennagaram', + 'Melnik', + 'Tondi', + 'Stebnyk', + 'Xo`jaobod', + 'Agsu', + 'Agstafa', + 'Mayluu-Suu', + 'Rivalta di Torino', + 'Pontassieve', + 'Pompeia', + 'Boromo', + "Cournon-d'Auvergne", + 'Uruburetama', + 'South Frontenac', + 'Douar Lamrabih', + 'Puerto Viejo', + 'Reitz', + 'Guacima', + 'Voyenno-Antonovka', + 'Skive', + 'Ripley', + 'Cruz Grande', + 'Ban Klang', + 'Blansko', + 'Taibet', + 'Polonne', + 'Seaham', + 'Talayazham', + 'Monte Alegre de Minas', + 'Abou el Hassan', + 'Peterlee', + 'Pargi', + 'Schopfheim', + 'Otegen Batyr', + 'Motatan', + 'Shafter', + 'Diondiori', + 'Sivagiri', + 'Nelkattumseval', + 'Akora', + 'Frontino', + 'Erragondapalem', + 'Aurad Shahjahani', + 'Ayaviri', + 'Pantanaw', + 'Sesheke', + 'Bhitarwar', + 'Regente Feijo', + 'Kheralu', + 'Cahors', + 'Midway', + 'Rosas', + 'Mattigiri', + 'Alblasserdam', + 'Alampalaiyam', + 'Dorchester', + 'Teonthar', + 'Arbutus', + 'Giengen an der Brenz', + 'Karukachal', + 'Aquidaba', + 'Kurten', + 'Del Carmen', + 'Toprakkale', + 'Mayfield Heights', + 'Farakka', + 'Turmalina', + 'Pujehun', + 'Belmonte', + 'Holzminden', + 'Bela', + 'Leinefelde', + 'Villa Verde', + 'Vettikkavala', + 'Riviere-du-Loup', + 'Huanimaro', + 'Senec', + 'Halewood', + 'Comrat', + 'Archena', + "Pallazzolo sull'Oglio", + 'Barkly West', + 'Nykobing Falster', + 'Culpeper', + 'Galvez', + 'Nkoteng', + 'Celorico de Basto', + 'Bilasuvar', + 'Luban', + 'Kulpahar', + 'Montalto Uffugo', + 'Buckhall', + 'Satsuma', + 'Oberkirch', + 'La Crescenta-Montrose', + 'Medina del Campo', + 'Villa Hidalgo', + 'Agoura Hills', + 'Kwinana', + 'Denderleeuw', + 'Piata', + 'Yabayo', + 'Siran', + 'Lonar', + 'Virarajendrapet', + 'Barroso', + 'Mithi', + 'Porto Real do Colegio', + 'Skanderborg', + 'Killingworth', + 'Depalpur', + 'Sidhapa', + 'Naranjos', + 'Esanboy', + 'Dhorimanna', + 'El Ancer', + 'Cabra', + 'Mahaditra', + 'Temacine', + 'Horwich', + 'Mont-Saint-Aignan', + 'Llallagua', + 'Schmalkalden', + 'Bani Murr', + 'Brezno', + 'Schroeder', + 'Rosedale', + 'Ban Wat Sala Daeng', + 'Casa de Oro-Mount Helix', + 'Nguekhokh', + 'Mesra', + 'Durbat', + 'Pita', + 'Kartikapalli', + 'Guding', + 'Diguapo', + 'Buxton', + 'Ferentino', + 'Lohur', + 'Meadowbrook', + 'Bulach', + 'Teopisca', + 'Kannod', + 'Kafr Laha', + 'Makoua', + 'Castillo de Teayo', + 'Mutuipe', + 'Sao Joaquim do Monte', + 'Tettnang', + 'Bhopatpur', + 'Yumbel', + 'Tolu Viejo', + 'Atescatempa', + 'Port Colborne', + 'Beaune', + 'Bubanza', + 'Hakui', + 'La Esmeralda', + 'Takanabe', + 'Rolla', + 'Atarfe', + 'Cittadella', + 'Howard', + 'Sidi Merouane', + 'Kissa', + 'Oderzo', + 'Jiangjiehe', + 'Dumbravita', + 'Krasnohrad', + 'Pertuis', + 'Etzatlan', + 'Calceta', + 'Presidente Getulio', + 'Kandakkadava', + 'Rio Formoso', + 'Goraya', + 'Port Angeles', + 'Tupancireta', + 'Forest Park', + 'Piove di Sacco', + 'El Ksiba', + 'Bispham', + 'Indwe', + 'Kfar Kidde', + 'El Bazouriye', + 'Ampasimena', + 'Mandrosohasina', + 'Ambalakirajy', + 'Rantabe', + 'Mandiavato', + 'Ambatosoratra', + 'Tsararafa', + 'Analapatsy', + 'Tsarabaria', + 'Soavina Antanety', + 'Bekatra Maromiandra', + 'Haka', + 'Arvayheer', + 'Kuala Lipis', + 'Opuwo', + 'Bulolo', + 'Gahi Mammar', + 'Alfena', + 'Kebemer', + 'Mikumi', + 'Muheza', + 'Sultonobod', + 'Sangin', + 'Sitrah', + 'Zemio', + 'Bamukumbit', + 'Bamumkumbit', + 'Sanjianxiang', + 'Minster', + 'Shri Mahavirji', + 'Tadas', + 'Asarganj', + 'Rankhandi', + 'Bhaluhar', + 'Mandi Bamora', + 'Bareja', + 'Sikka', + 'Munak', + 'Pirbahora', + 'Hudli', + 'Bazidpur Madhaul', + 'Suroth', + 'Sujnipur', + 'Marjampad', + 'Sohana', + 'Chimthana', + 'Mangapet', + 'Ankalgi', + 'Kothanuru', + 'Tuminkatti', + 'Naranda', + 'Sonaimukh', + 'Baragoi', + 'Ciudad Miguel Aleman', + "'Ain Mabed", + 'Comanesti', + 'Garhshankar', + 'Donauworth', + 'Vasiana', + 'Chaville', + 'Salsomaggiore Terme', + 'Dillingen', + 'Evaz', + 'Emet', + 'Antrim', + "Trostyanets'", + 'Chirilagua', + 'Sanrh Majhgawan', + 'Palashi', + 'Sidi Taibi', + 'Kumil', + "'Ali Ben Sliman", + 'Shonai', + 'Shirahama', + 'Vazante', + 'Shiruru', + 'Valderrama', + 'Valiyakumaramangalam', + 'Kadakola', + 'Vianen', + "L'Isle-sur-la-Sorgue", + 'Matheu', + 'Tibagi', + 'Itsoseng', + 'Alpinopolis', + 'Bafoulabe', + 'Altagracia', + 'Korntal-Munchingen', + 'Benicasim', + 'Kampong Thum', + 'Petrinja', + 'Ampefy', + 'Waldbrol', + 'Bhasawar', + 'Coruche', + 'Plaisance-du-Touch', + 'Ban Tha Kham', + 'Carira', + 'Chilly-Mazarin', + 'Acquaviva delle Fonti', + 'Butare', + 'Tarhzirt', + 'Nachod', + 'Irlam', + 'Mapai', + 'Mulundo', + 'Venmani', + 'Ait Tamlil', + 'Koskapur', + 'Doany', + 'San Martin de la Vega', + 'Had Zraqtane', + 'Sand Springs', + 'La Mornaghia', + 'Hiddenhausen', + 'Chatia', + 'Andal', + 'Siahkal', + 'Merrifield', + 'Affton', + 'Ulcinj', + 'Dhanaula', + 'Palliman', + 'Aanekoski', + 'Burnie', + 'Merad', + 'Bichena', + 'Yuancun', + 'Novate Milanese', + 'Senapparetti', + 'Pukhrayan', + 'Plattsburgh', + 'Saint-Augustin-de-Desmaures', + 'Bressuire', + 'Ban Tha Ton', + 'Sakae', + 'Nottuln', + 'El Arenal', + 'Zawiyat Razin', + 'Oregon', + 'Hunters Creek', + 'Akureyri', + 'Biddulph', + 'Saynshand', + 'Vevey', + 'Vila Rica', + 'Nejo', + 'Mokena', + 'Crest Hill', + 'Namegawa', + 'Maple Shade', + 'Loudima Poste', + 'Kisai', + 'El Paraiso', + 'Gil', + 'Guire', + 'Andira', + 'Kuysinjaq', + 'Brandsen', + 'Peshtera', + 'Hamina', + 'Miamisburg', + 'Senica', + 'Dagohoy', + 'Karlapalem', + 'Gherla', + 'Castilho', + 'Canelones', + 'El Castillo de La Concepcion', + 'Opfikon', + 'Sacile', + 'Ibirama', + 'Calella', + 'Orasje', + 'Quepos', + 'Bara Malehra', + 'Likak', + 'Boussu', + 'Umrapur', + 'El Mansouria', + 'Gerlingen', + 'Zimatlan de Alvarez', + 'Kavieng', + 'Tepetlixpa', + 'Cartavio', + 'Humanes de Madrid', + 'Moosburg', + 'Campamento', + 'Kuusankoski', + 'Jagatpur', + 'Cantagalo', + 'Rechaiga', + 'Gebre Guracha', + 'Stroud', + 'Peto', + 'Masterton', + 'Sint-Andries', + 'Rio Verde de Mato Grosso', + 'Ellamanda', + 'Khizrpur', + 'Kolavallur', + 'Makurazaki', + 'Spennymoor', + 'Broadview Heights', + 'Pradopolis', + 'Jambai', + 'Atlapexco', + 'Lincolnia', + 'Garforth', + 'Dokolo', + 'Lisieux', + 'Sleaford', + 'Anghad', + 'Mannur', + 'Kochas', + 'Kamakhyanagar', + 'Torgau', + 'Ban Na San', + 'Hirokawa', + 'Remigio', + 'Universal City', + 'Sainte-Marthe-sur-le-Lac', + 'Stoke Gifford', + 'Wilnsdorf', + 'Kannankurichchi', + 'Itaparica', + 'Rubiataba', + 'Nosy Varika', + 'Cekerek', + 'Araripe', + 'Holden', + 'Poperinge', + 'Time', + 'Mosopa', + 'Smorumnedre', + 'Sparta', + 'Oulad Embarek', + 'Vulcan', + 'Malabuyoc', + 'Cheung Chau', + 'Brandys nad Labem-Stara Boleslav', + 'Zhaodianzi', + 'Palm Valley', + 'Kattanam', + 'Puerto Armuelles', + 'Ghatkesar', + 'Lackawanna', + 'Selby', + 'Bishunpur', + 'Ennigerloh', + 'Ryuyo', + 'Oulad Fraj', + 'Xingangli', + 'Simonesia', + 'Lake Zurich', + 'Prudnik', + 'Poshkent', + 'Tres Barras', + 'Pattamadai', + 'Calvillo', + 'Os', + 'Wittlich', + 'Opoczno', + 'Itatinga', + 'Assebroek', + 'Thimiri', + 'Beldaur', + 'Marsberg', + 'Cherakhera', + 'Mengdan', + 'Sarstedt', + 'Yonabaru', + 'Issaba', + 'Kanekallu', + 'Evergreen Park', + 'Crisopolis', + 'Moinesti', + 'Yosano', + 'Claremore', + 'Viadana', + 'Nittedal', + 'Pecinci', + 'West Whiteland', + 'Cuite', + 'Hongshui', + 'Grobenzell', + 'Saavedra', + 'Castelo do Piaui', + 'Pichidegua', + 'Rio Segundo', + 'Payimattam', + 'Mayen', + 'Schenefeld', + 'Jnane Bouih', + 'Alga', + 'Oschersleben', + 'Beltsville', + 'Kinston', + 'Buckeburg', + 'Babanusah', + 'Lehara', + 'South El Monte', + 'Suarez', + 'Colotlan', + 'San Salvo', + 'Taketa', + 'Jimaguayu', + 'Dicholi', + 'Harmanli', + 'Mokeri', + 'Busra ash Sham', + 'Silla', + 'Katpadi', + 'Kanniyakumari', + 'Calatayud', + 'Mougins', + 'Namburu', + 'Oros', + 'Whitemarsh', + 'Sinacaban', + 'Mahmudabad Nemuneh', + 'Hajnowka', + 'Guantiankan', + 'Udalguri', + 'Korsholm', + 'Pastores', + 'Budipuram', + 'Westmount', + 'Andaingo Gara', + 'Chiconcuac', + 'Pichor', + 'Buriti dos Lopes', + 'Komarom', + 'Bruz', + 'Duragan', + 'Yuanhucun', + 'Grafton', + 'Chipiona', + 'Karuizawa', + 'Kondur', + 'Nove Mesto nad Vahom', + 'Luenoufla', + 'Dayr Abu Hinnis', + 'Davyhulme', + 'Villabate', + 'Ahfir', + 'Nilakkottai', + 'Urumita', + 'Hanumana', + 'Rawah', + 'Jussara', + 'Varpalota', + 'Haiger', + 'Bir Kasdali', + 'Ampere', + 'Atasu', + 'Otjiwarongo', + 'Yahotyn', + 'Bad Aibling', + 'Arvin', + 'Ramjibanpur', + 'Lerdo de Tejada', + 'Okhmalynka', + 'Punta Gorda', + 'Bad Pyrmont', + 'Mayahaura', + 'El Coco', + 'Ilijas', + 'Veroli', + 'Niiyama', + 'Brigham City', + 'Bondo', + 'Kutina', + 'San Juan Zitlaltepec', + 'Petrila', + 'Diinsoor', + 'Sadpur', + 'Tapaua', + 'Ischia', + 'Russell', + 'Turnu Magurele', + 'Holtsville', + 'Xapuri', + 'Lieto', + 'Rhede', + 'Buritirama', + 'Lastra a Signa', + 'Hidalgotitlan', + 'Visaginas', + 'Venadillo', + 'Schilde', + 'Engelskirchen', + 'Liuliang', + 'Les Coteaux', + 'Bourg-les-Valence', + 'Bequimao', + 'Jajarm', + 'Punjai Puliyampatti', + 'Caraubas', + 'Erlanger', + 'Burnham-on-Sea', + 'Baranain', + 'Heinola', + 'Caoayan', + 'Abbots Langley', + 'Suchiapa', + 'Amorebieta', + 'Aysha', + 'Atchoupa', + 'Wenden', + 'Doujing', + 'Mirfield', + 'Acigol', + 'Ansermanuevo', + 'Ballyfermot', + 'Vallam', + 'Morwa', + 'Mogiyon', + 'Tole Bi', + 'Hermosa Beach', + 'Carai', + 'Thamaga', + 'Huseni', + 'Pathrajolhania', + 'Tirthahalli', + 'Guapo', + 'Jhalida', + 'Artik', + 'Mihona', + 'Marahra', + 'Liuguang', + 'Herceg Novi', + 'Crespo', + 'Bagaces', + 'Rajaudha', + 'Eersel', + 'Eupen', + 'Ipanema', + 'Pauini', + 'Hoxut', + 'Ibigawa', + 'Goole', + 'Bedele', + 'Parsahi Sirsia', + 'Arese', + 'Fukude', + 'Yusufeli', + 'Alaca', + 'Kalayapuram', + 'Amta', + 'Telavi', + 'Mahinawan', + 'Tibba', + 'East Massapequa', + 'Akanavaritota', + 'Asasa', + 'West Mifflin', + 'Castellana Grotte', + 'Garsfontein', + 'Ait Bousarane', + 'Ait Bouziyane', + 'Sao Vicente Ferrer', + 'Sjobo', + 'Sangasso', + 'Hushihacun', + 'Los Alamos', + 'El Arahal', + 'Teminabuan', + 'Oulad Salmane', + 'Callosa de Segura', + 'San Juan de Dios', + 'Hoveyzeh', + 'Deneysville', + 'Nilgiri', + 'Rhar el Melah', + 'Capinota', + 'Orinda', + 'Albolote', + 'Cugir', + 'Eschwege', + 'Borna', + 'Molln', + 'Mullheim', + 'Jagalur', + 'Krishnapur', + 'Orvieto', + 'Sondiha', + 'Gogogogo', + 'Qorasuv', + 'Polonuevo', + 'Setlagode', + 'Ramchandrapur', + 'Teghra English', + 'Angleton', + 'Narsapur', + 'Cervantes', + 'Marihatag', + 'Kempston', + 'Hechingen', + 'Kemi', + 'Ronchin', + 'Sabaudia', + 'Madisonville', + 'Kos', + 'Salmon Arm', + 'Cardonal', + 'Adel', + 'Tublay', + 'Someren', + 'Santiago Texacuangos', + 'Ban Thap Kwang', + 'Bartow', + 'Gaeta', + 'Lynn Haven', + 'Kemise', + 'Liversedge', + 'Siruma', + 'Nova Granada', + 'Karttigappalli', + 'Vence', + 'Dorou', + 'Samalapuram', + 'Salangaippalaiyam', + 'Abrisham', + 'Xihuangcun', + 'Weil der Stadt', + 'Sulzbach-Rosenberg', + 'Zachary', + 'Los Bajos', + 'Frutillar Alto', + 'Sipoo', + 'Sweetwater', + 'Yandrapalle', + 'Dalanzadgad', + 'Pahsara', + 'Kantharalak', + 'Pariquera-Acu', + 'Bad Driburg', + 'Cabildo', + 'Alto Araguaia', + 'Arbaoun', + 'Annaberg-Buchholz', + 'Sartell', + 'Barro', + 'Torokszentmiklos', + 'Kalghatgi', + 'Shikrapur', + 'Charef', + 'Saint-Lo', + 'Manjathala', + 'Casarano', + 'Prunedale', + 'Middelkerke', + 'Heishanzuicun', + 'Seabrook', + 'Abhayapuri', + 'Kakdwip', + 'Boone', + 'Giovinazzo', + 'Canto do Buriti', + 'Burghausen', + 'Tajerouine', + 'Kloten', + 'Kitatajima', + 'Godo', + 'Saint-Fons', + 'Pastrana', + 'Juquia', + 'Rifadpur', + 'Mukaiengaru', + 'Sare-Yamou', + 'Buruanga', + 'Paranapanema', + 'Heishuikeng', + 'Arbatache', + 'Balta', + 'Prichard', + 'Nauen', + 'Kuttyadi', + 'Great Linford', + 'Dudu', + 'Jamsa', + 'Napindan', + 'Ban Bueng', + 'Ban Patong', + 'Mahajeran-e Kamar', + 'Oruvadalkotta', + 'Moulins', + 'Jose Cardel', + 'Tadian', + 'Wassenberg', + 'Allanridge', + 'Pugo', + 'Tangbian', + 'Wolfratshausen', + 'Sorada', + 'Weesp', + 'Bierun', + 'Cajola', + 'Corner Brook', + 'Dashtigulho', + 'Pultusk', + 'Presidente Medici', + 'Bholsar', + 'Ban Fang Tuen', + 'Peruru', + 'Tevaram', + 'Saint-Die-des-Vosges', + 'Kamiichi', + 'Warrensburg', + 'Faversham', + 'New Glasgow', + 'Moana', + 'Palera', + 'Panniperumthalai', + 'Mancio Lima', + 'San Antonio Huista', + 'Assamannur', + 'Pohadi', + 'Tash-Komur', + 'Pottanikad', + 'Heusenstamm', + 'Dukinfield', + 'Jirkov', + 'Monte Azul Paulista', + 'Virovitica', + 'Dorval', + 'Qandala', + 'Selestat', + 'Marechal Taumaturgo', + 'Espiritu', + 'Kapangan', + 'Sirvar', + 'Casamassima', + 'Sukumo', + 'Twinsburg', + 'Ganyesa', + 'Sudley', + 'Dolynska', + 'Seminole', + 'Douar Ait Sidi Daoud', + 'Bouanri', + 'Bhojpur Jadid', + 'Cutlerville', + 'Iiyama', + 'Wanluan', + 'Rovato', + 'Beaconsfield', + 'Tsumeb', + 'Pitimbu', + 'Sint-Gillis-Waas', + 'Mapastepec', + 'Marchena', + 'Peterhead', + 'Indargarh', + 'Haldensleben', + 'Hermiston', + 'Maitland', + 'Alzey', + 'El Viso del Alcor', + 'Kudra', + 'Ferndale', + "Cassano d'Adda", + 'Tillaberi', + 'Balintawak', + 'Babai', + 'Cabusao', + 'Sherrelwood', + 'Henichesk', + 'Valle Vista', + 'Tonantins', + 'Realeza', + 'Aguas Formosas', + 'Gilching', + 'Dracevo', + 'Sogut', + 'Quartier Morin', + 'Kamwenge', + 'Sirnia', + 'Groveland', + 'Holalkere', + 'Diadi', + 'Al Brouj', + 'Ballitoville', + 'Roosevelt', + 'Garot', + 'Kassama', + 'Ghosai', + 'Magitang', + 'Suhbaatar', + 'Pescia', + 'Gazi', + 'Vigna di Valle', + 'Atok', + 'Springboro', + 'Amboanana', + 'Khonj', + 'Eruvatti', + 'Cheticheri', + 'Kabudarahang', + 'Tingloy', + 'Malgrat de Mar', + 'Brie-Comte-Robert', + 'Bandar-e Kong', + 'Ecclesall', + 'Abomsa', + 'Jakobstad', + 'Zola Predosa', + 'Texcaltitlan', + 'Puerto Morelos', + 'Jiabong', + 'Lumphat', + 'Ystrad Mynach', + 'Andrychow', + 'Rangra', + 'Kale', + 'Jamiltepec', + 'Devgadh Bariya', + 'Attapu', + 'Aradippou', + 'Sligo', + 'Lebbeke', + 'Rurrenabaque', + 'La Corredoria', + 'Binka', + 'Khamaria', + 'Gomishan', + 'Ermita', + 'Schkeuditz', + 'Venceslau Bras', + 'Ranst', + 'Zerong', + 'Bad Tolz', + 'Dumra', + 'Pokaran', + 'Sibila', + 'Vera', + 'Oued el Abtal', + 'Sirpur', + 'Maumelle', + 'West Manchester', + 'Badger', + 'Maghar', + 'Tinton Falls', + 'La Crau', + 'Gioia Tauro', + 'Krasnogorskiy', + 'Schonefeld', + 'Ghogardiha', + 'Deerfield', + 'Jaicos', + 'Sidi Redouane', + 'Naantali', + 'Meise', + 'Koropi', + 'Chiari', + 'Horseheads', + 'Ambatomirahavavy', + 'Blankenburg', + 'Seesen', + 'Izra', + 'Gulagac', + 'Raita', + 'Pauktaw', + 'Vila Real de Santo Antonio', + 'Sommerda', + 'Tiruvadi', + 'Cocos', + 'Cedar Mill', + 'Papanduva', + 'Guaranesia', + 'Senguio', + 'Pitt Meadows', + 'Biswanath Chariali', + 'Gerze', + 'Reinach', + 'Ad Dir`iyah', + 'Schwalmtal', + 'Fukusaki', + 'Diamante', + 'Siralkoppa', + 'Schneverdingen', + 'Pidhorodne', + 'Billinghurst', + 'Kodumba', + 'Diepenbeek', + 'Passagem Franca', + 'Iramala', + 'Pljevlja', + 'Ampanety', + 'Trzebinia', + 'Zaouia Ait Ishak', + 'Eitorf', + 'Ainan', + 'Vargem Alta', + 'Contenda', + 'La Ligua', + 'Shemonaikha', + 'Knightdale', + 'Kufstein', + 'Imouzzer Kandar', + 'Chennirkara', + 'Mavinpalli', + 'Ban Mon Pin', + 'Ashkezar', + 'Shimokizukuri', + 'Central Point', + 'San Teodoro', + 'Martin Coronado', + 'Morauna', + 'Shahgarh', + 'Sorgues', + 'Cerqueira Cesar', + 'Cacahoatan', + 'Uwchlan', + 'Montemurlo', + 'Gobabis', + 'White Oak', + 'Bierun Stary', + 'Bella Union', + 'Harpur', + 'Lumberton', + 'Liberal', + 'Stord', + 'Lebach', + 'Taka', + 'Frimley', + 'Chautapal', + 'Lumbayanague', + 'Anguillara Sabazia', + 'Haslett', + 'Paillaco', + 'Molesey', + 'Tavares', + 'Niagara-on-the-Lake', + 'Saugerties', + 'Mumbwa', + 'Prestatyn', + 'Butia', + 'Pindobacu', + 'Villefontaine', + 'Cheran', + 'Tazishan', + 'Menzel Abderhaman', + 'Aizumisato', + 'Douar Toulal', + 'Cirencester', + 'Karlshamn', + 'Ban Bueng Phra', + 'Calne', + 'Perumkulam', + 'Mahisi', + 'Cocoa', + 'Simri', + 'Nalua', + 'Dixon', + 'Ixtlahuacan del Rio', + 'Scituate', + 'Sao Jose de Piranhas', + "Sant'Antonio Abate", + 'Pruzhany', + 'Bouansa', + 'Cunco', + 'Malanday', + 'Chinna Ganjam', + 'Murugampalaiyam', + 'La Eliana', + 'Sabanitas', + 'Gentilly', + 'Hindoria', + 'Tanbaichicho', + 'Zatec', + 'Monkseaton', + 'Preveza', + 'Puranpur', + 'Svay Pak', + 'Sylvania', + 'Itaosy', + 'Lejiangxiang', + 'Cimarron Hills', + 'Guaymango', + 'Dharmsala', + 'Bukungu', + 'Taquarana', + 'Winthrop', + 'Royan', + 'Tirmitine', + 'Telpaneca', + 'Rahata', + 'Point Pleasant', + 'Cardedeu', + 'Sarauli', + 'Wervik', + 'Monor', + 'Morlanwelz-Mariemont', + 'Cotija de la Paz', + 'North Valley Stream', + 'West Chester', + 'Caowotan', + 'Ferguson', + 'Dadeldhura', + 'Santa Ana Jilotzingo', + 'Sahline', + 'Spoltore', + 'Manjha', + 'Fond des Blancs', + 'Fate', + 'El Bolson', + 'Akune', + 'Agua Branca', + 'Gautier', + 'Quaregnon', + 'Pfullingen', + 'Lagoa de Itaenga', + 'Ellensburg', + 'Befandriana Atsimo', + 'Anjahabe', + 'Ambalanirana', + 'Ambatomena', + 'Mitsinjo', + 'Belamoty', + 'Vohimasy', + 'Ampataka', + 'Ifanirea', + 'Tanambe', + 'Ambodinonoka', + 'Miarinavaratra', + 'Ambatosia', + 'Mahazoarivo', + 'Manantenina', + 'Bezaha', + 'Ranomena', + 'Nootdorp', + 'Bajo Boquete', + 'Shovot', + 'Durpalli', + 'Vitre', + 'Cafelandia', + 'Vista Hermosa de Negrete', + 'Kouloum', + 'Haukipudas', + 'Druten', + 'Chapada dos Guimaraes', + 'Heredia', + 'Kosatarosh', + 'Barao do Grajau', + 'Narapala', + 'Sukhasan', + 'Scorze', + 'Radeberg', + 'Laukaa', + 'Kaveripatnam', + 'Onex', + 'Ait Ben Daoudi', + 'Caconde', + 'Boiro', + 'Koliakkod', + 'Weirton', + 'La Nucia', + 'Sarso', + 'Burscheid', + 'Acqui Terme', + 'Varidhanam', + 'Ban Na Yang', + 'Colwood', + 'Konstantynow Lodzki', + 'Chichiriviche', + 'Southbourne', + 'El Rosal', + 'Saint Peter Port', + 'Carei', + 'Sarsawa', + 'Krommenie', + 'Utebo', + 'Makronia', + 'Ansonia', + 'San Ignacio Cerro Gordo', + 'Chilkuru', + 'Krizevci', + 'Fox Crossing', + 'Pitseng', + 'Atacames', + 'Pinole', + 'Kolbermoor', + 'El Malah', + 'Tak Bai', + 'Guru Har Sahai', + 'Motomachi', + 'Beni Zouli', + 'Aikaranad', + 'Neviges', + 'Casalgrande', + 'Malacky', + 'Lakhnadon', + 'Ayvacik', + 'Middlesex Centre', + 'Desavilakku', + 'Monserrato', + 'Bad Berleburg', + 'Eiheiji', + 'Nakasi', + 'Elamattur', + 'Zuidhorn', + 'Pirkkala', + 'Ab Pakhsh', + 'Prenzlau', + 'Ismailpur', + 'Kotekara', + 'Ranbirsinghpura', + 'Tado', + 'Lagoa Formosa', + 'Franklin Farm', + 'Sironko', + 'Beshkent Shahri', + 'Shirin', + 'Fakfak', + 'Mo i Rana', + 'Matteson', + 'Utazu', + 'Horsforth', + 'Somandepalle', + 'Nayagarh', + 'Bad Reichenhall', + 'Gatada', + 'Gardhabaer', + 'Madalag', + 'Amares', + 'Nanjanad', + 'San Carlos Park', + 'Guarei', + 'Ezhamkulam', + 'Sugaon', + 'Kasterlee', + 'Naousa', + 'Formoso do Araguaia', + 'Jaggampeta', + 'Pozzallo', + 'Hun', + 'Lagawe', + 'Korsimoro', + 'Ap Khanh Hung', + 'Signa', + 'Malazgirt', + 'Ajacuba', + 'Massaguet', + 'Kalmthout', + 'Lake Shore', + 'Coronado', + 'Groesbeek', + 'Hemmingen', + 'Kabbur', + 'Varapatti', + 'Arita', + 'Alsip', + 'San Sebastian de Buenavista', + 'Arac', + 'Duero', + 'Conceicao', + 'Mont-Saint-Hilaire', + 'Naaldwijk', + 'Traiskirchen', + 'Cinco Ranch', + 'Weissenburg', + 'Larne', + 'Malimono', + 'Horizontina', + 'North Myrtle Beach', + 'Anzoategui', + 'Fihaonana', + 'Guachucal', + 'Kara-Kol', + 'Oirschot', + 'Varzelandia', + 'Santa Fe Springs', + 'Zahana', + 'Dukli', + "Ben 'Aknoun", + 'Ronkonkoma', + 'Chelmno', + 'Nakhl-e Taqi', + 'Onalaska', + 'Acri', + 'Tradate', + 'Lakeway', + 'Cusano Milanino', + 'Bradfordville', + 'Qitai', + 'Dzuunharaa', + 'Alzenau in Unterfranken', + 'Las Terrenas', + 'Edam', + 'Nunungan', + 'Khetia', + 'Somerset East', + 'Sao Jose da Coroa Grande', + 'Republic', + 'Camarate', + 'Berkovitsa', + 'Odzak', + 'Carlos Spegazzini', + 'Brownwood', + 'Bad Durkheim', + 'Sebaste', + 'Ascencion de Guarayos', + 'Lancing', + 'Sabalpur', + 'Marktoberdorf', + 'Velez', + 'Purushottampur', + 'Sheridan', + 'Syosset', + 'Kalabahi', + 'Udumanthala', + 'Huehuetla', + 'Pastos Bons', + 'Shimomura', + 'Abdurahmoni Jomi', + 'Dusti', + 'Hazorasp', + 'Diallassagou', + 'Ware', + 'Starobilsk', + 'East St. Louis', + 'Owego', + 'Bremervorde', + 'Arilje', + 'Ibirataia', + 'Tocaima', + 'Lukovit', + 'Oulmes', + 'Taft', + 'Jwaneng', + 'Wisconsin Rapids', + 'Terra Santa', + 'Itajuipe', + 'Sompeta', + 'Ban Bo Haeo', + 'Heerde', + 'Antotohazo', + 'Pastavy', + 'Chowchilla', + 'Camrose', + 'Kabala', + 'Kralupy nad Vltavou', + 'Zlotow', + 'Maranchi', + 'Presidente Olegario', + 'Villaquilambre', + 'Donihue', + 'Karia Ba Mohamed', + 'Villa Rica', + 'Ayyampettai', + 'Durant', + 'Birnagar', + 'Bergeijk', + 'Retiro', + 'Rutherford', + 'Hopkins', + 'San Juan Ermita', + 'Nanthankulam', + 'Bonneuil-sur-Marne', + 'Kurumbapalaiyam', + 'Hopkinton', + 'Koporo-Kenie-na', + 'Kiliia', + 'Bayshore Gardens', + 'Ngathainggyaung', + 'Palestine', + 'Harihans', + 'Altonia', + 'Wallingford Center', + 'Melmuri', + 'Riom', + 'Los Lagos', + 'San Rafael La Independencia', + 'Adliswil', + 'Schlieren', + 'Sendamaram', + 'Paglat', + 'Rufino', + 'Lansdale', + 'Gunri', + 'Gorele', + 'Alfeld', + 'Phoenixville', + 'Ozorkow', + 'Country Walk', + 'South San Jose Hills', + 'Tlalnelhuayocan', + 'Kljuc', + 'Hem', + 'Snina', + 'Altus', + 'Dhariwal', + 'Aroeiras', + 'Djidian', + 'Vadakkangara', + 'Choghadak', + 'Peduasi', + 'Aburi', + "Qo'shko'pir", + 'Abong Mbang', + 'Lupeni', + 'Tyele', + 'Tsivory', + 'Balilihan', + 'Cerkes', + 'Qaryat al Qi`an', + 'Valle', + "Nefas Mewch'a", + 'Perunturuttu', + 'Anderanboukan', + 'Majdanpek', + 'Ceglie Messapico', + 'Zapote', + 'Creve Coeur', + 'Martinsburg', + 'Round Lake', + 'Kinzau-Vuete', + 'Doura', + 'Blooming Grove', + 'Togba', + 'Afranio', + 'Bensenville', + 'Sao Raimundo das Mangabeiras', + 'Mansa Konko', + 'Trinity', + 'Sonhauli', + 'Lakhna', + 'Almel', + 'Rishivandiyam', + 'Lelydorp', + 'Meerssen', + 'Jasidih', + 'Broughty Ferry', + 'Samma', + 'Seagoville', + 'Siyazan', + 'Maimon', + 'Soalkuchi', + 'Molakalumuru', + 'Centerton', + 'Santa Catarina Juquila', + 'Selwyn', + 'Elumalai', + 'St. Michael', + 'Laualagaon', + 'Carnaiba', + 'Kangazha', + 'Telwa', + 'Adria', + 'Castaic', + 'Aldama', + 'Futog', + 'Szamotuly', + 'Basatpur', + 'Mukkanur', + 'Enkhuizen', + 'Bonanza', + 'Bergneustadt', + 'Kilmangalam', + 'Manikkal', + 'Le Puy-en-Velay', + 'Lede', + 'Mossendjo', + 'Ribeirao Branco', + 'Chakur', + 'Manakayi', + 'Ubaira', + 'Urucara', + 'Sanharo', + 'Tarifa', + 'Ballincollig', + 'Londerzeel', + 'Seara', + 'Knik-Fairview', + 'Uetersen', + 'Medjedel', + 'Carlos Chagas', + 'Volketswil', + 'Tillsonburg', + 'Eastwood', + 'Fairwood', + 'Engenheiro Coelho', + 'Maurepas', + 'Bellwood', + 'East Dereham', + 'Onga', + 'Mullach Ide', + 'Stannington', + 'Reriutaba', + 'Ajnala', + 'Leposaviq', + 'Saylac', + 'Toshloq', + 'Miyatoko', + 'Timoktene', + 'Los Alcazares', + 'Renningen', + 'Kalugumalai', + 'Jbabra', + 'Antombana', + 'Felanitx', + 'Five Forks', + 'Ploemeur', + 'Preakness', + 'Majhua', + 'Valavanur', + 'Al Jawf', + 'Anna', + 'Jalakandapuram', + 'San Mauro Torinese', + 'Colonia', + 'Skara', + 'Windham', + 'Shika', + 'Rhynern', + 'Tamri', + 'Mohana', + 'Liuma', + 'Clive', + 'Liancourt', + 'Narangba', + 'Meylan', + 'Kasongan', + 'Elizabeth City', + 'Nederland', + 'Bougtob', + 'Tomaszow Lubelski', + 'Crimmitschau', + 'Paluan', + 'San Sebastian Salitrillo', + 'Miracema do Tocantins', + 'Ban Mae Hia Nai', + 'Erumakkuzhi', + 'Zhosaly', + 'Kingsland', + 'Pizarro', + 'Tarrafal', + 'Bhadaur', + 'Shenandoah', + 'Ebbw Vale', + 'Garuva', + 'Boom', + 'Mingjiujie', + 'Leteri', + 'Wheatfield', + 'Morros', + 'Zakiyah', + 'Miracatu', + 'Lessines', + 'Matipo', + 'Kumbhraj', + 'Mennzel Bou Zelfa', + 'Mellacheruvu', + 'Berea', + 'Shaogang', + 'Glinde', + 'Ban Mae Kha Tai', + 'Sebt Gzoula', + 'Orhaneli', + 'Hochheim am Main', + 'Kothia', + 'Morro da Fumaca', + 'Kulu', + 'Arcata', + 'Baena', + 'Stabroek', + 'Guadix', + 'Parole', + 'Sokolow Podlaski', + 'Ba', + 'Rohar', + 'Melville', + 'Oxon Hill', + 'Asuncion Nochixtlan', + 'Thalwil', + 'Lodhwe', + 'Tsetserleg', + 'Tessenderlo', + 'Guanzhai', + 'Santa Cruz Zenzontepec', + 'Bilar', + 'Iselin', + 'Brook Park', + 'Harnosand', + 'Galhinna', + 'Huercal de Almeria', + 'St. Marys', + 'Tadikonda', + 'Madre de Deus', + 'Anicuns', + 'Tatsuno', + 'Palaiyampatti', + 'Hassleholm', + 'Buikwe', + 'Appley Bridge', + 'Goffstown', + 'Rawmarsh', + 'Ghedi', + 'Kivsharivka', + 'Potirendaba', + 'Bitkine', + 'Rhaude', + 'Vlotho', + 'Karcag', + 'Kalynivka', + 'Chubek', + 'San Lorenzo de El Escorial', + 'Busovaca', + 'Schwalmstadt', + 'Staines-upon-Thames', + 'Unquillo', + 'Zagarolo', + 'Pinas', + 'San Celoni', + 'Sirvel', + 'Fushe-Kruje', + 'Kherameh', + 'Ajaigarh', + 'Foxborough', + 'Tinoc', + 'Giszowiec', + 'Boerne', + 'Vellmar', + 'Tirmalgiri', + 'Qasr-e Shirin', + 'Sharon', + 'Bedlington', + 'Sacavem', + 'Hoppegarten', + 'Eragny', + 'Alcantara', + 'La Marque', + 'Catak', + 'Castel Maggiore', + 'Kotancheri', + 'Kunitomi', + 'Pio IX', + 'Kannapuram', + 'Osku', + 'Hessisch Oldendorf', + 'Lagoa da Canoa', + 'Od', + 'Kariyapatti', + 'Mill Hill', + 'Matelandia', + 'Cognac', + 'Ngolonianasso', + 'Shimokodanaka', + 'Narlica', + 'Coalcoman de Vazquez Pallares', + 'Haaltert', + 'Kassaro', + 'Jucuapa', + 'Achocalla', + 'Bakhmach', + 'Bonen', + 'Hellemmes-Lille', + 'Chouafa', + 'Zhangshicun', + 'Choi Hung', + 'Arroyo Grande', + 'Astrea', + 'Albert Lea', + 'Cullman', + 'Baliangao', + 'Lahnstein', + 'Dumjor', + 'Ponedera', + 'Johnstown', + 'Orestiada', + 'Juvisy-sur-Orge', + 'New River', + 'Mukkudal', + 'Vechelde', + 'Montrouis', + 'Pomaz', + 'Castelfidardo', + 'Kreminna', + 'Svatove', + 'San Vicente Pacaya', + 'Ocean Springs', + 'Fatick', + 'Kronberg', + 'Devadanappatti', + 'Basse Santa Su', + 'Unhel', + 'Winder', + 'Hardinxveld-Giessendam', + 'Amvrosiivka', + 'Foum el Anser', + 'Belo Campo', + 'Tallmadge', + 'San Blas Atempa', + 'Tilothu', + 'Niar', + 'Konz', + 'Nordestina', + 'Fairmont', + 'Korsun-Shevchenkivskyi', + 'Quitandinha', + 'Kumarapuram', + 'Santa Marinella', + 'Srikhanda', + 'North Babylon', + 'Inhapi', + 'Crowley', + 'North Bay Shore', + 'Aragarcas', + 'Harij', + 'Tinajeros', + 'Longjia', + 'Rio Maria', + 'Bhawanipur', + 'Itapororoca', + 'Sanpaicun', + 'Bracciano', + 'East Goshen', + 'Straseni', + 'Walcourt', + 'Greene', + 'Cesario Lange', + 'Sigmaringen', + 'Franklin Park', + 'Clonmel', + 'Qatlupur', + 'Illertissen', + 'Mumford', + 'Assa', + 'Filomeno Mata', + 'Chennevieres-sur-Marne', + 'Agarpur', + 'Baependi', + 'Santiago Ixcuintla', + 'Sao Benedito do Rio Preto', + 'El Transito', + 'Olten', + 'Ecully', + 'Noci', + 'Chhoti Sadri', + 'Krasyliv', + 'Newburyport', + 'Campo de la Cruz', + 'Stekene', + 'San Rafael Pie de la Cuesta', + 'Cagdianao', + 'Worth am Rhein', + 'Louviers', + 'Saladas', + 'Ammapettai', + 'Almondbury', + 'Redland', + 'Nari Bhadaun', + 'Maryland City', + 'Cortes', + 'Apastepeque', + 'Sendarappatti', + 'Capoeiras', + 'Mineros', + 'Lake Ronkonkoma', + 'Mirante do Paranapanema', + 'Daryabad', + 'Lamrasla', + 'Xintian', + 'Picui', + 'Novopavlovka', + 'Cran-Gevrier', + 'Pembroke', + 'Memuro-minami', + 'Sandare', + 'Shaoyu', + 'Nuuk', + 'Skydra', + 'Calverton', + 'Karuppur', + 'Tha Bo', + 'Taio', + 'Melzo', + 'San Jose Tenango', + 'Lora del Rio', + 'Carrieres-sous-Poissy', + 'Talata-Volonondry', + 'Riachao do Dantas', + 'Pully', + 'Pontalina', + 'Morretes', + 'Gerd Faramarz Shahediyeh', + 'Abrandabad-e Shahediyeh', + 'Kitagata', + 'Nossombougou', + 'Nehbandan', + 'Mangualde', + 'Belem de Sao Francisco', + 'Lenoir', + "Do'stlik Shahri", + 'Hadleigh', + 'Sint-Genesius-Rode', + 'Ommen', + 'Volochysk', + 'Puttlingen', + 'Bingley', + 'Rutigliano', + 'Taung', + 'Szigethalom', + 'Sakoueba', + 'Navraftor', + 'Senkaya', + 'Panama City Beach', + 'Pinecrest', + 'Parchim', + 'Palos Hills', + 'Fomboni', + 'Kadan', + 'Paraibano', + 'Kristiansund', + 'Mannara', + 'Rosendael', + 'Phelan', + 'Ait Bouchta', + 'Bni Bouayach', + 'Tarrega', + 'Kasba Maker', + 'Paraibuna', + 'Yupiltepeque', + 'Siloe', + 'Bideford', + 'Luz', + 'Ban Mai', + 'Monte Cristo', + 'Regensdorf', + 'Yoichi', + 'Mulanur', + 'Shuangluan', + 'South Orange Village', + 'Bagnols-sur-Ceze', + 'Moissy-Cramayel', + 'Staveley', + 'Asakapalle', + 'Mathurapur', + 'Pisz', + 'Shaw', + 'Savastepe', + 'Narayankher', + 'Monforte de Lemos', + 'Sivandipuram', + 'Santa Iria da Azoia', + 'Carrigaline', + 'Comodoro', + 'Kanp', + 'Ikniwn', + 'Calera de Tango', + 'Leczna', + 'Centralia', + 'Fulwood', + 'Ocean Acres', + 'Eski-Nookat', + 'Kingstowne', + 'Kottukal', + 'Julio de Castilhos', + 'Budrio', + 'Galaat el Andeless', + 'Mahiari', + 'Bad Segeberg', + 'Kurakhove', + 'Baixa Grande', + 'El Astillero', + 'Pieksamaki', + 'Bronte', + 'Pijijiapan', + 'Zielonka', + 'Taqah', + 'Bani Hasan ash Shuruq', + 'Nazare Paulista', + 'Farias Brito', + 'Bettioua', + 'Taku', + 'Gameleira', + 'Sipacate', + 'Stillorgan', + 'Tirunageswaram', + 'Sahna', + 'Filadelfia', + 'Sikhio', + 'Blindio', + 'Serrita', + 'Dagana', + 'Amaraji', + 'Kudatini', + 'Budhni', + 'Kishi', + 'Shaying', + 'Konskie', + 'Santiago de Maria', + "Bet She'an", + 'North Massapequa', + 'Kiangara', + 'Ranquitte', + 'Griffith', + 'Palamos', + 'San Sebastian Tutla', + 'Udaipura', + 'Sarvestan', + 'Taufkirchen', + '`Anbarabad', + 'Rikuzen-Takata', + 'Solonopole', + 'Dapi', + 'Oconomowoc', + 'Quibaxi', + 'Aldo Bonzi', + 'Steubenville', + 'South Fayette', + 'Gossau', + 'Sycamore', + 'Vredendal', + 'Logansport', + 'Bhadrapur', + 'Tummalapenta', + 'Redhill', + 'Laives', + 'Asane', + 'Kottapalle', + 'Corbetta', + 'Petawawa', + 'Colonial Heights', + 'Xochiatipan de Castillo', + 'Zinvie', + 'Qishe', + 'Guayama', + 'El Achir', + 'Heckmondwike', + 'Bouarouss', + 'Lavasan', + 'Inga', + 'Piatykhatky', + 'Citluk', + 'Keskin', + 'Heusweiler', + 'Minamishibetsucho', + 'Dobrush', + 'Pinabacdao', + 'Yoshimi', + 'Schofield Barracks', + 'Palanga', + 'Andalucia', + 'Tominian', + 'Gangwuzhen', + 'Svilengrad', + 'Beerse', + 'Sangre Grande', + 'Canby', + 'Dumri', + 'Jora Khurd', + 'Bourbonnais', + 'Menasha', + 'Lomianki', + 'Ouankoro', + 'Louny', + 'Cirie', + 'Pottanur', + 'Feyzabad', + "Terra Roxa d'Oeste", + 'Ambiula', + 'Raisari', + 'Coronda', + 'Poulton le Fylde', + 'Convencion', + 'Polohy', + 'Gandarbal', + 'Faches-Thumesnil', + 'Manikpur', + 'McAlester', + 'Caldas de Montbuy', + 'Paharpur', + 'Shorewood', + 'Campos Belos', + 'Mure', + 'White Settlement', + 'Binh Minh', + 'Varjota', + 'Fort Carson', + 'Maoussa', + 'Hybla Valley', + 'Pavullo nel Frignano', + 'San Vito dei Normanni', + 'Grossenhain', + 'Borgo San Lorenzo', + 'Kikube', + 'Berkhampstead', + 'Cofradia', + 'Belterra', + 'Dolny Kubin', + 'Southeast', + 'Tora', + 'Chapelle', + 'Antonina', + 'General Juan Madariaga', + 'Madalena', + 'Heguri', + 'Calenzano', + 'Barikot', + 'Ghouazi', + 'Agua Azul do Norte', + 'Kopa', + 'East Riverdale', + 'Arajpur', + 'Wandsworth', + 'Mayorga', + 'Bobingen', + 'Kety', + 'Ricaurte', + 'Manyas', + 'Pedra Preta', + 'Sao Tiago de Custoias', + 'Oroszlany', + 'Fuente-Alamo de Murcia', + 'Luganville', + 'Ismaning', + 'Tottiyam', + 'Scarsdale', + 'Bidestan', + 'Kotta Kalidindi', + 'Sidi Allal Tazi', + 'Tlacoachistlahuaca', + 'Libjo', + 'Myslenice', + 'Badkulla', + 'Spanish Lake', + 'Middelharnis', + 'Annakunnu', + 'Vilavur', + 'Buadiposo-Buntong', + 'Nigran', + 'Chodziez', + 'Taperoa', + 'Timri', + 'Whitestown', + 'Carmelo', + 'Abangaritos', + 'Frankenberg', + 'Bryn Mawr-Skyway', + 'Keszthely', + 'Targu Neamt', + 'Cristinapolis', + 'Porto Novo', + 'Schwechat', + 'Destelbergen', + 'Gidi', + 'Valenza', + 'Piossasco', + 'Zuhres', + 'Matigou', + 'Koratagere', + 'Lakshmaneswaram', + 'Tordera', + 'Ulao', + 'Banbalah', + 'Buchen in Odenwald', + 'Tillmans Corner', + 'Fecamp', + 'Itabera', + 'Jasien', + 'Dumont', + 'Campina Verde', + 'Toyono', + 'Marcos', + 'Marsciano', + 'Rwamagana', + 'Nipomo', + 'Soisy-sous-Montmorency', + 'Biro', + 'Ashtabula', + 'Sakri', + 'Terrell', + 'Dbaiye', + 'Antsampanimahazo', + 'Antanambe', + 'Manampatrana', + 'Alakamisy', + 'Maroteza', + 'Bemahatazana-Belobaka', + 'Vohilengo', + 'Amboahangibe', + 'Mahazoma', + 'Ambongo', + 'Alatsinainy Ialamarina', + 'Analaiva', + 'Maroaloka', + 'Belobaka', + 'Ankofa', + 'Matsakabanja', + 'Ambovombe Afovoany', + 'Tsianisiha', + 'Beantake', + 'Behenjy', + 'Tranoroa', + 'Qal`ah-ye Zal', + 'General Deheza', + 'Al Hamalah', + 'Ad Diraz', + 'Doruma', + 'Yoboki', + 'Mickleover', + 'Gondar', + 'Tankara', + 'Ghogaon', + 'Mahraurh', + 'Tall Qasab', + 'Athar', + 'Gorham', + 'Kamienna Gora', + 'Batie', + 'Kolonodale', + 'Serra Preta', + 'Bombon', + 'Tyagadurgam', + "Aci Sant'Antonio", + 'Cameron Park', + 'Wantagh', + 'Stony Plain', + 'Oak Bay', + 'Hijuelas', + 'San Cristobal Cucho', + 'Ariccia', + 'Mount Washington', + 'Sevierville', + 'Kosvik', + 'Lagoa do Carro', + 'Cuquio', + 'Hranice', + 'Halstenbek', + 'Sukhsena', + 'Rampur Tilak', + 'Rajmahal', + 'Terenure', + 'Konakli', + 'Dizicheh', + 'Antenor Navarro', + 'Melegnano', + 'North Grenville', + 'Sapeacu', + 'Santo Anastacio', + 'Kegalle', + 'Chaita', + 'Souba', + 'Payyannur', + 'Cohoes', + 'Ptuj', + 'Towamencin', + 'Jadcherla', + 'Torit', + 'Bodegraven', + 'Ranzan', + 'Koula', + 'Bucay', + 'Ben Daoud', + 'Erumapalaiyam', + 'Barvala', + 'Blythe', + 'Mukondapalli', + 'Doylestown', + 'Flora', + 'Loyalist', + 'Stilfontein', + 'Yeddumailaram', + 'Falkoping', + 'Bischheim', + 'Miyauchi', + 'Madeley', + 'Jiadong', + 'Agliana', + 'Kuchinda', + 'Quipapa', + 'Tres de Mayo', + 'Manthani', + 'Burke Centre', + 'Texistepeque', + 'Ammon', + 'Gitagum', + 'Palmi', + "Olho d'Agua das Cunhas", + 'Coltauco', + 'Kapsabet', + 'Shirosato', + 'Alice', + 'Union de San Antonio', + 'Roulia', + 'Deux-Montagnes', + 'Ituacu', + 'Narni', + 'Pelaya', + 'Pornic', + 'Mabehiri', + 'Chateauneuf-les-Martigues', + 'Khokha', + 'Natchitoches', + 'Franconia', + 'Wadowice', + 'Glenvar Heights', + 'Manambaro', + 'Saatli', + 'Nyborg', + 'Kostrzyn nad Odra', + 'Mebane', + 'Nao-Me-Toque', + 'Garches', + 'Nguigmi', + 'Fatima', + 'Tiffin', + 'Zapotlan del Rey', + 'Sint-Oedenrode', + 'Murambi', + 'Silvani', + 'Pudunagaram', + 'Anoka', + 'Puquio', + 'Bafanji', + 'Sanghera', + 'Veldurti', + 'Cal', + 'Mount Eliza', + 'Yuanquan', + 'Munguia', + 'Guapiara', + 'Steiner Ranch', + 'Gibsonton', + 'Carmopolis de Minas', + 'Gaoniang', + 'Santa Cruz Naranjo', + 'Vilattikulam', + 'El Bordj', + 'Ramsbottom', + 'Tolentino', + 'Patar', + 'Segue', + 'Vordingborg', + 'Sa Kaeo', + 'Pimentel', + 'Chortiatis', + 'Marturu', + 'Pachmir', + 'Marwa', + 'San Kamphaeng', + 'Cenovi', + 'Manilva', + 'Szazhalombatta', + 'Loay', + 'Forst (Lausitz)', + 'Colne', + 'Sangenjo', + 'Carvin', + 'Vissannapeta', + 'Aci Castello', + 'Ambohitralanana', + 'Bekalta', + 'Shirali', + 'Montanha', + 'Pontarlier', + 'Porto Grande', + 'Edessa', + 'Sing Buri', + 'Sidi Kada', + 'Pataskala', + 'Marabut', + 'Savignano sul Rubicone', + 'Itapiuna', + 'Kristinehamn', + 'Harper', + 'San Bartolo Tutotepec', + 'Ribera', + 'Pelahiivka', + 'Timbedgha', + 'Policoro', + 'Parede', + 'Goshaingaon', + 'Aguas de Lindoia', + 'Bredene', + 'Werdohl', + 'Paks', + 'Bhikhi', + 'Arcore', + 'Villa Corona', + 'Mengjiacun', + 'Sao Luis Gonzaga do Maranhao', + 'Carate Brianza', + 'Blaj', + 'Freilassing', + 'Mazapil', + 'Itanhem', + 'Oberasbach', + 'Pariharpur', + 'Muttenz', + 'Steinbach', + 'Salgar', + 'Seyah Cheshmeh', + 'Gazantarak', + "Fontaine-l'Eveque", + 'Feilding', + 'Dhansaria', + 'Herenfa', + 'Bagahi', + 'Hendaye', + 'Vennandur', + 'Jovellar', + 'Salaspils', + 'Delran', + 'Jucurutu', + 'Shichigahama', + 'Godfrey', + 'Aminpur', + 'San Rafael del Norte', + 'Portchester', + 'Idylwood', + 'Mankara', + 'Mooirivier', + 'Arakkapadi', + 'Cordenons', + 'Khasab', + 'Monthey', + 'Dhamaun', + 'Freudenberg', + 'North Canton', + 'Varvarin', + 'Lancut', + 'Prachin Buri', + "Fanipal'", + 'Tall `Aran', + 'Vise', + 'Somma Lombardo', + 'Ash Shaykhan', + 'Agua Blanca', + 'Lake Butler', + 'Klaeng', + 'Weilerswist', + 'Willimantic', + 'Cairu', + 'Auerbach', + 'Or `Aqiva', + 'Luneville', + 'Schrobenhausen', + 'Mahis', + 'Cahokia Heights', + 'Ostermundigen', + 'Arco', + 'North Aurora', + 'Floirac', + 'McKeesport', + 'Eslov', + 'Dergaon', + 'Douar Oulad Mbarek', + 'Kuttalam', + 'Chitipa', + 'Koping', + 'Toba', + 'Saint-Colomban', + 'Dianopolis', + 'Dniprorudne', + 'Reni', + 'Kodiyeri', + 'Nikshahr', + 'Laukaha', + 'Sapucaia', + 'Erjie', + 'Bad Munder am Deister', + 'Estancia Pozo Colorado', + 'Susner', + 'Bekes', + 'Herzele', + 'Rockland', + 'Cesson-Sevigne', + 'Ban Mae Ngon Khilek', + 'Pirapemas', + 'Domodossola', + 'Hlybokaye', + 'Live Oak', + 'Broken Hill', + 'Dialafara', + 'Zaltan', + 'Ngora', + 'Major Isidoro', + 'Kharhial', + 'Miramichi', + 'Kiangan', + 'Vettavalam', + 'Vrede', + 'Miaojiaping', + 'Kalyanpur Bamaiya', + 'Kreuzau', + 'Florina', + 'Diepholz', + 'Maripad', + 'Palanan', + 'Harwich', + 'East Lampeter', + 'Dourbali', + 'Panorama', + 'Bechem', + 'Dugo Selo', + 'Mairi', + 'Avion', + 'Hope Mills', + 'Levin', + 'Torredembarra', + 'South Ockendon', + 'Moreton', + 'Pulla', + 'Southbridge', + 'Tufanbeyli', + 'Beni Fouda', + 'Whittlesey', + 'Anacortes', + 'Duffel', + 'Brignoles', + 'Minquan', + 'Biliran', + 'El Omaria', + 'Bad Sackingen', + 'Jaguaripe', + 'Vandalur', + 'Brenham', + 'Yumurtalik', + 'Pinehurst', + 'Tohoue', + 'Pianoro', + 'Tunapuna', + 'Nidda', + 'Monzon', + 'Fern Down', + 'Balaguer', + 'Tabara Arriba', + 'Fornaka', + 'Pirapora do Bom Jesus', + 'Kappiyara', + 'Fanandrana', + 'Mount Holly', + 'Bexbach', + 'Arsanjan', + 'Camano', + 'Valluvandad', + 'Vettikattiri', + 'Stowbtsy', + 'Gretna', + 'Sao Miguel do Tapuio', + 'Abare', + 'Dingjiagouxiang', + 'Damme', + 'Stuart', + 'Terenos', + 'El Carmen de Chucuri', + 'Cerrillos', + 'Otrokovice', + 'Carire', + 'Pupri', + 'Manullahpatti', + 'Siloam Springs', + 'Woodmere', + 'Saint-Maximin-la-Sainte-Baume', + 'Stegen', + 'Oborniki', + 'Ban Mae Ka Hua Thung', + 'Daimiel', + 'Asarcik', + 'Pinili', + 'La Primavera', + 'Eastlake', + 'Gostynin', + 'Lobogo', + 'Naklo nad Notecia', + 'Karacasu', + 'Yayas de Viajama', + 'Colbun', + 'Benito Juarez', + 'Sao Francisco de Assis', + 'Vittal', + 'Ambolomadinika', + 'Sokolka', + 'San Jorge', + 'Iskilip', + 'Sam Phran', + 'Totoro', + 'Omallur', + 'Veliko Gradiste', + 'Ubaitaba', + 'Zhongguyue', + 'Restrepo', + 'Barrhead', + 'Capua', + 'Chedaopo', + 'Savsat', + 'Tijucas do Sul', + 'Storrs', + 'Bel Air', + 'Lousa', + 'New Philadelphia', + 'Pirayu', + 'Siderno Marina', + 'Bakouma', + 'Abejorral', + 'Amacuzac', + 'San Alejo', + 'Herve', + 'Boqueirao', + 'Sigus', + 'Arauco', + 'Yondo', + 'Neder-Over-Heembeek', + 'Bad Wildungen', + 'Palau', + 'Para', + 'Marcon', + 'Laatatra', + 'Srbac', + 'Manganj', + 'Putte', + 'Santos Reyes Nopala', + 'Inkollu', + 'Eldama Ravine', + 'Aja', + 'Maesteg', + 'Saint Andrews', + 'Chakkuvarakal', + 'Ziar nad Hronom', + 'Muhradah', + 'Quanzhang', + 'Peruvanthanam', + 'Rayappanpatti', + 'Zephyrhills', + 'Cortland', + 'Ait Majdane', + 'Trossingen', + 'Cerca Carvajal', + 'Boissy-Saint-Leger', + 'Alcochete', + 'Roznava', + 'Sagrada Familia', + 'Piritiba', + 'Tak', + 'Ban Thum', + 'Sirari', + 'Kambla', + 'Kisoro', + 'Bistaria', + 'Arroio Grande', + 'Khutaha', + 'Lemont', + 'Clemson', + 'Gomec', + 'Palaiyam', + 'Mawkanin', + 'Son en Breugel', + 'Penn', + 'Le Pontet', + 'Cameli', + 'Glencoe', + 'Punnayur', + 'Morarano-Gara', + 'Waalre', + 'Lattes', + 'Aliyabad', + 'Takoma Park', + 'Koriapatti', + 'Swellendam', + 'Al `Asharah', + 'Etacheri', + 'Sona', + 'Mitake', + 'Kempele', + 'Vayalpad', + 'Oak Grove', + 'Shangjing', + 'Shanglingcun', + 'Harinakunda', + 'Duijiang', + 'Kirksville', + 'Esquimalt', + 'Polignano a Mare', + 'Rio Bananal', + 'Bonnyrigg', + 'Turuvekere', + 'Shirva', + 'Norcross', + 'Mistrato', + 'Dabas', + 'Attimarappatti', + 'Garching bei Munchen', + 'Guidan Roumdji', + 'Boljoon', + 'Yesilhisar', + 'Villorba', + 'Matagob', + 'Manin', + 'Gunjur', + 'Krasnystaw', + 'Quedgeley', + 'Malacacheta', + 'Ivanovka', + 'Strzelce Opolskie', + 'Rocca di Papa', + 'St. Matthews', + 'Sulaco', + 'Ebino', + 'Elankur', + 'Moloacan', + 'Tenango de Doria', + 'Piratini', + 'Mendes', + 'Baxt', + 'San Antonio de Ibarra', + 'Eksambe', + 'Goodlettsville', + 'Buguda', + 'Kudavasal', + 'Sahel', + 'Ilam', + 'Stockach', + 'Scott', + 'Coalinga', + 'Numbrecht', + 'Biyahmu', + 'Karukh', + 'Augustinopolis', + 'Zhoujia', + 'Bhucho Mandi', + 'Ambatolahy', + 'Villa Sarmiento', + 'Croata', + 'Pajapan', + 'Budva', + 'Kushk', + 'Urucuia', + 'Shin-Kamigoto', + 'South Ogden', + 'El Reno', + 'Fairview', + 'Tepatlaxco', + 'Dharampuri', + 'Umirim', + 'Corbelia', + 'Vallieres', + 'Anantavur', + 'Saluzzo', + 'Pocinhos', + 'South Venice', + 'Phayao', + 'Cafarnaum', + 'Talitay', + 'Vladimirci', + 'Cruz do Espirito Santo', + 'Bluffdale', + 'West Columbia', + 'Guanagazapa', + 'Gautampura', + 'Morganton', + 'Karkamb', + 'Falea', + 'Marche-en-Famenne', + 'Kiyama', + 'Dar Chaifat', + 'Veternik', + 'Chamalieres', + 'Sibutao', + 'Puurs', + 'Los Lunas', + 'Laguna Woods', + 'Bon Air', + 'Tasquillo', + 'Rojales', + 'Woodhouse', + 'Albino', + 'Royston', + 'Pecanha', + 'Abdullahnagar', + 'Rio Pomba', + 'Tabernes de Valldigna', + 'Nedugula', + 'Lakhnaur', + 'Rozdilna', + 'Puerto Aysen', + 'Brielle', + 'Nova Era', + 'Nisang', + 'Lubang', + 'Montemor-o-Novo', + 'Sinzig', + 'Reota', + 'Forio', + 'Bramhall', + 'Mehran', + 'Derhachi', + 'Seoni Chhapara', + 'Totutla', + 'Remagen', + 'Pescantina', + 'Anosiarivo', + 'Santa Lucia Milpas Altas', + 'Nahazari', + 'Cham', + 'Kolokonde', + 'Camocim de Sao Felix', + 'Zaslawye', + 'Loboc', + 'Osuna', + 'Bahon', + 'Olivehurst', + 'Conyers', + 'Viradouro', + 'Calayan', + 'Awlouz', + 'Babenhausen', + 'Karahia', + 'Isola Capo Rizzuto', + 'Ummannur', + 'Namminikara', + 'Jhagarua', + 'Beinasco', + 'Fraserpet', + 'Borda da Mata', + 'Douetire', + 'Yutz', + 'Odaipatti', + 'Miedzyrzecz', + 'Bolhrad', + 'Jomboy Shahri', + 'Bry-sur-Marne', + 'Martahalli', + 'Wahiawa', + 'Bhagabanpur', + 'Kawa', + 'Curti', + 'Ziracuaretiro', + 'Pyskowice', + 'Sao Domingos do Prata', + 'Abelardo Luz', + 'Wilton', + 'Cat', + 'Banni', + 'Plunge', + 'Mareth', + 'Balma', + 'Central Saanich', + 'Solrod Strand', + 'Villanueva del Pardillo', + 'Mula', + 'Louth', + 'Nea Erythraia', + 'Kurugodu', + 'Santa Maria di Sala', + 'Streetsboro', + 'Woodcrest', + 'Wangaratta', + 'Gunjapalle', + 'Kelsterbach', + 'Ban Song', + 'Arpacay', + 'Paoua', + 'Holmdel', + 'Lalibela', + 'Mujikharf', + 'Barhan', + 'Sanwer', + 'Gescher', + "Milla'ab", + 'Oued el Kheir', + 'Betio', + 'Viljandi', + 'Glassmanor', + 'Ketama', + 'Bad Langensalza', + 'Sestri Levante', + 'Sainte-Catherine', + 'Lumbreras', + 'Kembhavi', + 'Ibrahimpatan', + 'Skadovsk', + 'Hednesford', + 'Kadogawa', + 'Tonj', + 'Kamudi', + 'Valenzano', + 'Gothini', + 'Yerrapalem', + 'Sedeh Lanjan', + 'Padre Paraiso', + 'Galaz', + 'Mori', + 'Pecel', + 'Riva del Garda', + 'New Amsterdam', + 'Guardamar del Segura', + 'Mau Dhaneshpur', + 'Betroka', + 'Mudukulattur', + 'Matam', + 'Manno', + 'Tagana-an', + 'Dijiasuoxiang', + 'Ain Zaouia', + 'Uryzhar', + 'Muniz Freire', + 'El Kouif', + 'Miharu', + 'Suesca', + 'Pital', + 'Betulia', + 'Schwarzenbek', + 'Villiers', + 'Mohacs', + 'Jenison', + 'As Suqaylibiyah', + 'Chadchan', + 'Mecayapan', + 'Otacilio Costa', + 'Fort Thomas', + 'Schwalbach', + 'Sierpc', + 'Tiogollo', + 'Maranello', + 'Charipara', + 'Almolonga', + 'Namayingo', + 'Dombovar', + 'Kanrangana', + 'Mundo Novo', + 'Ban Pong', + 'Holzwickede', + 'Saram', + 'Poyo', + 'Chorhat', + 'Krupanj', + 'Barbastro', + 'Thorne', + 'Fortim', + 'Port Hope', + 'Keota', + 'Jawkatia', + 'West Lampeter', + 'Horn-Bad Meinberg', + 'Porciuncula', + 'Pont-a-Celles', + 'Kouka', + 'Santo Antonio do Amparo', + 'Talwandi Bhai', + 'Brand', + 'Bad Munstereifel', + 'Bethpage', + 'Houghton Regis', + 'Garwolin', + 'Pollensa', + 'Amesbury', + 'Zebala', + 'Osny', + 'Baie de Henne', + 'Kukraun', + 'Norrtalje', + 'Mulki', + 'Arinos', + 'Senges', + 'Sanary-sur-Mer', + 'Kulasegaram', + 'Moroni', + 'Shongzhy', + 'Hernando', + 'Staphorst', + 'Dehti', + 'Elliniko', + 'Maigh Nuad', + 'Oskarshamn', + 'Tecolotlan', + 'Rattaphum', + 'Rancho Mirage', + 'San Juan Nonualco', + 'Stanford', + 'Capistrano', + 'G`uzor', + 'Illizi', + 'Venturosa', + 'Heanor', + 'Friern Barnet', + 'Mariakerke', + 'Baturbari', + 'North Druid Hills', + 'Mettuppalaiyam', + 'Gunzenhausen', + 'Marmande', + 'Oerlinghausen', + 'Nadugadda', + 'Bawgalegyi', + 'Les Clayes-sous-Bois', + 'Heilbad Heiligenstadt', + 'Kangaba', + 'Ejutla de Crespo', + 'Jaguaretama', + 'Cipo', + 'Pavumba', + 'Abadiania', + 'Resplendor', + 'Littau', + 'Souaflia', + 'Minakami', + 'Belmopan', + 'Buford', + 'Bendorf', + 'Monselice', + 'Castelfiorentino', + 'Cukurca', + 'Bakeshiyingcun', + 'Martigny', + 'Belakoba', + 'Pisaflores', + 'Bareggio', + 'Bailen', + 'Terzigno', + 'Avenel', + 'Durlesti', + 'Carnaubal', + 'Itacarambi', + 'Kretinga', + 'Port-a-Piment', + 'Marktredwitz', + "L'Isle-d'Abeau", + 'Raiyam', + 'Piera', + 'Chouafaa', + 'Shahritus', + 'Carmo', + 'Akassato', + 'Lerida', + 'Banabuiu', + 'Anori', + 'Digne-les-Bains', + 'Badantola', + 'Araruna', + 'Glen Parva', + 'Mont-Organise', + 'Dormentes', + 'Flowing Wells', + 'Sudipen', + 'Batufah', + 'Forssa', + 'Cherakara', + 'Calhoun', + 'North Decatur', + 'Lyepyel', + 'Trstenik', + 'Bad Worishofen', + 'Cacimba de Dentro', + 'Jouy-le-Moutier', + 'Padugupadu', + 'Neerpelt', + 'Al Harah', + 'Nederweert', + 'Shek Tong Tsui', + 'Villa Isabela', + 'Hinsdale', + 'Zandvoort', + 'Guoxing', + 'Castilleja de la Cuesta', + 'Sume', + 'Conceicao do Almeida', + 'Iati', + 'Traiguen', + 'Cluses', + 'Cottingham', + 'Calnali', + 'Bellaire', + 'Pinewood', + 'Massaranduba', + 'Peka', + 'Pocao de Pedras', + 'Tizi Rached', + 'Sinnai', + 'Itirapina', + 'Kayaralam', + 'Tanque Novo', + 'Malta', + 'Swansea', + 'Konstancin-Jeziorna', + 'Cassia', + 'Tejucuoca', + 'Tlahuelilpan', + 'Joaquim Gomes', + 'Mayuge', + 'Bom Sucesso', + 'Sake', + 'Settiyarpatti', + 'Monsenhor Tabosa', + 'Majitha', + 'Sawankhalok', + 'Oi', + 'Grumo Nevano', + 'Ayinikkad', + 'Tricase', + 'Clitheroe', + 'Grenchen', + 'Berezhany', + 'Saguday', + 'Firminy', + 'Panchgram', + 'Fairview Park', + 'Ipaba', + 'Figline Valdarno', + 'Frederikssund', + 'Regeneracao', + 'Sallanches', + 'Beckley', + 'Peso da Regua', + 'Banovici', + 'Correntes', + 'Giria', + 'Sa`adat Shahr', + 'Marsabit', + 'Pouso Redondo', + 'Ejea de los Caballeros', + 'Manassas Park', + "Wadi Halfa'", + 'Barrington', + 'Ilaka Atsinanana', + 'Ban Phe', + 'Wang Tau Hom', + 'South Hadley', + 'Peruwelz', + 'Damous', + 'Kaukauna', + 'Groves', + 'Kutiyana', + 'Manaquiri', + 'Shoufeng', + 'Ignacio de la Llave', + 'Nova Pazova', + 'Bulbula', + 'Yizhu', + 'Tagounite', + 'Dilasag', + 'Ginir', + 'Taxtako`pir', + 'Xintangcun', + 'Pottassheri', + 'Mosbrough', + 'Santa Magdalena', + 'Braunau am Inn', + 'Kolaccheri', + 'Melfi', + 'Estelle', + 'Mata Roma', + 'San Esteban', + 'Tadigadapa', + 'Chandia', + 'Lake St. Louis', + 'Stockelsdorf', + 'Toluprpatti', + 'Safety Harbor', + 'Lac', + 'Eutin', + 'Elias Fausto', + 'Usmanpur', + 'Denville', + 'El Segundo', + 'Peragamanna', + 'Sarotar', + 'Condeixa-a-Nova', + 'Zvenyhorodka', + 'Gudipallipadu', + 'San Rafael Cedros', + 'Sibinal', + 'Cinnaminson', + 'Puchov', + 'Svalyava', + 'Mannukara', + 'Ayikudi', + 'Challapalle', + 'Serra Dourada', + 'Crixas', + 'Guadarrama', + 'Kunzell', + 'Mavalli', + 'Upper Grand Lagoon', + 'Canon City', + 'Tifton', + 'Souto Soares', + 'Chuarrancho', + 'Paulino Neves', + 'Amfilochia', + 'Sidi Yakoub', + 'Tortum', + 'Condeuba', + 'Saint-Basile-le-Grand', + 'Kafr Zayta', + 'Itarantim', + 'La Garriga', + 'West Hempfield', + 'Kibungan', + 'Ruhango', + 'Canovellas', + 'Porteiras', + 'Guernica y Luno', + 'Caqueza', + 'Ilhota', + 'Knemis Dades', + 'Cheraro', + 'Terre Neuve', + 'Massapequa Park', + 'Kelheim', + 'Lons-le-Saunier', + 'Pernamitta', + 'Carlentini', + 'Kitanakagusuku', + 'Grojec', + 'Gennep', + 'Ribeiropolis', + 'Aricak', + 'Gachancipa', + 'Sinsina', + 'Tsararivotra', + 'Albal', + 'Milledgeville', + 'Rubeho', + 'Sao Simao', + 'Piranga', + 'Xinying', + 'Wadgassen', + 'Heysham', + 'Nayakanhatti', + 'Hinode', + 'Carius', + 'Kamenz', + 'Port Washington', + 'Karratha', + 'Macatuba', + 'Sitamau', + 'Penamiller', + 'Juazeirinho', + 'Avitanallur', + 'Wixom', + 'Upper Gwynedd', + 'Pendleton', + 'Brasnorte', + 'Saint-Cyr-sur-Loire', + 'Hannibal', + 'Baaqline', + 'Marosangy', + 'Tolongoina', + 'Etrotroka', + 'Ilakatra', + 'Ambila', + 'Marofoty', + 'Ambohitrolomahitsy', + 'Lazarivo', + 'Milanoa', + 'Isoanala', + 'Amboanjo', + 'Befotaka', + 'Tsarahonenana', + 'Antanimora Atsinanana', + 'Ankarongana', + 'Ambondromisotra', + 'Ambohitsimanova', + 'Anosivelo', + 'Manombo Atsimo', + 'Anosibe-Ifanja', + 'Beahitse', + 'Antsahavaribe', + 'Ambohipihaonana', + 'Mandritsara', + 'Ambolidibe Atsinanana', + 'Sadabe', + 'Dzitbalche', + 'Ghonchi', + 'Yangi Mirishkor', + 'Jayal', + 'Matauna', + 'Ad Dulu`iyah', + 'Santo Antonio do Leverger', + 'Hindarx', + 'Alauli', + 'Saint-Egreve', + 'Peraia', + 'Naula', + 'Santo Tomas de Janico', + 'Kakraul', + 'Tomas Oppus', + 'Itajobi', + 'Ban Rawai', + 'Ambalavayal', + 'Analanampotsy', + 'Shankar Saraiya', + 'Kawai', + 'Sikandra', + 'Lodwar', + 'Oulad Amrane', + 'Guisborough', + 'Brunico', + 'Bayt Ummar', + 'Ulubey', + 'Fortuna', + 'Arai', + 'Srikurmam', + 'San Juan Lalana', + 'Andranofasika', + 'Zarumilla', + "L'Ancienne-Lorette", + 'Ibitita', + 'Koroth', + 'Ramachandrapuran', + 'Ughara', + 'Geddes', + 'Serafina Corea', + 'Ginsheim-Gustavsburg', + 'Viroflay', + 'Yanggezhuang', + 'Berga', + 'Meltonakkal', + 'Bishunpura', + "Qal'at Mgouna", + 'Santana do Cariri', + 'Cercola', + 'Bou Hanifia el Hamamat', + 'Dirba', + 'Puerto Caimito', + 'Kombai', + 'Liuchuan', + 'Mers el Kebir', + 'Balmazujvaros', + 'Octeville', + 'Perupalem', + 'Acoyapa', + 'Hohenems', + 'Pozoblanco', + 'Myrtle Grove', + 'Garagoa', + 'Upper Saucon', + 'Adelphi', + 'Heber', + 'Namyslow', + 'San Jose de Chiquitos', + 'Hunfeld', + 'Hampton Bays', + 'Bridgeview', + 'Ashwaubenon', + 'Sarioglan', + 'Chavara Gramam', + 'Boki-Were', + 'Wondelgem', + 'Powder Springs', + 'Tibau do Sul', + 'Liuguoju', + "Long'e", + 'Morriston', + 'Aubange', + 'Dalain Hob', + 'Tekanpur', + 'Eggenstein-Leopoldshafen', + 'Guadalupe Victoria', + 'Huruta', + 'Baikatpur', + 'Malancha', + 'Shingucho-shingu', + 'Carovigno', + 'Stockerau', + 'Governador Celso Ramos', + 'Glace Bay', + 'Cubellas', + 'McKinleyville', + 'Tobre', + 'Rio Bueno', + 'Ginatilan', + 'Kronach', + 'Zinapecuaro', + 'Carlopolis', + 'Mari`', + 'Findikli', + 'Masse', + 'Iziaslav', + 'Naranattenvanpatti', + 'Nidgundi', + 'Sidi Daoud', + 'High Blantyre', + 'Pallikapuzha', + 'Douar Lamjaara', + 'Ramayampet', + 'Dehaqan', + 'Laconia', + 'Tubaran', + 'Dazhangzicun', + 'Dazhangzi', + 'Dhulkot', + 'Belle Glade', + 'Aklanpa', + 'Navalmoral de la Mata', + 'Fetromby', + 'Bruckmuhl', + 'Khed', + 'Colonial Park', + 'Ngara', + 'Morteros', + 'Sao Joao dos Poleiros', + 'Farmingville', + 'Vatutine', + 'Soumagne', + 'Ettaiyapuram', + 'Majra', + 'New Milford', + 'Miqiao', + 'Heidenau', + 'Azaourisse', + 'Chambellan', + 'Laferriere', + 'Ighram', + 'Bermeo', + 'Benesov', + 'La Quiaca', + 'Sada', + 'Agaram', + 'Boa Vista do Tupim', + 'Annonay', + 'Pleszew', + 'Bedigoazon', + 'Lamas', + 'Ashmyany', + 'Colesberg', + 'Canutama', + 'Thale', + 'Hosakote', + 'Le Pre-Saint-Gervais', + 'Bambara-Maounde', + 'Nerang', + 'Japaratuba', + 'Nerviano', + 'Pampa', + 'Jask', + 'Alfajayucan', + 'Ban Tha Mai I', + 'Moraga', + 'Latifpur', + 'Sayarpuram', + 'Linnei', + 'Korem', + 'Maltby', + 'Rampur Jalalpur', + 'Rubano', + 'Lerum', + 'Sliema', + 'Pulimel', + 'Janakkala', + 'Bitburg', + 'Defiance', + 'Sao Pedro do Sul', + 'Pran Buri', + 'Finnentrop', + 'Madanpur', + 'Braunstone', + 'Fiorano Modenese', + 'Bostonia', + 'Haslingden', + 'Boden', + 'Azeffoun', + 'Meiti', + 'North Hykeham', + 'Shahkot', + 'Hot Springs Village', + 'Ain Feka', + 'Xixinzhuangzhen', + 'Vallegrande', + 'Wittenberge', + 'Lillerod', + 'Acharipallam', + 'Devizes', + 'Tsuiki', + 'Hrubieszow', + 'Trzcianka', + 'Montceau-les-Mines', + 'Saltash', + 'Vechur', + 'Mattoon', + 'Upper Chichester', + 'Washougal', + 'Haslemere', + 'Achaljamu', + 'Ratba', + 'Orastie', + 'Brixham', + 'Yabuki', + 'Salinas de Hidalgo', + 'Gemert', + 'Bhainsoda', + 'Makinsk', + 'Asten', + 'Dongjiangshui', + 'Saint Ives', + 'Kadikkad', + 'Sidi Lamine', + 'Bad Lippspringe', + 'Vazhani', + 'Baronissi', + 'Minamichita', + 'Daireaux', + 'Altintas', + 'Kodikulam', + 'Wyckoff', + 'Cerea', + 'Keetmanshoop', + 'Rijen', + 'Busolwe', + 'Druzhba', + 'Maroochydore', + 'Astara', + 'Montornes del Valles', + 'Beinan', + 'Ambares-et-Lagrave', + 'Sinuni', + 'Kaliro', + 'Puliyankunnu', + 'Marib', + 'Famy', + 'Sierre', + 'Roxana', + 'Kamavarapukota', + 'Weehawken', + 'Cestas', + 'Tromsdalen', + 'Sao Paulo do Potengi', + 'Fazakerley', + 'El Rosario', + 'Sudak', + 'Batuco', + 'Kauhava', + 'Truckee', + 'Orta Nova', + 'Pionki', + 'Villeneuve-Loubet', + 'Tsundupalle', + 'Solothurn', + 'Palmetto Estates', + 'Ricany', + 'Windlesham', + 'Vila Bela da Santissima Trindade', + 'Latsia', + 'Buntok', + 'Sunland Park', + 'Ouaouzgane', + 'Posoltega', + 'Connahs Quay', + "'Ain Abessa", + 'Masamagrell', + 'Masif Sarsink', + 'Dhobauli', + 'Bauria', + 'Puerto Carreno', + 'Humacao', + 'Attappampatti', + 'Egirdir', + 'Havelock', + 'Yaglidere', + 'Young', + 'El Pinon', + 'Nandigaon', + 'Bovisio Masciago', + 'Djouab', + 'San Miguel de Salcedo', + 'Maardu', + 'Chiva', + 'Swift Current', + 'Campo do Brito', + 'Chestnuthill', + 'Kadod', + 'Nuevo San Juan Parangaricutiro', + 'Shahba', + 'Konigstein im Taunus', + 'Thandla', + 'Kushima', + 'Donna', + 'New Port Richey', + 'Chinampa de Gorostiza', + 'Agua Clara', + 'Vimodrone', + 'Ribat Al Khayr', + 'Bytow', + 'Diksmuide', + 'Arakkal', + 'Yerbas Buenas', + 'Preganziol', + 'Plumstead', + 'Livinjipuram', + 'Burstadt', + 'Sobrado de Paiva', + 'Leixlip', + 'Boysun', + 'Dera', + 'Tengampudur', + "Bek'oji", + 'Kings Park', + 'Penzberg', + 'Takhatgarh', + 'Sendurai', + 'Roche-a-Bateau', + 'Hirna', + 'Katsuura', + 'Ponte de Sor', + 'Baicoi', + 'Holzkirchen', + 'Bredbury', + 'Chalala', + 'Konodimini', + 'Kukes', + 'Iluppur', + 'Fuying', + 'Fuyingzicun', + 'Dour', + 'Kodumudi', + 'Glanerbrug', + 'Klippansbruk', + 'Aston', + 'La Vista', + 'Cabeceiras de Basto', + 'Pisticci', + 'Firestone', + 'Saalfelden am Steinernen Meer', + 'Kattiyeri', + 'Gikongoro', + 'Balighattam', + 'Porto Acre', + 'Gonegandla', + 'Ban Wang Nok Aen', + 'Verdun', + 'Pazhayannur', + 'Piriyapatna', + 'East Greenbush', + 'Jalpa de Mendez', + 'Saran', + 'Nassjo', + 'Rotselaar', + 'Erumad', + 'Harborcreek', + 'Havi Bhauar', + 'Zafra', + 'Murraysville', + 'Deoria', + 'Ocho Rios', + 'Nea Makri', + 'Chateaurenard', + 'Phrae', + 'Kundal', + 'Campagna', + 'Murehwa', + 'Sao Caetano de Odivelas', + 'Zequ', + 'Banstead', + 'Kumage', + 'Riemst', + 'Przasnysz', + 'Podalakur', + 'Federacion', + 'Bassum', + 'Kruibeke', + 'Hueytown', + 'Kakkalapalle', + 'Whickham', + 'Beaver Dam', + 'Agourai', + 'Loxstedt', + 'Zvecan', + 'Berber', + 'Grangemouth', + 'Arani', + 'Sidi Ettiji', + 'Bogatynia', + 'Tawargeri', + 'Aracagi', + 'Ban Na Sai', + 'Calera', + 'Khirhar', + 'Keynsham', + 'Barangka', + 'Itapiranga', + 'Shiraoi', + 'Lake Mary', + 'Ittiva', + 'Xiaolongtan', + 'Salitre', + 'Glenmont', + 'Millbrook', + 'Mullanwala', + 'Tadaoka-higashi', + 'Seeheim-Jugenheim', + 'Red Wing', + 'Anisoc', + 'Tantega', + 'Tiahounkossi', + 'Medicina', + 'Epitacio Huerta', + 'Cleckheaton', + 'Pratteln', + 'Micoud', + 'Bull Run', + 'Brod', + 'Douar Tabouda', + 'El Escorial', + 'La Algaba', + 'Valu lui Traian', + 'Itororo', + 'Shpola', + 'Piquet Carneiro', + 'Ad Dis', + 'Banovce nad Bebravou', + 'Leopoldshohe', + 'Wurzen', + 'Clearlake', + 'Mariestad', + 'Sedan', + 'Bargur', + 'Porec', + 'Zirara', + 'Ceadir-Lunga', + 'Noordwijkerhout', + 'Shek Wai Kok', + 'Khaniadhana', + 'Ibipeba', + 'Mangueirinha', + 'Marienberg', + 'Reinheim', + 'Lomas de Sargentillo', + 'Getulio Vargas', + 'Morton', + 'Kaatsheuvel', + 'Macetown', + 'Burbaliq', + 'Dilijan', + 'The Mumbles', + 'Pannaipuram', + 'Tukums', + 'Mauguio', + 'Three Lakes', + 'Rio Linda', + 'Saint-Jean-de-la-Ruelle', + 'San Juan Bautista', + 'Soumpi', + 'Wailuku', + 'Bijni', + 'Puerto El Triunfo', + 'Buritama', + 'Cidreira', + "N'Goussa", + 'Country Club Hills', + 'Lask', + 'Ilkhchi', + 'Ilkhechi', + 'La Sierpe', + 'Mohan Eghu', + 'Ippy', + 'San Giovanni Valdarno', + 'Heumen', + 'Barkot', + 'Pirque', + 'Eppelborn', + 'Miyazu', + 'Tongluo', + 'Paragaticherla', + 'Humble', + 'Menomonie', + 'Lakhipur', + 'Bhai Rupa', + 'Placido de Castro', + 'Mensora', + 'Cabaceiras do Paraguacu', + 'Guaymate', + 'Slany', + 'Itaquitinga', + 'Domchanch', + 'Indiaroba', + 'Coaraci', + 'Santa Maria das Barreiras', + 'Ramon Santana', + 'Honefoss', + 'West Richland', + 'Middelfart', + 'Tichi', + 'Sujina', + 'Regenstauf', + 'Cattolica', + 'Wentang', + 'Raunheim', + 'Kade', + 'Odumase', + 'Tamallalt', + 'Bogucice', + 'Parali', + 'Mangrauni', + 'Segbwema', + 'Marly-le-Roi', + 'Vero Beach', + 'Ahmetli', + 'Ledeberg', + 'Liangyi', + 'Ban Cho Ho', + 'Rentachintala', + 'Thi Tran Ngai Giao', + 'Hovelhof', + 'Brackenheim', + 'Mapiri', + 'Santa Maria Petapa', + 'Puerto Pilon', + 'Pedregulho', + 'Gussago', + 'Horodok', + 'Torre Maggiore', + 'Sunagawa', + 'Caiaponia', + 'Cassano al Ionio', + 'Thompson', + 'Ciudad Guadalupe Victoria', + 'Haji Shah', + 'Berezan', + 'Langrucun', + 'Espartinas', + "Sant'Elpidio a Mare", + 'Chinde', + 'Al Ghat', + 'Qarqin', + 'Qusar', + 'Cowley', + 'Pilappulli', + 'Mudakkiraye', + 'East Highland Park', + 'Amba Icharua', + 'Alpignano', + 'Ukiah', + 'Slubice', + 'Fleron', + 'Shintomi', + 'Adelfia', + 'Zapotlan de Juarez', + 'Jinjicun', + 'Jinji', + 'Tafresh', + 'Hebburn', + 'Linbian', + 'Ashby de la Zouch', + 'Milanowek', + 'Ham Lake', + 'Chorbogh', + 'Jasper', + 'Grimari', + 'Bobangui', + 'Kalundborg', + 'Rasivarai Tottam', + 'Reggello', + 'Antanambao Mahatsara', + 'Ervadi', + 'Braniewo', + 'Rajbalhai', + 'Hillcrest Heights', + 'Sabotsy', + 'Ban Lam Narai', + 'Enfield Lock', + 'Oyodo', + 'Fairburn', + 'Escoublac', + 'Mifune', + 'Dighaun', + 'Ujre', + 'Ban Nong Han', + 'Kirchhain', + 'Dahibhat Madhopur', + 'Loma Plata', + 'Kilwinning', + 'Chopadandi', + 'Mohanur', + 'San Casciano in Val di Pesa', + 'Lake Wales', + 'Fillmore', + 'Les Herbiers', + 'Ojus', + 'Wardenburg', + 'Nanbu', + 'Tohoku', + 'Sakardih', + 'Encruzilhada', + 'Churriana de la Vega', + 'Glenn Heights', + 'Albemarle', + 'Katosi', + 'Nakanoto', + 'Pianco', + 'Charqueada', + 'Ciney', + 'Cayetano Germosen', + 'Bordj Mokhtar', + 'Edmundston', + 'Cloverly', + 'Hannut', + 'Gurh', + 'Lufeng', + 'Rajnagar', + 'Auburndale', + 'Pupiales', + 'Altena', + 'Rawa Mazowiecka', + 'Bilohirsk', + 'Vedelago', + 'Gasparillo', + 'Neopolis', + 'Bykhaw', + 'Boshruyeh', + 'Pearl River', + 'Pelhrimov', + 'Kierspe', + 'Peer', + 'Adjahome', + 'Batangafo', + 'Goulmima', + 'Curacautin', + 'Nilaiyur', + 'Spanish Springs', + 'Hilltown', + 'Westbury', + 'Lugu', + 'Cajari', + 'Hanover', + 'Uhersky Brod', + 'Petersberg', + 'Islam Qal`ah', + 'Portachuelo', + 'Baro', + 'Dyer', + 'Pudu', + 'Poing', + 'Raikal', + 'Mastchoh', + 'Ntungamo', + 'Las Cabezas de San Juan', + 'Pocking', + 'Dentsville', + 'Bosobolo', + 'Toro', + 'Pamiers', + 'Hatti', + 'Mahesh Khunt', + 'Passa Quatro', + 'Kastoria', + 'Freienbach', + 'Kesath', + 'Faxinal', + 'Gokavaram', + 'Tahlequah', + 'Outat Oulad Al Haj', + 'Poco Fundo', + 'Nova Resende', + 'Hollins', + 'Libiaz', + 'Karema', + 'Bou Hadjar', + 'Stone', + 'Khargapur', + 'Khirpai', + 'Puan', + 'Zhongzai', + 'Radford', + 'Taohongpozhen', + 'Malnate', + 'Divrigi', + 'Caridade', + 'Panukulan', + 'Pasaquina', + 'Brakel', + 'Hude', + 'Aki', + 'Moreau', + 'Angara-Debou', + 'Kingsborough', + 'Zitorada', + 'Kirchlengern', + 'Barra de Santo Antonio', + 'Straelen', + 'Denby Dale', + 'Phirangipuram', + 'Erba', + 'Guben', + 'Ubrique', + 'Sebt Ait Saghiouchen', + 'East Longmeadow', + 'Juchique de Ferrer', + 'Arteche', + 'Bagnacavallo', + 'Fairview Heights', + 'Usgao', + 'Nunna', + 'Mahalandi', + 'Chettinayakkanpatti', + 'Cosautlan', + 'Jambalo', + 'Sulzbach', + 'Nova Olimpia', + 'North Arlington', + 'Rolleston', + 'Barnia', + 'Moussoro', + 'Chinacota', + 'Wemmel', + 'Halver', + 'Ban Thung Tam Sao', + 'Galivedu', + 'Kakching', + 'Grossostheim', + 'Arenys de Mar', + 'Huong Canh', + 'Bad Essen', + 'Novoukrainka', + 'Kargil', + 'Grosse Pointe Woods', + 'Vadugappatti', + 'Villa San Jose', + 'Piru', + 'Carsibasi', + 'La Falda', + 'Ouled Chebel', + 'Crawfordsville', + 'Sahatavy', + 'Muscle Shoals', + 'Erwitte', + 'Baipingshan', + 'Mount Dora', + 'Westport', + 'Sunnyside', + 'Sananduva', + 'Shuzenji', + 'Bree', + 'Yoshinogari', + 'Elsen', + 'Bandar Murcaayo', + 'Guelendeng', + 'Srbobran', + 'Wallisellen', + 'Poplar Bluff', + 'Yuvileine', + 'Xianxi', + 'Changji', + 'Khunti Dhanaili', + 'Northbridge', + 'Bargteheide', + 'Schmelz', + 'Moroto', + 'Lyantonde', + 'Leini', + 'Birstall', + 'Noniya', + 'Umbertide', + 'Fort Drum', + 'Shuili', + 'Tremedal', + 'Shahriston', + 'Kodala', + 'Merchtem', + 'Arachchalur', + 'Sohtha', + 'Malhipur', + 'Bacuri', + "'Ayn Bni Mathar", + 'Acarape', + 'Barharwa Kalan', + 'Welby', + 'Sao Francisco do Guapore', + 'Birsinghpur', + 'Wiefelstede', + 'Dungannon', + 'Colle Salvetti', + 'Yorkton', + 'Zumarraga', + 'Raposos', + 'Kabo', + 'Omalur', + 'Center Point', + 'Carcarana', + 'Utinga', + 'Domoni', + 'Kassorola', + 'Nawnghkio', + 'Berriche', + 'Ripon', + 'Madukkur', + 'Ivanava', + 'Sabana de La Mar', + 'Nobsa', + 'General Villegas', + 'Martinsicuro', + 'Al Lataminah', + 'San Antonio Oeste', + 'Acahay', + 'Momil', + 'Brus', + 'Yotoco', + 'Taishacho-kizukikita', + 'Oyten', + 'Wendlingen am Neckar', + 'Kasumi', + 'Antsahanoro', + 'Goundam', + 'Radzionkow Nowy', + 'Ispica', + 'Bad Bentheim', + 'Naama', + 'Ambalabe', + 'Llanquihue', + 'Benjamin Aceval', + 'Montalvo', + 'Eghezee', + 'Bikou', + 'Az Zaydiyah', + 'Jalalpur', + 'Glen Allen', + 'Carhue', + 'Santomera', + 'Ransiki', + 'Targu Secuiesc', + 'Manamelkudi', + 'Balasamudram', + 'Parkway', + 'Khirbat Ghazalah', + 'Longchang', + 'Sparti', + 'Stepney', + 'Massakory', + 'Mukhtarpur Salkani', + 'Fiano Romano', + 'Artesia', + 'Garou', + 'Tadikalapudi', + 'San Martino Buon Albergo', + 'Chickasha', + 'Opa-locka', + 'Kunzelsau', + 'South Middleton', + 'El Penol', + 'Giaveno', + 'Oteapan', + 'Orimattila', + 'Palma Campania', + 'Yunshan', + 'Neratovice', + 'Turgutalp', + 'Oyamazaki', + 'Freiberg am Neckar', + 'Hermitage', + 'Kabugao', + 'Cotorra', + 'Ikast', + 'Hajdunanas', + 'Vitthalapuram', + 'Caykara', + 'Aranyaprathet', + 'Lemay', + 'Jicin', + 'Al Hibah', + 'Walnut Park', + 'Basford', + 'Landerneau', + 'eMuziwezinto', + 'Roznov pod Radhostem', + 'Burrillville', + 'Singhwara', + 'Santa Anita', + 'Altinopolis', + 'Stahnsdorf', + 'Porumamilla', + 'Silute', + 'Do`stobod', + 'Vodil', + 'Handlova', + 'San Pedro de Lloc', + 'Xiangjiaba', + 'Gokarna', + 'Taree', + 'Khutauna', + 'Saraikela', + 'Izamal', + 'Nakhon Nayok', + 'Ansfelden', + 'Brzesko', + 'Stallings', + 'Kozienice', + 'Bandora', + 'Hostomel', + 'Rosu', + 'Mastic Beach', + 'Bileh Savar', + 'Kanhauli Manohar', + 'Svitavy', + 'Tocantins', + 'Ampahimanga', + 'Attur', + 'Itahri', + 'Aruvapalam', + 'Castellaneta', + 'Harenkarspel', + 'Koprukoy', + 'Chotala', + 'Alsfeld', + 'Riversdale', + 'Segoubougou', + 'Ganeshpur', + 'West Norriton', + 'As Sukhnah', + 'Chorfa', + 'Readington', + 'Ocean Pointe', + 'Timezgana', + 'Huarmey', + 'Dyersburg', + 'South Houston', + 'Banora Point', + 'Kotoura', + 'Hibbing', + 'Talsint', + 'River Falls', + 'Bingawan', + 'Four Corners', + 'Al Qbab', + 'Baharu', + 'Pujili', + 'Schluchtern', + 'Alcaniz', + 'Guerande', + 'Caldera', + 'Pielisjarvi', + 'Loimaa', + 'Agiripalle', + 'Troutdale', + 'Bni Tajjit', + 'Westwood', + 'Al Awjam', + 'Ban Kao', + 'Sikeston', + 'Rygge', + 'Castenaso', + 'Sayville', + 'Venustiano Carranza', + 'Voss', + 'Kittur', + 'Tyldesley', + 'Caravaggio', + 'Sylvan Lake', + 'Mafune', + 'Carlet', + 'Upala', + 'Santa Cruz Mulua', + 'Zegzel', + 'East Barnet', + 'Port-de-Bouc', + 'Easthampton', + 'Forks', + 'La Grange', + 'Jaypul', + 'Los Muermos', + 'Markranstadt', + 'Quarteira', + 'Noale', + 'Bang Phae', + 'Upton', + "'Ain Babouche", + 'Douar Azla', + 'Yeni Suraxani', + 'Buckley', + 'Jakkampalaiyam', + 'Chennur', + 'Ranong', + 'Bumpe', + 'Rustampur', + 'Simcoe', + 'Math Lohiyar', + 'Ustron', + 'Kamayakkavundanpatti', + 'Subachoque', + 'Jacupiranga', + 'Sultanabad', + 'Kujwa', + 'Parrita', + 'Ambarakaraka', + 'Gubin', + 'Bals', + 'Medjana', + 'Ubata', + 'Chaona', + 'Cherukunnu', + 'Khusropur', + 'Saraland', + 'Tarqui', + 'El Ach', + 'Diabigue', + 'Masmouda', + 'Frogn', + 'Pilkha', + 'Bakarpur Ogairah', + 'Nonantola', + 'Bovolone', + 'Prinzapolka', + 'Canudos', + 'Kajur', + 'Nowogard', + 'Surappalli', + 'Panajachel', + 'Chinggil', + 'Birhana', + 'Michelstadt', + 'Hazro', + 'Nyahanga', + 'Anantapalle', + 'Ait Yaazem', + 'Chai Prakan', + 'Johnstone', + 'Wendelstein', + 'Aurahi', + 'Aquitania', + 'Ottur', + 'Bouchabel', + 'Viskovo', + 'Fatipura', + 'Ottakkadai', + 'Bruggen', + 'South River', + 'Banigbe', + 'Semdinli', + 'Grossenkneten', + 'Kolluru', + 'Ramewadi', + 'Owase', + 'Santiago Tulantepec', + 'Wohlen', + 'Domont', + 'Mecheraa Asfa', + 'Olecko', + 'Tankal', + 'Federal', + 'Dalachi', + 'Kalanjur', + 'Eloy', + 'Quiindy', + 'Bhiloda', + 'Huyuk', + 'Middle Smithfield', + 'Yaojia', + 'Makhu', + 'Czernica', + 'Fartura', + 'Punta Umbria', + 'Vontimitta', + 'Safo', + 'Tachiarai', + 'Montbrison', + 'Badshahpur', + 'Baleyara', + 'Sulechow', + 'Serarou', + 'Mikkabi', + 'Ukrainka', + 'Strathroy', + 'Ayyampalaiyam', + 'Marbach am Neckar', + 'Marupe', + 'North Fayette', + 'Dickson', + 'Gardendale', + 'Agios Ioannis Rentis', + 'Bni Quolla', + 'Grovetown', + 'Stone Ridge', + 'Sivapuram', + 'Lady Lake', + 'Bay Village', + 'Telfs', + 'Al Hazm', + 'Mayilur', + 'Scordia', + 'Ranohira', + 'Duxbury', + 'Tourlaville', + 'Agudo', + 'Penugonda', + 'Fort Mohave', + 'Vaureal', + 'Hewitt', + 'Sulphur Springs', + 'Eilenburg', + 'Worcester Park', + 'Bou Djeniba', + 'Doganhisar', + 'Mahavelona', + 'Kayanna', + 'Samarate', + 'Mountain Home', + 'Ciudad de Huitzuco', + 'Az Zintan', + 'Cajueiro', + 'Preetz', + 'Azalea Park', + 'Zeulenroda', + 'Americus', + 'Lithia Springs', + 'Qazyan', + 'Grandville', + 'Rahon', + 'Marahom', + 'Khat Azakane', + 'Girua', + 'Ya`bad', + 'Locarno', + 'Aue', + 'Myrza-Ake', + 'Bracebridge', + 'Fort Hunt', + 'Satiro Dias', + 'Orsay', + 'Rani Shakarpura', + 'Sapatgram', + 'Utnur', + 'Turkeli', + 'Blanquefort', + 'Kumaranallur', + 'Sidi Azzouz', + 'Hoganas', + 'Sughrain', + 'Summerside', + 'Bethulie', + 'Tsiningia', + 'Antindra', + 'Andapafito', + 'Manompana', + 'Bevonotra', + 'Betanty', + 'Mandrosonoro', + 'Ankazondandy', + 'Androrangavola', + 'Alarobia', + 'Inanantonana', + 'Ambalatany', + 'Andemaka', + 'Vohiposa', + 'Anjangoveratra', + 'Leanja', + 'Bekitro', + 'Ambohibe', + 'Tangainony', + 'Antsenavolo', + 'Analila', + 'Mangabe', + 'Baltit', + 'Tullinge', + 'Kafia Kingi', + 'Manafwa', + 'Buwama', + 'Sardoba', + 'Ishtixon Shahri', + 'Mong Duong', + 'Longji', + 'Koulamoutou', + 'Asara', + 'Dandu Mailaram', + 'Al Mazar ash Shamali', + 'Watrap', + 'Illingen', + 'Rumilly', + 'Chilgazi', + 'Weener', + 'Zemrane', + 'Neriyamangalam', + 'Dengka', + 'Dianga', + 'Usharal', + 'Caidat Sidi Boubker El Haj', + 'Youngsville', + 'Canmore', + 'East Finchley', + 'Ambohimalaza', + 'Guioyo', + 'Lewes', + 'Nanattuparai', + 'San Cesareo', + 'The Dalles', + 'Tasil', + 'Fussen', + 'Raiganj Bazar', + 'Hammam al `Alil', + 'Chornobaivka', + 'Yaypan', + 'Sao Lourenco da Serra', + 'St. Simons', + 'Vicente Guerrero', + 'Balneario do Rincao', + 'Saint-Amand-les-Eaux', + 'Jawalgeri', + 'Saint-Leu-la-Foret', + 'Kizhur', + 'Kudali', + 'Cruz Machado', + 'Ouamri', + 'Antadinga', + 'Este', + 'Yurihama', + 'Chittayankottai', + 'Neykkarappatti', + 'Mwingi', + 'Erlensee', + 'Finsterwalde', + 'Hayange', + 'Tuineje', + 'Chertsey', + 'Sukth', + 'Valavakattumula', + 'Mohanpur', + 'Amarwara', + 'Ambohidrapeto', + 'Bahutal', + 'Landen', + 'Zhytkavichy', + 'Kyabe', + 'Chivolo', + 'Viera West', + 'Ghomrassen', + 'Gentbrugge', + "L'Oulja", + 'Patapatnam', + 'Elbeuf', + 'Tagazhi', + 'Ishidoriyacho-eso', + 'Motru', + 'Mandiakui', + 'Coos Bay', + 'South Hayling', + 'Fontainebleau', + 'Valeggio sul Mincio', + 'Tarquinia', + 'Marco Island', + 'Suchteln', + 'Despujols', + 'Summerfield', + 'Alotau', + 'Androy', + "Stara L'ubovna", + 'Hongsi', + 'Brahmadesam', + 'Bellmore', + 'Alabat', + 'Schwarzenberg', + 'Campanha', + 'Manatanna', + 'Codru', + 'Konigslutter am Elm', + 'Gargzdai', + 'Apora', + 'Sertanopolis', + 'Xiaqiaotou', + 'Bailesti', + 'Penicuik', + 'Rasnov', + 'Cumaru', + 'Comarapa', + 'Middleburg Heights', + 'Dunaivtsi', + 'Verneuil-sur-Seine', + 'Ban Dung', + 'Karambakkudi', + 'Lakamane', + 'Petite-Synthe', + 'Adwick le Street', + 'Alpine', + 'Quixelo', + 'Saint-Pierre-des-Corps', + 'Vlagtwedde', + 'Paso de Carrasco', + 'Sayalkudi', + 'Suchindram', + 'Nyasvizh', + 'Alexandreia', + 'San Giovanni in Fiore', + 'Kursumlija', + 'Calbuco', + 'Marmeleiro', + 'Lower Salford', + 'Schaesberg', + 'Heggadadevankote', + 'Fairhaven', + 'Haddada', + 'Aladag', + 'Piacabucu', + 'Bastogne', + 'Ostrov', + 'Zunil', + 'Sint-Kruis', + 'Eilendorf', + 'Walldorf', + 'Floral Park', + 'Greater Napanee', + 'Barentu', + 'Cerejeiras', + 'Skvyra', + 'Turffontein', + 'Vijayapuri North', + 'Wadern', + 'Gheorgheni', + 'Addlestone', + 'Vellikulangara', + 'Highland Village', + 'Lam Luk Ka', + 'Dighirpar', + 'Serta', + 'Concorezzo', + 'Benetuser', + 'Mahires', + 'Davutlar', + 'Brusciano', + 'Kulhudhuffushi', + 'Beek', + 'Drensteinfurt', + 'Kishundaspur', + 'Udayagiri', + 'Galvan', + 'Bar', + 'Sidi Allal el Bahraoui', + 'Alvaraes', + 'Villalbilla', + 'Gryfice', + 'Codroipo', + 'Mario Campos', + 'Prospect Heights', + 'Nidiyanga', + 'Vari', + 'Tupi Paulista', + 'Baghlia', + "Hammam M'Bails", + 'Demerval Lobao', + 'Valabhipur', + 'Toma', + 'Sahambala', + 'Toul', + 'Dembeni', + 'Gatesville', + 'Lonigo', + 'Tamazouzt', + 'Xiaozhengzhuang', + 'Pawai', + 'Indianola', + 'La Lucila', + 'Osowa', + 'Jatauba', + 'Gandevi', + 'Brofodoume', + 'Chhapra Bahas', + 'Simmerath', + 'Saint-Julien-en-Genevois', + 'Dassari', + 'Taromske', + 'Odaiyakulam', + 'Overland', + 'Bruck an der Mur', + 'Vatomandry', + 'Mandialaza', + 'Hadjadj', + 'Kavarna', + 'Feke', + 'Rypin', + 'Le Pecq', + 'Hugo', + 'Miedzyrzec Podlaski', + 'Zhutian', + 'Elkton', + 'Dhusar Tikapatti', + 'Srimushnam', + 'Seven Oaks', + 'Kodikkulam', + 'Vallirana', + 'Kadamakudi', + 'Ascheberg', + 'Ban Samo Khae', + 'Port Orchard', + 'Rutland', + 'Tlaltetela', + 'Tapiramuta', + 'Pewaukee', + 'Lake Country', + 'Colonia Leopoldina', + 'Taucha', + 'Ropczyce', + 'Grottammare', + 'Tanakpur', + 'Saviano', + 'Opelousas', + 'Joao Neiva', + 'Kabayan', + 'Ash Shaddadah', + 'Serinyol', + 'Niceville', + 'Haftkel', + 'Cadoneghe', + 'Lentate sul Seveso', + 'Ixhuatlan del Sureste', + 'Adrasmon', + 'Maliana', + 'Cholai', + 'Tarancon', + 'Victor', + 'Whakatane', + 'Diang', + 'Breisach am Rhein', + 'Salonta', + 'Puluvappatti', + 'Dhani Sukhan', + 'Centre de Flacq', + 'Belaur', + 'Kunithala', + 'Longmeadow', + 'Dhumnagar', + 'Vardannapet', + 'Oarai', + 'Krapkowice', + 'Palagiano', + 'Waterville', + 'Palagonia', + 'Altopascio', + 'Kandla Port', + 'Chethakal', + 'Mahudha', + 'Ras El Oued', + 'San Bartolome Jocotenango', + 'Macedo de Cavaleiros', + 'Yorito', + 'Rahden', + 'Lara', + 'Ouadhia', + 'Ain Mediouna', + 'Ramada', + 'Miguelturra', + 'Laurentides', + 'Goubellat', + 'Garrel', + 'Novo Airao', + 'Gonohe', + 'Kannampalaiyam', + 'Al Mu`abbadah', + 'Pijino del Carmen', + 'Mansingha', + 'Sulat', + 'Akambadam', + 'Kalanadu', + 'Rupbas', + 'Kasimkota', + 'Uusikaupunki', + 'San Antonio Palopo', + 'Vieux Fort', + 'Patton', + 'Diafarabe', + 'Vendome', + 'Hennebont', + 'Sonapur', + 'Herisau', + 'Ardestan', + 'Quimavango', + 'General Pinedo', + 'Northallerton', + 'Titel', + 'Thibodaux', + "Sered'", + 'Itatim', + 'Susanville', + 'Santa Juliana', + 'Mirangaba', + 'Lindas', + 'Trisshileri', + 'Usuda', + 'Toyoyama', + 'Hille', + 'Correia Pinto', + 'Guasca', + 'Puduppatti', + 'Minamiminowa', + 'Lubbenau/Spreewald', + 'Lymington', + 'Carugate', + 'Orizona', + 'La Montanita', + 'Dubacherla', + 'Whitewater', + 'Vynnyky', + 'Campina da Lagoa', + 'Baeza', + 'Lynden', + 'Ribnitz-Damgarten', + 'North Strabane', + 'San Jacinto Amilpas', + 'Zulte', + 'Tarur', + 'Maruim', + 'Langenberg', + 'Eravattur', + 'Newberry', + 'Bharanikavu Tekku', + 'Wolf Trap', + 'Coelemu', + 'Mennecy', + 'Sahar', + 'Steffisburg', + 'Castillo', + 'Morges', + 'Mwinilunga', + 'Pochampalli', + 'Hayden', + 'North Whitehall', + 'Southern Pines', + 'Kimwanyi', + 'Beko', + 'Dieburg', + 'Taima', + 'Hilvarenbeek', + 'Niepolomice', + 'Ebersbach an der Fils', + 'Si Satchanalai', + 'Turkaguda', + 'Damdama', + 'Grain Valley', + 'Bucimas', + 'Beernem', + 'Aabenraa', + 'Xixucun', + "'Ain el Arbaa", + 'Todi', + 'Ifanadiana', + 'Azzano Decimo', + 'Beaucaire', + 'Carterton', + "Nova Brasilandia d'Oeste", + 'Mount Clemens', + 'Binningen', + 'Yakumo', + 'Tiran', + 'Copparo', + 'Dhanot', + 'Renai', + 'Melonguane', + 'Namala Guimbala', + 'Bayt Saham', + 'Hedongcun', + 'Bububu', + 'Ponders End', + 'Ince-in-Makerfield', + 'Tsukumiura', + 'Colorado do Oeste', + 'Gaillac', + 'Wenwu', + 'Valmontone', + 'Bhit Bhagwanpur', + 'Kajha', + 'Dhemaji', + 'Soavina', + 'Mitchell', + 'Mecitozu', + 'Schiffweiler', + 'Marivorahona', + 'Arkivan', + 'Mindelheim', + 'Shchuchyn', + 'Ochiai', + 'Zarah Sharan', + 'Ban Tha Pho', + 'Northborough', + 'Le Vesinet', + 'Mvurwi', + 'Bengonbeyene', + 'Mezotur', + 'Balkonda', + 'Nioro du Rip', + 'Campulung Moldovenesc', + 'Ostroh', + 'Chenlu', + 'Baile an Bhiataigh', + 'Donacarney', + 'Yazu', + 'Capilla de Guadalupe', + 'Porthcawl', + 'Leso', + 'Chubbuck', + 'Molinella', + 'Jiaojiazhuang', + 'Toui', + 'Manujan', + 'Langenau', + 'Rajapur', + 'Coto de Caza', + 'Nailsea', + 'Manjil', + 'Boudjima', + 'Longwood', + 'Guinguineo', + 'Dammaj', + 'Palmitos', + 'Leopoldsburg', + 'Langenthal', + 'Loma de Cabrera', + 'Serpa', + 'Mayoyao', + 'Ashikita', + 'Cheramkod', + 'Solapuram', + 'Sukhothai', + 'Porto San Giorgio', + 'Tobetsu', + 'Dragasani', + 'Boppard', + 'Kara-Kulja', + 'Frecheirinha', + 'Fort Leonard Wood', + 'Tatahuicapan', + 'Rakvere', + 'Oswestry', + 'Jurawanpur Karari', + 'Olmue', + 'Dewangarh', + 'Mangqu', + 'Molnlycke', + 'Narendrapatnam', + 'Kolakaluru', + 'Antarvedi', + 'Sin-le-Noble', + 'Calumpang', + 'Luce', + 'Chembagaramanpudur', + 'Bilpura', + 'Porto Empedocle', + 'Templin', + 'Ermua', + 'Julita', + 'Shively', + 'Cumru', + 'Ponsacco', + 'Mouiat Ouennsa', + 'Sundarpur', + 'Crusinallo', + 'Dalanping', + 'Shizukuishi', + 'Mezokovesd', + 'Bhagta', + 'Bhagwangola', + 'Galliate', + 'Pozos', + 'Princeton Meadows', + 'Red Hill', + 'Baynala', + 'Akdepe', + 'Maullin', + 'Najasa', + 'Zevio', + 'Sebt Bni Smith', + 'Cosio', + 'Ban Pang Mu', + 'Kadaiyam', + 'Belo', + 'Kompalle', + 'Rakovnik', + 'Chamgardan', + 'Yigilca', + 'Southchase', + 'Cochoapa el Grande', + 'Ernagudem', + 'Juma Shahri', + 'Ipua', + 'Kasagi', + 'San Miguel Duenas', + 'Tung Tau Tsuen', + 'Miyota', + 'Vatluru', + 'Pequannock', + 'Canapi', + 'Bad Neustadt', + 'Frei Paulo', + 'Eppelheim', + 'El Chal', + 'Edakkazhiyur', + 'Puerto Pimentel', + 'Kezmarok', + 'Jasol', + 'West Ham', + 'Einsiedeln', + 'Chittur', + 'Saligrama', + 'Agrate Brianza', + 'Santa Cecilia', + 'Ponnamaravati', + 'Qaryat Suluq', + 'Scottsboro', + 'La Roda', + 'Ayas', + 'My Luong', + 'Palhalan', + 'Codogno', + 'Greenwood Village', + 'Rakhiv', + 'Souagui', + 'Kukkundur', + 'Sanatikri', + 'Kumaralingam', + 'Bissegem', + 'Bituruna', + 'Tidjikja', + 'Anar', + 'Kyazanga', + 'Wattignies', + 'Nannestad', + 'Wanda', + 'North Reading', + 'Itariri', + 'Lwengo', + 'Igapora', + 'Sainte-Luce-sur-Loire', + 'Bredasdorp', + 'Dastgerd', + 'Los Osos', + 'Rendon', + 'Aleg', + 'Hofgeismar', + 'Edinet', + 'Matlock', + 'Bokoro', + 'Kucevo', + 'Diapaga', + 'Lahoysk', + 'Certaldo', + 'Ebn Ziad', + 'Aldine', + 'Lezhe', + 'Palanisettipatti', + 'Sayo', + 'Sirali', + 'Meghauna', + 'Morteza Gerd', + 'Zhuolan', + 'Teodoro Schmidt', + 'Saffron Walden', + 'Rossville', + 'Kifosso', + 'Buston', + 'Cherryland', + 'Pipra Latif', + 'Kanan', + 'Nobres', + 'Pudtol', + 'Patilar', + 'Daigo', + 'Kurawar', + 'Banqiao', + 'Asthanwan', + 'Casalpusterlengo', + 'Vemuladivi', + 'Mauranwan', + 'Dejen', + 'Shipley', + 'Linguere', + 'Ain el Hadid', + 'Ternat', + 'Todmorden', + 'Skhour Rehamna', + 'Tizi-n-Tleta', + 'Tiszaujvaros', + 'White Center', + 'Overpelt', + 'Funyan Bira', + 'Maskanah', + 'Verkhnodniprovsk', + 'Pichhor', + 'Lajkovac', + 'Seekonk', + 'Nkouraba', + 'Budakeszi', + 'Isorana', + 'Ambaguio', + 'Moreni', + 'Skalica', + 'Ban Nong Kathao', + 'Fos-sur-Mer', + 'Hiep Hoa', + 'Traverse City', + 'Mainburg', + 'Sabana Grande de Palenque', + 'Corbera de Llobregat', + 'Sarai Jattan', + 'Amboavory', + 'Sagala', + 'Baiceng', + 'Neustadt in Holstein', + 'Kyzyl-Suu', + 'Ban Duea', + 'Altunhisar', + 'Noisiel', + 'Guipavas', + 'Udala', + 'Solec Kujawski', + 'Greeneville', + 'Yesilova', + 'Montivilliers', + 'Differdange', + 'Sandhausen', + 'Turhapatti', + 'Csongrad', + 'Phulaut', + 'Bilgi', + 'Pianezza', + 'Rosario Oeste', + 'Stapleford', + 'Soliera', + 'Kinna', + 'Mitrapur', + 'Weybridge', + 'Chilamatturu', + 'Ilovaisk', + 'Kestel', + 'Ventaquemada', + 'Santa Cruz de la Palma', + 'Knaresborough', + 'Kambaduru', + 'Bemidji', + 'Romit', + 'Broxburn', + 'Al Hammam', + 'Arumbavur', + "Bois-d'Arcy", + 'Cipanas', + 'Uthai Thani', + 'Jiblah', + 'Ezzhiliga', + 'Anazzou', + 'Estrela de Alagoas', + 'Dilarpur', + 'Nedumudi', + 'Northview', + 'Gehrden', + 'Ala-Buka', + 'Dacheng', + 'Nymburk', + 'Nuth', + 'Tarascon', + 'Manohisoa', + 'Yankton', + 'Saint-Rambert', + 'Odanavattam', + 'Vipparla', + 'Machelen', + 'Khao Yoi', + 'Efkarpia', + 'Bugganipalle', + 'Bruntal', + 'Clark', + 'Hartselle', + 'Tari', + 'Spittal an der Drau', + 'Robbinsville', + 'Tururu', + 'Nancagua', + 'Ezine', + 'Blomberg', + 'Sorrento', + 'Kerouane', + 'Dison', + 'Messias', + 'Zabbar', + 'Meco', + 'Chokkanathapuram', + 'Potenza Picena', + 'Grimes', + 'Andrakata', + 'Khampat', + 'Siladon', + 'Sodag', + 'Lal Khatanga', + 'Khijri', + 'Nova Olinda', + 'Malhada', + 'Landazuri', + 'Besana in Brianza', + 'Tendrara', + 'Jamao al Norte', + 'Seacombe', + 'Ac-cahrij', + 'Magdiwang', + 'Kurdamir', + 'Butiama', + 'Ambongamarina', + 'Ban Khek Noi', + 'Jelcz-Laskowice', + 'Samsikapuram', + 'Bradley', + 'Raspur Patasia', + 'Fraga', + 'Strzegom', + 'Gopalnagar', + 'Ayutla de los Libres', + 'Robinson', + 'San Policarpo', + 'Homosassa Springs', + 'Cruzilia', + 'Discovery Bay', + 'Putaendo', + 'Silvi Paese', + 'Thoen', + 'Baildon', + 'Kot Bhai', + 'Mortara', + 'Trelaze', + 'Talainayar Agraharam', + 'Lopare', + 'Kocakoy', + 'Urandi', + 'Rajgadh', + 'Frattaminore', + 'Genappe', + 'Tanhuato de Guerrero', + 'Mateszalka', + 'Sava', + 'Viseu de Sus', + 'Eden', + 'Dvur Kralove nad Labem', + 'Anao-aon', + 'San Luis del Palmar', + 'Kumaramputtur', + 'Bambous', + 'Amatitan', + 'Moul El Bergui', + 'Uvalde', + 'Bunnik', + 'Castro Daire', + 'Perivale', + 'Semra', + 'Bennington', + 'Kanegasaki', + 'Gomboussougou', + 'Chhajli', + 'Winkler', + 'Israin Kalan', + 'Khamir', + 'Fruitville', + 'Bad Bramstedt', + 'Haddon', + 'Ratekau', + 'Basarh', + 'Jupi', + 'Maddikera', + 'Odenthal', + 'Amanganj', + 'Undi', + 'Villa Paranacito', + 'Bandar-e Khamir', + 'Inhuma', + 'Wombwell', + 'Sao Joao Evangelista', + 'Burbach', + 'Pihra', + 'Maydolong', + 'Atalaia do Norte', + 'Stanley', + 'Bankheri', + 'Llantrisant', + 'Veys', + 'White', + 'Itajiba', + 'Mottola', + 'Bhanumukkala', + 'Guerouma', + 'Belchertown', + 'Broxbourne', + 'Dudhgaon', + 'Uirauna', + 'Andicun', + 'Elandakuttai', + 'Nagasu', + 'Tenafly', + 'Ladson', + 'Harper Woods', + 'Guamare', + 'Vennesla', + 'Medrissa', + 'Belari', + 'Erongaricuaro', + 'Norridge', + 'Shal', + 'Lagoa da Confusao', + 'Maryborough', + 'Clausthal-Zellerfeld', + 'Santa Ursula', + 'Saint-Charles-Borromee', + 'Chilcuautla', + 'Tekkampatti', + 'Matar', + 'Lyss', + 'Sidi Ghiles', + 'Atyra', + 'Ulladulla', + 'Cunit', + 'Sippola', + 'Shedbal', + 'Palmer Ranch', + 'Galanta', + 'Kalikapur', + 'Motiong', + 'Pereiro', + 'Chemini', + 'Boumahra Ahmed', + 'Peddaboddepalle', + 'Sahpur', + 'Udayendram', + 'Es Sebt', + 'Vincent', + 'Ain Jemaa', + 'San Rafael Arriba', + 'Wittenheim', + 'Mangawan', + 'Ratan', + 'Dawlish', + 'Shimohata', + 'Rio Grande City', + 'Pureparo de Echaiz', + 'Project Six', + 'Senlis', + 'Nonkon', + 'Ober-Ramstadt', + 'Penacova', + 'Ovruch', + 'Coulommiers', + 'Bouc-Bel-Air', + 'Vail', + 'Civita Castellana', + 'Volpiano', + 'Kinross', + 'Castellarano', + 'Dengshangcun', + 'Palmview', + 'Asbury Park', + 'Pichucalco', + 'Libagon', + 'Featherstone', + 'Mexborough', + 'Melissa', + 'Glenn Dale', + 'Tazert', + 'Anosy Avaratra', + 'La Solana', + 'Marui', + 'Kriel', + 'Beterou', + 'Itanhandu', + 'Metkovic', + 'Wilmington Island', + 'Kanding', + 'Pimpalgaon Raja', + 'Mulakaledu', + 'Cowansville', + 'Conchas', + 'Upper Southampton', + 'Rochedale', + 'Billapadu', + 'Vieiro', + 'Neston', + 'Sainte-Anne-des-Plaines', + 'Avsallar', + 'Chervonopartyzansk', + 'Tamesis', + 'Charam', + 'Bidston', + 'Rive-de-Gier', + 'Vammala', + 'Bunkeflostrand', + 'Capurso', + 'Shangtianba', + 'Musapur', + 'Saint-Brice-sous-Foret', + 'Humayingcun', + 'Macomb', + 'Sumidouro', + 'Phillipsburg', + 'Souk Et-Tleta des Oulad Hamdane', + 'Ljungby', + 'Aravakkurichchi', + 'Tirhassaline', + 'La Apartada', + 'Francheville', + 'Chateau-Thierry', + 'Barrocas', + 'Ceska Trebova', + 'Salesopolis', + 'Huasca de Ocampo', + 'Arnedo', + 'Zubin Potok', + 'Hallstahammar', + 'Gagarin Shahri', + 'Northenden', + 'Pyapali', + 'Kumiyama', + 'Davidson', + 'Chinsali', + 'Chellaston', + 'Ahram', + 'Mahaly', + 'Seshambe', + 'Mering', + 'Verwood', + 'Imerimandroso', + 'Adilcevaz', + 'Golmarmara', + 'Bangassi-Nangou', + 'Longwy', + 'Uchiko', + 'Melouza', + 'Jangid', + 'Tondangi', + 'Hebli', + 'San Vito al Tagliamento', + 'Dougouni', + 'Nakanojomachi', + 'Tasucu', + 'Azpeitia', + 'Domanic', + 'Schwyz', + 'Xiangyuncun', + 'Beech Grove', + 'Dorfen', + 'Adjud', + 'Gulf Shores', + 'Cessnock', + 'Wakuya', + 'Montagu', + 'Fray Luis A. Beltran', + 'Petlawad', + 'Espumoso', + 'Seven Pagodas', + 'Salua', + 'Gayeri', + 'Pa', + 'Niederkruchten', + 'Redruth', + 'Cumbum', + 'Greenlawn', + 'Waremme', + 'Rio San Juan', + 'Puliyur', + 'Hathiaundha', + 'Moura', + 'Ewa Beach', + 'Sobreda', + 'Douar El Arbaa Bou Quorra', + 'Yauco', + 'Lakhaura', + 'Gaspe', + 'Meruoca', + 'Palmers Green', + 'Totteridge', + 'Gurramkonda', + 'Kontiolahti', + 'Blaydon', + 'San Pedro Tapanatepec', + 'Biatorbagy', + 'Kawaminami', + 'Berkley', + 'Biritinga', + 'Kuusamo', + 'Whitman', + 'Mallapuram', + 'Mashpee', + 'Vicovu de Sus', + 'Telua', + 'Roanoke Rapids', + 'Depew', + 'Vandalia', + 'America Dourada', + 'Castiglione del Lago', + 'Weisswasser/Oberlausitz', + 'Sefaatli', + 'Vasterhaninge', + 'Pargas', + 'Grodzisk Wielkopolski', + 'Vesoul', + 'Gangapur', + 'Majiagoucha', + 'Ambohimierambe-Andranofito', + 'New Cassel', + 'Sansepolcro', + 'Swampscott', + 'Bayserke', + 'Raynham', + 'Ban Na Kham', + 'Warni', + 'Srivardhan', + 'Kutchan', + 'Jaguapita', + 'Zacualpan', + 'Klimavichy', + 'Mazagran', + 'Xihuangni', + 'Newport Pagnell', + 'Mahikeng', + 'Vize', + 'Rumst', + 'Koduman', + 'Oulad Bou Rahmoun', + 'Tamaki', + 'Gloversville', + 'Radviliskis', + 'Sakabansi', + 'Mirai', + 'Maesawa', + 'Bhoj', + 'Itki Thakurgaon', + 'Khaira', + 'Piratininga', + 'Chautham', + 'Doumanaba', + 'Tredegar', + 'Bilaua', + 'Silvino Lobos', + 'Putyvl', + 'Nopala de Villagran', + 'Cifteler', + 'Pacific Grove', + 'Huitzilan', + 'Wulflingen', + 'Tonawanda', + 'Galatone', + 'Brake', + 'Ban Ton Thong Chai', + 'Babhani Bholwa', + 'Schriesheim', + 'Al Madamud', + 'Bhatranha', + 'Kastsyukovichy', + 'Changamkari', + 'Canyon', + 'Cernavoda', + 'Putaparti', + 'Kidal', + 'Capotille', + 'Sooke', + 'Tabhka Khas', + 'Jadia', + 'Mellila', + 'Bonheiden', + 'Makapanstad', + 'Sultandagi', + 'Eggertsville', + 'Kohir', + 'Natividade do Carangola', + 'West Park', + 'Hatton', + 'Campodarsego', + 'Hasanganj', + 'Talladega', + 'Clevelandia', + 'Ipaucu', + 'Mani', + 'Peddapalle', + 'Devendranagar', + 'Hazel Park', + 'Neustadt bei Coburg', + 'Front Royal', + 'Ut Bulag', + 'Spring Creek', + 'Bad Wurzach', + 'Olonne-sur-Mer', + 'Montargis', + 'Sabou', + 'Alvinopolis', + 'Andondabe', + 'Pedara', + 'Tatarikan', + 'Kanungu', + 'Echuca', + 'Bolivia', + 'Markgroningen', + 'Patnanungan', + 'Royse City', + 'Rajni', + 'Mineral Wells', + 'Ekma', + 'Perchtoldsdorf', + 'Amlash', + 'La Magdalena Tlaltelulco', + 'Pontinia', + 'Boskoop', + 'Saint-Avold', + 'Murray Bridge', + 'Langelsheim', + 'Revur', + 'Kamitonda', + 'Burshtyn', + 'Ylivieska', + 'Ochanthururtha', + 'Carrieres-sur-Seine', + 'Villa Ocampo', + 'Chepica', + 'Grenzach-Wyhlen', + 'Mollerusa', + 'Contamana', + 'Tone', + 'Le Hochet', + 'Corupa', + 'Ritterhude', + 'Satyamangala', + 'Zozocolco de Hidalgo', + 'Filiasi', + 'Fritzlar', + 'Sabbah', + 'Udiyavara', + 'Ban Ho Mae Salong', + 'South Farmingdale', + 'Ferreiros', + 'Cuevas del Almanzora', + 'Swallownest', + 'Midar', + 'Kutavettur', + 'Brasilandia', + 'Ban Mae Sun Luang', + 'Puerto Salgar', + 'Boa Esperanca do Sul', + 'Netherton', + 'Aruvikkara', + 'Lockhart', + 'Kaintragarh', + 'Hudiksvall', + 'Konarka', + 'Shamsa', + 'Westervoort', + 'Busko-Zdroj', + 'Issoire', + 'Andorinha', + 'Canet de Mar', + 'Cassano delle Murge', + 'Struga', + 'Dionisio Cerqueira', + 'Dembecha', + 'Alpedrete', + 'Witzenhausen', + 'Wallan', + 'Novyi Buh', + 'Sarvar', + 'Barajor', + 'Pavannur', + 'Verdal', + 'California City', + 'Acala', + 'Kezi', + 'Ras Baalbek', + 'Quthing', + 'Manambondro', + 'Milenaka', + 'Soalala', + 'Ambodiriana', + 'Befasy', + 'Kopoky', + 'Ramainandro', + 'Ambatomanjaka', + 'Andranovelona', + 'Ianantsony', + 'Analamary', + 'Imanombo', + 'Beroy Atsimo', + 'Alarobia Bemaha', + 'Talata Ampano', + 'Ambatoharanana', + 'Sahave', + 'Bevoay', + 'Anahidrano', + 'Ambahive', + 'Ifatsy', + 'Ankisabe', + 'Anjoma-Ramartina', + 'Lokomby', + 'Behisatse', + 'Iharana', + 'Manandona', + 'Antanimenabaka', + 'Marofototra', + 'Tsiatajavona-Ankaratra', + 'Antsoso', + 'Ambesisika', + 'Ankilimivory', + 'Wan Long', + 'Kyaukmyaung', + 'Aiyetoro Gbede', + 'Amawom', + 'Ramechhap', + 'Bhimphedi', + 'Mian Sahib', + 'Awan Patti', + 'Koungheul', + 'Bakel', + 'Yufle', + 'Kuljibrin', + 'Sarmada', + 'Gammarth', + 'Ozdere', + 'Kalongo', + 'Matuga', + 'Zombo', + 'Mutukula', + 'Chaguaramas', + 'Clarines', + 'Fayroz Koh', + 'Taywarah', + 'Spitak', + 'Villa Ojo de Agua', + 'Baisari', + 'Jamaica', + 'Guayos', + 'Villaviciosa', + 'Saint-Avertin', + 'Hessle', + 'Tillor Khurd', + 'Chettikulam', + 'Aivanallur', + 'Shafinagar', + 'Damalcheruvu', + 'Cortalim', + 'Majhgawan', + 'Hombal', + 'Bellatti', + 'Singhanwala', + 'Hullahalli', + 'Muttamtura', + 'Sathamba', + 'Valattur', + 'Nedumpura', + 'Turori', + 'Khandhar', + 'Shirud', + 'Galatge', + 'Vasa', + 'Bartalah', + 'Amirli', + 'Yinhua', + 'Winkfield', + 'Talpa de Allende', + 'Worthington', + 'Buda', + 'Sanyi', + 'Shambu', + 'Huchuan', + 'Anororo', + 'Santa', + 'Suvalan', + 'Buttelborn', + 'Kisvarda', + 'Shklow', + 'Djambala', + 'La Gloria', + 'Pyryatyn', + 'Kaguchi', + 'Salinas da Margarida', + 'Esbiaat', + "Sant'Arpino", + 'Calanogas', + 'Lapseki', + 'Yelur', + 'Mandleshwar', + 'Andipalaiyam', + 'Belkheir', + 'Bouchegouf', + 'Texenna', + 'Petersfield', + 'Casalmaggiore', + 'Candoi', + 'Tavros', + 'Chirpan', + 'Porcia', + 'Castelnuovo Rangone', + 'Laurinburg', + 'Chrysoupoli', + 'Avanos', + 'Mastic', + 'Kenora', + 'Kenley', + 'Douar Souk L`qolla', + 'Santa Brigida', + 'El Hadjira', + 'Tabant', + 'Paralimni', + 'Saint-Servan-sur-Mer', + 'West University Place', + 'Baucau', + 'Cold Lake', + "'Tlat Bni Oukil", + 'Veliki Preslav', + 'Goluwali', + 'Lakeland North', + 'Weigelstown', + 'Metuchen', + 'Bludenz', + 'Vianopolis', + 'Monkey Bay', + 'Sidi Zouine', + 'Catalpinar', + 'Dolo', + 'Coconuco', + 'Finale Emilia', + 'Wyke', + 'Ramonville-Saint-Agne', + 'Lambidou', + 'Vallur', + 'Mitane', + 'Mendrisio', + 'Bissendorf', + 'Baiersbronn', + 'Joaima', + 'Serhetabat', + 'Grande Saline', + 'Restinga Seca', + 'Majholi', + 'Newtown', + 'Avrille', + 'Ganjam', + 'Swidwin', + 'Kimyogarlar', + 'La Fleche', + 'Oued Jdida', + 'Schiffdorf', + 'Calkini', + 'Chandi', + 'Riverdale', + 'Itahara', + 'Jisr ez Zarqa', + 'Malsch', + 'Ahigbe Koffikro', + 'Beckingen', + 'Chemmanam', + 'Gourrama', + 'Nalerigu', + 'Usingen', + 'East Rancho Dominguez', + 'Brooks', + 'Yellareddi', + 'Lanji', + 'Sembedu', + 'Lakkundi', + 'Tecuala', + 'Castanuelas', + 'Pursa', + 'Kunnumel', + 'Krasnohorivka', + 'Escaldes-Engordany', + 'Lolotique', + 'Lalejin', + 'Kew Green', + 'Hickory Hills', + 'Lagangilang', + 'Barra do Sul', + 'Sardinal', + 'Badarpur', + 'Kela Khera', + 'Ammur', + 'Aghbal', + 'Vinanivao', + 'Sindhnur', + 'Aizubange', + 'Kentville', + 'Castanet-Tolosan', + 'Morlaix', + 'Podebrady', + 'Torello', + 'Aiyampuzha', + 'Holliston', + 'Kurate', + 'Lake Arbor', + 'Vakhsh', + 'Qumqo`rg`on', + 'Chapelle-lez-Herlaimont', + 'Beizhou', + "Quan'ancun", + 'Cumayeri', + 'Tsabit', + 'Sisian', + 'Coquimatlan', + 'Naxxar', + 'Nastola', + 'Valangiman', + 'Dimiao', + 'Stolac', + 'Sassenheim', + 'Jhandapur', + 'Sahakevo', + 'Chemax', + 'West Wickham', + 'Parapatti', + 'Cerro Maggiore', + 'Bohodukhiv', + 'Taruma', + 'Branchburg', + 'Bacuag', + 'Przeworsk', + 'Doukouya', + 'Champapur', + 'Highland Springs', + 'Ngolobougou', + 'Grefrath', + 'San Tomas', + 'Lidzbark Warminski', + 'Sera', + 'Le Raincy', + 'Alampur', + 'Oldsmar', + 'Greensburg', + 'Shepshed', + 'Nisko', + 'Hanamsagar', + "Fiorenzuola d'Arda", + 'Sopelana', + 'Breaza', + 'Ravels', + 'Tayum', + 'Harchoune', + 'Bailleul', + 'Hedehusene', + 'Boulder City', + 'Yuchi', + 'Cujubim', + 'Vellalapuram', + 'Barharwa', + 'Ayni', + 'Grecia', + 'Tamani', + 'Chailaha', + 'Drahichyn', + 'Amberieu-en-Bugey', + 'Nagarur', + 'Red Oak', + 'Qiaoyang', + 'Forest City', + 'Bromborough', + 'Berlare', + 'Salida', + 'Niquinohomo', + 'Jever', + 'Chipurupalle', + 'Niedernhausen', + 'Madhuban', + 'Tremelo', + 'Terra Rica', + 'Gabane', + 'Avalpundurai', + 'Koumaira', + 'Huitan', + 'Nzalat Laadam', + 'Varnsdorf', + 'San Mateo del Mar', + 'Isny im Allgau', + 'San Vito', + 'Bela Vista do Paraiso', + 'Haga', + 'Le Bourget', + 'Chislehurst', + 'Jinta', + 'Taurianova', + 'Timissa', + 'Illzach', + 'Botelhos', + 'Betsukai', + 'Hariharpara', + 'Grandola', + 'Tall Abyad', + 'Huckeswagen', + 'Mercaderes', + 'Kumaramangalam', + 'Lemon Hill', + 'Cabral', + 'Vuhledar', + 'Tendukheda', + 'Tadjourah', + 'Ponto Novo', + 'Schwabmunchen', + 'Cabanas', + 'Cherrapunji', + 'Port Antonio', + 'Kumaripur', + 'Nenmini', + 'Fort Payne', + 'Tanque Verde', + 'Kochkor-Ata', + 'Huixcolotla', + 'Petrovaradin', + 'Candido de Abreu', + 'Ilkley', + 'Patrocinio Paulista', + 'Jozefoslaw', + 'Radzyn Podlaski', + 'Benipati', + 'Comox', + 'Astravyets', + "Ighrem n'Ougdal", + 'Buerarema', + 'Whitefish Bay', + 'Ogijares', + 'Dehmoi', + 'La Carolina', + 'Anta', + 'Weizhou', + 'Muthallath al Azraq', + 'Fameck', + 'Sullivan', + 'Devarapalle', + 'Merate', + 'Palod', + "Citta Sant'Angelo", + 'Baguley', + 'Waunakee', + 'Kapiri Mposhi', + 'Shuichecun', + 'Deblin', + 'Stony Point', + 'Lapy', + 'Pattensen', + 'Sozopol', + 'Afdem', + 'Alexander City', + 'New Paltz', + 'Konina', + 'Araputanga', + 'Itamonte', + 'Bni Darkoul', + 'Oulad Dahmane', + 'Armagh', + 'Amasra', + 'Sanquelim', + 'Hilchenbach', + 'Montmagny', + 'Pontivy', + 'Sitio do Quinto', + 'Laterza', + 'Williamstown', + 'Clarksdale', + 'Romsey', + 'Kamrawan', + 'Piney Green', + 'Adams', + 'Romilly-sur-Seine', + 'Zitsa', + 'Curtorim', + 'Harhorin', + 'Hasanpur Juned', + 'Selb', + 'Chitila', + 'Lummen', + 'Villers-les-Nancy', + 'Diankabou', + "Bo'ness", + 'Obanazawa', + 'Cherupazhasshi', + 'Much', + 'Ludus', + 'Cumpana', + 'Haubourdin', + 'Hirono', + 'Matungao', + 'Penrith', + 'Maqat', + 'Deming', + 'Tiltil', + 'El Ateuf', + 'Briniamaro', + 'Balham', + 'Pincourt', + 'Mozarlandia', + 'Teignmouth', + 'Perunkolattur', + 'Sinmperekou', + 'Sasso Marconi', + 'Masalli', + 'Entre Rios de Minas', + 'Ijra', + 'Eshowe', + 'Friedland', + 'Banbridge', + 'Cocorna', + 'Havre de Grace', + 'Punata', + 'Dennis', + 'Driouch', + 'San Juan del Sur', + 'Torokbalint', + 'Garhpura', + 'Lilburn', + 'Larkhall', + 'Mississippi Mills', + 'Youdiou', + 'Vaddapalli', + 'Tepetzintla', + 'Breukelen', + 'Bodmin', + 'Andurkonam', + 'Cicekdagi', + 'Labiod Medjadja', + 'Sakha', + 'Hammonton', + 'Pindai', + 'Chaabat el Leham', + 'Joubb Jannine', + 'Pine', + 'Rellingen', + 'Roseau', + 'Great Bend', + 'Conwy', + 'Neqab', + 'Matsushige', + 'Greendale', + 'Isla Vista', + 'Muy Muy', + 'Baladharmaram', + 'San Gwann', + 'Prestwick', + 'Alagoinha', + 'Douar Oulad Driss', + 'Oulad Driss', + 'Riofrio', + 'Neustadt an der Donau', + 'Sahit', + 'Cesis', + 'Mediouna', + 'Troon', + 'Chhapia', + 'Tarumirim', + 'Paola', + 'Uch-Korgon', + 'Ochakiv', + 'Purisima de la Concepcion', + 'Plerin', + 'Shimubi', + "Santa Croce sull' Arno", + 'Cuarte de Huerva', + 'Hima', + 'Tirumalaiyampalaiyam', + 'Hooksett', + 'Gladeview', + 'Koteshwar', + 'Harsefeld', + 'Villa Alegre', + 'Surbo', + 'Ospitaletto', + 'Nishinoomote', + 'Onklou', + 'Guilford', + 'Tlaxcala', + 'Carmen de Areco', + 'Lope de Vega', + 'Kodangipatti', + 'Baie du Tombeau', + 'Gross-Zimmern', + 'Kurumbalur', + 'Ankadinandriana', + 'Collecchio', + 'Coremas', + 'Masty', + 'Paramati', + 'Hershey', + 'Rubiera', + 'Owosso', + 'Melksham', + 'Mahatsinjo', + 'Ngoulemakong', + 'Dinan', + 'Ranomafana', + 'Thuin', + 'Laxou', + 'Wibsey', + 'Corridonia', + 'Bar-le-Duc', + 'Fraser', + 'Lake Stickney', + 'Manantheri', + 'Bere', + 'Pudur', + 'Malvik', + 'Las Guaranas', + 'Santa Marta de Tormes', + 'Saint-Omer', + 'Kushimoto', + 'Dzuunmod', + 'Kysucke Nove Mesto', + 'Condoto', + 'Ifrane', + 'Piraziz', + 'Tapes', + 'Kamalganj', + 'St. Clair', + 'Rasulpur Dhuria', + 'Zlotoryja', + 'Capinopolis', + 'Mmopone', + 'Djanet', + 'At-Bashy', + 'Langwedel', + 'Malo', + 'Kujukuri', + 'North New Hyde Park', + 'Mulakad', + 'Lognes', + 'Great Baddow', + 'Boguszow-Gorce', + 'Kaonke', + 'Sprimont', + 'Ferrier', + 'Mangamila', + 'Mineral del Monte', + 'Vubatalai', + 'Goure', + 'Sisa', + 'Tecpan de Galeana', + 'Limanowa', + 'Nea Alikarnassos', + 'Woudrichem', + 'Mahinog', + 'Bilozerske', + 'Ibitiara', + 'Tiruvasaladi', + 'Bilina', + 'Sepidan', + 'Terrace', + 'Ternitz', + 'Combita', + 'Rosa', + 'Rio Piracicaba', + 'Teixeira', + 'Flower Hill', + 'Pinia', + 'Djebahia', + 'Misaki', + 'Mercier', + 'Parlier', + 'Lumino', + 'Skipton', + 'Chippewa Falls', + 'Narragansett', + 'Bahcesaray', + 'Dahe', + 'Abony', + 'Alanganallur', + 'Zontecomatlan de Lopez y Fuentes', + 'Port Glasgow', + 'Magione', + 'Vredefort', + 'Kalocsa', + 'Groveton', + 'Negresti-Oas', + 'Cambuci', + 'Guajiquiro', + 'Kankipadu', + 'Vemuluru', + 'Roncade', + 'Kiri', + 'Plochingen', + 'Paliaturutu', + 'Bartabwa', + 'Batuan', + 'Huasuo', + 'Castellammare del Golfo', + 'Anzegem', + 'Lapua', + 'Langenselbold', + 'Hatten', + 'Ispir', + 'Tullamore', + 'Lowton', + 'Carmignano', + 'Suo-Oshima', + 'Saint-Maurice', + 'Sinha', + 'Sveti Ivan Zelina', + 'Arroio dos Ratos', + 'Saint-Jean-de-Luz', + 'Uzun', + 'Cabarete', + 'Nova Ponte', + 'Verrieres-le-Buisson', + 'Montabaur', + 'Wilbraham', + 'Holalagondi', + 'Jedrzejow', + 'Tonya', + 'Guastalla', + 'Satyun', + 'Villa Yapacani', + 'Yokoshiba', + 'Kelamangalam', + 'Dinmanpur', + 'Sangota', + 'Palmeirais', + 'Cajetina', + 'Arnouville-les-Gonesse', + 'Sigulda', + 'Thillangeri', + 'Tostado', + 'Baligaon', + 'Broadlands', + 'Lucao', + 'Zabkowice Slaskie', + 'Agios Athanasios', + 'Lauda-Konigshofen', + 'Tostedt', + 'Aleksandrovka', + 'Severinia', + 'Red Bluff', + 'Falls Church', + 'Talya', + 'Port Royal', + 'Kanjikkovil', + 'Key Biscayne', + 'Tzaneen', + 'Jitwarpur Nizamat', + 'Pineto', + 'Wawizaght', + 'Lakkampatti', + 'Salem Lakes', + 'Burbage', + 'Edenburg', + 'Palayad', + 'Benfreha', + 'Paniem', + 'Breza', + 'Kottacheruvu', + 'Naivasha', + 'Qazyqurt', + 'Mocha', + 'Jastrebarsko', + 'Darpa', + 'Debar', + 'Essau', + 'Tiruppachur', + 'Relangi', + 'Saint-Genis-Pouilly', + 'Belvedere Park', + 'Ban San Phak Wan Luang', + 'Loviisa', + 'Stein bei Nurnberg', + 'Thorpe Saint Andrew', + 'Andoain', + 'Bijaipur', + 'Bicas', + 'Solila', + 'Ratzeburg', + 'Clarkston', + 'Adekar Kebouche', + 'Anamoros', + 'El Paisnal', + 'Wilsdruff', + 'Biscarrosse', + 'Halwara', + 'Altinekin', + 'Iakora', + 'Cecil', + 'Marofinaritra', + 'Gundlapelle', + 'Merimandroso', + "Les Sables-d'Olonne", + "Ayt 'Attou ou L'Arbi", + 'Stanytsia Luhanska', + 'Ottweiler', + 'Ban Du', + 'Pindorama', + 'Blidet Amor', + 'Australind', + 'Jun Bel', + 'Bom Jesus do Galho', + 'Arbon', + 'Bakun', + 'Abensberg', + 'Nagireddipalli', + 'Moultrie', + 'Rio Paranaiba', + 'Falagueira', + 'Sarmin', + 'Ain Nouissy', + 'Kusaha', + 'Ban Kaeng', + 'Pualas', + 'Kannamanayakkanur', + 'Reidsville', + 'Cadaval', + 'Dargahan', + 'Middlesex', + 'Agua Boa', + 'Vitomirice', + 'Sha Kok Mei', + 'Pandhana', + 'Herselt', + 'Minignan', + 'Anapoima', + 'Moston', + 'Sonora', + 'Saint-Fargeau', + 'Pakarya Harsidhi', + 'Tabuse', + 'Dieramana', + 'Reboucas', + 'Guachochi', + 'Mbuyapey', + 'Neu-Anspach', + 'Immenstadt im Allgau', + 'Mosina', + 'Montesson', + 'Valea Lupului', + 'Olsberg', + 'McCalla', + 'Quinapundan', + 'Chelsfield', + 'Oria', + 'Aberdare', + 'Suwasra', + 'San Martin de Loba', + 'Eberbach', + 'Farap', + 'Angus', + 'Nadisal', + 'Gavinivaripalem', + 'Surajpura', + 'Sadhoa', + 'Sokone', + 'Oyam', + 'Guanduqiao', + 'West Lincoln', + 'Yanhewan', + 'Ouled Sidi Brahim', + 'Ludvika', + 'Tenente Portela', + 'Agua Fria', + 'Lingal', + 'Thornbury', + 'Chinnavadampatti', + 'Poco das Trincheiras', + 'Uckfield', + 'Lakho', + 'Uhingen', + 'Barhni', + 'Deysbrook', + 'Harduli', + 'Ahmed Rachedi', + 'Askim', + 'Murra', + 'Madagh', + "Boula'wane", + 'Cehegin', + 'Burglengenfeld', + 'Flers', + 'Valenton', + 'Babhangawan', + 'Fujisaki', + 'Mesa Geitonia', + 'Eisenstadt', + 'Barroquinha', + 'Buggenhout', + 'Turnov', + 'Nampicuan', + 'Qobustan', + 'Haacht', + 'Tlayacapan', + 'Markacho', + 'Roh', + 'Huizucar', + 'Khallikot', + 'Santaquin', + 'Ormeau', + 'Tiruvalanjuli', + 'Sommacampagna', + 'Plumtree', + 'Ichikawamisato', + 'Armthorpe', + 'Lagunia Surajkanth', + 'Ankaramena', + 'Yangasso', + 'Lopik', + 'Sassenberg', + 'Santo Domingo Xenacoj', + 'Larena', + 'Tarlapalli', + 'Scottsbluff', + 'Sopetran', + 'Shatrana', + 'Robbinsdale', + 'Gwanda', + 'Jacarau', + 'Narahia', + 'Bara', + 'Neubiberg', + 'Brwinow', + 'Roquebrune-sur-Argens', + 'Asagiri', + 'Short Hills', + 'West Freehold', + 'Tavagnacco', + 'Monticello', + 'Anderson Creek', + 'Tulchyn', + 'Chenove', + 'Nolensville', + 'Alginet', + 'Alloa', + 'Ait Yaich', + 'Vinci', + 'Eggenfelden', + 'Black Forest', + 'Claxton Bay', + 'Pahou', + 'Jacaraci', + 'Bokod', + 'Ban Ao Nang', + 'Barranco de Loba', + 'Sirmaur', + 'Araceli', + 'Rauch', + 'Ampohibe', + 'Perai', + 'Sainte-Maxime', + 'Nether Providence', + 'Busembatia', + 'Eching', + 'Kolwara', + 'Caln', + 'Ascension', + 'Morroa', + 'Baqiabad', + 'Bagulin', + 'Pilisvorosvar', + 'Szarvas', + 'Satwas', + 'Aartselaar', + 'Davorlim', + 'Alur', + 'Ulchin', + 'Dollis Hill', + 'Painan', + 'Dornakal', + 'Lavaltrie', + 'Villa Vasquez', + 'Kalyvia Thorikou', + 'Tirkarur', + 'Tagalft', + 'Kharki', + 'Cayey', + 'Mantaly', + 'Korsor', + 'Barhi', + 'Spenge', + 'Vadugapatti', + 'Magurele', + 'Gorbea', + 'Killarney', + 'Brainerd', + 'General MacArthur', + 'Saint-Brevin-les-Pins', + "Chateau-d'Olonne", + 'Hopatcong', + 'Halawa', + 'Ghora Gali', + 'Skippack', + 'Pomorie', + 'Chik Banavar', + 'Yerere', + 'Valbom', + 'Paidiipalli', + 'Itau de Minas', + 'Mutyalapalle', + 'Minneola', + 'Wymondham', + 'Nagra', + 'Haldibari', + 'Dumas', + 'North Auburn', + 'Hetton le Hole', + 'Alindao', + 'Tupran', + 'Wangjiaxian', + 'Choszczno', + 'Sierra Vista Southeast', + 'Gernsbach', + 'Sorso', + 'Muqui', + 'West Bradford', + 'Chiconquiaco', + 'Lubbeek', + 'Lohfelden', + 'Kihoku', + 'Majia', + 'Hargawan', + 'Uzumlu', + 'Liestal', + 'Stafa', + 'Rheydt', + 'Anomabu', + 'Zaysan', + 'Mohanpur Gaughata', + 'Yamada', + 'Kusnacht', + 'Washington Court House', + 'Maria', + 'Karempudi', + 'Amersham', + 'Vasad', + 'West Derby', + 'Lake Wylie', + 'East Bridgewater', + 'Ourtzagh', + 'Kamatgi', + 'Natchez', + 'Impruneta', + 'Moorestown-Lenola', + 'New Hamburg', + 'Opwijk', + 'Saint Joseph', + 'Zolote', + 'Tezu', + 'Ozarow Mazowiecki', + 'Elizabethton', + 'Doria Sonapur', + 'Penuganchiprolu', + 'Sailana', + 'Cowes', + 'West Drayton', + 'Nacozari Viejo', + 'Rosarno', + 'Churumuco de Morelos', + 'Patiali', + 'Miena', + 'Mercerville', + 'West Nipissing / Nipissing Ouest', + 'Barela', + 'Riegelsberg', + 'Santa Rosalia', + 'Pineville', + 'Markdorf', + 'Serinhisar', + 'Artsyz', + 'Jitauna', + 'Miho', + 'Lobau', + 'Thondiamannu', + 'Simoes', + 'Tornesch', + 'Rehlingen-Siersburg', + 'Breyten', + 'Zaouiat Moulay Bouchta El Khammar', + 'Ihaddadene', + 'Niederzier', + 'Baulia', + 'Bihpuriagaon', + 'Bradley Gardens', + 'Zhutang', + 'Jiaoxiyakou', + 'Balangiga', + 'Tianguistengo', + 'Narhan', + 'Bhanukumari', + 'Wilkinsburg', + 'Alto Longa', + 'Strathmore', + 'Pont-a-Mousson', + 'Leno', + 'Hindalgi', + 'Monte Alegre de Sergipe', + 'San Andres Timilpan', + 'Pazar', + 'Conisbrough', + 'Muttukuru', + 'Belazao', + 'Mittweida', + 'Lakhsetipet', + 'Hasami', + 'Horta', + 'Yanshuiguan', + 'Brookside', + 'Mascali', + 'Anpachi', + 'Baia-Sprie', + 'Saldana', + 'Palda', + 'Walajabad', + "Vil'nyans'k", + 'Klasterec nad Ohri', + 'Rottingdean', + 'High River', + 'Gua', + 'Jori Kalan', + 'Tepecoyo', + 'Polaia Kalan', + 'Chikhli Kalan', + 'Ustka', + 'Sadovoye', + 'Kottavalasa', + 'Tenerife', + 'Kizhariyur', + 'Saddle Brook', + 'Balangkas', + 'Estremoz', + 'Saint-Paul-les-Dax', + 'Doctor Juan Eulogio Estigarribia', + 'Karkudalpatti', + 'Viraghattam', + 'Radzymin', + 'Lotte', + 'Peumo', + 'Iflissen', + 'Rokycany', + 'Sumbas', + 'Lengede', + 'Murak', + 'Mangoli', + 'Tsukawaki', + 'Amay', + 'Sarqan', + 'Santo Antonio dos Lopes', + 'Huliyar', + 'Woippy', + 'Fakola', + 'Novohrodivka', + 'Nagongera', + 'Romitan Shahri', + 'Sariosiyo', + 'Kidbrooke', + 'Roldan', + 'Kambainellur', + 'Rock Ferry', + 'Baruun-Urt', + 'Coronel Bogado', + 'Dayr al Barsha', + 'Neutraubling', + 'Pollokshaws', + 'Iona', + 'Algarrobo', + 'Bad Camberg', + 'Korangal', + 'Omegna', + 'Eski Ikan', + 'Ambohimanga Atsimo', + 'Orbetello', + 'Nasice', + 'Chiaravalle', + 'Chard', + 'Anantarazupeta', + 'Bariariya', + 'Loganville', + 'Bousso', + 'Ban Don Kaeo', + 'Grafing bei Munchen', + 'Brandermill', + 'East Greenwich', + 'Chicago Ridge', + 'Gualdo Tadino', + 'Unguturu', + 'Bialy Kamien', + 'Bikkavolu', + 'Somerton', + 'El Barrio de la Soledad', + 'Puxinana', + 'Patcham', + 'Santa Maria a Vico', + 'West Lealman', + 'Gantt', + 'Razan', + 'Nkhata Bay', + 'Mongeri', + 'Ban Nong Kula', + 'Ucar', + 'Ghaura', + 'Vedasandur', + 'Lai', + 'Pak Thong Chai', + 'Ban Tha Thong', + 'Cienega de Flores', + 'Bokonbaev', + 'Manoharpur', + 'Det Udom', + 'Saint-Gilles', + 'Mionica', + 'Bollullos par del Condado', + 'Marechal Floriano', + 'Bois-Guillaume', + 'Morokweng', + 'Poynton', + 'Ait Yazza', + 'Chikitigarh', + 'Ben Taieb', + 'Langerwehe', + 'Haramachida', + 'Levoca', + 'Mondolfo', + 'Svrljig', + 'Imbau', + 'Raje', + 'Aibongo', + 'Maria da Fe', + 'Prieska', + 'Tafrant', + 'Brazopolis', + 'Seacroft', + 'Kukdeshwar', + 'Opera', + 'Arvika', + 'Kodanad', + 'Wingene', + 'Horw', + 'Kelafo', + 'Neftcala', + 'Padavedu', + 'Manuel Ribas', + 'Sabinopolis', + 'Toubakoro', + 'Sines', + 'Saren', + 'North Mankato', + 'Knic', + 'Mahavanona', + 'Kashti', + 'Mapanas', + 'Bainbridge', + 'Omerli', + 'Pannimadai', + 'Zhabinka', + 'San Giorgio Ionico', + 'Forfar', + 'Nagardevla Budrukh', + 'Little Falls', + 'Bou Izakarn', + 'Al Mu`addamiyah', + 'Douar Hammadi', + 'Borborema', + 'Elk Plain', + 'Kouroussa', + 'Auray', + 'Ishikawa', + 'Maldon', + 'Terkuvenganallur', + 'Barkuhi', + 'Bennane', + 'Lich', + 'Crepy-en-Valois', + 'Shichinohe', + 'Aqkol', + 'Wennigsen', + 'Zeven', + 'Chebrolu', + 'Oleggio', + 'Cedar Lake', + 'Willowick', + 'Ad Dab`ah', + 'Kearsley', + 'Mykolaivka', + 'Mittegrossefehn', + 'Wulong', + 'Luling', + 'Campos Altos', + 'Antas', + 'Tapolca', + 'Kartuzy', + 'Siddapur', + 'Alangudi', + 'Rescaldina', + 'Minamiaizu', + 'Fallsburg', + 'Nafplio', + 'Bensville', + 'Panr', + 'Kaoma', + 'Bochil', + 'Assenede', + 'Adustina', + 'Maisach', + 'Mill Valley', + 'Saraykent', + 'Feldkirchen', + 'Tranas', + 'Almoloya de Alquisiras', + 'Miraima', + 'Kawaii', + 'Haaren', + 'Oschatz', + 'Odlabari', + 'Shinto', + 'Ayomi', + 'Kalkar', + 'Chesterton', + 'Hobe Sound', + 'Montelupo Fiorentino', + 'Mankera', + 'Juan de Acosta', + 'Leyton', + 'Puerto Deseado', + 'Hautmont', + 'Pansemal', + 'Vinto', + 'Murrhardt', + 'Mackworth', + 'Grenaa', + 'Mnagueur', + 'Huron', + 'Castelsarrasin', + 'Nallagunta', + 'Talbahat', + 'Coolidge', + 'Uslar', + 'Pirangut', + 'Bhulwal', + 'Edingen-Neckarhausen', + 'Federal Heights', + 'Bamble', + 'Birqash', + 'Sanlucar la Mayor', + 'Feucht', + 'Ashtead', + 'Bua Yai', + 'Sao Jose do Cedro', + 'Mers el Hadjad', + 'Orumanayur', + 'Santol', + 'Mirandiba', + 'Barwon Heads', + 'Raghudebbati', + 'Katravulapalle', + 'Douarnenez', + 'Juan Aldama', + 'Antarvedipalem', + 'Dippoldiswalde', + 'Plewiska', + 'Jitwarpur Kumhra', + 'Grajales', + 'Staszow', + 'Wombourn', + 'Pulur', + 'Alto Santo', + 'Shergarh', + 'Buhusi', + 'Kutavur', + 'Clearview', + 'Beronono', + 'Narvik', + 'Sao Martinho do Bispo', + 'Sanjiang Nongchang', + 'Sun Lakes', + 'Nesebar', + 'Rambha', + 'Yuscaran', + 'Lauchhammer', + 'East Whiteland', + 'Boutilimit', + 'Ipiranga', + 'Beekman', + 'Thong Pha Phum', + 'Usti nad Orlici', + 'Massalubrense', + 'Kerben', + 'Omis', + 'Storozhynets', + 'Astolfo Dutra', + 'Kakunodatemachi', + 'Sai Buri', + 'Shepherdsville', + 'Santiago Jocotepec', + 'Collingswood', + 'Sur Singh', + 'Bad Ischl', + 'Ipanguacu', + 'Villasanta', + 'Tepoztlan', + 'Belison', + 'Kilattingal', + 'Luino', + 'Gurinhem', + 'Leirvik', + 'El Rodeo', + 'Bovenden', + 'Thonex', + 'Natanz', + 'Matias Barbosa', + 'Landau an der Isar', + 'Port Lincoln', + 'Lakewood Park', + 'Charcas', + 'Curua', + 'Nowy Tomysl', + 'Noya', + 'Kisanuki', + 'Powell', + 'Siroda', + 'Phulwar', + 'Capitao Eneas', + 'Varde', + 'Fergus Falls', + 'Lagoa Real', + 'Pierre', + 'Sibundoy', + 'Wittstock', + 'Eraura', + "Mu'minobod", + 'Pelezi', + 'Banos', + 'Lachute', + 'Trepuzzi', + 'Niska Banja', + 'Valentim Gentil', + 'Kemp Mill', + 'Doranahalli', + 'Byahatti', + 'Castel San Giovanni', + 'Oneonta', + 'Belm', + 'Bougzoul', + 'Sideropolis', + 'Titiribi', + 'Hohenstein-Ernstthal', + 'Kinogitan', + 'Rajim', + 'Rosemere', + 'Beilen', + 'Emerald', + 'Adakplame', + 'Allouez', + 'El Guetar', + 'Sungai Guntung', + 'Tan Van', + 'Sidi Ben Adda', + 'Indiana', + 'Dunmore', + 'Aldenhoven', + 'Tamar', + 'Ershui', + 'Jodoigne', + 'Aiuaba', + 'Koundian', + 'Hidalgo', + 'Oostakker', + 'Italva', + 'Lagoa dos Gatos', + 'Bezou', + 'Neuenkirchen', + 'Jefferson Valley-Yorktown', + 'Ponnampatti', + 'Caudry', + 'Andalgala', + 'Bishops Cleeve', + 'Ban Mueang Nga', + 'Santiago de Anaya', + 'Rotenburg an der Fulda', + 'East Wenatchee', + 'Nantucket', + 'Sumbal', + 'Tibasosa', + 'Zazafotsy', + 'Arenoso', + 'Talwat', + 'Sjenica', + 'Nina Rodrigues', + 'Montalvania', + 'Vammanal', + 'Arboga', + 'Grunstadt', + 'Kerugoya', + 'Pedro Afonso', + 'Beylul', + 'Teploklyuchenka', + 'New Ulm', + 'Sasan', + 'Ezequiel Montes', + 'Fisciano', + 'Moudjbara', + 'Pilas', + 'Thonotosassa', + 'Ahrensfelde', + 'El Socorro', + 'El Carmen de Atrato', + 'Karugamad', + 'Frunze', + 'Gouveia', + 'Chelmza', + 'Karlivka', + 'Khadra', + 'Nantwich', + 'Cojedes', + 'Mazamitla', + 'Rio de Oro', + 'Berettyoujfalu', + 'Wauconda', + 'Itakura', + 'Sidi Abdelkarim', + 'Nelas', + 'Aguas Vermelhas', + 'Daean', + 'Ostrzeszow', + 'Balassagyarmat', + 'Kottaiyur', + 'Mbini', + 'Amari', + 'Ciro Marina', + 'Suknadanga', + 'Karai', + 'Uttukkottai', + 'Rio Azul', + 'Mignoure', + 'Barari', + 'Primrose', + 'Itaguacu', + 'Sharonville', + 'Hazel Grove', + 'Kiashahr', + 'Gafanha da Nazare', + 'Wezembeek-Oppem', + 'Petrolandia', + 'Tierra Amarilla', + 'Famenin', + 'Santa Adelia', + 'Esquipulas Palo Gordo', + 'Morpeth', + 'Circleville', + 'Antohobe', + 'Lakoucun', + 'St. Helens', + 'Uttoxeter', + 'Sibirila', + 'Barjora', + 'Taguatinga', + 'Leuna', + 'Ollioules', + 'Ilampillai', + 'Hawaiian Gardens', + 'Haivoron', + 'Keal', + 'Hokuei', + 'Turuttiyad', + 'Selmana', + 'Ranapur', + 'Riposto', + 'Solhan', + 'Marlow', + 'Alewah', + 'Fujikawa', + 'Martinho Campos', + 'Rajasur', + 'Busto Garolfo', + 'Beraketa', + 'Ambahita', + 'Marotsiraka', + 'Mahajamba', + 'Ambatomarina', + 'Antanambaobe', + 'Kalandy', + 'Bekipay', + 'Marokarima', + 'Mahatsinjony', + 'Vanono', + 'Talata-Vohimena', + 'Vatolatsaka', + 'Belambo', + 'Beharona', + 'Ambohimitombo', + 'Tsarahasina', + 'Bevato', + 'Ankiliabo', + 'Amborondra', + 'Bealanana', + 'Sahalanona', + 'Ambodihara', + 'Ilha de Mocambique', + 'O`nhayot', + 'Shofirkon Shahri', + 'Rafai', + 'Takerbouzt', + 'Thouars', + 'Brahmanandapuram', + 'Tall Banat', + 'Milha', + 'Meilen', + 'Montfoort', + 'Persan', + 'Kamituga', + 'Beach Park', + 'Schneeberg', + 'Annaram', + 'Sahnaya', + 'Cristopolis', + 'Lone Tree', + 'Tulle', + 'Coribe', + 'Koundara', + 'Bandraboua', + 'Lorsch', + 'Pathum Thani', + 'Taiyong', + 'Shandiz', + 'Matane', + 'Donji Vakuf', + "Sao Joao d'Alianca", + 'Kongarapalli', + 'Ambohimiera', + 'Chumpak', + 'Bebra', + 'Fleury-Merogis', + 'East Norriton', + 'Kuraymah', + 'Ganguvarpatti', + 'Beiwusidui', + 'Thames Centre', + 'Felixlandia', + 'Mirinzal', + 'Oud-Turnhout', + 'Jardim de Piranhas', + 'Erbach', + 'Sutihar', + 'Boha', + 'Santa Branca', + 'Kambila', + 'Mankal', + 'East Milton', + 'Sogutlu', + 'Raydah', + 'McFarland', + 'Beasain', + 'Ovidiu', + 'Merosina', + 'Thala', + 'Drapetsona', + 'Goianapolis', + 'Sakaki', + 'Lubben (Spreewald)', + 'Canteleu', + 'Grass Valley', + 'Roselle Park', + 'Pacaembu', + 'Hajdusamson', + 'Bedfordview', + 'Mjolby', + 'Kargipinar', + 'Meridjonou', + 'Chaugain', + 'Detva', + 'Eynesil', + 'Nova Ipixuna', + 'Alfredo Chaves', + 'McPherson', + 'Kepno', + 'Belwara', + 'Amaha', + 'Havelock North', + 'Kanakir', + 'La Entrada', + 'Belsandi Tara', + "Cassina de' Pecchi", + 'Misano Adriatico', + 'Bothell East', + 'Perdur', + 'Warrenville', + 'Audincourt', + 'Powell River', + 'Furukawamen', + 'Wells Branch', + 'Marostica', + 'Carleton Place', + 'Ichtegem', + 'Castellanza', + 'San Jose Acatempa', + 'Bang Racham', + 'Attibele', + 'Aracatu', + 'Sesquile', + 'Camp Pendleton South', + 'Brierley Hill', + 'Tsingoni', + 'Ibicui', + 'Tarhzout', + 'Montevrain', + 'Streetly', + 'Lower Moreland', + 'Vohringen', + 'Hunasagi', + 'Waimalu', + 'Hochstadt an der Aisch', + 'Grunberg', + 'Locorotondo', + 'Nachikatsuura', + 'Zhipingxiang', + 'Cossato', + 'Nyzhnia Krynka', + 'Khe Sanh', + 'Abre Campo', + 'Gesuba', + 'Sukma', + 'East Cleveland', + 'Julianadorp', + 'Diego de Almagro', + 'Asslar', + 'Destin', + 'Caybasi', + 'Viraganur', + 'Temsamane', + 'Papagaios', + 'Mansidao', + 'Royal Kunia', + 'Oued Taria', + 'Alterosa', + 'Lons', + 'Maracai', + 'Weissenhorn', + "Berre-l'Etang", + 'Muttunayakkanpatti', + 'Khergam', + 'Denzlingen', + 'Kelangah', + 'Alto Parana', + 'Oberhaching', + 'Sankt Leon-Rot', + "Debre Werk'", + 'Melsungen', + 'Midleton', + 'Moralzarzal', + 'Buchloe', + 'Bickley', + 'Kubadupuram', + 'Guelph/Eramosa', + 'Krishnarayapuram', + 'Wood Dale', + 'Santo Augusto', + 'Tucacas', + 'Grao Mogol', + 'Bukedea', + 'Mogeiro', + 'Hall in Tirol', + 'Orikhiv', + 'Bhogpur', + 'Salaverry', + 'Shiloh', + 'Jiran', + 'Olean', + 'Bog Walk', + 'Galmi', + 'Meerane', + 'Tidjelabine', + 'Joaquim Pires', + 'Polukallu', + 'Quakenbruck', + 'Rustington', + 'Tumbippadi', + 'Philippsburg', + 'Eastham', + 'Areado', + 'Simplicio Mendes', + 'Makokou', + 'Cefalu', + 'Jabbeke', + 'Lauterbach', + 'Caselle Torinese', + 'Hockessin', + 'Sido', + 'Sunset', + 'Matican', + 'Friesenheim', + 'Beacon', + 'Tati', + 'New Franklin', + 'Hoa Thuong', + 'Ettenheim', + 'Torre del Campo', + "Ping'anbao", + 'Villalba', + 'Linganaboyinacherla', + 'Alcanena', + 'Taphan Hin', + 'Hilpoltstein', + 'Binkolo', + 'Tracunhaem', + 'Wakasa', + 'Oulad Chikh', + 'Billere', + 'Porto Alegre do Norte', + 'Ibipitanga', + 'Tamalameque', + 'Kishanpur Ratwara', + 'Artondale', + 'Polavaram', + 'Qiblai', + 'Manoel Vitorino', + 'Tarauna', + 'Avanhandava', + 'Shterpce', + 'Kingstown', + 'Huangyadong', + 'Weno', + 'Waycross', + 'Luozi', + 'Saboeiro', + 'Solaro', + 'Zhashkiv', + 'Carmopolis', + 'Markt Schwaben', + 'Grand Falls', + 'Toulal', + 'Zhovkva', + 'Iskapalli', + 'Millbury', + 'Polotitlan de la Ilustracion', + 'San Rafael Las Flores', + 'Amantea', + 'Bellair-Meadowbrook Terrace', + 'Parihara', + 'Dogachi', + 'Dryden', + 'Carapebus', + 'Oki', + 'Itaguara', + 'Beachwood', + 'Michendorf', + 'Mandalgarh', + 'Trinitapoli', + 'Mount Barker', + 'Kauriya', + 'Ribeiro do Amparo', + 'Hidaj', + "Khmis Sidi al 'Aydi", + 'Primavera', + 'Gangaikondan', + 'Saloa', + 'Barra do Mendes', + 'Tomino', + 'North Battleford', + 'Paripueira', + 'Valayam', + 'Fara in Sabina', + 'Kamigori', + 'South Sioux City', + 'Haidarnagar', + 'Vellodu', + 'Cosham', + 'Sauk Rapids', + 'Vembarpatti', + 'Strada', + 'Nules', + 'Pedro Velho', + 'Olympia Heights', + 'Maumee', + 'Bad Soden-Salmunster', + 'Enniskillen', + 'Khajawa', + 'Seiro', + 'Trbovlje', + 'Pigue', + 'Clemencia', + 'Wayland', + 'Irikkur', + 'Hassfurt', + 'Teays Valley', + 'Skoczow', + 'eManzimtoti', + 'Wanzleben', + 'Worgl', + 'Schwaz', + 'Colangute', + 'Forest Hill', + 'Turuvanur', + 'Dowbaran', + 'Lieusaint', + 'Calafat', + 'Magalhaes de Almeida', + 'Meckenbeuren', + 'Krumbach', + 'Littleborough', + 'Ewarton', + 'Channahon', + 'Nawagarh', + 'Plav', + 'San Antonio de las Vueltas', + 'Passo de Camarajibe', + 'Tako', + 'Braselton', + 'Koppies', + 'Itagi', + 'Gangavalli', + 'Graca', + 'Villas', + 'Kamnik', + 'Boyovut', + 'Tachov', + 'Union de Tula', + 'Horodyshche', + 'Pierrelatte', + 'Kivertsi', + 'Ronne', + 'Achuapa', + 'Assai', + 'Vargem da Roca', + 'Carmo de Minas', + 'Iguatemi', + 'Loningen', + 'Bideipur', + 'Acajutiba', + 'Rixheim', + 'Sarayan', + 'Tibri', + 'Arbaa Laaounate', + 'Anapurus', + 'Lys-les-Lannoy', + 'San Giljan', + 'Oftringen', + 'Itapetim', + 'Hunxe', + 'Ban Bang Muang', + 'San Rafael Petzal', + 'Ban Tha Luang Lang', + 'Akropong', + 'Bellefontaine', + 'Roncq', + 'Siemiatycze', + 'Couvin', + 'Jinmingsi', + 'Rosyth', + 'Sannicandro Garganico', + 'Mont-Laurier', + 'Higashimiyoshi', + 'Yulee', + 'Ampasinambo', + 'Zhongliao', + 'Cacu', + 'Chaoyangdicun', + 'Lomma', + 'Guape', + 'Torul', + 'Morwell', + 'Grafelfing', + 'Varedo', + 'Arugollu', + 'Berceni', + 'Marianske Lazne', + 'Saint-Orens-de-Gameville', + 'Gouka', + 'Feliz', + 'Leverano', + 'Snoqualmie', + 'Tampamolon Corona', + 'Taggia', + 'Kodigenahalli', + 'Willow Grove', + 'Eppstein', + 'Singalandapuram', + 'Sao Pedro do Piaui', + 'Gulcho', + 'Cayce', + 'Bandarbeyla', + 'Amrabad', + 'Travagliato', + 'Lipno', + 'Nehram', + 'Chityal', + 'Megarine', + 'Orange Walk', + 'Holzgerlingen', + 'Kannivadi', + 'Waianae', + 'Douar Lehgagcha', + 'Jardin', + 'Settara', + 'Moissac', + 'Uruoca', + 'Rostamabad', + 'Central Elgin', + 'Itinga', + 'Flores de Goias', + 'Urupes', + 'Manavalakurichi', + 'Barghat', + 'Msata', + 'Forster', + 'Hawick', + 'Mata', + 'Badarwas', + 'Tacaimbo', + 'Beverstedt', + 'Bondeno', + 'Ephrata', + 'Zarghun Shahr', + 'Sidmouth', + 'Ermoupoli', + 'Hazel Crest', + 'Ataleia', + 'Futrono', + 'Lyaskovets', + 'Guaraniacu', + 'Priverno', + 'Enghien', + 'Urbino', + 'Kudachi', + 'Palkur', + 'Bodagudipadu', + 'St. James', + 'Angical', + 'Ibateguara', + 'Taglio', + 'Darihat', + 'Uruana', + 'Saint-Martin-de-Crau', + 'Miami Springs', + 'Malepur', + 'Nova Trento', + 'Sao Joao do Triunfo', + 'Milford Haven', + 'Xireg', + 'Kidlington', + 'Sobraon', + 'Nonoai', + 'North Fair Oaks', + 'Mistassini', + 'Tamaraikkulam', + 'Rocky Point', + 'Wezep', + 'Nova Canaa', + 'Lamont', + 'Saugeen Shores', + 'Eichstatt', + 'Sher Chakla', + 'Marienheide', + 'Knottingley', + 'Ipecaeta', + 'Moberly', + 'Mions', + 'Kovilur', + 'Crevalcore', + 'Cerro Largo', + 'Ndele', + 'Kaleyanpur', + 'Coldwater', + 'Colesville', + 'Biedenkopf', + 'Quata', + 'South Park', + 'Montataire', + "Toyloq Qishlog'i", + 'Sariq', + 'Papagos', + 'Mohda', + 'Presidente Kennedy', + 'Tiruppanandal', + 'Hinabangan', + 'Ingersoll', + 'Auriflama', + 'Angermunde', + 'Valencia West', + 'Diai Koura', + 'Kraainem', + 'Boa Nova', + 'Itapagipe', + 'Uarini', + 'Mangha', + 'Santa Cruz de Bezana', + 'Castel San Giorgio', + 'Tarumizu', + 'San Pedro Pochutla', + 'Radomyshl', + 'Genthin', + 'Chak Husaini', + 'Schmolln', + 'Glenpool', + 'Quatis', + 'Palmito', + 'Motupe', + 'Cambados', + 'Karma', + 'Maribondo', + 'Hettstedt', + 'Kannadiparamba', + 'Copalchi', + 'Kaladgi', + 'Slobozhanske', + 'Sansare', + 'Sendenhorst', + "Saint Ann's Bay", + 'Yongcong', + 'Normandia', + 'Altos del Rosario', + 'Bhimadolu', + 'Duverge', + 'Otley', + 'Rio Caribe', + 'San Ferdinando di Puglia', + 'Chiran', + 'Mucambo', + 'Pote', + 'Nova Veneza', + 'Jindayris', + 'Qantir', + 'Latham', + 'Bad Durrheim', + 'Namin', + 'Fiesole', + 'Warrensville Heights', + 'Xikou', + 'Isagarh', + 'El Crucero', + 'Saint-Jacques-de-la-Lande', + 'Chosei', + 'Pien', + 'Barahari', + 'Ajjampur', + 'Glen Carbon', + 'Mirabela', + 'Retirolandia', + 'Avalepalli', + 'San Agustin de Guadalix', + 'University Heights', + 'Jurema', + 'Domkonda', + 'Curiuva', + 'Shodoshima', + 'Speedway', + 'Lanuza', + 'Umburanas', + 'Helensburgh', + 'Childwall', + 'Woudenberg', + 'Pedreiras', + 'Beauharnois', + 'Kostolac', + 'El Kerma', + 'Beeville', + 'Frei Miguelinho', + 'Abadla', + 'Port Neches', + 'California', + 'Hammam el Rhezez', + 'Milovice', + 'Santa Coloma de Farnes', + 'Bunhe', + 'Kunjatturu', + 'Dantewara', + 'Uitgeest', + 'Trzebnica', + 'Pitlam', + 'Spring Garden', + 'Jiquirica', + 'Samorin', + 'Solonytsivka', + 'Balhapur', + 'Bamafele', + 'Boninal', + 'Engenheiro Caldas', + 'Allestree', + 'Ottaikkalmantapam', + 'Mahuwa Singhrai', + 'Saimbeyli', + 'Yesilli', + 'Jaca', + 'Maglie', + 'Babhanganwa', + 'Brecksville', + 'Ihtiman', + 'Santa Luzia do Itanhy', + 'Pfullendorf', + 'Artena', + 'Shamalgan', + 'Serra Branca', + 'Baianopolis', + 'Primeira Cruz', + 'Formello', + 'Oroco', + 'Brejo do Cruz', + 'Sao Felix do Araguaia', + 'Mantenopolis', + 'Verin', + 'Kyzyl-Adyr', + 'Castilla La Nueva', + 'Soller', + 'Kauhajoki', + 'Yamanobe', + 'Rozaje', + 'Tejutla', + 'Elesbao Veloso', + 'Karpi', + 'Kerepestarcsa', + 'Masangshy', + 'Combarbala', + 'Bollene', + 'Marchtrenk', + 'Qingxicun', + 'Chengara', + 'Amboasary-Gara', + 'Dongshicuo', + 'Barssel', + 'Atner', + 'Mohania', + 'Wyandanch', + 'Marhamat', + 'Vedi', + 'Vazquez', + 'Nighoj', + 'Jannat Shahr', + 'Danielskuil', + 'Rayapalle', + 'Razole', + 'Guerrero Negro', + 'Sisai', + 'Duvva', + 'Canasgordas', + 'Middlewich', + 'Okinoshima', + 'New Providence', + 'Amingarh', + 'Tapilula', + 'Doume', + 'Ixcatepec', + 'Raquira', + 'Leczyca', + 'Nybro', + 'Pirallahi', + 'Camapua', + 'Atome-Avegame', + 'Beaufort', + 'Rommerskirchen', + 'New Carrollton', + 'Pama', + 'Gonzalez', + 'West End', + 'San Jose Villanueva', + 'Wanze', + 'Neckargemund', + 'Gondalga', + 'Dueville', + 'East Islip', + 'Piquete', + 'Marghita', + 'Cervignano del Friuli', + 'Tokoroa', + 'Upanema', + 'Patalia', + 'Royal Wootton Bassett', + 'South Stormont', + 'Bridport', + 'Gran', + 'Presidente Bernardes', + 'Lappersdorf', + 'Serui', + 'Bardstown', + 'Latiano', + 'Dattapulia', + 'Pegnitz', + 'Sharm ash Shaykh', + 'Dhana', + 'Becancour', + 'Winsum', + 'Palestina', + 'Newington', + 'Asperg', + 'Talne', + 'Nalatvad', + 'Rossington', + 'Bandar-e `Asaluyeh', + 'Western Springs', + 'Echelon', + 'Haselunne', + 'Hilsea', + 'Kurtkoti', + 'Stolin', + 'Nesconset', + 'Plover', + 'Bishenpur', + 'Chinique', + 'Mor', + 'Ugo', + 'Oosterzele', + 'Niaogho', + 'Rahui', + 'Karnawad', + 'Tamanique', + 'Hola Prystan', + 'Kaharlyk', + 'Dinant', + 'Mascote', + 'Castelfranco di Sotto', + 'Endicott', + 'Wentorf bei Hamburg', + 'Rukhae', + 'Martinsville', + 'Kheri Naru', + 'Lexington Park', + 'Bexley', + 'Beur', + 'Kharv-e Sofla', + 'Amriswil', + 'Thisted', + 'Wschowa', + 'Hemsworth', + 'Albertirsa', + 'Janapadu', + 'Spaichingen', + 'Koubel-Koundia', + 'Shangping', + "`Alem T'ena", + 'Rheinfelden', + 'Corabia', + 'South Charleston', + 'Darat `Izzah', + 'Llanes', + 'Antigua', + 'Pfarrkirchen', + 'Eatontown', + 'Tovuz', + 'Bad Salzdetfurth', + 'Borgaon', + 'Vaires-sur-Marne', + 'General Belgrano', + 'Novi Iskar', + 'Calolziocorte', + 'Kafr Nabudah', + 'Tauberbischofsheim', + 'Cayiralan', + 'Adh Dhakhirah', + 'Nynashamn', + 'Menaa', + 'Sao Ludgero', + 'Lourdes', + 'Nova Varos', + 'Ban Bung Kha', + 'Strabane', + 'Kodriva', + 'Glowno', + 'Hlucin', + 'Avidha', + 'Mqam at Tolba', + 'Ban Mae Kaluang', + 'Wiesmoor', + 'Calderara di Reno', + 'Perungala', + 'Muynoq', + 'Siriari', + 'Karuvellur', + 'Hard', + 'Wolfhagen', + 'Shawangunk', + 'Ganxi', + 'Chima', + 'Kenadsa', + 'Sikat', + 'Courcouronnes', + 'Nemocon', + 'Cajabamba', + 'Hantsavichy', + 'Gardony', + 'Chandla', + 'Bayt Jala', + 'Stezzano', + 'Genas', + 'El Hachimia', + 'Marudur', + 'Squinzano', + 'Kriva Palanka', + 'Gines', + 'Gudikallu', + 'Vaghodia', + 'Chalma', + 'Schermbeck', + 'Afzala', + 'Fereydunshahr', + 'Ilamatlan', + 'Strand', + "Al Ha'ir", + 'Caapiranga', + 'Plouzane', + 'Bonita', + 'Itaete', + 'Madakkathara', + 'Fontenay-le-Comte', + 'King City', + 'Avocado Heights', + 'Little Hulton', + 'Jamira', + 'Elanad', + 'Kesariya', + 'Yedapalli', + 'Palakkuzhi', + 'Bad Laasphe', + 'Chembrassheri', + 'Sao Joao do Araguaia', + 'Dundigal', + 'Panjgirain Kalan', + 'General Viamonte', + 'Lake Forest Park', + 'Fruita', + 'Nagnur', + 'Nallajerla', + 'Gullapuram', + 'Moncks Corner', + 'San Juan de Limay', + 'Fontenay-le-Fleury', + 'Villanchirai', + 'Irondale', + 'Callaway', + 'Barro Alto', + 'Valdemorillo', + 'Mambore', + 'Beesel', + 'Dok Kham Tai', + 'Hevie', + 'Bou Sfer', + 'Bhakua', + 'Kulharia', + 'Taneichi', + 'Plougastel-Daoulas', + 'Sao Pedro da Agua Branca', + 'Kadattur', + 'Fort Lewis', + 'San Juan de Betulia', + 'Dakit', + 'Orkney', + 'Pefka', + 'Zabreh', + 'Uibai', + 'Ouargaye', + 'Tergnier', + 'Mallet', + 'Tucapel', + 'San Jacinto del Cauca', + 'Chinna Mushidivada', + 'Monteroni di Lecce', + 'Jucuaran', + 'Adis `Alem', + 'Avenal', + 'Versoix', + 'Anzin', + 'Germasogeia', + 'Veglie', + 'Daharia', + 'Ghordaur', + 'Nafpaktos', + 'Sultanpur Mor', + 'Chaddesden', + 'Kotgir', + 'Dinklage', + 'Talegaon Dhamdhere', + 'Srebrenica', + 'Basaon', + 'Azle', + 'Tuchola', + 'Sitio do Mato', + 'Sunjiayan', + 'Vellarivalli', + 'Benaulim', + 'Richterswil', + 'Zawodzie', + 'Dyykan-Kyshtak', + 'Seyitgazi', + 'Chahbounia', + 'Vieste', + 'Villa Union', + 'Gaundra', + 'Inawashiro', + 'Ban Don Thong', + 'Heswall', + 'Kalardasht', + 'Mosgiel', + 'Kaabong', + 'Kaiwen', + 'Dalkeith', + 'San Juan La Laguna', + 'Kilgore', + 'Arklow', + 'Uppidamangalam', + 'Panapakkam', + 'Velanganni', + 'Testour', + 'Lacombe', + 'Balsa Nova', + 'Connersville', + 'Goudomp', + 'Kokri', + 'Drobak', + 'Amblecote', + 'Arruda dos Vinhos', + 'Vikravandi', + 'Joppatowne', + 'Targuist', + 'Kissane Ltouqi', + 'Abhwar', + 'Alsager', + 'Gien', + 'Telmar', + 'Butler', + 'Pottsville', + 'Lislique', + 'Besarh', + 'Palmetto', + 'Bouzina', + 'Sanankoro Djitoumou', + 'Aconibe', + 'Faberg', + 'Atlantic Beach', + 'Urziceni', + 'Amondara', + 'Chimalapadu', + 'Goldap', + 'Luis Antonio', + 'Suluktu', + 'Varzea Nova', + 'San Jose de Maipo', + 'Ribeira Brava', + 'Paruchuru', + 'Sainte-Sophie', + 'Wake', + 'Boechout', + 'Margraten', + 'Kawatana', + 'Feldbach', + 'Saint Budeaux', + 'Corsham', + 'Grez-Doiceau', + 'Bagli', + 'Zollikon', + 'Calle Larga', + 'Barka Parbatta', + 'Hatoyama', + 'El Almendro', + 'Arzachena', + 'River Ridge', + 'Yengema', + 'Jupiter Farms', + 'Zehak', + 'Hosbach', + 'Slupca', + 'Mangalapur', + 'Amity', + 'Qigexingcun', + 'Lake Station', + 'Makwassie', + 'Egg Buckland', + 'Mucur', + 'Tiorpara', + 'Port-Alfred', + 'Bijai', + 'Sabana Iglesia', + 'Kotor', + 'Cadereyta', + 'Zbarazh', + 'Peabiru', + 'Nattappettai', + 'Sigli', + 'Shetpe', + 'El Carmen', + 'Vemulapudi', + 'Carnot-Moon', + 'Payyanadam', + 'Czluchow', + 'Andrews', + 'Buli', + 'Barlinek', + 'Karapurcek', + 'Pazhanji', + 'Charlton', + 'Mangalapuram', + 'Rezzato', + 'Serrolandia', + 'Yantzaza', + 'Marungur', + 'Weilburg', + 'Alzano Lombardo', + 'Mountain Park', + 'Kumlu', + 'Ubstadt-Weiher', + 'La Grange Park', + "Sant'Angelo Lodigiano", + 'Sweden', + 'Hillcrest', + 'Puerto Morazan', + 'Itapui', + 'Val-des-Monts', + 'Torshavn', + 'Amarpura', + 'Santa Maria a Monte', + 'Dambal', + 'Blue Ash', + 'Okkerneutboom', + 'Tiruvarpu', + 'Pataili', + 'Bacup', + 'Dohta', + 'Beamsville', + 'Hanimciftligi', + 'Broussard', + 'Saint-Amable', + 'Bachhauta', + 'Kiiminki', + 'Carluke', + 'Kiskoros', + 'Manerbio', + 'Kuurne', + 'Santa Marcela', + 'Morag', + 'Wabrzezno', + 'Dumaria', + 'Faradonbeh', + 'Shibam', + 'Coatesville', + 'Busra al Harir', + 'Duzkoy', + 'Nosivka', + 'Ostwald', + 'Chifubu', + 'Ampthill', + 'Sidi Abd el Moumene', + 'Narayangarh', + 'Ban Na Chom Thian', + 'Coomera', + 'White House', + 'Ambodilazana', + 'Grimstad', + 'Velen', + 'Kagvad', + 'Manching', + 'Saarwellingen', + 'Bouskene', + 'Torredonjimeno', + 'Makarska', + 'Kadena', + 'Woodinville', + 'Nishon Tumani', + 'Charxin', + 'Shirebrook', + 'Shiremoor', + 'Berck-sur-Mer', + 'Tounfit', + 'Goh', + 'Reeuwijk', + 'Ponte San Giovanni', + 'Elfers', + 'Sirhali Kalan', + 'Pushing', + 'Ratnapuram', + 'Undrajavaram', + 'Debno', + 'Argentan', + 'Woodland Park', + 'Soyaniquilpan', + 'Badhoevedorp', + 'San Rafael Oriente', + 'Arendonk', + 'Weinsberg', + 'Cremlingen', + 'Oued Tlelat', + 'Padaivedu', + 'El Tabo', + 'Berezne', + 'Catemu', + 'Reggada', + 'Zehdenick', + 'Aginiparru', + 'Bayt Sahur', + 'Bocaiuva do Sul', + 'Hullhorst', + 'Annamalainagar', + 'Kuhbil', + 'Panchgani', + 'Terebovlya', + 'Guillena', + 'Vetralla', + 'Gura Humorului', + 'Standish', + 'Ang Thong', + 'Carros', + 'Xylokastro', + 'Ikizce', + 'Ettapur', + 'Blytheville', + 'Tummanatti', + 'Montepulciano', + 'Schuttorf', + 'Thame', + 'Ergolding', + 'Urtaowul', + 'West Boldon', + 'Outreau', + 'Portage La Prairie', + 'Joaquim Nabuco', + 'Buttar', + 'Znin', + 'Sulingen', + 'Modakkurichchi', + 'Lincolnwood', + 'Secanj', + 'Amilly', + 'Ban Chomphu Nuea', + 'Bugugoucun', + 'Skoghall', + 'Tarhunah', + 'Tanagura', + 'Rabor', + 'North Greenbush', + 'Los Chiles', + 'Peringom', + 'Naranja', + 'Bas Goynuk', + 'Linlithgow', + 'Knutsford', + 'Aldeia de Paio Pires', + 'Liangwancun', + 'Karivalamvandanallur', + 'Doddipatla', + 'El Tablon', + 'Inderbor', + 'Orange City', + 'Kings Park West', + 'Olfen', + 'Peshkopi', + 'Ares', + 'Steamboat Springs', + 'Trophy Club', + 'Montespertoli', + 'Muragacha', + 'Khoyniki', + 'Herbrechtingen', + 'Fehmarnsund', + 'New Kingman-Butler', + 'Sumbha', + 'Empedrado', + 'Paraiso do Norte', + 'Usumatlan', + 'Ad Duraykish', + 'Kuttyattur', + 'Puerto San Martin', + 'Pe de Serra', + 'Ortaklar', + 'Chhapra', + 'Ostringen', + 'Lubsko', + 'Gangelt', + 'Manivilundan', + 'Sternberk', + 'Dharmaram', + 'Beverungen', + 'Lawang Bato', + 'Ulvila', + 'Daulatnagar', + 'Moody', + 'Ain Youcef', + 'Nanjai Kilabadi', + 'Dharphari', + 'Casandrino', + 'Casatenovo', + 'Borodyanka', + 'Damaishan', + 'Andresy', + 'Perladka', + 'Ivai', + 'Santa Juana', + 'Sebt Labrikiyne', + 'Afir', + 'Mahalpur', + 'Gopalasamudram', + 'Mesudiye', + 'Sarria', + 'Chiroqchi', + 'Nioaque', + 'Basseterre', + 'Orangeburg', + 'Beelitz', + 'Jula Buzarg', + 'Palos Verdes Estates', + 'Yakage', + 'Muriedas', + 'Arsali', + 'Bichkunda', + "Shin'onsen", + 'Blegny', + 'Lariano', + 'Morangis', + 'Yamato', + 'El Kansera', + 'Kathevaram', + 'Khiria', + 'San Martino di Lupari', + 'Dorado', + 'Walsall Wood', + 'Ambohidronono', + 'Bondada', + 'Chulumani', + 'Beyla', + 'Vaerlose', + 'Novellara', + 'Noceto', + 'Douar Sidi Laaroussi', + 'Xaafuun', + 'Camardi', + 'Benairia', + 'Tonakkal', + 'Guttal', + 'Kuressaare', + 'Trebur', + 'Ain Lechiakh', + 'Tempio Pausania', + 'Southwick', + 'Bombarral', + 'Chenggong', + 'Bundala', + 'Gmunden', + 'Nemours', + 'Hissaramuruvani', + 'Cheval', + 'Liedekerke', + 'Jobat', + 'Vila Pouca de Aguiar', + 'Carpinteria', + 'Ban Khlong', + 'Rio de Contas', + 'Villacidro', + 'Castelnuovo di Verona', + 'Marathalli', + 'Zayda', + 'Oncativo', + 'Parvomay', + 'Fraserburgh', + 'Puspokladany', + 'Cedar Grove', + 'Kingersheim', + 'Sovetskoe', + 'Auria', + 'Bischofsheim', + 'Hashikami', + 'Cariamanga', + 'Bagado', + 'Mouvaux', + 'Weddington', + 'Plaza Huincul', + 'Melilli', + 'Druskininkai', + 'Bou Arada', + 'Penamaluru', + 'La Llagosta', + 'Qal`eh Ganj', + 'Casale sul Sile', + 'Graulhet', + 'Lezajsk', + 'Medway', + 'Hajan', + 'Canals', + 'Santa Maria de Ipire', + 'Ceyu', + 'Samalsar', + 'Ridgefield Park', + 'Vestby', + 'San Jeronimo', + 'Ban Chorakhe Samphan', + "'Ain Mouilah", + 'Villa Juarez', + 'Villa Sandino', + 'Mulungu do Morro', + 'Capaya', + 'Igrapiuna', + 'Mahao', + 'Matsushima', + 'Drochia', + 'South Glengarry', + 'Hulkoti', + 'Santa Maria Jalapa del Marques', + 'Tinglayan', + 'Caerfyrddin', + 'Pell City', + 'Nako', + 'Rio do Antonio', + 'Autun', + 'Ban Nong Hoi', + 'Singuilucan', + 'Glucholazy', + 'Chanaral', + 'Vigodarzere', + 'Alovera', + 'Balya', + 'Hamworthy', + 'Bajala', + 'Asjen', + 'Mutterstadt', + 'Crispiano', + 'Balsta', + 'Radomir', + 'Kaua Kol', + 'Sainte-Marie', + 'Novi Becej', + 'Latisana', + 'Bom Principio', + 'Shinile', + 'Gothva', + 'South Daytona', + 'Bensekrane', + 'North Perth', + 'Monteux', + 'Sarezzo', + 'Ketsch', + 'Qulan', + 'Kofele', + 'Tetari', + 'Saktipur', + 'Ksibet el Mediouni', + 'Ba Chuc', + 'Sankt Georgen im Schwarzwald', + 'Satoraljaujhely', + 'Ayodhyapattanam', + 'Plattling', + 'Cicuco', + 'Chino Valley', + 'Berkeley Heights', + 'Sidmant al Jabal', + 'General Enrique Mosconi', + 'Brieselang', + 'Giporlos', + "Alvorada D'Oeste", + 'Silago', + 'Koregaon', + 'Mahaboboka', + 'Maqsuda', + 'Tubmanburg', + 'Iraci', + 'Wehr', + 'Betatao', + 'Treuchtlingen', + 'Toura', + 'Rosbach vor der Hohe', + 'Brig-Glis', + 'Quattro Castella', + 'Phalaborwa', + 'Sargur', + 'Shitab Diara', + 'Kanabur', + 'Gland', + 'Wantage', + 'Rajupalem', + 'Grand Terrace', + 'Sao Domingos', + 'Tirumakudal Narsipur', + 'Pavona', + 'Mounds View', + 'Kozy', + 'Miranda do Corvo', + 'Mazatlan Villa de Flores', + 'Kavital', + 'Medapadu', + 'Lake Los Angeles', + 'La Grande', + 'Barsbuttel', + 'San Martin Zapotitlan', + 'Kottaram', + 'Mercedes Umana', + 'Chos Malal', + 'Albatera', + 'Wollaston', + 'North Palm Beach', + 'Guclukonak', + 'Soddy-Daisy', + 'Wolvega', + 'Joure', + 'Pomfret', + 'Itano', + 'Al Jumayliyah', + 'Tonosho', + 'Akseki', + 'Kussnacht', + 'San Antonio del Tequendama', + 'New Hanover', + 'Phra Samut Chedi', + 'Betanzos', + 'Darlowo', + 'Ionia', + 'Horst', + 'Andarai', + 'Caldeirao Grande', + 'Great Driffield', + 'Gex', + 'Gurlapeta', + 'Takkolam', + 'Cavdir', + 'Simijaca', + 'Chandhaus', + 'Udaipur Bithwar', + 'Kamikawa', + 'Peddavadlapudi', + 'Ekwari', + 'Huguan Nongchang', + 'Nasiyanur', + 'Hungen', + 'Motobu', + 'Oatfield', + 'Gouande', + 'Fannuj', + 'Cherry Hill Mall', + 'Darmanesti', + 'Apostolove', + 'Pendlebury', + 'Goodmayes', + 'Makabana', + 'Killai', + 'Scheessel', + 'Kalikiri', + 'Pallappalaiyam', + 'Cotegipe', + 'Jalhalli', + 'Dinbela', + 'Adi Keyh', + 'Milnrow', + 'Ribeirao do Pinhal', + 'Paina', + 'West Carrollton', + 'Kuruman', + 'Hajduhadhaz', + 'Balua', + 'Mohgaon', + 'Kafr `Awan', + 'On Top of the World Designated Place', + 'Lamacaes', + 'Muri', + 'Castlebar', + 'Rabot', + 'Balatonfured', + 'Nidzica', + 'Alto Garcas', + 'Dom Feliciano', + 'Vetlanda', + 'Godella', + 'Gamboula', + 'Forlimpopoli', + 'Kani-Bonzon', + 'Alcacer do Sal', + 'Afanyangan', + 'Monte Belo', + 'Danga', + 'La Crucecita', + 'Turvo', + 'Pandireddigudem', + 'Hadamar', + 'Hawaiian Paradise Park', + 'Aberystwyth', + 'Drongen', + 'Rasauli', + 'Mettet', + 'Velykodolynske', + 'Dahu', + 'Charabidya', + 'Turbihal', + 'Olivar Bajo', + 'Olivar', + 'Rodental', + 'Tezontepec', + 'Stjordalshalsen', + 'Lowshan', + 'Shahr-e Herat', + 'Nova Gorica', + "Capo d'Orlando", + 'Ajas', + 'Fernandina Beach', + 'Darasuram', + 'Missoes', + 'Holborn', + 'San Pietro Vernotico', + 'Dayalpur Sapha', + 'Baraon', + 'Shin', + 'Bolongongo', + 'Neuri', + 'Dinshaway', + 'Brackley', + 'Ubaporanga', + 'Barah', + 'Candiba', + 'Tetiiv', + 'Linnich', + 'Leibnitz', + 'Peddakurapadu', + 'Gangoli', + 'Bohmte', + 'Kalaiyamputtur', + 'Belpukur', + 'Forrest City', + 'Ampanavoana', + 'Thara', + 'Montgomeryville', + 'Chandauli', + 'Sidhwan', + 'Kaji', + 'Wasserburg am Inn', + 'Lawaan', + 'Quzanli', + 'Webb City', + 'Kahhale', + 'Ambararata', + 'Marovandrika', + 'Andreba', + 'Ampitasimo', + 'Ambohimahavelona', + 'Isaka-Ivondro', + 'Ambodiampana', + 'Andranomamy', + 'Ihorombe', + 'Antongomena-Bevary', + 'Antsirabe Afovoany', + 'Sahavalanina-Antenina', + 'Belemoka', + 'Mavorano', + 'Evato', + 'Tranovaho', + 'Amborompotsy', + 'Ambalakindresy', + 'Ambahoabe', + 'Vohitrindry', + 'Befandriana', + 'Ampanefena', + 'Ankilivalo', + 'Anjiajia', + 'Ambatondrakalavao', + 'Kirano', + 'Sakoabe', + 'Maroviro', + 'Ambakireny', + 'Tsiately', + 'Ambohitsilaozana', + 'Ambazoa', + 'Ambodisakoana', + 'Bemanevika', + 'Ambondrona', + 'Bejofo', + 'Manambolo', + 'Mangindrano', + 'Ankilimalinika', + 'Sandrakatsy', + 'Marojala', + 'Ilafy', + 'Morarano', + 'Befeta', + 'Amboaboa', + 'Manambidala', + 'Andohajango', + 'Harmah', + 'Sunne', + 'Alaverdi', + 'Midsomer Norton', + 'Galashiels', + 'Jalam', + 'Ghoradongri', + 'Moviya', + 'Amauna', + 'Dammennu', + 'Timberlake', + 'Lavello', + 'Bhalil', + 'Ksar Sghir', + 'Vieira do Minho', + 'Bocas del Toro', + 'Jennings', + 'Manalalondo', + 'Sebt Bni Garfett', + 'Anandapuram', + 'Waconia', + 'Gornalwood', + 'Lohiyar Ujain', + 'Ficarazzi', + 'Baduriatola', + 'Kottapadi', + 'Kara-Kyshtak', + 'Chhara', + 'Chawalhati', + 'Nacozari de Garcia', + 'Noyon', + 'Ridge', + 'West Monroe', + 'Korneuburg', + 'Steinkjer', + 'Paso de los Toros', + 'Zandhoven', + 'Sai Wan Ho', + 'Kibiito', + 'Ivanic-Grad', + 'Kollipara', + 'Vrbovec', + 'Bisee', + 'Cha da Alegria', + 'Antonio Prado', + 'Yiewsley', + 'Chang', + 'Schleiden', + 'Hoor', + 'Jianganj', + 'San Lucas', + 'Kanel', + 'Fouriesburg', + 'Pretoria-Noord', + 'Culaba', + 'Roding', + 'Sitalpur', + 'Ben', + 'Turi', + 'Barwat Pasrain', + 'Bachra', + 'Senmayacho-senmaya', + 'Larkspur', + 'An Thanh B', + 'Wanderley', + 'Rovinj', + 'Chapantongo', + 'Casinhas', + 'Wickede', + 'Lingamparti', + 'Itatiaiucu', + 'Abaran', + 'Uppada', + 'Juan de Herrera', + 'Palangarai', + 'Mizil', + 'Shenley Church End', + 'Campo de Criptana', + 'Montesarchio', + 'Cardoso Moreira', + 'Kingsbury', + 'Shanyincun', + 'Wicklow', + 'Kudangulam', + 'Schodack', + 'Pingtiancun', + 'Jhaua', + 'Montefiascone', + 'Pucioasa', + 'Saposoa', + 'Mirdaul', + 'Bocsa', + 'Mulakaluru', + 'Wachtersbach', + 'Vinings', + 'Jaitpur', + 'Solana Beach', + 'Tartarugalzinho', + "Sant Sadurni d'Anoia", + 'Lakkavaram', + 'Carpenedolo', + 'Cherutana Tekku', + 'Brejoes', + 'Maktar', + 'Shiwan', + 'Saint-Andre', + 'Camponogara', + 'Elandsdoorn', + 'Bou Fekrane', + 'Nossa Senhora do Livramento', + 'Gibraleon', + 'Sakhmohan', + 'Grantsville', + 'Japoata', + 'Amboise', + 'Rampur Shamchand', + 'North Adams', + 'Matinilla', + 'Trebaseleghe', + 'Gomparou', + 'Morungaba', + "'Ain Tolba", + 'Bni Khloug', + 'Isalo', + 'Meadville', + 'Kachavaram', + 'Song Phi Nong', + 'Atmakuru', + 'Qal`at al Madiq', + 'Lynnfield', + 'Nova Londrina', + 'Fengdeng', + 'Byram', + "D'Iberville", + 'Paranhos', + 'Woolton', + 'Sint-Gillis-bij-Dendermonde', + 'Tarnos', + 'Amarwa Khurd', + 'Tezze sul Brenta', + 'Chamical', + 'Holly Hill', + 'Mockern', + 'Castiglion Fiorentino', + 'Bujari', + 'Berja', + 'Statte', + 'St. Ann', + 'Messadine', + 'Kalanaur', + 'Balbalan', + 'Odder', + 'Schinnen', + 'Anolaima', + 'Leagrave', + 'Besigheim', + 'Chateaudun', + 'Cusset', + 'Cesky Krumlov', + 'Quierschied', + 'Lahaina', + 'Barra de Santa Rosa', + 'Tashi', + 'Fostoria', + 'Karahal', + 'Dardenne Prairie', + 'Khomam', + 'Bijelo Polje', + 'Amolatar', + 'Kapchorwa', + 'Goonellabah', + 'Corat', + 'Mayenne', + 'Cliftonville', + 'Kankandighi', + 'Trent Hills', + 'Vellakkinar', + 'Tirmaigiri', + 'Cho Moi', + 'Rossdorf', + 'Gurgunta', + 'Sisauna', + 'Kalappalangulam', + 'Monteprandone', + 'Bonneville', + 'Yuza', + 'Petrus Steyn', + 'Wommelgem', + 'Apuiares', + 'Saghar Sultanpur', + 'Bagewadi', + 'Moreira', + 'Esneux', + 'Elavanasur', + 'Pentapadu Kasba', + 'Barja', + 'Mandra', + 'Kalavai', + 'Crissiumal', + 'Uzwil', + 'Ambalarondra', + 'Bronderslev', + 'Highlands', + 'Kapelle', + 'Sangao', + 'Ayutla', + 'Khombole', + 'Ringnod', + 'Edattirutti', + 'Daru', + 'Suzu', + 'Cidelandia', + 'Suamico', + 'Moorreesburg', + 'Nurkot', + 'Frutillar', + 'Koturkolkara', + 'Keisen', + 'Causeni', + 'Kalush', + 'Lontras', + 'Palombara Sabina', + 'Kuala Kurun', + 'Finneytown', + 'Alayaman', + 'Colares', + 'Puren', + 'Red Bank', + 'Agutaya', + 'Tanakkangulam', + 'Woodhaven', + 'Vejer de la Frontera', + 'Chilwell', + 'Vadnais Heights', + 'Wadersloh', + 'Trail', + 'Muggia', + 'Calcinato', + 'Akayu', + 'Porto Murtinho', + 'Mansapur', + 'Rehti', + 'Mulaikkaraippatti', + 'Lanuvio', + 'Dhutauli', + 'Tehachapi', + 'Ecublens', + 'Saint-Andre-de-Cubzac', + 'Chinnasekkadu', + 'Daparkha', + 'Nuevo Ideal', + 'Malaryta', + 'Balao', + 'Abrera', + 'Saunshi', + 'Cheney', + 'Argentona', + 'Vedappatti', + 'Niandjila', + 'Zhongling', + 'Palmares do Sul', + 'Rahika', + 'Medfield', + 'Aldoar', + 'Bihariganj', + 'Sidlice', + 'Acasusso', + 'Sugauna', + 'Meric', + 'Florida City', + 'Dedemsvaart', + 'Gueret', + 'Emeryville', + 'Lansdowne', + 'Auriol', + 'Cavallino', + 'Kallad', + 'Fuldatal', + 'Janai', + 'Meddappakkam', + 'Puerto Jimenez', + 'Bloomsburg', + 'Seclin', + 'San Pietro in Casale', + 'Terrasini Favarotta', + 'Santa Rosa de Calamuchita', + 'Kadachchinallur', + 'Quartucciu', + 'Herzberg am Harz', + 'Sattar', + 'Barhauna', + 'Oxapampa', + 'Kaul', + 'Palacaguina', + 'San Juan Tecuaco', + 'Spilamberto', + 'Canelinha', + 'Raymond Terrace', + 'Mullassheri', + 'Nieuw Nickerie', + 'Salempur', + 'Fontanafredda', + 'Sugarland Run', + 'Juan L. Lacaze', + 'Tega Cay', + 'Nova Crixas', + 'Frederiksvaerk', + 'Santa Cruz Amilpas', + "M'dhilla", + 'Leopold', + 'Arakere', + 'Castellbisbal', + 'Antonivka', + 'Bad Urach', + 'Ganga', + 'Spiez', + 'Qazmalar', + 'The Nation / La Nation', + 'Bolintin Vale', + 'Nova Timboteua', + 'Ziro', + 'Bela Simri', + 'Bhagwanpur Khurd', + 'Douar Oulad Youssef', + 'Brenes', + 'Syston', + 'Little Lever', + 'Chiatura', + 'Venkatagirikota', + 'Rosario del Tala', + 'Bazidpur', + 'Ban Krang', + 'Bag`dod', + 'Yozyovon', + 'Santo Tomas La Union', + 'Govindgarh', + 'Yelmalla', + 'Rose Belle', + 'General Las Heras', + 'Teror', + 'Salzano', + 'Kachchippalli', + 'Spiesen-Elversberg', + 'Chinnakkampalaiyam', + 'Milngavie', + 'Tucson Estates', + 'Kalecik', + 'Arohi', + 'Overlea', + 'Toukoroba', + 'Kurwa Mathia', + 'Springbok', + 'Lokapur', + 'Florham Park', + 'Kyotera', + 'Rio Casca', + 'Santa Maria do Suacui', + 'Rampurwa', + 'Concepcion de Ataco', + 'Hulyaypole', + 'Mallapur', + 'Yavoriv', + 'Mesolongi', + 'Kasba Tanora', + 'Santa Ana de Yacuma', + 'Juvignac', + 'Aghbala', + 'Franeker', + 'Peissenberg', + 'Jasauli', + 'Oudenbosch', + 'Twistringen', + 'Kannudaiyampatti', + 'Sanderstead', + 'Kanbara', + 'Pichilemu', + 'Ocos', + 'Saint-Andre-les-Vergers', + 'Ashibetsu', + 'Tizgane', + 'Donwari', + 'Nangavalli', + 'Landeh', + 'Festus', + 'Velilla de San Antonio', + 'Chojnow', + 'Loyish Shaharchasi', + 'Gavere', + 'Lagoa Dourada', + 'Sorum', + 'Harpur Bochaha', + 'Nandyalampeta', + 'Huazalingo', + 'Chalfont Saint Peter', + 'Magdalena Milpas Altas', + 'Brzeg Dolny', + 'Agdangan', + 'Novo Lino', + 'Kaufungen', + 'Zag', + 'Perehinske', + 'San Anselmo', + 'Ban Tat', + 'Dhubaria', + 'Chahatpur', + 'Sedriano', + 'Sarahandrano', + 'Rodeio', + 'Bariyarpur', + 'Maheswa', + "Granarolo del l'Emilia", + 'Grover Beach', + 'Anaikal', + 'Antanandava', + 'Valbonne', + 'Big Bear City', + 'Casteel', + 'Kaeng Khoi', + 'Villa San Giovanni', + 'Kouti', + 'Vadasseri', + 'Nawada Gobindganj', + 'Barud', + 'Kolappalur', + 'Roudnice nad Labem', + 'Serra Azul', + 'Kamrej', + 'Maroli', + 'Eufaula', + 'Accokeek', + 'Rokupr', + 'Keerbergen', + 'Guymon', + 'Wietmarschen', + 'Begampur', + 'Ilicinia', + 'Dharampur Bande', + 'Cavarzere', + 'Terrabona', + 'Ban Sop Tia', + 'Bahadurpur', + 'Kochlowice', + 'Majarhat', + 'Chinna Gollapalem', + 'Calcinaia', + 'Mahabaleshwar', + 'Sebiston', + 'Vilanova del Cami', + 'Bandlaguda', + 'Chodov', + 'At Tur', + 'Jami', + 'Almirante', + 'Gartringen', + 'Koprubasi', + 'Sete Barras', + 'Chalette-sur-Loing', + 'Duvvuru', + 'Joanopolis', + 'Les Ponts-de-Ce', + 'Obalapuram', + 'Sulz am Neckar', + 'Canilla', + 'Ainsdale', + 'Ivanec', + 'Mar de Espanha', + 'Richton Park', + 'Oulad Rahmoun', + 'Khorol', + 'Brus Laguna', + 'Emmiganuru', + 'San Francisco de Mostazal', + 'Laamarna', + 'Debbache el Hadj Douadi', + 'San Antonio Aguas Calientes', + 'Bakhtawarpur', + 'Mahtha', + 'Kirchheim bei Munchen', + 'Varzaneh', + 'Kyotamba', + 'Pirnagar', + 'Annapolis Neck', + 'Hvardiiske', + 'Chaiyo', + 'Krupka', + 'Playa Grande', + 'Damarcherla', + 'Seiada', + 'Kaspi', + 'Sao Felix da Marinha', + 'Pennsville', + 'Sivalarkulam', + 'Madugula', + 'Buffelshoek', + 'Miranorte', + 'Nirakpurpali', + 'Serere', + 'Honggu', + 'Lymm', + 'Flitwick', + 'Zelzate', + 'Umag', + 'Samai', + 'Battulapalle', + 'Sason', + 'Puerto Ayora', + 'Caio', + 'Betton', + 'Sante Bennur', + 'Zelenodolsk', + 'Basmenj', + 'Librazhd-Qender', + 'Brad', + 'Peraiyur', + "Gricignano d'Aversa", + 'Altenstadt', + 'Buharkent', + 'Chuy', + 'Manakondur', + 'Bamhni', + 'Sangtuda', + 'Alampur Gonpura', + 'Bou Adel', + 'Dianguirde', + 'Dianke', + 'Challapata', + 'Santiago Amoltepec', + 'Ap Binh Thanh', + 'Feuchtwangen', + 'Mechtras', + 'Northlake', + 'Wawarsing', + 'Delemont', + 'Saint-Hilaire-de-Riez', + 'Hersbruck', + 'Maniyur', + 'Itayanagi', + 'Manorville', + 'Derventa', + 'Hedensted', + 'Luchong', + 'Cuisnahuat', + 'Brownhills', + 'Amos', + 'Beausoleil', + 'Ait Youssef Ou Ali', + 'Morazan', + 'Paradise Valley', + 'Winterberg', + 'Comines', + 'Olgiate Olona', + 'Neosho', + 'Taguai', + 'Ceuti', + 'Dunkirk', + 'Bad Abbach', + 'Diari', + 'Blaubeuren', + 'Meze', + 'Shirataka', + 'Fords', + 'Herk-de-Stad', + 'Wickliffe', + 'Kelso', + 'Gerpinnes', + 'Puduru', + 'Cairo Montenotte', + 'Hornsey', + 'Tamm', + 'Mugutkhan Hubli', + 'Valverde del Camino', + 'Santo Stino di Livenza', + 'Ahermoumou', + 'Kucove', + 'Malmedy', + 'Balpyq Bi', + 'Pasadena Hills', + 'Malhador', + 'Nakhla', + 'San Biagio di Callalta', + 'Sheopuria', + 'Gaffney', + 'Branson', + 'Waltershausen', + 'Ouzera', + 'Sinincay', + 'Takamori', + 'Bom Repouso', + 'Qiaotouba', + 'Alpen', + 'Sutton on Hull', + 'Tilari', + 'Schongau', + 'Fulton', + 'Novhorod-Siverskyi', + 'Awantipur', + 'Newington Forest', + 'Robertsville', + 'Market Warsop', + 'Warsop', + 'Bad Windsheim', + 'Nangola', + 'Isla Mujeres', + 'Petrovske', + 'Ziama Mansouria', + 'El Menzel', + 'Al Muzayrib', + 'Fortaleza dos Nogueiras', + 'Saltcoats', + 'Ponduru', + 'Los Hidalgos', + 'Horndean', + 'Holiday City-Berkeley', + 'Melvindale', + 'Groutville', + 'Rio Vermelho', + 'Koyulhisar', + 'Puttanattam', + 'Kakan', + 'Tenmalai', + 'De Haan', + 'North Walsham', + 'Adukam', + 'Kanniyambram', + 'San Marco in Lamis', + 'Souakene', + 'Dores do Indaia', + 'Tomball', + 'Enumclaw', + 'Shchastia', + 'Jaromer', + 'Naduhatti', + 'Costa Marques', + 'Knittelfeld', + 'Burj al `Arab', + 'Kadiyampatti', + 'Ap Phu Hai', + 'Castel Goffredo', + 'Teroual', + 'Maxcanu', + 'Junin de los Andes', + 'Presidente Janio Quadros', + 'Jalpura', + 'Cunda dia Baze', + 'Ulster', + 'Cedral', + 'Gurgentepe', + 'Villeneuve-les-Avignon', + 'Motkur', + 'Xalpatlahuac', + 'Concepcion Las Minas', + 'Summerstrand', + 'Isla Raton', + 'Buchs', + 'Steinheim', + 'Juterbog', + 'Ullo', + 'Mamakating', + 'Tamsaout', + 'Santa Barbara de Pinto', + 'Toplita', + 'Chariyakulam', + 'Oulad Ouchchih', + 'Yenipazar', + 'Bretzfeld', + 'Levelland', + 'Winnetka', + 'Minooka', + 'Lakeland South', + 'Kharak Kalan', + 'Road Town', + 'Brunsbuttel', + 'Garh Sisai', + 'Belagal', + 'Muttanampalaiyam', + 'Mendota', + 'Sariveliler', + 'Luchenza', + 'Galaosiyo Shahri', + 'Eski Arab', + 'Alat', + 'Angadikkal Tekkekara', + 'Hessisch Lichtenau', + 'Yzeure', + 'Canet-en-Roussillon', + 'Hosir', + 'Stupava', + 'Lamphun', + 'Khagra', + 'Grenada', + 'Wetaskiwin', + 'Dieli', + 'Brown Deer', + 'New Germany', + 'Dossenheim', + 'Minakshipuram', + 'Ibiracu', + "Jeppe's Reef", + 'Chropaczow', + 'Zimnicea', + 'Viota', + 'Cevicos', + 'Ban Tom Klang', + 'Kortemark', + 'Vilsbiburg', + 'Mahuakheraganj', + 'Koppal', + 'Hayashima', + 'Gaesti', + 'General Acha', + 'Sangar', + 'Wordsley', + 'Granville', + 'Jensen Beach', + 'Chandwa', + 'Lamballe', + 'Vatra Dornei', + 'Tuzdybastau', + 'Wieringerwerf', + 'Pago Pago', + 'Apricena', + 'Dabat', + 'Dingman', + 'Vidauban', + 'Karedu', + 'Dongyuancun', + 'Osecina', + 'Adre', + 'Saint-Jean-de-Vedas', + 'Appukkudal', + 'Chok Chai', + 'Vasylivka', + 'Duartina', + 'Gueltat Sidi Saad', + 'Tirukkattuppalli', + 'Kanra', + 'El Fuerte', + 'Campbelltown', + 'Lipari', + 'Tartar', + 'Quirihue', + 'Niefern-Oschelbronn', + 'Salobrena', + 'Croxley Green', + 'Upper', + 'Ancuabe', + 'Fene', + 'Prymorskyi', + 'Olen', + 'Maba', + 'Vohimarina', + 'Birni', + 'Cloquet', + 'Wadhraf', + 'Mandramo', + 'Rong Kwang', + 'Murud', + 'Nohsa', + 'Parasurampur', + 'Diamou', + 'Calanasan', + 'Cuers', + 'Armadale', + 'Pilich', + 'Marikal', + 'Devapur', + 'Osian', + 'Sankt Veit an der Glan', + 'Viera East', + 'Fonsorbes', + 'Pajo', + 'Dysselsdorp', + 'Sabugal', + 'Rantoul', + 'Monte Quemado', + 'Hirschaid', + 'Kwiha', + 'Monovar', + 'Cascades', + 'Ban Laem', + 'Chai Nat', + 'Conceicao do Rio Verde', + 'Makuyu', + 'Baraboo', + 'Luderitz', + 'Palos de la Frontera', + 'Kawamata', + 'Sarare', + 'Emstek', + 'North Smithfield', + 'Avrig', + 'Nakhtarana', + 'Varazze', + 'Kantang', + 'Jiuduhe', + 'Turki', + 'Hisarcik', + 'Rothenbach an der Pegnitz', + 'Preussisch Oldendorf', + 'Mablethorpe', + 'Chiampo', + 'Betma', + 'Mahrail', + 'Brock Hall', + 'Mayamankurichchi', + 'Bacalar', + 'Chikura', + 'Lake Norman of Catawba', + 'Villa Sola de Vega', + 'Hansot', + 'Justice', + 'Iconha', + 'Montegranaro', + 'Tola Khadda', + 'Fort Atkinson', + 'Montividiu', + 'Eloxochitlan', + 'Champadanga', + 'Kewatgawan', + 'Ereymentau', + 'West Grey', + 'Ladenburg', + 'Ialoveni', + 'Teulada', + 'Asbury Lake', + 'Zella-Mehlis', + 'Creutzwald', + 'Klobuck', + 'Gladenbach', + 'Gorazde', + 'Buchach', + 'Fort Bliss', + 'Campinorte', + 'Borgo San Dalmazzo', + 'Qarah', + 'Marabella', + 'Kashasha', + 'Beydag', + 'Edemissen', + 'Gumani', + 'Savalgi', + 'Borger', + 'Wolsztyn', + 'Pannaikkadu', + 'Sattegalam', + 'Stony Brook', + 'Miary', + 'Wlodawa', + 'Panj', + 'Culfa', + 'Dhanupra', + 'Sarasota Springs', + 'Anjahambe', + 'Paithan Kawai', + 'Giannouli', + 'Rionero in Vulture', + 'Goldenrod', + 'Codegua', + 'Nanzhai', + 'Coringa', + 'Puturge', + 'Wolverton', + 'Zuvvaladinne', + 'Gosaingaon', + 'Hincesti', + 'Uludere', + 'Canegrate', + 'Bauyrzhan Momyshuly', + 'Kingsburg', + 'Negotino', + 'Devsar', + 'Laarne', + 'Grave', + 'El Adjiba', + "Saint David's", + 'Vikasnagar', + 'Alwarkurichchi', + 'Xavantes', + 'Alto do Rodrigues', + 'Kotwapatti Rampur', + 'Rozhyshche', + 'Bang Phlat', + 'Ingeniero Maschwitz', + 'Okinawa Numero Uno', + 'Neuenburg am Rhein', + "'Ain el Assel", + 'Jerome', + 'Ocna Mures', + 'Santany', + 'Domahani', + 'Naysar', + 'Thair', + 'Poquoson', + 'Mariental', + 'Kamin-Kashyrskyi', + 'Tiruppalai', + 'Chabal Kalan', + 'Lana', + 'Kathanian', + 'Pidigan', + 'La Argentina', + 'San Miguel Panan', + 'Arhribs', + 'Upper Uwchlan', + 'Kuttiyeri', + 'Andernos-les-Bains', + 'Bheja', + 'Zaladanki', + 'Made', + 'Raamsdonksveer', + 'Sedro-Woolley', + 'Ranranagudipeta', + 'Canovanas', + 'Lakshminarayanapuram', + 'Matatiele', + 'Santa Ana Maya', + 'Voerendaal', + 'Ban Bang Non', + 'Singerei', + 'Bryne', + 'Hacilar', + 'Sylacauga', + 'North St. Paul', + 'Kuhsan', + 'Costessey', + 'Baker', + 'Chaval', + 'Mongat', + 'Barton upon Irwell', + 'Patiram', + 'Eyvanekey', + 'eXobho', + 'Ounagha', + 'Reshuijie', + 'Xinyingheyan', + 'Cetinje', + 'Busogo', + 'Iferhounene', + 'Pont-du-Chateau', + 'San Bartolo', + 'Putussibau', + 'Guruvarajukuppam', + 'El Tambo', + 'Cromer', + 'Refahiye', + 'Santana do Matos', + 'Nakskov', + 'Bickenhill', + 'Haddonfield', + 'Highland City', + 'Rozenburg', + 'Vernouillet', + 'Engenheiro Beltrao', + 'Macara', + 'Sillamae', + 'Bad Sassendorf', + 'Graben-Neudorf', + 'Bandipur', + 'Tilbury', + 'Chigwell', + 'Castelnaudary', + 'Anna Regina', + 'Ahirauliya', + 'Harrai', + 'Fagnano Olona', + 'Bagnolo Mella', + 'Kobiri', + 'Zonnebeke', + 'Boumia', + 'Satao', + 'Gamarra', + 'Celakovice', + 'Prairie Ridge', + 'Ozatlan', + 'Bhanas Hivre', + 'Sangan', + 'San Marino', + 'Upper Montclair', + 'Finspang', + 'Kanoni', + 'Hanumantanpatti', + 'Wimauma', + 'Nelmadur', + 'Villa Literno', + 'Shichuanxiang', + 'Gravatal', + 'Bischwiller', + 'Matsukawa', + 'Kankon', + 'Gogui', + 'Goiatins', + 'Los Santos', + 'Gohpur', + 'Koszutka', + 'Bandalli', + 'Balchik', + 'Kallupatti', + 'Campiglia Marittima', + 'Sint-Michiels', + 'Velten', + 'Dhansura', + 'Oshikango', + 'Guatica', + 'Pueblo Rico', + 'Titara', + 'Massena', + 'Provadia', + 'Jequeri', + 'Chachagui', + 'Warman', + 'Gulshan', + 'Taiynsha', + 'El Ayote', + 'Mallappulasseri', + 'Los Bellosos', + 'Hersham', + 'Maglod', + 'Huodoushancun', + 'Hizan', + 'Gaildorf', + 'Hullatti', + 'Bayona', + 'Grammichele', + 'Madiama', + 'Meerzorg', + 'Aywaille', + 'Kadiana', + 'Vallejuelo', + 'Escanaba', + 'Kolattur', + 'Kegeyli Shahar', + 'Mango', + 'Las Lomitas', + 'Prilly', + 'Hagenow', + 'Maraiyur', + 'Hinundayan', + 'Siki', + 'Kika', + 'Neerijnen', + 'Koluszki', + 'Xinbocun', + 'Mikashevichy', + 'Xinchangcun', + 'Ponnai', + 'Buttayagudem', + 'Arcozelo', + 'Trogir', + 'Sarableh', + 'Ambinanynony', + 'Payyanpalli', + 'Calvizzano', + 'Poco Branco', + 'Titisee-Neustadt', + 'Kalingiyam', + 'Brignais', + 'Triel-sur-Seine', + 'Orzinuovi', + 'Amelia', + 'San Pedro Jicayan', + 'Ebersberg', + 'Ammavarikuppam', + 'Kamtaul', + 'El Aouana', + 'Bollnas', + 'Chennampatti', + 'Boortmeerbeek', + 'Quinta de Tilcoco', + 'Kallamalai', + 'Lyelchytsy', + 'Pira', + 'Spondon', + 'Attanur', + "Anzola dell'Emilia", + 'Panjipara', + 'College', + 'Lewisburg', + 'Las Parejas', + 'Sher', + 'Zlocieniec', + 'Estepa', + 'Saboya', + 'Arma', + 'Conneaut', + 'Asfarvarin', + 'Tyngsborough', + 'Avigliana', + 'Nanakuli', + 'Ilmajoki', + 'Olagadam', + 'Oissel', + 'Villafranca de los Barros', + 'Dokkum', + 'Ribeirao Claro', + 'Issum', + 'Seravezza', + 'Vardenis', + 'Dharhara', + 'Bad Freienwalde', + 'Aubenas', + 'Mi`rabah', + 'Sarrebourg', + 'Moka', + 'Essenbach', + "L'Union", + 'Forecariah', + 'Ichora', + 'Coseley', + 'Sever do Vouga', + 'Fojnica', + 'Torroella de Montgri', + 'Porto Recanati', + 'Higashiagatsuma', + 'Gonzales', + 'Taraclia', + 'Biliaivka', + 'Pola de Laviana', + 'Ierapetra', + 'Rezvanshahr', + 'Piano di Sorrento', + 'Arluno', + 'Tup', + 'Nitte', + 'Bayanauyl', + 'Sydney Mines', + 'Gaimersheim', + 'Nobeji', + 'Vobkent Shahri', + 'Ovenden', + 'Tenambakkam', + 'Chepstow', + 'Sabinov', + 'Drouin', + 'Dubak', + 'Blackfoot', + 'Kladanj', + 'Cobh', + 'Lye', + 'Payariq Shahri', + 'Jork', + 'Herrin', + 'Patchogue', + 'Rinconada de Malloa', + 'Oulad Fares', + 'San Miguel Xoxtla', + 'Razlog', + 'Bad Fallingbostel', + 'Capdepera', + 'Mandalgovi', + 'Tiszavasvari', + 'Huai Yot', + 'Mutoko', + 'Bourem Inali', + 'Nong Khae', + 'Bandwar', + 'Kalajoki', + 'Laguna Paiva', + 'Maqu', + 'Vysoke Myto', + 'Pontecorvo', + 'Soubala', + 'Mecatlan', + 'Yoko', + 'Oulad Aissa', + 'Bozkurt', + 'Aphaur', + 'Leonforte', + 'Jaidte Lbatma', + 'Hawsh al Bahdaliyah', + 'Periyakoduveri', + 'Boumalne', + 'Dehqonobod', + 'Dragor', + 'Diamniadio', + 'Enkesen', + 'Kibuye', + 'Kalymnos', + 'Kattukkottai', + 'Desri', + 'Bulgan', + 'Capul', + 'Navelim', + 'Dawson Creek', + 'Shuangxianxiang', + 'Teotepeque', + 'Valga', + 'Jankinagar', + 'Harnes', + 'Aubergenville', + 'Mende', + 'Crestwood', + 'Dasraha Bhograjpur', + 'Cottonwood', + 'North Castle', + 'Sedziszow Malopolski', + 'Cambuquira', + 'Quimperle', + 'Cypress Lake', + 'Bou Arkoub', + 'Anklam', + 'Ocean Pines', + 'Kotia', + 'Gravenhurst', + 'Enniscorthy', + 'Heliopolis', + 'Sureshjan', + 'Shamaldy-Say', + 'Lake City', + 'Nkheila', + 'Wernau', + 'Chettipulam', + 'Pandalkudi', + 'Frohburg', + 'Biassono', + 'Makeni', + 'Aj Jourf', + 'Susa', + 'Tonyrefail', + 'Obikiik', + 'Qorao`zak', + "G'oliblar Qishlog'i", + 'Giffnock', + 'Prince Rupert', + 'Sacacoyo', + 'Vocklabruck', + 'La Motte-Servolex', + 'La Chapelle-Saint-Luc', + 'Kakching Khunou', + 'Paikpar', + 'Sendafa', + 'Ar Rommani', + 'Acarlar', + 'Lavagna', + 'Jefferson Hills', + 'Veurne', + 'McComb', + 'Bom Retiro do Sul', + 'Kot Shamir', + 'Rivarolo Canavese', + 'Narman', + 'Arbelaez', + 'Sidi Makhlouf', + 'Charmahin', + 'Ain Kansara', + 'Pont-Sainte-Maxence', + 'New Mills', + 'Melavayi', + 'Guisser', + 'Sala', + 'Cananeia', + 'Pebberu', + 'Gandorhun', + 'Acala del Rio', + 'Lavinia', + 'German Flatts', + 'Claye-Souilly', + 'Lodhikheda', + 'Eraniel', + 'Kasaishi', + 'Penal', + 'Teningen', + 'Bouca', + 'Haslev', + 'Thatto Heath', + 'Benisa', + 'Hathwan', + 'Streator', + 'Soklogbo', + 'Pendencias', + 'Home Gardens', + 'Doctor Phillips', + 'Yenkuvarigudem', + 'Lower Pottsgrove', + 'Fairfax Station', + 'Kafr Ruma', + 'Baikunthpur', + 'Kulattur', + 'Wolow', + 'Newman', + 'Gharbia', + 'Polas', + 'Burladingen', + 'Sevur', + 'Hatillo de Loba', + 'Ludwigslust', + 'Harrow on the Hill', + 'Bejar', + 'Dagmara', + 'Spearfish', + 'Dinkelsbuhl', + 'Pantepec', + 'Razua', + 'Jeronimo Monteiro', + 'Kamalnagar', + 'Beylaqan', + 'Cicciano', + 'Doi Lo', + 'Perth East', + 'Tzintzuntzan', + 'Godohou', + 'Neuhausen auf den Fildern', + 'Nurhak', + 'Teixeiras', + 'Gandara West', + 'Anderlues', + 'Gavardo', + 'Commerce', + 'Oulad Hamdane', + 'Ban Tap Tao', + 'Abu Dis', + 'Juchipila', + 'Marumori', + 'Malloussa', + 'Alucra', + 'Chasiv Yar', + 'Laichingen', + 'Paiker', + 'Mekra', + 'Mahespur', + 'Khujner', + 'West Deer', + 'West Plains', + 'Senjan', + 'Eral', + 'Ogulin', + 'Ouenou', + 'Kallanai', + 'Zaboli', + 'Boloso', + 'Effingham', + 'Doddanahalli', + 'Manamodu', + 'Engenheiro Paulo de Frontin', + 'Spresiano', + 'El Campo', + 'Porto Valter', + 'Lila', + 'Selston', + 'Ban Huai So Nuea', + 'Carnaubeira da Penha', + 'Neralakaje', + 'Narala', + 'Scotts Valley', + 'Cuichapa', + 'Nordstemmen', + 'Linkenheim-Hochstetten', + 'Tempoal de Sanchez', + 'Sala Consilina', + 'Beatrice', + 'Itiquira', + 'Sidi Aoun', + 'North Saanich', + 'Ramabitsa', + 'Kinrooi', + 'Zetel', + 'Newhaven', + 'Chamarru', + 'Presidencia de la Plaza', + 'Morbegno', + 'Hattem', + 'Steinheim am der Murr', + 'Bhachhi Asli', + 'Karrapur', + 'Affoltern am Albis', + 'Apen', + 'Emboscada', + 'Barra do Ribeiro', + 'Maxhutte-Haidhof', + 'Hassi Fedoul', + 'Bully-les-Mines', + 'Dharmastala', + 'Pathra', + 'Ujfeherto', + 'Bampur', + 'Obernai', + 'Puduvayal', + 'Malone', + 'Currimao', + 'Chene-Bougeries', + 'Fomeque', + 'Hanur', + 'Cedarburg', + 'Bom Lugar', + 'Arara', + 'Tsuruta', + 'Yakoma', + 'Chichli', + 'Okabecho-okabe', + 'Anao', + 'Hengshan', + 'Kumirimora', + 'Ghogha', + 'Lauriya Nandangarh', + 'Rottofreno', + 'Josefina', + 'Bershad', + 'Vrchlabi', + 'Profondeville', + 'Kolanpak', + 'Yakouren', + 'Koriukivka', + 'Brejinho', + 'Kottagudi Muttanad', + 'Montecorvino Rovella', + 'Karaburun', + 'Kuyganyor', + 'Yangiariq', + 'Sabbavaram', + 'Belwa', + 'Loberia', + 'Paranatama', + 'Sogndal', + 'Loiyo', + 'Concepcion Batres', + 'Cristais', + 'Santa Leopoldina', + 'Rudrur', + 'Diamond Springs', + 'Bukkapatnam', + 'Tamalpais-Homestead Valley', + 'Lake Tapps', + 'Te Awamutu', + 'Mariyammanahalli', + 'Doranda', + 'Lewisboro', + 'Kafr Buhum', + 'Port Victoria', + 'La Magdalena Chichicaspa', + 'Unguia', + 'North Merrick', + 'Hnivan', + 'Hobro', + 'Namchi', + 'Russi', + 'Chateaubriant', + 'Karimkunnum', + 'Malvinas Argentinas', + 'Saraiya', + 'San Mauro Pascoli', + 'Vulcanesti', + 'Oftersheim', + "'Ain Kerma", + 'Bashtanka', + 'Nevele', + 'Kuttur', + 'Kewanee', + 'Pianiga', + 'Pasca', + 'Rognac', + 'Bhaisalotan', + 'Katagon', + 'Uppukkottai', + 'Wrentham', + 'Moss Point', + 'Osterhofen', + 'Prevost', + 'Tomuk', + 'Ruti', + 'Ghoradal', + 'Sakawa', + 'Tiadiaye', + 'Rafina', + 'Olton', + 'Tioribougou', + 'Nemili', + 'Villamartin', + 'Cheadle', + 'Bhankarpur', + 'Riedisheim', + 'Bonyhad', + 'New Kensington', + 'Le Grand-Saconnex', + 'Matala', + 'Kayattar', + 'Brattleboro', + 'Puerto Nare', + 'Kottaya', + 'Vannivedu', + 'Na Wa', + 'Sagon', + 'Tholey', + 'Vandithavalam', + 'Khonobod', + 'Huetor Vega', + 'Claiborne', + 'Ebejico', + 'Encamp', + 'Barentin', + 'Choctaw', + 'Dranesville', + 'Gajhara', + 'Blonie', + 'Morab', + 'Oyon', + 'Liperi', + 'Samadh Bhai', + 'Wasilkow', + 'Rielasingen-Worblingen', + 'Marquetalia', + 'Arganil', + 'Gyomaendrod', + 'Kesarimangalam', + 'Ban Bo Luang', + 'Cocotitlan', + 'Havixbeck', + 'Panzgam', + 'Grumo Appula', + 'Tranent', + 'Eklahra', + 'Barsaun', + 'As Sars', + 'Mucuge', + 'Xiushuicun', + 'Muthuswamipuram', + 'Minabe', + 'Sainte-Adele', + 'Ban Bang Sai', + 'Ban Noen Phoem', + 'Sapna', + 'Sainte-Agathe-des-Monts', + 'Justo Daract', + 'Mulug', + 'Marsaskala', + 'Meitingen', + 'Bomlo', + 'Camp Verde', + 'Strzelin', + 'Salgado de Sao Felix', + 'Pachchaimalaiyankottai', + 'Mangarwara', + 'Eura', + 'Mandu', + 'El Sobrante', + 'Bela Palanka', + 'Bamber Bridge', + 'Macedonia', + 'Hagfors', + 'Socuellamos', + 'Ampasimbe', + 'Antri', + 'Pornichet', + 'Velair', + 'Ishkashim', + 'Kuzhippilli', + 'Hassi el Ghella', + 'Saclepea', + 'Brzeziny', + 'Kamianka-Dniprovska', + 'Kok-Janggak', + 'North Middleton', + 'Maili', + 'Choro', + 'Champahati', + 'San Prisco', + 'Wyndham', + 'Quesnel', + 'Citlaltepec', + 'Yecuatla', + 'Perleberg', + 'Gistel', + 'Santa Filomena', + 'Pulakurti', + 'Sonupur', + 'Punnila', + 'Yedtare', + 'New Baltimore', + 'Jerico', + 'Saint-Cyr-sur-Mer', + 'Bharweli', + 'Mitchellville', + 'Tahannawt', + 'Kinkala', + 'Mayate', + 'San Carlos Yautepec', + 'Datoda', + 'Waikanae', + 'Glubczyce', + 'Gulbahor', + 'Taltal', + 'El Marsa', + 'Manegaon', + 'Lenyenye', + 'Tring', + 'Crossville', + 'Umm ar Rizam', + 'Mattenhof', + 'Benoy', + 'Lehre', + 'Gieraltowice', + 'Munchenstein', + 'Sable-sur-Sarthe', + 'Kirippatti', + 'Acandi', + 'Bhairapura', + 'Anndevarapeta', + 'Dire', + 'Villars-sur-Glane', + 'Sassenburg', + 'Pillanallur', + 'Osako', + 'Kosjeric', + 'Steenokkerzeel', + 'Mostardas', + 'North Tidworth', + 'Narhat', + 'Zlatograd', + 'Si Mustapha', + 'Albox', + 'Sedgley', + 'Baozhong', + 'Mmadinare', + 'Glen Rock', + 'Durmersheim', + 'Portales', + 'Lower Gwynedd', + 'Ban Muang Ngam', + 'Papampeta', + 'Ganapatipalaiyam', + 'Paal', + 'Ipaumirim', + 'Miesbach', + 'Louvres', + 'Mugalivakkam', + 'Birdaban', + 'Kodusseri', + 'Dalby', + 'Mettlach', + 'La Queue-en-Brie', + "Motta Sant'Anastasia", + 'Sollies-Pont', + 'Rampur Kudarkatti', + 'Nihal Singhwala', + 'Borgosesia', + 'Hasbrouck Heights', + 'Bridgnorth', + 'Viswanathaperi', + 'Bhagwanpur Desua', + 'Unebicho', + 'East Renton Highlands', + 'Iwate', + 'Uzyn', + 'Piketberg', + 'Ugento', + 'Falesti', + 'Paslek', + 'Kalaidasht', + 'Nova Laranjeiras', + 'Kesabpur', + 'Valley Falls', + 'Tabua', + 'Dhaula', + 'Fenton', + 'Liuba', + 'Sinalunga', + 'Woodward', + 'Filandia', + 'Le Chambon-Feugerolles', + 'Al Majma`ah', + 'Poranga', + 'Curiti', + 'Ciudad-Rodrigo', + 'Sao Francisco do Maranhao', + 'Oiba', + 'Bishnah', + 'Bharokhara', + 'Pharkia', + 'Ponte da Barca', + 'Hodatsushimizu', + 'Mays Chapel', + 'Arroio do Tigre', + 'Jacala', + 'Destrehan', + 'Gardnerville Ranchos', + 'Nattarampalli', + 'Tall Dhahab', + 'Wolgast', + 'Voru', + 'Raismes', + 'Walton-on-the-Naze', + 'Chalgeri', + 'Eiras', + 'Solofra', + 'Nilo Pecanha', + 'Bangawan', + 'Ban Pae', + 'Erfelek', + 'Goner', + "Novalukoml'", + 'Bentley', + 'Rosdorf', + 'Snihurivka', + 'Karagwe', + 'Gbanhi', + 'Lajia', + 'Honeygo', + 'Valenii de Munte', + 'Alavus', + 'Berwick-Upon-Tweed', + 'Sarmastpur', + 'Vilangurichchi', + 'North Lebanon', + 'Hwlffordd', + 'Pyrzyce', + 'Rocca Priora', + 'Baxiangshan', + 'Manne Ekeli', + 'Bagra', + 'St. Peter', + 'Mato Verde', + 'Pittalavanipalem', + 'Steha', + 'Kongsvinger', + 'Imassogo', + 'Karvetnagar', + 'Paramanandal', + 'Iapu', + 'Sabaur', + 'Celebration', + 'Ronneby', + 'Villa Berthet', + 'Edamon', + 'Slawno', + 'Assomada', + 'Gulni', + 'Liberty Lake', + 'Rosaryville', + 'Theux', + 'Marly', + 'Chudamani', + 'Utehia', + 'River Edge', + 'Huite', + 'Kumarkhali', + 'Nariman', + 'Key Largo', + 'Beyne-Heusay', + 'Velivennu', + 'San Jose El Idolo', + 'Occhiobello', + 'Balha', + 'Fort Campbell North', + 'Saddlebrooke', + 'Budakalasz', + 'Tomar do Geru', + 'Sahtah', + 'Monfort Heights', + 'Al Fayd', + 'Les Iles-de-la-Madeleine', + 'Opmeer', + 'Monte San Giovanni Campano', + 'Raffadali', + 'Sam', + 'Verde Village', + 'Jardim Alegre', + 'Fuensalida', + 'Warka', + 'Singhbari', + 'Viyapuram', + 'San Gennaro Vesuviano', + 'Basantpur', + 'Keimoes', + 'Hasroun', + 'El Qaa', + 'Chaqra', + 'Bteghrine', + 'Qoubaiyat', + 'Ambolomoty', + 'Fanambana', + 'Ivoamba', + 'Ankafina Tsarafidy', + 'Andonabe', + 'Sorombo', + 'Itondy', + 'Iarinarivo', + 'Saharefo', + 'Vohindava', + 'Beandrarezona', + 'Andranovao', + 'Sendrisoa', + 'Maromiandra', + 'Ambalavero', + 'Bekapaika', + 'Anorombato', + 'Ambaliha', + 'Ambohinamboarina', + 'Anjanazana', + 'Andrembesoa', + 'Anjiamangirana I', + 'Nosiarina', + 'Antanamalaza', + 'Andramy', + 'Basibasy', + 'Ampondra', + 'Antaritarika', + 'Befody', + 'Maromby', + 'Omatjete', + 'Umm Badr', + 'Buqkoosaar', + 'Keve', + 'Bilovodsk', + 'Hukumati Gizab', + 'Jajce', + 'Karranah', + 'Ngou', + 'Tefam', + 'Mettingen', + 'Wells', + 'Madina do Boe', + 'Princetown', + 'Petit-Goave', + 'Huvin Hippargi', + 'Khanda', + 'Pinneli', + 'Dahivel', + 'Jai', + 'Sadalgi', + 'Halgar', + 'Arni ka Khera', + 'Pramatam', + 'Cecchina', + 'View Park-Windsor Hills', + 'Sokouhoue', + 'Oberschleissheim', + 'Urakawa', + 'Cimislia', + 'Arutla', + 'Talen', + 'Arkansas City', + 'Manuel Urbano', + 'Galvarino', + 'Boskovice', + 'Somersworth', + 'Wegrow', + 'Doranala', + 'Wang Saphung', + 'Mugdampalli', + 'Bolanos de Calatrava', + 'Alajuelita', + 'Mikkelin Maalaiskunta', + 'Martuni', + 'Shiotacho-matsusaki', + 'Rapho', + 'Husepur', + 'Winton', + 'Nagykata', + 'Tundhul', + 'Msambweni', + 'Yazihan', + 'Escazu', + 'Benifayo', + 'Kaviti', + 'Arth', + 'Iwanai', + 'Ifs', + 'Minehead', + 'Pata Putrela', + 'Klazienaveen', + 'Boldaji', + 'Tabocas do Brejo Velho', + 'Oulad Daoud', + 'Tryavna', + 'Gundelfingen', + 'Arakvaz-e Malekshahi', + 'Belampona', + 'Siruvachchur', + 'Minnal', + 'Kuangfu', + 'Rasingapuram', + 'Hathauri', + 'Erbaocun', + 'Santiago del Teide', + 'Marauatpur', + 'Kyzyl-Kyshtak', + 'Star', + 'Hadim', + 'Erkner', + 'Eraclea', + 'Kasaji', + 'Murnau am Staffelsee', + 'Froha', + 'Nueva Era', + 'Malthone', + 'Bernalda', + 'Mariana', + 'Sremska Kamenica', + 'Tetagunta', + 'Souq Jamaa Fdalate', + 'Welver', + 'Stidia', + 'Taran', + 'Palos Heights', + 'Bissora', + 'Bena', + 'Tigzirt', + 'Niagadina', + 'Saksohara', + 'Ballston', + 'Viralippatti', + 'Awankh', + 'Terranuova Bracciolini', + 'Kountouri', + 'Paispamba', + 'Provins', + 'Phuoc Long', + 'Karaund', + 'Adalaj', + 'Ibaretama', + 'Sidi Yahia', + 'Selimpasa', + 'Noria', + 'Vijayapati', + 'Spencer', + 'Jiajin', + 'Arrigorriaga', + 'Umurlu', + 'Blaricum', + 'Tori-Cada', + 'Jadayampalaiyam', + 'Nong Bua', + 'Sondho Dullah', + 'Konaje', + "Trezzo sull'Adda", + 'Pecica', + 'Seberi', + 'Amarapuuram', + 'El Parral', + 'Avesta', + 'Mykhailivka', + 'Darabani', + 'Guidel', + 'Umri', + "Ait I'yach", + 'Zlate Moravce', + 'Joaquim Tavora', + 'South Miami', + 'Goulds', + 'Alijo', + 'Kozloduy', + 'Cano Martin Pena', + 'Governador Dix-Sept Rosado', + 'Sheerness', + 'Khem Karan', + 'Enns', + 'Cinisi', + 'Lienz', + 'Don Sak', + 'Salpazari', + 'Distraccion', + 'Lagoa do Ouro', + 'Rijkevorsel', + 'Parappukara', + 'Pfaffikon', + 'Backa Topola', + 'Dhanauri', + 'Matmata', + 'Tectitan', + 'Panuco de Coronado', + 'Totogalpa', + 'Cungus', + 'Andrelandia', + 'Heddesheim', + 'Saint-Ave', + 'Sai Kung Tuk', + 'Chaital', + 'Pedda Adsarlapalli', + 'Tosashimizu', + 'Schoonhoven', + 'Bueu', + 'Vehkalahti', + 'Mullurkara', + 'Patarra', + 'Athol', + 'Gisors', + 'Sandridge', + 'Sansale', + 'Tizi Nisly', + '`Anadan', + 'Mandasa', + 'Gig Harbor', + 'Bilauri', + 'Hatod', + 'Tache', + 'Brejetuba', + 'Wellington North', + 'Zhdanivka', + 'Paramankurichi', + 'Fort Bonifacio', + 'Edattala', + 'Grand Baie', + 'Lalmatie', + 'Aheqi', + 'Harrislee', + 'Bairo', + 'Huanian', + 'Kotla', + 'Kronshagen', + 'Tanakallu', + 'Kirikera', + 'Mamarappatti', + 'Halstead', + 'Bound Brook', + 'Williams Lake', + 'Chandpura', + 'Box Elder', + 'Zebbug', + 'Ried im Innkreis', + 'Craponne', + 'Tabontabon', + 'Ambatturai', + 'East Bethel', + 'Oqqo`rg`on', + 'Qorashina', + 'Bargoed', + 'Ajjanahalli', + 'Chinna Orampadu', + 'Kampenhout', + 'Bhansia', + 'Baohe', + 'Enamadala', + 'Zemamra', + 'Halasztelek', + 'Wanding', + 'Zumbagua', + 'Gundugolanu', + 'Talant', + 'Hamilton Square', + 'Mamqan', + 'Aragoiania', + 'Shamshernagar', + 'Pakra', + 'Gora Kalwaria', + 'Sultanhani', + 'Cousse', + 'Cachoeira de Minas', + 'Dom Basilio', + 'Lauria Inferiore', + 'Kagamino', + 'Ojuelos de Jalisco', + 'Imarui', + 'Mayiladi', + 'San Severino Marche', + 'Hattian Bala', + 'Gander', + 'Kamlapur', + 'Puliyampatti', + 'Benaguacil', + 'Gerstetten', + 'Jaltenango', + 'Onet Village', + 'Archdale', + 'Maisaka', + 'Badamdar', + 'Rushall', + 'Comasagua', + 'Linganore', + 'Mohnesee', + 'Epinay-sous-Senart', + 'Florange', + 'Mehsari', + 'Bernissart', + 'Snaresbrook', + 'Altavilla Vicentina', + 'Iwaka', + 'Eichenau', + 'Oulad Amrane el Mekki', + 'El Arba Des Bir Lenni', + 'Yuxiaguan', + 'Rudrangi', + "Sant'Agata di Militello", + 'Brunn am Gebirge', + 'Monschau', + 'Vanimo', + 'La Puebla del Rio', + 'Olgiate Comasco', + 'Meral', + 'Lake Elmo', + 'Malar', + 'Iacanga', + 'Ban', + 'Big Lake', + 'Aguasay', + 'Lissegazoun', + 'San Juan del Rio del Centauro del Norte', + 'Rankweil', + 'Lauenburg', + 'Eckington', + 'Khajuri', + 'Whistler', + 'Horodnia', + 'Hoyland Nether', + 'Chainpur', + 'Monte Compatri', + 'Ivybridge', + 'Sao Goncalo do Rio Abaixo', + 'Zriba-Village', + 'Imaculada', + 'Avadattur', + 'Miller Place', + 'Recreo', + 'Sixaola', + 'Vendas Novas', + 'Gberouboue', + "L'Isle-Adam", + 'Pedda Vegi', + 'Denduluru', + "Sant'Ambrogio di Valpolicella", + 'Myrne', + 'Monte di Procida', + 'Lapinig', + 'Bad Voslau', + 'Palmilla', + 'Dishashah', + 'Peonga', + 'Vellallur', + 'Torton', + 'Biltine', + 'Bibipet', + 'Lizzanello', + 'Kalipatnam', + 'Middleburg', + 'Angalakurichchi', + 'Cho Lach', + 'Trentham', + 'Chero', + 'Bordentown', + 'Wolnzach', + 'Son Servera', + 'Lahra Muhabbat', + 'Guabari', + 'Itamati', + 'Sirsia Hanumanganj', + 'Licinio de Almeida', + 'Locri', + 'Andraitx', + 'Bataredh', + 'Spilimbergo', + 'Bibbiena', + 'Mangpa', + 'Raesfeld', + 'Tiddas', + 'San Andres de Llevaneras', + 'Hirao', + 'Alum Rock', + 'Premnagar', + 'Bou Merdes', + 'La Tour-de-Peilz', + 'Areal', + 'Hemsbach', + 'San Pedro La Laguna', + 'Korahia', + 'Oiwa', + 'Pilis', + 'Endwell', + 'Rasulpur', + 'Vecchiano', + 'Ukrainsk', + 'Poulsbo', + 'Oestrich-Winkel', + 'Baranzate', + 'North Union', + 'Gross-Enzersdorf', + 'Camposampiero', + 'Chilonga', + 'Tapiratiba', + 'Leingarten', + 'Lauffen am Neckar', + 'Wath upon Dearne', + 'Toualet', + 'Barokhar', + 'Sidi Amer El Hadi', + 'Mountougoula', + 'Wargal', + 'Menfi', + 'Jataizinho', + 'Langgons', + 'Walldurn', + 'Barrafranca', + 'Befandefa', + 'Tikar', + 'Holalu', + 'Senirkent', + 'Castle Pines', + 'Bocaina', + 'Dolo Bay', + 'Yakushima', + 'Portela', + 'Mboro', + 'Sonosari', + 'Chateau-Gontier', + 'Street', + 'South Yarmouth', + 'Virgem da Lapa', + 'Oberderdingen', + 'Winfield', + 'Picayune', + 'Oswaldtwistle', + 'Kakalur', + 'Ghabaghib', + 'Thogapalle', + 'Muscoy', + 'Serra do Salitre', + 'Jalalaqsi', + 'Hobyo', + 'Beladi', + 'Little Chute', + 'Portoferraio', + 'Barapire', + 'Deerlijk', + 'Oued Cheham', + 'Novi Marof', + 'Sanpetru', + 'Neuenrade', + 'Fenoughil', + 'Oued Seguin', + 'Maizieres-les-Metz', + 'Susegana', + 'Le Relecq-Kerhuon', + 'Srirampuram', + 'Khanaqin', + 'Mountain Top', + 'Santa Cruz Michapa', + 'Axixa', + 'Somain', + 'Zao', + 'Muping', + 'Spreitenbach', + 'Kete Krachi', + 'Tortoreto', + 'Biknur', + 'Tiny', + 'Zwonitz', + 'Ryuo', + 'Cafayate', + 'Aougrout', + 'Vegarai', + 'Roda', + 'Hauzenberg', + 'Ngerengere', + 'Ronchi dei Legionari', + 'Portomaggiore', + 'Oak Hills', + 'Villecresnes', + 'Kehen', + 'Fiume Veneto', + 'Baitoa', + 'Yeniciftlik', + 'Pritzwalk', + 'Leutenbach', + 'Chiautla de Tapia', + 'Sidi Ladjel', + 'Olivenza', + 'Tarrytown', + 'Bechloul', + 'Sahasmal', + 'Vauvert', + 'Khansahibpuram', + 'Market Drayton', + 'Borgaro Torinese', + 'Alamedin', + 'Putnam Valley', + 'Negele', + 'Green River', + 'Pragatinagar', + 'Burgthann', + 'Sao Goncalo do Para', + 'Kankaanpaa', + 'Allur', + 'Sipalakottai', + 'Kotha Guru', + 'Bitetto', + 'Show Low', + 'Baranivka', + 'Brotas de Macaubas', + 'Guttenberg', + 'Mack', + 'Drolshagen', + 'Campos del Puerto', + 'Cogolin', + 'Hankey', + 'Soderhamn', + 'Tifni', + 'Batocina', + 'Picana', + 'Owk', + 'Agcogon', + 'Tornquist', + 'Jaitwar', + 'Kornepadu', + 'Alken', + 'Annakattumula', + 'Pastpar', + 'Sher Muhammadpuram', + 'Mapleton', + 'Bopfingen', + 'Hawkesbury', + 'Blace', + 'Elektrenai', + 'Kuchinarai', + 'Moncion', + 'Possneck', + 'Bad Durrenberg', + 'Agadi', + 'Jose Maria Morelos', + 'Waldniel', + 'Tiruvadanai', + 'Rajaram', + 'Padinjaremuri', + 'Murukondapadu', + 'Lawrenceburg', + 'Abhia', + 'Edeia', + 'Chinaval', + 'Tolcayuca', + 'Francofonte', + 'Bajiao', + 'Cernay', + 'Konand', + 'Bilopillya', + 'Rossmoor', + 'Kamianka', + 'Ovidiopol', + 'An Cabhan', + 'Bajestan', + 'Muong Theng', + 'Serravalle Pistoiese', + 'Carignan', + 'Ban Phan Don', + 'Scharbeutz', + 'Lindenberg im Allgau', + 'Vasylkivka', + 'Medina Sidonia', + 'Chaltabaria', + 'Vengavasal', + 'Palleja', + 'Yamamoto', + 'Lunenburg', + 'San Nicolas de los Ranchos', + 'General Cabrera', + 'Septemes-les-Vallons', + 'Hackney', + 'Chintapalle', + 'Rio Colorado', + 'Dinara', + 'Chaumont-Gistoux', + 'Zhetibay', + 'Altstatten', + 'Hardiya', + 'Sveti Nikole', + 'Mestrino', + 'Los Alamitos', + 'Mutia', + 'Ambatofisaka II', + 'Cossimbazar', + 'Shady Hills', + 'Irupi', + 'Koszeg', + 'Golub-Dobrzyn', + 'Baghauni', + 'Appingedam', + 'Guatajiagua', + 'Kruje', + 'Deutschlandsberg', + 'Nellipoyil', + 'Villefranche-de-Rouergue', + 'Carmiano', + 'Soalandy', + 'Aleksandrow Kujawski', + 'Chundal', + 'Auta', + 'Wetherby', + 'Nandimandalam', + 'Saaminki', + 'Spring Lake', + 'Ubai', + 'Macusani', + 'Costa de Caparica', + 'Sindalakkundu', + 'Malka', + 'Lantana', + 'Bithan', + 'Sowerby Bridge', + 'Semri', + 'Rattihalli', + 'Lower Burrell', + 'Bol', + 'Nakasongola', + 'Gatumba', + 'Chakai', + 'Geisenheim', + 'Tamezmout', + 'Sengurichchi', + 'Ujhana', + 'Rangsdorf', + 'Olhanpur', + 'Risca', + 'Tibbar', + 'Elma', + 'Ringwood', + 'Kissing', + 'Vellar', + 'Zarach', + 'Ibira', + 'Waltikon', + 'Nova Gradiska', + 'Angel R. Cabada', + 'Hildburghausen', + 'Barkagaon', + 'James Island', + 'Schwaigern', + 'Rostam Kola', + 'Lom Sak', + 'Jaco', + 'Irmo', + 'Sao Bento do Sapucai', + 'Luis Alves', + 'Malial', + 'Mallikkundam', + 'Izola', + 'Peiting', + 'Hollabrunn', + 'Conceicao do Castelo', + 'Billerbeck', + 'Seven Hills', + 'Saint-Pierre-du-Perray', + 'Venkidanga', + 'Tirodi', + 'Torri di Quartesolo', + 'Ulverston', + 'Sothgaon', + 'Cornedo Vicentino', + 'Signal Hill', + 'Center', + 'Kibi', + 'Bellmawr', + 'Peligros', + 'Elland', + 'Prudhoe', + 'Kiskunmajsa', + 'Vilandai', + 'Bokakhat', + 'Alahina', + 'Bolsover', + 'Randaberg', + 'Skofja Loka', + 'Talakad', + 'Fgura', + 'Sao Sebastiao do Uatuma', + 'Kautalam', + 'Limburgerhof', + 'Keolari', + 'Nellipaka', + 'Karanchedu', + 'Vermillion', + 'Bayyanagudem', + 'Dent', + 'Elavalli', + 'Chittattukara', + 'Bullas', + 'Tiszakecske', + 'Narasapuram', + 'Hallbergmoos', + 'Bryn', + 'Lanham', + 'Sassenage', + 'Ponte San Pietro', + 'Marotta', + 'Bagaura', + 'Stokke', + 'Berlaar', + 'Bhainsahi', + 'Jardim do Serido', + 'Zofingen', + 'San Pedro Ixcatlan', + 'Lajosmizse', + 'La Riviera', + 'Raubling', + 'Nandavaram', + 'Panamaram', + 'Yirol', + 'Sukurhutu', + 'Lakri', + 'Jangy-Kyshtak', + 'Lessogou', + 'Mixtla de Altamirano', + 'Samesi', + 'Isaszeg', + 'Newport East', + 'Emmaus', + 'Bucyrus', + 'Isaka', + 'Ansiao', + 'Kattakampala', + 'Isapur', + 'Mitai', + 'Mendota Heights', + 'Brock', + 'Mount Sinai', + 'Carver', + 'Cowdenbeath', + 'Zaoqiao', + 'Kizhakkanela', + 'Miami Shores', + "L'Ile-Perrot", + 'Durbuy', + 'Dhanaura', + 'Kunkalagunta', + 'Azcoitia', + 'Lundazi', + 'Bolbec', + 'Sonada', + 'Hemiksem', + 'Karmauli', + 'Siur', + 'Nzeto', + 'Guaicara', + 'Thiers', + 'Knin', + 'Half Moon Bay', + 'Angicos', + 'Utiel', + "Diao'ecun", + 'Motegi', + 'Tlachichilco', + 'Derassi', + 'Burnham', + 'Ermenek', + 'Dammapeta', + 'Weiz', + 'Pongode', + 'Kallakkudi', + 'Pepperell', + 'Porecatu', + 'Bayou Blue', + 'Ostrhauderfehn', + 'Nawa Nagar Nizamat', + 'Lubaczow', + 'Henley on Thames', + 'Middle Valley', + 'Lenvik', + 'Annappes', + 'Ban Mae Tuen', + 'Mahta', + 'Santa Cruz Itundujia', + 'Moulay Driss Zerhoun', + 'Balaxani', + 'Ielmo Marinho', + 'Kotra', + 'Summerland', + 'Mala Vyska', + 'Baghambarpur', + 'Saint-Gaudens', + 'Manabo', + 'Ibicuitinga', + 'Xexeu', + 'Castello de Ampurias', + 'Ziyodin Shaharchasi', + 'Pirauba', + 'Veyrier', + 'Rokiskis', + 'Ambohimahasoa', + 'Sint Anthonis', + 'Betmangala', + 'Geisenfeld', + 'Qasr-e Qand', + 'Rayavaram', + 'Kalmiuske', + 'Ascot', + 'Sunninghill', + 'Wolmirstedt', + 'Gararu', + 'Abertillery', + 'Sewai', + 'Kolnad', + 'Cadale', + 'Tafaraoui', + 'Wallingford', + 'Schiller Park', + 'Fuente de Oro', + 'Devipattinam', + 'Gansbaai', + 'Shuinancun', + 'Aduru', + 'Santa Comba Dao', + 'Jiquipilas', + 'Cangas de Narcea', + 'Renapur', + 'Hartsville', + 'Mombris', + 'Guraahai', + 'Phon', + 'Bassersdorf', + 'Halsur', + 'Ankli', + 'Huandacareo', + 'Zero Branco', + 'Chambray-les-Tours', + 'Sablan', + 'Ross-Betio', + 'Tummalacheruvu', + 'Weeze', + 'Sakib', + 'St. Clements', + 'Khimlasa', + 'Morur', + 'Casteldaccia', + 'Gainza', + 'Vadakkumbagam', + 'Kurabalakota', + 'Novoishimskiy', + 'Roessleville', + 'Yercaud', + 'Minnehaha', + 'Moss Bluff', + 'Oulad Friha', + 'Santa Genoveva de Docordo', + 'San Josecito', + 'Wichelen', + 'Ipaporanga', + 'Town and Country', + 'View Royal', + 'Gopalapuram', + 'Le Haillan', + 'Naigarhi', + 'Jethuli', + 'Castenedolo', + 'Bahadarpur', + 'Pettaivayttalai', + 'Jarabulus', + 'Haradok', + 'Jidigunta', + 'Okuizumo', + 'Ban Mae Kham Lang Wat', + 'Ban Wiang Phan', + 'Caraguatay', + 'Schwieberdingen', + 'River Forest', + 'Santa Cruz da Baixa Verde', + 'Onate', + 'Isola della Scala', + 'Pampas', + 'Kennebunk', + 'Eijsden', + 'Landsmeer', + 'Nieuwpoort', + 'Gold Canyon', + 'Gardere', + 'Puerto Suarez', + 'Uberherrn', + 'Loutraki', + 'Ghal Kalan', + 'Kushmanchi', + 'Navarro', + 'Kopervik', + 'Yangiqo`rg`on', + 'Xiaoba', + 'Messstetten', + "Ghinda'e", + 'Mistelbach', + 'Sathmalpur', + 'Khandpara', + 'Belgrave', + 'Aracas', + 'Perches', + 'Gulgam', + 'Cisneros', + 'Anatoli', + 'Stuarts Draft', + 'Molteno', + 'Kundiawa', + 'Leama', + 'Espita', + 'Itainopolis', + 'Perumbakkam', + 'Tadapurambakkam', + 'Esil', + 'Saint-Esteve', + 'Dabrowa Tarnowska', + 'Krosuru', + 'Sussex', + 'Derdara', + 'Bugongi', + 'Broome', + 'Carmo da Cachoeira', + 'Patera', + 'Downpatrick', + 'Ghambiraopet', + 'Port Lavaca', + 'Wanstead', + 'Muroto-misakicho', + 'Platteville', + 'Den Chai', + 'Chintalavadi', + 'Holesov', + 'Labbaikkudikkadu', + 'Sidi Kasem', + 'Kibungo', + 'Mangalkot', + 'Port Morant', + 'Matca', + 'Pieve di Soligo', + 'Lamosina', + 'Weinfelden', + 'Sinzheim', + 'Nalwar', + 'Roma', + 'Taineste', + 'Krapina', + 'Kantilo', + 'Saint Helena Bay', + 'Doda', + 'Mit Damsis', + 'Sunkarevu', + 'Bahagalpur', + 'Ichhapur', + 'Moparipalaiyam', + 'Maniago', + 'Okpo', + 'Nandipeta', + 'Ekero', + 'Quatipuru', + 'Budha Theh', + 'Golet', + 'Stelle', + 'Nidamangalam', + 'Epazoyucan', + 'Sahri', + 'Ingurti', + 'Ramena', + 'Calheta', + 'Noeux-les-Mines', + 'Doddappanayakkanur', + 'Shahpur Baghauni', + 'Giffoni Valle Piana', + 'Cholpon-Ata', + 'Loyalsock', + 'Olintla', + 'Jucati', + 'Velke Mezirici', + 'Gorey', + 'Kundurpi', + 'Drawsko Pomorskie', + 'Raun', + 'Blundellsands', + 'Cachoeira Alta', + 'Desanagi', + 'Mirik', + 'Grosse Pointe Park', + 'San Carlos de Guaroa', + 'Hlaingbwe', + 'Brislington', + 'Orchha', + 'Doukombo', + 'Sagada', + 'Nova Odesa', + 'Coronel Dorrego', + 'Belp', + 'San Lazaro', + 'Pakkam', + 'Piprahi', + 'Zejtun', + 'Xuan Trung', + 'Burley', + 'Radnevo', + 'Badou', + 'Hang Tram', + "Al M'aziz", + 'Estiva', + 'Gospic', + 'Dzouz', + 'Beniel', + 'Fort Morgan', + 'Liubashivka', + 'Dang`ara', + 'Liman', + 'Strombeek-Bever', + 'Kaboua', + 'Unterfohring', + 'Ostbevern', + 'Elgoibar', + 'Lencois', + "'Ain Roua", + 'Devikapuram', + 'Taviano', + 'Nova Ubirata', + 'Chauny', + 'Baruari', + 'Lovington', + 'Bouabout', + 'Kemigawa', + 'Elk City', + 'Mercogliano', + 'Oskaloosa', + 'Zeuthen', + 'Ihumwa', + 'Guayabal', + 'Wittingen', + 'Mount Fletcher', + 'Tawnza', + 'Oxelosund', + 'Sathiala', + 'Ridgefield', + 'Moyamba', + 'Lokhvytsya', + 'Tinogasta', + 'Novy Bor', + 'Westerkappeln', + 'San Gregorio di Catania', + 'Leon Valley', + 'Revuca', + 'Diosd', + 'Bank', + 'Peringottukurusshi', + 'Yakymivka', + 'Gaurihar Khaliqnagar', + 'Healdsburg', + 'Fatehpur Shahbaz', + 'Alto Alegre dos Parecis', + 'Myronivka', + 'Jamsaut', + 'Panapur Langa', + 'Lindon', + 'Alfonsine', + 'East Glenville', + 'Bek-Abad', + 'Raca', + 'Sarbogard', + 'Satyavedu', + 'Kuriyama', + 'Gotzis', + 'Tadley', + 'Kavaratti', + 'Valea Adanca', + 'Lebon Regis', + 'Vengikkal', + 'Poldasht', + 'Sun Village', + 'Gonubie', + 'Pirangi', + 'Sinkolo', + 'Muna', + 'El Ancor', + 'Mios', + 'Hoenheim', + 'Kari', + 'Arasur', + 'Rupenaguntla', + 'Shanmukhasundarapuram', + 'Vlasenica', + 'Cidade Gaucha', + 'Prudente de Morais', + 'Agame', + 'Bhabanipur', + 'Fuller Heights', + 'Duruma', + 'Mariehamn', + 'Loran', + 'Ninga', + 'Kalakada', + 'Rengali', + 'Kashaf', + 'Douar Trougout', + 'Vedene', + 'Eningen unter Achalm', + 'Fourmies', + 'Khangaon', + 'Maruttuvakkudi', + 'Buram', + 'Vitry-le-Francois', + 'Culcheth', + 'Shingbwiyang', + 'Mogilno', + 'Egelsbach', + 'Pike Creek Valley', + 'Ahlaf', + 'Cocentaina', + 'Chakwai', + 'Wilton Manors', + 'Bellegarde-sur-Valserine', + 'Jodar', + 'Cantley', + 'Esmoriz', + 'Paro', + 'Chitauria', + 'Florestopolis', + 'Grafenhainichen', + 'Sidi Moussa Ben Ali', + 'Kirchhundem', + 'Odatturai', + 'El Khemis des Beni Chegdal', + 'Ban Saeo', + 'Satuek', + 'Montanhas', + 'Trostberg an der Alz', + 'Baroni Khurd', + 'North Wantagh', + 'Sideradougou', + 'Cumanda', + 'La Londe-les-Maures', + 'Milici', + 'New Garden', + 'University of California-Santa Barbara', + 'Sonoita', + 'Enghien-les-Bains', + 'Port Salerno', + 'Ajijic', + 'Dhalaa', + 'Erin', + 'Amdel', + 'Varzobkala', + 'Saubara', + 'Vlasim', + 'Harsum', + 'Lendinara', + 'Caetanopolis', + 'Gloucester City', + 'Campbellsville', + 'Egersund', + 'Barahkurwa', + 'Gandhari', + 'Woods Cross', + 'Tlacolulan', + 'Hato Corozal', + 'Mericourt', + 'Holyhead', + 'Dobbs Ferry', + 'Er Regueb', + 'Bad Schwalbach', + 'Ramallo', + "Notre-Dame-de-l'Ile-Perrot", + 'San Jose de Guaribe', + 'Mogogelo', + 'Kumari', + 'Stradella', + 'Koori', + 'Dorog', + 'Kuse', + 'Pallipattu', + 'Ain Legdah', + 'Malo Crnice', + 'Hohenkirchen-Siegertsbrunn', + 'Vakhrusheve', + 'Nemyriv', + 'Velimese', + 'Laqraqra', + 'Kinattukkadavu', + 'Dautphe', + 'Kondhali', + 'Haydock', + 'Casier', + 'Sanniquellie', + 'Qax', + 'Naliya', + 'Bytca', + 'Cadolzburg', + 'Jimani', + 'Tourougoumbe', + 'Mahagama', + 'Kostinbrod', + 'Guinagourou', + 'Sales Oliveira', + 'Pothia', + 'Senduria', + 'Raibari Mahuawa', + 'Ulricehamn', + 'Florennes', + 'Sao Amaro das Brotas', + 'Cabo Verde', + 'Sociedad', + 'Lopon', + 'Prataparampuram', + 'Tysvaer', + 'Lumaco', + 'Majdal Shams', + 'Ganserndorf', + 'Scottburgh', + 'Pelileo', + 'Laren', + 'Buzhum', + 'Dawley', + 'Saint-Cyprien', + 'Rostraver', + 'Plan-de-Cuques', + 'Byerazino', + 'Gundrajukuppam', + 'Wealdstone', + 'San Michele al Tagliamento', + 'Enebakk', + 'Sao Joao das Lampas', + 'Montegrotto Terme', + 'Saverne', + 'Yalluru', + 'Greetland', + 'Higashiizu', + 'Kincardine', + 'Marktheidenfeld', + 'Nyirbator', + 'Simrahi', + 'Clawson', + 'Douar Sgarta', + 'Saint-Junien', + 'Sidi Tabet', + 'Guacheta', + 'Yvetot', + 'Falimari', + 'East Grand Rapids', + 'Anjuna', + 'Hejiaji', + 'Grunwald', + 'Konakondla', + 'Campobello di Mazara', + 'Lijiacha', + 'Samayanallur', + 'Halavagalu', + 'Buckhurst Hill', + 'Baghmaria', + 'Harji', + 'Bind', + 'Hirnyk', + 'Onoto', + 'Sarjapur', + 'Snyder', + 'Rosario de Mora', + 'Campo do Meio', + 'Salamedu', + 'Pir Maker', + 'Staden', + 'Harrow Weald', + 'Suffern', + 'Mancha Real', + 'Great Bookham', + 'Little Bookham', + 'Lahfayr', + 'Bansbari', + 'Boudenib', + 'Buuhoodle', + 'Uchchangidurgam', + 'Kochkor', + 'Morgan City', + 'Tilmi', + 'Musile di Piave', + 'Elliot Lake', + 'Douar Oulad Naoual', + 'Pelsall', + 'Recke', + 'Kamiita', + 'Humahuaca', + 'Alcantaras', + 'Ploufragan', + 'Bhagwatpur', + 'Biddupur', + 'Puyehue', + 'Zambrano', + 'Parora', + 'Okmulgee', + 'Castalla', + 'Baghra', + 'Atharga', + 'Yangirabot', + 'San Jose del Fragua', + 'Lonate Pozzolo', + 'Progress', + 'Arumbakkam', + 'Meghraj', + 'Altdorf', + 'Jamhor', + 'Pachahi', + 'Manpaur', + 'Zierikzee', + 'Lyuban', + 'Sidi Baizid', + 'Carnoustie', + 'Gardone Val Trompia', + 'Bankya', + 'Rudersberg', + 'Phulparas', + 'Manappakkam', + 'Kalinagar', + 'Bromont', + 'Engen', + 'Parvatgiri', + 'Perampuzha', + 'Medulla', + 'Bargaon', + "Monte Sant'Angelo", + 'Rodenbach', + 'Catskill', + 'Klyetsk', + 'Talaigua Nuevo', + 'Bataipora', + 'Rothenburg ob der Tauber', + 'Charouine', + 'Ochsenfurt', + 'Vaal Reefs', + 'Cardoso', + 'Handewitt', + 'Taurisano', + 'Tegueste', + 'Nalambur', + 'Rheinau', + 'Knowsley', + 'Cherlagandlapalem', + 'Pimenteiras', + 'Lamsabih', + 'Capaci', + 'Ouaklim Oukider', + 'Teniet el Abed', + 'Domnesti', + 'Kurgunta', + 'Welzheim', + 'Dharmaj', + 'Cocoa Beach', + 'Yanahuanca', + 'Gustavsberg', + 'Waidhofen an der Ybbs', + 'Machados', + 'Humpolec', + 'Tokol', + 'Besalampy', + 'Gouvea', + 'Nussloch', + 'Ialysos', + 'Natshal', + 'Pemmperena', + 'El Quisco', + 'Papireddippatti', + 'Dugny', + 'Tiruvennanallur', + 'Langarivo', + 'Mashyal', + 'Rio Novo do Sul', + 'Ban Bang Lamung', + 'Barigarh', + 'Virton', + 'Tabapua', + 'Lardero', + 'Masinigudi', + 'Capitan Bado', + 'Varadarajampettai', + 'Taylorville', + 'Tosagua', + 'Capitan Sarmiento', + 'Leatherhead', + 'Gracemere', + 'Bitritto', + 'Marasesti', + 'Oxted', + 'Burslem', + 'Mulheim-Karlich', + 'Worb', + 'Tenenkou', + "Bruay-sur-l'Escaut", + 'Tazhakudi', + 'Janow Lubelski', + 'Hipperholme', + 'Edasseri', + 'Dimmbal', + 'Zimna Voda', + 'Saint-Germain-les-Arpajon', + 'Arnprior', + 'Villa Purificacion', + 'Denkendorf', + 'Ikhlaspur', + 'Sabana Yegua', + "Jem'at Oulad 'Abbou", + 'Periya Soragai', + 'Lafrayta', + 'Sebba', + 'Inhassoro', + 'Lieksa', + 'Caldogno', + 'Ichinohe', + 'Estiva Gerbi', + 'Gualcince', + 'Batemans Bay', + 'Caotan', + 'Singura', + 'Commune Sidi Youssef Ben Ahmed', + 'El Ghourdane', + 'Arslanbob', + 'Drochtersen', + 'Bad Nenndorf', + 'Panpuli', + 'Teano', + 'Getulina', + 'Chorleywood', + 'Antsambalahy', + 'Golfito', + 'Batonyterenye', + 'Tikota', + 'Amatenango del Valle', + 'Ban Kat', + 'Stamboliyski', + 'Svitlodarsk', + 'Pedro de Toledo', + 'Arpajon', + 'Norwell', + 'Dourdan', + 'Limavady', + 'Stanwell', + 'De Doorns', + 'Beldibi', + 'North Dundas', + 'Eichenzell', + 'Tramore', + 'Lakeland Highlands', + 'Pipariya', + 'Somavarappatti', + 'Biri', + 'Majanji', + 'Sajoszentpeter', + 'Kanhaipur', + 'Caimanera', + 'Bhilavadi', + 'Seneffe', + 'Dammartin-en-Goele', + 'Iskapalem', + 'Curimata', + 'Covenas', + 'Astley', + 'Fallersleben', + 'Riebeeckstad', + 'Simeria', + 'Sinor', + 'Asthal Bohar', + 'Caetano', + 'Bicske', + 'Samahuta', + 'Burtonwood', + 'Banavar', + 'Trecastagni', + 'Lowes Island', + 'Manvel', + 'Derecik', + 'Kurim', + 'La Roche-sur-Foron', + 'Sirpanandal', + 'Maryport', + 'Bara Belun', + 'Ventersburg', + 'Sogne', + 'Beclean', + 'Largs', + 'Westphalia', + 'Ocean City', + 'Edd', + 'Arcachon', + 'Boultham', + 'Datiana', + 'Kovurupalli', + "Sant'Ilario d'Enza", + 'Niasso', + 'North Valley', + 'Jadopur Shukul', + 'Groton', + 'Poko', + 'Narayanavanam', + 'El Playon', + 'Kin', + 'Two Rivers', + 'Jamaat Shaim', + 'Roncador', + 'Deodha', + 'Lang Suan', + 'Priolo Gargallo', + 'Quebrangulo', + 'Farciennes', + 'Pulpi', + 'Malkanur', + 'Alburquerque', + 'Sao Joao do Manhuacu', + 'Scalea', + 'Kings Mountain', + 'Sahsaul', + 'Moglingen', + 'Willistown', + 'Touama', + 'Prien am Chiemsee', + 'Las Charcas', + 'Saint-Jean', + 'Kingsnorth', + 'Makhmalpur', + 'Alpu', + 'Mannedorf', + 'Eranapuram', + 'Greasley', + 'Cranleigh', + 'Retie', + 'Kpandae', + 'Chintakunta', + 'Bramhabarada', + 'Bardiha Turki', + 'Attippattu', + 'Gethaura', + 'Kishunpur', + 'San Pablo Atlazalpan', + 'Akjoujt', + 'Sankt Johann im Pongau', + 'Pueblo Viejo', + 'Lavandevil', + 'Kourouma', + 'Derbisek', + 'Hagen im Bremischen', + 'Beniajan', + 'Tentena', + 'Bora', + 'Betania', + 'Mineiros do Tiete', + 'Resende Costa', + 'Mountain Ash', + 'Inzago', + 'Werther', + 'Lauingen', + 'Porto-Vecchio', + 'Moyuta', + 'Pasaco', + 'Monteforte Irpino', + 'Sidi Abdellah Ben Taazizt', + 'Anenecuilco', + 'Ortakent', + 'Rahiar Kunchi', + 'Crayford', + 'West Point', + 'Koog aan de Zaan', + 'Amarchinta', + 'Jagdishpur', + 'Lincolnton', + 'Aratuba', + 'Antonio Carlos', + 'Herbolzheim', + 'Hormigueros', + 'Gravelines', + 'Belauncha', + 'Vahdattiyeh', + 'Kassa', + 'Djemmorah', + 'Amala', + 'Granbury', + 'Kaset Wisai', + 'Vanj', + 'Castle Bromwich', + 'Wanaque', + 'Kedougou', + 'Hamadanak', + 'Miechow', + 'Sayda', + 'Sanzana', + 'Holic', + 'Pinheiro Machado', + 'Mannarai', + 'Hambantota', + 'Marquette-les-Lille', + 'Dhakaich', + 'Talupula', + 'Ranti', + 'Emba', + 'Prachatice', + 'Diez', + 'Montechiarugolo', + 'Nembro', + 'Schoningen', + 'Beni Ounif', + 'Khargram', + 'Isselburg', + 'Temamatla', + 'Tittachcheri', + 'Kummarapurugupalem', + 'Sonseca', + 'Lathasepura', + 'Carbonera', + 'Ichikai', + 'Guilherand', + 'Laukaria', + 'Lommedalen', + 'Budili', + 'Tagami', + 'Namli', + 'Kalasa', + 'Iygli', + 'Lloro', + 'Sanjiaocheng', + 'Tissa', + 'Valkeala', + 'Sarab-e Taveh-ye `Olya', + 'Borjomi', + 'Sirgora', + 'Chamestan', + 'Storm Lake', + 'Chikni', + 'Bhisho', + 'Pihuamo', + 'Faxinal dos Guedes', + 'Tournon-sur-Rhone', + 'Shahmirzad', + 'Kazarman', + 'Boiling Springs', + 'Feldkirchen-Westerham', + 'Mpraeso', + 'Busumbala', + 'Siniscola', + 'Nambour', + 'Guntupalle', + 'Damonojodi', + 'Arambakkam', + 'Pacoti', + 'Linslade', + 'Ilfracombe', + 'Prescot', + 'Bucheya', + 'Barka Gaon', + "Montopoli in Val d'Arno", + 'Los Almacigos', + 'Capilla del Monte', + 'Armstrong', + 'Kranenburg', + 'Parbata', + 'Wootton', + 'Malkhaid', + 'Aurelino Leal', + 'Hinwil', + 'Pungulam', + 'Harsinghpur', + 'Kawadgaon', + 'Baryshivka', + 'Rychnov nad Kneznou', + 'Chikkarampalaiyam', + 'Satellite Beach', + 'Mhangura', + 'Moreira Sales', + 'Vaux-le-Penil', + 'Gora', + 'Arvand Kenar', + 'Hoeilaart', + 'Grobbendonk', + 'Belzig', + 'Kuzuculu', + 'Seringueiras', + 'Westtown', + 'Tucson Mountains', + 'Coldstream', + 'Galbois', + 'Stonehaven', + 'New Port Richey East', + 'Potukonda', + 'Douar Jwalla', + 'Romanshorn', + 'Boujediane', + 'Nagalapuram', + 'Douar Ain Maatouf', + 'Rasaunk', + 'Penne', + 'Marginea', + 'Palukudoddi', + 'Targu Lapus', + 'Batesville', + 'San Jose de Aerocuar', + 'Sater', + 'Kumbadaje', + 'Margherita di Savoia', + 'Piedmont', + 'Elon', + 'Zaouiet Says', + 'Bollullos de la Mitacion', + 'Creazzo', + 'Vosselaar', + 'Capela de Santana', + 'Areiopolis', + 'Dorking', + 'Prymorsk', + 'Cacequi', + 'Bernardino de Campos', + 'Cherry Creek', + 'Chikha', + 'Honiton', + 'Inwood', + 'Mangalme', + 'Gerasdorf bei Wien', + 'North Lindenhurst', + 'Tambaga', + 'Kriftel', + 'Aylestone', + 'Bhandarso', + 'Sierra Madre', + 'Villepreux', + 'Aukstieji Paneriai', + 'Somnaha', + 'Hauterive', + 'Begogo', + 'Antonio Cardoso', + 'Finale Ligure', + 'Planura', + 'Bailin', + 'Mortugaba', + 'Waldkirchen', + 'Balve', + 'Sihaul', + 'Sonbari', + 'Bannewitz', + 'Mayureswar', + 'Okhargara', + 'Birch Bay', + 'Atru', + 'Pulsano', + 'Cerese', + 'Lloyd', + 'Barbadanes', + 'Cesson', + 'Dorridge', + 'Olaippatti', + 'Stollberg', + 'Hexham', + 'Cisternino', + 'Enfida', + 'Saadatpur Aguani', + 'Waipio', + 'Guebwiller', + 'Novska', + 'Banagi', + 'Balehonnur', + 'Oberwil', + 'Pongalur', + 'Kilkottai', + 'Ecaussinnes-Lalaing', + 'Kanamadi', + 'Udawantnagar', + 'Kurman', + "Finch'a'a", + 'Murapaka', + 'Roscoe', + "Ambinanin'i Sakaleona", + 'Evington', + 'Achankovil', + 'Jamapa', + 'Sheron', + 'Iazizatene', + 'Braunfels', + 'Kowdalli', + 'Valmadrera', + 'Burr Ridge', + 'Fagersta', + 'Kumharsan', + 'De Panne', + 'Brugg', + 'Quintanar de la Orden', + 'Orono', + 'Itanhomi', + 'Panhar', + 'Trofaiach', + 'Southborough', + 'Camisano Vicentino', + 'Elwood', + 'Congaz', + 'Shahrinav', + 'Mortad', + 'Kachnar', + 'White City', + 'Langeloop', + 'Puerto Caicedo', + 'Unicov', + 'Sao Jose do Campestre', + 'Nandayure', + 'Nawalpur', + 'Morant Bay', + 'Matsuo', + 'Mineral de Angangueo', + 'Hasbergen', + 'Iver', + 'Iuiu', + 'Saint-Saulve', + 'Gengenbach', + 'Kattupputtur', + 'La Massana', + 'Phulgachhi', + 'Kall', + 'Oporapa', + 'Alto Parnaiba', + 'Ikkadu', + 'Waupun', + 'Vila Frescainha', + 'Tha Chang', + 'An Phu', + 'Caorle', + 'Sorontona', + 'Firoza', + 'Murska Sobota', + 'Marilandia', + 'Comarnic', + 'Peri-Mirim', + 'Yamanouchi', + 'Mierlo', + "'Ain Taghrout", + 'Ollerton', + 'Port Wentworth', + 'Hatwans', + 'Kariz', + 'East Hanover', + 'Castelvetro di Modena', + 'Capitao de Campos', + 'Georgian Bluffs', + 'Oud-Heverlee', + 'Nagojanahalli', + 'Parapua', + 'Duggirala', + 'Ararenda', + 'Gucheng', + 'Illintsi', + 'Ksar Sbahi', + 'Biganos', + 'Yargatti', + 'Alcoa', + 'Raceland', + 'Melsele', + 'Calcado', + 'Bang Ban', + 'Chassieu', + 'Bhattiprolu', + 'Ban Wang Daeng', + 'Panguipulli', + 'Wulingshancun', + 'San Luis de La Loma', + 'Si Wilai', + 'Terku Valliyur', + 'Aydincik', + 'Herrsching am Ammersee', + 'Kariat Ben Aouda', + 'Ceu Azul', + 'Bagamanoc', + 'El Trebol', + 'Divinolandia', + 'Gacheta', + 'Canandaigua', + 'Juruaia', + 'Pedersore', + 'Congonhal', + "Sa'in Qal`eh", + 'Iguaraci', + 'Ramanayakkanpalaiyam', + 'Belen de los Andaquies', + 'Pata Ellamilli', + 'Moorslede', + 'Paullo', + 'Piazzola sul Brenta', + 'Pirapetinga', + 'Basaithi', + "Wen'anyi", + 'Pontchateau', + 'Arenzano', + 'Citrus Springs', + 'Berane', + 'Lalsaraia', + 'Dayalpur', + 'Karebilachi', + 'Codigoro', + 'Nossa Senhora dos Milagres', + 'Hebri', + 'Elchuru', + 'Merriam', + 'Niemasson', + 'El Aguila', + 'Tyrnavos', + 'Szprotawa', + 'Passy', + 'Kac', + 'Dois Riachos', + 'Stiring-Wendel', + 'Wyomissing', + 'Santa Mariana', + 'Barton upon Humber', + 'Cologno al Serio', + 'Lake Grove', + 'Shamunpet', + 'Marinette', + 'Doesburg', + 'Mahin', + 'Norvenich', + 'Panazol', + 'Kaniyambadi', + 'Villa La Angostura', + 'Longtaixiang', + 'Planegg', + 'Penagam', + 'General Carneiro', + 'La Calamine', + 'Timperley', + 'Whitchurch', + 'Great Wyrley', + 'San Giustino', + 'Great Neck', + 'Jayaque', + 'Korb', + 'Dalippur', + 'Lower Saucon', + 'Mainvilliers', + 'Hathidah Buzurg', + 'Bangramanjeshvara', + 'Rutesheim', + 'Devanakavundanur', + 'La Trinitaria', + 'San Carlos Centro', + 'Floresta Azul', + 'Shankarpalli', + 'Chhabila', + 'Kadur Sahib', + 'Coshocton', + 'Monmouth', + 'Mandal', + 'Awash', + 'Le Luc', + 'Nanpala', + 'Pharaha', + 'Pompton Lakes', + 'Novoazovsk', + 'Thanh Xuan', + 'Moita Bonita', + 'Wangjiabian', + 'Larbert', + 'Sturgis', + 'Brzeszcze', + 'Fagundes', + 'Glyka Nera', + 'Montlouis-sur-Loire', + 'Ballymoney', + 'Kisara', + 'Epping', + 'Madhopur', + 'Petal', + 'De Pinte', + 'Riorges', + 'Mukasi Pidariyur', + 'Andacollo', + 'Magnolia', + 'Rackeve', + 'Puliyara', + 'Joquicingo', + 'Jacinto', + 'Mohlin', + 'Bithlo', + 'Feira', + 'Sao Sebastiao de Lagoa de Roca', + 'Chornomorske', + 'Sankhavaram', + 'Sakkamapatti', + 'Bottesford', + 'Konen Agrahar', + 'Hikawadai', + 'Yuasa', + 'Lindome', + 'Athy', + 'Koch', + 'Perali', + 'Tezoatlan de Segura y Luna', + 'Aperibe', + 'Kenduadih', + 'Murgod', + 'Rezina', + 'Phanat Nikhom', + 'Tonse West', + 'Delvada', + 'Anguera', + 'Hornsby Bend', + 'Fanlu', + 'Riedlingen', + 'Waihee-Waiehu', + 'Cold Springs', + "Vel'ky Krtis", + 'Sao Felix', + 'Tekkumbagam', + 'Bertinoro', + 'Milicz', + 'Botupora', + 'Gernsheim', + 'Maromme', + 'Amha', + 'Qal`at an Nakhl', + 'Kongupatti', + 'Tirumayam', + 'Balingoan', + 'Brumunddal', + 'Corinda', + 'Carmo da Mata', + 'Weyburn', + 'Ekuvukeni', + 'El Hamel', + 'Tavistock', + 'Allahdurg', + 'Velddrif', + 'Nedelisce', + 'Sannieshof', + 'Itatuba', + 'Bir Ghbalou', + 'Greentree', + 'Gloucester Point', + 'Mawu', + 'Kiwoko', + 'Allonnes', + 'Chatteris', + 'Sarauni Kalan', + 'Fairview Shores', + 'Xinyaoshang', + 'Vijes', + 'Domazlice', + 'Patu', + 'Walur', + 'Dolhasca', + 'Franklin Lakes', + 'Chinna Annaluru', + 'Sebring', + 'Regen', + 'Solymar', + 'Saucillo', + 'Almhult', + 'Lorch', + 'Chauki', + 'Collegedale', + 'La Tuque', + 'Abasingammedda', + 'Ambotaka', + 'Kalafotsy', + 'Antsoha', + 'Maroambihy', + 'Voloina', + 'Ambatomasina', + 'Antsakanalabe', + 'Antsahabe', + 'Antakotako', + 'Tsararano', + 'Mahazony', + 'Fotsialanana', + 'Ambinanindovoka', + 'Ankavandra', + 'Manambolosy', + 'Ambohidranandriana', + 'Tsinjomitondraka', + 'Amporoforo', + 'Ambodimangavolo', + 'Analamitsivalana', + 'Bevata', + 'Antsambahara', + 'Androndrona Anava', + 'Sampona', + 'Marolinta', + 'Andranomeva', + 'Ambodimanary', + 'Maroamalona', + 'Marovantaza', + 'Marotandrano', + 'Efatsy-Anandroza', + 'Manandroy', + 'Tranomaro', + 'Vinaninkarena', + 'Soaserana', + 'Soamanova', + 'Loikaw', + 'Side', + 'Cerro Cora', + 'Zhamog', + 'Pingcha', + 'Al `Amadiyah', + 'Santa Flavia', + 'Itirucu', + 'Saint-Martin-Boulogne', + 'Byelaazyorsk', + 'Lyndon', + 'Edlapadu', + 'Bagnan', + 'Jagannathpur', + 'Agua de Dios', + 'Patori', + 'Vengapalli', + 'Farkhana', + 'Llandybie', + 'Matino', + 'Issoudun', + 'Westview', + 'Dhilwan Kalan', + 'Meaford', + 'Komorniki', + 'Churchdown', + 'Guspini', + 'Ribeirao Bonito', + 'Schkopau', + "Ma'ai", + 'Bardipuram', + 'Mansinghpur Bijrauli', + 'Myjava', + 'Akyaka', + 'Dayr `Atiyah', + 'Sabalito', + 'Wildau', + 'Nagar Nahusa', + 'Argostoli', + 'Colwyn Bay', + 'Santa Cruz Balanya', + 'Honwada', + 'North Logan', + 'Parauna', + 'Duas Barras', + 'Santa Croce Camerina', + 'Burkburnett', + 'Citrus', + 'Fao Rai', + 'Pingtouchuanxiang', + 'Bargas', + 'Paura Madan Singh', + 'Warden', + 'Cudworth', + 'Singoli', + 'Pebble Creek', + 'Chicureo Abajo', + 'Oakham', + 'Yelpur', + 'Sesto Calende', + 'Totowa', + 'Easttown', + 'Adjala-Tosorontio', + 'Koronowo', + 'Ahmadli', + 'Pirai do Norte', + 'Xintianfeng', + 'Manaira', + 'Staryya Darohi', + 'Rekovac', + 'Punjai Turaiyampalaiyam', + 'Cachira', + 'As Sabburah', + 'Mallagunta', + 'Satosho', + 'Takad Sahel', + 'Tixkokob', + 'Acanceh', + 'Haigerloch', + 'Cabanillas del Campo', + 'Bawali', + 'North Branch', + 'Champua', + 'Vochaiko', + 'Bhangha', + 'Campagnano di Roma', + 'Sarafand', + 'Ongwediva', + 'Guiratinga', + 'Medog', + 'Zhydachiv', + 'Tres Cachoeiras', + 'Ramabhadrapuram', + 'Alamos', + 'Vengur', + 'Masakkavundanchettipalaiyam', + 'Peschiera del Garda', + 'Grand Haven', + 'Volda', + 'Memunda', + 'Boekel', + 'Szydlowiec', + 'Rogozno', + 'Quimili', + "Dek'emhare", + 'Matias Olimpio', + 'Tarra', + 'El Tarra', + 'Eisenberg', + 'Ruthen', + 'Hellesdon', + 'Nacajuca', + 'Punitaqui', + 'Adendorf', + 'Neuhof', + 'Highgate', + 'Tirupporur', + 'Iioka', + 'Little Ferry', + 'Cunha Pora', + 'Burgkirchen an der Alz', + 'Tortoli', + 'Lezignan-Corbieres', + 'Longford', + 'Bishunpur Hakimabad', + 'Palsud', + 'Borsbeek', + 'Devgeri', + 'Satai', + 'Al Ghayzah', + 'Ibiraci', + 'Uttukkuli', + 'Mahmuda', + 'Volkermarkt', + 'Lichtenstein', + 'Nao Kothi', + 'Cepagatti', + 'Timahdit', + 'Vadamugam Vellodu', + 'Pottireddippatti', + 'Ruisui', + 'Chevigny-Saint-Sauveur', + 'Nallamada', + 'Cacaopera', + 'Ebreichsdorf', + 'Hasseh', + 'Pleasant View', + 'Hamilton Township', + 'Kalavapudi', + 'Pompton Plains', + 'Rialma', + 'Ban Yang Hom', + 'Vashon', + 'Rokytne', + 'Quilombo', + 'Itamarati', + 'Rumburk', + 'The Hills', + 'Pedappai', + 'Mena', + 'Semuto', + 'Nadendla', + 'Bni Drar', + 'Texcatepec', + 'Vimmerby', + 'Kabirpur', + 'Garmeh', + 'Shoo', + 'Bedford Heights', + 'Corbas', + 'Mazzarino', + 'Sangeorz-Bai', + 'Attard', + 'Etaples', + 'Kaniyur', + 'Orsta', + 'Malente', + 'Chaoke', + 'Valley Center', + 'Ingelmunster', + 'Swarna', + 'Donzdorf', + 'Karakthal', + 'West Caldwell', + 'Minamiise', + 'Sisia', + 'Hakone', + 'Chinnatadagam', + 'Bariarpur Kandh', + 'Basbiti', + 'Madna', + 'Wustermark', + 'Ponteland', + 'Mossley', + 'Ferney-Voltaire', + 'Hollinwood', + 'Kuttappatti', + 'Pellezzano', + 'Barberino di Mugello', + 'Berriozar', + 'Tibubeneng', + 'Wronki', + 'Gueoul', + 'Meliana', + 'Sontha', + 'Altensteig', + 'Karlsdorf-Neuthard', + 'Blitta', + 'Tizi', + 'Prineville', + 'Arniya', + 'Venosa', + 'Timberlane', + 'Bueno Brandao', + 'Groairas', + 'Rincon', + 'Kavaklidere', + 'Kenzingen', + 'Costesti', + 'Meulebeke', + 'Krosno Odrzanskie', + 'Oued Sebbah', + 'Keila', + 'Ogose', + 'Lehman', + 'Yairipok', + 'Koilakh', + 'Roque Perez', + 'Chenango', + 'Muswellbrook', + 'Khanjahanpur', + 'Sangram', + 'Nishi', + 'Pocono', + 'Bobrynets', + 'Osterwieck', + 'Karikad', + 'Chiltiupan', + 'Gages Lake', + 'Passa e Fica', + 'Tarwara', + 'Minamisanriku', + 'Imeni Chapayeva', + 'Bobrovytsia', + 'Xudat', + 'Castel Mella', + 'Nyakosoba', + 'Gilbues', + 'Santona', + 'Kodmial', + 'Manville', + 'Berthoud', + 'Alto Rio Doce', + 'Kiratpur Rajaram', + 'Haysville', + 'Soyalo', + 'Great Harwood', + 'Hardia', + 'Ghanpur', + 'Qasr-e Qomsheh', + 'Terryville', + 'Bernardo de Irigoyen', + 'Wisla', + 'Saire', + 'Yacopi', + 'Langenzenn', + 'Erstein', + 'Fife', + 'Triangle', + 'Gottmadingen', + 'Gluckstadt', + 'Beni Abbes', + 'Inverurie', + 'Gentio do Ouro', + 'Coroaci', + 'Yungay', + 'La Puebla de Cazalla', + 'Hammelburg', + 'Nova Vodolaha', + 'Itarana', + 'Conceicao dos Ouros', + 'Rambilli', + 'Chandur', + 'Wegorzewo', + 'Mae Wang', + 'Bofete', + 'Harri', + 'Garkha', + 'Petrovka', + 'Serravalle', + 'Sahoria Subhai', + 'Khan Bebin', + 'Nivala', + 'Castelginest', + 'Siversk', + 'Rush', + 'Pallarimangalam', + 'Schonaich', + 'Kothri Kalan', + 'Shing', + 'Santa Rosa de Rio Primero', + 'Figuig', + 'Anenii Noi', + 'Herxheim', + 'Estanzuela', + 'Panetha', + 'Guthrie', + 'Sant Joan de Vilatorrada', + 'Sagarejo', + 'Ankasakasabe', + 'Governador Lindenberg', + 'Puck', + 'Arapgir', + 'Lichtenau', + 'Avelino Lopes', + 'Ramchandarpur', + 'Rio dos Cedros', + 'Phrai Bueng', + 'Guantingzhan', + 'Bistan', + 'Tanippadi', + 'Amjhera', + 'Mataili Khemchand', + 'Burrel', + 'Etoumbi', + 'Davos', + 'Bondoufle', + 'Peru', + 'Geldermalsen', + 'Sanjiangkou', + 'Mogotes', + 'Soham', + 'Whitburn', + 'Wan Tau Tong', + 'Nirpur', + 'Malvern', + 'Worth', + 'Sarmiento', + 'Ukal', + 'Belmonte Mezzagno', + 'Adda-Doueni', + 'Risch', + 'Hambuhren', + 'Chirak', + 'Rianxo', + 'Rainhill', + 'Mudki', + 'Johvi', + 'Grand Gosier', + 'Venafro', + 'Onna', + 'Pir Bakran', + 'Estevan', + 'Anuppampattu', + 'Tiruppalaikudi', + 'Gol Tappeh', + 'Venmani Padinjara', + 'Dolbeau', + 'Palakollu', + 'Maryanaj', + 'Martinopole', + 'Steinbach am Taunus', + 'Sucua', + 'Kapaa', + 'Travilah', + 'Brunete', + 'Kyjov', + 'Patrasaer', + 'Yellayapalem', + 'Phibun Mangsahan', + 'Villa Corzo', + 'Pattanam', + 'Nauheim', + 'Afonso Bezerra', + 'Ghagga', + 'Kulgo', + 'Avintes', + 'Vargaur', + 'Ngorongoro', + 'Tatarbunary', + 'Cassa de la Selva', + 'Khlung', + 'Mount Kisco', + 'Urubici', + 'Lake Monticello', + 'Atchison', + 'Pottipuram', + 'South Dundas', + 'Dabiya', + 'Roseira', + 'Centenario do Sul', + 'Pua', + 'Mutluru', + 'Chiyoda', + 'Khattab', + 'Sitio Novo de Goias', + 'Sao Jeronimo da Serra', + 'Igaratinga', + 'Lavaur', + 'Earlestown', + 'Boizenburg', + 'Jitwarpur Chauth', + 'Reguengos de Monsaraz', + 'Amneville', + 'Jauli', + 'Van Wert', + 'Rajghat Garail', + 'Probistip', + 'Laranja da Terra', + 'Gamharia', + 'Kurwar', + 'Snovsk', + 'Manevychi', + 'Rampur Kalan', + 'Zurrieq', + 'Sao Luis do Curu', + 'Banu Chhapra', + 'Sugarmill Woods', + 'Union Park', + 'Susice', + 'East Cocalico', + 'Amatura', + 'Serekali', + 'Oliveirinha', + 'Dario Meira', + 'Stephanskirchen', + 'Biggin Hill', + 'Kurikuppi', + 'Alberique', + 'Cividale del Friuli', + 'San Valentino Torio', + 'Yuncos', + 'Hejamadi', + 'Alipur', + 'Olivenca', + 'Mulsen', + 'Keza', + 'Shepton Mallet', + 'Kaurihar', + 'Balupur', + 'Ugrinovci', + 'Bileca', + 'Rejiche', + 'Holmen', + 'Le Pont-de-Claix', + 'Chhatapur', + 'Andhana', + 'Tyamagondal', + 'Borshchiv', + 'Gympie', + 'Matomou', + 'Darmaha', + 'Eugenopolis', + 'Icononzo', + 'Palamedu', + 'Mangobandar', + 'Castano Primo', + 'Amuru', + 'Eski Yakkabog`', + 'Tallimarjon Shahri', + 'Bouchagroun', + 'Methil', + 'Terra Boa', + 'Wambrechies', + 'Fox Lake', + 'Panaon', + 'Papraur', + 'Kara-Tash', + 'South Union', + 'Guaraciaba', + 'Scornicesti', + 'Barbosa Ferraz', + 'Capena', + "Cornate d'Adda", + 'Muzaffarnagar', + 'Scaggsville', + 'Timonium', + 'Argeles-sur-Mer', + 'Wooburn', + 'Zafarabad', + 'Wald-Michelbach', + 'Binbrook', + 'Totolapan', + 'Seonar', + 'Marreddipalli', + 'Paduma', + 'Telkap', + 'Kuppachchipalaiyam', + 'Ambohidanerana', + 'Flixton', + 'Villa Nougues', + 'Los Corrales de Buelna', + 'Nurmo', + 'Sanson', + 'Kondakomarla', + 'Ravutulapudi', + 'Ousseltia', + 'Thouare-sur-Loire', + 'Miyato', + 'Cantillana', + 'Anavatti', + 'Belle Chasse', + 'Bougoula', + 'Annoeullin', + 'Tamiang Layang', + 'Parkstone', + 'Paceco', + 'Ovada', + 'Guaraci', + 'Nekarikallu', + 'Cave', + 'Chiramanangad', + 'Nilavarappatti', + 'Guaitarilla', + 'Matulji', + 'Bhanghi', + 'Nuvem', + 'Raymond', + 'Villamarchante', + 'Naranapuram', + 'Itamogi', + 'Nirkunnam', + 'Akhnur', + 'Pipalrawan', + 'Bhauradah', + 'Waasmunster', + 'Errahalli', + 'Punjai Kalamangalam', + 'Ban Bang Yai', + 'Gounarou', + 'DeForest', + 'Suyo', + 'Morro Bay', + 'Valentigney', + 'Mutukuru', + 'Langhirano', + 'Kirchseeon', + 'Qal`eh Chan`an', + 'Basht', + 'Gleisdorf', + 'Agouna', + 'Khrystynivka', + 'Vire', + 'Sarsai Nawar', + 'Kuhbanan', + 'Epinay-sur-Orge', + 'Kajhi Hridenagar', + 'Jhundo', + 'Niquen', + 'Antanandehibe', + 'Jarjanaz', + 'Kuruvambalam', + 'Rudra Nagar', + 'Del Aire', + 'Lulhaul', + 'Sambre', + 'Odugattur', + 'Pragadavaram', + 'Kilrajakularaman', + 'Alakamisy Anativato', + 'Ilicakoy', + 'East Bakersfield', + 'St. Albans', + 'Bendougouba', + 'Iramaia', + 'Barnoldswick', + 'Tiszafured', + 'Moda', + 'Sunadkuppi', + 'Lyngdal', + 'Suhagi', + 'Kattari', + 'Ogano', + 'Doi Saket', + 'Imi Mokorn', + 'Kuttattuppatti', + 'Jaladurgam', + 'Kelilalina', + 'Wang Sombun', + 'Kleinblittersdorf', + 'Kingri', + 'Babhnoul', + 'Komarolu', + 'Lieshout', + 'Deville-les-Rouen', + 'Lehigh', + 'Itacurubi de la Cordillera', + 'Capela do Alto Alegre', + 'Goasi', + 'Placerville', + 'Mogwase', + 'Na Sceiri', + 'Racale', + 'Jurua', + 'Fondettes', + 'Sarospatak', + 'Karuvelampatti', + 'Padiyur', + 'Munhall', + 'Selsey', + 'Brdovec', + 'Chanteloup-les-Vignes', + 'Kumaravadi', + 'Isola del Liri', + 'West Hanover', + 'Pia', + 'Chandreru', + 'Nandasmo', + 'Bhalpatti', + 'Raybag', + 'Vellavadanparappu', + 'Vidalia', + 'Martinengo', + 'Motta di Livenza', + 'Middle Island', + 'Linthicum', + 'Tuktukan', + 'Choachi', + 'Chapeltique', + 'Le Pradet', + 'Kerai', + 'Le Taillan-Medoc', + 'La Palma del Condado', + 'Deh Bakri', + 'Uropa', + 'Gaohucun', + 'Bad Orb', + 'Panamarattuppatti', + 'Maniamkulam', + 'Monte San Pietro', + 'Westwood Lakes', + 'Douar Bouchfaa', + 'Forestville', + 'Andovoranto', + 'Ankarabato', + 'Taimali', + 'Rogatica', + 'Bazid Chak Kasturi', + 'Zwettl', + 'Rajanagaram', + 'Grezzana', + 'Ripoll', + 'Voisins-le-Bretonneux', + 'Sapahi', + 'Edwards', + 'Sacueni', + 'Asalem', + 'Fujino', + 'Alagappapuram', + 'Otsuchi', + 'Ubala', + 'Gulbaar', + 'Sharg`un', + 'Campolongo Maggiore', + 'Novomyrhorod', + 'Ymittos', + 'Ormesby', + 'Diss', + 'Imani', + 'Richmond Heights', + 'Qaminis', + 'Villers-la-Ville', + 'Xiaozui', + 'Parnera', + 'Tigrana', + 'Nandiala', + 'Thevur', + 'Sivrice', + 'Louvain-la-Neuve', + 'Candiota', + 'Ichnia', + 'Frenstat pod Radhostem', + 'Enumulapalle', + 'Leognan', + 'Sutculer', + 'Raeren', + 'Tamarana', + 'Rewtith', + 'Tanant', + 'Chittarkottal', + 'Sidhap Kalan', + 'Waggaman', + 'Arbaa Sahel', + 'Sesori', + 'Diedorf', + 'Goynucek', + 'Botticino Sera', + 'Santa Catarina Ayotzingo', + 'Sonoma', + 'Morbach', + 'Jyllinge', + 'Bou Khadra', + 'Loano', + 'Shurobod', + 'Aduku', + 'Lwakhakha', + "Bog'ot", + 'Aliabad', + 'Mara Rosa', + 'Ross on Wye', + 'Marcali', + 'Galsi', + 'Tafalla', + 'Sangam', + 'Qal`eh Tall', + 'Malibu', + 'Pine Hill', + 'Ambohinihaonana', + 'Borgloon', + 'Desborough', + 'Tolna', + 'San Felice sul Panaro', + 'Potomac Park', + 'Rancho Mission Viejo', + 'Sam Ko', + 'Tarboro', + 'Sebin Karahisar', + 'Bestwig', + 'Milattur', + "Ville-d'Avray", + 'Kurdi', + 'Hatch End', + 'Sangalbahita', + 'Trevignano', + 'Doraville', + 'Baghuz Fawqani', + 'Bogalusa', + 'Sidi Namane', + 'Lachhmipur', + 'Sahuli', + 'Dallgow-Doberitz', + 'Santa Ana Huista', + 'Medesano', + 'Lyons', + 'Bischofswerda', + 'Querencia do Norte', + 'Darfield', + 'Gairtganj', + 'Corning', + 'Iretama', + 'Orthez', + 'Jhundpura', + 'Taouloukoult', + 'Peralillo', + 'Gambettola', + 'Matsuda-soryo', + 'Baetov', + 'Darby', + 'Agdz', + 'Tisma', + 'Talsur', + 'Kattipudi', + 'Yampil', + 'Valadares', + 'Trets', + 'Knowle', + 'Cerreto Guidi', + 'Powdersville', + 'Fo-Boure', + 'Uzda', + 'Sebt Ait Ikkou', + 'Mathigeri', + 'Gracanice', + 'Bela Crkva', + 'Cazzago San Martino', + 'Iwai', + 'Fountain Inn', + 'Huetor-Tajar', + 'Bhaur', + 'Dakhram', + 'Maynard', + 'Lohariandava', + 'Ardrossan', + 'Konganapuram', + 'Hemavati', + 'Darb-e Behesht', + 'Clute', + 'Cricova', + 'Itarhi', + 'Singapperumalkovil', + 'Katra', + 'Besagarahalli', + 'Hosahalli', + 'Anoviara', + 'Jesenik', + 'Kivisto', + 'Kankol', + 'Salotgi', + 'Dakhan', + 'Cameri', + 'Capim Branco', + 'Broomall', + 'Sao Bras de Alportel', + 'Betsiaka', + 'La Homa', + 'Monte Alegre do Piaui', + 'Aylesford', + 'Chuqung', + 'Joutseno', + 'Chettimangurichchi', + 'Al Atarib', + 'Gurun', + 'Yeghvard', + 'Plan-les-Ouates', + 'Aulla', + 'Puranattukara', + 'Kala Diara', + 'Malapannanagudi', + 'Leninskoe', + 'Myers Corner', + 'Nakonde', + 'Kursenai', + 'Lamhadi', + 'Bharra', + 'Teus', + 'Daganzo de Arriba', + 'Mysliborz', + 'Ponte Serrada', + 'West Haverstraw', + 'Antsaravibe', + 'Nowa Deba', + 'Novotroitske', + 'Corocoro', + 'Ramareddi', + 'Cookstown', + 'Essex Junction', + 'Hrebinka', + 'Santa Terezinha de Goias', + 'Kadwa', + "Sant'Antioco", + 'Filipstad', + 'Tinchlik', + 'Coite do Noia', + 'Gudibanda', + 'Veseli nad Moravou', + 'Gobardhanpur Kanap', + 'Karadichittur', + 'Galena Park', + 'Atlit', + 'Amayan', + 'Friendly', + 'Almoloya', + 'Lacarak', + 'Ruppichteroth', + 'Sedavi', + 'Bellefontaine Neighbors', + 'Pernes-les-Fontaines', + 'Kumbhari', + 'Sirugudi', + 'Maghra', + 'Felsberg', + 'Ngaputaw', + 'Asfour', + 'Hajeb el Aioun', + 'Lambton Shores', + 'Delareyville', + 'Nueva Helvecia', + 'Barmstedt', + 'Sannicolau Mare', + 'Svedala', + 'Lubawa', + 'Emsburen', + 'Jacinto Machado', + 'Jiwachhpur', + 'Kendall Park', + 'Little Canada', + 'Chinnamandem', + 'Adohoun', + 'Blackhawk', + 'Dinagat', + 'Mount Airy', + 'Kralendijk', + 'Schleusingen', + 'Paimio', + 'Groot-Brakrivier', + 'Villa Jaragua', + 'Opatija', + 'Hanson', + 'North Dumfries', + 'Hetane', + 'Altamirano', + 'Diessen am Ammersee', + 'Longbenton', + 'Nakayama', + 'Kilibo', + 'Oloron-Sainte-Marie', + 'Usuppur', + 'Partap Tanr', + 'Kanur', + 'Mittahalli', + 'Urcos', + 'Bouhmama', + 'Avigliano', + 'Itzer', + 'Lyakhavichy', + 'Cadelbosco di Sopra', + 'Calcoene', + 'Standerton', + 'Jilava', + 'Ouedo-Agueko', + 'Antardipa', + 'Canapolis', + 'Ghattu', + 'Hollviken', + 'Felton', + 'Englefield Green', + 'Sabnima', + 'Munnuru', + 'Toundout', + 'San Ignacio Cohuirimpo', + 'Lunca Cetatuii', + 'Pires Ferreira', + 'Barharia', + 'Nanticoke', + 'Mantasoa', + 'Kucukkuyu', + 'Aranda', + 'Massa Lombarda', + 'Bajpe', + 'Abadou', + 'Tubara', + 'Ain Zora', + 'Khovaling', + 'Kucuk Dalyan', + 'Urucania', + 'Pont-Saint-Esprit', + 'Kingsteignton', + 'Killiney', + 'Khokri Kalan', + 'Tangerhutte', + 'Sokhodewara', + 'Douglass', + 'Acari', + 'West Perrine', + 'Ironton', + 'Inebolu', + 'Al Mahwit', + 'La Maddalena', + 'Golpazari', + 'Lake Barcroft', + 'Miro Khan', + 'Karpuzlu', + 'Lymanka', + 'Monte Dourado', + 'Ghoswari', + 'Dasai', + 'Kabira', + 'Kurhani', + 'Sumner', + 'Ninheira', + 'Ait Hani', + 'Hoogland', + 'Ranko', + 'Busayra', + 'Murtosa', + 'Tamanar', + 'Iaciara', + 'Linluo', + 'Bohl-Iggelheim', + 'Vellipalaiyam', + 'Maida Babhangawan', + 'Sonakhal', + 'San Gaspar Ixchil', + 'Had Laaounate', + 'Jablanica', + 'Sao Joao de Ver', + 'Chorrocho', + 'Jaguari', + 'Yacuanquer', + 'Tenango del Aire', + 'Grijo', + 'Kimpese', + 'Trofarello', + 'Tourza', + 'Pasil', + 'Abergele', + 'Sirur Tajband', + 'Lejanias', + 'Acate', + 'Wendell', + 'Amtar', + 'Rocafuerte', + 'Bodippatti', + 'Pariconia', + "'Ain Fekan", + 'Zapotitlan', + 'Yazoo City', + 'Kielczow', + 'Kolarovo', + 'Lagoa do Mato', + 'Jurbarkas', + 'Schonwalde-Siedlung', + 'Sawadah', + 'Shampur', + 'Tekkattur', + 'Aerzen', + 'Alachua', + 'Airway Heights', + 'Mulungu', + 'Porto Firme', + 'Lenzburg', + 'Longuenesse', + 'Gajiginhalu', + 'Daskasan', + 'Catanduvas', + 'Scottdale', + 'Tarazona de Aragon', + 'Kasavanampatti', + 'Lakeland Village', + 'Vouzela', + 'Monsenhor Gil', + 'Puligunta', + 'Yorkshire', + 'Corumba de Goias', + 'Flamanzi', + 'Ban Ko', + 'Sao Tiago', + 'Bangshang', + 'Neuenhaus', + 'Briancon', + 'Flers-lez-Lille', + 'Trabia', + 'Ambolotarakely', + 'Ascope', + 'Koppaka', + 'Acushnet', + 'Bad Iburg', + 'Las Matas de Santa Cruz', + 'Kien Giang', + 'Millington', + 'Kanagicho', + 'Puente de Piedra', + 'Pachauth', + 'Pella', + 'Campton Hills', + 'Sawla', + 'Chitaga', + 'Pelissanne', + 'Loharda', + 'Darauli', + 'Kuiyibagecun', + 'Fenglin', + 'Tinqueux', + 'Nave', + 'Don Galo', + 'Weinbohla', + 'Le Mars', + 'Martensville', + '`Utaybah', + 'Sihma', + 'Monument', + 'Mancora', + 'Paddhari', + 'Usmate Velate', + 'Niel', + 'Sao Jose do Calcado', + 'Budelsdorf', + 'Mathila', + 'Excelsior Springs', + 'Mokrisset', + 'Sabaneta de Yasica', + 'Tarabha', + 'Tilougguit', + 'Phaphot', + 'Kulrian', + 'Bir Ben Laabed', + 'Urrugne', + 'Chervyen', + 'Wendeburg', + 'Sambalhera', + 'Bischofshofen', + 'Ormesson-sur-Marne', + 'Werlte', + 'Lasht-e Nesha', + 'Marotaolana', + 'Grevesmuhlen', + 'Torpa', + 'Madathapatti', + 'Montalegre', + 'Saint-Gely-du-Fesc', + 'Aravelli', + 'Chota Mollakhali', + 'Jhonkar', + 'Antenetibe', + 'Apt', + 'Pallattur', + 'San Juanito', + 'Torotoro', + 'Maevka', + 'Nagambhotlapalem', + 'The Pinery', + 'Mfou', + 'Kakhandiki', + 'River Grove', + 'Mouans-Sartoux', + 'Tamarankottai', + 'North Bellport', + 'Rabta', + 'Sidi Bousber', + 'Garag', + 'Pazaryeri', + 'Reiskirchen', + 'Cotacachi', + 'Alcora', + 'Tarnok', + 'Skillounta', + 'Alderwood Manor', + 'Dhilwan', + 'Tulshia', + 'Karukkalvadi', + 'Saks', + 'Wanderlandia', + 'La Virgen', + 'Benedito Novo', + 'Recreio', + 'Flawil', + 'Felida', + 'Rasebetsane', + 'Parczew', + 'Sahuria', + 'Nahargarh', + 'Buttar Khurd', + 'Montale', + 'Xambioa', + 'Paittur', + 'Simpelveld', + 'Golyaka', + 'Floha', + 'Sainte-Savine', + 'Pierre-Benite', + 'Heris', + 'Naganuma', + 'Loudoun Valley Estates', + 'Forest Acres', + 'Shumanay', + 'Perur', + 'Vargem', + 'Boudouaou el Bahri', + 'Stansbury Park', + 'Plankstadt', + 'Hilter', + 'Neuhausen am Rheinfall', + 'Obuse', + 'Winterville', + 'Burgau', + 'Bagrinagar', + 'Nallippalaiyam', + 'Surinam', + 'Santiago Chimaltenango', + 'Murata', + 'Morsand', + 'Soquel', + 'Imst', + 'Andonabe Atsimo', + 'Heule', + 'Ertvelde', + 'Cristino Castro', + 'Tierra Colorada', + 'Celic', + 'Agramonte', + 'Riesi', + 'San Ricardo', + 'Ban Thung Khao Phuang', + 'Usmat Shaharchasi', + 'Nuriston', + 'Bibala', + 'Court-Saint-Etienne', + 'Pocao', + 'Angostura', + 'Vembur', + 'Balwa', + 'Samakhiali', + 'Yedappalli', + 'Kamifurano', + 'Presidente Vargas', + 'Markt Indersdorf', + 'Candelaria Loxicha', + 'Susuz', + 'Rio do Pires', + 'Sadon', + 'Lighthouse Point', + 'Buriti Alegre', + 'Bad Wildbad', + 'Kibichuo', + 'Marck', + 'Bhopalia', + 'Naini', + 'Adalpur', + 'Devanakonda', + 'Nowe Miasto Lubawskie', + 'Krishnamsettipalle', + 'Heath', + 'Santa Maria de Itabira', + 'Grinon', + 'Gudlavalleru', + 'Hoki', + 'Soledar', + 'Likiskiai', + 'Regidor', + 'Whitnash', + 'Souq Sebt Says', + 'Chencha', + 'Duraiswamipuram', + 'Ingeniero White', + 'Rajpur Kalan', + 'Gommern', + 'Bonham', + 'Ryhope', + 'Ouolodo', + 'Coacoatzintla', + 'Leidschendam', + 'Attleborough', + 'Somers Point', + 'Sidi Abdallah', + 'Alfredo Wagner', + 'Buraan', + 'Ban Lueak', + 'Lake Hopatcong', + 'Bellmead', + 'Folomana', + 'Las Veredas', + 'Saude', + 'La Escala', + 'Hericourt', + 'Ambhua', + 'Bolekhiv', + 'Cacimbinhas', + 'Arkalochori', + 'Burgstadt', + 'Tiruvalam', + 'Machulishchy', + 'Rokunohe', + 'Espanola', + 'Hulshout', + 'Taormina', + 'Palatka', + 'Nova Dubnica', + 'Corzuela', + 'Luanco', + 'Balua Rampur', + 'Tokigawa', + 'Ambahy', + 'Caslav', + 'Kremiss', + 'Bordj Okhriss', + 'Al Musayfirah', + 'Hartswater', + 'Belao', + 'Dighawani', + 'Santiago Tangamandapio', + 'Novodnistrovsk', + 'Itaipe', + 'Wepangandla', + 'Vaddepalli', + 'Dhanwar', + 'Gemona del Friuli', + 'Macajuba', + 'Vermilion', + 'Olbernhau', + 'Friedeburg', + 'Holbeach', + 'Waimea', + 'East Bradford', + 'Karahalli', + 'Vikrutamala', + 'Burhia Dhanghatta', + 'Lake Morton-Berrydale', + 'Teotlaltzingo', + 'Santa Margarita de Mombuy', + 'Gokce', + 'Lollar', + 'Villers-Cotterets', + 'Kopparam', + 'Pedras de Maria da Cruz', + 'Khurmi', + 'Phai Sali', + 'Valpoy', + 'Minanba', + 'Flat Rock', + 'Braine-le-Chateau', + 'Da', + 'Vieux-Conde', + 'Bakwa', + 'Lonkly', + 'Fervedouro', + 'El Chol', + 'Birzai', + 'Catunda', + 'Burton Latimer', + 'Saidapet', + 'Plaine Magnien', + 'Timra', + 'Muquem de Sao Francisco', + 'Wildberg', + 'Valley', + 'Santa Teresinha', + 'Sao Sebastiao da Grama', + 'Litomysl', + 'Ulft', + 'Thilogne', + 'Mochizuki', + 'Minobu', + 'Wapienica', + 'Ivankiv', + 'Nova Europa', + 'Koth', + 'Silverton', + 'Sidi Boushab', + 'Yelm', + 'Manakana', + 'Kamthi', + 'Balia', + 'Dnestrovsc', + 'Yesilkoy', + 'Karkamis', + 'Zawyat Ahancal', + 'Antsahadinta', + 'Choyr', + 'Difficult Run', + 'Le Locle', + 'Eccleston', + 'Melito di Porto Salvo', + 'Plattekill', + 'Venganellur', + 'Ibiassuce', + 'Kiso', + 'Lovejoy', + 'Kraluv Dvur', + 'Tarare', + 'Awfouss', + 'Estaimpuis', + 'Takon', + 'Suhr', + 'Labin', + 'Warr Acres', + 'Sotkamo', + 'Portes-les-Valence', + 'South Lebanon', + 'Darling', + 'Rifle', + 'Firminopolis', + 'Nideggen', + 'Valatt', + 'Nagtala', + 'Roca Sales', + 'Coriano', + 'Libanggaon', + 'Nahulingo', + 'Jurbise', + 'Wabash', + 'Simbach am Inn', + 'Smithville', + 'Rawdon', + 'Bogue', + 'Ciechocinek', + 'Altenberge', + 'Chandera', + 'Kragero', + 'Trat', + 'Dona Ines', + 'Shenjiaba', + 'Phangnga', + 'Kalanak', + 'Oulad Slim', + 'Targu Ocna', + 'Prestonpans', + 'Scartho', + 'Machalpur', + 'Cunha Alta', + 'Corral de Bustos', + 'Telsang', + 'Baghin', + 'Urai', + 'Oued Amlil', + 'Villeneuve-les-Maguelone', + 'Thorigny-sur-Marne', + 'Bradford-on-Avon', + 'Prakhon Chai', + 'Kotharpettai', + 'Kiho', + 'Opglabbeek', + 'Podstrana', + 'Marlton', + 'Koffiefontein', + 'Nordkirchen', + 'Koduru', + 'Ban Ueam', + 'Plombieres', + 'Braunsbedra', + 'Cislago', + 'Fayzobod', + 'Masindi Port', + 'Terra Alta', + 'Banta', + 'Cadillac', + 'Brikcha', + 'Croissy-sur-Seine', + 'Mount Vista', + 'Hithadhoo', + 'Hachirud', + 'Montecchio Emilia', + 'Fairmount', + 'Santiago Suchilquitongo', + 'Kamianka-Buzka', + 'Sainkhera', + "Fanja'", + 'Great Dunmow', + 'Charlton Kings', + 'Sleepy Hollow', + 'Cuatro Cienegas de Carranza', + 'Lemmer', + 'Demmin', + 'Velappadi', + 'Eriyodu', + 'Gateway', + 'Turmanin', + 'Kangaroo Flat', + 'Uchoa', + 'Narkatpalli', + 'Farmersville', + 'Suchanino', + 'Puerto Quijarro', + 'Tripurantakam', + 'Leones', + 'Santa Clara La Laguna', + 'Nossen', + 'Jigani', + 'Coronel Freitas', + 'Kaufering', + 'Gelves', + 'Matsavaram', + 'Dougba', + 'Ickenham', + 'Alacati', + 'Gokinepalle', + 'Molango', + 'Constantina', + 'Morinville', + 'Senhora dos Remedios', + 'Caem', + 'Paramoti', + 'Telkapalli', + 'Nakasato', + 'Spout Springs', + 'Gayaspur', + 'Kennett', + 'Cholchol', + 'Faradabad', + 'Jalihalli', + 'Truseni', + 'Zdzieszowice', + 'Capitolio', + 'Akim Swedru', + 'Paraippatti', + 'Comstock Park', + 'Spa', + 'Belem de Maria', + 'Altusried', + 'Galion', + 'Fasintsara', + 'Steinfeld', + 'Desuri', + 'Nukan', + 'Ban Non Sombun', + 'Nidamanuru', + 'Merces', + 'Nalgora', + 'Ordubad', + 'Neuenstadt am Kocher', + 'Madhopur Hazari', + 'Winchendon', + 'Douar Echbanat', + 'Conceicao da Aparecida', + 'Steinau an der Strasse', + 'Sidi Brahim', + 'Phek', + 'Millstone', + 'Czarnkow', + 'Mankur', + 'Sarapui', + 'Villeneuve-Tolosane', + 'Gharyala', + 'Sarnen', + 'Haikoucun', + 'Atripalda', + 'Klipphausen', + 'Kottapuram', + 'Cori', + 'Calimesa', + 'Tnine Sidi Lyamani', + 'Libante', + 'Augustdorf', + 'Kalgi', + 'Bommarbettu', + 'Momanpet', + 'Corleone', + 'Ambalanur', + 'Peravali', + 'Itabirinha de Mantena', + 'Nieder-Olm', + 'Fakirtaki', + 'Shasta Lake', + 'Tavriisk', + 'Bassian', + 'Anrochte', + 'Phon Charoen', + 'Itri', + 'Dan', + 'Jaguaribara', + 'Phulmalik', + 'Bonate di Sopra', + 'Blandford Forum', + 'Khawaspur', + 'Kemin', + 'Arkadelphia', + 'Kelandis', + 'Scotchtown', + 'Aesch', + 'Siktiahi', + 'Krasnoilsk', + 'Rio do Fogo', + 'Kiklah', + 'Nijoni', + 'Sartana', + 'Gourock', + 'Hirehadagalli', + 'Rounia', + 'Harlau', + 'Ravanusa', + 'El Refugio', + 'Mallan', + 'Coroneo', + 'Vellaturu', + 'Woodlyn', + 'Delportshoop', + 'Maruteru', + 'Kiridh', + 'Srikrishnapur', + 'Villacarrillo', + 'Shahrak-e Enqelab', + 'Maria Pinto', + 'Brikama Ba', + 'Silea', + 'Canatlan', + 'Jeumont', + 'Mokarrampur', + 'Konkavaripalle', + 'Itape', + 'Cheruvannur', + 'Brewster', + 'Hoek van Holland', + 'Ganga Sagar', + 'Forde', + 'Natonin', + 'Steinen', + 'Chestnut Ridge', + 'Aulendorf', + 'Cabestany', + 'Sonwan', + 'Atessa', + 'Sao Luis do Paraitinga', + 'Tirkha', + 'White Marsh', + 'Garrucha', + 'Caspe', + 'Letychiv', + 'Bowral', + 'Trumbull Center', + 'Sao Miguel das Matas', + 'Wittelsheim', + 'Levanger', + 'Dabuleni', + 'Thanh Phu', + 'Firou', + 'Aydarken', + 'Benalla', + 'Ahogbeya', + 'Ben Nasseur', + 'Teddington', + 'Oppatavadi', + 'Ban Dan Na Kham', + 'Melres', + 'Gagnef', + 'Santo Antonio do Jacinto', + 'Qari Kola-ye Arateh', + 'El Jicaral', + 'Alvorada do Sul', + 'Erlenbach am Main', + 'Oneida', + 'Sirakoro', + 'Ananas', + 'Pintadas', + 'Inhangapi', + 'La Riche', + 'Babhniyawan', + 'Watervliet', + 'Beni Oulid', + 'Meerhout', + 'Weilheim an der Teck', + 'Vila Franca do Campo', + 'Itaueira', + 'Wallaceburg', + 'Arvorezinha', + 'El Alamo', + 'Villebon-sur-Yvette', + 'Riano', + 'Arimalam', + 'Appenweier', + 'Stranraer', + 'Ranchos', + 'Hochst im Odenwald', + 'Harsola', + 'Dombachcheri', + 'Hariana', + 'Kamepalle', + 'Caracol', + 'Berwick', + 'Teocuitatlan de Corona', + 'Karuzi', + 'Penarroya-Pueblonuevo', + 'Yadavolu', + 'Azamnagar', + 'Chong-Aryk', + 'Geneseo', + 'Etropole', + 'Burtonsville', + 'Sao Romao', + 'Mildenhall', + 'West Vero Corridor', + 'Blackfalds', + 'Virginopolis', + 'Umbita', + "Aghbalou n'Kerdous", + 'Agua Blanca Iturbide', + 'Amurrio', + 'Bacliff', + 'Wood River', + 'General Salgado', + 'Pola de Lena', + 'Brookdale', + 'Solim', + 'Bounaamane', + 'Haspra', + 'Qiushanxiang', + 'Auhar Sheikh', + 'Motibennur', + 'Riolandia', + 'Rodelas', + 'Kursunlu', + 'Buriti do Tocantins', + 'Khiram', + 'South Huntington', + 'Waynesville', + 'Jaqma', + 'Grossburgwedel', + 'Moldava nad Bodvou', + 'Mwaya', + 'Maurilandia', + 'Jordania', + 'Qanliko`l', + 'Pyetrykaw', + 'Broadstone', + 'Lakkireddipalle', + 'Trajano de Morais', + 'Merzenich', + 'Limoux', + 'Knezha', + 'Baran', + 'Caparrapi', + 'Bel Imour', + 'Sabana Grande', + 'Raymondville', + 'Orkelljunga', + 'Kangning', + 'Birsfelden', + 'Rancho Arriba', + 'Kalamula', + 'Boldesti-Scaeni', + 'Alto Paraiso de Goias', + 'Rubim', + 'Nana', + 'Shahar Telpa', + 'Bad Lauterberg', + 'Locate di Triulzi', + 'Murrells Inlet', + 'Armanaz', + 'Bonfinopolis', + 'Bordj Zemoura', + "Lyuboml'", + 'Kirchlinteln', + 'Castelli Calepio', + 'Ouroeste', + 'Ratauli', + "Castelnovo ne' Monti", + 'Morsbach', + 'Balaungi', + 'Zawal', + 'Fort Madison', + 'Dalgan', + 'Vilkaviskis', + 'Jordbro', + 'Serido', + 'Lenoir City', + 'Ma`raba', + 'Ekinozu', + 'Billdal', + 'Lutry', + 'Miedzychod', + 'Srisailain', + 'Simarwara Durgapur', + 'Arraias', + 'Lishuping', + 'Terra de Areia', + "'Ain Tellout", + 'Spitalfields', + 'Rayen', + 'Hecelchakan', + 'Irineopolis', + 'Cheam', + 'Arlov', + 'Schalksmuhle', + 'Jankampet', + 'Tangermunde', + 'Kandrawan', + 'Bandrele', + 'Sidi Bou Ali', + 'San Jose de Feliciano', + 'Sao Geraldo', + "Sant'Agata de' Goti", + 'Sidi Embarek', + 'Ganvie', + 'Venecia', + 'Shirako', + 'Itapitanga', + 'Bagh-e Bahadoran', + 'Oppeano', + 'Ban Wisit', + 'Bogen', + 'San Maurizio Canavese', + 'Selkirk', + 'Saint-Felicien', + 'La Trinite', + 'Dora', + 'Potiragua', + 'Salvatierra de Mino', + 'Mehdauli', + 'Meghaul', + 'Marina del Rey', + 'Tello', + 'Tremonton', + 'Gafour', + 'Tekkekara', + 'Kilminnal', + 'Gaunivaripalle', + 'Tabubil', + 'Ullur', + 'Carroll', + 'Estreito de Camara de Lobos', + 'Bhikkiwind Uttar', + 'Mel Seval', + 'Pine Ridge', + 'Lenguazaque', + 'Somireddipalle', + 'Dar Si Aissa', + 'Reddipalle', + 'Tipp City', + 'Jaltocan', + 'Saudade', + 'Alcaudete', + 'Rockport', + 'Chivhu', + 'Goldenstedt', + 'Indalvai', + 'Tenente Ananias Gomes', + 'Axixa do Tocantins', + 'Nazaria', + 'Lahstedt', + 'North Lakes', + 'Oliveira de Frades', + 'Rio Acima', + 'Ericeira', + 'Tettuppatti', + 'Hopetown', + 'Westonaria', + 'Kut Chap', + 'Fronteiras', + 'Chavinda', + 'Gerzat', + 'Hameenkyro', + 'Gohuma Bairia', + 'Querfurt', + 'Blumberg', + 'Sint-Lievens-Houtem', + 'Maxaranguape', + 'Popovaca', + 'Kormend', + 'Shahmirpet', + 'Tarar', + 'Barai', + 'Siparia', + 'Enriquillo', + 'Elkhorn', + 'Bonito de Santa Fe', + 'Kirchzarten', + 'Bougaribaya', + 'Lonquimay', + 'Ostercappeln', + 'Fenggeling', + 'Goldbach', + 'North Bend', + 'Puerto Santander', + 'Sussen', + 'Alberobello', + 'Boaz', + 'East Whittier', + 'Murowana Goslina', + 'Jaqueira', + 'Nayanagar', + 'Rovinari', + 'Robstown', + 'Sgamna', + 'Badru Khan', + 'Induno Olona', + 'Galimuyod', + 'Santa Teresinha (2)', + 'Vairampatti', + 'San Marzano sul Sarno', + 'Catarina', + 'Palmacia', + 'Lugovoy', + 'Santa Isabel Ishuatan', + 'Angelim', + 'Vila Muriqui', + 'Maheshram', + 'San Diego Country Estates', + 'Jean-Mermoz', + 'Avranches', + 'Khair Khan', + 'Vellur', + 'Sucupira do Norte', + 'Spelle', + 'Brumath', + 'Ksar Lmajaz', + 'Pfastatt', + 'Kiramangalam', + 'Apparaopeta', + 'Konigsbach-Stein', + 'Borgampad', + 'New Hyde Park', + 'Marawi', + 'Puvalur', + 'East Setauket', + 'Olifantshoek', + 'Agudos do Sul', + 'Bernex', + 'Rotonda', + 'Glogow Malopolski', + 'Santa Maria Madalena', + 'Chantepie', + 'Partibanur', + 'Gislaved', + 'Igarape Grande', + 'Treillieres', + 'Raibhir', + 'Vigasio', + 'Concordia Sagittaria', + 'Akbez', + 'Samux', + 'Governador Archer', + 'Lemington', + 'Muttam', + 'Isola Vicentina', + 'Roberval', + 'Villanueva de Arosa', + 'Miribel', + 'Monte San Juan', + 'Potunuru', + 'Duque Bacelar', + 'Betzdorf', + 'Luathaha', + 'Ahiro', + 'Benyahia Abderrahmane', + 'Koila Dewa', + 'Sao Miguel de Touros', + 'Halfway', + 'Neo Karlovasi', + 'Tha Muang', + 'Dinard', + 'Alguazas', + 'La Chapelle-Saint-Mesmin', + 'Vadakku Ariyanayakipuram', + 'Kowary', + 'Dangriga', + 'Alhendin', + 'Nasaud', + 'Campo Redondo', + 'Csomor', + 'Multi', + 'Tanggemu Nongchang', + 'Nagasamudram', + 'Divisopolis', + 'Lystrup', + 'Igny', + 'Pingree Grove', + 'Moimenta da Beira', + 'Pantano Grande', + 'Duga Resa', + 'Kandulapuram', + 'Minamiaso', + 'Charala', + 'Zumaia', + 'Aubiere', + 'Snodland', + 'Ramacca', + 'Oignies', + 'Cordele', + 'Tlalixtac de Cabrera', + 'Varre-Sai', + 'Centralina', + 'Huittinen', + 'Douchy-les-Mines', + 'Rideau Lakes', + 'Bonthe', + 'Vejen', + 'Borzna', + 'Porto Esperidiao', + 'Flowood', + 'Ouangani', + 'Miani', + 'Fort Oglethorpe', + 'Pintuyan', + 'Shyroke', + 'Kastav', + 'Ramannapeta', + 'Oudewater', + 'Canta', + 'Tefenni', + 'Chavkandak', + 'Ellon', + 'Alpena', + 'Sechelt', + 'Tetela del Volcan', + 'Rehburg-Loccum', + 'Courrieres', + 'Inkerman', + 'Bosanska Krupa', + 'Florania', + 'Tarashcha', + 'Beilngries', + 'Douar Mzoura', + 'New Silksworth', + 'Kottapalem', + 'Baragaon', + 'Tokunoshima', + 'Carencro', + 'Niebull', + 'Eleskirt', + 'Arataca', + 'Claymont', + 'Phra Pradaeng', + 'Radyvyliv', + "Al Jazirah al Hamra'", + 'Pescaria Brava', + 'Narasingam', + 'Barahi', + 'Lake Arrowhead', + 'Jemaat Oulad Mhamed', + 'San Blas', + 'Sao Jose do Jacuipe', + 'Mirante', + 'Blain', + 'Gudofredo Viana', + 'Carmo do Rio Verde', + 'Venkatapuram', + 'Celano', + 'Randazzo', + 'Balangkayan', + 'Zaleze', + 'Rainbow City', + 'Astoria', + 'Biandanshan', + 'Poirino', + 'Pechea', + 'Chaungtha', + 'Nanfang', + 'Carice', + 'Jimbolia', + 'Munchberg', + 'Amgachia', + 'Birao', + 'Angwali', + 'Aliganj', + 'Kothi', + 'Darwa', + 'Akil', + 'Kaynasli', + 'Shirbadgi', + 'Halgur', + 'Kendallville', + 'Bacioi', + 'Olovo', + 'Gaillard', + 'Fort William', + 'Remada', + 'Surla', + 'Birkenfeld', + 'Jhakhra', + 'Panchi', + 'Jandiala', + 'Kulundu', + 'Kranuan', + 'Jesenice', + 'Ajjipuram', + 'Pipra Naurangia', + 'Bellamkonda', + 'Svidnik', + 'Ban Bong Tai', + 'Bela Vista de Minas', + 'Canteras', + 'Bomporto', + 'Evander', + 'Morlenbach', + 'Cedartown', + 'Korolevo', + 'Fanzhao', + 'Labhgaon', + 'Katalpur', + 'Ban Bang Toei', + 'Roddam', + 'Biskupiec', + 'Balikumbat', + 'Bleicherode', + 'Foz', + 'Mexicaltzingo', + 'Tut', + 'Zelfana', + 'Calasparra', + 'Jadupatti', + 'Port Townsend', + 'Neuville-en-Ferrain', + 'Bordighera', + 'Castleton', + 'Bois-des-Filion', + 'Rogerstone', + 'New Richmond', + 'Toca', + 'Sobral de Monte Agraco', + 'Pabegou', + 'Togamalai', + 'Corte Madera', + 'Vutukuru', + 'Msila', + 'Sidi Abdelaziz', + 'Akhaltsikhe', + 'Narot Mehra', + 'Shioya', + 'Higashikagura', + 'Ain Zohra', + 'Valaparla', + 'Kilkunda', + 'Hazle', + 'Teplodar', + 'Tiruchchuli', + 'Kanteru', + 'Telnal', + 'Arcola', + 'Molalla', + 'Choele Choel', + 'Werneck', + 'Lenggries', + 'Masanasa', + 'Caudete', + 'Aizenay', + 'Kaza', + 'Msoga', + 'Busca', + 'Gakuch', + 'Zhengdong', + 'Ouled Rabah', + 'Parempuyre', + 'Visbek', + 'Mungod', + 'Periyanegamam', + 'Vernal', + 'Bibbiano', + 'Alella', + 'Ban Pa Hung', + 'Great Missenden', + 'North Gates', + "Za'roura", + 'Divonne-les-Bains', + 'Neo Psychiko', + 'Villasagar', + 'San Felice Circeo', + 'Cabo Rojo', + 'Montignies-le-Tilleul', + 'Okondja', + 'Caudebec-les-Elbeuf', + 'Rignano Flaminio', + 'Hermantown', + 'Elattur', + 'Iizuna', + 'Liminka', + 'Corfe Mullen', + 'Filippoi', + 'Dhanur Kalyanwadi', + 'Snohomish', + 'Siswar', + 'Haldipur', + 'Urlati', + 'Aigle', + 'Rompicherla', + 'Solindabad', + 'Raparla', + 'Hire Megalageri', + 'Qovlar', + 'Potavaram', + 'Kirkel', + 'Serebryansk', + 'Scherpenzeel', + 'Genova', + 'Deulgaon Mahi', + 'Auterive', + 'Serra Caiada', + 'Bilga', + 'Kondalahalli', + 'Bhagirathpur', + 'Hillsdale', + 'Doorn', + 'Borim', + 'Mawai', + 'Garden Acres', + 'Monaragala', + 'Pocklington', + 'Beccles', + 'Manglur', + 'Sirigeri', + 'Ankily', + 'Eidsberg', + 'Cajapio', + 'Belagola', + 'Sulagiri', + 'Oggaz', + 'Meymand', + 'Kabatas', + 'Altotting', + 'Meuselwitz', + 'Rettanai', + 'Hipparga', + 'Begowal', + 'Nathpur', + 'Sedico', + 'Hull', + 'Fuveau', + 'Aroali', + 'Rasak', + 'Torre Santa Susanna', + 'Vaddadi', + 'Kalakeri', + 'Anandnagar', + 'Horti', + 'Ardal', + 'Corcuera', + 'Komorowice', + 'Struer', + 'Safford', + 'Masdi', + 'Kondakindi Agraharam', + 'Adigappadi', + 'Hackettstown', + 'Garliava', + 'Marondry', + "Uchtepa Qishlog'i", + 'Bandixon', + 'Baker City', + 'North Glengarry', + 'Turkan', + 'Gunbarrel', + 'Videle', + "M'Chouneche", + 'Tutzing', + 'Zerizer', + 'Buxerolles', + 'Daruvar', + 'Mashhad Rizeh', + 'Perumuchchi', + 'Parnagua', + 'Kittery', + 'Sycow', + 'Gambissara', + 'Cuapiaxtla de Madero', + 'Havanur', + 'Nizza Monferrato', + 'Nkokonjeru', + 'Jomasho`y', + 'Shohimardon', + 'Naftalan', + 'Forres', + 'Chauki Hasan Chauki Makhdum', + 'Glenwood Springs', + 'Rokkasho', + 'Sariz', + 'Robore', + 'Fouesnant', + 'Padiham', + 'Machchand', + 'Shahpur Chaumukhi', + 'Muurame', + 'La Mision', + 'Talugai', + 'Korosavada', + 'Progress Village', + 'South Huron', + 'Guemoukouraba', + 'Kumcati', + 'Sahidganj', + 'Marieville', + 'Kadaladi', + 'Procida', + 'Worsley', + 'Ekamba', + 'Nong Ki', + 'Quartz Hill', + 'Warfield', + 'Jangalapalle', + 'Advi Devalpalli', + 'Brandywine', + 'Mellieha', + 'Kapyl', + 'Erutukada', + 'Mihqan', + 'Hardas Bigha', + 'Karapa', + 'Onan', + 'Vaals', + 'Kafr Takharim', + 'Kele', + 'Padugaipattu', + 'Rosstal', + 'Gignac-la-Nerthe', + 'Spanish Fort', + 'Primeiro de Maio', + 'Fiuggi', + 'Cody', + 'Zuidlaren', + 'Bingham', + 'Kilsyth', + 'Thikriwala', + 'Chichihualco', + 'Sao Sebastiao do Maranhao', + 'Hongliuwan', + 'Tympaki', + 'Pinczow', + 'Umarizal', + 'Weil im Schonbuch', + 'Abergavenny', + 'Rath To', + 'Eumseong', + 'Penetanguishene', + 'Santa Catarina Masahuat', + 'Hozin', + 'Saladoblanco', + 'Kouinine', + 'Cabanaquinta', + 'Mondeville', + 'Malinagar', + 'Sapkyo', + 'Rio Vista', + 'Naters', + 'Saint-Max', + 'Kuroshio', + 'Sax', + 'Ghatawan', + 'Novi di Modena', + 'San Elizario', + 'Celtik', + 'Roelofarendsveen', + 'Bieber', + 'Binefar', + 'Cabries', + 'Yaotsu', + 'Atoka', + 'East Rockaway', + 'Villerupt', + 'Bee Ridge', + 'Neves', + 'San Vicente de Castellet', + 'Badia Polesine', + 'Waldwick', + 'Stropkov', + 'La Leonesa', + 'Goytapa', + 'Ouedo', + 'Porangaba', + 'Antanananivo', + 'Mondai', + 'Bagalur', + 'Vrnjacka Banja', + 'Kidira', + 'Avelgem', + 'Swieqi', + 'Valozhyn', + 'Willstatt', + 'Mazamet', + 'Lake Hiawatha', + "La'tamna", + 'Ban Bu Sung', + 'Mstsislaw', + 'Heubach', + 'Kwale', + 'Olaine', + 'Bobenheim-Roxheim', + 'Were Ilu', + 'Auchel', + 'Sung Noen', + 'Struthers', + 'Jafra', + 'Jocoro', + 'Radlett', + 'Browns Mills', + 'Orange Lake', + 'Dudhpura', + 'Shahpur Undi', + 'Bara Khurd', + 'Mocharim', + 'Alassio', + 'Scenic Oaks', + 'Burgum', + 'Parthenay', + 'Mold', + 'Rupana', + 'Abjij', + 'Macerata Campania', + 'Jiji', + 'Calan', + 'Kisujszallas', + 'Dhamua', + 'Taghbalt', + 'San Ignacio de Moxo', + 'Rudesheim am Rhein', + "'Ain Naga", + 'Dalawarpur', + 'Begijnendijk', + 'Satipo', + 'Verucchio', + 'Saha', + 'Rangasamudram', + 'Vange', + 'Lysa nad Labem', + 'La Baneza', + 'Blackwells Mills', + 'Namorona', + 'Levski', + 'Mery-sur-Oise', + 'Al Hamah', + 'Vysokyi', + 'Schotten', + 'Oakbrook', + 'Ilic', + 'Francisville', + 'Ciudad Tula', + 'Chapeltown', + 'Lydney', + 'Taiyur', + 'Gauli Palasiya', + 'Petmanhalli', + 'Pajaros', + 'Buyukorhan', + 'Tinkoni', + 'Lepakshi', + 'Sakuho', + 'Makaha', + 'Mikuszowice', + 'Mengibar', + 'Lipova', + 'Tiszafoldvar', + 'Glocester', + 'Zaniena', + 'Abaiara', + 'Nallikodur', + 'Sermoneta', + 'Cross Lanes', + 'Parilla', + "Bou'nane", + 'Vembaditalam', + 'Cheat Lake', + 'Maharajapuram', + 'Baldeogarh', + 'Volpago del Montello', + 'Tay', + 'Zaggota', + 'Olevsk', + 'Houthulst', + 'Suthalia', + 'Puduparambubhagam', + 'Basmakci', + 'Sirugamani', + 'Nikaido-kaminoshocho', + 'Massi', + 'Red Hook', + 'Castlegar', + 'Lauterach', + 'Munagapaka', + 'Goito', + 'Benemerito', + 'Novooleksiivka', + 'Tomboutou', + 'Panrepatti', + 'Lalmunia Munhara', + 'Kuchesfahan', + 'Bierbeek', + 'Steinhaus', + 'Kaldenkirchen', + 'Southwater', + 'Kirundo', + 'Kil Perambalur', + 'Harrisonville', + 'Canelli', + 'Toukoto', + 'Kingaroy', + 'Airmont', + 'East Rutherford', + 'Kuldiga', + 'Reedsburg', + 'An Nayrab', + 'Grosse Pointe Farms', + 'George Mason', + 'Trebbin', + 'Belpara', + 'Cavan Monaghan', + 'Huejuquilla el Alto', + 'Ramiriqui', + 'Montignoso', + 'Chesapeake Ranch Estates', + 'Pajacuaran', + 'San Pedro Huamelula', + 'Dhangaraha', + 'Manahari', + 'Pakka Kalan', + 'Silamalai', + 'Juripiranga', + 'Mayfield', + 'Roslyn', + 'Fort Meade', + 'Piedrahita', + 'Saint-Laurent-de-la-Salanque', + 'Dagiapara', + 'North Versailles', + 'Platon Sanchez', + 'Strasshof an der Nordbahn', + 'Vandamettu', + 'Dores de Campos', + 'Le Beausset', + 'Capodrise', + 'Moba', + 'Suaita', + 'Alajarvi', + 'Senanga', + 'Zaruma', + 'Saint-Loubes', + 'Villiersdorp', + 'Horbury', + 'Tiri', + 'Amwa Majhar', + 'Soahany', + 'Haider Khel', + 'Krynica', + 'Shengping', + 'Kolagallu', + 'Srifa', + 'Chartoun', + 'Qana', + 'Amioun', + 'Ras el Metn', + 'Ed Damour', + 'Butha-Buthe', + 'Ghadamis', + 'Belavabary', + 'Mahabako', + 'Boanamary', + 'Esira', + 'Sandravinany', + 'Bedidy', + 'Vohitrafeno', + 'Daraina', + 'Masiaboay', + 'Ambatomivary', + 'Ambodisikidy', + 'Ambohimiarivo', + 'Bekodoka', + 'Maroharatra', + 'Ambararatabe', + 'Ambatomifanongoa', + 'Ambohitrambo', + 'Ebelo', + 'Analalava', + 'Lohafary', + 'Antsoantany', + 'Ambovonomby', + 'Isahara', + 'Ambodivoara', + 'Vodiriana', + 'Ambohimahazo', + 'Ambodimadiro', + 'Andranambolava', + 'Marosakoa', + 'Soavimbahoaka', + 'Erada', + 'Mahabe', + 'Mahabo-Mananivo', + 'Miary-Taheza', + 'Ankadindambo', + 'Antaretra', + 'Betrandraka', + 'Amparihy', + 'Tanamarina', + 'Sahanivotry-Manandona', + 'Andranomenatsa', + 'Ambodimandresy', + 'Anontsibe-Sakalava', + 'Amparihitsokatra', + 'Ambatolava', + 'Ankerana', + 'Sihanamaro', + 'Vinanitelo', + 'Ifarantsa', + 'Ampasimazava', + 'Vohitany', + 'Vohitsaoka', + 'Andranopasy', + 'Beheloka', + 'Ankirondro', + 'Tamponala', + 'Katsepy', + 'Vondrozo', + 'Tanambao-Daoud', + 'Sahatona-Tamboharivo', + 'Beanana', + 'Soatanana', + 'Ampitahana', + 'Anosimparihy', + 'Vatana', + 'Ambalanjanakomby', + 'Zoma-Bealoka', + 'Jangany', + 'Ianapera', + 'Ambahatrazo', + 'Fanjakana', + 'Putao', + 'China', + 'Padang Besar', + 'Zavora', + 'Outjo', + 'Al Mazyunah', + 'Surmon Chogga Grong', + 'Basla', + 'Gadani', + 'Bunji', + 'Ghota Fatehgarh', + 'Setubal', + 'Diabougou', + 'Koumpentoum', + 'Gadoon', + 'Murgap', + 'Khunays', + 'Kadama', + 'Bukomansimbi', + 'Xishrov', + 'Oyim', + 'Tujg', + 'Boladi', + 'Fatikchari', + 'Puerto America', + 'Mboki', + 'Gar', + 'Ziketan', + 'Sola', + 'Matagua', + 'Morayra', + 'Karaga', + 'Rebola', + 'Pont Sonde', + 'Haria', + 'Waghai', + 'Ghargaon', + 'Deh', + 'Medarametla', + 'Hanzviur', + 'Amsin', + 'Muttalakanpatti', + 'Isnapuram', + 'Karumulaikkal', + 'Dhalai', + 'Nidamaluru', + 'Budwan', + 'Chhimluang', + 'Dhirwas', + 'Siddarampuram', + 'Reha Mota', + 'Paravakkottai', + 'Mevani', + 'Tharial', + 'Dewal Thal', + 'Lakshmipuram', + 'Gandhali', + 'Fatehgarh', + 'Kambhaladinne', + 'Kerwada', + 'Ulipuram', + 'Kochhor', + 'Betnoti', + 'Balagam', + 'Sotik', + 'Kargi', + 'Kourani', + 'Kolno', + 'Ramamangalam', + 'Wahlstedt', + 'Pierrelaye', + 'Bomareddipalli', + 'Czersk Pomorski', + 'Aniche', + 'Rakhwari', + 'Atri', + 'Melendugno', + 'Bad Frankenhausen', + 'Mengen', + 'Soyaux', + 'Downham Market', + 'Vilpatti', + 'Euxton', + 'Erraballa', + 'Paikpara', + 'Lambesc', + 'Yadwad', + 'Monteriggioni', + 'Marton', + 'Ketugram', + 'Tarhjicht', + 'Lillers', + 'Praia do Carvoeiro', + 'Stenungsund', + 'Rangamati', + 'Barkly East', + 'Pavlikeni', + 'Salemi', + 'Kinnelon', + "Ben N'Choud", + 'Fateha', + 'Kengarai', + 'Pullambadi', + 'Chada', + 'Dilra', + 'Asagi Ayibli', + 'Gudensberg', + 'Inungur', + 'Budd Lake', + 'Mahajjah', + 'Lapinlahti', + 'Galleh Dar', + 'Leninskiy', + 'Gulyam', + 'Crikvenica', + 'Itikalapalle', + 'Cape Canaveral', + 'Painal', + 'Penn Forest', + 'Sulecin', + 'Wood-Ridge', + 'Yueyaquan', + 'Dettingen an der Erms', + 'Cedar Hills', + 'El Cairo', + 'Shildon', + 'Kanyana', + 'Mahalleh-ye Shirinu', + 'Ainring', + 'Ringkobing', + 'Tansandra', + 'Bolsward', + 'Eybens', + 'Bishopstoke', + 'Erenler', + 'Valdobbiadene', + 'Quinto di Treviso', + 'Walker Mill', + 'San Nicolas Buenos Aires', + 'Tsuno', + 'Willoughby Hills', + 'Prelouc', + 'Ottendorf-Okrilla', + "Barano d'Ischia", + 'Boundji', + 'Bananal', + 'Mamobihat', + 'Colts Neck', + 'East Liverpool', + 'Casino', + 'Kottaipatti', + 'Tzucacab', + 'Gaolingcun', + 'Singera', + 'Tan Son', + 'Dujiashigou', + 'Vegachi', + 'Erraguntlakota', + 'Detroit Lakes', + 'Altenholz', + 'Cuesmes', + 'Aberaman', + 'Tokkavadi', + 'Hiranai', + 'Los Rios', + 'Kambaliyampatti', + 'Sufian', + 'Iwashita', + 'Anama', + 'Chakicherla', + 'San Calixto', + 'Birchington', + 'Judenburg', + 'Sagure', + 'Nairn', + 'Makale', + 'Sundekuppam', + 'Kapasiawan', + 'Padinjarebagam', + 'Khandsa', + 'Bastak', + 'Aibak', + 'Bertem', + 'Friedrichsthal', + 'Mahem', + 'Siechnice', + 'Sankt Andra', + 'Handsworth', + 'Conselve', + 'Ettimadai', + 'Khuran Milik', + 'Ratne', + 'Kawara', + 'Bastrop', + 'DuPont', + 'Halls', + 'Souama', + 'Saharbani', + 'Muskegon Heights', + 'Koloti', + 'Leppavirta', + 'Kapuvar', + 'Anahuac', + 'Fallston', + 'Aich', + 'Bad Konig', + 'Oelsnitz', + 'Sorkheh', + 'Picnic Point', + 'Hooglede', + 'Coal', + "Fil'akovo", + 'Verkhivtseve', + 'Qufadah', + 'Sellersburg', + 'Araua', + 'Torrejon de la Calzada', + 'Birni Lafia', + 'Ennamangalam', + 'Cuicatlan', + 'Heeze', + 'Aboso', + 'Chavusy', + 'Tamzoura', + 'Bhado Khara', + 'Ban Ngao', + 'Payerne', + 'Bad Bevensen', + 'Balatonalmadi', + 'Kamalasai', + 'Sniatyn', + 'Thi Tran Mau A', + 'Consuegra', + 'Aldenham', + 'Ocsa', + 'Erquelinnes', + 'Caraibas', + 'Nariar', + 'Fino Mornasco', + "P'yongch'ang", + 'Pachchampalaiyam', + 'Dubove', + 'Porto Xavier', + 'Ammanabrolu', + 'Padilla', + 'Kenafif', + 'Coycoyan de las Flores', + 'Bad Ems', + 'Ipupiara', + 'Dongou', + 'La Sierra', + 'Marpingen', + 'Burscough', + 'Kamdoli', + 'Nohfelden', + 'Kraaipan', + 'Waltenhofen', + 'Miandasht', + 'Hingyon', + 'La Pointe', + 'Akalapura', + 'Telpur', + 'Kinalur', + 'Fosses', + 'Khapdeh', + 'Bucine', + 'Birkenau', + 'Karimunjawa', + 'Kalimala', + 'Kadrabad', + 'Parwaha', + 'Farsund', + 'Grossos', + 'Talkhvoncheh', + 'Heves', + 'Vedurupavaluru', + 'Rockcreek', + 'Ban Pong Yaeng Nai', + 'Oldenburg in Holstein', + 'Kargahia Purab', + 'Nanzhou', + 'Maxeville', + 'Bajwara', + 'Capitola', + 'Welkenraedt', + 'Dongcha', + 'Angalakuduru Malepalle', + 'Rye Brook', + 'Temiskaming Shores', + 'Nove Mesto na Morave', + 'Minnampalli', + 'Jilotlan de los Dolores', + 'Novgorodskoye', + 'Setubinha', + 'Bekkaria', + 'Balderton', + 'Pavittiram', + 'Fair Oaks Ranch', + 'Saarijarvi', + 'Barni', + 'Ellisville', + 'Varzedo', + 'Pipraun', + 'Mussomeli', + 'Uniontown', + 'Strzelce Krajenskie', + 'Liskeard', + 'Pudimadaka', + 'Dar El Kebdani', + 'Mandello del Lario', + 'Pokrovske', + 'Manduri', + 'Epanomi', + 'Kunnur', + 'Karajgi', + 'Polistena', + 'Arroyohondo', + 'Sidi Rahhal', + 'Boufatis', + 'Kaunra', + 'Vaiano', + 'Phak Hai', + 'Holsbeek', + 'Glanmire', + 'Bharhopur', + 'Lomazzo', + 'Coweta', + 'Kaith', + 'Ogdensburg', + 'Maceira', + 'Zefyri', + 'Navinipatti', + 'Panjab', + 'Sursee', + 'Baldock', + 'Matadepera', + 'Carmaux', + 'Suhiya', + 'Kourimat', + 'Maisenhausen', + 'Pachalum', + 'Shankarampet', + 'Tonse East', + 'Nenagh', + 'Wangi', + 'Kummersbruck', + 'Bilehra', + 'Pliezhausen', + 'Wilsele', + 'Huldenberg', + 'Schlitz', + 'Dera Baba Nanak', + 'Ippagudem', + 'Asola', + 'Golden Hills', + 'Rodinghausen', + 'Brinkmann', + 'Frydlant nad Ostravici', + 'Diavata', + 'Siruvalur', + 'Urgnano', + 'Miadanandriana', + 'Messini', + 'Baghant', + 'Jettihalli', + 'Koflach', + 'Ivancice', + 'Suknah', + 'Coello', + 'Pizarra', + 'Gudgeri', + 'Soulei', + 'Namakadu', + 'Campi Salentina', + 'River Vale', + 'Qiziltepa', + 'Muthabana', + 'Bhadsara', + 'Saquisili', + 'St. Augustine Shores', + 'Mohlanapeng', + 'Kaimati', + 'Kadanganeri', + 'Gurwalia Biswas', + 'Hinton', + 'Petorca', + 'Saint-Sauveur', + 'Ankazotsifantatra', + 'Vardenik', + 'Biot', + 'Beckett Ridge', + 'Ga-Kgapane', + 'Kaiken', + 'Ploermel', + 'Meldola', + 'Wapakoneta', + 'Trancoso', + 'Ech Chaibat', + 'Chupaca', + 'Barahra', + 'Margarita', + 'Baltara', + 'Kosching', + 'Heilsbronn', + 'Krasnyy Yar', + 'Widhwidh', + 'Ban Pha Bong', + 'Vetraz-Monthoux', + "Foum Jam'a", + 'Ban Phan Chali', + 'Beneditinos', + 'Reddigudem', + 'Heerlerbaan', + 'Ruoqiang', + 'Santa Maria de Palautordera', + 'Kanjiza', + 'Saint-Pierre-du-Mont', + 'Qazigund', + 'Douar Snada', + 'Metsamor', + 'Alcorta', + 'Ouled Brahim', + 'Montigny-en-Gohelle', + 'Chegur', + 'Ommangi', + 'Stocksbridge', + 'San Miguel Siguila', + 'Sarkeghat', + 'Krzeszowice', + 'Keokuk', + 'Therwil', + 'Palepalli', + 'Iwamuro-onsen', + 'Greencastle', + 'Berd', + 'Swan Hill', + 'Muttattuteruvu', + 'Boudinar', + 'Ntorosso', + 'Roche-la-Moliere', + 'Poggio a Caiano', + 'Sauk Village', + 'Laakirchen', + 'Vettaikkaraniruppu', + 'Celldomolk', + 'Lingampet', + 'Mahisanrh', + 'Geylegphug', + 'Independent Hill', + 'Nueva Palmira', + 'Tanichchiyam', + 'Outa Bouabane', + 'Zinkiv', + 'Paradarami', + 'Humlebaek', + 'Abram', + 'Berikai', + 'Ciudad de Loreto', + 'Aranzazu', + 'Mittenwalde', + 'Dandoli', + 'Huichapan', + 'Ii', + 'Sovicille', + 'Nhandeara', + 'Narasimharajapura', + 'Sweet Home', + 'Fundeni', + 'Rodynske', + 'Pailon', + 'Renaico', + 'Norosi', + 'Fuente Palmera', + 'Feyzin', + 'DeRidder', + 'Juru', + 'Achchippatti', + 'Kadoli', + 'Santo Stefano di Magra', + 'Cuencame de Ceniceros', + 'Altofonte', + 'Plains', + 'Mariluz', + 'Anjahamana', + 'Lambertville', + 'Eerbeek', + 'Berezivka', + 'Barcs', + 'Surir', + 'Hochdorf', + 'Bisingen', + 'Tulin', + 'Boriguma', + 'Mosjoen', + 'Tha Mai', + 'Merchweiler', + 'Katarmala', + 'Cavriago', + 'Sturbridge', + 'Kobeliaky', + 'Chimay', + 'Hansa', + 'Dindanko', + 'Masquefa', + 'Kharial', + 'Kokiladanga', + 'Pedda Kotayalanka', + 'Itamukkala', + 'Kaimuh', + 'Shahzadpur', + 'Manubolu', + 'Partanna', + 'Qarabalyq', + 'Saint-Gregoire', + 'Patsanda', + 'Philipstown', + 'Makariv', + 'Chandankiari', + 'Ozieri', + 'Fort Salonga', + 'Carregal do Sal', + 'Touwu', + 'Karghar', + 'Vigonovo', + 'Succasunna', + 'Tekit', + 'Bardmoor', + 'Cildir', + 'Aramari', + 'Cachipay', + 'Tolmezzo', + 'Sieverne', + 'Parkes', + 'Etchojoa', + 'Iraiyur', + 'Pushpattur', + 'Terku Narippaiyur', + 'Birpur Barapatti Pindraun', + 'Mudgee', + 'Bockenem', + 'Kodivalasa', + 'Kamikita-kita', + 'Ribadeo', + 'Couzeix', + 'Basso', + 'Toudja', + 'Gangapur Athar', + 'Berilo', + 'Ilsfeld', + 'Padarti', + 'Nisarpur', + 'Loudonville', + 'Kusugal', + 'Guia Lopes da Laguna', + 'Alfaro', + 'Nodinge-Nol', + 'Jixian', + 'Pithaura', + 'Mogosoaia', + 'San Rafael Obrajuelo', + 'Nagulapadu', + 'Amjhar', + 'Castelletto sopra Ticino', + 'Jesup', + 'Nong Wua So', + 'Pillaro', + 'Indurti', + 'Morrovalle', + "Oulad 'Azzouz", + 'Gorha', + 'Little River', + 'El Espinar', + 'Plainville', + 'Caldicot', + 'Socota', + 'Haapsalu', + 'Kiato', + 'Apiuna', + 'Pasewalk', + 'Vettweiss', + 'Chuhal', + 'Kostrzyn', + 'Kouarfa', + 'Samabouro', + 'Altlandsberg', + 'Kongen', + 'Basapatna', + 'Pasupatikovil', + 'Jerissa', + 'Sasaima', + 'Nordwalde', + 'Kalas', + 'Vlist', + 'Banino', + 'Coamo', + 'Vidor', + 'Sande', + 'Portet-sur-Garonne', + 'Arden Hills', + 'Palkot', + 'San Vendemiano', + 'Grey Highlands', + 'Gangaur', + 'Sorab', + 'Ban Mae Sam Laep', + 'Kinhalu', + 'Kalyanpur', + 'Paravada', + 'Bergambacht', + 'Laubach', + 'Kil Valur', + 'Keshwari', + 'Alden', + 'Djangoa', + 'Olmos', + 'Drezdenko', + 'Honow', + 'Manushmuria', + 'Mae O', + 'Bauska', + 'Imlil', + 'Pisac', + 'Velpuru', + 'College Place', + 'Resadiye', + 'Bad Liebenzell', + 'Boscotrecase', + 'Pleasant Valley', + 'Sabana Larga', + 'Madera Acres', + 'Altmunster', + 'Silvarpatti', + 'Khathjari', + 'Hawera', + 'Lobez', + 'Dangcheng', + 'Visselhovede', + 'Alamosa', + 'Bukowno', + 'Veppattur', + 'Kominato', + 'Lincoln City', + 'Magstadt', + 'Seysses', + 'Avon Park', + 'Chevy Chase', + 'Marathon', + 'Tiztoutine', + 'Trescore Balneario', + 'Bagnolo in Piano', + 'Bay St. Louis', + 'Alcarraz', + 'Choppington', + 'Chak That', + 'Bag', + 'El Roble', + 'Kippax', + 'Bamora', + 'Ghariyah al Gharbiyah', + 'Valpovo', + 'Kami-kawabe', + 'Gokceada', + 'Tottington', + 'Kotli Ablu', + 'Jhitkahiya', + 'Kiban', + 'Albert', + 'Alagarai', + 'Koini', + 'Terrace Heights', + 'Helston', + 'Rute', + 'Neshannock', + 'Sturovo', + 'Chom Thong', + 'Bueng Khong Long', + 'Ronda Alta', + 'Dodworth', + 'Charne', + 'Gangania', + 'Nueva Tolten', + 'Bavanat', + 'Muddanuru', + 'Biei', + 'Repatriacion', + 'Nallamadu', + 'Ramnagar Bankat', + 'Derazhnia', + 'Oulunsalo', + 'Miastko', + 'Figeac', + 'Stonegate', + 'Farako', + 'Manalurpettai', + 'Cittanova', + 'Urdorf', + 'Pakri', + 'Valantaravai', + 'Tesalia', + 'Pepinster', + 'Sugbongkogon', + 'Perket', + 'Karankot', + 'Garrison', + 'Puerto Tirol', + 'Zell am See', + 'Wolfersheim', + 'Loudeac', + 'Montemarciano', + 'Mahinathpur', + 'Keansburg', + 'Pluderhausen', + 'Camoluk', + 'Barracao', + 'El Molar', + 'Agatogba', + 'Wald', + 'Voreppe', + 'Kanchanpur', + 'Jaisinghnagar', + 'Kattagaram', + 'Green Cove Springs', + 'Ganguru', + 'Salkhua', + 'Fultondale', + 'Ncora', + 'Gaszowice', + 'Pobiedziska', + 'Ingre', + 'Erravaram', + 'Aramangalam', + 'Kolnur', + 'Xiba', + 'Oberstdorf', + 'Shepperton', + 'Pembroke Dock', + 'Gorom-Gorom', + 'Dhamsain', + 'Mesetas', + "Sant'Egidio alla Vibrata", + 'Grigiskes', + 'Tadla', + 'Wloszczowa', + 'Sankt Johann in Tirol', + 'Chegurumomadi', + 'Monmouth Junction', + 'Byalynichy', + 'Satuluru', + 'Ambinanintromby', + 'Ghabrah', + 'Dubliany', + 'Alayor', + 'Tsaramasoandro', + 'Liesveld', + 'Radekhiv', + 'Felpham', + 'Beius', + 'Hacari', + 'Urlaha', + 'Puerto Narino', + 'Dulce Nombre de Jesus', + 'Undavalli', + 'Dhanwada', + 'Andrainjato', + 'Fandrandava', + 'Ban Mae Chedi', + 'Basavilbaso', + "Skidal'", + 'Sirdala', + 'Hunasamaranhalli', + 'Ciudad Cuauhtemoc', + 'Ribeirao do Largo', + 'Bad Breisig', + 'Cobham', + 'Sedona', + 'Ain Karma', + 'Redentora', + 'Twist', + 'Darnetal', + 'Raynes Park', + 'Lykovrysi', + 'Murungattoluvu', + 'Birzebbuga', + 'Furstenau', + 'Osthofen', + 'Ghusiya', + 'Motipur', + 'Eagle Point', + 'Everswinkel', + 'Semmarikulan', + 'Calca', + 'Quiculungo', + 'Giesen', + 'Bou Nouh', + 'Kaithinia', + 'Non Sung', + 'Bom Jesus da Serra', + 'Gambolo', + 'Moyogalpa', + 'Alto Piquiri', + 'Kitee', + 'San Giorgio del Sannio', + 'Grand-Couronne', + 'Kusumha', + 'Hadiaya', + 'East Brandywine', + 'East St. Paul', + 'Nova Floresta', + 'Atlapadu', + 'Draganesti-Olt', + 'Chiang Klang', + 'Seforong', + 'Thomaston', + 'Vesele', + 'Karattuppalaiyam', + 'Elambalur', + 'Zahed Shahr', + 'Terralba', + 'Oudenburg', + 'Idanha-a-Nova', + 'Ledegem', + 'Tayakou', + 'Bareh', + 'Kakkat', + 'Tivim', + 'Aghbalou Aqourar', + 'Mahuver', + 'Carnaubais', + 'La Ferte-sous-Jouarre', + 'Panganiban', + 'Bondues', + 'Tellar', + 'Ingleside', + 'Estavayer-le-Lac', + 'Litovel', + 'Qahjavarestan', + 'Wijnegem', + 'Pine Lake Park', + 'Haraiya', + 'Oberhausen-Rheinhausen', + 'Aqadyr', + 'Lanskroun', + 'Kottampatti', + 'Sundarapandiyam', + 'Poggio Renatico', + 'Zengjiaba', + 'Worpswede', + 'Lapanga', + 'Mentone', + 'Wakoro', + 'Vitorino', + 'Serris', + 'Douar Lehouifrat', + 'Tiruvengadam', + 'Harvard', + 'Kokologo', + 'Periyapuliyur', + 'Kannandahalli', + 'Vanipenta', + 'Goluchow', + 'Sovata', + 'Lovendegem', + 'Punnavalli', + 'Belsara', + 'Bararam', + 'Lake Mohawk', + 'Mount Evelyn', + 'Schwaikheim', + 'Pipra Dewas', + 'Atturkuppam', + 'Eksjo', + 'Poloros', + 'Purkersdorf', + 'Genemuiden', + 'Huari', + 'Chilanga', + 'Sirka', + 'Wadgira', + 'Tungavi', + 'Flowery Branch', + 'Mae Ai', + 'Imias', + 'Asuke', + 'Dassel', + 'Zafargarh', + 'Rombas', + 'Rolesville', + 'Aklim', + 'Pai Bigha', + 'Sant Julia de Loria', + 'Neu Bleckede', + 'Rhosllanerchrugog', + 'Kokoszki', + 'Dodoni', + 'Latteri', + 'Cypress Gardens', + 'White Horse', + 'Imam Sahib', + 'Talachyn', + 'Wittenbach', + 'Pakhtaobod', + 'Neves Paulista', + 'Gorgab', + 'Oostzaan', + 'Sigtuna', + 'Ban Bueng Kok', + 'Sidi Ahmed El Khadir', + 'Santamaguluru', + 'Mohdra', + 'Malhargarh', + 'Velakkuttai', + 'Raseiniai', + 'Guifoes', + 'Saint-Lys', + 'Porto Rafti', + 'Hoeselt', + 'Moravska Trebova', + 'Bohechio', + 'Eidson Road', + 'Savja', + 'Avalurpet', + 'Santo Tomas de los Platanos', + 'Saint-Vith', + 'Tanaina', + 'Stoneham-et-Tewkesbury', + 'Fuli', + 'Ventania', + 'Lentvaris', + 'Amritpur', + 'Klotze', + 'Benkovac', + 'Csorna', + 'Hyrum', + 'Alfred and Plantagenet', + 'Alberdi', + 'Grossrohrsdorf', + 'Borgo', + 'Pulluru', + 'Pondaluru', + 'Jibou', + 'Ak-Suu', + 'Thap Khlo', + 'Ban Kang', + 'Ingichka', + 'Brandis', + 'Makri', + 'Piprai', + 'Monki', + 'Lambeth', + 'Pindra', + 'Crosia', + 'Lurate Caccivio', + 'Ottappidaram', + 'Castellamonte', + 'Zoudjame', + 'Tuta', + 'Lindesberg', + 'Canonsburg', + 'San Gregorio Atzompa', + 'Pathari', + 'Inacio Martins', + 'Makhar', + "'Ain Leuh", + 'Donabate', + 'Tepetlan', + 'Valsequillo de Gran Canaria', + 'Villarrubia de los Ojos', + 'Parmanpur', + 'Laligam', + 'Bithauli', + 'Langar', + 'Manrar', + 'Oued Laou', + 'Huachipato', + 'Revel', + 'San Francisco la Union', + 'Cepin', + 'Orotina', + 'Pinos Puente', + 'Alesd', + 'Thepaha Raja Ram', + 'Reddippatti', + 'Pareo', + 'Palafolls', + 'Karimpur', + 'Kishanpura Kalan', + 'San Juan del Puerto', + 'Kadriye', + 'La Farlede', + 'Dundankop', + 'Byarozawka', + 'Bradwell', + 'Dahua', + 'Masku', + 'Talapalli', + 'Salmanshahr', + 'Jucurucu', + 'Arques', + 'Inverell', + 'Bni Boufrah', + 'Barahbatta', + 'Merville', + 'Dandkhora', + 'Pike Road', + 'Palmares Paulista', + 'Sallaumines', + 'Tiruvambalapuram', + 'Konidena', + 'Silver City', + 'Comala', + 'Nova Bassano', + 'Dhorgaon', + 'Sangonera la Verde', + 'University of Virginia', + 'Tuam', + 'Simrol', + 'Le Muy', + 'Countryside', + 'Mont-Tremblant', + 'Saint-Doulchard', + 'Ikkarai Boluvampatti', + 'Delcevo', + 'Tirua', + 'Akabira', + 'Glenfield', + 'Nanjundapuram', + 'Kataha', + 'Torihama', + 'Ban Dong Mada', + 'Immingham', + 'Beltangadi', + 'Ban Lao Yao', + 'Fron', + 'Willow Street', + 'Pereshchepyne', + 'Bendrahalli', + 'Piploda', + 'Kathurah', + 'San Lorenzo della Costa', + 'Adamankottai', + 'Nueva Esparta', + 'Bhagsar', + 'Broni', + 'Argelato', + 'Orange Cove', + 'Veitshochheim', + 'Racconigi', + 'Dombasle-sur-Meurthe', + 'Brewer', + 'Monett', + 'Morehead City', + 'Madari Hat', + 'Dobre Miasto', + 'El Haouaria', + 'Banska Stiavnica', + 'Bochaha', + 'Kudowa-Zdroj', + 'Pinhel', + 'Itasca', + 'Armutlu', + 'Uracoa', + 'Gundi', + 'Nambutalai', + 'Colonia Nicolich', + 'Kauniainen', + 'Selfoss', + 'Kushijima', + 'St. Stephens', + 'Campo Ere', + 'Aweitancun', + 'Sigatoka', + 'Bernay', + 'Sabangan', + 'Caldas de Reyes', + 'Anantpur', + 'Sturgeon Bay', + 'Saint-Remy-de-Provence', + 'Bluefield', + 'Port Elgin', + 'Nowy Dwor Gdanski', + 'Flexeiras', + 'Saint-Zotique', + 'Tadhwa Nandpur', + 'Babhantoli', + 'South Strabane', + 'Widnau', + 'Sudlohn', + 'Grado', + 'Neuville-les-Dieppe', + 'Hockley', + 'Datori', + 'Caernarfon', + 'Boves', + 'Saint-Raymond', + 'Oulad Imloul', + 'Kfar Aabida', + 'Wladyslawowo', + 'Ohrdruf', + 'Masar', + 'Bowen', + 'Alcanar', + 'Epalinges', + 'Nersingen', + 'Fernan-Nunez', + 'Gandlapenta', + 'Agareb', + 'Tila', + 'Cuprija', + 'Izium', + 'Muyinga', + 'Thogaduru', + 'Kirlampudi', + 'Cuellar', + 'Herkimer', + 'Mortagua', + 'Dasso', + 'Yazikonak', + 'Postojna', + 'Dessel', + 'Sannicandro di Bari', + 'Sandy Hook', + 'Branquinha', + 'Guateque', + 'Bhawanandpur', + 'Nakaechi', + 'Gibsons', + 'Eschenbach', + 'North College Hill', + 'Jessup', + 'Swanage', + 'Hindoli', + 'Nurobod Shahri', + 'Yarm', + 'Hemau', + 'Khesht', + 'Oil City', + 'Hartland', + 'Yalaguina', + 'Targu Frumos', + 'Sofiivka', + 'Balsamo', + 'Hlinsko', + 'Petua', + 'Has', + 'Dobhawan', + 'Szigetvar', + 'Xicotencatl', + 'Ban Nam Dip Luang', + 'Hochberg', + 'Gonikoppal', + 'Chavuttahalli', + 'Trzebiatow', + 'Chilpur', + 'Ferros', + 'Beaumont-sur-Oise', + 'Kudayattur', + 'Agoue', + 'Cavalcante', + "'Ain Kihal", + 'Soanpeta', + 'Jacinto City', + 'Leers', + 'Majali', + 'Wiang Sa', + 'Sulibele', + 'Casaluce', + 'Grimmen', + 'Sarahs', + 'Luchow', + 'Aire-sur-la-Lys', + 'Pachhapur', + 'Banaso', + 'Wielsbeke', + 'Ratnahalli', + 'Puduppattanam', + 'Cingoli', + 'Bou Zemou', + 'Shiyuan', + 'Ramree', + 'Rellivalasa', + 'Talavadi', + 'Osterburg', + 'Bunol', + 'Perumbalai', + 'Pagidyala', + 'Avanashipalaiyam', + 'Lizzano', + 'Bourg-de-Peage', + 'Aytre', + 'Vasilika', + 'New Square', + 'Saint-Sulpice-la-Pointe', + 'Nagathan', + 'Photharam', + 'Lago Ranco', + 'Schulzendorf', + 'Bladensburg', + 'Villa Aldama', + 'Petrolina de Goias', + 'Ezanville', + 'Cuervos', + 'Fauske', + 'Ban Wiang Ka Long', + 'Parur', + 'Sarmera', + 'Cesa', + 'Aiea', + 'Sanampudi', + 'Gawan', + 'Ittikelakunta', + 'Mae Rim', + 'Mizhhiria', + 'Kochgawan', + 'Oulad Ayyad', + 'Karczew', + 'Miltenberg', + 'Nandamuru', + 'Topsham', + 'McKee City', + 'Bilozerka', + 'Daulatpur', + 'Girard', + 'West Glens Falls', + 'Sitebe', + 'Erdokertes', + 'Parsons', + 'Szubin', + 'Maliano', + 'Savignano sul Panaro', + 'Sorbolo', + 'Borogani', + 'Surany', + 'Baretha', + 'Perols', + 'Chansolme', + 'Kayyngdy', + 'Xiada', + 'Adesar', + 'Mianpur Dubauli', + 'Koranampatti', + 'Traversetolo', + 'Lititz', + 'Palankottai', + 'Bisaria', + 'Zymohiria', + 'Paranacity', + 'Vares', + 'Parauli', + 'Virapandiyanpattanam', + 'Rathdrum', + 'Pine Castle', + 'Lower Swatara', + 'Basse-Goulaine', + 'Kamargani', + 'Velyka Dymerka', + 'Boxley', + 'Vemulanarva', + 'Wepener', + 'Lincoln Village', + 'Port Perry', + 'Bad Gandersheim', + 'Nazira', + 'Sevilla La Nueva', + 'Kondaparti', + 'Fontoura Xavier', + 'Ekalbehri', + 'Vardhamankota', + 'Teixeira Soares', + 'Gobindpura', + 'Dakpatthar', + 'Kannulu', + 'Sangi', + 'Boulder Hill', + 'Fitampito', + 'Salehpur', + 'Arrapalli', + 'Matawan', + 'Mahomet', + 'Elizabethtown-Kitley', + 'Harding', + 'Cunday', + 'Thikri', + 'Dabhaura', + 'Naruar', + 'Paso Canoas', + 'Kadikoy', + 'Rauco', + 'Berchha', + 'Ramasingavaram', + 'Gangadhar', + 'Bjarred', + 'Lorgues', + 'Lototla', + 'Nieuw-Lekkerland', + 'Dodarasinakere', + 'Conselice', + 'Ehringshausen', + 'El Cacao', + 'Capitan Mauricio Jose Troche', + 'Chaplynka', + 'Hohenhameln', + 'Kanhai', + 'Udburu', + 'Listowel', + 'Kakamas', + 'Mezobereny', + 'Khundawandpur', + 'Volterra', + 'Bethel', + 'Jinshui', + 'Mama Khel', + 'Newburn', + 'Le Rheu', + 'Navani', + 'Ekhari', + 'Khaspur', + 'Wilkau-Hasslau', + 'Colmenarejo', + 'Jalkaura', + 'Bohemia', + 'Chanal', + 'Piedras Blancas', + 'Barskoon', + 'Menzel Kamel', + 'Jianshi', + 'Crosne', + 'Kaikaram', + 'Vatakemuri', + 'Rampur Rajwa', + 'Crystal Beach', + 'Tounfafi', + 'Pagqen', + 'Pedra Badejo', + 'Somvarpet', + 'Yamakita', + 'Falam', + 'Santa Rosa del Penon', + 'Psychiko', + 'Mallampalli', + 'Xinpi', + 'Meridianville', + 'Tatoufet', + 'Barwadih', + 'Castel Bolognese', + 'Tomah', + 'Ankadimanga', + 'Sroda Slaska', + 'Lescar', + 'Cuorgne', + 'Esopus', + 'Atari', + 'Sebnitz', + 'Tadworth', + 'Zawyat Sidi Ben Hamdoun', + 'Eurajoki', + 'Manbazar', + 'Valaiyampattu', + 'Bargersville', + 'Aguia Branca', + 'Cape Elizabeth', + 'Puigcerda', + 'Steger', + 'Tlahualilo de Zaragoza', + 'Basco', + 'Shevington', + 'Smiths Falls', + 'Worsborough', + 'Castelfranco di Sopra', + 'Seybaplaya', + 'Sztum', + 'Janapul', + 'Adivala', + 'Bni Gmil', + 'Salcea', + 'Byureghavan', + 'Ban Nong Tong', + 'Sabaoani', + 'Kalladai', + 'Grinnell', + 'Oosterwolde', + 'Manchenahalli', + 'Rampur Parhat', + 'Hohr-Grenzhausen', + 'Nagyatad', + 'Khagam', + 'Vandam', + 'London Colney', + 'Trovagunta', + 'Amityville', + 'Elhovo', + "Vaprio d'Adda", + 'Bougou', + 'Kujri', + 'Anjukulippatti', + 'Garlasco', + 'Wagner', + 'Dhantola', + 'Arenapolis', + 'Hickam Housing', + 'Lorraine', + 'Douar Messassa', + 'Muh Hasan', + 'Sonsoro', + 'Luckau', + 'San Sebastian de la Gomera', + 'Bisignano', + 'Ngaparou', + 'Tambura', + 'Bulisa', + 'Jingjiazhuang', + 'Bagor', + 'Nathana', + 'Ranigaon', + 'Mangrawan', + 'Iowa Colony', + 'Dagbe', + 'Grosshansdorf', + 'South Abington', + 'Fochville', + 'Gaada', + 'Muddada', + 'Ilami', + 'Devmaudaldal', + 'Oakwood', + 'Pedro Luro', + 'Saldus', + 'Sokotindji', + 'Tixter', + 'Baghduma', + 'Kanchanadit', + 'Emsworth', + 'Kaithwar', + 'Valtoha', + 'Saltsjobaden', + 'Madhuban Bediban', + 'Nea Artaki', + 'Karath', + 'Mehdipur', + 'Astorp', + 'Ramara', + 'Maizal', + 'Llantwit Major', + 'Narayanraopet', + 'Caracuaro', + 'Hesarghatta', + 'Malaudh', + 'Katigang', + 'Nadimpalem', + 'Lucon', + 'Deh-e Shu', + 'Ekchari', + 'Viralimalai', + 'Tamentit', + 'Tepperumalnallur', + 'Durgi', + 'Saumalkol', + 'Pryor Creek', + 'Corella', + 'Cherniakhiv', + 'The Village', + 'Periya Pattanam', + 'Columbia City', + 'Ilsenburg', + 'Quincy-sous-Senart', + 'Bimun', + 'Molagavalli', + 'Santa Maria Jacatepec', + 'Highfields', + 'Senmanat', + 'Leguevin', + 'Foix', + 'Malaimachchampatti', + 'Israna', + 'Ban Krot', + 'Sundarsi', + 'Notre-Dame-des-Prairies', + 'Puszczykowo', + 'Wertingen', + 'Bewdley', + "Anan'evo", + 'Helena-West Helena', + 'Berkine', + 'Molbergen', + 'Cervello', + 'Elurpatti', + 'Asahni', + 'Vallet', + 'Kemberg', + 'Rafelbunol', + 'Marne', + 'Alawalpur', + 'Woodfield', + 'Casca', + 'Toging am Inn', + 'Cherasco', + 'Leeds and the Thousand Islands', + 'Denyekoro', + 'Nehoiu', + 'Uppur', + 'Koufalia', + 'Halen', + 'Quixabeira', + 'Inole', + 'Bridge City', + 'Syurte', + 'Nyzhnohirskyi', + 'Cambira', + "Saint-Barthelemy-d'Anjou", + 'Saint-Amand-Montrond', + 'Legnaro', + 'Runkel', + 'Hohenmolsen', + 'Frouzins', + 'Tabernes Blanques', + 'Mareno di Piave', + 'El Amim', + 'Burela de Cabo', + 'Ban Sathan', + 'Cervera', + 'Gold', + 'Kranidi', + 'Kerap', + 'Shahrak-e Ja`fariyeh', + 'Dolianova', + 'Laurentian Valley', + 'Nittenau', + 'Idumbavanam', + 'Bijeraghogarh', + 'Narsingi', + 'Guney', + 'Khawad', + 'Erikolam', + 'Kadanadu', + 'Cicevac', + 'Negrine', + 'South Normanton', + 'Killamarsh', + 'Tissaf', + 'Kommuru', + 'Gonghaur', + 'Novi Banovci', + 'Dachengzicun', + 'Jisrayn', + 'Deruta', + 'Tavarede', + 'Raitar', + 'Monnickendam', + 'Jantho', + 'Eunice', + 'Rorschach', + 'Tarmount', + 'Dhanga', + 'Kankanalapalle', + 'Adolfo Gonzales Chaves', + 'Cosne sur Loire', + 'Bezliudivka', + 'Pipra', + 'Assi-Ben Okba', + 'Anaconda', + 'Tissint', + 'Ban Bang Phlap', + 'Villacanas', + 'Danesfahan', + 'Borovskoy', + 'Banikane', + 'San Juanito de Escobedo', + 'Villa Canas', + 'Wiener Neudorf', + 'Chewara', + 'Elne', + 'Olivares', + 'Harlakhi', + 'Rasol', + 'Ghosrawan', + 'Saidoke', + 'Huinca Renanco', + 'Braslaw', + 'Medleri', + 'Madeira', + 'Ban San Pong', + 'Abra Pampa', + 'Segorbe', + 'Lerici', + 'Dubrovytsya', + 'Mohelnice', + 'Khanpur Khairanti', + 'Bairiya', + 'Hertzogville', + 'Odobesti', + 'Ahus', + 'Soubakaniedougou', + 'Sabinanigo', + 'Elurupadu', + 'Lugoff', + 'Carneirinho', + 'Teisendorf', + 'Brockworth', + 'Dibraghani', + 'Vadakethara', + 'Ghanipur Bejha', + 'Fishersville', + 'Sidi El Hattab', + 'Basni', + 'Mono', + 'Ipiranga do Piaui', + 'Tocina', + 'Budalur', + 'Anjehalli', + 'Naurhiya', + 'Andergrove', + 'Embrach', + 'Radstock', + 'Sadiqpur Maraul', + 'Bendarhalli', + 'Simarbani', + 'Sivamalai', + 'Glenshaw', + "Estrela d'Oeste", + 'Carqueiranne', + 'Rochelle', + 'San Francisco Libre', + 'An Chau', + 'Jawasa', + 'Bobil', + 'Sarpamari', + 'Nirna', + 'Barga', + 'Coral Hills', + 'Bystrzyca Klodzka', + 'Iawar', + 'Khari', + 'Cavriglia', + 'Aschheim', + 'Arenys de Munt', + 'Halacho', + 'Ngoc Son', + 'Sa Pa', + 'Muhammadganj', + 'Dharir', + 'Ostroda', + 'Dunblane', + 'Kallayi', + 'Gumusova', + 'Benbutucun', + 'Kurort Steinbach-Hallenberg', + 'Orivesi', + 'San Giovanni in Marignano', + 'Anisio de Abreu', + 'Siano', + 'Bellinzago Novarese', + 'Chahar Borj-e Qadim', + 'Elmas', + 'Flossmoor', + 'Hani i Elezit', + 'Voitsberg', + 'Danau Kandimarg', + 'Ramdeora', + 'Mechanicsburg', + 'Cusseta', + 'Mutis', + 'Thames Ditton', + 'Hayle', + 'Ramkali', + 'Recco', + 'Woodway', + 'Dushanove', + 'Pettampalaiyam', + 'Uppalaguptam', + 'Piombino Dese', + 'Kapelle-op-den-Bos', + 'Makamba', + "Conde-sur-l'Escaut", + 'Pokotylivka', + 'Negrete', + 'Taisar', + 'Hazrat Shiura', + 'Denham Springs', + 'Hsenwi', + 'Novopskov', + 'Resana', + 'Magnago', + 'Cetraro', + 'Sint Willebrord', + 'Capriolo', + 'Gammasa', + 'Tazarka', + 'Saint-Philbert-de-Grand-Lieu', + 'Kose', + 'Narpes', + 'Jamunamukh', + 'Vempatti', + 'Ja`fariyeh', + 'Mhajar', + 'Magny-les-Hameaux', + 'Ukwa', + 'Gaurdah', + 'Cutro', + 'Horsell', + 'Middlesborough', + 'Kungsangen', + 'Kadimetla', + 'Grigoriopol', + 'Nepi', + 'Curepto', + 'Saint-Jean-le-Blanc', + 'Raunds', + 'Marvast', + "Sao Jorge d'Oeste", + 'Nove Mesto nad Metuji', + 'Salzhemmendorf', + 'Jhabrera', + 'Sarakkayhalli', + 'Cermenate', + 'Kharagbani', + 'Kakarati', + 'Dymka', + 'Umbrete', + 'San Giorgio di Piano', + 'Rangapuram', + 'Jarville-la-Malgrange', + 'Tirubhuvane', + 'Helena Valley Southeast', + 'Topoloveni', + 'Le Passage', + 'Broadwater', + 'Pumalakkundu', + 'Bakharia', + 'Douar Oulad Bouziane', + 'Pustomyty', + 'Ichenhausen', + 'Ukhai Purbari Patti', + 'Madaya', + 'Sierning', + 'Audenge', + 'Zacualpan de Amilpas', + 'Pau Brasil', + 'Mega', + 'Barjhar', + 'Hamira', + 'Ecatzingo', + 'Zorneding', + 'Rehau', + 'Werneuchen', + 'Hathaura', + 'Chhapera', + 'Tivat', + 'Locust Grove', + 'Frankfort Square', + 'Langnau', + 'Tandarampattu', + 'Baisuhalli', + 'Barahpur', + 'Langhnaj', + 'Shahr-e Majlesi', + 'Eemnes', + 'Punta Indio', + 'Tiruvaduturai', + 'Muppalla', + 'Opalenica', + 'Sebastiao Laranjeiras', + 'Obernkirchen', + 'Tadangam', + 'Diamondhead', + 'Maraial', + 'Miajadas', + 'Hattula', + 'Molsheim', + 'Mirjaveh', + 'Ubbergen', + 'Wallerfangen', + 'Tassera', + 'Wilnecote', + 'Southside', + 'Ntchisi', + 'Schlangen', + 'Bagchini', + 'Mahalgaon', + 'Canal Winchester', + 'Bayaram', + 'Kirangur', + 'Awans', + 'Lutterworth', + 'Chinnampalaiyam', + 'Ruffano', + 'Adelsdorf', + 'Aidlingen', + 'Gore', + 'Ameskroud', + 'Orlu', + 'Savenay', + 'Queensferry', + 'Sherborne', + 'Asudapuram', + 'Igarata', + 'Aucamville', + 'Chilmil', + 'Kolkwitz', + 'Siteia', + 'Chiman', + 'Oravita', + 'Modra', + 'Palhano', + 'Schaafheim', + 'Valreas', + 'Qutubpur', + 'East Stroudsburg', + 'Suan', + 'Barpathar', + 'Kalaikunda', + 'Laanoussar', + 'Harqalah', + 'San Agustin de las Juntas', + 'Santa Comba', + 'Nea Moudania', + 'Ladhuka', + 'Yezhi', + 'Nogent-le-Rotrou', + 'Chandwara', + 'Bhogapuram', + 'Sankt Valentin', + 'Pirpirituba', + 'Wehrheim', + 'Lancon-Provence', + 'Doctor Arroyo', + 'Parol', + 'Minano', + 'Rum', + 'Tonneins', + 'Nattakkadaiyur', + 'Katuria', + 'Takkali', + 'South Amboy', + 'Torrinha', + 'Mallappadi', + 'Santa Teresa di Riva', + 'Crestline', + 'Charter Oak', + 'Blachownia', + 'Ban Khi Lek', + 'Macomer', + 'Rodeo', + 'Zwenkau', + 'St. Anthony', + 'Havre', + 'Ouistreham', + 'Kesli', + 'Manteswar', + 'Nulivedu', + 'Sainte-Julienne', + 'Heiligenhafen', + 'Chinnakkavundanur', + 'Jaffar Khanpet', + 'Boddikurapadu', + 'Tarawan', + 'Pelagor', + 'Nort-sur-Erdre', + 'Studenka', + 'Samdrup Jongkhar', + 'Bruchhausen-Vilsen', + 'Irthlingborough', + 'Sujapur', + 'Vanzago', + 'Gatteo', + 'Chupinguaia', + "L'Isle-Jourdain", + 'Sosale', + 'Kaleybar', + 'Zafferana Etnea', + 'Fort Stewart', + 'Lubuagan', + 'Pesca', + 'Hagondange', + 'Hasanpura', + 'Nagayalanka', + 'Kopong', + 'Lac des Oiseaux', + 'Unao', + 'Telkathu', + 'Kalvarpatti', + 'Oued Essalem', + 'Maihma Sarja', + 'Jahangirpur Salkhani', + 'Bull Mountain', + 'Moisei', + 'Peixe', + 'Baisa', + 'Angola', + 'Santa Maria de Cayon', + 'Laghzawna', + 'Adakli', + 'Ehningen', + 'Timmapuram', + 'Boali', + 'Shanhur', + 'San Pablo Huixtepec', + 'Imielin', + 'Rudraprayag', + 'Janpur', + 'Mohammad Yar', + 'Monserrat', + 'Redon', + 'Chianki', + 'Bang Khla', + 'Ouled Rached', + 'Ralla', + 'Pangunattam', + 'Altinyayla', + 'Dornstadt', + 'Quakertown', + 'East Franklin', + 'Nor Hachn', + 'Torgelow', + 'Rupahi', + 'Choix', + 'Sadarak', + 'Pfedelbach', + 'Shimizu', + "Saint-Jean-d'Illac", + 'Hualane', + 'Patchur', + 'Mariyadau', + 'Satravada', + 'Qualicum Beach', + 'Nieuwleusen', + 'San Jose Guayabal', + 'Frodsham', + 'Polegate', + 'Pasraha', + 'Ilvesheim', + 'Draksharama', + 'Livron-sur-Drome', + 'Farsala', + 'Uranganpatti', + 'Mumaradikop', + 'Barros Cassal', + 'Honganur', + 'Porto de Pedras', + 'Rosario do Catete', + 'Le Cres', + 'Isua', + 'Bo`z', + 'Shende', + 'Kanajanahalli', + 'Khandaich', + 'Ecorse', + 'Skidaway Island', + 'Newfane', + 'Malahide', + 'Titu', + 'Poienile de sub Munte', + 'Perwez', + 'Modavandisatyamangalam', + 'Kharahara', + 'Gassino Torinese', + 'Kisslegg', + 'Ledbury', + 'Sindos', + 'Kruszwica', + 'Juprelle', + 'Tecklenburg', + 'La Jigua', + 'Dahi', + 'Milajerd', + 'St. Francis', + 'Tysmenytsia', + 'Asarhi', + 'Bernalillo', + 'Jandaira', + 'Marano Vicentino', + 'Ventnor City', + 'Bad Liebenwerda', + 'Lagunia Raghukanth', + 'Kollankulam', + 'Mabeskraal', + 'Analaroa', + 'Kunnattur', + 'Uppalapadu', + 'Ban Bo Phlap', + 'San Pancrazio Salentino', + 'Bethalto', + 'Frickenhausen', + 'Bagnara Calabra', + 'Moldova Noua', + 'Nakhon Thai', + 'Herculandia', + 'Chicholi', + 'Punta del Este', + 'Pozo Almonte', + 'Laurens', + 'Elsenfeld', + 'Catral', + 'Majhariya', + 'Bhachhi', + 'Altun Kawbri', + 'Nakoushi', + 'Thakurainia', + 'Almagro', + 'Coleford', + 'Leonia', + 'Mascota', + 'Skwierzyna', + 'Abuzar-e Ghaffari', + 'Gaggiano', + 'Nakao', + 'Mound', + 'Crigglestone', + 'Teplohirsk', + 'Gainrha', + 'Goldach', + "Clermont-l'Herault", + 'Deokali', + 'Joghtay', + 'Rajapudi', + 'Punnaikkayal', + 'Wasilla', + 'Guneysinir', + 'Oppicherla', + 'Merrill', + 'Freystadt', + 'Pappampatti', + 'Tlahuiltepa', + 'Niederhasli', + 'Macedon', + 'Padinska Skela', + 'Didymoteicho', + 'Alukkuli', + 'Chilakhana', + 'Khotyn', + 'Walworth', + 'Ochsenhausen', + 'Douar Oulad Sidi Moussa', + 'Ain el Hadjar', + 'Launaguet', + 'Sidi Lahsene', + 'Riscani', + 'Barei', + 'Rinopolis', + 'Piamonte', + 'Weissenthurm', + 'Edeleny', + 'Itiki', + 'Barnaon', + 'Picture Rocks', + 'Aljustrel', + 'Fairfield Glade', + 'Bojaca', + 'Pedda Tumbalam', + 'Las Tablas', + 'Velykyi Bychkiv', + 'Risaralda', + 'Bures-sur-Yvette', + 'Borgholzhausen', + 'Muro del Alcoy', + 'Escaudain', + 'San Pedro Nonualco', + 'Gomaringen', + 'Towcester', + 'Pasian di Prato', + 'Rensselaer', + 'Sugar Grove', + 'Kudelstaart', + 'Keuruu', + 'Ganaram', + 'Algun', + 'Samalpur', + 'Douar Ezzerarda', + 'Schubelbach', + 'Niesky', + 'San Jose La Arada', + 'Gandikunta', + 'Vittuone', + 'Manzanares el Real', + 'Bendapudi', + 'Katteragandla', + 'Sitanagaram', + 'Ban Son Loi', + 'Magalia', + 'Haiku-Pauwela', + 'Diouna', + 'Hamrun', + 'Capilla del Senor', + 'Benahavis', + 'Smoline', + 'Wunsiedel', + 'Fallon', + 'Otumba', + 'Mels', + 'Harbatpur', + 'Loria', + 'Lesquin', + 'Chunakhali', + 'Montescaglioso', + 'Talata-Angavo', + 'Chala', + 'Reshetylivka', + 'Fatao', + 'Paray-le-Monial', + 'Belley', + 'Barleben', + 'Rain', + 'Iarpur', + 'Raipur Buzurg', + 'Hailey', + 'Oulad Cherif', + 'Bandio', + 'Romang', + 'Tanakoub', + 'Santa Isabel Cholula', + 'Gooik', + 'Zoubiria', + 'Mamidipalli', + 'Aranya Kalan', + 'Nutakki', + 'Tanamarina-Sakay', + 'Momchilgrad', + 'Mirante da Serra', + 'Tasso', + 'Juraqan', + 'Kahla', + 'Nossa Senhora Aparecida', + 'Dielheim', + 'Sandalpur', + 'Bahabad', + 'Rethen', + 'Giardini', + 'Stevenston', + 'Karsaut', + 'Vallapuram', + 'Ryki', + 'Brugnera', + 'Philippeville', + 'Carrillos', + 'La Victoria de Acentejo', + 'Bowdon', + 'Kondrukota', + 'Vaikuntam', + 'Castelleone', + 'Kesap', + 'San Lorenzo de Descardazar', + 'Kaujalgi', + 'Hlyboka', + 'La Bruyere', + 'Fazendinha', + 'I-n-Amenas', + 'Aslanapa', + 'Kalanchak', + 'Baia da Traicao', + 'Kondayampalaiyam', + 'Tisnov', + 'Jajireddigudem', + 'White Meadow Lake', + 'Oromocto', + 'Borja', + 'Clay Cross', + 'Bude', + 'Shannon', + 'Gudimulakhandrika', + 'Bad Laer', + 'Baluntaicun', + 'Gandhwani', + 'Vallahbhapuram', + 'Badagabettu', + 'Gangaura Behra', + 'Washington Terrace', + 'Japaratinga', + 'Antonio Dias', + 'Mejillones', + 'Joigny', + 'Inverigo', + 'Badnor', + 'Nonea', + 'Saraunja', + 'Kandiyankovil', + 'Ottapparai', + 'Swamimalai', + 'Evian-les-Bains', + 'Totnes', + 'Babadag', + 'Nong Kung Si', + 'Ghattupal', + 'Sholaqqorghan', + 'Altenbeken', + 'Kandel', + 'Kharika', + 'Kodakkal', + 'Castrolibero', + 'Qarqaraly', + 'Shawano', + 'Cape St. Claire', + 'Kannavam', + 'Pong Nam Ron', + 'Ban Kham Pom', + 'Pohrebyshche', + 'Jambukuttaippatti', + 'Chokkalingapuram', + 'Badanahatti', + 'Covasna', + 'Llagostera', + 'Surak', + 'Waseca', + "O'Hara", + 'Gnarrenburg', + 'Golbaf', + 'Palm Beach', + 'Falan', + 'Elsfleth', + 'Arlesheim', + 'Mont-Saint-Martin', + 'Cullercoats', + 'Vadavalam', + 'Irungalur', + 'Xalqobod', + 'Qorovulbozor', + 'Gothurutha', + 'Ramayipatti', + 'Araujos', + 'Sassnitz', + 'Laheji', + 'Paredes de Coura', + 'Tiana', + 'Spata', + 'Aliquippa', + 'San Fausto de Campcentellas', + 'Bike', + 'Damargidda', + 'Panthersville', + 'Une', + 'Jamhra', + 'Susari', + 'Valkurti', + 'Blackstone', + 'Whitecourt', + 'Nowra', + 'Tenedla', + 'Leichi', + 'Landivisiau', + 'Ban Chang Phuak', + 'Muli', + 'Vignate', + 'Cobanlar', + 'Stovring', + 'Shirguppi', + 'Chalkari', + 'Jogaili', + 'As Sidrah', + 'Tibana', + 'Tepe-Korgon', + 'Santa Maria Ajoloapan', + 'Capbreton', + 'Tilehurst', + 'Chikkala', + 'Sewa', + 'Aberbargoed', + 'Olds', + 'Suwannaphum', + 'Jagannadapuram', + 'Himmatpura', + 'Rajepur', + 'Sukkampatti', + 'Roux', + 'Canela Baja', + 'Cisterniga', + 'Tiptree', + 'Conshohocken', + 'Sidi Bou Othmane', + 'Hirehalli', + 'Maidencreek', + 'Guntramsdorf', + 'Harpur Bhindi', + 'Vega Alta', + 'Cerro Grande', + 'Alsbach-Hahnlein', + 'Douar El Mellaliyine', + 'Arceburgo', + 'Galten', + 'Madepalli', + 'Nelali', + 'Horr-e Riahi', + 'Grants', + 'Ahuimanu', + 'Elze', + 'Hacine', + 'Yatton', + 'Budhma', + 'Nashtifan', + 'Obukhivka', + 'Itapebi', + 'Yaxley', + 'Ivins', + 'Rockingham', + 'Makow Mazowiecki', + 'Murfatlar', + 'Tuskegee', + 'Binisalem', + 'Onchan', + 'Waiuku', + 'Ban Wat Chan', + 'Jerez de los Caballeros', + 'Sarkad', + 'Ban Yaeng', + 'Trittau', + 'Biblis', + 'Dorverden', + 'Marale', + 'Matelica', + 'Verdejante', + 'Xiangping', + 'Ville-la-Grand', + 'Littleport', + 'Monte Rico', + 'Boekenhouthoek', + 'Foammulah', + 'Pencoed', + 'West Manheim', + 'Dommasandra', + 'Corumbaiba', + 'Waldfeucht', + 'Micco', + 'Flanders', + 'Irshava', + 'Yvoir', + 'Abalessa', + 'Incline Village', + 'Zabalj', + 'Gadabay', + 'Palomares del Rio', + 'Reggiolo', + 'Beauraing', + 'Ifigha', + 'Op', + 'Ussel', + 'Banbhag', + 'Bariariya Tola Rajpur', + 'Entre Ijuis', + 'Beauchamp', + 'Halgeri', + 'Santo Domingo Petapa', + 'Gualaquiza', + 'San Fructuoso de Bages', + 'Sungal', + 'Pilikodu', + 'Wysokie Mazowieckie', + 'Fateh Nangal', + 'Zorbig', + 'Zupanja', + 'Imotski', + 'Piripa', + 'Grunheide', + 'Kyritz', + 'Morubagalu', + 'Anjur', + 'Narayanpur', + 'Cachoeira dos Indios', + 'Vallendar', + 'Belakvadi', + 'Razanj', + 'Buenopolis', + 'Chinnayagudem', + 'Felino', + 'Lavis', + 'Al Bardiyah', + 'Sangeorgiu de Mures', + 'Sabie', + 'Gondizalves', + 'Konduru', + 'Sansa', + 'Veinticinco de Diciembre', + 'Mangasamudram', + 'Sauzal', + 'Maserada sul Piave', + 'Japura', + 'Santa Lucia di Piave', + 'Kaithahi', + 'Bir Tam Tam', + 'Damu', + 'Sibkund', + 'Nerinjippettai', + 'Seven Corners', + 'Audubon', + 'Helotes', + 'Des Peres', + 'Cajvana', + 'Caluco', + 'Solita', + 'Copceac', + 'Lagbe', + 'Pleternica', + 'Dihri', + 'Bhargaon', + 'Forestdale', + 'Huron East', + 'Stryzhavka', + 'Bilenke', + 'Laufenburg (Baden)', + 'Pepillo Salcedo', + 'Guano', + 'Gavirate', + 'Ipuiuna', + 'Tecoh', + 'Ban Wang Krachae', + 'Nagykallo', + 'Tafersit', + 'Ciudad Insurgentes', + 'Cajobi', + 'Malingaon', + 'North Codorus', + 'West Athens', + 'Dazhuangzi', + 'Haddington', + 'Yenmangandla', + 'Govindapalle', + 'Malalbergo', + 'Perkasie', + 'Mwaline al Oued', + 'Lanta', + 'Mokri', + 'Mendig', + 'Jandola', + 'San Manuel Chaparron', + 'Masera di Padova', + 'Elsmere', + 'Denekamp', + 'Montoro', + 'Umburetama', + 'Crawford', + 'Marlboro Village', + 'Amatlan de los Reyes', + 'Hostivice', + 'Shanklin', + 'Middlebury', + 'Chtiba', + 'Peresecina', + 'Olesno', + 'Chitrada', + 'Nandiyalam', + 'Currumbin', + 'Rothrist', + 'Guatape', + 'Tettu', + 'Temperance', + 'Sunset Hills', + 'Piranguinho', + 'Palocabildo', + 'Groenlo', + 'Dodji-Bata', + 'Bamaiya Harlal', + 'Killimangalam', + 'Bad Schussenried', + 'Kongnolli', + 'East Grand Forks', + 'Hurzuf', + 'Alawandi', + 'Kaglipur', + 'Koheda', + 'Dospat', + 'Sauce', + 'Phagu', + 'Sihali Jagir', + 'Eshkanan', + 'Miramar Beach', + 'Kuduru', + 'Istrana', + 'Horodenka', + 'Mata Verde', + 'Nechmeya', + 'Pattiswaram', + 'Tunari', + 'Zeydabad', + 'Fujisawacho-niinuma', + 'Montes Altos', + 'Beuvry', + 'Hawthorn Woods', + 'Zarbdor Shaharchasi', + 'Andre Fernandes', + 'Reinfeld', + 'Miryal', + 'Odayarpatti', + 'Herenthout', + 'Carmen de Carupa', + 'Chotebor', + 'Prabhat Pattan', + 'Fairless Hills', + 'Flemington', + 'Brejolandia', + 'Loeches', + 'Uchti', + 'Satghara', + 'Weare', + 'Embalse', + 'San Zenon', + 'Tekpanja', + 'Steynsrus', + 'Rebordosa', + 'Govindapuram', + 'Kod', + 'Cresskill', + 'Westampton', + 'Chaukhata', + 'Belek', + 'Datian', + 'Oborniki Slaskie', + 'Cameron', + 'Benton Harbor', + 'Iguidiy', + 'Hirske', + 'Katakwi', + 'Nalbach', + 'Usworth', + 'Gok', + 'Orosi', + 'Ouedeme', + 'Consaca', + 'Rivesaltes', + 'Guryongpo', + 'Rada Tilly', + 'Rincao', + 'McCordsville', + 'Rondon', + 'Ambara', + 'Tineo', + 'Urbach', + 'Coatetelco', + 'Fehrbellin', + 'Pithiviers', + 'Sogam', + 'Zeerust', + 'Kenar', + 'Bonnievale', + 'La Matanza de Acentejo', + 'Davuluru', + 'Nagaoki', + 'Bemarivo', + 'Logatec', + 'Suances', + 'Greytown', + 'Ouaregou', + 'Portlethen', + 'Kiskunlachaza', + 'Koila Belwa', + 'Yeldurti', + 'Huntertown', + 'Marinka', + 'August', + 'Mendon', + 'Dasaut', + 'Hokur Badasgom', + 'Haripura', + 'Sidi Ouassay', + 'Paraparaumu Beach', + 'New Scotland', + 'Kozuchow', + 'Bimawan', + 'Absecon', + 'Olalapadi', + 'Mauji', + 'Yui', + 'Beecher', + 'Gtarna', + 'Majhaulia', + 'Periyamuttur', + 'Hussepur', + 'Daita', + 'Velampatti', + 'Hooper', + 'Brejao', + 'Bageshwar', + 'Andiyappanur', + 'Dinnington', + 'Mirzanagar', + 'Banaruyeh', + 'Kanasanapalle', + 'Gurmia', + 'Carignano', + 'Ban Tha Phra', + 'Mainaschaff', + 'Jamunia', + 'Karayilan', + 'Mendicino', + 'Jumla', + 'Grossbeeren', + 'Pontardulais', + 'Suganwan', + 'Fiumefreddo di Sicilia', + 'Notodden', + 'Kirchberg', + "Mosciano Sant'Angelo", + 'Sinaia', + 'Sibilia', + 'Pedda Mupparam', + 'Marai Kalan', + 'Mbuzini', + 'Luis Gomes', + 'Hagaranahalli', + 'Townsend', + 'Fatehpur Bala', + 'Valley Cottage', + 'Nykobing Mors', + 'Viravada', + 'Gidha', + 'Ghat Borul', + 'Vinhais', + 'Carregado', + 'Paulo Lopes', + 'Morada Nova de Minas', + 'Chalastra', + 'Amal', + 'Puttai', + 'Orte', + 'Berndorf', + 'Adjido', + 'Iquira', + 'Magny-le-Hongre', + 'Venkatadripalem', + 'Oggiono', + 'Economy', + 'Ewo', + 'Campobello di Licata', + 'Sarauni', + 'Wollert', + 'Uppugunduru', + 'Strehaia', + 'Scionzier', + 'Harrodsburg', + 'Country Club Estates', + 'Roxborough Park', + 'Lacchiarella', + 'Toccoa', + 'Northwest Harborcreek', + 'Chaponost', + 'Januario Cicco', + 'Udarband', + 'Ayanikkad', + 'Salto Grande', + 'Bonhill', + 'Lanark', + 'Kegen', + 'Bemiss', + 'Colac', + "Intich'o", + 'Mohon', + 'Manoke', + 'Poiana Mare', + 'Mamnur', + 'Borgosatollo', + 'Orange Park', + 'Abu Khashab', + 'Khasbalanda', + 'Livno', + 'Zwiesel', + 'Banire Kore', + 'Berching', + 'Harahan', + 'Andilana Avaratra', + 'La Ravoire', + 'Janhapara', + 'Fossombrone', + 'Breckerfeld', + 'Podenzano', + 'Ban Ngio Ngam', + 'Santa Sylvina', + 'Leven', + 'Warkan', + 'Dadrewa', + 'Old Orchard Beach', + 'Charakunda', + "Monteroni d'Arbia", + 'Iijima', + 'Meridiala', + 'Travis Ranch', + 'Beregadougou', + 'Aadorf', + 'Tajpur', + 'Villa Castelli', + 'Nova Paka', + 'Bockhorn', + 'Breinigsville', + 'Adami Tulu', + 'Gohi Bishunpur', + 'Lapeer', + 'Waldheim', + 'Ksar Belezma', + 'North Merritt Island', + 'Cayirli', + 'Westerland', + 'Doberlug-Kirchhain', + 'Furth im Wald', + 'Bougival', + 'Les Sorinieres', + 'Porto Tolle', + 'Dunbar', + 'Nanzhuang', + 'Monticello Conte Otto', + 'Tuscumbia', + 'Velyki Luchky', + 'Nhan Trach', + 'Kurichedu', + 'Kannal', + 'Katsuyama', + 'Booneville', + 'Pullach im Isartal', + 'Hemmoor', + 'Pivnichne', + 'Sint-Martens-Lennik', + 'Rampur Khajuriya', + 'Ampasimpotsy-Gara', + 'Ceelbuur', + 'Coqueiral', + 'Manatuto', + 'Barwell', + 'Sahapur', + 'Odzaci', + 'Zalishchyky', + 'Beckwith', + 'Arico el Nuevo', + 'Blairgowrie', + 'Cupar', + 'Nadol', + 'Bala Cynwyd', + 'Muhos', + 'Tomblaine', + 'Kaniwara', + 'Foiano della Chiana', + 'Moman Barodiya', + 'Ban Wang Pradu', + 'Karliova', + 'Mandishah', + 'Babai Kalan', + 'Aplao', + 'Estanzuelas', + 'Coronel Du Graty', + 'Dhauni', + 'Madhurapur', + 'Basdeopur', + 'Hatti Mattur', + 'Akat Amnuai', + 'Treia', + 'Craig', + 'Kaeng Khro', + 'Mburucuya', + 'Harua', + 'Gerstungen', + 'Labrador City', + 'Brand-Erbisdorf', + 'Moranha', + 'Blacklick Estates', + 'Kasane', + 'Rio del Mar', + 'Tutrakan', + 'Mishrikot', + 'Perondi', + 'Seneca Falls', + 'Rafard', + 'Furtwangen im Schwarzwald', + 'Le Teich', + 'Venturina', + 'Lunner', + 'Tha Luang', + 'Chanco', + 'Kambaneri Pudukkudi', + 'Crvenka', + 'Lago Vista', + 'Ain el Mediour', + 'Chitcani', + 'Maropaika', + 'Soamahamanina', + 'Ambodivoanio', + 'Tsimafana', + 'Sahatsiho-Ambohimanjaka', + 'Ranopiso', + 'Ivandrika', + 'Marotolana', + 'Ambatoria', + 'Lanivo', + 'Sarasambo', + 'Antambohobe', + 'Ambalajia', + 'Nato', + 'Mahamaibe', + 'Mitanty', + 'Salobe', + 'Ambariokorano', + 'Vatananto', + 'Iara', + 'Ampary', + 'Ambalaromba', + 'Soamanonga', + 'Bemaharivo', + 'Anteza', + 'Bekopaka', + 'Antaly', + 'Anjialava', + 'Ankarana-Miraihina', + 'Antsaidoha-Bebao', + 'Nosibe', + 'Soanierana', + 'Soanenga', + 'Manampaneva', + 'Manja', + "Ambinanin' Andravory", + 'Belinta', + 'Marovatolena', + 'Antseza', + 'Andribavontsona', + 'Antanankambano', + 'Alakamisy-Ambohimahazo', + 'Benato-Toby', + 'Ankirihitra', + 'Antsatramidola', + 'Amboronabo', + 'Manevy', + 'Beparasy', + 'Tandrano', + 'Ambarimaninga', + 'Ambodimahabibo', + "'s-Gravendeel", + 'Dhiban', + 'Dahbed', + 'Qahramon', + 'Lo Miranda', + 'Bovingdon', + 'Diabugu', + 'Jangalapalli', + 'Urpaar', + 'Lohara', + 'Rohera', + 'Ugamedi', + 'Carneiros', + 'Marcacao', + 'Puerto Octay', + 'Patut', + 'Hetanpur', + 'Kalicherla', + 'Rarz', + 'San Pedro Atocpan', + 'Mbamba Bay', + 'Neuotting', + 'Dholbaja', + 'Novyi Svit', + 'Zschopau', + 'Almusafes', + 'Hirehaluhosahalli', + 'Lake Park', + 'Glens Falls North', + 'Guichen', + 'Rajod', + 'Pomichna', + 'Panasapadu', + 'Druento', + 'Lamorlaye', + 'Settivaripalle', + 'Peddannavaripalle', + 'Ixtapa Zihuatanejo', + 'Podu Iloaiei', + 'Perl', + 'Veauche', + 'Harleysville', + 'Saffle', + 'Icaraima', + 'Devanangurichchi', + 'Gacko', + 'Kandra', + 'Rice Lake', + 'Had Dra', + 'Apahida', + 'Kozova', + 'Iscuande', + 'Gudluru', + 'Chundale', + 'Shelburne', + 'Ardooie', + 'Togou', + 'Dulce Nombre de Maria', + 'Santana do Manhuacu', + 'Wenzenbach', + 'Kanchanpalli', + 'East Nottingham', + 'Foum Zguid', + 'Urdinarrain', + 'Bassenge', + 'Denbigh', + 'Hirayama', + 'Kosum Phisai', + 'Arboledas', + 'Telaprolu', + 'Almargem', + 'Tiou', + 'Seydunganallur', + 'Puerto Lleras', + 'Hilzingen', + 'Khiriawan', + 'Pulaski', + 'Yaprakli', + 'Brooksville', + 'Lopatcong', + 'San Francisco Ixhuatan', + 'Acobamba', + 'Kattamuru', + 'Bayabas', + 'Akpassi', + 'Hosuru', + 'Sanganakallu', + 'Pulimakkal', + 'Taber', + 'Huasco', + 'Sarzeau', + 'Pedda Pendyala', + 'Higuera de Zaragoza', + 'Leisure World', + 'Uspenka', + 'Ponnada', + 'Bhirua', + 'Barwan', + 'Grabels', + 'Iseo', + 'Saline', + 'Tepechitlan', + 'Pena Forte', + 'Yekambarakuppam', + 'Fitzgerald', + 'Evergreen', + 'Thung Sai', + 'Roztoky', + 'Talevad', + 'Mahamda', + 'Pararia', + 'Tulbagh', + 'Valea lui Mihai', + 'Ianca', + 'Vrhnika', + 'Borgoricco', + 'Miradouro', + 'Lolokhur', + 'Perkiomen', + 'Al Yadudah', + 'Neuried', + 'Fort Irwin', + 'Tzitzio', + 'Saint Sampson', + 'Kharsawan', + 'Siachoque', + 'Cloverdale', + 'Plainedge', + 'Ortenberg', + 'Cheste', + 'Mudgere', + 'Park Forest Village', + 'Aver-o-Mar', + "Gonfreville-l'Orcher", + 'Grenade', + 'Tovala', + 'Fredensborg', + 'Sileby', + 'Segni', + 'Nuqui', + 'Unagatla', + 'Sheffield Lake', + 'Sarenja', + 'Gazulapalle', + 'Hlobyne', + 'Rio das Flores', + 'Wangdue Phodrang', + 'Villamediana de Iregua', + 'Sanchi', + 'San Francisco Chimalpa', + 'Fuldabruck', + 'Zacharo', + 'Bayyavaram', + 'Kusmaul', + 'Tvrdosin', + 'Velden am Worthersee', + 'Yaguara', + 'Noventa Vicentina', + 'Bazimini', + 'Donnacona', + 'Sucha Beskidzka', + 'Emirgazi', + 'Mnichovo Hradiste', + 'Karadge', + 'Phulhara', + 'Vanavasi', + 'Gross Kreutz', + 'Ouled Rahou', + 'Sambhu Chak', + 'Bawana', + 'Aviano', + 'Villa Aberastain', + 'Angelopolis', + 'Ben Chicao', + 'Cebazat', + 'Baba Bakala', + 'Natuba', + 'Bhelsi', + 'Jasauli Patti', + 'Dalavaypattanam', + 'West Donegal', + 'Haledon', + 'Attnang-Puchheim', + 'Sene', + 'Indian Harbour Beach', + 'Czarna Bialostocka', + 'Yasenivskyi', + 'Acucena', + 'Chitvel', + 'Nanmucun', + 'Ferryhill', + 'Munagala', + 'Harwood Heights', + 'Colmeia', + 'Plon', + 'Corgao', + 'Bikkatti', + 'Esanai', + 'Malior', + 'Kotabommali', + 'Yellanda', + 'Colorno', + 'Peebles', + 'Broughton Astley', + 'Almoloya del Rio', + 'Viale', + 'Tshabong', + 'Bad Lauchstadt', + 'Borio', + 'Ramgarha', + 'Belma', + 'Juncos', + 'Montagnana', + 'Ban Nikhom Phatthana', + 'Caputira', + 'Sampgaon', + 'Kafr Sajnah', + 'Khagaur', + 'Ladue', + 'Beaver Falls', + 'Chinna Kalaiyamputtur', + 'Bestensee', + 'Glastonbury', + "Monteforte d'Alpone", + 'Thap Than', + 'Seddouk Oufella', + 'Guttikonda', + 'Qashyr', + 'Bni Sidel', + 'La Junta', + 'West Caln', + 'Hurtgenwald', + 'Nunchia', + 'Purcellville', + 'Zhur', + 'Neuhaus am Rennweg', + 'Shahr-e Pir', + 'Floro', + 'Monastyryshche', + 'Horokhiv', + 'Monistrol-sur-Loire', + 'Kovvali', + 'Gouvieux', + 'Balvadi', + 'Castelnuovo Berardenga', + 'Vila Nova de Cerveira', + 'Sai Ngam', + 'Cholavaram', + 'Kara-Bak', + 'Thi Tran Dong Dang', + 'Libonik', + 'Morieres-les-Avignon', + 'Edgewater Park', + 'Ramapattanam', + 'Hope', + 'Chirongui', + 'Zawyat Sidi al Mekki', + 'Terra Nova', + 'Eslohe', + 'Mangalpur Gudaria', + 'Nanguneri', + 'Somero', + 'Khoragachhi', + 'Upper Leacock', + 'Village St. George', + 'Santa Maria del Tule', + 'Bayport', + 'Fair Lakes', + 'Filottrano', + 'Kui Buri', + 'Weilmunster', + 'Barhagarh', + 'Asolo', + 'Penaballi', + 'Kilankundal', + 'Sepolno Krajenskie', + 'Dashouping', + 'Eceabat', + 'Santa Isabel do Ivai', + 'Ingenbohl', + 'Brownfield', + 'Dayr as Sanquriyah', + 'Policka', + 'Periyapodu', + 'Santa Cruz Atizapan', + 'Osicala', + 'Corman Park No. 344', + 'Felling', + 'Great Cornard', + 'Segarai', + 'Litchfield Beach', + 'Basaha', + 'Channubanda', + 'Helsinge', + 'Enkakad', + 'Bhadwar', + 'Nueva Guadalupe', + 'Devnya', + 'Belvedere Marittimo', + 'Makhambet', + 'St. Pete Beach', + 'Lakhanapuram', + 'Rock Falls', + "Palmeira d'Oeste", + 'Argos Orestiko', + 'Potangal', + 'Tullukuttinayakkanur', + 'Florstadt', + 'Le Teil', + 'Caister-on-Sea', + 'Wanaka', + 'Amuria', + 'Yangiobod', + 'Vadasikarambattu', + 'Karor', + 'Sandpoint', + 'Nangis', + 'Orting', + 'Le Portel', + 'San Jose de Gracia', + 'Ibirapua', + 'Punjai Lakkapuram', + 'Kishtwar', + 'Maddur', + 'Matias Cardoso', + 'Bosel', + 'Wabagai', + 'Prienai', + 'Crozet', + 'Tepetitlan', + 'San Marzano di San Giuseppe', + 'Kanhauli', + 'Oststeinbek', + 'Sandiacre', + 'Douar Ait Taleb', + 'Zunilito', + 'Whippany', + 'Napoleon', + 'Tiachiv', + 'Ap Tan Ngai', + 'Shoshong', + 'Allahpur', + 'Tarcento', + 'Tlumach', + 'Holywell', + 'Melpanaikkadu', + 'Bidkhun', + 'Ladan Kara', + 'Chachersk', + 'Francisco Caballero Alvarez', + 'Metsemotlhaba', + 'Partick', + 'Belisce', + 'Tharike', + 'Bargara', + 'North Londonderry', + "L'Epiphanie", + 'Ifield', + 'Rewahi', + 'Carmen de Apicala', + 'Palangavangudi', + 'Halikko', + 'Majhariya Sheikh', + 'Edgemere', + 'Liteni', + 'Oberriet', + 'Polakala', + 'Makaya', + 'Gurmaila', + 'Hallstadt', + 'Silleda', + 'Alwa Tirunagari', + 'Kulpsville', + 'Zuchwil', + 'Khem Karan Saray', + 'Balumath', + 'Nanan', + 'Bhagatpur', + 'Padakanti', + 'Breuillet', + 'Kharsod B', + 'Mosrah', + 'Camenca', + 'Hohenbrunn', + 'Khandrauli', + 'Thief River Falls', + 'Imilchil', + 'Bhataulia', + 'Agadallanka', + 'Minerbio', + 'Pearsall', + 'Tataltepec de Valdes', + 'Quetigny', + 'Ghorbanki', + 'Unterageri', + 'La Fare-les-Oliviers', + 'Irigny', + 'Mallaram', + 'Gangapatnam', + 'Iskourane', + 'Msemrir', + 'Hunduan', + 'Rabo de Peixe', + 'Papara', + 'Schleiz', + 'Kambur', + 'Golakpur', + 'Chiranellur', + 'Cumberland Hill', + 'Ait Ikkou', + 'Ainapur', + 'Katahra', + 'Kanakpur', + 'Teolo', + 'Collingdale', + 'West Perth', + 'Ayapango', + 'Yakakent', + 'Yelsk', + 'Kusterdingen', + 'Mannamangalam', + 'Muriyad', + 'Ponta do Sol', + 'Tasso Fragoso', + 'Kelle', + 'Sorisole', + 'Al Abraq', + 'Pullalacheruvu', + 'Sirikonda', + 'Jogiara', + 'Gondauli', + 'Viagrande', + 'Rocas de Santo Domingo', + 'Striano', + 'Yanchep', + 'Woodmoor', + 'Collier', + 'Le Thor', + 'Achacachi', + "Ak'ordat", + 'Vannikkonendal', + 'Pandino', + 'Bellheim', + 'El Valle', + 'Bellerive-sur-Allier', + 'Ilarionove', + 'Amtala', + 'Sulahpet', + 'East York', + 'Poteau', + 'Gilgit', + 'Kilchberg', + 'Mandalavadi', + 'Sakaddi', + 'Australia', + 'Bersenbruck', + 'Keora', + 'Kadiyadda', + 'Khetko', + 'Ait Ouaoumana', + 'Hlevakha', + 'Landquart', + 'Golbey', + 'Shankarpur', + 'Agadir Melloul', + 'Fontaine-les-Dijon', + 'Malangam', + 'Aradeo', + 'Ban Pong Tao', + 'Jaimalpura', + 'Karariya', + 'Rhymney', + 'Tirumalaippatti', + 'Sewari', + 'Kalkuni', + 'Nimmekal', + 'Casorate Primo', + 'Zoeterwoude', + 'Sabanozu', + 'Volkach', + 'Bansang', + 'Drazinda', + 'Nellutla', + 'Pallippatti', + 'Coffeyville', + 'Caturama', + 'Madnur', + 'Andalusia', + 'Chak Habib', + "Pa'in Chaf", + 'Naunhof', + 'Smizany', + 'Ban Noen Kum Nueng', + 'Ban Muang Kham', + 'Vinjam', + 'Saeby', + 'Finestrat', + 'Madanancheri', + 'Machadodorp', + 'El Realejo', + 'Armazem', + 'Ospina', + 'Steinheim am Albuch', + 'Seneca', + 'Potengi', + 'Pedrinhas', + 'Urania', + 'Sanwas', + 'Moslem Ebn-e `Aqil', + 'Signal Mountain', + 'Campbellton', + 'Al Buwaydah', + 'Cortez', + 'San Juan de la Costa', + 'Dobris', + 'Maysville', + 'Piriapolis', + 'Qizilhacili', + 'Heek', + 'Cumnock', + 'Ablu', + 'Tamganj', + 'Maria Enzersdorf', + 'Kressbronn am Bodensee', + 'Sanatoga', + 'Dardilly', + 'Hamsavaram', + 'Tirano', + 'Con Dao', + 'Memmelsdorf', + 'Gibsonville', + 'Hucclecote', + 'Montmelo', + 'Mahagaon', + 'Reyes', + 'Baia Formosa', + 'Neuenhof', + 'Satwar', + 'Ramgarh', + 'Missaglia', + 'Bouati Mahmoud', + 'Vert-Saint-Denis', + 'Jonnagiri', + 'Chakla Waini', + 'Kodavatipudi', + 'Fort Valley', + 'Amarzgane', + 'Entrerrios', + 'Toppenish', + 'Baciu', + 'Valasa', + 'Hish', + 'Basmanpur', + 'Vadapalanji', + 'Albinea', + 'Adigoppula', + 'Soresina', + 'Takua Pa', + 'Sao Sebastiao do Curral', + 'Upper Makefield', + 'Baramandougou', + 'Yacimiento Rio Turbio', + 'Rangvasa', + 'Ban Si Don Chai', + 'Oak Hills Place', + 'San Martin de Valdeiglesias', + 'Sarlat-la-Caneda', + 'Mansong', + 'Takouta', + 'Hoyo de Manzanares', + 'Parame', + 'Barun', + 'Sorala', + 'Jolfa', + 'Porto Santo Stefano', + 'Mokhotlong', + 'Kampong Tunah Jambu', + 'Boucau', + 'Bolszewo', + 'Checy', + 'Ineu', + 'Hunenberg', + 'Malipakar', + 'Mousoulou', + 'Lusca', + 'Ala', + 'Tagapul-an', + 'Pitman', + 'Rreshen', + 'Lovosice', + 'Iklod', + 'Dhobipet', + 'Ranjal', + 'Bernolakovo', + 'Beni Hassane', + 'Angor', + 'Tausa', + 'Obernburg am Main', + 'Tillaivilagam', + 'North Haledon', + 'G`ozg`on', + 'Taragi', + "Vel'ke Kapusany", + 'La Ferte-Bernard', + 'Dunavarsany', + 'Pittsgrove', + 'London Grove', + 'Ulstein', + 'Cristuru Secuiesc', + 'Rouvroy', + 'Penugolanu', + 'Vanduvancheri', + 'Bommayapalaiyam', + 'Uta', + 'Santa Maria Xadani', + 'Maisaram', + 'Ballenstedt', + 'Baikunthapur', + 'Ntossoni', + 'Strijen', + 'Hateg', + 'Lichtervelde', + 'Entraigues-sur-la-Sorgue', + 'Chichkah', + 'Abcoude', + 'Rautara', + 'Engerwitzdorf', + 'Lontra', + 'Queven', + 'Jeannette', + 'Kukrahill', + 'Falla', + 'Nagykovacsi', + 'Miyar', + 'Hassi Berkane', + 'Kryzhopil', + 'Brimington', + 'Varatanapalli', + 'Gholia Kalan', + 'Porcari', + 'Treze Tilias', + 'El Outaya', + 'Karis', + 'Tlagasana', + 'Soeda', + 'Toulou', + 'Sowan', + 'La Loggia', + 'Ban Sai Yoi', + 'Koekelare', + 'Dharawat', + 'Schuylkill', + 'Cofimvaba', + 'Lienen', + 'Costa Volpino', + 'Sodankyla', + 'Essey-les-Nancy', + 'Belsh', + 'Chahana', + 'Garsekurti', + 'Bhasaula Danapur', + 'Boonton', + 'Saidia', + 'Cherry Hinton', + 'Annan', + 'Nueva Ocotepeque', + 'Kampel', + 'Waldenbuch', + 'Bachchannapet', + 'Yelandur', + 'Kunimedu', + 'Moe', + 'Garching an der Alz', + 'La Mujer', + 'Bundehra', + 'Barth', + 'Monforte del Cid', + 'Cinderford', + 'Adiyakkamangalam', + 'Komijan', + 'Clanton', + 'Nea Michaniona', + 'Deodora', + 'Aliartos', + 'Somarasampettai', + 'Kusumbe', + 'Mahopac', + 'Tiqqi', + 'Pereiras', + 'Efringen-Kirchen', + 'Poisy', + 'Gessate', + 'Meadow Lakes', + 'Amberomanga', + 'Brevik', + 'Luzzi', + 'Presque Isle', + 'Paratdiha', + 'Bee Cave', + 'Coaldale', + 'Muturkha', + 'Cunupia', + 'Vicentinopolis', + 'Kirrayach', + 'Chartiers', + 'Taskent', + 'Hirni', + 'Chinna Mupparam', + 'Boukhralfa', + 'Sriramapuram', + 'Aragona', + 'Pizzo', + 'Grossenluder', + 'Idupugallu', + 'Spring Valley Lake', + 'Bertrix', + 'Rampatti', + 'Vidapanakallu', + 'Ashtian', + 'Marrupa', + 'Zapatoca', + 'Abiramam', + 'Otaki', + 'Perry Heights', + 'Mascoutah', + 'Borgentreich', + 'Cockermouth', + 'Borgo a Buggiano', + 'Galela', + 'Zulakallu', + 'Pukkulam', + 'Kibaya', + 'Fully', + 'Pa Mok', + 'Ottobeuren', + 'Saint-Paul-Trois-Chateaux', + 'Rani Sawargaon', + 'San Pedro de Coche', + 'Riacho dos Machados', + 'Hombrechtikon', + 'Pacuarito', + 'Vohburg an der Donau', + 'Aulnoye-Aymeries', + 'Crest', + 'Hiramandalam', + 'Damal', + 'Budamangalam', + 'Stony Brook University', + 'Natividade', + 'Lachen', + 'Angichettippalaiyam', + 'Habo', + 'Daping', + 'Banak', + 'San Juan Ixcaquixtla', + 'Lenox', + 'Pasivedalajimma', + 'Sremski Karlovci', + 'Tilvalli', + "Sant'Angelo in Lizzola", + 'Mozzate', + 'Coccaglio', + 'Shopokov', + 'Bouhlou', + 'Afumati', + 'Sanrha', + 'Castagneto Carducci', + 'Civitella in Val di Chiana', + 'Summit View', + 'Rudewa', + 'Sonsbeck', + 'Roccastrada', + 'Wervershoof', + 'Tanudan', + 'Stary Sacz', + 'Lamarao', + 'Jabera', + 'Ranod', + 'Leopoldo de Bulhoes', + 'Kanavaypudur', + 'Rahta', + 'Hoshoot', + 'Koror', + 'Uzundere', + 'Biederitz', + 'Notre-Dame-de-Gravenchon', + 'Murillo', + 'Teranikallu', + 'Dhanauli', + 'Nam Som', + 'Rio Jimenez', + 'Wingles', + 'Pullanvidudi', + 'Vadakadu', + 'Hoquiam', + 'Corona de Tucson', + 'Comendador Levy Gasparian', + 'Perigny', + 'Saint-Jean-de-Monts', + 'Hakka', + 'Pedda Nindrakolanu', + 'Parabita', + 'Doornkop', + 'Lichana', + 'Rudravaram', + 'Hollymead', + 'Krompachy', + 'Sanjat', + 'Queimada Nova', + 'Harsova', + 'Messkirch', + 'Malaimarpuram', + 'Mirchpur', + 'Aktepe', + 'Wattwil', + 'Bussy', + 'Rauenberg', + 'Moranbah', + 'Igana', + 'Bhui', + 'Ekangar Sarai', + 'Velakalnattam', + 'Bharno', + 'Ellicott', + 'Gundumal', + 'Folignano', + 'Karuveppampatti', + 'Satgachia', + 'Hostotipaquillo', + 'Bad Bergzabern', + 'Lowenberg', + 'Jalalkhera', + 'Maiquinique', + 'Herzberg', + 'Obertraubling', + 'Lillebonne', + 'Nagaiyampatti', + 'San Juan de Arama', + 'Cabras', + 'Carlosama', + 'Roetgen', + 'Saint-Claude', + 'Tsrar Sharif', + 'Pendekallu', + 'Galmaarden', + 'Narona', + 'Montalto di Castro', + 'Port Jervis', + 'Gendou', + 'Stara Tura', + 'Buved', + 'Ragampet', + 'Pont-Rouge', + 'Guneysu', + 'Pillutla', + 'Siggiewi', + 'Cutrofiano', + 'Hualaihue', + 'Virapalle', + 'Aransas Pass', + 'Onnaing', + "La Chapelle d'Armentieres", + 'Navappatti', + 'South Londonderry', + 'Ustrzyki Dolne', + 'Punnappatti', + 'Ponte Buggianese', + 'Santanopolis', + 'Margny-les-Compiegne', + 'Iaboutene', + 'Akalgarh', + 'Angallu', + 'Barbana', + 'Bommagondanahalli', + 'Sarbisheh', + 'Inekar', + 'Azizpur Chande', + 'Tomesti', + 'Velaux', + 'Uchen', + 'Chanute', + 'Talsi', + 'Gigmoto', + 'Al Quway`iyah', + 'Ouando', + 'Besozzo', + 'Hamlin', + 'Kolbuszowa', + 'Sohta', + 'Doiwala', + 'Sao Jose do Cerrito', + 'Chocen', + 'Gangajalghati', + 'Blanchard', + 'Anthony', + 'Summit Park', + 'Nanzhangcheng', + 'Dunn Loring', + 'Tleta Taghramt', + 'Gyumai', + 'Bhanuvalli', + 'Roccapiemonte', + 'Champlain', + 'Sidi el Mokhfi', + 'Lazaro Cardenas', + 'Janglot', + 'Sidi Dahbi', + 'Havsa', + 'Asagi Quscu', + 'Iles', + 'Richterich', + 'Lake Villa', + 'Bududa', + 'Jondor Shaharchasi', + 'Tashir', + 'Siklos', + 'Sini', + 'Volodymyrets', + 'Pardanjan', + 'Innsbrook', + 'Zawiat Moulay Brahim', + 'Koppunur', + 'Vadacheri', + 'Raia', + 'Pulivalam', + 'Flero', + 'Caprino Veronese', + 'Coaticook', + 'Marcy', + 'Phimai', + 'Simon Bolivar', + 'Tonk Khurd', + 'Karadipara', + 'Roverbella', + 'Stauceni', + 'Pokhraira', + 'Pappakudi', + 'Torre Boldone', + 'Cullinan', + 'Malov', + 'Nattarasankottai', + 'Solebury', + 'Mirdoddi', + 'Conthey', + 'Wietze', + 'Sao Pedro do Ivai', + 'Ergoldsbach', + 'Goworowo', + 'Binfield', + 'Dharhwa', + 'Heikendorf', + 'Le Petit-Couronne', + 'Gadaul', + 'Katridih', + 'Painkulam', + 'Koshanam', + 'Lequile', + "Limeira d'Oeste", + 'Newstead', + 'Stainz', + 'Titz', + 'Zanica', + 'Aigues-Mortes', + 'Azandarian', + 'Duchcov', + 'Monte Escobedo', + 'Murajpur', + 'Bagalvad', + 'Gobindpur', + 'Savoy', + 'Cheviot', + 'Kaldsletta', + 'Katuete', + 'Tordesillas', + 'Kambhampadu', + 'Hillview', + 'Pyalakurti', + 'Kursaha', + 'Brandizzo', + 'Sangaree', + 'Embrun', + 'Camliyayla', + 'Suttamalli', + 'Kottur', + 'Pibrac', + 'Aratuipe', + 'Marilandia do Sul', + 'Tilaran', + 'Chetma', + 'Chakand', + 'Guntapalli', + 'Castellabate', + 'Glodeni', + 'Longvic', + 'Teotitlan', + 'River Road', + 'Catuipe', + 'Kilcock', + 'Briceno', + 'Flieden', + 'Roquevaire', + 'Herseh Chhina', + 'Bhatkhori', + 'Parasbani', + 'Triuggio', + 'Ter Apel', + 'Al Qardahah', + 'Maraveh Tappeh', + 'Minto', + 'Malhada de Pedras', + 'Montlhery', + 'Atherstone', + 'Olmsted Falls', + 'Chelmek', + 'Norten-Hardenberg', + 'Coutras', + 'Owani', + 'Wharton', + 'Heartland', + 'Avabodji', + 'Passo do Sertao', + 'Altavilla Milicia', + 'North Cornwall', + 'Baxter', + 'Meine', + 'Domerat', + 'Amiawar', + 'Fort Mitchell', + 'Yang Talat', + 'Jujharpur', + 'Mustafabad', + 'Rodeiro', + "L'Ile-Saint-Denis", + 'Pathraha', + 'San Sebastiano al Vesuvio', + 'Perryton', + 'Lempdes', + 'Ohata', + 'Hirson', + 'Harike', + 'Benner', + 'Gillitts', + 'Koscielisko', + 'Chintakommadinne', + 'Barvynkove', + 'Paula Candido', + 'Chyhyryn', + 'Nagdah', + 'Clarendon Hills', + 'Abu Hardub', + 'Demirozu', + 'Aars', + 'Tumberi', + 'Dilawarpur', + 'Karavan', + 'Najrij', + 'Zabok', + 'Belhatti', + 'Ballina', + 'Tirschenreuth', + 'Fort Knox', + 'Campos Lindos', + 'Eduttavaynattam', + 'Bikrampur Bande', + 'Park Hills', + 'Ankatafa', + 'Sokyriany', + 'Chak Pahar', + 'Village Green-Green Ridge', + 'Highland Heights', + 'Deutsch-Wagram', + 'Untergruppenbach', + 'Logten', + 'Bedum', + 'Farob', + 'Seosaeng', + 'Le Loroux-Bottereau', + 'Isbergues', + 'Vodice', + 'Lihue', + 'Tudela de Duero', + 'Thathupur', + 'Vanukuru', + 'Kottadindulu', + "Sint-Job-in-'t-Goor", + 'Halawah', + 'Ouda-daito', + 'Gulf Hills', + 'Timmendorfer Strand', + 'Bishamagiri', + 'Pa Sang', + 'Redlynch', + 'Artigues-pres-Bordeaux', + 'Dirusumarru', + 'Serramazzoni', + 'Dobele', + 'Nansio', + 'Nandnawan', + 'Bovalino Marina', + 'Guntersville', + 'Solleftea', + 'Saint-Chamas', + 'Chamonix-Mont-Blanc', + 'San Bartolome Milpas Altas', + 'Lint', + 'Vergiate', + 'Buckie', + "Sant'Agnello", + 'Budenheim', + 'Sobhapur', + 'Anyksciai', + 'Rakitovo', + 'Kaoni', + 'Mahadipur', + 'Lourosa', + 'Niederwerrn', + 'Bisaul', + 'Panfilovka', + 'La Peche', + "'s-Heerenberg", + 'Bouaiche', + 'Chapel en le Frith', + 'Pinjranwan', + 'Digar', + 'Beibu', + 'Solotvyno', + 'Zuera', + 'Rangwasa', + 'Manteno', + 'Wiang Haeng', + 'Slateng Dua', + 'Parsad', + 'Tokatippa', + 'Long Hill', + 'Pantelho', + 'Ulatu', + 'Gokhulapur', + 'Belo Vale', + 'Monte Alegre do Sul', + 'Kilakkurichchi', + 'Kattirippulam', + 'Rajhanpur', + 'Cradock', + 'Chop', + 'Le Poire-sur-Vie', + 'Sa`idi', + 'East Donegal', + 'Vyetka', + 'Midalam', + 'Khandauli', + 'Shahrak-e Pars', + 'Sredets', + 'Garesnica', + 'Fort Riley', + 'Beutelsbach', + 'Basrur', + 'Mannegudam', + 'Chettiyapatti', + 'Nierstein', + 'Stansted Mountfitchet', + 'Hakubacho', + 'Ouro Verde', + 'Canford Cliffs', + 'Segaon', + 'Martano', + 'Mechanicstown', + 'Ferreira do Zezere', + 'Tarazu', + 'Panjampatti', + 'Hathiakan', + 'Trissino', + 'Buda-Kashalyova', + 'Raiparthi', + 'Hire Vadvatti', + 'Soverato Marina', + 'Moribila', + 'Tibro', + 'Magam', + 'Saidabad', + 'Chanp', + 'Petilia Policastro', + 'Templeton', + 'Arealva', + 'Santa Cruz do Monte Castelo', + 'Bremgarten', + 'Manpur', + 'Pirojgarh', + 'Whitwick', + 'Piliscsaba', + 'Barntrup', + 'Vostochnyy', + 'Corbin', + 'Ammanford', + 'New Ross', + 'Antargangi', + 'Tombos', + 'Aurisina', + 'Kappeln', + 'Kharod', + 'Carneys Point', + 'Oulad Khallouf', + 'Teghra', + 'Achchampeta', + 'Narino', + 'Karkkila', + 'Khaur', + 'Skowhegan', + 'Amalou', + 'Pasaul', + 'Jainagar', + 'Silaiyampatti', + 'Kanavaypatti', + 'Bientina', + 'Mudichchur', + 'Shyamnagar', + 'Zaandijk', + 'Nakaseke', + 'Schwarzenbruck', + 'Nefasit', + 'Chamba', + 'Velim', + 'Kennedy', + 'Citrus Hills', + 'Ueckermunde', + 'Hata', + 'Bad Rothenfelde', + 'Mauleon', + 'Seffner', + 'Egg', + 'La Belleza', + 'Peralta', + 'Balakrishnanpatti', + 'Serramanna', + 'Aibonito', + 'Amingaon', + 'Pariyari', + 'Koila', + 'Vrable', + 'Miyada', + 'Zuromin', + 'Dobrada', + 'Haibach', + 'Bryans Road', + 'Monona', + 'Quezalguaque', + 'Kanyakulam', + 'Amudalapalle', + 'Piliv', + 'Rayon', + 'Jalhay', + 'Kennedale', + 'Plabennec', + 'Roussillon', + 'Srirangapur', + 'Merksplas', + 'Anantasagaram', + 'Swissvale', + 'Eden Isle', + 'Gundur', + 'Adalar', + "Rava-Rus'ka", + 'Mareeba', + 'Viechtach', + 'El Ghomri', + 'Vinica', + 'Vif', + 'Tarxien', + 'Lakhzazra', + 'Gidan Ider', + 'Heroldsberg', + 'Thorigne-Fouillard', + 'Jagta', + 'Othello', + 'Gering', + 'Kizilcasar', + 'Dekanme', + 'Monte Porzio Catone', + 'Tamza', + 'Tougouni', + 'Yasinia', + 'Moss Vale', + 'Vicam Pueblo', + 'Liubymivka', + 'Nuevo Paysandu', + 'Sinimbu', + 'Ouled Abbes', + 'Kalaun', + 'Yali', + 'Waltham Cross', + 'Trebisacce', + 'Bandamurlanka', + 'El Espinal', + 'Ahumada', + 'Fallanden', + 'Karpenisi', + 'Kaliganj', + 'Seyyedan', + 'La Grande-Motte', + 'Nunihat', + 'Hale Dyamavvanahalli', + 'Virapperumanallur', + 'Torre de Moncorvo', + 'Steti', + 'Bucksburn', + 'Nettadahalli', + 'Rani Sagar', + 'Masandra', + 'Lalam', + 'Lamesa', + 'Reinosa', + 'Janze', + 'Kirk of Shotts', + 'Charuanwan', + 'Shiddapur', + 'Ban Ratchakrut', + 'Babhangaon', + 'Gamail', + 'Landupdih', + 'Locogahoue', + 'Biberist', + 'Castelnuovo di Porto', + 'Coahuitlan', + 'Semere', + 'Vaucresson', + 'Obersiggenthal', + 'Millis', + 'Anjahamarina', + 'Kamien Pomorski', + 'Na Yung', + 'Youghal', + 'Dharmajigudem', + 'Castel Gandolfo', + 'Oak Island', + 'Navipet', + 'Vicopisano', + 'Shediac', + 'Loenen', + 'Bushtyno', + 'Horice', + 'Poytya', + 'Miduturu', + 'San Pedro Ixtlahuaca', + 'Usiacuri', + 'Sompting', + 'Kings Grant', + 'Reeuwijksebrug', + 'Tanmpegre', + 'Chapalamadugu', + 'Lambarkiyine', + 'Ayotoxco de Guerrero', + 'Nerubaiske', + 'Pedreguer', + 'Raonta', + 'Paloma Creek South', + 'Dougoufe', + 'Brembate', + 'Merrydale', + 'Gretz-Armainvilliers', + 'Buba', + 'Harewa', + 'Lohna', + 'Closter', + 'Takieta', + 'Kodaimangalam', + 'Yaragol', + 'Modachchur', + "Nerk'in Getashen", + 'Ergue-Gaberic', + 'East Leake', + 'Sakhua', + 'Nesarg', + 'Vairichettipalaiyam', + 'Nulvi', + 'Arab', + 'Conewago', + 'Ad Darbasiyah', + 'Staufenberg', + 'Sukand', + 'Troina', + 'Monte San Savino', + 'Dachne', + 'Furstenfeld', + 'Colindres', + 'Iwaizumi', + 'Dunn', + 'Muzo', + 'Tadinada', + 'Tifra', + 'Pata Uppal', + 'West Long Branch', + 'Barton', + 'Hadibu', + 'Imsida', + 'Paszto', + 'Yamkanmardi', + 'Wissen', + 'Siegsdorf', + 'Bad Endorf', + 'Mucheln', + 'Glenwood', + 'Privas', + 'Reddiyapatti', + 'Kolumalapalle', + 'Arizona City', + 'Taftanaz', + 'Bacobampo', + 'Alfonso Castaneda', + 'Santiponce', + 'Zogno', + 'Bifeng', + 'Aglasun', + 'Kandern', + 'Tsallagundla', + 'Puran Bigha', + 'Kandanati', + 'Clusone', + 'Ortuella', + 'Talwandi Chaudhrian', + 'Nangal Chaudhri', + 'Perryville', + 'Chak Thathi', + 'Talakulam', + 'Guria', + 'Ban Charoen Mueang', + 'Meltham', + 'Ban Wat Phrik', + 'Marcolandia', + 'Rottenburg an der Laaber', + 'Bartica', + 'Dattapara', + 'Sulakyurt', + 'Mangala', + 'Poninguinim', + 'Bushkill', + 'Chamusca', + 'Worplesdon', + 'Montecito', + 'Keregodu', + 'Hongtuliang', + 'Montague', + 'Secovce', + 'Nonnweiler', + 'Penkridge', + 'Severance', + 'Malverne', + 'Ararica', + 'Nossa Senhora dos Remedios', + 'Kasap', + 'Phopnar Kalan', + 'Mockmuhl', + 'La Salvetat-Saint-Gilles', + 'Sallisaw', + 'Le Mont-sur-Lausanne', + 'Nijgaon Paranpur', + 'Kosiv', + 'Clayton le Moors', + 'Pokrovka', + 'Lewistown', + 'Lanco', + 'Nawanagar', + "Ra's al Ma`arrah", + 'Qorovul', + 'Woltersdorf', + 'Hundested', + 'Laitila', + 'Cam', + 'Thandewala', + 'Khutha Baijnath', + 'Kandanur', + 'Medikunda', + 'Perenchies', + 'Andanappettai', + 'Delavan', + 'Olamze', + 'Neuenburg', + 'Kond Rud', + 'Poniatowa', + 'Reichelsheim', + 'Moser', + 'Hanko', + 'Oakengates', + 'Schnaittach', + 'Perungulam', + 'Dodvad', + 'Santa Margherita Ligure', + 'Wieruszow', + 'Hathapur', + 'Lycksele', + 'Uedem', + 'Thaon-les-Vosges', + 'Sutherlin', + 'Richland Hills', + 'Carbonita', + 'Sautron', + 'Bedwas', + 'Sagarpur', + 'Darsur', + 'Whitehouse', + 'Hueyotlipan', + 'Takaharu', + 'Kuchai Kot', + 'Boshof', + 'West Auckland', + 'El Dovio', + 'Mandalapalle', + 'Pachrukhi', + 'Repala', + 'Tionk Essil', + 'Zhujiagua', + 'Liffre', + 'Pedda Penki', + 'Orsova', + 'Biloziria', + 'Nottampatti', + 'Old Forge', + 'Liesti', + 'Carlton Colville', + 'Hausjarvi', + 'Kalloni', + 'Campogalliano', + "Rignano sull'Arno", + 'West Earl', + 'Dobanovci', + 'Staufen im Breisgau', + 'Saint-Vallier', + 'Nalikkalpatti', + 'Chinaur', + 'Munnelli', + 'Nalas', + 'Tarichar Kalan', + 'Setana', + 'Saruu', + 'Rakai', + 'Chapaev', + 'Basarabeasca', + 'Namsos', + 'Joniskis', + 'Orocue', + 'Zardab', + 'As Sallum', + 'Gramsh', + 'Bulaevo', + 'Stans', + 'Gadzin Han', + 'Gunnedah', + 'Kaisiadorys', + 'Golubac', + 'Pazin', + 'Cowra', + 'Moengo', + 'Slovenska Bistrica', + 'Rubirizi', + 'Pampa del Infierno', + 'Tweed Heads', + 'Naujoji Akmene', + 'Shar', + 'Kocevje', + 'Kone', + 'Gleno', + 'Putina', + 'Paide', + 'Aguelhok', + 'Hammerfest', + 'Beocin', + 'Qusmuryn', + 'Osakarovka', + 'Varena', + 'Charters Towers', + 'Montpelier', + 'Gzira', + 'Kontcha', + 'Oldeani', + 'Nisporeni', + 'Sokobanja', + 'Ciudad Cortes', + 'Greymouth', + 'Katoomba', + 'Amapa', + 'Sharbaqty', + 'Port Maria', + 'Alebtong', + 'Monaghan', + 'Auki', + 'Dilolo', + 'Sembabule', + "Ch'osan-up", + 'Bentiu', + 'Ertis', + 'Iqaluit', + 'Luba', + 'Kalabo', + 'Grosuplje', + 'Qazaly', + 'Bayghanin', + 'Lascano', + 'Heyin', + 'Ludza', + 'Yeghegnadzor', + 'Yardimli', + 'Mtskheta', + 'Kibale', + 'Jacareacanga', + 'Bairnsdale', + 'San Pablo Villa de Mitla', + 'Castillos', + 'Kemijarvi', + 'Kelme', + 'Sen Monorom', + 'Gaoual', + 'Zhanibek', + 'Backi Petrovac', + 'Leova', + 'Leeton', + 'Coracora', + 'Kirkwall', + 'Goranboy', + 'Adazi', + 'Nangan', + 'Aiquile', + 'Ravne na Koroskem', + 'Luan Chau', + 'Aracinovo', + 'Briceni', + 'Lerik', + 'Thames', + 'Puerto Baquerizo Moreno', + 'Bossembele', + 'Kicevo', + 'Mongomo', + 'Slovenj Gradec', + 'Tranqueras', + 'Telenesti', + 'Bestobe', + 'Obo', + 'Mobaye', + 'Tobyl', + 'Lapovo', + 'Ruyigi', + 'Dowa', + 'Novoberde', + 'Donduseni', + 'Debe', + 'Stefan Voda', + 'Zambezi', + 'Moree', + 'Diekirch', + 'In Guezzam', + 'Wick', + 'Thyolo', + 'Rabaul', + 'Oguz', + 'Kapoeta', + 'Kraslava', + 'Kerikeri', + 'Novi Knezevac', + 'Kieta', + 'Aizkraukle', + 'Bongaree', + 'Nicoadala', + 'Librazhd', + 'Santa Venera', + 'Hola', + 'Livani', + 'Kiruhura', + 'Kiama', + 'Lerwick', + 'Zholymbet', + 'Borgo Maggiore', + 'Obiliq', + 'Brezice', + 'Ajdovscina', + 'Salcininkai', + 'Forbes', + 'Nata', + 'Gulbene', + 'Charagua', + 'Kishkenekol', + 'Magugpo Poblacion', + 'Criuleni', + 'Limbazi', + 'Litija', + 'Madona', + 'Carnarvon', + 'Awjilah', + 'Port Augusta', + 'Mazoe', + 'Ros Comain', + 'Kerema', + 'Northam', + 'Cliza', + 'Mae Hong Son', + 'Bogatic', + 'Oficina Maria Elena', + 'Ingeniero Guillermo N. Juarez', + 'Cooma', + "Port Saint John's", + 'Ndende', + 'Zouar', + 'Deniliquin', + 'Pasvalys', + 'Melut', + 'Comandante Luis Piedra Buena', + 'Siteki', + 'Medveda', + 'Sal Rei', + 'Dalaba', + 'Yeppoon', + 'Lorengau', + 'Derzhavinsk', + 'Omaruru', + 'Vanrhynsdorp', + 'Aluksne', + 'Punakha', + 'Ingeniero Jacobacci', + 'Bir Anzarane', + 'Jakar', + 'Phalombe', + 'Queanbeyan', + 'Tumut', + 'Kavadarci', + 'Palikir', + 'Moss', + 'Ub', + 'Kupiskis', + 'Espargos', + 'Gizo', + 'Veintiocho de Noviembre', + 'Menges', + 'Bac', + 'Junik', + 'Viqueque', + 'Yamba', + 'Kolonia', + 'Alausi', + 'Cabrayil', + 'Dinguiraye', + 'Sezana', + 'Funafuti', + 'Zagorje', + 'Chepes', + 'Lucea', + 'Maltahohe', + 'Mitoma', + 'Gyangze', + 'Schaan', + 'Glarus', + 'Radovljica', + 'Preili', + 'Luqa', + 'Permet', + 'Zarasai', + 'Trakai', + 'Soldanesti', + 'Echternach', + 'Kaitaia', + 'Rutana', + 'Berovo', + 'Idrija', + 'Sirvintos', + 'Ranillug', + 'Lobamba', + 'Aiyomojok', + 'Moletai', + 'Biloela', + 'Piggs Peak', + 'Appenzell', + 'Uncia', + 'Xocavand', + 'Vaduz', + 'Masunga', + 'Cacheu', + 'Balvi', + 'Nieuw Amsterdam', + 'Chonchi', + 'Stawell', + 'Hermanus', + 'Babak', + 'Sisimiut', + 'Muisne', + 'Vossevangen', + 'Fort-Shevchenko', + 'Mwatate', + 'Polva', + 'Eenhana', + 'Byron Bay', + 'Mamushe', + 'Kazlu Ruda', + 'Namanga', + 'Narrabri', + 'Crnomelj', + 'General Conesa', + 'Petnjica', + 'San Antonio de los Cobres', + 'Mali Idos', + 'Muramvya', + 'Sakiai', + 'Goondiwindi', + 'Ouadda', + 'Wiltz', + 'Thaba-Tseka', + 'Kratovo', + 'Kovacica', + 'Cospicua', + 'Saint-Pierre', + 'Cobram', + 'Medvode', + 'Witu', + 'San Matias', + 'Rapla', + 'Skuodas', + 'Bajram Curri', + 'Hohenau', + 'Napak', + 'Torghay', + 'Triesen', + 'Albina', + 'Otavi', + 'Thinadhoo', + 'Jogeva', + 'Mayumba', + 'Kalangala', + 'Jinzhong', + 'Canillo', + 'Slovenske Konjice', + 'Danilovgrad', + 'Liquica', + 'Karibib', + 'Smiltene', + 'Rogaska Slatina', + 'Roatan', + 'Kekava', + 'McMinns Lagoon', + 'Scone', + 'Zalec', + 'Puerto Casado', + 'Singleton', + 'Qasr al Farafirah', + 'Ignalina', + 'Grevenmacher', + 'Samtse', + 'Gevgelija', + 'Wonthaggi', + 'Hrastnik', + 'Sembe', + 'Lithgow', + 'Valdez', + 'Sentjur', + 'Bled', + 'Mitzic', + 'Vadso', + 'Mekambo', + 'Xaghra', + 'Vrapciste', + 'Ordino', + 'Irig', + 'Bolama', + 'Albury', + 'Brownsweg', + 'Tuzi', + 'Carrick on Shannon', + 'Ilulissat', + 'Halba', + 'Ghaxaq', + 'Fderik', + 'Coka', + 'Silale', + 'Svolvaer', + 'Komatipoort', + 'Radovis', + 'Klaksvik', + 'Finnsnes', + 'Balzers', + 'Bongandanga', + 'Prevalje', + 'Perito Moreno', + 'Outapi', + 'Valka', + 'Opovo', + 'Otar', + 'Sevnica', + 'Kununurra', + 'Nadur', + 'Fuerte Olimpo', + 'Gobernador Gregores', + 'Bueng Kan', + 'Pakruojis', + 'Svencionys', + 'Bururi', + 'Al Qasr', + 'Eschen', + 'Victorica', + 'Qivraq', + 'Mauren', + 'Marsa', + 'Karasburg', + 'Samaipata', + 'Saryshaghan', + 'Tepelene', + 'Ingham', + 'Ilirska Bistrica', + "Saint George's", + 'Dehiba', + 'Nwoya', + 'Bekily', + 'Comandante Fontana', + 'Narrogin', + 'Black River', + 'Kuala Belait', + 'Victor Harbor', + 'I-n-Amguel', + 'Manjimup', + 'Calheta de Sao Miguel', + 'Krusevo', + 'Naifaru', + 'Bensonville', + 'Berri', + 'Port Hedland', + 'Las Lajas', + 'Wabag', + 'Corovode', + 'Kalvarija', + 'Pieta', + 'Cerknica', + 'Remich', + 'El Maiten', + 'Avarua', + 'Manica', + 'Aliwal North', + 'Balzan', + 'Robertsport', + 'Karmah an Nuzul', + 'Trebnje', + 'Trzin', + 'Oranjemund', + 'Bethanie', + 'Bir Mogrein', + 'Lazdijai', + 'Butalangu', + 'Neiafu', + "P'ungsan", + 'Plandiste', + 'Sicasica', + 'Vergara', + 'Miklavz na Dravskem Polju', + 'Decan', + 'Omuthiya', + 'Piran', + 'Agdam', + 'Teseney', + 'Erseke', + 'Ulaan-Uul', + 'Grand Turk', + 'Lavumisa', + 'Sempeter pri Gorici', + 'Massenya', + 'Trzic', + 'Ziri', + 'Makedonski Brod', + 'Katanning', + 'Imgarr', + 'Cankuzo', + 'Tessalit', + 'Ribnica', + 'Dingli', + 'Puke', + 'Sao Joao dos Angolares', + 'Mojkovac', + 'Janjanbureh', + 'Lismore', + 'Villa Ygatimi', + 'Domagnano', + 'Merimbula', + 'Marsaxlokk', + 'Kirkenes', + 'Tolmin', + 'Ceduna', + 'Port Douglas', + 'Mongar', + 'Ligonha', + 'Kirakira', + 'La Paloma', + 'Wallaroo', + 'Proserpine', + 'Uspallata', + 'Alibunar', + 'Cantemir', + 'Darregueira', + 'Kaberamaido', + 'Malisheve', + 'Trancas', + 'Lukulu', + 'Fish Town', + 'Clare', + 'Turangi', + 'Imqabba', + 'Xewkija', + 'Weipa', + 'Lasko', + 'Pofadder', + 'Lenart v Slovenskih Goricah', + 'Smithton', + 'Demir Kapija', + 'The Valley', + 'Rietavas', + 'Ljutomer', + 'Jurado', + 'Domzale', + 'Metlika', + 'Rorvik', + 'Ankaran', + 'Brezovica', + 'Ghajnsielem', + 'Sinnamary', + 'Mezica', + 'Evinayong', + 'Brandfort', + 'Ocnita', + 'Kudahuvadhoo', + 'Saulkrasti', + 'Iklin', + 'Sencur', + 'Golubovci', + 'Birstonas', + 'Dravograd', + 'Gornja Radgona', + 'Ainaro', + 'Lija', + 'Zelezniki', + 'Aasiaat', + 'Mopipi', + 'Porto Ingles', + 'Arroyos y Esteros', + 'Qaqortoq', + 'Tearce', + 'Trashigang', + 'Ulbroka', + 'Skofljica', + 'Abai', + 'Taoudenni', + 'Kardla', + 'Kalkara', + 'Tifariti', + 'Mahibadhoo', + 'Lethem', + 'Gudja', + 'Al Jaghbub', + 'Lendava', + 'Bogdanci', + 'Rogasovci', + 'Sostanj', + 'Zrece', + 'Sowa Town', + 'Bopolu', + 'Zitiste', + 'Hokitika', + 'Nautla', + 'Tom Price', + 'Radlje ob Dravi', + 'Bordertown', + 'Villalonga', + 'Viligili', + 'Mangbwalu', + 'Buala', + 'Rio Mayo', + 'Senglea', + 'Gharghur', + 'Qrendi', + 'Kerewan', + 'Hlatikulu', + 'Longreach', + 'Trashi Yangtse', + 'Barclayville', + 'Kolasin', + 'Urubamba', + 'Trongsa', + 'Race', + 'Borovnica', + 'Eydhafushi', + 'Triesenberg', + 'Vittoriosa', + 'Isafjordhur', + 'Donegal', + 'Saudharkrokur', + 'Tofol', + 'Cestos City', + 'Imtarfa', + 'Mkokotoni', + 'Chumbicha', + 'Kllokot', + 'Rosoman', + 'Charleville', + 'Fiorentino', + 'Baltasar Brum', + 'Cloncurry', + 'Nauta', + 'Mariscal Jose Felix Estigarribia', + 'Capitol Hill', + 'Brokopondo', + 'Vojnik', + 'Aigua', + 'Tarabuco', + 'Quime', + 'Demir Hisar', + 'Beltinci', + 'Al `Alamayn', + 'Hofn', + 'Jaque', + 'Nida', + 'Merredin', + 'Karungu', + 'Vevcani', + 'Polzela', + 'Bloemhof', + 'Sohano', + 'Zhemgang', + 'Boffa', + 'Egilsstadhir', + 'Coroico', + 'Krsko', + 'Gustavia', + 'Ypejhu', + 'Ruggell', + 'Tolten', + 'Muta', + 'Sveta Ana', + 'Qala', + 'Lehututu', + 'Sahbuz', + 'Store', + 'Te Anau', + 'Ig', + 'Maradah', + 'Roura', + 'Onverwacht', + 'Gradsko', + 'Desaguadero', + 'Sorata', + 'Mwenga', + 'El Manteco', + 'Kaikoura', + 'Floriana', + 'Ivancna Gorica', + 'Jose Batlle y Ordonez', + 'Crna na Koroskem', + 'Puerto Villamil', + 'Kirkop', + 'Lacin', + 'Radenci', + 'Vianden', + 'Totness', + 'Cidade Velha', + 'Acquaviva', + 'Pozo Colorado', + 'Baures', + 'Apolo', + 'Sannat', + 'Spodnje Hoce', + 'Funadhoo', + 'Vipava', + 'Esperance', + 'Pivka', + 'Omboue', + 'Mozirje', + 'Manadhoo', + 'Pukekohe East', + 'Waitakere', + 'Waitangi', + 'Semic', + 'Ambrolauri', + 'Damongo', + 'Konza', + 'Altata', + 'Heydarabad', + 'Djibloho', + 'Sofifi', + 'Afega', + 'Radece', + 'Valandovo', + 'Lovrenc na Pohorju', + 'Capellen', + 'Tasiilaq', + 'Ormoz', + 'Borgarnes', + 'Katwe', + 'Straza', + 'Kercem', + 'Zabljak', + 'Abuna', + 'Amudat', + 'Philipsburg', + 'Taedong', + 'Krivogastani', + 'Mislinja', + 'Balakan', + "Ta' Xbiex", + 'Naklo', + 'Bohinjska Bistrica', + 'Nokaneng', + 'Smarje', + 'Longyearbyen', + 'Nasir', + 'Partesh', + 'Divaca', + 'Xghajra', + 'Cerklje na Gorenjskem', + 'Varaklani', + 'Spodnji Duplek', + 'Pehcevo', + 'Ropazi', + 'Gusinje', + 'Gamprin', + 'Parun', + 'Puerto Williams', + 'Cuevo', + 'Capitan Pablo Lagerenza', + 'Odranci', + 'Lifford', + 'Prebold', + 'Flying Fish Cove', + 'Zgornja Kungota', + 'Xizi', + 'Bovec', + 'Plasnica', + 'Chiradzulu', + 'Alto Rio Senguer', + 'Sierra Colorada', + 'Rogatec', + 'Gharb', + 'Iracoubo', + 'Bourke', + 'Zrnovci', + 'Kipili', + 'Ungoofaaru', + 'Vuzenica', + 'Tumby Bay', + 'Turnisce', + 'Miren', + 'Chibemba', + 'Alexander Bay', + 'Halls Creek', + 'Tajarhi', + 'Nova Crnja', + 'Lokwabe', + 'Clervaux', + 'Dragomer', + 'Munxar', + 'Kranjska Gora', + 'Sentjernej', + 'Cerkno', + 'Oplotnica', + 'Machinga', + 'Port Denison', + 'Tsau', + 'Uummannaq', + 'Xocali', + 'Smartno', + 'Penola', + 'Mirna', + 'Selnica ob Dravi', + 'Kingston South East', + 'Nyimba', + 'Veymandoo', + 'Lubutu', + 'Wagin', + 'Fulacunda', + 'Paamiut', + 'Bala Cangamba', + 'Tarutung', + 'Novaci', + 'Bosilovo', + 'Safotu', + 'Kalbarri', + 'Villa Rumipal', + 'Dornava', + 'Mogila', + 'Kidricevo', + 'Katherine', + 'Mabaruma', + 'Tulagi', + 'Novo Selo', + 'Barcaldine', + 'Villa Martin Colchak', + 'Ubombo', + 'Regedor Quissico', + 'Celeken', + 'Isangel', + 'Buluko', + 'Leulumoega', + 'Faetano', + 'Horjul', + 'Crensovci', + 'Daga', + 'Los Blancos', + 'Kanal', + 'Asau', + 'Gorenja Vas', + 'Puerto Acosta', + 'Mirbat', + 'Nacunday', + 'Poljcane', + 'Uad Damran', + 'Pluzine', + 'Ljubno', + 'Susques', + 'Upernavik', + 'Schellenberg', + 'Innisfail', + 'Kobarid', + 'Qasigiannguit', + 'Benedikt', + 'Mazatan', + 'Hagta', + 'Fulin', + 'Andrijevica', + 'Mata-Utu', + 'Ouyen', + 'Gornji Grad', + 'Mirna Pec', + 'Hughenden', + 'Haya', + 'Cowell', + 'Yelimane', + 'Sredisce ob Dravi', + 'General Eugenio A. Garay', + 'Montegiardino', + 'Streaky Bay', + 'Moravce', + 'Principe da Beira', + 'Lufilufi', + 'Dobrovnik', + 'Daraj', + 'Dobrova', + 'Konce', + 'Shamva', + 'Laverton', + 'Verzej', + 'Komenda', + 'Dolenjske Toplice', + 'Nazarje', + 'Rostusa', + 'Hoskins', + 'Velika Polana', + 'Luanza', + 'Meningie', + 'Vitanje', + 'Gorisnica', + 'Yulara', + 'Gingin', + 'Jegunovce', + 'Ozurgeti', + 'Pesnica', + 'Sodrazica', + 'Godhavn', + 'Stari Trg', + 'Preddvor', + 'Vatican City', + 'Charana', + 'Onslow', + 'Zgornja Hajdina', + 'Bicheno', + 'Vailoa', + 'Starse', + 'Muhembo', + 'Sveta Trojica v Slovenskih Goricah', + 'Moravske-Toplice', + 'San Lawrenz', + 'Yaren', + 'Rankovce', + 'Comallo', + 'Velike Lasce', + 'Hvalba', + 'Satadougou', + 'Lakatoro', + 'Mokronog', + 'Roebourne', + 'Zhaltyr', + 'Sopiste', + 'Kostanjevica na Krki', + 'Pannawonica', + 'Linxi', + 'Ituni', + 'Meekatharra', + 'Oblesevo', + 'Qubadli', + 'Leonora', + 'Massangena', + 'Gawler', + 'Qaanaaq', + 'Komen', + 'Kozje', + 'Puconci', + 'Vasilevo', + 'Grad', + 'Nkurenkuru', + 'Tigoa', + "Villa O'Higgins", + 'Kimba', + 'Majsperk', + 'Dibaya', + 'Panda', + 'Gastre', + 'Saleaula', + 'Kalbacar', + 'Alofi', + 'Quilpie', + 'Videm', + 'Podcetrtek', + 'Karbinci', + 'Sabaya', + 'Oatlands', + 'Zgornje Jezersko', + 'Chiramba', + 'Norseman', + 'Lata', + 'Llica', + 'Mereeg', + 'Telsen', + 'Apace', + 'Kobilje', + 'Wilcannia', + 'Dobrna', + 'Zgornje Gorje', + 'Calenga', + 'Southern Cross', + 'Lozovo', + 'Recica', + 'Caluula', + 'Tournavista', + 'Felidhoo', + 'Tmassah', + 'Puerto Pinasco', + 'Tchitado', + 'Yakossi', + 'Markovci', + 'Staro Nagoricane', + 'Smarjeske Toplice', + 'Karumba', + 'Planken', + 'Kempsey', + 'Mount Magnet', + 'Vreed-en-Hoop', + 'The Bottom', + 'Kullorsuaq', + 'Cirkulane', + 'Videm pri Ptuju', + 'Woomera', + 'Brvenica', + 'Dhuusamarreeb', + 'Skopun', + 'Morawa', + 'Lukovica', + 'Theodore', + 'Crna Trava', + 'Kuzma', + 'Eidsvold', + 'Ghasri', + 'Buabidi', + 'Montes Claros', + 'Cankova', + 'Hvannasund', + 'Tsavo', + 'Gornji Petrovci', + 'Tisina', + 'Tandil', + 'Espungabera', + 'Salovci', + 'Brades', + 'Jursinci', + 'Podlehnik', + 'Braslovce', + 'Toconao', + 'Trnovska Vas', + 'Savnik', + 'Rinconada', + 'Jurovski Dol', + 'Three Springs', + 'Centar Zupa', + 'Hrib-Loski Potok', + 'Ravensthorpe', + 'Scoresbysund', + 'Vitomarci', + 'Burubaytal', + 'Dobrovo', + 'Leava', + 'Pine Creek', + 'Keflavik', + 'Sentrupert', + 'Basse-Terre', + 'Umm al `Abid', + 'Dolneni', + 'Araouane', + 'Halfmoon Bay', + 'Buur Gaabo', + 'Podvelka', + 'Cazombo', + 'Belcista', + 'Porkeri', + 'Nova Vas', + 'Yaupi', + 'Imdina', + 'Ikela', + 'Hodos', + 'Dol', + 'Cucer-Sandevo', + 'Zelenikovo', + 'Melekeok', + 'Ngerulmud', + 'Andamooka', + 'Tomaz pri Ormozu', + 'Tasiusaq', + 'Adelaide River', + 'Kulusuk', + 'Burketown', + 'Bistrica ob Sotli', + 'Skocjan', + 'Kanyato', + 'Amau', + 'Kairaki', + 'Makole', + 'Boulia', + 'Sveti Jurij', + 'Solcava', + 'Thargomindah', + 'Destrnik', + 'Kraulshavn', + 'Lusanga', + 'Hurdiyo', + 'Port Pirie', + 'Cerkvenjak', + 'Ivanhoe', + 'Al Qunaytirah', + 'Camooweal', + 'Bafwasende', + 'Razkrizje', + 'Buton', + 'Bifoun', + 'Kangersuatsiaq', + 'Narsarsuaq', + 'Bedourie', + 'Petrovec', + 'Mount Isa', + 'Fort Wellington', + 'Dobje', + 'Punta Prieta', + 'Birdsville', + 'Star Dojran', + 'Zelino', + 'Windorah', + 'Al `Uqaylah', + 'Lemsid', + 'Grytviken', + 'Fuzuli', + 'Venado Tuerto', + 'Famjin', + 'Osilnica', + 'Piso Firme', + 'Studenicani', + 'Pagegiai', + 'Savissivik', + 'Adamstown', + 'Samamea', + 'Cauquenes', + 'Bogovinje', + 'Cuya', + 'Vransko', + 'Zillah', + 'Chegga', + 'Djado', + 'Gaigirgordub', + 'Andoas', + 'Puca Urco', + 'Soldado Bartra', + 'Gueppi', + 'Kostel', + 'Puerto Heath', + 'Lagunas', + 'Barnis', + 'Gamba', + 'Nord', + 'Timmiarmiut', + 'Kingoonya', + 'Sabha', + '`Amran', + 'Al Jabin', + 'Nelspruit', + 'Lupane', + 'Anouvong', + 'Xekong', + 'Phon-Hong', + "Qacha's Nek", + 'Mersch', + 'Redange-sur-Attert', + 'Idri', + 'Cocieri', + 'Lipkovo', + 'Ilinden', + 'Resen', + 'Makedonska Kamenica', + 'Dalandzadgad', + 'Tevragh Zeina', + 'Santa Lucija', + 'Rasdhoo', + 'Dhihdhoo', + 'Fonadhoo', + 'Nilandhoo', + 'Thulusdhoo', + 'Balaka', + 'Neno', + 'Chikwawa', + 'Usakos', + 'We', + 'Abakaliki', + 'Yenagoa', + 'Isemi-Ile', + "Hayma'", + 'Suhar', + 'Union Choco', + 'Sieyik', + 'Kurumul', + 'Buka', + 'Az Za`ayin', + 'Umm Salal `Ali', + 'Madinat ash Shamal', + 'Bosilegrad', + 'Zagubica', + 'Doljevac', + 'Boljevac', + 'Ljubovija', + 'Babusnica', + 'Presevo', + 'Ljig', + 'Mali Zvornik', + 'Priboj', + 'Bojnik', + 'Koceljeva', + 'Zabari', + 'Trgoviste', + 'Taro', + 'Rabak', + 'El Fula', + 'Edinburgh of the Seven Seas', + 'Zetale', + 'Sentilj', + 'Zuzemberk', + 'Zavrc', + 'Chiesanuova', + 'Sedhiou', + 'Ceerigaabo', + 'Laascaanood', + 'Boorama', + 'Nhlangano', + 'Pala', + 'Bardai', + 'Kara', + 'Ban Huai Hin', + 'Lospalos', + 'Aileu', + 'Pante Macassar', + 'Suai', + 'Aranguez', + 'Mahonda', + 'Vwawa', + 'Koani', + 'Namutumba', + 'Maracha', + 'Luuka Town', + 'Kasanda', + 'Kinoni', + 'Busesa', + 'Bulambuli', + 'Ntoroko', + 'Otuke', + 'Bupoto', + 'Agago', + 'Kitamilo', + 'Nsiika', + 'Kalaki', + 'Kasaali', + 'Nakapiripirit', + 'Pader', + 'Kakumiro', + 'Mparo', + 'Lamwo', + 'Kyankwanzi', + 'Ntara', + 'Bukwo', + 'Butebo', + 'Binyin', + 'Palenga', + 'Kibingo', + 'Kole', + 'Nabilatuk', + 'Rubanda', + 'Kalungu', + 'Kon Tum', + 'Da Nang', + 'Saratamata', + 'Safotulafai', + 'Mulifanua', + 'Satupa`itea', + 'Sharan', + 'Nili', + 'Davaci', + 'Sarur', + 'Qabala', + 'Isale', + 'Dogbo', + 'Tutong', + 'Sarpang', + 'Pemagatshel', + 'Tsimasham', + 'Gasa', + 'Haa', + 'Lhuentse', + 'Tsirang', + 'Loango', + 'Bangolo', + 'Chuquicamata', + 'Panying', + 'Chengde', + 'Huinan', + 'Joao Teves', + 'Igreja', + 'Nova Sintra', + 'Pombas', + 'Cova Figueira', + 'Erfurt', + 'Fuglafjordhur', + 'Hov', + 'Vagur', + 'Saltangara', + 'Kvivik', + 'Sumba', + 'Vidhareidhi', + 'Nordhragota', + 'Toftir', + 'Kirkja', + 'Eidhi', + 'Sandavagur', + 'Skuvoy', + 'Skalavik', + 'Sorvagur', + 'Vestmanna', + 'Strendur', + 'Tvoroyri', + 'Husavik', + 'Kunoy', + 'Oyrarbakki', + 'Goaso', + 'Dambai', + 'Sefwi Wiawso', + 'Kanifing', + 'King Edward Point', + 'Tanjung Selor', + 'Trim', + 'Jaitpura', + 'Navsari', + 'Tonk', + 'Sari', + 'Nyamira', + 'Siaya', + "Murang'a", + 'Ol Kalou', + 'Sotik Post', + 'Kapenguria', + 'Kabarnet', + 'Migori', + 'Pailin', + 'Ta Khmau', + 'Sariwon-si', + 'Munha-dong', + 'Sil-li', + 'Muan', + 'Hongseong', + 'Charlotte Amalie', +]; diff --git a/drizzle-seed/src/datasets/companyNameSuffixes.ts b/drizzle-seed/src/datasets/companyNameSuffixes.ts new file mode 100644 index 000000000..ae8ce6163 --- /dev/null +++ b/drizzle-seed/src/datasets/companyNameSuffixes.ts @@ -0,0 +1,27 @@ +export default [ + 'LLC', + 'Ltd', + 'Inc.', + 'Corp.', + 'PLC', + 'GmbH', + 'AG', + 'S.A.', + 'S.p.A.', + 'SARL', + 'B.V.', + 'N.V.', + 'Oy', + 'AB', + 'AS', + 'Pty Ltd', + 'K.K.', + 'JSC', + 'Ltda.', + 'Pvt Ltd', + 'Sdn Bhd', + 'A/S', + 'SAOG', + 'Co.', + 'SCC', +]; diff --git a/drizzle-seed/src/datasets/countries.ts b/drizzle-seed/src/datasets/countries.ts new file mode 100644 index 000000000..c251f25e8 --- /dev/null +++ b/drizzle-seed/src/datasets/countries.ts @@ -0,0 +1,169 @@ +export default [ + 'Afghanistan', + 'Albania', + 'Algeria', + 'Angola', + 'Antigua and Barbuda', + 'Argentina', + 'Armenia', + 'Australia', + 'Austria', + 'Azerbaijan', + 'Bahamas', + 'Bahrain', + 'Bangladesh', + 'Barbados', + 'Belarus', + 'Belgium', + 'Belize', + 'Benin', + 'Bhutan', + 'Bolivia', + 'Bosnia and Herzegovina', + 'Botswana', + 'Brazil', + 'Brunei', + 'Bulgaria', + 'Burkina Faso', + 'Burundi', + 'Cambodia', + 'Cameroon', + 'Canada', + 'Cape Verde', + 'Central African Republic', + 'Chad', + 'Chile', + 'China', + 'Colombia', + 'Comoros', + 'Congo, Dem. Rep.', + 'Congo, Rep.', + 'Costa Rica', + "Cote d'Ivoire", + 'Croatia', + 'Cyprus', + 'Czech Republic', + 'Denmark', + 'Dominican Republic', + 'Ecuador', + 'Egypt', + 'El Salvador', + 'Equatorial Guinea', + 'Eritrea', + 'Estonia', + 'Fiji', + 'Finland', + 'France', + 'Gabon', + 'Gambia', + 'Georgia', + 'Germany', + 'Ghana', + 'Greece', + 'Grenada', + 'Guatemala', + 'Guinea', + 'Guinea-Bissau', + 'Guyana', + 'Haiti', + 'Hungary', + 'Iceland', + 'India', + 'Indonesia', + 'Iran', + 'Iraq', + 'Ireland', + 'Israel', + 'Italy', + 'Jamaica', + 'Japan', + 'Jordan', + 'Kazakhstan', + 'Kenya', + 'Kiribati', + 'Kuwait', + 'Kyrgyz Republic', + 'Lao', + 'Latvia', + 'Lebanon', + 'Lesotho', + 'Liberia', + 'Libya', + 'Lithuania', + 'Luxembourg', + 'Macedonia, FYR', + 'Madagascar', + 'Malawi', + 'Malaysia', + 'Maldives', + 'Mali', + 'Malta', + 'Mauritania', + 'Mauritius', + 'Micronesia, Fed. Sts.', + 'Moldova', + 'Mongolia', + 'Montenegro', + 'Morocco', + 'Mozambique', + 'Myanmar', + 'Namibia', + 'Nepal', + 'Netherlands', + 'New Zealand', + 'Niger', + 'Nigeria', + 'Norway', + 'Oman', + 'Pakistan', + 'Panama', + 'Paraguay', + 'Peru', + 'Philippines', + 'Poland', + 'Portugal', + 'Qatar', + 'Romania', + 'Russia', + 'Rwanda', + 'Samoa', + 'Saudi Arabia', + 'Senegal', + 'Serbia', + 'Seychelles', + 'Sierra Leone', + 'Singapore', + 'Slovak Republic', + 'Slovenia', + 'Solomon Islands', + 'South Africa', + 'South Korea', + 'Spain', + 'Sri Lanka', + 'St. Vincent and the Grenadines', + 'Sudan', + 'Suriname', + 'Sweden', + 'Switzerland', + 'Tajikistan', + 'Tanzania', + 'Thailand', + 'Timor-Leste', + 'Togo', + 'Tonga', + 'Tunisia', + 'Turkey', + 'Turkmenistan', + 'Uganda', + 'Ukraine', + 'United Arab Emirates', + 'United Kingdom', + 'United States', + 'Uruguay', + 'Uzbekistan', + 'Vanuatu', + 'Venezuela', + 'Vietnam', + 'Yemen', + 'Zambia', +]; diff --git a/drizzle-seed/src/datasets/emailDomains.ts b/drizzle-seed/src/datasets/emailDomains.ts new file mode 100644 index 000000000..9904aad3e --- /dev/null +++ b/drizzle-seed/src/datasets/emailDomains.ts @@ -0,0 +1,24 @@ +export default [ + 'gmail.com', + 'yahoo.com', + 'outlook.com', + 'msn.com', + 'hotmail.com', + 'aol.com', + 'hotmail.co.uk', + 'hotmail.fr', + 'yahoo.fr', + 'wanadoo.fr', + 'orange.fr', + 'comcast.net', + 'yahoo.co.uk', + 'yahoo.com.br', + 'yahoo.co.in', + 'live.com', + 'rediffmail.com', + 'free.fr', + 'gmx.de', + 'web.de', + 'ymail.com', + 'libero.it', +]; diff --git a/drizzle-seed/src/datasets/firstNames.ts b/drizzle-seed/src/datasets/firstNames.ts new file mode 100644 index 000000000..ac6e1b74a --- /dev/null +++ b/drizzle-seed/src/datasets/firstNames.ts @@ -0,0 +1,30276 @@ +export default [ + 'Robert', + 'John', + 'Michael', + 'David', + 'James', + 'Richard', + 'Christopher', + 'William', + 'Daniel', + 'Mark', + 'Thomas', + 'Jose', + 'Joseph', + 'Matthew', + 'Jason', + 'Andrew', + 'Joshua', + 'Steven', + 'Anthony', + 'Jonathan', + 'Angel', + 'Ryan', + 'Kevin', + 'Jacob', + 'Nicholas', + 'Brandon', + 'Justin', + 'Charles', + 'Gary', + 'Paul', + 'Scott', + 'George', + 'Christian', + 'Eric', + 'Brian', + 'Alexander', + 'Ronald', + 'Jayden', + 'Juan', + 'Edward', + 'Noah', + 'Diego', + 'Donald', + 'Ethan', + 'Kyle', + 'Peter', + 'Jeffrey', + 'Luis', + 'Timothy', + 'Nathan', + 'Tyler', + 'Frank', + 'Stephen', + 'Dennis', + 'Larry', + 'Jesus', + 'Kenneth', + 'Austin', + 'Adrian', + 'Adam', + 'Sebastian', + 'Gregory', + 'Carlos', + 'Aiden', + 'Gabriel', + 'Isaac', + 'Zachary', + 'Julian', + 'Benjamin', + 'Liam', + 'Billy', + 'Miguel', + 'Mason', + 'Aaron', + 'Mike', + 'Dylan', + 'Sean', + 'Alejandro', + 'Bryan', + 'Jordan', + 'Cody', + 'Jeremy', + 'Samuel', + 'Harry', + 'Victor', + 'Joe', + 'Eduardo', + 'Isaiah', + 'Jorge', + 'Logan', + 'Elijah', + 'Bruce', + 'Patrick', + 'Jerry', + 'Jesse', + 'Lawrence', + 'Steve', + 'Walter', + 'Harold', + 'Arthur', + 'Lucas', + 'Francisco', + 'Douglas', + 'Oscar', + 'Craig', + 'Alexis', + 'Todd', + 'Randy', + 'Alan', + 'Raymond', + 'Damian', + 'Willie', + 'Albert', + 'Ricardo', + 'Louis', + 'Luke', + 'Edgar', + 'Travis', + 'Evan', + 'Ricky', + 'Aidan', + 'Jack', + 'Jeff', + 'Jimmy', + 'Manuel', + 'Oliver', + 'Mateo', + 'Johnny', + 'Henry', + 'Cristian', + 'Terry', + 'Dominic', + 'Cameron', + 'Gerald', + 'Caleb', + 'Christop', + 'Bobby', + 'Alex', + 'Gavin', + 'Shawn', + 'Jackson', + 'Ivan', + 'Keith', + 'Antonio', + 'Vincent', + 'Philip', + 'Chad', + 'Alfred', + 'Eugene', + 'Erik', + 'Martin', + 'Omar', + 'Chris', + 'Stanley', + 'Sergio', + 'Francis', + 'Mario', + 'Fernando', + 'Taylor', + 'Herbert', + 'Santiago', + 'Nathaniel', + 'Cesar', + 'Barry', + 'Trevor', + 'Dustin', + 'Hunter', + 'Roger', + 'Andres', + 'Javier', + 'Bernard', + 'Jim', + 'Ian', + 'Wayne', + 'Leonardo', + 'Giovanni', + 'Josiah', + 'Jeremiah', + 'Glenn', + 'Hector', + 'Roberto', + 'Rodney', + 'Howard', + 'Eli', + 'Xavier', + 'Jaxon', + 'Levi', + 'Derek', + 'Danny', + 'Jared', + 'Landon', + 'Ralph', + 'Ruben', + 'Gael', + 'Connor', + 'Tommy', + 'Tony', + 'Marc', + 'Wyatt', + 'Rick', + 'Carter', + 'Ayden', + 'Tim', + 'Roy', + 'Owen', + 'Greg', + 'Joel', + 'Leonard', + 'Frederick', + 'Russell', + 'Jon', + 'Jaden', + 'Jeffery', + 'Irving', + 'Erick', + 'Darren', + 'Dale', + 'Carl', + 'Brayden', + 'Ronnie', + 'Gerardo', + 'Pedro', + 'Raul', + 'Elias', + 'Chase', + 'Alberto', + 'Troy', + 'Tom', + 'Axel', + 'Julio', + 'Emmanuel', + 'Edwin', + 'Norman', + 'Marcus', + 'Fred', + 'Bill', + 'Jake', + 'Marco', + 'Leo', + 'Rafael', + 'Armando', + 'Jace', + 'Garrett', + 'Jaime', + 'Earl', + 'Shane', + 'Cole', + 'Phillip', + 'Seth', + 'Corey', + 'Nicolas', + 'Randall', + 'Hayden', + 'Abraham', + 'Grayson', + 'Tristan', + 'Cory', + 'Josue', + 'Andy', + 'Warren', + 'Roman', + 'Devin', + 'Salvador', + 'Shaun', + 'Spencer', + 'Infant', + 'Ryder', + 'Dillon', + 'Max', + 'Salvatore', + 'Bradley', + 'Seymour', + 'Arturo', + 'Iker', + 'Dean', + 'Milton', + 'Sidney', + 'Gustavo', + 'Alfredo', + 'Blake', + 'Clarence', + 'Brody', + 'Enrique', + 'Brett', + 'Colton', + 'Dan', + 'Brendan', + 'Charlie', + 'Darrell', + 'Hudson', + 'Ezra', + 'Emiliano', + 'Ashton', + 'Darryl', + 'Dave', + 'Nolan', + 'Theodore', + 'Casey', + 'Colin', + 'Easton', + 'Caden', + 'Marcos', + 'Cooper', + 'Mitchell', + 'Morris', + 'Don', + 'Eddie', + 'Jay', + 'Marvin', + 'Kaden', + 'Curtis', + 'Lance', + 'Gerard', + 'Israel', + 'Ramon', + 'Rickey', + 'Alec', + 'Carson', + 'Ernesto', + 'Riley', + 'Kai', + 'Ezekiel', + 'Yahir', + 'Dakota', + 'Ron', + 'Bob', + 'Saul', + 'Kayden', + 'Adan', + 'Fabian', + 'Maxwell', + 'Allen', + 'Micheal', + 'Parker', + 'Micah', + 'Miles', + 'Gilbert', + 'Grant', + 'Malik', + 'Abel', + 'Darrin', + 'Johnathan', + 'Jase', + 'Kaleb', + 'Ray', + 'Jaxson', + 'Brent', + 'Wesley', + 'Tanner', + 'Chester', + 'Bryce', + 'Lincoln', + 'Preston', + 'Maximiliano', + 'Jerome', + 'Sam', + 'Ernest', + 'Bentley', + 'Colby', + 'Elmer', + 'Moises', + 'Joaquin', + 'Arnold', + 'Stuart', + 'Murray', + 'Asher', + 'Andre', + 'Neil', + 'Allan', + 'Brady', + 'Brad', + 'Maximus', + 'Dalton', + 'Jonah', + 'Kim', + 'Kirk', + 'Bryson', + 'Kurt', + 'Angelo', + 'Rene', + 'Jimmie', + 'Emilio', + 'Damien', + 'Harvey', + 'Moshe', + 'Derrick', + 'Kelly', + 'Franklin', + 'Rodrigo', + 'Woodrow', + 'Leon', + 'Esteban', + 'Hugo', + 'Clayton', + 'Guadalupe', + 'Darin', + 'Pablo', + 'Luca', + 'Ken', + 'Ismael', + 'Leroy', + 'Guillermo', + 'Tracy', + 'Melvin', + 'Lorenzo', + 'Clifford', + 'Hugh', + 'Mathew', + 'Jameson', + 'Billie', + 'Nelson', + 'Herman', + 'Ira', + 'Jamie', + 'Alexande', + 'Lester', + 'Glen', + 'Damon', + 'Emanuel', + 'Maverick', + 'Braxton', + 'Zayden', + 'Dominick', + 'Irwin', + 'Rudy', + 'Calvin', + 'Julius', + 'Jermaine', + 'Jakob', + 'Donovan', + 'Lee', + 'Shaquille', + 'Gordon', + 'Peyton', + 'Duane', + 'Declan', + 'Jalen', + 'Jude', + 'Tyrone', + 'Bret', + 'Gene', + 'Felix', + 'Guy', + 'Devon', + 'Cruz', + 'Rylan', + 'Clinton', + 'Jonathon', + 'Kaiden', + 'Kingston', + 'Kristopher', + 'Felipe', + 'Collin', + 'Alfonso', + 'Rodolfo', + 'King', + 'Everett', + 'Chance', + 'Johnnie', + 'Clyde', + 'Weston', + 'Karl', + 'Camden', + 'Maddox', + 'Bryant', + 'Gage', + 'Dwayne', + 'Shannon', + 'Gilberto', + 'Braden', + 'Lewis', + 'Greyson', + 'Rudolph', + 'Floyd', + 'Jayce', + 'Harrison', + 'Brayan', + 'Cayden', + 'Reginald', + 'Jaiden', + 'Brantley', + 'Hyman', + 'Perry', + 'Kent', + 'Alvin', + 'Cade', + 'Doug', + 'Romeo', + 'Jax', + 'Silas', + 'Ty', + 'Emmett', + 'Jackie', + 'Leslie', + 'Vernon', + 'Jessie', + 'Lloyd', + 'Cecil', + 'Roland', + 'Ted', + 'Amir', + 'Cash', + 'Gregg', + 'Uriel', + 'Donnie', + 'Noel', + 'Mauricio', + 'Dana', + 'Osvaldo', + 'Sawyer', + 'Rogelio', + 'Terrence', + 'Conner', + 'Darius', + 'Chaim', + 'Maurice', + 'Male', + 'Malachi', + 'Issac', + 'Ramiro', + 'Zane', + 'Jaylen', + 'Dawson', + 'Willard', + 'Randolph', + 'Wilbur', + 'Noe', + 'Huey', + 'Sammy', + 'Lonnie', + 'Morton', + 'Chandler', + 'Elliot', + 'Geoffrey', + 'Robin', + 'Muhammad', + 'Wallace', + 'Matt', + 'Drew', + 'Bailey', + 'Orlando', + 'Jasper', + 'Tyrese', + 'Matteo', + 'Leonel', + 'Simon', + 'Braylon', + 'Corbin', + 'Jayceon', + 'Gunner', + 'Dante', + 'Daryl', + 'Bennett', + 'Ulises', + 'Efrain', + 'Drake', + 'Rolando', + 'Lukas', + 'Arian', + 'Trenton', + 'Humberto', + 'Ryker', + 'Aldo', + 'Landen', + 'Xander', + 'Dwight', + 'Alvaro', + 'Sheldon', + 'Freddie', + 'Vicente', + 'Avery', + 'Marty', + 'Irvin', + 'Ariel', + 'Lane', + 'Nestor', + 'Chuck', + 'Dominique', + 'Baby', + 'Kerry', + 'Enzo', + 'Nick', + 'Yosef', + 'Edmund', + 'Oswaldo', + 'Kobe', + 'Aden', + 'Clair', + 'Freddy', + 'Karter', + 'Stacy', + 'Byron', + 'Roosevelt', + 'Claude', + 'Marion', + 'Thiago', + 'Colt', + 'Sol', + 'Lamont', + 'Neal', + 'August', + 'Cason', + 'Kason', + 'Reynaldo', + 'Malcolm', + 'Beau', + 'Ignacio', + 'Kareem', + 'Laurence', + 'Finn', + 'Domingo', + 'Rigoberto', + 'Solomon', + 'Aaden', + 'Case', + 'Horace', + 'Griffin', + 'Rocco', + 'Pete', + 'Ross', + 'Skyler', + 'Kenny', + 'Tucker', + 'Morgan', + 'Forrest', + 'Timmy', + 'Clint', + 'Garry', + 'Elwood', + 'Knox', + 'Elian', + 'Zion', + 'Trey', + 'Vito', + 'Jamel', + 'Junior', + 'Roderick', + 'Brooks', + 'Isidore', + 'Kelvin', + 'Ali', + 'Octavio', + 'Luther', + 'Milo', + 'Jett', + 'Unknown', + 'Milan', + 'Nickolas', + 'German', + 'Terence', + 'Virgil', + 'Conor', + 'Isaias', + 'Cristopher', + 'Jayson', + 'Brenden', + 'Joey', + 'Tevin', + 'Branden', + 'Arjun', + 'Carmine', + 'Wendell', + 'Judah', + 'Nikolas', + 'Izaiah', + 'Dick', + 'Jairo', + 'Giovani', + 'Ervin', + 'Graham', + 'Trent', + 'Tyson', + 'Cedric', + 'Elliott', + 'Myles', + 'Kameron', + 'Jaylon', + 'Hubert', + 'Grady', + 'Homer', + 'Quinn', + 'Payton', + 'Bennie', + 'River', + 'Dexter', + 'Emil', + 'Jamal', + 'Orion', + 'Alonzo', + 'Paxton', + 'Ashley', + 'Desmond', + 'Waylon', + 'Patsy', + 'Agustin', + 'Shimon', + 'Jarrod', + 'Rex', + 'Pat', + 'Rhett', + 'Benny', + 'Adriel', + 'Moses', + 'Daquan', + 'Johan', + 'Adolfo', + 'Otis', + 'Kadeem', + 'Jody', + 'Wilson', + 'Pasquale', + 'Kendrick', + 'Alonso', + 'Ben', + 'Ezequiel', + 'Jair', + 'Tomas', + 'Zackary', + 'Dane', + 'Nasir', + 'Alton', + 'Tristen', + 'Wilfredo', + 'Lyle', + 'Rowan', + 'Deandre', + 'Mordechai', + 'Mohamed', + 'Khalil', + 'Maximilian', + 'Devante', + 'Wade', + 'Norbert', + 'Yehuda', + 'Dallas', + 'Menachem', + 'Anderson', + 'Jonas', + 'Zachery', + 'Zaiden', + 'Giovanny', + 'Clifton', + 'Tommie', + 'Ronaldo', + 'Major', + 'Barrett', + 'Darnell', + 'Keegan', + 'Randal', + 'Aarav', + 'Burton', + 'Terrance', + 'Reid', + 'Fredrick', + 'Bobbie', + 'Ace', + 'Kyler', + 'Yoel', + 'Earnest', + 'Toby', + 'Merle', + 'Archer', + 'Santos', + 'Nico', + 'Beckett', + 'Yisroel', + 'Nehemiah', + 'Lynn', + 'Holden', + 'Matias', + 'Rufus', + 'Mohammed', + 'Hayes', + 'Marshall', + 'Trinidad', + 'Valentin', + 'Heath', + 'Weldon', + 'Ed', + 'Lionel', + 'Jaret', + 'Aron', + 'Bernardo', + 'Zander', + 'Devonte', + 'Meyer', + 'Ulysses', + 'Myron', + 'Lowell', + 'Linwood', + 'Rocky', + 'Phoenix', + 'Antoine', + 'Cyrus', + 'Demarcus', + 'Bruno', + 'Titus', + 'Madison', + 'Jarod', + 'Caiden', + 'Kash', + 'Jarvis', + 'Clay', + 'Notnamed', + 'Doyle', + 'Dallin', + 'Atticus', + 'Orville', + 'Nixon', + 'Loren', + 'Wilbert', + 'Karson', + 'Brennan', + 'Brittany', + 'Marlon', + 'Gonzalo', + 'Carlton', + 'Cary', + 'Marquis', + 'Amari', + 'Rohan', + 'Terrell', + 'Gianni', + 'Johnathon', + 'Jan', + 'Boston', + 'Ibrahim', + 'Yitzchok', + 'Jean', + 'Camron', + 'Ronny', + 'Porter', + 'Adonis', + 'Alessandro', + 'Stefan', + 'Giancarlo', + 'Clark', + 'Lupe', + 'Edgardo', + 'Scotty', + 'Messiah', + 'Benito', + 'Zachariah', + 'Kristian', + 'Bodhi', + 'Ronan', + 'Emerson', + 'Wilfred', + 'Heriberto', + 'Davis', + 'Stewart', + 'Efren', + 'Brock', + 'Christophe', + 'Sammie', + 'Kade', + 'Denis', + 'Ernie', + 'Kayson', + 'Quincy', + 'Abe', + 'Estevan', + 'Jamari', + 'Mohammad', + 'Kendall', + 'Demetrius', + 'Walker', + 'Shlomo', + 'Louie', + 'Kody', + 'Valentino', + 'Jaheim', + 'Vince', + 'Frankie', + 'Aubrey', + 'Quinton', + 'Royce', + 'Ari', + 'Abram', + 'Jessica', + 'Curt', + 'Bart', + 'Daren', + 'Braylen', + 'Alexandro', + 'Lamar', + 'Kasen', + 'Willis', + 'Vihaan', + 'Delbert', + 'Triston', + 'Yakov', + 'Courtney', + 'Niko', + 'Pierre', + 'Jaquan', + 'Braulio', + 'Santino', + 'Quentin', + 'Dario', + 'Dusty', + 'Neymar', + 'Bridger', + 'Tyrell', + 'Bertram', + 'Raymundo', + 'Isiah', + 'Reed', + 'Archie', + 'Prince', + 'Rory', + 'Davon', + 'Stacey', + 'Bradford', + 'Nikolai', + 'Kian', + 'Kase', + 'Casen', + 'Dion', + 'Isai', + 'Armand', + 'Percy', + 'Emily', + 'Leland', + 'Sterling', + 'Yandel', + 'Olin', + 'Sanford', + 'Marlin', + 'Denzel', + 'Mekhi', + 'Elbert', + 'Braydon', + 'Dewey', + 'Dudley', + 'Shmuel', + 'Jadon', + 'Braeden', + 'Yair', + 'Rob', + 'Mickey', + 'Monty', + 'Hannah', + 'Luciano', + 'Remington', + 'Akeem', + 'Julien', + 'Carmen', + 'Jensen', + 'Johnie', + 'Mack', + 'Rickie', + 'Javon', + 'Misael', + 'Elvis', + 'Eden', + 'Jess', + 'Phil', + 'Malakai', + 'Melvyn', + 'Rod', + 'Arnulfo', + 'Cohen', + 'Fidel', + 'Levar', + 'Dominik', + 'Grover', + 'Yaakov', + 'Landyn', + 'Colten', + 'Dorian', + 'Keaton', + 'Loyd', + 'Brodie', + 'Otto', + 'Eliezer', + 'Ahmed', + 'Shelby', + 'Hernan', + 'Odin', + 'Regis', + 'Jaydon', + 'Uriah', + 'Remy', + 'Tariq', + 'Sonny', + 'Carroll', + 'Xavi', + 'Christia', + 'Marcel', + 'Brendon', + 'Kellan', + 'Bowen', + 'Unnamed', + 'Scottie', + 'Justice', + 'Kurtis', + 'Stephan', + 'Daxton', + 'Coby', + 'Jadiel', + 'Dashawn', + 'Amare', + 'Cannon', + 'Blaine', + 'Tate', + 'Talmadge', + 'Nathanael', + 'Adolph', + 'Talan', + 'Tobias', + 'Sylvester', + 'Tadeo', + 'Darrel', + 'Winston', + 'Garland', + 'Meir', + 'Kory', + 'Joseluis', + 'Wilburn', + 'Rusty', + 'Avraham', + 'Ayaan', + 'Theo', + 'Mathias', + 'Marcelo', + 'Dino', + 'Kolby', + 'Cael', + 'Tzvi', + 'Davion', + 'Aryan', + 'Rhys', + 'Cain', + 'Duke', + 'Pierce', + 'Landry', + 'Tristin', + 'Emma', + 'Zackery', + 'Antone', + 'Rayan', + 'Hendrix', + 'Lucca', + 'Luka', + 'Jarrett', + 'Miguelangel', + 'Rodger', + 'Kevon', + 'Jacoby', + 'Damion', + 'Maximo', + 'Robbie', + 'Jovanny', + 'Trace', + 'Gunnar', + 'Kieran', + 'Cristobal', + 'Kris', + 'Ellis', + 'Matthias', + 'Eloy', + 'Sarah', + 'Donny', + 'Donte', + 'Ronin', + 'Reece', + 'Alijah', + 'Zayne', + 'Jamarion', + 'Laverne', + 'Gregorio', + 'Kellen', + 'Nathen', + 'Gideon', + 'Rosario', + 'Erwin', + 'Jakub', + 'Normand', + 'Rey', + 'Trevon', + 'Stetson', + 'Carmelo', + 'Rashad', + 'Tod', + 'Elizabeth', + 'Harley', + 'Darian', + 'Scot', + 'Tavon', + 'Keven', + 'Merlin', + 'Nash', + 'Deangelo', + 'Raiden', + 'Jahir', + 'Isidro', + 'Davian', + 'Raekwon', + 'Alphonse', + 'Reese', + 'Abigail', + 'Deshawn', + 'Ahmad', + 'Conrad', + 'Truman', + 'Kolton', + 'Ryland', + 'Jamaal', + 'Abdiel', + 'Aditya', + 'Keenan', + 'Brycen', + 'Thaddeus', + 'Austen', + 'Leonidas', + 'Raphael', + 'Jovani', + 'Brenton', + 'Jasmine', + 'Thurman', + 'Russel', + 'Emory', + 'Cornelius', + 'Roel', + 'Xzavier', + 'Jovanni', + 'Zev', + 'Eldon', + 'Deven', + 'Kamden', + 'Eliseo', + 'Franco', + 'Duncan', + 'Anton', + 'Amarion', + 'Deron', + 'Sage', + 'Babyboy', + 'Fredy', + 'Russ', + 'Omarion', + 'Ryne', + 'Jovany', + 'Camilo', + 'Stan', + 'Cullen', + 'Armani', + 'Adrien', + 'Royal', + 'Kane', + 'Ishaan', + 'Spenser', + 'Antwan', + 'Stephon', + 'Juanpablo', + 'Tiffany', + 'Garret', + 'Jagger', + 'Will', + 'Nigel', + 'Chadwick', + 'Casimir', + 'Abdirahman', + 'Odell', + 'Keanu', + 'Josh', + 'Mortimer', + 'Raheem', + 'Jordon', + 'Nery', + 'Monte', + 'Jaxton', + 'Deacon', + 'Reuben', + 'Carlo', + 'Skylar', + 'Jamarcus', + 'Robby', + 'Jaycob', + 'Kristofer', + 'Buddy', + 'Korbin', + 'Arlo', + 'Jennifer', + 'Rodrick', + 'Juwan', + 'Latrell', + 'Chaz', + 'Lawson', + 'Mendel', + 'Jordy', + 'Dirk', + 'Finnegan', + 'Eason', + 'Atlas', + 'Eddy', + 'Mitch', + 'Reagan', + 'Clement', + 'Jamar', + 'Kamari', + 'Jarred', + 'Lauren', + 'Roscoe', + 'Jefferson', + 'Devan', + 'Elton', + 'Cortez', + 'Leandro', + 'Finley', + 'Cordero', + 'Dov', + 'Eliyahu', + 'Princeton', + 'Avrohom', + 'Hassan', + 'Dangelo', + 'Shamar', + 'Gino', + 'Yusuf', + 'Jaylin', + 'Martez', + 'Shad', + 'Keyshawn', + 'Nikhil', + 'Yael', + 'Harlan', + 'Jeffry', + 'Frederic', + 'Derick', + 'Dondre', + 'Vance', + 'Markus', + 'London', + 'Arman', + 'Marley', + 'Van', + 'Jaeden', + 'Krish', + 'Benson', + 'Marquise', + 'Cristofer', + 'Dewayne', + 'Gannon', + 'Genaro', + 'Crew', + 'Rashawn', + 'Rayden', + 'Raylan', + 'Jaxen', + 'Fredric', + 'Beckham', + 'Tripp', + 'Mckay', + 'Deonte', + 'Johann', + 'Johnpaul', + 'Santo', + 'Hakeem', + 'Federico', + 'Bert', + 'Flynn', + 'Edison', + 'Enoch', + 'Shulem', + 'Jovan', + 'Art', + 'Isadore', + 'Hal', + 'Cristiano', + 'Urijah', + 'Dilan', + 'Benicio', + 'Kingsley', + 'Aydan', + 'Syed', + 'Nicole', + 'Rachel', + 'Tyree', + 'Maximillian', + 'Branson', + 'Davin', + 'Layton', + 'Joan', + 'Darien', + 'Deion', + 'Augustus', + 'Dariel', + 'Oziel', + 'Juancarlos', + 'Pranav', + 'Danielle', + 'Rubin', + 'Jerald', + 'Wilmer', + 'Deegan', + 'Teddy', + 'Mariano', + 'Nathanie', + 'Stevie', + 'Dorsey', + 'Maxim', + 'Jaron', + 'Coty', + 'Damarion', + 'Semaj', + 'Maria', + 'Jamison', + 'Domenick', + 'Emile', + 'Armaan', + 'Arnav', + 'Mackenzie', + 'Everardo', + 'Aurelio', + 'Cayson', + 'Edwardo', + 'Charley', + 'Geovanni', + 'Vincenzo', + 'Yadiel', + 'Francesco', + 'Koby', + 'Joziah', + 'Jasiah', + 'Makai', + 'Long', + 'Cassius', + 'Omari', + 'Ferdinand', + 'Samir', + 'Cleveland', + 'Olivia', + 'Lanny', + 'Sincere', + 'Hyrum', + 'Christina', + 'Lucian', + 'Margarito', + 'Osiel', + 'Kinsler', + 'Sydney', + 'Slade', + 'Lazaro', + 'Sal', + 'Lipa', + 'Hobert', + 'Coy', + 'Elroy', + 'Tatum', + 'Katherine', + 'Chloe', + 'Kyrie', + 'Amanda', + 'Buford', + 'Kymani', + 'Kacper', + 'Elmo', + 'Alphonso', + 'Ramses', + 'Homero', + 'Sherman', + 'Reinaldo', + 'Yechiel', + 'Jonatan', + 'Mychal', + 'Gustave', + 'Paris', + 'Zain', + 'Markanthony', + 'Dimitri', + 'Mamadou', + 'Apollo', + 'Bronson', + 'Hamza', + 'Samson', + 'Madden', + 'Tylor', + 'Jacquez', + 'Garth', + 'Giuseppe', + 'Stephanie', + 'Darion', + 'Yurem', + 'Antony', + 'Rico', + 'Rich', + 'Dontavious', + 'Erin', + 'Kannon', + 'Isaak', + 'Dovid', + 'Coleman', + 'Monroe', + 'Bryon', + 'Asa', + 'Patricio', + 'Arnoldo', + 'Alexandra', + 'Jessy', + 'Jules', + 'Alexzander', + 'Jerrod', + 'Talon', + 'Elvin', + 'Chace', + 'Amos', + 'Galen', + 'Kenji', + 'Rahul', + 'Delmar', + 'Nakia', + 'Abdullah', + 'Deon', + 'Brice', + 'Osbaldo', + 'Favian', + 'Mauro', + 'Tristian', + 'Leopoldo', + 'Hans', + 'Hank', + 'Tou', + 'Demond', + 'Jemal', + 'Ladarius', + 'Kylan', + 'Braiden', + 'Darwin', + 'Kamron', + 'Millard', + 'Dax', + 'Shaquan', + 'Aloysius', + 'Tyshawn', + 'Westley', + 'Marquez', + 'Shayne', + 'Kasey', + 'Usher', + 'Ares', + 'Killian', + 'Maynard', + 'Jeshua', + 'Vaughn', + 'Shia', + 'Naftali', + 'Zaire', + 'Taj', + 'Edmond', + 'Zechariah', + 'Ollie', + 'Hoyt', + 'Donnell', + 'Soren', + 'Isac', + 'Tyquan', + 'Legend', + 'Devyn', + 'Shon', + 'Gerry', + 'Ellsworth', + 'Naftuli', + 'Johnson', + 'Haywood', + 'Aydin', + 'Junius', + 'Wiley', + 'Lennox', + 'Siddharth', + 'Odis', + 'Zaid', + 'Lacy', + 'Hussein', + 'Nicklas', + 'Callen', + 'Izayah', + 'Jaziel', + 'Claud', + 'Horacio', + 'Cyril', + 'Jariel', + 'Shemar', + 'Rebecca', + 'Reyes', + 'Denny', + 'Dereck', + 'Marcelino', + 'Najee', + 'Mac', + 'Hollis', + 'Korey', + 'Addison', + 'Jordi', + 'Eleazar', + 'Lisandro', + 'Dayton', + 'Ammon', + 'Reymundo', + 'Erich', + 'Tenzin', + 'Mitchel', + 'Kristoffer', + 'Jerrold', + 'Kristoph', + 'Refugio', + 'Erasmo', + 'Samantha', + 'Simcha', + 'Abdullahi', + 'Booker', + 'Quadir', + 'Kyson', + 'Hoover', + 'Gus', + 'Azael', + 'Mervin', + 'Yoshio', + 'Jorje', + 'Jesiah', + 'Shirley', + 'Brigham', + 'Memphis', + 'Reyansh', + 'Flavio', + 'Lavern', + 'Rosendo', + 'Dantrell', + 'Devonta', + 'Forest', + 'Alden', + 'Lyndon', + 'Luiz', + 'Elisha', + 'Al', + 'Bentlee', + 'Eriberto', + 'Marques', + 'Alexandre', + 'Fidencio', + 'Jabari', + 'Arsenio', + 'Kaysen', + 'Ethen', + 'Cleo', + 'Blaze', + 'Aryeh', + 'Dequan', + 'Denver', + 'Luc', + 'Delmas', + 'Javion', + 'Gauge', + 'Martell', + 'Ever', + 'Gavyn', + 'Aldair', + 'Okey', + 'Carey', + 'Geovanny', + 'Kalel', + 'Layne', + 'Hiroshi', + 'Ayan', + 'Akiva', + 'Clare', + 'Sigmund', + 'Furman', + 'Claudio', + 'Garrison', + 'Draven', + 'Aidyn', + 'Vern', + 'Andreas', + 'Kwame', + 'Imanol', + 'Jorden', + 'Glynn', + 'Adalberto', + 'Varun', + 'Dashiell', + 'Baron', + 'Jasen', + 'Child', + 'Earle', + 'Izaac', + 'Vivaan', + 'Koa', + 'Lennon', + 'Marcoantonio', + 'Gaetano', + 'Sumner', + 'Barney', + 'Demarion', + 'Abner', + 'Delonte', + 'Val', + 'Jacky', + 'Demario', + 'Zavier', + 'Kale', + 'Wilton', + 'Jordyn', + 'Tatsuo', + 'Boyd', + 'Zayn', + 'Darron', + 'Moe', + 'Dillan', + 'Naquan', + 'Ned', + 'Kaylee', + 'Kelton', + 'Sahil', + 'Kermit', + 'Abelardo', + 'Sullivan', + 'Crosby', + 'Hagen', + 'Tyreek', + 'Jaquez', + 'Andrea', + 'Kyan', + 'Jeremias', + 'Tracey', + 'Ward', + 'Brixton', + 'Seamus', + 'Cedrick', + 'Enrico', + 'Emmitt', + 'Ford', + 'Travon', + 'Felton', + 'Blair', + 'Rio', + 'Dandre', + 'Kaeden', + 'Tiger', + 'Orval', + 'Castiel', + 'Yousef', + 'Anson', + 'Callan', + 'Jamey', + 'Darrius', + 'Tre', + 'Michel', + 'Mcarthur', + 'Rasheed', + 'Jamir', + 'Herschel', + 'Anibal', + 'Kinnick', + 'Hilario', + 'Shea', + 'Jencarlos', + 'Darrick', + 'Rishi', + 'Shaya', + 'Haden', + 'Ean', + 'Jaylan', + 'Rolland', + 'Leobardo', + 'Fermin', + 'Keon', + 'Lucio', + 'Keagan', + 'Savion', + 'Masao', + 'Damari', + 'Aarush', + 'Nunzio', + 'Anakin', + 'Mayson', + 'Westin', + 'Norberto', + 'Tavares', + 'Gorge', + 'Tavaris', + 'Joesph', + 'Sylas', + 'Huy', + 'Gerson', + 'Augustine', + 'Buster', + 'Jelani', + 'Haley', + 'Filip', + 'Shmiel', + 'Lucius', + 'Rojelio', + 'Gale', + 'Quintin', + 'Channing', + 'Brayton', + 'Keshawn', + 'Osmar', + 'Otha', + 'Eder', + 'Mary', + 'Eusebio', + 'Matheus', + 'Randell', + 'Brennen', + 'Trae', + 'Paolo', + 'Caesar', + 'Estill', + 'Camren', + 'Dhruv', + 'Cutter', + 'Rayyan', + 'Jeramiah', + 'Anish', + 'Donavan', + 'Sunny', + 'Hershel', + 'Salvator', + 'Jedidiah', + 'Romario', + 'Hershy', + 'Anders', + 'Trevion', + 'Murphy', + 'Kanye', + 'Jionni', + 'Bradyn', + 'Cordell', + 'Alek', + 'Luisangel', + 'Norris', + 'Nevin', + 'Jaleel', + 'Lenny', + 'Judson', + 'Tayshaun', + 'Aedan', + 'Rhyder', + 'Domenic', + 'Santana', + 'Rahsaan', + 'Sebastien', + 'Corban', + 'Rowdy', + 'Kiyoshi', + 'Armen', + 'Efraim', + 'Vladimir', + 'Callum', + 'Abdul', + 'Gianluca', + 'Mayer', + 'Mustafa', + 'Demarco', + 'Neyland', + 'Vidal', + 'Marshawn', + 'Rudolfo', + 'Nazir', + 'Azariah', + 'Shoji', + 'Worth', + 'Levern', + 'Jai', + 'Antione', + 'Dickie', + 'Yehoshua', + 'Cliff', + 'Kaison', + 'Kye', + 'Jaren', + 'Emir', + 'Henrik', + 'Maxx', + 'Kainoa', + 'Athan', + 'Cletus', + 'Jasir', + 'Dejon', + 'Jadyn', + 'Houston', + 'Kadin', + 'Erubiel', + 'Hadi', + 'Jaydin', + 'Brianna', + 'Alyssa', + 'Marcello', + 'Omer', + 'Ikaika', + 'Ramel', + 'Arron', + 'Bently', + 'Daron', + 'Avi', + 'Jerod', + 'Shelton', + 'Winfred', + 'Mendy', + 'Ryu', + 'Nikko', + 'Arley', + 'Kamdyn', + 'Bo', + 'Erica', + 'Faustino', + 'Fletcher', + 'Dionte', + 'Boyce', + 'Kennedy', + 'Reyli', + 'Paulo', + 'Baruch', + 'Bernie', + 'Mohamad', + 'Kahlil', + 'Kong', + 'Baldemar', + 'Murry', + 'Rogers', + 'Sandy', + 'Bodie', + 'Ivory', + 'Youssef', + 'Kee', + 'Jahiem', + 'Isabella', + 'Keoni', + 'Michelle', + 'Luigi', + 'Marcanthony', + 'Jericho', + 'Achilles', + 'Everette', + 'Americo', + 'Edson', + 'Hiram', + 'Jeramy', + 'Metro', + 'Davi', + 'Hezekiah', + 'Harper', + 'Kiel', + 'Brandan', + 'Said', + 'Noam', + 'Tarik', + 'Raquan', + 'Zeb', + 'Broderick', + 'Arath', + 'Emery', + 'Kip', + 'Tymir', + 'Garrick', + 'Anfernee', + 'Khalid', + 'Jamil', + 'Demian', + 'Amador', + 'Oran', + 'Franklyn', + 'Porfirio', + 'Delano', + 'Justyn', + 'Aharon', + 'Karol', + 'Alva', + 'Nicky', + 'Zack', + 'Jerimiah', + 'Josef', + 'Errol', + 'Hideo', + 'Tahj', + 'Ilan', + 'Kennith', + 'Nathanial', + 'Kyron', + 'Merton', + 'Danial', + 'Tuan', + 'Hung', + 'Massimo', + 'Krew', + 'Arya', + 'Jedediah', + 'Nosson', + 'Jakobe', + 'Eitan', + 'Edmundo', + 'Olen', + 'Benedict', + 'Quintavious', + 'Shalom', + 'Akash', + 'Maxton', + 'Anna', + 'Julia', + 'Melissa', + 'Victoria', + 'Kekoa', + 'Konner', + 'Kirby', + 'Heyward', + 'Davonte', + 'Magnus', + 'Zeus', + 'Neel', + 'Franky', + 'Isael', + 'Gaylon', + 'Kole', + 'Axton', + 'Brando', + 'Mateusz', + 'Lucien', + 'Marquavious', + 'Lon', + 'Gian', + 'Savannah', + 'Trinity', + 'Harris', + 'Kamarion', + 'Aydenn', + 'Cale', + 'Neo', + 'Justus', + 'Mose', + 'Tiago', + 'Saverio', + 'Eligh', + 'Mikel', + 'Eliot', + 'Alvis', + 'Argenis', + 'Musa', + 'Lonny', + 'Thad', + 'Guido', + 'Ceasar', + 'Obed', + 'Pinchas', + 'Barton', + 'Durell', + 'Johnatha', + 'Aric', + 'Geovany', + 'Fransisco', + 'Jaheem', + 'Jarett', + 'Yeshua', + 'Karim', + 'Aayden', + 'Merrill', + 'Michele', + 'Jaydan', + 'Octavius', + 'Jermiah', + 'Alexavier', + 'Brandyn', + 'Arvid', + 'Brentley', + 'Sutton', + 'Coen', + 'Ameer', + 'Giovany', + 'Ishan', + 'Blaise', + 'Bayron', + 'Kamil', + 'Brooklyn', + 'Catherine', + 'Akira', + 'Briggs', + 'Damani', + 'Rasheen', + 'Rayford', + 'Moishe', + 'Ephraim', + 'Esequiel', + 'Kenyon', + 'Constantine', + 'Silvio', + 'Brain', + 'Daylon', + 'Raymon', + 'Ayush', + 'Lazer', + 'Telly', + 'Elan', + 'Stone', + 'Marland', + 'Donn', + 'Shamel', + 'Silvestre', + 'Zephyr', + 'Merrick', + 'Fausto', + 'Dedrick', + 'Cornell', + 'Whitney', + 'Derrell', + 'Mitsuo', + 'Lucious', + 'Tad', + 'Lyric', + 'Darrion', + 'Dannie', + 'Gayle', + 'Burl', + 'Jayquan', + 'Carrol', + 'Laquan', + 'Tyrek', + 'Natividad', + 'Casimer', + 'Jael', + 'Aven', + 'Arnaldo', + 'Yovani', + 'Laura', + 'Dejuan', + 'Dimitrios', + 'Yash', + 'Esai', + 'Zavion', + 'Ora', + 'Durward', + 'Bradly', + 'Hazel', + 'Che', + 'Richie', + 'Diana', + 'Alois', + 'Lynwood', + 'Luverne', + 'Zeke', + 'Dash', + 'Cairo', + 'Delvin', + 'Kawika', + 'Josemanuel', + 'Devean', + 'Sameer', + 'Seneca', + 'Presley', + 'Jed', + 'Malaki', + 'Dominque', + 'Dontae', + 'Dev', + 'Darey', + 'Reggie', + 'Izaak', + 'Manny', + 'Jere', + 'Minh', + 'Ryden', + 'Montana', + 'Kaleo', + 'Jacorey', + 'Ignatius', + 'Filiberto', + 'Cache', + 'Yitzchak', + 'Yaseen', + 'Kentrell', + 'Basil', + 'Ivy', + 'Migel', + 'Jalon', + 'Lenwood', + 'Ellwood', + 'Zakary', + 'Haiden', + 'Dontrell', + 'Braedon', + 'Lorne', + 'Trever', + 'Mikael', + 'Kenzo', + 'Javaris', + 'Ambrose', + 'Alain', + 'Columbus', + 'Leif', + 'Jerold', + 'Anwar', + 'Gabino', + 'Dillion', + 'Kelby', + 'Denzil', + 'Ulisses', + 'Sami', + 'Jahmir', + 'Elimelech', + 'Dock', + 'Zahir', + 'Hardy', + 'Florian', + 'Jewel', + 'Tobin', + 'Curley', + 'Mahdi', + 'Mccoy', + 'Jaquavious', + 'Justen', + 'Lino', + 'Teodoro', + 'Kazuo', + 'Lenard', + 'Robb', + 'Takashi', + 'Maison', + 'Merlyn', + 'Brecken', + 'Ricki', + 'Jet', + 'Lars', + 'Ulices', + 'Dereon', + 'Fox', + 'Ajay', + 'Geraldo', + 'Maksim', + 'Jullian', + 'Kalani', + 'Andrei', + 'Jaidyn', + 'Maxie', + 'Javen', + 'Gail', + 'Ely', + 'Caroline', + 'Amber', + 'Crystal', + 'Kiara', + 'Megan', + 'Reilly', + 'Eugenio', + 'Fisher', + 'Langston', + 'Gavriel', + 'Abhinav', + 'Dee', + 'Kace', + 'Axl', + 'Isabel', + 'Uziel', + 'Sabastian', + 'Rylee', + 'Eliazar', + 'Renato', + 'Harland', + 'Lavar', + 'Stefano', + 'Mayra', + 'Valentine', + 'Bud', + 'Hasan', + 'Zaden', + 'Truett', + 'Korbyn', + 'Toshio', + 'Stockton', + 'Edd', + 'Trystan', + 'Daylan', + 'Jayven', + 'Dewitt', + 'Kraig', + 'Wilford', + 'Celestino', + 'Jacobo', + 'Patryk', + 'Hailey', + 'Nainoa', + 'Haskell', + 'Sharif', + 'Jerad', + 'Raynaldo', + 'Jacques', + 'Jessi', + 'Geary', + 'Gaige', + 'Garnett', + 'Jakari', + 'Yonatan', + 'Eino', + 'Phong', + 'Jerel', + 'Benzion', + 'Quinten', + 'Amado', + 'Blas', + 'Kimberly', + 'Cuauhtemoc', + 'Aayan', + 'Catarino', + 'Jeromy', + 'Kyree', + 'Apolonio', + 'Boy', + 'Antwon', + 'Hakim', + 'Creed', + 'Shiloh', + 'Shepherd', + 'Garett', + 'Oakley', + 'Miller', + 'Dajuan', + 'Mattias', + 'Titan', + 'Immanuel', + 'Lamarcus', + 'Devontae', + 'Reef', + 'Brayson', + 'Grey', + 'Deante', + 'Yariel', + 'Makhi', + 'Jayse', + 'Corbyn', + 'Domenico', + 'Sedrick', + 'Deontae', + 'Kou', + 'Shant', + 'Willy', + 'Austyn', + 'Shloime', + 'Masen', + 'Linus', + 'Florentino', + 'Gionni', + 'Boden', + 'Torrey', + 'Minoru', + 'Daulton', + 'Kolten', + 'Jennings', + 'Noble', + 'Hersh', + 'Kelsey', + 'Nicholaus', + 'Florencio', + 'Nam', + 'Juelz', + 'Kainalu', + 'Destin', + 'Damarcus', + 'Jacolby', + 'Nikita', + 'Artis', + 'Bilal', + 'Kendell', + 'Alexsander', + 'Parth', + 'Esau', + 'Glennon', + 'Kohen', + 'Isacc', + 'Aleksander', + 'Vinh', + 'Trenten', + 'Koen', + 'Candelario', + 'Connie', + 'Aram', + 'Wolfgang', + 'Amit', + 'Om', + 'Shyheim', + 'Raven', + 'Kendra', + 'Eliel', + 'Viet', + 'Kenyatta', + 'Sky', + 'Binyomin', + 'Deanthony', + 'Lachlan', + 'Tory', + 'Kenton', + 'Tamir', + 'Kramer', + 'Deshaun', + 'Javian', + 'Haruo', + 'Rupert', + 'Jevon', + 'Shlome', + 'Danilo', + 'Vanessa', + 'Fernand', + 'Daveon', + 'Les', + 'Marko', + 'Delmer', + 'Marlyn', + 'Winfield', + 'Wes', + 'Rosevelt', + 'Rayshawn', + 'Tai', + 'Kalvin', + 'Jerardo', + 'Sarkis', + 'Bertrand', + 'Kaimana', + 'Kaitlyn', + 'Summer', + 'Veer', + 'Waymon', + 'Evin', + 'Andrey', + 'Iain', + 'Kimi', + 'Foster', + 'Servando', + 'Mychael', + 'Derik', + 'Ryon', + 'Rowen', + 'Mel', + 'Ibn', + 'Werner', + 'Jameel', + 'Avrum', + 'Nachman', + 'Jomar', + 'Rudolf', + 'Tyrique', + 'Rayburn', + 'Khalif', + 'Rondal', + 'Bijan', + 'Rohit', + 'Jeremie', + 'Kain', + 'Nicola', + 'Bode', + 'Brogan', + 'Trayvon', + 'Turner', + 'Dwain', + 'Konnor', + 'Lev', + 'Zayd', + 'Finnley', + 'Brantlee', + 'Deonta', + 'Demetrio', + 'Ajani', + 'Arther', + 'Bianca', + 'Takeo', + 'Harding', + 'Jareth', + 'Rigo', + 'Epifanio', + 'Nahum', + 'Carleton', + 'Cosmo', + 'Shigeru', + 'Josias', + 'Takeshi', + 'Jacobi', + 'Michal', + 'Dorris', + 'Treveon', + 'Jaxx', + 'Aren', + 'Tejas', + 'Beverly', + 'Geoff', + 'Maddux', + 'Camryn', + 'Burt', + 'Norwood', + 'Sholom', + 'Ahron', + 'Macario', + 'Carol', + 'Camdyn', + 'Gennaro', + 'Leeroy', + 'Pinchus', + 'Kaito', + 'Burnell', + 'Frantz', + 'Laron', + 'Clemente', + 'Chasen', + 'Neri', + 'Jerrell', + 'Kashawn', + 'Keola', + 'Alvan', + 'Amar', + 'Ubaldo', + 'Roque', + 'Zalmen', + 'Daylen', + 'Kadyn', + 'Gil', + 'Bernice', + 'Yosgart', + 'Shaan', + 'Yahel', + 'Elon', + 'Levon', + 'Kit', + 'Brodrick', + 'Gaven', + 'Kaidyn', + 'Ansel', + 'Jewell', + 'Mikhail', + 'Derian', + 'Elam', + 'Tye', + 'Leigh', + 'Wayde', + 'Rian', + 'Artemio', + 'Ibrahima', + 'Noa', + 'Autumn', + 'Kylie', + 'Pernell', + 'Britton', + 'Deondre', + 'Arlen', + 'Aman', + 'Kelley', + 'Eliud', + 'Dijon', + 'Imran', + 'Eulalio', + 'Juvenal', + 'Agapito', + 'Brant', + 'Nima', + 'Yisrael', + 'Yerik', + 'Ewan', + 'Lathan', + 'Adair', + 'Gentry', + 'Kyren', + 'Lian', + 'Tayshawn', + 'Alejandra', + 'Jeancarlos', + 'Keyon', + 'Jade', + 'Shayan', + 'June', + 'Christos', + 'Adrain', + 'Jarom', + 'Kathryn', + 'Thor', + 'Haven', + 'Duy', + 'Enmanuel', + 'Montavious', + 'Cortney', + 'Teagan', + 'Blayne', + 'Anselmo', + 'Leyton', + 'Jonny', + 'Braylin', + 'Albaro', + 'Pascual', + 'Gasper', + 'Waldo', + 'Tyreke', + 'Dylon', + 'Narciso', + 'Ebony', + 'Hilton', + 'Margaret', + 'Brighton', + 'Martavious', + 'Demetrios', + 'Kishan', + 'Ansh', + 'Treyton', + 'Albin', + 'Rashon', + 'Rony', + 'Krystian', + 'Amrom', + 'Korver', + 'Richardo', + 'Kayla', + 'Katelyn', + 'Milford', + 'Bishop', + 'Ottis', + 'Emmet', + 'Codey', + 'Ayub', + 'Isreal', + 'Karas', + 'Kendarius', + 'Isamu', + 'Kunta', + 'Jermey', + 'Arvin', + 'Kayleb', + 'Sione', + 'Taurean', + 'Tyron', + 'Mihir', + 'Rami', + 'Vincente', + 'Zayan', + 'Mahlon', + 'Clovis', + 'Kirt', + 'Dyllan', + 'Ramsey', + 'Jeramie', + 'Nikolaus', + 'Edsel', + 'Asael', + 'Andrik', + 'Lisa', + 'Sandro', + 'Desean', + 'Narek', + 'Kiran', + 'Elzie', + 'Jered', + 'Arlie', + 'Yahya', + 'Lizandro', + 'Rollin', + 'Khiry', + 'Yuvraj', + 'Jeancarlo', + 'Anay', + 'Freeman', + 'Stevan', + 'Keller', + 'Ledger', + 'Jasiel', + 'Jacinto', + 'Sherwin', + 'Beaux', + 'Campbell', + 'Sherwood', + 'Torrence', + 'Daryle', + 'Chevy', + 'Adiel', + 'Patricia', + 'Jameer', + 'Bilbo', + 'Jayvon', + 'Early', + 'Boruch', + 'Jadarius', + 'Alpha', + 'Amadou', + 'Reino', + 'Betty', + 'Moussa', + 'Wolf', + 'Jenna', + 'Grace', + 'Natalie', + 'Javonte', + 'Crawford', + 'Damir', + 'Mckinley', + 'Elden', + 'Jhon', + 'Lemuel', + 'Colston', + 'Donta', + 'Pearl', + 'Taquan', + 'Salman', + 'Palmer', + 'Muhammed', + 'Brennon', + 'Cashton', + 'Ysidro', + 'Salomon', + 'Ocean', + 'Anirudh', + 'Aksel', + 'Cal', + 'Ishmael', + 'Brenda', + 'Abran', + 'Rome', + 'Leighton', + 'Canyon', + 'Kael', + 'Amin', + 'Antoni', + 'Tiara', + 'Heather', + 'Christine', + 'Brittney', + 'Angela', + 'Johathan', + 'Cipriano', + 'Coltin', + 'Verne', + 'Darrien', + 'Eamon', + 'Oskar', + 'Mikah', + 'Matix', + 'Kooper', + 'Antonino', + 'Duwayne', + 'Dagoberto', + 'Kolt', + 'Sanjay', + 'Tayden', + 'Waverly', + 'Abrahan', + 'Diamond', + 'West', + 'Jefferey', + 'Shigeo', + 'Kabir', + 'Jamell', + 'Jaedyn', + 'Malcom', + 'Gadiel', + 'Manav', + 'Audie', + 'Hipolito', + 'Theron', + 'Codie', + 'General', + 'Lindy', + 'Carver', + 'Nat', + 'Jacari', + 'Khamari', + 'Wally', + 'Kay', + 'Anastacio', + 'Jaymes', + 'Skip', + 'Cheyne', + 'Dameon', + 'Geronimo', + 'Kevyn', + 'Toney', + 'Arden', + 'Dontavius', + 'Rasheem', + 'Geovani', + 'Gaspar', + 'Baltazar', + 'Bladimir', + 'Rashan', + 'Rulon', + 'Karan', + 'Jory', + 'Chet', + 'Abiel', + 'Lazarus', + 'Britt', + 'Rodriquez', + 'Akil', + 'Zuriel', + 'Rylen', + 'Aston', + 'Graysen', + 'Jaysen', + 'Hillel', + 'Alford', + 'Tyriq', + 'Cassidy', + 'Rahiem', + 'Juanmanuel', + 'Demetri', + 'Jayton', + 'Timoteo', + 'Infantof', + 'Braedyn', + 'Corde', + 'Bee', + 'Valente', + 'Gildardo', + 'Feliciano', + 'Dalvin', + 'Tadashi', + 'Claudie', + 'Teng', + 'Genesis', + 'Tayler', + 'Joeangel', + 'Teruo', + 'Tylan', + 'Markel', + 'Linda', + 'Taven', + 'Pierson', + 'Newton', + 'Keandre', + 'Jayvion', + 'Donavon', + 'Encarnacion', + 'Melton', + 'Ritchie', + 'Erika', + 'Edgard', + 'Christoper', + 'Rocio', + 'Alvie', + 'Josedejesus', + 'Dashaun', + 'Travion', + 'Johny', + 'Marcell', + 'Monique', + 'Caitlin', + 'Durwood', + 'Gustav', + 'Rosalio', + 'Farhan', + 'Benuel', + 'Lashawn', + 'Shakeem', + 'Ocie', + 'Yasir', + 'Szymon', + 'Aaryan', + 'Hansel', + 'Slater', + 'Samarth', + 'Kiyan', + 'Storm', + 'Ava', + 'Yassin', + 'Dayquan', + 'Sherrill', + 'Khari', + 'Anas', + 'Cheskel', + 'Kamryn', + 'Zyaire', + 'Cristo', + 'Christofer', + 'Akhil', + 'Shreyas', + 'Ryley', + 'Gibson', + 'Haziel', + 'Talen', + 'Bracken', + 'Dallen', + 'Rashard', + 'Rockwell', + 'Colie', + 'Del', + 'Jihad', + 'Simeon', + 'Jahmari', + 'Ashwin', + 'Shraga', + 'Cian', + 'Alistair', + 'Cartier', + 'Stoney', + 'Verlyn', + 'Kavon', + 'Konrad', + 'Conrado', + 'Colon', + 'Randel', + 'Christ', + 'Jeremey', + 'Raleigh', + 'Lauro', + 'Dionicio', + 'Kauan', + 'Piotr', + 'Cleon', + 'Malique', + 'Rand', + 'Fritz', + 'Cordaro', + 'Pietro', + 'Faris', + 'Ezio', + 'Atharv', + 'Karthik', + 'Jahsir', + 'Saleem', + 'Abdoulaye', + 'Jiovanni', + 'Ezrah', + 'Everest', + 'Bronx', + 'Kruz', + 'Viktor', + 'Yasiel', + 'Thatcher', + 'Michelangelo', + 'Alaric', + 'Oneal', + 'Sahib', + 'Osiris', + 'Teo', + 'Joseangel', + 'Nate', + 'Walton', + 'Yousif', + 'Ezzard', + 'Yamil', + 'Angus', + 'Jhonny', + 'Fabio', + 'Darold', + 'Junious', + 'Atreyu', + 'Beck', + 'Adriano', + 'Amani', + 'Trevin', + 'Rudra', + 'Parsa', + 'Breon', + 'Umar', + 'Taha', + 'Cormac', + 'Yossi', + 'Jaison', + 'Saad', + 'Shloimy', + 'Chesky', + 'Ayman', + 'Alicia', + 'Chadd', + 'Broc', + 'Cynthia', + 'Reynold', + 'Ismail', + 'Gaylord', + 'Saburo', + 'Kao', + 'Masato', + 'Alfonzo', + 'Joshue', + 'Earvin', + 'Patric', + 'Robinson', + 'Serjio', + 'Gavino', + 'Stanford', + 'Thanh', + 'Kamren', + 'Vikram', + 'Roan', + 'Jeronimo', + 'Zahid', + 'Anjel', + 'Jayro', + 'Skye', + 'Baylor', + 'Drayden', + 'Pheng', + 'Yeng', + 'Wilber', + 'Meng', + 'Arik', + 'Jamarius', + 'Avigdor', + 'Ladarrius', + 'Nicklaus', + 'Gatlin', + 'Boone', + 'Jacen', + 'Antonia', + 'Kyran', + 'Quintavius', + 'Estil', + 'Casimiro', + 'Prentice', + 'Jodie', + 'Rashaad', + 'Konstantinos', + 'Allison', + 'Sophia', + 'Makayla', + 'Lillian', + 'Zymir', + 'Canaan', + 'Delfino', + 'Benton', + 'Apolinar', + 'Winford', + 'Dayne', + 'Shivam', + 'Fredi', + 'Yves', + 'Jarrell', + 'Ignazio', + 'Gamaliel', + 'Young', + 'Kiefer', + 'Juanjose', + 'Rehan', + 'Kegan', + 'Davante', + 'Naim', + 'Lyman', + 'Erskine', + 'Toivo', + 'Darrian', + 'Jad', + 'Ender', + 'Remi', + 'Rishaan', + 'Shaurya', + 'Viaan', + 'Chelsea', + 'Molly', + 'Sara', + 'Leib', + 'Azriel', + 'Howell', + 'Briar', + 'Korben', + 'Manning', + 'Job', + 'Brandt', + 'Jaedon', + 'Ozzy', + 'Cordarius', + 'Lannie', + 'Stanton', + 'Radames', + 'Blease', + 'Zyon', + 'Chadrick', + 'Watson', + 'Kentavious', + 'Taurus', + 'Adin', + 'Jordin', + 'Bryden', + 'Susumu', + 'Tamotsu', + 'Yukio', + 'Granville', + 'Ashby', + 'Tristyn', + 'Devaughn', + 'Deric', + 'Cecilio', + 'Pershing', + 'Noboru', + 'Rashaun', + 'Masaichi', + 'Juventino', + 'Norton', + 'Serafin', + 'Windell', + 'Cris', + 'Curtiss', + 'Boris', + 'Elio', + 'Williams', + 'Trung', + 'Torao', + 'Karon', + 'Canon', + 'Tyrik', + 'Naythan', + 'Michaelangelo', + 'Kavin', + 'Akshay', + 'Broden', + 'Quran', + 'Rishabh', + 'Hilbert', + 'Abbas', + 'Damoni', + 'Dillard', + 'Tigran', + 'Romel', + 'Chip', + 'Aeden', + 'Deagan', + 'Treyson', + 'Brannon', + 'Tremaine', + 'Fay', + 'Bryton', + 'Lucky', + 'Izak', + 'Edan', + 'Casper', + 'Koda', + 'Saquan', + 'Alcide', + 'Quinlan', + 'Maddex', + 'Hoyle', + 'Sandra', + 'Joshuah', + 'Lindsay', + 'Donato', + 'Jancarlos', + 'Kalin', + 'Zigmund', + 'Kalen', + 'Jalil', + 'Bonifacio', + 'Gabrielle', + 'Destiny', + 'Cheyenne', + 'Ulyses', + 'Rueben', + 'Markell', + 'Jermel', + 'Corwin', + 'Justine', + 'Idris', + 'Pilar', + 'Torrance', + 'Raeford', + 'Olan', + 'Octavious', + 'Quantavious', + 'Modesto', + 'Kashton', + 'Librado', + 'Bonnie', + 'Lois', + 'Justo', + 'Mahmoud', + 'Divine', + 'Baylen', + 'Rakeem', + 'Diesel', + 'Kyng', + 'Daisy', + 'Armon', + 'Joseantonio', + 'Montel', + 'Gearld', + 'Cloyd', + 'Lindell', + 'Nile', + 'Kashif', + 'Johnmichael', + 'Aramis', + 'Leopold', + 'Kamal', + 'Jerrad', + 'Jadin', + 'Mykel', + 'Jahlil', + 'Cheng', + 'Ezriel', + 'Aria', + 'Dajon', + 'Holt', + 'Chauncey', + 'Karsen', + 'Stryker', + 'Olaf', + 'Reno', + 'Colter', + 'Schuyler', + 'Orvil', + 'Auden', + 'Eyan', + 'Tyce', + 'Barbara', + 'Zamir', + 'Alexi', + 'Braelyn', + 'Brook', + 'Marchello', + 'Tyrel', + 'Oracio', + 'Jalin', + 'Verlon', + 'Raj', + 'Lindsey', + 'Andon', + 'Devlin', + 'Brysen', + 'Harman', + 'Treyvon', + 'Foy', + 'Arash', + 'Cuong', + 'Torin', + 'Rommel', + 'Lorenza', + 'Vishal', + 'Kenya', + 'Heber', + 'Victoriano', + 'Shay', + 'Tremayne', + 'Natanael', + 'Zachry', + 'Eros', + 'Veronica', + 'Wayland', + 'Rayquan', + 'Ana', + 'Jaceon', + 'Yida', + 'Rahmel', + 'Alter', + 'Lamarion', + 'Tavion', + 'Javin', + 'Lawerence', + 'Alessio', + 'Kristen', + 'Jacqueline', + 'Oren', + 'Aahil', + 'Adyan', + 'Augustin', + 'Coleton', + 'Wilfrid', + 'Dezmond', + 'Keelan', + 'Ike', + 'Kanoa', + 'Kedrick', + 'Chue', + 'Danniel', + 'Jowell', + 'Micahel', + 'Yonathan', + 'Finnian', + 'Garfield', + 'Joao', + 'Ezell', + 'Masaru', + 'Yoshito', + 'Pasco', + 'Yechezkel', + 'Shloma', + 'Adnan', + 'Jaythan', + 'Laith', + 'Greysen', + 'Maddix', + 'Alfonse', + 'Ernst', + 'Hobart', + 'Tavin', + 'Dajour', + 'Cy', + 'Estel', + 'Osman', + 'Vedant', + 'Rolf', + 'Ova', + 'Colson', + 'Kelan', + 'Oumar', + 'Olivier', + 'Seichi', + 'Tayson', + 'Roshan', + 'Blane', + 'Baxter', + 'Vu', + 'Tam', + 'Pao', + 'Wardell', + 'Davonta', + 'Montrell', + 'Ravi', + 'Durrell', + 'Bastian', + 'Aj', + 'Ren', + 'Loki', + 'Kairo', + 'Rock', + 'Mylo', + 'Lavell', + 'Bjorn', + 'Arvil', + 'Reinhold', + 'Yesenia', + 'Carsen', + 'Zephaniah', + 'Renzo', + 'Willem', + 'Unique', + 'Elmore', + 'Kalob', + 'Payne', + 'Leeland', + 'Naseem', + 'Yusef', + 'Aboubacar', + 'Ioannis', + 'Bohdan', + 'Javien', + 'Jakobi', + 'Dempsey', + 'Xavian', + 'Antavious', + 'Jc', + 'Dara', + 'Obie', + 'Celso', + 'Tyrin', + 'Eian', + 'Elgin', + 'Jaylyn', + 'Brandin', + 'Adyn', + 'Gabriela', + 'Jaidon', + 'Zavian', + 'Lonzo', + 'Elwin', + 'Tsutomu', + 'Jeanluc', + 'Caeden', + 'Auston', + 'Jasson', + 'Omid', + 'Gray', + 'Vang', + 'Nancy', + 'Nader', + 'Kylen', + 'Jarell', + 'Prentiss', + 'Tahir', + 'Ahmir', + 'Terell', + 'Ludwig', + 'Biagio', + 'Douglass', + 'Nafis', + 'Harlem', + 'Phineas', + 'Lochlan', + 'Hermon', + 'Wilder', + 'Aniello', + 'Attilio', + 'Shiv', + 'Montgomery', + 'Bowie', + 'Aries', + 'Itzae', + 'Isa', + 'Huxley', + 'Elwyn', + 'Advik', + 'Mahamadou', + 'Grayden', + 'Landin', + 'Decker', + 'Dakotah', + 'Ella', + 'Md', + 'Shayaan', + 'Isidor', + 'Joahan', + 'Tillman', + 'Jafet', + 'Panagiotis', + 'Jajuan', + 'Cristhian', + 'Demetric', + 'Zaylen', + 'Kacen', + 'Sloan', + 'Shedrick', + 'Denilson', + 'Buck', + 'Dyland', + 'Aris', + 'Demonte', + 'Telvin', + 'Raynard', + 'Quantavius', + 'Neftali', + 'Alma', + 'Kadarius', + 'Philippe', + 'Laurel', + 'Vadhir', + 'Juandiego', + 'Alekzander', + 'Napoleon', + 'Fabrizio', + 'Abisai', + 'Yasin', + 'Kamran', + 'Ole', + 'Nicolai', + 'Erling', + 'Jathan', + 'Zen', + 'Shiven', + 'Keshaun', + 'Nikola', + 'Loy', + 'Usman', + 'Concepcion', + 'Verlin', + 'Dedric', + 'Derwin', + 'Graig', + 'Serge', + 'Merritt', + 'Kervin', + 'Maleek', + 'Baldomero', + 'Germaine', + 'Hampton', + 'Shan', + 'Alvino', + 'Davy', + 'Arlington', + 'Brandy', + 'Timmie', + 'Andrae', + 'Terrion', + 'Quang', + 'Jeb', + 'Clem', + 'Judd', + 'Severo', + 'Woody', + 'Toan', + 'Alonza', + 'Gardner', + 'Delton', + 'Vinny', + 'Vilas', + 'Welton', + 'Sabian', + 'Dell', + 'Randolf', + 'Tyren', + 'Glenwood', + 'Antwain', + 'Savon', + 'Lesley', + 'Rashid', + 'Tavian', + 'Marvens', + 'Aleksandr', + 'Vivek', + 'Maximino', + 'Pavel', + 'Renee', + 'Charly', + 'Donell', + 'Shariff', + 'Ennis', + 'Menashe', + 'Ygnacio', + 'Hoke', + 'Lebron', + 'Hillard', + 'Xavion', + 'Nicolaus', + 'Kemari', + 'Sammuel', + 'Jessiah', + 'Virgle', + 'Niklas', + 'Allante', + 'Keenen', + 'Albino', + 'Rivaldo', + 'Jospeh', + 'Broadus', + 'Trequan', + 'Finis', + 'Sabas', + 'Abdoul', + 'Tyronne', + 'Tyreik', + 'Tyriek', + 'Linton', + 'Jashawn', + 'Ivey', + 'Janiel', + 'Jayme', + 'Lamarr', + 'Tiernan', + 'Meilech', + 'Fitzgerald', + 'Jonnathan', + 'Tashawn', + 'Verl', + 'Nichoals', + 'Urban', + 'Marquan', + 'Montez', + 'Akshaj', + 'Syrus', + 'Nehemias', + 'Nova', + 'Makaio', + 'Joselito', + 'Armin', + 'Monica', + 'Natasha', + 'Leonce', + 'Corby', + 'Doris', + 'Chancellor', + 'Yonah', + 'Gaston', + 'Alston', + 'Tyreese', + 'Gaither', + 'Donna', + 'Graeme', + 'Frances', + 'Earlie', + 'Oral', + 'Ruby', + 'Krishna', + 'Berkley', + 'Viraj', + 'Jame', + 'Judge', + 'Denim', + 'Guilherme', + 'Salim', + 'Rondell', + 'Marek', + 'Zac', + 'Seven', + 'Stellan', + 'Calder', + 'Eithan', + 'Eliam', + 'Gareth', + 'Auther', + 'Theodis', + 'Denzell', + 'Octave', + 'Destry', + 'Bartholomew', + 'Rajiv', + 'Jaxxon', + 'Maxson', + 'Adler', + 'Tyran', + 'Carnell', + 'Alben', + 'Saif', + 'Merwin', + 'Binyamin', + 'Hayward', + 'Arav', + 'Berry', + 'Daunte', + 'Arvo', + 'Gerhard', + 'Selmer', + 'Davie', + 'Courtland', + 'Athanasios', + 'Ori', + 'Aadi', + 'Kamar', + 'Jeremih', + 'Jayvian', + 'Doyne', + 'Macarthur', + 'Elza', + 'Harden', + 'Soham', + 'Alder', + 'Josemaria', + 'Iziah', + 'Jin', + 'Woodie', + 'Alfie', + 'Stefon', + 'Oswald', + 'Talmage', + 'Leander', + 'Jancarlo', + 'Sasha', + 'Lorin', + 'Roby', + 'Juanmiguel', + 'Johannes', + 'Allie', + 'Demetris', + 'Sharod', + 'Mynor', + 'Lex', + 'Tito', + 'Domonique', + 'Seferino', + 'Jourdan', + 'Marcial', + 'Herminio', + 'Mikal', + 'Alegandro', + 'Makana', + 'Bb', + 'Jarret', + 'Jemel', + 'Kareen', + 'Sierra', + 'Michale', + 'Jalyn', + 'Meredith', + 'Gracie', + 'Dawud', + 'Raylon', + 'Avan', + 'Dayshawn', + 'Livan', + 'Kendal', + 'Otho', + 'Dung', + 'Reuven', + 'Karmelo', + 'Myer', + 'Tadao', + 'Bentzion', + 'Tex', + 'Jamin', + 'Clois', + 'Sadao', + 'Tetsuo', + 'Izrael', + 'Avion', + 'Katsumi', + 'Gerrit', + 'Jamauri', + 'Kunal', + 'Nickolaus', + 'Hoang', + 'Bernabe', + 'Khristian', + 'Arne', + 'Javeon', + 'Vasilios', + 'Noach', + 'Ruger', + 'Kutter', + 'Kyden', + 'Marshal', + 'Jaelon', + 'Raffi', + 'Rito', + 'Parrish', + 'Duvid', + 'Jamario', + 'Verle', + 'Harmon', + 'Thai', + 'Claire', + 'Daiquan', + 'Didier', + 'Jonnie', + 'Arlan', + 'Taggart', + 'Henri', + 'Rogan', + 'Woodford', + 'Maceo', + 'Nyjah', + 'Smith', + 'Syncere', + 'Ballard', + 'Kenichi', + 'Khaled', + 'Dwaine', + 'Mathieu', + 'Ousmane', + 'Emmit', + 'Aayush', + 'Elyas', + 'Taysom', + 'Azaiah', + 'Axle', + 'Ander', + 'Azaan', + 'Vic', + 'Terrel', + 'Alen', + 'Fabricio', + 'Yeshaya', + 'Greggory', + 'Derrik', + 'Esgar', + 'Selwyn', + 'Binh', + 'Tarun', + 'Quoc', + 'Corry', + 'Wylie', + 'Jadan', + 'Aamir', + 'Barron', + 'Ciaran', + 'Melville', + 'Bronislaus', + 'Fong', + 'Hakop', + 'Jashua', + 'Stanislaus', + 'Keion', + 'Timmothy', + 'Kenan', + 'Banks', + 'Ammar', + 'Maxfield', + 'Tyre', + 'Chistian', + 'Son', + 'Shaka', + 'Jahmal', + 'Jerell', + 'Beckam', + 'Zakariya', + 'Jayshawn', + 'Orvel', + 'Yona', + 'Derrek', + 'Warner', + 'Rollie', + 'Adelbert', + 'Von', + 'Kathleen', + 'April', + 'Nikolaos', + 'Alika', + 'Barrington', + 'Inez', + 'Len', + 'Arsh', + 'Elyjah', + 'Eshaan', + 'Shayden', + 'Jaykob', + 'Raziel', + 'Makoa', + 'Cornelio', + 'Rufino', + 'Leamon', + 'Terrill', + 'Hai', + 'Jonerik', + 'Hamilton', + 'Lindbergh', + 'Enos', + 'Sabino', + 'Ara', + 'Raudel', + 'Jones', + 'Cedar', + 'Yohan', + 'Janet', + 'Archibald', + 'Boaz', + 'Cleotha', + 'Dontez', + 'Eldridge', + 'Abhay', + 'Butch', + 'Jayvien', + 'Rowland', + 'Kimo', + 'Gurney', + 'Virgilio', + 'Alfonza', + 'Perley', + 'Silverio', + 'Amilcar', + 'Kapena', + 'Issak', + 'Josemiguel', + 'Mikey', + 'Camille', + 'Gershon', + 'Mehki', + 'Carsten', + 'Lavelle', + 'Jamere', + 'Natale', + 'Elya', + 'Antwone', + 'Pedrohenrique', + 'Kyjuan', + 'Shakim', + 'Evaristo', + 'Lionell', + 'Helen', + 'Aariz', + 'Paige', + 'Jaquavius', + 'Adolphus', + 'Faith', + 'Breanna', + 'Martavius', + 'Armondo', + 'Yobani', + 'Missael', + 'Marcellus', + 'Rishab', + 'Jaxsen', + 'Jahleel', + 'Bernell', + 'Woodroe', + 'Breck', + 'Paden', + 'Trumaine', + 'Rogerio', + 'Cleve', + 'Ameen', + 'Jermain', + 'Shakir', + 'Berl', + 'Conley', + 'Vinson', + 'Andru', + 'Andrue', + 'Suraj', + 'Ruvim', + 'Rodriguez', + 'Benji', + 'Kylon', + 'Matheo', + 'Kellin', + 'Karsyn', + 'Izan', + 'Caysen', + 'Caison', + 'Witten', + 'Issa', + 'Audrey', + 'Sekou', + 'Januel', + 'Christpher', + 'Octaviano', + 'Jereme', + 'Basilio', + 'Kaine', + 'Jayvyn', + 'Vishnu', + 'Umberto', + 'Keondre', + 'Delroy', + 'Herve', + 'Rakim', + 'Denton', + 'Donavin', + 'Elder', + 'Ger', + 'Jazmin', + 'Schneider', + 'Ethyn', + 'Davien', + 'Cross', + 'Reginal', + 'Maksymilian', + 'Rahim', + 'Ridge', + 'Ved', + 'Bartosz', + 'Kaye', + 'Quamir', + 'Jasmin', + 'Diante', + 'Codi', + 'Khamani', + 'Juliocesar', + 'Lydell', + 'Dakari', + 'Eluzer', + 'Daniyal', + 'Isidoro', + 'Yousuf', + 'Rider', + 'Winthrop', + 'Diogo', + 'Kejuan', + 'Micaiah', + 'Ransom', + 'Rolla', + 'Leibish', + 'Ilyas', + 'Arham', + 'Adham', + 'Abdulrahman', + 'Lateef', + 'Rahmir', + 'Kollin', + 'Jamaine', + 'Khary', + 'De', + 'Jabbar', + 'Hardin', + 'Deryl', + 'Yanky', + 'Aviel', + 'Boubacar', + 'Eshan', + 'Hanley', + 'Hussain', + 'Tylon', + 'Leldon', + 'Raoul', + 'Braheem', + 'Kaseem', + 'Tyshaun', + 'Rashaan', + 'Kordell', + 'Anil', + 'Devion', + 'Mervyn', + 'Shaquil', + 'Shaquill', + 'Shaul', + 'Musab', + 'Muad', + 'Tomasz', + 'Madeline', + 'Delante', + 'Jahari', + 'Leah', + 'Tamika', + 'Britney', + 'Jeriel', + 'Yidel', + 'Jarad', + 'Oneil', + 'Fransico', + 'Shamir', + 'Carmello', + 'Abdulahi', + 'Shneur', + 'Yehudah', + 'Brown', + 'Sylvan', + 'Dontay', + 'French', + 'Griffen', + 'Faisal', + 'Dru', + 'Demitri', + 'Faron', + 'Deloy', + 'Juston', + 'Charleston', + 'Farrell', + 'Tab', + 'Donaciano', + 'Candido', + 'Joyce', + 'Marquel', + 'Lamonte', + 'Raheen', + 'Dashon', + 'Hieu', + 'Tyus', + 'Ciro', + 'Naeem', + 'Rush', + 'Keifer', + 'Christion', + 'Bladen', + 'Kobie', + 'Darell', + 'Mouhamed', + 'Jia', + 'Shepard', + 'Price', + 'Kasyn', + 'Truitt', + 'Jenson', + 'Aizen', + 'Markeith', + 'Braylan', + 'Jonmichael', + 'Damond', + 'Jaycion', + 'Platon', + 'Amaury', + 'Amaan', + 'Daven', + 'Tobey', + 'Hymen', + 'Altariq', + 'Jacory', + 'Ashtin', + 'Domonic', + 'Demari', + 'Denise', + 'Abimael', + 'Izaya', + 'Jovon', + 'Harout', + 'Caelan', + 'Donal', + 'Martel', + 'Jaskaran', + 'Alante', + 'Bradon', + 'Deborah', + 'Harrell', + 'Kaipo', + 'Klayton', + 'Danthony', + 'Justino', + 'Kamuela', + 'Barrie', + 'Argelis', + 'Dolores', + 'Jahaziel', + 'Iram', + 'Adian', + 'Rance', + 'Karsten', + 'Christain', + 'Jamarian', + 'Yee', + 'Adriana', + 'Jamichael', + 'Waino', + 'Anh', + 'Casmer', + 'Ronnell', + 'Tong', + 'Vicent', + 'Jarius', + 'Tiburcio', + 'Burdette', + 'Amadeo', + 'Kevan', + 'Arlyn', + 'Derald', + 'Waleed', + 'Jabez', + 'Khoa', + 'Neville', + 'Susan', + 'Leandre', + 'Jorgeluis', + 'Angelica', + 'Regan', + 'Froylan', + 'Tevita', + 'Sagar', + 'Drayton', + 'Zade', + 'Karriem', + 'Townes', + 'Ram', + 'Jaceyon', + 'Keng', + 'Isao', + 'Unkown', + 'Vivian', + 'Mamoru', + 'Dyllon', + 'Hagop', + 'Masami', + 'Shoichi', + 'Landan', + 'Cadence', + 'Yanixan', + 'Xzavion', + 'Javan', + 'Avian', + 'Cadyn', + 'Collier', + 'Clarance', + 'Karen', + 'Christy', + 'Toriano', + 'Diallo', + 'Mateus', + 'Caio', + 'Larue', + 'Gilmer', + 'Rhyan', + 'Elijiah', + 'Curren', + 'Souleymane', + 'Deklan', + 'Zakaria', + 'Hayk', + 'Ric', + 'Briley', + 'Oval', + 'Lovell', + 'Daryn', + 'Franz', + 'Spurgeon', + 'Giacomo', + 'Orrin', + 'Vester', + 'Taran', + 'Salem', + 'Naveen', + 'Linkin', + 'Kallen', + 'Kongmeng', + 'Patrice', + 'Bibb', + 'Arjan', + 'Fateh', + 'Clive', + 'Pharaoh', + 'Subhan', + 'Rayaan', + 'Zebulon', + 'Webster', + 'Raghav', + 'Zakai', + 'Ekam', + 'Caspian', + 'Atom', + 'Athen', + 'Esdras', + 'Vihan', + 'Ronav', + 'Arrow', + 'Izek', + 'Gaines', + 'Trajan', + 'Onofrio', + 'Romello', + 'Ramone', + 'Symir', + 'Kanyon', + 'Shomari', + 'Christo', + 'Anthoney', + 'Giovonni', + 'Gurshan', + 'Nathon', + 'Zach', + 'Jhonatan', + 'Shakur', + 'Favio', + 'Imani', + 'Asad', + 'Brien', + 'Aureliano', + 'Fischer', + 'Yadier', + 'Marino', + 'Kimball', + 'Saleh', + 'Greco', + 'Helmer', + 'Sai', + 'Khai', + 'Marius', + 'Joy', + 'Amauri', + 'Tegan', + 'Darl', + 'Cosimo', + 'Armond', + 'Yecheskel', + 'Natan', + 'Shabazz', + 'Devine', + 'Fabrice', + 'Tarek', + 'Renaldo', + 'Jarrel', + 'Gamal', + 'Rajesh', + 'Lavon', + 'Ahnaf', + 'Cono', + 'Gaspare', + 'Chas', + 'Jaspreet', + 'Tevon', + 'Kush', + 'Nuchem', + 'Jostin', + 'Wm', + 'Darnel', + 'Thurston', + 'Maliek', + 'Shakeel', + 'Coolidge', + 'Shaheed', + 'Anastasios', + 'Wesson', + 'Humza', + 'Kofi', + 'Jamelle', + 'Davey', + 'Llewellyn', + 'Nashawn', + 'Odie', + 'Jun', + 'Jahmere', + 'Bienvenido', + 'Safwan', + 'Mordche', + 'Demarius', + 'Cillian', + 'Alexandros', + 'Nochum', + 'Shareef', + 'Pawel', + 'Theadore', + 'Dorothy', + 'Geno', + 'Haris', + 'Dayvon', + 'Lemarcus', + 'Rayvon', + 'Laird', + 'Zayvion', + 'Dennie', + 'Dwane', + 'Orvis', + 'Chalmer', + 'Adil', + 'Zamari', + 'Kodi', + 'Braxtyn', + 'Fahim', + 'Merl', + 'Name', + 'Aaiden', + 'Dyson', + 'Westyn', + 'Wells', + 'Niles', + 'Nabil', + 'Kaelan', + 'Dmitri', + 'Demitrius', + 'Arlis', + 'Reco', + 'Glendon', + 'Abhishek', + 'Jammie', + 'Grabiel', + 'Jerson', + 'Gerhardt', + 'Kyrin', + 'Kipton', + 'Bear', + 'Jaciel', + 'Dakoda', + 'Kaelin', + 'Keilan', + 'Brendyn', + 'Fortino', + 'Diondre', + 'Arin', + 'Cleophus', + 'Dimas', + 'Caine', + 'Jakoby', + 'Hagan', + 'Layden', + 'Calen', + 'Nils', + 'Cisco', + 'Jerrick', + 'Gevork', + 'Mckenzie', + 'Justis', + 'Coltyn', + 'Brazos', + 'Jaycen', + 'Kemauri', + 'Tyrus', + 'Zaidyn', + 'Lenin', + 'Karlos', + 'Shrey', + 'Edric', + 'Tino', + 'Macklin', + 'Nevan', + 'Lawrance', + 'Arno', + 'Irby', + 'Namir', + 'Chayse', + 'Ronit', + 'Clemens', + 'Giorgio', + 'Khriz', + 'Khang', + 'Zidane', + 'Nomar', + 'Glade', + 'Doyce', + 'Kaya', + 'Surya', + 'Jaelen', + 'Vernell', + 'Issiah', + 'Henderson', + 'Jessejames', + 'Gaylen', + 'Aldahir', + 'An', + 'Asencion', + 'Garner', + 'Treston', + 'Evans', + 'Salome', + 'Cyle', + 'Sang', + 'Isaih', + 'Kirkland', + 'Loyal', + 'Jonpaul', + 'Cindy', + 'Bao', + 'Laurie', + 'Monico', + 'Kiptyn', + 'Toribio', + 'Cresencio', + 'Ruperto', + 'Dat', + 'Rustin', + 'Kendric', + 'Miquel', + 'Hasani', + 'Caron', + 'Jarron', + 'Enrigue', + 'Evelyn', + 'Paulino', + 'Eligio', + 'Melchor', + 'Deshon', + 'Johndavid', + 'Cliffton', + 'Ovidio', + 'Jacorian', + 'Laken', + 'Aedyn', + 'Ichiro', + 'Derion', + 'Sharon', + 'Yasuo', + 'Masayuki', + 'Andrez', + 'Dustyn', + 'Toua', + 'Jossue', + 'Zakkary', + 'Bernardino', + 'Deward', + 'Joanthan', + 'Sandeep', + 'Hercules', + 'Claudia', + 'Sampson', + 'Jacobe', + 'Hulon', + 'Ventura', + 'Blade', + 'Jayzen', + 'Jarren', + 'Nakoa', + 'Chan', + 'Jerrel', + 'Isamar', + 'Artie', + 'Amy', + 'Meghan', + 'Rockey', + 'Sixto', + 'Ascencion', + 'Damonte', + 'Golden', + 'Bubba', + 'Randle', + 'Adelard', + 'Rumaldo', + 'Nieves', + 'Marshaun', + 'Kavion', + 'Mikolaj', + 'Brees', + 'Gayland', + 'Herb', + 'Quenton', + 'Flint', + 'Lennie', + 'Tramaine', + 'Nadir', + 'Timur', + 'Keshav', + 'Malek', + 'Ozzie', + 'Dresden', + 'Eliah', + 'Benaiah', + 'Muhsin', + 'Walt', + 'Damen', + 'Enoc', + 'Giancarlos', + 'Darsh', + 'Maximilliano', + 'Yaniel', + 'Jeevan', + 'Malakhi', + 'Viggo', + 'Karlo', + 'Yosgar', + 'Xavior', + 'Frazier', + 'Orin', + 'Payson', + 'Tonatiuh', + 'Amando', + 'Angad', + 'Gibran', + 'Eben', + 'Deaundre', + 'Rajon', + 'Anand', + 'Andree', + 'Dany', + 'Kayvon', + 'Joell', + 'Jahsiah', + 'Rosaire', + 'Kc', + 'Page', + 'Salvadore', + 'Arjen', + 'Torey', + 'Manraj', + 'Lyam', + 'Mazen', + 'Autry', + 'Coopar', + 'Ranveer', + 'Santhiago', + 'Ronen', + 'Remmy', + 'Kamauri', + 'Andra', + 'Sohan', + 'Cayetano', + 'Jarrad', + 'Fortunato', + 'Magdaleno', + 'Dorman', + 'Cesario', + 'Doroteo', + 'Roddy', + 'Matilde', + 'Lafayette', + 'Edelmiro', + 'Higinio', + 'Yancy', + 'Zvi', + 'Pascal', + 'Timm', + 'Dickey', + 'Spiros', + 'Georgios', + 'Jarid', + 'Johnatho', + 'Nachum', + 'Efrem', + 'Stafford', + 'Pajtim', + 'Amelia', + 'Jada', + 'Lily', + 'Lydia', + 'Sherrod', + 'Stedman', + 'Ardis', + 'Levy', + 'Ulysse', + 'Zalman', + 'Marquette', + 'Gabe', + 'Blaize', + 'Ashanti', + 'Shaheem', + 'Hervey', + 'Abbott', + 'Boleslaw', + 'Tyshon', + 'Kimani', + 'Beecher', + 'Diquan', + 'Eulogio', + 'Arvel', + 'Kennth', + 'Benigno', + 'Luz', + 'Dionisio', + 'Eustacio', + 'Trino', + 'Eldred', + 'Primitivo', + 'Perfecto', + 'Delma', + 'Cosme', + 'Milburn', + 'Shameek', + 'Quayshaun', + 'Evert', + 'Green', + 'Brylan', + 'Crit', + 'Haskel', + 'Ancil', + 'Rayhan', + 'Rose', + 'Gianfranco', + 'Matan', + 'Derin', + 'Artem', + 'Abhiram', + 'Yovanni', + 'Stevenson', + 'Crue', + 'Krue', + 'Jethro', + 'Jakai', + 'Mattix', + 'Daxon', + 'Dallan', + 'Murl', + 'Harsh', + 'Uzziel', + 'Kemarion', + 'Jashaun', + 'Rodman', + 'Elie', + 'Desi', + 'Malikai', + 'Angello', + 'Amogh', + 'Advaith', + 'Adryan', + 'Nazareth', + 'Adolf', + 'Bosco', + 'Arshan', + 'Abdulaziz', + 'Theseus', + 'Riaan', + 'Reza', + 'Radley', + 'Mars', + 'Kirin', + 'Kiaan', + 'Evander', + 'Indiana', + 'Hanson', + 'Viliami', + 'Jaydenn', + 'Ilya', + 'Draco', + 'Riyan', + 'Onyx', + 'Xian', + 'Khristopher', + 'Ayrton', + 'Aurelius', + 'Crosley', + 'Obadiah', + 'Nihal', + 'Rithvik', + 'Constantino', + 'Jeyden', + 'Jaycee', + 'Bane', + 'Aakash', + 'Aniket', + 'Mathis', + 'Maximos', + 'Kohl', + 'Fuquan', + 'Rahman', + 'Aziel', + 'Alexys', + 'Iverson', + 'Marck', + 'Criss', + 'Arsen', + 'Angelgabriel', + 'Ronak', + 'Selvin', + 'Ibraheem', + 'Yordi', + 'Taylen', + 'Javari', + 'Jairus', + 'Hamzah', + 'Sacha', + 'Nayan', + 'Marciano', + 'Aneesh', + 'Manfred', + 'Adal', + 'Bernhard', + 'Jeovanny', + 'Satvik', + 'Nicolo', + 'Julious', + 'Weyman', + 'Roswell', + 'Brevin', + 'Amedeo', + 'Deforest', + 'Barnett', + 'Braydin', + 'Italo', + 'Adrienne', + 'Anne', + 'Jr', + 'Krystal', + 'Brion', + 'Wilberto', + 'Detrick', + 'Bucky', + 'Kristin', + 'Christohper', + 'Laddie', + 'Creighton', + 'Gust', + 'Darby', + 'Shanon', + 'Darious', + 'Josua', + 'Thang', + 'Demarkus', + 'Chistopher', + 'Ehren', + 'Marlo', + 'Matas', + 'Augusto', + 'Diamonte', + 'Maciej', + 'Jamon', + 'Marcin', + 'Valdemar', + 'Nickey', + 'Niam', + 'Ambrosio', + 'Crispin', + 'Lukasz', + 'Yazan', + 'Romell', + 'Darryle', + 'Renard', + 'Ewald', + 'Quint', + 'Andrzej', + 'Vittorio', + 'Keonte', + 'Lavonte', + 'Cordale', + 'Darvin', + 'Marvell', + 'Krzysztof', + 'Corben', + 'Keylan', + 'Haydon', + 'Ociel', + 'Zeth', + 'Ahmari', + 'Texas', + 'Yutaka', + 'Isami', + 'Adarius', + 'Juaquin', + 'Jaydn', + 'Jaidan', + 'Exavier', + 'Steffan', + 'Vahe', + 'Crystian', + 'Edilberto', + 'Jaquavion', + 'Xavien', + 'Delvon', + 'Otoniel', + 'Demontae', + 'Collins', + 'Keoki', + 'Nolberto', + 'Leng', + 'Karina', + 'Grigor', + 'Isrrael', + 'Kaoru', + 'Hisao', + 'Masayoshi', + 'Satoru', + 'Satoshi', + 'Nobuo', + 'Michaelanthony', + 'Lucero', + 'Jocelyn', + 'Yovany', + 'Joangel', + 'Jaelyn', + 'Caedmon', + 'Granger', + 'Heston', + 'Rhodes', + 'Kanon', + 'Judith', + 'Montavius', + 'Antron', + 'Xaiden', + 'Burhanuddin', + 'Stratton', + 'Kadence', + 'Jhett', + 'Jacion', + 'Aiyden', + 'Journey', + 'Jaziah', + 'Thien', + 'Travious', + 'Carsyn', + 'Quindarius', + 'Masyn', + 'Jalan', + 'Jaelin', + 'Dorien', + 'Aarron', + 'Dmarcus', + 'Ramin', + 'Christan', + 'Blain', + 'Rosa', + 'Christoher', + 'Vadim', + 'Martha', + 'Osher', + 'Laakea', + 'Chayton', + 'Keahi', + 'Johnatan', + 'Juanantonio', + 'Kahiau', + 'Sheridan', + 'Samual', + 'Luisalberto', + 'Zacharias', + 'Phi', + 'Marquice', + 'Chong', + 'Harpreet', + 'Fue', + 'Derrion', + 'Eber', + 'Kevion', + 'Beryl', + 'Gavan', + 'Liliana', + 'Fernie', + 'Sulo', + 'Jayren', + 'Lior', + 'Ruth', + 'Carlie', + 'Thierno', + 'Davontae', + 'Jamier', + 'Arye', + 'Kiernan', + 'Hanad', + 'Huston', + 'Winson', + 'Hobson', + 'Yates', + 'Kaua', + 'Einar', + 'Berish', + 'Annie', + 'Mahir', + 'Amr', + 'Sabir', + 'Ewell', + 'Orland', + 'Dujuan', + 'Harvie', + 'Dahmir', + 'Hosea', + 'Haneef', + 'Wei', + 'Nello', + 'Fishel', + 'Amere', + 'Rafi', + 'Charlton', + 'Colden', + 'Hughes', + 'Laurier', + 'Blong', + 'Shimshon', + 'Jahmel', + 'Steward', + 'Milbert', + 'Buel', + 'Hallie', + 'Comer', + 'Tafari', + 'Iver', + 'Evangelos', + 'Jaquarius', + 'Azan', + 'Braedan', + 'Jadarrius', + 'Vernie', + 'Andi', + 'Darry', + 'Jawad', + 'Uri', + 'Kennard', + 'Yishai', + 'Kijana', + 'Brekken', + 'Rajan', + 'Stevens', + 'Sunil', + 'Siddhant', + 'Sir', + 'Sire', + 'Jansen', + 'Theodor', + 'Kaedyn', + 'Tymere', + 'Zyair', + 'Tron', + 'Sanchez', + 'Amaru', + 'Anastasio', + 'Agastya', + 'Hawk', + 'Honor', + 'Sotero', + 'Saeed', + 'Ziggy', + 'Conan', + 'Arie', + 'Gloria', + 'Onesimo', + 'Wellington', + 'Alexei', + 'Tavarus', + 'Cayleb', + 'Arion', + 'Amadeus', + 'Bryer', + 'Jeter', + 'Merced', + 'Kaylon', + 'Lakendrick', + 'Nolen', + 'Niccolo', + 'Halston', + 'Deontre', + 'Ash', + 'Arush', + 'Artur', + 'Bidwell', + 'Tomie', + 'Author', + 'Izik', + 'Jeriah', + 'Edwyn', + 'Zhi', + 'Gilman', + 'Jawan', + 'Bryar', + 'Giles', + 'Talha', + 'Gill', + 'Abelino', + 'Kwasi', + 'Stavros', + 'Juanita', + 'Tri', + 'Consuelo', + 'Khambrel', + 'Peterson', + 'Brantly', + 'Brently', + 'Vitaliy', + 'Hashim', + 'Rain', + 'Quintus', + 'Matthieu', + 'Kayne', + 'Icker', + 'Valen', + 'Nels', + 'Josephus', + 'Nasario', + 'Romulo', + 'Kaisen', + 'Sulaiman', + 'Selim', + 'Mahad', + 'Steele', + 'Stryder', + 'Cristina', + 'Thornton', + 'Girard', + 'Prudencio', + 'Ethaniel', + 'Laurent', + 'Jayvin', + 'Jayveon', + 'Eladio', + 'Ellison', + 'Caius', + 'Christiano', + 'Navid', + 'Gerold', + 'Sven', + 'Advay', + 'Cabell', + 'Marcio', + 'Luisalfredo', + 'Ryatt', + 'Elijio', + 'Pax', + 'Neev', + 'Mehtab', + 'Eluterio', + 'Tahmir', + 'Davit', + 'Eliott', + 'Keane', + 'Kysen', + 'Rafe', + 'Legacy', + 'Erie', + 'Orlin', + 'Dawn', + 'Calum', + 'Adithya', + 'Adarsh', + 'Ulysee', + 'Thurmond', + 'Christen', + 'Thayne', + 'Sriram', + 'Yoav', + 'Lawton', + 'Kemar', + 'Duston', + 'Jatavious', + 'Luisfernando', + 'Maxime', + 'Rithik', + 'Dior', + 'Phuong', + 'Roni', + 'Manu', + 'Esteven', + 'Hazen', + 'Farris', + 'Leverne', + 'Ryen', + 'Tanay', + 'Seaborn', + 'Cicero', + 'Gianmarco', + 'Isak', + 'Lige', + 'Burke', + 'Authur', + 'Javarius', + 'Jeromie', + 'Jerred', + 'Silvano', + 'Keyan', + 'Briant', + 'Arun', + 'Jeremi', + 'Decarlos', + 'Jeanpierre', + 'Haydn', + 'Ab', + 'Anmol', + 'Shaye', + 'Nana', + 'Mateen', + 'Maurisio', + 'Nitin', + 'Dustan', + 'Srikar', + 'Arlin', + 'Burnett', + 'Johnathen', + 'Wyman', + 'Aleksandar', + 'Agustine', + 'Ronney', + 'Marisol', + 'Dmarion', + 'Keir', + 'Demetrice', + 'Jawon', + 'Ricci', + 'Javontae', + 'Armoni', + 'Alto', + 'Dawid', + 'Zakir', + 'Jarek', + 'Lary', + 'Dez', + 'Kaydon', + 'Henley', + 'Adonai', + 'Zahmir', + 'Youssouf', + 'Oisin', + 'Deniz', + 'Antonios', + 'Netanel', + 'Shlok', + 'Ranger', + 'Uzziah', + 'Eryk', + 'Sid', + 'Andersen', + 'Daylin', + 'Naftoli', + 'Lyn', + 'Orvin', + 'Kesean', + 'Hanif', + 'Adael', + 'Maury', + 'Ronn', + 'Carlyle', + 'Ankur', + 'Takumi', + 'Piero', + 'Jeanpaul', + 'Hoa', + 'Jacarri', + 'Jakhi', + 'Zyion', + 'Jeovany', + 'Eoin', + 'Etienne', + 'Amrit', + 'Dang', + 'Juliano', + 'Blakely', + 'Tauno', + 'Edin', + 'Dmitriy', + 'Lambert', + 'Roderic', + 'Felice', + 'Zaki', + 'Debra', + 'Teegan', + 'Tosh', + 'Nicholai', + 'Erickson', + 'Atharva', + 'Aaditya', + 'Anuj', + 'Diane', + 'Sachin', + 'Elazar', + 'Torian', + 'Tan', + 'Cristoval', + 'Jonathen', + 'Kobi', + 'Yuki', + 'Jacori', + 'Eduard', + 'Keron', + 'Tysean', + 'Deshun', + 'Hewitt', + 'Kaulana', + 'Jaydyn', + 'Sebastia', + 'Shamell', + 'Trysten', + 'Treshawn', + 'Samer', + 'Burnice', + 'Da', + 'Parris', + 'Royer', + 'Tien', + 'Tj', + 'Andranik', + 'Nino', + 'Luisenrique', + 'Andrick', + 'Graydon', + 'Pookela', + 'Nevaeh', + 'Zoe', + 'Hanna', + 'Joniel', + 'Jamarious', + 'Hurley', + 'Avante', + 'Iban', + 'Isaiha', + 'Chee', + 'Kealii', + 'Irbin', + 'Maynor', + 'Wendy', + 'Germain', + 'Shamus', + 'Zygmunt', + 'Garnet', + 'Lopaka', + 'Damar', + 'Ramy', + 'Everton', + 'Raylen', + 'Tryston', + 'Kullen', + 'Therman', + 'Khaliq', + 'Alon', + 'Arch', + 'Tylen', + 'Kalan', + 'Zacharia', + 'Dalen', + 'Bedford', + 'Lou', + 'Tsuneo', + 'Kalub', + 'Dadrian', + 'Jiro', + 'Fahad', + 'Quashawn', + 'Hisashi', + 'Fumio', + 'Carlito', + 'Ewing', + 'Zarek', + 'Leron', + 'Cardell', + 'Westen', + 'Hogan', + 'Payden', + 'Chazz', + 'Jarryd', + 'Sedric', + 'Homar', + 'Tylar', + 'Keone', + 'Dasean', + 'Lake', + 'Joeanthony', + 'Haroon', + 'Adonys', + 'Grayling', + 'Braelon', + 'Loras', + 'Jontavious', + 'Nesanel', + 'Carlisle', + 'Camillo', + 'Mandeep', + 'Yang', + 'Blayden', + 'Niall', + 'Evelio', + 'Zaragoza', + 'Shlomie', + 'Percell', + 'Baylee', + 'Garold', + 'Eriq', + 'Ozell', + 'Benjiman', + 'Wayman', + 'Saturnino', + 'Moody', + 'Deandra', + 'Estanislado', + 'Curvin', + 'Demonta', + 'Crimson', + 'Scout', + 'Daequan', + 'Izael', + 'Trine', + 'Demontre', + 'Rexford', + 'Fenix', + 'Raheim', + 'Rivers', + 'Cobe', + 'Jeron', + 'Yanuel', + 'Naftula', + 'Dwan', + 'Kanai', + 'Nicco', + 'Kaeson', + 'Shadman', + 'Cobi', + 'Raequan', + 'Shae', + 'Osama', + 'Ernan', + 'Dennys', + 'Aquil', + 'Tierra', + 'Sabrina', + 'Mia', + 'Melanie', + 'Marissa', + 'Carolyn', + 'Arielle', + 'Zaine', + 'Macen', + 'Shahin', + 'Casyn', + 'Osmin', + 'Alphonsus', + 'Carrington', + 'Chayce', + 'Opal', + 'Taylon', + 'Koy', + 'Ebenezer', + 'Amarii', + 'Keshun', + 'Kolin', + 'Aspen', + 'Cort', + 'Zaylon', + 'Zaedyn', + 'Zaydyn', + 'Tuff', + 'Holton', + 'Ashtyn', + 'Lathen', + 'Hershell', + 'Jerre', + 'Tsugio', + 'Josealberto', + 'Adien', + 'Acen', + 'Maurilio', + 'Ashten', + 'Wataru', + 'Keontae', + 'Donaven', + 'Javonta', + 'Jacobie', + 'Peng', + 'Ector', + 'Ankit', + 'Ann', + 'Kasim', + 'Parley', + 'Mizael', + 'Maxon', + 'Kylar', + 'Jjesus', + 'Kaven', + 'Curran', + 'Edvin', + 'Enrrique', + 'Donovin', + 'Godfrey', + 'Xayden', + 'Xzavian', + 'Carlosmanuel', + 'Ladainian', + 'Keithan', + 'Azrael', + 'Jae', + 'Marlow', + 'Aviv', + 'Orson', + 'Zamarion', + 'Chason', + 'Henrry', + 'Gevorg', + 'Dartagnan', + 'Zakee', + 'Giovannie', + 'Halen', + 'Vinay', + 'Wilfrido', + 'Winton', + 'Garet', + 'Josafat', + 'Manjot', + 'Juandaniel', + 'Manley', + 'Oshea', + 'Wali', + 'Reymond', + 'Harjot', + 'Sidharth', + 'Amer', + 'Camari', + 'Quincey', + 'Dawan', + 'Newell', + 'Sigurd', + 'Logen', + 'Rafiq', + 'Delonta', + 'Katrina', + 'Kristina', + 'Octavia', + 'Sade', + 'Ziyad', + 'Tovia', + 'Malachai', + 'Briana', + 'Alison', + 'Ashleigh', + 'Jerick', + 'Benedetto', + 'Fiore', + 'Mikail', + 'Qasim', + 'Yochanan', + 'Ettore', + 'Ferris', + 'Aziz', + 'Naseer', + 'Jabril', + 'Brodey', + 'Alvah', + 'Kalman', + 'Ziyon', + 'Zakery', + 'Sedale', + 'Jevin', + 'Kalmen', + 'Moishy', + 'Shai', + 'Zakari', + 'Bradlee', + 'Kenley', + 'Pratham', + 'Izeah', + 'Ilias', + 'Emari', + 'Race', + 'Zacarias', + 'Yuri', + 'Kleber', + 'Kailer', + 'Jhovany', + 'Iven', + 'Issaiah', + 'Hosie', + 'Dixon', + 'Massiah', + 'Remo', + 'Pinchos', + 'Mahki', + 'Gunther', + 'Irene', + 'Jamarie', + 'Kaan', + 'Jayon', + 'Moroni', + 'Jkwon', + 'Barack', + 'Alastair', + 'Fares', + 'Zackariah', + 'Yoshua', + 'Tanish', + 'Iann', + 'Linden', + 'Avinash', + 'Willam', + 'Iman', + 'Domanic', + 'Lenton', + 'Samad', + 'Aimar', + 'Buddie', + 'Jozef', + 'Josmar', + 'Mercer', + 'Collie', + 'Nephi', + 'Kenai', + 'Alquan', + 'Cezar', + 'Verbon', + 'Aeneas', + 'Jeremyah', + 'Eren', + 'Tej', + 'Jahad', + 'Deep', + 'Augusta', + 'Yaqub', + 'Yahye', + 'Vashon', + 'Kristoff', + 'Penn', + 'Loukas', + 'Kaydin', + 'Kaius', + 'Perseus', + 'Mykah', + 'Joab', + 'Cylus', + 'Emrys', + 'Mikko', + 'Jaxsyn', + 'Sudais', + 'Tiberius', + 'Rooney', + 'Yuvan', + 'Cletis', + 'Liev', + 'Ester', + 'Harlow', + 'Shreyan', + 'Samar', + 'Saharsh', + 'Ruhaan', + 'Zyler', + 'Yuma', + 'Dwyane', + 'Yanni', + 'Dutch', + 'Rajveer', + 'Tayton', + 'Kasir', + 'Luster', + 'Tage', + 'Damarius', + 'Elihu', + 'Heinz', + 'Manolo', + 'Makhai', + 'Madhav', + 'Sohum', + 'Omri', + 'Egbert', + 'Marie', + 'Keshon', + 'Jahmier', + 'Nachmen', + 'Mckade', + 'Moise', + 'Ames', + 'Iden', + 'Benard', + 'Yannick', + 'Pasha', + 'Sherrick', + 'Jordany', + 'Fenton', + 'Tytan', + 'Dashel', + 'Daksh', + 'Juliani', + 'Jhonathan', + 'Broxton', + 'Essie', + 'Devontay', + 'Maksym', + 'Park', + 'Dasani', + 'Severiano', + 'Kamel', + 'Chayanne', + 'Jarel', + 'Yolanda', + 'Tylik', + 'Marquell', + 'Jamarr', + 'Micky', + 'Socorro', + 'Waymond', + 'Michial', + 'Yoseph', + 'Lumir', + 'Placido', + 'Asif', + 'Needham', + 'Claiborne', + 'Tennis', + 'Burley', + 'Raffaele', + 'Shavar', + 'Atanacio', + 'Jahmar', + 'Arben', + 'Nabeel', + 'Cordarryl', + 'Danyal', + 'Bryston', + 'Lemont', + 'Elston', + 'Kerwin', + 'Riccardo', + 'Danzel', + 'Waldemar', + 'Ledarius', + 'Omarr', + 'Wilho', + 'Alger', + 'Raymie', + 'Kenney', + 'Abdallah', + 'Aristides', + 'Avram', + 'Tayvion', + 'Urbano', + 'Deontay', + 'Darcy', + 'Robbin', + 'Bartlomiej', + 'Dann', + 'Tyjuan', + 'Khaleel', + 'Winifred', + 'Claron', + 'Linford', + 'Hilliard', + 'Arlon', + 'Yong', + 'Malvin', + 'Zymere', + 'Newborn', + 'Eleuterio', + 'Glyn', + 'Koltyn', + 'Serapio', + 'Pius', + 'Ines', + 'Harrold', + 'Caitlyn', + 'Rajeev', + 'Constantinos', + 'Abid', + 'Calvert', + 'Parnell', + 'Aubry', + 'Damone', + 'Akim', + 'Adem', + 'Othel', + 'Joaopedro', + 'Tomer', + 'Brentlee', + 'Melquan', + 'Elpidio', + 'Jenny', + 'Alejos', + 'Romie', + 'Ardell', + 'Doctor', + 'Virginia', + 'Makenzie', + 'Maggie', + 'Tywan', + 'Elisaul', + 'Luby', + 'Teofilo', + 'Jermell', + 'Gumesindo', + 'Harless', + 'Croix', + 'Obinna', + 'Traveon', + 'Coley', + 'Tu', + 'Brylon', + 'Carlin', + 'Daneil', + 'Garen', + 'Ronell', + 'Chesley', + 'Tyrece', + 'Arville', + 'Eamonn', + 'Kayshawn', + 'Wilkie', + 'Zacchaeus', + 'Rapheal', + 'Cordaryl', + 'Quan', + 'Nhan', + 'Vann', + 'Franciscojavier', + 'Kinte', + 'Rui', + 'Chuong', + 'Chao', + 'Chai', + 'Linh', + 'Cirilo', + 'Ky', + 'Gwyn', + 'Hearl', + 'Tray', + 'Carmon', + 'Phuc', + 'Neiman', + 'Ladon', + 'Moua', + 'Eulises', + 'Jonte', + 'Yusuke', + 'Vinnie', + 'Seanpatrick', + 'Pearson', + 'Daemon', + 'Reyn', + 'Daekwon', + 'Garron', + 'Sequan', + 'Zavien', + 'Geovanie', + 'Jessee', + 'Richmond', + 'Osualdo', + 'Artin', + 'Devone', + 'Makoto', + 'Hitoshi', + 'Shinichi', + 'Samari', + 'Saxon', + 'Glennis', + 'Fadi', + 'Bronislaw', + 'Estuardo', + 'Shaheen', + 'Saman', + 'Lue', + 'Djuan', + 'Cord', + 'Linville', + 'Landis', + 'Cameren', + 'Herson', + 'Ellie', + 'Seanmichael', + 'Froilan', + 'Delon', + 'Jestin', + 'Mattew', + 'Toni', + 'Kelii', + 'Maribel', + 'Jadrian', + 'Traylon', + 'Kaiea', + 'Kaeo', + 'Taft', + 'Dameion', + 'Darryn', + 'Dondi', + 'Clell', + 'Corbett', + 'Lyndell', + 'Avenir', + 'Seldon', + 'Jakwon', + 'Jacque', + 'Deane', + 'Cheikh', + 'Carmel', + 'Kieth', + 'Tahmid', + 'Lillard', + 'Tasheem', + 'Jens', + 'Christobal', + 'Delos', + 'Lashon', + 'Jaimie', + 'Kary', + 'Kendarious', + 'Johnell', + 'Harlen', + 'Terron', + 'Corliss', + 'Liston', + 'Seng', + 'Phu', + 'Rasean', + 'Sung', + 'San', + 'Babak', + 'Adel', + 'Gillermo', + 'Avon', + 'Harlon', + 'Allyn', + 'Clary', + 'Orry', + 'Nazario', + 'Jamail', + 'Daeshawn', + 'Tal', + 'Moustafa', + 'Tarell', + 'Jahquan', + 'Jian', + 'Lazar', + 'Adama', + 'Benyamin', + 'Tayvon', + 'Lamel', + 'Davonne', + 'Tayquan', + 'Jusitn', + 'Shjon', + 'Leotis', + 'Kasheem', + 'Ilir', + 'Ravon', + 'Parish', + 'Ehan', + 'Daishawn', + 'Islam', + 'Pinches', + 'Ovadia', + 'Mechel', + 'Berlin', + 'Deryk', + 'Tymel', + 'Vijay', + 'Dyquan', + 'Agron', + 'Tarrell', + 'Itamar', + 'Mordcha', + 'Chrisotpher', + 'Alban', + 'Stephane', + 'Tanvir', + 'Demetriu', + 'Yan', + 'Asim', + 'Ahsan', + 'Mackenzi', + 'Kristofe', + 'Kenrick', + 'Cuahutemoc', + 'Tavis', + 'Audric', + 'Deaven', + 'Nicanor', + 'Mick', + 'Geoffery', + 'Timofey', + 'Dolphus', + 'Franciso', + 'Gorje', + 'Jobany', + 'Abdelrahman', + 'Clenton', + 'Yohance', + 'Milad', + 'Juanluis', + 'Luismario', + 'Marvyn', + 'Rushil', + 'Tenoch', + 'Trentin', + 'Fardeen', + 'Shashank', + 'Yuta', + 'Ritvik', + 'Akili', + 'Aleksei', + 'Gaurav', + 'Iran', + 'Caillou', + 'Borach', + 'Keisuke', + 'Kaushik', + 'Hari', + 'Izac', + 'Josejulian', + 'Juanangel', + 'Kasra', + 'Anthonie', + 'Daivd', + 'Dain', + 'Toren', + 'Sesar', + 'Eldor', + 'Pieter', + 'Yu', + 'Cloyce', + 'Dusten', + 'Aquiles', + 'Aslan', + 'Sevastian', + 'Siddarth', + 'Tysen', + 'Johncarlo', + 'Idan', + 'Daymian', + 'Domanick', + 'Arnie', + 'Bartley', + 'Newman', + 'Akram', + 'Abdulla', + 'Lew', + 'Geremy', + 'Jehu', + 'Josejuan', + 'Jailen', + 'Etai', + 'Fabien', + 'Victormanuel', + 'Ossie', + 'Egan', + 'Eldin', + 'Shamari', + 'Nussen', + 'Arda', + 'Sina', + 'Tytus', + 'Pranay', + 'Dylen', + 'Juandavid', + 'Kalil', + 'Kushal', + 'Hazael', + 'Lecil', + 'Belton', + 'Aleczander', + 'Terance', + 'Faizan', + 'Naithan', + 'Koji', + 'Akshat', + 'Andruw', + 'Bram', + 'Dieter', + 'Saahil', + 'Saulo', + 'Arnel', + 'Demarea', + 'Farhad', + 'Joeseph', + 'Alondra', + 'Belal', + 'Antoniodejesus', + 'Anival', + 'Choua', + 'Cha', + 'Bryn', + 'Xiong', + 'Aristeo', + 'Mehmet', + 'Moustapha', + 'Jandel', + 'Asante', + 'Yunus', + 'Schneur', + 'Steffen', + 'Leovardo', + 'Kacey', + 'Payam', + 'Salbador', + 'Nicholes', + 'Neema', + 'Clarke', + 'Marqus', + 'Araceli', + 'Jerman', + 'Marioalberto', + 'Joseguadalupe', + 'Emigdio', + 'Krishan', + 'Jessey', + 'Arcadio', + 'Zong', + 'Yoni', + 'Tirso', + 'Thompson', + 'Damarea', + 'Everado', + 'Edy', + 'Edder', + 'Nikki', + 'Clemmie', + 'Willian', + 'Marquese', + 'Perris', + 'Miriam', + 'Shelly', + 'Bulmaro', + 'Jasdeep', + 'Irvine', + 'Hue', + 'Gurpreet', + 'Donaldo', + 'Jonthan', + 'Geroge', + 'Francois', + 'Duc', + 'Jerico', + 'Avedis', + 'Chang', + 'Damario', + 'Kenta', + 'Nikkolas', + 'Khoi', + 'Garren', + 'Norma', + 'My', + 'Lam', + 'Sahir', + 'Yer', + 'Jaskarn', + 'Jeric', + 'Maximillion', + 'Elson', + 'Marin', + 'Loc', + 'Lemar', + 'Kristofor', + 'Nai', + 'Takoda', + 'Tung', + 'Thong', + 'Rayshaun', + 'Derreck', + 'Regino', + 'Nadav', + 'Luismiguel', + 'Josede', + 'Hao', + 'Rayce', + 'Zacary', + 'Nareg', + 'Khyree', + 'Chi', + 'Joanna', + 'Sevag', + 'Garin', + 'Juluis', + 'Petros', + 'Berel', + 'Abubakar', + 'Jorel', + 'Kazi', + 'Jaiceon', + 'Haider', + 'Feynman', + 'Muhammadali', + 'Jassiel', + 'Morrison', + 'Nakai', + 'Oden', + 'Odysseus', + 'Quest', + 'Kaidan', + 'Kilian', + 'Kirill', + 'Thorin', + 'Tru', + 'Xzander', + 'Taniela', + 'Roen', + 'Sho', + 'Aarin', + 'Gracen', + 'Gurfateh', + 'Gurman', + 'Hiro', + 'Edrick', + 'Esaias', + 'Johncarlos', + 'Sidi', + 'Cataldo', + 'Noor', + 'Philbert', + 'Eyad', + 'Arber', + 'Abrar', + 'Ladislaus', + 'Serafino', + 'Mannie', + 'Daevon', + 'Haseeb', + 'Yale', + 'Spiro', + 'Emre', + 'Daryan', + 'Camrin', + 'Kavi', + 'Doran', + 'Vaibhav', + 'Rayne', + 'Derric', + 'Orbie', + 'Reily', + 'Gio', + 'Gurnoor', + 'Jaasiel', + 'Naman', + 'Josaiah', + 'Josiyah', + 'Kasper', + 'Filippo', + 'Sigfredo', + 'Joesiah', + 'Rei', + 'Nahom', + 'Ojas', + 'Vladislav', + 'Hilary', + 'Rinaldo', + 'Even', + 'Gautam', + 'Cornel', + 'Julyan', + 'Inaki', + 'Iseah', + 'Itai', + 'Laurance', + 'Garey', + 'Lawerance', + 'Quindon', + 'Levin', + 'Leviticus', + 'Link', + 'Glenford', + 'Avyan', + 'Dmitry', + 'Eiden', + 'Advait', + 'Ahaan', + 'Arhaan', + 'Kassius', + 'Hendrick', + 'Jaiveer', + 'Nirvaan', + 'Reeve', + 'Torsten', + 'True', + 'Iwao', + 'Jahvon', + 'Paxson', + 'Kali', + 'Kwesi', + 'Yaron', + 'Ami', + 'Dashiel', + 'Meliton', + 'Sylus', + 'Mika', + 'Jireh', + 'Selig', + 'Adi', + 'Brenner', + 'Breyden', + 'Mitsuru', + 'Farley', + 'Montrel', + 'Kyland', + 'Jadakiss', + 'Tadarius', + 'Brooke', + 'Alexandria', + 'Alexa', + 'Abby', + 'Hayley', + 'Mallory', + 'Madelyn', + 'Layla', + 'Kirsten', + 'Quayshawn', + 'Deadrick', + 'Hobby', + 'Eunice', + 'Macon', + 'Ysabel', + 'Secundino', + 'Hulen', + 'Estle', + 'Tolbert', + 'Baker', + 'Tilford', + 'Shyheem', + 'Orbin', + 'Ruel', + 'Hurshel', + 'Jailyn', + 'Dequincy', + 'Jamall', + 'Draper', + 'Kenric', + 'Aime', + 'Cam', + 'Connell', + 'Treylon', + 'Bethel', + 'Rommie', + 'Alphonza', + 'Gussie', + 'Elridge', + 'Hillery', + 'Ruffin', + 'Farrel', + 'Wendall', + 'Gerome', + 'Ferrell', + 'Uvaldo', + 'Marshon', + 'Jawaun', + 'Trevell', + 'Tyvon', + 'Telesforo', + 'Ellery', + 'Cordae', + 'Loran', + 'Travell', + 'Lamari', + 'Errick', + 'Antwoine', + 'Starsky', + 'Chirag', + 'Donzell', + 'Tierre', + 'Ketan', + 'Crespin', + 'Orris', + 'Bawi', + 'Wanda', + 'Canuto', + 'Aniceto', + 'Braxten', + 'Audry', + 'Bartolo', + 'Brigido', + 'Garvin', + 'Vergil', + 'Olegario', + 'Thelma', + 'Crecencio', + 'Eleno', + 'Wright', + 'Burtis', + 'Dicky', + 'Avelino', + 'Norval', + 'Cirildo', + 'Darwyn', + 'Delwin', + 'Henery', + 'Beauford', + 'Little', + 'Ameir', + 'Arland', + 'Verner', + 'Taron', + 'Undra', + 'Khasir', + 'Kymir', + 'Aleem', + 'Ordean', + 'Carmino', + 'Lucus', + 'Jodeci', + 'Linn', + 'Sinclair', + 'Delorean', + 'Chalmers', + 'Kentavius', + 'Jarious', + 'Lajuan', + 'Narada', + 'Hussien', + 'Alonte', + 'Damarco', + 'Benjamen', + 'Randon', + 'Jabree', + 'Lawyer', + 'Wanya', + 'Samie', + 'Sim', + 'Washington', + 'Isom', + 'Keyton', + 'Quin', + 'Mahamed', + 'Liban', + 'Ramir', + 'Samaj', + 'Kipp', + 'Prentis', + 'Jibril', + 'Kyaire', + 'Buell', + 'Nasim', + 'Adell', + 'Mohamedamin', + 'Abdiaziz', + 'Harun', + 'Amire', + 'Eligah', + 'Parks', + 'Colonel', + 'Joaovictor', + 'Vinicius', + 'Mcdonald', + 'Manly', + 'Phares', + 'Geza', + 'Kemp', + 'Alphonzo', + 'Loring', + 'Haig', + 'Joaquim', + 'Craven', + 'Bynum', + 'Parke', + 'Ignatz', + 'Hebert', + 'Berton', + 'Ayomide', + 'Kidus', + 'Ayven', + 'Aziah', + 'Banner', + 'Barret', + 'Blayze', + 'Braddock', + 'Javoris', + 'Cortland', + 'Antavius', + 'Amaziah', + 'Santonio', + 'Slate', + 'Sylis', + 'Thierry', + 'Joanthony', + 'Rhylan', + 'Pryce', + 'Riggin', + 'Dequavious', + 'Bakari', + 'Marquavius', + 'Artavious', + 'Desmon', + 'Rajohn', + 'Faheem', + 'Kage', + 'Arkeem', + 'Jaquon', + 'Dontavis', + 'Quentavious', + 'Braysen', + 'Bricen', + 'Traevon', + 'Caidyn', + 'Collyn', + 'Joah', + 'Patton', + 'Coleson', + 'Eythan', + 'Hadley', + 'Jaaziel', + 'Johntavious', + 'Quadarius', + 'Rafeal', + 'Karam', + 'Krishiv', + 'Majd', + 'Yeray', + 'Whitten', + 'Johnluke', + 'Demani', + 'Easten', + 'Ediel', + 'Tellis', + 'Delvecchio', + 'Aleks', + 'Rylie', + 'Osmel', + 'Lelan', + 'Tamarion', + 'Cayman', + 'Hajime', + 'Akio', + 'Takao', + 'Seiji', + 'Ah', + 'Mitsugi', + 'Koichi', + 'Ikenna', + 'Tyquavious', + 'Brannen', + 'Slayde', + 'Sultan', + 'Cage', + 'Jillian', + 'Kara', + 'Simone', + 'Theresa', + 'Julie', + 'Alisha', + 'Candace', + 'Candice', + 'Jazmine', + 'Domani', + 'Tiana', + 'Jeovanni', + 'Khaleb', + 'Copeland', + 'Dathan', + 'Deleon', + 'Jakori', + 'Jayke', + 'Kadon', + 'Camdon', + 'Shandon', + 'Mylan', + 'Jaxin', + 'Beverley', + 'Dallon', + 'Jakeem', + 'Tallon', + 'Vraj', + 'Welford', + 'Jadarian', + 'Yancarlos', + 'Omkar', + 'Jamaree', + 'Alix', + 'Trevyn', + 'Orestes', + 'Trevis', + 'Refoel', + 'Roddrick', + 'Tarvis', + 'Tamarick', + 'Denard', + 'Kerem', + 'Treyden', + 'Stephano', + 'Shubh', + 'Carston', + 'Utah', + 'Treven', + 'Reshard', + 'Yerachmiel', + 'Osmany', + 'Vansh', + 'Samaad', + 'Shakil', + 'Saford', + 'Doyal', + 'Cai', + 'Alexey', + 'Cruze', + 'Masiah', + 'Kitai', + 'Fedor', + 'Algie', + 'Worley', + 'Jakhari', + 'Brison', + 'Lanier', + 'Eston', + 'Qadir', + 'Lonzie', + 'Rayfield', + 'Chirstopher', + 'Eron', + 'Deontray', + 'Zoltan', + 'Christon', + 'Byford', + 'Mikeal', + 'Talyn', + 'Stormy', + 'Laramie', + 'Chrisopher', + 'Breckin', + 'Kennon', + 'Json', + 'Deiondre', + 'Heron', + 'Mykal', + 'Kalai', + 'Ervey', + 'Brayam', + 'Alakai', + 'Maika', + 'Kelson', + 'Trevaughn', + 'Aundre', + 'Eathan', + 'Keylon', + 'Kolbe', + 'Sebastion', + 'Kalib', + 'Jermy', + 'Jarrid', + 'Gumaro', + 'Maliq', + 'Armstead', + 'Stephone', + 'Oris', + 'Hassel', + 'Antwine', + 'Lorraine', + 'Budd', + 'Irfan', + 'Kamrin', + 'Araf', + 'Affan', + 'Leiby', + 'Sruly', + 'Peretz', + 'Mildred', + 'Louise', + 'Ryken', + 'Ryler', + 'Tayven', + 'Taysen', + 'Brexton', + 'Zayaan', + 'Oronde', + 'Firman', + 'Collen', + 'Letcher', + 'Clearence', + 'Braydan', + 'Yasser', + 'Jeferson', + 'Yahsir', + 'Cavan', + 'Ivor', + 'Hasker', + 'Kodie', + 'Lori', + 'Jaysean', + 'Cadin', + 'Breydon', + 'Amaree', + 'Nyeem', + 'Menno', + 'Orlo', + 'Nassir', + 'Sylar', + 'Drevon', + 'Burech', + 'Lenox', + 'Shloima', + 'Daris', + 'Diontae', + 'Aidin', + 'Brydon', + 'Jasean', + 'Nasier', + 'Johney', + 'Gabrial', + 'Fate', + 'Colyn', + 'Kaleem', + 'Capers', + 'Rembert', + 'Jquan', + 'Legrand', + 'Kirubel', + 'Gaberiel', + 'Thaddaeus', + 'Rece', + 'Dymir', + 'Tylil', + 'Remigio', + 'Ahad', + 'Melquiades', + 'Ethel', + 'Euel', + 'Harvy', + 'Margarita', + 'Jakeb', + 'Kagan', + 'Trinton', + 'Faiz', + 'Iliyan', + 'Emeterio', + 'Ferman', + 'Keeton', + 'Decorian', + 'Hadyn', + 'Rashaud', + 'Davontay', + 'Brallan', + 'Benancio', + 'Espiridion', + 'Seledonio', + 'Estefan', + 'Chanse', + 'Dade', + 'Sisto', + 'Herbie', + 'Janson', + 'Eusevio', + 'Loye', + 'Leocadio', + 'Kaelon', + 'Trevian', + 'Christien', + 'Chrystian', + 'Daegan', + 'Rosbel', + 'Romero', + 'Kylin', + 'Treyvion', + 'Ezekial', + 'Jaice', + 'Jantzen', + 'Aadyn', + 'Tennyson', + 'Kaedan', + 'Kaiser', + 'Kanin', + 'Jerron', + 'Jonaven', + 'Elija', + 'Amon', + 'Valton', + 'Derwood', + 'Atilano', + 'Jovanie', + 'Kaemon', + 'Oluwatobi', + 'Atlee', + 'Tadd', + 'Tammy', + 'Lem', + 'Hilmar', + 'Foch', + 'Clenard', + 'Jd', + 'Jiovanny', + 'Ladarion', + 'Lleyton', + 'Adrik', + 'Webb', + 'Toddrick', + 'Jerrett', + 'Omero', + 'Wendel', + 'Teresa', + 'Cass', + 'Kedric', + 'Heraclio', + 'Rainier', + 'Lakota', + 'Sanjuan', + 'Daymon', + 'Rodd', + 'Yancey', + 'Trampas', + 'Viviano', + 'Heith', + 'Bj', + 'Trevante', + 'Ildefonso', + 'Jaeger', + 'Jamarkus', + 'Remijio', + 'Desiderio', + 'Ausencio', + 'Alejo', + 'Keldrick', + 'Sigifredo', + 'Treavor', + 'Britain', + 'Macedonio', + 'Kourtney', + 'Gerrick', + 'Jousha', + 'Klinton', + 'Montreal', + 'Catlin', + 'Danner', + 'Eliberto', + 'Eliodoro', + 'Lonnell', + 'Michiel', + 'Hermilo', + 'Jackey', + 'Todrick', + 'Irineo', + 'Wenceslao', + 'Duaine', + 'Cleto', + 'Gaylan', + 'Derrel', + 'Nabor', + 'Huck', + 'Hoy', + 'Antwaun', + 'Hoyte', + 'Flournoy', + 'Mayford', + 'Harlie', + 'Hansford', + 'Cutler', + 'Amerigo', + 'Teague', + 'Griffith', + 'Emidio', + 'Kenna', + 'Cru', + 'Arnett', + 'Gay', + 'Dencil', + 'Carman', + 'Doy', + 'Trevan', + 'Jahziel', + 'Rodricus', + 'Copper', + 'Dael', + 'Aydon', + 'Ricco', + 'Judas', + 'Kessler', + 'Romelo', + 'Slayton', + 'Marico', + 'Leevi', + 'Xadrian', + 'Jceon', + 'Kross', + 'Chancey', + 'Bayne', + 'Brylen', + 'Eidan', + 'Olvin', + 'Pearce', + 'Zak', + 'Jaiven', + 'Dani', + 'Bairon', + 'Cordarious', + 'Jaxyn', + 'Rylin', + 'Avin', + 'Bransen', + 'Eastyn', + 'Eyden', + 'Brenham', + 'Chaston', + 'Horatio', + 'Dakarai', + 'Jencarlo', + 'Jevan', + 'Jhayden', + 'Tracen', + 'Peggy', + 'Wynn', + 'Bennet', + 'Milas', + 'Ronal', + 'Kadrian', + 'Jhase', + 'Callahan', + 'Hays', + 'Braidyn', + 'Ezana', + 'Chidubem', + 'Virat', + 'Maxemiliano', + 'Ozias', + 'Pace', + 'Mordecai', + 'Tabor', + 'Phillipe', + 'Maritza', + 'Ricahrd', + 'Jeanette', + 'Sundeep', + 'Tyric', + 'Mina', + 'Nasser', + 'Nhia', + 'Giuliano', + 'Farid', + 'Ryo', + 'Delmont', + 'Klaus', + 'Traquan', + 'Dawayne', + 'Broward', + 'Drequan', + 'Cagney', + 'Shellie', + 'Torre', + 'Deepak', + 'Janmichael', + 'Lan', + 'Quentavius', + 'Quantez', + 'Markevious', + 'Melbourne', + 'Melford', + 'Xue', + 'Samnang', + 'Jarquez', + 'Montrez', + 'Dao', + 'Luvern', + 'Vue', + 'Jenaro', + 'Wacey', + 'Lorena', + 'Ly', + 'Casmere', + 'Marsean', + 'Marinus', + 'Shiro', + 'Shizuo', + 'Knowledge', + 'Baudelio', + 'Cher', + 'Christiaan', + 'Adriane', + 'Wilgus', + 'Gustabo', + 'Barnet', + 'Xeng', + 'Priscilla', + 'Sou', + 'Sumeet', + 'Vartan', + 'Herschell', + 'Montell', + 'Illya', + 'Flem', + 'Marwan', + 'Johnrobert', + 'Boleslaus', + 'Christie', + 'Ericberto', + 'Esmeralda', + 'Cecilia', + 'Purvis', + 'Benjie', + 'Sutter', + 'Sufyan', + 'Viraaj', + 'Sathvik', + 'Quitman', + 'Liborio', + 'Humbert', + 'Zakariah', + 'Yichen', + 'Seward', + 'Alf', + 'Sebastiano', + 'Guiseppe', + 'Stanislaw', + 'Tyrice', + 'Lenell', + 'Kewon', + 'Bahe', + 'Recardo', + 'Paola', + 'Ronson', + 'Naveed', + 'Karla', + 'Lamberto', + 'Leoncio', + 'Sandor', + 'Diamante', + 'Woodson', + 'Hargis', + 'Kelcey', + 'Daquon', + 'Estell', + 'Christapher', + 'Jalal', + 'Tania', + 'Tramell', + 'Victoralfonso', + 'Kento', + 'Kiet', + 'Krystopher', + 'Shaine', + 'Bejamin', + 'Virgel', + 'Toxie', + 'Goebel', + 'Tyon', + 'Norvin', + 'Savalas', + 'Othmar', + 'Jakaiden', + 'Reis', + 'Pratik', + 'Ashish', + 'Hutson', + 'Karmello', + 'Dacari', + 'Katsuji', + 'Sadamu', + 'Masatoshi', + 'Kiyoto', + 'Carols', + 'Waylen', + 'Shain', + 'Alexandru', + 'Jomo', + 'Kalei', + 'Shyam', + 'Zyan', + 'Tamar', + 'Prem', + 'Jamiyl', + 'Remmel', + 'Harlin', + 'Novak', + 'Fynn', + 'Gonsalo', + 'Maliki', + 'Loghan', + 'Cauy', + 'Kassem', + 'Jitsuo', + 'Itsuo', + 'Atsushi', + 'Sunao', + 'Sueo', + 'Hiromu', + 'Toshiyuki', + 'Osamu', + 'Mena', + 'Aldin', + 'Leticia', + 'Darick', + 'Kawan', + 'Rajahn', + 'Asmar', + 'Emarion', + 'Hilmer', + 'Dameyune', + 'Rondarius', + 'Brinson', + 'Trason', + 'Chung', + 'Eran', + 'Khanh', + 'Javarious', + 'Makel', + 'Zyquan', + 'Quintarius', + 'Duran', + 'Veasna', + 'Thao', + 'Gracin', + 'Eberardo', + 'Ming', + 'Lusiano', + 'Kaveh', + 'Truong', + 'Ying', + 'Kentravious', + 'Dillen', + 'Jamonte', + 'Arthuro', + 'Camarion', + 'Avett', + 'Mehdi', + 'Nishant', + 'Bartek', + 'Aarnav', + 'Jeffory', + 'Deen', + 'Dayshaun', + 'Kemonte', + 'Petar', + 'Yug', + 'Donat', + 'Sylvio', + 'Magdiel', + 'Christianjames', + 'Lessie', + 'Sander', + 'Rajvir', + 'Nahuel', + 'Pearlie', + 'Aaren', + 'Dimitry', + 'Aravind', + 'Aristotle', + 'Jeury', + 'Naji', + 'Tysheem', + 'Alcee', + 'Gustaf', + 'Jamarrion', + 'Zollie', + 'Malick', + 'Navin', + 'Juwon', + 'Usama', + 'Walid', + 'Quamel', + 'Sadiq', + 'Tamarcus', + 'Merwyn', + 'Ferdie', + 'Kalif', + 'Latif', + 'Davidson', + 'Aahan', + 'Shahid', + 'Min', + 'Kieren', + 'Oz', + 'Oryan', + 'Madox', + 'Kota', + 'Gurshaan', + 'Gagik', + 'Finnigan', + 'Finlay', + 'Exodus', + 'Kaileb', + 'Jullien', + 'Jiovani', + 'Maryland', + 'Weaver', + 'Williard', + 'Keyondre', + 'Kailen', + 'Kanan', + 'Luisantonio', + 'Izack', + 'Daniela', + 'Colm', + 'Raja', + 'Keeshawn', + 'Adhemar', + 'Hillary', + 'Abdimalik', + 'Roark', + 'Kolston', + 'Cheryl', + 'Richardson', + 'Arif', + 'Jahkeem', + 'Kumar', + 'Raywood', + 'Jaiquan', + 'Earley', + 'Buren', + 'Rossie', + 'Jakayden', + 'Ruffus', + 'Zaquan', + 'Tamer', + 'Devonne', + 'Ikeem', + 'Dhruva', + 'Georges', + 'Kwabena', + 'Yeriel', + 'Glover', + 'Sanders', + 'Adonay', + 'Gillis', + 'Yomar', + 'Ediberto', + 'Antwane', + 'Isahi', + 'Haidyn', + 'Elizandro', + 'Markjoseph', + 'Jezreel', + 'Isayah', + 'Zedekiah', + 'Nikolay', + 'Jenner', + 'Uriyah', + 'Taiga', + 'Daniele', + 'Zacharie', + 'Joanne', + 'Manpreet', + 'Mohan', + 'Eliu', + 'Faraz', + 'Robah', + 'Isham', + 'Omarian', + 'Gagandeep', + 'Zeno', + 'Waddell', + 'Plato', + 'Quavon', + 'Talib', + 'Bascom', + 'Mayo', + 'Tequan', + 'Teron', + 'Anatole', + 'Tajh', + 'Algenis', + 'Liridon', + 'Kervens', + 'Yunior', + 'Kenson', + 'Wesly', + 'Antwann', + 'Zelig', + 'Demetrious', + 'Johnbenedict', + 'Josecarlos', + 'Kona', + 'Cj', + 'Atul', + 'Asaf', + 'Aleck', + 'Anthoni', + 'Anuar', + 'Gedalya', + 'Rafay', + 'Eyal', + 'Andry', + 'Natanel', + 'Nissim', + 'Jahdiel', + 'Jophy', + 'Rehaan', + 'Jhovani', + 'Maxximus', + 'Nain', + 'Yomtov', + 'Sheikh', + 'Demir', + 'Markos', + 'Mouhamadou', + 'Ousman', + 'Izreal', + 'Hadrian', + 'Aldrin', + 'Conlan', + 'Degan', + 'Toi', + 'Finneas', + 'Latroy', + 'Adon', + 'Antuan', + 'Elchonon', + 'Uzair', + 'Mohid', + 'Nazier', + 'Eliab', + 'Roc', + 'Pavan', + 'Yovanny', + 'Sinjin', + 'Tavoris', + 'Asiel', + 'Brayant', + 'Alexsandro', + 'Adrean', + 'Darel', + 'Olajuwon', + 'Corderro', + 'Tynan', + 'Xaiver', + 'Travaris', + 'Yonis', + 'Gerren', + 'Demon', + 'Furnell', + 'Juel', + 'Harish', + 'Raiyan', + 'Elia', + 'Elijha', + 'Gautham', + 'Arvind', + 'Audel', + 'Almer', + 'Djimon', + 'Jahi', + 'Gehrig', + 'Avant', + 'Arnell', + 'Eliaz', + 'Kaedon', + 'Jaedin', + 'Voshon', + 'Malachy', + 'Gilad', + 'Gabriele', + 'Riku', + 'Cameran', + 'Yoskar', + 'Jahfari', + 'Alexiz', + 'Javante', + 'Gregor', + 'Izel', + 'Donnovan', + 'Nikos', + 'Kodey', + 'Eytan', + 'Betzalel', + 'Dimitrius', + 'Chananya', + 'Graylin', + 'Samvel', + 'Yi', + 'Wassillie', + 'Kelechi', + 'Erroll', + 'Ardit', + 'Rahn', + 'Delaine', + 'Jule', + 'Idus', + 'Dessie', + 'Juda', + 'Levester', + 'Kiante', + 'Earnie', + 'Ihor', + 'Kapono', + 'Akoni', + 'Koamalu', + 'Sholem', + 'Howie', + 'Dariusz', + 'Hall', + 'Kekai', + 'Onix', + 'Ozie', + 'Liem', + 'Collis', + 'Lemon', + 'Hinton', + 'Guss', + 'Ronda', + 'Siddhartha', + 'Owyn', + 'Rye', + 'Riot', + 'Vander', + 'Selena', + 'Barnie', + 'Lewie', + 'Jaxiel', + 'Kaizen', + 'Haloa', + 'Dermot', + 'Misha', + 'Mister', + 'Nicholis', + 'Kevork', + 'Kia', + 'Houa', + 'Huriel', + 'Jesu', + 'Dionta', + 'Silvino', + 'Ivery', + 'Iokepa', + 'Geo', + 'Dex', + 'Izaan', + 'Jasraj', + 'Jakson', + 'Niel', + 'Avelardo', + 'Arjay', + 'Aran', + 'Alanzo', + 'Aidric', + 'Lomax', + 'Rawn', + 'Simmie', + 'Tonnie', + 'Yuto', + 'Mataio', + 'Nicodemus', + 'Maximilien', + 'Raider', + 'Ridley', + 'Orest', + 'Ramzi', + 'Kaikea', + 'Kamahao', + 'Kyrillos', + 'Mace', + 'Lyrik', + 'Lyon', + 'Lux', + 'Ashkan', + 'Jurgen', + 'Khachik', + 'Maher', + 'Jaccob', + 'Jagdeep', + 'Wash', + 'Simpson', + 'Macy', + 'Haylee', + 'Hope', + 'Katie', + 'Thurmon', + 'Savanna', + 'Zoey', + 'Atiba', + 'Dylann', + 'Kaylen', + 'Helio', + 'Geovannie', + 'Praneel', + 'Kamau', + 'Rhamel', + 'Knoah', + 'Harm', + 'Nyle', + 'Maveric', + 'Neithan', + 'Niklaus', + 'Lejon', + 'Wai', + 'Indigo', + 'Sayed', + 'Abdias', + 'Daniil', + 'Rashod', + 'Wren', + 'Chico', + 'Jamarri', + 'Leiland', + 'Ranvir', + 'Mavrick', + 'Matai', + 'Deveon', + 'Teyon', + 'Ramell', + 'Haik', + 'Dupree', + 'Emon', + 'Jermal', + 'Bayley', + 'Marshell', + 'Blouncie', + 'Larson', + 'Lorenz', + 'Jhovanny', + 'Jeffie', + 'Portia', + 'Adron', + 'Calogero', + 'Mathews', + 'Aundra', + 'Aariv', + 'Keniel', + 'Jameis', + 'Konstantin', + 'Khayden', + 'Manford', + 'Polo', + 'Chanel', + 'Brittani', + 'Kazuki', + 'Kaelen', + 'Alice', + 'Maya', + 'Madeleine', + 'Kiana', + 'Latasha', + 'Felicia', + 'Gabriella', + 'Bolivar', + 'Eileen', + 'Alister', + 'Aidenn', + 'Nina', + 'Ellington', + 'Alecsander', + 'Ja', + 'Jarmaine', + 'Kyriakos', + 'Apostolos', + 'Leshawn', + 'Shondell', + 'Matvey', + 'Savino', + 'Zakariye', + 'Dozier', + 'Holland', + 'Haruto', + 'Hendrik', + 'Allah', + 'Johnanthony', + 'Eliyah', + 'Champ', + 'Dastan', + 'Caliph', + 'Manish', + 'Agostino', + 'Kaio', + 'Avyaan', + 'Gerasimos', + 'Refujio', + 'Munir', + 'Abdurrahman', + 'Selso', + 'Epimenio', + 'Suhayb', + 'Jock', + 'Larwence', + 'Saadiq', + 'Lilburn', + 'Selestino', + 'Randi', + 'Nysir', + 'Harlyn', + 'Basir', + 'Kathy', + 'Teddie', + 'Luqman', + 'Tyhir', + 'Mubarak', + 'Ridwan', + 'Filemon', + 'Bergen', + 'Danney', + 'Eual', + 'Melburn', + 'Esiquio', + 'Cree', + 'Dorwin', + 'Naasir', + 'Ysmael', + 'Nirav', + 'Chuckie', + 'Lashaun', + 'Darris', + 'Blase', + 'Kiley', + 'Demarko', + 'Taiwan', + 'Lamon', + 'Corrie', + 'Feras', + 'Excell', + 'Cornelious', + 'Martinez', + 'Marvel', + 'Climmie', + 'Martrell', + 'Valley', + 'Lonie', + 'Jovante', + 'Lavante', + 'Lugene', + 'Cordarro', + 'Lacey', + 'Derrius', + 'Tedd', + 'Levell', + 'Linas', + 'Taras', + 'Toma', + 'Klint', + 'Gualberto', + 'Feliberto', + 'Tarrance', + 'Theran', + 'Lakeith', + 'Mearl', + 'Karry', + 'Denarius', + 'Dontarius', + 'Nikia', + 'Rakesh', + 'Not', + 'Darek', + 'Gery', + 'Ontario', + 'Jimi', + 'Shamarion', + 'Kedarius', + 'Jermarcus', + 'Amarie', + 'Kordae', + 'Montie', + 'Haleem', + 'Inocencio', + 'Brockton', + 'Yoshiaki', + 'Ponciano', + 'Silvester', + 'Derron', + 'Davaughn', + 'Urie', + 'Juanito', + 'Corky', + 'Pasqual', + 'Marilyn', + 'Morley', + 'Ayoub', + 'Eliasar', + 'Mickel', + 'Skylor', + 'Kewan', + 'Teon', + 'Rafal', + 'Devanta', + 'Rosco', + 'Tywon', + 'Evon', + 'Cleven', + 'Hardie', + 'Tori', + 'Trayvond', + 'Maaz', + 'Masashi', + 'Neno', + 'Kahari', + 'Terri', + 'Toru', + 'Jalynn', + 'Avonte', + 'Satchel', + 'Tanya', + 'Kalab', + 'Avetis', + 'Miko', + 'Kodiak', + 'Lang', + 'Leondre', + 'Purnell', + 'Harutyun', + 'Gorman', + 'Vong', + 'Shervin', + 'Soloman', + 'Sue', + 'Amandeep', + 'Amritpal', + 'Leonides', + 'Melecio', + 'Mikhael', + 'Estaban', + 'Arius', + 'Calix', + 'Gurtaj', + 'Dilraj', + 'Dillinger', + 'Aidden', + 'Shivansh', + 'Shravan', + 'Saud', + 'Yarel', + 'Riker', + 'Yareth', + 'Zeppelin', + 'Ladarious', + 'Lucan', + 'Terren', + 'Tustin', + 'Nicolaas', + 'Rakan', + 'Johnjoseph', + 'Hovanes', + 'Navjot', + 'Henrique', + 'Marsalis', + 'Karanveer', + 'Jeffren', + 'Khairi', + 'Haruki', + 'Jadden', + 'Iliya', + 'Hansen', + 'Srihan', + 'Sartaj', + 'Rishik', + 'Rishan', + 'Octavian', + 'Ranbir', + 'Padraic', + 'Tanush', + 'Tlaloc', + 'Cadarius', + 'Yared', + 'Vahan', + 'Lakai', + 'Fionn', + 'Eziah', + 'Emillio', + 'Hakob', + 'Gryphon', + 'Harsha', + 'Hiroto', + 'Nivaan', + 'Radin', + 'Nicasio', + 'Mael', + 'Lysander', + 'Rees', + 'Roemello', + 'Bretton', + 'Christoph', + 'Eliceo', + 'Armany', + 'Axell', + 'Bogdan', + 'Luan', + 'Aldon', + 'Aeson', + 'Adhvik', + 'Jese', + 'Blanca', + 'Crisanto', + 'Dietrich', + 'Tarin', + 'Yama', + 'Yia', + 'Omeed', + 'Arbie', + 'Shayn', + 'Ranferi', + 'Ricard', + 'Farmer', + 'Goble', + 'Herald', + 'Hager', + 'Elva', + 'Carlis', + 'Evertt', + 'Ledford', + 'Dequarius', + 'Hughie', + 'Burgess', + 'Kourosh', + 'Jaun', + 'Nicko', + 'Victorhugo', + 'Roverto', + 'Shadi', + 'Sopheak', + 'Acie', + 'Demar', + 'Carolina', + 'Vinal', + 'Earland', + 'Sergey', + 'Dayon', + 'Kwamaine', + 'Kerney', + 'Ola', + 'Welby', + 'Kyon', + 'Tyion', + 'Kiyon', + 'Neng', + 'Raquel', + 'Nadeem', + 'Terran', + 'Tin', + 'Rudi', + 'Murad', + 'Murrell', + 'Lenville', + 'Rondall', + 'Han', + 'Hovhannes', + 'Karapet', + 'Hamed', + 'Alasdair', + 'Agam', + 'Areg', + 'Ariston', + 'Askari', + 'Ayansh', + 'Byran', + 'Dolan', + 'Devonn', + 'Edith', + 'Christoffer', + 'Alaa', + 'Ashraf', + 'Rondle', + 'Tavarius', + 'Michaeljames', + 'Nichols', + 'Sonia', + 'Ryanchristopher', + 'Garo', + 'Hien', + 'Corin', + 'Dillin', + 'Jerid', + 'Jesusalberto', + 'Zeferino', + 'Gobel', + 'Tykeem', + 'Miking', + 'Juno', + 'Jiraiya', + 'Kailash', + 'Madix', + 'Lucciano', + 'Llewyn', + 'Leone', + 'Knight', + 'Dorse', + 'Oak', + 'Irie', + 'Brodi', + 'Hridhaan', + 'Coda', + 'Dekker', + 'Evren', + 'Eisen', + 'Eddison', + 'Donatello', + 'Happy', + 'Devron', + 'Suleiman', + 'Siddhanth', + 'Zorawar', + 'Zadkiel', + 'Waylan', + 'Valor', + 'Triton', + 'Govanni', + 'Angelus', + 'Ashvin', + 'Matthews', + 'Elver', + 'Brendin', + 'Rhea', + 'Jyron', + 'Matisse', + 'Karanvir', + 'Kenshin', + 'Saketh', + 'Trigo', + 'Wil', + 'Tyrick', + 'Trejon', + 'Manvir', + 'Sascha', + 'Samay', + 'Prabhjot', + 'Piers', + 'Arshia', + 'Karo', + 'Makani', + 'Ludwin', + 'Kean', + 'Nikoli', + 'Garlin', + 'Georgio', + 'Jyren', + 'Ledell', + 'Jayceion', + 'Wiltz', + 'Elgie', + 'Jediah', + 'Izzac', + 'Izeyah', + 'Jeyson', + 'Hamid', + 'Jalani', + 'Rohin', + 'Shiva', + 'Ramces', + 'Claudell', + 'Daymien', + 'Aeron', + 'Aadan', + 'Alesandro', + 'Aleksey', + 'Galileo', + 'Esvin', + 'Indy', + 'Graden', + 'Gor', + 'Vlad', + 'Kendrell', + 'Saket', + 'Asahel', + 'Blue', + 'Arshdeep', + 'Adain', + 'Keneth', + 'Jacy', + 'Dasan', + 'Haniel', + 'Ethin', + 'Ericson', + 'Izick', + 'Elisandro', + 'Coltrane', + 'Kemani', + 'Josearmando', + 'Josealfredo', + 'Alias', + 'Anurag', + 'Carlitos', + 'Ceaser', + 'Sukhraj', + 'Severin', + 'Nishanth', + 'Mattox', + 'Rhiley', + 'Dareon', + 'Danyel', + 'Calan', + 'Nithin', + 'Donivan', + 'Taye', + 'Trustin', + 'Igor', + 'Jayr', + 'Kayin', + 'Pleas', + 'Aadit', + 'Balam', + 'Jovannie', + 'Quintrell', + 'Japheth', + 'Hero', + 'Edu', + 'Duvan', + 'Anden', + 'Anshul', + 'Ailton', + 'Raybon', + 'Rabon', + 'Kendry', + 'Manases', + 'Damyan', + 'Braven', + 'Dhani', + 'Isaia', + 'Hovik', + 'Sonnie', + 'Wolfe', + 'Banyan', + 'Hiroki', + 'Matin', + 'Sequoia', + 'Acelin', + 'Aarya', + 'Arsalan', + 'Carlosdaniel', + 'Jaryd', + 'Ariana', + 'Kylee', + 'Mariah', + 'Serenity', + 'Kailey', + 'Delaney', + 'Emilee', + 'Isabelle', + 'Jayla', + 'Drue', + 'Emani', + 'Juandedios', + 'Kedar', + 'Baily', + 'Daijon', + 'Daman', + 'Kentaro', + 'Damaria', + 'Mareco', + 'Valmore', + 'Theophile', + 'Winslow', + 'Ugo', + 'Cainan', + 'Finian', + 'Keiji', + 'Issack', + 'Blanchard', + 'Domingos', + 'Jarin', + 'Giovan', + 'Ovila', + 'Lovelace', + 'Albion', + 'Curry', + 'Christophr', + 'Nolton', + 'Unborn', + 'Torry', + 'Yoshi', + 'Perrion', + 'Nathyn', + 'Syler', + 'Sheila', + 'Jaedan', + 'Cobey', + 'Bashar', + 'Ehsan', + 'Daryll', + 'Seann', + 'Niels', + 'Nazar', + 'Frederico', + 'Esther', + 'Bobie', + 'Loyce', + 'Heberto', + 'Bentura', + 'Jafar', + 'Keigan', + 'Bertil', + 'Aloys', + 'Janie', + 'Paz', + 'Damacio', + 'Oiva', + 'Ingvald', + 'Walfred', + 'Jakeob', + 'Georgie', + 'Alcuin', + 'Raynold', + 'Josey', + 'Lasaro', + 'Jo', + 'Hjalmer', + 'Philemon', + 'Paula', + 'Christophor', + 'Estanislao', + 'Angelita', + 'Anacleto', + 'Alfons', + 'Lawayne', + 'Delrico', + 'Clemson', + 'Jaleen', + 'Jerimy', + 'Javaughn', + 'Tiofilo', + 'Hubbard', + 'Abundio', + 'Derl', + 'Keagen', + 'Aymen', + 'Freedom', + 'Venancio', + 'Pauline', + 'Gorden', + 'Hani', + 'Pharrell', + 'Jager', + 'Nyair', + 'Azeem', + 'Khyir', + 'Jabriel', + 'Yandiel', + 'Zaahir', + 'Laine', + 'Xai', + 'Vernard', + 'Augie', + 'Sostenes', + 'Darryll', + 'Asir', + 'Lindon', + 'Jearl', + 'Peder', + 'Rudolpho', + 'Clancy', + 'Yue', + 'Ronnald', + 'Onofre', + 'Kysir', + 'Helmuth', + 'Marlowe', + 'Derk', + 'Demetrick', + 'Jefrey', + 'Burrell', + 'Robie', + 'Marlan', + 'Thane', + 'Jamire', + 'Donnel', + 'Syaire', + 'York', + 'Asaad', + 'Kyair', + 'Devere', + 'Wing', + 'Yaniv', + 'Mathhew', + 'Silvia', + 'Chia', + 'Bren', + 'Cavin', + 'Aldrich', + 'Judy', + 'Erron', + 'Butler', + 'Carole', + 'Almon', + 'Gilles', + 'Christin', + 'Renald', + 'Sony', + 'Chavis', + 'Nghia', + 'Mercedes', + 'Real', + 'Josejesus', + 'Ryman', + 'Kori', + 'Ichael', + 'Jabier', + 'Nguyen', + 'Angeldejesus', + 'Bobak', + 'Brittan', + 'Shaunt', + 'Karlton', + 'Jerin', + 'Gerado', + 'Raymund', + 'Kerolos', + 'Rolan', + 'Wilbern', + 'Sipriano', + 'Hermes', + 'Robyn', + 'Ynes', + 'Vernice', + 'Pink', + 'Jevonte', + 'Jerame', + 'Tajuan', + 'Mingo', + 'Jeremia', + 'Edmon', + 'Castulo', + 'Cleofas', + 'Arlee', + 'Oather', + 'Larkin', + 'Mcarther', + 'Ryann', + 'Hong', + 'Jamieson', + 'Enedino', + 'Gerad', + 'Lenord', + 'Alireza', + 'Hollie', + 'Gilford', + 'Lajuane', + 'Izell', + 'Trenidad', + 'Shelley', + 'Ulysees', + 'Juana', + 'Coalton', + 'Remer', + 'Raiford', + 'Caydon', + 'Dalyn', + 'Wilhelm', + 'Lenzy', + 'Bartow', + 'Tibor', + 'Cebert', + 'Elizar', + 'Ellen', + 'Uchenna', + 'Toy', + 'Curlee', + 'Ralf', + 'Giulio', + 'Conway', + 'Ngai', + 'Chaka', + 'Engelbert', + 'Auburn', + 'Socrates', + 'Kostas', + 'Kamalei', + 'Kupono', + 'Carrell', + 'Lister', + 'Mattie', + 'Thermon', + 'Tina', + 'Kennan', + 'Adison', + 'Dalon', + 'Ephram', + 'Jaylynn', + 'Zabdiel', + 'Kaidon', + 'Juvencio', + 'Havis', + 'Dagan', + 'Dacorian', + 'Donavyn', + 'Evyn', + 'Issai', + 'Zenon', + 'Inman', + 'Hason', + 'Lehman', + 'Afton', + 'Clayborn', + 'Abrahm', + 'Neill', + 'Conard', + 'Mutsuo', + 'Seikichi', + 'Wetzel', + 'Masaji', + 'Masanobu', + 'Shigeto', + 'Edgel', + 'Goro', + 'Lovett', + 'Seiko', + 'Sakae', + 'Roshawn', + 'Antjuan', + 'Erby', + 'Jobe', + 'Ladarian', + 'Cyler', + 'Edel', + 'Hartsel', + 'Jill', + 'Jami', + 'Rabun', + 'Fulton', + 'Dreddy', + 'Corrado', + 'Harald', + 'Alterick', + 'Hala', + 'Powell', + 'Lesly', + 'Kalon', + 'Theodoros', + 'Etan', + 'Trev', + 'Javiel', + 'Jusiah', + 'Joncarlos', + 'Jhamari', + 'Rasheim', + 'Raysean', + 'Kreg', + 'Rahmell', + 'Kerby', + 'Eliga', + 'Clemon', + 'Aneudy', + 'Keiran', + 'Kensley', + 'Ludie', + 'Jorell', + 'Can', + 'Demondre', + 'Cierra', + 'Maurizio', + 'Tacuma', + 'Ryzen', + 'Jabar', + 'Tara', + 'Reign', + 'Jashon', + 'Lasean', + 'Artavius', + 'Akbar', + 'Un', + 'Kaikane', + 'Tanisha', + 'Elena', + 'Bridget', + 'Asia', + 'Latisha', + 'Rachael', + 'Latoya', + 'Elisabeth', + 'Janelle', + 'Ikea', + 'Kobey', + 'Kamaehu', + 'Keona', + 'Calixto', + 'Theotis', + 'Worthy', + 'Galo', + 'Holly', + 'Sevyn', + 'Petr', + 'Cerrone', + 'Tedrick', + 'Kymari', + 'Gerrard', + 'Eldo', + 'Alcides', + 'Derrian', + 'Eulas', + 'Leodis', + 'Akai', + 'Dalonte', + 'Pantelis', + 'Sheron', + 'Tommaso', + 'Treg', + 'Shirl', + 'Abrian', + 'Brewer', + 'Yamir', + 'Zadok', + 'Holdyn', + 'Jayanthony', + 'Eh', + 'Dayson', + 'Khaden', + 'Quintez', + 'Rontavious', + 'Markese', + 'Quintavis', + 'Daveion', + 'Tonny', + 'Jaevon', + 'Ahkeem', + 'Hy', + 'Adams', + 'Marian', + 'Huner', + 'Jarmarcus', + 'Treyon', + 'Tullio', + 'Oreste', + 'Oleg', + 'Xzavien', + 'Atzel', + 'Brenan', + 'Abriel', + 'Braylyn', + 'Chidera', + 'Lebaron', + 'Jameir', + 'Kameryn', + 'Shade', + 'Koltin', + 'Cordarrius', + 'Amelio', + 'Demarquez', + 'Tarus', + 'Calob', + 'Dmarco', + 'Creek', + 'Amen', + 'Cylas', + 'Davyn', + 'Haygen', + 'Godric', + 'Garn', + 'Renardo', + 'Locke', + 'Lexington', + 'Mazin', + 'Othniel', + 'Kruze', + 'Jaxston', + 'Jaxten', + 'Jeziah', + 'Jettson', + 'Zebastian', + 'Sarim', + 'Jawuan', + 'Tremain', + 'Hassell', + 'Quartez', + 'Hawkins', + 'Riggs', + 'Rebel', + 'Nael', + 'Kaycen', + 'Kamsiyochukwu', + 'Kagen', + 'Jrue', + 'Jaydeen', + 'Azazel', + 'Ayson', + 'Cheston', + 'Aarian', + 'Chavez', + 'Void', + 'Zacariah', + 'Keena', + 'Antwuan', + 'Labarron', + 'Quamere', + 'Mikell', + 'Prestyn', + 'Savian', + 'Dayden', + 'Jaivion', + 'Geremiah', + 'Aidon', + 'Bralyn', + 'Gianncarlo', + 'Jarquavious', + 'Muriel', + 'Akshar', + 'Kadir', + 'Najir', + 'Neko', + 'Jahaad', + 'Jdyn', + 'Kashon', + 'Jaquil', + 'Wah', + 'Delmos', + 'Masuo', + 'Nobuichi', + 'Kiichi', + 'Jerone', + 'Tatsumi', + 'Damarian', + 'Elier', + 'Lansing', + 'Heinrich', + 'Hasson', + 'Larrie', + 'Phyllis', + 'Jamoni', + 'Zylen', + 'Demoni', + 'Harrel', + 'Levie', + 'Zaryan', + 'Orazio', + 'Seymore', + 'Florence', + 'Kolter', + 'Kemper', + 'Daelyn', + 'Haddon', + 'Syon', + 'Sair', + 'Filadelfio', + 'Marquavion', + 'Breylon', + 'Filimon', + 'Abie', + 'Cortavious', + 'Achille', + 'Dontrez', + 'Matty', + 'Darshawn', + 'Overton', + 'Bashir', + 'Kavan', + 'Caidan', + 'Braelen', + 'Param', + 'Kani', + 'Percival', + 'Hartley', + 'Erminio', + 'Candler', + 'Ulyssee', + 'Damontae', + 'Ellijah', + 'Cesare', + 'Eleanor', + 'Eustace', + 'Joachim', + 'Tarique', + 'Altin', + 'Tyleek', + 'Posey', + 'Awais', + 'Daivon', + 'Zi', + 'Hammad', + 'Meshulem', + 'Nickie', + 'Brehon', + 'Dacoda', + 'Kwamane', + 'Rafuel', + 'Mikai', + 'Hensel', + 'Thelbert', + 'Valerio', + 'Trevonte', + 'Koran', + 'Cheick', + 'Shahzaib', + 'Tahsin', + 'Derry', + 'Mustapha', + 'Chucky', + 'Osborne', + 'Daquarius', + 'Marque', + 'Raquon', + 'Cherokee', + 'Keyshaun', + 'Mohamadou', + 'Keishawn', + 'Jahmeek', + 'Junaid', + 'Amil', + 'Mckoy', + 'Zackry', + 'Nyheim', + 'Nkosi', + 'Kweli', + 'Tydarius', + 'Umer', + 'Demorris', + 'Demarquis', + 'Hersch', + 'Luzer', + 'Li', + 'Aly', + 'Quade', + 'Quamaine', + 'Markee', + 'Jhoan', + 'Mert', + 'Supreme', + 'Tyheem', + 'Gomer', + 'Taseen', + 'Yousaf', + 'Yonason', + 'Gifford', + 'Ashar', + 'Sender', + 'Salah', + 'Saifan', + 'Raihan', + 'Nizar', + 'Abrahim', + 'Kunga', + 'Javis', + 'Evens', + 'Bayard', + 'Kaysan', + 'Padraig', + 'Ney', + 'Ahmet', + 'Misty', + 'Ayyan', + 'Saint', + 'Fern', + 'Wasil', + 'Nolie', + 'Zarif', + 'Younis', + 'Eesa', + 'Ketrick', + 'Veryl', + 'Refael', + 'Motty', + 'Naftuly', + 'Waseem', + 'Yusif', + 'Brigg', + 'Zaheer', + 'Shiya', + 'Karma', + 'Meilich', + 'Mihran', + 'Javares', + 'Efe', + 'Abubakr', + 'Avrumi', + 'Nayshawn', + 'Mostafa', + 'Hinckley', + 'Jahmeir', + 'Fintan', + 'Sollie', + 'Amiel', + 'Abu', + 'Yaro', + 'Josha', + 'Jermane', + 'Bertis', + 'Hernando', + 'Gerrod', + 'Haim', + 'Frandy', + 'Andrews', + 'Dayle', + 'Fleming', + 'Volvi', + 'Savior', + 'Shuford', + 'Plummer', + 'Ralston', + 'Dayvion', + 'Muhamed', + 'Naheem', + 'Nataniel', + 'Kaeleb', + 'Billyjoe', + 'Able', + 'Fareed', + 'Purcell', + 'Trayson', + 'Mackay', + 'Moyer', + 'Haynes', + 'Domnick', + 'Burnie', + 'Gleen', + 'Leavy', + 'Lennart', + 'Breken', + 'Arlind', + 'Clarnce', + 'Nissen', + 'Josiel', + 'Alvester', + 'Jaquay', + 'Nickolaos', + 'Ruddy', + 'Berkeley', + 'Flamur', + 'Sherif', + 'Shateek', + 'Ayodele', + 'Davone', + 'Meshach', + 'Kinston', + 'Algernon', + 'Dvonte', + 'Jawara', + 'Zamar', + 'Dayron', + 'Jaequan', + 'Tyrelle', + 'Jazion', + 'Tamel', + 'Torris', + 'Marguis', + 'Yuniel', + 'Saige', + 'Gottlieb', + 'Cori', + 'Dre', + 'Yordan', + 'Shaquell', + 'Jonel', + 'Kashaun', + 'Arjenis', + 'Tashan', + 'Fitzroy', + 'Francisc', + 'Kwaku', + 'Jakyri', + 'Trayton', + 'Jarrick', + 'Reginaldo', + 'Facundo', + 'Elma', + 'Dardan', + 'Dreshawn', + 'Demontray', + 'Chaddrick', + 'Roper', + 'Taariq', + 'Ausitn', + 'Jachai', + 'Duval', + 'Braun', + 'Taylan', + 'Dionis', + 'Samy', + 'Armistead', + 'Alize', + 'Tayshon', + 'Ainsley', + 'Kaheem', + 'Jaire', + 'Kyshawn', + 'Nahshon', + 'Aaliyah', + 'Shanard', + 'Azion', + 'Alana', + 'Alexia', + 'Breyon', + 'Trigg', + 'Wylder', + 'Zaydin', + 'Ziaire', + 'Zixuan', + 'Yanis', + 'Zair', + 'Zaven', + 'Alanmichael', + 'Viyan', + 'Vivan', + 'Klay', + 'Erico', + 'Tycho', + 'Waris', + 'Winter', + 'Aliyah', + 'Kamilo', + 'Kei', + 'Glendell', + 'Lilly', + 'Lauryn', + 'Jovian', + 'Shayla', + 'Tessa', + 'Jupiter', + 'Aaric', + 'Aadhav', + 'Jetson', + 'Abir', + 'Adhrit', + 'Alexandr', + 'Brooklynn', + 'Callie', + 'Ashlee', + 'Ashlyn', + 'Haleigh', + 'Heaven', + 'Jahkari', + 'Izaiyah', + 'Troyce', + 'Bige', + 'Hayze', + 'Neldon', + 'Marven', + 'Beckem', + 'Dvante', + 'Navarro', + 'Neiko', + 'Noeh', + 'Jen', + 'Torrian', + 'Helios', + 'Macallan', + 'Lio', + 'Wilkens', + 'Merrik', + 'Ameal', + 'Mujtaba', + 'Iktan', + 'Kavious', + 'Monterrio', + 'Hughey', + 'Calin', + 'Cali', + 'Jamaar', + 'Kenith', + 'Rihaan', + 'Deaglan', + 'Kelso', + 'Lavaris', + 'Ashot', + 'Marshun', + 'Rainer', + 'Rivan', + 'Talal', + 'Taiyo', + 'Minor', + 'Yvon', + 'Stonewall', + 'Merril', + 'Okie', + 'Trevino', + 'Imari', + 'Ithan', + 'Izmael', + 'Jayan', + 'Harut', + 'Harshaan', + 'Kainen', + 'Kalyan', + 'Kanishk', + 'Kotaro', + 'Josyah', + 'Vola', + 'Omarie', + 'Dmari', + 'Mannix', + 'Elad', + 'Shun', + 'Andriy', + 'Angelino', + 'Ary', + 'Axcel', + 'Becker', + 'Daxten', + 'Daemian', + 'Cypress', + 'Jakhai', + 'Warnie', + 'Maikel', + 'Davinci', + 'Calloway', + 'Vernal', + 'Tyrome', + 'Mont', + 'Ovie', + 'Hester', + 'Arvis', + 'Corbit', + 'Tarvaris', + 'Audra', + 'Cloud', + 'Taveon', + 'Balian', + 'Bodi', + 'Brodee', + 'Kainan', + 'Dezi', + 'Devesh', + 'Emad', + 'Esa', + 'Massie', + 'Moir', + 'Markavious', + 'Veachel', + 'Dalan', + 'Carles', + 'Antawn', + 'Jermichael', + 'Talin', + 'Sy', + 'Murrel', + 'Elster', + 'Kru', + 'Okley', + 'Maverik', + 'Diangelo', + 'Burns', + 'Jamaris', + 'Jayshaun', + 'Dantae', + 'Rahil', + 'Renny', + 'Rohith', + 'Strummer', + 'Birchel', + 'Astor', + 'Nolyn', + 'Neeko', + 'Reyan', + 'Kailan', + 'Jaideep', + 'Manveer', + 'Maeson', + 'Khris', + 'Lancelot', + 'Shaunak', + 'Shubham', + 'Siaosi', + 'Ruslan', + 'Sajan', + 'Renwick', + 'Yann', + 'Vitali', + 'Zealand', + 'Vyom', + 'Xabi', + 'Yazid', + 'Terrelle', + 'Oaks', + 'Kache', + 'Arjuna', + 'Cephas', + 'Holmes', + 'Rockie', + 'Elray', + 'Doc', + 'Mell', + 'Tyresse', + 'Maguire', + 'Sheddrick', + 'Loney', + 'Helaman', + 'Andrus', + 'Asberry', + 'Love', + 'Clebert', + 'Cashius', + 'Egypt', + 'Devansh', + 'Elige', + 'Tobe', + 'Taten', + 'Arias', + 'Leandrew', + 'Dekota', + 'Varian', + 'Lehi', + 'Colbert', + 'Ignace', + 'Suhas', + 'Syris', + 'Ahan', + 'Aithan', + 'Aiven', + 'Akshath', + 'Hamp', + 'Kato', + 'Leeon', + 'Reubin', + 'Lukah', + 'Wilmon', + 'Tait', + 'Theophilus', + 'Sion', + 'Maysen', + 'Nicoli', + 'Nason', + 'Mykell', + 'Montae', + 'Laszlo', + 'Lestat', + 'Prithvi', + 'Maxi', + 'Mekhai', + 'Hammond', + 'Atiksh', + 'Aldean', + 'Aldine', + 'Jedi', + 'Almond', + 'Edahi', + 'Hisham', + 'Clide', + 'Cosby', + 'Hayato', + 'Harnoor', + 'Gurjot', + 'Ethridge', + 'Dublin', + 'Daimian', + 'Derreon', + 'Hansell', + 'Mae', + 'Semisi', + 'Ulysess', + 'Render', + 'Eschol', + 'Rodell', + 'Atzin', + 'Alik', + 'Amiri', + 'Keyvon', + 'Noland', + 'Terius', + 'Isauro', + 'Harshith', + 'Pledger', + 'Tilman', + 'Lennis', + 'Jovin', + 'Jaymin', + 'Jaydee', + 'Asbury', + 'Lovie', + 'Mcclinton', + 'Grayton', + 'Cardin', + 'Jacey', + 'Gurveer', + 'Ethanmatthew', + 'Aaronjames', + 'Ascher', + 'Aarion', + 'Windle', + 'Jahan', + 'Jayen', + 'Jatin', + 'Jedrek', + 'Anthonyjr', + 'Dabney', + 'Galvin', + 'Ilijah', + 'Gohan', + 'Quaid', + 'Teancum', + 'Chael', + 'Chetan', + 'Cylis', + 'Manas', + 'Logun', + 'Karston', + 'Mickeal', + 'Iskander', + 'Isaah', + 'Aryaman', + 'Juvens', + 'Joncarlo', + 'Gurkirat', + 'Laymon', + 'Salesi', + 'Rion', + 'Tao', + 'Tadhg', + 'Stephens', + 'Terryl', + 'Jacquan', + 'Zubin', + 'Yul', + 'Yadriel', + 'Dolph', + 'Keiden', + 'Koston', + 'Demetre', + 'Kameren', + 'Kaedin', + 'Zebedee', + 'Tyrie', + 'Truth', + 'Lanorris', + 'Tilden', + 'Tidus', + 'Thelonious', + 'Tennessee', + 'Sirius', + 'Pervis', + 'Saatvik', + 'Adley', + 'Amarian', + 'Numa', + 'Bronco', + 'Zian', + 'Zephan', + 'Yaziel', + 'Ajit', + 'Arick', + 'Ollin', + 'Kort', + 'Tayvin', + 'Grason', + 'Leonid', + 'Nihaal', + 'Koah', + 'Southern', + 'Kavish', + 'Joeziah', + 'Javi', + 'Kaiyan', + 'Kyro', + 'Ziad', + 'Maxen', + 'Xion', + 'Mica', + 'Mansour', + 'Matteus', + 'Renner', + 'Jonan', + 'Shilo', + 'Josedaniel', + 'Kaj', + 'Robel', + 'Krithik', + 'Lautaro', + 'Evann', + 'Carden', + 'Nathaneal', + 'Wirt', + 'Kile', + 'Kevonte', + 'Jazz', + 'Vardan', + 'Tanav', + 'Tamim', + 'Ojani', + 'Raydel', + 'Rigel', + 'Sheamus', + 'Cameryn', + 'Jedd', + 'Dalessandro', + 'Daejon', + 'Zacheriah', + 'Jt', + 'Valeria', + 'Treshon', + 'Martynas', + 'Markeese', + 'Ladislado', + 'Fidensio', + 'Cincere', + 'Amonte', + 'Erion', + 'Emin', + 'Tayten', + 'Zachory', + 'Ysidoro', + 'Treshaun', + 'Franciszek', + 'Adit', + 'Neftaly', + 'Kaylan', + 'Dezmon', + 'Joby', + 'Terrick', + 'Irma', + 'Isiaha', + 'Micha', + 'Sylvia', + 'Dejan', + 'Kippy', + 'Tyreece', + 'Corie', + 'Martese', + 'Senovio', + 'Lexus', + 'Freddrick', + 'Jemarcus', + 'Kuba', + 'Corion', + 'Andrian', + 'Romualdo', + 'Lyndal', + 'Kalem', + 'Laderrick', + 'Jobin', + 'Chaise', + 'Naren', + 'Reynol', + 'Ohm', + 'Trashawn', + 'Danyell', + 'Diron', + 'Kameran', + 'Dunte', + 'Ikechukwu', + 'Trendon', + 'Visente', + 'Valeriano', + 'Dillian', + 'Chantz', + 'Bacilio', + 'Crescencio', + 'Policarpio', + 'Janice', + 'Kem', + 'Rutilio', + 'Jaqualin', + 'Kendon', + 'Keevin', + 'Adelaido', + 'Coltan', + 'Theodoro', + 'Devondre', + 'Dekendrick', + 'Deionte', + 'Taz', + 'Jimmey', + 'Cristan', + 'Chancelor', + 'Ascension', + 'Kemon', + 'Makari', + 'Cordel', + 'Colbey', + 'Ambrocio', + 'Marselino', + 'Dewain', + 'Graciano', + 'Gumecindo', + 'Lorenso', + 'Quaylon', + 'Halbert', + 'Celedonio', + 'Terrin', + 'Zuri', + 'Sherod', + 'Ermal', + 'Elisa', + 'Larnell', + 'Tully', + 'Wenceslaus', + 'Lashun', + 'Duan', + 'Correy', + 'Wilburt', + 'Antwoin', + 'Lynell', + 'Ramond', + 'Victorio', + 'Antion', + 'Dragan', + 'Priest', + 'Marice', + 'Laroy', + 'Ninos', + 'Byrl', + 'Ebert', + 'Keita', + 'Dimitris', + 'Zoran', + 'Khaalis', + 'Rollo', + 'Alwin', + 'Loraine', + 'Jerard', + 'Lyndle', + 'Quirino', + 'Ramey', + 'Jarian', + 'Marky', + 'Adlai', + 'Shamon', + 'Treyshawn', + 'Shaft', + 'Gumercindo', + 'Rita', + 'Derryl', + 'Chancy', + 'Kacy', + 'Jonothan', + 'Ruston', + 'Ranulfo', + 'Talik', + 'Johntae', + 'Kendale', + 'Diandre', + 'Reginold', + 'Tyris', + 'Davell', + 'Ladell', + 'Raymone', + 'Mariusz', + 'Edvardo', + 'Joh', + 'Lavontae', + 'Markie', + 'Laquinton', + 'Alexandar', + 'Divante', + 'Jabin', + 'Shawon', + 'Jawann', + 'Ladd', + 'Khali', + 'Gilmore', + 'Oliverio', + 'Thuan', + 'Daiel', + 'Kierre', + 'Javar', + 'Stevon', + 'Derius', + 'Chadley', + 'Manual', + 'Johnaton', + 'Lc', + 'Erek', + 'Jakaden', + 'Jden', + 'Drayke', + 'Dawsen', + 'Jadarion', + 'Shriyans', + 'Raylin', + 'Kaydan', + 'Lynden', + 'Duard', + 'Elo', + 'Amarius', + 'Cleburne', + 'Dailen', + 'Brance', + 'Braycen', + 'Daiden', + 'Cruzito', + 'Caedyn', + 'Aizik', + 'Abyan', + 'Felisiano', + 'Taevion', + 'Zaeden', + 'Zadrian', + 'Fredie', + 'Burnis', + 'Cleave', + 'Ki', + 'Quandarius', + 'Quavion', + 'Makell', + 'Myrl', + 'Tae', + 'Melik', + 'Samarion', + 'Branton', + 'Vollie', + 'Reynolds', + 'Draylon', + 'Keivon', + 'Kevontae', + 'Deundre', + 'Zaydrian', + 'Zaydan', + 'Jotham', + 'Janthony', + 'Sahid', + 'Keilon', + 'Lain', + 'Kenechukwu', + 'Kanaan', + 'Kamdon', + 'Ahmod', + 'Dong', + 'Nnamdi', + 'Jontavius', + 'Kelijah', + 'Searcy', + 'Wheeler', + 'Francisca', + 'Burrel', + 'Zyquavious', + 'Kortez', + 'Tres', + 'Tranquilino', + 'Guinn', + 'Hiawatha', + 'Jasiyah', + 'Arlos', + 'Celestine', + 'Deadrian', + 'Chinedu', + 'Cane', + 'Caedon', + 'Gabryel', + 'Garon', + 'Solon', + 'Udell', + 'Medardo', + 'Chon', + 'Zakk', + 'Trip', + 'Somtochukwu', + 'Shooter', + 'Frutoso', + 'Laurencio', + 'Izayiah', + 'Franko', + 'Izzak', + 'Braelan', + 'Dryden', + 'Wilborn', + 'Newt', + 'Petronilo', + 'Nathanel', + 'Jatavius', + 'Locadio', + 'Tyquez', + 'Laiden', + 'Allister', + 'Javarion', + 'Demarrio', + 'Shenouda', + 'Rodriques', + 'Jenard', + 'Azarias', + 'Axxel', + 'Ariyan', + 'Pate', + 'Raidyn', + 'Saylor', + 'Kreed', + 'Kayce', + 'Bray', + 'Zyren', + 'Zayvien', + 'Yeiden', + 'Kinta', + 'Trampus', + 'Lofton', + 'Zayvian', + 'Zaydon', + 'Zaidan', + 'Weslee', + 'Robben', + 'Rook', + 'Roston', + 'Trigger', + 'Steel', + 'Rustyn', + 'Jaeceon', + 'Hutton', + 'Hatcher', + 'Kartier', + 'Kallan', + 'Daxtyn', + 'Corvin', + 'Deklyn', + 'Kaveon', + 'Leviathan', + 'Leelan', + 'Lael', + 'Prynce', + 'Korban', + 'Khyren', + 'Omran', + 'Oluwademilade', + 'Orenthal', + 'Dequavius', + 'Quinterrius', + 'Quantavis', + 'Astin', + 'Asaiah', + 'Dace', + 'Brylee', + 'Kenyan', + 'Jeovani', + 'Kolson', + 'Dreyden', + 'Jujuan', + 'Gregoria', + 'Abdon', + 'Javious', + 'Latravious', + 'Nanya', + 'Kaleel', + 'Elsie', + 'Iris', + 'Javarus', + 'Hunner', + 'Ebubechukwu', + 'Ashaz', + 'Huntley', + 'Montravious', + 'Argelio', + 'Amaar', + 'Abdulmalik', + 'Deronte', + 'Ramirez', + 'Travius', + 'Xavius', + 'Rashamel', + 'Martice', + 'Oshay', + 'Jamerson', + 'Derico', + 'Benino', + 'Otilio', + 'Palani', + 'Trystin', + 'Domonick', + 'Jayron', + 'Josephine', + 'Dora', + 'Larence', + 'Feliz', + 'Tereso', + 'Natalio', + 'Olga', + 'Bralen', + 'Temple', + 'Keala', + 'Anita', + 'Eathen', + 'Lamond', + 'Jakobie', + 'Johnthan', + 'Elnathan', + 'Edris', + 'Alcario', + 'Cornie', + 'Ival', + 'Pantaleon', + 'Deavion', + 'Daevion', + 'Dorance', + 'Jailon', + 'Ragene', + 'Kaena', + 'Kaimipono', + 'Keaka', + 'Kiai', + 'Babygirl', + 'Aukai', + 'Kaitlin', + 'Kaikoa', + 'Jedadiah', + 'Pono', + 'Layth', + 'Kolbie', + 'Naaman', + 'Pacey', + 'Jearld', + 'Corinthian', + 'Bryceson', + 'Kayzen', + 'Mana', + 'Janee', + 'Janae', + 'Kelli', + 'Tamara', + 'Nora', + 'Sophie', + 'Rashida', + 'Princess', + 'Lakeisha', + 'Nadia', + 'Monet', + 'Meaghan', + 'Marquita', + 'Chiquita', + 'Charlotte', + 'Chantelle', + 'Cassandra', + 'Cara', + 'Brandi', + 'Asha', + 'Tatiana', + 'Haaheo', + 'Valerie', + 'Valencia', + 'Shoso', + 'Yoshimi', + 'Bristol', + 'Mikio', + 'Nobuyuki', + 'Tomio', + 'Kazumi', + 'Kunio', + 'Yoshiharu', + 'Balentin', + 'Paublo', + 'Nobuyoshi', + 'Toshiaki', + 'Matsuo', + 'Hachiro', + 'Tokio', + 'Eichi', + 'Manabu', + 'Masanori', + 'Yoshiyuki', + 'Tokuo', + 'Eustolio', + 'Petra', + 'Fukuichi', + 'Haruyoshi', + 'Eastin', + 'Keygan', + 'Kelin', + 'Lalo', + 'Ramona', + 'Felis', + 'Rodgers', + 'Deigo', + 'Guerin', + 'Arrington', + 'Bradin', + 'Aurora', + 'Calistro', + 'Ervie', + 'Velma', + 'Whit', + 'Adarian', + 'Jakevion', + 'Jadrien', + 'Calub', + 'Kaegan', + 'Jamorian', + 'Milam', + 'Usiel', + 'Drayven', + 'Orange', + 'Daelon', + 'Jatavion', + 'Vastine', + 'Preciliano', + 'Floyce', + 'Billye', + 'Burney', + 'Consepcion', + 'Dason', + 'Osie', + 'Tashaun', + 'Sajid', + 'Umair', + 'Tymarion', + 'Jakorian', + 'Ginobili', + 'Areeb', + 'Jonovan', + 'Jonavan', + 'Jaqualyn', + 'Billey', + 'Luisgustavo', + 'Lamario', + 'Telford', + 'Lekendrick', + 'Brinton', + 'Lebarron', + 'Marrio', + 'Tyshun', + 'Kendarrius', + 'Zylan', + 'Jarrius', + 'Kadarrius', + 'Marvis', + 'Orie', + 'Kimber', + 'Jakevious', + 'Shawndale', + 'Jakel', + 'Jaquarious', + 'Deakon', + 'Brevan', + 'Rochester', + 'Lemmie', + 'Athony', + 'Rosie', + 'Lillie', + 'Mozell', + 'Aubert', + 'Kimble', + 'Jaymon', + 'Gaza', + 'Lysle', + 'Wasco', + 'Zigmond', + 'Addie', + 'Erastus', + 'Claudius', + 'Audley', + 'Thadeus', + 'Exum', + 'Caldwell', + 'Emmert', + 'Teagen', + 'Royden', + 'Mykale', + 'Lindberg', + 'Elmon', + 'Norfleet', + 'Radford', + 'Romulus', + 'Thedore', + 'Cor', + 'Ledarrius', + 'Cyncere', + 'Hurbert', + 'Pearly', + 'Jobie', + 'Garvey', + 'Meade', + 'Casmir', + 'Bertie', + 'Belvin', + 'Lynford', + 'Verdun', + 'Junie', + 'Dover', + 'Harlee', + 'Romolo', + 'Sirr', + 'Bradey', + 'Kingsten', + 'Manuelito', + 'Leno', + 'Primo', + 'Antonie', + 'Jane', + 'Halsey', + 'Mujahid', + 'Quron', + 'Cleophas', + 'Amedio', + 'Gildo', + 'Norvel', + 'Livingston', + 'Norvell', + 'Fard', + 'Khaleef', + 'Dorr', + 'Chaquille', + 'Giro', + 'Verdell', + 'Concetto', + 'Taevon', + 'Amato', + 'Hasaan', + 'Burr', + 'Payten', + 'Baden', + 'Abdirizak', + 'Emran', + 'Abdurahman', + 'Greig', + 'Sabree', + 'Shymir', + 'Haakon', + 'Aasim', + 'Abdifatah', + 'Cheemeng', + 'Yuepheng', + 'Hamsa', + 'Abdalla', + 'Samatar', + 'Joshawa', + 'Leeman', + 'Hershal', + 'Fayette', + 'Patty', + 'Thom', + 'Yaaseen', + 'Alven', + 'Hillis', + 'Bard', + 'Nymir', + 'Imir', + 'Mohamud', + 'Muaad', + 'Mickael', + 'Hermann', + 'Varner', + 'Norm', + 'Suheyb', + 'Eivin', + 'Jamy', + 'Taro', + 'Caydin', + 'Masaharu', + 'Cassie', + 'Virgie', + 'Oddie', + 'Pamela', + 'Emmette', + 'Rayshon', + 'Vardaman', + 'Ruble', + 'Clance', + 'Rigdon', + 'Osborn', + 'Gina', + 'Rozell', + 'Marcy', + 'Farron', + 'Bartolomeo', + 'Dierre', + 'Demetrus', + 'Yoneo', + 'Blayke', + 'Decarlo', + 'Sebert', + 'Quayon', + 'Nihar', + 'Segundo', + 'Ritik', + 'Aljaquan', + 'Lealon', + 'Opie', + 'Darshan', + 'Trapper', + 'Ladarrion', + 'Thaine', + 'Abanoub', + 'Filipe', + 'Oley', + 'Zaylan', + 'Rushi', + 'Watie', + 'Cleatus', + 'Harshil', + 'Alferd', + 'Carthel', + 'Ogden', + 'Carmin', + 'Hiren', + 'Harl', + 'Drexel', + 'Shadeed', + 'Malvern', + 'Argus', + 'Sharief', + 'Almalik', + 'Audy', + 'Terral', + 'Nuno', + 'Verna', + 'Alim', + 'Sherron', + 'Terek', + 'Clardie', + 'Shadee', + 'Clendon', + 'Johnpatrick', + 'Chritopher', + 'Taheem', + 'Jahid', + 'Waitman', + 'Jabraylen', + 'Quasim', + 'Azim', + 'Eulis', + 'Wladyslaw', + 'Delmus', + 'Minter', + 'Kharter', + 'Zavhary', + 'Taji', + 'Hoskie', + 'Colsen', + 'Orlanda', + 'Shawntez', + 'Obryan', + 'Emanual', + 'Silviano', + 'Chrishawn', + 'Rayon', + 'Martino', + 'Fairley', + 'Lenward', + 'Autzen', + 'Selby', + 'Odus', + 'Redell', + 'Seavy', + 'Dennison', + 'Jamiere', + 'Rondy', + 'Donold', + 'Lindwood', + 'Laudie', + 'Obert', + 'Jahki', + 'Braidon', + 'Zalen', + 'Zymier', + 'Jahzir', + 'Nahsir', + 'Vikrant', + 'Shourya', + 'Eliyohu', + 'Tyheim', + 'Keyshon', + 'Kaydence', + 'Ekin', + 'Tresean', + 'Quendarius', + 'Shammond', + 'Malakye', + 'Findlay', + 'Ashrith', + 'Elfego', + 'Jalik', + 'Nyzir', + 'Boe', + 'Abdikadir', + 'Jameek', + 'Gyasi', + 'Khyri', + 'Mohit', + 'Shayquan', + 'Sivan', + 'Steffon', + 'Lord', + 'Leor', + 'Kujtim', + 'Haaris', + 'Rafid', + 'Nechemia', + 'Nyles', + 'Khalik', + 'Tysheen', + 'Shaheim', + 'Starling', + 'Taiquan', + 'Takeem', + 'Teshawn', + 'Tuvia', + 'Shu', + 'Schyler', + 'Indalecio', + 'Edouard', + 'Alverto', + 'Alexio', + 'Aurash', + 'Fabiola', + 'Firas', + 'Fredis', + 'Guthrie', + 'Babacar', + 'Ayinde', + 'Khallid', + 'Shadrach', + 'Rikki', + 'Prescott', + 'Saam', + 'Perla', + 'Michell', + 'Markis', + 'Nou', + 'Sher', + 'Tor', + 'Kyre', + 'Shykeem', + 'Jilberto', + 'Klye', + 'Jeramey', + 'Herber', + 'Kue', + 'Mainor', + 'Macaulay', + 'Jequan', + 'Bond', + 'Hykeem', + 'Husam', + 'Catalina', + 'Danh', + 'Aaronmichael', + 'Anthonyjames', + 'Jerrid', + 'Jobani', + 'Kenia', + 'Oshae', + 'Michaelvincent', + 'Mong', + 'Dawit', + 'Dabid', + 'Daisuke', + 'Geddy', + 'Ehab', + 'Jarmal', + 'Caelin', + 'Barak', + 'Gurtej', + 'Geordan', + 'Jacobb', + 'Estefani', + 'Esaul', + 'Karandeep', + 'Jevaughn', + 'Kassim', + 'Kion', + 'Vikas', + 'Infinite', + 'Yekusiel', + 'Zohaib', + 'Yaw', + 'Sakib', + 'Shah', + 'Zeshan', + 'Hassaan', + 'Masai', + 'Mattheus', + 'Jeniel', + 'Martine', + 'Maalik', + 'Jeanclaude', + 'Stirling', + 'Trayveon', + 'Paymon', + 'Ajai', + 'Habib', + 'Enis', + 'Grafton', + 'Nissan', + 'Oshane', + 'Mirza', + 'Malike', + 'Yianni', + 'Zachari', + 'Tadeh', + 'Patrik', + 'Richy', + 'Riki', + 'Yao', + 'Yadira', + 'Nylan', + 'Lennard', + 'Roldan', + 'Admir', + 'Oniel', + 'Addam', + 'Itzel', + 'Ivann', + 'Shabab', + 'Honorio', + 'Hrag', + 'Harutun', + 'Keano', + 'Kayvan', + 'Takahiro', + 'Juanfrancisco', + 'Eri', + 'Ermon', + 'Ramzy', + 'Selma', + 'Kasean', + 'Obrian', + 'Jonatha', + 'Jonahtan', + 'Davione', + 'Chandara', + 'Chantha', + 'Lo', + 'Loreto', + 'Derell', + 'Ganesh', + 'Janathan', + 'Alejandr', + 'Rodolphe', + 'Isaul', + 'Bejan', + 'Doron', + 'Yvette', + 'Erlon', + 'Erland', + 'Yuji', + 'Milagro', + 'Ndrew', + 'Pedram', + 'Thinh', + 'Vandy', + 'Vi', + 'Ryanjoseph', + 'Richar', + 'Hosey', + 'Adeel', + 'Nicholos', + 'Michaeljohn', + 'Philipe', + 'Bravlio', + 'Anup', + 'Davide', + 'Daquann', + 'Lequan', + 'Raymel', + 'Rahsean', + 'Woodley', + 'Jarmel', + 'Wiliam', + 'Joseh', + 'Somnang', + 'Colvin', + 'Jenkins', + 'Jaquawn', + 'Javonne', + 'Javed', + 'Joelle', + 'Lameek', + 'Kishawn', + 'Krikor', + 'Christipher', + 'Ghassan', + 'Essa', + 'Hovig', + 'Nayquan', + 'Shawndell', + 'Rawle', + 'Marwin', + 'Record', + 'Dmario', + 'Crist', + 'La', + 'Access', + 'Shaquel', + 'Tyrrell', + 'Tiquan', + 'Shavon', + 'Shatique', + 'Yochanon', + 'Keontay', + 'Shaquelle', + 'Kshawn', + 'Armend', + 'Eliazer', + 'Diony', + 'Saddam', + 'Takayuki', + 'Sukhdeep', + 'Shahan', + 'Valon', + 'Orel', + 'Tremell', + 'Chayim', + 'Jaquille', + 'Ayodeji', + 'Bekim', + 'Besnik', + 'Oluwanifemi', + 'Stalin', + 'Sadam', + 'Aniel', + 'Laureat', + 'Dyrell', + 'Jhony', + 'Barkim', + 'Ludger', + 'Mahendra', + 'Kadeen', + 'Jovaughn', + 'Khadeem', + 'Ardian', + 'Ravindra', + 'Harpal', + 'Jatinder', + 'Erving', + 'Gerrell', + 'Sylvestre', + 'Luismanuel', + 'Pharell', + 'Jahziah', + 'Salif', + 'Jakyrin', + 'Idrissa', + 'Daoud', + 'Swan', + 'Pryor', + 'Polk', + 'Rameses', + 'Prateek', + 'Lelon', + 'Ebrima', + 'Ezechiel', + 'Tevan', + 'Sohail', + 'Luiseduardo', + 'Clearance', + 'Brayn', + 'Alexsis', + 'Edwar', + 'Johnmark', + 'Hikaru', + 'Edon', + 'Chezkel', + 'Dinari', + 'Ahmadou', + 'Jadien', + 'Ismaeel', + 'Heshy', + 'Jhan', + 'Dejohn', + 'Ajdin', + 'Damier', + 'Cashmere', + 'Amitai', + 'Alp', + 'Avrahom', + 'Hooper', + 'Daichi', + 'Dariush', + 'Bryen', + 'Oseas', + 'Moyses', + 'Alderic', + 'Dickson', + 'Joon', + 'Justinkyle', + 'Jassiah', + 'Jaidin', + 'Lexie', + 'Mieczyslaw', + 'Joffre', + 'Augustino', + 'Adelino', + 'Tadeusz', + 'Humphrey', + 'Lonas', + 'Avry', + 'Tylin', + 'Dixie', + 'Goldman', + 'Yissachar', + 'Toure', + 'Yafet', + 'Siraj', + 'Nasiah', + 'Maor', + 'Roniel', + 'Kerim', + 'Danieljr', + 'Django', + 'Lion', + 'Baruc', + 'Cervando', + 'Akul', + 'Abdi', + 'Ameya', + 'Arhan', + 'Aliou', + 'Arcangel', + 'Avrumy', + 'Deandrea', + 'Dontreal', + 'Yossef', + 'Walden', + 'Tameem', + 'Kenderick', + 'Yassine', + 'Zeyad', + 'Riyad', + 'Kashmere', + 'Tevis', + 'Malichi', + 'Malakhai', + 'Yulian', + 'Clearnce', + 'Esco', + 'Fabrizzio', + 'Gianpaolo', + 'Jaskirat', + 'Termaine', + 'Daouda', + 'Abba', + 'Aaban', + 'Chanoch', + 'Raynell', + 'Ihsan', + 'Djibril', + 'Cassiel', + 'Ishaq', + 'Azlan', + 'Behruz', + 'Amirjon', + 'Anisjon', + 'Asadbek', + 'Dhilan', + 'Dream', + 'Daviel', + 'Mosha', + 'Rayane', + 'Shabsi', + 'Olie', + 'Vinicio', + 'Yuda', + 'Shohjahon', + 'Kylematthew', + 'Kien', + 'Matthewjames', + 'Giorgi', + 'Konstantine', + 'Jibreel', + 'Jadriel', + 'Lliam', + 'Travonte', + 'Taiki', + 'Rendell', + 'Wyland', + 'Arafat', + 'Tajon', + 'Loic', + 'Shaw', + 'Sukhman', + 'Randiel', + 'Stefanos', + 'Lukus', + 'Majesty', + 'Massimiliano', + 'Burach', + 'Jansel', + 'Ismaila', + 'Henoch', + 'Daelin', + 'Giordano', + 'Huber', + 'Rontrell', + 'Simran', + 'Majid', + 'Rayjon', + 'Pharoah', + 'Lamine', + 'Hanoch', + 'Chidi', + 'Jahmani', + 'Javid', + 'Kamani', + 'Endrit', + 'Endy', + 'Nasean', + 'Danyael', + 'Cinque', + 'Akaash', + 'Zeeshan', + 'Amel', + 'Adib', + 'Aboubakar', + 'Artan', + 'Burak', + 'Serigne', + 'Samin', + 'Hovsep', + 'Jomari', + 'Cesareo', + 'Dajohn', + 'Charbel', + 'Bakary', + 'Camerin', + 'Jaquel', + 'Pape', + 'Jahrel', + 'Jahrell', + 'Khadim', + 'Jeison', + 'Yobany', + 'Zaul', + 'Taryn', + 'Abou', + 'Besim', + 'Abdur', + 'Ebrahim', + 'Albi', + 'Haadi', + 'Saba', + 'Wen', + 'Felipedejesus', + 'Dragon', + 'Jamiel', + 'Alecxis', + 'Ashkon', + 'Tejon', + 'Meelad', + 'Renan', + 'Brailyn', + 'Harel', + 'Abdou', + 'Amier', + 'Jonathanjoseph', + 'Juanalberto', + 'Larenz', + 'Nerses', + 'Emmanuelle', + 'Jasmeet', + 'Jahred', + 'Elsworth', + 'Nyshawn', + 'Alexes', + 'Cranford', + 'Trenell', + 'Cephus', + 'Costas', + 'Rama', + 'Nickalas', + 'Moultrie', + 'Deklin', + 'Saafir', + 'Alexie', + 'Kajuan', + 'Jamahl', + 'Robet', + 'Antoin', + 'Turhan', + 'Mart', + 'Richrd', + 'Ante', + 'Bransyn', + 'Dargan', + 'Levan', + 'Milledge', + 'Ollis', + 'Morey', + 'Jeromey', + 'Ebon', + 'Nicholus', + 'Yvonne', + 'Gladstone', + 'Kwan', + 'Sherry', + 'Romney', + 'Nicolaos', + 'Oded', + 'Koty', + 'Mandy', + 'Adger', + 'Esaw', + 'Shaunte', + 'Nimesh', + 'Ahren', + 'Marcellino', + 'Attila', + 'Pinkney', + 'Reinhard', + 'Deanna', + 'Shanti', + 'Calmer', + 'Reda', + 'Darral', + 'Monserrate', + 'Levert', + 'Harce', + 'Ayham', + 'Breslin', + 'Dom', + 'Darrow', + 'Haidar', + 'Willaim', + 'Shann', + 'Regina', + 'Einer', + 'Zui', + 'Shonn', + 'Skipper', + 'Henning', + 'Jacek', + 'Wendelin', + 'Wilmar', + 'Algot', + 'Marlen', + 'Dquan', + 'Emanuele', + 'Erol', + 'Boby', + 'Elbin', + 'Londell', + 'Bradd', + 'Malo', + 'Mohamadali', + 'Toussaint', + 'Roald', + 'Trini', + 'Stace', + 'Erubey', + 'Labron', + 'Kyseem', + 'Duong', + 'Rande', + 'Siegfried', + 'Mamon', + 'Va', + 'Quy', + 'Raman', + 'Ramil', + 'Jasai', + 'Carla', + 'Belen', + 'Lawernce', + 'Jemar', + 'Markham', + 'Kym', + 'Jemaine', + 'Baldwin', + 'Damany', + 'Timonthy', + 'Tesfa', + 'Vinod', + 'Albertus', + 'Yupheng', + 'Danie', + 'Tashiem', + 'Uno', + 'Onnie', + 'Juliana', + 'Duff', + 'Doua', + 'Orman', + 'Kamaal', + 'Godwin', + 'Ulric', + 'Darrold', + 'Rennie', + 'Lory', + 'Jamile', + 'Terril', + 'Gable', + 'Hanh', + 'Grisel', + 'Jimmylee', + 'Mikkel', + 'Victorino', + 'Jaymere', + 'Rayn', + 'Duriel', + 'Ceferino', + 'Autrey', + 'Durant', + 'Kolsen', + 'Abayomi', + 'Azell', + 'Spyros', + 'Ato', + 'Damin', + 'Diogenes', + 'Barnaby', + 'Pinckney', + 'Keno', + 'Sherard', + 'Chukwuemeka', + 'Akin', + 'Harvel', + 'Marv', + 'Kenyetta', + 'Huel', + 'Royzell', + 'Luddie', + 'Olden', + 'Ardith', + 'Branch', + 'Bertha', + 'Hillman', + 'Namon', + 'Donnis', + 'Fitzhugh', + 'Lavaughn', + 'Lucille', + 'Amanuel', + 'Carvin', + 'Minnie', + 'Tivis', + 'Birt', + 'Bronner', + 'Vaden', + 'Joenathan', + 'Alphonsa', + 'Elvie', + 'Alpheus', + 'Clausell', + 'Clayburn', + 'Demetrias', + 'Avis', + 'Garlon', + 'Romaine', + 'Jamorris', + 'Swanson', + 'Perez', + 'Hurschel', + 'Virge', + 'Rutherford', + 'Lelton', + 'Tarris', + 'Denson', + 'Benjaman', + 'Rashun', + 'Keino', + 'Cedarius', + 'Keanthony', + 'Blakeley', + 'Burwell', + 'Kasai', + 'Euell', + 'Eldrick', + 'Ashford', + 'Demetruis', + 'Wood', + 'Blanton', + 'Daniell', + 'Robt', + 'Lamorris', + 'Waller', + 'Devoris', + 'Herley', + 'Jermery', + 'Jamicheal', + 'Horton', + 'Gradie', + 'Etheridge', + 'Millie', + 'Jammy', + 'Karey', + 'Rodregus', + 'Cordera', + 'Embry', + 'Forney', + 'Sims', + 'Gergory', + 'Rosser', + 'Benjamine', + 'Erskin', + 'Heflin', + 'Torrie', + 'Norville', + 'Arvie', + 'Bessie', + 'Keonta', + 'Tarrence', + 'Chapman', + 'Limmie', + 'Tavius', + 'Reynard', + 'Lonza', + 'Detroit', + 'Camauri', + 'Clanton', + 'Obbie', + 'Mizell', + 'Marshel', + 'Tollie', + 'Jondarius', + 'Therion', + 'Antoino', + 'Beatrice', + 'Keyonte', + 'Littleton', + 'Hozie', + 'Atwell', + 'Ottie', + 'Pelham', + 'Vickie', + 'Cederick', + 'Zaykeese', + 'Jadarious', + 'Shin', + 'Tizoc', + 'Mischa', + 'Tycen', + 'Jubal', + 'Kito', + 'Sabin', + 'Brannan', + 'Baltasar', + 'Hilda', + 'Orasio', + 'Bassel', + 'Ameet', + 'Talus', + 'Renne', + 'Reuel', + 'Saro', + 'Kam', + 'Heliodoro', + 'Hodari', + 'Mondo', + 'Damaso', + 'Damein', + 'Thunder', + 'Ravinder', + 'Remberto', + 'Rodel', + 'Yvan', + 'Marcelle', + 'Kiril', + 'Shem', + 'Bardo', + 'Carlson', + 'Jebediah', + 'Austreberto', + 'Hannibal', + 'Shawnn', + 'Kenyatte', + 'Geoffry', + 'Hadden', + 'Natnael', + 'Edurdo', + 'Errik', + 'Eva', + 'Gaelan', + 'Gilverto', + 'Antwaine', + 'Barclay', + 'Rithy', + 'Sarath', + 'Sasan', + 'Stefen', + 'Susana', + 'Le', + 'Mai', + 'Marquies', + 'Neeraj', + 'Galdino', + 'Cuitlahuac', + 'Griselda', + 'Jerret', + 'Filbert', + 'Travone', + 'Lizette', + 'Lourdes', + 'Ratana', + 'Sarith', + 'Ku', + 'Jocob', + 'Jushua', + 'Shaughn', + 'Sophal', + 'Sophana', + 'Stepan', + 'Tramel', + 'Veniamin', + 'Ha', + 'Halley', + 'Hiep', + 'Maclain', + 'Alberta', + 'Alejando', + 'Eliana', + 'Chay', + 'Esmond', + 'Frisco', + 'Dai', + 'Marta', + 'Man', + 'Kha', + 'Kin', + 'Sun', + 'Paulmichael', + 'Rj', + 'Jeoffrey', + 'Custodio', + 'Herberth', + 'Gerrad', + 'Seanpaul', + 'Sten', + 'Nereida', + 'Jasun', + 'Micharl', + 'Robbert', + 'Ronnel', + 'Rosio', + 'Othon', + 'Chau', + 'Hart', + 'Atthew', + 'Angelito', + 'Debbie', + 'Randol', + 'Jeffrie', + 'Kern', + 'Rohn', + 'Raef', + 'Arleigh', + 'Jef', + 'Reg', + 'Vinton', + 'Perrin', + 'Parry', + 'Sally', + 'Hoby', + 'Vint', + 'Dagmawi', + 'Mat', + 'Gregrey', + 'Darol', + 'Merik', + 'Rickard', + 'Clete', + 'Fredrik', + 'Darrol', + 'Lyall', + 'Jamare', + 'Duffy', + 'Barre', + 'Shawnee', + 'Tige', + 'Whittaker', + 'Tyrion', + 'Jamas', + 'Jud', + 'Spence', + 'Dione', + 'Erinn', + 'Bron', + 'Ackley', + 'Dal', + 'Monti', + 'Paco', + 'Kjell', + 'Gabor', + 'Davinder', + 'Shonte', + 'Maximiano', + 'Heshimu', + 'Jassen', + 'Jerami', + 'Jermon', + 'Keefe', + 'Keri', + 'Daric', + 'Christropher', + 'Johnney', + 'Dodd', + 'Wilferd', + 'Raymondo', + 'Keary', + 'Orlan', + 'Gerhart', + 'Clemence', + 'Pepe', + 'Whitaker', + 'Vaughan', + 'Wess', + 'Abenezer', + 'Miroslav', + 'Kurk', + 'Helmut', + 'Timothey', + 'Annette', + 'Cruise', + 'Jahel', + 'Itay', + 'Isaiahs', + 'Isack', + 'Eagan', + 'Finbar', + 'Famous', + 'Ethanjoseph', + 'Ethanjames', + 'Edi', + 'Isais', + 'Albeiro', + 'Abhijot', + 'Joshuajames', + 'Amine', + 'Edwardjames', + 'Donyae', + 'Danieljohn', + 'Avaneesh', + 'Aryav', + 'Andoni', + 'Yeison', + 'Lowen', + 'Obi', + 'Mycah', + 'Moksh', + 'Miliano', + 'Maxamillion', + 'Lazlo', + 'Jocsan', + 'Jibran', + 'Jerimyah', + 'Jefte', + 'Korde', + 'Kanav', + 'Tavita', + 'Taesean', + 'Yoltzin', + 'Xzavior', + 'Vibhav', + 'Romen', + 'Rocket', + 'Rai', + 'Orian', + 'Rumi', + 'Shota', + 'Shaheer', + 'Sadrac', + 'Semaje', + 'Sohrob', + 'Yuval', + 'Yuren', + 'Yannis', + 'Vineet', + 'Yarden', + 'Jesusjr', + 'Kartik', + 'Jairon', + 'Millen', + 'Nahun', + 'Krisna', + 'Kyrese', + 'Mher', + 'Mayan', + 'Kais', + 'Joshuan', + 'Jometh', + 'Keawe', + 'Siris', + 'Sinai', + 'Shuban', + 'Shian', + 'Sneijder', + 'Sota', + 'Uday', + 'Sevak', + 'Royale', + 'Yuuki', + 'Reyhan', + 'Seena', + 'Moisses', + 'Nayib', + 'Sumit', + 'Dayveon', + 'Christianpaul', + 'Garrin', + 'Edgerrin', + 'Edrees', + 'Estephan', + 'Assael', + 'Azad', + 'Tydus', + 'Yosuf', + 'Zekiel', + 'Strider', + 'Senai', + 'Edmar', + 'Dmorea', + 'Eman', + 'Darran', + 'Keston', + 'Keny', + 'Hardeep', + 'Heladio', + 'Hernesto', + 'Hovannes', + 'Sankalp', + 'Brenten', + 'Navraj', + 'Mavrik', + 'Nilmar', + 'Rishit', + 'Edwing', + 'Eswin', + 'Flabio', + 'Jasn', + 'Romar', + 'Sevan', + 'Shahab', + 'Justinmichael', + 'Joseandres', + 'Marcelus', + 'Mariana', + 'Andhy', + 'Angeles', + 'Tannor', + 'Tristain', + 'Joshuaray', + 'Luisdavid', + 'Damaris', + 'Daymond', + 'Anthonyjohn', + 'Dezhon', + 'Emelio', + 'Eulices', + 'Maclean', + 'Jaeson', + 'Ethanjohn', + 'Ethanjacob', + 'Jasiri', + 'Kaisei', + 'Khyle', + 'Jona', + 'Jeren', + 'Jeramyah', + 'Jesusantonio', + 'Jguadalupe', + 'Joseeduardo', + 'Elkin', + 'Prashant', + 'Anguel', + 'Anant', + 'Aisea', + 'Abhimanyu', + 'Daelen', + 'Dylin', + 'Dodge', + 'Nazaret', + 'Mikie', + 'Matthewjoseph', + 'Maximillan', + 'Savir', + 'Dhillon', + 'Donoven', + 'Ebin', + 'Edrei', + 'Elek', + 'Nykolas', + 'Nikash', + 'Nik', + 'Reyly', + 'Razi', + 'Presten', + 'Arul', + 'Avo', + 'Yandell', + 'Wynston', + 'Tallen', + 'Suhaib', + 'Joshuajohn', + 'Jesusmanuel', + 'Malacai', + 'Kethan', + 'Londen', + 'Larenzo', + 'Kriss', + 'Kohei', + 'Hamlet', + 'Martinjr', + 'Mansoor', + 'Archit', + 'Aniketh', + 'Kincaid', + 'Lunden', + 'Masaki', + 'Salam', + 'Sahith', + 'Nour', + 'Miqueas', + 'Estefano', + 'Hatim', + 'Gurvir', + 'Adeeb', + 'Tobiah', + 'Torrin', + 'Tushar', + 'Tyee', + 'Sulayman', + 'Takai', + 'Tayo', + 'Yoan', + 'Vegas', + 'Duilio', + 'Dyami', + 'Greko', + 'Harim', + 'Ioane', + 'Ashmit', + 'Bora', + 'Alekxander', + 'Alexanderjames', + 'Amanpreet', + 'Anthonny', + 'Brandom', + 'Daimon', + 'Sirus', + 'Seananthony', + 'Vignesh', + 'Vir', + 'Wisdom', + 'Rameen', + 'Kenzie', + 'Joshuamichael', + 'Josejr', + 'Joseenrique', + 'Jacksen', + 'Jeriko', + 'Jesua', + 'Myka', + 'Naithen', + 'Saurav', + 'Shalim', + 'Puneet', + 'Denali', + 'Daveyon', + 'Sohil', + 'Edilson', + 'Jafeth', + 'Nathin', + 'Maurion', + 'Mekai', + 'Nadim', + 'Jamani', + 'Jamisen', + 'Gared', + 'Gahel', + 'Emron', + 'Hanzel', + 'Xaviar', + 'Yohann', + 'Alam', + 'Brasen', + 'Ashlan', + 'Rury', + 'Ralphie', + 'Robertanthony', + 'Tomoki', + 'Zamuel', + 'Urian', + 'Vinayak', + 'Wilberth', + 'Jazziel', + 'Mizraim', + 'Mosiah', + 'Muneeb', + 'Lennin', + 'Chaitanya', + 'Cyrille', + 'Dilpreet', + 'Bhargav', + 'Captain', + 'Camil', + 'Jaion', + 'Eithen', + 'Dominyk', + 'Domenik', + 'Imad', + 'Dabin', + 'Ceejay', + 'Avishek', + 'Anoop', + 'Aaronjoshua', + 'Billal', + 'Euan', + 'Eion', + 'Beauregard', + 'Fouad', + 'Chriss', + 'Daimien', + 'Cyan', + 'Conall', + 'Inigo', + 'Jashan', + 'Jaicob', + 'Arek', + 'Benjaminjoseph', + 'Bodey', + 'Andrewjames', + 'Abdel', + 'Alian', + 'Artyom', + 'Anik', + 'Angeljesus', + 'Shriyan', + 'Sosaia', + 'Shabd', + 'Tayveon', + 'Samik', + 'Josephanthony', + 'Kaushal', + 'Gerardojr', + 'Haile', + 'Henok', + 'Imer', + 'Izaiha', + 'Vedanth', + 'Rishav', + 'Praveen', + 'Kenner', + 'Juanjr', + 'Kinan', + 'Maven', + 'Neven', + 'Niccolas', + 'Raynav', + 'Rani', + 'Noahjames', + 'Nirvan', + 'Nevaan', + 'Naythen', + 'Rhythm', + 'Samyak', + 'Sahas', + 'Roczen', + 'Kroy', + 'Johanna', + 'Miro', + 'Mayank', + 'Masson', + 'Yamato', + 'Xaden', + 'Vin', + 'Tyden', + 'Gaudencio', + 'Garreth', + 'Toryn', + 'Jaswinder', + 'Stiles', + 'Graciela', + 'Rutger', + 'Razmig', + 'Keo', + 'Kavir', + 'Kalev', + 'Kal', + 'Kabeer', + 'Jianni', + 'Terrace', + 'Vicken', + 'Westly', + 'Pardeep', + 'Lizeth', + 'Lucia', + 'Mandela', + 'Maricela', + 'Joshus', + 'Kayle', + 'Klyde', + 'Djavan', + 'Wang', + 'Aljandro', + 'Belisario', + 'Cristino', + 'Yihan', + 'Carina', + 'Chritian', + 'Juanramon', + 'Khan', + 'Jaiver', + 'Nefi', + 'Murtaza', + 'Raciel', + 'Marlene', + 'Maira', + 'Chima', + 'Cheenou', + 'Bijon', + 'Dorion', + 'Elber', + 'Emeka', + 'Ge', + 'Ratha', + 'Jaxxson', + 'Ryanjames', + 'Shannen', + 'Shue', + 'Sia', + 'Romaldo', + 'Zareh', + 'Tomy', + 'Vanna', + 'Xao', + 'Bertin', + 'Dhyan', + 'Dexton', + 'Esiah', + 'Ayce', + 'Avyukt', + 'Avner', + 'Caspar', + 'Cove', + 'Ciel', + 'Yen', + 'Yessenia', + 'Yony', + 'Fin', + 'Ezrael', + 'Ezel', + 'Ilay', + 'Harveer', + 'Hamad', + 'Asiah', + 'Ashwath', + 'Arcenio', + 'Aroldo', + 'Awet', + 'Alexx', + 'Arihant', + 'Arihaan', + 'Apolo', + 'Aero', + 'Advith', + 'Arren', + 'Beatriz', + 'Jony', + 'Joseramon', + 'Justinray', + 'Jamaul', + 'Tarren', + 'Cristal', + 'Dinh', + 'Chantra', + 'Dshawn', + 'Geraldine', + 'Fuad', + 'Edlin', + 'Jerren', + 'Jerrin', + 'Josje', + 'Chrystopher', + 'Darriel', + 'Takuya', + 'Vannak', + 'Zenas', + 'Miklos', + 'Marten', + 'Rondale', + 'Rothana', + 'Randeep', + 'Ryle', + 'Eduardoluis', + 'Christepher', + 'Davionne', + 'Eriverto', + 'Farbod', + 'Chauncy', + 'Charle', + 'Bayardo', + 'Ashneel', + 'Shoua', + 'Redmond', + 'Ustin', + 'Johnnathan', + 'Josephmichael', + 'Marisela', + 'Markandrew', + 'Michaeljoseph', + 'Marcua', + 'Nidal', + 'Phat', + 'Pritesh', + 'Seaver', + 'Ryananthony', + 'Tyan', + 'Vatche', + 'Thoren', + 'Othoniel', + 'Nicandro', + 'Rajdeep', + 'Tulio', + 'Soua', + 'Jovonte', + 'Kalyn', + 'Jamesryan', + 'Navdeep', + 'Maxmillian', + 'Kayon', + 'Koua', + 'Aaryn', + 'Wilver', + 'Zubair', + 'Ankush', + 'Andie', + 'Adonnis', + 'Jacobanthony', + 'Izekiel', + 'Izacc', + 'Escher', + 'Elijahjames', + 'Edrik', + 'Drayson', + 'Dj', + 'Giordan', + 'Dejaun', + 'Davidmichael', + 'Deshone', + 'Auron', + 'Auguste', + 'Athos', + 'Cutberto', + 'Hairo', + 'Anvay', + 'Adrick', + 'Aydeen', + 'Bassam', + 'Basem', + 'Kyrell', + 'Rjay', + 'Ozil', + 'Taisei', + 'Samanyu', + 'Marvion', + 'Mykael', + 'Mukund', + 'Namish', + 'Naoki', + 'Nishan', + 'Aideen', + 'Aalijah', + 'Hassani', + 'Harkirat', + 'Exzavier', + 'Hudsen', + 'Hrach', + 'Caelum', + 'Caeleb', + 'Destan', + 'Jaspal', + 'Huan', + 'Marcellous', + 'Mehran', + 'Luisfelipe', + 'Gelacio', + 'Eris', + 'Eneas', + 'Terin', + 'Sohrab', + 'Ravneet', + 'Uziah', + 'Vedansh', + 'Peni', + 'Nethaniel', + 'Niraj', + 'Odilon', + 'Kalden', + 'Mariela', + 'Levonte', + 'Elih', + 'Ej', + 'Eames', + 'Jarome', + 'Jishnu', + 'Gurtaaj', + 'Hamish', + 'Gryffin', + 'Jayin', + 'Trong', + 'Sebastain', + 'Sargon', + 'Wa', + 'Cheveyo', + 'Ariv', + 'Aum', + 'Caellum', + 'Bayan', + 'Balthazar', + 'Sagan', + 'Rowyn', + 'Sehaj', + 'Ivon', + 'Stavro', + 'Shrihan', + 'Noey', + 'Oswin', + 'Abrham', + 'Adalid', + 'Aldric', + 'Zayed', + 'Vonn', + 'Vaishnav', + 'Urias', + 'Yahshua', + 'Yago', + 'Darith', + 'Mantej', + 'Kyo', + 'Khyler', + 'Marcjacob', + 'Nayden', + 'Morrissey', + 'Benedicto', + 'Kendrix', + 'Xang', + 'Ranjit', + 'Raymar', + 'Milos', + 'Rayansh', + 'Rawley', + 'Paxon', + 'Krishang', + 'Leeam', + 'Yerick', + 'Yegor', + 'Viren', + 'Saathvik', + 'Shailen', + 'Sahaj', + 'Rydan', + 'Rollins', + 'Rivaan', + 'Soul', + 'Aerick', + 'Aladdin', + 'Catalino', + 'Berenice', + 'Branndon', + 'Kyleanthony', + 'Maclovio', + 'Kiven', + 'Johnchristopher', + 'Jonh', + 'Kassandra', + 'Jobanny', + 'Pastor', + 'Michaela', + 'Montre', + 'Morgen', + 'Gerber', + 'Danish', + 'Haroutun', + 'Duron', + 'Adrion', + 'Evrett', + 'Reegan', + 'Haskie', + 'Quamane', + 'Derrike', + 'Haydyn', + 'Glenville', + 'Dearl', + 'Deroe', + 'Dewell', + 'Lundy', + 'Cleaster', + 'Jeral', + 'Delontae', + 'Delford', + 'Argie', + 'Loise', + 'Elmar', + 'Donley', + 'Ferrel', + 'Carrel', + 'Athel', + 'Rector', + 'Cledith', + 'Dail', + 'Donzel', + 'Lenoard', + 'Winferd', + 'Birl', + 'Dorsie', + 'Olee', + 'Erman', + 'Dorsel', + 'Roma', + 'Othell', + 'Herold', + 'Chaffee', + 'Trygve', + 'Aubra', + 'Opha', + 'Dionne', + 'Colleen', + 'Ciara', + 'Cleotis', + 'Alissa', + 'Alesha', + 'Elise', + 'Emilie', + 'Tiera', + 'Tia', + 'Suzanne', + 'Jaleesa', + 'Jaclyn', + 'Ingrid', + 'India', + 'Georgia', + 'Francesca', + 'Female', + 'Fatima', + 'Rochelle', + 'Precious', + 'Nichelle', + 'Martina', + 'Lucy', + 'Latonya', + 'Cline', + 'Ott', + 'Ona', + 'Otmer', + 'Ersel', + 'Olufemi', + 'Gordy', + 'Marne', + 'Jahquez', + 'Daeshaun', + 'Nashaun', + 'Seiichi', + 'Shigeki', + 'Kazuto', + 'Shozo', + 'Alhaji', + 'Lonn', + 'Tevion', + 'Kaige', + 'Darlene', + 'Braydyn', + 'Masaaki', + 'Graeson', + 'Bernerd', + 'Lynne', + 'Dewaine', + 'Shig', + 'Junichi', + 'Toshiro', + 'Azavion', + 'Michio', + 'Yoshiro', + 'Heraldo', + 'Epitacio', + 'Mas', + 'Taequan', + 'Trindon', + 'Tirrell', + 'Dmonte', + 'Jaquante', + 'Yeeleng', + 'Maleik', + 'Airam', + 'Noname', + 'Shyhiem', + 'Tyquon', + 'Damonta', + 'Undray', + 'Shadrick', + 'Durwin', + 'Lataurus', + 'Corneall', + 'Dantonio', + 'Tilmon', + 'Mackie', + 'Ebbie', + 'Eligha', + 'Beth', + 'Barth', + 'Hezzie', + 'Artha', + 'Darrie', + 'Frederi', + 'Benford', + 'Elves', + 'Theodia', + 'Jaye', + 'Fran', + 'Khylan', + 'Berwyn', + 'Constance', + 'Markevion', + 'Martavion', + 'Jashun', + 'Jermarion', + 'Taylin', + 'Breland', + 'Franchot', + 'Chrishun', + 'Davarius', + 'Dearius', + 'Tredarius', + 'Jayland', + 'Cortavius', + 'Deyonta', + 'Tradarius', + 'Kemarrion', + 'Markavion', + 'Jmarion', + 'Jacarius', + 'Kairi', + 'Rasool', + 'Jarreau', + 'Khayree', + 'Brahin', + 'Hameed', + 'Rolen', + 'Cleason', + 'Cartez', + 'Nicholad', + 'Brahim', + 'Bryheem', + 'Khalief', + 'Anel', + 'Mcgwire', + 'Lula', + 'Gaddis', + 'Lowery', + 'Odies', + 'Rannie', + 'Artee', + 'Aurther', + 'Bookert', + 'Lenon', + 'Oree', + 'Gennie', + 'Emitt', + 'Sedgie', + 'Claudy', + 'Coyt', + 'Lieutenant', + 'Zannie', + 'Kenn', + 'Roosvelt', + 'Vertis', + 'Elex', + 'Eula', + 'Abron', + 'Perkins', + 'Emersyn', + 'Lakin', + 'Dravin', + 'Other', + 'President', + 'Carrie', + 'Cleother', + 'Estus', + 'Tee', + 'Raymont', + 'Woodard', + 'Ras', + 'Zennie', + 'Versie', + 'Mansfield', + 'Atha', + 'Bossie', + 'Smiley', + 'Kenard', + 'Jermie', + 'Vardell', + 'Kadan', + 'Roney', + 'Furney', + 'Caroll', + 'Benjy', + 'Shamond', + 'Tyrease', + 'Dontre', + 'Raekwan', + 'Raequon', + 'Chrishon', + 'Jahmez', + 'Jaques', + 'Zaveon', + 'Zaccheus', + 'Demaris', + 'Shaquile', + 'Shiheem', + 'Santario', + 'Monterio', + 'Jawaan', + 'Lavere', + 'Levere', + 'Guerino', + 'Lisle', + 'Fraser', + 'Grier', + 'Gurnie', + 'Lattie', + 'Wassil', + 'Domer', + 'Melio', + 'Zolton', + 'Haines', + 'Gervase', + 'Fermon', + 'Geneva', + 'Trask', + 'Linward', + 'Colen', + 'Dossie', + 'Zygmund', + 'Teofil', + 'Talbert', + 'Mosby', + 'Elworth', + 'Garvie', + 'Jiles', + 'Mallie', + 'Flay', + 'Stokes', + 'Bernis', + 'Gardiner', + 'Deno', + 'Algerd', + 'Handy', + 'Flake', + 'Hallet', + 'Coyte', + 'Wingate', + 'Burlie', + 'Sigmond', + 'Myrle', + 'Stiney', + 'Americus', + 'Claxton', + 'Acy', + 'Hill', + 'Fenner', + 'Festus', + 'Linnie', + 'Guilford', + 'Artice', + 'Constant', + 'Faber', + 'Jb', + 'Pleasant', + 'Dallis', + 'Vestal', + 'Terez', + 'English', + 'Allard', + 'Ingram', + 'Beaufort', + 'Chene', + 'Dequante', + 'Bubber', + 'Jamone', + 'Zebulun', + 'Daqwan', + 'Delshawn', + 'Jamond', + 'Dacota', + 'Wilmot', + 'Prue', + 'Wister', + 'Kenyata', + 'Darik', + 'Sumter', + 'Hovie', + 'Tallie', + 'Diontay', + 'Dontaye', + 'Brentt', + 'Felder', + 'Chappell', + 'Ralpheal', + 'Wofford', + 'Stclair', + 'Aiken', + 'Hashem', + 'Daire', + 'Grahm', + 'Jaivon', + 'Davarion', + 'Arnez', + 'Ryer', + 'Mousa', + 'Jahlon', + 'Leyland', + 'Maizen', + 'Zadyn', + 'Zein', + 'Amarri', + 'Hady', + 'Keegen', + 'Taeshawn', + 'Jontae', + 'Radwan', + 'Jsean', + 'Hartwell', + 'Roddey', + 'Arend', + 'Marjorie', + 'Clements', + 'Rae', + 'Pressley', + 'Saintclair', + 'Derrill', + 'Joann', + 'Cote', + 'Philo', + 'Urho', + 'Evart', + 'Vada', + 'Deo', + 'Tonie', + 'Irven', + 'Stjulian', + 'Durand', + 'Diarra', + 'Burnet', + 'Steed', + 'Demont', + 'Burris', + 'Donyell', + 'Gjon', + 'Demone', + 'Jodi', + 'Boban', + 'Brunson', + 'Mackey', + 'Delwyn', + 'Gordie', + 'Owens', + 'Efton', + 'Uel', + 'Ancel', + 'Zafir', + 'Kyeem', + 'Vencil', + 'Irl', + 'Tymeer', + 'Dymere', + 'Kier', + 'Murel', + 'Hale', + 'Lorn', + 'Tahjir', + 'Sufyaan', + 'Trig', + 'Yacqub', + 'Khadir', + 'Najib', + 'Ayuub', + 'Hamse', + 'Yassir', + 'Yussuf', + 'Abdihafid', + 'Abdinasir', + 'Abdiqani', + 'Tayon', + 'Abdirahim', + 'Abdishakur', + 'Mukhtar', + 'Bauer', + 'Damere', + 'Rashee', + 'Kalief', + 'Shyheed', + 'Dejour', + 'Kuran', + 'Qaadir', + 'Aldor', + 'Jasyah', + 'Hajj', + 'Ordell', + 'Gradyn', + 'Ayyub', + 'Atley', + 'Mahkai', + 'Lochlann', + 'Sakai', + 'Saamir', + 'Bernhardt', + 'Willmer', + 'Swen', + 'Hilding', + 'Knute', + 'Wael', + 'Thorvald', + 'Erle', + 'Melroy', + 'Valerian', + 'Jorgen', + 'Dacotah', + 'Shaydon', + 'Lamir', + 'Kahseem', + 'Jihaad', + 'Tylee', + 'Sakariye', + 'Qalid', + 'Syair', + 'Syire', + 'Safi', + 'Zaakir', + 'Sahmir', + 'Saahir', + 'Karlin', + 'Kowen', + 'Kahne', + 'Azir', + 'Tysir', + 'Maki', + 'Zekhi', + 'Pater', + 'Louden', + 'Jandiel', + 'Khaseem', + 'Livio', + 'Pellegrino', + 'Loretta', + 'Lothar', + 'Morty', + 'Harvard', + 'Jeris', + 'Arlene', + 'Salvotore', + 'Erasmus', + 'Canio', + 'Heywood', + 'Ivar', + 'Maitland', + 'Neale', + 'Gladys', + 'Ethelbert', + 'Fergus', + 'Arcangelo', + 'Sigismund', + 'Fremont', + 'Stillman', + 'Egidio', + 'Pincus', + 'Sabatino', + 'Solly', + 'Bela', + 'Stanly', + 'Faust', + 'Gesualdo', + 'Adolphe', + 'Ladislav', + 'Mandel', + 'Philander', + 'Catello', + 'Fordyce', + 'Brownie', + 'Darnley', + 'Alfio', + 'Emerito', + 'Darrly', + 'Delfin', + 'Chiam', + 'Beril', + 'Albie', + 'Roberts', + 'Ferdinando', + 'Maureen', + 'Herberto', + 'Lamark', + 'Philipp', + 'Uwe', + 'Dermott', + 'Amalio', + 'Sandford', + 'Shawnta', + 'Shannan', + 'Sheppard', + 'Jerauld', + 'Antoinne', + 'Oleh', + 'Tobie', + 'Thoms', + 'Valice', + 'Thurnell', + 'Deamonte', + 'Kendel', + 'Trevone', + 'Kaylob', + 'Carder', + 'Antrell', + 'Traven', + 'Jaymir', + 'Joni', + 'Keisean', + 'Krishawn', + 'Marquelle', + 'Dearis', + 'Delvonte', + 'Jamez', + 'Zebadiah', + 'Kreig', + 'Teran', + 'Resean', + 'Zackory', + 'Lamontae', + 'Albieri', + 'Albiery', + 'Chen', + 'Alexy', + 'Arslan', + 'Taliek', + 'Nakhi', + 'Naphtali', + 'Papa', + 'Pesach', + 'Michoel', + 'Salih', + 'Harshdeep', + 'Elhadj', + 'Izzy', + 'Jahkai', + 'Tyliek', + 'Vasilis', + 'Yaacov', + 'Sohaib', + 'Yissochor', + 'Mir', + 'Jasin', + 'Jensy', + 'Rehman', + 'Nazeer', + 'Jahmil', + 'Enson', + 'Nasif', + 'Rizwan', + 'Samiul', + 'Rahat', + 'Angelos', + 'Avroham', + 'Abdulai', + 'Adir', + 'Enes', + 'Yishay', + 'Doyt', + 'Gal', + 'Shoaib', + 'Quaron', + 'Ishraq', + 'Nazaire', + 'Nyzaiah', + 'Mattia', + 'Javone', + 'Mahesh', + 'Mamady', + 'Johnattan', + 'Jorman', + 'Kaliq', + 'Devendra', + 'Burhan', + 'Zishe', + 'Zeandre', + 'Arel', + 'Shalik', + 'Shameer', + 'Nisson', + 'Ralik', + 'Agim', + 'Amauris', + 'Atif', + 'Samory', + 'Shatiek', + 'Taner', + 'Rafat', + 'Zhen', + 'Radhames', + 'Raliek', + 'Ronel', + 'Sabbir', + 'Saqib', + 'Jeudy', + 'Hesham', + 'Hyun', + 'Lakeem', + 'Mishael', + 'Ivo', + 'Tajay', + 'Taleek', + 'Tishawn', + 'Tyreem', + 'Samori', + 'Nickholas', + 'Pearse', + 'Mamadi', + 'Elhadji', + 'Dawood', + 'Dilon', + 'Ishmel', + 'Yiannis', + 'Jahquel', + 'Jahquell', + 'El', + 'Equan', + 'Ho', + 'Delno', + 'Dinesh', + 'Damel', + 'Temitayo', + 'Tenzing', + 'Wahab', + 'Alisher', + 'Adonijah', + 'Bradan', + 'Efrayim', + 'Elnatan', + 'Elmin', + 'Hossain', + 'Eliav', + 'Azimjon', + 'Dovber', + 'Sheya', + 'Yahia', + 'Jasani', + 'Liav', + 'Kamare', + 'Kaysean', + 'Kinsley', + 'Nikoloz', + 'Nyrell', + 'Wyeth', + 'Jeremaih', + 'Mahin', + 'Matis', + 'Oriel', + 'Mourad', + 'Shmeil', + 'Messi', + 'Jonibek', + 'Jeyren', + 'Keyden', + 'Temur', + 'Tanveer', + 'Zyir', + 'Zidan', + 'Zayyan', + 'Varick', + 'Wesam', + 'Abdoulie', + 'Aqib', + 'Asani', + 'Bless', + 'Hasnain', + 'Hamdan', + 'Getzel', + 'Fatin', + 'Huzaifa', + 'Jarif', + 'Jahlani', + 'Davier', + 'Chuna', + 'Eashan', + 'Rafan', + 'Rakin', + 'Ngawang', + 'Mouhamad', + 'Rohaan', + 'Vanness', + 'Volvy', + 'Javel', + 'Jabir', + 'Jaevion', + 'Fahd', + 'Lean', + 'Machai', + 'Juniel', + 'Kaylin', + 'Jeremiyah', + 'Matisyahu', + 'Menasha', + 'Mikaeel', + 'Gaspard', + 'Lorik', + 'Shuaib', + 'Seif', + 'Shlomy', + 'Shneor', + 'Sonam', + 'Volf', + 'Yussef', + 'Ziv', + 'Krrish', + 'Machi', + 'Endi', + 'Frederik', + 'Abdo', + 'Alif', + 'Elchanan', + 'Yordy', + 'Shafin', + 'Siam', + 'Furkan', + 'Fallou', + 'Devyne', + 'Chaskel', + 'Arbi', + 'Younes', + 'Ziare', + 'Tanyon', + 'Terique', + 'Nicholaos', + 'Nickita', + 'Mordchai', + 'Saifullah', + 'Saliou', + 'Savier', + 'Jahmiere', + 'Jahson', + 'Javoni', + 'Jayel', + 'Jie', + 'Kwadwo', + 'Kahmani', + 'Johansel', + 'Murat', + 'Nasire', + 'Nezar', + 'Seydou', + 'Jamair', + 'Jahmeer', + 'Chanina', + 'Chezky', + 'Zyire', + 'Yoscar', + 'Alassane', + 'Aitan', + 'Dannon', + 'Donelle', + 'Harrington', + 'Sha', + 'Shamal', + 'Josph', + 'Torrell', + 'Ralphy', + 'Sharron', + 'Eleftherios', + 'Gedalia', + 'Kasheen', + 'Manoj', + 'Nuri', + 'Daran', + 'Devanand', + 'Evagelos', + 'Fatmir', + 'Haralambos', + 'Biju', + 'Nilson', + 'Wane', + 'Tarig', + 'Rober', + 'Sharone', + 'Lezer', + 'Odalis', + 'Glenston', + 'Josip', + 'Kostantinos', + 'Rahshawn', + 'Osei', + 'Shariyf', + 'Sotirios', + 'Aneudi', + 'Marios', + 'Biff', + 'Damiano', + 'Shean', + 'Rajendra', + 'Mare', + 'Richad', + 'Jaja', + 'Efstathios', + 'Nephtali', + 'Kowan', + 'Rhonda', + 'Pasqualino', + 'Confesor', + 'Linc', + 'Safet', + 'Sharrieff', + 'Kiron', + 'Damain', + 'Aurohom', + 'Kariem', + 'Tiheim', + 'Dushawn', + 'Kindu', + 'Aswad', + 'Kwane', + 'Oba', + 'Jermayne', + 'Dakeem', + 'Babatunde', + 'Ackeem', + 'Alvi', + 'Adetokunbo', + 'Akeel', + 'Kedwin', + 'Kayron', + 'Mergim', + 'Wilkins', + 'Wojciech', + 'Omair', + 'Kushtrim', + 'Kwamel', + 'Saiquan', + 'Naquon', + 'Quandell', + 'Veton', + 'Shaune', + 'Daguan', + 'Duquan', + 'Jency', + 'Ka', + 'Waqas', + 'Xiao', + 'Mahlik', + 'Kasiem', + 'Navindra', + 'Sayquan', + 'Shaquon', + 'Shiquan', + 'Rameek', + 'Jerelle', + 'Devaun', + 'Jakim', + 'Jaquell', + 'Eury', + 'Shaiquan', + 'Shakeal', + 'Shakiem', + 'Shaleek', + 'Ramesh', + 'Suhail', + 'Tylique', + 'Jawanza', + 'Jonell', + 'Hamdi', + 'Jaimeson', + 'Kerven', + 'Demetreus', + 'Giselle', + 'Aikeem', + 'Akiem', + 'Rondel', + 'Dow', + 'Gregroy', + 'Darnelle', + 'Naguan', + 'Tyronn', + 'Ricke', + 'Dishawn', + 'Rishawn', + 'Tarick', + 'Tynell', + 'Japhet', + 'Francesc', + 'Maximili', + 'Herby', + 'Jaqwan', + 'Kemal', + 'Akeen', + 'Azeez', + 'Devindra', + 'Deryck', + 'Deval', + 'Alessand', + 'Masood', + 'Uladimir', + 'Cadon', + 'Quanah', + 'Zimere', + 'Chatham', + 'Koi', + 'Zymire', + 'Jamaury', + 'Jahmire', + 'Ziyan', + 'Cowen', + 'Jamaurie', + 'Nyquan', + 'Jayleen', + 'Zymiere', + 'Zymarion', + 'Kahmari', + 'Langdon', + 'Zymari', + 'Jymir', + 'Kamaree', + 'Nycere', + 'Sayvion', + 'Jahmarion', + 'Justyce', + 'Tuck', + 'Thayer', + 'Mung', + 'Graison', + 'Delane', + 'Lemoyne', + 'Cinch', + 'Nevada', + 'Dhairya', + 'Jyaire', + 'Yazir', + 'Tahjmir', + 'Sequoyah', + 'Quention', + 'Tanmay', + 'Shreyansh', + 'Ahyan', + 'Aaryav', + 'Zaylin', + 'Laksh', + 'Basheer', + 'Bhavik', + 'Orley', + 'Vestel', + 'Altus', + 'Choice', + 'Bufford', + 'Quasir', + 'Emry', + 'Tressel', + 'Eppie', + 'Jayvier', + 'Prestin', + 'Haydin', + 'Caydan', + 'Corday', + 'Camdin', + 'Brodyn', + 'Liberato', + 'Trayon', + 'Telesfor', + 'Jayko', + 'Lavi', + 'Procopio', + 'Rubel', + 'Karder', + 'Jaymar', + 'Bryor', + 'Gottlob', + 'Saladin', + 'Tunis', + 'Saheed', + 'Alsexander', + 'Davonn', + 'Jaquill', + 'Shakeil', + 'Krunal', + 'Tashon', + 'Doyel', + 'Odes', + 'Thoams', + 'Rasul', + 'Wendyl', + 'Glendale', + 'Ahmid', + 'Altarik', + 'Amish', + 'Jaquis', + 'Dashan', + 'Salaam', + 'Bhavin', + 'Nashid', + 'Tauheed', + 'Jamill', + 'Cordney', + 'Derly', + 'Jamale', + 'Hristopher', + 'Camaron', + 'Domanique', + 'Desmund', + 'Keenon', + 'Paulanthony', + 'Demarques', + 'Meryl', + 'Medard', + 'Erbey', + 'Adrin', + 'Evo', + 'Pal', + 'Deke', + 'Glendal', + 'Tramayne', + 'Aloysuis', + 'Berthal', + 'Ashly', + 'Arien', + 'Teodulo', + 'Johsua', + 'Kelwin', + 'Quintan', + 'Mauel', + 'Quisto', + 'Gaylin', + 'Trayvion', + 'Tracer', + 'Ramsay', + 'Verlan', + 'Kyndal', + 'Donovon', + 'Samuell', + 'Treyveon', + 'Nereo', + 'Areli', + 'Dashun', + 'Devontre', + 'Stran', + 'Zarian', + 'Pacen', + 'Kamakani', + 'Alii', + 'Chidozie', + 'Cobie', + 'Acxel', + 'Jatavian', + 'Kelvon', + 'Keldon', + 'Giezi', + 'Gavon', + 'Virtus', + 'Burdell', + 'Dorrance', + 'Naail', + 'Lantz', + 'Travian', + 'Cleland', + 'Arish', + 'Elyan', + 'Chukwudi', + 'Shahrukh', + 'Coulter', + 'Karver', + 'Seeley', + 'Wynton', + 'Detric', + 'Quenten', + 'Joemichael', + 'Daruis', + 'Tyeler', + 'Montray', + 'Hermenegildo', + 'Donathan', + 'Mckenna', + 'Kijuan', + 'Braijon', + 'Vashawn', + 'Darvell', + 'Kennie', + 'Rejino', + 'Vickey', + 'Lyndall', + 'Reynoldo', + 'Malyk', + 'Armarion', + 'Brit', + 'Trayshawn', + 'Contrell', + 'Eutimio', + 'Dantrel', + 'Darrious', + 'Dawon', + 'Richey', + 'Arrion', + 'Zohair', + 'Randale', + 'Keyshone', + 'Kiwane', + 'Jibri', + 'Devell', + 'Beto', + 'Jaymz', + 'Ritchey', + 'Tremel', + 'Keante', + 'Vontrell', + 'Guadlupe', + 'Esiquiel', + 'Erasto', + 'Dub', + 'Augustas', + 'Panfilo', + 'Vuk', + 'Mickie', + 'Javonni', + 'Riddick', + 'Nikodem', + 'Marrion', + 'Kamareon', + 'Maks', + 'Eliverto', + 'Cresenciano', + 'Jerrol', + 'Joakim', + 'Maddax', + 'Kayvion', + 'Khizar', + 'Haze', + 'Aveon', + 'Amjad', + 'Audwin', + 'Almir', + 'Vicky', + 'Lonell', + 'Jabarie', + 'Jaylun', + 'Damarrion', + 'Mantas', + 'Dannye', + 'Aadarsh', + 'Caelen', + 'Tilton', + 'Kimmie', + 'Josgar', + 'Oleksandr', + 'Keyontae', + 'Fidelio', + 'Wiktor', + 'Maxymilian', + 'Cayce', + 'Rodric', + 'Manrique', + 'Kestutis', + 'Donnald', + 'Grayland', + 'Lavance', + 'Medgar', + 'Chaney', + 'Monta', + 'Lemond', + 'Medford', + 'Mareo', + 'Camerino', + 'Ronold', + 'Lancer', + 'Credell', + 'Elbridge', + 'Stony', + 'Dvid', + 'Hilberto', + 'Erineo', + 'Jerrald', + 'Antawan', + 'Cordario', + 'Levelle', + 'Ramsen', + 'Jigar', + 'Laroyce', + 'Lazerrick', + 'Artez', + 'Cordelro', + 'Creon', + 'Lonzell', + 'Shanton', + 'Orpheus', + 'Terris', + 'Renauld', + 'Deondra', + 'Fontaine', + 'Airrion', + 'Branko', + 'Enemencio', + 'Antiono', + 'Caprice', + 'Danyale', + 'Valdez', + 'Oswell', + 'Tahitoa', + 'Fannie', + 'Estes', + 'Herchel', + 'Seabron', + 'Bunyan', + 'Thelmon', + 'Agnew', + 'Broughton', + 'Harwell', + 'Mather', + 'Quillie', + 'Hardwick', + 'Phinizy', + 'Pope', + 'Addis', + 'Seals', + 'Thelman', + 'Summie', + 'Romano', + 'Zacari', + 'Kortney', + 'Makye', + 'Graycen', + 'Kavari', + 'Kamarri', + 'Ajahni', + 'Dayan', + 'Sharrod', + 'Pheonix', + 'Trentyn', + 'Jacai', + 'Jamesley', + 'Destyn', + 'Maddon', + 'Gianlucas', + 'Aydrian', + 'Bader', + 'Jaise', + 'Godson', + 'Gleb', + 'Jatniel', + 'Yaxiel', + 'Marvins', + 'Miron', + 'Yaroslav', + 'Legrande', + 'Lonzy', + 'Merrell', + 'Flemming', + 'Guerry', + 'Kimothy', + 'Remus', + 'Wyndell', + 'Barnard', + 'Denorris', + 'Edna', + 'Bevan', + 'Warnell', + 'Josie', + 'Arthor', + 'Theartis', + 'Kimsey', + 'Wymon', + 'Duglas', + 'Reshawn', + 'Natrone', + 'Treysen', + 'Davaris', + 'Jocqui', + 'Traivon', + 'Trevonne', + 'Tavarious', + 'Monson', + 'Kevis', + 'Ladonte', + 'Mackenson', + 'Bodee', + 'Chayden', + 'Dequon', + 'Keiondre', + 'Dewan', + 'Taige', + 'Renel', + 'Jasher', + 'Bayler', + 'Dodger', + 'Tyke', + 'Jarvin', + 'Edner', + 'Travonn', + 'Traxton', + 'Malosi', + 'Lavonta', + 'Janard', + 'Kyzer', + 'Packer', + 'Travoris', + 'Frantzy', + 'Makay', + 'Tamari', + 'Kanard', + 'Dairon', + 'Gabriell', + 'Kemaury', + 'Jshaun', + 'Karel', + 'Jakarri', + 'Rubens', + 'Zamauri', + 'Winsley', + 'Giulian', + 'Yosbel', + 'Kevaughn', + 'Jimson', + 'Kendly', + 'Dishon', + 'Dallyn', + 'Jephthe', + 'Luccas', + 'Kemuel', + 'Eddrick', + 'Ahmarion', + 'Amariyon', + 'Artavis', + 'Dewin', + 'Jacarie', + 'Jahn', + 'Janari', + 'Geordy', + 'Mardochee', + 'Jimari', + 'Yoshinobu', + 'Eiji', + 'Yasunobu', + 'Koon', + 'Hidemi', + 'Norio', + 'Kiyomi', + 'Shuichi', + 'Kazuyoshi', + 'Yoshitaka', + 'Kanji', + 'Tetsuro', + 'Asao', + 'Dominador', + 'Shogo', + 'Jakye', + 'Braelin', + 'Chrisangel', + 'Calab', + 'Morio', + 'Seiki', + 'Tsuyoshi', + 'Soichi', + 'Masakatsu', + 'Tadayoshi', + 'Tokuichi', + 'Yoshikatsu', + 'Matsuichi', + 'Lorrin', + 'Javeion', + 'Kail', + 'Jvon', + 'Joshwa', + 'Keylen', + 'Rylon', + 'Oved', + 'Kraven', + 'Koben', + 'Klever', + 'Nedved', + 'Dago', + 'Cortlen', + 'Reeves', + 'Yhair', + 'Xane', + 'Jamori', + 'Jayshon', + 'Jaiveon', + 'Joseth', + 'Drelynn', + 'Haldrin', + 'Keelyn', + 'Nathanuel', + 'Kvon', + 'Jayln', + 'Khyrie', + 'Zayveon', + 'Braxston', + 'Jaceion', + 'Jonavon', + 'Jesaiah', + 'Gaddiel', + 'Tobyn', + 'Becket', + 'Aydyn', + 'Arinze', + 'Dacian', + 'Aadin', + 'Fender', + 'Brysun', + 'Demarious', + 'Kaimi', + 'Ryson', + 'Jarrin', + 'Maleko', + 'Kamakana', + 'Kamalani', + 'Johnavon', + 'Kawena', + 'Aadil', + 'Blayde', + 'Garyn', + 'Izaih', + 'Bryndon', + 'Drelyn', + 'Demarian', + 'Kupaa', + 'Nalu', + 'Makena', + 'Lawaia', + 'Kaimalu', + 'Kanaloa', + 'Oshen', + 'Mj', + 'Kahekili', + 'Koalii', + 'Makua', + 'Promise', + 'Keylin', + 'Kevondrick', + 'Tobenna', + 'Infantboy', + 'Oluwatimilehin', + 'Nathanal', + 'Zakkery', + 'Shariq', + 'Sadler', + 'Rockne', + 'Drelon', + 'Ethon', + 'Catcher', + 'Clayten', + 'Kaniela', + 'Isaack', + 'Josten', + 'Zarius', + 'Tayte', + 'Ugochukwu', + 'Aiman', + 'Eduar', + 'Basel', + 'Canton', + 'Dyron', + 'Keaden', + 'Kayceon', + 'Kyrian', + 'Kree', + 'Jj', + 'Iaan', + 'Hudsyn', + 'Graceson', + 'Gatlyn', + 'Eydan', + 'Jak', + 'Townsend', + 'Owais', + 'Nandan', + 'Rayland', + 'Ridhaan', + 'Dantavious', + 'Lavoris', + 'Maricus', + 'Rodrigus', + 'Aayansh', + 'Chasten', + 'Durante', + 'Johnta', + 'Detavious', + 'Donterrius', + 'Rilyn', + 'Rilee', + 'Marquize', + 'Quinterius', + 'Jamarco', + 'Quinnton', + 'Deston', + 'Aceson', + 'Britten', + 'Adric', + 'Tabias', + 'Lajarvis', + 'Corderius', + 'Romon', + 'Que', + 'Nord', + 'Lerone', + 'Skylan', + 'Tobi', + 'Mccrae', + 'Mathayus', + 'Marcuz', + 'Levii', + 'Lander', + 'Oluwadarasimi', + 'Miklo', + 'Nijah', + 'Nero', + 'Quavis', + 'Zailyn', + 'Whitman', + 'Zavior', + 'Zlatan', + 'Crixus', + 'Cotton', + 'Chukwuebuka', + 'Draden', + 'Caston', + 'Aceyn', + 'Caeson', + 'Brax', + 'Azel', + 'Kaisyn', + 'Hunt', + 'Gaius', + 'Gabrian', + 'Falcon', + 'Iyan', + 'Jayjay', + 'Altonio', + 'Woodruff', + 'Tavare', + 'Kawaski', + 'Dontravious', + 'Gabreil', + 'Holten', + 'Dayvian', + 'Brennyn', + 'Chayson', + 'Dailon', + 'Keyshun', + 'Jaryn', + 'Jamyron', + 'Jakavion', + 'July', + 'Jonanthony', + 'Trenden', + 'Tobechukwu', + 'Yostin', + 'Casin', + 'Kaydyn', + 'Jshawn', + 'Keaghan', + 'Khalen', + 'Haylen', + 'Jamarques', + 'Alyjah', + 'Baylon', + 'Kemontae', + 'Taysean', + 'Slaton', + 'Saxton', + 'Yadir', + 'Tramon', + 'Traevion', + 'Raydon', + 'Raahim', + 'Olamide', + 'Oreoluwa', + 'Zyien', + 'Zayde', + 'Marqavious', + 'Marquavis', + 'Trevious', + 'Zyshonne', + 'Quindarrius', + 'Quintarious', + 'Quinterious', + 'Rodarius', + 'Deontavious', + 'Champion', + 'Decklan', + 'Daxx', + 'Pecos', + 'Jovonni', + 'Jaydrian', + 'Montravius', + 'Gunter', + 'Zerrick', + 'Quontavious', + 'Ayeden', + 'Audi', + 'Bentlie', + 'Brek', + 'Travonne', + 'Daquavious', + 'Jartavious', + 'Keldric', + 'Alezander', + 'Kamen', + 'Taytum', + 'Siler', + 'Yavuz', + 'Zaniel', + 'Yuriel', + 'Draiden', + 'Axzel', + 'Castin', + 'Keeland', + 'Jrake', + 'Jonhatan', + 'Jeziel', + 'Javery', + 'Severino', + 'Olavi', + 'Benoit', + 'Phillips', + 'Lothrop', + 'Konstanty', + 'Mato', + 'Carney', + 'Keithen', + 'Easley', + 'Chanler', + 'Erbie', + 'Ephriam', + 'Kentravion', + 'Kesan', + 'Ladamien', + 'Treshun', + 'Jakyron', + 'Burch', + 'Kaston', + 'Kyndall', + 'Jarden', + 'Shields', + 'Jontrell', + 'Thales', + 'Minnis', + 'Ida', + 'Hildred', + 'Helder', + 'Fernell', + 'Shone', + 'Laterrance', + 'Tuyen', + 'Roshun', + 'Vincient', + 'Ory', + 'Hilman', + 'Calton', + 'Clydell', + 'Vick', + 'Derrin', + 'Silton', + 'Tandy', + 'Emeal', + 'Rual', + 'Cardarius', + 'Jylan', + 'Hodge', + 'Charls', + 'Jacobey', + 'Jaqualon', + 'Jyrin', + 'Calib', + 'Fowler', + 'Kalep', + 'Osco', + 'Treylan', + 'Paschal', + 'Lowry', + 'Tydrick', + 'Ladavion', + 'Roe', + 'Jarmall', + 'Josuha', + 'Quindell', + 'Tra', + 'Jamaria', + 'Jermicheal', + 'Hobie', + 'Oluwaseun', + 'Trimayne', + 'Kaire', + 'Katrell', + 'Tradd', + 'Yohannes', + 'Oluwaseyi', + 'Tyski', + 'Lansana', + 'Tion', + 'Delontay', + 'Tavone', + 'Quante', + 'Taavon', + 'Daquane', + 'Burleigh', + 'Eyoel', + 'Cung', + 'Khodee', + 'Emilien', + 'Laurien', + 'Leonide', + 'Loomis', + 'Antrone', + 'Sewall', + 'Nicollas', + 'Vitor', + 'Jaythian', + 'Jasaun', + 'Tighe', + 'Colman', + 'Antionne', + 'Nygel', + 'Garnell', + 'Jamareon', + 'Alvey', + 'Carvel', + 'Carville', + 'Carlester', + 'Rutledge', + 'Mills', + 'Rayner', + 'Doil', + 'Gregario', + 'Aniseto', + 'Audon', + 'Brevyn', + 'Pio', + 'Tanis', + 'Jasinto', + 'Jaxtin', + 'Nugent', + 'Eldredge', + 'Egon', + 'Jong', + 'Pancho', + 'Lionardo', + 'Susano', + 'Trueman', + 'Braxtin', + 'Delphine', + 'Harroll', + 'Goree', + 'Manuela', + 'Epigmenio', + 'Laureano', + 'Josefina', + 'Tiodoro', + 'Silbestre', + 'Patrocinio', + 'Corando', + 'Maciah', + 'Quintyn', + 'Wrigley', + 'Onie', + 'Noal', + 'Duward', + 'Filomeno', + 'Cleburn', + 'Garvis', + 'Bisente', + 'Cedell', + 'Jap', + 'Rube', + 'Mavis', + 'Jarold', + 'Hijinio', + 'Dewie', + 'Trinida', + 'Jung', + 'Byrd', + 'Mcadoo', + 'Floy', + 'Eldie', + 'Volney', + 'Saragosa', + 'Derward', + 'Francico', + 'Genovevo', + 'Lindley', + 'Lasalle', + 'Borden', + 'Bonny', + 'Claudis', + 'Silberio', + 'Asuncion', + 'Rolly', + 'Doak', + 'Luvender', + 'Thurl', + 'Garl', + 'Arvine', + 'Johnnye', + 'Emiterio', + 'Crisoforo', + 'Eulojio', + 'Edell', + 'Infboy', + 'Ural', + 'Natalia', + 'Delia', + 'Acencion', + 'Joas', + 'Keagon', + 'Reice', + 'Esperanza', + 'Velton', + 'Eufemio', + 'Frumencio', + 'Dominga', + 'Eutiquio', + 'Dois', + 'Gean', + 'Odaniel', + 'Lyndel', + 'Kreigh', + 'Bobbye', + 'Rogue', + 'Deundra', + 'Cambron', + 'Kaitlynn', + 'Kayleigh', + 'Hailee', + 'Piper', + 'Sofia', + 'Carly', + 'Abigayle', + 'Angelina', + 'Tavish', + 'Christophere', + 'Anterrio', + 'Thimothy', + 'Montarius', + 'Marquarius', + 'Labradford', + 'Lawless', + 'Lenis', + 'Camile', + 'Tonya', + 'Hersey', + 'Abbie', + 'Loveless', + 'Aristide', + 'Ovey', + 'Ovide', + 'Robley', + 'Elward', + 'Leory', + 'Earlis', + 'Gaynell', + 'Printes', + 'Elzy', + 'Aswell', + 'Waver', + 'Wilma', + 'Minos', + 'Euclide', + 'Aster', + 'Demarrion', + 'Selbert', + 'Stoy', + 'Brack', + 'Strother', + 'Osa', + 'Ovel', + 'Custer', + 'Keveon', + 'Lenvil', + 'Hargus', + 'Kline', + 'Goldie', + 'Warfield', + 'Wavy', + 'Carless', + 'Proctor', + 'Holston', + 'Philopateer', + 'Loman', + 'Vernis', + 'Forster', + 'Jakie', + 'Martavis', + 'Louard', + 'Corbet', + 'Waldon', + 'Cluster', + 'Lafe', + 'Tayshun', + 'Browder', + 'Moss', + 'Rudell', + 'Loyde', + 'Glendel', + 'Elby', + 'Shafter', + 'Camila', + 'Elaine', + 'Scarlett', + 'Gertrude', + 'Bella', + 'Penelope', + 'Cathy', + 'Lizbeth', + 'Arianna', + 'Agnes', + 'Vicki', + 'Mila', + 'Ximena', + 'Delilah', + 'Stella', + 'Miranda', + 'Valentina', + 'Rosemary', + 'Khloe', + 'Heidi', + 'Desiree', + 'Violet', + 'Gianna', + 'Nayeli', + 'Luna', + 'Doreen', + 'Jennie', + 'Roberta', + 'Sheri', + 'Jeanne', + 'Alina', + 'Celeste', + 'Rosalie', + 'Naomi', + 'Teri', + 'Maryann', + 'Glenda', + 'Lynda', + 'Annabelle', + 'Antoinette', + 'Stephani', + 'Marcia', + 'Sherri', + 'Clara', + 'Julissa', + 'Becky', + 'Marianne', + 'Melody', + 'Sadie', + 'Sienna', + 'Marsha', + 'Belinda', + 'Jaylah', + 'Harriet', + 'Kristine', + 'Elizabet', + 'Paisley', + 'Genevieve', + 'Melinda', + 'Leilani', + 'Aubree', + 'Keira', + 'Kristy', + 'Sheryl', + 'Fernanda', + 'Tami', + 'Daleyza', + 'Rosemarie', + 'Francine', + 'Kristi', + 'Jaqueline', + 'Meagan', + 'Nichole', + 'Athena', + 'Anahi', + 'Marisa', + 'Yaretzi', + 'Lena', + 'Serena', + 'Miley', + 'Izabella', + 'Kate', + 'Joselyn', + 'Margie', + 'Krystle', + 'Dulce', + 'Pam', + 'Traci', + 'Mikayla', + 'Shari', + 'Delores', + 'Nellie', + 'Gisselle', + 'Blanche', + 'Clarissa', + 'Dianne', + 'Maxine', + 'Janis', + 'Carmela', + 'Mabel', + 'Estrella', + 'Emely', + 'Viola', + 'Penny', + 'Viviana', + 'Estelle', + 'Krista', + 'Adalynn', + 'Julianna', + 'Danna', + 'Marina', + 'Sheena', + 'Shawna', + 'Mya', + 'Leona', + 'Leila', + 'Isla', + 'Charlene', + 'Mindy', + 'Bernadette', + 'Audrina', + 'Tricia', + 'Adele', + 'Myrtle', + 'Nataly', + 'Kimberley', + 'Gwendolyn', + 'Emilia', + 'Janine', + 'Paulina', + 'Stefanie', + 'Marguerite', + 'Dayanara', + 'Katina', + 'Brielle', + 'Vera', + 'Jimena', + 'Aileen', + 'Bethany', + 'America', + 'Kellie', + 'Shanice', + 'Roxanne', + 'Darla', + 'Mamie', + 'Jocelyne', + 'Katherin', + 'Lyla', + 'Sonya', + 'Allyson', + 'Debora', + 'Chaya', + 'Jaslene', + 'Malia', + 'Daniella', + 'Alessandra', + 'Aimee', + 'Dina', + 'Arabella', + 'Juliet', + 'Laila', + 'Rhoda', + 'Angie', + 'Everly', + 'Adrianna', + 'Shelia', + 'Jana', + 'Analia', + 'Kamila', + 'Rebekah', + 'Myrna', + 'Concetta', + 'Amaya', + 'Juliette', + 'Litzy', + 'Marely', + 'Londyn', + 'Patti', + 'Adalyn', + 'Marla', + 'Tammie', + 'Cora', + 'Angelique', + 'Fiona', + 'Kari', + 'Jaylene', + 'Lucile', + 'Rubi', + 'Vivienne', + 'Hattie', + 'Noemi', + 'Celina', + 'Dena', + 'Sherlyn', + 'Selina', + 'Bonita', + 'Paulette', + 'Aisha', + 'Susie', + 'Adeline', + 'Elsa', + 'Shania', + 'Yasmin', + 'Dalia', + 'Jacquelyn', + 'Thalia', + 'Trina', + 'Allisson', + 'Chana', + 'Olive', + 'Helene', + 'Nelda', + 'Mireya', + 'Chelsey', + 'Cheri', + 'Kira', + 'Karissa', + 'Lynette', + 'Deneen', + 'Ivette', + 'Roslyn', + 'Kinley', + 'Rosalinda', + 'Lila', + 'Kaylie', + 'Dayana', + 'Melany', + 'Carissa', + 'Aniyah', + 'Kyla', + 'Yulissa', + 'Trisha', + 'Camilla', + 'Ansley', + 'Sarai', + 'Lola', + 'Arline', + 'Lara', + 'Stacie', + 'Annika', + 'Christi', + 'Brisa', + 'Gia', + 'Therese', + 'Abril', + 'Angeline', + 'Isabela', + 'Marcella', + 'Shanna', + 'Stephany', + 'Henrietta', + 'Tasha', + 'Brianne', + 'Rosanne', + 'Luann', + 'Frieda', + 'Renata', + 'Dianna', + 'Celia', + 'Sondra', + 'Aylin', + 'Melba', + 'Catina', + 'Alayna', + 'Mollie', + 'Nathalie', + 'Tabitha', + 'Tracie', + 'Scarlet', + 'Jayne', + 'Rachelle', + 'Jeannette', + 'Addyson', + 'Cecelia', + 'Annabella', + 'Dahlia', + 'Dorothea', + 'Annmarie', + 'Marlys', + 'Deirdre', + 'Evangeline', + 'Melina', + 'Erma', + 'Jeanine', + 'Roxana', + 'Yaritza', + 'Montserrat', + 'Lizzie', + 'Kerri', + 'Yoselin', + 'Migdalia', + 'Rivka', + 'Cathleen', + 'Lorene', + 'Yareli', + 'Bette', + 'Kyra', + 'Janette', + 'Beulah', + 'Danica', + 'Arely', + 'Lexi', + 'Shana', + 'Sherrie', + 'Alexus', + 'Mable', + 'Citlalli', + 'Nadine', + 'Shauna', + 'Ryleigh', + 'Jeri', + 'Phoebe', + 'Jazlyn', + 'Noreen', + 'Keisha', + 'Lora', + 'Brynlee', + 'Alivia', + 'Lottie', + 'Monserrat', + 'Giuliana', + 'Adelyn', + 'Deana', + 'Jacqueli', + 'Makenna', + 'Jeannie', + 'Noelle', + 'Imogene', + 'Daphne', + 'Reyna', + 'Katelynn', + 'Bettie', + 'Carmella', + 'Estefania', + 'Cassandr', + 'Betsy', + 'Brianda', + 'Iliana', + 'Bryanna', + 'Aranza', + 'Rihanna', + 'Anissa', + 'Alisa', + 'Azul', + 'Milagros', + 'Gemma', + 'Freda', + 'Ada', + 'Bettye', + 'Nia', + 'Oralia', + 'Alaina', + 'Anabelle', + 'Destinee', + 'Sallie', + 'Sonja', + 'Willow', + 'Staci', + 'Lia', + 'Breana', + 'Eliza', + 'Mikaela', + 'Mona', + 'Cataleya', + 'Jeannine', + 'Lilah', + 'Anabel', + 'Ashlynn', + 'Aleena', + 'Estella', + 'Ayla', + 'Adelaide', + 'Lilliana', + 'Kristie', + 'Nettie', + 'Cherie', + 'May', + 'Myra', + 'Nicolette', + 'Lissette', + 'Siena', + 'Ivanna', + 'Christa', + 'Caylee', + 'Roseann', + 'Anastasia', + 'Karin', + 'Corinne', + 'Ginger', + 'Flora', + 'Bria', + 'Gretchen', + 'Maryellen', + 'Lana', + 'Harmony', + 'Elvira', + 'Ilene', + 'Iesha', + 'Celine', + 'Faye', + 'Khadijah', + 'Elyse', + 'Joana', + 'Sharyn', + 'Leia', + 'Catherin', + 'Corina', + 'Sheree', + 'Salma', + 'Deja', + 'Liz', + 'Aracely', + 'Roselyn', + 'Samara', + 'Lorrie', + 'Frida', + 'Tessie', + 'Talia', + 'Rosalind', + 'Jailene', + 'Lisette', + 'Raelynn', + 'Yetta', + 'Catharine', + 'Adelynn', + 'Odalys', + 'Jolene', + 'Charity', + 'Aniya', + 'Sanjuanita', + 'Norah', + 'Terrie', + 'Yuliana', + 'Lorie', + 'Yazmin', + 'Eleanore', + 'Anika', + 'Elida', + 'Valery', + 'Matilda', + 'Nannie', + 'Eloise', + 'Gillian', + 'Tatyana', + 'Kimora', + 'Brynn', + 'Maliyah', + 'Madilyn', + 'Jenifer', + 'Maddison', + 'Colette', + 'Nanette', + 'Ayleen', + 'Winnie', + 'Jayda', + 'Deloris', + 'Tillie', + 'Kizzy', + 'Galilea', + 'Janessa', + 'Brenna', + 'Amelie', + 'Marybeth', + 'Lorna', + 'Kaia', + 'Sarahi', + 'Viridiana', + 'Rebeca', + 'Ericka', + 'Mareli', + 'Anaya', + 'Nathaly', + 'Candy', + 'Larissa', + 'Elle', + 'Yasmine', + 'Claudine', + 'Kyleigh', + 'Paloma', + 'Lenore', + 'Citlali', + 'Rosanna', + 'Misti', + 'Kasandra', + 'Zara', + 'Isis', + 'Alisson', + 'Cheyanne', + 'Reba', + 'Ariella', + 'Lavonne', + 'Miah', + 'Roxanna', + 'Anabella', + 'Suzette', + 'Kiera', + 'Gitty', + 'Farrah', + 'Helena', + 'Shaniqua', + 'Maryanne', + 'Liana', + 'Arleen', + 'Belle', + 'Katy', + 'Anya', + 'Selene', + 'Maura', + 'Chantel', + 'Keyla', + 'Maryjane', + 'Tisha', + 'Kisha', + 'Kaelyn', + 'Malka', + 'Maci', + 'Evelin', + 'Julianne', + 'Magdalena', + 'Kimberlee', + 'Ernestine', + 'Alyson', + 'Kaley', + 'Danika', + 'Kecia', + 'Leanne', + 'Tonia', + 'Nyla', + 'Ivonne', + 'Madelynn', + 'Ofelia', + 'Lakisha', + 'Adilene', + 'Wendi', + 'Susanne', + 'Katharine', + 'Faigy', + 'Raizy', + 'Tawny', + 'Jackeline', + 'Ariadne', + 'Giovanna', + 'Janiyah', + 'Alani', + 'Nayely', + 'Lilian', + 'Saundra', + 'Jazlynn', + 'Jaelynn', + 'Elliana', + 'Gayla', + 'Deena', + 'Earnestine', + 'Margo', + 'Herlinda', + 'Elinor', + 'Salina', + 'Casandra', + 'Nathalia', + 'Kaila', + 'Deanne', + 'Desirae', + 'Liza', + 'Bobbi', + 'Briella', + 'Gilda', + 'Averie', + 'Charlize', + 'Azalea', + 'Sanjuana', + 'Yajaira', + 'Brandie', + 'Aleah', + 'Della', + 'Elaina', + 'Yahaira', + 'Aja', + 'Bernadine', + 'Lela', + 'Annabel', + 'Xiomara', + 'Kassidy', + 'Nohely', + 'Aubrie', + 'Angelia', + 'Macie', + 'Shelbi', + 'Chelsie', + 'Lilyana', + 'Jazlene', + 'Amina', + 'Dorthy', + 'Noelia', + 'Addisyn', + 'Dalilah', + 'Clarisa', + 'Chrystal', + 'Oleta', + 'Georgina', + 'Adelina', + 'Edythe', + 'Lucinda', + 'Jannie', + 'Minerva', + 'Kelsie', + 'Madisyn', + 'Aida', + 'Katlyn', + 'Julieta', + 'Violeta', + 'Heidy', + 'Lea', + 'Leola', + 'Chasity', + 'Nell', + 'Felicity', + 'Kathi', + 'Karyn', + 'Hana', + 'Micaela', + 'Chandra', + 'Liberty', + 'Cielo', + 'Tameka', + 'Maude', + 'Malky', + 'Coraima', + 'Haylie', + 'Vanesa', + 'Sloane', + 'Karyme', + 'Evelynn', + 'Batsheva', + 'Nallely', + 'Tamra', + 'Maricruz', + 'Paislee', + 'Kynlee', + 'Marcela', + 'Marci', + 'Vonda', + 'Cinthia', + 'Amiyah', + 'Breanne', + 'Lisbeth', + 'Leanna', + 'Anais', + 'Flor', + 'Annemarie', + 'Amie', + 'Estela', + 'Tammi', + 'Rhiannon', + 'Denisse', + 'Leyla', + 'Iridian', + 'Dariana', + 'Romina', + 'Yamileth', + 'Lidia', + 'Sybil', + 'Elvia', + 'Debby', + 'Philomena', + 'Jacklyn', + 'Charlee', + 'Kathie', + 'Aryanna', + 'Katarina', + 'Elianna', + 'Zariah', + 'Andreina', + 'Filomena', + 'Xochitl', + 'Mariam', + 'Myla', + 'Janiya', + 'Kristal', + 'Estefany', + 'Debi', + 'Miracle', + 'Shaindy', + 'Evangelina', + 'Naya', + 'Maeve', + 'Judi', + 'Effie', + 'Lilia', + 'Dayami', + 'Kierra', + 'Vincenza', + 'Cari', + 'Lauri', + 'Bethzy', + 'Trudy', + 'Deidre', + 'Melisa', + 'Luciana', + 'Chantal', + 'Laisha', + 'Kennedi', + 'Ayanna', + 'Madalyn', + 'Dania', + 'Jaliyah', + 'Madilynn', + 'Citlaly', + 'Lolita', + 'Drema', + 'Iva', + 'Kailee', + 'Grecia', + 'Kailyn', + 'Ladonna', + 'Latanya', + 'Maia', + 'Jaquelin', + 'Alanna', + 'Etta', + 'Marlee', + 'Reina', + 'Aiyana', + 'Carolann', + 'Gizelle', + 'Greta', + 'Lynnette', + 'Cecile', + 'Shayna', + 'Savanah', + 'Annalise', + 'Nylah', + 'Lesa', + 'Jolie', + 'Arleth', + 'Laraine', + 'Selah', + 'Alysha', + 'Bridgette', + 'Madyson', + 'Marylou', + 'Adela', + 'Shaina', + 'Trista', + 'Katia', + 'Kayleen', + 'Lilianna', + 'Tamera', + 'Millicent', + 'Eugenia', + 'Myrtice', + 'Baila', + 'Charmaine', + 'Maegan', + 'Ruthie', + 'Jovanna', + 'Julisa', + 'Mayte', + 'Latrice', + 'Priscila', + 'Glenna', + 'Yitty', + 'Tawana', + 'Yessica', + 'Ina', + 'Brittni', + 'Johana', + 'Tess', + 'Caryn', + 'Natalee', + 'Barb', + 'Journee', + 'Malaysia', + 'Yulisa', + 'Alta', + 'Shaila', + 'Maurine', + 'Amira', + 'Tiffani', + 'Danette', + 'Fanny', + 'Justina', + 'Leann', + 'Dafne', + 'Ima', + 'Azucena', + 'Braylee', + 'Amaris', + 'Bailee', + 'Giana', + 'Josette', + 'Raegan', + 'Gena', + 'Luella', + 'Nita', + 'Laney', + 'Gisela', + 'Alexandrea', + 'Rosalia', + 'Odessa', + 'Laci', + 'Yamilex', + 'Tamia', + 'Astrid', + 'Luanne', + 'Gwen', + 'Tabatha', + 'Rivky', + 'Laureen', + 'Zina', + 'Amara', + 'Itzayana', + 'Adamaris', + 'Laylah', + 'Luisa', + 'Georgette', + 'Joselin', + 'Yamilet', + 'Nilda', + 'Luisana', + 'Coleen', + 'Cecily', + 'Jocelynn', + 'Mirella', + 'Jessika', + 'Moriah', + 'Halle', + 'Caren', + 'Earline', + 'Shantel', + 'Aliana', + 'Keila', + 'Maryam', + 'Marianna', + 'Magaly', + 'Sariah', + 'Marnie', + 'Kiersten', + 'Janeth', + 'Lyndsey', + 'Shelli', + 'Jaylee', + 'Ashlie', + 'Tianna', + 'Bree', + 'Isela', + 'Krystina', + 'Yaretzy', + 'Evelina', + 'Sarina', + 'Tyra', + 'Eloisa', + 'Maite', + 'Leilah', + 'Marcie', + 'Imelda', + 'Alena', + 'Juniper', + 'Shelbie', + 'Shakira', + 'Ember', + 'Emmalyn', + 'Elissa', + 'Skyla', + 'Lylah', + 'Xitlali', + 'Gisele', + 'Polly', + 'Ernestina', + 'Sandi', + 'Emmy', + 'Josefa', + 'Magali', + 'Ashely', + 'Eve', + 'Jayde', + 'Rosella', + 'Yuridia', + 'Sheyla', + 'Raelyn', + 'Domenica', + 'Valarie', + 'Herminia', + 'Katalina', + 'Shaquana', + 'Nelly', + 'Rosalyn', + 'Denice', + 'Saanvi', + 'Cambria', + 'Joseline', + 'Tomasa', + 'Milana', + 'Harriett', + 'Devorah', + 'Jackelyn', + 'Jacquelin', + 'Yadhira', + 'Antonella', + 'Shreya', + 'Janay', + 'Betzy', + 'Kaiya', + 'Terra', + 'Roseanne', + 'Karime', + 'Lina', + 'Macey', + 'Vilma', + 'Shaniya', + 'Deyanira', + 'Cindi', + 'Mandi', + 'Sanaa', + 'Lakesha', + 'Essence', + 'Faviola', + 'Brinley', + 'Kirstie', + 'Brissa', + 'Alia', + 'Janney', + 'Kaylynn', + 'Kamilah', + 'Kianna', + 'Adrianne', + 'Yasmeen', + 'Jerri', + 'Anayeli', + 'Ambar', + 'Lorri', + 'Hailie', + 'Demetria', + 'Awilda', + 'Isabell', + 'Leonor', + 'Florine', + 'Tennille', + 'Deann', + 'Nyah', + 'Jolette', + 'Xitlaly', + 'Vienna', + 'Lenora', + 'Keily', + 'Syble', + 'Ciera', + 'Milania', + 'Lainey', + 'Nyasia', + 'Carley', + 'Kelsi', + 'Blossom', + 'Maranda', + 'Ally', + 'Serina', + 'Charli', + 'Taraji', + 'Jena', + 'Natalya', + 'Hortencia', + 'Ila', + 'Kailani', + 'Mira', + 'Evie', + 'Ione', + 'Briseyda', + 'Aryana', + 'Yarely', + 'Susanna', + 'Amya', + 'Kaleigh', + 'Qiana', + 'Juli', + 'Mckayla', + 'Suzan', + 'Fallon', + 'Jacalyn', + 'Ileana', + 'Yesica', + 'Willa', + 'Fatoumata', + 'Arly', + 'Jakayla', + 'Chyna', + 'Jaida', + 'Sunshine', + 'Beyonce', + 'Lawanda', + 'Flossie', + 'Lupita', + 'Demi', + 'Keely', + 'Aliya', + 'Jeanie', + 'Tamiko', + 'Gigi', + 'Brissia', + 'Mariel', + 'Lluvia', + 'Jasleen', + 'Lizet', + 'Brittanie', + 'Kaci', + 'Alycia', + 'Madalynn', + 'Milena', + 'Coraline', + 'Kaela', + 'Soraya', + 'Mozelle', + 'Jessenia', + 'Wilhelmina', + 'Jazmyn', + 'Stefani', + 'Natali', + 'Christiana', + 'Ivana', + 'Eiza', + 'Zaria', + 'Zaira', + 'Lorelei', + 'Cherry', + 'Aline', + 'Briseida', + 'Siani', + 'Yara', + 'Rhianna', + 'Kalia', + 'Destiney', + 'Hindy', + 'Arlette', + 'Shyanne', + 'Joceline', + 'Janell', + 'Vianey', + 'Elnora', + 'Zoie', + 'Elba', + 'Jamila', + 'Rena', + 'Mari', + 'Chava', + 'Scarlette', + 'Shyla', + 'Corine', + 'Kaliyah', + 'Ailyn', + 'Liv', + 'Freya', + 'Diya', + 'Myrtis', + 'Aliah', + 'Margery', + 'Gracelyn', + 'Shira', + 'Riya', + 'Breann', + 'Siobhan', + 'Rochel', + 'Tiffanie', + 'Mirna', + 'Nilsa', + 'Tenley', + 'Aliza', + 'Celena', + 'Vianney', + 'Janel', + 'Toccara', + 'Dayna', + 'Rona', + 'Alba', + 'Althea', + 'Josselyn', + 'Karlie', + 'Alyce', + 'Erlinda', + 'Kadijah', + 'Rosalba', + 'Tangela', + 'Marlena', + 'Delois', + 'Chastity', + 'Coral', + 'Braelynn', + 'Dalila', + 'Rosetta', + 'Lu', + 'Venessa', + 'Kayley', + 'Barbra', + 'Jesica', + 'Dona', + 'Mitzi', + 'Catrina', + 'Gracelynn', + 'Ophelia', + 'Ayana', + 'Mara', + 'Calista', + 'Adyson', + 'Marilynn', + 'Tomeka', + 'Britni', + 'Whitley', + 'Karly', + 'Verenice', + 'Raylee', + 'Dayanna', + 'Shonda', + 'Felecia', + 'Betzaida', + 'Kaylani', + 'Shaylee', + 'Jazzlyn', + 'Giavanna', + 'Vivianna', + 'Jesusa', + 'Lashonda', + 'Maile', + 'Suzy', + 'Vania', + 'Giada', + 'Maisie', + 'Venus', + 'Emerald', + 'Wilda', + 'Saniya', + 'Naydelin', + 'Enid', + 'Leilany', + 'Jesenia', + 'Maliah', + 'Dortha', + 'Dalary', + 'Chany', + 'Amia', + 'Amalia', + 'Khaleesi', + 'Taina', + 'Abbey', + 'Dollie', + 'Joslyn', + 'Sommer', + 'Lilibeth', + 'Charleigh', + 'Sydell', + 'Shoshana', + 'Nechama', + 'Jamya', + 'Jeanmarie', + 'Albertha', + 'Akeelah', + 'Aanya', + 'Destini', + 'Kacie', + 'Maleah', + 'Cayla', + 'Bryana', + 'Zelma', + 'Anjanette', + 'Kaylah', + 'Tonja', + 'Amairani', + 'Karli', + 'Elina', + 'Aurelia', + 'Judie', + 'Letha', + 'Brittnee', + 'Yanira', + 'Ariza', + 'Kataleya', + 'Berta', + 'Soleil', + 'Marleen', + 'Desteny', + 'Gissel', + 'Suri', + 'Anjelica', + 'Lilith', + 'Breeanna', + 'Krysta', + 'Alysia', + 'Chrissy', + 'Lailah', + 'Cathryn', + 'Dawna', + 'Myah', + 'Lelia', + 'Aviana', + 'Xena', + 'Pansy', + 'Jazleen', + 'Kaylyn', + 'Mariann', + 'Celene', + 'Berniece', + 'Anjali', + 'Benita', + 'Reanna', + 'Sydnee', + 'Taliyah', + 'Raylene', + 'Kristyn', + 'Latonia', + 'Pa', + 'Nola', + 'Lyanne', + 'Danae', + 'Sharla', + 'Chanelle', + 'Aleyda', + 'Deb', + 'Sofie', + 'Shameka', + 'Emelia', + 'Miya', + 'Latricia', + 'Claribel', + 'Lacie', + 'Taisha', + 'Queen', + 'Breeana', + 'Ilana', + 'Erna', + 'Neha', + 'Melodie', + 'Ariah', + 'Ursula', + 'Janna', + 'Cienna', + 'Maryjo', + 'Vannessa', + 'Saniyah', + 'Mariajose', + 'Malaya', + 'Abbigail', + 'Elin', + 'Emi', + 'Shanaya', + 'Zahra', + 'Lorine', + 'Karrie', + 'Johnna', + 'Marni', + 'Karis', + 'Shelba', + 'Omayra', + 'Claudette', + 'Anitra', + 'Jenelle', + 'Zelda', + 'Alyse', + 'Alethea', + 'Jannet', + 'Myranda', + 'Corinna', + 'Pattie', + 'Jemma', + 'Avah', + 'Joycelyn', + 'Loriann', + 'Kirstin', + 'Davina', + 'Clementine', + 'Arantza', + 'Esme', + 'Vida', + 'Samira', + 'Alysa', + 'Ananya', + 'Cherish', + 'Jocelin', + 'Renae', + 'Jalisa', + 'Elease', + 'Salena', + 'Zhane', + 'Zulema', + 'Rubye', + 'Amerie', + 'Leatrice', + 'Geralyn', + 'Brigitte', + 'Sibyl', + 'Corrina', + 'Phylicia', + 'Karlee', + 'Kerrie', + 'Addilyn', + 'Alayah', + 'Jacquely', + 'Mirian', + 'Jovana', + 'Katelin', + 'Marielena', + 'Libby', + 'Aditi', + 'Nalani', + 'Lilyanna', + 'Mylee', + 'Goldy', + 'Melia', + 'Audriana', + 'Lillyana', + 'Enriqueta', + 'Tasia', + 'Debbi', + 'Ani', + 'Elyssa', + 'Yamile', + 'Bridgett', + 'Taniya', + 'Britany', + 'Latosha', + 'Shanda', + 'Estephanie', + 'Maudie', + 'Mariyah', + 'Tana', + 'Neva', + 'Kalea', + 'Oma', + 'Jazelle', + 'Neveah', + 'Leonora', + 'Miesha', + 'Corrine', + 'Jordynn', + 'Cornelia', + 'Ronni', + 'Malinda', + 'Janeen', + 'Neriah', + 'Brigette', + 'Windy', + 'Cassondra', + 'Klarissa', + 'Lizzette', + 'Tanika', + 'Izamar', + 'Tera', + 'Arianny', + 'Florene', + 'Evalyn', + 'Poppy', + 'Deisy', + 'Jannette', + 'Thania', + 'Kelsea', + 'Taniyah', + 'Geri', + 'Allyssa', + 'Zariyah', + 'Averi', + 'Leeann', + 'Kallie', + 'Loni', + 'Bryleigh', + 'Rosina', + 'Carlee', + 'Preslee', + 'Alexsandra', + 'Adamari', + 'Saray', + 'Yaneli', + 'Raina', + 'Lianna', + 'Keilani', + 'Tamela', + 'Ninfa', + 'Ireland', + 'Shante', + 'Racheal', + 'Zainab', + 'Blima', + 'Yocheved', + 'Gema', + 'Sayra', + 'Aretha', + 'Nya', + 'Criselda', + 'Anai', + 'Bracha', + 'Amirah', + 'Sury', + 'Twila', + 'Arissa', + 'Livia', + 'Jacquline', + 'Chiara', + 'Anneliese', + 'Quiana', + 'Monika', + 'Charisse', + 'Emerie', + 'Rosalva', + 'Halie', + 'Jenesis', + 'Zaylee', + 'Pricilla', + 'Ouida', + 'Felipa', + 'Latifah', + 'Kalley', + 'Clarice', + 'Nona', + 'Jaunita', + 'Hermelinda', + 'Analy', + 'Jizelle', + 'Theda', + 'Yoselyn', + 'Dottie', + 'Brittaney', + 'Meghann', + 'Azeneth', + 'Richelle', + 'Peggie', + 'Brittny', + 'Jaci', + 'Marietta', + 'Gissell', + 'Evolet', + 'Abbygail', + 'Naima', + 'Noelani', + 'Jaslyn', + 'Katheryn', + 'Ruthann', + 'Shelva', + 'Ashli', + 'Alianna', + 'Felicitas', + 'Delfina', + 'Rayna', + 'Christal', + 'Leta', + 'Tawnya', + 'Zaniyah', + 'Cathie', + 'Antonette', + 'Bethann', + 'Nannette', + 'Vita', + 'Santa', + 'Dejah', + 'Patience', + 'Alessia', + 'Ahuva', + 'Karely', + 'Anette', + 'Alfreda', + 'Cyndi', + 'Cami', + 'Shirlee', + 'Roxann', + 'Alvina', + 'Sima', + 'Star', + 'Tatianna', + 'Krissy', + 'Dreama', + 'Diann', + 'Birdie', + 'Yoshiko', + 'Violette', + 'Mylah', + 'Rosita', + 'Eartha', + 'Miabella', + 'Shanika', + 'Gricel', + 'Ariyah', + 'Emmalee', + 'Nidia', + 'Gladis', + 'Roxie', + 'Zoraida', + 'Kandace', + 'Annamarie', + 'Alannah', + 'Abrielle', + 'Mercy', + 'Lesli', + 'Sydni', + 'Kathrine', + 'Jiselle', + 'Anisa', + 'Felisha', + 'Kayli', + 'Nanci', + 'Ria', + 'Cailyn', + 'Melani', + 'Alyna', + 'Bambi', + 'Avril', + 'Amberly', + 'Towanda', + 'Malissa', + 'Kaleena', + 'Kinsey', + 'Andria', + 'Emogene', + 'Milani', + 'Milah', + 'Hadassah', + 'Avianna', + 'Aubri', + 'Pessy', + 'Dori', + 'Tea', + 'Keshia', + 'Adina', + 'Esha', + 'Magnolia', + 'Moesha', + 'Elana', + 'Vikki', + 'Lakendra', + 'Ilse', + 'Sydnie', + 'Laquita', + 'Hortense', + 'Elouise', + 'Tarah', + 'Shamika', + 'Genoveva', + 'Margot', + 'Aubrielle', + 'Aya', + 'Aleta', + 'Shantell', + 'Angelle', + 'Lakeshia', + 'Leota', + 'Stormie', + 'Caryl', + 'Cristy', + 'Sydelle', + 'Analisa', + 'Earlene', + 'Syreeta', + 'Paityn', + 'Citlally', + 'Nikole', + 'Leandra', + 'Elda', + 'Lizbet', + 'Blimy', + 'Lorelai', + 'Gittel', + 'Jasmyn', + 'Verania', + 'Zoya', + 'Anyssa', + 'Jeniffer', + 'Dorene', + 'Makaila', + 'Earlean', + 'Ysabella', + 'Brandee', + 'Nailea', + 'Stefany', + 'Amiya', + 'Carolee', + 'Kassie', + 'Theodora', + 'Merissa', + 'Skylah', + 'Alesia', + 'Leela', + 'Madge', + 'Shanta', + 'Soledad', + 'Sharonda', + 'Thea', + 'Capri', + 'Amparo', + 'Concha', + 'Karolina', + 'Keitha', + 'Harriette', + 'Evette', + 'Mylie', + 'Isha', + 'Suzie', + 'Carlene', + 'Brunilda', + 'Annamae', + 'Ariadna', + 'Sanai', + 'Gisell', + 'Danelle', + 'Dovie', + 'Lani', + 'Shavonne', + 'Janiah', + 'Kora', + 'Jessa', + 'Melva', + 'Yehudis', + 'Analee', + 'Enedina', + 'Oaklee', + 'Aubrianna', + 'Velia', + 'Zooey', + 'Dolly', + 'Shanae', + 'Lyndsay', + 'Allene', + 'Kamya', + 'Tedra', + 'Yecenia', + 'Nyree', + 'Shyann', + 'Kandice', + 'Edwina', + 'Aiyanna', + 'Carli', + 'Sariyah', + 'Gwyneth', + 'Roseanna', + 'Charla', + 'Nereyda', + 'Yides', + 'Helaine', + 'Evita', + 'Alanis', + 'Starr', + 'Rosalee', + 'Yaire', + 'Risa', + 'Kristel', + 'Greidys', + 'Lillianna', + 'Khushi', + 'Triniti', + 'Lilyan', + 'Myesha', + 'Kala', + 'Moira', + 'Neida', + 'Gisel', + 'Myriam', + 'Anali', + 'Izabel', + 'Savana', + 'Sanjana', + 'Willodean', + 'Briza', + 'Lyra', + 'Merry', + 'Cheryle', + 'Porsha', + 'Kaili', + 'Buffy', + 'Deidra', + 'Everleigh', + 'Gardenia', + 'Italia', + 'Novella', + 'Sahara', + 'Sirena', + 'Elide', + 'Madisen', + 'Katerina', + 'Ashlea', + 'Rianna', + 'Samatha', + 'Diandra', + 'Shanell', + 'Annalee', + 'Samiyah', + 'Joselyne', + 'Maylin', + 'Jazmyne', + 'Terese', + 'Nydia', + 'Stasia', + 'Saira', + 'Carlota', + 'Kathia', + 'Katya', + 'Elodie', + 'Priya', + 'Malena', + 'Aadhya', + 'Meera', + 'Tayla', + 'Jovita', + 'Rafaela', + 'Faiga', + 'Jaquelyn', + 'Elisheva', + 'Debbra', + 'Melyssa', + 'Chelsi', + 'Gricelda', + 'Tawanda', + 'Sharlene', + 'Mellissa', + 'Alene', + 'Amayah', + 'Nicolle', + 'Yanet', + 'Zissy', + 'Candi', + 'Hedwig', + 'Leyna', + 'Nichol', + 'Reva', + 'Fraidy', + 'Esty', + 'Kaily', + 'Mimi', + 'Shani', + 'Hadlee', + 'Naomy', + 'Kinslee', + 'Emmalynn', + 'Alverta', + 'Anushka', + 'Tinsley', + 'Armida', + 'Cleta', + 'Analise', + 'Ahtziri', + 'Anakaren', + 'Tracee', + 'Glynda', + 'Kaelynn', + 'Carie', + 'Avalon', + 'Eboni', + 'Shameeka', + 'Letitia', + 'Enola', + 'Rasheeda', + 'Taylee', + 'Jerrica', + 'Janely', + 'Taya', + 'Xochilt', + 'Rosana', + 'Doretha', + 'Henny', + 'Shaniece', + 'Charleen', + 'Abigale', + 'Marylyn', + 'Retha', + 'Keren', + 'Elly', + 'Ailani', + 'Aarna', + 'Starla', + 'Maren', + 'Nan', + 'Marivel', + 'Georgianna', + 'Era', + 'Kirra', + 'Maisha', + 'Caydence', + 'Dinah', + 'Noemy', + 'Tamatha', + 'Madonna', + 'Kristan', + 'Keana', + 'Kloe', + 'Maribeth', + 'Sana', + 'Korina', + 'Irania', + 'Izabelle', + 'Roxy', + 'Mariaguadalupe', + 'Sulema', + 'Vivien', + 'Tatia', + 'Holli', + 'Debrah', + 'Kattie', + 'Kaidence', + 'Cathey', + 'Anniston', + 'Refugia', + 'Renita', + 'Aubriella', + 'Kaleah', + 'Zuleyka', + 'Sherie', + 'Tomika', + 'Charisma', + 'Caridad', + 'Kailynn', + 'Gertie', + 'Jaslynn', + 'Agatha', + 'Avani', + 'Hennessy', + 'Pamala', + 'Malak', + 'Raizel', + 'Kami', + 'Rosalina', + 'Ferne', + 'Cloe', + 'Jeryl', + 'Louann', + 'Jacie', + 'Tais', + 'Johnsie', + 'Brittnie', + 'Collette', + 'Lettie', + 'Jeanna', + 'Kyara', + 'Renada', + 'Abrianna', + 'Nayelli', + 'Alda', + 'Yuna', + 'Cristi', + 'Yazmine', + 'Marlie', + 'Milly', + 'Anastacia', + 'Daria', + 'Caitlynn', + 'Shriya', + 'Vianca', + 'Sayuri', + 'Dennise', + 'Aleyna', + 'Jenni', + 'Tanesha', + 'Suzanna', + 'Zaniya', + 'Kesha', + 'Edie', + 'Ansleigh', + 'Emmie', + 'Marjory', + 'Lanette', + 'Babette', + 'Alaya', + 'Palma', + 'Tamie', + 'Nelle', + 'Haydee', + 'Zeinab', + 'Stephania', + 'Biridiana', + 'Yoshie', + 'Mayme', + 'Michaele', + 'Marimar', + 'Winona', + 'Christene', + 'Meadow', + 'Ariya', + 'Daleysa', + 'Thuy', + 'Nautica', + 'Hadleigh', + 'Aliyana', + 'Annabell', + 'Stacia', + 'Leonore', + 'Albina', + 'Daira', + 'Rhona', + 'Lisbet', + 'Alizae', + 'Aminata', + 'Samanta', + 'Jerilyn', + 'Darci', + 'Sudie', + 'Kynleigh', + 'Marva', + 'Karie', + 'Marbella', + 'Franchesca', + 'Kylah', + 'Lillyanna', + 'Melony', + 'Abygail', + 'Yulianna', + 'Sahana', + 'Velvet', + 'Michelina', + 'Treva', + 'Iona', + 'Adilynn', + 'Milla', + 'Teressa', + 'Coretta', + 'Venita', + 'Evalynn', + 'Chynna', + 'Janett', + 'Nohemi', + 'Symone', + 'Kaycee', + 'Racquel', + 'Jerica', + 'Chanda', + 'Vannesa', + 'Deasia', + 'Alanah', + 'Dasha', + 'Dian', + 'Iyana', + 'Katlin', + 'Shizue', + 'Mitsuko', + 'Shara', + 'Shanelle', + 'Sinead', + 'Jacinda', + 'Alecia', + 'Tanvi', + 'Genese', + 'Crissy', + 'Niki', + 'Shanequa', + 'Trish', + 'Shalonda', + 'Darleen', + 'Magda', + 'Annalisa', + 'Lashanda', + 'Carin', + 'Nahomi', + 'Londynn', + 'Alaysia', + 'Annaliese', + 'Valorie', + 'Naidelyn', + 'Abbe', + 'Karley', + 'Cinda', + 'Marilu', + 'Azaria', + 'Kitty', + 'Mechelle', + 'Jazzmin', + 'Malina', + 'Cianna', + 'Leesa', + 'Nahla', + 'Dorotha', + 'Jaeda', + 'Tinley', + 'Kelis', + 'Ayesha', + 'Cinthya', + 'Shawnte', + 'Fawn', + 'Calleigh', + 'Mittie', + 'Aide', + 'Lisset', + 'Tyesha', + 'Devora', + 'Analeigh', + 'Anahy', + 'Donnamarie', + 'Nala', + 'Haruko', + 'Lesia', + 'Aideliz', + 'Emme', + 'Mitsue', + 'Jamiya', + 'Joleen', + 'Missy', + 'Shawanda', + 'Chastelyn', + 'Jaleah', + 'Eulalia', + 'Elvera', + 'Kalina', + 'Adrina', + 'Nicolasa', + 'Belia', + 'Elodia', + 'Kazuko', + 'Ixchel', + 'Leena', + 'Yoseline', + 'Yocelin', + 'Jamiyah', + 'Mariama', + 'Audrianna', + 'Dasia', + 'Ieshia', + 'Malorie', + 'Toniann', + 'Genessis', + 'Makeda', + 'Cherise', + 'Tarsha', + 'Karri', + 'Romayne', + 'Beronica', + 'Nubia', + 'Shasta', + 'Cristin', + 'Cristine', + 'Eryn', + 'Jazzmine', + 'Alyssia', + 'Verona', + 'Divya', + 'Beatrix', + 'Chiyoko', + 'Destinie', + 'Hali', + 'Myisha', + 'Sabina', + 'Chante', + 'Brea', + 'Aundrea', + 'Harmoni', + 'Iyanna', + 'Rosaria', + 'Hettie', + 'Bronte', + 'Constanza', + 'Heavenly', + 'Georgiana', + 'Coco', + 'Eleni', + 'Brylie', + 'Ajee', + 'Jerrie', + 'Zella', + 'Xenia', + 'Djuana', + 'Bianka', + 'Lizett', + 'Destany', + 'Bettina', + 'Pennie', + 'Ciji', + 'Ciani', + 'Tosha', + 'Roxane', + 'Tenisha', + 'Pepper', + 'Ayva', + 'Dynasty', + 'Krysten', + 'Maud', + 'Janene', + 'Yomaira', + 'Kizzie', + 'Oriana', + 'Antionette', + 'Kamille', + 'Candis', + 'Kimberlie', + 'Britta', + 'Malika', + 'Khalilah', + 'Louisa', + 'Maiya', + 'Shanay', + 'Kellye', + 'Gaye', + 'Rosangelica', + 'Breonna', + 'Jenae', + 'Kaylene', + 'Rileigh', + 'Linnea', + 'Tawanna', + 'Harleen', + 'Tamya', + 'Makaylah', + 'Annabeth', + 'Alysson', + 'Adella', + 'Adalee', + 'Karisa', + 'Rosangela', + 'Ema', + 'Dayra', + 'Tena', + 'Mathilda', + 'Magan', + 'Dayanira', + 'Annelise', + 'Takisha', + 'Rosamaria', + 'Shifra', + 'Vianna', + 'Daysi', + 'Jalissa', + 'Samaya', + 'Aubriana', + 'Alora', + 'Emmeline', + 'Elora', + 'Laylani', + 'Willene', + 'Cathrine', + 'Ginny', + 'Lashunda', + 'Mikalah', + 'Kiyoko', + 'Wynter', + 'Zuleima', + 'Alease', + 'Louella', + 'Jubilee', + 'Allegra', + 'Karmen', + 'Emiliana', + 'Jianna', + 'Eisley', + 'Emmaline', + 'Teresita', + 'Mackenna', + 'Lauretta', + 'Krystin', + 'Kalene', + 'Aviva', + 'Zena', + 'Shanique', + 'Glynis', + 'Toya', + 'Linsey', + 'Denisha', + 'Marysol', + 'Marcelina', + 'Makiyah', + 'Masako', + 'Cintia', + 'Sharen', + 'Lahoma', + 'Magen', + 'Alyvia', + 'Shaniyah', + 'Anamaria', + 'Shivani', + 'Hannia', + 'Chavy', + 'Hayleigh', + 'Jaycie', + 'Mayah', + 'Delila', + 'Danita', + 'Modesta', + 'Arcelia', + 'Deedee', + 'Monserrath', + 'Angelie', + 'Mellisa', + 'Leisa', + 'Melannie', + 'Mafalda', + 'Kinlee', + 'Annetta', + 'Freida', + 'Anisha', + 'Mayrin', + 'Dajah', + 'Delylah', + 'Hortensia', + 'Joretta', + 'Lexy', + 'Laysha', + 'Anessa', + 'Jesusita', + 'Pearline', + 'Caleigh', + 'Liset', + 'Leilene', + 'Jaya', + 'Haily', + 'Tatyanna', + 'Desire', + 'Lisha', + 'Mindi', + 'Ivelisse', + 'Amariah', + 'Blythe', + 'Treasure', + 'Latarsha', + 'Emelda', + 'Latavia', + 'Debanhi', + 'Brynleigh', + 'Gala', + 'Jurnee', + 'Joslynn', + 'Harleigh', + 'Trang', + 'Audree', + 'Brande', + 'Genea', + 'Carri', + 'Kandy', + 'Kenisha', + 'Georgene', + 'Kamora', + 'Anabell', + 'Meranda', + 'Renesmee', + 'Rosaura', + 'Linette', + 'Rosamond', + 'Candida', + 'Crista', + 'Keeley', + 'Mykayla', + 'Rina', + 'Jonna', + 'Lorinda', + 'Wynona', + 'Kylene', + 'Kellee', + 'Elayne', + 'Chela', + 'Zykeria', + 'Shawnna', + 'Jaimee', + 'Zuleyma', + 'Britnee', + 'Mikala', + 'Coletta', + 'Morelia', + 'Isadora', + 'Anayah', + 'Amiah', + 'Ailin', + 'Jordana', + 'Casie', + 'Shakia', + 'Cordelia', + 'Analeah', + 'Janelly', + 'Adelita', + 'Yoana', + 'Lizabeth', + 'Latoria', + 'Pricila', + 'Margaretta', + 'Fumiko', + 'Lura', + 'Toshiko', + 'Marge', + 'Luana', + 'Marilee', + 'Jeana', + 'Tallulah', + 'Zia', + 'Betsabe', + 'Delanie', + 'Jenicka', + 'Kensington', + 'Navya', + 'Golda', + 'Kambree', + 'Orpha', + 'Rayleigh', + 'Kinleigh', + 'Karleigh', + 'Avalynn', + 'Addilynn', + 'Cambree', + 'Brinlee', + 'Liba', + 'Zendaya', + 'Farah', + 'Oumou', + 'Aislinn', + 'Karena', + 'Erendira', + 'Mariaelena', + 'Temperance', + 'Angelic', + 'Khadija', + 'Jonelle', + 'Aniah', + 'Aleigha', + 'Samaria', + 'Dedra', + 'Sammantha', + 'Bernardine', + 'Leilanie', + 'Makaela', + 'Samiya', + 'Porsche', + 'Krystel', + 'Simona', + 'Catarina', + 'Joi', + 'Etty', + 'Jannat', + 'Rubie', + 'Waneta', + 'Shaquita', + 'Shaindel', + 'Alida', + 'January', + 'Riana', + 'Jamilet', + 'Jala', + 'Gearldine', + 'Iola', + 'Tiesha', + 'Ariyana', + 'Josslyn', + 'Verla', + 'Gerri', + 'Emili', + 'Jennyfer', + 'Halo', + 'Raya', + 'Asusena', + 'Jessalyn', + 'Anaiah', + 'Sabine', + 'Dorinda', + 'Andriana', + 'Charissa', + 'Cambrie', + 'Daija', + 'Danyelle', + 'Maricarmen', + 'Melania', + 'Glinda', + 'Jaretzy', + 'Keesha', + 'Lucie', + 'Persephone', + 'Veda', + 'Avalyn', + 'Odilia', + 'Teena', + 'Daisha', + 'Shianne', + 'Nadya', + 'Peighton', + 'Shawana', + 'Lateefah', + 'Geena', + 'Aixa', + 'Magdalene', + 'Estefana', + 'China', + 'Tamekia', + 'Audrie', + 'Angely', + 'Charline', + 'Britny', + 'Quanisha', + 'Erykah', + 'Kenzi', + 'Carleigh', + 'Kamiyah', + 'Zayra', + 'Abagail', + 'Sulay', + 'Shelita', + 'Cattleya', + 'Ariela', + 'Yalitza', + 'Marleigh', + 'Colbie', + 'Lavergne', + 'Pyper', + 'Tawni', + 'Kasie', + 'Kati', + 'Cinnamon', + 'Trana', + 'Verda', + 'Romana', + 'Merrily', + 'Landri', + 'Bruchy', + 'Irlanda', + 'Lanie', + 'Kendyl', + 'Sanvi', + 'Akshara', + 'Aneesa', + 'Giulia', + 'Ruchy', + 'Giulianna', + 'Zahara', + 'Sumaya', + 'Guillermina', + 'Araseli', + 'Jackelin', + 'Norine', + 'Ariane', + 'Naidelin', + 'Gwenyth', + 'Kya', + 'Liyah', + 'Danya', + 'Sujey', + 'Grayce', + 'Honey', + 'Assunta', + 'Aleksandra', + 'Almeda', + 'Devany', + 'Spring', + 'Patrica', + 'Delisa', + 'Fantasia', + 'Cydney', + 'Laquisha', + 'Lynsey', + 'Stephenie', + 'Cassaundra', + 'Elisabet', + 'Echo', + 'Juliann', + 'Micayla', + 'Iridiana', + 'Antonietta', + 'Rosaisela', + 'Bayleigh', + 'Candelaria', + 'Zaida', + 'Mercedez', + 'Kindra', + 'Malayah', + 'Stephaine', + 'Nayla', + 'Tameeka', + 'Kiesha', + 'Pooja', + 'Sahar', + 'Paisleigh', + 'Kynslee', + 'Idella', + 'Arelis', + 'Shizuko', + 'Leslee', + 'Acacia', + 'Elexis', + 'Violetta', + 'Sailor', + 'Marceline', + 'Una', + 'Kamilla', + 'Aulani', + 'Aracelis', + 'Kikue', + 'Kasi', + 'Elwanda', + 'Brookelyn', + 'Kellyann', + 'Shaquanna', + 'Marielle', + 'Isel', + 'Agustina', + 'Vergie', + 'Arriana', + 'Perel', + 'Maylee', + 'Navy', + 'Lanell', + 'Rosann', + 'Carmelita', + 'Deisi', + 'Alyza', + 'Nailah', + 'Somaya', + 'Kiarra', + 'Tatiyana', + 'Nelida', + 'Demetra', + 'Thais', + 'Syriana', + 'Nicki', + 'Tyanna', + 'Idaly', + 'Ramonita', + 'Zuzanna', + 'Aiza', + 'Larae', + 'Alyanna', + 'Aleyah', + 'Elayna', + 'Blaire', + 'Laniyah', + 'Rilynn', + 'Kandi', + 'Sherryl', + 'Marti', + 'Cherri', + 'Kimberli', + 'Carma', + 'Trena', + 'Darcie', + 'Evelyne', + 'Allissa', + 'Meliza', + 'Regine', + 'Adalina', + 'Siya', + 'Seraphina', + 'Calliope', + 'Jiya', + 'Talisa', + 'Mistie', + 'Ignacia', + 'Crysta', + 'Lona', + 'Voncile', + 'Rutha', + 'Kamiya', + 'Anslee', + 'Janya', + 'Berenise', + 'Sonji', + 'Yaeko', + 'Nika', + 'Queena', + 'Yatziri', + 'Aiko', + 'Lisamarie', + 'Evalina', + 'Alline', + 'Alejandrina', + 'Trula', + 'Hinda', + 'Delinda', + 'Brisia', + 'Aminah', + 'Mariella', + 'Nayzeth', + 'Sherlin', + 'Idalia', + 'Madaline', + 'Shenika', + 'Janaya', + 'Fabiana', + 'Aleeah', + 'Lasonya', + 'Jania', + 'Breindy', + 'Mitzy', + 'Yaquelin', + 'Tzipora', + 'Serene', + 'Mikaila', + 'Aicha', + 'Brucha', + 'Myrka', + 'Kaaren', + 'Meg', + 'Lise', + 'Suhani', + 'Liane', + 'Celisse', + 'Jasmyne', + 'Sharde', + 'Dannielle', + 'Crystle', + 'Jenniffer', + 'Shaneka', + 'Leslye', + 'Hedy', + 'Tashina', + 'Letisia', + 'Carys', + 'Antonetta', + 'Tamisha', + 'Kaniya', + 'Darline', + 'Alizay', + 'Minna', + 'Raelene', + 'Rebecka', + 'Martika', + 'Makiya', + 'Idalis', + 'Keasia', + 'Breeann', + 'Vlasta', + 'Ellianna', + 'Caelyn', + 'Kaytlin', + 'Cathi', + 'Jamia', + 'Tahnee', + 'Zulma', + 'Mallorie', + 'Katlynn', + 'Mahi', + 'Carleen', + 'Honesty', + 'Rasheedah', + 'Ronna', + 'Lissa', + 'Sherika', + 'Carolynn', + 'Romona', + 'Jamesha', + 'Shakiyla', + 'Mccall', + 'Joanie', + 'Makala', + 'Brionna', + 'Shaunna', + 'Hawa', + 'Marylin', + 'Baylie', + 'Preslie', + 'Aaralyn', + 'Pia', + 'Beatris', + 'Adria', + 'Arianne', + 'Carmina', + 'Sebrina', + 'Malani', + 'Lovely', + 'Jahaira', + 'Miyah', + 'Sylvie', + 'Cassi', + 'Kaniyah', + 'Cailin', + 'Santina', + 'Nariah', + 'Calandra', + 'Georgine', + 'Serafina', + 'Keyana', + 'Amethyst', + 'Tehya', + 'Avni', + 'Alessa', + 'Novalee', + 'Mayleen', + 'Aadya', + 'Jacquelynn', + 'Izetta', + 'Sumiko', + 'Irasema', + 'Annamaria', + 'Niya', + 'Latrina', + 'Cicely', + 'Kristiana', + 'Kimiko', + 'Keara', + 'Mazie', + 'Najah', + 'Evelia', + 'Tiarra', + 'Jaela', + 'Montine', + 'Mandie', + 'Lavada', + 'Dimple', + 'Emiko', + 'Yocelyn', + 'Issabella', + 'Rowena', + 'Tanja', + 'Velda', + 'Chantell', + 'Gretel', + 'Jacelyn', + 'Kambri', + 'Zayla', + 'Anasofia', + 'Atiana', + 'Dulcemaria', + 'Zulay', + 'Tari', + 'Sahasra', + 'Rayleen', + 'Greydis', + 'Shiela', + 'Florinda', + 'Samya', + 'Shakima', + 'Shakeema', + 'Yanely', + 'Lavina', + 'Azalee', + 'Oneta', + 'Tammye', + 'Kelsy', + 'Kalie', + 'Keanna', + 'Daniya', + 'Antonina', + 'Katharin', + 'Tiare', + 'Yorley', + 'Jeslyn', + 'Emeli', + 'Zakia', + 'Massiel', + 'Latesha', + 'Jenessa', + 'Jayna', + 'Raylynn', + 'Ainslee', + 'Aralynn', + 'Khloee', + 'Ily', + 'Emeri', + 'Jeni', + 'Kassi', + 'Nakita', + 'Lakia', + 'Ariyanna', + 'Addalyn', + 'Keyanna', + 'Bibiana', + 'Genna', + 'Kathya', + 'Leana', + 'Trane', + 'Yomira', + 'Brigid', + 'Dionna', + 'Jerilynn', + 'Sarita', + 'Altha', + 'Laniya', + 'Zakiya', + 'Akilah', + 'Celestina', + 'Priyanka', + 'Taliah', + 'Donya', + 'Soila', + 'Quetzalli', + 'Cristel', + 'Naia', + 'Kailah', + 'Zitlaly', + 'Tonda', + 'Cate', + 'Lizzet', + 'Vesta', + 'Sherilyn', + 'Teruko', + 'Aldona', + 'Armandina', + 'Ciana', + 'Amairany', + 'Elysia', + 'Samarah', + 'Janyla', + 'Skylee', + 'Rolanda', + 'Sapphire', + 'Setsuko', + 'Miyoko', + 'Contina', + 'Imogen', + 'Jailine', + 'Vanellope', + 'Leora', + 'Jennah', + 'Perl', + 'Analiyah', + 'Hellen', + 'Tyasia', + 'Symphony', + 'Amada', + 'Otilia', + 'Avigail', + 'Tzivia', + 'Fradel', + 'Mariadelcarmen', + 'Ilona', + 'Dyan', + 'Zahraa', + 'Patrisia', + 'Jersey', + 'Lilla', + 'Lossie', + 'Somer', + 'Deserie', + 'Jaila', + 'Briseis', + 'Aniston', + 'Idell', + 'Raeleigh', + 'Gracyn', + 'Everlee', + 'Laurene', + 'Sherita', + 'Pinkie', + 'Nakisha', + 'Olevia', + 'Corene', + 'Loreen', + 'Sandie', + 'Keosha', + 'Kenleigh', + 'Alli', + 'Alyana', + 'Prisha', + 'Brookelynn', + 'Thaily', + 'Maddie', + 'Grettel', + 'Kinzley', + 'Jailynn', + 'Kalli', + 'Jazzlynn', + 'Klaudia', + 'Blanch', + 'Mariafernanda', + 'Makenzi', + 'Shonna', + 'Lita', + 'Karima', + 'Rebeccah', + 'Isaura', + 'Kalee', + 'Jori', + 'Allysa', + 'Tonisha', + 'Neda', + 'Jenine', + 'Chanell', + 'Jamaya', + 'Lorrayne', + 'Birtha', + 'Kanisha', + 'Nicollette', + 'Desiray', + 'Kaity', + 'Shamya', + 'Kathlene', + 'Jann', + 'Sari', + 'Lucila', + 'Tressie', + 'Charise', + 'Kalista', + 'Jamileth', + 'Kalena', + 'Sakura', + 'Blondell', + 'Thomasina', + 'Aila', + 'Mossie', + 'Tamala', + 'Siri', + 'Gertha', + 'Reta', + 'Easter', + 'Tala', + 'Vivianne', + 'Nila', + 'Merida', + 'Ahana', + 'Lanelle', + 'Hilaria', + 'Arlys', + 'Inell', + 'Rylynn', + 'Cosette', + 'Penne', + 'Jenevieve', + 'Jenilee', + 'Carlotta', + 'Ziva', + 'Hildegard', + 'Aleshia', + 'Nedra', + 'Madelaine', + 'Lisandra', + 'Pang', + 'Sindy', + 'Zenaida', + 'Lulu', + 'Shanya', + 'Shakema', + 'Katiria', + 'Raffaela', + 'Solange', + 'Illiana', + 'Chelsy', + 'Shanee', + 'Adriene', + 'Tyla', + 'Cailey', + 'Daijah', + 'Melonie', + 'Courteney', + 'Deysi', + 'Makinley', + 'Brynna', + 'Hildegarde', + 'Fiorella', + 'Kenadee', + 'Ellyn', + 'Ebonie', + 'Thu', + 'Charde', + 'Kaytlyn', + 'Kenadie', + 'Georgeann', + 'Analicia', + 'Emalee', + 'Shatara', + 'Lucerito', + 'Mckell', + 'Atiya', + 'Stormi', + 'Maleny', + 'Nariyah', + 'Steffanie', + 'Kirstyn', + 'Zayda', + 'Mariadejesus', + 'Deeann', + 'Abcde', + 'Eleanora', + 'Pearle', + 'Seana', + 'Denine', + 'Presleigh', + 'Keziah', + 'Queenie', + 'Henchy', + 'Merari', + 'Joscelyn', + 'Celest', + 'Mirel', + 'Sania', + 'Maryah', + 'Angelena', + 'Emelyn', + 'Gissele', + 'Fanta', + 'Gaylene', + 'Adelaida', + 'Madie', + 'Maja', + 'Nashaly', + 'Christel', + 'Rachele', + 'Raniyah', + 'Rashel', + 'Kavya', + 'Callista', + 'Elmira', + 'Rifky', + 'Syeda', + 'Tresa', + 'Detra', + 'Jarely', + 'Prisila', + 'Enedelia', + 'Trany', + 'Lainie', + 'Yisel', + 'Alynna', + 'Allysson', + 'Tamica', + 'Velva', + 'Nancee', + 'Breleigh', + 'Shanita', + 'Orelia', + 'Patrici', + 'Daja', + 'Shardae', + 'Abriana', + 'Halee', + 'Dorcas', + 'Kathey', + 'Rosia', + 'Princesa', + 'Lezly', + 'Dawnmarie', + 'Gaby', + 'Ania', + 'Denae', + 'Jahzara', + 'Jaymie', + 'Bari', + 'Suzann', + 'Alnisa', + 'Fatimah', + 'Zakiyyah', + 'Yana', + 'Naimah', + 'Tyisha', + 'Kathaleen', + 'Sameerah', + 'Chesney', + 'Shanteria', + 'Pamella', + 'Rayven', + 'Romelia', + 'Lucretia', + 'Tova', + 'Aura', + 'Chelsee', + 'Roizy', + 'Manha', + 'Nisha', + 'Tierney', + 'Girl', + 'Taelor', + 'Litzi', + 'Sneha', + 'Natisha', + 'Alliyah', + 'Sully', + 'Twyla', + 'Daisey', + 'Sarahy', + 'Shemeka', + 'Lexis', + 'Shalanda', + 'Kelcie', + 'Natacha', + 'Amyah', + 'Byanka', + 'Kymberly', + 'Navil', + 'Britani', + 'Karolyn', + 'Emelie', + 'Zana', + 'Vernita', + 'Leigha', + 'Romy', + 'Arlet', + 'Jazlin', + 'Laynie', + 'Jesslyn', + 'Adilyn', + 'Karoline', + 'Nyomi', + 'Maycee', + 'Nicol', + 'Daliah', + 'Lillyann', + 'Shawnda', + 'Dede', + 'Wiktoria', + 'Liah', + 'Liya', + 'Emmerson', + 'Aarohi', + 'Aribella', + 'Brayleigh', + 'Sumie', + 'Elke', + 'Taja', + 'Ahsley', + 'Tisa', + 'Dannette', + 'Gidget', + 'Misao', + 'Adelle', + 'Jamiah', + 'Joselynn', + 'Jalyssa', + 'Marnita', + 'Trinitee', + 'Bev', + 'Aleida', + 'Cloey', + 'Tahlia', + 'Melodee', + 'Anaiya', + 'Clover', + 'Prudence', + 'Kalynn', + 'Dezirae', + 'Solana', + 'Reena', + 'Mariko', + 'Tiffiny', + 'Elinore', + 'Madelyne', + 'Anela', + 'Bess', + 'Perri', + 'Loree', + 'Cyndy', + 'Yolonda', + 'Jolee', + 'Tequila', + 'Sumer', + 'Cherilyn', + 'Ela', + 'Kenlee', + 'Alexxis', + 'Larisa', + 'Nevaeha', + 'Nira', + 'Shaquasia', + 'Shanel', + 'Medina', + 'Rifka', + 'Sable', + 'Atara', + 'Aissatou', + 'Mecca', + 'Anastasi', + 'Falon', + 'Holley', + 'Yuliza', + 'Lili', + 'Siara', + 'Kiarah', + 'Tiffaney', + 'Alyah', + 'Annalia', + 'Naila', + 'Analiah', + 'Aymar', + 'Tambra', + 'Elna', + 'Eola', + 'Tkeyah', + 'Zola', + 'Francheska', + 'Aidee', + 'Alexzandra', + 'Cianni', + 'Myasia', + 'Carisa', + 'Ilah', + 'Yenifer', + 'Veronika', + 'Nahomy', + 'Madysen', + 'Elsy', + 'Lilli', + 'Belva', + 'Steffie', + 'Kaylea', + 'Ginamarie', + 'Sharman', + 'Latia', + 'Shakeria', + 'Audelia', + 'Odette', + 'Shaniah', + 'Diamantina', + 'Lorayne', + 'Ciarra', + 'Wilhelmena', + 'Zaina', + 'Niesha', + 'Kanesha', + 'Turquoise', + 'Tziporah', + 'Timi', + 'Fatou', + 'Karna', + 'Matsue', + 'Vina', + 'Ronisha', + 'Layan', + 'Viktoria', + 'Lilyann', + 'Maliya', + 'Jamilex', + 'Epifania', + 'Fidela', + 'Delphia', + 'Starasia', + 'Glennie', + 'Teodora', + 'Hatsue', + 'Margarett', + 'Margarette', + 'Laronda', + 'Vicenta', + 'Cotina', + 'Meilani', + 'Mannat', + 'Leylani', + 'Lailani', + 'Seerat', + 'Reya', + 'Amilia', + 'Avary', + 'Brocha', + 'Daneen', + 'Kimie', + 'Trudi', + 'Margret', + 'Djuna', + 'Charis', + 'Izzabella', + 'Brionne', + 'Elenora', + 'Lakeitha', + 'Jacki', + 'Beckie', + 'Guinevere', + 'Inara', + 'Landrie', + 'Nicoletta', + 'Ayari', + 'Zaniah', + 'Merlene', + 'Keli', + 'Maricella', + 'Leonela', + 'Donita', + 'Tehani', + 'Susannah', + 'Journi', + 'Machelle', + 'Tammara', + 'Cherrie', + 'Nelva', + 'Destanie', + 'Neyda', + 'Tabetha', + 'Wilhelmenia', + 'Brieanna', + 'Turkessa', + 'Ameera', + 'Avital', + 'Marycruz', + 'Zoila', + 'Tressa', + 'Joellen', + 'Raisa', + 'Bethanie', + 'Ermelinda', + 'Asiyah', + 'Monifa', + 'Samia', + 'Adamary', + 'Anahit', + 'Rania', + 'Miri', + 'Ether', + 'Desirea', + 'Chimere', + 'Erla', + 'Karisma', + 'Nalleli', + 'Larhonda', + 'Darlyn', + 'Anaisa', + 'Suellen', + 'Kamaria', + 'Nashla', + 'Yuriko', + 'Tzirel', + 'Tehila', + 'Myriah', + 'Frimet', + 'Cesilia', + 'Marika', + 'Frady', + 'Deloise', + 'Saleen', + 'Betsey', + 'Merri', + 'Laurette', + 'Sharita', + 'Shena', + 'Porscha', + 'Aerial', + 'Florrie', + 'Ayah', + 'Anusha', + 'Jeanelle', + 'Lessly', + 'Mahogany', + 'See', + 'Hang', + 'Karinna', + 'Leighann', + 'Elexus', + 'Markayla', + 'Kaneesha', + 'Barbie', + 'Aurea', + 'Kaeli', + 'Arwen', + 'Angelyn', + 'Jaclynn', + 'Tesla', + 'Maritsa', + 'Madelin', + 'Alisia', + 'Tyana', + 'Kimberlyn', + 'Dejanae', + 'Dalena', + 'Blessing', + 'Courtnie', + 'Amaria', + 'Micki', + 'Safa', + 'Jadah', + 'Mele', + 'Maryssa', + 'Channel', + 'Lianne', + 'Alea', + 'Chyanne', + 'Addelyn', + 'Aaleyah', + 'Michela', + 'Torri', + 'Indira', + 'Kanani', + 'Lashundra', + 'Mikaylah', + 'Zoee', + 'Taelyn', + 'Noheli', + 'Sarena', + 'Dariela', + 'Adalie', + 'Meggan', + 'Daniyah', + 'Sela', + 'Shaelyn', + 'Maylen', + 'Giovana', + 'Ayvah', + 'Arabelle', + 'Adaline', + 'Isyss', + 'Melanny', + 'Margaux', + 'Klara', + 'Janey', + 'Idolina', + 'Georgetta', + 'Amaiya', + 'Sianna', + 'Rebeka', + 'Meleny', + 'Kelle', + 'Angelika', + 'Malerie', + 'Latara', + 'Niamh', + 'Yevette', + 'Yomayra', + 'Karizma', + 'Nayelie', + 'Shantal', + 'Latoyia', + 'Jenee', + 'Shandra', + 'Magdalen', + 'Yatzari', + 'Jettie', + 'Charlsie', + 'Idy', + 'Inaya', + 'Yitta', + 'Reem', + 'Basya', + 'Skylynn', + 'Elyana', + 'Brynley', + 'Amor', + 'Amberlee', + 'Eternity', + 'Niyah', + 'Emiley', + 'Madeleyn', + 'Korie', + 'Sanaya', + 'Meira', + 'Chevonne', + 'Sabra', + 'Uma', + 'Kaira', + 'Isobel', + 'Elli', + 'Gurleen', + 'Berneice', + 'Alvera', + 'Ambrosia', + 'Roya', + 'Bettyann', + 'Alverda', + 'Tinamarie', + 'Tanasia', + 'Lavonda', + 'Jorja', + 'Heide', + 'Marwa', + 'Annaly', + 'Aaliah', + 'Ileen', + 'Lamonica', + 'Enjoli', + 'Ninel', + 'Milissa', + 'Dawne', + 'Joie', + 'Ashlei', + 'Elidia', + 'Maybelle', + 'Getsemani', + 'Gisella', + 'Mariya', + 'Adisyn', + 'Adia', + 'Caterina', + 'Bettyjane', + 'Kaydee', + 'Rasheda', + 'Camisha', + 'Chassidy', + 'Sadia', + 'Aislyn', + 'Ngoc', + 'Mirka', + 'Lanita', + 'Lashawnda', + 'Liridona', + 'Tynisa', + 'Arnelle', + 'Librada', + 'Marita', + 'Makyla', + 'Raniya', + 'Kandis', + 'Ethelyn', + 'Divina', + 'Genevie', + 'Jadelyn', + 'Ashleen', + 'Saya', + 'Marli', + 'Calli', + 'Anyla', + 'Sheng', + 'Vasiliki', + 'Yelena', + 'Darya', + 'Clarabelle', + 'Shirlene', + 'Tommye', + 'Julieann', + 'Jennefer', + 'Rana', + 'Raeann', + 'Suleima', + 'Lilyanne', + 'Jelisa', + 'Jaymee', + 'Rhylee', + 'Keyli', + 'Brooklin', + 'Meta', + 'Shakirah', + 'Loria', + 'Sharyl', + 'Sharday', + 'Manuelita', + 'Debera', + 'Lera', + 'Jacquie', + 'Ardella', + 'Jameria', + 'Winnifred', + 'Rossana', + 'Shemika', + 'Sedona', + 'Arvilla', + 'Samaira', + 'Aitana', + 'Daiana', + 'Cassia', + 'Lucianna', + 'Tama', + 'Shigeko', + 'Sueko', + 'Hatsuko', + 'Hazle', + 'Lida', + 'Wylene', + 'Sachiko', + 'Tahiry', + 'Renea', + 'Janina', + 'Becki', + 'Vy', + 'Cherryl', + 'Arionna', + 'Marrissa', + 'Randee', + 'Norita', + 'Sonali', + 'Susann', + 'Rachell', + 'Natashia', + 'Aspyn', + 'Malaika', + 'Nuvia', + 'Safiya', + 'Contessa', + 'Julyssa', + 'Analiese', + 'Jacee', + 'Kathlyn', + 'Gracey', + 'Chassity', + 'Kady', + 'Tytiana', + 'Katiana', + 'Eneida', + 'Teela', + 'Roiza', + 'Alaura', + 'Giuseppina', + 'Randa', + 'Danisha', + 'Mariza', + 'Marquisha', + 'Sharese', + 'Deseree', + 'Inaaya', + 'Rivkah', + 'Tawnie', + 'Miriah', + 'Shereen', + 'Candra', + 'Tomiko', + 'Whittney', + 'Aziza', + 'Ayala', + 'Hafsa', + 'Zaynab', + 'Kaileigh', + 'Yarima', + 'Danitza', + 'Maram', + 'Shakeya', + 'Emmer', + 'Kareema', + 'Maayan', + 'Rheanna', + 'Jaritza', + 'Marleny', + 'Zitlali', + 'Vanity', + 'Apryl', + 'Zully', + 'Tashia', + 'Courtnee', + 'Laporsha', + 'Luvenia', + 'Batya', + 'Ayelet', + 'Quetcy', + 'Tiny', + 'Felicita', + 'Omaira', + 'Nyssa', + 'Krystine', + 'Stevi', + 'Michiko', + 'Tennie', + 'Tomekia', + 'Billiejo', + 'Yohana', + 'Krystyna', + 'Kacee', + 'Naja', + 'Charmayne', + 'Twana', + 'Jeane', + 'Brittnay', + 'Cherelle', + 'Raechel', + 'Temeka', + 'Jasmeen', + 'Zuria', + 'Zailey', + 'Saydee', + 'Renatta', + 'Neta', + 'Bg', + 'Italy', + 'Terrica', + 'Goldia', + 'Monae', + 'Yelitza', + 'Ryanne', + 'Samirah', + 'Breckyn', + 'Nicolina', + 'Olympia', + 'Almeta', + 'Tamesha', + 'Zora', + 'Emmaleigh', + 'Loralei', + 'Kennadi', + 'Julieanna', + 'Jenavieve', + 'Shylah', + 'Akemi', + 'Fonda', + 'Nizhoni', + 'Iqra', + 'Gaetana', + 'Coreen', + 'Evonne', + 'Sadako', + 'Angele', + 'Macel', + 'Alinna', + 'Avneet', + 'Jannah', + 'Nickole', + 'Lotus', + 'Yukie', + 'Laiyah', + 'Kynzlee', + 'Mailen', + 'Nobuko', + 'Annaleigh', + 'Otila', + 'Shona', + 'Kimberely', + 'Delcie', + 'Zula', + 'Roselynn', + 'Aleeyah', + 'Bellarose', + 'Damya', + 'Cammie', + 'Treena', + 'Chanie', + 'Kaliah', + 'Abella', + 'Aahana', + 'Mileena', + 'Adaleigh', + 'Keiry', + 'Journie', + 'Myrtie', + 'Tsuruko', + 'Lyda', + 'Fernande', + 'Julee', + 'Estephany', + 'Louvenia', + 'Monserat', + 'Meena', + 'Jayline', + 'Brie', + 'Elicia', + 'Suzana', + 'Dusti', + 'Odile', + 'Hilma', + 'Katarzyna', + 'Jenise', + 'Hiromi', + 'Huong', + 'Deolinda', + 'Pamelia', + 'Awa', + 'Odelia', + 'Mattison', + 'Gwenda', + 'Sera', + 'Yuritzi', + 'Karishma', + 'Kaina', + 'Henna', + 'Norene', + 'Brina', + 'Chyenne', + 'Moncerrat', + 'Keilah', + 'Saphira', + 'Marylee', + 'Meri', + 'Lajuana', + 'Lindsy', + 'Shanise', + 'Sugey', + 'Jaimi', + 'Viki', + 'Ceola', + 'Naiya', + 'Adysen', + 'Shantavia', + 'Amberlyn', + 'Brihanna', + 'Laela', + 'Kenadi', + 'Hermine', + 'Bernita', + 'Deziree', + 'Anja', + 'Lawana', + 'Aletha', + 'Nella', + 'Irelyn', + 'Jakira', + 'Wynema', + 'Janai', + 'Keondra', + 'Venice', + 'Zenobia', + 'Jaelene', + 'Ammy', + 'Alizah', + 'Lakiesha', + 'Azure', + 'Aysha', + 'Saniah', + 'Mahnoor', + 'Ananda', + 'Asma', + 'Aissata', + 'Jaileen', + 'Yailin', + 'Xiana', + 'Laiza', + 'Liseth', + 'Marykate', + 'Daizy', + 'Neoma', + 'Tykeria', + 'Shamiya', + 'Nykeria', + 'Addalynn', + 'Kenzley', + 'Ardyce', + 'Anylah', + 'Vallie', + 'Darlyne', + 'Makiah', + 'Neela', + 'Naraly', + 'Danni', + 'Jolina', + 'Ailene', + 'Lyndia', + 'Erminia', + 'Asiya', + 'Alexius', + 'Mc', + 'Maylene', + 'Signe', + 'Adelfa', + 'Yusra', + 'Keyonna', + 'Yasuko', + 'Yukiko', + 'Augustina', + 'Leen', + 'Fumie', + 'Amora', + 'Annaleah', + 'Anvi', + 'Indie', + 'Haya', + 'Emmarie', + 'Enya', + 'Chieko', + 'Kinsleigh', + 'Shiann', + 'Eufemia', + 'Fusae', + 'Akiko', + 'Hosanna', + 'Alitzel', + 'Araya', + 'Anaiyah', + 'Rosy', + 'Nishka', + 'Gao', + 'Tamiya', + 'Lillyan', + 'Eudelia', + 'Kamea', + 'Berlyn', + 'Kahlan', + 'Alinah', + 'Mahealani', + 'Leeah', + 'Rosalynn', + 'Zadie', + 'Aolanis', + 'Esta', + 'Maisy', + 'Chevelle', + 'Jalayah', + 'Yatziry', + 'Alyne', + 'Jodell', + 'Sariya', + 'Yashica', + 'Jissel', + 'Letty', + 'Mariaisabel', + 'Lizzeth', + 'Yovana', + 'Dyanna', + 'Tamyra', + 'Monzerrat', + 'Seanna', + 'Eldora', + 'Mattea', + 'Zahira', + 'Jeanetta', + 'Aysia', + 'Ashlin', + 'Tenika', + 'Lezlie', + 'Kailie', + 'Jariyah', + 'Jovie', + 'Kiyah', + 'Lynlee', + 'Abriella', + 'Adleigh', + 'Ranada', + 'Vertie', + 'Flonnie', + 'Kynnedi', + 'Lya', + 'Acelynn', + 'Emalyn', + 'Emberly', + 'Yalexa', + 'Izabela', + 'Sadye', + 'Kamyla', + 'Jayleigh', + 'Cayleigh', + 'Ceil', + 'Inger', + 'Cindee', + 'Nena', + 'Loan', + 'Kiya', + 'Laure', + 'Cristen', + 'Celenia', + 'Fredda', + 'Ravyn', + 'Mee', + 'Graci', + 'Azalia', + 'Latina', + 'Hassie', + 'Dinorah', + 'Virna', + 'Autum', + 'Michala', + 'Macayla', + 'Franca', + 'Corissa', + 'Alysse', + 'Monisha', + 'Jessyca', + 'Nisa', + 'Jacqulyn', + 'Makaylee', + 'Ellin', + 'Jameelah', + 'Shalon', + 'Jlynn', + 'Kennady', + 'Brinkley', + 'Providence', + 'Phylis', + 'Eugenie', + 'Clementina', + 'Kadynce', + 'Yuvia', + 'Mailyn', + 'Taneisha', + 'Samone', + 'Aurore', + 'Brienne', + 'Tritia', + 'Fayth', + 'Jayci', + 'Jorie', + 'Loreal', + 'Taylar', + 'Maryn', + 'Melissia', + 'Midori', + 'Hisako', + 'Hulda', + 'Bobbijo', + 'Bulah', + 'Nancye', + 'Melvina', + 'Sherree', + 'Kierstin', + 'Merrilee', + 'Lonna', + 'Judyth', + 'Nancie', + 'Lark', + 'Candyce', + 'Kadejah', + 'Kenda', + 'Fara', + 'Estephania', + 'Cady', + 'Marilin', + 'Kadie', + 'Suleyma', + 'Jacquelyne', + 'Vonetta', + 'Tanairi', + 'Charlott', + 'Shannel', + 'Zenia', + 'Alise', + 'Takara', + 'Lyndsie', + 'Ivett', + 'Letisha', + 'Idania', + 'Lacee', + 'Candie', + 'Camelia', + 'Brittanee', + 'Mariaeduarda', + 'Geovanna', + 'Kirsti', + 'Michaella', + 'Kelsee', + 'Cheryll', + 'Cyrstal', + 'Keriann', + 'Latrisha', + 'Exie', + 'Deborha', + 'Verdie', + 'Zahava', + 'Zuleika', + 'Dorla', + 'Dominiqu', + 'Sharina', + 'Ardeth', + 'Alethia', + 'Starlene', + 'Shamira', + 'Shantelle', + 'Marilou', + 'Kyah', + 'Kyana', + 'Clemencia', + 'Cordie', + 'Meagen', + 'Xitlalic', + 'Gaia', + 'Ellia', + 'Elani', + 'Jaylani', + 'Krisha', + 'Khalia', + 'Aaradhya', + 'Aeris', + 'Avamarie', + 'Artemis', + 'Sheana', + 'Jolynn', + 'Sandee', + 'Wendie', + 'Willia', + 'Loriene', + 'Apolonia', + 'Eusebia', + 'Kazue', + 'Synthia', + 'Harue', + 'Siomara', + 'Nhi', + 'Maleni', + 'Toyoko', + 'Freeda', + 'Hideko', + 'Sherrye', + 'Bethanne', + 'Merrie', + 'Peri', + 'Ozella', + 'Venetia', + 'Revonda', + 'Breauna', + 'Arika', + 'Annissa', + 'Leeza', + 'Siera', + 'Jakiyah', + 'Kamaya', + 'Lashay', + 'Elvina', + 'Laquinta', + 'Faren', + 'Harmonie', + 'Brianny', + 'Jama', + 'Johna', + 'Sharalyn', + 'Aziyah', + 'Hadassa', + 'Shantinique', + 'Treasa', + 'Penni', + 'Shakera', + 'Carolyne', + 'Shaunda', + 'Talya', + 'Karyna', + 'Natosha', + 'Vivica', + 'Pauletta', + 'Laverna', + 'Danasia', + 'Shakita', + 'Sharee', + 'Yajayra', + 'Karlene', + 'Reatha', + 'Laiba', + 'Zamiyah', + 'Shirleen', + 'Bettylou', + 'Nakiya', + 'Eryka', + 'Bailie', + 'Janiece', + 'Keisa', + 'Kiah', + 'Jennica', + 'Niasia', + 'Hildy', + 'Jacquel', + 'Mahina', + 'Eshal', + 'Khloey', + 'Emelin', + 'Eesha', + 'Kaylei', + 'Aymee', + 'Alona', + 'Catelyn', + 'Arushi', + 'Ameerah', + 'Regenia', + 'Brailey', + 'Sparkle', + 'Giavonna', + 'Ashunti', + 'Naudia', + 'Kyrsten', + 'Emmalina', + 'Neve', + 'Aolani', + 'Gizella', + 'Tameika', + 'Leocadia', + 'Nidhi', + 'Wende', + 'Eshaal', + 'Cherice', + 'Lakeysha', + 'Menucha', + 'Ameena', + 'Kloey', + 'Nayelly', + 'Kathryne', + 'Lashawna', + 'Kristle', + 'Zaylie', + 'Keylee', + 'Landree', + 'Wynell', + 'Dezarae', + 'Angelli', + 'Haddie', + 'Ilyana', + 'Jaleigh', + 'Brilee', + 'Lakeya', + 'Kanika', + 'Lavinia', + 'Marykay', + 'Ruthanne', + 'Tenille', + 'Dorine', + 'Esabella', + 'Genavieve', + 'Zarah', + 'Mileidy', + 'Solara', + 'Yamila', + 'Amaia', + 'Season', + 'Cheree', + 'Luise', + 'Tracye', + 'Christeen', + 'Florida', + 'Breona', + 'Kathe', + 'Jakyra', + 'Zury', + 'Lakeesha', + 'Yaneth', + 'Keandra', + 'Agnieszka', + 'Markita', + 'Mariska', + 'Zada', + 'Breasia', + 'Aaniyah', + 'Kambria', + 'Lilit', + 'Sheilah', + 'Cherisse', + 'Hermione', + 'Angeli', + 'Britnie', + 'Lisett', + 'Joette', + 'Nga', + 'Ruthe', + 'Anamarie', + 'Mayeli', + 'Takia', + 'Lien', + 'Tenaya', + 'Kera', + 'Meah', + 'Mei', + 'Anoushka', + 'Annalyse', + 'Persia', + 'Sheccid', + 'Kyndra', + 'Susy', + 'Steffany', + 'Jennavecia', + 'Briannah', + 'Kynlie', + 'Alexxa', + 'Paizlee', + 'Jesika', + 'Kinzlee', + 'Ishani', + 'Freyja', + 'Julietta', + 'Raynette', + 'Nely', + 'Zayleigh', + 'Amberlynn', + 'Journei', + 'Eimy', + 'Delany', + 'Emarie', + 'Brilynn', + 'Audri', + 'Abilene', + 'Saoirse', + 'Naveah', + 'Ayelen', + 'Emeline', + 'Loryn', + 'Mykaela', + 'Skarlett', + 'Tionne', + 'Rashelle', + 'Jerline', + 'Ofilia', + 'Rufina', + 'Phillis', + 'Jenica', + 'Dineen', + 'Glory', + 'Camellia', + 'Alane', + 'Angelyna', + 'Amalie', + 'Kina', + 'Kateri', + 'Neyva', + 'Malisa', + 'Saida', + 'Jerika', + 'Bayli', + 'Crystale', + 'Silvana', + 'Inga', + 'Lyndi', + 'Leeanna', + 'Cheyanna', + 'Fayrene', + 'Torie', + 'Latashia', + 'Baleigh', + 'Fidencia', + 'Rori', + 'Lorianne', + 'Catrice', + 'Cherrelle', + 'Lashaunda', + 'Sammi', + 'Thomasena', + 'Roshanda', + 'Alazae', + 'Enza', + 'Mairead', + 'Pandora', + 'Kortni', + 'Timber', + 'Chasidy', + 'Danesha', + 'Camry', + 'Charlette', + 'Kaneshia', + 'Shadae', + 'Keturah', + 'Randye', + 'Kiyana', + 'Charlean', + 'Delana', + 'Tomasita', + 'Lilliam', + 'Bibi', + 'Marguita', + 'Maryalice', + 'Iraida', + 'Tyhessia', + 'Makeba', + 'Tanaya', + 'Keiara', + 'Madlyn', + 'Jelissa', + 'Shakayla', + 'Mickayla', + 'Aleisha', + 'Keyara', + 'Mekayla', + 'Mykala', + 'Riva', + 'Inaara', + 'Paulita', + 'Lashae', + 'Destynee', + 'Christianna', + 'Rise', + 'Larraine', + 'Luetta', + 'Merna', + 'Francena', + 'Diedre', + 'Georgiann', + 'Rubbie', + 'Denita', + 'Dyani', + 'Laticia', + 'Ludivina', + 'Suanne', + 'Hareem', + 'Nava', + 'Florie', + 'Sherly', + 'Vidhi', + 'Camie', + 'Sharell', + 'Chole', + 'Jolin', + 'Polina', + 'Brittiany', + 'Delicia', + 'Brystol', + 'Beaulah', + 'Leatha', + 'Jamilah', + 'Zona', + 'Elliette', + 'Joye', + 'Aashi', + 'Kerriann', + 'Xin', + 'Michaelene', + 'Senaida', + 'Emaan', + 'Nakayla', + 'Aine', + 'Jadalyn', + 'Maimouna', + 'Klaire', + 'Macee', + 'Shandi', + 'Heily', + 'Braylynn', + 'Aislynn', + 'Chevon', + 'Henretta', + 'Bellamy', + 'Icie', + 'Draya', + 'Darianna', + 'Zyana', + 'Zaelynn', + 'Story', + 'Kambrie', + 'Ranae', + 'Florencia', + 'Porfiria', + 'Elianny', + 'Karren', + 'Yachet', + 'Euna', + 'Naoma', + 'Stefania', + 'Liora', + 'Zlaty', + 'Margene', + 'Denna', + 'Isidra', + 'Faustina', + 'Bintou', + 'Arbutus', + 'Kelci', + 'Evelena', + 'Maudine', + 'Agapita', + 'Olyvia', + 'Loma', + 'Veola', + 'Mckinlee', + 'Lamya', + 'Nashali', + 'Baileigh', + 'Josselin', + 'Kaydance', + 'Paiton', + 'Myleigh', + 'Jazlyne', + 'Indya', + 'Siham', + 'Aryn', + 'Madalene', + 'Nefertiti', + 'Meridith', + 'Kamesha', + 'Peg', + 'Shelbey', + 'Pearlean', + 'Jamika', + 'Maryama', + 'Sabria', + 'Taniqua', + 'Maraya', + 'Joely', + 'Karys', + 'Charolette', + 'Orly', + 'Jennipher', + 'Kimbra', + 'Krislynn', + 'Kenlie', + 'Karrington', + 'Kambry', + 'Alasia', + 'Carletta', + 'Maija', + 'Nadirah', + 'Gladyce', + 'Shevy', + 'Jalessa', + 'Mushka', + 'Cyre', + 'Mabry', + 'Arihanna', + 'Brithany', + 'Ilianna', + 'Jozlynn', + 'Zandra', + 'Serinity', + 'Passion', + 'Lacresha', + 'Jeraldine', + 'Henriette', + 'Elenore', + 'Nastassia', + 'Ruchel', + 'Amal', + 'Madina', + 'Rosaline', + 'Liyana', + 'Pasqualina', + 'Keyra', + 'Kaycie', + 'Lyanna', + 'Naina', + 'Gennesis', + 'Aarushi', + 'Lariah', + 'Jakiya', + 'Kareena', + 'Rhiana', + 'Emilly', + 'Yeimi', + 'Matsuko', + 'Makhia', + 'Alin', + 'Addisen', + 'Lanae', + 'Oceana', + 'Laquanda', + 'Coralie', + 'Arina', + 'Harini', + 'Emy', + 'Emmarose', + 'Ellyana', + 'Eila', + 'Havana', + 'Dagny', + 'Leylah', + 'Shawanna', + 'Aleenah', + 'Adalia', + 'Aaliya', + 'Zyanya', + 'Felisa', + 'Tameca', + 'Sama', + 'Ripley', + 'Nayomi', + 'Quanesha', + 'Shequita', + 'Shanik', + 'Savina', + 'Nalah', + 'Magaby', + 'Cattaleya', + 'Calla', + 'Lillia', + 'Kaida', + 'Izabell', + 'Francia', + 'Caylin', + 'Bianey', + 'Hanah', + 'Julienne', + 'Viva', + 'Xochil', + 'Staphany', + 'Rayanne', + 'Marialuisa', + 'Devina', + 'Sabryna', + 'Estefanie', + 'Dinora', + 'Clarisse', + 'Josephina', + 'Milca', + 'Anjolie', + 'Akayla', + 'Malea', + 'Mea', + 'Meghana', + 'Briceida', + 'Betsaida', + 'Roselin', + 'Anuhea', + 'Megha', + 'Azusena', + 'Nandini', + 'Prisilla', + 'Shelsy', + 'Olene', + 'Kaneisha', + 'Onalee', + 'Jadore', + 'Monteen', + 'Trudie', + 'Leisha', + 'Drucilla', + 'Tamiyah', + 'Ashante', + 'Daysha', + 'Caliyah', + 'Sabella', + 'Emoni', + 'Jakyla', + 'Reginae', + 'Anyah', + 'Kierstyn', + 'Sharleen', + 'Doretta', + 'Harlene', + 'Gerrie', + 'Zofia', + 'Albertine', + 'Bronwyn', + 'Terresa', + 'Delta', + 'Anijah', + 'Mathilde', + 'Cindie', + 'Dalene', + 'Cyndee', + 'Eulah', + 'Ayako', + 'Beverlee', + 'Nicholle', + 'Kaitlan', + 'Yeraldin', + 'Tawney', + 'Tawnee', + 'Britteny', + 'Alishia', + 'Shireen', + 'Byanca', + 'Rebekka', + 'Annel', + 'Krizia', + 'Kerstin', + 'Shera', + 'Uyen', + 'Ligia', + 'Dallana', + 'Itsel', + 'Karine', + 'Sharmaine', + 'Noely', + 'Marrisa', + 'Karah', + 'Rayann', + 'Oksana', + 'Stephannie', + 'Brynne', + 'Alixandra', + 'Dyana', + 'Emilce', + 'Delmy', + 'Jamee', + 'Caitlan', + 'Marily', + 'Kiani', + 'Jennafer', + 'Nissa', + 'Jenell', + 'Jennette', + 'Marquitta', + 'Chimene', + 'Justyna', + 'Jenette', + 'Cassy', + 'Temika', + 'Katrice', + 'Brandis', + 'Consuela', + 'Chavon', + 'Angella', + 'Shantrell', + 'Christiane', + 'Shenna', + 'Donia', + 'Angelise', + 'Janyah', + 'Damiyah', + 'Luzmaria', + 'Meghna', + 'Natally', + 'Nerissa', + 'Kaori', + 'Laya', + 'Analyssa', + 'Teya', + 'Alizon', + 'Jasline', + 'Lavette', + 'Emmi', + 'Kamisha', + 'Taleah', + 'Shenita', + 'Kaytlynn', + 'Azariyah', + 'Dominica', + 'Malvina', + 'Skyy', + 'Shondra', + 'Lorina', + 'Donielle', + 'Kaisley', + 'Katalyna', + 'Jesslynn', + 'Yasmina', + 'Glada', + 'Maliha', + 'Irina', + 'Hiba', + 'Trinette', + 'Oona', + 'Aleeza', + 'Arisha', + 'Janean', + 'Cristie', + 'Syd', + 'Lavona', + 'Kennia', + 'Kyanna', + 'Lovenia', + 'Julieanne', + 'Launa', + 'Taunya', + 'Tytianna', + 'Becca', + 'Deonna', + 'Jihan', + 'Jomaira', + 'Shantay', + 'Talitha', + 'Shyra', + 'Alverna', + 'Chere', + 'Kamela', + 'Phaedra', + 'Stacee', + 'Gretta', + 'Kathyrn', + 'Shalee', + 'Beautiful', + 'Lissett', + 'Georgann', + 'Corrin', + 'Chelsa', + 'Cera', + 'Layna', + 'Lizanne', + 'Mariellen', + 'Lashandra', + 'Sophya', + 'Shruti', + 'Janea', + 'Rheta', + 'Jezebel', + 'Alizee', + 'Delaila', + 'Dayani', + 'Arieanna', + 'Amarah', + 'Janyia', + 'Makalah', + 'Dorie', + 'Tynisha', + 'Tran', + 'Prisma', + 'Shirin', + 'Tonette', + 'Suzi', + 'Alajah', + 'Lurline', + 'Adelia', + 'Tani', + 'Cassey', + 'Maha', + 'Cheyann', + 'Keyona', + 'Yezenia', + 'Vaness', + 'Stephine', + 'Cyndie', + 'Jaylanie', + 'Jeannemarie', + 'Mammie', + 'Sherice', + 'Delynn', + 'Aoife', + 'Kadiatou', + 'Sherese', + 'Trenyce', + 'Anaiz', + 'Anaiza', + 'Dajanae', + 'Lisaann', + 'Keiko', + 'Martiza', + 'Elysa', + 'Petrina', + 'Dierdre', + 'Davida', + 'Falyn', + 'Briona', + 'Maryjean', + 'Lanisha', + 'Marlenne', + 'Nawal', + 'Ethelene', + 'Alya', + 'Ariannah', + 'Jacinta', + 'Alaia', + 'Sindee', + 'Jalaya', + 'Mellanie', + 'Lasya', + 'Kyrah', + 'Mirabella', + 'Renay', + 'Seren', + 'Hiliana', + 'Kinzie', + 'Isra', + 'Hanan', + 'Kaleia', + 'Melynda', + 'Marine', + 'Twanna', + 'Lekisha', + 'Jamecia', + 'Penney', + 'Tiwanna', + 'Rylea', + 'Shekinah', + 'Mckenzi', + 'Abigael', + 'Patrizia', + 'Jamillah', + 'Caris', + 'Karmyn', + 'Kyli', + 'Princessa', + 'Sakinah', + 'Deserae', + 'Patrina', + 'Carmelina', + 'Mayela', + 'Sherise', + 'Ilda', + 'Florentina', + 'Nelwyn', + 'Jennine', + 'Aleeya', + 'Kynsley', + 'Arlett', + 'Tarra', + 'Lakyn', + 'Tyeisha', + 'Temima', + 'Mallori', + 'Ingeborg', + 'Elizaveta', + 'Jentry', + 'Kymber', + 'Maddisyn', + 'Allana', + 'Anistyn', + 'Emberlynn', + 'Faithlynn', + 'Arianah', + 'Tionna', + 'Lenda', + 'Laveta', + 'Alayla', + 'Aisling', + 'Miryam', + 'Marena', + 'Aneta', + 'Yzabella', + 'Mihika', + 'Raine', + 'Samiah', + 'Raveena', + 'Elfrieda', + 'Niccole', + 'Tatanisha', + 'Medha', + 'Katharina', + 'Jazmen', + 'Cally', + 'Louanne', + 'Caress', + 'Naylea', + 'Avarie', + 'Madelynne', + 'Dayla', + 'Shanterria', + 'Tesha', + 'Thanya', + 'Jalia', + 'Josalyn', + 'Ailey', + 'Brooklynne', + 'Dodie', + 'Champagne', + 'Taneka', + 'Tenesha', + 'Tinisha', + 'Deeanna', + 'Shelvia', + 'Chenoa', + 'Darcel', + 'Kailea', + 'Jatziry', + 'Merryl', + 'Sharlyn', + 'Harolyn', + 'Rilla', + 'Ayisha', + 'Jacklynn', + 'Chloee', + 'Makynzie', + 'Leyah', + 'Aalyiah', + 'Tynlee', + 'Statia', + 'Tyronda', + 'Tsuyako', + 'Casimira', + 'Kehaulani', + 'Ragan', + 'Lorissa', + 'Abelina', + 'Cuca', + 'Sachi', + 'Evany', + 'Elektra', + 'Sianni', + 'Raychel', + 'Natassia', + 'Vermell', + 'Sharifa', + 'Everley', + 'Ivanka', + 'Arisbeth', + 'Aleyza', + 'Bay', + 'Deedra', + 'Zarina', + 'Regena', + 'Kitana', + 'Latoshia', + 'Virgia', + 'Aili', + 'Breslyn', + 'Ishika', + 'Jhoana', + 'Dorrace', + 'Chanice', + 'Sheniqua', + 'Tashana', + 'Joetta', + 'Sanya', + 'Altamese', + 'Pari', + 'Niah', + 'Ysabelle', + 'Lisseth', + 'Parisa', + 'Aislin', + 'Leiah', + 'Atziri', + 'Anvita', + 'Jaydah', + 'Gabby', + 'Ashia', + 'Dymond', + 'Marah', + 'Uniqua', + 'Blimie', + 'Anny', + 'Dalinda', + 'Wauneta', + 'Gionna', + 'Rabia', + 'Jayanna', + 'Anica', + 'Maybell', + 'Kathern', + 'Amrita', + 'Mayerli', + 'Irais', + 'Kemberly', + 'Vena', + 'Kamri', + 'Destine', + 'Adreanna', + 'Seleste', + 'Claretha', + 'Brynnlee', + 'Anquette', + 'Komal', + 'Lysette', + 'Michayla', + 'Zamya', + 'Sierrah', + 'Felica', + 'Otelia', + 'Rihana', + 'Doloris', + 'Alanie', + 'Angelly', + 'Kassandr', + 'Rosemari', + 'Shaday', + 'Annemari', + 'Marlana', + 'Clorinda', + 'Oneida', + 'Shaunta', + 'Alexcia', + 'Takesha', + 'Amiracle', + 'Sharion', + 'Joline', + 'Jaziyah', + 'Teal', + 'Sueann', + 'Sora', + 'Kamiah', + 'Caressa', + 'Eleana', + 'Bernetha', + 'Alexyss', + 'Sharda', + 'Aishwarya', + 'Suhaill', + 'Radhika', + 'Wonda', + 'Renda', + 'Janny', + 'Ardelle', + 'Malory', + 'Jossie', + 'Anaid', + 'Mitsuye', + 'Shizuye', + 'Fariha', + 'Aiesha', + 'Nitya', + 'Nadiya', + 'Katerin', + 'Bruna', + 'Varsha', + 'Yaretsi', + 'Xitlalli', + 'Leshia', + 'Eda', + 'Sheronda', + 'Malikah', + 'Tayah', + 'Briann', + 'Tasnim', + 'Jayonna', + 'Kenedy', + 'Anarosa', + 'Zaya', + 'Kerline', + 'Brinda', + 'Amna', + 'Desarae', + 'Sarrah', + 'Silva', + 'Steffani', + 'Almarosa', + 'Alyshia', + 'Ariell', + 'Breeanne', + 'Alyxandra', + 'Juliane', + 'Jesseca', + 'Janisha', + 'Donisha', + 'Darnisha', + 'Jakeria', + 'Kirsty', + 'Markeisha', + 'Breena', + 'Selin', + 'Nikisha', + 'Adreana', + 'Elois', + 'Arrianna', + 'Melenie', + 'Rayanna', + 'Kaelee', + 'Shakyra', + 'Clotee', + 'Jakeline', + 'Kalysta', + 'Cesia', + 'Ankita', + 'Cristela', + 'Shunta', + 'Mozella', + 'Chrissie', + 'Adora', + 'Ashanty', + 'Ashna', + 'Lehua', + 'Nohealani', + 'Shruthi', + 'Metzli', + 'Jakelin', + 'Jisel', + 'Mikenna', + 'Miroslava', + 'Mansi', + 'Daphney', + 'Amisha', + 'Adara', + 'Alexzandria', + 'Alliah', + 'Yuriana', + 'Nanea', + 'Kahealani', + 'Ritika', + 'Arica', + 'Amayrani', + 'Kealani', + 'Dorina', + 'Lucienne', + 'Estrellita', + 'Kimberlin', + 'Lai', + 'Yovanna', + 'Rebekkah', + 'Azra', + 'Nada', + 'Gabryella', + 'Avigayil', + 'Binta', + 'Devoiry', + 'Raeanna', + 'Arlena', + 'Briauna', + 'Itati', + 'Grabiela', + 'Noella', + 'Teaghan', + 'Tzippy', + 'Faiza', + 'Zaara', + 'Tehilla', + 'Miki', + 'Sendy', + 'Kassondra', + 'Katherina', + 'Lissete', + 'Livier', + 'Lauran', + 'Dandrea', + 'Chelse', + 'Lizmarie', + 'Sunday', + 'Haidee', + 'Carrissa', + 'Nicholette', + 'Katey', + 'Katheryne', + 'Katty', + 'Kimia', + 'Leeanne', + 'Lizmary', + 'Jani', + 'Emmanuella', + 'Jahniya', + 'Talar', + 'Sintia', + 'Narda', + 'Chriselda', + 'Candance', + 'Delorise', + 'Daysy', + 'Lusine', + 'Raeanne', + 'Cherylann', + 'Ayat', + 'Halima', + 'Zissel', + 'Courtni', + 'Adahli', + 'Der', + 'Emree', + 'Brynlie', + 'Cherlyn', + 'Bostyn', + 'Francie', + 'Oaklie', + 'Shakeerah', + 'Hertha', + 'Haneefah', + 'Taheerah', + 'Nikkia', + 'Sheryll', + 'Donnabelle', + 'Teddi', + 'Jodee', + 'Tammera', + 'Janylah', + 'Laquesha', + 'Penina', + 'Gracee', + 'Thomasine', + 'Janyce', + 'Randie', + 'Mela', + 'Alka', + 'Cordia', + 'Shaquetta', + 'Mi', + 'Jaquetta', + 'Yoshiye', + 'Haruye', + 'Yoneko', + 'Fumi', + 'Wava', + 'Congetta', + 'Denee', + 'Kandyce', + 'Soraida', + 'Triana', + 'Kenedi', + 'Abena', + 'Talisha', + 'Rochell', + 'Sharisse', + 'Tijuana', + 'Amiee', + 'Nyesha', + 'Towana', + 'Lore', + 'Melodye', + 'Hayli', + 'Joyelle', + 'Shareen', + 'Amarilis', + 'Takiyah', + 'Takiya', + 'Keysha', + 'Feige', + 'Diahann', + 'Kloie', + 'Laynee', + 'Mariely', + 'Rainey', + 'Alizabeth', + 'Alyssandra', + 'Cambry', + 'Jadelynn', + 'Marylynn', + 'Keoka', + 'Jamaica', + 'Lus', + 'Shonta', + 'Kameelah', + 'Danell', + 'Evamarie', + 'Francoise', + 'Beata', + 'Caylie', + 'Elexa', + 'Joscelin', + 'Hessie', + 'Alazay', + 'Robena', + 'Texie', + 'Clarine', + 'Makennah', + 'Arletha', + 'Willette', + 'Amee', + 'Jetaun', + 'Anyia', + 'Aryssa', + 'Bonni', + 'Graciella', + 'Haileigh', + 'Sharae', + 'Shanea', + 'Ieisha', + 'Porche', + 'Teanna', + 'Ashanta', + 'Taiya', + 'Nicolett', + 'Naisha', + 'Sharice', + 'Madelein', + 'Kimberle', + 'Monifah', + 'Cameo', + 'Evelynne', + 'Edlyn', + 'Porcha', + 'Maricel', + 'Waleska', + 'Shakeena', + 'Shavone', + 'Ashlynne', + 'Yahira', + 'Shamecca', + 'Yashira', + 'Sherell', + 'Fiorela', + 'Nansi', + 'Shawntae', + 'Poonam', + 'Shala', + 'Kellyn', + 'Jazzmyn', + 'Asya', + 'Shatoya', + 'Yury', + 'Weronika', + 'Dawnette', + 'Lorita', + 'Michaelle', + 'Tomi', + 'Abbi', + 'Maudry', + 'Jaylinn', + 'Kynzie', + 'Lynnlee', + 'Madisson', + 'Denese', + 'Devona', + 'Sharika', + 'Sharilyn', + 'Zayna', + 'Janalee', + 'Sherril', + 'Timika', + 'Lynelle', + 'Rolayne', + 'Lubertha', + 'Jariah', + 'Kamala', + 'Taffy', + 'Marquetta', + 'Honora', + 'Frederica', + 'Monalisa', + 'Rashonda', + 'Francene', + 'Diedra', + 'Ceara', + 'Marylouise', + 'Kenesha', + 'Aisley', + 'Donnalee', + 'Genisis', + 'Debroah', + 'Helayne', + 'Raelee', + 'Maryrose', + 'Yalonda', + 'Chyla', + 'Edelmira', + 'Roselle', + 'Alyssah', + 'Brenley', + 'Gaynelle', + 'Shelvie', + 'Mackayla', + 'Linley', + 'Allizon', + 'Alonna', + 'Kendalyn', + 'Jozlyn', + 'Gwenn', + 'Jina', + 'Zariya', + 'Rosabella', + 'Emrie', + 'Tamu', + 'Senta', + 'Myia', + 'Emberlyn', + 'Emorie', + 'Arantxa', + 'Richele', + 'Christianne', + 'Lashan', + 'Koren', + 'Buffie', + 'Ronnette', + 'Marna', + 'Tuesday', + 'Helga', + 'Emilyn', + 'Cailee', + 'Shaquilla', + 'Dyamond', + 'Gerda', + 'Mckynzie', + 'Khloie', + 'Kendyll', + 'Maryfrances', + 'Khadejah', + 'Annalie', + 'Adaya', + 'Akia', + 'Markia', + 'Iyla', + 'Kaely', + 'Rafaella', + 'Tali', + 'Sukhmani', + 'Mili', + 'Kaylanie', + 'Maribelle', + 'Zharia', + 'Georgeanne', + 'Shamekia', + 'Siyona', + 'Layah', + 'Maylani', + 'Elianah', + 'Ellena', + 'Elyanna', + 'Yanilen', + 'Jashanti', + 'Lakita', + 'Juanell', + 'Caley', + 'Annella', + 'Vinita', + 'Zakiyah', + 'Sherian', + 'Palmira', + 'Delpha', + 'Creola', + 'Veta', + 'Sheneka', + 'Ameria', + 'Keonna', + 'Nathali', + 'Vaishnavi', + 'Zurisadai', + 'Mily', + 'Aalyah', + 'Hasini', + 'Irelynn', + 'Taneshia', + 'Lashanti', + 'Shatavia', + 'Shantoria', + 'Avelina', + 'Vanya', + 'Erline', + 'Surina', + 'Maribella', + 'Julieana', + 'Jazel', + 'Kalissa', + 'Marlis', + 'Hadasa', + 'Iveth', + 'Miliani', + 'Leiana', + 'Devynn', + 'Ahtziry', + 'Shilah', + 'Sicily', + 'Ashari', + 'Yarenis', + 'Tamiah', + 'Annis', + 'Azzie', + 'Sedalia', + 'Maebell', + 'Empress', + 'Fairy', + 'Najma', + 'Loreta', + 'Suhayla', + 'Sundus', + 'Vayda', + 'Doshia', + 'Ahlam', + 'Lashondra', + 'Ryanna', + 'Lala', + 'Merline', + 'Severa', + 'Kymora', + 'Fae', + 'Jameka', + 'Othella', + 'Wyoma', + 'Ailee', + 'Aishani', + 'Fransisca', + 'Noma', + 'Meztli', + 'Miliana', + 'Navaeh', + 'Swara', + 'Malillany', + 'Jaina', + 'Dia', + 'Ivyanna', + 'Jamira', + 'Jazaria', + 'Oletha', + 'Julieth', + 'Avia', + 'Elizebeth', + 'Yareni', + 'Korra', + 'Miraya', + 'Bernetta', + 'Helyn', + 'Suhaylah', + 'Laina', + 'Lassie', + 'Anyae', + 'Maleena', + 'Nirvana', + 'Danely', + 'Keilana', + 'Hildur', + 'Mariaclara', + 'Toshie', + 'Maniyah', + 'Hanako', + 'Asako', + 'Hiroko', + 'Hisae', + 'Suraya', + 'Kaileen', + 'Pearla', + 'Layal', + 'Batoul', + 'Johannah', + 'Gizel', + 'Venecia', + 'Yanelly', + 'Atianna', + 'Apple', + 'Arizbeth', + 'Sriya', + 'Natania', + 'Mayline', + 'Emmagrace', + 'Meriam', + 'Laree', + 'Tempie', + 'Sedonia', + 'Evalee', + 'Laquana', + 'Sheli', + 'Liesl', + 'Hazeline', + 'Blanchie', + 'Samyra', + 'Keelie', + 'Krislyn', + 'Yanelis', + 'Addysen', + 'Inis', + 'Tammra', + 'Johnette', + 'Amery', + 'Alayza', + 'Alaiyah', + 'Abree', + 'Amri', + 'Anapaula', + 'Jacelynn', + 'Kenzleigh', + 'Kenzlee', + 'Jaelah', + 'Brenlee', + 'Avalee', + 'Paizley', + 'Columbia', + 'Benedetta', + 'Daeja', + 'Myeshia', + 'Jeanene', + 'Terina', + 'Ethyl', + 'Oliwia', + 'Taniah', + 'Yaiza', + 'Eveline', + 'Monnie', + 'Margherita', + 'Jayana', + 'Macil', + 'Leontine', + 'Catera', + 'Wynelle', + 'Eldana', + 'Sallyann', + 'Yolande', + 'Marybelle', + 'Leanore', + 'Clothilde', + 'Tonita', + 'Kimaya', + 'Sumayah', + 'Latrenda', + 'Kelleen', + 'Deatrice', + 'Madelon', + 'Phyliss', + 'Argelia', + 'Mellie', + 'Emmah', + 'Jorley', + 'Muna', + 'Daphine', + 'Darina', + 'Bliss', + 'Karyl', + 'Taelynn', + 'Blenda', + 'Tonika', + 'Jerrilyn', + 'Sahra', + 'Keilyn', + 'Pearlene', + 'Arrie', + 'Ellene', + 'Fredericka', + 'Ladawn', + 'Maudell', + 'Rahma', + 'Jaylie', + 'Jaidah', + 'Vernetta', + 'Aleya', + 'Aubreigh', + 'Alaysha', + 'Adena', + 'Jacara', + 'Elfriede', + 'Maysel', + 'Munira', + 'Mumtaz', + 'Dorathy', + 'Chanin', + 'Ronette', + 'Maymie', + 'Providencia', + 'Mirta', + 'Loida', + 'Blakelyn', + 'Bentleigh', + 'Alliana', + 'Aleen', + 'Daliyah', + 'Jodene', + 'Johanne', + 'Timeka', + 'Ilhan', + 'Aloma', + 'Maris', + 'Arlyne', + 'Jene', + 'Hazelene', + 'Shakela', + 'Maida', + 'Maycie', + 'Makynlee', + 'Kawanda', + 'Consuella', + 'Sephora', + 'Andrianna', + 'Joshlyn', + 'Hollyn', + 'Kyliee', + 'Adaly', + 'Dailyn', + 'Averee', + 'Berklee', + 'Marly', + 'Gianella', + 'Ekaterina', + 'Colene', + 'Dayonna', + 'Shareka', + 'Roshni', + 'Latifa', + 'Merilyn', + 'Vernelle', + 'Marlyce', + 'Sabrena', + 'Jeneen', + 'Genie', + 'Lawanna', + 'Tashara', + 'Kayzlee', + 'Skylie', + 'Iyonna', + 'Honesti', + 'Cherylene', + 'Tahira', + 'Chizuko', + 'Aneesah', + 'Helmi', + 'Katrena', + 'Shyanna', + 'Zeola', + 'Lempi', + 'Arliss', + 'Madgie', + 'Verlie', + 'Ardys', + 'Twanda', + 'Kareemah', + 'Chardae', + 'Arlinda', + 'Darlena', + 'Karee', + 'Lorry', + 'Rolande', + 'Marlane', + 'Lelah', + 'Zahria', + 'Michalene', + 'Nayelis', + 'Abbigale', + 'Lorretta', + 'Sheril', + 'Priscille', + 'Cleda', + 'Kerrigan', + 'Wanita', + 'Ambria', + 'Wanetta', + 'Ebone', + 'Georgianne', + 'Karleen', + 'Laural', + 'Jonette', + 'Sharie', + 'Francina', + 'Yarelis', + 'Tempestt', + 'Kamie', + 'Julene', + 'Londa', + 'Haniya', + 'Kristeen', + 'Classie', + 'Nakiyah', + 'Valinda', + 'Kamree', + 'Micheline', + 'Mckaylee', + 'Prescilla', + 'Shaylynn', + 'Donelda', + 'Fayetta', + 'Terrye', + 'Dorthey', + 'Azilee', + 'Juanda', + 'Eustolia', + 'Nakeisha', + 'Hira', + 'Tarrah', + 'Jamyra', + 'Azaleah', + 'Aveline', + 'Chanae', + 'Andreana', + 'Banesa', + 'Berenis', + 'Brittini', + 'Orianna', + 'Reet', + 'Rayah', + 'Sofi', + 'Japji', + 'Kensie', + 'Roshonda', + 'Agripina', + 'Blasa', + 'Anevay', + 'Akari', + 'Krissi', + 'Maily', + 'Kitzia', + 'Keilly', + 'Raveen', + 'Kaiah', + 'Juliett', + 'Jocelynne', + 'Eowyn', + 'Calie', + 'Ebonee', + 'Chelcie', + 'Kayci', + 'Lauralee', + 'Trenity', + 'Deborrah', + 'Imagene', + 'Akasha', + 'Analaura', + 'Liani', + 'Lizania', + 'Lucina', + 'Melaine', + 'Sanah', + 'Stepanie', + 'Zabrina', + 'Janaye', + 'Jelena', + 'Kaylina', + 'Diavian', + 'Tasnia', + 'Nusrat', + 'Ashleymarie', + 'Maheen', + 'Ndeye', + 'Yumi', + 'Vittoria', + 'Amyra', + 'Yakelin', + 'Yudith', + 'Yumalay', + 'Juliza', + 'Daila', + 'Daenerys', + 'Calissa', + 'Tahirah', + 'Laquasia', + 'Jenay', + 'Crystina', + 'Eleonore', + 'Inessa', + 'Irine', + 'Vennie', + 'Oda', + 'Laurine', + 'Lavera', + 'Saraya', + 'Kerin', + 'Itzia', + 'Jennessa', + 'Katerine', + 'Rosselyn', + 'Leidy', + 'Adamariz', + 'Adylene', + 'Aylen', + 'Aniela', + 'Aleesha', + 'Alyssamarie', + 'Ainara', + 'Emalie', + 'Darlin', + 'Inna', + 'Emmely', + 'Eriana', + 'Esbeidy', + 'Chenelle', + 'Janise', + 'Sherrell', + 'Basilia', + 'Malayna', + 'Hilinai', + 'Mardell', + 'Romi', + 'Rosena', + 'Violett', + 'Zaylah', + 'Taia', + 'Anisah', + 'Esli', + 'Cleopatra', + 'Carisma', + 'Dezaray', + 'Swayze', + 'Raeven', + 'Neiva', + 'Myeisha', + 'Shelsea', + 'Yissel', + 'Velinda', + 'Josseline', + 'Denasia', + 'Digna', + 'Keiana', + 'Clytee', + 'Vernette', + 'Cheyene', + 'Roshunda', + 'Telisha', + 'Nilah', + 'Ayda', + 'Zykia', + 'Isabellamarie', + 'Melanee', + 'Laylanie', + 'Ajah', + 'Guiliana', + 'Oliva', + 'Mikela', + 'Mirabelle', + 'Nabiha', + 'Jasmina', + 'Hendy', + 'Ita', + 'Elif', + 'Reola', + 'Jamyah', + 'Tempest', + 'Arletta', + 'Keaira', + 'Ibeth', + 'Jerolyn', + 'Nelta', + 'Alishba', + 'Crisol', + 'Sabreena', + 'Silver', + 'Toba', + 'Yunuen', + 'Rishika', + 'Naomie', + 'Brittanya', + 'Annasophia', + 'Ayumi', + 'Jayleene', + 'Emmily', + 'Lyssa', + 'Natoya', + 'Vallerie', + 'Andee', + 'Annastasia', + 'Mazzy', + 'Zinnia', + 'Sheran', + 'Sumaiya', + 'Tasneem', + 'Aniylah', + 'Dua', + 'Tausha', + 'Jabria', + 'Lanora', + 'Janeli', + 'Mileydi', + 'Mikaella', + 'Ryah', + 'Rolonda', + 'Ajanae', + 'Ianna', + 'Xaria', + 'Winni', + 'Marializ', + 'Aidel', + 'Jonae', + 'Sanam', + 'Mao', + 'Tesia', + 'Yanina', + 'Brieana', + 'Genova', + 'Lashanae', + 'Anneke', + 'Siarra', + 'Sharhonda', + 'Zeldy', + 'Saron', + 'Johnisha', + 'Katelynne', + 'Janneth', + 'Corayma', + 'Helvi', + 'Asucena', + 'Lachelle', + 'Solmayra', + 'Tavia', + 'Marlina', + 'Rachal', + 'Sunni', + 'Nycole', + 'Aliannah', + 'Nafisa', + 'Simi', + 'Suki', + 'Jadalynn', + 'Kezia', + 'Athziri', + 'Huda', + 'Evy', + 'Jailah', + 'Jaselle', + 'Jaslyne', + 'Dalyla', + 'Emeraude', + 'Mahika', + 'Yoanna', + 'Fraida', + 'Tannia', + 'Selenne', + 'Analiz', + 'Angelene', + 'Anacristina', + 'Kylea', + 'Naydelyn', + 'Lecia', + 'Gitel', + 'Shareese', + 'Cassady', + 'Diem', + 'Perlita', + 'Monigue', + 'Marisha', + 'Emillee', + 'Kareli', + 'Shandreka', + 'Kerrin', + 'Tram', + 'Nohelani', + 'Monic', + 'Brandice', + 'Johnetta', + 'Evangelia', + 'Shakina', + 'Shunda', + 'Robbi', + 'Ariatna', + 'Shantae', + 'Sorangel', + 'Valene', + 'Aletta', + 'Libbie', + 'Marifer', + 'Deitra', + 'Despina', + 'Hayle', + 'Kassidi', + 'Dayrin', + 'Anjelina', + 'Gimena', + 'Llesenia', + 'Rainbow', + 'Muskaan', + 'Judit', + 'Kyley', + 'Tanna', + 'Luci', + 'Altagracia', + 'Kilee', + 'Kamry', + 'Kalyssa', + 'Jadeyn', + 'Virgen', + 'Damita', + 'Leinaala', + 'Illeana', + 'Nneka', + 'Onika', + 'Aralyn', + 'Mahalia', + 'Marelyn', + 'Jalene', + 'Bobbiejo', + 'Apollonia', + 'Anjuli', + 'Ricarda', + 'Fusako', + 'Michie', + 'Janira', + 'Citlalic', + 'Jannelle', + 'Tiffini', + 'Elisia', + 'Racine', + 'Marybel', + 'Xitlally', + 'Tynesha', + 'Sharay', + 'Shamara', + 'Aleene', + 'Rayssa', + 'Carlyn', + 'Falisha', + 'Lasandra', + 'Trinh', + 'Seema', + 'Tonianne', + 'Destani', + 'Nairobi', + 'Tomica', + 'Raena', + 'Ivania', + 'Odaliz', + 'Lilybeth', + 'Sheyenne', + 'Tereza', + 'Yuka', + 'Baleria', + 'Ayiana', + 'Floree', + 'Jhoanna', + 'Shakila', + 'Meleah', + 'Monserath', + 'Lelani', + 'Conception', + 'Zowie', + 'Teah', + 'Takayla', + 'Teaira', + 'Karyssa', + 'Delina', + 'Kamaile', + 'Rut', + 'Reanne', + 'Zamantha', + 'Ellyse', + 'Jisela', + 'Latonja', + 'Eiko', + 'Aylene', + 'Atziry', + 'Avila', + 'Andreya', + 'Delyla', + 'Aashna', + 'Dacia', + 'Shavonda', + 'Desirey', + 'Matea', + 'Makailah', + 'Henessy', + 'Naliyah', + 'Charlise', + 'Keirsten', + 'Ressie', + 'Halia', + 'Gweneth', + 'Manda', + 'Lilinoe', + 'Mariselda', + 'Tajuana', + 'Mahima', + 'Noeli', + 'Yanelli', + 'Sole', + 'Saloni', + 'Annistyn', + 'Marcille', + 'Thresa', + 'Cerenity', + 'Samnatha', + 'Alexah', + 'Analie', + 'Aryah', + 'Jazline', + 'Evony', + 'Erandy', + 'Jezelle', + 'Kamara', + 'Emelina', + 'Kadance', + 'Masae', + 'Davonna', + 'Shamaya', + 'Shalynn', + 'Rima', + 'Toria', + 'Zamira', + 'Cerina', + 'Fujiko', + 'Armine', + 'Morganne', + 'Gicela', + 'Desree', + 'Khaila', + 'Nikayla', + 'Kennedie', + 'Marylu', + 'Ilyssa', + 'Jatziri', + 'Shianna', + 'Dharma', + 'Resa', + 'Abra', + 'Neely', + 'Imo', + 'Betzabeth', + 'Briceyda', + 'Karenna', + 'Jakhia', + 'Ramiyah', + 'Khaliyah', + 'Tocarra', + 'Milee', + 'Athina', + 'Maleigha', + 'Shalyn', + 'Syliva', + 'Roseline', + 'Claira', + 'Jisselle', + 'Kiely', + 'Marisabel', + 'Maryanna', + 'Melena', + 'Mylene', + 'Mariangela', + 'Mailey', + 'Sonora', + 'Siana', + 'Shreeya', + 'Sevana', + 'Samhita', + 'Jackelyne', + 'Kyrstin', + 'Anslie', + 'Samella', + 'Jewelia', + 'Sammye', + 'Ayline', + 'Navneet', + 'Charlesetta', + 'Raye', + 'Yulonda', + 'Esmerelda', + 'Gianina', + 'Danessa', + 'Calia', + 'Everlena', + 'Sadaf', + 'Analucia', + 'Meriah', + 'Gwendalyn', + 'Disha', + 'Katana', + 'Kalaya', + 'Kaeley', + 'Tyonna', + 'Rozella', + 'Marjean', + 'Conchita', + 'Kylynn', + 'Aasiyah', + 'Maelynn', + 'Kahla', + 'Prachi', + 'Tajanae', + 'Megumi', + 'Micheala', + 'Yanitza', + 'Geselle', + 'Reather', + 'Annalicia', + 'Bonna', + 'Lilliann', + 'Callia', + 'Brigit', + 'Quintina', + 'Fujie', + 'Jolanda', + 'Nanami', + 'Yosselin', + 'Jakelyn', + 'Kadeja', + 'Eveny', + 'Emaly', + 'Ciena', + 'Julliana', + 'Jareli', + 'Jaretzi', + 'Kailin', + 'Kimiye', + 'Ammie', + 'Kiona', + 'Sumayyah', + 'Terre', + 'Laryssa', + 'Marleni', + 'Kamira', + 'Yulanda', + 'Jonda', + 'Lania', + 'Pippa', + 'Jazariah', + 'Takeya', + 'Shatima', + 'Ysenia', + 'Mikki', + 'Necole', + 'Etha', + 'Williemae', + 'Margurite', + 'Leonarda', + 'Inocencia', + 'Dominika', + 'Laisa', + 'Haylea', + 'Annamay', + 'Azia', + 'Mckynlee', + 'Maddilyn', + 'Scotlyn', + 'Lillith', + 'Mertie', + 'Kynzee', + 'Joshlynn', + 'Maelee', + 'Daleiza', + 'Xyla', + 'Royalty', + 'Railynn', + 'Patrycja', + 'Dotty', + 'Leda', + 'Toshiba', + 'Nelma', + 'Yeni', + 'Ottilie', + 'Lyna', + 'Leslieann', + 'Onita', + 'Darcey', + 'Marya', + 'Africa', + 'Seferina', + 'Theola', + 'Ysidra', + 'Zita', + 'Cing', + 'Zailynn', + 'Jennilee', + 'Sharmon', + 'Tyechia', + 'Irmgard', + 'Shameika', + 'Jemima', + 'Jazzelle', + 'Adlee', + 'Aliyanna', + 'Acelyn', + 'Catalaya', + 'Brileigh', + 'Braylie', + 'Angelin', + 'Arianni', + 'Ariani', + 'Kennya', + 'Maelyn', + 'Lillee', + 'Maripaz', + 'Laikyn', + 'Kenslee', + 'Ileane', + 'Puja', + 'Oanh', + 'Jakara', + 'Shawntay', + 'Cendy', + 'Erianna', + 'Chloie', + 'Birtie', + 'Korin', + 'Jannett', + 'Shawntel', + 'Markisha', + 'Nastassja', + 'Shalene', + 'Alexya', + 'Cloie', + 'Exa', + 'Jentri', + 'Modena', + 'Veronique', + 'Daina', + 'Mechele', + 'Lakesia', + 'Kawanna', + 'Clotilde', + 'Diamonique', + 'Teyana', + 'Rheagan', + 'Shanece', + 'Yanique', + 'Taysha', + 'Ulyssa', + 'Jadzia', + 'Kadija', + 'Towanna', + 'Lurlene', + 'Sharri', + 'Rosenda', + 'Daphna', + 'Hermina', + 'Shaquanda', + 'Saachi', + 'Sena', + 'Yazaira', + 'Yatzil', + 'Anam', + 'Sparrow', + 'Anetra', + 'Nalayah', + 'Jaylenne', + 'Joya', + 'Kensi', + 'Khylee', + 'Lilyrose', + 'Iasia', + 'Jaliah', + 'Melda', + 'Armella', + 'Zyasia', + 'Nazia', + 'Shanasia', + 'Krystie', + 'Dorothe', + 'Thora', + 'Adelene', + 'Avaya', + 'Aurielle', + 'Ailany', + 'Andromeda', + 'Loa', + 'Cleora', + 'Darling', + 'Caliana', + 'Keniyah', + 'Crystel', + 'Dimitra', + 'Renate', + 'Zyriah', + 'Taegan', + 'Marygrace', + 'Mckinzie', + 'Nivea', + 'Rhian', + 'Amarissa', + 'Kadee', + 'Devani', + 'Khara', + 'Aishia', + 'Annell', + 'Jaslin', + 'Jaide', + 'Briahna', + 'Merary', + 'Lauraine', + 'Tywana', + 'Athanasia', + 'Chantay', + 'Loretha', + 'Anyiah', + 'Marvine', + 'Jennelle', + 'Hiedi', + 'Sunnie', + 'Panagiota', + 'Lanesha', + 'Amity', + 'Denyse', + 'Nataleigh', + 'Amyia', + 'Avrie', + 'Analysa', + 'Ameris', + 'Ambrielle', + 'Kynnedy', + 'Gracy', + 'Kaelie', + 'Heydi', + 'Latrese', + 'Lavonia', + 'Latrelle', + 'Lynetta', + 'Graceann', + 'Susette', + 'Sarabeth', + 'Arnetta', + 'Shelonda', + 'Myiesha', + 'Shila', + 'Pascale', + 'Zenja', + 'Madelene', + 'Lalena', + 'Doria', + 'Dagmar', + 'Griselle', + 'Nitza', + 'Moraima', + 'Miguelina', + 'Brittania', + 'Emmalin', + 'Novie', + 'Chavonne', + 'Lashana', + 'Quyen', + 'Gennifer', + 'Zaryah', + 'Paytin', + 'Keeli', + 'Kolbi', + 'Maddyson', + 'Jackqueline', + 'Arnita', + 'Brynnley', + 'Edelyn', + 'Arial', + 'Yaneliz', + 'Ena', + 'Barbaraann', + 'Glendora', + 'Heavyn', + 'Neomi', + 'Rebbecca', + 'Laketa', + 'Renetta', + 'Carline', + 'Nezzie', + 'Shaneeka', + 'Desaray', + 'Hiromy', + 'Hallee', + 'Halli', + 'Sheba', + 'Tahisha', + 'Paetyn', + 'Katisha', + 'Joyell', + 'Joyel', + 'Zoei', + 'Zamiya', + 'Raygan', + 'Clydie', + 'Missouri', + 'Debany', + 'Kalisha', + 'Niurka', + 'Beverlyn', + 'Bell', + 'Zuly', + 'Lakayla', + 'Lainee', + 'Kynli', + 'Lundyn', + 'Erynn', + 'Braleigh', + 'Allena', + 'Lashanna', + 'Shaunya', + 'Tykia', + 'Leeba', + 'Bassheva', + 'Kandra', + 'Breyana', + 'Geovana', + 'Joandra', + 'Jessyka', + 'Analilia', + 'Charna', + 'Josefita', + 'Laurin', + 'Casi', + 'Jeniah', + 'Koraima', + 'Vivi', + 'Merlina', + 'Marinna', + 'Soriya', + 'Sarayu', + 'Ma', + 'Adali', + 'Abbygale', + 'Avonlea', + 'Bellah', + 'Makeyla', + 'Maanya', + 'Hania', + 'Ellah', + 'Esmee', + 'Jaylean', + 'Verlene', + 'Kendria', + 'Kasondra', + 'Kadesha', + 'Kadedra', + 'Reizel', + 'Reizy', + 'Sheryle', + 'Elka', + 'Caileigh', + 'Meya', + 'Rondi', + 'Janetta', + 'Dwana', + 'Yakira', + 'Donetta', + 'Laurissa', + 'Jordann', + 'Jenice', + 'Hasmik', + 'Mychelle', + 'Shabnam', + 'Sarahann', + 'Shaylene', + 'Zuleica', + 'Verenise', + 'Dejanee', + 'Alyx', + 'Breyanna', + 'Anum', + 'Jamesia', + 'Asheley', + 'Keya', + 'Lyzette', + 'Rossy', + 'Terilyn', + 'Rahaf', + 'Anabia', + 'Neala', + 'Payal', + 'Taheera', + 'Nakhia', + 'Shaela', + 'Krupa', + 'Suriya', + 'Victory', + 'Viviane', + 'Habiba', + 'Fortune', + 'Farida', + 'Erina', + 'Ranya', + 'Tifani', + 'Surie', + 'Aastha', + 'Joella', + 'Sherida', + 'Vonnie', + 'Bluma', + 'Gianny', + 'Naziyah', + 'Taylie', + 'Jakia', + 'Timia', + 'Farren', + 'Skylin', + 'Sabiha', + 'Nashley', + 'Blimi', + 'Annita', + 'Kristianna', + 'Delena', + 'Dalina', + 'Kyasia', + 'Cathlene', + 'Karalee', + 'Merilee', + 'Monette', + 'Asharia', + 'Jacquelina', + 'Nishat', + 'Charlcie', + 'Sukanya', + 'Celines', + 'Rashell', + 'Nadja', + 'Lamiyah', + 'Najae', + 'Zipporah', + 'Rawan', + 'Tailor', + 'Denesha', + 'Masiel', + 'Nida', + 'Assata', + 'Infiniti', + 'Cresencia', + 'Omega', + 'Meher', + 'Maneh', + 'Noura', + 'Yanine', + 'Maral', + 'Malori', + 'Safia', + 'Saori', + 'Vesper', + 'Audrinna', + 'Dea', + 'Kahlia', + 'Eliora', + 'Isley', + 'Laurinda', + 'Mignon', + 'Debie', + 'Denette', + 'Jolyn', + 'Casondra', + 'Donnisha', + 'Elysse', + 'Lazaria', + 'Aleia', + 'Shelbee', + 'Ivone', + 'Mazal', + 'Sherley', + 'Shantia', + 'Christelle', + 'Tatjana', + 'Roselia', + 'Pebbles', + 'Cleotilde', + 'Erendida', + 'Chardonnay', + 'Brittiny', + 'Brittanny', + 'Scarleth', + 'Mehar', + 'Neila', + 'Sofiya', + 'Lakshmi', + 'Lilianne', + 'Akeiba', + 'Shabreka', + 'Joannie', + 'Samiha', + 'Fatma', + 'Itzell', + 'Envy', + 'Maybelline', + 'Nashly', + 'Rya', + 'Kaelani', + 'Kailana', + 'Aylah', + 'Bellamarie', + 'Marizol', + 'Malyssa', + 'Madai', + 'Neelam', + 'Ysamar', + 'Sulma', + 'Sueling', + 'Song', + 'Sharayah', + 'Melisha', + 'Ashliegh', + 'Melodi', + 'Belem', + 'Chrystina', + 'Tonantzin', + 'Setareh', + 'Valeri', + 'Yaffa', + 'Niara', + 'Mame', + 'Janasia', + 'Flo', + 'Gustavia', + 'Lanya', + 'Nanie', + 'Velta', + 'Dot', + 'Luberta', + 'Ledora', + 'Olean', + 'Abbigayle', + 'Hadeel', + 'Rayma', + 'Mayola', + 'Nonnie', + 'Voncille', + 'Heloise', + 'Nolia', + 'Victorine', + 'Yola', + 'Vella', + 'Terrilyn', + 'Noelie', + 'Alean', + 'Allean', + 'Lorean', + 'Josiephine', + 'Heba', + 'Kerrianne', + 'Odeal', + 'Aigner', + 'Anaclara', + 'Gudrun', + 'Valborg', + 'Trenice', + 'Ardath', + 'Aune', + 'Teresia', + 'Lesha', + 'Dewanna', + 'Arlyce', + 'Jayliana', + 'Orene', + 'Paralee', + 'Jamyia', + 'Kemiyah', + 'Fredia', + 'Amyiah', + 'Doreatha', + 'Lashanta', + 'Cerissa', + 'Kawana', + 'Arizona', + 'Shanetta', + 'Jalesa', + 'Asmaa', + 'Garnette', + 'Clella', + 'Artemisa', + 'Liliya', + 'Oretha', + 'Adna', + 'Amyri', + 'Tyshae', + 'Maryan', + 'Santanna', + 'Bushra', + 'Jamyla', + 'Earma', + 'Delsie', + 'Verlean', + 'Sherena', + 'Carmelite', + 'Chari', + 'Darlean', + 'Shamia', + 'Audryna', + 'Genevia', + 'Avie', + 'Tamora', + 'Lavonna', + 'September', + 'Sharolyn', + 'Athziry', + 'Alyiah', + 'Aleina', + 'Alesandra', + 'Amoreena', + 'Nykia', + 'Drea', + 'Galilee', + 'Ainslie', + 'Ishita', + 'Jenavie', + 'Jezabel', + 'Erandi', + 'Evana', + 'Jiana', + 'Laniah', + 'Britanny', + 'Sanika', + 'Solash', + 'Laasya', + 'Nairi', + 'Leighla', + 'Kaiyah', + 'Suhana', + 'Taliya', + 'Maleia', + 'Candee', + 'Ninette', + 'Eugena', + 'Lateisha', + 'Salvatrice', + 'Quaneisha', + 'Mertis', + 'Bebe', + 'Rida', + 'Takyra', + 'Floye', + 'Christell', + 'Ozelle', + 'Juanice', + 'Genia', + 'Shaundra', + 'Shanin', + 'Wendee', + 'Cynde', + 'Adalynne', + 'Adelin', + 'Hayven', + 'Ayra', + 'Chimamanda', + 'Kenzlie', + 'Taylynn', + 'Zerenity', + 'Kynsleigh', + 'Dorthea', + 'Alley', + 'Melrose', + 'Keyondra', + 'Anglia', + 'Lynnea', + 'Tamira', + 'Terisa', + 'Tona', + 'Isaly', + 'Jeimy', + 'Giannah', + 'Leilanni', + 'Leya', + 'Quetzali', + 'Naylene', + 'Misaki', + 'Amely', + 'Donette', + 'Charlayne', + 'Selia', + 'Kittie', + 'Tamaya', + 'Lenna', + 'Zykerria', + 'Teisha', + 'Terrea', + 'Alita', + 'Bunny', + 'Deniece', + 'Inge', + 'Takira', + 'Monesha', + 'Mahala', + 'Donica', + 'Fortunata', + 'Valrie', + 'Zayah', + 'Ziyah', + 'Vela', + 'Vassie', + 'Omie', + 'Nadean', + 'Annalynn', + 'Adah', + 'Edmae', + 'Aalayah', + 'Yuritzy', + 'Ytzel', + 'Svetlana', + 'Soha', + 'Alfredia', + 'Kylei', + 'Landrey', + 'Lariyah', + 'Rozlyn', + 'Sakina', + 'Greer', + 'Bula', + 'Eura', + 'Harmonee', + 'Pecola', + 'Noreta', + 'Laveda', + 'Retta', + 'Rozlynn', + 'Skarlet', + 'Snow', + 'Zoha', + 'Sophiarose', + 'Anglea', + 'Itzabella', + 'Elanie', + 'Calirose', + 'Adhya', + 'Amaiyah', + 'Lavender', + 'Leylanie', + 'Kaliana', + 'Quetzaly', + 'Helon', + 'Nalia', + 'Cipriana', + 'Martyna', + 'Pola', + 'Dierra', + 'Maximina', + 'Sherica', + 'Murlene', + 'Berna', + 'Bernarda', + 'Ettie', + 'Laiken', + 'Hensley', + 'Fontella', + 'Modelle', + 'Timotea', + 'Venora', + 'Lakelyn', + 'Licia', + 'Laury', + 'Loralee', + 'Kamyah', + 'Verba', + 'Angelee', + 'Adalind', + 'Adaliz', + 'Ailynn', + 'Airi', + 'Alany', + 'Avika', + 'Avleen', + 'Leoni', + 'Saisha', + 'Savvy', + 'Philippa', + 'Jasneet', + 'Izabellah', + 'Elienai', + 'Kalayah', + 'Eureka', + 'Dionicia', + 'Zylah', + 'Zosia', + 'Yetzali', + 'Tigerlily', + 'Dorena', + 'Nakesha', + 'Lakenya', + 'Margarete', + 'Margarite', + 'Cloteal', + 'Adline', + 'Willadeen', + 'Anselma', + 'Marcheta', + 'Havyn', + 'Ilyanna', + 'Idalie', + 'Fallyn', + 'Emori', + 'Anzal', + 'Kalila', + 'Ellisyn', + 'Maddalyn', + 'Roslynn', + 'Hodan', + 'Emalynn', + 'Addy', + 'Adelyne', + 'Aizah', + 'Dalayza', + 'Cambri', + 'Annali', + 'Angelynn', + 'Caidence', + 'Auriana', + 'Azlynn', + 'Blakelee', + 'Brenleigh', + 'Tailynn', + 'Zyla', + 'Verline', + 'Pierina', + 'Panhia', + 'Valda', + 'Shela', + 'Uldine', + 'Vibha', + 'Wednesday', + 'Porshia', + 'Shabria', + 'Palmina', + 'Khristine', + 'Lannette', + 'Sandhya', + 'Janalyn', + 'Floreine', + 'Marchelle', + 'Minette', + 'Tawnia', + 'Wynne', + 'Sada', + 'Windi', + 'Clydene', + 'Shundra', + 'Joycie', + 'Delories', + 'Alvena', + 'Edmonia', + 'Denean', + 'Dhana', + 'Marjie', + 'Alicja', + 'Cammy', + 'Aryam', + 'Leonie', + 'Adrielle', + 'Felisita', + 'Tinnie', + 'Marinda', + 'Lamia', + 'Conchetta', + 'Naylah', + 'Sarayah', + 'Nataliya', + 'Delani', + 'Eknoor', + 'Ellee', + 'Maiah', + 'Mayumi', + 'Meara', + 'Kalliope', + 'Jewels', + 'Lanaya', + 'Yui', + 'Maxcine', + 'Yaqueline', + 'Yoceline', + 'Marilynne', + 'Maple', + 'Ronesha', + 'Marili', + 'Reema', + 'Rayana', + 'Aggie', + 'Talina', + 'Doristine', + 'Romelle', + 'Shaqueena', + 'Sharelle', + 'Caira', + 'Gelsey', + 'Tashawna', + 'Takeisha', + 'Jerlean', + 'Sunita', + 'Shalini', + 'Michaeline', + 'Audria', + 'Ronnisha', + 'Leonia', + 'Monna', + 'Ambra', + 'Corena', + 'Taren', + 'Alexiss', + 'Kajal', + 'Jordanne', + 'Kasia', + 'Brienna', + 'Gayane', + 'Deija', + 'Cidney', + 'Tabytha', + 'Raeleen', + 'Mkayla', + 'Harli', + 'Jassmin', + 'Ilo', + 'Lasheena', + 'Keianna', + 'Kally', + 'Makenzy', + 'Angelea', + 'Natasia', + 'Shaneequa', + 'Monay', + 'Moet', + 'Marcelline', + 'Shatia', + 'Sarafina', + 'Kaisha', + 'Tiffney', + 'Shenequa', + 'Sheretta', + 'Floria', + 'Alacia', + 'Kavita', + 'Kerianne', + 'Tameshia', + 'Jamye', + 'Shanese', + 'Latiqua', + 'Jesscia', + 'Johanny', + 'Daniqua', + 'Geneviev', + 'Bernadet', + 'Annice', + 'Megann', + 'Katee', + 'Nikeya', + 'Stavroula', + 'Tawna', + 'Sindia', + 'Marlaina', + 'Jury', + 'Tovah', + 'Shivonne', + 'Nekia', + 'Yvonnie', + 'Kyna', + 'Railey', + 'Xandria', + 'Genine', + 'Tashima', + 'Marycarmen', + 'Kiahna', + 'Jadynn', + 'Akua', + 'Eather', + 'Fatema', + 'Aiysha', + 'Allisa', + 'Ashleynicole', + 'Bobette', + 'Shandrika', + 'Hollace', + 'Chandni', + 'Cayley', + 'Brenae', + 'Areisy', + 'Annahi', + 'Anallely', + 'Klarisa', + 'Ayssa', + 'Jatavia', + 'Nohemy', + 'Mikyla', + 'Mariadelosang', + 'Shatina', + 'Kazandra', + 'Elsi', + 'Teryl', + 'Yennifer', + 'Destyni', + 'Damariz', + 'Areanna', + 'Everlean', + 'Lesslie', + 'Margrette', + 'Tuyet', + 'Jacquelene', + 'Grissel', + 'Walterine', + 'Shterna', + 'Gila', + 'Nabila', + 'Liel', + 'Sani', + 'Djeneba', + 'Angeliz', + 'Anari', + 'Amyrie', + 'Aissa', + 'Tichina', + 'Amariana', + 'Xiara', + 'Yamiles', + 'Isatou', + 'Airiana', + 'Carrigan', + 'Aldea', + 'Aarika', + 'Bryanne', + 'Alegandra', + 'Carrisa', + 'Andrina', + 'Casaundra', + 'Breanda', + 'Biviana', + 'Irena', + 'Denielle', + 'Lizzett', + 'Shaunice', + 'Sigourney', + 'Sona', + 'Paradise', + 'Lashanique', + 'Melaina', + 'Zoua', + 'Vaneza', + 'Tyresha', + 'Shyasia', + 'Tiyana', + 'Youa', + 'Zaneta', + 'Muskan', + 'Talissa', + 'Kennisha', + 'Lizandra', + 'Akosua', + 'Jaymi', + 'Chelby', + 'Chelci', + 'Aeriel', + 'Isamara', + 'Payge', + 'Hadja', + 'Fruma', + 'Fiza', + 'Fatumata', + 'Kabrina', + 'Feigy', + 'Zanaya', + 'Yanette', + 'Teairra', + 'Talor', + 'Kathrina', + 'Justeen', + 'Maryelizabeth', + 'Jannete', + 'Chantalle', + 'Haide', + 'Genelle', + 'Esthela', + 'Emilse', + 'Maegen', + 'Lyndsi', + 'Cristiana', + 'Clio', + 'Breindel', + 'Briyana', + 'Jamyria', + 'Jameshia', + 'Kadeshia', + 'Jamisha', + 'Faige', + 'Aishah', + 'Lorette', + 'Nandi', + 'Nastasia', + 'Shada', + 'Shakeia', + 'Shaneice', + 'Yanel', + 'Teryn', + 'Shaylyn', + 'Karimah', + 'Fabienne', + 'Shaianne', + 'Saleena', + 'Raychelle', + 'Pahoua', + 'Justyne', + 'Fransheska', + 'Katilyn', + 'Shadaya', + 'Quanasia', + 'Shantasia', + 'Nyasha', + 'Minahil', + 'Shahd', + 'Chani', + 'Bassy', + 'Zunairah', + 'Lynsie', + 'Charnelle', + 'Jaquana', + 'Taquana', + 'Shaasia', + 'Idelle', + 'Rogene', + 'Udy', + 'Devory', + 'Evanna', + 'Keisy', + 'Hadiya', + 'Brittainy', + 'Cortni', + 'Erikka', + 'Lindsie', + 'Mayraalejandra', + 'Topacio', + 'Elky', + 'Yita', + 'Sura', + 'Tiani', + 'Sadiya', + 'Kaitlen', + 'Jessicca', + 'Linna', + 'Stephy', + 'Hadia', + 'Jaiyana', + 'Aldina', + 'Frimy', + 'Tywanda', + 'Renarda', + 'Mardelle', + 'Alaijah', + 'Antoinetta', + 'Amyria', + 'Sheyanne', + 'Jackee', + 'Bina', + 'Khole', + 'Selenia', + 'Seidy', + 'Albertina', + 'Yoandra', + 'Yarelyn', + 'Kassaundra', + 'Lynzee', + 'Haneen', + 'Marshay', + 'Sharona', + 'Shanygne', + 'Nigeria', + 'Nechy', + 'Jhane', + 'Chrisette', + 'Gypsy', + 'Drusilla', + 'Milta', + 'Ranee', + 'Yvett', + 'Mykenzie', + 'Aracelia', + 'Vernessa', + 'Chekesha', + 'Cadance', + 'Moria', + 'Tsurue', + 'Yarisbel', + 'Verena', + 'Tomoe', + 'Breezy', + 'Swannie', + 'Tsuyuko', + 'Hisayo', + 'Gerianne', + 'Cailynn', + 'Adrionna', + 'Lillianne', + 'Eduarda', + 'Melinna', + 'Sanaiya', + 'Nohelia', + 'Zarela', + 'Yarethzy', + 'Sruthi', + 'Josefine', + 'Kiela', + 'Kersten', + 'Syriah', + 'Emaleigh', + 'Jazlynne', + 'Aeryn', + 'Danelly', + 'Dalylah', + 'Lexa', + 'Kherington', + 'Nivia', + 'Carolanne', + 'Sharlotte', + 'Vanda', + 'Deirdra', + 'Ilyse', + 'Judyann', + 'Venezia', + 'Mailee', + 'Latishia', + 'Ajla', + 'Lucine', + 'Shontell', + 'Rosiland', + 'Celinda', + 'Aanika', + 'Felicidad', + 'Denia', + 'Natsuko', + 'Analyse', + 'Angellina', + 'Brizeida', + 'Jazira', + 'Terah', + 'Reana', + 'Jennalyn', + 'Jenaya', + 'Kelani', + 'Miyuki', + 'Aracelie', + 'Dannika', + 'Danity', + 'Cadie', + 'Breelyn', + 'Kayra', + 'Mayli', + 'Malarie', + 'Tequilla', + 'Gerilyn', + 'Mieko', + 'Belynda', + 'Shamiyah', + 'Reaghan', + 'Ziya', + 'Rozanne', + 'Joyanne', + 'Zamaria', + 'Luiza', + 'Tamanika', + 'Kimya', + 'Patriciaann', + 'Eilene', + 'Bryna', + 'Yena', + 'Yarelly', + 'Maddyn', + 'Khylie', + 'Khyla', + 'Margueritte', + 'Ramya', + 'Jenea', + 'Jennavie', + 'Jazzlene', + 'Marelly', + 'Manya', + 'Lillyanne', + 'Gyselle', + 'Niyati', + 'Moana', + 'Kenosha', + 'Ezmeralda', + 'Anvitha', + 'Avelyn', + 'Dahlila', + 'Emmaly', + 'Dayamy', + 'Anajulia', + 'Mandee', + 'Valli', + 'Sharan', + 'Leasia', + 'Shiquita', + 'Malana', + 'Nadeen', + 'Parneet', + 'Lynna', + 'Saskia', + 'Samaiya', + 'Saffron', + 'Vianka', + 'Evey', + 'Ebelin', + 'Anishka', + 'Aneth', + 'Addelynn', + 'Kayly', + 'Alyzae', + 'Anniyah', + 'Ayme', + 'Alexsa', + 'Aidsa', + 'Elyn', + 'Illianna', + 'Greenlee', + 'Tinesha', + 'Sherline', + 'Yvanna', + 'Joslin', + 'Estee', + 'Lusia', + 'Nhung', + 'Janielle', + 'Smithie', + 'Yohanna', + 'Shanette', + 'Marilena', + 'Blannie', + 'Meleana', + 'Malie', + 'Jannine', + 'Kuulei', + 'Kawehi', + 'Velna', + 'Kuuipo', + 'Keani', + 'Tiffeny', + 'Billi', + 'Conni', + 'Elexia', + 'Sheily', + 'Mehak', + 'Ardelia', + 'Phung', + 'Aleasha', + 'Toyia', + 'Kalliopi', + 'Carrieann', + 'Shayal', + 'Brandye', + 'Shatisha', + 'Neola', + 'Pallavi', + 'Symantha', + 'Mackenzee', + 'Shalawn', + 'Krimson', + 'Jaquelinne', + 'Sonal', + 'Calysta', + 'Kaylamarie', + 'Kirah', + 'Belicia', + 'Anicia', + 'Aerin', + 'Marisel', + 'Priscella', + 'Lei', + 'Imaan', + 'Haruka', + 'Kila', + 'Jerusha', + 'Deva', + 'Charon', + 'Leida', + 'Deadra', + 'Areana', + 'Iriana', + 'Drenda', + 'Saadia', + 'Danne', + 'Jossalyn', + 'Kennadie', + 'Makaya', + 'Daelynn', + 'Daffne', + 'Galia', + 'Naida', + 'Yaira', + 'Latania', + 'Damarys', + 'Mireille', + 'Maribell', + 'Luzelena', + 'Anacani', + 'Sahira', + 'Shaylin', + 'Sejal', + 'Subrina', + 'Julaine', + 'Saby', + 'Zoraya', + 'Atalie', + 'Deseray', + 'Nacole', + 'Jennell', + 'Laneisha', + 'Ivie', + 'Darnella', + 'Lashone', + 'Lekeisha', + 'Puanani', + 'Uilani', + 'Donyale', + 'Terriann', + 'Marianela', + 'Josalynn', + 'Avari', + 'Blonnie', + 'Makya', + 'Seriah', + 'Nori', + 'Roselee', + 'Verbie', + 'Borghild', + 'Marcene', + 'Syretta', + 'Bama', + 'Eulene', + 'Chantale', + 'Shontae', + 'Mabell', + 'Hellon', + 'Shantanique', + 'Janki', + 'Dhara', + 'Buna', + 'Naeemah', + 'Tacara', + 'Shirleyann', + 'Tshwanda', + 'Nadege', + 'Georganne', + 'Leondra', + 'Fredricka', + 'Margaree', + 'Quincee', + 'Oaklynn', + 'Arlean', + 'Judee', + 'Nyoka', + 'Khia', + 'Kendia', + 'Mahek', + 'Anasia', + 'Jenin', + 'Gerline', + 'Elwillie', + 'Annsley', + 'Juhi', + 'Zettie', + 'Shacara', + 'Shantique', + 'Marijo', + 'Shakara', + 'Ersie', + 'Bionca', + 'Kolleen', + 'Ertha', + 'Chioma', + 'Roneisha', + 'Courtenay', + 'Altie', + 'Arla', + 'Delainey', + 'Rainelle', + 'Lockie', + 'Rayonna', + 'Nasiyah', + 'Zori', + 'Carollee', + 'Mima', + 'Irja', + 'Willadean', + 'Sigrid', + 'Myong', + 'Khaliah', + 'Sakeenah', + 'Saleemah', + 'Emmersyn', + 'Miyeko', + 'Brooksie', + 'Brailynn', + 'Raghad', + 'Nadira', + 'Hassana', + 'Toshiye', + 'Fumiye', + 'Kelise', + 'Angelis', + 'Earla', + 'Dilia', + 'Arwa', + 'Shaylie', + 'Synai', + 'Tanijah', + 'Jalaysia', + 'Charnita', + 'Marit', + 'Gaelle', + 'Shandiin', + 'Janelis', + 'Gatha', + 'Alahna', + 'Aniyla', + 'Mikelle', + 'Skai', + 'Merlinda', + 'Tariyah', + 'Arietta', + 'Terrika', + 'Elenor', + 'Ruthanna', + 'Evaline', + 'Abigaelle', + 'Alayjah', + 'Naysa', + 'Camya', + 'Pachia', + 'Kamia', + 'Sylvania', + 'Ambree', + 'Oakleigh', + 'Zania', + 'Murielle', + 'Charlyn', + 'Zykira', + 'Jestine', + 'Simonne', + 'Willodene', + 'Lyndee', + 'Sophonie', + 'Saddie', + 'Darlis', + 'Lynnda', + 'Marysa', + 'Seleena', + 'Raevyn', + 'Lilikoi', + 'Maiyer', + 'Kymberli', + 'Shayda', + 'Cassidee', + 'Jadira', + 'Delora', + 'Afsheen', + 'Adira', + 'Amena', + 'Canary', + 'Humaira', + 'Derricka', + 'Fatiha', + 'Xia', + 'Jaquelyne', + 'Aurianna', + 'Sarahjane', + 'Sanaz', + 'Taleen', + 'Teara', + 'Taiz', + 'Sharai', + 'Magally', + 'Manon', + 'Maizie', + 'Manisha', + 'Marisleysis', + 'Anjela', + 'Youlanda', + 'Jermani', + 'Elysha', + 'Claritza', + 'Gissela', + 'Icela', + 'Alixandria', + 'Asley', + 'Analuisa', + 'Maddalena', + 'Cortnee', + 'Coretha', + 'Audreanna', + 'Manal', + 'Kadijatou', + 'Pollie', + 'Mysti', + 'Tiffiany', + 'Corean', + 'Amiree', + 'Anner', + 'Cleone', + 'Lavone', + 'Fredna', + 'Konnie', + 'Robbyn', + 'Alica', + 'Bessy', + 'Aleesa', + 'Analleli', + 'Mischelle', + 'Bethani', + 'Baillie', + 'Odessie', + 'Erlene', + 'Marcile', + 'Edona', + 'Tylah', + 'Tyrah', + 'Rainell', + 'Precilla', + 'Genever', + 'Ajanee', + 'Chera', + 'Amye', + 'Monserratt', + 'Moorea', + 'Richa', + 'Willetta', + 'Shawne', + 'Trisa', + 'Lasonia', + 'Cleona', + 'Alizea', + 'Anayely', + 'Emelly', + 'Fionna', + 'Cerena', + 'Julyana', + 'Kaile', + 'Jacklin', + 'Brianca', + 'Ashleyann', + 'Richardine', + 'Kelcee', + 'Keyaira', + 'Mabelle', + 'Brecklyn', + 'Samyah', + 'Ayonna', + 'Mesha', + 'Tyeshia', + 'Tiffiney', + 'Tyara', + 'Azuri', + 'Merideth', + 'Hermie', + 'Leaner', + 'Mendi', + 'Kanoelani', + 'Kadeidra', + 'Akeela', + 'Lin', + 'Mindel', + 'Lashell', + 'Meegan', + 'Ia', + 'Ellamae', + 'Jasmen', + 'Nechuma', + 'Romilda', + 'Hiilei', + 'Osmara', + 'Keidy', + 'Rianne', + 'Afia', + 'Teylor', + 'Raquelle', + 'Grizelda', + 'Tasfia', + 'Laquasha', + 'Tandra', + 'Maeghan', + 'Kameshia', + 'Alara', + 'Emina', + 'Delaina', + 'Jacquetta', + 'Christena', + 'Topanga', + 'Viviann', + 'Eboney', + 'Kasha', + 'Sativa', + 'Secilia', + 'Niomi', + 'Neena', + 'Tanji', + 'Shandy', + 'Corryn', + 'Esly', + 'Silka', + 'Sanaii', + 'Annais', + 'Kaitlynne', + 'Epiphany', + 'Maniya', + 'Mali', + 'Madigan', + 'Sanii', + 'Jaeleen', + 'Faria', + 'Maralyn', + 'Johnae', + 'Lekesha', + 'Sharry', + 'Latecia', + 'Kimberl', + 'Charita', + 'Modean', + 'Marrie', + 'Lielle', + 'Zeina', + 'Pessel', + 'Sameera', + 'Eleonora', + 'Jannatul', + 'Coryn', + 'Dustie', + 'Demitria', + 'Jacqlyn', + 'Nekisha', + 'Latrecia', + 'Rabecca', + 'Malaysha', + 'Lugenia', + 'Elese', + 'Myrissa', + 'Lucrecia', + 'Lysandra', + 'Tarryn', + 'Tammey', + 'Bonnita', + 'Shiffy', + 'Shirel', + 'Clariza', + 'Analis', + 'Rechy', + 'Nusaiba', + 'Manahil', + 'Chamisa', + 'Almetta', + 'Moncia', + 'Leba', + 'Jeilyn', + 'Earnesteen', + 'Mennie', + 'Kieara', + 'Sheina', + 'Yo', + 'Sharnice', + 'Ravin', + 'Daisi', + 'Britini', + 'Carlina', + 'Arisa', + 'Margy', + 'Whitnee', + 'Krysti', + 'Odean', + 'Darlys', + 'Janita', + 'Donnetta', + 'Guynell', + 'Neomia', + 'Loyalty', + 'Serra', + 'Kaysie', + 'Preciosa', + 'Earleen', + 'Shatoria', + 'Kourtnie', + 'Kana', + 'Jahnavi', + 'Kyarra', + 'Licet', + 'Railyn', + 'Delisha', + 'Flordia', + 'Arsema', + 'Kena', + 'Kaelah', + 'Kashia', + 'Emonie', + 'Izola', + 'Linsay', + 'Naibe', + 'Natallie', + 'Rosi', + 'Taline', + 'Cortina', + 'Annett', + 'Kadi', + 'Lindsi', + 'Lasasha', + 'Tamre', + 'Yenny', + 'Yasaman', + 'Shawnice', + 'Thi', + 'Jannel', + 'Kaleen', + 'Demitra', + 'Meisha', + 'Mahira', + 'Emmanuela', + 'Janaiya', + 'Rechel', + 'Nazifa', + 'Zeynep', + 'Shalena', + 'Hila', + 'Ailish', + 'Altovise', + 'Anabeth', + 'Anavictoria', + 'Averey', + 'Berlynn', + 'Alitza', + 'Adelynne', + 'Aiva', + 'Alenna', + 'Harlowe', + 'Camrynn', + 'Daphnie', + 'Ezri', + 'Lanna', + 'Lua', + 'Maddilynn', + 'Maeva', + 'Maytte', + 'Jovi', + 'Karalyn', + 'Kataleah', + 'Kaylana', + 'Milliana', + 'Surveen', + 'Veera', + 'Nimrat', + 'Nimrit', + 'Radha', + 'Roisin', + 'Senna', + 'Ruhi', + 'Saja', + 'Glenice', + 'Damiana', + 'Mikeria', + 'Lakeria', + 'Yulia', + 'Zanna', + 'Lynnae', + 'Illa', + 'Buelah', + 'Novis', + 'Johnye', + 'Valree', + 'Santiaga', + 'Modell', + 'Maydell', + 'Elfida', + 'Charlyne', + 'Argentina', + 'Terica', + 'Kiandra', + 'Tangi', + 'Pascuala', + 'Narcisa', + 'Macaria', + 'Thomasa', + 'Verta', + 'Eulogia', + 'Trellis', + 'Tavaria', + 'Dakayla', + 'Oneita', + 'Kimberlynn', + 'Aslee', + 'Jenascia', + 'Shamaria', + 'Lakely', + 'Etna', + 'Gilberte', + 'Glena', + 'Delorse', + 'Margrett', + 'Endia', + 'Buena', + 'Alvilda', + 'Domitila', + 'Jasmaine', + 'Jaquita', + 'Shontavia', + 'Roneshia', + 'Leasa', + 'Feliciana', + 'Allyana', + 'Anaia', + 'Annalyn', + 'Ayane', + 'Belladonna', + 'Adanely', + 'Akshaya', + 'Aleiyah', + 'Tereasa', + 'Antonisha', + 'Darlah', + 'Dhalia', + 'Dianelly', + 'Elika', + 'Camillia', + 'Leonila', + 'Manreet', + 'Jazzlin', + 'Kaiulani', + 'Kashvi', + 'Talayah', + 'Viana', + 'Ximenna', + 'Shaylah', + 'Quorra', + 'Anagha', + 'Annalea', + 'Jaleyah', + 'Bethanny', + 'Zophia', + 'Alegria', + 'Advika', + 'Taneika', + 'Marye', + 'Latorya', + 'Sayler', + 'Nara', + 'Nithya', + 'Phoenyx', + 'Saiya', + 'Mellany', + 'Yazlin', + 'Adalena', + 'Adya', + 'Aliviah', + 'Aalia', + 'Rickia', + 'Eliyana', + 'Arella', + 'Audris', + 'Auria', + 'Avantika', + 'Aylani', + 'Beya', + 'Camilah', + 'Kaede', + 'Laylonie', + 'Jayani', + 'Katara', + 'Hera', + 'Audrea', + 'Nataley', + 'Nazli', + 'Neyla', + 'Noya', + 'Srinidhi', + 'Pranavi', + 'Sareen', + 'Satya', + 'Terika', + 'Zamora', + 'Jimmye', + 'Brigida', + 'Shereka', + 'Widline', + 'Natori', + 'Dorthie', + 'Berit', + 'Aretta', + 'Svea', + 'Wenona', + 'Amera', + 'Nayah', + 'Lollie', + 'Genice', + 'Fabianna', + 'Nazaria', + 'Edra', + 'Jamariah', + 'Willine', + 'Madolyn', + 'Wanell', + 'Lucetta', + 'Eudora', + 'Adda', + 'Shariah', + 'Jaelle', + 'Jalena', + 'Annelle', + 'Solveig', + 'Autherine', + 'Nobie', + 'Izora', + 'Eudell', + 'Wyolene', + 'Mariangel', + 'Mayar', + 'Luevenia', + 'Eniyah', + 'Lilie', + 'Eliany', + 'Ivyonna', + 'Beadie', + 'Zeta', + 'Merita', + 'Valjean', + 'Delbra', + 'Alanys', + 'Camiyah', + 'Edyth', + 'Kanya', + 'Perina', + 'Catelynn', + 'Angelisse', + 'Relda', + 'Eathel', + 'Kerrington', + 'Lyriq', + 'Brita', + 'Meda', + 'Zanya', + 'Emileigh', + 'Aracelys', + 'Lisania', + 'Evalena', + 'Traniya', + 'Janiyla', + 'Syesha', + 'Ahmya', + 'Camora', + 'Armonie', + 'Beula', + 'Veva', + 'Kateria', + 'Harumi', + 'Kimiyo', + 'Tangie', + 'Amayrany', + 'Alexiah', + 'Alyn', + 'Tokie', + 'Masayo', + 'Makenzee', + 'Arieana', + 'Asayo', + 'Seirra', + 'Elfrida', + 'Ariona', + 'Masue', + 'Mizuki', + 'Liliane', + 'Malanie', + 'Sabreen', + 'Yuritza', + 'Shanautica', + 'Kateleen', + 'Montanna', + 'Tiona', + 'Theresia', + 'Vernia', + 'Mahayla', + 'Glynna', + 'Shaelynn', + 'Isabelly', + 'Aileth', + 'Ailie', + 'Melvia', + 'Sherrel', + 'Ivah', + 'Himani', + 'Marayah', + 'Melane', + 'Evanie', + 'Atalia', + 'Athalia', + 'Bethsy', + 'Betzi', + 'California', + 'Bryonna', + 'Yaretsy', + 'Zamara', + 'Sanyah', + 'Gaylynn', + 'Vitoria', + 'Yoshino', + 'Hatsumi', + 'Tatsuko', + 'Samika', + 'Maili', + 'Charnae', + 'Jamilla', + 'Vieno', + 'Rylei', + 'Vanita', + 'Hydia', + 'Carmyn', + 'Kenslie', + 'Maryhelen', + 'Lamees', + 'Lilley', + 'Haunani', + 'Pualani', + 'Mikiyah', + 'Lovina', + 'Janith', + 'Kanoe', + 'Anouk', + 'Mayerly', + 'Kiele', + 'Lexia', + 'Janani', + 'Berlinda', + 'Belma', + 'Inayah', + 'Saloma', + 'Anely', + 'Anjolina', + 'Devonna', + 'Nikhita', + 'Nayana', + 'Naidely', + 'Hina', + 'Ismerai', + 'Daisie', + 'Sitlaly', + 'Yahayra', + 'Trinidy', + 'Vallery', + 'Ceaira', + 'Floretta', + 'Lavena', + 'Shawntavia', + 'Dessa', + 'Tareva', + 'Iyanla', + 'Kania', + 'Shakiya', + 'Latora', + 'Hermila', + 'Clora', + 'Tiyanna', + 'Saydie', + 'Sherlene', + 'Trixie', + 'Nadiyah', + 'Zarria', + 'Saidy', + 'Sabriya', + 'Keirra', + 'Leeana', + 'Leianna', + 'Jaia', + 'Ishanvi', + 'Ailed', + 'Fathima', + 'Hansika', + 'Delailah', + 'Caliah', + 'Dayleen', + 'Jolisa', + 'Sallye', + 'Levonia', + 'Tula', + 'Kristene', + 'Alanni', + 'Aleiah', + 'Aeva', + 'Ilean', + 'Annet', + 'Lateshia', + 'Markesha', + 'Nikol', + 'Nadolyn', + 'Kimyatta', + 'Ercilia', + 'Sheliah', + 'Heiley', + 'Metztli', + 'Teyla', + 'Saranya', + 'Tanishka', + 'Kayana', + 'Donnamae', + 'Lajoyce', + 'Kemya', + 'Kemora', + 'Jozelyn', + 'Keili', + 'Jaydy', + 'Linzy', + 'Marelin', + 'Melaney', + 'Aleksa', + 'Alynah', + 'Elyza', + 'Emmery', + 'Angeleen', + 'Annica', + 'Bindi', + 'Demya', + 'Nayleen', + 'Sadee', + 'Samah', + 'Shylee', + 'Talula', + 'Vannia', + 'Yarelli', + 'Zohar', + 'Miangel', + 'Orla', + 'Sundra', + 'Korinne', + 'Taniesha', + 'Zaliyah', + 'Zionna', + 'Amariyah', + 'Loris', + 'Cruzita', + 'Landa', + 'Eduvina', + 'Ileanna', + 'Ileene', + 'Jesselle', + 'Daviana', + 'Eleny', + 'Marijane', + 'Okla', + 'Violanda', + 'Dorma', + 'Leoma', + 'Esperansa', + 'Shanreka', + 'Baudelia', + 'Teasia', + 'Aubrei', + 'Jeree', + 'Ortencia', + 'Melida', + 'Pernie', + 'Sweetie', + 'Arelly', + 'Ariday', + 'Bhavya', + 'Aiyanah', + 'Akshita', + 'Ginette', + 'Docia', + 'Pegeen', + 'Alaynah', + 'Allanah', + 'Daniah', + 'Loriana', + 'Kenly', + 'Kenli', + 'Kendahl', + 'Kenady', + 'Senora', + 'Hetal', + 'Aloha', + 'Barri', + 'Shaniquah', + 'Feather', + 'Rica', + 'Adriann', + 'Fleta', + 'Shontel', + 'Kynisha', + 'Nahima', + 'Myracle', + 'Syniah', + 'Jomarie', + 'Leeandra', + 'Maylie', + 'Marijose', + 'Jaley', + 'Sydnei', + 'Amariya', + 'Alysandra', + 'Damia', + 'Laurieann', + 'Lucecita', + 'Miosotis', + 'Shelvy', + 'Bernina', + 'Darice', + 'Dorrie', + 'Myrta', + 'Yoko', + 'Vara', + 'Joanmarie', + 'Kerryann', + 'Carmesa', + 'Kenzington', + 'Oaklyn', + 'Shelbia', + 'Arhianna', + 'Ardyn', + 'Amarachi', + 'Cydnee', + 'Chloey', + 'Brailee', + 'Aily', + 'Rosette', + 'Geryl', + 'Luba', + 'Marguerita', + 'Ayannah', + 'Deziyah', + 'Lurdes', + 'Dawnelle', + 'Reiko', + 'Brynli', + 'Tenlee', + 'Kynadee', + 'Emersen', + 'Josilyn', + 'Jazalyn', + 'Maleyah', + 'Cozette', + 'Xoe', + 'Syria', + 'Charyl', + 'Gita', + 'Aniaya', + 'Yulemni', + 'Joleigh', + 'Kenzy', + 'Logann', + 'Genesys', + 'Cherita', + 'Trenise', + 'Stpehanie', + 'Riann', + 'Matilyn', + 'Akisha', + 'Coralee', + 'Presli', + 'Yariana', + 'Edda', + 'Lisabeth', + 'Farm', + 'Dennice', + 'Deepa', + 'Chiffon', + 'Alyzea', + 'Alexas', + 'Emylee', + 'Joellyn', + 'Zo', + 'Marybell', + 'Sapna', + 'Khristina', + 'Kellyanne', + 'Chrystie', + 'Damary', + 'Graziella', + 'Tene', + 'Shakisha', + 'Shirelle', + 'Gwynne', + 'Insha', + 'Lydiann', + 'Cuba', + 'Cortnie', + 'Denelle', + 'Huyen', + 'Brieann', + 'Cindia', + 'Shalina', + 'Linnette', + 'Kiamesha', + 'Anecia', + 'Brinna', + 'Kewanna', + 'Malke', + 'Yira', + 'Rashidah', + 'Karicia', + 'Chrislyn', + 'Idali', + 'Zandria', + 'Ruta', + 'Toshi', + 'Daena', + 'Aneliz', + 'Cherese', + 'Brandalyn', + 'Brieanne', + 'Chistina', + 'Denys', + 'Nyisha', + 'Lissie', + 'Sherine', + 'Marisal', + 'Tuwana', + 'Zyonna', + 'Shady', + 'Patrisha', + 'Laniece', + 'Jessamyn', + 'Letticia', + 'Shirlie', + 'Miyo', + 'Marilouise', + 'Yukiye', + 'Ltanya', + 'Geralynn', + 'Anastazia', + 'Mitzie', + 'Lluliana', + 'Rozanna', + 'Magalie', + 'Salima', + 'Bevin', + 'Gaudy', + 'Ieasha', + 'Makia', + 'Sacheen', + 'Sherene', + 'Mataya', + 'Hatsuye', + 'Chiyeko', + 'Devanny', + 'Nasya', + 'Odyssey', + 'Tunisia', + 'Caldonia', + 'Marsi', + 'Mindee', + 'Tamy', + 'Sherill', + 'Tsitsiki', + 'Arva', + 'Gayleen', + 'Kimmy', + 'Lenette', + 'Roxan', + 'Leanora', + 'Charlena', + 'Claudina', + 'Danise', + 'Denell', + 'Eydie', + 'Irish', + 'Hydeia', + 'Nichele', + 'Ronica', + 'Temre', + 'Cindra', + 'Vincenta', + 'Zyra', + 'Larita', + 'Jodine', + 'Ewelina', + 'Madylin', + 'Kinzleigh', + 'Malone', + 'Layken', + 'Verity', + 'Tinleigh', + 'Sophi', + 'Skyleigh', + 'Stanislawa', + 'Rylinn', + 'Natalynn', + 'Marlei', + 'Rhylie', + 'Payslee', + 'Paxtyn', + 'Brittyn', + 'Alaynna', + 'Avory', + 'Aubriee', + 'Jacqui', + 'Aseel', + 'Jannell', + 'Simra', + 'Raneem', + 'Kellene', + 'Shellee', + 'Tish', + 'Lashauna', + 'Ashira', + 'Sharrie', + 'Donnette', + 'Milarain', + 'Toshia', + 'Shariyah', + 'Dariah', + 'Gustava', + 'Leotha', + 'Sherelle', + 'Lindi', + 'Luanna', + 'Shanan', + 'Arelys', + 'Nyema', + 'Errin', + 'Fredrica', + 'Dhriti', + 'Yashvi', + 'Gaile', + 'Ermalinda', + 'Gregorita', + 'Klynn', + 'Kaedence', + 'Zaila', + 'Yaritzi', + 'Taylyn', + 'Tailyn', + 'Milka', + 'Maesyn', + 'Macyn', + 'Riyah', + 'Alleigh', + 'Aracelli', + 'Hadlie', + 'Iza', + 'Riddhi', + 'Kathleene', + 'Darely', + 'Eleyna', + 'Analiya', + 'Fanchon', + 'Allyce', + 'Jasma', + 'Porschia', + 'Deberah', + 'Zoi', + 'Sherlyne', + 'Favour', + 'Shakari', + 'Mckenzy', + 'Makinzie', + 'Maahi', + 'Jacqualine', + 'Nancyann', + 'Ronne', + 'Charmane', + 'Martie', + 'Leane', + 'Kama', + 'Corrinne', + 'Vangie', + 'Jonni', + 'Michon', + 'Sharise', + 'Shawnie', + 'Joane', + 'Rosary', + 'Noretta', + 'Zaylynn', + 'Paislie', + 'Infinity', + 'Amaryllis', + 'Altair', + 'Cookie', + 'Danyella', + 'Collyns', + 'Chrislynn', + 'Bryley', + 'Brelynn', + 'Finleigh', + 'Evianna', + 'Flavia', + 'Wilhemina', + 'Jaeliana', + 'Taija', + 'Naiomi', + 'Jennika', + 'Jenika', + 'Jaicee', + 'Laurice', + 'Ashaunti', + 'Alyxandria', + 'Delfinia', + 'Tyiesha', + 'Petrita', + 'Fedelina', + 'Eufelia', + 'Marshae', + 'Marquesha', + 'Feloniz', + 'Tyliyah', + 'Nadene', + 'Natascha', + 'Shawnette', + 'Jamese', + 'Tashay', + 'Mckenzee', + 'Mckinsey', + 'Langley', + 'Kensleigh', + 'Karolyna', + 'Coralyn', + 'Grethel', + 'Baylei', + 'Ariany', + 'Mekenzie', + 'Whitlee', + 'Sayde', + 'Willena', + 'Tzipporah', + 'Afsana', + 'Kearra', + 'Marialy', + 'Quiara', + 'Jing', + 'Dorathea', + 'Rachelann', + 'Melissaann', + 'Jeanett', + 'Jensine', + 'Jessicaann', + 'Ellesse', + 'Kaula', + 'Calley', + 'Malkie', + 'Shenelle', + 'Sheela', + 'Steffi', + 'Shadia', + 'Marielis', + 'Saima', + 'Tiarah', + 'Reginia', + 'Shaquala', + 'Shadiamond', + 'Kallista', + 'Allee', + 'Allexis', + 'Nakeya', + 'Reshma', + 'Sosha', + 'Kendrea', + 'Imalay', + 'Kyong', + 'Sharmin', + 'Sorah', + 'Alayshia', + 'Katja', + 'Chavie', + 'Farzana', + 'Lanasia', + 'Khayla', + 'Jamella', + 'Diva', + 'Ericca', + 'Brettany', + 'Imunique', + 'Tiasia', + 'Tajae', + 'Sidra', + 'Chelbi', + 'Kourtni', + 'Lamisha', + 'Krystyn', + 'Maly', + 'Mirtha', + 'Nary', + 'Nuria', + 'Falicia', + 'Zilpha', + 'Keyasia', + 'Ranisha', + 'Garnetta', + 'Alexxus', + 'Hae', + 'Herma', + 'Tasheena', + 'Philicia', + 'Fotini', + 'Avanell', + 'Czarina', + 'Kindle', + 'Antoinet', + 'Constanc', + 'Cassondr', + 'Destanee', + 'Christinia', + 'Shalisa', + 'Stepahnie', + 'Sopheap', + 'Somaly', + 'Shalane', + 'Saran', + 'Alaycia', + 'Carolynne', + 'Nikolette', + 'Saphire', + 'Dominigue', + 'Channa', + 'Leva', + 'Starquasia', + 'Shyan', + 'Sabah', + 'Shakiera', + 'Nagely', + 'Hajar', + 'Keniya', + 'Anhthu', + 'Ashle', + 'Taira', + 'Meline', + 'Rebeckah', + 'Daritza', + 'Kaysha', + 'Kathrin', + 'Edit', + 'Jennae', + 'Kaja', + 'Molli', + 'Hildreth', + 'Elyssia', + 'Keandrea', + 'Courtlyn', + 'Cova', + 'Kyndle', + 'Kadisha', + 'Mitchelle', + 'Chabeli', + 'Ashlen', + 'Feiga', + 'Shakena', + 'Lakeia', + 'Jehan', + 'Karianne', + 'Renisha', + 'Crystalyn', + 'Blia', + 'Amanada', + 'Neiba', + 'Oyuki', + 'Lianet', + 'Javaria', + 'Praise', + 'Sagal', + 'Avaleigh', + 'Amoni', + 'Fadumo', + 'Debhora', + 'Sharol', + 'Sahalie', + 'Aleana', + 'Dezire', + 'Catalia', + 'Barbarann', + 'Raelin', + 'Reniyah', + 'Jeniyah', + 'Jaziya', + 'Wilhemenia', + 'Wavie', + 'Modestine', + 'Tariah', + 'Cathern', + 'Asenath', + 'Nakya', + 'Reeva', + 'Tkai', + 'Orva', + 'Theora', + 'Brookie', + 'Breyonna', + 'Ellagrace', + 'Kaliya', + 'Jemimah', + 'Ahna', + 'Zetta', + 'Tanyia', + 'Dicie', + 'Malasia', + 'Janvi', + 'Talaysia', + 'Kaybree', + 'Teia', + 'Robertha', + 'Tilda', + 'Marykatherine', + 'Gusta', + 'Gola', + 'Malta', + 'Nija', + 'Kaija', + 'Tamaria', + 'Chyann', + 'Davianna', + 'Gae', + 'Ruther', + 'Kennadee', + 'Arvella', + 'Ashonti', + 'Euphemia', + 'Teyanna', + 'Jahnya', + 'Jamariya', + 'Ceanna', + 'Francenia', + 'Charletta', + 'Catheryn', + 'Theodosia', + 'Magdaline', + 'Samariah', + 'Jamara', + 'Nehemie', + 'Mikenzie', + 'Marielys', + 'Keilany', + 'Bernardita', + 'Marketa', + 'Takya', + 'Frona', + 'Draxie', + 'Genell', + 'Celesta', + 'Deloria', + 'Sister', + 'Icy', + 'Mardi', + 'Florance', + 'Azari', + 'Ahmiyah', + 'Chaniya', + 'Rheda', + 'Kateland', + 'Rielle', + 'Kjersten', + 'Olivette', + 'Tita', + 'Tharon', + 'Briasia', + 'Pakou', + 'Raniah', + 'Janaria', + 'Jaliya', + 'Alexiana', + 'Alayja', + 'Ailea', + 'Camiya', + 'Versa', + 'Vertell', + 'Loyola', + 'Mckelle', + 'Ebonique', + 'Jaynie', + 'Shamiah', + 'Keela', + 'Laterrica', + 'Fidelia', + 'Annia', + 'Rosslyn', + 'Robynn', + 'Darlynn', + 'Shakiara', + 'Shakeira', + 'Olinda', + 'Kionna', + 'Annslee', + 'Rudine', + 'Teonna', + 'Rudene', + 'Latrece', + 'Wynette', + 'Damiya', + 'Zonnie', + 'Jenne', + 'Deeanne', + 'Doree', + 'Jennilyn', + 'Lari', + 'Lourie', + 'Tedi', + 'Deaira', + 'Deairra', + 'Fatuma', + 'Gearldean', + 'Genise', + 'Karlyn', + 'Arleta', + 'Alla', + 'Donie', + 'Lady', + 'Rheba', + 'Nuha', + 'Olita', + 'Elzina', + 'Lutricia', + 'Tauna', + 'Teasha', + 'Elberta', + 'Jeralyn', + 'Shaketa', + 'Elonda', + 'Lafondra', + 'Shelle', + 'Lamiya', + 'Lejla', + 'Labria', + 'Wessie', + 'Cleola', + 'Suad', + 'Andretta', + 'Piccola', + 'Jadalee', + 'Louanna', + 'Donabelle', + 'Shauntel', + 'Vannie', + 'Naomia', + 'Ludell', + 'Ikram', + 'Ariyonna', + 'Anaelle', + 'Pamila', + 'Scheryl', + 'Kandee', + 'Donella', + 'Vicie', + 'Tajah', + 'Jodeen', + 'Debborah', + 'Varvara', + 'Jalisha', + 'Paw', + 'Tranette', + 'Ruwayda', + 'Jeanice', + 'Lowana', + 'Curlie', + 'Viveca', + 'Tommi', + 'Lynnel', + 'Shawneen', + 'Tora', + 'Ikhlas', + 'Delene', + 'Jillyn', + 'Abria', + 'Blondine', + 'Katharyn', + 'Gini', + 'Lynnell', + 'Laurey', + 'Ikran', + 'Madell', + 'Dura', + 'Trenia', + 'Arsie', + 'Runell', + 'Lawan', + 'Georgeanna', + 'Nashay', + 'Lasha', + 'Michi', + 'Arloa', + 'Kazuye', + 'Arnette', + 'Morghan', + 'Allure', + 'Kiyo', + 'Fusaye', + 'Sebrena', + 'Kikuye', + 'Mykia', + 'Soon', + 'Kyung', + 'Maysa', + 'Manessa', + 'Ople', + 'Amyre', + 'Katera', + 'Danaya', + 'Dorothey', + 'Shahidah', + 'Soliana', + 'Concettina', + 'Delphie', + 'Aqueelah', + 'Cassadee', + 'Larayne', + 'Burnette', + 'Diona', + 'Stasha', + 'Sheria', + 'Luciel', + 'Anise', + 'Cumi', + 'Marillyn', + 'Domenique', + 'Sumiye', + 'Masaye', + 'Imojean', + 'Louetta', + 'Taimi', + 'Berdie', + 'Jyl', + 'Cyrilla', + 'Kearstin', + 'Tosca', + 'Billee', + 'Milda', + 'Rema', + 'Tyne', + 'Altamease', + 'Aleaha', + 'Malaina', + 'Jersie', + 'Nadyne', + 'Suhailah', + 'Reghan', + 'Burma', + 'Kamyra', + 'Geraldean', + 'Ivalee', + 'Waunita', + 'Aritza', + 'Madalynne', + 'Talaya', + 'Azura', + 'Aldonia', + 'Robinette', + 'Ameenah', + 'Abeer', + 'Yamilette', + 'Tanae', + 'Mertha', + 'Jamirah', + 'Chun', + 'Avayah', + 'Janayah', + 'Bena', + 'Mahiyah', + 'Karn', + 'Kristien', + 'Mikesha', + 'Eriel', + 'Kemoni', + 'Aziya', + 'Raigan', + 'Rissie', + 'Tenna', + 'Tambria', + 'Birdell', + 'Almena', + 'Jonisha', + 'Marcey', + 'Rosebud', + 'Lakevia', + 'Shateria', + 'Nelia', + 'Rilda', + 'Doshie', + 'Onzell', + 'Safiyyah', + 'Lorilee', + 'Shiane', + 'Gauri', + 'Ashiya', + 'Yaileen', + 'Vendetta', + 'Margaretmary', + 'Telisa', + 'Imogean', + 'Sheryn', + 'Nance', + 'Mariette', + 'Keerthana', + 'Rosellen', + 'Michelene', + 'Kamrie', + 'Mayci', + 'Jerzi', + 'Vermelle', + 'Tondra', + 'Dorethea', + 'Wannetta', + 'Tilly', + 'Brightyn', + 'Patt', + 'Lynae', + 'Willo', + 'Cloma', + 'Yailyn', + 'Takeria', + 'Janyiah', + 'Rasheema', + 'Nafeesa', + 'Rosene', + 'Kellianne', + 'Taccara', + 'Quanda', + 'Patsie', + 'Chaquita', + 'Shakelia', + 'Guerline', + 'Tashika', + 'Taneesha', + 'Fatme', + 'Marliss', + 'Hye', + 'Marjo', + 'Meggie', + 'Maye', + 'Walline', + 'Dodi', + 'Kristyna', + 'Aliyyah', + 'Latravia', + 'Diania', + 'Elta', + 'Oralee', + 'Nikkita', + 'Rasha', + 'Sharena', + 'Tecora', + 'Pluma', + 'Ovell', + 'Keeya', + 'Dayja', + 'Sherrian', + 'Jinnie', + 'Ekta', + 'Javonda', + 'Shantrice', + 'Dava', + 'Kimbley', + 'Lafonda', + 'Lasonja', + 'Hiilani', + 'Danay', + 'Avree', + 'Kelliann', + 'Keasha', + 'Kimmarie', + 'Jannely', + 'Manasi', + 'Moncerat', + 'Miyu', + 'Jullianna', + 'Joelene', + 'Ynez', + 'Yazmeen', + 'Yasamin', + 'Syann', + 'Surena', + 'Tresia', + 'Trecia', + 'Sonjia', + 'Hokulani', + 'Amarilys', + 'Bethzaida', + 'Noraida', + 'Dietra', + 'Nealie', + 'Charice', + 'Alicea', + 'Jozie', + 'Delzora', + 'Jordis', + 'Jolett', + 'Kahlen', + 'Kallee', + 'Natilee', + 'Pecolia', + 'Iyari', + 'Shandrell', + 'Quintella', + 'Monchel', + 'Tysha', + 'Vanetta', + 'Shawneequa', + 'Odesser', + 'Lareina', + 'Jannifer', + 'Kinya', + 'Lateesha', + 'Dvora', + 'Katrin', + 'Denene', + 'Diondra', + 'Ciclali', + 'Sula', + 'Talena', + 'Afrika', + 'Cheron', + 'Emireth', + 'Cadee', + 'Jlyn', + 'Jermya', + 'Alyia', + 'Sitlali', + 'Sissy', + 'Felita', + 'Kerith', + 'Wendolyn', + 'Chaundra', + 'Angle', + 'Gladies', + 'Meygan', + 'Sereniti', + 'Saryn', + 'Vielka', + 'Tirzah', + 'Lynnmarie', + 'Lisanne', + 'Yliana', + 'Yamilett', + 'Keyoka', + 'Laquanta', + 'Teneshia', + 'Trenna', + 'Veronda', + 'Fronie', + 'Carlette', + 'Lanetta', + 'Raynelle', + 'Tianne', + 'Siria', + 'Mayda', + 'Lorien', + 'Celica', + 'Tabbitha', + 'Kayanna', + 'Julitza', + 'Kylia', + 'Heavenlee', + 'Nikka', + 'Rachana', + 'Mekenna', + 'Maritere', + 'Ai', + 'Angelisa', + 'Anysa', + 'Basia', + 'Ilka', + 'Geanine', + 'Kedra', + 'Caila', + 'Deysy', + 'Emilyann', + 'Samera', + 'Mackinzie', + 'Lynzie', + 'Akela', + 'Navpreet', + 'Reylene', + 'Reyanna', + 'Kathlynn', + 'Kiaira', + 'Guiselle', + 'Brinn', + 'Jerelyn', + 'Lorel', + 'Alandra', + 'Ardyth', + 'Kloee', + 'Mellody', + 'Carlisa', + 'Martinique', + 'Damali', + 'Cassandre', + 'Ivanelle', + 'Janaan', + 'Shontay', + 'Tamieka', + 'Tashema', + 'Irmalinda', + 'Tayna', + 'Berdena', + 'Janika', + 'Shauntay', + 'Nikea', + 'Ekaterini', + 'Glendaly', + 'Vernee', + 'Kang', + 'Candise', + 'Jamica', + 'Andera', + 'Katheleen', + 'Annagrace', + 'Bradleigh', + 'Kissy', + 'Lachandra', + 'Tamikia', + 'Shevon', + 'Wardean', + 'Betina', + 'Marcee', + 'Evia', + 'Carry', + 'Marica', + 'Tiwana', + 'Stacye', + 'Theressa', + 'Torsha', + 'Allayna', + 'Betania', + 'Berania', + 'Claryssa', + 'Clarise', + 'Cassidi', + 'Mehana', + 'Janella', + 'Mackenzy', + 'Kaeleigh', + 'Sanoe', + 'Neysa', + 'Shawntee', + 'Shannah', + 'Tihani', + 'Willye', + 'Zalma', + 'Serrina', + 'Shealyn', + 'Hiiaka', + 'Jeselle', + 'Mitsy', + 'Kela', + 'Aquila', + 'Marikay', + 'Christella', + 'Tameria', + 'Ebelina', + 'Maricar', + 'Shalimar', + 'Yanin', + 'Xuan', + 'Tifany', + 'Thy', + 'Quynh', + 'Shronda', + 'Kysha', + 'Lular', + 'Danee', + 'Christyna', + 'Antonieta', + 'Chara', + 'Bich', + 'Tishana', + 'Sophy', + 'Shoshanna', + 'Adrea', + 'Lavaun', + 'Keryn', + 'Okema', + 'Njeri', + 'Ashaki', + 'Alegra', + 'Anapatricia', + 'Terena', + 'Tuere', + 'Ensley', + 'Geraline', + 'Corrinna', + 'Carlye', + 'Dawnielle', + 'Fancy', + 'Akiba', + 'Korrie', + 'Lavita', + 'Chisa', + 'Lakishia', + 'Mandisa', + 'Lalita', + 'Sakeena', + 'Noami', + 'Olivea', + 'Lucilla', + 'Marialuiza', + 'Radonna', + 'Magaline', + 'Minda', + 'Annah', + 'Mitsuyo', + 'Kameko', + 'Miyako', + 'Satsuki', + 'Hatsuyo', + 'Aimie', + 'Jalexis', + 'Haruyo', + 'Tokiko', + 'Matsuyo', + 'Myiah', + 'Natalye', + 'Priseis', + 'Yeraldi', + 'Natsue', + 'Nobue', + 'Zyria', + 'Tierany', + 'Samyia', + 'Rhema', + 'Chiyo', + 'Lailoni', + 'Momoka', + 'Miku', + 'Havanna', + 'Izela', + 'Kendy', + 'Rashanda', + 'Aleysha', + 'Sherlita', + 'Tamana', + 'Kikuyo', + 'Tapanga', + 'Shauntell', + 'Adithi', + 'Chiamaka', + 'Devika', + 'Angy', + 'Arwyn', + 'Aparna', + 'Anneka', + 'Betzayra', + 'Analuiza', + 'Blondie', + 'October', + 'Yarexi', + 'Yarethzi', + 'Annaclaire', + 'Rosabel', + 'Jerlene', + 'Clelia', + 'Jatara', + 'Anzley', + 'Zamaya', + 'Venera', + 'Kalleigh', + 'Jaylynne', + 'Kaylor', + 'Milli', + 'Nelsy', + 'Laycee', + 'Arayah', + 'Betzabe', + 'Bethzi', + 'Haidy', + 'Chayla', + 'Elizah', + 'Evoleth', + 'Edyn', + 'Cyniah', + 'December', + 'Amerika', + 'Analea', + 'Ayshia', + 'Alauna', + 'Shamica', + 'Peaches', + 'Shenee', + 'Letecia', + 'Arminda', + 'Yolander', + 'Amariona', + 'Kaithlyn', + 'Jasiya', + 'Niharika', + 'Sareena', + 'Maryana', + 'Melanye', + 'Solei', + 'Suhey', + 'Soyla', + 'Koral', + 'Lilee', + 'Mercede', + 'Pennye', + 'Yumeka', + 'Mazel', + 'Vani', + 'Pattiann', + 'Shirell', + 'Carmencita', + 'Delayla', + 'Hailyn', + 'Brena', + 'Daana', + 'Lenise', + 'Ryhanna', + 'Lorely', + 'Tiannah', + 'Zabdi', + 'Kammy', + 'Josslynn', + 'Keilee', + 'Kamrynn', + 'Itza', + 'Jaidy', + 'Cherly', + 'Ladeana', + 'Memory', + 'Maresa', + 'Shauntae', + 'Risha', + 'Ilisa', + 'Debraann', + 'Gavriela', + 'Jenai', + 'Suzzette', + 'Mailani', + 'Leiloni', + 'Manasa', + 'Malin', + 'Faythe', + 'Haylei', + 'Haili', + 'Gwenivere', + 'Jamilette', + 'Naydeline', + 'Sakshi', + 'Nayda', + 'Nuala', + 'Chelsae', + 'Berenize', + 'Bahar', + 'Arpi', + 'Tearra', + 'Metta', + 'Lethia', + 'Akanksha', + 'Danine', + 'Alayne', + 'Jeanann', + 'Loyda', + 'Yamna', + 'Marsela', + 'Jolinda', + 'Leina', + 'Mariane', + 'Kaydince', + 'Etsuko', + 'Tinika', + 'Lashona', + 'Chidinma', + 'Jazell', + 'Derenda', + 'Cylinda', + 'Amaiah', + 'Alyzza', + 'Abbygayle', + 'Tashae', + 'Tesa', + 'Sarra', + 'Tanasha', + 'Latoy', + 'Dawnell', + 'Corinn', + 'Charmain', + 'Odetta', + 'Kimiya', + 'Kiaya', + 'Mairin', + 'Maelani', + 'Halena', + 'Dorianne', + 'Ilia', + 'Cheyenna', + 'Noora', + 'Nareh', + 'Namrata', + 'Sholanda', + 'Sita', + 'Dunia', + 'Betzayda', + 'Analissa', + 'Amulya', + 'Annaka', + 'Anneth', + 'Anaalicia', + 'Noemie', + 'Leni', + 'Robyne', + 'Skyleen', + 'Tiphanie', + 'Belmira', + 'Francelina', + 'Kreindy', + 'Kiri', + 'Kristena', + 'Lawren', + 'Christyn', + 'Deicy', + 'Hollyann', + 'Jamela', + 'Eriko', + 'Sotheary', + 'Lekeshia', + 'Onica', + 'Micole', + 'Marlisa', + 'Aqsa', + 'Bayla', + 'Abigal', + 'Charny', + 'Shaquira', + 'Rabab', + 'Yasemin', + 'Keishla', + 'Donasia', + 'Ellamarie', + 'Darianny', + 'Dahiana', + 'Areeba', + 'Shaquasha', + 'Oneisha', + 'Daicy', + 'Karem', + 'Kymberlee', + 'Kayleena', + 'Katryna', + 'Jessicamae', + 'Gessica', + 'Jameela', + 'Janele', + 'Naylani', + 'Anagabriela', + 'Andraya', + 'Andreanna', + 'Artavia', + 'Alexanderia', + 'Laporche', + 'Laporsche', + 'Folasade', + 'Kirandeep', + 'Davia', + 'Davona', + 'Darbi', + 'Baylea', + 'Sylwia', + 'Glendy', + 'Ivet', + 'Fritzi', + 'Lusero', + 'Marlayna', + 'Marlissa', + 'Leanny', + 'Duaa', + 'Ruchama', + 'Orli', + 'Nabeeha', + 'Maurissa', + 'Shevawn', + 'Shauni', + 'Shellby', + 'Sindi', + 'Taralyn', + 'Tanzania', + 'Sinthia', + 'Ondrea', + 'Nhu', + 'Narine', + 'Naly', + 'Yanett', + 'Temmy', + 'Manar', + 'Maimuna', + 'Arielys', + 'Dalya', + 'Allyse', + 'Mariateresa', + 'Mariade', + 'Lashea', + 'Kimberlyann', + 'Cyntia', + 'Cystal', + 'Elisse', + 'Tonimarie', + 'Nashalie', + 'Shatasia', + 'Teigan', + 'Muntaha', + 'Zlata', + 'Zehra', + 'Shaterra', + 'Leeya', + 'Keysi', + 'Christabel', + 'Alfrieda', + 'Mehgan', + 'Hyacinth', + 'Shley', + 'Caterin', + 'Darnesha', + 'Amaranta', + 'Jazzmen', + 'Kelia', + 'Kassy', + 'Grasiela', + 'Sheindy', + 'Yenty', + 'Tahani', + 'Umme', + 'Mayla', + 'Maryon', + 'Kiyanna', + 'Dezeray', + 'Macaela', + 'Nalley', + 'Mikeisha', + 'Sylvana', + 'Smantha', + 'Virdiana', + 'Afiya', + 'Chanise', + 'Glorimar', + 'Hui', + 'Hendel', + 'Junia', + 'Gioia', + 'Elene', + 'Dorothie', + 'Elynor', + 'Mercades', + 'Arfa', + 'Abiha', + 'Aayat', + 'Amarianna', + 'Raynisha', + 'Pahola', + 'Sarin', + 'Marixa', + 'Shavonna', + 'Tannya', + 'Tijera', + 'Girtha', + 'Tameko', + 'Caresse', + 'Bernyce', + 'Allisha', + 'Branda', + 'Jahmya', + 'Haleema', + 'Hodaya', + 'Samina', + 'Sheva', + 'Theadora', + 'Skylyn', + 'Razan', + 'Somalia', + 'Thalya', + 'Quadasia', + 'Yanil', + 'Arabia', + 'Edina', + 'Briyanna', + 'Verdia', + 'Sehar', + 'Naama', + 'Timberly', + 'Reann', + 'Narissa', + 'Maggy', + 'Marriah', + 'Joua', + 'Kellsie', + 'Kelcy', + 'Evonna', + 'Jacqueleen', + 'Xee', + 'Zaynah', + 'Janique', + 'Jailin', + 'Aniqa', + 'Melana', + 'Mariame', + 'Aundria', + 'Anacaren', + 'Anahid', + 'Jassmine', + 'Keoshia', + 'Keyera', + 'Delmi', + 'Briselda', + 'Carlisha', + 'Brittnei', + 'Clarrisa', + 'Dezerae', + 'Banessa', + 'Ariele', + 'Cherrell', + 'Daissy', + 'Cecila', + 'Jady', + 'Kristelle', + 'Kristinamarie', + 'Korinna', + 'Kortnee', + 'Jasimine', + 'Jahnay', + 'Farhana', + 'Shaliyah', + 'Nemesis', + 'Shakerria', + 'Phoua', + 'Carylon', + 'Ironesha', + 'Lariza', + 'Anesa', + 'Elantra', + 'Deandria', + 'Denecia', + 'Chelsia', + 'Teighlor', + 'Suzannah', + 'Zelene', + 'Zeena', + 'Catriona', + 'Tamarra', + 'Tannaz', + 'Titiana', + 'Briany', + 'Lyana', + 'Maytal', + 'Antanasia', + 'Kierston', + 'Dashia', + 'Ismenia', + 'Annessa', + 'Carolena', + 'Miasia', + 'Mikhaila', + 'Lamiracle', + 'Kassey', + 'Markeshia', + 'Hilarie', + 'Necha', + 'Ziara', + 'Jahniyah', + 'Safiyah', + 'Tanaisha', + 'Shamyra', + 'Laportia', + 'Shavy', + 'Viktoriya', + 'Khrystyne', + 'Kristyne', + 'Juanisha', + 'Jerrika', + 'Channelle', + 'Jacquiline', + 'Rakia', + 'Tamarah', + 'Sarha', + 'Mishelle', + 'Nastasha', + 'Acadia', + 'Brittiney', + 'Mickaela', + 'Natavia', + 'Seryna', + 'Ardene', + 'Special', + 'Simranjit', + 'Marivi', + 'Natassja', + 'Neira', + 'Nikkie', + 'Asiana', + 'Dazhane', + 'Channell', + 'Adryana', + 'Mariluz', + 'Dajia', + 'Breigh', + 'Zelpha', + 'Lataya', + 'Glenny', + 'Sharene', + 'Shaguana', + 'Henrine', + 'Camesha', + 'Birdia', + 'Dynisha', + 'Sherina', + 'Ayde', + 'Danille', + 'Charday', + 'Almadelia', + 'Larena', + 'Charlestine', + 'Suellyn', + 'Marry', + 'Constantina', + 'Tandi', + 'Lacretia', + 'Noralba', + 'Latresha', + 'Latacha', + 'Talynn', + 'Rox', + 'Chasey', + 'Nyia', + 'Alyissa', + 'Karilyn', + 'Shevonne', + 'Genny', + 'Tamicka', + 'Doneisha', + 'Cyrena', + 'Daisia', + 'Ravina', + 'Berdia', + 'Aneesha', + 'Vashti', + 'Latrica', + 'Kennetha', + 'Aarti', + 'Raiza', + 'Elspeth', + 'Kyleen', + 'Ronika', + 'Lyndsy', + 'Jone', + 'Chanta', + 'Serita', + 'Margree', + 'Ruthel', + 'Ruthella', + 'Breunna', + 'Cyann', + 'Atlanta', + 'Danniela', + 'Junita', + 'Floella', + 'Brittane', + 'Avanelle', + 'Priscill', + 'Luvina', + 'Jeneva', + 'Teretha', + 'Clarita', + 'Ilce', + 'Jacqualyn', + 'Justene', + 'Daysia', + 'Taylore', + 'Sadi', + 'Verenis', + 'Shyenne', + 'Toriana', + 'Alvira', + 'Kalah', + 'Rajanee', + 'Reonna', + 'Mariadelaluz', + 'Mychaela', + 'Charnele', + 'Aeisha', + 'Shaquaya', + 'Shaakira', + 'Tayana', + 'Cozetta', + 'Kensey', + 'Jazsmin', + 'Kaitlyne', + 'Hollye', + 'Lavren', + 'Sarit', + 'Shanieka', + 'Margorie', + 'Virgene', + 'Dannia', + 'Clorissa', + 'Breahna', + 'Rayla', + 'Dellanira', + 'Megen', + 'Matalie', + 'Taraneh', + 'Teila', + 'Etter', + 'Cheetara', + 'Shetara', + 'Jamielee', + 'Kariann', + 'Karess', + 'Bea', + 'Leyda', + 'Misa', + 'Mareena', + 'Maisee', + 'Yvonna', + 'Yocelyne', + 'Yilda', + 'Sabrinna', + 'Sirenia', + 'Tyriel', + 'Darrielle', + 'Siedah', + 'Yuko', + 'Stevee', + 'Chrystle', + 'Shaterrica', + 'Janyll', + 'Evelisse', + 'Belkis', + 'Renesmae', + 'Sahily', + 'Zurie', + 'Edelia', + 'Sequoya', + 'Waldine', + 'Marinell', + 'Moya', + 'Lavenia', + 'Liboria', + 'Meliah', + 'Meliyah', + 'Mio', + 'Xitllali', + 'Nare', + 'Oliviah', + 'Mayrani', + 'Sravya', + 'Valeska', + 'Riona', + 'Lashaundra', + 'Phebe', + 'Yeira', + 'Zarai', + 'Ayanah', + 'Kriti', + 'Kaileah', + 'Donata', + 'Jenavee', + 'Daphnee', + 'Gurneet', + 'Emmalie', + 'Rowrenia', + 'Haisley', + 'Harbor', + 'Arilyn', + 'Aubrii', + 'Avielle', + 'Avyn', + 'Bethenny', + 'Arienne', + 'Anyeli', + 'Brilyn', + 'Cataleyah', + 'Chisom', + 'Dalis', + 'Malaiya', + 'Meela', + 'Karsynn', + 'Kaselyn', + 'Kashlyn', + 'Amorette', + 'Lenita', + 'Adabelle', + 'Allisyn', + 'Alyzah', + 'Aaralynn', + 'Avyanna', + 'Aylinn', + 'Bexley', + 'Blakeleigh', + 'Caeli', + 'Chizaram', + 'Avriana', + 'Clarity', + 'Juanelle', + 'Jerelene', + 'Eluteria', + 'Lamerle', + 'Aletheia', + 'Abrie', + 'Adelie', + 'Elleigh', + 'Emmelyn', + 'Emsley', + 'Everlynn', + 'Galileah', + 'Derrica', + 'Keondria', + 'Keneshia', + 'Amberley', + 'Valkyrie', + 'Yazleemar', + 'Maybree', + 'Shloka', + 'Neah', + 'Oluwatomisin', + 'Saydi', + 'Jessalynn', + 'Katalaya', + 'Katniss', + 'Kendalynn', + 'Davionna', + 'Mercie', + 'Danett', + 'Deetya', + 'Dilynn', + 'Dunya', + 'Camyla', + 'Elliotte', + 'Ivee', + 'Jadie', + 'Kyleah', + 'Laelani', + 'Mileah', + 'Nalanie', + 'Nixie', + 'Oviya', + 'Lakecia', + 'Sharnae', + 'Abbagail', + 'Derica', + 'Truly', + 'Tvisha', + 'Vedika', + 'Xiclaly', + 'Syra', + 'Idamae', + 'Dashanti', + 'Neita', + 'Siona', + 'Jourdyn', + 'Analyn', + 'Shamiracle', + 'Daylene', + 'Kadeesha', + 'Malgorzata', + 'Dashay', + 'Else', + 'Pixie', + 'Myleah', + 'Myleen', + 'Nadiah', + 'Sadhana', + 'Samai', + 'Seraphine', + 'Sereen', + 'Sharanya', + 'Simar', + 'Mahlia', + 'Inika', + 'Jennavieve', + 'Genevy', + 'Harshita', + 'Hennessey', + 'Zari', + 'Jamiracle', + 'Loveta', + 'Coleta', + 'Adabella', + 'Alesana', + 'Brinleigh', + 'Azlyn', + 'Braelee', + 'Shaquila', + 'Shanyia', + 'Jamilia', + 'Corlis', + 'Dulcie', + 'Desha', + 'Timya', + 'Rakiya', + 'Tyliah', + 'Taura', + 'Terasha', + 'Gaynel', + 'Roylene', + 'Janecia', + 'Alonda', + 'Tyneisha', + 'Fleurette', + 'Mayleigh', + 'Meklit', + 'Sarenity', + 'Gulianna', + 'Itzayanna', + 'Ivyana', + 'Jazmynn', + 'Esmie', + 'Favor', + 'Kimbella', + 'Shanavia', + 'Yaritzel', + 'Daun', + 'Tykerria', + 'Antoria', + 'Shykemmia', + 'Remona', + 'Lucrezia', + 'Cicily', + 'Aradhya', + 'Esmae', + 'Evah', + 'Jhene', + 'Katalia', + 'Cyrine', + 'Delayza', + 'Eleonor', + 'Arohi', + 'Aseneth', + 'Avarose', + 'Caia', + 'Hulene', + 'Valera', + 'Nasaria', + 'Makesha', + 'Zera', + 'Aahna', + 'Aariyah', + 'Aashvi', + 'Adalene', + 'Annaliyah', + 'Aira', + 'Alaska', + 'Amila', + 'Amour', + 'Kaylinn', + 'Isidora', + 'Marija', + 'Suha', + 'Marigold', + 'Mayzie', + 'Liesel', + 'Darielle', + 'Sapphira', + 'Scotland', + 'Serah', + 'Srinika', + 'Novah', + 'Primrose', + 'Latresa', + 'Theia', + 'Alleen', + 'Agness', + 'Estanislada', + 'Ellouise', + 'Emilija', + 'Glynnis', + 'Paulene', + 'Wilna', + 'Maedell', + 'Lometa', + 'Cressie', + 'Allyne', + 'Calleen', + 'Joaquina', + 'Lashelle', + 'Modene', + 'Jonie', + 'Minta', + 'Milady', + 'Jearlene', + 'Rithika', + 'Simrat', + 'Vonzella', + 'Venna', + 'Pabla', + 'Benilde', + 'Eniya', + 'Shakendra', + 'Ailen', + 'Aina', + 'Marionna', + 'Millette', + 'Emiyah', + 'Kayloni', + 'Keerat', + 'Keeva', + 'Lailany', + 'Mishka', + 'Naevia', + 'Nathania', + 'Nyari', + 'Jayah', + 'Kaavya', + 'Frankee', + 'Anahita', + 'Anella', + 'Elizabella', + 'Damara', + 'Juaquina', + 'Gracia', + 'Rozalyn', + 'Ruhani', + 'Novalie', + 'Mialani', + 'Minka', + 'Nessa', + 'Sissi', + 'Sitara', + 'Jaynee', + 'Jeyla', + 'Gizzelle', + 'Maila', + 'Maizy', + 'Lamaya', + 'Katalea', + 'Khamila', + 'Shekita', + 'Chinita', + 'Anshika', + 'Aerabella', + 'Azelia', + 'Cici', + 'Daleyssa', + 'Divinity', + 'Fermina', + 'Murline', + 'Mattye', + 'Devra', + 'Jakya', + 'Santresa', + 'Larene', + 'Deola', + 'Liliann', + 'Lexxi', + 'Kamori', + 'Myonna', + 'Yitzel', + 'Lindalee', + 'Tira', + 'Mairyn', + 'Riyana', + 'Shaleen', + 'Rhyleigh', + 'Fleeta', + 'Gabrielly', + 'Deajah', + 'Yarielis', + 'Arelie', + 'Amore', + 'Sacoria', + 'Hedda', + 'Wanza', + 'Janyth', + 'Yaslin', + 'Brianah', + 'Anyelin', + 'Shayleigh', + 'Lace', + 'Kurstin', + 'Zakhia', + 'Charvi', + 'Raylie', + 'Nyellie', + 'Natalyn', + 'Libra', + 'Khianna', + 'Jolena', + 'Genevive', + 'Jadine', + 'Deniya', + 'Madysin', + 'Porchia', + 'Layleen', + 'Kemiya', + 'Donesha', + 'Jewelene', + 'Sakari', + 'Narely', + 'Maylyn', + 'Halina', + 'Nelli', + 'Myangel', + 'British', + 'Adore', + 'Alainah', + 'Shadonna', + 'Aminta', + 'Marolyn', + 'Jalea', + 'Breelynn', + 'Carah', + 'Sagrario', + 'Akyra', + 'Kailei', + 'Kenza', + 'Renette', + 'Joanann', + 'Solimar', + 'Semira', + 'Harneet', + 'Jahayra', + 'Evanny', + 'Gyzelle', + 'Nathalee', + 'Dalphine', + 'Mane', + 'Merelyn', + 'Kayliana', + 'Aubryn', + 'Brooklyne', + 'Kimari', + 'Dandra', + 'Cilia', + 'Laren', + 'Denetra', + 'Kandise', + 'Makynli', + 'Janan', + 'Rosalea', + 'Ludean', + 'Syndey', + 'Shaney', + 'Vannary', + 'Reynalda', + 'Rainee', + 'Trishia', + 'Kirbie', + 'Kristyl', + 'Lynzi', + 'Shardai', + 'Yaricza', + 'Tarina', + 'Lynley', + 'Maniah', + 'Arcilia', + 'Keaundra', + 'Karrigan', + 'Madeliene', + 'Lessley', + 'Laurynn', + 'Ragen', + 'Essance', + 'Celsey', + 'Caitlen', + 'Dulse', + 'Sulamita', + 'Evlyn', + 'Dorace', + 'Marciana', + 'Tenecia', + 'Natarsha', + 'Analiza', + 'Ladene', + 'Tatumn', + 'Maricsa', + 'Lysa', + 'Leydi', + 'Limayri', + 'Rebbeca', + 'Amreen', + 'Saina', + 'Remedy', + 'Rael', + 'Nami', + 'Nalini', + 'Naiyah', + 'Moxie', + 'Olina', + 'Whitni', + 'Dayannara', + 'Diara', + 'Arma', + 'Giorgia', + 'Evee', + 'Bricia', + 'Brizeyda', + 'Chihiro', + 'Ayram', + 'Ayushi', + 'Isolde', + 'Husna', + 'Khrystal', + 'Kriston', + 'Raylena', + 'Porschea', + 'Samanthia', + 'Mylinda', + 'Ginelle', + 'Coreena', + 'Aryel', + 'Mallary', + 'Maciel', + 'Kursten', + 'Leandrea', + 'Mackensie', + 'Camri', + 'Itzamara', + 'Aryiah', + 'Alayssa', + 'Andreah', + 'Anberlin', + 'Amrie', + 'Breah', + 'Ryane', + 'Tonna', + 'Valisa', + 'Adryanna', + 'Ajia', + 'Robynne', + 'Brystal', + 'Brylynn', + 'Kaleigha', + 'Danyka', + 'Dannica', + 'Caylen', + 'Jonier', + 'Ruthy', + 'Mada', + 'Vaida', + 'Yeila', + 'Zoelle', + 'Elzora', + 'Samreen', + 'Seylah', + 'Sayla', + 'Allina', + 'Stellarose', + 'Starlett', + 'Simrit', + 'Shina', + 'Bernestine', + 'Tranisha', + 'Tiffanyann', + 'Adamarys', + 'Tylyn', + 'Shahrzad', + 'Addisson', + 'Aeriana', + 'Alaiya', + 'Anni', + 'Ariely', + 'Anvika', + 'Aneya', + 'Bani', + 'Ayame', + 'Ayaka', + 'Aviella', + 'Alabama', + 'Adalyne', + 'Teresea', + 'Ishana', + 'Hargun', + 'Jasnoor', + 'Deby', + 'Dannelle', + 'Swetha', + 'Catherina', + 'Bridgitt', + 'Birgit', + 'Calisi', + 'Defne', + 'Delsa', + 'Demiyah', + 'Cataleah', + 'Icel', + 'Ixel', + 'Jazman', + 'Jessicamarie', + 'Desaree', + 'Chika', + 'Estephani', + 'Dilcia', + 'Dartha', + 'Lesieli', + 'Breyona', + 'Waynette', + 'Verma', + 'Calletana', + 'Cherisa', + 'Casara', + 'Jil', + 'Shella', + 'Renell', + 'Venise', + 'Loura', + 'Kaylia', + 'Leileen', + 'Jessel', + 'Janesa', + 'Kaelly', + 'Julina', + 'Joselinne', + 'Juna', + 'Hazelle', + 'Mauricia', + 'Octaviana', + 'Rumalda', + 'Kataleyah', + 'Kimela', + 'Mosella', + 'Delone', + 'Shemekia', + 'Balinda', + 'Hazell', + 'Deboraha', + 'Gizell', + 'Camilia', + 'Avalina', + 'Audreyana', + 'Baran', + 'Genesee', + 'Elyzabeth', + 'Eliya', + 'Kathyleen', + 'Deeksha', + 'Scherry', + 'Angelyne', + 'Amiliana', + 'Amaira', + 'Jeani', + 'Alysen', + 'Alania', + 'Adiana', + 'Chinyere', + 'Lamesha', + 'Keiley', + 'Lanea', + 'Rosely', + 'Surabhi', + 'Dyanne', + 'Mallika', + 'Tabbatha', + 'Shilpa', + 'Morgyn', + 'Narali', + 'Jenevie', + 'Lovette', + 'Nayleah', + 'Navi', + 'Meili', + 'Nazly', + 'Nethra', + 'Earlee', + 'Layloni', + 'Kiannah', + 'Lilyanah', + 'Liannah', + 'Jaylenn', + 'Jiayi', + 'Kattleya', + 'Kanna', + 'Jimin', + 'Kaleesi', + 'Kailia', + 'Itzy', + 'Itzela', + 'Jasminemarie', + 'Malynda', + 'Jeweline', + 'Eloiza', + 'Carolin', + 'Helma', + 'Arlyle', + 'Giannina', + 'Constancia', + 'Elyce', + 'Montoya', + 'Marline', + 'Krystale', + 'Maghan', + 'Laquitta', + 'Elishia', + 'Aliciana', + 'Maralee', + 'Brunetta', + 'Cybil', + 'Dannell', + 'Cherene', + 'Agueda', + 'Guillerma', + 'Haillie', + 'Bobbe', + 'Gesselle', + 'Esthefany', + 'Sian', + 'Ouita', + 'Sasheen', + 'Abigaile', + 'Demarie', + 'Edwena', + 'Aamiyah', + 'Breaunna', + 'Bryssa', + 'Catlyn', + 'Xaviera', + 'Sierria', + 'Skyelar', + 'Aujanae', + 'Rika', + 'Roshelle', + 'Roxsana', + 'Zonia', + 'Tifanie', + 'Thavy', + 'Teala', + 'Tanea', + 'Loukisha', + 'Melita', + 'Keiona', + 'Maryfer', + 'Delcenia', + 'Akila', + 'Gwenevere', + 'Obdulia', + 'Texana', + 'Licette', + 'Larina', + 'Lany', + 'Yailine', + 'Yomara', + 'Zavia', + 'Sydne', + 'Mariadelourdes', + 'Margeaux', + 'Daneille', + 'Doni', + 'Donalee', + 'Darilyn', + 'Jennfier', + 'Jeanny', + 'Haliegh', + 'Dymon', + 'Callee', + 'Cydni', + 'Daesha', + 'Tamila', + 'Tresha', + 'Mckennah', + 'Shouana', + 'Xcaret', + 'Yeneisy', + 'Yumalai', + 'Ziana', + 'Hanny', + 'Shanisha', + 'Nissi', + 'Mirabel', + 'Miarose', + 'Valerya', + 'Rosalin', + 'Saliha', + 'Samayah', + 'Smriti', + 'Jozette', + 'Gari', + 'Jeanell', + 'Dyann', + 'Vonna', + 'Velina', + 'Salli', + 'Nonie', + 'Olena', + 'Camela', + 'Eufracia', + 'Ethelyne', + 'Yuhan', + 'Silveria', + 'Silvestra', + 'Thressa', + 'Tiahna', + 'Vasti', + 'Calee', + 'Florentine', + 'Sherre', + 'Almira', + 'Zitlalli', + 'Vianne', + 'Yaribeth', + 'Yarelie', + 'Robbye', + 'Jasminne', + 'Sophiah', + 'Saryah', + 'Hermalinda', + 'Sinclaire', + 'Korissa', + 'Lanee', + 'Keeana', + 'Parlee', + 'Luceal', + 'Jetta', + 'Mairani', + 'Tameisha', + 'Haruna', + 'Chasiti', + 'Leighanne', + 'Anaisabel', + 'Aanchal', + 'Alesa', + 'Annisa', + 'Brigitta', + 'Elideth', + 'Chua', + 'Cherrish', + 'Aleece', + 'Maizee', + 'Navie', + 'Philomene', + 'Jilian', + 'Jesi', + 'Kortnie', + 'Beija', + 'Delissa', + 'Shiree', + 'Silbia', + 'Tamura', + 'Aerianna', + 'Abegail', + 'Braniya', + 'Calyn', + 'Carlynn', + 'Anjana', + 'Angelik', + 'Alyzabeth', + 'Amorie', + 'Joannamarie', + 'Kerissa', + 'Kennesha', + 'Laruen', + 'Korrina', + 'Felisitas', + 'Gilma', + 'Essica', + 'Gerarda', + 'Petronila', + 'Dorotea', + 'Maguadalupe', + 'Najla', + 'Loana', + 'Illyana', + 'Amunique', + 'Antwanette', + 'Krystan', + 'Shaniquia', + 'Shanequia', + 'Rainy', + 'Raynesha', + 'Shayleen', + 'Stephanee', + 'Sharaya', + 'Nikkole', + 'Cecille', + 'Christyne', + 'Auriel', + 'Franki', + 'Zelina', + 'Deshanae', + 'Deshawna', + 'Tyneshia', + 'Tyrisha', + 'Deangela', + 'Dynasia', + 'Maigan', + 'Jericka', + 'Jackalyn', + 'Kayln', + 'Ceslie', + 'Bethaney', + 'Samanvi', + 'Saidee', + 'Rosibel', + 'Spirit', + 'Srishti', + 'Varnika', + 'Vanshika', + 'Rosha', + 'Rheya', + 'Yoyo', + 'Veyda', + 'Weslyn', + 'Palak', + 'Sieanna', + 'Riannah', + 'Lovetta', + 'Lota', + 'Florice', + 'Hortence', + 'Zuley', + 'Zoejane', + 'Zemira', + 'Mineola', + 'Senona', + 'Concepsion', + 'Conrada', + 'Dardanella', + 'Rhina', + 'Rubicela', + 'Raissa', + 'Porchea', + 'Latiana', + 'Landy', + 'Monee', + 'Maritssa', + 'Marjani', + 'Meosha', + 'Cecilie', + 'Britanie', + 'Brandilyn', + 'Khrystina', + 'Atenas', + 'Kristeena', + 'Kristell', + 'Kristianne', + 'Angelicia', + 'Alexandera', + 'Jaimy', + 'Jeneffer', + 'Hayde', + 'Vickye', + 'Suzzanne', + 'Susi', + 'Sherrilyn', + 'Sanda', + 'Janeal', + 'Stephnie', + 'Luwana', + 'Shenae', + 'Yaris', + 'Marzell', + 'Lashane', + 'Liandra', + 'Keionna', + 'Korri', + 'Marlet', + 'Marytza', + 'Lorraina', + 'Deepika', + 'Devi', + 'Fion', + 'Darrah', + 'Dalisha', + 'Karessa', + 'Karrisa', + 'Kasara', + 'Ismar', + 'Jacquilyn', + 'Janica', + 'Jeannett', + 'Samanatha', + 'Samra', + 'Sayda', + 'Breklyn', + 'Ashika', + 'Bita', + 'Allysha', + 'Areil', + 'Arlenne', + 'Artelia', + 'Janicia', + 'Corinthia', + 'Angellica', + 'Maygen', + 'Maygan', + 'Odelle', + 'Wenonah', + 'Perfecta', + 'Anjelika', + 'Solmaira', + 'Fredonia', + 'Burgandy', + 'Chelcee', + 'Kellsey', + 'Lyann', + 'Jazmon', + 'Ardie', + 'Latunya', + 'Benetta', + 'Delphina', + 'Ortensia', + 'Obelia', + 'Lurene', + 'Refujia', + 'Noriko', + 'Ladelle', + 'Lella', + 'Shanie', + 'Shawndra', + 'Zell', + 'Zela', + 'Wenda', + 'Troylene', + 'Merrilyn', + 'Kapri', + 'Timesha', + 'Gwendlyn', + 'Jenean', + 'Lamona', + 'Ladana', + 'Cina', + 'Cybele', + 'Eugina', + 'Anjeanette', + 'Vana', + 'Jeneal', + 'Cherlene', + 'Railee', + 'Palin', + 'Yuliet', + 'Rechelle', + 'Sherisse', + 'Pollyanna', + 'Tiphani', + 'Tiffanee', + 'Vanisha', + 'Yurico', + 'Junko', + 'Shannell', + 'Shalise', + 'Kimberlina', + 'Kerra', + 'Shantee', + 'Emmelia', + 'Micala', + 'Lexxus', + 'Candiss', + 'Chauntel', + 'Alese', + 'Margit', + 'Any', + 'Ambur', + 'Chrysta', + 'Janese', + 'Jinny', + 'Zaydee', + 'Makisha', + 'Carola', + 'Marjan', + 'Samanth', + 'Shaquinta', + 'Polette', + 'Riane', + 'Nitasha', + 'Kasarah', + 'Jillianne', + 'Keidra', + 'Karrah', + 'Kaytie', + 'Sondi', + 'Swayzie', + 'Laporcha', + 'Bridgit', + 'Chanika', + 'Antoniette', + 'Jessicia', + 'Francies', + 'Kaizley', + 'Negin', + 'Mistica', + 'Lorenia', + 'Kalise', + 'Kynslie', + 'Dene', + 'Jizel', + 'Jinger', + 'Jayli', + 'Jariya', + 'Joelynn', + 'Haylin', + 'Isabellah', + 'Ciria', + 'Dealva', + 'Barbarita', + 'Prudencia', + 'Wanna', + 'Marieli', + 'Madisynn', + 'Madalyne', + 'Artisha', + 'Everlyn', + 'Cyerra', + 'Liezl', + 'Kabao', + 'Karmina', + 'Kashmir', + 'Nani', + 'Mithra', + 'Mishika', + 'Milynn', + 'Mehr', + 'Marybella', + 'Maisey', + 'Maddy', + 'Lyah', + 'Marnee', + 'Machele', + 'Ladona', + 'Lorilei', + 'Liara', + 'Alahni', + 'Analaya', + 'Amalya', + 'Alyannah', + 'Aayla', + 'Aarini', + 'Arliz', + 'Cyra', + 'Asenet', + 'Avy', + 'Avaree', + 'Ciela', + 'Evangelyn', + 'Kaidynce', + 'Isella', + 'Ilaria', + 'Kattaleya', + 'Laveah', + 'Lareen', + 'Lanah', + 'Deema', + 'Hannaley', + 'Fiora', + 'Eviana', + 'Ellieana', + 'Elisabetta', + 'Dejanira', + 'Manaia', + 'Malibu', + 'Charlsey', + 'Kaytee', + 'Kinberly', + 'Cinderella', + 'Miana', + 'Kimm', + 'Koni', + 'Eraina', + 'Dory', + 'Deette', + 'Nysa', + 'Nyima', + 'Nikitha', + 'Anasophia', + 'Alissandra', + 'Alisi', + 'Corynn', + 'Aubreyana', + 'Anjani', + 'Oliana', + 'Nura', + 'Nihira', + 'Loveda', + 'Gayathri', + 'Kleigh', + 'Ladaisha', + 'Ilette', + 'Jillene', + 'Jalina', + 'Izellah', + 'Tiaira', + 'Mickala', + 'Macarena', + 'Rubina', + 'Shadow', + 'Emillie', + 'Morine', + 'Novell', + 'Oletta', + 'Pura', + 'Winna', + 'Synia', + 'Shyloh', + 'Kaizlee', + 'Raley', + 'Merly', + 'Na', + 'Yenia', + 'Shayanne', + 'Raeana', + 'Tiauna', + 'Tanairy', + 'Georganna', + 'Mahsa', + 'Maiquel', + 'Korena', + 'Yamel', + 'Shamonica', + 'Romesha', + 'Terrisha', + 'Hannan', + 'Hillarie', + 'Feliza', + 'Courtny', + 'Lyndsee', + 'Katelan', + 'Lakedra', + 'Elisabel', + 'Cynthya', + 'Dannah', + 'Darienne', + 'Dejanique', + 'Madalin', + 'Makynzi', + 'Gwendolynn', + 'Alaine', + 'Bridney', + 'Kimorah', + 'Klee', + 'Kynedi', + 'Loreley', + 'Parthenia', + 'Aubryana', + 'Aryannah', + 'Edeline', + 'Elen', + 'Raguel', + 'Marizela', + 'Michella', + 'Haasini', + 'Tristine', + 'Elis', + 'Pattye', + 'Tanishia', + 'Jenel', + 'Jurea', + 'Laini', + 'Britania', + 'Christabelle', + 'Dafney', + 'Laterica', + 'Angelmarie', + 'Asuzena', + 'Aleea', + 'Teneka', + 'Yicel', + 'Malisha', + 'Prairie', + 'Makelle', + 'Shaelee', + 'Dafina', + 'Hisaye', + 'Adayah', + 'Alexsia', + 'Allysen', + 'Takako', + 'Thamara', + 'Trinitie', + 'Shaneen', + 'Sueellen', + 'Telma', + 'Meyah', + 'Rorie', + 'Preslea', + 'Elbia', + 'Ginna', + 'Marja', + 'Marites', + 'Neisha', + 'Shir', + 'Shastelyn', + 'Saraih', + 'Unity', + 'Makinna', + 'Franchelle', + 'Azadeh', + 'Charito', + 'Joli', + 'Amyrah', + 'Sharlee', + 'Jasey', + 'Kortlynn', + 'Kiari', + 'Kyria', + 'Eleina', + 'Elany', + 'Daleah', + 'Sumi', + 'Kileigh', + 'Lorianna', + 'Macady', + 'Naviah', + 'Mattilyn', + 'Raylyn', + 'Bridgitte', + 'Hasina', + 'Johnelle', + 'Gwendlyon', + 'Itxel', + 'Iyanah', + 'Jeidy', + 'Jaidynn', + 'Jaslynne', + 'Zoii', + 'Tensley', + 'Yolando', + 'Keyarah', + 'Keyri', + 'Katherinne', + 'Thersa', + 'Sinahi', + 'Secret', + 'Vivika', + 'Yobana', + 'Hailley', + 'Haliey', + 'Isys', + 'Deyla', + 'Kassidee', + 'Jalie', + 'Florestela', + 'Cyla', + 'Samyuktha', + 'Libni', + 'Laritza', + 'Breannah', + 'Breya', + 'Keelin', + 'Jarelly', + 'Jenyfer', + 'Julyanna', + 'Kaetlyn', + 'Mixtli', + 'Mykaila', + 'Nasia', + 'Judieth', + 'Misako', + 'Bre', + 'Shaley', + 'Gelila', + 'Aariana', + 'Laquetta', + 'Shizu', + 'Annay', + 'Annai', + 'Breeze', + 'Mahum', + 'Harsimran', + 'Helaina', + 'Alexza', + 'Tangelia', + 'Shellye', + 'Blondena', + 'Keva', + 'Suzzane', + 'Vallorie', + 'Absidy', + 'Alis', + 'Alexxia', + 'Allura', + 'Ariba', + 'Annete', + 'Anett', + 'Deyanara', + 'Ellise', + 'Majorie', + 'Hibah', + 'Chaselyn', + 'Hennesy', + 'Gayatri', + 'Kathelyn', + 'Caylah', + 'Athyna', + 'Arpita', + 'Ciclaly', + 'Emmamarie', + 'Virjinia', + 'Tyna', + 'Cyd', + 'Glennda', + 'Littie', + 'Orlean', + 'Derinda', + 'Hether', + 'Clata', + 'Pleshette', + 'Maricelda', + 'Charmin', + 'Matsuye', + 'Tamitha', + 'Armanda', + 'Sayaka', + 'Lacresia', + 'Demonica', + 'Skie', + 'Trynity', + 'Sereena', + 'Shefali', + 'Rewa', + 'Reshonda', + 'Yalanda', + 'Anissia', + 'Layni', + 'Paolina', + 'Manaal', + 'Mariali', + 'Merina', + 'Milenia', + 'Millenia', + 'Moncerrath', + 'Monzerrath', + 'Kaydie', + 'Adianna', + 'Toluwalase', + 'Trysta', + 'Ainsleigh', + 'Alianah', + 'Meuy', + 'Meloney', + 'Talea', + 'Sheetal', + 'Shalana', + 'Venesa', + 'Teana', + 'Kiki', + 'Imee', + 'Aubryanna', + 'Allyanna', + 'Ambrie', + 'Amory', + 'Aniyha', + 'Caelynn', + 'Reita', + 'Rylann', + 'Aijah', + 'Aaliyha', + 'Alezandra', + 'Yeraldine', + 'Forestine', + 'Sameeha', + 'Caeley', + 'Britzy', + 'Blessin', + 'Armilda', + 'Birda', + 'Lorrine', + 'Krisalyn', + 'Linell', + 'Maryl', + 'Karole', + 'Maryela', + 'Mckinzy', + 'Madailein', + 'Kendi', + 'Kayda', + 'Jenasis', + 'Madelis', + 'Jamyiah', + 'Gabryela', + 'Catie', + 'Genessa', + 'Jamelia', + 'Jenene', + 'Nicholl', + 'Saralyn', + 'Taylah', + 'Xandra', + 'Jezlyn', + 'Zakayla', + 'Jaira', + 'Veena', + 'Shaden', + 'Sahiti', + 'Sahian', + 'Shelsey', + 'Sreya', + 'Zianna', + 'Angeleah', + 'Camily', + 'Lesvia', + 'Sonda', + 'Franceska', + 'Cytlaly', + 'Ylonda', + 'Issis', + 'Moon', + 'Joei', + 'Mariposa', + 'Ramandeep', + 'Preeti', + 'Niobe', + 'Sherran', + 'Nichola', + 'Letrice', + 'Waneda', + 'Meka', + 'Takeshia', + 'Leaann', + 'Girlie', + 'Olar', + 'Pearlena', + 'Carlean', + 'Dhanya', + 'Chastelin', + 'Aryanah', + 'Brihana', + 'Bijou', + 'Haifa', + 'Genesiss', + 'Genavie', + 'Enna', + 'Jazzel', + 'Japleen', + 'Iana', + 'Rahel', + 'Rylyn', + 'Pragya', + 'Yosselyn', + 'Yarelin', + 'Ellasyn', + 'Charlaine', + 'Zayli', + 'Taide', + 'Jodean', + 'Emilynn', + 'Channon', + 'Carinne', + 'Anaira', + 'Amisadai', + 'Caraline', + 'Danella', + 'Debanhy', + 'Devanee', + 'Koneta', + 'Jenie', + 'Hollee', + 'Marelie', + 'Mahathi', + 'Madilynne', + 'Lylia', + 'Loreli', + 'Lolah', + 'Lexine', + 'Maylynn', + 'Clarinda', + 'Marlynn', + 'Netra', + 'Makaylin', + 'Naira', + 'Naleah', + 'Mishel', + 'Myli', + 'Charlotta', + 'Arlisa', + 'Kaylynne', + 'Kamillah', + 'Ksenia', + 'Briseidy', + 'Aysel', + 'Anaily', + 'Eulean', + 'Adilee', + 'Abri', + 'Aidynn', + 'Alisyn', + 'Alicen', + 'Marveline', + 'Lupie', + 'Mariabelen', + 'Makenah', + 'Kyliegh', + 'Foye', + 'Yajahira', + 'Trenda', + 'Tya', + 'Nattaly', + 'Netanya', + 'Supriya', + 'Teja', + 'Srija', + 'Sherra', + 'Janissa', + 'Mysha', + 'Essfa', + 'Alexandrya', + 'Abi', + 'Takhia', + 'Jaeli', + 'Jaelynne', + 'Dianey', + 'Denisa', + 'Aleli', + 'Akina', + 'Aayushi', + 'Adanna', + 'Aunika', + 'Ithzel', + 'Caricia', + 'Kallyn', + 'Karmin', + 'Kindall', + 'Gredmarie', + 'Peace', + 'Jennalee', + 'Yaindhi', + 'Arcola', + 'Trannie', + 'Lyza', + 'Mackynzie', + 'Peggye', + 'Zenab', + 'Megyn', + 'Navina', + 'Naileah', + 'Maddelyn', + 'Luxe', + 'Arkie', + 'Belvia', + 'Edilia', + 'Monda', + 'Ridhi', + 'Peyten', + 'Sorayah', + 'Syrena', + 'Amberle', + 'Johnita', + 'Jerrye', + 'Alfa', + 'Jonita', + 'Lakie', + 'Jenalee', + 'Minami', + 'Morena', + 'Elsbeth', + 'Sylia', + 'Eunique', + 'Ellisa', + 'Lanai', + 'Jesselyn', + 'Jolissa', + 'Julizza', + 'Laquitha', + 'Jobina', + 'Wyvonne', + 'Shalese', + 'Deshannon', + 'Almendra', + 'Alisandra', + 'Geraldene', + 'Abygale', + 'Katelyne', + 'Kennede', + 'Karisia', + 'Lindzy', + 'Keyhla', + 'Emilea', + 'Dacey', + 'Jalah', + 'Adrienna', + 'Aisa', + 'Alaisha', + 'Brithney', + 'Calynn', + 'Cassity', + 'Brendy', + 'Reagen', + 'Myrah', + 'Montserrath', + 'Pheobe', + 'Nyeli', + 'Jocell', + 'Serenidy', + 'Issabela', + 'Hanalei', + 'Laelah', + 'Emmylou', + 'Geraldy', + 'Ovetta', + 'Analena', + 'Allyna', + 'Aliyanah', + 'Magdalyn', + 'Suann', + 'Ronee', + 'Amey', + 'Chirstina', + 'Trude', + 'Jearldine', + 'Maeleigh', + 'Lizzy', + 'Liviana', + 'Eithel', + 'Meryem', + 'Yaneisy', + 'Shatika', + 'Zeniyah', + 'Xaylee', + 'Pennelope', + 'Xochilth', + 'Jullie', + 'Saki', + 'Shaiann', + 'Haille', + 'Dannya', + 'Kerie', + 'Chianti', + 'Leza', + 'Koreen', + 'Letricia', + 'Lamanda', + 'Kinza', + 'Marisella', + 'Joelyn', + 'Cinde', + 'Chyrl', + 'Cece', + 'Boni', + 'Felecity', + 'Faithe', + 'Delayna', + 'Diamon', + 'Daley', + 'Darah', + 'France', + 'Kolina', + 'Kieu', + 'Grizel', + 'Shaleigh', + 'Shaylea', + 'Anitza', + 'Carrolyn', + 'Olimpia', + 'Jeannene', + 'Victoriana', + 'Azara', + 'Avelynn', + 'Aveah', + 'Ariam', + 'Devanie', + 'Daleisa', + 'Karelly', + 'Karalynn', + 'Keyleen', + 'Kendallyn', + 'Graceyn', + 'Falynn', + 'Evoleht', + 'Everlie', + 'Emri', + 'Hartlee', + 'Eleena', + 'Jailee', + 'Insiya', + 'Analysia', + 'Chalee', + 'Amzie', + 'Amilya', + 'Celisa', + 'Airabella', + 'Laketha', + 'Kyoko', + 'Saria', + 'Neli', + 'Melonee', + 'Neidy', + 'Nyanza', + 'Aizlynn', + 'Arthurine', + 'Mikhaela', + 'Adalae', + 'Parveen', + 'Lotoya', + 'Evanjelina', + 'Deborra', + 'Lunna', + 'Makylah', + 'Mckinleigh', + 'Mayalen', + 'Ladasia', + 'Javia', + 'Evian', + 'Jaelee', + 'Oluwatamilore', + 'Payzlee', + 'Reiley', + 'Samarra', + 'Chyler', + 'Areona', + 'Vanesha', + 'Tomisha', + 'Betzaira', + 'Dalana', + 'Destenie', + 'Brennah', + 'Cassidie', + 'Deziray', + 'Dimond', + 'Braeleigh', + 'Aylee', + 'Anastyn', + 'Amillia', + 'Jailyne', + 'Jissell', + 'Jailenne', + 'Inioluwa', + 'Jensyn', + 'Allia', + 'Evolett', + 'Emmalynne', + 'Emberlee', + 'Emaline', + 'Ellayna', + 'Kollins', + 'Keyly', + 'Livi', + 'Judeen', + 'Eleah', + 'Vonceil', + 'Kaaliyah', + 'Girtie', + 'Gianelle', + 'Iniya', + 'Harlynn', + 'Greidy', + 'Shayli', + 'Belina', + 'Auri', + 'Avangeline', + 'Alizey', + 'Arlynn', + 'Anelise', + 'Aneli', + 'Delmira', + 'Vanassa', + 'Ceana', + 'Ambre', + 'Florita', + 'Balbina', + 'Clova', + 'Danice', + 'Aydee', + 'Carlena', + 'Benicia', + 'Soumya', + 'Lissandra', + 'Ling', + 'Liahna', + 'Leonna', + 'Leilana', + 'Reeya', + 'Krisinda', + 'Maleiah', + 'Maiyah', + 'Mailin', + 'Lucciana', + 'Naydeen', + 'Nailani', + 'Miette', + 'Yeva', + 'Suley', + 'Shravya', + 'Kyia', + 'Shree', + 'Cerise', + 'Katriana', + 'Jaskiran', + 'Mone', + 'Latijera', + 'Rosicela', + 'Sidnee', + 'Rosisela', + 'Troi', + 'Victorya', + 'Creasie', + 'Latorsha', + 'Erienne', + 'Jovonna', + 'Jessia', + 'Jeny', + 'Dejia', + 'Destynie', + 'Barbi', + 'Marlinda', + 'Shakeitha', + 'Mistelle', + 'Ziona', + 'Zarahi', + 'Xiadani', + 'Zyrah', + 'Zoriah', + 'Pamla', + 'Cinamon', + 'Bernardette', + 'Makensie', + 'Lexani', + 'Miyana', + 'Costella', + 'Cliffie', + 'Lashune', + 'Windie', + 'Rhondalyn', + 'Avonelle', + 'Marcine', + 'Berneda', + 'Rosabelle', + 'Huldah', + 'Emagene', + 'Clarabell', + 'Marceil', + 'Ula', + 'Renika', + 'Shaterica', + 'Labrittany', + 'Zelia', + 'Aidy', + 'Abeeha', + 'Maebelle', + 'Farzona', + 'Bryelle', + 'Aphrodite', + 'Diyora', + 'Zilphia', + 'Ercell', + 'Starlynn', + 'Renad', + 'Reham', + 'Marwah', + 'Raaina', + 'Mehreen', + 'Chermaine', + 'Ameliah', + 'Hajra', + 'Anamika', + 'Caoimhe', + 'Tasheka', + 'Cladie', + 'Claretta', + 'Ratzy', + 'Parizoda', + 'Tzurty', + 'Simrah', + 'Miamor', + 'Mala', + 'Yittel', + 'Ranata', + 'Clellie', + 'Dewana', + 'Kenyada', + 'Sennie', + 'Estie', + 'Oprah', + 'Chessie', + 'Rumaisa', + 'Rosmery', + 'Shenell', + 'Cosima', + 'Ellyanna', + 'Hebe', + 'Aamira', + 'Beily', + 'Areesha', + 'Amilah', + 'Mahdiya', + 'Ramata', + 'Naava', + 'Cannie', + 'Dorraine', + 'Verlee', + 'Anija', + 'Garnita', + 'Lorenda', + 'Mikia', + 'Marvella', + 'Sharma', + 'Pamula', + 'Anmarie', + 'Valicia', + 'Collene', + 'Ronetta', + 'Floris', + 'Andora', + 'Berdina', + 'Ivadell', + 'Lorain', + 'Kevinisha', + 'Corielle', + 'Rinda', + 'Jodelle', + 'Arta', + 'Kalima', + 'Kalifa', + 'Liat', + 'Dashawna', + 'Jahnae', + 'Eylin', + 'Tahmina', + 'Sherin', + 'Niambi', + 'Tonjua', + 'Hanifah', + 'Maham', + 'Sokhna', + 'Carliss', + 'Nimra', + 'Quianna', + 'Shadai', + 'Renella', + 'Eliska', + 'Alima', + 'Agata', + 'Adenike', + 'Charizma', + 'Shirlean', + 'Joycelin', + 'Cyanne', + 'Ambika', + 'Albana', + 'Noshin', + 'Merve', + 'Sanjida', + 'Khiabet', + 'Maudrey', + 'Manuella', + 'Linder', + 'Bisma', + 'Shataya', + 'Shandel', + 'Samanthamarie', + 'Liron', + 'Liann', + 'Merdis', + 'Daquana', + 'Chanee', + 'Ezora', + 'Janiqua', + 'Jamielyn', + 'Kyesha', + 'Eulalie', + 'Montressa', + 'Alzina', + 'Monez', + 'Casmira', + 'Eileene', + 'Ethelmae', + 'Veneta', + 'Madiha', + 'Akeema', + 'Daneisha', + 'Cecely', + 'Gwendola', + 'Javonna', + 'Teshia', + 'Yaniris', + 'Valbona', + 'Corita', + 'Deshanna', + 'Kameka', + 'Armina', + 'Georgian', + 'Shakeera', + 'Saudia', + 'Stacyann', + 'Shenique', + 'Ura', + 'Felicie', + 'Ezola', + 'Janeece', + 'Chavely', + 'Ashling', + 'Nakea', + 'Shiana', + 'Shadasia', + 'Petronella', + 'Virgin', + 'Gunhild', + 'Brianni', + 'Grainne', + 'Aneisha', + 'Chaniece', + 'Zalika', + 'Tynasia', + 'Tashauna', + 'Shazia', + 'Shatiqua', + 'Sharissa', + 'Shanyce', + 'Shandell', + 'Shakeyla', + 'Vergia', + 'Geraldyne', + 'Dorita', + 'Nathasha', + 'Samanthajo', + 'Amela', + 'Afnan', + 'Halimah', + 'Dayatra', + 'Shontrell', + 'Tziry', + 'Shanyah', + 'Shawntell', + 'Schwanda', + 'Magalene', + 'Si', + 'Ramisa', + 'Ioanna', + 'Imane', + 'Hadar', + 'Ettel', + 'Coumba', + 'Chumy', + 'Shiran', + 'Lianny', + 'Kimara', + 'Nicha', + 'Chestine', + 'Fatmata', + 'Chedva', + 'Shaima', + 'Shailyn', + 'Zarin', + 'Zahrah', + 'Wania', + 'Tsering', + 'Syrai', + 'Suriyah', + 'No', + 'Niylah', + 'Meerab', + 'Emanuela', + 'Draizy', + 'Giabella', + 'Jeily', + 'Sofya', + 'Shantrelle', + 'Analisse', + 'Ramatoulaye', + 'Raima', + 'Sumaiyah', + 'Stori', + 'Tremeka', + 'Beila', + 'Clodagh', + 'Lyniah', + 'Giavana', + 'Tikisha', + 'Kesia', + 'Shawan', + 'Mazelle', + 'Lear', + 'Rosilyn', + 'Jnaya', + 'Jahnia', + 'Shi', + 'Henya', + 'Jhoselyn', + 'Doha', + 'Dilara', + 'Adelisa', + 'Dedria', + 'Troylynn', + 'Basha', + 'Fatimata', + 'Ama', + 'Ashantee', + 'Chania', + 'Donzella', + 'Ya', + 'Fahmida', + 'Iysis', + 'Neviah', + 'Anastasiya', + 'Brandel', + 'Afra', + 'Lendora', + 'Zisel', + 'Dwanda', + 'Ciarah', + 'Brighid', + 'Rafia', + 'Keamber', + 'Virdie', + 'Girtrude', + 'Nakaya', + 'Donis', + 'Anslei', + 'Alyene', + 'Audell', + 'Nahriah', + 'Zakeria', + 'Zoria', + 'Nikeria', + 'Kynley', + 'Karaline', + 'Jacquita', + 'Shonteria', + 'Carlyon', + 'Tykira', + 'Nykerria', + 'Lema', + 'Destyne', + 'Kansas', + 'Aryonna', + 'Iyannah', + 'Jamayah', + 'Serenitee', + 'Jood', + 'Willean', + 'Makyah', + 'Kameria', + 'Shelagh', + 'Zarriah', + 'Avionna', + 'Arilynn', + 'Vira', + 'Lelar', + 'Miyonna', + 'Jaionna', + 'Nakiah', + 'Rubby', + 'Henrene', + 'Perlie', + 'Tanyah', + 'Luretha', + 'Fannye', + 'Arquilla', + 'Albirta', + 'Annakate', + 'Akeria', + 'Teola', + 'Darthy', + 'Amberleigh', + 'Floriene', + 'Alleyne', + 'Karra', + 'Shaneika', + 'Nekita', + 'Niketa', + 'Kiaraliz', + 'Anacarolina', + 'Sharonica', + 'Renota', + 'Shambrica', + 'Mylea', + 'Jalicia', + 'Shantavious', + 'Antania', + 'Derika', + 'Rashunda', + 'Shandrea', + 'Teneisha', + 'Wachovia', + 'Jalecia', + 'Leimomi', + 'Lasondra', + 'Tela', + 'Caleah', + 'Iwalani', + 'Jamyri', + 'Azyria', + 'Napua', + 'Lahela', + 'Lehuanani', + 'Lameka', + 'Davelyn', + 'Filippa', + 'Tywanna', + 'Toini', + 'Pota', + 'Berthe', + 'Aliesha', + 'Iolanda', + 'Seaira', + 'Kealohilani', + 'Leialoha', + 'Chastidy', + 'Taimane', + 'Taylorann', + 'Briunna', + 'Tyrielle', + 'Alohilani', + 'Jakala', + 'Lakendria', + 'Tiffinie', + 'Laprecious', + 'Kaylaann', + 'Marigny', + 'Roise', + 'Kaidance', + 'Niyla', + 'Mahari', + 'Zya', + 'Ruthia', + 'Timara', + 'Caniya', + 'Keirah', + 'Arieonna', + 'Alydia', + 'Alivea', + 'Ahmani', + 'Elynn', + 'Earnstine', + 'Ramiya', + 'Morrigan', + 'Masiyah', + 'Harmoney', + 'Pearley', + 'Jearlean', + 'Korrine', + 'Chyanna', + 'Catena', + 'Pacita', + 'Kalle', + 'Alzira', + 'Tashayla', + 'Tsugie', + 'Yachiyo', + 'Shellia', + 'Sueno', + 'Kazuyo', + 'Kikumi', + 'Shizuka', + 'Chiyono', + 'Shigeno', + 'Tatsue', + 'Fumiyo', + 'Misayo', + 'Momoyo', + 'Hanayo', + 'Misae', + 'Dalaney', + 'Dewanda', + 'Itsuko', + 'Nyamal', + 'Claris', + 'Virlee', + 'Lulabelle', + 'Valada', + 'Neleigh', + 'Rafelita', + 'Placida', + 'Dulcinea', + 'Pita', + 'Heer', + 'Beren', + 'Ramoncita', + 'Orlinda', + 'Florette', + 'Deluvina', + 'Lugarda', + 'Crucita', + 'Rafaelita', + 'Pablita', + 'Lamaria', + 'Terriana', + 'Terrianna', + 'Dariyah', + 'Carmie', + 'Clotine', + 'Antha', + 'Takyla', + 'Peachie', + 'Akirah', + 'Captola', + 'Sadeel', + 'Dosha', + 'Miquela', + 'Anilah', + 'Erielle', + 'Janiylah', + 'Aubriel', + 'Priti', + 'Purvi', + 'Shakeemah', + 'Anjail', + 'Shaheerah', + 'Amneris', + 'Melverine', + 'Twilla', + 'Kruti', + 'Jalee', + 'Shareefah', + 'Muslimah', + 'Tauheedah', + 'Anabela', + 'Yakima', + 'Lyllian', + 'Tanajah', + 'Sakiyah', + 'Eun', + 'Yashika', + 'Ji', + 'Demiana', + 'Mariaeduard', + 'Snigdha', + 'Dala', + 'Kum', + 'Myung', + 'Hadiyah', + 'Gopi', + 'Cresta', + 'In', + 'Davita', + 'Talayeh', + 'Tracyann', + 'Petula', + 'Nerida', + 'Jeaneen', + 'Ilissa', + 'Letta', + 'Kishia', + 'Gesenia', + 'Bethsaida', + 'Tanija', + 'Ivelise', + 'Marines', + 'Angenette', + 'Alanda', + 'Lauraann', + 'Darnetta', + 'Alisande', + 'Jeniya', + 'Patria', + 'Tieysha', + 'Tasheen', + 'Ife', + 'Loredana', + 'Amyjo', + 'Chane', + 'Nilka', + 'Sharema', + 'Grazia', + 'Renna', + 'Tahesha', + 'Tarita', + 'Jannis', + 'Geriann', + 'Areatha', + 'Rosangel', + 'Kemba', + 'Noni', + 'Margaretann', + 'Kimberleigh', + 'Latisa', + 'Kiriaki', + 'Bobbyjo', + 'Walida', + 'Lynanne', + 'Niyanna', + 'Daziah', + 'Kharma', + 'Pier', + 'Marymargaret', + 'Lorrain', + 'Ketty', + 'Helane', + 'Tarnisha', + 'Sherrice', + 'Swati', + 'Donnajean', + 'Tunya', + 'Annmargaret', + 'Raffaella', + 'Pina', + 'Deneene', + 'Lorriane', + 'Shenise', + 'Ziyonna', + 'Evagelia', + 'Chantae', + 'Tasheema', + 'Meaghen', + 'Shanikqua', + 'Lynnox', + 'Taiesha', + 'Sharima', + 'Shantai', + 'Shaena', + 'Jamine', + 'Rasheena', + 'Tashi', + 'Magdala', + 'Edia', + 'Lasheka', + 'Tiasha', + 'Quanita', + 'Jomayra', + 'Nairoby', + 'Danamarie', + 'Roena', + 'Zasha', + 'Shatema', + 'Orissa', + 'Elvire', + 'Louisiana', + 'Hoda', + 'Kashana', + 'Jaquanna', + 'Jacqulin', + 'Annamari', + 'Marquia', + 'Elmire', + 'Viney', + 'Sonna', + 'Yokasta', + 'Esma', + 'Rella', + 'Deloras', + 'Janill', + 'Samanthan', + 'Ketsia', + 'Chaunte', + 'Aderonke', + 'Sheindel', + 'Shameen', + 'Karema', + 'Amalin', + 'Glendaliz', + 'Finesse', + 'Talibah', + 'Lakima', + 'Geeta', + 'Suehay', + 'Dorice', + 'Aesha', + 'Lateasha', + 'Kimitra', + 'Omolola', + 'Bobbette', + 'Deliah', + 'Carianne', + 'Chanah', + 'Laquandra', + 'Laquanna', + 'Yanick', + 'Nathifa', + 'Nakima', + 'Gayl', + 'Shamaine', + 'Saquana', + 'Nixzaliz', + 'Chaye', + 'Maleka', + 'Latima', + 'Yamira', + 'Tashanna', + 'Kathiria', + 'Jameika', + 'Jamesetta', + 'Moniqua', + 'Yamaris', + 'Tasheba', + 'Virgina', + 'Aviance', + 'Calogera', + 'Candita', + 'Kinga', + 'Alissia', + 'Onnolee', + 'Johnda', + 'Sebastiana', + 'Michelena', + 'Tecla', + 'Mirriam', + 'Sydel', + 'Glema', + 'Tatiyanna', + 'Patrycia', + 'Fortuna', + 'Ebba', + 'Carmelia', + 'Liddie', + 'Genella', + 'Detta', + 'Malvery', + 'Evelene', + 'Loretto', + 'Nunziata', + 'Jenan', + 'Keshawna', + 'Kinisha', + 'Tikia', + 'Sueanne', + 'Cira', + 'Charda', + 'Midge', + 'Annina', + 'Delcina', + 'Barbette', + 'Danah', + 'Isolina', + 'Tanita', + 'Gracemarie', + 'Halleigh', + 'Julita', + 'Kaprice', + 'Dorothyann', + 'Binnie', + 'Bettyjean', + 'Frayda', + 'Tashiana', + 'Breshey', + 'Charnise', + 'Tashena', + 'Meribeth', + 'Sandralee', + 'Heena', + 'Walda', + 'Latika', + 'Rashaunda', + 'Linde', + 'Rosaleen', + 'Illona', + 'Clydette', + 'Benay', + 'Damonica', + 'Anajah', + 'Louelle', + 'Lunette', + 'Faduma', + 'Nadeige', + 'Meylin', + 'Elverna', + 'Etrulia', + 'Ellaree', + 'Rushie', + 'Jayona', + 'Mauri', + 'Radiah', + 'Runette', + 'Terrah', + 'Joia', + 'Ezma', + 'Glenys', + 'Ramla', + 'Shatasha', + 'Berma', + 'Chanteria', + 'Chantrell', + 'Elvi', + 'Sharnell', + 'Rether', + 'Keshana', + 'Ranesha', + 'Earther', + 'Zahirah', + 'Anye', + 'Khori', + 'Saniyyah', + 'Teniola', + 'Anniemae', + 'Oluwadamilola', + 'Aldene', + 'Amellia', + 'Junice', + 'Carolene', + 'Ireoluwa', + 'Nasra', + 'Vernease', + 'Delrose', + 'Marysue', + 'Mirlande', + 'Lashannon', + 'Taijah', + 'Markiesha', + 'Syanne', + 'Jahiya', + 'Vyonne', + 'Reniya', + 'Ryana', + 'Idonia', + 'Loette', + 'Etheleen', + 'Ariyon', + 'Jeneane', + 'Jamea', + 'Airyana', + 'Natesha', + 'Bonnell', + 'Savilla', + 'Daneshia', + 'Deneshia', + 'Alexzandrea', + 'Martharee', + 'Elfreda', + 'Danyla', + 'Retaj', + 'Childnotnamed', + 'Kariana', + 'Ladeja', + 'Johnesha', + 'Nariya', + 'Zamariah', + 'Shanyla', + 'Zykiria', + 'Micaella', + 'Angeliyah', + 'Camara', + 'Kenniyah', + 'Keyani', + 'Renie', + 'Aldena', + 'Paytyn', + 'Perma', + 'Annamary', + 'Roniyah', + 'Zeniya', + 'Capitola', + 'Jaiana', + 'Lakiya', + 'Reida', + 'Ahniya', + 'Elanor', + 'Dorothee', + 'Joud', + 'Ludmilla', + 'Traniyah', + 'Kjerstin', + 'Jeylin', + 'Teona', + 'Marypat', + 'Jacquelynne', + 'Harmonii', + 'Kenyah', + 'Anora', + 'Deniyah', + 'Tyleah', + 'Samora', + 'Almeter', + 'Floride', + 'Lether', + 'Aviah', + 'Livie', + 'Federica', + 'Khalani', + 'Dericka', + 'Ronisue', + 'Raziah', + 'Emaya', + 'Christyana', + 'Rasheka', + 'Jahira', + 'Jalana', + 'Lateria', + 'Baneen', + 'Davisha', + 'Joyanna', + 'Janelys', + 'Raneisha', + 'Israa', + 'Shauntavia', + 'Shericka', + 'Deloma', + 'Maryetta', + 'Jeannetta', + 'Tymber', + 'Charmon', + 'Lanise', + 'Charlisa', + 'Bloneva', + 'Andrena', + 'Katena', + 'Latorria', + 'Letoya', + 'Quovadis', + 'Lakeisa', + 'Sihaam', + 'Charo', + 'Annaclara', + 'Margretta', + 'Nataki', + 'Tyjae', + 'Bahja', + 'Shequila', + 'Quadira', + 'Toinette', + 'Sumeya', + 'Takita', + 'Sherlonda', + 'Daejah', + 'Zyanna', + 'Antonique', + 'Linnae', + 'Georgean', + 'Charlane', + 'Jakerria', + 'Nimo', + 'Saprina', + 'Detrice', + 'Nicolly', + 'Nayara', + 'Seandra', + 'Demetrica', + 'Kayton', + 'Jalayna', + 'Emanuelly', + 'Dondra', + 'Michaeleen', + 'Aquinnah', + 'Lakrisha', + 'Latoia', + 'Bernessia', + 'Jaydaliz', + 'Deona', + 'Donyelle', + 'Kearsten', + 'Tashira', + 'Kaisa', + 'Korrin', + 'Onelia', + 'Shawntia', + 'Faylene', + 'Nafeesah', + 'Synetta', + 'Robertine', + 'Krystn', + 'Nyjae', + 'Nijae', + 'Cieara', + 'Ellerie', + 'Thomasenia', + 'Tiki', + 'Lougenia', + 'Joeann', + 'Marlyss', + 'Saralee', + 'Dayona', + 'Alainna', + 'Gennell', + 'Berline', + 'Latoiya', + 'Eyvonne', + 'Cherline', + 'Tequesta', + 'Loann', + 'Kerstyn', + 'Najmo', + 'Shanitra', + 'Marnice', + 'Tamyah', + 'Ave', + 'Cierrah', + 'Deborahann', + 'Davette', + 'Kennidy', + 'Breelle', + 'Lundon', + 'Imoni', + 'Shamyah', + 'Lindia', + 'Caylyn', + 'Ghadeer', + 'Amirrah', + 'Arlayne', + 'Norrine', + 'Vondell', + 'Ruqaya', + 'Azariya', + 'Narice', + 'Glenadine', + 'Lallie', + 'Conola', + 'Airlie', + 'Lorelie', + 'Levis', + 'Sanyia', + 'Mckaela', + 'Arlina', + 'Dellar', + 'Zorianna', + 'Zanyiah', + 'Maleya', + 'Niyana', + 'Amonie', + 'Aryia', + 'Autie', + 'Keileigh', + 'Kyndel', + 'Saliyah', + 'Naziah', + 'Bernette', + 'Vona', + 'Venie', + 'Tyashia', + 'Khaliya', + 'Mckensie', + 'Kerigan', + 'Kaniah', + 'Eria', + 'Maziyah', + 'Kiasia', + 'Anice', + 'Dera', + 'Georgena', + 'Ezelle', + 'Eavan', + 'Marlyne', + 'Lovella', + 'Westonia', + 'Keniah', + 'Janiaya', + 'Mertice', + 'Marget', + 'Zyeria', + 'Marquerite', + 'Minha', + 'Redonna', + 'Deetta', + 'Aiyla', + 'Majel', + 'Elnor', + 'Deronda', + 'Viona', + 'Rosaleigh', + 'Virgiline', + 'Reeda', + 'Minnah', + 'Keerthi', + 'Kaleyah', + 'Myanna', + 'Remas', + 'Noralee', + 'Idabelle', + 'Albena', + 'Ellory', + 'Areej', + 'Zariel', + 'Laverle', + 'Hjordis', + 'Hilja', + 'Ragna', + 'Cordella', + 'Irean', + 'Ottilia', + 'Gerane', + 'Locklyn', + 'Equilla', + 'Dellie', + 'Aarvi', + 'Mardella', + 'Leighanna', + 'Theone', + 'Ordella', + 'Lidwina', + 'Alyda', + 'Arlyss', + 'Evangelita', + 'Hee', + 'Cherell', + 'Charelle', + 'Shealynn', + 'Anesha', + 'Jasman', + 'Stephie', + 'Ok', + 'Tacarra', + 'Sharnita', + 'Jessic', + 'Dulcey', + 'Natina', + 'Sharvae', + 'Nachelle', + 'Jillane', + 'Tarri', + 'Ajena', + 'Allexus', + 'Labrenda', + 'Pammy', + 'Shemeika', + 'Ysela', + 'Meghin', + 'Marketta', + 'Porshe', + 'Kayti', + 'Taylour', + 'Shavonte', + 'Aivah', + 'Khloi', + 'Jerzie', + 'Nikesha', + 'Cherron', + 'Coralynn', + 'Alvita', + 'Carlita', + 'Albany', + 'Deshawnda', + 'Lacole', + 'Lameeka', + 'Mashawn', + 'Kimyata', + 'Keenya', + 'Baya', + 'Kiva', + 'Samona', + 'Meggin', + 'Chanita', + 'Danissa', + 'Lileigh', + 'Addeline', + 'Shemeeka', + 'Aprille', + 'Donice', + 'Tannisha', + 'Angelette', + 'Lakeita', + 'Marcelyn', + 'Lesta', + 'Claudene', + 'Marney', + 'Tonyia', + 'Nellora', + 'Kimyetta', + 'Ameliana', + 'Electa', + 'Sherl', + 'Jeniece', + 'Jawana', + 'Errica', + 'Braya', + 'Titania', + 'Guydra', + 'Valeta', + 'Danetta', + 'Sharia', + 'Hawraa', + 'Danaja', + 'Makalynn', + 'Tayonna', + 'Kyrene', + 'Arieona', + 'Dallie', + 'Ruie', + 'Ophia', + 'Odella', + 'Vessie', + 'Offie', + 'Evadean', + 'Ample', + 'Aleecia', + 'Shakyla', + 'Makynna', + 'Lakyra', + 'Korryn', + 'Araina', + 'Semiyah', + 'Ndea', + 'Areonna', + 'Jasia', + 'Xavia', + 'Merikay', + 'Keshara', + 'Jennetta', + 'Vergene', + 'Wilodean', + 'Wyona', + 'Avonell', + 'Datha', + 'Ellar', + 'Morene', + 'Laverda', + 'Loetta', + 'Emmogene', + 'Arbadella', + 'Camaria', + 'Rochella', + 'Indiya', + 'Shayma', + 'Orneta', + 'Clotene', + 'Genoa', + 'Lanyah', + 'Oneda', + 'Glendola', + 'Rosala', + 'Zelphia', + 'Suda', + 'Jerrilynn', + 'Orlena', + 'Lorella', + 'Bernadean', + 'Novice', + 'Pheba', + 'Rukaya', + 'Gathel', + 'Meron', + 'Asianae', + 'Arriel', + 'Whisper', + 'Talesha', + 'Morgann', + 'Madissen', + 'Dajanay', + 'Karil', + 'Sherrita', + 'Chery', + 'Lezlee', + 'Daytona', + 'Raegen', + 'Dalal', + 'Majerle', + 'Lama', + 'Daijanae', + 'Celicia', + 'Cheril', + 'Cornesha', + 'Aniza', + 'Clytie', + 'Persis', + 'Aino', + 'Lawandra', + 'Deshonda', + 'Catrena', + 'Temekia', + 'Camella', + 'Arnetra', + 'Latoyna', + 'Tekisha', + 'Nalee', + 'Jennife', + 'Daphanie', + 'Shewanda', + 'Cheronda', + 'Latayna', + 'Almerinda', + 'Danene', + 'Jadwiga', + 'Ellora', + 'Tanga', + 'Tamekka', + 'Lashond', + 'Shinika', + 'Khyleigh', + 'Baelyn', + 'Clarene', + 'Monyette', + 'Lakisa', + 'Audreyanna', + 'Malayjah', + 'Keia', + 'Lajessica', + 'Marquite', + 'Odessia', + 'Marketia', + 'Malayshia', + 'Laconya', + 'Brayla', + 'Germani', + 'Luberdie', + 'Angla', + 'Cona', + 'Katrinia', + 'Shaletha', + 'Eutha', + 'Elmyra', + 'Cleva', + 'Elnore', + 'Vila', + 'Evone', + 'Margert', + 'Pairlee', + 'Bernelle', + 'Diannie', + 'Alinda', + 'Emerine', + 'Rogena', + 'Genette', + 'Jearline', + 'Estalee', + 'Bertina', + 'Cassand', + 'Kisa', + 'Veronic', + 'Idalina', + 'Walsie', + 'Gwendol', + 'Orvilla', + 'Latonga', + 'Elizabe', + 'Bernece', + 'Charlen', + 'Dola', + 'Alaija', + 'Martia', + 'Shanica', + 'Shariya', + 'Yuliya', + 'Atleigh', + 'Flannery', + 'Loeta', + 'Zakiah', + 'Alayia', + 'Glee', + 'Embree', + 'Kasidy', + 'Zacaria', + 'Derriona', + 'Jakyria', + 'Kiauna', + 'Garnelle', + 'Tyriana', + 'Juliya', + 'Maddisen', + 'Auna', + 'Jameisha', + 'Lurleen', + 'Kourtlyn', + 'Chelan', + 'Verlinda', + 'Sherria', + 'Alzada', + 'Ketara', + 'Anaka', + 'Breion', + 'Shadestiny', + 'Shanterica', + 'Tenia', + 'Keiosha', + 'Jamyriah', + 'Jamyrie', + 'Jalacia', + 'Ronita', + 'Maryln', + 'Earsie', + 'Kyri', + 'Markiyah', + 'Malajah', + 'Alandria', + 'Shaquitta', + 'Raymona', + 'Paeton', + 'Yaritzy', + 'Jonesha', + 'Anda', + 'Khadjah', + 'Amyree', + 'Vernestine', + 'Lavetta', + 'Jniya', + 'Shakiyah', + 'Aasia', + 'Roniya', + 'Keleigh', + 'Makalyn', + 'Kadasia', + 'Johneisha', + 'Jakaya', + 'Kinzey', + 'Wendelyn', + 'Darielys', + 'Wyteria', + 'Yarieliz', + 'Taysia', + 'Carmya', + 'Erionna', + 'Shameria', + 'Kearia', + 'Graycie', + 'Jurnie', + 'Calypso', + 'Finlee', + 'Fynlee', + 'Sophee', + 'Lorali', + 'Shacoria', + 'Kadeejah', + 'Lakira', + 'Kelsay', + 'Angelys', + 'Moeshia', + 'Keundra', + 'Mayara', + 'Josi', + 'Annaluiza', + 'Jacquese', + 'Jillaine', + 'Annajulia', + 'Nayeliz', + 'Maire', + 'Jamonica', + 'Jadalys', + 'Missie', + 'Machell', + 'Liisa', + 'Jalaine', + 'Odester', + 'Veria', + 'Virda', + 'Arleene', + 'Cigi', + 'Eloda', + 'Kacelyn', + 'Cidalia', + 'Vadie', + 'Wydell', + 'Donnita', + 'Lousie', + 'Oreatha', + 'Berdine', + 'Cielita', + 'Lilas', + 'Verneda', + 'Armelia', + 'Glender', + 'Elizbeth', + 'Vanella', + 'Florean', + 'Vyolet', + 'Albertia', + 'Albirda', + 'Sylva', + 'Lakresha', + 'Matha', + 'Nerine', + 'Dezzie', + 'Lodell', + 'Rosielee', + 'Julane', + 'Lodena', + 'Brookley', + 'Kynadi', + 'Krymson', + 'Etoile', + 'Meighan', + 'Izella', + 'Jakaria', + 'Jaleria', + 'Clister', + 'Alberdia', + 'Zykeriah', + 'Mileigh', + 'Isola', + 'Mamye', + 'Eller', + 'Kamoria', + 'Lakelynn', + 'Aslean', + 'Bular', + 'Emmaclaire', + 'Dasie', + 'Denotra', + 'Everlene', + 'Lynleigh', + 'Iantha', + 'Quinetta', + 'Lillion', + 'Sophronia', + 'Japonica', + 'Beauty', + 'Pearlina', + 'Evella', + 'Jatana', + 'Kechia', + 'Conswella', + 'Malissia', + 'Alexina', + 'Demeka', + 'Muguette', + 'Vaudine', + 'Aprill', + 'Villa', + 'Florece', + 'Tonjia', + 'Bethania', + 'Makinlee', + 'Latondra', + 'Audery', + 'Ericia', + 'Miyoshi', + 'Betti', + 'Harlym', + 'Novelle', + 'Liller', + 'Pinkey', + 'Narcille', + 'Lasheika', + 'Leonise', + 'Lydie', + 'Olla', + 'Rejeanne', + 'Athelene', + 'Eloyse', + 'Edolia', + 'Clotile', + 'Ethelrine', + 'Devonda', + 'Nakeshia', + 'Tomesha', + 'Orena', + 'Karlyne', + 'Enolia', + 'Faynell', + 'Margia', + 'Marvelene', + 'Justilia', + 'Iceola', + 'Shantina', + 'Shinita', + 'Loula', + 'Ireta', + 'Vanessia', + 'Ramonia', + 'Monita', + 'Shalva', + 'Ong', + 'Remonia', + 'Sheral', + 'Angelean', + 'Phyllistine', + 'Brenetta', + 'Madgeline', + 'Zyairah', + 'Anjolaoluwa', + 'Clotiel', + 'Eldine', + 'Tylia', + 'Ifeoluwa', + 'Florestine', + 'Althia', + 'Ravonda', + 'Tsion', + 'Zyaira', + 'Wylodene', + 'Janesha', + 'Vonciel', + 'Ruthey', + 'Khiana', + 'Kadesia', + 'Murdis', + 'Zhana', + 'Jillayne', + 'Quatisha', + 'Jaquasia', + 'Michaila', + 'Mashayla', + 'Travia', + 'Tyrika', + 'Aldah', + 'Makaiya', + 'Maridee', + 'Kyndell', + 'Nykira', + 'Mazell', + 'Luecile', + 'Quatasia', + 'Khala', + 'Sible', + 'Jakera', + 'Ovella', + 'Lealer', + 'Juleen', + 'Rinette', + 'Laykin', + 'Ozite', + 'Shaquanta', + 'Quanetta', + 'Shannyn', + 'Lacrystal', + 'Everline', + 'Editha', + 'Toneka', + 'Reinette', + 'Maclovia', + 'Ledia', + 'Shakeeka', + 'Shakeeta', + 'Taquanna', + 'Miyisha', + 'Patrecia', + 'Wylodean', + 'Solita', + 'Dalisa', + 'Jatoya', + 'Texanna', + 'Yvetta', + 'Lectoria', + 'Cyntrell', + 'Monyae', + 'Ibtisam', + 'Miski', + 'Renesha', + 'Maelle', + 'Azhar', + 'Zamzam', + 'Jamera', + 'Tyranika', + 'Ladan', + 'Ruweyda', + 'Jabrea', + 'Sherrica', + 'Clyda', + 'Treniece', + 'Fonnie', + 'Bedie', + 'Kewanda', + 'Mozel', + 'Tramika', + 'Quessie', + 'Tyshay', + 'Ladasha', + 'Kaarin', + 'Mazzie', + 'Genora', + 'Monie', + 'Muntas', + 'Hayat', + 'Jovanda', + 'Appolonia', + 'Cuma', + 'Briante', + 'Reneisha', + 'Zenovia', + 'Allysia', + 'Aliene', + 'Raini', + 'Tyja', + 'Iriel', + 'Deshante', + 'Shatira', + 'Demri', + 'Ajaysia', + 'Ireon', + 'Idil', + 'Nawaal', + 'Riham', + 'Nyeisha', + 'Jonique', + 'Keneisha', + 'Ravan', + 'Khadra', + 'Dawanna', + 'Gavriella', + 'Myrene', + 'Jasamine', + 'Brione', + 'Earlisha', + 'Dazia', + 'Jalesia', + 'Cabrina', + 'Marieme', + 'Gloristine', + 'Cattie', + 'Damilola', + 'Evora', + 'Almarie', + 'Vauda', + 'Tanzie', + 'Truby', + 'Tayona', + 'Francelia', + 'Brona', + 'Jannice', + 'Weltha', + 'Phylliss', + 'Vieva', + 'Danera', + 'Saratha', + 'Colinda', + 'Suzonne', + 'Shelene', + 'Shelda', + 'Annye', + 'Kaola', + 'Modine', + 'Velvie', + 'Vetra', + 'Tyrhonda', + 'Malissie', + 'Shemica', + 'Rockell', + 'Adgie', + 'Lachanda', + 'Kwanza', + 'Keyanta', + 'Hazeleen', + 'Yarnell', + 'Mettie', + 'Kissie', + 'Jawanna', + 'Ilham', + 'Enchantra', + 'Lucielle', + 'Salmo', + 'Sabrin', + 'Nicy', + 'Rubell', + 'Willet', + 'Ronata', + 'Semiko', + 'Idman', + 'Meoshia', + 'Maie', + 'Eulala', + 'Tiyonna', + 'Sabarin', + 'Merlie', + 'Oneka', + 'Khiya', + 'Geralene', + 'Hubbie', + 'Patches', + 'Robenia', + 'Carita', + 'Veleka', + 'Tamla', + 'Zondra', + 'Cheramie', + 'Nimco', + 'Chauntelle', + 'Calonia', + 'Mulki', + 'Clydia', + 'Glida', + 'Fartun', + 'Fardowsa', + 'Iyona', + 'Dwanna', + 'Angila', + 'Carletha', + 'Blakley', + 'Valecia', + 'Songa', + 'Shya', + 'Kamber', + 'Siah', + 'Sloka', + 'Sophiagrace', + 'Sophiamarie', + 'Setayesh', + 'Roselie', + 'Samhitha', + 'Savreen', + 'Zanayah', + 'Yilia', + 'Zareena', + 'Yeilin', + 'Ulyana', + 'Tylie', + 'Vaani', + 'Vasilisa', + 'Videl', + 'Xylia', + 'Rubylee', + 'Jessye', + 'Itasca', + 'Bonifacia', + 'Bennye', + 'Estellene', + 'Daycee', + 'Vung', + 'Babe', + 'Lucyle', + 'Laurencia', + 'Frankye', + 'Clariece', + 'Alsace', + 'Ernesteen', + 'Zuma', + 'Loleta', + 'Matiana', + 'Thyra', + 'Thekla', + 'Miladie', + 'Moselle', + 'Waldene', + 'Thula', + 'Ethelda', + 'Elbira', + 'Eddye', + 'Lafaye', + 'Beryle', + 'Beanna', + 'Basilisa', + 'Bernardina', + 'Vontressa', + 'Elner', + 'Gladine', + 'Saketha', + 'Nellene', + 'Margurette', + 'Levada', + 'Alcie', + 'Beuna', + 'Miaa', + 'Miia', + 'Miral', + 'Lunabella', + 'Manvi', + 'Nahlia', + 'Quetzal', + 'Preet', + 'Navreet', + 'Prajna', + 'Analayah', + 'Aalaya', + 'Aaleah', + 'Aaria', + 'Aby', + 'Adeena', + 'Adelaine', + 'Adhara', + 'Alekhya', + 'Avaline', + 'Avina', + 'Azaliah', + 'Azayla', + 'Anwita', + 'Arna', + 'Asmi', + 'Cutina', + 'Jaydalynn', + 'Jerusalem', + 'Hiyab', + 'Icey', + 'Jaanvi', + 'Khalessi', + 'Khiara', + 'Leelah', + 'Ketzaly', + 'Kaliyanei', + 'Karolynn', + 'Kaylonnie', + 'Harveen', + 'Danilynn', + 'Decklyn', + 'Deleyza', + 'Charm', + 'Calina', + 'Cathaleya', + 'Dailynn', + 'Corra', + 'Cyrene', + 'Eveleen', + 'Fia', + 'Galina', + 'Gohar', + 'Gursirat', + 'Harleyquinn', + 'Evalin', + 'Eevee', + 'Eira', + 'Elara', + 'Ellaina', + 'Ellarose', + 'Erabella', + 'Teofila', + 'Calamity', + 'Sherion', + 'Niang', + 'Oreta', + 'Leita', + 'Maedelle', + 'Othello', + 'Meshell', + 'Alfreida', + 'Detria', + 'Cloda', + 'Ermine', + 'Gertrudes', + 'Zudora', + 'Benigna', + 'Dolorez', + 'Narcissa', + 'Eduviges', + 'Dionisia', + 'Crisanta', + 'Adreena', + 'Aivy', + 'Sharanda', + 'Amma', + 'Danitra', + 'Lashuna', + 'Yasheka', + 'Sheronica', + 'Ameliya', + 'Cayetana', + 'Benancia', + 'Tiya', + 'Umaiza', + 'Vicktoria', + 'Vidushi', + 'Yaretzie', + 'Siennah', + 'Sofiah', + 'Stuti', + 'Taitum', + 'Yuli', + 'Zarya', + 'Zeriah', + 'Sadiee', + 'Rubee', + 'Ryenn', + 'Sayana', + 'Ezabella', + 'Galya', + 'Hayzel', + 'Evalette', + 'Eleanna', + 'Elize', + 'Elleana', + 'Hiya', + 'Jezabelle', + 'Jazzy', + 'Jeraldin', + 'Jocabed', + 'Kaloni', + 'Jazmeen', + 'Jasmarie', + 'Ilani', + 'Ilany', + 'Ariannie', + 'Angelinne', + 'Delaynie', + 'Calise', + 'Bethlehem', + 'Cateleya', + 'Paitynn', + 'Peytin', + 'Rainie', + 'Rhylin', + 'Rosaly', + 'Nomi', + 'Mirai', + 'Moksha', + 'Mylin', + 'Nazeli', + 'Nilani', + 'Marcelene', + 'Victorina', + 'Laiah', + 'Leeyah', + 'Miaisabella', + 'Ravleen', + 'Lazara', + 'Zuleidy', + 'Shraddha', + 'Simarpreet', + 'Rinoa', + 'Ridhima', + 'Ryla', + 'Ryleeann', + 'Ryli', + 'Sahori', + 'Smrithi', + 'Yeslin', + 'Yanessa', + 'Zeltzin', + 'Sonakshi', + 'Sophea', + 'Carlissa', + 'Bryttani', + 'Albesa', + 'Bonnye', + 'Daksha', + 'Terria', + 'Davinah', + 'Enalina', + 'Evolette', + 'Dhwani', + 'Eleora', + 'Leea', + 'Lexii', + 'Meilyn', + 'Nevah', + 'Noga', + 'Prabhleen', + 'Quinley', + 'Mursal', + 'Naiara', + 'Navah', + 'Izumi', + 'Janelli', + 'Jniyah', + 'Klaryssa', + 'Kritika', + 'Laksmi', + 'Lalani', + 'Joselle', + 'Kashish', + 'Kenyana', + 'Laquishia', + 'Deshonna', + 'Sentoria', + 'Ernestene', + 'Maxima', + 'Senovia', + 'Nestora', + 'Valta', + 'Casady', + 'Daphene', + 'Chonita', + 'Omelia', + 'Odena', + 'Melchora', + 'Quetzally', + 'Thera', + 'Gabina', + 'Donaciana', + 'Riddhima', + 'Lakessa', + 'Lakeeta', + 'Katasha', + 'Chaitra', + 'Chizara', + 'Aveyah', + 'Elah', + 'Eliannah', + 'Ellanore', + 'Emmalia', + 'Dalexa', + 'Delara', + 'Donatella', + 'Aubreanna', + 'Aberdeen', + 'Aerilyn', + 'Aleksia', + 'Annarose', + 'Anthea', + 'Aoi', + 'Amberrose', + 'Anaeli', + 'Lilou', + 'Lumen', + 'Manasvi', + 'Lillybeth', + 'Keylani', + 'Lenya', + 'Lidya', + 'Mulan', + 'Nirvi', + 'Ondine', + 'Meenakshi', + 'Mathea', + 'Melyna', + 'Io', + 'Izelle', + 'Jailia', + 'Eztli', + 'Gali', + 'Hade', + 'Hafsah', + 'Hannahgrace', + 'Kayleah', + 'Kayleeann', + 'Kemily', + 'Jeylah', + 'Jiaqi', + 'Sherrika', + 'Daffney', + 'Solstice', + 'Soriah', + 'Sumayya', + 'Saory', + 'Shaily', + 'Shanzay', + 'Sharvi', + 'Xylina', + 'Yeimy', + 'Yizel', + 'Zaidee', + 'Ziah', + 'Jesucita', + 'Madalena', + 'Vontresa', + 'Tangee', + 'Shekina', + 'Sista', + 'Norvis', + 'Winnell', + 'Yoshida', + 'Nikiya', + 'Vidala', + 'Shandria', + 'Rozelle', + 'Maragret', + 'Sixta', + 'Theta', + 'Wylma', + 'Jobita', + 'Gaudalupe', + 'Lurlean', + 'Oveta', + 'Heriberta', + 'Bacilia', + 'Senorina', + 'Denika', + 'Akeisha', + 'Tamecia', + 'Jera', + 'Crestina', + 'Shwanda', + 'Kelbie', + 'Sanayah', + 'Zaliah', + 'Nadezhda', + 'Maaliyah', + 'Mahaley', + 'Raziyah', + 'Saraiya', + 'Cyriah', + 'Chaniyah', + 'Emmarae', + 'Eleen', + 'Ashland', + 'Briniyah', + 'Ainhoa', + 'Aviyah', + 'Atarah', + 'Lutrelle', + 'Clevie', + 'Blossie', + 'Cola', + 'Para', + 'Verdelle', + 'Beddie', + 'Lilliemae', + 'Jurell', + 'Bertice', + 'Fozie', + 'Oppie', + 'Rozia', + 'Rozie', + 'Epsie', + 'Karman', + 'Estoria', + 'Dynesha', + 'Sarae', + 'Xolani', + 'Talyah', + 'Zanaria', + 'Zamiah', + 'Starkeisha', + 'Alys', + 'Izaria', + 'Cayenne', + 'Damiah', + 'Alwilda', + 'Leoda', + 'Yariah', + 'Tuleen', + 'Rhelda', + 'Carlesha', + 'Alfretta', + 'Orma', + 'Ornella', + 'Nazyia', + 'Samorah', + 'Keyonni', + 'Jeriyah', + 'Jazariyah', + 'Demaria', + 'Mikeyla', + 'Malania', + 'Miyanna', + 'Neriyah', + 'Naelle', + 'Lazariah', + 'Rea', + 'Annaya', + 'Aleanna', + 'Baylin', + 'Aela', + 'Emmilyn', + 'Anila', + 'Rodnesha', + 'Janeliz', + 'Kseniya', + 'Nyana', + 'Zemirah', + 'Somya', + 'Yanna', + 'Terryn', + 'Naika', + 'Laiyla', + 'Lyrica', + 'Loralie', + 'Lilya', + 'Wonnie', + 'Runelle', + 'Tynleigh', + 'Loralye', + 'Arynn', + 'Melvis', + 'Akiyah', + 'Matline', + 'Ellean', + 'Wylean', + 'Marfa', + 'Elliemae', + 'Nancey', + 'Waltina', + 'Ommie', + 'Lonia', + 'Reaver', + 'Virdell', + 'Rosabell', + 'Sarahgrace', + 'Faustine', + 'Euretha', + 'Sussie', + 'Rebie', + 'Oveline', + 'Reathel', + 'Algia', + 'Mylissa', + 'Rethel', + 'Nakyla', + 'Necia', + 'Deanie', + 'Beckey', + 'Yasmen', + 'Yukari', + 'Zamyra', + 'Roselinda', + 'Takeko', + 'Vicke', + 'Mckala', + 'Hanae', + 'Elley', + 'Ellyssa', + 'Geanna', + 'Geetika', + 'Elenoa', + 'Elane', + 'Deeya', + 'Deviny', + 'Genecis', + 'Jasminerose', + 'Ireri', + 'Hailei', + 'Hannya', + 'Harshini', + 'Holiday', + 'Arista', + 'Dannae', + 'Melayna', + 'Meleni', + 'Mystique', + 'Nathalya', + 'Natsumi', + 'Sharlize', + 'Shine', + 'Sindhu', + 'Starlyn', + 'Sarika', + 'Sarine', + 'Seleen', + 'Khalea', + 'Kirti', + 'Jocilyn', + 'Maille', + 'Mariaceleste', + 'Leelee', + 'Leidi', + 'Libertad', + 'Lizvet', + 'Kierstan', + 'Adja', + 'Debbye', + 'Dorenda', + 'Kiyono', + 'Katsuko', + 'Katsue', + 'Misue', + 'Umeno', + 'Rayvin', + 'Sachie', + 'Kinue', + 'Danajah', + 'Denay', + 'Tsuneko', + 'Tamae', + 'Saeko', + 'Tsutako', + 'Sumako', + 'Momoe', + 'Tomoko', + 'Asae', + 'Nautika', + 'Kourtnee', + 'Keauna', + 'Maydeen', + 'Chianne', + 'Macala', + 'Briaunna', + 'Ceirra', + 'Kimberlea', + 'Normalinda', + 'Milinda', + 'Jonetta', + 'Seleta', + 'Chryl', + 'Aaminah', + 'Mersades', + 'Mickenzie', + 'Tahlor', + 'Kimetha', + 'Hopie', + 'Guadulupe', + 'Blakelynn', + 'Orfelinda', + 'Aubre', + 'Ajayla', + 'Makenlee', + 'Journii', + 'Janayla', + 'Talulah', + 'Siddhi', + 'Shaira', + 'Yuridiana', + 'Yulitza', + 'Tulsi', + 'Yatana', + 'Jaleya', + 'Ayrianna', + 'Damaya', + 'Myana', + 'Lanyiah', + 'Kadince', + 'Aunna', + 'Avrielle', + 'Khyli', + 'Kariyah', + 'Bralynn', + 'Derrianna', + 'Maryella', + 'Charlynn', + 'Ilma', + 'Tresea', + 'Mersadies', + 'Macenzie', + 'Terriona', + 'Telia', + 'Tamryn', + 'Tahari', + 'Solyana', + 'Lyrical', + 'Akie', + 'Teruyo', + 'Shizuyo', + 'Tsuruyo', + 'Daviona', + 'Marshelia', + 'Connye', + 'Marka', + 'Adelmira', + 'Dorelia', + 'Nirel', + 'Oceanna', + 'Neeka', + 'Sherolyn', + 'Sheralyn', + 'Sharlet', + 'Milenka', + 'Astha', + 'Angeleena', + 'Anysia', + 'Apoorva', + 'Bryanah', + 'Carolyna', + 'Cecy', + 'Anadalay', + 'Akaylah', + 'Aika', + 'Aasha', + 'Ahniah', + 'Adelayda', + 'Kyaira', + 'Manmeet', + 'Linsy', + 'Malini', + 'Mairany', + 'Haeley', + 'Evelen', + 'Jezel', + 'Jinelle', + 'Joleena', + 'Hikari', + 'Inari', + 'Itcel', + 'Lokelani', + 'Keikilani', + 'Sherilynn', + 'Jamieann', + 'Lajuanna', + 'Roselind', + 'Rhetta', + 'Alysah', + 'Ameyalli', + 'Abigayl', + 'Aizza', + 'Alaiza', + 'Aslyn', + 'Anjalee', + 'Annaliza', + 'Antara', + 'Areen', + 'Carra', + 'Katieann', + 'Kimla', + 'Xan', + 'Mikiala', + 'Chrissa', + 'Belanna', + 'Ankitha', + 'Celestial', + 'Chiana', + 'Akhila', + 'Alique', + 'Alyssamae', + 'Betheny', + 'Stepheny', + 'Brittanyann', + 'Adonna', + 'Barbarella', + 'Shalamar', + 'Flecia', + 'Dlisa', + 'Anabelia', + 'Velen', + 'Xotchil', + 'Yairis', + 'Lytzy', + 'Faizah', + 'Eilleen', + 'Elona', + 'Esteffany', + 'Jesyka', + 'Jhovana', + 'Jisell', + 'Joclyn', + 'Teel', + 'Sundee', + 'Mechell', + 'Lisia', + 'Nandita', + 'Natalina', + 'Nattalie', + 'Rosaelena', + 'Siclali', + 'Skyllar', + 'Taeya', + 'Sadey', + 'Sadira', + 'Sanae', + 'Serenah', + 'Shamila', + 'Brizza', + 'Chalisa', + 'Shakeela', + 'Gordean', + 'Akane', + 'Akansha', + 'Angeni', + 'Annalina', + 'Anushree', + 'Allexa', + 'Katelynd', + 'Raenette', + 'Airiel', + 'Matina', + 'Teira', + 'Deatra', + 'Darolyn', + 'Hilliary', + 'Roanna', + 'Prissy', + 'Monya', + 'Armelinda', + 'Ginnie', + 'Darenda', + 'Leslea', + 'Marcedes', + 'Jeweliana', + 'Jewelissa', + 'Josselyne', + 'Lavanya', + 'Koryn', + 'Khushpreet', + 'Kierah', + 'Cyana', + 'Deeana', + 'Bibianna', + 'Bryannah', + 'Heidie', + 'Desteni', + 'Elleanna', + 'Sierah', + 'Sumedha', + 'Shantall', + 'Yarissa', + 'Yerania', + 'Tifanny', + 'Mehek', + 'Mirely', + 'Mitra', + 'Mar', + 'Rohini', + 'Prerana', + 'Naizeth', + 'Naydeli', + 'Melveen', + 'Moani', + 'Endora', + 'Jackquline', + 'Stefanny', + 'Tamanna', + 'Sofija', + 'Zitlalic', + 'Ymani', + 'Jumana', + 'Kailene', + 'Josephyne', + 'Leiya', + 'Letzy', + 'Litsy', + 'Lizbett', + 'Lizveth', + 'Jaiya', + 'Dreanna', + 'Celestia', + 'Electra', + 'Sevanna', + 'Sidnie', + 'Semone', + 'Sharra', + 'Sharlette', + 'Selinda', + 'Saumya', + 'Meilan', + 'Melea', + 'Maleeha', + 'Mitali', + 'Rheana', + 'Ruchi', + 'Oasis', + 'Preethi', + 'Aungelique', + 'Kristl', + 'Tashala', + 'Darcell', + 'Rolinda', + 'Toye', + 'Shirlyn', + 'Yvonda', + 'Tymia', + 'Oteka', + 'Ladora', + 'Deashia', + 'Janautica', + 'Sonnet', + 'Sucely', + 'Suriah', + 'Tallula', + 'Sanna', + 'Seniyah', + 'Seri', + 'Yexalen', + 'Yumiko', + 'Zayana', + 'Zohal', + 'Valerye', + 'Yarisbeth', + 'Vivyana', + 'Xela', + 'Brithanny', + 'Jasira', + 'Jenessy', + 'Jezebelle', + 'Leahna', + 'Leilanee', + 'Leily', + 'Kohana', + 'Dorsa', + 'Elanna', + 'Caralyn', + 'Erilyn', + 'Halyn', + 'Helayna', + 'Lionor', + 'Maela', + 'Masha', + 'Myley', + 'Malaak', + 'Malai', + 'Mariapaula', + 'Nathalye', + 'Remie', + 'Parnika', + 'Neveen', + 'Cherith', + 'Orvella', + 'Aurion', + 'Shonterria', + 'Natoria', + 'Shaterria', + 'Clo', + 'Donnia', + 'Cana', + 'Niaya', + 'Brelyn', + 'Aalliyah', + 'Shaaron', + 'Doylene', + 'Lowanda', + 'Henryetta', + 'Obera', + 'Marykathryn', + 'Dema', + 'Arcadia', + 'Lodema', + 'Aloni', + 'Analya', + 'Aashritha', + 'Ayani', + 'Audreena', + 'Audrena', + 'Ariahna', + 'Antonela', + 'Atzi', + 'Amunet', + 'Jaala', + 'Keambria', + 'Kanaya', + 'Emya', + 'Deijah', + 'Dayjah', + 'Tiye', + 'Nyja', + 'Markesia', + 'Valla', + 'Cesaria', + 'Eusevia', + 'Elpidia', + 'Jaquisha', + 'Romanita', + 'Shauntia', + 'Chasmine', + 'Deneisha', + 'Quatesha', + 'Nicosha', + 'Shandricka', + 'Shambria', + 'Shakerra', + 'Santrice', + 'Quinesha', + 'Shantika', + 'Roderica', + 'Whitnie', + 'Piedad', + 'Koleta', + 'Brazil', + 'Aamina', + 'Adaleen', + 'Adyline', + 'Bricola', + 'Analeigha', + 'Anara', + 'Ladawna', + 'Ruperta', + 'Deaundra', + 'Jaleisa', + 'Keria', + 'Sharaine', + 'Shanekqua', + 'Shanekia', + 'Kenyanna', + 'Jacoria', + 'Airianna', + 'Amana', + 'Amariz', + 'Ammi', + 'Miaya', + 'Aaniya', + 'Anaisha', + 'Bellina', + 'Annasofia', + 'Archita', + 'Arianie', + 'Shaquandra', + 'Shakeyra', + 'Tiandra', + 'Soveida', + 'Gonzala', + 'Gaylia', + 'Freddye', + 'Roxi', + 'Neya', + 'Nitika', + 'Noriah', + 'Raha', + 'Briah', + 'Syrah', + 'Talise', + 'Tarynn', + 'Tianah', + 'Solay', + 'Saraiah', + 'Sherlynn', + 'Leylany', + 'Lilu', + 'Maelie', + 'Lexxie', + 'Monzeratt', + 'Nari', + 'Naveyah', + 'Mianna', + 'Maylea', + 'Mery', + 'Marene', + 'Zeba', + 'Xymena', + 'Yaremi', + 'Yari', + 'Yulie', + 'Lile', + 'Dafnee', + 'Indra', + 'Itzelle', + 'Evangaline', + 'Evelett', + 'Evely', + 'Ghazal', + 'Arnisha', + 'Kassia', + 'Kayah', + 'Kalliyan', + 'Diannia', + 'Damyah', + 'Torianna', + 'Talasia', + 'Zakira', + 'Zyah', + 'Masiya', + 'Rhyanna', + 'Kemaya', + 'Jadasia', + 'Kanijah', + 'Henleigh', + 'Ciella', + 'Dayanne', + 'Ivannia', + 'Heydy', + 'Fergie', + 'Fianna', + 'Goretti', + 'Gwynneth', + 'Gyanna', + 'Haidi', + 'Christabella', + 'Angelinah', + 'Anina', + 'Annya', + 'Alejah', + 'Bradie', + 'Breanah', + 'Arihana', + 'Aryona', + 'Ashwika', + 'Aylet', + 'Ayleth', + 'Meleena', + 'Micel', + 'Misel', + 'Naiema', + 'Meiling', + 'Malaia', + 'Rehanna', + 'Raengel', + 'Padma', + 'Majestic', + 'Katelen', + 'Jenaveve', + 'Jennessy', + 'Jewelisa', + 'Joelie', + 'Lyliana', + 'Mahati', + 'Sherral', + 'Kamariah', + 'Larsen', + 'Khaniya', + 'Jakiah', + 'Darionna', + 'Bristal', + 'Ahlana', + 'Aireanna', + 'Alaila', + 'Jarethzy', + 'Orfalinda', + 'Nataliah', + 'Nayra', + 'Nishika', + 'Meeya', + 'Sanaia', + 'Sensi', + 'Percilla', + 'Pranathi', + 'Kathrynn', + 'Katriel', + 'Jordanna', + 'Jessilyn', + 'Jilliana', + 'Madeira', + 'Laia', + 'Leala', + 'Courtlynn', + 'Ahriana', + 'Aliena', + 'Adalay', + 'Nakyia', + 'Niema', + 'Leeasia', + 'Evenny', + 'Dorismar', + 'Dyanara', + 'Elonna', + 'Estreya', + 'Ashmita', + 'Anureet', + 'Angeliah', + 'Annaliz', + 'Dallanara', + 'Danaly', + 'Carely', + 'Sevilla', + 'Aleigh', + 'Allianna', + 'Alamar', + 'Jaiah', + 'Shellsea', + 'Sheylin', + 'Sonoma', + 'Hayla', + 'Yoali', + 'Yzabel', + 'Zeenat', + 'Zienna', + 'Shirlynn', + 'Shilynn', + 'Raphaella', + 'Makyia', + 'Inola', + 'Omaria', + 'Michiah', + 'Anareli', + 'Anacamila', + 'Anahis', + 'Anapaola', + 'Clowie', + 'Brizia', + 'Alexssa', + 'Ailanie', + 'Aileene', + 'Francille', + 'Jatoria', + 'Jaquitta', + 'Sybol', + 'Landra', + 'Danyela', + 'Cubia', + 'Arabela', + 'Adelfina', + 'Quaniya', + 'Paulyne', + 'Vanteen', + 'Treba', + 'Kaylena', + 'Kaelynne', + 'Kalanie', + 'Lezli', + 'Lithzy', + 'Lanessa', + 'Laylene', + 'Leilaney', + 'Emmajean', + 'Francella', + 'Eiliyah', + 'Jadey', + 'Jamilett', + 'Ingris', + 'Tayanna', + 'Skarlette', + 'Sady', + 'Senia', + 'Yakeline', + 'Yenna', + 'Yesmin', + 'Meily', + 'Mikeila', + 'Miu', + 'Rakel', + 'Niveah', + 'Nyemah', + 'Gorgeous', + 'Zaraya', + 'Lavaeh', + 'Meila', + 'Labella', + 'Lilyona', + 'Zykierra', + 'Orfa', + 'Seriyah', + 'Shivali', + 'Sibylla', + 'Sua', + 'Ulani', + 'Vianet', + 'Yanell', + 'Yolette', + 'Yudany', + 'Suheidy', + 'Sukhpreet', + 'Syanna', + 'Tatevik', + 'Tayde', + 'Sameria', + 'Mikiya', + 'Claramae', + 'Audine', + 'Francile', + 'Tynia', + 'Goddess', + 'Samoria', + 'Llana', + 'Oveda', + 'Amelya', + 'Auda', + 'Disaya', + 'Zanyah', + 'Samiyyah', + 'Jaianna', + 'Ruqayyah', + 'Nakira', + 'Shamirah', + 'Ta', + 'Giani', + 'Brya', + 'Cyani', + 'Ashiyah', + 'Kahli', + 'Beauton', + 'Kashay', + 'Sadiyah', + 'Mikaya', + 'Nasira', + 'Nasirah', + 'Ariauna', + 'Yasirah', + 'Skyelynn', + 'Naailah', + 'Nyelle', + 'Adessa', + 'Ayriana', + 'Mirielle', + 'Munirah', + 'Layani', + 'Haniyah', + 'Ovida', + 'Haniyyah', + 'Layonna', + 'Jazmarie', + 'Wicahpi', + 'Cante', + 'Zamyah', + 'Tanyiah', + 'Shalita', + 'Salley', + 'Jnya', + 'Santasia', + 'Shaneque', + 'Quantina', + 'Temeika', + 'Narvis', + 'Pearlee', + 'Nykesha', + 'Orrie', + 'Mozter', + 'Earthalee', + 'Rozena', + 'Anniebell', + 'Hannie', + 'Pretto', + 'Caro', + 'Everlina', + 'Arnetha', + 'Glenora', + 'Asalee', + 'Parniece', + 'Rubena', + 'Wilhemena', + 'Perline', + 'Elloree', + 'Clorine', + 'Richardean', + 'Rovena', + 'Arthuree', + 'Mikea', + 'Charnice', + 'Tylashia', + 'Rebacca', + 'Caretha', + 'Dynasti', + 'Marvie', + 'Hermenia', + 'Tekela', + 'Trenace', + 'Valetta', + 'Topaz', + 'Debara', + 'Jaquasha', + 'Markeria', + 'Alkeria', + 'Salwa', + 'Tatayana', + 'Dianelys', + 'Beyounce', + 'Drena', + 'Julysa', + 'Shuntel', + 'Antasia', + 'Alyze', + 'Marytheresa', + 'Raechelle', + 'Trevia', + 'Tomara', + 'Jermeka', + 'Curtisha', + 'Kebrina', + 'Kayte', + 'Shakeila', + 'Ronnesha', + 'Shavontae', + 'Taquila', + 'Shaquia', + 'Lynnann', + 'Markevia', + 'Terrilynn', + 'Carime', + 'Quaneshia', + 'Shaylen', + 'Corneisha', + 'Rodneshia', + 'Nateria', + 'Marycatherine', + 'Ashlyne', + 'Reyne', + 'Natia', + 'Taquisha', + 'Mikeshia', + 'Khadeja', + 'Lismary', + 'Prisca', + 'Antwonette', + 'Anesia', + 'Clotilda', + 'Willavene', + 'Lovey', + 'Aleda', + 'Karita', + 'Rakiyah', + 'Nyasiah', + 'Timaya', + 'Gabryelle', + 'Caniyah', + 'Ethelreda', + 'Aryelle', + 'Trianna', + 'Yesli', + 'Yareliz', + 'Tanyla', + 'Keyshia', + 'Makinsey', + 'Daily', + 'Caylynn', + 'Kalyse', + 'Sarabelle', + 'Araminta', + 'Magdelene', + 'Kristalyn', + 'Lianni', + 'Layana', + 'Haedyn', + 'Teyona', + 'Taziyah', + 'Ranijah', + 'Darneisha', + 'Jahzaria', + 'Palmyra', + 'Altheda', + 'Armanii', + 'Blodwyn', + 'Colletta', + 'Yelenis', + 'Yazlyn', + 'Leira', + 'Anaysia', + 'Anayiah', + 'Valia', + 'Bambina', + 'Burnetta', + 'Clarabel', + 'Philomenia', + 'Lorma', + 'Janeka', + 'Danaisha', + 'Cayci', + 'Jermia', + 'Idalys', + 'Sarajane', + 'Shakenya', + 'Kashanti', + 'Lanika', + 'Ceira', + 'Deshanti', + 'Adianez', + 'Alannis', + 'Lubov', + 'Aylana', + 'Nephtalie', + 'Harlean', + 'Shelvey', + 'Yalissa', + 'Asianna', + 'Jahnyah', + 'Jahliyah', + 'Ellissa', + 'Gabrianna', + 'Katonya', + 'Elsia', + 'Ketina', + 'Kateena', + 'Claudean', + 'Chenita', + 'Belkys', + 'Kerryn', + 'Teria', + 'Charron', + 'Charnissa', + 'Alura', + 'Bashirah', + 'Gerldine', + 'Katilynn', + 'Trellany', + 'Lacheryl', + 'Twalla', + 'Sharnise', + 'Yoland', + 'Shanai', + 'Ikia', + 'Aquilla', + 'Shalandra', + 'Nekesha', + 'Sonni', + 'Kutana', + 'Sharnay', + 'Timitra', + 'Shareena', + 'Tyeesha', + 'Natara', + 'Amatullah', + 'Nydirah', + 'Shahadah', + 'Inetha', + 'Clatie', + 'Ladye', + 'Makalia', + 'Sabriyah', + 'Graple', + 'Lorell', + 'Vercie', + 'Rayona', + 'Dayshia', + 'Nakirah', + 'Mcneva', + 'Bunia', + 'Brooxie', + 'Delcia', + 'Naje', + 'Eilish', + 'Lashara', + 'Crystall', + 'Shearon', + 'Kafi', + 'Kea', + 'Shantrel', + 'Jeanni', + 'Andreia', + 'Myrlande', + 'Jennifier', + 'Damika', + 'Carloyn', + 'Lashera', + 'Kamika', + 'Chrisann', + 'Lashavia', + 'Ivis', + 'Quinisha', + 'Yanelys', + 'Taralee', + 'Ibis', + 'Jazma', + 'Shakevia', + 'Deneane', + 'Kimala', + 'Casee', + 'Audreana', + 'Shahida', + 'Latangela', + 'Lashira', + 'Lashawndra', + 'Sherrina', + 'Shawntrell', + 'Latronda', + 'Meghaan', + 'Ayasha', + 'Raushanah', + 'Serrita', + 'Tennile', + 'Keyonda', + 'Idalmis', + 'Telicia', + 'Takeia', + 'Aristea', + 'Letesha', + 'Badia', + 'Nykea', + 'Bilan', + 'Ieva', + 'Kimmi', + 'Geniel', + 'Tamberly', + 'Tammee', + 'Sherma', + 'Emira', + 'Agena', + 'Carrin', + 'Ladean', + 'Caera', + 'Shatha', + 'Utahna', + 'Lujean', + 'Joylyn', + 'Kathren', + 'Kristiane', + 'Lenee', + 'Angi', + 'Vichelle', + 'Rochele', + 'Shonnie', + 'Anastasija', + 'Clea', + 'Myrlene', + 'Dniyah', + 'Tashanti', + 'Sireen', + 'Vincie', + 'Wreatha', + 'Josphine', + 'Casimera', + 'Hildagarde', + 'Margeret', + 'Grettell', + 'Greenley', + 'Gloriana', + 'Eyleen', + 'Evaleigh', + 'Davanee', + 'Corley', + 'Liliah', + 'Leanah', + 'Kynzlie', + 'Kynzleigh', + 'Kolette', + 'Lively', + 'Makenlie', + 'Lochlyn', + 'Kinslie', + 'Jleigh', + 'Jeslynn', + 'Jenisis', + 'Jenisha', + 'Kensli', + 'Addalie', + 'Demia', + 'Cele', + 'Aderinsola', + 'Auriella', + 'Blyss', + 'Cashlynn', + 'Callyn', + 'Allyzon', + 'Aleiya', + 'Alazne', + 'Alayzia', + 'Ailah', + 'Annora', + 'Analynn', + 'Leonilda', + 'Minnette', + 'Onolee', + 'Michaelina', + 'Rosemond', + 'Milica', + 'Ednamae', + 'Floribel', + 'Nur', + 'Ndia', + 'Thecla', + 'Immaculate', + 'Mayfred', + 'Selda', + 'Vincenzia', + 'Vitina', + 'Tammatha', + 'Joley', + 'Kelene', + 'Kriste', + 'Liese', + 'Mariaemilia', + 'Lasaundra', + 'Letica', + 'Karene', + 'Devera', + 'Denyce', + 'Dawnn', + 'Maryum', + 'Giovannina', + 'Roze', + 'Reygan', + 'Quinlyn', + 'Stassi', + 'Meelah', + 'Novaleigh', + 'Navey', + 'Mirakle', + 'Naiovy', + 'Munachiso', + 'Montzerrat', + 'Misk', + 'Mireyah', + 'Temiloluwa', + 'Zaiya', + 'Varshini', + 'Tiwatope', + 'Tinlee', + 'Geneve', + 'Kotryna', + 'Janila', + 'Janeah', + 'Mollye', + 'Dody', + 'Doreena', + 'Chelle', + 'Javaeh', + 'Dim', + 'Jamylah', + 'Kamyia', + 'Ramie', + 'Kandie', + 'Kitt', + 'Gaylyn', + 'Marji', + 'Laurena', + 'Lorre', + 'Ronelle', + 'Kresta', + 'Jonylah', + 'Kornelia', + 'Mindie', + 'Kendis', + 'Dorri', + 'Seaneen', + 'Lorilyn', + 'Lolly', + 'Pati', + 'Shalayne', + 'Dorise', + 'Joani', + 'Yailene', + 'Batool', + 'Cyntha', + 'Coni', + 'Kae', + 'Cynia', + 'Rhonna', + 'Lynnetta', + 'Terrisa', + 'Nishi', + 'Delise', + 'Ladena', + 'Bronwen', + 'Tere', + 'Tippi', + 'Peggi', + 'Portland', + 'Sherrin', + 'Tacy', + 'Terie', + 'Dore', + 'Daphane', + 'Juliene', + 'Kamile', + 'Janeil', + 'Megin', + 'Shenandoah', + 'Rashada', + 'Disa', + 'Elita', + 'Kelee', + 'Genee', + 'Taneya', + 'Storie', + 'Sheza', + 'Rielyn', + 'Venicia', + 'Zamyria', + 'Yisell', + 'Appollonia', + 'Meryle', + 'Frann', + 'Lucyann', + 'Clarivel', + 'Marguarite', + 'Nelsa', + 'Reanetta', + 'Roshaunda', + 'Channie', + 'Bathsheba', + 'Jannessa', + 'Jakaylah', + 'Jesalyn', + 'Ellyson', + 'Hally', + 'Haelyn', + 'Gabbie', + 'Emmerie', + 'Makailyn', + 'Maddi', + 'Lirio', + 'Lexee', + 'Matalyn', + 'Kenzee', + 'Kenlei', + 'Kaydi', + 'Kynlei', + 'Krissa', + 'Adalin', + 'Alayiah', + 'Ellice', + 'Caydee', + 'Annalysa', + 'Anisty', + 'Abeni', + 'Aliha', + 'Aerith', + 'Adrie', + 'Peggyann', + 'Pietrina', + 'Amberlie', + 'Dabria', + 'Cylee', + 'Amyriah', + 'Ambry', + 'Berkleigh', + 'Azula', + 'Zaryiah', + 'Zanyia', + 'Gerardine', + 'Joycelynn', + 'Jeslin', + 'Kenzli', + 'Keisi', + 'Kayelynn', + 'Jaselyn', + 'Mckinnley', + 'Maryse', + 'Peightyn', + 'Latausha', + 'Lety', + 'Tekia', + 'Arasely', + 'Arlynne', + 'Noell', + 'Patrcia', + 'Morning', + 'Meika', + 'Tanda', + 'Terasa', + 'Tika', + 'Roshon', + 'Marlaine', + 'Stephaie', + 'Franne', + 'Ewa', + 'Tomeca', + 'Chequita', + 'Dierdra', + 'Doriann', + 'Tammika', + 'Jeananne', + 'Cythia', + 'Laconda', + 'Catiria', + 'Migna', + 'Latiesha', + 'Sharin', + 'Tekesha', + 'Elga', + 'Barbarajean', + 'Ilena', + 'Evett', + 'Timiko', + 'Kachina', + 'Desere', + 'Galadriel', + 'Lynea', + 'Laurajean', + 'Rukiya', + 'Sakara', + 'Snezana', + 'Tashonda', + 'Orquidea', + 'Myshia', + 'Latrease', + 'Monquie', + 'Robina', + 'Vesna', + 'Faline', + 'Glori', + 'Jennel', + 'Keyatta', + 'Dimitria', + 'Uzma', + 'Lalia', + 'Krystiana', + 'Kaedynce', + 'Juany', + 'Kesley', + 'Kennedee', + 'Keeleigh', + 'Paiten', + 'Neelah', + 'Naylee', + 'Sairy', + 'Rocsi', + 'Mckenzey', + 'Modesty', + 'Abbiegail', + 'Jasalyn', + 'Genises', + 'Emmory', + 'Elisea', + 'Dlaney', + 'Haelee', + 'Jadence', + 'Audryana', + 'Carizma', + 'Josanne', + 'Nashira', + 'Meesha', + 'Taneil', + 'Sobeida', + 'Zakyra', + 'Syndee', + 'Zipora', + 'Amita', + 'Bridie', + 'Hilde', + 'Aspasia', + 'Yalexi', + 'Tenleigh', + 'Anjannette', + 'Zniyah', + 'Zayley', + 'Kyerra', + 'Lynnsey', + 'Dashae', + 'Jasha', + 'Anjenette', + 'Lelania', + 'Mija', + 'Lorrene', + 'Shanyn', + 'Shindana', + 'Shamra', + 'Dove', + 'Drina', + 'Caralee', + 'Charmian', + 'Katrine', + 'Lagina', + 'Jahna', + 'Nesita', + 'Teriana', + 'Dajae', + 'Kyiah', + 'Keslyn', + 'Kayelee', + 'Kamberlyn', + 'Raygen', + 'Orchid', + 'Maleigh', + 'Mairim', + 'Amily', + 'Ameli', + 'Alie', + 'Adelai', + 'Eniola', + 'Enaya', + 'Brealynn', + 'Blakleigh', + 'Ayelene', + 'Camrie', + 'Dianely', + 'Delayne', + 'Cortlyn', + 'Jaylei', + 'Jaycelynn', + 'Jaleigha', + 'Iviana', + 'Kaedance', + 'Jewelz', + 'Jillianna', + 'Faithlyn', + 'Isabeau', + 'Irany', + 'Galiana', + 'Makynzee', + 'Maebry', + 'Merit', + 'Mckinzee', + 'Kinzee', + 'Kendrah', + 'Laityn', + 'Amberlin', + 'Ahliyah', + 'Raphaela', + 'Ameri', + 'Brecklynn', + 'Cristabel', + 'Annalucia', + 'Avri', + 'Averly', + 'Shalia', + 'Sheilla', + 'Dejana', + 'Tonnette', + 'Tracia', + 'Trese', + 'Lalanya', + 'Kristiann', + 'Zunaira', + 'Zinachidi', + 'Xayla', + 'Zaybree', + 'Zanae', + 'Xoey', + 'Sirenity', + 'Renesme', + 'Raeley', + 'Preslyn', + 'Nyx', + 'Nyelli', + 'Rozalynn', + 'Safaa', + 'Abaigeal', + 'Perle', + 'Ersilia', + 'Ethlyn', + 'Dashanae', + 'Dajana', + 'Tahja', + 'Shavona', + 'Vernisha', + 'Sunya', + 'Zenorah', + 'Dorota', + 'Ramsha', + 'Nirali', + 'Najia', + 'Maryclaire', + 'Ismay', + 'Alfonsina', + 'Letizia', + 'Lotta', + 'Honore', + 'Jamille', + 'Kashe', + 'Bonnielee', + 'Lorelle', + 'Gloriajean', + 'Trenae', + 'Tonesha', + 'Maxene', + 'Aliz', + 'Annelyse', + 'Avagrace', + 'Adanelly', + 'Dariella', + 'Colbi', + 'Tema', + 'Marlea', + 'Elleen', + 'Veroncia', + 'Shelina', + 'Sundae', + 'Jericca', + 'Liduvina', + 'Jenney', + 'Pascha', + 'Roshell', + 'Marlies', + 'Marny', + 'Judithann', + 'Nancylee', + 'Freyda', + 'Joyceann', + 'Caroleann', + 'Desirie', + 'Christol', + 'Shulamith', + 'Marlise', + 'Rocquel', + 'Tamsen', + 'Sukari', + 'Tinna', + 'Magdelena', + 'Ruba', + 'Patra', + 'Erryn', + 'Buffi', + 'Chantil', + 'Kerensa', + 'Annastacia', + 'Zailee', + 'Lamika', + 'Kashlynn', + 'Jaedynn', + 'Kaly', + 'Paisyn', + 'Seraiah', + 'Mckenzye', + 'Nhyla', + 'Chandrika', + 'Dawana', + 'Elesha', + 'Caryle', + 'Karrin', + 'Valency', + 'Kianga', + 'Shawndee', + 'Tamasha', + 'Rhodora', + 'Shivangi', + 'Vermont', + 'Diasia', + 'Aniyyah', + 'Azhane', + 'Katleyn', + 'Tynetta', + 'Negan', + 'Marilyne', + 'Leronia', + 'Charmie', + 'Lateefa', + 'Hassanah', + 'Louvinia', + 'Shirly', + 'Sanjna', + 'Andelyn', + 'Jaima', + 'Aftyn', + 'Atira', + 'Weslie', + 'Tayzlee', + 'Rossi', + 'Nayvie', + 'Livvy', + 'Brinklee', + 'Drinda', + 'Nazirah', + 'Krithika', + 'Taisley', + 'Starlee', + 'Bijal', + 'Hiral', + 'Gwynn', + 'Orlene', + 'Maurene', + 'Sweta', + 'Naasia', + 'Luvinia', + 'Sayoko', + 'Geannie', + 'Rupal', + 'Zerlina', + 'Nobu', + 'Taeko', + 'Miye', + 'Carnation', + 'Joplin', + 'Yayeko', + 'Sakaye', + 'Ernell', + 'Tazuko', + 'Bayyinah', + 'Konstantina', + 'Danuta', + 'Cariann', + 'Charnette', + 'Michiye', + 'Tejal', + 'Shaheedah', + 'Zakkiyya', + 'Latoyah', + 'Audre', + 'Tayeko', + 'Qadriyyah', + 'Nikema', + 'Wadeeah', + 'Quanika', + 'Fareeda', + 'Ivelis', + 'Karigan', + 'Yayoi', + 'Tauni', + 'Shailee', + 'Ronnah', + 'Roseana', + 'Rosalita', + 'Orlidia', + 'Mckall', + 'Seattle', + 'Lauree', + 'Georgi', + 'Jacolyn', + 'Meichele', + 'Starlet', + 'Shandee', + 'Miquelle', + 'Cathe', + 'Nondas', + 'Roben', + 'Manette', + 'Monzelle', + 'Genieve', + 'Rumaysa', + 'Dariya', + 'Brynnleigh', + 'Vicci', + 'Sharli', + 'Chandi', + 'Guadelupe', + 'Jamilyn', + 'Willadene', + 'Centhia', + 'Cheryal', + 'Normalee', + 'Wilmajean', + 'Roanne', + 'Dyane', + 'Jinx', + 'Jorene', + 'Ceceilia', + 'Arikka', + 'Latanza', + 'Lacinda', + 'Rus', + 'Sangeeta', + 'Demita', + 'Jerene', + 'Marcellina', + 'Zani', + 'Izzabelle', + 'Graycee', + 'Sajada', + 'Quinlee', + 'Brooklee', + 'Shulamis', + 'Bunnie', + 'Michaelyn', + 'Dhruvi', + 'Sreeja', + 'Tzipa', + 'Doreene', + 'Bedelia', + 'Eutimia', + 'Tomacita', + 'Jerra', + 'Rosela', + 'Ignacita', + 'Conferina', + 'Andreita', + 'Lugardita', + 'Estefanita', + 'Suetta', + 'Debbe', + 'Amadita', + 'Mardel', + 'Mliss', + 'Korla', + 'Felipita', + 'Erminda', + 'Chrys', + 'Karthika', + 'Guilianna', + 'Chasya', + 'Bryndee', + 'Taeler', + 'Sinforosa', + 'Brinnley', + 'Aviya', + 'Jayma', + 'Zimal', + 'Vivia', + 'Arielis', + 'Arshiya', + 'Adiba', + 'Afreen', + 'Ajooni', + 'Alianny', + 'Fariza', + 'Breina', + 'Sila', + 'Aaima', + 'Amesha', + 'Antigone', + 'Kayse', + 'Aurelie', + 'Marianny', + 'Naba', + 'Salimata', + 'Retal', + 'Pema', + 'Pesha', + 'Reemas', + 'Emunah', + 'Farzeen', + 'Safina', + 'Sema', + 'Seynabou', + 'Roza', + 'Romaisa', + 'Yehudit', + 'Tzivi', + 'Tzivy', + 'Zahro', + 'Jeylen', + 'Klea', + 'Namirah', + 'Lamiah', + 'Mahjabeen', + 'Daielle', + 'Ogechi', + 'Laresha', + 'Laqueta', + 'Anayla', + 'Bashy', + 'Naeema', + 'Sarrinah', + 'Sevinch', + 'Frimmy', + 'Hibba', + 'Fajr', + 'Rayhona', + 'Rokia', + 'Wafa', + 'Britne', + 'Crystalann', + 'Reah', + 'Maggi', + 'Lenae', + 'Kambra', + 'Tabita', + 'Tamlyn', + 'Thuytien', + 'Titianna', + 'Trenisha', + 'Yuan', + 'Yarithza', + 'Yarixa', + 'Satin', + 'Elizeth', + 'Gabiela', + 'Jackline', + 'Janisa', + 'Graviela', + 'Gudalupe', + 'Hena', + 'Bryanda', + 'Avilene', + 'Ayerim', + 'Breiana', + 'Nicoleanne', + 'Merisa', + 'Relina', + 'Rebecah', + 'Rachyl', + 'Kasaundra', + 'Katryn', + 'Jeaneth', + 'Jenah', + 'Jocely', + 'Jorgina', + 'Lindsee', + 'Lizvette', + 'Oleen', + 'Waveline', + 'Laurabelle', + 'Charma', + 'Gleneva', + 'Yesika', + 'Felina', + 'Nguyet', + 'Krissie', + 'Silvina', + 'Stephanny', + 'Teera', + 'Kristol', + 'Karisha', + 'Lorisa', + 'Iracema', + 'Temesha', + 'Tamber', + 'Shelisa', + 'Roshana', + 'Rheannon', + 'Amala', + 'Anabelen', + 'Daizhane', + 'Darbie', + 'Dezaree', + 'Dezhane', + 'Carrina', + 'Chessa', + 'Christinejoy', + 'Aliea', + 'Adalhi', + 'Alexandrina', + 'Abrina', + 'Madaleine', + 'Maressa', + 'Marki', + 'Koryna', + 'Lilibet', + 'Mystic', + 'Neyra', + 'Ivonna', + 'Jenalyn', + 'Truc', + 'Berneta', + 'Quinci', + 'Rachelanne', + 'Raylina', + 'Nykole', + 'Stephaney', + 'Seleni', + 'Marvene', + 'Melizza', + 'Aimme', + 'Anaissa', + 'Anhelica', + 'Celyna', + 'Azalie', + 'Bereniz', + 'Meliss', + 'Leanza', + 'Lenina', + 'Karrina', + 'Kalynne', + 'Kanwal', + 'Kazzandra', + 'Mandalyn', + 'Limairy', + 'Lizzete', + 'Lyly', + 'Coua', + 'Icsel', + 'Izamary', + 'Lakindra', + 'Rosezella', + 'Wilhelmine', + 'Clela', + 'Marvelle', + 'Jenafer', + 'Katye', + 'Eliabeth', + 'Angelicamaria', + 'Adrieanna', + 'Caludia', + 'Caycee', + 'Chenay', + 'Cherika', + 'Arpine', + 'Kimberlyanne', + 'Jully', + 'Jyoti', + 'Mariha', + 'Meganelizabeth', + 'Melysa', + 'Lashanay', + 'Jericha', + 'Eliset', + 'Esmirna', + 'Clarie', + 'Conny', + 'Derrisha', + 'Frania', + 'Jeena', + 'Gresia', + 'Hlee', + 'Emanie', + 'Liany', + 'Aisatou', + 'Ashya', + 'Nefertari', + 'Nyanna', + 'Mariem', + 'Michellee', + 'Amenda', + 'Markella', + 'Kiyara', + 'Issamar', + 'Cecilee', + 'Rehana', + 'Nube', + 'Simy', + 'Laneshia', + 'Vasthi', + 'Treanna', + 'Tria', + 'Tuongvi', + 'Brany', + 'Niza', + 'Shandale', + 'Shanley', + 'Shastina', + 'Sheyna', + 'Ronniesha', + 'Rubit', + 'Ruvi', + 'Siobhain', + 'Shauntal', + 'Linzie', + 'Linzi', + 'Fatimatou', + 'Efrat', + 'Jasmely', + 'Kadidia', + 'Kamily', + 'Meirav', + 'Areebah', + 'Fatim', + 'Nuzhat', + 'Saribel', + 'Zorah', + 'Ting', + 'Laporscha', + 'Mieshia', + 'Vanecia', + 'Brittne', + 'Denetria', + 'Deamber', + 'Cymone', + 'Arieal', + 'Araly', + 'Shamieka', + 'Deshay', + 'Britainy', + 'Matraca', + 'Krystyne', + 'Kristela', + 'Kindell', + 'Ceyda', + 'Jahnasia', + 'Halimatou', + 'Graciana', + 'Haja', + 'Safiatou', + 'Su', + 'Zaineb', + 'Yianna', + 'Shilat', + 'Zanai', + 'Zeinabou', + 'Jalysa', + 'Garcia', + 'Jinna', + 'Brytni', + 'Crystalmarie', + 'Kyrstie', + 'Labrea', + 'Laurita', + 'Kathleena', + 'Salimatou', + 'Martisha', + 'Damisha', + 'Londin', + 'Toree', + 'Yadria', + 'Yaminah', + 'Nili', + 'Pella', + 'Menna', + 'Minah', + 'Porshay', + 'Rahwa', + 'Parissa', + 'Nury', + 'Sheeva', + 'Sendi', + 'Aroush', + 'Jerlyn', + 'Momina', + 'Nylia', + 'Mahreen', + 'Mattingly', + 'Emanuella', + 'Ceylin', + 'Biana', + 'Ishrat', + 'Genendy', + 'Hindel', + 'Chavi', + 'Freidy', + 'Rouguiatou', + 'Osnas', + 'Yagmur', + 'Yitel', + 'Hudy', + 'Jamielynn', + 'Valyncia', + 'Cheyla', + 'Assa', + 'Tasmia', + 'Yaslene', + 'Zaima', + 'Jenisse', + 'Juliannah', + 'Reveca', + 'Amra', + 'Anaria', + 'Arlenis', + 'Anastassia', + 'Anique', + 'Arilene', + 'Adileni', + 'Chelcy', + 'Chelesa', + 'Columba', + 'Corri', + 'Briane', + 'Carine', + 'Deziah', + 'Jojo', + 'Jaidalyn', + 'Cecelie', + 'Meagon', + 'Raysha', + 'Mylinh', + 'Madelena', + 'Saniyya', + 'Shama', + 'Shifa', + 'Nyala', + 'Lafaun', + 'Ronnetta', + 'Rondia', + 'Christe', + 'Tynnetta', + 'Ethyle', + 'Bobi', + 'Rayetta', + 'Wilmina', + 'Tangala', + 'Chloris', + 'Marvyl', + 'Larinda', + 'Narcedalia', + 'Tiaa', + 'Terressa', + 'Missi', + 'Ardythe', + 'Briget', + 'Julya', + 'Emilyanne', + 'Ayano', + 'Eliane', + 'Tatem', + 'Roselani', + 'Zareen', + 'Yaxeni', + 'Marleena', + 'Nicolemarie', + 'Patzy', + 'Morgana', + 'Mirca', + 'Mystica', + 'Rosaicela', + 'Rosaysela', + 'Serrena', + 'Shiori', + 'Yannely', + 'Threasa', + 'Zohra', + 'Lanitra', + 'Laquinthia', + 'Deshundra', + 'Mirasol', + 'Lladira', + 'Tejuana', + 'Michaelann', + 'Normajean', + 'Leasha', + 'Kajuana', + 'Xianna', + 'Yaquelyn', + 'Marcea', + 'Mohini', + 'Jaysha', + 'Saysha', + 'Makamae', + 'Lynnett', + 'Mistee', + 'Kaysee', + 'Lizel', + 'Kiora', + 'Kla', + 'Lanay', + 'Kainani', + 'Pomaikai', + 'Piilani', + 'Aulii', + 'Khristi', + 'Delfa', + 'Toka', + 'Satonya', + 'Jammi', + 'Iolani', + 'Hinaea', + 'Ilihia', + 'Kulia', + 'Darcus', + 'Raejean', + 'Brisamar', + 'Francessca', + 'Dhamar', + 'Lehiwa', + 'Ajane', + 'Alexsys', + 'Jema', + 'Imara', + 'Itzanami', + 'Ivori', + 'Tabby', + 'Charnell', + 'Vanessamarie', + 'Vibiana', + 'Kameisha', + 'Edica', + 'Shanetra', + 'Shametria', + 'Quinette', + 'Abreanna', + 'Corazon', + 'Correna', + 'Lilac', + 'Najwa', + 'Moranda', + 'Monik', + 'Deise', + 'Edid', + 'Karinne', + 'Ilsa', + 'Irazema', + 'Pegge', + 'Chenique', + 'Temisha', + 'Cristella', + 'Christle', + 'Falan', + 'Mekesha', + 'Jonquil', + 'Latarya', + 'Maretta', + 'Sonceria', + 'Latamara', + 'Ladina', + 'Rozann', + 'Suz', + 'Aleja', + 'Wray', + 'Indica', + 'Harkiran', + 'Gemini', + 'Erikah', + 'Fey', + 'Gudelia', + 'Komalpreet', + 'Anah', + 'Angelicamarie', + 'Cammi', + 'Dejane', + 'Dejanay', + 'Cilicia', + 'Merla', + 'Janann', + 'Maurita', + 'Aireana', + 'Shuronda', + 'Shunte', + 'Lacrisha', + 'Kwana', + 'Krisi', + 'Kaysi', + 'Latressa', + 'Tyronza', + 'Debralee', + 'Crissie', + 'Crissa', + 'Jameca', + 'Alicha', + 'Ketra', + 'Chrisie', + 'Delecia', + 'Rokisha', + 'Natoshia', + 'Shajuana', + 'Jenipher', + 'Jenefer', + 'Anjanae', + 'Azita', + 'Clairissa', + 'Brezhane', + 'Keera', + 'Siarah', + 'Smita', + 'Savonna', + 'Raquelin', + 'Lorren', + 'Omunique', + 'Molina', + 'Nixaliz', + 'Melitza', + 'Shylo', + 'Teniqua', + 'Charmine', + 'Deonne', + 'Kima', + 'Galit', + 'Ikesha', + 'Jamala', + 'Cherl', + 'Ageliki', + 'Ydania', + 'Kortlyn', + 'Lisvet', + 'Khya', + 'Kearstyn', + 'Seline', + 'Stormey', + 'Rehma', + 'Mckynna', + 'Brynnan', + 'Abiola', + 'Ambriel', + 'Akaysha', + 'Hailea', + 'Fryda', + 'Fedra', + 'Dacie', + 'Deissy', + 'Deyna', + 'Mayling', + 'Tessy', + 'Yaa', + 'Shameca', + 'Shivon', + 'Taesha', + 'Dinamarie', + 'Ifeoma', + 'Ashlye', + 'Patriciajo', + 'Danute', + 'Amalyn', + 'Nakeia', + 'Takima', + 'Shavonn', + 'Katira', + 'Lakema', + 'Jahaida', + 'Marshelle', + 'Angeliki', + 'Carrianne', + 'Carrieanne', + 'Tarika', + 'Sherece', + 'Kalimah', + 'Kinda', + 'Sadiga', + 'Paraskevi', + 'Ayianna', + 'Alezay', + 'Cadynce', + 'Haely', + 'Heavenleigh', + 'Dajanique', + 'Lasharn', + 'Drita', + 'Genene', + 'Gittle', + 'Carriann', + 'Emerita', + 'Jenniferann', + 'Kammie', + 'Bryony', + 'Rupinder', + 'Tenise', + 'Yazmyn', + 'Maricris', + 'Rhianon', + 'Nicolet', + 'Mui', + 'Nacy', + 'Naoko', + 'Gaila', + 'Charene', + 'Bas', + 'Geni', + 'Lorez', + 'Taneeka', + 'Tanikqua', + 'Tulani', + 'Sotiria', + 'Sheeba', + 'Katiuscia', + 'Eleftheria', + 'Ghislaine', + 'Jamiylah', + 'Omotayo', + 'Yuleidy', + 'Tylene', + 'Zanetta', + 'Yizza', + 'Ngan', + 'Natassha', + 'Sophear', + 'Starkisha', + 'Stehanie', + 'Jasie', + 'Aprile', + 'Billiejean', + 'Wilnelia', + 'Yaasmiyn', + 'Ednita', + 'Engracia', + 'Grisell', + 'Christinamarie', + 'Eftihia', + 'Jenniefer', + 'Chantee', + 'Afua', + 'Shamea', + 'Shamina', + 'Vickiana', + 'Sharoya', + 'Shateema', + 'Aubrea', + 'Alexcis', + 'Wallis', + 'Jalyne', + 'Harlea', + 'Carisia', + 'Cheynne', + 'Daylee', + 'Kyera', + 'Latayvia', + 'Raashida', + 'Saajida', + 'Nakema', + 'Annalyssa', + 'Chivonne', + 'Lyndie', + 'Sabrian', + 'Rahcel', + 'Hoai', + 'Krisann', + 'Jilliane', + 'Saide', + 'Matti', + 'Raigen', + 'Tenea', + 'Staphanie', + 'Zitlally', + 'Yudelca', + 'Raysa', + 'Monea', + 'Shanigua', + 'Shirah', + 'Chemise', + 'Jajaira', + 'Tunisha', + 'Yelissa', + 'Yudelka', + 'Taria', + 'Taralynn', + 'Condol', + 'Nikima', + 'Syrianna', + 'Anndrea', + 'Charae', + 'Ebelia', + 'Comfort', + 'Denishia', + 'Lanyia', + 'Lahna', + 'Iraima', + 'Josaline', + 'Onyinyechi', + 'Mykalah', + 'Shamyia', + 'Sarely', + 'Makaylie', + 'Madasyn', + 'Carron', + 'Shawnetta', + 'Dorca', + 'Subrena', + 'Romanda', + 'Sallyanne', + 'Ahniyah', + 'Annalissa', + 'Anikah', + 'Anet', + 'Emelee', + 'Branae', + 'Rosemaria', + 'Kimerly', + 'Lorra', + 'Breda', + 'Graceanne', + 'Kathyann', + 'Letetia', + 'Allaina', + 'Anaceli', + 'Brendalee', + 'Aidaly', + 'Arlana', + 'Trinetta', + 'Tennesha', + 'Talonda', + 'Sherrilynn', + 'Maloree', + 'Laiya', + 'Kynlea', + 'Ludwika', + 'Raeli', + 'Yadirah', + 'Yveth', + 'Sabrie', + 'Dannielynn', + 'Breely', + 'Jozlin', + 'Jewelyssa', + 'Keylie', + 'Jazzalyn', + 'Ijeoma', + 'Jaydie', + 'Irianna', + 'Ronya', + 'Lynee', + 'Myrian', + 'Cristalle', + 'Delinah', + 'Arnetia', + 'Guisela', + 'Orna', + 'Samehesha', + 'Scherrie', + 'Marylynne', + 'Judianne', + 'Tomasina', + 'Sanora', + 'Cheray', + 'Gordana', + 'Torina', + 'Yolandra', + 'Tyese', + 'Sharine', + 'Marea', + 'Areti', + 'Sharmila', + 'Charrise', + 'Cyndia', + 'Cinzia', + 'Gecenia', + 'Tarshia', + 'Luwanda', + 'Negar', + 'Sharah', + 'Sherah', + 'Sokha', + 'Marium', + 'Taslin', + 'Taleyah', + 'Parys', + 'Odeth', + 'Mirabai', + 'Myree', + 'Tyhesha', + 'Soyini', + 'Liria', + 'Jenille', + 'Marivic', + 'Mey', + 'Adrena', + 'Cristyn', + 'Jodette', + 'Ilea', + 'Jennett', + 'Latoi', + 'Charrisse', + 'Correne', + 'Reannon', + 'Shanah', + 'Shavaun', + 'Shelena', + 'Macrina', + 'Lashonna', + 'Tecia', + 'Zobeida', + 'Casilda', + 'Ketsy', + 'Lizza', + 'Lucesita', + 'Anelis', + 'Amori', + 'Atlantis', + 'Aslynn', + 'Kimbery', + 'Yolunda', + 'Pasqua', + 'Magalis', + 'Yanellie', + 'Tryniti', + 'Tniya', + 'Ziza', + 'Nadina', + 'Lloana', + 'Shoshannah', + 'Tamarie', + 'Ronique', + 'Keatyn', + 'Matison', + 'Micalah', + 'Nataya', + 'Mama', + 'Bailea', + 'Sidrah', + 'Jazzman', + 'Deanndra', + 'Shawniece', + 'Polett', + 'Rathana', + 'Timisha', + 'Tristina', + 'Vanezza', + 'Shiri', + 'Stephanieann', + 'Genessy', + 'Hema', + 'Huma', + 'Alessandria', + 'Yarisa', + 'Oyindamola', + 'Tianni', + 'Monasia', + 'Kely', + 'Khady', + 'Pegah', + 'Casarah', + 'Cassara', + 'Chalise', + 'Arti', + 'Natanya', + 'Masuma', + 'Shellyann', + 'Taje', + 'Saher', + 'Kelsye', + 'Odaly', + 'Talicia', + 'Mollee', + 'Tashea', + 'Shima', + 'Janaia', + 'Jenia', + 'Jharline', + 'Chabely', + 'Chalon', + 'Charnesha', + 'Christna', + 'Melika', + 'Melis', + 'Lesleyann', + 'Maleeka', + 'Krystalyn', + 'Krystalynn', + 'Marnisha', + 'Mariele', + 'Michelleann', + 'Melessa', + 'Diasy', + 'Dioselina', + 'Jenita', + 'Jaynae', + 'Jeanae', + 'Hripsime', + 'Janete', + 'Lanique', + 'Ashlon', + 'Aroosa', + 'Enisa', + 'Danaysha', + 'Briani', + 'Arjeta', + 'Sapir', + 'Naysha', + 'Kharisma', + 'Laterra', + 'Yannet', + 'Aruna', + 'Anaja', + 'Fahima', + 'Dasmine', + 'Amberlea', + 'Latiera', + 'Kimanh', + 'Mayuri', + 'Meshelle', + 'Morgane', + 'Nahal', + 'Mariacristina', + 'Marlisha', + 'Elaura', + 'Kacia', + 'Neesha', + 'Tila', + 'Waynisha', + 'Witney', + 'Niloofar', + 'Solina', + 'Soo', + 'Stphanie', + 'Shanesha', + 'Sharrell', + 'Nene', + 'Bleona', + 'Hudes', + 'Isatu', + 'Aylssa', + 'Camerina', + 'Arrielle', + 'Allycia', + 'Anacecilia', + 'Anairis', + 'Courney', + 'Dashanique', + 'Cedrina', + 'Celida', + 'Taaliyah', + 'Clarrissa', + 'Egla', + 'Duyen', + 'Kendle', + 'Janil', + 'Adeola', + 'Jazmene', + 'Leesha', + 'Lyzeth', + 'Madeley', + 'Khrystyna', + 'Charisa', + 'Crystelle', + 'Carinna', + 'Channy', + 'Flory', + 'Glenisha', + 'Sheida', + 'Naara', + 'Nassim', + 'Ngozi', + 'Nidya', + 'Marche', + 'Mariaesther', + 'Shaleena', + 'Kioni', + 'Nayab', + 'Nzinga', + 'Fizza', + 'Diavion', + 'Zanib', + 'Tionni', + 'Temitope', + 'Nasreen', + 'Melaysia', + 'Maame', + 'Sameen', + 'Azka', + 'Basma', + 'Virjean', + 'Jarmila', + 'Louren', + 'Mckenize', + 'Malyn', + 'Mercadies', + 'Vika', + 'Suong', + 'Mariadel', + 'Mariatheresa', + 'Marison', + 'Meleane', + 'Shabana', + 'Salote', + 'Raquell', + 'Rekha', + 'Sibel', + 'Shavaughn', + 'Shaquoia', + 'Shatera', + 'Fatina', + 'Jestina', + 'Latasia', + 'Geraldin', + 'Shirleymae', + 'Lubna', + 'Maxiel', + 'Naquasha', + 'Dalissa', + 'Chaniqua', + 'Chanele', + 'Jahlisa', + 'Faatimah', + 'Abagayle', + 'Adwoa', + 'Angeliqu', + 'Gelisa', + 'Bradi', + 'Shantice', + 'Sharece', + 'Nyiesha', + 'Yanill', + 'Yocasta', + 'Stepheni', + 'Suleika', + 'Takeema', + 'Kerrilyn', + 'Jamiyla', + 'Josephin', + 'Margarit', + 'Ilaisaane', + 'Jamilee', + 'Corvette', + 'Janitza', + 'Lexey', + 'Jazzmyne', + 'Kirstan', + 'Kattia', + 'Yatzary', + 'Pricsilla', + 'Gisette', + 'Panayiota', + 'Pinar', + 'Rasheida', + 'Tiffay', + 'Venisha', + 'Jennier', + 'Margulia', + 'Katima', + 'Anjoli', + 'Evelise', + 'Chetara', + 'Jaquelynn', + 'Pessie', + 'Quintessa', + 'Orit', + 'Nelissa', + 'Shekia', + 'Sherrise', + 'Abbye', + 'Imagine', + 'Britlyn', + 'Baley', + 'Tanequa', + 'Tanique', + 'Nocole', + 'Sokhom', + 'Krystelle', + 'Marqui', + 'Mariaangelica', + 'Raiven', + 'Nini', + 'Lesliee', + 'Crystalee', + 'Amadi', + 'Suzett', + 'Thelda', + 'Wladyslawa', + 'Shaqueen', + 'Shayra', + 'Domingue', + 'Garine', + 'Johnanna', + 'Karia', + 'Jany', + 'Ardele', + 'Bilma', + 'Lindita', + 'Lisbel', + 'Lyasia', + 'Kianie', + 'Saidah', + 'Niasha', + 'Chantele', + 'Brette', + 'Cydnie', + 'Chealsea', + 'Jaritsa', + 'Hanaa', + 'Jordain', + 'Kerria', + 'Shannara', + 'Shaquna', + 'Sultana', + 'Tajana', + 'Taquasha', + 'Queenasia', + 'Wandalee', + 'Mikalyn', + 'Jossette', + 'Jazsmine', + 'Keairra', + 'Arleny', + 'Selest', + 'Sabryn', + 'Jilliann', + 'Janin', + 'Kayliegh', + 'Alyss', + 'Asuka', + 'Chenin', + 'Eiliana', + 'Fahm', + 'Cyndle', + 'Daniesha', + 'Saranda', + 'Shany', + 'Veridiana', + 'Yanai', + 'Melanieann', + 'Mishell', + 'Mariadelosangel', + 'Rupa', + 'Orabelle', + 'Taquasia', + 'Tyquasia', + 'Cecillia', + 'Jeanet', + 'Lucely', + 'Kar', + 'Niaja', + 'Naquana', + 'Joanny', + 'Anjelique', + 'Aquasia', + 'Ardita', + 'Jatasia', + 'Donika', + 'Fantasha', + 'Dominiqua', + 'Elecia', + 'Deyra', + 'Erial', + 'Bayle', + 'Ninoska', + 'Jonee', + 'Jullisa', + 'Lavasia', + 'Laniqua', +]; diff --git a/drizzle-seed/src/datasets/jobsTitles.ts b/drizzle-seed/src/datasets/jobsTitles.ts new file mode 100644 index 000000000..74ef3146a --- /dev/null +++ b/drizzle-seed/src/datasets/jobsTitles.ts @@ -0,0 +1,149 @@ +export default [ + 'Digital marketing specialist', + 'Web developer', + 'Operations manager', + 'Network engineer', + 'Event manager', + 'Software tester', + 'Teacher', + 'Ux/ui designer', + 'Wedding planner', + 'Qa analyst', + 'Litigation attorney', + 'Mechanical engineer', + 'Network administrator', + 'Account manager', + 'Brand manager', + 'Social worker', + 'Social media coordinator', + 'Email marketing specialist', + 'Hr generalist', + 'Legal assistant', + 'Nurse practitioner', + 'Account director', + 'Software engineer', + 'Purchasing agent', + 'Sales consultant', + 'Civil engineer', + 'Network security specialist', + 'Ui developer', + 'Financial planner', + 'Event planner', + 'Psychologist', + 'Electrical designer', + 'Data analyst', + 'Technical writer', + 'Tax consultant', + 'Account executive', + 'Systems administrator', + 'Database administrator', + 'Research analyst', + 'Data entry clerk', + 'Registered nurse', + 'Investment analyst', + 'Speech therapist', + 'Sales manager', + 'Landscape architect', + 'Key account manager', + 'Ux researcher', + 'Investment banker', + 'It support specialist', + 'Art director', + 'Software developer', + 'Project manager', + 'Customer service manager', + 'Procurement manager', + 'Substance abuse counselor', + 'Supply chain analyst', + 'Data engineer', + 'Accountant', + 'Sales representative', + 'Environmental consultant', + 'Electrical engineer', + 'Systems engineer', + 'Art teacher', + 'Human resources manager', + 'Inventory analyst', + 'Legal counsel', + 'Database developer', + 'Procurement specialist', + 'Systems analyst', + 'Copywriter', + 'Content writer', + 'Hr coordinator', + 'Business development manager', + 'Java developer', + 'Supply chain manager', + 'Event coordinator', + 'Family nurse practitioner', + 'Front-end engineer', + 'Customer success manager', + 'Procurement coordinator', + 'Urban planner', + 'Architectural designer', + 'Financial analyst', + 'Environmental engineer', + 'Back-end developer', + 'Structural engineer', + 'Market research analyst', + 'Customer service representative', + 'Customer support specialist', + 'Business analyst', + 'Social media manager', + 'Family lawyer', + 'Chemical analyst', + 'Network technician', + 'Interior designer', + 'Software architect', + 'Nurse manager', + 'Veterinarian', + 'Process engineer', + 'It manager', + 'Quality assurance analyst', + 'Pharmaceutical sales representative', + 'Office manager', + 'Architect', + 'Physician assistant', + 'Marketing director', + 'Front-end developer', + 'Research scientist', + 'Executive assistant', + 'Hr manager', + 'Marketing manager', + 'Public relations specialist', + 'Financial controller', + 'Investment advisor', + 'Aerospace engineer', + 'Marketing analyst', + 'Paralegal', + 'Landscape designer', + 'Web designer', + 'Occupational therapist', + 'Legal advisor', + 'Marketing coordinator', + 'Dental hygienist', + 'Sem specialist', + 'Seo specialist', + 'Pediatrician', + 'Qa engineer', + 'Data scientist', + 'Financial advisor', + 'Personal assistant', + 'Seo analyst', + 'Network analyst', + 'Mechanical designer', + 'Marketing specialist', + 'Graphic designer', + 'Finance manager', + 'Physical therapist', + 'Product designer', + 'Administrative assistant', + 'Brand ambassador', + 'Project coordinator', + 'Product manager', + 'It administrator', + 'Sales associate', + 'Chemical engineer', + 'Legal secretary', + 'Market analyst', +]; diff --git a/drizzle-seed/src/datasets/lastNames.ts b/drizzle-seed/src/datasets/lastNames.ts new file mode 100644 index 000000000..f69f2c629 --- /dev/null +++ b/drizzle-seed/src/datasets/lastNames.ts @@ -0,0 +1,50000 @@ +export default [ + 'Smith', + 'Johnson', + 'Williams', + 'Brown', + 'Jones', + 'Miller', + 'Davis', + 'Garcia', + 'Rodriguez', + 'Wilson', + 'Martinez', + 'Anderson', + 'Taylor', + 'Thomas', + 'Hernandez', + 'Moore', + 'Martin', + 'Jackson', + 'Thompson', + 'White', + 'Lopez', + 'Lee', + 'Gonzalez', + 'Harris', + 'Clark', + 'Lewis', + 'Robinson', + 'Walker', + 'Perez', + 'Hall', + 'Young', + 'Allen', + 'Sanchez', + 'Wright', + 'King', + 'Scott', + 'Green', + 'Baker', + 'Adams', + 'Nelson', + 'Hill', + 'Ramirez', + 'Campbell', + 'Mitchell', + 'Roberts', + 'Carter', + 'Phillips', + 'Evans', + 'Turner', + 'Torres', + 'Parker', + 'Collins', + 'Edwards', + 'Stewart', + 'Flores', + 'Morris', + 'Nguyen', + 'Murphy', + 'Rivera', + 'Cook', + 'Rogers', + 'Morgan', + 'Peterson', + 'Cooper', + 'Reed', + 'Bailey', + 'Bell', + 'Gomez', + 'Kelly', + 'Howard', + 'Ward', + 'Cox', + 'Diaz', + 'Richardson', + 'Wood', + 'Watson', + 'Brooks', + 'Bennett', + 'Gray', + 'James', + 'Reyes', + 'Cruz', + 'Hughes', + 'Price', + 'Myers', + 'Long', + 'Foster', + 'Sanders', + 'Ross', + 'Morales', + 'Powell', + 'Sullivan', + 'Russell', + 'Ortiz', + 'Jenkins', + 'Gutierrez', + 'Perry', + 'Butler', + 'Barnes', + 'Fisher', + 'Henderson', + 'Coleman', + 'Simmons', + 'Patterson', + 'Jordan', + 'Reynolds', + 'Hamilton', + 'Graham', + 'Kim', + 'Gonzales', + 'Alexander', + 'Ramos', + 'Wallace', + 'Griffin', + 'West', + 'Cole', + 'Hayes', + 'Chavez', + 'Gibson', + 'Bryant', + 'Ellis', + 'Stevens', + 'Murray', + 'Ford', + 'Marshall', + 'Owens', + 'Mcdonald', + 'Harrison', + 'Ruiz', + 'Kennedy', + 'Wells', + 'Alvarez', + 'Woods', + 'Mendoza', + 'Castillo', + 'Olson', + 'Webb', + 'Washington', + 'Tucker', + 'Freeman', + 'Burns', + 'Henry', + 'Vasquez', + 'Snyder', + 'Simpson', + 'Crawford', + 'Jimenez', + 'Porter', + 'Mason', + 'Shaw', + 'Gordon', + 'Wagner', + 'Hunter', + 'Romero', + 'Hicks', + 'Dixon', + 'Hunt', + 'Palmer', + 'Robertson', + 'Black', + 'Holmes', + 'Stone', + 'Meyer', + 'Boyd', + 'Mills', + 'Warren', + 'Fox', + 'Rose', + 'Rice', + 'Moreno', + 'Schmidt', + 'Patel', + 'Ferguson', + 'Nichols', + 'Herrera', + 'Medina', + 'Ryan', + 'Fernandez', + 'Weaver', + 'Daniels', + 'Stephens', + 'Gardner', + 'Payne', + 'Kelley', + 'Dunn', + 'Pierce', + 'Arnold', + 'Tran', + 'Spencer', + 'Peters', + 'Hawkins', + 'Grant', + 'Hansen', + 'Castro', + 'Hoffman', + 'Hart', + 'Elliott', + 'Cunningham', + 'Knight', + 'Bradley', + 'Carroll', + 'Hudson', + 'Duncan', + 'Armstrong', + 'Berry', + 'Andrews', + 'Johnston', + 'Ray', + 'Lane', + 'Riley', + 'Carpenter', + 'Perkins', + 'Aguilar', + 'Silva', + 'Richards', + 'Willis', + 'Matthews', + 'Chapman', + 'Lawrence', + 'Garza', + 'Vargas', + 'Watkins', + 'Wheeler', + 'Larson', + 'Carlson', + 'Harper', + 'George', + 'Greene', + 'Burke', + 'Guzman', + 'Morrison', + 'Munoz', + 'Jacobs', + 'Obrien', + 'Lawson', + 'Franklin', + 'Lynch', + 'Bishop', + 'Carr', + 'Salazar', + 'Austin', + 'Mendez', + 'Gilbert', + 'Jensen', + 'Williamson', + 'Montgomery', + 'Harvey', + 'Oliver', + 'Howell', + 'Dean', + 'Hanson', + 'Weber', + 'Garrett', + 'Sims', + 'Burton', + 'Fuller', + 'Soto', + 'Mccoy', + 'Welch', + 'Chen', + 'Schultz', + 'Walters', + 'Reid', + 'Fields', + 'Walsh', + 'Little', + 'Fowler', + 'Bowman', + 'Davidson', + 'May', + 'Day', + 'Schneider', + 'Newman', + 'Brewer', + 'Lucas', + 'Holland', + 'Wong', + 'Banks', + 'Santos', + 'Curtis', + 'Pearson', + 'Delgado', + 'Valdez', + 'Pena', + 'Rios', + 'Douglas', + 'Sandoval', + 'Barrett', + 'Hopkins', + 'Keller', + 'Guerrero', + 'Stanley', + 'Bates', + 'Alvarado', + 'Beck', + 'Ortega', + 'Wade', + 'Estrada', + 'Contreras', + 'Barnett', + 'Caldwell', + 'Santiago', + 'Lambert', + 'Powers', + 'Chambers', + 'Nunez', + 'Craig', + 'Leonard', + 'Lowe', + 'Rhodes', + 'Byrd', + 'Gregory', + 'Shelton', + 'Frazier', + 'Becker', + 'Maldonado', + 'Fleming', + 'Vega', + 'Sutton', + 'Cohen', + 'Jennings', + 'Parks', + 'Mcdaniel', + 'Watts', + 'Barker', + 'Norris', + 'Vaughn', + 'Vazquez', + 'Holt', + 'Schwartz', + 'Steele', + 'Benson', + 'Neal', + 'Dominguez', + 'Horton', + 'Terry', + 'Wolfe', + 'Hale', + 'Lyons', + 'Graves', + 'Haynes', + 'Miles', + 'Park', + 'Warner', + 'Padilla', + 'Bush', + 'Thornton', + 'Mccarthy', + 'Mann', + 'Zimmerman', + 'Erickson', + 'Fletcher', + 'Mckinney', + 'Page', + 'Dawson', + 'Joseph', + 'Marquez', + 'Reeves', + 'Klein', + 'Espinoza', + 'Baldwin', + 'Moran', + 'Love', + 'Robbins', + 'Higgins', + 'Ball', + 'Cortez', + 'Le', + 'Griffith', + 'Bowen', + 'Sharp', + 'Cummings', + 'Ramsey', + 'Hardy', + 'Swanson', + 'Barber', + 'Acosta', + 'Luna', + 'Chandler', + 'Blair', + 'Daniel', + 'Cross', + 'Simon', + 'Dennis', + 'Oconnor', + 'Quinn', + 'Gross', + 'Navarro', + 'Moss', + 'Fitzgerald', + 'Doyle', + 'Mclaughlin', + 'Rojas', + 'Rodgers', + 'Stevenson', + 'Singh', + 'Yang', + 'Figueroa', + 'Harmon', + 'Newton', + 'Paul', + 'Manning', + 'Garner', + 'Mcgee', + 'Reese', + 'Francis', + 'Burgess', + 'Adkins', + 'Goodman', + 'Curry', + 'Brady', + 'Christensen', + 'Potter', + 'Walton', + 'Goodwin', + 'Mullins', + 'Molina', + 'Webster', + 'Fischer', + 'Campos', + 'Avila', + 'Sherman', + 'Todd', + 'Chang', + 'Blake', + 'Malone', + 'Wolf', + 'Hodges', + 'Juarez', + 'Gill', + 'Farmer', + 'Hines', + 'Gallagher', + 'Duran', + 'Hubbard', + 'Cannon', + 'Miranda', + 'Wang', + 'Saunders', + 'Tate', + 'Mack', + 'Hammond', + 'Carrillo', + 'Townsend', + 'Wise', + 'Ingram', + 'Barton', + 'Mejia', + 'Ayala', + 'Schroeder', + 'Hampton', + 'Rowe', + 'Parsons', + 'Frank', + 'Waters', + 'Strickland', + 'Osborne', + 'Maxwell', + 'Chan', + 'Deleon', + 'Norman', + 'Harrington', + 'Casey', + 'Patton', + 'Logan', + 'Bowers', + 'Mueller', + 'Glover', + 'Floyd', + 'Hartman', + 'Buchanan', + 'Cobb', + 'French', + 'Kramer', + 'Mccormick', + 'Clarke', + 'Tyler', + 'Gibbs', + 'Moody', + 'Conner', + 'Sparks', + 'Mcguire', + 'Leon', + 'Bauer', + 'Norton', + 'Pope', + 'Flynn', + 'Hogan', + 'Robles', + 'Salinas', + 'Yates', + 'Lindsey', + 'Lloyd', + 'Marsh', + 'Mcbride', + 'Owen', + 'Solis', + 'Pham', + 'Lang', + 'Pratt', + 'Lara', + 'Brock', + 'Ballard', + 'Trujillo', + 'Shaffer', + 'Drake', + 'Roman', + 'Aguirre', + 'Morton', + 'Stokes', + 'Lamb', + 'Pacheco', + 'Patrick', + 'Cochran', + 'Shepherd', + 'Cain', + 'Burnett', + 'Hess', + 'Li', + 'Cervantes', + 'Olsen', + 'Briggs', + 'Ochoa', + 'Cabrera', + 'Velasquez', + 'Montoya', + 'Roth', + 'Meyers', + 'Cardenas', + 'Fuentes', + 'Weiss', + 'Hoover', + 'Wilkins', + 'Nicholson', + 'Underwood', + 'Short', + 'Carson', + 'Morrow', + 'Colon', + 'Holloway', + 'Summers', + 'Bryan', + 'Petersen', + 'Mckenzie', + 'Serrano', + 'Wilcox', + 'Carey', + 'Clayton', + 'Poole', + 'Calderon', + 'Gallegos', + 'Greer', + 'Rivas', + 'Guerra', + 'Decker', + 'Collier', + 'Wall', + 'Whitaker', + 'Bass', + 'Flowers', + 'Davenport', + 'Conley', + 'Houston', + 'Huff', + 'Copeland', + 'Hood', + 'Monroe', + 'Massey', + 'Roberson', + 'Combs', + 'Franco', + 'Larsen', + 'Pittman', + 'Randall', + 'Skinner', + 'Wilkinson', + 'Kirby', + 'Cameron', + 'Bridges', + 'Anthony', + 'Richard', + 'Kirk', + 'Bruce', + 'Singleton', + 'Mathis', + 'Bradford', + 'Boone', + 'Abbott', + 'Charles', + 'Allison', + 'Sweeney', + 'Atkinson', + 'Horn', + 'Jefferson', + 'Rosales', + 'York', + 'Christian', + 'Phelps', + 'Farrell', + 'Castaneda', + 'Nash', + 'Dickerson', + 'Bond', + 'Wyatt', + 'Foley', + 'Chase', + 'Gates', + 'Vincent', + 'Mathews', + 'Hodge', + 'Garrison', + 'Trevino', + 'Villarreal', + 'Heath', + 'Dalton', + 'Valencia', + 'Callahan', + 'Hensley', + 'Atkins', + 'Huffman', + 'Roy', + 'Boyer', + 'Shields', + 'Lin', + 'Hancock', + 'Grimes', + 'Glenn', + 'Cline', + 'Delacruz', + 'Camacho', + 'Dillon', + 'Parrish', + 'Oneill', + 'Melton', + 'Booth', + 'Kane', + 'Berg', + 'Harrell', + 'Pitts', + 'Savage', + 'Wiggins', + 'Brennan', + 'Salas', + 'Marks', + 'Russo', + 'Sawyer', + 'Baxter', + 'Golden', + 'Hutchinson', + 'Liu', + 'Walter', + 'Mcdowell', + 'Wiley', + 'Rich', + 'Humphrey', + 'Johns', + 'Koch', + 'Suarez', + 'Hobbs', + 'Beard', + 'Gilmore', + 'Ibarra', + 'Keith', + 'Macias', + 'Khan', + 'Andrade', + 'Ware', + 'Stephenson', + 'Henson', + 'Wilkerson', + 'Dyer', + 'Mcclure', + 'Blackwell', + 'Mercado', + 'Tanner', + 'Eaton', + 'Clay', + 'Barron', + 'Beasley', + 'Oneal', + 'Preston', + 'Small', + 'Wu', + 'Zamora', + 'Macdonald', + 'Vance', + 'Snow', + 'Mcclain', + 'Stafford', + 'Orozco', + 'Barry', + 'English', + 'Shannon', + 'Kline', + 'Jacobson', + 'Woodard', + 'Huang', + 'Kemp', + 'Mosley', + 'Prince', + 'Merritt', + 'Hurst', + 'Villanueva', + 'Roach', + 'Nolan', + 'Lam', + 'Yoder', + 'Mccullough', + 'Lester', + 'Santana', + 'Valenzuela', + 'Winters', + 'Barrera', + 'Leach', + 'Orr', + 'Berger', + 'Mckee', + 'Strong', + 'Conway', + 'Stein', + 'Whitehead', + 'Bullock', + 'Escobar', + 'Knox', + 'Meadows', + 'Solomon', + 'Velez', + 'Odonnell', + 'Kerr', + 'Stout', + 'Blankenship', + 'Browning', + 'Kent', + 'Lozano', + 'Bartlett', + 'Pruitt', + 'Buck', + 'Barr', + 'Gaines', + 'Durham', + 'Gentry', + 'Mcintyre', + 'Sloan', + 'Rocha', + 'Melendez', + 'Herman', + 'Sexton', + 'Moon', + 'Hendricks', + 'Rangel', + 'Stark', + 'Lowery', + 'Hardin', + 'Hull', + 'Sellers', + 'Ellison', + 'Calhoun', + 'Gillespie', + 'Mora', + 'Knapp', + 'Mccall', + 'Morse', + 'Dorsey', + 'Weeks', + 'Nielsen', + 'Livingston', + 'Leblanc', + 'Mclean', + 'Bradshaw', + 'Glass', + 'Middleton', + 'Buckley', + 'Schaefer', + 'Frost', + 'Howe', + 'House', + 'Mcintosh', + 'Ho', + 'Pennington', + 'Reilly', + 'Hebert', + 'Mcfarland', + 'Hickman', + 'Noble', + 'Spears', + 'Conrad', + 'Arias', + 'Galvan', + 'Velazquez', + 'Huynh', + 'Frederick', + 'Randolph', + 'Cantu', + 'Fitzpatrick', + 'Mahoney', + 'Peck', + 'Villa', + 'Michael', + 'Donovan', + 'Mcconnell', + 'Walls', + 'Boyle', + 'Mayer', + 'Zuniga', + 'Giles', + 'Pineda', + 'Pace', + 'Hurley', + 'Mays', + 'Mcmillan', + 'Crosby', + 'Ayers', + 'Case', + 'Bentley', + 'Shepard', + 'Everett', + 'Pugh', + 'David', + 'Mcmahon', + 'Dunlap', + 'Bender', + 'Hahn', + 'Harding', + 'Acevedo', + 'Raymond', + 'Blackburn', + 'Duffy', + 'Landry', + 'Dougherty', + 'Bautista', + 'Shah', + 'Potts', + 'Arroyo', + 'Valentine', + 'Meza', + 'Gould', + 'Vaughan', + 'Fry', + 'Rush', + 'Avery', + 'Herring', + 'Dodson', + 'Clements', + 'Sampson', + 'Tapia', + 'Bean', + 'Lynn', + 'Crane', + 'Farley', + 'Cisneros', + 'Benton', + 'Ashley', + 'Mckay', + 'Finley', + 'Best', + 'Blevins', + 'Friedman', + 'Moses', + 'Sosa', + 'Blanchard', + 'Huber', + 'Frye', + 'Krueger', + 'Bernard', + 'Rosario', + 'Rubio', + 'Mullen', + 'Benjamin', + 'Haley', + 'Chung', + 'Moyer', + 'Choi', + 'Horne', + 'Yu', + 'Woodward', + 'Ali', + 'Nixon', + 'Hayden', + 'Rivers', + 'Estes', + 'Mccarty', + 'Richmond', + 'Stuart', + 'Maynard', + 'Brandt', + 'Oconnell', + 'Hanna', + 'Sanford', + 'Sheppard', + 'Church', + 'Burch', + 'Levy', + 'Rasmussen', + 'Coffey', + 'Ponce', + 'Faulkner', + 'Donaldson', + 'Schmitt', + 'Novak', + 'Costa', + 'Montes', + 'Booker', + 'Cordova', + 'Waller', + 'Arellano', + 'Maddox', + 'Mata', + 'Bonilla', + 'Stanton', + 'Compton', + 'Kaufman', + 'Dudley', + 'Mcpherson', + 'Beltran', + 'Dickson', + 'Mccann', + 'Villegas', + 'Proctor', + 'Hester', + 'Cantrell', + 'Daugherty', + 'Cherry', + 'Bray', + 'Davila', + 'Rowland', + 'Levine', + 'Madden', + 'Spence', + 'Good', + 'Irwin', + 'Werner', + 'Krause', + 'Petty', + 'Whitney', + 'Baird', + 'Hooper', + 'Pollard', + 'Zavala', + 'Jarvis', + 'Holden', + 'Haas', + 'Hendrix', + 'Mcgrath', + 'Bird', + 'Lucero', + 'Terrell', + 'Riggs', + 'Joyce', + 'Mercer', + 'Rollins', + 'Galloway', + 'Duke', + 'Odom', + 'Andersen', + 'Downs', + 'Hatfield', + 'Benitez', + 'Archer', + 'Huerta', + 'Travis', + 'Mcneil', + 'Hinton', + 'Zhang', + 'Hays', + 'Mayo', + 'Fritz', + 'Branch', + 'Mooney', + 'Ewing', + 'Ritter', + 'Esparza', + 'Frey', + 'Braun', + 'Gay', + 'Riddle', + 'Haney', + 'Kaiser', + 'Holder', + 'Chaney', + 'Mcknight', + 'Gamble', + 'Vang', + 'Cooley', + 'Carney', + 'Cowan', + 'Forbes', + 'Ferrell', + 'Davies', + 'Barajas', + 'Shea', + 'Osborn', + 'Bright', + 'Cuevas', + 'Bolton', + 'Murillo', + 'Lutz', + 'Duarte', + 'Kidd', + 'Key', + 'Cooke', + 'Goff', + 'Dejesus', + 'Marin', + 'Dotson', + 'Bonner', + 'Cotton', + 'Merrill', + 'Lindsay', + 'Lancaster', + 'Mcgowan', + 'Felix', + 'Salgado', + 'Slater', + 'Carver', + 'Guthrie', + 'Holman', + 'Fulton', + 'Snider', + 'Sears', + 'Witt', + 'Newell', + 'Byers', + 'Lehman', + 'Gorman', + 'Costello', + 'Donahue', + 'Delaney', + 'Albert', + 'Workman', + 'Rosas', + 'Springer', + 'Kinney', + 'Justice', + 'Odell', + 'Lake', + 'Donnelly', + 'Law', + 'Dailey', + 'Guevara', + 'Shoemaker', + 'Barlow', + 'Marino', + 'Winter', + 'Craft', + 'Katz', + 'Pickett', + 'Espinosa', + 'Maloney', + 'Daly', + 'Goldstein', + 'Crowley', + 'Vogel', + 'Kuhn', + 'Pearce', + 'Hartley', + 'Cleveland', + 'Palacios', + 'Mcfadden', + 'Britt', + 'Wooten', + 'Cortes', + 'Dillard', + 'Childers', + 'Alford', + 'Dodd', + 'Emerson', + 'Wilder', + 'Lange', + 'Goldberg', + 'Quintero', + 'Beach', + 'Enriquez', + 'Quintana', + 'Helms', + 'Mackey', + 'Finch', + 'Cramer', + 'Minor', + 'Flanagan', + 'Franks', + 'Corona', + 'Kendall', + 'Mccabe', + 'Hendrickson', + 'Moser', + 'Mcdermott', + 'Camp', + 'Mcleod', + 'Bernal', + 'Kaplan', + 'Medrano', + 'Lugo', + 'Tracy', + 'Bacon', + 'Crowe', + 'Richter', + 'Welsh', + 'Holley', + 'Ratliff', + 'Mayfield', + 'Talley', + 'Haines', + 'Dale', + 'Gibbons', + 'Hickey', + 'Byrne', + 'Kirkland', + 'Farris', + 'Correa', + 'Tillman', + 'Sweet', + 'Kessler', + 'England', + 'Hewitt', + 'Blanco', + 'Connolly', + 'Pate', + 'Elder', + 'Bruno', + 'Holcomb', + 'Hyde', + 'Mcallister', + 'Cash', + 'Christopher', + 'Whitfield', + 'Meeks', + 'Hatcher', + 'Fink', + 'Sutherland', + 'Noel', + 'Ritchie', + 'Rosa', + 'Leal', + 'Joyner', + 'Starr', + 'Morin', + 'Delarosa', + 'Connor', + 'Hilton', + 'Alston', + 'Gilliam', + 'Wynn', + 'Wills', + 'Jaramillo', + 'Oneil', + 'Nieves', + 'Britton', + 'Rankin', + 'Belcher', + 'Guy', + 'Chamberlain', + 'Tyson', + 'Puckett', + 'Downing', + 'Sharpe', + 'Boggs', + 'Truong', + 'Pierson', + 'Godfrey', + 'Mobley', + 'John', + 'Kern', + 'Dye', + 'Hollis', + 'Bravo', + 'Magana', + 'Rutherford', + 'Ng', + 'Tuttle', + 'Lim', + 'Romano', + 'Trejo', + 'Arthur', + 'Knowles', + 'Lyon', + 'Shirley', + 'Quinones', + 'Childs', + 'Dolan', + 'Head', + 'Reyna', + 'Saenz', + 'Hastings', + 'Kenney', + 'Cano', + 'Foreman', + 'Denton', + 'Villalobos', + 'Pryor', + 'Sargent', + 'Doherty', + 'Hopper', + 'Phan', + 'Womack', + 'Lockhart', + 'Ventura', + 'Dwyer', + 'Muller', + 'Galindo', + 'Grace', + 'Sorensen', + 'Courtney', + 'Parra', + 'Rodrigues', + 'Nicholas', + 'Ahmed', + 'Mcginnis', + 'Langley', + 'Madison', + 'Locke', + 'Jamison', + 'Nava', + 'Gustafson', + 'Sykes', + 'Dempsey', + 'Hamm', + 'Rodriquez', + 'Mcgill', + 'Xiong', + 'Esquivel', + 'Simms', + 'Kendrick', + 'Boyce', + 'Vigil', + 'Downey', + 'Mckenna', + 'Sierra', + 'Webber', + 'Kirkpatrick', + 'Dickinson', + 'Couch', + 'Burks', + 'Sheehan', + 'Slaughter', + 'Pike', + 'Whitley', + 'Magee', + 'Cheng', + 'Sinclair', + 'Cassidy', + 'Rutledge', + 'Burris', + 'Bowling', + 'Crabtree', + 'Mcnamara', + 'Avalos', + 'Vu', + 'Herron', + 'Broussard', + 'Abraham', + 'Garland', + 'Corbett', + 'Corbin', + 'Stinson', + 'Chin', + 'Burt', + 'Hutchins', + 'Woodruff', + 'Lau', + 'Brandon', + 'Singer', + 'Hatch', + 'Rossi', + 'Shafer', + 'Ott', + 'Goss', + 'Gregg', + 'Dewitt', + 'Tang', + 'Polk', + 'Worley', + 'Covington', + 'Saldana', + 'Heller', + 'Emery', + 'Swartz', + 'Cho', + 'Mccray', + 'Elmore', + 'Rosenberg', + 'Simons', + 'Clemons', + 'Beatty', + 'Harden', + 'Herbert', + 'Bland', + 'Rucker', + 'Manley', + 'Ziegler', + 'Grady', + 'Lott', + 'Rouse', + 'Gleason', + 'Mcclellan', + 'Abrams', + 'Vo', + 'Albright', + 'Meier', + 'Dunbar', + 'Ackerman', + 'Padgett', + 'Mayes', + 'Tipton', + 'Coffman', + 'Peralta', + 'Shapiro', + 'Roe', + 'Weston', + 'Plummer', + 'Helton', + 'Stern', + 'Fraser', + 'Stover', + 'Fish', + 'Schumacher', + 'Baca', + 'Curran', + 'Vinson', + 'Vera', + 'Clifton', + 'Ervin', + 'Eldridge', + 'Lowry', + 'Childress', + 'Becerra', + 'Gore', + 'Seymour', + 'Chu', + 'Field', + 'Akers', + 'Carrasco', + 'Bingham', + 'Sterling', + 'Greenwood', + 'Leslie', + 'Groves', + 'Manuel', + 'Swain', + 'Edmonds', + 'Muniz', + 'Thomson', + 'Crouch', + 'Walden', + 'Smart', + 'Tomlinson', + 'Alfaro', + 'Quick', + 'Goldman', + 'Mcelroy', + 'Yarbrough', + 'Funk', + 'Hong', + 'Portillo', + 'Lund', + 'Ngo', + 'Elkins', + 'Stroud', + 'Meredith', + 'Battle', + 'Mccauley', + 'Zapata', + 'Bloom', + 'Gee', + 'Givens', + 'Cardona', + 'Schafer', + 'Robison', + 'Gunter', + 'Griggs', + 'Tovar', + 'Teague', + 'Swift', + 'Bowden', + 'Schulz', + 'Blanton', + 'Buckner', + 'Whalen', + 'Pritchard', + 'Pierre', + 'Kang', + 'Metcalf', + 'Butts', + 'Kurtz', + 'Sanderson', + 'Tompkins', + 'Inman', + 'Crowder', + 'Dickey', + 'Hutchison', + 'Conklin', + 'Hoskins', + 'Holbrook', + 'Horner', + 'Neely', + 'Tatum', + 'Hollingsworth', + 'Draper', + 'Clement', + 'Lord', + 'Reece', + 'Feldman', + 'Kay', + 'Hagen', + 'Crews', + 'Bowles', + 'Post', + 'Jewell', + 'Daley', + 'Cordero', + 'Mckinley', + 'Velasco', + 'Masters', + 'Driscoll', + 'Burrell', + 'Valle', + 'Crow', + 'Devine', + 'Larkin', + 'Chappell', + 'Pollock', + 'Ly', + 'Kimball', + 'Schmitz', + 'Lu', + 'Rubin', + 'Self', + 'Barrios', + 'Pereira', + 'Phipps', + 'Mcmanus', + 'Nance', + 'Steiner', + 'Poe', + 'Crockett', + 'Jeffries', + 'Amos', + 'Nix', + 'Newsome', + 'Dooley', + 'Payton', + 'Rosen', + 'Swenson', + 'Connelly', + 'Tolbert', + 'Segura', + 'Esposito', + 'Coker', + 'Biggs', + 'Hinkle', + 'Thurman', + 'Drew', + 'Ivey', + 'Bullard', + 'Baez', + 'Neff', + 'Maher', + 'Stratton', + 'Egan', + 'Dubois', + 'Gallardo', + 'Blue', + 'Rainey', + 'Yeager', + 'Saucedo', + 'Ferreira', + 'Sprague', + 'Lacy', + 'Hurtado', + 'Heard', + 'Connell', + 'Stahl', + 'Aldridge', + 'Amaya', + 'Forrest', + 'Erwin', + 'Gunn', + 'Swan', + 'Butcher', + 'Rosado', + 'Godwin', + 'Hand', + 'Gabriel', + 'Otto', + 'Whaley', + 'Ludwig', + 'Clifford', + 'Grove', + 'Beaver', + 'Silver', + 'Dang', + 'Hammer', + 'Dick', + 'Boswell', + 'Mead', + 'Colvin', + 'Oleary', + 'Milligan', + 'Goins', + 'Ames', + 'Dodge', + 'Kaur', + 'Escobedo', + 'Arredondo', + 'Geiger', + 'Winkler', + 'Dunham', + 'Temple', + 'Babcock', + 'Billings', + 'Grimm', + 'Lilly', + 'Wesley', + 'Mcghee', + 'Siegel', + 'Painter', + 'Bower', + 'Purcell', + 'Block', + 'Aguilera', + 'Norwood', + 'Sheridan', + 'Cartwright', + 'Coates', + 'Davison', + 'Regan', + 'Ramey', + 'Koenig', + 'Kraft', + 'Bunch', + 'Engel', + 'Tan', + 'Winn', + 'Steward', + 'Link', + 'Vickers', + 'Bragg', + 'Piper', + 'Huggins', + 'Michel', + 'Healy', + 'Jacob', + 'Mcdonough', + 'Wolff', + 'Colbert', + 'Zepeda', + 'Hoang', + 'Dugan', + 'Meade', + 'Kilgore', + 'Guillen', + 'Do', + 'Hinojosa', + 'Goode', + 'Arrington', + 'Gary', + 'Snell', + 'Willard', + 'Renteria', + 'Chacon', + 'Gallo', + 'Hankins', + 'Montano', + 'Browne', + 'Peacock', + 'Ohara', + 'Cornell', + 'Sherwood', + 'Castellanos', + 'Thorpe', + 'Stiles', + 'Sadler', + 'Latham', + 'Redmond', + 'Greenberg', + 'Cote', + 'Waddell', + 'Dukes', + 'Diamond', + 'Bui', + 'Madrid', + 'Alonso', + 'Sheets', + 'Irvin', + 'Hurt', + 'Ferris', + 'Sewell', + 'Carlton', + 'Aragon', + 'Blackmon', + 'Hadley', + 'Hoyt', + 'Mcgraw', + 'Pagan', + 'Land', + 'Tidwell', + 'Lovell', + 'Miner', + 'Doss', + 'Dahl', + 'Delatorre', + 'Stanford', + 'Kauffman', + 'Vela', + 'Gagnon', + 'Winston', + 'Gomes', + 'Thacker', + 'Coronado', + 'Ash', + 'Jarrett', + 'Hager', + 'Samuels', + 'Metzger', + 'Raines', + 'Spivey', + 'Maurer', + 'Han', + 'Voss', + 'Henley', + 'Caballero', + 'Caruso', + 'Coulter', + 'North', + 'Finn', + 'Cahill', + 'Lanier', + 'Souza', + 'Mcwilliams', + 'Deal', + 'Urban', + 'Schaffer', + 'Houser', + 'Cummins', + 'Romo', + 'Crocker', + 'Bassett', + 'Kruse', + 'Bolden', + 'Ybarra', + 'Metz', + 'Root', + 'Mcmullen', + 'Hagan', + 'Crump', + 'Guidry', + 'Brantley', + 'Kearney', + 'Beal', + 'Toth', + 'Jorgensen', + 'Timmons', + 'Milton', + 'Tripp', + 'Hurd', + 'Sapp', + 'Whitman', + 'Messer', + 'Burgos', + 'Major', + 'Westbrook', + 'Castle', + 'Serna', + 'Carlisle', + 'Varela', + 'Cullen', + 'Wilhelm', + 'Bergeron', + 'Burger', + 'Posey', + 'Barnhart', + 'Hackett', + 'Madrigal', + 'Eubanks', + 'Sizemore', + 'Hilliard', + 'Hargrove', + 'Boucher', + 'Thomason', + 'Melvin', + 'Roper', + 'Barnard', + 'Fonseca', + 'Pedersen', + 'Quiroz', + 'Washburn', + 'Holliday', + 'Yee', + 'Rudolph', + 'Bermudez', + 'Coyle', + 'Gil', + 'Pina', + 'Goodrich', + 'Elias', + 'Lockwood', + 'Cabral', + 'Carranza', + 'Duvall', + 'Cornelius', + 'Mccollum', + 'Street', + 'Mcneal', + 'Connors', + 'Angel', + 'Paulson', + 'Hinson', + 'Keenan', + 'Sheldon', + 'Farr', + 'Eddy', + 'Samuel', + 'Ring', + 'Ledbetter', + 'Betts', + 'Fontenot', + 'Gifford', + 'Hannah', + 'Hanley', + 'Person', + 'Fountain', + 'Levin', + 'Stubbs', + 'Hightower', + 'Murdock', + 'Koehler', + 'Ma', + 'Engle', + 'Smiley', + 'Carmichael', + 'Sheffield', + 'Langston', + 'Mccracken', + 'Yost', + 'Trotter', + 'Story', + 'Starks', + 'Lujan', + 'Blount', + 'Cody', + 'Rushing', + 'Benoit', + 'Herndon', + 'Jacobsen', + 'Nieto', + 'Wiseman', + 'Layton', + 'Epps', + 'Shipley', + 'Leyva', + 'Reeder', + 'Brand', + 'Roland', + 'Fitch', + 'Rico', + 'Napier', + 'Cronin', + 'Mcqueen', + 'Paredes', + 'Trent', + 'Christiansen', + 'Spangler', + 'Pettit', + 'Langford', + 'Benavides', + 'Penn', + 'Paige', + 'Weir', + 'Dietz', + 'Prater', + 'Brewster', + 'Louis', + 'Diehl', + 'Pack', + 'Spaulding', + 'Ernst', + 'Aviles', + 'Nowak', + 'Olvera', + 'Rock', + 'Mansfield', + 'Aquino', + 'Ogden', + 'Stacy', + 'Rizzo', + 'Sylvester', + 'Gillis', + 'Sands', + 'Machado', + 'Lovett', + 'Duong', + 'Hyatt', + 'Landis', + 'Platt', + 'Bustamante', + 'Hedrick', + 'Pritchett', + 'Gaston', + 'Dobson', + 'Caudill', + 'Tackett', + 'Bateman', + 'Landers', + 'Carmona', + 'Gipson', + 'Uribe', + 'Mcneill', + 'Ledford', + 'Mims', + 'Abel', + 'Gold', + 'Smallwood', + 'Thorne', + 'Mchugh', + 'Dickens', + 'Leung', + 'Tobin', + 'Kowalski', + 'Medeiros', + 'Cope', + 'Quezada', + 'Kraus', + 'Overton', + 'Montalvo', + 'Staley', + 'Woody', + 'Hathaway', + 'Osorio', + 'Laird', + 'Dobbs', + 'Capps', + 'Putnam', + 'Lay', + 'Francisco', + 'Bernstein', + 'Adair', + 'Hutton', + 'Burkett', + 'Rhoades', + 'Yanez', + 'Richey', + 'Bledsoe', + 'Mccain', + 'Beyer', + 'Cates', + 'Roche', + 'Spicer', + 'Queen', + 'Doty', + 'Darling', + 'Darby', + 'Sumner', + 'Kincaid', + 'Hay', + 'Grossman', + 'Lacey', + 'Wilkes', + 'Humphries', + 'Paz', + 'Darnell', + 'Keys', + 'Kyle', + 'Lackey', + 'Vogt', + 'Locklear', + 'Kiser', + 'Presley', + 'Bryson', + 'Bergman', + 'Peoples', + 'Fair', + 'Mcclendon', + 'Corley', + 'Prado', + 'Christie', + 'Delong', + 'Skaggs', + 'Dill', + 'Shearer', + 'Judd', + 'Stapleton', + 'Flaherty', + 'Casillas', + 'Pinto', + 'Youngblood', + 'Haywood', + 'Toney', + 'Ricks', + 'Granados', + 'Crum', + 'Triplett', + 'Soriano', + 'Waite', + 'Hoff', + 'Anaya', + 'Crenshaw', + 'Jung', + 'Canales', + 'Cagle', + 'Denny', + 'Marcus', + 'Berman', + 'Munson', + 'Ocampo', + 'Bauman', + 'Corcoran', + 'Keen', + 'Zimmer', + 'Friend', + 'Ornelas', + 'Varner', + 'Pelletier', + 'Vernon', + 'Blum', + 'Albrecht', + 'Culver', + 'Schuster', + 'Cuellar', + 'Mccord', + 'Shultz', + 'Mcrae', + 'Moreland', + 'Calvert', + 'William', + 'Whittington', + 'Eckert', + 'Keene', + 'Mohr', + 'Hanks', + 'Kimble', + 'Cavanaugh', + 'Crowell', + 'Russ', + 'Feliciano', + 'Crain', + 'Busch', + 'Mccormack', + 'Drummond', + 'Omalley', + 'Aldrich', + 'Luke', + 'Greco', + 'Mott', + 'Oakes', + 'Mallory', + 'Mclain', + 'Burrows', + 'Otero', + 'Allred', + 'Eason', + 'Finney', + 'Weller', + 'Waldron', + 'Champion', + 'Jeffers', + 'Coon', + 'Rosenthal', + 'Huddleston', + 'Solano', + 'Hirsch', + 'Akins', + 'Olivares', + 'Song', + 'Sneed', + 'Benedict', + 'Bain', + 'Okeefe', + 'Hidalgo', + 'Matos', + 'Stallings', + 'Paris', + 'Gamez', + 'Kenny', + 'Quigley', + 'Marrero', + 'Fagan', + 'Dutton', + 'Pappas', + 'Atwood', + 'Mcgovern', + 'Bagley', + 'Read', + 'Lunsford', + 'Moseley', + 'Oakley', + 'Ashby', + 'Granger', + 'Shaver', + 'Hope', + 'Coe', + 'Burroughs', + 'Helm', + 'Neumann', + 'Ambrose', + 'Michaels', + 'Prescott', + 'Light', + 'Dumas', + 'Flood', + 'Stringer', + 'Currie', + 'Comer', + 'Fong', + 'Whitlock', + 'Lemus', + 'Hawley', + 'Ulrich', + 'Staples', + 'Boykin', + 'Knutson', + 'Grover', + 'Hobson', + 'Cormier', + 'Doran', + 'Thayer', + 'Woodson', + 'Whitt', + 'Hooker', + 'Kohler', + 'Vandyke', + 'Addison', + 'Schrader', + 'Haskins', + 'Whittaker', + 'Madsen', + 'Gauthier', + 'Burnette', + 'Keating', + 'Purvis', + 'Aleman', + 'Huston', + 'Pimentel', + 'Hamlin', + 'Gerber', + 'Hooks', + 'Schwab', + 'Honeycutt', + 'Schulte', + 'Alonzo', + 'Isaac', + 'Conroy', + 'Adler', + 'Eastman', + 'Cottrell', + 'Orourke', + 'Hawk', + 'Goldsmith', + 'Rader', + 'Crandall', + 'Reynoso', + 'Shook', + 'Abernathy', + 'Baer', + 'Olivas', + 'Grayson', + 'Bartley', + 'Henning', + 'Parr', + 'Duff', + 'Brunson', + 'Baum', + 'Ennis', + 'Laughlin', + 'Foote', + 'Valadez', + 'Adamson', + 'Begay', + 'Stovall', + 'Lincoln', + 'Cheung', + 'Malloy', + 'Rider', + 'Giordano', + 'Jansen', + 'Lopes', + 'Arnett', + 'Pendleton', + 'Gage', + 'Barragan', + 'Keyes', + 'Navarrete', + 'Amador', + 'Hoffmann', + 'Schilling', + 'Hawthorne', + 'Perdue', + 'Schreiber', + 'Arevalo', + 'Naylor', + 'Deluca', + 'Marcum', + 'Altman', + 'Mark', + 'Chadwick', + 'Doan', + 'Easley', + 'Ladd', + 'Woodall', + 'Betancourt', + 'Shin', + 'Maguire', + 'Bellamy', + 'Quintanilla', + 'Ham', + 'Sorenson', + 'Mattson', + 'Brenner', + 'Means', + 'Faust', + 'Calloway', + 'Ojeda', + 'Mcnally', + 'Dietrich', + 'Ransom', + 'Hare', + 'Felton', + 'Whiting', + 'Burkhart', + 'Clinton', + 'Schwarz', + 'Cleary', + 'Wetzel', + 'Reagan', + 'Stjohn', + 'Chow', + 'Hauser', + 'Dupree', + 'Brannon', + 'Lyles', + 'Prather', + 'Willoughby', + 'Sepulveda', + 'Nugent', + 'Pickens', + 'Mosher', + 'Joiner', + 'Stoner', + 'Dowling', + 'Trimble', + 'Valdes', + 'Cheek', + 'Scruggs', + 'Coy', + 'Tilley', + 'Barney', + 'Saylor', + 'Nagy', + 'Horvath', + 'Lai', + 'Corey', + 'Ruth', + 'Sauer', + 'Baron', + 'Thao', + 'Rowell', + 'Grubbs', + 'Schaeffer', + 'Hillman', + 'Sams', + 'Hogue', + 'Hutson', + 'Busby', + 'Nickerson', + 'Bruner', + 'Parham', + 'Rendon', + 'Anders', + 'Lombardo', + 'Iverson', + 'Kinsey', + 'Earl', + 'Borden', + 'Titus', + 'Jean', + 'Tellez', + 'Beavers', + 'Cornett', + 'Sotelo', + 'Kellogg', + 'Silverman', + 'Burnham', + 'Mcnair', + 'Jernigan', + 'Escamilla', + 'Barrow', + 'Coats', + 'London', + 'Redding', + 'Ruffin', + 'Yi', + 'Boudreaux', + 'Goodson', + 'Dowell', + 'Fenton', + 'Mock', + 'Dozier', + 'Bynum', + 'Gale', + 'Jolly', + 'Beckman', + 'Goddard', + 'Craven', + 'Whitmore', + 'Leary', + 'Mccloud', + 'Gamboa', + 'Kerns', + 'Brunner', + 'Negron', + 'Hough', + 'Cutler', + 'Ledesma', + 'Pyle', + 'Monahan', + 'Tabor', + 'Burk', + 'Leone', + 'Stauffer', + 'Hayward', + 'Driver', + 'Ruff', + 'Talbot', + 'Seals', + 'Boston', + 'Carbajal', + 'Fay', + 'Purdy', + 'Mcgregor', + 'Sun', + 'Orellana', + 'Gentile', + 'Mahan', + 'Brower', + 'Patino', + 'Thurston', + 'Shipman', + 'Torrez', + 'Aaron', + 'Weiner', + 'Call', + 'Wilburn', + 'Oliva', + 'Hairston', + 'Coley', + 'Hummel', + 'Arreola', + 'Watt', + 'Sharma', + 'Lentz', + 'Arce', + 'Power', + 'Longoria', + 'Wagoner', + 'Burr', + 'Hsu', + 'Tinsley', + 'Beebe', + 'Wray', + 'Nunn', + 'Prieto', + 'German', + 'Rowley', + 'Grubb', + 'Brito', + 'Royal', + 'Valentin', + 'Bartholomew', + 'Schuler', + 'Aranda', + 'Flint', + 'Hearn', + 'Venegas', + 'Unger', + 'Mattingly', + 'Boles', + 'Casas', + 'Barger', + 'Julian', + 'Dow', + 'Dobbins', + 'Vann', + 'Chester', + 'Strange', + 'Lemon', + 'Kahn', + 'Mckinnon', + 'Gannon', + 'Waggoner', + 'Conn', + 'Meek', + 'Cavazos', + 'Skelton', + 'Lo', + 'Kumar', + 'Toledo', + 'Lorenz', + 'Vallejo', + 'Starkey', + 'Kitchen', + 'Reaves', + 'Demarco', + 'Farrar', + 'Stearns', + 'Michaud', + 'Higginbotham', + 'Fernandes', + 'Isaacs', + 'Marion', + 'Guillory', + 'Priest', + 'Meehan', + 'Oliveira', + 'Palma', + 'Oswald', + 'Loomis', + 'Galvez', + 'Lind', + 'Mena', + 'Stclair', + 'Hinds', + 'Reardon', + 'Alley', + 'Barth', + 'Crook', + 'Bliss', + 'Nagel', + 'Banuelos', + 'Parish', + 'Harman', + 'Douglass', + 'Kearns', + 'Newcomb', + 'Mulligan', + 'Coughlin', + 'Way', + 'Fournier', + 'Lawler', + 'Kaminski', + 'Barbour', + 'Sousa', + 'Stump', + 'Alaniz', + 'Ireland', + 'Rudd', + 'Carnes', + 'Lundy', + 'Godinez', + 'Pulido', + 'Dennison', + 'Burdick', + 'Baumann', + 'Dove', + 'Stoddard', + 'Liang', + 'Dent', + 'Roark', + 'Mcmahan', + 'Bowser', + 'Parnell', + 'Mayberry', + 'Wakefield', + 'Arndt', + 'Ogle', + 'Worthington', + 'Durbin', + 'Escalante', + 'Pederson', + 'Weldon', + 'Vick', + 'Knott', + 'Ryder', + 'Zarate', + 'Irving', + 'Clemens', + 'Shelley', + 'Salter', + 'Jack', + 'Cloud', + 'Dasilva', + 'Muhammad', + 'Squires', + 'Rapp', + 'Dawkins', + 'Polanco', + 'Chatman', + 'Maier', + 'Yazzie', + 'Gruber', + 'Staton', + 'Blackman', + 'Mcdonnell', + 'Dykes', + 'Laws', + 'Whitten', + 'Pfeiffer', + 'Vidal', + 'Early', + 'Kelsey', + 'Baughman', + 'Dias', + 'Starnes', + 'Crespo', + 'Lombardi', + 'Kilpatrick', + 'Deaton', + 'Satterfield', + 'Wiles', + 'Weinstein', + 'Rowan', + 'Delossantos', + 'Hamby', + 'Estep', + 'Daigle', + 'Elam', + 'Creech', + 'Heck', + 'Chavis', + 'Echols', + 'Foss', + 'Trahan', + 'Strauss', + 'Vanhorn', + 'Winslow', + 'Rea', + 'Heaton', + 'Fairchild', + 'Minton', + 'Hitchcock', + 'Linton', + 'Handy', + 'Crouse', + 'Coles', + 'Upton', + 'Foy', + 'Herrington', + 'Mcclelland', + 'Hwang', + 'Rector', + 'Luther', + 'Kruger', + 'Salcedo', + 'Chance', + 'Gunderson', + 'Tharp', + 'Griffiths', + 'Graf', + 'Branham', + 'Humphreys', + 'Renner', + 'Lima', + 'Rooney', + 'Moya', + 'Almeida', + 'Gavin', + 'Coburn', + 'Ouellette', + 'Goetz', + 'Seay', + 'Parrott', + 'Harms', + 'Robb', + 'Storey', + 'Barbosa', + 'Barraza', + 'Loyd', + 'Merchant', + 'Donohue', + 'Carrier', + 'Diggs', + 'Chastain', + 'Sherrill', + 'Whipple', + 'Braswell', + 'Weathers', + 'Linder', + 'Chapa', + 'Bock', + 'Oh', + 'Lovelace', + 'Saavedra', + 'Ferrara', + 'Callaway', + 'Salmon', + 'Templeton', + 'Christy', + 'Harp', + 'Dowd', + 'Forrester', + 'Lawton', + 'Epstein', + 'Gant', + 'Tierney', + 'Seaman', + 'Corral', + 'Dowdy', + 'Zaragoza', + 'Morrissey', + 'Eller', + 'Chau', + 'Breen', + 'High', + 'Newberry', + 'Beam', + 'Yancey', + 'Jarrell', + 'Cerda', + 'Ellsworth', + 'Lofton', + 'Thibodeaux', + 'Pool', + 'Rinehart', + 'Arteaga', + 'Marlow', + 'Hacker', + 'Will', + 'Mackenzie', + 'Hook', + 'Gilliland', + 'Emmons', + 'Pickering', + 'Medley', + 'Willey', + 'Andrew', + 'Shell', + 'Randle', + 'Brinkley', + 'Pruett', + 'Tobias', + 'Edmondson', + 'Grier', + 'Saldivar', + 'Batista', + 'Askew', + 'Moeller', + 'Chavarria', + 'Augustine', + 'Troyer', + 'Layne', + 'Mcnulty', + 'Shank', + 'Desai', + 'Herrmann', + 'Hemphill', + 'Bearden', + 'Spear', + 'Keener', + 'Holguin', + 'Culp', + 'Braden', + 'Briscoe', + 'Bales', + 'Garvin', + 'Stockton', + 'Abreu', + 'Suggs', + 'Mccartney', + 'Ferrer', + 'Rhoads', + 'Ha', + 'Nevarez', + 'Singletary', + 'Chong', + 'Alcala', + 'Cheney', + 'Westfall', + 'Damico', + 'Snodgrass', + 'Devries', + 'Looney', + 'Hein', + 'Lyle', + 'Lockett', + 'Jacques', + 'Barkley', + 'Wahl', + 'Aponte', + 'Myrick', + 'Bolin', + 'Holm', + 'Slack', + 'Scherer', + 'Martino', + 'Bachman', + 'Ely', + 'Nesbitt', + 'Marroquin', + 'Bouchard', + 'Mast', + 'Jameson', + 'Hills', + 'Mireles', + 'Bueno', + 'Pease', + 'Vitale', + 'Alarcon', + 'Linares', + 'Schell', + 'Lipscomb', + 'Arriaga', + 'Bourgeois', + 'Markham', + 'Bonds', + 'Wisniewski', + 'Ivy', + 'Oldham', + 'Wendt', + 'Fallon', + 'Joy', + 'Stamper', + 'Babb', + 'Steinberg', + 'Asher', + 'Fuchs', + 'Blank', + 'Willett', + 'Heredia', + 'Croft', + 'Lytle', + 'Lance', + 'Lassiter', + 'Barrientos', + 'Condon', + 'Barfield', + 'Darden', + 'Araujo', + 'Noonan', + 'Guinn', + 'Burleson', + 'Belanger', + 'Main', + 'Traylor', + 'Messina', + 'Zeigler', + 'Danielson', + 'Millard', + 'Kenyon', + 'Radford', + 'Graff', + 'Beaty', + 'Baggett', + 'Salisbury', + 'Crisp', + 'Trout', + 'Lorenzo', + 'Parson', + 'Gann', + 'Garber', + 'Adcock', + 'Covarrubias', + 'Scales', + 'Acuna', + 'Thrasher', + 'Card', + 'Van', + 'Mabry', + 'Mohamed', + 'Montanez', + 'Stock', + 'Redd', + 'Willingham', + 'Redman', + 'Zambrano', + 'Gaffney', + 'Herr', + 'Schubert', + 'Devlin', + 'Pringle', + 'Houck', + 'Casper', + 'Rees', + 'Wing', + 'Ebert', + 'Jeter', + 'Cornejo', + 'Gillette', + 'Shockley', + 'Amato', + 'Girard', + 'Leggett', + 'Cheatham', + 'Bustos', + 'Epperson', + 'Dubose', + 'Seitz', + 'Frias', + 'East', + 'Schofield', + 'Steen', + 'Orlando', + 'Myles', + 'Caron', + 'Grey', + 'Denney', + 'Ontiveros', + 'Burden', + 'Jaeger', + 'Reich', + 'Witherspoon', + 'Najera', + 'Frantz', + 'Hammonds', + 'Xu', + 'Leavitt', + 'Gilchrist', + 'Adam', + 'Barone', + 'Forman', + 'Ceja', + 'Ragsdale', + 'Sisk', + 'Tubbs', + 'Elizondo', + 'Pressley', + 'Bollinger', + 'Linn', + 'Huntley', + 'Dewey', + 'Geary', + 'Carlos', + 'Ragland', + 'Mixon', + 'Mcarthur', + 'Baugh', + 'Tam', + 'Nobles', + 'Clevenger', + 'Lusk', + 'Foust', + 'Cooney', + 'Tamayo', + 'Robert', + 'Longo', + 'Overstreet', + 'Oglesby', + 'Mace', + 'Churchill', + 'Matson', + 'Hamrick', + 'Rockwell', + 'Trammell', + 'Wheatley', + 'Carrington', + 'Ferraro', + 'Ralston', + 'Clancy', + 'Mondragon', + 'Carl', + 'Hu', + 'Hopson', + 'Breaux', + 'Mccurdy', + 'Mares', + 'Mai', + 'Chisholm', + 'Matlock', + 'Aiken', + 'Cary', + 'Lemons', + 'Anguiano', + 'Herrick', + 'Crawley', + 'Montero', + 'Hassan', + 'Archuleta', + 'Farias', + 'Cotter', + 'Parris', + 'Felder', + 'Luu', + 'Pence', + 'Gilman', + 'Killian', + 'Naranjo', + 'Duggan', + 'Scarborough', + 'Swann', + 'Easter', + 'Ricketts', + 'France', + 'Bello', + 'Nadeau', + 'Still', + 'Rincon', + 'Cornwell', + 'Slade', + 'Fierro', + 'Mize', + 'Christianson', + 'Greenfield', + 'Mcafee', + 'Landrum', + 'Adame', + 'Dinh', + 'Lankford', + 'Lewandowski', + 'Rust', + 'Bundy', + 'Waterman', + 'Milner', + 'Mccrary', + 'Hite', + 'Curley', + 'Donald', + 'Duckworth', + 'Cecil', + 'Carrera', + 'Speer', + 'Birch', + 'Denson', + 'Beckwith', + 'Stack', + 'Durant', + 'Lantz', + 'Dorman', + 'Christman', + 'Spann', + 'Masterson', + 'Hostetler', + 'Kolb', + 'Brink', + 'Scanlon', + 'Nye', + 'Wylie', + 'Beverly', + 'Woo', + 'Spurlock', + 'Sommer', + 'Shelby', + 'Reinhardt', + 'Robledo', + 'Bertrand', + 'Ashton', + 'Cyr', + 'Edgar', + 'Doe', + 'Harkins', + 'Brubaker', + 'Stoll', + 'Dangelo', + 'Zhou', + 'Moulton', + 'Hannon', + 'Falk', + 'Rains', + 'Broughton', + 'Applegate', + 'Hudgins', + 'Slone', + 'Yoon', + 'Farnsworth', + 'Perales', + 'Reedy', + 'Milam', + 'Franz', + 'Ponder', + 'Ricci', + 'Fontaine', + 'Irizarry', + 'Puente', + 'New', + 'Selby', + 'Cazares', + 'Doughty', + 'Moffett', + 'Balderas', + 'Fine', + 'Smalley', + 'Carlin', + 'Trinh', + 'Dyson', + 'Galvin', + 'Valdivia', + 'Benner', + 'Low', + 'Turpin', + 'Lyman', + 'Billingsley', + 'Mcadams', + 'Cardwell', + 'Fraley', + 'Patten', + 'Holton', + 'Shanks', + 'Mcalister', + 'Canfield', + 'Sample', + 'Harley', + 'Cason', + 'Tomlin', + 'Ahmad', + 'Coyne', + 'Forte', + 'Riggins', + 'Littlejohn', + 'Forsythe', + 'Brinson', + 'Halverson', + 'Bach', + 'Stuckey', + 'Falcon', + 'Wenzel', + 'Talbert', + 'Champagne', + 'Mchenry', + 'Vest', + 'Shackelford', + 'Ordonez', + 'Collazo', + 'Boland', + 'Sisson', + 'Bigelow', + 'Wharton', + 'Hyman', + 'Brumfield', + 'Oates', + 'Mesa', + 'Morrell', + 'Beckett', + 'Reis', + 'Alves', + 'Chiu', + 'Larue', + 'Streeter', + 'Grogan', + 'Blakely', + 'Brothers', + 'Hatton', + 'Kimbrough', + 'Lauer', + 'Wallis', + 'Jett', + 'Pepper', + 'Hildebrand', + 'Rawls', + 'Mello', + 'Neville', + 'Bull', + 'Steffen', + 'Braxton', + 'Cowart', + 'Simpkins', + 'Mcneely', + 'Blalock', + 'Spain', + 'Shipp', + 'Lindquist', + 'Oreilly', + 'Butterfield', + 'Perrin', + 'Qualls', + 'Edge', + 'Havens', + 'Luong', + 'Switzer', + 'Troutman', + 'Fortner', + 'Tolliver', + 'Monk', + 'Poindexter', + 'Rupp', + 'Ferry', + 'Negrete', + 'Muse', + 'Gresham', + 'Beauchamp', + 'Schmid', + 'Barclay', + 'Chun', + 'Brice', + 'Faulk', + 'Watters', + 'Briones', + 'Guajardo', + 'Harwood', + 'Grissom', + 'Harlow', + 'Whelan', + 'Burdette', + 'Palumbo', + 'Paulsen', + 'Corrigan', + 'Garvey', + 'Levesque', + 'Dockery', + 'Delgadillo', + 'Gooch', + 'Cao', + 'Mullin', + 'Ridley', + 'Stanfield', + 'Noriega', + 'Dial', + 'Ceballos', + 'Nunes', + 'Newby', + 'Baumgartner', + 'Hussain', + 'Wyman', + 'Causey', + 'Gossett', + 'Ness', + 'Waugh', + 'Choate', + 'Carman', + 'Daily', + 'Kong', + 'Devore', + 'Irby', + 'Breeden', + 'Whatley', + 'Ellington', + 'Lamar', + 'Fultz', + 'Bair', + 'Zielinski', + 'Colby', + 'Houghton', + 'Grigsby', + 'Fortune', + 'Paxton', + 'Mcmillian', + 'Hammons', + 'Bronson', + 'Keck', + 'Wellman', + 'Ayres', + 'Whiteside', + 'Menard', + 'Roush', + 'Warden', + 'Espino', + 'Strand', + 'Haggerty', + 'Banda', + 'Krebs', + 'Fabian', + 'Bowie', + 'Branson', + 'Lenz', + 'Benavidez', + 'Keeler', + 'Newsom', + 'Ezell', + 'Jeffrey', + 'Pulliam', + 'Clary', + 'Byrnes', + 'Kopp', + 'Beers', + 'Smalls', + 'Sommers', + 'Gardiner', + 'Fennell', + 'Mancini', + 'Osullivan', + 'Sebastian', + 'Bruns', + 'Giron', + 'Parent', + 'Boyles', + 'Keefe', + 'Muir', + 'Wheat', + 'Vergara', + 'Shuler', + 'Pemberton', + 'South', + 'Brownlee', + 'Brockman', + 'Royer', + 'Fanning', + 'Herzog', + 'Morley', + 'Bethea', + 'Tong', + 'Needham', + 'Roque', + 'Mojica', + 'Bunn', + 'Francois', + 'Noe', + 'Kuntz', + 'Snowden', + 'Withers', + 'Harlan', + 'Seibert', + 'Limon', + 'Kiefer', + 'Bone', + 'Sell', + 'Allan', + 'Skidmore', + 'Wren', + 'Dunaway', + 'Finnegan', + 'Moe', + 'Wolford', + 'Seeley', + 'Kroll', + 'Lively', + 'Janssen', + 'Montague', + 'Rahman', + 'Boehm', + 'Nettles', + 'Dees', + 'Krieger', + 'Peek', + 'Hershberger', + 'Sage', + 'Custer', + 'Zheng', + 'Otoole', + 'Jaimes', + 'Elrod', + 'Somers', + 'Lira', + 'Nagle', + 'Grooms', + 'Soria', + 'Drury', + 'Keane', + 'Bostic', + 'Hartmann', + 'Pauley', + 'Murrell', + 'Manzo', + 'Morey', + 'Agee', + 'Hamel', + 'Tavares', + 'Dunning', + 'Mccloskey', + 'Plunkett', + 'Maples', + 'March', + 'Armenta', + 'Waldrop', + 'Espinal', + 'Fajardo', + 'Christenson', + 'Robins', + 'Bagwell', + 'Massie', + 'Leahy', + 'Urbina', + 'Medlin', + 'Zhu', + 'Pantoja', + 'Barbee', + 'Clawson', + 'Reiter', + 'Ko', + 'Crider', + 'Maxey', + 'Worrell', + 'Brackett', + 'Mclemore', + 'Younger', + 'Her', + 'Hardesty', + 'Danner', + 'Ragan', + 'Almanza', + 'Nielson', + 'Graber', + 'Mcintire', + 'Tirado', + 'Griswold', + 'Seifert', + 'Valles', + 'Laney', + 'Gupta', + 'Malik', + 'Libby', + 'Marvin', + 'Koontz', + 'Marr', + 'Kozlowski', + 'Lemke', + 'Brant', + 'Phelan', + 'Kemper', + 'Gooden', + 'Beaulieu', + 'Cardoza', + 'Healey', + 'Zhao', + 'Hardwick', + 'Kitchens', + 'Box', + 'Stepp', + 'Comstock', + 'Poston', + 'Sager', + 'Conti', + 'Borges', + 'Farrow', + 'Acker', + 'Glaser', + 'Antonio', + 'Lennon', + 'Gaither', + 'Freitas', + 'Alicea', + 'Mcmillen', + 'Chapin', + 'Ratcliff', + 'Lerma', + 'Severson', + 'Wilde', + 'Mortensen', + 'Winchester', + 'Flannery', + 'Villasenor', + 'Centeno', + 'Burkholder', + 'Horan', + 'Meador', + 'Ingle', + 'Roldan', + 'Estrella', + 'Pullen', + 'Newkirk', + 'Gaytan', + 'Lindberg', + 'Windham', + 'Gatlin', + 'Stoltzfus', + 'Behrens', + 'Cintron', + 'Broderick', + 'Solorzano', + 'Jaime', + 'Venable', + 'Culbertson', + 'Garay', + 'Caputo', + 'Grantham', + 'Hanlon', + 'Parry', + 'Crist', + 'Cosby', + 'Shore', + 'Everhart', + 'Dorn', + 'Turley', + 'Eng', + 'Valerio', + 'Rand', + 'Hiatt', + 'Mota', + 'Judge', + 'Kinder', + 'Colwell', + 'Ashworth', + 'Tejeda', + 'Sikes', + 'Oshea', + 'Westmoreland', + 'Faber', + 'Culpepper', + 'Logsdon', + 'Fugate', + 'Apodaca', + 'Lindley', + 'Samson', + 'Liles', + 'Mcclanahan', + 'Burge', + 'Vail', + 'Etheridge', + 'Boudreau', + 'Andres', + 'Noll', + 'Higgs', + 'Snead', + 'Layman', + 'Turk', + 'Nolen', + 'Wayne', + 'Betz', + 'Victor', + 'Lafferty', + 'Carbone', + 'Skipper', + 'Zeller', + 'Kasper', + 'Desantis', + 'Fogle', + 'Gandy', + 'Mendenhall', + 'Seward', + 'Schweitzer', + 'Gulley', + 'Stine', + 'Sowers', + 'Duenas', + 'Monson', + 'Brinkman', + 'Hubert', + 'Motley', + 'Pfeifer', + 'Weinberg', + 'Eggleston', + 'Isom', + 'Quinlan', + 'Gilley', + 'Jasso', + 'Loya', + 'Mull', + 'Reichert', + 'Wirth', + 'Reddy', + 'Hodgson', + 'Stowe', + 'Mccallum', + 'Ahrens', + 'Huey', + 'Mattox', + 'Dupont', + 'Aguayo', + 'Pak', + 'Tice', + 'Alba', + 'Colburn', + 'Currier', + 'Gaskins', + 'Harder', + 'Cohn', + 'Yoo', + 'Garnett', + 'Harter', + 'Wenger', + 'Charlton', + 'Littleton', + 'Minter', + 'Henriquez', + 'Cone', + 'Vines', + 'Kimmel', + 'Crooks', + 'Caraballo', + 'Searcy', + 'Peyton', + 'Renfro', + 'Groff', + 'Thorn', + 'Moua', + 'Jay', + 'Leigh', + 'Sanborn', + 'Wicker', + 'Martens', + 'Broome', + 'Abney', + 'Fisk', + 'Argueta', + 'Upchurch', + 'Alderman', + 'Tisdale', + 'Castellano', + 'Legg', + 'Wilbur', + 'Bills', + 'Dix', + 'Mauldin', + 'Isbell', + 'Mears', + 'Latimer', + 'Ashcraft', + 'Earley', + 'Tejada', + 'Partridge', + 'Anglin', + 'Caswell', + 'Easton', + 'Kirchner', + 'Mehta', + 'Lanham', + 'Blaylock', + 'Binder', + 'Catalano', + 'Handley', + 'Storm', + 'Albertson', + 'Free', + 'Tuck', + 'Keegan', + 'Moriarty', + 'Dexter', + 'Mancuso', + 'Allard', + 'Pino', + 'Chamberlin', + 'Moffitt', + 'Haag', + 'Schott', + 'Agnew', + 'Malcolm', + 'Hallman', + 'Heckman', + 'Karr', + 'Soares', + 'Alfonso', + 'Tom', + 'Wadsworth', + 'Schindler', + 'Garibay', + 'Kuykendall', + 'Penny', + 'Littlefield', + 'Mcnabb', + 'Sam', + 'Lea', + 'Berrios', + 'Murry', + 'Regalado', + 'Dehart', + 'Mohammed', + 'Counts', + 'Solorio', + 'Preciado', + 'Armendariz', + 'Martell', + 'Barksdale', + 'Frick', + 'Haller', + 'Broyles', + 'Doll', + 'Cable', + 'Delvalle', + 'Weems', + 'Kelleher', + 'Gagne', + 'Albers', + 'Kunz', + 'Hoy', + 'Hawes', + 'Guenther', + 'Johansen', + 'Chaffin', + 'Whitworth', + 'Wynne', + 'Mcmurray', + 'Luce', + 'Fiore', + 'Straub', + 'Majors', + 'Mcduffie', + 'Bohannon', + 'Rawlings', + 'Freed', + 'Sutter', + 'Lindstrom', + 'Buss', + 'Loera', + 'Hoyle', + 'Witte', + 'Tyree', + 'Luttrell', + 'Andrus', + 'Steed', + 'Thiel', + 'Cranford', + 'Fulmer', + 'Gable', + 'Porras', + 'Weis', + 'Maas', + 'Packard', + 'Noyes', + 'Kwon', + 'Knoll', + 'Marx', + 'Feeney', + 'Israel', + 'Bohn', + 'Cockrell', + 'Glick', + 'Cosgrove', + 'Keefer', + 'Mundy', + 'Batchelor', + 'Loveless', + 'Horowitz', + 'Haskell', + 'Kunkel', + 'Colson', + 'Hedges', + 'Staggs', + 'Swisher', + 'Lomeli', + 'Padron', + 'Cota', + 'Homan', + 'Musser', + 'Curtin', + 'Salerno', + 'Segovia', + 'Keeton', + 'Brandenburg', + 'Starling', + 'Tsai', + 'Mahon', + 'Klinger', + 'Paquette', + 'Haddad', + 'Mccune', + 'Mathew', + 'Shull', + 'Higdon', + 'Guest', + 'Shay', + 'Swafford', + 'Angulo', + 'Hackney', + 'Evers', + 'Sibley', + 'Woodworth', + 'Ostrander', + 'Mangum', + 'Smyth', + 'Quarles', + 'Mccarter', + 'Close', + 'Truitt', + 'Stpierre', + 'Mackay', + 'Bayer', + 'Timm', + 'Thatcher', + 'Bess', + 'Trinidad', + 'Jacoby', + 'Proffitt', + 'Concepcion', + 'Parkinson', + 'Carreon', + 'Ramon', + 'Monroy', + 'Leger', + 'Jauregui', + 'Glynn', + 'Taggart', + 'Neil', + 'Reddick', + 'Wiese', + 'Dover', + 'Wicks', + 'Hennessy', + 'Bittner', + 'Mcclung', + 'Mcwhorter', + 'Derrick', + 'Strom', + 'Beckham', + 'Kee', + 'Coombs', + 'Schrock', + 'Holtz', + 'Maki', + 'Willson', + 'Hulsey', + 'Whitson', + 'Haugen', + 'Lumpkin', + 'Scholl', + 'Gall', + 'Carvalho', + 'Kovach', + 'Vieira', + 'Millan', + 'Irvine', + 'Held', + 'Jolley', + 'Jasper', + 'Cadena', + 'Runyon', + 'Lomax', + 'Fahey', + 'Hoppe', + 'Bivens', + 'Ruggiero', + 'Hussey', + 'Ainsworth', + 'Hardman', + 'Ulloa', + 'Dugger', + 'Fitzsimmons', + 'Scroggins', + 'Sowell', + 'Toler', + 'Barba', + 'Biddle', + 'Rafferty', + 'Trapp', + 'Byler', + 'Brill', + 'Delagarza', + 'Thigpen', + 'Hiller', + 'Martins', + 'Jankowski', + 'Findley', + 'Hollins', + 'Stull', + 'Pollack', + 'Poirier', + 'Reno', + 'Bratton', + 'Jeffery', + 'Menendez', + 'Mcnutt', + 'Kohl', + 'Forster', + 'Clough', + 'Deloach', + 'Bader', + 'Hanes', + 'Sturm', + 'Tafoya', + 'Beall', + 'Coble', + 'Demers', + 'Kohn', + 'Santamaria', + 'Vaught', + 'Correia', + 'Mcgrew', + 'Sarmiento', + 'Roby', + 'Reinhart', + 'Rosenbaum', + 'Bernier', + 'Schiller', + 'Furman', + 'Grabowski', + 'Perryman', + 'Kidwell', + 'Sabo', + 'Saxton', + 'Noland', + 'Seaton', + 'Packer', + 'Seal', + 'Ruby', + 'Smoot', + 'Lavoie', + 'Putman', + 'Fairbanks', + 'Neill', + 'Florence', + 'Beattie', + 'Tarver', + 'Stephen', + 'Bolen', + 'Mccombs', + 'Freedman', + 'Barnhill', + 'Gaddis', + 'Goad', + 'Worden', + 'Canada', + 'Vickery', + 'Calvin', + 'Mcclintock', + 'Slocum', + 'Clausen', + 'Mccutcheon', + 'Ripley', + 'Razo', + 'Southard', + 'Bourne', + 'Aiello', + 'Knudsen', + 'Angeles', + 'Keeney', + 'Stacey', + 'Neeley', + 'Holly', + 'Gallant', + 'Eads', + 'Lafleur', + 'Fredrickson', + 'Popp', + 'Bobo', + 'Pardo', + 'Artis', + 'Lawless', + 'Shen', + 'Headley', + 'Pedraza', + 'Pickard', + 'Salvador', + 'Hofmann', + 'Davey', + 'Szymanski', + 'Dallas', + 'Erb', + 'Perea', + 'Alcantar', + 'Ashford', + 'Harry', + 'Crutchfield', + 'Goebel', + 'Ridgeway', + 'Mcvey', + 'Cordell', + 'Kovacs', + 'Florez', + 'Calkins', + 'Redden', + 'Ricker', + 'Salcido', + 'Farrington', + 'Reimer', + 'Mullis', + 'Mayhew', + 'Register', + 'Kaye', + 'Blocker', + 'Buford', + 'Munguia', + 'Cady', + 'Burley', + 'Sander', + 'Robinette', + 'Stubblefield', + 'Shuman', + 'Santillan', + 'Loy', + 'Deutsch', + 'Sales', + 'Langdon', + 'Mazur', + 'Clapp', + 'Teal', + 'Buffington', + 'Elliot', + 'Halstead', + 'Sturgeon', + 'Colley', + 'Koehn', + 'Bergstrom', + 'Dunne', + 'Pond', + 'Gantt', + 'Cousins', + 'Viera', + 'Wilks', + 'Haase', + 'Sweat', + 'Simonson', + 'Breedlove', + 'Munn', + 'Pitt', + 'Faircloth', + 'Peter', + 'Wheaton', + 'Howland', + 'Merriman', + 'Fusco', + 'Burney', + 'Bedford', + 'Baltazar', + 'Persaud', + 'Gerard', + 'Bourque', + 'Chao', + 'Slagle', + 'Kirsch', + 'Volk', + 'Heim', + 'Glasgow', + 'Borders', + 'Rauch', + 'Goforth', + 'Batson', + 'Basham', + 'Mount', + 'Peace', + 'Lazo', + 'Samples', + 'Amaro', + 'Slattery', + 'Ibrahim', + 'Weatherford', + 'Taft', + 'Santoro', + 'Aparicio', + 'Jiang', + 'Ritchey', + 'Goble', + 'Spring', + 'Strain', + 'Scully', + 'Villareal', + 'Toro', + 'Duval', + 'Jonas', + 'Neuman', + 'Wozniak', + 'Varney', + 'Dell', + 'Conover', + 'Landon', + 'Sigler', + 'Galbraith', + 'Boss', + 'Cepeda', + 'Back', + 'Mateo', + 'Peebles', + 'Arsenault', + 'Cathey', + 'Calabrese', + 'Dodds', + 'Gilbertson', + 'Hoke', + 'Greenlee', + 'Sauceda', + 'Vue', + 'Lehmann', + 'Zink', + 'Lapointe', + 'Laster', + 'Moy', + 'Ammons', + 'Llamas', + 'Foltz', + 'Fleck', + 'Chew', + 'Amaral', + 'Geer', + 'Su', + 'Carden', + 'Nunley', + 'Creel', + 'Clarkson', + 'Provost', + 'Covey', + 'Paine', + 'Wofford', + 'Frame', + 'Dube', + 'Grice', + 'Tully', + 'Molnar', + 'Luciano', + 'Bartels', + 'Winstead', + 'Canady', + 'Moreau', + 'Burnside', + 'Bratcher', + 'Infante', + 'Peterman', + 'Swope', + 'Freeland', + 'Vetter', + 'Lanning', + 'Marquis', + 'Schulze', + 'Thai', + 'Coppola', + 'Rayburn', + 'Conte', + 'Martz', + 'Showalter', + 'Quinonez', + 'Bandy', + 'Rao', + 'Bunting', + 'Belt', + 'Cruse', + 'Hamblin', + 'Himes', + 'Raney', + 'Merrell', + 'See', + 'Gough', + 'Maciel', + 'Wimberly', + 'Craddock', + 'Marquardt', + 'Wentz', + 'Meeker', + 'Sandberg', + 'Mosier', + 'Wasson', + 'Hundley', + 'Joe', + 'Shumaker', + 'Fortin', + 'Embry', + 'Olivarez', + 'Akin', + 'Seidel', + 'Coons', + 'Corrales', + 'Earle', + 'Matheny', + 'Kish', + 'Outlaw', + 'Lieberman', + 'Spalding', + 'Barnette', + 'Martel', + 'Hargis', + 'Kelso', + 'Merrick', + 'Fullerton', + 'Fries', + 'Doucette', + 'Clouse', + 'Prewitt', + 'Hawks', + 'Keaton', + 'Worthy', + 'Zook', + 'Montez', + 'Poore', + 'Autry', + 'Lemay', + 'Shifflett', + 'Forsyth', + 'Briseno', + 'Piazza', + 'Welker', + 'Tennant', + 'Heinz', + 'Haggard', + 'Leighton', + 'Brittain', + 'Begley', + 'Flanders', + 'Hermann', + 'Botello', + 'Mathias', + 'Hofer', + 'Hutto', + 'Godoy', + 'Cave', + 'Pagano', + 'Asbury', + 'Bowens', + 'Withrow', + 'Olivo', + 'Harbin', + 'Andre', + 'Sandlin', + 'Wertz', + 'Desimone', + 'Greiner', + 'Heinrich', + 'Whitcomb', + 'Dayton', + 'Petrie', + 'Hair', + 'Ketchum', + 'Shanahan', + 'Bianco', + 'Heil', + 'Cochrane', + 'Wegner', + 'Dagostino', + 'Couture', + 'Ling', + 'Wingate', + 'Arenas', + 'Keel', + 'Casteel', + 'Boothe', + 'Derosa', + 'Horst', + 'Rau', + 'Palermo', + 'Mccorkle', + 'Altamirano', + 'Nall', + 'Shumate', + 'Lightfoot', + 'Creamer', + 'Romeo', + 'Coffin', + 'Hutchings', + 'Jerome', + 'Hutcheson', + 'Damron', + 'Sorrell', + 'Nickel', + 'Sells', + 'Pinkerton', + 'Dao', + 'Dion', + 'Mcfarlane', + 'Ridenour', + 'Atwell', + 'Sturgill', + 'Schoen', + 'Partin', + 'Nemeth', + 'Almonte', + 'Pan', + 'Rickard', + 'Wentworth', + 'Sammons', + 'Sayre', + 'Southerland', + 'Parisi', + 'Ahn', + 'Carrion', + 'Testa', + 'Shorter', + 'Covert', + 'Gorham', + 'Alcantara', + 'Belton', + 'Bannister', + 'Sharkey', + 'Mccreary', + 'Pannell', + 'Scarbrough', + 'Keeling', + 'Gainey', + 'Mill', + 'Camarena', + 'Herbst', + 'Roller', + 'Wild', + 'Dellinger', + 'Lovejoy', + 'Manson', + 'Dupuis', + 'Clem', + 'Resendez', + 'Burkhardt', + 'Williford', + 'Mclendon', + 'Mazza', + 'Mccaffrey', + 'Lum', + 'Settle', + 'Hefner', + 'Dupre', + 'Louie', + 'Gunther', + 'Weimer', + 'Turnbull', + 'Bradbury', + 'Maness', + 'Urena', + 'Lor', + 'Sides', + 'Wick', + 'Monaco', + 'Gillen', + 'Ives', + 'Battaglia', + 'Ulmer', + 'Schreiner', + 'Caceres', + 'Sprouse', + 'Scoggins', + 'Ahern', + 'Tracey', + 'Terrazas', + 'Bracken', + 'Gurley', + 'Soliz', + 'Alcaraz', + 'Martines', + 'Weidner', + 'Criswell', + 'Wilbanks', + 'Hennessey', + 'Mendes', + 'Peak', + 'Ruelas', + 'Caudle', + 'Fuqua', + 'Jewett', + 'Chism', + 'Volpe', + 'Nino', + 'Logue', + 'Mcculloch', + 'Furr', + 'Kersey', + 'Shinn', + 'Yan', + 'Rausch', + 'Stinnett', + 'Mowery', + 'Rivero', + 'Weed', + 'Bertram', + 'Durand', + 'Gatewood', + 'Tilton', + 'Mahaffey', + 'Niles', + 'Mccue', + 'Vargo', + 'Holcombe', + 'Ralph', + 'Castleberry', + 'Snipes', + 'Wilt', + 'Vanmeter', + 'Nutter', + 'Mendiola', + 'Burchett', + 'Enos', + 'Jobe', + 'Kirkwood', + 'Pedroza', + 'Iglesias', + 'Leong', + 'Cromer', + 'Trice', + 'Magnuson', + 'Eagle', + 'Montenegro', + 'Troy', + 'Cato', + 'Edmond', + 'Hendrick', + 'Lebron', + 'Lathrop', + 'Budd', + 'Appel', + 'Knowlton', + 'Bianchi', + 'Camarillo', + 'Ginn', + 'Pulley', + 'True', + 'Gaddy', + 'Domingo', + 'Kingsley', + 'Loftus', + 'Denham', + 'Sifuentes', + 'Siler', + 'Hardison', + 'Kwan', + 'Pendergrass', + 'Frasier', + 'Hutchens', + 'Fort', + 'Montiel', + 'Fincher', + 'Eggers', + 'Moen', + 'Griffis', + 'Hauck', + 'Lister', + 'Lundberg', + 'Tanaka', + 'Cornish', + 'Whitlow', + 'Chou', + 'Griego', + 'Robson', + 'Prosser', + 'Ballinger', + 'Fogarty', + 'Allman', + 'Atchison', + 'Conaway', + 'Riddick', + 'Rupert', + 'Krug', + 'Pinkston', + 'Coggins', + 'Narvaez', + 'Earnest', + 'Fain', + 'Rash', + 'Olmstead', + 'Sherrod', + 'Beeler', + 'Spearman', + 'Poland', + 'Rousseau', + 'Hyland', + 'Rhea', + 'Son', + 'Redmon', + 'Wilke', + 'Valenti', + 'Paulino', + 'Geyer', + 'Blackwood', + 'Leclair', + 'Olguin', + 'Maestas', + 'Buckingham', + 'Blythe', + 'Samuelson', + 'Bounds', + 'Nakamura', + 'Batts', + 'Galarza', + 'Sisco', + 'Mcvay', + 'Hynes', + 'Mertz', + 'Tremblay', + 'Orosco', + 'Prentice', + 'Wilhite', + 'Seiler', + 'Archibald', + 'Wooldridge', + 'Winfield', + 'Oden', + 'Zelaya', + 'Chestnut', + 'Guardado', + 'Mccallister', + 'Canty', + 'Grasso', + 'Collett', + 'Hylton', + 'Easterling', + 'Deangelis', + 'Treadway', + 'Ferrari', + 'Ethridge', + 'Milburn', + 'Mercier', + 'Bickford', + 'Thibodeau', + 'Bolanos', + 'Fellows', + 'Hales', + 'Greathouse', + 'Buchholz', + 'Strunk', + 'Faison', + 'Purnell', + 'Clegg', + 'Steinmetz', + 'Wojcik', + 'Alcorn', + 'Ballesteros', + 'Basile', + 'Paez', + 'Armour', + 'Devito', + 'Tello', + 'Flick', + 'Yount', + 'Estevez', + 'Hitt', + 'Houle', + 'Cha', + 'Travers', + 'Cass', + 'Loper', + 'Getz', + 'Cade', + 'Gonsalves', + 'Lear', + 'Cromwell', + 'Stephan', + 'Ocasio', + 'Deluna', + 'Tolentino', + 'Picard', + 'Eaves', + 'Toscano', + 'Ault', + 'Osburn', + 'Ruvalcaba', + 'Szabo', + 'Kozak', + 'Bear', + 'Eck', + 'Deyoung', + 'Morehead', + 'Herrin', + 'Tillery', + 'Royster', + 'Kehoe', + 'Swank', + 'Yamamoto', + 'Schoonover', + 'Clanton', + 'Stutzman', + 'Swearingen', + 'Martinson', + 'Harrelson', + 'Leo', + 'Keyser', + 'Guyton', + 'Lucio', + 'Veal', + 'Vanwinkle', + 'Angelo', + 'Zamudio', + 'Haddock', + 'Quach', + 'Thomsen', + 'Curiel', + 'Badger', + 'Teel', + 'Hibbard', + 'Dvorak', + 'Ballew', + 'Falls', + 'Bostick', + 'Monaghan', + 'Segal', + 'Denning', + 'Bahr', + 'Serrato', + 'Toomey', + 'Lacroix', + 'Antoine', + 'Resendiz', + 'Sperry', + 'Rosser', + 'Bogan', + 'Gaspar', + 'Amin', + 'Schramm', + 'Lemaster', + 'Echevarria', + 'Lilley', + 'Poling', + 'Villagomez', + 'Conde', + 'Delrio', + 'Lerner', + 'Leroy', + 'Otis', + 'Durkin', + 'Lavender', + 'Schenk', + 'Ong', + 'Guess', + 'Alanis', + 'Jacobo', + 'Ramsay', + 'Henke', + 'Sledge', + 'Whited', + 'Frazer', + 'Fortier', + 'Macleod', + 'Pascual', + 'Casanova', + 'Olds', + 'Jenson', + 'Tijerina', + 'Flora', + 'Casto', + 'Rinaldi', + 'Blunt', + 'Fontana', + 'Minnick', + 'Larios', + 'Raynor', + 'Fung', + 'Marek', + 'Valladares', + 'Clemmons', + 'Gracia', + 'Rohrer', + 'Fryer', + 'Folsom', + 'Gearhart', + 'Sumpter', + 'Kraemer', + 'Aceves', + 'Pettigrew', + 'Mclaurin', + 'Southern', + 'Barrows', + 'Landeros', + 'Janes', + 'Deguzman', + 'Mcfall', + 'Fredericks', + 'Ashe', + 'Mauro', + 'Merino', + 'Windsor', + 'Taber', + 'Armijo', + 'Bricker', + 'Pitman', + 'Morrill', + 'Sanches', + 'Deboer', + 'Conlon', + 'Reuter', + 'Stegall', + 'Clemente', + 'Romine', + 'Dykstra', + 'Ehlers', + 'Tallman', + 'Lovato', + 'Brent', + 'Pearl', + 'Pyles', + 'Cloutier', + 'Mccurry', + 'Mckeever', + 'Graziano', + 'Heflin', + 'Garman', + 'Isaacson', + 'Mcreynolds', + 'Meister', + 'Stroup', + 'Everson', + 'Halsey', + 'Mcewen', + 'Sparkman', + 'Yager', + 'Bucher', + 'Berryman', + 'Derr', + 'Jester', + 'Mickelson', + 'Sayers', + 'Whiteman', + 'Riordan', + 'Mcinnis', + 'Jose', + 'Goolsby', + 'Stidham', + 'Donley', + 'Johnsen', + 'Stallworth', + 'Franke', + 'Silvers', + 'Reitz', + 'Nathan', + 'Brogan', + 'Cardoso', + 'Linville', + 'Baptiste', + 'Gorski', + 'Rey', + 'Hazen', + 'Damon', + 'Shores', + 'Boling', + 'Jablonski', + 'Lemieux', + 'Hecht', + 'Dong', + 'Langlois', + 'Burrow', + 'Hernandes', + 'Mcdevitt', + 'Pichardo', + 'Lew', + 'Stillwell', + 'Savoy', + 'Teixeira', + 'Matheson', + 'Hildreth', + 'Warfield', + 'Hogg', + 'Tiller', + 'Unruh', + 'Rudy', + 'Bristol', + 'Matias', + 'Buxton', + 'Ambriz', + 'Chiang', + 'Pomeroy', + 'Pogue', + 'Hammock', + 'Bethel', + 'Miguel', + 'Cassell', + 'Towns', + 'Bunker', + 'Mcmichael', + 'Kress', + 'Newland', + 'Whitehurst', + 'Fazio', + 'Batten', + 'Calvillo', + 'Wallen', + 'Lung', + 'Turney', + 'Sparrow', + 'Steadman', + 'Battles', + 'Berlin', + 'Lindgren', + 'Mckeon', + 'Luckett', + 'Spradlin', + 'Sherry', + 'Timmerman', + 'Utley', + 'Beale', + 'Driggers', + 'Hintz', + 'Pellegrino', + 'Hazel', + 'Grim', + 'Desmond', + 'Spellman', + 'Boren', + 'Staten', + 'Schlegel', + 'Maya', + 'Johnstone', + 'Harwell', + 'Pinson', + 'Barreto', + 'Spooner', + 'Candelaria', + 'Hammett', + 'Sessions', + 'Mckeown', + 'Mccool', + 'Gilson', + 'Knudson', + 'Irish', + 'Spruill', + 'Kling', + 'Gerlach', + 'Carnahan', + 'Markley', + 'Laporte', + 'Flanigan', + 'Spires', + 'Cushman', + 'Plante', + 'Schlosser', + 'Sachs', + 'Jamieson', + 'Hornsby', + 'Armstead', + 'Kremer', + 'Madera', + 'Thornburg', + 'Briley', + 'Garris', + 'Jorgenson', + 'Moorman', + 'Vuong', + 'Ard', + 'Irons', + 'Fiedler', + 'Jackman', + 'Kuehn', + 'Jenks', + 'Bristow', + 'Mosby', + 'Aldana', + 'Maclean', + 'Freund', + 'Creighton', + 'Smothers', + 'Melson', + 'Lundgren', + 'Donato', + 'Usher', + 'Thornhill', + 'Lowman', + 'Mariano', + 'Button', + 'Mcbee', + 'Cupp', + 'Wickham', + 'Destefano', + 'Nutt', + 'Rambo', + 'Voigt', + 'Talbott', + 'Saxon', + 'Cedillo', + 'Mattison', + 'Speed', + 'Reiss', + 'Nan', + 'Westphal', + 'Whittle', + 'Bernhardt', + 'Boatwright', + 'Bussey', + 'Rojo', + 'Eden', + 'Crites', + 'Place', + 'He', + 'Chaves', + 'Larose', + 'Thames', + 'Hoch', + 'Knotts', + 'Simone', + 'Binkley', + 'Koester', + 'Pettis', + 'Moye', + 'Napolitano', + 'Heffner', + 'Sasser', + 'Jessup', + 'Aguiar', + 'Ogrady', + 'Pippin', + 'Worth', + 'Shively', + 'Whitmire', + 'Rutter', + 'Cedeno', + 'Welborn', + 'Mcdougal', + 'Angell', + 'Sacco', + 'Hailey', + 'Neel', + 'Paniagua', + 'Pointer', + 'Rohde', + 'Holloman', + 'Strother', + 'Guffey', + 'Fenner', + 'Huntington', + 'Shane', + 'Yuen', + 'Gosnell', + 'Martini', + 'Loving', + 'Molloy', + 'Olmos', + 'Christ', + 'Oaks', + 'Ostrowski', + 'Badillo', + 'To', + 'Laplante', + 'Martindale', + 'Richie', + 'Pleasant', + 'Palomino', + 'Rodarte', + 'Stamps', + 'Peeples', + 'Ries', + 'Brownell', + 'Walz', + 'Arana', + 'Tenney', + 'Roddy', + 'Lindner', + 'Bolt', + 'Rigsby', + 'Matteson', + 'Fielder', + 'Randazzo', + 'Deanda', + 'Drayton', + 'Ridge', + 'Tarr', + 'Shade', + 'Upshaw', + 'Woodcock', + 'Miley', + 'Hargrave', + 'Langer', + 'Yun', + 'Wilkie', + 'Choe', + 'Ching', + 'Dugas', + 'Saul', + 'Corder', + 'Bobbitt', + 'Spurgeon', + 'Gladden', + 'Woodbury', + 'Tibbs', + 'Mcgarry', + 'Mcdaniels', + 'Weigel', + 'Bickel', + 'Michels', + 'Hughey', + 'Apple', + 'Bosley', + 'Nesmith', + 'Farber', + 'Ackley', + 'Goodin', + 'Almond', + 'Garrity', + 'Bettencourt', + 'Koss', + 'Falcone', + 'Lavigne', + 'Rainwater', + 'Nation', + 'Blodgett', + 'Dabney', + 'Mabe', + 'Trowbridge', + 'Lundquist', + 'Rosenberger', + 'Dombrowski', + 'Ferro', + 'Evangelista', + 'Bowlin', + 'Mckelvey', + 'Roderick', + 'Michalski', + 'Berkowitz', + 'Sato', + 'Mayorga', + 'Corwin', + 'Mckenney', + 'Salyer', + 'Walling', + 'Abell', + 'Palacio', + 'Lash', + 'Collado', + 'Gass', + 'Luis', + 'Cooksey', + 'Moll', + 'Miramontes', + 'Luster', + 'Shrader', + 'Toliver', + 'Hard', + 'Tu', + 'Sena', + 'Mckoy', + 'Wainwright', + 'Barela', + 'Keiser', + 'Hoag', + 'Backus', + 'Huskey', + 'Brannan', + 'Brumley', + 'Palm', + 'Boynton', + 'Krauss', + 'Steel', + 'Jurado', + 'Mulder', + 'Paterson', + 'Woolsey', + 'Smithson', + 'Joslin', + 'Richman', + 'Partida', + 'Grisham', + 'Wooden', + 'Gooding', + 'Fang', + 'Mcdade', + 'Spriggs', + 'Fishman', + 'Gabel', + 'Rutkowski', + 'Pride', + 'Beals', + 'Gaskin', + 'Friday', + 'Underhill', + 'Rodas', + 'Melo', + 'Sipes', + 'Zimmermann', + 'Mosqueda', + 'Haight', + 'Beeson', + 'Judy', + 'Bankston', + 'Pieper', + 'Siebert', + 'Horning', + 'Butt', + 'Bice', + 'Sills', + 'Philips', + 'Eisenberg', + 'Schumann', + 'Conger', + 'Bare', + 'Hume', + 'Nolasco', + 'Trainor', + 'Weatherly', + 'Huebner', + 'Bosch', + 'Gayle', + 'Kuhns', + 'Byron', + 'Glaze', + 'Poulin', + 'Enright', + 'Large', + 'Comeaux', + 'Rountree', + 'Tavarez', + 'Beardsley', + 'Rubino', + 'Fee', + 'Grider', + 'Bechtel', + 'Gaona', + 'Wallin', + 'Mashburn', + 'Dalrymple', + 'Gingerich', + 'Vaccaro', + 'Hass', + 'Manzano', + 'Tyner', + 'Loza', + 'Lowell', + 'Kaufmann', + 'Bischoff', + 'Doolittle', + 'Shivers', + 'Valente', + 'Bozeman', + 'Howes', + 'Felts', + 'Feller', + 'Justus', + 'Schnell', + 'Boettcher', + 'Ivory', + 'Thorson', + 'Corn', + 'Snook', + 'Heilman', + 'Baxley', + 'Hasty', + 'Wasserman', + 'Barringer', + 'Frankel', + 'Peltier', + 'Guarino', + 'Avina', + 'Sturdivant', + 'Lien', + 'Montemayor', + 'Giddens', + 'Valverde', + 'Burchfield', + 'Pang', + 'Holbert', + 'Rooks', + 'Erdman', + 'Mcmaster', + 'Iniguez', + 'Hartwell', + 'Menchaca', + 'Bordelon', + 'Farkas', + 'Chrisman', + 'Metzler', + 'Fredrick', + 'Porterfield', + 'Slayton', + 'Quesada', + 'Hembree', + 'Peel', + 'Woodley', + 'Mather', + 'Waltz', + 'Totten', + 'Forney', + 'Woolley', + 'Trombley', + 'Yarborough', + 'Javier', + 'Durr', + 'Macklin', + 'Macon', + 'Novotny', + 'Amundson', + 'Kidder', + 'Flagg', + 'Oxendine', + 'Arguello', + 'Marler', + 'Penrod', + 'Mallett', + 'Council', + 'Kinard', + 'Bremer', + 'Towne', + 'Harless', + 'Merkel', + 'Giese', + 'Fife', + 'Byars', + 'Grande', + 'Kuo', + 'Levi', + 'Darr', + 'Sanabria', + 'Pounds', + 'Roeder', + 'Keim', + 'Brush', + 'Dreyer', + 'Taveras', + 'Furlong', + 'Dorris', + 'Prior', + 'Musgrove', + 'Weiler', + 'Munro', + 'Leake', + 'Vollmer', + 'Musick', + 'Hetrick', + 'Perdomo', + 'Kester', + 'Lock', + 'Pine', + 'Baskin', + 'Bonham', + 'Heffernan', + 'Mandel', + 'Sarver', + 'Hamer', + 'Duckett', + 'Lozada', + 'Stocker', + 'Fulcher', + 'Damato', + 'Camargo', + 'Shephard', + 'Loftis', + 'Winfrey', + 'Rueda', + 'Ledezma', + 'Gottlieb', + 'Lamont', + 'Mackie', + 'Bowe', + 'Stockwell', + 'Groth', + 'Chavira', + 'Lohr', + 'Loftin', + 'Gilmer', + 'Cushing', + 'Brody', + 'Nowlin', + 'Holiday', + 'Shirk', + 'Archie', + 'Howerton', + 'Matthew', + 'Copley', + 'Marchese', + 'Echeverria', + 'Soper', + 'Cantwell', + 'Nelms', + 'Tuggle', + 'Dumont', + 'Bard', + 'Gower', + 'Mathes', + 'Yeung', + 'Buell', + 'Bastian', + 'Burd', + 'Broadway', + 'Peng', + 'Greenwell', + 'Vanover', + 'Correll', + 'Tindall', + 'Bill', + 'Mulcahy', + 'Dionne', + 'Rathbun', + 'Baeza', + 'Booher', + 'Fried', + 'Mcginley', + 'Lavin', + 'Atherton', + 'Donnell', + 'Bays', + 'Riedel', + 'Grenier', + 'Zachary', + 'Harold', + 'Styles', + 'Wisdom', + 'Raley', + 'Tamez', + 'Arena', + 'Morelli', + 'Hazelwood', + 'Somerville', + 'Lapp', + 'Rood', + 'Salem', + 'Pape', + 'Olivera', + 'Albritton', + 'Carvajal', + 'Zayas', + 'Myer', + 'Pohl', + 'Haynie', + 'Mariscal', + 'Wampler', + 'Rife', + 'Leeper', + 'Newhouse', + 'Rodney', + 'Vandenberg', + 'Spitzer', + 'Kingston', + 'Wessel', + 'Hartzell', + 'Durden', + 'Marques', + 'Born', + 'Scribner', + 'Rocco', + 'Germain', + 'Tinoco', + 'Valdovinos', + 'Musselman', + 'Vicente', + 'Parsley', + 'Crittenden', + 'Tibbetts', + 'Hulse', + 'Mccleary', + 'Barboza', + 'Velarde', + 'Brodie', + 'Beaudoin', + 'Moreira', + 'Maggard', + 'Jara', + 'Ferrante', + 'Overby', + 'Friesen', + 'Viola', + 'Nelsen', + 'Hash', + 'Doane', + 'Deese', + 'Messick', + 'Bay', + 'Anton', + 'Ingersoll', + 'Saucier', + 'Kwiatkowski', + 'Rawson', + 'Brophy', + 'Ladner', + 'Lehr', + 'Weil', + 'Yocum', + 'Brasher', + 'Denison', + 'Hutcherson', + 'Stowers', + 'Geller', + 'Fortenberry', + 'Stebbins', + 'Conyers', + 'Toole', + 'Stoker', + 'Roden', + 'Chitwood', + 'Beeman', + 'Fannin', + 'Strait', + 'Marlowe', + 'Greenwald', + 'Hann', + 'Stumpf', + 'Samaniego', + 'Colton', + 'Bogart', + 'Morel', + 'Montelongo', + 'Boylan', + 'Guido', + 'Wyrick', + 'Horsley', + 'Tenorio', + 'Sallee', + 'Morehouse', + 'Whyte', + 'Neilson', + 'Watanabe', + 'Magallanes', + 'Mudd', + 'Kieffer', + 'Brigham', + 'Dollar', + 'Huss', + 'Albanese', + 'Spiegel', + 'Hixson', + 'Rounds', + 'Orth', + 'Blanchette', + 'Vanderpool', + 'Pfaff', + 'Speck', + 'Shreve', + 'Sevilla', + 'Neri', + 'Rohr', + 'Ruble', + 'Vanpelt', + 'Rickman', + 'Caraway', + 'Berndt', + 'Mchale', + 'Ingalls', + 'Roybal', + 'Money', + 'Mcdougall', + 'Melancon', + 'Wellington', + 'Ingraham', + 'Ritz', + 'Lashley', + 'Marchand', + 'Schatz', + 'Heiser', + 'Eby', + 'Wimmer', + 'Orton', + 'Atchley', + 'Mumford', + 'Bahena', + 'Gammon', + 'Buehler', + 'Fike', + 'Plank', + 'Carrigan', + 'Kempf', + 'Cundiff', + 'So', + 'Sauls', + 'Mohler', + 'Grillo', + 'Prichard', + 'Pastor', + 'Prasad', + 'Babin', + 'Bontrager', + 'Weddle', + 'Alberts', + 'Theis', + 'Lemoine', + 'Hartnett', + 'Kingsbury', + 'Baran', + 'Birmingham', + 'Gault', + 'Thorp', + 'Wyant', + 'Obryan', + 'Santacruz', + 'Camara', + 'Whitehouse', + 'Evenson', + 'Halvorson', + 'Palmieri', + 'Hannan', + 'Dew', + 'Au', + 'Nolte', + 'Click', + 'Wooley', + 'Hung', + 'Eberhardt', + 'Rawlins', + 'Sadowski', + 'Sarabia', + 'Soule', + 'Millar', + 'Engstrom', + 'Cowles', + 'Runyan', + 'Mitchel', + 'Torrence', + 'Silverstein', + 'Hewett', + 'Pilgrim', + 'Yeh', + 'Rosenfeld', + 'Mulholland', + 'Hatley', + 'Fawcett', + 'Delrosario', + 'Chinn', + 'Bayless', + 'Dee', + 'Deane', + 'Arriola', + 'Duda', + 'Koster', + 'Rath', + 'Karl', + 'Weiland', + 'Lemmon', + 'Blaine', + 'Scofield', + 'Marston', + 'Gist', + 'Pinckney', + 'Moritz', + 'Mclellan', + 'Fulkerson', + 'Gaynor', + 'Pitre', + 'Warrick', + 'Cobbs', + 'Meacham', + 'Guerin', + 'Tedesco', + 'Passmore', + 'Northcutt', + 'Ison', + 'Cowell', + 'Ream', + 'Walther', + 'Meraz', + 'Tribble', + 'Bumgarner', + 'Gabbard', + 'Dawes', + 'Moncada', + 'Chilton', + 'Deweese', + 'Rigby', + 'Marte', + 'Baylor', + 'Valentino', + 'Shine', + 'August', + 'Billups', + 'Jarman', + 'Jacks', + 'Coffee', + 'Friedrich', + 'Marley', + 'Hasan', + 'Pennell', + 'Abercrombie', + 'Bazan', + 'Strickler', + 'Bruton', + 'Lamm', + 'Pender', + 'Wingfield', + 'Hoffer', + 'Zahn', + 'Chaplin', + 'Reinke', + 'Larosa', + 'Maupin', + 'Bunnell', + 'Hassell', + 'Guo', + 'Galan', + 'Paschal', + 'Browder', + 'Krantz', + 'Milne', + 'Pelayo', + 'Emanuel', + 'Mccluskey', + 'Edens', + 'Radtke', + 'Alger', + 'Duhon', + 'Probst', + 'Witmer', + 'Hoagland', + 'Saechao', + 'Pitcher', + 'Villalpando', + 'Carswell', + 'Roundtree', + 'Kuhlman', + 'Tait', + 'Shaughnessy', + 'Wei', + 'Cravens', + 'Sipe', + 'Islas', + 'Hollenbeck', + 'Lockard', + 'Perrone', + 'Tapp', + 'Santoyo', + 'Jaffe', + 'Klotz', + 'Gilpin', + 'Ehrlich', + 'Klug', + 'Stowell', + 'Ibanez', + 'Lazar', + 'Osman', + 'Larkins', + 'Donofrio', + 'Ericson', + 'Schenck', + 'Mouton', + 'Medlock', + 'Hubbell', + 'Bixler', + 'Nowicki', + 'Muro', + 'Homer', + 'Grijalva', + 'Ashmore', + 'Harbison', + 'Duffey', + 'Osgood', + 'Hardee', + 'Jain', + 'Wilber', + 'Bolling', + 'Lett', + 'Phillip', + 'Dipietro', + 'Lefebvre', + 'Batiste', + 'Mcswain', + 'Distefano', + 'Hack', + 'Strobel', + 'Kipp', + 'Doerr', + 'Radcliffe', + 'Cartagena', + 'Paradis', + 'Stilwell', + 'Mccrea', + 'Searles', + 'Frausto', + 'Hendershot', + 'Gosselin', + 'Islam', + 'Freese', + 'Stockman', + 'Burwell', + 'Vandiver', + 'Engler', + 'Geisler', + 'Barham', + 'Wiegand', + 'Goncalves', + 'Theriot', + 'Doucet', + 'Bridge', + 'Catron', + 'Blanks', + 'Rahn', + 'Schaub', + 'Hershey', + 'Strader', + 'Buckman', + 'Hartwig', + 'Campo', + 'Tsang', + 'Luck', + 'Bernardo', + 'Marker', + 'Pinkney', + 'Benefield', + 'Mcginty', + 'Bode', + 'Linden', + 'Manriquez', + 'Jaquez', + 'Bedard', + 'Flack', + 'Hesse', + 'Costanzo', + 'Boardman', + 'Carper', + 'Word', + 'Miracle', + 'Edmunds', + 'Bott', + 'Flemming', + 'Manns', + 'Kesler', + 'Piatt', + 'Tankersley', + 'Eberle', + 'Roney', + 'Belk', + 'Vansickle', + 'Varga', + 'Hillard', + 'Neubauer', + 'Quirk', + 'Chevalier', + 'Mintz', + 'Kocher', + 'Casarez', + 'Tinker', + 'Elmer', + 'Decarlo', + 'Cordes', + 'Berube', + 'Kimbrell', + 'Schick', + 'Papa', + 'Alderson', + 'Callaghan', + 'Renaud', + 'Pardue', + 'Krohn', + 'Bloomfield', + 'Coward', + 'Ligon', + 'Trask', + 'Wingo', + 'Book', + 'Crutcher', + 'Canter', + 'Teran', + 'Denman', + 'Stackhouse', + 'Chambliss', + 'Gourley', + 'Earls', + 'Frizzell', + 'Bergen', + 'Abdullah', + 'Sprinkle', + 'Fancher', + 'Urias', + 'Lavelle', + 'Baumgardner', + 'Kahler', + 'Baldridge', + 'Alejandro', + 'Plascencia', + 'Hix', + 'Rule', + 'Mix', + 'Petro', + 'Hadden', + 'Fore', + 'Humes', + 'Barnum', + 'Laing', + 'Maggio', + 'Sylvia', + 'Malinowski', + 'Fell', + 'Durst', + 'Plant', + 'Vaca', + 'Abarca', + 'Shirey', + 'Parton', + 'Ta', + 'Ramires', + 'Ochs', + 'Gaitan', + 'Ledoux', + 'Darrow', + 'Messenger', + 'Chalmers', + 'Schaller', + 'Derby', + 'Coakley', + 'Saleh', + 'Kirkman', + 'Orta', + 'Crabb', + 'Spinks', + 'Dinkins', + 'Harrigan', + 'Koller', + 'Dorr', + 'Carty', + 'Sturgis', + 'Shriver', + 'Macedo', + 'Feng', + 'Bentz', + 'Bedell', + 'Osuna', + 'Dibble', + 'Dejong', + 'Fender', + 'Parada', + 'Vanburen', + 'Chaffee', + 'Stott', + 'Sigmon', + 'Nicolas', + 'Salyers', + 'Magdaleno', + 'Deering', + 'Puentes', + 'Funderburk', + 'Jang', + 'Christopherson', + 'Sellars', + 'Marcotte', + 'Oster', + 'Liao', + 'Tudor', + 'Specht', + 'Chowdhury', + 'Landa', + 'Monge', + 'Brake', + 'Behnke', + 'Llewellyn', + 'Labelle', + 'Mangan', + 'Godsey', + 'Truax', + 'Lombard', + 'Thurmond', + 'Emerick', + 'Blume', + 'Mcginn', + 'Beer', + 'Marrs', + 'Zinn', + 'Rieger', + 'Dilley', + 'Thibault', + 'Witkowski', + 'Chi', + 'Fielding', + 'Tyrrell', + 'Peeler', + 'Northrup', + 'Augustin', + 'Toy', + 'Geist', + 'Schuman', + 'Fairley', + 'Duque', + 'Villatoro', + 'Dudek', + 'Sonnier', + 'Fritts', + 'Worsham', + 'Herold', + 'Mcgehee', + 'Caskey', + 'Boatright', + 'Lazaro', + 'Deck', + 'Palomo', + 'Cory', + 'Olivier', + 'Baines', + 'Fan', + 'Futrell', + 'Halpin', + 'Garrido', + 'Koonce', + 'Fogg', + 'Meneses', + 'Mulkey', + 'Restrepo', + 'Ducharme', + 'Slate', + 'Toussaint', + 'Sorrells', + 'Fitts', + 'Dickman', + 'Alfred', + 'Grimsley', + 'Settles', + 'Etienne', + 'Eggert', + 'Hague', + 'Caldera', + 'Hillis', + 'Hollander', + 'Haire', + 'Theriault', + 'Madigan', + 'Kiernan', + 'Parkhurst', + 'Lippert', + 'Jaynes', + 'Moniz', + 'Bost', + 'Bettis', + 'Sandy', + 'Kuhl', + 'Wilk', + 'Borrego', + 'Koon', + 'Penney', + 'Pizarro', + 'Stitt', + 'Koski', + 'Galicia', + 'Quiles', + 'Real', + 'Massa', + 'Crone', + 'Teeter', + 'Voorhees', + 'Hilbert', + 'Nabors', + 'Shupe', + 'Blood', + 'Mcauliffe', + 'Waits', + 'Blakley', + 'Stoltz', + 'Maes', + 'Munroe', + 'Rhoden', + 'Abeyta', + 'Milliken', + 'Harkness', + 'Almaraz', + 'Remington', + 'Raya', + 'Frierson', + 'Olszewski', + 'Quillen', + 'Westcott', + 'Fu', + 'Tolley', + 'Olive', + 'Mcclary', + 'Corbitt', + 'Lui', + 'Lachance', + 'Meagher', + 'Cowley', + 'Hudak', + 'Cress', + 'Mccrory', + 'Talavera', + 'Mclaren', + 'Laurent', + 'Bias', + 'Whetstone', + 'Hollister', + 'Quevedo', + 'Byerly', + 'Berryhill', + 'Folk', + 'Conners', + 'Kellum', + 'Haro', + 'Mallard', + 'Mccants', + 'Risner', + 'Barros', + 'Downes', + 'Mayers', + 'Loeffler', + 'Mink', + 'Hotchkiss', + 'Bartz', + 'Alt', + 'Hindman', + 'Bayne', + 'Bagby', + 'Colin', + 'Treadwell', + 'Hemingway', + 'Bane', + 'Heintz', + 'Fite', + 'Mccomb', + 'Carmody', + 'Kistler', + 'Olinger', + 'Vestal', + 'Byrum', + 'Seale', + 'Turnage', + 'Raber', + 'Prendergast', + 'Koons', + 'Nickell', + 'Benz', + 'Mcculley', + 'Lightner', + 'Hamill', + 'Castellon', + 'Chesser', + 'Moats', + 'Buie', + 'Svoboda', + 'Wold', + 'Macmillan', + 'Boring', + 'Terrill', + 'Loveland', + 'Gaskill', + 'Verdugo', + 'Yip', + 'Oviedo', + 'Hight', + 'Carmack', + 'Scheer', + 'Dreher', + 'Appleby', + 'Lally', + 'Kibler', + 'Marra', + 'Mcnamee', + 'Cooks', + 'Kavanaugh', + 'Carrico', + 'Alden', + 'Dillman', + 'Zamarripa', + 'Serra', + 'Gilligan', + 'Nester', + 'Sokol', + 'Latta', + 'Hanrahan', + 'Ballou', + 'Hollinger', + 'Lux', + 'Caton', + 'Hamann', + 'Sackett', + 'Leiva', + 'Emory', + 'Barden', + 'Houk', + 'Lees', + 'Deltoro', + 'Lowrey', + 'Mcevoy', + 'Hibbs', + 'Crossley', + 'Rego', + 'Melchor', + 'Tull', + 'Bramlett', + 'Hsieh', + 'Warwick', + 'Sayles', + 'Mapes', + 'Pabon', + 'Dearing', + 'Stamm', + 'Joshi', + 'Quan', + 'Larry', + 'Nordstrom', + 'Heisler', + 'Bigham', + 'Walston', + 'Solberg', + 'Bodnar', + 'Posada', + 'Mancilla', + 'Ovalle', + 'Harr', + 'Mccaskill', + 'Bromley', + 'Koerner', + 'Macpherson', + 'Trudeau', + 'Blais', + 'Kiley', + 'Lawlor', + 'Suter', + 'Rothman', + 'Oberg', + 'Seely', + 'Maxfield', + 'Truman', + 'Salvatore', + 'Fouts', + 'Goulet', + 'Munger', + 'Sikora', + 'Comeau', + 'Oliphant', + 'Baber', + 'Hensel', + 'Edelman', + 'Farina', + 'Albano', + 'Aycock', + 'Sung', + 'Deckard', + 'Steinke', + 'Silveira', + 'Servin', + 'Rex', + 'Franzen', + 'Hecker', + 'Gragg', + 'Mcgriff', + 'Ellingson', + 'Kerrigan', + 'An', + 'Bartel', + 'Priddy', + 'Hodson', + 'Tse', + 'Arbogast', + 'Arceneaux', + 'Leatherman', + 'Federico', + 'Pridgen', + 'Yim', + 'Kowalczyk', + 'Deberry', + 'Lejeune', + 'Elston', + 'Mielke', + 'Shelly', + 'Stambaugh', + 'Eagan', + 'Rivard', + 'Silvia', + 'Lawhorn', + 'Denis', + 'Hendry', + 'Wieland', + 'Levinson', + 'Marlin', + 'Gerdes', + 'Pfister', + 'Carder', + 'Pipkin', + 'Angle', + 'Hang', + 'Hagerty', + 'Rhinehart', + 'Gao', + 'Petit', + 'Mccraw', + 'Markle', + 'Lupo', + 'Busse', + 'Marble', + 'Bivins', + 'Storms', + 'Yuan', + 'Waldman', + 'Suh', + 'Wyckoff', + 'Stillman', + 'Piotrowski', + 'Abrego', + 'Gregoire', + 'Bogle', + 'Wortham', + 'Phung', + 'Brister', + 'Karnes', + 'Deming', + 'Ley', + 'Carrasquillo', + 'Curtiss', + 'Appleton', + 'Salley', + 'Borja', + 'Begum', + 'Phifer', + 'Shoup', + 'Cawley', + 'Deason', + 'Castanon', + 'Loucks', + 'Hagler', + 'Mcclinton', + 'Dulaney', + 'Hargett', + 'Mcardle', + 'Burcham', + 'Philpot', + 'Laroche', + 'Breland', + 'Hatten', + 'Karp', + 'Brummett', + 'Boatman', + 'Natale', + 'Pepe', + 'Mortimer', + 'Sink', + 'Voyles', + 'Reeve', + 'Honaker', + 'Loredo', + 'Ridgway', + 'Donner', + 'Lessard', + 'Dever', + 'Salomon', + 'Hickson', + 'Nicholls', + 'Bushey', + 'Osteen', + 'Reavis', + 'Rodman', + 'Barahona', + 'Knecht', + 'Hinman', + 'Faria', + 'Dana', + 'Bancroft', + 'Hatchett', + 'Hageman', + 'Klaus', + 'Castor', + 'Lampkin', + 'Dalessandro', + 'Riffle', + 'Korn', + 'Savoie', + 'Sandifer', + 'Mciver', + 'Magill', + 'Delafuente', + 'Widener', + 'Vermillion', + 'Dandrea', + 'Mader', + 'Woodman', + 'Milan', + 'Hollowell', + 'Schaaf', + 'Kao', + 'Nail', + 'Beaman', + 'Hawkes', + 'Mclane', + 'Marchant', + 'Scanlan', + 'Syed', + 'Peabody', + 'Uhl', + 'Schauer', + 'Azevedo', + 'Wolcott', + 'Mick', + 'Melgar', + 'Pilcher', + 'Burgin', + 'Weiser', + 'Daughtry', + 'Theisen', + 'Babbitt', + 'Petry', + 'Cotten', + 'Fick', + 'Eubank', + 'Tolson', + 'Judkins', + 'Cronk', + 'Wendel', + 'Monteiro', + 'Kissinger', + 'Banta', + 'Senn', + 'Fix', + 'Brehm', + 'Rittenhouse', + 'Banner', + 'Elwell', + 'Herd', + 'Araiza', + 'Hui', + 'Nowell', + 'Brett', + 'Hua', + 'Breeding', + 'Pawlowski', + 'Thompkins', + 'Bocanegra', + 'Bosworth', + 'Dutcher', + 'Cotto', + 'Beecher', + 'Callender', + 'Hamlett', + 'Benfield', + 'Claudio', + 'Reel', + 'Brookshire', + 'Helmick', + 'Ryals', + 'Winder', + 'Thom', + 'Robin', + 'Overman', + 'Furtado', + 'Dacosta', + 'Paddock', + 'Dancy', + 'Carpio', + 'Manzanares', + 'Zito', + 'Favela', + 'Beckley', + 'Adrian', + 'Flory', + 'Nestor', + 'Spell', + 'Speight', + 'Strawn', + 'Beckner', + 'Gause', + 'Berglund', + 'Ruppert', + 'Mincey', + 'Spinelli', + 'Suzuki', + 'Mizell', + 'Kirksey', + 'Bolduc', + 'Kilmer', + 'Wesson', + 'Brinker', + 'Urrutia', + 'Markey', + 'Brenneman', + 'Haupt', + 'Sievers', + 'Puga', + 'Halloran', + 'Birdsong', + 'Stancil', + 'Wiener', + 'Calvo', + 'Macy', + 'Cairns', + 'Kahl', + 'Vice', + 'Ordaz', + 'Grow', + 'Lafrance', + 'Dryden', + 'Studer', + 'Matney', + 'Edward', + 'Rackley', + 'Gurrola', + 'Demoss', + 'Woolard', + 'Oquinn', + 'Hambrick', + 'Christmas', + 'Robey', + 'Crayton', + 'Haber', + 'Arango', + 'Newcomer', + 'Groom', + 'Corson', + 'Harness', + 'Rossman', + 'Slaton', + 'Schutz', + 'Conant', + 'Tedder', + 'Sabin', + 'Lowder', + 'Womble', + 'Jin', + 'Monday', + 'Garmon', + 'Aronson', + 'Skeen', + 'Headrick', + 'Lefevre', + 'Whittemore', + 'Pelton', + 'Barner', + 'Hildebrandt', + 'Rick', + 'Helmer', + 'Grose', + 'Zak', + 'Schroder', + 'Mahler', + 'Keeley', + 'Flinn', + 'Jordon', + 'Ozuna', + 'Sand', + 'Henkel', + 'Turcotte', + 'Vining', + 'Bellinger', + 'Neese', + 'Hagerman', + 'Mcmillin', + 'Gaylord', + 'Harney', + 'Milano', + 'Carothers', + 'Depew', + 'Bucci', + 'Pirtle', + 'Hafner', + 'Dimas', + 'Howlett', + 'Reber', + 'Abram', + 'Davalos', + 'Zajac', + 'Pedro', + 'Goodall', + 'Kaylor', + 'Wrenn', + 'Gartner', + 'Kell', + 'Curl', + 'Leathers', + 'Spiller', + 'Beason', + 'Shattuck', + 'Brewington', + 'Pinon', + 'Nazario', + 'Wash', + 'Ruggles', + 'Matz', + 'Capers', + 'Dorsett', + 'Wilmoth', + 'Bracey', + 'Lenhart', + 'Devoe', + 'Choy', + 'Oswalt', + 'Capone', + 'Wayman', + 'Parikh', + 'Eastwood', + 'Cofield', + 'Rickert', + 'Mccandless', + 'Greenway', + 'Majewski', + 'Rigdon', + 'Armbruster', + 'Royce', + 'Sterner', + 'Swaim', + 'Flournoy', + 'Amezcua', + 'Delano', + 'Westerman', + 'Grau', + 'Claxton', + 'Veliz', + 'Haun', + 'Roscoe', + 'Mccafferty', + 'Ringer', + 'Volz', + 'Blessing', + 'Mcphail', + 'Thelen', + 'Gagliardi', + 'Scholz', + 'Genovese', + 'Boyette', + 'Squire', + 'Naughton', + 'Levitt', + 'Erskine', + 'Leffler', + 'Manchester', + 'Hallett', + 'Whitmer', + 'Gillett', + 'Groce', + 'Roos', + 'Bejarano', + 'Moskowitz', + 'Constantine', + 'Fidler', + 'Roll', + 'Schutte', + 'Ohare', + 'Warnock', + 'Wester', + 'Macgregor', + 'Golding', + 'Abner', + 'Burgett', + 'Bushnell', + 'Brazil', + 'Ascencio', + 'Hock', + 'Legrand', + 'Eversole', + 'Rome', + 'Radcliff', + 'Fuhrman', + 'Schmit', + 'Tew', + 'Caro', + 'Cowen', + 'Marriott', + 'Kephart', + 'Hartung', + 'Keil', + 'Benally', + 'Hazlett', + 'Avant', + 'Desrosiers', + 'Kwong', + 'Guyer', + 'Penner', + 'Avelar', + 'Cashman', + 'Stith', + 'Orona', + 'Rager', + 'Johanson', + 'Lanza', + 'Min', + 'Cool', + 'Heine', + 'Nissen', + 'Buenrostro', + 'Mcmullin', + 'Oropeza', + 'Hom', + 'Degroot', + 'Wescott', + 'Hulbert', + 'Shrum', + 'Muncy', + 'Littrell', + 'Forest', + 'Dyke', + 'Garces', + 'Cimino', + 'Gebhardt', + 'Hickerson', + 'Satterwhite', + 'Radke', + 'Luckey', + 'Coronel', + 'Pugliese', + 'Frazee', + 'Siddiqui', + 'Flatt', + 'Abbey', + 'Gerald', + 'Bodine', + 'Lora', + 'Youngs', + 'Catlett', + 'Alexis', + 'Luo', + 'Youmans', + 'Sherlock', + 'Kinser', + 'Wales', + 'Dinsmore', + 'Abramson', + 'Stricker', + 'Rumsey', + 'Showers', + 'Mickens', + 'Tallent', + 'Setzer', + 'Etter', + 'Allgood', + 'Pagel', + 'Jefferies', + 'Bissell', + 'Colombo', + 'Musgrave', + 'Kuehl', + 'Raab', + 'Kavanagh', + 'Beane', + 'Witcher', + 'Pattison', + 'Paulus', + 'Gong', + 'Mcgough', + 'Burkhalter', + 'Vanbuskirk', + 'Kite', + 'Sass', + 'Lalonde', + 'Gormley', + 'Baier', + 'Brauer', + 'Stricklin', + 'Napoli', + 'Brotherton', + 'Stansbury', + 'Loggins', + 'Sorrentino', + 'Poff', + 'Nieman', + 'Roebuck', + 'Reiner', + 'Hovey', + 'Walley', + 'Leech', + 'Gambino', + 'Hammack', + 'Burson', + 'Tatro', + 'Perrine', + 'Carley', + 'Stadler', + 'Nason', + 'Peckham', + 'Gervais', + 'Ables', + 'Turman', + 'Dore', + 'Peavy', + 'Addington', + 'Tobar', + 'Gilstrap', + 'Brumbaugh', + 'Gerhardt', + 'Slusher', + 'Nevins', + 'Garofalo', + 'Amick', + 'Barrick', + 'Race', + 'Daggett', + 'Manion', + 'Noah', + 'Kranz', + 'Runge', + 'Wysocki', + 'Gillum', + 'Verduzco', + 'Alvey', + 'Pettus', + 'Sim', + 'Cage', + 'Mckean', + 'Harrod', + 'Weatherspoon', + 'Takahashi', + 'Wingard', + 'Endres', + 'Skiles', + 'Wald', + 'Finger', + 'Reams', + 'Ussery', + 'Fricke', + 'Jaworski', + 'Cusick', + 'Stanek', + 'Shaner', + 'Massaro', + 'Ribeiro', + 'Eades', + 'Rue', + 'Scharf', + 'Standridge', + 'Wojciechowski', + 'Victoria', + 'Galbreath', + 'Lander', + 'Martinelli', + 'Raper', + 'Karas', + 'Tomas', + 'La', + 'Kizer', + 'Gastelum', + 'Delp', + 'Sansone', + 'Therrien', + 'Brookins', + 'Shi', + 'Hammel', + 'Polley', + 'Riddell', + 'Claiborne', + 'Lampe', + 'Benham', + 'Braddock', + 'Elwood', + 'Mcminn', + 'Amerson', + 'Leija', + 'Gambrell', + 'Nuno', + 'Mallon', + 'Gard', + 'Burford', + 'Halley', + 'Maley', + 'Eicher', + 'Caban', + 'Rubenstein', + 'Tighe', + 'Harbaugh', + 'Bergmann', + 'Runnels', + 'Carrizales', + 'Gustin', + 'Wight', + 'Dominick', + 'Cannady', + 'Brace', + 'Beauregard', + 'Weitzel', + 'Orcutt', + 'Abrahamson', + 'Jorge', + 'Mccown', + 'Harriman', + 'Nicol', + 'Gott', + 'Andino', + 'Tsosie', + 'Shumway', + 'Aucoin', + 'Bowes', + 'Hixon', + 'Broom', + 'Cate', + 'Desantiago', + 'Haug', + 'Pinedo', + 'Mowry', + 'Moyers', + 'Deangelo', + 'Mcshane', + 'Boley', + 'Tiffany', + 'Steger', + 'Woodford', + 'Whitford', + 'Collette', + 'Muth', + 'Mansour', + 'Schuh', + 'Fortney', + 'Khoury', + 'Livengood', + 'Haworth', + 'Rusk', + 'Mathieu', + 'Peppers', + 'Gehring', + 'Faris', + 'Diep', + 'Rae', + 'Hupp', + 'Escalera', + 'Gwin', + 'Engelhardt', + 'Bannon', + 'Menjivar', + 'Eberhart', + 'Kershaw', + 'Cottle', + 'Palomares', + 'Carrell', + 'Galaviz', + 'Willie', + 'Troxell', + 'Visser', + 'Xie', + 'Juan', + 'Spector', + 'Izzo', + 'Woodring', + 'Gilbreath', + 'Bey', + 'Giraldo', + 'Neary', + 'Ready', + 'Toland', + 'Benge', + 'Thrower', + 'Bemis', + 'Hostetter', + 'Dull', + 'Poulos', + 'Vanegas', + 'Abad', + 'Harker', + 'Mei', + 'Nigro', + 'Messner', + 'Peres', + 'Hardaway', + 'Crumpton', + 'Dingman', + 'Hipp', + 'Lemley', + 'Maloy', + 'Ye', + 'Neighbors', + 'Proulx', + 'Jamerson', + 'Finkelstein', + 'Payan', + 'Holler', + 'Simonds', + 'Toms', + 'Schulman', + 'Aguero', + 'Hinrichs', + 'Steffens', + 'Clapper', + 'Delao', + 'Knighton', + 'Jahn', + 'Mach', + 'Heal', + 'Detwiler', + 'Corso', + 'Toner', + 'Rook', + 'Brockway', + 'Coulson', + 'Delia', + 'Giddings', + 'Hermosillo', + 'Ballenger', + 'Persinger', + 'Delk', + 'Pedigo', + 'Burg', + 'Voelker', + 'Ecker', + 'Kile', + 'Propst', + 'Rascon', + 'Stultz', + 'Swindle', + 'Swindell', + 'Deaver', + 'Welty', + 'Sussman', + 'Southworth', + 'Child', + 'Coston', + 'Lei', + 'Spillman', + 'Hochstetler', + 'Veach', + 'Melcher', + 'Chipman', + 'Lebeau', + 'Summerville', + 'Peden', + 'Lizarraga', + 'Kingery', + 'Leos', + 'Fogel', + 'Eckman', + 'Burbank', + 'Castano', + 'Chartier', + 'Medellin', + 'Torrey', + 'Peake', + 'Swinney', + 'Aziz', + 'Reinert', + 'Borg', + 'Pires', + 'Brooke', + 'Forester', + 'Greaves', + 'Delapaz', + 'Hunnicutt', + 'Bierman', + 'Stringfellow', + 'Lavallee', + 'Farnham', + 'Gadson', + 'Gainer', + 'Kulp', + 'Liston', + 'Brooker', + 'Loudermilk', + 'Reza', + 'Henshaw', + 'Hinz', + 'Brammer', + 'Frisch', + 'Toombs', + 'Esquibel', + 'Feinberg', + 'Plaza', + 'Bly', + 'Encarnacion', + 'Cockerham', + 'Shealy', + 'Haile', + 'Nave', + 'Chenoweth', + 'Goto', + 'Ernest', + 'Staub', + 'Marty', + 'Huizar', + 'Lammers', + 'Mcavoy', + 'Dishman', + 'Giroux', + 'Dowdell', + 'Via', + 'Fenn', + 'Kain', + 'Breckenridge', + 'Egbert', + 'Steelman', + 'Gasper', + 'Riojas', + 'Parmer', + 'Creed', + 'Gillispie', + 'Edgerton', + 'Yen', + 'Calder', + 'Holmberg', + 'Kreider', + 'Landau', + 'Eley', + 'Lewallen', + 'Quimby', + 'Holladay', + 'Du', + 'Leland', + 'Hyder', + 'Omeara', + 'Acton', + 'Gaspard', + 'Kennard', + 'Renfroe', + 'Hayman', + 'Gladney', + 'Glidden', + 'Wilmot', + 'Pearsall', + 'Cahoon', + 'Hallock', + 'Grigg', + 'Boggess', + 'Lewin', + 'Doering', + 'Thach', + 'Mcatee', + 'Paulk', + 'Rusch', + 'Harrold', + 'Suttles', + 'Chiles', + 'Sawyers', + 'Roger', + 'Kwok', + 'Luevano', + 'Coelho', + 'Waldo', + 'Ewell', + 'Lagunas', + 'Rude', + 'Barrington', + 'Mccomas', + 'Whiteley', + 'Jeanbaptiste', + 'Darcy', + 'Lussier', + 'Kerley', + 'Fordham', + 'Moorehead', + 'Welton', + 'Nicely', + 'Constantino', + 'Townes', + 'Giglio', + 'Damian', + 'Mckibben', + 'Resnick', + 'Endicott', + 'Lindeman', + 'Killion', + 'Gwinn', + 'Beaumont', + 'Nord', + 'Miceli', + 'Fast', + 'Bidwell', + 'Sites', + 'Drum', + 'Maze', + 'Abshire', + 'Berner', + 'Rhyne', + 'Juliano', + 'Wortman', + 'Beggs', + 'Winchell', + 'Summerlin', + 'Thrash', + 'Biggers', + 'Buckles', + 'Barnwell', + 'Thomasson', + 'Wan', + 'Arneson', + 'Rodrigue', + 'Wroblewski', + 'Quiroga', + 'Fulk', + 'Dillingham', + 'Rone', + 'Mapp', + 'Sattler', + 'Letourneau', + 'Gaudet', + 'Mccaslin', + 'Gurule', + 'Huck', + 'Hudspeth', + 'Welter', + 'Wittman', + 'Hileman', + 'Ewald', + 'Yao', + 'Kindred', + 'Kato', + 'Nickels', + 'Tyndall', + 'Sanmiguel', + 'Mayle', + 'Alfano', + 'Eichelberger', + 'Bee', + 'Sheehy', + 'Rogan', + 'Philip', + 'Dilworth', + 'Midkiff', + 'Hudgens', + 'Killingsworth', + 'Russel', + 'Criss', + 'Liddell', + 'Eberly', + 'Khalil', + 'Lattimore', + 'Koval', + 'Maxson', + 'Schram', + 'Goodell', + 'Catlin', + 'Cofer', + 'Alva', + 'Sandler', + 'Kunkle', + 'Perron', + 'Bushman', + 'Edmonson', + 'Roa', + 'Nesbit', + 'Ahearn', + 'Garver', + 'Bible', + 'Barley', + 'Struble', + 'Oxford', + 'Wulf', + 'Marron', + 'Haught', + 'Bonnell', + 'Pigg', + 'Friel', + 'Almaguer', + 'Bowler', + 'Mitchem', + 'Fussell', + 'Lemos', + 'Savino', + 'Boisvert', + 'Torgerson', + 'Annis', + 'Dicks', + 'Ruhl', + 'Pepin', + 'Wildman', + 'Gendron', + 'Melanson', + 'Sherer', + 'Duty', + 'Cassel', + 'Croteau', + 'Rolon', + 'Staats', + 'Pass', + 'Larocca', + 'Sauter', + 'Sacks', + 'Boutwell', + 'Hunsaker', + 'Omara', + 'Mcbroom', + 'Lohman', + 'Treat', + 'Dufour', + 'Brashear', + 'Yepez', + 'Lao', + 'Telles', + 'Manis', + 'Mars', + 'Shilling', + 'Tingle', + 'Macaluso', + 'Rigney', + 'Clair', + 'Matsumoto', + 'Agosto', + 'Halbert', + 'Dabbs', + 'Eckstein', + 'Mercurio', + 'Berkley', + 'Wachter', + 'Langan', + 'Peach', + 'Carreno', + 'Lepore', + 'Howie', + 'Thaxton', + 'Arrowood', + 'Weinberger', + 'Eldred', + 'Hooten', + 'Raymer', + 'Feaster', + 'Bosco', + 'Cataldo', + 'Fears', + 'Eckhardt', + 'Mullinax', + 'Spratt', + 'Laboy', + 'Marsden', + 'Carlile', + 'Bustillos', + 'Crim', + 'Surratt', + 'Kurth', + 'Gaul', + 'Machuca', + 'Rolfe', + 'Lower', + 'Edmiston', + 'Millsap', + 'Dehaven', + 'Racine', + 'Coney', + 'Rinker', + 'Maddux', + 'Burmeister', + 'Fenwick', + 'Stocks', + 'Forde', + 'Pettway', + 'Balderrama', + 'Westover', + 'Bloch', + 'Burress', + 'Hunley', + 'Futch', + 'Chee', + 'Alvarenga', + 'Bostwick', + 'Cleaver', + 'Pelkey', + 'Bryce', + 'Pisano', + 'Qureshi', + 'Varghese', + 'Cunha', + 'Hellman', + 'Grass', + 'Luker', + 'Hazelton', + 'Cathcart', + 'Yamada', + 'Gallego', + 'Menke', + 'Yingling', + 'Merriweather', + 'Fleury', + 'Salmeron', + 'Metcalfe', + 'Brook', + 'Freitag', + 'Malek', + 'Obregon', + 'Blain', + 'Mellott', + 'Alam', + 'Bessette', + 'Moncrief', + 'Arvizu', + 'Botts', + 'Moorer', + 'Landreth', + 'Hulett', + 'Marinelli', + 'Falco', + 'Silvestri', + 'Gottschalk', + 'Thiele', + 'Kight', + 'Warrington', + 'Huckaby', + 'Ledet', + 'Charbonneau', + 'Crozier', + 'Mohan', + 'Stroh', + 'Bolinger', + 'Delvecchio', + 'Macfarlane', + 'Cribbs', + 'Mcloughlin', + 'Maynor', + 'Ming', + 'Digiovanni', + 'Truesdale', + 'Pfeffer', + 'Benn', + 'Chaparro', + 'Englert', + 'Spano', + 'Ogletree', + 'Yancy', + 'Swick', + 'Hallmark', + 'Mattern', + 'Tryon', + 'Plumb', + 'Martineau', + 'Man', + 'Grube', + 'Holst', + 'Nez', + 'Belden', + 'Aikens', + 'Litton', + 'Moorhead', + 'Dufresne', + 'Bonney', + 'Heyward', + 'Halliday', + 'Ito', + 'Crossman', + 'Gast', + 'Levan', + 'Wine', + 'Desouza', + 'Kornegay', + 'Nam', + 'Keough', + 'Stotts', + 'Dickenson', + 'Ousley', + 'Leduc', + 'Revels', + 'Dizon', + 'Arreguin', + 'Shockey', + 'Alegria', + 'Blades', + 'Ignacio', + 'Mellon', + 'Ebersole', + 'Sain', + 'Weissman', + 'Wargo', + 'Claypool', + 'Zorn', + 'Julien', + 'Hinshaw', + 'Alberto', + 'Garduno', + 'Kellar', + 'Rizo', + 'Labonte', + 'Humble', + 'Downer', + 'Lykins', + 'Tower', + 'Vanhouten', + 'Chairez', + 'Campa', + 'Blizzard', + 'Standley', + 'Reiser', + 'Whitener', + 'Menefee', + 'Nalley', + 'Lasher', + 'Strang', + 'Smock', + 'Moralez', + 'Kiel', + 'Moffatt', + 'Behm', + 'Hackworth', + 'Dirks', + 'Kratz', + 'Guillot', + 'Tittle', + 'Stlouis', + 'Seymore', + 'Searle', + 'Utter', + 'Wilborn', + 'Dortch', + 'Duron', + 'Cardinal', + 'Spikes', + 'Arambula', + 'Cutter', + 'Dibenedetto', + 'Botelho', + 'Bedwell', + 'Kilby', + 'Bottoms', + 'Cassady', + 'Rothwell', + 'Bilodeau', + 'Markowitz', + 'Baucom', + 'Valley', + 'Esqueda', + 'Depalma', + 'Laskowski', + 'Hopp', + 'Casale', + 'Perreault', + 'Shuster', + 'Wolter', + 'Raby', + 'Cyrus', + 'Tseng', + 'Georges', + 'Das', + 'Wilfong', + 'Schlueter', + 'Woolf', + 'Stickney', + 'Mcinerney', + 'Curcio', + 'Fowlkes', + 'Boldt', + 'Zander', + 'Shropshire', + 'Antonelli', + 'Froehlich', + 'Butterworth', + 'Stedman', + 'Broadnax', + 'Kroeger', + 'Kellner', + 'Monreal', + 'Armas', + 'Mcguinness', + 'Canterbury', + 'Weisman', + 'Hilburn', + 'Carruthers', + 'Pell', + 'Peele', + 'Devaney', + 'Owings', + 'Mar', + 'Liggett', + 'Breslin', + 'Soucy', + 'Aguila', + 'Weidman', + 'Mingo', + 'Tarango', + 'Winger', + 'Poteet', + 'Acree', + 'Mcnew', + 'Leatherwood', + 'Aubrey', + 'Waring', + 'Soler', + 'Roof', + 'Sunderland', + 'Blackford', + 'Rabe', + 'Hepler', + 'Leonardo', + 'Spina', + 'Smythe', + 'Alex', + 'Barta', + 'Bybee', + 'Campagna', + 'Pete', + 'Batchelder', + 'Gurney', + 'Wyche', + 'Schutt', + 'Rashid', + 'Almazan', + 'Pahl', + 'Perri', + 'Viramontes', + 'Cavender', + 'Snapp', + 'Newson', + 'Sandhu', + 'Fernando', + 'Stockdale', + 'Garfield', + 'Ealy', + 'Mcfarlin', + 'Bieber', + 'Callan', + 'Arruda', + 'Oquendo', + 'Levasseur', + 'Maple', + 'Kowal', + 'Kushner', + 'Naquin', + 'Shouse', + 'Mcquade', + 'Cai', + 'Smedley', + 'Gober', + 'Saiz', + 'Brunelle', + 'Arbuckle', + 'Landes', + 'Mak', + 'Korte', + 'Oxley', + 'Boger', + 'Mickey', + 'Lent', + 'Cureton', + 'Husted', + 'Eidson', + 'Boyett', + 'Kitts', + 'Shope', + 'Hance', + 'Jessen', + 'Litchfield', + 'Torre', + 'Cargill', + 'Herren', + 'Straight', + 'Merz', + 'Weese', + 'Sperling', + 'Lapierre', + 'Yung', + 'Doggett', + 'Cauley', + 'Hardeman', + 'Margolis', + 'Watford', + 'Seltzer', + 'Fullmer', + 'Timberlake', + 'Butz', + 'Duquette', + 'Olin', + 'Leverett', + 'Hartford', + 'Otte', + 'Beaton', + 'Grimaldi', + 'Marotta', + 'Carlsen', + 'Cullum', + 'Monte', + 'Haygood', + 'Middlebrooks', + 'Lazarus', + 'Shiver', + 'Ivie', + 'Niemi', + 'Lacombe', + 'Judson', + 'Ginsberg', + 'Firestone', + 'Izquierdo', + 'Deel', + 'Jacinto', + 'Towers', + 'Fritsch', + 'Albin', + 'Kaminsky', + 'Yin', + 'Wrobel', + 'Birdwell', + 'Krieg', + 'Danforth', + 'Florio', + 'Saito', + 'Clift', + 'Duck', + 'Matt', + 'Moxley', + 'Barbieri', + 'Klatt', + 'Saltzman', + 'Chesney', + 'Bojorquez', + 'Cosentino', + 'Lodge', + 'Converse', + 'Decastro', + 'Gerhart', + 'Music', + 'Danley', + 'Santangelo', + 'Bevins', + 'Coen', + 'Seibel', + 'Lindemann', + 'Dressler', + 'Newport', + 'Bedolla', + 'Lillie', + 'Rhone', + 'Penaloza', + 'Swart', + 'Niemeyer', + 'Pilkington', + 'Matta', + 'Hollifield', + 'Gillman', + 'Montana', + 'Maroney', + 'Stenger', + 'Loos', + 'Wert', + 'Brogdon', + 'Gandhi', + 'Bent', + 'Tabb', + 'Sikorski', + 'Hagedorn', + 'Hannigan', + 'Hoss', + 'Conlin', + 'Trott', + 'Fall', + 'Granado', + 'Bartell', + 'Rubalcava', + 'Neves', + 'Poynter', + 'Alton', + 'Paschall', + 'Waltman', + 'Parke', + 'Kittle', + 'Czarnecki', + 'Bloodworth', + 'Knorr', + 'Timms', + 'Derry', + 'Messier', + 'Saad', + 'Cozart', + 'Sutphin', + 'Puryear', + 'Gatto', + 'Whitacre', + 'Verdin', + 'Bloomer', + 'Brundage', + 'Brian', + 'Seger', + 'Clare', + 'Balch', + 'Tharpe', + 'Rayford', + 'Halter', + 'Barefoot', + 'Gonsalez', + 'Lomas', + 'Monzon', + 'Howarth', + 'Mccready', + 'Gudino', + 'Serafin', + 'Sanfilippo', + 'Minnich', + 'Eldredge', + 'Malave', + 'Greeley', + 'Sisneros', + 'Kangas', + 'Peery', + 'Lunn', + 'Lukas', + 'Bunce', + 'Riccio', + 'Thies', + 'Stivers', + 'Conard', + 'Mullaney', + 'Catalan', + 'Omar', + 'Theobald', + 'Jeffcoat', + 'Kucera', + 'Borkowski', + 'Coomer', + 'Mathison', + 'Croom', + 'Rushton', + 'Stites', + 'Pendley', + 'Till', + 'Oconner', + 'Forsberg', + 'Wages', + 'Fillmore', + 'Barcenas', + 'Gillard', + 'Leak', + 'Towle', + 'Esser', + 'Dunlop', + 'Quackenbush', + 'Archambault', + 'Buller', + 'Newlin', + 'Urquhart', + 'Shanley', + 'Mote', + 'Ippolito', + 'Rozier', + 'Reidy', + 'Gregor', + 'Swaney', + 'Bradfield', + 'Fudge', + 'More', + 'Tester', + 'Higley', + 'Dambrosio', + 'Bullington', + 'Highsmith', + 'Silas', + 'Felker', + 'Sawicki', + 'Beltz', + 'Albarran', + 'Aitken', + 'Findlay', + 'Looper', + 'Tooley', + 'Lasley', + 'Moynihan', + 'Ratcliffe', + 'Grizzle', + 'Souders', + 'Nussbaum', + 'Suber', + 'Macdougall', + 'Waddle', + 'Brawner', + 'Tucci', + 'Cosme', + 'Walk', + 'Gordy', + 'Tarrant', + 'Rosenblum', + 'Huth', + 'Bridgeman', + 'Hinkley', + 'Gehrke', + 'Boden', + 'Suazo', + 'Gambill', + 'Widner', + 'Chick', + 'Mccollough', + 'Hassler', + 'Odum', + 'Pawlak', + 'Prevost', + 'Slavin', + 'Fetters', + 'Beamon', + 'Renshaw', + 'Deng', + 'Plourde', + 'Holstein', + 'Rye', + 'Holliman', + 'Melville', + 'Messinger', + 'Turcios', + 'Garnica', + 'Feeley', + 'Mariani', + 'Otten', + 'Dorado', + 'Mortenson', + 'Meissner', + 'Scarlett', + 'Sweitzer', + 'Glisson', + 'Desjardins', + 'Penland', + 'Elledge', + 'Crumley', + 'Deen', + 'Shih', + 'Heuer', + 'Gloria', + 'Lail', + 'Mcandrew', + 'Mcnaughton', + 'Cortese', + 'Stgermain', + 'Hammon', + 'Leininger', + 'Flickinger', + 'Dement', + 'Bumgardner', + 'Tessier', + 'Fulford', + 'Cervantez', + 'Wisner', + 'Shulman', + 'Sabol', + 'Papp', + 'Strasser', + 'Sartin', + 'Rothstein', + 'Grote', + 'Beaudry', + 'Deville', + 'Roop', + 'Villar', + 'Bussell', + 'Bowyer', + 'Yoshida', + 'Hertz', + 'Countryman', + 'Hoey', + 'Roseberry', + 'Schock', + 'Boozer', + 'Mccowan', + 'Kirschner', + 'Lechner', + 'Winkelman', + 'Witham', + 'Thurber', + 'Depriest', + 'Chenault', + 'Moten', + 'Tillotson', + 'Guan', + 'Ketcham', + 'Jiles', + 'Grosso', + 'Nottingham', + 'Kellam', + 'Alejo', + 'Thoma', + 'Marchetti', + 'Holifield', + 'Fortson', + 'Leasure', + 'Mceachern', + 'Oceguera', + 'Carleton', + 'Weekley', + 'Kinsella', + 'Harvell', + 'Waldon', + 'Kean', + 'Chancellor', + 'Blosser', + 'Detweiler', + 'Presnell', + 'Beachy', + 'Lingle', + 'Plumley', + 'Knopp', + 'Gamache', + 'Atwater', + 'Caine', + 'Woodland', + 'Terwilliger', + 'Moller', + 'Cleland', + 'Cottingham', + 'Janke', + 'Willman', + 'Dann', + 'Mangrum', + 'Shuck', + 'Paden', + 'Adelman', + 'Brim', + 'Tullis', + 'Hertel', + 'Gallaher', + 'Leopold', + 'Donegan', + 'Popovich', + 'Gusman', + 'Chatham', + 'Schooley', + 'Pinder', + 'Heise', + 'Maines', + 'Nystrom', + 'Jahnke', + 'Poon', + 'Murphree', + 'Pelaez', + 'Risley', + 'Sohn', + 'Shim', + 'Armentrout', + 'Kastner', + 'Philpott', + 'Mao', + 'Pursley', + 'Mangold', + 'Mccourt', + 'Hollar', + 'Desmarais', + 'Debord', + 'Gullett', + 'Gaeta', + 'Bae', + 'Houlihan', + 'Gorton', + 'Steinman', + 'Santo', + 'Snelling', + 'Corpuz', + 'Look', + 'Scudder', + 'Treece', + 'Binns', + 'Sokolowski', + 'Harner', + 'Gallup', + 'Marti', + 'Teasley', + 'Markel', + 'Casiano', + 'Nicks', + 'Recinos', + 'Paradise', + 'Colman', + 'Orange', + 'Mele', + 'Medford', + 'Templin', + 'Zuber', + 'Mackin', + 'Brodsky', + 'Householder', + 'Wirtz', + 'Hackman', + 'Tippett', + 'Polson', + 'Colston', + 'Cerna', + 'Herald', + 'Shults', + 'Shubert', + 'Mertens', + 'Dave', + 'Duffield', + 'Vanness', + 'Mayne', + 'Driskell', + 'Percy', + 'Lauderdale', + 'Cipriano', + 'Theodore', + 'Colella', + 'Kiger', + 'Brownfield', + 'Stella', + 'Wideman', + 'Maye', + 'Chisolm', + 'Muldoon', + 'Fitzwater', + 'Harville', + 'Dixson', + 'Burkey', + 'Hartsfield', + 'Schade', + 'Brawley', + 'Pelfrey', + 'Tennyson', + 'Whitted', + 'Silvas', + 'Harbour', + 'Krupa', + 'Peraza', + 'Erdmann', + 'Halpern', + 'Finnerty', + 'Mackinnon', + 'Humbert', + 'Mccarley', + 'Doster', + 'Kugler', + 'Livesay', + 'Force', + 'Haberman', + 'Lamp', + 'Hector', + 'Charron', + 'Woosley', + 'Rein', + 'Ashburn', + 'Greenleaf', + 'Niemann', + 'Carillo', + 'Skelly', + 'Nunnally', + 'Renfrow', + 'Prickett', + 'Angus', + 'Bednar', + 'Nightingale', + 'Steinbach', + 'Warnick', + 'Jason', + 'Hans', + 'Lydon', + 'Rutland', + 'Alleman', + 'Hawn', + 'Malin', + 'Beech', + 'Auger', + 'Desilva', + 'Izaguirre', + 'Isham', + 'Mandujano', + 'Glasser', + 'Dimarco', + 'Berumen', + 'Nipper', + 'Pegram', + 'Sundberg', + 'Labbe', + 'Mcphee', + 'Crafton', + 'Agustin', + 'Cantor', + 'Beller', + 'Bang', + 'Lawyer', + 'Croy', + 'Kyles', + 'Winans', + 'Battista', + 'Jost', + 'Bakken', + 'Dandridge', + 'Mustafa', + 'Ice', + 'Eklund', + 'Montesdeoca', + 'Hermes', + 'Grimaldo', + 'Vannoy', + 'Grainger', + 'Lamas', + 'Tarantino', + 'Witter', + 'Worthen', + 'Basinger', + 'Cowden', + 'Hiles', + 'Mcanally', + 'Felipe', + 'Gallimore', + 'Kapp', + 'Makowski', + 'Copenhaver', + 'Ramer', + 'Gideon', + 'Bowker', + 'Wilkens', + 'Seeger', + 'Huntsman', + 'Palladino', + 'Jessee', + 'Kittrell', + 'Rolle', + 'Ciccone', + 'Kolar', + 'Brannen', + 'Bixby', + 'Pohlman', + 'Strachan', + 'Lesher', + 'Fleischer', + 'Umana', + 'Murphey', + 'Mcentire', + 'Rabon', + 'Mcauley', + 'Bunton', + 'Soileau', + 'Sheriff', + 'Borowski', + 'Mullens', + 'Larrabee', + 'Prouty', + 'Malley', + 'Sumrall', + 'Reisinger', + 'Surber', + 'Kasten', + 'Shoemake', + 'Yowell', + 'Bonin', + 'Bevan', + 'Bove', + 'Boe', + 'Hazard', + 'Slay', + 'Carraway', + 'Kaczmarek', + 'Armitage', + 'Lowther', + 'Sheaffer', + 'Farah', + 'Atencio', + 'Ung', + 'Kirkham', + 'Cavanagh', + 'Mccutchen', + 'Shoop', + 'Nickles', + 'Borchardt', + 'Durkee', + 'Maus', + 'Shedd', + 'Petrillo', + 'Brainard', + 'Eddings', + 'Fanelli', + 'Seo', + 'Heaney', + 'Drennan', + 'Mcgarvey', + 'Saddler', + 'Lucia', + 'Higa', + 'Gailey', + 'Groh', + 'Hinckley', + 'Griner', + 'Norfleet', + 'Caplan', + 'Rademacher', + 'Souder', + 'Autrey', + 'Eskridge', + 'Drumm', + 'Fiske', + 'Giffin', + 'Townley', + 'Derose', + 'Burrus', + 'Castrejon', + 'Emmert', + 'Cothran', + 'Hartsell', + 'Kilburn', + 'Riggle', + 'Trussell', + 'Mulvey', + 'Barto', + 'Crank', + 'Lovely', + 'Woodhouse', + 'Powe', + 'Pablo', + 'Zack', + 'Murchison', + 'Dicarlo', + 'Kessel', + 'Hagood', + 'Rost', + 'Edson', + 'Blakeney', + 'Fant', + 'Brodeur', + 'Jump', + 'Spry', + 'Laguna', + 'Lotz', + 'Bergquist', + 'Collard', + 'Mash', + 'Rideout', + 'Bilbrey', + 'Selman', + 'Fortunato', + 'Holzer', + 'Pifer', + 'Mcabee', + 'Talamantes', + 'Tollefson', + 'Pastore', + 'Crew', + 'Wilcher', + 'Kutz', + 'Stallard', + 'Ressler', + 'Fehr', + 'Piercy', + 'Lafond', + 'Digiacomo', + 'Schuck', + 'Winkle', + 'Graybill', + 'Plata', + 'Gribble', + 'Odle', + 'Fraga', + 'Bressler', + 'Moultrie', + 'Tung', + 'Charette', + 'Marvel', + 'Kerby', + 'Mori', + 'Hamman', + 'Favors', + 'Freeze', + 'Delisle', + 'Straw', + 'Dingle', + 'Elizalde', + 'Cabello', + 'Zalewski', + 'Funkhouser', + 'Abate', + 'Nero', + 'Holston', + 'Josey', + 'Schreck', + 'Shroyer', + 'Paquin', + 'Bing', + 'Chauvin', + 'Maria', + 'Melgoza', + 'Arms', + 'Caddell', + 'Pitchford', + 'Sternberg', + 'Rana', + 'Lovelady', + 'Strouse', + 'Macarthur', + 'Lechuga', + 'Wolfson', + 'Mcglynn', + 'Koo', + 'Stoops', + 'Tetreault', + 'Lepage', + 'Duren', + 'Hartz', + 'Kissel', + 'Gish', + 'Largent', + 'Henninger', + 'Janson', + 'Carrick', + 'Kenner', + 'Haack', + 'Diego', + 'Wacker', + 'Wardell', + 'Ballentine', + 'Smeltzer', + 'Bibb', + 'Winton', + 'Bibbs', + 'Reinhard', + 'Nilsen', + 'Edison', + 'Kalinowski', + 'June', + 'Hewlett', + 'Blaisdell', + 'Zeman', + 'Chon', + 'Board', + 'Nealy', + 'Moretti', + 'Wanner', + 'Bonnett', + 'Hardie', + 'Mains', + 'Cordeiro', + 'Karim', + 'Kautz', + 'Craver', + 'Colucci', + 'Congdon', + 'Mounts', + 'Kurz', + 'Eder', + 'Merryman', + 'Soles', + 'Dulin', + 'Lubin', + 'Mcgowen', + 'Hockenberry', + 'Work', + 'Mazzola', + 'Crandell', + 'Mcgrady', + 'Caruthers', + 'Govea', + 'Meng', + 'Fetter', + 'Trusty', + 'Weintraub', + 'Hurlburt', + 'Reiff', + 'Nowakowski', + 'Hoard', + 'Densmore', + 'Blumenthal', + 'Neale', + 'Schiff', + 'Raleigh', + 'Steiger', + 'Marmolejo', + 'Jessie', + 'Palafox', + 'Tutt', + 'Keister', + 'Core', + 'Im', + 'Wendell', + 'Bennet', + 'Canning', + 'Krull', + 'Patti', + 'Zucker', + 'Schlesinger', + 'Wiser', + 'Dunson', + 'Olmedo', + 'Hake', + 'Champlin', + 'Braley', + 'Wheelock', + 'Geier', + 'Janis', + 'Turek', + 'Grindstaff', + 'Schaffner', + 'Deas', + 'Sirois', + 'Polito', + 'Bergin', + 'Schall', + 'Vineyard', + 'Pellegrini', + 'Corrado', + 'Oleson', + 'List', + 'Dameron', + 'Parkin', + 'Flake', + 'Hollingshead', + 'Chancey', + 'Hufford', + 'Morell', + 'Kantor', + 'Chasteen', + 'Laborde', + 'Sessoms', + 'Hermanson', + 'Burnell', + 'Dewberry', + 'Tolman', + 'Glasscock', + 'Durfee', + 'Gilroy', + 'Wilkey', + 'Dungan', + 'Saravia', + 'Weigand', + 'Bigler', + 'Vancleave', + 'Burlingame', + 'Roseman', + 'Stiffler', + 'Gagliano', + 'Kates', + 'Awad', + 'Knepp', + 'Rondeau', + 'Bertsch', + 'Wolverton', + 'Walcott', + 'Poss', + 'Frisby', + 'Wexler', + 'Reinhold', + 'Krol', + 'Stuck', + 'Ricciardi', + 'Ardoin', + 'Michaelson', + 'Lillard', + 'Burciaga', + 'Birchfield', + 'Patch', + 'Silvey', + 'Simmonds', + 'Siu', + 'Press', + 'Deans', + 'Riegel', + 'Ismail', + 'Magallon', + 'Diller', + 'Hine', + 'Michalak', + 'Dones', + 'Deitz', + 'Gulledge', + 'Stroman', + 'Kobayashi', + 'Hafer', + 'Berk', + 'Landin', + 'Gilles', + 'Obryant', + 'Cheeks', + 'Gress', + 'Lutes', + 'Raphael', + 'Pizano', + 'Bachmann', + 'Cifuentes', + 'Earp', + 'Gilreath', + 'Peluso', + 'Hubbs', + 'Alvis', + 'Peer', + 'Dutra', + 'Stetson', + 'Constant', + 'Benford', + 'Sorto', + 'Cater', + 'Rosier', + 'Isenberg', + 'Shanklin', + 'Veloz', + 'Ramage', + 'Dunford', + 'Ku', + 'Hames', + 'Eddins', + 'Ruano', + 'Frink', + 'Flower', + 'Beadle', + 'Rochester', + 'Fontes', + 'Mefford', + 'Barwick', + 'Millen', + 'Stelly', + 'Cann', + 'Rayner', + 'Carruth', + 'Wendling', + 'Shutt', + 'Hazzard', + 'Maravilla', + 'Gregorio', + 'Pavlik', + 'Hudnall', + 'Aston', + 'Mcglothlin', + 'Weise', + 'Devereaux', + 'Belle', + 'Borst', + 'Burdett', + 'Frisbie', + 'Rummel', + 'Rentz', + 'Cobos', + 'Kimura', + 'Neu', + 'Winner', + 'Candelario', + 'Callis', + 'Basso', + 'Mckim', + 'Tai', + 'Eskew', + 'Lair', + 'Pye', + 'Knuth', + 'Scarberry', + 'Alter', + 'Mcgann', + 'Anson', + 'Drews', + 'Zuckerman', + 'Petrone', + 'Ludlow', + 'Bechtold', + 'Nair', + 'Rennie', + 'Rhine', + 'Fleetwood', + 'Sudduth', + 'Leftwich', + 'Hardiman', + 'Northrop', + 'Banker', + 'Killen', + 'Mastin', + 'Mcmurry', + 'Jasinski', + 'Taliaferro', + 'Mathers', + 'Sheikh', + 'Nuss', + 'Jesse', + 'Zabel', + 'Crotty', + 'Kamp', + 'Fleenor', + 'Halcomb', + 'Eady', + 'Vella', + 'Demars', + 'Ensley', + 'Delosreyes', + 'Zendejas', + 'Leeds', + 'Just', + 'Oday', + 'Dills', + 'Zeng', + 'Barriga', + 'Millican', + 'Cascio', + 'Eakin', + 'Argo', + 'Borland', + 'Cover', + 'Diorio', + 'Coria', + 'Lease', + 'Pinkham', + 'Reichard', + 'Guadalupe', + 'Hansel', + 'Bye', + 'Westerfield', + 'Gales', + 'Mickle', + 'Licata', + 'Cram', + 'Bracy', + 'Motta', + 'Imhoff', + 'Siegfried', + 'Merry', + 'Swiger', + 'Ton', + 'Hersey', + 'Marrone', + 'Ginter', + 'Miele', + 'Breton', + 'Scheffler', + 'Pray', + 'Stapp', + 'Bogard', + 'Towner', + 'Mcelhaney', + 'Bridgewater', + 'Waldner', + 'Quijano', + 'Galante', + 'Quesenberry', + 'Rourke', + 'Harshman', + 'Traver', + 'Alvares', + 'Mcgaha', + 'Nyberg', + 'Pharr', + 'Lerch', + 'Sok', + 'Rosson', + 'Wiggs', + 'Mcelveen', + 'Dimaggio', + 'Rettig', + 'Ahumada', + 'Hetzel', + 'Welling', + 'Chadwell', + 'Swink', + 'Mckinzie', + 'Kwak', + 'Chabot', + 'Tomaszewski', + 'Bonanno', + 'Lesko', + 'Teter', + 'Stalnaker', + 'Ober', + 'Hovis', + 'Hosey', + 'Chaudhry', + 'Fey', + 'Vital', + 'Earhart', + 'Heins', + 'Crowther', + 'Hanner', + 'Behr', + 'Billington', + 'Vogler', + 'Hersh', + 'Perlman', + 'Given', + 'Files', + 'Partain', + 'Coddington', + 'Jardine', + 'Grimmett', + 'Springs', + 'Macomber', + 'Horgan', + 'Arrieta', + 'Charley', + 'Josephson', + 'Tupper', + 'Provenzano', + 'Celaya', + 'Mcvicker', + 'Sigala', + 'Wimer', + 'Ayon', + 'Dossantos', + 'Norvell', + 'Lorenzen', + 'Pasquale', + 'Lambright', + 'Goings', + 'Defelice', + 'Wen', + 'Sigman', + 'Gaylor', + 'Rehm', + 'Carino', + 'Werth', + 'Forehand', + 'Hanke', + 'Lasalle', + 'Mitchum', + 'Priester', + 'Lefler', + 'Celis', + 'Lesser', + 'Fitz', + 'Wentzel', + 'Lavery', + 'Klassen', + 'Shiflett', + 'Hedden', + 'Henn', + 'Coursey', + 'Drain', + 'Delorenzo', + 'Haws', + 'Stansberry', + 'Trump', + 'Dantzler', + 'Chaidez', + 'Mcsweeney', + 'Griffen', + 'Trail', + 'Gandara', + 'Brunk', + 'Kennon', + 'Coss', + 'Blackmore', + 'Metts', + 'Gluck', + 'Blackshear', + 'Cogan', + 'Boney', + 'Encinas', + 'Adamski', + 'Roberge', + 'Schuette', + 'Valero', + 'Barroso', + 'Antunez', + 'Mohammad', + 'Housley', + 'Escoto', + 'Ullrich', + 'Helman', + 'Trost', + 'Lafave', + 'Faith', + 'Blaney', + 'Kershner', + 'Hoehn', + 'Roemer', + 'Isley', + 'Lipinski', + 'Claus', + 'Caulfield', + 'Paiz', + 'Leyba', + 'Robinett', + 'Lambeth', + 'Tarpley', + 'Essex', + 'Eilers', + 'Epley', + 'Murdoch', + 'Sandstrom', + 'Laux', + 'Domingue', + 'Grundy', + 'Bellows', + 'Spindler', + 'Boos', + 'Bhatt', + 'Tye', + 'Salamone', + 'Cirillo', + 'Troup', + 'Jemison', + 'Calzada', + 'Dowden', + 'Geraci', + 'Dunphy', + 'Sack', + 'Sloane', + 'Hathcock', + 'Yap', + 'Ronquillo', + 'Willette', + 'Partlow', + 'Dear', + 'Tunstall', + 'Kiss', + 'Huhn', + 'Seabolt', + 'Beene', + 'Sather', + 'Lockridge', + 'Despain', + 'Wines', + 'Mcalpine', + 'Wadley', + 'Dey', + 'Loring', + 'Meadors', + 'Buettner', + 'Lavalley', + 'Bugg', + 'Creek', + 'Millett', + 'Pumphrey', + 'Fregoso', + 'Merkle', + 'Sheffer', + 'Glassman', + 'Groover', + 'Sweatt', + 'Colunga', + 'Boykins', + 'Seng', + 'Stutz', + 'Brann', + 'Blakey', + 'Munos', + 'Geddes', + 'Avendano', + 'Molitor', + 'Diedrich', + 'Langham', + 'Kindle', + 'Lacour', + 'Buckler', + 'Corum', + 'Bakke', + 'Godin', + 'Kerner', + 'Tobey', + 'Kubiak', + 'Hoyer', + 'Hedge', + 'Priebe', + 'Callison', + 'Lahr', + 'Shears', + 'Snavely', + 'Blatt', + 'Mcpeak', + 'Tinney', + 'Sullins', + 'Bernhard', + 'Gibb', + 'Vaillancourt', + 'Paugh', + 'Funes', + 'Romans', + 'Maurice', + 'Lough', + 'Kerwin', + 'Sanger', + 'Vierra', + 'Markus', + 'Comfort', + 'Krall', + 'Spies', + 'Malcom', + 'Vizcarra', + 'Beamer', + 'Kellerman', + 'Mcroberts', + 'Waterhouse', + 'Stromberg', + 'Persons', + 'Whitesell', + 'Harty', + 'Rosenblatt', + 'Broadwater', + 'Clardy', + 'Shackleford', + 'Jacquez', + 'Brittingham', + 'Lindahl', + 'Feliz', + 'Danna', + 'Garwood', + 'Heron', + 'Southwick', + 'Dehoyos', + 'Cottrill', + 'Mellor', + 'Goldfarb', + 'Grieco', + 'Helgeson', + 'Vandusen', + 'Heinen', + 'Batt', + 'Ruch', + 'Garretson', + 'Pankey', + 'Caudillo', + 'Jakubowski', + 'Plowman', + 'Starcher', + 'Wessels', + 'Moose', + 'Rosner', + 'Louden', + 'Walczak', + 'Poulsen', + 'Mcchesney', + 'Karns', + 'Casares', + 'Cusack', + 'Cespedes', + 'Cornelison', + 'Crossland', + 'Hirst', + 'Mier', + 'Roberto', + 'Canchola', + 'Bosse', + 'Shetler', + 'Melendrez', + 'Giannini', + 'Six', + 'Traynor', + 'Knepper', + 'Lonergan', + 'Kessinger', + 'Hollon', + 'Weathersby', + 'Stouffer', + 'Gingrich', + 'Breault', + 'Pompa', + 'Vanhoose', + 'Burdine', + 'Lark', + 'Stiltner', + 'Wunderlich', + 'Yong', + 'Merrifield', + 'Willhite', + 'Geiser', + 'Lambrecht', + 'Keffer', + 'Carlo', + 'Germany', + 'Turgeon', + 'Dame', + 'Tristan', + 'Bova', + 'Doak', + 'Mannino', + 'Shotwell', + 'Bash', + 'Coots', + 'Feist', + 'Mahmood', + 'Schlabach', + 'Salzman', + 'Kass', + 'Bresnahan', + 'Stonge', + 'Tesch', + 'Grajeda', + 'Mccarron', + 'Mcelwee', + 'Spradling', + 'Mckown', + 'Colgan', + 'Piedra', + 'Collum', + 'Stoffel', + 'Won', + 'Gulick', + 'Devault', + 'Enders', + 'Yanes', + 'Lansing', + 'Ebner', + 'Deegan', + 'Boutin', + 'Fetzer', + 'Andresen', + 'Trigg', + 'Sale', + 'Polite', + 'Hummer', + 'Wille', + 'Bowerman', + 'Routh', + 'Iqbal', + 'Lakey', + 'Mcadoo', + 'Laflamme', + 'Boulware', + 'Guadarrama', + 'Campana', + 'Strayer', + 'Aho', + 'Emmett', + 'Wolters', + 'Bos', + 'Knighten', + 'Averill', + 'Bhakta', + 'Schumaker', + 'Stutts', + 'Mejias', + 'Byer', + 'Mahone', + 'Staab', + 'Riehl', + 'Briceno', + 'Zabala', + 'Lafountain', + 'Clemmer', + 'Mansell', + 'Rossetti', + 'Lafontaine', + 'Mager', + 'Adamo', + 'Bogue', + 'Northern', + 'Disney', + 'Masse', + 'Senter', + 'Yaeger', + 'Dahlberg', + 'Bisson', + 'Leitner', + 'Bolding', + 'Ormsby', + 'Berard', + 'Brazell', + 'Pickle', + 'Hord', + 'Mcguigan', + 'Glennon', + 'Aman', + 'Dearman', + 'Cauthen', + 'Rembert', + 'Delucia', + 'Enciso', + 'Slusser', + 'Kratzer', + 'Schoenfeld', + 'Gillam', + 'Rael', + 'Rhode', + 'Moton', + 'Eide', + 'Eliason', + 'Helfrich', + 'Bish', + 'Goodnight', + 'Campion', + 'Blow', + 'Gerken', + 'Goldenberg', + 'Mellinger', + 'Nations', + 'Maiden', + 'Anzalone', + 'Wagers', + 'Arguelles', + 'Christen', + 'Guth', + 'Stamey', + 'Bozarth', + 'Balogh', + 'Grammer', + 'Chafin', + 'Prine', + 'Freer', + 'Alder', + 'Latorre', + 'Zaleski', + 'Lindholm', + 'Belisle', + 'Zacharias', + 'Swinson', + 'Bazemore', + 'Glazer', + 'Acord', + 'Said', + 'Liggins', + 'Lueck', + 'Luedtke', + 'Blackstone', + 'Copper', + 'Riker', + 'Braud', + 'Demello', + 'Rode', + 'Haven', + 'Rhee', + 'Galligan', + 'Record', + 'Nilson', + 'Ansley', + 'Pera', + 'Gilliard', + 'Copp', + 'Haugh', + 'Dunigan', + 'Grinnell', + 'Garr', + 'Leonhardt', + 'Elswick', + 'Shahan', + 'Mike', + 'Boddie', + 'Casella', + 'Mauricio', + 'Millet', + 'Daye', + 'Claussen', + 'Pierrelouis', + 'Fleischman', + 'Embrey', + 'Durso', + 'Whisenant', + 'Rankins', + 'Lasky', + 'Askins', + 'Rupe', + 'Rochelle', + 'Burkes', + 'Kreger', + 'Mishler', + 'Heald', + 'Jager', + 'Player', + 'Linehan', + 'Horwitz', + 'Jacobi', + 'Maine', + 'Wiest', + 'Ostrom', + 'Sealy', + 'Jimerson', + 'Alverson', + 'Senior', + 'Hassett', + 'Colter', + 'Schleicher', + 'Marini', + 'Mcbrayer', + 'Arzola', + 'Sobel', + 'Frederickson', + 'Confer', + 'Tadlock', + 'Belmonte', + 'Lebrun', + 'Clyde', + 'Alleyne', + 'Lozoya', + 'Teller', + 'Husband', + 'Brigman', + 'Secrest', + 'Krajewski', + 'Neiman', + 'Trull', + 'Watterson', + 'Vanhook', + 'Sotomayor', + 'Woodrum', + 'Baskerville', + 'Finke', + 'Hohman', + 'Arp', + 'Hearne', + 'Mauk', + 'Danko', + 'Laurie', + 'Linderman', + 'Hutt', + 'Springfield', + 'Chmielewski', + 'Klimek', + 'Phinney', + 'Leboeuf', + 'Mcglone', + 'Holmquist', + 'Cogswell', + 'Nichol', + 'Klink', + 'Dunston', + 'Krawczyk', + 'Dart', + 'Woodside', + 'Smitherman', + 'Gasca', + 'Sala', + 'Foxworth', + 'Kammerer', + 'Auer', + 'Pegues', + 'Bukowski', + 'Koger', + 'Spitz', + 'Blomquist', + 'Creasy', + 'Bomar', + 'Holub', + 'Loney', + 'Garry', + 'Habib', + 'Chea', + 'Dupuy', + 'Seaver', + 'Sowards', + 'Julius', + 'Fulks', + 'Braithwaite', + 'Bretz', + 'Mccammon', + 'Sedillo', + 'Chiasson', + 'Oney', + 'Horstman', + 'Waites', + 'Mccusker', + 'Fenske', + 'Conwell', + 'Brokaw', + 'Cloyd', + 'Biles', + 'Aguinaga', + 'Astorga', + 'Demaio', + 'Liberty', + 'Kayser', + 'Ney', + 'Barthel', + 'Lennox', + 'Trautman', + 'Purser', + 'Pitzer', + 'Mattos', + 'Liss', + 'Clack', + 'Sias', + 'Bobb', + 'Stoller', + 'Robillard', + 'Almodovar', + 'Cribb', + 'Ebel', + 'Oyler', + 'Dail', + 'Ericksen', + 'Geis', + 'Everitt', + 'Cropper', + 'Meisner', + 'Skeens', + 'Frith', + 'Privett', + 'Braddy', + 'Bolick', + 'Severance', + 'Jeffreys', + 'Bethune', + 'Delcid', + 'Buzzard', + 'Broadbent', + 'Bono', + 'Addis', + 'Johannes', + 'Tims', + 'Castorena', + 'Simonsen', + 'Glidewell', + 'Mui', + 'Ogilvie', + 'Soukup', + 'Sunday', + 'Redwine', + 'Borton', + 'Schuyler', + 'Rudisill', + 'Beckford', + 'Pascua', + 'Garton', + 'Gilkey', + 'Applewhite', + 'Halterman', + 'Alsup', + 'Delreal', + 'Hubble', + 'Quijada', + 'Kropp', + 'Dunkle', + 'Lemire', + 'Lamontagne', + 'Dunkin', + 'Paulin', + 'Attaway', + 'Baugher', + 'Hornbeck', + 'Niehaus', + 'Nice', + 'Trimmer', + 'Canaday', + 'Maney', + 'Trexler', + 'Schmucker', + 'Edinger', + 'Massengill', + 'Rowlett', + 'Caviness', + 'Kam', + 'Chesnut', + 'Giardina', + 'Spaeth', + 'Gebhart', + 'Morano', + 'Salguero', + 'Buckland', + 'Reina', + 'Jumper', + 'Navas', + 'Thrift', + 'Spradley', + 'Bitner', + 'Ayer', + 'Harber', + 'Landaverde', + 'Mcmillion', + 'Naugle', + 'Dole', + 'Seagraves', + 'Smithers', + 'Frechette', + 'Weeden', + 'Caston', + 'Cavallaro', + 'Laureano', + 'Mandell', + 'Lowrance', + 'Baty', + 'Ronan', + 'Gigliotti', + 'Rossiter', + 'Mines', + 'Alatorre', + 'Markowski', + 'Berge', + 'Hatter', + 'Weakley', + 'Borrero', + 'Glazier', + 'Lavergne', + 'Sines', + 'Ingham', + 'Meltzer', + 'Rabinowitz', + 'Siciliano', + 'Canas', + 'Perna', + 'Struck', + 'Dare', + 'Nay', + 'Severino', + 'Mathewson', + 'Bouldin', + 'Topete', + 'Brunette', + 'Sin', + 'Hendren', + 'Brickey', + 'Ferrier', + 'Alessi', + 'Scheel', + 'Storer', + 'Matherne', + 'Mecham', + 'Spiker', + 'Hibbert', + 'Klingensmith', + 'Lefever', + 'Banning', + 'Bankhead', + 'Roan', + 'Brack', + 'Pascoe', + 'Davie', + 'Scheid', + 'Jim', + 'Tweedy', + 'Strahan', + 'Revis', + 'Fermin', + 'Obrian', + 'Motes', + 'Lobo', + 'Palmisano', + 'Faught', + 'Byington', + 'Garren', + 'Hungerford', + 'Vanzandt', + 'Gust', + 'Heater', + 'Klingler', + 'Delay', + 'Wear', + 'Hendley', + 'Threatt', + 'Gaughan', + 'Kunze', + 'Hessler', + 'Lindell', + 'Monteleone', + 'Palazzolo', + 'Shear', + 'Phares', + 'Cavalier', + 'Benning', + 'Urbanski', + 'Darrah', + 'Wager', + 'Mohn', + 'Vereen', + 'Beiler', + 'Hedlund', + 'Quade', + 'Wieczorek', + 'Cicero', + 'Hoekstra', + 'Scalf', + 'Ducote', + 'Havard', + 'Espiritu', + 'Beacham', + 'Bolger', + 'Schuller', + 'Sill', + 'Dice', + 'Lemmons', + 'Orlowski', + 'Lundeen', + 'Steck', + 'Stanfill', + 'Rakes', + 'Laine', + 'Haviland', + 'Durrett', + 'Naumann', + 'Donahoe', + 'Reif', + 'Franck', + 'Amoroso', + 'Belknap', + 'Tolle', + 'Perrotta', + 'Heyer', + 'Dougan', + 'Frakes', + 'Leath', + 'Poteat', + 'Violette', + 'Marine', + 'Zellner', + 'Granillo', + 'Fontanez', + 'Didonato', + 'Bradberry', + 'Morman', + 'Mentzer', + 'Lamoureux', + 'Sabatino', + 'Catania', + 'Wenner', + 'Pastrana', + 'Shenk', + 'Losey', + 'Hepburn', + 'Antonucci', + 'Egger', + 'Higbee', + 'Adames', + 'Reep', + 'Cavallo', + 'Bridwell', + 'Villalba', + 'Poor', + 'Peet', + 'Everette', + 'Arney', + 'Towery', + 'Sharon', + 'Trainer', + 'Marrow', + 'Cumming', + 'Rimmer', + 'Stanger', + 'Pinter', + 'Felt', + 'Parrett', + 'Garrard', + 'Benedetto', + 'Lingenfelter', + 'Resch', + 'Billy', + 'Mikesell', + 'Osterman', + 'Trueblood', + 'Redfern', + 'Calderone', + 'Placencia', + 'Wamsley', + 'Warr', + 'Varnado', + 'Harshbarger', + 'Topping', + 'Feltner', + 'Decosta', + 'Tart', + 'Blumberg', + 'Shaikh', + 'Culley', + 'Bork', + 'Thibeault', + 'Stolz', + 'Ramsdell', + 'Tedford', + 'Noto', + 'Poulson', + 'Daves', + 'Altieri', + 'Mendosa', + 'Kisner', + 'Grafton', + 'Remy', + 'Hartline', + 'Cripe', + 'Sher', + 'Mulvaney', + 'Ansari', + 'Hartfield', + 'Whitton', + 'Wathen', + 'Eisele', + 'Hinojos', + 'Backer', + 'Speaks', + 'Schuetz', + 'Novoa', + 'Marcos', + 'Mask', + 'Oboyle', + 'Kircher', + 'Stang', + 'Sibert', + 'Scala', + 'Zacarias', + 'Hendon', + 'Halvorsen', + 'Montalbano', + 'Zermeno', + 'Vancamp', + 'Grams', + 'Hornberger', + 'Binion', + 'Dewald', + 'Rives', + 'Sankey', + 'Kleinman', + 'Falconer', + 'Rumph', + 'Matus', + 'Swett', + 'Spinner', + 'Depasquale', + 'Gamino', + 'Olmsted', + 'Absher', + 'Culler', + 'Fryman', + 'Lampert', + 'Carlyle', + 'Terranova', + 'Dunagan', + 'Chouinard', + 'Wesolowski', + 'Hetherington', + 'Scalise', + 'Pendergast', + 'Marcano', + 'Joubert', + 'Scheller', + 'Whisenhunt', + 'Lenoir', + 'Mahar', + 'Vanlandingham', + 'Pecoraro', + 'You', + 'Natividad', + 'Daum', + 'Penick', + 'Eddington', + 'Deleo', + 'Soltis', + 'Santucci', + 'Costanza', + 'Hiner', + 'Farlow', + 'Hartsock', + 'Duprey', + 'Fann', + 'Safford', + 'Murtha', + 'Fessler', + 'Chien', + 'Paynter', + 'Devera', + 'Hoelscher', + 'Boltz', + 'Deacon', + 'Loo', + 'Enoch', + 'Dilorenzo', + 'Saville', + 'Mirza', + 'Takacs', + 'Drexler', + 'Lakin', + 'Geraghty', + 'Widmer', + 'Esteves', + 'Llanes', + 'Cerny', + 'Quist', + 'Hargraves', + 'Toma', + 'Tarter', + 'Chapple', + 'Alderete', + 'Michelson', + 'Clymer', + 'Batey', + 'Sealey', + 'Loughlin', + 'Preece', + 'Zurita', + 'Courville', + 'Desousa', + 'Shamblin', + 'Tingley', + 'Noles', + 'Misner', + 'Standifer', + 'Dinardo', + 'Dillow', + 'Bullis', + 'Carballo', + 'Everly', + 'Mulvihill', + 'Tincher', + 'Carle', + 'Lundin', + 'Birdsall', + 'Bainbridge', + 'Suttle', + 'Wightman', + 'Mower', + 'Mountain', + 'Bickham', + 'Durante', + 'Viveros', + 'Swinford', + 'Mcgruder', + 'Tapley', + 'Grable', + 'Gwynn', + 'Wiebe', + 'Stagg', + 'Dash', + 'Heitman', + 'Cluff', + 'Huertas', + 'Fortuna', + 'Lines', + 'Sly', + 'Halford', + 'Helsel', + 'Bicknell', + 'Blakeman', + 'Colangelo', + 'Olney', + 'Quinton', + 'Rothrock', + 'Renz', + 'Hone', + 'Prejean', + 'Oshiro', + 'Serio', + 'Latour', + 'Newbold', + 'Fitzhugh', + 'Songer', + 'Cardin', + 'Geter', + 'Barbera', + 'Abbas', + 'Caesar', + 'Blakeslee', + 'Camper', + 'Mcclurg', + 'Driskill', + 'Cancel', + 'Donelson', + 'Borrelli', + 'Donoghue', + 'Shoaf', + 'Tinajero', + 'Arzate', + 'Keesee', + 'Pasley', + 'Strode', + 'Morello', + 'Trantham', + 'Ackerson', + 'Jowers', + 'Brockington', + 'Barcia', + 'Lipp', + 'Dinger', + 'Ridings', + 'Canavan', + 'Rank', + 'Hagans', + 'Lampley', + 'Beckmann', + 'Bjork', + 'Raygoza', + 'Schirmer', + 'Longmire', + 'Schiavone', + 'Breuer', + 'Lore', + 'Stenson', + 'Koziol', + 'Channell', + 'Cale', + 'Trader', + 'Culberson', + 'Mundt', + 'Sickles', + 'Nemec', + 'Holl', + 'Stribling', + 'Berens', + 'Nauman', + 'Lehner', + 'Deem', + 'Castelli', + 'Billman', + 'Orndorff', + 'Gumm', + 'Davy', + 'Pelham', + 'Spotts', + 'Jurgens', + 'Sword', + 'Adorno', + 'Gorrell', + 'Boughton', + 'Bobadilla', + 'Mauer', + 'Moline', + 'Guay', + 'Holsinger', + 'Baranowski', + 'Gutierres', + 'Beveridge', + 'Marable', + 'Berkey', + 'Lamothe', + 'Spitler', + 'Carbaugh', + 'Hoopes', + 'Wilken', + 'Milford', + 'Bingaman', + 'Crippen', + 'Shock', + 'Yarnell', + 'Oman', + 'Wethington', + 'Kost', + 'Gaudette', + 'Spielman', + 'Foran', + 'Starke', + 'Eugene', + 'Birnbaum', + 'Navarrette', + 'Hussein', + 'Ranson', + 'Hedgepeth', + 'Doctor', + 'Higuera', + 'Brough', + 'Cookson', + 'Provencher', + 'Mendonca', + 'Gowen', + 'Summer', + 'Rutz', + 'Reader', + 'Doud', + 'Raven', + 'Toribio', + 'Peachey', + 'Gunning', + 'Bittle', + 'Vale', + 'Harnish', + 'Marano', + 'Aker', + 'Damore', + 'Utz', + 'Throckmorton', + 'Bulger', + 'Vanzant', + 'Pasillas', + 'Holmgren', + 'Corpus', + 'Longley', + 'Wetmore', + 'Carstens', + 'Line', + 'Percival', + 'Ayotte', + 'Batres', + 'Pipes', + 'Ludwick', + 'Alpert', + 'Pick', + 'Carlock', + 'Edmundson', + 'Feinstein', + 'Krouse', + 'Dahlgren', + 'Sasaki', + 'Lieb', + 'Londono', + 'Oloughlin', + 'Wardlaw', + 'Lineberry', + 'Castello', + 'Milstead', + 'Parmenter', + 'Riffe', + 'Pare', + 'Sitton', + 'Tarin', + 'Delcastillo', + 'Manor', + 'Calabro', + 'Elkin', + 'Grill', + 'Boaz', + 'Coco', + 'Chamblee', + 'Celestine', + 'Nick', + 'Stork', + 'Meekins', + 'Moise', + 'Devers', + 'Jun', + 'Kegley', + 'Brick', + 'Lobato', + 'Biggerstaff', + 'Kersten', + 'Jayne', + 'Nasser', + 'Southall', + 'Kempton', + 'Eaddy', + 'Paladino', + 'Berardi', + 'Pizzo', + 'Pulver', + 'Ohalloran', + 'Fromm', + 'Cranston', + 'Rowden', + 'Capobianco', + 'Kahle', + 'Thiessen', + 'Malott', + 'Houseman', + 'Maul', + 'Gallion', + 'Tressler', + 'Pauly', + 'Pellerin', + 'Sainz', + 'Firth', + 'Cryer', + 'Jeanlouis', + 'Mong', + 'Trawick', + 'Chronister', + 'Hayashi', + 'Posner', + 'Cueva', + 'Sherwin', + 'Lacasse', + 'Gorden', + 'Bohl', + 'Twigg', + 'Coan', + 'Hocker', + 'Goodale', + 'Urbano', + 'Loeb', + 'Perrault', + 'Frawley', + 'Carcamo', + 'Richburg', + 'Moffat', + 'Hennings', + 'Weyer', + 'Myatt', + 'Ullman', + 'Tunnell', + 'Hern', + 'Lopresti', + 'Sonnenberg', + 'Knisley', + 'Twomey', + 'Jaggers', + 'Tanksley', + 'Rachal', + 'Poppe', + 'Vos', + 'Kania', + 'Speakman', + 'Peirce', + 'Pound', + 'Romer', + 'Patty', + 'Millsaps', + 'Kyser', + 'Telford', + 'Hegarty', + 'Kellett', + 'Michaelis', + 'Halligan', + 'Maughan', + 'Herb', + 'Rainer', + 'Robichaud', + 'Fiscus', + 'Sickler', + 'Blom', + 'Lavine', + 'Medel', + 'Bolyard', + 'Secor', + 'Creekmore', + 'Magruder', + 'Haskin', + 'Laliberte', + 'Drago', + 'Bernabe', + 'Leader', + 'Cavin', + 'Lukens', + 'Vassallo', + 'Pletcher', + 'Fuson', + 'Hasson', + 'Huckabee', + 'Edington', + 'Eichler', + 'Hering', + 'Vong', + 'Mardis', + 'Gu', + 'Segarra', + 'Bilyeu', + 'Runion', + 'Fragoso', + 'Gama', + 'Dunton', + 'Frady', + 'Lewellen', + 'Crumpler', + 'Jeske', + 'Furlow', + 'Delapena', + 'Kale', + 'Massengale', + 'Hamlet', + 'Galli', + 'Esteban', + 'Greeson', + 'Shue', + 'Pollak', + 'Pinney', + 'Ruffner', + 'Maitland', + 'Steven', + 'Hockett', + 'Fraire', + 'Mulhern', + 'Elbert', + 'Hoggard', + 'Labarge', + 'Silcox', + 'Saez', + 'Sluder', + 'Stamp', + 'Darlington', + 'Mccarroll', + 'Pillow', + 'Palazzo', + 'Blaha', + 'Demaria', + 'Swanger', + 'Winningham', + 'Lippincott', + 'Dake', + 'Goldsberry', + 'Seidl', + 'Woolfolk', + 'Murawski', + 'Hobart', + 'Kimber', + 'Nilsson', + 'Stough', + 'Almendarez', + 'Nevels', + 'Fasano', + 'Salmons', + 'Denmark', + 'Lathan', + 'Mosely', + 'Stengel', + 'Mendieta', + 'Felice', + 'Drown', + 'Vidrine', + 'Callihan', + 'Polston', + 'Howze', + 'Eakins', + 'Leek', + 'Featherstone', + 'Lajoie', + 'Athey', + 'Asuncion', + 'Ashbaugh', + 'Orman', + 'Morrissette', + 'Peart', + 'Hamner', + 'Zell', + 'Dry', + 'Dieter', + 'Terrones', + 'Campuzano', + 'Reveles', + 'Bakker', + 'Banister', + 'Arceo', + 'Dhillon', + 'Normand', + 'Shavers', + 'Ginsburg', + 'Go', + 'Rubinstein', + 'Arens', + 'Clutter', + 'Jaques', + 'Traxler', + 'Hackler', + 'Cisco', + 'Starrett', + 'Ceron', + 'Gillenwater', + 'Ottinger', + 'Caster', + 'Blakemore', + 'Thorsen', + 'Molinar', + 'Baur', + 'Hower', + 'Haldeman', + 'Oliveri', + 'Mcalpin', + 'Standish', + 'Bengtson', + 'Strack', + 'Cordoba', + 'Blackstock', + 'Barna', + 'Schantz', + 'Hawkinson', + 'Breese', + 'Saba', + 'Camden', + 'Gwaltney', + 'Corliss', + 'Smit', + 'Cruise', + 'Mcneese', + 'Duggins', + 'Laub', + 'Burman', + 'Kenworthy', + 'Spohn', + 'Santini', + 'Nuttall', + 'Willison', + 'Stjean', + 'Shabazz', + 'Manes', + 'Gerry', + 'Mclamb', + 'Koepke', + 'Reeser', + 'Ogburn', + 'Wegener', + 'Risinger', + 'Carrero', + 'Livermore', + 'Brewton', + 'Harsh', + 'Utterback', + 'Lecompte', + 'Schnabel', + 'Ting', + 'Honea', + 'Stryker', + 'Foshee', + 'Baptista', + 'Gravely', + 'Courson', + 'Goyette', + 'Leitch', + 'Tasker', + 'Laurence', + 'Reneau', + 'Voight', + 'Tilson', + 'Range', + 'Hallam', + 'Dufrene', + 'Boice', + 'Shrewsbury', + 'Sturges', + 'Lenard', + 'Sistrunk', + 'Weitz', + 'Carnevale', + 'Hepner', + 'Wehner', + 'Callen', + 'Oshaughnessy', + 'Wingert', + 'Mouser', + 'Palmore', + 'Rugg', + 'Elia', + 'Alcazar', + 'Avitia', + 'Penton', + 'Brisco', + 'Ambrosio', + 'Wardlow', + 'Leaf', + 'Rowles', + 'Buggs', + 'Dittmer', + 'Schweizer', + 'Puleo', + 'Vaden', + 'Haughton', + 'Cardinale', + 'Seguin', + 'Ruddy', + 'Minard', + 'Stalker', + 'Bennington', + 'Hilt', + 'Works', + 'Broadus', + 'Engels', + 'Haddix', + 'Buster', + 'Recker', + 'Bopp', + 'Wilton', + 'Costantino', + 'Boots', + 'Falkner', + 'Tennison', + 'Mcgary', + 'Holz', + 'Lofgren', + 'Putney', + 'Christner', + 'Fruge', + 'Vassar', + 'Vankirk', + 'Spoon', + 'Pearlman', + 'Guertin', + 'Meece', + 'Sartain', + 'Petterson', + 'Primm', + 'Cardillo', + 'Dryer', + 'Hartshorn', + 'Dane', + 'Chaisson', + 'Espitia', + 'Creager', + 'Disalvo', + 'Janik', + 'Parente', + 'Paiva', + 'Slaven', + 'Tague', + 'Kujawa', + 'Gruver', + 'Foor', + 'Frampton', + 'Prokop', + 'Mettler', + 'Collis', + 'Lamkin', + 'Shuey', + 'Tepper', + 'Colyer', + 'Masi', + 'Trumble', + 'Guice', + 'Hurwitz', + 'Windle', + 'Mccully', + 'Cutting', + 'Stotler', + 'Grullon', + 'Wagstaff', + 'Morfin', + 'Dehaan', + 'Noon', + 'Flesher', + 'Ferri', + 'Covell', + 'Coll', + 'Lucy', + 'Albaugh', + 'Testerman', + 'Gordillo', + 'Jepson', + 'Brinkerhoff', + 'Calle', + 'Crowl', + 'Mcelwain', + 'Chumley', + 'Brockett', + 'Thoms', + 'Revell', + 'Garzon', + 'Polak', + 'Rothenberg', + 'Socha', + 'Vallejos', + 'Felty', + 'Peguero', + 'Ping', + 'Tso', + 'Charleston', + 'Fedor', + 'Haider', + 'Abe', + 'Enlow', + 'Fifer', + 'Bumpus', + 'Keele', + 'Mcdavid', + 'Panek', + 'Scholten', + 'Dyess', + 'Heatherly', + 'Donohoe', + 'Hoban', + 'Griffey', + 'Corry', + 'Mcclean', + 'Plyler', + 'Feathers', + 'Adkison', + 'Killeen', + 'Hoeft', + 'Myhre', + 'Fiorentino', + 'Mcbeth', + 'Erazo', + 'Madson', + 'Fulbright', + 'Wilds', + 'Petrucci', + 'Mcgaughey', + 'Monteith', + 'Murguia', + 'Hausman', + 'Zukowski', + 'Shute', + 'Brisson', + 'Lain', + 'Runkle', + 'Hickok', + 'Caffrey', + 'Million', + 'Elson', + 'Peay', + 'Haga', + 'Ancheta', + 'Cordle', + 'Blas', + 'Carmen', + 'Pettiford', + 'Dimartino', + 'Spahr', + 'Mozingo', + 'Backman', + 'Stgeorge', + 'Konrad', + 'Buhler', + 'Mcelrath', + 'Oliveros', + 'Edelstein', + 'Cadet', + 'Gilmartin', + 'Munday', + 'Roane', + 'Desalvo', + 'Lepe', + 'Symons', + 'Shearin', + 'Linkous', + 'Cheshire', + 'Klemm', + 'Beagle', + 'Pooler', + 'Dewalt', + 'Esch', + 'Finnell', + 'Sinnott', + 'Kepler', + 'Toups', + 'Riccardi', + 'Caylor', + 'Tillis', + 'Messmer', + 'Rothschild', + 'Boutte', + 'Zumwalt', + 'Bohrer', + 'Elgin', + 'Kinley', + 'Schechter', + 'Gowan', + 'Pyne', + 'Cousin', + 'Hunsinger', + 'Fishel', + 'Edenfield', + 'Nadler', + 'Warman', + 'Bruhn', + 'Swint', + 'Lizotte', + 'Nardone', + 'Troxel', + 'Grindle', + 'Labrie', + 'Tao', + 'Olea', + 'Schermerhorn', + 'Stier', + 'Hettinger', + 'Farthing', + 'Roux', + 'Max', + 'Amburgey', + 'Auerbach', + 'Janzen', + 'Ortez', + 'Alejandre', + 'Peiffer', + 'Molinaro', + 'Burleigh', + 'Benites', + 'Ringler', + 'Hou', + 'Haffner', + 'Nace', + 'Crosson', + 'Karcher', + 'Neufeld', + 'Bayles', + 'Riemer', + 'Amezquita', + 'Cadwell', + 'Petrosky', + 'Swallow', + 'Minnis', + 'Krupp', + 'Nardi', + 'Orsini', + 'Diez', + 'Updike', + 'Gasser', + 'Rogerson', + 'Speicher', + 'Dubay', + 'Hollaway', + 'Teets', + 'Keown', + 'Center', + 'Blanding', + 'Whisler', + 'Spurlin', + 'Collin', + 'Greenawalt', + 'Tomes', + 'Leister', + 'Chatfield', + 'Helwig', + 'Reimers', + 'Andress', + 'Norcross', + 'Melnick', + 'Yearwood', + 'Defazio', + 'Kubik', + 'Bhatia', + 'Uddin', + 'Belmont', + 'Haden', + 'Bench', + 'Chilson', + 'Pegg', + 'Cane', + 'Goehring', + 'Lino', + 'Tyus', + 'Furey', + 'Castleman', + 'Heywood', + 'Leedy', + 'Holleman', + 'Villeda', + 'Mcveigh', + 'Carreiro', + 'Hocking', + 'Azar', + 'Blough', + 'Lieu', + 'Marcial', + 'Coblentz', + 'Hossain', + 'Weisberg', + 'Gardea', + 'Hoyos', + 'Lipsey', + 'Reger', + 'Clouser', + 'Bewley', + 'Magness', + 'Goines', + 'Thome', + 'Odea', + 'Mannion', + 'Dansby', + 'Dipasquale', + 'Constable', + 'Truelove', + 'Hubler', + 'Ulibarri', + 'Wymer', + 'Cron', + 'Hugo', + 'Hilderbrand', + 'Milazzo', + 'Vasques', + 'Sproul', + 'Shuford', + 'Chavers', + 'Kral', + 'Vecchio', + 'Mehl', + 'Rymer', + 'Henriksen', + 'Taulbee', + 'Hagy', + 'Ammerman', + 'Kagan', + 'Galdamez', + 'Krick', + 'Owsley', + 'Mullikin', + 'Beery', + 'Eccles', + 'Kleinschmidt', + 'Kloss', + 'Oldenburg', + 'Ospina', + 'Harbert', + 'Andujar', + 'Florian', + 'Antone', + 'Mcmillon', + 'Ceniceros', + 'Rippy', + 'Adkisson', + 'Stange', + 'Balmer', + 'Mazurek', + 'Dahlke', + 'Girouard', + 'Nickelson', + 'Perera', + 'Tullos', + 'Cioffi', + 'Bogdan', + 'Olivieri', + 'Petree', + 'Speights', + 'Jantz', + 'Collings', + 'Zellers', + 'Yarber', + 'Lafollette', + 'Rink', + 'Currin', + 'Chua', + 'Hartle', + 'Larocque', + 'Cuthbertson', + 'Ehrhardt', + 'Mara', + 'Rieck', + 'Lumley', + 'Anderton', + 'Hennigan', + 'Fabrizio', + 'Hutter', + 'Bruning', + 'Korman', + 'Haring', + 'Monette', + 'Woodyard', + 'Goggins', + 'Balzer', + 'Philbrick', + 'Bruder', + 'Hansford', + 'Averett', + 'Teske', + 'Mauck', + 'Billiot', + 'Collie', + 'Caffey', + 'Manos', + 'Buchan', + 'Birk', + 'Abdallah', + 'Featherston', + 'Koh', + 'Valera', + 'Deyo', + 'Buono', + 'Aubin', + 'Doody', + 'Pigott', + 'Peloquin', + 'Maniscalco', + 'Eisenhauer', + 'Biller', + 'Farwell', + 'Hartzog', + 'Brazier', + 'Talton', + 'Mcdougald', + 'Midgett', + 'Strout', + 'Spiers', + 'Eiland', + 'Garth', + 'Sequeira', + 'Noyola', + 'Petri', + 'Goodyear', + 'Dineen', + 'Bernardi', + 'Berns', + 'Coolidge', + 'Dorfman', + 'Dittman', + 'Zeno', + 'Hauer', + 'Finlay', + 'Ziemba', + 'Spillane', + 'Kays', + 'Ekstrom', + 'Hile', + 'Mckinstry', + 'Lesley', + 'Courtright', + 'Kuhlmann', + 'Verma', + 'Cripps', + 'Wigley', + 'Nickens', + 'Petrick', + 'Delozier', + 'Hardcastle', + 'Yamaguchi', + 'Romig', + 'Venezia', + 'Reading', + 'Redford', + 'Heng', + 'Anselmo', + 'Getty', + 'Marten', + 'Badgett', + 'Eisner', + 'Holtzman', + 'Stell', + 'Hiser', + 'Dustin', + 'Bordeaux', + 'Debolt', + 'Trevizo', + 'Eckard', + 'Follett', + 'Lal', + 'Dark', + 'Buskirk', + 'Roca', + 'Todaro', + 'Campanella', + 'Lindsley', + 'Wickman', + 'Pritt', + 'Cutlip', + 'Pokorny', + 'Friedlander', + 'Saari', + 'Casias', + 'Macneil', + 'Clyburn', + 'Kravitz', + 'Edgington', + 'Portis', + 'Culbreth', + 'Cuff', + 'Brouillette', + 'Artz', + 'Trudell', + 'Pledger', + 'Markovich', + 'Pisani', + 'Faller', + 'Sergent', + 'Hail', + 'Stabile', + 'Wait', + 'Mcilwain', + 'Eriksen', + 'Nee', + 'Boll', + 'Catanzaro', + 'Giuliano', + 'Oldfield', + 'Banas', + 'Ickes', + 'Vachon', + 'Gleeson', + 'Bailes', + 'Biehl', + 'Woodham', + 'Troupe', + 'Mcgoldrick', + 'Cappello', + 'Kirkendall', + 'Baisden', + 'Joshua', + 'Nicoletti', + 'Roesch', + 'Deatherage', + 'Matter', + 'Sheth', + 'Tynes', + 'Shaheen', + 'Wilbert', + 'Toles', + 'Sanner', + 'Bury', + 'Boman', + 'Bose', + 'Millner', + 'Eisen', + 'Couto', + 'Ide', + 'Howells', + 'Jiminez', + 'Crampton', + 'Monti', + 'Jelinek', + 'Morford', + 'Yeomans', + 'Turnbow', + 'Rolland', + 'Scheetz', + 'Arends', + 'Repp', + 'Hohn', + 'Paton', + 'Govan', + 'Fabela', + 'Mroz', + 'Bourassa', + 'Rizzi', + 'Froelich', + 'Molinari', + 'Lunde', + 'Navarre', + 'Alexandre', + 'Dearborn', + 'Lakes', + 'Foxx', + 'Jerez', + 'Lamanna', + 'Talarico', + 'Butera', + 'Riner', + 'Gros', + 'Champ', + 'Phoenix', + 'Vandeventer', + 'Samora', + 'Behling', + 'Karpinski', + 'Hosier', + 'Tufts', + 'Hobby', + 'Rohrbach', + 'Youngman', + 'Yeary', + 'Paisley', + 'Ben', + 'Villalta', + 'Hempel', + 'Giblin', + 'Lunt', + 'Hagar', + 'Lapoint', + 'Singley', + 'Shows', + 'Kesterson', + 'Bollman', + 'Stansell', + 'Yon', + 'Gabaldon', + 'Simental', + 'Zastrow', + 'Enloe', + 'Sasso', + 'Harkey', + 'Sansom', + 'Twyman', + 'Haslam', + 'Sowa', + 'Hunsberger', + 'Norberg', + 'Hornback', + 'Hanshaw', + 'Axtell', + 'Hoge', + 'Gantz', + 'Mccullum', + 'Blazek', + 'Scher', + 'Carlucci', + 'Jeong', + 'Tillett', + 'Woolridge', + 'Carberry', + 'Reck', + 'Nevin', + 'Armes', + 'Sidhu', + 'Wiesner', + 'Auman', + 'Teeters', + 'Rigg', + 'Moloney', + 'Feld', + 'Lucier', + 'Cardone', + 'Kilian', + 'Conder', + 'Horta', + 'Murakami', + 'Schaff', + 'Dresser', + 'Spray', + 'Hott', + 'Capuano', + 'Englund', + 'Rothe', + 'Ferree', + 'Nolt', + 'Triana', + 'Sanjuan', + 'Oller', + 'Brathwaite', + 'Richert', + 'Holdren', + 'Goree', + 'Branstetter', + 'Schimmel', + 'Jessop', + 'Nellis', + 'Sevier', + 'Rabb', + 'Mcmorris', + 'Lindo', + 'Littles', + 'Polzin', + 'Ranieri', + 'Reale', + 'Sturtevant', + 'Arnone', + 'Zamorano', + 'Keever', + 'Clow', + 'Corr', + 'Blaser', + 'Sheetz', + 'Llanos', + 'Belew', + 'Rusnak', + 'Brandes', + 'Eichhorn', + 'Guida', + 'Pucci', + 'Streit', + 'Renn', + 'Partee', + 'Rappaport', + 'Rosso', + 'Defeo', + 'Greve', + 'Schoch', + 'Langevin', + 'Manna', + 'Towe', + 'Scoville', + 'Marco', + 'Gove', + 'Mckissick', + 'Dangerfield', + 'Mcwhirter', + 'Port', + 'Marrufo', + 'Nicosia', + 'Farren', + 'Kinsley', + 'Pearman', + 'Porch', + 'Mooneyham', + 'Buff', + 'Ruben', + 'Blanc', + 'Mellen', + 'Heiman', + 'Novack', + 'Heston', + 'Huie', + 'Justin', + 'Kincade', + 'Laverty', + 'Villavicencio', + 'Burkart', + 'Offutt', + 'Halliburton', + 'Polo', + 'Barbara', + 'Trammel', + 'Rosati', + 'Sakamoto', + 'Salo', + 'Heyman', + 'Rooker', + 'Sarno', + 'Leroux', + 'Virgen', + 'Collison', + 'Branum', + 'Mcmasters', + 'Divine', + 'Mcnatt', + 'Threadgill', + 'Desir', + 'Borchers', + 'Walkup', + 'Sy', + 'Greenbaum', + 'Vidales', + 'Mercedes', + 'Selph', + 'Bardwell', + 'Whorton', + 'Demartino', + 'Endsley', + 'Verner', + 'Hillier', + 'Mancha', + 'Ricard', + 'Postell', + 'Kummer', + 'Welsch', + 'Almanzar', + 'Brunet', + 'Deeds', + 'Romanowski', + 'Ocallaghan', + 'Cueto', + 'Terhune', + 'Truesdell', + 'Whisnant', + 'Lingo', + 'Aden', + 'Labrecque', + 'Braga', + 'Iles', + 'Garrick', + 'Knickerbocker', + 'Rasberry', + 'Hervey', + 'Schill', + 'Kiely', + 'Liddle', + 'Blakeley', + 'Marez', + 'Schoonmaker', + 'Swinton', + 'Fryar', + 'Exum', + 'Gouge', + 'Hoskinson', + 'Lupton', + 'Guild', + 'Davisson', + 'Chidester', + 'Gravitt', + 'Lenox', + 'Pyatt', + 'Moberg', + 'Overholt', + 'Whiddon', + 'Foti', + 'Lipps', + 'Shankle', + 'Xiao', + 'Balentine', + 'Cesar', + 'Barreras', + 'Schroer', + 'Ram', + 'Eames', + 'Gutman', + 'Pardee', + 'Damiano', + 'Houchin', + 'Porto', + 'Leclerc', + 'Mahaney', + 'Deardorff', + 'Garey', + 'Trotta', + 'Lachapelle', + 'Suiter', + 'Ewert', + 'Costner', + 'Bever', + 'Charpentier', + 'Milewski', + 'Coffelt', + 'Schorr', + 'Leis', + 'Dasher', + 'Cullins', + 'Eveland', + 'Hornung', + 'Swingle', + 'Eudy', + 'Motter', + 'Silk', + 'Gadd', + 'Sidwell', + 'Sandusky', + 'Auld', + 'Mazariegos', + 'Hirt', + 'Zane', + 'Rickett', + 'Ritenour', + 'Goin', + 'Dipaolo', + 'Wolfgang', + 'Inouye', + 'Branton', + 'Rakestraw', + 'Kimbro', + 'Craighead', + 'Sandefur', + 'Foerster', + 'Wipf', + 'Wilkin', + 'Shoffner', + 'Overcash', + 'Simonetti', + 'Toomer', + 'Albino', + 'Eshelman', + 'Rockwood', + 'Pineiro', + 'Reames', + 'Cray', + 'Wulff', + 'Heider', + 'Bath', + 'Colletti', + 'Fiala', + 'Greenstein', + 'Moles', + 'Bashaw', + 'Adamczyk', + 'Finkel', + 'Kistner', + 'Manzi', + 'Ferretti', + 'Demarest', + 'Ahlers', + 'Lack', + 'Wedel', + 'Kinzer', + 'Sechrist', + 'Stickler', + 'Easterday', + 'Mallette', + 'Loehr', + 'Gessner', + 'Croce', + 'Stanko', + 'Innes', + 'Farfan', + 'Heady', + 'Chambless', + 'Balbuena', + 'Decicco', + 'Winsor', + 'Pereyra', + 'Zoller', + 'Ingles', + 'Churchwell', + 'Westlake', + 'Villagran', + 'Soderberg', + 'Thill', + 'Timmer', + 'Mccaleb', + 'Mckernan', + 'Vandergriff', + 'Yoho', + 'Crispin', + 'Dorton', + 'Fults', + 'Borne', + 'Maxie', + 'Bloomquist', + 'Kung', + 'Budde', + 'Weinstock', + 'Honey', + 'Diener', + 'Horak', + 'Tsui', + 'Zirkle', + 'Plum', + 'Heitz', + 'Manrique', + 'Balcom', + 'Napper', + 'Boese', + 'Stefan', + 'Kime', + 'Gautreaux', + 'Leverette', + 'Lemaire', + 'Danford', + 'Hollman', + 'Kuzma', + 'Swinehart', + 'Merriam', + 'Novick', + 'Stankiewicz', + 'Parkes', + 'Englehart', + 'Polansky', + 'Leclaire', + 'Magner', + 'Masson', + 'Mass', + 'Coogan', + 'Jepsen', + 'Pittenger', + 'Bump', + 'Hain', + 'Burchell', + 'Chesley', + 'Cawthon', + 'Dance', + 'Piccolo', + 'Lucey', + 'Ordway', + 'Recio', + 'Ginther', + 'Hauge', + 'Lesperance', + 'Suhr', + 'Ding', + 'Ogg', + 'Skiba', + 'Scannell', + 'Gillies', + 'Brame', + 'Schipper', + 'Brune', + 'Stuber', + 'Pesce', + 'Stead', + 'Bushong', + 'Juneau', + 'Mccalla', + 'Feder', + 'Plaisance', + 'Tweed', + 'Hashimoto', + 'Mounce', + 'Diana', + 'Savala', + 'Vanek', + 'Lamson', + 'Dubin', + 'Killebrew', + 'Kan', + 'Nault', + 'Mulford', + 'Salamanca', + 'Linker', + 'Penrose', + 'Kowalewski', + 'Platz', + 'Kogan', + 'Martucci', + 'Gutowski', + 'Mattes', + 'Haigh', + 'Merida', + 'Ashman', + 'Batton', + 'Biondo', + 'Sweigart', + 'Sorg', + 'Barrier', + 'Gatling', + 'Geib', + 'Henrich', + 'Dabrowski', + 'Vara', + 'Weikel', + 'Jarosz', + 'Mummert', + 'Uriarte', + 'Fifield', + 'Locker', + 'Merlo', + 'Lasater', + 'Ripple', + 'Hopwood', + 'Sherrell', + 'Ruark', + 'Litz', + 'Kinkade', + 'Simkins', + 'Grandy', + 'Lemasters', + 'Wehr', + 'Jinks', + 'Alas', + 'Bale', + 'Stimpson', + 'Glickman', + 'Hage', + 'Seabrook', + 'Stirling', + 'Rozell', + 'Woodburn', + 'Braaten', + 'Sugg', + 'Linde', + 'Castille', + 'Grewal', + 'Blackwelder', + 'Hover', + 'Spurling', + 'Mckellar', + 'Muench', + 'Bovee', + 'Amado', + 'Yau', + 'Harger', + 'Lederer', + 'Seda', + 'Doney', + 'Kimes', + 'Western', + 'Foret', + 'Luera', + 'Warnke', + 'Bussard', + 'Cartier', + 'Andreasen', + 'Lagasse', + 'Topper', + 'Nyman', + 'Hallberg', + 'Whisman', + 'Cremeans', + 'Dewar', + 'Garrow', + 'Odaniel', + 'Stabler', + 'Bourg', + 'Appling', + 'Dahlstrom', + 'Fujimoto', + 'Prudhomme', + 'Gum', + 'Nau', + 'Hiers', + 'Rockett', + 'Sobczak', + 'Traub', + 'Bevis', + 'Tilghman', + 'Plasencia', + 'Sison', + 'Blau', + 'Abbate', + 'Sisler', + 'Rudder', + 'Trotman', + 'Brust', + 'Lederman', + 'Frahm', + 'Fredette', + 'Parise', + 'Urso', + 'Amann', + 'Kaul', + 'Woolery', + 'Thielen', + 'Symonds', + 'Marcy', + 'Wiltshire', + 'Sustaita', + 'Botkin', + 'Kernan', + 'Doolin', + 'Babineaux', + 'Greenspan', + 'Delacerda', + 'Kinnard', + 'Twitty', + 'Augustus', + 'Corriveau', + 'Stults', + 'Toman', + 'Sklar', + 'Leber', + 'Considine', + 'Ohearn', + 'Deforest', + 'Mcmann', + 'Farquhar', + 'Ferrel', + 'Bickley', + 'Manno', + 'Vreeland', + 'Berthiaume', + 'Mcentee', + 'Summerfield', + 'Woodrow', + 'Reynaga', + 'Soltero', + 'Tomko', + 'Jarboe', + 'Allmon', + 'Duplessis', + 'Sydnor', + 'Diallo', + 'Cogar', + 'Mandeville', + 'Shimizu', + 'Aubuchon', + 'Gabbert', + 'Ashlock', + 'Macri', + 'Weng', + 'Walser', + 'Teng', + 'Bailon', + 'Steeves', + 'Perillo', + 'Quattlebaum', + 'Knipp', + 'Delavega', + 'Kirtley', + 'Bramble', + 'Sublett', + 'Borchert', + 'Doria', + 'Session', + 'Merced', + 'Lundstrom', + 'Bluhm', + 'Cortinas', + 'Proper', + 'Sieber', + 'Mccay', + 'Wilford', + 'Asberry', + 'Muldrow', + 'Berning', + 'Hemenway', + 'Millman', + 'Ewers', + 'Timko', + 'Reding', + 'Sayer', + 'Pickel', + 'Cogburn', + 'Chappel', + 'Custodio', + 'Reichel', + 'Robeson', + 'Waid', + 'Wagler', + 'Sappington', + 'Bart', + 'Zazueta', + 'Najar', + 'Marko', + 'Nally', + 'States', + 'Bellard', + 'Marciano', + 'Killough', + 'Cosper', + 'Sangster', + 'Heinze', + 'Bortz', + 'Matamoros', + 'Nuckols', + 'Townsley', + 'Bak', + 'Ralls', + 'Ferrin', + 'Villela', + 'Siegrist', + 'Arora', + 'Collinsworth', + 'Masten', + 'Deer', + 'Balog', + 'Buchman', + 'Scaggs', + 'Holeman', + 'Lefkowitz', + 'Santora', + 'Funke', + 'Redfield', + 'Douthit', + 'Marciniak', + 'Twitchell', + 'Sheahan', + 'Dai', + 'Demuth', + 'Ganz', + 'Bruckner', + 'Wier', + 'Alamo', + 'Aultman', + 'Chubb', + 'Branco', + 'Courter', + 'Vivian', + 'Guin', + 'Witten', + 'Glen', + 'Hyer', + 'Crowson', + 'Arendt', + 'Cipolla', + 'Prochaska', + 'Schober', + 'Harte', + 'Arciniega', + 'Beier', + 'Middlebrook', + 'Dennard', + 'Vantassel', + 'Weekes', + 'Penley', + 'Lozier', + 'Lamberson', + 'Broomfield', + 'Nygaard', + 'Pascale', + 'Hyden', + 'Mundell', + 'Kamara', + 'Ehlert', + 'Mangus', + 'Bornstein', + 'Benedetti', + 'Erikson', + 'Quint', + 'Westman', + 'Basler', + 'Smoak', + 'Leavell', + 'Kerber', + 'Kopec', + 'Emrick', + 'Mattice', + 'Render', + 'Mccree', + 'Feldmann', + 'Cutright', + 'Randell', + 'Drucker', + 'Gilmour', + 'Marconi', + 'Stripling', + 'Mucha', + 'Shipe', + 'Chalk', + 'Martone', + 'Lema', + 'Ricardo', + 'Cobian', + 'Laufer', + 'Mistretta', + 'Shortt', + 'Menzel', + 'Wickline', + 'Oddo', + 'Chai', + 'Rabideau', + 'Stogner', + 'Mckie', + 'Luongo', + 'Trieu', + 'Breshears', + 'Sturdevant', + 'Abernethy', + 'Rohan', + 'Bonnette', + 'Steffes', + 'Straka', + 'Lawhon', + 'Shawver', + 'Guilford', + 'Wiltz', + 'Digregorio', + 'Warburton', + 'Fleshman', + 'Kerstetter', + 'Byram', + 'Obannon', + 'Dalessio', + 'Gatti', + 'Kalb', + 'Boris', + 'Graver', + 'Parkins', + 'Kollar', + 'Crothers', + 'Patin', + 'Cutshall', + 'Fern', + 'Derosier', + 'Goodrum', + 'Kaelin', + 'Baynes', + 'Beesley', + 'Macintyre', + 'Butters', + 'Kinsman', + 'Huffer', + 'Eslinger', + 'Prunty', + 'Boehmer', + 'Nusbaum', + 'Gouveia', + 'Mire', + 'Mccary', + 'Mikell', + 'Petrovich', + 'Melillo', + 'Kennelly', + 'Howley', + 'Merwin', + 'Cotner', + 'Kanter', + 'Sahagun', + 'Bodden', + 'Mcconville', + 'Leddy', + 'Auten', + 'Downie', + 'Armistead', + 'Goudy', + 'Gerhard', + 'Theiss', + 'Lauria', + 'Tuthill', + 'Ammon', + 'Ikeda', + 'Schultheis', + 'Zhong', + 'Pearcy', + 'Vass', + 'Essary', + 'Wendland', + 'Zehr', + 'Hartigan', + 'Ugalde', + 'Mossman', + 'Hartwick', + 'Joaquin', + 'Andreas', + 'Bartee', + 'Gajewski', + 'Gallaway', + 'Comerford', + 'Lieber', + 'Wireman', + 'Damm', + 'Yousif', + 'Kosinski', + 'Kelm', + 'Durrant', + 'Derouen', + 'Bonk', + 'Rubalcaba', + 'Opperman', + 'Decamp', + 'Fairfield', + 'Pauls', + 'Dicicco', + 'Northup', + 'Woerner', + 'Stegman', + 'Ritch', + 'Bedoya', + 'Jeanpierre', + 'Rioux', + 'Strohl', + 'Herrell', + 'Simonton', + 'Carriere', + 'Pridemore', + 'Karam', + 'Marple', + 'Topp', + 'Heiden', + 'Leibowitz', + 'Morabito', + 'Junker', + 'Calixto', + 'Hardt', + 'Silverio', + 'Swords', + 'Rickey', + 'Roussel', + 'Earles', + 'Bastien', + 'Defilippo', + 'Bigley', + 'Mosteller', + 'Issa', + 'Prout', + 'Grossi', + 'Bartos', + 'Lipman', + 'Colegrove', + 'Stpeter', + 'Vanfleet', + 'Fordyce', + 'Risher', + 'Royston', + 'Shoulders', + 'Mendel', + 'Statler', + 'Dantonio', + 'Inglis', + 'Fogleman', + 'Loveday', + 'Straus', + 'Luft', + 'Dam', + 'Chewning', + 'Winkel', + 'Bousquet', + 'Eckhart', + 'Dillinger', + 'Locascio', + 'Shellenberger', + 'Duerr', + 'Alcocer', + 'Licht', + 'Gingras', + 'Grassi', + 'Gately', + 'Padula', + 'Brien', + 'Nimmo', + 'Nell', + 'Bondurant', + 'Hughley', + 'Schalk', + 'Cabrales', + 'Heinemann', + 'Meunier', + 'Maddock', + 'Noone', + 'Brackin', + 'Dunnigan', + 'Sargeant', + 'Kinchen', + 'Veras', + 'Gile', + 'Bacchus', + 'Ang', + 'Cowgill', + 'Currey', + 'Garlick', + 'Manus', + 'Ballance', + 'Robitaille', + 'Begin', + 'Mijares', + 'Keogh', + 'Wicklund', + 'Mccurley', + 'Truett', + 'Pullin', + 'Alkire', + 'Loughran', + 'Mort', + 'Tatman', + 'Wanamaker', + 'Haralson', + 'Harrah', + 'Stucker', + 'Reda', + 'Pascal', + 'Holter', + 'Solares', + 'Bruck', + 'Mah', + 'Didomenico', + 'Korth', + 'Virgil', + 'Nishimura', + 'Vacca', + 'Stenberg', + 'Tomczak', + 'Sayler', + 'Chasse', + 'Blazer', + 'Sleeper', + 'Doiron', + 'Nunnery', + 'Ortman', + 'Maag', + 'Cali', + 'Ferrera', + 'Hotaling', + 'Festa', + 'Murr', + 'Sterrett', + 'Cuthbert', + 'Clayborn', + 'Pendergraft', + 'Yoakum', + 'Baily', + 'Overbey', + 'Warne', + 'Hokanson', + 'Tafolla', + 'Puglisi', + 'Wooster', + 'Nassar', + 'Lesniak', + 'Noack', + 'Beres', + 'Liberatore', + 'Guyette', + 'Duffin', + 'Ishmael', + 'Dolezal', + 'Larimer', + 'Musso', + 'Borman', + 'Deemer', + 'Hobgood', + 'Triggs', + 'Mau', + 'Wainscott', + 'Seth', + 'Hodnett', + 'Mckeehan', + 'Toon', + 'Evens', + 'Drost', + 'Roehl', + 'Trapani', + 'Bains', + 'Modica', + 'Arcos', + 'Knopf', + 'Salvo', + 'Garlock', + 'Lounsbury', + 'Hennen', + 'Drescher', + 'Morgenstern', + 'Studebaker', + 'Nordin', + 'Madore', + 'Joslyn', + 'Brousseau', + 'Addy', + 'Audette', + 'Santibanez', + 'Sauers', + 'Engelman', + 'Mauney', + 'Arechiga', + 'Eckel', + 'Jerry', + 'Pernell', + 'Sedlacek', + 'Mcnary', + 'Loewen', + 'Eyler', + 'Feather', + 'Mckinnie', + 'Bowersox', + 'Laclair', + 'Melby', + 'Thoman', + 'Hose', + 'Carmon', + 'Bartram', + 'Berggren', + 'Rogge', + 'Seto', + 'Court', + 'Deskins', + 'Barcus', + 'Putt', + 'Minick', + 'Durgin', + 'Hockman', + 'Keltner', + 'Legaspi', + 'Wallach', + 'Ranney', + 'Borger', + 'Wakeman', + 'Schoolcraft', + 'Souther', + 'Villani', + 'Sauder', + 'Chupp', + 'Slover', + 'Faul', + 'Degroat', + 'Hakim', + 'Brucker', + 'Moylan', + 'Castilleja', + 'Whetzel', + 'Eanes', + 'Brouwer', + 'Okelley', + 'Crimmins', + 'Bargas', + 'Jo', + 'Clover', + 'Adan', + 'Domingues', + 'Yelton', + 'Lobdell', + 'Mattis', + 'Escudero', + 'Pentecost', + 'Riser', + 'Lorentz', + 'Neace', + 'Caplinger', + 'Lipe', + 'Satterlee', + 'Labarbera', + 'Cullison', + 'Goggin', + 'Coke', + 'Keo', + 'Buckmaster', + 'Holtzclaw', + 'Lustig', + 'Ellinger', + 'Lollar', + 'Cork', + 'Mccrae', + 'Hilario', + 'Yawn', + 'Arnette', + 'Yuhas', + 'Wardle', + 'Pixley', + 'Leflore', + 'Fluker', + 'Krier', + 'Wind', + 'Ditto', + 'Rorie', + 'Ensminger', + 'Hunsucker', + 'Levenson', + 'Millington', + 'Gorsuch', + 'Willems', + 'Fredricks', + 'Agarwal', + 'Lariviere', + 'Don', + 'Chery', + 'Pfeil', + 'Wurtz', + 'Remillard', + 'Cozad', + 'Hodgkins', + 'Cohan', + 'Nurse', + 'Espana', + 'Giguere', + 'Hoskin', + 'Pettaway', + 'Keifer', + 'Yandell', + 'Frandsen', + 'Nawrocki', + 'Vila', + 'Pouliot', + 'Boulanger', + 'Pruden', + 'Strauch', + 'Lua', + 'Rohn', + 'Greig', + 'Lightsey', + 'Etheredge', + 'Hara', + 'Ensign', + 'Ruckman', + 'Senecal', + 'Sedgwick', + 'Maciejewski', + 'Morningstar', + 'Creswell', + 'Britten', + 'Godley', + 'Laubach', + 'Schwenk', + 'Hayhurst', + 'Cammarata', + 'Paxson', + 'Mcmurtry', + 'Marasco', + 'Weatherby', + 'Fales', + 'Fondren', + 'Deherrera', + 'Gaydos', + 'Defranco', + 'Bjorklund', + 'Silberman', + 'Maxon', + 'Rockey', + 'Brass', + 'Marcoux', + 'Marquette', + 'Marcello', + 'Veit', + 'Debose', + 'Cloninger', + 'Puccio', + 'Greenman', + 'Bross', + 'Lile', + 'Behan', + 'Plumlee', + 'Hampson', + 'Steverson', + 'Wininger', + 'Mcmullan', + 'Jude', + 'Sharif', + 'Rothermel', + 'Becher', + 'Keithley', + 'Gargano', + 'Morillo', + 'Dumond', + 'Johannsen', + 'Baney', + 'Lipton', + 'Railey', + 'Clowers', + 'Rotondo', + 'Simeone', + 'Hatt', + 'Schexnayder', + 'Snoddy', + 'Gelinas', + 'Mendelson', + 'Matherly', + 'Klock', + 'Clubb', + 'Dunkley', + 'Rosenzweig', + 'Chuang', + 'Gines', + 'Galasso', + 'Helland', + 'Rohrbaugh', + 'Avilez', + 'Czajkowski', + 'Olsson', + 'Lumsden', + 'Birt', + 'Ortego', + 'Acuff', + 'Yetter', + 'Tichenor', + 'Mork', + 'Skillman', + 'Row', + 'Lollis', + 'Wolk', + 'Demott', + 'Lazenby', + 'Bellew', + 'Brickner', + 'Ragusa', + 'Stice', + 'Herlihy', + 'Guillermo', + 'Estabrook', + 'Montijo', + 'Jenner', + 'Rayfield', + 'Donlon', + 'Greenhalgh', + 'Alberti', + 'Rix', + 'Holthaus', + 'Mistry', + 'Ruzicka', + 'Sievert', + 'Koopman', + 'Kalish', + 'Kehl', + 'Ponte', + 'Varnell', + 'Guss', + 'Kovac', + 'Hosmer', + 'Scrivner', + 'Tomblin', + 'Villafuerte', + 'Branscum', + 'Nitz', + 'Reider', + 'Gaunt', + 'Richerson', + 'Hemmer', + 'Vinyard', + 'Barrie', + 'Manalo', + 'Flynt', + 'Cadle', + 'Hau', + 'Uy', + 'Manfredi', + 'Deeter', + 'Resto', + 'Carnell', + 'Drane', + 'Cusumano', + 'Fein', + 'Schneck', + 'Stucky', + 'Heid', + 'Bruggeman', + 'Schweiger', + 'Vanetten', + 'Munsey', + 'Kiker', + 'Whittier', + 'Seeman', + 'Zerbe', + 'Hillyer', + 'Burkhead', + 'Gafford', + 'Gephart', + 'Braman', + 'Plott', + 'Henriques', + 'Coppock', + 'Mcandrews', + 'Valtierra', + 'Dileo', + 'Stiner', + 'Mikel', + 'Owensby', + 'Gupton', + 'Scurlock', + 'Gittens', + 'Degnan', + 'Guillaume', + 'Helmuth', + 'Nolin', + 'Mair', + 'Bergeson', + 'Paik', + 'Kinne', + 'Goodloe', + 'Nakagawa', + 'Raposo', + 'Defreitas', + 'Korb', + 'Hinkel', + 'Magers', + 'Althoff', + 'Rafael', + 'Akhtar', + 'Cashion', + 'Mcquillan', + 'Patricio', + 'Sweeny', + 'Meaux', + 'Tyre', + 'Demeo', + 'Trivedi', + 'Goodfellow', + 'Dunleavy', + 'Middaugh', + 'Barbato', + 'Pasco', + 'Harland', + 'Shorts', + 'Mowrey', + 'Dempster', + 'Knuckles', + 'Luebke', + 'Petrella', + 'Retana', + 'Licea', + 'Rundle', + 'Cape', + 'Lou', + 'Mcconkey', + 'Leeman', + 'Cabe', + 'Timothy', + 'Crochet', + 'Fulgham', + 'Glasco', + 'Backes', + 'Konopka', + 'Mcquaid', + 'Schley', + 'Abrahams', + 'Dahlin', + 'Iversen', + 'Chico', + 'Huffaker', + 'Modlin', + 'Laduke', + 'Marquart', + 'Motz', + 'Keech', + 'Louviere', + 'Como', + 'Fye', + 'Brightwell', + 'Yamashita', + 'Desrochers', + 'Richer', + 'Bourke', + 'Broadhead', + 'Pink', + 'Okamoto', + 'Chicas', + 'Vanatta', + 'Shick', + 'Furst', + 'Layfield', + 'Mcewan', + 'Baumgart', + 'Kappel', + 'Kucharski', + 'Quam', + 'Taub', + 'Houghtaling', + 'Sundquist', + 'Monks', + 'Wake', + 'Quiros', + 'Pursell', + 'Johansson', + 'Talkington', + 'Bast', + 'Stimson', + 'Hakes', + 'Loe', + 'Caggiano', + 'Schaper', + 'Chandra', + 'Tuma', + 'Arledge', + 'Romain', + 'Hornick', + 'Bridgman', + 'Livingstone', + 'Potvin', + 'Sparling', + 'Hause', + 'Trosclair', + 'Pless', + 'Szeto', + 'Clontz', + 'Lauber', + 'Detrick', + 'Dominique', + 'Mosser', + 'Degraff', + 'Liner', + 'Fleet', + 'Czerwinski', + 'Kopf', + 'Kovar', + 'Sheedy', + 'Zaremba', + 'Mina', + 'Sweeten', + 'Ou', + 'Musto', + 'Hennig', + 'Bangs', + 'Pasternak', + 'Berrier', + 'Smidt', + 'Brayton', + 'Claytor', + 'Ellerbe', + 'Reiman', + 'Larimore', + 'Ratzlaff', + 'Mudge', + 'Ni', + 'Spillers', + 'Cuomo', + 'Gerke', + 'Polizzi', + 'Harmer', + 'Apperson', + 'Regis', + 'Ugarte', + 'Paull', + 'Lagrange', + 'Dinwiddie', + 'Becton', + 'Gadsden', + 'Conforti', + 'Desoto', + 'Orme', + 'Filer', + 'Viers', + 'Lares', + 'Stair', + 'Hipps', + 'Kaneshiro', + 'Ladson', + 'Altizer', + 'Montejano', + 'Scalzo', + 'Sowder', + 'Ebeling', + 'Faucher', + 'Dicken', + 'Sartor', + 'Mcnerney', + 'Stage', + 'Mika', + 'Hice', + 'Grinstead', + 'Bartsch', + 'Mccumber', + 'Lenahan', + 'Liska', + 'Tietz', + 'Gauna', + 'Janda', + 'Bellis', + 'Shew', + 'Kelton', + 'Doby', + 'Golson', + 'Plaster', + 'Gonsales', + 'Krone', + 'Lape', + 'Lowrie', + 'Polly', + 'Gerardi', + 'Lamoreaux', + 'Bhatti', + 'Kimsey', + 'Buhl', + 'Arvin', + 'Gillian', + 'Benbow', + 'Roesler', + 'Stlaurent', + 'Canon', + 'Swihart', + 'Corea', + 'Petitt', + 'Spates', + 'Nappi', + 'Sebring', + 'Smelser', + 'Eckenrode', + 'Palos', + 'Disanto', + 'Tabares', + 'Okane', + 'Easterly', + 'Dendy', + 'Whigham', + 'Bednarz', + 'Wedge', + 'Edelen', + 'Stiff', + 'Borjas', + 'Obando', + 'Mcspadden', + 'Breed', + 'Dismuke', + 'Jarmon', + 'Serpa', + 'Lucky', + 'Cournoyer', + 'Hedberg', + 'Martine', + 'Michell', + 'Wittig', + 'Clodfelter', + 'Davids', + 'Gattis', + 'Kull', + 'Mascorro', + 'Schad', + 'Rine', + 'Bradburn', + 'Marie', + 'Czech', + 'Sunderman', + 'Wickersham', + 'Toohey', + 'Capozzi', + 'Poplin', + 'Markland', + 'Brosnan', + 'Fetterman', + 'Heiss', + 'Haglund', + 'Jourdan', + 'Turnipseed', + 'Tiernan', + 'Horrocks', + 'Barnhardt', + 'Sing', + 'Belford', + 'Baumgarten', + 'Klee', + 'Degeorge', + 'Caulder', + 'Gladstone', + 'Dancer', + 'Satchell', + 'Vento', + 'Larock', + 'Kimberly', + 'Hunn', + 'Harvin', + 'Krahn', + 'Ogorman', + 'Storch', + 'Coomes', + 'Bevilacqua', + 'Crotts', + 'Schillinger', + 'Morelock', + 'Hayworth', + 'Avis', + 'Cranmer', + 'Getchell', + 'Tena', + 'Buzzell', + 'Widman', + 'Barter', + 'Lafayette', + 'Asencio', + 'Embree', + 'Krell', + 'Siders', + 'Fuselier', + 'Whitby', + 'Elsner', + 'Pando', + 'Surface', + 'Rolf', + 'Highland', + 'Bufford', + 'Scheidt', + 'Defrancesco', + 'Fellers', + 'Carrol', + 'Germano', + 'Licon', + 'Hilty', + 'Ringo', + 'Dowler', + 'Glowacki', + 'Slabaugh', + 'Tomasello', + 'Messing', + 'Lavalle', + 'Milo', + 'Frerichs', + 'Plotkin', + 'Ziolkowski', + 'Gentle', + 'Knobloch', + 'Larochelle', + 'Duell', + 'Hurdle', + 'Speller', + 'Ceasar', + 'Vinci', + 'Mosquera', + 'Wyse', + 'Towler', + 'Ayoub', + 'Gullickson', + 'Spade', + 'Forshee', + 'Cliff', + 'Gholson', + 'Reichenbach', + 'Lockman', + 'Morones', + 'Storie', + 'Bissett', + 'Janney', + 'Durocher', + 'Fentress', + 'Troiano', + 'Boes', + 'Rouleau', + 'Rall', + 'Sultan', + 'Braggs', + 'Bethke', + 'Schacht', + 'Straley', + 'Mcfalls', + 'Fahy', + 'Winegar', + 'Gorecki', + 'Rudnick', + 'Wigginton', + 'Dedrick', + 'Sthilaire', + 'Lovette', + 'Hanneman', + 'Loch', + 'Moores', + 'Polen', + 'Anchondo', + 'Rosato', + 'Tindell', + 'Hunsicker', + 'Penna', + 'Privette', + 'Gayton', + 'Sliger', + 'Wink', + 'Brummer', + 'Crown', + 'Sommerville', + 'Mastrangelo', + 'Latimore', + 'Merlino', + 'Thoreson', + 'Kleiner', + 'Able', + 'Boose', + 'Loyola', + 'Jimenes', + 'Lapham', + 'Srinivasan', + 'Hammers', + 'Mo', + 'Evert', + 'Vanslyke', + 'Caywood', + 'Gremillion', + 'Rauscher', + 'Eckhoff', + 'Dearth', + 'Sinha', + 'Becerril', + 'Tuten', + 'Greenwalt', + 'Curlee', + 'Burgan', + 'Feagin', + 'Gallman', + 'Germann', + 'Swensen', + 'Vanallen', + 'Bissonnette', + 'Stoudt', + 'Handler', + 'Tanguay', + 'Lovins', + 'Smotherman', + 'Cutts', + 'Herod', + 'Maclin', + 'Arcuri', + 'Hackbarth', + 'Breazeale', + 'Rainville', + 'Crick', + 'Macintosh', + 'Bloss', + 'Fridley', + 'Stefanski', + 'Beauvais', + 'Koop', + 'Andes', + 'Blomberg', + 'Vallee', + 'Lanigan', + 'Blouin', + 'Rochon', + 'Dorazio', + 'Drouin', + 'Lamonica', + 'Wilbourn', + 'Spraggins', + 'Rieder', + 'Shugart', + 'Chacko', + 'Rutan', + 'Nutting', + 'Lawley', + 'Landy', + 'January', + 'Blowers', + 'Handel', + 'Doman', + 'Swiney', + 'Ettinger', + 'Jellison', + 'Veilleux', + 'Wiens', + 'Raimondi', + 'Spink', + 'Emond', + 'Yale', + 'Rachel', + 'Alldredge', + 'Lach', + 'Morlan', + 'Wayland', + 'Colquitt', + 'Gabrielson', + 'Mccarver', + 'Frances', + 'Granville', + 'Costigan', + 'Preuss', + 'Lentini', + 'Vansant', + 'Mosca', + 'Connally', + 'Frei', + 'Laplant', + 'Lago', + 'Leiter', + 'Trumbull', + 'Shaeffer', + 'Gongora', + 'Coady', + 'Fyffe', + 'Mance', + 'Worcester', + 'Zehner', + 'Bodie', + 'Burnes', + 'Pompey', + 'Teitelbaum', + 'Beaupre', + 'Visconti', + 'Mumma', + 'Markiewicz', + 'Piscitelli', + 'Moak', + 'Bourland', + 'Pennock', + 'Hannum', + 'Robichaux', + 'Folks', + 'Coppage', + 'Heffron', + 'Mullet', + 'Kimberlin', + 'Breneman', + 'Blandford', + 'Matthias', + 'Engebretson', + 'Roessler', + 'Allee', + 'Parkman', + 'Barge', + 'Ren', + 'Backstrom', + 'Bullen', + 'Lampman', + 'Loesch', + 'Echavarria', + 'Haman', + 'Cortina', + 'Elms', + 'Gordan', + 'Pabst', + 'Snelson', + 'Vanarsdale', + 'Pecora', + 'Rabago', + 'Enger', + 'Senger', + 'Dewees', + 'Semple', + 'Howey', + 'Westlund', + 'Daw', + 'Hagemann', + 'Mcpeek', + 'Vanderhoof', + 'Ohler', + 'Bohm', + 'Mazzone', + 'Arnott', + 'Bouton', + 'Fackler', + 'Giunta', + 'Stagner', + 'Tavera', + 'Poorman', + 'Buch', + 'Mangano', + 'Bonar', + 'Gerson', + 'Ranger', + 'Mccullar', + 'Wunder', + 'Bade', + 'Armand', + 'Chalfant', + 'Lichtenstein', + 'Turco', + 'Degraw', + 'Few', + 'Haigler', + 'Lis', + 'Bittinger', + 'Morrone', + 'Hodgdon', + 'Wittenberg', + 'Imes', + 'Dreiling', + 'Landwehr', + 'Maly', + 'Warlick', + 'Terpstra', + 'Bolte', + 'Stiller', + 'Stmartin', + 'Pankratz', + 'Albee', + 'Victory', + 'Lezama', + 'Brecht', + 'Monarrez', + 'Thurlow', + 'Laskey', + 'Bothwell', + 'Candler', + 'Esh', + 'Kalman', + 'Samano', + 'Yohe', + 'Regnier', + 'Leite', + 'Ballantyne', + 'Dan', + 'Fikes', + 'Cendejas', + 'Mikula', + 'Fairman', + 'Dragon', + 'Manzella', + 'Renninger', + 'Leaman', + 'Godbey', + 'Current', + 'Mirabal', + 'Boerner', + 'Depaz', + 'Birge', + 'Westberry', + 'Severin', + 'Weddington', + 'Longenecker', + 'Mccreery', + 'Lebel', + 'Nader', + 'Gan', + 'Auguste', + 'Colonna', + 'Paramo', + 'Minyard', + 'Duley', + 'Beil', + 'Salters', + 'Brindley', + 'Simmers', + 'Lumpkins', + 'Crisman', + 'Raulerson', + 'Lanz', + 'Deroche', + 'Kemmerer', + 'Bogner', + 'Mahn', + 'Willer', + 'Gunnels', + 'Warford', + 'Reason', + 'Scherr', + 'Digirolamo', + 'Hallowell', + 'Wilcoxson', + 'Gaillard', + 'Deshields', + 'Hively', + 'Sakai', + 'Creason', + 'Jaber', + 'Lapinski', + 'Bolivar', + 'Millwood', + 'Shumpert', + 'Fujii', + 'Plemmons', + 'Lamere', + 'Cleghorn', + 'Mccaw', + 'Seavey', + 'Zwick', + 'Hosler', + 'Lepley', + 'Marden', + 'Cornwall', + 'Gauger', + 'Hofmeister', + 'Bugarin', + 'Loose', + 'Guardiola', + 'Hertzog', + 'Bigger', + 'Heineman', + 'Retzlaff', + 'Rizzuto', + 'Flannigan', + 'Rathburn', + 'Moulder', + 'Town', + 'Gautier', + 'Hamid', + 'Torrance', + 'Walthall', + 'Windom', + 'Kleckner', + 'Kirwan', + 'Gasaway', + 'Pinkard', + 'Concannon', + 'Mcquiston', + 'Yow', + 'Eshleman', + 'Riggleman', + 'Foulk', + 'Bolles', + 'Craine', + 'Hinnant', + 'Gholston', + 'Lebo', + 'Torkelson', + 'Mancia', + 'Canale', + 'Celestin', + 'Neubert', + 'Schmaltz', + 'Highfill', + 'Fisch', + 'Matte', + 'Hoefer', + 'Flippin', + 'Mclin', + 'Mikkelson', + 'Gump', + 'Kilroy', + 'Ensor', + 'Klosterman', + 'Ruppel', + 'Steffey', + 'Sauve', + 'Cessna', + 'Apgar', + 'Jacobus', + 'Pettyjohn', + 'Northington', + 'Smithey', + 'Moro', + 'Dossett', + 'Mccroskey', + 'Yelverton', + 'Mascarenas', + 'Hebb', + 'Quinteros', + 'Giang', + 'Pontius', + 'Sipple', + 'Atkin', + 'Howington', + 'Hiebert', + 'Lingerfelt', + 'Schueler', + 'Sailer', + 'Smits', + 'Keeter', + 'Macrae', + 'Mease', + 'Shortridge', + 'Scates', + 'Amstutz', + 'Kuebler', + 'Cambron', + 'Eaker', + 'Finlayson', + 'Bookout', + 'Mullett', + 'Bank', + 'Schlenker', + 'Morlock', + 'Haskett', + 'Dade', + 'Gallucci', + 'Lahey', + 'Ryerson', + 'Crownover', + 'Banfield', + 'Mcclay', + 'Diggins', + 'Conerly', + 'Primus', + 'Syverson', + 'Prindle', + 'Blasingame', + 'Deford', + 'Garnes', + 'Hoisington', + 'Glasper', + 'Lorusso', + 'Hesson', + 'Youssef', + 'Threlkeld', + 'Talmadge', + 'Winfree', + 'Heacock', + 'Rawlinson', + 'Burse', + 'Diederich', + 'Niemiec', + 'Norby', + 'Bauder', + 'Scranton', + 'Prentiss', + 'Towles', + 'Henton', + 'Purifoy', + 'Pinzon', + 'Edler', + 'Ragin', + 'Albarado', + 'Cuadra', + 'Hoadley', + 'Devita', + 'Pavon', + 'Alday', + 'Goulding', + 'Millis', + 'Dalley', + 'Kolodziej', + 'Kropf', + 'Kuiper', + 'Crespin', + 'Xavier', + 'Sailor', + 'Lagrone', + 'Boehme', + 'Tidd', + 'Wilmore', + 'Ziemer', + 'Ropp', + 'Kettler', + 'Pilon', + 'Miron', + 'Salsbury', + 'Job', + 'Sensenig', + 'Cayton', + 'Nanney', + 'Rasch', + 'Silvestre', + 'Ladue', + 'Dampier', + 'Ackermann', + 'Friedel', + 'Kleiman', + 'Geronimo', + 'Ezzell', + 'Duclos', + 'Moor', + 'Neuhaus', + 'Lan', + 'Allender', + 'Tedeschi', + 'Langton', + 'Dawley', + 'Kearse', + 'Godina', + 'Guernsey', + 'Kober', + 'Bisbee', + 'Lamphere', + 'Kinman', + 'Wesner', + 'Malo', + 'Stroupe', + 'Millette', + 'Yeoman', + 'Baig', + 'Kirchoff', + 'Tsao', + 'Cristobal', + 'Mucci', + 'Pair', + 'Barefield', + 'Dewolf', + 'Fitzmaurice', + 'Mcaleer', + 'Natal', + 'Bara', + 'Macey', + 'Mclennan', + 'Fabre', + 'Vieyra', + 'Magno', + 'Eyre', + 'Chatterton', + 'Gilland', + 'Hurlbut', + 'Umberger', + 'Roloff', + 'Brambila', + 'Mazzeo', + 'Letson', + 'Norsworthy', + 'Bier', + 'Gioia', + 'Kapoor', + 'Marlatt', + 'Flippo', + 'Houde', + 'Baughn', + 'Blackledge', + 'Fly', + 'Dinkel', + 'Rathbone', + 'Bober', + 'Boydston', + 'Ferdinand', + 'Coletti', + 'Cuenca', + 'Deters', + 'Blagg', + 'Timmins', + 'Boyden', + 'Meads', + 'Narcisse', + 'Saelee', + 'Cosner', + 'Strawser', + 'Amico', + 'Dowdle', + 'Golub', + 'Silverberg', + 'Riles', + 'Balk', + 'Buhr', + 'Feltman', + 'Stickel', + 'Zapien', + 'Cargile', + 'Kulik', + 'Lazzaro', + 'Oberle', + 'Wickstrom', + 'Maeda', + 'Cockrum', + 'Boulton', + 'Sandford', + 'Culbert', + 'Dula', + 'Ament', + 'Chunn', + 'Owenby', + 'Wasilewski', + 'Wichman', + 'Oestreich', + 'Klos', + 'Orchard', + 'Hogge', + 'Presson', + 'Cordon', + 'Gans', + 'Leonardi', + 'Manjarrez', + 'Olander', + 'Drennen', + 'Wirt', + 'Tiger', + 'Dolce', + 'Hagstrom', + 'Hirsh', + 'Tally', + 'Crumbley', + 'Mcgreevy', + 'Amidon', + 'Olague', + 'Lint', + 'Poche', + 'Lipford', + 'Engen', + 'Mcelfresh', + 'Cuneo', + 'Krumm', + 'Haak', + 'Arocho', + 'Longworth', + 'Seamon', + 'Bronner', + 'Swartzentruber', + 'Chand', + 'Wilhoit', + 'Chapel', + 'Hitchens', + 'Brzezinski', + 'Heidenreich', + 'Ellenberger', + 'Gamblin', + 'Ormond', + 'Burchard', + 'Dibella', + 'Nicoll', + 'Simcox', + 'Strohm', + 'Dittmar', + 'Wycoff', + 'Grays', + 'Spero', + 'Vess', + 'Picone', + 'Greening', + 'Maynes', + 'Knauss', + 'Wojtowicz', + 'Chaput', + 'Soliman', + 'Ponton', + 'Carlino', + 'Kestner', + 'Kelch', + 'Dimauro', + 'Iorio', + 'Parenteau', + 'Pesina', + 'Clauson', + 'Stigall', + 'Keels', + 'Waldrep', + 'Wix', + 'Draeger', + 'Ertel', + 'Starner', + 'Charest', + 'Simoneaux', + 'Ivanov', + 'Thor', + 'Gravel', + 'Trottier', + 'Clendenin', + 'Kromer', + 'Benda', + 'Touchet', + 'Hornbuckle', + 'Avent', + 'Dombroski', + 'Friedland', + 'Radabaugh', + 'Vesely', + 'Wike', + 'Lax', + 'Messersmith', + 'Deoliveira', + 'Brey', + 'Cogdill', + 'Overturf', + 'Sova', + 'Pero', + 'Beaird', + 'Cevallos', + 'Defalco', + 'Taormina', + 'Thornberry', + 'Westervelt', + 'Macaulay', + 'Hajek', + 'Brugger', + 'Leff', + 'Ketterer', + 'Ono', + 'Mullenix', + 'Frison', + 'Gullo', + 'Calhoon', + 'Summey', + 'Hockaday', + 'Dimatteo', + 'Agan', + 'Patenaude', + 'Mary', + 'Tanis', + 'Obert', + 'Elton', + 'Randles', + 'Migliore', + 'Schmalz', + 'Vanvalkenburg', + 'Quinto', + 'Palmquist', + 'Hoops', + 'Naples', + 'Orear', + 'Eberhard', + 'Fitzgibbons', + 'Adkinson', + 'Gerace', + 'Elie', + 'Dressel', + 'Silber', + 'Otey', + 'Hsiao', + 'Kreutzer', + 'Tutor', + 'Roundy', + 'Haddox', + 'Bridgers', + 'Leto', + 'Daniell', + 'Pollitt', + 'Freda', + 'Mraz', + 'Engelbrecht', + 'Ariza', + 'Grand', + 'Pavone', + 'Everts', + 'Benes', + 'Reamer', + 'Faucett', + 'Eatmon', + 'Raymundo', + 'Zaman', + 'Devitt', + 'Master', + 'Carron', + 'Hoffner', + 'Sciortino', + 'Stringham', + 'Bookman', + 'Westberg', + 'Spahn', + 'Hise', + 'Waterbury', + 'Buckwalter', + 'Hug', + 'Overly', + 'Dingus', + 'Ince', + 'Haar', + 'Shain', + 'Heaps', + 'Oppenheimer', + 'Miyamoto', + 'Schreier', + 'Martello', + 'Atteberry', + 'Folger', + 'Macke', + 'Pal', + 'Lucchesi', + 'Osterhout', + 'Liriano', + 'Legge', + 'Barra', + 'Crumb', + 'Gwyn', + 'Forst', + 'Axelrod', + 'Samayoa', + 'Edgell', + 'Purkey', + 'Lannon', + 'Branam', + 'Yeo', + 'Hatmaker', + 'Borum', + 'Villagrana', + 'Lawing', + 'Bark', + 'Muirhead', + 'Eckles', + 'Weight', + 'Surles', + 'Cullinan', + 'Lagos', + 'Naber', + 'Sloat', + 'Foos', + 'Vine', + 'Milliner', + 'Reliford', + 'Dahlquist', + 'Gibney', + 'Moroney', + 'Stecker', + 'Bella', + 'Brickhouse', + 'Canela', + 'Kula', + 'Tartaglia', + 'Siewert', + 'Hitch', + 'Brickman', + 'Cheeseman', + 'Carollo', + 'Geissler', + 'Jiron', + 'Cossey', + 'Sroka', + 'Border', + 'Brownlow', + 'Ellenburg', + 'Cella', + 'Brinton', + 'Scurry', + 'Behrendt', + 'Carstensen', + 'Schendel', + 'Bodner', + 'Eddleman', + 'Stec', + 'Capasso', + 'Leu', + 'Kennett', + 'Ruane', + 'Critchfield', + 'Carbonell', + 'Mitcham', + 'Troncoso', + 'Mckeen', + 'Cammack', + 'Broach', + 'Culbreath', + 'Callejas', + 'Wurst', + 'Brookman', + 'Guerrier', + 'Seese', + 'Kitzmiller', + 'Graybeal', + 'Yardley', + 'Cheever', + 'Virgin', + 'Brimmer', + 'Swoboda', + 'Pandya', + 'Canton', + 'Magnus', + 'Draughn', + 'Dilts', + 'Tauber', + 'Vandegrift', + 'Rene', + 'Cousineau', + 'Joo', + 'Pimental', + 'Carpentier', + 'Eager', + 'Cumberland', + 'Eastridge', + 'Moberly', + 'Erhardt', + 'Meldrum', + 'Degennaro', + 'Desanto', + 'Manahan', + 'Gowdy', + 'Popham', + 'Mee', + 'Kinslow', + 'Harned', + 'Cartee', + 'Raiford', + 'Henrichs', + 'Maffei', + 'Seamans', + 'Heckel', + 'Toll', + 'Milian', + 'Mabrey', + 'Dall', + 'Lanford', + 'Carew', + 'Bascom', + 'Christofferson', + 'Hadfield', + 'Ferber', + 'Mestas', + 'Leith', + 'Abston', + 'Cuddy', + 'Svendsen', + 'Cowling', + 'Segars', + 'Nalls', + 'Hofstetter', + 'Badgley', + 'Mccaffery', + 'Burner', + 'Laymon', + 'Pinion', + 'Schooler', + 'Brun', + 'Aldaco', + 'Savarese', + 'Gravelle', + 'Belvin', + 'Brekke', + 'Dekker', + 'Ellefson', + 'Lurie', + 'Cassity', + 'Epperly', + 'Genova', + 'Dehn', + 'Fargo', + 'Vanderford', + 'Sine', + 'Horrell', + 'Napoleon', + 'Kamm', + 'Riel', + 'Gerena', + 'Check', + 'Devane', + 'Grissett', + 'Brendel', + 'Weyant', + 'Basurto', + 'Coppinger', + 'Grosse', + 'Saeed', + 'Lunceford', + 'Washam', + 'Benard', + 'Eastham', + 'Holleran', + 'Kiesel', + 'Risch', + 'Mccullen', + 'Vizcaino', + 'Fullen', + 'Westbrooks', + 'Babich', + 'Mauch', + 'Hensler', + 'Bryner', + 'Phillippi', + 'Santistevan', + 'Jalbert', + 'Vanorden', + 'Brantner', + 'Mcgrail', + 'Rustin', + 'Lebaron', + 'Genao', + 'Quast', + 'Hamburg', + 'Mensah', + 'Heckler', + 'Popa', + 'Mantooth', + 'Hargreaves', + 'Jury', + 'Seiber', + 'Calton', + 'Lafreniere', + 'Starbuck', + 'Gow', + 'Veazey', + 'Kneeland', + 'Woodberry', + 'Vallone', + 'Sutcliffe', + 'Loh', + 'Wiltse', + 'Choudhury', + 'Rollo', + 'Bjerke', + 'Huffstetler', + 'Ogren', + 'Legere', + 'Wilmer', + 'Conboy', + 'Pressler', + 'Hon', + 'Monger', + 'Devos', + 'Houtz', + 'Shurtleff', + 'Sedlak', + 'Carolan', + 'Luc', + 'Immel', + 'Guizar', + 'Kron', + 'Lusby', + 'Whitsett', + 'Pryce', + 'Mengel', + 'Youngberg', + 'Kluge', + 'Thrush', + 'Wilsey', + 'Santee', + 'Braham', + 'Palmeri', + 'Cousino', + 'Willits', + 'Gram', + 'Dearmond', + 'Fonville', + 'Sabatini', + 'Nehring', + 'Henne', + 'Prager', + 'Mederos', + 'Schuldt', + 'Weisz', + 'Mccart', + 'Warriner', + 'Bartelt', + 'Dimond', + 'Mccubbin', + 'Say', + 'Mickel', + 'Bracamonte', + 'Volkman', + 'Brindle', + 'Bitter', + 'Dickie', + 'Inge', + 'Brinegar', + 'Lerman', + 'Bohan', + 'Rondon', + 'Dilbeck', + 'Rumbaugh', + 'Simard', + 'Berke', + 'Ealey', + 'Knauer', + 'Michalek', + 'Smolinski', + 'Wurster', + 'Zullo', + 'Nott', + 'Claar', + 'Mayor', + 'Moir', + 'Hubbert', + 'Hankerson', + 'Mok', + 'Simko', + 'Mumm', + 'Sheely', + 'Abramowitz', + 'Pusateri', + 'Boomer', + 'Chappelle', + 'Demery', + 'Coniglio', + 'Asay', + 'Nova', + 'Biel', + 'Delancey', + 'Tocco', + 'Tant', + 'Melin', + 'Lacoste', + 'Derrico', + 'Stacks', + 'Watley', + 'Stoneking', + 'Westrick', + 'Pons', + 'Malm', + 'Parekh', + 'Loop', + 'Kitt', + 'Crisostomo', + 'Ecklund', + 'Tollison', + 'Dziedzic', + 'Pillsbury', + 'Baumer', + 'Matsuda', + 'Jeon', + 'Foye', + 'Peltz', + 'Candela', + 'Levey', + 'Organ', + 'Hathorn', + 'Galeano', + 'Nies', + 'Cabezas', + 'Barras', + 'Pier', + 'Truss', + 'Leist', + 'Lheureux', + 'Nakano', + 'Ladwig', + 'Grunwald', + 'Centers', + 'Sherrard', + 'Morais', + 'Juhl', + 'Ivers', + 'Dunfee', + 'Jolliff', + 'Breeze', + 'Tapper', + 'Goodridge', + 'Kelliher', + 'Finck', + 'Roose', + 'Gauvin', + 'Coil', + 'Pounders', + 'Lobb', + 'Stalcup', + 'Swanner', + 'Boivin', + 'Neer', + 'Laxton', + 'Pai', + 'Postma', + 'Janus', + 'Didier', + 'Engleman', + 'League', + 'Fray', + 'Aguillon', + 'Richins', + 'Tolar', + 'Criner', + 'Rowlands', + 'Verdi', + 'Utt', + 'Winders', + 'Turbeville', + 'Rada', + 'Mcnichols', + 'Boddy', + 'Binford', + 'Amey', + 'Schultze', + 'Sontag', + 'Saleem', + 'Przybylski', + 'Vanderlinden', + 'Vanfossen', + 'Longacre', + 'Heasley', + 'Southwell', + 'Decesare', + 'Munch', + 'Minix', + 'Hymes', + 'Klopp', + 'Militello', + 'Schuessler', + 'Velazco', + 'Jurek', + 'Claycomb', + 'Diemer', + 'Roser', + 'Huse', + 'Perkinson', + 'Musa', + 'Leavy', + 'Seidman', + 'Vroman', + 'Stalter', + 'Grieve', + 'Aron', + 'Purdie', + 'Dusek', + 'Rago', + 'Shepler', + 'Leopard', + 'Araya', + 'Rutt', + 'Voth', + 'Hittle', + 'Husain', + 'Gratton', + 'Seigler', + 'Coppedge', + 'Nicastro', + 'Fitzgibbon', + 'Sosebee', + 'Tank', + 'Troche', + 'Delph', + 'Ryland', + 'Mazzella', + 'Rai', + 'Strecker', + 'Epp', + 'Clower', + 'Porche', + 'Gelman', + 'Herrman', + 'Balser', + 'Tosh', + 'Bonn', + 'Cerrato', + 'Varley', + 'Dingess', + 'Goodspeed', + 'Boller', + 'Heimann', + 'Gottfried', + 'Super', + 'Falzone', + 'Bizzell', + 'Litwin', + 'Ji', + 'Rogowski', + 'Tindle', + 'Hoye', + 'Balfour', + 'Focht', + 'Manz', + 'Stender', + 'Sutterfield', + 'Bayes', + 'Mullings', + 'Dockter', + 'Figueiredo', + 'Kepner', + 'Posadas', + 'Nettleton', + 'Ruder', + 'Younce', + 'Flanary', + 'Scotti', + 'Bayliss', + 'Tandy', + 'Henrickson', + 'Volker', + 'Letts', + 'Joines', + 'Fewell', + 'Wherry', + 'Stelzer', + 'Stever', + 'Viator', + 'Catt', + 'Jeffords', + 'Guerriero', + 'Milby', + 'Jozwiak', + 'Slawson', + 'Portwood', + 'Billie', + 'Borunda', + 'Chinchilla', + 'Papadopoulos', + 'Lohse', + 'Mantz', + 'Gabriele', + 'Hosford', + 'Kohut', + 'Tardiff', + 'Puma', + 'Bodin', + 'Hodgins', + 'Boon', + 'Golightly', + 'Bogert', + 'Abdi', + 'Wigfall', + 'Fleischmann', + 'Nease', + 'Rayborn', + 'Zigler', + 'Reimann', + 'Malagon', + 'Puls', + 'Grogg', + 'Drinkwater', + 'Dacus', + 'Mcfee', + 'Domino', + 'Harjo', + 'Pascarella', + 'Spengler', + 'Copple', + 'Rollings', + 'Brew', + 'Brabham', + 'Nordquist', + 'Emig', + 'Riggio', + 'Sanson', + 'Gerardo', + 'Pereda', + 'Renken', + 'Stickley', + 'Milliron', + 'Rolling', + 'Hollie', + 'Biondi', + 'Fluharty', + 'Magyar', + 'Balsamo', + 'Imler', + 'Hanlin', + 'Dycus', + 'Kirkley', + 'Wimberley', + 'Finan', + 'Kulkarni', + 'Morreale', + 'Briner', + 'Pelzer', + 'Bouie', + 'Fenstermaker', + 'Gimenez', + 'Labella', + 'Scherrer', + 'Holzman', + 'Winer', + 'Wrigley', + 'Leighty', + 'Liptak', + 'Chamness', + 'Franko', + 'Arwood', + 'Tiner', + 'Schoenberger', + 'Gear', + 'Hereford', + 'Slezak', + 'Longfellow', + 'Cull', + 'Brashears', + 'Clear', + 'Zielke', + 'Arden', + 'Bonneau', + 'Muck', + 'Tarvin', + 'Beran', + 'Coulombe', + 'Toothman', + 'Ghosh', + 'Mcguirk', + 'Pinero', + 'Ruan', + 'Gartman', + 'Peed', + 'Cassano', + 'Forcier', + 'Haque', + 'Veatch', + 'Fodor', + 'Wetherington', + 'Barrette', + 'Bottorff', + 'Holmstrom', + 'Honda', + 'Kopecky', + 'Loaiza', + 'Castelan', + 'Haydon', + 'Lamotte', + 'Mutchler', + 'Mahmoud', + 'Gleaton', + 'Rebollar', + 'Moctezuma', + 'Tannehill', + 'Bernardino', + 'Walrath', + 'Adcox', + 'Heidt', + 'Rakowski', + 'Soza', + 'Limas', + 'Wysong', + 'Mannix', + 'Pattillo', + 'Corner', + 'Kuang', + 'Loflin', + 'Ledger', + 'Ivery', + 'Likens', + 'Mctaggart', + 'Hartin', + 'Prange', + 'Stenzel', + 'Shadle', + 'Karn', + 'Duplantis', + 'Garibaldi', + 'Batty', + 'Goulart', + 'Ranck', + 'Beekman', + 'Nicolosi', + 'Arizmendi', + 'Donoho', + 'Drewry', + 'Lenihan', + 'Spatz', + 'Wible', + 'Dimmick', + 'Stelter', + 'Seyler', + 'Stringfield', + 'Bonaparte', + 'Dematteo', + 'Petrey', + 'Bellino', + 'Cavaliere', + 'Thaler', + 'Heiner', + 'Lillis', + 'Hammes', + 'Rainbolt', + 'Hillyard', + 'Farnum', + 'Overmyer', + 'Replogle', + 'Sclafani', + 'Audet', + 'Santa', + 'Hollen', + 'Lineberger', + 'Bonnet', + 'Caples', + 'Dahlen', + 'Ruggieri', + 'Keppler', + 'Ryman', + 'Copas', + 'Lyda', + 'Pusey', + 'Bostrom', + 'Patnode', + 'Richeson', + 'Hamil', + 'Wyss', + 'Mcadam', + 'Dennett', + 'Lever', + 'Drinkard', + 'Ohl', + 'Restivo', + 'Vyas', + 'Moyle', + 'Blauvelt', + 'Gregson', + 'Scull', + 'Verret', + 'Stines', + 'Forsman', + 'Gehman', + 'Watrous', + 'Gunnell', + 'Choice', + 'Castaldo', + 'Pietrzak', + 'Goodsell', + 'Klima', + 'Stratman', + 'Foutz', + 'Massingill', + 'Huneycutt', + 'Zellmer', + 'Tefft', + 'Hamblen', + 'Baggs', + 'Mcgarity', + 'Alfieri', + 'Stetler', + 'Hershman', + 'Fuerst', + 'Granda', + 'Villafane', + 'Stocking', + 'Laguerre', + 'Salvato', + 'Mcniel', + 'Trim', + 'Goldston', + 'Tannenbaum', + 'Laforge', + 'Hawker', + 'Innis', + 'Rasheed', + 'Marbury', + 'Jules', + 'Harpster', + 'Hruska', + 'Mancillas', + 'Ruck', + 'Schloss', + 'Shy', + 'Leming', + 'Eich', + 'Allain', + 'Premo', + 'Goodner', + 'Karlin', + 'Natoli', + 'Sinn', + 'Althouse', + 'Bodiford', + 'Krishnan', + 'Snedeker', + 'Weigle', + 'Blohm', + 'Renwick', + 'Menzies', + 'Stonebraker', + 'Brunetti', + 'Crompton', + 'Hucks', + 'Maharaj', + 'Bangert', + 'Hepp', + 'Kammer', + 'Sutliff', + 'Doyon', + 'Hutsell', + 'Cumbie', + 'Dibiase', + 'Linke', + 'Sapienza', + 'Sprayberry', + 'Sundstrom', + 'Vanbeek', + 'Ewart', + 'Erlandson', + 'Knutsen', + 'Nicolai', + 'Oros', + 'Almquist', + 'Tedrow', + 'Diebold', + 'Bellman', + 'Sherrer', + 'Ehret', + 'Ota', + 'Seman', + 'Folse', + 'Amy', + 'Mcateer', + 'Steinhauer', + 'Vannatta', + 'Holle', + 'Carreras', + 'Anger', + 'Clinkscales', + 'Castiglione', + 'Zakrzewski', + 'Principe', + 'Artman', + 'Waiters', + 'Tarbox', + 'Sippel', + 'Belz', + 'Joachim', + 'Pipkins', + 'Peterkin', + 'Abalos', + 'Flock', + 'Brochu', + 'Tobler', + 'Mckinnis', + 'Gatson', + 'Cronan', + 'Manthey', + 'Oberholtzer', + 'Schiltz', + 'Skowronski', + 'Matute', + 'Castonguay', + 'Bechard', + 'Drees', + 'Carte', + 'Baysinger', + 'Kees', + 'Steve', + 'Ratchford', + 'Clopton', + 'Heimbach', + 'Selig', + 'Peavey', + 'Sidney', + 'Hilliker', + 'Oehler', + 'Essig', + 'Ownby', + 'Huling', + 'Aylward', + 'Matzke', + 'Mikkelsen', + 'Vandam', + 'Rodden', + 'Plunk', + 'Mcdonell', + 'Buechler', + 'Dahm', + 'Tarlton', + 'Funches', + 'Alvidrez', + 'Padua', + 'Pingel', + 'Cid', + 'Mcburney', + 'Brunton', + 'Dwight', + 'Bucio', + 'Schiffer', + 'Dyal', + 'Cyphers', + 'Gildea', + 'Wengerd', + 'Lappin', + 'Longwell', + 'Basil', + 'Acklin', + 'Cancino', + 'Kalina', + 'Tynan', + 'Raasch', + 'Fleener', + 'Dunmire', + 'Gent', + 'Cruickshank', + 'Baltimore', + 'Shum', + 'Vanpatten', + 'Costilla', + 'Grimshaw', + 'Loar', + 'Royse', + 'Amon', + 'Amendola', + 'Mcgonagle', + 'Alm', + 'Hausmann', + 'Heitzman', + 'Mailloux', + 'Brault', + 'Capra', + 'Levis', + 'Barillas', + 'Quandt', + 'Fedele', + 'Chittenden', + 'Cheesman', + 'Wildes', + 'Bolan', + 'Metoyer', + 'Ciccarelli', + 'Melara', + 'Gano', + 'Janowski', + 'Magoon', + 'Kuster', + 'Ofarrell', + 'Joplin', + 'Cannella', + 'Middendorf', + 'Putz', + 'Saephan', + 'Sieg', + 'Lainez', + 'Roten', + 'Buras', + 'Nock', + 'Manke', + 'Hymel', + 'Devaughn', + 'Braverman', + 'Fleisher', + 'Persson', + 'Sandidge', + 'Corsi', + 'Torok', + 'Steinhoff', + 'Corby', + 'Shorey', + 'Wooton', + 'Estell', + 'Bolander', + 'Vivar', + 'Cuesta', + 'Renick', + 'Isler', + 'Caprio', + 'Crissman', + 'Wann', + 'Matchett', + 'Calahan', + 'Escareno', + 'Liguori', + 'Helt', + 'Boner', + 'Luper', + 'Hoppes', + 'Ingold', + 'Gilleland', + 'Saathoff', + 'Szczepanski', + 'Yockey', + 'Veith', + 'Wasser', + 'Denniston', + 'Fretwell', + 'Goetsch', + 'Havel', + 'Banach', + 'Schaal', + 'Nisbet', + 'Depaul', + 'Escalona', + 'Gammons', + 'Schmelzer', + 'Wehrle', + 'Guglielmo', + 'Oberlander', + 'Wolski', + 'Dimick', + 'Rebello', + 'Braunstein', + 'Vanderveen', + 'Saini', + 'Meiners', + 'Metheny', + 'Schommer', + 'Kissell', + 'Burgoyne', + 'Walmsley', + 'Parmley', + 'Arthurs', + 'Worsley', + 'Hulme', + 'Campisi', + 'Parvin', + 'Ogawa', + 'Coder', + 'Gardener', + 'Taplin', + 'Nuzzo', + 'Linthicum', + 'Rosenstein', + 'Simoneau', + 'Preble', + 'Chae', + 'Nealon', + 'Stonecipher', + 'Medders', + 'Bencomo', + 'Durazo', + 'Scotto', + 'Klem', + 'Corman', + 'Byard', + 'Evan', + 'Dengler', + 'Kohls', + 'Seidler', + 'Clute', + 'Nebel', + 'Hohl', + 'Younker', + 'Parkerson', + 'Pullins', + 'Sweeting', + 'Wiersma', + 'Callanan', + 'Lisk', + 'Fassett', + 'Alloway', + 'Lafever', + 'Ollis', + 'Gracey', + 'Tune', + 'Ester', + 'Weingarten', + 'Swigart', + 'Frew', + 'Conkle', + 'Mendelsohn', + 'Belliveau', + 'Bacher', + 'Coto', + 'Ro', + 'Lipson', + 'Standard', + 'Hoerner', + 'Moldenhauer', + 'Trivette', + 'Colligan', + 'Cacho', + 'Emrich', + 'Condit', + 'Styer', + 'Paramore', + 'Cheramie', + 'Sprenger', + 'Kreps', + 'Curd', + 'Josephs', + 'Bruch', + 'Villano', + 'Banh', + 'Kennison', + 'Hilson', + 'Gathers', + 'Weinman', + 'Brickley', + 'Jetton', + 'Munford', + 'Charboneau', + 'Dittrich', + 'Boysen', + 'Newbury', + 'Hayner', + 'Pfau', + 'Wegman', + 'Eure', + 'Heinrichs', + 'Kresge', + 'Klepper', + 'Yohn', + 'Bergan', + 'Spells', + 'Reisman', + 'Schiffman', + 'Napoles', + 'Banegas', + 'Landman', + 'Hallenbeck', + 'Sever', + 'Hole', + 'Bown', + 'Barnaby', + 'Junior', + 'Deloatch', + 'Secrist', + 'Steigerwald', + 'Kallas', + 'Littell', + 'Clinger', + 'Rehman', + 'Cothern', + 'Class', + 'Sabino', + 'Mckain', + 'Werts', + 'Asmus', + 'Fierros', + 'Heffelfinger', + 'Henthorn', + 'Weirich', + 'Ashbrook', + 'Alber', + 'Calles', + 'Bragdon', + 'Gerow', + 'Hanger', + 'Machen', + 'Patt', + 'Harada', + 'Parmelee', + 'Decaro', + 'Sons', + 'Tindal', + 'Lubbers', + 'Ferland', + 'Bruni', + 'Boyes', + 'Danis', + 'Tigner', + 'Anzaldua', + 'Gaxiola', + 'Iacono', + 'Lizama', + 'Forbis', + 'Mcguffin', + 'Greenhill', + 'Baity', + 'Welcome', + 'Lauzon', + 'Nicodemus', + 'Rabin', + 'Teegarden', + 'Yunker', + 'Salim', + 'Dews', + 'Schueller', + 'Stogsdill', + 'Minch', + 'Ellett', + 'Villafana', + 'Shan', + 'Boler', + 'Kast', + 'Shrout', + 'Taff', + 'Willcox', + 'Kahan', + 'Gerth', + 'Sabella', + 'Procopio', + 'Vedder', + 'Heeter', + 'Banes', + 'Alaimo', + 'Raza', + 'Starkweather', + 'Mutter', + 'Manners', + 'Bohanan', + 'Virden', + 'Booze', + 'Wimbush', + 'Eickhoff', + 'Hankinson', + 'Swilley', + 'Killinger', + 'Labar', + 'Tallant', + 'Rosin', + 'Hillhouse', + 'Labarre', + 'Ryans', + 'Heintzelman', + 'Cottone', + 'Bickerstaff', + 'Westley', + 'Rotter', + 'Hey', + 'Dinapoli', + 'Lohmann', + 'Reetz', + 'Vences', + 'Mckiernan', + 'Thornsberry', + 'Hofman', + 'Murrieta', + 'Vanwormer', + 'Sen', + 'Pinheiro', + 'Jaco', + 'Maner', + 'Crosley', + 'Rogalski', + 'Hollandsworth', + 'Hinze', + 'Seawright', + 'Brosius', + 'Keehn', + 'Sweetman', + 'Vicknair', + 'Casler', + 'Hagopian', + 'Westhoff', + 'Lipari', + 'Poll', + 'Lintz', + 'Rosinski', + 'Henrie', + 'Crystal', + 'Wroten', + 'Perla', + 'Zawacki', + 'Mckillip', + 'Dorantes', + 'Wallick', + 'Hoots', + 'Witty', + 'Granata', + 'Janicki', + 'Petroff', + 'Emert', + 'Raskin', + 'Picou', + 'Caple', + 'Mcelyea', + 'Blackmer', + 'Busbee', + 'Pettengill', + 'Newberg', + 'Nickle', + 'Hedman', + 'Flavin', + 'Forgione', + 'Wachtel', + 'Meader', + 'Nale', + 'Westby', + 'Pulaski', + 'Schupp', + 'Troutt', + 'Fishburn', + 'Laprade', + 'Dealba', + 'Waymire', + 'Stiefel', + 'Carner', + 'Fallin', + 'Belin', + 'Anand', + 'Lesh', + 'Okada', + 'Whipkey', + 'Mang', + 'Harvill', + 'Caver', + 'Moskal', + 'Schaible', + 'Vandeusen', + 'Boyko', + 'Matteo', + 'Crisler', + 'Capehart', + 'Heide', + 'Holdsworth', + 'Mcdonagh', + 'Burlison', + 'Beshears', + 'Gills', + 'Cowger', + 'Gendreau', + 'Goering', + 'Hewes', + 'Whelchel', + 'Kier', + 'Tramel', + 'Mcsherry', + 'Morita', + 'Cissell', + 'Knaus', + 'Vangilder', + 'Karsten', + 'Linscott', + 'Ratner', + 'Catoe', + 'Scriven', + 'Gerstner', + 'Brobst', + 'Normandin', + 'Piasecki', + 'Tamura', + 'Balboa', + 'Nathanson', + 'Huizenga', + 'Renard', + 'Deshazo', + 'Ethier', + 'Fabiano', + 'Quisenberry', + 'Mcbryde', + 'Palencia', + 'Scaglione', + 'Friese', + 'Laughter', + 'Houchins', + 'Loman', + 'Garden', + 'Cromartie', + 'Borgman', + 'Hoffpauir', + 'Choquette', + 'Jarrard', + 'Fernald', + 'Barranco', + 'Levering', + 'Ansell', + 'Perl', + 'Caudell', + 'Ewen', + 'Ohanlon', + 'Swofford', + 'Reasoner', + 'Grout', + 'Rising', + 'Buttram', + 'Vandenheuvel', + 'Imel', + 'Rearick', + 'Harn', + 'Sorrels', + 'Biggins', + 'Renda', + 'Norden', + 'Matula', + 'Walch', + 'Broad', + 'Stokley', + 'Gully', + 'Barrientes', + 'Chilcote', + 'Freel', + 'Lage', + 'Farner', + 'Rubel', + 'Demko', + 'Shao', + 'Cupples', + 'Holderman', + 'Dunnam', + 'Hughs', + 'Foskey', + 'Darst', + 'Greenblatt', + 'Shiner', + 'Brasfield', + 'Simeon', + 'Maser', + 'Lacayo', + 'Priestley', + 'Pleasants', + 'Howse', + 'Iyer', + 'Perreira', + 'Baillargeon', + 'Revilla', + 'Yarger', + 'Gries', + 'Sheeley', + 'Prim', + 'Picazo', + 'Heinlein', + 'Merola', + 'Malhotra', + 'Wein', + 'Mchone', + 'Valliere', + 'Minner', + 'Blumer', + 'Hasse', + 'Kuester', + 'Landi', + 'Suits', + 'Primeaux', + 'Jarnagin', + 'Galle', + 'Greenlaw', + 'Qiu', + 'Lamarche', + 'Acheson', + 'Gothard', + 'Mendivil', + 'Bombard', + 'Mcquillen', + 'Munden', + 'Herzberg', + 'Ros', + 'Umstead', + 'Levins', + 'Pellegrin', + 'Castagna', + 'Alvord', + 'Huckins', + 'Wagnon', + 'Plemons', + 'Dolin', + 'Garica', + 'Lyttle', + 'Bazile', + 'Astudillo', + 'Gover', + 'Galati', + 'Seager', + 'Girardi', + 'Freels', + 'Bramblett', + 'Brancato', + 'Reppert', + 'Saetern', + 'Puig', + 'Prettyman', + 'Chagnon', + 'Heavner', + 'Schlichting', + 'Saladino', + 'Stall', + 'Loiselle', + 'Sedano', + 'Panos', + 'Heilig', + 'Ridgley', + 'Basilio', + 'Rapoza', + 'Furrow', + 'Oliveras', + 'Cordray', + 'Strausbaugh', + 'Culhane', + 'Iraheta', + 'Lamantia', + 'Shires', + 'Wilding', + 'Obanion', + 'Easterwood', + 'Hearns', + 'Manske', + 'Spiess', + 'Eckley', + 'Wootton', + 'Enochs', + 'Cheatwood', + 'Woodfin', + 'Akridge', + 'Mattocks', + 'Mcdougle', + 'Legette', + 'Neher', + 'Rhoton', + 'Vartanian', + 'Dunkel', + 'Wehmeyer', + 'Foutch', + 'Dille', + 'Halle', + 'Lowden', + 'Olesen', + 'Chace', + 'Hasbrouck', + 'Lesage', + 'Pappalardo', + 'Shinkle', + 'Ishii', + 'Peralez', + 'Gabler', + 'Fichter', + 'Mcnicholas', + 'Moshier', + 'Barbeau', + 'Bossert', + 'Trivett', + 'Bamford', + 'Lauterbach', + 'Gossman', + 'Epling', + 'Welk', + 'Daub', + 'Squier', + 'Dicus', + 'Siller', + 'Romaine', + 'Meriwether', + 'Bordner', + 'Baden', + 'Hagins', + 'Sica', + 'Mullane', + 'Jurgensen', + 'Tien', + 'Gertz', + 'Touchstone', + 'Bones', + 'Kimmons', + 'Prisco', + 'Kaser', + 'Drysdale', + 'Jelks', + 'Cerrone', + 'Wolfenbarger', + 'Deckert', + 'Ganley', + 'Fleeman', + 'Cubbage', + 'Woodie', + 'Schwan', + 'Siefert', + 'Rizvi', + 'Heier', + 'Khanna', + 'Leet', + 'Gratz', + 'Mullan', + 'Moorefield', + 'Fishback', + 'Whittenburg', + 'Casson', + 'Statham', + 'Red', + 'Coldiron', + 'Keplinger', + 'Reichman', + 'Brier', + 'Vavra', + 'Housman', + 'Kitson', + 'Fekete', + 'Rotella', + 'Onofre', + 'Orvis', + 'Beutler', + 'Cadwallader', + 'Gabor', + 'Emmanuel', + 'Moretz', + 'Suniga', + 'Mcmath', + 'Kinlaw', + 'Beringer', + 'Gaudreau', + 'Lirette', + 'Drye', + 'Oubre', + 'Gardella', + 'Reigle', + 'Zubia', + 'Mccardle', + 'Ambler', + 'Lucius', + 'Fizer', + 'Hilley', + 'Fischbach', + 'Borelli', + 'Gies', + 'Barks', + 'Sheard', + 'Hammontree', + 'Hogle', + 'Fagg', + 'Buitron', + 'Eiler', + 'Grandstaff', + 'Hank', + 'Wark', + 'Decoteau', + 'Depina', + 'Clabaugh', + 'Desiderio', + 'Kuchta', + 'Trang', + 'Abril', + 'Smathers', + 'Kaspar', + 'Melia', + 'Sandman', + 'Maltese', + 'Mccasland', + 'Rayl', + 'Meche', + 'Wiggin', + 'Saint', + 'Dorner', + 'Columbus', + 'Boatner', + 'Fresquez', + 'Sykora', + 'Shriner', + 'Drumheller', + 'Mahony', + 'Redinger', + 'Radloff', + 'Mitts', + 'Casperson', + 'Gammill', + 'Moraga', + 'Baratta', + 'Tow', + 'Ocon', + 'Cruce', + 'Bohannan', + 'Hurtt', + 'Mose', + 'Caines', + 'Heisey', + 'Pitcock', + 'Swiderski', + 'Shu', + 'Buda', + 'Whidden', + 'Busick', + 'Simas', + 'Croley', + 'Morrisey', + 'Saulsberry', + 'Crudup', + 'Bongiorno', + 'Beem', + 'Bunner', + 'Rosemond', + 'Freire', + 'Casado', + 'Merideth', + 'Selden', + 'Lamarre', + 'Fullwood', + 'Hartig', + 'Kerlin', + 'Lebowitz', + 'Kibbe', + 'Fannon', + 'Hotz', + 'Yerkes', + 'Re', + 'Waddington', + 'Akbar', + 'Baek', + 'Closson', + 'Miers', + 'Bonomo', + 'Wetherbee', + 'Taranto', + 'Henslee', + 'Bartle', + 'Hilger', + 'Asaro', + 'Mahr', + 'Strozier', + 'Agudelo', + 'Kulick', + 'Skoglund', + 'Yamasaki', + 'Schlemmer', + 'Hefley', + 'Waxman', + 'Radley', + 'Sanderlin', + 'Arispe', + 'Galang', + 'Morejon', + 'Stich', + 'Cesario', + 'Silvis', + 'Gurganus', + 'Shofner', + 'Funderburg', + 'Reddish', + 'Rybak', + 'Dingler', + 'Mankin', + 'Renna', + 'Alban', + 'Mckittrick', + 'Lippman', + 'Brenton', + 'Liebman', + 'Santillo', + 'Crigger', + 'Riney', + 'Mccraney', + 'Kluck', + 'Sosnowski', + 'Anspach', + 'Bourdon', + 'Modi', + 'Heer', + 'Mastroianni', + 'Musial', + 'Whiteaker', + 'Summa', + 'Herber', + 'Roselli', + 'Orris', + 'Bert', + 'Dedmon', + 'Kelson', + 'Paone', + 'Barstow', + 'Gerst', + 'Bettinger', + 'Castner', + 'Penman', + 'Broaddus', + 'Ohman', + 'Villalon', + 'Carwile', + 'Fluellen', + 'Ort', + 'Bommarito', + 'Shuff', + 'Cannata', + 'Westgate', + 'Bien', + 'Driggs', + 'Maisonet', + 'Costin', + 'Raine', + 'Banton', + 'Buterbaugh', + 'Katzman', + 'Coreas', + 'Rosalez', + 'Gose', + 'Robie', + 'Winburn', + 'Glancy', + 'Hild', + 'Strock', + 'Umanzor', + 'Hoglund', + 'Kesner', + 'Lynam', + 'Swayze', + 'Grizzard', + 'Fettig', + 'Macko', + 'Schrum', + 'Sours', + 'Yonker', + 'Ebanks', + 'Chiodo', + 'Meaney', + 'Paras', + 'Struthers', + 'Sicard', + 'Leveille', + 'Beckstead', + 'Calero', + 'Fuhrmann', + 'Lybarger', + 'Capo', + 'Adolph', + 'Raabe', + 'Gran', + 'Borel', + 'Ary', + 'Charland', + 'Huh', + 'Steinert', + 'Stemple', + 'Groat', + 'Zang', + 'Nath', + 'Ogara', + 'Pecina', + 'Simoes', + 'Breece', + 'Nascimento', + 'Usry', + 'Gain', + 'Brassfield', + 'Lochner', + 'Pietsch', + 'Wechsler', + 'Sum', + 'Teneyck', + 'Pelt', + 'Burnley', + 'Renzi', + 'Mujica', + 'Profitt', + 'Body', + 'Debusk', + 'Robidoux', + 'Pruneda', + 'Pomerantz', + 'Gonyea', + 'Crosier', + 'Currence', + 'Newborn', + 'Tolleson', + 'Conlan', + 'Dunsmore', + 'Tansey', + 'Clinard', + 'Staudt', + 'Oppenheim', + 'Gossard', + 'Osbourne', + 'Gilyard', + 'Lucido', + 'Tonkin', + 'Mitzel', + 'Sola', + 'Palombo', + 'Duane', + 'Mac', + 'Kerry', + 'Stills', + 'Viveiros', + 'Stallman', + 'Moos', + 'Follis', + 'Maris', + 'Hollier', + 'Gundlach', + 'Moler', + 'Schweigert', + 'Chartrand', + 'Finkle', + 'Meese', + 'Nigh', + 'Amundsen', + 'Brocato', + 'Dreier', + 'Glessner', + 'Weibel', + 'Fritch', + 'Retherford', + 'Rahim', + 'Markert', + 'Ronk', + 'Olmeda', + 'Gosney', + 'Keathley', + 'Luby', + 'Harrill', + 'Dinges', + 'Rocheleau', + 'Meisel', + 'Farrer', + 'Lute', + 'Apel', + 'Pincus', + 'Maida', + 'Jimmerson', + 'Baltz', + 'Cuccia', + 'Heenan', + 'Thieme', + 'Zoeller', + 'Larocco', + 'Abdalla', + 'Classen', + 'Hassinger', + 'Filler', + 'Pidgeon', + 'Hanford', + 'Espy', + 'Goodlett', + 'Jone', + 'Ruggeri', + 'Lisi', + 'Spada', + 'Gerrard', + 'Allbritton', + 'Brazelton', + 'Boggan', + 'Dufault', + 'Espejo', + 'Bodkin', + 'Penix', + 'Dockins', + 'Rascoe', + 'Swarthout', + 'Tritt', + 'Gouin', + 'Lamberth', + 'Bourn', + 'Barnhouse', + 'Guzzo', + 'Netherton', + 'Zamarron', + 'Rosenberry', + 'Dahms', + 'Anwar', + 'Whitesides', + 'Tidmore', + 'Longstreet', + 'Claunch', + 'Ehrhart', + 'Hullinger', + 'Xia', + 'Heideman', + 'Nicklas', + 'Prins', + 'Soni', + 'Dominquez', + 'Vogelsang', + 'Pew', + 'Chess', + 'Simmerman', + 'Brunell', + 'Matthes', + 'Kinnison', + 'Cansler', + 'Weekly', + 'Eger', + 'Garabedian', + 'Milliman', + 'Severns', + 'Magnusson', + 'Fossum', + 'Salamon', + 'Vandoren', + 'Gillingham', + 'Charney', + 'Nokes', + 'Lamon', + 'Irick', + 'Okeeffe', + 'Zou', + 'Kott', + 'Quillin', + 'Friar', + 'Drummer', + 'Catchings', + 'Hamada', + 'Scheck', + 'Setser', + 'Gobble', + 'Condra', + 'Bowley', + 'Deschamps', + 'Sylva', + 'Bartolome', + 'Warfel', + 'Veltri', + 'Speers', + 'Butner', + 'Delorme', + 'Giesler', + 'Sonntag', + 'Wetherell', + 'Ohagan', + 'Torbert', + 'Grandberry', + 'Ronning', + 'Howser', + 'Soden', + 'Rasco', + 'Clauss', + 'Beland', + 'Nicola', + 'Justiniano', + 'Varnum', + 'Fergus', + 'Lazcano', + 'Sartori', + 'Carnley', + 'Lucarelli', + 'Bergh', + 'Wellborn', + 'Bow', + 'Longshore', + 'Marcel', + 'Sumlin', + 'Atilano', + 'Dostal', + 'Westendorf', + 'Stiver', + 'Morency', + 'Herrod', + 'Bologna', + 'Valiente', + 'Weinert', + 'Gaertner', + 'Prock', + 'Spangenberg', + 'Tineo', + 'Cosio', + 'Maass', + 'Rist', + 'Oatman', + 'Waguespack', + 'Cardiel', + 'Grate', + 'Behrends', + 'Linger', + 'Pozo', + 'Scoggin', + 'Jenkinson', + 'Ake', + 'Redick', + 'Bonacci', + 'Rivet', + 'Declue', + 'Swing', + 'Chopra', + 'Leib', + 'Wallner', + 'Grimmer', + 'Wilmes', + 'Pirkle', + 'Stanhope', + 'Knop', + 'Culotta', + 'Dipaola', + 'Hipolito', + 'Gerling', + 'Sennett', + 'Fulghum', + 'Grothe', + 'Krout', + 'Onorato', + 'Donis', + 'Winbush', + 'Aoki', + 'Buscher', + 'Jarquin', + 'Lemanski', + 'Mcgrane', + 'Tardif', + 'Segundo', + 'Caba', + 'Sease', + 'Blinn', + 'Losee', + 'Kirschbaum', + 'Baskett', + 'Knights', + 'Goudeau', + 'Grondin', + 'Harting', + 'Szewczyk', + 'Wieder', + 'Conatser', + 'Romanelli', + 'Freshour', + 'Brizendine', + 'Rolen', + 'Guynn', + 'Laforest', + 'Doris', + 'Sandridge', + 'Dublin', + 'Blancas', + 'Duryea', + 'Naik', + 'Paradiso', + 'Scheele', + 'Westra', + 'Hassel', + 'Bertucci', + 'Fansler', + 'Flohr', + 'Solt', + 'Suess', + 'Keiper', + 'Downard', + 'Ivester', + 'Darley', + 'Seales', + 'Kolesar', + 'Overbeck', + 'Subramanian', + 'Panter', + 'Parshall', + 'Stannard', + 'Gravley', + 'Dhaliwal', + 'Shippy', + 'Dolphin', + 'Lepper', + 'Gorby', + 'Delmonte', + 'Piccirillo', + 'Besaw', + 'Alligood', + 'Rhymes', + 'Eisenman', + 'Deveau', + 'Tilden', + 'Girton', + 'Buser', + 'Rentschler', + 'Sopko', + 'Uriostegui', + 'Wasko', + 'Noffsinger', + 'Barkman', + 'Dyck', + 'Ferrero', + 'Kiehl', + 'Leffel', + 'Rybicki', + 'Hedstrom', + 'Bracamontes', + 'Zebrowski', + 'Blundell', + 'Brightman', + 'Hegwood', + 'Beecham', + 'Kolbe', + 'Bucy', + 'Bondi', + 'Borgen', + 'Gibbens', + 'Pullman', + 'Letcher', + 'Ferebee', + 'Kitterman', + 'Seefeldt', + 'Upham', + 'Thiede', + 'Bolster', + 'Bastin', + 'Bondy', + 'Mershon', + 'Nickson', + 'Drozd', + 'Schroyer', + 'Mcmenamin', + 'Reith', + 'Lovin', + 'San', + 'Henegar', + 'Haislip', + 'Barco', + 'Arter', + 'Malecki', + 'Teeple', + 'Walpole', + 'Feil', + 'Neitzel', + 'Ostler', + 'Parmar', + 'Vinton', + 'Jan', + 'Weldy', + 'Etherton', + 'Joya', + 'Saliba', + 'Schnur', + 'Belles', + 'Mcgeorge', + 'Olden', + 'Rarick', + 'Worrall', + 'Degen', + 'Froman', + 'Odowd', + 'Einhorn', + 'Fimbres', + 'Maresca', + 'Rocker', + 'Arend', + 'Biermann', + 'Guimond', + 'Mcgurk', + 'Goll', + 'Santilli', + 'Hadlock', + 'Teer', + 'Dillion', + 'Jorden', + 'Honore', + 'Bromberg', + 'Stoneman', + 'Blossom', + 'Guzik', + 'Stockstill', + 'Wax', + 'Anello', + 'Blasko', + 'Frese', + 'Berthold', + 'Morefield', + 'Baptist', + 'Legault', + 'Bouffard', + 'Bebout', + 'Darnall', + 'Buscemi', + 'Buentello', + 'Scroggs', + 'Gatton', + 'Turnquist', + 'Lucht', + 'Remick', + 'Godlewski', + 'Bradt', + 'Waldorf', + 'Zeringue', + 'Rowen', + 'Mowbray', + 'Parkey', + 'Engram', + 'Mazzarella', + 'Kirkbride', + 'Gridley', + 'Kaster', + 'Lorenzana', + 'Wareham', + 'Star', + 'Marshburn', + 'Everman', + 'Wolfram', + 'Zick', + 'Hyun', + 'Yerger', + 'Baham', + 'Gebhard', + 'Ruf', + 'Suchy', + 'Tieman', + 'Wenz', + 'Schiro', + 'Fout', + 'Abdo', + 'Hayter', + 'Cleaves', + 'Fritsche', + 'Meurer', + 'Riendeau', + 'Ventimiglia', + 'Cervera', + 'Mallow', + 'Allie', + 'Hanscom', + 'Viloria', + 'Dubon', + 'Leeson', + 'Ruffing', + 'Jonson', + 'Fenimore', + 'Gonzaga', + 'Schriver', + 'Traina', + 'Mecca', + 'Lantigua', + 'Baril', + 'Harford', + 'Bartow', + 'Asbell', + 'Rumley', + 'Brogden', + 'Derryberry', + 'Ketner', + 'Dakin', + 'Wass', + 'Fallis', + 'Wada', + 'Studdard', + 'Lecroy', + 'Fetty', + 'Nass', + 'Chute', + 'Parman', + 'Bevans', + 'Headen', + 'Hysell', + 'Merten', + 'Most', + 'Fuss', + 'Schrank', + 'Last', + 'Even', + 'Vaz', + 'Sifford', + 'Streets', + 'Claude', + 'Bronstein', + 'Sherburne', + 'Wadkins', + 'Gascon', + 'Seiter', + 'Steffan', + 'Cardozo', + 'Henricks', + 'Claflin', + 'Etzel', + 'Kulas', + 'Trinkle', + 'Ortegon', + 'Phaneuf', + 'Langworthy', + 'Barb', + 'Mazon', + 'Veney', + 'Redondo', + 'Tieu', + 'Laursen', + 'Nanez', + 'Votaw', + 'Walraven', + 'Abella', + 'Dsouza', + 'Bayley', + 'Townson', + 'Applebaum', + 'Mazzei', + 'Piche', + 'Rivenbark', + 'Urrea', + 'Dolph', + 'Bonifacio', + 'Shehan', + 'Glascock', + 'Verde', + 'Gadberry', + 'Trimm', + 'Dowe', + 'Khang', + 'Mulhall', + 'Selzer', + 'Raub', + 'Ore', + 'Copes', + 'Masuda', + 'Moscoso', + 'Zeitler', + 'Mollica', + 'Iler', + 'Leventhal', + 'Manders', + 'Prue', + 'Fergerson', + 'Brose', + 'Phu', + 'Debellis', + 'Haan', + 'Schoening', + 'Stager', + 'Demos', + 'Rumble', + 'Brunt', + 'Nivens', + 'Manigault', + 'Buendia', + 'Deschenes', + 'Wittmer', + 'Hamon', + 'Hentz', + 'Loud', + 'Oseguera', + 'Rayo', + 'Macfarland', + 'Mimms', + 'Grunewald', + 'Hartness', + 'Wynkoop', + 'Wallingford', + 'Juergens', + 'Meszaros', + 'Riehle', + 'Trego', + 'Neece', + 'Coggin', + 'Burrill', + 'Laurel', + 'Routt', + 'Rodger', + 'Krum', + 'Faulkenberry', + 'Labadie', + 'Hemming', + 'Fulp', + 'Jamal', + 'Deloney', + 'Fells', + 'Bohnert', + 'Kapadia', + 'Guill', + 'Coop', + 'Broadhurst', + 'Mccrimmon', + 'Bonfiglio', + 'Capetillo', + 'Chamorro', + 'Gargiulo', + 'Stoehr', + 'Schlecht', + 'Karlson', + 'Garten', + 'Remer', + 'Mebane', + 'Finnigan', + 'Bourdeau', + 'Espindola', + 'Shukla', + 'Petras', + 'Steinberger', + 'Casner', + 'Carico', + 'Seevers', + 'Westwood', + 'Hosea', + 'Mcphillips', + 'Nygren', + 'Wagaman', + 'Coghlan', + 'Sutherlin', + 'Sellman', + 'Bashore', + 'Mullican', + 'Stoneburner', + 'Montag', + 'Karst', + 'Murch', + 'Puffer', + 'Sabala', + 'Pauli', + 'Odonoghue', + 'Lassen', + 'Mattera', + 'Mcaninch', + 'Portugal', + 'Clingan', + 'Michener', + 'Munsell', + 'Streetman', + 'Harton', + 'Swarts', + 'Honig', + 'Jesus', + 'Rentas', + 'Trosper', + 'Coffield', + 'Burket', + 'Donaghy', + 'Byun', + 'Riess', + 'Mcqueary', + 'Stayton', + 'Ferron', + 'Wedding', + 'Tibbitts', + 'Frisbee', + 'Reinoso', + 'Lama', + 'Allyn', + 'Sheen', + 'Tyra', + 'Golder', + 'Veasey', + 'Schroth', + 'Kukla', + 'Narayan', + 'Vandemark', + 'Horace', + 'Kadlec', + 'Portnoy', + 'Reynosa', + 'Surprenant', + 'Savell', + 'Seagle', + 'Vandervort', + 'Eye', + 'Eccleston', + 'Blaise', + 'Glaspie', + 'Cressman', + 'Lahti', + 'Yocom', + 'Leppert', + 'Brendle', + 'Greenough', + 'Relyea', + 'Marinez', + 'Bouley', + 'Fincham', + 'Highley', + 'Goza', + 'Norrell', + 'Yusuf', + 'Ohm', + 'Thakkar', + 'Cosenza', + 'Efird', + 'Heger', + 'Dysart', + 'Mango', + 'Fitchett', + 'Kring', + 'Paolucci', + 'Menges', + 'Layden', + 'Mccleery', + 'Benko', + 'Sandor', + 'Blakney', + 'Zanders', + 'Gengler', + 'Fujita', + 'Huls', + 'Basquez', + 'Trepanier', + 'Spadaro', + 'Ankney', + 'Damiani', + 'Games', + 'Cherney', + 'Fitzsimons', + 'Dearmas', + 'Bonet', + 'Diem', + 'Shimp', + 'Agrawal', + 'Gaw', + 'Gahagan', + 'Fossett', + 'Kafka', + 'Dedios', + 'Coryell', + 'Bahe', + 'Wurm', + 'Wishart', + 'Dray', + 'Armer', + 'Khalid', + 'Gassaway', + 'Vawter', + 'Loew', + 'Coello', + 'Curren', + 'Gilder', + 'Letendre', + 'Sprecher', + 'Rexrode', + 'Minich', + 'Koepp', + 'Mulloy', + 'Bohman', + 'Gambrel', + 'Hackley', + 'Demasi', + 'Hoffert', + 'Kittredge', + 'Maltby', + 'Nyquist', + 'Schieber', + 'Kennell', + 'Calderwood', + 'Compean', + 'Romines', + 'Simonelli', + 'Pico', + 'Oda', + 'Holte', + 'Bate', + 'Learn', + 'Lowenstein', + 'Holtman', + 'Mingus', + 'Sessa', + 'Legendre', + 'Gerrish', + 'Schoenberg', + 'Liberman', + 'Mclachlan', + 'Higginson', + 'Vince', + 'Mallery', + 'Delamora', + 'Difranco', + 'Lein', + 'Haltom', + 'Dority', + 'Marcellus', + 'Heskett', + 'Harward', + 'Spinney', + 'Darwin', + 'Baylis', + 'Amodeo', + 'Schwandt', + 'Mcmorrow', + 'Foraker', + 'Fyfe', + 'Shingleton', + 'Blandon', + 'Waddy', + 'Ricca', + 'Scheffer', + 'Balliet', + 'Philipp', + 'Rish', + 'Hattaway', + 'Krejci', + 'Orduno', + 'Passarelli', + 'Skala', + 'Oram', + 'Raynes', + 'Hiett', + 'Tolan', + 'Kimbell', + 'Delara', + 'Farhat', + 'Kamps', + 'Mohney', + 'Escarcega', + 'Mell', + 'Mcquay', + 'Cannizzaro', + 'Deuel', + 'Losoya', + 'Goldin', + 'Zaidi', + 'Gillmore', + 'Buelow', + 'Maust', + 'Guerrera', + 'Bouck', + 'Bick', + 'Kelty', + 'Pines', + 'Braziel', + 'Bruening', + 'Frenzel', + 'Kenna', + 'Loria', + 'Koren', + 'Cornelio', + 'Poisson', + 'Raker', + 'Ptak', + 'Bohr', + 'Coury', + 'Failla', + 'Cipriani', + 'Delany', + 'Marmon', + 'Kinch', + 'Figgins', + 'Delfino', + 'Risser', + 'Hickox', + 'Fager', + 'Turpen', + 'Dalzell', + 'Falvey', + 'Leiker', + 'Mcgonigal', + 'Vaquera', + 'Weisser', + 'Viviano', + 'Shrock', + 'Minaya', + 'Chitty', + 'Costley', + 'Granberry', + 'Dimaria', + 'Roma', + 'Ortis', + 'Burnam', + 'Burruss', + 'Stoughton', + 'Cales', + 'Burrage', + 'Vanwagner', + 'Espada', + 'Mccuen', + 'Baize', + 'Pullum', + 'Gerrity', + 'Vicari', + 'Heuser', + 'Semler', + 'Fear', + 'Havener', + 'Kash', + 'Thibodaux', + 'Hadaway', + 'Smithwick', + 'Eisenhart', + 'Hodgin', + 'Cluck', + 'Godby', + 'Belli', + 'Demaree', + 'Beyers', + 'Jared', + 'Mall', + 'Defoe', + 'Chmura', + 'Hepworth', + 'Hintze', + 'Luk', + 'Vanriper', + 'Solari', + 'Atlas', + 'Outland', + 'Hanselman', + 'Scharff', + 'Rhein', + 'Milone', + 'Rochford', + 'Mynatt', + 'Lambdin', + 'Sandell', + 'Grounds', + 'Tabler', + 'Smartt', + 'Dejean', + 'Clayborne', + 'Vangorder', + 'Eastin', + 'Hiler', + 'Lisle', + 'Gramling', + 'Degarmo', + 'Malec', + 'Tinkham', + 'Vanauken', + 'Andrzejewski', + 'Rundell', + 'Happel', + 'Strine', + 'Koerber', + 'Haner', + 'Ashcroft', + 'Hille', + 'Cairo', + 'Upson', + 'Mooring', + 'Koury', + 'Vito', + 'Oberlin', + 'Christiano', + 'Redfearn', + 'Trower', + 'Hibbler', + 'Sumter', + 'Raftery', + 'Geise', + 'Wohl', + 'Gorney', + 'Peasley', + 'Heap', + 'Brazeal', + 'Mccleskey', + 'Yard', + 'Mcroy', + 'Amend', + 'Cutshaw', + 'Kazmierczak', + 'Strandberg', + 'Lasko', + 'Newlon', + 'File', + 'Bevill', + 'Silvera', + 'Arakaki', + 'Kelsch', + 'Ostendorf', + 'Cowie', + 'Hove', + 'Doles', + 'Bouvier', + 'Fecteau', + 'Hasegawa', + 'Paschke', + 'Taing', + 'Heldt', + 'Allaire', + 'Ochsner', + 'Giusti', + 'Reisner', + 'Swim', + 'Laidlaw', + 'Vanderbilt', + 'Atterberry', + 'Barthelemy', + 'Chalker', + 'Degregorio', + 'Mastro', + 'Patlan', + 'Gipe', + 'Roosa', + 'Filkins', + 'Styron', + 'Bryer', + 'Blackston', + 'Hagel', + 'Fralick', + 'Linhart', + 'Moura', + 'Pavia', + 'Pavao', + 'Furry', + 'Petrus', + 'Fairweather', + 'Blystone', + 'Co', + 'Divito', + 'Villicana', + 'Winch', + 'Tome', + 'Lanoue', + 'Biron', + 'Noell', + 'Mckeel', + 'Worthey', + 'Aten', + 'Eyer', + 'Zhen', + 'Tischler', + 'Luoma', + 'Opp', + 'Riggin', + 'Furness', + 'Wolbert', + 'Penning', + 'Draves', + 'Whitehill', + 'Dudgeon', + 'Kinkead', + 'Luca', + 'Rosell', + 'Macauley', + 'Goldner', + 'Ishikawa', + 'Kirchhoff', + 'Lamarca', + 'Miyashiro', + 'Weger', + 'Wuest', + 'Kreis', + 'Urbanek', + 'Palko', + 'Victorino', + 'Morado', + 'Burchette', + 'Holyfield', + 'Tulloch', + 'Twombly', + 'Munk', + 'Woolford', + 'Knisely', + 'Locher', + 'Eckart', + 'Rancourt', + 'Pyron', + 'Edney', + 'Besser', + 'Truex', + 'Monterroso', + 'Bruneau', + 'Province', + 'Permenter', + 'Nims', + 'Rollison', + 'Cabell', + 'Sylvain', + 'Salman', + 'Signorelli', + 'Vegas', + 'Maddy', + 'Bachelder', + 'Sevigny', + 'Stolte', + 'Chavarin', + 'Lukes', + 'Rather', + 'Gartland', + 'Kurek', + 'Nantz', + 'Savard', + 'Finegan', + 'No', + 'Chichester', + 'Newbill', + 'Mahnke', + 'Sax', + 'Sowinski', + 'Wendler', + 'Cadiz', + 'Male', + 'Mealey', + 'Brookes', + 'Enderle', + 'Valenta', + 'Tooker', + 'Whitbeck', + 'Threet', + 'Cavitt', + 'Murtagh', + 'Phalen', + 'Errico', + 'Merkley', + 'Ju', + 'Zachery', + 'Bramer', + 'Henline', + 'Noga', + 'Woelfel', + 'Deras', + 'Amen', + 'Aldape', + 'Bartling', + 'Claros', + 'Spurrier', + 'Ginder', + 'Fred', + 'Giberson', + 'Ryba', + 'Sommerfeld', + 'Dahle', + 'Endo', + 'Haddon', + 'Bowlby', + 'Wagener', + 'Ketter', + 'Balint', + 'Goheen', + 'Motsinger', + 'Celentano', + 'Drawdy', + 'Dennehy', + 'Mcelligott', + 'Nakamoto', + 'Deines', + 'Goldsby', + 'Drakeford', + 'Steffy', + 'Streich', + 'Villasana', + 'Cermak', + 'Prill', + 'Ellzey', + 'Gartrell', + 'Duffie', + 'Rother', + 'Buse', + 'Luz', + 'Groen', + 'Laviolette', + 'Roles', + 'Days', + 'Eash', + 'Haefner', + 'Font', + 'Mcree', + 'Bustillo', + 'Coughlan', + 'Bax', + 'Hoxie', + 'Barre', + 'Scaife', + 'Nowacki', + 'Reichardt', + 'Rogel', + 'Ivins', + 'Vanderburg', + 'Etchison', + 'Chesson', + 'Molden', + 'Giuliani', + 'Goodpaster', + 'Kriner', + 'Sturtz', + 'Tschida', + 'Henschel', + 'Asselin', + 'Kocsis', + 'Kroger', + 'Swayne', + 'Gallop', + 'Fraker', + 'Lauro', + 'Tuohy', + 'Scholes', + 'Croxton', + 'Fertig', + 'Gregerson', + 'Gundersen', + 'Lehrer', + 'Monsivais', + 'Pilla', + 'Weishaar', + 'Gutshall', + 'Winget', + 'Human', + 'Oberry', + 'Learned', + 'Marburger', + 'Teed', + 'Parrilla', + 'Due', + 'Hartzler', + 'Cieslak', + 'Feltz', + 'Geren', + 'Wile', + 'Waldrip', + 'Clore', + 'Stutler', + 'Feehan', + 'Lacher', + 'Felter', + 'Barakat', + 'Flippen', + 'Holsey', + 'Finkbeiner', + 'Istre', + 'Lengyel', + 'Lupercio', + 'Beegle', + 'Habel', + 'Hammill', + 'Kifer', + 'Buswell', + 'Deboard', + 'Guilliams', + 'Ahlstrom', + 'Beliveau', + 'Sasse', + 'Delker', + 'Letterman', + 'Avey', + 'Bohlen', + 'Piner', + 'Folmar', + 'Barile', + 'Komar', + 'Bonelli', + 'Lamay', + 'Cora', + 'Deere', + 'Sanon', + 'Deppe', + 'Emmerich', + 'Giannone', + 'Navarra', + 'Hudock', + 'Seaborn', + 'Burda', + 'Faz', + 'Stefani', + 'Beemer', + 'Vose', + 'Calandra', + 'Eno', + 'Figueredo', + 'Lauck', + 'Schwindt', + 'Dumais', + 'Hedger', + 'Capp', + 'Barreiro', + 'Buker', + 'Spruell', + 'Bertolini', + 'Hoar', + 'Tiemann', + 'Vandenbosch', + 'Winebrenner', + 'Maio', + 'Winship', + 'Brissette', + 'Hansell', + 'Elsey', + 'Hansard', + 'Gildersleeve', + 'Hambright', + 'Borba', + 'Konieczny', + 'Lundell', + 'Tiedemann', + 'Siegler', + 'Ying', + 'Mckinsey', + 'Olah', + 'Boersma', + 'Younkin', + 'Evanoff', + 'Nakashima', + 'Scalia', + 'Piro', + 'Colorado', + 'Felan', + 'Fuentez', + 'Blea', + 'Gowin', + 'Hanning', + 'Byrom', + 'Morant', + 'Bachand', + 'Mcsorley', + 'Peaslee', + 'Bardsley', + 'Stilson', + 'Severs', + 'Kincheloe', + 'Kyler', + 'Aurand', + 'Bento', + 'Hoeppner', + 'Mertes', + 'Pickrell', + 'Rustad', + 'Millikan', + 'Celestino', + 'Hovland', + 'Kurowski', + 'Zollinger', + 'Tallon', + 'Junkins', + 'Mizrahi', + 'Bomberger', + 'Farrand', + 'Curto', + 'Bona', + 'Donatelli', + 'Eppley', + 'Schurman', + 'Henao', + 'Tomberlin', + 'Provencio', + 'Speidel', + 'Cree', + 'Inskeep', + 'Yeates', + 'Hoggatt', + 'Hinkson', + 'Ficklin', + 'Mcnealy', + 'Cabanas', + 'Laycock', + 'Theroux', + 'Weymouth', + 'Mabie', + 'Hatchell', + 'Bohanon', + 'Bilger', + 'Nazarian', + 'Weist', + 'Depue', + 'Mangini', + 'Gelb', + 'Luman', + 'Blass', + 'Desroches', + 'Hearon', + 'Mcmiller', + 'Stoltenberg', + 'Parenti', + 'Daulton', + 'Smail', + 'Chisum', + 'Benefiel', + 'Tetrault', + 'Foland', + 'Reddington', + 'Mattei', + 'Custis', + 'Fransen', + 'Zylstra', + 'Salvaggio', + 'Factor', + 'Deshong', + 'Biederman', + 'Sirianni', + 'Steckler', + 'Thrall', + 'Dorsch', + 'Harpe', + 'Tell', + 'Galusha', + 'Guttman', + 'Raposa', + 'Jaros', + 'Lipka', + 'Shive', + 'Shand', + 'Brizuela', + 'Horvat', + 'Pisciotta', + 'Sorge', + 'Riebe', + 'Vanderlaan', + 'Isenhour', + 'Franson', + 'Goslin', + 'Amore', + 'Leachman', + 'Foulks', + 'Alamillo', + 'Scarpa', + 'Tickle', + 'Pettitt', + 'Orrell', + 'Fleckenstein', + 'Sapien', + 'Roye', + 'Mcmeans', + 'Sligh', + 'Landgraf', + 'Cecere', + 'Aune', + 'Ketron', + 'Welcher', + 'Tilford', + 'Maston', + 'Overall', + 'Fails', + 'Bah', + 'Ketterman', + 'Lindauer', + 'Saxe', + 'Majka', + 'Goodenough', + 'Panella', + 'Ramm', + 'Caley', + 'Christine', + 'Kinsler', + 'Pippen', + 'Murph', + 'Ammann', + 'Falkowski', + 'Madonna', + 'Seligman', + 'Rommel', + 'Lareau', + 'Melone', + 'Frasure', + 'Joyal', + 'Piekarski', + 'Porcelli', + 'Kennington', + 'Pica', + 'Ankrom', + 'Capron', + 'Chatmon', + 'Horrigan', + 'Morelos', + 'Noren', + 'Paolini', + 'Wildermuth', + 'Rossow', + 'Dorgan', + 'Pawlik', + 'Reiber', + 'Rothenberger', + 'Mcgonigle', + 'Oren', + 'Jeans', + 'Vivas', + 'Gerner', + 'Brzozowski', + 'Croyle', + 'Klick', + 'Vidaurri', + 'Wollman', + 'Brouillard', + 'Dejohn', + 'Meikle', + 'Grochowski', + 'Kaczor', + 'Philbin', + 'Sperber', + 'Vancil', + 'Zornes', + 'Strope', + 'Housel', + 'Minks', + 'Dike', + 'Jasmin', + 'Denicola', + 'Gokey', + 'Dominy', + 'Gillham', + 'Viray', + 'Herz', + 'Hursh', + 'Koeller', + 'Caicedo', + 'Near', + 'Harrel', + 'Veale', + 'Gustavson', + 'Lopiccolo', + 'Goldschmidt', + 'Loder', + 'Vannorman', + 'Maske', + 'Randel', + 'Pinner', + 'Buntin', + 'Roache', + 'Pinnock', + 'Dimaio', + 'Heckert', + 'Perrigo', + 'Schank', + 'Lisowski', + 'Brownstein', + 'Sharer', + 'Hambleton', + 'Maker', + 'Hursey', + 'Aguado', + 'Tian', + 'Rheaume', + 'Becraft', + 'Sowders', + 'Bratt', + 'Tebo', + 'Eid', + 'Reinecke', + 'Storck', + 'Pech', + 'Alspaugh', + 'Grell', + 'Purdue', + 'Jennette', + 'Pauling', + 'Wint', + 'Knupp', + 'Madewell', + 'Schwanke', + 'Tellier', + 'Washer', + 'Staff', + 'Keely', + 'Lisenby', + 'Walder', + 'Kennerly', + 'Ip', + 'Michalik', + 'Eichner', + 'Disbrow', + 'Bellomy', + 'Boesch', + 'Chirico', + 'Lietz', + 'Ploof', + 'Dyar', + 'Bai', + 'Lary', + 'Corbo', + 'Danaher', + 'Schiavo', + 'Giacalone', + 'Pentz', + 'Studley', + 'Doyal', + 'Edie', + 'Nathaniel', + 'Cambra', + 'Fenstermacher', + 'Garst', + 'Gaudio', + 'Zavaleta', + 'Castilla', + 'Griffeth', + 'Warthen', + 'Derringer', + 'Samsel', + 'Mattia', + 'Boelter', + 'Mathieson', + 'Estelle', + 'Frisk', + 'Hipple', + 'Garceau', + 'Ehrman', + 'Buchner', + 'Frailey', + 'Ganey', + 'Belser', + 'Leiby', + 'Schwind', + 'Hagberg', + 'Hooley', + 'Rafter', + 'Hasting', + 'Mcnab', + 'Piggott', + 'Millhouse', + 'Brescia', + 'Giancola', + 'Grob', + 'Uresti', + 'Tawney', + 'Huot', + 'Mizer', + 'Storrs', + 'Shobe', + 'Blade', + 'Baumbach', + 'Eppler', + 'Henningsen', + 'Kmetz', + 'Sepeda', + 'Pangburn', + 'Falgout', + 'Hurn', + 'Sholar', + 'Kendricks', + 'Brimhall', + 'Bucklin', + 'Hruby', + 'Hunziker', + 'Krenz', + 'Schwager', + 'Murley', + 'Crittendon', + 'Broady', + 'Kintz', + 'Entrekin', + 'Estey', + 'Sharrow', + 'Quarterman', + 'Gumbs', + 'Steely', + 'Machin', + 'Difiore', + 'Desch', + 'Wiedemann', + 'Tonn', + 'Villines', + 'Mcdole', + 'Bashir', + 'Beauford', + 'Crary', + 'Gallina', + 'Wolak', + 'Aburto', + 'Hasler', + 'Gullion', + 'Bracewell', + 'Rusher', + 'Sarvis', + 'Dargan', + 'Garbarino', + 'Pigeon', + 'Blasi', + 'Viens', + 'Reising', + 'Vosburgh', + 'Canipe', + 'Mcnett', + 'Bruss', + 'Shiflet', + 'Pinard', + 'Lattin', + 'Armbrust', + 'Peffer', + 'Shotts', + 'Arbaugh', + 'Hux', + 'First', + 'Bolds', + 'Ceaser', + 'Cephas', + 'Bormann', + 'Broadwell', + 'Qian', + 'Talamantez', + 'Vandermolen', + 'Maza', + 'Kinnear', + 'Bullins', + 'Arant', + 'Brodbeck', + 'Rolfes', + 'Wisneski', + 'Dague', + 'Dudas', + 'Greener', + 'Noguera', + 'Greeno', + 'Daddario', + 'Giambrone', + 'Menon', + 'Sherrick', + 'Spier', + 'Semon', + 'Fendley', + 'Crichton', + 'Moree', + 'Stratford', + 'Zobel', + 'Halladay', + 'Keesler', + 'Prewett', + 'Deavers', + 'Kamal', + 'Bottom', + 'Caves', + 'Harshaw', + 'Fretz', + 'Secord', + 'Seibold', + 'Pantaleon', + 'Greek', + 'Baumeister', + 'Kleven', + 'Kos', + 'Orban', + 'Papke', + 'Shatto', + 'Cui', + 'Boan', + 'Nevitt', + 'Hultgren', + 'Kreiser', + 'Veres', + 'Jent', + 'Merck', + 'Gibby', + 'Hosch', + 'Mallet', + 'Dock', + 'Dallman', + 'Loiacono', + 'Tetzlaff', + 'Arboleda', + 'Mclelland', + 'Willing', + 'Coonrod', + 'Cappiello', + 'Courtemanche', + 'Halperin', + 'Odegard', + 'Hornyak', + 'Stem', + 'Doner', + 'Saffold', + 'Hochman', + 'Ing', + 'Knudtson', + 'Laabs', + 'Selleck', + 'Bassler', + 'Kamin', + 'Hur', + 'Forward', + 'Finnie', + 'Blubaugh', + 'Hitz', + 'Litteral', + 'Mansur', + 'Rosenow', + 'Vermeulen', + 'Markarian', + 'Marceau', + 'Weisner', + 'Sharpless', + 'Cunniff', + 'Guilfoyle', + 'Lauver', + 'Lukasik', + 'Ripp', + 'Wierzbicki', + 'Wunsch', + 'Boothby', + 'Selfridge', + 'Mckey', + 'Vandermeer', + 'Vanhoy', + 'Edlund', + 'Eggen', + 'Bickett', + 'Hallum', + 'Brow', + 'Rhymer', + 'Buckalew', + 'Haughey', + 'Hentges', + 'Matthies', + 'Mccloy', + 'Simmon', + 'Concha', + 'Feingold', + 'Maglio', + 'Olaughlin', + 'Tassone', + 'Abbasi', + 'Oyola', + 'Mook', + 'Makin', + 'Carnegie', + 'Yue', + 'Sethi', + 'Duchene', + 'Mcnear', + 'Bartolo', + 'Hegedus', + 'Knoblauch', + 'Orner', + 'Hottinger', + 'Lovitt', + 'Harkless', + 'Anastasio', + 'Hohmann', + 'Mangione', + 'Dalby', + 'Urich', + 'Shuttleworth', + 'Guilbeau', + 'Bausch', + 'Demartini', + 'Difrancesco', + 'Schwalm', + 'Steere', + 'Guel', + 'Blanford', + 'Flax', + 'Fearon', + 'Severe', + 'Canto', + 'Krogh', + 'Meola', + 'Dykema', + 'Angelini', + 'Pooley', + 'Raff', + 'Rister', + 'Baehr', + 'Daubert', + 'Dechant', + 'Kliewer', + 'Hamdan', + 'Gaiser', + 'Lichty', + 'Pomerleau', + 'Uhler', + 'Membreno', + 'Printz', + 'Worman', + 'Thornley', + 'Burbridge', + 'Burdge', + 'Schnitzer', + 'Swanberg', + 'Steinkamp', + 'Heidel', + 'Karch', + 'Igo', + 'Mccausland', + 'Huskins', + 'Kuss', + 'Newbern', + 'Peete', + 'Godbolt', + 'Climer', + 'Neuenschwander', + 'Then', + 'Tietjen', + 'Trombetta', + 'Hawke', + 'Hazlewood', + 'Mayse', + 'Patillo', + 'Banos', + 'Kuck', + 'Lashbrook', + 'Sarkisian', + 'Goldberger', + 'Moravec', + 'Arey', + 'Crosswhite', + 'Elders', + 'Fricks', + 'Hercules', + 'Bester', + 'Erhart', + 'Kuper', + 'Sickels', + 'Mun', + 'Beddingfield', + 'Panetta', + 'Poplawski', + 'Lansford', + 'Negri', + 'Dawe', + 'Belair', + 'Lattimer', + 'Betty', + 'Raye', + 'Gobert', + 'Dragoo', + 'Horney', + 'Strawbridge', + 'Howery', + 'Bosarge', + 'Panzer', + 'Labrador', + 'Ransdell', + 'Trumbo', + 'Aubry', + 'Fenderson', + 'Fukuda', + 'Grosz', + 'Jacome', + 'Slick', + 'Kogut', + 'Haig', + 'Fouse', + 'Hufnagel', + 'Kehr', + 'Musselwhite', + 'Otwell', + 'Raddatz', + 'Oliverio', + 'Sluss', + 'Crossen', + 'Guidroz', + 'Mollett', + 'Sumler', + 'Chmiel', + 'Guinan', + 'Vita', + 'Wieser', + 'Ohlson', + 'Bubb', + 'Stennett', + 'Bugbee', + 'Minchew', + 'Grado', + 'Calcagno', + 'Losh', + 'Witzel', + 'Brandl', + 'Geoghegan', + 'Vanbrunt', + 'Smalling', + 'Carignan', + 'Schuelke', + 'Sienkiewicz', + 'Sollars', + 'Dames', + 'Malkin', + 'Rodriges', + 'Rozanski', + 'Tews', + 'Aust', + 'Bardin', + 'Voorhies', + 'Rines', + 'Courts', + 'Bannerman', + 'Martinsen', + 'Malick', + 'Collar', + 'Twilley', + 'Freiberg', + 'Latiolais', + 'Zehnder', + 'Mannon', + 'Becnel', + 'Cowans', + 'Arrigo', + 'Crago', + 'Curtsinger', + 'Gassman', + 'Marcelo', + 'Rosendahl', + 'Benito', + 'Cortright', + 'Carlon', + 'Kenton', + 'Hemminger', + 'Martinek', + 'Galeana', + 'Cobble', + 'Ruffino', + 'Wittrock', + 'Aberle', + 'Catanese', + 'Huezo', + 'Soules', + 'Ashraf', + 'Mera', + 'Gash', + 'Agnello', + 'Hauk', + 'Hayek', + 'Rahm', + 'Higham', + 'Kondo', + 'Almon', + 'Earwood', + 'Kriebel', + 'Philbrook', + 'Rimer', + 'Cuffee', + 'Wolfgram', + 'Wardwell', + 'Ridder', + 'Runner', + 'Houchens', + 'Vasser', + 'Charlesworth', + 'Dierks', + 'Molter', + 'Orosz', + 'Roudebush', + 'Coca', + 'Brost', + 'Lovern', + 'Brott', + 'Baudoin', + 'Prophet', + 'Bermea', + 'Ulm', + 'Bahl', + 'Ulery', + 'Caraveo', + 'Maez', + 'Corchado', + 'Baillie', + 'Colmenero', + 'Rebolledo', + 'Shevlin', + 'Mehaffey', + 'Hedin', + 'Pickell', + 'Spiro', + 'Coatney', + 'Gentner', + 'Fuhr', + 'Zeh', + 'Fuerte', + 'Knerr', + 'Nakata', + 'Voll', + 'Zach', + 'Gatica', + 'Rabalais', + 'Macek', + 'Petti', + 'Dickison', + 'Sheley', + 'Kinner', + 'Effinger', + 'Axelson', + 'Overbay', + 'Vancleve', + 'Speegle', + 'Muntz', + 'Sang', + 'Mcleroy', + 'Aleshire', + 'Holdridge', + 'Knouse', + 'Saling', + 'Zacher', + 'Zambrana', + 'Neblett', + 'Cichon', + 'Herdman', + 'Poli', + 'Schisler', + 'Antrim', + 'Babineau', + 'Coplin', + 'Straughn', + 'Watlington', + 'Burbach', + 'Campanelli', + 'Coletta', + 'Tennis', + 'Dymond', + 'Darosa', + 'Chard', + 'Delcampo', + 'Lyden', + 'Piland', + 'Eslick', + 'Beets', + 'Ransome', + 'Schuett', + 'Styers', + 'Fegley', + 'Corning', + 'Crume', + 'Villeneuve', + 'Schmeling', + 'Zeiger', + 'Blaker', + 'Ramsden', + 'Carol', + 'Roseboro', + 'Egner', + 'Filip', + 'Poitras', + 'Flanery', + 'Cothren', + 'Bridger', + 'Hoose', + 'Demas', + 'Kozel', + 'Marzano', + 'Penwell', + 'Rast', + 'Whicker', + 'Haslett', + 'Bibby', + 'Keese', + 'Montilla', + 'Sultana', + 'Resendes', + 'Vanscoy', + 'Dinan', + 'Bala', + 'Dirksen', + 'Ek', + 'Shimer', + 'Doshi', + 'Mayeux', + 'Streater', + 'Dattilo', + 'Marlar', + 'Senft', + 'Vanalstine', + 'Rehberg', + 'Vanderhoff', + 'Brenes', + 'Motto', + 'Sproles', + 'Toone', + 'Royall', + 'Beaudette', + 'Belding', + 'Berta', + 'Carmean', + 'Simonian', + 'Avera', + 'Martina', + 'Kind', + 'Buchheit', + 'Corrao', + 'Crumrine', + 'Wertman', + 'Lininger', + 'Pressman', + 'Slane', + 'Manges', + 'Theus', + 'Canizales', + 'Eugenio', + 'Ferrigno', + 'Ellard', + 'Stilley', + 'Crabbe', + 'Procter', + 'Baccus', + 'Hellmann', + 'Risk', + 'Schild', + 'Tostado', + 'Fessenden', + 'Glines', + 'Perone', + 'Carns', + 'Belote', + 'Deshotel', + 'Bottomley', + 'Delbosque', + 'Dubinsky', + 'Flinchum', + 'Berlanga', + 'Darland', + 'Daniele', + 'Jess', + 'Mungia', + 'Harlin', + 'Rocca', + 'Saltsman', + 'Trovato', + 'Dionisio', + 'Erbe', + 'Dauzat', + 'Laferriere', + 'Kear', + 'Brannigan', + 'Guard', + 'Roquemore', + 'Brehmer', + 'Kappes', + 'Kepley', + 'Labounty', + 'Sudol', + 'Walburn', + 'Bibeau', + 'Euler', + 'Brawn', + 'Pilot', + 'Bunger', + 'Earnhardt', + 'Fischetti', + 'Buitrago', + 'Calo', + 'Surette', + 'Martyn', + 'Tollett', + 'Tuller', + 'Noakes', + 'Marson', + 'Bongiovanni', + 'Novello', + 'Werling', + 'Wyland', + 'Palen', + 'Sigmund', + 'Salzer', + 'Abels', + 'Penson', + 'Cazarez', + 'Diblasi', + 'Jantzen', + 'Kittleson', + 'Hurlbert', + 'Shepardson', + 'Munz', + 'Bozek', + 'Woll', + 'Forth', + 'Colvard', + 'Baginski', + 'Beirne', + 'Lemmer', + 'Shover', + 'Lucci', + 'Hockensmith', + 'Mayhall', + 'Faucette', + 'Soloman', + 'Lembo', + 'Tarnowski', + 'Westerlund', + 'Gossage', + 'Bold', + 'Davi', + 'Crater', + 'Saia', + 'Spisak', + 'Zerr', + 'Penate', + 'Piel', + 'Raja', + 'Farney', + 'Cutrer', + 'Liverman', + 'Brar', + 'Nocera', + 'Coutu', + 'Rishel', + 'Spurr', + 'Kail', + 'Molino', + 'Favreau', + 'Mullinix', + 'Pospisil', + 'Rohloff', + 'Slavens', + 'Stumbo', + 'Ahl', + 'Hosking', + 'Speaker', + 'Tarkington', + 'Majeski', + 'Skoog', + 'Kirch', + 'Vannostrand', + 'Olmo', + 'Dorrell', + 'Newcombe', + 'Halls', + 'Riffel', + 'Luque', + 'Rolston', + 'Lokey', + 'Nicholes', + 'Gula', + 'Schrage', + 'Goshorn', + 'Woodell', + 'Ahmadi', + 'Austria', + 'Shaul', + 'Berwick', + 'Graczyk', + 'Lacourse', + 'Porcaro', + 'Rexroad', + 'Chrzanowski', + 'Abele', + 'Woodin', + 'Gillan', + 'Lone', + 'Orzechowski', + 'Fader', + 'Regina', + 'Ban', + 'Morriss', + 'Rickards', + 'Gannaway', + 'Tassin', + 'Accardi', + 'Engelke', + 'Kruk', + 'Mantilla', + 'Soderstrom', + 'Kriz', + 'Cantley', + 'Cangelosi', + 'Kalin', + 'Sobolewski', + 'Prinz', + 'Bessey', + 'Chittum', + 'Marcucci', + 'Annunziata', + 'Hegg', + 'Mishra', + 'Heppner', + 'Benningfield', + 'Rhoten', + 'Smolen', + 'Lewellyn', + 'Tall', + 'Comiskey', + 'Gobel', + 'Klump', + 'Stauber', + 'Tocci', + 'Gosser', + 'Tussey', + 'Summitt', + 'Ottman', + 'Vester', + 'Pasko', + 'Latshaw', + 'Kies', + 'Valderrama', + 'Leese', + 'Orduna', + 'Gilcrease', + 'Alli', + 'Berberich', + 'Delariva', + 'Harb', + 'Schmuck', + 'Spang', + 'Uecker', + 'Garfinkel', + 'Mcalexander', + 'Monty', + 'Leonetti', + 'Knipe', + 'Loudon', + 'Leisure', + 'Swearengin', + 'Tinnin', + 'Engelmann', + 'Noblitt', + 'Ruhland', + 'Shewmaker', + 'Smetana', + 'Vangundy', + 'Yzaguirre', + 'Nehls', + 'Sullens', + 'Mahurin', + 'Ferman', + 'Lenhardt', + 'Littman', + 'Udell', + 'Coutts', + 'Mcginness', + 'Nakayama', + 'Goguen', + 'Lass', + 'Tibbits', + 'Pafford', + 'Fett', + 'Ruis', + 'Trogdon', + 'Tarleton', + 'Isabell', + 'Paylor', + 'Grandison', + 'Bejar', + 'Highfield', + 'Peplinski', + 'Hammitt', + 'Mitton', + 'Dashiell', + 'Turrentine', + 'Rusin', + 'Sheeran', + 'Barrs', + 'Grund', + 'Kowalsky', + 'Mccaughey', + 'Orantes', + 'Oshields', + 'Tourville', + 'Szymczak', + 'Gagner', + 'Kemble', + 'Delangel', + 'Kaler', + 'Treanor', + 'Deems', + 'Ours', + 'Loss', + 'Remley', + 'Welles', + 'Bogardus', + 'Feher', + 'Grzybowski', + 'Meinert', + 'Mickelsen', + 'Opitz', + 'Osowski', + 'Paglia', + 'Srivastava', + 'Hirata', + 'Vandermark', + 'Maggi', + 'Gautreau', + 'Fonte', + 'Meck', + 'Mcquinn', + 'Criddle', + 'Hulin', + 'Fulmore', + 'Baldino', + 'Neugebauer', + 'Sletten', + 'Talcott', + 'Tessmer', + 'Vrooman', + 'Whitlatch', + 'Miano', + 'Arauz', + 'Lafon', + 'Cashin', + 'Carrow', + 'Feely', + 'Provo', + 'Botsford', + 'Chojnacki', + 'Pritts', + 'Duby', + 'Danos', + 'Mundo', + 'Strum', + 'Bealer', + 'Barmore', + 'Birkholz', + 'Hedgecock', + 'Vides', + 'Mcjunkin', + 'Paley', + 'Dennie', + 'Cosey', + 'Trombly', + 'Wagar', + 'Tope', + 'Venters', + 'Neptune', + 'Allshouse', + 'Kuczynski', + 'Beams', + 'Kilbourne', + 'Troxler', + 'Mcgahee', + 'Latson', + 'Miraglia', + 'Suda', + 'Prall', + 'Searls', + 'Tevis', + 'Vales', + 'Coberly', + 'Eichman', + 'Hiltz', + 'Mancera', + 'Mrozek', + 'Obermeyer', + 'Wiedeman', + 'Yoshimura', + 'Pascucci', + 'Denk', + 'Pita', + 'Abdul', + 'Schurr', + 'Huntoon', + 'Sund', + 'Blose', + 'Agostini', + 'Cogdell', + 'Hamburger', + 'Orwig', + 'Pelley', + 'Mcnelly', + 'Litten', + 'Osterberg', + 'Zepp', + 'Mathur', + 'Ardon', + 'Petre', + 'Schroeter', + 'Christoff', + 'Ridenhour', + 'Hibler', + 'Coachman', + 'Tadeo', + 'Vanderploeg', + 'Ference', + 'Connery', + 'Albro', + 'Bublitz', + 'Fagundes', + 'Purpura', + 'Deeb', + 'Melzer', + 'Haus', + 'Huffine', + 'Groner', + 'Laforce', + 'Burriss', + 'Longino', + 'Seldon', + 'Chicoine', + 'Neira', + 'Pintor', + 'Trager', + 'Garg', + 'Camilleri', + 'Limbaugh', + 'Marinello', + 'Sanz', + 'Hankey', + 'Aylor', + 'Homes', + 'Marro', + 'Stalder', + 'Creasey', + 'Blankinship', + 'Waldrup', + 'Aubert', + 'Quintanar', + 'Tarbell', + 'Mayton', + 'Baba', + 'Voltz', + 'Cuba', + 'Bracco', + 'Dimeo', + 'Cauble', + 'Rodela', + 'Sambrano', + 'Doten', + 'Jobes', + 'Laura', + 'Farrier', + 'Mixson', + 'Bassi', + 'Kroening', + 'Papineau', + 'Scheuerman', + 'Zertuche', + 'Cardella', + 'Taube', + 'Bazzi', + 'Sautter', + 'Tobon', + 'Venditti', + 'Nordman', + 'Loken', + 'Fortino', + 'Godbout', + 'Knaub', + 'Larabee', + 'Meserve', + 'Slama', + 'Junge', + 'Stamand', + 'Daigneault', + 'Fredericksen', + 'Loveall', + 'Clothier', + 'Kuehne', + 'Delahoussaye', + 'Bosquez', + 'Hildenbrand', + 'Muto', + 'Vanvliet', + 'Frederiksen', + 'Mero', + 'Rapier', + 'Feldt', + 'Mcpartland', + 'Stegner', + 'Veenstra', + 'Yeater', + 'Yeatts', + 'Rosenbloom', + 'Shepperd', + 'Marchbanks', + 'Tapscott', + 'Baynard', + 'Osby', + 'Cumberbatch', + 'Brassard', + 'Dahlman', + 'Doi', + 'Katona', + 'Niesen', + 'Slavik', + 'Macneill', + 'Marsala', + 'Fazekas', + 'Cudd', + 'Ocana', + 'Brimer', + 'Lachman', + 'Balla', + 'Shahid', + 'Gammage', + 'Canez', + 'Fickes', + 'Goldblatt', + 'Mcgeehan', + 'Westerberg', + 'Legler', + 'Stanberry', + 'Hillery', + 'Colosimo', + 'Florek', + 'Heckathorn', + 'Lenart', + 'Mcneilly', + 'Viles', + 'Davin', + 'Pierro', + 'Edman', + 'Patron', + 'Tipps', + 'Ardis', + 'Hassen', + 'Crase', + 'Gebert', + 'Predmore', + 'Entwistle', + 'Lourenco', + 'Snively', + 'Chivers', + 'Byas', + 'Edsall', + 'Sneddon', + 'Kloster', + 'Luedke', + 'Barcelo', + 'Corns', + 'Paula', + 'Tacker', + 'Marton', + 'Lyke', + 'Huitt', + 'Tinch', + 'Tagle', + 'Linnell', + 'Loden', + 'Witman', + 'Condrey', + 'Swindler', + 'Denby', + 'Mcdow', + 'Bennion', + 'Berkman', + 'Esguerra', + 'Kohli', + 'Leicht', + 'Platero', + 'Purtell', + 'Sarro', + 'Spera', + 'Wasielewski', + 'Nold', + 'Gander', + 'Coster', + 'Burn', + 'Sindelar', + 'Spivak', + 'Stangl', + 'Eakes', + 'Host', + 'Raybon', + 'Stickle', + 'Vitiello', + 'Borntrager', + 'Glorioso', + 'Winnie', + 'Blocher', + 'Che', + 'Godbold', + 'Blumenfeld', + 'Hallford', + 'Nuckolls', + 'Rasor', + 'Tardy', + 'Hayslett', + 'Kivett', + 'Pettry', + 'Klopfenstein', + 'Martelli', + 'Dunker', + 'Klass', + 'Denn', + 'Vessels', + 'Stukes', + 'Iannone', + 'Kovarik', + 'Perlmutter', + 'Som', + 'Kump', + 'Tack', + 'Warf', + 'Coffer', + 'Baas', + 'Balli', + 'Fleishman', + 'Lyall', + 'Meli', + 'Petrovic', + 'Sego', + 'Tignor', + 'Maule', + 'Stinchcomb', + 'Doxey', + 'Garbutt', + 'Drewes', + 'Prestridge', + 'Vivanco', + 'Weinmann', + 'Amrhein', + 'Schluter', + 'Cleek', + 'Rossignol', + 'Rezendes', + 'Marone', + 'Sloss', + 'Weary', + 'Leishman', + 'Searfoss', + 'Springman', + 'Wolfer', + 'Hires', + 'Mccampbell', + 'Casselman', + 'Frasca', + 'Lintner', + 'Preiss', + 'Neilsen', + 'Twiss', + 'Boughner', + 'Donnellan', + 'Rech', + 'Mccaulley', + 'Massenburg', + 'Dermody', + 'Neuberger', + 'Rifkin', + 'Ullom', + 'Marth', + 'Blacker', + 'Kase', + 'Garon', + 'Calaway', + 'Grange', + 'Yopp', + 'Service', + 'Blassingame', + 'Lockley', + 'Straughter', + 'Porath', + 'Situ', + 'Stansfield', + 'Eves', + 'Cianci', + 'Colindres', + 'Killam', + 'Luiz', + 'Stahlman', + 'Silvernail', + 'Moorhouse', + 'Langner', + 'Soucie', + 'Lucke', + 'Manly', + 'Huggard', + 'Higareda', + 'Matarazzo', + 'Jusino', + 'Winnett', + 'Matheney', + 'Bufkin', + 'Bilbo', + 'Levingston', + 'Auxier', + 'Guevarra', + 'Triolo', + 'Roder', + 'Clever', + 'Moodie', + 'Cabana', + 'Kiesling', + 'Lindblom', + 'Reuther', + 'Rubi', + 'Brinkmann', + 'Donati', + 'Cresswell', + 'Fortes', + 'Bayard', + 'Grayer', + 'Malveaux', + 'Hauger', + 'Hirschman', + 'Soroka', + 'Witek', + 'Pugsley', + 'Eoff', + 'Alewine', + 'Hastie', + 'Budzinski', + 'Burgard', + 'Hebel', + 'Kleist', + 'Lawhead', + 'Saporito', + 'Sugarman', + 'Sechler', + 'Cohoon', + 'Treadaway', + 'Silliman', + 'Horsey', + 'Chauhan', + 'Jovel', + 'Giorgio', + 'Waltrip', + 'Templeman', + 'Morning', + 'Fava', + 'Mcinturff', + 'Migliaccio', + 'Moncayo', + 'Pesek', + 'Olivero', + 'Devall', + 'Dauphin', + 'Banerjee', + 'Benway', + 'Bermejo', + 'Dacey', + 'Pilarski', + 'Pinnell', + 'Chia', + 'Pung', + 'Rahe', + 'Greenhaw', + 'Byrns', + 'Ancona', + 'Granato', + 'Luciani', + 'Shryock', + 'Sloop', + 'Murcia', + 'Croll', + 'Congleton', + 'Okelly', + 'Norville', + 'Flesch', + 'Murad', + 'Seddon', + 'Waybright', + 'Cremer', + 'Hagman', + 'Largo', + 'Solar', + 'Costales', + 'Gier', + 'Tober', + 'Reeb', + 'Lands', + 'Hoback', + 'Ingrassia', + 'Youngquist', + 'Tyrell', + 'Profit', + 'Collura', + 'Oldaker', + 'Vogl', + 'Spafford', + 'Laughman', + 'Goris', + 'Coghill', + 'Sweatman', + 'Rozelle', + 'Chatelain', + 'Fouch', + 'Legros', + 'Koza', + 'Vialpando', + 'Subia', + 'Danz', + 'Dosch', + 'Debruin', + 'Stefanik', + 'Gamber', + 'Saylors', + 'Cost', + 'Bernat', + 'Eastburn', + 'Getman', + 'Maillet', + 'Dogan', + 'Finklea', + 'Alongi', + 'Ballas', + 'Konkel', + 'Ryu', + 'Scoles', + 'Oles', + 'Algarin', + 'Seago', + 'Delaune', + 'Pettey', + 'Gettys', + 'Blanch', + 'Kea', + 'Cambridge', + 'Ciesielski', + 'Pribble', + 'Mayhugh', + 'Dery', + 'Allsup', + 'Hauptman', + 'Shoff', + 'Spath', + 'Lipsky', + 'Lakhani', + 'Lona', + 'Andrea', + 'Heist', + 'Herzig', + 'Insley', + 'Frasher', + 'Muise', + 'Kettle', + 'Catano', + 'Harkleroad', + 'Rominger', + 'Schreffler', + 'Bielecki', + 'Knarr', + 'Arvidson', + 'Harnden', + 'Galyon', + 'Rando', + 'Delima', + 'Constance', + 'Bosman', + 'Meinke', + 'Rosenquist', + 'Stickles', + 'Batz', + 'Eitel', + 'Kouba', + 'Marmol', + 'Rini', + 'Kinyon', + 'Munns', + 'Hilts', + 'Verrett', + 'Shead', + 'Staggers', + 'Naccarato', + 'Shupp', + 'Willeford', + 'Gayer', + 'Bran', + 'Krider', + 'Cue', + 'Dubiel', + 'Kawamoto', + 'Quayle', + 'Meckley', + 'Weingart', + 'Ivan', + 'Aller', + 'Pattee', + 'Pile', + 'Shinault', + 'Alzate', + 'Goudreau', + 'Weitzman', + 'Zurek', + 'Portman', + 'Tellis', + 'Achenbach', + 'Cranfill', + 'Scheib', + 'Rud', + 'Forgey', + 'Sardina', + 'Hayslip', + 'Fadden', + 'Ethington', + 'Jette', + 'Maberry', + 'Stecher', + 'Mcgahan', + 'Buffa', + 'Lehto', + 'Lesch', + 'Minier', + 'Niblett', + 'Behar', + 'Gochenour', + 'Thole', + 'Woodmansee', + 'Guse', + 'Breunig', + 'Deibert', + 'Levario', + 'Liming', + 'Oltman', + 'Vought', + 'Higby', + 'Lummus', + 'Casimir', + 'Grabow', + 'Helzer', + 'Madero', + 'Panico', + 'Ruud', + 'Beas', + 'Knebel', + 'Lorence', + 'Sizer', + 'Goodwill', + 'Darrell', + 'Dismukes', + 'Wimbish', + 'Kleine', + 'Prohaska', + 'Freeborn', + 'Caso', + 'Meis', + 'Bise', + 'Maxim', + 'Chumbley', + 'Eaglin', + 'Bergey', + 'Hillenbrand', + 'Pacifico', + 'Plath', + 'Rio', + 'Ristau', + 'Zych', + 'Whang', + 'Fister', + 'Forbush', + 'Lagarde', + 'Atha', + 'Hallinan', + 'Hesser', + 'Hoak', + 'Kohr', + 'Longnecker', + 'Nomura', + 'Raia', + 'Seybold', + 'Spagnola', + 'Majano', + 'Sanmartin', + 'Mangual', + 'Stanback', + 'Gangi', + 'Lauritzen', + 'Seeber', + 'Disla', + 'Frain', + 'Besse', + 'Makris', + 'Ducker', + 'Demps', + 'Laporta', + 'Pavey', + 'Reineke', + 'Najjar', + 'Mcclaskey', + 'Luff', + 'Vanderveer', + 'Mccoll', + 'Leamon', + 'Meinhardt', + 'Dinatale', + 'Laffoon', + 'Jenny', + 'Skipworth', + 'Folds', + 'Burstein', + 'Freas', + 'Lizardo', + 'Selle', + 'Vrabel', + 'Beranek', + 'Hakala', + 'Spataro', + 'Prahl', + 'Meas', + 'Haston', + 'Croker', + 'Carmouche', + 'Doolan', + 'Guerrieri', + 'Poulton', + 'Mauger', + 'Klose', + 'Husk', + 'Pharis', + 'Dipalma', + 'Hamaker', + 'Simek', + 'Strube', + 'Corl', + 'Bence', + 'Meigs', + 'Gillaspie', + 'Moring', + 'Eli', + 'Mccullers', + 'Erving', + 'Dopp', + 'Falbo', + 'Gensler', + 'Heroux', + 'Hertzler', + 'Muscarella', + 'Wittmann', + 'Willner', + 'Howton', + 'Brummitt', + 'Demar', + 'Hardrick', + 'Benavente', + 'Choo', + 'Tiscareno', + 'Bunge', + 'Helle', + 'Ogan', + 'Allbright', + 'Jervis', + 'Tompson', + 'Sheats', + 'Hebron', + 'Esters', + 'Fiorillo', + 'Narciso', + 'Slowik', + 'Kush', + 'Sole', + 'Bitting', + 'Bradham', + 'Goggans', + 'Rushin', + 'Huguley', + 'Kittelson', + 'Nadel', + 'Noggle', + 'Xue', + 'Alameda', + 'Hege', + 'Liberto', + 'Maron', + 'Aber', + 'Brodersen', + 'Clasen', + 'Couturier', + 'Godines', + 'Ozment', + 'Parga', + 'Rohm', + 'Voris', + 'Leaver', + 'Newhart', + 'Sabourin', + 'Kelling', + 'Repass', + 'Wigington', + 'Prioleau', + 'Antle', + 'Goucher', + 'Kreitzer', + 'Reuss', + 'Rosenfield', + 'Sliva', + 'Nolting', + 'Radel', + 'Quintal', + 'Lisa', + 'Temples', + 'Cavins', + 'Gazaway', + 'Hopewell', + 'Albury', + 'Broberg', + 'Khuu', + 'Zelinski', + 'Kurian', + 'Treacy', + 'Rake', + 'Tirrell', + 'Macdowell', + 'Smead', + 'Edgerly', + 'Fowles', + 'Yorke', + 'Goodwyn', + 'Sciacca', + 'Breitenbach', + 'Charity', + 'Greenidge', + 'Kendig', + 'Navarette', + 'Doremus', + 'Marcelino', + 'Ribera', + 'Luse', + 'Hasley', + 'Halton', + 'Jakes', + 'Balas', + 'Cheema', + 'Dettman', + 'Schachter', + 'Weisenberger', + 'Lehn', + 'Sailors', + 'Alcott', + 'Mancino', + 'Mineo', + 'Montz', + 'Stettler', + 'Brannock', + 'Shumake', + 'Blunk', + 'Feuerstein', + 'Mangino', + 'Bitzer', + 'Padden', + 'Wetter', + 'Blase', + 'Helvey', + 'Sabia', + 'Folden', + 'Wyllie', + 'Hoosier', + 'Gehringer', + 'Peifer', + 'Schneiderman', + 'Raj', + 'Gift', + 'Sue', + 'Wedgeworth', + 'Bischof', + 'Coviello', + 'Flor', + 'Barrentine', + 'Ells', + 'Dundas', + 'Baine', + 'Bouknight', + 'Koning', + 'Mallari', + 'Monje', + 'Wingler', + 'Stainbrook', + 'Mari', + 'Hemby', + 'Boateng', + 'Enfinger', + 'Esquer', + 'Salvatierra', + 'Tercero', + 'Porta', + 'Speth', + 'Plate', + 'Rockhold', + 'Hampshire', + 'Stipe', + 'Buescher', + 'Denault', + 'Fahnestock', + 'Vandehey', + 'Brouse', + 'Ciaccio', + 'Hund', + 'Wire', + 'Sherron', + 'Fairfax', + 'Owusu', + 'Cuervo', + 'Minjarez', + 'Zarco', + 'Vandyne', + 'Gedeon', + 'Kegler', + 'Ebron', + 'Murtaugh', + 'Pariseau', + 'Morvant', + 'Ellwood', + 'Beazley', + 'Farrelly', + 'Mccollom', + 'Alegre', + 'Dussault', + 'Goulette', + 'Hession', + 'Regier', + 'Speranza', + 'Spinella', + 'Maloof', + 'Nogueira', + 'Beaudin', + 'Sable', + 'Samford', + 'Marchan', + 'Rodriques', + 'Rhines', + 'Aldrete', + 'Creedon', + 'Laberge', + 'Sandel', + 'Spady', + 'Horsman', + 'Schimpf', + 'Sottile', + 'Than', + 'Ybanez', + 'Sagastume', + 'Vosburg', + 'Langlais', + 'Windley', + 'Bielski', + 'Meyerson', + 'Rizk', + 'Sparacino', + 'Winebarger', + 'Helsley', + 'Alward', + 'Wilker', + 'Clyne', + 'Bergren', + 'Gin', + 'Heberling', + 'Noh', + 'Rotz', + 'Laffey', + 'Zurawski', + 'Aliff', + 'Coover', + 'Steves', + 'Brain', + 'Greggs', + 'Burts', + 'Culwell', + 'Halbrook', + 'Marcantel', + 'Alsip', + 'Esslinger', + 'Kinnaird', + 'Rew', + 'Wimbley', + 'Dalal', + 'Litke', + 'Ostlund', + 'Petersheim', + 'Vezina', + 'Vickrey', + 'Vida', + 'Stachowiak', + 'Santizo', + 'Stow', + 'Hoel', + 'Parrino', + 'Elsberry', + 'Pharris', + 'Chiarello', + 'Konen', + 'Ogata', + 'Tousignant', + 'Turano', + 'Zoll', + 'Reser', + 'Ribble', + 'Dally', + 'Kersh', + 'Crivello', + 'Glantz', + 'Vanvleet', + 'Dy', + 'Woolwine', + 'Ager', + 'Romney', + 'Dedeaux', + 'Ringgold', + 'Mir', + 'Rexford', + 'Whitehair', + 'Wilczynski', + 'Kleinsasser', + 'Siemens', + 'Kindig', + 'Kemmer', + 'Fonda', + 'Litt', + 'Mcferrin', + 'Riche', + 'Beaudet', + 'Lasala', + 'Maglione', + 'Milani', + 'Moscato', + 'Pangilinan', + 'Haycraft', + 'Camilo', + 'Trafton', + 'Stroble', + 'Dollard', + 'Consiglio', + 'Kinnaman', + 'Mumaw', + 'Mustard', + 'Nees', + 'Rupprecht', + 'Gimbel', + 'Chamberland', + 'Lish', + 'Beedle', + 'Minder', + 'Broxton', + 'Cocco', + 'Vore', + 'Slough', + 'Pehrson', + 'Graney', + 'Reade', + 'Cozzi', + 'Mowrer', + 'Necaise', + 'Notaro', + 'Vanderwall', + 'Jeffs', + 'Lynd', + 'Perino', + 'Poyner', + 'Oscar', + 'Mihalik', + 'Coscia', + 'Zoellner', + 'Shippee', + 'Casimiro', + 'Phillippe', + 'Bartolotta', + 'Graciano', + 'Schnoor', + 'Aube', + 'Duguay', + 'Dickerman', + 'Santi', + 'Cude', + 'Haver', + 'Heidelberg', + 'Farquharson', + 'Bianchini', + 'Kasprzak', + 'Pizzi', + 'Urquiza', + 'Knee', + 'Lust', + 'Strayhorn', + 'Ader', + 'Canup', + 'Mira', + 'Saulnier', + 'Stalvey', + 'Takeuchi', + 'Updegraff', + 'Barletta', + 'Mikhail', + 'Abadie', + 'Cohee', + 'Sones', + 'Hird', + 'Mizelle', + 'Graddy', + 'Demay', + 'Escandon', + 'Kozar', + 'Lecuyer', + 'Tredway', + 'Danks', + 'Pry', + 'Mathena', + 'Gomer', + 'Moussa', + 'Journey', + 'Brison', + 'Denardo', + 'Digiorgio', + 'Worster', + 'Kottke', + 'Sayegh', + 'Aday', + 'Chain', + 'Digby', + 'Beeks', + 'Malpass', + 'Toft', + 'Fucci', + 'Stam', + 'Smoker', + 'Willms', + 'Bohner', + 'Sugar', + 'Tay', + 'Faye', + 'Melnik', + 'Pankow', + 'Stehle', + 'Vecchione', + 'Weatherwax', + 'Monterrosa', + 'Bodily', + 'Serino', + 'Jerkins', + 'Bosma', + 'Luczak', + 'Serafini', + 'Baze', + 'Hemmings', + 'Darrington', + 'Fraizer', + 'Henrikson', + 'Kok', + 'Larrison', + 'Mirabella', + 'Newhall', + 'Hollenbach', + 'Formica', + 'Haake', + 'Seim', + 'Zeledon', + 'Crabill', + 'Mensch', + 'Prevatt', + 'Riggan', + 'Gallien', + 'Erby', + 'Running', + 'Shisler', + 'Sidebottom', + 'Sladek', + 'Alejos', + 'Momin', + 'Bickers', + 'Smither', + 'Ahart', + 'Huseman', + 'Cantero', + 'Reiley', + 'Mcneeley', + 'Quill', + 'Binger', + 'Ellerbee', + 'Cearley', + 'Guilmette', + 'Helbig', + 'Nuzum', + 'Gravatt', + 'Turlington', + 'Deramus', + 'Casados', + 'Harrop', + 'Kardos', + 'Krehbiel', + 'Homa', + 'Agostino', + 'Candia', + 'Byerley', + 'Kincer', + 'Vitello', + 'Backhaus', + 'Burzynski', + 'Zaborowski', + 'Puebla', + 'Pedrick', + 'Hyson', + 'Mazyck', + 'Deno', + 'Yutzy', + 'Dubbs', + 'Shimek', + 'Saha', + 'Philipps', + 'Chretien', + 'Bramwell', + 'Mccalister', + 'Ebright', + 'Parkhill', + 'Rieke', + 'Karras', + 'Mcbain', + 'Gibbon', + 'Beckler', + 'Nordby', + 'Sipos', + 'Swider', + 'Treiber', + 'Weakland', + 'Zagorski', + 'Peavler', + 'Cirino', + 'Corzine', + 'Barbier', + 'Dolby', + 'Sheperd', + 'Vanderhorst', + 'Cornman', + 'Dippel', + 'Gramlich', + 'Hoffmeister', + 'Markwell', + 'Milks', + 'Schriner', + 'Cusimano', + 'Emberton', + 'Kimbler', + 'Merrow', + 'Huard', + 'Paulo', + 'Durrance', + 'Faherty', + 'Palmatier', + 'Rezac', + 'Speir', + 'Streicher', + 'Ackman', + 'Veitch', + 'Bedgood', + 'Pantano', + 'Raman', + 'Eusebio', + 'Coldwell', + 'Omer', + 'Swanigan', + 'Stepney', + 'Breiner', + 'Casebolt', + 'Deblasio', + 'Mascaro', + 'Maselli', + 'Overfield', + 'Enyart', + 'Litman', + 'Borer', + 'Dudash', + 'Mcniff', + 'Cherian', + 'Scearce', + 'Brakefield', + 'Hamed', + 'Cooperman', + 'Kinzel', + 'Mchargue', + 'Schiefelbein', + 'Varughese', + 'Brumm', + 'Novy', + 'Vicars', + 'Barratt', + 'Titsworth', + 'Mole', + 'Crisafulli', + 'Deitch', + 'Slager', + 'Tokarz', + 'Speelman', + 'Tunney', + 'Peal', + 'Chenevert', + 'Haggins', + 'Heitmann', + 'Scheuer', + 'Stuhr', + 'Zenner', + 'Wishon', + 'Arno', + 'Lauder', + 'Goertz', + 'Jew', + 'Knapik', + 'Lococo', + 'Murnane', + 'Pawloski', + 'Contino', + 'Holbrooks', + 'Carlstrom', + 'Heitkamp', + 'Muszynski', + 'Shelnutt', + 'Tortora', + 'Dietrick', + 'Kyzer', + 'Colt', + 'Propes', + 'Caffee', + 'Fankhauser', + 'Liotta', + 'Patil', + 'Broder', + 'Disher', + 'Telfer', + 'Lampkins', + 'Bartman', + 'Beauchemin', + 'Gatz', + 'Pedrosa', + 'Schuch', + 'Zorrilla', + 'Capote', + 'Vanderslice', + 'Boulden', + 'Kirkendoll', + 'Fausto', + 'Krom', + 'Ngai', + 'Sepe', + 'Domenech', + 'Dines', + 'Aschenbrenner', + 'Carias', + 'Inoue', + 'Montagna', + 'Pulsifer', + 'Rieman', + 'Seelye', + 'Yochum', + 'Defilippis', + 'Lacross', + 'Betances', + 'Jenne', + 'Rousey', + 'Brunswick', + 'Wadlington', + 'Brainerd', + 'Dauria', + 'Dinicola', + 'Fath', + 'Gemmell', + 'Rudman', + 'Urbaniak', + 'Fillion', + 'Brandel', + 'Devin', + 'Derrickson', + 'Jenkin', + 'Ebling', + 'Ferranti', + 'Lueders', + 'Alvear', + 'Gero', + 'Maury', + 'Estill', + 'Beadles', + 'Philyaw', + 'Tann', + 'Bednarski', + 'Nagata', + 'Partington', + 'Sobol', + 'Soohoo', + 'Welliver', + 'Yam', + 'Popejoy', + 'Berthelot', + 'Manwaring', + 'Cahn', + 'Layer', + 'Poarch', + 'Tee', + 'Arellanes', + 'Ehler', + 'Montalto', + 'Pavlick', + 'Rauh', + 'Mcnees', + 'Balke', + 'Alles', + 'Caperton', + 'Frier', + 'Thweatt', + 'Whitely', + 'Demby', + 'Kowalik', + 'Loffredo', + 'Solem', + 'Clampitt', + 'Dossey', + 'Fauver', + 'Toto', + 'Corlett', + 'Nickols', + 'Golston', + 'Graef', + 'Salsman', + 'Hartl', + 'Towell', + 'Lasseter', + 'Arata', + 'Diver', + 'Malan', + 'Lanter', + 'Justis', + 'Prime', + 'Ditzler', + 'Engelhart', + 'Plouffe', + 'Zaldivar', + 'Elser', + 'Witherow', + 'Mateer', + 'Rikard', + 'Dolson', + 'Mariner', + 'Amis', + 'Toby', + 'Evins', + 'Midgette', + 'Pinnix', + 'Blackard', + 'Huisman', + 'Lager', + 'Deloera', + 'Dutt', + 'Goodrow', + 'Morphis', + 'Quin', + 'Frankenfield', + 'Craycraft', + 'Mazer', + 'Meloy', + 'Lebouef', + 'Beresford', + 'Spiva', + 'Michie', + 'Jarreau', + 'Vallier', + 'Dunmore', + 'Cerra', + 'Ciulla', + 'Dauer', + 'Helling', + 'Jackowski', + 'Taboada', + 'Balistreri', + 'Blattner', + 'Cabot', + 'Lawver', + 'Cornette', + 'Arline', + 'Amsden', + 'Degner', + 'Ungar', + 'Birney', + 'Goldie', + 'Croston', + 'Wixon', + 'Alan', + 'Garneau', + 'Kolakowski', + 'Vitek', + 'Witherell', + 'Licari', + 'Badeaux', + 'Sammon', + 'Greenland', + 'Corlew', + 'Cashwell', + 'Aldinger', + 'Bilderback', + 'Kleeman', + 'Sisto', + 'Menz', + 'Bakos', + 'Ebbert', + 'Berliner', + 'Kin', + 'Cabaniss', + 'Ouzts', + 'Mccook', + 'Campfield', + 'Gulino', + 'Odriscoll', + 'Weyand', + 'Mcguckin', + 'Crean', + 'Boyington', + 'Bracero', + 'Carini', + 'Chawla', + 'Chaudhary', + 'Koehl', + 'Wahlstrom', + 'Francoeur', + 'Leveque', + 'Ledgerwood', + 'Paluch', + 'Wyble', + 'Latif', + 'Koen', + 'Eddie', + 'Mcgirt', + 'Boxley', + 'Exline', + 'Lujano', + 'Michalowski', + 'Rottman', + 'Throop', + 'Zech', + 'Baros', + 'Bohne', + 'Mule', + 'Monica', + 'Lasiter', + 'Alsop', + 'Pittard', + 'Whitefield', + 'Mccaskey', + 'Paek', + 'Reilley', + 'Wasik', + 'Bouma', + 'Garrigan', + 'Nett', + 'Mclarty', + 'Flemings', + 'Alcorta', + 'Spoor', + 'Mccranie', + 'Coverdale', + 'Guaman', + 'Jenness', + 'Knoop', + 'Scarpelli', + 'Schrecengost', + 'Toews', + 'Caughey', + 'Laska', + 'Helfer', + 'Bevers', + 'Forbus', + 'Mccrady', + 'Reasor', + 'Aggarwal', + 'Locicero', + 'Uber', + 'Vadnais', + 'Budnick', + 'Duhamel', + 'Stelling', + 'Kicklighter', + 'Basco', + 'Otts', + 'Tippins', + 'Bliven', + 'Gayheart', + 'Knauf', + 'Lalli', + 'Quigg', + 'Kingman', + 'Boros', + 'Henneman', + 'Lofland', + 'Pendarvis', + 'Keitt', + 'Gelfand', + 'Greaney', + 'Kindt', + 'Stimac', + 'Kirn', + 'Tokar', + 'Miura', + 'Wendorf', + 'Vigue', + 'Dorey', + 'Fegan', + 'Meares', + 'Thierry', + 'Ambrosino', + 'Coenen', + 'Kersting', + 'Leas', + 'Millward', + 'Petzold', + 'Morphew', + 'Filippone', + 'Stoffer', + 'Mani', + 'Clairmont', + 'Mccreight', + 'Cully', + 'Bissonette', + 'Kochan', + 'Linneman', + 'Parlier', + 'Bergner', + 'Sterns', + 'Steveson', + 'Clingerman', + 'Karg', + 'Medved', + 'Prakash', + 'Ulman', + 'Petroski', + 'Hagaman', + 'Huddle', + 'Auclair', + 'Shives', + 'Dunavant', + 'Glade', + 'Chauncey', + 'Pough', + 'Burgoon', + 'Pluta', + 'Couey', + 'Punch', + 'Colmenares', + 'Fosdick', + 'Henze', + 'Kaczynski', + 'Lomonaco', + 'Roepke', + 'Schenkel', + 'Schlatter', + 'Schoenherr', + 'Tripodi', + 'Zeiler', + 'Bunt', + 'Dolly', + 'Boyland', + 'Bickle', + 'Cincotta', + 'Crull', + 'Enfield', + 'Saltz', + 'Skelley', + 'Younts', + 'Bussiere', + 'Latona', + 'Sensabaugh', + 'Grosvenor', + 'Woolbright', + 'Shorty', + 'Brungardt', + 'Cardon', + 'Carlberg', + 'Clevinger', + 'Rucinski', + 'Vanhooser', + 'Westling', + 'Imperial', + 'Tyer', + 'Elzey', + 'Aslam', + 'Fesler', + 'Leiser', + 'Smitley', + 'Orgeron', + 'Scuderi', + 'Flatley', + 'Whiteford', + 'Tison', + 'Laurin', + 'Fortman', + 'Whitty', + 'Kirton', + 'Cassella', + 'Flom', + 'Seigel', + 'Cossette', + 'Bryden', + 'Gobin', + 'Hieb', + 'Marzullo', + 'Matuszak', + 'Rolph', + 'Spilman', + 'Vanvoorhis', + 'Sande', + 'Suydam', + 'Gledhill', + 'Krill', + 'Mackiewicz', + 'Templet', + 'Friedrichs', + 'Ruddell', + 'Kats', + 'Nourse', + 'Millender', + 'Wafer', + 'Fauntleroy', + 'Archibeque', + 'Maslowski', + 'Metzgar', + 'Pizana', + 'Mcguffey', + 'Estridge', + 'Vanalstyne', + 'Decuir', + 'Mcbean', + 'Hardnett', + 'Avilla', + 'Spadafora', + 'Weisel', + 'Kann', + 'Leyden', + 'Purdom', + 'Tappan', + 'Gunnells', + 'Slaten', + 'Hansley', + 'Chiappetta', + 'Rozek', + 'Tiede', + 'Winland', + 'Dubuque', + 'Heslin', + 'Bradway', + 'Eckels', + 'Saffell', + 'Germaine', + 'Apolinar', + 'Coloma', + 'Gawlik', + 'Chipps', + 'Hicklin', + 'Glanton', + 'Dalke', + 'Denlinger', + 'Kuipers', + 'Houpt', + 'Parcell', + 'Claeys', + 'Ferreri', + 'Greif', + 'Lucente', + 'Siems', + 'Yousef', + 'Llerena', + 'Rote', + 'Suero', + 'Malmberg', + 'Touchette', + 'Luton', + 'Wess', + 'Height', + 'Stampley', + 'Anastasi', + 'Bulman', + 'Deharo', + 'Laube', + 'Severt', + 'Midgley', + 'Colling', + 'Ell', + 'Burbage', + 'Commander', + 'Hubner', + 'Zurcher', + 'Arocha', + 'Nobile', + 'Tingler', + 'Ellman', + 'Lolley', + 'Pewitt', + 'Mcduff', + 'Hyler', + 'Goltz', + 'Kubota', + 'Lamberti', + 'Ohern', + 'Uhrig', + 'Dummer', + 'Keesling', + 'Litzinger', + 'Moriarity', + 'Servantes', + 'Rohe', + 'Stokely', + 'Weedon', + 'Pippins', + 'Dehner', + 'Krogman', + 'Luecke', + 'Rosete', + 'Zona', + 'Lowy', + 'Applebee', + 'Heather', + 'Cruikshank', + 'Linson', + 'Brandy', + 'Koser', + 'Ruel', + 'Ruppe', + 'Saeteurn', + 'Dewolfe', + 'Sawtelle', + 'Rudin', + 'Raver', + 'Bassham', + 'Yaw', + 'Segrest', + 'Belfiore', + 'Heeren', + 'Kotowski', + 'Luken', + 'Makela', + 'Ranallo', + 'Schug', + 'Seery', + 'Payson', + 'Caufield', + 'Lacefield', + 'Bratten', + 'Jr', + 'Buske', + 'Ternes', + 'Bivona', + 'Felber', + 'Rott', + 'Pitkin', + 'Pridmore', + 'Oyer', + 'Astle', + 'Jeppesen', + 'Shimabukuro', + 'Soltys', + 'Vieth', + 'Rasnick', + 'Calfee', + 'Brignac', + 'Lamy', + 'Facey', + 'Alper', + 'Borquez', + 'Cavalieri', + 'Niswonger', + 'Pajak', + 'Schwabe', + 'Ringel', + 'Abbe', + 'Fenley', + 'Churchman', + 'Haydel', + 'Stockard', + 'Adamek', + 'Ellerman', + 'Torpey', + 'Waldroup', + 'Hunte', + 'Bienaime', + 'Lazzara', + 'Nemitz', + 'Wingerter', + 'Boer', + 'Franken', + 'Lebow', + 'Manger', + 'Baisley', + 'Pane', + 'Gayden', + 'Bertelsen', + 'Curfman', + 'Leanos', + 'Nissley', + 'Odwyer', + 'Manzer', + 'Kollman', + 'Quon', + 'Holgate', + 'Cola', + 'Mckissack', + 'Cousar', + 'Bilski', + 'Boehler', + 'Kawamura', + 'April', + 'Mckelvy', + 'Lanni', + 'Roehm', + 'Salva', + 'Stackpole', + 'Stracener', + 'Masiello', + 'Barrus', + 'Tubb', + 'Brummel', + 'Devereux', + 'Foushee', + 'Corado', + 'Gladfelter', + 'Grewe', + 'Hodapp', + 'Swartwood', + 'Vacek', + 'Wrona', + 'Shaffner', + 'Ullah', + 'Heslop', + 'Mungo', + 'Haymon', + 'Behrend', + 'Falter', + 'Feola', + 'Gruner', + 'Picklesimer', + 'Riedl', + 'Stegeman', + 'Harpole', + 'Moyes', + 'Boulay', + 'Brighton', + 'Guise', + 'Laury', + 'Badilla', + 'Cypher', + 'Houdek', + 'Juhasz', + 'Klingbeil', + 'Pinales', + 'Fellman', + 'Daher', + 'Allmond', + 'Bal', + 'Crager', + 'Hillebrand', + 'Menezes', + 'Serpas', + 'Zager', + 'Alvardo', + 'Summerford', + 'Stillings', + 'Vandergrift', + 'Hanchett', + 'Minto', + 'Daughtery', + 'Gillon', + 'Rajan', + 'Vasko', + 'Wirick', + 'Woolever', + 'Caserta', + 'Welle', + 'Kimbrel', + 'Traywick', + 'Hands', + 'Spratley', + 'Iannuzzi', + 'Krikorian', + 'Runk', + 'Sood', + 'Riese', + 'Antunes', + 'Winsett', + 'Mans', + 'Capel', + 'Condron', + 'Nilles', + 'Petz', + 'Salemi', + 'Bainter', + 'Patchett', + 'Hirschfeld', + 'Murrin', + 'Lamey', + 'Mcglothin', + 'Hodo', + 'Hirth', + 'Kaltenbach', + 'Kensinger', + 'Leidy', + 'Shurtz', + 'Braatz', + 'Brafford', + 'Willet', + 'Clendening', + 'Basch', + 'Brockwell', + 'Oberman', + 'Palmateer', + 'Osornio', + 'Gehl', + 'Staker', + 'Mattila', + 'Dawn', + 'Cowherd', + 'Appleman', + 'Carbonaro', + 'Castruita', + 'Pilling', + 'Wenrich', + 'Christoffersen', + 'Hinzman', + 'Kaup', + 'Pettersen', + 'Jue', + 'Khalsa', + 'Mutz', + 'Remus', + 'Arch', + 'Shands', + 'Borek', + 'Buresh', + 'Egli', + 'Feldkamp', + 'Hampel', + 'Lichtenberg', + 'Morimoto', + 'Brasel', + 'Demelo', + 'Royalty', + 'Averitt', + 'Metivier', + 'Bradsher', + 'Avallone', + 'Demeter', + 'Masucci', + 'Musil', + 'Wichmann', + 'Broman', + 'Taunton', + 'Blewett', + 'Duhart', + 'Goo', + 'Hanus', + 'Mathai', + 'Shutts', + 'Taniguchi', + 'Vanleeuwen', + 'Delvillar', + 'Hane', + 'Givan', + 'Croskey', + 'Elamin', + 'Deffenbaugh', + 'Miklos', + 'Passalacqua', + 'Woessner', + 'Lapan', + 'Miah', + 'Coty', + 'Baksh', + 'Beehler', + 'Goel', + 'Wolfinger', + 'Goodhue', + 'Toal', + 'Mattoon', + 'Haq', + 'Nida', + 'Dant', + 'Varnadore', + 'Tippit', + 'Every', + 'Bohling', + 'Lichtenberger', + 'Louk', + 'Soderquist', + 'Werkheiser', + 'Willbanks', + 'Whitis', + 'Millikin', + 'Dietzel', + 'Frase', + 'Ishida', + 'Pilger', + 'Grajales', + 'Kole', + 'Roff', + 'Ballantine', + 'Basden', + 'Cadenas', + 'Caliendo', + 'Hotard', + 'Vidrio', + 'Lichtman', + 'Devinney', + 'Fugitt', + 'Proud', + 'Hults', + 'Galey', + 'Verna', + 'Newburn', + 'Lafortune', + 'Fobbs', + 'Azure', + 'Cheong', + 'Heft', + 'Aispuro', + 'Longstreth', + 'Lajeunesse', + 'Howle', + 'Galley', + 'Lovan', + 'Convery', + 'Malatesta', + 'Warnecke', + 'Glavin', + 'Reil', + 'Filson', + 'Poage', + 'Fountaine', + 'Nolley', + 'Raglin', + 'Backlund', + 'Doerfler', + 'Faunce', + 'Hooton', + 'Lightcap', + 'Stepanek', + 'Grosser', + 'Weld', + 'Filippi', + 'Youn', + 'Matis', + 'Harnett', + 'Ferrill', + 'Segers', + 'Ponds', + 'Cuyler', + 'Faile', + 'Flaugher', + 'Kuehner', + 'Giorgi', + 'Eckler', + 'Sergeant', + 'Twiggs', + 'Boeck', + 'Flach', + 'Iliff', + 'Mcmurtrey', + 'Mcnelis', + 'Steckel', + 'Rouillard', + 'Folkerts', + 'Mechling', + 'Whitcher', + 'Daws', + 'Joly', + 'Abt', + 'Eells', + 'Niccum', + 'Twining', + 'Grinder', + 'Melrose', + 'Yarbro', + 'Degenhardt', + 'Dimeglio', + 'Okamura', + 'Kriss', + 'Payette', + 'Chui', + 'Mowers', + 'Foose', + 'Kinzie', + 'Blick', + 'Rizer', + 'Alcock', + 'Sirmans', + 'Behrman', + 'Carsten', + 'Kopacz', + 'Randhawa', + 'Schwing', + 'Burkhard', + 'Cunanan', + 'Exley', + 'Balducci', + 'Leman', + 'Hyslop', + 'Burtch', + 'Hadnot', + 'Lanphear', + 'Finchum', + 'Voit', + 'Jock', + 'Wilhoite', + 'Officer', + 'Mayweather', + 'Ravenell', + 'Arehart', + 'Bonetti', + 'Cloer', + 'Galliher', + 'Niven', + 'Uyeda', + 'Coughenour', + 'Siddiqi', + 'Karimi', + 'Cupit', + 'Loupe', + 'Hammell', + 'Antley', + 'Ally', + 'Southers', + 'Haymond', + 'Hosley', + 'Broz', + 'Kinoshita', + 'Kohout', + 'Lipke', + 'Ostrow', + 'Teves', + 'Gaus', + 'Meiser', + 'Cravey', + 'Noss', + 'Drayer', + 'Crooms', + 'Carrano', + 'Mckechnie', + 'Uhrich', + 'Villalva', + 'Wilkening', + 'Benevides', + 'Kepple', + 'Pon', + 'Randol', + 'Leadbetter', + 'Russom', + 'Locklin', + 'Battiste', + 'Abundis', + 'Agosta', + 'Bartek', + 'Brillhart', + 'Hoffmaster', + 'Mehr', + 'Spanos', + 'Denker', + 'Kimberling', + 'Schon', + 'Felten', + 'Lightle', + 'Ramseur', + 'Branning', + 'Deblois', + 'Inocencio', + 'Maricle', + 'Nishimoto', + 'Oviatt', + 'Shunk', + 'Taddeo', + 'Villarruel', + 'Otterson', + 'Clune', + 'Seamster', + 'Dandy', + 'Cybulski', + 'Daza', + 'Eastep', + 'Faulhaber', + 'Friedberg', + 'Gentz', + 'Scola', + 'Sebesta', + 'Glinski', + 'Schoon', + 'Graeber', + 'Sinks', + 'Wee', + 'Summerall', + 'Deets', + 'Furnish', + 'Kelemen', + 'Maiorano', + 'Teachout', + 'Paquet', + 'Mcgahey', + 'Kill', + 'Horman', + 'Selders', + 'Cottman', + 'Delfin', + 'Fronk', + 'Seelig', + 'Visco', + 'Briles', + 'Castillon', + 'Suire', + 'Havey', + 'Arner', + 'Farver', + 'Marts', + 'Gean', + 'Hugh', + 'Stoney', + 'Townsel', + 'Sandquist', + 'Neidig', + 'Miser', + 'Leeth', + 'Hocutt', + 'Balcazar', + 'Caporale', + 'Guymon', + 'Horstmann', + 'Miedema', + 'Zickefoose', + 'Casterline', + 'Pfannenstiel', + 'Becht', + 'Myres', + 'Ried', + 'Vallery', + 'Bator', + 'Calise', + 'Cotterman', + 'Desautels', + 'Hinchey', + 'Kostka', + 'Orenstein', + 'Rosenau', + 'Skow', + 'Cuello', + 'Herder', + 'Cure', + 'Eadie', + 'Claggett', + 'Batie', + 'Kirwin', + 'Troia', + 'Sinnett', + 'Books', + 'Maize', + 'Tremble', + 'Sinkler', + 'Gallon', + 'Winkles', + 'Zion', + 'Walt', + 'Pearse', + 'Gathright', + 'Isakson', + 'Saeger', + 'Siegle', + 'Wittwer', + 'Modesto', + 'Bensen', + 'Royals', + 'Mccane', + 'Begaye', + 'Matuszewski', + 'Schrier', + 'Shimko', + 'Torchia', + 'Ausmus', + 'Casazza', + 'Mealer', + 'Yant', + 'Amar', + 'Callas', + 'Depaola', + 'Kintner', + 'Lech', + 'Marsico', + 'Boerger', + 'Rak', + 'Kellen', + 'Kennemer', + 'Carbo', + 'Rennick', + 'Brennen', + 'Dorrough', + 'Shealey', + 'Breyer', + 'Dilks', + 'Geske', + 'Hundt', + 'Occhipinti', + 'Strauser', + 'Schult', + 'Transue', + 'Holding', + 'Vanhorne', + 'Critchlow', + 'Steptoe', + 'Buerger', + 'Claassen', + 'Farinas', + 'Ruland', + 'Holsapple', + 'Mcclintic', + 'Bendel', + 'Muriel', + 'Mckeithan', + 'Shellman', + 'Balzano', + 'Bement', + 'Montesinos', + 'Ringle', + 'Sobotka', + 'Donahoo', + 'Dicker', + 'Harling', + 'Burkley', + 'Browner', + 'Iovino', + 'Kubala', + 'Labriola', + 'Morra', + 'Orloff', + 'Patchen', + 'Recchia', + 'Budge', + 'Glendenning', + 'Nethery', + 'Scholtz', + 'Aybar', + 'Buis', + 'Mattie', + 'Bonsall', + 'Conine', + 'Dettmer', + 'Gerding', + 'Plantz', + 'Vandorn', + 'Tremaine', + 'Ruddick', + 'Murrow', + 'Mceachin', + 'Bridgeforth', + 'Docherty', + 'Hultman', + 'Liechty', + 'Touchton', + 'Yokoyama', + 'Borth', + 'Daoud', + 'Mealy', + 'Hearst', + 'Stalling', + 'Drapeau', + 'Hellwig', + 'Longtin', + 'Rappa', + 'Tormey', + 'Vanantwerp', + 'Sabel', + 'Neagle', + 'Duet', + 'Liebert', + 'Lush', + 'Aly', + 'Behn', + 'Brereton', + 'Atienza', + 'Dubey', + 'Gennaro', + 'Miltenberger', + 'Nitschke', + 'Ragle', + 'Schumm', + 'Tangen', + 'Waibel', + 'Whitham', + 'Stallone', + 'Perritt', + 'Coody', + 'Hinch', + 'Depuy', + 'Dunkelberger', + 'Texeira', + 'Tomita', + 'Diers', + 'Elsasser', + 'Neve', + 'Clendenen', + 'Pettibone', + 'Dobyns', + 'Ciotti', + 'Dodrill', + 'Fridman', + 'Lepine', + 'Nygard', + 'Shreves', + 'Sollenberger', + 'Leinbach', + 'Diazdeleon', + 'Bourget', + 'Ramadan', + 'Allensworth', + 'Scarboro', + 'Prowell', + 'Ghee', + 'Edouard', + 'Duca', + 'Ziebell', + 'Kercher', + 'Greger', + 'Mas', + 'Shier', + 'Branca', + 'Melchior', + 'Cast', + 'Saner', + 'Beswick', + 'Carone', + 'Sobieski', + 'Zweifel', + 'Beahm', + 'Defrank', + 'Krebsbach', + 'Mericle', + 'Mcinnes', + 'Lown', + 'Brumback', + 'Clause', + 'Claborn', + 'Rollin', + 'Montford', + 'Beckles', + 'Grebe', + 'Groesbeck', + 'Guidi', + 'Mathisen', + 'Mukherjee', + 'Rotolo', + 'Seybert', + 'Odegaard', + 'Mackley', + 'Glatt', + 'Going', + 'Perks', + 'Sansbury', + 'Prude', + 'Bequette', + 'Difilippo', + 'Dodgen', + 'Terpening', + 'Vanepps', + 'Poncedeleon', + 'Qu', + 'Ullery', + 'Wisener', + 'Lok', + 'Lutton', + 'Bellah', + 'Kinsel', + 'Tone', + 'Carabajal', + 'Koll', + 'Shankar', + 'Edick', + 'Donathan', + 'Andree', + 'Perrino', + 'Moffit', + 'Gaddie', + 'Breidenbach', + 'Jespersen', + 'Larrick', + 'Mauriello', + 'Morgado', + 'Roh', + 'Svec', + 'Tebbe', + 'Thieman', + 'Cerezo', + 'Perkowski', + 'Colville', + 'Yarnall', + 'Chason', + 'Brach', + 'Meller', + 'Brayboy', + 'Salaam', + 'Keleher', + 'Kilbourn', + 'Lowenthal', + 'Rispoli', + 'Vanzee', + 'Vlahos', + 'Trojan', + 'Birdsell', + 'Defoor', + 'Mcclusky', + 'Barret', + 'Smoke', + 'Berkeley', + 'Cuadrado', + 'Galyean', + 'Gruen', + 'Gualtieri', + 'Kurland', + 'Sposato', + 'Stieber', + 'Weatherman', + 'Strausser', + 'Miera', + 'Edlin', + 'Gilford', + 'Mouzon', + 'Buczek', + 'Krapf', + 'Lucatero', + 'Amburn', + 'Peddicord', + 'Forero', + 'Domer', + 'Farish', + 'Segraves', + 'Sant', + 'Engles', + 'Douthitt', + 'Lall', + 'Wormley', + 'Geisel', + 'Hao', + 'Polhemus', + 'Slifer', + 'Mowen', + 'Markin', + 'Rape', + 'Bollin', + 'Bulloch', + 'Pouncey', + 'Rufus', + 'Goodlow', + 'Dammann', + 'Delgrosso', + 'Gadbois', + 'Leap', + 'Lorentzen', + 'Sprankle', + 'Stucki', + 'Vitela', + 'Walck', + 'Winkelmann', + 'Mund', + 'Bley', + 'Channel', + 'Griebel', + 'Nordberg', + 'Slinkard', + 'Orrick', + 'Crooker', + 'Groll', + 'Maradiaga', + 'Jolin', + 'Boni', + 'Prom', + 'Reder', + 'Easler', + 'Totty', + 'Arnaud', + 'Bohler', + 'Heikkila', + 'Kehler', + 'Klingenberg', + 'Matera', + 'Striegel', + 'Urzua', + 'Baldi', + 'Burling', + 'Osmond', + 'Rucks', + 'Diel', + 'Kassel', + 'Schewe', + 'Conkling', + 'Ricke', + 'Schack', + 'Shirah', + 'Brauner', + 'Carriker', + 'Mcduffy', + 'Bieker', + 'Credeur', + 'Fabry', + 'Holdeman', + 'Jeansonne', + 'Klett', + 'Kolstad', + 'Mustain', + 'Strub', + 'Ricketson', + 'Fairbairn', + 'Langel', + 'Fenster', + 'Slatton', + 'Ehrenberg', + 'Espinola', + 'Hannaford', + 'Hinderliter', + 'Siqueiros', + 'Ange', + 'Gillin', + 'Battin', + 'Belue', + 'Spigner', + 'Simien', + 'Gervasi', + 'Pallares', + 'Plotner', + 'Puri', + 'Swiatek', + 'Vanmatre', + 'Corp', + 'Devillier', + 'Bucholtz', + 'Bremner', + 'Jen', + 'Evanson', + 'Ghent', + 'Eastland', + 'Kappler', + 'Grahn', + 'Shadrick', + 'Kibby', + 'Chaires', + 'Kontos', + 'Petrov', + 'Pillai', + 'Chadbourne', + 'Sotolongo', + 'Allende', + 'Kells', + 'Hayford', + 'Hempstead', + 'Livers', + 'Farrior', + 'Authement', + 'Bitz', + 'Corkery', + 'Klawitter', + 'Mongold', + 'Somma', + 'Topham', + 'Defrancisco', + 'Noda', + 'Breon', + 'Thetford', + 'Rod', + 'Kisling', + 'Drouillard', + 'Dotts', + 'Gramajo', + 'Masek', + 'Volkert', + 'Vora', + 'Pietras', + 'Sheffler', + 'Shrestha', + 'Kono', + 'Panza', + 'Brunn', + 'Tatom', + 'Nasir', + 'Barris', + 'Bursey', + 'Elsea', + 'Kettner', + 'Martorana', + 'Lindow', + 'Chevez', + 'Pater', + 'Hennis', + 'Iman', + 'Stembridge', + 'Satcher', + 'Britz', + 'Hommel', + 'Llanas', + 'Pathak', + 'Schwartzman', + 'Janz', + 'Hickle', + 'Deakins', + 'Mantle', + 'Billing', + 'Veiga', + 'Darbonne', + 'Angelle', + 'Granderson', + 'Odoms', + 'Mondesir', + 'Ducksworth', + 'Anker', + 'Deneen', + 'Follmer', + 'Norred', + 'Whitecotton', + 'Halsted', + 'Schiele', + 'Reddin', + 'Pichon', + 'Eustice', + 'Finelli', + 'Kawasaki', + 'Kerekes', + 'Surrett', + 'Divers', + 'Kerney', + 'Bohlman', + 'Oberst', + 'Prough', + 'Tarwater', + 'Wangler', + 'Piceno', + 'Persico', + 'Lastra', + 'Fillman', + 'Barlett', + 'Cort', + 'Kuchar', + 'Plaisted', + 'Rufo', + 'Whitmarsh', + 'Fusaro', + 'Bajwa', + 'Belter', + 'Aldama', + 'Conlee', + 'Tweedie', + 'Greear', + 'Riviera', + 'Stormer', + 'Flannagan', + 'Heatley', + 'Feazell', + 'Bastidas', + 'Benninger', + 'Canseco', + 'Hanners', + 'Kreiner', + 'Pestana', + 'Simerly', + 'Such', + 'Tiedeman', + 'Weible', + 'Zawadzki', + 'Rayman', + 'Crose', + 'Sheeler', + 'Kirven', + 'Winford', + 'Mackall', + 'Balderson', + 'Calleja', + 'Klinefelter', + 'Lauffer', + 'Probert', + 'Melero', + 'Ravelo', + 'Degroff', + 'Pylant', + 'Ricco', + 'Varona', + 'Pickney', + 'Bachmeier', + 'Dulay', + 'Hanover', + 'Virgilio', + 'Spino', + 'Bohon', + 'Cantin', + 'Pettijohn', + 'Branigan', + 'Duhe', + 'Perine', + 'Thedford', + 'Shamburger', + 'Guarnieri', + 'Guptill', + 'Nyland', + 'Setliff', + 'Shreffler', + 'Viggiano', + 'Pries', + 'Sunde', + 'Bulmer', + 'Platts', + 'Jeremiah', + 'Fawley', + 'Jansson', + 'Rebelo', + 'Prochnow', + 'Waldeck', + 'Citron', + 'Roughton', + 'Ryckman', + 'Molano', + 'Cannaday', + 'Ned', + 'Beckerman', + 'Galaz', + 'Graziani', + 'Kawakami', + 'Limones', + 'Mousseau', + 'Riha', + 'Huser', + 'Casady', + 'Kirker', + 'Benish', + 'Tomczyk', + 'Hallahan', + 'Kue', + 'Siple', + 'Kandel', + 'Maring', + 'Bosak', + 'Gandolfo', + 'Reichart', + 'Robarge', + 'Shufelt', + 'Forry', + 'Richart', + 'Shireman', + 'Tozzi', + 'Trudel', + 'Tat', + 'Maday', + 'Faw', + 'Lawrie', + 'Mingle', + 'Yasin', + 'Cutrone', + 'Fairbrother', + 'Ficken', + 'Kluesner', + 'Lagana', + 'Schoenborn', + 'Greb', + 'Stromain', + 'Mcpeters', + 'Toepfer', + 'Wehrman', + 'Kozma', + 'Rohner', + 'Kittel', + 'Louderback', + 'Daughtrey', + 'Philippe', + 'Bargo', + 'Cullinane', + 'Fama', + 'Fredenburg', + 'Pedone', + 'Santillanes', + 'Zahner', + 'Zupan', + 'Dundon', + 'Gilfillan', + 'Grego', + 'Otter', + 'Jamil', + 'Beaubien', + 'Collingwood', + 'Quinney', + 'Botero', + 'Edstrom', + 'Flink', + 'Ortner', + 'Schmidtke', + 'Reichle', + 'Leder', + 'Pelosi', + 'Fiorito', + 'Berber', + 'Hislop', + 'Dunstan', + 'Favorite', + 'Wooding', + 'Gariepy', + 'Gottesman', + 'Guercio', + 'Konz', + 'Kothari', + 'Laguardia', + 'Lamphier', + 'Puetz', + 'Casagrande', + 'Quay', + 'Rieth', + 'Vowell', + 'Mcanulty', + 'Mian', + 'Lucus', + 'Alvizo', + 'Domanski', + 'Elling', + 'Maniaci', + 'Neumeyer', + 'Piraino', + 'Schroll', + 'Willsey', + 'Avellaneda', + 'Wilcoxen', + 'Murrey', + 'Bennette', + 'Boyajian', + 'Distler', + 'Lindamood', + 'Maclaren', + 'Onken', + 'Stefano', + 'Uselton', + 'Wilgus', + 'Rardin', + 'Boen', + 'Stillwagon', + 'Satter', + 'Allis', + 'Capell', + 'Nedd', + 'Arcand', + 'Breit', + 'Horwath', + 'Lakatos', + 'Roling', + 'Hessel', + 'Cusson', + 'Rockefeller', + 'Shiffer', + 'Briney', + 'Celeste', + 'Sayed', + 'Revelle', + 'Corker', + 'Baldonado', + 'Lokken', + 'Plymale', + 'Sugden', + 'Twist', + 'Parten', + 'Geil', + 'Sime', + 'Grisby', + 'Jeanty', + 'Baroni', + 'Ditullio', + 'Domenico', + 'Geiss', + 'Gemmill', + 'Leng', + 'Lewicki', + 'Weyandt', + 'Haycock', + 'Coonce', + 'Pillar', + 'Medcalf', + 'Sall', + 'Goldsborough', + 'Bergerson', + 'Daffron', + 'Hinchman', + 'Leibold', + 'Sarkissian', + 'Serratos', + 'Uhlig', + 'Wurth', + 'Ost', + 'Steinmann', + 'Saum', + 'Bullion', + 'Dejonge', + 'Assad', + 'Adelson', + 'Sholes', + 'Clermont', + 'Tabron', + 'Kilduff', + 'Millspaugh', + 'Partyka', + 'Santore', + 'Wensel', + 'Zima', + 'Raschke', + 'Simonis', + 'Tuell', + 'Obriant', + 'Lewter', + 'Nealey', + 'Baranski', + 'Bloomberg', + 'Franchi', + 'Klemme', + 'Raborn', + 'Wohlgemuth', + 'Basta', + 'Bernardini', + 'Canlas', + 'Yeargin', + 'Stingley', + 'Crosland', + 'Bob', + 'Ascher', + 'Dibona', + 'Farabaugh', + 'Kilcoyne', + 'Poblete', + 'Beato', + 'Teasdale', + 'Rossell', + 'Lawhorne', + 'Jama', + 'Behringer', + 'Hallstrom', + 'Kitzman', + 'Klenk', + 'Mctigue', + 'Onate', + 'Rodda', + 'Siegal', + 'Pepple', + 'Tash', + 'Gager', + 'Hing', + 'Yokley', + 'Epting', + 'Mangham', + 'Zackery', + 'Blackerby', + 'Canedo', + 'Glatz', + 'Hilker', + 'Hummell', + 'Mangels', + 'Gamel', + 'Gang', + 'Hooser', + 'Moates', + 'Mutch', + 'Lyerly', + 'Vesey', + 'Satterthwaite', + 'Calcote', + 'Saulsbury', + 'Averette', + 'Ates', + 'Rita', + 'Vicencio', + 'Wismer', + 'Mayoral', + 'Crader', + 'Levens', + 'Joel', + 'Haye', + 'Drager', + 'Eiden', + 'Escutia', + 'Inzunza', + 'Moroz', + 'Sepulvado', + 'Tomaselli', + 'Zartman', + 'Isaak', + 'Philippi', + 'Mcgeary', + 'Taha', + 'Buttler', + 'Crisci', + 'Kot', + 'Micek', + 'Mondello', + 'Petrarca', + 'Rossini', + 'Villalvazo', + 'Weedman', + 'Mitten', + 'Favre', + 'Varnes', + 'Betancur', + 'Bevington', + 'Bockman', + 'Feldstein', + 'Kujawski', + 'Siemer', + 'Soderlund', + 'Fricker', + 'Gerstein', + 'Kick', + 'Haff', + 'Brackman', + 'Hulen', + 'Nephew', + 'Birkett', + 'Gardenhire', + 'Garn', + 'Kellenberger', + 'Mogensen', + 'Murata', + 'Weisbrod', + 'Vilchis', + 'Meder', + 'Akey', + 'Mcmanis', + 'Delatte', + 'Guiles', + 'Turnbough', + 'Murrah', + 'Kilgo', + 'Marcelin', + 'Cecchini', + 'Chrysler', + 'Eick', + 'Fletes', + 'Luevanos', + 'Kurt', + 'Firman', + 'Hensen', + 'Champine', + 'Holford', + 'Appelbaum', + 'Ciampa', + 'Florentino', + 'Lorton', + 'Lubinski', + 'Moquin', + 'Welke', + 'Grinberg', + 'Bolstad', + 'Ade', + 'Outten', + 'Grear', + 'Haith', + 'Borntreger', + 'Steinhauser', + 'Facio', + 'Preslar', + 'Speirs', + 'Grasser', + 'Zuck', + 'Deslauriers', + 'Frates', + 'Mayville', + 'Suddeth', + 'Littlepage', + 'Aversa', + 'Chagolla', + 'Godshall', + 'Jordahl', + 'Oakland', + 'Monsen', + 'Rudolf', + 'Mccollister', + 'Mickles', + 'Flaig', + 'Friberg', + 'Grubaugh', + 'Sliwinski', + 'Stach', + 'Bechtol', + 'Pasch', + 'Keebler', + 'Fagin', + 'Mister', + 'Wynter', + 'Bednarek', + 'Blansett', + 'Crossett', + 'Kettering', + 'Lafata', + 'Raffa', + 'Roig', + 'Schopp', + 'Voegele', + 'Waldschmidt', + 'Clatterbuck', + 'Amer', + 'Kraut', + 'Furniss', + 'Edgecomb', + 'Aspinwall', + 'Buckelew', + 'Loranger', + 'Koppel', + 'Vernier', + 'Latino', + 'Hayton', + 'Girod', + 'Primrose', + 'Jetter', + 'Hyche', + 'Ottley', + 'Isidro', + 'Kort', + 'Mulroy', + 'Reznik', + 'Tozer', + 'Vanderheyden', + 'Kassab', + 'Paro', + 'Belen', + 'Vandever', + 'Harsch', + 'Rawley', + 'Gonder', + 'Delbridge', + 'Alumbaugh', + 'Basulto', + 'Hoehne', + 'Mccaig', + 'Qin', + 'Rasnake', + 'Tewksbury', + 'Ratajczak', + 'Reinbold', + 'Mcgillivray', + 'Nuccio', + 'Steinbeck', + 'Deland', + 'Callow', + 'Wootten', + 'Lytton', + 'Calix', + 'Stinger', + 'Slider', + 'Cadman', + 'Faulconer', + 'Higashi', + 'Lamping', + 'Sellner', + 'Walko', + 'Kilkenny', + 'Charter', + 'Gauntt', + 'Bronk', + 'Legare', + 'Hukill', + 'Kulikowski', + 'Kunde', + 'Michelsen', + 'Mottola', + 'Pasion', + 'Stimmel', + 'Deavila', + 'Lian', + 'Koga', + 'Kitchin', + 'Whitner', + 'Bucholz', + 'Kilbride', + 'Klumpp', + 'Osinski', + 'Petrich', + 'Saar', + 'Robards', + 'Flakes', + 'Accardo', + 'Gebauer', + 'Matyas', + 'Montesano', + 'Schiefer', + 'Zuehlke', + 'Swartout', + 'Gidley', + 'Burghardt', + 'Delcambre', + 'Jerman', + 'Laufenberg', + 'Paterno', + 'Piccione', + 'Wenning', + 'Wilhelmi', + 'Rathjen', + 'Bauch', + 'Hiott', + 'Bagnall', + 'Miskell', + 'Snellings', + 'Sally', + 'Bjornson', + 'Din', + 'Kroeker', + 'Mitra', + 'Saxena', + 'Hausler', + 'Scogin', + 'Jeronimo', + 'Holderfield', + 'Cruze', + 'Christina', + 'Beville', + 'Whitehorn', + 'Bembry', + 'Fludd', + 'Abboud', + 'Blomgren', + 'Friddle', + 'Jarvi', + 'Nastasi', + 'Tomich', + 'Peinado', + 'Rinaldo', + 'Proudfoot', + 'Down', + 'Lawry', + 'Noor', + 'Bachelor', + 'Mullenax', + 'Pocock', + 'Resler', + 'Sprunger', + 'Wiegel', + 'Wohlers', + 'Niedzwiecki', + 'Bourgoin', + 'Grist', + 'Nora', + 'Gude', + 'Mcgaughy', + 'Borror', + 'Bushee', + 'Crego', + 'Engberg', + 'Karle', + 'Raso', + 'Rayas', + 'Roehrig', + 'Villamil', + 'Croucher', + 'Candido', + 'Rockhill', + 'Dahn', + 'Philp', + 'Grasty', + 'Basnight', + 'Cacioppo', + 'Heavener', + 'Hoenig', + 'Janisch', + 'Labombard', + 'Sheng', + 'Wettstein', + 'Wymore', + 'Zuluaga', + 'Canova', + 'Maclennan', + 'Tuley', + 'Geddings', + 'Cayetano', + 'Bogar', + 'Malbrough', + 'Bradish', + 'Chiaramonte', + 'Eguia', + 'Loux', + 'Nemecek', + 'Ouimet', + 'Roxas', + 'Yoshioka', + 'Cossio', + 'Sleight', + 'Walla', + 'Younan', + 'Hee', + 'Bartlow', + 'Parchman', + 'Leaks', + 'Folz', + 'Knittel', + 'Lovvorn', + 'Melick', + 'Weingartner', + 'Eustace', + 'Robbs', + 'Jacquet', + 'Direnzo', + 'Domke', + 'Kestler', + 'Pavelka', + 'Pileggi', + 'Silvestro', + 'Leedom', + 'Kyte', + 'Espey', + 'Kincannon', + 'Robicheaux', + 'Lard', + 'Falkenstein', + 'Fino', + 'Kotz', + 'Lammert', + 'Markovic', + 'Mcwaters', + 'Shibata', + 'Garoutte', + 'Brum', + 'Hora', + 'Gundrum', + 'Leer', + 'Coller', + 'Delsignore', + 'Ebarb', + 'Heras', + 'Skolnick', + 'Sponseller', + 'Baltes', + 'Rabinovich', + 'Welden', + 'Papas', + 'Bingman', + 'Neto', + 'Burrough', + 'Ollie', + 'Deitrick', + 'Hermansen', + 'Datta', + 'Gebo', + 'Bulla', + 'Rippey', + 'Solon', + 'Draughon', + 'Sylvestre', + 'Outen', + 'Westfield', + 'Daoust', + 'Kuan', + 'Kubat', + 'Labuda', + 'Olejniczak', + 'Radomski', + 'Scheuermann', + 'Schunk', + 'Tuazon', + 'Wineland', + 'Gizzi', + 'Millay', + 'Hamp', + 'Murdaugh', + 'Hayles', + 'Plowden', + 'Lesure', + 'Artrip', + 'Kenneally', + 'Piehl', + 'Vandermeulen', + 'Camberos', + 'Hochberg', + 'Sinner', + 'Crass', + 'Gade', + 'Tedrick', + 'Nicholl', + 'Speece', + 'Chatterjee', + 'Gillihan', + 'Luzzi', + 'Obyrne', + 'Uchida', + 'Kidney', + 'Dorough', + 'Dangler', + 'Mcneel', + 'Ruley', + 'Mcloud', + 'Smarr', + 'Gayles', + 'Janiszewski', + 'Kubo', + 'Mckibbin', + 'Szatkowski', + 'Lehnert', + 'Mcilvain', + 'Mcclish', + 'Mcentyre', + 'Strawder', + 'Briere', + 'Headlee', + 'Leszczynski', + 'Mauser', + 'Rask', + 'Wisler', + 'Burba', + 'Shaulis', + 'Showman', + 'Proto', + 'Creasman', + 'Slye', + 'Dunwoody', + 'Ellingsworth', + 'Linebaugh', + 'Riva', + 'Um', + 'Muldowney', + 'Burlew', + 'Gettings', + 'Clingman', + 'Shield', + 'Trollinger', + 'Stiger', + 'Kellman', + 'Arviso', + 'Boettger', + 'Deak', + 'Deiter', + 'Hackenberg', + 'Langone', + 'Lichter', + 'Siano', + 'Wrinkle', + 'Dickert', + 'Boor', + 'Ludington', + 'Griffing', + 'Perin', + 'Woodby', + 'Quail', + 'Harriss', + 'Bilotta', + 'Chino', + 'Cocke', + 'Corbell', + 'Dearden', + 'Facundo', + 'Gaskell', + 'Grieser', + 'Houts', + 'Zuk', + 'Yamauchi', + 'Caouette', + 'Perham', + 'Hewson', + 'Keppel', + 'Artiaga', + 'Sa', + 'Ginger', + 'Goosby', + 'Bollig', + 'Grippo', + 'Hoffmeyer', + 'Klaas', + 'Rohlfing', + 'Stolp', + 'Vielma', + 'Gresh', + 'Mignone', + 'Parsell', + 'Sprout', + 'Hase', + 'Nadal', + 'Joye', + 'Butkus', + 'Donlan', + 'Fuhrer', + 'Grobe', + 'Haverkamp', + 'Janecek', + 'Pancoast', + 'Rathke', + 'Scheibe', + 'Schneller', + 'Scally', + 'Valeriano', + 'Fail', + 'Everage', + 'Murff', + 'Demayo', + 'Dieterich', + 'Kramp', + 'Macchia', + 'Ruyle', + 'Zuidema', + 'Tischer', + 'Palo', + 'Bahn', + 'Hartson', + 'Rosborough', + 'Hartke', + 'Hixenbaugh', + 'Matlack', + 'Hoefler', + 'Hsia', + 'Cech', + 'Donham', + 'Szafranski', + 'Jennison', + 'Emmer', + 'Christians', + 'Swigert', + 'Mclawhorn', + 'Costas', + 'Culligan', + 'Eisenstein', + 'Joos', + 'Villacorta', + 'Majerus', + 'Lukowski', + 'Byford', + 'Canepa', + 'Jeppson', + 'Larison', + 'Waechter', + 'Bleich', + 'Trigo', + 'Lill', + 'Mcisaac', + 'Oflaherty', + 'Dedman', + 'Lynes', + 'Everidge', + 'Armfield', + 'Cadieux', + 'Dembowski', + 'Flewelling', + 'Guadagno', + 'Lamendola', + 'Meidinger', + 'Muzzy', + 'Pacelli', + 'Pangle', + 'Denzer', + 'Sharman', + 'Venzor', + 'Shadwick', + 'Saine', + 'Lighty', + 'Twine', + 'Buehner', + 'Caruana', + 'Filipiak', + 'Fiori', + 'Kellison', + 'Odonovan', + 'Ragone', + 'Enyeart', + 'Coale', + 'Coombes', + 'Yarrington', + 'Leno', + 'Coad', + 'Well', + 'Labranche', + 'Banaszak', + 'Jovanovic', + 'Junk', + 'Kratochvil', + 'Marchi', + 'Mcnitt', + 'Monnin', + 'Portales', + 'Nazzaro', + 'Laramie', + 'Kohlman', + 'Pinette', + 'Craw', + 'Aldred', + 'Jolicoeur', + 'Nevers', + 'Boseman', + 'Apostol', + 'Barbaro', + 'Dirienzo', + 'Kimrey', + 'Knaack', + 'Marenco', + 'Meixner', + 'Placek', + 'Prigge', + 'Sablan', + 'Stoecker', + 'Ulrey', + 'Madonia', + 'Mariotti', + 'Hypes', + 'Teti', + 'Pothier', + 'Duer', + 'Reay', + 'Charlie', + 'Alix', + 'Cropp', + 'Wellons', + 'Haugland', + 'Malkowski', + 'Powley', + 'Query', + 'Stolle', + 'Twedt', + 'Grech', + 'Musson', + 'Larrimore', + 'Esper', + 'Suleiman', + 'Gillie', + 'Aaronson', + 'Brueggeman', + 'Kupfer', + 'Orf', + 'Pozzi', + 'Rayos', + 'Scheiner', + 'Schmoll', + 'Sirota', + 'Trickey', + 'Ahuja', + 'Halm', + 'Jaycox', + 'Carithers', + 'Bjorkman', + 'Klar', + 'Lembke', + 'Nordyke', + 'Primeau', + 'Wachs', + 'Wissinger', + 'Doonan', + 'Mikulski', + 'Murthy', + 'Raju', + 'Thrailkill', + 'Splawn', + 'Lockamy', + 'Brassell', + 'Mcshan', + 'Hawbaker', + 'Kracht', + 'Lahman', + 'Lauritsen', + 'Metzner', + 'Presser', + 'Rapoport', + 'Romani', + 'Wolken', + 'Bertone', + 'Bhat', + 'Lenzi', + 'Lefort', + 'Makar', + 'Melnyk', + 'Siguenza', + 'Ristow', + 'Piller', + 'Mcgaugh', + 'Lampton', + 'Delva', + 'Gethers', + 'Leday', + 'Bateson', + 'Beckstrom', + 'Bedsole', + 'Hauber', + 'Hodgkinson', + 'Croghan', + 'Glanz', + 'Gaver', + 'Pinkley', + 'Traynham', + 'Heffley', + 'Indelicato', + 'Lindblad', + 'Petrik', + 'Ptacek', + 'Capen', + 'Carrara', + 'Ortuno', + 'Lobue', + 'Corella', + 'Lybrand', + 'Myler', + 'Steer', + 'Mckamey', + 'Coman', + 'Auker', + 'Escue', + 'Knell', + 'Mahood', + 'Tillinghast', + 'Deremer', + 'Janak', + 'Naegele', + 'Patnaude', + 'Leahey', + 'Pupo', + 'Bouse', + 'Bradstreet', + 'Symes', + 'Callies', + 'Duncanson', + 'Blanche', + 'Span', + 'Shakir', + 'Finneran', + 'Lenker', + 'Mendola', + 'Navin', + 'Palka', + 'Spanier', + 'Stahler', + 'Vannatter', + 'Botta', + 'Gonser', + 'Edelson', + 'Brashier', + 'Golla', + 'Parramore', + 'Bigby', + 'El', + 'Habeck', + 'Kleinhans', + 'Knobel', + 'Pekar', + 'Remmers', + 'Dea', + 'Foo', + 'Plumer', + 'Combest', + 'Godbee', + 'Hilaire', + 'Lepak', + 'Sgro', + 'Vierling', + 'Harm', + 'Holtsclaw', + 'Gaetano', + 'Kindler', + 'Sabbagh', + 'Politte', + 'Amor', + 'Tilly', + 'Trone', + 'Callaham', + 'Roussell', + 'Asplund', + 'Cacciatore', + 'Dries', + 'Friedl', + 'Hartranft', + 'Kimmell', + 'Lengacher', + 'Scardino', + 'Werley', + 'Zappa', + 'Hust', + 'Seiden', + 'Bultman', + 'Withey', + 'Brandow', + 'Oler', + 'Ladouceur', + 'Celli', + 'Condie', + 'Egge', + 'Kleman', + 'Krafft', + 'Margulies', + 'Weier', + 'Mikels', + 'Pavel', + 'Sigel', + 'Foulke', + 'Kluttz', + 'Mcgown', + 'Acero', + 'Gering', + 'Knauff', + 'Ruesch', + 'Rydberg', + 'Shonk', + 'Weisgerber', + 'Wieber', + 'Zinser', + 'Lilienthal', + 'Crosbie', + 'Luckie', + 'Chenier', + 'Aceto', + 'Atnip', + 'Hisey', + 'Imhof', + 'Klocke', + 'Renderos', + 'Schaad', + 'Shoults', + 'Slevin', + 'Tenenbaum', + 'Vrana', + 'Dicesare', + 'Colarusso', + 'Killgore', + 'Courtois', + 'Tysinger', + 'Agard', + 'Brutus', + 'Woodfork', + 'Boeckman', + 'Breitenstein', + 'Downen', + 'Franzese', + 'Garbe', + 'Iannucci', + 'Kist', + 'Mccolgan', + 'Seib', + 'Sereno', + 'Varma', + 'Fought', + 'Barcomb', + 'Happ', + 'Yeaton', + 'Sharples', + 'Huson', + 'Askin', + 'Elliston', + 'Birks', + 'Allums', + 'Richarson', + 'Arterburn', + 'Auyeung', + 'Engman', + 'Segall', + 'Sjoberg', + 'Sturman', + 'Buys', + 'Basford', + 'Gaut', + 'Hollomon', + 'Antal', + 'Groseclose', + 'Motyka', + 'Reddell', + 'Ansel', + 'Fausett', + 'Girgis', + 'Brownson', + 'Pouncy', + 'Behler', + 'Ciesla', + 'Dewall', + 'Helmers', + 'Pizzuto', + 'Sao', + 'Hourigan', + 'Novelli', + 'Kuta', + 'Gau', + 'Verville', + 'Parkison', + 'Souter', + 'Whitelaw', + 'Vercher', + 'Coger', + 'Issac', + 'Cardamone', + 'Heneghan', + 'Herrero', + 'Plancarte', + 'Reach', + 'Sarinana', + 'Zweig', + 'Berkheimer', + 'Brosseau', + 'Angstadt', + 'Popoca', + 'Brode', + 'Presswood', + 'Hannibal', + 'Pigford', + 'Argento', + 'Dieringer', + 'Kinnett', + 'Maclachlan', + 'Perko', + 'Rosenkranz', + 'Kobus', + 'Merk', + 'Prevatte', + 'Kaya', + 'Didio', + 'Thong', + 'Cowin', + 'Tumlin', + 'Lopp', + 'Callier', + 'Sesay', + 'Beerman', + 'Creger', + 'Eyster', + 'Libbey', + 'Minear', + 'Pontious', + 'Stemen', + 'Strahl', + 'Trillo', + 'Dively', + 'Lackner', + 'Welte', + 'Likes', + 'Mazzoni', + 'Resh', + 'Oser', + 'Dilday', + 'Requena', + 'Bail', + 'Ellen', + 'Buchanon', + 'Almeda', + 'Dimino', + 'Griess', + 'Wetzler', + 'Kriegel', + 'Attanasio', + 'Reighard', + 'Alling', + 'Wiginton', + 'Penfield', + 'Barbe', + 'Alred', + 'Ridout', + 'Lucien', + 'Cerullo', + 'Esterline', + 'Garriott', + 'Hendershott', + 'Kaczmarczyk', + 'Pazos', + 'Racicot', + 'Kowaleski', + 'Lippold', + 'Bankert', + 'Emigh', + 'Cupps', + 'Jagger', + 'Leavens', + 'Lies', + 'Ater', + 'Bleau', + 'Pellot', + 'Crosslin', + 'Faulks', + 'Antwine', + 'Calixte', + 'Brod', + 'Hamad', + 'Junkin', + 'Koeppel', + 'Leifer', + 'Vannest', + 'Olcott', + 'Delange', + 'Hillen', + 'Merlin', + 'Gundy', + 'Hogans', + 'Arseneau', + 'Buzard', + 'Ewalt', + 'Persing', + 'Pursel', + 'Rohrs', + 'Sisemore', + 'Vilchez', + 'Bernath', + 'Rosenbalm', + 'Woolverton', + 'Gibbins', + 'Like', + 'Larsson', + 'Savidge', + 'Strohmeyer', + 'Trentham', + 'Wotring', + 'Boster', + 'Sewall', + 'Glore', + 'Burtis', + 'Marchman', + 'Fouche', + 'Okafor', + 'Khatri', + 'Lengel', + 'Pribyl', + 'Rodewald', + 'Cafaro', + 'Mattix', + 'Shingler', + 'Seawell', + 'Square', + 'Belnap', + 'Heidemann', + 'Kretz', + 'Nebeker', + 'Zemke', + 'Reiners', + 'Cassels', + 'Hout', + 'Favor', + 'Rattray', + 'Custard', + 'Bellucci', + 'Bucklew', + 'Casavant', + 'Davanzo', + 'Kleber', + 'Koeppen', + 'Kulpa', + 'Ledonne', + 'Scarano', + 'Schaar', + 'Staiger', + 'Trigueros', + 'Trobaugh', + 'Tufano', + 'Tschetter', + 'Labra', + 'Beverage', + 'Hulet', + 'Stairs', + 'Waggener', + 'Candy', + 'Kaba', + 'Feiner', + 'Ipock', + 'Nelligan', + 'Pottorff', + 'Beno', + 'Beausoleil', + 'Mayen', + 'Kalil', + 'Deller', + 'Cormack', + 'Hayne', + 'Below', + 'Bundick', + 'Avakian', + 'Desmet', + 'Dobler', + 'Dykeman', + 'Eckstrom', + 'Mahle', + 'Meers', + 'Bortner', + 'Kroon', + 'Lindenmuth', + 'Mcnichol', + 'Sechrest', + 'Abdulla', + 'Gaudin', + 'Lamers', + 'Luffman', + 'Marchione', + 'Paredez', + 'Polster', + 'Maresh', + 'Kristoff', + 'Rickel', + 'Frary', + 'Lorance', + 'Round', + 'Toye', + 'Claybrook', + 'Senegal', + 'Gayhart', + 'Mcmackin', + 'Sagan', + 'Sarkar', + 'Whistler', + 'Stutsman', + 'Alderfer', + 'Spainhour', + 'Karol', + 'Ke', + 'Mifflin', + 'Salah', + 'Alberty', + 'Hynson', + 'Beisel', + 'Castelo', + 'Dau', + 'Diliberto', + 'Dollins', + 'Fiorini', + 'Fritzler', + 'Hanan', + 'Hauschild', + 'Overholser', + 'Wrobleski', + 'Peil', + 'Bellon', + 'Buice', + 'Rolls', + 'Shack', + 'Arakelian', + 'Carpino', + 'Liou', + 'Lydick', + 'Supple', + 'Tammaro', + 'Walbridge', + 'Jandreau', + 'Riter', + 'Roeser', + 'Merson', + 'Bole', + 'Franey', + 'Berrett', + 'Carton', + 'Mcnish', + 'Earnhart', + 'Lehrman', + 'Lipski', + 'Mandelbaum', + 'Tanabe', + 'Mirabile', + 'Ocegueda', + 'Clementi', + 'Shake', + 'Buckle', + 'Rowsey', + 'Eifert', + 'Giesen', + 'Standiford', + 'Vallecillo', + 'Walworth', + 'Berkshire', + 'Feit', + 'Lande', + 'Fiddler', + 'Deputy', + 'Feemster', + 'Evelyn', + 'Bocchino', + 'Cozza', + 'Dirocco', + 'Kock', + 'Luisi', + 'Marcantonio', + 'Presti', + 'Rahimi', + 'Ridinger', + 'Sergi', + 'Viana', + 'Kabat', + 'Suriel', + 'Mester', + 'Bozman', + 'Huffines', + 'Linck', + 'Lodato', + 'Ownbey', + 'Pietz', + 'Rudnicki', + 'Schoener', + 'Schrag', + 'Spicher', + 'Sze', + 'Villella', + 'Steinle', + 'Seaberg', + 'Derks', + 'Mavis', + 'Luellen', + 'Garlington', + 'Nimmons', + 'Brevard', + 'Seabrooks', + 'Ahlquist', + 'Golembiewski', + 'Kochis', + 'Popov', + 'Poulter', + 'Redington', + 'Wingrove', + 'Krepps', + 'Viars', + 'Gallatin', + 'Gilham', + 'Jimison', + 'Glosson', + 'Campeau', + 'Goodhart', + 'Koth', + 'Lettieri', + 'Siragusa', + 'Sojka', + 'Tichy', + 'Viar', + 'Carrozza', + 'Chaffins', + 'Eagleson', + 'Prestwood', + 'Deshazer', + 'Ike', + 'Kubacki', + 'Minogue', + 'Sunseri', + 'Turnbaugh', + 'Heminger', + 'Delira', + 'Jani', + 'Platte', + 'Waterson', + 'Keeble', + 'Kiper', + 'Crigler', + 'Swaby', + 'Brisbin', + 'Galiano', + 'Negley', + 'Regal', + 'Stottlemyer', + 'Volkmann', + 'Herrold', + 'Cypert', + 'Markman', + 'Laman', + 'Williard', + 'Terrio', + 'Raulston', + 'Harrow', + 'Humiston', + 'Kantner', + 'Mcmonagle', + 'Polasek', + 'Ruocco', + 'Schelling', + 'Seip', + 'Woller', + 'Despres', + 'Melius', + 'Keiffer', + 'Voges', + 'Figg', + 'Judice', + 'Henery', + 'Dejarnette', + 'Prosper', + 'Duenez', + 'Frenette', + 'Jaimez', + 'Krist', + 'Kuch', + 'Schlachter', + 'Traeger', + 'Mrozinski', + 'Colberg', + 'Lade', + 'Been', + 'Revere', + 'Greely', + 'Belizaire', + 'Amberg', + 'Cerniglia', + 'Lattanzio', + 'Leitz', + 'Ocker', + 'Ratto', + 'Thornburgh', + 'Yule', + 'Hibner', + 'Puerto', + 'Shoultz', + 'Baley', + 'Linley', + 'Alfrey', + 'Bazaldua', + 'Deniz', + 'Lohnes', + 'Marder', + 'Pelland', + 'Urick', + 'Loberg', + 'Rempel', + 'Faux', + 'Tomkins', + 'Gail', + 'Mccardell', + 'Reuben', + 'Brabant', + 'Hutzler', + 'Liedtke', + 'Nowack', + 'Pittsley', + 'Pelc', + 'Darragh', + 'Pae', + 'Blanke', + 'Brinks', + 'Delap', + 'Brea', + 'Milsap', + 'Borneman', + 'Crofts', + 'Nakai', + 'Silguero', + 'Speciale', + 'Martindelcampo', + 'Vandenburg', + 'Wimsatt', + 'Harbor', + 'Mccorvey', + 'Bensinger', + 'Carhart', + 'Condo', + 'Lemen', + 'Malchow', + 'Vandewater', + 'Ventresca', + 'Morena', + 'Mendell', + 'Faustino', + 'Kleiber', + 'Alberson', + 'Lamonte', + 'Kiner', + 'Belgrave', + 'Blitz', + 'Dildine', + 'Gosch', + 'Grabill', + 'Klemp', + 'Larrea', + 'Pallas', + 'Leonhard', + 'Littler', + 'Dilling', + 'Weatherbee', + 'Robnett', + 'Lacount', + 'Brackins', + 'Counterman', + 'Divincenzo', + 'Dobrowolski', + 'Eppard', + 'Estepp', + 'Gahan', + 'Steininger', + 'Tancredi', + 'Wixom', + 'Combes', + 'Dena', + 'Warn', + 'Teems', + 'Askey', + 'Delmar', + 'Ogles', + 'Herriott', + 'Aguinaldo', + 'In', + 'Kinter', + 'Moul', + 'Santaniello', + 'Tringali', + 'Vanasse', + 'Vanwagoner', + 'Whitesel', + 'Vanderwal', + 'Friedmann', + 'Kalis', + 'Cayer', + 'Para', + 'Wander', + 'Cothron', + 'Betters', + 'Cloward', + 'Cusano', + 'Encinias', + 'Imai', + 'Lalone', + 'Saks', + 'Nosal', + 'Crossan', + 'Caverly', + 'Tewell', + 'Lowney', + 'Merle', + 'Meighan', + 'Labat', + 'Pou', + 'Linsey', + 'Gaviria', + 'Manthei', + 'Marquina', + 'Siegert', + 'Blondin', + 'Maskell', + 'Kimpel', + 'Cappel', + 'Tootle', + 'Folkes', + 'Mainor', + 'Offord', + 'Clagg', + 'Minshew', + 'Niebuhr', + 'Schanz', + 'Stotz', + 'Takeda', + 'Huelsman', + 'Madril', + 'Monico', + 'Stradley', + 'Thein', + 'Cannell', + 'Malson', + 'Ludden', + 'Couts', + 'Mishoe', + 'Dales', + 'Slemp', + 'Stueve', + 'Ziemann', + 'Fluke', + 'Vitali', + 'Monn', + 'Dooling', + 'Lambe', + 'Cail', + 'Louder', + 'Lotts', + 'Augusta', + 'Ando', + 'Depaolo', + 'Egolf', + 'Hibdon', + 'Marzan', + 'Mccawley', + 'Mcgivern', + 'Minjares', + 'Mullally', + 'Portner', + 'Vinciguerra', + 'Wolpert', + 'Yingst', + 'Checo', + 'Starck', + 'Ra', + 'Credle', + 'Baldauf', + 'Bamberger', + 'Besch', + 'Caulkins', + 'Huyck', + 'Portela', + 'Walberg', + 'Kutcher', + 'Hunger', + 'Trant', + 'Cumbee', + 'Cheadle', + 'Drewery', + 'Andrada', + 'Dollinger', + 'Dondero', + 'Salvati', + 'Sefton', + 'Siemers', + 'Sitz', + 'Smale', + 'Wenk', + 'Reschke', + 'Puglia', + 'Koob', + 'Overland', + 'Furrer', + 'Gohl', + 'Hegge', + 'Hentschel', + 'Huberty', + 'Krise', + 'Stasiak', + 'Tripoli', + 'Palomera', + 'Norling', + 'Smucker', + 'Hennes', + 'Metro', + 'Himmel', + 'Paolino', + 'Prato', + 'Wommack', + 'Mcpheeters', + 'Ronald', + 'Eppinger', + 'Cantey', + 'Appell', + 'Capellan', + 'Fielden', + 'Garfias', + 'Heit', + 'Janusz', + 'Pagliaro', + 'Pitz', + 'Winegardner', + 'Gregorich', + 'Schlager', + 'Selvidge', + 'Shultis', + 'Severn', + 'Buffum', + 'Crafts', + 'Antony', + 'Timpson', + 'Deveaux', + 'Maese', + 'Merlos', + 'Mojarro', + 'Policastro', + 'Tawil', + 'Flamm', + 'Aasen', + 'Lipkin', + 'Dyches', + 'Caulk', + 'Rampersad', + 'Pettie', + 'Hagwood', + 'Jedlicka', + 'Paoli', + 'Perkey', + 'Shaub', + 'Vires', + 'Glad', + 'Mandrell', + 'Angeli', + 'Antuna', + 'Bessler', + 'Cebula', + 'Heagy', + 'Mankowski', + 'Sitler', + 'Vanleuven', + 'Blanck', + 'Dannenberg', + 'Moren', + 'Hites', + 'Leckie', + 'Tham', + 'Dower', + 'Beans', + 'Alls', + 'Sipp', + 'Dygert', + 'Kubicek', + 'Matsumura', + 'Shiroma', + 'Smiddy', + 'Szilagyi', + 'Winkleman', + 'Zentz', + 'Niehoff', + 'Boedeker', + 'Dimmitt', + 'Trew', + 'Wilner', + 'Traughber', + 'Bardales', + 'Borbon', + 'Bramhall', + 'Crofoot', + 'Desilets', + 'Disch', + 'Kehrer', + 'Leffingwell', + 'Olalde', + 'Wawrzyniak', + 'Jagodzinski', + 'Schwerin', + 'Heiney', + 'Hirano', + 'Rueter', + 'Sarris', + 'Magnan', + 'Rigsbee', + 'Blay', + 'Edgeworth', + 'Hafford', + 'Legrande', + 'Netter', + 'Dulac', + 'Etherington', + 'Gaede', + 'Matranga', + 'Misch', + 'Gryder', + 'Kolman', + 'Reyer', + 'Landsman', + 'Huppert', + 'Steagall', + 'Heims', + 'Baldini', + 'Breithaupt', + 'Claypoole', + 'Feuer', + 'Heishman', + 'Pallotta', + 'Sponaugle', + 'Pershing', + 'Spaid', + 'Salt', + 'Giger', + 'Whetsel', + 'Balaban', + 'Baus', + 'Croke', + 'Heimer', + 'Milnes', + 'Onstott', + 'Wagman', + 'Magro', + 'Havlik', + 'Menge', + 'Talmage', + 'Aungst', + 'Dichiara', + 'Kuhr', + 'Milstein', + 'Sinatra', + 'Speiser', + 'Vise', + 'Panther', + 'Phair', + 'Commons', + 'Mincy', + 'Ashline', + 'Eagen', + 'Enns', + 'Epler', + 'Giltner', + 'Rexroat', + 'Schein', + 'Wellner', + 'Wickert', + 'Ardito', + 'Ihrig', + 'Schuerman', + 'Wentland', + 'Wohlford', + 'Stoy', + 'Kohan', + 'Ratley', + 'Hazell', + 'Coppin', + 'Blackshire', + 'Coolbaugh', + 'Essman', + 'Gandee', + 'Moccia', + 'Mullarkey', + 'Sugrue', + 'Woomer', + 'Arriaza', + 'Pipitone', + 'Heart', + 'Prothro', + 'Connaughton', + 'Covelli', + 'Lunger', + 'Mcilroy', + 'Morataya', + 'Swedberg', + 'Trembley', + 'Wiederhold', + 'Zappia', + 'Perret', + 'Glander', + 'Snedden', + 'Stonestreet', + 'Archey', + 'Arbour', + 'Cordaro', + 'Diskin', + 'Dumlao', + 'Fravel', + 'Spagnuolo', + 'Derossett', + 'Grigorian', + 'Mercadante', + 'Harcourt', + 'Norgaard', + 'Terhaar', + 'Touch', + 'Mccubbins', + 'Tadros', + 'Zabriskie', + 'Fontanilla', + 'Ruse', + 'Springsteen', + 'Getter', + 'Berrian', + 'Louissaint', + 'Cobbins', + 'Dorney', + 'Kugel', + 'Luth', + 'Poffenberger', + 'Sidoti', + 'Steinfeld', + 'Poley', + 'Dreger', + 'Ertl', + 'Capper', + 'Laswell', + 'Spragg', + 'Coltrane', + 'Winborne', + 'Langhorne', + 'Fambro', + 'Berkebile', + 'Bosserman', + 'Cygan', + 'Debonis', + 'Munsch', + 'Pflug', + 'Skowron', + 'Ediger', + 'Bosler', + 'Morden', + 'Virtue', + 'Orso', + 'Claire', + 'Damas', + 'Eichenlaub', + 'Gatchell', + 'Mikus', + 'Tjaden', + 'Tremper', + 'Tusing', + 'Longest', + 'Baires', + 'Dobos', + 'Deforge', + 'Kawa', + 'Hodder', + 'Thornell', + 'Mcgarrity', + 'Gotcher', + 'Judah', + 'Busey', + 'Perrier', + 'Hawthorn', + 'Captain', + 'Costlow', + 'Frohlich', + 'Gulla', + 'Hildebrant', + 'Hilgendorf', + 'Ramachandran', + 'Reaume', + 'Vollrath', + 'Lambertson', + 'Wyer', + 'Coit', + 'Dietsch', + 'Struve', + 'Vicario', + 'Ahlberg', + 'Warshaw', + 'Ryon', + 'Evatt', + 'Mobbs', + 'Gartin', + 'Kenley', + 'Marcell', + 'Bumpers', + 'Jans', + 'Karczewski', + 'Mazurkiewicz', + 'Nadolny', + 'Verrill', + 'Sitter', + 'Freyer', + 'Hindle', + 'Hergert', + 'Inda', + 'Magwood', + 'Basa', + 'Covello', + 'Pacini', + 'Ruoff', + 'Schenker', + 'Zwicker', + 'Popovic', + 'Augustyn', + 'Sutera', + 'Almy', + 'Keisler', + 'Vowels', + 'Lemond', + 'Abila', + 'Beardslee', + 'Benvenuto', + 'Deschaine', + 'Hodel', + 'Turbyfill', + 'Vejar', + 'Iddings', + 'Labrada', + 'Bowne', + 'Seel', + 'Stretch', + 'Haswell', + 'Rickerson', + 'Speas', + 'Southward', + 'Tony', + 'Burrier', + 'Casco', + 'Lorch', + 'Pietrowski', + 'Rabbitt', + 'Sefcik', + 'Trenary', + 'Trisler', + 'Zarazua', + 'Kube', + 'Riera', + 'Stmarie', + 'Starns', + 'Carmel', + 'Shire', + 'Britto', + 'Lacks', + 'Cifelli', + 'Dusenberry', + 'Lusher', + 'Mattioli', + 'Quiring', + 'Regner', + 'Shetty', + 'Stober', + 'Winemiller', + 'Zinke', + 'Heffington', + 'Santelli', + 'Figeroa', + 'Dishon', + 'Doble', + 'Canino', + 'Tahir', + 'Stamant', + 'Sharpton', + 'Sancho', + 'Linzy', + 'Ba', + 'Bonebrake', + 'Frenkel', + 'Irion', + 'Marines', + 'Lacava', + 'Drennon', + 'Fallen', + 'Whiten', + 'Bielawski', + 'Brasch', + 'Eichorn', + 'Gattuso', + 'Neis', + 'Tkach', + 'Usrey', + 'Walkowiak', + 'Dorame', + 'Orem', + 'Crombie', + 'Lowes', + 'Truscott', + 'Marlette', + 'Bushell', + 'Gosa', + 'Hillary', + 'Byfield', + 'Engdahl', + 'Ganser', + 'Hollars', + 'Lambros', + 'Matzen', + 'Moldovan', + 'Najarian', + 'Schoff', + 'Soo', + 'Spargo', + 'Wierenga', + 'Maysonet', + 'Dewan', + 'Bardo', + 'Figgs', + 'Bostian', + 'Graser', + 'Pecor', + 'Rodrigo', + 'Spilker', + 'Suen', + 'Nafziger', + 'Khouri', + 'Milling', + 'Benke', + 'Chapdelaine', + 'Darwish', + 'Merrigan', + 'Narayanan', + 'Neuner', + 'Wallman', + 'Caracciolo', + 'Uren', + 'Borge', + 'Garside', + 'Veasley', + 'Arquette', + 'Gastineau', + 'Helbling', + 'Maggiore', + 'Prell', + 'Vangelder', + 'Giaquinto', + 'Macha', + 'Jonsson', + 'Febus', + 'Lady', + 'Hughson', + 'Wickliffe', + 'Archila', + 'Bearce', + 'Harstad', + 'Krein', + 'Kulesza', + 'Levitan', + 'Nakasone', + 'Saraceno', + 'Stankus', + 'Shelden', + 'Hopping', + 'Diab', + 'Agar', + 'Mcpike', + 'Betterton', + 'Buzbee', + 'Dieguez', + 'Lins', + 'Phuong', + 'Pinegar', + 'Postel', + 'Beatrice', + 'Biddy', + 'Over', + 'Riding', + 'Rials', + 'Rance', + 'Simington', + 'Degraffenreid', + 'Sherard', + 'Clum', + 'Harkin', + 'Mallen', + 'Messerschmidt', + 'Patz', + 'Shatzer', + 'Stetz', + 'Beckert', + 'Worm', + 'Belmontes', + 'Narron', + 'Lyne', + 'Mckendrick', + 'Rester', + 'Archbold', + 'Whorley', + 'Monts', + 'Crapo', + 'Gribbin', + 'Lamborn', + 'Leverenz', + 'Mccarville', + 'Nishida', + 'Ryberg', + 'Smeal', + 'Piontek', + 'Routhier', + 'Willmon', + 'Proffit', + 'Sharrock', + 'Gasque', + 'Minott', + 'Corpening', + 'Capizzi', + 'Dubuc', + 'Gurevich', + 'Hohenstein', + 'Kotch', + 'Peper', + 'Rehbein', + 'Stortz', + 'Corvin', + 'Savant', + 'Ryle', + 'Madere', + 'Firmin', + 'Bitterman', + 'Bruso', + 'Guzzi', + 'Hefty', + 'Almada', + 'Mcninch', + 'Mangin', + 'On', + 'Hardage', + 'Garson', + 'Hisle', + 'Dease', + 'Critelli', + 'Digennaro', + 'Ehle', + 'Freestone', + 'Grieb', + 'Haubert', + 'Kelsay', + 'Loughman', + 'Neth', + 'Pen', + 'Ranta', + 'Sater', + 'Tomei', + 'Castiglia', + 'Kosek', + 'Zentner', + 'Nowland', + 'Klinedinst', + 'Karls', + 'Charon', + 'Cart', + 'Umphrey', + 'Laramore', + 'Mckenny', + 'Hamler', + 'Stoudemire', + 'Diercks', + 'Hodzic', + 'Huntzinger', + 'Runde', + 'Scavone', + 'Halbach', + 'Banales', + 'Thiry', + 'Waterfield', + 'Bebee', + 'Dass', + 'Caughman', + 'Admire', + 'Attebery', + 'Faubion', + 'Friess', + 'Goldsworthy', + 'Raburn', + 'Vantine', + 'Newswanger', + 'Manhart', + 'Grecco', + 'Meany', + 'Rumpf', + 'Dunlevy', + 'Franceschi', + 'Romanski', + 'Alwine', + 'Cahall', + 'Czaja', + 'Krawiec', + 'Mikolajczyk', + 'Neyman', + 'Perrotti', + 'Weideman', + 'Coppa', + 'Ingerson', + 'Avena', + 'Crunk', + 'Cadenhead', + 'Gittings', + 'Gloss', + 'Trowell', + 'Denard', + 'Funchess', + 'Kinnamon', + 'Mailhot', + 'Mollohan', + 'Polacek', + 'Pozos', + 'Rempe', + 'Schutter', + 'Shimkus', + 'Bedrosian', + 'Beede', + 'Conry', + 'Legan', + 'Pickford', + 'Chamblin', + 'Depinto', + 'Geibel', + 'Gilpatrick', + 'Hashmi', + 'Hermsen', + 'Petruzzi', + 'Robben', + 'Sorkin', + 'Gambardella', + 'Podgorski', + 'Langenfeld', + 'Yanke', + 'Zipperer', + 'Tillson', + 'Ariola', + 'Kelman', + 'Hert', + 'Fearn', + 'Goods', + 'Cervenka', + 'Kreft', + 'Kreidler', + 'Kuhar', + 'Leffew', + 'Maziarz', + 'Vollmar', + 'Zmuda', + 'Eisenhower', + 'Yelle', + 'Bhagat', + 'Kirst', + 'Gilkerson', + 'Kindel', + 'Argyle', + 'Bedingfield', + 'Manney', + 'Guion', + 'Rencher', + 'Plater', + 'Beitzel', + 'Camero', + 'Delaluz', + 'Fennelly', + 'Keenum', + 'Kingrey', + 'Mckillop', + 'Munyon', + 'Rorick', + 'Schrimsher', + 'Sohl', + 'Torbett', + 'Lynde', + 'Reiland', + 'Shepley', + 'Cudney', + 'Cather', + 'Abed', + 'Holen', + 'Jobson', + 'Husbands', + 'Marc', + 'Blatz', + 'Feucht', + 'Gunkel', + 'Margolin', + 'Messerly', + 'Womer', + 'Teston', + 'Ditch', + 'Marta', + 'Osier', + 'Awan', + 'Marcella', + 'Silvester', + 'Baugus', + 'Wilcoxon', + 'Nowling', + 'Torain', + 'Badalamenti', + 'Bartosh', + 'Czajka', + 'Savedra', + 'Shaker', + 'Shambaugh', + 'Stapley', + 'Goeke', + 'Schepers', + 'Tyo', + 'Rhodus', + 'Arencibia', + 'Kara', + 'Aitchison', + 'Parlin', + 'Benny', + 'Shakespeare', + 'Altomare', + 'Axe', + 'Bednarczyk', + 'Feasel', + 'Heikkinen', + 'Heyl', + 'Konecny', + 'Montalbo', + 'Semones', + 'Zuercher', + 'Dorrance', + 'Gehrig', + 'Kretzer', + 'Puchalski', + 'Asche', + 'Astacio', + 'Steers', + 'Jeanes', + 'Bamberg', + 'Matthis', + 'Maultsby', + 'Bunkley', + 'Afonso', + 'Danielsen', + 'Freier', + 'Graeff', + 'Gutknecht', + 'Jansky', + 'Lindenberg', + 'Macphee', + 'Pequeno', + 'Petrocelli', + 'Petrowski', + 'Prete', + 'Igoe', + 'Demonte', + 'Khatib', + 'Agin', + 'Siddall', + 'Mcdill', + 'Higginbottom', + 'Gallow', + 'Inniss', + 'Ballman', + 'Bieniek', + 'Casino', + 'Garringer', + 'Griese', + 'Heritage', + 'Zeitz', + 'Montanaro', + 'Qi', + 'Belcastro', + 'Brautigam', + 'Wakeland', + 'Keasler', + 'Oglesbee', + 'Saye', + 'Steppe', + 'Cichocki', + 'Melgarejo', + 'Primavera', + 'Rippe', + 'Sieger', + 'Stutes', + 'Tustin', + 'Vanloon', + 'Konkol', + 'Altmann', + 'Anderegg', + 'Bun', + 'Mcduffee', + 'Deo', + 'Persad', + 'Kindell', + 'Antillon', + 'Ast', + 'Kumm', + 'Lauricella', + 'Minkler', + 'Pilch', + 'Porreca', + 'Shoopman', + 'Skeels', + 'Chanthavong', + 'Hounshell', + 'Pitner', + 'Space', + 'Blackley', + 'Groomes', + 'Bleeker', + 'Duddy', + 'Inlow', + 'Knabe', + 'Lehmkuhl', + 'Salais', + 'Statz', + 'Sundin', + 'Woolston', + 'Hojnacki', + 'Drolet', + 'Gallivan', + 'Viner', + 'Hafley', + 'Hollan', + 'Phillis', + 'Montrose', + 'Colclough', + 'Coaxum', + 'Basel', + 'Campoverde', + 'Cirelli', + 'Delmonico', + 'Goh', + 'Goyal', + 'Hungate', + 'Lufkin', + 'Passaro', + 'Penta', + 'Quispe', + 'Ovalles', + 'Bulkley', + 'Show', + 'Purington', + 'Sockwell', + 'Mccluney', + 'Asato', + 'Buchta', + 'Cassara', + 'Cesena', + 'Empey', + 'Fass', + 'Gazda', + 'Giannetti', + 'Giuffre', + 'Jahns', + 'Jong', + 'Ruh', + 'Schmieder', + 'Sheerin', + 'Weinheimer', + 'Iwamoto', + 'Ouyang', + 'Uranga', + 'Ranalli', + 'Woolum', + 'Calabria', + 'Arrowsmith', + 'Cashen', + 'Vogan', + 'Giffen', + 'Sherk', + 'Denner', + 'Lanclos', + 'Whittlesey', + 'Dora', + 'Plain', + 'Bransford', + 'Bradwell', + 'Davitt', + 'Dehoff', + 'Lotito', + 'Roell', + 'Satterly', + 'Stahr', + 'Thiem', + 'Helberg', + 'Vause', + 'Willmore', + 'Seid', + 'Linebarger', + 'Geddis', + 'Bringhurst', + 'Damelio', + 'Fetterolf', + 'Galban', + 'Henkle', + 'Kamen', + 'Kaneko', + 'Kissane', + 'Rua', + 'Tehrani', + 'Tingey', + 'Lizardi', + 'Strick', + 'Halper', + 'Striker', + 'Amason', + 'Lesueur', + 'Tatem', + 'Bulluck', + 'Hobdy', + 'Flythe', + 'Brookover', + 'Fishbein', + 'Hartless', + 'Snelgrove', + 'Weikert', + 'Wissman', + 'Bourbeau', + 'Colclasure', + 'Sampley', + 'Shubin', + 'Rhoda', + 'Mcclane', + 'Meals', + 'Peets', + 'Anding', + 'Clewis', + 'Gaymon', + 'Bierly', + 'Brockmeyer', + 'Burnworth', + 'Dierking', + 'Patzer', + 'Seipel', + 'Shieh', + 'Pazmino', + 'Bailie', + 'Ducey', + 'Sessler', + 'Hornaday', + 'Andry', + 'Mowatt', + 'Charlot', + 'Buchholtz', + 'Gaulke', + 'Gondek', + 'Grossmann', + 'Hammerschmidt', + 'Heinle', + 'Huckabay', + 'Neathery', + 'Vanzile', + 'Vossler', + 'Schillaci', + 'Lem', + 'Paff', + 'Oja', + 'Broker', + 'Marlett', + 'Innocent', + 'Adsit', + 'Begg', + 'Kocian', + 'Maddalena', + 'Melamed', + 'Mikos', + 'Pio', + 'Poth', + 'Richwine', + 'Ruda', + 'Sackman', + 'Querry', + 'Padro', + 'Sober', + 'Ayscue', + 'Puff', + 'Hunton', + 'Woltz', + 'Alsobrook', + 'Baskins', + 'Daggs', + 'Brands', + 'Buechel', + 'Gonda', + 'Haberkorn', + 'Hartel', + 'Hazeltine', + 'Lantrip', + 'Leoni', + 'Licona', + 'Stanke', + 'Zwart', + 'Aplin', + 'Leatham', + 'Ace', + 'Ganter', + 'Bartolomeo', + 'Colgrove', + 'Halling', + 'Hesler', + 'Hainline', + 'Susi', + 'Kroner', + 'Sanden', + 'Rylander', + 'Basaldua', + 'Fujiwara', + 'Hengst', + 'Kapur', + 'Kienzle', + 'Miao', + 'Mutschler', + 'Orsi', + 'Pais', + 'Termini', + 'Yamane', + 'Zipp', + 'Wildey', + 'Bauerle', + 'Rehn', + 'Hipsher', + 'Staubin', + 'Esquilin', + 'Goley', + 'Buenaventura', + 'Frutos', + 'Gaugler', + 'Maclellan', + 'Mehring', + 'Stiers', + 'Gearheart', + 'Bong', + 'Maddocks', + 'Canary', + 'Urie', + 'Skillings', + 'Amir', + 'Bogus', + 'Oakman', + 'Barresi', + 'Cappelli', + 'Clausing', + 'Genest', + 'Grella', + 'Mulherin', + 'Roettger', + 'Corle', + 'Mantel', + 'Mody', + 'Delapp', + 'Dunnington', + 'Harvard', + 'Berquist', + 'Foglia', + 'Gilbride', + 'Krenek', + 'Gagnier', + 'Berney', + 'Bazzell', + 'Selvage', + 'Gullette', + 'Lavan', + 'Gunderman', + 'Holaday', + 'Horine', + 'Salata', + 'Slaybaugh', + 'Tobia', + 'Knick', + 'Tinkle', + 'Calcaterra', + 'Fauth', + 'Helmke', + 'Margiotta', + 'Mejorado', + 'Salomone', + 'Sevy', + 'Suri', + 'Vasconcellos', + 'Vetrano', + 'Flaten', + 'Sweetser', + 'Logston', + 'Varon', + 'Allsop', + 'Mickler', + 'Swails', + 'Conejo', + 'Derosia', + 'Hamre', + 'Hanvey', + 'Holscher', + 'Interiano', + 'Kleinberg', + 'Kravetz', + 'Reinking', + 'Schow', + 'Schur', + 'Vanbrocklin', + 'Yinger', + 'Zelenka', + 'Chagoya', + 'Sieben', + 'Devora', + 'Archambeau', + 'Burpee', + 'Shamp', + 'Stander', + 'Weaks', + 'Viney', + 'Halloway', + 'Artiga', + 'Clinkenbeard', + 'Kenison', + 'Loeza', + 'Schaap', + 'Simoni', + 'Frock', + 'Galea', + 'Graven', + 'Brookhart', + 'Gurr', + 'Mackintosh', + 'Arjona', + 'Busche', + 'Salvi', + 'Bedenbaugh', + 'Duan', + 'Clara', + 'Brundidge', + 'Akhter', + 'Amsler', + 'Bolz', + 'Bonura', + 'Brumbelow', + 'Droste', + 'Lohmeyer', + 'Lorah', + 'Louthan', + 'Botti', + 'Feigenbaum', + 'Thon', + 'Osbourn', + 'Peugh', + 'Viau', + 'Elsayed', + 'Hilyard', + 'Coram', + 'Alvin', + 'Milbourne', + 'Hickmon', + 'Basu', + 'Fasnacht', + 'Heathcock', + 'Matsui', + 'Oyama', + 'Stransky', + 'Blakesley', + 'Antes', + 'Flury', + 'Lacrosse', + 'Lull', + 'Clelland', + 'Rugh', + 'Hamelin', + 'Reta', + 'Barnet', + 'Ballow', + 'Pyburn', + 'Slayden', + 'Freshwater', + 'Fomby', + 'Bourquin', + 'Bowersock', + 'Calleros', + 'Dallmann', + 'Gootee', + 'Koelling', + 'Parfitt', + 'Pruss', + 'Tretter', + 'Bellini', + 'Gulden', + 'Pett', + 'Mcglasson', + 'Yerby', + 'Buth', + 'Curnow', + 'Goller', + 'Halderman', + 'Kulig', + 'Laue', + 'Roesner', + 'Samra', + 'Sorrow', + 'Vanbibber', + 'Mellin', + 'Villacis', + 'Hilborn', + 'Ditty', + 'Vasey', + 'Crall', + 'Sera', + 'Honeywell', + 'Blanchet', + 'Halim', + 'Nevius', + 'Ines', + 'Stuard', + 'Birr', + 'Curnutt', + 'Deibler', + 'Jaster', + 'Ouk', + 'Poppell', + 'Provence', + 'Rebman', + 'Schmick', + 'Terra', + 'Zea', + 'Hoven', + 'Loth', + 'Arreaga', + 'Cambre', + 'Roots', + 'Gains', + 'Jeancharles', + 'Cerritos', + 'Ihle', + 'Zambito', + 'Brueggemann', + 'Kluth', + 'Schwartzkopf', + 'Shott', + 'Mcglaughlin', + 'Decoster', + 'Northam', + 'Esau', + 'Fling', + 'Castile', + 'Milledge', + 'Desjarlais', + 'Laframboise', + 'Remigio', + 'Rudloff', + 'Utecht', + 'Enrique', + 'Wygant', + 'Fairbank', + 'Behl', + 'Meuse', + 'Pyke', + 'Fury', + 'Chowning', + 'Hyndman', + 'Donat', + 'Nuckles', + 'Cartledge', + 'Bilal', + 'Antonacci', + 'Huether', + 'Kha', + 'Mascia', + 'Rothberg', + 'Sieck', + 'Younes', + 'Sassaman', + 'Amparan', + 'Benesh', + 'Faraci', + 'Gaber', + 'Lehew', + 'Belzer', + 'Segoviano', + 'Teagle', + 'Burian', + 'Menne', + 'Niemeier', + 'Old', + 'Olenick', + 'Takemoto', + 'Tepe', + 'Test', + 'Zahler', + 'Matsuoka', + 'Hopf', + 'Misenheimer', + 'Mings', + 'Hullett', + 'Beutel', + 'Criscuolo', + 'Fedak', + 'Holtkamp', + 'Kretschmer', + 'Mongillo', + 'Mulrooney', + 'Panganiban', + 'Pollick', + 'Sgroi', + 'Shirkey', + 'Stodola', + 'Tozier', + 'Weidler', + 'Puskar', + 'Fiorello', + 'Stille', + 'Pomales', + 'Gladding', + 'Griffie', + 'Warmack', + 'Uzzell', + 'Stennis', + 'Buttrey', + 'Ekberg', + 'Harmsen', + 'Lieske', + 'Madriz', + 'Mohs', + 'Reininger', + 'Edgin', + 'Galla', + 'Chattin', + 'Frayer', + 'Brents', + 'Lasker', + 'Angelone', + 'Boulter', + 'Burritt', + 'Choudhry', + 'Claffey', + 'Elizarraras', + 'Gaumer', + 'Gawronski', + 'Henwood', + 'Lapine', + 'Bitar', + 'Himel', + 'Almand', + 'Brase', + 'Lala', + 'Salama', + 'Essick', + 'Longman', + 'Mone', + 'Reynard', + 'Brackney', + 'Cottam', + 'Donadio', + 'Geesey', + 'Laudenslager', + 'Mcgilvray', + 'Yano', + 'Bueche', + 'Irey', + 'Carneal', + 'Tinder', + 'Walke', + 'Baston', + 'Segar', + 'Brisbane', + 'Venson', + 'Arguijo', + 'Beitler', + 'Burek', + 'Burgener', + 'Collyer', + 'Donlin', + 'Duhaime', + 'Dworak', + 'Frech', + 'Kozik', + 'Montejo', + 'Nhan', + 'Quirarte', + 'Tram', + 'Deshpande', + 'Silverthorn', + 'Leard', + 'Sheller', + 'Alphin', + 'Boxer', + 'Shawn', + 'Pinnick', + 'Stigler', + 'Arpin', + 'Falkenberg', + 'Gerig', + 'Lemonds', + 'Salm', + 'Sarkis', + 'Paprocki', + 'Probasco', + 'Haithcock', + 'Carn', + 'Farrish', + 'Haliburton', + 'Copen', + 'Pieri', + 'Slaymaker', + 'Cardarelli', + 'Veneziano', + 'Melfi', + 'Solley', + 'Hymer', + 'Pleitez', + 'Hinsley', + 'Bruen', + 'Arita', + 'Dreisbach', + 'Fichtner', + 'Keckler', + 'Slaby', + 'Tanguma', + 'Wiberg', + 'Ferrucci', + 'Lick', + 'Maginnis', + 'Quaranta', + 'Bera', + 'Maybee', + 'Hennessee', + 'Kerrick', + 'Kabir', + 'Branscome', + 'Fullington', + 'Menser', + 'Brooking', + 'Patridge', + 'Gue', + 'Gowens', + 'Redus', + 'Ector', + 'Distasio', + 'Kissner', + 'Prada', + 'Sponsler', + 'Tempel', + 'Wedemeyer', + 'Degler', + 'Bodenhamer', + 'Sherbert', + 'Jefferis', + 'Belgarde', + 'Bevel', + 'Figaro', + 'Bertino', + 'Fabbri', + 'Kovacevic', + 'Kunst', + 'Leja', + 'Ruffo', + 'Stearman', + 'Trickett', + 'Zafar', + 'Valdivieso', + 'Curbelo', + 'Mabee', + 'Emma', + 'Arman', + 'Swasey', + 'Lyday', + 'Muff', + 'Rideaux', + 'Ahlgren', + 'Cobo', + 'Hanratty', + 'Litwiller', + 'Mallonee', + 'Glunt', + 'Moudy', + 'Hickam', + 'Mahmud', + 'Fate', + 'Hemsley', + 'Biery', + 'Buechner', + 'Fragale', + 'Hornbaker', + 'Lacorte', + 'Mateos', + 'Mickley', + 'Reusch', + 'Sabado', + 'Schnurr', + 'Gasior', + 'Konkle', + 'Okazaki', + 'Doubleday', + 'Couvillion', + 'Lupien', + 'Oder', + 'Ohair', + 'Win', + 'Quaintance', + 'Diltz', + 'Poythress', + 'Percell', + 'Weatherall', + 'Ainslie', + 'Brandner', + 'Byrge', + 'Cawood', + 'Heatwole', + 'Kerschner', + 'Looker', + 'Racz', + 'Skirvin', + 'Steitz', + 'Svenson', + 'Vermette', + 'Zupancic', + 'Monnier', + 'Scafidi', + 'Trousdale', + 'Bares', + 'Costantini', + 'Frees', + 'Kallio', + 'Methvin', + 'Prudencio', + 'Hayse', + 'Mahabir', + 'Wafford', + 'Borgmann', + 'Cogley', + 'Gigante', + 'Kurkowski', + 'Lavoy', + 'Wertheimer', + 'Wienke', + 'Goodling', + 'Danek', + 'Brinley', + 'Charlson', + 'Whitsell', + 'Lowen', + 'Minnix', + 'Lowers', + 'Palin', + 'Burgher', + 'Lorick', + 'Sobers', + 'Gavigan', + 'Italiano', + 'Liebl', + 'Prevette', + 'Wehunt', + 'Radin', + 'Guillotte', + 'Mode', + 'Halfacre', + 'Stjames', + 'Isabelle', + 'Meggs', + 'Burkard', + 'Giannotti', + 'Justo', + 'Kasprzyk', + 'Kuba', + 'Mino', + 'Morganti', + 'Schnelle', + 'Serfass', + 'Yacoub', + 'Thode', + 'Wykoff', + 'Macbeth', + 'Oxner', + 'Mayhue', + 'Saulter', + 'Budnik', + 'Gandarilla', + 'Michalec', + 'Eisel', + 'Newmark', + 'Placido', + 'Bellar', + 'Dollarhide', + 'Huett', + 'Copher', + 'Lacaze', + 'Dominic', + 'Bibler', + 'Boydstun', + 'Faas', + 'Grana', + 'Guardino', + 'Illig', + 'Luebbert', + 'Lyford', + 'Mcgettigan', + 'Repko', + 'Widmann', + 'Trevathan', + 'Ewan', + 'Mcray', + 'Footman', + 'Kerchner', + 'Leggio', + 'Bullinger', + 'Rushford', + 'Edel', + 'Leandro', + 'Burkman', + 'Grattan', + 'Tench', + 'Dartez', + 'Lemar', + 'Fane', + 'Zenon', + 'Sabb', + 'Blatchford', + 'Chilcoat', + 'Hahne', + 'Hanssen', + 'Mawhinney', + 'Pflueger', + 'Pol', + 'Vitelli', + 'Brierley', + 'Zundel', + 'Mcgillicuddy', + 'Adriano', + 'Mate', + 'Wilkison', + 'Ramnarine', + 'Peaks', + 'Bacote', + 'Barretto', + 'Benevento', + 'Gubler', + 'Koelsch', + 'Naas', + 'Patane', + 'Schnitzler', + 'Sprenkle', + 'Ulbrich', + 'Violante', + 'Rench', + 'Najarro', + 'Kristensen', + 'Poma', + 'Sara', + 'Jerrell', + 'Sarratt', + 'Mondy', + 'Antill', + 'Belleville', + 'Dworkin', + 'Holdaway', + 'Lenderman', + 'Murga', + 'Reiling', + 'Stasko', + 'Topel', + 'Verity', + 'Vinas', + 'Ziebarth', + 'Vanguilder', + 'Stoots', + 'Yantis', + 'Faries', + 'Tulley', + 'Baucum', + 'Fugett', + 'Harring', + 'Semien', + 'Dauphinais', + 'Furukawa', + 'Grilli', + 'Ohanian', + 'Ormiston', + 'Osegueda', + 'Wiegert', + 'Zier', + 'Chiesa', + 'Radecki', + 'Mongeon', + 'Stake', + 'Sweetland', + 'Shearon', + 'Lamore', + 'Mccuiston', + 'Minson', + 'Burditt', + 'Mcferren', + 'Covin', + 'Straker', + 'Elzy', + 'Althaus', + 'Anzures', + 'Glaeser', + 'Huseby', + 'Nitta', + 'Ribaudo', + 'Sobota', + 'Spieker', + 'Stefaniak', + 'Valois', + 'Vanwie', + 'Venturini', + 'Beltre', + 'Ewer', + 'Hartt', + 'Keaney', + 'Throne', + 'Edrington', + 'Inmon', + 'Isabel', + 'Brayman', + 'Devilbiss', + 'Krasner', + 'Malak', + 'Tito', + 'Vermeer', + 'Benigno', + 'Bosque', + 'Berridge', + 'Clines', + 'Brite', + 'Mcbeath', + 'Gleaves', + 'Koenen', + 'Kubicki', + 'Kudla', + 'Seiple', + 'Warkentin', + 'Choiniere', + 'Nassif', + 'Banko', + 'Muncie', + 'Garling', + 'Causby', + 'Mcgaw', + 'Burkeen', + 'Balan', + 'Georgia', + 'Hick', + 'Tumblin', + 'Badon', + 'Warrior', + 'Yearby', + 'Hiestand', + 'Hughart', + 'Proffer', + 'Sult', + 'Yepes', + 'Zachman', + 'Beddow', + 'Molyneux', + 'Camejo', + 'Stephany', + 'Cadogan', + 'Gosha', + 'Goodwine', + 'Harewood', + 'Burnsed', + 'Frappier', + 'Minardi', + 'Rieser', + 'Tabbert', + 'Marietta', + 'Butch', + 'Steil', + 'Canal', + 'Brundige', + 'Comas', + 'Hopkinson', + 'Shomo', + 'Kendle', + 'Bowsher', + 'Illingworth', + 'Kampa', + 'Manasco', + 'Mcdorman', + 'Theurer', + 'Widger', + 'Carbonneau', + 'Stachura', + 'Eriksson', + 'Trostle', + 'Foxworthy', + 'Lex', + 'Belman', + 'Isola', + 'Mckane', + 'Gearing', + 'Rimes', + 'Couillard', + 'Emanuele', + 'Pho', + 'Scimeca', + 'Skaar', + 'Vibbert', + 'Bilby', + 'Hink', + 'Gohn', + 'Nguy', + 'Perrett', + 'Bowland', + 'Comes', + 'Moffet', + 'Pauline', + 'Donalson', + 'Tilman', + 'Hansberry', + 'Acedo', + 'Camarda', + 'Devivo', + 'Eurich', + 'Jojola', + 'Railsback', + 'Rumfelt', + 'Stastny', + 'Strittmatter', + 'Houseknecht', + 'Rynearson', + 'Weinrich', + 'Kinghorn', + 'Astin', + 'Aguillard', + 'Hameed', + 'Drone', + 'Lonon', + 'Burgio', + 'Klimas', + 'Riegler', + 'Schiano', + 'Slonaker', + 'Deery', + 'Weissinger', + 'Cea', + 'Grenz', + 'Arent', + 'Sopher', + 'Jarratt', + 'Mitchener', + 'Conigliaro', + 'Dohm', + 'Feenstra', + 'Meiers', + 'Hetland', + 'Kinsinger', + 'Kmiec', + 'Teich', + 'Fukushima', + 'Kerins', + 'Cienfuegos', + 'Orlandi', + 'Bonser', + 'Okun', + 'Coate', + 'Rittenberry', + 'Mcclaine', + 'Dunklin', + 'Citizen', + 'Danzy', + 'Geers', + 'Georgeson', + 'Kikuchi', + 'Macinnis', + 'Malizia', + 'Mukai', + 'Plants', + 'Ehmann', + 'Haren', + 'Lachney', + 'Duchesne', + 'Collinson', + 'Connett', + 'Hostler', + 'Farnell', + 'Osler', + 'Triche', + 'Ballweg', + 'Bansal', + 'Galo', + 'Hollabaugh', + 'Hultquist', + 'Mcbrien', + 'Pelz', + 'Picciano', + 'Tashjian', + 'Thresher', + 'Uphoff', + 'Shawley', + 'Tomasek', + 'Aldaz', + 'Harig', + 'Kullman', + 'Vaness', + 'Isabella', + 'Munley', + 'Bissette', + 'Thackston', + 'Borgia', + 'Camire', + 'Charters', + 'Feiler', + 'Geisinger', + 'Racca', + 'Rasmusson', + 'Stonesifer', + 'Vidmar', + 'Arciga', + 'Bialek', + 'Baruch', + 'Kornfeld', + 'Harmeyer', + 'Picon', + 'Suppa', + 'Strate', + 'Hyre', + 'Verdon', + 'Reily', + 'Castell', + 'Foard', + 'Exner', + 'Furnari', + 'Guereca', + 'Hallgren', + 'Holsclaw', + 'Ketelsen', + 'Magnani', + 'Mehling', + 'Naser', + 'Seder', + 'Sparr', + 'Strnad', + 'Tatar', + 'Crecelius', + 'Knicely', + 'Vantassell', + 'Balsley', + 'Babbs', + 'Gowans', + 'Mcclam', + 'Batdorf', + 'Belsky', + 'Gull', + 'Letizia', + 'Ludlum', + 'Mascari', + 'Scheffel', + 'Spurgin', + 'Dignan', + 'Steffensen', + 'Freeberg', + 'Honan', + 'Hamric', + 'Woolman', + 'Valeri', + 'Saab', + 'Boyers', + 'Pardon', + 'Deasy', + 'Forshey', + 'Juntunen', + 'Kamel', + 'Macisaac', + 'Marinaro', + 'Milroy', + 'Parillo', + 'Rappold', + 'Schippers', + 'Smola', + 'Staniszewski', + 'Strasburg', + 'Epple', + 'Dewitte', + 'Hubley', + 'Queener', + 'Stoddart', + 'Briant', + 'Mcclurkin', + 'Binkowski', + 'Eberts', + 'Kilbane', + 'Kiraly', + 'Monsalve', + 'Othman', + 'Pasek', + 'Rinke', + 'Steinbrecher', + 'Trees', + 'Winther', + 'Boal', + 'Eber', + 'Funez', + 'Harryman', + 'Boyter', + 'Rill', + 'Jolliffe', + 'Dorian', + 'Demore', + 'Sebree', + 'Jeff', + 'Jolivette', + 'Elko', + 'Jividen', + 'Lenzen', + 'Marsee', + 'Milbrandt', + 'Orihuela', + 'Osterhoudt', + 'Parras', + 'Schnepp', + 'Tenaglia', + 'Thoren', + 'Diosdado', + 'Pingree', + 'Rutigliano', + 'Filbert', + 'Babel', + 'Stollings', + 'Hopes', + 'Bynes', + 'Brockmann', + 'Carta', + 'Deleeuw', + 'Demo', + 'Margeson', + 'Mckitrick', + 'Reyez', + 'Sidor', + 'Strehlow', + 'Timlin', + 'Wegrzyn', + 'Burgdorf', + 'Benzing', + 'Bonneville', + 'Clonts', + 'Camps', + 'Graydon', + 'Pasha', + 'Andreoli', + 'Cockerill', + 'Covino', + 'Hajjar', + 'Korpi', + 'Pohlmann', + 'Wente', + 'Wickwire', + 'Schaber', + 'Vonderhaar', + 'Manser', + 'Fitton', + 'Galindez', + 'Ares', + 'Longmore', + 'Buchert', + 'Delisi', + 'Gaulin', + 'Genco', + 'Helgerson', + 'Khawaja', + 'Radosevich', + 'Sannicolas', + 'Sterk', + 'Theberge', + 'Voiles', + 'Warchol', + 'Potthoff', + 'Runkel', + 'Stachowski', + 'Snay', + 'Share', + 'Conkey', + 'Pontes', + 'Mathies', + 'Brittian', + 'Allgeier', + 'Daughenbaugh', + 'Glock', + 'Meisinger', + 'Pantaleo', + 'Saitta', + 'Weick', + 'Burak', + 'Borda', + 'Rim', + 'Bunyard', + 'Neaves', + 'Mcilvaine', + 'Zee', + 'Buskey', + 'Roseborough', + 'Bellin', + 'Fasulo', + 'Grab', + 'Jia', + 'Knab', + 'Skalski', + 'Stensland', + 'Zajicek', + 'Echeverry', + 'Kolenda', + 'Cadden', + 'Delawder', + 'Propp', + 'Scheeler', + 'Clukey', + 'Loven', + 'Bogen', + 'Whittingham', + 'Barcelona', + 'Braasch', + 'Haubrich', + 'Kolberg', + 'Vendetti', + 'Sheesley', + 'Bartoli', + 'Knierim', + 'Amparo', + 'Lauth', + 'Rosero', + 'Burry', + 'Guynes', + 'Cumbo', + 'Pridgeon', + 'Aarons', + 'Alarid', + 'Arakawa', + 'Benzel', + 'Bywater', + 'Grosch', + 'Heth', + 'Logiudice', + 'Maisel', + 'Morquecho', + 'Wahlberg', + 'Teigen', + 'Bockelman', + 'Rehak', + 'Bitler', + 'Brion', + 'Niece', + 'Selvey', + 'Sudderth', + 'Ruddock', + 'Sandiford', + 'Aguas', + 'Folan', + 'Herwig', + 'Krupinski', + 'Mccarrick', + 'Mudgett', + 'Pancake', + 'Redner', + 'Wentzell', + 'Soliday', + 'Marschall', + 'Krakowski', + 'Rebholz', + 'Dold', + 'Giller', + 'Gassett', + 'Brazzell', + 'Bellow', + 'Tolen', + 'Gloster', + 'Gagliardo', + 'Harbuck', + 'Lorber', + 'Natarajan', + 'Sarna', + 'Schrack', + 'Vena', + 'Witzke', + 'Minassian', + 'Loi', + 'Rogue', + 'Trace', + 'Bomba', + 'Cozzens', + 'Evett', + 'Boze', + 'Petros', + 'Cotta', + 'Eisenmann', + 'Florea', + 'Hammersley', + 'Keohane', + 'Necessary', + 'Nodine', + 'Pekarek', + 'Sjogren', + 'Ruybal', + 'Arabie', + 'Huntsinger', + 'Eiseman', + 'Mehler', + 'Craner', + 'Vandine', + 'Gaffey', + 'Menna', + 'Royle', + 'Cordrey', + 'Gala', + 'Gauss', + 'Dacruz', + 'Cardell', + 'Devan', + 'Calmes', + 'Humber', + 'Stoute', + 'Balko', + 'Cera', + 'Griesbach', + 'Kissick', + 'Kloos', + 'Oertel', + 'Sedlock', + 'Stellato', + 'Tuite', + 'Bero', + 'Rinard', + 'Dambra', + 'Cinelli', + 'Tea', + 'Hicken', + 'Linch', + 'Dials', + 'Bennefield', + 'Hillsman', + 'Flemister', + 'Alvaro', + 'Goranson', + 'Henk', + 'Ryden', + 'Verhagen', + 'Wessling', + 'Willetts', + 'Neidlinger', + 'Pereida', + 'Lainhart', + 'Nemes', + 'Rudzinski', + 'Sward', + 'Rom', + 'Rosko', + 'Runions', + 'Henney', + 'Ridgely', + 'Tomson', + 'Arballo', + 'Bohorquez', + 'Brixey', + 'Durling', + 'Espina', + 'Esquivias', + 'Nungaray', + 'Ovando', + 'Zapf', + 'Pizza', + 'Arel', + 'Ballin', + 'Heathman', + 'Morison', + 'Troop', + 'Monfort', + 'Copland', + 'Harriott', + 'Mcwhite', + 'Amini', + 'Cirilo', + 'Gassner', + 'Gulbranson', + 'Kovatch', + 'Venne', + 'Terriquez', + 'Savin', + 'Amo', + 'Moris', + 'Crable', + 'Delaughter', + 'Greenhouse', + 'Eckardt', + 'Hendrixson', + 'Manansala', + 'Mongeau', + 'Panko', + 'Pichette', + 'Sliwa', + 'Tabak', + 'Determan', + 'Freeburg', + 'Portell', + 'Steller', + 'Buffkin', + 'Righter', + 'Mcguinn', + 'Corrie', + 'Tatham', + 'Smelley', + 'Terrel', + 'Selmon', + 'Blecha', + 'Eisler', + 'Engelking', + 'Goen', + 'Krey', + 'Mceldowney', + 'Plamondon', + 'Slovak', + 'Sorce', + 'Spagnolo', + 'Wambold', + 'Colborn', + 'Englander', + 'Monsour', + 'Pait', + 'Perricone', + 'Loveridge', + 'Cragg', + 'Dies', + 'Holsten', + 'Dagley', + 'Beverley', + 'Bayona', + 'Cam', + 'Chock', + 'Coppersmith', + 'Donath', + 'Guillemette', + 'Iannelli', + 'Potratz', + 'Selander', + 'Suk', + 'Waldvogel', + 'Olberding', + 'Giaimo', + 'Spoto', + 'Crocco', + 'Waskiewicz', + 'Krizan', + 'Vigo', + 'Boarman', + 'Ron', + 'Facer', + 'Garlow', + 'Filsaime', + 'Andersson', + 'Demski', + 'Derouin', + 'Diegel', + 'Feria', + 'Foth', + 'Hertzberg', + 'Jillson', + 'Kram', + 'Mammen', + 'Melhorn', + 'Monjaras', + 'Oslund', + 'Petrin', + 'Pinho', + 'Scheerer', + 'Shadden', + 'Sitzman', + 'Stumbaugh', + 'Wengert', + 'Gershon', + 'Mcelhinney', + 'Batterson', + 'Macqueen', + 'Janas', + 'Gladson', + 'Aull', + 'Wasinger', + 'Shemwell', + 'Seats', + 'Colas', + 'Allbee', + 'Fithian', + 'Fonner', + 'Gergen', + 'Lubrano', + 'Mannarino', + 'Piscopo', + 'Sydow', + 'Werle', + 'Aumiller', + 'Coplen', + 'Dardar', + 'Morrisette', + 'Mchaney', + 'Simes', + 'Gillison', + 'Emmel', + 'Klunk', + 'Luber', + 'Madeira', + 'Schlicht', + 'Tremain', + 'Cleaveland', + 'Boulet', + 'Golladay', + 'Enck', + 'Fera', + 'Hammar', + 'Hebner', + 'Ishee', + 'Nanni', + 'Palomar', + 'Pangborn', + 'Rogala', + 'Rushlow', + 'Wiedman', + 'Laber', + 'Schoenfelder', + 'Sonner', + 'Duffer', + 'Granier', + 'Sawin', + 'Dwiggins', + 'Jaso', + 'Popplewell', + 'Loren', + 'Ord', + 'Dearmon', + 'Hammen', + 'Misra', + 'Reindl', + 'Siordia', + 'Woodhead', + 'Yasuda', + 'Dockstader', + 'Kobs', + 'Tokarski', + 'Villers', + 'Mase', + 'Arrant', + 'Hedgpeth', + 'Eggleton', + 'Frederic', + 'Victorian', + 'Akerman', + 'Balazs', + 'Brandau', + 'Depietro', + 'Dillenbeck', + 'Goodnow', + 'Larner', + 'Mcmurtrie', + 'Salameh', + 'Swicegood', + 'Koshy', + 'Stdenis', + 'Deakin', + 'Izzi', + 'Teater', + 'Gramm', + 'Doig', + 'Blacklock', + 'Haymore', + 'Heggie', + 'Kirklin', + 'Kassa', + 'Ryles', + 'Tenner', + 'Ndiaye', + 'Burrola', + 'Faires', + 'Grega', + 'Krentz', + 'Needles', + 'Portz', + 'Ruedas', + 'Sitko', + 'Viernes', + 'Setter', + 'Tricarico', + 'Prest', + 'Olivar', + 'Whitsitt', + 'Labossiere', + 'Bellomo', + 'Burgeson', + 'Capriotti', + 'Drinnon', + 'Gulati', + 'Haffey', + 'Lasota', + 'Laughery', + 'Mees', + 'Melander', + 'Paoletti', + 'Petermann', + 'Zerby', + 'Burhans', + 'Lasseigne', + 'Vannote', + 'Wai', + 'Berson', + 'Gritton', + 'Searl', + 'Toller', + 'Brackeen', + 'Screws', + 'Hagens', + 'Billingslea', + 'Hyppolite', + 'Asmussen', + 'Bitton', + 'Diiorio', + 'Grigoryan', + 'Hauenstein', + 'Krukowski', + 'Mulcahey', + 'Perras', + 'Prak', + 'Reitzel', + 'Spackman', + 'Valenciano', + 'Wieck', + 'Yeagley', + 'Zanetti', + 'Goeller', + 'Azizi', + 'Grise', + 'Mogan', + 'Traverso', + 'Nangle', + 'Saladin', + 'Hardgrove', + 'Osei', + 'Fehrenbach', + 'Giesbrecht', + 'Halas', + 'Hetzler', + 'Orsak', + 'Salaz', + 'Surace', + 'Whipp', + 'Charlebois', + 'Stayer', + 'Stelmach', + 'Hitchings', + 'Senters', + 'Mcnaught', + 'Cordier', + 'Dawsey', + 'Barhorst', + 'Clauser', + 'Dibernardo', + 'Hawkey', + 'Hritz', + 'Patchin', + 'Raatz', + 'Seubert', + 'Slingerland', + 'Vanderwoude', + 'Aquilino', + 'Goertzen', + 'Navratil', + 'Mccuistion', + 'Vallin', + 'Moors', + 'Connely', + 'Fedrick', + 'Bontempo', + 'Dishong', + 'Felch', + 'Laino', + 'Minshall', + 'Montroy', + 'Plotts', + 'Radice', + 'Sachse', + 'Safran', + 'Schecter', + 'Traut', + 'Vasile', + 'Yadon', + 'Gorka', + 'Roelofs', + 'Suit', + 'Asbill', + 'Torrens', + 'Kimmey', + 'Ruger', + 'Vinzant', + 'Watkin', + 'Rawles', + 'Cubero', + 'Duch', + 'Endress', + 'Fangman', + 'Holben', + 'Holzapfel', + 'Karner', + 'Otteson', + 'Stangel', + 'Terrebonne', + 'Wagley', + 'Wisecup', + 'Bengston', + 'Leck', + 'Coalson', + 'Farooq', + 'Safi', + 'Smyers', + 'All', + 'Else', + 'Wason', + 'Nairn', + 'Panton', + 'Ahrendt', + 'Arvizo', + 'Klahn', + 'Robak', + 'Schier', + 'Start', + 'Tiano', + 'Kraatz', + 'Corzo', + 'Maranto', + 'Elm', + 'Eagles', + 'Acres', + 'Schoolfield', + 'Ancrum', + 'Ahner', + 'Augsburger', + 'Berna', + 'Danh', + 'Fruth', + 'Galluzzo', + 'Racette', + 'Selva', + 'Szekely', + 'Zirbel', + 'Hauff', + 'Markgraf', + 'Wonderly', + 'Rydell', + 'Julia', + 'Chris', + 'Simson', + 'Bridgeford', + 'Jeffress', + 'Brailsford', + 'Bluford', + 'Boser', + 'Fichera', + 'Meininger', + 'Meyerhoff', + 'Modzelewski', + 'Niese', + 'Pavlovich', + 'Radovich', + 'Ratz', + 'Frankowski', + 'Berti', + 'Geno', + 'Fares', + 'Marney', + 'Harwick', + 'Tata', + 'Bobby', + 'Dobbin', + 'Roosevelt', + 'Greenaway', + 'Janvier', + 'Oatis', + 'Beilke', + 'Brelsford', + 'Dowty', + 'Giudice', + 'Hetzer', + 'Imboden', + 'Irelan', + 'Nie', + 'Ramberg', + 'Rega', + 'Sproat', + 'Sytsma', + 'Unrein', + 'Davignon', + 'Ganoe', + 'Leinweber', + 'Mantell', + 'Troisi', + 'Sahr', + 'Esperanza', + 'Asper', + 'Lathem', + 'Eagleton', + 'Lamons', + 'Gaulden', + 'Bloodgood', + 'Cerone', + 'Claro', + 'Durfey', + 'Enamorado', + 'Herrada', + 'Maw', + 'Schlagel', + 'Signor', + 'Reisch', + 'Gruenwald', + 'Helbert', + 'Lorenzi', + 'Woodlief', + 'Huval', + 'Batman', + 'Meadow', + 'Croswell', + 'Bordonaro', + 'Earnshaw', + 'Freiburger', + 'Gunnoe', + 'Lamberton', + 'Martella', + 'Mischke', + 'Shelor', + 'Venuti', + 'Bilek', + 'Mcmains', + 'Balding', + 'Mestre', + 'Mcconnaughey', + 'Manso', + 'Decoste', + 'Egerton', + 'Alvino', + 'Arizpe', + 'Blaschke', + 'Foglesong', + 'Heyn', + 'Irigoyen', + 'Komorowski', + 'Lesinski', + 'Nghiem', + 'Rund', + 'Santiesteban', + 'Strahm', + 'Hendel', + 'Capes', + 'Carls', + 'Bon', + 'Sires', + 'Nichelson', + 'Brimm', + 'Aikins', + 'Berra', + 'Brazee', + 'Burkert', + 'Capalbo', + 'Criscione', + 'Feddersen', + 'Hofbauer', + 'Jacobowitz', + 'Mackowiak', + 'Mcenroe', + 'Philbeck', + 'Shimada', + 'Ticknor', + 'Wozny', + 'Biernacki', + 'Hirschi', + 'Polich', + 'Sokoloski', + 'Dolores', + 'Knoch', + 'Ge', + 'Groome', + 'Markell', + 'Fearing', + 'Mcclaren', + 'Hadsell', + 'Rumple', + 'Samudio', + 'Scardina', + 'Spinosa', + 'Abramov', + 'Siracusa', + 'Goren', + 'Rocchio', + 'Bibi', + 'Lamer', + 'Liddy', + 'Anna', + 'Coxe', + 'De', + 'Rodes', + 'Cheshier', + 'Coulon', + 'Closs', + 'Tigue', + 'Seville', + 'Hopkin', + 'Rodwell', + 'Bibbins', + 'Baldree', + 'Bawden', + 'Bishoff', + 'Costabile', + 'Dec', + 'Hillegass', + 'Infantino', + 'Mantia', + 'Mcamis', + 'Northcott', + 'Ruprecht', + 'Sanpedro', + 'Campione', + 'Muchow', + 'Ostby', + 'Mohl', + 'Pulice', + 'Vigna', + 'Thomann', + 'Lillibridge', + 'Manville', + 'Vives', + 'Bellanger', + 'Desormeaux', + 'Lovingood', + 'Stjulien', + 'Echeverri', + 'Florey', + 'Gieseke', + 'Maeder', + 'Marcinko', + 'Nuncio', + 'Quirino', + 'Versteeg', + 'Voelkel', + 'Wanless', + 'Morocho', + 'Monteagudo', + 'Aikin', + 'Bramley', + 'Bartleson', + 'Skeete', + 'Batra', + 'Dolloff', + 'Gehr', + 'Hellyer', + 'Hersch', + 'Hier', + 'Lannan', + 'Reffitt', + 'Carboni', + 'Schouten', + 'Burkle', + 'Riches', + 'Busa', + 'Rademaker', + 'Hult', + 'Synder', + 'Bossard', + 'Tunis', + 'Pamplin', + 'Oats', + 'Mcphaul', + 'Baik', + 'Kieser', + 'Pareja', + 'Raffaele', + 'Erhard', + 'Iwasaki', + 'Tonelli', + 'Mabey', + 'Debruyn', + 'Carrel', + 'Myron', + 'Arai', + 'Vallo', + 'Points', + 'Buteau', + 'Becknell', + 'Lue', + 'Antos', + 'Folkers', + 'Galletta', + 'Hissong', + 'Knoche', + 'Kundert', + 'Larussa', + 'Lobos', + 'Poitra', + 'Rinn', + 'Seamons', + 'Senko', + 'Villaverde', + 'Weatherholt', + 'Maliszewski', + 'Jurkowski', + 'Scism', + 'Hallas', + 'Collet', + 'Capello', + 'Lena', + 'Popper', + 'Aikman', + 'Blakes', + 'Cadigan', + 'Dupler', + 'Kazi', + 'Masri', + 'Matejka', + 'Mcgirr', + 'Pistone', + 'Prenger', + 'Ranes', + 'Thiemann', + 'Voeller', + 'Cockman', + 'Burtt', + 'Looby', + 'Bonnie', + 'Mcclenny', + 'Ridgell', + 'Nails', + 'Lesane', + 'Bertolino', + 'Doheny', + 'Fechter', + 'Holshouser', + 'Kierstead', + 'Krewson', + 'Lanahan', + 'Vig', + 'Wiswell', + 'Freytag', + 'Haselden', + 'Kuras', + 'Navar', + 'Raisor', + 'Finamore', + 'Kipper', + 'Morissette', + 'Laughton', + 'Awe', + 'Manier', + 'Cumby', + 'Cabada', + 'Hafen', + 'Kojima', + 'Massari', + 'Mctague', + 'Stehr', + 'Vandevelde', + 'Voong', + 'Wisely', + 'Girardin', + 'Bies', + 'Demaris', + 'Galles', + 'Goldstone', + 'Kai', + 'Cord', + 'Brigance', + 'Gomillion', + 'Drakes', + 'Bartkowiak', + 'Chica', + 'Draheim', + 'Honeyman', + 'Klapper', + 'Kniffen', + 'Knoblock', + 'Scherzer', + 'Tougas', + 'Toyama', + 'Urbach', + 'Walia', + 'Wattenbarger', + 'Marz', + 'Cesare', + 'Miro', + 'Kervin', + 'Godard', + 'Beiter', + 'Betcher', + 'Evarts', + 'Evensen', + 'Gaff', + 'Griffitts', + 'Grunden', + 'Hoffart', + 'Kroupa', + 'Maiers', + 'Mckendry', + 'Puett', + 'Shoe', + 'Stermer', + 'Wineinger', + 'Brocious', + 'Chudy', + 'Spofford', + 'Wessinger', + 'Weich', + 'Croff', + 'Ephraim', + 'Sallis', + 'Blasco', + 'Burningham', + 'Buschmann', + 'Forget', + 'Kulak', + 'Panozzo', + 'Pierpont', + 'Priolo', + 'Puhl', + 'Ruffolo', + 'Voisine', + 'Mancinelli', + 'Santacroce', + 'Vanvalkenburgh', + 'Veverka', + 'Desena', + 'Agner', + 'Boron', + 'Wheeling', + 'Plato', + 'Tonge', + 'Deibel', + 'Herriman', + 'Holroyd', + 'Huitron', + 'Hum', + 'Kreamer', + 'Lada', + 'Lucena', + 'Pao', + 'Planck', + 'Vanroekel', + 'Bodell', + 'Francia', + 'Anastasia', + 'Haxton', + 'Maile', + 'Warning', + 'Labeau', + 'Pujol', + 'Done', + 'Minney', + 'Hogsett', + 'Tayler', + 'Delancy', + 'Philson', + 'Allemand', + 'Buhrman', + 'Diefenbach', + 'Gawel', + 'Kovacic', + 'Kralik', + 'Lazor', + 'Mcnemar', + 'Warth', + 'Glanzer', + 'Keep', + 'Hochstein', + 'Febles', + 'Morneau', + 'Agostinelli', + 'Galeas', + 'Landen', + 'Lion', + 'Attwood', + 'Capshaw', + 'Willy', + 'Dekle', + 'Murrill', + 'Coby', + 'Falvo', + 'Kanagy', + 'Mihalko', + 'Schellenberg', + 'Sugimoto', + 'Lippard', + 'Sardo', + 'Suckow', + 'Demichele', + 'Kath', + 'Lappe', + 'Lego', + 'Schleifer', + 'Vold', + 'Kingsland', + 'Mitch', + 'Manlove', + 'Cuozzo', + 'Dauber', + 'Deininger', + 'Goldbach', + 'Halfmann', + 'Kazarian', + 'Marksberry', + 'Marzec', + 'Mcmurphy', + 'Oregan', + 'Paczkowski', + 'Pinsky', + 'Poynor', + 'Schertz', + 'Tetrick', + 'Umali', + 'Valenza', + 'Witherington', + 'Kesselring', + 'Nylund', + 'Cinnamon', + 'Rielly', + 'Surman', + 'Fowle', + 'Hains', + 'Sharlow', + 'Lones', + 'Durgan', + 'Savory', + 'Minger', + 'Okon', + 'Berends', + 'Binning', + 'Malina', + 'Loeser', + 'Marthaler', + 'Pacella', + 'Vasta', + 'Hinerman', + 'Goodchild', + 'Chuck', + 'Linney', + 'Beckworth', + 'Carrie', + 'Lovings', + 'Ginyard', + 'Bredeson', + 'Debiase', + 'Gorder', + 'Noce', + 'Redlin', + 'Schwinn', + 'Zins', + 'Burtner', + 'Kosakowski', + 'Erler', + 'Altom', + 'Husman', + 'Markos', + 'Thorman', + 'Fagen', + 'Voisin', + 'Gauldin', + 'Pressey', + 'Calbert', + 'Holness', + 'Alspach', + 'Broeker', + 'Danziger', + 'Klenke', + 'Popescu', + 'Schoenrock', + 'Schreckengost', + 'Syme', + 'Trick', + 'Plautz', + 'Beckel', + 'Dealmeida', + 'Winne', + 'Moron', + 'Seed', + 'Capozzoli', + 'Gawron', + 'Kobel', + 'Kouns', + 'Nunemaker', + 'Steinbacher', + 'Stookey', + 'Vidana', + 'Zoch', + 'Ohlinger', + 'Hudkins', + 'Ferren', + 'Gille', + 'Sheckler', + 'Kittell', + 'Roath', + 'Ziglar', + 'Brecher', + 'Coldren', + 'Degraaf', + 'Eddinger', + 'Joffe', + 'Luthy', + 'Metzinger', + 'Nayak', + 'Paule', + 'Prudente', + 'Wooddell', + 'Zuccaro', + 'Rineer', + 'Soos', + 'Manka', + 'Vandervoort', + 'Kitchell', + 'Casserly', + 'Watchman', + 'Poteete', + 'Dopson', + 'Mathurin', + 'Cataldi', + 'Crepeau', + 'Fackrell', + 'Goben', + 'Macinnes', + 'Scherf', + 'Shaddix', + 'Sorber', + 'Teichman', + 'Wydra', + 'Holzworth', + 'Baade', + 'Tinnell', + 'Tinkler', + 'Mauzy', + 'Alphonse', + 'Fullard', + 'Adger', + 'Akiyama', + 'Bloxham', + 'Coultas', + 'Esler', + 'Giebel', + 'Goswick', + 'Heikes', + 'Javed', + 'Linan', + 'Mooers', + 'Nemetz', + 'Pradhan', + 'Rainone', + 'Romito', + 'Treichel', + 'Vohs', + 'Grosskopf', + 'Weisinger', + 'Ruple', + 'Naff', + 'Meaders', + 'Lamarr', + 'Toppin', + 'Apicella', + 'Beecroft', + 'Boshears', + 'Breier', + 'Cuadros', + 'Umbarger', + 'Alioto', + 'Ravenscroft', + 'Vesper', + 'Oak', + 'Tigges', + 'Simmer', + 'Hanby', + 'Webre', + 'Lenk', + 'Mcelvain', + 'Boy', + 'Debarros', + 'Hickenbottom', + 'Quincy', + 'Billips', + 'Ollison', + 'Barbuto', + 'Clearwater', + 'Cronkhite', + 'Groleau', + 'Mehra', + 'Tessler', + 'Kegel', + 'Borenstein', + 'Newnam', + 'Crofton', + 'Phenix', + 'Dankert', + 'Hymas', + 'Lobel', + 'Marszalek', + 'Moceri', + 'Ottaviano', + 'Papazian', + 'Roedel', + 'Jochum', + 'Urquidez', + 'Lapin', + 'Garro', + 'Lamond', + 'Sessums', + 'Tooke', + 'Steadham', + 'Azam', + 'Bleier', + 'Buelna', + 'Bupp', + 'Burridge', + 'Derderian', + 'Derstine', + 'Halberg', + 'Katzer', + 'Meegan', + 'Ortmann', + 'Herschberger', + 'Sanroman', + 'Winiarski', + 'Alcon', + 'Picker', + 'Demille', + 'Huron', + 'Hankin', + 'Dahmen', + 'Fronczak', + 'Klingman', + 'Perugini', + 'Pettinato', + 'Powelson', + 'Saffer', + 'Schwenke', + 'Pals', + 'Estremera', + 'Sofia', + 'Arvelo', + 'Terrero', + 'Bankes', + 'Sais', + 'Netherland', + 'Odeh', + 'Sutphen', + 'Caddy', + 'Dorval', + 'Glaude', + 'Mcadory', + 'Eichinger', + 'Lesniewski', + 'Petito', + 'Pfohl', + 'Presler', + 'Rys', + 'Sano', + 'Willenborg', + 'Seppala', + 'Shibley', + 'Cajigas', + 'Gal', + 'Farag', + 'Pickles', + 'Rump', + 'Grills', + 'Mikes', + 'Adderley', + 'Altland', + 'Araki', + 'Beitz', + 'Brotzman', + 'Buonocore', + 'Fayard', + 'Gelber', + 'Jurewicz', + 'Lezcano', + 'Marsteller', + 'Minarik', + 'Opsahl', + 'Pranger', + 'Tiburcio', + 'Zollo', + 'Engh', + 'Henault', + 'Barrineau', + 'Pilkinton', + 'Pratte', + 'Niland', + 'Warda', + 'Southwood', + 'Clinch', + 'Halsell', + 'Mccaa', + 'Isreal', + 'Pinkett', + 'Asch', + 'Beauchesne', + 'Bruemmer', + 'Doebler', + 'Ehlinger', + 'Goelz', + 'Hashemi', + 'Karel', + 'Magiera', + 'Martorano', + 'Mooneyhan', + 'Cibrian', + 'Cavey', + 'Kosko', + 'Christo', + 'Cockrill', + 'Mansker', + 'Balls', + 'Degree', + 'Tiggs', + 'Alberico', + 'Clugston', + 'Elman', + 'Frueh', + 'Kampf', + 'Kochanski', + 'Leider', + 'Marsella', + 'Mckendree', + 'Moffa', + 'Quattrocchi', + 'Raval', + 'Snoke', + 'Akopyan', + 'Barrilleaux', + 'Cambria', + 'Kawaguchi', + 'Bonde', + 'Dawdy', + 'Willig', + 'Kazee', + 'Debow', + 'Beachum', + 'Vicks', + 'Aurelio', + 'Barocio', + 'Bonesteel', + 'Ezzo', + 'Gesell', + 'Krzeminski', + 'Madan', + 'Magda', + 'Manring', + 'Mcfaul', + 'Morera', + 'Purinton', + 'Retzer', + 'Schonfeld', + 'Staszak', + 'Stubbe', + 'Talerico', + 'Wikoff', + 'Zia', + 'Seyfried', + 'Diangelo', + 'Keach', + 'Shipton', + 'Shewmake', + 'Behrmann', + 'Hopps', + 'Paster', + 'Augenstein', + 'Castaldi', + 'Ferrufino', + 'Gregersen', + 'Hosseini', + 'Keniston', + 'Nadolski', + 'Ouimette', + 'Pellett', + 'Riebel', + 'Schwark', + 'Spelman', + 'Tesar', + 'Yahn', + 'Grossnickle', + 'Rosillo', + 'Dostie', + 'Noa', + 'Khalaf', + 'Cardosa', + 'Afzal', + 'Mercure', + 'Wheless', + 'Tailor', + 'Mcgarrah', + 'Miler', + 'Norfolk', + 'Crapps', + 'Dansereau', + 'Jenney', + 'Keast', + 'Lieser', + 'Mihm', + 'Porco', + 'Zelinsky', + 'Sleeth', + 'Mcelreath', + 'Hemann', + 'Capaldi', + 'Huggett', + 'Reagle', + 'Mayotte', + 'Liller', + 'Leen', + 'Demmer', + 'Tunison', + 'Woodbridge', + 'Haymes', + 'Cunning', + 'Blaze', + 'Eatman', + 'Ulysse', + 'Bagshaw', + 'Buczkowski', + 'Cardello', + 'Decola', + 'Diloreto', + 'Evola', + 'Glassburn', + 'Hazelbaker', + 'Holycross', + 'Minasian', + 'Regula', + 'Ruge', + 'Uhlman', + 'Lamprecht', + 'Shifflet', + 'Weikle', + 'Coupe', + 'Isherwood', + 'Dimon', + 'Pop', + 'Willhoite', + 'Bari', + 'Boise', + 'Doom', + 'Mccolley', + 'Bircher', + 'Wannamaker', + 'Eppes', + 'Pea', + 'Okeke', + 'Alpizar', + 'Arista', + 'Barbagallo', + 'Baumert', + 'Bhattacharya', + 'Gheen', + 'Hutchcraft', + 'Karlen', + 'Klier', + 'Ladnier', + 'Marrujo', + 'Reister', + 'Rorrer', + 'Tarpey', + 'Wisecarver', + 'Beydoun', + 'Fillinger', + 'Kemnitz', + 'Takata', + 'Leight', + 'Kross', + 'Junco', + 'Holmer', + 'Sando', + 'Biddix', + 'Dawood', + 'Frisco', + 'Flagler', + 'Arntz', + 'Bache', + 'Bundrick', + 'Glasson', + 'Los', + 'Scheiber', + 'Shellenbarger', + 'Steinmeyer', + 'Sura', + 'Tanski', + 'Teodoro', + 'Vanaken', + 'Jodoin', + 'Klinker', + 'Szydlowski', + 'Yamashiro', + 'Kutch', + 'Hoth', + 'Edwardson', + 'Gess', + 'Mohamad', + 'Goodine', + 'Carolina', + 'Blauser', + 'Emerich', + 'Flook', + 'Graul', + 'Gribben', + 'Herbold', + 'Kreutz', + 'Lavey', + 'Lukacs', + 'Maiorana', + 'Openshaw', + 'Plattner', + 'Sauro', + 'Schardt', + 'Tortorici', + 'Wendlandt', + 'Danowski', + 'Mcnellis', + 'Pinkowski', + 'Linz', + 'Virga', + 'Jardin', + 'Maclaughlin', + 'Rama', + 'Deline', + 'Kimbel', + 'Hagin', + 'Pottinger', + 'Detmer', + 'Ferrone', + 'Matthiesen', + 'Melchert', + 'Ruehl', + 'Takach', + 'Briese', + 'Elmendorf', + 'Valentini', + 'Hersom', + 'Bordeau', + 'Linsley', + 'Keatts', + 'Dina', + 'Boye', + 'Riviere', + 'Stodghill', + 'Madry', + 'Angelos', + 'Bou', + 'Ketterling', + 'Niemczyk', + 'Pardini', + 'Rippel', + 'Schieffer', + 'Schnee', + 'Shogren', + 'Sholl', + 'Ullmann', + 'Ure', + 'Curless', + 'Gonnella', + 'Tholen', + 'Valladolid', + 'Silbernagel', + 'Cohrs', + 'Shahin', + 'Beth', + 'Holmen', + 'Tippie', + 'Opie', + 'Sprowl', + 'Byam', + 'Bethany', + 'Saintil', + 'Auriemma', + 'Blust', + 'Dibello', + 'Digangi', + 'Farnam', + 'Farnan', + 'Linford', + 'Mcgroarty', + 'Meisenheimer', + 'Pagels', + 'Sauber', + 'Schwalbe', + 'Seemann', + 'Slivka', + 'Twardowski', + 'Wickey', + 'Zettler', + 'Zuchowski', + 'Feldhaus', + 'Baldock', + 'Cowman', + 'Carp', + 'Camera', + 'Balon', + 'Neveu', + 'Caminiti', + 'Carreira', + 'Gura', + 'Hershkowitz', + 'Killoran', + 'Narducci', + 'Reigel', + 'Saccone', + 'Tomasi', + 'Wieneke', + 'Sibrian', + 'Hashem', + 'Kellems', + 'Stouder', + 'Villamar', + 'Piette', + 'Wand', + 'Battey', + 'Staunton', + 'Bedore', + 'Hanel', + 'Jutras', + 'Kanner', + 'Mathiesen', + 'Northway', + 'Privitera', + 'Reichelt', + 'Zucco', + 'Roys', + 'Aderholt', + 'Lampson', + 'Olen', + 'Mcgarr', + 'Schools', + 'Leaphart', + 'Lykes', + 'Brightbill', + 'Koos', + 'Lahue', + 'Laplaca', + 'Naqvi', + 'Novo', + 'Puerta', + 'Siers', + 'Strutz', + 'Trimboli', + 'Waldie', + 'Goold', + 'Falke', + 'Corter', + 'Cartmell', + 'Brazel', + 'Farabee', + 'Majeed', + 'Hilden', + 'Kealoha', + 'Neider', + 'Parodi', + 'Rizza', + 'Rong', + 'Silberstein', + 'Snellgrove', + 'Trojanowski', + 'Warneke', + 'Wissler', + 'Yiu', + 'Grein', + 'Sak', + 'Daines', + 'Monzo', + 'Emmerson', + 'Lorraine', + 'Samaroo', + 'Edmund', + 'Cacace', + 'Dornan', + 'Eyman', + 'Hovanec', + 'Jeschke', + 'Limberg', + 'Maturo', + 'Pandey', + 'Somoza', + 'Streiff', + 'Wiemer', + 'Zablocki', + 'Crace', + 'Leinen', + 'Rucci', + 'Blyth', + 'Clemans', + 'Magid', + 'Ferrick', + 'Garriga', + 'Martir', + 'Tanton', + 'Hoon', + 'Echard', + 'Borrell', + 'Howden', + 'Gravett', + 'Lando', + 'Amacher', + 'Dalman', + 'Hollenbaugh', + 'Sigrist', + 'Tamashiro', + 'Therriault', + 'Villafranca', + 'Matthys', + 'Salois', + 'Sforza', + 'Swager', + 'Borah', + 'Sentell', + 'Besson', + 'Ghani', + 'Bilinski', + 'Holzinger', + 'Kus', + 'Lobianco', + 'Morawski', + 'Perz', + 'Sada', + 'Wollenberg', + 'Yusko', + 'Caughron', + 'Diffenderfer', + 'Slowinski', + 'Skiver', + 'Galland', + 'Hodes', + 'Boyne', + 'Towry', + 'Alers', + 'Hellums', + 'Certain', + 'Megginson', + 'Creer', + 'Coutee', + 'Strothers', + 'Stfleur', + 'Barga', + 'Bina', + 'Cellini', + 'Digiulio', + 'Douma', + 'Klement', + 'Mccambridge', + 'Parmeter', + 'Presto', + 'Salmi', + 'Seabaugh', + 'Barreda', + 'Nepomuceno', + 'Zent', + 'Yonce', + 'Loreto', + 'Honer', + 'Conquest', + 'Gathings', + 'Wims', + 'Upshur', + 'Aeschliman', + 'Casaus', + 'Dumke', + 'Earlywine', + 'Ferreyra', + 'Heyne', + 'Hudon', + 'Kuder', + 'Malia', + 'Brueckner', + 'Luchsinger', + 'Ornellas', + 'Ramseyer', + 'Weidemann', + 'Walbert', + 'Zola', + 'Linquist', + 'Storts', + 'Dente', + 'Lebleu', + 'Stockham', + 'Rollinson', + 'Auzenne', + 'Abebe', + 'Bartol', + 'Cozzolino', + 'Der', + 'Fata', + 'Gorr', + 'Janousek', + 'Moschella', + 'Riedy', + 'Dust', + 'Malmgren', + 'Puterbaugh', + 'Sacchetti', + 'Lascano', + 'Begnaud', + 'Duling', + 'Porteous', + 'Debnam', + 'Abron', + 'Delehanty', + 'Fazenbaker', + 'Flener', + 'Gora', + 'Herter', + 'Johann', + 'Keiter', + 'Lucca', + 'Passman', + 'Saindon', + 'Schoppe', + 'Skibinski', + 'Stueber', + 'Tegeler', + 'Jochim', + 'Buttner', + 'Crilly', + 'Swanton', + 'Muncey', + 'Negrin', + 'Thorburn', + 'Delpino', + 'Kinn', + 'Gaiter', + 'Obi', + 'Hohensee', + 'Rollman', + 'Scheff', + 'Shor', + 'Tumbleson', + 'Mccrum', + 'Knack', + 'Llano', + 'Saber', + 'Rosman', + 'Bankson', + 'Atkisson', + 'Kennel', + 'Cammon', + 'Bangura', + 'Cichy', + 'Gillikin', + 'Hiltner', + 'Lubben', + 'Mcqueeney', + 'Nasca', + 'Nordgren', + 'Ostermann', + 'Quito', + 'Sakowski', + 'Schut', + 'Stobaugh', + 'Alessio', + 'Gorelik', + 'Heinzman', + 'Westrich', + 'Nardella', + 'Cruzado', + 'Lansberry', + 'Dubreuil', + 'Nylander', + 'Rabel', + 'Moret', + 'Crout', + 'Ardrey', + 'Rolley', + 'Finks', + 'Cliett', + 'Caito', + 'Clingenpeel', + 'Delprete', + 'Dolen', + 'Heidrich', + 'Hinrichsen', + 'Jindra', + 'Madej', + 'Panzarella', + 'Sandin', + 'Seekins', + 'Shilts', + 'Sokoloff', + 'Maggart', + 'Pigman', + 'Travieso', + 'Denbow', + 'Dollison', + 'Gaye', + 'Binette', + 'Dutta', + 'Grandinetti', + 'Kitch', + 'Tangeman', + 'Finstad', + 'Rodkey', + 'Servis', + 'Tiwari', + 'Rodd', + 'Parfait', + 'Seck', + 'Delaurentis', + 'Dragan', + 'Fleig', + 'Giacobbe', + 'Hilligoss', + 'Kroh', + 'Lippe', + 'Maleski', + 'Perini', + 'Rutten', + 'Stauss', + 'Yoshikawa', + 'Dibattista', + 'Gilsdorf', + 'Riemenschneider', + 'Streck', + 'Gessler', + 'Springstead', + 'Zaki', + 'Lambie', + 'Barczak', + 'Ellerbrock', + 'Foresman', + 'Holstine', + 'Lemm', + 'Santillana', + 'Trautwein', + 'Unsworth', + 'Valderas', + 'Vaquero', + 'Vetsch', + 'Wadleigh', + 'Yonts', + 'Mcguiness', + 'Auvil', + 'Leeder', + 'Sprowls', + 'Cala', + 'Portalatin', + 'Casso', + 'Chirinos', + 'Less', + 'Baltzell', + 'Bo', + 'Whetsell', + 'Ledlow', + 'Fullbright', + 'Arnell', + 'Stainback', + 'Mcleish', + 'Lyn', + 'Bermeo', + 'Billet', + 'Craun', + 'Gladwell', + 'Goral', + 'Herbig', + 'Kluver', + 'Mermelstein', + 'Odette', + 'Poggi', + 'Schacher', + 'Thielman', + 'Cianciolo', + 'Ferrie', + 'Kapusta', + 'Kreager', + 'Messineo', + 'Rovira', + 'Stricklen', + 'Wansley', + 'Amell', + 'Baena', + 'Depaula', + 'Fickett', + 'Housewright', + 'Kreiger', + 'Legate', + 'Lutterman', + 'Men', + 'Pautz', + 'Swecker', + 'Tantillo', + 'Dudeck', + 'Bellas', + 'Marian', + 'Bienvenu', + 'Riden', + 'Hosein', + 'Couser', + 'Batterton', + 'Desantos', + 'Dieterle', + 'Drabek', + 'Grennan', + 'Greulich', + 'Ludlam', + 'Maltos', + 'Marcin', + 'Ostertag', + 'Rednour', + 'Tippetts', + 'Updyke', + 'Ormsbee', + 'Reutter', + 'Uyehara', + 'Musumeci', + 'Antonini', + 'Thistle', + 'Marcia', + 'Renne', + 'Jines', + 'Dorothy', + 'Menter', + 'Crosser', + 'Ditommaso', + 'Glueck', + 'Malta', + 'Mcgranahan', + 'Mensing', + 'Ostroff', + 'Rota', + 'Rothfuss', + 'Borcherding', + 'Haveman', + 'Swallows', + 'Heltzel', + 'Aloi', + 'Stipp', + 'Broda', + 'Darter', + 'Gressett', + 'Brasier', + 'Lana', + 'Crooke', + 'Seegers', + 'Sirmons', + 'Berberian', + 'Goers', + 'Losch', + 'Memon', + 'Paternoster', + 'Rierson', + 'Miyake', + 'Barndt', + 'Kirstein', + 'Azua', + 'Zeck', + 'Britain', + 'Lanman', + 'Gorges', + 'Clock', + 'Alman', + 'Callicutt', + 'Walford', + 'Searight', + 'Eakle', + 'Federici', + 'Hosack', + 'Jarecki', + 'Kauffmann', + 'Maras', + 'Nisley', + 'Sandahl', + 'Shidler', + 'Wnek', + 'Moneymaker', + 'Santander', + 'Schneeberger', + 'Luviano', + 'Gorin', + 'Negus', + 'Coulston', + 'Polin', + 'Winslett', + 'Anstett', + 'Cowsert', + 'Dipiazza', + 'Fitting', + 'Forslund', + 'Poquette', + 'Tibbets', + 'Tomasini', + 'Toor', + 'Starry', + 'Venema', + 'Cedano', + 'Carro', + 'Samons', + 'Matty', + 'Ellenwood', + 'Kilcrease', + 'Noblin', + 'Decatur', + 'Heckard', + 'Nard', + 'Beighley', + 'Delamater', + 'Eblen', + 'Heninger', + 'Kehn', + 'Rotunno', + 'Uppal', + 'Hynek', + 'Zenk', + 'Brasil', + 'Mu', + 'Julio', + 'Cassar', + 'Crisco', + 'Oriley', + 'Turton', + 'Goens', + 'Cargo', + 'Toure', + 'Breitbach', + 'Cahalan', + 'Chadha', + 'Kittinger', + 'Marnell', + 'Masias', + 'Matousek', + 'Mittal', + 'Nieblas', + 'Onan', + 'Purdum', + 'Tursi', + 'Esplin', + 'Etsitty', + 'Fratto', + 'Przybyla', + 'Cassin', + 'Nitti', + 'Arshad', + 'Sandoz', + 'Walzer', + 'Everton', + 'Russum', + 'Morland', + 'Fennel', + 'Viel', + 'Jarrells', + 'Vassell', + 'Frigo', + 'Kodama', + 'Naron', + 'Oelke', + 'Remaley', + 'Shean', + 'Cloonan', + 'Clayman', + 'Lasch', + 'Lepard', + 'Rewis', + 'Vankeuren', + 'Lightbody', + 'Houseworth', + 'Caison', + 'Denmon', + 'Rauls', + 'Sallie', + 'Humphery', + 'Showell', + 'Raysor', + 'Angotti', + 'Barbero', + 'Buxbaum', + 'Capella', + 'Horsch', + 'Kunselman', + 'Nishikawa', + 'Perotti', + 'Sprung', + 'Szucs', + 'Emch', + 'Kotula', + 'Mendizabal', + 'Yeaman', + 'Beste', + 'Kader', + 'Forker', + 'Wiggers', + 'Cotham', + 'Primo', + 'Fetterhoff', + 'Giarrusso', + 'Glosser', + 'Lumbreras', + 'Rosano', + 'Strohecker', + 'Wanek', + 'Waycaster', + 'Worthley', + 'Salasar', + 'Boulos', + 'Pulsipher', + 'Scheider', + 'Lorimer', + 'Alamilla', + 'Zapp', + 'Deis', + 'Tariq', + 'Kasey', + 'Famiglietti', + 'Flansburg', + 'Georgiou', + 'Groft', + 'Heistand', + 'Merker', + 'Stoeckel', + 'Tackitt', + 'Verbeck', + 'Weyers', + 'Wiltrout', + 'Brabec', + 'Caligiuri', + 'Dudzinski', + 'Grieger', + 'Benfer', + 'Pesta', + 'Wool', + 'Sunshine', + 'Oka', + 'Stamour', + 'Barrio', + 'Mathe', + 'Vanduyne', + 'Brager', + 'Mcphatter', + 'Ahluwalia', + 'Borys', + 'Dreibelbis', + 'Kalmbach', + 'Karwoski', + 'Moomaw', + 'Youngren', + 'Offerman', + 'Nine', + 'Symington', + 'Branan', + 'Turberville', + 'Heber', + 'Loughridge', + 'Vanderberg', + 'Mccannon', + 'Linda', + 'Dupee', + 'Cottom', + 'Mcphearson', + 'Razor', + 'Buchwald', + 'Fraze', + 'Grannis', + 'Krolikowski', + 'Lapidus', + 'Madruga', + 'Mcmartin', + 'Quinlivan', + 'Riaz', + 'Spittler', + 'Zahm', + 'Zender', + 'Eisman', + 'Hourihan', + 'Shirazi', + 'Herendeen', + 'Perdew', + 'Pendell', + 'Chernoff', + 'Lyell', + 'Clarey', + 'Macken', + 'Guthridge', + 'Redditt', + 'Bedi', + 'Debenedictis', + 'Distel', + 'Gapinski', + 'Iwanski', + 'Medici', + 'Schmutz', + 'Tuel', + 'Verburg', + 'Galgano', + 'Skogen', + 'Aymond', + 'Raymo', + 'Croney', + 'Carry', + 'Rhynes', + 'Lamour', + 'Shedrick', + 'Tookes', + 'Baltierra', + 'Leitzel', + 'Letchworth', + 'Montesino', + 'Preis', + 'Sanzone', + 'Shantz', + 'Teo', + 'Twohig', + 'Wajda', + 'Windisch', + 'Zinck', + 'Fiero', + 'Hornby', + 'Paget', + 'Serano', + 'Rodrick', + 'Lewison', + 'Dyas', + 'Delcarmen', + 'Garske', + 'Hontz', + 'Mcquown', + 'Melling', + 'Rolando', + 'Rosencrans', + 'Steichen', + 'Teeples', + 'Forseth', + 'Quijas', + 'Schraeder', + 'Vaidya', + 'Ventre', + 'Mountjoy', + 'Morr', + 'Leviner', + 'Paulette', + 'Dobie', + 'Brue', + 'Prier', + 'Biffle', + 'Neyland', + 'Valcourt', + 'Mckeithen', + 'Lemelle', + 'Alviar', + 'Auth', + 'Bahm', + 'Bierbaum', + 'Cazier', + 'Eschbach', + 'Etzler', + 'Nowlan', + 'Sahota', + 'Vanaman', + 'Zaugg', + 'Hogeland', + 'Choat', + 'Walmer', + 'Cepero', + 'Michal', + 'Foxwell', + 'Decoursey', + 'Molyneaux', + 'Peat', + 'Jeanfrancois', + 'Arevalos', + 'Bachert', + 'Beachler', + 'Berrones', + 'Clavijo', + 'Elsen', + 'Fuhs', + 'Hooven', + 'Johannessen', + 'Klausner', + 'Masso', + 'Puzio', + 'Sekula', + 'Smyser', + 'Stepanian', + 'Barg', + 'Trueman', + 'Constante', + 'Cubas', + 'Dowers', + 'Pratts', + 'Cockburn', + 'Counce', + 'Nappier', + 'Lindon', + 'Burrowes', + 'Cokley', + 'Tillmon', + 'Bao', + 'Inks', + 'Liberato', + 'Moehring', + 'Ryker', + 'Sar', + 'Swartzendruber', + 'Torgersen', + 'Treto', + 'Tungate', + 'Ricotta', + 'Weesner', + 'Willyard', + 'Callicoat', + 'Hoque', + 'Atkison', + 'Mcwherter', + 'Dubuisson', + 'Wanzer', + 'Stradford', + 'Abruzzo', + 'Amerman', + 'Bame', + 'Bantz', + 'Bleakley', + 'Galt', + 'Hoobler', + 'Jaquith', + 'Lessman', + 'Polinski', + 'Rasche', + 'Roeber', + 'Rubright', + 'Sarnowski', + 'Signore', + 'Solum', + 'Vankampen', + 'Vath', + 'Malmquist', + 'Mittelstadt', + 'Belyea', + 'Haverty', + 'Wickett', + 'Sansing', + 'Yeatman', + 'Brocker', + 'Wonders', + 'Both', + 'Rabun', + 'Rocke', + 'Meachum', + 'Blane', + 'Lapsley', + 'Biswas', + 'Derocher', + 'Haran', + 'Hehn', + 'Keshishian', + 'Kniffin', + 'Lacina', + 'Skolnik', + 'Spiewak', + 'Wileman', + 'Eble', + 'Kraynak', + 'Wiesen', + 'Micheli', + 'Scroggin', + 'Roch', + 'Denise', + 'Altenburg', + 'Hornstein', + 'Netto', + 'Opel', + 'Passey', + 'Roeske', + 'Schrantz', + 'Abrahamsen', + 'Powless', + 'Callais', + 'Desjardin', + 'Pirro', + 'Yonkers', + 'Macallister', + 'Dady', + 'Ruskin', + 'Escott', + 'Abbot', + 'Sankar', + 'Bolar', + 'Angelucci', + 'Biegel', + 'Cirone', + 'Damewood', + 'Flett', + 'Kronenberg', + 'Ky', + 'Nagler', + 'Perlstein', + 'Saperstein', + 'Tenbrink', + 'Vana', + 'Wnuk', + 'Bonnema', + 'Schoenecker', + 'Pichler', + 'Armendarez', + 'Oiler', + 'Rouch', + 'Boas', + 'Laracuente', + 'Milbourn', + 'Summy', + 'Counter', + 'Gracie', + 'Belfield', + 'Bynoe', + 'Jalloh', + 'Blazier', + 'Bochenek', + 'Broughman', + 'Chuong', + 'Cregger', + 'Estacio', + 'Kaleta', + 'Lanctot', + 'Mish', + 'Novosel', + 'Passero', + 'Ripplinger', + 'Vitt', + 'Walborn', + 'Friscia', + 'Memmott', + 'Tripi', + 'Weinhold', + 'Honn', + 'Gianni', + 'Poch', + 'Sagar', + 'Markum', + 'Primmer', + 'Belmore', + 'Rain', + 'Bevard', + 'Skyles', + 'Farland', + 'Mccleese', + 'Teachey', + 'Moulden', + 'Antolin', + 'Augello', + 'Borrayo', + 'Effler', + 'Hornak', + 'Hosman', + 'Leingang', + 'Limbach', + 'Oregel', + 'Ritzman', + 'Rochefort', + 'Schimke', + 'Stefanelli', + 'Vien', + 'Zurn', + 'Badolato', + 'Bieri', + 'Clarkin', + 'Folino', + 'Kelchner', + 'Pote', + 'Brahm', + 'Hoop', + 'Macbride', + 'Hunting', + 'Brule', + 'Wainright', + 'Rolison', + 'Bennie', + 'Banghart', + 'Bertke', + 'Bozzo', + 'Gadomski', + 'Granberg', + 'Kostecki', + 'Lemelin', + 'Levengood', + 'Puskas', + 'Swanstrom', + 'Willcutt', + 'Deitrich', + 'Grieves', + 'Ferran', + 'Boileau', + 'Kendra', + 'Trippe', + 'Mcconnel', + 'Cara', + 'Stephans', + 'Bachus', + 'Applin', + 'Utsey', + 'Auston', + 'Arras', + 'Bencosme', + 'Berntsen', + 'Decarolis', + 'Dettloff', + 'Duerksen', + 'Pavlovic', + 'Schwantes', + 'Sjostrom', + 'Sugiyama', + 'Sulak', + 'Virani', + 'Winberg', + 'Yoshimoto', + 'Comito', + 'Pandolfo', + 'Cathers', + 'Hardisty', + 'Collom', + 'Wain', + 'Worthing', + 'Leep', + 'Simo', + 'Boom', + 'Bald', + 'Applegarth', + 'Gilbreth', + 'Griest', + 'Jobin', + 'Matsuura', + 'Misko', + 'Scerbo', + 'Scheidler', + 'Sterba', + 'Tomaino', + 'Wixson', + 'Yadao', + 'Hietpas', + 'Gruss', + 'Fors', + 'Gosse', + 'Katt', + 'Virk', + 'Quebedeaux', + 'Barkey', + 'Salam', + 'Willford', + 'Tarry', + 'Chancy', + 'Beynon', + 'Eckes', + 'Eischen', + 'Felger', + 'Kimm', + 'Labate', + 'Mehan', + 'Netzer', + 'Strosnider', + 'Trezza', + 'Vial', + 'Waugaman', + 'Zieman', + 'Ankeny', + 'Digman', + 'Farino', + 'Faro', + 'Vasconcelos', + 'Nevill', + 'Rave', + 'Sabine', + 'Hagg', + 'Weightman', + 'Berton', + 'Fipps', + 'Knapper', + 'Camel', + 'Gilkes', + 'Aldous', + 'Delucca', + 'Dicke', + 'Evitts', + 'Hachey', + 'Rinck', + 'Treese', + 'Uher', + 'Victorio', + 'Vignola', + 'Willert', + 'Baun', + 'Wever', + 'Varn', + 'Yokum', + 'Dunk', + 'Maben', + 'Arzu', + 'Guider', + 'Bonhomme', + 'Majette', + 'Crislip', + 'Gresko', + 'Luppino', + 'Posch', + 'Potenza', + 'Rial', + 'Ruderman', + 'Shaff', + 'Balboni', + 'Solheim', + 'Mey', + 'Sittig', + 'Perman', + 'Sumners', + 'Deaner', + 'Keizer', + 'Reves', + 'Glanville', + 'Menzie', + 'Mccowen', + 'Steib', + 'Portee', + 'Azad', + 'Dallaire', + 'Denno', + 'Deptula', + 'Fischman', + 'Guilbault', + 'Imperato', + 'Koehne', + 'Menning', + 'Mirelez', + 'Stanislawski', + 'Streb', + 'Sumida', + 'Wolke', + 'Kerfoot', + 'Pirie', + 'Saracino', + 'Maslanka', + 'Slominski', + 'Nienaber', + 'Serena', + 'Kamper', + 'Matheis', + 'Westin', + 'Ishman', + 'Biagi', + 'Chiou', + 'Dieckmann', + 'Frieden', + 'Huestis', + 'Presutti', + 'Ribas', + 'Siedlecki', + 'Steege', + 'Uehara', + 'Petrosyan', + 'Siebold', + 'Turi', + 'Rady', + 'Vanorman', + 'Arif', + 'Hiland', + 'Naidu', + 'Clagett', + 'Ludy', + 'Bodley', + 'Avelino', + 'Citro', + 'Cuda', + 'Derbyshire', + 'Kruszewski', + 'Kupper', + 'Mahl', + 'Muratore', + 'Noecker', + 'Osmer', + 'Pasquariello', + 'Schlick', + 'Snover', + 'Strzelecki', + 'Studt', + 'Sunga', + 'Belmares', + 'Seifried', + 'Urioste', + 'Housh', + 'Babu', + 'Bures', + 'Augusto', + 'Faddis', + 'Pun', + 'Chopp', + 'Tullock', + 'Sea', + 'Boisseau', + 'Herbin', + 'Balcer', + 'Copus', + 'Eichenberger', + 'Enterline', + 'Gamarra', + 'Gursky', + 'Hovsepian', + 'Laffin', + 'Melena', + 'Rappe', + 'Soma', + 'Spira', + 'Spraker', + 'Teuscher', + 'Hochhalter', + 'Brenden', + 'Snee', + 'Polan', + 'Hataway', + 'Tirey', + 'Cobler', + 'Marren', + 'Ress', + 'Bennis', + 'Busha', + 'Galler', + 'Orea', + 'Nailor', + 'Magby', + 'Bridgett', + 'Island', + 'Camino', + 'Coderre', + 'Gangloff', + 'Gillilan', + 'Goergen', + 'Henthorne', + 'Heverly', + 'Loughry', + 'Records', + 'Schweikert', + 'Seeds', + 'Vanderwerf', + 'Westall', + 'Cristiano', + 'Biser', + 'Cartmill', + 'Greenly', + 'Kountz', + 'Craney', + 'Sheffey', + 'Gelin', + 'Gourdine', + 'Canham', + 'Edgmon', + 'Enz', + 'Feldpausch', + 'Hestand', + 'Kaus', + 'Kostelnik', + 'Ocanas', + 'Riggi', + 'Rohl', + 'Scheurer', + 'Sleeman', + 'Tosi', + 'Phegley', + 'Abelson', + 'Mclees', + 'Sinor', + 'Babson', + 'Whalley', + 'Manton', + 'Patteson', + 'Doyen', + 'Asad', + 'Thurmon', + 'Cassese', + 'Ditmore', + 'Duva', + 'Pilato', + 'Polaski', + 'Rzepka', + 'Sevin', + 'Sivak', + 'Speckman', + 'Stepien', + 'Switalski', + 'Valletta', + 'Knoth', + 'Niver', + 'Ciancio', + 'Giza', + 'Liebowitz', + 'Orengo', + 'Rothgeb', + 'Witz', + 'Airhart', + 'Gayman', + 'Belland', + 'Eury', + 'Randal', + 'Mcghie', + 'Briganti', + 'Hoopingarner', + 'Lugar', + 'Manfre', + 'Mongelli', + 'Squibb', + 'Vasil', + 'Cap', + 'Veillon', + 'Ege', + 'Spice', + 'Nevel', + 'Vanleer', + 'Petway', + 'Petitfrere', + 'Barcena', + 'Belville', + 'Brezina', + 'Ketcherside', + 'Knodel', + 'Krinsky', + 'Lundahl', + 'Mescher', + 'Pilat', + 'Sneller', + 'Staller', + 'Steinhaus', + 'Stensrud', + 'Szalay', + 'Tani', + 'Saviano', + 'Genna', + 'Emry', + 'Allin', + 'Harvel', + 'Harth', + 'Pay', + 'Harries', + 'Brannum', + 'Elijah', + 'Hoyte', + 'Bazinet', + 'Bhandari', + 'Brozek', + 'Cava', + 'Dalbey', + 'Delgiudice', + 'Klages', + 'Riffey', + 'Straube', + 'Zagar', + 'Zientek', + 'Dilger', + 'Hof', + 'Karwowski', + 'Rybarczyk', + 'Spiering', + 'Stamos', + 'Gangemi', + 'Olavarria', + 'Sardinas', + 'Magin', + 'Payano', + 'Deady', + 'Henricksen', + 'Kary', + 'Garnier', + 'Babic', + 'Behymer', + 'Billig', + 'Huegel', + 'Ishihara', + 'Mcglinchey', + 'Misuraca', + 'Petrosino', + 'Zizzo', + 'Reierson', + 'Wadman', + 'Brander', + 'Risko', + 'Basye', + 'Mcmakin', + 'Straughan', + 'Chesnutt', + 'Sima', + 'Ree', + 'Mankins', + 'Soberanis', + 'Greenup', + 'Commodore', + 'Carucci', + 'Defibaugh', + 'Finfrock', + 'Funston', + 'Grantz', + 'Guiney', + 'Ohrt', + 'Tinsman', + 'Godek', + 'Mcgrory', + 'Mikeska', + 'Kamer', + 'Lovas', + 'Kirshner', + 'Bevacqua', + 'Franqui', + 'Walts', + 'Doke', + 'Orsborn', + 'Tavernier', + 'Kibble', + 'Scipio', + 'Diop', + 'Antczak', + 'Bastida', + 'Callister', + 'Dusseau', + 'Ficarra', + 'Garcilazo', + 'Hughett', + 'Liebel', + 'Rodenbaugh', + 'Rosselli', + 'Teresi', + 'Bohnsack', + 'Steidl', + 'Vanderheiden', + 'Demma', + 'Dutson', + 'Mcmeekin', + 'Glassford', + 'Serrao', + 'Marriner', + 'Mcchristian', + 'Lias', + 'Blahnik', + 'Brunke', + 'Daleo', + 'Fullam', + 'Goetzinger', + 'Leva', + 'Rehder', + 'Ripperger', + 'Shindler', + 'Tussing', + 'Mayr', + 'Rozzi', + 'Bonsignore', + 'Te', + 'Graft', + 'Ok', + 'Clink', + 'Mccamey', + 'Goldring', + 'Tartt', + 'Fullilove', + 'Amodio', + 'Arkin', + 'Dettmann', + 'Ellingwood', + 'Figura', + 'Fritzinger', + 'Heilmann', + 'Hillstrom', + 'Marasigan', + 'Pavlov', + 'Totman', + 'Dokken', + 'Serpico', + 'Shumard', + 'Rathman', + 'Siegmund', + 'Woodhull', + 'Oregon', + 'Roselle', + 'Taul', + 'Maddix', + 'Nwosu', + 'Bavaro', + 'Carella', + 'Cowdrey', + 'Goodnough', + 'Koffler', + 'Mahajan', + 'Montalvan', + 'Morga', + 'Parrella', + 'Quiggle', + 'Rehrig', + 'Rotondi', + 'Tavenner', + 'Wigger', + 'Yax', + 'Bartko', + 'Netzel', + 'Zechman', + 'Socia', + 'Vea', + 'Wemple', + 'Matti', + 'Striplin', + 'Hollin', + 'Geddie', + 'Nolden', + 'Freeney', + 'Jeanjacques', + 'Bermudes', + 'Castrellon', + 'Catino', + 'Feeser', + 'Kreitz', + 'Maisano', + 'Melkonian', + 'Toste', + 'Vancura', + 'Bylsma', + 'Wiant', + 'Mcpheron', + 'Gere', + 'Geoffroy', + 'Fuston', + 'Petteway', + 'Barsky', + 'Bovard', + 'Buttars', + 'Christophersen', + 'Dudzik', + 'Ganger', + 'Hilgers', + 'Holzhauer', + 'Minervini', + 'Pong', + 'Rozycki', + 'Sulzer', + 'Tauscher', + 'Upright', + 'Verastegui', + 'Lobello', + 'Sandt', + 'Timbrook', + 'Yniguez', + 'Nuzzi', + 'Sakata', + 'Koran', + 'Veloso', + 'Cullers', + 'Culton', + 'Reynold', + 'Feagins', + 'Amaker', + 'Cafferty', + 'Coontz', + 'Iden', + 'Mazzotta', + 'Montanye', + 'Wandell', + 'Weiman', + 'Vik', + 'Staib', + 'Lasso', + 'Waynick', + 'Boniface', + 'Massingale', + 'Gainous', + 'Sharper', + 'Columbia', + 'Felkins', + 'Gatzke', + 'Heindel', + 'Ludeman', + 'Mcmunn', + 'Mogavero', + 'Ratti', + 'Rickabaugh', + 'Ripper', + 'Tessman', + 'Triano', + 'Vanderpol', + 'Langille', + 'Holten', + 'Steeley', + 'Solan', + 'Devaul', + 'Lindler', + 'Armor', + 'Fambrough', + 'Golliday', + 'Bognar', + 'Gamba', + 'Gettinger', + 'Hanzel', + 'Krumwiede', + 'Marcinkowski', + 'Nicolay', + 'Peppard', + 'Sisti', + 'Sundeen', + 'Senatore', + 'Diebel', + 'Demarais', + 'Letellier', + 'Goon', + 'Texidor', + 'Baughan', + 'Gunder', + 'Lalor', + 'Wigglesworth', + 'Aird', + 'Basey', + 'Afshar', + 'Anhalt', + 'Bondoc', + 'Bunten', + 'Daniello', + 'Kazmierski', + 'Marcott', + 'Petruska', + 'Trejos', + 'Droege', + 'Fukumoto', + 'Harju', + 'Hauf', + 'Yagi', + 'Mccallie', + 'Moulds', + 'Singleterry', + 'Ramkissoon', + 'Sanks', + 'Siggers', + 'Myrie', + 'Conteh', + 'Biss', + 'Brees', + 'Collopy', + 'Dashner', + 'Dehaas', + 'Delzer', + 'Fees', + 'Finocchiaro', + 'Forsgren', + 'Giampietro', + 'Levandowski', + 'Mallick', + 'Maudlin', + 'Micheletti', + 'Newhard', + 'Parmentier', + 'Pintado', + 'Pliego', + 'Radigan', + 'Selke', + 'Uptain', + 'Wigton', + 'Zabinski', + 'Becenti', + 'Guthmiller', + 'Malecha', + 'Eardley', + 'Muscat', + 'Ruhe', + 'Battersby', + 'Lamie', + 'Stan', + 'Dutch', + 'Duplechain', + 'Dildy', + 'Auch', + 'Baltzer', + 'Degaetano', + 'Mileski', + 'Parrillo', + 'Schoof', + 'Stires', + 'Villescas', + 'Knittle', + 'Degrave', + 'Deihl', + 'Moseman', + 'Prillaman', + 'Wakeley', + 'Jake', + 'Murden', + 'Shareef', + 'Yarbough', + 'Bothe', + 'Boutilier', + 'Breck', + 'Buschman', + 'Coccia', + 'Eberlein', + 'Harriger', + 'Neas', + 'Sullenger', + 'Walp', + 'Yaple', + 'Zinger', + 'Zufelt', + 'Marinaccio', + 'Viele', + 'Markee', + 'Melody', + 'Rooke', + 'Ales', + 'Mumphrey', + 'Bessinger', + 'Bialas', + 'Brugh', + 'Chum', + 'Diehm', + 'Frieze', + 'Hieber', + 'Malouf', + 'Maltz', + 'Mcmanaway', + 'Musante', + 'Pester', + 'Roda', + 'Snarr', + 'Tovey', + 'Buchmann', + 'Fluck', + 'Sadowsky', + 'Viteri', + 'Loewe', + 'Mullaly', + 'Lamboy', + 'Bouman', + 'Provencal', + 'Siddons', + 'Chelette', + 'Rachels', + 'Dynes', + 'Nobel', + 'Desselle', + 'Tillison', + 'Bajaj', + 'Bresee', + 'Hisel', + 'Mallo', + 'Meints', + 'Potocki', + 'Spore', + 'Steier', + 'Toothaker', + 'Wildt', + 'Darcangelo', + 'Karbowski', + 'Scaccia', + 'Lascola', + 'Duman', + 'Mccaul', + 'Rowton', + 'Setters', + 'Hendryx', + 'Belson', + 'Manny', + 'Winckler', + 'Longe', + 'Mclucas', + 'Lenon', + 'Linen', + 'Anstine', + 'Belkin', + 'Drozdowski', + 'Ender', + 'Ferra', + 'Lessig', + 'Marucci', + 'Nardo', + 'Nipp', + 'Passarella', + 'Roecker', + 'Siddique', + 'Stanczak', + 'Stavros', + 'Tomasetti', + 'Lagreca', + 'Seegmiller', + 'Keena', + 'Suddarth', + 'Wayt', + 'Matas', + 'Ryer', + 'Mortimore', + 'Durnell', + 'Pieters', + 'Slocumb', + 'Andaya', + 'Brymer', + 'Dufek', + 'Ekman', + 'Espericueta', + 'Feltes', + 'Hammann', + 'Heydt', + 'Inthavong', + 'Jagielski', + 'Nast', + 'Petrucelli', + 'Phippen', + 'Vanderzanden', + 'Whinery', + 'Zatarain', + 'Zelenak', + 'Aquilina', + 'Hougland', + 'Isais', + 'Canney', + 'Flath', + 'Ragon', + 'Len', + 'Violet', + 'Carra', + 'Everetts', + 'Lockey', + 'Dahmer', + 'Fuquay', + 'Alpers', + 'Borromeo', + 'Bringas', + 'Brumit', + 'Campanile', + 'Folts', + 'Hirai', + 'Kiessling', + 'Krogstad', + 'Ovitt', + 'Bhardwaj', + 'Hlavaty', + 'Monceaux', + 'Spatola', + 'Trunzo', + 'Girvin', + 'Shady', + 'Grimley', + 'Tagg', + 'Weddell', + 'Mcfadyen', + 'Reagin', + 'Philo', + 'Emily', + 'Codd', + 'Cherrington', + 'Skates', + 'Deary', + 'Ballester', + 'Barilla', + 'Cicchetti', + 'Dyche', + 'Goossen', + 'Graveline', + 'Hajduk', + 'Halliwell', + 'Kohnen', + 'Kupiec', + 'Machacek', + 'Manship', + 'Slinker', + 'Mallozzi', + 'Dotter', + 'Brazeau', + 'Manon', + 'Crofford', + 'Gauthreaux', + 'Petillo', + 'Bailor', + 'Ganesh', + 'Reaser', + 'Barren', + 'Adachi', + 'Aguiniga', + 'Cartrette', + 'Crady', + 'Hegland', + 'Isner', + 'Karasek', + 'Labrum', + 'Maroon', + 'Rullo', + 'Schull', + 'Stawicki', + 'Withee', + 'Penfold', + 'Foronda', + 'Claridge', + 'Coiner', + 'Guimaraes', + 'Mawyer', + 'Rivkin', + 'Kiggins', + 'Hackel', + 'Wey', + 'Fairhurst', + 'Albertini', + 'Gaal', + 'Flurry', + 'Patricia', + 'Savery', + 'Colen', + 'Cuthrell', + 'Maffett', + 'Dungey', + 'Luter', + 'Hurston', + 'Ahles', + 'Czapla', + 'Gallas', + 'Kotecki', + 'Lazzari', + 'Marcellino', + 'Valvo', + 'Vukovich', + 'Wisor', + 'Agler', + 'Wease', + 'Gallentine', + 'Christoph', + 'Poyer', + 'Norment', + 'Rhett', + 'Amabile', + 'Barish', + 'Heifner', + 'Kolarik', + 'Mcquarrie', + 'Morua', + 'Nahas', + 'Razzano', + 'Riegle', + 'Torralba', + 'Perfetti', + 'Stalzer', + 'Killman', + 'Lenning', + 'Wyler', + 'Soward', + 'Releford', + 'Battisti', + 'Bergum', + 'Catapano', + 'Doerner', + 'Ehlen', + 'Finken', + 'Genereux', + 'Hillegas', + 'Hopple', + 'Kaatz', + 'Lacson', + 'Macario', + 'Marzolf', + 'Muha', + 'Picha', + 'Springston', + 'Stooksbury', + 'Weide', + 'Glodowski', + 'Lueth', + 'Assaf', + 'Robuck', + 'Lamaster', + 'Foulkes', + 'Swopes', + 'Winkfield', + 'Aristizabal', + 'Aylesworth', + 'Bellotti', + 'Bittick', + 'Capistran', + 'Cizek', + 'Dinneen', + 'Ellender', + 'Friske', + 'Hoffa', + 'Klinge', + 'Kuklinski', + 'Luzier', + 'Martensen', + 'Rolin', + 'Shankles', + 'Siska', + 'Wiegman', + 'Winterbottom', + 'Crookston', + 'Gorospe', + 'Curci', + 'Lamberty', + 'Antonetti', + 'Sheer', + 'Durning', + 'Hootman', + 'Doub', + 'Klaiber', + 'Mayeaux', + 'Domingos', + 'Wheeless', + 'Vantrease', + 'Summerhill', + 'Agresta', + 'Annas', + 'Aquilar', + 'Crea', + 'Froese', + 'Medlen', + 'Peeters', + 'Rhudy', + 'Risse', + 'Schor', + 'Zimmerer', + 'Bombardier', + 'Halfhill', + 'Koppenhaver', + 'Kruckenberg', + 'Boccia', + 'Rella', + 'Carelli', + 'Overson', + 'Tamburro', + 'Rosamond', + 'Lie', + 'Mesquita', + 'Jennett', + 'Jewel', + 'Waye', + 'Bogucki', + 'Colpitts', + 'Galpin', + 'Hrdlicka', + 'Kading', + 'Kushnir', + 'Leano', + 'Liebig', + 'Mceuen', + 'Nestler', + 'Payer', + 'Santarelli', + 'Schrupp', + 'Schwarze', + 'Semrau', + 'Solanki', + 'Terzian', + 'Treloar', + 'Ureno', + 'Vohra', + 'Voshell', + 'Nakanishi', + 'Senese', + 'Dierker', + 'Quinley', + 'Monier', + 'Rounsaville', + 'Mcfaddin', + 'Defrance', + 'Joynes', + 'Levert', + 'Adragna', + 'Buczynski', + 'Cranor', + 'Englebert', + 'Furney', + 'Gorny', + 'Mockler', + 'Pavlicek', + 'Petrini', + 'Schadt', + 'Slagel', + 'Cumpston', + 'Priore', + 'Paonessa', + 'Carling', + 'Espaillat', + 'Hem', + 'Griffo', + 'Tomer', + 'Venn', + 'Giraud', + 'Becks', + 'Mungin', + 'Attard', + 'Brucato', + 'Dreyfus', + 'Droz', + 'Falck', + 'Firebaugh', + 'Fiser', + 'Hemmelgarn', + 'Hofacker', + 'Kreeger', + 'Rippee', + 'Ruehle', + 'Saputo', + 'Scovill', + 'Silbaugh', + 'Smolenski', + 'Spickler', + 'Swango', + 'Kaehler', + 'Mootz', + 'Noblett', + 'Zarcone', + 'Katzenberger', + 'Kita', + 'Brezinski', + 'Castles', + 'Padin', + 'Hinde', + 'Barretta', + 'Amiri', + 'Shelburne', + 'Mccoin', + 'Heaston', + 'Aldredge', + 'Milhouse', + 'Wilbon', + 'Cephus', + 'Barsness', + 'Belch', + 'Blatter', + 'Boyum', + 'Corvino', + 'Dagenais', + 'Doscher', + 'Elizarraraz', + 'Gierke', + 'Habegger', + 'Ketcher', + 'Kristiansen', + 'Oldroyd', + 'Sandage', + 'Tesoriero', + 'Unzueta', + 'Wollam', + 'Cefalu', + 'Achey', + 'Wegmann', + 'Lessner', + 'Bunk', + 'Mallin', + 'Polis', + 'Aronoff', + 'Portal', + 'Crock', + 'Escher', + 'Medler', + 'Pretty', + 'Younge', + 'Agbayani', + 'Brinkmeyer', + 'Castrillon', + 'Feick', + 'Gutmann', + 'Hagenbuch', + 'Hesseltine', + 'Houska', + 'Kimzey', + 'Kolasa', + 'Lentine', + 'Lobaugh', + 'Maimone', + 'Meshell', + 'Nardini', + 'Rosetti', + 'Siefker', + 'Sileo', + 'Silveria', + 'Argumedo', + 'Lesmeister', + 'Donnan', + 'Hermans', + 'Raggio', + 'Dupras', + 'Empson', + 'Bevier', + 'Tumey', + 'Donn', + 'Darville', + 'Douse', + 'Cheyne', + 'Dewing', + 'Jansma', + 'Mayeda', + 'Nield', + 'Obermiller', + 'Opfer', + 'Surma', + 'Tiffin', + 'Tirpak', + 'Wassel', + 'Blickenstaff', + 'Dorland', + 'Kulhanek', + 'Andras', + 'Estupinan', + 'Gonce', + 'Weast', + 'Souto', + 'Guirguis', + 'Glazebrook', + 'Dain', + 'Loyer', + 'Bensley', + 'Verge', + 'Tubman', + 'Onley', + 'Dais', + 'Barash', + 'Bullman', + 'Crispino', + 'Davino', + 'Isenhart', + 'Kneller', + 'Loschiavo', + 'Opper', + 'Pfleger', + 'Wahler', + 'Zelasko', + 'Havrilla', + 'Mintzer', + 'Devoll', + 'Giannelli', + 'Sees', + 'Barritt', + 'Mesta', + 'Sostre', + 'Rohman', + 'Padget', + 'Edds', + 'Slinger', + 'Borowicz', + 'Bregman', + 'Bubar', + 'Debartolo', + 'Desposito', + 'Grieshaber', + 'Ludtke', + 'Pagani', + 'Quiambao', + 'Schapiro', + 'Winward', + 'Bouska', + 'Olstad', + 'Rough', + 'Genz', + 'Husby', + 'Nealis', + 'Hyams', + 'Andrades', + 'Mcgibbon', + 'Edwin', + 'Buckhalter', + 'Baylon', + 'Fiene', + 'Fillingim', + 'Fiorenza', + 'Greenstreet', + 'Krager', + 'Laxson', + 'Noreen', + 'Roberds', + 'Rundquist', + 'Smelcer', + 'Tabone', + 'Train', + 'Zeoli', + 'Defries', + 'Kolp', + 'Maahs', + 'Mcnall', + 'Ehman', + 'Keeth', + 'Shackleton', + 'Hogarth', + 'Westbury', + 'Gulliver', + 'Oquin', + 'Holiman', + 'Saintlouis', + 'Vaughns', + 'Aichele', + 'Arbelaez', + 'Bathurst', + 'Bresler', + 'Cecena', + 'Drollinger', + 'Fellner', + 'Griesemer', + 'Harnois', + 'Hire', + 'Kraker', + 'Roylance', + 'Zaccaria', + 'Dinunzio', + 'Foisy', + 'Nordlund', + 'Peppler', + 'Kishbaugh', + 'Marcil', + 'Mcfarren', + 'Puello', + 'Supplee', + 'Boyea', + 'Depp', + 'Tift', + 'Wince', + 'Pam', + 'Ifill', + 'Brodt', + 'Caamano', + 'Gibler', + 'Litherland', + 'Miesner', + 'Pixler', + 'Schwimmer', + 'Suriano', + 'Abendroth', + 'Gillaspy', + 'Kumpf', + 'Schroepfer', + 'Boals', + 'Seneca', + 'Sasson', + 'Hindes', + 'Posten', + 'Lann', + 'Anctil', + 'Arebalo', + 'Beacom', + 'Boberg', + 'Coufal', + 'Didion', + 'Fromme', + 'Greenan', + 'Guerrette', + 'Hudec', + 'Kazmi', + 'Lucchese', + 'Mouw', + 'Savastano', + 'Schomer', + 'Shorb', + 'Storz', + 'Finazzo', + 'Knigge', + 'Pawlikowski', + 'Cercone', + 'Sutfin', + 'Valdespino', + 'Mccartin', + 'Yurko', + 'Treaster', + 'Peaden', + 'Russin', + 'Dibartolo', + 'Dona', + 'Skillern', + 'Brackens', + 'Amyx', + 'Bornemann', + 'Comtois', + 'Kaestner', + 'Kallenbach', + 'Krupka', + 'Lineback', + 'Lopata', + 'Mcclenahan', + 'Monteverde', + 'Otani', + 'Panchal', + 'Pawlicki', + 'Suman', + 'Vallance', + 'Zammit', + 'Liszewski', + 'Trunk', + 'Sharifi', + 'Lents', + 'Watkinson', + 'Willow', + 'Flaming', + 'Sol', + 'Dory', + 'Purchase', + 'Haris', + 'Bigsby', + 'Boonstra', + 'Emge', + 'Goodpasture', + 'Iwata', + 'Kau', + 'Syring', + 'Vlach', + 'Klaassen', + 'Vicuna', + 'Wasden', + 'Cattell', + 'Ridlon', + 'Fassler', + 'Scullion', + 'Hibbitts', + 'Mcgillis', + 'Pla', + 'Mustin', + 'Darty', + 'Minniefield', + 'Bloyd', + 'Calnan', + 'Casal', + 'Fickel', + 'Gamero', + 'Higuchi', + 'Huante', + 'Knies', + 'Letner', + 'Quang', + 'Teufel', + 'Topolski', + 'Tumminello', + 'Vanorder', + 'Slawinski', + 'Nyce', + 'Asmar', + 'Loudin', + 'Karen', + 'Budden', + 'Mothershed', + 'Fenelon', + 'Mccrorey', + 'Ashenfelter', + 'Auge', + 'Christison', + 'Cilley', + 'Corsetti', + 'Coxwell', + 'Critchley', + 'Griep', + 'Hausner', + 'Hiemstra', + 'Koprowski', + 'Kozicki', + 'Marling', + 'Marmo', + 'Noller', + 'Pich', + 'Recendez', + 'Renegar', + 'Rinne', + 'Zeis', + 'Buzzelli', + 'Lipham', + 'Schaner', + 'Kartchner', + 'Kealy', + 'Sinopoli', + 'Krishna', + 'Brinn', + 'Zachry', + 'Barbre', + 'Sharber', + 'Fritze', + 'Hanshew', + 'Lemere', + 'Maruyama', + 'Masker', + 'Melendy', + 'Pelto', + 'Rigo', + 'Rohling', + 'Scobee', + 'Sundell', + 'Tranter', + 'Vancuren', + 'Augustyniak', + 'Mehringer', + 'Sulkowski', + 'Gittins', + 'Twiford', + 'Dumm', + 'Jacklin', + 'Mcquaig', + 'Richison', + 'Jex', + 'Meritt', + 'Hegler', + 'Duboise', + 'Houze', + 'Akana', + 'Corsaro', + 'Delosangeles', + 'Guidice', + 'Maccallum', + 'Moes', + 'Steinhardt', + 'Stirewalt', + 'Wooters', + 'Schissler', + 'Sobeck', + 'Boyte', + 'Jilek', + 'Suder', + 'Kellis', + 'Blankenbaker', + 'Lank', + 'Mandigo', + 'Fremont', + 'Rideau', + 'Beidler', + 'Boda', + 'Gulotta', + 'Havelka', + 'Herberger', + 'Isenhower', + 'Lattanzi', + 'Pandolfi', + 'Shearman', + 'Wilmarth', + 'Dutkiewicz', + 'Mazzuca', + 'Tabarez', + 'Vermilyea', + 'Kray', + 'Vitti', + 'Packwood', + 'Paulos', + 'Howson', + 'Collman', + 'Ameen', + 'Berisha', + 'Capece', + 'Fantasia', + 'Galas', + 'Laszlo', + 'Luthi', + 'Maietta', + 'Mcconaghy', + 'Naab', + 'Nerio', + 'Pineau', + 'Rossbach', + 'Senne', + 'Unangst', + 'Kautzman', + 'Muhs', + 'Ripka', + 'Wehling', + 'Hoot', + 'Jee', + 'Megna', + 'Tirone', + 'Walle', + 'Brandi', + 'Lutter', + 'Mona', + 'Roley', + 'Mcfann', + 'Swader', + 'Cavett', + 'Delmore', + 'Walthour', + 'Goldson', + 'Biddinger', + 'Bjornstad', + 'Buesing', + 'Cerino', + 'Diede', + 'Hagle', + 'Hodgman', + 'Killmer', + 'Loa', + 'Matsunaga', + 'Micciche', + 'Newquist', + 'Poppen', + 'Shellhammer', + 'Tienda', + 'Tino', + 'Mihelich', + 'Garsia', + 'Orzel', + 'Ericsson', + 'Dose', + 'Kotter', + 'Amante', + 'Hanif', + 'Huckleberry', + 'Blandin', + 'Carvin', + 'Axton', + 'Delosrios', + 'Diekmann', + 'Failing', + 'Filipek', + 'Otting', + 'Rozman', + 'Sadeghi', + 'Slutsky', + 'Speake', + 'Szostak', + 'Tacy', + 'Kmiecik', + 'Macgillivray', + 'Yeakel', + 'Dykman', + 'Gorey', + 'Dowding', + 'Revel', + 'Geathers', + 'Cappa', + 'Davidoff', + 'Lukehart', + 'Mccutchan', + 'Neeb', + 'Nikolic', + 'Piorkowski', + 'Sandvig', + 'Schmidgall', + 'Stockbridge', + 'Thornock', + 'Valk', + 'Wiechmann', + 'Chait', + 'Gacek', + 'Schupbach', + 'Gemma', + 'Rus', + 'Barch', + 'Wyles', + 'Scrivener', + 'Salls', + 'Akram', + 'Mcclatchey', + 'Bromfield', + 'Burl', + 'Redwood', + 'Starkes', + 'Beaston', + 'Boggio', + 'Cantillo', + 'Cina', + 'Cryan', + 'Dubs', + 'Edmisten', + 'Fitzer', + 'Fugere', + 'Fundora', + 'Galvis', + 'Jafri', + 'Nalepa', + 'Peri', + 'Pippenger', + 'Rheault', + 'Rohrbacher', + 'Romberg', + 'Samek', + 'Stehlik', + 'Stepan', + 'Torrisi', + 'Wessner', + 'Zappala', + 'Bangerter', + 'Czerniak', + 'Mcshea', + 'Raczkowski', + 'Rohwer', + 'Spehar', + 'Lague', + 'Messman', + 'Angst', + 'Temme', + 'Tolles', + 'Lawn', + 'Ayars', + 'Austen', + 'Stansel', + 'Fairclough', + 'Tribbett', + 'Peevy', + 'Fraiser', + 'Caradine', + 'Fiegel', + 'Gignac', + 'Halpert', + 'Karels', + 'Knappenberger', + 'Prezioso', + 'Rohlfs', + 'Szot', + 'Varano', + 'Weinreich', + 'Butterbaugh', + 'Heying', + 'Vandewalle', + 'Yandle', + 'Thede', + 'Astor', + 'Blanchfield', + 'Hegeman', + 'Fels', + 'Miniard', + 'Lorio', + 'Muhammed', + 'Lazard', + 'Ehmke', + 'Hulst', + 'Imlay', + 'Kinzler', + 'Knaak', + 'Poehler', + 'Prusak', + 'Rakow', + 'Raupp', + 'Sucher', + 'Tanenbaum', + 'Burich', + 'Macmaster', + 'Shapley', + 'Thurgood', + 'Mires', + 'Gotay', + 'Attia', + 'Martis', + 'Greenley', + 'Fothergill', + 'Bonvillain', + 'Buffalo', + 'Dues', + 'Crute', + 'Cantone', + 'Dewit', + 'Dovel', + 'Klopfer', + 'Philhower', + 'Piatek', + 'Pion', + 'Rapaport', + 'Vanwert', + 'Wikstrom', + 'Graffeo', + 'Kissling', + 'Niday', + 'Soong', + 'Adami', + 'Hammersmith', + 'Keir', + 'Yo', + 'Grizzell', + 'Stclaire', + 'Swales', + 'Nole', + 'Pole', + 'Hartgrove', + 'Carrothers', + 'Carlone', + 'Ciano', + 'Finucane', + 'Fitterer', + 'Gellman', + 'Hakimi', + 'Janos', + 'Krings', + 'Malmstrom', + 'Markwardt', + 'Rodin', + 'Schau', + 'Scheible', + 'Orick', + 'Dine', + 'Tremmel', + 'Shon', + 'Wilms', + 'Bren', + 'Bertin', + 'Poster', + 'Jeng', + 'Stcharles', + 'Jenning', + 'Eutsey', + 'Fayne', + 'Gustave', + 'Mccargo', + 'Boruff', + 'Boschert', + 'Burmester', + 'Colello', + 'Conchas', + 'Devi', + 'Dishaw', + 'Funaro', + 'Gallen', + 'Hsueh', + 'Lanser', + 'Macaraeg', + 'Munster', + 'Petsch', + 'Routon', + 'Werkmeister', + 'Woznicki', + 'Boroff', + 'Cochenour', + 'Dibartolomeo', + 'Elzinga', + 'Heyen', + 'Lapaglia', + 'Schiel', + 'Rauda', + 'Woltman', + 'Carll', + 'Kanda', + 'Runnells', + 'Hazelett', + 'Arnwine', + 'Sherfield', + 'Borthwick', + 'Coyner', + 'Ensey', + 'Feinman', + 'Leyendecker', + 'Lickteig', + 'Lubeck', + 'Maccarone', + 'Minahan', + 'Plew', + 'Saur', + 'Schleich', + 'Sixtos', + 'Soller', + 'Valek', + 'Umland', + 'Swogger', + 'Iannacone', + 'Tomey', + 'Venuto', + 'Peru', + 'Adolf', + 'Lemme', + 'Bureau', + 'River', + 'Buffaloe', + 'Leacock', + 'Threat', + 'Boza', + 'Constancio', + 'Dandurand', + 'Hiscock', + 'Kaley', + 'Michaelsen', + 'Roberti', + 'Sicilia', + 'Sliker', + 'Sooter', + 'Steyer', + 'Tabora', + 'Vanderbeek', + 'Vanscyoc', + 'Piercey', + 'Sabater', + 'Bride', + 'Tippens', + 'Acquaviva', + 'Baublitz', + 'Mccanna', + 'Mckaig', + 'Merenda', + 'Obermeier', + 'Pechacek', + 'Pugmire', + 'Shaneyfelt', + 'Steuer', + 'Zeidler', + 'Bodenheimer', + 'Gaglio', + 'Maceachern', + 'Munsterman', + 'Rayle', + 'Wisnewski', + 'Baar', + 'Thi', + 'Foulds', + 'Rufino', + 'Chrisco', + 'Barrientez', + 'Lare', + 'Munnerlyn', + 'Pitter', + 'Koroma', + 'Caisse', + 'Espe', + 'Kerin', + 'Melchiorre', + 'Mentz', + 'Paasch', + 'Parrales', + 'Rhew', + 'Sigley', + 'Skiff', + 'Stockert', + 'Viglione', + 'Kraska', + 'Botto', + 'Ponzio', + 'Wolfley', + 'Wack', + 'Kilborn', + 'Dunnavant', + 'Pitney', + 'Dolman', + 'Biscoe', + 'Michelle', + 'Azcona', + 'Brasington', + 'Fazzino', + 'Hoefs', + 'Kohlmeyer', + 'Laser', + 'Morea', + 'Morrin', + 'Neuwirth', + 'Nicklaus', + 'Pennypacker', + 'Rueckert', + 'Schriefer', + 'Scovel', + 'Swyers', + 'Thebeau', + 'Mijangos', + 'Douville', + 'Tidball', + 'Smullen', + 'Lecount', + 'Pruiett', + 'Branche', + 'Arment', + 'Babiarz', + 'Char', + 'Granlund', + 'Hillock', + 'Kahrs', + 'Khong', + 'Lalley', + 'Laspina', + 'Pietila', + 'Ponciano', + 'Rosengren', + 'Slee', + 'Snowberger', + 'Weglarz', + 'Camarata', + 'Villalovos', + 'Buza', + 'Kenning', + 'Rohrig', + 'Sedor', + 'Perretta', + 'Hamberg', + 'Mongan', + 'Formby', + 'Portier', + 'Silcott', + 'Levell', + 'Barrantes', + 'Bellefeuille', + 'Beneke', + 'Bilbao', + 'Danahy', + 'Delahanty', + 'Deppen', + 'Dicostanzo', + 'Dudding', + 'Elmquist', + 'Handa', + 'Hatem', + 'Loverde', + 'Mesick', + 'Onofrio', + 'Ramesh', + 'Tiberio', + 'Trachtenberg', + 'Vanwagenen', + 'Cassada', + 'Pepitone', + 'Stillson', + 'Pfarr', + 'Radle', + 'Scallan', + 'Carlen', + 'Bermingham', + 'Sagers', + 'Llorens', + 'Turay', + 'Beamish', + 'Carlini', + 'Galipeau', + 'Heavey', + 'Kempker', + 'Masser', + 'Montellano', + 'Peine', + 'Pietro', + 'Plitt', + 'Pollman', + 'Rike', + 'Spees', + 'Vandervelde', + 'Vanwey', + 'Grundman', + 'Marinucci', + 'Molenda', + 'Shideler', + 'Turrubiartes', + 'Schaer', + 'Firkins', + 'Haid', + 'Parnes', + 'Pulse', + 'Masone', + 'Burpo', + 'Tharrington', + 'Winborn', + 'Petite', + 'Buttry', + 'Clason', + 'Eutsler', + 'Haberer', + 'Haft', + 'Kotler', + 'Meloche', + 'Raether', + 'Rengifo', + 'Roback', + 'Stangle', + 'Wilderman', + 'Chickering', + 'Gervacio', + 'Penaranda', + 'Schnieders', + 'Coyer', + 'Laramee', + 'Curts', + 'Bailiff', + 'Truby', + 'Molder', + 'Hedley', + 'Carbon', + 'Gudger', + 'Fontenette', + 'Askren', + 'Deshane', + 'Enriques', + 'Fake', + 'Jungers', + 'Krech', + 'Niemela', + 'Perfetto', + 'Ritt', + 'Soldano', + 'Stanish', + 'Strege', + 'Wichert', + 'Wolz', + 'Zimbelman', + 'Abplanalp', + 'Nikkel', + 'Oravec', + 'Coile', + 'Mizuno', + 'Fenlon', + 'Vanloo', + 'Callery', + 'Hortman', + 'Hashim', + 'Sorey', + 'Ajayi', + 'Alesi', + 'Alessandro', + 'Avants', + 'Bachtel', + 'Bonine', + 'Butkovich', + 'Cerros', + 'Colina', + 'Dayhoff', + 'Favata', + 'Haning', + 'Kamath', + 'Kosik', + 'Loughrey', + 'Mollo', + 'Nagi', + 'Nesler', + 'Nosek', + 'Ordoyne', + 'Politis', + 'Zwolinski', + 'Yaffe', + 'Sigal', + 'Burow', + 'Scarbro', + 'Buckel', + 'Broxson', + 'Goyer', + 'Goding', + 'Delee', + 'Jefferys', + 'Blissett', + 'Balian', + 'Brader', + 'Curreri', + 'Dickmann', + 'Eckerle', + 'Erives', + 'Fedewa', + 'Frisina', + 'Gropp', + 'Hinck', + 'Lamorte', + 'Litzenberger', + 'Proehl', + 'Struss', + 'Tamburello', + 'Digioia', + 'Galarneau', + 'Jurkiewicz', + 'Macnaughton', + 'Talsma', + 'Vlasak', + 'Weyrauch', + 'Yontz', + 'Kho', + 'Stgermaine', + 'Grauer', + 'Benware', + 'Rearden', + 'Molin', + 'Pendergrast', + 'Sivils', + 'Ellery', + 'Ikner', + 'Metayer', + 'Toran', + 'Seaberry', + 'Banderas', + 'Bannan', + 'Critzer', + 'Doescher', + 'Haakenson', + 'Hignite', + 'Hoeksema', + 'Inserra', + 'Korbel', + 'Kruzel', + 'Langen', + 'Mittelstaedt', + 'Popkin', + 'Schwarting', + 'Toral', + 'Ilagan', + 'Lamica', + 'Lierman', + 'Zimmerly', + 'Fosse', + 'Pagnotta', + 'Trenholm', + 'Clayson', + 'Cerutti', + 'Wollard', + 'Mcburnett', + 'Stallcup', + 'Magan', + 'Wonder', + 'Gillock', + 'Ellisor', + 'Clayburn', + 'Mabery', + 'Cariaga', + 'Crail', + 'Dieckman', + 'Joynt', + 'Kleinert', + 'Kutner', + 'Milla', + 'Nauta', + 'Rende', + 'Robare', + 'Santella', + 'Scianna', + 'Sevcik', + 'Smolik', + 'Staudinger', + 'Cedillos', + 'Shroff', + 'Ueda', + 'Yearout', + 'Zuno', + 'Pottle', + 'Klabunde', + 'Tusa', + 'Schomburg', + 'Alto', + 'Packett', + 'Muns', + 'Dante', + 'Jarnigan', + 'Londo', + 'Bigbee', + 'Isles', + 'Nembhard', + 'Appiah', + 'Hypolite', + 'Acebedo', + 'Arlt', + 'Champney', + 'Kawahara', + 'Lehan', + 'Pavlak', + 'Ritacco', + 'Seckinger', + 'Turvey', + 'Vanevery', + 'Wronski', + 'Bahnsen', + 'Clites', + 'Ellwanger', + 'Husak', + 'Lydic', + 'Zubiate', + 'Muehlbauer', + 'Neumeister', + 'Wellnitz', + 'Langstaff', + 'Gort', + 'Eve', + 'Stones', + 'Stanard', + 'Whichard', + 'Cheers', + 'Baldus', + 'Bertoni', + 'Chesebro', + 'Dino', + 'Dubray', + 'Icenhour', + 'Marquard', + 'Mette', + 'Potash', + 'Winterhalter', + 'Crupi', + 'Lascala', + 'Tauer', + 'Vandenburgh', + 'Mende', + 'Swarey', + 'Sarles', + 'Platter', + 'Dekeyser', + 'Jaye', + 'Pelle', + 'Caroll', + 'Rosette', + 'Shepperson', + 'Fooks', + 'Kennerson', + 'Bolser', + 'Chim', + 'Diefenderfer', + 'Frosch', + 'Holzwarth', + 'Kjos', + 'Langland', + 'Meland', + 'Stufflebeam', + 'Worland', + 'Barrales', + 'Chhay', + 'Corkern', + 'Creegan', + 'Golan', + 'Marceaux', + 'Matsuo', + 'Micallef', + 'Otsuka', + 'Rinella', + 'Creveling', + 'Krane', + 'Mcnay', + 'Detter', + 'Drexel', + 'Kibodeaux', + 'Shippey', + 'Medearis', + 'Samms', + 'Drzewiecki', + 'Fariss', + 'Glandon', + 'Heinecke', + 'Hendler', + 'Jungwirth', + 'Panepinto', + 'Rohleder', + 'Saragosa', + 'Stuller', + 'Wissel', + 'Atwal', + 'Tisch', + 'Esterly', + 'Mourad', + 'Brickell', + 'Bough', + 'Rubens', + 'Angevine', + 'Tolin', + 'Sago', + 'Apfel', + 'Ashdown', + 'Derusha', + 'Fiorino', + 'Koyama', + 'Matteucci', + 'Newbrough', + 'Seufert', + 'Stahley', + 'Tyburski', + 'Zaino', + 'Cdebaca', + 'Hormann', + 'Wangen', + 'Winterton', + 'Beagley', + 'Sowden', + 'Daul', + 'Errington', + 'Steber', + 'Emfinger', + 'Olan', + 'Fiveash', + 'Carriger', + 'Breakfield', + 'Ezekiel', + 'Wallington', + 'Hollimon', + 'Izzard', + 'Lyde', + 'Bellmore', + 'Benkert', + 'Bhargava', + 'Dacanay', + 'Dano', + 'Diprima', + 'Garlitz', + 'Hannemann', + 'Janiak', + 'Klann', + 'Kunce', + 'Malicki', + 'Mcgivney', + 'Nordeen', + 'Procell', + 'Rands', + 'Smeltz', + 'Sutch', + 'Wach', + 'Wentling', + 'Karapetyan', + 'Mcvicar', + 'Pennisi', + 'Perley', + 'Graner', + 'Hartney', + 'Shadley', + 'Pennebaker', + 'Cayce', + 'Marris', + 'Burges', + 'Odem', + 'Charvat', + 'Delgreco', + 'Diven', + 'Latu', + 'Mccallion', + 'Mcfeely', + 'Mon', + 'Nagai', + 'Obrecht', + 'Opdyke', + 'Pearlstein', + 'Pomroy', + 'Prothero', + 'Rado', + 'Roehr', + 'Seiffert', + 'Spake', + 'Stech', + 'Thakur', + 'Trzcinski', + 'Uvalle', + 'Vazques', + 'Anschutz', + 'Boecker', + 'Descoteaux', + 'Idol', + 'Stanzione', + 'Welp', + 'Schumer', + 'Ridner', + 'Kasner', + 'Auton', + 'Barca', + 'Ocheltree', + 'Biernat', + 'Mercuri', + 'Truslow', + 'Witters', + 'Mcelhannon', + 'Mccrackin', + 'Brabson', + 'Baumberger', + 'Double', + 'Garis', + 'Kasparian', + 'Kooistra', + 'Loser', + 'Mangone', + 'Massman', + 'Raimondo', + 'Sparacio', + 'Valli', + 'Viets', + 'Wessell', + 'Kieu', + 'Vonderheide', + 'Wojnar', + 'Furbee', + 'Heyden', + 'Lackie', + 'Ehrich', + 'Roupe', + 'Holy', + 'Care', + 'Isa', + 'Samad', + 'Rougeau', + 'Chavous', + 'Rattler', + 'Wedderburn', + 'President', + 'Blackham', + 'Bobak', + 'Crimi', + 'Durland', + 'Gargus', + 'Gitlin', + 'Levandoski', + 'Niu', + 'Piccirilli', + 'Sauvageau', + 'Schweers', + 'Talty', + 'Uthe', + 'Verga', + 'Warzecha', + 'Erisman', + 'Gallacher', + 'Shanholtz', + 'Fulgencio', + 'Migues', + 'Garin', + 'Heisel', + 'Stong', + 'Christiana', + 'Bonenfant', + 'Clancey', + 'Kindley', + 'Nill', + 'Mood', + 'Atterbury', + 'Tobe', + 'Eisenhardt', + 'Franceschini', + 'Heiland', + 'Kreuzer', + 'Lockaby', + 'Scarola', + 'Tessitore', + 'Warehime', + 'Kukowski', + 'Ruhlman', + 'Frymire', + 'Bartone', + 'Wrightson', + 'Langlinais', + 'Planas', + 'Darsey', + 'Darin', + 'Gammel', + 'Giroir', + 'Aspinall', + 'Hollywood', + 'Childres', + 'Copelin', + 'Teamer', + 'Okoro', + 'Abshier', + 'Arizaga', + 'Berenson', + 'Biegler', + 'Dugdale', + 'Erlich', + 'Gavino', + 'Haaland', + 'Lautenschlager', + 'Lilja', + 'Livingood', + 'Lockner', + 'Pyeatt', + 'Reist', + 'Rummell', + 'Schadler', + 'Snare', + 'Zawada', + 'Dumler', + 'Moncivais', + 'Sammarco', + 'Laraway', + 'Voorhis', + 'Detty', + 'Manko', + 'Zale', + 'Autin', + 'Quaid', + 'Denver', + 'Demario', + 'Nearing', + 'Amerine', + 'Bea', + 'Carraher', + 'Dierkes', + 'Dutko', + 'Hosek', + 'Kassner', + 'Meo', + 'Mesler', + 'Norquist', + 'Pacetti', + 'Pellerito', + 'Ryser', + 'Turnmire', + 'Caniglia', + 'Zollman', + 'Gerwig', + 'Denslow', + 'Stapler', + 'Majid', + 'Prestage', + 'Eargle', + 'Spight', + 'Argabright', + 'Borgeson', + 'Cipollone', + 'Dippold', + 'Korf', + 'Milhoan', + 'Pinelli', + 'Roblero', + 'Scolaro', + 'Sperl', + 'Svensson', + 'Bauguess', + 'Freimuth', + 'Luquin', + 'Barman', + 'Solivan', + 'Buel', + 'Birkeland', + 'Cafiero', + 'Degollado', + 'Demeyer', + 'Hoberg', + 'Homola', + 'Kadel', + 'Koslowski', + 'Lefrancois', + 'Macconnell', + 'Madill', + 'Nudelman', + 'Raucci', + 'Reidenbach', + 'Schermer', + 'Sergio', + 'Bucko', + 'Haegele', + 'Nibert', + 'Sidell', + 'Slape', + 'Hellard', + 'Russi', + 'Wilcock', + 'Verdejo', + 'Lessley', + 'Camille', + 'Topps', + 'Acampora', + 'Blacketer', + 'Clapham', + 'Efaw', + 'Louks', + 'Mersch', + 'Odden', + 'Schettler', + 'Schnarr', + 'Sieracki', + 'Skog', + 'Zobrist', + 'Corless', + 'Zunker', + 'Bega', + 'Victoriano', + 'Singler', + 'Keltz', + 'Valcarcel', + 'Curet', + 'Harvison', + 'Mccullah', + 'Cranfield', + 'Gardin', + 'Mewborn', + 'Bisel', + 'Carfagno', + 'Carli', + 'Chirino', + 'Fairless', + 'Gaboury', + 'Goetze', + 'Guitron', + 'Haut', + 'Krupski', + 'Lata', + 'Misiak', + 'Sawaya', + 'Schomaker', + 'Schulke', + 'Tin', + 'Dewhurst', + 'Krummel', + 'Hannahs', + 'Carlow', + 'Hemp', + 'Bowdoin', + 'Breda', + 'Chriss', + 'Kebede', + 'Binney', + 'Brasseaux', + 'Cunliffe', + 'Gantner', + 'Gillick', + 'Hottle', + 'Hren', + 'Irani', + 'Klitzke', + 'Luhrs', + 'Micale', + 'Oien', + 'Oppelt', + 'Rallo', + 'Ringwald', + 'Stonerock', + 'Strebel', + 'Tiberi', + 'Volner', + 'Whetstine', + 'Wrubel', + 'Brakebill', + 'Fechner', + 'Geurts', + 'Hoefling', + 'Misener', + 'Andros', + 'Dimock', + 'Rosendo', + 'Megill', + 'Gloyd', + 'Garney', + 'Andries', + 'Esco', + 'Rhames', + 'Draine', + 'Plair', + 'Jiggetts', + 'Atcheson', + 'Brienza', + 'Cerveny', + 'Depaoli', + 'Deroo', + 'Dorf', + 'Guidotti', + 'Heimlich', + 'Insalaco', + 'Kaczorowski', + 'Kinnunen', + 'Loureiro', + 'Lyster', + 'Pia', + 'Piccoli', + 'Quale', + 'Sadek', + 'Stenstrom', + 'Strause', + 'Tortorella', + 'Traweek', + 'Vanderwerff', + 'Varian', + 'Vink', + 'Waxler', + 'Wynia', + 'Annese', + 'Economou', + 'Whitsel', + 'Dougher', + 'Schnieder', + 'Cosman', + 'Farra', + 'Osmon', + 'Bardon', + 'Rampersaud', + 'Jane', + 'Kirts', + 'Chennault', + 'Thomison', + 'Graig', + 'Narine', + 'Gunner', + 'Aamodt', + 'Adinolfi', + 'Adolphson', + 'Aki', + 'Alderton', + 'Aloisio', + 'Bellavia', + 'Clutts', + 'Coughran', + 'Frasco', + 'Guinta', + 'Hatala', + 'Ibach', + 'Mecum', + 'Medero', + 'Neria', + 'Nery', + 'Pignataro', + 'Podesta', + 'Statzer', + 'Stombaugh', + 'Szczesny', + 'Kovaleski', + 'Ades', + 'Bauers', + 'Bern', + 'Horsfall', + 'Masood', + 'Cinque', + 'Stay', + 'Beare', + 'Donavan', + 'Ikerd', + 'Seney', + 'Layson', + 'Coler', + 'Tuft', + 'Tamplin', + 'Billinger', + 'Scrivens', + 'Bartolomei', + 'Baza', + 'Dimattia', + 'Dotterer', + 'Dushane', + 'Fulop', + 'Iacovelli', + 'Macnamara', + 'Mahlum', + 'Noteboom', + 'Rebstock', + 'Drechsler', + 'Itzkowitz', + 'Rigler', + 'Schrom', + 'Pirozzi', + 'Ferre', + 'Shiley', + 'Villanova', + 'Barona', + 'Farrel', + 'Shelman', + 'Nute', + 'Rowlette', + 'Tarrance', + 'Cadorette', + 'Christenberry', + 'Deocampo', + 'Farace', + 'Fesmire', + 'Kallman', + 'Koogler', + 'Pitsch', + 'Salce', + 'Schnepf', + 'Totaro', + 'Towey', + 'Urdiales', + 'Gotschall', + 'Brunett', + 'Dier', + 'Hainsworth', + 'Seabury', + 'Cornelious', + 'Altobelli', + 'Andreozzi', + 'Bohlmann', + 'Carranco', + 'Daubenspeck', + 'Delagrange', + 'Delo', + 'Faler', + 'Ficke', + 'Hellinger', + 'Hudman', + 'Ihde', + 'Landolfi', + 'Leiner', + 'Mosman', + 'Rang', + 'Tarbet', + 'Wineman', + 'Fehrman', + 'Guinto', + 'Icenogle', + 'Tomasik', + 'Looman', + 'Iriarte', + 'Denaro', + 'Montross', + 'Piersall', + 'Lauren', + 'Lablanc', + 'Kindrick', + 'Deriso', + 'Manker', + 'Maycock', + 'Cullens', + 'Frieson', + 'Clippinger', + 'Colavito', + 'Fassbender', + 'Fennessy', + 'Granada', + 'Gugliotta', + 'Guiliano', + 'Hirschberg', + 'Kerbs', + 'Kusch', + 'Limmer', + 'Malpica', + 'Mcaloon', + 'Morken', + 'Pytel', + 'Resnik', + 'Spangle', + 'Worstell', + 'Kerkhoff', + 'Kupka', + 'Stanczyk', + 'Storlie', + 'Thurow', + 'Caetano', + 'Ernandez', + 'Males', + 'Coopersmith', + 'Everest', + 'Leander', + 'Demeritt', + 'Thomes', + 'Codner', + 'Livsey', + 'Alcoser', + 'Arico', + 'Balestrieri', + 'Cavalli', + 'Florendo', + 'Gottshall', + 'Hinesley', + 'Lafuente', + 'Landess', + 'Ornstein', + 'Pettingill', + 'Romesburg', + 'Tokunaga', + 'Wiersema', + 'Janeway', + 'Pecha', + 'Steimel', + 'Sproule', + 'Sommerfield', + 'Mirsky', + 'Staines', + 'Pu', + 'Corbit', + 'Mcelmurry', + 'Wickes', + 'Yell', + 'Mordecai', + 'Aye', + 'Boldin', + 'China', + 'Fason', + 'Thibeaux', + 'Nesby', + 'Bergevin', + 'Besecker', + 'Dohrmann', + 'Fujioka', + 'Fyock', + 'Goralski', + 'Kirschenbaum', + 'Knipper', + 'Menor', + 'Mischler', + 'Nolder', + 'Odoherty', + 'Pickerill', + 'Poremba', + 'Swantek', + 'Difabio', + 'Kulka', + 'Servais', + 'Wickizer', + 'Melecio', + 'Zeek', + 'Fruit', + 'Agnes', + 'Bar', + 'Mccarrell', + 'Hopgood', + 'Califano', + 'Cratty', + 'Dishner', + 'Gabrielli', + 'Hamacher', + 'Hinote', + 'Jakob', + 'Klinkhammer', + 'Krasinski', + 'Krysiak', + 'Pardi', + 'Petrilli', + 'Razon', + 'Reifsnyder', + 'Reisig', + 'Reller', + 'Sassano', + 'Steinhart', + 'Wrede', + 'Zevallos', + 'Coombe', + 'Quesnel', + 'Rebuck', + 'Wantz', + 'Bendele', + 'Lacomb', + 'Hagge', + 'Donelan', + 'Kempe', + 'Po', + 'Varnadoe', + 'Constantin', + 'Deon', + 'Motte', + 'Beckum', + 'Parchment', + 'Meriweather', + 'Borucki', + 'Fatima', + 'Gerkin', + 'Guglielmi', + 'Hettich', + 'Hoerr', + 'Karlsson', + 'Kenealy', + 'Paolillo', + 'Pfenning', + 'Rueger', + 'Schildt', + 'Sem', + 'Vilches', + 'Dornbusch', + 'Erdahl', + 'Kleinhenz', + 'Moneypenny', + 'Tomasko', + 'Vandevender', + 'Cromley', + 'Tun', + 'Velasques', + 'Roble', + 'Burgo', + 'Waples', + 'Mabon', + 'Benincasa', + 'Buttermore', + 'Dalbec', + 'Eikenberry', + 'Fuehrer', + 'Hossler', + 'Lepp', + 'Opheim', + 'Sarsfield', + 'Strobl', + 'Strouth', + 'Tousley', + 'Wilczek', + 'Kleppe', + 'Muraoka', + 'Wiencek', + 'Pinckard', + 'Ahsan', + 'Welder', + 'Forton', + 'Lorden', + 'Stlawrence', + 'Marina', + 'Mcquire', + 'Randleman', + 'Pates', + 'Fluitt', + 'Scotland', + 'Clerk', + 'Townsell', + 'Arrasmith', + 'Baisch', + 'Berling', + 'Busler', + 'Curtice', + 'Ebinger', + 'Fleeger', + 'Geng', + 'Goettsch', + 'Henneberry', + 'Johannesen', + 'Mcilrath', + 'Perigo', + 'Phibbs', + 'Riske', + 'Scarcella', + 'Vandyken', + 'Barstad', + 'Dicamillo', + 'Ernsberger', + 'Guebara', + 'Peetz', + 'Newcome', + 'Alterman', + 'Weik', + 'Trier', + 'Yeats', + 'Hugg', + 'Crayne', + 'Ige', + 'Coach', + 'Archuletta', + 'Bodi', + 'Cadavid', + 'Ceccarelli', + 'Derksen', + 'Deutscher', + 'Genter', + 'Gogel', + 'Gorczyca', + 'Grohs', + 'Koplin', + 'Kozloski', + 'Lillo', + 'Oplinger', + 'Pulis', + 'Renk', + 'Repka', + 'Scavo', + 'Vitagliano', + 'Weinkauf', + 'Yellin', + 'Boehlke', + 'Montecalvo', + 'Castrillo', + 'Grenon', + 'Wellen', + 'Keelan', + 'Coville', + 'Rison', + 'Jourdain', + 'Chestnutt', + 'Sharpley', + 'Acharya', + 'Bartles', + 'Burruel', + 'Capelle', + 'Contos', + 'Friedrichsen', + 'Heaberlin', + 'Hermiz', + 'Iracheta', + 'Klutts', + 'Koziel', + 'Salto', + 'Scaturro', + 'Stasik', + 'Stitzel', + 'Wiseley', + 'Paccione', + 'Squyres', + 'Leverich', + 'Holderness', + 'Elvin', + 'Morand', + 'Lizana', + 'Woolen', + 'Amarante', + 'Arn', + 'Biedermann', + 'Daddio', + 'Davilla', + 'Forti', + 'Gripp', + 'Hanzlik', + 'Iannotti', + 'Larin', + 'Nakajima', + 'Novacek', + 'Pesch', + 'Regino', + 'Rosengarten', + 'Schleif', + 'Searing', + 'Sikkema', + 'Walstrom', + 'Guastella', + 'Hemstreet', + 'Rorabaugh', + 'Weisenburger', + 'Cannan', + 'Band', + 'Fowkes', + 'Bennetts', + 'Purviance', + 'Tippin', + 'Brossard', + 'Seigle', + 'Babyak', + 'Billiter', + 'Cartner', + 'Deetz', + 'Dorow', + 'Laur', + 'Leblond', + 'Lecomte', + 'Morando', + 'Reitman', + 'Sarria', + 'Scheu', + 'Timmermann', + 'Vaneck', + 'Vangorp', + 'Windhorst', + 'Kaeser', + 'Kosloski', + 'Cappuccio', + 'Knitter', + 'Evon', + 'Garbett', + 'Wickens', + 'Ruston', + 'Fregia', + 'Ashurst', + 'Ede', + 'Strider', + 'Reaux', + 'Castellani', + 'Debus', + 'Degracia', + 'Hineman', + 'Laning', + 'Litts', + 'Losito', + 'Massi', + 'Mazzara', + 'Schriber', + 'Seyfert', + 'Strength', + 'Treptow', + 'Yuhasz', + 'Kamrath', + 'Krigbaum', + 'Marrocco', + 'Wanta', + 'Yakubov', + 'Hy', + 'Sabedra', + 'Belling', + 'Deats', + 'Mahaffy', + 'Brodrick', + 'Mcneece', + 'Madding', + 'Mottley', + 'Asp', + 'Borgerding', + 'Conrady', + 'Dagenhart', + 'Defusco', + 'Duensing', + 'Ensz', + 'Fockler', + 'Gajda', + 'Masino', + 'Minster', + 'Naso', + 'Nifong', + 'Ohlsen', + 'Prairie', + 'Rosendale', + 'Rotman', + 'Salzano', + 'Samet', + 'Takagi', + 'Vandagriff', + 'Vespa', + 'Zaragosa', + 'Howdyshell', + 'Kilburg', + 'Mellado', + 'Mollet', + 'Varone', + 'Benne', + 'Dillehay', + 'Ruther', + 'Gullick', + 'Lasure', + 'Wilkenson', + 'Lawrance', + 'Amacker', + 'Wisher', + 'Pryer', + 'Torian', + 'Aragona', + 'Dains', + 'Darrigo', + 'Escajeda', + 'Fertitta', + 'Futral', + 'Kielty', + 'Kightlinger', + 'Lanuza', + 'Marich', + 'Mcenaney', + 'Mohrman', + 'Pressnell', + 'Prestia', + 'Scullin', + 'Seidner', + 'Steigerwalt', + 'Wassell', + 'Bonavita', + 'Bourgault', + 'Sentz', + 'Viswanathan', + 'Hanchey', + 'Volpi', + 'Wilensky', + 'Mathey', + 'Mages', + 'Raimo', + 'Cozine', + 'Sprow', + 'Petties', + 'Bracht', + 'Cayabyab', + 'Comp', + 'Flamenco', + 'Friederich', + 'Hori', + 'Husmann', + 'Isidoro', + 'Ketchem', + 'Krishnamurthy', + 'Kucinski', + 'Lalani', + 'Lamacchia', + 'Lecher', + 'Morante', + 'Schrieber', + 'Sciarra', + 'Vandamme', + 'Welz', + 'Bozich', + 'Cancilla', + 'Panduro', + 'Mcglade', + 'Wasmund', + 'Riso', + 'Moronta', + 'Kemple', + 'Rocks', + 'Sainsbury', + 'Solo', + 'Harnage', + 'Sturkie', + 'Hollingworth', + 'Denley', + 'Bumpass', + 'Lovick', + 'Bribiesca', + 'Dewilde', + 'Drohan', + 'Geringer', + 'Kokoszka', + 'Kronberg', + 'Lewinski', + 'Lunney', + 'Morehart', + 'Ty', + 'Vasseur', + 'Vona', + 'Wriston', + 'Casarrubias', + 'Copsey', + 'Rochette', + 'Macwilliams', + 'Natali', + 'Milanes', + 'Rux', + 'Woodcox', + 'Bernett', + 'Bronaugh', + 'Fulwood', + 'Bhalla', + 'Depalo', + 'Hench', + 'Huckeba', + 'Kasch', + 'Kisor', + 'Marinos', + 'Nakahara', + 'Parrent', + 'Rantz', + 'Schoenbeck', + 'Schwieterman', + 'Selk', + 'Swonger', + 'Walding', + 'Nunamaker', + 'Schuchardt', + 'Leverton', + 'Fiallo', + 'Viruet', + 'Fadel', + 'Robel', + 'Calley', + 'Renton', + 'Rack', + 'Brin', + 'Cocks', + 'Mcivor', + 'Bois', + 'Demary', + 'Bason', + 'Dowlen', + 'Prophete', + 'Collymore', + 'Beisner', + 'Briand', + 'Cumberledge', + 'Curro', + 'Cutcher', + 'Daponte', + 'Eckroth', + 'Edgemon', + 'Farinella', + 'Kobe', + 'Muilenburg', + 'Osiecki', + 'Cutsinger', + 'Biggar', + 'Maciver', + 'Quesinberry', + 'Rippetoe', + 'Baswell', + 'Caven', + 'Mimbs', + 'Hurlock', + 'Cham', + 'Cypress', + 'Emile', + 'Beitel', + 'Bellavance', + 'Casada', + 'Fandel', + 'Gillentine', + 'Gorelick', + 'Kassis', + 'Klim', + 'Kohnke', + 'Lutgen', + 'Nalbandian', + 'Schepis', + 'Troester', + 'Hartje', + 'Hippensteel', + 'Kiehn', + 'Kuenzi', + 'Greenburg', + 'Boroughs', + 'Catton', + 'Adney', + 'Olivencia', + 'Mcdermitt', + 'Ashwell', + 'Leazer', + 'Poag', + 'Prevo', + 'Porcher', + 'Hugley', + 'Salone', + 'Jupiter', + 'Bratz', + 'Ehresman', + 'Fauber', + 'Filippelli', + 'Kesling', + 'Kronk', + 'Mcelhiney', + 'Mcgreal', + 'Miyasato', + 'Moomey', + 'Nicolini', + 'Osberg', + 'Ostroski', + 'Sanzo', + 'Sybert', + 'Dimichele', + 'Gerrits', + 'Shatley', + 'Weider', + 'Faraj', + 'Paules', + 'Yarberry', + 'Lege', + 'Pembroke', + 'Clipper', + 'Filmore', + 'Crichlow', + 'Blaustein', + 'Boak', + 'Canzoneri', + 'Crescenzo', + 'Ebaugh', + 'Feig', + 'Jens', + 'Knoebel', + 'Mohammadi', + 'Montour', + 'Norgren', + 'Pasquini', + 'Prost', + 'Reh', + 'Rosal', + 'Thesing', + 'Titcomb', + 'Wolinski', + 'Zeitlin', + 'Depoy', + 'Guccione', + 'Ritsema', + 'Valent', + 'Drey', + 'Govoni', + 'Lonsdale', + 'Hultz', + 'Harvie', + 'Levison', + 'Colomb', + 'Dace', + 'Cleckley', + 'Godette', + 'Brentlinger', + 'Fetrow', + 'Giuffrida', + 'Kopka', + 'Kurtzman', + 'Panameno', + 'Pannone', + 'Parzych', + 'Seipp', + 'Stobbe', + 'Thulin', + 'Torosian', + 'Trani', + 'Zietlow', + 'Montufar', + 'Stohr', + 'Woloszyn', + 'Cimini', + 'Angles', + 'Nicasio', + 'Vi', + 'Em', + 'Couchman', + 'Hobbie', + 'Bluestein', + 'Phillipson', + 'Shiels', + 'Altice', + 'Williston', + 'Kone', + 'Tadesse', + 'Abbruzzese', + 'Badders', + 'Duxbury', + 'Egeland', + 'Freyre', + 'Haen', + 'Hineline', + 'Kniss', + 'Kothe', + 'Kyker', + 'Popelka', + 'Sanjose', + 'Slaugh', + 'Wecker', + 'Wiechman', + 'Bilello', + 'Keezer', + 'Knode', + 'Longhurst', + 'Wisser', + 'Cease', + 'Contrera', + 'Berroa', + 'Aguon', + 'Pott', + 'Blitch', + 'Suares', + 'Bein', + 'Acre', + 'Ailes', + 'Tutwiler', + 'Porte', + 'Ashwood', + 'Blackson', + 'Viverette', + 'Balthazar', + 'Kidane', + 'Allegretti', + 'Corbeil', + 'Crossno', + 'Cudworth', + 'Federspiel', + 'Hamstra', + 'Kibbey', + 'Lefevers', + 'Loomer', + 'Losada', + 'Medema', + 'Palmerin', + 'Peregoy', + 'Previte', + 'Riedinger', + 'Schlossberg', + 'Wilemon', + 'Lepkowski', + 'Mcdanel', + 'Commisso', + 'Baiza', + 'Fones', + 'Divis', + 'Diedrick', + 'Grave', + 'Bonkowski', + 'Cerami', + 'Drinkwine', + 'Hauke', + 'Heun', + 'Keilman', + 'Klemmer', + 'Mella', + 'Olarte', + 'Ryall', + 'Veltman', + 'Wlodarczyk', + 'Bashor', + 'Kubinski', + 'Vanacker', + 'Prouse', + 'Perrott', + 'Berrio', + 'Mccarney', + 'Seiders', + 'Jafari', + 'Louque', + 'Melder', + 'Grazier', + 'Gabay', + 'Hardway', + 'Sadiq', + 'Sully', + 'Durrell', + 'Barno', + 'Maybin', + 'Brazile', + 'Asante', + 'Awalt', + 'Badal', + 'Cucinotta', + 'Grenfell', + 'Hartis', + 'Herbster', + 'Hesch', + 'Klosowski', + 'Overfelt', + 'Pangelinan', + 'Pflum', + 'Rozema', + 'Spivack', + 'Vallez', + 'Vetere', + 'Villamor', + 'Wedekind', + 'Bobrowski', + 'Nguyenthi', + 'Nowaczyk', + 'Vis', + 'Pownall', + 'Susan', + 'Yanni', + 'Gest', + 'Balthrop', + 'Treasure', + 'Harston', + 'Frett', + 'Buttery', + 'Chiarelli', + 'Colledge', + 'Czaplicki', + 'Fahringer', + 'Fedder', + 'Gerstenberger', + 'Gretz', + 'Hallquist', + 'Hemme', + 'Kolling', + 'Krauth', + 'Liquori', + 'Podolsky', + 'Scheirer', + 'Sehgal', + 'Selinger', + 'Wintermute', + 'Chokshi', + 'Dimarzio', + 'Santoni', + 'Wetherby', + 'Flis', + 'Comley', + 'Boyt', + 'Farrah', + 'Mario', + 'Mcquilkin', + 'Tim', + 'Cusic', + 'Enge', + 'Millage', + 'Waheed', + 'Kenan', + 'Silmon', + 'Mcconico', + 'Bougher', + 'Braly', + 'Coriell', + 'Daignault', + 'Henschen', + 'Holsomback', + 'Johal', + 'Kellams', + 'Schaumburg', + 'Stockinger', + 'Urquidi', + 'Cabanillas', + 'Lindbloom', + 'Willinger', + 'Redpath', + 'Baller', + 'Juarbe', + 'Badia', + 'Elderkin', + 'Dessert', + 'Retter', + 'Mccollam', + 'Rivette', + 'Devins', + 'Hewell', + 'Penniman', + 'Arbuthnot', + 'Cotman', + 'Tezeno', + 'Albo', + 'Beezley', + 'Can', + 'Chesler', + 'Dehne', + 'Demchak', + 'Edberg', + 'Gotham', + 'Ingels', + 'Kaercher', + 'Kwiecinski', + 'Landolt', + 'Macdonnell', + 'Malicoat', + 'Meinen', + 'Niswander', + 'Pandit', + 'Pettet', + 'Pliska', + 'Ploch', + 'Ratigan', + 'Sampsel', + 'Sick', + 'Ciampi', + 'Mctighe', + 'Riester', + 'Salvucci', + 'Tornow', + 'Vencill', + 'Racey', + 'Haroldson', + 'Finder', + 'Dennen', + 'Stano', + 'Boys', + 'Camillo', + 'Woodfield', + 'Turrell', + 'Sami', + 'Annan', + 'Yeldell', + 'Madlock', + 'Manigo', + 'Arcila', + 'Bauza', + 'Bisceglia', + 'Crouthamel', + 'Debenedetto', + 'Delude', + 'Dorta', + 'Fairburn', + 'Garciagarcia', + 'Geeslin', + 'Kazanjian', + 'Loescher', + 'Mccarl', + 'Mulqueen', + 'Pultz', + 'Shutter', + 'Spacek', + 'Yamanaka', + 'Borkholder', + 'Halko', + 'Pieroni', + 'Proano', + 'Sarkisyan', + 'Riopelle', + 'Routson', + 'Fogelman', + 'Sou', + 'Tress', + 'Altemus', + 'Bosh', + 'Laroque', + 'Hueston', + 'Latin', + 'Taitt', + 'Lymon', + 'Chadd', + 'Challis', + 'Comella', + 'Drabik', + 'Entz', + 'Hagner', + 'Knobbe', + 'Luckenbill', + 'Macphail', + 'Mogg', + 'Paustian', + 'Rimel', + 'Schilke', + 'Folkman', + 'Lemery', + 'Quinby', + 'Cliburn', + 'Rowand', + 'Wambach', + 'Gammell', + 'Nobrega', + 'Hoggan', + 'Nightengale', + 'Alison', + 'Batte', + 'Borner', + 'Hudnell', + 'Casseus', + 'Boteler', + 'Cantos', + 'Contois', + 'Coventry', + 'Dezarn', + 'Eisenbarth', + 'Hegel', + 'Jahr', + 'Joss', + 'Lober', + 'Marcks', + 'Portilla', + 'Reinders', + 'Scouten', + 'Siri', + 'Sobocinski', + 'Tesh', + 'Veno', + 'Wheeldon', + 'Yankee', + 'Wanke', + 'Wollin', + 'Longobardi', + 'Mccarson', + 'Sampsell', + 'Harrer', + 'Bakewell', + 'Mcgalliard', + 'Truluck', + 'Bremmer', + 'Lois', + 'Goody', + 'Kassim', + 'Conniff', + 'Elenes', + 'Esker', + 'Groshong', + 'Hallisey', + 'Loree', + 'Marken', + 'Molle', + 'Muntean', + 'Ozaki', + 'Roen', + 'Rumer', + 'Shorr', + 'Tanzer', + 'Varady', + 'Hillmer', + 'Macari', + 'Schuld', + 'Swartzlander', + 'Tsuji', + 'Holahan', + 'Abee', + 'Rowse', + 'Pawley', + 'Samp', + 'Shad', + 'Wintz', + 'Rainford', + 'Cellucci', + 'Cumpton', + 'Dando', + 'Dress', + 'Funari', + 'Gouker', + 'Hemberger', + 'Latz', + 'Meckes', + 'Parrinello', + 'Picardi', + 'Pilz', + 'Pretzer', + 'Schriever', + 'Sodano', + 'Stetter', + 'Storti', + 'Tiu', + 'Zimmerle', + 'Dragone', + 'Engert', + 'Fullenkamp', + 'Rockafellow', + 'Siwek', + 'Zillmer', + 'Devol', + 'Milke', + 'Taira', + 'Richner', + 'Aros', + 'Mancil', + 'Yetman', + 'Hanney', + 'Kinion', + 'Ferrand', + 'Conyer', + 'Chahal', + 'Fulfer', + 'Gurski', + 'Horseman', + 'Liebe', + 'Nyhus', + 'Pernice', + 'Pesqueira', + 'Rieker', + 'Trautmann', + 'Yellowhair', + 'Schwanz', + 'Salinger', + 'Carvell', + 'Heymann', + 'Grad', + 'Pharo', + 'Pipher', + 'Magalhaes', + 'Kissee', + 'Winthrop', + 'Leid', + 'Sledd', + 'Bladen', + 'Rahaman', + 'Holdman', + 'Goldwire', + 'Lawal', + 'Sinkfield', + 'Bryk', + 'Butkiewicz', + 'Gagen', + 'Gettle', + 'Goede', + 'Hardenbrook', + 'Heinsohn', + 'Kovalcik', + 'Needleman', + 'Obeso', + 'Parziale', + 'Schaus', + 'Wadlow', + 'Haluska', + 'Stiteler', + 'Zaruba', + 'Tschirhart', + 'Biscardi', + 'Gopal', + 'Avella', + 'Ponto', + 'Levit', + 'Trevor', + 'Pimienta', + 'Plass', + 'Guthery', + 'Cordy', + 'Tuff', + 'Zellars', + 'Altier', + 'Berges', + 'Connick', + 'Deruyter', + 'Divita', + 'Frankovich', + 'Ingenito', + 'Kosman', + 'Lantis', + 'Lovering', + 'Sortino', + 'Waage', + 'Wildrick', + 'Barberio', + 'Domin', + 'Meisels', + 'Sender', + 'Giovanni', + 'Sanguinetti', + 'Beary', + 'Helmstetter', + 'Joens', + 'Beaven', + 'Kines', + 'Surrency', + 'Sheilds', + 'Chamber', + 'Albarez', + 'Ambrocio', + 'Arrellano', + 'Berrigan', + 'Bookwalter', + 'Caravella', + 'Higbie', + 'Lotter', + 'Lougee', + 'Manganiello', + 'Nobriga', + 'Roorda', + 'Serr', + 'Squillace', + 'Tejera', + 'Tipping', + 'Wohler', + 'Carreto', + 'Deignan', + 'Luebbers', + 'Engelhard', + 'Hollenback', + 'Baldo', + 'Gearin', + 'Bia', + 'Figueras', + 'Lule', + 'Libert', + 'Florida', + 'Wyne', + 'Mccright', + 'Jacko', + 'Cawthorne', + 'Rhue', + 'Betton', + 'Cisse', + 'Arth', + 'Bendickson', + 'Cangialosi', + 'Coltharp', + 'Cubias', + 'Czarnik', + 'Erpelding', + 'Erway', + 'Heister', + 'Mergen', + 'Murrietta', + 'Nachman', + 'Nusser', + 'Ostrem', + 'Pei', + 'Pescatore', + 'Reim', + 'Shaull', + 'Spranger', + 'Uphold', + 'Yslas', + 'Heinold', + 'Lindemuth', + 'Redeker', + 'Rochin', + 'Wisehart', + 'Carsey', + 'Nocella', + 'Combe', + 'Thacher', + 'Hammad', + 'Bene', + 'Yelvington', + 'Mccrone', + 'Driessen', + 'Saxby', + 'Maull', + 'Jeune', + 'Amorim', + 'Degrazia', + 'Doege', + 'Flinchbaugh', + 'Goodreau', + 'Hanisch', + 'Hoaglund', + 'Imamura', + 'Lafler', + 'Linne', + 'Profeta', + 'Reifschneider', + 'Santaana', + 'Scaffidi', + 'Shreeve', + 'Stadelman', + 'Dippolito', + 'Pizzuti', + 'Rodenberg', + 'Schartz', + 'Reiger', + 'Solie', + 'Willen', + 'Atallah', + 'Wyers', + 'Harpel', + 'Cleckler', + 'Fobes', + 'Sniffen', + 'Pedroso', + 'Samara', + 'Malcomb', + 'Penry', + 'Stearn', + 'Seller', + 'Abeita', + 'Bilotti', + 'Brosky', + 'Clewell', + 'Fraijo', + 'Gaskey', + 'Goodfriend', + 'Mesaros', + 'Musch', + 'Nulph', + 'Obarr', + 'Roat', + 'Sabato', + 'Sauerwein', + 'Schum', + 'Silsby', + 'Weyenberg', + 'Corrente', + 'Egloff', + 'Kohrs', + 'Sammartino', + 'Thoennes', + 'Carmer', + 'Madura', + 'Shang', + 'Faxon', + 'Monell', + 'Laden', + 'Yousuf', + 'Mcgauley', + 'Salmond', + 'Berhane', + 'Abood', + 'Bondar', + 'Buehrer', + 'Capelli', + 'Gersten', + 'Hambly', + 'Haymaker', + 'Kosar', + 'Lahaie', + 'Lecrone', + 'Lippy', + 'Pohle', + 'Shimmel', + 'Viall', + 'Yother', + 'Deviney', + 'Kosiba', + 'Wiederholt', + 'Sivley', + 'Wheelis', + 'Kanipe', + 'Braz', + 'Peacher', + 'Quadri', + 'Hancox', + 'Paye', + 'Curlin', + 'Broden', + 'Mckeller', + 'Baltodano', + 'Baquero', + 'Bolek', + 'Brede', + 'Bulson', + 'Christmann', + 'Cisler', + 'Delio', + 'Duffee', + 'Duzan', + 'Kuschel', + 'Mohon', + 'Nedrow', + 'Sengupta', + 'Timpe', + 'Veeder', + 'Zollner', + 'Zummo', + 'Hribar', + 'Laredo', + 'Mcdivitt', + 'Nazari', + 'Davern', + 'Heizer', + 'Orejel', + 'Haggett', + 'Flore', + 'Soley', + 'Bardell', + 'Comegys', + 'Bessent', + 'Shaheed', + 'Brugman', + 'Choudhary', + 'Fehl', + 'Fogt', + 'Heckmann', + 'Iacobucci', + 'Klaver', + 'Lumbert', + 'Mussman', + 'Pierotti', + 'Pihl', + 'Sandrock', + 'Scritchfield', + 'Siefken', + 'Stavropoulos', + 'Thomley', + 'Zenker', + 'Enke', + 'Knoke', + 'Rung', + 'Mikita', + 'Kunkler', + 'Deskin', + 'Egnor', + 'Vader', + 'Allers', + 'Pi', + 'Sproull', + 'Peller', + 'Kendell', + 'Jinkins', + 'Iglehart', + 'Brookens', + 'Darrough', + 'Winzer', + 'Amenta', + 'Aughenbaugh', + 'Barnick', + 'Conaty', + 'Eichmann', + 'Gilday', + 'Guhl', + 'Koskela', + 'Makuch', + 'Osoria', + 'Pujols', + 'Reinsch', + 'Reiswig', + 'Rosebrock', + 'Sahli', + 'Seitzinger', + 'Shermer', + 'Vasbinder', + 'Zanghi', + 'Flahive', + 'Mieczkowski', + 'Osmundson', + 'Willmann', + 'Agramonte', + 'Aven', + 'Vanderzee', + 'Fraher', + 'Kannan', + 'Shira', + 'Zetina', + 'Gilden', + 'Hingle', + 'Boutros', + 'Scutt', + 'Foree', + 'Gillins', + 'Screen', + 'Birden', + 'Guinyard', + 'Berreth', + 'Bertini', + 'Bousman', + 'Butchko', + 'Caras', + 'Donoso', + 'Gavilanes', + 'Karow', + 'Kouri', + 'Rediger', + 'Rininger', + 'Rosecrans', + 'Toops', + 'Vigliotti', + 'Cancio', + 'Karger', + 'Milholland', + 'Thielke', + 'Amster', + 'Rosch', + 'Elks', + 'Vasco', + 'Doshier', + 'Belasco', + 'Lean', + 'Dickason', + 'Suitt', + 'Tipler', + 'Obey', + 'Crear', + 'Redic', + 'Agredano', + 'Amarillas', + 'Arnesen', + 'Celedon', + 'Clapsaddle', + 'Coveney', + 'Demorest', + 'Gleich', + 'Guenthner', + 'Haverland', + 'Jaffee', + 'Kusek', + 'Manni', + 'Mysliwiec', + 'Nakama', + 'Ngan', + 'Ohmer', + 'Romanoff', + 'Salaiz', + 'Zeiders', + 'Bartholow', + 'Budke', + 'Centanni', + 'Koppelman', + 'Liberti', + 'Gatta', + 'Lovegrove', + 'Maggs', + 'Malay', + 'Blind', + 'Kerman', + 'Frans', + 'Rendleman', + 'Tyrone', + 'Ambers', + 'Rambert', + 'Killings', + 'Balicki', + 'Bohac', + 'Brisbois', + 'Cervone', + 'Curtner', + 'Ertle', + 'Fantozzi', + 'Feger', + 'Fineman', + 'Garate', + 'Goldy', + 'Gudmundson', + 'Harcrow', + 'Herdt', + 'Klapp', + 'Mirra', + 'Radu', + 'Saiki', + 'Unser', + 'Valko', + 'Verhoff', + 'Candelas', + 'Ireton', + 'Vanhuss', + 'Wierman', + 'Zawistowski', + 'Geiman', + 'Mess', + 'Full', + 'Fuertes', + 'Derickson', + 'Mccole', + 'Godden', + 'Mizzell', + 'Sane', + 'Shirer', + 'Fickling', + 'Marcelle', + 'Tramble', + 'Cappelletti', + 'Catterton', + 'Champeau', + 'Czyzewski', + 'Dirusso', + 'Herget', + 'Heupel', + 'Hinchliffe', + 'Levitsky', + 'Maheu', + 'Nakao', + 'Petsche', + 'Pilkenton', + 'Raska', + 'Rief', + 'Scheidegger', + 'Schmeltzer', + 'Sherlin', + 'Skarda', + 'Strassburg', + 'Sundaram', + 'Wuertz', + 'Bonanni', + 'Montante', + 'Ottesen', + 'Nading', + 'Bram', + 'Debell', + 'Sia', + 'Latch', + 'Largen', + 'Nack', + 'Smillie', + 'Debold', + 'Bruer', + 'Steedley', + 'Mckinny', + 'Radney', + 'Amadio', + 'Bearman', + 'Canny', + 'Cansino', + 'Cupo', + 'Ekstrand', + 'Forrer', + 'Imm', + 'Kawano', + 'Klingaman', + 'Kovacevich', + 'Lukasiewicz', + 'Mcdermid', + 'Michon', + 'Mincks', + 'Piano', + 'Ronayne', + 'Schaum', + 'Sciandra', + 'Villafan', + 'Wolin', + 'Schrager', + 'Strawderman', + 'Hable', + 'Skees', + 'Persky', + 'Defore', + 'Edmonston', + 'Base', + 'Barrell', + 'Cressey', + 'Husser', + 'Matin', + 'Mckennon', + 'Barak', + 'Buffone', + 'Clemence', + 'Delaguila', + 'Eberwein', + 'Eichholz', + 'Faraone', + 'Herington', + 'Kempa', + 'Kenefick', + 'Lahaye', + 'Larusso', + 'Osterloh', + 'Pfluger', + 'Pomponio', + 'Shiu', + 'Stokke', + 'Trembly', + 'Weck', + 'Alire', + 'Babayan', + 'Hustad', + 'Stumph', + 'Zwiebel', + 'Wicke', + 'Brauch', + 'Milos', + 'Haggart', + 'Mento', + 'Kennamer', + 'Thibeau', + 'Winge', + 'Lords', + 'Debaun', + 'Haw', + 'Mould', + 'Elison', + 'Etling', + 'Froemming', + 'Ghazarian', + 'Justesen', + 'Kawai', + 'Lensing', + 'Lindhorst', + 'Poveda', + 'Rabadan', + 'Vigeant', + 'Warnken', + 'Bermel', + 'Manry', + 'Suppes', + 'Stauder', + 'Dayley', + 'Lose', + 'Tappe', + 'Harle', + 'Mcquain', + 'Bettes', + 'Carline', + 'Cordner', + 'Habeeb', + 'Sisney', + 'Kyer', + 'Bruins', + 'Prosise', + 'Molton', + 'Blye', + 'Mccuin', + 'Babler', + 'Caiazzo', + 'Cereceres', + 'Ciaramitaro', + 'Corkran', + 'Crawshaw', + 'Degan', + 'Dunlavy', + 'Gronewold', + 'Hartner', + 'Kornacki', + 'Lapolla', + 'Mountz', + 'Mumpower', + 'Orefice', + 'Prats', + 'Repasky', + 'Schlee', + 'Sekhon', + 'Stanich', + 'Yilmaz', + 'Desisto', + 'Hanko', + 'Nichter', + 'Risenhoover', + 'Tomasso', + 'Blome', + 'Carda', + 'Ebrahimi', + 'Devor', + 'Pappa', + 'Caravello', + 'Lunday', + 'Slim', + 'Praytor', + 'Pickerel', + 'Wahab', + 'Breeland', + 'Flowe', + 'Brodnax', + 'Monds', + 'Sylla', + 'Bekele', + 'Mozee', + 'Beechy', + 'Birky', + 'Dellavalle', + 'Delmastro', + 'Dematteis', + 'Eckberg', + 'Eisenbraun', + 'Englehardt', + 'Fazzio', + 'Gedney', + 'Hana', + 'Keeran', + 'Lallier', + 'Martenson', + 'Mcelheny', + 'Paar', + 'Suski', + 'Vossen', + 'Westergaard', + 'Westermann', + 'Wiemann', + 'Golz', + 'Lofquist', + 'Pracht', + 'Tifft', + 'Ruhnke', + 'Schnider', + 'How', + 'Knaggs', + 'Bleck', + 'Whitelock', + 'Berringer', + 'Clepper', + 'Birkhead', + 'Pilson', + 'Inabinet', + 'Gentles', + 'Respress', + 'Crumble', + 'Bandera', + 'Bartunek', + 'Buerkle', + 'Dulong', + 'Eisinger', + 'Favero', + 'Giusto', + 'Guisinger', + 'Kiddy', + 'Krisher', + 'Lounsberry', + 'Morikawa', + 'Mowdy', + 'Penaflor', + 'Picariello', + 'Quirion', + 'Scali', + 'Scheibel', + 'Schlitt', + 'Sermeno', + 'Thalman', + 'Barraclough', + 'Boshart', + 'Glatfelter', + 'Hjelm', + 'Horlacher', + 'Muratalla', + 'Schepp', + 'Fogerty', + 'Mulero', + 'Manner', + 'Creecy', + 'Leftridge', + 'Ancira', + 'Anselmi', + 'Blew', + 'Coykendall', + 'Dembinski', + 'Emmerling', + 'Fawver', + 'Giard', + 'Heinzen', + 'Kasson', + 'Linam', + 'Lofaro', + 'Magnotta', + 'Pitzen', + 'Ripa', + 'Skowronek', + 'Sliter', + 'Stauch', + 'Szczepaniak', + 'Yerian', + 'Baccam', + 'Berres', + 'Helstrom', + 'Kocurek', + 'Kostelecky', + 'Corkins', + 'Fesperman', + 'Gibble', + 'Liranzo', + 'Karan', + 'Lavely', + 'Yorks', + 'Lisenbee', + 'Jerger', + 'Cockroft', + 'Brodhead', + 'Weathersbee', + 'Salih', + 'Pore', + 'Melbourne', + 'Code', + 'Scotton', + 'Addie', + 'Snipe', + 'Cuffie', + 'Haynesworth', + 'Borawski', + 'Borchard', + 'Cacciola', + 'Dedic', + 'Grzyb', + 'Hecox', + 'Horacek', + 'Nierman', + 'Nofziger', + 'Raup', + 'Rissler', + 'Segler', + 'Serviss', + 'Soon', + 'Tesmer', + 'Campanaro', + 'Curnutte', + 'Rabold', + 'Schreyer', + 'Siebenaler', + 'Zenteno', + 'Deveney', + 'Kuchera', + 'Ruden', + 'Skaff', + 'Sciulli', + 'Howeth', + 'Hanly', + 'Gola', + 'Forkner', + 'Rosene', + 'Beeker', + 'Mazo', + 'Lambson', + 'Younis', + 'Batch', + 'Ayo', + 'Ackles', + 'Hansbrough', + 'Terrance', + 'Bacani', + 'Cracraft', + 'Ebben', + 'Falzarano', + 'Ferreras', + 'Hovatter', + 'Jaskiewicz', + 'Killpack', + 'Kwasniewski', + 'Mahnken', + 'Natera', + 'Noboa', + 'Rapson', + 'Raybuck', + 'Shima', + 'Vahle', + 'Sheeks', + 'Laker', + 'Krok', + 'Debo', + 'Oberly', + 'Chelf', + 'Catala', + 'Airey', + 'Osten', + 'Golay', + 'Eliot', + 'Lebert', + 'Swaggerty', + 'Hue', + 'Seavers', + 'Bomer', + 'Bouyer', + 'Andazola', + 'Blancarte', + 'Brierly', + 'Centofanti', + 'Dalesandro', + 'Dickstein', + 'Kalas', + 'Langman', + 'Mouradian', + 'Okubo', + 'Overbaugh', + 'Popek', + 'Runnion', + 'Sannes', + 'Schamber', + 'Silfies', + 'Sinko', + 'Sit', + 'Cerrillo', + 'Gayler', + 'Kauth', + 'Culkin', + 'Peers', + 'Spidle', + 'Ballon', + 'Rasmus', + 'Queenan', + 'Reynaud', + 'Ambroise', + 'Mcclenton', + 'Adelmann', + 'Avellino', + 'Fickle', + 'Humm', + 'Hussong', + 'Iturralde', + 'Kritzer', + 'Lautzenheiser', + 'Linsky', + 'Malarkey', + 'Mallia', + 'Marban', + 'Mccance', + 'Nawaz', + 'Pallone', + 'Rindfleisch', + 'Schmall', + 'Sowle', + 'Stanco', + 'Whelpley', + 'Winning', + 'Kopczynski', + 'Pickup', + 'Tsou', + 'Phebus', + 'Munter', + 'Sisko', + 'Fico', + 'Mosco', + 'Rani', + 'Kon', + 'Baggott', + 'Brom', + 'Valerius', + 'Fines', + 'Megee', + 'Salsberry', + 'Sheff', + 'Mourning', + 'Archambeault', + 'Bhatnagar', + 'Budreau', + 'Dieffenbach', + 'Gildner', + 'Hevener', + 'Hippler', + 'Jonker', + 'Keef', + 'Kirlin', + 'Litvak', + 'Liz', + 'Mulhearn', + 'Popal', + 'Samaha', + 'Schwartzberg', + 'Sotello', + 'Weiskopf', + 'Neitzke', + 'Strelow', + 'Nitsch', + 'Lynne', + 'Olver', + 'Bange', + 'Boot', + 'Carmine', + 'Bellville', + 'Lafitte', + 'Condry', + 'Mccotter', + 'Spruiell', + 'Moman', + 'Legree', + 'Bongard', + 'Deiss', + 'Devoy', + 'Gusler', + 'Ianni', + 'Kolker', + 'Lagomarsino', + 'Leier', + 'Marbut', + 'Minsky', + 'Okumura', + 'Roza', + 'Siemon', + 'Vescio', + 'Wirkus', + 'Huizinga', + 'Lazalde', + 'Morici', + 'Ungaro', + 'Detamore', + 'Meer', + 'Erman', + 'Sherrow', + 'Laforte', + 'Pellman', + 'Bostock', + 'Lender', + 'Peagler', + 'Rhem', + 'Brisbon', + 'Angers', + 'Azbill', + 'Busto', + 'Coggeshall', + 'Cucci', + 'Defino', + 'Duey', + 'Fecht', + 'Grudzinski', + 'Guarneri', + 'Huesca', + 'Kolbeck', + 'Mennella', + 'Nishi', + 'Ohaver', + 'Porth', + 'Romanello', + 'Serrata', + 'Thoele', + 'Thornsbury', + 'Ulsh', + 'Vanderlinde', + 'Weninger', + 'Bonaventura', + 'Cura', + 'Filley', + 'Grabinski', + 'Kloc', + 'Kulinski', + 'Maruca', + 'Dantoni', + 'Grohman', + 'Starbird', + 'Rach', + 'Asman', + 'Mosso', + 'Slaney', + 'Kall', + 'Nevil', + 'Blann', + 'Frear', + 'Mosey', + 'Wrench', + 'Balkcom', + 'Liburd', + 'Yeboah', + 'Abbatiello', + 'Creviston', + 'Dunivan', + 'Durnin', + 'Eckerman', + 'Fennimore', + 'Gohlke', + 'Holtan', + 'Kochevar', + 'Kraushaar', + 'Landino', + 'Maack', + 'Montefusco', + 'Noguchi', + 'Norgard', + 'Olafson', + 'Paulick', + 'Petropoulos', + 'Principato', + 'Qazi', + 'Sammis', + 'Sida', + 'Sorum', + 'Vandal', + 'Vertrees', + 'Votta', + 'Wiesman', + 'Fleagle', + 'Panaro', + 'Stolarski', + 'Ogborn', + 'Petta', + 'Annett', + 'Campas', + 'Xing', + 'Lorey', + 'Restaino', + 'Forgue', + 'Rourk', + 'Modisette', + 'Aris', + 'Vandunk', + 'Dia', + 'Alverio', + 'Ancell', + 'Bieler', + 'Bouwman', + 'Campillo', + 'Cebreros', + 'Chant', + 'Cira', + 'Cragun', + 'Geppert', + 'Hemmert', + 'Kister', + 'Luger', + 'Ojala', + 'Pfeifle', + 'Piechocki', + 'Saldarriaga', + 'Skoda', + 'Vangorden', + 'Winberry', + 'Zeeb', + 'Gehm', + 'Oshima', + 'Tofte', + 'Tsoi', + 'Delman', + 'Harsha', + 'Finton', + 'Triola', + 'Bingle', + 'Delise', + 'Westergard', + 'Aul', + 'Celia', + 'Headings', + 'Mates', + 'Coste', + 'Venus', + 'Shearn', + 'Adell', + 'Minnifield', + 'Baxa', + 'Cieri', + 'Coppens', + 'Delahoz', + 'Fratus', + 'Gribbins', + 'Homann', + 'Ilg', + 'Majchrzak', + 'Mcclard', + 'Podolak', + 'Pollan', + 'Savio', + 'Schloemer', + 'Sesma', + 'Tilbury', + 'Torrico', + 'Vanduyn', + 'Eisert', + 'Levalley', + 'Silversmith', + 'Zanoni', + 'Grupe', + 'Marmolejos', + 'Marsch', + 'Martes', + 'Gorley', + 'Furbush', + 'Hughlett', + 'Stcyr', + 'Faustin', + 'Bushaw', + 'Cerbone', + 'Equihua', + 'Fiorella', + 'Ganzer', + 'Gugel', + 'Hladik', + 'Kalra', + 'Leuenberger', + 'Lusardi', + 'Nogales', + 'Schifano', + 'Swalley', + 'Tangney', + 'Zakarian', + 'Arenz', + 'Bottcher', + 'Gervasio', + 'Peschel', + 'Potteiger', + 'Teruya', + 'Tullier', + 'Lenhard', + 'Brusseau', + 'Streett', + 'Loan', + 'Fahmy', + 'Broadfoot', + 'Shugars', + 'Wilshire', + 'Mohabir', + 'Baye', + 'Sean', + 'Caruth', + 'Arroyos', + 'Campise', + 'Capparelli', + 'Desanti', + 'Dunsworth', + 'Fasching', + 'Heldman', + 'Keagle', + 'Kulesa', + 'Lawrenz', + 'Monhollen', + 'Niekamp', + 'Nucci', + 'Ostman', + 'Salzmann', + 'Schemmel', + 'Selin', + 'Stencel', + 'Zilka', + 'Friesner', + 'Onstad', + 'Poovey', + 'Squillante', + 'Tullo', + 'Uriegas', + 'Vigilante', + 'Lasswell', + 'Navedo', + 'Dunnagan', + 'Pevey', + 'Santino', + 'Waldren', + 'Leven', + 'Stinnette', + 'Eleazer', + 'Ragas', + 'Cockfield', + 'Lafontant', + 'Babinski', + 'Balash', + 'Hadler', + 'Kantz', + 'Latini', + 'Lavy', + 'Mally', + 'Maurin', + 'Mifsud', + 'Miguez', + 'Muma', + 'Needle', + 'Orrico', + 'Zalazar', + 'Chinen', + 'Coluccio', + 'Gibboney', + 'Knapke', + 'Moczygemba', + 'Leonguerrero', + 'Punzalan', + 'Lortz', + 'Rosel', + 'Mcclaran', + 'Weatherhead', + 'Mcgurn', + 'Sanville', + 'Goe', + 'Phang', + 'Briskey', + 'Bluitt', + 'Hapner', + 'Lamadrid', + 'Leuthold', + 'Litchford', + 'Scaduto', + 'Smoyer', + 'Stonehouse', + 'Streng', + 'Susman', + 'Swoyer', + 'Tempesta', + 'Tiedt', + 'Politi', + 'Ruotolo', + 'Schwendeman', + 'Siegenthaler', + 'Streff', + 'Strite', + 'Kroft', + 'Lewey', + 'Silbert', + 'Frie', + 'Bentson', + 'Coin', + 'Lupe', + 'Mousa', + 'Syler', + 'Fester', + 'Tenny', + 'Surgeon', + 'Blowe', + 'Metellus', + 'Borboa', + 'Danker', + 'Ferch', + 'Fritzsche', + 'Gudiel', + 'Kilmartin', + 'Nieland', + 'Soffer', + 'Yescas', + 'Chappelear', + 'Hincapie', + 'Landowski', + 'Barfoot', + 'Hesketh', + 'Mittelman', + 'Escorcia', + 'Meetze', + 'Coral', + 'Huddleson', + 'Hoo', + 'Googe', + 'Munir', + 'Reine', + 'Studstill', + 'Swims', + 'Ganaway', + 'Daise', + 'Blando', + 'Bream', + 'Cangemi', + 'Dicola', + 'Difalco', + 'Gleim', + 'Goerke', + 'Jauch', + 'Lashway', + 'Mckinlay', + 'Mura', + 'Polsky', + 'Roehrich', + 'Schwalbach', + 'Tegtmeier', + 'Theel', + 'Wuthrich', + 'Yabut', + 'Zara', + 'Ardizzone', + 'Blasius', + 'Deramo', + 'Heffern', + 'Rickels', + 'Wojtas', + 'Bue', + 'Garant', + 'Kitagawa', + 'Vorhees', + 'Randa', + 'Seider', + 'Bi', + 'Womac', + 'Santerre', + 'Mesmer', + 'Bailly', + 'Argue', + 'Spidell', + 'Manu', + 'General', + 'Exantus', + 'Neloms', + 'Piggee', + 'Agcaoili', + 'Ambrosini', + 'Balleza', + 'Bhavsar', + 'Brandstetter', + 'Cascone', + 'Deyton', + 'Fette', + 'Gershman', + 'Hanni', + 'Hitchner', + 'Manthe', + 'Marengo', + 'Ockerman', + 'Pergola', + 'Ratterree', + 'Shober', + 'Swezey', + 'Vadala', + 'Waszak', + 'Wishard', + 'Zhuang', + 'Bobst', + 'Filippini', + 'Giardino', + 'Johanning', + 'Kloepfer', + 'Dahan', + 'Rahmani', + 'Hett', + 'Sha', + 'Spaugh', + 'Darner', + 'Dagen', + 'Gaier', + 'Musco', + 'Holling', + 'Keahey', + 'Merricks', + 'Nur', + 'Andrick', + 'Demauro', + 'Haury', + 'Hsiung', + 'Kotarski', + 'Kriesel', + 'Leleux', + 'Nazar', + 'Oganesyan', + 'Polivka', + 'Sansoucie', + 'Serafino', + 'Stammer', + 'Tamm', + 'Wachowiak', + 'Zinda', + 'Goedde', + 'Pedregon', + 'Snader', + 'Witczak', + 'Kem', + 'Prabhu', + 'Purtle', + 'Nola', + 'Om', + 'Finster', + 'Bryans', + 'Mateus', + 'Bour', + 'Santy', + 'Mola', + 'Guile', + 'Denne', + 'Bol', + 'Mont', + 'Perro', + 'Haji', + 'Swinger', + 'Mitchelle', + 'Creary', + 'Leeks', + 'Barsotti', + 'Bolender', + 'Dohner', + 'Federman', + 'Lancour', + 'Lueken', + 'Pettinger', + 'Rathmann', + 'Schiess', + 'Schulenberg', + 'Troyan', + 'Dafoe', + 'Delahunt', + 'Domagala', + 'Ganske', + 'Grasmick', + 'Guinther', + 'Hlavac', + 'Klumb', + 'Susko', + 'Vanhandel', + 'Burget', + 'Thaker', + 'Winker', + 'Castellucci', + 'Guerette', + 'Garde', + 'Busher', + 'Usery', + 'Braker', + 'Blan', + 'Goar', + 'Loiseau', + 'Anderberg', + 'Bamber', + 'Biagini', + 'Dack', + 'Groeneveld', + 'Habig', + 'Howk', + 'Kutsch', + 'Mcgloin', + 'Nevares', + 'Piedrahita', + 'Puffenbarger', + 'Racer', + 'Stanaland', + 'Turck', + 'Vanvleck', + 'Velardi', + 'Verhoeven', + 'Wernick', + 'Wherley', + 'Zamzow', + 'Binegar', + 'Kaluza', + 'Kudrna', + 'Marbach', + 'Schwichtenberg', + 'Chay', + 'Lanthier', + 'Balling', + 'Parcher', + 'Venner', + 'Nolette', + 'Quant', + 'Grierson', + 'Quest', + 'Level', + 'Birkner', + 'Evancho', + 'Grinde', + 'Horiuchi', + 'Hoselton', + 'Kuk', + 'Maiello', + 'Matuska', + 'Melito', + 'Northey', + 'Pallante', + 'Porzio', + 'Rad', + 'Rizzolo', + 'Thull', + 'Urenda', + 'Dalfonso', + 'Harbold', + 'Kemerer', + 'Knapton', + 'Meeder', + 'Ruckle', + 'Segui', + 'Behne', + 'Bamburg', + 'Galen', + 'Hallen', + 'Herandez', + 'Chittick', + 'Deshon', + 'Verrier', + 'Sorel', + 'Neylon', + 'Thatch', + 'Bayly', + 'Beever', + 'Galka', + 'Gruhn', + 'Gsell', + 'Happe', + 'Hovan', + 'Marter', + 'Matarese', + 'Mellema', + 'Ollila', + 'Schempp', + 'Serda', + 'Skenandore', + 'Stemper', + 'Toupin', + 'Vandeven', + 'Yauger', + 'Koenigs', + 'Mullendore', + 'Ouellet', + 'Sullenberger', + 'Julson', + 'Pelot', + 'Clamp', + 'Berte', + 'Beese', + 'Matkin', + 'Erie', + 'Rosenburg', + 'Reap', + 'Stelle', + 'Rayon', + 'Hoit', + 'Hollyfield', + 'Kindall', + 'Agent', + 'Glascoe', + 'Holts', + 'Wynder', + 'Balderston', + 'Bernardy', + 'Blehm', + 'Casebeer', + 'Emler', + 'Farrugia', + 'Guzzardo', + 'Johnsrud', + 'Maffeo', + 'Mccartan', + 'Redburn', + 'Reesman', + 'Savas', + 'Shamoon', + 'Shown', + 'Spinale', + 'Tabaka', + 'Wedell', + 'Armato', + 'Bassford', + 'Bungard', + 'Faerber', + 'Freet', + 'Oesterle', + 'Vandeberg', + 'Bacha', + 'Stemm', + 'Edgett', + 'Karrick', + 'Girten', + 'Orgill', + 'Meridith', + 'Cullom', + 'Hennington', + 'Minns', + 'Appleberry', + 'Abare', + 'Annen', + 'Beierle', + 'Berish', + 'Cracchiolo', + 'Dilullo', + 'Kehm', + 'Kuhne', + 'Modglin', + 'Norland', + 'Petruzzelli', + 'Schabel', + 'Stauffacher', + 'Villena', + 'Wageman', + 'Willden', + 'Faiella', + 'Mangiaracina', + 'Petralia', + 'Witwer', + 'Tropp', + 'Bores', + 'Burkel', + 'Stanifer', + 'Teele', + 'Cornick', + 'Credit', + 'Dorvil', + 'Bonillas', + 'Callinan', + 'Colleran', + 'Finer', + 'Krach', + 'Lubas', + 'Lutman', + 'Marien', + 'Mccort', + 'Merica', + 'Mies', + 'Nicotra', + 'Novosad', + 'Priem', + 'Ramakrishnan', + 'Zolman', + 'Deitsch', + 'Georgi', + 'Haberstroh', + 'Kofoed', + 'Kreischer', + 'Nazareno', + 'Norkus', + 'Steimle', + 'Fellin', + 'Ghanem', + 'Kosch', + 'Pages', + 'Balthazor', + 'Corte', + 'Hoh', + 'Shrewsberry', + 'Beharry', + 'Waight', + 'Leconte', + 'Clowney', + 'Tesfaye', + 'Andis', + 'Brosch', + 'Bruckman', + 'Carducci', + 'Erbes', + 'Ferreiro', + 'Gatten', + 'Heggen', + 'Kackley', + 'Klamm', + 'Korff', + 'Lehane', + 'Mech', + 'Montanari', + 'Pousson', + 'Soderholm', + 'Strey', + 'Upp', + 'Wahlen', + 'Cedrone', + 'Steuber', + 'Vonfeldt', + 'Deridder', + 'Shams', + 'Barnas', + 'Bake', + 'Brownrigg', + 'Donohoo', + 'Mccorry', + 'Spruce', + 'Masden', + 'Porchia', + 'Fofana', + 'Bless', + 'Caler', + 'Calva', + 'Carnero', + 'Chakraborty', + 'Clenney', + 'Dockendorf', + 'Dziak', + 'Errickson', + 'Ewoldt', + 'Klippel', + 'Krass', + 'Luebbe', + 'Parlett', + 'Paternostro', + 'Peterka', + 'Petitti', + 'Puthoff', + 'Wessman', + 'Brossman', + 'Glotfelty', + 'Grabau', + 'Kortz', + 'Sienko', + 'Yonan', + 'Fakhoury', + 'Bunney', + 'Sillas', + 'Guerry', + 'Sedwick', + 'Okey', + 'Virgo', + 'Babers', + 'Casali', + 'Chiquito', + 'Correnti', + 'Doverspike', + 'Fryberger', + 'Golas', + 'Golob', + 'Hufstetler', + 'Inoa', + 'Lasser', + 'Nesheim', + 'Peveto', + 'Reckner', + 'Rydzewski', + 'Shartzer', + 'Smouse', + 'Tipple', + 'Wantland', + 'Wolfert', + 'Yordy', + 'Zuleta', + 'Heimerl', + 'Mccarren', + 'Cabeza', + 'Neice', + 'Kassem', + 'Hodgen', + 'Charrier', + 'Duggar', + 'Blacksmith', + 'Cush', + 'Trunnell', + 'Laventure', + 'Salahuddin', + 'Batalla', + 'Brahmbhatt', + 'Breslow', + 'Cua', + 'Deatley', + 'Digrazia', + 'Divirgilio', + 'Falin', + 'Freiberger', + 'Gladish', + 'Holyoak', + 'Lazos', + 'Loader', + 'Mcclafferty', + 'Meloni', + 'Muhr', + 'Salzwedel', + 'Schaab', + 'Shehadeh', + 'Suresh', + 'Verdusco', + 'Younglove', + 'Damman', + 'Fulco', + 'Neikirk', + 'Laver', + 'Biro', + 'Shill', + 'Labarr', + 'Kari', + 'Mcclory', + 'Torelli', + 'Knock', + 'Dormer', + 'Papin', + 'Stoneham', + 'Weathington', + 'Albus', + 'Andel', + 'Banville', + 'Cassens', + 'Chalifoux', + 'Dellaquila', + 'Depauw', + 'Deschene', + 'Genung', + 'Greider', + 'Luhman', + 'Mastropietro', + 'Mignogna', + 'Pisarski', + 'Terrien', + 'Thomure', + 'Tornabene', + 'Beheler', + 'Chimento', + 'Engelbert', + 'Gambone', + 'Goettl', + 'Jasperson', + 'Kovalenko', + 'Infinger', + 'Timbs', + 'Dasgupta', + 'Purdon', + 'Velie', + 'Eland', + 'Ankrum', + 'Narain', + 'Mcfarling', + 'Creagh', + 'Bunyan', + 'Rattigan', + 'Reddix', + 'Aumann', + 'Beilfuss', + 'Bogosian', + 'Bramel', + 'Burlingham', + 'Cruzan', + 'Demel', + 'Dorff', + 'Figley', + 'Friesz', + 'Huffstutler', + 'Mcdaris', + 'Meinecke', + 'Moench', + 'Newville', + 'Normile', + 'Pfund', + 'Pilar', + 'Seckman', + 'Szoke', + 'Zyla', + 'Freilich', + 'Hammerle', + 'Kopel', + 'Liskey', + 'Mesina', + 'Schlicher', + 'Dalen', + 'Bettin', + 'Malanga', + 'Dern', + 'Tuckey', + 'Warder', + 'Harren', + 'Siner', + 'Mahdi', + 'Ahmann', + 'Allor', + 'Claywell', + 'Corkill', + 'Follansbee', + 'Iseman', + 'Lawter', + 'Myslinski', + 'Sauser', + 'Tornatore', + 'Bhasin', + 'Governale', + 'Karstens', + 'Klocek', + 'Stempien', + 'Petrino', + 'Kohlmeier', + 'Igou', + 'Sari', + 'Mareno', + 'Bouche', + 'Romas', + 'Urey', + 'Sprott', + 'Ponzo', + 'Nevills', + 'Affolter', + 'Alleva', + 'Allgaier', + 'Azbell', + 'Branagan', + 'Fiebig', + 'Geremia', + 'Grabert', + 'Grahl', + 'Gruwell', + 'Koebel', + 'Krauter', + 'Kuhnert', + 'Kuperman', + 'Laverdiere', + 'Leuck', + 'Masella', + 'Mierzejewski', + 'Platek', + 'Samaan', + 'Selsor', + 'Vickroy', + 'Whitenack', + 'Zanella', + 'Cavagnaro', + 'Galioto', + 'Schoeneman', + 'Zanotti', + 'Bort', + 'Alpaugh', + 'Culverhouse', + 'Perona', + 'Wheelwright', + 'Amber', + 'Bradner', + 'Sedberry', + 'Goethe', + 'Swygert', + 'Nisbett', + 'Harts', + 'Pendelton', + 'Keita', + 'Addair', + 'Anania', + 'Armagost', + 'Brumett', + 'Butala', + 'Celmer', + 'Forquer', + 'Hagadorn', + 'Jalomo', + 'Koranda', + 'Lemmond', + 'Liske', + 'Mcglamery', + 'Ramiro', + 'Tickner', + 'Toso', + 'Tosti', + 'Beerbower', + 'Bichler', + 'Buege', + 'Cadotte', + 'Chiong', + 'Romberger', + 'Mandarino', + 'Deter', + 'Wallack', + 'Bligh', + 'Harer', + 'Terral', + 'Hobert', + 'Doren', + 'Affleck', + 'Marquess', + 'Lewton', + 'Covel', + 'Reff', + 'Gowins', + 'Claybrooks', + 'Artiles', + 'Brunelli', + 'Campusano', + 'Deshaies', + 'Elpers', + 'Fait', + 'Heathcote', + 'Katayama', + 'Landreneau', + 'Nardelli', + 'Padovano', + 'Pendry', + 'Santillano', + 'Ubaldo', + 'Wurz', + 'Bathke', + 'Fillers', + 'Reitano', + 'Patrone', + 'Mountford', + 'Farran', + 'Burdo', + 'Danish', + 'Windell', + 'Amrine', + 'Pilgreen', + 'Pross', + 'Bowery', + 'Girdner', + 'Stockley', + 'Chisom', + 'Bigos', + 'Cavallero', + 'Choma', + 'Chorba', + 'Doubek', + 'Eynon', + 'Fitzmorris', + 'Gergely', + 'Hilsabeck', + 'Hime', + 'Kafer', + 'Kilday', + 'Lairson', + 'Mccanless', + 'Meenan', + 'Mossburg', + 'Muscato', + 'Raap', + 'Ramp', + 'Reali', + 'Reinard', + 'Rivadeneira', + 'Schwenn', + 'Serbin', + 'Soeder', + 'Wagle', + 'Jablonowski', + 'Vanni', + 'Grapes', + 'Hilleary', + 'Mondor', + 'Natalie', + 'Seat', + 'Heming', + 'Waide', + 'Haverly', + 'Eva', + 'Marshman', + 'Mais', + 'Portlock', + 'Scoby', + 'Sharps', + 'Buday', + 'Bumbalough', + 'Burback', + 'Carano', + 'Eustis', + 'Flaim', + 'Fraticelli', + 'Grimme', + 'Heape', + 'Hoaglin', + 'Kreuser', + 'Odgers', + 'Pastorius', + 'Pavek', + 'Rogoff', + 'Skorupski', + 'Stene', + 'Tomasino', + 'Varble', + 'Vasek', + 'Woolums', + 'Arcaro', + 'Graley', + 'Larkey', + 'Ortlieb', + 'Piccone', + 'Verhey', + 'Inch', + 'Laroe', + 'Brockmeier', + 'Familia', + 'Soll', + 'Duplechin', + 'Blevens', + 'Gell', + 'Hipkins', + 'Kleinpeter', + 'Swindall', + 'Sabir', + 'Kinloch', + 'Muldrew', + 'Clausell', + 'Bouch', + 'Casciano', + 'Dewhirst', + 'Draney', + 'Fourman', + 'Fuente', + 'Ganci', + 'Gentzler', + 'Gerhold', + 'Ingoglia', + 'Jerabek', + 'Keisling', + 'Larivee', + 'Negro', + 'Pelchat', + 'Quilty', + 'Reinig', + 'Rubeck', + 'Rudick', + 'Rulli', + 'Spagnoli', + 'Wiltsie', + 'Vitolo', + 'Neuhauser', + 'Khurana', + 'Vint', + 'Kant', + 'Nead', + 'Deroy', + 'Ransford', + 'Stromer', + 'Buley', + 'Bloxom', + 'Rieves', + 'Bastos', + 'Deckman', + 'Duenes', + 'Hessling', + 'Kresse', + 'Langdale', + 'Penberthy', + 'Polyak', + 'Sagun', + 'Salehi', + 'Sas', + 'Soja', + 'Spieth', + 'Verhulst', + 'Walen', + 'Woodling', + 'Acierno', + 'Bergsma', + 'Biskup', + 'Buonomo', + 'Gores', + 'Koffman', + 'Redder', + 'Ishak', + 'Billow', + 'Ratledge', + 'Widder', + 'Margerum', + 'Bussing', + 'Caccamo', + 'Carozza', + 'Cwik', + 'Forner', + 'Goeden', + 'Greninger', + 'Hartenstein', + 'Hermida', + 'Krutz', + 'Kubes', + 'Kulow', + 'Lynott', + 'Mank', + 'Meinders', + 'Mikrut', + 'Moots', + 'Patek', + 'Pogorzelski', + 'Reinstein', + 'Ruiter', + 'Rupard', + 'Salvia', + 'Sissom', + 'Sligar', + 'Spendlove', + 'Vian', + 'Wissing', + 'Witucki', + 'Brossart', + 'Warhurst', + 'Staron', + 'Gilly', + 'Borck', + 'Mccarn', + 'Stanbery', + 'Aydelotte', + 'Etters', + 'Rho', + 'Menzer', + 'Knoble', + 'Luallen', + 'Meda', + 'Myre', + 'Nevils', + 'Seide', + 'Rouser', + 'Bernas', + 'Bressette', + 'Dohn', + 'Domina', + 'Filion', + 'Fossen', + 'Grunder', + 'Hofland', + 'Larranaga', + 'Launius', + 'Lento', + 'Mohrmann', + 'Papenfuss', + 'Polcyn', + 'Pollina', + 'Reinheimer', + 'Rueb', + 'Sacher', + 'Sauseda', + 'Whitwell', + 'Caspers', + 'Dejager', + 'Kastelic', + 'Kildow', + 'Sappenfield', + 'Schultes', + 'Tucciarone', + 'Gogan', + 'Sarti', + 'Percle', + 'Cagney', + 'Wasley', + 'Getts', + 'Sahm', + 'Brandle', + 'Osbon', + 'Febres', + 'Billett', + 'Pall', + 'Spearing', + 'Thursby', + 'Junious', + 'Allenbaugh', + 'Calamia', + 'Cregan', + 'Hostettler', + 'Leete', + 'Pirrone', + 'Ploeger', + 'Revak', + 'Sarlo', + 'Sayavong', + 'Schlichter', + 'Shonkwiler', + 'Soots', + 'Spak', + 'Thien', + 'Torgeson', + 'Urbanczyk', + 'Vredenburg', + 'Wormuth', + 'Yankovich', + 'Badertscher', + 'Holewinski', + 'Kalinoski', + 'Kwasny', + 'Neidert', + 'Remmel', + 'Uram', + 'Zettlemoyer', + 'Sanna', + 'Walthers', + 'Kinkaid', + 'Rummage', + 'Vane', + 'Morgen', + 'Stum', + 'Ainsley', + 'Mckelvie', + 'Barbin', + 'Shariff', + 'Blanchett', + 'Mayon', + 'Broadie', + 'Millien', + 'Azzarello', + 'Bocock', + 'Bohlander', + 'Brennecke', + 'Daman', + 'Dixit', + 'Goth', + 'Kocur', + 'Koslow', + 'Loncar', + 'Narez', + 'Oleksy', + 'Ouderkirk', + 'Rathe', + 'Sandmann', + 'Scarpino', + 'Siegman', + 'Soloway', + 'Tomeo', + 'Vantuyl', + 'Benesch', + 'Doornbos', + 'Gisler', + 'Nistler', + 'Pelzel', + 'Piecuch', + 'Schweiss', + 'Zieba', + 'Domangue', + 'Curti', + 'Iams', + 'Viger', + 'Sandefer', + 'Maybury', + 'Haneline', + 'Shappell', + 'Charlier', + 'Belardo', + 'Lynk', + 'Ocain', + 'Ismael', + 'Blacksher', + 'Lesesne', + 'Blash', + 'Fantroy', + 'Bucciarelli', + 'Deruiter', + 'Fetner', + 'Filla', + 'Frontera', + 'Furlan', + 'Goepfert', + 'Gorsline', + 'Gugino', + 'Kleis', + 'Kriger', + 'Lebarron', + 'Lesnick', + 'Losano', + 'Macquarrie', + 'Marczak', + 'Mazariego', + 'Moraes', + 'Murano', + 'Myint', + 'Philley', + 'Ruffalo', + 'Salyards', + 'Swab', + 'Trester', + 'Vlcek', + 'Abramo', + 'Kaczmarski', + 'Mastronardi', + 'Lafont', + 'Tomerlin', + 'Mchan', + 'Blanda', + 'Deandrade', + 'Klien', + 'Meno', + 'Maia', + 'Durall', + 'Lansdowne', + 'Cones', + 'Adley', + 'Taffe', + 'Ikard', + 'Sylve', + 'Bartok', + 'Farler', + 'Farnworth', + 'Gookin', + 'Guijarro', + 'Hazan', + 'Hosterman', + 'Klees', + 'Knust', + 'Leadingham', + 'Lefeber', + 'Maisch', + 'Muchmore', + 'Pini', + 'Polinsky', + 'Quakenbush', + 'Rought', + 'Ruta', + 'Tingen', + 'Urness', + 'Valade', + 'Wadle', + 'Hietala', + 'Hockenbury', + 'Ivanoff', + 'Mcevers', + 'Miyazaki', + 'Druckenmiller', + 'Neisler', + 'Vroom', + 'Berland', + 'Rizor', + 'Caris', + 'Jenison', + 'Folmer', + 'Si', + 'Pulling', + 'Houge', + 'Snuggs', + 'Enis', + 'Peeks', + 'Stacker', + 'Destin', + 'Ojo', + 'Barraco', + 'Childree', + 'Ciszewski', + 'Dicenzo', + 'Gowing', + 'Granquist', + 'Kapinos', + 'Khalili', + 'Kienitz', + 'Konrath', + 'Kosa', + 'Schilz', + 'Sealock', + 'Soucek', + 'Stefanko', + 'Trow', + 'Udy', + 'Fricano', + 'Hunnewell', + 'Sieler', + 'Stranahan', + 'Thammavongsa', + 'Zettel', + 'Cutrell', + 'Balter', + 'Clavel', + 'Thibert', + 'Ondo', + 'Senna', + 'Kun', + 'Maximo', + 'Wares', + 'Caldeira', + 'Furgerson', + 'Franklyn', + 'Christophe', + 'Bady', + 'Blanken', + 'Boike', + 'Cuen', + 'Davidian', + 'Glauser', + 'Gleave', + 'Guzy', + 'Halleck', + 'Kempfer', + 'Kenkel', + 'Kloth', + 'Knable', + 'Mcenery', + 'Pizzolato', + 'Schryver', + 'Seminara', + 'Shenoy', + 'Somera', + 'Stroop', + 'Weirick', + 'Yatsko', + 'Evanko', + 'Koegel', + 'Lastinger', + 'Schrenk', + 'Vitullo', + 'Holste', + 'Susa', + 'Pedley', + 'Cove', + 'Levett', + 'Gillyard', + 'Boeding', + 'Delpozo', + 'Denoyer', + 'Farese', + 'Floro', + 'Gavina', + 'Hargus', + 'Kisiel', + 'Konig', + 'Krotz', + 'Lundblad', + 'Masoner', + 'Mumper', + 'Nolf', + 'Sandgren', + 'Schussler', + 'Shallcross', + 'Singhal', + 'Standen', + 'Teta', + 'Vacanti', + 'Yokota', + 'Borski', + 'Filice', + 'Frankum', + 'Kleinsmith', + 'Plauche', + 'Spohr', + 'Goya', + 'Rosensteel', + 'Srey', + 'Touhey', + 'Launer', + 'Dome', + 'Mossey', + 'Mclay', + 'Sturgess', + 'Demond', + 'Buren', + 'Millin', + 'Riddles', + 'Arps', + 'Dugar', + 'Carradine', + 'Brasseur', + 'Burchill', + 'Champoux', + 'Chojnowski', + 'Cyphert', + 'Devincentis', + 'Donze', + 'Gaspari', + 'Harshberger', + 'Merchan', + 'Mulgrew', + 'Parma', + 'Pasqua', + 'Pierpoint', + 'Rozeboom', + 'Rumery', + 'Stahle', + 'Stierwalt', + 'Swander', + 'Tiegs', + 'Trabucco', + 'Withington', + 'Frericks', + 'Kilman', + 'Locastro', + 'Samonte', + 'Sanko', + 'Wisman', + 'Flecha', + 'Coplan', + 'Zafra', + 'Art', + 'Maxam', + 'Cavaness', + 'Willi', + 'Vanliew', + 'Fresh', + 'Bauserman', + 'Bergemann', + 'Buchler', + 'Curbow', + 'Dimascio', + 'Einstein', + 'Favila', + 'Galeno', + 'Granat', + 'Halteman', + 'Janczak', + 'Janicek', + 'Jundt', + 'Karren', + 'Modesitt', + 'Provance', + 'Reasons', + 'Riveron', + 'Salts', + 'Salvino', + 'Sawhney', + 'Shallenberger', + 'Sirk', + 'Tylka', + 'Baumler', + 'Mcmenamy', + 'Territo', + 'Thackeray', + 'Much', + 'Papageorge', + 'Rynders', + 'Bacigalupo', + 'Fulwider', + 'Hendricksen', + 'Lepre', + 'Mangel', + 'Dering', + 'Soda', + 'Bazar', + 'Dinning', + 'Portera', + 'Schatzman', + 'Kernodle', + 'Bashford', + 'Ferrebee', + 'Cortner', + 'Sanker', + 'Livings', + 'Jemmott', + 'Arzaga', + 'Cihak', + 'Cobarrubias', + 'Coey', + 'Coutinho', + 'Deneau', + 'Droll', + 'Hickel', + 'Hillmann', + 'Kitto', + 'Lefebre', + 'Lev', + 'Mato', + 'Mcomber', + 'Norlin', + 'Renstrom', + 'Rhyner', + 'Sacca', + 'Sangha', + 'Sutor', + 'Dwire', + 'Huyser', + 'Kressin', + 'Moilanen', + 'Picado', + 'Schmidlin', + 'Albor', + 'Zaldana', + 'Failor', + 'Dubberly', + 'Youse', + 'Mohiuddin', + 'Shiel', + 'Loran', + 'Hamme', + 'Castine', + 'Lanum', + 'Mcelderry', + 'Riggsbee', + 'Madkins', + 'Abts', + 'Bekker', + 'Boccio', + 'Florin', + 'Lienemann', + 'Madara', + 'Manganello', + 'Mcfetridge', + 'Medsker', + 'Minish', + 'Roberg', + 'Sajdak', + 'Schwall', + 'Sedivy', + 'Suto', + 'Wieberg', + 'Catherman', + 'Ficker', + 'Leckrone', + 'Lieder', + 'Rodak', + 'Tomek', + 'Everard', + 'Spong', + 'Glacken', + 'Polka', + 'Aley', + 'Farro', + 'Stanwood', + 'Petter', + 'Desrosier', + 'Kerl', + 'Goslee', + 'Burston', + 'Pennywell', + 'Birchard', + 'Federer', + 'Flicker', + 'Frangos', + 'Korhonen', + 'Kozikowski', + 'Kyger', + 'Mccoskey', + 'Standing', + 'Terada', + 'Trierweiler', + 'Trupiano', + 'Urbanowicz', + 'Viegas', + 'Ybarbo', + 'Brinlee', + 'Daddona', + 'Deisher', + 'Schwieger', + 'Farless', + 'Slaght', + 'Jarvie', + 'Hunkins', + 'Barrack', + 'Bisset', + 'Bruley', + 'Molen', + 'Milas', + 'Matts', + 'Wickware', + 'Timbers', + 'Minus', + 'Kennebrew', + 'Boorman', + 'Faughn', + 'Feight', + 'Githens', + 'Hazelrigg', + 'Hutzell', + 'Klang', + 'Kogler', + 'Lechtenberg', + 'Malachowski', + 'Orsburn', + 'Retz', + 'Saban', + 'Tak', + 'Underdahl', + 'Veldman', + 'Virnig', + 'Wanat', + 'Achord', + 'Drenth', + 'Heibel', + 'Hendee', + 'Raiche', + 'Saunier', + 'Wertheim', + 'Forand', + 'Stathis', + 'Raider', + 'Cassaro', + 'Cly', + 'Hagey', + 'Moad', + 'Rhody', + 'Fogler', + 'Hellen', + 'Sweezy', + 'Farid', + 'Suddreth', + 'Kenneth', + 'Pindell', + 'Corney', + 'Monsanto', + 'Laye', + 'Lingard', + 'Armwood', + 'Asif', + 'Axley', + 'Barkan', + 'Bittel', + 'Boesen', + 'Camilli', + 'Champa', + 'Dauenhauer', + 'Ehrmann', + 'Gangl', + 'Gatrell', + 'Gehret', + 'Hankel', + 'Kalbach', + 'Kessell', + 'Khatoon', + 'Lanese', + 'Manco', + 'Masteller', + 'Pruner', + 'Remmert', + 'Valasek', + 'Vater', + 'Yurick', + 'Zavalza', + 'Biesecker', + 'Frankenberg', + 'Hovorka', + 'Poissant', + 'Neises', + 'Moog', + 'Hadad', + 'Wittenburg', + 'Devere', + 'Hynds', + 'Sparkes', + 'Brailey', + 'Addo', + 'Accetta', + 'Altschuler', + 'Amescua', + 'Corredor', + 'Didonna', + 'Jencks', + 'Keady', + 'Keidel', + 'Mancebo', + 'Matusiak', + 'Rakoczy', + 'Reamy', + 'Sardella', + 'Slotnick', + 'Fotheringham', + 'Gettman', + 'Kunzler', + 'Manganaro', + 'Manygoats', + 'Huelskamp', + 'Newsham', + 'Kohen', + 'Cong', + 'Goulden', + 'Timmers', + 'Aderhold', + 'Shinall', + 'Cowser', + 'Uzzle', + 'Harps', + 'Balster', + 'Baringer', + 'Bechler', + 'Billick', + 'Chenard', + 'Ditta', + 'Fiallos', + 'Kampe', + 'Kretzschmar', + 'Manukyan', + 'Mcbreen', + 'Mcmanigal', + 'Miko', + 'Mol', + 'Orrego', + 'Penalosa', + 'Ronco', + 'Thum', + 'Tupa', + 'Vittitow', + 'Wierzba', + 'Gavitt', + 'Hampe', + 'Kowalkowski', + 'Neuroth', + 'Sterkel', + 'Herling', + 'Boldman', + 'Camus', + 'Drier', + 'Arcia', + 'Feagans', + 'Thompsen', + 'Maka', + 'Villalona', + 'Bonito', + 'Buist', + 'Dato', + 'Yankey', + 'Daluz', + 'Hollands', + 'Durio', + 'Bradly', + 'Daffin', + 'Chhabra', + 'Dettling', + 'Dolinger', + 'Flenniken', + 'Henrichsen', + 'Laduca', + 'Lashomb', + 'Leick', + 'Luchini', + 'Mcmanaman', + 'Minkoff', + 'Nobbe', + 'Oyster', + 'Quintela', + 'Robar', + 'Sakurai', + 'Solak', + 'Stolt', + 'Taddei', + 'Puopolo', + 'Schwarzkopf', + 'Stango', + 'Mcparland', + 'Schembri', + 'Standefer', + 'Dayan', + 'Sculley', + 'Bhuiyan', + 'Delauder', + 'Harrity', + 'Bree', + 'Haste', + 'Mcbay', + 'Garmany', + 'Maison', + 'Common', + 'Hanton', + 'Aigner', + 'Aliaga', + 'Boeve', + 'Cromie', + 'Demick', + 'Filipowicz', + 'Frickey', + 'Garrigus', + 'Heindl', + 'Hilmer', + 'Homeyer', + 'Lanterman', + 'Larch', + 'Masci', + 'Minami', + 'Palmiter', + 'Rufener', + 'Saal', + 'Sarmento', + 'Seewald', + 'Sestito', + 'Somarriba', + 'Sparano', + 'Vorce', + 'Wombles', + 'Zarr', + 'Antonson', + 'Bruzzese', + 'Chillemi', + 'Dannunzio', + 'Hogrefe', + 'Mastandrea', + 'Moynahan', + 'Wangerin', + 'Wedeking', + 'Ziobro', + 'Flegel', + 'Axsom', + 'Buzby', + 'Slowey', + 'Cuebas', + 'App', + 'Dar', + 'Robers', + 'Elting', + 'Demus', + 'Finkley', + 'Taborn', + 'Balogun', + 'Binstock', + 'Gebel', + 'Hinnenkamp', + 'Kosta', + 'Lamphear', + 'Linhares', + 'Luzader', + 'Mcconathy', + 'Motl', + 'Mroczkowski', + 'Reznicek', + 'Rieken', + 'Sadlowski', + 'Schlink', + 'Snuffer', + 'Tep', + 'Vaske', + 'Whisner', + 'Amesquita', + 'Demler', + 'Macdonell', + 'Rajala', + 'Sandate', + 'Kolk', + 'Bickerton', + 'Dugal', + 'Kirtland', + 'Neilan', + 'Doughman', + 'Crye', + 'Depena', + 'Quire', + 'Hafeez', + 'Rosse', + 'Devon', + 'Deboe', + 'Kitchings', + 'Blackett', + 'Acey', + 'Mcculler', + 'Obie', + 'Pleas', + 'Lurry', + 'Abid', + 'Bierlein', + 'Boisclair', + 'Cabanilla', + 'Celano', + 'Conrow', + 'Deeley', + 'Frankhouser', + 'Janowiak', + 'Jarchow', + 'Mcnicol', + 'Peixoto', + 'Pompeo', + 'Reitmeyer', + 'Scalera', + 'Schnorr', + 'Sideris', + 'Solesbee', + 'Stejskal', + 'Strole', + 'Tosto', + 'Wenke', + 'Dombek', + 'Gottschall', + 'Halbur', + 'Kuchler', + 'Kuyper', + 'Wruck', + 'Lorenc', + 'Search', + 'Chohan', + 'Monda', + 'Clowes', + 'Farson', + 'Rhoad', + 'Clavin', + 'Ramus', + 'Hayley', + 'Dolley', + 'Menton', + 'Dejarnett', + 'Challenger', + 'Branner', + 'Shed', + 'Dada', + 'Flewellen', + 'Volcy', + 'Allphin', + 'Barberena', + 'Bencivenga', + 'Bienkowski', + 'Bossi', + 'Corsini', + 'Dardis', + 'Falconi', + 'Fitzhenry', + 'Gaglione', + 'Handlin', + 'Kainz', + 'Lorge', + 'Nase', + 'Pavich', + 'Perelman', + 'Shanafelt', + 'Towsley', + 'Weill', + 'Zollars', + 'Appelt', + 'Cannizzo', + 'Carrubba', + 'Detar', + 'Dobrzynski', + 'Hashman', + 'Maassen', + 'Mccullagh', + 'Rettinger', + 'Roediger', + 'Rybolt', + 'Savoca', + 'Wortmann', + 'Boria', + 'Mairs', + 'Stream', + 'Larmore', + 'Sama', + 'Graden', + 'Hollinshead', + 'Mandy', + 'Gidney', + 'Demming', + 'Alexandra', + 'Caleb', + 'Abdullahi', + 'Cabal', + 'Dikeman', + 'Ellenbecker', + 'Fosnaugh', + 'Funck', + 'Heidorn', + 'Housden', + 'Ilic', + 'Illescas', + 'Kohlmann', + 'Lagman', + 'Larez', + 'Penafiel', + 'Pense', + 'Ragonese', + 'Reitan', + 'Shetterly', + 'Trapasso', + 'Zank', + 'Zecca', + 'Grisanti', + 'Hemker', + 'Mascolo', + 'Muhlenkamp', + 'Riemann', + 'Schindel', + 'Uncapher', + 'Zelman', + 'Koper', + 'Byrn', + 'Calzadilla', + 'Dilly', + 'Beiser', + 'Maller', + 'Bagg', + 'Winnick', + 'Sillman', + 'Bilton', + 'Esmond', + 'Sconyers', + 'Lemma', + 'Geralds', + 'Lazare', + 'Threats', + 'Accurso', + 'Boitnott', + 'Calcagni', + 'Chavera', + 'Corda', + 'Delisio', + 'Demont', + 'Eichel', + 'Faulds', + 'Ficek', + 'Gappa', + 'Graci', + 'Hammaker', + 'Heino', + 'Katcher', + 'Keslar', + 'Larsh', + 'Lashua', + 'Leising', + 'Magri', + 'Manbeck', + 'Mcwatters', + 'Mixer', + 'Moder', + 'Noori', + 'Pallo', + 'Pfingsten', + 'Plett', + 'Prehn', + 'Reyburn', + 'Savini', + 'Sebek', + 'Thang', + 'Lemberg', + 'Xiang', + 'Stiegler', + 'Groman', + 'Bowlen', + 'Grignon', + 'Morren', + 'Dini', + 'Mcaulay', + 'Ngu', + 'Bethell', + 'Warring', + 'Belyeu', + 'Ramcharan', + 'Mcjunkins', + 'Alms', + 'Ayub', + 'Brem', + 'Dresen', + 'Flori', + 'Geesaman', + 'Haugan', + 'Heppler', + 'Hermance', + 'Korinek', + 'Lograsso', + 'Madriaga', + 'Milbrath', + 'Radwan', + 'Riemersma', + 'Rivett', + 'Roggenbuck', + 'Stefanick', + 'Storment', + 'Ziegenfuss', + 'Blackhurst', + 'Daquila', + 'Maruska', + 'Rybka', + 'Schweer', + 'Tandon', + 'Hersman', + 'Galster', + 'Lemp', + 'Hantz', + 'Enderson', + 'Marchal', + 'Conly', + 'Bali', + 'Canaan', + 'Anstead', + 'Savary', + 'Andy', + 'Tisdell', + 'Livas', + 'Grinage', + 'Afanador', + 'Alviso', + 'Aracena', + 'Denio', + 'Dentremont', + 'Eldreth', + 'Gravois', + 'Huebsch', + 'Kalbfleisch', + 'Labree', + 'Mones', + 'Reitsma', + 'Schnapp', + 'Seek', + 'Shuping', + 'Tortorice', + 'Viscarra', + 'Wahlers', + 'Wittner', + 'Yake', + 'Zamani', + 'Carriveau', + 'Delage', + 'Gargan', + 'Goldade', + 'Golec', + 'Lapage', + 'Meinhart', + 'Mierzwa', + 'Riggenbach', + 'Schloesser', + 'Sedam', + 'Winkels', + 'Woldt', + 'Beckers', + 'Teach', + 'Feagan', + 'Booe', + 'Slates', + 'Bears', + 'Market', + 'Moone', + 'Verdun', + 'Ibe', + 'Jeudy', + 'Agudo', + 'Brisendine', + 'Casillo', + 'Chalupa', + 'Daversa', + 'Fissel', + 'Fleites', + 'Giarratano', + 'Glackin', + 'Granzow', + 'Hawver', + 'Hayashida', + 'Hovermale', + 'Huaman', + 'Jezek', + 'Lansdell', + 'Loughery', + 'Niedzielski', + 'Orellano', + 'Pebley', + 'Rojek', + 'Tomic', + 'Yellen', + 'Zerkle', + 'Boettner', + 'Decook', + 'Digilio', + 'Dinsdale', + 'Germer', + 'Kleve', + 'Marcinek', + 'Mendicino', + 'Pehl', + 'Revoir', + 'Osmun', + 'Bahner', + 'Shone', + 'Howald', + 'Kanode', + 'Amari', + 'Enix', + 'Levene', + 'Joffrion', + 'Lenis', + 'Carmicheal', + 'Njoku', + 'Coffel', + 'Ditter', + 'Grupp', + 'Kabel', + 'Kanzler', + 'Konop', + 'Lupi', + 'Mautz', + 'Mccahill', + 'Perella', + 'Perich', + 'Rion', + 'Ruvolo', + 'Torio', + 'Vipperman', + 'Bentivegna', + 'Formanek', + 'Smet', + 'Tarquinio', + 'Wesche', + 'Dearinger', + 'Makara', + 'Duba', + 'Iser', + 'Nicklow', + 'Wignall', + 'Wanger', + 'Goda', + 'Huckstep', + 'Basse', + 'Debruhl', + 'Hainey', + 'Damour', + 'Ebbs', + 'Armond', + 'Ewings', + 'Rease', + 'Okoye', + 'Arentz', + 'Baack', + 'Bellantoni', + 'Buckholz', + 'Cirigliano', + 'Colletta', + 'Dutka', + 'Everingham', + 'Gilardi', + 'Hudelson', + 'Klimczak', + 'Kneip', + 'Papaleo', + 'Peregrino', + 'Piechowski', + 'Prucha', + 'Ryburn', + 'Scholle', + 'Scholtes', + 'Socarras', + 'Wrightsman', + 'Yum', + 'Campau', + 'Dwinell', + 'Haupert', + 'Lotspeich', + 'Madar', + 'Casa', + 'Michals', + 'Rainier', + 'Tenpenny', + 'Lakeman', + 'Spadoni', + 'Cantrelle', + 'Mangal', + 'Chachere', + 'Swoope', + 'Carwell', + 'Voltaire', + 'Durrah', + 'Roulhac', + 'Aboytes', + 'Apuzzo', + 'Bielinski', + 'Bollenbacher', + 'Borjon', + 'Croak', + 'Dansie', + 'Espin', + 'Euceda', + 'Garone', + 'Garthwaite', + 'Hata', + 'Heu', + 'Hogenson', + 'Jahner', + 'Keesey', + 'Kotas', + 'Labrake', + 'Laitinen', + 'Laumann', + 'Miske', + 'Nickless', + 'Onishi', + 'Setty', + 'Shinnick', + 'Takayama', + 'Tassinari', + 'Tribe', + 'Bowdish', + 'Friesenhahn', + 'Hoffarth', + 'Wachowski', + 'Gudgel', + 'Gautney', + 'Matar', + 'Ellenberg', + 'Inghram', + 'Bevil', + 'Rasul', + 'Niblack', + 'Perkin', + 'Goring', + 'Potier', + 'Bachrach', + 'Bozza', + 'Budz', + 'Devens', + 'Ditzel', + 'Drahos', + 'Ducat', + 'Fahrner', + 'Friedline', + 'Geurin', + 'Goodenow', + 'Greenfeld', + 'Grunow', + 'Ingber', + 'Kashani', + 'Kochman', + 'Kozub', + 'Kukuk', + 'Leppo', + 'Liew', + 'Metheney', + 'Molony', + 'Montemurro', + 'Neiss', + 'Postlethwait', + 'Quaglia', + 'Ruszkowski', + 'Shertzer', + 'Titone', + 'Waldmann', + 'Wenninger', + 'Wheeland', + 'Zorich', + 'Mervine', + 'Weatherholtz', + 'Brotman', + 'Malenfant', + 'Nong', + 'Rogness', + 'Dibert', + 'Gallahan', + 'Gange', + 'Chilcott', + 'Axt', + 'Wiler', + 'Jacot', + 'Ory', + 'Abdon', + 'Fenter', + 'Bryars', + 'Ramroop', + 'Jacox', + 'Mainer', + 'Figures', + 'Alig', + 'Bires', + 'Cassata', + 'Cholewa', + 'Dispenza', + 'Eckmann', + 'Gauer', + 'Gloor', + 'Hattori', + 'Huster', + 'Kopplin', + 'Krugman', + 'Lancon', + 'Ledin', + 'Limb', + 'Marentes', + 'Minges', + 'Monacelli', + 'Monteon', + 'Naslund', + 'Nitsche', + 'Rapozo', + 'Rimkus', + 'Schwerdtfeger', + 'Vandenbos', + 'Balandran', + 'Biehn', + 'Briody', + 'Hackmann', + 'Kalka', + 'Keranen', + 'Lortie', + 'Mannella', + 'Shiffler', + 'Stempel', + 'Takaki', + 'Tomassi', + 'Reidel', + 'Ciprian', + 'Penza', + 'Vite', + 'Cormany', + 'Derousse', + 'Beus', + 'Shurley', + 'Courtwright', + 'Donna', + 'Karney', + 'Keats', + 'Harron', + 'Stjacques', + 'Regester', + 'Stoke', + 'Garron', + 'Sulaiman', + 'Fusilier', + 'Hence', + 'Altidor', + 'Rollerson', + 'Anfinson', + 'Badua', + 'Balmaceda', + 'Bringman', + 'Bystrom', + 'Goffinet', + 'Guindon', + 'Hilling', + 'Makepeace', + 'Mooradian', + 'Muzquiz', + 'Newcom', + 'Perrella', + 'Postlewait', + 'Raetz', + 'Riveros', + 'Saephanh', + 'Scharer', + 'Sheeder', + 'Sitar', + 'Umlauf', + 'Voegeli', + 'Yurkovich', + 'Chaudhari', + 'Chianese', + 'Clonch', + 'Gasparini', + 'Giambalvo', + 'Gindlesperger', + 'Rauen', + 'Riegert', + 'Collingsworth', + 'Stief', + 'Zeisler', + 'Kirsten', + 'Vessey', + 'Scherman', + 'Ledwith', + 'Goudie', + 'Ayre', + 'Salome', + 'Knoles', + 'Munyan', + 'Corbet', + 'Hagewood', + 'Humphry', + 'Bernardez', + 'Drummonds', + 'Lide', + 'Veals', + 'Andolina', + 'Anzaldo', + 'Aufiero', + 'Bakshi', + 'Berdan', + 'Birrell', + 'Colcord', + 'Dutro', + 'Eisenhour', + 'Falgoust', + 'Foertsch', + 'Forlenza', + 'Harroun', + 'Kurtenbach', + 'Livesey', + 'Luka', + 'Manseau', + 'Mcdaid', + 'Miska', + 'Overley', + 'Panzica', + 'Reish', + 'Riolo', + 'Roseland', + 'Shenberger', + 'Splinter', + 'Strupp', + 'Sturgell', + 'Swatzell', + 'Totherow', + 'Villarroel', + 'Wenig', + 'Zimny', + 'Brunetto', + 'Hiester', + 'Kasinger', + 'Laverde', + 'Mihalek', + 'Aquila', + 'Moreton', + 'Collums', + 'Ergle', + 'Keziah', + 'Bourbon', + 'Scaff', + 'Leamy', + 'Sublette', + 'Winkley', + 'Arlington', + 'Cuffe', + 'Guity', + 'Mcmickle', + 'Summerour', + 'Baggerly', + 'Biltz', + 'Calma', + 'Dephillips', + 'Graffam', + 'Holsopple', + 'Izumi', + 'Joerger', + 'Kesselman', + 'Kingdon', + 'Kinkel', + 'Knezevich', + 'Liebler', + 'Maceda', + 'Qualey', + 'Robeck', + 'Sciarrino', + 'Sooy', + 'Stahly', + 'Stieglitz', + 'Strike', + 'Unwin', + 'Urizar', + 'Volmer', + 'Winterstein', + 'Aronov', + 'Czyz', + 'Marrazzo', + 'Seagren', + 'Wiegmann', + 'Yearsley', + 'Brommer', + 'Sterne', + 'Armel', + 'Kryger', + 'Barten', + 'Bodwell', + 'Hollett', + 'Sharron', + 'Scobey', + 'Croson', + 'Gainor', + 'Axel', + 'Basore', + 'Bengel', + 'Chiem', + 'Desanctis', + 'Gillooly', + 'Groulx', + 'Hulings', + 'Koenigsberg', + 'Kuchinski', + 'Pagaduan', + 'Pataky', + 'Rietz', + 'Robello', + 'Schuchman', + 'Shek', + 'Brattain', + 'Gottwald', + 'Klapperich', + 'Kosky', + 'Ruegg', + 'Smid', + 'Taillon', + 'Klonowski', + 'Attar', + 'Mansoor', + 'Daus', + 'Falla', + 'Guyot', + 'Hasten', + 'Mcdowall', + 'Tugwell', + 'Remo', + 'Dishmon', + 'Leggette', + 'Sudler', + 'Prescod', + 'Benvenuti', + 'Bittenbender', + 'Burkland', + 'Crehan', + 'Donjuan', + 'Ewbank', + 'Fluegel', + 'Freiman', + 'Fuelling', + 'Grabner', + 'Gras', + 'Horr', + 'Jurich', + 'Kentner', + 'Laski', + 'Minero', + 'Olivos', + 'Porro', + 'Purves', + 'Smethers', + 'Spallone', + 'Stangler', + 'Gebbia', + 'Fowers', + 'Gaster', + 'Fero', + 'Gamon', + 'Wiss', + 'Strassner', + 'Cott', + 'Houp', + 'Fidel', + 'Parisien', + 'Daisy', + 'Calais', + 'Boers', + 'Bolle', + 'Caccavale', + 'Colantonio', + 'Columbo', + 'Goswami', + 'Hakanson', + 'Jelley', + 'Kahlon', + 'Lopezgarcia', + 'Marier', + 'Mesko', + 'Monter', + 'Mowell', + 'Piech', + 'Shortell', + 'Slechta', + 'Starman', + 'Tiemeyer', + 'Troutner', + 'Vandeveer', + 'Voorheis', + 'Woodhams', + 'Helget', + 'Kalk', + 'Kiester', + 'Lagace', + 'Obst', + 'Parrack', + 'Rennert', + 'Rodeheaver', + 'Schuermann', + 'Warmuth', + 'Wisnieski', + 'Yahnke', + 'Yurek', + 'Faver', + 'Belleau', + 'Moan', + 'Remsen', + 'Bonano', + 'Genson', + 'Genis', + 'Risen', + 'Franze', + 'Lauderback', + 'Ferns', + 'Cooler', + 'Mcwilliam', + 'Micheals', + 'Gotch', + 'Teat', + 'Bacus', + 'Banik', + 'Bernhart', + 'Doell', + 'Francese', + 'Gasbarro', + 'Gietzen', + 'Gossen', + 'Haberle', + 'Havlicek', + 'Henion', + 'Kevorkian', + 'Liem', + 'Loor', + 'Moede', + 'Mostafa', + 'Mottern', + 'Naito', + 'Nofsinger', + 'Omelia', + 'Pirog', + 'Pirone', + 'Plucinski', + 'Raghavan', + 'Robaina', + 'Seliga', + 'Stade', + 'Steinhilber', + 'Wedin', + 'Wieman', + 'Zemaitis', + 'Creps', + 'Gumina', + 'Inglett', + 'Jhaveri', + 'Kolasinski', + 'Salvesen', + 'Vallely', + 'Weseman', + 'Zysk', + 'Gourlay', + 'Zanger', + 'Delorey', + 'Sneider', + 'Tacey', + 'Valls', + 'Ossman', + 'Watton', + 'Breau', + 'Burell', + 'Villard', + 'Janice', + 'Honor', + 'Arterberry', + 'Sow', + 'Cucchiara', + 'Diemert', + 'Fluty', + 'Guadiana', + 'Ionescu', + 'Kearley', + 'Krzyzanowski', + 'Lavecchia', + 'Lundmark', + 'Melichar', + 'Mulkern', + 'Odonohue', + 'Payment', + 'Pinnow', + 'Popoff', + 'Prus', + 'Reinoehl', + 'Scarlata', + 'Schamp', + 'Schowalter', + 'Scinto', + 'Semmler', + 'Sheline', + 'Sigg', + 'Trauger', + 'Bleiler', + 'Carrino', + 'Hauth', + 'Kunsman', + 'Reicks', + 'Rotenberg', + 'Soltesz', + 'Wascher', + 'Mattina', + 'Tamblyn', + 'Bellanca', + 'Heward', + 'Seif', + 'Agha', + 'Gosling', + 'Defreese', + 'Lyvers', + 'Robley', + 'Hadi', + 'Ledyard', + 'Mitchner', + 'Berrien', + 'Clinkscale', + 'Affeldt', + 'Aung', + 'Azpeitia', + 'Boehnlein', + 'Cavan', + 'Ekdahl', + 'Ellyson', + 'Fahl', + 'Herrig', + 'Hulick', + 'Ihrke', + 'Kaeding', + 'Keagy', + 'Mehlman', + 'Minniear', + 'Paniccia', + 'Pleva', + 'Prestidge', + 'Pulford', + 'Quattrone', + 'Riquelme', + 'Rombach', + 'Sarwar', + 'Sivertsen', + 'Sprang', + 'Wardrop', + 'Anglemyer', + 'Bobek', + 'Scronce', + 'Snethen', + 'Stancliff', + 'Booton', + 'Pinal', + 'Weihe', + 'Bria', + 'Lopresto', + 'Awbrey', + 'Fogal', + 'Ning', + 'Hydrick', + 'Lumb', + 'Pommier', + 'Hendy', + 'Armon', + 'Spenser', + 'Beachem', + 'Decrescenzo', + 'Heaphy', + 'Kalata', + 'Kastl', + 'Kosel', + 'Kunert', + 'Laatsch', + 'Lanpher', + 'Malinski', + 'Mazzie', + 'Neuendorf', + 'Salloum', + 'Tays', + 'Yackel', + 'Calvario', + 'Feese', + 'Feldner', + 'Kness', + 'Kozuch', + 'Magat', + 'Pantalone', + 'Rilling', + 'Teska', + 'Fantauzzi', + 'Wartman', + 'Stansbery', + 'Sox', + 'Napp', + 'Schauf', + 'Cumings', + 'Coxon', + 'Labor', + 'Brash', + 'Egleston', + 'Quintin', + 'Oki', + 'Date', + 'Tuckett', + 'Devaux', + 'Hewins', + 'Abdelrahman', + 'Schumpert', + 'Dort', + 'Limbrick', + 'Linwood', + 'Delaine', + 'Liverpool', + 'Azimi', + 'Biever', + 'Craigo', + 'Eschete', + 'Fortini', + 'Francom', + 'Giacomini', + 'Girdler', + 'Halasz', + 'Hillin', + 'Inglese', + 'Isaza', + 'Lewman', + 'Ploetz', + 'Rampley', + 'Reifsteck', + 'Rossano', + 'Sanagustin', + 'Sotak', + 'Spainhower', + 'Stecklein', + 'Stolberg', + 'Teschner', + 'Thew', + 'Blaszczyk', + 'Caradonna', + 'Cillo', + 'Diluzio', + 'Hagemeyer', + 'Holstrom', + 'Jewkes', + 'Mcquaide', + 'Osterhaus', + 'Twaddle', + 'Wenck', + 'Yakel', + 'Zeiner', + 'Zulauf', + 'Mirabelli', + 'Gerold', + 'Sherr', + 'Ogando', + 'Achilles', + 'Woodlee', + 'Underdown', + 'Peirson', + 'Abdelaziz', + 'Bently', + 'Junes', + 'Furtick', + 'Muckle', + 'Freemon', + 'Jamar', + 'Scriber', + 'Michaux', + 'Cheatum', + 'Hollings', + 'Telfair', + 'Amadeo', + 'Bargar', + 'Berchtold', + 'Boomhower', + 'Camba', + 'Compo', + 'Dellavecchia', + 'Doring', + 'Doyel', + 'Geck', + 'Giovannini', + 'Herda', + 'Kopko', + 'Kuns', + 'Maciag', + 'Neenan', + 'Neglia', + 'Nienhuis', + 'Niznik', + 'Pieczynski', + 'Quintos', + 'Quirin', + 'Ravi', + 'Teaster', + 'Tipsword', + 'Troiani', + 'Consuegra', + 'Damaso', + 'Garavaglia', + 'Pischke', + 'Prowse', + 'Rumore', + 'Simcoe', + 'Slentz', + 'Sposito', + 'Sulser', + 'Weichel', + 'Sandobal', + 'Siver', + 'Vickerman', + 'Sham', + 'Gutridge', + 'Gracy', + 'Weatherington', + 'Benett', + 'Nottage', + 'Myricks', + 'Tukes', + 'Alcaide', + 'Curatolo', + 'Dalziel', + 'Fandrich', + 'Fisette', + 'Gianino', + 'Grether', + 'Hari', + 'Ichikawa', + 'Lantzy', + 'Monteforte', + 'Moskovitz', + 'Porritt', + 'Raz', + 'Rodenbeck', + 'Ryczek', + 'Strehle', + 'Vanduzer', + 'Voge', + 'Wiker', + 'Yanik', + 'Zangari', + 'Cahue', + 'Dellapenna', + 'Gohr', + 'Gurka', + 'Imburgia', + 'Langenberg', + 'Kivi', + 'Pikul', + 'Sexson', + 'Sharrer', + 'Aramburo', + 'Kadar', + 'Casasola', + 'Nina', + 'Borras', + 'Toledano', + 'Wykle', + 'Naeem', + 'Bailer', + 'Lalla', + 'Booty', + 'Turenne', + 'Merrit', + 'Duffus', + 'Hemmingway', + 'Asare', + 'Ahlborn', + 'Arroyave', + 'Brandenberger', + 'Carolus', + 'Coonan', + 'Dacunha', + 'Dost', + 'Filter', + 'Freudenberg', + 'Grabski', + 'Hengel', + 'Holohan', + 'Kohne', + 'Kollmann', + 'Levick', + 'Lupinacci', + 'Meservey', + 'Reisdorf', + 'Rodabaugh', + 'Shimon', + 'Soth', + 'Spall', + 'Tener', + 'Thier', + 'Welshans', + 'Chermak', + 'Ciolino', + 'Frantzen', + 'Grassman', + 'Okuda', + 'Passantino', + 'Schellinger', + 'Sneath', + 'Bolla', + 'Bobe', + 'Maves', + 'Matey', + 'Shafi', + 'Rothchild', + 'Ker', + 'Verrette', + 'Thorington', + 'Lathers', + 'Merriwether', + 'Bendall', + 'Bercier', + 'Botz', + 'Claybaugh', + 'Creson', + 'Dilone', + 'Gabehart', + 'Gencarelli', + 'Ghormley', + 'Hacking', + 'Haefele', + 'Haros', + 'Holderby', + 'Krotzer', + 'Nanda', + 'Oltmanns', + 'Orndoff', + 'Poniatowski', + 'Rosol', + 'Sheneman', + 'Shifrin', + 'Smay', + 'Swickard', + 'Thayne', + 'Tripathi', + 'Vonbehren', + 'Pummill', + 'Schnitker', + 'Steines', + 'Beechler', + 'Faron', + 'Villari', + 'Spickard', + 'Levings', + 'Polack', + 'Standre', + 'Castel', + 'Louise', + 'Janey', + 'Lindor', + 'Bulthuis', + 'Cantrall', + 'Cisnero', + 'Dangel', + 'Deborde', + 'Decena', + 'Grandon', + 'Gritz', + 'Heberlein', + 'Kestenbaum', + 'Kubitz', + 'Luers', + 'Naiman', + 'Ramaswamy', + 'Sek', + 'Slauson', + 'Walsworth', + 'Biehler', + 'Capano', + 'Casstevens', + 'Forgette', + 'Furnas', + 'Gilkison', + 'Janoski', + 'Jerde', + 'Mcclimans', + 'Rohlf', + 'Vliet', + 'Heeney', + 'Zapanta', + 'Lighthall', + 'Shallow', + 'Neils', + 'Raikes', + 'Clarkston', + 'Claud', + 'Guilbeaux', + 'Pennie', + 'Arizola', + 'Aud', + 'Checketts', + 'Corvera', + 'Easterbrook', + 'Gamm', + 'Grassel', + 'Guarin', + 'Hanf', + 'Hitsman', + 'Lackman', + 'Lubitz', + 'Lupian', + 'Olexa', + 'Omori', + 'Oscarson', + 'Picasso', + 'Plewa', + 'Schmahl', + 'Stolze', + 'Todisco', + 'Zarzycki', + 'Baluyot', + 'Cerrito', + 'Elenbaas', + 'Gavidia', + 'Heisner', + 'Karpowicz', + 'Neidhardt', + 'Silkwood', + 'Taras', + 'Dobias', + 'Widen', + 'Blandino', + 'Fanguy', + 'Probus', + 'Guilbert', + 'Shadowens', + 'Keepers', + 'Bruin', + 'Hitson', + 'Crymes', + 'Roston', + 'Beaubrun', + 'Arrambide', + 'Betti', + 'Brockhaus', + 'Bumanglag', + 'Cabreja', + 'Dicenso', + 'Hartlaub', + 'Hertlein', + 'Lapenna', + 'Rathje', + 'Rotert', + 'Salzberg', + 'Siniard', + 'Tomsic', + 'Wondra', + 'Zenger', + 'Norrod', + 'Opalka', + 'Osment', + 'Zhan', + 'Lemcke', + 'Meranda', + 'Joles', + 'Labay', + 'Monserrate', + 'Grime', + 'Martha', + 'Coltrain', + 'Vardaman', + 'Wragg', + 'Frater', + 'Offer', + 'Elcock', + 'Auble', + 'Bistline', + 'Chorney', + 'Colgate', + 'Dadamo', + 'Deol', + 'Discher', + 'Ertz', + 'Fletchall', + 'Galletti', + 'Geffre', + 'Grall', + 'Hoos', + 'Iezzi', + 'Kawecki', + 'Madamba', + 'Margolies', + 'Mccreedy', + 'Okimoto', + 'Oum', + 'Pangan', + 'Pasternack', + 'Plazola', + 'Prochazka', + 'Tewes', + 'Tramontana', + 'Yauch', + 'Zarling', + 'Zemanek', + 'Altshuler', + 'Bartkowski', + 'Cuoco', + 'Garcialopez', + 'Kauzlarich', + 'Shishido', + 'Zaun', + 'Hallin', + 'Starliper', + 'Belflower', + 'Kneece', + 'Genet', + 'Palmero', + 'Willmott', + 'Riek', + 'Belger', + 'Abbitt', + 'Statum', + 'Jacque', + 'Chisley', + 'Habersham', + 'Berardinelli', + 'Bodle', + 'Deshaw', + 'Ingalsbe', + 'Kirchgessner', + 'Kuna', + 'Pellow', + 'Pickler', + 'Pistole', + 'Rosenstock', + 'Salceda', + 'Sawatzky', + 'Schappell', + 'Scholer', + 'Shellabarger', + 'Spader', + 'Swadley', + 'Travelstead', + 'Varin', + 'Villwock', + 'Wiemers', + 'Bedoy', + 'Borowiak', + 'Celio', + 'Dornfeld', + 'Juhnke', + 'Livernois', + 'Sakaguchi', + 'Sandall', + 'Sivertson', + 'Whitcraft', + 'Anda', + 'Aprile', + 'Kritz', + 'Speier', + 'Karman', + 'Kise', + 'Madia', + 'Bodo', + 'Madole', + 'Harl', + 'Gach', + 'Stalls', + 'Holme', + 'Lomba', + 'Tutton', + 'Windon', + 'Bines', + 'Benoist', + 'Cirrincione', + 'Coday', + 'Delrosso', + 'Dlouhy', + 'Domenick', + 'Edelmann', + 'Goos', + 'Hamling', + 'Huda', + 'Hutzel', + 'Lanasa', + 'Loudenslager', + 'Lueras', + 'Magnussen', + 'Mcferran', + 'Nowinski', + 'Pikula', + 'Precht', + 'Quilici', + 'Robling', + 'Rusche', + 'Schettino', + 'Scibelli', + 'Soderman', + 'Spirito', + 'Teaford', + 'Updegrove', + 'Weygandt', + 'Zervos', + 'Brunker', + 'Demuro', + 'Eckenrod', + 'Emley', + 'Franek', + 'Frankenberger', + 'Longbrake', + 'Magallanez', + 'Stofko', + 'Zenz', + 'Galik', + 'Crevier', + 'Fina', + 'Harari', + 'Dudney', + 'Inga', + 'Sowles', + 'Folker', + 'Cressy', + 'Eckerson', + 'Gerringer', + 'Capito', + 'Huxtable', + 'Arcement', + 'Lansdown', + 'Amara', + 'Brazill', + 'Flye', + 'Currington', + 'Buffin', + 'Desta', + 'Cheuvront', + 'Fuoco', + 'Gerbino', + 'Hilyer', + 'Hogsed', + 'Kubis', + 'Lautner', + 'Loeber', + 'Meyn', + 'Mortell', + 'Nunziato', + 'Opdahl', + 'Panebianco', + 'Reffner', + 'Repsher', + 'Riccobono', + 'Wik', + 'Circle', + 'Hovde', + 'Keaveney', + 'Landsberg', + 'Pesavento', + 'Bedel', + 'Glas', + 'Thurn', + 'Jaffer', + 'Dantin', + 'Risi', + 'Many', + 'Egler', + 'Craghead', + 'Ann', + 'Turnbo', + 'Crumby', + 'Faciane', + 'Brummell', + 'Bujak', + 'Chaddock', + 'Cullop', + 'Eberling', + 'Ennen', + 'Frum', + 'Gassert', + 'Grothaus', + 'Hucke', + 'Lanphere', + 'Lozon', + 'Macadam', + 'Mezo', + 'Peretti', + 'Perlin', + 'Prestwich', + 'Redmann', + 'Ringley', + 'Rivenburg', + 'Sandow', + 'Spreitzer', + 'Stachnik', + 'Szczesniak', + 'Tworek', + 'Wogan', + 'Zygmunt', + 'Austad', + 'Chiappone', + 'Gelineau', + 'Lannom', + 'Livezey', + 'Monrroy', + 'Norem', + 'Oetting', + 'Ostberg', + 'Takeshita', + 'Gorsky', + 'Allcorn', + 'Pemble', + 'Josselyn', + 'Lanzo', + 'Hoare', + 'Ticer', + 'Netterville', + 'Lawes', + 'Lenton', + 'Garraway', + 'Cyprian', + 'Alferez', + 'Allocco', + 'Aslanian', + 'Brenna', + 'Carachure', + 'Devoss', + 'Dubas', + 'Garrabrant', + 'Gerloff', + 'Gerritsen', + 'Hobaugh', + 'Jasek', + 'Kulis', + 'Lenehan', + 'Lodes', + 'Mandich', + 'Manter', + 'Mcfatridge', + 'Mikolajczak', + 'Netz', + 'Perrelli', + 'Ribar', + 'Sekerak', + 'Shingledecker', + 'Talamante', + 'Taverna', + 'Thoresen', + 'Throneberry', + 'Vanacore', + 'Vieau', + 'Wermuth', + 'Zeidan', + 'Counihan', + 'Dircks', + 'Markovitz', + 'Panas', + 'Steffel', + 'Bergstedt', + 'Mohar', + 'Sonne', + 'Mitsch', + 'Aceituno', + 'Loker', + 'Treen', + 'Prunier', + 'Amberson', + 'Allington', + 'Artley', + 'Caffery', + 'Rhoney', + 'Nimmer', + 'Ledwell', + 'Barkus', + 'Fralin', + 'Locks', + 'Azzara', + 'Bartosik', + 'Bertelson', + 'Birman', + 'Brogna', + 'Cachola', + 'Dennington', + 'Enea', + 'Gallogly', + 'Grafe', + 'Jankowiak', + 'Kaas', + 'Karis', + 'Kostick', + 'Lentsch', + 'Locken', + 'Mathys', + 'Maxcy', + 'Monegro', + 'Olano', + 'Paske', + 'Raible', + 'Rowbotham', + 'Vanderbeck', + 'Vanosdol', + 'Wenzler', + 'Yglesias', + 'Eisenberger', + 'Grzelak', + 'Hamidi', + 'Hottel', + 'Markoff', + 'Santagata', + 'Seefeld', + 'Stachowicz', + 'Stiehl', + 'Staver', + 'Raad', + 'Sarber', + 'Rudge', + 'Connelley', + 'Danser', + 'Chumney', + 'Hind', + 'Desper', + 'Fergusson', + 'Ringwood', + 'Byles', + 'Alyea', + 'Benzinger', + 'Betzer', + 'Brix', + 'Chiarella', + 'Chiriboga', + 'Cicala', + 'Cohick', + 'Creeden', + 'Delligatti', + 'Garbacz', + 'Grossberg', + 'Habecker', + 'Inscoe', + 'Irias', + 'Karlsen', + 'Kilts', + 'Koetter', + 'Laflin', + 'Laperle', + 'Mizner', + 'Navia', + 'Nolet', + 'Procaccini', + 'Pula', + 'Scarfo', + 'Schmelz', + 'Taaffe', + 'Troth', + 'Vanlaningham', + 'Vosberg', + 'Whitchurch', + 'Benak', + 'Hanawalt', + 'Lindman', + 'Moschetti', + 'Rozas', + 'Sporleder', + 'Stopka', + 'Turowski', + 'Wahlgren', + 'Youngstrom', + 'Jabbour', + 'Myerson', + 'Perlow', + 'Cannone', + 'Kil', + 'Stiverson', + 'Cedar', + 'Sweeden', + 'Pourciau', + 'Salina', + 'Delmoral', + 'Balle', + 'Cohea', + 'Bute', + 'Rayne', + 'Cawthorn', + 'Conely', + 'Cartlidge', + 'Powel', + 'Nwankwo', + 'Centrella', + 'Delaura', + 'Deprey', + 'Dulude', + 'Garrod', + 'Gassen', + 'Greenberger', + 'Huneke', + 'Kunzman', + 'Laakso', + 'Oppermann', + 'Radich', + 'Rozen', + 'Schoffstall', + 'Swetnam', + 'Vitrano', + 'Wolber', + 'Amirault', + 'Przybysz', + 'Trzeciak', + 'Fontan', + 'Mathie', + 'Roswell', + 'Mcquitty', + 'Kye', + 'Lucious', + 'Chilcutt', + 'Difazio', + 'Diperna', + 'Gashi', + 'Goodstein', + 'Gruetzmacher', + 'Imus', + 'Krumholz', + 'Lanzetta', + 'Leaming', + 'Lehigh', + 'Lobosco', + 'Pardoe', + 'Pellicano', + 'Purtee', + 'Ramanathan', + 'Roszkowski', + 'Satre', + 'Steinborn', + 'Stinebaugh', + 'Thiesen', + 'Tierno', + 'Wrisley', + 'Yazdani', + 'Zwilling', + 'Berntson', + 'Gisclair', + 'Golliher', + 'Neumeier', + 'Stohl', + 'Swartley', + 'Wannemacher', + 'Wickard', + 'Duford', + 'Rosello', + 'Merfeld', + 'Arko', + 'Cotney', + 'Hai', + 'Milley', + 'Figueira', + 'Willes', + 'Helmes', + 'Abair', + 'Life', + 'Izard', + 'Duskin', + 'Moland', + 'Primer', + 'Hagos', + 'Anyanwu', + 'Balasubramanian', + 'Bluth', + 'Calk', + 'Chrzan', + 'Constanza', + 'Durney', + 'Ekholm', + 'Erny', + 'Ferrando', + 'Froberg', + 'Gonyer', + 'Guagliardo', + 'Hreha', + 'Kobza', + 'Kuruvilla', + 'Preziosi', + 'Ricciuti', + 'Rosiles', + 'Schiesser', + 'Schmoyer', + 'Slota', + 'Szeliga', + 'Verba', + 'Widjaja', + 'Wrzesinski', + 'Zufall', + 'Bumstead', + 'Dohrman', + 'Dommer', + 'Eisenmenger', + 'Glogowski', + 'Kaufhold', + 'Kuiken', + 'Ricklefs', + 'Sinyard', + 'Steenbergen', + 'Schweppe', + 'Chatwin', + 'Dingee', + 'Mittleman', + 'Menear', + 'Milot', + 'Riccardo', + 'Clemenson', + 'Mellow', + 'Gabe', + 'Rolla', + 'Vander', + 'Casselberry', + 'Hubbart', + 'Colvert', + 'Billingsly', + 'Burgman', + 'Cattaneo', + 'Duthie', + 'Hedtke', + 'Heidler', + 'Hertenstein', + 'Hudler', + 'Hustead', + 'Ibsen', + 'Krutsinger', + 'Mauceri', + 'Mersereau', + 'Morad', + 'Rentfro', + 'Rumrill', + 'Shedlock', + 'Sindt', + 'Soulier', + 'Squitieri', + 'Trageser', + 'Vatter', + 'Vollman', + 'Wagster', + 'Caselli', + 'Dibacco', + 'Gick', + 'Kachel', + 'Lukaszewski', + 'Minniti', + 'Neeld', + 'Zarrella', + 'Hedglin', + 'Jahan', + 'Nathe', + 'Starn', + 'Kana', + 'Bernet', + 'Rossa', + 'Barro', + 'Smylie', + 'Bowlds', + 'Mccalley', + 'Oniel', + 'Thaggard', + 'Cayson', + 'Sinegal', + 'Bergfeld', + 'Bickmore', + 'Boch', + 'Bushway', + 'Carneiro', + 'Cerio', + 'Colbath', + 'Eade', + 'Eavenson', + 'Epping', + 'Fredricksen', + 'Gramer', + 'Hassman', + 'Hinderer', + 'Kantrowitz', + 'Kaplowitz', + 'Kelner', + 'Lecates', + 'Lothrop', + 'Lupica', + 'Masterman', + 'Meeler', + 'Neumiller', + 'Newbauer', + 'Noyce', + 'Nulty', + 'Shanker', + 'Taheri', + 'Timblin', + 'Vitucci', + 'Zappone', + 'Femia', + 'Hejl', + 'Helmbrecht', + 'Kiesow', + 'Maschino', + 'Brougher', + 'Koff', + 'Reffett', + 'Langhoff', + 'Milman', + 'Sidener', + 'Levie', + 'Chaudry', + 'Rattan', + 'Finkler', + 'Bollen', + 'Booz', + 'Shipps', + 'Theall', + 'Scallion', + 'Furlough', + 'Landfair', + 'Albuquerque', + 'Beckstrand', + 'Colglazier', + 'Darcey', + 'Fahr', + 'Gabert', + 'Gertner', + 'Gettler', + 'Giovannetti', + 'Hulvey', + 'Juenger', + 'Kantola', + 'Kemmerling', + 'Leclere', + 'Liberati', + 'Lopezlopez', + 'Minerva', + 'Redlich', + 'Shoun', + 'Sickinger', + 'Vivier', + 'Yerdon', + 'Ziomek', + 'Dechert', + 'Delbene', + 'Galassi', + 'Rawdon', + 'Wesenberg', + 'Laurino', + 'Grosjean', + 'Levay', + 'Zike', + 'Stukey', + 'Loft', + 'Kool', + 'Hatchel', + 'Mainville', + 'Salis', + 'Greenslade', + 'Mantey', + 'Spratlin', + 'Fayette', + 'Marner', + 'Rolan', + 'Pain', + 'Colquhoun', + 'Brave', + 'Locust', + 'Sconiers', + 'Bahler', + 'Barrero', + 'Bartha', + 'Basnett', + 'Berghoff', + 'Bomgardner', + 'Brindisi', + 'Campoli', + 'Carawan', + 'Chhim', + 'Corro', + 'Crissey', + 'Deterding', + 'Dileonardo', + 'Dowis', + 'Hagemeier', + 'Heichel', + 'Kipfer', + 'Lemberger', + 'Maestri', + 'Mauri', + 'Nakatani', + 'Notestine', + 'Polakowski', + 'Schlobohm', + 'Segel', + 'Socci', + 'Stieg', + 'Thorstad', + 'Trausch', + 'Whitledge', + 'Wilkowski', + 'Barkdull', + 'Dubeau', + 'Ellingsen', + 'Hayduk', + 'Lauter', + 'Lizak', + 'Machamer', + 'Makarewicz', + 'Shuffield', + 'Heiserman', + 'Sandeen', + 'Plough', + 'Stemler', + 'Bossler', + 'Catalina', + 'Betley', + 'Bonello', + 'Pryde', + 'Nickey', + 'Schanck', + 'Single', + 'Mulberry', + 'Point', + 'Danson', + 'Flemmings', + 'Behnken', + 'Catone', + 'Cummiskey', + 'Currens', + 'Gersch', + 'Kitamura', + 'Meddaugh', + 'Montagne', + 'Nouri', + 'Olejnik', + 'Pintar', + 'Placke', + 'Quinter', + 'Rakers', + 'Stuteville', + 'Sullo', + 'Voelz', + 'Barabas', + 'Estock', + 'Hultberg', + 'Savitz', + 'Treml', + 'Vigneault', + 'Jezierski', + 'Zayed', + 'Dewell', + 'Yanko', + 'Moulin', + 'Whalin', + 'Elsworth', + 'Summit', + 'Esty', + 'Mahadeo', + 'Shular', + 'Amedee', + 'Bellerose', + 'Bendixen', + 'Briski', + 'Buysse', + 'Desa', + 'Dobry', + 'Dufner', + 'Fetterly', + 'Finau', + 'Gaudioso', + 'Giangrande', + 'Heuring', + 'Kitchel', + 'Latulippe', + 'Pombo', + 'Vancott', + 'Woofter', + 'Bojarski', + 'Cretella', + 'Heumann', + 'Limpert', + 'Mcneff', + 'Pluff', + 'Tumlinson', + 'Widick', + 'Yeargan', + 'Hanft', + 'Novinger', + 'Ruddle', + 'Wrye', + 'Felde', + 'Basic', + 'Babington', + 'Karson', + 'Forgy', + 'Rendall', + 'Icard', + 'Jann', + 'Ady', + 'Therrell', + 'Sroufe', + 'Maden', + 'Ganus', + 'Preddy', + 'Marberry', + 'Fonder', + 'Latty', + 'Leatherbury', + 'Mentor', + 'Brissett', + 'Mcglory', + 'Readus', + 'Akau', + 'Bellone', + 'Berendt', + 'Bok', + 'Broten', + 'Colosi', + 'Corio', + 'Gilani', + 'Huffmaster', + 'Kieler', + 'Leonor', + 'Lips', + 'Madron', + 'Missey', + 'Nabozny', + 'Panning', + 'Reinwald', + 'Ridener', + 'Silvio', + 'Soder', + 'Spieler', + 'Vaeth', + 'Vincenti', + 'Walczyk', + 'Washko', + 'Wiater', + 'Wilen', + 'Windish', + 'Consalvo', + 'Fioravanti', + 'Hinners', + 'Paduano', + 'Ranum', + 'Parlato', + 'Dweck', + 'Matern', + 'Cryder', + 'Rubert', + 'Furgason', + 'Virella', + 'Boylen', + 'Devenport', + 'Perrodin', + 'Hollingshed', + 'Pennix', + 'Bogdanski', + 'Carretero', + 'Cubillos', + 'Deponte', + 'Forrey', + 'Gatchalian', + 'Geisen', + 'Gombos', + 'Hartlage', + 'Huddy', + 'Kou', + 'Matsko', + 'Muffley', + 'Niazi', + 'Nodarse', + 'Pawelek', + 'Pyper', + 'Stahnke', + 'Udall', + 'Baldyga', + 'Chrostowski', + 'Frable', + 'Handshoe', + 'Helderman', + 'Lambing', + 'Marolf', + 'Maynez', + 'Bunde', + 'Coia', + 'Piersol', + 'Agne', + 'Manwarren', + 'Bolter', + 'Kirsh', + 'Limerick', + 'Degray', + 'Bossie', + 'Frizell', + 'Saulters', + 'Staple', + 'Raspberry', + 'Arvie', + 'Abler', + 'Caya', + 'Ceci', + 'Dado', + 'Dewoody', + 'Hartzel', + 'Haverstick', + 'Kagel', + 'Kinnan', + 'Krock', + 'Kubica', + 'Laun', + 'Leimbach', + 'Mecklenburg', + 'Messmore', + 'Milich', + 'Mor', + 'Nachreiner', + 'Novelo', + 'Poer', + 'Vaupel', + 'Wery', + 'Breisch', + 'Cashdollar', + 'Corbridge', + 'Craker', + 'Heiberger', + 'Landress', + 'Leichty', + 'Wiedmann', + 'Yankowski', + 'Rigel', + 'Eary', + 'Riggen', + 'Nazir', + 'Shambo', + 'Gingery', + 'Guyon', + 'Bogie', + 'Kar', + 'Manifold', + 'Lafavor', + 'Montas', + 'Yeadon', + 'Cutchin', + 'Burkins', + 'Achille', + 'Bulls', + 'Torry', + 'Bartkus', + 'Beshara', + 'Busalacchi', + 'Calkin', + 'Corkum', + 'Crilley', + 'Cuny', + 'Delgaudio', + 'Devenney', + 'Emanuelson', + 'Fiel', + 'Galanti', + 'Gravina', + 'Herzing', + 'Huckaba', + 'Jaquish', + 'Kellermann', + 'Ketola', + 'Klunder', + 'Kolinski', + 'Kosak', + 'Loscalzo', + 'Moehle', + 'Ressel', + 'Skora', + 'Steakley', + 'Traugott', + 'Volden', + 'Berrong', + 'Kehres', + 'Loeffelholz', + 'Mensinger', + 'Nudo', + 'Pargas', + 'Endy', + 'Corniel', + 'Azzam', + 'Soard', + 'Flud', + 'Shuffler', + 'Hiley', + 'Logwood', + 'Ducre', + 'Aikey', + 'Ardolino', + 'Bergstresser', + 'Cen', + 'Delpriore', + 'Divelbiss', + 'Fishkin', + 'Gaucin', + 'Hemmingsen', + 'Inscore', + 'Kathman', + 'Kempen', + 'Koble', + 'Maestre', + 'Mcmonigle', + 'Merendino', + 'Meske', + 'Pietrzyk', + 'Renfrew', + 'Shevchenko', + 'Wied', + 'Digeronimo', + 'Heberer', + 'Himmelberger', + 'Nordmeyer', + 'Pocius', + 'Sigurdson', + 'Simic', + 'Steury', + 'Kealey', + 'Sabat', + 'Verstraete', + 'Patchell', + 'Finigan', + 'Critz', + 'Janelle', + 'Cima', + 'Zachariah', + 'Lebon', + 'Kellough', + 'Whitehall', + 'Jaudon', + 'Civil', + 'Dokes', + 'Slappy', + 'Bernacki', + 'Castronovo', + 'Douty', + 'Formoso', + 'Handelman', + 'Hauswirth', + 'Janowicz', + 'Klostermann', + 'Lochridge', + 'Mcdiarmid', + 'Schmale', + 'Shaddox', + 'Sitzes', + 'Spaw', + 'Urbanik', + 'Voller', + 'Fujikawa', + 'Kimmet', + 'Klingel', + 'Stoffregen', + 'Thammavong', + 'Varelas', + 'Whobrey', + 'Mandella', + 'Montuori', + 'Safrit', + 'Turan', + 'Khokhar', + 'Sircy', + 'Sabio', + 'Fill', + 'Brandao', + 'Avans', + 'Mencer', + 'Sherley', + 'Mccadden', + 'Sydney', + 'Smack', + 'Lastrapes', + 'Rowser', + 'Moultry', + 'Faulcon', + 'Arnall', + 'Babiak', + 'Balsam', + 'Bezanson', + 'Bocook', + 'Bohall', + 'Celi', + 'Costillo', + 'Crom', + 'Crusan', + 'Dibari', + 'Donaho', + 'Followell', + 'Gaudino', + 'Gericke', + 'Gori', + 'Hurrell', + 'Jakubiak', + 'Kazemi', + 'Koslosky', + 'Massoud', + 'Niebla', + 'Noffke', + 'Panjwani', + 'Papandrea', + 'Patella', + 'Plambeck', + 'Plichta', + 'Prinkey', + 'Raptis', + 'Ruffini', + 'Shoen', + 'Temkin', + 'Thul', + 'Vandall', + 'Wyeth', + 'Zalenski', + 'Consoli', + 'Gumbert', + 'Milanowski', + 'Musolf', + 'Naeger', + 'Okonski', + 'Orrison', + 'Solache', + 'Verdone', + 'Woehler', + 'Yonke', + 'Risdon', + 'Orzech', + 'Bergland', + 'Collen', + 'Bloodsworth', + 'Furgeson', + 'Moch', + 'Callegari', + 'Alphonso', + 'Ozier', + 'Paulding', + 'Ringold', + 'Yarde', + 'Abbett', + 'Axford', + 'Capwell', + 'Datz', + 'Delillo', + 'Delisa', + 'Dicaprio', + 'Dimare', + 'Faughnan', + 'Fehrenbacher', + 'Gellert', + 'Ging', + 'Gladhill', + 'Goates', + 'Hammerstrom', + 'Hilbun', + 'Iodice', + 'Kadish', + 'Kilker', + 'Lurvey', + 'Maue', + 'Michna', + 'Parslow', + 'Pawelski', + 'Quenzer', + 'Raboin', + 'Sader', + 'Sawka', + 'Velis', + 'Wilczewski', + 'Willemsen', + 'Zebley', + 'Benscoter', + 'Denhartog', + 'Dolinsky', + 'Malacara', + 'Mccosh', + 'Modugno', + 'Tsay', + 'Vanvoorst', + 'Mincher', + 'Nickol', + 'Elster', + 'Kerce', + 'Brittan', + 'Quilter', + 'Spike', + 'Mcintee', + 'Boldon', + 'Balderama', + 'Cauffman', + 'Chovanec', + 'Difonzo', + 'Fagerstrom', + 'Galanis', + 'Jeziorski', + 'Krasowski', + 'Lansdale', + 'Laven', + 'Magallan', + 'Mahal', + 'Mehrer', + 'Naus', + 'Peltzer', + 'Petraitis', + 'Pritz', + 'Salway', + 'Savich', + 'Schmehl', + 'Teniente', + 'Tuccillo', + 'Wahlquist', + 'Wetz', + 'Brozovich', + 'Catalfamo', + 'Dioguardi', + 'Guzzetta', + 'Hanak', + 'Lipschutz', + 'Sholtis', + 'Bleecker', + 'Sattar', + 'Thivierge', + 'Camfield', + 'Heslep', + 'Tree', + 'Calvey', + 'Mcgowin', + 'Strickling', + 'Manderson', + 'Dieudonne', + 'Bonini', + 'Bruinsma', + 'Burgueno', + 'Cotugno', + 'Fukunaga', + 'Krog', + 'Lacerda', + 'Larrivee', + 'Lepera', + 'Pinilla', + 'Reichenberger', + 'Rovner', + 'Rubiano', + 'Saraiva', + 'Smolka', + 'Soboleski', + 'Tallmadge', + 'Wigand', + 'Wikle', + 'Bentsen', + 'Bierer', + 'Cohenour', + 'Dobberstein', + 'Holderbaum', + 'Polhamus', + 'Skousen', + 'Theiler', + 'Fornes', + 'Sisley', + 'Zingale', + 'Nimtz', + 'Prieur', + 'Mccaughan', + 'Fawaz', + 'Hobbins', + 'Killingbeck', + 'Roads', + 'Nicolson', + 'Mcculloh', + 'Verges', + 'Badley', + 'Shorten', + 'Litaker', + 'Laseter', + 'Stthomas', + 'Mcguffie', + 'Depass', + 'Flemons', + 'Ahola', + 'Armacost', + 'Bearse', + 'Downum', + 'Drechsel', + 'Farooqi', + 'Filosa', + 'Francesconi', + 'Kielbasa', + 'Latella', + 'Monarch', + 'Ozawa', + 'Papadakis', + 'Politano', + 'Poucher', + 'Roussin', + 'Safley', + 'Schwer', + 'Tesoro', + 'Tsan', + 'Wintersteen', + 'Zanni', + 'Barlage', + 'Brancheau', + 'Buening', + 'Dahlem', + 'Forni', + 'Gerety', + 'Gutekunst', + 'Leamer', + 'Liwanag', + 'Meech', + 'Wigal', + 'Bonta', + 'Cheetham', + 'Crespi', + 'Fahs', + 'Prow', + 'Postle', + 'Delacy', + 'Dufort', + 'Gallery', + 'Romey', + 'Aime', + 'Molock', + 'Dixion', + 'Carstarphen', + 'Appleyard', + 'Aylsworth', + 'Barberi', + 'Contini', + 'Cugini', + 'Eiben', + 'Faso', + 'Hartog', + 'Jelen', + 'Loayza', + 'Maugeri', + 'Mcgannon', + 'Osorno', + 'Paratore', + 'Sahagian', + 'Sarracino', + 'Scallon', + 'Sypniewski', + 'Teters', + 'Throgmorton', + 'Vogelpohl', + 'Walkowski', + 'Winchel', + 'Niedermeyer', + 'Jayroe', + 'Montello', + 'Neyer', + 'Milder', + 'Obar', + 'Stanis', + 'Pro', + 'Pin', + 'Fatheree', + 'Cotterell', + 'Reeds', + 'Comrie', + 'Zamor', + 'Gradney', + 'Poullard', + 'Betker', + 'Bondarenko', + 'Buchko', + 'Eischens', + 'Glavan', + 'Hannold', + 'Heafner', + 'Karaffa', + 'Krabbe', + 'Meinzer', + 'Olgin', + 'Raeder', + 'Sarff', + 'Senechal', + 'Sette', + 'Shovlin', + 'Slife', + 'Tallarico', + 'Trivino', + 'Wyszynski', + 'Audia', + 'Facemire', + 'Januszewski', + 'Klebba', + 'Kovacik', + 'Moroni', + 'Nieder', + 'Schorn', + 'Sundby', + 'Tehan', + 'Trias', + 'Kissler', + 'Margo', + 'Jefcoat', + 'Bulow', + 'Maire', + 'Vizcarrondo', + 'Ki', + 'Ayuso', + 'Mayhan', + 'Usman', + 'Blincoe', + 'Whidby', + 'Tinson', + 'Calarco', + 'Cena', + 'Ciccarello', + 'Cloe', + 'Consolo', + 'Davydov', + 'Decristofaro', + 'Delmundo', + 'Dubrow', + 'Ellinwood', + 'Gehling', + 'Halberstadt', + 'Hascall', + 'Hoeffner', + 'Huettl', + 'Iafrate', + 'Imig', + 'Khoo', + 'Krausz', + 'Kuether', + 'Kulla', + 'Marchesani', + 'Ormonde', + 'Platzer', + 'Preusser', + 'Rebel', + 'Reidhead', + 'Riehm', + 'Robertshaw', + 'Runco', + 'Sandino', + 'Spare', + 'Trefethen', + 'Tribby', + 'Yamazaki', + 'Ziesmer', + 'Calamari', + 'Deyoe', + 'Marullo', + 'Neidigh', + 'Salveson', + 'Senesac', + 'Ausburn', + 'Herner', + 'Seagrave', + 'Lormand', + 'Niblock', + 'Somes', + 'Naim', + 'Murren', + 'Callander', + 'Glassco', + 'Henri', + 'Jabbar', + 'Bordes', + 'Altemose', + 'Bagnell', + 'Belloso', + 'Beougher', + 'Birchall', + 'Cantara', + 'Demetriou', + 'Galford', + 'Hast', + 'Heiny', + 'Hieronymus', + 'Jehle', + 'Khachatryan', + 'Kristof', + 'Kubas', + 'Mano', + 'Munar', + 'Ogas', + 'Riccitelli', + 'Sidman', + 'Suchocki', + 'Tortorello', + 'Trombino', + 'Vullo', + 'Badura', + 'Clerkin', + 'Criollo', + 'Dashnaw', + 'Mednick', + 'Pickrel', + 'Mawson', + 'Hockey', + 'Alo', + 'Frankland', + 'Gaby', + 'Hoda', + 'Marchena', + 'Fawbush', + 'Cowing', + 'Aydelott', + 'Dieu', + 'Rise', + 'Morten', + 'Gunby', + 'Modeste', + 'Balcerzak', + 'Cutbirth', + 'Dejoseph', + 'Desaulniers', + 'Dimperio', + 'Dubord', + 'Gruszka', + 'Haske', + 'Hehr', + 'Kolander', + 'Kusiak', + 'Lampron', + 'Mapel', + 'Montie', + 'Mumme', + 'Naramore', + 'Raffel', + 'Ruter', + 'Sawa', + 'Sencion', + 'Somogyi', + 'Ventola', + 'Zabawa', + 'Alagna', + 'Burmaster', + 'Chirco', + 'Gjerde', + 'Hilgenberg', + 'Huntress', + 'Kochel', + 'Nist', + 'Schena', + 'Toolan', + 'Wurzer', + 'Masih', + 'Ritts', + 'Rousse', + 'Buckey', + 'Sausedo', + 'Dolle', + 'Bena', + 'Franca', + 'Commins', + 'Gago', + 'Pattie', + 'Brener', + 'Verley', + 'Griffy', + 'Heiskell', + 'Osley', + 'Babula', + 'Barbone', + 'Berzins', + 'Demirjian', + 'Dietze', + 'Haseltine', + 'Heinbaugh', + 'Henneke', + 'Korba', + 'Levitz', + 'Lorenzini', + 'Mansilla', + 'Peffley', + 'Poletti', + 'Portelli', + 'Rottinghaus', + 'Scifres', + 'Stadel', + 'Stettner', + 'Swauger', + 'Vanwart', + 'Vorhies', + 'Worst', + 'Yadav', + 'Yebra', + 'Kreiter', + 'Mroczek', + 'Pennella', + 'Stangelo', + 'Suchan', + 'Weiand', + 'Widhalm', + 'Wojcicki', + 'Gutzman', + 'Griffee', + 'Konicki', + 'Moorehouse', + 'Neighbor', + 'Butte', + 'Cooter', + 'Humpherys', + 'Morrish', + 'Stockhausen', + 'Slatter', + 'Cheely', + 'Yassin', + 'Bazil', + 'Mcsween', + 'Anastos', + 'Annunziato', + 'Bora', + 'Burkitt', + 'Cino', + 'Codding', + 'Criado', + 'Firestine', + 'Goecke', + 'Golda', + 'Holloran', + 'Homen', + 'Laubscher', + 'Memmer', + 'Navejar', + 'Peraino', + 'Petrizzo', + 'Pflieger', + 'Pint', + 'Porcello', + 'Raffety', + 'Riedesel', + 'Salado', + 'Scaletta', + 'Schuring', + 'Slaydon', + 'Solecki', + 'Spomer', + 'Waldridge', + 'Zawislak', + 'Bottone', + 'Helgesen', + 'Knippel', + 'Loutzenhiser', + 'Mallinson', + 'Malnar', + 'Pethtel', + 'Sissel', + 'Thorstenson', + 'Winokur', + 'Dittmann', + 'Fencl', + 'Kernen', + 'Gath', + 'Hiney', + 'Godman', + 'Hopton', + 'Tinley', + 'Wamble', + 'Greg', + 'Garrette', + 'Acoff', + 'Ausman', + 'Burggraf', + 'Colliver', + 'Dejulio', + 'Fedorchak', + 'Finocchio', + 'Grasse', + 'Harpold', + 'Hopman', + 'Kilzer', + 'Losasso', + 'Lovallo', + 'Neumayer', + 'Purohit', + 'Reddinger', + 'Scheper', + 'Valbuena', + 'Wenzl', + 'Eilerman', + 'Galbo', + 'Haydu', + 'Vipond', + 'Wesselman', + 'Yeagle', + 'Boutelle', + 'Odonnel', + 'Morocco', + 'Speak', + 'Ruckel', + 'Cornier', + 'Burbidge', + 'Esselman', + 'Daisey', + 'Juran', + 'Henard', + 'Trench', + 'Hurry', + 'Estis', + 'Allport', + 'Beedy', + 'Blower', + 'Bogacz', + 'Caldas', + 'Carriero', + 'Garand', + 'Gonterman', + 'Harbeck', + 'Husar', + 'Lizcano', + 'Lonardo', + 'Meneely', + 'Misiewicz', + 'Pagliuca', + 'Pember', + 'Rybacki', + 'Safar', + 'Seeberger', + 'Siharath', + 'Spoerl', + 'Tattersall', + 'Birchmeier', + 'Denunzio', + 'Dustman', + 'Franchini', + 'Gettel', + 'Goldrick', + 'Goodheart', + 'Keshishyan', + 'Mcgrogan', + 'Newingham', + 'Scheier', + 'Skorupa', + 'Utech', + 'Weidenbach', + 'Chaloupka', + 'Grater', + 'Libman', + 'Recore', + 'Savona', + 'Verbeke', + 'Lunetta', + 'Schlater', + 'Staffieri', + 'Troll', + 'Leyton', + 'Peto', + 'Trella', + 'Follin', + 'Morro', + 'Woodhall', + 'Krauser', + 'Salles', + 'Brunty', + 'Wadford', + 'Shaddock', + 'Minnie', + 'Mountcastle', + 'Butter', + 'Galentine', + 'Longsworth', + 'Edgecombe', + 'Babino', + 'Printup', + 'Humbles', + 'Vessel', + 'Relford', + 'Taite', + 'Aliberti', + 'Brostrom', + 'Budlong', + 'Bykowski', + 'Coursen', + 'Darga', + 'Doutt', + 'Gomberg', + 'Greaser', + 'Hilde', + 'Hirschy', + 'Mayorquin', + 'Mcartor', + 'Mechler', + 'Mein', + 'Montville', + 'Peskin', + 'Popiel', + 'Ricciardelli', + 'Terrana', + 'Urton', + 'Cardiff', + 'Foiles', + 'Humann', + 'Pokorney', + 'Seehafer', + 'Sporer', + 'Timme', + 'Tweten', + 'Widrick', + 'Harnack', + 'Chamlee', + 'Lafountaine', + 'Lowdermilk', + 'Akel', + 'Maulden', + 'Sloman', + 'Odonald', + 'Hitchman', + 'Pendergraph', + 'Klugh', + 'Mctier', + 'Stargell', + 'Hailu', + 'Kanu', + 'Abrahamian', + 'Ackerly', + 'Belongia', + 'Cudmore', + 'Jaskolski', + 'Kedzierski', + 'Licciardi', + 'Lowenberg', + 'Meitzler', + 'Metzer', + 'Mitcheltree', + 'Nishioka', + 'Pascuzzi', + 'Pelphrey', + 'Ramones', + 'Schuchard', + 'Smithee', + 'Bignell', + 'Blaszak', + 'Borello', + 'Fiacco', + 'Garrelts', + 'Guzowski', + 'Rychlik', + 'Siebers', + 'Speziale', + 'Zauner', + 'Corell', + 'Welt', + 'Koby', + 'Auletta', + 'Bursch', + 'Luckman', + 'Vanhoesen', + 'Russian', + 'Statton', + 'Yahya', + 'Boxx', + 'Haltiwanger', + 'Redhead', + 'Mcgregory', + 'Baccari', + 'Berrey', + 'Bogden', + 'Braniff', + 'Cafarelli', + 'Clavette', + 'Corallo', + 'Dealy', + 'Gilger', + 'Gitter', + 'Goldwasser', + 'Hillesheim', + 'Hulsizer', + 'Jankovic', + 'Limburg', + 'Lopera', + 'Mcaleese', + 'Mcclintick', + 'Montealegre', + 'Mosko', + 'Nogle', + 'Ordones', + 'Papesh', + 'Peragine', + 'Picco', + 'Podraza', + 'Ras', + 'Rezek', + 'Rork', + 'Schraufnagel', + 'Scipione', + 'Terlizzi', + 'Vanblarcom', + 'Yoshino', + 'Beaverson', + 'Behunin', + 'Isch', + 'Janiga', + 'Koeppe', + 'Laurich', + 'Vondrak', + 'Walkley', + 'Hottenstein', + 'Garms', + 'Macknight', + 'Seagroves', + 'Shehata', + 'Arons', + 'Liley', + 'Pressly', + 'Cowper', + 'Branon', + 'Abdella', + 'Milord', + 'Appenzeller', + 'Ardila', + 'Belgard', + 'Boop', + 'Burbano', + 'Capitano', + 'Carrig', + 'Conrey', + 'Donica', + 'Fineberg', + 'Gemberling', + 'Harrier', + 'Hufnagle', + 'Kitner', + 'Lessing', + 'Manoukian', + 'Menk', + 'Repetto', + 'Rhinesmith', + 'Stechschulte', + 'Yep', + 'Zuhlke', + 'Abundiz', + 'Buccellato', + 'Closser', + 'Gielow', + 'Nurmi', + 'Pelka', + 'Piscitello', + 'Shoaff', + 'Champlain', + 'Conran', + 'Leidig', + 'Carel', + 'Zahid', + 'Dimitri', + 'Sapia', + 'Labauve', + 'Khalifa', + 'Gonsoulin', + 'Parrot', + 'Propps', + 'Dunnaway', + 'Cayo', + 'Mccleod', + 'Bonifas', + 'Dirkes', + 'Farruggia', + 'Gut', + 'Heacox', + 'Herrejon', + 'Ipina', + 'Keatley', + 'Kowitz', + 'Kratky', + 'Langseth', + 'Nidiffer', + 'Plimpton', + 'Riesenberg', + 'Sulewski', + 'Tabar', + 'Takara', + 'Tomassetti', + 'Tweet', + 'Weltz', + 'Youtsey', + 'Franckowiak', + 'Geffert', + 'Glawe', + 'Hillestad', + 'Ladewig', + 'Luckow', + 'Radebaugh', + 'Ransbottom', + 'Stordahl', + 'Weimar', + 'Wiegers', + 'Jowett', + 'Tomb', + 'Waitt', + 'Beaudreau', + 'Notter', + 'Rijo', + 'Denike', + 'Mam', + 'Vent', + 'Gamage', + 'Carre', + 'Childrey', + 'Heaven', + 'Forge', + 'Beckom', + 'Collick', + 'Bovell', + 'Hardimon', + 'Shells', + 'Bolf', + 'Canete', + 'Cozby', + 'Dunlavey', + 'Febo', + 'Lamke', + 'Lant', + 'Larned', + 'Leiss', + 'Lofthouse', + 'Marohn', + 'Stradling', + 'Subramaniam', + 'Vitug', + 'Ziccardi', + 'Akamine', + 'Bellissimo', + 'Bottini', + 'Braund', + 'Cavasos', + 'Heltsley', + 'Landstrom', + 'Lisiecki', + 'Navejas', + 'Sobczyk', + 'Trela', + 'Yablonski', + 'Yocham', + 'Fier', + 'Laiche', + 'Zenor', + 'Grew', + 'Naval', + 'Garratt', + 'Sako', + 'Zollicoffer', + 'Momon', + 'Bensman', + 'Cirincione', + 'Dimitrov', + 'Domeier', + 'Gaska', + 'Gensel', + 'Gernert', + 'Groot', + 'Guarisco', + 'Llorente', + 'Ludemann', + 'Moisan', + 'Muzio', + 'Neiswender', + 'Ottaway', + 'Paslay', + 'Readinger', + 'Skok', + 'Spittle', + 'Sweany', + 'Tanzi', + 'Upadhyay', + 'Valone', + 'Varas', + 'Benecke', + 'Faulstich', + 'Hebda', + 'Jobst', + 'Schleis', + 'Shuart', + 'Treinen', + 'Fok', + 'Dentler', + 'Ginty', + 'Ronda', + 'Tess', + 'Scantlin', + 'Kham', + 'Murin', + 'Faubert', + 'Ocarroll', + 'Maranda', + 'Gadsby', + 'Mouse', + 'Lunden', + 'Asquith', + 'Batley', + 'Bazzle', + 'Hooke', + 'Macneal', + 'Desnoyers', + 'Verdier', + 'Biglow', + 'Leverson', + 'Becherer', + 'Cecilio', + 'Correale', + 'Ehinger', + 'Erney', + 'Fassnacht', + 'Humpal', + 'Korpela', + 'Kratt', + 'Kunes', + 'Lockyer', + 'Macho', + 'Manfredo', + 'Maturino', + 'Raineri', + 'Seiger', + 'Stant', + 'Tecson', + 'Tempest', + 'Traverse', + 'Vonk', + 'Wormington', + 'Yeske', + 'Erichsen', + 'Fiorelli', + 'Fouty', + 'Hodgkiss', + 'Lindenbaum', + 'Matusik', + 'Mazzocco', + 'Oldani', + 'Ronca', + 'Amero', + 'Ormand', + 'Cagley', + 'Teutsch', + 'Likins', + 'Blurton', + 'Lapier', + 'Rensch', + 'Howitt', + 'Kady', + 'Broce', + 'Gaba', + 'Summerson', + 'Faure', + 'Densley', + 'Matkins', + 'Boleware', + 'Rahming', + 'Degrate', + 'Broaden', + 'Barbian', + 'Brancaccio', + 'Dimiceli', + 'Doukas', + 'Fredell', + 'Fritchman', + 'Gahr', + 'Geerdes', + 'Heidrick', + 'Hernon', + 'Ipsen', + 'Koci', + 'Lato', + 'Lyng', + 'Montella', + 'Petraglia', + 'Redlinger', + 'Riedlinger', + 'Rodier', + 'Shenton', + 'Smigiel', + 'Spanbauer', + 'Swetland', + 'Sypolt', + 'Taubert', + 'Wallander', + 'Willers', + 'Ziller', + 'Bielak', + 'Careaga', + 'Droddy', + 'Girardot', + 'Kanouse', + 'Perusse', + 'Schwier', + 'Velo', + 'Westrum', + 'Bouza', + 'Calverley', + 'Shupert', + 'Simi', + 'Zieger', + 'Nicole', + 'Fergeson', + 'Guerrant', + 'Tongue', + 'Amison', + 'Darius', + 'Banasiak', + 'Cocca', + 'Dannemiller', + 'Frommer', + 'Guardia', + 'Herl', + 'Lippa', + 'Nappo', + 'Olaya', + 'Ozburn', + 'Patry', + 'Pontiff', + 'Rauth', + 'Reier', + 'Rolfs', + 'Sassone', + 'Servidio', + 'Shough', + 'Tencza', + 'Ernster', + 'Helminiak', + 'Mcmanamon', + 'Ottens', + 'Vinh', + 'Bula', + 'Elza', + 'Serres', + 'Holan', + 'Wetherill', + 'Balis', + 'Schexnider', + 'Harral', + 'Dulany', + 'Webley', + 'Addleman', + 'Antonopoulos', + 'Badman', + 'Czerwonka', + 'Deweerd', + 'Donaghey', + 'Duszynski', + 'Firkus', + 'Foell', + 'Goyne', + 'Hattabaugh', + 'Herbel', + 'Liebelt', + 'Lovera', + 'Quenneville', + 'Ramic', + 'Rissmiller', + 'Schlag', + 'Selover', + 'Seyer', + 'Stangeland', + 'Stutesman', + 'Suminski', + 'Sweger', + 'Tetlow', + 'Thornbury', + 'Votava', + 'Weberg', + 'Canniff', + 'Evetts', + 'Gutterman', + 'Kasparek', + 'Krenzer', + 'Luckenbaugh', + 'Mainwaring', + 'Vanderweide', + 'Balladares', + 'Riesterer', + 'Salmen', + 'Mirando', + 'Rockman', + 'Warnes', + 'Crispell', + 'Corban', + 'Chrystal', + 'Barlowe', + 'Perot', + 'Ka', + 'Stockett', + 'Montfort', + 'Reagor', + 'Coote', + 'Christon', + 'Dor', + 'Apt', + 'Bandel', + 'Bibbee', + 'Brunkhorst', + 'Dexheimer', + 'Disharoon', + 'Engelstad', + 'Glaza', + 'Locey', + 'Loughney', + 'Minotti', + 'Posa', + 'Renzulli', + 'Schlauch', + 'Shadix', + 'Sloboda', + 'Topor', + 'Vacha', + 'Cerulli', + 'Ciaravino', + 'Cisek', + 'Congrove', + 'Domzalski', + 'Fleitas', + 'Helfand', + 'Lehnen', + 'Moleski', + 'Walski', + 'Dazey', + 'Mckellips', + 'Kanne', + 'Deguire', + 'Macmurray', + 'Marcelli', + 'Creach', + 'Antrobus', + 'Hykes', + 'Barriere', + 'Avinger', + 'Handford', + 'Beaufort', + 'Abend', + 'Bozzi', + 'Burnsworth', + 'Crosthwaite', + 'Eilert', + 'Frigon', + 'Hanbury', + 'Hoilman', + 'Isaksen', + 'Juday', + 'Legarda', + 'Mcgourty', + 'Mittler', + 'Olkowski', + 'Pau', + 'Pescador', + 'Pinkerman', + 'Renno', + 'Rescigno', + 'Salsgiver', + 'Schlanger', + 'Sobek', + 'Stasi', + 'Talaga', + 'Tish', + 'Tropea', + 'Umphress', + 'Weisheit', + 'Bartolini', + 'Dassow', + 'Ferullo', + 'Fetherolf', + 'Kimery', + 'Kurihara', + 'Schneiter', + 'Sramek', + 'Swier', + 'Weinzierl', + 'Karrer', + 'Hurta', + 'Lodico', + 'Conkright', + 'Sandvik', + 'Pash', + 'Pinell', + 'Dougal', + 'Burnet', + 'Hoe', + 'Rann', + 'Curvin', + 'Route', + 'Outler', + 'Corprew', + 'Berhe', + 'Eleby', + 'Acoba', + 'Ante', + 'Baio', + 'Befort', + 'Brueck', + 'Chevere', + 'Ciani', + 'Farnes', + 'Hamar', + 'Hirschhorn', + 'Imbrogno', + 'Kegg', + 'Leever', + 'Mesker', + 'Nodal', + 'Olveda', + 'Paletta', + 'Pilant', + 'Rissman', + 'Sebold', + 'Siebel', + 'Smejkal', + 'Stai', + 'Vanderkolk', + 'Allday', + 'Canupp', + 'Dieck', + 'Hinders', + 'Karcz', + 'Shomaker', + 'Tuinstra', + 'Urquizo', + 'Wiltgen', + 'Withem', + 'Yanda', + 'Blizard', + 'Christenbury', + 'Helser', + 'Jing', + 'Stave', + 'Waddill', + 'Mairena', + 'Rebert', + 'Gara', + 'Shipes', + 'Hartsoe', + 'Bargeron', + 'Arne', + 'Ebrahim', + 'Basha', + 'Rozar', + 'Venter', + 'Mounger', + 'Marsalis', + 'Gildon', + 'Antkowiak', + 'Brus', + 'Cicalese', + 'Einspahr', + 'Faucheux', + 'Frix', + 'Gateley', + 'Hamberger', + 'Holdorf', + 'Hollibaugh', + 'Junod', + 'Keaveny', + 'Knechtel', + 'Kuffel', + 'Mcwhirt', + 'Navis', + 'Neave', + 'Rackers', + 'Romagnoli', + 'Shawhan', + 'Valvano', + 'Vina', + 'Wielgus', + 'Wojtaszek', + 'Bartnik', + 'Fiebelkorn', + 'Gertsch', + 'Morgenthaler', + 'Nambo', + 'Nemmers', + 'Nihart', + 'Nilges', + 'Pulgarin', + 'Recktenwald', + 'Vandenbrink', + 'Wion', + 'Cundy', + 'Burby', + 'Cu', + 'Vansciver', + 'Herne', + 'Doughtie', + 'Cowdery', + 'Woodle', + 'Lafosse', + 'Hodgens', + 'Mckune', + 'Car', + 'Callens', + 'Corsey', + 'Brimage', + 'Westry', + 'Arismendez', + 'Benenati', + 'Brine', + 'Brookbank', + 'Burfield', + 'Charnock', + 'Copado', + 'Demilio', + 'Elvira', + 'Fantini', + 'Ferko', + 'Flanagin', + 'Gotto', + 'Hartsough', + 'Heckart', + 'Herskowitz', + 'Hoene', + 'Ishibashi', + 'Kysar', + 'Leaverton', + 'Longfield', + 'Mischel', + 'Musleh', + 'Neyra', + 'Obeirne', + 'Ostrum', + 'Pedretti', + 'Pilkerton', + 'Plasse', + 'Reesor', + 'Roznowski', + 'Rusinko', + 'Sickle', + 'Spiteri', + 'Stash', + 'Syracuse', + 'Trachsel', + 'Weinand', + 'Gruenberg', + 'Gutkowski', + 'Morella', + 'Morneault', + 'Slivinski', + 'Blessinger', + 'Taketa', + 'Hussaini', + 'Obeid', + 'Seebeck', + 'Spayd', + 'Keasling', + 'Famularo', + 'Carne', + 'Lacosse', + 'Morino', + 'Gutzmer', + 'Spinola', + 'Deahl', + 'Crumm', + 'Folley', + 'Lennard', + 'Rowson', + 'Pickron', + 'Union', + 'Abraha', + 'Yohannes', + 'Whidbee', + 'Mccaster', + 'Batzel', + 'Borowy', + 'Disanti', + 'Druck', + 'Elsbury', + 'Eschmann', + 'Fehn', + 'Flesner', + 'Grawe', + 'Haapala', + 'Helvie', + 'Hudy', + 'Joswick', + 'Kilcullen', + 'Mabus', + 'Marzo', + 'Obradovich', + 'Oriordan', + 'Phy', + 'Scarff', + 'Schappert', + 'Scire', + 'Vandevander', + 'Weyland', + 'Anstey', + 'Feeback', + 'Komarek', + 'Kyllo', + 'Manivong', + 'Timberman', + 'Tinkey', + 'Zempel', + 'Haselhorst', + 'Herberg', + 'Laris', + 'Morter', + 'Fredman', + 'Reny', + 'Ferrall', + 'Silverthorne', + 'Shuttlesworth', + 'Stigers', + 'Koker', + 'Mollette', + 'Mansel', + 'Chrisp', + 'Glymph', + 'Preyer', + 'Worlds', + 'Arutyunyan', + 'Carrizosa', + 'Dambrosia', + 'Dantuono', + 'Delduca', + 'Florencio', + 'Garafola', + 'Habermehl', + 'Hanaway', + 'Harmes', + 'Heinonen', + 'Hellstrom', + 'Herzer', + 'Klahr', + 'Kobler', + 'Korner', + 'Lancia', + 'Leask', + 'Ledo', + 'Manzanarez', + 'Myung', + 'Prestigiacomo', + 'Serpe', + 'Tonche', + 'Ventrella', + 'Walrod', + 'Warga', + 'Wasmer', + 'Weins', + 'Zaccaro', + 'Bartus', + 'Fiumara', + 'Incorvaia', + 'Khatun', + 'Kisamore', + 'Riesen', + 'Santry', + 'Schmierer', + 'Talamo', + 'Zaccone', + 'Liddick', + 'Mcclune', + 'Hade', + 'Calcutt', + 'Gillet', + 'Husein', + 'Be', + 'Lavell', + 'Veley', + 'Buckholtz', + 'Naves', + 'Debrosse', + 'Palms', + 'Lacewell', + 'Tates', + 'Tekle', + 'Golphin', + 'Asleson', + 'Bartlebaugh', + 'Benter', + 'Bielefeld', + 'Cappetta', + 'Hanback', + 'Heeg', + 'Helf', + 'Hibberd', + 'Holsworth', + 'Kowalchuk', + 'Kruczek', + 'Lieurance', + 'Markwood', + 'Muckey', + 'Rasey', + 'Rautio', + 'Salek', + 'Schwaller', + 'Scibilia', + 'Speltz', + 'Stopper', + 'Struckman', + 'Surowiec', + 'Texter', + 'Venturi', + 'Wolfenden', + 'Zortman', + 'Dehler', + 'Gillogly', + 'Hoelzel', + 'Iida', + 'Paparella', + 'Petrea', + 'Pflaum', + 'Spampinato', + 'Spaur', + 'Umbaugh', + 'Cerney', + 'Athens', + 'Salvas', + 'Gardinier', + 'Ammar', + 'Arns', + 'Calvi', + 'Palazzola', + 'Starlin', + 'Quave', + 'Rhame', + 'Gulliford', + 'Nettle', + 'Picken', + 'Warde', + 'Pelissier', + 'Mcteer', + 'Freeny', + 'Tappin', + 'Bromell', + 'People', + 'Carthen', + 'Battenfield', + 'Bunte', + 'Estrin', + 'Fitzner', + 'Flattery', + 'Hlavacek', + 'Holecek', + 'Jorstad', + 'Jurczak', + 'Kraszewski', + 'Lencioni', + 'Mamula', + 'Mater', + 'Petrakis', + 'Safranek', + 'Santorelli', + 'Speyer', + 'Waterworth', + 'Worner', + 'Antonellis', + 'Codispoti', + 'Docken', + 'Economos', + 'Petrilla', + 'Puccinelli', + 'Rondinelli', + 'Leibel', + 'Santoya', + 'Hader', + 'Yeakley', + 'Dowse', + 'Hattan', + 'Lia', + 'Emel', + 'Corse', + 'Danes', + 'Rambin', + 'Dura', + 'Kyne', + 'Sanderford', + 'Mincer', + 'Rawl', + 'Staves', + 'Mccleave', + 'Faniel', + 'Abeln', + 'Asta', + 'Beymer', + 'Cresap', + 'Cryderman', + 'Gutwein', + 'Kaszuba', + 'Maland', + 'Marella', + 'Mcmannis', + 'Molenaar', + 'Olivarria', + 'Panfil', + 'Pieratt', + 'Ramthun', + 'Resurreccion', + 'Rosander', + 'Rostad', + 'Sallas', + 'Santone', + 'Schey', + 'Shasteen', + 'Spalla', + 'Sui', + 'Tannous', + 'Tarman', + 'Trayer', + 'Wolman', + 'Chausse', + 'Debacker', + 'Dozal', + 'Hach', + 'Klossner', + 'Kruchten', + 'Mahowald', + 'Rosenlund', + 'Steffenhagen', + 'Vanmaanen', + 'Wildasin', + 'Winiecki', + 'Dilauro', + 'Wygal', + 'Cadmus', + 'Smallman', + 'Sear', + 'Berch', + 'Nabor', + 'Bro', + 'Storr', + 'Goynes', + 'Chestang', + 'Alvillar', + 'Arya', + 'Aton', + 'Bors', + 'Brydon', + 'Castagno', + 'Catena', + 'Catterson', + 'Chhun', + 'Delrossi', + 'Garnsey', + 'Harbeson', + 'Holum', + 'Iglesia', + 'Kleen', + 'Lavallie', + 'Lossing', + 'Miyata', + 'Myszka', + 'Peth', + 'Pyka', + 'Radler', + 'Roggenkamp', + 'Sarra', + 'Schmeltz', + 'Schreifels', + 'Schrimpf', + 'Scrogham', + 'Sieminski', + 'Singson', + 'Stichter', + 'Vajda', + 'Vilardo', + 'Ziff', + 'Cegielski', + 'Fanara', + 'Mefferd', + 'Polanski', + 'Reining', + 'Roggow', + 'Sassi', + 'Wagenknecht', + 'Roadcap', + 'Tuman', + 'Demesa', + 'Surita', + 'Armando', + 'Macks', + 'Megan', + 'Angello', + 'Bosher', + 'Neugent', + 'Croslin', + 'Bumpas', + 'Gladman', + 'Demmons', + 'Mcnairy', + 'Sermons', + 'Okonkwo', + 'Alvira', + 'Barfuss', + 'Bersch', + 'Bustin', + 'Ciriello', + 'Cords', + 'Cuddeback', + 'Debono', + 'Delosh', + 'Haeger', + 'Ida', + 'Kneer', + 'Koppen', + 'Kottwitz', + 'Laib', + 'Matsushita', + 'Mckone', + 'Meester', + 'Ohashi', + 'Pickert', + 'Risso', + 'Vannice', + 'Vargason', + 'Vorpahl', + 'Gluth', + 'Goossens', + 'Kloeppel', + 'Krolczyk', + 'Lequire', + 'Nila', + 'Savoia', + 'Wassmer', + 'Bianca', + 'Rousselle', + 'Wittler', + 'Gillean', + 'Cervi', + 'Fremin', + 'Vanzanten', + 'Varvel', + 'Sween', + 'Peron', + 'Trudo', + 'Welford', + 'Scovil', + 'Beazer', + 'Cohill', + 'Estime', + 'Alcalde', + 'Bugay', + 'Bushard', + 'Dethloff', + 'Gahn', + 'Gronau', + 'Hogston', + 'Kleinfelter', + 'Ksiazek', + 'Lyness', + 'Marak', + 'Munafo', + 'Noorani', + 'Plonski', + 'Pontarelli', + 'Presas', + 'Ringenberg', + 'Sabillon', + 'Schaut', + 'Shankland', + 'Sheil', + 'Shugrue', + 'Soter', + 'Stankovich', + 'Arrants', + 'Boeckmann', + 'Boothroyd', + 'Dysinger', + 'Gersh', + 'Monnig', + 'Scheiderer', + 'Slifka', + 'Vilardi', + 'Podell', + 'Tarallo', + 'Goodroe', + 'Sardinha', + 'Blish', + 'Califf', + 'Dorion', + 'Dougall', + 'Hamza', + 'Boggus', + 'Mccan', + 'Branscomb', + 'Baatz', + 'Bendix', + 'Hartstein', + 'Hechler', + 'Komatsu', + 'Kooiman', + 'Loghry', + 'Lorson', + 'Mcgoff', + 'Moga', + 'Monsees', + 'Nigg', + 'Pacitti', + 'Shiffman', + 'Shoupe', + 'Snarski', + 'Vrba', + 'Wilmeth', + 'Yurchak', + 'Budney', + 'Estok', + 'Knipple', + 'Krzywicki', + 'Librizzi', + 'Obringer', + 'Poliquin', + 'Severtson', + 'Vecchiarelli', + 'Zelazny', + 'Eis', + 'Wildeman', + 'Gatt', + 'Gordin', + 'Dusenbury', + 'Prew', + 'Mander', + 'Tine', + 'Debarr', + 'Bann', + 'Mcguirt', + 'Vanloan', + 'Basdeo', + 'Kosh', + 'Bertha', + 'Mcglothen', + 'Youman', + 'Hallums', + 'Mcfield', + 'Asano', + 'Barbo', + 'Braver', + 'Bua', + 'Buetow', + 'Buttke', + 'Estela', + 'Kauk', + 'Kosmicki', + 'Kuecker', + 'Lahm', + 'Lienhard', + 'Lombera', + 'Menken', + 'Niederhauser', + 'Norcia', + 'Petrelli', + 'Phong', + 'Piontkowski', + 'Prihoda', + 'Raffo', + 'Sherpa', + 'Shinsky', + 'Skoczylas', + 'Sosinski', + 'Sua', + 'Sur', + 'Thorndike', + 'Trease', + 'Wessler', + 'Witting', + 'Ackroyd', + 'Bartnick', + 'Dziuba', + 'Lisko', + 'Muradyan', + 'Pistilli', + 'Riechers', + 'Saxman', + 'Rodi', + 'Venables', + 'Holway', + 'Vargus', + 'Oley', + 'Delmont', + 'Fuster', + 'Wyndham', + 'Whittenberg', + 'Chustz', + 'Swilling', + 'Moncure', + 'Housey', + 'Mckiver', + 'Shelvin', + 'Aslin', + 'Begeman', + 'Capek', + 'Christlieb', + 'Colasanti', + 'Daidone', + 'Detlefsen', + 'Elsass', + 'Faus', + 'Francke', + 'Hensarling', + 'Hollmann', + 'Isaacks', + 'Kocis', + 'Kofman', + 'Kwiatek', + 'Osterkamp', + 'Pickar', + 'Prellwitz', + 'Ramo', + 'Steenson', + 'Tomasulo', + 'Weinreb', + 'Wiard', + 'Ambs', + 'Baglio', + 'Frayre', + 'Hisaw', + 'Justman', + 'Morrical', + 'Sherfey', + 'Gera', + 'Ilgenfritz', + 'Silos', + 'Boge', + 'Darocha', + 'Hennon', + 'Hendriks', + 'Purrington', + 'Eunice', + 'Kirks', + 'Barbar', + 'Guichard', + 'Bonny', + 'Lobban', + 'Winrow', + 'Alavi', + 'Binner', + 'Canan', + 'Ciullo', + 'Cyran', + 'Doolen', + 'Enquist', + 'Fatzinger', + 'Forsell', + 'Harnisch', + 'Hirose', + 'Lunz', + 'Mcbrearty', + 'Mcgavin', + 'Minkin', + 'Ralphs', + 'Ruegsegger', + 'Shetter', + 'Slagter', + 'Tyminski', + 'Ubben', + 'Vanderschaaf', + 'Wigfield', + 'Zellman', + 'Bettenhausen', + 'Busker', + 'Jabs', + 'Mishkin', + 'Sturdy', + 'Vanstone', + 'Tierce', + 'Cormican', + 'Mazzucco', + 'Buenger', + 'Gallier', + 'Duma', + 'Rainbow', + 'Herlong', + 'Chriswell', + 'Litsey', + 'Wyke', + 'Kissoon', + 'Sesler', + 'Farve', + 'Lalanne', + 'Myhand', + 'Heggs', + 'Andujo', + 'Arcilla', + 'Bult', + 'Caponigro', + 'Commerford', + 'Ditmars', + 'Dressen', + 'Eggemeyer', + 'Forstner', + 'From', + 'Heldreth', + 'Hevia', + 'Leiphart', + 'Mastrocola', + 'Mcanelly', + 'Mccrillis', + 'Mellick', + 'Mogle', + 'Mummey', + 'Nishiyama', + 'Nordine', + 'Picinich', + 'Rafiq', + 'Savo', + 'Selvig', + 'Sestak', + 'Shafran', + 'Smithhart', + 'Soltani', + 'Stillion', + 'Szuch', + 'Tigert', + 'Trine', + 'Un', + 'Brest', + 'Callari', + 'Jaskowiak', + 'Maneval', + 'Sarchet', + 'Szuba', + 'Taubman', + 'Wandel', + 'Blok', + 'Pasquarello', + 'Sava', + 'Diekman', + 'Blight', + 'Lovgren', + 'Clemson', + 'Lince', + 'Kanady', + 'Whipps', + 'Coren', + 'Coye', + 'Patman', + 'Souffrant', + 'Bloodsaw', + 'Amano', + 'Cassaday', + 'Cutillo', + 'Dayrit', + 'Deringer', + 'Duwe', + 'Favazza', + 'Fennema', + 'Hackleman', + 'Harders', + 'Imperiale', + 'Kano', + 'Kingma', + 'Meuser', + 'Neiger', + 'Neitz', + 'Nied', + 'Prows', + 'Riss', + 'Rotundo', + 'Scheurich', + 'Stopa', + 'Tonks', + 'Veen', + 'Volante', + 'Maerz', + 'Nunnelley', + 'Sommerfeldt', + 'Spoonemore', + 'Wechter', + 'Wehrli', + 'Ackert', + 'Begun', + 'Dreyfuss', + 'Frezza', + 'Mako', + 'Nagao', + 'Lassetter', + 'Linse', + 'Raum', + 'Graca', + 'Enslow', + 'Bruff', + 'Hodgkin', + 'Coone', + 'Trippett', + 'Tippitt', + 'Sumerlin', + 'Carelock', + 'Whitelow', + 'Beightol', + 'Cappadona', + 'Carrizal', + 'Clendaniel', + 'Cresci', + 'Dietzman', + 'Figge', + 'Heyde', + 'Jarema', + 'Kyllonen', + 'Laminack', + 'Luddy', + 'Monical', + 'Mula', + 'Picotte', + 'Sandiego', + 'Seki', + 'Senner', + 'Starkman', + 'Stassi', + 'Stuckert', + 'Wiers', + 'Wieting', + 'Ziska', + 'Ardelean', + 'Hulslander', + 'Loewenstein', + 'Mearns', + 'Roese', + 'Sweaney', + 'Winick', + 'Zaring', + 'Farry', + 'Dulle', + 'Gunnerson', + 'Duden', + 'Arts', + 'Lame', + 'Mcquerry', + 'Smiles', + 'Pennick', + 'Adderly', + 'Becka', + 'Bluemel', + 'Bocek', + 'Bouwens', + 'Deren', + 'Dewitz', + 'Doland', + 'Ewton', + 'Funnell', + 'Gavel', + 'Haidar', + 'Kalkbrenner', + 'Kawashima', + 'Kueker', + 'Lutze', + 'Macareno', + 'Nenninger', + 'Schone', + 'Seever', + 'Sexauer', + 'Sibilia', + 'Sperrazza', + 'Vanderhoef', + 'Vanoss', + 'Werre', + 'Wotton', + 'Behney', + 'Bossart', + 'Ellithorpe', + 'Eyrich', + 'Fosco', + 'Fulginiti', + 'Grumbles', + 'Hoeger', + 'Kizziah', + 'Kloiber', + 'Kudo', + 'Majcher', + 'Stickels', + 'Stoler', + 'Umholtz', + 'Vasallo', + 'Wenker', + 'Wittmeyer', + 'Telesco', + 'Jha', + 'Maulding', + 'Campton', + 'Verble', + 'Mclure', + 'Bernardin', + 'Eison', + 'Coffie', + 'Ceesay', + 'Balakrishnan', + 'Barich', + 'Bigman', + 'Blumenstein', + 'Bonafede', + 'Cebulski', + 'Chesbro', + 'Cuaresma', + 'Demarino', + 'Derienzo', + 'Donmoyer', + 'Fairall', + 'Gelpi', + 'Giambra', + 'Hasselman', + 'Highlander', + 'Hunker', + 'Iyengar', + 'Kulaga', + 'Kuznicki', + 'Labus', + 'Limbert', + 'Molchan', + 'Neuharth', + 'Overgaard', + 'Paszkiewicz', + 'Plescia', + 'Redcay', + 'Ritzer', + 'Smirnov', + 'Valiquette', + 'Vannortwick', + 'Warstler', + 'Yantz', + 'Beardall', + 'Cimmino', + 'Crnkovich', + 'Konishi', + 'Kosowski', + 'Ragen', + 'Sebert', + 'Valla', + 'Venancio', + 'Maltez', + 'Skehan', + 'Abrantes', + 'Colfer', + 'Beman', + 'Wilhelmsen', + 'Wilking', + 'Rorer', + 'Shutes', + 'Albany', + 'Wearing', + 'Assefa', + 'Angeloni', + 'Bisher', + 'Blancett', + 'Briel', + 'Chiara', + 'Clearman', + 'Dengel', + 'Detert', + 'Fadely', + 'Flinders', + 'Garguilo', + 'Goes', + 'Hakimian', + 'Henehan', + 'Homewood', + 'Kalla', + 'Keirn', + 'Kerwood', + 'Laflam', + 'Lynskey', + 'Minhas', + 'Mow', + 'Olk', + 'Ostergaard', + 'Palecek', + 'Poirrier', + 'Raudenbush', + 'Schlottman', + 'Shatz', + 'Sieloff', + 'Stikeleather', + 'Swavely', + 'Tapanes', + 'Teehan', + 'Wendorff', + 'Wollner', + 'Bichsel', + 'Brandenburger', + 'Demattia', + 'Eggebrecht', + 'Koelzer', + 'Landrigan', + 'Morsch', + 'Pittinger', + 'Rewerts', + 'Schopf', + 'Tetro', + 'Westenberger', + 'Kieft', + 'Overy', + 'Cutrona', + 'Misa', + 'Erich', + 'Swapp', + 'Welchel', + 'Messa', + 'Ala', + 'Witbeck', + 'Mothershead', + 'Stofer', + 'Mcneice', + 'Ayling', + 'Zakaria', + 'Bu', + 'Rauf', + 'Richbourg', + 'Fristoe', + 'Dorch', + 'Mcclarin', + 'Privott', + 'Bonsu', + 'Ayson', + 'Bifulco', + 'Brungard', + 'Bub', + 'Budzynski', + 'Chizmar', + 'Coriz', + 'Corser', + 'Daughdrill', + 'Delre', + 'Elfers', + 'Fabrizi', + 'Gunawan', + 'Haecker', + 'Hammac', + 'Handwerk', + 'Larcom', + 'Liera', + 'Littlewood', + 'Luikart', + 'Pasquarella', + 'Radman', + 'Ranft', + 'Rigas', + 'Santin', + 'Sorbello', + 'Tayag', + 'Ureste', + 'Weidinger', + 'Yerena', + 'Aase', + 'Galyen', + 'Halferty', + 'Hindley', + 'Kunath', + 'Laprairie', + 'Oza', + 'Stohler', + 'Tokarczyk', + 'Yusupov', + 'Nogueras', + 'Jersey', + 'Eastes', + 'Agron', + 'Boso', + 'Kender', + 'Couse', + 'Moreta', + 'Larrow', + 'Degrace', + 'Sonier', + 'Tisdel', + 'Creque', + 'Esther', + 'Girtman', + 'Seraphin', + 'Wesby', + 'Kargbo', + 'Adjei', + 'Angeline', + 'Biby', + 'Brucks', + 'Bucaro', + 'Farman', + 'Gerdeman', + 'Hodsdon', + 'Hoying', + 'Kasperek', + 'Keinath', + 'Kidman', + 'Kleier', + 'Kuban', + 'Lacko', + 'Latourette', + 'Leffert', + 'Leonhart', + 'Mathern', + 'Ploss', + 'Poblano', + 'Raigoza', + 'Santor', + 'Schmitzer', + 'Sirico', + 'Skalsky', + 'Spreen', + 'Standlee', + 'Vonbargen', + 'Cederberg', + 'Cornforth', + 'Dercole', + 'Diblasio', + 'Fleer', + 'Fredlund', + 'Gehris', + 'Guck', + 'Lannen', + 'Lurz', + 'Mazzaferro', + 'Neukam', + 'Rookstool', + 'Scharrer', + 'Sevey', + 'Sicairos', + 'Skrocki', + 'Sneeringer', + 'Stefanowicz', + 'Zuleger', + 'Harmel', + 'Sendejo', + 'Bearer', + 'Shur', + 'Weers', + 'Norell', + 'Plotnick', + 'Cecchi', + 'Gandia', + 'Bastone', + 'Tole', + 'Tramell', + 'Willock', + 'Rhome', + 'Curington', + 'Rapley', + 'Hazley', + 'Todman', + 'Lathon', + 'Alperin', + 'Axtman', + 'Boeke', + 'Butson', + 'Cestaro', + 'Cosgriff', + 'Docter', + 'Eblin', + 'Filsinger', + 'Franzone', + 'Gareau', + 'Garfinkle', + 'Gatch', + 'Germosen', + 'Grzywacz', + 'Huesman', + 'Kasel', + 'Kazan', + 'Manalang', + 'Marando', + 'Marchio', + 'Massimino', + 'Mcneer', + 'Menger', + 'Milanese', + 'Monrreal', + 'Moretto', + 'Mulvany', + 'Petkus', + 'Rehling', + 'Rubbo', + 'Rudnik', + 'Settlemire', + 'Treon', + 'Yaklin', + 'Zittel', + 'Betzold', + 'Bohlin', + 'Churilla', + 'Conrath', + 'Ozbun', + 'Sciuto', + 'Stitz', + 'Sweigert', + 'Tamanaha', + 'Wallgren', + 'Eplin', + 'Ion', + 'Liford', + 'Orendorff', + 'Wootan', + 'Carmical', + 'Mince', + 'Stormes', + 'Lantry', + 'Sportsman', + 'Corron', + 'Padia', + 'Cunnington', + 'Pitta', + 'Ori', + 'Obara', + 'Gaultney', + 'Vanlue', + 'Emmitt', + 'Roddey', + 'Payen', + 'Elmi', + 'Culmer', + 'Mealing', + 'Allegra', + 'Bano', + 'Batterman', + 'Bickell', + 'Dager', + 'Drach', + 'Duchesneau', + 'Erdos', + 'Fedorko', + 'Fluhr', + 'Gassmann', + 'Gillig', + 'Goedert', + 'Golomb', + 'Hatler', + 'Jalali', + 'Joosten', + 'Koke', + 'Lausch', + 'Leisner', + 'Mallinger', + 'Marsolek', + 'Mashek', + 'Ognibene', + 'Oishi', + 'Outman', + 'Paganelli', + 'Passino', + 'Petrak', + 'Rosenwald', + 'Schroader', + 'Stehman', + 'Tenuta', + 'Todt', + 'Tritz', + 'Boerman', + 'Doeden', + 'Etcheverry', + 'Grissinger', + 'Gruenewald', + 'Lijewski', + 'Marcom', + 'Niebauer', + 'Rukavina', + 'Sakuma', + 'Woehrle', + 'Amores', + 'Krammes', + 'Shontz', + 'Bunning', + 'Widdowson', + 'Blankenburg', + 'Goans', + 'Longan', + 'Aboud', + 'Michelli', + 'Rivere', + 'Colla', + 'Lory', + 'Lougheed', + 'Wadel', + 'Chalkley', + 'Gaubert', + 'Goodlin', + 'Bommer', + 'Abbs', + 'Rashad', + 'Malachi', + 'Abrigo', + 'Akre', + 'Antolik', + 'Bachner', + 'Blegen', + 'Cona', + 'Diantonio', + 'Emde', + 'Enrico', + 'Follette', + 'Hagarty', + 'Hanser', + 'Hulsman', + 'Jelinski', + 'Kalisz', + 'Kolek', + 'Kough', + 'Ninneman', + 'Offield', + 'Perezgarcia', + 'Plude', + 'Printy', + 'Rosengrant', + 'Salminen', + 'Schamberger', + 'Teall', + 'Zipfel', + 'Bickler', + 'Casanas', + 'Holtzapple', + 'Sachdeva', + 'Scharnhorst', + 'Schnack', + 'Grode', + 'Strough', + 'Teare', + 'Korona', + 'Creelman', + 'Simper', + 'Marett', + 'Nadeem', + 'Pollet', + 'Eduardo', + 'Chipley', + 'Vanrossum', + 'Fabio', + 'Colona', + 'Whirley', + 'Hider', + 'Plaskett', + 'Trabue', + 'Gibert', + 'Cabiness', + 'Loyal', + 'Rayson', + 'Aloia', + 'Aukerman', + 'Broxterman', + 'Cada', + 'Catalanotto', + 'Condos', + 'Corriher', + 'Eliopoulos', + 'Furia', + 'Girolamo', + 'Haese', + 'Israelson', + 'Jaworowski', + 'Jirik', + 'Kalmar', + 'Leipold', + 'Lemmo', + 'Loja', + 'Loughmiller', + 'Matelski', + 'Mcrorie', + 'Moeckel', + 'Naill', + 'Raczka', + 'Rathgeber', + 'Shamoun', + 'Shannahan', + 'Simler', + 'Stamer', + 'Stonehocker', + 'Twersky', + 'Voeltz', + 'Willets', + 'Wolgamott', + 'Yamin', + 'Acri', + 'Dalgleish', + 'Ehrenreich', + 'Huish', + 'Huxley', + 'Pinkstaff', + 'Rincones', + 'Saric', + 'Shreiner', + 'Stitely', + 'Tippets', + 'Vanamburg', + 'Zbikowski', + 'Sharrett', + 'Suther', + 'Renta', + 'Balles', + 'Florentine', + 'Chrisley', + 'Offner', + 'Matheus', + 'Akens', + 'Dugue', + 'Rigaud', + 'Mohamud', + 'Magloire', + 'Stigger', + 'Andrist', + 'Chaudoin', + 'Clos', + 'Cragin', + 'Dinius', + 'Duignan', + 'Elk', + 'Frenz', + 'Frogge', + 'Giammarino', + 'Hackl', + 'Jaeckel', + 'Knieriem', + 'Lajara', + 'Lisak', + 'Luxton', + 'Merriott', + 'Montini', + 'Olender', + 'Orebaugh', + 'Orren', + 'Osika', + 'Sciascia', + 'Selvaggio', + 'Stoneback', + 'Sweis', + 'Torosyan', + 'Trupp', + 'Wardrip', + 'Wigle', + 'Beissel', + 'Brakke', + 'Carosella', + 'Dobek', + 'Eidem', + 'Homolka', + 'Kemery', + 'Kinderman', + 'Palla', + 'Puccini', + 'Szarek', + 'Vandehei', + 'Arca', + 'Jou', + 'Needs', + 'Habermann', + 'Hyle', + 'Jagoda', + 'Smigielski', + 'Guttierrez', + 'Awwad', + 'Maccormack', + 'Bassin', + 'Achee', + 'Demark', + 'Jardon', + 'Kelsoe', + 'Olear', + 'Comacho', + 'Rosetta', + 'Peddie', + 'Delsol', + 'Nwachukwu', + 'Bagdasarian', + 'Boehringer', + 'Bunke', + 'Burkhammer', + 'Delahoya', + 'Dietzen', + 'Ditmer', + 'Duchaine', + 'Felske', + 'Gumpert', + 'Hansson', + 'Hedeen', + 'Jalil', + 'Kalal', + 'Kanan', + 'Kaska', + 'Kaufer', + 'Knoff', + 'Kornblum', + 'Lanzi', + 'Obenchain', + 'Piatkowski', + 'Prugh', + 'Rima', + 'Shadduck', + 'Sodergren', + 'Spitzley', + 'Tauzin', + 'Weigelt', + 'Baldassarre', + 'Biglin', + 'Fuhriman', + 'Gaumond', + 'Ledvina', + 'Meckler', + 'Minteer', + 'Nesser', + 'Riederer', + 'Ruelle', + 'Turchi', + 'Alberg', + 'Vanderlip', + 'Halder', + 'Hop', + 'Larmon', + 'Bonfield', + 'Ketch', + 'Mannis', + 'Mcallen', + 'Alfonzo', + 'Sampey', + 'Guillet', + 'Madaris', + 'Lisby', + 'Crowner', + 'Frager', + 'Coar', + 'Crewe', + 'Levier', + 'Ligons', + 'Abello', + 'Brinsfield', + 'Buccieri', + 'Cantera', + 'Cieslinski', + 'Cragle', + 'Flater', + 'Grunert', + 'Higinbotham', + 'Janish', + 'Kuennen', + 'Lanners', + 'Lesiak', + 'Litvin', + 'Madueno', + 'Maffia', + 'Manetta', + 'Marschke', + 'Mourer', + 'Nordahl', + 'Nordan', + 'Pankowski', + 'Petron', + 'Qualley', + 'Recht', + 'Rosenbach', + 'Ruttenberg', + 'Saam', + 'Savarino', + 'Solana', + 'Stumpff', + 'Tsukamoto', + 'Vanlanen', + 'Wainer', + 'Kasza', + 'Kuehler', + 'Landgren', + 'Omahony', + 'Paullin', + 'Ramales', + 'Schmelzle', + 'Schnakenberg', + 'Touma', + 'Urgiles', + 'Vorndran', + 'Corne', + 'Higman', + 'Dutil', + 'Reef', + 'Racanelli', + 'Gladwin', + 'Jaspers', + 'Crutchley', + 'Homme', + 'Hughbanks', + 'Crismon', + 'Burdin', + 'Dise', + 'Enzor', + 'Hally', + 'Mccone', + 'Mckell', + 'Belo', + 'Moat', + 'Ijames', + 'Bussie', + 'Papillion', + 'Pratcher', + 'Baranek', + 'Bidlack', + 'Boyadjian', + 'Chern', + 'Conahan', + 'Dimuzio', + 'Erker', + 'Fregeau', + 'Gelsinger', + 'Gonzalo', + 'Heo', + 'Hoog', + 'Jovanovich', + 'Kaschak', + 'Kasik', + 'Katich', + 'Laible', + 'Mastel', + 'Muellner', + 'Pingleton', + 'Rexroth', + 'Schmitter', + 'Stick', + 'Strollo', + 'Traficante', + 'Veteto', + 'Wampole', + 'Winings', + 'Amalfitano', + 'Amiot', + 'Camaj', + 'Cuartas', + 'Drotar', + 'Eatherton', + 'Fioretti', + 'Fudala', + 'Gehrman', + 'Gittleman', + 'Heppe', + 'Maffucci', + 'Tammen', + 'Chovan', + 'Ginley', + 'Stipes', + 'Antigua', + 'Ironside', + 'Kuroda', + 'Lebar', + 'Laske', + 'Salay', + 'Gisi', + 'Mccormic', + 'Veron', + 'Robbin', + 'Morain', + 'Mayden', + 'Vanputten', + 'Triplet', + 'Ravenel', + 'Moragne', + 'Bowdry', + 'Agundez', + 'Allinson', + 'Bosko', + 'Buehrle', + 'Devey', + 'Gasiorowski', + 'Goettel', + 'Halleran', + 'Innocenti', + 'Orser', + 'Scarpati', + 'Scherff', + 'Schlott', + 'Skilling', + 'Speedy', + 'Staal', + 'Szafran', + 'Szczech', + 'Szczepanik', + 'Venturella', + 'Vert', + 'Vogelgesang', + 'Vollbrecht', + 'Wiehe', + 'Achterberg', + 'Fadness', + 'Groene', + 'Halbrooks', + 'Leavenworth', + 'Pruski', + 'Redifer', + 'Schmiesing', + 'Stanforth', + 'Stepanski', + 'Ziel', + 'Hefter', + 'Urman', + 'Muela', + 'Simpler', + 'Elick', + 'Shalabi', + 'Cooner', + 'Ferriera', + 'Templer', + 'Prashad', + 'Gorum', + 'Wheller', + 'Spratling', + 'Gutter', + 'Eke', + 'Rias', + 'Belcourt', + 'Bernards', + 'Camburn', + 'Cerqueira', + 'Conkel', + 'Deist', + 'Derobertis', + 'Desio', + 'Eimer', + 'Fayad', + 'Frommelt', + 'Guariglia', + 'Laba', + 'Labine', + 'Lanius', + 'Loconte', + 'Nop', + 'Omary', + 'Penninger', + 'Pentland', + 'Pinkus', + 'Richoux', + 'Sturrock', + 'Theil', + 'Vanvranken', + 'Bartoszek', + 'Bruski', + 'Engelken', + 'Kranich', + 'Mrazek', + 'Muralles', + 'Pienta', + 'Salido', + 'Sridhar', + 'Turkington', + 'Vellucci', + 'Verhage', + 'Derenzo', + 'Lucker', + 'Wands', + 'Parrow', + 'Branyon', + 'Houff', + 'Bossier', + 'Reels', + 'Rockmore', + 'Altmeyer', + 'Anacker', + 'Antoniou', + 'Berlinger', + 'Busser', + 'Caracci', + 'Caseres', + 'Corcino', + 'Demint', + 'Dhanani', + 'Erekson', + 'Farinacci', + 'Ganesan', + 'Gornick', + 'Gresser', + 'Kremers', + 'Kreuter', + 'Lesieur', + 'Linarez', + 'Mccrystal', + 'Morang', + 'Pucillo', + 'Spicuzza', + 'Tranchina', + 'Tullar', + 'Vantilburg', + 'Yeck', + 'Zandstra', + 'Zeleny', + 'Bearss', + 'Burgner', + 'Delich', + 'Fetsch', + 'Grom', + 'Kreisel', + 'Laprise', + 'Legarreta', + 'Musacchio', + 'Rembold', + 'Sjoblom', + 'Skalicky', + 'Sokolov', + 'Tuminello', + 'Vanskiver', + 'Zidek', + 'Severa', + 'Stables', + 'Guffy', + 'Lebeck', + 'Barradas', + 'Chanley', + 'Dayal', + 'Villafranco', + 'Droke', + 'Popwell', + 'Renier', + 'Bolten', + 'Mille', + 'Swagerty', + 'Grismore', + 'Brantly', + 'Divens', + 'Ottey', + 'Hagger', + 'Advincula', + 'Boschee', + 'Buckbee', + 'Carlan', + 'Casciato', + 'Cregar', + 'Fehring', + 'Ianniello', + 'Interrante', + 'Juedes', + 'Kosier', + 'Lizaola', + 'Lorenzetti', + 'Mccauslin', + 'Older', + 'Osuch', + 'Ramstad', + 'Sare', + 'Stavinoha', + 'Taborda', + 'Warmoth', + 'Weissmann', + 'Winograd', + 'Woeste', + 'Zywicki', + 'Blalack', + 'Chavoya', + 'Clickner', + 'Daigrepont', + 'Dissinger', + 'Kovalik', + 'Lemler', + 'Shortall', + 'Tucholski', + 'Vanmetre', + 'Zetino', + 'Niezgoda', + 'Recupero', + 'Booms', + 'Ramsburg', + 'Berka', + 'Mininger', + 'Tamer', + 'Baka', + 'Jago', + 'Bucks', + 'Laude', + 'Andrepont', + 'Gair', + 'Hayer', + 'Kitching', + 'Towson', + 'Slappey', + 'Syms', + 'Derico', + 'Badie', + 'Kenon', + 'Goffney', + 'Amigon', + 'Belsito', + 'Bergamo', + 'Caputi', + 'Delpilar', + 'Entsminger', + 'Gehres', + 'Geimer', + 'Hada', + 'Krolak', + 'Kruer', + 'Malaney', + 'Mancias', + 'Misiaszek', + 'Pring', + 'Salonga', + 'Schaefers', + 'Schmied', + 'Schwertfeger', + 'Scialabba', + 'Stemmer', + 'Stifter', + 'Suon', + 'Szczygiel', + 'Weisse', + 'Yackley', + 'Decasas', + 'Donado', + 'Drenning', + 'Eppich', + 'Kertesz', + 'Mihal', + 'Mochizuki', + 'Schiebel', + 'Schlageter', + 'Scruton', + 'Weckerly', + 'Wemhoff', + 'Wernette', + 'Zietz', + 'Iwanicki', + 'Ara', + 'Barson', + 'Resor', + 'Rampy', + 'Iskander', + 'Oharra', + 'Kope', + 'Soli', + 'Bodkins', + 'Bussa', + 'Maletta', + 'Clemen', + 'Vaneaton', + 'Berkel', + 'Salvage', + 'Gilchrest', + 'Whitter', + 'Bruster', + 'Mccowin', + 'Gullatt', + 'Cherubin', + 'Flamer', + 'Gueye', + 'Angerer', + 'Baray', + 'Barreca', + 'Bresson', + 'Brougham', + 'Buscaglia', + 'Candee', + 'Decelles', + 'Durflinger', + 'Dusenbery', + 'Enomoto', + 'Galliano', + 'Klooster', + 'Lowrimore', + 'Manda', + 'Morace', + 'Raisanen', + 'Ravenscraft', + 'Rutman', + 'Schmieg', + 'Schorsch', + 'Selim', + 'Stanchfield', + 'Stankowski', + 'Tolosa', + 'Uyeno', + 'Vancleef', + 'Kamdar', + 'Kazlauskas', + 'Kwasnik', + 'Pivonka', + 'Shrode', + 'Sellinger', + 'Deliz', + 'Longerbeam', + 'Schobert', + 'Shader', + 'Collister', + 'Curtright', + 'Franc', + 'Wakely', + 'Duree', + 'Laban', + 'Gascoigne', + 'Noy', + 'Hulon', + 'Michele', + 'Crowden', + 'Dolton', + 'Ryner', + 'Gene', + 'Tetterton', + 'Laffitte', + 'Laidler', + 'Hoston', + 'Akter', + 'Biebel', + 'Bohnenkamp', + 'Bottger', + 'Brecheisen', + 'Bumbarger', + 'Burgert', + 'Burtnett', + 'Coffing', + 'Corigliano', + 'Dault', + 'Dettinger', + 'Fenech', + 'Golaszewski', + 'Hernando', + 'Hoppel', + 'Kadrmas', + 'Khim', + 'Labrado', + 'Leh', + 'Michiels', + 'Milkovich', + 'Mosel', + 'Nestle', + 'Nunan', + 'Palomarez', + 'Peretz', + 'Perno', + 'Popowski', + 'Pottebaum', + 'Rallis', + 'Rase', + 'Rotramel', + 'Sokolik', + 'Sparlin', + 'Zipf', + 'Abruzzese', + 'Branin', + 'Cheslock', + 'Chimenti', + 'Czechowski', + 'Diveley', + 'Eisenbeis', + 'Eisenhut', + 'Friedt', + 'Gehlhausen', + 'Kamphaus', + 'Mctiernan', + 'Monnett', + 'Schue', + 'Steffensmeier', + 'Gens', + 'Schlotterbeck', + 'Ask', + 'Leser', + 'Renville', + 'Wisenbaker', + 'Kellow', + 'Mounsey', + 'Dupin', + 'Causer', + 'Yapp', + 'Stmary', + 'Bowditch', + 'Nickolson', + 'Molla', + 'Larke', + 'Kamau', + 'Cardinali', + 'Deely', + 'Deep', + 'Dietel', + 'Ferraris', + 'Fons', + 'Hahm', + 'Huy', + 'Imber', + 'Leichliter', + 'Longanecker', + 'Lordi', + 'Ludewig', + 'Maiolo', + 'Mckern', + 'Meyering', + 'Muhl', + 'Nylen', + 'Ohlendorf', + 'Palmgren', + 'Raffield', + 'Reusser', + 'Revette', + 'Ridolfi', + 'Rosemeyer', + 'Seber', + 'Silberberg', + 'Sitzmann', + 'Tayman', + 'Tygart', + 'Vertz', + 'Volkmer', + 'Bellemare', + 'Benanti', + 'Bialecki', + 'Biber', + 'Dipierro', + 'Dornbush', + 'Eichhorst', + 'Messana', + 'Neisen', + 'Ottoson', + 'Salmonson', + 'Turcott', + 'Vlachos', + 'Wojdyla', + 'Dagg', + 'Hernan', + 'Mannes', + 'Fent', + 'Tappen', + 'Hyers', + 'Gery', + 'Deam', + 'Channing', + 'Gesner', + 'Swaringen', + 'Lakins', + 'Cogbill', + 'Allsbrook', + 'Kennemore', + 'Sumrell', + 'Luma', + 'Rookard', + 'Shakoor', + 'Philbert', + 'Maragh', + 'Wordlaw', + 'Ofori', + 'Arseneault', + 'Arslanian', + 'Aydin', + 'Balthaser', + 'Bensch', + 'Boord', + 'Botting', + 'Brummet', + 'Cassiday', + 'Chubbuck', + 'Crance', + 'Dobis', + 'Dymek', + 'Kakar', + 'Kipnis', + 'Kooi', + 'Kovack', + 'Malzahn', + 'Melendes', + 'Micucci', + 'Miklas', + 'Molander', + 'Nungesser', + 'Razavi', + 'Reppond', + 'Reznick', + 'Rosten', + 'Schwegler', + 'Sielaff', + 'Sincavage', + 'Soave', + 'Socorro', + 'Tausch', + 'Tracz', + 'Vey', + 'Weltman', + 'Wittich', + 'Emswiler', + 'Etzkorn', + 'Kuchenbecker', + 'Lampi', + 'Pfahler', + 'Thronson', + 'Trefz', + 'Pont', + 'Hendrie', + 'Russon', + 'Coleson', + 'Gregori', + 'Herzfeld', + 'Tamas', + 'Oslin', + 'Warrell', + 'Basher', + 'Elizabeth', + 'Nickolas', + 'Prigmore', + 'Okray', + 'Cannedy', + 'Mercy', + 'Daigre', + 'Leggins', + 'Savannah', + 'Russaw', + 'Opoku', + 'Angier', + 'Behrle', + 'Budny', + 'Cislo', + 'Covalt', + 'Dershem', + 'Devincent', + 'Dhar', + 'Dombrosky', + 'Dragovich', + 'Drobny', + 'Fess', + 'Genthner', + 'Gierhart', + 'Hadzic', + 'Hehir', + 'Henle', + 'Heyd', + 'Hudlow', + 'Janko', + 'Kapral', + 'Kietzman', + 'Malburg', + 'Maret', + 'Mcever', + 'Sann', + 'Scheidel', + 'Schultheiss', + 'Sedita', + 'Sigl', + 'Starace', + 'Stoklosa', + 'Tainter', + 'Tamburrino', + 'Vankleeck', + 'Vannucci', + 'Wernecke', + 'Widmayer', + 'Agresti', + 'Boshell', + 'Dartt', + 'Dobkin', + 'Effertz', + 'Gaydosh', + 'Hocevar', + 'Kluger', + 'Mcguffee', + 'Pekala', + 'Tuchman', + 'Keylon', + 'Pletz', + 'Germond', + 'Keedy', + 'Meir', + 'Tromp', + 'Solly', + 'Baerga', + 'Jawad', + 'Chanda', + 'Scobie', + 'Snowball', + 'Pricer', + 'Graper', + 'Bally', + 'Mcfarlan', + 'Duncombe', + 'Mccory', + 'Costen', + 'Poplar', + 'Denkins', + 'Padmore', + 'Waithe', + 'Adduci', + 'Aldaba', + 'Berhow', + 'Cocuzza', + 'Dubroc', + 'Earnheart', + 'Eickholt', + 'Gutzwiller', + 'Heavin', + 'Himebaugh', + 'Jakubik', + 'Kiang', + 'Klusman', + 'Knueppel', + 'Neddo', + 'Oakey', + 'Rachlin', + 'Spegal', + 'Spizzirri', + 'Stavola', + 'Zika', + 'Beverlin', + 'Boehle', + 'Caltagirone', + 'Chernick', + 'Ciaccia', + 'Courchaine', + 'Covault', + 'Crihfield', + 'Fojtik', + 'Gronski', + 'Huwe', + 'Ostrovsky', + 'Quraishi', + 'Rauber', + 'Scalici', + 'Schuetze', + 'Advani', + 'Galer', + 'Rog', + 'Husson', + 'Karpen', + 'Ess', + 'Henman', + 'Slatten', + 'Bango', + 'Barkin', + 'Vessell', + 'Mayson', + 'Kittles', + 'Quince', + 'Beardmore', + 'Breceda', + 'Carmony', + 'Ciliberto', + 'Cotroneo', + 'Dimitroff', + 'Granahan', + 'Haacke', + 'Huska', + 'Jankiewicz', + 'Klipp', + 'Kostic', + 'Langarica', + 'Lanphier', + 'Maran', + 'Marmion', + 'Mclinden', + 'Mcpeake', + 'Minkel', + 'Nicolo', + 'Quihuis', + 'Siemsen', + 'Somero', + 'Spuhler', + 'Spychalski', + 'Stary', + 'Stitzer', + 'Stucke', + 'Tango', + 'Ticas', + 'Vivero', + 'Campen', + 'Fei', + 'Ganas', + 'Klipfel', + 'Vodicka', + 'Zajdel', + 'Ulin', + 'Bodey', + 'Moral', + 'Fellenz', + 'Charo', + 'Cliver', + 'Clasby', + 'Neeson', + 'Durell', + 'Hew', + 'Mcgray', + 'Breaker', + 'Haslem', + 'Verser', + 'Broner', + 'Mannings', + 'Darensbourg', + 'Petithomme', + 'Akbari', + 'Amdahl', + 'Boeger', + 'Bougie', + 'Buffo', + 'Cisar', + 'Deleonardis', + 'Diffee', + 'Dillen', + 'Dingley', + 'Dugo', + 'Fedora', + 'Habibi', + 'Hartland', + 'Hennelly', + 'Kachmar', + 'Louth', + 'Mughal', + 'Muska', + 'Narang', + 'Pontillo', + 'Roel', + 'Shehorn', + 'Smick', + 'Soliven', + 'Starzyk', + 'Swaminathan', + 'Teagarden', + 'Thune', + 'Vokes', + 'Volkov', + 'Weckesser', + 'Wigen', + 'Donaghue', + 'Ederer', + 'Glaus', + 'Gwozdz', + 'Kimler', + 'Kocak', + 'Lagerquist', + 'Pellecchia', + 'Ruminski', + 'Scholler', + 'Steurer', + 'Tlatelpa', + 'Zegarra', + 'Janssens', + 'Jass', + 'Ciriaco', + 'Kessner', + 'Georg', + 'Harre', + 'Brannam', + 'Beel', + 'Kaine', + 'Roher', + 'Evora', + 'Rittman', + 'Sion', + 'Millon', + 'Morre', + 'Bouler', + 'Seegars', + 'Jenifer', + 'Bernd', + 'Chahine', + 'Crisanto', + 'Desautel', + 'Dirosa', + 'Fehringer', + 'Fukui', + 'Hetz', + 'Hueber', + 'Ivanova', + 'Klecker', + 'Kulzer', + 'Machi', + 'Menn', + 'Mudry', + 'Niro', + 'Nyenhuis', + 'Pressel', + 'Prusinski', + 'Roske', + 'Shaefer', + 'Stear', + 'Stumpo', + 'Teas', + 'Tolsma', + 'Troha', + 'Vanveen', + 'Waltermire', + 'Zaretsky', + 'Zingg', + 'Arntson', + 'Dizdarevic', + 'Kassebaum', + 'Natzke', + 'Passanisi', + 'Rodebaugh', + 'Skonieczny', + 'Vanhoozer', + 'Wiechert', + 'Golonka', + 'Roycroft', + 'Robl', + 'Lisboa', + 'Brandis', + 'Symmes', + 'Nou', + 'Pawson', + 'Comins', + 'Ranker', + 'Silman', + 'Lonas', + 'Goldthwaite', + 'Aries', + 'Leckey', + 'Conolly', + 'Ezelle', + 'Degrasse', + 'Tarte', + 'Bonaventure', + 'Rambeau', + 'Alsobrooks', + 'Blumenberg', + 'Snape', + 'Delane', + 'Sarr', + 'Rankine', + 'Mcclarty', + 'Skipwith', + 'Mapps', + 'Poke', + 'Ahlman', + 'Brunkow', + 'Crissinger', + 'Critcher', + 'Cronce', + 'Earney', + 'Fischler', + 'Franta', + 'Haist', + 'Hirschfield', + 'Jacobe', + 'Karraker', + 'Kronenberger', + 'Layland', + 'Liscano', + 'Lohrman', + 'Luy', + 'Macik', + 'Makinen', + 'Mis', + 'Musarra', + 'Orbe', + 'Ortloff', + 'Potempa', + 'Presta', + 'Rebollo', + 'Rudden', + 'Schab', + 'Settlemyre', + 'Shaban', + 'Shiraishi', + 'Shrake', + 'Suba', + 'Tornquist', + 'Treglia', + 'Vanschaick', + 'Velten', + 'Waln', + 'Addeo', + 'Dacquisto', + 'Fenno', + 'Gilberg', + 'Halberstam', + 'Holck', + 'Landgrebe', + 'Lipa', + 'Luehrs', + 'Mkrtchyan', + 'Proscia', + 'Schucker', + 'Selner', + 'Sinisi', + 'Wandersee', + 'Weigold', + 'Winterrowd', + 'Stoutenburg', + 'Medinger', + 'Bittman', + 'Gerges', + 'Langelier', + 'Berdine', + 'Hartshorne', + 'Matters', + 'Lavere', + 'Delauter', + 'Caillouet', + 'Elford', + 'Derrington', + 'Mollison', + 'Erskin', + 'Doswell', + 'Loadholt', + 'Stepter', + 'Contee', + 'Adwell', + 'Banez', + 'Birchler', + 'Bodman', + 'Bransfield', + 'Butzer', + 'Cenci', + 'Fabro', + 'Fila', + 'Follman', + 'Geoffrion', + 'Hardegree', + 'Klindt', + 'Kuzniar', + 'Lapenta', + 'Lasorsa', + 'Lykens', + 'Madariaga', + 'Mcginnity', + 'Mezger', + 'Milleson', + 'Nisly', + 'Palau', + 'Salz', + 'Sholly', + 'Spartz', + 'Spevak', + 'Svehla', + 'Trafford', + 'Treu', + 'Winski', + 'Zervas', + 'Bautch', + 'Dybas', + 'Hillenburg', + 'Krahl', + 'Loretto', + 'Mcanany', + 'Meschke', + 'Panuco', + 'Pezzullo', + 'Pokorski', + 'Reinertson', + 'Spoden', + 'Steinbrenner', + 'Wedig', + 'Mom', + 'Furner', + 'Harpin', + 'Carlston', + 'Oo', + 'Betten', + 'Duro', + 'Veronica', + 'Klutz', + 'Coven', + 'Siles', + 'Carby', + 'Duvernay', + 'Gory', + 'Adamczak', + 'Adee', + 'Agius', + 'Bachicha', + 'Belka', + 'Bridenstine', + 'Cappella', + 'Chiao', + 'Georgiadis', + 'Hansmann', + 'Kettlewell', + 'Klemann', + 'Kracke', + 'Legacy', + 'Mateja', + 'Mcgarrigle', + 'Peitz', + 'Pergande', + 'Proia', + 'Reicher', + 'Rentfrow', + 'Rudkin', + 'Sahni', + 'Santopietro', + 'Sarin', + 'Schear', + 'Seckel', + 'Sopp', + 'Sorci', + 'Terbush', + 'Uplinger', + 'Vantol', + 'Zaro', + 'Cuppett', + 'Depetro', + 'Hofferber', + 'Kreifels', + 'Kuznetsov', + 'Matassa', + 'Mazanec', + 'Naegle', + 'Sphar', + 'Villaneda', + 'Wachholz', + 'Pastrano', + 'Pilotte', + 'Shedden', + 'Molt', + 'Dalia', + 'Bishara', + 'Dumoulin', + 'Dehnert', + 'Dilmore', + 'Termine', + 'Bracher', + 'Laplace', + 'Sherin', + 'Morine', + 'Garrott', + 'Banford', + 'Drumwright', + 'Linnen', + 'Belay', + 'Juste', + 'Moment', + 'Adamec', + 'Alessandrini', + 'Bolda', + 'Buonanno', + 'Corrow', + 'Couvillon', + 'Dahnke', + 'Durrani', + 'Errett', + 'Fingerhut', + 'Ittner', + 'Kandler', + 'Khosla', + 'Mascio', + 'Mesch', + 'Napolitan', + 'Packman', + 'Parady', + 'Saline', + 'Spatafore', + 'Squiers', + 'Stailey', + 'Stolar', + 'Strommen', + 'Vahey', + 'Vanbebber', + 'Wimpee', + 'Wolinsky', + 'Yambao', + 'Ciocca', + 'Fornwalt', + 'Giannattasio', + 'Herbers', + 'Korol', + 'Lindenberger', + 'Lysne', + 'Piacentini', + 'Vogeler', + 'Cassetta', + 'Hildebran', + 'Masoud', + 'Shiller', + 'Fisler', + 'Loll', + 'Wattles', + 'Carris', + 'Hippe', + 'Torregrossa', + 'Thain', + 'Enman', + 'Kanno', + 'Jeane', + 'Clendenning', + 'Halt', + 'Dorin', + 'Carnathan', + 'Bisch', + 'Simm', + 'Goatley', + 'July', + 'Oke', + 'Basley', + 'Dillahunt', + 'Times', + 'Mcglown', + 'Cohens', + 'Jeanphilippe', + 'Benshoof', + 'Bensing', + 'Bir', + 'Birnie', + 'Burklow', + 'Capili', + 'Cordts', + 'Falanga', + 'Farooqui', + 'Furber', + 'Godino', + 'Gollnick', + 'Harmening', + 'Hilpert', + 'Hrivnak', + 'Iribe', + 'Krienke', + 'Kuntzman', + 'Laslo', + 'Loso', + 'Omohundro', + 'Rabadi', + 'Reisenauer', + 'Rohrich', + 'Salak', + 'Schuckman', + 'Semmel', + 'Sendelbach', + 'Sidler', + 'Stegmann', + 'Sudbeck', + 'Tara', + 'Walcher', + 'Walkenhorst', + 'Wellbrock', + 'Capaldo', + 'Cotnoir', + 'Durrence', + 'Fralix', + 'Leibfried', + 'Schlarb', + 'Whitenight', + 'Grannan', + 'Mugford', + 'Filo', + 'Soh', + 'Deprez', + 'Semidey', + 'Vandivier', + 'Shawl', + 'Happy', + 'Gartley', + 'Jonathan', + 'Bouquet', + 'Warsaw', + 'Verne', + 'Furse', + 'Holms', + 'Bassette', + 'Fishburne', + 'Ambrosius', + 'Amrein', + 'Astorino', + 'Bedonie', + 'Bibee', + 'Brearley', + 'Chesher', + 'Colasurdo', + 'Deike', + 'Dimarino', + 'Felling', + 'Freid', + 'Gad', + 'Gambale', + 'Gieser', + 'Greff', + 'Halseth', + 'Hamor', + 'Hargens', + 'Hohenberger', + 'Hohler', + 'Illes', + 'Koscielniak', + 'Kotara', + 'Krygier', + 'Lopinto', + 'Mangas', + 'Mantione', + 'Mcendree', + 'Musich', + 'Nordling', + 'Panagopoulos', + 'Pollio', + 'Score', + 'Semaan', + 'Tortorelli', + 'Trabert', + 'Troung', + 'Vittorio', + 'Barkdoll', + 'Dombeck', + 'Ferriter', + 'Gancarz', + 'Gubbels', + 'Kertz', + 'Langenderfer', + 'Roppolo', + 'Siglin', + 'Trnka', + 'Vanderkooi', + 'Yaun', + 'Witkin', + 'Caryl', + 'Boies', + 'Carattini', + 'Hannes', + 'Harmison', + 'Mctavish', + 'Bille', + 'Sullivant', + 'Yeakey', + 'Respess', + 'Gooley', + 'Maura', + 'Jukes', + 'Oguin', + 'Demory', + 'Morson', + 'Hathorne', + 'Anklam', + 'Antaya', + 'Bentler', + 'Bettcher', + 'Bresette', + 'Broadrick', + 'Degante', + 'Demaray', + 'Dipinto', + 'Doberstein', + 'Dorminey', + 'Dorwart', + 'Gugliuzza', + 'Jesser', + 'Kjar', + 'Kujala', + 'Lemarr', + 'Lynds', + 'Novitsky', + 'Oropesa', + 'Scarpulla', + 'Schave', + 'Siravo', + 'Torma', + 'Uva', + 'Winkowski', + 'Boscia', + 'Buikema', + 'Byland', + 'Enneking', + 'Enstrom', + 'Gotsch', + 'Kulakowski', + 'Mattheis', + 'Niemuth', + 'Oberdorf', + 'Rabuck', + 'Shinners', + 'Struebing', + 'Dickes', + 'Hettrick', + 'Pille', + 'Vilar', + 'Blewitt', + 'Gutt', + 'Haseley', + 'Pennel', + 'Figuereo', + 'Lassalle', + 'Tannahill', + 'Teats', + 'Mumby', + 'Cheves', + 'Spark', + 'Ale', + 'Wally', + 'Lowndes', + 'Ballo', + 'Couper', + 'Alberta', + 'Puller', + 'Rochell', + 'Bachar', + 'Ballengee', + 'Bellizzi', + 'Boback', + 'Cammarano', + 'Dirr', + 'Findling', + 'Fruin', + 'Ghattas', + 'Kaliszewski', + 'Kammeyer', + 'Kwiecien', + 'Lamora', + 'Lehrke', + 'Macewen', + 'Nasta', + 'Neibert', + 'Ogaz', + 'Olesky', + 'Otano', + 'Prescher', + 'Romick', + 'Scibetta', + 'Slicker', + 'Ungerer', + 'Vanheel', + 'Wadas', + 'Weissert', + 'Armiger', + 'Brusca', + 'Christeson', + 'Crookshanks', + 'Demarinis', + 'Fahrney', + 'Heiple', + 'Howat', + 'Knoedler', + 'Kuske', + 'Leifheit', + 'Lukach', + 'Nauert', + 'Obremski', + 'Seidenberg', + 'Smigelski', + 'Visscher', + 'Wauneka', + 'Whitmoyer', + 'Wyand', + 'Ilardi', + 'Jackel', + 'Rackham', + 'Macgowan', + 'Braid', + 'Bringle', + 'Dirk', + 'Paci', + 'Wears', + 'Vanbergen', + 'Sidle', + 'Mellish', + 'Paino', + 'State', + 'Cargle', + 'Harcum', + 'Beyene', + 'Mwangi', + 'Anderle', + 'Cancienne', + 'Compeau', + 'Egle', + 'Farone', + 'Harke', + 'Hollopeter', + 'Jambor', + 'Jermyn', + 'Kadakia', + 'Kerker', + 'Langowski', + 'Lechman', + 'Nagengast', + 'Narvaiz', + 'Paola', + 'Partch', + 'Plucker', + 'Rawe', + 'Rohland', + 'Rosebrook', + 'Stanphill', + 'Stoltman', + 'Volkers', + 'Balingit', + 'Bausman', + 'Besler', + 'Dalto', + 'Edgren', + 'Hairfield', + 'Janek', + 'Kenoyer', + 'Koska', + 'Mihok', + 'Monjaraz', + 'Reisz', + 'Snedegar', + 'Vandezande', + 'Viscomi', + 'Kiene', + 'Dib', + 'Kuc', + 'Magley', + 'Swearingin', + 'Culliton', + 'Roome', + 'Fendrick', + 'Trindade', + 'Whaling', + 'Tarbutton', + 'Sider', + 'Swingler', + 'Lover', + 'Clarida', + 'Jocelyn', + 'Mervin', + 'Blaize', + 'Semper', + 'Bagsby', + 'Pree', + 'Dieujuste', + 'Anacleto', + 'Annable', + 'Bacci', + 'Bottari', + 'Cinco', + 'Delzell', + 'Dowless', + 'Drilling', + 'Egert', + 'Fanton', + 'Geerts', + 'Ghaffari', + 'Guggenheim', + 'Hankes', + 'Hediger', + 'Hornig', + 'Kauer', + 'Kossman', + 'Krasnow', + 'Lauman', + 'Lebsack', + 'Liendo', + 'Marhefka', + 'Noguez', + 'Oxman', + 'Pa', + 'Pella', + 'Pongratz', + 'Prisk', + 'Rajagopalan', + 'Rozo', + 'Vanvorst', + 'Wachob', + 'Avolio', + 'Banet', + 'Boissonneault', + 'Coglianese', + 'Crudele', + 'Dobratz', + 'Gerdts', + 'Koors', + 'Mazzanti', + 'Ozimek', + 'Vanhove', + 'Zern', + 'Kalama', + 'Mikelson', + 'Renehan', + 'Blecher', + 'Meath', + 'Bonus', + 'Wesch', + 'Kirkey', + 'Goldbeck', + 'Hun', + 'Morgans', + 'Strohman', + 'Lanagan', + 'Wyly', + 'Syers', + 'Berne', + 'Tondreau', + 'Witts', + 'Budhu', + 'Flott', + 'Alsbrooks', + 'Mabin', + 'Kingsberry', + 'Berend', + 'Brandeberry', + 'Carandang', + 'Ciavarella', + 'Foil', + 'Galano', + 'Garzia', + 'Golembeski', + 'Kossow', + 'Kren', + 'Lefave', + 'Macmahon', + 'Nilan', + 'Peregrina', + 'Pralle', + 'Sahakian', + 'Sarate', + 'Scalzi', + 'Soulliere', + 'Srock', + 'Stammen', + 'Sterry', + 'Tadych', + 'Trembath', + 'Watwood', + 'Wolske', + 'Woolson', + 'Aversano', + 'Chavana', + 'Digiuseppe', + 'Escano', + 'Harkrider', + 'Liebmann', + 'Soldan', + 'Swiatkowski', + 'Tomala', + 'Keay', + 'Lindstedt', + 'Maille', + 'Thurner', + 'Favia', + 'Guedes', + 'Simao', + 'Rambow', + 'Chriscoe', + 'Hiss', + 'Mcraney', + 'Barke', + 'Hobday', + 'Buri', + 'Sigle', + 'Bawa', + 'Lalande', + 'Bordon', + 'Friley', + 'Feild', + 'Arington', + 'Jons', + 'Funderburke', + 'Mccommons', + 'Troublefield', + 'Mable', + 'Hullum', + 'Wrice', + 'Cager', + 'Barse', + 'Braunschweig', + 'Dasch', + 'Fraioli', + 'Giefer', + 'Giovanniello', + 'Glahn', + 'Hatheway', + 'Holtrop', + 'Katsaros', + 'Koetting', + 'Malinoski', + 'Markov', + 'Mcclosky', + 'Mccormac', + 'Mertins', + 'Milito', + 'Mroczka', + 'Overdorf', + 'Palombi', + 'Peninger', + 'Provenza', + 'Quinnell', + 'Roady', + 'Ruthven', + 'Savitsky', + 'Shenefield', + 'Stapel', + 'Venkataraman', + 'Zachow', + 'Aaberg', + 'Bajorek', + 'Bankowski', + 'Barquero', + 'Delcamp', + 'Deshler', + 'Halili', + 'Hebenstreit', + 'Hirota', + 'Hladky', + 'Kliethermes', + 'Koestner', + 'Kroes', + 'Luepke', + 'Mckeough', + 'Mielcarek', + 'Nobis', + 'Olenik', + 'Plessinger', + 'Shillingburg', + 'Spadaccini', + 'Springborn', + 'Werden', + 'Willenbring', + 'Zyskowski', + 'Paucar', + 'Werst', + 'Wohlwend', + 'Nauss', + 'Alma', + 'Tebeau', + 'Paskett', + 'Spindle', + 'Twiddy', + 'Alomar', + 'Mi', + 'Billard', + 'Bails', + 'Channer', + 'Fripp', + 'Abreo', + 'Adamowicz', + 'Bocian', + 'Breden', + 'Breitkreutz', + 'Celona', + 'Chizek', + 'Chrestman', + 'Ciaramella', + 'Compher', + 'Crannell', + 'Dermer', + 'Duryee', + 'Feuerborn', + 'Garrels', + 'Gausman', + 'Grippi', + 'Guadamuz', + 'Hatlestad', + 'Heon', + 'Hokenson', + 'Kaden', + 'Kluever', + 'Lagares', + 'Mamone', + 'Mascola', + 'Matich', + 'Messimer', + 'Mezera', + 'Mongiello', + 'Moradi', + 'Nessler', + 'Nijjar', + 'Nin', + 'Pasquarelli', + 'Pawlowicz', + 'Petitto', + 'Petruccelli', + 'Pullano', + 'Rebar', + 'Romack', + 'Rosener', + 'Soland', + 'Solow', + 'Vandervelden', + 'Vazguez', + 'Vonruden', + 'Balmes', + 'Berninger', + 'Broecker', + 'Clogston', + 'Fontanella', + 'Gubbins', + 'Kampen', + 'Levenhagen', + 'Lyter', + 'Nagamine', + 'Regas', + 'Riecke', + 'Veltre', + 'Wojahn', + 'Angelino', + 'Mccomber', + 'Grisso', + 'Saran', + 'Pecore', + 'Sorter', + 'Encalada', + 'Robart', + 'Deerman', + 'Lori', + 'Mcnee', + 'Dagher', + 'Villars', + 'Chaplain', + 'Houtman', + 'Dingwall', + 'Akerson', + 'Donaway', + 'Dimmer', + 'Mittman', + 'Camm', + 'Kenedy', + 'Bilbro', + 'Brocks', + 'Mansaray', + 'Acebo', + 'Ahr', + 'Alayon', + 'Benyo', + 'Blatnik', + 'Degidio', + 'Dumire', + 'Elefante', + 'Gase', + 'Gilboy', + 'Gradillas', + 'Haverstock', + 'Heberle', + 'Hilmes', + 'Hjort', + 'Johnsey', + 'Lambiase', + 'Marland', + 'Mcevilly', + 'Mergenthaler', + 'Mini', + 'Noska', + 'Patrie', + 'Rohrback', + 'Seelbach', + 'Stopher', + 'Trzaska', + 'Vanessen', + 'Veillette', + 'Walizer', + 'Zapalac', + 'Andalon', + 'Beukema', + 'Cieslik', + 'Dukart', + 'Gerads', + 'Gilhooly', + 'Hinebaugh', + 'Jumonville', + 'Macchi', + 'Oldenkamp', + 'Plotz', + 'Robideau', + 'Streed', + 'Trochez', + 'Grames', + 'Beltram', + 'Fishbaugh', + 'Lais', + 'Ossa', + 'Wilden', + 'Erick', + 'Dosier', + 'Trust', + 'Swaine', + 'Darity', + 'Mccroy', + 'Yuille', + 'Cantave', + 'Barsanti', + 'Carbonara', + 'Cavanah', + 'Chrismer', + 'Cuestas', + 'Czaplewski', + 'Denes', + 'Dorio', + 'Geraldo', + 'Giebler', + 'Goewey', + 'Gorniak', + 'Grabe', + 'Guidera', + 'Hannig', + 'Herin', + 'Kadow', + 'Klauer', + 'Kleppinger', + 'Lerro', + 'Manoogian', + 'Mentzel', + 'Muramoto', + 'Ollinger', + 'Pacey', + 'Pufahl', + 'Quero', + 'Revuelta', + 'Rickles', + 'Rudie', + 'Ruggerio', + 'Salberg', + 'Schwoerer', + 'Stephani', + 'Stevick', + 'Strada', + 'Thorley', + 'Thrun', + 'Virts', + 'Wingett', + 'Balfe', + 'Branaman', + 'Brookshier', + 'Carlsson', + 'Chismar', + 'Habben', + 'Migdal', + 'Ozga', + 'Rivest', + 'Russman', + 'Schellhorn', + 'Staup', + 'Pietri', + 'Welby', + 'Cisney', + 'Hijazi', + 'Brines', + 'Calderin', + 'Mudrick', + 'Domine', + 'Parlow', + 'Ervine', + 'Banis', + 'Mathenia', + 'Carbin', + 'Rashed', + 'Mcgilvery', + 'Prichett', + 'Feimster', + 'Smoots', + 'Persley', + 'Desire', + 'Abadi', + 'Bercaw', + 'Bertz', + 'Bibian', + 'Brosious', + 'Brunken', + 'Calvano', + 'Chenette', + 'Chiusano', + 'Dendinger', + 'Diffley', + 'Eichenberg', + 'Gawne', + 'Gelardi', + 'Gottman', + 'Gulyas', + 'Hak', + 'Haydock', + 'Hettler', + 'Hinsch', + 'Kozlik', + 'Krebbs', + 'Krichbaum', + 'Loges', + 'Lyssy', + 'Mitnick', + 'Podolski', + 'Priego', + 'Radhakrishnan', + 'Reineck', + 'Ruggirello', + 'Samborski', + 'Schwalb', + 'Sitek', + 'Sprinkel', + 'Tkachuk', + 'Viscuso', + 'Working', + 'Zinner', + 'Anspaugh', + 'Anthes', + 'Bratsch', + 'Breining', + 'Cejka', + 'Delbuono', + 'Hugill', + 'Huyett', + 'Irlbeck', + 'Kilgus', + 'Langwell', + 'Margulis', + 'Meara', + 'Napierala', + 'Stanaway', + 'Worton', + 'Gaucher', + 'Bakeman', + 'Pasos', + 'Feazel', + 'Evitt', + 'Marrin', + 'Baskette', + 'Orne', + 'Ivens', + 'Burnstein', + 'Rodell', + 'Bowell', + 'Maraj', + 'Lango', + 'Boudoin', + 'Wider', + 'Walkins', + 'Raheem', + 'Talford', + 'Jeanmarie', + 'Drumgoole', + 'Arnot', + 'Bennick', + 'Buchinger', + 'Cleven', + 'Corsello', + 'Delucchi', + 'Dicocco', + 'Eachus', + 'Eilts', + 'Fandino', + 'Fyke', + 'Giammarco', + 'Gwartney', + 'Hawken', + 'Henkelman', + 'Jaggi', + 'Jurczyk', + 'Kamman', + 'Kattner', + 'Keator', + 'Klus', + 'Leidner', + 'Ligas', + 'Martus', + 'Maslow', + 'Piccinini', + 'Pysher', + 'Riga', + 'Siek', + 'Sizelove', + 'Vanostrand', + 'Vastine', + 'Viviani', + 'Youngerman', + 'Zahniser', + 'Brigante', + 'Burklund', + 'Cajina', + 'Coppolino', + 'Goytia', + 'Icenhower', + 'Ihnen', + 'Jablonsky', + 'Koepsell', + 'Mennenga', + 'Redenius', + 'Tengan', + 'Weishaupt', + 'Dorst', + 'Kief', + 'Busk', + 'Luba', + 'Quine', + 'Deshotels', + 'Roulston', + 'Diniz', + 'Chandley', + 'Saleeby', + 'Maro', + 'Faidley', + 'Burrous', + 'Ilyas', + 'Roster', + 'Clovis', + 'Bacot', + 'Pembleton', + 'Bellot', + 'Entzminger', + 'Ryce', + 'Posley', + 'Alvi', + 'Audino', + 'Bitters', + 'Boomershine', + 'Boyack', + 'Branda', + 'Bresnan', + 'Brusco', + 'Bunda', + 'Catanzarite', + 'Dohmen', + 'Elbaum', + 'Farago', + 'Ferrentino', + 'Gimpel', + 'Grzeskowiak', + 'Gutting', + 'Henandez', + 'Herbeck', + 'Hoben', + 'Hunnell', + 'Ibbotson', + 'Kida', + 'Kirchman', + 'Kubin', + 'Laplume', + 'Laskin', + 'Lefferts', + 'Leimer', + 'Locatelli', + 'Pitsenbarger', + 'Reum', + 'Rittgers', + 'Scadden', + 'Shammas', + 'Tatge', + 'Tiongson', + 'Wengler', + 'Wenrick', + 'Wortley', + 'Bretado', + 'Detloff', + 'Dlugosz', + 'Eisemann', + 'Embler', + 'Graffius', + 'Kienast', + 'Kucher', + 'Larew', + 'Lemmerman', + 'Maners', + 'Peckinpaugh', + 'Rupnow', + 'Schubring', + 'Staheli', + 'Stege', + 'Talwar', + 'Truszkowski', + 'Coda', + 'Comunale', + 'Holtry', + 'Newfield', + 'Blankley', + 'Devino', + 'Wahba', + 'Cathell', + 'Timson', + 'Setzler', + 'Shacklett', + 'Nicols', + 'Rocque', + 'Nest', + 'Freelove', + 'Neat', + 'Kina', + 'Caslin', + 'Creal', + 'Wyre', + 'Compere', + 'Brisker', + 'Givhan', + 'Menifee', + 'Hymon', + 'Boakye', + 'Aguillar', + 'Alpern', + 'Antico', + 'Attridge', + 'Bjorge', + 'Bordwell', + 'Brumbach', + 'Castronova', + 'Cowher', + 'Fakhouri', + 'Hanigan', + 'Heidecker', + 'Hosick', + 'Lorang', + 'Magadan', + 'Marovich', + 'Masur', + 'Nienow', + 'Passow', + 'Priola', + 'Prose', + 'Radillo', + 'Saracco', + 'Schlender', + 'Sellards', + 'Stirn', + 'Strathman', + 'Supan', + 'Taguchi', + 'Tufte', + 'Vanderleest', + 'Vanderpoel', + 'Vondra', + 'Wayment', + 'Wisinski', + 'Brodowski', + 'Cichowski', + 'Delarocha', + 'Demyan', + 'Dobies', + 'Hegner', + 'Karapetian', + 'Konieczka', + 'Lazarz', + 'Loughner', + 'Portanova', + 'Rosentreter', + 'Rothlisberger', + 'Schropp', + 'Trenkamp', + 'Flaharty', + 'Murfin', + 'Waner', + 'Baiz', + 'Dunegan', + 'Gillson', + 'Erne', + 'Mahin', + 'Hardgrave', + 'Felps', + 'Bevens', + 'Abdou', + 'Songy', + 'Boule', + 'Wisham', + 'Devonshire', + 'Havis', + 'Relf', + 'Pean', + 'Manago', + 'Brazzle', + 'Mckelvin', + 'Goulbourne', + 'Pinkins', + 'Yelder', + 'Akina', + 'Allerton', + 'Aminov', + 'Barsamian', + 'Biondolillo', + 'Bouchillon', + 'Bustle', + 'Dolney', + 'Dunkerley', + 'Farha', + 'Floor', + 'Gaustad', + 'Gilberti', + 'Helder', + 'Kolber', + 'Kuznia', + 'Longhi', + 'Mamaril', + 'Milhorn', + 'Mozo', + 'Norbury', + 'Okano', + 'Perkovich', + 'Rafanan', + 'Rulo', + 'Ruperto', + 'Scow', + 'Shadoan', + 'Smisek', + 'Steinfeldt', + 'Thobe', + 'Venturino', + 'Widell', + 'Broccoli', + 'Helmig', + 'Koegler', + 'Lewandoski', + 'Pequignot', + 'Radermacher', + 'Resetar', + 'Rostro', + 'Sebald', + 'Walgren', + 'Lottes', + 'Capraro', + 'Grine', + 'Gordner', + 'Crus', + 'Easom', + 'Bayle', + 'Barts', + 'Duguid', + 'Estel', + 'Peggs', + 'Cheaney', + 'Rossin', + 'Mackel', + 'Vassel', + 'Fils', + 'Senat', + 'Alarie', + 'Allar', + 'Brownlie', + 'Bumbaugh', + 'Caissie', + 'Cordone', + 'Critser', + 'Delconte', + 'Falzon', + 'Formosa', + 'Frerking', + 'Gadea', + 'Ganem', + 'Guzek', + 'Hauch', + 'Heese', + 'Hemmen', + 'Holzschuh', + 'Impson', + 'Jablon', + 'Kiedrowski', + 'Krob', + 'Kuhnle', + 'Laake', + 'Larouche', + 'Leaton', + 'Leyland', + 'Lorenson', + 'Macduff', + 'Maready', + 'Newberger', + 'Ohnstad', + 'Pinela', + 'Polino', + 'Postema', + 'Pyon', + 'Radziewicz', + 'Rathod', + 'Salopek', + 'Salvadore', + 'Sawchuk', + 'Trotto', + 'Vereb', + 'Auslander', + 'Beninati', + 'Blunck', + 'Decandia', + 'Deeney', + 'Escatel', + 'Foskett', + 'Hagmann', + 'Hussar', + 'Jakubek', + 'Kluender', + 'Mcelhinny', + 'Salatino', + 'Sangalang', + 'Schoenfeldt', + 'Stogdill', + 'Svitak', + 'Taravella', + 'Tezak', + 'Wieseler', + 'Komperda', + 'Reinitz', + 'Malis', + 'Duce', + 'Salib', + 'Keelin', + 'Labell', + 'Symmonds', + 'Gwynne', + 'Byus', + 'Burgy', + 'Delfosse', + 'Benskin', + 'Hedgepath', + 'Ursin', + 'Kinnebrew', + 'Tinnon', + 'Callum', + 'Allah', + 'Arduini', + 'Azucena', + 'Birkel', + 'Bowermaster', + 'Caires', + 'Chrobak', + 'Cottier', + 'Cropley', + 'Crotteau', + 'Dutan', + 'Ezernack', + 'Fabiani', + 'Fauser', + 'Feeny', + 'Ferdig', + 'Fliss', + 'Gallus', + 'Harlacher', + 'Hasselbach', + 'Honsinger', + 'Landberg', + 'Lohn', + 'Losinski', + 'Maung', + 'Melikian', + 'Nooney', + 'Oyervides', + 'Prum', + 'Riepe', + 'Seebach', + 'Sendejas', + 'Sprick', + 'Torino', + 'Weida', + 'Geschke', + 'Girgenti', + 'Klever', + 'Rathert', + 'Roszell', + 'Sarich', + 'Shimmin', + 'Trimpe', + 'Turrubiates', + 'Zelada', + 'Danzig', + 'Diamant', + 'Hannen', + 'Odland', + 'Puzzo', + 'Slyter', + 'Smaldone', + 'Ebey', + 'Beg', + 'Magel', + 'Tebbs', + 'Gali', + 'Winney', + 'Juba', + 'Stargel', + 'Waren', + 'Stann', + 'Ducasse', + 'Vaugh', + 'Lewers', + 'Stjuste', + 'Heckstall', + 'Bokhari', + 'Bonino', + 'Brummond', + 'Caterino', + 'Deatrick', + 'Decorte', + 'Demara', + 'Dubree', + 'Dulski', + 'Feck', + 'Foglio', + 'Heinzelman', + 'Jory', + 'Knoell', + 'Kronick', + 'Maclay', + 'Mastrogiovanni', + 'Reichling', + 'Rueff', + 'Sellitto', + 'Sensing', + 'Sheu', + 'Soberanes', + 'Stahlecker', + 'Wholey', + 'Yochim', + 'Zeiss', + 'Bojanowski', + 'Bonawitz', + 'Caporaso', + 'Dalesio', + 'Exposito', + 'Giovinazzo', + 'Palardy', + 'Rastogi', + 'Saenger', + 'Sirek', + 'Sonoda', + 'Sovereign', + 'Weimann', + 'Wirtanen', + 'Enerson', + 'Olliff', + 'Kallam', + 'Leggitt', + 'Goude', + 'Rampey', + 'Letsinger', + 'Walles', + 'Kater', + 'Betsill', + 'Creese', + 'Lisbon', + 'Abitz', + 'Bednarik', + 'Bendorf', + 'Berkovich', + 'Brevik', + 'Cassatt', + 'Ciarlo', + 'Cookman', + 'Cosma', + 'Defee', + 'Essner', + 'Fallas', + 'Holda', + 'Kemler', + 'Kovich', + 'Krimmel', + 'Landauer', + 'Meharg', + 'Moncus', + 'Nabi', + 'Redenbaugh', + 'Ruwe', + 'Scalisi', + 'Shughart', + 'Sloma', + 'Sovine', + 'Tomaso', + 'Trueba', + 'Urista', + 'Vanyo', + 'Wolanski', + 'Zettle', + 'Arvanitis', + 'Baeten', + 'Caponi', + 'Carrazco', + 'Galambos', + 'Hartsook', + 'Helseth', + 'Kobylarz', + 'Krugh', + 'Meckel', + 'Ohnemus', + 'Voytek', + 'Winegarden', + 'Zuba', + 'Piloto', + 'Shames', + 'Debella', + 'Keddy', + 'Perra', + 'Winks', + 'Hemrick', + 'Snowdon', + 'Cleere', + 'Leavey', + 'Courington', + 'Herson', + 'Nelon', + 'Bloise', + 'Mcphie', + 'Catledge', + 'Mcneary', + 'Hoffler', + 'Suell', + 'Coard', + 'Woolfork', + 'Biros', + 'Brouhard', + 'Dinovo', + 'Disano', + 'Emami', + 'Flegal', + 'Hardebeck', + 'Hobin', + 'Huttner', + 'Kloosterman', + 'Knutzen', + 'Kopinski', + 'Mailman', + 'Mankey', + 'Mccamish', + 'Mccorquodale', + 'Minichiello', + 'Miyasaki', + 'Osher', + 'Prutzman', + 'Sagen', + 'Shawgo', + 'Sokolow', + 'Southam', + 'Sulik', + 'Wiedel', + 'Wollschlager', + 'Cantalupo', + 'Cruser', + 'Denomme', + 'Dinardi', + 'Donahey', + 'Havlin', + 'Lasecki', + 'Margraf', + 'Mchaffie', + 'Mihaly', + 'Omlor', + 'Roope', + 'Schremp', + 'Vanhecke', + 'Washabaugh', + 'Zaunbrecher', + 'Joost', + 'Pensinger', + 'Kraner', + 'Mikles', + 'Delair', + 'Bukhari', + 'Earll', + 'Sans', + 'Gatliff', + 'Casteneda', + 'Shalom', + 'Fidalgo', + 'Leitao', + 'Degrange', + 'Fruits', + 'Kercheval', + 'Mew', + 'Chopin', + 'Seawood', + 'Agro', + 'Aliano', + 'Badour', + 'Betsch', + 'Buchbinder', + 'Cleavenger', + 'Collazos', + 'Cusmano', + 'Dienes', + 'Dittus', + 'Eggenberger', + 'Fierst', + 'Gingell', + 'Greever', + 'Grisales', + 'Hegstrom', + 'Justen', + 'Kalt', + 'Kirkhart', + 'Krage', + 'Kyzar', + 'Livolsi', + 'Neyhart', + 'Nunziata', + 'Orlich', + 'Parcel', + 'Peshlakai', + 'Schemm', + 'Segner', + 'Urieta', + 'Wolfman', + 'Coonradt', + 'Disilvestro', + 'Dobrowski', + 'Gramza', + 'Kotlyar', + 'Micka', + 'Miksch', + 'Mione', + 'Montone', + 'Palmerton', + 'Parrill', + 'Passafiume', + 'Rosoff', + 'Spaziani', + 'Venditto', + 'Wisch', + 'Fini', + 'Horky', + 'Perel', + 'Arzuaga', + 'Nasworthy', + 'Carland', + 'Elden', + 'Moises', + 'Maione', + 'Glace', + 'Laverdure', + 'Sieh', + 'Toulouse', + 'Hannam', + 'Cumber', + 'Rendell', + 'Hardey', + 'Maddison', + 'Brittle', + 'Helen', + 'Aina', + 'Allwood', + 'Fenty', + 'Herard', + 'Traore', + 'Ator', + 'Bedsaul', + 'Bickert', + 'Brendlinger', + 'Camuso', + 'Dutter', + 'Eastlick', + 'Fernholz', + 'Guza', + 'Heitzenrater', + 'Huo', + 'Isbill', + 'Katzenstein', + 'Keigley', + 'Kelnhofer', + 'Klarich', + 'Mangat', + 'Mathiason', + 'Murzyn', + 'Odenthal', + 'Pascarelli', + 'Passwaters', + 'Rotunda', + 'Schons', + 'Sein', + 'Sobon', + 'Stayner', + 'Tri', + 'Uhlir', + 'Viscusi', + 'Winstanley', + 'Xi', + 'Yodice', + 'Aerts', + 'Antosh', + 'Baldinger', + 'Brislin', + 'Christopoulos', + 'Faurot', + 'Fusselman', + 'Hamsher', + 'Henckel', + 'Macht', + 'Moellering', + 'Oclair', + 'Pavelko', + 'Poehlman', + 'Rajewski', + 'Richcreek', + 'Schmeichel', + 'Venkatesh', + 'Zemba', + 'Zuelke', + 'Dechellis', + 'Reddig', + 'Splain', + 'Claw', + 'Mottram', + 'Crise', + 'Villaflor', + 'Allocca', + 'Buttrum', + 'Cocking', + 'Mundie', + 'Tavis', + 'Saidi', + 'Latter', + 'Tuberville', + 'Spease', + 'Leatherberry', + 'Peatross', + 'Claridy', + 'Duerson', + 'Durley', + 'Mekonnen', + 'Thiam', + 'Aderman', + 'Al', + 'Andreu', + 'Beine', + 'Bowron', + 'Campi', + 'Chura', + 'Ciraulo', + 'Daywalt', + 'Fleek', + 'Friant', + 'Gahm', + 'Gongaware', + 'Grosh', + 'Heaslip', + 'Knape', + 'Kravets', + 'Kritikos', + 'Kumagai', + 'Kustra', + 'Madani', + 'Mich', + 'Norlander', + 'Paulhus', + 'Rabanal', + 'Saker', + 'Stupak', + 'Suchomel', + 'Vandenberghe', + 'Wehrenberg', + 'Zaccardi', + 'Davlin', + 'Dykhouse', + 'Grandfield', + 'Hullender', + 'Kallis', + 'Livshits', + 'Rihn', + 'Criger', + 'Michl', + 'Tutino', + 'Zulueta', + 'Cristo', + 'Meline', + 'Fetch', + 'Dung', + 'Shami', + 'Teale', + 'Cocker', + 'Eshbach', + 'Phagan', + 'Millea', + 'Tayloe', + 'Olivia', + 'Houchen', + 'Peddy', + 'Ferryman', + 'Boodram', + 'Maduro', + 'Fullman', + 'Landingham', + 'Pee', + 'Argenbright', + 'Aronowitz', + 'Baldenegro', + 'Barentine', + 'Bernasconi', + 'Bicking', + 'Bohle', + 'Camerer', + 'Dufford', + 'Ende', + 'Gessel', + 'Grauman', + 'Jaqua', + 'Kagawa', + 'Kalinski', + 'Kanz', + 'Klasen', + 'Koloski', + 'Kriete', + 'Litalien', + 'Maish', + 'Massar', + 'Muraski', + 'Pickelsimer', + 'Sagraves', + 'Servellon', + 'Shellito', + 'Shiveley', + 'Stanislaw', + 'Volland', + 'Biehle', + 'Cruey', + 'Eagar', + 'Ermis', + 'Goracke', + 'Mackert', + 'Malloch', + 'Merillat', + 'Rylee', + 'Schelin', + 'Tibbals', + 'Zandi', + 'Golde', + 'Steuart', + 'Jamie', + 'Lavis', + 'Bromwell', + 'Tregre', + 'Alkhatib', + 'Carvey', + 'Essa', + 'Wale', + 'Mccarey', + 'Brandley', + 'Hermon', + 'Stenhouse', + 'Oguinn', + 'Barclift', + 'Sylvan', + 'Smyre', + 'Ellerby', + 'Alemany', + 'Beyl', + 'Boven', + 'Bultema', + 'Buzan', + 'Cappo', + 'Cottongim', + 'Detore', + 'Dierolf', + 'Dueck', + 'Egelston', + 'Emard', + 'Eveleth', + 'Ferrini', + 'Fodera', + 'Hidy', + 'Kahley', + 'Karasik', + 'Klare', + 'Koudelka', + 'Lafleche', + 'Minturn', + 'Montemarano', + 'Plock', + 'Ratterman', + 'Reingold', + 'Rieber', + 'Schnackenberg', + 'Schrade', + 'Steffek', + 'Stehling', + 'Sticha', + 'Velaquez', + 'Weissberg', + 'Allnutt', + 'Barkhurst', + 'Bettendorf', + 'Canonico', + 'Deshmukh', + 'Dobosz', + 'Glab', + 'Kirkeby', + 'Menapace', + 'Parizek', + 'Pursifull', + 'Ragucci', + 'Raisch', + 'Schronce', + 'Tuason', + 'Duross', + 'Hainer', + 'Kinnick', + 'Rens', + 'Williamsen', + 'Hilke', + 'Hark', + 'Mellett', + 'Decarvalho', + 'Filyaw', + 'Sian', + 'Mccard', + 'Symon', + 'Grade', + 'Giboney', + 'Sadik', + 'Caul', + 'Gater', + 'Sulton', + 'Dungee', + 'Adriance', + 'Almas', + 'Andler', + 'Bellina', + 'Belshe', + 'Blouch', + 'Bradeen', + 'Brandwein', + 'Buechele', + 'Cristina', + 'Davidov', + 'Defiore', + 'Defrain', + 'Derasmo', + 'Dober', + 'Grosshans', + 'Hoek', + 'Hofstad', + 'Ingman', + 'Kille', + 'Langill', + 'Matic', + 'Niederer', + 'Novella', + 'Oelkers', + 'Percifield', + 'Phariss', + 'Pola', + 'Pompei', + 'Potthast', + 'Raden', + 'Radick', + 'Rendina', + 'Sicotte', + 'Sleep', + 'Wadhwa', + 'Buccheri', + 'Calogero', + 'Catrett', + 'Flemmer', + 'Mancinas', + 'Mcmichen', + 'Measel', + 'Pudlo', + 'Ruether', + 'Shusterman', + 'Stabley', + 'Teffeteller', + 'Waisanen', + 'Zappulla', + 'Symanski', + 'Mckenrick', + 'Moger', + 'Obispo', + 'Armenteros', + 'Roses', + 'Makki', + 'Faley', + 'Rumford', + 'Schonberg', + 'Hizer', + 'Blaydes', + 'Coor', + 'Mccalip', + 'Stancill', + 'Cal', + 'Murat', + 'Amie', + 'Placide', + 'Akpan', + 'Bembenek', + 'Bilyk', + 'Bizzarro', + 'Bugge', + 'Cunnane', + 'Degenhart', + 'Doehring', + 'Flammia', + 'Fritcher', + 'Godinho', + 'Gouger', + 'Heyboer', + 'Humenik', + 'Iannaccone', + 'Lacivita', + 'Lagunes', + 'Leitzke', + 'Luty', + 'Maute', + 'Micke', + 'Midura', + 'Nydam', + 'Rasp', + 'Rediker', + 'Requejo', + 'Roskos', + 'Ruckert', + 'Saldierna', + 'Salemme', + 'Tsuchiya', + 'Vallas', + 'Werder', + 'Arenivas', + 'Bartholomay', + 'Brozowski', + 'Dusza', + 'Frevert', + 'Giannopoulos', + 'Kormos', + 'Martos', + 'Mollenhauer', + 'Romanek', + 'Solinger', + 'Tomaro', + 'Zangara', + 'Buttrick', + 'Pardy', + 'Alvelo', + 'Breth', + 'Hemond', + 'Kayes', + 'Manne', + 'Grandchamp', + 'Gilbo', + 'Calame', + 'Clippard', + 'Gieger', + 'Penalver', + 'Ecton', + 'Totton', + 'Poyser', + 'Kettles', + 'Hosang', + 'Waker', + 'Maryland', + 'Girma', + 'Baribeau', + 'Boehnke', + 'Brunick', + 'Buhrow', + 'Cerreta', + 'Dascoli', + 'Eroh', + 'Fallert', + 'Fotopoulos', + 'Granholm', + 'Hebdon', + 'Hoelzer', + 'Hyser', + 'Lisanti', + 'Mastrianni', + 'Mewes', + 'Mulanax', + 'Nikolai', + 'Odekirk', + 'Ofallon', + 'Onnen', + 'Or', + 'Osso', + 'Ridpath', + 'Schara', + 'Schnipke', + 'Slayter', + 'Sodhi', + 'Steffler', + 'Stegemann', + 'Weisensel', + 'Bertling', + 'Dueitt', + 'Keehner', + 'Khaimov', + 'Kramlich', + 'Salkeld', + 'Ulbricht', + 'Vultaggio', + 'Dennin', + 'Mondo', + 'Kett', + 'Dom', + 'Kalan', + 'Yaney', + 'Nicley', + 'Carabello', + 'Ellegood', + 'Mcglocklin', + 'Figuero', + 'Pillard', + 'Wolfrey', + 'Leys', + 'Cobert', + 'Wahid', + 'Fede', + 'Ausbrooks', + 'Gums', + 'Gillion', + 'Mcgeachy', + 'Parran', + 'Likely', + 'Marbley', + 'Argote', + 'Bhullar', + 'Botros', + 'Brethauer', + 'Chell', + 'Conradi', + 'Covill', + 'Crays', + 'Crysler', + 'Handke', + 'Hanneken', + 'Hidrogo', + 'Hirayama', + 'Huebert', + 'Hurford', + 'Iskra', + 'Malczewski', + 'Menees', + 'Monforte', + 'Murdick', + 'Naclerio', + 'Nohr', + 'Pangallo', + 'Payeur', + 'Pozniak', + 'Rammel', + 'Schield', + 'Schrick', + 'Seifer', + 'Sperduto', + 'Stagliano', + 'Staubs', + 'Stromme', + 'Tourigny', + 'Traister', + 'Vandecar', + 'Wilhelms', + 'Wilinski', + 'Wittke', + 'Clougherty', + 'Crotwell', + 'Hannula', + 'Heavrin', + 'Heidinger', + 'Keehan', + 'Ortwein', + 'Palinkas', + 'Seivert', + 'Sloniker', + 'Yielding', + 'Lac', + 'Shove', + 'Venard', + 'Violett', + 'Foresta', + 'Gapp', + 'Dejongh', + 'Ambrosia', + 'Simkin', + 'Sastre', + 'Mcarthy', + 'Bering', + 'Sarah', + 'Hickling', + 'Sookdeo', + 'Val', + 'Colden', + 'Feltus', + 'Hailes', + 'Canizalez', + 'Cloke', + 'Connole', + 'Dancel', + 'Demmon', + 'Ehrler', + 'Fruchey', + 'Helinski', + 'Hepfer', + 'Katzen', + 'Kressler', + 'Lagrow', + 'Nethercutt', + 'Novitski', + 'Papale', + 'Pesola', + 'Petrosian', + 'Pies', + 'Prazak', + 'Preza', + 'Reiche', + 'Salle', + 'Savic', + 'Servello', + 'Sherbondy', + 'Solazzo', + 'Stabenow', + 'Walstad', + 'Yaden', + 'Zagal', + 'Zani', + 'Dimambro', + 'Engquist', + 'Fochtman', + 'Frasch', + 'Fuerstenberg', + 'Galus', + 'Gronowski', + 'Grossenbacher', + 'Hahs', + 'Iavarone', + 'Kerper', + 'Kravchenko', + 'Kwolek', + 'Lusignan', + 'Lybbert', + 'Maertens', + 'Mahany', + 'Medico', + 'Orrantia', + 'Reitmeier', + 'Sieve', + 'Sterbenz', + 'Tenpas', + 'Wischmeyer', + 'Zajkowski', + 'Cregg', + 'Shetley', + 'Tisher', + 'Coup', + 'Murdy', + 'Lysaght', + 'Sesco', + 'Koy', + 'Wakley', + 'Bertholf', + 'Swaner', + 'Stakes', + 'Gren', + 'Elahi', + 'Torney', + 'Gopaul', + 'Egland', + 'Gingles', + 'Aurich', + 'Biela', + 'Binz', + 'Blumenstock', + 'Boardwine', + 'Boehner', + 'Boening', + 'Crankshaw', + 'Decarli', + 'Fauble', + 'Georgopoulos', + 'Gieske', + 'Hasselbring', + 'Heeb', + 'Janosik', + 'Kalafut', + 'Karpf', + 'Kramm', + 'Lanyon', + 'Lewelling', + 'Lilla', + 'Marik', + 'Moyano', + 'Oppel', + 'Panagos', + 'Renovato', + 'Rohlman', + 'Rostron', + 'Todhunter', + 'Torello', + 'Umfleet', + 'Wien', + 'Youker', + 'Ytuarte', + 'Zavada', + 'Altvater', + 'Arnzen', + 'Blixt', + 'Elek', + 'Geiselman', + 'Hiltunen', + 'Jachim', + 'Kolenovic', + 'Kooyman', + 'Muecke', + 'Pierron', + 'Preisler', + 'Rogus', + 'Schoeller', + 'Solimine', + 'Speagle', + 'Courser', + 'Mascarenhas', + 'Dorer', + 'Scotten', + 'Goy', + 'Avers', + 'Blanca', + 'Choung', + 'Goleman', + 'Nanna', + 'Lave', + 'Seley', + 'Meggison', + 'Ripoll', + 'Mannan', + 'Bihm', + 'Tribbey', + 'Ports', + 'Asby', + 'Philibert', + 'Furby', + 'Keal', + 'Louallen', + 'Idris', + 'Artist', + 'Branford', + 'Sabree', + 'Ainley', + 'Amezola', + 'Andreason', + 'Athans', + 'Batiz', + 'Bostelman', + 'Bozic', + 'Butman', + 'Coiro', + 'Defina', + 'Garbo', + 'Gewirtz', + 'Hathcoat', + 'Heebner', + 'Helbing', + 'Kasler', + 'Kastler', + 'Kearby', + 'Krus', + 'Lezotte', + 'Lithgow', + 'Mealor', + 'Moltz', + 'Morcom', + 'Norbeck', + 'Novicki', + 'Osmani', + 'Posluszny', + 'Quiroa', + 'Rahal', + 'Roddenberry', + 'Rodino', + 'Sallade', + 'Saraceni', + 'Schmaus', + 'Stathopoulos', + 'Swatek', + 'Tupy', + 'Vonseggern', + 'Zens', + 'Ahonen', + 'Arrazola', + 'Avedisian', + 'Bachtell', + 'Bastarache', + 'Chavero', + 'Darienzo', + 'Giampa', + 'Gillott', + 'Hierholzer', + 'Kruckeberg', + 'Lafrenz', + 'Milkowski', + 'Missildine', + 'Passaretti', + 'Rogstad', + 'Saadeh', + 'Sielski', + 'Slavick', + 'Tieken', + 'Wittenmyer', + 'Yepiz', + 'Zimdars', + 'Rail', + 'Kook', + 'Jian', + 'Piet', + 'Sanjurjo', + 'Shampine', + 'Christel', + 'Hechavarria', + 'Blucher', + 'Crimm', + 'Lebreton', + 'Charbonnet', + 'Bolls', + 'Stroder', + 'Baise', + 'Mcnease', + 'Alen', + 'Priestly', + 'Mannie', + 'Doleman', + 'Areas', + 'Atayde', + 'Berent', + 'Bodmer', + 'Brodin', + 'Buntrock', + 'Eckrich', + 'Emberson', + 'Hilgert', + 'Hirn', + 'Holihan', + 'Hoshino', + 'Jeung', + 'Leece', + 'Leonardis', + 'Macera', + 'Mcferron', + 'Muster', + 'Naef', + 'Pecka', + 'Peloso', + 'Pensyl', + 'Reaney', + 'Reidinger', + 'Rockholt', + 'Tabrizi', + 'Trauth', + 'Trulock', + 'Tupou', + 'Asbridge', + 'Franzel', + 'Gesualdi', + 'Grimwood', + 'Hardinger', + 'Kondrat', + 'Koskinen', + 'Ludolph', + 'Marchesi', + 'Mehrtens', + 'Racioppi', + 'Sabey', + 'Stroebel', + 'Swendsen', + 'Vandewalker', + 'Korber', + 'Messler', + 'Mowat', + 'Kor', + 'Pua', + 'Sarazin', + 'Wayson', + 'Oland', + 'Bandi', + 'Fabel', + 'Frankl', + 'Rane', + 'Mozer', + 'Weaber', + 'Moustafa', + 'Robe', + 'Lindy', + 'Medaris', + 'Derden', + 'Benthall', + 'Ayler', + 'Osias', + 'Choyce', + 'Scantlebury', + 'Patmon', + 'Ahlgrim', + 'Boffa', + 'Brideau', + 'Bubeck', + 'Bubel', + 'Casio', + 'Casique', + 'Casten', + 'Colebank', + 'Demoura', + 'Devincenzo', + 'Elsesser', + 'Fauci', + 'Frentz', + 'Hemler', + 'Keitel', + 'Luan', + 'Luhn', + 'Luquette', + 'Mazurowski', + 'Mendibles', + 'Mickiewicz', + 'Minelli', + 'Mistler', + 'Nemer', + 'Nikolaus', + 'Offill', + 'Pezza', + 'Ruzich', + 'Skrzypek', + 'Swimmer', + 'Trucks', + 'Vaccarella', + 'Zeidman', + 'Brattin', + 'Deblock', + 'Dufrane', + 'Gural', + 'Hufstedler', + 'Kapuscinski', + 'Lyerla', + 'Musolino', + 'Neubecker', + 'Polus', + 'Protzman', + 'Retzloff', + 'Sachdev', + 'Sazama', + 'Shrider', + 'Tobolski', + 'Mcbane', + 'Clabo', + 'Fredrich', + 'Lace', + 'Bertran', + 'Kama', + 'Simonet', + 'Lippitt', + 'Thomlinson', + 'Vallot', + 'Dede', + 'Brimley', + 'Parler', + 'Standfield', + 'Goodie', + 'Isidore', + 'Philogene', + 'Abramczyk', + 'Andert', + 'Besancon', + 'Bieda', + 'Birkey', + 'Boquet', + 'Borak', + 'Bottino', + 'Breyfogle', + 'Crill', + 'Daffern', + 'Derrig', + 'Dimalanta', + 'Dresch', + 'Feulner', + 'Friede', + 'Furth', + 'Gamet', + 'Garramone', + 'Gaunce', + 'Gitto', + 'Guandique', + 'Hoxworth', + 'Hubers', + 'Ingwersen', + 'Junio', + 'Kassing', + 'Magrath', + 'Martelle', + 'Mcweeney', + 'Neris', + 'Nesheiwat', + 'Remlinger', + 'Rentmeester', + 'Schlein', + 'Schoneman', + 'Sterr', + 'Streib', + 'Szymanowski', + 'Trompeter', + 'Tullius', + 'Cherico', + 'Cremin', + 'Dominey', + 'Gotthardt', + 'Kowalke', + 'Onderdonk', + 'Pirrello', + 'Rumberger', + 'Schreur', + 'Westerhoff', + 'Maroni', + 'Dire', + 'Menta', + 'Hoeg', + 'Meise', + 'Standerfer', + 'Roam', + 'Tibbett', + 'Beevers', + 'Evrard', + 'Locklair', + 'Brester', + 'Sirmon', + 'Woodbeck', + 'Wires', + 'Durette', + 'Raul', + 'Stephanie', + 'Mcwain', + 'Skeeters', + 'Wilbourne', + 'Debroux', + 'Keyton', + 'Noris', + 'Fanta', + 'Goshen', + 'Kithcart', + 'Shepheard', + 'Sherod', + 'Buntyn', + 'Gissendanner', + 'Goodley', + 'Mckissic', + 'Bissinger', + 'Biswell', + 'Borruso', + 'Danese', + 'Eslava', + 'Gehle', + 'Gibeau', + 'Gionet', + 'Greth', + 'Gul', + 'Hambley', + 'Harshfield', + 'Helin', + 'Henken', + 'Hogland', + 'Hoxha', + 'Hurlbutt', + 'Kaminer', + 'Kien', + 'Kliebert', + 'Koivisto', + 'Kooken', + 'Laconte', + 'Lovo', + 'Manninen', + 'Maxham', + 'Mcleland', + 'Mclerran', + 'Milici', + 'Negrette', + 'Nicotera', + 'Nissan', + 'Philipson', + 'Pimenta', + 'Pinch', + 'Rietveld', + 'Seyller', + 'Shollenberger', + 'Sochacki', + 'Telleria', + 'Toda', + 'Unrue', + 'Vanbenschoten', + 'Versace', + 'Villada', + 'Watry', + 'Wirsing', + 'Zeimet', + 'Zynda', + 'Angelillo', + 'Fleissner', + 'Freehling', + 'Grewell', + 'Heick', + 'Kartes', + 'Kishi', + 'Kopke', + 'Laubenstein', + 'Leske', + 'Lohmeier', + 'Marotz', + 'Moccio', + 'Mullineaux', + 'Muzyka', + 'Ostermiller', + 'Penuelas', + 'Plagge', + 'Stolarz', + 'Wertenberger', + 'Sella', + 'Allinger', + 'Betzler', + 'Rosenkrantz', + 'Trimarchi', + 'Dionicio', + 'Frohman', + 'Landenberger', + 'Shillings', + 'Chill', + 'Leather', + 'Sonn', + 'Connel', + 'Fougere', + 'Alia', + 'Wisby', + 'Haisley', + 'Minion', + 'Mccathern', + 'Rozzell', + 'Armbrister', + 'Ryant', + 'Almeyda', + 'Bonjour', + 'Bordas', + 'Bozard', + 'Buccola', + 'Cihlar', + 'Dargis', + 'Faivre', + 'Fejes', + 'Grulke', + 'Harken', + 'Heimberger', + 'Hochmuth', + 'Keadle', + 'Kedrowski', + 'Kortman', + 'Krahenbuhl', + 'Krasniqi', + 'Kundrat', + 'Leistner', + 'Loguidice', + 'Mcauliff', + 'Mchatton', + 'Minella', + 'Muccio', + 'Normington', + 'Nuttle', + 'Orsino', + 'Reker', + 'Respicio', + 'Shein', + 'Teichert', + 'Varisco', + 'Accomando', + 'Amelio', + 'Burckhard', + 'Fleischhacker', + 'Hagglund', + 'Kessenich', + 'Langrehr', + 'Lauderbaugh', + 'Misquez', + 'Muneton', + 'Ourada', + 'Rulon', + 'Scholze', + 'Stellmach', + 'Sudano', + 'Thelander', + 'Yeckley', + 'Corsino', + 'Grage', + 'Isla', + 'Narramore', + 'Coolman', + 'Heatherington', + 'Newey', + 'Kunda', + 'Motts', + 'Tawfik', + 'Tindel', + 'Passon', + 'Sypher', + 'Conceicao', + 'Haraway', + 'Deamer', + 'Nored', + 'Mamo', + 'Mcgilberry', + 'Akerley', + 'Andreatta', + 'Aronhalt', + 'Barz', + 'Bebber', + 'Brubacher', + 'Cabriales', + 'Dyckman', + 'Ellers', + 'Finerty', + 'Hargan', + 'Haselton', + 'Hellmuth', + 'Hoffmeier', + 'Homrich', + 'Hrabak', + 'Intrieri', + 'Lebeda', + 'Lutzke', + 'Malka', + 'Mcglinn', + 'Nicklin', + 'Nusz', + 'Pennings', + 'Rebmann', + 'Rodocker', + 'Sacra', + 'Saksa', + 'Shehane', + 'Siever', + 'Snide', + 'Sotero', + 'Sponsel', + 'Therien', + 'Viti', + 'Wubben', + 'Zieske', + 'Billingham', + 'Bruschi', + 'Cullipher', + 'Eppolito', + 'Greuel', + 'Huq', + 'Matott', + 'Mohlman', + 'Monterroza', + 'Risberg', + 'Shvartsman', + 'Sigafoos', + 'Zehring', + 'Manuele', + 'Asghar', + 'Shelp', + 'Grieder', + 'Hippert', + 'Dani', + 'Beserra', + 'Kennan', + 'Scholfield', + 'Joh', + 'Swailes', + 'Pear', + 'Hell', + 'Kittler', + 'Pickeral', + 'Somerset', + 'Streat', + 'Tinner', + 'Landor', + 'Pretlow', + 'Tensley', + 'Abela', + 'Abramovich', + 'Acocella', + 'Avino', + 'Bacchi', + 'Bayliff', + 'Beganovic', + 'Belinsky', + 'Bilicki', + 'Borowiec', + 'Bucknam', + 'Calandro', + 'Ciszek', + 'Cooling', + 'Cundari', + 'Derk', + 'Ekern', + 'Engelson', + 'Fennessey', + 'Ferencz', + 'Filipkowski', + 'Frescas', + 'Frisinger', + 'Gegg', + 'Hanken', + 'Harbach', + 'Jipson', + 'Kasal', + 'Kinstler', + 'Langenbach', + 'Leccese', + 'Maalouf', + 'Mcinerny', + 'Mcpartlin', + 'Meth', + 'Mitzner', + 'Riano', + 'Saggese', + 'Schroff', + 'Skibicki', + 'Textor', + 'Vancampen', + 'Vukelich', + 'Wascom', + 'Workinger', + 'Xin', + 'Bronkema', + 'Gerstel', + 'Geving', + 'Gravlin', + 'Hannay', + 'Haughn', + 'Lippi', + 'Lonsway', + 'Paradowski', + 'Poust', + 'Thinnes', + 'Wassenaar', + 'Hemm', + 'Isip', + 'Pastorino', + 'Barkett', + 'Montalban', + 'Ballestero', + 'Floren', + 'Rossen', + 'Chuba', + 'Burrington', + 'Derman', + 'Wickland', + 'Dunman', + 'Beek', + 'Petitjean', + 'Michelin', + 'Chapell', + 'Pullam', + 'Adamcik', + 'Albarracin', + 'Batrez', + 'Berghuis', + 'Birkland', + 'Boulier', + 'Broderson', + 'Bruun', + 'Cicio', + 'Davidow', + 'Denova', + 'Dooner', + 'Espeland', + 'Fifita', + 'Guidone', + 'Hartnell', + 'Havranek', + 'Janca', + 'Klepac', + 'Langhorst', + 'Lippmann', + 'Merrihew', + 'Mondelli', + 'Monterosso', + 'Moster', + 'Noxon', + 'Poznanski', + 'Reents', + 'Samaras', + 'Silvius', + 'Srour', + 'Stasio', + 'Steffe', + 'Steimer', + 'Stracke', + 'Taney', + 'Theodorou', + 'Trickel', + 'Tunks', + 'Vavrek', + 'Whitfill', + 'Wohlfeil', + 'Zirkelbach', + 'Brissey', + 'Busboom', + 'Collignon', + 'Emling', + 'Fratzke', + 'Genrich', + 'Giglia', + 'Hayakawa', + 'Lupinski', + 'Pulvermacher', + 'Steinbrink', + 'Xayavong', + 'Yerkey', + 'Arlotta', + 'Calia', + 'Pfiffner', + 'Gostomski', + 'Declerck', + 'Demedeiros', + 'Dirickson', + 'Wo', + 'Hosie', + 'Chad', + 'Herbison', + 'Fleece', + 'Connon', + 'Dun', + 'Gaffin', + 'Plush', + 'Gravette', + 'Houseal', + 'Seaward', + 'Esson', + 'Mayhorn', + 'Surrell', + 'Horsford', + 'Mcduffey', + 'Huger', + 'Alexie', + 'Apsey', + 'Belke', + 'Bourcier', + 'Cardena', + 'Daun', + 'Dunworth', + 'Ehrsam', + 'Elizardo', + 'Elkhatib', + 'Emick', + 'Fernau', + 'Finnan', + 'Hitzeman', + 'Housand', + 'Kallstrom', + 'Katen', + 'Kerstein', + 'Kiracofe', + 'Klammer', + 'Largaespada', + 'Limoges', + 'Lodwick', + 'Lozito', + 'Madl', + 'Mauthe', + 'Mogel', + 'Newstrom', + 'Ninh', + 'Obrochta', + 'Opsal', + 'Ordiway', + 'Osentoski', + 'Paxman', + 'Plume', + 'Rickenbach', + 'Rinks', + 'Saltmarsh', + 'Scheuring', + 'Schwegel', + 'Skov', + 'Woodrome', + 'Zdanowicz', + 'Zera', + 'Basgall', + 'Bornhorst', + 'Clotfelter', + 'Coulthard', + 'Dresner', + 'Fischl', + 'Grahek', + 'Grefe', + 'Knightly', + 'Kuenzel', + 'Mccumbers', + 'Millstein', + 'Mulnix', + 'Weiher', + 'Yust', + 'Metter', + 'Polio', + 'Ayad', + 'Banke', + 'Lawlis', + 'Coba', + 'Twyford', + 'Burck', + 'Barthold', + 'Sames', + 'Jacquot', + 'Allsopp', + 'Mcglaun', + 'Hollinsworth', + 'Gillings', + 'Buchannon', + 'Bas', + 'Beaber', + 'Berto', + 'Bobrow', + 'Bochicchio', + 'Bohland', + 'Burghart', + 'Chaloux', + 'Costella', + 'Depace', + 'Dils', + 'Diviney', + 'Ehly', + 'Ermer', + 'Fussner', + 'Gunia', + 'Guterrez', + 'Holik', + 'Holster', + 'Kasperski', + 'Koscinski', + 'Lamoureaux', + 'Marotti', + 'Masullo', + 'Mcconahy', + 'Mehlhaff', + 'Mocarski', + 'Moosman', + 'Pavlich', + 'Pfisterer', + 'Ruacho', + 'Semrad', + 'Slemmer', + 'Stineman', + 'Toelle', + 'Vanderstelt', + 'Wagy', + 'Wuensch', + 'Wykes', + 'Zar', + 'Bouchie', + 'Friis', + 'Gehrt', + 'Hempfling', + 'Henkes', + 'Huggler', + 'Kelbaugh', + 'Petrenko', + 'Pfost', + 'Rubendall', + 'Shimel', + 'Stapf', + 'Sweeton', + 'Tsuda', + 'Vitanza', + 'Voytko', + 'Bibbo', + 'Hagee', + 'Majer', + 'Mangieri', + 'Pala', + 'Volle', + 'Cabassa', + 'Lipsett', + 'Macdougal', + 'Minar', + 'Eline', + 'Eskin', + 'Angeletti', + 'Lattner', + 'Kimple', + 'Marsan', + 'Tornes', + 'Moncur', + 'Sanderfer', + 'Crite', + 'Levels', + 'Valcin', + 'Motton', + 'Foggie', + 'Battistoni', + 'Bedient', + 'Bendt', + 'Bennison', + 'Bonnin', + 'Caridi', + 'Cedotal', + 'Choinski', + 'Cossin', + 'Devargas', + 'Deveny', + 'Dosher', + 'Dredge', + 'Fittro', + 'Gorgone', + 'Gourd', + 'Herra', + 'Holwerda', + 'Iannello', + 'Klintworth', + 'Kubena', + 'Leyvas', + 'Magowan', + 'Mendolia', + 'Nehme', + 'Pelikan', + 'Pfalzgraf', + 'Raith', + 'Reichenberg', + 'Reinertsen', + 'Sens', + 'Simer', + 'Spektor', + 'Sweda', + 'Wordell', + 'Blasing', + 'Dinoto', + 'Goblirsch', + 'Helming', + 'Hibshman', + 'Lamountain', + 'Latka', + 'Licausi', + 'Malerba', + 'Mentink', + 'Meskill', + 'Moening', + 'Montminy', + 'Ryno', + 'Sluka', + 'Solarz', + 'Swainston', + 'Tagliaferri', + 'Twichell', + 'Vertucci', + 'Voland', + 'Wolgast', + 'Bissen', + 'Duray', + 'Flaum', + 'Taves', + 'Caplin', + 'Hayat', + 'Pollett', + 'Baris', + 'Taher', + 'Anes', + 'Beza', + 'Pere', + 'Tipper', + 'Farrey', + 'Slott', + 'Sinquefield', + 'Bobbett', + 'Calico', + 'Eigner', + 'Gambrill', + 'Donigan', + 'Daney', + 'Natt', + 'Gettis', + 'Kincy', + 'Dolberry', + 'Curenton', + 'Elzie', + 'Beretta', + 'Carbine', + 'Carpenito', + 'Clarin', + 'Conrado', + 'Conradt', + 'Courteau', + 'Daft', + 'Debruler', + 'Delahunty', + 'Duerst', + 'Dzik', + 'Ellner', + 'Faeth', + 'Fournet', + 'Galinski', + 'Goldenstein', + 'Hanauer', + 'Higgason', + 'Hoeper', + 'Hollo', + 'Ildefonso', + 'Jocson', + 'Kasprowicz', + 'Kochanowski', + 'Labrosse', + 'Lazaroff', + 'Leino', + 'Levinsky', + 'Lopezhernandez', + 'Mckeague', + 'Otremba', + 'Paluzzi', + 'Pevehouse', + 'Polgar', + 'Raneri', + 'Rumler', + 'Sanantonio', + 'Schissel', + 'Senteno', + 'Sieling', + 'Smee', + 'Swiggum', + 'Tarnow', + 'Tavakoli', + 'Tholl', + 'Valdiviezo', + 'Willadsen', + 'Wilmouth', + 'Dudziak', + 'Eskenazi', + 'Garity', + 'Gravino', + 'Impastato', + 'Kuhner', + 'Mcclaflin', + 'Nein', + 'Precourt', + 'Rotenberry', + 'Sciara', + 'Arenson', + 'Coupland', + 'Sedler', + 'Pizer', + 'Him', + 'Combee', + 'Rhorer', + 'Gelles', + 'Baroody', + 'Basten', + 'Sprinkles', + 'Vanier', + 'Clementson', + 'Robberson', + 'Harten', + 'Kade', + 'Bhola', + 'Bahar', + 'Pellum', + 'Isadore', + 'Dixie', + 'Axline', + 'Backs', + 'Berdahl', + 'Billeter', + 'Bily', + 'Broerman', + 'Declercq', + 'Derleth', + 'Fanucchi', + 'Forkey', + 'Gallinger', + 'Gionfriddo', + 'Gretzinger', + 'Grima', + 'Helgren', + 'Hoelting', + 'Hundertmark', + 'Inscho', + 'Jernberg', + 'Kamiya', + 'Lekas', + 'Marchini', + 'Markuson', + 'Matsushima', + 'Meineke', + 'Mizrachi', + 'Moglia', + 'Nagele', + 'Naro', + 'Padillo', + 'Palleschi', + 'Palomba', + 'Purgason', + 'Qadri', + 'Recalde', + 'Rosiak', + 'Rumney', + 'Savitt', + 'Shibuya', + 'Szalkowski', + 'Wagg', + 'Wolsey', + 'Zumpano', + 'Benbrook', + 'Blasdel', + 'Carusone', + 'Karalis', + 'Koep', + 'Kohles', + 'Rumbo', + 'Siggins', + 'Unverzagt', + 'Eatherly', + 'Kapper', + 'Salser', + 'Wege', + 'Zinsmeister', + 'Alf', + 'Wish', + 'Falero', + 'Bur', + 'Imam', + 'Biven', + 'Merritts', + 'Kaigler', + 'Verdell', + 'Feggins', + 'Acerra', + 'Antenucci', + 'Benegas', + 'Bisesi', + 'Boshers', + 'Chap', + 'Clouatre', + 'Doxtater', + 'Dullea', + 'Eischeid', + 'Gundry', + 'Hinger', + 'Hodak', + 'Iseminger', + 'Juris', + 'Kirchen', + 'Knezevic', + 'Kobrin', + 'Krizek', + 'Leza', + 'Lusty', + 'Luttrull', + 'Mattke', + 'Mossbarger', + 'Narro', + 'Osland', + 'Ostwald', + 'Pepperman', + 'Pritzl', + 'Reasner', + 'Schimming', + 'Schulenburg', + 'Trefry', + 'Vigorito', + 'Bayardo', + 'Bieser', + 'Brinkmeier', + 'Camposano', + 'Cremeens', + 'Delgrande', + 'Demopoulos', + 'Deyarmin', + 'Grismer', + 'Jubb', + 'Kinker', + 'Lauf', + 'Mabile', + 'Muehl', + 'Orlick', + 'Pillado', + 'Pizzano', + 'Poppleton', + 'Quickel', + 'Stoneberg', + 'Szwed', + 'Zadrozny', + 'Ziemke', + 'Zupko', + 'Diesel', + 'Hornbrook', + 'Pillion', + 'Holaway', + 'Massad', + 'Rossmiller', + 'Parriott', + 'Toya', + 'Dross', + 'Burwick', + 'Kaman', + 'Bruna', + 'Milles', + 'Acrey', + 'Toogood', + 'Austell', + 'Chastang', + 'Jasmine', + 'Eckford', + 'Stiggers', + 'Saintvil', + 'Adeyemi', + 'Basto', + 'Bolon', + 'Brilliant', + 'Brockhoff', + 'Colao', + 'Emens', + 'Endler', + 'Fabris', + 'Falletta', + 'Felver', + 'Ferdon', + 'Golinski', + 'Gosdin', + 'Gronlund', + 'Guijosa', + 'Hainley', + 'Halama', + 'Heinicke', + 'Heldenbrand', + 'Helmkamp', + 'Hoctor', + 'Hoeck', + 'Kroboth', + 'Lamagna', + 'Lingg', + 'Locurto', + 'Marchewka', + 'Micco', + 'Mormino', + 'Newmeyer', + 'Ostrosky', + 'Redel', + 'Saccoccio', + 'Stavely', + 'Stidd', + 'Tonne', + 'Tonnesen', + 'Umbach', + 'Vardanyan', + 'Wank', + 'Wolven', + 'Cilento', + 'Delmonaco', + 'Denigris', + 'Gerbig', + 'Gradilla', + 'Grebner', + 'Landini', + 'Marohl', + 'Muenchow', + 'Niedermeier', + 'Nussbaumer', + 'Nycz', + 'Pizzino', + 'Schader', + 'Schuneman', + 'Takano', + 'Ureta', + 'Vanderloop', + 'Windholz', + 'Wombacher', + 'Woulfe', + 'Hamley', + 'Schickel', + 'Yuill', + 'Batta', + 'Galant', + 'Mofield', + 'Kint', + 'Barnell', + 'Ashmead', + 'Crossin', + 'Lasco', + 'Chasen', + 'Swire', + 'Gleghorn', + 'Bearfield', + 'Goodgame', + 'Daris', + 'Plump', + 'Derricott', + 'Burno', + 'Baylock', + 'Vanterpool', + 'Judon', + 'Mells', + 'Proby', + 'Bagan', + 'Batcheller', + 'Bjelland', + 'Boline', + 'Boullion', + 'Broomall', + 'Carcia', + 'Cassinelli', + 'Cerro', + 'Colantuono', + 'Dembeck', + 'Doto', + 'Eckersley', + 'Edell', + 'Ewy', + 'Goodness', + 'Huhta', + 'Kallen', + 'Keimig', + 'Kemppainen', + 'Koopmann', + 'Lacap', + 'Lehtinen', + 'Maciolek', + 'Marchuk', + 'Mcfate', + 'Mentel', + 'Minihan', + 'Mohsin', + 'Oppedisano', + 'Patriarca', + 'Raske', + 'Schueneman', + 'Shostak', + 'Sibal', + 'Spadafore', + 'Suitor', + 'Tavella', + 'Vy', + 'Wies', + 'Beadnell', + 'Bogusz', + 'Cleverly', + 'Dellorusso', + 'Dudenhoeffer', + 'Glendinning', + 'Glomb', + 'Heinkel', + 'Jiwani', + 'Lonigro', + 'Machala', + 'Marsicano', + 'Neuenfeldt', + 'Overlock', + 'Popko', + 'Russomanno', + 'Saxer', + 'Scicchitano', + 'Spiegelberg', + 'Spindel', + 'Timpone', + 'Vincelette', + 'Waidelich', + 'Wissink', + 'Woolstenhulme', + 'Danza', + 'Sleasman', + 'Frometa', + 'Savinon', + 'Higgerson', + 'Helmich', + 'Nahar', + 'Campus', + 'Hassey', + 'Mccorkel', + 'Tola', + 'Ferrington', + 'Nicolls', + 'Markes', + 'Edgley', + 'Dupriest', + 'Wah', + 'Mclester', + 'Scantling', + 'Goffe', + 'Battie', + 'Battershell', + 'Bearup', + 'Bisig', + 'Brouillet', + 'Canby', + 'Chaussee', + 'Colandrea', + 'Colocho', + 'Daube', + 'Dobransky', + 'Dolbow', + 'Dyk', + 'Elfrink', + 'Figel', + 'Hauter', + 'Henkels', + 'Keillor', + 'Kollasch', + 'Krabill', + 'Kubly', + 'Kvasnicka', + 'Leise', + 'Martirosyan', + 'Mihalic', + 'Montecinos', + 'Myren', + 'Okerlund', + 'Ozer', + 'Rajput', + 'Reihl', + 'Rimando', + 'Saffle', + 'Schmelter', + 'Tellado', + 'Wachsmuth', + 'Wussow', + 'Zylka', + 'Caiola', + 'Certo', + 'Disabatino', + 'Ehrke', + 'Lahmann', + 'Lamartina', + 'Manheim', + 'Mckevitt', + 'Nardozzi', + 'Neuzil', + 'Novotney', + 'Oldfather', + 'Sietsema', + 'Stemmler', + 'Stumm', + 'Ueno', + 'Weckwerth', + 'Berrocal', + 'Nolde', + 'Alava', + 'Revier', + 'Sester', + 'Saller', + 'Tonga', + 'Kala', + 'Reveron', + 'Homesley', + 'Pagett', + 'Blackie', + 'Raimer', + 'Fitt', + 'Kimbley', + 'Amory', + 'Cabler', + 'Juett', + 'Crate', + 'Burres', + 'Siddle', + 'Barnfield', + 'Bordenave', + 'Cubit', + 'Elem', + 'Hardmon', + 'Augspurger', + 'Barriger', + 'Bau', + 'Bloomingdale', + 'Busta', + 'Canoy', + 'Carapia', + 'Cavenaugh', + 'Conkin', + 'Coppernoll', + 'Daloia', + 'Debruyne', + 'Egly', + 'Esmail', + 'Estorga', + 'Gladu', + 'Gladue', + 'Harvath', + 'Hirschmann', + 'Juel', + 'Kappus', + 'Kopriva', + 'Krul', + 'Lavorgna', + 'Maginn', + 'Malphrus', + 'Mcilhenny', + 'Perazzo', + 'Peredo', + 'Pineo', + 'Rigoni', + 'Robleto', + 'Schoene', + 'Sevillano', + 'Stears', + 'Stoltzfoos', + 'Sutley', + 'Terracciano', + 'Villacres', + 'Yoak', + 'Brensinger', + 'Brodzinski', + 'Cordial', + 'Cornacchia', + 'Corralejo', + 'Demarchi', + 'Dziuk', + 'Hirzel', + 'Keirns', + 'Kocourek', + 'Kupec', + 'Nazaryan', + 'Oftedahl', + 'Pignatelli', + 'Pundt', + 'Repinski', + 'Ryther', + 'Sampedro', + 'Shemanski', + 'Siess', + 'Trettel', + 'Urquilla', + 'Vantil', + 'Vicens', + 'Dunahoo', + 'Safer', + 'Romaniello', + 'Tallo', + 'Cavell', + 'Cobern', + 'Yarrow', + 'Serge', + 'Adel', + 'Allum', + 'Pruit', + 'Wali', + 'Forson', + 'Bells', + 'Blyden', + 'Andreotti', + 'Bagnato', + 'Beauchaine', + 'Biedrzycki', + 'Brabo', + 'Brodman', + 'Bruyere', + 'Canizares', + 'Chio', + 'Coudriet', + 'Dara', + 'Dhawan', + 'Diclemente', + 'Doro', + 'Elvir', + 'Fivecoat', + 'Frate', + 'Furuya', + 'Greis', + 'Halbleib', + 'Heuerman', + 'Hoener', + 'Holberg', + 'Hoogendoorn', + 'Inclan', + 'Jokinen', + 'Kretchmer', + 'Lafromboise', + 'Mccomsey', + 'Mckiddy', + 'Pelky', + 'Plaia', + 'Ponti', + 'Reichl', + 'Schicker', + 'Sotto', + 'Staehle', + 'Thau', + 'Turchin', + 'Zill', + 'Aicher', + 'Arrigoni', + 'Bertagnolli', + 'Binetti', + 'Dahlheimer', + 'Delashmit', + 'Disque', + 'Hemmerling', + 'Hovater', + 'Kachur', + 'Massmann', + 'Schlup', + 'Turkovich', + 'Underberg', + 'Wambolt', + 'Vassey', + 'Larney', + 'Brisky', + 'Minas', + 'Kata', + 'Magar', + 'Arlen', + 'Corporan', + 'Westland', + 'Detherage', + 'Reen', + 'Morale', + 'Hoes', + 'Baynham', + 'Norrington', + 'Lartigue', + 'Hakeem', + 'Kendrix', + 'Cazeau', + 'Amadi', + 'Mczeal', + 'Alwin', + 'Barcellos', + 'Bastedo', + 'Bintz', + 'Brackenbury', + 'Brockel', + 'Bucek', + 'Cecala', + 'Dapper', + 'Dettore', + 'Dowdall', + 'Dralle', + 'Essenmacher', + 'Evaristo', + 'Fecher', + 'Feldmeier', + 'Fetherston', + 'Futterman', + 'Garlinghouse', + 'Germani', + 'Gotz', + 'Hoen', + 'Janikowski', + 'Kiess', + 'Lagerstrom', + 'Lozinski', + 'Magnone', + 'Markow', + 'Mayall', + 'Mehdi', + 'Mineau', + 'Morgenroth', + 'Nitzsche', + 'Nordell', + 'Pavlock', + 'Peruzzi', + 'Pettine', + 'Pinos', + 'Polidoro', + 'Rahl', + 'Rudis', + 'Ryback', + 'Santellan', + 'Scharfenberg', + 'Schnake', + 'Schwake', + 'Seeling', + 'Senk', + 'Siron', + 'Speich', + 'Summerhays', + 'Torno', + 'Vangieson', + 'Wiacek', + 'Begnoche', + 'Carrejo', + 'Chervenak', + 'Edminster', + 'Halonen', + 'Macumber', + 'Mazeika', + 'Mikami', + 'Minetti', + 'Mosbrucker', + 'Mundis', + 'Onder', + 'Prowant', + 'Pyo', + 'Sedlack', + 'Stanbro', + 'Woehl', + 'Wrage', + 'Carpentieri', + 'Guedry', + 'Hodde', + 'Waggy', + 'Weitman', + 'Handal', + 'Gosman', + 'Mckeone', + 'Oliveria', + 'Soutar', + 'Glance', + 'Surprise', + 'Milius', + 'Crammer', + 'Mclear', + 'Borris', + 'Malon', + 'Mane', + 'Arrick', + 'Brazzel', + 'Matthewson', + 'Philemon', + 'Selvy', + 'Lites', + 'Deadwyler', + 'Marzette', + 'Alipio', + 'Arancibia', + 'Arrona', + 'Basista', + 'Blethen', + 'Brull', + 'Colaianni', + 'Dreese', + 'Giammona', + 'Giovanetti', + 'Grandmaison', + 'Grondahl', + 'Gulli', + 'Hellenbrand', + 'Iturbe', + 'Koesters', + 'Kondracki', + 'Konitzer', + 'Kubic', + 'Lauerman', + 'Mcfadin', + 'Musquiz', + 'Papalia', + 'Porrazzo', + 'Prien', + 'Reichley', + 'Treichler', + 'Ursua', + 'Vanblaricom', + 'Wich', + 'Windler', + 'Wos', + 'Zampino', + 'Alexopoulos', + 'Bambrick', + 'Beabout', + 'Brechtel', + 'Buroker', + 'Dahler', + 'Everding', + 'Furno', + 'Gikas', + 'Gilkeson', + 'Hubka', + 'Konwinski', + 'Krisko', + 'Kuligowski', + 'Maltbie', + 'Molstad', + 'Nonnemacher', + 'Nowotny', + 'Odisho', + 'Remsburg', + 'Rollyson', + 'Siegmann', + 'Slaubaugh', + 'Wasco', + 'Carlyon', + 'Chanin', + 'Cominsky', + 'Karber', + 'Aynes', + 'Swamy', + 'Kolden', + 'Rochel', + 'Julin', + 'Demarcus', + 'Malena', + 'Morice', + 'Burst', + 'Sukhu', + 'Mccravy', + 'Rinehardt', + 'Veazie', + 'Isaiah', + 'Bradby', + 'Poellnitz', + 'Agyemang', + 'Agate', + 'Aschoff', + 'Beenken', + 'Bogenschutz', + 'Casamento', + 'Correira', + 'Ebers', + 'Ellertson', + 'Forcum', + 'Gortney', + 'Jarriel', + 'Jasmer', + 'Kennebeck', + 'Kimpton', + 'Lad', + 'Lasek', + 'Licavoli', + 'Lipper', + 'Luedecke', + 'Maqueda', + 'Matsen', + 'Mest', + 'Neang', + 'Neault', + 'Newlun', + 'Oetken', + 'Rodick', + 'Rollinger', + 'Sabins', + 'Schalow', + 'Sheils', + 'Spilde', + 'Virzi', + 'Watz', + 'Wehrly', + 'Boscarino', + 'Chavolla', + 'Dasaro', + 'Eisenbach', + 'Ignatowski', + 'Kievit', + 'Kuzminski', + 'Lickliter', + 'Moravek', + 'Pawling', + 'Prause', + 'Redler', + 'Wunschel', + 'Suchanek', + 'Eyring', + 'Loge', + 'Tout', + 'Fross', + 'Swiss', + 'Deforrest', + 'Umphlett', + 'Herran', + 'Matton', + 'Passe', + 'Ode', + 'Della', + 'Caillier', + 'Baten', + 'Chesterfield', + 'Odneal', + 'Azeez', + 'Salami', + 'Ramson', + 'Mcvea', + 'Pittmon', + 'Cheatom', + 'Dorsainvil', + 'Cheeseboro', + 'Lavalais', + 'Allegro', + 'Bressi', + 'Brocklehurst', + 'Cassarino', + 'Dario', + 'Gazzola', + 'Glinka', + 'Goffredo', + 'Halabi', + 'Kroeze', + 'Lenig', + 'Marciel', + 'Marcussen', + 'Massoni', + 'Mayernik', + 'Nawrot', + 'Palazzi', + 'Pfefferkorn', + 'Placeres', + 'Polimeni', + 'Recendiz', + 'Sawdey', + 'Seidell', + 'Suchecki', + 'Titzer', + 'Virag', + 'Vitulli', + 'Wiltfong', + 'Wolden', + 'Woolworth', + 'Yandow', + 'Zeiter', + 'Zogg', + 'Brosh', + 'Dunsmoor', + 'Gucciardo', + 'Gumz', + 'Luginbill', + 'Mathwig', + 'Pannullo', + 'Raitt', + 'Reutzel', + 'Sonnen', + 'Bahri', + 'Guiffre', + 'Hons', + 'Platner', + 'Balaguer', + 'Lapre', + 'Rabbani', + 'Talent', + 'Hoster', + 'Thal', + 'Apo', + 'Duggin', + 'Kirley', + 'Burnard', + 'Lourie', + 'Wilham', + 'Craton', + 'Griff', + 'Falwell', + 'Upperman', + 'Laverne', + 'Wi', + 'Foucher', + 'Sudberry', + 'Oriol', + 'Cowens', + 'Marshell', + 'Chargois', + 'Bordley', + 'Artale', + 'Boeker', + 'Cookston', + 'Dattilio', + 'Dewinter', + 'Ditton', + 'Droessler', + 'Dusch', + 'Eltringham', + 'Feige', + 'Giel', + 'Grigas', + 'Hannagan', + 'Haubner', + 'Henzler', + 'Kippes', + 'Kneebone', + 'Lozeau', + 'Mallek', + 'Mandato', + 'Mangiapane', + 'Matusek', + 'Newgard', + 'Notte', + 'Purdin', + 'Ramaker', + 'Reddoch', + 'Rensing', + 'Rohrman', + 'Romm', + 'Rudiger', + 'Torti', + 'Travaglini', + 'Uno', + 'Wojciak', + 'Yannuzzi', + 'Zeien', + 'Arpino', + 'Borgstrom', + 'Burkemper', + 'Cristino', + 'Detjen', + 'Gienger', + 'Glockner', + 'Grillot', + 'Jentz', + 'Kendzierski', + 'Klebe', + 'Knippenberg', + 'Kusler', + 'Olofson', + 'Orlov', + 'Rindt', + 'Stallbaumer', + 'Troost', + 'Turri', + 'Uzelac', + 'Weichert', + 'Sweazy', + 'Alcivar', + 'Canner', + 'Lottman', + 'Salame', + 'Berkes', + 'Pickren', + 'Ganson', + 'Odonell', + 'Geron', + 'Kasa', + 'Banbury', + 'Tinnel', + 'Umble', + 'Flow', + 'Kirt', + 'Rhule', + 'Diles', + 'Seeney', + 'Givans', + 'Mckethan', + 'Crusoe', + 'Darko', + 'Mucker', + 'Kizzee', + 'Daniely', + 'Nutall', + 'Angove', + 'Appelhans', + 'Balder', + 'Blatchley', + 'Botkins', + 'Brisk', + 'Burandt', + 'Clowdus', + 'Debauche', + 'Deily', + 'Group', + 'Hoecker', + 'Holsonback', + 'Humpert', + 'Jacquin', + 'Jurica', + 'Karnik', + 'Krontz', + 'Lapiana', + 'Lenzo', + 'Luscombe', + 'Madey', + 'Mirabito', + 'Neifert', + 'Pennino', + 'Piechota', + 'Pizzimenti', + 'Reeg', + 'Roarty', + 'Routzahn', + 'Salsedo', + 'Schuff', + 'Silveri', + 'Steckman', + 'Supak', + 'Swackhamer', + 'Trusler', + 'Vizzini', + 'Wences', + 'Whelton', + 'Zachar', + 'Albertsen', + 'Bischel', + 'Brigandi', + 'Campoy', + 'Castagnola', + 'Doenges', + 'Flessner', + 'Garbers', + 'Jezewski', + 'Kozlov', + 'Niedbalski', + 'Schillo', + 'Schoepke', + 'Schranz', + 'Trulson', + 'Vanwyhe', + 'Versluis', + 'Zavadil', + 'Brau', + 'Rudell', + 'Golen', + 'Meter', + 'Sherrin', + 'Tolly', + 'Mandala', + 'Calcano', + 'Lewing', + 'Sedeno', + 'Ramalho', + 'Haggar', + 'Borns', + 'Matherson', + 'Cobin', + 'Turnley', + 'Pone', + 'Tuner', + 'Crandle', + 'Sturkey', + 'Heggins', + 'Tisby', + 'Allbaugh', + 'Baars', + 'Bethard', + 'Brenizer', + 'Bussman', + 'Casebier', + 'Castanos', + 'Climaco', + 'Dux', + 'Farrens', + 'Frediani', + 'Gaccione', + 'Garciaperez', + 'Hoppa', + 'Juckett', + 'Klinkner', + 'Kooy', + 'Krinke', + 'Locy', + 'Lovecchio', + 'Lukin', + 'Machia', + 'Mand', + 'Maslin', + 'Mehrotra', + 'Nicolet', + 'Peyser', + 'Reckart', + 'Roanhorse', + 'Rokicki', + 'Sargis', + 'Sciullo', + 'Shevchuk', + 'Sindoni', + 'Slankard', + 'Sobiech', + 'Stoneberger', + 'Stys', + 'Tuzzolino', + 'Waligora', + 'Wiland', + 'Clabough', + 'Drawbaugh', + 'Figurski', + 'Gibeault', + 'Gojcaj', + 'Hartfiel', + 'Inbody', + 'Konarski', + 'Kruszka', + 'Letarte', + 'Lillich', + 'Mccandlish', + 'Mollenkopf', + 'Oltmann', + 'Pfenninger', + 'Ruediger', + 'Schaben', + 'Shauger', + 'Wilczak', + 'Wolanin', + 'Ziehm', + 'Bassinger', + 'Brannick', + 'Schlereth', + 'Capri', + 'Roscher', + 'Pasqual', + 'Lallo', + 'Sweney', + 'Rozario', + 'Hamblet', + 'Muckleroy', + 'Frankson', + 'Moure', + 'Shrieves', + 'Bosket', + 'Strowbridge', + 'Hawkin', + 'Cooperwood', + 'Agena', + 'Barrowman', + 'Belko', + 'Blasdell', + 'Brobeck', + 'Chieffo', + 'Cooperrider', + 'Dickard', + 'Erion', + 'Fradkin', + 'Hattery', + 'Hefferon', + 'Hofstra', + 'Hoiland', + 'Jirak', + 'Klugman', + 'Klundt', + 'Knope', + 'Lawniczak', + 'Luckenbach', + 'Manzione', + 'Mccombie', + 'Minden', + 'Mousel', + 'Ridling', + 'Rightmire', + 'Ritzel', + 'Santori', + 'Semmens', + 'Snyders', + 'Spargur', + 'Staszewski', + 'Swiech', + 'Tasso', + 'Veldhuizen', + 'Vuolo', + 'Wojnarowski', + 'Yoe', + 'Bachler', + 'Cimo', + 'Hippen', + 'Klimaszewski', + 'Kohlhepp', + 'Kovacich', + 'Kretsch', + 'Lacoursiere', + 'Lopezmartinez', + 'Marsiglia', + 'Metzker', + 'Murchie', + 'Paradee', + 'Pfefferle', + 'Rothert', + 'Skellenger', + 'Tourangeau', + 'Beumer', + 'Thunder', + 'Uden', + 'Broe', + 'Moxon', + 'Kassin', + 'Murton', + 'Hockley', + 'Vinet', + 'Suthers', + 'Bayman', + 'Cokeley', + 'Ailey', + 'Crossfield', + 'Desha', + 'Dowson', + 'Acheampong', + 'Boomsma', + 'Buer', + 'Caratachea', + 'Dascenzo', + 'Debes', + 'Degroote', + 'Dillie', + 'Dorsi', + 'Dorward', + 'Eyestone', + 'Geister', + 'Gonia', + 'Heiler', + 'Hin', + 'Hoheisel', + 'Horger', + 'Hulce', + 'Kainer', + 'Kerkman', + 'Kloehn', + 'Krempasky', + 'Kuehnel', + 'Leetch', + 'Lio', + 'Lohrey', + 'Lucchetti', + 'Machnik', + 'Majeske', + 'Martire', + 'Mores', + 'Oyen', + 'Pappert', + 'Platas', + 'Podany', + 'Prata', + 'Radoncic', + 'Sainato', + 'Salada', + 'Serota', + 'Tatsch', + 'Torbeck', + 'Vilhauer', + 'Waltner', + 'Wauters', + 'Welge', + 'Yoss', + 'Bigwood', + 'Brunsman', + 'Civitello', + 'Compston', + 'Cuccaro', + 'Denholm', + 'Emmick', + 'Gadzinski', + 'Goedken', + 'Graumann', + 'Hackert', + 'Hardacre', + 'Hehl', + 'Magliocco', + 'Marotto', + 'Ozanich', + 'Pidcock', + 'Schlangen', + 'Scoma', + 'Sobecki', + 'Spreng', + 'Thalmann', + 'Wolfrum', + 'Groninger', + 'Howatt', + 'Kindy', + 'Swor', + 'Ledden', + 'Voyer', + 'Colli', + 'Andrae', + 'Duchemin', + 'Boker', + 'Malter', + 'Snooks', + 'Morss', + 'Haylett', + 'Mitter', + 'Fairey', + 'Kenerson', + 'Albea', + 'Ellerson', + 'Alcindor', + 'Gadison', + 'Arabia', + 'Bundren', + 'Calica', + 'Cartaya', + 'Cielo', + 'Ebbers', + 'Entler', + 'Friedly', + 'Granja', + 'Landt', + 'Lorensen', + 'Michelini', + 'Oliveto', + 'Piela', + 'Reust', + 'Roussos', + 'Sanluis', + 'Seier', + 'Sobolik', + 'Stader', + 'Stetzer', + 'Tetley', + 'Zirbes', + 'Bridenbaugh', + 'Chinnici', + 'Crabbs', + 'Evilsizer', + 'Favaloro', + 'Haeberle', + 'Hopfensperger', + 'Kijowski', + 'Kingbird', + 'Leikam', + 'Montavon', + 'Petrossian', + 'Quizhpi', + 'Spoelstra', + 'Testani', + 'Plaut', + 'Windt', + 'Dubie', + 'Kozinski', + 'Sorell', + 'Nish', + 'Katon', + 'Soy', + 'Pelcher', + 'Sayres', + 'Waitman', + 'Relph', + 'Hearld', + 'Farewell', + 'Giordani', + 'Canida', + 'Martian', + 'Suliman', + 'Mckesson', + 'Randon', + 'Eastmond', + 'Willaims', + 'Collington', + 'Hardge', + 'Asevedo', + 'Beauchene', + 'Bebeau', + 'Bobick', + 'Bogacki', + 'Bolich', + 'Bonadonna', + 'Butsch', + 'Coltrin', + 'Corbello', + 'Dastrup', + 'Dunshee', + 'Firpo', + 'Foister', + 'Franssen', + 'Fredriksen', + 'Gfeller', + 'Glassner', + 'Johanns', + 'Korson', + 'Langsam', + 'Linstrom', + 'Longstaff', + 'Lukic', + 'Maler', + 'Marteney', + 'Milardo', + 'Rhatigan', + 'Ruetz', + 'Semel', + 'Senske', + 'Shatswell', + 'Simmering', + 'Tasch', + 'Vanskike', + 'Verano', + 'Viscardi', + 'Weidmann', + 'Doubet', + 'Farraj', + 'Fritter', + 'Griesinger', + 'Horkey', + 'Hornik', + 'Izatt', + 'Klayman', + 'Mantei', + 'Notz', + 'Oberholzer', + 'Petko', + 'Rueth', + 'Rygiel', + 'Tumolo', + 'Unterreiner', + 'Urgo', + 'Weisbecker', + 'Weniger', + 'Zarro', + 'Zunino', + 'Goldmann', + 'Verderber', + 'Glennie', + 'Shere', + 'Lamos', + 'Face', + 'Sparger', + 'Donnay', + 'Kage', + 'Leason', + 'Mcgue', + 'Brickle', + 'Mae', + 'Thomaston', + 'Dunnell', + 'Tillie', + 'Miggins', + 'Geffrard', + 'Aubel', + 'Backe', + 'Beaumier', + 'Bloor', + 'Brackbill', + 'Brandvold', + 'Bylund', + 'Carbary', + 'Catrambone', + 'Dapolito', + 'Dillenburg', + 'Elliff', + 'Fehnel', + 'Ferriss', + 'Gellner', + 'Graw', + 'Guilbeault', + 'Hautala', + 'Hollenberg', + 'Imparato', + 'Kaner', + 'Kley', + 'Lanzer', + 'Laterza', + 'Legner', + 'Lombardozzi', + 'Mcerlean', + 'Mcgilton', + 'Mohring', + 'Neeper', + 'Pollinger', + 'Pullara', + 'Sagona', + 'Scripter', + 'Skillen', + 'Streeper', + 'Tritch', + 'Vayda', + 'Verbeek', + 'Wenberg', + 'Youngers', + 'Bayus', + 'Cobaugh', + 'Dolak', + 'Forys', + 'Genther', + 'Jankovich', + 'Kneale', + 'Komp', + 'Kreher', + 'Kuwahara', + 'Mclouth', + 'Melland', + 'Molesky', + 'Neustadt', + 'Oesterling', + 'Quirke', + 'Roeper', + 'Stantz', + 'Vandenboom', + 'Venhuizen', + 'Westermeyer', + 'Embury', + 'Cozort', + 'Crispo', + 'Woollard', + 'Thiery', + 'Lecy', + 'Terris', + 'Stencil', + 'Yero', + 'Bollard', + 'Chander', + 'Shepp', + 'Younkins', + 'Jon', + 'Anselm', + 'Deveraux', + 'Better', + 'Birth', + 'Hoskie', + 'Kirtz', + 'Encalade', + 'Aprea', + 'Bernick', + 'Bialy', + 'Bolenbaugh', + 'Chinea', + 'Cwiklinski', + 'Dunavan', + 'Dunckel', + 'Essen', + 'Ferner', + 'Gallick', + 'Gruba', + 'Hauss', + 'Intriago', + 'Javaid', + 'Kaney', + 'Klemens', + 'Kuriakose', + 'Leyda', + 'Losurdo', + 'Mcelhone', + 'Methot', + 'Morioka', + 'Mundorf', + 'Nocito', + 'Nordmann', + 'Oommen', + 'Pfahl', + 'Piquette', + 'Prinsen', + 'Sacramento', + 'Shenker', + 'Skidgel', + 'Sobalvarro', + 'Soldo', + 'Synan', + 'Tostenson', + 'Trotti', + 'Vienneau', + 'Vigneau', + 'Waitkus', + 'Wiess', + 'Bartmess', + 'Comparan', + 'Dalonzo', + 'Dutrow', + 'Fleegle', + 'Fronek', + 'Handrich', + 'Hazelip', + 'Heinig', + 'Macapagal', + 'Masciarelli', + 'Pitstick', + 'Radakovich', + 'Ripberger', + 'Schwebel', + 'Slomski', + 'Stinchfield', + 'Zegers', + 'Zeiser', + 'Kimmer', + 'Rippon', + 'Satz', + 'Bosques', + 'Mcnickle', + 'Yarwood', + 'Babar', + 'Ghazi', + 'Mcquary', + 'Africa', + 'Sofer', + 'Marsland', + 'Curby', + 'Odor', + 'Gillem', + 'Selmer', + 'Delmas', + 'Lamison', + 'Lanes', + 'Shadd', + 'Goard', + 'Haylock', + 'Sermon', + 'Meachem', + 'Vernet', + 'Akiona', + 'Avitabile', + 'Berkson', + 'Bisono', + 'Busic', + 'Caroselli', + 'Corradi', + 'Delval', + 'Egley', + 'Elkind', + 'Everling', + 'Ferrario', + 'Frumkin', + 'Gelder', + 'Gironda', + 'Glasheen', + 'Goette', + 'Gotts', + 'Haub', + 'Herro', + 'Hudzik', + 'Hula', + 'Inboden', + 'Isensee', + 'Kiesewetter', + 'Koetje', + 'Laughridge', + 'Lovewell', + 'Meeuwsen', + 'Mokry', + 'Navarez', + 'Plake', + 'Quain', + 'Reppucci', + 'Sorn', + 'Tallerico', + 'Uselman', + 'Verrastro', + 'Wineberg', + 'Blazina', + 'Falardeau', + 'Garavito', + 'Gellerman', + 'Havins', + 'Kurdziel', + 'Liedel', + 'Lofstrom', + 'Pakula', + 'Presby', + 'Ringstad', + 'Rokosz', + 'Schuchart', + 'Seckler', + 'Verderame', + 'Veselka', + 'Asfour', + 'Delanoy', + 'Fromer', + 'Koba', + 'Kostrzewa', + 'Melle', + 'Merkey', + 'Scalese', + 'Oritz', + 'Kilgour', + 'Piker', + 'Janet', + 'Huge', + 'Hails', + 'Dobey', + 'Escoe', + 'Rasool', + 'Gilcrest', + 'Codrington', + 'Jeangilles', + 'Outley', + 'Bambach', + 'Beaulac', + 'Begue', + 'Bobeck', + 'Buccino', + 'Carrigg', + 'Cranney', + 'Denninger', + 'Dicioccio', + 'Eapen', + 'Fargnoli', + 'Fatica', + 'Fernicola', + 'Forse', + 'Freck', + 'Gardipee', + 'Gibas', + 'Goeman', + 'Guadian', + 'Hlad', + 'Jakab', + 'Kishimoto', + 'Krenn', + 'Lagesse', + 'Lhommedieu', + 'Lusch', + 'Mausolf', + 'Mazzocchi', + 'Mcdavitt', + 'Noseworthy', + 'Passante', + 'Placzek', + 'Quamme', + 'Ringgenberg', + 'Spiegelman', + 'Vinluan', + 'Wachsman', + 'Bacigalupi', + 'Baechle', + 'Baetz', + 'Barsch', + 'Colbaugh', + 'Devoto', + 'Dimercurio', + 'Dosanjh', + 'Dukeman', + 'Ferger', + 'Garinger', + 'Grelle', + 'Guyett', + 'Harpenau', + 'Hundal', + 'Kamerer', + 'Klomp', + 'Licklider', + 'Martinec', + 'Matzek', + 'Nixdorf', + 'Pankonin', + 'Pogosyan', + 'Schweickert', + 'Smethurst', + 'Stroope', + 'Zwack', + 'Tebbetts', + 'Stains', + 'Tosado', + 'Carles', + 'Rings', + 'Hebard', + 'Choplin', + 'Townshend', + 'Doorn', + 'Aja', + 'Picking', + 'Oneall', + 'Logie', + 'Aro', + 'Dua', + 'Heney', + 'Manard', + 'Atchinson', + 'Breech', + 'Brashers', + 'Addams', + 'Nooner', + 'Barsh', + 'Orum', + 'Dancey', + 'Bamba', + 'Kareem', + 'Theard', + 'Marseille', + 'Molette', + 'Getachew', + 'Saintfleur', + 'Frimpong', + 'Anglada', + 'Attardo', + 'Barreira', + 'Bleicher', + 'Bonecutter', + 'Bricco', + 'Compian', + 'Creppel', + 'Cuadras', + 'Cuccio', + 'Cutsforth', + 'Dinino', + 'Eskelson', + 'Freemyer', + 'Friedhoff', + 'Grandt', + 'Holzmann', + 'Hoverson', + 'Hurteau', + 'Iacona', + 'Jergens', + 'Kingham', + 'Leiterman', + 'Leugers', + 'Leyh', + 'Lotti', + 'Majkowski', + 'Mossberg', + 'Nuffer', + 'Oaxaca', + 'Pagenkopf', + 'Paille', + 'Petzoldt', + 'Rogalla', + 'Siddens', + 'Siddoway', + 'Spatafora', + 'Tufo', + 'Weismann', + 'Werntz', + 'Wilz', + 'Ammirati', + 'Benninghoff', + 'Escarsega', + 'Fessel', + 'Hurless', + 'Jastrzebski', + 'Klingerman', + 'Kurilla', + 'Kuzmin', + 'Meserole', + 'Politz', + 'Pollino', + 'Rettke', + 'Sinay', + 'Strebeck', + 'Strycharz', + 'Suhre', + 'Thumm', + 'Trybus', + 'Uhrin', + 'Weisberger', + 'Zeger', + 'Carringer', + 'Sitts', + 'Lungren', + 'Iiams', + 'Sudbury', + 'Surrette', + 'Chellis', + 'Yore', + 'Joice', + 'Foot', + 'Ausley', + 'Scioneaux', + 'Mcaffee', + 'Pinn', + 'Maina', + 'Dorce', + 'Agrusa', + 'Albornoz', + 'Arave', + 'Bacallao', + 'Bendavid', + 'Bochner', + 'Bortle', + 'Carragher', + 'Chalfin', + 'Courtade', + 'Dagle', + 'Debuhr', + 'Fowble', + 'Galinsky', + 'Hardigree', + 'Haulk', + 'Hendron', + 'Herringshaw', + 'Jayaraman', + 'Koestler', + 'Konicek', + 'Kutscher', + 'Lachowicz', + 'Lafauci', + 'Lansky', + 'Lazarski', + 'Lolli', + 'Ludvigsen', + 'Manternach', + 'Martorelli', + 'Mcquillin', + 'Mikaelian', + 'Northcraft', + 'Nyborg', + 'Palone', + 'Peckman', + 'Schwebach', + 'Simbeck', + 'Sittler', + 'Udovich', + 'Viesca', + 'Yazell', + 'Zimmers', + 'Bielen', + 'Cohron', + 'Dearcos', + 'Feezor', + 'Hilgart', + 'Karriker', + 'Klingberg', + 'Leisenring', + 'Napora', + 'Nedved', + 'Okeson', + 'Seratt', + 'Trautner', + 'Trimarco', + 'Turkel', + 'Bronder', + 'Itani', + 'Verona', + 'Blackbird', + 'Laque', + 'Karpel', + 'Louro', + 'Hamson', + 'Ashland', + 'Gruel', + 'Breer', + 'Wesely', + 'Bebo', + 'Conery', + 'Mccarry', + 'Cradic', + 'Aytes', + 'Dikes', + 'Soltau', + 'Debois', + 'Berko', + 'Callins', + 'Anastacio', + 'Balbi', + 'Bata', + 'Bechel', + 'Borsuk', + 'Chihuahua', + 'Cindric', + 'Denapoli', + 'Dotzler', + 'Dusing', + 'Dziekan', + 'Eifler', + 'Franchino', + 'Garritano', + 'Herrarte', + 'Jaskot', + 'Kettell', + 'Kingsford', + 'Marsters', + 'Oshel', + 'Overacker', + 'Pagliarulo', + 'Pannier', + 'Pyun', + 'Rardon', + 'Reville', + 'Rogozinski', + 'Scatena', + 'Schoeppner', + 'Senkbeil', + 'Silkey', + 'Takhar', + 'Whitebread', + 'Wiech', + 'Adelsberger', + 'Aslinger', + 'Bhattacharyya', + 'Brege', + 'Burright', + 'Cafarella', + 'Chlebowski', + 'Decaprio', + 'Dilello', + 'Dresher', + 'Finkbiner', + 'Gerlich', + 'Ignasiak', + 'Kataoka', + 'Kearl', + 'Pingitore', + 'Sellick', + 'Sinning', + 'Stojanovic', + 'Vanasten', + 'Vanluven', + 'Westerfeld', + 'Mahala', + 'Biancardi', + 'Velardo', + 'Payes', + 'Debello', + 'Kyes', + 'Reever', + 'Joung', + 'Coran', + 'Perrow', + 'Linzer', + 'Birchett', + 'Poles', + 'Cajuste', + 'Albergo', + 'Andal', + 'Belaire', + 'Borell', + 'Bruehl', + 'Celani', + 'Cerruti', + 'Crellin', + 'Delcarlo', + 'Dubach', + 'Elicker', + 'Fialkowski', + 'Ganim', + 'Gladieux', + 'Glendening', + 'Glomski', + 'Kalp', + 'Kavan', + 'Kawabata', + 'Kever', + 'Kisch', + 'Maiorino', + 'Masaki', + 'Mcgeough', + 'Miyoshi', + 'Nand', + 'Nitka', + 'Novakovich', + 'Penagos', + 'Pierini', + 'Rassi', + 'Rorke', + 'Rosenboom', + 'Rossmann', + 'Scarfone', + 'Scarsella', + 'Siedschlag', + 'Sobotta', + 'Studnicka', + 'Teeling', + 'Tegtmeyer', + 'Woznick', + 'Beske', + 'Dersch', + 'Deschepper', + 'Duffner', + 'Geroux', + 'Lindvall', + 'Linnemann', + 'Roethler', + 'Scanlin', + 'Schaecher', + 'Schmude', + 'Schwertner', + 'Shimamoto', + 'Stratmann', + 'Stufflebean', + 'Ulatowski', + 'Witkop', + 'Landrus', + 'Sahin', + 'Araque', + 'Massett', + 'Meanor', + 'Sebo', + 'Delic', + 'Bryand', + 'Frederico', + 'Portuondo', + 'Verry', + 'Browe', + 'Winecoff', + 'Gipp', + 'Khamis', + 'Ingrum', + 'Gilliand', + 'Poinsett', + 'Hagley', + 'Valliant', + 'Henly', + 'Bingley', + 'Romulus', + 'Moyd', + 'Abascal', + 'Adelstein', + 'Arabian', + 'Barcelos', + 'Barot', + 'Cabacungan', + 'Darco', + 'Dickmeyer', + 'Gindi', + 'Grone', + 'Haberland', + 'Hachem', + 'Humbarger', + 'Insco', + 'Kravchuk', + 'Mackowski', + 'Madrazo', + 'Malesky', + 'Markowicz', + 'Mcconnon', + 'Meiring', + 'Micalizzi', + 'Moeser', + 'Mortier', + 'Muegge', + 'Ollar', + 'Pamperin', + 'Pusch', + 'Remache', + 'Roginski', + 'Rothbauer', + 'Sellin', + 'Stachurski', + 'Stelmack', + 'Suprenant', + 'Totzke', + 'Uemura', + 'Vandercook', + 'Yott', + 'Zaher', + 'Autio', + 'Barnhard', + 'Brys', + 'Chisenhall', + 'Deiters', + 'Fetsko', + 'Finzel', + 'Gangwer', + 'Grygiel', + 'Heidelberger', + 'Kommer', + 'Latchford', + 'Liszka', + 'Mcconaha', + 'Miazga', + 'Nettesheim', + 'Oelschlager', + 'Rafuse', + 'Reichow', + 'Santosuosso', + 'Sebastiani', + 'Serratore', + 'Spenner', + 'Steffenson', + 'Strehl', + 'Tropeano', + 'Vanstraten', + 'Vegh', + 'Virrueta', + 'Wilhide', + 'Prey', + 'Ullmer', + 'Ferraz', + 'Mazor', + 'Vinje', + 'Mory', + 'Rody', + 'Dowen', + 'Bord', + 'Rajkumar', + 'Qadir', + 'Turbin', + 'Rorex', + 'Wilmott', + 'Grandpre', + 'Bucker', + 'Reasonover', + 'Holoman', + 'Mustapha', + 'Warsame', + 'Laday', + 'Whack', + 'Blahut', + 'Boxell', + 'Britnell', + 'Buehl', + 'Burri', + 'Cesaro', + 'Degrand', + 'Demetro', + 'Fadeley', + 'Fischel', + 'Florer', + 'Givler', + 'Gockley', + 'Iuliano', + 'Koral', + 'Kotlarz', + 'Kraai', + 'Kvamme', + 'Latchaw', + 'Lopeman', + 'Manocchio', + 'Martinezgarcia', + 'Minehart', + 'Narasimhan', + 'Nier', + 'Niziolek', + 'Oliff', + 'Piascik', + 'Pitera', + 'Pronovost', + 'Roseboom', + 'Rosevear', + 'Runkles', + 'Santmyer', + 'Skillin', + 'Stamas', + 'Storbeck', + 'Teicher', + 'Titterington', + 'Tomkinson', + 'Tzeng', + 'Vukovic', + 'Wescoat', + 'Algeo', + 'Aronow', + 'Balbach', + 'Brockbank', + 'Caloca', + 'Caughlin', + 'Devincenzi', + 'Doetsch', + 'Filby', + 'Godar', + 'Keeven', + 'Marchetta', + 'Quiram', + 'Rudeen', + 'Siemen', + 'Suderman', + 'Tacke', + 'Walby', + 'Fram', + 'Maccarthy', + 'Fana', + 'Kimberley', + 'Richens', + 'Doser', + 'Bigford', + 'Brazie', + 'Haroon', + 'Mcginniss', + 'Knipfer', + 'Seltz', + 'Laton', + 'Balow', + 'Cramp', + 'Edger', + 'Alonge', + 'Beagles', + 'Ken', + 'Peary', + 'Lifsey', + 'Acy', + 'Lightbourne', + 'Antwi', + 'Arntzen', + 'Bracknell', + 'Brewbaker', + 'Carville', + 'Cinquemani', + 'Corales', + 'Corgan', + 'Craze', + 'Dechristopher', + 'Eltzroth', + 'Fjelstad', + 'Forinash', + 'Gudenkauf', + 'Hapeman', + 'Hassing', + 'Hurm', + 'Jaurigue', + 'Kneisel', + 'Kulwicki', + 'Lookingbill', + 'Moist', + 'Naderi', + 'Nicoli', + 'Nicoson', + 'Olvey', + 'Remaly', + 'Stare', + 'Steinruck', + 'Switala', + 'Tada', + 'Toves', + 'Traber', + 'Tuohey', + 'Venti', + 'Vinal', + 'Wahle', + 'Yarosh', + 'Balinski', + 'Bauknecht', + 'Bernauer', + 'Bink', + 'Chudzik', + 'Coppess', + 'Corrick', + 'Gruener', + 'Kutter', + 'Malkiewicz', + 'Marking', + 'Mcgrain', + 'Melberg', + 'Ohmann', + 'Pellicane', + 'Regehr', + 'Schmoldt', + 'Schmuhl', + 'Starmer', + 'Stiens', + 'Whilden', + 'Yearick', + 'Desmith', + 'Habiger', + 'Papay', + 'Study', + 'Toot', + 'Franzoni', + 'Neuhoff', + 'Boreman', + 'Sayas', + 'Hinks', + 'Dax', + 'Sasnett', + 'Hannis', + 'Rotan', + 'Haze', + 'Jennifer', + 'Barganier', + 'Milson', + 'Kinnie', + 'Boyde', + 'Dyce', + 'Cuttino', + 'Neals', + 'Mccovery', + 'Abaya', + 'Balz', + 'Bezold', + 'Breighner', + 'Buttacavoli', + 'Cattani', + 'Detzel', + 'Douthat', + 'Dunay', + 'Eicholtz', + 'Eirich', + 'Felkner', + 'Friedenberg', + 'Haskew', + 'Henes', + 'Jamroz', + 'Kelter', + 'Kutzer', + 'Laughner', + 'Livoti', + 'Magistro', + 'Makinson', + 'Manwell', + 'Mckimmy', + 'Mcwethy', + 'Pacholski', + 'Pankau', + 'Poh', + 'Purewal', + 'Remedios', + 'Ringuette', + 'Rocchi', + 'Rojero', + 'Sabina', + 'Schiffner', + 'Sellen', + 'Setaro', + 'Soledad', + 'Stoermer', + 'Tal', + 'Vanwyk', + 'Waack', + 'Xenos', + 'Yoakam', + 'Zweber', + 'Apachito', + 'Belluomini', + 'Cancelliere', + 'Cervini', + 'Davidovich', + 'Deguia', + 'Doxtator', + 'Errera', + 'Eshbaugh', + 'Mandt', + 'Pautler', + 'Raczynski', + 'Roemmich', + 'Rosamilia', + 'Shelhamer', + 'Vandevoorde', + 'Vanengen', + 'Vindiola', + 'Weyman', + 'Dufur', + 'Reaver', + 'Bugh', + 'Starley', + 'Macmullen', + 'Mataya', + 'Bucknell', + 'Taitano', + 'Coole', + 'Huguet', + 'Top', + 'Rockford', + 'Carrithers', + 'Garrell', + 'Toppins', + 'Mayner', + 'Dantes', + 'Tones', + 'Dauphine', + 'Shillingford', + 'Massiah', + 'Angermeier', + 'Arrizon', + 'Azer', + 'Badami', + 'Beeck', + 'Buddenhagen', + 'Cheyney', + 'Danielski', + 'Delgiorno', + 'Enslin', + 'Erber', + 'Fluegge', + 'Fresco', + 'Frishman', + 'Geigle', + 'Gervase', + 'Giangregorio', + 'Glauber', + 'Hedding', + 'Janota', + 'Labore', + 'Ladley', + 'Levee', + 'Lipuma', + 'Lomanto', + 'Magos', + 'Mangen', + 'Miltner', + 'Mitschke', + 'Pingley', + 'Puertas', + 'Schwed', + 'Seminario', + 'Sinsel', + 'Sliney', + 'Spielmann', + 'Standage', + 'Waas', + 'Cooprider', + 'Delguercio', + 'Dockham', + 'Dohse', + 'Doubrava', + 'Emerine', + 'Frazzini', + 'Godown', + 'Heidbreder', + 'Ladow', + 'Lariccia', + 'Molzahn', + 'Opiela', + 'Ordorica', + 'Otterness', + 'Owczarzak', + 'Rafalski', + 'Smigel', + 'Urbas', + 'Andon', + 'Kota', + 'Ruzzo', + 'Pheasant', + 'Proch', + 'Sullinger', + 'Ezra', + 'Portes', + 'Mynhier', + 'Depree', + 'Slight', + 'Selley', + 'Daughety', + 'Shamel', + 'Glasby', + 'Casher', + 'Brisby', + 'Whittley', + 'Brye', + 'Mackins', + 'Allam', + 'Berwanger', + 'Borgmeyer', + 'Brumlow', + 'Cashmore', + 'Clementz', + 'Coopman', + 'Corti', + 'Danzer', + 'Deater', + 'Delprado', + 'Dibuono', + 'Dwan', + 'Edling', + 'Ekins', + 'Feighner', + 'Galica', + 'Gasparro', + 'Geisert', + 'Gilvin', + 'Glotzbach', + 'Goostree', + 'Hollenkamp', + 'Hronek', + 'Kamins', + 'Khun', + 'Klimowicz', + 'Langella', + 'Letz', + 'Lindh', + 'Lycan', + 'Magouirk', + 'Mcbryar', + 'Milonas', + 'Patalano', + 'Petrides', + 'Plocher', + 'Signer', + 'Sinagra', + 'Taibi', + 'Thissen', + 'Thueson', + 'Tietje', + 'Trebilcock', + 'Zelek', + 'Alavez', + 'Beyersdorf', + 'Ferraiolo', + 'Flodin', + 'Fulwiler', + 'Gieselman', + 'Heisinger', + 'Hutmacher', + 'Laraia', + 'Lempke', + 'Marchiano', + 'Mendia', + 'Milberger', + 'Murri', + 'Willhelm', + 'Yannone', + 'Diss', + 'Golab', + 'Meuth', + 'Strebe', + 'Berenguer', + 'Cunard', + 'Girvan', + 'Pacer', + 'Nate', + 'Weare', + 'Dile', + 'Donate', + 'Pamer', + 'Charlet', + 'Roades', + 'Krah', + 'Merton', + 'Debrito', + 'Montel', + 'Guimont', + 'Caire', + 'Olley', + 'Ausborn', + 'Ramdass', + 'Stores', + 'Hush', + 'Watler', + 'Robotham', + 'Stanislaus', + 'Bellevue', + 'Almeter', + 'Bartold', + 'Bathgate', + 'Bollier', + 'Boundy', + 'Bushart', + 'Buzek', + 'Cauthon', + 'Daudelin', + 'Delguidice', + 'Depaolis', + 'Dysert', + 'Forsee', + 'Goglia', + 'Gruenhagen', + 'Guilfoil', + 'Guldin', + 'Gurnee', + 'Henzel', + 'Jurney', + 'Kable', + 'Korenek', + 'Kussman', + 'Liese', + 'Mauss', + 'Mexicano', + 'Morini', + 'Oathout', + 'Paragas', + 'Phommachanh', + 'Pixton', + 'Pucciarelli', + 'Rabine', + 'Ramlow', + 'Ravert', + 'Redhouse', + 'Renault', + 'Rybinski', + 'Sahlin', + 'Scherger', + 'Schoeffler', + 'Smolinsky', + 'Stadnik', + 'Stallsmith', + 'Timoney', + 'Whiteeagle', + 'Woodsmall', + 'Zinter', + 'Bargmann', + 'Basich', + 'Bossio', + 'Coutant', + 'Curcuru', + 'Duitsman', + 'Hunkele', + 'Kingry', + 'Kotek', + 'Mancusi', + 'Orama', + 'Paszek', + 'Schrodt', + 'Schuknecht', + 'Torsiello', + 'Troise', + 'Wernimont', + 'Wipperfurth', + 'Wissner', + 'Zahradnik', + 'Deasis', + 'Pac', + 'Vowles', + 'Montesi', + 'Carie', + 'Name', + 'Broy', + 'Hillson', + 'Exton', + 'Skerritt', + 'Ude', + 'Allston', + 'Cliatt', + 'Chevis', + 'Poitier', + 'Barrasso', + 'Bartnicki', + 'Broski', + 'Cobleigh', + 'Crickenberger', + 'Cruces', + 'Cumba', + 'Diodato', + 'Dipietrantonio', + 'Eyerly', + 'Fedler', + 'Fetting', + 'Francavilla', + 'Frein', + 'Gasparyan', + 'Gingold', + 'Gunnarson', + 'Houy', + 'Huelsmann', + 'Jeppsen', + 'Labreck', + 'Lefton', + 'Maenza', + 'Mauritz', + 'Mingione', + 'Mullany', + 'Mussell', + 'Muston', + 'Paraiso', + 'Peelman', + 'Penuel', + 'Piccola', + 'Punt', + 'Ramella', + 'Rauser', + 'Reas', + 'Reino', + 'Schlack', + 'Sebastiano', + 'Sgambati', + 'Shackett', + 'Szpak', + 'Thalacker', + 'Theissen', + 'Tutko', + 'Astarita', + 'Blazejewski', + 'Dejaynes', + 'Djordjevic', + 'Eckenroth', + 'Estala', + 'Giacomo', + 'Glaub', + 'Golubski', + 'Guerreiro', + 'Housholder', + 'Kashuba', + 'Klute', + 'Lennartz', + 'Messamore', + 'Rovito', + 'Schreurs', + 'Starcevich', + 'Starkel', + 'Szczerba', + 'Thomassen', + 'Varkey', + 'Yorio', + 'Guba', + 'Unzicker', + 'Howry', + 'Bido', + 'Farella', + 'Frane', + 'Werry', + 'Cornia', + 'Postal', + 'Humphres', + 'Ran', + 'Macnair', + 'Duston', + 'Aveni', + 'Mcconn', + 'Sistare', + 'Wadell', + 'Naraine', + 'Mubarak', + 'Lonzo', + 'Shyne', + 'Tilmon', + 'Symonette', + 'Shinholster', + 'Oree', + 'Ogarro', + 'Quashie', + 'Almario', + 'Antonsen', + 'Armetta', + 'Avetisyan', + 'Bania', + 'Barricklow', + 'Bloemker', + 'Cannavo', + 'Dolliver', + 'Espenshade', + 'Falor', + 'Fukuhara', + 'Gemme', + 'Goldfinger', + 'Gonya', + 'Hamamoto', + 'Hindi', + 'Hiraldo', + 'Holquin', + 'Janco', + 'Janow', + 'Lemming', + 'Macchio', + 'Mago', + 'Mavity', + 'Mcnamer', + 'Mushrush', + 'Niskanen', + 'Ohms', + 'Pawluk', + 'Popple', + 'Poser', + 'Schiavi', + 'Stram', + 'Streight', + 'Stueck', + 'Vansandt', + 'Vivona', + 'Vongphakdy', + 'Zalar', + 'Zipper', + 'Altic', + 'Billmeyer', + 'Boghosian', + 'Bohlke', + 'Cisewski', + 'Gabrielsen', + 'Gianotti', + 'Heffler', + 'Holian', + 'Kannenberg', + 'Lenius', + 'Manuelito', + 'Mugavero', + 'Reinier', + 'Rekowski', + 'Sadlier', + 'Scialdone', + 'Stromquist', + 'Vittetoe', + 'Vorwald', + 'Widrig', + 'Audi', + 'Peral', + 'Devery', + 'Gato', + 'Sower', + 'Vanes', + 'Bonnes', + 'Hense', + 'Counsell', + 'Frankie', + 'Colford', + 'Wanser', + 'Mickels', + 'Briddell', + 'Washinton', + 'Antilla', + 'Baxendale', + 'Beining', + 'Belveal', + 'Boedecker', + 'Bottenfield', + 'Bufano', + 'Castellana', + 'Chaikin', + 'Cherne', + 'Costilow', + 'Dzialo', + 'Goeken', + 'Gombert', + 'Hammerman', + 'Hansman', + 'Hartling', + 'Kalani', + 'Klich', + 'Kolodziejski', + 'Kramar', + 'Lapinsky', + 'Latterell', + 'Lipsitz', + 'Loma', + 'Lukenbill', + 'Marxen', + 'Metallo', + 'Molner', + 'Niquette', + 'Ostrand', + 'Pelster', + 'Previti', + 'Rennaker', + 'Roering', + 'Roode', + 'Saltos', + 'Sangiovanni', + 'Schiraldi', + 'Schlafer', + 'Schwering', + 'Seedorf', + 'Sklenar', + 'Spinello', + 'Steinhorst', + 'Urueta', + 'Vonstein', + 'Bonczek', + 'Casalino', + 'Chiaro', + 'Doffing', + 'Downham', + 'Gillotti', + 'Hearl', + 'Karges', + 'Kunesh', + 'Langeland', + 'Maertz', + 'Mattinson', + 'Mignano', + 'Pasquinelli', + 'Petracca', + 'Pherigo', + 'Pikus', + 'Reichmuth', + 'Schwegman', + 'Schwerdt', + 'Seelman', + 'Winquist', + 'Wyka', + 'Yahr', + 'Bunkers', + 'Delnegro', + 'Norder', + 'Manas', + 'Polites', + 'Grape', + 'Jares', + 'Surges', + 'Asa', + 'Copeman', + 'Askar', + 'Goman', + 'Whitmyer', + 'Cohran', + 'Imbert', + 'Beaner', + 'Hugger', + 'Petion', + 'Lauture', + 'Andringa', + 'Athanas', + 'Butrick', + 'Caronna', + 'Dedominicis', + 'Eligio', + 'Fasick', + 'Hilinski', + 'Hinely', + 'Idler', + 'Janosko', + 'Kempner', + 'Klosinski', + 'Lapeyrouse', + 'Lindroth', + 'Marcon', + 'Meding', + 'Peppin', + 'Quizon', + 'Rectenwald', + 'Roessner', + 'Roets', + 'Schonberger', + 'Szostek', + 'Wassink', + 'Whan', + 'Yeakle', + 'Alguire', + 'Bielenberg', + 'Bisaillon', + 'Bonenberger', + 'Centola', + 'Colaizzi', + 'Deroos', + 'Eberlin', + 'Ehrig', + 'Ferenc', + 'Freiermuth', + 'Fruchter', + 'Garnto', + 'Huxford', + 'Knous', + 'Luttman', + 'Mulry', + 'Schirm', + 'Stankovic', + 'Authier', + 'Derise', + 'Doo', + 'Kessen', + 'Maline', + 'Porada', + 'Vasconez', + 'Haseman', + 'Tonner', + 'Woodroof', + 'Bedrossian', + 'Cranmore', + 'Dodaro', + 'Hommes', + 'Harmony', + 'Peno', + 'Mccommon', + 'Colver', + 'Olinde', + 'Oba', + 'Colone', + 'Warbington', + 'Monie', + 'Whitmill', + 'Moxey', + 'Canion', + 'Mcclenney', + 'Hallmon', + 'Austill', + 'Berni', + 'Boehning', + 'Bueso', + 'Cefalo', + 'Conneely', + 'Demicco', + 'Dieppa', + 'Duris', + 'Durnil', + 'Erxleben', + 'Hashimi', + 'Hedquist', + 'Koc', + 'Lamattina', + 'Lassman', + 'Ligman', + 'Lukins', + 'Mackler', + 'Manolis', + 'Mou', + 'Oblak', + 'Omahoney', + 'Paolo', + 'Pollok', + 'Priess', + 'Reeh', + 'Rempfer', + 'Rickerd', + 'Schoettle', + 'Serritella', + 'Steedman', + 'Suss', + 'Tanimoto', + 'Thaden', + 'Thelin', + 'Vanwingerden', + 'Wacha', + 'Weldin', + 'Youkhana', + 'Bazzano', + 'Behring', + 'Caliri', + 'Cocchi', + 'Croissant', + 'Dibbern', + 'Figiel', + 'Flygare', + 'Grieshop', + 'Iten', + 'Kaupp', + 'Linnane', + 'Plybon', + 'Rappleye', + 'Romanik', + 'Saefong', + 'Schetter', + 'Schryer', + 'Siwik', + 'Snitker', + 'Tomasic', + 'Wavra', + 'Auen', + 'Thone', + 'Marso', + 'Shadid', + 'Cake', + 'Louvier', + 'Macia', + 'Areola', + 'Kardell', + 'Strome', + 'Coogle', + 'Delis', + 'Pistorius', + 'Raybourn', + 'Sula', + 'Math', + 'Sanda', + 'Renaldo', + 'Pat', + 'Florance', + 'Brank', + 'Alice', + 'Rosebrough', + 'Quiett', + 'Henigan', + 'Mcclees', + 'Dase', + 'Bagot', + 'Kings', + 'Lanehart', + 'Barbary', + 'Stitts', + 'Aurora', + 'Baldoni', + 'Barkalow', + 'Bohnet', + 'Bosshart', + 'Decapua', + 'Denbo', + 'Deneault', + 'Dinse', + 'Dul', + 'Estle', + 'Filipski', + 'Fishell', + 'Fluckiger', + 'Glassberg', + 'Janick', + 'Juda', + 'Kibbee', + 'Kreisler', + 'Lawther', + 'Levangie', + 'Lichtenwalner', + 'Lucking', + 'Meiner', + 'Mileham', + 'Milz', + 'Reposa', + 'Rinehimer', + 'Rupley', + 'Sandez', + 'Schinke', + 'Sharpnack', + 'Sineath', + 'Tax', + 'Thumma', + 'Urda', + 'Widdison', + 'Bergdoll', + 'Bruhl', + 'Chesmore', + 'Delfavero', + 'Ferderer', + 'Haueter', + 'Hirshberg', + 'Hollobaugh', + 'Lalama', + 'Mckeag', + 'Mehlhoff', + 'Mirchandani', + 'Orwick', + 'Puskarich', + 'Schlotzhauer', + 'Stoiber', + 'Swetz', + 'Basara', + 'Magaw', + 'Amble', + 'Hawe', + 'Toren', + 'Parilla', + 'Gowell', + 'Selkirk', + 'Edris', + 'Ariel', + 'Kihara', + 'Dunkerson', + 'Halk', + 'Mooty', + 'Tippen', + 'Fullenwider', + 'Herford', + 'Salton', + 'Feider', + 'Buckhannon', + 'Mckneely', + 'Milon', + 'Whiters', + 'Barasch', + 'Baria', + 'Basques', + 'Beavin', + 'Borre', + 'Branz', + 'Broers', + 'Conca', + 'Cortopassi', + 'Courchesne', + 'Crisanti', + 'Cumpian', + 'Dagan', + 'Dekay', + 'Demartin', + 'Dewaard', + 'Dowland', + 'Duffell', + 'Ebersol', + 'Faiola', + 'Frontz', + 'Fryling', + 'Garczynski', + 'Hanway', + 'Huettner', + 'Janovsky', + 'Johndrow', + 'Kahana', + 'Kaniewski', + 'Kulish', + 'Lich', + 'Lincks', + 'Loppnow', + 'Macnab', + 'Mcconaughy', + 'Melroy', + 'Noviello', + 'Orn', + 'Pacas', + 'Peppel', + 'Polidori', + 'Radi', + 'Riesgo', + 'Romanoski', + 'Sagrero', + 'Schirripa', + 'Spack', + 'Sternhagen', + 'Tamburri', + 'Traczyk', + 'Uballe', + 'Vandruff', + 'Voght', + 'Weant', + 'Weinel', + 'Angerman', + 'Boultinghouse', + 'Dolinar', + 'Dripps', + 'Dubow', + 'Ehrhard', + 'Janvrin', + 'Lazear', + 'Liddiard', + 'Madayag', + 'Mirkin', + 'Monticello', + 'Mulka', + 'Oliger', + 'Pierceall', + 'Pittner', + 'Polkowski', + 'Prindiville', + 'Rasnic', + 'Tellefsen', + 'Uffelman', + 'Vandenbergh', + 'Weisenbach', + 'Wiedmeyer', + 'Wintle', + 'Wisz', + 'Yorba', + 'Holtmeyer', + 'Tabet', + 'Laham', + 'Barsoum', + 'Henner', + 'Idle', + 'Shaft', + 'Rennels', + 'Swarm', + 'Forgie', + 'Khaled', + 'Avon', + 'Hewey', + 'Grober', + 'Pipe', + 'Macfadden', + 'Keath', + 'Fergason', + 'Polland', + 'Brownley', + 'Haslip', + 'Crocket', + 'Tines', + 'Juniel', + 'Opara', + 'Bethley', + 'Ambuehl', + 'Bagheri', + 'Baquera', + 'Bertoli', + 'Bisek', + 'Borroto', + 'Botten', + 'Bovenzi', + 'Bruntz', + 'Buehring', + 'Canche', + 'Cicco', + 'Dambach', + 'Delellis', + 'Deniston', + 'Dirico', + 'Feagle', + 'Frayne', + 'Haagenson', + 'Janicke', + 'Kashyap', + 'Kastel', + 'Kruck', + 'Langi', + 'Lapka', + 'Marschner', + 'Megia', + 'Nesta', + 'Nevala', + 'Oblinger', + 'Picchi', + 'Rodeffer', + 'Salkin', + 'Scavuzzo', + 'Sladky', + 'Soyars', + 'Suchil', + 'Thielbar', + 'Timoteo', + 'Vanhise', + 'Varden', + 'Waldoch', + 'Watling', + 'Werk', + 'Becvar', + 'Betteridge', + 'Bolliger', + 'Bonifield', + 'Buchberger', + 'Caprara', + 'Castrogiovanni', + 'Fallaw', + 'Geeting', + 'Hiegel', + 'Hulgan', + 'Kokesh', + 'Lanting', + 'Mcphetridge', + 'Nuxoll', + 'Soun', + 'Strothman', + 'Triska', + 'Vensel', + 'Wesolek', + 'Wixted', + 'Wolgemuth', + 'Yedinak', + 'Anthis', + 'Manfred', + 'Agans', + 'Lafoe', + 'Mcginnes', + 'Folwell', + 'Galvao', + 'Carmo', + 'Valin', + 'Woon', + 'Degregory', + 'Evangelist', + 'Coast', + 'Strater', + 'Decou', + 'Pears', + 'Nellums', + 'Kynard', + 'Boursiquot', + 'Ruffins', + 'Akhavan', + 'Baloga', + 'Barany', + 'Buche', + 'Davoli', + 'Fennewald', + 'Figler', + 'Frede', + 'Gannett', + 'Ghannam', + 'Handlon', + 'Herridge', + 'Jakel', + 'Kamphuis', + 'Kattan', + 'Kemplin', + 'Klecka', + 'Korver', + 'Kozakiewicz', + 'Linenberger', + 'Lofaso', + 'Lorman', + 'Lueder', + 'Mcconahay', + 'Mcternan', + 'Mench', + 'Norenberg', + 'Oro', + 'Ostenson', + 'Pant', + 'Peardon', + 'Pertuit', + 'Ritzert', + 'Salvetti', + 'Sandner', + 'Sheek', + 'Sniegowski', + 'Sorbo', + 'Sperbeck', + 'Sump', + 'Supinski', + 'Sweetin', + 'Toenjes', + 'Velotta', + 'Venier', + 'Veracruz', + 'Wender', + 'Yamagata', + 'Arostegui', + 'Balestra', + 'Blumstein', + 'Carras', + 'Grauberger', + 'Howdeshell', + 'Murayama', + 'Nippert', + 'Notch', + 'Reisert', + 'Sebren', + 'Tetzloff', + 'Venneman', + 'Douds', + 'Lineman', + 'Powles', + 'Huet', + 'Matto', + 'Roes', + 'Dillin', + 'Lagan', + 'Bakes', + 'Yann', + 'Canterberry', + 'Milum', + 'Hinderman', + 'Linzey', + 'Ballen', + 'Ventress', + 'Prysock', + 'Bangle', + 'Blinder', + 'Bugaj', + 'Carlisi', + 'Dimario', + 'Dzikowski', + 'Gaetz', + 'Galves', + 'Ghazal', + 'Golebiewski', + 'Hadsall', + 'Hogberg', + 'Krammer', + 'Kreisher', + 'Lamia', + 'Luhmann', + 'Lupa', + 'Michelotti', + 'Nesci', + 'Paape', + 'Posthumus', + 'Reth', + 'Sassman', + 'Schlechter', + 'Schlie', + 'Schumacker', + 'Seliger', + 'Shanholtzer', + 'Strojny', + 'Taglieri', + 'Tibbles', + 'Tregoning', + 'Valine', + 'Zeiset', + 'Antu', + 'Bierwirth', + 'Birenbaum', + 'Boeder', + 'Dobkins', + 'Fenoglio', + 'Jentsch', + 'Marcinkiewicz', + 'Mruk', + 'Muhlbauer', + 'Namba', + 'Oettinger', + 'Rigor', + 'Rothweiler', + 'Schmader', + 'Schork', + 'Vandevoort', + 'Brenny', + 'Neels', + 'Fodge', + 'Que', + 'Dalpe', + 'Guerard', + 'Lammey', + 'Alfredo', + 'Corrin', + 'Quarry', + 'Reise', + 'Derrow', + 'Worrel', + 'Tennent', + 'Cassis', + 'Winson', + 'Cornet', + 'Garlin', + 'Saucer', + 'Ursery', + 'Saffo', + 'Battee', + 'Ackerley', + 'Ackland', + 'Allmendinger', + 'Altamura', + 'Anastas', + 'Artola', + 'Baldassari', + 'Bayron', + 'Bouwkamp', + 'Buonopane', + 'Chronis', + 'Coffaro', + 'Dech', + 'Delfierro', + 'Depaulo', + 'Digges', + 'Dowda', + 'Drab', + 'Feijoo', + 'Formato', + 'Friedli', + 'Hanahan', + 'Hegna', + 'Igarashi', + 'Kamai', + 'Kory', + 'Kuzel', + 'Lewkowicz', + 'Lumbra', + 'Mccreadie', + 'Meisch', + 'Montoro', + 'Pamintuan', + 'Petrow', + 'Pulcini', + 'Shewell', + 'Spitznagel', + 'Swedlund', + 'Terhorst', + 'Wilberg', + 'Willwerth', + 'Affinito', + 'Baune', + 'Beichner', + 'Boutell', + 'Challender', + 'Ellestad', + 'Gomm', + 'Hochstatter', + 'Jasko', + 'Kielar', + 'Kimmerle', + 'Kirshenbaum', + 'Kotila', + 'Lecker', + 'Manross', + 'Mcnevin', + 'Neuburger', + 'Verderosa', + 'Wiltsey', + 'Caminero', + 'Gianfrancesco', + 'Shiverdecker', + 'Amman', + 'Flavell', + 'Oconor', + 'Shure', + 'Hanagan', + 'Bokor', + 'Mashaw', + 'Ground', + 'Brittenham', + 'Pinera', + 'Smaltz', + 'Hold', + 'Gallamore', + 'Delon', + 'Hearing', + 'Rynes', + 'Cocklin', + 'Cassie', + 'Calligan', + 'Josue', + 'Congo', + 'Tennell', + 'Blyther', + 'Azarian', + 'Bauernfeind', + 'Beeghly', + 'Berget', + 'Brayfield', + 'Cerasoli', + 'Dedecker', + 'Gloeckner', + 'Herriges', + 'Hoganson', + 'Ivancic', + 'Jakeway', + 'Kayne', + 'Kitko', + 'Kohlbeck', + 'Krabbenhoft', + 'Kumari', + 'Lauri', + 'Leiber', + 'Minke', + 'Montecino', + 'Moutray', + 'Munshi', + 'Ohlin', + 'Portocarrero', + 'Rados', + 'Roedl', + 'Rossing', + 'Schake', + 'Simonin', + 'Staffa', + 'Stroschein', + 'Titman', + 'Treder', + 'Vonada', + 'Xenakis', + 'Aulds', + 'Benedick', + 'Boulais', + 'Butikofer', + 'Butorac', + 'Contento', + 'Goetting', + 'Goldammer', + 'Hopke', + 'Koppes', + 'Phetteplace', + 'Roehrs', + 'Schul', + 'Slabach', + 'Steinmiller', + 'Sucharski', + 'Vorwerk', + 'Wahlert', + 'Wheatcraft', + 'Abellera', + 'Jutte', + 'Baumgarner', + 'Tijerino', + 'Awadallah', + 'Horen', + 'Lina', + 'Stanbrough', + 'College', + 'Jarry', + 'Keas', + 'Mordan', + 'Ramnauth', + 'Rena', + 'Wa', + 'Petters', + 'Ramnath', + 'Hellams', + 'Mamon', + 'Cheese', + 'Meggett', + 'Anttila', + 'Beilman', + 'Binsfeld', + 'Brining', + 'Brubeck', + 'Carcione', + 'Chandran', + 'Chaudhuri', + 'Cogliano', + 'Dimaano', + 'Dols', + 'Doughten', + 'Ehrenfeld', + 'Elena', + 'Fausnaugh', + 'Fetz', + 'Fogelson', + 'Fraleigh', + 'Gaza', + 'Giesey', + 'Gockel', + 'Gougeon', + 'Granito', + 'Grassia', + 'Hauserman', + 'Idrovo', + 'Iwan', + 'Janning', + 'Kaffenberger', + 'Kichline', + 'Kimoto', + 'Kolodny', + 'Kortum', + 'Lafevers', + 'Lodi', + 'Longton', + 'Ludke', + 'Manganelli', + 'Mccuan', + 'Merryfield', + 'Mezquita', + 'Morandi', + 'Neibauer', + 'Oran', + 'Ozaeta', + 'Pacha', + 'Palese', + 'Perala', + 'Pisarcik', + 'Pobanz', + 'Pommer', + 'Pontrelli', + 'Prabhakar', + 'Rehmann', + 'Scheunemann', + 'Severini', + 'Skalla', + 'Srinivas', + 'Stadtmiller', + 'Trentman', + 'Trinka', + 'Tutterow', + 'Vari', + 'Wence', + 'Zeff', + 'Anagnos', + 'Arvayo', + 'Bihl', + 'Darbyshire', + 'Deeg', + 'Domagalski', + 'Estenson', + 'Finkenbinder', + 'Gaboriault', + 'Kastens', + 'Lacek', + 'Merkin', + 'Mersman', + 'Nicolaus', + 'Offerdahl', + 'Pallett', + 'Platten', + 'Quesnell', + 'Skene', + 'Sondag', + 'Wolfrom', + 'Mineer', + 'Sor', + 'Canard', + 'Mcmeen', + 'Tur', + 'Giner', + 'Mackrell', + 'Alic', + 'Sampath', + 'Baby', + 'Beales', + 'Kadri', + 'Minot', + 'Bienvenue', + 'Millirons', + 'Woodstock', + 'Landing', + 'Limehouse', + 'Andonian', + 'Armentor', + 'Asai', + 'Cutaia', + 'Darji', + 'Delsanto', + 'Deutch', + 'Droge', + 'Emme', + 'Flenner', + 'Gaida', + 'Gladd', + 'Guettler', + 'Guggisberg', + 'Guier', + 'Habenicht', + 'Heininger', + 'Helfman', + 'Hiscox', + 'Holtorf', + 'Hovious', + 'Juul', + 'Lacock', + 'Lepisto', + 'Malanowski', + 'Marineau', + 'Matza', + 'Meffert', + 'Nuon', + 'Oneto', + 'Padmanabhan', + 'Pantuso', + 'Pesci', + 'Rosenbluth', + 'Rubano', + 'Sedlar', + 'Sferrazza', + 'Sifuentez', + 'Simione', + 'Torossian', + 'Vaux', + 'Weilbacher', + 'Wiatrek', + 'Brzoska', + 'Caltabiano', + 'Csaszar', + 'Eyerman', + 'Geissinger', + 'Gioffre', + 'Grilliot', + 'Grotz', + 'Harrower', + 'Jaroszewski', + 'Jokerst', + 'Kamali', + 'Kampmann', + 'Klemz', + 'Koike', + 'Lista', + 'Mcconkie', + 'Mencia', + 'Missler', + 'Olshefski', + 'Omdahl', + 'Penunuri', + 'Scheckel', + 'Schreiter', + 'Swackhammer', + 'Taflinger', + 'Tegethoff', + 'Ummel', + 'Wetsel', + 'Wissmann', + 'Porr', + 'Ramser', + 'Russett', + 'Clucas', + 'Matlin', + 'Noblet', + 'Boyan', + 'Koman', + 'Lope', + 'Deman', + 'Latendresse', + 'Bound', + 'Rijos', + 'Bouillon', + 'Crunkleton', + 'Jayson', + 'Anne', + 'Staude', + 'Sturn', + 'Burdell', + 'Arther', + 'Yett', + 'Woolcock', + 'Clemon', + 'Saintjean', + 'Sainvil', + 'Coverson', + 'Barroga', + 'Benedicto', + 'Borin', + 'Budrow', + 'Cuddihy', + 'Forness', + 'Gohman', + 'Hepker', + 'Hilscher', + 'Holien', + 'Holstad', + 'Hopfer', + 'Hulburt', + 'Kalter', + 'Kuehnle', + 'Lachica', + 'Macioce', + 'Massimo', + 'Matsubara', + 'Meaker', + 'Mehmedovic', + 'Minckler', + 'Miralles', + 'Mostek', + 'Oshita', + 'Parthasarathy', + 'Roszak', + 'Rottenberg', + 'Rydman', + 'Shankman', + 'Sprong', + 'Stenerson', + 'Strubel', + 'Tavano', + 'Thornberg', + 'Trumpower', + 'Whittinghill', + 'Altenhofen', + 'Bartolucci', + 'Debski', + 'Dekoning', + 'Dottavio', + 'Emminger', + 'Hodkinson', + 'Hurtubise', + 'Lauridsen', + 'Leinberger', + 'Luskin', + 'Pask', + 'Rehfeld', + 'Spagna', + 'Szumski', + 'Szymborski', + 'Teem', + 'Tritschler', + 'Tschantz', + 'Tsutsui', + 'Vanecek', + 'Haddaway', + 'Colombe', + 'Mayol', + 'Shivley', + 'Maturin', + 'Babe', + 'Bovey', + 'Bathe', + 'Belliard', + 'Loner', + 'Arrow', + 'Billa', + 'Mcneish', + 'Kinton', + 'Scarber', + 'Donson', + 'Atherley', + 'Abdulaziz', + 'Age', + 'Carreker', + 'Tory', + 'Leduff', + 'Wattley', + 'Altergott', + 'Belitz', + 'Bidinger', + 'Blauch', + 'Cariker', + 'Condren', + 'Curiale', + 'Dronet', + 'Elstad', + 'Esquerra', + 'Fread', + 'Gilb', + 'Goga', + 'Gonyo', + 'Grudzien', + 'Hino', + 'Ishler', + 'Jacober', + 'Kilty', + 'Kuhrt', + 'Lairmore', + 'Lamba', + 'Lorek', + 'Lucich', + 'Marcou', + 'Mcgath', + 'Menze', + 'Mindel', + 'Nabb', + 'Ottosen', + 'Pann', + 'Ratkowski', + 'Saurer', + 'Sedore', + 'Shonka', + 'Soberano', + 'Sossamon', + 'Stdennis', + 'Stillinger', + 'Tager', + 'Tersigni', + 'Tissue', + 'Trampe', + 'Twite', + 'Whitling', + 'Wiebusch', + 'Abundez', + 'Bisping', + 'Candella', + 'Dahill', + 'Groebner', + 'Gulbrandsen', + 'Hasenauer', + 'Heesch', + 'Hipwell', + 'Kamrowski', + 'Keyworth', + 'Kleinschmit', + 'Legorreta', + 'Minium', + 'Mixter', + 'Neiswonger', + 'Purk', + 'Rinkenberger', + 'Rosenkrans', + 'Rozenberg', + 'Simenson', + 'Soltes', + 'Storino', + 'Viereck', + 'Schaafsma', + 'Craigie', + 'Amorin', + 'Latner', + 'Bowmer', + 'Nasby', + 'Bada', + 'Rami', + 'Mcglashan', + 'Reede', + 'Police', + 'Cobey', + 'Dahir', + 'Dirden', + 'Destine', + 'Akkerman', + 'Azzopardi', + 'Blankenhorn', + 'Bolio', + 'Brandhorst', + 'Buchter', + 'Canul', + 'Cocozza', + 'Collantes', + 'Cronic', + 'Cullifer', + 'Delpizzo', + 'Demoranville', + 'Dolder', + 'Dvorsky', + 'Eggett', + 'Elgersma', + 'Episcopo', + 'Esses', + 'Fehlman', + 'Gansen', + 'Garciamartinez', + 'Goldwater', + 'Gushue', + 'Hittner', + 'Igel', + 'Jupin', + 'Kostoff', + 'Kruschke', + 'Kuechler', + 'Labs', + 'Lacerte', + 'Lagle', + 'Leischner', + 'Linders', + 'Marulanda', + 'Meindl', + 'Melman', + 'Menden', + 'Orbach', + 'Patak', + 'Patras', + 'Petroni', + 'Rabenold', + 'Rapisarda', + 'Rodenburg', + 'Roelle', + 'Schar', + 'Scherbarth', + 'Simar', + 'Thoen', + 'Trana', + 'Tuch', + 'Turko', + 'Wamser', + 'Weinfeld', + 'Wirz', + 'Zatorski', + 'Zbinden', + 'Aksamit', + 'Asebedo', + 'Biello', + 'Bouchey', + 'Callejo', + 'Espanol', + 'Flathers', + 'Kunka', + 'Liaw', + 'Mckowen', + 'Mitrano', + 'Needler', + 'Och', + 'Paolella', + 'Patricelli', + 'Recine', + 'Rengel', + 'Spinler', + 'Wagenaar', + 'Winnicki', + 'Eichert', + 'Dabb', + 'Imrie', + 'Antoni', + 'Lardner', + 'Maund', + 'Schou', + 'Brittin', + 'Anthon', + 'Was', + 'Nevis', + 'Delamar', + 'Mcnorton', + 'Tankard', + 'Boardley', + 'Garcon', + 'Wimes', + 'Antell', + 'Belmarez', + 'Boff', + 'Boughan', + 'Cando', + 'Carrender', + 'Carrieri', + 'Charnley', + 'Cittadino', + 'Cwynar', + 'Deupree', + 'Doepke', + 'Fasone', + 'Fauteux', + 'Foody', + 'Fornal', + 'Fust', + 'Gasner', + 'Gloe', + 'Gorter', + 'Grumbine', + 'Hancher', + 'Hapke', + 'Heckendorn', + 'Heinlen', + 'Hilgeman', + 'Kahre', + 'Kakos', + 'Kops', + 'Lahn', + 'Leiferman', + 'Lothamer', + 'Mallis', + 'Napierkowski', + 'Orbin', + 'Panno', + 'Piacente', + 'Posas', + 'Ragasa', + 'Sonora', + 'Stupka', + 'Tio', + 'Valido', + 'Weyrick', + 'Argall', + 'Arrighi', + 'Bohlken', + 'Desrocher', + 'Distad', + 'Erkkila', + 'Gherardi', + 'Goughnour', + 'Koltz', + 'Koperski', + 'Lafalce', + 'Lucken', + 'Meleski', + 'Mortellaro', + 'Nagorski', + 'Pedrotti', + 'Pruyn', + 'Revard', + 'Saffran', + 'Schnoebelen', + 'Sermersheim', + 'Skroch', + 'Vandervliet', + 'Alwood', + 'Bosso', + 'Hor', + 'Licerio', + 'Septer', + 'Labo', + 'Lessa', + 'Ooley', + 'Gorgas', + 'Medal', + 'Coull', + 'Creely', + 'Bolland', + 'Ishaq', + 'Legore', + 'Alicia', + 'Fillingame', + 'Levers', + 'Flight', + 'Woodrick', + 'Berrie', + 'Buckels', + 'Pigue', + 'Crosse', + 'Speakes', + 'Wynes', + 'Mussa', + 'Highbaugh', + 'Venning', + 'Dupas', + 'Mccastle', + 'Andreoni', + 'Bakula', + 'Besemer', + 'Blier', + 'Braaksma', + 'Brocco', + 'Cajas', + 'Campano', + 'Crapser', + 'Dentinger', + 'Deziel', + 'Dragos', + 'Ekblad', + 'Gargis', + 'Gilberto', + 'Guadron', + 'Hollern', + 'Leibensperger', + 'Lindaman', + 'Lumadue', + 'Mault', + 'Mieses', + 'Nanninga', + 'Nudd', + 'Ouch', + 'Ramin', + 'Reggio', + 'Ruttan', + 'Saccomanno', + 'Scheaffer', + 'Sohm', + 'Spaniol', + 'Stenner', + 'Strieter', + 'Takashima', + 'Vaid', + 'Venzke', + 'Wallwork', + 'Zaffuto', + 'Zaucha', + 'Zemel', + 'Zinni', + 'Alltop', + 'Ciolek', + 'Empie', + 'Flitton', + 'Gullikson', + 'Hassebrock', + 'Kanitz', + 'Kirschenmann', + 'Krivanek', + 'Loseke', + 'Mckercher', + 'Melching', + 'Nham', + 'Ormerod', + 'Randlett', + 'Reifel', + 'Sawada', + 'Sofranko', + 'Stoia', + 'Umeda', + 'Eagon', + 'Hucker', + 'Kenniston', + 'Salus', + 'Ayyad', + 'Camey', + 'Dacy', + 'Joa', + 'Peerson', + 'Rossy', + 'Aure', + 'Keetch', + 'Sprigg', + 'Southgate', + 'Parden', + 'Andris', + 'Bossman', + 'Blondell', + 'Carmickle', + 'Pelly', + 'Mceachron', + 'Marry', + 'Burel', + 'Shark', + 'Flash', + 'Rickenbacker', + 'Foots', + 'Sillah', + 'Almgren', + 'Awtrey', + 'Berganza', + 'Boehne', + 'Bralley', + 'Brosnahan', + 'Caddick', + 'Chandonnet', + 'Cullimore', + 'Darroch', + 'Eimers', + 'Flam', + 'Howerter', + 'Jerzak', + 'Kabler', + 'Kirkes', + 'Kopper', + 'Krakow', + 'Linskey', + 'Lizzi', + 'Luria', + 'Marcrum', + 'Mathy', + 'Matulich', + 'Miskin', + 'Moghadam', + 'Nagarajan', + 'Packham', + 'Papania', + 'Paup', + 'Rippeon', + 'Rolli', + 'Rubey', + 'Scherzinger', + 'Scrima', + 'Sharar', + 'Shoberg', + 'Stupar', + 'Tendler', + 'Tobiason', + 'Vanvooren', + 'Zisa', + 'Bindel', + 'Flasch', + 'Graetz', + 'Heintzman', + 'Kosanke', + 'Longden', + 'Mahfouz', + 'Mormile', + 'Nannini', + 'Olaes', + 'Panik', + 'Putzier', + 'Radilla', + 'Schaedler', + 'Schoepf', + 'Sianez', + 'Taucher', + 'Wiebelhaus', + 'Banka', + 'Console', + 'Derego', + 'Vile', + 'Colgin', + 'Drage', + 'Josten', + 'Luckadoo', + 'Ryen', + 'Bako', + 'Ow', + 'Patient', + 'Elmes', + 'Mossa', + 'Colee', + 'Comber', + 'Tippy', + 'Perrell', + 'Axon', + 'Rickson', + 'Postlewaite', + 'Lafargue', + 'Guffin', + 'Cains', + 'Dewindt', + 'Cathy', + 'Tallie', + 'Ausby', + 'Alires', + 'Baz', + 'Bergeman', + 'Bodensteiner', + 'Borghi', + 'Dematos', + 'Denzler', + 'Dorko', + 'Duffett', + 'Dykas', + 'Emerton', + 'Fenger', + 'Fosberg', + 'Gwinner', + 'Kniess', + 'Lerew', + 'Lohner', + 'Lun', + 'Maita', + 'Mandler', + 'Marcoe', + 'Nikolov', + 'Paschen', + 'Paver', + 'Prosperi', + 'Rackliff', + 'Roever', + 'Ruberg', + 'Ruest', + 'Schnick', + 'Schuur', + 'Sowash', + 'Zanca', + 'Brecheen', + 'Brusky', + 'Chauca', + 'Debernardi', + 'Froio', + 'Gadway', + 'Karoly', + 'Kintzel', + 'Kneisley', + 'Kruser', + 'Lindfors', + 'Lwin', + 'Oursler', + 'Peruski', + 'Petteys', + 'Rottmann', + 'Schroeck', + 'Stenglein', + 'Vigen', + 'Wempe', + 'Zehren', + 'Wollen', + 'Dismore', + 'Santalucia', + 'Laza', + 'Pesnell', + 'Litle', + 'Markson', + 'Piercefield', + 'Jerrett', + 'Virginia', + 'Demonbreun', + 'Tugman', + 'Ramoutar', + 'Bazin', + 'Ola', + 'Alamin', + 'Adebayo', + 'Berkland', + 'Bernt', + 'Briguglio', + 'Bulnes', + 'Burack', + 'Cantoran', + 'Giardini', + 'Goetzke', + 'Graziosi', + 'Guberman', + 'Kamaka', + 'Karvonen', + 'Kitz', + 'Kopera', + 'Krempa', + 'Linkenhoker', + 'Mascioli', + 'Matlick', + 'Mcmahill', + 'Medaglia', + 'Mirarchi', + 'Mondry', + 'Muhlestein', + 'Murty', + 'Orender', + 'Pesantez', + 'Postiglione', + 'Reisen', + 'Riff', + 'Scarantino', + 'Seelinger', + 'Seher', + 'Sharum', + 'Sorice', + 'Staebler', + 'Tanney', + 'Tech', + 'Tramontano', + 'Trude', + 'Vasudevan', + 'Wareing', + 'Westerhold', + 'Wohlfarth', + 'Achorn', + 'Boesel', + 'Calabaza', + 'Dunkleberger', + 'Erck', + 'Fanger', + 'Felmlee', + 'Friebel', + 'Gabrys', + 'Godsil', + 'Goldhammer', + 'Gourneau', + 'Kaseman', + 'Keysor', + 'Mccargar', + 'Mittag', + 'Narum', + 'Schoeneck', + 'Stenquist', + 'Sunderlin', + 'Tarazon', + 'Tietze', + 'Wemmer', + 'Witthuhn', + 'Durango', + 'Simerson', + 'Beber', + 'Bjorn', + 'Neuville', + 'Preas', + 'Reitter', + 'Senf', + 'Mcclatchy', + 'Sanor', + 'Benney', + 'Sarrazin', + 'Woodliff', + 'Bramlet', + 'Cullin', + 'Wessells', + 'Higgens', + 'Rout', + 'Craigen', + 'Ackers', + 'Wickliff', + 'Hofler', + 'Pilgram', + 'Mcfayden', + 'Dillworth', + 'Robenson', + 'Mateen', + 'Ambrogio', + 'Aoun', + 'Aranas', + 'Balsiger', + 'Bonzo', + 'Busam', + 'Casassa', + 'Ciborowski', + 'Cotterill', + 'Cressler', + 'Cristales', + 'Crumpacker', + 'Daloisio', + 'Damasco', + 'Depolo', + 'Diguglielmo', + 'Dominik', + 'Esbenshade', + 'Fineran', + 'Formisano', + 'Gandolfi', + 'Geidel', + 'Gerwitz', + 'Grammatico', + 'Idleman', + 'Iwinski', + 'Kerth', + 'Lacouture', + 'Lafoy', + 'Lapid', + 'Lardizabal', + 'Lembcke', + 'Maga', + 'Mahrt', + 'Maniatis', + 'Martinezlopez', + 'Martinovich', + 'Milham', + 'Muscatello', + 'Perezperez', + 'Quiocho', + 'Rickner', + 'Sackrider', + 'Schwarm', + 'Schwebke', + 'Scollard', + 'Seader', + 'Shutters', + 'Skare', + 'Slothower', + 'Steeber', + 'Want', + 'Cherubini', + 'Coslett', + 'Degener', + 'Dulak', + 'Faull', + 'Freyman', + 'Gatchel', + 'Ginzburg', + 'Gronberg', + 'Landeck', + 'Lehenbauer', + 'Lubke', + 'Mcconaughey', + 'Mendonsa', + 'Minnehan', + 'Palaguachi', + 'Peedin', + 'Raithel', + 'Rezabek', + 'Rolfson', + 'Schuitema', + 'Sjodin', + 'Underkoffler', + 'Verrilli', + 'Yogi', + 'Zimpfer', + 'Zingaro', + 'Butrum', + 'Ritson', + 'Martinka', + 'Cashatt', + 'Kearn', + 'Sawtell', + 'Boyster', + 'Broyhill', + 'Cockerell', + 'Thane', + 'Resende', + 'Pealer', + 'Perrot', + 'Everhardt', + 'Breach', + 'Bry', + 'Juma', + 'Mclaine', + 'Paddy', + 'Hennesy', + 'Ledee', + 'Web', + 'Delone', + 'Louison', + 'Hamiel', + 'Tutson', + 'Bellingham', + 'Brenn', + 'Bussen', + 'Charrette', + 'Denenberg', + 'Depascale', + 'Derner', + 'Dondlinger', + 'Favro', + 'Frana', + 'Goeser', + 'Guerrini', + 'Hamideh', + 'Hetu', + 'Hnat', + 'Hollerbach', + 'Kenagy', + 'Kregel', + 'Lammi', + 'Laubacher', + 'Madarang', + 'Mangine', + 'Marut', + 'Mcmahen', + 'Memoli', + 'Milko', + 'Morash', + 'Mulvehill', + 'Nelles', + 'Perfecto', + 'Perkes', + 'Pesantes', + 'Peschke', + 'Polyakov', + 'Preheim', + 'Prust', + 'Reha', + 'Richardt', + 'Rockers', + 'Sartwell', + 'Schedler', + 'Scheler', + 'Skop', + 'Stefko', + 'Tatlock', + 'Tiley', + 'Waldecker', + 'Weinbaum', + 'Aguallo', + 'Benassi', + 'Bezio', + 'Bockover', + 'Dobesh', + 'Encina', + 'Eversman', + 'Haverfield', + 'Heigl', + 'Holzhauser', + 'Liebenow', + 'Mesenbrink', + 'Mittendorf', + 'Normoyle', + 'Pickart', + 'Rosselot', + 'Shigley', + 'Skufca', + 'Stroot', + 'Walth', + 'Wernert', + 'Lahood', + 'Ragain', + 'Stumpe', + 'Kolle', + 'Minerd', + 'Dickeson', + 'Koone', + 'Stoessel', + 'Kington', + 'Soe', + 'Wailes', + 'Monet', + 'Mccullars', + 'Huguenin', + 'Warnell', + 'Calip', + 'Sandles', + 'Fayson', + 'Balik', + 'Bauermeister', + 'Bianculli', + 'Bin', + 'Bring', + 'Busenbark', + 'Canevari', + 'Crile', + 'Dyment', + 'Egelhoff', + 'Elbe', + 'Estudillo', + 'Feigel', + 'Flammer', + 'Folta', + 'Ghuman', + 'Hefferan', + 'Hennick', + 'Hosner', + 'Kilner', + 'Liuzzi', + 'Maj', + 'Massing', + 'Nicolaisen', + 'Ohlrich', + 'Ozdemir', + 'Piccininni', + 'Prem', + 'Primiano', + 'Reek', + 'Riling', + 'Rohweder', + 'Rosasco', + 'Sandau', + 'Santarsiero', + 'Schuhmacher', + 'Stenseth', + 'Stilts', + 'Strohmeier', + 'Thorell', + 'Torr', + 'Vaswani', + 'Yono', + 'Amadon', + 'Ballowe', + 'Betke', + 'Borgwardt', + 'Decelle', + 'Dibiasio', + 'Fieldhouse', + 'Hegyi', + 'Heuberger', + 'Kreiling', + 'Montney', + 'Sammut', + 'Senseney', + 'Takenaka', + 'Tramonte', + 'Zalesky', + 'Zumstein', + 'Bents', + 'Vandersluis', + 'Wieringa', + 'Houlton', + 'Lippens', + 'Maino', + 'Keeny', + 'Bethards', + 'Guillette', + 'Lenn', + 'Minge', + 'Masley', + 'Christley', + 'Gabrielle', + 'Bruington', + 'Perren', + 'Ander', + 'Leeb', + 'Callicott', + 'Peaster', + 'Hardister', + 'Daughtridge', + 'Mclauchlin', + 'Culliver', + 'Missouri', + 'Aloisi', + 'Barua', + 'Bezek', + 'Broshears', + 'Busbin', + 'Cajamarca', + 'Dellarocco', + 'Dezeeuw', + 'Ferrelli', + 'Fieber', + 'Fredin', + 'Giovannoni', + 'Glasner', + 'Grenda', + 'Haberl', + 'Heimsoth', + 'Heinl', + 'Hellickson', + 'Hernandezlopez', + 'Huckeby', + 'Jungman', + 'Langhans', + 'Lingelbach', + 'Manera', + 'Maneri', + 'Marzella', + 'Mennen', + 'Molesworth', + 'Nagano', + 'Narula', + 'Niner', + 'Nordhoff', + 'Olazabal', + 'Perfect', + 'Plonka', + 'Pund', + 'Reincke', + 'Schimek', + 'Seegert', + 'Summar', + 'Tanori', + 'Trethewey', + 'Wehler', + 'Wirthlin', + 'Wolaver', + 'Zuver', + 'Bendure', + 'Bither', + 'Bungert', + 'Chaviano', + 'Derhammer', + 'Disbro', + 'Facchini', + 'Hoefle', + 'Hoepner', + 'Kimmes', + 'Korus', + 'Manfredonia', + 'Neuser', + 'Samarin', + 'Sanghera', + 'Sherburn', + 'Shiplett', + 'Steckelberg', + 'Faist', + 'Cardy', + 'Colan', + 'Goodbar', + 'Boro', + 'Moden', + 'Hardick', + 'Esteve', + 'Rawling', + 'Benet', + 'Nabers', + 'Atkerson', + 'Countess', + 'Thwaites', + 'Caroline', + 'Whisonant', + 'Alridge', + 'Pamphile', + 'Abdelnour', + 'Allebach', + 'Armenti', + 'Baudendistel', + 'Biers', + 'Bockrath', + 'Borgert', + 'Bovino', + 'Burgamy', + 'Cadiente', + 'Calabretta', + 'Cariveau', + 'Christoffel', + 'Daigler', + 'Dannels', + 'Darnold', + 'Decock', + 'Dominski', + 'Fest', + 'Forren', + 'Freise', + 'Galperin', + 'Hackbart', + 'Holtzer', + 'Idell', + 'Kapala', + 'Kohlenberg', + 'Kolton', + 'Lemburg', + 'Lievanos', + 'Maranan', + 'Marchitto', + 'Masini', + 'Mayabb', + 'Mccrossen', + 'Metrick', + 'Molinelli', + 'Oehlert', + 'Parlee', + 'Pizzini', + 'Polachek', + 'Salmans', + 'Selbe', + 'Sickman', + 'Stegmaier', + 'Sulek', + 'Thall', + 'Tiznado', + 'Tonini', + 'Trostel', + 'Warshawsky', + 'Aument', + 'Byrer', + 'Dechaine', + 'Fearnow', + 'Gallicchio', + 'Gertler', + 'Greubel', + 'Hironaka', + 'Kashner', + 'Kleffner', + 'Korthals', + 'Kundinger', + 'Lenger', + 'Lingafelter', + 'Luczynski', + 'Ostermeier', + 'Petrasek', + 'Righetti', + 'Tvedt', + 'Weindel', + 'Wurtzel', + 'Zumbro', + 'Wikel', + 'Burdi', + 'Ozturk', + 'Parmele', + 'Oteri', + 'Alexa', + 'Erven', + 'Keng', + 'Fare', + 'Sade', + 'Saw', + 'Jaquay', + 'Pillay', + 'Kearsley', + 'Kirkby', + 'Game', + 'Herst', + 'Vallie', + 'Bayon', + 'Whitler', + 'Pe', + 'Lockerman', + 'Cogle', + 'Rouzer', + 'Curling', + 'Mandley', + 'Kleckley', + 'Buckson', + 'Risby', + 'Averhart', + 'Almendariz', + 'Angelopoulos', + 'Brallier', + 'Decaire', + 'Deloria', + 'Derham', + 'Drudge', + 'Eckelberry', + 'Ehling', + 'Engebretsen', + 'Ercole', + 'Fiscal', + 'Gabino', + 'Gelvin', + 'Giannetto', + 'Godeaux', + 'Goshert', + 'Hedrich', + 'Ioannou', + 'Jungbluth', + 'Kia', + 'Krusemark', + 'Lader', + 'Lythgoe', + 'Malinak', + 'Mcinvale', + 'Melis', + 'Metsker', + 'Minasyan', + 'Nuhfer', + 'Omana', + 'Parco', + 'Pha', + 'Phanthavong', + 'Proa', + 'Sarli', + 'Schirtzinger', + 'Schlotter', + 'Sharrar', + 'Spielberg', + 'Stelzner', + 'Tschudy', + 'Utke', + 'Weipert', + 'Yera', + 'Berkemeier', + 'Bothun', + 'Dalporto', + 'Deschler', + 'Dragonetti', + 'Hasz', + 'Holtzinger', + 'Kallal', + 'Kesinger', + 'Kilfoyle', + 'Kobylinski', + 'Kramme', + 'Kreh', + 'Lindseth', + 'Plaugher', + 'Rehfeldt', + 'Repine', + 'Roudabush', + 'Swoveland', + 'Teper', + 'Tucek', + 'Wadding', + 'Wenzlick', + 'Ghobrial', + 'Golberg', + 'Soyka', + 'Matura', + 'Moras', + 'Natter', + 'Apps', + 'Imran', + 'Rossel', + 'Harne', + 'Les', + 'Silla', + 'Deblanc', + 'Rhinehardt', + 'Delaware', + 'Alkins', + 'Laidley', + 'Maree', + 'Cassells', + 'Abdulrahman', + 'Cange', + 'Devone', + 'Eustache', + 'Negash', + 'Tanks', + 'Sivels', + 'Cabbagestalk', + 'Ahlin', + 'Akard', + 'Barbaree', + 'Bielat', + 'Bressman', + 'Capurro', + 'Cortazar', + 'Dauphinee', + 'Dornak', + 'Eckl', + 'Eisenhuth', + 'Fazzini', + 'Fraim', + 'Glaab', + 'Glod', + 'Guedea', + 'Hearty', + 'Hinostroza', + 'Honold', + 'Jostes', + 'Korzeniewski', + 'Lobell', + 'Lopardo', + 'Middlekauff', + 'Monfils', + 'Oshana', + 'Schiappa', + 'Schubach', + 'Servantez', + 'Shaler', + 'Siverson', + 'Slimp', + 'Slovacek', + 'Staat', + 'Strassman', + 'Waffle', + 'Wuebker', + 'Beigel', + 'Berardo', + 'Berkery', + 'Bloyer', + 'Cronkright', + 'Cuautle', + 'Devenny', + 'Ghrist', + 'Gipple', + 'Gwilliam', + 'Hunzeker', + 'Ierardi', + 'Kathol', + 'Kienle', + 'Krack', + 'Loeper', + 'Minchey', + 'Pecht', + 'Schaberg', + 'Schollmeyer', + 'Siniscalchi', + 'Toback', + 'Tramp', + 'Vandaele', + 'Witzig', + 'Wivell', + 'Moros', + 'Saso', + 'Gares', + 'Heagle', + 'Murrillo', + 'Stankey', + 'Shamon', + 'Avram', + 'Achor', + 'Ovens', + 'Rames', + 'Perris', + 'Kernes', + 'Semmes', + 'Thaw', + 'Stevison', + 'Clemetson', + 'Belmar', + 'Guster', + 'Bascomb', + 'Adrien', + 'Jeanpaul', + 'Alabi', + 'Jallow', + 'Atamian', + 'Basque', + 'Bubier', + 'Casad', + 'Czekaj', + 'Dejoy', + 'Dulworth', + 'Fatula', + 'Favale', + 'Feutz', + 'Freundlich', + 'Frid', + 'Gagan', + 'Gaughran', + 'Guderian', + 'Hagemeister', + 'Haser', + 'Leibman', + 'Meddings', + 'Narlock', + 'Offenberger', + 'Pesa', + 'Poupard', + 'Raus', + 'Repetti', + 'Revello', + 'Robarts', + 'Rowin', + 'Saltarelli', + 'Sanghvi', + 'Schleyer', + 'Silba', + 'Steuck', + 'Stoffers', + 'Tangredi', + 'Taussig', + 'Tiso', + 'Wehmeier', + 'Zwiefelhofer', + 'Bartelson', + 'Brabender', + 'Cornfield', + 'Davtyan', + 'Delnero', + 'Frontino', + 'Gathman', + 'Graessle', + 'Hinchcliff', + 'Houdeshell', + 'Kapler', + 'Karabin', + 'Kerestes', + 'Lemmen', + 'Merkt', + 'Mitro', + 'Nahm', + 'Nancarrow', + 'Novakowski', + 'Parraz', + 'Revolorio', + 'Schamel', + 'Scowden', + 'Steever', + 'Suastegui', + 'Villarin', + 'Wuellner', + 'Dooly', + 'Erno', + 'Arbelo', + 'Groshek', + 'Boliver', + 'Gane', + 'Bees', + 'Dowds', + 'Newmann', + 'Kewley', + 'Stile', + 'Lobe', + 'Skeet', + 'Burgen', + 'Mckamie', + 'Hubanks', + 'Suleman', + 'Billey', + 'Efferson', + 'Mcleary', + 'Housen', + 'Shambley', + 'Fanfan', + 'Bacca', + 'Battaglini', + 'Bonfanti', + 'Bongers', + 'Butzin', + 'Caira', + 'Councilman', + 'Crounse', + 'Dadisman', + 'Donais', + 'Estabrooks', + 'Fornoff', + 'Froh', + 'Gaige', + 'Garofolo', + 'Grivas', + 'Jacuinde', + 'Kalmus', + 'Kientz', + 'Kostenko', + 'Kras', + 'Lagoy', + 'Larzelere', + 'Lizer', + 'Maric', + 'Mayette', + 'Mcfeeters', + 'Meadowcroft', + 'Newgent', + 'Parpart', + 'Pauwels', + 'Perriello', + 'Persichetti', + 'Proietti', + 'Siefring', + 'Simones', + 'Taliercio', + 'Thilges', + 'Thumann', + 'Thun', + 'Tuomi', + 'Uhde', + 'Umscheid', + 'Uran', + 'Velador', + 'Veltkamp', + 'Waddoups', + 'Yeley', + 'Bihn', + 'Bladow', + 'Boeh', + 'Chadderdon', + 'Ensing', + 'Fasbender', + 'Folkert', + 'Goellner', + 'Heitmeyer', + 'Iovine', + 'Klinke', + 'Nessel', + 'Perleberg', + 'Rajagopal', + 'Sackmann', + 'Sapio', + 'Schickling', + 'Schliep', + 'Siminski', + 'Sirrine', + 'Sporn', + 'Stockburger', + 'Tangonan', + 'Tarkowski', + 'Tartaglione', + 'Traum', + 'Vanoverbeke', + 'Weirauch', + 'Wellendorf', + 'Wonnacott', + 'Camplin', + 'Leth', + 'Meltz', + 'Cavero', + 'Florido', + 'Tremont', + 'Riviello', + 'Piotter', + 'Munce', + 'Trescott', + 'Eben', + 'Vaillant', + 'Furches', + 'Bazen', + 'Esse', + 'Losier', + 'Zahir', + 'Lazier', + 'Lightell', + 'Christal', + 'Behe', + 'Blayney', + 'Buchalter', + 'Demarsh', + 'Dhondt', + 'Diefendorf', + 'Dillavou', + 'Dombkowski', + 'Duchow', + 'Fettes', + 'Gallaga', + 'Gallet', + 'Haaf', + 'Hartinger', + 'Jech', + 'Klas', + 'Kostal', + 'Kubler', + 'Leisey', + 'Leisinger', + 'Marinas', + 'Mcpeck', + 'Miccio', + 'Mikkola', + 'Morath', + 'Olthoff', + 'Pacific', + 'Penado', + 'Petronio', + 'Pirani', + 'Pitones', + 'Pociask', + 'Ratay', + 'Riesberg', + 'Ruberto', + 'Sabet', + 'Sabic', + 'Simonich', + 'Skains', + 'Skarzynski', + 'Spreeman', + 'Steig', + 'Struckhoff', + 'Trolinger', + 'Uliano', + 'Vaquerano', + 'Zukas', + 'Zwahlen', + 'Amborn', + 'Amspacher', + 'Azzaro', + 'Bartoletti', + 'Berkstresser', + 'Buboltz', + 'Ekstein', + 'Fohl', + 'Heinzel', + 'Hellmer', + 'Kapfer', + 'Kurka', + 'Mccreless', + 'Miyahira', + 'Nebergall', + 'Orlosky', + 'Pajor', + 'Quartararo', + 'Rahilly', + 'Rzasa', + 'Sabas', + 'Slutz', + 'Speros', + 'Stumpp', + 'Tamburo', + 'Tesler', + 'Tonkovich', + 'Urbieta', + 'Vallandingham', + 'Youngdahl', + 'Juliana', + 'Rienstra', + 'Prideaux', + 'Coval', + 'Hausen', + 'Seith', + 'Ny', + 'Bian', + 'Gressman', + 'Yanick', + 'Mannina', + 'Nater', + 'Gurry', + 'Vaile', + 'Sortor', + 'Woodington', + 'Apollo', + 'Mozley', + 'Patience', + 'Hearron', + 'Milloy', + 'Huntsberry', + 'Polidore', + 'Ridges', + 'Bonton', + 'Mercadel', + 'Alikhan', + 'Antis', + 'Bartosiewicz', + 'Brems', + 'Clopper', + 'Colato', + 'Collver', + 'Daino', + 'Degrande', + 'Dellis', + 'Depner', + 'Disantis', + 'Dolecki', + 'Dollens', + 'Eliasen', + 'Fasig', + 'Favinger', + 'Furuta', + 'Gharibian', + 'Gombar', + 'Gordo', + 'Gornik', + 'Gulas', + 'Khoshaba', + 'Laurita', + 'Liby', + 'Linhardt', + 'Lookabaugh', + 'Lorincz', + 'Mautner', + 'Mcquigg', + 'Meine', + 'Melaragno', + 'Meroney', + 'Mikesh', + 'Miu', + 'Monasterio', + 'Navarete', + 'Orendain', + 'Puricelli', + 'Riede', + 'Rubis', + 'Sandness', + 'Schellhase', + 'Stehlin', + 'Sunder', + 'Teaney', + 'Terman', + 'Tith', + 'Totino', + 'Tudisco', + 'Urwin', + 'Vandrunen', + 'Vasicek', + 'Youtz', + 'Berwald', + 'Bilow', + 'Bubolz', + 'Cieslewicz', + 'Denbleyker', + 'Ensinger', + 'Gantenbein', + 'Gurnsey', + 'Herceg', + 'Kless', + 'Kollias', + 'Leppek', + 'Naeve', + 'Oncale', + 'Pastran', + 'Pinyan', + 'Porrata', + 'Pustejovsky', + 'Renko', + 'Scioli', + 'Sinkhorn', + 'Sporrer', + 'Tomkiewicz', + 'Weisbeck', + 'Gautam', + 'Gleed', + 'Shave', + 'Crotzer', + 'Demarr', + 'Reckard', + 'Coyt', + 'Norberto', + 'Ury', + 'Crispen', + 'Parcells', + 'Meiklejohn', + 'Risden', + 'Bracker', + 'Askari', + 'Hyneman', + 'Auberry', + 'Bruney', + 'Weakly', + 'Ysaguirre', + 'Calender', + 'Benison', + 'Nazaire', + 'Pondexter', + 'Fryson', + 'Aguino', + 'Antonino', + 'Babilonia', + 'Banfill', + 'Beger', + 'Berardino', + 'Bizub', + 'Contractor', + 'Convey', + 'Cossairt', + 'Cruzen', + 'Dible', + 'Dorning', + 'Ellena', + 'Fafard', + 'Fano', + 'Favaro', + 'Feeler', + 'Foulger', + 'Gulbrandson', + 'Heckaman', + 'Heimerman', + 'Herms', + 'Hotchkin', + 'Jinright', + 'Kisler', + 'Kontz', + 'Kryder', + 'Lopezperez', + 'Lumm', + 'Mcelravy', + 'Meditz', + 'Melucci', + 'Meras', + 'Miyahara', + 'Musella', + 'Nelis', + 'Nhem', + 'Olivan', + 'Popson', + 'Presgraves', + 'Reindel', + 'Riege', + 'Rivenburgh', + 'Sahl', + 'Selberg', + 'Tashiro', + 'Todorov', + 'Toutant', + 'Turski', + 'Vankuren', + 'Westrup', + 'Beeney', + 'Bickhart', + 'Borkenhagen', + 'Bukoski', + 'Citrin', + 'Civello', + 'Forstrom', + 'Froning', + 'Geiler', + 'Hargadon', + 'Hemric', + 'Jeffus', + 'Klingele', + 'Kooiker', + 'Lizalde', + 'Nardiello', + 'Pestka', + 'Pignato', + 'Pudwill', + 'Rabelo', + 'Remund', + 'Skluzacek', + 'Stegenga', + 'Steidle', + 'Stenz', + 'Terlecki', + 'Vanselow', + 'Waskey', + 'Azhar', + 'Wroe', + 'Tool', + 'Leibert', + 'Vary', + 'Scovell', + 'Derick', + 'Arrey', + 'Cavness', + 'Garley', + 'Sholtz', + 'Legard', + 'Heyliger', + 'Thorns', + 'Sowells', + 'Alemu', + 'Aragones', + 'Ayllon', + 'Baab', + 'Blankenbeckler', + 'Brengle', + 'Burick', + 'Deuser', + 'Disabato', + 'Doddridge', + 'Dolinski', + 'Economy', + 'Ems', + 'Hagenow', + 'Iwen', + 'Kiesler', + 'Lehrmann', + 'Loisel', + 'Mallicoat', + 'Mansouri', + 'Marse', + 'Mccartt', + 'Menninger', + 'Montee', + 'Nappa', + 'Ohanesian', + 'Podgurski', + 'Prosch', + 'Puder', + 'Ritthaler', + 'Rodelo', + 'Shipper', + 'Shorkey', + 'Sirna', + 'Smedberg', + 'Smink', + 'Strahle', + 'Troeger', + 'Twaddell', + 'Vandyk', + 'Wandrey', + 'Yaworski', + 'Zagami', + 'Duecker', + 'Finlinson', + 'Frysinger', + 'Grush', + 'Knackstedt', + 'Morozov', + 'Murgia', + 'Naffziger', + 'Ontko', + 'Piltz', + 'Roskelley', + 'Sonderman', + 'Garrand', + 'Kopack', + 'Theys', + 'Sanseverino', + 'Budai', + 'Selwyn', + 'Assante', + 'Nary', + 'Fildes', + 'Tano', + 'Hogen', + 'Gennett', + 'Melka', + 'Thorner', + 'Grandjean', + 'Dury', + 'Gerrald', + 'Quilling', + 'Mccallon', + 'Preister', + 'Kydd', + 'Cranshaw', + 'Folson', + 'Roker', + 'Dockett', + 'Stfort', + 'Haymer', + 'Njie', + 'Adamik', + 'Aredondo', + 'Bathrick', + 'Beldin', + 'Blackwater', + 'Branscom', + 'Cappucci', + 'Cartelli', + 'Carullo', + 'Cunneen', + 'Davee', + 'Deboy', + 'Defrates', + 'Esham', + 'Furio', + 'Garverick', + 'Gimlin', + 'Gosline', + 'Gromer', + 'Halbig', + 'Hasbrook', + 'Holgerson', + 'Hupfer', + 'Jochem', + 'Kihn', + 'Klotzbach', + 'Lantagne', + 'Leichter', + 'Lerette', + 'Lupu', + 'Machorro', + 'Mieles', + 'Mikulec', + 'Mirante', + 'Nasrallah', + 'Piccini', + 'Pinkhasov', + 'Poplaski', + 'Pottenger', + 'Rahrig', + 'Ranganathan', + 'Ravan', + 'Righi', + 'Rogacki', + 'Sadlon', + 'Salafia', + 'Schlitz', + 'Slayback', + 'Stetzel', + 'Tamargo', + 'Tenore', + 'Verkuilen', + 'Vuncannon', + 'Waggle', + 'Bacorn', + 'Boerema', + 'Cimorelli', + 'Ciresi', + 'Dethlefs', + 'Dimarzo', + 'Ficco', + 'Floresca', + 'Gnau', + 'Hefel', + 'Holbein', + 'Klepacki', + 'Konigsberg', + 'Lienau', + 'Malsam', + 'Meidl', + 'Nawabi', + 'Netzley', + 'Renbarger', + 'Rumbold', + 'Sarafian', + 'Sonnenfeld', + 'Tindol', + 'Trettin', + 'Tuckerman', + 'Vanderweele', + 'Weppler', + 'Westbay', + 'Zaveri', + 'Boran', + 'Deighan', + 'Rothery', + 'Yom', + 'Gatley', + 'Caldron', + 'Lucado', + 'Dromgoole', + 'Novell', + 'Sherriff', + 'Gerrick', + 'Balgobin', + 'Danger', + 'Sookram', + 'Daron', + 'Knibbs', + 'Faggart', + 'Beidleman', + 'Russey', + 'Lagrand', + 'Bluett', + 'Glaspy', + 'Baldon', + 'Trueheart', + 'Cradle', + 'Asfaw', + 'Ballinas', + 'Bogdon', + 'Brizzi', + 'Carrio', + 'Cherny', + 'Crogan', + 'Depierro', + 'Dhami', + 'Dresden', + 'Finnicum', + 'Geltz', + 'Granade', + 'Granieri', + 'Guia', + 'Hashagen', + 'Hollick', + 'Jicha', + 'Jollie', + 'Kathan', + 'Malara', + 'Manabat', + 'Mehall', + 'Midcap', + 'Mitre', + 'Newburg', + 'Parveen', + 'Pianka', + 'Plouff', + 'Posillico', + 'Ransier', + 'Reano', + 'Roskam', + 'Rufer', + 'Schnetzer', + 'Scorsone', + 'Sitterly', + 'Skilton', + 'Sohail', + 'Starin', + 'Stavish', + 'Tufaro', + 'Vano', + 'Vinsant', + 'Vlahakis', + 'Vondrasek', + 'Waldroop', + 'Wamboldt', + 'Achatz', + 'Bomkamp', + 'Fetzner', + 'Gemmer', + 'Haroutunian', + 'Hurtig', + 'Juncaj', + 'Kleban', + 'Knier', + 'Kopischke', + 'Kugelman', + 'Lacoss', + 'Meulemans', + 'Neyens', + 'Niccoli', + 'Oberhaus', + 'Penkala', + 'Podoll', + 'Roupp', + 'Scozzari', + 'Siverling', + 'Uhls', + 'Werber', + 'Grealish', + 'Montieth', + 'Haik', + 'Kuri', + 'Kanaan', + 'Prenatt', + 'Dingledine', + 'Mccamy', + 'Balin', + 'Droney', + 'Clyatt', + 'Ramone', + 'Anglen', + 'Mathus', + 'Bagent', + 'Lamarque', + 'Arscott', + 'Romes', + 'Speigner', + 'Latouche', + 'Tripplett', + 'Eversley', + 'Aquirre', + 'Bernales', + 'Bouthillier', + 'Cavendish', + 'Detienne', + 'Dewbre', + 'Dimuro', + 'Dosh', + 'Dunklee', + 'Duyck', + 'Emilio', + 'Ence', + 'Garofano', + 'Gellis', + 'Haertel', + 'Handyside', + 'Hornburg', + 'Jenniges', + 'Kallhoff', + 'Klontz', + 'Langsdorf', + 'Leabo', + 'Lorette', + 'Maracle', + 'Merta', + 'Muoio', + 'Nierenberg', + 'Oborn', + 'Osorto', + 'Ruscitti', + 'Santaella', + 'Spinnato', + 'Stentz', + 'Stocke', + 'Sundt', + 'Thorup', + 'Tresch', + 'Urdaneta', + 'Uttech', + 'Vosler', + 'Wieand', + 'Zacharia', + 'Zeleznik', + 'Zoucha', + 'Zuch', + 'Abrell', + 'Atiyeh', + 'Aydt', + 'Cleeton', + 'Crisan', + 'Cwikla', + 'Denz', + 'Diesing', + 'Emmi', + 'Fringer', + 'Gibbard', + 'Graunke', + 'Gschwind', + 'Hafele', + 'Hoogland', + 'Howsare', + 'Kesecker', + 'Kilgallon', + 'Kleyman', + 'Kufahl', + 'Laut', + 'Malstrom', + 'Michetti', + 'Nosbisch', + 'Rasner', + 'Rosekrans', + 'Schnebly', + 'Staebell', + 'Theilen', + 'Tieszen', + 'Mellone', + 'Burcher', + 'Feister', + 'Hoage', + 'Irmen', + 'Derwin', + 'Dien', + 'Markins', + 'Egnew', + 'Dunlow', + 'Brickel', + 'Curt', + 'Smyly', + 'Whedbee', + 'Larman', + 'Boisselle', + 'Jaquess', + 'Bowns', + 'Nile', + 'Boyson', + 'Phillipps', + 'Weech', + 'Pillars', + 'Cauldwell', + 'Wynns', + 'Toca', + 'Scorza', + 'Ramsaran', + 'Arkwright', + 'Gurganious', + 'Jubert', + 'Beed', + 'Kellem', + 'Gervin', + 'Yarn', + 'Bookhart', + 'Sullen', + 'Moncrieffe', + 'Eze', + 'Agyeman', + 'Aldea', + 'Amodei', + 'Attig', + 'Bergthold', + 'Blaskowski', + 'Blitzer', + 'Bowring', + 'Brenning', + 'Chappuis', + 'Cordasco', + 'Cosens', + 'Denoble', + 'Dochterman', + 'Domek', + 'Embleton', + 'Georgiades', + 'Gintz', + 'Grooters', + 'Hoell', + 'Honse', + 'Jagiello', + 'Jaskulski', + 'Kaluzny', + 'Keske', + 'Khiev', + 'Koeneman', + 'Majestic', + 'Mandile', + 'Marandola', + 'Mcinroy', + 'Nienhaus', + 'Peckenpaugh', + 'Raquel', + 'Rossler', + 'Rusconi', + 'Schaffert', + 'Schipani', + 'Sittner', + 'Sweezey', + 'Swenor', + 'Tagliaferro', + 'Tubby', + 'Ulep', + 'Vallette', + 'Westergren', + 'Yaros', + 'Yasui', + 'Anway', + 'Bannick', + 'Biasi', + 'Breitling', + 'Catarino', + 'Dunaj', + 'Giovanelli', + 'Hemmerich', + 'Iott', + 'Knotek', + 'Kraeger', + 'Laskaris', + 'Lomboy', + 'Oleski', + 'Reibel', + 'Rightmyer', + 'Salmela', + 'Salow', + 'Siebels', + 'Spielvogel', + 'Streitmatter', + 'Ucci', + 'Windmiller', + 'Wojtkiewicz', + 'Zirkel', + 'Markie', + 'Nedeau', + 'Froehle', + 'Jesson', + 'Regala', + 'Boody', + 'Hayen', + 'Ose', + 'Loewy', + 'Radliff', + 'Davia', + 'Sky', + 'Halker', + 'Alu', + 'Ey', + 'Badawi', + 'Yeargain', + 'Jeanette', + 'Doublin', + 'Nolton', + 'Streety', + 'Blueford', + 'Abeles', + 'Aldava', + 'Alsteen', + 'Altadonna', + 'Apa', + 'Behlke', + 'Bellisario', + 'Bienstock', + 'Brenan', + 'Capley', + 'Castoro', + 'Demir', + 'Evinger', + 'Gartside', + 'Gellatly', + 'Goldinger', + 'Grabel', + 'Henkin', + 'Herrle', + 'Honegger', + 'Kunin', + 'Larmer', + 'Lizano', + 'Lorino', + 'Malcomson', + 'Matesic', + 'Mathiasen', + 'Mccolm', + 'Meenach', + 'Mullady', + 'Neiderer', + 'Ogier', + 'Omura', + 'Plog', + 'Pomplun', + 'Procida', + 'Raisbeck', + 'Rastetter', + 'Reither', + 'Rettberg', + 'Roblee', + 'Rossitto', + 'Scahill', + 'Schmoker', + 'Segreto', + 'Shelstad', + 'Shwartz', + 'Sondgeroth', + 'Supnet', + 'Swartzbaugh', + 'Tkachenko', + 'Urbani', + 'Vanslooten', + 'Varricchio', + 'Villarino', + 'Whiston', + 'Wyffels', + 'Yehle', + 'Basinski', + 'Belvedere', + 'Bernabei', + 'Bolotin', + 'Bresett', + 'Dabkowski', + 'Dalsanto', + 'Gotwalt', + 'Hellberg', + 'Hunke', + 'Kroenke', + 'Leppla', + 'Luginbuhl', + 'Mimnaugh', + 'Mullenbach', + 'Nearhood', + 'Raser', + 'Resendis', + 'Seydel', + 'Sozio', + 'Stillions', + 'Stormont', + 'Strimple', + 'Toruno', + 'Trouten', + 'Tryba', + 'Vandalen', + 'Wilhelmy', + 'Orland', + 'Loui', + 'Morcos', + 'Radell', + 'Artus', + 'Truxillo', + 'Copelan', + 'Bress', + 'Unthank', + 'Sudlow', + 'Branden', + 'Rowzee', + 'Montreuil', + 'Sollers', + 'Umar', + 'Coulibaly', + 'Allegretto', + 'Andreen', + 'Bielicki', + 'Bustard', + 'Cardosi', + 'Carkhuff', + 'Cetina', + 'Clouthier', + 'Dolata', + 'Fiola', + 'Fjeld', + 'Gawthrop', + 'Glastetter', + 'Hamlyn', + 'Hanten', + 'Huerter', + 'Kreiss', + 'Lestrange', + 'Litzau', + 'Luberto', + 'Menconi', + 'Milosevic', + 'Munera', + 'Nachtigal', + 'Nethers', + 'Nicolaou', + 'Olund', + 'Paddack', + 'Pfiester', + 'Pilley', + 'Polendo', + 'Porcayo', + 'Preast', + 'Runquist', + 'Saccente', + 'Santoli', + 'Saragoza', + 'Selway', + 'Smestad', + 'Stebner', + 'Toben', + 'Trapnell', + 'Urschel', + 'Verno', + 'Vidovich', + 'Walterscheid', + 'Yoh', + 'Zmijewski', + 'Allwein', + 'Bessire', + 'Broering', + 'Budzik', + 'Denherder', + 'Goerner', + 'Goldbaum', + 'Grussing', + 'Huaracha', + 'Ippoliti', + 'Kanak', + 'Kaucher', + 'Kious', + 'Kirkner', + 'Kratzke', + 'Kubisiak', + 'Kueny', + 'Mazzilli', + 'Mazzo', + 'Mcclenathan', + 'Mehlberg', + 'Miotke', + 'Nihiser', + 'Olheiser', + 'Oravetz', + 'Radwanski', + 'Shinsato', + 'Vandekamp', + 'Zagata', + 'Abert', + 'Llera', + 'Thommen', + 'Wirkkala', + 'Brasuell', + 'Shawler', + 'Mourey', + 'Gavia', + 'Morgano', + 'Newill', + 'Rathel', + 'Wist', + 'Braner', + 'Soman', + 'Koskey', + 'Searson', + 'Brocksmith', + 'Peale', + 'Couzens', + 'Shall', + 'Anis', + 'Stanly', + 'Cauthorn', + 'Kinkle', + 'Laughinghouse', + 'Mellette', + 'Rox', + 'Demetrius', + 'Cullars', + 'Summons', + 'Banwart', + 'Bartl', + 'Bebb', + 'Bobier', + 'Bogdanoff', + 'Bollmann', + 'Borrowman', + 'Borseth', + 'Buttitta', + 'Canelo', + 'Cassedy', + 'Cata', + 'Crivelli', + 'Daane', + 'Dhingra', + 'Dipple', + 'Dovidio', + 'Duesler', + 'Eissler', + 'Ent', + 'Falotico', + 'Goodrick', + 'Goupil', + 'Huels', + 'Keithly', + 'Killilea', + 'Klausing', + 'Kludt', + 'Licitra', + 'Llerenas', + 'Merolla', + 'Oatley', + 'Osmanovic', + 'Poudrier', + 'Raben', + 'Realmuto', + 'Reczek', + 'Ricchio', + 'Rossner', + 'Rozak', + 'Sandora', + 'Schuenemann', + 'Seres', + 'Shoptaw', + 'Splitt', + 'Tonkinson', + 'Willardson', + 'Winterberg', + 'Zayac', + 'Bobzien', + 'Buhman', + 'Carotenuto', + 'Chynoweth', + 'Defenbaugh', + 'Dipiero', + 'Duve', + 'Goonan', + 'Gragert', + 'Hangartner', + 'Heemstra', + 'Hensch', + 'Hollatz', + 'Jakubowicz', + 'Kapaun', + 'Kiener', + 'Landesman', + 'Lenzini', + 'Longbottom', + 'Parde', + 'Pincock', + 'Schlicker', + 'Shankel', + 'Vidas', + 'Waisner', + 'Zilberman', + 'Allcock', + 'Durban', + 'Javid', + 'Shoda', + 'Edes', + 'Boxwell', + 'Dezern', + 'Rubley', + 'Angelica', + 'Jeannette', + 'Planer', + 'Pata', + 'Lothridge', + 'Lucks', + 'Bais', + 'Sandra', + 'Enwright', + 'Maxton', + 'Radway', + 'Hoof', + 'Morisset', + 'Danzey', + 'Ancar', + 'Mcwright', + 'Leggs', + 'Monestime', + 'Massaquoi', + 'Barkow', + 'Bastyr', + 'Bautz', + 'Behanna', + 'Bewick', + 'Bezdek', + 'Bielby', + 'Bretschneider', + 'Bugher', + 'Carchi', + 'Chapp', + 'Conser', + 'Crete', + 'Derflinger', + 'Elsbernd', + 'Freimark', + 'Gerwin', + 'Grunfeld', + 'Harpham', + 'Hoeschen', + 'Holmlund', + 'Horch', + 'Hulsebus', + 'Kassabian', + 'Konczal', + 'Korell', + 'Lacuesta', + 'Lantier', + 'Larowe', + 'Lietzke', + 'Lunny', + 'Masin', + 'Massicotte', + 'Michalsky', + 'Notarianni', + 'Pautsch', + 'Poppy', + 'Sukup', + 'Suleski', + 'Tafel', + 'Wanninger', + 'Zaffino', + 'Zody', + 'Arganbright', + 'Bohmer', + 'Cintora', + 'Connatser', + 'Dlugos', + 'Fariello', + 'Fedie', + 'Felicetti', + 'Garno', + 'Gottsch', + 'Gratzer', + 'Gubser', + 'Kappelman', + 'Kuechle', + 'Laningham', + 'Latsch', + 'Longie', + 'Luscher', + 'Lybeck', + 'Rhude', + 'Setterlund', + 'Sobh', + 'Sonneborn', + 'Villamizar', + 'Wolstenholme', + 'Zacek', + 'Leppanen', + 'Casdorph', + 'Pinsker', + 'Reutov', + 'Rede', + 'Sheck', + 'Bakley', + 'Radde', + 'Moher', + 'Khader', + 'Rossie', + 'Scriver', + 'Provine', + 'Debarge', + 'Darke', + 'Griswell', + 'Naji', + 'Frere', + 'Cheevers', + 'Schnyder', + 'Curb', + 'Luten', + 'Cashaw', + 'Agerton', + 'Barnier', + 'Bluestone', + 'Boward', + 'Boyar', + 'Briano', + 'Bryngelson', + 'Calef', + 'Caraher', + 'Castelluccio', + 'Conk', + 'Crewse', + 'Demarzo', + 'Deutschman', + 'Eckrote', + 'Edmister', + 'Ferg', + 'Ghan', + 'Giampaolo', + 'Goedecke', + 'Gonet', + 'Gradel', + 'Gregston', + 'Grzesiak', + 'Guallpa', + 'Hanline', + 'Hardyman', + 'Hogate', + 'Houg', + 'Justiss', + 'Kaps', + 'Klopf', + 'Kniskern', + 'Laneve', + 'Lenhoff', + 'Lojewski', + 'Melott', + 'Milillo', + 'Passage', + 'Pereyda', + 'Plack', + 'Poet', + 'Prospero', + 'Quadros', + 'Revelo', + 'Rogier', + 'Sanabia', + 'Tragesser', + 'Vanarsdall', + 'Vanausdal', + 'Verbrugge', + 'Wandler', + 'Zoss', + 'Balzarini', + 'Brotz', + 'Bulin', + 'Bumann', + 'Cancro', + 'Centner', + 'Deblasi', + 'Duesing', + 'Friedley', + 'Frieling', + 'Heinke', + 'Holzheimer', + 'Klinck', + 'Knouff', + 'Kuczek', + 'Leible', + 'Lerum', + 'Liddicoat', + 'Mikowski', + 'Nonaka', + 'Ohlman', + 'Picaso', + 'Plamann', + 'Porretta', + 'Prajapati', + 'Rancour', + 'Stepka', + 'Studzinski', + 'Vaysman', + 'Wallenstein', + 'Wunderlin', + 'Pattinson', + 'Siskind', + 'Sitzer', + 'Thuman', + 'Barella', + 'Brillon', + 'Arnholt', + 'Karge', + 'Dohman', + 'Morone', + 'Macie', + 'Aken', + 'Lye', + 'Student', + 'Westen', + 'Bonsell', + 'Komara', + 'Hafiz', + 'Stickland', + 'Morina', + 'Creekmur', + 'Hussien', + 'Walrond', + 'Louischarles', + 'Alkema', + 'Angert', + 'Arcidiacono', + 'Ashkar', + 'Bookbinder', + 'Bootz', + 'Cilia', + 'Devilla', + 'Difatta', + 'Enberg', + 'Enderby', + 'Forbess', + 'Frutiger', + 'Graefe', + 'Guenette', + 'Hauschildt', + 'Keirsey', + 'Kolka', + 'Kopelman', + 'Lewan', + 'Mcluckie', + 'Mia', + 'Moebius', + 'Oestreicher', + 'Oprea', + 'Ortolano', + 'Padovani', + 'Pensabene', + 'Phimmasone', + 'Pointon', + 'Punches', + 'Schertzer', + 'Seoane', + 'Skramstad', + 'Sorlie', + 'Syfert', + 'Tasca', + 'Townzen', + 'Wernli', + 'Wurzel', + 'Yazdi', + 'Devendorf', + 'Featherly', + 'Frush', + 'Heringer', + 'Iwai', + 'Kallenberger', + 'Kobashigawa', + 'Langbehn', + 'Livecchi', + 'Middlesworth', + 'Niess', + 'Osterlund', + 'Ruz', + 'Seiwert', + 'Vanwieren', + 'Wernet', + 'Grabbe', + 'Gaugh', + 'Mcclarren', + 'Raudales', + 'Urry', + 'Clere', + 'Lacer', + 'Mathia', + 'Mccrumb', + 'Cotrell', + 'Mannor', + 'Medine', + 'Tittsworth', + 'Hughston', + 'Buick', + 'Limes', + 'Hams', + 'Thagard', + 'Leavelle', +]; diff --git a/drizzle-seed/src/datasets/loremIpsumSentences.ts b/drizzle-seed/src/datasets/loremIpsumSentences.ts new file mode 100644 index 000000000..aabd5f771 --- /dev/null +++ b/drizzle-seed/src/datasets/loremIpsumSentences.ts @@ -0,0 +1,1636 @@ +export default [ + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + 'Nam porta quis ex a blandit.', + 'Donec ullamcorper erat sed diam luctus, eu euismod nibh eleifend.', + 'Curabitur sit amet tortor vehicula lacus mollis efficitur eu feugiat tortor.', + 'Quisque in erat vitae nisl tristique blandit.', + 'Vivamus in lectus tellus.', + 'Donec quis neque sit amet diam elementum accumsan.', + 'Sed vitae sollicitudin tellus, sed rhoncus magna.', + 'Aliquam eu interdum purus, sed viverra lorem.', + 'Etiam eget viverra dui.', + 'Morbi vel risus dolor.', + 'Donec laoreet, ipsum sed vestibulum venenatis, ligula leo fermentum enim, in pharetra lorem massa volutpat metus.', + 'Aliquam egestas mi in urna blandit, quis viverra justo condimentum.', + 'Maecenas pulvinar quam sapien, sed euismod enim rhoncus quis.', + 'Maecenas at quam non elit varius rutrum.', + 'Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + 'Quisque et malesuada erat.', + 'Maecenas eleifend tellus eu luctus tempor.', + 'Cras at scelerisque massa, quis dapibus urna.', + 'Aliquam porttitor a risus quis luctus.', + 'Aenean mollis ex tempor ligula cursus, interdum porttitor nibh fringilla.', + 'Donec aliquet ac nulla nec scelerisque.', + 'Curabitur neque diam, posuere nec tortor a, posuere pretium odio.', + 'Nullam et vehicula ante.', + 'Etiam mattis, odio quis sodales maximus, nisl lectus sagittis ligula, quis ornare urna nibh ac est.', + 'Pellentesque eget finibus eros.', + 'Maecenas gravida risus vitae vestibulum facilisis.', + 'Sed rhoncus libero fringilla arcu viverra tempus.', + 'Suspendisse non lacus vitae urna viverra vehicula.', + 'Pellentesque eu elementum enim.', + 'Morbi aliquet nisl eu accumsan rhoncus.', + 'Ut fringilla dolor ut odio blandit, et dignissim lectus placerat.', + 'Aliquam vulputate mauris elit, in semper purus accumsan tempor.', + 'Sed at elit ut ligula bibendum tincidunt.', + 'Maecenas ut tristique ipsum, ac sollicitudin quam.', + 'Pellentesque ut ante quis tellus pellentesque tempus.', + 'Nulla suscipit ex eget ex cursus accumsan.', + 'Sed at purus sapien.', + 'Fusce feugiat ante ac massa aliquam, maximus bibendum arcu convallis.', + 'Interdum et malesuada fames ac ante ipsum primis in faucibus.', + 'Cras vitae dignissim leo, ac pretium est.', + 'Aliquam lectus lectus, varius in eros eget, tempus sollicitudin ex.', + 'Nunc gravida mi lectus, tincidunt ultrices sapien lobortis cursus.', + 'Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.', + 'Maecenas aliquam vulputate justo vel lacinia.', + 'Nam facilisis augue vitae dolor mattis, sit amet maximus orci molestie.', + 'Etiam et nibh id lorem viverra aliquet.', + 'Quisque et mauris et odio finibus ullamcorper id eget odio.', + 'Duis sit amet varius purus.', + 'In congue posuere libero, nec tincidunt dui suscipit ac.', + 'Vivamus suscipit risus vel massa commodo pulvinar vitae eu diam.', + 'Mauris porta non orci at dapibus.', + 'Sed ullamcorper, sem ac fringilla tristique, purus massa hendrerit turpis, at elementum massa nulla nec quam.', + 'Praesent sed felis vitae felis vestibulum hendrerit vel at ipsum.', + 'Nunc egestas, lectus feugiat consequat auctor, erat mauris pretium sapien, et consequat magna ex id purus.', + 'Maecenas nibh ex, bibendum at augue eget, pulvinar cursus libero.', + 'Quisque ultricies vestibulum neque, in sollicitudin felis euismod in.', + 'Maecenas viverra mauris sit amet neque vulputate, sed suscipit sapien laoreet.', + 'Sed vitae sapien maximus, faucibus enim a, placerat erat.', + 'Cras maximus ipsum nec dui fermentum, eu facilisis augue fringilla.', + 'Sed eget nibh ante.', + 'Praesent pellentesque sodales tellus non consectetur.', + 'Suspendisse pulvinar, massa id gravida facilisis, diam nulla molestie metus, et convallis purus elit quis sapien.', + 'Mauris fermentum nec metus id consectetur.', + 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.', + 'Nulla vel maximus nunc.', + 'Duis dolor orci, tempor nec odio at, gravida congue ex.', + 'Pellentesque faucibus, est et eleifend commodo, ipsum nunc lobortis felis, at aliquam erat leo eu massa.', + 'Morbi egestas vehicula lacus, in pharetra nulla dictum in.', + 'Ut facilisis, erat eu suscipit mollis, ipsum ex sagittis augue, sit amet vehicula neque nunc ut leo.', + 'Donec dapibus non odio non auctor.', + 'Donec vitae ipsum eget risus vulputate vestibulum.', + 'Cras vestibulum purus leo, in porttitor erat finibus quis.', + 'Vivamus tincidunt justo diam, placerat maximus orci congue ac.', + 'Curabitur pulvinar congue accumsan.', + 'Vivamus eget velit dictum, sagittis diam eu, elementum diam.', + 'Quisque pharetra pellentesque purus at tristique.', + 'Cras dignissim arcu massa, eu pellentesque eros tristique id.', + 'Proin efficitur turpis vel sem ultricies molestie.', + 'Curabitur rhoncus viverra nibh ut sollicitudin.', + 'Vestibulum ut magna dolor.', + 'Suspendisse placerat eleifend lorem, at aliquet enim lacinia ut.', + 'Integer at nisi eu ex viverra viverra.', + 'Morbi finibus bibendum volutpat.', + 'Donec facilisis sem id eros tempor vehicula.', + 'Phasellus a dolor in dolor finibus iaculis et at quam.', + 'Phasellus volutpat nulla eget mauris blandit pharetra ut sit amet augue.', + 'Phasellus leo urna, ornare ut mauris ultrices, posuere imperdiet dui.', + 'Morbi accumsan bibendum neque, sit amet eleifend nunc bibendum nec.', + 'Praesent dapibus tristique tempor.', + 'Duis dapibus nulla in lectus luctus, nec blandit sem tristique.', + 'In odio dolor, consectetur eget sapien egestas, viverra pharetra urna.', + 'Nam risus est, suscipit fermentum tincidunt id, vehicula vitae arcu.', + 'Aenean venenatis pretium condimentum.', + 'Mauris lobortis blandit dapibus.', + 'Phasellus aliquet efficitur condimentum.', + 'Nam pulvinar ullamcorper metus ac vehicula.', + 'Donec eget auctor tellus.', + 'Morbi quis diam ultrices, tristique lectus eu, vehicula dolor.', + 'Aenean malesuada lorem sed vestibulum rutrum.', + 'Praesent quis metus id quam facilisis blandit.', + 'Proin venenatis eleifend augue nec gravida.', + 'Nulla eget vehicula mauris, vel rutrum ligula.', + 'Ut interdum aliquam fermentum.', + 'Morbi elementum metus ut velit pellentesque lacinia.', + 'Suspendisse malesuada est sed varius rhoncus.', + 'Sed eu porta ex.', + 'Nullam dignissim egestas dapibus.', + 'Vestibulum a pharetra ipsum.', + 'Donec in interdum diam.', + 'Morbi viverra id sem quis mollis.', + 'In eget porta lorem.', + 'Aliquam tincidunt feugiat magna, vel finibus odio rutrum sit amet.', + 'Morbi faucibus metus at vehicula efficitur.', + 'Cras metus lectus, egestas lacinia leo vitae, lacinia dapibus quam.', + 'Morbi tincidunt ut velit sed hendrerit.', + 'Vivamus eleifend at leo porttitor blandit.', + 'Morbi egestas diam augue, vel condimentum odio pulvinar id.', + 'Morbi porta vulputate ante sed lacinia.', + 'Fusce massa est, varius et lacinia sit amet, dictum at turpis.', + 'Vestibulum viverra augue elit, eget tristique ipsum accumsan vitae.', + 'Sed sit amet ex sapien.', + 'Mauris dapibus tincidunt scelerisque.', + 'Aliquam nunc libero, vestibulum id facilisis in, sollicitudin vitae nulla.', + 'Aenean a nulla commodo, rutrum orci eget, pellentesque erat.', + 'Aenean ut sem felis.', + 'Donec sapien ante, ornare sit amet ornare id, mattis lobortis tellus.', + 'Nam ut placerat metus.', + 'Vivamus in cursus eros, sit amet scelerisque mauris.', + 'Integer tempus, justo vel aliquet aliquam, mi libero iaculis leo, placerat sollicitudin mauris ipsum faucibus justo.', + 'Cras at vehicula urna.', + 'Phasellus id nunc eu enim ultricies hendrerit.', + 'Nulla sodales sodales orci in placerat.', + 'Donec placerat, justo in imperdiet euismod, nulla metus pharetra nibh, nec auctor tortor mauris ac augue.', + 'Donec at elit non odio malesuada consequat non id velit.', + 'Morbi pellentesque eleifend iaculis.', + 'Aliquam ullamcorper lacinia vulputate.', + 'Nulla commodo risus et efficitur mollis.', + 'In venenatis consectetur metus, in iaculis ligula bibendum fermentum.', + 'Nullam ac finibus nisl.', + 'Aenean blandit sagittis justo, ut cursus tortor vehicula vel.', + 'Integer at pulvinar eros, sed dictum ex.', + 'Phasellus bibendum interdum porttitor.', + 'Fusce blandit egestas nisl, quis mattis elit commodo in.', + 'Donec in ex justo.', + 'Aenean elementum tristique eros, vel mattis tellus malesuada nec.', + 'Quisque euismod tincidunt erat.', + 'Proin turpis orci, vehicula vitae ipsum et, auctor ornare ex.', + 'Nunc efficitur nisl sit amet justo faucibus, eu bibendum diam pretium.', + 'Nullam consectetur finibus dui at malesuada.', + 'Ut elementum, ante vitae gravida feugiat, orci enim molestie libero, ut vehicula purus ipsum a eros.', + 'Ut mi neque, vestibulum nec nibh eu, imperdiet elementum ipsum.', + 'Donec cursus augue quis ex rutrum lacinia.', + 'Mauris purus mi, pellentesque at leo in, auctor ultrices massa.', + 'Maecenas finibus quam quis arcu mattis porttitor.', + 'Suspendisse ac urna ac odio aliquet congue.', + 'Integer suscipit, odio in ullamcorper ornare, diam nibh elementum eros, a aliquam lacus velit vel mauris.', + 'Quisque ut bibendum risus.', + 'Suspendisse bibendum augue pellentesque, dapibus leo ac, luctus purus.', + 'Phasellus interdum ipsum sit amet elit rhoncus varius.', + 'Pellentesque pharetra lorem et nibh aliquam, vel luctus elit sodales.', + 'Maecenas ornare cursus metus in efficitur.', + 'Phasellus laoreet ipsum nec erat mattis, vitae vulputate risus auctor.', + 'Maecenas augue magna, mattis elementum dapibus sed, vulputate venenatis ante.', + 'Fusce non lorem vitae velit molestie auctor.', + 'Etiam sodales, orci sed consequat luctus, ante urna hendrerit ipsum, at ultrices mauris neque in velit.', + 'Vestibulum a egestas ipsum.', + 'Donec sit amet laoreet mi.', + 'Quisque varius ligula dolor.', + 'Morbi sodales volutpat nulla, et ullamcorper lacus bibendum at.', + 'In mattis in dui quis facilisis.', + 'Cras pulvinar, massa eu rhoncus rhoncus, mi mi ultricies turpis, eu iaculis elit nulla et metus.', + 'Donec et neque suscipit, iaculis ipsum at, maximus eros.', + 'Quisque eu accumsan risus.', + 'Phasellus in consectetur nisl.', + 'Nullam interdum porttitor enim fermentum bibendum.', + 'Vestibulum consequat fermentum mollis.', + 'Quisque id velit sit amet magna posuere aliquam vel in nunc.', + 'Maecenas nisl lectus, sollicitudin eu auctor nec, cursus vel quam.', + 'Proin elementum efficitur velit vel vestibulum.', + 'Nunc non tincidunt ex.', + 'Fusce nec nisl eget nunc fringilla dignissim vel nec ex.', + 'Cras malesuada erat quis ligula lacinia consectetur.', + 'Aliquam semper elit ante, sed accumsan lacus molestie in.', + 'Vivamus porttitor enim eros, eu ultricies lectus pulvinar eget.', + 'Nullam consequat tincidunt ligula, eu luctus nisi congue id.', + 'Aenean lacinia lobortis ante, fermentum vulputate turpis eleifend faucibus.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Phasellus tempus libero non ipsum cursus rhoncus.', + 'Sed euismod molestie augue vitae fringilla.', + 'Pellentesque mi tortor, tempor quis condimentum quis, lobortis quis quam.', + 'Sed in vestibulum purus, in vestibulum neque.', + 'Etiam pellentesque ligula ligula, sit amet varius mi venenatis fringilla.', + 'Morbi vitae est ac diam convallis sagittis in facilisis ligula.', + 'Sed vel consequat diam.', + 'Nunc ac tempor felis.', + 'Aenean luctus tristique urna lacinia venenatis.', + 'Suspendisse vehicula auctor accumsan.', + 'Suspendisse ultrices rhoncus nisi a pellentesque.', + 'Sed sollicitudin id orci ut laoreet.', + 'Cras pulvinar lorem ut ipsum malesuada, sed euismod turpis placerat.', + 'Ut vitae massa quis augue posuere ultricies.', + 'In quis erat posuere, posuere dolor ac, tempus tortor.', + 'Aliquam aliquet nisl eu tortor mollis, id dictum nisi congue.', + 'Etiam pulvinar, ex a tincidunt bibendum, nisl elit venenatis lacus, nec dictum odio ligula non nulla.', + 'Etiam sit amet nunc vestibulum, pharetra diam ac, lacinia felis.', + 'Quisque volutpat laoreet lorem, sit amet porta justo ultrices aliquet.', + 'Praesent aliquet nisi elit, ut facilisis orci accumsan vitae.', + 'Quisque vehicula augue at leo varius, ac dictum tortor viverra.', + 'Proin eu bibendum diam.', + 'Aliquam blandit, erat et feugiat varius, erat mauris convallis ipsum, ut convallis massa erat vel neque.', + 'Sed commodo nec ipsum in maximus.', + 'Pellentesque ligula nisl, tincidunt volutpat convallis non, interdum quis felis.', + 'Nunc ultrices neque ut diam congue, non tristique metus tempor.', + 'Pellentesque sodales metus leo, at eleifend dui pretium at.', + 'Suspendisse sit amet metus at est viverra fermentum.', + 'Donec ac odio vitae urna blandit consectetur.', + 'Vivamus tincidunt cursus nunc in mollis.', + 'Nullam malesuada quis odio eu imperdiet.', + 'Integer convallis sapien vitae semper varius.', + 'Nullam malesuada tincidunt lacus elementum condimentum.', + 'Nam eget neque vitae leo convallis aliquam id eu quam.', + 'Quisque aliquet elementum lectus, vitae pharetra nisl facilisis at.', + 'Fusce ut velit porttitor, porta erat ac, vehicula odio.', + 'Sed tempor est at nulla mollis aliquet.', + 'Quisque luctus dolor eu placerat ultrices.', + 'Vivamus luctus ex non ante pretium venenatis.', + 'Ut non arcu vitae velit pellentesque accumsan eget id risus.', + 'Pellentesque accumsan elementum turpis, a aliquam dui sodales nec.', + 'Donec quis semper tortor, scelerisque venenatis velit.', + 'Morbi tempus lacus pretium risus rhoncus, tincidunt lacinia diam dapibus.', + 'Donec libero neque, aliquet non aliquet et, mollis at est.', + 'Fusce mauris tortor, molestie ut porttitor nec, euismod consequat metus.', + 'Maecenas in nunc blandit, sagittis orci sed, fringilla risus.', + 'Suspendisse vel vulputate velit.', + 'Nulla aliquam facilisis velit.', + 'Donec placerat porttitor sapien.', + 'Quisque non pharetra mi.', + 'Suspendisse mattis justo nec arcu efficitur, nec suscipit mi tempor.', + 'Sed et dui vitae nisi accumsan faucibus nec vel odio.', + 'Donec at lacus eget nisi ultricies efficitur.', + 'Aenean ultricies elit eget mi consectetur imperdiet.', + 'Ut lorem magna, ullamcorper sit amet dui quis, pulvinar cursus felis.', + 'Morbi ligula nibh, fermentum nec pellentesque eget, sodales in sapien.', + 'Sed eu vehicula mi.', + 'Vestibulum et erat erat.', + 'Maecenas eleifend ultricies erat eget vehicula.', + 'Donec varius lectus ut metus finibus pellentesque.', + 'Aliquam nec orci scelerisque, elementum odio non, aliquet ante.', + 'Nulla eget nisi ac magna aliquet efficitur vitae sed felis.', + 'Suspendisse purus erat, blandit eget leo quis, iaculis vestibulum sapien.', + 'Vivamus rutrum, leo ac suscipit tincidunt, ipsum sem volutpat purus, quis sodales augue lacus id mi.', + 'Aenean interdum ac turpis eu viverra.', + 'Suspendisse rhoncus rutrum augue.', + 'Ut dolor lectus, rutrum et metus et, volutpat sagittis urna.', + 'Donec blandit tortor sed pellentesque maximus.', + 'Phasellus molestie congue erat, ut euismod leo pulvinar nec.', + 'Nulla elementum vestibulum libero vehicula aliquet.', + 'Sed venenatis enim eu nisi laoreet, sit amet sagittis magna gravida.', + 'Suspendisse semper molestie ligula sit amet lobortis.', + 'Nulla urna eros, condimentum a odio id, aliquet scelerisque justo.', + 'Suspendisse sit amet orci ante.', + 'Sed congue sem sapien, ac ornare nibh porta efficitur.', + 'Nullam suscipit, lectus ac gravida ultrices, lectus neque viverra sem, sit amet eleifend purus felis vulputate odio.', + 'In velit lacus, facilisis quis nunc vitae, imperdiet bibendum mauris.', + 'Duis iaculis sodales turpis, vestibulum rutrum eros efficitur ac.', + 'Aenean interdum congue libero vel suscipit.', + 'Quisque pharetra semper lorem ac posuere.', + 'Mauris viverra neque pellentesque, semper augue id, placerat arcu.', + 'Mauris sit amet bibendum nisi, a laoreet ipsum.', + 'Proin tristique auctor massa convallis imperdiet.', + 'Curabitur congue sed neque vel imperdiet.', + 'Quisque egestas metus at diam feugiat, vestibulum ornare nulla venenatis.', + 'Donec non hendrerit urna.', + 'Curabitur id justo ex.', + 'Sed consectetur urna a purus egestas, a fringilla leo scelerisque.', + 'Morbi interdum massa sed ligula dapibus semper.', + 'Nam sit amet condimentum erat.', + 'Nam vel magna porta, ultrices nisl eu, lacinia lorem.', + 'Pellentesque accumsan, felis sit amet elementum tincidunt, risus arcu bibendum eros, vitae commodo justo orci vitae ex.', + 'Vestibulum eu fermentum lacus.', + 'Nulla quis pulvinar metus.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Curabitur malesuada non erat vitae dapibus.', + 'Donec sit amet facilisis ante, vitae tristique risus.', + 'Vestibulum maximus vehicula purus sed tincidunt.', + 'Fusce facilisis odio et fermentum dapibus.', + 'In hac habitasse platea dictumst.', + 'Etiam et viverra felis, in vulputate enim.', + 'Donec vel pulvinar elit.', + 'Mauris quis velit suscipit, accumsan libero eget, consectetur sapien.', + 'Maecenas vel placerat justo, sit amet eleifend sem.', + 'Pellentesque cursus felis enim, vitae convallis lectus finibus et.', + 'Aliquam eu dolor eros.', + 'Cras dictum, est quis porttitor semper, turpis lacus maximus eros, at luctus diam orci et elit.', + 'Nulla id augue tincidunt, sollicitudin mi vel, pellentesque mi.', + 'Vestibulum ultricies turpis a congue rutrum.', + 'Praesent sed dictum nunc.', + 'Donec finibus commodo ligula non tincidunt.', + 'Aliquam eget tellus velit.', + 'Proin tempor elit at nulla commodo molestie.', + 'Morbi ultricies sit amet tortor eu porttitor.', + 'Duis congue elit ac porttitor lobortis.', + 'Sed fringilla mi pretium lacinia finibus.', + 'Maecenas faucibus metus sed ipsum tristique, sed vulputate odio bibendum.', + 'Nulla facilisi.', + 'Nulla non dapibus nibh, id ultricies augue.', + 'Vestibulum vitae lorem neque.', + 'Maecenas non augue nibh.', + 'Suspendisse laoreet dapibus auctor.', + 'In sit amet lorem eget purus ultrices tincidunt ut at neque.', + 'Fusce congue, nunc sit amet lobortis pellentesque, sapien ex rutrum elit, vel gravida nulla velit sed dui.', + 'Cras nec hendrerit sapien, eu euismod elit.', + 'Maecenas lobortis egestas interdum.', + 'Nunc sagittis bibendum erat sit amet varius.', + 'Mauris varius nunc at odio facilisis facilisis.', + 'Sed maximus sit amet urna vitae aliquam.', + 'Donec vel ipsum sed sapien aliquet pharetra id vitae leo.', + 'Sed vitae diam elit.', + 'Nam tempor, risus nec gravida mollis, velit neque efficitur leo, sit amet porta purus magna euismod ipsum.', + 'Suspendisse potenti.', + 'Donec interdum vulputate lorem, vitae pellentesque sem mollis at.', + 'Vivamus vitae faucibus libero.', + 'Etiam laoreet semper accumsan.', + 'Morbi imperdiet, ex ut fringilla fermentum, sapien ipsum efficitur magna, a ultrices purus massa at nibh.', + 'Sed a dolor euismod, facilisis ex eget, efficitur est.', + 'Phasellus eleifend, felis quis convallis semper, dui magna accumsan leo, a mattis magna urna in ligula.', + 'Donec porta sollicitudin vestibulum.', + 'Nunc et nisl in ligula iaculis rutrum id consequat neque.', + 'Nunc sed purus quis felis aliquet accumsan.', + 'Aliquam congue placerat condimentum.', + 'Proin ultrices condimentum facilisis.', + 'Aenean in faucibus odio.', + 'Pellentesque enim ex, mattis non risus ut, euismod imperdiet lorem.', + 'Integer quis magna non risus luctus posuere.', + 'Vestibulum pellentesque suscipit arcu, id dignissim leo rhoncus nec.', + 'Praesent vitae sodales quam.', + 'Morbi viverra nibh quam, quis dapibus nibh consequat sed.', + 'Morbi sed risus sollicitudin, tincidunt augue vel, posuere orci.', + 'Nunc nisi nisi, varius ac commodo ac, placerat hendrerit nisi.', + 'Donec sapien magna, elementum eu mi vitae, laoreet euismod turpis.', + 'Cras eget pretium eros.', + 'Sed tincidunt ante id tortor porta, ac pellentesque erat suscipit.', + 'Fusce consequat nisi dolor, eget tincidunt tellus imperdiet at.', + 'Nullam scelerisque commodo eleifend.', + 'Mauris et nisl bibendum, varius sem at, sollicitudin libero.', + 'Quisque purus felis, tristique id ligula in, ullamcorper pellentesque felis.', + 'Phasellus et tortor ut sem rhoncus suscipit ac eget elit.', + 'Donec rhoncus ex finibus neque volutpat, ut placerat metus gravida.', + 'Suspendisse at sem id diam efficitur dapibus.', + 'Aliquam erat volutpat.', + 'Nunc ac nibh eget augue sodales ornare.', + 'Integer ultricies neque at felis aliquam, vel interdum felis mollis.', + 'Nulla iaculis libero velit, a consequat eros hendrerit venenatis.', + 'Etiam aliquet eros magna, ut ultricies metus feugiat vitae.', + 'Maecenas est orci, accumsan eu eleifend vitae, sollicitudin vitae metus.', + 'Sed aliquet, tellus sed euismod sodales, lectus leo imperdiet dui, eu luctus mauris turpis id turpis.', + 'Sed eget accumsan felis, viverra euismod nulla.', + 'Nullam convallis odio consectetur nisl tempus, sed dictum urna tempor.', + 'Proin scelerisque elit tortor, a ultricies odio ullamcorper vel.', + 'Etiam ultrices congue neque ac sollicitudin.', + 'Ut placerat consectetur sapien ut rhoncus.', + 'Ut aliquam quam nec ornare fermentum.', + 'Vivamus aliquet facilisis magna.', + 'Vestibulum dictum sed leo non cursus.', + 'Morbi egestas et augue fringilla bibendum.', + 'Etiam vel maximus tellus.', + 'Praesent et turpis justo.', + 'Morbi a hendrerit diam, cursus posuere lorem.', + 'In sed sem id eros dignissim tincidunt.', + 'Nullam porta varius risus at ullamcorper.', + 'Nam varius sodales dolor, dapibus rutrum ligula vulputate at.', + 'Nam ultricies sed ante eget convallis.', + 'Duis ultrices est ac orci auctor, et malesuada neque sodales.', + 'Aliquam venenatis sodales aliquam.', + 'Phasellus ut lectus id sapien dictum luctus a vitae nibh.', + 'Sed euismod varius malesuada.', + 'Ut faucibus ultricies posuere.', + 'Nunc vitae diam in mi pellentesque vehicula eu elementum lectus.', + 'Vivamus gravida felis eget ipsum consectetur tincidunt.', + 'Nullam nunc eros, blandit ut finibus sit amet, porta nec lectus.', + 'Vestibulum non orci neque.', + 'Praesent velit massa, pulvinar quis mauris sit amet, consequat tincidunt mauris.', + 'Quisque id cursus magna.', + 'Donec eros ante, placerat at efficitur in, placerat id turpis.', + 'Morbi non dui tortor.', + 'Quisque at turpis sodales, pharetra justo ut, accumsan est.', + 'Sed molestie dolor mi, ac feugiat elit blandit et.', + 'Nullam libero ex, rutrum ac ultrices vitae, tincidunt ut velit.', + 'Proin pharetra placerat eros, eget mattis risus semper at.', + 'In feugiat congue risus.', + 'Curabitur non odio ligula.', + 'Nulla sit amet ligula facilisis, venenatis ante eget, porttitor libero.', + 'In eu sodales sem.', + 'In iaculis ex eget nisi euismod, eget porta libero condimentum.', + 'Vivamus tristique faucibus nunc.', + 'Nam sit amet cursus erat.', + 'Suspendisse ligula velit, molestie ac nisl quis, cursus sodales nunc.', + 'Nunc vel semper odio, at scelerisque felis.', + 'Fusce egestas purus id enim accumsan ultrices.', + 'Curabitur porttitor justo urna, nec ultricies magna varius non.', + 'Nullam euismod, nunc varius efficitur viverra, sem justo scelerisque elit, a pretium ante sem id mi.', + 'Sed sagittis faucibus urna, eu sollicitudin magna.', + 'Nam pretium velit quis lectus viverra sodales.', + 'Cras lectus mi, accumsan non vulputate et, hendrerit ac libero.', + 'Integer nec faucibus risus.', + 'Vestibulum a finibus nulla.', + 'Quisque consequat nisi varius, laoreet justo et, elementum dui.', + 'Praesent cursus quam nec vestibulum porta.', + 'Nunc fermentum semper molestie.', + 'Cras fermentum, sem et lobortis iaculis, magna erat bibendum sapien, in sollicitudin erat metus in lectus.', + 'Nullam ligula est, tincidunt vitae consectetur vel, rutrum at erat.', + 'Etiam in rhoncus nisl, ut tempor ex.', + 'Phasellus mollis tempus urna, vel hendrerit felis aliquam sit amet.', + 'Aliquam eget mi tellus.', + 'Maecenas consectetur enim diam, a fringilla nunc suscipit egestas.', + 'Phasellus ac efficitur dolor.', + 'Nullam efficitur metus a risus sodales, quis vestibulum urna lacinia.', + 'Nam eu risus vulputate, commodo purus quis, ullamcorper nunc.', + 'Maecenas in urna tortor.', + 'Duis a purus volutpat ligula tristique suscipit.', + 'Sed id libero accumsan, finibus ipsum et, sagittis justo.', + 'Suspendisse malesuada lectus in ligula interdum condimentum.', + 'Fusce viverra ipsum lacus, et condimentum nisi tincidunt vitae.', + 'Ut pulvinar sodales nisl non dictum.', + 'Proin et efficitur tortor.', + 'Cras viverra lacinia dolor, a condimentum mauris rhoncus eu.', + 'Quisque non nunc lobortis, iaculis neque et, venenatis eros.', + 'Etiam posuere, risus quis feugiat gravida, velit nisi ornare enim, vitae dictum leo massa id orci.', + 'Sed sit amet ligula nisi.', + 'Cras et velit eget urna pulvinar dignissim.', + 'Phasellus feugiat enim eu dolor molestie, vitae molestie dui consectetur.', + 'Morbi scelerisque sapien et diam tincidunt volutpat.', + 'Praesent viverra lobortis tristique.', + 'Vestibulum placerat rutrum congue.', + 'Sed vel leo eu odio feugiat bibendum.', + 'Mauris lobortis ante tortor, ac mattis nunc consequat sit amet.', + 'Aenean sollicitudin faucibus purus, ut facilisis neque convallis quis.', + 'Aenean sit amet risus in libero eleifend pellentesque nec non lacus.', + 'Maecenas iaculis at ligula eget rutrum.', + 'Aliquam vitae tristique justo.', + 'Aliquam enim nibh, porta accumsan tortor at, condimentum feugiat tellus.', + 'Morbi dignissim egestas maximus.', + 'Sed dui risus, vulputate ac accumsan vel, rhoncus vitae nunc.', + 'Phasellus elementum ac enim a tincidunt.', + 'Curabitur vulputate enim ut leo suscipit rhoncus.', + 'Ut vitae dapibus dui.', + 'Proin sed nulla purus.', + 'Etiam a eros elementum, fringilla orci nec, cursus magna.', + 'Curabitur egestas ultricies risus, vitae ultrices dolor.', + 'Donec et tempus leo.', + 'Phasellus justo tellus, lacinia ut lorem sed, pretium hendrerit dolor.', + 'Mauris in mattis libero, sed pulvinar lorem.', + 'Cras quis auctor velit.', + 'Vestibulum vitae hendrerit tortor.', + 'Cras dictum ligula eget arcu malesuada suscipit ac sed arcu.', + 'Suspendisse vel enim sit amet metus eleifend venenatis.', + 'Quisque eget purus in lorem vulputate congue.', + 'Curabitur non enim vulputate, accumsan purus nec, suscipit lacus.', + 'Donec eros est, pretium blandit semper eu, dignissim vitae leo.', + 'Maecenas molestie erat ac magna finibus, quis sollicitudin dui euismod.', + 'Curabitur rutrum dolor ut nibh suscipit luctus.', + 'Fusce venenatis orci nulla, eget semper libero dictum sed.', + 'Sed id justo id est eleifend tristique.', + 'Phasellus eleifend eget lectus vitae luctus.', + 'Fusce vitae dolor id dui aliquam gravida ac id ex.', + 'Maecenas elementum, mi sed suscipit malesuada, magna ex laoreet lorem, lacinia pellentesque erat nisl quis augue.', + 'Ut egestas tincidunt tincidunt.', + 'Nullam consectetur magna id dictum varius.', + 'Pellentesque mattis, velit ac volutpat euismod, ipsum magna volutpat tellus, ac pharetra dolor erat vel felis.', + 'Nunc pretium, tortor blandit gravida pretium, neque nulla vehicula diam, eget aliquet turpis eros eu orci.', + 'Integer non arcu eget odio eleifend tempor quis eget elit.', + 'Ut molestie nulla ornare, congue nulla vel, eleifend tellus.', + 'Pellentesque ultrices diam ut risus convallis viverra.', + 'Integer ex erat, molestie in rhoncus ornare, rhoncus id ipsum.', + 'Fusce non nulla id augue molestie malesuada.', + 'Proin in ornare ligula.', + 'Fusce sit amet augue eget orci imperdiet consequat.', + 'Maecenas sodales est dui, vel feugiat orci aliquam a.', + 'Aenean pulvinar quam in nunc fringilla, et convallis turpis congue.', + 'Proin ex erat, vehicula tristique mi vehicula, finibus congue ex.', + 'Nunc ornare fermentum convallis.', + 'Quisque scelerisque orci non dignissim sodales.', + 'Donec eget facilisis enim.', + 'Maecenas at libero at urna vestibulum mattis.', + 'Curabitur fringilla ex purus, quis egestas tortor lacinia nec.', + 'Sed vel est consequat, sagittis lacus at, ullamcorper augue.', + 'Sed eget dui ac nisi hendrerit auctor.', + 'Nulla consectetur placerat magna, at mattis felis rutrum in.', + 'Nullam vitae risus viverra, faucibus lacus a, eleifend eros.', + 'Nullam tempus sit amet eros vitae semper.', + 'Nullam vestibulum sem sed purus congue, hendrerit porttitor leo maximus.', + 'Praesent fringilla aliquet efficitur.', + 'Aliquam quis metus at ante posuere gravida.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Aliquam sapien dui, mollis sed hendrerit id, fermentum sed tortor.', + 'Ut eget velit a urna interdum volutpat.', + 'Maecenas rhoncus dui vitae tempus rhoncus.', + 'Phasellus eu molestie sem.', + 'Mauris quis aliquam lectus, nec vehicula dui.', + 'Aenean eget imperdiet odio.', + 'Vestibulum non ullamcorper lacus.', + 'Etiam eu augue eget massa tempus rutrum eu sit amet leo.', + 'Vestibulum nec nulla quis tellus lacinia scelerisque quis vitae felis.', + 'Donec convallis, elit sit amet viverra fermentum, libero eros auctor elit, a tincidunt erat eros vitae ligula.', + 'Cras ornare placerat ultrices.', + 'Mauris blandit, nunc eu viverra interdum, est odio bibendum urna, eget mattis purus nisl sollicitudin mauris.', + 'Cras ornare velit ac facilisis rhoncus.', + 'Donec lacus lectus, consectetur in fringilla ac, aliquet et nisl.', + 'Morbi sit amet nulla vitae arcu porttitor elementum ac vitae nulla.', + 'Duis sed tristique velit, non rutrum tellus.', + 'Cras et imperdiet nisl.', + 'Fusce id ipsum a dui volutpat volutpat.', + 'Nam eget augue et lectus placerat vehicula.', + 'In egestas condimentum mi, id efficitur nunc mattis sit amet.', + 'Nunc pulvinar tortor nec dolor vehicula, at porta elit porttitor.', + 'Praesent ac auctor erat.', + 'Donec eu faucibus eros, eu varius tortor.', + 'Sed eget sapien at est lacinia molestie eu in ligula.', + 'Duis mollis vehicula cursus.', + 'Duis finibus auctor pellentesque.', + 'Nullam sed urna diam.', + 'Nulla quis ipsum lacinia, placerat nisl et, dignissim est.', + 'Vivamus hendrerit, urna vel pulvinar maximus, elit turpis placerat dolor, quis sodales erat turpis sed lorem.', + 'Nulla dapibus porta odio, at porta ligula convallis a.', + 'Morbi rhoncus tempor libero, lobortis facilisis ligula convallis at.', + 'Etiam dapibus lacinia massa a finibus.', + 'Nam eget convallis mi.', + 'Integer posuere consectetur nisl eu ullamcorper.', + 'Cras et lorem sit amet dui venenatis pellentesque non laoreet quam.', + 'Sed eget fermentum diam, eget suscipit nulla.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Aliquam luctus eros quis metus faucibus luctus.', + 'Suspendisse rutrum libero magna, eu porttitor purus pretium vel.', + 'Curabitur ultricies pellentesque dui sit amet volutpat.', + 'Fusce tincidunt vulputate elit et efficitur.', + 'Nunc tincidunt malesuada dignissim.', + 'Nullam ornare venenatis purus semper porta.', + 'Nullam nisl massa, porttitor non gravida id, bibendum at dui.', + 'Curabitur rhoncus at massa ac ultricies.', + 'Phasellus aliquet ex in quam placerat feugiat.', + 'Nullam placerat in quam vitae venenatis.', + 'Vivamus quis mi accumsan, egestas nunc ac, laoreet arcu.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Sed faucibus imperdiet tortor vitae dapibus.', + 'Morbi neque sapien, aliquam eget leo in, maximus feugiat eros.', + 'In interdum ipsum quis dictum posuere.', + 'Vestibulum pellentesque ullamcorper rutrum.', + 'Vivamus sed lacus imperdiet, vehicula augue id, aliquet magna.', + 'Donec mollis auctor consectetur.', + 'Proin ultrices orci tellus, in volutpat leo pellentesque id.', + 'Donec sapien mauris, sagittis iaculis iaculis non, iaculis at nunc.', + 'In dapibus leo ac elit gravida, in ornare tortor mattis.', + 'Nam ac auctor arcu, id semper ex.', + 'Sed vitae mauris sagittis, vestibulum sapien sed, consectetur tortor.', + 'Sed dapibus metus vitae condimentum sagittis.', + 'Integer purus leo, pretium id vulputate sit amet, tempus at quam.', + 'Donec egestas laoreet efficitur.', + 'Phasellus et ante vehicula, consectetur lacus ut, vehicula nunc.', + 'Vestibulum ultricies, ligula et consequat fermentum, nisi mauris imperdiet turpis, tincidunt mollis felis tellus sed quam.', + 'Praesent id arcu dui.', + 'Suspendisse suscipit, velit vel tempus ultricies, turpis magna facilisis lectus, et varius enim sem vel enim.', + 'Vivamus id elit turpis.', + 'Duis porta, nibh sit amet pharetra dapibus, massa neque elementum turpis, et porta ante ex at libero.', + 'In tempus, sem a pulvinar viverra, turpis nulla malesuada metus, vitae posuere augue odio at nunc.', + 'Donec lectus sem, cursus ut vestibulum vitae, facilisis ac mi.', + 'Maecenas bibendum nisl eu libero hendrerit, vel mollis lorem tristique.', + 'Nulla cursus cursus mauris.', + 'Vestibulum laoreet augue ac nunc pulvinar, vestibulum ullamcorper purus volutpat.', + 'Vivamus iaculis euismod accumsan.', + 'Vestibulum eu dui feugiat, consectetur libero id, consectetur arcu.', + 'Nam lobortis ut turpis ac convallis.', + 'Duis dapibus turpis nec aliquet porta.', + 'Suspendisse id gravida nunc.', + 'Nullam tristique risus et magna dictum bibendum.', + 'Morbi semper tellus id arcu dictum, vitae accumsan purus sollicitudin.', + 'Nunc id laoreet diam.', + 'Praesent congue, elit ac molestie pharetra, nulla orci viverra turpis, quis tristique dolor sem quis magna.', + 'Donec eu ligula mauris.', + 'Etiam nec pretium arcu, et vehicula leo.', + 'Pellentesque non libero eu justo aliquet dictum.', + 'Mauris vel aliquet nulla.', + 'Aliquam vitae pharetra purus.', + 'Morbi aliquam aliquet malesuada.', + 'Duis id luctus arcu.', + 'In rutrum mattis leo.', + 'Sed mattis augue sed nulla porta, sit amet efficitur libero aliquet.', + 'Vivamus quis dignissim nibh.', + 'Donec accumsan vitae nisl ac placerat.', + 'Maecenas in neque nunc.', + 'Donec placerat quis ex id egestas.', + 'Quisque aliquam ex vel convallis eleifend.', + 'Mauris sodales elementum risus, quis fermentum augue vulputate a.', + 'Suspendisse sollicitudin finibus tellus, vitae sollicitudin eros tincidunt et.', + 'Nulla ut ex in eros consectetur aliquam.', + 'Ut maximus nulla tellus, eget tincidunt nulla auctor a.', + 'Vivamus accumsan dictum felis, sit amet tempor sapien pulvinar at.', + 'Morbi interdum, justo in scelerisque varius, purus enim vulputate nisi, consectetur interdum odio lorem vel justo.', + 'Aenean vitae hendrerit tortor.', + 'Suspendisse maximus imperdiet mi eu pellentesque.', + 'Quisque ultrices ultrices tortor, eget tristique odio pretium nec.', + 'Fusce metus dui, ultrices vel bibendum non, elementum sit amet magna.', + 'Nullam euismod ligula non ligula pulvinar, eu elementum velit cursus.', + 'Donec neque quam, feugiat nec vehicula non, ultricies non ex.', + 'Vivamus felis dui, vulputate in sollicitudin id, blandit nec odio.', + 'Pellentesque risus elit, mattis a purus vitae, varius auctor eros.', + 'Donec non rhoncus magna.', + 'Vestibulum volutpat orci enim, sed cursus massa vehicula ut.', + 'Vestibulum in rhoncus mi.', + 'Fusce vitae pulvinar nunc.', + 'Nam sit amet urna et lacus auctor accumsan et malesuada mauris.', + 'Curabitur ac eleifend urna.', + 'Maecenas a justo sed augue consequat blandit nec sit amet lacus.', + 'Phasellus vehicula est diam, in pharetra turpis porta ut.', + 'Nunc arcu lorem, pretium vitae feugiat in, elementum ac purus.', + 'Phasellus eget mollis diam, eu lacinia mi.', + 'Aenean eget lectus nulla.', + 'Integer sapien nibh, blandit quis libero mattis, ultricies consequat nisl.', + 'Nunc ac sagittis ligula, vel varius ante.', + 'Proin ut turpis a erat viverra lobortis eu quis quam.', + 'Mauris eu augue vel nisl interdum accumsan.', + 'Ut ut euismod leo.', + 'Aliquam urna turpis, blandit nec suscipit non, convallis at ante.', + 'Nulla quis molestie erat, ut venenatis nunc.', + 'Fusce pellentesque sit amet felis eu mattis.', + 'Mauris felis elit, gravida at dapibus ut, cursus at ante.', + 'Praesent in lacus euismod, porta ipsum id, feugiat mauris.', + 'Maecenas in eros nec arcu aliquet hendrerit.', + 'Duis bibendum rutrum mi.', + 'Donec elementum, felis eu fringilla placerat, mi lacus molestie tortor, et varius libero justo in tortor.', + 'Integer rutrum at neque et luctus.', + 'Nullam faucibus tempus metus, vitae dignissim leo viverra a.', + 'Integer augue erat, aliquet id tortor a, convallis dignissim tellus.', + 'Morbi elementum mollis tellus, id interdum arcu sodales sit amet.', + 'Suspendisse a sapien quis nibh convallis laoreet eu eget sem.', + 'Aliquam blandit odio vel nulla rhoncus dapibus.', + 'Nullam mollis tristique ligula, in tristique mauris eleifend id.', + 'Pellentesque eget consequat nunc.', + 'Donec et orci hendrerit, lacinia nisl in, pretium ex.', + 'Quisque sit amet eleifend tortor.', + 'Proin viverra dui eget tortor faucibus hendrerit.', + 'Etiam pretium fringilla justo, quis ornare risus posuere quis.', + 'Sed commodo maximus mauris, eu vulputate metus consectetur eget.', + 'Maecenas in arcu porttitor, condimentum arcu at, pretium ante.', + 'Ut vel urna viverra diam gravida condimentum non at enim.', + 'In ligula orci, malesuada convallis est a, egestas auctor elit.', + 'Sed blandit sagittis ipsum, id tempus diam ornare at.', + 'Mauris volutpat faucibus magna ac sodales.', + 'Fusce eget arcu et nunc rhoncus egestas et vel metus.', + 'Vestibulum egestas euismod bibendum.', + 'Ut id ex cursus, congue nulla ac, finibus mi.', + 'Suspendisse vitae tempor arcu.', + 'Integer ultricies orci purus, non finibus nisi laoreet in.', + 'Vestibulum metus purus, sodales rutrum tincidunt pharetra, eleifend vel dui.', + 'Pellentesque convallis dolor sed consequat pretium.', + 'Fusce suscipit ex ante, ac accumsan quam eleifend non.', + 'Donec porta, neque eu cursus cursus, enim arcu consequat neque, cursus laoreet dolor nunc at sem.', + 'Praesent sit amet arcu eros.', + 'Donec congue tellus nec mi ullamcorper pretium.', + 'Duis aliquet, orci eu facilisis dapibus, mauris erat congue neque, in commodo diam libero maximus urna.', + 'Curabitur interdum et metus at ullamcorper.', + 'Nulla a dui purus.', + 'Proin sed dapibus risus.', + 'Nunc consectetur posuere maximus.', + 'In sodales sem nisl, ut varius est venenatis at.', + 'Vestibulum non consectetur lorem.', + 'Nunc id risus sapien.', + 'Sed tristique condimentum tortor, tincidunt vulputate turpis.', + 'Ut neque purus, molestie eu varius vitae, venenatis sit amet nulla.', + 'Quisque dapibus libero libero, sed blandit lectus blandit sed.', + 'Nulla congue urna quis metus molestie vehicula.', + 'Vivamus sed aliquet felis, volutpat dignissim metus.', + 'Duis id augue neque.', + 'Nullam placerat mollis malesuada.', + 'Aenean malesuada elit ac ante imperdiet posuere sed et nibh.', + 'Vivamus id interdum ligula.', + 'Nunc nisl tellus, aliquam nec tristique et, elementum non est.', + 'Praesent fermentum gravida dolor, eu viverra justo posuere id.', + 'Ut nec iaculis velit, quis pretium mi.', + 'Vivamus scelerisque dolor sit amet erat dapibus consectetur.', + 'Pellentesque dolor risus, maximus quis gravida non, viverra sit amet dui.', + 'Phasellus placerat lectus velit, id ultrices augue posuere id.', + 'In consequat aliquet justo, in ornare turpis tempus sed.', + 'Fusce condimentum rhoncus condimentum.', + 'Phasellus convallis, sem molestie scelerisque congue, est justo lobortis diam, id commodo ligula ipsum eu nibh.', + 'Etiam id dolor vehicula, vehicula orci vitae, elementum dolor.', + 'Proin sit amet massa et dui varius auctor at nec ex.', + 'Donec ultrices sem vel nisi fermentum vulputate.', + 'In viverra quam ante, sit amet efficitur est varius sed.', + 'Sed vestibulum, tortor sed tincidunt congue, eros turpis mollis ipsum, id dictum nibh ipsum et metus.', + 'Proin nec sem eros.', + 'Donec vulputate lacus nisl, nec consectetur nulla blandit ac.', + 'Nulla sapien ipsum, tristique a mi sed, iaculis accumsan sapien.', + 'Etiam vitae est quis purus rhoncus blandit.', + 'Proin suscipit nec tortor sit amet malesuada.', + 'Aenean felis odio, facilisis sit amet enim in, condimentum sollicitudin ante.', + 'Nullam porttitor vel nulla sit amet feugiat.', + 'Phasellus mi libero, vulputate eu magna at, molestie aliquet erat.', + 'Mauris eros lorem, malesuada nec ligula vitae, pellentesque consequat est.', + 'Donec sodales pellentesque mi vitae pulvinar.', + 'Morbi sapien nisi, commodo nec ultricies et, iaculis nec nisl.', + 'Vestibulum maximus luctus elit malesuada tincidunt.', + 'Duis eget varius orci, eget sagittis eros.', + 'Quisque eu eros nisl.', + 'Pellentesque eleifend aliquam metus, a finibus neque sodales eu.', + 'Sed tempus ligula sapien, eu scelerisque nisl porttitor gravida.', + 'Sed vitae lectus sit amet lectus ornare interdum.', + 'Aenean arcu diam, porta sit amet lorem eget, sagittis iaculis erat.', + 'Nulla pharetra, sem non auctor ultrices, ex metus dictum magna, at sollicitudin ex justo ut turpis.', + 'Sed aliquam luctus semper.', + 'Nullam vitae malesuada sapien, tempor scelerisque lorem.', + 'Integer congue lorem ligula, ac volutpat lorem sagittis id.', + 'Nam nec pretium elit.', + 'Quisque volutpat ex dui, a sagittis augue consequat tincidunt.', + 'Cras tristique felis arcu, at vestibulum enim scelerisque sollicitudin.', + 'Nunc est metus, semper vel magna et, tincidunt scelerisque felis.', + 'Morbi lacus nisl, porttitor ac justo non, ultricies fringilla tellus.', + 'Ut eu metus metus.', + 'Proin vehicula vestibulum sollicitudin.', + 'Sed iaculis sem non ante ultricies, at semper libero porttitor.', + 'Ut dapibus laoreet sem ac consectetur.', + 'Etiam hendrerit, odio sit amet iaculis semper, ligula sapien rhoncus lorem, sit amet cursus eros ante sed nunc.', + 'Etiam interdum pellentesque enim id dapibus.', + 'Fusce luctus orci tortor.', + 'Cras id bibendum risus.', + 'Nam pretium felis nec ante tincidunt interdum.', + 'Nam cursus nibh non justo pharetra tristique.', + 'Nam facilisis dapibus lacus sit amet volutpat.', + 'Morbi felis ex, semper sed tortor eu, finibus aliquet lacus.', + 'Integer a orci augue.', + 'Vivamus lobortis tellus sed est fringilla ornare.', + 'Mauris tempus ante tortor, ac feugiat dui viverra et.', + 'Vivamus risus leo, ultrices at eleifend vel, luctus non arcu.', + 'Nullam dictum purus commodo turpis maximus, a mollis nibh efficitur.', + 'Nullam elementum dapibus suscipit.', + 'Nullam blandit sem lacus, vel blandit eros fermentum et.', + 'Sed cursus fermentum augue sit amet rutrum.', + 'Maecenas posuere, ante sed tristique ultrices, nisl orci molestie metus, sed vehicula mauris odio quis neque.', + 'Aliquam quis elit enim.', + 'Aenean cursus, turpis vel rhoncus imperdiet, dolor est consectetur metus, nec egestas elit orci ac ex.', + 'Fusce convallis justo eget dui ultrices, nec venenatis felis venenatis.', + 'Praesent eleifend, arcu eget auctor venenatis, nibh mi aliquet ligula, ac sagittis risus mi sed est.', + 'Phasellus pharetra, leo sed elementum aliquam, nisl justo lacinia ante, eu vehicula justo diam a sem.', + 'Praesent ac convallis neque, a dictum ipsum.', + 'Quisque venenatis nulla porta nunc semper sollicitudin.', + 'Duis a lectus velit.', + 'Phasellus lobortis, arcu et feugiat imperdiet, magna ipsum vestibulum massa, eget ullamcorper libero eros sed justo.', + 'Vivamus eget augue a ligula ultrices condimentum.', + 'Maecenas at eros a eros dictum mollis.', + 'Sed pellentesque tempor purus rhoncus pulvinar.', + 'Vestibulum faucibus urna quis convallis rutrum.', + 'Donec ultricies tempor nunc, a facilisis velit elementum non.', + 'Sed in risus in ante eleifend congue sed non nisl.', + 'Vestibulum in ante quis libero rhoncus sollicitudin id in quam.', + 'Sed imperdiet dapibus purus.', + 'Sed blandit, enim a cursus scelerisque, ante purus ornare massa, in dictum lacus neque id quam.', + 'Suspendisse tincidunt consectetur eros ac imperdiet.', + 'Sed ac justo feugiat, convallis ligula eget, interdum erat.', + 'Integer fermentum id arcu quis blandit.', + 'Curabitur iaculis, mauris at efficitur condimentum, justo lectus ornare quam, a euismod enim dolor gravida sem.', + 'Vivamus eu diam et nisl tincidunt pretium.', + 'Nullam sodales pulvinar urna in ultricies.', + 'Phasellus in condimentum enim.', + 'Vivamus eu mollis lacus.', + 'Etiam id ante eget dolor vehicula porta.', + 'Etiam purus urna, bibendum sollicitudin viverra quis, tristique id felis.', + 'Morbi porttitor tortor eget lorem commodo, nec pharetra urna vestibulum.', + 'Integer id faucibus massa.', + 'Duis interdum, quam quis ornare vulputate, eros est sodales ligula, a tincidunt mauris turpis ac diam.', + 'Mauris dictum nisl a vulputate cursus.', + 'Nulla cursus accumsan nisi, sit amet vulputate sapien semper ac.', + 'Vestibulum malesuada sodales condimentum.', + 'Sed tincidunt iaculis interdum.', + 'Maecenas quis nulla arcu.', + 'Fusce lacus urna, vulputate eu fringilla ut, vulputate quis magna.', + 'Vivamus a commodo neque.', + 'Donec maximus erat libero, eget sagittis magna tincidunt ac.', + 'Proin at dui id orci ornare vestibulum.', + 'Ut porttitor eget urna non efficitur.', + 'Nullam ut ligula est.', + 'Vestibulum vulputate, nulla sit amet laoreet egestas, ex mauris mattis metus, ut bibendum elit diam nec felis.', + 'Duis tempus finibus lorem, sit amet consequat dolor porta eu.', + 'Phasellus vel fringilla orci.', + 'Curabitur nec elit pulvinar mi vestibulum accumsan id quis augue.', + 'Ut ante neque, malesuada sed lacinia id, faucibus eget dui.', + 'In dui nibh, dignissim sed nisi at, feugiat vestibulum odio.', + 'Nunc ac lacus eleifend, laoreet tellus sit amet, condimentum nulla.', + 'Sed ac elit a lacus fermentum auctor in ac mi.', + 'Donec a justo in tellus laoreet facilisis.', + 'Pellentesque a enim dui.', + 'Vivamus sit amet rhoncus neque.', + 'Vivamus risus leo, aliquet ut sollicitudin vel, blandit in risus.', + 'Pellentesque eget tincidunt urna.', + 'Duis iaculis suscipit diam a tempus.', + 'Etiam posuere eu est vel congue.', + 'Nunc vel accumsan justo.', + 'Sed pharetra arcu vitae mauris eleifend, eu fermentum elit fermentum.', + 'In suscipit quam neque, ut dapibus urna venenatis in.', + 'Vivamus ultrices consequat risus, ac vestibulum orci porta finibus.', + 'Fusce sem orci, egestas ut feugiat sit amet, molestie quis arcu.', + 'Fusce vel ex nec justo ullamcorper viverra sit amet sed justo.', + 'Nunc sit amet leo consequat, commodo mauris quis, euismod mi.', + 'Ut finibus sapien ut dictum maximus.', + 'Suspendisse sed dui urna.', + 'Ut mattis et ex sit amet sagittis.', + 'Nulla vitae condimentum metus.', + 'Fusce sodales nulla metus, lacinia tincidunt sapien lobortis tincidunt.', + 'Vestibulum dapibus urna diam, nec ultricies neque feugiat et.', + 'Vestibulum eget quam ac lectus fermentum sagittis eu sit amet massa.', + 'Suspendisse quis diam eget felis faucibus tempus.', + 'Nullam nec consectetur urna.', + 'Aenean pharetra ullamcorper nibh, in maximus dui molestie non.', + 'Mauris laoreet, ex id volutpat bibendum, magna purus sodales lacus, eu fringilla ante ex ac metus.', + 'Suspendisse ac sapien massa.', + 'Donec pellentesque, ipsum in mollis accumsan, nisi risus sodales nisl, sed malesuada enim nibh quis mi.', + 'Duis varius viverra lacus non ultricies.', + 'Vestibulum venenatis id odio eget gravida.', + 'Suspendisse at quam et justo sollicitudin ornare eget ut felis.', + 'Etiam rhoncus ornare nisl ac tincidunt.', + 'Etiam vitae maximus tellus.', + 'In nibh leo, mattis vel tellus id, facilisis imperdiet lacus.', + 'Mauris sagittis ut erat eget porta.', + 'Nam a lectus laoreet, consequat elit ac, porta magna.', + 'Aenean commodo suscipit lorem, quis iaculis risus interdum ut.', + 'In cursus ullamcorper quam vel imperdiet.', + 'Nullam id mattis lectus.', + 'Cras sagittis massa urna, vitae mollis elit tincidunt a.', + 'Aliquam commodo urna quis nunc elementum ultricies at interdum massa.', + 'Sed pharetra urna eros, eget aliquam sem interdum id.', + 'Integer vestibulum dolor eget urna suscipit ultricies.', + 'Nam facilisis velit non mi pulvinar, eu mattis massa interdum.', + 'Sed faucibus, velit id tempor maximus, magna odio sodales ligula, vitae efficitur massa nunc non odio.', + 'Integer mattis lorem vitae turpis molestie faucibus.', + 'Praesent sagittis, quam quis placerat viverra, orci eros interdum mauris, ac iaculis erat lectus vel augue.', + 'Donec dapibus leo leo, accumsan tincidunt augue aliquet et.', + 'Ut non erat sed odio gravida blandit.', + 'Praesent placerat ante nulla, a iaculis magna lobortis in.', + 'Nulla erat nisi, pharetra at luctus vitae, cursus eget neque.', + 'Vivamus diam ante, pulvinar elementum vestibulum ut, fringilla quis lacus.', + 'Pellentesque ultrices odio placerat sollicitudin tincidunt.', + 'Nunc accumsan nisl nunc, tempor egestas odio elementum a.', + 'Vestibulum ut leo euismod, hendrerit tortor sed, eleifend purus.', + 'Aenean venenatis viverra elementum.', + 'Vivamus eu mattis quam, sit amet iaculis mi.', + 'Proin ultricies, arcu et tempus blandit, neque tortor vehicula felis, quis mattis magna metus non velit.', + 'Mauris imperdiet eu quam nec efficitur.', + 'Nam sodales sem at nulla laoreet, a luctus odio viverra.', + 'Morbi non lectus semper, interdum lectus ac, elementum purus.', + 'Vestibulum efficitur faucibus volutpat.', + 'Aliquam pellentesque, ex id laoreet gravida, sapien orci sodales dolor, vitae pretium turpis dolor a metus.', + 'Nulla metus tellus, porttitor in placerat non, laoreet eget nunc.', + 'Maecenas euismod massa et viverra consectetur.', + 'Curabitur est sapien, commodo vel urna lacinia, accumsan viverra libero.', + 'Maecenas fringilla, odio vitae congue malesuada, elit mi rhoncus erat, at hendrerit metus magna et eros.', + 'Suspendisse efficitur cursus purus quis commodo.', + 'Duis egestas sem urna.', + 'Suspendisse consectetur posuere purus id dignissim.', + 'Aenean ut congue velit.', + 'Etiam suscipit, tellus non laoreet maximus, orci dolor faucibus velit, quis vulputate leo dui in lacus.', + 'Ut iaculis metus ante, sed sollicitudin sem consequat ut.', + 'Fusce semper mattis turpis, vel elementum leo ornare eget.', + 'Donec magna nulla, vulputate quis lacinia sit amet, tempor ac mauris.', + 'Aenean interdum purus ligula, ut porttitor arcu aliquam vitae.', + 'Morbi venenatis sem in velit venenatis rutrum.', + 'Nullam porta leo convallis, molestie massa non, sagittis metus.', + 'Nunc posuere pretium augue, eu condimentum augue sollicitudin sit amet.', + 'Pellentesque elementum ipsum nec tincidunt aliquam.', + 'Pellentesque massa enim, vehicula quis euismod non, lobortis eget magna.', + 'Mauris posuere risus non velit vestibulum pretium non non ipsum.', + 'Cras vel ornare turpis, vel feugiat purus.', + 'Quisque odio eros, porttitor nec vulputate vitae, sollicitudin pretium purus.', + 'Maecenas imperdiet lacus a urna finibus fringilla sit amet et felis.', + 'Aenean quis ipsum tempus, pellentesque nunc mattis, tristique diam.', + 'Vestibulum vitae nunc hendrerit, gravida sem eu, tempus risus.', + 'Donec condimentum bibendum ipsum, a hendrerit neque posuere nec.', + 'Donec a dolor a massa maximus efficitur.', + 'Praesent velit massa, tempus ac semper quis, scelerisque vitae ante.', + 'Aliquam purus urna, hendrerit vitae sagittis at, porta vel justo.', + 'Curabitur pellentesque consectetur lobortis.', + 'Vivamus scelerisque hendrerit venenatis.', + 'Integer tincidunt ut diam sed congue.', + 'Sed ut aliquam nisi.', + 'Nullam nec eros id nunc semper luctus.', + 'Aliquam maximus eleifend dui, nec blandit massa bibendum eget.', + 'Donec interdum placerat tincidunt.', + 'Quisque non nulla sapien.', + 'Etiam tincidunt eros eget elit bibendum gravida.', + 'Quisque fringilla facilisis tortor quis ullamcorper.', + 'Integer gravida justo in iaculis posuere.', + 'Praesent sed tincidunt sapien.', + 'Sed euismod vitae ex vel scelerisque.', + 'Aenean nisi felis, ornare et feugiat eget, sodales vitae odio.', + 'Aenean libero sapien, lacinia ac sapien ac, laoreet dignissim dui.', + 'Nunc nibh massa, convallis in augue et, efficitur mattis elit.', + 'Suspendisse id nisl luctus, sollicitudin justo non, luctus arcu.', + 'Aliquam a est massa.', + 'Pellentesque dignissim mattis arcu.', + 'Aliquam efficitur ante metus, ut pellentesque felis suscipit eu.', + 'Ut facilisis vestibulum arcu elementum dignissim.', + 'Cras non sapien mauris.', + 'Maecenas interdum libero eu libero luctus, sit amet efficitur leo porttitor.', + 'Duis ut mollis ex.', + 'Quisque mi eros, suscipit vitae tempus ut, condimentum sit amet est.', + 'Ut non posuere erat.', + 'Curabitur bibendum magna turpis, non tincidunt risus dictum at.', + 'Etiam tempus magna at odio auctor, ac euismod nibh pulvinar.', + 'Morbi dapibus et sapien in elementum.', + 'Ut finibus est odio, eu convallis nunc viverra id.', + 'Quisque rhoncus mollis est sit amet semper.', + 'Ut dapibus urna sed diam ornare, eu efficitur leo feugiat.', + 'Vestibulum vel felis et erat molestie volutpat.', + 'Maecenas molestie lorem eget quam porta, a venenatis felis accumsan.', + 'In id auctor risus.', + 'Phasellus at diam sed orci porttitor tempus.', + 'Nunc dapibus, massa id ornare condimentum, mi sem ullamcorper nunc, et auctor felis felis id sem.', + 'Suspendisse nec vehicula augue.', + 'Aliquam imperdiet sagittis justo at iaculis.', + 'Praesent vulputate tellus ornare malesuada faucibus.', + 'Sed sed tristique ante.', + 'Curabitur ac augue et leo fermentum commodo eu in nulla.', + 'Aliquam pellentesque risus velit, a consequat dolor vestibulum ac.', + 'Fusce in dolor porttitor arcu viverra gravida.', + 'Maecenas ex orci, pretium vitae dui eget, scelerisque dapibus arcu.', + 'Praesent efficitur efficitur imperdiet.', + 'Curabitur eget tortor finibus, elementum orci quis, viverra arcu.', + 'Aenean ac tincidunt lacus.', + 'Donec vel ultricies est.', + 'Mauris mollis nisi a efficitur scelerisque.', + 'Nam dictum lacinia odio at pharetra.', + 'Quisque ultricies arcu in venenatis rutrum.', + 'In odio ipsum, euismod in posuere eget, placerat et felis.', + 'Curabitur mi est, placerat quis egestas non, mollis sed urna.', + 'Praesent malesuada, dolor in fermentum faucibus, tellus velit accumsan ipsum, tincidunt luctus turpis nulla sed enim.', + 'Integer rhoncus, turpis id tincidunt pulvinar, metus orci cursus mi, nec feugiat lorem elit ut enim.', + 'Aliquam et felis vel elit porta cursus in sit amet diam.', + 'In a vehicula eros, eu ullamcorper turpis.', + 'Vivamus eleifend libero non nulla accumsan porttitor.', + 'Suspendisse vel neque ultrices, scelerisque lacus in, ornare massa.', + 'Duis dolor leo, ullamcorper vel lacinia eget, aliquam rhoncus risus.', + 'Vivamus dapibus ac elit sed imperdiet.', + 'Vestibulum eget auctor dui, at tempus dolor.', + 'Sed consequat placerat libero, et sodales sapien porttitor non.', + 'Aenean arcu diam, imperdiet sit amet purus a, ornare sodales metus.', + 'Integer accumsan ante sem, at facilisis ipsum egestas et.', + 'Nulla non orci dolor.', + 'Sed rhoncus facilisis condimentum.', + 'Nulla vitae maximus nisl.', + 'Praesent a rhoncus ante, a pharetra ante.', + 'Fusce volutpat eu risus nec eleifend.', + 'Suspendisse nibh leo, semper in egestas eget, placerat vel nulla.', + 'Ut malesuada condimentum eros, id dignissim nunc imperdiet ac.', + 'Praesent posuere tortor vitae augue convallis malesuada.', + 'Donec congue sem eu leo dignissim, at blandit felis blandit.', + 'In auctor, sapien quis hendrerit auctor, arcu tellus aliquam ante, quis vulputate purus metus eget mauris.', + 'Proin eget purus purus.', + 'Vestibulum pretium pharetra egestas.', + 'Proin vulputate augue non odio commodo, eu varius sem porta.', + 'Quisque porta massa quis finibus dignissim.', + 'Sed sit amet lectus sit amet elit porta rutrum.', + 'Nunc ornare vulputate tellus, eu rutrum turpis sagittis rutrum.', + 'Nam elit justo, laoreet a tortor et, tempus dapibus sapien.', + 'Sed velit augue, maximus et dignissim sed, mollis id mi.', + 'Integer eget libero consequat, placerat massa maximus, efficitur dui.', + 'Praesent quis ipsum a ex ultricies euismod a sit amet mi.', + 'Curabitur at accumsan urna.', + 'Cras pulvinar leo sit amet ligula suscipit mattis.', + 'Morbi dapibus facilisis euismod.', + 'Quisque efficitur venenatis eros ac elementum.', + 'Suspendisse imperdiet nunc non libero consectetur, eget blandit libero mattis.', + 'Vivamus tempor ullamcorper sapien vitae aliquam.', + 'In eget tempus ante.', + 'Vestibulum accumsan enim sed est eleifend, non commodo orci tristique.', + 'Nam pellentesque nisi a laoreet lobortis.', + 'Sed faucibus eros nec urna elementum, sed tincidunt est elementum.', + 'Suspendisse bibendum, velit nec tempus ullamcorper, urna elit auctor mauris, et tempus dui purus ut sapien.', + 'Aliquam posuere pulvinar lorem, ac vulputate neque congue eget.', + 'Vivamus sit amet elit id ante pellentesque rhoncus.', + 'Maecenas sagittis dui justo, id bibendum nulla egestas ac.', + 'Mauris placerat sapien urna, eget porta nisi molestie eu.', + 'Pellentesque metus arcu, gravida eget erat et, condimentum sodales quam.', + 'Ut finibus tortor ac dui vestibulum, et interdum elit fringilla.', + 'Aliquam a fringilla augue.', + 'Aenean placerat, enim nec dapibus viverra, arcu leo pharetra nibh, id pretium nisl purus et orci.', + 'Praesent felis odio, bibendum ut rutrum non, vehicula mollis tortor.', + 'Nam id vulputate magna.', + 'Vivamus ultrices purus vitae risus vehicula, et varius magna fringilla.', + 'Integer mollis, arcu in aliquet eleifend, augue felis suscipit augue, vitae consectetur sem elit non neque.', + 'Suspendisse dictum, lectus et sagittis dictum, turpis lorem ultrices odio, vitae tincidunt ex dolor vitae leo.', + 'Nulla aliquet risus ut augue finibus, ac egestas ante varius.', + 'In eget est a urna pulvinar bibendum quis eget dui.', + 'In sodales auctor imperdiet.', + 'Aenean et ipsum commodo, gravida erat vel, molestie nunc.', + 'Etiam maximus nibh finibus ex aliquet aliquam.', + 'Aliquam ultricies tellus lectus, ac suscipit tellus congue ac.', + 'Ut id ullamcorper urna.', + 'Aliquam ut faucibus nunc.', + 'Morbi vel elit dapibus, faucibus sem quis, feugiat lacus.', + 'Sed euismod diam mi, ac lacinia diam ornare sed.', + 'Duis dictum sodales turpis at feugiat.', + 'Donec id orci maximus, venenatis metus quis, tincidunt sapien.', + 'Etiam et justo non orci elementum bibendum ut sed elit.', + 'Donec imperdiet porta augue eget suscipit.', + 'Donec posuere dui eget quam faucibus hendrerit.', + 'Nunc non nibh mi.', + 'Nullam augue ex, tincidunt nec turpis pretium, porttitor tempor neque.', + 'Integer vel neque commodo, consectetur nulla a, blandit risus.', + 'Quisque maximus est condimentum hendrerit placerat.', + 'Morbi sagittis posuere feugiat.', + 'Mauris nec lacinia dolor, eu accumsan ante.', + 'Sed eu lorem auctor, gravida ligula vitae, auctor arcu.', + 'Curabitur porttitor et lacus nec tempor.', + 'Nulla sed posuere lorem, at facilisis quam.', + 'Sed ornare leo vitae ipsum condimentum, in ullamcorper magna rhoncus.', + 'Nullam quis augue tristique, scelerisque turpis sit amet, placerat tortor.', + 'Suspendisse aliquam magna a suscipit egestas.', + 'Fusce dictum consectetur mattis.', + 'Etiam commodo iaculis neque quis scelerisque.', + 'Nulla eu condimentum lectus, vitae tincidunt nisi.', + 'Vestibulum lacinia ac ligula quis fringilla.', + 'Pellentesque aliquam posuere nunc sed malesuada.', + 'Fusce a sem lobortis, egestas tortor eu, mollis sapien.', + 'Praesent malesuada consequat ante in hendrerit.', + 'Pellentesque lorem ligula, sodales quis suscipit at, venenatis in risus.', + 'Phasellus sapien nibh, tincidunt ut suscipit non, hendrerit id turpis.', + 'Maecenas ut lorem non risus efficitur tristique ac at arcu.', + 'Phasellus consequat urna ligula, a luctus justo cursus ac.', + 'Praesent et augue augue.', + 'Morbi accumsan neque id nisl malesuada, quis cursus sapien blandit.', + 'Phasellus ultrices dignissim neque a posuere.', + 'Mauris eu vehicula nunc.', + 'Sed egestas nisi dui, at lobortis dui condimentum vitae.', + 'Quisque sit amet dui eu massa molestie malesuada iaculis in nulla.', + 'Phasellus et molestie lacus.', + 'Pellentesque egestas iaculis tortor, ac tempus ante commodo non.', + 'Maecenas ullamcorper dictum tortor ut luctus.', + 'Curabitur id dui quis felis pharetra elementum vitae nec elit.', + 'Nunc dictum malesuada ante, in elementum nulla ornare ut.', + 'Vivamus luctus lacus id venenatis eleifend.', + 'Suspendisse a venenatis turpis.', + 'Sed suscipit feugiat massa sed molestie.', + 'Suspendisse vitae ornare quam.', + 'Vivamus tincidunt metus sed aliquet sodales.', + 'Ut quis massa a magna vulputate dictum in vitae ex.', + 'Phasellus nulla elit, volutpat eu tincidunt eu, fringilla interdum metus.', + 'Praesent dignissim felis nec est molestie, in commodo lectus tempor.', + 'Donec quis mi venenatis, suscipit nibh eget, euismod dui.', + 'Morbi enim elit, tempor at euismod quis, lacinia sit amet risus.', + 'Vestibulum vitae pharetra magna, non luctus mauris.', + 'Nullam vel luctus arcu, condimentum posuere libero.', + 'Ut ullamcorper, dolor ac interdum auctor, massa leo vehicula urna, sed interdum lacus magna in quam.', + 'Integer pretium pulvinar sem, eget vehicula sem egestas vel.', + 'Aenean malesuada odio eget fermentum facilisis.', + 'Suspendisse finibus, tortor sit amet porta ultricies, sapien dolor sodales metus, a commodo risus nulla vel justo.', + 'Integer nec justo at neque aliquam ultrices a quis libero.', + 'Ut sem ligula, facilisis ut turpis quis, convallis porta ex.', + 'Nam sed ullamcorper ipsum, ut tincidunt risus.', + 'Curabitur nisi nisl, finibus et maximus id, bibendum hendrerit risus.', + 'Suspendisse molestie laoreet quam, in lobortis ipsum sodales id.', + 'Integer et suscipit nisi.', + 'Mauris mattis porta malesuada.', + 'Vivamus interdum blandit dolor, vitae egestas turpis rutrum eget.', + 'In a est sit amet dolor tristique vehicula.', + 'Sed et vehicula magna, eget laoreet dui.', + 'In convallis sem in maximus luctus.', + 'Vestibulum vestibulum convallis diam, nec tristique nisl cursus vel.', + 'Suspendisse nec lorem eget ligula venenatis placerat et et massa.', + 'Vestibulum efficitur ac libero vel fermentum.', + 'Cras condimentum diam turpis, sit amet egestas neque hendrerit ac.', + 'Pellentesque mattis mollis dignissim.', + 'Donec eleifend magna ac pulvinar sagittis.', + 'Vestibulum accumsan vulputate odio et molestie.', + 'Vestibulum accumsan volutpat interdum.', + 'Fusce vestibulum feugiat odio bibendum bibendum.', + 'Mauris non blandit nibh, id mattis dolor.', + 'Nunc interdum ipsum quis sem scelerisque sagittis.', + 'Integer sit amet dapibus velit, sit amet facilisis sem.', + 'In hendrerit sapien vel nulla rutrum, at lobortis quam gravida.', + 'Etiam euismod est quis leo convallis, eu interdum risus viverra.', + 'Nam ullamcorper imperdiet erat, ut efficitur nunc molestie a.', + 'Sed eget tellus cursus, ullamcorper odio sit amet, semper est.', + 'Aliquam suscipit urna ex, quis sodales nisi dapibus non.', + 'Nulla quis leo non tellus sollicitudin suscipit.', + 'Fusce in aliquet nulla.', + 'Donec risus tellus, imperdiet sed vulputate ut, pulvinar malesuada quam.', + 'Morbi id ligula leo.', + 'Fusce varius mauris dui, vel placerat magna efficitur eget.', + 'Morbi vulputate et lectus a porta.', + 'Quisque porta tortor sapien, quis rhoncus libero maximus volutpat.', + 'Cras sodales ex nec tortor finibus, aliquet scelerisque sem pellentesque.', + 'Aliquam ornare sodales quam.', + 'Donec eleifend ornare velit, in mollis elit.', + 'Nunc bibendum venenatis dui, sit amet scelerisque ex blandit eget.', + 'In non lacus iaculis, dictum urna id, placerat lorem.', + 'Vestibulum quis sem imperdiet, pellentesque neque ac, varius justo.', + 'Phasellus porta, augue at mattis dignissim, erat tortor porttitor leo, eu pretium purus lectus quis diam.', + 'Nam scelerisque, turpis eget pharetra sollicitudin, erat lacus tincidunt odio, at condimentum augue eros nec lectus.', + 'Proin vestibulum, tortor non maximus sodales, quam nibh gravida risus, vitae porta ex nisi eget velit.', + 'Cras at orci eu tortor vulputate facilisis nec in ex.', + 'Donec a turpis pulvinar, gravida nisl ut, suscipit justo.', + 'Vestibulum pharetra, lacus eu sodales vestibulum, eros lectus ullamcorper odio, in vulputate dui leo a enim.', + 'Aenean at consectetur quam, in elementum ipsum.', + 'Vestibulum maximus aliquam leo, vitae accumsan felis hendrerit varius.', + 'Sed bibendum vestibulum nibh, scelerisque dictum ex feugiat et.', + 'Suspendisse placerat dolor quis aliquam maximus.', + 'Sed sed enim convallis, sodales nulla id, molestie nisi.', + 'Aliquam at iaculis ante.', + 'Cras blandit hendrerit accumsan.', + 'Vestibulum convallis nisi vel dui luctus, sit amet malesuada mi tincidunt.', + 'Nunc tempor eget massa porta dignissim.', + 'Proin ut congue neque, sit amet maximus felis.', + 'Mauris ultrices eleifend nunc.', + 'Maecenas maximus mauris ac sagittis volutpat.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Cras ac pulvinar diam.', + 'Donec mollis mi eu arcu convallis mattis.', + 'Donec ipsum lectus, placerat sed consectetur id, ultricies nec tortor.', + 'Cras tellus augue, faucibus et felis ut, vehicula pretium sem.', + 'Fusce sit amet cursus leo, nec cursus dui.', + 'Curabitur massa leo, varius ut consectetur in, sodales sit amet nisi.', + 'In faucibus nibh id massa porttitor, vitae sollicitudin metus pretium.', + 'Phasellus ultrices erat enim, vitae mollis justo tincidunt at.', + 'Donec accumsan commodo quam non iaculis.', + 'Pellentesque viverra et magna eget sollicitudin.', + 'Suspendisse at dui eu diam mattis congue sagittis in magna.', + 'Fusce fermentum commodo arcu sed consectetur.', + 'Fusce nec orci lacus.', + 'Aliquam eu mauris accumsan, ullamcorper massa eu, facilisis augue.', + 'Curabitur vel tincidunt felis, vitae faucibus nibh.', + 'Cras mattis dignissim viverra.', + 'Phasellus sed erat congue, maximus quam id, blandit lectus.', + 'Pellentesque a volutpat magna.', + 'Aenean tempus, tortor sit amet porttitor consectetur, ante libero pulvinar urna, at euismod purus erat a turpis.', + 'Vestibulum congue interdum laoreet.', + 'Morbi auctor sollicitudin lacus nec feugiat.', + 'Etiam et justo eget elit egestas bibendum eget varius nibh.', + 'Phasellus tempor ullamcorper tellus, fermentum lobortis velit luctus vel.', + 'In commodo ac ligula sit amet maximus.', + 'Duis consectetur nibh velit, vitae tristique urna mattis at.', + 'Cras vitae risus at metus finibus vestibulum.', + 'Ut sit amet suscipit mauris.', + 'Fusce euismod dolor non nibh consequat viverra.', + 'Duis viverra orci magna, vel volutpat turpis pretium vel.', + 'Integer ultricies tempus augue ut ultrices.', + 'Ut gravida ante venenatis commodo dapibus.', + 'Fusce tincidunt id nisl nec tincidunt.', + 'Phasellus sed diam bibendum, tincidunt felis ac, malesuada augue.', + 'In convallis mauris non turpis convallis auctor.', + 'Vivamus dolor tortor, suscipit at vulputate vitae, ullamcorper vitae ipsum.', + 'Sed dictum eros neque, sit amet cursus felis condimentum ac.', + 'Sed laoreet diam eu euismod tempus.', + 'Phasellus ultricies suscipit lacus, at faucibus est varius ac.', + 'Praesent aliquam tristique interdum.', + 'Quisque quis porttitor ipsum, sed pellentesque arcu.', + 'Ut convallis eros sed tellus euismod posuere.', + 'Proin eget dictum lacus.', + 'Mauris scelerisque ex ac faucibus maximus.', + 'Donec at leo sed libero iaculis gravida sed ac enim.', + 'Proin a consequat ligula.', + 'In euismod tempus velit vel condimentum.', + 'Proin viverra convallis ipsum sit amet accumsan.', + 'Ut mi nisl, consequat a neque eu, aliquam placerat quam.', + 'Duis tempus ullamcorper risus ut finibus.', + 'Duis ac enim eros.', + 'In blandit malesuada tellus, in bibendum massa condimentum in.', + 'Vivamus quis orci libero.', + 'Cras eu condimentum ipsum.', + 'Maecenas lacinia lobortis euismod.', + 'Nulla at imperdiet nibh, eget lacinia augue.', + 'Curabitur sit amet pulvinar ipsum.', + 'Praesent tincidunt velit in nunc congue dictum.', + 'Cras arcu arcu, elementum sit amet molestie non, pellentesque id orci.', + 'Vestibulum eleifend faucibus magna pellentesque imperdiet.', + 'Curabitur convallis non nunc nec consectetur.', + 'Integer at maximus tellus, ac pellentesque velit.', + 'Etiam nec elementum turpis, et blandit sapien.', + 'Mauris iaculis pulvinar ipsum, ac vulputate lacus maximus sit amet.', + 'Mauris quis turpis in orci ornare posuere at quis lorem.', + 'Etiam egestas aliquam rhoncus.', + 'Maecenas metus ex, lobortis malesuada rutrum viverra, pellentesque quis ligula.', + 'Pellentesque a nunc orci.', + 'Integer vitae elit sodales nisl aliquet luctus nec eu augue.', + 'Pellentesque feugiat eget urna eu molestie.', + 'Quisque dolor sem, gravida id nisl nec, sodales hendrerit sapien.', + 'Vivamus vehicula neque lacus.', + 'Duis non justo et nunc consequat sagittis non in eros.', + 'Morbi nulla diam, interdum et massa at, eleifend lobortis nibh.', + 'Nunc sollicitudin pharetra tincidunt.', + 'Pellentesque nulla diam, bibendum ac dictum a, facilisis gravida est.', + 'Fusce tempus turpis fringilla pellentesque pretium.', + 'Aenean ultricies sapien dolor, ullamcorper auctor libero interdum eu.', + 'Duis quis velit in urna laoreet imperdiet id ut sem.', + 'Phasellus fermentum odio at tempor scelerisque.', + 'Donec semper viverra ex, ut hendrerit ante tristique vel.', + 'Cras vel tempor massa.', + 'Sed lacinia viverra vestibulum.', + 'Suspendisse libero elit, porta at enim eu, iaculis consectetur lectus.', + 'Pellentesque aliquet lorem vehicula sapien sagittis, vel tristique augue venenatis.', + 'Nunc felis diam, iaculis vitae tortor at, rutrum efficitur orci.', + 'Pellentesque mi metus, luctus a tellus eget, eleifend elementum tortor.', + 'Praesent aliquet quam efficitur urna blandit lacinia.', + 'Pellentesque euismod sodales ultrices.', + 'Quisque non arcu ut arcu molestie dapibus.', + 'Aenean euismod lacus mi.', + 'Morbi sodales massa sed nisl luctus, eget posuere tortor vehicula.', + 'Etiam interdum convallis enim eu sagittis.', + 'Mauris sollicitudin nisi eget diam placerat, ac malesuada ligula vestibulum.', + 'Phasellus in vulputate elit.', + 'Phasellus porta consequat scelerisque.', + 'Ut tincidunt eget quam et faucibus.', + 'Integer mi elit, blandit at vehicula non, porta ut odio.', + 'Donec sollicitudin varius finibus.', + 'Nam a venenatis massa.', + 'Vivamus sit amet porta arcu.', + 'Maecenas dui nunc, venenatis ac sem ac, elementum molestie tellus.', + 'Aliquam scelerisque, velit ac venenatis vestibulum, nisi ante semper risus, in eleifend diam lorem ac ligula.', + 'Aliquam pulvinar dui porttitor magna sagittis volutpat.', + 'Sed posuere tortor a tellus tincidunt semper.', + 'Nulla rhoncus id nunc vitae condimentum.', + 'Donec efficitur faucibus ex eget varius.', + 'Cras fermentum vestibulum tellus eget iaculis.', + 'Vestibulum vestibulum nec purus eget semper.', + 'Sed commodo purus arcu, a consequat felis sollicitudin a.', + 'Suspendisse mollis lectus sed nulla dapibus gravida.', + 'Sed fermentum sem et nunc venenatis luctus.', + 'Phasellus dapibus est non magna iaculis, vel venenatis ex ornare.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec malesuada commodo nibh, id vulputate enim viverra at.', + 'Sed venenatis viverra mattis.', + 'Aliquam tincidunt dignissim sem, et sodales purus mollis id.', + 'Nam vitae pellentesque augue, a congue magna.', + 'Quisque vitae blandit nisi, sed vehicula magna.', + 'Aliquam id diam ac purus sagittis pharetra mattis eget ipsum.', + 'Praesent pulvinar gravida mi, a ornare velit cursus ac.', + 'Aliquam bibendum vulputate consequat.', + 'Nulla elit ante, ultrices quis eleifend eu, egestas quis ipsum.', + 'Aliquam non auctor nulla.', + 'Curabitur in condimentum ex.', + 'Mauris vestibulum ligula sit amet tortor porttitor iaculis.', + 'Ut sollicitudin sed nunc eu iaculis.', + 'Integer mattis egestas tellus, et volutpat ligula placerat non.', + 'Aliquam id sem interdum, scelerisque arcu in, tempus elit.', + 'Etiam tristique, mi et euismod dictum, leo augue posuere tellus, vitae malesuada libero dolor sed urna.', + 'Donec interdum dolor metus, ac euismod magna pulvinar in.', + 'Cras at nunc at nibh sollicitudin tristique.', + 'Nullam nec quam porta, rhoncus diam et, porta erat.', + 'Vestibulum ut vestibulum ante.', + 'Aliquam tincidunt blandit metus ac varius.', + 'Vivamus sollicitudin, quam a suscipit volutpat, leo eros commodo ex, sed sodales urna diam sed nulla.', + 'Sed a nibh ac felis efficitur luctus sit amet mollis leo.', + 'Vestibulum tempor urna quis erat accumsan hendrerit.', + 'Etiam euismod mauris non est iaculis dignissim.', + 'Nunc in dui ultrices, placerat tellus ut, sollicitudin magna.', + 'Aliquam efficitur nunc ac elit viverra laoreet.', + 'Pellentesque dui nisl, viverra vitae venenatis eu, ultricies vel risus.', + 'Integer volutpat quam non erat condimentum placerat.', + 'Maecenas molestie odio vel ultrices porta.', + 'Integer ullamcorper mollis elementum.', + 'Suspendisse mi sapien, mattis ut posuere vitae, vulputate a nisi.', + 'Nulla et ullamcorper odio.', + 'Mauris nec arcu massa.', + 'Aliquam quis eleifend ante.', + 'Nulla dignissim pulvinar hendrerit.', + 'Aenean lobortis tempus condimentum.', + 'Sed rhoncus metus quis mi ullamcorper tincidunt.', + 'Phasellus augue nisi, auctor quis posuere sed, mattis eu libero.', + 'Mauris pharetra ac libero at sodales.', + 'Cras efficitur enim ut tempor convallis.', + 'Donec lectus lorem, consectetur quis felis sed, vehicula suscipit massa.', + 'Vestibulum posuere viverra ultrices.', + 'Vivamus mollis cursus nibh sed fermentum.', + 'Vestibulum in varius ligula.', + 'Donec sit amet est scelerisque, sodales odio a, dictum ligula.', + 'Suspendisse consequat laoreet est, sit amet pulvinar elit sodales vitae.', + 'Nunc fermentum sodales eros, at vestibulum arcu vulputate ut.', + 'Integer faucibus aliquet eros.', + 'Suspendisse metus quam, placerat nec rutrum a, feugiat vel sapien.', + 'Donec malesuada, eros id blandit scelerisque, tellus libero ultricies leo, ac accumsan arcu metus eu nisl.', + 'Integer vitae arcu turpis.', + 'Sed eget congue orci, vel porta tellus.', + 'Integer ligula nisl, finibus eu sollicitudin ac, malesuada vitae nisi.', + 'Donec sit amet vulputate metus.', + 'Phasellus enim sem, varius ac vulputate ut, dapibus id tellus.', + 'Nam non malesuada metus.', + 'Nulla scelerisque magna ut est imperdiet, ac luctus sem sodales.', + 'In auctor neque enim, eu hendrerit eros fringilla nec.', + 'Duis quis purus rhoncus, malesuada enim vitae, bibendum nisl.', + 'Donec ut libero lacinia, tempus enim sed, volutpat metus.', + 'In commodo posuere nisi vitae faucibus.', + 'Maecenas felis odio, vehicula ac ullamcorper non, maximus id elit.', + 'Curabitur congue urna in mi venenatis euismod.', + 'Suspendisse hendrerit lacus ac risus tempor, non tristique urna venenatis.', + 'Suspendisse cursus urna ornare, varius risus sit amet, lobortis eros.', + 'Fusce consequat porttitor tortor in dignissim.', + 'Ut nulla magna, semper posuere ex quis, pharetra tempor quam.', + 'Morbi enim ligula, tincidunt id ligula ac, imperdiet pretium arcu.', + 'Maecenas quis risus malesuada nisl efficitur pretium.', + 'Integer at ante congue, luctus neque sed, dictum sem.', + 'Phasellus luctus diam nec risus porttitor posuere.', + 'Vestibulum ultrices tristique ex.', + 'Nulla id lacus erat.', + 'Vestibulum eu orci turpis.', + 'Ut feugiat auctor interdum.', + 'Donec at convallis dui.', + 'Phasellus placerat vitae dui eu tincidunt.', + 'Vestibulum metus lacus, fermentum id dignissim a, sagittis a nulla.', + 'In fermentum turpis in dui dignissim iaculis.', + 'Suspendisse vehicula ex vel imperdiet vestibulum.', + 'Suspendisse lobortis felis non augue lacinia ornare.', + 'Cras porta neque tellus, sed aliquet purus vulputate tincidunt.', + 'Nullam non purus tellus.', + 'Vivamus ex diam, condimentum ut ornare sit amet, venenatis pharetra turpis.', + 'Aliquam dui tortor, volutpat ut molestie eu, efficitur id nibh.', + 'Morbi vel ante et tellus rhoncus mattis id at sem.', + 'In vel tellus sapien.', + 'Aenean nec est finibus, iaculis orci a, molestie turpis.', + 'Proin ornare eget odio luctus sodales.', + 'Etiam hendrerit a nisl at pellentesque.', + 'Nunc blandit blandit mauris, eget blandit nisi luctus eget.', + 'Ut justo justo, imperdiet nec magna maximus, venenatis vestibulum leo.', + 'Cras a consequat quam.', + 'Vestibulum ac lectus ullamcorper, efficitur lacus quis, pulvinar est.', + 'Aenean nec odio elit.', + 'Nulla quis viverra odio, nec cursus erat.', + 'Vestibulum lobortis est nec sem dignissim, id luctus tortor congue.', + 'Morbi sollicitudin massa et justo aliquam volutpat.', + 'Aliquam bibendum tristique lacus sit amet mattis.', + 'Sed hendrerit lorem feugiat est feugiat ultricies.', + 'Cras dictum, turpis id imperdiet volutpat, nisl orci facilisis mi, in tincidunt arcu diam et dui.', + 'Mauris congue neque libero, vitae sagittis elit consectetur in.', + 'Cras commodo at sem et fermentum.', + 'Nullam consequat ligula in est pellentesque malesuada.', + 'In sit amet elit ac erat varius posuere scelerisque in lectus.', + 'Nunc ac odio vitae orci placerat mollis at in velit.', + 'Vivamus interdum nunc quis velit viverra consectetur.', + 'Nam sit amet semper arcu.', + 'Donec pellentesque feugiat lorem nec elementum.', + 'Quisque tincidunt maximus vehicula.', + 'Curabitur fermentum, ligula in sollicitudin tempus, odio libero euismod augue, vulputate pellentesque lorem nisi vehicula nulla.', + 'Aenean quis mauris et neque venenatis laoreet.', + 'Fusce id porta augue.', + 'Integer ac nunc vel enim ultrices consequat.', + 'Mauris magna purus, congue ut sapien in, molestie luctus nulla.', + 'Donec consequat, augue in tristique scelerisque, nisi sem tincidunt lorem, varius tempus est nunc in ipsum.', + 'Duis dictum ut est ac viverra.', + 'Aliquam id tincidunt ligula.', + 'Aliquam vitae tortor ut massa eleifend imperdiet sed et ipsum.', + 'Maecenas aliquet tellus ac nisl molestie, vel ullamcorper lacus vulputate.', + 'Mauris nec lacus sapien.', + 'Integer sagittis dolor sit amet velit mollis, quis sodales odio sollicitudin.', + 'Vivamus varius, libero a cursus imperdiet, lorem diam vestibulum risus, eget dictum lectus dolor eget eros.', + 'Nullam vitae orci varius, suscipit magna vitae, efficitur tellus.', + 'Praesent sagittis mi nec rutrum tempus.', + 'Aenean eu eros in erat gravida consectetur.', + 'Nulla lacinia vitae urna commodo ultricies.', + 'In interdum fermentum malesuada.', + 'Nullam placerat vel velit vel blandit.', + 'Praesent blandit tortor nec nisl viverra rutrum.', + 'Fusce ac euismod dui.', + 'Curabitur auctor quam dui, quis tristique ligula ornare et.', + 'Vivamus tellus diam, fringilla a congue quis, porta sit amet diam.', + 'Proin consectetur pulvinar malesuada.', + 'Duis tempor maximus libero non fringilla.', + 'Maecenas et elit leo.', + 'Fusce porttitor ex tortor, iaculis mollis sapien scelerisque eu.', + 'Etiam in dignissim tellus, nec egestas mauris.', + 'Aenean lacinia nec sapien quis suscipit.', + 'Ut id libero nec ligula laoreet rutrum.', + 'In id hendrerit nisl, sed luctus tortor.', + 'Morbi interdum augue justo, tincidunt suscipit sem lacinia vel.', + 'Aliquam a massa tortor.', + 'Sed eget libero id est pharetra laoreet.', + 'Morbi molestie, ex eu aliquet maximus, ante felis efficitur ligula, ac commodo justo augue quis velit.', + 'Integer lorem nulla, rhoncus a magna placerat, semper faucibus quam.', + 'Curabitur imperdiet aliquet diam nec scelerisque.', + 'Sed sed pellentesque risus.', + 'Sed tortor odio, vestibulum et augue a, maximus congue turpis.', + 'Donec pulvinar mi a enim rutrum, eu blandit neque molestie.', + 'Nullam tristique pulvinar sapien, ut consectetur velit mollis eu.', + 'Suspendisse vestibulum nisi leo, et ornare mi congue id.', + 'Integer urna nulla, molestie vitae arcu in, finibus aliquet felis.', + 'Maecenas laoreet venenatis felis, eget finibus urna pharetra sed.', + 'Pellentesque in turpis a nulla rutrum egestas vel in augue.', + 'Curabitur a lectus ac nulla porta vehicula.', + 'Cras quis euismod massa.', + 'Sed consequat arcu vitae gravida pellentesque.', + 'Donec rhoncus rhoncus imperdiet.', + 'Praesent pulvinar risus sed orci dignissim, sed tincidunt leo viverra.', + 'Aenean euismod maximus posuere.', + 'Quisque odio dolor, suscipit ut semper sed, molestie vel nulla.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Quisque auctor, leo at vulputate tempus, est nisi imperdiet arcu, nec dignissim nunc mauris eget enim.', + 'Aliquam at posuere mauris, ac dignissim nibh.', + 'Donec lacinia lobortis tempus.', + 'Sed blandit varius enim et sodales.', + 'Morbi pretium vulputate ipsum et congue.', + 'Quisque scelerisque justo eget ullamcorper vestibulum.', + 'Cras quis erat ut turpis dictum aliquam rutrum vel ligula.', + 'Sed ipsum elit, congue quis mi sit amet, semper porttitor magna.', + 'Nulla vel tellus condimentum, accumsan ex ac, gravida mauris.', + 'Donec cursus, nisi in vestibulum suscipit, magna tellus interdum tortor, a tincidunt mi turpis vitae libero.', + 'Etiam consectetur, odio ut iaculis convallis, ex nisl rhoncus enim, vitae placerat sem dui eu elit.', + 'Curabitur libero tellus, posuere nec fringilla sed, lobortis nec quam.', + 'Curabitur a augue ligula.', + 'Mauris pharetra eu ante non porta.', + 'Cras efficitur velit sem.', + 'Proin at dapibus arcu.', + 'Integer nec purus vitae lorem aliquam placerat.', + 'Integer sem risus, ultricies sit amet magna eget, viverra vehicula augue.', + 'Morbi blandit ligula vitae interdum euismod.', + 'Vestibulum egestas eleifend pulvinar.', + 'Ut euismod ex rutrum, viverra augue non, molestie libero.', + 'Proin fringilla, urna eu condimentum pharetra, dolor quam sollicitudin mi, vitae consequat sapien purus id magna.', + 'Phasellus pulvinar vel massa eu ullamcorper.', + 'Etiam nunc leo, vestibulum a tortor quis, laoreet gravida odio.', + 'Nullam tristique consequat lacus nec aliquam.', + 'Pellentesque aliquet augue facilisis felis pretium faucibus.', + 'Integer vitae ultrices diam, id lobortis ipsum.', + 'In at augue nibh.', + 'In non gravida ante.', + 'Aenean euismod eros augue.', + 'Nunc ac metus eget mauris bibendum cursus.', + 'Etiam et massa eu lacus molestie dignissim.', + 'Proin dictum ante non urna sollicitudin eleifend.', + 'Mauris convallis ultricies neque sit amet semper.', + 'Morbi venenatis euismod quam sed gravida.', + 'Nulla elementum orci at justo scelerisque, vel dapibus eros scelerisque.', + 'Integer accumsan augue posuere, suscipit odio vitae, tincidunt nisi.', + 'Quisque in orci malesuada, lobortis neque sit amet, pretium odio.', + 'Integer tempus eget sapien non sodales.', + 'Nunc ut dapibus justo.', + 'Quisque id nulla elit.', + 'Nam quis justo eget velit convallis facilisis.', + 'Quisque iaculis ex lectus, sit amet dictum neque pellentesque volutpat.', + 'Aenean quis tellus lacinia, gravida elit non, interdum quam.', + 'Donec interdum orci ut mauris molestie lacinia.', + 'Donec risus elit, mattis et viverra placerat, viverra et turpis.', + 'Morbi in sodales urna.', + 'Nam lorem ligula, tempus vitae sapien eget, vulputate fermentum purus.', + 'Aenean vulputate, nulla id euismod aliquet, leo ligula ornare tortor, sed tincidunt ante metus non felis.', + 'Cras volutpat, dolor consectetur luctus volutpat, mauris eros laoreet augue, at vehicula purus enim in tortor.', + 'Cras mi est, tincidunt in sapien nec, tempor cursus purus.', + 'Phasellus rutrum nibh a sagittis feugiat.', + 'Aenean sit amet tincidunt enim, at tincidunt justo.', + 'Pellentesque maximus nisi vitae nibh porttitor gravida.', + 'Aliquam ac sem mollis, pulvinar ligula id, rhoncus turpis.', + 'Ut placerat turpis ac finibus fringilla.', + 'Sed sit amet est eu tortor efficitur dignissim.', + 'Mauris iaculis, dolor et lobortis congue, augue massa scelerisque libero, in lobortis augue dolor et libero.', + 'Mauris pharetra finibus turpis, non maximus quam pellentesque sit amet.', + 'Praesent feugiat, ex eu aliquam tempor, sem nibh tempus est, eget tincidunt velit quam eget est.', + 'Donec imperdiet enim tellus, vel tincidunt felis accumsan rutrum.', + 'Ut ac sem sit amet sem posuere luctus at in enim.', + 'Nulla euismod, libero vel finibus lobortis, nulla libero porttitor tellus, a interdum odio quam nec nunc.', + 'Phasellus quis efficitur risus, ullamcorper condimentum nisl.', + 'Aliquam id neque a nunc vehicula euismod.', + 'In nec ultrices eros.', + 'Nunc sit amet purus neque.', + 'Pellentesque pharetra nisl augue, sed sollicitudin eros faucibus eget.', + 'Morbi sit amet lorem eget enim cursus vehicula.', + 'Etiam euismod ante in venenatis bibendum.', + 'Curabitur eu efficitur tortor.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla interdum nibh in vehicula tincidunt.', + 'Sed fringilla, magna non malesuada dignissim, quam enim mollis tellus, non faucibus purus tellus a ipsum.', + 'Ut placerat varius diam in vulputate.', + 'Mauris aliquet lectus id lacus iaculis, nec viverra ante porttitor.', + 'Maecenas finibus posuere risus.', + 'Suspendisse sit amet lectus quis nunc tincidunt bibendum eget in felis.', + 'In mattis dolor purus, id tempus nibh rutrum ut.', + 'Phasellus ornare diam ac elit laoreet, ac egestas ante maximus.', + 'In et lacus leo.', + 'Nam volutpat id nulla non dictum.', + 'Nunc blandit eu libero at consequat.', + 'In pretium lacus ac leo malesuada condimentum.', + 'Maecenas congue dictum ultricies.', + 'Sed id tincidunt ex.', + 'Praesent gravida lectus id ante facilisis, nec pharetra justo rutrum.', + 'Praesent cursus lobortis accumsan.', + 'Aenean sed lacus ac arcu blandit placerat.', + 'Quisque vitae ligula vitae elit congue dictum.', + 'Nulla condimentum fermentum nulla ac porta.', + 'Cras ornare diam vitae augue maximus, quis faucibus dui fermentum.', + 'Maecenas porttitor porttitor felis, sit amet facilisis diam sodales vitae.', + 'Aliquam dictum arcu tortor, et fringilla leo euismod vel.', + 'Phasellus diam mauris, feugiat aliquet fermentum in, porttitor et tortor.', + 'Maecenas ex justo, sagittis sed magna sed, efficitur venenatis felis.', + 'In placerat et nunc et malesuada.', + 'Aenean vehicula neque odio, vitae molestie mauris aliquet quis.', + 'Vestibulum gravida dolor vel velit semper rhoncus.', + 'Ut egestas sodales nulla quis rutrum.', + 'Integer quis nisi nec enim vestibulum convallis.', + 'Fusce eget nisi rutrum justo porttitor gravida nec nec ipsum.', + 'Nam blandit nec leo ut porttitor.', + 'Suspendisse a nunc sed ante fringilla fermentum consectetur vitae orci.', + 'Nunc bibendum arcu erat, eu ullamcorper est placerat ac.', + 'Sed facilisis, enim a tempor ullamcorper, metus nunc interdum lacus, id pellentesque mauris magna ut augue.', + 'Curabitur eu dignissim velit.', + 'Sed ut quam erat.', + 'Sed faucibus sapien felis, ac malesuada nunc cursus et.', + 'Sed vestibulum lacus nec sapien ultrices, at euismod tellus dignissim.', + 'Integer sagittis vulputate lectus, sed scelerisque tortor pulvinar id.', + 'Integer finibus venenatis massa, eget fringilla arcu placerat et.', + 'Proin blandit neque a quam blandit mollis.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse potenti.', + 'Ut nec risus nisl.', + 'Vestibulum rhoncus pellentesque augue fringilla molestie.', + 'Praesent sodales eget sapien eu tristique.', + 'In nec purus leo.', + 'Vivamus vitae sem sed massa bibendum tempor eu id lectus.', + 'Ut id pulvinar nunc.', + 'Nam tempus dignissim lectus, ac pellentesque neque porttitor non.', + 'Suspendisse lobortis rhoncus dui, ac ullamcorper dolor dignissim sed.', + 'Vestibulum sollicitudin faucibus nisl a laoreet.', + 'Aenean consequat purus et lorem suscipit, sed efficitur magna facilisis.', + 'Mauris fermentum malesuada tortor et tempus.', + 'Maecenas interdum rutrum pretium.', + 'Morbi non neque eget lorem suscipit congue id eget quam.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse malesuada purus nibh, volutpat facilisis lacus iaculis a.', + 'Aenean eu pharetra ligula.', + 'Nulla nec leo porta, sollicitudin nunc et, lacinia quam.', + 'Nunc placerat tristique pellentesque.', + 'Ut enim nisi, condimentum quis felis ut, vestibulum cursus mi.', + 'Vestibulum ut ipsum eros.', + 'Proin vehicula bibendum enim, vitae laoreet ante auctor vitae.', + 'Donec imperdiet vestibulum congue.', + 'Sed velit mi, dictum in commodo at, semper a neque.', + 'Aliquam lectus turpis, vulputate at nunc et, laoreet porttitor turpis.', + 'Nullam eu mauris eget augue tincidunt ornare.', + 'Pellentesque sit amet leo eu nibh placerat sagittis.', + 'Curabitur et finibus odio.', + 'Fusce tristique non tellus sed egestas.', + 'Donec metus nunc, consequat non lorem sit amet, vehicula venenatis nisl.', + 'Aenean sodales molestie posuere.', + 'Mauris ut sollicitudin orci.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nunc sit amet condimentum mauris, eu fermentum risus.', + 'Cras quis ante felis.', + 'Pellentesque id interdum neque.', + 'Phasellus erat tellus, tempus quis pulvinar volutpat, efficitur in odio.', + 'Maecenas a venenatis ex, at tempor libero.', + 'Pellentesque suscipit ipsum eget tincidunt faucibus.', + 'Aenean sollicitudin est odio, vitae vulputate ligula dapibus sit amet.', + 'Nam finibus arcu at dui blandit ornare.', + 'Integer id dapibus est, ut fringilla lorem.', + 'Aenean interdum quis dui nec pharetra.', + 'Maecenas non diam non elit fringilla tempor id sollicitudin purus.', + 'Nullam odio metus, aliquam eu dolor non, rutrum sodales mauris.', + 'Maecenas nibh sem, faucibus at turpis vitae, tristique vestibulum eros.', + 'Duis ac dolor eget augue luctus dignissim.', + 'Fusce eget libero hendrerit, placerat purus id, volutpat tellus.', + 'Fusce viverra, arcu ut molestie ultricies, dui tortor lacinia risus, eu auctor elit mauris eu orci.', + 'Praesent semper mi eu mi dignissim, imperdiet dictum urna tincidunt.', + 'Nulla in lorem id sapien rhoncus ultrices.', + 'Quisque imperdiet, tortor ac viverra blandit, massa sapien auctor tortor, at fermentum ex tortor sit amet sem.', + 'Fusce nisl libero, sollicitudin vel feugiat iaculis, consectetur ac diam.', + 'Aliquam velit arcu, faucibus id ornare a, pharetra et leo.', + 'Nullam eu fringilla felis.', + 'Donec dignissim risus facilisis bibendum tincidunt.', + 'Donec sed orci nunc.', + 'Fusce at metus lobortis, iaculis ante laoreet, aliquam nisi.', + 'Integer imperdiet ornare turpis, sed viverra felis mattis non.', + 'Nulla tincidunt purus sed fermentum volutpat.', + 'Phasellus eu dignissim massa, non consectetur lorem.', + 'Praesent venenatis, nulla nec ornare vulputate, velit ipsum lobortis nisl, sed consequat nibh turpis vel diam.', + 'Pellentesque pharetra odio lobortis, congue enim eu, sagittis velit.', + 'Mauris sed molestie tortor.', + 'Suspendisse consectetur nunc vel dolor aliquet, vel venenatis eros laoreet.', + 'Nullam malesuada nulla libero, dapibus pretium mi iaculis a.', + 'Donec placerat nibh leo, id tristique enim tincidunt sed.', + 'Nunc elementum, arcu nec ultrices convallis, urna turpis finibus velit, eu euismod nibh orci ac eros.', + 'Proin cursus pellentesque turpis, vel tempor lorem feugiat et.', + 'Duis finibus aliquet lacus, at accumsan tortor posuere nec.', + 'Aliquam id sem justo.', + 'Suspendisse eget dignissim eros.', + 'Suspendisse feugiat scelerisque ante id fermentum.', + 'Quisque pellentesque libero et sem pellentesque ultrices.', + 'Nunc dignissim magna interdum, feugiat odio sit amet, pharetra lacus.', + 'Duis in sapien aliquam, volutpat est sit amet, semper risus.', + 'Proin blandit enim at fermentum mattis.', + 'Proin pharetra, orci a semper porttitor, purus felis placerat lorem, nec mollis orci tellus sit amet elit.', + 'Duis sed convallis turpis, a pellentesque nibh.', + 'Proin et est vel nisl dictum aliquam et et sem.', + 'Donec sed augue laoreet, suscipit sem quis, consectetur est.', + 'Sed hendrerit arcu quis porttitor vestibulum.', + 'Pellentesque interdum lorem urna, et vestibulum enim pharetra et.', + 'Cras sed neque sit amet erat aliquam semper.', + 'Fusce sit amet eros lacus.', + 'Cras commodo, nibh et sodales vehicula, eros magna pellentesque orci, et laoreet lacus dolor nec enim.', + 'Donec et quam ultrices, porta justo tempor, auctor odio.', + 'Morbi eget iaculis nisi, ut finibus orci.', + 'Sed tellus lectus, consequat nec dapibus ac, interdum vitae lectus.', + 'Praesent accumsan vehicula lacus ut efficitur.', + 'Integer sit amet nisl non odio tincidunt sodales eu ut mauris.', + 'Duis euismod risus quis iaculis sodales.', + 'Pellentesque eleifend vel lorem sed iaculis.', + 'Duis a mollis ex.', + 'Nunc ullamcorper id felis non aliquam.', + 'Etiam ut posuere lacus.', + 'Duis quis elementum ligula.', + 'Aenean pulvinar elit a eleifend luctus.', + 'Vivamus accumsan tincidunt dui in pellentesque.', + 'Cras vulputate metus at suscipit vestibulum.', + 'Phasellus ultrices consequat lectus, ac tristique nunc mattis sit amet.', + 'Donec arcu diam, mollis ut euismod sit amet, tincidunt vel ipsum.', + 'Maecenas aliquet orci ac rutrum laoreet.', + 'Quisque maximus nisl sed sapien posuere pulvinar.', + 'Sed interdum, ante et laoreet iaculis, arcu ligula pretium mi, eget bibendum lorem urna sit amet odio.', + 'Praesent consequat nisl quis tellus mollis eleifend.', + 'Suspendisse facilisis sem vitae sapien rhoncus, ac dignissim nunc pharetra.', + 'Quisque id lacus ut neque vehicula pellentesque.', + 'Quisque scelerisque, risus sit amet condimentum consectetur, quam erat pretium tellus, ut tempor metus lectus suscipit risus.', + 'Vestibulum eu lectus eget nunc aliquet laoreet.', + 'Phasellus ornare neque auctor pulvinar pellentesque.', + 'Aliquam vitae dignissim mi, ac mattis nibh.', + 'Duis vitae porta velit, ac efficitur mauris.', + 'Sed id nisi nisl.', + 'Donec malesuada odio in posuere eleifend.', + 'Cras ut mi quis tortor mollis iaculis sed a dolor.', + 'Nunc a nisi vitae orci consectetur semper.', + 'Mauris tristique pharetra mattis.', + 'Sed iaculis fermentum mauris a tempus.', + 'Quisque cursus, mauris vel tristique molestie, massa libero suscipit orci, ut sodales lacus massa vel odio.', + 'Sed eu mi sapien.', + 'Sed tincidunt ullamcorper mauris nec lobortis.', + 'Suspendisse at est in diam elementum commodo.', + 'Ut felis lectus, hendrerit sit amet vulputate sit amet, cursus sit amet quam.', + 'Quisque porta arcu ac purus scelerisque, ac aliquam mi ornare.', + 'Sed ultricies vitae purus et convallis.', + 'Nunc ligula nisl, malesuada ut scelerisque ac, maximus quis odio.', + 'Duis nisi arcu, commodo ac purus ac, dignissim convallis arcu.', + 'Suspendisse eget scelerisque libero.', + 'Morbi dolor purus, vehicula id sem sed, condimentum viverra eros.', + 'Etiam bibendum commodo enim, ac vulputate ex consequat aliquet.', + 'Pellentesque porta nisl sit amet tortor dignissim, quis aliquet arcu consectetur.', + 'Integer et pretium lectus.', + 'Fusce efficitur posuere ipsum, ut convallis nisl sollicitudin ultrices.', + 'Sed suscipit elementum est, vitae laoreet tellus dignissim ultricies.', + 'Praesent viverra nisl ut odio posuere, tristique finibus nibh rhoncus.', + 'Aliquam consequat ornare orci ac ultrices.', + 'Vivamus vel lacinia velit.', + 'Vestibulum sit amet sapien sit amet velit tincidunt suscipit.', + 'Etiam ornare molestie aliquet.', + 'Sed gravida enim quis nunc interdum imperdiet.', + 'Proin cursus odio ac dolor blandit, quis sollicitudin ante rutrum.', +]; diff --git a/drizzle-seed/src/datasets/phonesInfo.ts b/drizzle-seed/src/datasets/phonesInfo.ts new file mode 100644 index 000000000..fc1f26750 --- /dev/null +++ b/drizzle-seed/src/datasets/phonesInfo.ts @@ -0,0 +1,871 @@ +// ["country prefix, operator prefix, number length including operator prefix and excluding country prefix", ] +export default [ + '93,70,9', + '93,71,9', + '93,72,9', + '93,73,9', + '93,74,9', + '93,75,9', + '93,76,9', + '93,77,9', + '93,78,9', + '93,79,9', + '355,66,9', + '355,67,9', + '355,68,9', + '355,69,9', + '213,5,9', + '213,6,9', + '213,7,9', + '1,684,10', + '1,264 772,10', + '1,268 7,10', + '374,55,6', + '374,95,6', + '374,41,6', + '374,44,6', + '374,77,6', + '374,93,6', + '374,94,6', + '374,98,6', + '374,91,6', + '374,99,6', + '374,43,6', + '374,97,6', + '61,4,9', + '672,1,9', + '43,650,10', + '43,660,10', + '43,664,10', + '43,676,10', + '43,680,10', + '43,677,11', + '43,681,11', + '43,688,11', + '43,699,11', + '994,41,9', + '994,50,9', + '994,51,9', + '994,55,9', + '994,70,9', + '994,77,9', + '994,99,9', + '1,242 35,10', + '1,242 45,10', + '1,242 55,10', + '973,31,8', + '973,322,8', + '973,33,8', + '973,340,8', + '973,341,8', + '973,343,8', + '973,344,8', + '973,345,8', + '973,353,8', + '973,355,8', + '973,36,8', + '973,377,8', + '973,383,8', + '973,384,8', + '973,388,8', + '973,39,8', + '973,663,8', + '973,666,8', + '973,669,8', + '880,13,10', + '880,14,10', + '880,15,10', + '880,16,10', + '880,17,10', + '880,18,10', + '880,19,10', + '1,246,10', + '375,25,9', + '375,29 1,9', + '375,29 2,9', + '375,29 3,9', + '375,29 4,9', + '375,29 5,9', + '375,29 6,9', + '375,29 7,9', + '375,29 8,9', + '375,29 9,9', + '375,33,9', + '375,44,9', + '32,456,9', + '32,47,9', + '32,48,9', + '32,49,9', + '501,6,7', + '1,441,10', + '387,60,8', + '387,69,8', + '387,62,8', + '387,63,8', + '387,64,8', + '387,65,8', + '387,66,8', + '246,387,7', + '1,284,10', + '359,87,9', + '359,88,9', + '359,89,9', + '359,988,9', + '226,70,8', + '226,71,8', + '226,72,8', + '226,74,8', + '226,75,8', + '226,77,8', + '226,78,8', + '226,79,8', + '855,92,9', + '855,12,9', + '855,11,9', + '855,77,9', + '855,99,9', + '1,345,10', + '235,66,8', + '235,63,8', + '235,65,8', + '235,99,8', + '235,95,8', + '235,93,8', + '235,90,8', + '235,77,8', + '56,9,9', + '86,13,11', + '86,15,11', + '86,18,11', + '86,19,11', + '57,30,10', + '57,310,10', + '57,311,10', + '57,312,10', + '57,313,10', + '57,314,10', + '57,315,10', + '57,316,10', + '57,317,10', + '57,318,10', + '57,319,10', + '57,32,10', + '682,5,5', + '682,7,5', + '506,6,8', + '506,7,8', + '506,8,8', + '385,91,9', + '385,92,9', + '385,95,9', + '385,97,9', + '385,98,9', + '385,99,9', + '357,94,8', + '357,95,8', + '357,96,8', + '357,97,8', + '357,99,8', + '420,601,9', + '420,602,9', + '420,603,9', + '420,604,9', + '420,605,9', + '420,606,9', + '420,607,9', + '420,608,9', + '420,702,9', + '420,72,9', + '420,73,9', + '420,77,9', + '420,790,9', + '45,2,8', + '45,30,8', + '45,31,8', + '45,40,8', + '45,41,8', + '45,42,8', + '45,50,8', + '45,51,8', + '45,52,8', + '45,53,8', + '45,60,8', + '45,61,8', + '45,71,8', + '45,81,8', + '1,767 2,10', + '1,809,10', + '1,829,10', + '1,849,10', + '670,77,8', + '670,78,8', + '593,9,9', + '20,10,10', + '20,11,10', + '20,12,10', + '503,6,8', + '503,7,8', + '268,7,8', + '500,5,5', + '500,6,5', + '298,21,5', + '298,22,5', + '298,23,5', + '298,24,5', + '298,25,5', + '298,26,5', + '298,27,5', + '298,28,5', + '298,29,5', + '298,5,5', + '298,71,5', + '298,72,5', + '298,73,5', + '298,74,5', + '298,75,5', + '298,76,5', + '298,77,5', + '298,78,5', + '298,79,5', + '298,91,5', + '298,92,5', + '298,93,5', + '298,94,5', + '298,95,5', + '298,96,5', + '298,97,5', + '298,98,5', + '298,99,5', + '691,92,7', + '691,93,7', + '691,95,7', + '691,97,7', + '358,457,10', + '33,6,9', + '33,700,9', + '33,73,9', + '33,74,9', + '33,75,9', + '33,76,9', + '33,77,9', + '33,78,9', + '594,694,9', + '241,2,7', + '241,3,7', + '241,4,7', + '241,5,7', + '241,6,7', + '241,7,7', + '995,544,9', + '995,514,9', + '995,551,9', + '995,555,9', + '995,557,9', + '995,558,9', + '995,568,9', + '995,570,9', + '995,571,9', + '995,574,9', + '995,577,9', + '995,578,9', + '995,579,9', + '995,591,9', + '995,592,9', + '995,593,9', + '995,595,9', + '995,596,9', + '995,597,9', + '995,598,9', + '995,599,9', + '49,151,10', + '49,152,10', + '49,155,10', + '49,157,10', + '49,159,10', + '49,162,10', + '49,163,10', + '49,170,10', + '49,171,10', + '49,172,10', + '49,173,10', + '49,174,10', + '49,175,10', + '49,176,10', + '49,177,10', + '49,178,10', + '49,179,10', + '233,20,9', + '233,50,9', + '233,23,9', + '233,24,9', + '233,54,9', + '233,55,9', + '233,59,9', + '233,26,9', + '233,56,9', + '233,27,9', + '233,57,9', + '233,28,9', + '30,690,10', + '30,693,10', + '30,694,10', + '30,695,10', + '30,697,10', + '30,698,10', + '30,699,10', + '1,473 41,10', + '1,671,10', + '502,231,8', + '502,2324,8', + '502,2326,8', + '502,2327,8', + '502,2328,8', + '502,2329,8', + '502,2428,8', + '502,2429,8', + '502,30,8', + '502,310,8', + '502,311,8', + '502,448,8', + '502,449,8', + '502,45,8', + '502,46,8', + '502,478,8', + '502,479,8', + '502,480,8', + '502,481,8', + '502,49,8', + '502,5,8', + '1,808,10', + '504,3,8', + '504,7,8', + '504,8,8', + '504,9,8', + '36,20,9', + '36,30,9', + '36,31,9', + '36,38,9', + '36,50,9', + '36,60,9', + '36,70,9', + '91,7,10', + '91,8,10', + '91,90,10', + '91,91,10', + '91,92,10', + '91,93,10', + '91,94,10', + '91,95,10', + '91,96,10', + '91,97,10', + '91,98,10', + '91,99,10', + '62,811,9', + '62,813,11', + '62,814,11', + '62,815,10', + '62,818,9', + '62,819,10', + '62,838,10', + '62,852,11', + '62,853,11', + '62,855,10', + '62,858,11', + '62,859,11', + '62,878,11', + '62,896,10', + '62,897,10', + '62,898,10', + '62,899,10', + '98,91,10', + '98,990,10', + '353,8,9', + '353,83,9', + '353,85,9', + '353,86,9', + '353,87,9', + '353,89,9', + '972,50,9', + '972,52,9', + '972,53,9', + '972,54,9', + '972,556,9', + '972,558,9', + '972,559,9', + '972,58,9', + '39,310,10', + '39,31100,10', + '39,31101,10', + '39,31105,10', + '39,313,10', + '39,319,10', + '39,320,10', + '39,324,10', + '39,327,10', + '39,328,10', + '39,329,10', + '39,331,10', + '39,333,10', + '39,334,10', + '39,338,10', + '39,339,10', + '39,340,10', + '39,342,10', + '39,344,10', + '39,345,10', + '39,346,10', + '39,347,10', + '39,348,10', + '39,349,10', + '39,3505,10', + '39,3510,10', + '39,3512,10', + '39,366,10', + '39,370,10', + '39,3710,10', + '39,3711,10', + '39,373,10', + '39,377,10', + '39,380,10', + '39,385,10', + '39,388,10', + '39,389,10', + '39,391,10', + '39,392,10', + '39,393,10', + '1,876,10', + '81,060,11', + '81,070,11', + '81,080,11', + '81,090,11', + '7,700,10', + '7,708,10', + '7,701,10', + '7,702,10', + '7,775,10', + '7,778,10', + '7,705,10', + '7,771,10', + '7,776,10', + '7,777,10', + '7,707,10', + '7,747,10', + '254,10,10', + '254,11,10', + '254,70,10', + '254,71,10', + '254,72,10', + '254,73,10', + '254,74,10', + '254,75,10', + '254,763,10', + '254,77,10', + '254,78,10', + '686,63,8', + '686,7,8', + '383,44,8', + '383,45,8', + '383,49,8', + '965,5,8', + '965,6,8', + '965,9,8', + '371,2,8', + '231,46,7', + '231,47,7', + '231,5,7', + '231,64,7', + '231,65,7', + '231,7,8', + '218,91,10', + '218,92,10', + '218,94,10', + '370,6,8', + '352,621,9', + '352,628,9', + '352,661,9', + '352,668,9', + '352,691,9', + '352,698,9', + '60,11,7', + '60,12,7', + '60,13,7', + '60,14,7', + '60,16,7', + '60,17,7', + '60,18,7', + '60,19,7', + '960,7,7', + '960,9,7', + '223,6,8', + '223,7,8', + '596,696,9', + '230,57,8', + '230,58,8', + '230,59,8', + '230,54,8', + '52,1,10', + '373,60,8', + '373,65,8', + '373,67,8', + '373,68,8', + '373,69,8', + '373,78,8', + '373,79,8', + '976,70,8', + '976,88,8', + '976,89,8', + '976,91,8', + '976,93,8', + '976,94,8', + '976,95,8', + '976,96,8', + '976,98,8', + '976,99,8', + '382,60,8', + '382,63,8', + '382,66,8', + '382,67,8', + '382,68,8', + '382,69,8', + '1,664,10', + '95,92,8', + '95,925,10', + '95,926,10', + '95,943,9', + '95,94,10', + '95,944,9', + '95,95,8', + '95,96,8', + '95,973,9', + '95,991,9', + '95,93,9', + '95,996,10', + '95,997,10', + '95,977,10', + '95,978,10', + '95,979,10', + '977,98,10', + '31,6,9', + '687,7,6', + '687,8,6', + '687,9,6', + '64,22,9', + '64,27,9', + '505,8,8', + '227,9,8', + '234,804,8', + '234,805,8', + '234,803,8', + '234,802,8', + '234,809,8', + '683,1,4', + '683,3,4', + '683,4,4', + '672,38,6', + '389,70,8', + '389,71,8', + '389,72,8', + '389,74,8', + '389,75,8', + '389,76,8', + '389,77,8', + '389,78,8', + '389,79,8', + '90,533,7', + '1,670,10', + '47,4,8', + '47,59,8', + '47,9,8', + '968,91,8', + '92,30,10', + '92,31,10', + '92,32,10', + '92,33,10', + '92,34,10', + '507,6,8', + '595,9,9', + '51,9,9', + '63,973,10', + '63,974,10', + '63,905,10', + '63,906,10', + '63,977,10', + '63,915,10', + '63,916,10', + '63,926,10', + '63,927,10', + '63,935,10', + '63,936,10', + '63,937,10', + '63,996,10', + '63,997,10', + '63,917,10', + '63,979,10', + '63,920,10', + '63,930,10', + '63,938,10', + '63,939,10', + '63,907,10', + '63,908,10', + '63,909,10', + '63,910,10', + '63,912,10', + '63,919,10', + '63,921,10', + '63,928,10', + '63,929,10', + '63,947,10', + '63,948,10', + '63,949,10', + '63,989,10', + '63,918,10', + '63,999,10', + '63,922,10', + '63,923,10', + '63,932,10', + '63,933,10', + '63,942,10', + '63,943,10', + '48,50,9', + '48,45,9', + '48,51,9', + '48,53,9', + '48,57,9', + '48,60,9', + '48,66,9', + '48,69,9', + '48,72,9', + '48,73,9', + '48,78,9', + '48,79,9', + '48,88,9', + '351,91,9', + '351,921,9', + '351,922,9', + '351,924,9', + '351,925,9', + '351,926,9', + '351,927,9', + '351,9290,9', + '351,9291,9', + '351,9292,9', + '351,9293,9', + '351,9294,9', + '351,93,9', + '351,96,9', + '1,787,10', + '1,939,10', + '974,33,8', + '974,55,8', + '974,66,8', + '974,77,8', + '1,869,10', + '1,758,10', + '1,784,10', + '685,77,5', + '966,50,9', + '966,51,9', + '966,53,9', + '966,54,9', + '966,55,9', + '966,56,9', + '966,57,9', + '966,58,9', + '966,59,9', + '381,60,9', + '381,61,9', + '381,62,9', + '381,63,9', + '381,64,9', + '381,65,9', + '381,66,9', + '381,677,9', + '381,68,9', + '381,69,8', + '65,8,8', + '65,9,8', + '1,721,10', + '421,901,9', + '421,902,9', + '421,903,9', + '421,904,9', + '421,905,9', + '421,906,9', + '421,907,9', + '421,908,9', + '421,910,9', + '421,911,9', + '421,912,9', + '421,914,9', + '421,915,9', + '421,916,9', + '421,917,9', + '421,918,9', + '421,940,9', + '421,944,9', + '421,948,9', + '421,949,9', + '421,950,9', + '421,951,9', + '386,20,8', + '386,21,8', + '386,30,8', + '386,31,8', + '386,40,8', + '386,41,8', + '386,49,8', + '386,50,8', + '386,51,8', + '386,60,8', + '386,61,8', + '386,64,8', + '386,70,8', + '386,71,8', + '677,74,7', + '677,75,7', + '27,60,9', + '27,710,9', + '27,711,9', + '27,712,9', + '27,713,9', + '27,714,9', + '27,715,9', + '27,716,9', + '27,717,9', + '27,718,9', + '27,719,9', + '27,72,9', + '27,73,9', + '27,74,9', + '27,741,9', + '27,76,9', + '27,78,9', + '27,79,9', + '27,811,9', + '27,812,9', + '27,813,9', + '27,814,9', + '27,82,9', + '27,83,9', + '27,84,9', + '34,6,9', + '34,7,9', + '94,70,7', + '94,71,7', + '94,72,7', + '94,75,7', + '94,76,7', + '94,77,7', + '94,78,7', + '46,70,7', + '46,71 0,10', + '46,73 00,7', + '46,73 01,7', + '46,73 10,7', + '46,73 11,7', + '46,73 12,7', + '46,73 13,7', + '46,73 16,7', + '46,73 170,7', + '46,73 18,7', + '46,73 19,7', + '46,73 20,7', + '46,73 23,7', + '46,73 27,7', + '46,73 28,7', + '46,73 29,7', + '46,73 3,7', + '46,73 455,7', + '46,73 456,7', + '46,73 6,7', + '46,73 85,7', + '46,73 86,7', + '46,73 87,7', + '46,73 88,7', + '46,73 89,7', + '46,73 9,7', + '41,74,9', + '41,75,9', + '41,76,9', + '41,77,9', + '41,78,9', + '41,79,9', + '963,93,9', + '963,98,9', + '963,99,9', + '963,94,9', + '963,95,9', + '963,96,9', + '886,9,9', + '66,6,9', + '66,8,9', + '66,9,9', + '228,90,8', + '228,91,8', + '228,92,8', + '228,97,8', + '228,98,8', + '228,99,8', + '1,868,10', + '216,2,8', + '216,3,8', + '216,4,8', + '216,5,8', + '216,9,8', + '90,50,11', + '90,53,11', + '90,54,11', + '90,55,11', + '1,649,10', + '380,39,9', + '380,50,9', + '380,63,9', + '380,66,9', + '380,67,9', + '380,68,9', + '380,91,9', + '380,92,9', + '380,93,9', + '380,94,9', + '380,95,9', + '380,96,9', + '380,97,9', + '380,98,9', + '380,99,9', + '971,50,9', + '971,52,9', + '971,54,9', + '971,55,9', + '971,56,9', + '971,58,9', + '44,71,10', + '44,72,10', + '44,73,10', + '44,74,10', + '44,75,10', + '44,7624,10', + '44,77,10', + '44,78,10', + '44,79,10', + '598,91,8', + '598,93,8', + '598,94,8', + '598,95,8', + '598,96,8', + '598,97,8', + '598,98,8', + '598,99,8', + '39,06 698,10', + '58,4,7', + '58,412,7', + '58,414,7', + '58,416,7', + '58,424,7', + '58,426,7', + '1,340,10', + '967,7,9', + '967,70,9', + '967,71,9', + '967,73,9', + '967,77,9', +]; diff --git a/drizzle-seed/src/datasets/states.ts b/drizzle-seed/src/datasets/states.ts new file mode 100644 index 000000000..1de77160d --- /dev/null +++ b/drizzle-seed/src/datasets/states.ts @@ -0,0 +1,52 @@ +export default [ + 'Alabama', + 'Alaska', + 'Arizona', + 'Arkansas', + 'California', + 'Colorado', + 'Connecticut', + 'Delaware', + 'Florida', + 'Georgia', + 'Hawaii', + 'Idaho', + 'Illinois', + 'Indiana', + 'Iowa', + 'Kansas', + 'Kentucky', + 'Louisiana', + 'Maine', + 'Maryland', + 'Massachusetts', + 'Michigan', + 'Minnesota', + 'Mississippi', + 'Missouri', + 'Montana', + 'Nebraska', + 'Nevada', + 'New Hampshire', + 'New Jersey', + 'New Mexico', + 'New York', + 'North Carolina', + 'North Dakota', + 'Ohio', + 'Oklahoma', + 'Oregon', + 'Pennsylvania', + 'Rhode Island', + 'South Carolina', + 'South Dakota', + 'Tennessee', + 'Texas', + 'Utah', + 'Vermont', + 'Virginia', + 'Washington', + 'West Virginia', + 'Wisconsin', + 'Wyoming', +]; diff --git a/drizzle-seed/src/datasets/streetSuffix.ts b/drizzle-seed/src/datasets/streetSuffix.ts new file mode 100644 index 000000000..e6e02d505 --- /dev/null +++ b/drizzle-seed/src/datasets/streetSuffix.ts @@ -0,0 +1,197 @@ +export default [ + 'Alley', + 'Avenue', + 'Branch', + 'Bridge', + 'Brook', + 'Brooks', + 'Burg', + 'Burgs', + 'Bypass', + 'Camp', + 'Canyon', + 'Cape', + 'Causeway', + 'Center', + 'Centers', + 'Circle', + 'Circles', + 'Cliff', + 'Cliffs', + 'Club', + 'Common', + 'Corner', + 'Corners', + 'Course', + 'Court', + 'Courts', + 'Cove', + 'Coves', + 'Creek', + 'Crescent', + 'Crest', + 'Crossing', + 'Crossroad', + 'Curve', + 'Dale', + 'Dam', + 'Divide', + 'Drive', + 'Drives', + 'Estate', + 'Estates', + 'Expressway', + 'Extension', + 'Extensions', + 'Fall', + 'Falls', + 'Ferry', + 'Field', + 'Fields', + 'Flat', + 'Flats', + 'Ford', + 'Fords', + 'Forest', + 'Forge', + 'Forges', + 'Fork', + 'Forks', + 'Fort', + 'Freeway', + 'Garden', + 'Gardens', + 'Gateway', + 'Glen', + 'Glens', + 'Green', + 'Greens', + 'Grove', + 'Groves', + 'Harbor', + 'Harbors', + 'Haven', + 'Heights', + 'Highway', + 'Hill', + 'Hills', + 'Hollow', + 'Inlet', + 'Island', + 'Islands', + 'Isle', + 'Junction', + 'Junctions', + 'Key', + 'Keys', + 'Knoll', + 'Knolls', + 'Lake', + 'Lakes', + 'Land', + 'Landing', + 'Lane', + 'Light', + 'Lights', + 'Loaf', + 'Lock', + 'Locks', + 'Lodge', + 'Loop', + 'Mall', + 'Manor', + 'Manors', + 'Meadow', + 'Meadows', + 'Mews', + 'Mill', + 'Mills', + 'Mission', + 'Motorway', + 'Mount', + 'Mountain', + 'Mountains', + 'Neck', + 'Orchard', + 'Oval', + 'Overpass', + 'Park', + 'Parks', + 'Parkway', + 'Parkways', + 'Pass', + 'Passage', + 'Path', + 'Pike', + 'Pine', + 'Pines', + 'Place', + 'Plain', + 'Plains', + 'Plaza', + 'Point', + 'Points', + 'Port', + 'Ports', + 'Prairie', + 'Radial', + 'Ramp', + 'Ranch', + 'Rapid', + 'Rapids', + 'Rest', + 'Ridge', + 'Ridges', + 'River', + 'Road', + 'Roads', + 'Route', + 'Row', + 'Rue', + 'Run', + 'Shoal', + 'Shoals', + 'Shore', + 'Shores', + 'Skyway', + 'Spring', + 'Springs', + 'Spur', + 'Spurs', + 'Square', + 'Squares', + 'Station', + 'Stravenue', + 'Stream', + 'Street', + 'Streets', + 'Summit', + 'Terrace', + 'Throughway', + 'Trace', + 'Track', + 'Trafficway', + 'Trail', + 'Tunnel', + 'Turnpike', + 'Underpass', + 'Union', + 'Unions', + 'Valley', + 'Valleys', + 'Via', + 'Viaduct', + 'View', + 'Views', + 'Village', + 'Villages', + 'Ville', + 'Vista', + 'Walk', + 'Walks', + 'Wall', + 'Way', + 'Ways', + 'Well', + 'Wells', +]; diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts new file mode 100644 index 000000000..e3a22c427 --- /dev/null +++ b/drizzle-seed/src/index.ts @@ -0,0 +1,957 @@ +import { entityKind, getTableName, is, sql } from 'drizzle-orm'; + +import type { MySqlColumn, MySqlSchema } from 'drizzle-orm/mysql-core'; +import { getTableConfig as getMysqlTableConfig, MySqlDatabase, MySqlTable } from 'drizzle-orm/mysql-core'; + +import type { PgColumn, PgSchema } from 'drizzle-orm/pg-core'; +import { getTableConfig as getPgTableConfig, PgDatabase, PgTable } from 'drizzle-orm/pg-core'; + +import type { SQLiteColumn } from 'drizzle-orm/sqlite-core'; +import { BaseSQLiteDatabase, getTableConfig as getSqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; + +import type { AbstractGenerator } from './services/GeneratorsWrappers.ts'; +import { generatorsFuncs } from './services/GeneratorsWrappers.ts'; +import seedService from './services/SeedService.ts'; +import type { DrizzleStudioObjectType, DrizzleStudioRelationType } from './types/drizzleStudio.ts'; +import type { RefinementsType } from './types/seedService.ts'; +import type { Relation, Table } from './types/tables.ts'; + +type InferCallbackType< + DB extends + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + SCHEMA extends { + [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable; + }, +> = DB extends PgDatabase ? SCHEMA extends { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable; + } ? { + // iterates through schema fields. example -> schema: {"tableName": PgTable} + [ + table in keyof SCHEMA as SCHEMA[table] extends PgTable ? table + : never + ]?: { + count?: number; + columns?: { + // iterates through table fields. example -> table: {"columnName": PgColumn} + [ + column in keyof SCHEMA[table] as SCHEMA[table][column] extends PgColumn ? column + : never + ]?: AbstractGenerator; + // ReturnType< + // (typeof generatorsFuncs)[keyof typeof generatorsFuncs] + // > + }; + with?: { + [ + refTable in keyof SCHEMA as SCHEMA[refTable] extends PgTable ? refTable + : never + ]?: + | number + | { weight: number; count: number | number[] }[]; + }; + }; + } + : {} + : DB extends MySqlDatabase ? SCHEMA extends { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable; + } ? { + // iterates through schema fields. example -> schema: {"tableName": MySqlTable} + [ + table in keyof SCHEMA as SCHEMA[table] extends MySqlTable ? table + : never + ]?: { + count?: number; + columns?: { + // iterates through table fields. example -> table: {"columnName": MySqlColumn} + [ + column in keyof SCHEMA[table] as SCHEMA[table][column] extends MySqlColumn ? column + : never + ]?: AbstractGenerator; + // ReturnType< + // (typeof generatorsFuncs)[keyof typeof generatorsFuncs] + // >; + }; + with?: { + [ + refTable in keyof SCHEMA as SCHEMA[refTable] extends MySqlTable ? refTable + : never + ]?: + | number + | { weight: number; count: number | number[] }[]; + }; + }; + } + : {} + : DB extends BaseSQLiteDatabase ? SCHEMA extends { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable; + } ? { + // iterates through schema fields. example -> schema: {"tableName": SQLiteTable} + [ + table in keyof SCHEMA as SCHEMA[table] extends SQLiteTable ? table + : never + ]?: { + count?: number; + columns?: { + // iterates through table fields. example -> table: {"columnName": SQLiteColumn} + [ + column in keyof SCHEMA[table] as SCHEMA[table][column] extends SQLiteColumn ? column + : never + ]?: AbstractGenerator; + // ReturnType< + // (typeof generatorsFuncs)[keyof typeof generatorsFuncs] + // >; + }; + with?: { + [ + refTable in keyof SCHEMA as SCHEMA[refTable] extends SQLiteTable ? refTable + : never + ]?: + | number + | { weight: number; count: number | number[] }[]; + }; + }; + } + : {} + : {}; + +class SeedPromise< + DB extends + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + SCHEMA extends { + [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable; + }, +> implements Promise { + static readonly [entityKind]: string = 'SeedPromise'; + + [Symbol.toStringTag] = 'SeedPromise'; + + constructor( + private db: DB, + private schema: SCHEMA, + private options?: { count?: number; seed?: number }, + ) {} + + then( + onfulfilled?: + | ((value: void) => TResult1 | PromiseLike) + | null + | undefined, + onrejected?: + | ((reason: any) => TResult2 | PromiseLike) + | null + | undefined, + ): Promise { + return seedFunc(this.db, this.schema, this.options).then( + onfulfilled, + onrejected, + ); + } + + catch( + onrejected?: + | ((reason: any) => TResult | PromiseLike) + | null + | undefined, + ): Promise { + return this.then(undefined, onrejected); + } + + finally(onfinally?: (() => void) | null | undefined): Promise { + return this.then( + (value) => { + onfinally?.(); + return value; + }, + (reason) => { + onfinally?.(); + throw reason; + }, + ); + } + + async refine( + callback: (funcs: typeof generatorsFuncs) => InferCallbackType, + ): Promise { + const refinements = callback(generatorsFuncs) as RefinementsType; + + await seedFunc(this.db, this.schema, this.options, refinements); + } +} +// type DrizzleStudioColumnType = { +// default?: unknown, +// autoincrement: boolean, +// name: string, +// type: string, +// primaryKey: boolean, +// notNull: boolean, +// }; + +// export type DrizzleStudioObjectType = { +// schemas: { +// [schemaName: string]: { +// tables: { +// [tableName: string]: { +// name: string, +// type: string, +// indexes: {}, //TODO change to real type +// schema: string, +// columns: { +// [columnName: string]: DrizzleStudioColumnType +// }, +// foreignKeys: {}, //TODO change to real type +// compositePrimaryKeys: {}, //TODO change to real type +// uniqueConstraints: {}, //TODO change to real type +// } +// }, +// views: { +// [viewName: string]: { +// name: string, +// type: string, +// indexes: {}, //TODO change to real type +// schema: string, +// columns: { +// [columnName: string]: DrizzleStudioColumnType +// }, +// foreignKeys: {}, //TODO change to real type +// compositePrimaryKeys: {}, //TODO change to real type +// uniqueConstraints: {}, //TODO change to real type +// } +// }, +// enums: {} +// } +// } +// }; + +export function getGeneratorsFunctions() { + return generatorsFuncs; +} + +export async function seedForDrizzleStudio( + { sqlDialect, drizzleStudioObject, drizzleStudioRelations, schemasRefinements, options }: { + sqlDialect: 'postgresql' | 'mysql' | 'sqlite'; + drizzleStudioObject: DrizzleStudioObjectType; + drizzleStudioRelations: DrizzleStudioRelationType[]; + schemasRefinements?: { [schemaName: string]: RefinementsType }; + options?: { count?: number; seed?: number }; + }, +) { + // where can I find primary keys? + // where can I find relations? + const generatedSchemas: { + [schemaName: string]: { + tables: { + tableName: string; + rows: { + [columnName: string]: string | number | boolean | undefined; + }[]; + }[]; + }; + } = {}; + + let tables: Table[], relations: Relation[], refinements: RefinementsType | undefined; + drizzleStudioRelations = drizzleStudioRelations.filter((rel) => rel.type === 'one'); + for (const [schemaName, { tables: drizzleStudioTables }] of Object.entries(drizzleStudioObject)) { + tables = []; + for (const [tableName, table] of Object.entries(drizzleStudioTables)) { + const drizzleStudioColumns = Object.values(table.columns); + const columns = drizzleStudioColumns.map((col) => ({ + name: col.name, + dataType: 'string', + columnType: col.type, + default: col.default, + hasDefault: col.default === undefined ? false : true, + isUnique: col.isUnique === undefined ? false : col.isUnique, + notNull: col.notNull, + })); + tables.push( + { + name: tableName, + columns, + primaryKeys: drizzleStudioColumns.filter((col) => col.primaryKey === true).map((col) => col.name), + }, + ); + } + + relations = drizzleStudioRelations.filter((rel) => rel.schema === schemaName && rel.refSchema === schemaName); + + refinements = schemasRefinements !== undefined && schemasRefinements[schemaName] !== undefined + ? schemasRefinements[schemaName] + : undefined; + + // console.log("tables:", tables) + const generatedTablesGenerators = seedService.generatePossibleGenerators( + sqlDialect, + tables, + relations, + refinements, + options, + ); + // console.log("generatedTablesGenerators:", generatedTablesGenerators[0]?.columnsPossibleGenerators) + + // console.time("generateTablesValues"); + const generatedTables = await seedService.generateTablesValues( + relations, + generatedTablesGenerators, + undefined, + undefined, + { ...options, preserveData: true, insertDataInDb: false }, + ); + // console.log("generatedTables:", generatedTables) + + generatedSchemas[schemaName] = { tables: generatedTables }; + } + + return generatedSchemas; +} + +/** + * @param db - database you would like to seed. + * @param schema - object that contains all your database tables you would like to seed. + * @param options - object that contains properties `count` and `seed`: + * + * `count` - number of rows you want to generate. + * + * `seed` - a number that controls the state of generated data. (if the `seed` number is the same and nothing is changed in the seeding script, generated data will remain the same each time you seed database) + * + * @returns SeedPromise - a class object that has a refine method that is used to change generators for columns. + * + * @example + * ```ts + * //base seeding + * await seed(db, schema); + * + * //seeding with count specified + * await seed(db, schema, { count: 100000 }); + * + * //seeding with count and seed specified + * await seed(db, schema, { count: 100000, seed: 1 }); + * + * //seeding using refine + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * name: funcs.firstName({ isUnique: true }), + * email: funcs.email(), + * phone: funcs.phoneNumber({ template: "+380 99 ###-##-##" }), + * password: funcs.string({ isUnique: true }), + * }, + * count: 100000, + * }, + * posts: { + * columns: { + * title: funcs.valuesFromArray({ + * values: ["Title1", "Title2", "Title3", "Title4", "Title5"], + * }), + * content: funcs.loremIpsum({ sentencesCount: 3 }), + * }, + * }, + * })); + * + * ``` + */ +export function seed< + DB extends + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + SCHEMA extends { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; + }, +>(db: DB, schema: SCHEMA, options?: { count?: number; seed?: number }) { + return new SeedPromise(db, schema, options); +} + +const seedFunc = async ( + db: PgDatabase | MySqlDatabase | BaseSQLiteDatabase, + schema: { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; + }, + options: { count?: number; seed?: number } = {}, + refinements?: RefinementsType, +) => { + // console.time("seedFunc"); + if (is(db, PgDatabase)) { + const { pgSchema } = filterPgTables(schema); + + await seedPostgres(db, pgSchema, options, refinements); + } else if (is(db, MySqlDatabase)) { + const { mySqlSchema } = filterMySqlTables(schema); + + await seedMySql(db, mySqlSchema, options, refinements); + } else if (is(db, BaseSQLiteDatabase)) { + const { sqliteSchema } = filterSqliteTables(schema); + + await seedSqlite(db, sqliteSchema, options, refinements); + } else { + throw new Error('given db is not supported.'); + } + // console.timeEnd("seedFunc"); +}; + +/** + * deletes all data from specified tables + * + * @param db - database you would like to reset. + * @param schema - object that contains all your database tables you would like to delete data from. + * + * `If db is a PgDatabase object`, we will execute sql query and delete data from your tables the following way: + * ```sql + * truncate tableName1, tableName2, ... cascade; + * ``` + * + * `If db is a MySqlDatabase object`, we will execute sql queries and delete data from your tables the following way: + * ```sql + * SET FOREIGN_KEY_CHECKS = 0; + * truncate tableName1; + * truncate tableName2; + * . + * . + * . + * + * SET FOREIGN_KEY_CHECKS = 1; + * ``` + * + * `If db is a BaseSQLiteDatabase object`, we will execute sql queries and delete data from your tables the following way: + * ```sql + * PRAGMA foreign_keys = OFF; + * delete from tableName1; + * delete from tableName2; + * . + * . + * . + * + * PRAGMA foreign_keys = ON; + * ``` + * + * @example + * ```ts + * await reset(db, schema); + * ``` + */ +export async function reset< + DB extends + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + SCHEMA extends { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; + }, +>(db: DB, schema: SCHEMA) { + if (is(db, PgDatabase)) { + const { pgSchema } = filterPgTables(schema); + + if (Object.entries(pgSchema).length > 0) { + await resetPostgres(db, pgSchema); + } + } else if (is(db, MySqlDatabase)) { + const { mySqlSchema } = filterMySqlTables(schema); + + if (Object.entries(mySqlSchema).length > 0) { + await resetMySql(db, mySqlSchema); + } + } else if (is(db, BaseSQLiteDatabase)) { + const { sqliteSchema } = filterSqliteTables(schema); + + if (Object.entries(sqliteSchema).length > 0) { + await resetSqlite(db, sqliteSchema); + } + } else { + throw new Error('given db is not supported.'); + } +} + +// Postgres----------------------------------------------------------------------------------------------------------- +const resetPostgres = async ( + db: PgDatabase, + schema: { [key: string]: PgTable }, +) => { + const tablesToTruncate = Object.entries(schema).map(([_, table]) => { + const config = getPgTableConfig(table); + config.schema = config.schema === undefined ? 'public' : config.schema; + + return `${config.schema}.${config.name}`; + }); + + await db.execute(sql.raw(`truncate ${tablesToTruncate.join(',')} cascade;`)); +}; + +const filterPgTables = (schema: { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; +}) => { + const pgSchema = Object.fromEntries( + Object.entries(schema).filter((keyValue): keyValue is [string, PgTable] => is(keyValue[1], PgTable)), + ); + + return { pgSchema }; +}; + +const seedPostgres = async ( + db: PgDatabase, + schema: { [key: string]: PgTable }, + options: { count?: number; seed?: number } = {}, + refinements?: RefinementsType, +) => { + const { tables, relations } = getPostgresInfo(schema); + const generatedTablesGenerators = seedService.generatePossibleGenerators( + 'postgresql', + tables, + relations, + refinements, + options, + ); + + // console.time("generateTablesValues"); + await seedService.generateTablesValues( + relations, + generatedTablesGenerators, + db, + schema, + options, + ); + // console.timeEnd("generateTablesValues"); + + // for (const generatedTable of generatedTables) { + // await db + // .insert(schema[generatedTable.tableName]) + // .values(generatedTable.rows) + // .execute(); + // } +}; + +const getPostgresInfo = (schema: { [key: string]: PgTable }) => { + let tableConfig: ReturnType; + let dbToTsColumnNamesMap: { [key: string]: string }; + const dbToTsTableNamesMap: { [key: string]: string } = Object.fromEntries( + Object.entries(schema).map(([key, value]) => [getTableName(value), key]), + ); + + const tables: Table[] = []; + const relations: Relation[] = []; + const dbToTsColumnNamesMapGlobal: { + [tableName: string]: { [dbColumnName: string]: string }; + } = {}; + + const getDbToTsColumnNamesMap = (table: PgTable) => { + let dbToTsColumnNamesMap: { [dbColName: string]: string } = {}; + + const tableName = getTableName(table); + if (Object.hasOwn(dbToTsColumnNamesMapGlobal, tableName)) { + dbToTsColumnNamesMap = dbToTsColumnNamesMapGlobal[tableName]!; + return dbToTsColumnNamesMap; + } + + const tableConfig = getPgTableConfig(table); + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + dbToTsColumnNamesMapGlobal[tableName] = dbToTsColumnNamesMap; + + return dbToTsColumnNamesMap; + }; + + for (const table of Object.values(schema)) { + tableConfig = getPgTableConfig(table); + + dbToTsColumnNamesMap = {}; + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + + relations.push( + ...tableConfig.foreignKeys.map((fk) => { + const table = dbToTsTableNamesMap[tableConfig.name] as string; + const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; + + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( + fk.reference().foreignTable, + ); + + return { + table, + columns: fk + .reference() + .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), + refTable, + refColumns: fk + .reference() + .foreignColumns.map( + (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, + ), + }; + }), + ); + + tables.push({ + name: dbToTsTableNamesMap[tableConfig.name] as string, + columns: tableConfig.columns.map((column) => ({ + name: dbToTsColumnNamesMap[column.name] as string, + columnType: column.columnType.replace('Pg', '').toLowerCase(), + dataType: column.dataType, + hasDefault: column.hasDefault, + default: column.default, + enumValues: column.enumValues, + isUnique: column.isUnique, + notNull: column.notNull, + })), + primaryKeys: tableConfig.columns + .filter((column) => column.primary) + .map((column) => dbToTsColumnNamesMap[column.name] as string), + }); + } + + return { tables, relations }; +}; + +// MySql----------------------------------------------------------------------------------------------------- +const resetMySql = async ( + db: MySqlDatabase, + schema: { [key: string]: MySqlTable }, +) => { + const tablesToTruncate = Object.entries(schema).map(([_tsTableName, table]) => { + const dbTableName = getTableName(table); + // console.log(config) + return dbTableName; + }); + + await db.execute(sql.raw('SET FOREIGN_KEY_CHECKS = 0;')); + + for (const tableName of tablesToTruncate) { + const sqlQuery = `truncate \`${tableName}\`;`; + // console.log(sqlQuery) + await db.execute(sql.raw(sqlQuery)); + } + + await db.execute(sql.raw('SET FOREIGN_KEY_CHECKS = 1;')); +}; + +const filterMySqlTables = (schema: { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; +}) => { + const mySqlSchema = Object.fromEntries( + Object.entries(schema).filter( + (keyValue): keyValue is [string, MySqlTable] => is(keyValue[1], MySqlTable), + ), + ); + + return { mySqlSchema }; +}; + +const seedMySql = async ( + db: MySqlDatabase, + schema: { [key: string]: MySqlTable }, + options: { count?: number; seed?: number } = {}, + refinements?: RefinementsType, +) => { + const { tables, relations } = getMySqlInfo(schema); + + const generatedTablesGenerators = seedService.generatePossibleGenerators( + 'mysql', + tables, + relations, + refinements, + options, + ); + + await seedService.generateTablesValues( + relations, + generatedTablesGenerators, + db, + schema, + options, + ); + + // for (const generatedTable of generatedTables) { + // await db + // .insert(schema[generatedTable.tableName]) + // .values(generatedTable.rows) + // .execute(); + // } +}; + +const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { + let tableConfig: ReturnType; + let dbToTsColumnNamesMap: { [key: string]: string }; + + const dbToTsTableNamesMap: { [key: string]: string } = Object.fromEntries( + Object.entries(schema).map(([key, value]) => [getTableName(value), key]), + ); + + const tables: Table[] = []; + const relations: Relation[] = []; + const dbToTsColumnNamesMapGlobal: { + [tableName: string]: { [dbColumnName: string]: string }; + } = {}; + + const getDbToTsColumnNamesMap = (table: MySqlTable) => { + let dbToTsColumnNamesMap: { [dbColName: string]: string } = {}; + + const tableName = getTableName(table); + if (Object.hasOwn(dbToTsColumnNamesMapGlobal, tableName)) { + dbToTsColumnNamesMap = dbToTsColumnNamesMapGlobal[tableName]!; + return dbToTsColumnNamesMap; + } + + const tableConfig = getMysqlTableConfig(table); + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + dbToTsColumnNamesMapGlobal[tableName] = dbToTsColumnNamesMap; + + return dbToTsColumnNamesMap; + }; + + for (const table of Object.values(schema)) { + tableConfig = getMysqlTableConfig(table); + + dbToTsColumnNamesMap = {}; + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + + relations.push( + ...tableConfig.foreignKeys.map((fk) => { + const table = dbToTsTableNamesMap[tableConfig.name] as string; + const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( + fk.reference().foreignTable, + ); + + return { + table, + columns: fk + .reference() + .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), + refTable, + refColumns: fk + .reference() + .foreignColumns.map( + (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, + ), + }; + }), + ); + + tables.push({ + name: dbToTsTableNamesMap[tableConfig.name] as string, + columns: tableConfig.columns.map((column) => ({ + name: dbToTsColumnNamesMap[column.name] as string, + columnType: column.columnType.replace('MySql', '').toLowerCase(), + dataType: column.dataType, + hasDefault: column.hasDefault, + default: column.default, + enumValues: column.enumValues, + isUnique: column.isUnique, + notNull: column.notNull, + })), + primaryKeys: tableConfig.columns + .filter((column) => column.primary) + .map((column) => dbToTsColumnNamesMap[column.name] as string), + }); + } + + return { tables, relations }; +}; + +// Sqlite------------------------------------------------------------------------------------------------------------------------ +const resetSqlite = async ( + db: BaseSQLiteDatabase, + schema: { [key: string]: SQLiteTable }, +) => { + const tablesToTruncate = Object.entries(schema).map(([_tsTableName, table]) => { + const dbTableName = getTableName(table); + // console.log(config) + return dbTableName; + }); + + await db.run(sql.raw('PRAGMA foreign_keys = OFF')); + + for (const tableName of tablesToTruncate) { + const sqlQuery = `delete from \`${tableName}\`;`; + // console.log(sqlQuery) + await db.run(sql.raw(sqlQuery)); + } + + await db.run(sql.raw('PRAGMA foreign_keys = ON')); +}; + +const filterSqliteTables = (schema: { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; +}) => { + const sqliteSchema = Object.fromEntries( + Object.entries(schema).filter( + (keyValue): keyValue is [string, SQLiteTable] => is(keyValue[1], SQLiteTable), + ), + ); + + return { sqliteSchema }; +}; + +const seedSqlite = async ( + db: BaseSQLiteDatabase, + schema: { [key: string]: SQLiteTable }, + options: { count?: number; seed?: number } = {}, + refinements?: RefinementsType, +) => { + const { tables, relations } = getSqliteInfo(schema); + + const generatedTablesGenerators = seedService.generatePossibleGenerators( + 'sqlite', + tables, + relations, + refinements, + options, + ); + + await seedService.generateTablesValues( + relations, + generatedTablesGenerators, + db, + schema, + options, + ); + + // for (const generatedTable of generatedTables) { + // await db + // .insert(schema[generatedTable.tableName]) + // .values(generatedTable.rows) + // .execute(); + // } +}; + +const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { + let tableConfig: ReturnType; + let dbToTsColumnNamesMap: { [key: string]: string }; + const dbToTsTableNamesMap: { [key: string]: string } = Object.fromEntries( + Object.entries(schema).map(([key, value]) => [getTableName(value), key]), + ); + + const tables: Table[] = []; + const relations: Relation[] = []; + const dbToTsColumnNamesMapGlobal: { + [tableName: string]: { [dbColumnName: string]: string }; + } = {}; + + const getDbToTsColumnNamesMap = (table: SQLiteTable) => { + let dbToTsColumnNamesMap: { [dbColName: string]: string } = {}; + + const tableName = getTableName(table); + if (Object.hasOwn(dbToTsColumnNamesMapGlobal, tableName)) { + dbToTsColumnNamesMap = dbToTsColumnNamesMapGlobal[tableName]!; + return dbToTsColumnNamesMap; + } + + const tableConfig = getSqliteTableConfig(table); + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + dbToTsColumnNamesMapGlobal[tableName] = dbToTsColumnNamesMap; + + return dbToTsColumnNamesMap; + }; + + for (const table of Object.values(schema)) { + tableConfig = getSqliteTableConfig(table); + + dbToTsColumnNamesMap = {}; + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + + relations.push( + ...tableConfig.foreignKeys.map((fk) => { + const table = dbToTsTableNamesMap[tableConfig.name] as string; + const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( + fk.reference().foreignTable, + ); + + return { + table, + columns: fk + .reference() + .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), + refTable, + refColumns: fk + .reference() + .foreignColumns.map( + (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, + ), + }; + }), + ); + + tables.push({ + name: dbToTsTableNamesMap[tableConfig.name] as string, + columns: tableConfig.columns.map((column) => ({ + name: dbToTsColumnNamesMap[column.name] as string, + columnType: column.columnType.replace('SQLite', '').toLowerCase(), + dataType: column.dataType, + hasDefault: column.hasDefault, + default: column.default, + enumValues: column.enumValues, + isUnique: column.isUnique, + notNull: column.notNull, + })), + primaryKeys: tableConfig.columns + .filter((column) => column.primary) + .map((column) => dbToTsColumnNamesMap[column.name] as string), + }); + } + + return { tables, relations }; +}; diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts new file mode 100644 index 000000000..635f4d15f --- /dev/null +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -0,0 +1,3588 @@ +import { entityKind } from 'drizzle-orm'; +import prand from 'pure-rand'; +import adjectives from '../datasets/adjectives.ts'; +import cityNames from '../datasets/cityNames.ts'; +import companyNameSuffixes from '../datasets/companyNameSuffixes.ts'; +import countries from '../datasets/countries.ts'; +import emailDomains from '../datasets/emailDomains.ts'; +import firstNames from '../datasets/firstNames.ts'; +import jobsTitles from '../datasets/jobsTitles.ts'; +import lastNames from '../datasets/lastNames.ts'; +import loremIpsumSentences from '../datasets/loremIpsumSentences.ts'; +import phonesInfo from '../datasets/phonesInfo.ts'; +import states from '../datasets/states.ts'; +import streetSuffix from '../datasets/streetSuffix.ts'; +import { fastCartesianProduct, fillTemplate, getWeightedIndices } from './utils.ts'; + +export abstract class AbstractGenerator { + static readonly [entityKind]: string = 'AbstractGenerator'; + + public isUnique = false; + public notNull = false; + public uniqueVersionOfGen?: new(params: T) => AbstractGenerator; + public dataType?: string; + public timeSpent?: number; + + constructor(public params: T) {} + + abstract init(params: { count: number | { weight: number; count: number | number[] }[]; seed: number }): void; + + abstract generate(params: { i: number }): number | string | boolean | unknown | undefined | void; +} + +// type OptionalSpread = +// T extends undefined +// ? [] +// : [T]; + +// function createGenerator>( +// generatorConstructor: new ({ }: T) => GT +// ) { +// return (...args: OptionalSpread): GT => { +// if (params === undefined) params = {} as T; +// return new generatorConstructor(params); +// }; +// } + +// function foo(...args: OptionalSpread) { +// const arg = args[0] // Type of: T = undefined +// return arg; +// } + +// foo(1) + +// function createGenerator( +// generatorConstructor: new ({ }: T) => AbstractGenerator +// ) { +// return (...args: IsRequired extends true ? [T] : ([] | [T])): AbstractGenerator => { +// let params = args[0]; +// if (params === undefined) params = {} as T; +// return new generatorConstructor(params); +// }; +// } + +function createGenerator, T>( + generatorConstructor: new(params: T) => GeneratorType, +) { + return ( + ...args: GeneratorType extends GenerateValuesFromArray | GenerateDefault | WeightedRandomGenerator ? [T] + : ([] | [T]) + ): GeneratorType => { + let params = args[0]; + if (params === undefined) params = {} as T; + return new generatorConstructor(params); + }; +} + +// Generators Classes ----------------------------------------------------------------------------------------------------------------------- +export class GenerateWeightedCount extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'GenerateWeightedCount'; + + private state: { + rng: prand.RandomGenerator; + weightedIndices: number[]; + weightedCount: { weight: number; count: number | number[] }[]; + } | undefined; + + init({ seed, count }: { count: { weight: number; count: number | number[] }[]; seed: number }) { + const rng = prand.xoroshiro128plus(seed); + const weightedIndices = getWeightedIndices(count.map((val) => val.weight)); + this.state = { rng, weightedIndices, weightedCount: count }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + // logic for this generator + let idx: number; + const weightedCount = this.state.weightedCount; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.weightedIndices.length - 1, this.state.rng); + const objIdx = this.state.weightedIndices[idx] as number; + + if (typeof weightedCount[objIdx]!.count === 'number') { + return weightedCount[objIdx]!.count as number; + } else { + // typeof weightedCount[objIdx]!.count === 'object' // number[] + const possCounts = weightedCount[objIdx]!.count as number[]; + [idx, this.state.rng] = prand.uniformIntDistribution(0, possCounts.length - 1, this.state.rng); + return possCounts[idx]!; + } + } +} + +export class HollowGenerator extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'HollowGenerator'; + + init() {} + + generate() {} +} + +export class GenerateDefault extends AbstractGenerator<{ + defaultValue: unknown; +}> { + static readonly [entityKind]: string = 'GenerateDefault'; + + init() {} + + generate() { + return this.params.defaultValue; + } +} + +export class GenerateValuesFromArray extends AbstractGenerator< + { + values: + | (number | string | boolean | undefined)[] + | { weight: number; values: (number | string | boolean | undefined)[] }[]; + isUnique?: boolean; + } +> { + static readonly [entityKind]: string = 'GenerateValuesFromArray'; + + public weightedCountSeed: number | undefined = undefined; + public maxRepeatedValuesCount?: number | { weight: number; count: number | number[] }[] = undefined; + private state: { + rng: prand.RandomGenerator; + values: + | (number | string | boolean | undefined)[] + | { weight: number; values: (number | string | boolean | undefined)[] }[]; + // valuesCount: { [key: string | number]: number }; + // indicesCount: { [key: number]: number }; + genIndicesObj: GenerateUniqueInt | undefined; + genIndicesObjList: GenerateUniqueInt[] | undefined; + valuesWeightedIndices: number[] | undefined; + genMaxRepeatedValuesCount: GenerateDefault | GenerateWeightedCount | undefined; + } | undefined; + public override timeSpent: number = 0; + + checks({ count }: { count: number }) { + const { values } = this.params; + const { maxRepeatedValuesCount, notNull, isUnique } = this; + if (values.length === 0) { + throw new Error('values length equals zero.'); + } + + if ( + typeof values[0] === 'object' + && !(values as { weight: number; values: any[] }[]).every((val) => val.values.length !== 0) + ) { + throw new Error('one of weighted values length equals zero.'); + } + + if ( + maxRepeatedValuesCount !== undefined && ( + (typeof maxRepeatedValuesCount === 'number' && maxRepeatedValuesCount <= 0) + || (typeof maxRepeatedValuesCount === 'object' && !maxRepeatedValuesCount + .every((obj) => + (typeof obj.count) === 'number' + ? (obj.count as number) > 0 + : (obj.count as number[]).every((count) => count > 0) + )) + ) + ) { + throw new Error('maxRepeatedValuesCount should be greater than zero.'); + } + + let allValuesCount = values.length; + if (typeof values[0] === 'object') { + allValuesCount = (values as { values: any[] }[]).reduce((acc, currVal) => acc + currVal.values.length, 0); + } + + if ( + notNull === true + && maxRepeatedValuesCount !== undefined + && ( + (typeof values[0] !== 'object' && typeof maxRepeatedValuesCount === 'number' + && maxRepeatedValuesCount * values.length < count) + || (typeof values[0] === 'object' && typeof maxRepeatedValuesCount === 'number' + && maxRepeatedValuesCount * allValuesCount < count) + ) + ) { + throw new Error("(maxRepeatedValuesCount * values.length) < count. can't fill notNull column with null values."); + } + + if ( + isUnique === true && maxRepeatedValuesCount !== undefined && ( + (typeof maxRepeatedValuesCount === 'number' && maxRepeatedValuesCount > 1) + || (typeof maxRepeatedValuesCount === 'object' && !maxRepeatedValuesCount + .every((obj) => + (typeof obj.count) === 'number' + ? obj.count === 1 + : (obj.count as number[]).every((count) => count === 1) + )) + ) + ) { + throw new Error("maxRepeatedValuesCount can't be greater than 1 if column is unique."); + } + + if ( + isUnique === true && notNull === true && ( + (typeof values[0] !== 'object' && values.length < count) + || (typeof values[0] === 'object' && allValuesCount < count) + ) + ) { + // console.log(maxRepeatedValuesCount, values.length, allValuesCount, count) + throw new Error('there are no enough values to fill unique column.'); + } + } + + init({ count, seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + this.checks({ count }); + + let { maxRepeatedValuesCount } = this; + const { params, isUnique, notNull, weightedCountSeed } = this; + + const values = params.values; + // let values; + // if (typeof this.params.values[0] === "object") { + // values = this.params.values.slice(); + // } + // else { + // values = this.params.values; + // } + + // const valuesCount = {}; + // const indicesCount = {}; + + let valuesWeightedIndices; + if (typeof values[0] === 'object') { + valuesWeightedIndices = getWeightedIndices((values as { weight: number }[]).map((val) => val.weight)); + if (isUnique === true && notNull === true) { + let idx: number, valueIdx: number, rng = prand.xoroshiro128plus(seed); + const indicesCounter: { [key: number]: number } = {}; + for (let i = 0; i < count; i++) { + [idx, rng] = prand.uniformIntDistribution(0, valuesWeightedIndices.length - 1, rng); + valueIdx = valuesWeightedIndices[idx]!; + if (!Object.hasOwn(indicesCounter, valueIdx)) indicesCounter[valueIdx] = 0; + indicesCounter[valueIdx]! += 1; + } + + // console.log(values, indicesCounter) + for (const [idx, value] of values.entries()) { + // console.log((value as { values: (number | string | boolean | undefined)[] }).values.length) + if ((value as { values: (number | string | boolean | undefined)[] }).values.length < indicesCounter[idx]!) { + throw new Error( + 'weighted values arrays is too small to generate values with specified probability for unique not null column.' + + `it's planned to generate: ${ + Object.entries(indicesCounter).map(([idx, count]) => { + return `${count} values with probability ${(values as { weight: number }[])[Number(idx)]?.weight}`; + }).join(',') + }`, + ); + } + } + } + } + if (isUnique === true && maxRepeatedValuesCount === undefined) { + maxRepeatedValuesCount = 1; + } + let genMaxRepeatedValuesCount: GenerateDefault | GenerateWeightedCount | undefined; + if (typeof maxRepeatedValuesCount === 'number') { + genMaxRepeatedValuesCount = new GenerateDefault({ defaultValue: maxRepeatedValuesCount }); + } else if (typeof maxRepeatedValuesCount === 'object') { + genMaxRepeatedValuesCount = new GenerateWeightedCount({}); + (genMaxRepeatedValuesCount as GenerateWeightedCount).init( + { + count: maxRepeatedValuesCount, + seed: weightedCountSeed === undefined ? seed : weightedCountSeed, + }, + ); + } + + let genIndicesObj: GenerateUniqueInt | undefined; + let genIndicesObjList: GenerateUniqueInt[] | undefined; + + if (maxRepeatedValuesCount !== undefined) { + if (typeof values[0] !== 'object') { + genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: values.length - 1 }); + genIndicesObj.genMaxRepeatedValuesCount = genMaxRepeatedValuesCount; + genIndicesObj.skipCheck = true; + genIndicesObj.init({ count, seed }); + } else if (typeof values[0] === 'object') { + genIndicesObjList = []; + for (const obj of values as { weight: number; values: (number | string | boolean | undefined)[] }[]) { + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: obj.values.length - 1 }); + genIndicesObj.genMaxRepeatedValuesCount = genMaxRepeatedValuesCount; + genIndicesObj.skipCheck = true; + genIndicesObj.init({ count, seed }); + genIndicesObjList.push(genIndicesObj); + } + } + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng, values, valuesWeightedIndices, genMaxRepeatedValuesCount, genIndicesObj, genIndicesObjList }; + } + + generate() { + const t0 = new Date(); + // let { maxRepeatedValuesCount } = this; + + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + // logic for this generator + let idx: number, + value: string | number | boolean | undefined; + let valueIdx: number; + + if (this.state.valuesWeightedIndices === undefined) { + if (this.state.genIndicesObj === undefined) { + // isUnique !== true + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.values.length - 1, this.state.rng); + } else { + // isUnique === true + idx = this.state.genIndicesObj.generate() as number; + // console.log("maxRepeatedValuesCount:", this.maxRepeatedValuesCount, "idx:", idx) + } + + // [idx, this.rng] = prand.uniformIntDistribution(0, this.values!.length - 1, this.rng!); + value = (this.state.values as (number | string | boolean | undefined)[])[idx]; + } else { + // weighted values + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + this.state.valuesWeightedIndices.length - 1, + this.state.rng, + ); + valueIdx = this.state.valuesWeightedIndices[idx] as number; + const currValues = + (this.state.values![valueIdx] as { weight: number; values: (number | string | boolean | undefined)[] }).values; + if (this.state.genIndicesObjList === undefined) { + // isUnique !== true + [idx, this.state.rng] = prand.uniformIntDistribution(0, currValues.length - 1, this.state.rng); + } else { + // isUnique === true + idx = this.state.genIndicesObjList[valueIdx]!.generate() as number; + } + value = currValues[idx]; + } + + // if (maxRepeatedValuesCount !== undefined) { + // if (this.state.valuesCount[value as string | number] === undefined) { + // this.state.valuesCount[value as string | number] = this.state.genMaxRepeatedValuesCount!.generate() as number; + // } + // this.state.valuesCount![value as string | number] -= 1; + + // // this.state.indicesCount[idx] = this.state.valuesCount[value as string | number]; + // console.log("indicesCount", this.state.indicesCount) + + // if (this.state.valuesCount![value as string | number] === 0) { + // if (this.state.valuesWeightedIndices !== undefined) { + // // this.values!.splice(idx, 1); + // const currValues = (this.state.values![valueIdx!] as { weight: number, values: (number | string | boolean | undefined)[] }).values; + // currValues.splice(idx, 1); + // if (currValues.length === 0) { + // this.state.values!.splice(valueIdx!, 1); + // } + // } + // } + // } + + this.timeSpent += (Date.now() - t0.getTime()) / 1000; + return value; + } +} + +export class GenerateSelfRelationsValuesFromArray extends AbstractGenerator<{ values: (number | string | boolean)[] }> { + static readonly [entityKind]: string = 'GenerateSelfRelationsValuesFromArray'; + + private state: { + rng: prand.RandomGenerator; + firstValuesCount: number; + firstValues: (string | number | boolean)[]; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + let rng = prand.xoroshiro128plus(seed); + + // generate 15-40 % values with the same value as reference column + let percent = 30; + [percent, rng] = prand.uniformIntDistribution(20, 40, rng); + const firstValuesCount = Math.floor((percent / 100) * count), firstValues: (string | number | boolean)[] = []; + + this.state = { rng, firstValuesCount, firstValues }; + } + + generate({ i }: { i: number }) { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const { values } = this.params; + // logic for this generator + let idx: number; + + if (i < this.state.firstValuesCount) { + this.state.firstValues.push(values[i]!); + return values[i]; + } else { + // i >= this.state.firstValuesCount + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.firstValues.length - 1, this.state.rng); + return this.state.firstValues[idx]; + } + } +} + +export class GenerateIntPrimaryKey extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'GenerateIntPrimaryKey'; + + public maxValue?: number | bigint; + + init({ count }: { count: number; seed: number }) { + if (this.maxValue !== undefined && count > this.maxValue) { + throw new Error('count exceeds max number for this column type.'); + } + } + + generate({ i }: { i: number }) { + if (this.dataType === 'bigint') { + return BigInt(i + 1); + } + + return i + 1; + } +} + +export class GenerateNumber extends AbstractGenerator< + { + minValue?: number; + maxValue?: number; + precision?: number; + isUnique?: boolean; + } | undefined +> { + static readonly [entityKind]: string = 'GenerateNumber'; + + private state: { + rng: prand.RandomGenerator; + minValue: number; + maxValue: number; + precision: number; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueNumber; + + init({ seed }: { seed: number }) { + if (this.params === undefined) this.params = {}; + + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + let { minValue, maxValue, precision } = this.params; + // logic for this generator + if (precision === undefined) { + precision = 100; + } + + if (maxValue === undefined) { + maxValue = precision * 1000; + } else { + maxValue *= precision; + } + + if (minValue === undefined) { + minValue = -maxValue; + } else { + minValue *= precision; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng, minValue, maxValue, precision }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let value: number; + + [value, this.state.rng] = prand.uniformIntDistribution(this.state.minValue, this.state.maxValue, this.state.rng); + return value / this.state.precision; + } +} + +export class GenerateUniqueNumber extends AbstractGenerator< + { + minValue?: number; + maxValue?: number; + precision?: number; + isUnique?: boolean; + } | undefined +> { + static readonly [entityKind]: string = 'GenerateUniqueNumber'; + + private state: { + genUniqueIntObj: GenerateUniqueInt; + minValue: number; + maxValue: number; + precision: number; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + if (this.params === undefined) this.params = {}; + let { minValue, maxValue, precision } = this.params; + + if (precision === undefined) { + precision = 100; + } + + if (maxValue === undefined) { + maxValue = count * precision; + } else { + maxValue *= precision; + } + + if (minValue === undefined) { + minValue = -maxValue; + } else { + minValue *= precision; + } + + const genUniqueIntObj = new GenerateUniqueInt({ minValue, maxValue }); + genUniqueIntObj.init({ count, seed }); + + this.state = { genUniqueIntObj, minValue, maxValue, precision }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const value = this.state.genUniqueIntObj.generate() as number / this.state.precision; + + return value; + } +} + +export class GenerateInt extends AbstractGenerator<{ + minValue?: number | bigint; + maxValue?: number | bigint; + isUnique?: boolean; +}> { + static readonly [entityKind]: string = 'GenerateInt'; + + private state: { + rng: prand.RandomGenerator; + minValue: number | bigint; + maxValue: number | bigint; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueInt; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + let { minValue, maxValue } = this.params; + + if (maxValue === undefined) { + maxValue = 1000; + } + + if (minValue === undefined) { + minValue = maxValue === undefined ? -1000 : -maxValue; + } + + if (typeof minValue === 'number' && typeof maxValue === 'number') { + minValue = minValue >= 0 ? Math.ceil(minValue) : Math.floor(minValue); + maxValue = maxValue >= 0 ? Math.floor(maxValue) : Math.ceil(maxValue); + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng, minValue, maxValue }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let value: number | bigint; + if (typeof this.state.minValue === 'bigint' && typeof this.state.maxValue === 'bigint') { + [value, this.state.rng] = prand.uniformBigIntDistribution( + this.state.minValue, + this.state.maxValue, + this.state.rng, + ); + } else { + [value, this.state.rng] = prand.uniformIntDistribution( + this.state.minValue as number, + this.state.maxValue as number, + this.state.rng, + ); + } + + if (this.dataType === 'string') { + return String(value); + } + + if (this.dataType === 'bigint') { + value = BigInt(value); + } + return value; + } +} + +export class GenerateUniqueInt extends AbstractGenerator<{ + minValue?: number | bigint; + maxValue?: number | bigint; + isUnique?: boolean; +}> { + static readonly [entityKind]: string = 'GenerateUniqueInt'; + + public genMaxRepeatedValuesCount: GenerateDefault | GenerateWeightedCount | undefined; + public skipCheck?: boolean = false; + public state: { + rng: prand.RandomGenerator; + minValue: number | bigint; + maxValue: number | bigint; + intervals: (number | bigint)[][]; + integersCount: Map; + } | undefined; + public override isUnique = true; + public override timeSpent = 0; + + init({ count, seed }: { count: number; seed: number }) { + const rng = prand.xoroshiro128plus(seed); + let { minValue, maxValue } = this.params; + + if (maxValue === undefined) { + maxValue = count * 10; + } + if (minValue === undefined) { + minValue = -maxValue; + } + + const intervals = [[minValue, maxValue]]; + + const integersCount = new Map(); + + if (typeof minValue === 'bigint' && typeof maxValue === 'bigint') { + if (this.skipCheck === false && maxValue - minValue + BigInt(1) < count) { + throw new Error( + 'count exceeds max number of unique integers in given range(min, max), try to make range wider.', + ); + } + } else if (typeof minValue === 'number' && typeof maxValue === 'number') { + minValue = minValue >= 0 ? Math.ceil(minValue) : Math.floor(minValue); + maxValue = maxValue >= 0 ? Math.floor(maxValue) : Math.ceil(maxValue); + if (this.skipCheck === false && maxValue - minValue + 1 < count) { + throw new Error( + 'count exceeds max number of unique integers in given range(min, max), try to make range wider.', + ); + } + } else { + throw new Error( + 'minValue and maxValue should be the same type.', + ); + } + + this.state = { rng, minValue, maxValue, intervals, integersCount }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let intervalIdx: number, + numb: number | bigint | undefined; + + const intervalsToAdd: (number | bigint)[][] = []; + + if (this.state.intervals.length === 0) { + if (this.skipCheck === false) { + // console.log(`i:${i}`); + // console.log("integersCount", integersCount, "maxValue", maxValue) + // console.log("maxValue", this.state.maxValue, "minValue", this.state.minValue, this.skipCheck) + throw new RangeError( + 'generateUniqueInt: count exceeds max number of unique integers in given range(min, max), try to increase range.', + ); + } else { + return; + } + } + + [intervalIdx, this.state.rng] = prand.uniformIntDistribution( + 0, + this.state.intervals.length - 1, + this.state.rng, + ); + + const interval = this.state.intervals[intervalIdx] as (number | bigint)[]; + const [currMinNumb, currMaxNumb] = [interval[0] as number | bigint, interval[1] as number | bigint]; + + if (typeof currMinNumb === 'number' && typeof currMaxNumb === 'number') { + numb = this.generateNumber(currMinNumb, currMaxNumb, intervalsToAdd as number[][], intervalIdx); + } else if (typeof currMinNumb === 'bigint' && typeof currMaxNumb === 'bigint') { + numb = this.generateBigint( + currMinNumb as bigint, + currMaxNumb as bigint, + intervalsToAdd as bigint[][], + intervalIdx, + ); + } + + if (this.dataType === 'string') { + return String(numb); + } + + if (this.dataType === 'bigint' && numb !== undefined) { + numb = BigInt(numb); + } + return numb; + } + + generateNumber(currMinNumb: number, currMaxNumb: number, intervalsToAdd: number[][], intervalIdx: number) { + let numb: number; + + [numb, this.state!.rng] = prand.uniformIntDistribution(currMinNumb, currMaxNumb, this.state!.rng); + + if (this.genMaxRepeatedValuesCount !== undefined) { + if (this.state!.integersCount.get(numb) === undefined) { + this.state!.integersCount.set(numb, this.genMaxRepeatedValuesCount.generate() as number); + } + this.state!.integersCount.set(numb, this.state!.integersCount.get(numb)! - 1); + } + + // console.log("integersCount", this.state.integersCount); + + if (this.state!.integersCount.get(numb) === undefined || this.state!.integersCount.get(numb) === 0) { + if (numb === currMinNumb) { + intervalsToAdd = numb + 1 <= currMaxNumb ? [[numb + 1, currMaxNumb]] : []; + } else if (numb === currMaxNumb) { + intervalsToAdd = [[currMinNumb, numb - 1]]; + } else { + intervalsToAdd = [ + [currMinNumb, numb - 1], + [numb + 1, currMaxNumb], + ]; + } + + // delete intervals[intervalIdx]; + const t0 = new Date(); + this.state!.intervals[intervalIdx] = this.state!.intervals[this.state!.intervals.length - 1]!; + this.state?.intervals.pop(); + // this.state!.intervals.splice(intervalIdx, 1); + this.timeSpent += (Date.now() - t0.getTime()) / 1000; + this.state!.intervals.push(...intervalsToAdd); + } + + return numb; + } + + generateBigint(currMinNumb: bigint, currMaxNumb: bigint, intervalsToAdd: bigint[][], intervalIdx: number) { + let numb: bigint; + [numb, this.state!.rng] = prand.uniformBigIntDistribution(currMinNumb, currMaxNumb, this.state!.rng); + if (this.genMaxRepeatedValuesCount !== undefined) { + if (this.state!.integersCount.get(numb) === undefined) { + this.state!.integersCount.set(numb, this.genMaxRepeatedValuesCount.generate() as number); + } + this.state!.integersCount.set(numb, this.state!.integersCount.get(numb)! - 1); + } + + // console.log("integersCount", this.state.integersCount); + if (this.state!.integersCount.get(numb) === undefined || this.state!.integersCount.get(numb) === 0) { + if (numb === currMinNumb) { + intervalsToAdd = numb + BigInt(1) <= currMaxNumb ? [[numb + BigInt(1), currMaxNumb]] : []; + } else if (numb === currMaxNumb) { + intervalsToAdd = [[currMinNumb, numb - BigInt(1)]]; + } else { + intervalsToAdd = [ + [currMinNumb, numb - BigInt(1)], + [numb + BigInt(1), currMaxNumb], + ]; + } + + // delete intervals[intervalIdx]; + // this.state!.intervals.splice(intervalIdx, 1); + this.state!.intervals[intervalIdx] = this.state!.intervals[this.state!.intervals.length - 1]!; + this.state?.intervals.pop(); + this.state!.intervals.push(...intervalsToAdd); + } + + return numb; + } +} + +export class GenerateBoolean extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'GenerateBoolean'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let value: number; + + [value, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); + return value === 1; + } +} + +export class GenerateDate extends AbstractGenerator<{ minDate?: string | Date; maxDate?: string | Date }> { + static readonly [entityKind]: string = 'GenerateDate'; + + private state: { + rng: prand.RandomGenerator; + minDate: Date; + maxDate: Date; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + let { minDate, maxDate } = this.params; + const anchorDate = new Date('2024-05-08'); + // const formatter = new Intl.DateTimeFormat("en-US", { year: "numeric", month: "2-digit", day: "2-digit", }); + // anchorDate.toLocaleDateString("en-US", { year: "numeric", month: "2-digit", day: "2-digit", }) + // fourYearsInMilliseconds + const deltaMilliseconds = 4 * 31536000000; + + if (typeof minDate === 'string') { + minDate = new Date(minDate); + } + + if (typeof maxDate === 'string') { + maxDate = new Date(maxDate); + } + + if (minDate === undefined) { + if (maxDate === undefined) { + minDate = new Date(anchorDate.getTime() - deltaMilliseconds); + maxDate = new Date(anchorDate.getTime() + deltaMilliseconds); + } else { + minDate = new Date(maxDate.getTime() - (2 * deltaMilliseconds)); + } + } + + if (maxDate === undefined) { + maxDate = new Date(minDate.getTime() + (2 * deltaMilliseconds)); + } + + this.state = { rng, minDate, maxDate }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let milliseconds: number; + + [milliseconds, this.state.rng] = prand.uniformIntDistribution( + this.state.minDate.getTime(), + this.state.maxDate.getTime(), + this.state.rng, + ); + const date = new Date(milliseconds); + + if (this.dataType === 'string') { + return date.toISOString().replace(/T.+/, ''); + } + // this.dataType === "date" + return date; + } +} + +// export class GenerateDateString extends AbstractGenerator<{}> { +// private state: { +// dateGen: GenerateDate +// } | undefined; + +// init({ seed }: { seed: number }) { +// const dateGen = new GenerateDate({}); +// dateGen.init({ seed }); + +// this.state = { dateGen }; +// } + +// generate() { +// if (this.state === undefined) { +// throw new Error("state is not defined."); +// } + +// const date = this.state.dateGen.generate(); + +// return date.toISOString().replace(/T.+/, ""); +// } +// } + +export class GenerateTime extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'GenerateTime'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const anchorDateTime = new Date('2024-05-08T12:00:00.000Z'); + const oneDayInMilliseconds = 86400000; + + let date = new Date(); + let milliseconds: number; + + [milliseconds, this.state.rng] = prand.uniformIntDistribution( + -oneDayInMilliseconds, + oneDayInMilliseconds, + this.state.rng, + ); + date = new Date(date.setTime(anchorDateTime.getTime() + milliseconds)); + + return date.toISOString().replace(/(\d{4}-\d{2}-\d{2}T)|(\.\d{3}Z)/g, ''); + } +} + +// export class GenerateTimestampString extends AbstractGenerator<{}> { +// private state: { +// generateTimestampObj: GenerateTimestamp; +// } | undefined; + +// init({ seed }: { seed: number }) { +// const generateTimestampObj = new GenerateTimestamp({}); +// generateTimestampObj.init({ seed }); + +// this.state = { generateTimestampObj }; +// } + +// generate() { +// if (this.state === undefined) { +// throw new Error("state is not defined."); +// } + +// let date: Date; +// date = this.state.generateTimestampObj.generate(); + +// return date +// .toISOString() +// .replace("T", " ") +// .replace(/\.\d{3}Z/, ""); + +// } + +export class GenerateTimestampInt extends AbstractGenerator<{ unitOfTime?: 'seconds' | 'milliseconds' }> { + static readonly [entityKind]: string = 'GenerateTimestampInt'; + + private state: { + generateTimestampObj: GenerateTimestamp; + } | undefined; + + init({ seed }: { seed: number }) { + const generateTimestampObj = new GenerateTimestamp({}); + generateTimestampObj.dataType = 'date'; + generateTimestampObj.init({ seed }); + + this.state = { generateTimestampObj }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const date = this.state.generateTimestampObj.generate() as Date; + + if (this.params.unitOfTime === 'seconds') { + return Math.floor(date.getTime() / 1000); + } else if (this.params.unitOfTime === 'milliseconds') { + return date.getTime(); + } else { + // this.params.unitOfTime === undefined + return Math.floor(date.getTime() / 1000); + } + } +} + +export class GenerateTimestamp extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'GenerateTimestamp'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const anchorTimestamp = new Date('2024-05-08'); + const twoYearsInMilliseconds = 2 * 31536000000; + + let date = new Date(); + let milliseconds: number; + + [milliseconds, this.state.rng] = prand.uniformIntDistribution( + -twoYearsInMilliseconds, + twoYearsInMilliseconds, + this.state.rng, + ); + date = new Date(date.setTime(anchorTimestamp.getTime() + milliseconds)); + + if (this.dataType === 'string') { + return date + .toISOString() + .replace('T', ' ') + .replace(/\.\d{3}Z/, ''); + } + + return date; + } +} + +export class GenerateDatetime extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'GenerateDatetime'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const anchorDate = new Date('2024-05-08'); + const twoYearsInMilliseconds = 2 * 31536000000; + + let date = new Date(); + let milliseconds: number; + + [milliseconds, this.state.rng] = prand.uniformIntDistribution( + -twoYearsInMilliseconds, + twoYearsInMilliseconds, + this.state.rng, + ); + date = new Date(date.setTime(anchorDate.getTime() + milliseconds)); + + if (this.dataType === 'string') { + return date + .toISOString() + .replace('T', ' ') + .replace(/\.\d{3}Z/, ''); + } + + return date; + } +} + +export class GenerateYear extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'GenerateYear'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const anchorDate = new Date('2024-05-08'); + const tenYears = 10; + + let date = new Date(); + let years: number; + + [years, this.state.rng] = prand.uniformIntDistribution(-tenYears, tenYears, this.state.rng); + date = new Date(date.setFullYear(anchorDate.getFullYear() + years)); + + return date + .toISOString() + .replace(/(-\d{2}-\d{2}T)|(\d{2}:\d{2}:\d{2}\.\d{3}Z)/g, ''); + } +} + +export class GenerateJson extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'GenerateJson'; + + private state: { + emailGeneratorObj: GenerateEmail; + nameGeneratorObj: GenerateFirstName; + booleanGeneratorObj: GenerateBoolean; + salaryGeneratorObj: GenerateInt; + dateGeneratorObj: GenerateDate; + visitedCountriesNumberGeneratorObj: GenerateInt; + seed: number; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const emailGeneratorObj = new GenerateEmail({}); + emailGeneratorObj.init({ count, seed }); + + const nameGeneratorObj = new GenerateFirstName({}); + nameGeneratorObj.init({ seed }); + + const booleanGeneratorObj = new GenerateBoolean({}); + booleanGeneratorObj.init({ + seed, + }); + + const salaryGeneratorObj = new GenerateInt({ minValue: 200, maxValue: 4000 }); + salaryGeneratorObj.init({ + count, + seed, + ...salaryGeneratorObj.params, + }); + + const dateGeneratorObj = new GenerateDate({}); + dateGeneratorObj.dataType = 'string'; + dateGeneratorObj.init({ seed }); + + const visitedCountriesNumberGeneratorObj = new GenerateInt({ minValue: 0, maxValue: 4 }); + visitedCountriesNumberGeneratorObj.init( + { count, seed, ...visitedCountriesNumberGeneratorObj.params }, + ); + + this.state = { + emailGeneratorObj, + nameGeneratorObj, + booleanGeneratorObj, + salaryGeneratorObj, + dateGeneratorObj, + visitedCountriesNumberGeneratorObj, + seed, + }; + } + + generate({ i }: { i: number }) { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const visitedCountries: string[] = []; + const email = this.state.emailGeneratorObj.generate(); + const name = this.state.nameGeneratorObj.generate(); + const isGraduated = this.state.booleanGeneratorObj.generate(); + const hasJob = this.state.booleanGeneratorObj.generate(); + const salary = this.state.salaryGeneratorObj.generate() as number; + const startedWorking = this.state.dateGeneratorObj.generate() as string; + const visitedCountriesNumber = this.state.visitedCountriesNumberGeneratorObj.generate() as number; + + const uniqueCountriesGeneratorObj = new GenerateUniqueCountry({}); + uniqueCountriesGeneratorObj.init({ + count: visitedCountriesNumber, + seed: this.state.seed + i, + }); + for (let j = 0; j < visitedCountriesNumber; j++) { + visitedCountries.push(uniqueCountriesGeneratorObj.generate()); + } + + const returnJson = hasJob + ? { + email, + name, + isGraduated, + hasJob, + salary, + startedWorking, + visitedCountries, + } + : { + email, + name, + isGraduated, + hasJob, + visitedCountries, + }; + + if (this.dataType === 'string') { + return JSON.stringify(returnJson); + } + + return returnJson; + } +} + +// export class GenerateJsonb extends AbstractGenerator<{}> { +// private state: { jsonGeneratorObj: GenerateJson } | undefined; + +// init({ count, seed }: { count: number, seed: number }) { +// const jsonGeneratorObj = new GenerateJson({}); +// jsonGeneratorObj.init({ count, seed }); + +// this.state = { jsonGeneratorObj }; +// } + +// generate({ i }: { i: number }) { +// if (this.state === undefined) { +// throw new Error("state is not defined."); +// } +// return this.state.jsonGeneratorObj.generate({ i }) +// // return JSON.parse(this.state.jsonGeneratorObj.generate({ i })); +// } + +export class GenerateEnum extends AbstractGenerator<{ enumValues: (string | number | boolean)[] }> { + static readonly [entityKind]: string = 'GenerateEnum'; + + private state: { + enumValuesGenerator: GenerateValuesFromArray; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const { enumValues } = this.params; + const enumValuesGenerator = new GenerateValuesFromArray({ values: enumValues }); + enumValuesGenerator.init({ count, seed }); + this.state = { enumValuesGenerator }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + // logic for this generator + return this.state.enumValuesGenerator.generate(); + } +} + +export class GenerateInterval extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateInterval'; + + private state: { rng: prand.RandomGenerator } | undefined; + override uniqueVersionOfGen = GenerateUniqueInterval; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let yearsNumb: number, + monthsNumb: number, + daysNumb: number, + hoursNumb: number, + minutesNumb: number, + secondsNumb: number; + + let interval = ''; + + [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); + [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); + + [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); + // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); + // daysNumb = randVal === 0 ? 0 : daysNumb; + + [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); + // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); + // hoursNumb = randVal === 0 ? 0 : hoursNumb; + + [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); + // minutesNumb = randVal === 0 ? 0 : minutesNumb; + + [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); + // secondsNumb = randVal === 0 ? 0 : secondsNumb; + + interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` + + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` + + `${daysNumb === 0 ? '' : `${daysNumb} days `}` + + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` + + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` + + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; + + return interval; + } +} + +export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateUniqueInterval'; + + private state: { + rng: prand.RandomGenerator; + intervalSet: Set; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const maxUniqueIntervalsNumber = 6 * 13 * 29 * 25 * 61 * 61; + if (count > maxUniqueIntervalsNumber) { + throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`); + } + + const rng = prand.xoroshiro128plus(seed); + const intervalSet = new Set(); + this.state = { rng, intervalSet }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let yearsNumb: number, + monthsNumb: number, + daysNumb: number, + hoursNumb: number, + minutesNumb: number, + secondsNumb: number; + + let interval = ''; + + for (;;) { + [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); + [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); + + [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); + // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); + // daysNumb = randVal === 0 ? 0 : daysNumb; + + [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); + // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); + // hoursNumb = randVal === 0 ? 0 : hoursNumb; + + [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); + // minutesNumb = randVal === 0 ? 0 : minutesNumb; + + [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); + // secondsNumb = randVal === 0 ? 0 : secondsNumb; + + interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` + + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` + + `${daysNumb === 0 ? '' : `${daysNumb} days `}` + + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` + + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` + + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; + + if (!this.state.intervalSet.has(interval)) { + this.state.intervalSet.add(interval); + break; + } + } + + return interval; + } +} + +export class GenerateString extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateString'; + + private state: { rng: prand.RandomGenerator } | undefined; + override uniqueVersionOfGen = GenerateUniqueString; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const minStringLength = 7; + const maxStringLength = 20; + const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let idx: number, + strLength: number, + currStr: string; + + currStr = ''; + [strLength, this.state.rng] = prand.uniformIntDistribution( + minStringLength, + maxStringLength, + this.state.rng, + ); + for (let j = 0; j < strLength; j++) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + stringChars.length - 1, + this.state.rng, + ); + currStr += stringChars[idx]; + } + return currStr; + } +} + +export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateUniqueString'; + + private state: { rng: prand.RandomGenerator } | undefined; + public override isUnique = true; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + this.state = { rng }; + } + + generate({ i }: { i: number }) { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const minStringLength = 7; + const maxStringLength = 20; + const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let idx: number, + strLength: number; + let currStr: string; + + currStr = ''; + const uniqueStr = i.toString(16); + [strLength, this.state.rng] = prand.uniformIntDistribution( + minStringLength, + maxStringLength - uniqueStr.length, + this.state.rng, + ); + for (let j = 0; j < strLength - uniqueStr.length; j++) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + stringChars.length - 1, + this.state.rng, + ); + currStr += stringChars[idx]; + } + + return currStr.slice(0, 4) + uniqueStr + currStr.slice(4); + } +} + +export class GenerateFirstName extends AbstractGenerator<{ + isUnique?: boolean; +}> { + static readonly [entityKind]: string = 'GenerateFirstName'; + + override timeSpent: number = 0; + private state: { + rng: prand.RandomGenerator; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueFirstName; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + // logic for this generator + // names dataset contains about 30000 unique names. + // TODO: generate names accordingly to max column length + let idx: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, firstNames.length - 1, this.state.rng); + return firstNames[idx] as string; + } +} + +export class GenerateUniqueFirstName extends AbstractGenerator<{ + isUnique?: boolean; +}> { + static readonly [entityKind]: string = 'GenerateUniqueFirstName'; + + private state: { + genIndicesObj: GenerateUniqueInt; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + // console.log("1-------", count, firstNames.length) + if (count > firstNames.length) { + throw new Error('count exceeds max number of unique first names.'); + } + // console.log("2-------") + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: firstNames.length - 1 }); + genIndicesObj.init({ count, seed }); + + this.state = { genIndicesObj }; + } + + generate() { + // names dataset contains about 30000 unique names. + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const nameIdx = this.state.genIndicesObj.generate() as number; + const name = firstNames[nameIdx] as string; + + return name; + } +} + +export class GenerateLastName extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateLastName'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueLastName; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, lastNames.length - 1, this.state.rng); + return lastNames[idx]; + } +} + +export class GenerateUniqueLastName extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateUniqueLastName'; + + private state: { + genIndicesObj: GenerateUniqueInt; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + if (count > lastNames.length) { + throw new Error('count exceeds max number of unique last names.'); + } + + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: lastNames.length - 1 }); + genIndicesObj.init({ count, seed }); + + this.state = { genIndicesObj }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const surnameIdx = this.state.genIndicesObj.generate() as number; + const surname = lastNames[surnameIdx] as string; + + return surname; + } +} + +export class GenerateFullName extends AbstractGenerator<{ + isUnique?: boolean; +}> { + static readonly [entityKind]: string = 'GenerateFullName'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueFullName; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, firstNames.length - 1, this.state.rng); + const name = firstNames[idx] as string; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, lastNames.length - 1, this.state.rng); + const surname = lastNames[idx] as string; + + const fullName = `${name} ${surname}`; + + return fullName; + } +} + +export class GenerateUniqueFullName extends AbstractGenerator<{ + isUnique?: boolean; +}> { + static readonly [entityKind]: string = 'GenerateUniqueFullName'; + + private state: { + fullnameSet: Set; + rng: prand.RandomGenerator; + } | undefined; + public override isUnique = true; + public override timeSpent = 0; + + init({ count, seed }: { count: number; seed: number }) { + const t0 = new Date(); + + const maxUniqueFullNamesNumber = firstNames.length * lastNames.length; + if (count > maxUniqueFullNamesNumber) { + throw new RangeError( + `count exceeds max number of unique full names(${maxUniqueFullNamesNumber}).`, + ); + } + const rng = prand.xoroshiro128plus(seed); + const fullnameSet = new Set(); + + this.state = { rng, fullnameSet }; + this.timeSpent += (Date.now() - t0.getTime()) / 1000; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let fullname: string, name: string, surname: string, idx: number; + + const t0 = new Date(); + for (;;) { + [idx, this.state.rng] = prand.uniformIntDistribution(0, firstNames.length - 1, this.state.rng); + name = firstNames[idx] as string; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, lastNames.length - 1, this.state.rng); + surname = lastNames[idx] as string; + + fullname = `${name} ${surname}`; + + if (!this.state.fullnameSet.has(fullname)) { + this.state.fullnameSet.add(fullname); + break; + } + } + + this.timeSpent += (Date.now() - t0.getTime()) / 1000; + return fullname; + } +} + +export class GenerateEmail extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'GenerateEmail'; + + private state: { + genIndicesObj: GenerateUniqueInt; + arraysToGenerateFrom: string[][]; + } | undefined; + public override timeSpent: number = 0; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + const domainsArray = emailDomains; + const adjectivesArray = adjectives; + const namesArray = firstNames; + + const maxUniqueEmailsNumber = adjectivesArray.length * namesArray.length * domainsArray.length; + if (count > maxUniqueEmailsNumber) { + throw new RangeError( + `count exceeds max number of unique emails(${maxUniqueEmailsNumber}).`, + ); + } + + const arraysToGenerateFrom = [adjectivesArray, namesArray, domainsArray]; + const genIndicesObj = new GenerateUniqueInt({ + minValue: 0, + maxValue: maxUniqueEmailsNumber - 1, + }); + genIndicesObj.init({ count, seed }); + + this.state = { genIndicesObj, arraysToGenerateFrom }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const t0 = new Date(); + const emailIndex = this.state.genIndicesObj.generate() as number; + this.timeSpent += (Date.now() - t0.getTime()) / 1000; + const tokens = fastCartesianProduct( + this.state.arraysToGenerateFrom, + emailIndex, + ) as string[]; + + const [adjective, name, domain] = [tokens[0] as string, tokens[1] as string, tokens[2] as string]; + + const email = `${adjective}_${name.toLowerCase()}@${domain}`; + + return email; + } +} + +export class GeneratePhoneNumber extends AbstractGenerator<{ + template?: string; + prefixes?: string[]; + generatedDigitsNumbers?: number | number[]; +}> { + static readonly [entityKind]: string = 'GeneratePhoneNumber'; + + private state: { + rng: prand.RandomGenerator; + placeholdersCount?: number; + prefixesArray: string[]; + generatedDigitsNumbers: number[]; + generatorsMap: Map; + phoneNumbersSet: Set; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + let { generatedDigitsNumbers } = this.params; + const { prefixes, template } = this.params; + + const rng = prand.xoroshiro128plus(seed); + + if (template !== undefined) { + const iterArray = [...template.matchAll(/#/g)]; + const placeholdersCount = iterArray.length; + + const maxUniquePhoneNumbersCount = Math.pow(10, placeholdersCount); + if (maxUniquePhoneNumbersCount < count) { + throw new RangeError( + `count exceeds max number of unique phone numbers(${maxUniquePhoneNumbersCount}).`, + ); + } + + const generatorsMap = new Map(); + const genObj = new GenerateUniqueInt({ minValue: 0, maxValue: maxUniquePhoneNumbersCount - 1 }); + genObj.init({ + count, + seed, + }); + + generatorsMap.set( + template, + genObj, + ); + + const prefixesArray: string[] = []; + const generatedDigitsNumbers: number[] = []; + const phoneNumbersSet = new Set(); + + this.state = { rng, placeholdersCount, generatorsMap, prefixesArray, generatedDigitsNumbers, phoneNumbersSet }; + return; + } + + let prefixesArray: string[]; + if (prefixes === undefined || prefixes.length === 0) { + prefixesArray = phonesInfo.map((phoneInfo) => phoneInfo.split(',').slice(0, -1).join(' ')); + generatedDigitsNumbers = phonesInfo.map((phoneInfo) => { + // tokens = ["380","99","9"] = + // = ["country prefix", "operator prefix", "number length including operator prefix and excluding country prefix"] + const tokens = phoneInfo.split(','); + const operatorPrefixLength = tokens[1]!.replaceAll(' ', '').length; + + return Number(tokens[2]) - operatorPrefixLength; + }); + } else { + prefixesArray = prefixes; + if (typeof generatedDigitsNumbers === 'number') { + generatedDigitsNumbers = Array.from({ length: prefixes.length }).fill( + generatedDigitsNumbers, + ); + } else if ( + generatedDigitsNumbers === undefined + || generatedDigitsNumbers.length === 0 + ) { + generatedDigitsNumbers = Array.from({ length: prefixes.length }).fill(7); + } + } + + if (new Set(prefixesArray).size !== prefixesArray.length) { + // prefixesArray.forEach(prefix => console.log(prefix)) + // console.log(prefixesArray.length - new Set(prefixesArray).size) + throw new Error('prefixes are not unique.'); + } + + const maxUniquePhoneNumbersCount = generatedDigitsNumbers.reduce( + (a, b) => a + Math.pow(10, b), + 0, + ); + if (maxUniquePhoneNumbersCount < count) { + throw new RangeError( + `count exceeds max number of unique phone numbers(${maxUniquePhoneNumbersCount}).`, + ); + } + + const generatorsMap = new Map(); + let maxValue: number, prefix: string, generatedDigitsNumber: number; + for (const [i, element] of prefixesArray.entries()) { + prefix = element as string; + generatedDigitsNumber = generatedDigitsNumbers[i] as number; + maxValue = Math.pow(10, generatedDigitsNumber) - 1; + + if (!generatorsMap.has(prefix)) { + const genObj = new GenerateUniqueInt({ minValue: 0, maxValue }); + genObj.init({ + count: Math.min(count, maxValue + 1), + seed, + }); + genObj.skipCheck = true; + generatorsMap.set( + prefix, + genObj, + ); + } + } + const phoneNumbersSet = new Set(); + + this.state = { rng, prefixesArray, generatedDigitsNumbers, generatorsMap, phoneNumbersSet }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let prefix: string, generatedDigitsNumber: number, numberBody: string, phoneNumber: string, idx: number; + + if (this.params.template === undefined) { + for (;;) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + this.state.prefixesArray.length - 1, + this.state.rng, + ); + prefix = this.state.prefixesArray[idx] as string; + generatedDigitsNumber = this.state.generatedDigitsNumbers[idx] as number; + + numberBody = String(this.state.generatorsMap.get(prefix)?.generate()); + if (numberBody === 'undefined') { + this.state.prefixesArray!.splice(idx, 1); + this.state.generatedDigitsNumbers.splice(idx, 1); + + this.state.generatorsMap.delete(prefix); + + continue; + } + + if (this.state.phoneNumbersSet.has(numberBody)) { + continue; + } + this.state.phoneNumbersSet.add(numberBody); + + break; + } + + const digitsNumberDiff = generatedDigitsNumber - numberBody.length; + if (digitsNumberDiff > 0) { + numberBody = '0'.repeat(digitsNumberDiff) + numberBody; + } + + phoneNumber = (prefix.includes('+') ? '' : '+') + prefix + '' + numberBody; + + return phoneNumber; + } else { + numberBody = String(this.state.generatorsMap.get(this.params.template)?.generate()); + phoneNumber = fillTemplate({ + template: this.params.template, + values: [...numberBody], + defaultValue: '0', + placeholdersCount: this.state.placeholdersCount, + }); + + return phoneNumber; + } + } +} + +export class GenerateCountry extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateCountry'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueCountry; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, countries.length - 1, this.state.rng); + const country = countries[idx] as string; + + return country; + } +} + +export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateUniqueCountry'; + + private state: { + genIndicesObj: GenerateUniqueInt; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + if (count > countries.length) { + throw new Error('count exceeds max number of unique countries.'); + } + + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: countries.length - 1 }); + genIndicesObj.init({ count, seed }); + + this.state = { genIndicesObj }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const countryIdx = this.state.genIndicesObj.generate() as number; + const country = countries[countryIdx] as string; + + return country; + } +} + +export class GenerateJobTitle extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'GenerateJobTitle'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + let idx; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, jobsTitles.length - 1, this.state.rng); + + return jobsTitles[idx]; + } +} + +export class GenerateStreetAdddress extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateStreetAdddress'; + + private state: { + rng: prand.RandomGenerator; + possStreetNames: string[][]; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueStreetAdddress; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + const possStreetNames = [firstNames, lastNames]; + this.state = { rng, possStreetNames }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx, streetBaseNameIdx, streetSuffixIdx, streetNumber; + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.possStreetNames.length - 1, this.state.rng); + + [streetBaseNameIdx, this.state.rng] = prand.uniformIntDistribution( + 0, + this.state.possStreetNames[idx]!.length - 1, + this.state.rng, + ); + [streetSuffixIdx, this.state.rng] = prand.uniformIntDistribution(0, streetSuffix.length - 1, this.state.rng); + const streetName = `${this.state.possStreetNames[idx]![streetBaseNameIdx]} ${streetSuffix[streetSuffixIdx]}`; + + [streetNumber, this.state.rng] = prand.uniformIntDistribution(1, 999, this.state.rng); + + return `${streetNumber} ${streetName}`; + } +} + +export class GenerateUniqueStreetAdddress extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateUniqueStreetAdddress'; + + private state: { + rng: prand.RandomGenerator; + possStreetNameObjs: { + indicesGen: GenerateUniqueInt; + maxUniqueStreetNamesNumber: number; + count: number; + arraysToChooseFrom: string[][]; + }[]; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const streetNumberStrs = Array.from({ length: 999 }, (_, i) => String(i + 1)); + const maxUniqueStreetnamesNumber = streetNumberStrs.length * firstNames.length * streetSuffix.length + + streetNumberStrs.length * firstNames.length * streetSuffix.length; + + if (count > maxUniqueStreetnamesNumber) { + throw new RangeError( + `count exceeds max number of unique street names(${maxUniqueStreetnamesNumber}).`, + ); + } + + const rng = prand.xoroshiro128plus(seed); + // ["1", "2", ..., "999"] + + const possStreetNameObjs = [ + { + indicesGen: new GenerateUniqueInt({ + minValue: 0, + maxValue: streetNumberStrs.length * firstNames.length * streetSuffix.length - 1, + }), + maxUniqueStreetNamesNumber: streetNumberStrs.length * firstNames.length * streetSuffix.length, + count: 0, + arraysToChooseFrom: [streetNumberStrs, firstNames, streetSuffix], + }, + { + indicesGen: new GenerateUniqueInt({ + minValue: 0, + maxValue: streetNumberStrs.length * lastNames.length * streetSuffix.length - 1, + }), + maxUniqueStreetNamesNumber: streetNumberStrs.length * firstNames.length * streetSuffix.length, + count: 0, + arraysToChooseFrom: [streetNumberStrs, lastNames, streetSuffix], + }, + ]; + + for (const possStreetNameObj of possStreetNameObjs) { + possStreetNameObj.indicesGen.skipCheck = true; + possStreetNameObj.indicesGen.init({ count, seed }); + } + + this.state = { rng, possStreetNameObjs }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let streetNameObjIdx; + [streetNameObjIdx, this.state.rng] = prand.uniformIntDistribution( + 0, + this.state.possStreetNameObjs.length - 1, + this.state.rng, + ); + const streetNameObj = this.state.possStreetNameObjs[streetNameObjIdx]!; + + const idx = streetNameObj.indicesGen.generate() as number; + const values = fastCartesianProduct(streetNameObj.arraysToChooseFrom, idx) as string[]; + + streetNameObj.count += 1; + if (streetNameObj.count === streetNameObj.maxUniqueStreetNamesNumber) { + this.state.possStreetNameObjs[streetNameObjIdx] = this.state + .possStreetNameObjs.at(-1)!; + this.state.possStreetNameObjs.pop(); + } + + const streetName = fillTemplate({ template: '# # #', values, placeholdersCount: 3 }); + + return streetName; + } +} + +export class GenerateCity extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateCity'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueCity; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx; + [idx, this.state.rng] = prand.uniformIntDistribution(0, cityNames.length - 1, this.state.rng); + + return cityNames[idx]; + } +} + +export class GenerateUniqueCity extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateUniqueCity'; + + private state: { + genIndicesObj: GenerateUniqueInt; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + if (count > cityNames.length) { + throw new Error('count exceeds max number of unique cities.'); + } + + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: cityNames.length - 1 }); + genIndicesObj.init({ count, seed }); + + this.state = { genIndicesObj }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const cityIdx = this.state.genIndicesObj.generate() as number; + const city = cityNames[cityIdx] as string; + + return city; + } +} + +export class GeneratePostcode extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GeneratePostcode'; + + private state: { + rng: prand.RandomGenerator; + templates: string[]; + } | undefined; + override uniqueVersionOfGen = GenerateUniquePostcode; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + const templates = ['#####', '#####-####']; + + this.state = { rng, templates }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number, postcodeNumber: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.templates.length - 1, this.state.rng); + const template = this.state.templates[idx]!; + + const iterArray = [...template.matchAll(/#/g)]; + const placeholdersCount = iterArray.length; + + [postcodeNumber, this.state.rng] = prand.uniformIntDistribution( + 0, + Math.pow(10, placeholdersCount) - 1, + this.state.rng, + ); + const postcode = fillTemplate({ + template, + placeholdersCount, + values: [...String(postcodeNumber)], + defaultValue: '0', + }); + + return postcode; + } +} + +export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateUniquePostcode'; + + private state: { + rng: prand.RandomGenerator; + templates: { + template: string; + indicesGen: GenerateUniqueInt; + placeholdersCount: number; + count: number; + maxUniquePostcodeNumber: number; + }[]; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const maxUniquePostcodeNumber = Math.pow(10, 5) + Math.pow(10, 9); + if (count > maxUniquePostcodeNumber) { + throw new RangeError( + `count exceeds max number of unique postcodes(${maxUniquePostcodeNumber}).`, + ); + } + + const rng = prand.xoroshiro128plus(seed); + const templates = [ + { + template: '#####', + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: Math.pow(10, 5) - 1 }), + placeholdersCount: 5, + count: 0, + maxUniquePostcodeNumber: Math.pow(10, 5), + }, + { + template: '#####-####', + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: Math.pow(10, 9) - 1 }), + placeholdersCount: 9, + count: 0, + maxUniquePostcodeNumber: Math.pow(10, 9), + }, + ]; + + for (const templateObj of templates) { + templateObj.indicesGen.skipCheck = true; + templateObj.indicesGen.init({ count, seed }); + } + + this.state = { rng, templates }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.templates.length - 1, this.state.rng); + const templateObj = this.state.templates[idx]!; + + const postcodeNumber = templateObj.indicesGen.generate() as number; + + templateObj.count += 1; + if (templateObj.count === templateObj.maxUniquePostcodeNumber) { + this.state.templates[idx] = this.state.templates.at(-1)!; + this.state.templates.pop(); + } + + const postcode = fillTemplate({ + template: templateObj.template, + placeholdersCount: templateObj.placeholdersCount, + values: [...String(postcodeNumber)], + defaultValue: '0', + }); + + return postcode; + } +} + +export class GenerateState extends AbstractGenerator<{}> { + static readonly [entityKind]: string = 'GenerateState'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx; + [idx, this.state.rng] = prand.uniformIntDistribution(0, states.length - 1, this.state.rng); + + return states[idx]; + } +} + +export class GenerateCompanyName extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateCompanyName'; + + private state: { + rng: prand.RandomGenerator; + templates: { template: string; placeholdersCount: number }[]; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueCompanyName; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + const templates = [ + { template: '#', placeholdersCount: 1 }, + { template: '# - #', placeholdersCount: 2 }, + { template: '# and #', placeholdersCount: 2 }, + { template: '#, # and #', placeholdersCount: 3 }, + ]; + + this.state = { rng, templates }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let templateIdx, idx, lastName, companyNameSuffix, companyName; + [templateIdx, this.state.rng] = prand.uniformIntDistribution(0, this.state.templates.length - 1, this.state.rng); + const templateObj = this.state.templates[templateIdx]!; + + if (templateObj.template === '#') { + [idx, this.state.rng] = prand.uniformIntDistribution(0, lastNames.length - 1, this.state.rng); + lastName = lastNames[idx]; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, companyNameSuffixes.length - 1, this.state.rng); + companyNameSuffix = companyNameSuffixes[idx]; + + companyName = `${lastName} ${companyNameSuffix}`; + return companyName; + } + + const values = []; + for (let i = 0; i < templateObj.placeholdersCount; i++) { + [idx, this.state.rng] = prand.uniformIntDistribution(0, lastNames.length - 1, this.state.rng); + values.push(lastNames[idx]!); + } + + companyName = fillTemplate({ + template: templateObj.template, + values, + placeholdersCount: templateObj.placeholdersCount, + }); + return companyName; + } +} + +export class GenerateUniqueCompanyName extends AbstractGenerator<{ isUnique?: boolean }> { + static readonly [entityKind]: string = 'GenerateUniqueCompanyName'; + + private state: { + rng: prand.RandomGenerator; + templates: { + template: string; + placeholdersCount: number; + indicesGen: GenerateUniqueInt; + maxUniqueCompanyNameNumber: number; + count: number; + arraysToChooseFrom: string[][]; + }[]; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const maxUniqueCompanyNameNumber = lastNames.length * companyNameSuffixes.length + Math.pow(lastNames.length, 2) + + Math.pow(lastNames.length, 2) + Math.pow(lastNames.length, 3); + if (count > maxUniqueCompanyNameNumber) { + throw new RangeError( + `count exceeds max number of unique company names(${maxUniqueCompanyNameNumber}).`, + ); + } + + const rng = prand.xoroshiro128plus(seed); + // when count reach maxUniqueCompanyNameNumber template will be deleted from array + const templates = [ + { + template: '# - #', + placeholdersCount: 1, + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: lastNames.length * companyNameSuffixes.length - 1 }), + maxUniqueCompanyNameNumber: lastNames.length * companyNameSuffixes.length, + count: 0, + arraysToChooseFrom: [lastNames, companyNameSuffixes], + }, + { + template: '# - #', + placeholdersCount: 2, + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: Math.pow(lastNames.length, 2) - 1 }), + maxUniqueCompanyNameNumber: Math.pow(lastNames.length, 2), + count: 0, + arraysToChooseFrom: [lastNames, lastNames], + }, + { + template: '# and #', + placeholdersCount: 2, + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: Math.pow(lastNames.length, 2) - 1 }), + maxUniqueCompanyNameNumber: Math.pow(lastNames.length, 2), + count: 0, + arraysToChooseFrom: [lastNames, lastNames], + }, + { + template: '#, # and #', + placeholdersCount: 3, + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: Math.pow(lastNames.length, 3) - 1 }), + maxUniqueCompanyNameNumber: Math.pow(lastNames.length, 3), + count: 0, + arraysToChooseFrom: [lastNames, lastNames, lastNames], + }, + ]; + + for (const templateObj of templates) { + templateObj.indicesGen.skipCheck = true; + templateObj.indicesGen.init({ count, seed }); + } + + this.state = { rng, templates }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let templateIdx; + [templateIdx, this.state.rng] = prand.uniformIntDistribution(0, this.state.templates.length - 1, this.state.rng); + const templateObj = this.state.templates[templateIdx]!; + + const idx = templateObj.indicesGen.generate() as number; + const values = fastCartesianProduct(templateObj.arraysToChooseFrom, idx) as string[]; + + templateObj.count += 1; + if (templateObj.count === templateObj.maxUniqueCompanyNameNumber) { + this.state.templates[templateIdx] = this.state.templates.at(-1)!; + this.state.templates.pop(); + } + + const companyName = fillTemplate({ + template: templateObj.template, + values, + placeholdersCount: templateObj.placeholdersCount, + }); + return companyName; + } +} + +export class GenerateLoremIpsum extends AbstractGenerator<{ sentencesCount?: number }> { + static readonly [entityKind]: string = 'GenerateLoremIpsum'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + if (this.params.sentencesCount === undefined) this.params.sentencesCount = 1; + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx, resultText: string = ''; + for (let i = 0; i < this.params.sentencesCount!; i++) { + [idx, this.state.rng] = prand.uniformIntDistribution(0, loremIpsumSentences.length - 1, this.state.rng); + resultText += loremIpsumSentences[idx] + ' '; + } + + return resultText; + } +} + +export class WeightedRandomGenerator extends AbstractGenerator<{ weight: number; value: AbstractGenerator }[]> { + static readonly [entityKind]: string = 'WeightedRandomGenerator'; + + private state: { + rng: prand.RandomGenerator; + weightedIndices: number[]; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const weights = this.params.map((weightedGen) => weightedGen.weight); + const weightedIndices = getWeightedIndices(weights); + + let idx: number, valueIdx: number, tempRng = prand.xoroshiro128plus(seed); + const indicesCounter: { [key: number]: number } = {}; + for (let i = 0; i < count; i++) { + [idx, tempRng] = prand.uniformIntDistribution(0, weightedIndices.length - 1, tempRng); + valueIdx = weightedIndices[idx]!; + if (!Object.hasOwn(indicesCounter, valueIdx)) indicesCounter[valueIdx] = 0; + indicesCounter[valueIdx]! += 1; + } + + for (const [idx, weightedGen] of this.params.entries()) { + weightedGen.value.isUnique = this.isUnique; + weightedGen.value.dataType = this.dataType; + weightedGen.value.init({ count: indicesCounter[idx]!, seed }); + + if ( + weightedGen.value.uniqueVersionOfGen !== undefined + && weightedGen.value.isUnique === true + ) { + const uniqueGen = new weightedGen.value.uniqueVersionOfGen({ + ...weightedGen.value.params, + }); + uniqueGen.init({ + count: indicesCounter[idx]!, + seed, + }); + uniqueGen.isUnique = weightedGen.value.isUnique; + uniqueGen.dataType = weightedGen.value.dataType; + + weightedGen.value = uniqueGen; + } + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { weightedIndices, rng }; + } + + generate({ i }: { i: number }) { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number; + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.weightedIndices.length - 1, this.state.rng); + const generatorIdx = this.state.weightedIndices[idx] as number; + const value = this.params[generatorIdx]!.value.generate({ i }); + + return value; + } +} + +export class GeneratePoint extends AbstractGenerator<{ + isUnique?: boolean; + minXValue?: number; + maxXValue?: number; + minYValue?: number; + maxYValue?: number; +}> { + static readonly [entityKind]: string = 'GeneratePoint'; + + private state: { + xCoordinateGen: GenerateNumber; + yCoordinateGen: GenerateNumber; + } | undefined; + override uniqueVersionOfGen = GenerateUniquePoint; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const xCoordinateGen = new GenerateNumber({ + minValue: this.params.minXValue, + maxValue: this.params.maxXValue, + precision: 10, + }); + xCoordinateGen.init({ seed }); + + const yCoordinateGen = new GenerateNumber({ + minValue: this.params.minYValue, + maxValue: this.params.maxYValue, + precision: 10, + }); + yCoordinateGen.init({ seed }); + + this.state = { xCoordinateGen, yCoordinateGen }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const x = this.state.xCoordinateGen.generate(); + const y = this.state.yCoordinateGen.generate(); + + if (this.dataType === 'json') { + return { x, y }; + } else if (this.dataType === 'string') { + return `[${x}, ${y}]`; + } else { + // if (this.dataType === "array") + return [x, y]; + } + } +} + +export class GenerateUniquePoint extends AbstractGenerator<{ + minXValue?: number; + maxXValue?: number; + minYValue?: number; + maxYValue?: number; + isUnique?: boolean; +}> { + static readonly [entityKind]: string = 'GenerateUniquePoint'; + + private state: { + xCoordinateGen: GenerateUniqueNumber; + yCoordinateGen: GenerateUniqueNumber; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const xCoordinateGen = new GenerateUniqueNumber({ + minValue: this.params.minXValue, + maxValue: this.params.maxXValue, + precision: 10, + }); + xCoordinateGen.init({ count, seed }); + + const yCoordinateGen = new GenerateUniqueNumber({ + minValue: this.params.minYValue, + maxValue: this.params.maxYValue, + precision: 10, + }); + yCoordinateGen.init({ count, seed }); + + this.state = { xCoordinateGen, yCoordinateGen }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const x = this.state.xCoordinateGen.generate(); + const y = this.state.yCoordinateGen.generate(); + + if (this.dataType === 'json') { + return { x, y }; + } else if (this.dataType === 'string') { + return `[${x}, ${y}]`; + } else { + // if (this.dataType === "array") + return [x, y]; + } + } +} + +export class GenerateLine extends AbstractGenerator<{ + isUnique?: boolean; + minAValue?: number; + maxAValue?: number; + minBValue?: number; + maxBValue?: number; + minCValue?: number; + maxCValue?: number; +}> { + static readonly [entityKind]: string = 'GenerateLine'; + + private state: { + aCoefficientGen: GenerateNumber; + bCoefficientGen: GenerateNumber; + cCoefficientGen: GenerateNumber; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueLine; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const aCoefficientGen = new GenerateNumber({ + minValue: this.params.minAValue, + maxValue: this.params.maxAValue, + precision: 10, + }); + aCoefficientGen.init({ seed }); + + const bCoefficientGen = new GenerateNumber({ + minValue: this.params.minBValue, + maxValue: this.params.maxBValue, + precision: 10, + }); + bCoefficientGen.init({ seed }); + + const cCoefficientGen = new GenerateNumber({ + minValue: this.params.minCValue, + maxValue: this.params.maxCValue, + precision: 10, + }); + cCoefficientGen.init({ seed }); + + this.state = { aCoefficientGen, bCoefficientGen, cCoefficientGen }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let b: number; + const a = this.state.aCoefficientGen.generate(); + + b = this.state.bCoefficientGen.generate(); + while (a === 0 && b === 0) { + b = this.state.bCoefficientGen.generate(); + } + + const c = this.state.cCoefficientGen.generate(); + + if (this.dataType === 'json') { + return { a, b, c }; + } else if (this.dataType === 'string') { + return `[${a}, ${b}, ${c}]`; + } else { + // if (this.dataType === "array") + return [a, b, c]; + } + } +} + +export class GenerateUniqueLine extends AbstractGenerator<{ + minAValue?: number; + maxAValue?: number; + minBValue?: number; + maxBValue?: number; + minCValue?: number; + maxCValue?: number; + isUnique?: boolean; +}> { + static readonly [entityKind]: string = 'GenerateUniqueLine'; + + private state: { + aCoefficientGen: GenerateUniqueNumber; + bCoefficientGen: GenerateUniqueNumber; + cCoefficientGen: GenerateUniqueNumber; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const aCoefficientGen = new GenerateUniqueNumber({ + minValue: this.params.minAValue, + maxValue: this.params.maxAValue, + precision: 10, + }); + aCoefficientGen.init({ count, seed }); + + const bCoefficientGen = new GenerateUniqueNumber({ + minValue: this.params.minBValue, + maxValue: this.params.maxBValue, + precision: 10, + }); + bCoefficientGen.init({ count, seed }); + + const cCoefficientGen = new GenerateUniqueNumber({ + minValue: this.params.minCValue, + maxValue: this.params.maxCValue, + precision: 10, + }); + cCoefficientGen.init({ count, seed }); + + this.state = { aCoefficientGen, bCoefficientGen, cCoefficientGen }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let b: number; + const a = this.state.aCoefficientGen.generate(); + + b = this.state.bCoefficientGen.generate(); + while (a === 0 && b === 0) { + b = this.state.bCoefficientGen.generate(); + } + + const c = this.state.cCoefficientGen.generate(); + + if (this.dataType === 'json') { + return { a, b, c }; + } else if (this.dataType === 'string') { + return `[${a}, ${b}, ${c}]`; + } else { + // if (this.dataType === "array") + return [a, b, c]; + } + } +} + +export const generatorsFuncs = { + /** + * generates same given value each time the generator is called. + * @param defaultValue - value you want to generate + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.default({ defaultValue: "post content" }), + * }, + * }, + * })); + * ``` + */ + default: createGenerator(GenerateDefault), + + /** + * generates values from given array + * @param values - array of values you want to generate. can be array of weighted values. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * title: funcs.valuesFromArray({ + * values: ["Title1", "Title2", "Title3", "Title4", "Title5"], + * isUnique: true + * }), + * }, + * }, + * })); + * + * ``` + * weighted values example + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * title: funcs.valuesFromArray({ + * values: [ + * { weight: 0.35, values: ["Title1", "Title2"] }, + * { weight: 0.5, values: ["Title3", "Title4"] }, + * { weight: 0.15, values: ["Title5"] }, + * ], + * isUnique: false + * }), + * }, + * }, + * })); + * + * ``` + */ + valuesFromArray: createGenerator(GenerateValuesFromArray), + + /** + * generates sequential integers starting with 1. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * id: funcs.intPrimaryKey(), + * }, + * }, + * })); + * + * ``` + */ + intPrimaryKey: createGenerator(GenerateIntPrimaryKey), + + /** + * generates numbers with floating point in given range. + * @param minValue - lower border of range. + * @param maxValue - upper border of range. + * @param precision - precision of generated number: + * precision equals 10 means that values will be accurate to one tenth (1.2, 34.6); + * precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67). + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * products: { + * columns: { + * unitPrice: funcs.number({ minValue: 10, maxValue: 120, precision: 100, isUnique: false }), + * }, + * }, + * })); + * + * ``` + */ + number: createGenerator(GenerateNumber), + // uniqueNumber: createGenerator(GenerateUniqueNumber), + + /** + * generates integers within given range. + * @param minValue - lower border of range. + * @param maxValue - upper border of range. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * products: { + * columns: { + * unitsInStock: funcs.number({ minValue: 0, maxValue: 100, isUnique: false }), + * }, + * }, + * })); + * + * ``` + */ + int: createGenerator(GenerateInt), + // uniqueInt: createGenerator(GenerateUniqueInt), + + /** + * generates boolean values(true or false) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * isAvailable: funcs.boolean() + * }, + * }, + * })); + * + * ``` + */ + boolean: createGenerator(GenerateBoolean), + + /** + * generates date within given range. + * @param minDate - lower border of range. + * @param maxDate - upper border of range. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthDate: funcs.date({ minDate: "1990-01-01", maxDate: "2010-12-31" }) + * }, + * }, + * })); + * + * ``` + */ + date: createGenerator(GenerateDate), + + /** + * generates time in 24 hours style. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthTime: funcs.time() + * }, + * }, + * })); + * + * ``` + */ + time: createGenerator(GenerateTime), + + /** + * generates timestamps. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * orders: { + * columns: { + * shippedDate: funcs.timestamp() + * }, + * }, + * })); + * + * ``` + */ + timestamp: createGenerator(GenerateTimestamp), + + /** + * generates datetime objects. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * orders: { + * columns: { + * shippedDate: funcs.datetime() + * }, + * }, + * })); + * + * ``` + */ + datetime: createGenerator(GenerateDatetime), + + /** + * generates years. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthYear: funcs.year() + * }, + * }, + * })); + * + * ``` + */ + year: createGenerator(GenerateYear), + + /** + * generates json objects with fixed structure. + * + * json structure can equal this: + * ``` + * { + * email, + * name, + * isGraduated, + * hasJob, + * salary, + * startedWorking, + * visitedCountries, + * } + * ``` + * or this + * ``` + * { + * email, + * name, + * isGraduated, + * hasJob, + * visitedCountries, + * } + * ``` + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * metadata: funcs.json() + * }, + * }, + * })); + * ``` + */ + json: createGenerator(GenerateJson), + // jsonb: createGenerator(GenerateJsonb), + + /** + * generates time intervals. + * + * interval example: "1 years 12 days 5 minutes" + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * timeSpentOnWebsite: funcs.interval() + * }, + * }, + * })); + * ``` + */ + interval: createGenerator(GenerateInterval), + // uniqueInterval: createGenerator(GenerateUniqueInterval), + + /** + * generates random strings. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * hashedPassword: funcs.string({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + string: createGenerator(GenerateString), + // uniqueString: createGenerator(GenerateUniqueString), + + /** + * generates person's first names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * firstName: funcs.firstName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + firstName: createGenerator(GenerateFirstName), + // uniqueFirstName: createGenerator(GenerateUniqueName), + + /** + * generates person's last names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * lastName: funcs.lastName({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + lastName: createGenerator(GenerateLastName), + // uniqueLastName: createGenerator(GenerateUniqueSurname), + + /** + * generates person's full names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * fullName: funcs.fullName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + fullName: createGenerator(GenerateFullName), + // uniqueFullName: createGenerator(GenerateUniqueFullName), + + /** + * generates unique emails. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * email: funcs.email() + * }, + * }, + * })); + * ``` + */ + email: createGenerator(GenerateEmail), + + /** + * generates unique phone numbers. + * + * @param template - phone number template, where all '#' symbols will be substituted with generated digits. + * @param prefixes - array of any string you want to be your phone number prefixes.(not compatible with template property) + * @param generatedDigitsNumbers - number of digits that will be added at the end of prefixes.(not compatible with template property) + * @example + * ```ts + * //generate phone number using template property + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({template: "+(380) ###-####"}) + * }, + * }, + * })); + * + * //generate phone number using prefixes and generatedDigitsNumbers properties + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67" ], generatedDigitsNumbers: 7}) + * }, + * }, + * })); + * + * //generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67", "+1" ], generatedDigitsNumbers: [7, 7, 10]}) + * }, + * }, + * })); + * + * ``` + */ + phoneNumber: createGenerator(GeneratePhoneNumber), + + /** + * generates country's names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * country: funcs.country({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + country: createGenerator(GenerateCountry), + // uniqueCountry: createGenerator(GenerateUniqueCountry), + + /** + * generates city's names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * city: funcs.cityName({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + city: createGenerator(GenerateCity), + // uniqueCity: createGenerator(GenerateUniqueCityName), + + /** + * generates street address. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * streetAddress: funcs.streetAddress({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + streetAddress: createGenerator(GenerateStreetAdddress), + // uniqueStreetAddress: createGenerator(GenerateUniqueStreetAdddress), + + /** + * generates job titles. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * jobTitle: funcs.jobTitle() + * }, + * }, + * })); + * ``` + */ + jobTitle: createGenerator(GenerateJobTitle), + + /** + * generates postal codes. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * postcode: funcs.postcode({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + postcode: createGenerator(GeneratePostcode), + // uniquePostcoe: createGenerator(GenerateUniquePostcode), + + /** + * generates states of America. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * state: funcs.state() + * }, + * }, + * })); + * ``` + */ + state: createGenerator(GenerateState), + + /** + * generates company's names. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * company: funcs.companyName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + companyName: createGenerator(GenerateCompanyName), + // uniqueCompanyName: createGenerator(GenerateUniqueCompanyName), + + /** + * generates 'lorem ipsum' text sentences. + * + * @param sentencesCount - number of sentences you want to generate as one generated value(string). + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.loremIpsum({sentencesCount: 2}) + * }, + * }, + * })); + * ``` + */ + loremIpsum: createGenerator(GenerateLoremIpsum), + + /** + * generates 2D points within specified ranges for x and y coordinates. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param minXValue - lower bound of range for x coordinate. + * @param maxXValue - upper bound of range for x coordinate. + * @param minYValue - lower bound of range for y coordinate. + * @param maxYValue - upper bound of range for y coordinate. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * triangles: { + * columns: { + * pointCoords: funcs.point({ + * isUnique: true, + * minXValue: -5, maxXValue:20, + * minYValue: 0, maxYValue: 30 + * }) + * }, + * }, + * })); + * ``` + */ + point: createGenerator(GeneratePoint), + // uniquePoint: createGenerator(GenerateUniquePoint), + + /** + * generates 2D lines within specified ranges for a, b and c parameters of line. + * + * ``` + * line equation: a*x + b*y + c = 0 + * ``` + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param minAValue - lower bound of range for a parameter. + * @param maxAValue - upper bound of range for x parameter. + * @param minBValue - lower bound of range for y parameter. + * @param maxBValue - upper bound of range for y parameter. + * @param minCValue - lower bound of range for y parameter. + * @param maxCValue - upper bound of range for y parameter. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * lines: { + * columns: { + * lineParams: funcs.point({ + * isUnique: true, + * minAValue: -5, maxAValue:20, + * minBValue: 0, maxBValue: 30, + * minCValue: 0, maxCValue: 10 + * }) + * }, + * }, + * })); + * ``` + */ + line: createGenerator(GenerateLine), + // uniqueLine: createGenerator(GenerateUniqueLine), + + /** + * gives you the opportunity to call different generators with different probabilities to generate values for one column. + * @param params - array of generators with probabilities you would like to call them to generate values. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.weightedRandom([ + * { + * weight: 0.6, + * value: funcs.loremIpsum({ sentencesCount: 3 }), + * }, + * { + * weight: 0.4, + * value: funcs.default({ defaultValue: "TODO" }), + * }, + * ]), + * }, + * }, + * })); + * ``` + */ + weightedRandom: createGenerator(WeightedRandomGenerator), +}; diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts new file mode 100644 index 000000000..fd78b647a --- /dev/null +++ b/drizzle-seed/src/services/SeedService.ts @@ -0,0 +1,1223 @@ +import { entityKind, is } from 'drizzle-orm'; +import type { MySqlTable } from 'drizzle-orm/mysql-core'; +import { MySqlDatabase } from 'drizzle-orm/mysql-core'; +import type { PgTable } from 'drizzle-orm/pg-core'; +import { PgDatabase } from 'drizzle-orm/pg-core'; +import type { SQLiteTable } from 'drizzle-orm/sqlite-core'; +import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core'; +import type { + GeneratePossibleGeneratorsColumnType, + GeneratePossibleGeneratorsTableType, + RefinementsType, + TableGeneratorsType, +} from '../types/seedService.ts'; +import type { Column, Prettify, Relation, Table } from '../types/tables.ts'; +import type { AbstractGenerator } from './GeneratorsWrappers.ts'; +import { + GenerateBoolean, + GenerateDate, + GenerateDatetime, + GenerateDefault, + GenerateEmail, + GenerateEnum, + GenerateFirstName, + GenerateInt, + GenerateInterval, + GenerateIntPrimaryKey, + GenerateJson, + GenerateLine, + GenerateNumber, + GeneratePoint, + GenerateSelfRelationsValuesFromArray, + GenerateString, + GenerateTime, + GenerateTimestamp, + GenerateUniqueString, + GenerateValuesFromArray, + GenerateWeightedCount, + GenerateYear, + HollowGenerator, +} from './GeneratorsWrappers.ts'; +import { generateHashFromString } from './utils.ts'; + +class SeedService { + static readonly [entityKind]: string = 'SeedService'; + + private defaultCountForTable = 10; + private postgresMaxParametersNumber = 65535; + // there is no max parameters number in mysql, so you can increase mysqlMaxParametersNumber if it's needed. + private mysqlMaxParametersNumber = 100000; + // SQLITE_MAX_VARIABLE_NUMBER, which by default equals to 999 for SQLite versions prior to 3.32.0 (2020-05-22) or 32766 for SQLite versions after 3.32.0. + private sqliteMaxParametersNumber = 32766; + + generatePossibleGenerators = ( + connectionType: 'postgresql' | 'mysql' | 'sqlite', + tables: Table[], + relations: Relation[], + refinements?: RefinementsType, + options?: { count?: number; seed?: number }, + ) => { + let columnPossibleGenerator: Prettify; + let tablePossibleGenerators: Prettify; + const customSeed = options?.seed === undefined ? 0 : options.seed; + + // console.log("relations:", relations); + // sorting table in order which they will be filled up (tables with foreign keys case) + // relations = relations.filter(rel => rel.type === "one"); + const orderedTablesNames = this.getOrderedTablesList(relations); + tables = tables.sort((tabel1, tabel2) => { + const tabel1Order = orderedTablesNames.indexOf( + tabel1.name, + ), + tabel2Order = orderedTablesNames.indexOf( + tabel2.name, + ); + return tabel1Order - tabel2Order; + }); + + const tablesPossibleGenerators: Prettify< + (typeof tablePossibleGenerators)[] + > = tables.map((table) => ({ + tableName: table.name, + columnsPossibleGenerators: [], + withFromTable: {}, + })); + + for (const [i, table] of tables.entries()) { + // get foreignKey columns relations + const foreignKeyColumns: { + [columnName: string]: { table: string; column: string }; + } = {}; + + for ( + const rel of relations + .filter((rel) => rel.table === table.name) + ) { + for (const [idx, col] of rel.columns.entries()) { + foreignKeyColumns[col] = { + table: rel.refTable, + column: rel.refColumns[idx] as string, + }; + } + } + + // console.time("generatePossibleGenerators_refinements section"); + // console.log(refinements) + if (refinements !== undefined && refinements[table.name] !== undefined) { + if (refinements[table.name]!.count !== undefined) { + tablesPossibleGenerators[i]!.count = refinements[table.name]!.count; + } + + if (refinements[table.name]!.with !== undefined) { + tablesPossibleGenerators[i]!.count = refinements[table.name]!.count + || options?.count + || this.defaultCountForTable; + let idx: number; + for ( + const fkTableName of Object.keys( + refinements[table.name]!.with as {}, + ) + ) { + idx = tablesPossibleGenerators.findIndex( + (table) => table.tableName === fkTableName, + ); + if (idx !== -1) { + let newTableWithCount: number, + weightedCountSeed: number | undefined; + if ( + typeof refinements![table.name]!.with![fkTableName] === 'number' + ) { + newTableWithCount = (tablesPossibleGenerators[i]!.withCount + || tablesPossibleGenerators[i]!.count)! + * (refinements[table.name]!.with![fkTableName] as number); + } else { + const weightedRepeatedValuesCount = refinements[table.name]! + .with![fkTableName] as { + weight: number; + count: number | number[]; + }[]; + + weightedCountSeed = customSeed + + generateHashFromString(`${table.name}.${fkTableName}`); + // const repeatedValuesCount = this.getCountFromWeightedCount(weightedRepeatedValuesCount, seed); + + // refinements![table.name].with![fkTableName] = repeatedValuesCount; + // console.time("getWeightedWithCount") + newTableWithCount = this.getWeightedWithCount( + weightedRepeatedValuesCount, + (tablesPossibleGenerators[i]!.withCount + || tablesPossibleGenerators[i]!.count)!, + weightedCountSeed, + ); + // console.timeEnd("getWeightedWithCount") + // console.log("newTableWithCount:", newTableWithCount) + } + + if ( + tablesPossibleGenerators[idx]!.withCount === undefined + || newTableWithCount > tablesPossibleGenerators[idx]!.withCount! + ) { + tablesPossibleGenerators[idx]!.withCount = newTableWithCount; + } + + tablesPossibleGenerators[idx]!.withFromTable[table.name] = { + repeatedValuesCount: refinements[table.name]!.with![fkTableName]!, + weightedCountSeed, + }; + + // tablesPossibleGenerators[idx].withFromTableName = table.name; + } + } + } + } + // console.timeEnd("generatePossibleGenerators_refinements section"); + // console.time("generatePossibleGenerators_generatorPick section"); + tablePossibleGenerators = tablesPossibleGenerators[i]!; + for (const col of table.columns) { + // col.myType = typeMap[col._type as keyof typeof typeMap]; + columnPossibleGenerator = { + columnName: col.name, + isUnique: col.isUnique, + notNull: col.notNull, + generator: undefined, + }; + + if ( + refinements !== undefined + && refinements[table.name] !== undefined + && refinements[table.name]!.columns !== undefined + && refinements[table.name]!.columns[col.name] !== undefined + ) { + const genObj = refinements[table.name]!.columns[col.name]!; + // if (genObj instanceof GenerateValuesFromArray) + // for now only GenerateValuesFromArray support notNull property + genObj.notNull = col.notNull; + + columnPossibleGenerator.generator = genObj; + } else if (Object.hasOwn(foreignKeyColumns, col.name)) { + // TODO: I might need to assign repeatedValuesCount to column there instead of doing so in generateTablesValues + columnPossibleGenerator.generator = new HollowGenerator({}); + } else if (col.hasDefault && col.default !== undefined) { + columnPossibleGenerator.generator = new GenerateDefault({ + defaultValue: col.default, + }); + } // TODO: rewrite pickGeneratorFor... using new col properties: isUnique and notNull + else if (connectionType === 'postgresql') { + columnPossibleGenerator = this.pickGeneratorForPostgresColumn( + columnPossibleGenerator, + table, + col, + ); + } else if (connectionType === 'mysql') { + columnPossibleGenerator = this.pickGeneratorForMysqlColumn( + columnPossibleGenerator, + table, + col, + ); + } else if (connectionType === 'sqlite') { + columnPossibleGenerator = this.pickGeneratorForSqlite( + columnPossibleGenerator, + table, + col, + ); + } + + if (columnPossibleGenerator.generator === undefined) { + // console.log("column:", col); + throw new Error( + `column with type ${col.columnType} is not supported for now.`, + ); + } + + columnPossibleGenerator.generator.isUnique = col.isUnique; + columnPossibleGenerator.generator.dataType = col.dataType; + tablePossibleGenerators.columnsPossibleGenerators.push( + columnPossibleGenerator, + ); + // console.log("column:", col, columnPossibleGenerator.generator) + } + // console.timeEnd("generatePossibleGenerators_generatorPick section"); + } + + // console.timeEnd("generatePossibleGenerators"); + return tablesPossibleGenerators; + }; + + getOrderedTablesList = (relations: Relation[]): string[] => { + // console.time("getOrderedTablesList"); + const tablesInOutRelations = this.getTablesInOutRelations(relations); + + const leafTablesNames = Object.entries(tablesInOutRelations) + .filter( + (tableRel) => + tableRel[1].out === 0 + || (tableRel[1].out !== 0 + && tableRel[1].selfRelCount === tableRel[1].out), + ) + .map((tableRel) => tableRel[0]); + + // console.log("leafTablesNames", leafTablesNames); + const orderedTablesNames: string[] = []; + // BFS + let parent: string, children: string[]; + for (let i = 0; leafTablesNames.length !== 0; i++) { + // console.log(i); + // console.log("leafTablesNames", leafTablesNames); + // console.log("orderedTablesNames", orderedTablesNames); + parent = leafTablesNames.shift() as string; + + // console.log(parent, tablesInOutRelations[parent].requiredTableNames) + + if (orderedTablesNames.includes(parent)) { + continue; + } + + if (tablesInOutRelations[parent] === undefined) { + orderedTablesNames.push(parent); + continue; + } + + tablesInOutRelations[parent]!.requiredTableNames = new Set( + [...tablesInOutRelations[parent]!.requiredTableNames.values()].filter( + (tableName) => !orderedTablesNames.includes(tableName), + ), + ); + + if (tablesInOutRelations[parent]!.requiredTableNames.size === 0) { + orderedTablesNames.push(parent); + } else { + leafTablesNames.push(parent); + continue; + } + + // children = relations + // .filter((rel) => rel.refTable === parent) + // .map((rel) => rel.table) + // .filter((child) => child !== parent); + + children = [...tablesInOutRelations[parent]!.dependantTableNames]; + // console.log("children", children); + // console.log("children1", tablesInOutRelations[parent].dependantTableNames); + leafTablesNames.push(...children); + } + // console.log("orderedTablesNames", orderedTablesNames); + // console.timeEnd("getOrderedTablesList"); + return orderedTablesNames; + }; + + getTablesInOutRelations = (relations: Relation[]) => { + const tablesInOutRelations: { + [tableName: string]: { + out: number; + in: number; + selfRelation: boolean; + selfRelCount: number; + requiredTableNames: Set; + dependantTableNames: Set; + }; + } = {}; + + for (const rel of relations) { + if (tablesInOutRelations[rel.table] === undefined) { + tablesInOutRelations[rel.table] = { + out: 0, + in: 0, + selfRelation: false, + selfRelCount: 0, + requiredTableNames: new Set(), + dependantTableNames: new Set(), + }; + } + + if (tablesInOutRelations[rel.refTable] === undefined) { + tablesInOutRelations[rel.refTable] = { + out: 0, + in: 0, + selfRelation: false, + selfRelCount: 0, + requiredTableNames: new Set(), + dependantTableNames: new Set(), + }; + } + + tablesInOutRelations[rel.table]!.out += 1; + tablesInOutRelations[rel.refTable]!.in += 1; + + if (rel.refTable === rel.table) { + tablesInOutRelations[rel.table]!.selfRelation = true; + tablesInOutRelations[rel.table]!.selfRelCount = rel.columns.length; + } else { + tablesInOutRelations[rel.table]!.requiredTableNames.add(rel.refTable); + tablesInOutRelations[rel.refTable]!.dependantTableNames.add(rel.table); + } + } + + return tablesInOutRelations; + }; + + getWeightedWithCount = ( + weightedCount: { weight: number; count: number | number[] }[], + count: number, + seed: number, + ) => { + // const gen = (new GenerateWeightedCount({})).execute({ weightedCount, count, seed }); + const gen = new GenerateWeightedCount({}); + gen.init({ count: weightedCount, seed }); + let weightedWithCount = 0; + for (let i = 0; i < count; i++) { + weightedWithCount += gen.generate(); + } + // gen.return(); + + return weightedWithCount; + }; + + // TODO: revise serial part generators + pickGeneratorForPostgresColumn = ( + columnPossibleGenerator: Prettify, + table: Table, + col: Column, + ) => { + // INT ------------------------------------------------------------------------------------------------------------ + if ( + (col.columnType.includes('serial') + || col.columnType === 'integer' + || col.columnType === 'smallint' + || col.columnType.includes('bigint')) + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateIntPrimaryKey({}); + return columnPossibleGenerator; + } + + let minValue: number | bigint | undefined; + let maxValue: number | bigint | undefined; + if (col.columnType.includes('serial')) { + minValue = 1; + if (col.columnType === 'smallserial') { + // 2^16 / 2 - 1, 2 bytes + maxValue = 32767; + } else if (col.columnType === 'serial') { + // 2^32 / 2 - 1, 4 bytes + maxValue = 2147483647; + } else if (col.columnType === 'bigserial') { + // 2^64 / 2 - 1, 8 bytes + minValue = BigInt(1); + maxValue = BigInt('9223372036854775807'); + } + } else if (col.columnType.includes('int')) { + if (col.columnType === 'smallint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -32768; + maxValue = 32767; + } else if (col.columnType === 'integer') { + // 2^32 / 2 - 1, 4 bytes + minValue = -2147483648; + maxValue = 2147483647; + } else if (col.columnType.includes('bigint')) { + if (col.dataType === 'bigint') { + // 2^64 / 2 - 1, 8 bytes + minValue = BigInt('-9223372036854775808'); + maxValue = BigInt('9223372036854775807'); + } else if (col.dataType === 'number') { + // if you’re expecting values above 2^31 but below 2^53 + minValue = -9007199254740991; + maxValue = 9007199254740991; + } + } + } + + if ( + col.columnType.includes('int') + && !col.columnType.includes('interval') + && !col.columnType.includes('point') + ) { + columnPossibleGenerator.generator = new GenerateInt({ + minValue, + maxValue, + }); + return columnPossibleGenerator; + } + + if (col.columnType.includes('serial')) { + const genObj = new GenerateIntPrimaryKey({}); + genObj.maxValue = maxValue; + columnPossibleGenerator.generator = genObj; + } + + // NUMBER(real, double, decimal, numeric) + if ( + col.columnType === 'real' + || col.columnType === 'doubleprecision' + || col.columnType === 'decimal' + || col.columnType === 'numeric' + ) { + columnPossibleGenerator.generator = new GenerateNumber({}); + return columnPossibleGenerator; + } + + // STRING + if ( + (col.columnType === 'text' + || col.columnType === 'varchar' + || col.columnType === 'char') + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateUniqueString({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'varchar' + || col.columnType === 'char') + && col.name.toLowerCase().includes('name') + ) { + columnPossibleGenerator.generator = new GenerateFirstName({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'varchar' + || col.columnType === 'char') + && col.name.toLowerCase().includes('email') + ) { + columnPossibleGenerator.generator = new GenerateEmail({}); + return columnPossibleGenerator; + } + + if ( + col.columnType === 'text' + || col.columnType === 'varchar' + || col.columnType === 'char' + ) { + // console.log(col, table) + columnPossibleGenerator.generator = new GenerateString({}); + return columnPossibleGenerator; + } + + // BOOLEAN + if (col.columnType === 'boolean') { + columnPossibleGenerator.generator = new GenerateBoolean({}); + return columnPossibleGenerator; + } + + // DATE, TIME, TIMESTAMP + if (col.columnType.includes('date')) { + columnPossibleGenerator.generator = new GenerateDate({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'time') { + columnPossibleGenerator.generator = new GenerateTime({}); + return columnPossibleGenerator; + } + + if (col.columnType.includes('timestamp')) { + columnPossibleGenerator.generator = new GenerateTimestamp({}); + return columnPossibleGenerator; + } + + // JSON, JSONB + if (col.columnType === 'json' || col.columnType === 'jsonb') { + columnPossibleGenerator.generator = new GenerateJson({}); + return columnPossibleGenerator; + } + + // if (col.columnType === "jsonb") { + // columnPossibleGenerator.generator = new GenerateJsonb({}); + // return columnPossibleGenerator; + // } + + // ENUM + if (col.enumValues !== undefined) { + columnPossibleGenerator.generator = new GenerateEnum({ + enumValues: col.enumValues, + }); + return columnPossibleGenerator; + } + + // INTERVAL + if (col.columnType === 'interval') { + columnPossibleGenerator.generator = new GenerateInterval({}); + return columnPossibleGenerator; + } + + // POINT, LINE + if (col.columnType.includes('point')) { + columnPossibleGenerator.generator = new GeneratePoint({}); + return columnPossibleGenerator; + } + + if (col.columnType.includes('line')) { + columnPossibleGenerator.generator = new GenerateLine({}); + return columnPossibleGenerator; + } + + return columnPossibleGenerator; + }; + + pickGeneratorForMysqlColumn = ( + columnPossibleGenerator: Prettify, + table: Table, + col: Column, + ) => { + // console.log(col); + // INT ------------------------------------------------------------------------------------------------------------ + if ( + (col.columnType.includes('serial') || col.columnType.includes('int')) + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateIntPrimaryKey({}); + return columnPossibleGenerator; + } + + let minValue: number | bigint | undefined; + let maxValue: number | bigint | undefined; + if (col.columnType === 'serial') { + // 2^64 % 2 - 1, 8 bytes + minValue = BigInt(0); + maxValue = BigInt('9223372036854775807'); + } else if (col.columnType.includes('int')) { + if (col.columnType === 'tinyint') { + // 2^8 / 2 - 1, 1 bytes + minValue = -128; + maxValue = 127; + } else if (col.columnType === 'smallint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -32768; + maxValue = 32767; + } else if (col.columnType === 'mediumint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -8388608; + maxValue = 8388607; + } else if (col.columnType === 'int') { + // 2^32 / 2 - 1, 4 bytes + minValue = -2147483648; + maxValue = 2147483647; + } else if (col.columnType === 'bigint') { + // 2^64 / 2 - 1, 8 bytes + minValue = BigInt('-9223372036854775808'); + maxValue = BigInt('9223372036854775807'); + } + } + + if (col.columnType.includes('int')) { + columnPossibleGenerator.generator = new GenerateInt({ + minValue, + maxValue, + }); + return columnPossibleGenerator; + } + + if (col.columnType.includes('serial')) { + const genObj = new GenerateIntPrimaryKey({}); + genObj.maxValue = maxValue; + columnPossibleGenerator.generator = genObj; + } + + // NUMBER(real, double, decimal, float) + if ( + col.columnType === 'real' + || col.columnType === 'double' + || col.columnType === 'decimal' + || col.columnType === 'float' + ) { + columnPossibleGenerator.generator = new GenerateNumber({}); + return columnPossibleGenerator; + } + + // STRING + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.includes('char') + || col.columnType.includes('varchar') + || col.columnType.includes('binary') + || col.columnType.includes('varbinary')) + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateUniqueString({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.includes('char') + || col.columnType.includes('varchar') + || col.columnType.includes('binary') + || col.columnType.includes('varbinary')) + && col.name.toLowerCase().includes('name') + ) { + columnPossibleGenerator.generator = new GenerateFirstName({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.includes('char') + || col.columnType.includes('varchar') + || col.columnType.includes('binary') + || col.columnType.includes('varbinary')) + && col.name.toLowerCase().includes('email') + ) { + columnPossibleGenerator.generator = new GenerateEmail({}); + return columnPossibleGenerator; + } + + if ( + col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.includes('char') + || col.columnType.includes('varchar') + || col.columnType.includes('binary') + || col.columnType.includes('varbinary') + ) { + // console.log(col, table); + columnPossibleGenerator.generator = new GenerateString({}); + return columnPossibleGenerator; + } + + // BOOLEAN + if (col.columnType === 'boolean') { + columnPossibleGenerator.generator = new GenerateBoolean({}); + return columnPossibleGenerator; + } + + // DATE, TIME, TIMESTAMP, DATETIME, YEAR + if (col.columnType.includes('datetime')) { + columnPossibleGenerator.generator = new GenerateDatetime({}); + return columnPossibleGenerator; + } + + if (col.columnType.includes('date')) { + columnPossibleGenerator.generator = new GenerateDate({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'time') { + columnPossibleGenerator.generator = new GenerateTime({}); + return columnPossibleGenerator; + } + + if (col.columnType.includes('timestamp')) { + columnPossibleGenerator.generator = new GenerateTimestamp({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'year') { + columnPossibleGenerator.generator = new GenerateYear({}); + return columnPossibleGenerator; + } + + // JSON + if (col.columnType === 'json') { + columnPossibleGenerator.generator = new GenerateJson({}); + return columnPossibleGenerator; + } + + // ENUM + if (col.enumValues !== undefined) { + columnPossibleGenerator.generator = new GenerateEnum({ + enumValues: col.enumValues, + }); + return columnPossibleGenerator; + } + + return columnPossibleGenerator; + }; + + pickGeneratorForSqlite = ( + columnPossibleGenerator: Prettify, + table: Table, + col: Column, + ) => { + // int section --------------------------------------------------------------------------------------- + if ( + (col.columnType === 'integer' || col.columnType === 'numeric') + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateIntPrimaryKey({}); + return columnPossibleGenerator; + } + + if ( + col.columnType === 'integer' + || col.columnType === 'numeric' + || col.columnType === 'bigint' + ) { + columnPossibleGenerator.generator = new GenerateInt({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'boolean') { + columnPossibleGenerator.generator = new GenerateBoolean({}); + return columnPossibleGenerator; + } + + // number section ------------------------------------------------------------------------------------ + if (col.columnType === 'real' || col.columnType === 'numeric') { + columnPossibleGenerator.generator = new GenerateNumber({}); + return columnPossibleGenerator; + } + + // string section ------------------------------------------------------------------------------------ + if ( + (col.columnType === 'text' + || col.columnType === 'numeric' + || col.columnType === 'blob') + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateUniqueString({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'numeric' + || col.columnType === 'blob') + && col.name.toLowerCase().includes('name') + ) { + columnPossibleGenerator.generator = new GenerateFirstName({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'numeric' + || col.columnType === 'blob') + && col.name.toLowerCase().includes('email') + ) { + columnPossibleGenerator.generator = new GenerateEmail({}); + return columnPossibleGenerator; + } + + if ( + col.columnType === 'text' + || col.columnType === 'numeric' + || col.columnType === 'blob' + || col.columnType === 'blobbuffer' + ) { + columnPossibleGenerator.generator = new GenerateString({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'textjson' || col.columnType === 'blobjson') { + columnPossibleGenerator.generator = new GenerateJson({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'timestamp' || col.columnType === 'timestamp_ms') { + columnPossibleGenerator.generator = new GenerateTimestamp({}); + return columnPossibleGenerator; + } + + return columnPossibleGenerator; + }; + + generateTablesValues = async ( + relations: Relation[], + tablesGenerators: ReturnType, + db?: + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + schema?: { [key: string]: PgTable | MySqlTable | SQLiteTable }, + options?: { count?: number; seed?: number; preserveData?: boolean; insertDataInDb?: boolean }, + ) => { + // console.time( + // "generateTablesValues-----------------------------------------------------" + // ); + const customSeed = options?.seed === undefined ? 0 : options.seed; + let tableCount: number | undefined; + let columnsGenerators: Prettify[]; + let tableGenerators: Prettify; + + let tableValues: { + [columnName: string]: string | number | boolean | undefined; + }[]; + + let tablesValues: { + tableName: string; + rows: typeof tableValues; + }[] = []; + + let pRNGSeed: number; + // relations = relations.filter(rel => rel.type === "one"); + let filteredRelations: Relation[]; + + let preserveData: boolean, insertDataInDb: boolean = true; + if (options?.preserveData !== undefined) preserveData = options.preserveData; + if (options?.insertDataInDb !== undefined) insertDataInDb = options.insertDataInDb; + + // TODO: now I'm generating tablesInOutRelations twice, first time in generatePossibleGenerators and second time here. maybe should generate it once instead. + const tablesInOutRelations = this.getTablesInOutRelations(relations); + for (const table of tablesGenerators) { + // console.log("tableName:", table) + tableCount = table.count === undefined ? options?.count || this.defaultCountForTable : table.count; + + tableGenerators = {}; + columnsGenerators = table.columnsPossibleGenerators; + + filteredRelations = relations.filter( + (rel) => rel.table === table.tableName, + ); + + // adding pRNG seed to column + for (const col of columnsGenerators) { + const columnRelations = filteredRelations.filter((rel) => rel.columns.includes(col.columnName)); + pRNGSeed = (columnRelations.length !== 0 + && columnRelations[0]!.columns.length >= 2) + ? (customSeed + generateHashFromString( + `${columnRelations[0]!.table}.${columnRelations[0]!.columns.join('_')}`, + )) + : (customSeed + generateHashFromString(`${table.tableName}.${col.columnName}`)); + + // console.log(pRNGSeed); + tableGenerators[col.columnName] = { + pRNGSeed, + ...col, + }; + } + + // get values to generate columns with foreign key + + // if table posts contains foreign key to table users, then rel.table === 'posts' and rel.refTable === 'users', because table posts has reference to table users. + if (filteredRelations.length !== 0) { + for (const rel of filteredRelations) { + if ( + table.withFromTable[rel.refTable] !== undefined + && table.withCount !== undefined + ) { + tableCount = table.withCount; + } + + for (let colIdx = 0; colIdx < rel.columns.length; colIdx++) { + let refColumnValues: (string | number | boolean)[]; + let hasSelfRelation: boolean; + let repeatedValuesCount: + | number + | { weight: number; count: number | number[] }[] + | undefined, + weightedCountSeed: number | undefined; + let genObj: AbstractGenerator; + + if (rel.table === rel.refTable) { + const refColName = rel.refColumns[colIdx] as string; + pRNGSeed = generateHashFromString( + `${table.tableName}.${refColName}`, + ); + + const refColumnGenerator: typeof tableGenerators = {}; + refColumnGenerator[refColName] = { + ...tableGenerators[refColName]!, + pRNGSeed, + }; + + refColumnValues = (await this.generateColumnsValuesByGenerators({ + tableGenerators: refColumnGenerator, + count: tableCount, + preserveData: true, + insertDataInDb: false, + }))!.map((rows) => rows[refColName]) as (string | number | boolean)[]; + + hasSelfRelation = true; + genObj = new GenerateSelfRelationsValuesFromArray({ + values: refColumnValues, + }); + } else { + refColumnValues = tablesValues + .find((val) => val.tableName === rel.refTable)! + .rows!.map((row) => row[rel.refColumns[colIdx]!]!); + hasSelfRelation = false; + + if ( + table.withFromTable[rel.refTable] !== undefined + && table.withFromTable[rel.refTable]!.repeatedValuesCount + !== undefined + ) { + repeatedValuesCount = table.withFromTable[rel.refTable]!.repeatedValuesCount; + weightedCountSeed = table.withFromTable[rel.refTable]!.weightedCountSeed; + } + + genObj = new GenerateValuesFromArray({ values: refColumnValues }); + (genObj as GenerateValuesFromArray).notNull = tableGenerators[rel.columns[colIdx]!]!.notNull; + (genObj as GenerateValuesFromArray).weightedCountSeed = weightedCountSeed; + (genObj as GenerateValuesFromArray).maxRepeatedValuesCount = repeatedValuesCount; + } + + // console.log(rel.columns[colIdx], tableGenerators) + tableGenerators[rel.columns[colIdx]!]!.generator = genObj; + tableGenerators[rel.columns[colIdx]!] = { + ...tableGenerators[rel.columns[colIdx]!]!, + hasSelfRelation, + hasRelation: true, + }; + } + } + } + + preserveData = ( + options?.preserveData === undefined + && tablesInOutRelations[table.tableName]?.in === 0 + ) + ? false + : true; + + // if (table.tableName === "products") { + // console.log("tableGenerators:", tableGenerators); + // console.log("name:", tableGenerators["name"].generator?.params) + // } + // console.time("generateColumnsValuesByGenerators"); + tableValues = await this.generateColumnsValuesByGenerators({ + tableGenerators, + db, + schema, + tableName: table.tableName, + count: tableCount, + preserveData, + insertDataInDb, + }); + // console.timeEnd("generateColumnsValuesByGenerators"); + + if (preserveData === true) { + tablesValues.push({ + tableName: table.tableName, + rows: tableValues, + }); + } + + // removing "link" from table that was required to generate current table + if (tablesInOutRelations[table.tableName] !== undefined) { + for (const tableName of tablesInOutRelations[table.tableName]!.requiredTableNames) { + tablesInOutRelations[tableName]!.in -= 1; + } + } + + if (preserveData === false) { + tablesValues = tablesValues.filter( + (table) => + tablesInOutRelations[table.tableName] !== undefined && tablesInOutRelations[table.tableName]!.in > 0, + ); + } + + // console.timeEnd("generateOneTableValues"); + } + + // console.log("tablesValues", tablesValues); + return tablesValues; + }; + + generateColumnsValuesByGenerators = async ({ + tableGenerators, + db, + schema, + tableName, + count, + preserveData = true, + insertDataInDb = true, + batchSize = 10000, + }: { + tableGenerators: Prettify; + db?: + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase; + schema?: { [key: string]: PgTable | MySqlTable | SQLiteTable }; + tableName?: string; + count?: number; + preserveData?: boolean; + insertDataInDb?: boolean; + batchSize?: number; + }) => { + if (count === undefined) { + count = this.defaultCountForTable; + } + + // console.log("count:", count); + let columnGenerator: (typeof tableGenerators)[string]; + // const columnsGenerators: { + // [columnName: string]: Generator< + // number | string | boolean | unknown, + // void, + // unknown + // >; + // } = {}; + const columnsGenerators: { + [columnName: string]: AbstractGenerator; + } = {}; + let generatedValues: { [columnName: string]: number | string | boolean | undefined }[] = []; + + // console.time("initiate generators"); + let columnsNumber = 0; + // console.log("before init") + for (const columnName of Object.keys(tableGenerators)) { + columnsNumber += 1; + columnGenerator = tableGenerators[columnName]!; + + // columnsGenerators[columnName] = columnGenerator.generator!.execute({ + // count, + // seed: columnGenerator.pRNGSeed, + // }); + columnsGenerators[columnName] = columnGenerator.generator!; + columnsGenerators[columnName]!.init({ + count, + seed: columnGenerator.pRNGSeed, + }); + + if ( + columnsGenerators[columnName]!.uniqueVersionOfGen !== undefined + && columnsGenerators[columnName]!.isUnique === true + ) { + const uniqueGen = new columnsGenerators[columnName]!.uniqueVersionOfGen!({ + ...columnsGenerators[columnName]!.params, + }); + uniqueGen.init({ + count, + seed: columnGenerator.pRNGSeed, + }); + uniqueGen.isUnique = columnsGenerators[columnName]!.isUnique; + uniqueGen.dataType = columnsGenerators[columnName]!.dataType; + + columnsGenerators[columnName] = uniqueGen; + } + + // console.log("col:", columnName, columnsGenerators[columnName]); + } + // if (tableName === "products") { + // // console.log("tableGenerators:", tableGenerators); + // console.log("name:", (tableGenerators["name"].generator as GenerateValuesFromArray)) + // } + // console.timeEnd("initiate generators"); + let maxParametersNumber: number; + if (is(db, PgDatabase)) { + maxParametersNumber = this.postgresMaxParametersNumber; + } else if (is(db, MySqlDatabase)) { + maxParametersNumber = this.mysqlMaxParametersNumber; + } else { + // is(db, BaseSQLiteDatabase) + maxParametersNumber = this.sqliteMaxParametersNumber; + } + const maxBatchSize = Math.floor(maxParametersNumber / columnsNumber); + batchSize = batchSize > maxBatchSize ? maxBatchSize : batchSize; + + // console.time("columnsGenerators"); + if ( + insertDataInDb === true + && (db === undefined || schema === undefined || tableName === undefined) + ) { + // console.log(db, schema, tableName); + throw new Error('db or schema or tableName is undefined.'); + } + + let row: { [columnName: string]: string | number | boolean }, + generatedValue, + i: number; + + for (i = 0; i < count; i++) { + row = {}; + generatedValues.push(row); + + for (const columnName of Object.keys(columnsGenerators)) { + // generatedValue = columnsGenerators[columnName].next().value as + // | string + // | number + // | boolean; + generatedValue = columnsGenerators[columnName]!.generate({ i }) as + | string + | number + | boolean; + // console.log("generatedValue:", generatedValue); + row[columnName as keyof typeof row] = generatedValue; + } + + if ( + insertDataInDb === true + && ((i + 1) % batchSize === 0 || i === count - 1) + ) { + if (preserveData === false) { + await this.insertInDb({ + generatedValues, + db: db as + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + schema: schema as { + [key: string]: PgTable | MySqlTable | SQLiteTable; + }, + tableName: tableName as string, + }); + generatedValues = []; + } else { + const batchCount = Math.floor(i / batchSize); + + await this.insertInDb({ + generatedValues: generatedValues.slice( + batchSize * batchCount, + batchSize * (batchCount + 1), + ), + db: db as + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + schema: schema as { + [key: string]: PgTable | MySqlTable | SQLiteTable; + }, + tableName: tableName as string, + }); + } + } + } + + // for (const columnName of Object.keys(columnsGenerators)) { + // console.log( + // `timeSpent to generate ${columnName}:`, + // columnsGenerators[columnName]!.timeSpent + // ); + // } + + return preserveData === true ? generatedValues : []; + }; + + insertInDb = async ({ + generatedValues, + db, + schema, + tableName, + }: { + generatedValues: { + [columnName: string]: number | string | boolean | undefined; + }[]; + db: + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase; + schema: { + [key: string]: PgTable | MySqlTable | SQLiteTable; + }; + tableName: string; + }) => { + // console.log(tableName, generatedValues); + if (is(db, PgDatabase)) { + // console.log("table to insert data:", tableName, ";columns in table:", Object.keys(generatedValues[0]!).length, ";rows to insert:", generatedValues, ";overall parameters:", generatedValues.length * Object.keys(generatedValues[0]!).length); + await db + .insert((schema as { [key: string]: PgTable })[tableName]!) + .values(generatedValues); + } else if (is(db, MySqlDatabase)) { + // console.log("table to insert data:", tableName, ";columns in table:", Object.keys(generatedValues[0]).length, ";rows to insert:", generatedValues, ";overall parameters:", generatedValues.length * Object.keys(generatedValues[0]).length); + await db + .insert((schema as { [key: string]: MySqlTable })[tableName]!) + .values(generatedValues); + } else if (is(db, BaseSQLiteDatabase)) { + // console.log("table to insert data:", tableName, ";columns in table:", Object.keys(generatedValues[0]).length, ";rows to insert:", generatedValues.length, ";overall parameters:", generatedValues.length * Object.keys(generatedValues[0]).length); + await db + .insert((schema as { [key: string]: SQLiteTable })[tableName]!) + .values(generatedValues); + } + }; +} + +export default new SeedService(); diff --git a/drizzle-seed/src/services/utils.ts b/drizzle-seed/src/services/utils.ts new file mode 100644 index 000000000..dfe52253a --- /dev/null +++ b/drizzle-seed/src/services/utils.ts @@ -0,0 +1,94 @@ +export const fastCartesianProduct = (sets: (number | string | boolean | object)[][], index: number) => { + const resultList = []; + let currSet: (typeof sets)[number]; + let element: (typeof sets)[number][number]; + + for (let i = sets.length - 1; i >= 0; i--) { + currSet = sets[i]!; + element = currSet[index % currSet.length]!; + resultList.unshift(element); + index = Math.floor(index / currSet.length); + } + + return resultList; +}; + +/** + * @param weights positive number in range [0, 1], that represents probabilities to choose index of array. Example: weights = [0.2, 0.8] + * @param [accuracy=100] approximate number of elements in returning array + * @returns Example: with weights = [0.2, 0.8] and accuracy = 10 returning array of indices gonna equal this: [0, 0, 1, 1, 1, 1, 1, 1, 1, 1] + */ +export const getWeightedIndices = (weights: number[], accuracy = 100) => { + const weightsSum = weights.reduce((acc, currVal) => acc + currVal, 0); + if (weightsSum !== 1) { + throw new Error(`sum of all weights don't equal to 1; ${weightsSum} !== 1`); + } + + // const accuracy = 100; + const weightedIndices: number[] = []; + for (const [index, weight] of weights.entries()) { + const ticketsNumb = Math.floor(weight * accuracy); + weightedIndices.push(...Array.from({ length: ticketsNumb }).fill(index)); + } + + return weightedIndices; +}; + +export const generateHashFromString = (s: string) => { + let hash = 0; + // p and m are prime numbers + const p = 53; + const m = 28871271685163; + + for (let i = 0; i < s.length; i++) { + hash += ((s.codePointAt(i) || 0) * Math.pow(p, i)) % m; + } + + return hash; +}; + +/** + * @param param0.template example: "#####" or "#####-####" + * @param param0.values example: ["3", "2", "h"] + * @param param0.defaultValue example: "0" + * @returns + */ +export const fillTemplate = ({ template, placeholdersCount, values, defaultValue = ' ' }: { + template: string; + placeholdersCount?: number; + values: string[]; + defaultValue?: string; +}) => { + if (placeholdersCount === undefined) { + const iterArray = [...template.matchAll(/#/g)]; + placeholdersCount = iterArray.length; + } + + const diff = placeholdersCount - values.length; + if (diff > 0) { + values.unshift(...Array.from({ length: diff }).fill(defaultValue)); + } + + let resultStr = '', valueIdx = 0; + for (const si of template) { + if (si === '#') { + resultStr += values[valueIdx]; + valueIdx += 1; + continue; + } + resultStr += si; + } + + return resultStr; +}; + +// let count = 0; +// for (let i = 0; i < 3; i++) { +// for (let j = 0; j < 3; j++) { +// for (let k = 0; k < 3; k++) { +// console.log([i, j, k], "===", fastCartesianProduct([[0, 1, 2], [0, 1, 2], [0, 1, 2]], count)); +// count++; +// } + +// } +// } diff --git a/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts b/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts new file mode 100644 index 000000000..7eff3c751 --- /dev/null +++ b/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts @@ -0,0 +1,142 @@ +import lastNames from '../../datasets/lastNames.ts'; +import { + GenerateBoolean, + GenerateCity, + GenerateCompanyName, + GenerateCountry, + GenerateDate, + GenerateDatetime, + GenerateDefault, + GenerateEmail, + GenerateFirstName, + GenerateFullName, + GenerateInt, + GenerateInterval, + GenerateIntPrimaryKey, + GenerateJobTitle, + GenerateJson, + GenerateLastName, + GenerateLine, + GenerateLoremIpsum, + GenerateNumber, + GeneratePhoneNumber, + GeneratePoint, + GeneratePostcode, + GenerateState, + GenerateStreetAdddress, + GenerateString, + GenerateTime, + GenerateTimestamp, + GenerateUniqueCompanyName, + GenerateUniqueFullName, + GenerateUniqueInt, + GenerateUniqueInterval, + GenerateUniqueLine, + GenerateUniqueNumber, + GenerateUniquePoint, + GenerateUniquePostcode, + GenerateUniqueStreetAdddress, + GenerateUniqueString, + GenerateValuesFromArray, + GenerateYear, + WeightedRandomGenerator, +} from '../../services/GeneratorsWrappers.ts'; + +const benchmark = ({ generatorName, generator, count = 100000, seed = 1 }: { + generatorName: string; + generator: (typeof generatorsFuncs)[keyof typeof generatorsFuncs]; + count?: number; + seed?: number; +}) => { + generator.init({ count, seed }); + // if (generator.uniqueVersionOfGen !== undefined && generator.isUnique === true) { + // const uniqueGen = new generator.uniqueVersionOfGen({ ...generator.params }); + // uniqueGen.init({ + // count, + // seed + // }); + // uniqueGen.isUnique = generator.isUnique; + // uniqueGen.dataType = generator.dataType; + + // generator = uniqueGen; + // } + + let timeSpentToInit = 0, timeSpent = 0; + const t0 = new Date(); + + generator.init({ count, seed }); + timeSpentToInit += (Date.now() - t0.getTime()) / 1000; + + for (let i = 0; i < count; i++) { + const val = generator.generate({ i }); + if (val === undefined) { + console.log(val, `in ${generatorName} generator.`); + } + } + + timeSpent += (Date.now() - t0.getTime()) / 1000; + console.log(`${generatorName} spent ${timeSpentToInit} to init and spent ${timeSpent} to generate ${count} rows.`); + console.log( + 'time spent in particular code part:', + generator.timeSpent, + ';', + generator.timeSpent === undefined ? generator.timeSpent : (generator.timeSpent / timeSpent), + 'percent of all time', + ); + console.log('\n'); +}; + +const generatorsFuncs = { + default: new GenerateDefault({ defaultValue: 'defaultValue' }), + valuesFromArray: new GenerateValuesFromArray({ values: lastNames }), + intPrimaryKey: new GenerateIntPrimaryKey({}), + number: new GenerateNumber({}), + uniqueNumber: new GenerateUniqueNumber({}), + int: new GenerateInt({}), + uniqueInt: new GenerateUniqueInt({}), + boolean: new GenerateBoolean({}), + date: new GenerateDate({}), + time: new GenerateTime({}), + timestamp: new GenerateTimestamp({}), + datetime: new GenerateDatetime({}), + year: new GenerateYear({}), + json: new GenerateJson({}), + jsonb: new GenerateJson({}), + interval: new GenerateInterval({}), + uniqueInterval: new GenerateUniqueInterval({}), + string: new GenerateString({}), + uniqueString: new GenerateUniqueString({}), + firstName: new GenerateFirstName({}), + // uniqueFirstName: new GenerateUniqueName({}), + lastName: new GenerateLastName({}), + // uniqueLastName: new GenerateUniqueSurname({}), + fullName: new GenerateFullName({}), + uniqueFullName: new GenerateUniqueFullName({}), + email: new GenerateEmail({}), + phoneNumber: new GeneratePhoneNumber({ template: '+380 ## ## ### ##' }), + country: new GenerateCountry({}), + // uniqueCountry: new GenerateUniqueCountry({}), + city: new GenerateCity({}), + // uniqueCity: new GenerateUniqueCity({}), + streetAddress: new GenerateStreetAdddress({}), + uniqueStreetAddress: new GenerateUniqueStreetAdddress({}), + jobTitle: new GenerateJobTitle({}), + postcode: new GeneratePostcode({}), + uniquePostcode: new GenerateUniquePostcode({}), + state: new GenerateState({}), + companyName: new GenerateCompanyName({}), + uniqueCompanyName: new GenerateUniqueCompanyName({}), + loremIpsum: new GenerateLoremIpsum({}), + point: new GeneratePoint({}), + uniquePoint: new GenerateUniquePoint({}), + line: new GenerateLine({}), + uniqueLine: new GenerateUniqueLine({}), + weightedRandom: new WeightedRandomGenerator([ + { weight: 0.8, value: new GenerateUniqueInt({ minValue: 0, maxValue: 90000 }) }, + { weight: 0.2, value: new GenerateDefault({ defaultValue: Number.NaN }) }, + ]), +}; + +for (const [generatorName, generator] of Object.entries(generatorsFuncs)) { + benchmark({ generatorName, generator, count: 100000, seed: 1 }); +} diff --git a/drizzle-seed/src/tests/mysql/allDataTypesTest/drizzle.config.ts b/drizzle-seed/src/tests/mysql/allDataTypesTest/drizzle.config.ts new file mode 100644 index 000000000..78ff7a54b --- /dev/null +++ b/drizzle-seed/src/tests/mysql/allDataTypesTest/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/mysql/allDataTypesTest/mysqlSchema.ts', + out: './src/tests/mysql/allDataTypesTest/mysqlMigrations', + dialect: 'mysql', +}); diff --git a/drizzle-seed/src/tests/mysql/allDataTypesTest/mysqlSchema.ts b/drizzle-seed/src/tests/mysql/allDataTypesTest/mysqlSchema.ts new file mode 100644 index 000000000..217fe74e7 --- /dev/null +++ b/drizzle-seed/src/tests/mysql/allDataTypesTest/mysqlSchema.ts @@ -0,0 +1,56 @@ +import { + bigint, + binary, + boolean, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + mysqlEnum, + mysqlTable, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, +} from 'drizzle-orm/mysql-core'; + +export const allDataTypes = mysqlTable('all_data_types', { + int: int('integer'), + tinyint: tinyint('tinyint'), + smallint: smallint('smallint'), + mediumint: mediumint('mediumint'), + biginteger: bigint('bigint', { mode: 'bigint' }), + bigintNumber: bigint('bigint_number', { mode: 'number' }), + real: real('real'), + decimal: decimal('decimal'), + double: double('double'), + float: float('float'), + serial: serial('serial'), + binary: binary('binary', { length: 255 }), + varbinary: varbinary('varbinary', { length: 256 }), + char: char('char', { length: 255 }), + varchar: varchar('varchar', { length: 256 }), + text: text('text'), + boolean: boolean('boolean'), + dateString: date('date_string', { mode: 'string' }), + date: date('date', { mode: 'date' }), + datetime: datetime('datetime', { mode: 'date' }), + datetimeString: datetime('datetimeString', { mode: 'string' }), + time: time('time'), + year: year('year'), + timestampDate: timestamp('timestamp_date', { mode: 'date' }), + timestampString: timestamp('timestamp_string', { mode: 'string' }), + json: json('json'), + mysqlEnum: mysqlEnum('popularity', ['unknown', 'known', 'popular']), +}); diff --git a/drizzle-seed/src/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts b/drizzle-seed/src/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts new file mode 100644 index 000000000..dc663800e --- /dev/null +++ b/drizzle-seed/src/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts @@ -0,0 +1,121 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import type { MySql2Database } from 'drizzle-orm/mysql2'; +import { drizzle } from 'drizzle-orm/mysql2'; +import getPort from 'get-port'; +import type { Connection } from 'mysql2/promise'; +import { createConnection } from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, expect, test } from 'vitest'; +import { seed } from '../../../index.ts'; +import * as schema from './mysqlSchema.ts'; + +let mysqlContainer: Docker.Container; +let client: Connection; +let db: MySql2Database; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +beforeAll(async () => { + const connectionString = await createDockerDB(); + + const sleep = 1000; + let timeLeft = 40000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + const client = await createConnection(connectionString); + await client.connect(); + db = drizzle(client); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } + + await db.execute( + sql` + CREATE TABLE \`all_data_types\` ( + \`integer\` int, + \`tinyint\` tinyint, + \`smallint\` smallint, + \`mediumint\` mediumint, + \`bigint\` bigint, + \`bigint_number\` bigint, + \`real\` real, + \`decimal\` decimal, + \`double\` double, + \`float\` float, + \`serial\` serial AUTO_INCREMENT, + \`binary\` binary(255), + \`varbinary\` varbinary(256), + \`char\` char(255), + \`varchar\` varchar(256), + \`text\` text, + \`boolean\` boolean, + \`date_string\` date, + \`date\` date, + \`datetime\` datetime, + \`datetimeString\` datetime, + \`time\` time, + \`year\` year, + \`timestamp_date\` timestamp, + \`timestamp_string\` timestamp, + \`json\` json, + \`popularity\` enum('unknown','known','popular') + ); + `, + ); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +test('basic seed test', async () => { + await seed(db, schema, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); diff --git a/drizzle-seed/src/tests/mysql/drizzle.config.ts b/drizzle-seed/src/tests/mysql/drizzle.config.ts new file mode 100644 index 000000000..9a84354e3 --- /dev/null +++ b/drizzle-seed/src/tests/mysql/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/mysql/mysqlSchema.ts', + out: './src/tests/mysql/mysqlMigrations', + dialect: 'mysql', +}); diff --git a/drizzle-seed/src/tests/mysql/generatorsTest/drizzle.config.ts b/drizzle-seed/src/tests/mysql/generatorsTest/drizzle.config.ts new file mode 100644 index 000000000..621d8acc1 --- /dev/null +++ b/drizzle-seed/src/tests/mysql/generatorsTest/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/mysql/generatorsTest/mysqlSchema.ts', + out: './src/tests/mysql/generatorsTest/mysqlMigrations', + dialect: 'mysql', +}); diff --git a/drizzle-seed/src/tests/mysql/generatorsTest/generators.test.ts b/drizzle-seed/src/tests/mysql/generatorsTest/generators.test.ts new file mode 100644 index 000000000..223d5b54e --- /dev/null +++ b/drizzle-seed/src/tests/mysql/generatorsTest/generators.test.ts @@ -0,0 +1,128 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import type { MySql2Database } from 'drizzle-orm/mysql2'; +import { drizzle } from 'drizzle-orm/mysql2'; +import getPort from 'get-port'; +import type { Connection } from 'mysql2/promise'; +import { createConnection } from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, expect, test } from 'vitest'; +import { seed } from '../../../index.ts'; +import * as schema from './mysqlSchema.ts'; + +let mysqlContainer: Docker.Container; +let client: Connection; +let db: MySql2Database; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +beforeAll(async () => { + const connectionString = await createDockerDB(); + + const sleep = 1000; + let timeLeft = 40000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + db = drizzle(client); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } + + await db.execute( + sql` + CREATE TABLE \`datetime_table\` ( + \`datetime\` datetime + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`year_table\` ( + \`year\` year + ); + `, + ); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +const count = 10000; + +test('datetime generator test', async () => { + await seed(db, { datetimeTable: schema.datetimeTable }).refine((funcs) => ({ + datetimeTable: { + count, + columns: { + datetime: funcs.datetime(), + }, + }, + })); + + const data = await db.select().from(schema.datetimeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('year generator test', async () => { + await seed(db, { yearTable: schema.yearTable }).refine((funcs) => ({ + yearTable: { + count, + columns: { + year: funcs.year(), + }, + }, + })); + + const data = await db.select().from(schema.yearTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); diff --git a/drizzle-seed/src/tests/mysql/generatorsTest/mysqlSchema.ts b/drizzle-seed/src/tests/mysql/generatorsTest/mysqlSchema.ts new file mode 100644 index 000000000..c9a7edc62 --- /dev/null +++ b/drizzle-seed/src/tests/mysql/generatorsTest/mysqlSchema.ts @@ -0,0 +1,9 @@ +import { datetime, mysqlTable, year } from 'drizzle-orm/mysql-core'; + +export const datetimeTable = mysqlTable('datetime_table', { + datetime: datetime('datetime'), +}); + +export const yearTable = mysqlTable('year_table', { + year: year('year'), +}); diff --git a/drizzle-seed/src/tests/mysql/mysql.test.ts b/drizzle-seed/src/tests/mysql/mysql.test.ts new file mode 100644 index 000000000..d1b6790ec --- /dev/null +++ b/drizzle-seed/src/tests/mysql/mysql.test.ts @@ -0,0 +1,381 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import type { MySql2Database } from 'drizzle-orm/mysql2'; +import { drizzle } from 'drizzle-orm/mysql2'; +import getPort from 'get-port'; +import type { Connection } from 'mysql2/promise'; +import { createConnection } from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../index.ts'; +import * as schema from './mysqlSchema.ts'; + +let mysqlContainer: Docker.Container; +let client: Connection; +let db: MySql2Database; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +beforeAll(async () => { + const connectionString = await createDockerDB(); + + const sleep = 1000; + let timeLeft = 40000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + db = drizzle(client); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } + + await db.execute( + sql` + CREATE TABLE \`customer\` ( + \`id\` varchar(256) NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text, + \`region\` text, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + \`fax\` text, + CONSTRAINT \`customer_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`order_detail\` ( + \`unit_price\` float NOT NULL, + \`quantity\` int NOT NULL, + \`discount\` float NOT NULL, + \`order_id\` int NOT NULL, + \`product_id\` int NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`employee\` ( + \`id\` int NOT NULL, + \`last_name\` text NOT NULL, + \`first_name\` text, + \`title\` text NOT NULL, + \`title_of_courtesy\` text NOT NULL, + \`birth_date\` timestamp NOT NULL, + \`hire_date\` timestamp NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`home_phone\` text NOT NULL, + \`extension\` int NOT NULL, + \`notes\` text NOT NULL, + \`reports_to\` int, + \`photo_path\` text, + CONSTRAINT \`employee_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`order\` ( + \`id\` int NOT NULL, + \`order_date\` timestamp NOT NULL, + \`required_date\` timestamp NOT NULL, + \`shipped_date\` timestamp, + \`ship_via\` int NOT NULL, + \`freight\` float NOT NULL, + \`ship_name\` text NOT NULL, + \`ship_city\` text NOT NULL, + \`ship_region\` text, + \`ship_postal_code\` text, + \`ship_country\` text NOT NULL, + \`customer_id\` varchar(256) NOT NULL, + \`employee_id\` int NOT NULL, + CONSTRAINT \`order_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`product\` ( + \`id\` int NOT NULL, + \`name\` text NOT NULL, + \`quantity_per_unit\` text NOT NULL, + \`unit_price\` float NOT NULL, + \`units_in_stock\` int NOT NULL, + \`units_on_order\` int NOT NULL, + \`reorder_level\` int NOT NULL, + \`discontinued\` int NOT NULL, + \`supplier_id\` int NOT NULL, + CONSTRAINT \`product_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`supplier\` ( + \`id\` int NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`region\` text, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + CONSTRAINT \`supplier_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order_detail\` ADD CONSTRAINT \`order_detail_order_id_order_id_fk\` FOREIGN KEY (\`order_id\`) REFERENCES \`order\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order_detail\` ADD CONSTRAINT \`order_detail_product_id_product_id_fk\` FOREIGN KEY (\`product_id\`) REFERENCES \`product\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`employee\` ADD CONSTRAINT \`employee_reports_to_employee_id_fk\` FOREIGN KEY (\`reports_to\`) REFERENCES \`employee\`(\`id\`) ON DELETE no action ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order\` ADD CONSTRAINT \`order_customer_id_customer_id_fk\` FOREIGN KEY (\`customer_id\`) REFERENCES \`customer\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order\` ADD CONSTRAINT \`order_employee_id_employee_id_fk\` FOREIGN KEY (\`employee_id\`) REFERENCES \`employee\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`product\` ADD CONSTRAINT \`product_supplier_id_supplier_id_fk\` FOREIGN KEY (\`supplier_id\`) REFERENCES \`supplier\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); diff --git a/drizzle-seed/src/tests/mysql/mysqlSchema.ts b/drizzle-seed/src/tests/mysql/mysqlSchema.ts new file mode 100644 index 000000000..684a5d798 --- /dev/null +++ b/drizzle-seed/src/tests/mysql/mysqlSchema.ts @@ -0,0 +1,128 @@ +// import { serial, int, varchar, mysqlTable } from "drizzle-orm/mysql-core"; + +// export const schema = mysqlSchema("public"); + +// export const users = mysqlTable("users", { +// id: int("id").autoincrement().primaryKey(), +// name: varchar("name", { length: 256 }), +// email: varchar("email", { length: 256 }), +// phone: varchar("phone", { length: 256 }), +// password: varchar("password", { length: 256 }) +// }); + +// export const posts = mysqlTable("posts", { +// id: int("id").autoincrement().primaryKey(), +// title: varchar("title", { length: 256 }), +// content: varchar("content", { length: 256 }), +// userId: int("user_id").references(() => users.id) +// }); + +// export const comments = mysqlTable("comments", { +// id: serial("id").primaryKey(), +// content: varchar("content", { length: 256 }), +// postId: int("post_id").references(() => posts.id), +// userId: int("user_id").references(() => users.id) +// }); + +import type { AnyMySqlColumn } from 'drizzle-orm/mysql-core'; +import { float, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'; + +export const customers = mysqlTable('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = mysqlTable( + 'employee', + { + id: int('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: int('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: int('reports_to').references((): AnyMySqlColumn => employees.id), + photoPath: text('photo_path'), + }, +); + +export const orders = mysqlTable('order', { + id: int('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: int('ship_via').notNull(), + freight: float('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: varchar('customer_id', { length: 256 }) + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: int('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = mysqlTable('supplier', { + id: int('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = mysqlTable('product', { + id: int('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: float('unit_price').notNull(), + unitsInStock: int('units_in_stock').notNull(), + unitsOnOrder: int('units_on_order').notNull(), + reorderLevel: int('reorder_level').notNull(), + discontinued: int('discontinued').notNull(), + + supplierId: int('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = mysqlTable('order_detail', { + unitPrice: float('unit_price').notNull(), + quantity: int('quantity').notNull(), + discount: float('discount').notNull(), + + orderId: int('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: int('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); diff --git a/drizzle-seed/src/tests/northwind/mysqlSchema.ts b/drizzle-seed/src/tests/northwind/mysqlSchema.ts new file mode 100644 index 000000000..337d43948 --- /dev/null +++ b/drizzle-seed/src/tests/northwind/mysqlSchema.ts @@ -0,0 +1,128 @@ +// import { serial, int, varchar, mysqlTable } from "drizzle-orm/mysql-core"; + +// // export const schema = mysqlSchema("public"); + +// export const users = mysqlTable("users", { +// id: int("id").autoincrement().primaryKey(), +// name: varchar("name", { length: 256 }), +// email: varchar("email", { length: 256 }), +// phone: varchar("phone", { length: 256 }), +// password: varchar("password", { length: 256 }) +// }); + +// export const posts = mysqlTable("posts", { +// id: serial("id").primaryKey(), +// title: varchar("title", { length: 256 }), +// content: varchar("content", { length: 256 }), +// userId: int("user_id").references(() => users.id) +// }); + +// export const comments = mysqlTable("comments", { +// id: serial("id").primaryKey(), +// content: varchar("content", { length: 256 }), +// postId: int("post_id").references(() => posts.id), +// userId: int("user_id").references(() => users.id) +// }); + +import type { AnyMySqlColumn } from 'drizzle-orm/mysql-core'; +import { float, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'; + +export const customers = mysqlTable('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = mysqlTable( + 'employee', + { + id: int('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: int('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: int('reports_to').references((): AnyMySqlColumn => employees.id), + photoPath: text('photo_path'), + }, +); + +export const orders = mysqlTable('order', { + id: int('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: int('ship_via').notNull(), + freight: float('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: varchar('customer_id', { length: 256 }) + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: int('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = mysqlTable('supplier', { + id: int('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = mysqlTable('product', { + id: int('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: float('unit_price').notNull(), + unitsInStock: int('units_in_stock').notNull(), + unitsOnOrder: int('units_on_order').notNull(), + reorderLevel: int('reorder_level').notNull(), + discontinued: int('discontinued').notNull(), + + supplierId: int('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = mysqlTable('order_detail', { + unitPrice: float('unit_price').notNull(), + quantity: int('quantity').notNull(), + discount: float('discount').notNull(), + + orderId: int('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: int('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); diff --git a/drizzle-seed/src/tests/northwind/mysqlTest.ts b/drizzle-seed/src/tests/northwind/mysqlTest.ts new file mode 100644 index 000000000..98c2dd742 --- /dev/null +++ b/drizzle-seed/src/tests/northwind/mysqlTest.ts @@ -0,0 +1,176 @@ +import 'dotenv/config'; +import path from 'path'; + +import { drizzle } from 'drizzle-orm/mysql2'; +import { migrate } from 'drizzle-orm/mysql2/migrator'; +import mysql from 'mysql2/promise'; + +import * as schema from './mysqlSchema.ts'; + +import { seed } from '../../index.ts'; + +const { Mysql_HOST, Mysql_PORT, Mysql_DATABASE, Mysql_USER, Mysql_PASSWORD } = process.env; + +const mysqlPool = mysql.createPool({ + host: Mysql_HOST, + port: Number(Mysql_PORT) || 3306, + database: Mysql_DATABASE, + user: Mysql_USER, + password: Mysql_PASSWORD, + // ssl: { rejectUnauthorized: false } +}); + +const db = drizzle(mysqlPool); + +console.log('database connection was established successfully.'); + +(async () => { + await migrate(db, { migrationsFolder: path.join(__dirname, '../../../mysqlMigrations') }); + console.log('database was migrated.'); + + // await seed(db, schema, { count: 100000, seed: 1 }); + + const titlesOfCourtesy = ['Ms.', 'Mrs.', 'Dr.']; + const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100]; + const reorderLevels = [0, 5, 10, 15, 20, 25, 30]; + const quantityPerUnit = [ + '100 - 100 g pieces', + '100 - 250 g bags', + '10 - 200 g glasses', + '10 - 4 oz boxes', + '10 - 500 g pkgs.', + '10 - 500 g pkgs.', + '10 boxes x 12 pieces', + '10 boxes x 20 bags', + '10 boxes x 8 pieces', + '10 kg pkg.', + '10 pkgs.', + '12 - 100 g bars', + '12 - 100 g pkgs', + '12 - 12 oz cans', + '12 - 1 lb pkgs.', + '12 - 200 ml jars', + '12 - 250 g pkgs.', + '12 - 355 ml cans', + '12 - 500 g pkgs.', + '750 cc per bottle', + '5 kg pkg.', + '50 bags x 30 sausgs.', + '500 ml', + '500 g', + '48 pieces', + '48 - 6 oz jars', + '4 - 450 g glasses', + '36 boxes', + '32 - 8 oz bottles', + '32 - 500 g boxes', + ]; + const discounts = [0.05, 0.15, 0.2, 0.25]; + + await seed(db, schema).refine((funcs) => ({ + customers: { + count: 10000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + fax: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + employees: { + count: 200, + columns: { + firstName: funcs.firstName({}), + lastName: funcs.lastName({}), + title: funcs.jobTitle({}), + titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }), + birthDate: funcs.date({ minDate: '1990-01-01', maxDate: '2010-12-31' }), + hireDate: funcs.date({ minDate: '2010-12-31', maxDate: '2024-08-26' }), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + country: funcs.country({}), + homePhone: funcs.phoneNumber({ template: '(###) ###-####' }), + extension: funcs.int({ minValue: 428, maxValue: 5467 }), + notes: funcs.loremIpsum({}), + }, + }, + orders: { + count: 50000, + columns: { + shipVia: funcs.int({ minValue: 1, maxValue: 3 }), + freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }), + shipName: funcs.streetAddress({}), + shipCity: funcs.city({}), + shipRegion: funcs.state({}), + shipPostalCode: funcs.postcode({}), + shipCountry: funcs.country({}), + }, + with: { + details: [ + { weight: 0.6, count: [1, 2, 3, 4] }, + { weight: 0.2, count: [5, 6, 7, 8, 9, 10] }, + { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] }, + { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] }, + ], + }, + }, + suppliers: { + count: 1000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + products: { + count: 5000, + columns: { + name: funcs.companyName({}), + quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }), + unitPrice: funcs.weightedRandom( + [ + { + weight: 0.5, + value: funcs.int({ minValue: 3, maxValue: 300 }), + }, + { + weight: 0.5, + value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 }), + }, + ], + ), + unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }), + unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }), + reorderLevel: funcs.valuesFromArray({ values: reorderLevels }), + discontinued: funcs.int({ minValue: 0, maxValue: 1 }), + }, + }, + details: { + columns: { + unitPrice: funcs.number({ minValue: 10, maxValue: 130 }), + quantity: funcs.int({ minValue: 1, maxValue: 130 }), + discount: funcs.weightedRandom( + [ + { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) }, + { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }, + ], + ), + }, + }, + })); + + await mysqlPool.end(); +})().then(); diff --git a/drizzle-seed/src/tests/northwind/pgSchema.ts b/drizzle-seed/src/tests/northwind/pgSchema.ts new file mode 100644 index 000000000..2855df3fd --- /dev/null +++ b/drizzle-seed/src/tests/northwind/pgSchema.ts @@ -0,0 +1,130 @@ +// import { serial, integer, varchar, pgSchema, getTableConfig as getPgTableConfig } from "drizzle-orm/pg-core"; + +// export const schema = pgSchema("seeder_lib_pg"); + +// export const users = schema.table("users", { +// id: serial("id").primaryKey(), +// name: varchar("name", { length: 256 }), +// email: varchar("email", { length: 256 }), +// phone: varchar("phone", { length: 256 }), +// password: varchar("password", { length: 256 }) +// }); + +// export const posts = schema.table("posts", { +// id: serial("id").primaryKey(), +// title: varchar("title", { length: 256 }), +// content: varchar("content", { length: 256 }), +// userId: integer("user_id").references(() => users.id) +// }); + +// export const comments = schema.table("comments", { +// id: serial("id").primaryKey(), +// content: varchar("content", { length: 256 }), +// postId: integer("post_id").references(() => posts.id), +// userId: integer("user_id").references(() => users.id) +// }); + +import type { AnyPgColumn } from 'drizzle-orm/pg-core'; +import { integer, numeric, pgSchema, text, timestamp, varchar } from 'drizzle-orm/pg-core'; + +export const schema = pgSchema('seeder_lib_pg'); + +export const customers = schema.table('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = schema.table('employee', { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to').references((): AnyPgColumn => employees.id), + photoPath: text('photo_path'), +}); + +export const orders = schema.table('order', { + id: integer('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = schema.table( + 'supplier', + { + id: integer('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), + }, +); + +export const products = schema.table('product', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = schema.table('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); diff --git a/drizzle-seed/src/tests/northwind/pgTest.ts b/drizzle-seed/src/tests/northwind/pgTest.ts new file mode 100644 index 000000000..284f28957 --- /dev/null +++ b/drizzle-seed/src/tests/northwind/pgTest.ts @@ -0,0 +1,175 @@ +import 'dotenv/config'; +import path from 'path'; + +import { drizzle } from 'drizzle-orm/node-postgres'; +import { migrate } from 'drizzle-orm/node-postgres/migrator'; +import { Pool as PgPool } from 'pg'; + +import { seed } from '../../index.ts'; +import * as schema from './pgSchema.ts'; + +const { PG_HOST, PG_PORT, PG_DATABASE, PG_USER, PG_PASSWORD } = process.env; + +const pgPool = new PgPool({ + host: PG_HOST, + port: Number(PG_PORT) || 5432, + database: PG_DATABASE, + user: PG_USER, + password: PG_PASSWORD, + // ssl: true +}); + +const db = drizzle(pgPool); + +console.log('database connection was established successfully.'); + +(async () => { + await migrate(db, { migrationsFolder: path.join(__dirname, '../../../pgMigrations') }); + console.log('database was migrated.'); + + // await seed(db, schema, { count: 100000, seed: 1 }); + + const titlesOfCourtesy = ['Ms.', 'Mrs.', 'Dr.']; + const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100]; + const reorderLevels = [0, 5, 10, 15, 20, 25, 30]; + const quantityPerUnit = [ + '100 - 100 g pieces', + '100 - 250 g bags', + '10 - 200 g glasses', + '10 - 4 oz boxes', + '10 - 500 g pkgs.', + '10 - 500 g pkgs.', + '10 boxes x 12 pieces', + '10 boxes x 20 bags', + '10 boxes x 8 pieces', + '10 kg pkg.', + '10 pkgs.', + '12 - 100 g bars', + '12 - 100 g pkgs', + '12 - 12 oz cans', + '12 - 1 lb pkgs.', + '12 - 200 ml jars', + '12 - 250 g pkgs.', + '12 - 355 ml cans', + '12 - 500 g pkgs.', + '750 cc per bottle', + '5 kg pkg.', + '50 bags x 30 sausgs.', + '500 ml', + '500 g', + '48 pieces', + '48 - 6 oz jars', + '4 - 450 g glasses', + '36 boxes', + '32 - 8 oz bottles', + '32 - 500 g boxes', + ]; + const discounts = [0.05, 0.15, 0.2, 0.25]; + + await seed(db, schema).refine((funcs) => ({ + customers: { + count: 10000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + fax: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + employees: { + count: 200, + columns: { + firstName: funcs.firstName({}), + lastName: funcs.lastName({}), + title: funcs.jobTitle({}), + titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }), + birthDate: funcs.date({ minDate: '1990-01-01', maxDate: '2010-12-31' }), + hireDate: funcs.date({ minDate: '2010-12-31', maxDate: '2024-08-26' }), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + country: funcs.country({}), + homePhone: funcs.phoneNumber({ template: '(###) ###-####' }), + extension: funcs.int({ minValue: 428, maxValue: 5467 }), + notes: funcs.loremIpsum({}), + }, + }, + orders: { + count: 50000, + columns: { + shipVia: funcs.int({ minValue: 1, maxValue: 3 }), + freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }), + shipName: funcs.streetAddress({}), + shipCity: funcs.city({}), + shipRegion: funcs.state({}), + shipPostalCode: funcs.postcode({}), + shipCountry: funcs.country({}), + }, + with: { + details: [ + { weight: 0.6, count: [1, 2, 3, 4] }, + { weight: 0.2, count: [5, 6, 7, 8, 9, 10] }, + { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] }, + { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] }, + ], + }, + }, + suppliers: { + count: 1000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + products: { + count: 5000, + columns: { + name: funcs.companyName({}), + quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }), + unitPrice: funcs.weightedRandom( + [ + { + weight: 0.5, + value: funcs.int({ minValue: 3, maxValue: 300 }), + }, + { + weight: 0.5, + value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 }), + }, + ], + ), + unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }), + unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }), + reorderLevel: funcs.valuesFromArray({ values: reorderLevels }), + discontinued: funcs.int({ minValue: 0, maxValue: 1 }), + }, + }, + details: { + columns: { + unitPrice: funcs.number({ minValue: 10, maxValue: 130 }), + quantity: funcs.int({ minValue: 1, maxValue: 130 }), + discount: funcs.weightedRandom( + [ + { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) }, + { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }, + ], + ), + }, + }, + })); + + await pgPool.end(); +})().then(); diff --git a/drizzle-seed/src/tests/northwind/sqliteSchema.ts b/drizzle-seed/src/tests/northwind/sqliteSchema.ts new file mode 100644 index 000000000..5a053dcad --- /dev/null +++ b/drizzle-seed/src/tests/northwind/sqliteSchema.ts @@ -0,0 +1,131 @@ +// import { integer, text, sqliteTable } from "drizzle-orm/sqlite-core"; + +// export const users = sqliteTable("users", { +// id: integer("id").primaryKey(), +// name: text("name", { length: 256 }), +// email: text("email", { length: 256 }), +// phone: text("phone", { length: 256 }), +// password: text("password", { length: 256 }) +// }); + +// export const posts = sqliteTable("posts", { +// id: integer("id").primaryKey(), +// title: text("title", { length: 256 }), +// content: text("content", { length: 256 }), +// userId: integer("user_id").references(() => users.id) +// }); + +// export const comments = sqliteTable("comments", { +// id: integer("id").primaryKey(), +// content: text("content", { length: 256 }), +// postId: integer("post_id").references(() => posts.id), +// userId: integer("user_id").references(() => users.id) +// }); + +import { foreignKey, integer, numeric, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const customers = sqliteTable('customer', { + id: text('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = sqliteTable( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: integer('birth_date', { mode: 'timestamp' }).notNull(), + hireDate: integer('hire_date', { mode: 'timestamp' }).notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to'), + photoPath: text('photo_path'), + }, + (table) => ({ + reportsToFk: foreignKey(() => ({ + columns: [table.reportsTo], + foreignColumns: [table.id], + })), + }), +); + +export const orders = sqliteTable('order', { + id: integer('id').primaryKey(), + orderDate: integer('order_date', { mode: 'timestamp' }).notNull(), + requiredDate: integer('required_date', { mode: 'timestamp' }).notNull(), + shippedDate: integer('shipped_date', { mode: 'timestamp' }), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = sqliteTable('supplier', { + id: integer('id').primaryKey({ autoIncrement: true }), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = sqliteTable('product', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = sqliteTable('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); diff --git a/drizzle-seed/src/tests/northwind/sqliteTest.ts b/drizzle-seed/src/tests/northwind/sqliteTest.ts new file mode 100644 index 000000000..4f9d328d5 --- /dev/null +++ b/drizzle-seed/src/tests/northwind/sqliteTest.ts @@ -0,0 +1,164 @@ +import 'dotenv/config'; +import path from 'path'; + +import betterSqlite3 from 'better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import { migrate } from 'drizzle-orm/better-sqlite3/migrator'; + +import { seed } from '../../index.ts'; +import * as schema from './sqliteSchema.ts'; + +const { Sqlite_PATH } = process.env; +const sqliteDb = betterSqlite3(Sqlite_PATH); +const db = drizzle(sqliteDb); + +console.log('database connection was established successfully.'); + +(async () => { + migrate(db, { migrationsFolder: path.join(__dirname, '../../../sqliteMigrations') }); + console.log('database was migrated.'); + + // await seed(db, schema, { count: 100000, seed: 1 }); + + const titlesOfCourtesy = ['Ms.', 'Mrs.', 'Dr.']; + const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100]; + const reorderLevels = [0, 5, 10, 15, 20, 25, 30]; + const quantityPerUnit = [ + '100 - 100 g pieces', + '100 - 250 g bags', + '10 - 200 g glasses', + '10 - 4 oz boxes', + '10 - 500 g pkgs.', + '10 - 500 g pkgs.', + '10 boxes x 12 pieces', + '10 boxes x 20 bags', + '10 boxes x 8 pieces', + '10 kg pkg.', + '10 pkgs.', + '12 - 100 g bars', + '12 - 100 g pkgs', + '12 - 12 oz cans', + '12 - 1 lb pkgs.', + '12 - 200 ml jars', + '12 - 250 g pkgs.', + '12 - 355 ml cans', + '12 - 500 g pkgs.', + '750 cc per bottle', + '5 kg pkg.', + '50 bags x 30 sausgs.', + '500 ml', + '500 g', + '48 pieces', + '48 - 6 oz jars', + '4 - 450 g glasses', + '36 boxes', + '32 - 8 oz bottles', + '32 - 500 g boxes', + ]; + const discounts = [0.05, 0.15, 0.2, 0.25]; + + await seed(db, schema).refine((funcs) => ({ + customers: { + count: 10000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + fax: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + employees: { + count: 200, + columns: { + firstName: funcs.firstName({}), + lastName: funcs.lastName({}), + title: funcs.jobTitle({}), + titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }), + birthDate: funcs.date({ minDate: '1990-01-01', maxDate: '2010-12-31' }), + hireDate: funcs.date({ minDate: '2010-12-31', maxDate: '2024-08-26' }), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + country: funcs.country({}), + homePhone: funcs.phoneNumber({ template: '(###) ###-####' }), + extension: funcs.int({ minValue: 428, maxValue: 5467 }), + notes: funcs.loremIpsum({}), + }, + }, + orders: { + count: 50000, + columns: { + shipVia: funcs.int({ minValue: 1, maxValue: 3 }), + freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }), + shipName: funcs.streetAddress({}), + shipCity: funcs.city({}), + shipRegion: funcs.state({}), + shipPostalCode: funcs.postcode({}), + shipCountry: funcs.country({}), + }, + with: { + details: [ + { weight: 0.6, count: [1, 2, 3, 4] }, + { weight: 0.2, count: [5, 6, 7, 8, 9, 10] }, + { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] }, + { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] }, + ], + }, + }, + suppliers: { + count: 1000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + products: { + count: 5000, + columns: { + name: funcs.companyName({}), + quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }), + unitPrice: funcs.weightedRandom( + [ + { + weight: 0.5, + value: funcs.int({ minValue: 3, maxValue: 300 }), + }, + { + weight: 0.5, + value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 }), + }, + ], + ), + unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }), + unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }), + reorderLevel: funcs.valuesFromArray({ values: reorderLevels }), + discontinued: funcs.int({ minValue: 0, maxValue: 1 }), + }, + }, + details: { + columns: { + unitPrice: funcs.number({ minValue: 10, maxValue: 130 }), + quantity: funcs.int({ minValue: 1, maxValue: 130 }), + discount: funcs.weightedRandom( + [ + { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) }, + { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }, + ], + ), + }, + }, + })); +})().then(); diff --git a/drizzle-seed/src/tests/pg/allDataTypesTest/drizzle.config.ts b/drizzle-seed/src/tests/pg/allDataTypesTest/drizzle.config.ts new file mode 100644 index 000000000..131b4d025 --- /dev/null +++ b/drizzle-seed/src/tests/pg/allDataTypesTest/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/pg/allDataTypesTest/pgSchema.ts', + out: './src/tests/pg/allDataTypesTest/pgMigrations', + dialect: 'postgresql', +}); diff --git a/drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts b/drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts new file mode 100644 index 000000000..c8dd22355 --- /dev/null +++ b/drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts @@ -0,0 +1,62 @@ +import { + bigint, + bigserial, + boolean, + char, + date, + decimal, + doublePrecision, + integer, + interval, + json, + jsonb, + line, + numeric, + pgEnum, + pgSchema, + point, + real, + serial, + smallint, + smallserial, + text, + time, + timestamp, + varchar, +} from 'drizzle-orm/pg-core'; + +export const schema = pgSchema('seeder_lib_pg'); + +export const moodEnum = pgEnum('mood_enum', ['sad', 'ok', 'happy']); + +export const allDataTypes = schema.table('all_data_types', { + integer: integer('integer'), + smallint: smallint('smallint'), + biginteger: bigint('bigint', { mode: 'bigint' }), + bigintNumber: bigint('bigint_number', { mode: 'number' }), + serial: serial('serial'), + smallserial: smallserial('smallserial'), + bigserial: bigserial('bigserial', { mode: 'bigint' }), + bigserialNumber: bigserial('bigserial_number', { mode: 'number' }), + boolean: boolean('boolean'), + text: text('text'), + varchar: varchar('varchar', { length: 256 }), + char: char('char', { length: 256 }), + numeric: numeric('numeric'), + decimal: decimal('decimal'), + real: real('real'), + doublePrecision: doublePrecision('double_precision'), + json: json('json'), + jsonb: jsonb('jsonb'), + time: time('time'), + timestampDate: timestamp('timestamp_date', { mode: 'date' }), + timestampString: timestamp('timestamp_string', { mode: 'string' }), + dateString: date('date_string', { mode: 'string' }), + date: date('date', { mode: 'date' }), + interval: interval('interval'), + point: point('point', { mode: 'xy' }), + pointTuple: point('point_tuple', { mode: 'tuple' }), + line: line('line', { mode: 'abc' }), + lineTuple: line('line_tuple', { mode: 'tuple' }), + moodEnum: moodEnum('mood_enum'), +}); diff --git a/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts b/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts new file mode 100644 index 000000000..b876915b2 --- /dev/null +++ b/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts @@ -0,0 +1,78 @@ +import { PGlite } from '@electric-sql/pglite'; +import { sql } from 'drizzle-orm'; +import type { PgliteDatabase } from 'drizzle-orm/pglite'; +import { drizzle } from 'drizzle-orm/pglite'; +import { afterAll, beforeAll, expect, test } from 'vitest'; +import { seed } from '../../../index.ts'; +import * as schema from './pgSchema.ts'; + +let client: PGlite; +let db: PgliteDatabase; + +beforeAll(async () => { + client = new PGlite(); + + db = drizzle(client); + + await db.execute(sql`CREATE SCHEMA "seeder_lib_pg";`); + + await db.execute( + sql` + DO $$ BEGIN + CREATE TYPE "seeder_lib_pg"."mood_enum" AS ENUM('sad', 'ok', 'happy'); + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."all_data_types" ( + "integer" integer, + "smallint" smallint, + "bigint" bigint, + "bigint_number" bigint, + "serial" serial NOT NULL, + "smallserial" "smallserial" NOT NULL, + "bigserial" bigserial, + "bigserial_number" bigserial NOT NULL, + "boolean" boolean, + "text" text, + "varchar" varchar(256), + "char" char(256), + "numeric" numeric, + "decimal" numeric, + "real" real, + "double_precision" double precision, + "json" json, + "jsonb" jsonb, + "time" time, + "timestamp_date" timestamp, + "timestamp_string" timestamp, + "date_string" date, + "date" date, + "interval" interval, + "point" "point", + "point_tuple" "point", + "line" "line", + "line_tuple" "line", + "mood_enum" "seeder_lib_pg"."mood_enum" + ); + `, + ); +}); + +afterAll(async () => { + await client.close(); +}); + +test('all data types test', async () => { + await seed(db, schema, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); diff --git a/drizzle-seed/src/tests/pg/drizzle.config.ts b/drizzle-seed/src/tests/pg/drizzle.config.ts new file mode 100644 index 000000000..65b65236f --- /dev/null +++ b/drizzle-seed/src/tests/pg/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/pg/pgSchema.ts', + out: './src/tests/pg/pgMigrations', + dialect: 'postgresql', +}); diff --git a/drizzle-seed/src/tests/pg/generatorsTest/drizzle.config.ts b/drizzle-seed/src/tests/pg/generatorsTest/drizzle.config.ts new file mode 100644 index 000000000..30331986c --- /dev/null +++ b/drizzle-seed/src/tests/pg/generatorsTest/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/pg/generatorsTest/pgSchema.ts', + out: './src/tests/pg/generatorsTest/pgMigrations', + dialect: 'postgresql', +}); diff --git a/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts b/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts new file mode 100644 index 000000000..5f8356da5 --- /dev/null +++ b/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts @@ -0,0 +1,1370 @@ +import { afterAll, beforeAll, expect, test } from 'vitest'; + +import { PGlite } from '@electric-sql/pglite'; +import type { PgliteDatabase } from 'drizzle-orm/pglite'; +import { drizzle } from 'drizzle-orm/pglite'; + +import { reset, seed } from '../../../index.ts'; +import * as schema from './pgSchema.ts'; + +import { sql } from 'drizzle-orm'; +import firstNames from '../../../datasets/firstNames.ts'; +import lastNames from '../../../datasets/lastNames.ts'; + +let client: PGlite; +let db: PgliteDatabase; + +beforeAll(async () => { + client = new PGlite(); + + db = drizzle(client); + + await db.execute(sql`CREATE SCHEMA "seeder_lib_pg";`); + + await db.execute( + sql` + DO $$ BEGIN + CREATE TYPE "seeder_lib_pg"."enum" AS ENUM('sad', 'ok', 'happy'); + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."boolean_table" ( + "boolean" boolean + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_table" ( + "city" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_unique_table" ( + "city_unique" varchar(256), + CONSTRAINT "city_unique_table_city_unique_unique" UNIQUE("city_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_table" ( + "company_name" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_unique_table" ( + "company_name_unique" varchar(256), + CONSTRAINT "company_name_unique_table_company_name_unique_unique" UNIQUE("company_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_table" ( + "country" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_unique_table" ( + "country_unique" varchar(256), + CONSTRAINT "country_unique_table_country_unique_unique" UNIQUE("country_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."date_table" ( + "date" date + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."default_table" ( + "default_string" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."email_table" ( + "email" varchar(256), + CONSTRAINT "email_table_email_unique" UNIQUE("email") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."enum_table" ( + "mood_enum" "seeder_lib_pg"."enum" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."first_name_table" ( + "first_name" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."first_name_unique_table" ( + "first_name_unique" varchar(256), + CONSTRAINT "first_name_unique_table_first_name_unique_unique" UNIQUE("first_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name__table" ( + "full_name_" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name_unique_table" ( + "full_name_unique" varchar(256), + CONSTRAINT "full_name_unique_table_full_name_unique_unique" UNIQUE("full_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_primary_key_table" ( + "int_primary_key" integer, + CONSTRAINT "int_primary_key_table_int_primary_key_unique" UNIQUE("int_primary_key") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_table" ( + "int" integer + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_unique_table" ( + "int_unique" integer, + CONSTRAINT "int_unique_table_int_unique_unique" UNIQUE("int_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_table" ( + "interval" interval + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_unique_table" ( + "interval_unique" interval, + CONSTRAINT "interval_unique_table_interval_unique_unique" UNIQUE("interval_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."job_Title_table" ( + "job_title" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."json_table" ( + "json" json + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_table" ( + "last_name" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_unique_table" ( + "last_name_unique" varchar(256), + CONSTRAINT "last_name_unique_table_last_name_unique_unique" UNIQUE("last_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."line_table" ( + "line" "line" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."lorem_ipsum_table" ( + "lorem_ipsum" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_table" ( + "number" real + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_unique_table" ( + "number_unique" real, + CONSTRAINT "number_unique_table_number_unique_unique" UNIQUE("number_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."phone_number_table" ( + "phoneNumber" varchar(256), + "phone_number_template" varchar(256), + "phone_number_prefixes" varchar(256), + CONSTRAINT "phone_number_table_phoneNumber_unique" UNIQUE("phoneNumber"), + CONSTRAINT "phone_number_table_phone_number_template_unique" UNIQUE("phone_number_template"), + CONSTRAINT "phone_number_table_phone_number_prefixes_unique" UNIQUE("phone_number_prefixes") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."point_table" ( + "point" "point" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_table" ( + "postcode" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_unique_table" ( + "postcode_unique" varchar(256), + CONSTRAINT "postcode_unique_table_postcode_unique_unique" UNIQUE("postcode_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."state_table" ( + "state" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_table" ( + "street_address" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_unique_table" ( + "street_address_unique" varchar(256), + CONSTRAINT "street_address_unique_table_street_address_unique_unique" UNIQUE("street_address_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_table" ( + "string" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_unique_table" ( + "string_unique" varchar(256), + CONSTRAINT "string_unique_table_string_unique_unique" UNIQUE("string_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."time_table" ( + "time" time + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."timestamp_table" ( + "timestamp" timestamp + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_table" ( + "values_from_array_not_null" varchar(256) NOT NULL, + "values_from_array_weighted_not_null" varchar(256) NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_unique_table" ( + "values_from_array" varchar(256), + "values_from_array_not_null" varchar(256) NOT NULL, + "values_from_array_weighted" varchar(256), + "values_from_array_weighted_not_null" varchar(256) NOT NULL, + CONSTRAINT "values_from_array_unique_table_values_from_array_unique" UNIQUE("values_from_array"), + CONSTRAINT "values_from_array_unique_table_values_from_array_not_null_unique" UNIQUE("values_from_array_not_null"), + CONSTRAINT "values_from_array_unique_table_values_from_array_weighted_unique" UNIQUE("values_from_array_weighted"), + CONSTRAINT "values_from_array_unique_table_values_from_array_weighted_not_null_unique" UNIQUE("values_from_array_weighted_not_null") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."weighted_random_table" ( + "weighted_random" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."weighted_random_with_unique_gens_table" ( + "weighted_random_with_unique_gens" varchar(256), + CONSTRAINT "weighted_random_with_unique_gens_table_weighted_random_with_unique_gens_unique" UNIQUE("weighted_random_with_unique_gens") + ); + `, + ); +}); + +afterAll(async () => { + await client.close(); +}); + +const count = 10000; + +test('enum generator test', async () => { + await seed(db, { enumTable: schema.enumTable }).refine(() => ({ + enumTable: { + count, + }, + })); + + const data = await db.select().from(schema.enumTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('default generator test', async () => { + await seed(db, { defaultTable: schema.defaultTable }).refine((funcs) => ({ + defaultTable: { + count, + columns: { + defaultString: funcs.default({ defaultValue: 'default string' }), + }, + }, + })); + + const data = await db.select().from(schema.defaultTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('valuesFromArray generator test', async () => { + await seed(db, { valuesFromArrayTable: schema.valuesFromArrayTable }).refine((funcs) => ({ + valuesFromArrayTable: { + count, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ values: lastNames }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames, weight: 0.3 }, + { values: firstNames, weight: 0.7 }, + ], + }), + }, + }, + })); + + const data = await db.select().from(schema.valuesFromArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('valuesFromArray unique generator test', async () => { + // valuesFromArrayUniqueTable----------------------------------------------------------------------------------- + await seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }, { seed: 1 }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArray: funcs.valuesFromArray({ values: lastNames.slice(0, 20), isUnique: true }), + valuesFromArrayNotNull: funcs.valuesFromArray({ values: lastNames, isUnique: true }), + valuesFromArrayWeighted: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 20000), weight: 0.3 }, + { values: lastNames.slice(20000), weight: 0.7 }, + ], + isUnique: true, + }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 14920), weight: 0.3 }, + { values: lastNames.slice(14920), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })); + + const data = await db.select().from(schema.valuesFromArrayUniqueTable); + // console.log(valuesFromArrayUniqueTableData); + const predicate = data.length !== 0 && data.every((row) => + row['valuesFromArrayWeightedNotNull'] !== null + && row['valuesFromArrayNotNull'] !== null + ); + expect(predicate).toBe(true); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 20000), weight: 0.3 }, + { values: lastNames.slice(20000), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow( + /^weighted values arrays is too small to generate values with specified probability for unique not null column\..+/, + ); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ + values: lastNames.slice(20), + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow('there are no enough values to fill unique column.'); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }, { seed: 1 }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49999, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ + values: lastNames, + isUnique: true, + }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 14854), weight: 0.3 }, + { values: lastNames.slice(14854), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow('there are no enough values to fill unique column.'); +}); + +test('intPrimaryKey generator test', async () => { + await seed(db, { intPrimaryKeyTable: schema.intPrimaryKeyTable }).refine((funcs) => ({ + intPrimaryKeyTable: { + count, + columns: { + intPrimaryKey: funcs.intPrimaryKey(), + }, + }, + })); + + const data = await db.select().from(schema.intPrimaryKeyTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('number generator test', async () => { + await seed(db, { numberTable: schema.numberTable }).refine((funcs) => ({ + numberTable: { + count, + columns: { + number: funcs.number(), + }, + }, + })); + + const data = await db.select().from(schema.numberTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('number unique generator test', async () => { + // numberUniqueTable----------------------------------------------------------------------------------- + await seed(db, { numberUniqueTable: schema.numberUniqueTable }).refine((funcs) => ({ + numberUniqueTable: { + count: 20070, + columns: { + numberUnique: funcs.number({ isUnique: true, minValue: -100.23, maxValue: 100.46 }), + }, + }, + })); + + const data = await db.select().from(schema.numberUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && val >= -100.23 && val <= 100.46) + ); + expect(predicate).toBe(true); + + await expect( + seed(db, { numberUniqueTable: schema.numberUniqueTable }).refine((funcs) => ({ + numberUniqueTable: { + count: 20071, + columns: { + numberUnique: funcs.number({ isUnique: true, minValue: -100.23, maxValue: 100.46 }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); +}); + +test('int generator test', async () => { + await seed(db, { intTable: schema.intTable }).refine((funcs) => ({ + intTable: { + count, + columns: { + int: funcs.int(), + }, + }, + })); + + const data = await db.select().from(schema.intTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('int unique generator test', async () => { + // intUniqueTable----------------------------------------------------------------------------------- + await seed(db, { intUniqueTable: schema.intUniqueTable }).refine((funcs) => ({ + intUniqueTable: { + count: 201, + columns: { + intUnique: funcs.int({ isUnique: true, minValue: -100, maxValue: 100 }), + }, + }, + })); + + const data = await db.select().from(schema.intUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { intUniqueTable: schema.intUniqueTable }).refine((funcs) => ({ + intUniqueTable: { + count: 202, + columns: { + intUnique: funcs.int({ isUnique: true, minValue: -100, maxValue: 100 }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); +}); + +test('boolean generator test', async () => { + await seed(db, { booleanTable: schema.booleanTable }).refine((funcs) => ({ + booleanTable: { + count, + columns: { + boolean: funcs.boolean(), + }, + }, + })); + + const data = await db.select().from(schema.booleanTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('date generator test', async () => { + await seed(db, { dateTable: schema.dateTable }).refine((funcs) => ({ + dateTable: { + count, + columns: { + date: funcs.date(), + }, + }, + })); + + const data = await db.select().from(schema.dateTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('time generator test', async () => { + await seed(db, { timeTable: schema.timeTable }).refine((funcs) => ({ + timeTable: { + count, + columns: { + time: funcs.time(), + }, + }, + })); + + const data = await db.select().from(schema.timeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('timestamp generator test', async () => { + await seed(db, { timestampTable: schema.timestampTable }).refine((funcs) => ({ + timestampTable: { + count, + columns: { + timestamp: funcs.timestamp(), + }, + }, + })); + + const data = await db.select().from(schema.timestampTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('json generator test', async () => { + await seed(db, { jsonTable: schema.jsonTable }).refine((funcs) => ({ + jsonTable: { + count, + columns: { + json: funcs.json(), + }, + }, + })); + + const data = await db.select().from(schema.jsonTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('interval generator test', async () => { + await seed(db, { intervalTable: schema.intervalTable }).refine((funcs) => ({ + intervalTable: { + count, + columns: { + interval: funcs.interval(), + }, + }, + })); + + const data = await db.select().from(schema.intervalTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('interval unique generator test', async () => { + // intervalUniqueTable----------------------------------------------------------------------------------- + await seed(db, { intervalUniqueTable: schema.intervalUniqueTable }).refine((funcs) => ({ + intervalUniqueTable: { + count, + columns: { + intervalUnique: funcs.interval({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.intervalUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('string generator test', async () => { + await seed(db, { stringTable: schema.stringTable }).refine((funcs) => ({ + stringTable: { + count, + columns: { + string: funcs.string(), + }, + }, + })); + + const data = await db.select().from(schema.stringTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('string unique generator test', async () => { + await seed(db, { stringUniqueTable: schema.stringUniqueTable }).refine((funcs) => ({ + stringUniqueTable: { + count, + columns: { + stringUnique: funcs.string({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.stringUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('email generator test', async () => { + await seed(db, { emailTable: schema.emailTable }).refine((funcs) => ({ + emailTable: { + count, + columns: { + email: funcs.email(), + }, + }, + })); + + const data = await db.select().from(schema.emailTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('firstName generator test', async () => { + await seed(db, { firstNameTable: schema.firstNameTable }).refine((funcs) => ({ + firstNameTable: { + count, + columns: { + firstName: funcs.firstName(), + }, + }, + })); + + const data = await db.select().from(schema.firstNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('firstName unique generator test', async () => { + // firstNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { firstNameUniqueTable: schema.firstNameUniqueTable }).refine((funcs) => ({ + firstNameUniqueTable: { + count: 30274, + columns: { + firstNameUnique: funcs.firstName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.firstNameUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { firstNameUniqueTable: schema.firstNameUniqueTable }, { count: 30275 }).refine((funcs) => ({ + firstNameUniqueTable: { + count: 30275, + columns: { + firstNameUnique: funcs.firstName({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique first names.'); +}); + +test('lastName generator test', async () => { + await seed(db, { lastNameTable: schema.lastNameTable }).refine((funcs) => ({ + lastNameTable: { + count, + columns: { + lastName: funcs.lastName(), + }, + }, + })); + + const data = await db.select().from(schema.lastNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('lastName unique generator test', async () => { + // lastNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { lastNameUniqueTable: schema.lastNameUniqueTable }).refine((funcs) => ({ + lastNameUniqueTable: { + count: 49998, + columns: { + lastNameUnique: funcs.lastName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.lastNameUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { lastNameUniqueTable: schema.lastNameUniqueTable }).refine((funcs) => ({ + lastNameUniqueTable: { + count: 49999, + columns: { + lastNameUnique: funcs.lastName({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique last names.'); +}); + +test('fullName generator test', async () => { + await seed(db, { fullNameTable: schema.fullNameTable }).refine((funcs) => ({ + fullNameTable: { + count, + columns: { + fullName: funcs.fullName(), + }, + }, + })); + + const data = await db.select().from(schema.fullNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('fullName unique generator test', async () => { + // fullNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { fullNameUniqueTable: schema.fullNameUniqueTable }).refine((funcs) => ({ + fullNameUniqueTable: { + count, + columns: { + fullNameUnique: funcs.fullName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.fullNameUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('country generator test', async () => { + await seed(db, { countryTable: schema.countryTable }).refine((funcs) => ({ + countryTable: { + count, + columns: { + country: funcs.country(), + }, + }, + })); + + const data = await db.select().from(schema.countryTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('country unique generator test', async () => { + // countryUniqueTable----------------------------------------------------------------------------------- + await seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ + countryUniqueTable: { + count: 167, + columns: { + countryUnique: funcs.country({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.countryUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ + countryUniqueTable: { + count: 168, + columns: { + countryUnique: funcs.country({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique countries.'); +}); + +test('city generator test', async () => { + await seed(db, { cityTable: schema.cityTable }).refine((funcs) => ({ + cityTable: { + count, + columns: { + city: funcs.city(), + }, + }, + })); + + const data = await db.select().from(schema.cityTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('city unique generator test', async () => { + // cityUniqueTable----------------------------------------------------------------------------------- + await reset(db, { cityUniqueTable: schema.cityUniqueTable }); + await seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ + cityUniqueTable: { + count: 42984, + columns: { + cityUnique: funcs.city({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.cityUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ + cityUniqueTable: { + count: 42985, + columns: { + cityUnique: funcs.city({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique cities.'); +}); + +test('streetAddress generator test', async () => { + await seed(db, { streetAddressTable: schema.streetAddressTable }).refine((funcs) => ({ + streetAddressTable: { + count, + columns: { + streetAddress: funcs.streetAddress(), + }, + }, + })); + + const data = await db.select().from(schema.streetAddressTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('streetAddress unique generator test', async () => { + await seed(db, { streetAddressUniqueTable: schema.streetAddressUniqueTable }).refine((funcs) => ({ + streetAddressUniqueTable: { + count, + columns: { + streetAddressUnique: funcs.streetAddress({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.streetAddressUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('jobTitle generator test', async () => { + await seed(db, { jobTitleTable: schema.jobTitleTable }).refine((funcs) => ({ + jobTitleTable: { + count, + columns: { + jobTitle: funcs.jobTitle(), + }, + }, + })); + + const data = await db.select().from(schema.jobTitleTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('postcode generator test', async () => { + await seed(db, { postcodeTable: schema.postcodeTable }).refine((funcs) => ({ + postcodeTable: { + count, + columns: { + postcode: funcs.postcode(), + }, + }, + })); + + const data = await db.select().from(schema.postcodeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('postcode unique generator test', async () => { + await seed(db, { postcodeUniqueTable: schema.postcodeUniqueTable }).refine((funcs) => ({ + postcodeUniqueTable: { + count, + columns: { + postcodeUnique: funcs.postcode({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.postcodeUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('state generator test', async () => { + await seed(db, { stateTable: schema.stateTable }).refine((funcs) => ({ + stateTable: { + count, + columns: { + state: funcs.state(), + }, + }, + })); + + const data = await db.select().from(schema.stateTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('companyName generator test', async () => { + await seed(db, { companyNameTable: schema.companyNameTable }).refine((funcs) => ({ + companyNameTable: { + count, + columns: { + companyName: funcs.companyName(), + }, + }, + })); + + const data = await db.select().from(schema.companyNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('companyName unique generator test', async () => { + await seed(db, { companyNameUniqueTable: schema.companyNameUniqueTable }).refine((funcs) => ({ + companyNameUniqueTable: { + count, + columns: { + companyNameUnique: funcs.companyName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.companyNameUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('loremIpsum generator test', async () => { + await seed(db, { loremIpsumTable: schema.loremIpsumTable }).refine((funcs) => ({ + loremIpsumTable: { + count, + columns: { + loremIpsum: funcs.loremIpsum(), + }, + }, + })); + + const data = await db.select().from(schema.loremIpsumTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('point generator test', async () => { + await seed(db, { pointTable: schema.pointTable }).refine((funcs) => ({ + pointTable: { + count, + columns: { + point: funcs.point(), + }, + }, + })); + + const data = await db.select().from(schema.pointTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('point unique generator test', async () => { + await reset(db, { pointTable: schema.pointTable }); + await seed(db, { pointTable: schema.pointTable }).refine((funcs) => ({ + pointTable: { + count, + columns: { + point: funcs.point({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.pointTable); + // every value in each row does not equal undefined. + let predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + // using Set because PGlite does not support unique point + const pointStrsSet = new Set(data.map((row) => row.point!.map(String).join(','))); + predicate = pointStrsSet.size === data.length; + expect(predicate).toBe(true); +}); + +test('line generator test', async () => { + await seed(db, { lineTable: schema.lineTable }).refine((funcs) => ({ + lineTable: { + count, + columns: { + line: funcs.line(), + }, + }, + })); + + const data = await db.select().from(schema.lineTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('line unique generator test', async () => { + await reset(db, { lineTable: schema.lineTable }); + await seed(db, { lineTable: schema.lineTable }).refine((funcs) => ({ + lineTable: { + count, + columns: { + line: funcs.line({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.lineTable); + // every value in each row does not equal undefined. + let predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + // using Set because PGlite does not support unique point + const lineStrsSet = new Set(data.map((row) => row.line!.map(String).join(','))); + predicate = lineStrsSet.size === data.length; + expect(predicate).toBe(true); +}); + +test('phoneNumber generator test', async () => { + await seed(db, { phoneNumberTable: schema.phoneNumberTable }).refine((funcs) => ({ + phoneNumberTable: { + count, + columns: { + phoneNumber: funcs.phoneNumber(), + phoneNumberPrefixes: funcs.phoneNumber({ + prefixes: ['+380 99', '+380 67', '+1'], + generatedDigitsNumbers: [7, 7, 10], + }), + phoneNumberTemplate: funcs.phoneNumber({ template: '+380 ## ## ### ##' }), + }, + }, + })); + + const data = await db.select().from(schema.phoneNumberTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('weightedRandom generator test', async () => { + await seed(db, { weightedRandomTable: schema.weightedRandomTable }).refine((funcs) => ({ + weightedRandomTable: { + count, + columns: { + weightedRandom: funcs.weightedRandom([ + { value: funcs.default({ defaultValue: 'default value' }), weight: 0.3 }, + { value: funcs.loremIpsum(), weight: 0.7 }, + ]), + }, + }, + })); + + const data = await db.select().from(schema.weightedRandomTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('weightedRandom with unique gens generator test', async () => { + await seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 10000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.3, value: funcs.email() }, + { weight: 0.7, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })); + + const data = await db.select().from(schema.weightedRandomWithUniqueGensTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 40000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.1, value: funcs.email() }, + { weight: 0.9, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique first names.'); + + await expect( + seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 10000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.2, value: funcs.email() }, + { weight: 0.9, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })), + ).rejects.toThrow("sum of all weights don't equal to 1; 1.1 !== 1"); +}); diff --git a/drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts b/drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts new file mode 100644 index 000000000..57f585297 --- /dev/null +++ b/drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts @@ -0,0 +1,205 @@ +import { + boolean, + date, + integer, + interval, + json, + line, + pgSchema, + point, + real, + text, + time, + timestamp, + varchar, +} from 'drizzle-orm/pg-core'; + +export const schema = pgSchema('seeder_lib_pg'); + +export const moodEnum = schema.enum('enum', ['sad', 'ok', 'happy']); + +export const enumTable = schema.table('enum_table', { + mood: moodEnum('mood_enum'), +}); + +export const defaultTable = schema.table('default_table', { + defaultString: text('default_string'), +}); + +export const valuesFromArrayTable = schema.table('values_from_array_table', { + valuesFromArrayNotNull: varchar('values_from_array_not_null', { length: 256 }).notNull(), + valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).notNull(), +}); + +export const valuesFromArrayUniqueTable = schema.table('values_from_array_unique_table', { + valuesFromArray: varchar('values_from_array', { length: 256 }).unique(), + valuesFromArrayNotNull: varchar('values_from_array_not_null', { length: 256 }).unique().notNull(), + valuesFromArrayWeighted: varchar('values_from_array_weighted', { length: 256 }).unique(), + valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).unique().notNull(), +}); + +export const intPrimaryKeyTable = schema.table('int_primary_key_table', { + intPrimaryKey: integer('int_primary_key').unique(), +}); + +export const numberTable = schema.table('number_table', { + number: real('number'), +}); + +export const numberUniqueTable = schema.table('number_unique_table', { + numberUnique: real('number_unique').unique(), +}); + +export const intTable = schema.table('int_table', { + int: integer('int'), +}); + +export const intUniqueTable = schema.table('int_unique_table', { + intUnique: integer('int_unique').unique(), +}); + +export const booleanTable = schema.table('boolean_table', { + boolean: boolean('boolean'), +}); + +export const dateTable = schema.table('date_table', { + date: date('date'), +}); + +export const timeTable = schema.table('time_table', { + time: time('time'), +}); + +export const timestampTable = schema.table('timestamp_table', { + timestamp: timestamp('timestamp'), +}); + +export const jsonTable = schema.table('json_table', { + json: json('json'), +}); + +export const intervalTable = schema.table('interval_table', { + interval: interval('interval'), +}); + +export const intervalUniqueTable = schema.table('interval_unique_table', { + intervalUnique: interval('interval_unique').unique(), +}); + +export const stringTable = schema.table('string_table', { + string: text('string'), +}); + +export const stringUniqueTable = schema.table('string_unique_table', { + stringUnique: varchar('string_unique', { length: 256 }).unique(), +}); + +export const emailTable = schema.table('email_table', { + email: varchar('email', { length: 256 }).unique(), +}); + +export const firstNameTable = schema.table('first_name_table', { + firstName: varchar('first_name', { length: 256 }), +}); + +export const firstNameUniqueTable = schema.table('first_name_unique_table', { + firstNameUnique: varchar('first_name_unique', { length: 256 }).unique(), +}); + +export const lastNameTable = schema.table('last_name_table', { + lastName: varchar('last_name', { length: 256 }), +}); + +export const lastNameUniqueTable = schema.table('last_name_unique_table', { + lastNameUnique: varchar('last_name_unique', { length: 256 }).unique(), +}); + +export const fullNameTable = schema.table('full_name__table', { + fullName: varchar('full_name_', { length: 256 }), +}); + +export const fullNameUniqueTable = schema.table('full_name_unique_table', { + fullNameUnique: varchar('full_name_unique', { length: 256 }).unique(), +}); + +export const countryTable = schema.table('country_table', { + country: varchar('country', { length: 256 }), +}); + +export const countryUniqueTable = schema.table('country_unique_table', { + countryUnique: varchar('country_unique', { length: 256 }).unique(), +}); + +export const cityTable = schema.table('city_table', { + city: varchar('city', { length: 256 }), +}); + +export const cityUniqueTable = schema.table('city_unique_table', { + cityUnique: varchar('city_unique', { length: 256 }).unique(), +}); + +export const streetAddressTable = schema.table('street_address_table', { + streetAddress: varchar('street_address', { length: 256 }), +}); + +export const streetAddressUniqueTable = schema.table('street_address_unique_table', { + streetAddressUnique: varchar('street_address_unique', { length: 256 }).unique(), +}); + +export const jobTitleTable = schema.table('job_Title_table', { + jobTitle: text('job_title'), +}); + +export const postcodeTable = schema.table('postcode_table', { + postcode: varchar('postcode', { length: 256 }), +}); + +export const postcodeUniqueTable = schema.table('postcode_unique_table', { + postcodeUnique: varchar('postcode_unique', { length: 256 }).unique(), +}); + +export const stateTable = schema.table('state_table', { + state: text('state'), +}); + +export const companyNameTable = schema.table('company_name_table', { + companyName: text('company_name'), +}); + +export const companyNameUniqueTable = schema.table('company_name_unique_table', { + companyNameUnique: varchar('company_name_unique', { length: 256 }).unique(), +}); + +export const loremIpsumTable = schema.table('lorem_ipsum_table', { + loremIpsum: text('lorem_ipsum'), +}); + +export const pointTable = schema.table('point_table', { + point: point('point'), +}); + +export const lineTable = schema.table('line_table', { + line: line('line'), +}); + +// export const pointUniqueTable = schema.table("point_unique_table", { +// pointUnique: point("point_unique").unique(), +// }); + +// export const lineUniqueTable = schema.table("line_unique_table", { +// lineUnique: line("line_unique").unique(), +// }); + +export const phoneNumberTable = schema.table('phone_number_table', { + phoneNumber: varchar('phoneNumber', { length: 256 }).unique(), + phoneNumberTemplate: varchar('phone_number_template', { length: 256 }).unique(), + phoneNumberPrefixes: varchar('phone_number_prefixes', { length: 256 }).unique(), +}); + +export const weightedRandomTable = schema.table('weighted_random_table', { + weightedRandom: varchar('weighted_random', { length: 256 }), +}); + +export const weightedRandomWithUniqueGensTable = schema.table('weighted_random_with_unique_gens_table', { + weightedRandomWithUniqueGens: varchar('weighted_random_with_unique_gens', { length: 256 }).unique(), +}); diff --git a/drizzle-seed/src/tests/pg/pg.test.ts b/drizzle-seed/src/tests/pg/pg.test.ts new file mode 100644 index 000000000..9aadf28c2 --- /dev/null +++ b/drizzle-seed/src/tests/pg/pg.test.ts @@ -0,0 +1,345 @@ +import { PGlite } from '@electric-sql/pglite'; +import { sql } from 'drizzle-orm'; +import type { PgliteDatabase } from 'drizzle-orm/pglite'; +import { drizzle } from 'drizzle-orm/pglite'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../index.ts'; +import * as schema from './pgSchema.ts'; + +let client: PGlite; +let db: PgliteDatabase; + +beforeAll(async () => { + client = new PGlite(); + + db = drizzle(client); + + await db.execute(sql`CREATE SCHEMA "seeder_lib_pg";`); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."customer" ( + "id" varchar(256) PRIMARY KEY NOT NULL, + "company_name" text NOT NULL, + "contact_name" text NOT NULL, + "contact_title" text NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "postal_code" text, + "region" text, + "country" text NOT NULL, + "phone" text NOT NULL, + "fax" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."order_detail" ( + "unit_price" numeric NOT NULL, + "quantity" integer NOT NULL, + "discount" numeric NOT NULL, + "order_id" integer NOT NULL, + "product_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."employee" ( + "id" integer PRIMARY KEY NOT NULL, + "last_name" text NOT NULL, + "first_name" text, + "title" text NOT NULL, + "title_of_courtesy" text NOT NULL, + "birth_date" timestamp NOT NULL, + "hire_date" timestamp NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "postal_code" text NOT NULL, + "country" text NOT NULL, + "home_phone" text NOT NULL, + "extension" integer NOT NULL, + "notes" text NOT NULL, + "reports_to" integer, + "photo_path" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."order" ( + "id" integer PRIMARY KEY NOT NULL, + "order_date" timestamp NOT NULL, + "required_date" timestamp NOT NULL, + "shipped_date" timestamp, + "ship_via" integer NOT NULL, + "freight" numeric NOT NULL, + "ship_name" text NOT NULL, + "ship_city" text NOT NULL, + "ship_region" text, + "ship_postal_code" text, + "ship_country" text NOT NULL, + "customer_id" text NOT NULL, + "employee_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."product" ( + "id" integer PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "quantity_per_unit" text NOT NULL, + "unit_price" numeric NOT NULL, + "units_in_stock" integer NOT NULL, + "units_on_order" integer NOT NULL, + "reorder_level" integer NOT NULL, + "discontinued" integer NOT NULL, + "supplier_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."supplier" ( + "id" integer PRIMARY KEY NOT NULL, + "company_name" text NOT NULL, + "contact_name" text NOT NULL, + "contact_title" text NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "region" text, + "postal_code" text NOT NULL, + "country" text NOT NULL, + "phone" text NOT NULL + ); + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order_detail" ADD CONSTRAINT "order_detail_order_id_order_id_fk" FOREIGN KEY ("order_id") REFERENCES "seeder_lib_pg"."order"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order_detail" ADD CONSTRAINT "order_detail_product_id_product_id_fk" FOREIGN KEY ("product_id") REFERENCES "seeder_lib_pg"."product"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."employee" ADD CONSTRAINT "employee_reports_to_employee_id_fk" FOREIGN KEY ("reports_to") REFERENCES "seeder_lib_pg"."employee"("id") ON DELETE no action ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order" ADD CONSTRAINT "order_customer_id_customer_id_fk" FOREIGN KEY ("customer_id") REFERENCES "seeder_lib_pg"."customer"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order" ADD CONSTRAINT "order_employee_id_employee_id_fk" FOREIGN KEY ("employee_id") REFERENCES "seeder_lib_pg"."employee"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."product" ADD CONSTRAINT "product_supplier_id_supplier_id_fk" FOREIGN KEY ("supplier_id") REFERENCES "seeder_lib_pg"."supplier"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +afterAll(async () => { + await client.close(); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); diff --git a/drizzle-seed/src/tests/pg/pgSchema.ts b/drizzle-seed/src/tests/pg/pgSchema.ts new file mode 100644 index 000000000..fdf42f89b --- /dev/null +++ b/drizzle-seed/src/tests/pg/pgSchema.ts @@ -0,0 +1,130 @@ +// import { serial, integer, varchar, pgSchema, getTableConfig as getPgTableConfig } from "drizzle-orm/pg-core"; + +// export const schema = pgSchema("seeder_lib_pg"); + +// export const users = schema.table("users", { +// id: serial("id").primaryKey(), +// name: varchar("name", { length: 256 }), +// email: varchar("email", { length: 256 }), +// phone: varchar("phone", { length: 256 }), +// password: varchar("password", { length: 256 }) +// }); + +// export const posts = schema.table("posts", { +// id: serial("id").primaryKey(), +// title: varchar("title", { length: 256 }), +// content: varchar("content", { length: 256 }), +// userId: integer("user_id").references(() => users.id) +// }); + +// export const comments = schema.table("comments", { +// id: serial("id").primaryKey(), +// content: varchar("content", { length: 256 }), +// postId: integer("post_id").references(() => posts.id), +// userId: integer("user_id").references(() => users.id) +// }); + +import type { AnyPgColumn } from 'drizzle-orm/pg-core'; +import { integer, numeric, pgSchema, text, timestamp, varchar } from 'drizzle-orm/pg-core'; + +export const schema = pgSchema('seeder_lib_pg'); + +export const customers = schema.table('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = schema.table( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to').references((): AnyPgColumn => employees.id), + photoPath: text('photo_path'), + }, +); + +export const orders = schema.table('order', { + id: integer('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = schema.table('supplier', { + id: integer('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = schema.table('product', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = schema.table('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); diff --git a/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqliteSchema.ts b/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqliteSchema.ts new file mode 100644 index 000000000..f9737344e --- /dev/null +++ b/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqliteSchema.ts @@ -0,0 +1,15 @@ +import { blob, integer, numeric, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const allDataTypes = sqliteTable('all_data_types', { + integerNumber: integer('integer_number', { mode: 'number' }), + integerBoolean: integer('integer_boolean', { mode: 'boolean' }), + integerTimestamp: integer('integer_timestamp', { mode: 'timestamp' }), + integerTimestampms: integer('integer_timestampms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { mode: 'text' }), + textJson: text('text_json', { mode: 'json' }), + blobBigint: blob('blob_bigint', { mode: 'bigint' }), + blobBuffer: blob('blob_buffer', { mode: 'buffer' }), + blobJson: blob('blob_json', { mode: 'json' }), + numeric: numeric('numeric'), +}); diff --git a/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts b/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts new file mode 100644 index 000000000..b377ba9a1 --- /dev/null +++ b/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts @@ -0,0 +1,53 @@ +import BetterSqlite3 from 'better-sqlite3'; +import { sql } from 'drizzle-orm'; +import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import { afterAll, beforeAll, expect, test } from 'vitest'; +import { seed } from '../../../index.ts'; +import * as schema from './sqliteSchema.ts'; + +let client: BetterSqlite3.Database; +let db: BetterSQLite3Database; + +beforeAll(async () => { + client = new BetterSqlite3(':memory:'); + + db = drizzle(client); + + db.run( + sql.raw(` + CREATE TABLE \`all_data_types\` ( + \`integer_number\` integer, + \`integer_boolean\` integer, + \`integer_timestamp\` integer, + \`integer_timestampms\` integer, + \`real\` real, + \`text\` text, + \`text_json\` text, + \`blob_bigint\` blob, + \`blob_buffer\` blob, + \`blob_json\` blob, + \`numeric\` numeric +); + + `), + ); +}); + +afterAll(async () => { + client.close(); +}); + +test('basic seed test', async () => { + // migrate(db, { migrationsFolder: path.join(__dirname, "sqliteMigrations") }); + + await seed(db, schema, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); + + client.close(); +}); diff --git a/drizzle-seed/src/tests/sqlite/sqlite.test.ts b/drizzle-seed/src/tests/sqlite/sqlite.test.ts new file mode 100644 index 000000000..50db1fa8b --- /dev/null +++ b/drizzle-seed/src/tests/sqlite/sqlite.test.ts @@ -0,0 +1,290 @@ +import BetterSqlite3 from 'better-sqlite3'; +import { sql } from 'drizzle-orm'; +import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../index.ts'; +import * as schema from './sqliteSchema.ts'; + +let client: BetterSqlite3.Database; +let db: BetterSQLite3Database; + +beforeAll(async () => { + client = new BetterSqlite3(':memory:'); + + db = drizzle(client); + + db.run( + sql.raw(` + CREATE TABLE \`customer\` ( + \`id\` text PRIMARY KEY NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text, + \`region\` text, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + \`fax\` text +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`order_detail\` ( + \`unit_price\` numeric NOT NULL, + \`quantity\` integer NOT NULL, + \`discount\` numeric NOT NULL, + \`order_id\` integer NOT NULL, + \`product_id\` integer NOT NULL, + FOREIGN KEY (\`order_id\`) REFERENCES \`order\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`product_id\`) REFERENCES \`product\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`employee\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`last_name\` text NOT NULL, + \`first_name\` text, + \`title\` text NOT NULL, + \`title_of_courtesy\` text NOT NULL, + \`birth_date\` integer NOT NULL, + \`hire_date\` integer NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`home_phone\` text NOT NULL, + \`extension\` integer NOT NULL, + \`notes\` text NOT NULL, + \`reports_to\` integer, + \`photo_path\` text, + FOREIGN KEY (\`reports_to\`) REFERENCES \`employee\`(\`id\`) ON UPDATE no action ON DELETE no action +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`order\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`order_date\` integer NOT NULL, + \`required_date\` integer NOT NULL, + \`shipped_date\` integer, + \`ship_via\` integer NOT NULL, + \`freight\` numeric NOT NULL, + \`ship_name\` text NOT NULL, + \`ship_city\` text NOT NULL, + \`ship_region\` text, + \`ship_postal_code\` text, + \`ship_country\` text NOT NULL, + \`customer_id\` text NOT NULL, + \`employee_id\` integer NOT NULL, + FOREIGN KEY (\`customer_id\`) REFERENCES \`customer\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`employee_id\`) REFERENCES \`employee\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`product\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`name\` text NOT NULL, + \`quantity_per_unit\` text NOT NULL, + \`unit_price\` numeric NOT NULL, + \`units_in_stock\` integer NOT NULL, + \`units_on_order\` integer NOT NULL, + \`reorder_level\` integer NOT NULL, + \`discontinued\` integer NOT NULL, + \`supplier_id\` integer NOT NULL, + FOREIGN KEY (\`supplier_id\`) REFERENCES \`supplier\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`supplier\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`region\` text, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`phone\` text NOT NULL +); + `), + ); +}); + +afterAll(async () => { + client.close(); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); diff --git a/drizzle-seed/src/tests/sqlite/sqliteSchema.ts b/drizzle-seed/src/tests/sqlite/sqliteSchema.ts new file mode 100644 index 000000000..5a053dcad --- /dev/null +++ b/drizzle-seed/src/tests/sqlite/sqliteSchema.ts @@ -0,0 +1,131 @@ +// import { integer, text, sqliteTable } from "drizzle-orm/sqlite-core"; + +// export const users = sqliteTable("users", { +// id: integer("id").primaryKey(), +// name: text("name", { length: 256 }), +// email: text("email", { length: 256 }), +// phone: text("phone", { length: 256 }), +// password: text("password", { length: 256 }) +// }); + +// export const posts = sqliteTable("posts", { +// id: integer("id").primaryKey(), +// title: text("title", { length: 256 }), +// content: text("content", { length: 256 }), +// userId: integer("user_id").references(() => users.id) +// }); + +// export const comments = sqliteTable("comments", { +// id: integer("id").primaryKey(), +// content: text("content", { length: 256 }), +// postId: integer("post_id").references(() => posts.id), +// userId: integer("user_id").references(() => users.id) +// }); + +import { foreignKey, integer, numeric, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const customers = sqliteTable('customer', { + id: text('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = sqliteTable( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: integer('birth_date', { mode: 'timestamp' }).notNull(), + hireDate: integer('hire_date', { mode: 'timestamp' }).notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to'), + photoPath: text('photo_path'), + }, + (table) => ({ + reportsToFk: foreignKey(() => ({ + columns: [table.reportsTo], + foreignColumns: [table.id], + })), + }), +); + +export const orders = sqliteTable('order', { + id: integer('id').primaryKey(), + orderDate: integer('order_date', { mode: 'timestamp' }).notNull(), + requiredDate: integer('required_date', { mode: 'timestamp' }).notNull(), + shippedDate: integer('shipped_date', { mode: 'timestamp' }), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = sqliteTable('supplier', { + id: integer('id').primaryKey({ autoIncrement: true }), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = sqliteTable('product', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = sqliteTable('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); diff --git a/drizzle-seed/src/tests/vitest.config.ts b/drizzle-seed/src/tests/vitest.config.ts new file mode 100644 index 000000000..a74ccd37c --- /dev/null +++ b/drizzle-seed/src/tests/vitest.config.ts @@ -0,0 +1,25 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: [ + './src/tests/pg/**/*.test.ts', + './src/tests/mysql/**/*.test.ts', + './src/tests/sqlite/**/*.test.ts', + ], + exclude: [], + typecheck: { + tsconfig: 'tsconfig.json', + }, + testTimeout: 100000, + hookTimeout: 100000, + isolate: true, + poolOptions: { + threads: { + singleThread: true, + }, + }, + maxWorkers: 1, + fileParallelism: false, + }, +}); diff --git a/drizzle-seed/src/types/drizzleStudio.ts b/drizzle-seed/src/types/drizzleStudio.ts new file mode 100644 index 000000000..c3b635b97 --- /dev/null +++ b/drizzle-seed/src/types/drizzleStudio.ts @@ -0,0 +1,65 @@ +export type DbPrimaryKey = { + name: string; + columns: string[]; +}; + +export type DbForeignKey = { + name: string; + tableFrom: string; + columnsFrom: string[]; + schemaFrom: string; + schemaTo: string; + tableTo: string; + columnsTo: string[]; + onUpdate?: string; + onDelete?: string; +}; + +export type DbColumn = { + name: string; + type: string; + primaryKey: boolean; + notNull: boolean; + default?: any; + isUnique?: any; + autoIncrement?: boolean; + uniqueName?: string; + nullsNotDistinct?: boolean; + onUpdate?: boolean; +}; + +export type DbTable = { + name: string; + type: 'table'; + database?: string; + schema: string; + columns: Record; + indexes: Record; + foreignKeys: Record; + compositePrimaryKeys: Record; + uniqueConstraints: Record; +}; + +export type DbView = Omit & { + type: 'view' | 'mat_view'; +}; + +export type DbSchema = { + database?: string; + tables: Record; + views: Record; + enums: Record; +}; + +export type DrizzleStudioObjectType = { [schemaName: string]: DbSchema }; + +export type DrizzleStudioRelationType = { + name: string; + type: 'one' | 'many'; + table: string; + schema: string; + columns: string[]; + refTable: string; + refSchema: string; + refColumns: string[]; +}; diff --git a/drizzle-seed/src/types/seedService.ts b/drizzle-seed/src/types/seedService.ts new file mode 100644 index 000000000..3244a0a12 --- /dev/null +++ b/drizzle-seed/src/types/seedService.ts @@ -0,0 +1,44 @@ +import type { AbstractGenerator } from '../services/GeneratorsWrappers.ts'; +import type { Prettify } from './tables.ts'; + +export type TableGeneratorsType = { + [columnName: string]: Prettify< + { + hasSelfRelation?: boolean | undefined; + hasRelation?: boolean | undefined; + pRNGSeed: number; + } & GeneratePossibleGeneratorsColumnType + >; +}; + +export type GeneratePossibleGeneratorsColumnType = { + columnName: string; + generator: AbstractGenerator | undefined; + isUnique: boolean; + notNull: boolean; +}; + +export type GeneratePossibleGeneratorsTableType = Prettify<{ + tableName: string; + count?: number; + withCount?: number; + withFromTable: { + [withFromTableName: string]: { + repeatedValuesCount: + | number + | { weight: number; count: number | number[] }[]; + weightedCountSeed?: number; + }; + }; + // repeatedValuesCount?: number, + // withFromTableName?: string, + columnsPossibleGenerators: GeneratePossibleGeneratorsColumnType[]; +}>; + +export type RefinementsType = Prettify<{ + [tableName: string]: { + count?: number; + columns: { [columnName: string]: AbstractGenerator<{}> }; + with?: { [tableName: string]: number | { weight: number; count: number | number[] }[] }; + }; +}>; diff --git a/drizzle-seed/src/types/tables.ts b/drizzle-seed/src/types/tables.ts new file mode 100644 index 000000000..206d94be5 --- /dev/null +++ b/drizzle-seed/src/types/tables.ts @@ -0,0 +1,35 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export type Column = { + name: string; + dataType: string; + columnType: string; + default?: any; + hasDefault: boolean; + enumValues?: string[]; + isUnique: boolean; + notNull: boolean; +}; + +export type Table = { + name: string; + columns: Column[]; + primaryKeys: string[]; +}; + +export type Relation = { + // name: string; + // type: "one" | "many"; + table: string; + // schema: string; + columns: string[]; + refTable: string; + // refSchema: string; + refColumns: string[]; +}; + +export type Prettify = + & { + [K in keyof T]: T[K]; + } + & {}; diff --git a/drizzle-seed/tsconfig.build.json b/drizzle-seed/tsconfig.build.json new file mode 100644 index 000000000..3377281ba --- /dev/null +++ b/drizzle-seed/tsconfig.build.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "src" + }, + "include": ["src"] +} diff --git a/drizzle-seed/tsconfig.json b/drizzle-seed/tsconfig.json new file mode 100644 index 000000000..c75766c3f --- /dev/null +++ b/drizzle-seed/tsconfig.json @@ -0,0 +1,48 @@ +{ + "compilerOptions": { + "isolatedModules": true, + "composite": false, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["es2020", "es2018", "es2017", "es7", "es6", "es5", "es2022"], + "declarationMap": false, + "sourceMap": true, + "allowJs": true, + "incremental": false, + "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + "exactOptionalPropertyTypes": false, /* Interpret optional property types as written, rather than adding 'undefined'. */ + "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + "allowUnusedLabels": false, /* Disable error reporting for unused labels. */ + "allowUnreachableCode": false, /* Disable error reporting for unreachable code. */ + "skipLibCheck": true, /* Skip type checking all .d.ts files. */ + "noErrorTruncation": true, /* Disable truncating types in error messages. */ + "checkJs": true, + "noEmit": true, + "allowImportingTsExtensions": true, + "outDir": "dist", + "baseUrl": ".", + "declaration": true, + "paths": { + "~/*": ["src/*"] + } + }, + "exclude": ["**/dist"], + "include": ["src", "*.ts"] +} diff --git a/integration-tests/package.json b/integration-tests/package.json index 78f36fe30..039fd08e0 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -58,6 +58,7 @@ "drizzle-typebox": "workspace:../drizzle-typebox/dist", "drizzle-valibot": "workspace:../drizzle-valibot/dist", "drizzle-zod": "workspace:../drizzle-zod/dist", + "drizzle-seed": "workspace:../drizzle-seed/dist", "express": "^4.18.2", "get-port": "^7.0.0", "mysql2": "^3.3.3", diff --git a/integration-tests/tests/seeder/firstNames.ts b/integration-tests/tests/seeder/firstNames.ts new file mode 100644 index 000000000..ac6e1b74a --- /dev/null +++ b/integration-tests/tests/seeder/firstNames.ts @@ -0,0 +1,30276 @@ +export default [ + 'Robert', + 'John', + 'Michael', + 'David', + 'James', + 'Richard', + 'Christopher', + 'William', + 'Daniel', + 'Mark', + 'Thomas', + 'Jose', + 'Joseph', + 'Matthew', + 'Jason', + 'Andrew', + 'Joshua', + 'Steven', + 'Anthony', + 'Jonathan', + 'Angel', + 'Ryan', + 'Kevin', + 'Jacob', + 'Nicholas', + 'Brandon', + 'Justin', + 'Charles', + 'Gary', + 'Paul', + 'Scott', + 'George', + 'Christian', + 'Eric', + 'Brian', + 'Alexander', + 'Ronald', + 'Jayden', + 'Juan', + 'Edward', + 'Noah', + 'Diego', + 'Donald', + 'Ethan', + 'Kyle', + 'Peter', + 'Jeffrey', + 'Luis', + 'Timothy', + 'Nathan', + 'Tyler', + 'Frank', + 'Stephen', + 'Dennis', + 'Larry', + 'Jesus', + 'Kenneth', + 'Austin', + 'Adrian', + 'Adam', + 'Sebastian', + 'Gregory', + 'Carlos', + 'Aiden', + 'Gabriel', + 'Isaac', + 'Zachary', + 'Julian', + 'Benjamin', + 'Liam', + 'Billy', + 'Miguel', + 'Mason', + 'Aaron', + 'Mike', + 'Dylan', + 'Sean', + 'Alejandro', + 'Bryan', + 'Jordan', + 'Cody', + 'Jeremy', + 'Samuel', + 'Harry', + 'Victor', + 'Joe', + 'Eduardo', + 'Isaiah', + 'Jorge', + 'Logan', + 'Elijah', + 'Bruce', + 'Patrick', + 'Jerry', + 'Jesse', + 'Lawrence', + 'Steve', + 'Walter', + 'Harold', + 'Arthur', + 'Lucas', + 'Francisco', + 'Douglas', + 'Oscar', + 'Craig', + 'Alexis', + 'Todd', + 'Randy', + 'Alan', + 'Raymond', + 'Damian', + 'Willie', + 'Albert', + 'Ricardo', + 'Louis', + 'Luke', + 'Edgar', + 'Travis', + 'Evan', + 'Ricky', + 'Aidan', + 'Jack', + 'Jeff', + 'Jimmy', + 'Manuel', + 'Oliver', + 'Mateo', + 'Johnny', + 'Henry', + 'Cristian', + 'Terry', + 'Dominic', + 'Cameron', + 'Gerald', + 'Caleb', + 'Christop', + 'Bobby', + 'Alex', + 'Gavin', + 'Shawn', + 'Jackson', + 'Ivan', + 'Keith', + 'Antonio', + 'Vincent', + 'Philip', + 'Chad', + 'Alfred', + 'Eugene', + 'Erik', + 'Martin', + 'Omar', + 'Chris', + 'Stanley', + 'Sergio', + 'Francis', + 'Mario', + 'Fernando', + 'Taylor', + 'Herbert', + 'Santiago', + 'Nathaniel', + 'Cesar', + 'Barry', + 'Trevor', + 'Dustin', + 'Hunter', + 'Roger', + 'Andres', + 'Javier', + 'Bernard', + 'Jim', + 'Ian', + 'Wayne', + 'Leonardo', + 'Giovanni', + 'Josiah', + 'Jeremiah', + 'Glenn', + 'Hector', + 'Roberto', + 'Rodney', + 'Howard', + 'Eli', + 'Xavier', + 'Jaxon', + 'Levi', + 'Derek', + 'Danny', + 'Jared', + 'Landon', + 'Ralph', + 'Ruben', + 'Gael', + 'Connor', + 'Tommy', + 'Tony', + 'Marc', + 'Wyatt', + 'Rick', + 'Carter', + 'Ayden', + 'Tim', + 'Roy', + 'Owen', + 'Greg', + 'Joel', + 'Leonard', + 'Frederick', + 'Russell', + 'Jon', + 'Jaden', + 'Jeffery', + 'Irving', + 'Erick', + 'Darren', + 'Dale', + 'Carl', + 'Brayden', + 'Ronnie', + 'Gerardo', + 'Pedro', + 'Raul', + 'Elias', + 'Chase', + 'Alberto', + 'Troy', + 'Tom', + 'Axel', + 'Julio', + 'Emmanuel', + 'Edwin', + 'Norman', + 'Marcus', + 'Fred', + 'Bill', + 'Jake', + 'Marco', + 'Leo', + 'Rafael', + 'Armando', + 'Jace', + 'Garrett', + 'Jaime', + 'Earl', + 'Shane', + 'Cole', + 'Phillip', + 'Seth', + 'Corey', + 'Nicolas', + 'Randall', + 'Hayden', + 'Abraham', + 'Grayson', + 'Tristan', + 'Cory', + 'Josue', + 'Andy', + 'Warren', + 'Roman', + 'Devin', + 'Salvador', + 'Shaun', + 'Spencer', + 'Infant', + 'Ryder', + 'Dillon', + 'Max', + 'Salvatore', + 'Bradley', + 'Seymour', + 'Arturo', + 'Iker', + 'Dean', + 'Milton', + 'Sidney', + 'Gustavo', + 'Alfredo', + 'Blake', + 'Clarence', + 'Brody', + 'Enrique', + 'Brett', + 'Colton', + 'Dan', + 'Brendan', + 'Charlie', + 'Darrell', + 'Hudson', + 'Ezra', + 'Emiliano', + 'Ashton', + 'Darryl', + 'Dave', + 'Nolan', + 'Theodore', + 'Casey', + 'Colin', + 'Easton', + 'Caden', + 'Marcos', + 'Cooper', + 'Mitchell', + 'Morris', + 'Don', + 'Eddie', + 'Jay', + 'Marvin', + 'Kaden', + 'Curtis', + 'Lance', + 'Gerard', + 'Israel', + 'Ramon', + 'Rickey', + 'Alec', + 'Carson', + 'Ernesto', + 'Riley', + 'Kai', + 'Ezekiel', + 'Yahir', + 'Dakota', + 'Ron', + 'Bob', + 'Saul', + 'Kayden', + 'Adan', + 'Fabian', + 'Maxwell', + 'Allen', + 'Micheal', + 'Parker', + 'Micah', + 'Miles', + 'Gilbert', + 'Grant', + 'Malik', + 'Abel', + 'Darrin', + 'Johnathan', + 'Jase', + 'Kaleb', + 'Ray', + 'Jaxson', + 'Brent', + 'Wesley', + 'Tanner', + 'Chester', + 'Bryce', + 'Lincoln', + 'Preston', + 'Maximiliano', + 'Jerome', + 'Sam', + 'Ernest', + 'Bentley', + 'Colby', + 'Elmer', + 'Moises', + 'Joaquin', + 'Arnold', + 'Stuart', + 'Murray', + 'Asher', + 'Andre', + 'Neil', + 'Allan', + 'Brady', + 'Brad', + 'Maximus', + 'Dalton', + 'Jonah', + 'Kim', + 'Kirk', + 'Bryson', + 'Kurt', + 'Angelo', + 'Rene', + 'Jimmie', + 'Emilio', + 'Damien', + 'Harvey', + 'Moshe', + 'Derrick', + 'Kelly', + 'Franklin', + 'Rodrigo', + 'Woodrow', + 'Leon', + 'Esteban', + 'Hugo', + 'Clayton', + 'Guadalupe', + 'Darin', + 'Pablo', + 'Luca', + 'Ken', + 'Ismael', + 'Leroy', + 'Guillermo', + 'Tracy', + 'Melvin', + 'Lorenzo', + 'Clifford', + 'Hugh', + 'Mathew', + 'Jameson', + 'Billie', + 'Nelson', + 'Herman', + 'Ira', + 'Jamie', + 'Alexande', + 'Lester', + 'Glen', + 'Damon', + 'Emanuel', + 'Maverick', + 'Braxton', + 'Zayden', + 'Dominick', + 'Irwin', + 'Rudy', + 'Calvin', + 'Julius', + 'Jermaine', + 'Jakob', + 'Donovan', + 'Lee', + 'Shaquille', + 'Gordon', + 'Peyton', + 'Duane', + 'Declan', + 'Jalen', + 'Jude', + 'Tyrone', + 'Bret', + 'Gene', + 'Felix', + 'Guy', + 'Devon', + 'Cruz', + 'Rylan', + 'Clinton', + 'Jonathon', + 'Kaiden', + 'Kingston', + 'Kristopher', + 'Felipe', + 'Collin', + 'Alfonso', + 'Rodolfo', + 'King', + 'Everett', + 'Chance', + 'Johnnie', + 'Clyde', + 'Weston', + 'Karl', + 'Camden', + 'Maddox', + 'Bryant', + 'Gage', + 'Dwayne', + 'Shannon', + 'Gilberto', + 'Braden', + 'Lewis', + 'Greyson', + 'Rudolph', + 'Floyd', + 'Jayce', + 'Harrison', + 'Brayan', + 'Cayden', + 'Reginald', + 'Jaiden', + 'Brantley', + 'Hyman', + 'Perry', + 'Kent', + 'Alvin', + 'Cade', + 'Doug', + 'Romeo', + 'Jax', + 'Silas', + 'Ty', + 'Emmett', + 'Jackie', + 'Leslie', + 'Vernon', + 'Jessie', + 'Lloyd', + 'Cecil', + 'Roland', + 'Ted', + 'Amir', + 'Cash', + 'Gregg', + 'Uriel', + 'Donnie', + 'Noel', + 'Mauricio', + 'Dana', + 'Osvaldo', + 'Sawyer', + 'Rogelio', + 'Terrence', + 'Conner', + 'Darius', + 'Chaim', + 'Maurice', + 'Male', + 'Malachi', + 'Issac', + 'Ramiro', + 'Zane', + 'Jaylen', + 'Dawson', + 'Willard', + 'Randolph', + 'Wilbur', + 'Noe', + 'Huey', + 'Sammy', + 'Lonnie', + 'Morton', + 'Chandler', + 'Elliot', + 'Geoffrey', + 'Robin', + 'Muhammad', + 'Wallace', + 'Matt', + 'Drew', + 'Bailey', + 'Orlando', + 'Jasper', + 'Tyrese', + 'Matteo', + 'Leonel', + 'Simon', + 'Braylon', + 'Corbin', + 'Jayceon', + 'Gunner', + 'Dante', + 'Daryl', + 'Bennett', + 'Ulises', + 'Efrain', + 'Drake', + 'Rolando', + 'Lukas', + 'Arian', + 'Trenton', + 'Humberto', + 'Ryker', + 'Aldo', + 'Landen', + 'Xander', + 'Dwight', + 'Alvaro', + 'Sheldon', + 'Freddie', + 'Vicente', + 'Avery', + 'Marty', + 'Irvin', + 'Ariel', + 'Lane', + 'Nestor', + 'Chuck', + 'Dominique', + 'Baby', + 'Kerry', + 'Enzo', + 'Nick', + 'Yosef', + 'Edmund', + 'Oswaldo', + 'Kobe', + 'Aden', + 'Clair', + 'Freddy', + 'Karter', + 'Stacy', + 'Byron', + 'Roosevelt', + 'Claude', + 'Marion', + 'Thiago', + 'Colt', + 'Sol', + 'Lamont', + 'Neal', + 'August', + 'Cason', + 'Kason', + 'Reynaldo', + 'Malcolm', + 'Beau', + 'Ignacio', + 'Kareem', + 'Laurence', + 'Finn', + 'Domingo', + 'Rigoberto', + 'Solomon', + 'Aaden', + 'Case', + 'Horace', + 'Griffin', + 'Rocco', + 'Pete', + 'Ross', + 'Skyler', + 'Kenny', + 'Tucker', + 'Morgan', + 'Forrest', + 'Timmy', + 'Clint', + 'Garry', + 'Elwood', + 'Knox', + 'Elian', + 'Zion', + 'Trey', + 'Vito', + 'Jamel', + 'Junior', + 'Roderick', + 'Brooks', + 'Isidore', + 'Kelvin', + 'Ali', + 'Octavio', + 'Luther', + 'Milo', + 'Jett', + 'Unknown', + 'Milan', + 'Nickolas', + 'German', + 'Terence', + 'Virgil', + 'Conor', + 'Isaias', + 'Cristopher', + 'Jayson', + 'Brenden', + 'Joey', + 'Tevin', + 'Branden', + 'Arjun', + 'Carmine', + 'Wendell', + 'Judah', + 'Nikolas', + 'Izaiah', + 'Dick', + 'Jairo', + 'Giovani', + 'Ervin', + 'Graham', + 'Trent', + 'Tyson', + 'Cedric', + 'Elliott', + 'Myles', + 'Kameron', + 'Jaylon', + 'Hubert', + 'Grady', + 'Homer', + 'Quinn', + 'Payton', + 'Bennie', + 'River', + 'Dexter', + 'Emil', + 'Jamal', + 'Orion', + 'Alonzo', + 'Paxton', + 'Ashley', + 'Desmond', + 'Waylon', + 'Patsy', + 'Agustin', + 'Shimon', + 'Jarrod', + 'Rex', + 'Pat', + 'Rhett', + 'Benny', + 'Adriel', + 'Moses', + 'Daquan', + 'Johan', + 'Adolfo', + 'Otis', + 'Kadeem', + 'Jody', + 'Wilson', + 'Pasquale', + 'Kendrick', + 'Alonso', + 'Ben', + 'Ezequiel', + 'Jair', + 'Tomas', + 'Zackary', + 'Dane', + 'Nasir', + 'Alton', + 'Tristen', + 'Wilfredo', + 'Lyle', + 'Rowan', + 'Deandre', + 'Mordechai', + 'Mohamed', + 'Khalil', + 'Maximilian', + 'Devante', + 'Wade', + 'Norbert', + 'Yehuda', + 'Dallas', + 'Menachem', + 'Anderson', + 'Jonas', + 'Zachery', + 'Zaiden', + 'Giovanny', + 'Clifton', + 'Tommie', + 'Ronaldo', + 'Major', + 'Barrett', + 'Darnell', + 'Keegan', + 'Randal', + 'Aarav', + 'Burton', + 'Terrance', + 'Reid', + 'Fredrick', + 'Bobbie', + 'Ace', + 'Kyler', + 'Yoel', + 'Earnest', + 'Toby', + 'Merle', + 'Archer', + 'Santos', + 'Nico', + 'Beckett', + 'Yisroel', + 'Nehemiah', + 'Lynn', + 'Holden', + 'Matias', + 'Rufus', + 'Mohammed', + 'Hayes', + 'Marshall', + 'Trinidad', + 'Valentin', + 'Heath', + 'Weldon', + 'Ed', + 'Lionel', + 'Jaret', + 'Aron', + 'Bernardo', + 'Zander', + 'Devonte', + 'Meyer', + 'Ulysses', + 'Myron', + 'Lowell', + 'Linwood', + 'Rocky', + 'Phoenix', + 'Antoine', + 'Cyrus', + 'Demarcus', + 'Bruno', + 'Titus', + 'Madison', + 'Jarod', + 'Caiden', + 'Kash', + 'Jarvis', + 'Clay', + 'Notnamed', + 'Doyle', + 'Dallin', + 'Atticus', + 'Orville', + 'Nixon', + 'Loren', + 'Wilbert', + 'Karson', + 'Brennan', + 'Brittany', + 'Marlon', + 'Gonzalo', + 'Carlton', + 'Cary', + 'Marquis', + 'Amari', + 'Rohan', + 'Terrell', + 'Gianni', + 'Johnathon', + 'Jan', + 'Boston', + 'Ibrahim', + 'Yitzchok', + 'Jean', + 'Camron', + 'Ronny', + 'Porter', + 'Adonis', + 'Alessandro', + 'Stefan', + 'Giancarlo', + 'Clark', + 'Lupe', + 'Edgardo', + 'Scotty', + 'Messiah', + 'Benito', + 'Zachariah', + 'Kristian', + 'Bodhi', + 'Ronan', + 'Emerson', + 'Wilfred', + 'Heriberto', + 'Davis', + 'Stewart', + 'Efren', + 'Brock', + 'Christophe', + 'Sammie', + 'Kade', + 'Denis', + 'Ernie', + 'Kayson', + 'Quincy', + 'Abe', + 'Estevan', + 'Jamari', + 'Mohammad', + 'Kendall', + 'Demetrius', + 'Walker', + 'Shlomo', + 'Louie', + 'Kody', + 'Valentino', + 'Jaheim', + 'Vince', + 'Frankie', + 'Aubrey', + 'Quinton', + 'Royce', + 'Ari', + 'Abram', + 'Jessica', + 'Curt', + 'Bart', + 'Daren', + 'Braylen', + 'Alexandro', + 'Lamar', + 'Kasen', + 'Willis', + 'Vihaan', + 'Delbert', + 'Triston', + 'Yakov', + 'Courtney', + 'Niko', + 'Pierre', + 'Jaquan', + 'Braulio', + 'Santino', + 'Quentin', + 'Dario', + 'Dusty', + 'Neymar', + 'Bridger', + 'Tyrell', + 'Bertram', + 'Raymundo', + 'Isiah', + 'Reed', + 'Archie', + 'Prince', + 'Rory', + 'Davon', + 'Stacey', + 'Bradford', + 'Nikolai', + 'Kian', + 'Kase', + 'Casen', + 'Dion', + 'Isai', + 'Armand', + 'Percy', + 'Emily', + 'Leland', + 'Sterling', + 'Yandel', + 'Olin', + 'Sanford', + 'Marlin', + 'Denzel', + 'Mekhi', + 'Elbert', + 'Braydon', + 'Dewey', + 'Dudley', + 'Shmuel', + 'Jadon', + 'Braeden', + 'Yair', + 'Rob', + 'Mickey', + 'Monty', + 'Hannah', + 'Luciano', + 'Remington', + 'Akeem', + 'Julien', + 'Carmen', + 'Jensen', + 'Johnie', + 'Mack', + 'Rickie', + 'Javon', + 'Misael', + 'Elvis', + 'Eden', + 'Jess', + 'Phil', + 'Malakai', + 'Melvyn', + 'Rod', + 'Arnulfo', + 'Cohen', + 'Fidel', + 'Levar', + 'Dominik', + 'Grover', + 'Yaakov', + 'Landyn', + 'Colten', + 'Dorian', + 'Keaton', + 'Loyd', + 'Brodie', + 'Otto', + 'Eliezer', + 'Ahmed', + 'Shelby', + 'Hernan', + 'Odin', + 'Regis', + 'Jaydon', + 'Uriah', + 'Remy', + 'Tariq', + 'Sonny', + 'Carroll', + 'Xavi', + 'Christia', + 'Marcel', + 'Brendon', + 'Kellan', + 'Bowen', + 'Unnamed', + 'Scottie', + 'Justice', + 'Kurtis', + 'Stephan', + 'Daxton', + 'Coby', + 'Jadiel', + 'Dashawn', + 'Amare', + 'Cannon', + 'Blaine', + 'Tate', + 'Talmadge', + 'Nathanael', + 'Adolph', + 'Talan', + 'Tobias', + 'Sylvester', + 'Tadeo', + 'Darrel', + 'Winston', + 'Garland', + 'Meir', + 'Kory', + 'Joseluis', + 'Wilburn', + 'Rusty', + 'Avraham', + 'Ayaan', + 'Theo', + 'Mathias', + 'Marcelo', + 'Dino', + 'Kolby', + 'Cael', + 'Tzvi', + 'Davion', + 'Aryan', + 'Rhys', + 'Cain', + 'Duke', + 'Pierce', + 'Landry', + 'Tristin', + 'Emma', + 'Zackery', + 'Antone', + 'Rayan', + 'Hendrix', + 'Lucca', + 'Luka', + 'Jarrett', + 'Miguelangel', + 'Rodger', + 'Kevon', + 'Jacoby', + 'Damion', + 'Maximo', + 'Robbie', + 'Jovanny', + 'Trace', + 'Gunnar', + 'Kieran', + 'Cristobal', + 'Kris', + 'Ellis', + 'Matthias', + 'Eloy', + 'Sarah', + 'Donny', + 'Donte', + 'Ronin', + 'Reece', + 'Alijah', + 'Zayne', + 'Jamarion', + 'Laverne', + 'Gregorio', + 'Kellen', + 'Nathen', + 'Gideon', + 'Rosario', + 'Erwin', + 'Jakub', + 'Normand', + 'Rey', + 'Trevon', + 'Stetson', + 'Carmelo', + 'Rashad', + 'Tod', + 'Elizabeth', + 'Harley', + 'Darian', + 'Scot', + 'Tavon', + 'Keven', + 'Merlin', + 'Nash', + 'Deangelo', + 'Raiden', + 'Jahir', + 'Isidro', + 'Davian', + 'Raekwon', + 'Alphonse', + 'Reese', + 'Abigail', + 'Deshawn', + 'Ahmad', + 'Conrad', + 'Truman', + 'Kolton', + 'Ryland', + 'Jamaal', + 'Abdiel', + 'Aditya', + 'Keenan', + 'Brycen', + 'Thaddeus', + 'Austen', + 'Leonidas', + 'Raphael', + 'Jovani', + 'Brenton', + 'Jasmine', + 'Thurman', + 'Russel', + 'Emory', + 'Cornelius', + 'Roel', + 'Xzavier', + 'Jovanni', + 'Zev', + 'Eldon', + 'Deven', + 'Kamden', + 'Eliseo', + 'Franco', + 'Duncan', + 'Anton', + 'Amarion', + 'Deron', + 'Sage', + 'Babyboy', + 'Fredy', + 'Russ', + 'Omarion', + 'Ryne', + 'Jovany', + 'Camilo', + 'Stan', + 'Cullen', + 'Armani', + 'Adrien', + 'Royal', + 'Kane', + 'Ishaan', + 'Spenser', + 'Antwan', + 'Stephon', + 'Juanpablo', + 'Tiffany', + 'Garret', + 'Jagger', + 'Will', + 'Nigel', + 'Chadwick', + 'Casimir', + 'Abdirahman', + 'Odell', + 'Keanu', + 'Josh', + 'Mortimer', + 'Raheem', + 'Jordon', + 'Nery', + 'Monte', + 'Jaxton', + 'Deacon', + 'Reuben', + 'Carlo', + 'Skylar', + 'Jamarcus', + 'Robby', + 'Jaycob', + 'Kristofer', + 'Buddy', + 'Korbin', + 'Arlo', + 'Jennifer', + 'Rodrick', + 'Juwan', + 'Latrell', + 'Chaz', + 'Lawson', + 'Mendel', + 'Jordy', + 'Dirk', + 'Finnegan', + 'Eason', + 'Atlas', + 'Eddy', + 'Mitch', + 'Reagan', + 'Clement', + 'Jamar', + 'Kamari', + 'Jarred', + 'Lauren', + 'Roscoe', + 'Jefferson', + 'Devan', + 'Elton', + 'Cortez', + 'Leandro', + 'Finley', + 'Cordero', + 'Dov', + 'Eliyahu', + 'Princeton', + 'Avrohom', + 'Hassan', + 'Dangelo', + 'Shamar', + 'Gino', + 'Yusuf', + 'Jaylin', + 'Martez', + 'Shad', + 'Keyshawn', + 'Nikhil', + 'Yael', + 'Harlan', + 'Jeffry', + 'Frederic', + 'Derick', + 'Dondre', + 'Vance', + 'Markus', + 'London', + 'Arman', + 'Marley', + 'Van', + 'Jaeden', + 'Krish', + 'Benson', + 'Marquise', + 'Cristofer', + 'Dewayne', + 'Gannon', + 'Genaro', + 'Crew', + 'Rashawn', + 'Rayden', + 'Raylan', + 'Jaxen', + 'Fredric', + 'Beckham', + 'Tripp', + 'Mckay', + 'Deonte', + 'Johann', + 'Johnpaul', + 'Santo', + 'Hakeem', + 'Federico', + 'Bert', + 'Flynn', + 'Edison', + 'Enoch', + 'Shulem', + 'Jovan', + 'Art', + 'Isadore', + 'Hal', + 'Cristiano', + 'Urijah', + 'Dilan', + 'Benicio', + 'Kingsley', + 'Aydan', + 'Syed', + 'Nicole', + 'Rachel', + 'Tyree', + 'Maximillian', + 'Branson', + 'Davin', + 'Layton', + 'Joan', + 'Darien', + 'Deion', + 'Augustus', + 'Dariel', + 'Oziel', + 'Juancarlos', + 'Pranav', + 'Danielle', + 'Rubin', + 'Jerald', + 'Wilmer', + 'Deegan', + 'Teddy', + 'Mariano', + 'Nathanie', + 'Stevie', + 'Dorsey', + 'Maxim', + 'Jaron', + 'Coty', + 'Damarion', + 'Semaj', + 'Maria', + 'Jamison', + 'Domenick', + 'Emile', + 'Armaan', + 'Arnav', + 'Mackenzie', + 'Everardo', + 'Aurelio', + 'Cayson', + 'Edwardo', + 'Charley', + 'Geovanni', + 'Vincenzo', + 'Yadiel', + 'Francesco', + 'Koby', + 'Joziah', + 'Jasiah', + 'Makai', + 'Long', + 'Cassius', + 'Omari', + 'Ferdinand', + 'Samir', + 'Cleveland', + 'Olivia', + 'Lanny', + 'Sincere', + 'Hyrum', + 'Christina', + 'Lucian', + 'Margarito', + 'Osiel', + 'Kinsler', + 'Sydney', + 'Slade', + 'Lazaro', + 'Sal', + 'Lipa', + 'Hobert', + 'Coy', + 'Elroy', + 'Tatum', + 'Katherine', + 'Chloe', + 'Kyrie', + 'Amanda', + 'Buford', + 'Kymani', + 'Kacper', + 'Elmo', + 'Alphonso', + 'Ramses', + 'Homero', + 'Sherman', + 'Reinaldo', + 'Yechiel', + 'Jonatan', + 'Mychal', + 'Gustave', + 'Paris', + 'Zain', + 'Markanthony', + 'Dimitri', + 'Mamadou', + 'Apollo', + 'Bronson', + 'Hamza', + 'Samson', + 'Madden', + 'Tylor', + 'Jacquez', + 'Garth', + 'Giuseppe', + 'Stephanie', + 'Darion', + 'Yurem', + 'Antony', + 'Rico', + 'Rich', + 'Dontavious', + 'Erin', + 'Kannon', + 'Isaak', + 'Dovid', + 'Coleman', + 'Monroe', + 'Bryon', + 'Asa', + 'Patricio', + 'Arnoldo', + 'Alexandra', + 'Jessy', + 'Jules', + 'Alexzander', + 'Jerrod', + 'Talon', + 'Elvin', + 'Chace', + 'Amos', + 'Galen', + 'Kenji', + 'Rahul', + 'Delmar', + 'Nakia', + 'Abdullah', + 'Deon', + 'Brice', + 'Osbaldo', + 'Favian', + 'Mauro', + 'Tristian', + 'Leopoldo', + 'Hans', + 'Hank', + 'Tou', + 'Demond', + 'Jemal', + 'Ladarius', + 'Kylan', + 'Braiden', + 'Darwin', + 'Kamron', + 'Millard', + 'Dax', + 'Shaquan', + 'Aloysius', + 'Tyshawn', + 'Westley', + 'Marquez', + 'Shayne', + 'Kasey', + 'Usher', + 'Ares', + 'Killian', + 'Maynard', + 'Jeshua', + 'Vaughn', + 'Shia', + 'Naftali', + 'Zaire', + 'Taj', + 'Edmond', + 'Zechariah', + 'Ollie', + 'Hoyt', + 'Donnell', + 'Soren', + 'Isac', + 'Tyquan', + 'Legend', + 'Devyn', + 'Shon', + 'Gerry', + 'Ellsworth', + 'Naftuli', + 'Johnson', + 'Haywood', + 'Aydin', + 'Junius', + 'Wiley', + 'Lennox', + 'Siddharth', + 'Odis', + 'Zaid', + 'Lacy', + 'Hussein', + 'Nicklas', + 'Callen', + 'Izayah', + 'Jaziel', + 'Claud', + 'Horacio', + 'Cyril', + 'Jariel', + 'Shemar', + 'Rebecca', + 'Reyes', + 'Denny', + 'Dereck', + 'Marcelino', + 'Najee', + 'Mac', + 'Hollis', + 'Korey', + 'Addison', + 'Jordi', + 'Eleazar', + 'Lisandro', + 'Dayton', + 'Ammon', + 'Reymundo', + 'Erich', + 'Tenzin', + 'Mitchel', + 'Kristoffer', + 'Jerrold', + 'Kristoph', + 'Refugio', + 'Erasmo', + 'Samantha', + 'Simcha', + 'Abdullahi', + 'Booker', + 'Quadir', + 'Kyson', + 'Hoover', + 'Gus', + 'Azael', + 'Mervin', + 'Yoshio', + 'Jorje', + 'Jesiah', + 'Shirley', + 'Brigham', + 'Memphis', + 'Reyansh', + 'Flavio', + 'Lavern', + 'Rosendo', + 'Dantrell', + 'Devonta', + 'Forest', + 'Alden', + 'Lyndon', + 'Luiz', + 'Elisha', + 'Al', + 'Bentlee', + 'Eriberto', + 'Marques', + 'Alexandre', + 'Fidencio', + 'Jabari', + 'Arsenio', + 'Kaysen', + 'Ethen', + 'Cleo', + 'Blaze', + 'Aryeh', + 'Dequan', + 'Denver', + 'Luc', + 'Delmas', + 'Javion', + 'Gauge', + 'Martell', + 'Ever', + 'Gavyn', + 'Aldair', + 'Okey', + 'Carey', + 'Geovanny', + 'Kalel', + 'Layne', + 'Hiroshi', + 'Ayan', + 'Akiva', + 'Clare', + 'Sigmund', + 'Furman', + 'Claudio', + 'Garrison', + 'Draven', + 'Aidyn', + 'Vern', + 'Andreas', + 'Kwame', + 'Imanol', + 'Jorden', + 'Glynn', + 'Adalberto', + 'Varun', + 'Dashiell', + 'Baron', + 'Jasen', + 'Child', + 'Earle', + 'Izaac', + 'Vivaan', + 'Koa', + 'Lennon', + 'Marcoantonio', + 'Gaetano', + 'Sumner', + 'Barney', + 'Demarion', + 'Abner', + 'Delonte', + 'Val', + 'Jacky', + 'Demario', + 'Zavier', + 'Kale', + 'Wilton', + 'Jordyn', + 'Tatsuo', + 'Boyd', + 'Zayn', + 'Darron', + 'Moe', + 'Dillan', + 'Naquan', + 'Ned', + 'Kaylee', + 'Kelton', + 'Sahil', + 'Kermit', + 'Abelardo', + 'Sullivan', + 'Crosby', + 'Hagen', + 'Tyreek', + 'Jaquez', + 'Andrea', + 'Kyan', + 'Jeremias', + 'Tracey', + 'Ward', + 'Brixton', + 'Seamus', + 'Cedrick', + 'Enrico', + 'Emmitt', + 'Ford', + 'Travon', + 'Felton', + 'Blair', + 'Rio', + 'Dandre', + 'Kaeden', + 'Tiger', + 'Orval', + 'Castiel', + 'Yousef', + 'Anson', + 'Callan', + 'Jamey', + 'Darrius', + 'Tre', + 'Michel', + 'Mcarthur', + 'Rasheed', + 'Jamir', + 'Herschel', + 'Anibal', + 'Kinnick', + 'Hilario', + 'Shea', + 'Jencarlos', + 'Darrick', + 'Rishi', + 'Shaya', + 'Haden', + 'Ean', + 'Jaylan', + 'Rolland', + 'Leobardo', + 'Fermin', + 'Keon', + 'Lucio', + 'Keagan', + 'Savion', + 'Masao', + 'Damari', + 'Aarush', + 'Nunzio', + 'Anakin', + 'Mayson', + 'Westin', + 'Norberto', + 'Tavares', + 'Gorge', + 'Tavaris', + 'Joesph', + 'Sylas', + 'Huy', + 'Gerson', + 'Augustine', + 'Buster', + 'Jelani', + 'Haley', + 'Filip', + 'Shmiel', + 'Lucius', + 'Rojelio', + 'Gale', + 'Quintin', + 'Channing', + 'Brayton', + 'Keshawn', + 'Osmar', + 'Otha', + 'Eder', + 'Mary', + 'Eusebio', + 'Matheus', + 'Randell', + 'Brennen', + 'Trae', + 'Paolo', + 'Caesar', + 'Estill', + 'Camren', + 'Dhruv', + 'Cutter', + 'Rayyan', + 'Jeramiah', + 'Anish', + 'Donavan', + 'Sunny', + 'Hershel', + 'Salvator', + 'Jedidiah', + 'Romario', + 'Hershy', + 'Anders', + 'Trevion', + 'Murphy', + 'Kanye', + 'Jionni', + 'Bradyn', + 'Cordell', + 'Alek', + 'Luisangel', + 'Norris', + 'Nevin', + 'Jaleel', + 'Lenny', + 'Judson', + 'Tayshaun', + 'Aedan', + 'Rhyder', + 'Domenic', + 'Santana', + 'Rahsaan', + 'Sebastien', + 'Corban', + 'Rowdy', + 'Kiyoshi', + 'Armen', + 'Efraim', + 'Vladimir', + 'Callum', + 'Abdul', + 'Gianluca', + 'Mayer', + 'Mustafa', + 'Demarco', + 'Neyland', + 'Vidal', + 'Marshawn', + 'Rudolfo', + 'Nazir', + 'Azariah', + 'Shoji', + 'Worth', + 'Levern', + 'Jai', + 'Antione', + 'Dickie', + 'Yehoshua', + 'Cliff', + 'Kaison', + 'Kye', + 'Jaren', + 'Emir', + 'Henrik', + 'Maxx', + 'Kainoa', + 'Athan', + 'Cletus', + 'Jasir', + 'Dejon', + 'Jadyn', + 'Houston', + 'Kadin', + 'Erubiel', + 'Hadi', + 'Jaydin', + 'Brianna', + 'Alyssa', + 'Marcello', + 'Omer', + 'Ikaika', + 'Ramel', + 'Arron', + 'Bently', + 'Daron', + 'Avi', + 'Jerod', + 'Shelton', + 'Winfred', + 'Mendy', + 'Ryu', + 'Nikko', + 'Arley', + 'Kamdyn', + 'Bo', + 'Erica', + 'Faustino', + 'Fletcher', + 'Dionte', + 'Boyce', + 'Kennedy', + 'Reyli', + 'Paulo', + 'Baruch', + 'Bernie', + 'Mohamad', + 'Kahlil', + 'Kong', + 'Baldemar', + 'Murry', + 'Rogers', + 'Sandy', + 'Bodie', + 'Ivory', + 'Youssef', + 'Kee', + 'Jahiem', + 'Isabella', + 'Keoni', + 'Michelle', + 'Luigi', + 'Marcanthony', + 'Jericho', + 'Achilles', + 'Everette', + 'Americo', + 'Edson', + 'Hiram', + 'Jeramy', + 'Metro', + 'Davi', + 'Hezekiah', + 'Harper', + 'Kiel', + 'Brandan', + 'Said', + 'Noam', + 'Tarik', + 'Raquan', + 'Zeb', + 'Broderick', + 'Arath', + 'Emery', + 'Kip', + 'Tymir', + 'Garrick', + 'Anfernee', + 'Khalid', + 'Jamil', + 'Demian', + 'Amador', + 'Oran', + 'Franklyn', + 'Porfirio', + 'Delano', + 'Justyn', + 'Aharon', + 'Karol', + 'Alva', + 'Nicky', + 'Zack', + 'Jerimiah', + 'Josef', + 'Errol', + 'Hideo', + 'Tahj', + 'Ilan', + 'Kennith', + 'Nathanial', + 'Kyron', + 'Merton', + 'Danial', + 'Tuan', + 'Hung', + 'Massimo', + 'Krew', + 'Arya', + 'Jedediah', + 'Nosson', + 'Jakobe', + 'Eitan', + 'Edmundo', + 'Olen', + 'Benedict', + 'Quintavious', + 'Shalom', + 'Akash', + 'Maxton', + 'Anna', + 'Julia', + 'Melissa', + 'Victoria', + 'Kekoa', + 'Konner', + 'Kirby', + 'Heyward', + 'Davonte', + 'Magnus', + 'Zeus', + 'Neel', + 'Franky', + 'Isael', + 'Gaylon', + 'Kole', + 'Axton', + 'Brando', + 'Mateusz', + 'Lucien', + 'Marquavious', + 'Lon', + 'Gian', + 'Savannah', + 'Trinity', + 'Harris', + 'Kamarion', + 'Aydenn', + 'Cale', + 'Neo', + 'Justus', + 'Mose', + 'Tiago', + 'Saverio', + 'Eligh', + 'Mikel', + 'Eliot', + 'Alvis', + 'Argenis', + 'Musa', + 'Lonny', + 'Thad', + 'Guido', + 'Ceasar', + 'Obed', + 'Pinchas', + 'Barton', + 'Durell', + 'Johnatha', + 'Aric', + 'Geovany', + 'Fransisco', + 'Jaheem', + 'Jarett', + 'Yeshua', + 'Karim', + 'Aayden', + 'Merrill', + 'Michele', + 'Jaydan', + 'Octavius', + 'Jermiah', + 'Alexavier', + 'Brandyn', + 'Arvid', + 'Brentley', + 'Sutton', + 'Coen', + 'Ameer', + 'Giovany', + 'Ishan', + 'Blaise', + 'Bayron', + 'Kamil', + 'Brooklyn', + 'Catherine', + 'Akira', + 'Briggs', + 'Damani', + 'Rasheen', + 'Rayford', + 'Moishe', + 'Ephraim', + 'Esequiel', + 'Kenyon', + 'Constantine', + 'Silvio', + 'Brain', + 'Daylon', + 'Raymon', + 'Ayush', + 'Lazer', + 'Telly', + 'Elan', + 'Stone', + 'Marland', + 'Donn', + 'Shamel', + 'Silvestre', + 'Zephyr', + 'Merrick', + 'Fausto', + 'Dedrick', + 'Cornell', + 'Whitney', + 'Derrell', + 'Mitsuo', + 'Lucious', + 'Tad', + 'Lyric', + 'Darrion', + 'Dannie', + 'Gayle', + 'Burl', + 'Jayquan', + 'Carrol', + 'Laquan', + 'Tyrek', + 'Natividad', + 'Casimer', + 'Jael', + 'Aven', + 'Arnaldo', + 'Yovani', + 'Laura', + 'Dejuan', + 'Dimitrios', + 'Yash', + 'Esai', + 'Zavion', + 'Ora', + 'Durward', + 'Bradly', + 'Hazel', + 'Che', + 'Richie', + 'Diana', + 'Alois', + 'Lynwood', + 'Luverne', + 'Zeke', + 'Dash', + 'Cairo', + 'Delvin', + 'Kawika', + 'Josemanuel', + 'Devean', + 'Sameer', + 'Seneca', + 'Presley', + 'Jed', + 'Malaki', + 'Dominque', + 'Dontae', + 'Dev', + 'Darey', + 'Reggie', + 'Izaak', + 'Manny', + 'Jere', + 'Minh', + 'Ryden', + 'Montana', + 'Kaleo', + 'Jacorey', + 'Ignatius', + 'Filiberto', + 'Cache', + 'Yitzchak', + 'Yaseen', + 'Kentrell', + 'Basil', + 'Ivy', + 'Migel', + 'Jalon', + 'Lenwood', + 'Ellwood', + 'Zakary', + 'Haiden', + 'Dontrell', + 'Braedon', + 'Lorne', + 'Trever', + 'Mikael', + 'Kenzo', + 'Javaris', + 'Ambrose', + 'Alain', + 'Columbus', + 'Leif', + 'Jerold', + 'Anwar', + 'Gabino', + 'Dillion', + 'Kelby', + 'Denzil', + 'Ulisses', + 'Sami', + 'Jahmir', + 'Elimelech', + 'Dock', + 'Zahir', + 'Hardy', + 'Florian', + 'Jewel', + 'Tobin', + 'Curley', + 'Mahdi', + 'Mccoy', + 'Jaquavious', + 'Justen', + 'Lino', + 'Teodoro', + 'Kazuo', + 'Lenard', + 'Robb', + 'Takashi', + 'Maison', + 'Merlyn', + 'Brecken', + 'Ricki', + 'Jet', + 'Lars', + 'Ulices', + 'Dereon', + 'Fox', + 'Ajay', + 'Geraldo', + 'Maksim', + 'Jullian', + 'Kalani', + 'Andrei', + 'Jaidyn', + 'Maxie', + 'Javen', + 'Gail', + 'Ely', + 'Caroline', + 'Amber', + 'Crystal', + 'Kiara', + 'Megan', + 'Reilly', + 'Eugenio', + 'Fisher', + 'Langston', + 'Gavriel', + 'Abhinav', + 'Dee', + 'Kace', + 'Axl', + 'Isabel', + 'Uziel', + 'Sabastian', + 'Rylee', + 'Eliazar', + 'Renato', + 'Harland', + 'Lavar', + 'Stefano', + 'Mayra', + 'Valentine', + 'Bud', + 'Hasan', + 'Zaden', + 'Truett', + 'Korbyn', + 'Toshio', + 'Stockton', + 'Edd', + 'Trystan', + 'Daylan', + 'Jayven', + 'Dewitt', + 'Kraig', + 'Wilford', + 'Celestino', + 'Jacobo', + 'Patryk', + 'Hailey', + 'Nainoa', + 'Haskell', + 'Sharif', + 'Jerad', + 'Raynaldo', + 'Jacques', + 'Jessi', + 'Geary', + 'Gaige', + 'Garnett', + 'Jakari', + 'Yonatan', + 'Eino', + 'Phong', + 'Jerel', + 'Benzion', + 'Quinten', + 'Amado', + 'Blas', + 'Kimberly', + 'Cuauhtemoc', + 'Aayan', + 'Catarino', + 'Jeromy', + 'Kyree', + 'Apolonio', + 'Boy', + 'Antwon', + 'Hakim', + 'Creed', + 'Shiloh', + 'Shepherd', + 'Garett', + 'Oakley', + 'Miller', + 'Dajuan', + 'Mattias', + 'Titan', + 'Immanuel', + 'Lamarcus', + 'Devontae', + 'Reef', + 'Brayson', + 'Grey', + 'Deante', + 'Yariel', + 'Makhi', + 'Jayse', + 'Corbyn', + 'Domenico', + 'Sedrick', + 'Deontae', + 'Kou', + 'Shant', + 'Willy', + 'Austyn', + 'Shloime', + 'Masen', + 'Linus', + 'Florentino', + 'Gionni', + 'Boden', + 'Torrey', + 'Minoru', + 'Daulton', + 'Kolten', + 'Jennings', + 'Noble', + 'Hersh', + 'Kelsey', + 'Nicholaus', + 'Florencio', + 'Nam', + 'Juelz', + 'Kainalu', + 'Destin', + 'Damarcus', + 'Jacolby', + 'Nikita', + 'Artis', + 'Bilal', + 'Kendell', + 'Alexsander', + 'Parth', + 'Esau', + 'Glennon', + 'Kohen', + 'Isacc', + 'Aleksander', + 'Vinh', + 'Trenten', + 'Koen', + 'Candelario', + 'Connie', + 'Aram', + 'Wolfgang', + 'Amit', + 'Om', + 'Shyheim', + 'Raven', + 'Kendra', + 'Eliel', + 'Viet', + 'Kenyatta', + 'Sky', + 'Binyomin', + 'Deanthony', + 'Lachlan', + 'Tory', + 'Kenton', + 'Tamir', + 'Kramer', + 'Deshaun', + 'Javian', + 'Haruo', + 'Rupert', + 'Jevon', + 'Shlome', + 'Danilo', + 'Vanessa', + 'Fernand', + 'Daveon', + 'Les', + 'Marko', + 'Delmer', + 'Marlyn', + 'Winfield', + 'Wes', + 'Rosevelt', + 'Rayshawn', + 'Tai', + 'Kalvin', + 'Jerardo', + 'Sarkis', + 'Bertrand', + 'Kaimana', + 'Kaitlyn', + 'Summer', + 'Veer', + 'Waymon', + 'Evin', + 'Andrey', + 'Iain', + 'Kimi', + 'Foster', + 'Servando', + 'Mychael', + 'Derik', + 'Ryon', + 'Rowen', + 'Mel', + 'Ibn', + 'Werner', + 'Jameel', + 'Avrum', + 'Nachman', + 'Jomar', + 'Rudolf', + 'Tyrique', + 'Rayburn', + 'Khalif', + 'Rondal', + 'Bijan', + 'Rohit', + 'Jeremie', + 'Kain', + 'Nicola', + 'Bode', + 'Brogan', + 'Trayvon', + 'Turner', + 'Dwain', + 'Konnor', + 'Lev', + 'Zayd', + 'Finnley', + 'Brantlee', + 'Deonta', + 'Demetrio', + 'Ajani', + 'Arther', + 'Bianca', + 'Takeo', + 'Harding', + 'Jareth', + 'Rigo', + 'Epifanio', + 'Nahum', + 'Carleton', + 'Cosmo', + 'Shigeru', + 'Josias', + 'Takeshi', + 'Jacobi', + 'Michal', + 'Dorris', + 'Treveon', + 'Jaxx', + 'Aren', + 'Tejas', + 'Beverly', + 'Geoff', + 'Maddux', + 'Camryn', + 'Burt', + 'Norwood', + 'Sholom', + 'Ahron', + 'Macario', + 'Carol', + 'Camdyn', + 'Gennaro', + 'Leeroy', + 'Pinchus', + 'Kaito', + 'Burnell', + 'Frantz', + 'Laron', + 'Clemente', + 'Chasen', + 'Neri', + 'Jerrell', + 'Kashawn', + 'Keola', + 'Alvan', + 'Amar', + 'Ubaldo', + 'Roque', + 'Zalmen', + 'Daylen', + 'Kadyn', + 'Gil', + 'Bernice', + 'Yosgart', + 'Shaan', + 'Yahel', + 'Elon', + 'Levon', + 'Kit', + 'Brodrick', + 'Gaven', + 'Kaidyn', + 'Ansel', + 'Jewell', + 'Mikhail', + 'Derian', + 'Elam', + 'Tye', + 'Leigh', + 'Wayde', + 'Rian', + 'Artemio', + 'Ibrahima', + 'Noa', + 'Autumn', + 'Kylie', + 'Pernell', + 'Britton', + 'Deondre', + 'Arlen', + 'Aman', + 'Kelley', + 'Eliud', + 'Dijon', + 'Imran', + 'Eulalio', + 'Juvenal', + 'Agapito', + 'Brant', + 'Nima', + 'Yisrael', + 'Yerik', + 'Ewan', + 'Lathan', + 'Adair', + 'Gentry', + 'Kyren', + 'Lian', + 'Tayshawn', + 'Alejandra', + 'Jeancarlos', + 'Keyon', + 'Jade', + 'Shayan', + 'June', + 'Christos', + 'Adrain', + 'Jarom', + 'Kathryn', + 'Thor', + 'Haven', + 'Duy', + 'Enmanuel', + 'Montavious', + 'Cortney', + 'Teagan', + 'Blayne', + 'Anselmo', + 'Leyton', + 'Jonny', + 'Braylin', + 'Albaro', + 'Pascual', + 'Gasper', + 'Waldo', + 'Tyreke', + 'Dylon', + 'Narciso', + 'Ebony', + 'Hilton', + 'Margaret', + 'Brighton', + 'Martavious', + 'Demetrios', + 'Kishan', + 'Ansh', + 'Treyton', + 'Albin', + 'Rashon', + 'Rony', + 'Krystian', + 'Amrom', + 'Korver', + 'Richardo', + 'Kayla', + 'Katelyn', + 'Milford', + 'Bishop', + 'Ottis', + 'Emmet', + 'Codey', + 'Ayub', + 'Isreal', + 'Karas', + 'Kendarius', + 'Isamu', + 'Kunta', + 'Jermey', + 'Arvin', + 'Kayleb', + 'Sione', + 'Taurean', + 'Tyron', + 'Mihir', + 'Rami', + 'Vincente', + 'Zayan', + 'Mahlon', + 'Clovis', + 'Kirt', + 'Dyllan', + 'Ramsey', + 'Jeramie', + 'Nikolaus', + 'Edsel', + 'Asael', + 'Andrik', + 'Lisa', + 'Sandro', + 'Desean', + 'Narek', + 'Kiran', + 'Elzie', + 'Jered', + 'Arlie', + 'Yahya', + 'Lizandro', + 'Rollin', + 'Khiry', + 'Yuvraj', + 'Jeancarlo', + 'Anay', + 'Freeman', + 'Stevan', + 'Keller', + 'Ledger', + 'Jasiel', + 'Jacinto', + 'Sherwin', + 'Beaux', + 'Campbell', + 'Sherwood', + 'Torrence', + 'Daryle', + 'Chevy', + 'Adiel', + 'Patricia', + 'Jameer', + 'Bilbo', + 'Jayvon', + 'Early', + 'Boruch', + 'Jadarius', + 'Alpha', + 'Amadou', + 'Reino', + 'Betty', + 'Moussa', + 'Wolf', + 'Jenna', + 'Grace', + 'Natalie', + 'Javonte', + 'Crawford', + 'Damir', + 'Mckinley', + 'Elden', + 'Jhon', + 'Lemuel', + 'Colston', + 'Donta', + 'Pearl', + 'Taquan', + 'Salman', + 'Palmer', + 'Muhammed', + 'Brennon', + 'Cashton', + 'Ysidro', + 'Salomon', + 'Ocean', + 'Anirudh', + 'Aksel', + 'Cal', + 'Ishmael', + 'Brenda', + 'Abran', + 'Rome', + 'Leighton', + 'Canyon', + 'Kael', + 'Amin', + 'Antoni', + 'Tiara', + 'Heather', + 'Christine', + 'Brittney', + 'Angela', + 'Johathan', + 'Cipriano', + 'Coltin', + 'Verne', + 'Darrien', + 'Eamon', + 'Oskar', + 'Mikah', + 'Matix', + 'Kooper', + 'Antonino', + 'Duwayne', + 'Dagoberto', + 'Kolt', + 'Sanjay', + 'Tayden', + 'Waverly', + 'Abrahan', + 'Diamond', + 'West', + 'Jefferey', + 'Shigeo', + 'Kabir', + 'Jamell', + 'Jaedyn', + 'Malcom', + 'Gadiel', + 'Manav', + 'Audie', + 'Hipolito', + 'Theron', + 'Codie', + 'General', + 'Lindy', + 'Carver', + 'Nat', + 'Jacari', + 'Khamari', + 'Wally', + 'Kay', + 'Anastacio', + 'Jaymes', + 'Skip', + 'Cheyne', + 'Dameon', + 'Geronimo', + 'Kevyn', + 'Toney', + 'Arden', + 'Dontavius', + 'Rasheem', + 'Geovani', + 'Gaspar', + 'Baltazar', + 'Bladimir', + 'Rashan', + 'Rulon', + 'Karan', + 'Jory', + 'Chet', + 'Abiel', + 'Lazarus', + 'Britt', + 'Rodriquez', + 'Akil', + 'Zuriel', + 'Rylen', + 'Aston', + 'Graysen', + 'Jaysen', + 'Hillel', + 'Alford', + 'Tyriq', + 'Cassidy', + 'Rahiem', + 'Juanmanuel', + 'Demetri', + 'Jayton', + 'Timoteo', + 'Infantof', + 'Braedyn', + 'Corde', + 'Bee', + 'Valente', + 'Gildardo', + 'Feliciano', + 'Dalvin', + 'Tadashi', + 'Claudie', + 'Teng', + 'Genesis', + 'Tayler', + 'Joeangel', + 'Teruo', + 'Tylan', + 'Markel', + 'Linda', + 'Taven', + 'Pierson', + 'Newton', + 'Keandre', + 'Jayvion', + 'Donavon', + 'Encarnacion', + 'Melton', + 'Ritchie', + 'Erika', + 'Edgard', + 'Christoper', + 'Rocio', + 'Alvie', + 'Josedejesus', + 'Dashaun', + 'Travion', + 'Johny', + 'Marcell', + 'Monique', + 'Caitlin', + 'Durwood', + 'Gustav', + 'Rosalio', + 'Farhan', + 'Benuel', + 'Lashawn', + 'Shakeem', + 'Ocie', + 'Yasir', + 'Szymon', + 'Aaryan', + 'Hansel', + 'Slater', + 'Samarth', + 'Kiyan', + 'Storm', + 'Ava', + 'Yassin', + 'Dayquan', + 'Sherrill', + 'Khari', + 'Anas', + 'Cheskel', + 'Kamryn', + 'Zyaire', + 'Cristo', + 'Christofer', + 'Akhil', + 'Shreyas', + 'Ryley', + 'Gibson', + 'Haziel', + 'Talen', + 'Bracken', + 'Dallen', + 'Rashard', + 'Rockwell', + 'Colie', + 'Del', + 'Jihad', + 'Simeon', + 'Jahmari', + 'Ashwin', + 'Shraga', + 'Cian', + 'Alistair', + 'Cartier', + 'Stoney', + 'Verlyn', + 'Kavon', + 'Konrad', + 'Conrado', + 'Colon', + 'Randel', + 'Christ', + 'Jeremey', + 'Raleigh', + 'Lauro', + 'Dionicio', + 'Kauan', + 'Piotr', + 'Cleon', + 'Malique', + 'Rand', + 'Fritz', + 'Cordaro', + 'Pietro', + 'Faris', + 'Ezio', + 'Atharv', + 'Karthik', + 'Jahsir', + 'Saleem', + 'Abdoulaye', + 'Jiovanni', + 'Ezrah', + 'Everest', + 'Bronx', + 'Kruz', + 'Viktor', + 'Yasiel', + 'Thatcher', + 'Michelangelo', + 'Alaric', + 'Oneal', + 'Sahib', + 'Osiris', + 'Teo', + 'Joseangel', + 'Nate', + 'Walton', + 'Yousif', + 'Ezzard', + 'Yamil', + 'Angus', + 'Jhonny', + 'Fabio', + 'Darold', + 'Junious', + 'Atreyu', + 'Beck', + 'Adriano', + 'Amani', + 'Trevin', + 'Rudra', + 'Parsa', + 'Breon', + 'Umar', + 'Taha', + 'Cormac', + 'Yossi', + 'Jaison', + 'Saad', + 'Shloimy', + 'Chesky', + 'Ayman', + 'Alicia', + 'Chadd', + 'Broc', + 'Cynthia', + 'Reynold', + 'Ismail', + 'Gaylord', + 'Saburo', + 'Kao', + 'Masato', + 'Alfonzo', + 'Joshue', + 'Earvin', + 'Patric', + 'Robinson', + 'Serjio', + 'Gavino', + 'Stanford', + 'Thanh', + 'Kamren', + 'Vikram', + 'Roan', + 'Jeronimo', + 'Zahid', + 'Anjel', + 'Jayro', + 'Skye', + 'Baylor', + 'Drayden', + 'Pheng', + 'Yeng', + 'Wilber', + 'Meng', + 'Arik', + 'Jamarius', + 'Avigdor', + 'Ladarrius', + 'Nicklaus', + 'Gatlin', + 'Boone', + 'Jacen', + 'Antonia', + 'Kyran', + 'Quintavius', + 'Estil', + 'Casimiro', + 'Prentice', + 'Jodie', + 'Rashaad', + 'Konstantinos', + 'Allison', + 'Sophia', + 'Makayla', + 'Lillian', + 'Zymir', + 'Canaan', + 'Delfino', + 'Benton', + 'Apolinar', + 'Winford', + 'Dayne', + 'Shivam', + 'Fredi', + 'Yves', + 'Jarrell', + 'Ignazio', + 'Gamaliel', + 'Young', + 'Kiefer', + 'Juanjose', + 'Rehan', + 'Kegan', + 'Davante', + 'Naim', + 'Lyman', + 'Erskine', + 'Toivo', + 'Darrian', + 'Jad', + 'Ender', + 'Remi', + 'Rishaan', + 'Shaurya', + 'Viaan', + 'Chelsea', + 'Molly', + 'Sara', + 'Leib', + 'Azriel', + 'Howell', + 'Briar', + 'Korben', + 'Manning', + 'Job', + 'Brandt', + 'Jaedon', + 'Ozzy', + 'Cordarius', + 'Lannie', + 'Stanton', + 'Radames', + 'Blease', + 'Zyon', + 'Chadrick', + 'Watson', + 'Kentavious', + 'Taurus', + 'Adin', + 'Jordin', + 'Bryden', + 'Susumu', + 'Tamotsu', + 'Yukio', + 'Granville', + 'Ashby', + 'Tristyn', + 'Devaughn', + 'Deric', + 'Cecilio', + 'Pershing', + 'Noboru', + 'Rashaun', + 'Masaichi', + 'Juventino', + 'Norton', + 'Serafin', + 'Windell', + 'Cris', + 'Curtiss', + 'Boris', + 'Elio', + 'Williams', + 'Trung', + 'Torao', + 'Karon', + 'Canon', + 'Tyrik', + 'Naythan', + 'Michaelangelo', + 'Kavin', + 'Akshay', + 'Broden', + 'Quran', + 'Rishabh', + 'Hilbert', + 'Abbas', + 'Damoni', + 'Dillard', + 'Tigran', + 'Romel', + 'Chip', + 'Aeden', + 'Deagan', + 'Treyson', + 'Brannon', + 'Tremaine', + 'Fay', + 'Bryton', + 'Lucky', + 'Izak', + 'Edan', + 'Casper', + 'Koda', + 'Saquan', + 'Alcide', + 'Quinlan', + 'Maddex', + 'Hoyle', + 'Sandra', + 'Joshuah', + 'Lindsay', + 'Donato', + 'Jancarlos', + 'Kalin', + 'Zigmund', + 'Kalen', + 'Jalil', + 'Bonifacio', + 'Gabrielle', + 'Destiny', + 'Cheyenne', + 'Ulyses', + 'Rueben', + 'Markell', + 'Jermel', + 'Corwin', + 'Justine', + 'Idris', + 'Pilar', + 'Torrance', + 'Raeford', + 'Olan', + 'Octavious', + 'Quantavious', + 'Modesto', + 'Kashton', + 'Librado', + 'Bonnie', + 'Lois', + 'Justo', + 'Mahmoud', + 'Divine', + 'Baylen', + 'Rakeem', + 'Diesel', + 'Kyng', + 'Daisy', + 'Armon', + 'Joseantonio', + 'Montel', + 'Gearld', + 'Cloyd', + 'Lindell', + 'Nile', + 'Kashif', + 'Johnmichael', + 'Aramis', + 'Leopold', + 'Kamal', + 'Jerrad', + 'Jadin', + 'Mykel', + 'Jahlil', + 'Cheng', + 'Ezriel', + 'Aria', + 'Dajon', + 'Holt', + 'Chauncey', + 'Karsen', + 'Stryker', + 'Olaf', + 'Reno', + 'Colter', + 'Schuyler', + 'Orvil', + 'Auden', + 'Eyan', + 'Tyce', + 'Barbara', + 'Zamir', + 'Alexi', + 'Braelyn', + 'Brook', + 'Marchello', + 'Tyrel', + 'Oracio', + 'Jalin', + 'Verlon', + 'Raj', + 'Lindsey', + 'Andon', + 'Devlin', + 'Brysen', + 'Harman', + 'Treyvon', + 'Foy', + 'Arash', + 'Cuong', + 'Torin', + 'Rommel', + 'Lorenza', + 'Vishal', + 'Kenya', + 'Heber', + 'Victoriano', + 'Shay', + 'Tremayne', + 'Natanael', + 'Zachry', + 'Eros', + 'Veronica', + 'Wayland', + 'Rayquan', + 'Ana', + 'Jaceon', + 'Yida', + 'Rahmel', + 'Alter', + 'Lamarion', + 'Tavion', + 'Javin', + 'Lawerence', + 'Alessio', + 'Kristen', + 'Jacqueline', + 'Oren', + 'Aahil', + 'Adyan', + 'Augustin', + 'Coleton', + 'Wilfrid', + 'Dezmond', + 'Keelan', + 'Ike', + 'Kanoa', + 'Kedrick', + 'Chue', + 'Danniel', + 'Jowell', + 'Micahel', + 'Yonathan', + 'Finnian', + 'Garfield', + 'Joao', + 'Ezell', + 'Masaru', + 'Yoshito', + 'Pasco', + 'Yechezkel', + 'Shloma', + 'Adnan', + 'Jaythan', + 'Laith', + 'Greysen', + 'Maddix', + 'Alfonse', + 'Ernst', + 'Hobart', + 'Tavin', + 'Dajour', + 'Cy', + 'Estel', + 'Osman', + 'Vedant', + 'Rolf', + 'Ova', + 'Colson', + 'Kelan', + 'Oumar', + 'Olivier', + 'Seichi', + 'Tayson', + 'Roshan', + 'Blane', + 'Baxter', + 'Vu', + 'Tam', + 'Pao', + 'Wardell', + 'Davonta', + 'Montrell', + 'Ravi', + 'Durrell', + 'Bastian', + 'Aj', + 'Ren', + 'Loki', + 'Kairo', + 'Rock', + 'Mylo', + 'Lavell', + 'Bjorn', + 'Arvil', + 'Reinhold', + 'Yesenia', + 'Carsen', + 'Zephaniah', + 'Renzo', + 'Willem', + 'Unique', + 'Elmore', + 'Kalob', + 'Payne', + 'Leeland', + 'Naseem', + 'Yusef', + 'Aboubacar', + 'Ioannis', + 'Bohdan', + 'Javien', + 'Jakobi', + 'Dempsey', + 'Xavian', + 'Antavious', + 'Jc', + 'Dara', + 'Obie', + 'Celso', + 'Tyrin', + 'Eian', + 'Elgin', + 'Jaylyn', + 'Brandin', + 'Adyn', + 'Gabriela', + 'Jaidon', + 'Zavian', + 'Lonzo', + 'Elwin', + 'Tsutomu', + 'Jeanluc', + 'Caeden', + 'Auston', + 'Jasson', + 'Omid', + 'Gray', + 'Vang', + 'Nancy', + 'Nader', + 'Kylen', + 'Jarell', + 'Prentiss', + 'Tahir', + 'Ahmir', + 'Terell', + 'Ludwig', + 'Biagio', + 'Douglass', + 'Nafis', + 'Harlem', + 'Phineas', + 'Lochlan', + 'Hermon', + 'Wilder', + 'Aniello', + 'Attilio', + 'Shiv', + 'Montgomery', + 'Bowie', + 'Aries', + 'Itzae', + 'Isa', + 'Huxley', + 'Elwyn', + 'Advik', + 'Mahamadou', + 'Grayden', + 'Landin', + 'Decker', + 'Dakotah', + 'Ella', + 'Md', + 'Shayaan', + 'Isidor', + 'Joahan', + 'Tillman', + 'Jafet', + 'Panagiotis', + 'Jajuan', + 'Cristhian', + 'Demetric', + 'Zaylen', + 'Kacen', + 'Sloan', + 'Shedrick', + 'Denilson', + 'Buck', + 'Dyland', + 'Aris', + 'Demonte', + 'Telvin', + 'Raynard', + 'Quantavius', + 'Neftali', + 'Alma', + 'Kadarius', + 'Philippe', + 'Laurel', + 'Vadhir', + 'Juandiego', + 'Alekzander', + 'Napoleon', + 'Fabrizio', + 'Abisai', + 'Yasin', + 'Kamran', + 'Ole', + 'Nicolai', + 'Erling', + 'Jathan', + 'Zen', + 'Shiven', + 'Keshaun', + 'Nikola', + 'Loy', + 'Usman', + 'Concepcion', + 'Verlin', + 'Dedric', + 'Derwin', + 'Graig', + 'Serge', + 'Merritt', + 'Kervin', + 'Maleek', + 'Baldomero', + 'Germaine', + 'Hampton', + 'Shan', + 'Alvino', + 'Davy', + 'Arlington', + 'Brandy', + 'Timmie', + 'Andrae', + 'Terrion', + 'Quang', + 'Jeb', + 'Clem', + 'Judd', + 'Severo', + 'Woody', + 'Toan', + 'Alonza', + 'Gardner', + 'Delton', + 'Vinny', + 'Vilas', + 'Welton', + 'Sabian', + 'Dell', + 'Randolf', + 'Tyren', + 'Glenwood', + 'Antwain', + 'Savon', + 'Lesley', + 'Rashid', + 'Tavian', + 'Marvens', + 'Aleksandr', + 'Vivek', + 'Maximino', + 'Pavel', + 'Renee', + 'Charly', + 'Donell', + 'Shariff', + 'Ennis', + 'Menashe', + 'Ygnacio', + 'Hoke', + 'Lebron', + 'Hillard', + 'Xavion', + 'Nicolaus', + 'Kemari', + 'Sammuel', + 'Jessiah', + 'Virgle', + 'Niklas', + 'Allante', + 'Keenen', + 'Albino', + 'Rivaldo', + 'Jospeh', + 'Broadus', + 'Trequan', + 'Finis', + 'Sabas', + 'Abdoul', + 'Tyronne', + 'Tyreik', + 'Tyriek', + 'Linton', + 'Jashawn', + 'Ivey', + 'Janiel', + 'Jayme', + 'Lamarr', + 'Tiernan', + 'Meilech', + 'Fitzgerald', + 'Jonnathan', + 'Tashawn', + 'Verl', + 'Nichoals', + 'Urban', + 'Marquan', + 'Montez', + 'Akshaj', + 'Syrus', + 'Nehemias', + 'Nova', + 'Makaio', + 'Joselito', + 'Armin', + 'Monica', + 'Natasha', + 'Leonce', + 'Corby', + 'Doris', + 'Chancellor', + 'Yonah', + 'Gaston', + 'Alston', + 'Tyreese', + 'Gaither', + 'Donna', + 'Graeme', + 'Frances', + 'Earlie', + 'Oral', + 'Ruby', + 'Krishna', + 'Berkley', + 'Viraj', + 'Jame', + 'Judge', + 'Denim', + 'Guilherme', + 'Salim', + 'Rondell', + 'Marek', + 'Zac', + 'Seven', + 'Stellan', + 'Calder', + 'Eithan', + 'Eliam', + 'Gareth', + 'Auther', + 'Theodis', + 'Denzell', + 'Octave', + 'Destry', + 'Bartholomew', + 'Rajiv', + 'Jaxxon', + 'Maxson', + 'Adler', + 'Tyran', + 'Carnell', + 'Alben', + 'Saif', + 'Merwin', + 'Binyamin', + 'Hayward', + 'Arav', + 'Berry', + 'Daunte', + 'Arvo', + 'Gerhard', + 'Selmer', + 'Davie', + 'Courtland', + 'Athanasios', + 'Ori', + 'Aadi', + 'Kamar', + 'Jeremih', + 'Jayvian', + 'Doyne', + 'Macarthur', + 'Elza', + 'Harden', + 'Soham', + 'Alder', + 'Josemaria', + 'Iziah', + 'Jin', + 'Woodie', + 'Alfie', + 'Stefon', + 'Oswald', + 'Talmage', + 'Leander', + 'Jancarlo', + 'Sasha', + 'Lorin', + 'Roby', + 'Juanmiguel', + 'Johannes', + 'Allie', + 'Demetris', + 'Sharod', + 'Mynor', + 'Lex', + 'Tito', + 'Domonique', + 'Seferino', + 'Jourdan', + 'Marcial', + 'Herminio', + 'Mikal', + 'Alegandro', + 'Makana', + 'Bb', + 'Jarret', + 'Jemel', + 'Kareen', + 'Sierra', + 'Michale', + 'Jalyn', + 'Meredith', + 'Gracie', + 'Dawud', + 'Raylon', + 'Avan', + 'Dayshawn', + 'Livan', + 'Kendal', + 'Otho', + 'Dung', + 'Reuven', + 'Karmelo', + 'Myer', + 'Tadao', + 'Bentzion', + 'Tex', + 'Jamin', + 'Clois', + 'Sadao', + 'Tetsuo', + 'Izrael', + 'Avion', + 'Katsumi', + 'Gerrit', + 'Jamauri', + 'Kunal', + 'Nickolaus', + 'Hoang', + 'Bernabe', + 'Khristian', + 'Arne', + 'Javeon', + 'Vasilios', + 'Noach', + 'Ruger', + 'Kutter', + 'Kyden', + 'Marshal', + 'Jaelon', + 'Raffi', + 'Rito', + 'Parrish', + 'Duvid', + 'Jamario', + 'Verle', + 'Harmon', + 'Thai', + 'Claire', + 'Daiquan', + 'Didier', + 'Jonnie', + 'Arlan', + 'Taggart', + 'Henri', + 'Rogan', + 'Woodford', + 'Maceo', + 'Nyjah', + 'Smith', + 'Syncere', + 'Ballard', + 'Kenichi', + 'Khaled', + 'Dwaine', + 'Mathieu', + 'Ousmane', + 'Emmit', + 'Aayush', + 'Elyas', + 'Taysom', + 'Azaiah', + 'Axle', + 'Ander', + 'Azaan', + 'Vic', + 'Terrel', + 'Alen', + 'Fabricio', + 'Yeshaya', + 'Greggory', + 'Derrik', + 'Esgar', + 'Selwyn', + 'Binh', + 'Tarun', + 'Quoc', + 'Corry', + 'Wylie', + 'Jadan', + 'Aamir', + 'Barron', + 'Ciaran', + 'Melville', + 'Bronislaus', + 'Fong', + 'Hakop', + 'Jashua', + 'Stanislaus', + 'Keion', + 'Timmothy', + 'Kenan', + 'Banks', + 'Ammar', + 'Maxfield', + 'Tyre', + 'Chistian', + 'Son', + 'Shaka', + 'Jahmal', + 'Jerell', + 'Beckam', + 'Zakariya', + 'Jayshawn', + 'Orvel', + 'Yona', + 'Derrek', + 'Warner', + 'Rollie', + 'Adelbert', + 'Von', + 'Kathleen', + 'April', + 'Nikolaos', + 'Alika', + 'Barrington', + 'Inez', + 'Len', + 'Arsh', + 'Elyjah', + 'Eshaan', + 'Shayden', + 'Jaykob', + 'Raziel', + 'Makoa', + 'Cornelio', + 'Rufino', + 'Leamon', + 'Terrill', + 'Hai', + 'Jonerik', + 'Hamilton', + 'Lindbergh', + 'Enos', + 'Sabino', + 'Ara', + 'Raudel', + 'Jones', + 'Cedar', + 'Yohan', + 'Janet', + 'Archibald', + 'Boaz', + 'Cleotha', + 'Dontez', + 'Eldridge', + 'Abhay', + 'Butch', + 'Jayvien', + 'Rowland', + 'Kimo', + 'Gurney', + 'Virgilio', + 'Alfonza', + 'Perley', + 'Silverio', + 'Amilcar', + 'Kapena', + 'Issak', + 'Josemiguel', + 'Mikey', + 'Camille', + 'Gershon', + 'Mehki', + 'Carsten', + 'Lavelle', + 'Jamere', + 'Natale', + 'Elya', + 'Antwone', + 'Pedrohenrique', + 'Kyjuan', + 'Shakim', + 'Evaristo', + 'Lionell', + 'Helen', + 'Aariz', + 'Paige', + 'Jaquavius', + 'Adolphus', + 'Faith', + 'Breanna', + 'Martavius', + 'Armondo', + 'Yobani', + 'Missael', + 'Marcellus', + 'Rishab', + 'Jaxsen', + 'Jahleel', + 'Bernell', + 'Woodroe', + 'Breck', + 'Paden', + 'Trumaine', + 'Rogerio', + 'Cleve', + 'Ameen', + 'Jermain', + 'Shakir', + 'Berl', + 'Conley', + 'Vinson', + 'Andru', + 'Andrue', + 'Suraj', + 'Ruvim', + 'Rodriguez', + 'Benji', + 'Kylon', + 'Matheo', + 'Kellin', + 'Karsyn', + 'Izan', + 'Caysen', + 'Caison', + 'Witten', + 'Issa', + 'Audrey', + 'Sekou', + 'Januel', + 'Christpher', + 'Octaviano', + 'Jereme', + 'Basilio', + 'Kaine', + 'Jayvyn', + 'Vishnu', + 'Umberto', + 'Keondre', + 'Delroy', + 'Herve', + 'Rakim', + 'Denton', + 'Donavin', + 'Elder', + 'Ger', + 'Jazmin', + 'Schneider', + 'Ethyn', + 'Davien', + 'Cross', + 'Reginal', + 'Maksymilian', + 'Rahim', + 'Ridge', + 'Ved', + 'Bartosz', + 'Kaye', + 'Quamir', + 'Jasmin', + 'Diante', + 'Codi', + 'Khamani', + 'Juliocesar', + 'Lydell', + 'Dakari', + 'Eluzer', + 'Daniyal', + 'Isidoro', + 'Yousuf', + 'Rider', + 'Winthrop', + 'Diogo', + 'Kejuan', + 'Micaiah', + 'Ransom', + 'Rolla', + 'Leibish', + 'Ilyas', + 'Arham', + 'Adham', + 'Abdulrahman', + 'Lateef', + 'Rahmir', + 'Kollin', + 'Jamaine', + 'Khary', + 'De', + 'Jabbar', + 'Hardin', + 'Deryl', + 'Yanky', + 'Aviel', + 'Boubacar', + 'Eshan', + 'Hanley', + 'Hussain', + 'Tylon', + 'Leldon', + 'Raoul', + 'Braheem', + 'Kaseem', + 'Tyshaun', + 'Rashaan', + 'Kordell', + 'Anil', + 'Devion', + 'Mervyn', + 'Shaquil', + 'Shaquill', + 'Shaul', + 'Musab', + 'Muad', + 'Tomasz', + 'Madeline', + 'Delante', + 'Jahari', + 'Leah', + 'Tamika', + 'Britney', + 'Jeriel', + 'Yidel', + 'Jarad', + 'Oneil', + 'Fransico', + 'Shamir', + 'Carmello', + 'Abdulahi', + 'Shneur', + 'Yehudah', + 'Brown', + 'Sylvan', + 'Dontay', + 'French', + 'Griffen', + 'Faisal', + 'Dru', + 'Demitri', + 'Faron', + 'Deloy', + 'Juston', + 'Charleston', + 'Farrell', + 'Tab', + 'Donaciano', + 'Candido', + 'Joyce', + 'Marquel', + 'Lamonte', + 'Raheen', + 'Dashon', + 'Hieu', + 'Tyus', + 'Ciro', + 'Naeem', + 'Rush', + 'Keifer', + 'Christion', + 'Bladen', + 'Kobie', + 'Darell', + 'Mouhamed', + 'Jia', + 'Shepard', + 'Price', + 'Kasyn', + 'Truitt', + 'Jenson', + 'Aizen', + 'Markeith', + 'Braylan', + 'Jonmichael', + 'Damond', + 'Jaycion', + 'Platon', + 'Amaury', + 'Amaan', + 'Daven', + 'Tobey', + 'Hymen', + 'Altariq', + 'Jacory', + 'Ashtin', + 'Domonic', + 'Demari', + 'Denise', + 'Abimael', + 'Izaya', + 'Jovon', + 'Harout', + 'Caelan', + 'Donal', + 'Martel', + 'Jaskaran', + 'Alante', + 'Bradon', + 'Deborah', + 'Harrell', + 'Kaipo', + 'Klayton', + 'Danthony', + 'Justino', + 'Kamuela', + 'Barrie', + 'Argelis', + 'Dolores', + 'Jahaziel', + 'Iram', + 'Adian', + 'Rance', + 'Karsten', + 'Christain', + 'Jamarian', + 'Yee', + 'Adriana', + 'Jamichael', + 'Waino', + 'Anh', + 'Casmer', + 'Ronnell', + 'Tong', + 'Vicent', + 'Jarius', + 'Tiburcio', + 'Burdette', + 'Amadeo', + 'Kevan', + 'Arlyn', + 'Derald', + 'Waleed', + 'Jabez', + 'Khoa', + 'Neville', + 'Susan', + 'Leandre', + 'Jorgeluis', + 'Angelica', + 'Regan', + 'Froylan', + 'Tevita', + 'Sagar', + 'Drayton', + 'Zade', + 'Karriem', + 'Townes', + 'Ram', + 'Jaceyon', + 'Keng', + 'Isao', + 'Unkown', + 'Vivian', + 'Mamoru', + 'Dyllon', + 'Hagop', + 'Masami', + 'Shoichi', + 'Landan', + 'Cadence', + 'Yanixan', + 'Xzavion', + 'Javan', + 'Avian', + 'Cadyn', + 'Collier', + 'Clarance', + 'Karen', + 'Christy', + 'Toriano', + 'Diallo', + 'Mateus', + 'Caio', + 'Larue', + 'Gilmer', + 'Rhyan', + 'Elijiah', + 'Curren', + 'Souleymane', + 'Deklan', + 'Zakaria', + 'Hayk', + 'Ric', + 'Briley', + 'Oval', + 'Lovell', + 'Daryn', + 'Franz', + 'Spurgeon', + 'Giacomo', + 'Orrin', + 'Vester', + 'Taran', + 'Salem', + 'Naveen', + 'Linkin', + 'Kallen', + 'Kongmeng', + 'Patrice', + 'Bibb', + 'Arjan', + 'Fateh', + 'Clive', + 'Pharaoh', + 'Subhan', + 'Rayaan', + 'Zebulon', + 'Webster', + 'Raghav', + 'Zakai', + 'Ekam', + 'Caspian', + 'Atom', + 'Athen', + 'Esdras', + 'Vihan', + 'Ronav', + 'Arrow', + 'Izek', + 'Gaines', + 'Trajan', + 'Onofrio', + 'Romello', + 'Ramone', + 'Symir', + 'Kanyon', + 'Shomari', + 'Christo', + 'Anthoney', + 'Giovonni', + 'Gurshan', + 'Nathon', + 'Zach', + 'Jhonatan', + 'Shakur', + 'Favio', + 'Imani', + 'Asad', + 'Brien', + 'Aureliano', + 'Fischer', + 'Yadier', + 'Marino', + 'Kimball', + 'Saleh', + 'Greco', + 'Helmer', + 'Sai', + 'Khai', + 'Marius', + 'Joy', + 'Amauri', + 'Tegan', + 'Darl', + 'Cosimo', + 'Armond', + 'Yecheskel', + 'Natan', + 'Shabazz', + 'Devine', + 'Fabrice', + 'Tarek', + 'Renaldo', + 'Jarrel', + 'Gamal', + 'Rajesh', + 'Lavon', + 'Ahnaf', + 'Cono', + 'Gaspare', + 'Chas', + 'Jaspreet', + 'Tevon', + 'Kush', + 'Nuchem', + 'Jostin', + 'Wm', + 'Darnel', + 'Thurston', + 'Maliek', + 'Shakeel', + 'Coolidge', + 'Shaheed', + 'Anastasios', + 'Wesson', + 'Humza', + 'Kofi', + 'Jamelle', + 'Davey', + 'Llewellyn', + 'Nashawn', + 'Odie', + 'Jun', + 'Jahmere', + 'Bienvenido', + 'Safwan', + 'Mordche', + 'Demarius', + 'Cillian', + 'Alexandros', + 'Nochum', + 'Shareef', + 'Pawel', + 'Theadore', + 'Dorothy', + 'Geno', + 'Haris', + 'Dayvon', + 'Lemarcus', + 'Rayvon', + 'Laird', + 'Zayvion', + 'Dennie', + 'Dwane', + 'Orvis', + 'Chalmer', + 'Adil', + 'Zamari', + 'Kodi', + 'Braxtyn', + 'Fahim', + 'Merl', + 'Name', + 'Aaiden', + 'Dyson', + 'Westyn', + 'Wells', + 'Niles', + 'Nabil', + 'Kaelan', + 'Dmitri', + 'Demitrius', + 'Arlis', + 'Reco', + 'Glendon', + 'Abhishek', + 'Jammie', + 'Grabiel', + 'Jerson', + 'Gerhardt', + 'Kyrin', + 'Kipton', + 'Bear', + 'Jaciel', + 'Dakoda', + 'Kaelin', + 'Keilan', + 'Brendyn', + 'Fortino', + 'Diondre', + 'Arin', + 'Cleophus', + 'Dimas', + 'Caine', + 'Jakoby', + 'Hagan', + 'Layden', + 'Calen', + 'Nils', + 'Cisco', + 'Jerrick', + 'Gevork', + 'Mckenzie', + 'Justis', + 'Coltyn', + 'Brazos', + 'Jaycen', + 'Kemauri', + 'Tyrus', + 'Zaidyn', + 'Lenin', + 'Karlos', + 'Shrey', + 'Edric', + 'Tino', + 'Macklin', + 'Nevan', + 'Lawrance', + 'Arno', + 'Irby', + 'Namir', + 'Chayse', + 'Ronit', + 'Clemens', + 'Giorgio', + 'Khriz', + 'Khang', + 'Zidane', + 'Nomar', + 'Glade', + 'Doyce', + 'Kaya', + 'Surya', + 'Jaelen', + 'Vernell', + 'Issiah', + 'Henderson', + 'Jessejames', + 'Gaylen', + 'Aldahir', + 'An', + 'Asencion', + 'Garner', + 'Treston', + 'Evans', + 'Salome', + 'Cyle', + 'Sang', + 'Isaih', + 'Kirkland', + 'Loyal', + 'Jonpaul', + 'Cindy', + 'Bao', + 'Laurie', + 'Monico', + 'Kiptyn', + 'Toribio', + 'Cresencio', + 'Ruperto', + 'Dat', + 'Rustin', + 'Kendric', + 'Miquel', + 'Hasani', + 'Caron', + 'Jarron', + 'Enrigue', + 'Evelyn', + 'Paulino', + 'Eligio', + 'Melchor', + 'Deshon', + 'Johndavid', + 'Cliffton', + 'Ovidio', + 'Jacorian', + 'Laken', + 'Aedyn', + 'Ichiro', + 'Derion', + 'Sharon', + 'Yasuo', + 'Masayuki', + 'Andrez', + 'Dustyn', + 'Toua', + 'Jossue', + 'Zakkary', + 'Bernardino', + 'Deward', + 'Joanthan', + 'Sandeep', + 'Hercules', + 'Claudia', + 'Sampson', + 'Jacobe', + 'Hulon', + 'Ventura', + 'Blade', + 'Jayzen', + 'Jarren', + 'Nakoa', + 'Chan', + 'Jerrel', + 'Isamar', + 'Artie', + 'Amy', + 'Meghan', + 'Rockey', + 'Sixto', + 'Ascencion', + 'Damonte', + 'Golden', + 'Bubba', + 'Randle', + 'Adelard', + 'Rumaldo', + 'Nieves', + 'Marshaun', + 'Kavion', + 'Mikolaj', + 'Brees', + 'Gayland', + 'Herb', + 'Quenton', + 'Flint', + 'Lennie', + 'Tramaine', + 'Nadir', + 'Timur', + 'Keshav', + 'Malek', + 'Ozzie', + 'Dresden', + 'Eliah', + 'Benaiah', + 'Muhsin', + 'Walt', + 'Damen', + 'Enoc', + 'Giancarlos', + 'Darsh', + 'Maximilliano', + 'Yaniel', + 'Jeevan', + 'Malakhi', + 'Viggo', + 'Karlo', + 'Yosgar', + 'Xavior', + 'Frazier', + 'Orin', + 'Payson', + 'Tonatiuh', + 'Amando', + 'Angad', + 'Gibran', + 'Eben', + 'Deaundre', + 'Rajon', + 'Anand', + 'Andree', + 'Dany', + 'Kayvon', + 'Joell', + 'Jahsiah', + 'Rosaire', + 'Kc', + 'Page', + 'Salvadore', + 'Arjen', + 'Torey', + 'Manraj', + 'Lyam', + 'Mazen', + 'Autry', + 'Coopar', + 'Ranveer', + 'Santhiago', + 'Ronen', + 'Remmy', + 'Kamauri', + 'Andra', + 'Sohan', + 'Cayetano', + 'Jarrad', + 'Fortunato', + 'Magdaleno', + 'Dorman', + 'Cesario', + 'Doroteo', + 'Roddy', + 'Matilde', + 'Lafayette', + 'Edelmiro', + 'Higinio', + 'Yancy', + 'Zvi', + 'Pascal', + 'Timm', + 'Dickey', + 'Spiros', + 'Georgios', + 'Jarid', + 'Johnatho', + 'Nachum', + 'Efrem', + 'Stafford', + 'Pajtim', + 'Amelia', + 'Jada', + 'Lily', + 'Lydia', + 'Sherrod', + 'Stedman', + 'Ardis', + 'Levy', + 'Ulysse', + 'Zalman', + 'Marquette', + 'Gabe', + 'Blaize', + 'Ashanti', + 'Shaheem', + 'Hervey', + 'Abbott', + 'Boleslaw', + 'Tyshon', + 'Kimani', + 'Beecher', + 'Diquan', + 'Eulogio', + 'Arvel', + 'Kennth', + 'Benigno', + 'Luz', + 'Dionisio', + 'Eustacio', + 'Trino', + 'Eldred', + 'Primitivo', + 'Perfecto', + 'Delma', + 'Cosme', + 'Milburn', + 'Shameek', + 'Quayshaun', + 'Evert', + 'Green', + 'Brylan', + 'Crit', + 'Haskel', + 'Ancil', + 'Rayhan', + 'Rose', + 'Gianfranco', + 'Matan', + 'Derin', + 'Artem', + 'Abhiram', + 'Yovanni', + 'Stevenson', + 'Crue', + 'Krue', + 'Jethro', + 'Jakai', + 'Mattix', + 'Daxon', + 'Dallan', + 'Murl', + 'Harsh', + 'Uzziel', + 'Kemarion', + 'Jashaun', + 'Rodman', + 'Elie', + 'Desi', + 'Malikai', + 'Angello', + 'Amogh', + 'Advaith', + 'Adryan', + 'Nazareth', + 'Adolf', + 'Bosco', + 'Arshan', + 'Abdulaziz', + 'Theseus', + 'Riaan', + 'Reza', + 'Radley', + 'Mars', + 'Kirin', + 'Kiaan', + 'Evander', + 'Indiana', + 'Hanson', + 'Viliami', + 'Jaydenn', + 'Ilya', + 'Draco', + 'Riyan', + 'Onyx', + 'Xian', + 'Khristopher', + 'Ayrton', + 'Aurelius', + 'Crosley', + 'Obadiah', + 'Nihal', + 'Rithvik', + 'Constantino', + 'Jeyden', + 'Jaycee', + 'Bane', + 'Aakash', + 'Aniket', + 'Mathis', + 'Maximos', + 'Kohl', + 'Fuquan', + 'Rahman', + 'Aziel', + 'Alexys', + 'Iverson', + 'Marck', + 'Criss', + 'Arsen', + 'Angelgabriel', + 'Ronak', + 'Selvin', + 'Ibraheem', + 'Yordi', + 'Taylen', + 'Javari', + 'Jairus', + 'Hamzah', + 'Sacha', + 'Nayan', + 'Marciano', + 'Aneesh', + 'Manfred', + 'Adal', + 'Bernhard', + 'Jeovanny', + 'Satvik', + 'Nicolo', + 'Julious', + 'Weyman', + 'Roswell', + 'Brevin', + 'Amedeo', + 'Deforest', + 'Barnett', + 'Braydin', + 'Italo', + 'Adrienne', + 'Anne', + 'Jr', + 'Krystal', + 'Brion', + 'Wilberto', + 'Detrick', + 'Bucky', + 'Kristin', + 'Christohper', + 'Laddie', + 'Creighton', + 'Gust', + 'Darby', + 'Shanon', + 'Darious', + 'Josua', + 'Thang', + 'Demarkus', + 'Chistopher', + 'Ehren', + 'Marlo', + 'Matas', + 'Augusto', + 'Diamonte', + 'Maciej', + 'Jamon', + 'Marcin', + 'Valdemar', + 'Nickey', + 'Niam', + 'Ambrosio', + 'Crispin', + 'Lukasz', + 'Yazan', + 'Romell', + 'Darryle', + 'Renard', + 'Ewald', + 'Quint', + 'Andrzej', + 'Vittorio', + 'Keonte', + 'Lavonte', + 'Cordale', + 'Darvin', + 'Marvell', + 'Krzysztof', + 'Corben', + 'Keylan', + 'Haydon', + 'Ociel', + 'Zeth', + 'Ahmari', + 'Texas', + 'Yutaka', + 'Isami', + 'Adarius', + 'Juaquin', + 'Jaydn', + 'Jaidan', + 'Exavier', + 'Steffan', + 'Vahe', + 'Crystian', + 'Edilberto', + 'Jaquavion', + 'Xavien', + 'Delvon', + 'Otoniel', + 'Demontae', + 'Collins', + 'Keoki', + 'Nolberto', + 'Leng', + 'Karina', + 'Grigor', + 'Isrrael', + 'Kaoru', + 'Hisao', + 'Masayoshi', + 'Satoru', + 'Satoshi', + 'Nobuo', + 'Michaelanthony', + 'Lucero', + 'Jocelyn', + 'Yovany', + 'Joangel', + 'Jaelyn', + 'Caedmon', + 'Granger', + 'Heston', + 'Rhodes', + 'Kanon', + 'Judith', + 'Montavius', + 'Antron', + 'Xaiden', + 'Burhanuddin', + 'Stratton', + 'Kadence', + 'Jhett', + 'Jacion', + 'Aiyden', + 'Journey', + 'Jaziah', + 'Thien', + 'Travious', + 'Carsyn', + 'Quindarius', + 'Masyn', + 'Jalan', + 'Jaelin', + 'Dorien', + 'Aarron', + 'Dmarcus', + 'Ramin', + 'Christan', + 'Blain', + 'Rosa', + 'Christoher', + 'Vadim', + 'Martha', + 'Osher', + 'Laakea', + 'Chayton', + 'Keahi', + 'Johnatan', + 'Juanantonio', + 'Kahiau', + 'Sheridan', + 'Samual', + 'Luisalberto', + 'Zacharias', + 'Phi', + 'Marquice', + 'Chong', + 'Harpreet', + 'Fue', + 'Derrion', + 'Eber', + 'Kevion', + 'Beryl', + 'Gavan', + 'Liliana', + 'Fernie', + 'Sulo', + 'Jayren', + 'Lior', + 'Ruth', + 'Carlie', + 'Thierno', + 'Davontae', + 'Jamier', + 'Arye', + 'Kiernan', + 'Hanad', + 'Huston', + 'Winson', + 'Hobson', + 'Yates', + 'Kaua', + 'Einar', + 'Berish', + 'Annie', + 'Mahir', + 'Amr', + 'Sabir', + 'Ewell', + 'Orland', + 'Dujuan', + 'Harvie', + 'Dahmir', + 'Hosea', + 'Haneef', + 'Wei', + 'Nello', + 'Fishel', + 'Amere', + 'Rafi', + 'Charlton', + 'Colden', + 'Hughes', + 'Laurier', + 'Blong', + 'Shimshon', + 'Jahmel', + 'Steward', + 'Milbert', + 'Buel', + 'Hallie', + 'Comer', + 'Tafari', + 'Iver', + 'Evangelos', + 'Jaquarius', + 'Azan', + 'Braedan', + 'Jadarrius', + 'Vernie', + 'Andi', + 'Darry', + 'Jawad', + 'Uri', + 'Kennard', + 'Yishai', + 'Kijana', + 'Brekken', + 'Rajan', + 'Stevens', + 'Sunil', + 'Siddhant', + 'Sir', + 'Sire', + 'Jansen', + 'Theodor', + 'Kaedyn', + 'Tymere', + 'Zyair', + 'Tron', + 'Sanchez', + 'Amaru', + 'Anastasio', + 'Agastya', + 'Hawk', + 'Honor', + 'Sotero', + 'Saeed', + 'Ziggy', + 'Conan', + 'Arie', + 'Gloria', + 'Onesimo', + 'Wellington', + 'Alexei', + 'Tavarus', + 'Cayleb', + 'Arion', + 'Amadeus', + 'Bryer', + 'Jeter', + 'Merced', + 'Kaylon', + 'Lakendrick', + 'Nolen', + 'Niccolo', + 'Halston', + 'Deontre', + 'Ash', + 'Arush', + 'Artur', + 'Bidwell', + 'Tomie', + 'Author', + 'Izik', + 'Jeriah', + 'Edwyn', + 'Zhi', + 'Gilman', + 'Jawan', + 'Bryar', + 'Giles', + 'Talha', + 'Gill', + 'Abelino', + 'Kwasi', + 'Stavros', + 'Juanita', + 'Tri', + 'Consuelo', + 'Khambrel', + 'Peterson', + 'Brantly', + 'Brently', + 'Vitaliy', + 'Hashim', + 'Rain', + 'Quintus', + 'Matthieu', + 'Kayne', + 'Icker', + 'Valen', + 'Nels', + 'Josephus', + 'Nasario', + 'Romulo', + 'Kaisen', + 'Sulaiman', + 'Selim', + 'Mahad', + 'Steele', + 'Stryder', + 'Cristina', + 'Thornton', + 'Girard', + 'Prudencio', + 'Ethaniel', + 'Laurent', + 'Jayvin', + 'Jayveon', + 'Eladio', + 'Ellison', + 'Caius', + 'Christiano', + 'Navid', + 'Gerold', + 'Sven', + 'Advay', + 'Cabell', + 'Marcio', + 'Luisalfredo', + 'Ryatt', + 'Elijio', + 'Pax', + 'Neev', + 'Mehtab', + 'Eluterio', + 'Tahmir', + 'Davit', + 'Eliott', + 'Keane', + 'Kysen', + 'Rafe', + 'Legacy', + 'Erie', + 'Orlin', + 'Dawn', + 'Calum', + 'Adithya', + 'Adarsh', + 'Ulysee', + 'Thurmond', + 'Christen', + 'Thayne', + 'Sriram', + 'Yoav', + 'Lawton', + 'Kemar', + 'Duston', + 'Jatavious', + 'Luisfernando', + 'Maxime', + 'Rithik', + 'Dior', + 'Phuong', + 'Roni', + 'Manu', + 'Esteven', + 'Hazen', + 'Farris', + 'Leverne', + 'Ryen', + 'Tanay', + 'Seaborn', + 'Cicero', + 'Gianmarco', + 'Isak', + 'Lige', + 'Burke', + 'Authur', + 'Javarius', + 'Jeromie', + 'Jerred', + 'Silvano', + 'Keyan', + 'Briant', + 'Arun', + 'Jeremi', + 'Decarlos', + 'Jeanpierre', + 'Haydn', + 'Ab', + 'Anmol', + 'Shaye', + 'Nana', + 'Mateen', + 'Maurisio', + 'Nitin', + 'Dustan', + 'Srikar', + 'Arlin', + 'Burnett', + 'Johnathen', + 'Wyman', + 'Aleksandar', + 'Agustine', + 'Ronney', + 'Marisol', + 'Dmarion', + 'Keir', + 'Demetrice', + 'Jawon', + 'Ricci', + 'Javontae', + 'Armoni', + 'Alto', + 'Dawid', + 'Zakir', + 'Jarek', + 'Lary', + 'Dez', + 'Kaydon', + 'Henley', + 'Adonai', + 'Zahmir', + 'Youssouf', + 'Oisin', + 'Deniz', + 'Antonios', + 'Netanel', + 'Shlok', + 'Ranger', + 'Uzziah', + 'Eryk', + 'Sid', + 'Andersen', + 'Daylin', + 'Naftoli', + 'Lyn', + 'Orvin', + 'Kesean', + 'Hanif', + 'Adael', + 'Maury', + 'Ronn', + 'Carlyle', + 'Ankur', + 'Takumi', + 'Piero', + 'Jeanpaul', + 'Hoa', + 'Jacarri', + 'Jakhi', + 'Zyion', + 'Jeovany', + 'Eoin', + 'Etienne', + 'Amrit', + 'Dang', + 'Juliano', + 'Blakely', + 'Tauno', + 'Edin', + 'Dmitriy', + 'Lambert', + 'Roderic', + 'Felice', + 'Zaki', + 'Debra', + 'Teegan', + 'Tosh', + 'Nicholai', + 'Erickson', + 'Atharva', + 'Aaditya', + 'Anuj', + 'Diane', + 'Sachin', + 'Elazar', + 'Torian', + 'Tan', + 'Cristoval', + 'Jonathen', + 'Kobi', + 'Yuki', + 'Jacori', + 'Eduard', + 'Keron', + 'Tysean', + 'Deshun', + 'Hewitt', + 'Kaulana', + 'Jaydyn', + 'Sebastia', + 'Shamell', + 'Trysten', + 'Treshawn', + 'Samer', + 'Burnice', + 'Da', + 'Parris', + 'Royer', + 'Tien', + 'Tj', + 'Andranik', + 'Nino', + 'Luisenrique', + 'Andrick', + 'Graydon', + 'Pookela', + 'Nevaeh', + 'Zoe', + 'Hanna', + 'Joniel', + 'Jamarious', + 'Hurley', + 'Avante', + 'Iban', + 'Isaiha', + 'Chee', + 'Kealii', + 'Irbin', + 'Maynor', + 'Wendy', + 'Germain', + 'Shamus', + 'Zygmunt', + 'Garnet', + 'Lopaka', + 'Damar', + 'Ramy', + 'Everton', + 'Raylen', + 'Tryston', + 'Kullen', + 'Therman', + 'Khaliq', + 'Alon', + 'Arch', + 'Tylen', + 'Kalan', + 'Zacharia', + 'Dalen', + 'Bedford', + 'Lou', + 'Tsuneo', + 'Kalub', + 'Dadrian', + 'Jiro', + 'Fahad', + 'Quashawn', + 'Hisashi', + 'Fumio', + 'Carlito', + 'Ewing', + 'Zarek', + 'Leron', + 'Cardell', + 'Westen', + 'Hogan', + 'Payden', + 'Chazz', + 'Jarryd', + 'Sedric', + 'Homar', + 'Tylar', + 'Keone', + 'Dasean', + 'Lake', + 'Joeanthony', + 'Haroon', + 'Adonys', + 'Grayling', + 'Braelon', + 'Loras', + 'Jontavious', + 'Nesanel', + 'Carlisle', + 'Camillo', + 'Mandeep', + 'Yang', + 'Blayden', + 'Niall', + 'Evelio', + 'Zaragoza', + 'Shlomie', + 'Percell', + 'Baylee', + 'Garold', + 'Eriq', + 'Ozell', + 'Benjiman', + 'Wayman', + 'Saturnino', + 'Moody', + 'Deandra', + 'Estanislado', + 'Curvin', + 'Demonta', + 'Crimson', + 'Scout', + 'Daequan', + 'Izael', + 'Trine', + 'Demontre', + 'Rexford', + 'Fenix', + 'Raheim', + 'Rivers', + 'Cobe', + 'Jeron', + 'Yanuel', + 'Naftula', + 'Dwan', + 'Kanai', + 'Nicco', + 'Kaeson', + 'Shadman', + 'Cobi', + 'Raequan', + 'Shae', + 'Osama', + 'Ernan', + 'Dennys', + 'Aquil', + 'Tierra', + 'Sabrina', + 'Mia', + 'Melanie', + 'Marissa', + 'Carolyn', + 'Arielle', + 'Zaine', + 'Macen', + 'Shahin', + 'Casyn', + 'Osmin', + 'Alphonsus', + 'Carrington', + 'Chayce', + 'Opal', + 'Taylon', + 'Koy', + 'Ebenezer', + 'Amarii', + 'Keshun', + 'Kolin', + 'Aspen', + 'Cort', + 'Zaylon', + 'Zaedyn', + 'Zaydyn', + 'Tuff', + 'Holton', + 'Ashtyn', + 'Lathen', + 'Hershell', + 'Jerre', + 'Tsugio', + 'Josealberto', + 'Adien', + 'Acen', + 'Maurilio', + 'Ashten', + 'Wataru', + 'Keontae', + 'Donaven', + 'Javonta', + 'Jacobie', + 'Peng', + 'Ector', + 'Ankit', + 'Ann', + 'Kasim', + 'Parley', + 'Mizael', + 'Maxon', + 'Kylar', + 'Jjesus', + 'Kaven', + 'Curran', + 'Edvin', + 'Enrrique', + 'Donovin', + 'Godfrey', + 'Xayden', + 'Xzavian', + 'Carlosmanuel', + 'Ladainian', + 'Keithan', + 'Azrael', + 'Jae', + 'Marlow', + 'Aviv', + 'Orson', + 'Zamarion', + 'Chason', + 'Henrry', + 'Gevorg', + 'Dartagnan', + 'Zakee', + 'Giovannie', + 'Halen', + 'Vinay', + 'Wilfrido', + 'Winton', + 'Garet', + 'Josafat', + 'Manjot', + 'Juandaniel', + 'Manley', + 'Oshea', + 'Wali', + 'Reymond', + 'Harjot', + 'Sidharth', + 'Amer', + 'Camari', + 'Quincey', + 'Dawan', + 'Newell', + 'Sigurd', + 'Logen', + 'Rafiq', + 'Delonta', + 'Katrina', + 'Kristina', + 'Octavia', + 'Sade', + 'Ziyad', + 'Tovia', + 'Malachai', + 'Briana', + 'Alison', + 'Ashleigh', + 'Jerick', + 'Benedetto', + 'Fiore', + 'Mikail', + 'Qasim', + 'Yochanan', + 'Ettore', + 'Ferris', + 'Aziz', + 'Naseer', + 'Jabril', + 'Brodey', + 'Alvah', + 'Kalman', + 'Ziyon', + 'Zakery', + 'Sedale', + 'Jevin', + 'Kalmen', + 'Moishy', + 'Shai', + 'Zakari', + 'Bradlee', + 'Kenley', + 'Pratham', + 'Izeah', + 'Ilias', + 'Emari', + 'Race', + 'Zacarias', + 'Yuri', + 'Kleber', + 'Kailer', + 'Jhovany', + 'Iven', + 'Issaiah', + 'Hosie', + 'Dixon', + 'Massiah', + 'Remo', + 'Pinchos', + 'Mahki', + 'Gunther', + 'Irene', + 'Jamarie', + 'Kaan', + 'Jayon', + 'Moroni', + 'Jkwon', + 'Barack', + 'Alastair', + 'Fares', + 'Zackariah', + 'Yoshua', + 'Tanish', + 'Iann', + 'Linden', + 'Avinash', + 'Willam', + 'Iman', + 'Domanic', + 'Lenton', + 'Samad', + 'Aimar', + 'Buddie', + 'Jozef', + 'Josmar', + 'Mercer', + 'Collie', + 'Nephi', + 'Kenai', + 'Alquan', + 'Cezar', + 'Verbon', + 'Aeneas', + 'Jeremyah', + 'Eren', + 'Tej', + 'Jahad', + 'Deep', + 'Augusta', + 'Yaqub', + 'Yahye', + 'Vashon', + 'Kristoff', + 'Penn', + 'Loukas', + 'Kaydin', + 'Kaius', + 'Perseus', + 'Mykah', + 'Joab', + 'Cylus', + 'Emrys', + 'Mikko', + 'Jaxsyn', + 'Sudais', + 'Tiberius', + 'Rooney', + 'Yuvan', + 'Cletis', + 'Liev', + 'Ester', + 'Harlow', + 'Shreyan', + 'Samar', + 'Saharsh', + 'Ruhaan', + 'Zyler', + 'Yuma', + 'Dwyane', + 'Yanni', + 'Dutch', + 'Rajveer', + 'Tayton', + 'Kasir', + 'Luster', + 'Tage', + 'Damarius', + 'Elihu', + 'Heinz', + 'Manolo', + 'Makhai', + 'Madhav', + 'Sohum', + 'Omri', + 'Egbert', + 'Marie', + 'Keshon', + 'Jahmier', + 'Nachmen', + 'Mckade', + 'Moise', + 'Ames', + 'Iden', + 'Benard', + 'Yannick', + 'Pasha', + 'Sherrick', + 'Jordany', + 'Fenton', + 'Tytan', + 'Dashel', + 'Daksh', + 'Juliani', + 'Jhonathan', + 'Broxton', + 'Essie', + 'Devontay', + 'Maksym', + 'Park', + 'Dasani', + 'Severiano', + 'Kamel', + 'Chayanne', + 'Jarel', + 'Yolanda', + 'Tylik', + 'Marquell', + 'Jamarr', + 'Micky', + 'Socorro', + 'Waymond', + 'Michial', + 'Yoseph', + 'Lumir', + 'Placido', + 'Asif', + 'Needham', + 'Claiborne', + 'Tennis', + 'Burley', + 'Raffaele', + 'Shavar', + 'Atanacio', + 'Jahmar', + 'Arben', + 'Nabeel', + 'Cordarryl', + 'Danyal', + 'Bryston', + 'Lemont', + 'Elston', + 'Kerwin', + 'Riccardo', + 'Danzel', + 'Waldemar', + 'Ledarius', + 'Omarr', + 'Wilho', + 'Alger', + 'Raymie', + 'Kenney', + 'Abdallah', + 'Aristides', + 'Avram', + 'Tayvion', + 'Urbano', + 'Deontay', + 'Darcy', + 'Robbin', + 'Bartlomiej', + 'Dann', + 'Tyjuan', + 'Khaleel', + 'Winifred', + 'Claron', + 'Linford', + 'Hilliard', + 'Arlon', + 'Yong', + 'Malvin', + 'Zymere', + 'Newborn', + 'Eleuterio', + 'Glyn', + 'Koltyn', + 'Serapio', + 'Pius', + 'Ines', + 'Harrold', + 'Caitlyn', + 'Rajeev', + 'Constantinos', + 'Abid', + 'Calvert', + 'Parnell', + 'Aubry', + 'Damone', + 'Akim', + 'Adem', + 'Othel', + 'Joaopedro', + 'Tomer', + 'Brentlee', + 'Melquan', + 'Elpidio', + 'Jenny', + 'Alejos', + 'Romie', + 'Ardell', + 'Doctor', + 'Virginia', + 'Makenzie', + 'Maggie', + 'Tywan', + 'Elisaul', + 'Luby', + 'Teofilo', + 'Jermell', + 'Gumesindo', + 'Harless', + 'Croix', + 'Obinna', + 'Traveon', + 'Coley', + 'Tu', + 'Brylon', + 'Carlin', + 'Daneil', + 'Garen', + 'Ronell', + 'Chesley', + 'Tyrece', + 'Arville', + 'Eamonn', + 'Kayshawn', + 'Wilkie', + 'Zacchaeus', + 'Rapheal', + 'Cordaryl', + 'Quan', + 'Nhan', + 'Vann', + 'Franciscojavier', + 'Kinte', + 'Rui', + 'Chuong', + 'Chao', + 'Chai', + 'Linh', + 'Cirilo', + 'Ky', + 'Gwyn', + 'Hearl', + 'Tray', + 'Carmon', + 'Phuc', + 'Neiman', + 'Ladon', + 'Moua', + 'Eulises', + 'Jonte', + 'Yusuke', + 'Vinnie', + 'Seanpatrick', + 'Pearson', + 'Daemon', + 'Reyn', + 'Daekwon', + 'Garron', + 'Sequan', + 'Zavien', + 'Geovanie', + 'Jessee', + 'Richmond', + 'Osualdo', + 'Artin', + 'Devone', + 'Makoto', + 'Hitoshi', + 'Shinichi', + 'Samari', + 'Saxon', + 'Glennis', + 'Fadi', + 'Bronislaw', + 'Estuardo', + 'Shaheen', + 'Saman', + 'Lue', + 'Djuan', + 'Cord', + 'Linville', + 'Landis', + 'Cameren', + 'Herson', + 'Ellie', + 'Seanmichael', + 'Froilan', + 'Delon', + 'Jestin', + 'Mattew', + 'Toni', + 'Kelii', + 'Maribel', + 'Jadrian', + 'Traylon', + 'Kaiea', + 'Kaeo', + 'Taft', + 'Dameion', + 'Darryn', + 'Dondi', + 'Clell', + 'Corbett', + 'Lyndell', + 'Avenir', + 'Seldon', + 'Jakwon', + 'Jacque', + 'Deane', + 'Cheikh', + 'Carmel', + 'Kieth', + 'Tahmid', + 'Lillard', + 'Tasheem', + 'Jens', + 'Christobal', + 'Delos', + 'Lashon', + 'Jaimie', + 'Kary', + 'Kendarious', + 'Johnell', + 'Harlen', + 'Terron', + 'Corliss', + 'Liston', + 'Seng', + 'Phu', + 'Rasean', + 'Sung', + 'San', + 'Babak', + 'Adel', + 'Gillermo', + 'Avon', + 'Harlon', + 'Allyn', + 'Clary', + 'Orry', + 'Nazario', + 'Jamail', + 'Daeshawn', + 'Tal', + 'Moustafa', + 'Tarell', + 'Jahquan', + 'Jian', + 'Lazar', + 'Adama', + 'Benyamin', + 'Tayvon', + 'Lamel', + 'Davonne', + 'Tayquan', + 'Jusitn', + 'Shjon', + 'Leotis', + 'Kasheem', + 'Ilir', + 'Ravon', + 'Parish', + 'Ehan', + 'Daishawn', + 'Islam', + 'Pinches', + 'Ovadia', + 'Mechel', + 'Berlin', + 'Deryk', + 'Tymel', + 'Vijay', + 'Dyquan', + 'Agron', + 'Tarrell', + 'Itamar', + 'Mordcha', + 'Chrisotpher', + 'Alban', + 'Stephane', + 'Tanvir', + 'Demetriu', + 'Yan', + 'Asim', + 'Ahsan', + 'Mackenzi', + 'Kristofe', + 'Kenrick', + 'Cuahutemoc', + 'Tavis', + 'Audric', + 'Deaven', + 'Nicanor', + 'Mick', + 'Geoffery', + 'Timofey', + 'Dolphus', + 'Franciso', + 'Gorje', + 'Jobany', + 'Abdelrahman', + 'Clenton', + 'Yohance', + 'Milad', + 'Juanluis', + 'Luismario', + 'Marvyn', + 'Rushil', + 'Tenoch', + 'Trentin', + 'Fardeen', + 'Shashank', + 'Yuta', + 'Ritvik', + 'Akili', + 'Aleksei', + 'Gaurav', + 'Iran', + 'Caillou', + 'Borach', + 'Keisuke', + 'Kaushik', + 'Hari', + 'Izac', + 'Josejulian', + 'Juanangel', + 'Kasra', + 'Anthonie', + 'Daivd', + 'Dain', + 'Toren', + 'Sesar', + 'Eldor', + 'Pieter', + 'Yu', + 'Cloyce', + 'Dusten', + 'Aquiles', + 'Aslan', + 'Sevastian', + 'Siddarth', + 'Tysen', + 'Johncarlo', + 'Idan', + 'Daymian', + 'Domanick', + 'Arnie', + 'Bartley', + 'Newman', + 'Akram', + 'Abdulla', + 'Lew', + 'Geremy', + 'Jehu', + 'Josejuan', + 'Jailen', + 'Etai', + 'Fabien', + 'Victormanuel', + 'Ossie', + 'Egan', + 'Eldin', + 'Shamari', + 'Nussen', + 'Arda', + 'Sina', + 'Tytus', + 'Pranay', + 'Dylen', + 'Juandavid', + 'Kalil', + 'Kushal', + 'Hazael', + 'Lecil', + 'Belton', + 'Aleczander', + 'Terance', + 'Faizan', + 'Naithan', + 'Koji', + 'Akshat', + 'Andruw', + 'Bram', + 'Dieter', + 'Saahil', + 'Saulo', + 'Arnel', + 'Demarea', + 'Farhad', + 'Joeseph', + 'Alondra', + 'Belal', + 'Antoniodejesus', + 'Anival', + 'Choua', + 'Cha', + 'Bryn', + 'Xiong', + 'Aristeo', + 'Mehmet', + 'Moustapha', + 'Jandel', + 'Asante', + 'Yunus', + 'Schneur', + 'Steffen', + 'Leovardo', + 'Kacey', + 'Payam', + 'Salbador', + 'Nicholes', + 'Neema', + 'Clarke', + 'Marqus', + 'Araceli', + 'Jerman', + 'Marioalberto', + 'Joseguadalupe', + 'Emigdio', + 'Krishan', + 'Jessey', + 'Arcadio', + 'Zong', + 'Yoni', + 'Tirso', + 'Thompson', + 'Damarea', + 'Everado', + 'Edy', + 'Edder', + 'Nikki', + 'Clemmie', + 'Willian', + 'Marquese', + 'Perris', + 'Miriam', + 'Shelly', + 'Bulmaro', + 'Jasdeep', + 'Irvine', + 'Hue', + 'Gurpreet', + 'Donaldo', + 'Jonthan', + 'Geroge', + 'Francois', + 'Duc', + 'Jerico', + 'Avedis', + 'Chang', + 'Damario', + 'Kenta', + 'Nikkolas', + 'Khoi', + 'Garren', + 'Norma', + 'My', + 'Lam', + 'Sahir', + 'Yer', + 'Jaskarn', + 'Jeric', + 'Maximillion', + 'Elson', + 'Marin', + 'Loc', + 'Lemar', + 'Kristofor', + 'Nai', + 'Takoda', + 'Tung', + 'Thong', + 'Rayshaun', + 'Derreck', + 'Regino', + 'Nadav', + 'Luismiguel', + 'Josede', + 'Hao', + 'Rayce', + 'Zacary', + 'Nareg', + 'Khyree', + 'Chi', + 'Joanna', + 'Sevag', + 'Garin', + 'Juluis', + 'Petros', + 'Berel', + 'Abubakar', + 'Jorel', + 'Kazi', + 'Jaiceon', + 'Haider', + 'Feynman', + 'Muhammadali', + 'Jassiel', + 'Morrison', + 'Nakai', + 'Oden', + 'Odysseus', + 'Quest', + 'Kaidan', + 'Kilian', + 'Kirill', + 'Thorin', + 'Tru', + 'Xzander', + 'Taniela', + 'Roen', + 'Sho', + 'Aarin', + 'Gracen', + 'Gurfateh', + 'Gurman', + 'Hiro', + 'Edrick', + 'Esaias', + 'Johncarlos', + 'Sidi', + 'Cataldo', + 'Noor', + 'Philbert', + 'Eyad', + 'Arber', + 'Abrar', + 'Ladislaus', + 'Serafino', + 'Mannie', + 'Daevon', + 'Haseeb', + 'Yale', + 'Spiro', + 'Emre', + 'Daryan', + 'Camrin', + 'Kavi', + 'Doran', + 'Vaibhav', + 'Rayne', + 'Derric', + 'Orbie', + 'Reily', + 'Gio', + 'Gurnoor', + 'Jaasiel', + 'Naman', + 'Josaiah', + 'Josiyah', + 'Kasper', + 'Filippo', + 'Sigfredo', + 'Joesiah', + 'Rei', + 'Nahom', + 'Ojas', + 'Vladislav', + 'Hilary', + 'Rinaldo', + 'Even', + 'Gautam', + 'Cornel', + 'Julyan', + 'Inaki', + 'Iseah', + 'Itai', + 'Laurance', + 'Garey', + 'Lawerance', + 'Quindon', + 'Levin', + 'Leviticus', + 'Link', + 'Glenford', + 'Avyan', + 'Dmitry', + 'Eiden', + 'Advait', + 'Ahaan', + 'Arhaan', + 'Kassius', + 'Hendrick', + 'Jaiveer', + 'Nirvaan', + 'Reeve', + 'Torsten', + 'True', + 'Iwao', + 'Jahvon', + 'Paxson', + 'Kali', + 'Kwesi', + 'Yaron', + 'Ami', + 'Dashiel', + 'Meliton', + 'Sylus', + 'Mika', + 'Jireh', + 'Selig', + 'Adi', + 'Brenner', + 'Breyden', + 'Mitsuru', + 'Farley', + 'Montrel', + 'Kyland', + 'Jadakiss', + 'Tadarius', + 'Brooke', + 'Alexandria', + 'Alexa', + 'Abby', + 'Hayley', + 'Mallory', + 'Madelyn', + 'Layla', + 'Kirsten', + 'Quayshawn', + 'Deadrick', + 'Hobby', + 'Eunice', + 'Macon', + 'Ysabel', + 'Secundino', + 'Hulen', + 'Estle', + 'Tolbert', + 'Baker', + 'Tilford', + 'Shyheem', + 'Orbin', + 'Ruel', + 'Hurshel', + 'Jailyn', + 'Dequincy', + 'Jamall', + 'Draper', + 'Kenric', + 'Aime', + 'Cam', + 'Connell', + 'Treylon', + 'Bethel', + 'Rommie', + 'Alphonza', + 'Gussie', + 'Elridge', + 'Hillery', + 'Ruffin', + 'Farrel', + 'Wendall', + 'Gerome', + 'Ferrell', + 'Uvaldo', + 'Marshon', + 'Jawaun', + 'Trevell', + 'Tyvon', + 'Telesforo', + 'Ellery', + 'Cordae', + 'Loran', + 'Travell', + 'Lamari', + 'Errick', + 'Antwoine', + 'Starsky', + 'Chirag', + 'Donzell', + 'Tierre', + 'Ketan', + 'Crespin', + 'Orris', + 'Bawi', + 'Wanda', + 'Canuto', + 'Aniceto', + 'Braxten', + 'Audry', + 'Bartolo', + 'Brigido', + 'Garvin', + 'Vergil', + 'Olegario', + 'Thelma', + 'Crecencio', + 'Eleno', + 'Wright', + 'Burtis', + 'Dicky', + 'Avelino', + 'Norval', + 'Cirildo', + 'Darwyn', + 'Delwin', + 'Henery', + 'Beauford', + 'Little', + 'Ameir', + 'Arland', + 'Verner', + 'Taron', + 'Undra', + 'Khasir', + 'Kymir', + 'Aleem', + 'Ordean', + 'Carmino', + 'Lucus', + 'Jodeci', + 'Linn', + 'Sinclair', + 'Delorean', + 'Chalmers', + 'Kentavius', + 'Jarious', + 'Lajuan', + 'Narada', + 'Hussien', + 'Alonte', + 'Damarco', + 'Benjamen', + 'Randon', + 'Jabree', + 'Lawyer', + 'Wanya', + 'Samie', + 'Sim', + 'Washington', + 'Isom', + 'Keyton', + 'Quin', + 'Mahamed', + 'Liban', + 'Ramir', + 'Samaj', + 'Kipp', + 'Prentis', + 'Jibril', + 'Kyaire', + 'Buell', + 'Nasim', + 'Adell', + 'Mohamedamin', + 'Abdiaziz', + 'Harun', + 'Amire', + 'Eligah', + 'Parks', + 'Colonel', + 'Joaovictor', + 'Vinicius', + 'Mcdonald', + 'Manly', + 'Phares', + 'Geza', + 'Kemp', + 'Alphonzo', + 'Loring', + 'Haig', + 'Joaquim', + 'Craven', + 'Bynum', + 'Parke', + 'Ignatz', + 'Hebert', + 'Berton', + 'Ayomide', + 'Kidus', + 'Ayven', + 'Aziah', + 'Banner', + 'Barret', + 'Blayze', + 'Braddock', + 'Javoris', + 'Cortland', + 'Antavius', + 'Amaziah', + 'Santonio', + 'Slate', + 'Sylis', + 'Thierry', + 'Joanthony', + 'Rhylan', + 'Pryce', + 'Riggin', + 'Dequavious', + 'Bakari', + 'Marquavius', + 'Artavious', + 'Desmon', + 'Rajohn', + 'Faheem', + 'Kage', + 'Arkeem', + 'Jaquon', + 'Dontavis', + 'Quentavious', + 'Braysen', + 'Bricen', + 'Traevon', + 'Caidyn', + 'Collyn', + 'Joah', + 'Patton', + 'Coleson', + 'Eythan', + 'Hadley', + 'Jaaziel', + 'Johntavious', + 'Quadarius', + 'Rafeal', + 'Karam', + 'Krishiv', + 'Majd', + 'Yeray', + 'Whitten', + 'Johnluke', + 'Demani', + 'Easten', + 'Ediel', + 'Tellis', + 'Delvecchio', + 'Aleks', + 'Rylie', + 'Osmel', + 'Lelan', + 'Tamarion', + 'Cayman', + 'Hajime', + 'Akio', + 'Takao', + 'Seiji', + 'Ah', + 'Mitsugi', + 'Koichi', + 'Ikenna', + 'Tyquavious', + 'Brannen', + 'Slayde', + 'Sultan', + 'Cage', + 'Jillian', + 'Kara', + 'Simone', + 'Theresa', + 'Julie', + 'Alisha', + 'Candace', + 'Candice', + 'Jazmine', + 'Domani', + 'Tiana', + 'Jeovanni', + 'Khaleb', + 'Copeland', + 'Dathan', + 'Deleon', + 'Jakori', + 'Jayke', + 'Kadon', + 'Camdon', + 'Shandon', + 'Mylan', + 'Jaxin', + 'Beverley', + 'Dallon', + 'Jakeem', + 'Tallon', + 'Vraj', + 'Welford', + 'Jadarian', + 'Yancarlos', + 'Omkar', + 'Jamaree', + 'Alix', + 'Trevyn', + 'Orestes', + 'Trevis', + 'Refoel', + 'Roddrick', + 'Tarvis', + 'Tamarick', + 'Denard', + 'Kerem', + 'Treyden', + 'Stephano', + 'Shubh', + 'Carston', + 'Utah', + 'Treven', + 'Reshard', + 'Yerachmiel', + 'Osmany', + 'Vansh', + 'Samaad', + 'Shakil', + 'Saford', + 'Doyal', + 'Cai', + 'Alexey', + 'Cruze', + 'Masiah', + 'Kitai', + 'Fedor', + 'Algie', + 'Worley', + 'Jakhari', + 'Brison', + 'Lanier', + 'Eston', + 'Qadir', + 'Lonzie', + 'Rayfield', + 'Chirstopher', + 'Eron', + 'Deontray', + 'Zoltan', + 'Christon', + 'Byford', + 'Mikeal', + 'Talyn', + 'Stormy', + 'Laramie', + 'Chrisopher', + 'Breckin', + 'Kennon', + 'Json', + 'Deiondre', + 'Heron', + 'Mykal', + 'Kalai', + 'Ervey', + 'Brayam', + 'Alakai', + 'Maika', + 'Kelson', + 'Trevaughn', + 'Aundre', + 'Eathan', + 'Keylon', + 'Kolbe', + 'Sebastion', + 'Kalib', + 'Jermy', + 'Jarrid', + 'Gumaro', + 'Maliq', + 'Armstead', + 'Stephone', + 'Oris', + 'Hassel', + 'Antwine', + 'Lorraine', + 'Budd', + 'Irfan', + 'Kamrin', + 'Araf', + 'Affan', + 'Leiby', + 'Sruly', + 'Peretz', + 'Mildred', + 'Louise', + 'Ryken', + 'Ryler', + 'Tayven', + 'Taysen', + 'Brexton', + 'Zayaan', + 'Oronde', + 'Firman', + 'Collen', + 'Letcher', + 'Clearence', + 'Braydan', + 'Yasser', + 'Jeferson', + 'Yahsir', + 'Cavan', + 'Ivor', + 'Hasker', + 'Kodie', + 'Lori', + 'Jaysean', + 'Cadin', + 'Breydon', + 'Amaree', + 'Nyeem', + 'Menno', + 'Orlo', + 'Nassir', + 'Sylar', + 'Drevon', + 'Burech', + 'Lenox', + 'Shloima', + 'Daris', + 'Diontae', + 'Aidin', + 'Brydon', + 'Jasean', + 'Nasier', + 'Johney', + 'Gabrial', + 'Fate', + 'Colyn', + 'Kaleem', + 'Capers', + 'Rembert', + 'Jquan', + 'Legrand', + 'Kirubel', + 'Gaberiel', + 'Thaddaeus', + 'Rece', + 'Dymir', + 'Tylil', + 'Remigio', + 'Ahad', + 'Melquiades', + 'Ethel', + 'Euel', + 'Harvy', + 'Margarita', + 'Jakeb', + 'Kagan', + 'Trinton', + 'Faiz', + 'Iliyan', + 'Emeterio', + 'Ferman', + 'Keeton', + 'Decorian', + 'Hadyn', + 'Rashaud', + 'Davontay', + 'Brallan', + 'Benancio', + 'Espiridion', + 'Seledonio', + 'Estefan', + 'Chanse', + 'Dade', + 'Sisto', + 'Herbie', + 'Janson', + 'Eusevio', + 'Loye', + 'Leocadio', + 'Kaelon', + 'Trevian', + 'Christien', + 'Chrystian', + 'Daegan', + 'Rosbel', + 'Romero', + 'Kylin', + 'Treyvion', + 'Ezekial', + 'Jaice', + 'Jantzen', + 'Aadyn', + 'Tennyson', + 'Kaedan', + 'Kaiser', + 'Kanin', + 'Jerron', + 'Jonaven', + 'Elija', + 'Amon', + 'Valton', + 'Derwood', + 'Atilano', + 'Jovanie', + 'Kaemon', + 'Oluwatobi', + 'Atlee', + 'Tadd', + 'Tammy', + 'Lem', + 'Hilmar', + 'Foch', + 'Clenard', + 'Jd', + 'Jiovanny', + 'Ladarion', + 'Lleyton', + 'Adrik', + 'Webb', + 'Toddrick', + 'Jerrett', + 'Omero', + 'Wendel', + 'Teresa', + 'Cass', + 'Kedric', + 'Heraclio', + 'Rainier', + 'Lakota', + 'Sanjuan', + 'Daymon', + 'Rodd', + 'Yancey', + 'Trampas', + 'Viviano', + 'Heith', + 'Bj', + 'Trevante', + 'Ildefonso', + 'Jaeger', + 'Jamarkus', + 'Remijio', + 'Desiderio', + 'Ausencio', + 'Alejo', + 'Keldrick', + 'Sigifredo', + 'Treavor', + 'Britain', + 'Macedonio', + 'Kourtney', + 'Gerrick', + 'Jousha', + 'Klinton', + 'Montreal', + 'Catlin', + 'Danner', + 'Eliberto', + 'Eliodoro', + 'Lonnell', + 'Michiel', + 'Hermilo', + 'Jackey', + 'Todrick', + 'Irineo', + 'Wenceslao', + 'Duaine', + 'Cleto', + 'Gaylan', + 'Derrel', + 'Nabor', + 'Huck', + 'Hoy', + 'Antwaun', + 'Hoyte', + 'Flournoy', + 'Mayford', + 'Harlie', + 'Hansford', + 'Cutler', + 'Amerigo', + 'Teague', + 'Griffith', + 'Emidio', + 'Kenna', + 'Cru', + 'Arnett', + 'Gay', + 'Dencil', + 'Carman', + 'Doy', + 'Trevan', + 'Jahziel', + 'Rodricus', + 'Copper', + 'Dael', + 'Aydon', + 'Ricco', + 'Judas', + 'Kessler', + 'Romelo', + 'Slayton', + 'Marico', + 'Leevi', + 'Xadrian', + 'Jceon', + 'Kross', + 'Chancey', + 'Bayne', + 'Brylen', + 'Eidan', + 'Olvin', + 'Pearce', + 'Zak', + 'Jaiven', + 'Dani', + 'Bairon', + 'Cordarious', + 'Jaxyn', + 'Rylin', + 'Avin', + 'Bransen', + 'Eastyn', + 'Eyden', + 'Brenham', + 'Chaston', + 'Horatio', + 'Dakarai', + 'Jencarlo', + 'Jevan', + 'Jhayden', + 'Tracen', + 'Peggy', + 'Wynn', + 'Bennet', + 'Milas', + 'Ronal', + 'Kadrian', + 'Jhase', + 'Callahan', + 'Hays', + 'Braidyn', + 'Ezana', + 'Chidubem', + 'Virat', + 'Maxemiliano', + 'Ozias', + 'Pace', + 'Mordecai', + 'Tabor', + 'Phillipe', + 'Maritza', + 'Ricahrd', + 'Jeanette', + 'Sundeep', + 'Tyric', + 'Mina', + 'Nasser', + 'Nhia', + 'Giuliano', + 'Farid', + 'Ryo', + 'Delmont', + 'Klaus', + 'Traquan', + 'Dawayne', + 'Broward', + 'Drequan', + 'Cagney', + 'Shellie', + 'Torre', + 'Deepak', + 'Janmichael', + 'Lan', + 'Quentavius', + 'Quantez', + 'Markevious', + 'Melbourne', + 'Melford', + 'Xue', + 'Samnang', + 'Jarquez', + 'Montrez', + 'Dao', + 'Luvern', + 'Vue', + 'Jenaro', + 'Wacey', + 'Lorena', + 'Ly', + 'Casmere', + 'Marsean', + 'Marinus', + 'Shiro', + 'Shizuo', + 'Knowledge', + 'Baudelio', + 'Cher', + 'Christiaan', + 'Adriane', + 'Wilgus', + 'Gustabo', + 'Barnet', + 'Xeng', + 'Priscilla', + 'Sou', + 'Sumeet', + 'Vartan', + 'Herschell', + 'Montell', + 'Illya', + 'Flem', + 'Marwan', + 'Johnrobert', + 'Boleslaus', + 'Christie', + 'Ericberto', + 'Esmeralda', + 'Cecilia', + 'Purvis', + 'Benjie', + 'Sutter', + 'Sufyan', + 'Viraaj', + 'Sathvik', + 'Quitman', + 'Liborio', + 'Humbert', + 'Zakariah', + 'Yichen', + 'Seward', + 'Alf', + 'Sebastiano', + 'Guiseppe', + 'Stanislaw', + 'Tyrice', + 'Lenell', + 'Kewon', + 'Bahe', + 'Recardo', + 'Paola', + 'Ronson', + 'Naveed', + 'Karla', + 'Lamberto', + 'Leoncio', + 'Sandor', + 'Diamante', + 'Woodson', + 'Hargis', + 'Kelcey', + 'Daquon', + 'Estell', + 'Christapher', + 'Jalal', + 'Tania', + 'Tramell', + 'Victoralfonso', + 'Kento', + 'Kiet', + 'Krystopher', + 'Shaine', + 'Bejamin', + 'Virgel', + 'Toxie', + 'Goebel', + 'Tyon', + 'Norvin', + 'Savalas', + 'Othmar', + 'Jakaiden', + 'Reis', + 'Pratik', + 'Ashish', + 'Hutson', + 'Karmello', + 'Dacari', + 'Katsuji', + 'Sadamu', + 'Masatoshi', + 'Kiyoto', + 'Carols', + 'Waylen', + 'Shain', + 'Alexandru', + 'Jomo', + 'Kalei', + 'Shyam', + 'Zyan', + 'Tamar', + 'Prem', + 'Jamiyl', + 'Remmel', + 'Harlin', + 'Novak', + 'Fynn', + 'Gonsalo', + 'Maliki', + 'Loghan', + 'Cauy', + 'Kassem', + 'Jitsuo', + 'Itsuo', + 'Atsushi', + 'Sunao', + 'Sueo', + 'Hiromu', + 'Toshiyuki', + 'Osamu', + 'Mena', + 'Aldin', + 'Leticia', + 'Darick', + 'Kawan', + 'Rajahn', + 'Asmar', + 'Emarion', + 'Hilmer', + 'Dameyune', + 'Rondarius', + 'Brinson', + 'Trason', + 'Chung', + 'Eran', + 'Khanh', + 'Javarious', + 'Makel', + 'Zyquan', + 'Quintarius', + 'Duran', + 'Veasna', + 'Thao', + 'Gracin', + 'Eberardo', + 'Ming', + 'Lusiano', + 'Kaveh', + 'Truong', + 'Ying', + 'Kentravious', + 'Dillen', + 'Jamonte', + 'Arthuro', + 'Camarion', + 'Avett', + 'Mehdi', + 'Nishant', + 'Bartek', + 'Aarnav', + 'Jeffory', + 'Deen', + 'Dayshaun', + 'Kemonte', + 'Petar', + 'Yug', + 'Donat', + 'Sylvio', + 'Magdiel', + 'Christianjames', + 'Lessie', + 'Sander', + 'Rajvir', + 'Nahuel', + 'Pearlie', + 'Aaren', + 'Dimitry', + 'Aravind', + 'Aristotle', + 'Jeury', + 'Naji', + 'Tysheem', + 'Alcee', + 'Gustaf', + 'Jamarrion', + 'Zollie', + 'Malick', + 'Navin', + 'Juwon', + 'Usama', + 'Walid', + 'Quamel', + 'Sadiq', + 'Tamarcus', + 'Merwyn', + 'Ferdie', + 'Kalif', + 'Latif', + 'Davidson', + 'Aahan', + 'Shahid', + 'Min', + 'Kieren', + 'Oz', + 'Oryan', + 'Madox', + 'Kota', + 'Gurshaan', + 'Gagik', + 'Finnigan', + 'Finlay', + 'Exodus', + 'Kaileb', + 'Jullien', + 'Jiovani', + 'Maryland', + 'Weaver', + 'Williard', + 'Keyondre', + 'Kailen', + 'Kanan', + 'Luisantonio', + 'Izack', + 'Daniela', + 'Colm', + 'Raja', + 'Keeshawn', + 'Adhemar', + 'Hillary', + 'Abdimalik', + 'Roark', + 'Kolston', + 'Cheryl', + 'Richardson', + 'Arif', + 'Jahkeem', + 'Kumar', + 'Raywood', + 'Jaiquan', + 'Earley', + 'Buren', + 'Rossie', + 'Jakayden', + 'Ruffus', + 'Zaquan', + 'Tamer', + 'Devonne', + 'Ikeem', + 'Dhruva', + 'Georges', + 'Kwabena', + 'Yeriel', + 'Glover', + 'Sanders', + 'Adonay', + 'Gillis', + 'Yomar', + 'Ediberto', + 'Antwane', + 'Isahi', + 'Haidyn', + 'Elizandro', + 'Markjoseph', + 'Jezreel', + 'Isayah', + 'Zedekiah', + 'Nikolay', + 'Jenner', + 'Uriyah', + 'Taiga', + 'Daniele', + 'Zacharie', + 'Joanne', + 'Manpreet', + 'Mohan', + 'Eliu', + 'Faraz', + 'Robah', + 'Isham', + 'Omarian', + 'Gagandeep', + 'Zeno', + 'Waddell', + 'Plato', + 'Quavon', + 'Talib', + 'Bascom', + 'Mayo', + 'Tequan', + 'Teron', + 'Anatole', + 'Tajh', + 'Algenis', + 'Liridon', + 'Kervens', + 'Yunior', + 'Kenson', + 'Wesly', + 'Antwann', + 'Zelig', + 'Demetrious', + 'Johnbenedict', + 'Josecarlos', + 'Kona', + 'Cj', + 'Atul', + 'Asaf', + 'Aleck', + 'Anthoni', + 'Anuar', + 'Gedalya', + 'Rafay', + 'Eyal', + 'Andry', + 'Natanel', + 'Nissim', + 'Jahdiel', + 'Jophy', + 'Rehaan', + 'Jhovani', + 'Maxximus', + 'Nain', + 'Yomtov', + 'Sheikh', + 'Demir', + 'Markos', + 'Mouhamadou', + 'Ousman', + 'Izreal', + 'Hadrian', + 'Aldrin', + 'Conlan', + 'Degan', + 'Toi', + 'Finneas', + 'Latroy', + 'Adon', + 'Antuan', + 'Elchonon', + 'Uzair', + 'Mohid', + 'Nazier', + 'Eliab', + 'Roc', + 'Pavan', + 'Yovanny', + 'Sinjin', + 'Tavoris', + 'Asiel', + 'Brayant', + 'Alexsandro', + 'Adrean', + 'Darel', + 'Olajuwon', + 'Corderro', + 'Tynan', + 'Xaiver', + 'Travaris', + 'Yonis', + 'Gerren', + 'Demon', + 'Furnell', + 'Juel', + 'Harish', + 'Raiyan', + 'Elia', + 'Elijha', + 'Gautham', + 'Arvind', + 'Audel', + 'Almer', + 'Djimon', + 'Jahi', + 'Gehrig', + 'Avant', + 'Arnell', + 'Eliaz', + 'Kaedon', + 'Jaedin', + 'Voshon', + 'Malachy', + 'Gilad', + 'Gabriele', + 'Riku', + 'Cameran', + 'Yoskar', + 'Jahfari', + 'Alexiz', + 'Javante', + 'Gregor', + 'Izel', + 'Donnovan', + 'Nikos', + 'Kodey', + 'Eytan', + 'Betzalel', + 'Dimitrius', + 'Chananya', + 'Graylin', + 'Samvel', + 'Yi', + 'Wassillie', + 'Kelechi', + 'Erroll', + 'Ardit', + 'Rahn', + 'Delaine', + 'Jule', + 'Idus', + 'Dessie', + 'Juda', + 'Levester', + 'Kiante', + 'Earnie', + 'Ihor', + 'Kapono', + 'Akoni', + 'Koamalu', + 'Sholem', + 'Howie', + 'Dariusz', + 'Hall', + 'Kekai', + 'Onix', + 'Ozie', + 'Liem', + 'Collis', + 'Lemon', + 'Hinton', + 'Guss', + 'Ronda', + 'Siddhartha', + 'Owyn', + 'Rye', + 'Riot', + 'Vander', + 'Selena', + 'Barnie', + 'Lewie', + 'Jaxiel', + 'Kaizen', + 'Haloa', + 'Dermot', + 'Misha', + 'Mister', + 'Nicholis', + 'Kevork', + 'Kia', + 'Houa', + 'Huriel', + 'Jesu', + 'Dionta', + 'Silvino', + 'Ivery', + 'Iokepa', + 'Geo', + 'Dex', + 'Izaan', + 'Jasraj', + 'Jakson', + 'Niel', + 'Avelardo', + 'Arjay', + 'Aran', + 'Alanzo', + 'Aidric', + 'Lomax', + 'Rawn', + 'Simmie', + 'Tonnie', + 'Yuto', + 'Mataio', + 'Nicodemus', + 'Maximilien', + 'Raider', + 'Ridley', + 'Orest', + 'Ramzi', + 'Kaikea', + 'Kamahao', + 'Kyrillos', + 'Mace', + 'Lyrik', + 'Lyon', + 'Lux', + 'Ashkan', + 'Jurgen', + 'Khachik', + 'Maher', + 'Jaccob', + 'Jagdeep', + 'Wash', + 'Simpson', + 'Macy', + 'Haylee', + 'Hope', + 'Katie', + 'Thurmon', + 'Savanna', + 'Zoey', + 'Atiba', + 'Dylann', + 'Kaylen', + 'Helio', + 'Geovannie', + 'Praneel', + 'Kamau', + 'Rhamel', + 'Knoah', + 'Harm', + 'Nyle', + 'Maveric', + 'Neithan', + 'Niklaus', + 'Lejon', + 'Wai', + 'Indigo', + 'Sayed', + 'Abdias', + 'Daniil', + 'Rashod', + 'Wren', + 'Chico', + 'Jamarri', + 'Leiland', + 'Ranvir', + 'Mavrick', + 'Matai', + 'Deveon', + 'Teyon', + 'Ramell', + 'Haik', + 'Dupree', + 'Emon', + 'Jermal', + 'Bayley', + 'Marshell', + 'Blouncie', + 'Larson', + 'Lorenz', + 'Jhovanny', + 'Jeffie', + 'Portia', + 'Adron', + 'Calogero', + 'Mathews', + 'Aundra', + 'Aariv', + 'Keniel', + 'Jameis', + 'Konstantin', + 'Khayden', + 'Manford', + 'Polo', + 'Chanel', + 'Brittani', + 'Kazuki', + 'Kaelen', + 'Alice', + 'Maya', + 'Madeleine', + 'Kiana', + 'Latasha', + 'Felicia', + 'Gabriella', + 'Bolivar', + 'Eileen', + 'Alister', + 'Aidenn', + 'Nina', + 'Ellington', + 'Alecsander', + 'Ja', + 'Jarmaine', + 'Kyriakos', + 'Apostolos', + 'Leshawn', + 'Shondell', + 'Matvey', + 'Savino', + 'Zakariye', + 'Dozier', + 'Holland', + 'Haruto', + 'Hendrik', + 'Allah', + 'Johnanthony', + 'Eliyah', + 'Champ', + 'Dastan', + 'Caliph', + 'Manish', + 'Agostino', + 'Kaio', + 'Avyaan', + 'Gerasimos', + 'Refujio', + 'Munir', + 'Abdurrahman', + 'Selso', + 'Epimenio', + 'Suhayb', + 'Jock', + 'Larwence', + 'Saadiq', + 'Lilburn', + 'Selestino', + 'Randi', + 'Nysir', + 'Harlyn', + 'Basir', + 'Kathy', + 'Teddie', + 'Luqman', + 'Tyhir', + 'Mubarak', + 'Ridwan', + 'Filemon', + 'Bergen', + 'Danney', + 'Eual', + 'Melburn', + 'Esiquio', + 'Cree', + 'Dorwin', + 'Naasir', + 'Ysmael', + 'Nirav', + 'Chuckie', + 'Lashaun', + 'Darris', + 'Blase', + 'Kiley', + 'Demarko', + 'Taiwan', + 'Lamon', + 'Corrie', + 'Feras', + 'Excell', + 'Cornelious', + 'Martinez', + 'Marvel', + 'Climmie', + 'Martrell', + 'Valley', + 'Lonie', + 'Jovante', + 'Lavante', + 'Lugene', + 'Cordarro', + 'Lacey', + 'Derrius', + 'Tedd', + 'Levell', + 'Linas', + 'Taras', + 'Toma', + 'Klint', + 'Gualberto', + 'Feliberto', + 'Tarrance', + 'Theran', + 'Lakeith', + 'Mearl', + 'Karry', + 'Denarius', + 'Dontarius', + 'Nikia', + 'Rakesh', + 'Not', + 'Darek', + 'Gery', + 'Ontario', + 'Jimi', + 'Shamarion', + 'Kedarius', + 'Jermarcus', + 'Amarie', + 'Kordae', + 'Montie', + 'Haleem', + 'Inocencio', + 'Brockton', + 'Yoshiaki', + 'Ponciano', + 'Silvester', + 'Derron', + 'Davaughn', + 'Urie', + 'Juanito', + 'Corky', + 'Pasqual', + 'Marilyn', + 'Morley', + 'Ayoub', + 'Eliasar', + 'Mickel', + 'Skylor', + 'Kewan', + 'Teon', + 'Rafal', + 'Devanta', + 'Rosco', + 'Tywon', + 'Evon', + 'Cleven', + 'Hardie', + 'Tori', + 'Trayvond', + 'Maaz', + 'Masashi', + 'Neno', + 'Kahari', + 'Terri', + 'Toru', + 'Jalynn', + 'Avonte', + 'Satchel', + 'Tanya', + 'Kalab', + 'Avetis', + 'Miko', + 'Kodiak', + 'Lang', + 'Leondre', + 'Purnell', + 'Harutyun', + 'Gorman', + 'Vong', + 'Shervin', + 'Soloman', + 'Sue', + 'Amandeep', + 'Amritpal', + 'Leonides', + 'Melecio', + 'Mikhael', + 'Estaban', + 'Arius', + 'Calix', + 'Gurtaj', + 'Dilraj', + 'Dillinger', + 'Aidden', + 'Shivansh', + 'Shravan', + 'Saud', + 'Yarel', + 'Riker', + 'Yareth', + 'Zeppelin', + 'Ladarious', + 'Lucan', + 'Terren', + 'Tustin', + 'Nicolaas', + 'Rakan', + 'Johnjoseph', + 'Hovanes', + 'Navjot', + 'Henrique', + 'Marsalis', + 'Karanveer', + 'Jeffren', + 'Khairi', + 'Haruki', + 'Jadden', + 'Iliya', + 'Hansen', + 'Srihan', + 'Sartaj', + 'Rishik', + 'Rishan', + 'Octavian', + 'Ranbir', + 'Padraic', + 'Tanush', + 'Tlaloc', + 'Cadarius', + 'Yared', + 'Vahan', + 'Lakai', + 'Fionn', + 'Eziah', + 'Emillio', + 'Hakob', + 'Gryphon', + 'Harsha', + 'Hiroto', + 'Nivaan', + 'Radin', + 'Nicasio', + 'Mael', + 'Lysander', + 'Rees', + 'Roemello', + 'Bretton', + 'Christoph', + 'Eliceo', + 'Armany', + 'Axell', + 'Bogdan', + 'Luan', + 'Aldon', + 'Aeson', + 'Adhvik', + 'Jese', + 'Blanca', + 'Crisanto', + 'Dietrich', + 'Tarin', + 'Yama', + 'Yia', + 'Omeed', + 'Arbie', + 'Shayn', + 'Ranferi', + 'Ricard', + 'Farmer', + 'Goble', + 'Herald', + 'Hager', + 'Elva', + 'Carlis', + 'Evertt', + 'Ledford', + 'Dequarius', + 'Hughie', + 'Burgess', + 'Kourosh', + 'Jaun', + 'Nicko', + 'Victorhugo', + 'Roverto', + 'Shadi', + 'Sopheak', + 'Acie', + 'Demar', + 'Carolina', + 'Vinal', + 'Earland', + 'Sergey', + 'Dayon', + 'Kwamaine', + 'Kerney', + 'Ola', + 'Welby', + 'Kyon', + 'Tyion', + 'Kiyon', + 'Neng', + 'Raquel', + 'Nadeem', + 'Terran', + 'Tin', + 'Rudi', + 'Murad', + 'Murrell', + 'Lenville', + 'Rondall', + 'Han', + 'Hovhannes', + 'Karapet', + 'Hamed', + 'Alasdair', + 'Agam', + 'Areg', + 'Ariston', + 'Askari', + 'Ayansh', + 'Byran', + 'Dolan', + 'Devonn', + 'Edith', + 'Christoffer', + 'Alaa', + 'Ashraf', + 'Rondle', + 'Tavarius', + 'Michaeljames', + 'Nichols', + 'Sonia', + 'Ryanchristopher', + 'Garo', + 'Hien', + 'Corin', + 'Dillin', + 'Jerid', + 'Jesusalberto', + 'Zeferino', + 'Gobel', + 'Tykeem', + 'Miking', + 'Juno', + 'Jiraiya', + 'Kailash', + 'Madix', + 'Lucciano', + 'Llewyn', + 'Leone', + 'Knight', + 'Dorse', + 'Oak', + 'Irie', + 'Brodi', + 'Hridhaan', + 'Coda', + 'Dekker', + 'Evren', + 'Eisen', + 'Eddison', + 'Donatello', + 'Happy', + 'Devron', + 'Suleiman', + 'Siddhanth', + 'Zorawar', + 'Zadkiel', + 'Waylan', + 'Valor', + 'Triton', + 'Govanni', + 'Angelus', + 'Ashvin', + 'Matthews', + 'Elver', + 'Brendin', + 'Rhea', + 'Jyron', + 'Matisse', + 'Karanvir', + 'Kenshin', + 'Saketh', + 'Trigo', + 'Wil', + 'Tyrick', + 'Trejon', + 'Manvir', + 'Sascha', + 'Samay', + 'Prabhjot', + 'Piers', + 'Arshia', + 'Karo', + 'Makani', + 'Ludwin', + 'Kean', + 'Nikoli', + 'Garlin', + 'Georgio', + 'Jyren', + 'Ledell', + 'Jayceion', + 'Wiltz', + 'Elgie', + 'Jediah', + 'Izzac', + 'Izeyah', + 'Jeyson', + 'Hamid', + 'Jalani', + 'Rohin', + 'Shiva', + 'Ramces', + 'Claudell', + 'Daymien', + 'Aeron', + 'Aadan', + 'Alesandro', + 'Aleksey', + 'Galileo', + 'Esvin', + 'Indy', + 'Graden', + 'Gor', + 'Vlad', + 'Kendrell', + 'Saket', + 'Asahel', + 'Blue', + 'Arshdeep', + 'Adain', + 'Keneth', + 'Jacy', + 'Dasan', + 'Haniel', + 'Ethin', + 'Ericson', + 'Izick', + 'Elisandro', + 'Coltrane', + 'Kemani', + 'Josearmando', + 'Josealfredo', + 'Alias', + 'Anurag', + 'Carlitos', + 'Ceaser', + 'Sukhraj', + 'Severin', + 'Nishanth', + 'Mattox', + 'Rhiley', + 'Dareon', + 'Danyel', + 'Calan', + 'Nithin', + 'Donivan', + 'Taye', + 'Trustin', + 'Igor', + 'Jayr', + 'Kayin', + 'Pleas', + 'Aadit', + 'Balam', + 'Jovannie', + 'Quintrell', + 'Japheth', + 'Hero', + 'Edu', + 'Duvan', + 'Anden', + 'Anshul', + 'Ailton', + 'Raybon', + 'Rabon', + 'Kendry', + 'Manases', + 'Damyan', + 'Braven', + 'Dhani', + 'Isaia', + 'Hovik', + 'Sonnie', + 'Wolfe', + 'Banyan', + 'Hiroki', + 'Matin', + 'Sequoia', + 'Acelin', + 'Aarya', + 'Arsalan', + 'Carlosdaniel', + 'Jaryd', + 'Ariana', + 'Kylee', + 'Mariah', + 'Serenity', + 'Kailey', + 'Delaney', + 'Emilee', + 'Isabelle', + 'Jayla', + 'Drue', + 'Emani', + 'Juandedios', + 'Kedar', + 'Baily', + 'Daijon', + 'Daman', + 'Kentaro', + 'Damaria', + 'Mareco', + 'Valmore', + 'Theophile', + 'Winslow', + 'Ugo', + 'Cainan', + 'Finian', + 'Keiji', + 'Issack', + 'Blanchard', + 'Domingos', + 'Jarin', + 'Giovan', + 'Ovila', + 'Lovelace', + 'Albion', + 'Curry', + 'Christophr', + 'Nolton', + 'Unborn', + 'Torry', + 'Yoshi', + 'Perrion', + 'Nathyn', + 'Syler', + 'Sheila', + 'Jaedan', + 'Cobey', + 'Bashar', + 'Ehsan', + 'Daryll', + 'Seann', + 'Niels', + 'Nazar', + 'Frederico', + 'Esther', + 'Bobie', + 'Loyce', + 'Heberto', + 'Bentura', + 'Jafar', + 'Keigan', + 'Bertil', + 'Aloys', + 'Janie', + 'Paz', + 'Damacio', + 'Oiva', + 'Ingvald', + 'Walfred', + 'Jakeob', + 'Georgie', + 'Alcuin', + 'Raynold', + 'Josey', + 'Lasaro', + 'Jo', + 'Hjalmer', + 'Philemon', + 'Paula', + 'Christophor', + 'Estanislao', + 'Angelita', + 'Anacleto', + 'Alfons', + 'Lawayne', + 'Delrico', + 'Clemson', + 'Jaleen', + 'Jerimy', + 'Javaughn', + 'Tiofilo', + 'Hubbard', + 'Abundio', + 'Derl', + 'Keagen', + 'Aymen', + 'Freedom', + 'Venancio', + 'Pauline', + 'Gorden', + 'Hani', + 'Pharrell', + 'Jager', + 'Nyair', + 'Azeem', + 'Khyir', + 'Jabriel', + 'Yandiel', + 'Zaahir', + 'Laine', + 'Xai', + 'Vernard', + 'Augie', + 'Sostenes', + 'Darryll', + 'Asir', + 'Lindon', + 'Jearl', + 'Peder', + 'Rudolpho', + 'Clancy', + 'Yue', + 'Ronnald', + 'Onofre', + 'Kysir', + 'Helmuth', + 'Marlowe', + 'Derk', + 'Demetrick', + 'Jefrey', + 'Burrell', + 'Robie', + 'Marlan', + 'Thane', + 'Jamire', + 'Donnel', + 'Syaire', + 'York', + 'Asaad', + 'Kyair', + 'Devere', + 'Wing', + 'Yaniv', + 'Mathhew', + 'Silvia', + 'Chia', + 'Bren', + 'Cavin', + 'Aldrich', + 'Judy', + 'Erron', + 'Butler', + 'Carole', + 'Almon', + 'Gilles', + 'Christin', + 'Renald', + 'Sony', + 'Chavis', + 'Nghia', + 'Mercedes', + 'Real', + 'Josejesus', + 'Ryman', + 'Kori', + 'Ichael', + 'Jabier', + 'Nguyen', + 'Angeldejesus', + 'Bobak', + 'Brittan', + 'Shaunt', + 'Karlton', + 'Jerin', + 'Gerado', + 'Raymund', + 'Kerolos', + 'Rolan', + 'Wilbern', + 'Sipriano', + 'Hermes', + 'Robyn', + 'Ynes', + 'Vernice', + 'Pink', + 'Jevonte', + 'Jerame', + 'Tajuan', + 'Mingo', + 'Jeremia', + 'Edmon', + 'Castulo', + 'Cleofas', + 'Arlee', + 'Oather', + 'Larkin', + 'Mcarther', + 'Ryann', + 'Hong', + 'Jamieson', + 'Enedino', + 'Gerad', + 'Lenord', + 'Alireza', + 'Hollie', + 'Gilford', + 'Lajuane', + 'Izell', + 'Trenidad', + 'Shelley', + 'Ulysees', + 'Juana', + 'Coalton', + 'Remer', + 'Raiford', + 'Caydon', + 'Dalyn', + 'Wilhelm', + 'Lenzy', + 'Bartow', + 'Tibor', + 'Cebert', + 'Elizar', + 'Ellen', + 'Uchenna', + 'Toy', + 'Curlee', + 'Ralf', + 'Giulio', + 'Conway', + 'Ngai', + 'Chaka', + 'Engelbert', + 'Auburn', + 'Socrates', + 'Kostas', + 'Kamalei', + 'Kupono', + 'Carrell', + 'Lister', + 'Mattie', + 'Thermon', + 'Tina', + 'Kennan', + 'Adison', + 'Dalon', + 'Ephram', + 'Jaylynn', + 'Zabdiel', + 'Kaidon', + 'Juvencio', + 'Havis', + 'Dagan', + 'Dacorian', + 'Donavyn', + 'Evyn', + 'Issai', + 'Zenon', + 'Inman', + 'Hason', + 'Lehman', + 'Afton', + 'Clayborn', + 'Abrahm', + 'Neill', + 'Conard', + 'Mutsuo', + 'Seikichi', + 'Wetzel', + 'Masaji', + 'Masanobu', + 'Shigeto', + 'Edgel', + 'Goro', + 'Lovett', + 'Seiko', + 'Sakae', + 'Roshawn', + 'Antjuan', + 'Erby', + 'Jobe', + 'Ladarian', + 'Cyler', + 'Edel', + 'Hartsel', + 'Jill', + 'Jami', + 'Rabun', + 'Fulton', + 'Dreddy', + 'Corrado', + 'Harald', + 'Alterick', + 'Hala', + 'Powell', + 'Lesly', + 'Kalon', + 'Theodoros', + 'Etan', + 'Trev', + 'Javiel', + 'Jusiah', + 'Joncarlos', + 'Jhamari', + 'Rasheim', + 'Raysean', + 'Kreg', + 'Rahmell', + 'Kerby', + 'Eliga', + 'Clemon', + 'Aneudy', + 'Keiran', + 'Kensley', + 'Ludie', + 'Jorell', + 'Can', + 'Demondre', + 'Cierra', + 'Maurizio', + 'Tacuma', + 'Ryzen', + 'Jabar', + 'Tara', + 'Reign', + 'Jashon', + 'Lasean', + 'Artavius', + 'Akbar', + 'Un', + 'Kaikane', + 'Tanisha', + 'Elena', + 'Bridget', + 'Asia', + 'Latisha', + 'Rachael', + 'Latoya', + 'Elisabeth', + 'Janelle', + 'Ikea', + 'Kobey', + 'Kamaehu', + 'Keona', + 'Calixto', + 'Theotis', + 'Worthy', + 'Galo', + 'Holly', + 'Sevyn', + 'Petr', + 'Cerrone', + 'Tedrick', + 'Kymari', + 'Gerrard', + 'Eldo', + 'Alcides', + 'Derrian', + 'Eulas', + 'Leodis', + 'Akai', + 'Dalonte', + 'Pantelis', + 'Sheron', + 'Tommaso', + 'Treg', + 'Shirl', + 'Abrian', + 'Brewer', + 'Yamir', + 'Zadok', + 'Holdyn', + 'Jayanthony', + 'Eh', + 'Dayson', + 'Khaden', + 'Quintez', + 'Rontavious', + 'Markese', + 'Quintavis', + 'Daveion', + 'Tonny', + 'Jaevon', + 'Ahkeem', + 'Hy', + 'Adams', + 'Marian', + 'Huner', + 'Jarmarcus', + 'Treyon', + 'Tullio', + 'Oreste', + 'Oleg', + 'Xzavien', + 'Atzel', + 'Brenan', + 'Abriel', + 'Braylyn', + 'Chidera', + 'Lebaron', + 'Jameir', + 'Kameryn', + 'Shade', + 'Koltin', + 'Cordarrius', + 'Amelio', + 'Demarquez', + 'Tarus', + 'Calob', + 'Dmarco', + 'Creek', + 'Amen', + 'Cylas', + 'Davyn', + 'Haygen', + 'Godric', + 'Garn', + 'Renardo', + 'Locke', + 'Lexington', + 'Mazin', + 'Othniel', + 'Kruze', + 'Jaxston', + 'Jaxten', + 'Jeziah', + 'Jettson', + 'Zebastian', + 'Sarim', + 'Jawuan', + 'Tremain', + 'Hassell', + 'Quartez', + 'Hawkins', + 'Riggs', + 'Rebel', + 'Nael', + 'Kaycen', + 'Kamsiyochukwu', + 'Kagen', + 'Jrue', + 'Jaydeen', + 'Azazel', + 'Ayson', + 'Cheston', + 'Aarian', + 'Chavez', + 'Void', + 'Zacariah', + 'Keena', + 'Antwuan', + 'Labarron', + 'Quamere', + 'Mikell', + 'Prestyn', + 'Savian', + 'Dayden', + 'Jaivion', + 'Geremiah', + 'Aidon', + 'Bralyn', + 'Gianncarlo', + 'Jarquavious', + 'Muriel', + 'Akshar', + 'Kadir', + 'Najir', + 'Neko', + 'Jahaad', + 'Jdyn', + 'Kashon', + 'Jaquil', + 'Wah', + 'Delmos', + 'Masuo', + 'Nobuichi', + 'Kiichi', + 'Jerone', + 'Tatsumi', + 'Damarian', + 'Elier', + 'Lansing', + 'Heinrich', + 'Hasson', + 'Larrie', + 'Phyllis', + 'Jamoni', + 'Zylen', + 'Demoni', + 'Harrel', + 'Levie', + 'Zaryan', + 'Orazio', + 'Seymore', + 'Florence', + 'Kolter', + 'Kemper', + 'Daelyn', + 'Haddon', + 'Syon', + 'Sair', + 'Filadelfio', + 'Marquavion', + 'Breylon', + 'Filimon', + 'Abie', + 'Cortavious', + 'Achille', + 'Dontrez', + 'Matty', + 'Darshawn', + 'Overton', + 'Bashir', + 'Kavan', + 'Caidan', + 'Braelen', + 'Param', + 'Kani', + 'Percival', + 'Hartley', + 'Erminio', + 'Candler', + 'Ulyssee', + 'Damontae', + 'Ellijah', + 'Cesare', + 'Eleanor', + 'Eustace', + 'Joachim', + 'Tarique', + 'Altin', + 'Tyleek', + 'Posey', + 'Awais', + 'Daivon', + 'Zi', + 'Hammad', + 'Meshulem', + 'Nickie', + 'Brehon', + 'Dacoda', + 'Kwamane', + 'Rafuel', + 'Mikai', + 'Hensel', + 'Thelbert', + 'Valerio', + 'Trevonte', + 'Koran', + 'Cheick', + 'Shahzaib', + 'Tahsin', + 'Derry', + 'Mustapha', + 'Chucky', + 'Osborne', + 'Daquarius', + 'Marque', + 'Raquon', + 'Cherokee', + 'Keyshaun', + 'Mohamadou', + 'Keishawn', + 'Jahmeek', + 'Junaid', + 'Amil', + 'Mckoy', + 'Zackry', + 'Nyheim', + 'Nkosi', + 'Kweli', + 'Tydarius', + 'Umer', + 'Demorris', + 'Demarquis', + 'Hersch', + 'Luzer', + 'Li', + 'Aly', + 'Quade', + 'Quamaine', + 'Markee', + 'Jhoan', + 'Mert', + 'Supreme', + 'Tyheem', + 'Gomer', + 'Taseen', + 'Yousaf', + 'Yonason', + 'Gifford', + 'Ashar', + 'Sender', + 'Salah', + 'Saifan', + 'Raihan', + 'Nizar', + 'Abrahim', + 'Kunga', + 'Javis', + 'Evens', + 'Bayard', + 'Kaysan', + 'Padraig', + 'Ney', + 'Ahmet', + 'Misty', + 'Ayyan', + 'Saint', + 'Fern', + 'Wasil', + 'Nolie', + 'Zarif', + 'Younis', + 'Eesa', + 'Ketrick', + 'Veryl', + 'Refael', + 'Motty', + 'Naftuly', + 'Waseem', + 'Yusif', + 'Brigg', + 'Zaheer', + 'Shiya', + 'Karma', + 'Meilich', + 'Mihran', + 'Javares', + 'Efe', + 'Abubakr', + 'Avrumi', + 'Nayshawn', + 'Mostafa', + 'Hinckley', + 'Jahmeir', + 'Fintan', + 'Sollie', + 'Amiel', + 'Abu', + 'Yaro', + 'Josha', + 'Jermane', + 'Bertis', + 'Hernando', + 'Gerrod', + 'Haim', + 'Frandy', + 'Andrews', + 'Dayle', + 'Fleming', + 'Volvi', + 'Savior', + 'Shuford', + 'Plummer', + 'Ralston', + 'Dayvion', + 'Muhamed', + 'Naheem', + 'Nataniel', + 'Kaeleb', + 'Billyjoe', + 'Able', + 'Fareed', + 'Purcell', + 'Trayson', + 'Mackay', + 'Moyer', + 'Haynes', + 'Domnick', + 'Burnie', + 'Gleen', + 'Leavy', + 'Lennart', + 'Breken', + 'Arlind', + 'Clarnce', + 'Nissen', + 'Josiel', + 'Alvester', + 'Jaquay', + 'Nickolaos', + 'Ruddy', + 'Berkeley', + 'Flamur', + 'Sherif', + 'Shateek', + 'Ayodele', + 'Davone', + 'Meshach', + 'Kinston', + 'Algernon', + 'Dvonte', + 'Jawara', + 'Zamar', + 'Dayron', + 'Jaequan', + 'Tyrelle', + 'Jazion', + 'Tamel', + 'Torris', + 'Marguis', + 'Yuniel', + 'Saige', + 'Gottlieb', + 'Cori', + 'Dre', + 'Yordan', + 'Shaquell', + 'Jonel', + 'Kashaun', + 'Arjenis', + 'Tashan', + 'Fitzroy', + 'Francisc', + 'Kwaku', + 'Jakyri', + 'Trayton', + 'Jarrick', + 'Reginaldo', + 'Facundo', + 'Elma', + 'Dardan', + 'Dreshawn', + 'Demontray', + 'Chaddrick', + 'Roper', + 'Taariq', + 'Ausitn', + 'Jachai', + 'Duval', + 'Braun', + 'Taylan', + 'Dionis', + 'Samy', + 'Armistead', + 'Alize', + 'Tayshon', + 'Ainsley', + 'Kaheem', + 'Jaire', + 'Kyshawn', + 'Nahshon', + 'Aaliyah', + 'Shanard', + 'Azion', + 'Alana', + 'Alexia', + 'Breyon', + 'Trigg', + 'Wylder', + 'Zaydin', + 'Ziaire', + 'Zixuan', + 'Yanis', + 'Zair', + 'Zaven', + 'Alanmichael', + 'Viyan', + 'Vivan', + 'Klay', + 'Erico', + 'Tycho', + 'Waris', + 'Winter', + 'Aliyah', + 'Kamilo', + 'Kei', + 'Glendell', + 'Lilly', + 'Lauryn', + 'Jovian', + 'Shayla', + 'Tessa', + 'Jupiter', + 'Aaric', + 'Aadhav', + 'Jetson', + 'Abir', + 'Adhrit', + 'Alexandr', + 'Brooklynn', + 'Callie', + 'Ashlee', + 'Ashlyn', + 'Haleigh', + 'Heaven', + 'Jahkari', + 'Izaiyah', + 'Troyce', + 'Bige', + 'Hayze', + 'Neldon', + 'Marven', + 'Beckem', + 'Dvante', + 'Navarro', + 'Neiko', + 'Noeh', + 'Jen', + 'Torrian', + 'Helios', + 'Macallan', + 'Lio', + 'Wilkens', + 'Merrik', + 'Ameal', + 'Mujtaba', + 'Iktan', + 'Kavious', + 'Monterrio', + 'Hughey', + 'Calin', + 'Cali', + 'Jamaar', + 'Kenith', + 'Rihaan', + 'Deaglan', + 'Kelso', + 'Lavaris', + 'Ashot', + 'Marshun', + 'Rainer', + 'Rivan', + 'Talal', + 'Taiyo', + 'Minor', + 'Yvon', + 'Stonewall', + 'Merril', + 'Okie', + 'Trevino', + 'Imari', + 'Ithan', + 'Izmael', + 'Jayan', + 'Harut', + 'Harshaan', + 'Kainen', + 'Kalyan', + 'Kanishk', + 'Kotaro', + 'Josyah', + 'Vola', + 'Omarie', + 'Dmari', + 'Mannix', + 'Elad', + 'Shun', + 'Andriy', + 'Angelino', + 'Ary', + 'Axcel', + 'Becker', + 'Daxten', + 'Daemian', + 'Cypress', + 'Jakhai', + 'Warnie', + 'Maikel', + 'Davinci', + 'Calloway', + 'Vernal', + 'Tyrome', + 'Mont', + 'Ovie', + 'Hester', + 'Arvis', + 'Corbit', + 'Tarvaris', + 'Audra', + 'Cloud', + 'Taveon', + 'Balian', + 'Bodi', + 'Brodee', + 'Kainan', + 'Dezi', + 'Devesh', + 'Emad', + 'Esa', + 'Massie', + 'Moir', + 'Markavious', + 'Veachel', + 'Dalan', + 'Carles', + 'Antawn', + 'Jermichael', + 'Talin', + 'Sy', + 'Murrel', + 'Elster', + 'Kru', + 'Okley', + 'Maverik', + 'Diangelo', + 'Burns', + 'Jamaris', + 'Jayshaun', + 'Dantae', + 'Rahil', + 'Renny', + 'Rohith', + 'Strummer', + 'Birchel', + 'Astor', + 'Nolyn', + 'Neeko', + 'Reyan', + 'Kailan', + 'Jaideep', + 'Manveer', + 'Maeson', + 'Khris', + 'Lancelot', + 'Shaunak', + 'Shubham', + 'Siaosi', + 'Ruslan', + 'Sajan', + 'Renwick', + 'Yann', + 'Vitali', + 'Zealand', + 'Vyom', + 'Xabi', + 'Yazid', + 'Terrelle', + 'Oaks', + 'Kache', + 'Arjuna', + 'Cephas', + 'Holmes', + 'Rockie', + 'Elray', + 'Doc', + 'Mell', + 'Tyresse', + 'Maguire', + 'Sheddrick', + 'Loney', + 'Helaman', + 'Andrus', + 'Asberry', + 'Love', + 'Clebert', + 'Cashius', + 'Egypt', + 'Devansh', + 'Elige', + 'Tobe', + 'Taten', + 'Arias', + 'Leandrew', + 'Dekota', + 'Varian', + 'Lehi', + 'Colbert', + 'Ignace', + 'Suhas', + 'Syris', + 'Ahan', + 'Aithan', + 'Aiven', + 'Akshath', + 'Hamp', + 'Kato', + 'Leeon', + 'Reubin', + 'Lukah', + 'Wilmon', + 'Tait', + 'Theophilus', + 'Sion', + 'Maysen', + 'Nicoli', + 'Nason', + 'Mykell', + 'Montae', + 'Laszlo', + 'Lestat', + 'Prithvi', + 'Maxi', + 'Mekhai', + 'Hammond', + 'Atiksh', + 'Aldean', + 'Aldine', + 'Jedi', + 'Almond', + 'Edahi', + 'Hisham', + 'Clide', + 'Cosby', + 'Hayato', + 'Harnoor', + 'Gurjot', + 'Ethridge', + 'Dublin', + 'Daimian', + 'Derreon', + 'Hansell', + 'Mae', + 'Semisi', + 'Ulysess', + 'Render', + 'Eschol', + 'Rodell', + 'Atzin', + 'Alik', + 'Amiri', + 'Keyvon', + 'Noland', + 'Terius', + 'Isauro', + 'Harshith', + 'Pledger', + 'Tilman', + 'Lennis', + 'Jovin', + 'Jaymin', + 'Jaydee', + 'Asbury', + 'Lovie', + 'Mcclinton', + 'Grayton', + 'Cardin', + 'Jacey', + 'Gurveer', + 'Ethanmatthew', + 'Aaronjames', + 'Ascher', + 'Aarion', + 'Windle', + 'Jahan', + 'Jayen', + 'Jatin', + 'Jedrek', + 'Anthonyjr', + 'Dabney', + 'Galvin', + 'Ilijah', + 'Gohan', + 'Quaid', + 'Teancum', + 'Chael', + 'Chetan', + 'Cylis', + 'Manas', + 'Logun', + 'Karston', + 'Mickeal', + 'Iskander', + 'Isaah', + 'Aryaman', + 'Juvens', + 'Joncarlo', + 'Gurkirat', + 'Laymon', + 'Salesi', + 'Rion', + 'Tao', + 'Tadhg', + 'Stephens', + 'Terryl', + 'Jacquan', + 'Zubin', + 'Yul', + 'Yadriel', + 'Dolph', + 'Keiden', + 'Koston', + 'Demetre', + 'Kameren', + 'Kaedin', + 'Zebedee', + 'Tyrie', + 'Truth', + 'Lanorris', + 'Tilden', + 'Tidus', + 'Thelonious', + 'Tennessee', + 'Sirius', + 'Pervis', + 'Saatvik', + 'Adley', + 'Amarian', + 'Numa', + 'Bronco', + 'Zian', + 'Zephan', + 'Yaziel', + 'Ajit', + 'Arick', + 'Ollin', + 'Kort', + 'Tayvin', + 'Grason', + 'Leonid', + 'Nihaal', + 'Koah', + 'Southern', + 'Kavish', + 'Joeziah', + 'Javi', + 'Kaiyan', + 'Kyro', + 'Ziad', + 'Maxen', + 'Xion', + 'Mica', + 'Mansour', + 'Matteus', + 'Renner', + 'Jonan', + 'Shilo', + 'Josedaniel', + 'Kaj', + 'Robel', + 'Krithik', + 'Lautaro', + 'Evann', + 'Carden', + 'Nathaneal', + 'Wirt', + 'Kile', + 'Kevonte', + 'Jazz', + 'Vardan', + 'Tanav', + 'Tamim', + 'Ojani', + 'Raydel', + 'Rigel', + 'Sheamus', + 'Cameryn', + 'Jedd', + 'Dalessandro', + 'Daejon', + 'Zacheriah', + 'Jt', + 'Valeria', + 'Treshon', + 'Martynas', + 'Markeese', + 'Ladislado', + 'Fidensio', + 'Cincere', + 'Amonte', + 'Erion', + 'Emin', + 'Tayten', + 'Zachory', + 'Ysidoro', + 'Treshaun', + 'Franciszek', + 'Adit', + 'Neftaly', + 'Kaylan', + 'Dezmon', + 'Joby', + 'Terrick', + 'Irma', + 'Isiaha', + 'Micha', + 'Sylvia', + 'Dejan', + 'Kippy', + 'Tyreece', + 'Corie', + 'Martese', + 'Senovio', + 'Lexus', + 'Freddrick', + 'Jemarcus', + 'Kuba', + 'Corion', + 'Andrian', + 'Romualdo', + 'Lyndal', + 'Kalem', + 'Laderrick', + 'Jobin', + 'Chaise', + 'Naren', + 'Reynol', + 'Ohm', + 'Trashawn', + 'Danyell', + 'Diron', + 'Kameran', + 'Dunte', + 'Ikechukwu', + 'Trendon', + 'Visente', + 'Valeriano', + 'Dillian', + 'Chantz', + 'Bacilio', + 'Crescencio', + 'Policarpio', + 'Janice', + 'Kem', + 'Rutilio', + 'Jaqualin', + 'Kendon', + 'Keevin', + 'Adelaido', + 'Coltan', + 'Theodoro', + 'Devondre', + 'Dekendrick', + 'Deionte', + 'Taz', + 'Jimmey', + 'Cristan', + 'Chancelor', + 'Ascension', + 'Kemon', + 'Makari', + 'Cordel', + 'Colbey', + 'Ambrocio', + 'Marselino', + 'Dewain', + 'Graciano', + 'Gumecindo', + 'Lorenso', + 'Quaylon', + 'Halbert', + 'Celedonio', + 'Terrin', + 'Zuri', + 'Sherod', + 'Ermal', + 'Elisa', + 'Larnell', + 'Tully', + 'Wenceslaus', + 'Lashun', + 'Duan', + 'Correy', + 'Wilburt', + 'Antwoin', + 'Lynell', + 'Ramond', + 'Victorio', + 'Antion', + 'Dragan', + 'Priest', + 'Marice', + 'Laroy', + 'Ninos', + 'Byrl', + 'Ebert', + 'Keita', + 'Dimitris', + 'Zoran', + 'Khaalis', + 'Rollo', + 'Alwin', + 'Loraine', + 'Jerard', + 'Lyndle', + 'Quirino', + 'Ramey', + 'Jarian', + 'Marky', + 'Adlai', + 'Shamon', + 'Treyshawn', + 'Shaft', + 'Gumercindo', + 'Rita', + 'Derryl', + 'Chancy', + 'Kacy', + 'Jonothan', + 'Ruston', + 'Ranulfo', + 'Talik', + 'Johntae', + 'Kendale', + 'Diandre', + 'Reginold', + 'Tyris', + 'Davell', + 'Ladell', + 'Raymone', + 'Mariusz', + 'Edvardo', + 'Joh', + 'Lavontae', + 'Markie', + 'Laquinton', + 'Alexandar', + 'Divante', + 'Jabin', + 'Shawon', + 'Jawann', + 'Ladd', + 'Khali', + 'Gilmore', + 'Oliverio', + 'Thuan', + 'Daiel', + 'Kierre', + 'Javar', + 'Stevon', + 'Derius', + 'Chadley', + 'Manual', + 'Johnaton', + 'Lc', + 'Erek', + 'Jakaden', + 'Jden', + 'Drayke', + 'Dawsen', + 'Jadarion', + 'Shriyans', + 'Raylin', + 'Kaydan', + 'Lynden', + 'Duard', + 'Elo', + 'Amarius', + 'Cleburne', + 'Dailen', + 'Brance', + 'Braycen', + 'Daiden', + 'Cruzito', + 'Caedyn', + 'Aizik', + 'Abyan', + 'Felisiano', + 'Taevion', + 'Zaeden', + 'Zadrian', + 'Fredie', + 'Burnis', + 'Cleave', + 'Ki', + 'Quandarius', + 'Quavion', + 'Makell', + 'Myrl', + 'Tae', + 'Melik', + 'Samarion', + 'Branton', + 'Vollie', + 'Reynolds', + 'Draylon', + 'Keivon', + 'Kevontae', + 'Deundre', + 'Zaydrian', + 'Zaydan', + 'Jotham', + 'Janthony', + 'Sahid', + 'Keilon', + 'Lain', + 'Kenechukwu', + 'Kanaan', + 'Kamdon', + 'Ahmod', + 'Dong', + 'Nnamdi', + 'Jontavius', + 'Kelijah', + 'Searcy', + 'Wheeler', + 'Francisca', + 'Burrel', + 'Zyquavious', + 'Kortez', + 'Tres', + 'Tranquilino', + 'Guinn', + 'Hiawatha', + 'Jasiyah', + 'Arlos', + 'Celestine', + 'Deadrian', + 'Chinedu', + 'Cane', + 'Caedon', + 'Gabryel', + 'Garon', + 'Solon', + 'Udell', + 'Medardo', + 'Chon', + 'Zakk', + 'Trip', + 'Somtochukwu', + 'Shooter', + 'Frutoso', + 'Laurencio', + 'Izayiah', + 'Franko', + 'Izzak', + 'Braelan', + 'Dryden', + 'Wilborn', + 'Newt', + 'Petronilo', + 'Nathanel', + 'Jatavius', + 'Locadio', + 'Tyquez', + 'Laiden', + 'Allister', + 'Javarion', + 'Demarrio', + 'Shenouda', + 'Rodriques', + 'Jenard', + 'Azarias', + 'Axxel', + 'Ariyan', + 'Pate', + 'Raidyn', + 'Saylor', + 'Kreed', + 'Kayce', + 'Bray', + 'Zyren', + 'Zayvien', + 'Yeiden', + 'Kinta', + 'Trampus', + 'Lofton', + 'Zayvian', + 'Zaydon', + 'Zaidan', + 'Weslee', + 'Robben', + 'Rook', + 'Roston', + 'Trigger', + 'Steel', + 'Rustyn', + 'Jaeceon', + 'Hutton', + 'Hatcher', + 'Kartier', + 'Kallan', + 'Daxtyn', + 'Corvin', + 'Deklyn', + 'Kaveon', + 'Leviathan', + 'Leelan', + 'Lael', + 'Prynce', + 'Korban', + 'Khyren', + 'Omran', + 'Oluwademilade', + 'Orenthal', + 'Dequavius', + 'Quinterrius', + 'Quantavis', + 'Astin', + 'Asaiah', + 'Dace', + 'Brylee', + 'Kenyan', + 'Jeovani', + 'Kolson', + 'Dreyden', + 'Jujuan', + 'Gregoria', + 'Abdon', + 'Javious', + 'Latravious', + 'Nanya', + 'Kaleel', + 'Elsie', + 'Iris', + 'Javarus', + 'Hunner', + 'Ebubechukwu', + 'Ashaz', + 'Huntley', + 'Montravious', + 'Argelio', + 'Amaar', + 'Abdulmalik', + 'Deronte', + 'Ramirez', + 'Travius', + 'Xavius', + 'Rashamel', + 'Martice', + 'Oshay', + 'Jamerson', + 'Derico', + 'Benino', + 'Otilio', + 'Palani', + 'Trystin', + 'Domonick', + 'Jayron', + 'Josephine', + 'Dora', + 'Larence', + 'Feliz', + 'Tereso', + 'Natalio', + 'Olga', + 'Bralen', + 'Temple', + 'Keala', + 'Anita', + 'Eathen', + 'Lamond', + 'Jakobie', + 'Johnthan', + 'Elnathan', + 'Edris', + 'Alcario', + 'Cornie', + 'Ival', + 'Pantaleon', + 'Deavion', + 'Daevion', + 'Dorance', + 'Jailon', + 'Ragene', + 'Kaena', + 'Kaimipono', + 'Keaka', + 'Kiai', + 'Babygirl', + 'Aukai', + 'Kaitlin', + 'Kaikoa', + 'Jedadiah', + 'Pono', + 'Layth', + 'Kolbie', + 'Naaman', + 'Pacey', + 'Jearld', + 'Corinthian', + 'Bryceson', + 'Kayzen', + 'Mana', + 'Janee', + 'Janae', + 'Kelli', + 'Tamara', + 'Nora', + 'Sophie', + 'Rashida', + 'Princess', + 'Lakeisha', + 'Nadia', + 'Monet', + 'Meaghan', + 'Marquita', + 'Chiquita', + 'Charlotte', + 'Chantelle', + 'Cassandra', + 'Cara', + 'Brandi', + 'Asha', + 'Tatiana', + 'Haaheo', + 'Valerie', + 'Valencia', + 'Shoso', + 'Yoshimi', + 'Bristol', + 'Mikio', + 'Nobuyuki', + 'Tomio', + 'Kazumi', + 'Kunio', + 'Yoshiharu', + 'Balentin', + 'Paublo', + 'Nobuyoshi', + 'Toshiaki', + 'Matsuo', + 'Hachiro', + 'Tokio', + 'Eichi', + 'Manabu', + 'Masanori', + 'Yoshiyuki', + 'Tokuo', + 'Eustolio', + 'Petra', + 'Fukuichi', + 'Haruyoshi', + 'Eastin', + 'Keygan', + 'Kelin', + 'Lalo', + 'Ramona', + 'Felis', + 'Rodgers', + 'Deigo', + 'Guerin', + 'Arrington', + 'Bradin', + 'Aurora', + 'Calistro', + 'Ervie', + 'Velma', + 'Whit', + 'Adarian', + 'Jakevion', + 'Jadrien', + 'Calub', + 'Kaegan', + 'Jamorian', + 'Milam', + 'Usiel', + 'Drayven', + 'Orange', + 'Daelon', + 'Jatavion', + 'Vastine', + 'Preciliano', + 'Floyce', + 'Billye', + 'Burney', + 'Consepcion', + 'Dason', + 'Osie', + 'Tashaun', + 'Sajid', + 'Umair', + 'Tymarion', + 'Jakorian', + 'Ginobili', + 'Areeb', + 'Jonovan', + 'Jonavan', + 'Jaqualyn', + 'Billey', + 'Luisgustavo', + 'Lamario', + 'Telford', + 'Lekendrick', + 'Brinton', + 'Lebarron', + 'Marrio', + 'Tyshun', + 'Kendarrius', + 'Zylan', + 'Jarrius', + 'Kadarrius', + 'Marvis', + 'Orie', + 'Kimber', + 'Jakevious', + 'Shawndale', + 'Jakel', + 'Jaquarious', + 'Deakon', + 'Brevan', + 'Rochester', + 'Lemmie', + 'Athony', + 'Rosie', + 'Lillie', + 'Mozell', + 'Aubert', + 'Kimble', + 'Jaymon', + 'Gaza', + 'Lysle', + 'Wasco', + 'Zigmond', + 'Addie', + 'Erastus', + 'Claudius', + 'Audley', + 'Thadeus', + 'Exum', + 'Caldwell', + 'Emmert', + 'Teagen', + 'Royden', + 'Mykale', + 'Lindberg', + 'Elmon', + 'Norfleet', + 'Radford', + 'Romulus', + 'Thedore', + 'Cor', + 'Ledarrius', + 'Cyncere', + 'Hurbert', + 'Pearly', + 'Jobie', + 'Garvey', + 'Meade', + 'Casmir', + 'Bertie', + 'Belvin', + 'Lynford', + 'Verdun', + 'Junie', + 'Dover', + 'Harlee', + 'Romolo', + 'Sirr', + 'Bradey', + 'Kingsten', + 'Manuelito', + 'Leno', + 'Primo', + 'Antonie', + 'Jane', + 'Halsey', + 'Mujahid', + 'Quron', + 'Cleophas', + 'Amedio', + 'Gildo', + 'Norvel', + 'Livingston', + 'Norvell', + 'Fard', + 'Khaleef', + 'Dorr', + 'Chaquille', + 'Giro', + 'Verdell', + 'Concetto', + 'Taevon', + 'Amato', + 'Hasaan', + 'Burr', + 'Payten', + 'Baden', + 'Abdirizak', + 'Emran', + 'Abdurahman', + 'Greig', + 'Sabree', + 'Shymir', + 'Haakon', + 'Aasim', + 'Abdifatah', + 'Cheemeng', + 'Yuepheng', + 'Hamsa', + 'Abdalla', + 'Samatar', + 'Joshawa', + 'Leeman', + 'Hershal', + 'Fayette', + 'Patty', + 'Thom', + 'Yaaseen', + 'Alven', + 'Hillis', + 'Bard', + 'Nymir', + 'Imir', + 'Mohamud', + 'Muaad', + 'Mickael', + 'Hermann', + 'Varner', + 'Norm', + 'Suheyb', + 'Eivin', + 'Jamy', + 'Taro', + 'Caydin', + 'Masaharu', + 'Cassie', + 'Virgie', + 'Oddie', + 'Pamela', + 'Emmette', + 'Rayshon', + 'Vardaman', + 'Ruble', + 'Clance', + 'Rigdon', + 'Osborn', + 'Gina', + 'Rozell', + 'Marcy', + 'Farron', + 'Bartolomeo', + 'Dierre', + 'Demetrus', + 'Yoneo', + 'Blayke', + 'Decarlo', + 'Sebert', + 'Quayon', + 'Nihar', + 'Segundo', + 'Ritik', + 'Aljaquan', + 'Lealon', + 'Opie', + 'Darshan', + 'Trapper', + 'Ladarrion', + 'Thaine', + 'Abanoub', + 'Filipe', + 'Oley', + 'Zaylan', + 'Rushi', + 'Watie', + 'Cleatus', + 'Harshil', + 'Alferd', + 'Carthel', + 'Ogden', + 'Carmin', + 'Hiren', + 'Harl', + 'Drexel', + 'Shadeed', + 'Malvern', + 'Argus', + 'Sharief', + 'Almalik', + 'Audy', + 'Terral', + 'Nuno', + 'Verna', + 'Alim', + 'Sherron', + 'Terek', + 'Clardie', + 'Shadee', + 'Clendon', + 'Johnpatrick', + 'Chritopher', + 'Taheem', + 'Jahid', + 'Waitman', + 'Jabraylen', + 'Quasim', + 'Azim', + 'Eulis', + 'Wladyslaw', + 'Delmus', + 'Minter', + 'Kharter', + 'Zavhary', + 'Taji', + 'Hoskie', + 'Colsen', + 'Orlanda', + 'Shawntez', + 'Obryan', + 'Emanual', + 'Silviano', + 'Chrishawn', + 'Rayon', + 'Martino', + 'Fairley', + 'Lenward', + 'Autzen', + 'Selby', + 'Odus', + 'Redell', + 'Seavy', + 'Dennison', + 'Jamiere', + 'Rondy', + 'Donold', + 'Lindwood', + 'Laudie', + 'Obert', + 'Jahki', + 'Braidon', + 'Zalen', + 'Zymier', + 'Jahzir', + 'Nahsir', + 'Vikrant', + 'Shourya', + 'Eliyohu', + 'Tyheim', + 'Keyshon', + 'Kaydence', + 'Ekin', + 'Tresean', + 'Quendarius', + 'Shammond', + 'Malakye', + 'Findlay', + 'Ashrith', + 'Elfego', + 'Jalik', + 'Nyzir', + 'Boe', + 'Abdikadir', + 'Jameek', + 'Gyasi', + 'Khyri', + 'Mohit', + 'Shayquan', + 'Sivan', + 'Steffon', + 'Lord', + 'Leor', + 'Kujtim', + 'Haaris', + 'Rafid', + 'Nechemia', + 'Nyles', + 'Khalik', + 'Tysheen', + 'Shaheim', + 'Starling', + 'Taiquan', + 'Takeem', + 'Teshawn', + 'Tuvia', + 'Shu', + 'Schyler', + 'Indalecio', + 'Edouard', + 'Alverto', + 'Alexio', + 'Aurash', + 'Fabiola', + 'Firas', + 'Fredis', + 'Guthrie', + 'Babacar', + 'Ayinde', + 'Khallid', + 'Shadrach', + 'Rikki', + 'Prescott', + 'Saam', + 'Perla', + 'Michell', + 'Markis', + 'Nou', + 'Sher', + 'Tor', + 'Kyre', + 'Shykeem', + 'Jilberto', + 'Klye', + 'Jeramey', + 'Herber', + 'Kue', + 'Mainor', + 'Macaulay', + 'Jequan', + 'Bond', + 'Hykeem', + 'Husam', + 'Catalina', + 'Danh', + 'Aaronmichael', + 'Anthonyjames', + 'Jerrid', + 'Jobani', + 'Kenia', + 'Oshae', + 'Michaelvincent', + 'Mong', + 'Dawit', + 'Dabid', + 'Daisuke', + 'Geddy', + 'Ehab', + 'Jarmal', + 'Caelin', + 'Barak', + 'Gurtej', + 'Geordan', + 'Jacobb', + 'Estefani', + 'Esaul', + 'Karandeep', + 'Jevaughn', + 'Kassim', + 'Kion', + 'Vikas', + 'Infinite', + 'Yekusiel', + 'Zohaib', + 'Yaw', + 'Sakib', + 'Shah', + 'Zeshan', + 'Hassaan', + 'Masai', + 'Mattheus', + 'Jeniel', + 'Martine', + 'Maalik', + 'Jeanclaude', + 'Stirling', + 'Trayveon', + 'Paymon', + 'Ajai', + 'Habib', + 'Enis', + 'Grafton', + 'Nissan', + 'Oshane', + 'Mirza', + 'Malike', + 'Yianni', + 'Zachari', + 'Tadeh', + 'Patrik', + 'Richy', + 'Riki', + 'Yao', + 'Yadira', + 'Nylan', + 'Lennard', + 'Roldan', + 'Admir', + 'Oniel', + 'Addam', + 'Itzel', + 'Ivann', + 'Shabab', + 'Honorio', + 'Hrag', + 'Harutun', + 'Keano', + 'Kayvan', + 'Takahiro', + 'Juanfrancisco', + 'Eri', + 'Ermon', + 'Ramzy', + 'Selma', + 'Kasean', + 'Obrian', + 'Jonatha', + 'Jonahtan', + 'Davione', + 'Chandara', + 'Chantha', + 'Lo', + 'Loreto', + 'Derell', + 'Ganesh', + 'Janathan', + 'Alejandr', + 'Rodolphe', + 'Isaul', + 'Bejan', + 'Doron', + 'Yvette', + 'Erlon', + 'Erland', + 'Yuji', + 'Milagro', + 'Ndrew', + 'Pedram', + 'Thinh', + 'Vandy', + 'Vi', + 'Ryanjoseph', + 'Richar', + 'Hosey', + 'Adeel', + 'Nicholos', + 'Michaeljohn', + 'Philipe', + 'Bravlio', + 'Anup', + 'Davide', + 'Daquann', + 'Lequan', + 'Raymel', + 'Rahsean', + 'Woodley', + 'Jarmel', + 'Wiliam', + 'Joseh', + 'Somnang', + 'Colvin', + 'Jenkins', + 'Jaquawn', + 'Javonne', + 'Javed', + 'Joelle', + 'Lameek', + 'Kishawn', + 'Krikor', + 'Christipher', + 'Ghassan', + 'Essa', + 'Hovig', + 'Nayquan', + 'Shawndell', + 'Rawle', + 'Marwin', + 'Record', + 'Dmario', + 'Crist', + 'La', + 'Access', + 'Shaquel', + 'Tyrrell', + 'Tiquan', + 'Shavon', + 'Shatique', + 'Yochanon', + 'Keontay', + 'Shaquelle', + 'Kshawn', + 'Armend', + 'Eliazer', + 'Diony', + 'Saddam', + 'Takayuki', + 'Sukhdeep', + 'Shahan', + 'Valon', + 'Orel', + 'Tremell', + 'Chayim', + 'Jaquille', + 'Ayodeji', + 'Bekim', + 'Besnik', + 'Oluwanifemi', + 'Stalin', + 'Sadam', + 'Aniel', + 'Laureat', + 'Dyrell', + 'Jhony', + 'Barkim', + 'Ludger', + 'Mahendra', + 'Kadeen', + 'Jovaughn', + 'Khadeem', + 'Ardian', + 'Ravindra', + 'Harpal', + 'Jatinder', + 'Erving', + 'Gerrell', + 'Sylvestre', + 'Luismanuel', + 'Pharell', + 'Jahziah', + 'Salif', + 'Jakyrin', + 'Idrissa', + 'Daoud', + 'Swan', + 'Pryor', + 'Polk', + 'Rameses', + 'Prateek', + 'Lelon', + 'Ebrima', + 'Ezechiel', + 'Tevan', + 'Sohail', + 'Luiseduardo', + 'Clearance', + 'Brayn', + 'Alexsis', + 'Edwar', + 'Johnmark', + 'Hikaru', + 'Edon', + 'Chezkel', + 'Dinari', + 'Ahmadou', + 'Jadien', + 'Ismaeel', + 'Heshy', + 'Jhan', + 'Dejohn', + 'Ajdin', + 'Damier', + 'Cashmere', + 'Amitai', + 'Alp', + 'Avrahom', + 'Hooper', + 'Daichi', + 'Dariush', + 'Bryen', + 'Oseas', + 'Moyses', + 'Alderic', + 'Dickson', + 'Joon', + 'Justinkyle', + 'Jassiah', + 'Jaidin', + 'Lexie', + 'Mieczyslaw', + 'Joffre', + 'Augustino', + 'Adelino', + 'Tadeusz', + 'Humphrey', + 'Lonas', + 'Avry', + 'Tylin', + 'Dixie', + 'Goldman', + 'Yissachar', + 'Toure', + 'Yafet', + 'Siraj', + 'Nasiah', + 'Maor', + 'Roniel', + 'Kerim', + 'Danieljr', + 'Django', + 'Lion', + 'Baruc', + 'Cervando', + 'Akul', + 'Abdi', + 'Ameya', + 'Arhan', + 'Aliou', + 'Arcangel', + 'Avrumy', + 'Deandrea', + 'Dontreal', + 'Yossef', + 'Walden', + 'Tameem', + 'Kenderick', + 'Yassine', + 'Zeyad', + 'Riyad', + 'Kashmere', + 'Tevis', + 'Malichi', + 'Malakhai', + 'Yulian', + 'Clearnce', + 'Esco', + 'Fabrizzio', + 'Gianpaolo', + 'Jaskirat', + 'Termaine', + 'Daouda', + 'Abba', + 'Aaban', + 'Chanoch', + 'Raynell', + 'Ihsan', + 'Djibril', + 'Cassiel', + 'Ishaq', + 'Azlan', + 'Behruz', + 'Amirjon', + 'Anisjon', + 'Asadbek', + 'Dhilan', + 'Dream', + 'Daviel', + 'Mosha', + 'Rayane', + 'Shabsi', + 'Olie', + 'Vinicio', + 'Yuda', + 'Shohjahon', + 'Kylematthew', + 'Kien', + 'Matthewjames', + 'Giorgi', + 'Konstantine', + 'Jibreel', + 'Jadriel', + 'Lliam', + 'Travonte', + 'Taiki', + 'Rendell', + 'Wyland', + 'Arafat', + 'Tajon', + 'Loic', + 'Shaw', + 'Sukhman', + 'Randiel', + 'Stefanos', + 'Lukus', + 'Majesty', + 'Massimiliano', + 'Burach', + 'Jansel', + 'Ismaila', + 'Henoch', + 'Daelin', + 'Giordano', + 'Huber', + 'Rontrell', + 'Simran', + 'Majid', + 'Rayjon', + 'Pharoah', + 'Lamine', + 'Hanoch', + 'Chidi', + 'Jahmani', + 'Javid', + 'Kamani', + 'Endrit', + 'Endy', + 'Nasean', + 'Danyael', + 'Cinque', + 'Akaash', + 'Zeeshan', + 'Amel', + 'Adib', + 'Aboubakar', + 'Artan', + 'Burak', + 'Serigne', + 'Samin', + 'Hovsep', + 'Jomari', + 'Cesareo', + 'Dajohn', + 'Charbel', + 'Bakary', + 'Camerin', + 'Jaquel', + 'Pape', + 'Jahrel', + 'Jahrell', + 'Khadim', + 'Jeison', + 'Yobany', + 'Zaul', + 'Taryn', + 'Abou', + 'Besim', + 'Abdur', + 'Ebrahim', + 'Albi', + 'Haadi', + 'Saba', + 'Wen', + 'Felipedejesus', + 'Dragon', + 'Jamiel', + 'Alecxis', + 'Ashkon', + 'Tejon', + 'Meelad', + 'Renan', + 'Brailyn', + 'Harel', + 'Abdou', + 'Amier', + 'Jonathanjoseph', + 'Juanalberto', + 'Larenz', + 'Nerses', + 'Emmanuelle', + 'Jasmeet', + 'Jahred', + 'Elsworth', + 'Nyshawn', + 'Alexes', + 'Cranford', + 'Trenell', + 'Cephus', + 'Costas', + 'Rama', + 'Nickalas', + 'Moultrie', + 'Deklin', + 'Saafir', + 'Alexie', + 'Kajuan', + 'Jamahl', + 'Robet', + 'Antoin', + 'Turhan', + 'Mart', + 'Richrd', + 'Ante', + 'Bransyn', + 'Dargan', + 'Levan', + 'Milledge', + 'Ollis', + 'Morey', + 'Jeromey', + 'Ebon', + 'Nicholus', + 'Yvonne', + 'Gladstone', + 'Kwan', + 'Sherry', + 'Romney', + 'Nicolaos', + 'Oded', + 'Koty', + 'Mandy', + 'Adger', + 'Esaw', + 'Shaunte', + 'Nimesh', + 'Ahren', + 'Marcellino', + 'Attila', + 'Pinkney', + 'Reinhard', + 'Deanna', + 'Shanti', + 'Calmer', + 'Reda', + 'Darral', + 'Monserrate', + 'Levert', + 'Harce', + 'Ayham', + 'Breslin', + 'Dom', + 'Darrow', + 'Haidar', + 'Willaim', + 'Shann', + 'Regina', + 'Einer', + 'Zui', + 'Shonn', + 'Skipper', + 'Henning', + 'Jacek', + 'Wendelin', + 'Wilmar', + 'Algot', + 'Marlen', + 'Dquan', + 'Emanuele', + 'Erol', + 'Boby', + 'Elbin', + 'Londell', + 'Bradd', + 'Malo', + 'Mohamadali', + 'Toussaint', + 'Roald', + 'Trini', + 'Stace', + 'Erubey', + 'Labron', + 'Kyseem', + 'Duong', + 'Rande', + 'Siegfried', + 'Mamon', + 'Va', + 'Quy', + 'Raman', + 'Ramil', + 'Jasai', + 'Carla', + 'Belen', + 'Lawernce', + 'Jemar', + 'Markham', + 'Kym', + 'Jemaine', + 'Baldwin', + 'Damany', + 'Timonthy', + 'Tesfa', + 'Vinod', + 'Albertus', + 'Yupheng', + 'Danie', + 'Tashiem', + 'Uno', + 'Onnie', + 'Juliana', + 'Duff', + 'Doua', + 'Orman', + 'Kamaal', + 'Godwin', + 'Ulric', + 'Darrold', + 'Rennie', + 'Lory', + 'Jamile', + 'Terril', + 'Gable', + 'Hanh', + 'Grisel', + 'Jimmylee', + 'Mikkel', + 'Victorino', + 'Jaymere', + 'Rayn', + 'Duriel', + 'Ceferino', + 'Autrey', + 'Durant', + 'Kolsen', + 'Abayomi', + 'Azell', + 'Spyros', + 'Ato', + 'Damin', + 'Diogenes', + 'Barnaby', + 'Pinckney', + 'Keno', + 'Sherard', + 'Chukwuemeka', + 'Akin', + 'Harvel', + 'Marv', + 'Kenyetta', + 'Huel', + 'Royzell', + 'Luddie', + 'Olden', + 'Ardith', + 'Branch', + 'Bertha', + 'Hillman', + 'Namon', + 'Donnis', + 'Fitzhugh', + 'Lavaughn', + 'Lucille', + 'Amanuel', + 'Carvin', + 'Minnie', + 'Tivis', + 'Birt', + 'Bronner', + 'Vaden', + 'Joenathan', + 'Alphonsa', + 'Elvie', + 'Alpheus', + 'Clausell', + 'Clayburn', + 'Demetrias', + 'Avis', + 'Garlon', + 'Romaine', + 'Jamorris', + 'Swanson', + 'Perez', + 'Hurschel', + 'Virge', + 'Rutherford', + 'Lelton', + 'Tarris', + 'Denson', + 'Benjaman', + 'Rashun', + 'Keino', + 'Cedarius', + 'Keanthony', + 'Blakeley', + 'Burwell', + 'Kasai', + 'Euell', + 'Eldrick', + 'Ashford', + 'Demetruis', + 'Wood', + 'Blanton', + 'Daniell', + 'Robt', + 'Lamorris', + 'Waller', + 'Devoris', + 'Herley', + 'Jermery', + 'Jamicheal', + 'Horton', + 'Gradie', + 'Etheridge', + 'Millie', + 'Jammy', + 'Karey', + 'Rodregus', + 'Cordera', + 'Embry', + 'Forney', + 'Sims', + 'Gergory', + 'Rosser', + 'Benjamine', + 'Erskin', + 'Heflin', + 'Torrie', + 'Norville', + 'Arvie', + 'Bessie', + 'Keonta', + 'Tarrence', + 'Chapman', + 'Limmie', + 'Tavius', + 'Reynard', + 'Lonza', + 'Detroit', + 'Camauri', + 'Clanton', + 'Obbie', + 'Mizell', + 'Marshel', + 'Tollie', + 'Jondarius', + 'Therion', + 'Antoino', + 'Beatrice', + 'Keyonte', + 'Littleton', + 'Hozie', + 'Atwell', + 'Ottie', + 'Pelham', + 'Vickie', + 'Cederick', + 'Zaykeese', + 'Jadarious', + 'Shin', + 'Tizoc', + 'Mischa', + 'Tycen', + 'Jubal', + 'Kito', + 'Sabin', + 'Brannan', + 'Baltasar', + 'Hilda', + 'Orasio', + 'Bassel', + 'Ameet', + 'Talus', + 'Renne', + 'Reuel', + 'Saro', + 'Kam', + 'Heliodoro', + 'Hodari', + 'Mondo', + 'Damaso', + 'Damein', + 'Thunder', + 'Ravinder', + 'Remberto', + 'Rodel', + 'Yvan', + 'Marcelle', + 'Kiril', + 'Shem', + 'Bardo', + 'Carlson', + 'Jebediah', + 'Austreberto', + 'Hannibal', + 'Shawnn', + 'Kenyatte', + 'Geoffry', + 'Hadden', + 'Natnael', + 'Edurdo', + 'Errik', + 'Eva', + 'Gaelan', + 'Gilverto', + 'Antwaine', + 'Barclay', + 'Rithy', + 'Sarath', + 'Sasan', + 'Stefen', + 'Susana', + 'Le', + 'Mai', + 'Marquies', + 'Neeraj', + 'Galdino', + 'Cuitlahuac', + 'Griselda', + 'Jerret', + 'Filbert', + 'Travone', + 'Lizette', + 'Lourdes', + 'Ratana', + 'Sarith', + 'Ku', + 'Jocob', + 'Jushua', + 'Shaughn', + 'Sophal', + 'Sophana', + 'Stepan', + 'Tramel', + 'Veniamin', + 'Ha', + 'Halley', + 'Hiep', + 'Maclain', + 'Alberta', + 'Alejando', + 'Eliana', + 'Chay', + 'Esmond', + 'Frisco', + 'Dai', + 'Marta', + 'Man', + 'Kha', + 'Kin', + 'Sun', + 'Paulmichael', + 'Rj', + 'Jeoffrey', + 'Custodio', + 'Herberth', + 'Gerrad', + 'Seanpaul', + 'Sten', + 'Nereida', + 'Jasun', + 'Micharl', + 'Robbert', + 'Ronnel', + 'Rosio', + 'Othon', + 'Chau', + 'Hart', + 'Atthew', + 'Angelito', + 'Debbie', + 'Randol', + 'Jeffrie', + 'Kern', + 'Rohn', + 'Raef', + 'Arleigh', + 'Jef', + 'Reg', + 'Vinton', + 'Perrin', + 'Parry', + 'Sally', + 'Hoby', + 'Vint', + 'Dagmawi', + 'Mat', + 'Gregrey', + 'Darol', + 'Merik', + 'Rickard', + 'Clete', + 'Fredrik', + 'Darrol', + 'Lyall', + 'Jamare', + 'Duffy', + 'Barre', + 'Shawnee', + 'Tige', + 'Whittaker', + 'Tyrion', + 'Jamas', + 'Jud', + 'Spence', + 'Dione', + 'Erinn', + 'Bron', + 'Ackley', + 'Dal', + 'Monti', + 'Paco', + 'Kjell', + 'Gabor', + 'Davinder', + 'Shonte', + 'Maximiano', + 'Heshimu', + 'Jassen', + 'Jerami', + 'Jermon', + 'Keefe', + 'Keri', + 'Daric', + 'Christropher', + 'Johnney', + 'Dodd', + 'Wilferd', + 'Raymondo', + 'Keary', + 'Orlan', + 'Gerhart', + 'Clemence', + 'Pepe', + 'Whitaker', + 'Vaughan', + 'Wess', + 'Abenezer', + 'Miroslav', + 'Kurk', + 'Helmut', + 'Timothey', + 'Annette', + 'Cruise', + 'Jahel', + 'Itay', + 'Isaiahs', + 'Isack', + 'Eagan', + 'Finbar', + 'Famous', + 'Ethanjoseph', + 'Ethanjames', + 'Edi', + 'Isais', + 'Albeiro', + 'Abhijot', + 'Joshuajames', + 'Amine', + 'Edwardjames', + 'Donyae', + 'Danieljohn', + 'Avaneesh', + 'Aryav', + 'Andoni', + 'Yeison', + 'Lowen', + 'Obi', + 'Mycah', + 'Moksh', + 'Miliano', + 'Maxamillion', + 'Lazlo', + 'Jocsan', + 'Jibran', + 'Jerimyah', + 'Jefte', + 'Korde', + 'Kanav', + 'Tavita', + 'Taesean', + 'Yoltzin', + 'Xzavior', + 'Vibhav', + 'Romen', + 'Rocket', + 'Rai', + 'Orian', + 'Rumi', + 'Shota', + 'Shaheer', + 'Sadrac', + 'Semaje', + 'Sohrob', + 'Yuval', + 'Yuren', + 'Yannis', + 'Vineet', + 'Yarden', + 'Jesusjr', + 'Kartik', + 'Jairon', + 'Millen', + 'Nahun', + 'Krisna', + 'Kyrese', + 'Mher', + 'Mayan', + 'Kais', + 'Joshuan', + 'Jometh', + 'Keawe', + 'Siris', + 'Sinai', + 'Shuban', + 'Shian', + 'Sneijder', + 'Sota', + 'Uday', + 'Sevak', + 'Royale', + 'Yuuki', + 'Reyhan', + 'Seena', + 'Moisses', + 'Nayib', + 'Sumit', + 'Dayveon', + 'Christianpaul', + 'Garrin', + 'Edgerrin', + 'Edrees', + 'Estephan', + 'Assael', + 'Azad', + 'Tydus', + 'Yosuf', + 'Zekiel', + 'Strider', + 'Senai', + 'Edmar', + 'Dmorea', + 'Eman', + 'Darran', + 'Keston', + 'Keny', + 'Hardeep', + 'Heladio', + 'Hernesto', + 'Hovannes', + 'Sankalp', + 'Brenten', + 'Navraj', + 'Mavrik', + 'Nilmar', + 'Rishit', + 'Edwing', + 'Eswin', + 'Flabio', + 'Jasn', + 'Romar', + 'Sevan', + 'Shahab', + 'Justinmichael', + 'Joseandres', + 'Marcelus', + 'Mariana', + 'Andhy', + 'Angeles', + 'Tannor', + 'Tristain', + 'Joshuaray', + 'Luisdavid', + 'Damaris', + 'Daymond', + 'Anthonyjohn', + 'Dezhon', + 'Emelio', + 'Eulices', + 'Maclean', + 'Jaeson', + 'Ethanjohn', + 'Ethanjacob', + 'Jasiri', + 'Kaisei', + 'Khyle', + 'Jona', + 'Jeren', + 'Jeramyah', + 'Jesusantonio', + 'Jguadalupe', + 'Joseeduardo', + 'Elkin', + 'Prashant', + 'Anguel', + 'Anant', + 'Aisea', + 'Abhimanyu', + 'Daelen', + 'Dylin', + 'Dodge', + 'Nazaret', + 'Mikie', + 'Matthewjoseph', + 'Maximillan', + 'Savir', + 'Dhillon', + 'Donoven', + 'Ebin', + 'Edrei', + 'Elek', + 'Nykolas', + 'Nikash', + 'Nik', + 'Reyly', + 'Razi', + 'Presten', + 'Arul', + 'Avo', + 'Yandell', + 'Wynston', + 'Tallen', + 'Suhaib', + 'Joshuajohn', + 'Jesusmanuel', + 'Malacai', + 'Kethan', + 'Londen', + 'Larenzo', + 'Kriss', + 'Kohei', + 'Hamlet', + 'Martinjr', + 'Mansoor', + 'Archit', + 'Aniketh', + 'Kincaid', + 'Lunden', + 'Masaki', + 'Salam', + 'Sahith', + 'Nour', + 'Miqueas', + 'Estefano', + 'Hatim', + 'Gurvir', + 'Adeeb', + 'Tobiah', + 'Torrin', + 'Tushar', + 'Tyee', + 'Sulayman', + 'Takai', + 'Tayo', + 'Yoan', + 'Vegas', + 'Duilio', + 'Dyami', + 'Greko', + 'Harim', + 'Ioane', + 'Ashmit', + 'Bora', + 'Alekxander', + 'Alexanderjames', + 'Amanpreet', + 'Anthonny', + 'Brandom', + 'Daimon', + 'Sirus', + 'Seananthony', + 'Vignesh', + 'Vir', + 'Wisdom', + 'Rameen', + 'Kenzie', + 'Joshuamichael', + 'Josejr', + 'Joseenrique', + 'Jacksen', + 'Jeriko', + 'Jesua', + 'Myka', + 'Naithen', + 'Saurav', + 'Shalim', + 'Puneet', + 'Denali', + 'Daveyon', + 'Sohil', + 'Edilson', + 'Jafeth', + 'Nathin', + 'Maurion', + 'Mekai', + 'Nadim', + 'Jamani', + 'Jamisen', + 'Gared', + 'Gahel', + 'Emron', + 'Hanzel', + 'Xaviar', + 'Yohann', + 'Alam', + 'Brasen', + 'Ashlan', + 'Rury', + 'Ralphie', + 'Robertanthony', + 'Tomoki', + 'Zamuel', + 'Urian', + 'Vinayak', + 'Wilberth', + 'Jazziel', + 'Mizraim', + 'Mosiah', + 'Muneeb', + 'Lennin', + 'Chaitanya', + 'Cyrille', + 'Dilpreet', + 'Bhargav', + 'Captain', + 'Camil', + 'Jaion', + 'Eithen', + 'Dominyk', + 'Domenik', + 'Imad', + 'Dabin', + 'Ceejay', + 'Avishek', + 'Anoop', + 'Aaronjoshua', + 'Billal', + 'Euan', + 'Eion', + 'Beauregard', + 'Fouad', + 'Chriss', + 'Daimien', + 'Cyan', + 'Conall', + 'Inigo', + 'Jashan', + 'Jaicob', + 'Arek', + 'Benjaminjoseph', + 'Bodey', + 'Andrewjames', + 'Abdel', + 'Alian', + 'Artyom', + 'Anik', + 'Angeljesus', + 'Shriyan', + 'Sosaia', + 'Shabd', + 'Tayveon', + 'Samik', + 'Josephanthony', + 'Kaushal', + 'Gerardojr', + 'Haile', + 'Henok', + 'Imer', + 'Izaiha', + 'Vedanth', + 'Rishav', + 'Praveen', + 'Kenner', + 'Juanjr', + 'Kinan', + 'Maven', + 'Neven', + 'Niccolas', + 'Raynav', + 'Rani', + 'Noahjames', + 'Nirvan', + 'Nevaan', + 'Naythen', + 'Rhythm', + 'Samyak', + 'Sahas', + 'Roczen', + 'Kroy', + 'Johanna', + 'Miro', + 'Mayank', + 'Masson', + 'Yamato', + 'Xaden', + 'Vin', + 'Tyden', + 'Gaudencio', + 'Garreth', + 'Toryn', + 'Jaswinder', + 'Stiles', + 'Graciela', + 'Rutger', + 'Razmig', + 'Keo', + 'Kavir', + 'Kalev', + 'Kal', + 'Kabeer', + 'Jianni', + 'Terrace', + 'Vicken', + 'Westly', + 'Pardeep', + 'Lizeth', + 'Lucia', + 'Mandela', + 'Maricela', + 'Joshus', + 'Kayle', + 'Klyde', + 'Djavan', + 'Wang', + 'Aljandro', + 'Belisario', + 'Cristino', + 'Yihan', + 'Carina', + 'Chritian', + 'Juanramon', + 'Khan', + 'Jaiver', + 'Nefi', + 'Murtaza', + 'Raciel', + 'Marlene', + 'Maira', + 'Chima', + 'Cheenou', + 'Bijon', + 'Dorion', + 'Elber', + 'Emeka', + 'Ge', + 'Ratha', + 'Jaxxson', + 'Ryanjames', + 'Shannen', + 'Shue', + 'Sia', + 'Romaldo', + 'Zareh', + 'Tomy', + 'Vanna', + 'Xao', + 'Bertin', + 'Dhyan', + 'Dexton', + 'Esiah', + 'Ayce', + 'Avyukt', + 'Avner', + 'Caspar', + 'Cove', + 'Ciel', + 'Yen', + 'Yessenia', + 'Yony', + 'Fin', + 'Ezrael', + 'Ezel', + 'Ilay', + 'Harveer', + 'Hamad', + 'Asiah', + 'Ashwath', + 'Arcenio', + 'Aroldo', + 'Awet', + 'Alexx', + 'Arihant', + 'Arihaan', + 'Apolo', + 'Aero', + 'Advith', + 'Arren', + 'Beatriz', + 'Jony', + 'Joseramon', + 'Justinray', + 'Jamaul', + 'Tarren', + 'Cristal', + 'Dinh', + 'Chantra', + 'Dshawn', + 'Geraldine', + 'Fuad', + 'Edlin', + 'Jerren', + 'Jerrin', + 'Josje', + 'Chrystopher', + 'Darriel', + 'Takuya', + 'Vannak', + 'Zenas', + 'Miklos', + 'Marten', + 'Rondale', + 'Rothana', + 'Randeep', + 'Ryle', + 'Eduardoluis', + 'Christepher', + 'Davionne', + 'Eriverto', + 'Farbod', + 'Chauncy', + 'Charle', + 'Bayardo', + 'Ashneel', + 'Shoua', + 'Redmond', + 'Ustin', + 'Johnnathan', + 'Josephmichael', + 'Marisela', + 'Markandrew', + 'Michaeljoseph', + 'Marcua', + 'Nidal', + 'Phat', + 'Pritesh', + 'Seaver', + 'Ryananthony', + 'Tyan', + 'Vatche', + 'Thoren', + 'Othoniel', + 'Nicandro', + 'Rajdeep', + 'Tulio', + 'Soua', + 'Jovonte', + 'Kalyn', + 'Jamesryan', + 'Navdeep', + 'Maxmillian', + 'Kayon', + 'Koua', + 'Aaryn', + 'Wilver', + 'Zubair', + 'Ankush', + 'Andie', + 'Adonnis', + 'Jacobanthony', + 'Izekiel', + 'Izacc', + 'Escher', + 'Elijahjames', + 'Edrik', + 'Drayson', + 'Dj', + 'Giordan', + 'Dejaun', + 'Davidmichael', + 'Deshone', + 'Auron', + 'Auguste', + 'Athos', + 'Cutberto', + 'Hairo', + 'Anvay', + 'Adrick', + 'Aydeen', + 'Bassam', + 'Basem', + 'Kyrell', + 'Rjay', + 'Ozil', + 'Taisei', + 'Samanyu', + 'Marvion', + 'Mykael', + 'Mukund', + 'Namish', + 'Naoki', + 'Nishan', + 'Aideen', + 'Aalijah', + 'Hassani', + 'Harkirat', + 'Exzavier', + 'Hudsen', + 'Hrach', + 'Caelum', + 'Caeleb', + 'Destan', + 'Jaspal', + 'Huan', + 'Marcellous', + 'Mehran', + 'Luisfelipe', + 'Gelacio', + 'Eris', + 'Eneas', + 'Terin', + 'Sohrab', + 'Ravneet', + 'Uziah', + 'Vedansh', + 'Peni', + 'Nethaniel', + 'Niraj', + 'Odilon', + 'Kalden', + 'Mariela', + 'Levonte', + 'Elih', + 'Ej', + 'Eames', + 'Jarome', + 'Jishnu', + 'Gurtaaj', + 'Hamish', + 'Gryffin', + 'Jayin', + 'Trong', + 'Sebastain', + 'Sargon', + 'Wa', + 'Cheveyo', + 'Ariv', + 'Aum', + 'Caellum', + 'Bayan', + 'Balthazar', + 'Sagan', + 'Rowyn', + 'Sehaj', + 'Ivon', + 'Stavro', + 'Shrihan', + 'Noey', + 'Oswin', + 'Abrham', + 'Adalid', + 'Aldric', + 'Zayed', + 'Vonn', + 'Vaishnav', + 'Urias', + 'Yahshua', + 'Yago', + 'Darith', + 'Mantej', + 'Kyo', + 'Khyler', + 'Marcjacob', + 'Nayden', + 'Morrissey', + 'Benedicto', + 'Kendrix', + 'Xang', + 'Ranjit', + 'Raymar', + 'Milos', + 'Rayansh', + 'Rawley', + 'Paxon', + 'Krishang', + 'Leeam', + 'Yerick', + 'Yegor', + 'Viren', + 'Saathvik', + 'Shailen', + 'Sahaj', + 'Rydan', + 'Rollins', + 'Rivaan', + 'Soul', + 'Aerick', + 'Aladdin', + 'Catalino', + 'Berenice', + 'Branndon', + 'Kyleanthony', + 'Maclovio', + 'Kiven', + 'Johnchristopher', + 'Jonh', + 'Kassandra', + 'Jobanny', + 'Pastor', + 'Michaela', + 'Montre', + 'Morgen', + 'Gerber', + 'Danish', + 'Haroutun', + 'Duron', + 'Adrion', + 'Evrett', + 'Reegan', + 'Haskie', + 'Quamane', + 'Derrike', + 'Haydyn', + 'Glenville', + 'Dearl', + 'Deroe', + 'Dewell', + 'Lundy', + 'Cleaster', + 'Jeral', + 'Delontae', + 'Delford', + 'Argie', + 'Loise', + 'Elmar', + 'Donley', + 'Ferrel', + 'Carrel', + 'Athel', + 'Rector', + 'Cledith', + 'Dail', + 'Donzel', + 'Lenoard', + 'Winferd', + 'Birl', + 'Dorsie', + 'Olee', + 'Erman', + 'Dorsel', + 'Roma', + 'Othell', + 'Herold', + 'Chaffee', + 'Trygve', + 'Aubra', + 'Opha', + 'Dionne', + 'Colleen', + 'Ciara', + 'Cleotis', + 'Alissa', + 'Alesha', + 'Elise', + 'Emilie', + 'Tiera', + 'Tia', + 'Suzanne', + 'Jaleesa', + 'Jaclyn', + 'Ingrid', + 'India', + 'Georgia', + 'Francesca', + 'Female', + 'Fatima', + 'Rochelle', + 'Precious', + 'Nichelle', + 'Martina', + 'Lucy', + 'Latonya', + 'Cline', + 'Ott', + 'Ona', + 'Otmer', + 'Ersel', + 'Olufemi', + 'Gordy', + 'Marne', + 'Jahquez', + 'Daeshaun', + 'Nashaun', + 'Seiichi', + 'Shigeki', + 'Kazuto', + 'Shozo', + 'Alhaji', + 'Lonn', + 'Tevion', + 'Kaige', + 'Darlene', + 'Braydyn', + 'Masaaki', + 'Graeson', + 'Bernerd', + 'Lynne', + 'Dewaine', + 'Shig', + 'Junichi', + 'Toshiro', + 'Azavion', + 'Michio', + 'Yoshiro', + 'Heraldo', + 'Epitacio', + 'Mas', + 'Taequan', + 'Trindon', + 'Tirrell', + 'Dmonte', + 'Jaquante', + 'Yeeleng', + 'Maleik', + 'Airam', + 'Noname', + 'Shyhiem', + 'Tyquon', + 'Damonta', + 'Undray', + 'Shadrick', + 'Durwin', + 'Lataurus', + 'Corneall', + 'Dantonio', + 'Tilmon', + 'Mackie', + 'Ebbie', + 'Eligha', + 'Beth', + 'Barth', + 'Hezzie', + 'Artha', + 'Darrie', + 'Frederi', + 'Benford', + 'Elves', + 'Theodia', + 'Jaye', + 'Fran', + 'Khylan', + 'Berwyn', + 'Constance', + 'Markevion', + 'Martavion', + 'Jashun', + 'Jermarion', + 'Taylin', + 'Breland', + 'Franchot', + 'Chrishun', + 'Davarius', + 'Dearius', + 'Tredarius', + 'Jayland', + 'Cortavius', + 'Deyonta', + 'Tradarius', + 'Kemarrion', + 'Markavion', + 'Jmarion', + 'Jacarius', + 'Kairi', + 'Rasool', + 'Jarreau', + 'Khayree', + 'Brahin', + 'Hameed', + 'Rolen', + 'Cleason', + 'Cartez', + 'Nicholad', + 'Brahim', + 'Bryheem', + 'Khalief', + 'Anel', + 'Mcgwire', + 'Lula', + 'Gaddis', + 'Lowery', + 'Odies', + 'Rannie', + 'Artee', + 'Aurther', + 'Bookert', + 'Lenon', + 'Oree', + 'Gennie', + 'Emitt', + 'Sedgie', + 'Claudy', + 'Coyt', + 'Lieutenant', + 'Zannie', + 'Kenn', + 'Roosvelt', + 'Vertis', + 'Elex', + 'Eula', + 'Abron', + 'Perkins', + 'Emersyn', + 'Lakin', + 'Dravin', + 'Other', + 'President', + 'Carrie', + 'Cleother', + 'Estus', + 'Tee', + 'Raymont', + 'Woodard', + 'Ras', + 'Zennie', + 'Versie', + 'Mansfield', + 'Atha', + 'Bossie', + 'Smiley', + 'Kenard', + 'Jermie', + 'Vardell', + 'Kadan', + 'Roney', + 'Furney', + 'Caroll', + 'Benjy', + 'Shamond', + 'Tyrease', + 'Dontre', + 'Raekwan', + 'Raequon', + 'Chrishon', + 'Jahmez', + 'Jaques', + 'Zaveon', + 'Zaccheus', + 'Demaris', + 'Shaquile', + 'Shiheem', + 'Santario', + 'Monterio', + 'Jawaan', + 'Lavere', + 'Levere', + 'Guerino', + 'Lisle', + 'Fraser', + 'Grier', + 'Gurnie', + 'Lattie', + 'Wassil', + 'Domer', + 'Melio', + 'Zolton', + 'Haines', + 'Gervase', + 'Fermon', + 'Geneva', + 'Trask', + 'Linward', + 'Colen', + 'Dossie', + 'Zygmund', + 'Teofil', + 'Talbert', + 'Mosby', + 'Elworth', + 'Garvie', + 'Jiles', + 'Mallie', + 'Flay', + 'Stokes', + 'Bernis', + 'Gardiner', + 'Deno', + 'Algerd', + 'Handy', + 'Flake', + 'Hallet', + 'Coyte', + 'Wingate', + 'Burlie', + 'Sigmond', + 'Myrle', + 'Stiney', + 'Americus', + 'Claxton', + 'Acy', + 'Hill', + 'Fenner', + 'Festus', + 'Linnie', + 'Guilford', + 'Artice', + 'Constant', + 'Faber', + 'Jb', + 'Pleasant', + 'Dallis', + 'Vestal', + 'Terez', + 'English', + 'Allard', + 'Ingram', + 'Beaufort', + 'Chene', + 'Dequante', + 'Bubber', + 'Jamone', + 'Zebulun', + 'Daqwan', + 'Delshawn', + 'Jamond', + 'Dacota', + 'Wilmot', + 'Prue', + 'Wister', + 'Kenyata', + 'Darik', + 'Sumter', + 'Hovie', + 'Tallie', + 'Diontay', + 'Dontaye', + 'Brentt', + 'Felder', + 'Chappell', + 'Ralpheal', + 'Wofford', + 'Stclair', + 'Aiken', + 'Hashem', + 'Daire', + 'Grahm', + 'Jaivon', + 'Davarion', + 'Arnez', + 'Ryer', + 'Mousa', + 'Jahlon', + 'Leyland', + 'Maizen', + 'Zadyn', + 'Zein', + 'Amarri', + 'Hady', + 'Keegen', + 'Taeshawn', + 'Jontae', + 'Radwan', + 'Jsean', + 'Hartwell', + 'Roddey', + 'Arend', + 'Marjorie', + 'Clements', + 'Rae', + 'Pressley', + 'Saintclair', + 'Derrill', + 'Joann', + 'Cote', + 'Philo', + 'Urho', + 'Evart', + 'Vada', + 'Deo', + 'Tonie', + 'Irven', + 'Stjulian', + 'Durand', + 'Diarra', + 'Burnet', + 'Steed', + 'Demont', + 'Burris', + 'Donyell', + 'Gjon', + 'Demone', + 'Jodi', + 'Boban', + 'Brunson', + 'Mackey', + 'Delwyn', + 'Gordie', + 'Owens', + 'Efton', + 'Uel', + 'Ancel', + 'Zafir', + 'Kyeem', + 'Vencil', + 'Irl', + 'Tymeer', + 'Dymere', + 'Kier', + 'Murel', + 'Hale', + 'Lorn', + 'Tahjir', + 'Sufyaan', + 'Trig', + 'Yacqub', + 'Khadir', + 'Najib', + 'Ayuub', + 'Hamse', + 'Yassir', + 'Yussuf', + 'Abdihafid', + 'Abdinasir', + 'Abdiqani', + 'Tayon', + 'Abdirahim', + 'Abdishakur', + 'Mukhtar', + 'Bauer', + 'Damere', + 'Rashee', + 'Kalief', + 'Shyheed', + 'Dejour', + 'Kuran', + 'Qaadir', + 'Aldor', + 'Jasyah', + 'Hajj', + 'Ordell', + 'Gradyn', + 'Ayyub', + 'Atley', + 'Mahkai', + 'Lochlann', + 'Sakai', + 'Saamir', + 'Bernhardt', + 'Willmer', + 'Swen', + 'Hilding', + 'Knute', + 'Wael', + 'Thorvald', + 'Erle', + 'Melroy', + 'Valerian', + 'Jorgen', + 'Dacotah', + 'Shaydon', + 'Lamir', + 'Kahseem', + 'Jihaad', + 'Tylee', + 'Sakariye', + 'Qalid', + 'Syair', + 'Syire', + 'Safi', + 'Zaakir', + 'Sahmir', + 'Saahir', + 'Karlin', + 'Kowen', + 'Kahne', + 'Azir', + 'Tysir', + 'Maki', + 'Zekhi', + 'Pater', + 'Louden', + 'Jandiel', + 'Khaseem', + 'Livio', + 'Pellegrino', + 'Loretta', + 'Lothar', + 'Morty', + 'Harvard', + 'Jeris', + 'Arlene', + 'Salvotore', + 'Erasmus', + 'Canio', + 'Heywood', + 'Ivar', + 'Maitland', + 'Neale', + 'Gladys', + 'Ethelbert', + 'Fergus', + 'Arcangelo', + 'Sigismund', + 'Fremont', + 'Stillman', + 'Egidio', + 'Pincus', + 'Sabatino', + 'Solly', + 'Bela', + 'Stanly', + 'Faust', + 'Gesualdo', + 'Adolphe', + 'Ladislav', + 'Mandel', + 'Philander', + 'Catello', + 'Fordyce', + 'Brownie', + 'Darnley', + 'Alfio', + 'Emerito', + 'Darrly', + 'Delfin', + 'Chiam', + 'Beril', + 'Albie', + 'Roberts', + 'Ferdinando', + 'Maureen', + 'Herberto', + 'Lamark', + 'Philipp', + 'Uwe', + 'Dermott', + 'Amalio', + 'Sandford', + 'Shawnta', + 'Shannan', + 'Sheppard', + 'Jerauld', + 'Antoinne', + 'Oleh', + 'Tobie', + 'Thoms', + 'Valice', + 'Thurnell', + 'Deamonte', + 'Kendel', + 'Trevone', + 'Kaylob', + 'Carder', + 'Antrell', + 'Traven', + 'Jaymir', + 'Joni', + 'Keisean', + 'Krishawn', + 'Marquelle', + 'Dearis', + 'Delvonte', + 'Jamez', + 'Zebadiah', + 'Kreig', + 'Teran', + 'Resean', + 'Zackory', + 'Lamontae', + 'Albieri', + 'Albiery', + 'Chen', + 'Alexy', + 'Arslan', + 'Taliek', + 'Nakhi', + 'Naphtali', + 'Papa', + 'Pesach', + 'Michoel', + 'Salih', + 'Harshdeep', + 'Elhadj', + 'Izzy', + 'Jahkai', + 'Tyliek', + 'Vasilis', + 'Yaacov', + 'Sohaib', + 'Yissochor', + 'Mir', + 'Jasin', + 'Jensy', + 'Rehman', + 'Nazeer', + 'Jahmil', + 'Enson', + 'Nasif', + 'Rizwan', + 'Samiul', + 'Rahat', + 'Angelos', + 'Avroham', + 'Abdulai', + 'Adir', + 'Enes', + 'Yishay', + 'Doyt', + 'Gal', + 'Shoaib', + 'Quaron', + 'Ishraq', + 'Nazaire', + 'Nyzaiah', + 'Mattia', + 'Javone', + 'Mahesh', + 'Mamady', + 'Johnattan', + 'Jorman', + 'Kaliq', + 'Devendra', + 'Burhan', + 'Zishe', + 'Zeandre', + 'Arel', + 'Shalik', + 'Shameer', + 'Nisson', + 'Ralik', + 'Agim', + 'Amauris', + 'Atif', + 'Samory', + 'Shatiek', + 'Taner', + 'Rafat', + 'Zhen', + 'Radhames', + 'Raliek', + 'Ronel', + 'Sabbir', + 'Saqib', + 'Jeudy', + 'Hesham', + 'Hyun', + 'Lakeem', + 'Mishael', + 'Ivo', + 'Tajay', + 'Taleek', + 'Tishawn', + 'Tyreem', + 'Samori', + 'Nickholas', + 'Pearse', + 'Mamadi', + 'Elhadji', + 'Dawood', + 'Dilon', + 'Ishmel', + 'Yiannis', + 'Jahquel', + 'Jahquell', + 'El', + 'Equan', + 'Ho', + 'Delno', + 'Dinesh', + 'Damel', + 'Temitayo', + 'Tenzing', + 'Wahab', + 'Alisher', + 'Adonijah', + 'Bradan', + 'Efrayim', + 'Elnatan', + 'Elmin', + 'Hossain', + 'Eliav', + 'Azimjon', + 'Dovber', + 'Sheya', + 'Yahia', + 'Jasani', + 'Liav', + 'Kamare', + 'Kaysean', + 'Kinsley', + 'Nikoloz', + 'Nyrell', + 'Wyeth', + 'Jeremaih', + 'Mahin', + 'Matis', + 'Oriel', + 'Mourad', + 'Shmeil', + 'Messi', + 'Jonibek', + 'Jeyren', + 'Keyden', + 'Temur', + 'Tanveer', + 'Zyir', + 'Zidan', + 'Zayyan', + 'Varick', + 'Wesam', + 'Abdoulie', + 'Aqib', + 'Asani', + 'Bless', + 'Hasnain', + 'Hamdan', + 'Getzel', + 'Fatin', + 'Huzaifa', + 'Jarif', + 'Jahlani', + 'Davier', + 'Chuna', + 'Eashan', + 'Rafan', + 'Rakin', + 'Ngawang', + 'Mouhamad', + 'Rohaan', + 'Vanness', + 'Volvy', + 'Javel', + 'Jabir', + 'Jaevion', + 'Fahd', + 'Lean', + 'Machai', + 'Juniel', + 'Kaylin', + 'Jeremiyah', + 'Matisyahu', + 'Menasha', + 'Mikaeel', + 'Gaspard', + 'Lorik', + 'Shuaib', + 'Seif', + 'Shlomy', + 'Shneor', + 'Sonam', + 'Volf', + 'Yussef', + 'Ziv', + 'Krrish', + 'Machi', + 'Endi', + 'Frederik', + 'Abdo', + 'Alif', + 'Elchanan', + 'Yordy', + 'Shafin', + 'Siam', + 'Furkan', + 'Fallou', + 'Devyne', + 'Chaskel', + 'Arbi', + 'Younes', + 'Ziare', + 'Tanyon', + 'Terique', + 'Nicholaos', + 'Nickita', + 'Mordchai', + 'Saifullah', + 'Saliou', + 'Savier', + 'Jahmiere', + 'Jahson', + 'Javoni', + 'Jayel', + 'Jie', + 'Kwadwo', + 'Kahmani', + 'Johansel', + 'Murat', + 'Nasire', + 'Nezar', + 'Seydou', + 'Jamair', + 'Jahmeer', + 'Chanina', + 'Chezky', + 'Zyire', + 'Yoscar', + 'Alassane', + 'Aitan', + 'Dannon', + 'Donelle', + 'Harrington', + 'Sha', + 'Shamal', + 'Josph', + 'Torrell', + 'Ralphy', + 'Sharron', + 'Eleftherios', + 'Gedalia', + 'Kasheen', + 'Manoj', + 'Nuri', + 'Daran', + 'Devanand', + 'Evagelos', + 'Fatmir', + 'Haralambos', + 'Biju', + 'Nilson', + 'Wane', + 'Tarig', + 'Rober', + 'Sharone', + 'Lezer', + 'Odalis', + 'Glenston', + 'Josip', + 'Kostantinos', + 'Rahshawn', + 'Osei', + 'Shariyf', + 'Sotirios', + 'Aneudi', + 'Marios', + 'Biff', + 'Damiano', + 'Shean', + 'Rajendra', + 'Mare', + 'Richad', + 'Jaja', + 'Efstathios', + 'Nephtali', + 'Kowan', + 'Rhonda', + 'Pasqualino', + 'Confesor', + 'Linc', + 'Safet', + 'Sharrieff', + 'Kiron', + 'Damain', + 'Aurohom', + 'Kariem', + 'Tiheim', + 'Dushawn', + 'Kindu', + 'Aswad', + 'Kwane', + 'Oba', + 'Jermayne', + 'Dakeem', + 'Babatunde', + 'Ackeem', + 'Alvi', + 'Adetokunbo', + 'Akeel', + 'Kedwin', + 'Kayron', + 'Mergim', + 'Wilkins', + 'Wojciech', + 'Omair', + 'Kushtrim', + 'Kwamel', + 'Saiquan', + 'Naquon', + 'Quandell', + 'Veton', + 'Shaune', + 'Daguan', + 'Duquan', + 'Jency', + 'Ka', + 'Waqas', + 'Xiao', + 'Mahlik', + 'Kasiem', + 'Navindra', + 'Sayquan', + 'Shaquon', + 'Shiquan', + 'Rameek', + 'Jerelle', + 'Devaun', + 'Jakim', + 'Jaquell', + 'Eury', + 'Shaiquan', + 'Shakeal', + 'Shakiem', + 'Shaleek', + 'Ramesh', + 'Suhail', + 'Tylique', + 'Jawanza', + 'Jonell', + 'Hamdi', + 'Jaimeson', + 'Kerven', + 'Demetreus', + 'Giselle', + 'Aikeem', + 'Akiem', + 'Rondel', + 'Dow', + 'Gregroy', + 'Darnelle', + 'Naguan', + 'Tyronn', + 'Ricke', + 'Dishawn', + 'Rishawn', + 'Tarick', + 'Tynell', + 'Japhet', + 'Francesc', + 'Maximili', + 'Herby', + 'Jaqwan', + 'Kemal', + 'Akeen', + 'Azeez', + 'Devindra', + 'Deryck', + 'Deval', + 'Alessand', + 'Masood', + 'Uladimir', + 'Cadon', + 'Quanah', + 'Zimere', + 'Chatham', + 'Koi', + 'Zymire', + 'Jamaury', + 'Jahmire', + 'Ziyan', + 'Cowen', + 'Jamaurie', + 'Nyquan', + 'Jayleen', + 'Zymiere', + 'Zymarion', + 'Kahmari', + 'Langdon', + 'Zymari', + 'Jymir', + 'Kamaree', + 'Nycere', + 'Sayvion', + 'Jahmarion', + 'Justyce', + 'Tuck', + 'Thayer', + 'Mung', + 'Graison', + 'Delane', + 'Lemoyne', + 'Cinch', + 'Nevada', + 'Dhairya', + 'Jyaire', + 'Yazir', + 'Tahjmir', + 'Sequoyah', + 'Quention', + 'Tanmay', + 'Shreyansh', + 'Ahyan', + 'Aaryav', + 'Zaylin', + 'Laksh', + 'Basheer', + 'Bhavik', + 'Orley', + 'Vestel', + 'Altus', + 'Choice', + 'Bufford', + 'Quasir', + 'Emry', + 'Tressel', + 'Eppie', + 'Jayvier', + 'Prestin', + 'Haydin', + 'Caydan', + 'Corday', + 'Camdin', + 'Brodyn', + 'Liberato', + 'Trayon', + 'Telesfor', + 'Jayko', + 'Lavi', + 'Procopio', + 'Rubel', + 'Karder', + 'Jaymar', + 'Bryor', + 'Gottlob', + 'Saladin', + 'Tunis', + 'Saheed', + 'Alsexander', + 'Davonn', + 'Jaquill', + 'Shakeil', + 'Krunal', + 'Tashon', + 'Doyel', + 'Odes', + 'Thoams', + 'Rasul', + 'Wendyl', + 'Glendale', + 'Ahmid', + 'Altarik', + 'Amish', + 'Jaquis', + 'Dashan', + 'Salaam', + 'Bhavin', + 'Nashid', + 'Tauheed', + 'Jamill', + 'Cordney', + 'Derly', + 'Jamale', + 'Hristopher', + 'Camaron', + 'Domanique', + 'Desmund', + 'Keenon', + 'Paulanthony', + 'Demarques', + 'Meryl', + 'Medard', + 'Erbey', + 'Adrin', + 'Evo', + 'Pal', + 'Deke', + 'Glendal', + 'Tramayne', + 'Aloysuis', + 'Berthal', + 'Ashly', + 'Arien', + 'Teodulo', + 'Johsua', + 'Kelwin', + 'Quintan', + 'Mauel', + 'Quisto', + 'Gaylin', + 'Trayvion', + 'Tracer', + 'Ramsay', + 'Verlan', + 'Kyndal', + 'Donovon', + 'Samuell', + 'Treyveon', + 'Nereo', + 'Areli', + 'Dashun', + 'Devontre', + 'Stran', + 'Zarian', + 'Pacen', + 'Kamakani', + 'Alii', + 'Chidozie', + 'Cobie', + 'Acxel', + 'Jatavian', + 'Kelvon', + 'Keldon', + 'Giezi', + 'Gavon', + 'Virtus', + 'Burdell', + 'Dorrance', + 'Naail', + 'Lantz', + 'Travian', + 'Cleland', + 'Arish', + 'Elyan', + 'Chukwudi', + 'Shahrukh', + 'Coulter', + 'Karver', + 'Seeley', + 'Wynton', + 'Detric', + 'Quenten', + 'Joemichael', + 'Daruis', + 'Tyeler', + 'Montray', + 'Hermenegildo', + 'Donathan', + 'Mckenna', + 'Kijuan', + 'Braijon', + 'Vashawn', + 'Darvell', + 'Kennie', + 'Rejino', + 'Vickey', + 'Lyndall', + 'Reynoldo', + 'Malyk', + 'Armarion', + 'Brit', + 'Trayshawn', + 'Contrell', + 'Eutimio', + 'Dantrel', + 'Darrious', + 'Dawon', + 'Richey', + 'Arrion', + 'Zohair', + 'Randale', + 'Keyshone', + 'Kiwane', + 'Jibri', + 'Devell', + 'Beto', + 'Jaymz', + 'Ritchey', + 'Tremel', + 'Keante', + 'Vontrell', + 'Guadlupe', + 'Esiquiel', + 'Erasto', + 'Dub', + 'Augustas', + 'Panfilo', + 'Vuk', + 'Mickie', + 'Javonni', + 'Riddick', + 'Nikodem', + 'Marrion', + 'Kamareon', + 'Maks', + 'Eliverto', + 'Cresenciano', + 'Jerrol', + 'Joakim', + 'Maddax', + 'Kayvion', + 'Khizar', + 'Haze', + 'Aveon', + 'Amjad', + 'Audwin', + 'Almir', + 'Vicky', + 'Lonell', + 'Jabarie', + 'Jaylun', + 'Damarrion', + 'Mantas', + 'Dannye', + 'Aadarsh', + 'Caelen', + 'Tilton', + 'Kimmie', + 'Josgar', + 'Oleksandr', + 'Keyontae', + 'Fidelio', + 'Wiktor', + 'Maxymilian', + 'Cayce', + 'Rodric', + 'Manrique', + 'Kestutis', + 'Donnald', + 'Grayland', + 'Lavance', + 'Medgar', + 'Chaney', + 'Monta', + 'Lemond', + 'Medford', + 'Mareo', + 'Camerino', + 'Ronold', + 'Lancer', + 'Credell', + 'Elbridge', + 'Stony', + 'Dvid', + 'Hilberto', + 'Erineo', + 'Jerrald', + 'Antawan', + 'Cordario', + 'Levelle', + 'Ramsen', + 'Jigar', + 'Laroyce', + 'Lazerrick', + 'Artez', + 'Cordelro', + 'Creon', + 'Lonzell', + 'Shanton', + 'Orpheus', + 'Terris', + 'Renauld', + 'Deondra', + 'Fontaine', + 'Airrion', + 'Branko', + 'Enemencio', + 'Antiono', + 'Caprice', + 'Danyale', + 'Valdez', + 'Oswell', + 'Tahitoa', + 'Fannie', + 'Estes', + 'Herchel', + 'Seabron', + 'Bunyan', + 'Thelmon', + 'Agnew', + 'Broughton', + 'Harwell', + 'Mather', + 'Quillie', + 'Hardwick', + 'Phinizy', + 'Pope', + 'Addis', + 'Seals', + 'Thelman', + 'Summie', + 'Romano', + 'Zacari', + 'Kortney', + 'Makye', + 'Graycen', + 'Kavari', + 'Kamarri', + 'Ajahni', + 'Dayan', + 'Sharrod', + 'Pheonix', + 'Trentyn', + 'Jacai', + 'Jamesley', + 'Destyn', + 'Maddon', + 'Gianlucas', + 'Aydrian', + 'Bader', + 'Jaise', + 'Godson', + 'Gleb', + 'Jatniel', + 'Yaxiel', + 'Marvins', + 'Miron', + 'Yaroslav', + 'Legrande', + 'Lonzy', + 'Merrell', + 'Flemming', + 'Guerry', + 'Kimothy', + 'Remus', + 'Wyndell', + 'Barnard', + 'Denorris', + 'Edna', + 'Bevan', + 'Warnell', + 'Josie', + 'Arthor', + 'Theartis', + 'Kimsey', + 'Wymon', + 'Duglas', + 'Reshawn', + 'Natrone', + 'Treysen', + 'Davaris', + 'Jocqui', + 'Traivon', + 'Trevonne', + 'Tavarious', + 'Monson', + 'Kevis', + 'Ladonte', + 'Mackenson', + 'Bodee', + 'Chayden', + 'Dequon', + 'Keiondre', + 'Dewan', + 'Taige', + 'Renel', + 'Jasher', + 'Bayler', + 'Dodger', + 'Tyke', + 'Jarvin', + 'Edner', + 'Travonn', + 'Traxton', + 'Malosi', + 'Lavonta', + 'Janard', + 'Kyzer', + 'Packer', + 'Travoris', + 'Frantzy', + 'Makay', + 'Tamari', + 'Kanard', + 'Dairon', + 'Gabriell', + 'Kemaury', + 'Jshaun', + 'Karel', + 'Jakarri', + 'Rubens', + 'Zamauri', + 'Winsley', + 'Giulian', + 'Yosbel', + 'Kevaughn', + 'Jimson', + 'Kendly', + 'Dishon', + 'Dallyn', + 'Jephthe', + 'Luccas', + 'Kemuel', + 'Eddrick', + 'Ahmarion', + 'Amariyon', + 'Artavis', + 'Dewin', + 'Jacarie', + 'Jahn', + 'Janari', + 'Geordy', + 'Mardochee', + 'Jimari', + 'Yoshinobu', + 'Eiji', + 'Yasunobu', + 'Koon', + 'Hidemi', + 'Norio', + 'Kiyomi', + 'Shuichi', + 'Kazuyoshi', + 'Yoshitaka', + 'Kanji', + 'Tetsuro', + 'Asao', + 'Dominador', + 'Shogo', + 'Jakye', + 'Braelin', + 'Chrisangel', + 'Calab', + 'Morio', + 'Seiki', + 'Tsuyoshi', + 'Soichi', + 'Masakatsu', + 'Tadayoshi', + 'Tokuichi', + 'Yoshikatsu', + 'Matsuichi', + 'Lorrin', + 'Javeion', + 'Kail', + 'Jvon', + 'Joshwa', + 'Keylen', + 'Rylon', + 'Oved', + 'Kraven', + 'Koben', + 'Klever', + 'Nedved', + 'Dago', + 'Cortlen', + 'Reeves', + 'Yhair', + 'Xane', + 'Jamori', + 'Jayshon', + 'Jaiveon', + 'Joseth', + 'Drelynn', + 'Haldrin', + 'Keelyn', + 'Nathanuel', + 'Kvon', + 'Jayln', + 'Khyrie', + 'Zayveon', + 'Braxston', + 'Jaceion', + 'Jonavon', + 'Jesaiah', + 'Gaddiel', + 'Tobyn', + 'Becket', + 'Aydyn', + 'Arinze', + 'Dacian', + 'Aadin', + 'Fender', + 'Brysun', + 'Demarious', + 'Kaimi', + 'Ryson', + 'Jarrin', + 'Maleko', + 'Kamakana', + 'Kamalani', + 'Johnavon', + 'Kawena', + 'Aadil', + 'Blayde', + 'Garyn', + 'Izaih', + 'Bryndon', + 'Drelyn', + 'Demarian', + 'Kupaa', + 'Nalu', + 'Makena', + 'Lawaia', + 'Kaimalu', + 'Kanaloa', + 'Oshen', + 'Mj', + 'Kahekili', + 'Koalii', + 'Makua', + 'Promise', + 'Keylin', + 'Kevondrick', + 'Tobenna', + 'Infantboy', + 'Oluwatimilehin', + 'Nathanal', + 'Zakkery', + 'Shariq', + 'Sadler', + 'Rockne', + 'Drelon', + 'Ethon', + 'Catcher', + 'Clayten', + 'Kaniela', + 'Isaack', + 'Josten', + 'Zarius', + 'Tayte', + 'Ugochukwu', + 'Aiman', + 'Eduar', + 'Basel', + 'Canton', + 'Dyron', + 'Keaden', + 'Kayceon', + 'Kyrian', + 'Kree', + 'Jj', + 'Iaan', + 'Hudsyn', + 'Graceson', + 'Gatlyn', + 'Eydan', + 'Jak', + 'Townsend', + 'Owais', + 'Nandan', + 'Rayland', + 'Ridhaan', + 'Dantavious', + 'Lavoris', + 'Maricus', + 'Rodrigus', + 'Aayansh', + 'Chasten', + 'Durante', + 'Johnta', + 'Detavious', + 'Donterrius', + 'Rilyn', + 'Rilee', + 'Marquize', + 'Quinterius', + 'Jamarco', + 'Quinnton', + 'Deston', + 'Aceson', + 'Britten', + 'Adric', + 'Tabias', + 'Lajarvis', + 'Corderius', + 'Romon', + 'Que', + 'Nord', + 'Lerone', + 'Skylan', + 'Tobi', + 'Mccrae', + 'Mathayus', + 'Marcuz', + 'Levii', + 'Lander', + 'Oluwadarasimi', + 'Miklo', + 'Nijah', + 'Nero', + 'Quavis', + 'Zailyn', + 'Whitman', + 'Zavior', + 'Zlatan', + 'Crixus', + 'Cotton', + 'Chukwuebuka', + 'Draden', + 'Caston', + 'Aceyn', + 'Caeson', + 'Brax', + 'Azel', + 'Kaisyn', + 'Hunt', + 'Gaius', + 'Gabrian', + 'Falcon', + 'Iyan', + 'Jayjay', + 'Altonio', + 'Woodruff', + 'Tavare', + 'Kawaski', + 'Dontravious', + 'Gabreil', + 'Holten', + 'Dayvian', + 'Brennyn', + 'Chayson', + 'Dailon', + 'Keyshun', + 'Jaryn', + 'Jamyron', + 'Jakavion', + 'July', + 'Jonanthony', + 'Trenden', + 'Tobechukwu', + 'Yostin', + 'Casin', + 'Kaydyn', + 'Jshawn', + 'Keaghan', + 'Khalen', + 'Haylen', + 'Jamarques', + 'Alyjah', + 'Baylon', + 'Kemontae', + 'Taysean', + 'Slaton', + 'Saxton', + 'Yadir', + 'Tramon', + 'Traevion', + 'Raydon', + 'Raahim', + 'Olamide', + 'Oreoluwa', + 'Zyien', + 'Zayde', + 'Marqavious', + 'Marquavis', + 'Trevious', + 'Zyshonne', + 'Quindarrius', + 'Quintarious', + 'Quinterious', + 'Rodarius', + 'Deontavious', + 'Champion', + 'Decklan', + 'Daxx', + 'Pecos', + 'Jovonni', + 'Jaydrian', + 'Montravius', + 'Gunter', + 'Zerrick', + 'Quontavious', + 'Ayeden', + 'Audi', + 'Bentlie', + 'Brek', + 'Travonne', + 'Daquavious', + 'Jartavious', + 'Keldric', + 'Alezander', + 'Kamen', + 'Taytum', + 'Siler', + 'Yavuz', + 'Zaniel', + 'Yuriel', + 'Draiden', + 'Axzel', + 'Castin', + 'Keeland', + 'Jrake', + 'Jonhatan', + 'Jeziel', + 'Javery', + 'Severino', + 'Olavi', + 'Benoit', + 'Phillips', + 'Lothrop', + 'Konstanty', + 'Mato', + 'Carney', + 'Keithen', + 'Easley', + 'Chanler', + 'Erbie', + 'Ephriam', + 'Kentravion', + 'Kesan', + 'Ladamien', + 'Treshun', + 'Jakyron', + 'Burch', + 'Kaston', + 'Kyndall', + 'Jarden', + 'Shields', + 'Jontrell', + 'Thales', + 'Minnis', + 'Ida', + 'Hildred', + 'Helder', + 'Fernell', + 'Shone', + 'Laterrance', + 'Tuyen', + 'Roshun', + 'Vincient', + 'Ory', + 'Hilman', + 'Calton', + 'Clydell', + 'Vick', + 'Derrin', + 'Silton', + 'Tandy', + 'Emeal', + 'Rual', + 'Cardarius', + 'Jylan', + 'Hodge', + 'Charls', + 'Jacobey', + 'Jaqualon', + 'Jyrin', + 'Calib', + 'Fowler', + 'Kalep', + 'Osco', + 'Treylan', + 'Paschal', + 'Lowry', + 'Tydrick', + 'Ladavion', + 'Roe', + 'Jarmall', + 'Josuha', + 'Quindell', + 'Tra', + 'Jamaria', + 'Jermicheal', + 'Hobie', + 'Oluwaseun', + 'Trimayne', + 'Kaire', + 'Katrell', + 'Tradd', + 'Yohannes', + 'Oluwaseyi', + 'Tyski', + 'Lansana', + 'Tion', + 'Delontay', + 'Tavone', + 'Quante', + 'Taavon', + 'Daquane', + 'Burleigh', + 'Eyoel', + 'Cung', + 'Khodee', + 'Emilien', + 'Laurien', + 'Leonide', + 'Loomis', + 'Antrone', + 'Sewall', + 'Nicollas', + 'Vitor', + 'Jaythian', + 'Jasaun', + 'Tighe', + 'Colman', + 'Antionne', + 'Nygel', + 'Garnell', + 'Jamareon', + 'Alvey', + 'Carvel', + 'Carville', + 'Carlester', + 'Rutledge', + 'Mills', + 'Rayner', + 'Doil', + 'Gregario', + 'Aniseto', + 'Audon', + 'Brevyn', + 'Pio', + 'Tanis', + 'Jasinto', + 'Jaxtin', + 'Nugent', + 'Eldredge', + 'Egon', + 'Jong', + 'Pancho', + 'Lionardo', + 'Susano', + 'Trueman', + 'Braxtin', + 'Delphine', + 'Harroll', + 'Goree', + 'Manuela', + 'Epigmenio', + 'Laureano', + 'Josefina', + 'Tiodoro', + 'Silbestre', + 'Patrocinio', + 'Corando', + 'Maciah', + 'Quintyn', + 'Wrigley', + 'Onie', + 'Noal', + 'Duward', + 'Filomeno', + 'Cleburn', + 'Garvis', + 'Bisente', + 'Cedell', + 'Jap', + 'Rube', + 'Mavis', + 'Jarold', + 'Hijinio', + 'Dewie', + 'Trinida', + 'Jung', + 'Byrd', + 'Mcadoo', + 'Floy', + 'Eldie', + 'Volney', + 'Saragosa', + 'Derward', + 'Francico', + 'Genovevo', + 'Lindley', + 'Lasalle', + 'Borden', + 'Bonny', + 'Claudis', + 'Silberio', + 'Asuncion', + 'Rolly', + 'Doak', + 'Luvender', + 'Thurl', + 'Garl', + 'Arvine', + 'Johnnye', + 'Emiterio', + 'Crisoforo', + 'Eulojio', + 'Edell', + 'Infboy', + 'Ural', + 'Natalia', + 'Delia', + 'Acencion', + 'Joas', + 'Keagon', + 'Reice', + 'Esperanza', + 'Velton', + 'Eufemio', + 'Frumencio', + 'Dominga', + 'Eutiquio', + 'Dois', + 'Gean', + 'Odaniel', + 'Lyndel', + 'Kreigh', + 'Bobbye', + 'Rogue', + 'Deundra', + 'Cambron', + 'Kaitlynn', + 'Kayleigh', + 'Hailee', + 'Piper', + 'Sofia', + 'Carly', + 'Abigayle', + 'Angelina', + 'Tavish', + 'Christophere', + 'Anterrio', + 'Thimothy', + 'Montarius', + 'Marquarius', + 'Labradford', + 'Lawless', + 'Lenis', + 'Camile', + 'Tonya', + 'Hersey', + 'Abbie', + 'Loveless', + 'Aristide', + 'Ovey', + 'Ovide', + 'Robley', + 'Elward', + 'Leory', + 'Earlis', + 'Gaynell', + 'Printes', + 'Elzy', + 'Aswell', + 'Waver', + 'Wilma', + 'Minos', + 'Euclide', + 'Aster', + 'Demarrion', + 'Selbert', + 'Stoy', + 'Brack', + 'Strother', + 'Osa', + 'Ovel', + 'Custer', + 'Keveon', + 'Lenvil', + 'Hargus', + 'Kline', + 'Goldie', + 'Warfield', + 'Wavy', + 'Carless', + 'Proctor', + 'Holston', + 'Philopateer', + 'Loman', + 'Vernis', + 'Forster', + 'Jakie', + 'Martavis', + 'Louard', + 'Corbet', + 'Waldon', + 'Cluster', + 'Lafe', + 'Tayshun', + 'Browder', + 'Moss', + 'Rudell', + 'Loyde', + 'Glendel', + 'Elby', + 'Shafter', + 'Camila', + 'Elaine', + 'Scarlett', + 'Gertrude', + 'Bella', + 'Penelope', + 'Cathy', + 'Lizbeth', + 'Arianna', + 'Agnes', + 'Vicki', + 'Mila', + 'Ximena', + 'Delilah', + 'Stella', + 'Miranda', + 'Valentina', + 'Rosemary', + 'Khloe', + 'Heidi', + 'Desiree', + 'Violet', + 'Gianna', + 'Nayeli', + 'Luna', + 'Doreen', + 'Jennie', + 'Roberta', + 'Sheri', + 'Jeanne', + 'Alina', + 'Celeste', + 'Rosalie', + 'Naomi', + 'Teri', + 'Maryann', + 'Glenda', + 'Lynda', + 'Annabelle', + 'Antoinette', + 'Stephani', + 'Marcia', + 'Sherri', + 'Clara', + 'Julissa', + 'Becky', + 'Marianne', + 'Melody', + 'Sadie', + 'Sienna', + 'Marsha', + 'Belinda', + 'Jaylah', + 'Harriet', + 'Kristine', + 'Elizabet', + 'Paisley', + 'Genevieve', + 'Melinda', + 'Leilani', + 'Aubree', + 'Keira', + 'Kristy', + 'Sheryl', + 'Fernanda', + 'Tami', + 'Daleyza', + 'Rosemarie', + 'Francine', + 'Kristi', + 'Jaqueline', + 'Meagan', + 'Nichole', + 'Athena', + 'Anahi', + 'Marisa', + 'Yaretzi', + 'Lena', + 'Serena', + 'Miley', + 'Izabella', + 'Kate', + 'Joselyn', + 'Margie', + 'Krystle', + 'Dulce', + 'Pam', + 'Traci', + 'Mikayla', + 'Shari', + 'Delores', + 'Nellie', + 'Gisselle', + 'Blanche', + 'Clarissa', + 'Dianne', + 'Maxine', + 'Janis', + 'Carmela', + 'Mabel', + 'Estrella', + 'Emely', + 'Viola', + 'Penny', + 'Viviana', + 'Estelle', + 'Krista', + 'Adalynn', + 'Julianna', + 'Danna', + 'Marina', + 'Sheena', + 'Shawna', + 'Mya', + 'Leona', + 'Leila', + 'Isla', + 'Charlene', + 'Mindy', + 'Bernadette', + 'Audrina', + 'Tricia', + 'Adele', + 'Myrtle', + 'Nataly', + 'Kimberley', + 'Gwendolyn', + 'Emilia', + 'Janine', + 'Paulina', + 'Stefanie', + 'Marguerite', + 'Dayanara', + 'Katina', + 'Brielle', + 'Vera', + 'Jimena', + 'Aileen', + 'Bethany', + 'America', + 'Kellie', + 'Shanice', + 'Roxanne', + 'Darla', + 'Mamie', + 'Jocelyne', + 'Katherin', + 'Lyla', + 'Sonya', + 'Allyson', + 'Debora', + 'Chaya', + 'Jaslene', + 'Malia', + 'Daniella', + 'Alessandra', + 'Aimee', + 'Dina', + 'Arabella', + 'Juliet', + 'Laila', + 'Rhoda', + 'Angie', + 'Everly', + 'Adrianna', + 'Shelia', + 'Jana', + 'Analia', + 'Kamila', + 'Rebekah', + 'Myrna', + 'Concetta', + 'Amaya', + 'Juliette', + 'Litzy', + 'Marely', + 'Londyn', + 'Patti', + 'Adalyn', + 'Marla', + 'Tammie', + 'Cora', + 'Angelique', + 'Fiona', + 'Kari', + 'Jaylene', + 'Lucile', + 'Rubi', + 'Vivienne', + 'Hattie', + 'Noemi', + 'Celina', + 'Dena', + 'Sherlyn', + 'Selina', + 'Bonita', + 'Paulette', + 'Aisha', + 'Susie', + 'Adeline', + 'Elsa', + 'Shania', + 'Yasmin', + 'Dalia', + 'Jacquelyn', + 'Thalia', + 'Trina', + 'Allisson', + 'Chana', + 'Olive', + 'Helene', + 'Nelda', + 'Mireya', + 'Chelsey', + 'Cheri', + 'Kira', + 'Karissa', + 'Lynette', + 'Deneen', + 'Ivette', + 'Roslyn', + 'Kinley', + 'Rosalinda', + 'Lila', + 'Kaylie', + 'Dayana', + 'Melany', + 'Carissa', + 'Aniyah', + 'Kyla', + 'Yulissa', + 'Trisha', + 'Camilla', + 'Ansley', + 'Sarai', + 'Lola', + 'Arline', + 'Lara', + 'Stacie', + 'Annika', + 'Christi', + 'Brisa', + 'Gia', + 'Therese', + 'Abril', + 'Angeline', + 'Isabela', + 'Marcella', + 'Shanna', + 'Stephany', + 'Henrietta', + 'Tasha', + 'Brianne', + 'Rosanne', + 'Luann', + 'Frieda', + 'Renata', + 'Dianna', + 'Celia', + 'Sondra', + 'Aylin', + 'Melba', + 'Catina', + 'Alayna', + 'Mollie', + 'Nathalie', + 'Tabitha', + 'Tracie', + 'Scarlet', + 'Jayne', + 'Rachelle', + 'Jeannette', + 'Addyson', + 'Cecelia', + 'Annabella', + 'Dahlia', + 'Dorothea', + 'Annmarie', + 'Marlys', + 'Deirdre', + 'Evangeline', + 'Melina', + 'Erma', + 'Jeanine', + 'Roxana', + 'Yaritza', + 'Montserrat', + 'Lizzie', + 'Kerri', + 'Yoselin', + 'Migdalia', + 'Rivka', + 'Cathleen', + 'Lorene', + 'Yareli', + 'Bette', + 'Kyra', + 'Janette', + 'Beulah', + 'Danica', + 'Arely', + 'Lexi', + 'Shana', + 'Sherrie', + 'Alexus', + 'Mable', + 'Citlalli', + 'Nadine', + 'Shauna', + 'Ryleigh', + 'Jeri', + 'Phoebe', + 'Jazlyn', + 'Noreen', + 'Keisha', + 'Lora', + 'Brynlee', + 'Alivia', + 'Lottie', + 'Monserrat', + 'Giuliana', + 'Adelyn', + 'Deana', + 'Jacqueli', + 'Makenna', + 'Jeannie', + 'Noelle', + 'Imogene', + 'Daphne', + 'Reyna', + 'Katelynn', + 'Bettie', + 'Carmella', + 'Estefania', + 'Cassandr', + 'Betsy', + 'Brianda', + 'Iliana', + 'Bryanna', + 'Aranza', + 'Rihanna', + 'Anissa', + 'Alisa', + 'Azul', + 'Milagros', + 'Gemma', + 'Freda', + 'Ada', + 'Bettye', + 'Nia', + 'Oralia', + 'Alaina', + 'Anabelle', + 'Destinee', + 'Sallie', + 'Sonja', + 'Willow', + 'Staci', + 'Lia', + 'Breana', + 'Eliza', + 'Mikaela', + 'Mona', + 'Cataleya', + 'Jeannine', + 'Lilah', + 'Anabel', + 'Ashlynn', + 'Aleena', + 'Estella', + 'Ayla', + 'Adelaide', + 'Lilliana', + 'Kristie', + 'Nettie', + 'Cherie', + 'May', + 'Myra', + 'Nicolette', + 'Lissette', + 'Siena', + 'Ivanna', + 'Christa', + 'Caylee', + 'Roseann', + 'Anastasia', + 'Karin', + 'Corinne', + 'Ginger', + 'Flora', + 'Bria', + 'Gretchen', + 'Maryellen', + 'Lana', + 'Harmony', + 'Elvira', + 'Ilene', + 'Iesha', + 'Celine', + 'Faye', + 'Khadijah', + 'Elyse', + 'Joana', + 'Sharyn', + 'Leia', + 'Catherin', + 'Corina', + 'Sheree', + 'Salma', + 'Deja', + 'Liz', + 'Aracely', + 'Roselyn', + 'Samara', + 'Lorrie', + 'Frida', + 'Tessie', + 'Talia', + 'Rosalind', + 'Jailene', + 'Lisette', + 'Raelynn', + 'Yetta', + 'Catharine', + 'Adelynn', + 'Odalys', + 'Jolene', + 'Charity', + 'Aniya', + 'Sanjuanita', + 'Norah', + 'Terrie', + 'Yuliana', + 'Lorie', + 'Yazmin', + 'Eleanore', + 'Anika', + 'Elida', + 'Valery', + 'Matilda', + 'Nannie', + 'Eloise', + 'Gillian', + 'Tatyana', + 'Kimora', + 'Brynn', + 'Maliyah', + 'Madilyn', + 'Jenifer', + 'Maddison', + 'Colette', + 'Nanette', + 'Ayleen', + 'Winnie', + 'Jayda', + 'Deloris', + 'Tillie', + 'Kizzy', + 'Galilea', + 'Janessa', + 'Brenna', + 'Amelie', + 'Marybeth', + 'Lorna', + 'Kaia', + 'Sarahi', + 'Viridiana', + 'Rebeca', + 'Ericka', + 'Mareli', + 'Anaya', + 'Nathaly', + 'Candy', + 'Larissa', + 'Elle', + 'Yasmine', + 'Claudine', + 'Kyleigh', + 'Paloma', + 'Lenore', + 'Citlali', + 'Rosanna', + 'Misti', + 'Kasandra', + 'Zara', + 'Isis', + 'Alisson', + 'Cheyanne', + 'Reba', + 'Ariella', + 'Lavonne', + 'Miah', + 'Roxanna', + 'Anabella', + 'Suzette', + 'Kiera', + 'Gitty', + 'Farrah', + 'Helena', + 'Shaniqua', + 'Maryanne', + 'Liana', + 'Arleen', + 'Belle', + 'Katy', + 'Anya', + 'Selene', + 'Maura', + 'Chantel', + 'Keyla', + 'Maryjane', + 'Tisha', + 'Kisha', + 'Kaelyn', + 'Malka', + 'Maci', + 'Evelin', + 'Julianne', + 'Magdalena', + 'Kimberlee', + 'Ernestine', + 'Alyson', + 'Kaley', + 'Danika', + 'Kecia', + 'Leanne', + 'Tonia', + 'Nyla', + 'Ivonne', + 'Madelynn', + 'Ofelia', + 'Lakisha', + 'Adilene', + 'Wendi', + 'Susanne', + 'Katharine', + 'Faigy', + 'Raizy', + 'Tawny', + 'Jackeline', + 'Ariadne', + 'Giovanna', + 'Janiyah', + 'Alani', + 'Nayely', + 'Lilian', + 'Saundra', + 'Jazlynn', + 'Jaelynn', + 'Elliana', + 'Gayla', + 'Deena', + 'Earnestine', + 'Margo', + 'Herlinda', + 'Elinor', + 'Salina', + 'Casandra', + 'Nathalia', + 'Kaila', + 'Deanne', + 'Desirae', + 'Liza', + 'Bobbi', + 'Briella', + 'Gilda', + 'Averie', + 'Charlize', + 'Azalea', + 'Sanjuana', + 'Yajaira', + 'Brandie', + 'Aleah', + 'Della', + 'Elaina', + 'Yahaira', + 'Aja', + 'Bernadine', + 'Lela', + 'Annabel', + 'Xiomara', + 'Kassidy', + 'Nohely', + 'Aubrie', + 'Angelia', + 'Macie', + 'Shelbi', + 'Chelsie', + 'Lilyana', + 'Jazlene', + 'Amina', + 'Dorthy', + 'Noelia', + 'Addisyn', + 'Dalilah', + 'Clarisa', + 'Chrystal', + 'Oleta', + 'Georgina', + 'Adelina', + 'Edythe', + 'Lucinda', + 'Jannie', + 'Minerva', + 'Kelsie', + 'Madisyn', + 'Aida', + 'Katlyn', + 'Julieta', + 'Violeta', + 'Heidy', + 'Lea', + 'Leola', + 'Chasity', + 'Nell', + 'Felicity', + 'Kathi', + 'Karyn', + 'Hana', + 'Micaela', + 'Chandra', + 'Liberty', + 'Cielo', + 'Tameka', + 'Maude', + 'Malky', + 'Coraima', + 'Haylie', + 'Vanesa', + 'Sloane', + 'Karyme', + 'Evelynn', + 'Batsheva', + 'Nallely', + 'Tamra', + 'Maricruz', + 'Paislee', + 'Kynlee', + 'Marcela', + 'Marci', + 'Vonda', + 'Cinthia', + 'Amiyah', + 'Breanne', + 'Lisbeth', + 'Leanna', + 'Anais', + 'Flor', + 'Annemarie', + 'Amie', + 'Estela', + 'Tammi', + 'Rhiannon', + 'Denisse', + 'Leyla', + 'Iridian', + 'Dariana', + 'Romina', + 'Yamileth', + 'Lidia', + 'Sybil', + 'Elvia', + 'Debby', + 'Philomena', + 'Jacklyn', + 'Charlee', + 'Kathie', + 'Aryanna', + 'Katarina', + 'Elianna', + 'Zariah', + 'Andreina', + 'Filomena', + 'Xochitl', + 'Mariam', + 'Myla', + 'Janiya', + 'Kristal', + 'Estefany', + 'Debi', + 'Miracle', + 'Shaindy', + 'Evangelina', + 'Naya', + 'Maeve', + 'Judi', + 'Effie', + 'Lilia', + 'Dayami', + 'Kierra', + 'Vincenza', + 'Cari', + 'Lauri', + 'Bethzy', + 'Trudy', + 'Deidre', + 'Melisa', + 'Luciana', + 'Chantal', + 'Laisha', + 'Kennedi', + 'Ayanna', + 'Madalyn', + 'Dania', + 'Jaliyah', + 'Madilynn', + 'Citlaly', + 'Lolita', + 'Drema', + 'Iva', + 'Kailee', + 'Grecia', + 'Kailyn', + 'Ladonna', + 'Latanya', + 'Maia', + 'Jaquelin', + 'Alanna', + 'Etta', + 'Marlee', + 'Reina', + 'Aiyana', + 'Carolann', + 'Gizelle', + 'Greta', + 'Lynnette', + 'Cecile', + 'Shayna', + 'Savanah', + 'Annalise', + 'Nylah', + 'Lesa', + 'Jolie', + 'Arleth', + 'Laraine', + 'Selah', + 'Alysha', + 'Bridgette', + 'Madyson', + 'Marylou', + 'Adela', + 'Shaina', + 'Trista', + 'Katia', + 'Kayleen', + 'Lilianna', + 'Tamera', + 'Millicent', + 'Eugenia', + 'Myrtice', + 'Baila', + 'Charmaine', + 'Maegan', + 'Ruthie', + 'Jovanna', + 'Julisa', + 'Mayte', + 'Latrice', + 'Priscila', + 'Glenna', + 'Yitty', + 'Tawana', + 'Yessica', + 'Ina', + 'Brittni', + 'Johana', + 'Tess', + 'Caryn', + 'Natalee', + 'Barb', + 'Journee', + 'Malaysia', + 'Yulisa', + 'Alta', + 'Shaila', + 'Maurine', + 'Amira', + 'Tiffani', + 'Danette', + 'Fanny', + 'Justina', + 'Leann', + 'Dafne', + 'Ima', + 'Azucena', + 'Braylee', + 'Amaris', + 'Bailee', + 'Giana', + 'Josette', + 'Raegan', + 'Gena', + 'Luella', + 'Nita', + 'Laney', + 'Gisela', + 'Alexandrea', + 'Rosalia', + 'Odessa', + 'Laci', + 'Yamilex', + 'Tamia', + 'Astrid', + 'Luanne', + 'Gwen', + 'Tabatha', + 'Rivky', + 'Laureen', + 'Zina', + 'Amara', + 'Itzayana', + 'Adamaris', + 'Laylah', + 'Luisa', + 'Georgette', + 'Joselin', + 'Yamilet', + 'Nilda', + 'Luisana', + 'Coleen', + 'Cecily', + 'Jocelynn', + 'Mirella', + 'Jessika', + 'Moriah', + 'Halle', + 'Caren', + 'Earline', + 'Shantel', + 'Aliana', + 'Keila', + 'Maryam', + 'Marianna', + 'Magaly', + 'Sariah', + 'Marnie', + 'Kiersten', + 'Janeth', + 'Lyndsey', + 'Shelli', + 'Jaylee', + 'Ashlie', + 'Tianna', + 'Bree', + 'Isela', + 'Krystina', + 'Yaretzy', + 'Evelina', + 'Sarina', + 'Tyra', + 'Eloisa', + 'Maite', + 'Leilah', + 'Marcie', + 'Imelda', + 'Alena', + 'Juniper', + 'Shelbie', + 'Shakira', + 'Ember', + 'Emmalyn', + 'Elissa', + 'Skyla', + 'Lylah', + 'Xitlali', + 'Gisele', + 'Polly', + 'Ernestina', + 'Sandi', + 'Emmy', + 'Josefa', + 'Magali', + 'Ashely', + 'Eve', + 'Jayde', + 'Rosella', + 'Yuridia', + 'Sheyla', + 'Raelyn', + 'Domenica', + 'Valarie', + 'Herminia', + 'Katalina', + 'Shaquana', + 'Nelly', + 'Rosalyn', + 'Denice', + 'Saanvi', + 'Cambria', + 'Joseline', + 'Tomasa', + 'Milana', + 'Harriett', + 'Devorah', + 'Jackelyn', + 'Jacquelin', + 'Yadhira', + 'Antonella', + 'Shreya', + 'Janay', + 'Betzy', + 'Kaiya', + 'Terra', + 'Roseanne', + 'Karime', + 'Lina', + 'Macey', + 'Vilma', + 'Shaniya', + 'Deyanira', + 'Cindi', + 'Mandi', + 'Sanaa', + 'Lakesha', + 'Essence', + 'Faviola', + 'Brinley', + 'Kirstie', + 'Brissa', + 'Alia', + 'Janney', + 'Kaylynn', + 'Kamilah', + 'Kianna', + 'Adrianne', + 'Yasmeen', + 'Jerri', + 'Anayeli', + 'Ambar', + 'Lorri', + 'Hailie', + 'Demetria', + 'Awilda', + 'Isabell', + 'Leonor', + 'Florine', + 'Tennille', + 'Deann', + 'Nyah', + 'Jolette', + 'Xitlaly', + 'Vienna', + 'Lenora', + 'Keily', + 'Syble', + 'Ciera', + 'Milania', + 'Lainey', + 'Nyasia', + 'Carley', + 'Kelsi', + 'Blossom', + 'Maranda', + 'Ally', + 'Serina', + 'Charli', + 'Taraji', + 'Jena', + 'Natalya', + 'Hortencia', + 'Ila', + 'Kailani', + 'Mira', + 'Evie', + 'Ione', + 'Briseyda', + 'Aryana', + 'Yarely', + 'Susanna', + 'Amya', + 'Kaleigh', + 'Qiana', + 'Juli', + 'Mckayla', + 'Suzan', + 'Fallon', + 'Jacalyn', + 'Ileana', + 'Yesica', + 'Willa', + 'Fatoumata', + 'Arly', + 'Jakayla', + 'Chyna', + 'Jaida', + 'Sunshine', + 'Beyonce', + 'Lawanda', + 'Flossie', + 'Lupita', + 'Demi', + 'Keely', + 'Aliya', + 'Jeanie', + 'Tamiko', + 'Gigi', + 'Brissia', + 'Mariel', + 'Lluvia', + 'Jasleen', + 'Lizet', + 'Brittanie', + 'Kaci', + 'Alycia', + 'Madalynn', + 'Milena', + 'Coraline', + 'Kaela', + 'Soraya', + 'Mozelle', + 'Jessenia', + 'Wilhelmina', + 'Jazmyn', + 'Stefani', + 'Natali', + 'Christiana', + 'Ivana', + 'Eiza', + 'Zaria', + 'Zaira', + 'Lorelei', + 'Cherry', + 'Aline', + 'Briseida', + 'Siani', + 'Yara', + 'Rhianna', + 'Kalia', + 'Destiney', + 'Hindy', + 'Arlette', + 'Shyanne', + 'Joceline', + 'Janell', + 'Vianey', + 'Elnora', + 'Zoie', + 'Elba', + 'Jamila', + 'Rena', + 'Mari', + 'Chava', + 'Scarlette', + 'Shyla', + 'Corine', + 'Kaliyah', + 'Ailyn', + 'Liv', + 'Freya', + 'Diya', + 'Myrtis', + 'Aliah', + 'Margery', + 'Gracelyn', + 'Shira', + 'Riya', + 'Breann', + 'Siobhan', + 'Rochel', + 'Tiffanie', + 'Mirna', + 'Nilsa', + 'Tenley', + 'Aliza', + 'Celena', + 'Vianney', + 'Janel', + 'Toccara', + 'Dayna', + 'Rona', + 'Alba', + 'Althea', + 'Josselyn', + 'Karlie', + 'Alyce', + 'Erlinda', + 'Kadijah', + 'Rosalba', + 'Tangela', + 'Marlena', + 'Delois', + 'Chastity', + 'Coral', + 'Braelynn', + 'Dalila', + 'Rosetta', + 'Lu', + 'Venessa', + 'Kayley', + 'Barbra', + 'Jesica', + 'Dona', + 'Mitzi', + 'Catrina', + 'Gracelynn', + 'Ophelia', + 'Ayana', + 'Mara', + 'Calista', + 'Adyson', + 'Marilynn', + 'Tomeka', + 'Britni', + 'Whitley', + 'Karly', + 'Verenice', + 'Raylee', + 'Dayanna', + 'Shonda', + 'Felecia', + 'Betzaida', + 'Kaylani', + 'Shaylee', + 'Jazzlyn', + 'Giavanna', + 'Vivianna', + 'Jesusa', + 'Lashonda', + 'Maile', + 'Suzy', + 'Vania', + 'Giada', + 'Maisie', + 'Venus', + 'Emerald', + 'Wilda', + 'Saniya', + 'Naydelin', + 'Enid', + 'Leilany', + 'Jesenia', + 'Maliah', + 'Dortha', + 'Dalary', + 'Chany', + 'Amia', + 'Amalia', + 'Khaleesi', + 'Taina', + 'Abbey', + 'Dollie', + 'Joslyn', + 'Sommer', + 'Lilibeth', + 'Charleigh', + 'Sydell', + 'Shoshana', + 'Nechama', + 'Jamya', + 'Jeanmarie', + 'Albertha', + 'Akeelah', + 'Aanya', + 'Destini', + 'Kacie', + 'Maleah', + 'Cayla', + 'Bryana', + 'Zelma', + 'Anjanette', + 'Kaylah', + 'Tonja', + 'Amairani', + 'Karli', + 'Elina', + 'Aurelia', + 'Judie', + 'Letha', + 'Brittnee', + 'Yanira', + 'Ariza', + 'Kataleya', + 'Berta', + 'Soleil', + 'Marleen', + 'Desteny', + 'Gissel', + 'Suri', + 'Anjelica', + 'Lilith', + 'Breeanna', + 'Krysta', + 'Alysia', + 'Chrissy', + 'Lailah', + 'Cathryn', + 'Dawna', + 'Myah', + 'Lelia', + 'Aviana', + 'Xena', + 'Pansy', + 'Jazleen', + 'Kaylyn', + 'Mariann', + 'Celene', + 'Berniece', + 'Anjali', + 'Benita', + 'Reanna', + 'Sydnee', + 'Taliyah', + 'Raylene', + 'Kristyn', + 'Latonia', + 'Pa', + 'Nola', + 'Lyanne', + 'Danae', + 'Sharla', + 'Chanelle', + 'Aleyda', + 'Deb', + 'Sofie', + 'Shameka', + 'Emelia', + 'Miya', + 'Latricia', + 'Claribel', + 'Lacie', + 'Taisha', + 'Queen', + 'Breeana', + 'Ilana', + 'Erna', + 'Neha', + 'Melodie', + 'Ariah', + 'Ursula', + 'Janna', + 'Cienna', + 'Maryjo', + 'Vannessa', + 'Saniyah', + 'Mariajose', + 'Malaya', + 'Abbigail', + 'Elin', + 'Emi', + 'Shanaya', + 'Zahra', + 'Lorine', + 'Karrie', + 'Johnna', + 'Marni', + 'Karis', + 'Shelba', + 'Omayra', + 'Claudette', + 'Anitra', + 'Jenelle', + 'Zelda', + 'Alyse', + 'Alethea', + 'Jannet', + 'Myranda', + 'Corinna', + 'Pattie', + 'Jemma', + 'Avah', + 'Joycelyn', + 'Loriann', + 'Kirstin', + 'Davina', + 'Clementine', + 'Arantza', + 'Esme', + 'Vida', + 'Samira', + 'Alysa', + 'Ananya', + 'Cherish', + 'Jocelin', + 'Renae', + 'Jalisa', + 'Elease', + 'Salena', + 'Zhane', + 'Zulema', + 'Rubye', + 'Amerie', + 'Leatrice', + 'Geralyn', + 'Brigitte', + 'Sibyl', + 'Corrina', + 'Phylicia', + 'Karlee', + 'Kerrie', + 'Addilyn', + 'Alayah', + 'Jacquely', + 'Mirian', + 'Jovana', + 'Katelin', + 'Marielena', + 'Libby', + 'Aditi', + 'Nalani', + 'Lilyanna', + 'Mylee', + 'Goldy', + 'Melia', + 'Audriana', + 'Lillyana', + 'Enriqueta', + 'Tasia', + 'Debbi', + 'Ani', + 'Elyssa', + 'Yamile', + 'Bridgett', + 'Taniya', + 'Britany', + 'Latosha', + 'Shanda', + 'Estephanie', + 'Maudie', + 'Mariyah', + 'Tana', + 'Neva', + 'Kalea', + 'Oma', + 'Jazelle', + 'Neveah', + 'Leonora', + 'Miesha', + 'Corrine', + 'Jordynn', + 'Cornelia', + 'Ronni', + 'Malinda', + 'Janeen', + 'Neriah', + 'Brigette', + 'Windy', + 'Cassondra', + 'Klarissa', + 'Lizzette', + 'Tanika', + 'Izamar', + 'Tera', + 'Arianny', + 'Florene', + 'Evalyn', + 'Poppy', + 'Deisy', + 'Jannette', + 'Thania', + 'Kelsea', + 'Taniyah', + 'Geri', + 'Allyssa', + 'Zariyah', + 'Averi', + 'Leeann', + 'Kallie', + 'Loni', + 'Bryleigh', + 'Rosina', + 'Carlee', + 'Preslee', + 'Alexsandra', + 'Adamari', + 'Saray', + 'Yaneli', + 'Raina', + 'Lianna', + 'Keilani', + 'Tamela', + 'Ninfa', + 'Ireland', + 'Shante', + 'Racheal', + 'Zainab', + 'Blima', + 'Yocheved', + 'Gema', + 'Sayra', + 'Aretha', + 'Nya', + 'Criselda', + 'Anai', + 'Bracha', + 'Amirah', + 'Sury', + 'Twila', + 'Arissa', + 'Livia', + 'Jacquline', + 'Chiara', + 'Anneliese', + 'Quiana', + 'Monika', + 'Charisse', + 'Emerie', + 'Rosalva', + 'Halie', + 'Jenesis', + 'Zaylee', + 'Pricilla', + 'Ouida', + 'Felipa', + 'Latifah', + 'Kalley', + 'Clarice', + 'Nona', + 'Jaunita', + 'Hermelinda', + 'Analy', + 'Jizelle', + 'Theda', + 'Yoselyn', + 'Dottie', + 'Brittaney', + 'Meghann', + 'Azeneth', + 'Richelle', + 'Peggie', + 'Brittny', + 'Jaci', + 'Marietta', + 'Gissell', + 'Evolet', + 'Abbygail', + 'Naima', + 'Noelani', + 'Jaslyn', + 'Katheryn', + 'Ruthann', + 'Shelva', + 'Ashli', + 'Alianna', + 'Felicitas', + 'Delfina', + 'Rayna', + 'Christal', + 'Leta', + 'Tawnya', + 'Zaniyah', + 'Cathie', + 'Antonette', + 'Bethann', + 'Nannette', + 'Vita', + 'Santa', + 'Dejah', + 'Patience', + 'Alessia', + 'Ahuva', + 'Karely', + 'Anette', + 'Alfreda', + 'Cyndi', + 'Cami', + 'Shirlee', + 'Roxann', + 'Alvina', + 'Sima', + 'Star', + 'Tatianna', + 'Krissy', + 'Dreama', + 'Diann', + 'Birdie', + 'Yoshiko', + 'Violette', + 'Mylah', + 'Rosita', + 'Eartha', + 'Miabella', + 'Shanika', + 'Gricel', + 'Ariyah', + 'Emmalee', + 'Nidia', + 'Gladis', + 'Roxie', + 'Zoraida', + 'Kandace', + 'Annamarie', + 'Alannah', + 'Abrielle', + 'Mercy', + 'Lesli', + 'Sydni', + 'Kathrine', + 'Jiselle', + 'Anisa', + 'Felisha', + 'Kayli', + 'Nanci', + 'Ria', + 'Cailyn', + 'Melani', + 'Alyna', + 'Bambi', + 'Avril', + 'Amberly', + 'Towanda', + 'Malissa', + 'Kaleena', + 'Kinsey', + 'Andria', + 'Emogene', + 'Milani', + 'Milah', + 'Hadassah', + 'Avianna', + 'Aubri', + 'Pessy', + 'Dori', + 'Tea', + 'Keshia', + 'Adina', + 'Esha', + 'Magnolia', + 'Moesha', + 'Elana', + 'Vikki', + 'Lakendra', + 'Ilse', + 'Sydnie', + 'Laquita', + 'Hortense', + 'Elouise', + 'Tarah', + 'Shamika', + 'Genoveva', + 'Margot', + 'Aubrielle', + 'Aya', + 'Aleta', + 'Shantell', + 'Angelle', + 'Lakeshia', + 'Leota', + 'Stormie', + 'Caryl', + 'Cristy', + 'Sydelle', + 'Analisa', + 'Earlene', + 'Syreeta', + 'Paityn', + 'Citlally', + 'Nikole', + 'Leandra', + 'Elda', + 'Lizbet', + 'Blimy', + 'Lorelai', + 'Gittel', + 'Jasmyn', + 'Verania', + 'Zoya', + 'Anyssa', + 'Jeniffer', + 'Dorene', + 'Makaila', + 'Earlean', + 'Ysabella', + 'Brandee', + 'Nailea', + 'Stefany', + 'Amiya', + 'Carolee', + 'Kassie', + 'Theodora', + 'Merissa', + 'Skylah', + 'Alesia', + 'Leela', + 'Madge', + 'Shanta', + 'Soledad', + 'Sharonda', + 'Thea', + 'Capri', + 'Amparo', + 'Concha', + 'Karolina', + 'Keitha', + 'Harriette', + 'Evette', + 'Mylie', + 'Isha', + 'Suzie', + 'Carlene', + 'Brunilda', + 'Annamae', + 'Ariadna', + 'Sanai', + 'Gisell', + 'Danelle', + 'Dovie', + 'Lani', + 'Shavonne', + 'Janiah', + 'Kora', + 'Jessa', + 'Melva', + 'Yehudis', + 'Analee', + 'Enedina', + 'Oaklee', + 'Aubrianna', + 'Velia', + 'Zooey', + 'Dolly', + 'Shanae', + 'Lyndsay', + 'Allene', + 'Kamya', + 'Tedra', + 'Yecenia', + 'Nyree', + 'Shyann', + 'Kandice', + 'Edwina', + 'Aiyanna', + 'Carli', + 'Sariyah', + 'Gwyneth', + 'Roseanna', + 'Charla', + 'Nereyda', + 'Yides', + 'Helaine', + 'Evita', + 'Alanis', + 'Starr', + 'Rosalee', + 'Yaire', + 'Risa', + 'Kristel', + 'Greidys', + 'Lillianna', + 'Khushi', + 'Triniti', + 'Lilyan', + 'Myesha', + 'Kala', + 'Moira', + 'Neida', + 'Gisel', + 'Myriam', + 'Anali', + 'Izabel', + 'Savana', + 'Sanjana', + 'Willodean', + 'Briza', + 'Lyra', + 'Merry', + 'Cheryle', + 'Porsha', + 'Kaili', + 'Buffy', + 'Deidra', + 'Everleigh', + 'Gardenia', + 'Italia', + 'Novella', + 'Sahara', + 'Sirena', + 'Elide', + 'Madisen', + 'Katerina', + 'Ashlea', + 'Rianna', + 'Samatha', + 'Diandra', + 'Shanell', + 'Annalee', + 'Samiyah', + 'Joselyne', + 'Maylin', + 'Jazmyne', + 'Terese', + 'Nydia', + 'Stasia', + 'Saira', + 'Carlota', + 'Kathia', + 'Katya', + 'Elodie', + 'Priya', + 'Malena', + 'Aadhya', + 'Meera', + 'Tayla', + 'Jovita', + 'Rafaela', + 'Faiga', + 'Jaquelyn', + 'Elisheva', + 'Debbra', + 'Melyssa', + 'Chelsi', + 'Gricelda', + 'Tawanda', + 'Sharlene', + 'Mellissa', + 'Alene', + 'Amayah', + 'Nicolle', + 'Yanet', + 'Zissy', + 'Candi', + 'Hedwig', + 'Leyna', + 'Nichol', + 'Reva', + 'Fraidy', + 'Esty', + 'Kaily', + 'Mimi', + 'Shani', + 'Hadlee', + 'Naomy', + 'Kinslee', + 'Emmalynn', + 'Alverta', + 'Anushka', + 'Tinsley', + 'Armida', + 'Cleta', + 'Analise', + 'Ahtziri', + 'Anakaren', + 'Tracee', + 'Glynda', + 'Kaelynn', + 'Carie', + 'Avalon', + 'Eboni', + 'Shameeka', + 'Letitia', + 'Enola', + 'Rasheeda', + 'Taylee', + 'Jerrica', + 'Janely', + 'Taya', + 'Xochilt', + 'Rosana', + 'Doretha', + 'Henny', + 'Shaniece', + 'Charleen', + 'Abigale', + 'Marylyn', + 'Retha', + 'Keren', + 'Elly', + 'Ailani', + 'Aarna', + 'Starla', + 'Maren', + 'Nan', + 'Marivel', + 'Georgianna', + 'Era', + 'Kirra', + 'Maisha', + 'Caydence', + 'Dinah', + 'Noemy', + 'Tamatha', + 'Madonna', + 'Kristan', + 'Keana', + 'Kloe', + 'Maribeth', + 'Sana', + 'Korina', + 'Irania', + 'Izabelle', + 'Roxy', + 'Mariaguadalupe', + 'Sulema', + 'Vivien', + 'Tatia', + 'Holli', + 'Debrah', + 'Kattie', + 'Kaidence', + 'Cathey', + 'Anniston', + 'Refugia', + 'Renita', + 'Aubriella', + 'Kaleah', + 'Zuleyka', + 'Sherie', + 'Tomika', + 'Charisma', + 'Caridad', + 'Kailynn', + 'Gertie', + 'Jaslynn', + 'Agatha', + 'Avani', + 'Hennessy', + 'Pamala', + 'Malak', + 'Raizel', + 'Kami', + 'Rosalina', + 'Ferne', + 'Cloe', + 'Jeryl', + 'Louann', + 'Jacie', + 'Tais', + 'Johnsie', + 'Brittnie', + 'Collette', + 'Lettie', + 'Jeanna', + 'Kyara', + 'Renada', + 'Abrianna', + 'Nayelli', + 'Alda', + 'Yuna', + 'Cristi', + 'Yazmine', + 'Marlie', + 'Milly', + 'Anastacia', + 'Daria', + 'Caitlynn', + 'Shriya', + 'Vianca', + 'Sayuri', + 'Dennise', + 'Aleyna', + 'Jenni', + 'Tanesha', + 'Suzanna', + 'Zaniya', + 'Kesha', + 'Edie', + 'Ansleigh', + 'Emmie', + 'Marjory', + 'Lanette', + 'Babette', + 'Alaya', + 'Palma', + 'Tamie', + 'Nelle', + 'Haydee', + 'Zeinab', + 'Stephania', + 'Biridiana', + 'Yoshie', + 'Mayme', + 'Michaele', + 'Marimar', + 'Winona', + 'Christene', + 'Meadow', + 'Ariya', + 'Daleysa', + 'Thuy', + 'Nautica', + 'Hadleigh', + 'Aliyana', + 'Annabell', + 'Stacia', + 'Leonore', + 'Albina', + 'Daira', + 'Rhona', + 'Lisbet', + 'Alizae', + 'Aminata', + 'Samanta', + 'Jerilyn', + 'Darci', + 'Sudie', + 'Kynleigh', + 'Marva', + 'Karie', + 'Marbella', + 'Franchesca', + 'Kylah', + 'Lillyanna', + 'Melony', + 'Abygail', + 'Yulianna', + 'Sahana', + 'Velvet', + 'Michelina', + 'Treva', + 'Iona', + 'Adilynn', + 'Milla', + 'Teressa', + 'Coretta', + 'Venita', + 'Evalynn', + 'Chynna', + 'Janett', + 'Nohemi', + 'Symone', + 'Kaycee', + 'Racquel', + 'Jerica', + 'Chanda', + 'Vannesa', + 'Deasia', + 'Alanah', + 'Dasha', + 'Dian', + 'Iyana', + 'Katlin', + 'Shizue', + 'Mitsuko', + 'Shara', + 'Shanelle', + 'Sinead', + 'Jacinda', + 'Alecia', + 'Tanvi', + 'Genese', + 'Crissy', + 'Niki', + 'Shanequa', + 'Trish', + 'Shalonda', + 'Darleen', + 'Magda', + 'Annalisa', + 'Lashanda', + 'Carin', + 'Nahomi', + 'Londynn', + 'Alaysia', + 'Annaliese', + 'Valorie', + 'Naidelyn', + 'Abbe', + 'Karley', + 'Cinda', + 'Marilu', + 'Azaria', + 'Kitty', + 'Mechelle', + 'Jazzmin', + 'Malina', + 'Cianna', + 'Leesa', + 'Nahla', + 'Dorotha', + 'Jaeda', + 'Tinley', + 'Kelis', + 'Ayesha', + 'Cinthya', + 'Shawnte', + 'Fawn', + 'Calleigh', + 'Mittie', + 'Aide', + 'Lisset', + 'Tyesha', + 'Devora', + 'Analeigh', + 'Anahy', + 'Donnamarie', + 'Nala', + 'Haruko', + 'Lesia', + 'Aideliz', + 'Emme', + 'Mitsue', + 'Jamiya', + 'Joleen', + 'Missy', + 'Shawanda', + 'Chastelyn', + 'Jaleah', + 'Eulalia', + 'Elvera', + 'Kalina', + 'Adrina', + 'Nicolasa', + 'Belia', + 'Elodia', + 'Kazuko', + 'Ixchel', + 'Leena', + 'Yoseline', + 'Yocelin', + 'Jamiyah', + 'Mariama', + 'Audrianna', + 'Dasia', + 'Ieshia', + 'Malorie', + 'Toniann', + 'Genessis', + 'Makeda', + 'Cherise', + 'Tarsha', + 'Karri', + 'Romayne', + 'Beronica', + 'Nubia', + 'Shasta', + 'Cristin', + 'Cristine', + 'Eryn', + 'Jazzmine', + 'Alyssia', + 'Verona', + 'Divya', + 'Beatrix', + 'Chiyoko', + 'Destinie', + 'Hali', + 'Myisha', + 'Sabina', + 'Chante', + 'Brea', + 'Aundrea', + 'Harmoni', + 'Iyanna', + 'Rosaria', + 'Hettie', + 'Bronte', + 'Constanza', + 'Heavenly', + 'Georgiana', + 'Coco', + 'Eleni', + 'Brylie', + 'Ajee', + 'Jerrie', + 'Zella', + 'Xenia', + 'Djuana', + 'Bianka', + 'Lizett', + 'Destany', + 'Bettina', + 'Pennie', + 'Ciji', + 'Ciani', + 'Tosha', + 'Roxane', + 'Tenisha', + 'Pepper', + 'Ayva', + 'Dynasty', + 'Krysten', + 'Maud', + 'Janene', + 'Yomaira', + 'Kizzie', + 'Oriana', + 'Antionette', + 'Kamille', + 'Candis', + 'Kimberlie', + 'Britta', + 'Malika', + 'Khalilah', + 'Louisa', + 'Maiya', + 'Shanay', + 'Kellye', + 'Gaye', + 'Rosangelica', + 'Breonna', + 'Jenae', + 'Kaylene', + 'Rileigh', + 'Linnea', + 'Tawanna', + 'Harleen', + 'Tamya', + 'Makaylah', + 'Annabeth', + 'Alysson', + 'Adella', + 'Adalee', + 'Karisa', + 'Rosangela', + 'Ema', + 'Dayra', + 'Tena', + 'Mathilda', + 'Magan', + 'Dayanira', + 'Annelise', + 'Takisha', + 'Rosamaria', + 'Shifra', + 'Vianna', + 'Daysi', + 'Jalissa', + 'Samaya', + 'Aubriana', + 'Alora', + 'Emmeline', + 'Elora', + 'Laylani', + 'Willene', + 'Cathrine', + 'Ginny', + 'Lashunda', + 'Mikalah', + 'Kiyoko', + 'Wynter', + 'Zuleima', + 'Alease', + 'Louella', + 'Jubilee', + 'Allegra', + 'Karmen', + 'Emiliana', + 'Jianna', + 'Eisley', + 'Emmaline', + 'Teresita', + 'Mackenna', + 'Lauretta', + 'Krystin', + 'Kalene', + 'Aviva', + 'Zena', + 'Shanique', + 'Glynis', + 'Toya', + 'Linsey', + 'Denisha', + 'Marysol', + 'Marcelina', + 'Makiyah', + 'Masako', + 'Cintia', + 'Sharen', + 'Lahoma', + 'Magen', + 'Alyvia', + 'Shaniyah', + 'Anamaria', + 'Shivani', + 'Hannia', + 'Chavy', + 'Hayleigh', + 'Jaycie', + 'Mayah', + 'Delila', + 'Danita', + 'Modesta', + 'Arcelia', + 'Deedee', + 'Monserrath', + 'Angelie', + 'Mellisa', + 'Leisa', + 'Melannie', + 'Mafalda', + 'Kinlee', + 'Annetta', + 'Freida', + 'Anisha', + 'Mayrin', + 'Dajah', + 'Delylah', + 'Hortensia', + 'Joretta', + 'Lexy', + 'Laysha', + 'Anessa', + 'Jesusita', + 'Pearline', + 'Caleigh', + 'Liset', + 'Leilene', + 'Jaya', + 'Haily', + 'Tatyanna', + 'Desire', + 'Lisha', + 'Mindi', + 'Ivelisse', + 'Amariah', + 'Blythe', + 'Treasure', + 'Latarsha', + 'Emelda', + 'Latavia', + 'Debanhi', + 'Brynleigh', + 'Gala', + 'Jurnee', + 'Joslynn', + 'Harleigh', + 'Trang', + 'Audree', + 'Brande', + 'Genea', + 'Carri', + 'Kandy', + 'Kenisha', + 'Georgene', + 'Kamora', + 'Anabell', + 'Meranda', + 'Renesmee', + 'Rosaura', + 'Linette', + 'Rosamond', + 'Candida', + 'Crista', + 'Keeley', + 'Mykayla', + 'Rina', + 'Jonna', + 'Lorinda', + 'Wynona', + 'Kylene', + 'Kellee', + 'Elayne', + 'Chela', + 'Zykeria', + 'Shawnna', + 'Jaimee', + 'Zuleyma', + 'Britnee', + 'Mikala', + 'Coletta', + 'Morelia', + 'Isadora', + 'Anayah', + 'Amiah', + 'Ailin', + 'Jordana', + 'Casie', + 'Shakia', + 'Cordelia', + 'Analeah', + 'Janelly', + 'Adelita', + 'Yoana', + 'Lizabeth', + 'Latoria', + 'Pricila', + 'Margaretta', + 'Fumiko', + 'Lura', + 'Toshiko', + 'Marge', + 'Luana', + 'Marilee', + 'Jeana', + 'Tallulah', + 'Zia', + 'Betsabe', + 'Delanie', + 'Jenicka', + 'Kensington', + 'Navya', + 'Golda', + 'Kambree', + 'Orpha', + 'Rayleigh', + 'Kinleigh', + 'Karleigh', + 'Avalynn', + 'Addilynn', + 'Cambree', + 'Brinlee', + 'Liba', + 'Zendaya', + 'Farah', + 'Oumou', + 'Aislinn', + 'Karena', + 'Erendira', + 'Mariaelena', + 'Temperance', + 'Angelic', + 'Khadija', + 'Jonelle', + 'Aniah', + 'Aleigha', + 'Samaria', + 'Dedra', + 'Sammantha', + 'Bernardine', + 'Leilanie', + 'Makaela', + 'Samiya', + 'Porsche', + 'Krystel', + 'Simona', + 'Catarina', + 'Joi', + 'Etty', + 'Jannat', + 'Rubie', + 'Waneta', + 'Shaquita', + 'Shaindel', + 'Alida', + 'January', + 'Riana', + 'Jamilet', + 'Jala', + 'Gearldine', + 'Iola', + 'Tiesha', + 'Ariyana', + 'Josslyn', + 'Verla', + 'Gerri', + 'Emili', + 'Jennyfer', + 'Halo', + 'Raya', + 'Asusena', + 'Jessalyn', + 'Anaiah', + 'Sabine', + 'Dorinda', + 'Andriana', + 'Charissa', + 'Cambrie', + 'Daija', + 'Danyelle', + 'Maricarmen', + 'Melania', + 'Glinda', + 'Jaretzy', + 'Keesha', + 'Lucie', + 'Persephone', + 'Veda', + 'Avalyn', + 'Odilia', + 'Teena', + 'Daisha', + 'Shianne', + 'Nadya', + 'Peighton', + 'Shawana', + 'Lateefah', + 'Geena', + 'Aixa', + 'Magdalene', + 'Estefana', + 'China', + 'Tamekia', + 'Audrie', + 'Angely', + 'Charline', + 'Britny', + 'Quanisha', + 'Erykah', + 'Kenzi', + 'Carleigh', + 'Kamiyah', + 'Zayra', + 'Abagail', + 'Sulay', + 'Shelita', + 'Cattleya', + 'Ariela', + 'Yalitza', + 'Marleigh', + 'Colbie', + 'Lavergne', + 'Pyper', + 'Tawni', + 'Kasie', + 'Kati', + 'Cinnamon', + 'Trana', + 'Verda', + 'Romana', + 'Merrily', + 'Landri', + 'Bruchy', + 'Irlanda', + 'Lanie', + 'Kendyl', + 'Sanvi', + 'Akshara', + 'Aneesa', + 'Giulia', + 'Ruchy', + 'Giulianna', + 'Zahara', + 'Sumaya', + 'Guillermina', + 'Araseli', + 'Jackelin', + 'Norine', + 'Ariane', + 'Naidelin', + 'Gwenyth', + 'Kya', + 'Liyah', + 'Danya', + 'Sujey', + 'Grayce', + 'Honey', + 'Assunta', + 'Aleksandra', + 'Almeda', + 'Devany', + 'Spring', + 'Patrica', + 'Delisa', + 'Fantasia', + 'Cydney', + 'Laquisha', + 'Lynsey', + 'Stephenie', + 'Cassaundra', + 'Elisabet', + 'Echo', + 'Juliann', + 'Micayla', + 'Iridiana', + 'Antonietta', + 'Rosaisela', + 'Bayleigh', + 'Candelaria', + 'Zaida', + 'Mercedez', + 'Kindra', + 'Malayah', + 'Stephaine', + 'Nayla', + 'Tameeka', + 'Kiesha', + 'Pooja', + 'Sahar', + 'Paisleigh', + 'Kynslee', + 'Idella', + 'Arelis', + 'Shizuko', + 'Leslee', + 'Acacia', + 'Elexis', + 'Violetta', + 'Sailor', + 'Marceline', + 'Una', + 'Kamilla', + 'Aulani', + 'Aracelis', + 'Kikue', + 'Kasi', + 'Elwanda', + 'Brookelyn', + 'Kellyann', + 'Shaquanna', + 'Marielle', + 'Isel', + 'Agustina', + 'Vergie', + 'Arriana', + 'Perel', + 'Maylee', + 'Navy', + 'Lanell', + 'Rosann', + 'Carmelita', + 'Deisi', + 'Alyza', + 'Nailah', + 'Somaya', + 'Kiarra', + 'Tatiyana', + 'Nelida', + 'Demetra', + 'Thais', + 'Syriana', + 'Nicki', + 'Tyanna', + 'Idaly', + 'Ramonita', + 'Zuzanna', + 'Aiza', + 'Larae', + 'Alyanna', + 'Aleyah', + 'Elayna', + 'Blaire', + 'Laniyah', + 'Rilynn', + 'Kandi', + 'Sherryl', + 'Marti', + 'Cherri', + 'Kimberli', + 'Carma', + 'Trena', + 'Darcie', + 'Evelyne', + 'Allissa', + 'Meliza', + 'Regine', + 'Adalina', + 'Siya', + 'Seraphina', + 'Calliope', + 'Jiya', + 'Talisa', + 'Mistie', + 'Ignacia', + 'Crysta', + 'Lona', + 'Voncile', + 'Rutha', + 'Kamiya', + 'Anslee', + 'Janya', + 'Berenise', + 'Sonji', + 'Yaeko', + 'Nika', + 'Queena', + 'Yatziri', + 'Aiko', + 'Lisamarie', + 'Evalina', + 'Alline', + 'Alejandrina', + 'Trula', + 'Hinda', + 'Delinda', + 'Brisia', + 'Aminah', + 'Mariella', + 'Nayzeth', + 'Sherlin', + 'Idalia', + 'Madaline', + 'Shenika', + 'Janaya', + 'Fabiana', + 'Aleeah', + 'Lasonya', + 'Jania', + 'Breindy', + 'Mitzy', + 'Yaquelin', + 'Tzipora', + 'Serene', + 'Mikaila', + 'Aicha', + 'Brucha', + 'Myrka', + 'Kaaren', + 'Meg', + 'Lise', + 'Suhani', + 'Liane', + 'Celisse', + 'Jasmyne', + 'Sharde', + 'Dannielle', + 'Crystle', + 'Jenniffer', + 'Shaneka', + 'Leslye', + 'Hedy', + 'Tashina', + 'Letisia', + 'Carys', + 'Antonetta', + 'Tamisha', + 'Kaniya', + 'Darline', + 'Alizay', + 'Minna', + 'Raelene', + 'Rebecka', + 'Martika', + 'Makiya', + 'Idalis', + 'Keasia', + 'Breeann', + 'Vlasta', + 'Ellianna', + 'Caelyn', + 'Kaytlin', + 'Cathi', + 'Jamia', + 'Tahnee', + 'Zulma', + 'Mallorie', + 'Katlynn', + 'Mahi', + 'Carleen', + 'Honesty', + 'Rasheedah', + 'Ronna', + 'Lissa', + 'Sherika', + 'Carolynn', + 'Romona', + 'Jamesha', + 'Shakiyla', + 'Mccall', + 'Joanie', + 'Makala', + 'Brionna', + 'Shaunna', + 'Hawa', + 'Marylin', + 'Baylie', + 'Preslie', + 'Aaralyn', + 'Pia', + 'Beatris', + 'Adria', + 'Arianne', + 'Carmina', + 'Sebrina', + 'Malani', + 'Lovely', + 'Jahaira', + 'Miyah', + 'Sylvie', + 'Cassi', + 'Kaniyah', + 'Cailin', + 'Santina', + 'Nariah', + 'Calandra', + 'Georgine', + 'Serafina', + 'Keyana', + 'Amethyst', + 'Tehya', + 'Avni', + 'Alessa', + 'Novalee', + 'Mayleen', + 'Aadya', + 'Jacquelynn', + 'Izetta', + 'Sumiko', + 'Irasema', + 'Annamaria', + 'Niya', + 'Latrina', + 'Cicely', + 'Kristiana', + 'Kimiko', + 'Keara', + 'Mazie', + 'Najah', + 'Evelia', + 'Tiarra', + 'Jaela', + 'Montine', + 'Mandie', + 'Lavada', + 'Dimple', + 'Emiko', + 'Yocelyn', + 'Issabella', + 'Rowena', + 'Tanja', + 'Velda', + 'Chantell', + 'Gretel', + 'Jacelyn', + 'Kambri', + 'Zayla', + 'Anasofia', + 'Atiana', + 'Dulcemaria', + 'Zulay', + 'Tari', + 'Sahasra', + 'Rayleen', + 'Greydis', + 'Shiela', + 'Florinda', + 'Samya', + 'Shakima', + 'Shakeema', + 'Yanely', + 'Lavina', + 'Azalee', + 'Oneta', + 'Tammye', + 'Kelsy', + 'Kalie', + 'Keanna', + 'Daniya', + 'Antonina', + 'Katharin', + 'Tiare', + 'Yorley', + 'Jeslyn', + 'Emeli', + 'Zakia', + 'Massiel', + 'Latesha', + 'Jenessa', + 'Jayna', + 'Raylynn', + 'Ainslee', + 'Aralynn', + 'Khloee', + 'Ily', + 'Emeri', + 'Jeni', + 'Kassi', + 'Nakita', + 'Lakia', + 'Ariyanna', + 'Addalyn', + 'Keyanna', + 'Bibiana', + 'Genna', + 'Kathya', + 'Leana', + 'Trane', + 'Yomira', + 'Brigid', + 'Dionna', + 'Jerilynn', + 'Sarita', + 'Altha', + 'Laniya', + 'Zakiya', + 'Akilah', + 'Celestina', + 'Priyanka', + 'Taliah', + 'Donya', + 'Soila', + 'Quetzalli', + 'Cristel', + 'Naia', + 'Kailah', + 'Zitlaly', + 'Tonda', + 'Cate', + 'Lizzet', + 'Vesta', + 'Sherilyn', + 'Teruko', + 'Aldona', + 'Armandina', + 'Ciana', + 'Amairany', + 'Elysia', + 'Samarah', + 'Janyla', + 'Skylee', + 'Rolanda', + 'Sapphire', + 'Setsuko', + 'Miyoko', + 'Contina', + 'Imogen', + 'Jailine', + 'Vanellope', + 'Leora', + 'Jennah', + 'Perl', + 'Analiyah', + 'Hellen', + 'Tyasia', + 'Symphony', + 'Amada', + 'Otilia', + 'Avigail', + 'Tzivia', + 'Fradel', + 'Mariadelcarmen', + 'Ilona', + 'Dyan', + 'Zahraa', + 'Patrisia', + 'Jersey', + 'Lilla', + 'Lossie', + 'Somer', + 'Deserie', + 'Jaila', + 'Briseis', + 'Aniston', + 'Idell', + 'Raeleigh', + 'Gracyn', + 'Everlee', + 'Laurene', + 'Sherita', + 'Pinkie', + 'Nakisha', + 'Olevia', + 'Corene', + 'Loreen', + 'Sandie', + 'Keosha', + 'Kenleigh', + 'Alli', + 'Alyana', + 'Prisha', + 'Brookelynn', + 'Thaily', + 'Maddie', + 'Grettel', + 'Kinzley', + 'Jailynn', + 'Kalli', + 'Jazzlynn', + 'Klaudia', + 'Blanch', + 'Mariafernanda', + 'Makenzi', + 'Shonna', + 'Lita', + 'Karima', + 'Rebeccah', + 'Isaura', + 'Kalee', + 'Jori', + 'Allysa', + 'Tonisha', + 'Neda', + 'Jenine', + 'Chanell', + 'Jamaya', + 'Lorrayne', + 'Birtha', + 'Kanisha', + 'Nicollette', + 'Desiray', + 'Kaity', + 'Shamya', + 'Kathlene', + 'Jann', + 'Sari', + 'Lucila', + 'Tressie', + 'Charise', + 'Kalista', + 'Jamileth', + 'Kalena', + 'Sakura', + 'Blondell', + 'Thomasina', + 'Aila', + 'Mossie', + 'Tamala', + 'Siri', + 'Gertha', + 'Reta', + 'Easter', + 'Tala', + 'Vivianne', + 'Nila', + 'Merida', + 'Ahana', + 'Lanelle', + 'Hilaria', + 'Arlys', + 'Inell', + 'Rylynn', + 'Cosette', + 'Penne', + 'Jenevieve', + 'Jenilee', + 'Carlotta', + 'Ziva', + 'Hildegard', + 'Aleshia', + 'Nedra', + 'Madelaine', + 'Lisandra', + 'Pang', + 'Sindy', + 'Zenaida', + 'Lulu', + 'Shanya', + 'Shakema', + 'Katiria', + 'Raffaela', + 'Solange', + 'Illiana', + 'Chelsy', + 'Shanee', + 'Adriene', + 'Tyla', + 'Cailey', + 'Daijah', + 'Melonie', + 'Courteney', + 'Deysi', + 'Makinley', + 'Brynna', + 'Hildegarde', + 'Fiorella', + 'Kenadee', + 'Ellyn', + 'Ebonie', + 'Thu', + 'Charde', + 'Kaytlyn', + 'Kenadie', + 'Georgeann', + 'Analicia', + 'Emalee', + 'Shatara', + 'Lucerito', + 'Mckell', + 'Atiya', + 'Stormi', + 'Maleny', + 'Nariyah', + 'Steffanie', + 'Kirstyn', + 'Zayda', + 'Mariadejesus', + 'Deeann', + 'Abcde', + 'Eleanora', + 'Pearle', + 'Seana', + 'Denine', + 'Presleigh', + 'Keziah', + 'Queenie', + 'Henchy', + 'Merari', + 'Joscelyn', + 'Celest', + 'Mirel', + 'Sania', + 'Maryah', + 'Angelena', + 'Emelyn', + 'Gissele', + 'Fanta', + 'Gaylene', + 'Adelaida', + 'Madie', + 'Maja', + 'Nashaly', + 'Christel', + 'Rachele', + 'Raniyah', + 'Rashel', + 'Kavya', + 'Callista', + 'Elmira', + 'Rifky', + 'Syeda', + 'Tresa', + 'Detra', + 'Jarely', + 'Prisila', + 'Enedelia', + 'Trany', + 'Lainie', + 'Yisel', + 'Alynna', + 'Allysson', + 'Tamica', + 'Velva', + 'Nancee', + 'Breleigh', + 'Shanita', + 'Orelia', + 'Patrici', + 'Daja', + 'Shardae', + 'Abriana', + 'Halee', + 'Dorcas', + 'Kathey', + 'Rosia', + 'Princesa', + 'Lezly', + 'Dawnmarie', + 'Gaby', + 'Ania', + 'Denae', + 'Jahzara', + 'Jaymie', + 'Bari', + 'Suzann', + 'Alnisa', + 'Fatimah', + 'Zakiyyah', + 'Yana', + 'Naimah', + 'Tyisha', + 'Kathaleen', + 'Sameerah', + 'Chesney', + 'Shanteria', + 'Pamella', + 'Rayven', + 'Romelia', + 'Lucretia', + 'Tova', + 'Aura', + 'Chelsee', + 'Roizy', + 'Manha', + 'Nisha', + 'Tierney', + 'Girl', + 'Taelor', + 'Litzi', + 'Sneha', + 'Natisha', + 'Alliyah', + 'Sully', + 'Twyla', + 'Daisey', + 'Sarahy', + 'Shemeka', + 'Lexis', + 'Shalanda', + 'Kelcie', + 'Natacha', + 'Amyah', + 'Byanka', + 'Kymberly', + 'Navil', + 'Britani', + 'Karolyn', + 'Emelie', + 'Zana', + 'Vernita', + 'Leigha', + 'Romy', + 'Arlet', + 'Jazlin', + 'Laynie', + 'Jesslyn', + 'Adilyn', + 'Karoline', + 'Nyomi', + 'Maycee', + 'Nicol', + 'Daliah', + 'Lillyann', + 'Shawnda', + 'Dede', + 'Wiktoria', + 'Liah', + 'Liya', + 'Emmerson', + 'Aarohi', + 'Aribella', + 'Brayleigh', + 'Sumie', + 'Elke', + 'Taja', + 'Ahsley', + 'Tisa', + 'Dannette', + 'Gidget', + 'Misao', + 'Adelle', + 'Jamiah', + 'Joselynn', + 'Jalyssa', + 'Marnita', + 'Trinitee', + 'Bev', + 'Aleida', + 'Cloey', + 'Tahlia', + 'Melodee', + 'Anaiya', + 'Clover', + 'Prudence', + 'Kalynn', + 'Dezirae', + 'Solana', + 'Reena', + 'Mariko', + 'Tiffiny', + 'Elinore', + 'Madelyne', + 'Anela', + 'Bess', + 'Perri', + 'Loree', + 'Cyndy', + 'Yolonda', + 'Jolee', + 'Tequila', + 'Sumer', + 'Cherilyn', + 'Ela', + 'Kenlee', + 'Alexxis', + 'Larisa', + 'Nevaeha', + 'Nira', + 'Shaquasia', + 'Shanel', + 'Medina', + 'Rifka', + 'Sable', + 'Atara', + 'Aissatou', + 'Mecca', + 'Anastasi', + 'Falon', + 'Holley', + 'Yuliza', + 'Lili', + 'Siara', + 'Kiarah', + 'Tiffaney', + 'Alyah', + 'Annalia', + 'Naila', + 'Analiah', + 'Aymar', + 'Tambra', + 'Elna', + 'Eola', + 'Tkeyah', + 'Zola', + 'Francheska', + 'Aidee', + 'Alexzandra', + 'Cianni', + 'Myasia', + 'Carisa', + 'Ilah', + 'Yenifer', + 'Veronika', + 'Nahomy', + 'Madysen', + 'Elsy', + 'Lilli', + 'Belva', + 'Steffie', + 'Kaylea', + 'Ginamarie', + 'Sharman', + 'Latia', + 'Shakeria', + 'Audelia', + 'Odette', + 'Shaniah', + 'Diamantina', + 'Lorayne', + 'Ciarra', + 'Wilhelmena', + 'Zaina', + 'Niesha', + 'Kanesha', + 'Turquoise', + 'Tziporah', + 'Timi', + 'Fatou', + 'Karna', + 'Matsue', + 'Vina', + 'Ronisha', + 'Layan', + 'Viktoria', + 'Lilyann', + 'Maliya', + 'Jamilex', + 'Epifania', + 'Fidela', + 'Delphia', + 'Starasia', + 'Glennie', + 'Teodora', + 'Hatsue', + 'Margarett', + 'Margarette', + 'Laronda', + 'Vicenta', + 'Cotina', + 'Meilani', + 'Mannat', + 'Leylani', + 'Lailani', + 'Seerat', + 'Reya', + 'Amilia', + 'Avary', + 'Brocha', + 'Daneen', + 'Kimie', + 'Trudi', + 'Margret', + 'Djuna', + 'Charis', + 'Izzabella', + 'Brionne', + 'Elenora', + 'Lakeitha', + 'Jacki', + 'Beckie', + 'Guinevere', + 'Inara', + 'Landrie', + 'Nicoletta', + 'Ayari', + 'Zaniah', + 'Merlene', + 'Keli', + 'Maricella', + 'Leonela', + 'Donita', + 'Tehani', + 'Susannah', + 'Journi', + 'Machelle', + 'Tammara', + 'Cherrie', + 'Nelva', + 'Destanie', + 'Neyda', + 'Tabetha', + 'Wilhelmenia', + 'Brieanna', + 'Turkessa', + 'Ameera', + 'Avital', + 'Marycruz', + 'Zoila', + 'Tressa', + 'Joellen', + 'Raisa', + 'Bethanie', + 'Ermelinda', + 'Asiyah', + 'Monifa', + 'Samia', + 'Adamary', + 'Anahit', + 'Rania', + 'Miri', + 'Ether', + 'Desirea', + 'Chimere', + 'Erla', + 'Karisma', + 'Nalleli', + 'Larhonda', + 'Darlyn', + 'Anaisa', + 'Suellen', + 'Kamaria', + 'Nashla', + 'Yuriko', + 'Tzirel', + 'Tehila', + 'Myriah', + 'Frimet', + 'Cesilia', + 'Marika', + 'Frady', + 'Deloise', + 'Saleen', + 'Betsey', + 'Merri', + 'Laurette', + 'Sharita', + 'Shena', + 'Porscha', + 'Aerial', + 'Florrie', + 'Ayah', + 'Anusha', + 'Jeanelle', + 'Lessly', + 'Mahogany', + 'See', + 'Hang', + 'Karinna', + 'Leighann', + 'Elexus', + 'Markayla', + 'Kaneesha', + 'Barbie', + 'Aurea', + 'Kaeli', + 'Arwen', + 'Angelyn', + 'Jaclynn', + 'Tesla', + 'Maritsa', + 'Madelin', + 'Alisia', + 'Tyana', + 'Kimberlyn', + 'Dejanae', + 'Dalena', + 'Blessing', + 'Courtnie', + 'Amaria', + 'Micki', + 'Safa', + 'Jadah', + 'Mele', + 'Maryssa', + 'Channel', + 'Lianne', + 'Alea', + 'Chyanne', + 'Addelyn', + 'Aaleyah', + 'Michela', + 'Torri', + 'Indira', + 'Kanani', + 'Lashundra', + 'Mikaylah', + 'Zoee', + 'Taelyn', + 'Noheli', + 'Sarena', + 'Dariela', + 'Adalie', + 'Meggan', + 'Daniyah', + 'Sela', + 'Shaelyn', + 'Maylen', + 'Giovana', + 'Ayvah', + 'Arabelle', + 'Adaline', + 'Isyss', + 'Melanny', + 'Margaux', + 'Klara', + 'Janey', + 'Idolina', + 'Georgetta', + 'Amaiya', + 'Sianna', + 'Rebeka', + 'Meleny', + 'Kelle', + 'Angelika', + 'Malerie', + 'Latara', + 'Niamh', + 'Yevette', + 'Yomayra', + 'Karizma', + 'Nayelie', + 'Shantal', + 'Latoyia', + 'Jenee', + 'Shandra', + 'Magdalen', + 'Yatzari', + 'Jettie', + 'Charlsie', + 'Idy', + 'Inaya', + 'Yitta', + 'Reem', + 'Basya', + 'Skylynn', + 'Elyana', + 'Brynley', + 'Amor', + 'Amberlee', + 'Eternity', + 'Niyah', + 'Emiley', + 'Madeleyn', + 'Korie', + 'Sanaya', + 'Meira', + 'Chevonne', + 'Sabra', + 'Uma', + 'Kaira', + 'Isobel', + 'Elli', + 'Gurleen', + 'Berneice', + 'Alvera', + 'Ambrosia', + 'Roya', + 'Bettyann', + 'Alverda', + 'Tinamarie', + 'Tanasia', + 'Lavonda', + 'Jorja', + 'Heide', + 'Marwa', + 'Annaly', + 'Aaliah', + 'Ileen', + 'Lamonica', + 'Enjoli', + 'Ninel', + 'Milissa', + 'Dawne', + 'Joie', + 'Ashlei', + 'Elidia', + 'Maybelle', + 'Getsemani', + 'Gisella', + 'Mariya', + 'Adisyn', + 'Adia', + 'Caterina', + 'Bettyjane', + 'Kaydee', + 'Rasheda', + 'Camisha', + 'Chassidy', + 'Sadia', + 'Aislyn', + 'Ngoc', + 'Mirka', + 'Lanita', + 'Lashawnda', + 'Liridona', + 'Tynisa', + 'Arnelle', + 'Librada', + 'Marita', + 'Makyla', + 'Raniya', + 'Kandis', + 'Ethelyn', + 'Divina', + 'Genevie', + 'Jadelyn', + 'Ashleen', + 'Saya', + 'Marli', + 'Calli', + 'Anyla', + 'Sheng', + 'Vasiliki', + 'Yelena', + 'Darya', + 'Clarabelle', + 'Shirlene', + 'Tommye', + 'Julieann', + 'Jennefer', + 'Rana', + 'Raeann', + 'Suleima', + 'Lilyanne', + 'Jelisa', + 'Jaymee', + 'Rhylee', + 'Keyli', + 'Brooklin', + 'Meta', + 'Shakirah', + 'Loria', + 'Sharyl', + 'Sharday', + 'Manuelita', + 'Debera', + 'Lera', + 'Jacquie', + 'Ardella', + 'Jameria', + 'Winnifred', + 'Rossana', + 'Shemika', + 'Sedona', + 'Arvilla', + 'Samaira', + 'Aitana', + 'Daiana', + 'Cassia', + 'Lucianna', + 'Tama', + 'Shigeko', + 'Sueko', + 'Hatsuko', + 'Hazle', + 'Lida', + 'Wylene', + 'Sachiko', + 'Tahiry', + 'Renea', + 'Janina', + 'Becki', + 'Vy', + 'Cherryl', + 'Arionna', + 'Marrissa', + 'Randee', + 'Norita', + 'Sonali', + 'Susann', + 'Rachell', + 'Natashia', + 'Aspyn', + 'Malaika', + 'Nuvia', + 'Safiya', + 'Contessa', + 'Julyssa', + 'Analiese', + 'Jacee', + 'Kathlyn', + 'Gracey', + 'Chassity', + 'Kady', + 'Tytiana', + 'Katiana', + 'Eneida', + 'Teela', + 'Roiza', + 'Alaura', + 'Giuseppina', + 'Randa', + 'Danisha', + 'Mariza', + 'Marquisha', + 'Sharese', + 'Deseree', + 'Inaaya', + 'Rivkah', + 'Tawnie', + 'Miriah', + 'Shereen', + 'Candra', + 'Tomiko', + 'Whittney', + 'Aziza', + 'Ayala', + 'Hafsa', + 'Zaynab', + 'Kaileigh', + 'Yarima', + 'Danitza', + 'Maram', + 'Shakeya', + 'Emmer', + 'Kareema', + 'Maayan', + 'Rheanna', + 'Jaritza', + 'Marleny', + 'Zitlali', + 'Vanity', + 'Apryl', + 'Zully', + 'Tashia', + 'Courtnee', + 'Laporsha', + 'Luvenia', + 'Batya', + 'Ayelet', + 'Quetcy', + 'Tiny', + 'Felicita', + 'Omaira', + 'Nyssa', + 'Krystine', + 'Stevi', + 'Michiko', + 'Tennie', + 'Tomekia', + 'Billiejo', + 'Yohana', + 'Krystyna', + 'Kacee', + 'Naja', + 'Charmayne', + 'Twana', + 'Jeane', + 'Brittnay', + 'Cherelle', + 'Raechel', + 'Temeka', + 'Jasmeen', + 'Zuria', + 'Zailey', + 'Saydee', + 'Renatta', + 'Neta', + 'Bg', + 'Italy', + 'Terrica', + 'Goldia', + 'Monae', + 'Yelitza', + 'Ryanne', + 'Samirah', + 'Breckyn', + 'Nicolina', + 'Olympia', + 'Almeta', + 'Tamesha', + 'Zora', + 'Emmaleigh', + 'Loralei', + 'Kennadi', + 'Julieanna', + 'Jenavieve', + 'Shylah', + 'Akemi', + 'Fonda', + 'Nizhoni', + 'Iqra', + 'Gaetana', + 'Coreen', + 'Evonne', + 'Sadako', + 'Angele', + 'Macel', + 'Alinna', + 'Avneet', + 'Jannah', + 'Nickole', + 'Lotus', + 'Yukie', + 'Laiyah', + 'Kynzlee', + 'Mailen', + 'Nobuko', + 'Annaleigh', + 'Otila', + 'Shona', + 'Kimberely', + 'Delcie', + 'Zula', + 'Roselynn', + 'Aleeyah', + 'Bellarose', + 'Damya', + 'Cammie', + 'Treena', + 'Chanie', + 'Kaliah', + 'Abella', + 'Aahana', + 'Mileena', + 'Adaleigh', + 'Keiry', + 'Journie', + 'Myrtie', + 'Tsuruko', + 'Lyda', + 'Fernande', + 'Julee', + 'Estephany', + 'Louvenia', + 'Monserat', + 'Meena', + 'Jayline', + 'Brie', + 'Elicia', + 'Suzana', + 'Dusti', + 'Odile', + 'Hilma', + 'Katarzyna', + 'Jenise', + 'Hiromi', + 'Huong', + 'Deolinda', + 'Pamelia', + 'Awa', + 'Odelia', + 'Mattison', + 'Gwenda', + 'Sera', + 'Yuritzi', + 'Karishma', + 'Kaina', + 'Henna', + 'Norene', + 'Brina', + 'Chyenne', + 'Moncerrat', + 'Keilah', + 'Saphira', + 'Marylee', + 'Meri', + 'Lajuana', + 'Lindsy', + 'Shanise', + 'Sugey', + 'Jaimi', + 'Viki', + 'Ceola', + 'Naiya', + 'Adysen', + 'Shantavia', + 'Amberlyn', + 'Brihanna', + 'Laela', + 'Kenadi', + 'Hermine', + 'Bernita', + 'Deziree', + 'Anja', + 'Lawana', + 'Aletha', + 'Nella', + 'Irelyn', + 'Jakira', + 'Wynema', + 'Janai', + 'Keondra', + 'Venice', + 'Zenobia', + 'Jaelene', + 'Ammy', + 'Alizah', + 'Lakiesha', + 'Azure', + 'Aysha', + 'Saniah', + 'Mahnoor', + 'Ananda', + 'Asma', + 'Aissata', + 'Jaileen', + 'Yailin', + 'Xiana', + 'Laiza', + 'Liseth', + 'Marykate', + 'Daizy', + 'Neoma', + 'Tykeria', + 'Shamiya', + 'Nykeria', + 'Addalynn', + 'Kenzley', + 'Ardyce', + 'Anylah', + 'Vallie', + 'Darlyne', + 'Makiah', + 'Neela', + 'Naraly', + 'Danni', + 'Jolina', + 'Ailene', + 'Lyndia', + 'Erminia', + 'Asiya', + 'Alexius', + 'Mc', + 'Maylene', + 'Signe', + 'Adelfa', + 'Yusra', + 'Keyonna', + 'Yasuko', + 'Yukiko', + 'Augustina', + 'Leen', + 'Fumie', + 'Amora', + 'Annaleah', + 'Anvi', + 'Indie', + 'Haya', + 'Emmarie', + 'Enya', + 'Chieko', + 'Kinsleigh', + 'Shiann', + 'Eufemia', + 'Fusae', + 'Akiko', + 'Hosanna', + 'Alitzel', + 'Araya', + 'Anaiyah', + 'Rosy', + 'Nishka', + 'Gao', + 'Tamiya', + 'Lillyan', + 'Eudelia', + 'Kamea', + 'Berlyn', + 'Kahlan', + 'Alinah', + 'Mahealani', + 'Leeah', + 'Rosalynn', + 'Zadie', + 'Aolanis', + 'Esta', + 'Maisy', + 'Chevelle', + 'Jalayah', + 'Yatziry', + 'Alyne', + 'Jodell', + 'Sariya', + 'Yashica', + 'Jissel', + 'Letty', + 'Mariaisabel', + 'Lizzeth', + 'Yovana', + 'Dyanna', + 'Tamyra', + 'Monzerrat', + 'Seanna', + 'Eldora', + 'Mattea', + 'Zahira', + 'Jeanetta', + 'Aysia', + 'Ashlin', + 'Tenika', + 'Lezlie', + 'Kailie', + 'Jariyah', + 'Jovie', + 'Kiyah', + 'Lynlee', + 'Abriella', + 'Adleigh', + 'Ranada', + 'Vertie', + 'Flonnie', + 'Kynnedi', + 'Lya', + 'Acelynn', + 'Emalyn', + 'Emberly', + 'Yalexa', + 'Izabela', + 'Sadye', + 'Kamyla', + 'Jayleigh', + 'Cayleigh', + 'Ceil', + 'Inger', + 'Cindee', + 'Nena', + 'Loan', + 'Kiya', + 'Laure', + 'Cristen', + 'Celenia', + 'Fredda', + 'Ravyn', + 'Mee', + 'Graci', + 'Azalia', + 'Latina', + 'Hassie', + 'Dinorah', + 'Virna', + 'Autum', + 'Michala', + 'Macayla', + 'Franca', + 'Corissa', + 'Alysse', + 'Monisha', + 'Jessyca', + 'Nisa', + 'Jacqulyn', + 'Makaylee', + 'Ellin', + 'Jameelah', + 'Shalon', + 'Jlynn', + 'Kennady', + 'Brinkley', + 'Providence', + 'Phylis', + 'Eugenie', + 'Clementina', + 'Kadynce', + 'Yuvia', + 'Mailyn', + 'Taneisha', + 'Samone', + 'Aurore', + 'Brienne', + 'Tritia', + 'Fayth', + 'Jayci', + 'Jorie', + 'Loreal', + 'Taylar', + 'Maryn', + 'Melissia', + 'Midori', + 'Hisako', + 'Hulda', + 'Bobbijo', + 'Bulah', + 'Nancye', + 'Melvina', + 'Sherree', + 'Kierstin', + 'Merrilee', + 'Lonna', + 'Judyth', + 'Nancie', + 'Lark', + 'Candyce', + 'Kadejah', + 'Kenda', + 'Fara', + 'Estephania', + 'Cady', + 'Marilin', + 'Kadie', + 'Suleyma', + 'Jacquelyne', + 'Vonetta', + 'Tanairi', + 'Charlott', + 'Shannel', + 'Zenia', + 'Alise', + 'Takara', + 'Lyndsie', + 'Ivett', + 'Letisha', + 'Idania', + 'Lacee', + 'Candie', + 'Camelia', + 'Brittanee', + 'Mariaeduarda', + 'Geovanna', + 'Kirsti', + 'Michaella', + 'Kelsee', + 'Cheryll', + 'Cyrstal', + 'Keriann', + 'Latrisha', + 'Exie', + 'Deborha', + 'Verdie', + 'Zahava', + 'Zuleika', + 'Dorla', + 'Dominiqu', + 'Sharina', + 'Ardeth', + 'Alethia', + 'Starlene', + 'Shamira', + 'Shantelle', + 'Marilou', + 'Kyah', + 'Kyana', + 'Clemencia', + 'Cordie', + 'Meagen', + 'Xitlalic', + 'Gaia', + 'Ellia', + 'Elani', + 'Jaylani', + 'Krisha', + 'Khalia', + 'Aaradhya', + 'Aeris', + 'Avamarie', + 'Artemis', + 'Sheana', + 'Jolynn', + 'Sandee', + 'Wendie', + 'Willia', + 'Loriene', + 'Apolonia', + 'Eusebia', + 'Kazue', + 'Synthia', + 'Harue', + 'Siomara', + 'Nhi', + 'Maleni', + 'Toyoko', + 'Freeda', + 'Hideko', + 'Sherrye', + 'Bethanne', + 'Merrie', + 'Peri', + 'Ozella', + 'Venetia', + 'Revonda', + 'Breauna', + 'Arika', + 'Annissa', + 'Leeza', + 'Siera', + 'Jakiyah', + 'Kamaya', + 'Lashay', + 'Elvina', + 'Laquinta', + 'Faren', + 'Harmonie', + 'Brianny', + 'Jama', + 'Johna', + 'Sharalyn', + 'Aziyah', + 'Hadassa', + 'Shantinique', + 'Treasa', + 'Penni', + 'Shakera', + 'Carolyne', + 'Shaunda', + 'Talya', + 'Karyna', + 'Natosha', + 'Vivica', + 'Pauletta', + 'Laverna', + 'Danasia', + 'Shakita', + 'Sharee', + 'Yajayra', + 'Karlene', + 'Reatha', + 'Laiba', + 'Zamiyah', + 'Shirleen', + 'Bettylou', + 'Nakiya', + 'Eryka', + 'Bailie', + 'Janiece', + 'Keisa', + 'Kiah', + 'Jennica', + 'Niasia', + 'Hildy', + 'Jacquel', + 'Mahina', + 'Eshal', + 'Khloey', + 'Emelin', + 'Eesha', + 'Kaylei', + 'Aymee', + 'Alona', + 'Catelyn', + 'Arushi', + 'Ameerah', + 'Regenia', + 'Brailey', + 'Sparkle', + 'Giavonna', + 'Ashunti', + 'Naudia', + 'Kyrsten', + 'Emmalina', + 'Neve', + 'Aolani', + 'Gizella', + 'Tameika', + 'Leocadia', + 'Nidhi', + 'Wende', + 'Eshaal', + 'Cherice', + 'Lakeysha', + 'Menucha', + 'Ameena', + 'Kloey', + 'Nayelly', + 'Kathryne', + 'Lashawna', + 'Kristle', + 'Zaylie', + 'Keylee', + 'Landree', + 'Wynell', + 'Dezarae', + 'Angelli', + 'Haddie', + 'Ilyana', + 'Jaleigh', + 'Brilee', + 'Lakeya', + 'Kanika', + 'Lavinia', + 'Marykay', + 'Ruthanne', + 'Tenille', + 'Dorine', + 'Esabella', + 'Genavieve', + 'Zarah', + 'Mileidy', + 'Solara', + 'Yamila', + 'Amaia', + 'Season', + 'Cheree', + 'Luise', + 'Tracye', + 'Christeen', + 'Florida', + 'Breona', + 'Kathe', + 'Jakyra', + 'Zury', + 'Lakeesha', + 'Yaneth', + 'Keandra', + 'Agnieszka', + 'Markita', + 'Mariska', + 'Zada', + 'Breasia', + 'Aaniyah', + 'Kambria', + 'Lilit', + 'Sheilah', + 'Cherisse', + 'Hermione', + 'Angeli', + 'Britnie', + 'Lisett', + 'Joette', + 'Nga', + 'Ruthe', + 'Anamarie', + 'Mayeli', + 'Takia', + 'Lien', + 'Tenaya', + 'Kera', + 'Meah', + 'Mei', + 'Anoushka', + 'Annalyse', + 'Persia', + 'Sheccid', + 'Kyndra', + 'Susy', + 'Steffany', + 'Jennavecia', + 'Briannah', + 'Kynlie', + 'Alexxa', + 'Paizlee', + 'Jesika', + 'Kinzlee', + 'Ishani', + 'Freyja', + 'Julietta', + 'Raynette', + 'Nely', + 'Zayleigh', + 'Amberlynn', + 'Journei', + 'Eimy', + 'Delany', + 'Emarie', + 'Brilynn', + 'Audri', + 'Abilene', + 'Saoirse', + 'Naveah', + 'Ayelen', + 'Emeline', + 'Loryn', + 'Mykaela', + 'Skarlett', + 'Tionne', + 'Rashelle', + 'Jerline', + 'Ofilia', + 'Rufina', + 'Phillis', + 'Jenica', + 'Dineen', + 'Glory', + 'Camellia', + 'Alane', + 'Angelyna', + 'Amalie', + 'Kina', + 'Kateri', + 'Neyva', + 'Malisa', + 'Saida', + 'Jerika', + 'Bayli', + 'Crystale', + 'Silvana', + 'Inga', + 'Lyndi', + 'Leeanna', + 'Cheyanna', + 'Fayrene', + 'Torie', + 'Latashia', + 'Baleigh', + 'Fidencia', + 'Rori', + 'Lorianne', + 'Catrice', + 'Cherrelle', + 'Lashaunda', + 'Sammi', + 'Thomasena', + 'Roshanda', + 'Alazae', + 'Enza', + 'Mairead', + 'Pandora', + 'Kortni', + 'Timber', + 'Chasidy', + 'Danesha', + 'Camry', + 'Charlette', + 'Kaneshia', + 'Shadae', + 'Keturah', + 'Randye', + 'Kiyana', + 'Charlean', + 'Delana', + 'Tomasita', + 'Lilliam', + 'Bibi', + 'Marguita', + 'Maryalice', + 'Iraida', + 'Tyhessia', + 'Makeba', + 'Tanaya', + 'Keiara', + 'Madlyn', + 'Jelissa', + 'Shakayla', + 'Mickayla', + 'Aleisha', + 'Keyara', + 'Mekayla', + 'Mykala', + 'Riva', + 'Inaara', + 'Paulita', + 'Lashae', + 'Destynee', + 'Christianna', + 'Rise', + 'Larraine', + 'Luetta', + 'Merna', + 'Francena', + 'Diedre', + 'Georgiann', + 'Rubbie', + 'Denita', + 'Dyani', + 'Laticia', + 'Ludivina', + 'Suanne', + 'Hareem', + 'Nava', + 'Florie', + 'Sherly', + 'Vidhi', + 'Camie', + 'Sharell', + 'Chole', + 'Jolin', + 'Polina', + 'Brittiany', + 'Delicia', + 'Brystol', + 'Beaulah', + 'Leatha', + 'Jamilah', + 'Zona', + 'Elliette', + 'Joye', + 'Aashi', + 'Kerriann', + 'Xin', + 'Michaelene', + 'Senaida', + 'Emaan', + 'Nakayla', + 'Aine', + 'Jadalyn', + 'Maimouna', + 'Klaire', + 'Macee', + 'Shandi', + 'Heily', + 'Braylynn', + 'Aislynn', + 'Chevon', + 'Henretta', + 'Bellamy', + 'Icie', + 'Draya', + 'Darianna', + 'Zyana', + 'Zaelynn', + 'Story', + 'Kambrie', + 'Ranae', + 'Florencia', + 'Porfiria', + 'Elianny', + 'Karren', + 'Yachet', + 'Euna', + 'Naoma', + 'Stefania', + 'Liora', + 'Zlaty', + 'Margene', + 'Denna', + 'Isidra', + 'Faustina', + 'Bintou', + 'Arbutus', + 'Kelci', + 'Evelena', + 'Maudine', + 'Agapita', + 'Olyvia', + 'Loma', + 'Veola', + 'Mckinlee', + 'Lamya', + 'Nashali', + 'Baileigh', + 'Josselin', + 'Kaydance', + 'Paiton', + 'Myleigh', + 'Jazlyne', + 'Indya', + 'Siham', + 'Aryn', + 'Madalene', + 'Nefertiti', + 'Meridith', + 'Kamesha', + 'Peg', + 'Shelbey', + 'Pearlean', + 'Jamika', + 'Maryama', + 'Sabria', + 'Taniqua', + 'Maraya', + 'Joely', + 'Karys', + 'Charolette', + 'Orly', + 'Jennipher', + 'Kimbra', + 'Krislynn', + 'Kenlie', + 'Karrington', + 'Kambry', + 'Alasia', + 'Carletta', + 'Maija', + 'Nadirah', + 'Gladyce', + 'Shevy', + 'Jalessa', + 'Mushka', + 'Cyre', + 'Mabry', + 'Arihanna', + 'Brithany', + 'Ilianna', + 'Jozlynn', + 'Zandra', + 'Serinity', + 'Passion', + 'Lacresha', + 'Jeraldine', + 'Henriette', + 'Elenore', + 'Nastassia', + 'Ruchel', + 'Amal', + 'Madina', + 'Rosaline', + 'Liyana', + 'Pasqualina', + 'Keyra', + 'Kaycie', + 'Lyanna', + 'Naina', + 'Gennesis', + 'Aarushi', + 'Lariah', + 'Jakiya', + 'Kareena', + 'Rhiana', + 'Emilly', + 'Yeimi', + 'Matsuko', + 'Makhia', + 'Alin', + 'Addisen', + 'Lanae', + 'Oceana', + 'Laquanda', + 'Coralie', + 'Arina', + 'Harini', + 'Emy', + 'Emmarose', + 'Ellyana', + 'Eila', + 'Havana', + 'Dagny', + 'Leylah', + 'Shawanna', + 'Aleenah', + 'Adalia', + 'Aaliya', + 'Zyanya', + 'Felisa', + 'Tameca', + 'Sama', + 'Ripley', + 'Nayomi', + 'Quanesha', + 'Shequita', + 'Shanik', + 'Savina', + 'Nalah', + 'Magaby', + 'Cattaleya', + 'Calla', + 'Lillia', + 'Kaida', + 'Izabell', + 'Francia', + 'Caylin', + 'Bianey', + 'Hanah', + 'Julienne', + 'Viva', + 'Xochil', + 'Staphany', + 'Rayanne', + 'Marialuisa', + 'Devina', + 'Sabryna', + 'Estefanie', + 'Dinora', + 'Clarisse', + 'Josephina', + 'Milca', + 'Anjolie', + 'Akayla', + 'Malea', + 'Mea', + 'Meghana', + 'Briceida', + 'Betsaida', + 'Roselin', + 'Anuhea', + 'Megha', + 'Azusena', + 'Nandini', + 'Prisilla', + 'Shelsy', + 'Olene', + 'Kaneisha', + 'Onalee', + 'Jadore', + 'Monteen', + 'Trudie', + 'Leisha', + 'Drucilla', + 'Tamiyah', + 'Ashante', + 'Daysha', + 'Caliyah', + 'Sabella', + 'Emoni', + 'Jakyla', + 'Reginae', + 'Anyah', + 'Kierstyn', + 'Sharleen', + 'Doretta', + 'Harlene', + 'Gerrie', + 'Zofia', + 'Albertine', + 'Bronwyn', + 'Terresa', + 'Delta', + 'Anijah', + 'Mathilde', + 'Cindie', + 'Dalene', + 'Cyndee', + 'Eulah', + 'Ayako', + 'Beverlee', + 'Nicholle', + 'Kaitlan', + 'Yeraldin', + 'Tawney', + 'Tawnee', + 'Britteny', + 'Alishia', + 'Shireen', + 'Byanca', + 'Rebekka', + 'Annel', + 'Krizia', + 'Kerstin', + 'Shera', + 'Uyen', + 'Ligia', + 'Dallana', + 'Itsel', + 'Karine', + 'Sharmaine', + 'Noely', + 'Marrisa', + 'Karah', + 'Rayann', + 'Oksana', + 'Stephannie', + 'Brynne', + 'Alixandra', + 'Dyana', + 'Emilce', + 'Delmy', + 'Jamee', + 'Caitlan', + 'Marily', + 'Kiani', + 'Jennafer', + 'Nissa', + 'Jenell', + 'Jennette', + 'Marquitta', + 'Chimene', + 'Justyna', + 'Jenette', + 'Cassy', + 'Temika', + 'Katrice', + 'Brandis', + 'Consuela', + 'Chavon', + 'Angella', + 'Shantrell', + 'Christiane', + 'Shenna', + 'Donia', + 'Angelise', + 'Janyah', + 'Damiyah', + 'Luzmaria', + 'Meghna', + 'Natally', + 'Nerissa', + 'Kaori', + 'Laya', + 'Analyssa', + 'Teya', + 'Alizon', + 'Jasline', + 'Lavette', + 'Emmi', + 'Kamisha', + 'Taleah', + 'Shenita', + 'Kaytlynn', + 'Azariyah', + 'Dominica', + 'Malvina', + 'Skyy', + 'Shondra', + 'Lorina', + 'Donielle', + 'Kaisley', + 'Katalyna', + 'Jesslynn', + 'Yasmina', + 'Glada', + 'Maliha', + 'Irina', + 'Hiba', + 'Trinette', + 'Oona', + 'Aleeza', + 'Arisha', + 'Janean', + 'Cristie', + 'Syd', + 'Lavona', + 'Kennia', + 'Kyanna', + 'Lovenia', + 'Julieanne', + 'Launa', + 'Taunya', + 'Tytianna', + 'Becca', + 'Deonna', + 'Jihan', + 'Jomaira', + 'Shantay', + 'Talitha', + 'Shyra', + 'Alverna', + 'Chere', + 'Kamela', + 'Phaedra', + 'Stacee', + 'Gretta', + 'Kathyrn', + 'Shalee', + 'Beautiful', + 'Lissett', + 'Georgann', + 'Corrin', + 'Chelsa', + 'Cera', + 'Layna', + 'Lizanne', + 'Mariellen', + 'Lashandra', + 'Sophya', + 'Shruti', + 'Janea', + 'Rheta', + 'Jezebel', + 'Alizee', + 'Delaila', + 'Dayani', + 'Arieanna', + 'Amarah', + 'Janyia', + 'Makalah', + 'Dorie', + 'Tynisha', + 'Tran', + 'Prisma', + 'Shirin', + 'Tonette', + 'Suzi', + 'Alajah', + 'Lurline', + 'Adelia', + 'Tani', + 'Cassey', + 'Maha', + 'Cheyann', + 'Keyona', + 'Yezenia', + 'Vaness', + 'Stephine', + 'Cyndie', + 'Jaylanie', + 'Jeannemarie', + 'Mammie', + 'Sherice', + 'Delynn', + 'Aoife', + 'Kadiatou', + 'Sherese', + 'Trenyce', + 'Anaiz', + 'Anaiza', + 'Dajanae', + 'Lisaann', + 'Keiko', + 'Martiza', + 'Elysa', + 'Petrina', + 'Dierdre', + 'Davida', + 'Falyn', + 'Briona', + 'Maryjean', + 'Lanisha', + 'Marlenne', + 'Nawal', + 'Ethelene', + 'Alya', + 'Ariannah', + 'Jacinta', + 'Alaia', + 'Sindee', + 'Jalaya', + 'Mellanie', + 'Lasya', + 'Kyrah', + 'Mirabella', + 'Renay', + 'Seren', + 'Hiliana', + 'Kinzie', + 'Isra', + 'Hanan', + 'Kaleia', + 'Melynda', + 'Marine', + 'Twanna', + 'Lekisha', + 'Jamecia', + 'Penney', + 'Tiwanna', + 'Rylea', + 'Shekinah', + 'Mckenzi', + 'Abigael', + 'Patrizia', + 'Jamillah', + 'Caris', + 'Karmyn', + 'Kyli', + 'Princessa', + 'Sakinah', + 'Deserae', + 'Patrina', + 'Carmelina', + 'Mayela', + 'Sherise', + 'Ilda', + 'Florentina', + 'Nelwyn', + 'Jennine', + 'Aleeya', + 'Kynsley', + 'Arlett', + 'Tarra', + 'Lakyn', + 'Tyeisha', + 'Temima', + 'Mallori', + 'Ingeborg', + 'Elizaveta', + 'Jentry', + 'Kymber', + 'Maddisyn', + 'Allana', + 'Anistyn', + 'Emberlynn', + 'Faithlynn', + 'Arianah', + 'Tionna', + 'Lenda', + 'Laveta', + 'Alayla', + 'Aisling', + 'Miryam', + 'Marena', + 'Aneta', + 'Yzabella', + 'Mihika', + 'Raine', + 'Samiah', + 'Raveena', + 'Elfrieda', + 'Niccole', + 'Tatanisha', + 'Medha', + 'Katharina', + 'Jazmen', + 'Cally', + 'Louanne', + 'Caress', + 'Naylea', + 'Avarie', + 'Madelynne', + 'Dayla', + 'Shanterria', + 'Tesha', + 'Thanya', + 'Jalia', + 'Josalyn', + 'Ailey', + 'Brooklynne', + 'Dodie', + 'Champagne', + 'Taneka', + 'Tenesha', + 'Tinisha', + 'Deeanna', + 'Shelvia', + 'Chenoa', + 'Darcel', + 'Kailea', + 'Jatziry', + 'Merryl', + 'Sharlyn', + 'Harolyn', + 'Rilla', + 'Ayisha', + 'Jacklynn', + 'Chloee', + 'Makynzie', + 'Leyah', + 'Aalyiah', + 'Tynlee', + 'Statia', + 'Tyronda', + 'Tsuyako', + 'Casimira', + 'Kehaulani', + 'Ragan', + 'Lorissa', + 'Abelina', + 'Cuca', + 'Sachi', + 'Evany', + 'Elektra', + 'Sianni', + 'Raychel', + 'Natassia', + 'Vermell', + 'Sharifa', + 'Everley', + 'Ivanka', + 'Arisbeth', + 'Aleyza', + 'Bay', + 'Deedra', + 'Zarina', + 'Regena', + 'Kitana', + 'Latoshia', + 'Virgia', + 'Aili', + 'Breslyn', + 'Ishika', + 'Jhoana', + 'Dorrace', + 'Chanice', + 'Sheniqua', + 'Tashana', + 'Joetta', + 'Sanya', + 'Altamese', + 'Pari', + 'Niah', + 'Ysabelle', + 'Lisseth', + 'Parisa', + 'Aislin', + 'Leiah', + 'Atziri', + 'Anvita', + 'Jaydah', + 'Gabby', + 'Ashia', + 'Dymond', + 'Marah', + 'Uniqua', + 'Blimie', + 'Anny', + 'Dalinda', + 'Wauneta', + 'Gionna', + 'Rabia', + 'Jayanna', + 'Anica', + 'Maybell', + 'Kathern', + 'Amrita', + 'Mayerli', + 'Irais', + 'Kemberly', + 'Vena', + 'Kamri', + 'Destine', + 'Adreanna', + 'Seleste', + 'Claretha', + 'Brynnlee', + 'Anquette', + 'Komal', + 'Lysette', + 'Michayla', + 'Zamya', + 'Sierrah', + 'Felica', + 'Otelia', + 'Rihana', + 'Doloris', + 'Alanie', + 'Angelly', + 'Kassandr', + 'Rosemari', + 'Shaday', + 'Annemari', + 'Marlana', + 'Clorinda', + 'Oneida', + 'Shaunta', + 'Alexcia', + 'Takesha', + 'Amiracle', + 'Sharion', + 'Joline', + 'Jaziyah', + 'Teal', + 'Sueann', + 'Sora', + 'Kamiah', + 'Caressa', + 'Eleana', + 'Bernetha', + 'Alexyss', + 'Sharda', + 'Aishwarya', + 'Suhaill', + 'Radhika', + 'Wonda', + 'Renda', + 'Janny', + 'Ardelle', + 'Malory', + 'Jossie', + 'Anaid', + 'Mitsuye', + 'Shizuye', + 'Fariha', + 'Aiesha', + 'Nitya', + 'Nadiya', + 'Katerin', + 'Bruna', + 'Varsha', + 'Yaretsi', + 'Xitlalli', + 'Leshia', + 'Eda', + 'Sheronda', + 'Malikah', + 'Tayah', + 'Briann', + 'Tasnim', + 'Jayonna', + 'Kenedy', + 'Anarosa', + 'Zaya', + 'Kerline', + 'Brinda', + 'Amna', + 'Desarae', + 'Sarrah', + 'Silva', + 'Steffani', + 'Almarosa', + 'Alyshia', + 'Ariell', + 'Breeanne', + 'Alyxandra', + 'Juliane', + 'Jesseca', + 'Janisha', + 'Donisha', + 'Darnisha', + 'Jakeria', + 'Kirsty', + 'Markeisha', + 'Breena', + 'Selin', + 'Nikisha', + 'Adreana', + 'Elois', + 'Arrianna', + 'Melenie', + 'Rayanna', + 'Kaelee', + 'Shakyra', + 'Clotee', + 'Jakeline', + 'Kalysta', + 'Cesia', + 'Ankita', + 'Cristela', + 'Shunta', + 'Mozella', + 'Chrissie', + 'Adora', + 'Ashanty', + 'Ashna', + 'Lehua', + 'Nohealani', + 'Shruthi', + 'Metzli', + 'Jakelin', + 'Jisel', + 'Mikenna', + 'Miroslava', + 'Mansi', + 'Daphney', + 'Amisha', + 'Adara', + 'Alexzandria', + 'Alliah', + 'Yuriana', + 'Nanea', + 'Kahealani', + 'Ritika', + 'Arica', + 'Amayrani', + 'Kealani', + 'Dorina', + 'Lucienne', + 'Estrellita', + 'Kimberlin', + 'Lai', + 'Yovanna', + 'Rebekkah', + 'Azra', + 'Nada', + 'Gabryella', + 'Avigayil', + 'Binta', + 'Devoiry', + 'Raeanna', + 'Arlena', + 'Briauna', + 'Itati', + 'Grabiela', + 'Noella', + 'Teaghan', + 'Tzippy', + 'Faiza', + 'Zaara', + 'Tehilla', + 'Miki', + 'Sendy', + 'Kassondra', + 'Katherina', + 'Lissete', + 'Livier', + 'Lauran', + 'Dandrea', + 'Chelse', + 'Lizmarie', + 'Sunday', + 'Haidee', + 'Carrissa', + 'Nicholette', + 'Katey', + 'Katheryne', + 'Katty', + 'Kimia', + 'Leeanne', + 'Lizmary', + 'Jani', + 'Emmanuella', + 'Jahniya', + 'Talar', + 'Sintia', + 'Narda', + 'Chriselda', + 'Candance', + 'Delorise', + 'Daysy', + 'Lusine', + 'Raeanne', + 'Cherylann', + 'Ayat', + 'Halima', + 'Zissel', + 'Courtni', + 'Adahli', + 'Der', + 'Emree', + 'Brynlie', + 'Cherlyn', + 'Bostyn', + 'Francie', + 'Oaklie', + 'Shakeerah', + 'Hertha', + 'Haneefah', + 'Taheerah', + 'Nikkia', + 'Sheryll', + 'Donnabelle', + 'Teddi', + 'Jodee', + 'Tammera', + 'Janylah', + 'Laquesha', + 'Penina', + 'Gracee', + 'Thomasine', + 'Janyce', + 'Randie', + 'Mela', + 'Alka', + 'Cordia', + 'Shaquetta', + 'Mi', + 'Jaquetta', + 'Yoshiye', + 'Haruye', + 'Yoneko', + 'Fumi', + 'Wava', + 'Congetta', + 'Denee', + 'Kandyce', + 'Soraida', + 'Triana', + 'Kenedi', + 'Abena', + 'Talisha', + 'Rochell', + 'Sharisse', + 'Tijuana', + 'Amiee', + 'Nyesha', + 'Towana', + 'Lore', + 'Melodye', + 'Hayli', + 'Joyelle', + 'Shareen', + 'Amarilis', + 'Takiyah', + 'Takiya', + 'Keysha', + 'Feige', + 'Diahann', + 'Kloie', + 'Laynee', + 'Mariely', + 'Rainey', + 'Alizabeth', + 'Alyssandra', + 'Cambry', + 'Jadelynn', + 'Marylynn', + 'Keoka', + 'Jamaica', + 'Lus', + 'Shonta', + 'Kameelah', + 'Danell', + 'Evamarie', + 'Francoise', + 'Beata', + 'Caylie', + 'Elexa', + 'Joscelin', + 'Hessie', + 'Alazay', + 'Robena', + 'Texie', + 'Clarine', + 'Makennah', + 'Arletha', + 'Willette', + 'Amee', + 'Jetaun', + 'Anyia', + 'Aryssa', + 'Bonni', + 'Graciella', + 'Haileigh', + 'Sharae', + 'Shanea', + 'Ieisha', + 'Porche', + 'Teanna', + 'Ashanta', + 'Taiya', + 'Nicolett', + 'Naisha', + 'Sharice', + 'Madelein', + 'Kimberle', + 'Monifah', + 'Cameo', + 'Evelynne', + 'Edlyn', + 'Porcha', + 'Maricel', + 'Waleska', + 'Shakeena', + 'Shavone', + 'Ashlynne', + 'Yahira', + 'Shamecca', + 'Yashira', + 'Sherell', + 'Fiorela', + 'Nansi', + 'Shawntae', + 'Poonam', + 'Shala', + 'Kellyn', + 'Jazzmyn', + 'Asya', + 'Shatoya', + 'Yury', + 'Weronika', + 'Dawnette', + 'Lorita', + 'Michaelle', + 'Tomi', + 'Abbi', + 'Maudry', + 'Jaylinn', + 'Kynzie', + 'Lynnlee', + 'Madisson', + 'Denese', + 'Devona', + 'Sharika', + 'Sharilyn', + 'Zayna', + 'Janalee', + 'Sherril', + 'Timika', + 'Lynelle', + 'Rolayne', + 'Lubertha', + 'Jariah', + 'Kamala', + 'Taffy', + 'Marquetta', + 'Honora', + 'Frederica', + 'Monalisa', + 'Rashonda', + 'Francene', + 'Diedra', + 'Ceara', + 'Marylouise', + 'Kenesha', + 'Aisley', + 'Donnalee', + 'Genisis', + 'Debroah', + 'Helayne', + 'Raelee', + 'Maryrose', + 'Yalonda', + 'Chyla', + 'Edelmira', + 'Roselle', + 'Alyssah', + 'Brenley', + 'Gaynelle', + 'Shelvie', + 'Mackayla', + 'Linley', + 'Allizon', + 'Alonna', + 'Kendalyn', + 'Jozlyn', + 'Gwenn', + 'Jina', + 'Zariya', + 'Rosabella', + 'Emrie', + 'Tamu', + 'Senta', + 'Myia', + 'Emberlyn', + 'Emorie', + 'Arantxa', + 'Richele', + 'Christianne', + 'Lashan', + 'Koren', + 'Buffie', + 'Ronnette', + 'Marna', + 'Tuesday', + 'Helga', + 'Emilyn', + 'Cailee', + 'Shaquilla', + 'Dyamond', + 'Gerda', + 'Mckynzie', + 'Khloie', + 'Kendyll', + 'Maryfrances', + 'Khadejah', + 'Annalie', + 'Adaya', + 'Akia', + 'Markia', + 'Iyla', + 'Kaely', + 'Rafaella', + 'Tali', + 'Sukhmani', + 'Mili', + 'Kaylanie', + 'Maribelle', + 'Zharia', + 'Georgeanne', + 'Shamekia', + 'Siyona', + 'Layah', + 'Maylani', + 'Elianah', + 'Ellena', + 'Elyanna', + 'Yanilen', + 'Jashanti', + 'Lakita', + 'Juanell', + 'Caley', + 'Annella', + 'Vinita', + 'Zakiyah', + 'Sherian', + 'Palmira', + 'Delpha', + 'Creola', + 'Veta', + 'Sheneka', + 'Ameria', + 'Keonna', + 'Nathali', + 'Vaishnavi', + 'Zurisadai', + 'Mily', + 'Aalyah', + 'Hasini', + 'Irelynn', + 'Taneshia', + 'Lashanti', + 'Shatavia', + 'Shantoria', + 'Avelina', + 'Vanya', + 'Erline', + 'Surina', + 'Maribella', + 'Julieana', + 'Jazel', + 'Kalissa', + 'Marlis', + 'Hadasa', + 'Iveth', + 'Miliani', + 'Leiana', + 'Devynn', + 'Ahtziry', + 'Shilah', + 'Sicily', + 'Ashari', + 'Yarenis', + 'Tamiah', + 'Annis', + 'Azzie', + 'Sedalia', + 'Maebell', + 'Empress', + 'Fairy', + 'Najma', + 'Loreta', + 'Suhayla', + 'Sundus', + 'Vayda', + 'Doshia', + 'Ahlam', + 'Lashondra', + 'Ryanna', + 'Lala', + 'Merline', + 'Severa', + 'Kymora', + 'Fae', + 'Jameka', + 'Othella', + 'Wyoma', + 'Ailee', + 'Aishani', + 'Fransisca', + 'Noma', + 'Meztli', + 'Miliana', + 'Navaeh', + 'Swara', + 'Malillany', + 'Jaina', + 'Dia', + 'Ivyanna', + 'Jamira', + 'Jazaria', + 'Oletha', + 'Julieth', + 'Avia', + 'Elizebeth', + 'Yareni', + 'Korra', + 'Miraya', + 'Bernetta', + 'Helyn', + 'Suhaylah', + 'Laina', + 'Lassie', + 'Anyae', + 'Maleena', + 'Nirvana', + 'Danely', + 'Keilana', + 'Hildur', + 'Mariaclara', + 'Toshie', + 'Maniyah', + 'Hanako', + 'Asako', + 'Hiroko', + 'Hisae', + 'Suraya', + 'Kaileen', + 'Pearla', + 'Layal', + 'Batoul', + 'Johannah', + 'Gizel', + 'Venecia', + 'Yanelly', + 'Atianna', + 'Apple', + 'Arizbeth', + 'Sriya', + 'Natania', + 'Mayline', + 'Emmagrace', + 'Meriam', + 'Laree', + 'Tempie', + 'Sedonia', + 'Evalee', + 'Laquana', + 'Sheli', + 'Liesl', + 'Hazeline', + 'Blanchie', + 'Samyra', + 'Keelie', + 'Krislyn', + 'Yanelis', + 'Addysen', + 'Inis', + 'Tammra', + 'Johnette', + 'Amery', + 'Alayza', + 'Alaiyah', + 'Abree', + 'Amri', + 'Anapaula', + 'Jacelynn', + 'Kenzleigh', + 'Kenzlee', + 'Jaelah', + 'Brenlee', + 'Avalee', + 'Paizley', + 'Columbia', + 'Benedetta', + 'Daeja', + 'Myeshia', + 'Jeanene', + 'Terina', + 'Ethyl', + 'Oliwia', + 'Taniah', + 'Yaiza', + 'Eveline', + 'Monnie', + 'Margherita', + 'Jayana', + 'Macil', + 'Leontine', + 'Catera', + 'Wynelle', + 'Eldana', + 'Sallyann', + 'Yolande', + 'Marybelle', + 'Leanore', + 'Clothilde', + 'Tonita', + 'Kimaya', + 'Sumayah', + 'Latrenda', + 'Kelleen', + 'Deatrice', + 'Madelon', + 'Phyliss', + 'Argelia', + 'Mellie', + 'Emmah', + 'Jorley', + 'Muna', + 'Daphine', + 'Darina', + 'Bliss', + 'Karyl', + 'Taelynn', + 'Blenda', + 'Tonika', + 'Jerrilyn', + 'Sahra', + 'Keilyn', + 'Pearlene', + 'Arrie', + 'Ellene', + 'Fredericka', + 'Ladawn', + 'Maudell', + 'Rahma', + 'Jaylie', + 'Jaidah', + 'Vernetta', + 'Aleya', + 'Aubreigh', + 'Alaysha', + 'Adena', + 'Jacara', + 'Elfriede', + 'Maysel', + 'Munira', + 'Mumtaz', + 'Dorathy', + 'Chanin', + 'Ronette', + 'Maymie', + 'Providencia', + 'Mirta', + 'Loida', + 'Blakelyn', + 'Bentleigh', + 'Alliana', + 'Aleen', + 'Daliyah', + 'Jodene', + 'Johanne', + 'Timeka', + 'Ilhan', + 'Aloma', + 'Maris', + 'Arlyne', + 'Jene', + 'Hazelene', + 'Shakela', + 'Maida', + 'Maycie', + 'Makynlee', + 'Kawanda', + 'Consuella', + 'Sephora', + 'Andrianna', + 'Joshlyn', + 'Hollyn', + 'Kyliee', + 'Adaly', + 'Dailyn', + 'Averee', + 'Berklee', + 'Marly', + 'Gianella', + 'Ekaterina', + 'Colene', + 'Dayonna', + 'Shareka', + 'Roshni', + 'Latifa', + 'Merilyn', + 'Vernelle', + 'Marlyce', + 'Sabrena', + 'Jeneen', + 'Genie', + 'Lawanna', + 'Tashara', + 'Kayzlee', + 'Skylie', + 'Iyonna', + 'Honesti', + 'Cherylene', + 'Tahira', + 'Chizuko', + 'Aneesah', + 'Helmi', + 'Katrena', + 'Shyanna', + 'Zeola', + 'Lempi', + 'Arliss', + 'Madgie', + 'Verlie', + 'Ardys', + 'Twanda', + 'Kareemah', + 'Chardae', + 'Arlinda', + 'Darlena', + 'Karee', + 'Lorry', + 'Rolande', + 'Marlane', + 'Lelah', + 'Zahria', + 'Michalene', + 'Nayelis', + 'Abbigale', + 'Lorretta', + 'Sheril', + 'Priscille', + 'Cleda', + 'Kerrigan', + 'Wanita', + 'Ambria', + 'Wanetta', + 'Ebone', + 'Georgianne', + 'Karleen', + 'Laural', + 'Jonette', + 'Sharie', + 'Francina', + 'Yarelis', + 'Tempestt', + 'Kamie', + 'Julene', + 'Londa', + 'Haniya', + 'Kristeen', + 'Classie', + 'Nakiyah', + 'Valinda', + 'Kamree', + 'Micheline', + 'Mckaylee', + 'Prescilla', + 'Shaylynn', + 'Donelda', + 'Fayetta', + 'Terrye', + 'Dorthey', + 'Azilee', + 'Juanda', + 'Eustolia', + 'Nakeisha', + 'Hira', + 'Tarrah', + 'Jamyra', + 'Azaleah', + 'Aveline', + 'Chanae', + 'Andreana', + 'Banesa', + 'Berenis', + 'Brittini', + 'Orianna', + 'Reet', + 'Rayah', + 'Sofi', + 'Japji', + 'Kensie', + 'Roshonda', + 'Agripina', + 'Blasa', + 'Anevay', + 'Akari', + 'Krissi', + 'Maily', + 'Kitzia', + 'Keilly', + 'Raveen', + 'Kaiah', + 'Juliett', + 'Jocelynne', + 'Eowyn', + 'Calie', + 'Ebonee', + 'Chelcie', + 'Kayci', + 'Lauralee', + 'Trenity', + 'Deborrah', + 'Imagene', + 'Akasha', + 'Analaura', + 'Liani', + 'Lizania', + 'Lucina', + 'Melaine', + 'Sanah', + 'Stepanie', + 'Zabrina', + 'Janaye', + 'Jelena', + 'Kaylina', + 'Diavian', + 'Tasnia', + 'Nusrat', + 'Ashleymarie', + 'Maheen', + 'Ndeye', + 'Yumi', + 'Vittoria', + 'Amyra', + 'Yakelin', + 'Yudith', + 'Yumalay', + 'Juliza', + 'Daila', + 'Daenerys', + 'Calissa', + 'Tahirah', + 'Laquasia', + 'Jenay', + 'Crystina', + 'Eleonore', + 'Inessa', + 'Irine', + 'Vennie', + 'Oda', + 'Laurine', + 'Lavera', + 'Saraya', + 'Kerin', + 'Itzia', + 'Jennessa', + 'Katerine', + 'Rosselyn', + 'Leidy', + 'Adamariz', + 'Adylene', + 'Aylen', + 'Aniela', + 'Aleesha', + 'Alyssamarie', + 'Ainara', + 'Emalie', + 'Darlin', + 'Inna', + 'Emmely', + 'Eriana', + 'Esbeidy', + 'Chenelle', + 'Janise', + 'Sherrell', + 'Basilia', + 'Malayna', + 'Hilinai', + 'Mardell', + 'Romi', + 'Rosena', + 'Violett', + 'Zaylah', + 'Taia', + 'Anisah', + 'Esli', + 'Cleopatra', + 'Carisma', + 'Dezaray', + 'Swayze', + 'Raeven', + 'Neiva', + 'Myeisha', + 'Shelsea', + 'Yissel', + 'Velinda', + 'Josseline', + 'Denasia', + 'Digna', + 'Keiana', + 'Clytee', + 'Vernette', + 'Cheyene', + 'Roshunda', + 'Telisha', + 'Nilah', + 'Ayda', + 'Zykia', + 'Isabellamarie', + 'Melanee', + 'Laylanie', + 'Ajah', + 'Guiliana', + 'Oliva', + 'Mikela', + 'Mirabelle', + 'Nabiha', + 'Jasmina', + 'Hendy', + 'Ita', + 'Elif', + 'Reola', + 'Jamyah', + 'Tempest', + 'Arletta', + 'Keaira', + 'Ibeth', + 'Jerolyn', + 'Nelta', + 'Alishba', + 'Crisol', + 'Sabreena', + 'Silver', + 'Toba', + 'Yunuen', + 'Rishika', + 'Naomie', + 'Brittanya', + 'Annasophia', + 'Ayumi', + 'Jayleene', + 'Emmily', + 'Lyssa', + 'Natoya', + 'Vallerie', + 'Andee', + 'Annastasia', + 'Mazzy', + 'Zinnia', + 'Sheran', + 'Sumaiya', + 'Tasneem', + 'Aniylah', + 'Dua', + 'Tausha', + 'Jabria', + 'Lanora', + 'Janeli', + 'Mileydi', + 'Mikaella', + 'Ryah', + 'Rolonda', + 'Ajanae', + 'Ianna', + 'Xaria', + 'Winni', + 'Marializ', + 'Aidel', + 'Jonae', + 'Sanam', + 'Mao', + 'Tesia', + 'Yanina', + 'Brieana', + 'Genova', + 'Lashanae', + 'Anneke', + 'Siarra', + 'Sharhonda', + 'Zeldy', + 'Saron', + 'Johnisha', + 'Katelynne', + 'Janneth', + 'Corayma', + 'Helvi', + 'Asucena', + 'Lachelle', + 'Solmayra', + 'Tavia', + 'Marlina', + 'Rachal', + 'Sunni', + 'Nycole', + 'Aliannah', + 'Nafisa', + 'Simi', + 'Suki', + 'Jadalynn', + 'Kezia', + 'Athziri', + 'Huda', + 'Evy', + 'Jailah', + 'Jaselle', + 'Jaslyne', + 'Dalyla', + 'Emeraude', + 'Mahika', + 'Yoanna', + 'Fraida', + 'Tannia', + 'Selenne', + 'Analiz', + 'Angelene', + 'Anacristina', + 'Kylea', + 'Naydelyn', + 'Lecia', + 'Gitel', + 'Shareese', + 'Cassady', + 'Diem', + 'Perlita', + 'Monigue', + 'Marisha', + 'Emillee', + 'Kareli', + 'Shandreka', + 'Kerrin', + 'Tram', + 'Nohelani', + 'Monic', + 'Brandice', + 'Johnetta', + 'Evangelia', + 'Shakina', + 'Shunda', + 'Robbi', + 'Ariatna', + 'Shantae', + 'Sorangel', + 'Valene', + 'Aletta', + 'Libbie', + 'Marifer', + 'Deitra', + 'Despina', + 'Hayle', + 'Kassidi', + 'Dayrin', + 'Anjelina', + 'Gimena', + 'Llesenia', + 'Rainbow', + 'Muskaan', + 'Judit', + 'Kyley', + 'Tanna', + 'Luci', + 'Altagracia', + 'Kilee', + 'Kamry', + 'Kalyssa', + 'Jadeyn', + 'Virgen', + 'Damita', + 'Leinaala', + 'Illeana', + 'Nneka', + 'Onika', + 'Aralyn', + 'Mahalia', + 'Marelyn', + 'Jalene', + 'Bobbiejo', + 'Apollonia', + 'Anjuli', + 'Ricarda', + 'Fusako', + 'Michie', + 'Janira', + 'Citlalic', + 'Jannelle', + 'Tiffini', + 'Elisia', + 'Racine', + 'Marybel', + 'Xitlally', + 'Tynesha', + 'Sharay', + 'Shamara', + 'Aleene', + 'Rayssa', + 'Carlyn', + 'Falisha', + 'Lasandra', + 'Trinh', + 'Seema', + 'Tonianne', + 'Destani', + 'Nairobi', + 'Tomica', + 'Raena', + 'Ivania', + 'Odaliz', + 'Lilybeth', + 'Sheyenne', + 'Tereza', + 'Yuka', + 'Baleria', + 'Ayiana', + 'Floree', + 'Jhoanna', + 'Shakila', + 'Meleah', + 'Monserath', + 'Lelani', + 'Conception', + 'Zowie', + 'Teah', + 'Takayla', + 'Teaira', + 'Karyssa', + 'Delina', + 'Kamaile', + 'Rut', + 'Reanne', + 'Zamantha', + 'Ellyse', + 'Jisela', + 'Latonja', + 'Eiko', + 'Aylene', + 'Atziry', + 'Avila', + 'Andreya', + 'Delyla', + 'Aashna', + 'Dacia', + 'Shavonda', + 'Desirey', + 'Matea', + 'Makailah', + 'Henessy', + 'Naliyah', + 'Charlise', + 'Keirsten', + 'Ressie', + 'Halia', + 'Gweneth', + 'Manda', + 'Lilinoe', + 'Mariselda', + 'Tajuana', + 'Mahima', + 'Noeli', + 'Yanelli', + 'Sole', + 'Saloni', + 'Annistyn', + 'Marcille', + 'Thresa', + 'Cerenity', + 'Samnatha', + 'Alexah', + 'Analie', + 'Aryah', + 'Jazline', + 'Evony', + 'Erandy', + 'Jezelle', + 'Kamara', + 'Emelina', + 'Kadance', + 'Masae', + 'Davonna', + 'Shamaya', + 'Shalynn', + 'Rima', + 'Toria', + 'Zamira', + 'Cerina', + 'Fujiko', + 'Armine', + 'Morganne', + 'Gicela', + 'Desree', + 'Khaila', + 'Nikayla', + 'Kennedie', + 'Marylu', + 'Ilyssa', + 'Jatziri', + 'Shianna', + 'Dharma', + 'Resa', + 'Abra', + 'Neely', + 'Imo', + 'Betzabeth', + 'Briceyda', + 'Karenna', + 'Jakhia', + 'Ramiyah', + 'Khaliyah', + 'Tocarra', + 'Milee', + 'Athina', + 'Maleigha', + 'Shalyn', + 'Syliva', + 'Roseline', + 'Claira', + 'Jisselle', + 'Kiely', + 'Marisabel', + 'Maryanna', + 'Melena', + 'Mylene', + 'Mariangela', + 'Mailey', + 'Sonora', + 'Siana', + 'Shreeya', + 'Sevana', + 'Samhita', + 'Jackelyne', + 'Kyrstin', + 'Anslie', + 'Samella', + 'Jewelia', + 'Sammye', + 'Ayline', + 'Navneet', + 'Charlesetta', + 'Raye', + 'Yulonda', + 'Esmerelda', + 'Gianina', + 'Danessa', + 'Calia', + 'Everlena', + 'Sadaf', + 'Analucia', + 'Meriah', + 'Gwendalyn', + 'Disha', + 'Katana', + 'Kalaya', + 'Kaeley', + 'Tyonna', + 'Rozella', + 'Marjean', + 'Conchita', + 'Kylynn', + 'Aasiyah', + 'Maelynn', + 'Kahla', + 'Prachi', + 'Tajanae', + 'Megumi', + 'Micheala', + 'Yanitza', + 'Geselle', + 'Reather', + 'Annalicia', + 'Bonna', + 'Lilliann', + 'Callia', + 'Brigit', + 'Quintina', + 'Fujie', + 'Jolanda', + 'Nanami', + 'Yosselin', + 'Jakelyn', + 'Kadeja', + 'Eveny', + 'Emaly', + 'Ciena', + 'Julliana', + 'Jareli', + 'Jaretzi', + 'Kailin', + 'Kimiye', + 'Ammie', + 'Kiona', + 'Sumayyah', + 'Terre', + 'Laryssa', + 'Marleni', + 'Kamira', + 'Yulanda', + 'Jonda', + 'Lania', + 'Pippa', + 'Jazariah', + 'Takeya', + 'Shatima', + 'Ysenia', + 'Mikki', + 'Necole', + 'Etha', + 'Williemae', + 'Margurite', + 'Leonarda', + 'Inocencia', + 'Dominika', + 'Laisa', + 'Haylea', + 'Annamay', + 'Azia', + 'Mckynlee', + 'Maddilyn', + 'Scotlyn', + 'Lillith', + 'Mertie', + 'Kynzee', + 'Joshlynn', + 'Maelee', + 'Daleiza', + 'Xyla', + 'Royalty', + 'Railynn', + 'Patrycja', + 'Dotty', + 'Leda', + 'Toshiba', + 'Nelma', + 'Yeni', + 'Ottilie', + 'Lyna', + 'Leslieann', + 'Onita', + 'Darcey', + 'Marya', + 'Africa', + 'Seferina', + 'Theola', + 'Ysidra', + 'Zita', + 'Cing', + 'Zailynn', + 'Jennilee', + 'Sharmon', + 'Tyechia', + 'Irmgard', + 'Shameika', + 'Jemima', + 'Jazzelle', + 'Adlee', + 'Aliyanna', + 'Acelyn', + 'Catalaya', + 'Brileigh', + 'Braylie', + 'Angelin', + 'Arianni', + 'Ariani', + 'Kennya', + 'Maelyn', + 'Lillee', + 'Maripaz', + 'Laikyn', + 'Kenslee', + 'Ileane', + 'Puja', + 'Oanh', + 'Jakara', + 'Shawntay', + 'Cendy', + 'Erianna', + 'Chloie', + 'Birtie', + 'Korin', + 'Jannett', + 'Shawntel', + 'Markisha', + 'Nastassja', + 'Shalene', + 'Alexya', + 'Cloie', + 'Exa', + 'Jentri', + 'Modena', + 'Veronique', + 'Daina', + 'Mechele', + 'Lakesia', + 'Kawanna', + 'Clotilde', + 'Diamonique', + 'Teyana', + 'Rheagan', + 'Shanece', + 'Yanique', + 'Taysha', + 'Ulyssa', + 'Jadzia', + 'Kadija', + 'Towanna', + 'Lurlene', + 'Sharri', + 'Rosenda', + 'Daphna', + 'Hermina', + 'Shaquanda', + 'Saachi', + 'Sena', + 'Yazaira', + 'Yatzil', + 'Anam', + 'Sparrow', + 'Anetra', + 'Nalayah', + 'Jaylenne', + 'Joya', + 'Kensi', + 'Khylee', + 'Lilyrose', + 'Iasia', + 'Jaliah', + 'Melda', + 'Armella', + 'Zyasia', + 'Nazia', + 'Shanasia', + 'Krystie', + 'Dorothe', + 'Thora', + 'Adelene', + 'Avaya', + 'Aurielle', + 'Ailany', + 'Andromeda', + 'Loa', + 'Cleora', + 'Darling', + 'Caliana', + 'Keniyah', + 'Crystel', + 'Dimitra', + 'Renate', + 'Zyriah', + 'Taegan', + 'Marygrace', + 'Mckinzie', + 'Nivea', + 'Rhian', + 'Amarissa', + 'Kadee', + 'Devani', + 'Khara', + 'Aishia', + 'Annell', + 'Jaslin', + 'Jaide', + 'Briahna', + 'Merary', + 'Lauraine', + 'Tywana', + 'Athanasia', + 'Chantay', + 'Loretha', + 'Anyiah', + 'Marvine', + 'Jennelle', + 'Hiedi', + 'Sunnie', + 'Panagiota', + 'Lanesha', + 'Amity', + 'Denyse', + 'Nataleigh', + 'Amyia', + 'Avrie', + 'Analysa', + 'Ameris', + 'Ambrielle', + 'Kynnedy', + 'Gracy', + 'Kaelie', + 'Heydi', + 'Latrese', + 'Lavonia', + 'Latrelle', + 'Lynetta', + 'Graceann', + 'Susette', + 'Sarabeth', + 'Arnetta', + 'Shelonda', + 'Myiesha', + 'Shila', + 'Pascale', + 'Zenja', + 'Madelene', + 'Lalena', + 'Doria', + 'Dagmar', + 'Griselle', + 'Nitza', + 'Moraima', + 'Miguelina', + 'Brittania', + 'Emmalin', + 'Novie', + 'Chavonne', + 'Lashana', + 'Quyen', + 'Gennifer', + 'Zaryah', + 'Paytin', + 'Keeli', + 'Kolbi', + 'Maddyson', + 'Jackqueline', + 'Arnita', + 'Brynnley', + 'Edelyn', + 'Arial', + 'Yaneliz', + 'Ena', + 'Barbaraann', + 'Glendora', + 'Heavyn', + 'Neomi', + 'Rebbecca', + 'Laketa', + 'Renetta', + 'Carline', + 'Nezzie', + 'Shaneeka', + 'Desaray', + 'Hiromy', + 'Hallee', + 'Halli', + 'Sheba', + 'Tahisha', + 'Paetyn', + 'Katisha', + 'Joyell', + 'Joyel', + 'Zoei', + 'Zamiya', + 'Raygan', + 'Clydie', + 'Missouri', + 'Debany', + 'Kalisha', + 'Niurka', + 'Beverlyn', + 'Bell', + 'Zuly', + 'Lakayla', + 'Lainee', + 'Kynli', + 'Lundyn', + 'Erynn', + 'Braleigh', + 'Allena', + 'Lashanna', + 'Shaunya', + 'Tykia', + 'Leeba', + 'Bassheva', + 'Kandra', + 'Breyana', + 'Geovana', + 'Joandra', + 'Jessyka', + 'Analilia', + 'Charna', + 'Josefita', + 'Laurin', + 'Casi', + 'Jeniah', + 'Koraima', + 'Vivi', + 'Merlina', + 'Marinna', + 'Soriya', + 'Sarayu', + 'Ma', + 'Adali', + 'Abbygale', + 'Avonlea', + 'Bellah', + 'Makeyla', + 'Maanya', + 'Hania', + 'Ellah', + 'Esmee', + 'Jaylean', + 'Verlene', + 'Kendria', + 'Kasondra', + 'Kadesha', + 'Kadedra', + 'Reizel', + 'Reizy', + 'Sheryle', + 'Elka', + 'Caileigh', + 'Meya', + 'Rondi', + 'Janetta', + 'Dwana', + 'Yakira', + 'Donetta', + 'Laurissa', + 'Jordann', + 'Jenice', + 'Hasmik', + 'Mychelle', + 'Shabnam', + 'Sarahann', + 'Shaylene', + 'Zuleica', + 'Verenise', + 'Dejanee', + 'Alyx', + 'Breyanna', + 'Anum', + 'Jamesia', + 'Asheley', + 'Keya', + 'Lyzette', + 'Rossy', + 'Terilyn', + 'Rahaf', + 'Anabia', + 'Neala', + 'Payal', + 'Taheera', + 'Nakhia', + 'Shaela', + 'Krupa', + 'Suriya', + 'Victory', + 'Viviane', + 'Habiba', + 'Fortune', + 'Farida', + 'Erina', + 'Ranya', + 'Tifani', + 'Surie', + 'Aastha', + 'Joella', + 'Sherida', + 'Vonnie', + 'Bluma', + 'Gianny', + 'Naziyah', + 'Taylie', + 'Jakia', + 'Timia', + 'Farren', + 'Skylin', + 'Sabiha', + 'Nashley', + 'Blimi', + 'Annita', + 'Kristianna', + 'Delena', + 'Dalina', + 'Kyasia', + 'Cathlene', + 'Karalee', + 'Merilee', + 'Monette', + 'Asharia', + 'Jacquelina', + 'Nishat', + 'Charlcie', + 'Sukanya', + 'Celines', + 'Rashell', + 'Nadja', + 'Lamiyah', + 'Najae', + 'Zipporah', + 'Rawan', + 'Tailor', + 'Denesha', + 'Masiel', + 'Nida', + 'Assata', + 'Infiniti', + 'Cresencia', + 'Omega', + 'Meher', + 'Maneh', + 'Noura', + 'Yanine', + 'Maral', + 'Malori', + 'Safia', + 'Saori', + 'Vesper', + 'Audrinna', + 'Dea', + 'Kahlia', + 'Eliora', + 'Isley', + 'Laurinda', + 'Mignon', + 'Debie', + 'Denette', + 'Jolyn', + 'Casondra', + 'Donnisha', + 'Elysse', + 'Lazaria', + 'Aleia', + 'Shelbee', + 'Ivone', + 'Mazal', + 'Sherley', + 'Shantia', + 'Christelle', + 'Tatjana', + 'Roselia', + 'Pebbles', + 'Cleotilde', + 'Erendida', + 'Chardonnay', + 'Brittiny', + 'Brittanny', + 'Scarleth', + 'Mehar', + 'Neila', + 'Sofiya', + 'Lakshmi', + 'Lilianne', + 'Akeiba', + 'Shabreka', + 'Joannie', + 'Samiha', + 'Fatma', + 'Itzell', + 'Envy', + 'Maybelline', + 'Nashly', + 'Rya', + 'Kaelani', + 'Kailana', + 'Aylah', + 'Bellamarie', + 'Marizol', + 'Malyssa', + 'Madai', + 'Neelam', + 'Ysamar', + 'Sulma', + 'Sueling', + 'Song', + 'Sharayah', + 'Melisha', + 'Ashliegh', + 'Melodi', + 'Belem', + 'Chrystina', + 'Tonantzin', + 'Setareh', + 'Valeri', + 'Yaffa', + 'Niara', + 'Mame', + 'Janasia', + 'Flo', + 'Gustavia', + 'Lanya', + 'Nanie', + 'Velta', + 'Dot', + 'Luberta', + 'Ledora', + 'Olean', + 'Abbigayle', + 'Hadeel', + 'Rayma', + 'Mayola', + 'Nonnie', + 'Voncille', + 'Heloise', + 'Nolia', + 'Victorine', + 'Yola', + 'Vella', + 'Terrilyn', + 'Noelie', + 'Alean', + 'Allean', + 'Lorean', + 'Josiephine', + 'Heba', + 'Kerrianne', + 'Odeal', + 'Aigner', + 'Anaclara', + 'Gudrun', + 'Valborg', + 'Trenice', + 'Ardath', + 'Aune', + 'Teresia', + 'Lesha', + 'Dewanna', + 'Arlyce', + 'Jayliana', + 'Orene', + 'Paralee', + 'Jamyia', + 'Kemiyah', + 'Fredia', + 'Amyiah', + 'Doreatha', + 'Lashanta', + 'Cerissa', + 'Kawana', + 'Arizona', + 'Shanetta', + 'Jalesa', + 'Asmaa', + 'Garnette', + 'Clella', + 'Artemisa', + 'Liliya', + 'Oretha', + 'Adna', + 'Amyri', + 'Tyshae', + 'Maryan', + 'Santanna', + 'Bushra', + 'Jamyla', + 'Earma', + 'Delsie', + 'Verlean', + 'Sherena', + 'Carmelite', + 'Chari', + 'Darlean', + 'Shamia', + 'Audryna', + 'Genevia', + 'Avie', + 'Tamora', + 'Lavonna', + 'September', + 'Sharolyn', + 'Athziry', + 'Alyiah', + 'Aleina', + 'Alesandra', + 'Amoreena', + 'Nykia', + 'Drea', + 'Galilee', + 'Ainslie', + 'Ishita', + 'Jenavie', + 'Jezabel', + 'Erandi', + 'Evana', + 'Jiana', + 'Laniah', + 'Britanny', + 'Sanika', + 'Solash', + 'Laasya', + 'Nairi', + 'Leighla', + 'Kaiyah', + 'Suhana', + 'Taliya', + 'Maleia', + 'Candee', + 'Ninette', + 'Eugena', + 'Lateisha', + 'Salvatrice', + 'Quaneisha', + 'Mertis', + 'Bebe', + 'Rida', + 'Takyra', + 'Floye', + 'Christell', + 'Ozelle', + 'Juanice', + 'Genia', + 'Shaundra', + 'Shanin', + 'Wendee', + 'Cynde', + 'Adalynne', + 'Adelin', + 'Hayven', + 'Ayra', + 'Chimamanda', + 'Kenzlie', + 'Taylynn', + 'Zerenity', + 'Kynsleigh', + 'Dorthea', + 'Alley', + 'Melrose', + 'Keyondra', + 'Anglia', + 'Lynnea', + 'Tamira', + 'Terisa', + 'Tona', + 'Isaly', + 'Jeimy', + 'Giannah', + 'Leilanni', + 'Leya', + 'Quetzali', + 'Naylene', + 'Misaki', + 'Amely', + 'Donette', + 'Charlayne', + 'Selia', + 'Kittie', + 'Tamaya', + 'Lenna', + 'Zykerria', + 'Teisha', + 'Terrea', + 'Alita', + 'Bunny', + 'Deniece', + 'Inge', + 'Takira', + 'Monesha', + 'Mahala', + 'Donica', + 'Fortunata', + 'Valrie', + 'Zayah', + 'Ziyah', + 'Vela', + 'Vassie', + 'Omie', + 'Nadean', + 'Annalynn', + 'Adah', + 'Edmae', + 'Aalayah', + 'Yuritzy', + 'Ytzel', + 'Svetlana', + 'Soha', + 'Alfredia', + 'Kylei', + 'Landrey', + 'Lariyah', + 'Rozlyn', + 'Sakina', + 'Greer', + 'Bula', + 'Eura', + 'Harmonee', + 'Pecola', + 'Noreta', + 'Laveda', + 'Retta', + 'Rozlynn', + 'Skarlet', + 'Snow', + 'Zoha', + 'Sophiarose', + 'Anglea', + 'Itzabella', + 'Elanie', + 'Calirose', + 'Adhya', + 'Amaiyah', + 'Lavender', + 'Leylanie', + 'Kaliana', + 'Quetzaly', + 'Helon', + 'Nalia', + 'Cipriana', + 'Martyna', + 'Pola', + 'Dierra', + 'Maximina', + 'Sherica', + 'Murlene', + 'Berna', + 'Bernarda', + 'Ettie', + 'Laiken', + 'Hensley', + 'Fontella', + 'Modelle', + 'Timotea', + 'Venora', + 'Lakelyn', + 'Licia', + 'Laury', + 'Loralee', + 'Kamyah', + 'Verba', + 'Angelee', + 'Adalind', + 'Adaliz', + 'Ailynn', + 'Airi', + 'Alany', + 'Avika', + 'Avleen', + 'Leoni', + 'Saisha', + 'Savvy', + 'Philippa', + 'Jasneet', + 'Izabellah', + 'Elienai', + 'Kalayah', + 'Eureka', + 'Dionicia', + 'Zylah', + 'Zosia', + 'Yetzali', + 'Tigerlily', + 'Dorena', + 'Nakesha', + 'Lakenya', + 'Margarete', + 'Margarite', + 'Cloteal', + 'Adline', + 'Willadeen', + 'Anselma', + 'Marcheta', + 'Havyn', + 'Ilyanna', + 'Idalie', + 'Fallyn', + 'Emori', + 'Anzal', + 'Kalila', + 'Ellisyn', + 'Maddalyn', + 'Roslynn', + 'Hodan', + 'Emalynn', + 'Addy', + 'Adelyne', + 'Aizah', + 'Dalayza', + 'Cambri', + 'Annali', + 'Angelynn', + 'Caidence', + 'Auriana', + 'Azlynn', + 'Blakelee', + 'Brenleigh', + 'Tailynn', + 'Zyla', + 'Verline', + 'Pierina', + 'Panhia', + 'Valda', + 'Shela', + 'Uldine', + 'Vibha', + 'Wednesday', + 'Porshia', + 'Shabria', + 'Palmina', + 'Khristine', + 'Lannette', + 'Sandhya', + 'Janalyn', + 'Floreine', + 'Marchelle', + 'Minette', + 'Tawnia', + 'Wynne', + 'Sada', + 'Windi', + 'Clydene', + 'Shundra', + 'Joycie', + 'Delories', + 'Alvena', + 'Edmonia', + 'Denean', + 'Dhana', + 'Marjie', + 'Alicja', + 'Cammy', + 'Aryam', + 'Leonie', + 'Adrielle', + 'Felisita', + 'Tinnie', + 'Marinda', + 'Lamia', + 'Conchetta', + 'Naylah', + 'Sarayah', + 'Nataliya', + 'Delani', + 'Eknoor', + 'Ellee', + 'Maiah', + 'Mayumi', + 'Meara', + 'Kalliope', + 'Jewels', + 'Lanaya', + 'Yui', + 'Maxcine', + 'Yaqueline', + 'Yoceline', + 'Marilynne', + 'Maple', + 'Ronesha', + 'Marili', + 'Reema', + 'Rayana', + 'Aggie', + 'Talina', + 'Doristine', + 'Romelle', + 'Shaqueena', + 'Sharelle', + 'Caira', + 'Gelsey', + 'Tashawna', + 'Takeisha', + 'Jerlean', + 'Sunita', + 'Shalini', + 'Michaeline', + 'Audria', + 'Ronnisha', + 'Leonia', + 'Monna', + 'Ambra', + 'Corena', + 'Taren', + 'Alexiss', + 'Kajal', + 'Jordanne', + 'Kasia', + 'Brienna', + 'Gayane', + 'Deija', + 'Cidney', + 'Tabytha', + 'Raeleen', + 'Mkayla', + 'Harli', + 'Jassmin', + 'Ilo', + 'Lasheena', + 'Keianna', + 'Kally', + 'Makenzy', + 'Angelea', + 'Natasia', + 'Shaneequa', + 'Monay', + 'Moet', + 'Marcelline', + 'Shatia', + 'Sarafina', + 'Kaisha', + 'Tiffney', + 'Shenequa', + 'Sheretta', + 'Floria', + 'Alacia', + 'Kavita', + 'Kerianne', + 'Tameshia', + 'Jamye', + 'Shanese', + 'Latiqua', + 'Jesscia', + 'Johanny', + 'Daniqua', + 'Geneviev', + 'Bernadet', + 'Annice', + 'Megann', + 'Katee', + 'Nikeya', + 'Stavroula', + 'Tawna', + 'Sindia', + 'Marlaina', + 'Jury', + 'Tovah', + 'Shivonne', + 'Nekia', + 'Yvonnie', + 'Kyna', + 'Railey', + 'Xandria', + 'Genine', + 'Tashima', + 'Marycarmen', + 'Kiahna', + 'Jadynn', + 'Akua', + 'Eather', + 'Fatema', + 'Aiysha', + 'Allisa', + 'Ashleynicole', + 'Bobette', + 'Shandrika', + 'Hollace', + 'Chandni', + 'Cayley', + 'Brenae', + 'Areisy', + 'Annahi', + 'Anallely', + 'Klarisa', + 'Ayssa', + 'Jatavia', + 'Nohemy', + 'Mikyla', + 'Mariadelosang', + 'Shatina', + 'Kazandra', + 'Elsi', + 'Teryl', + 'Yennifer', + 'Destyni', + 'Damariz', + 'Areanna', + 'Everlean', + 'Lesslie', + 'Margrette', + 'Tuyet', + 'Jacquelene', + 'Grissel', + 'Walterine', + 'Shterna', + 'Gila', + 'Nabila', + 'Liel', + 'Sani', + 'Djeneba', + 'Angeliz', + 'Anari', + 'Amyrie', + 'Aissa', + 'Tichina', + 'Amariana', + 'Xiara', + 'Yamiles', + 'Isatou', + 'Airiana', + 'Carrigan', + 'Aldea', + 'Aarika', + 'Bryanne', + 'Alegandra', + 'Carrisa', + 'Andrina', + 'Casaundra', + 'Breanda', + 'Biviana', + 'Irena', + 'Denielle', + 'Lizzett', + 'Shaunice', + 'Sigourney', + 'Sona', + 'Paradise', + 'Lashanique', + 'Melaina', + 'Zoua', + 'Vaneza', + 'Tyresha', + 'Shyasia', + 'Tiyana', + 'Youa', + 'Zaneta', + 'Muskan', + 'Talissa', + 'Kennisha', + 'Lizandra', + 'Akosua', + 'Jaymi', + 'Chelby', + 'Chelci', + 'Aeriel', + 'Isamara', + 'Payge', + 'Hadja', + 'Fruma', + 'Fiza', + 'Fatumata', + 'Kabrina', + 'Feigy', + 'Zanaya', + 'Yanette', + 'Teairra', + 'Talor', + 'Kathrina', + 'Justeen', + 'Maryelizabeth', + 'Jannete', + 'Chantalle', + 'Haide', + 'Genelle', + 'Esthela', + 'Emilse', + 'Maegen', + 'Lyndsi', + 'Cristiana', + 'Clio', + 'Breindel', + 'Briyana', + 'Jamyria', + 'Jameshia', + 'Kadeshia', + 'Jamisha', + 'Faige', + 'Aishah', + 'Lorette', + 'Nandi', + 'Nastasia', + 'Shada', + 'Shakeia', + 'Shaneice', + 'Yanel', + 'Teryn', + 'Shaylyn', + 'Karimah', + 'Fabienne', + 'Shaianne', + 'Saleena', + 'Raychelle', + 'Pahoua', + 'Justyne', + 'Fransheska', + 'Katilyn', + 'Shadaya', + 'Quanasia', + 'Shantasia', + 'Nyasha', + 'Minahil', + 'Shahd', + 'Chani', + 'Bassy', + 'Zunairah', + 'Lynsie', + 'Charnelle', + 'Jaquana', + 'Taquana', + 'Shaasia', + 'Idelle', + 'Rogene', + 'Udy', + 'Devory', + 'Evanna', + 'Keisy', + 'Hadiya', + 'Brittainy', + 'Cortni', + 'Erikka', + 'Lindsie', + 'Mayraalejandra', + 'Topacio', + 'Elky', + 'Yita', + 'Sura', + 'Tiani', + 'Sadiya', + 'Kaitlen', + 'Jessicca', + 'Linna', + 'Stephy', + 'Hadia', + 'Jaiyana', + 'Aldina', + 'Frimy', + 'Tywanda', + 'Renarda', + 'Mardelle', + 'Alaijah', + 'Antoinetta', + 'Amyria', + 'Sheyanne', + 'Jackee', + 'Bina', + 'Khole', + 'Selenia', + 'Seidy', + 'Albertina', + 'Yoandra', + 'Yarelyn', + 'Kassaundra', + 'Lynzee', + 'Haneen', + 'Marshay', + 'Sharona', + 'Shanygne', + 'Nigeria', + 'Nechy', + 'Jhane', + 'Chrisette', + 'Gypsy', + 'Drusilla', + 'Milta', + 'Ranee', + 'Yvett', + 'Mykenzie', + 'Aracelia', + 'Vernessa', + 'Chekesha', + 'Cadance', + 'Moria', + 'Tsurue', + 'Yarisbel', + 'Verena', + 'Tomoe', + 'Breezy', + 'Swannie', + 'Tsuyuko', + 'Hisayo', + 'Gerianne', + 'Cailynn', + 'Adrionna', + 'Lillianne', + 'Eduarda', + 'Melinna', + 'Sanaiya', + 'Nohelia', + 'Zarela', + 'Yarethzy', + 'Sruthi', + 'Josefine', + 'Kiela', + 'Kersten', + 'Syriah', + 'Emaleigh', + 'Jazlynne', + 'Aeryn', + 'Danelly', + 'Dalylah', + 'Lexa', + 'Kherington', + 'Nivia', + 'Carolanne', + 'Sharlotte', + 'Vanda', + 'Deirdra', + 'Ilyse', + 'Judyann', + 'Venezia', + 'Mailee', + 'Latishia', + 'Ajla', + 'Lucine', + 'Shontell', + 'Rosiland', + 'Celinda', + 'Aanika', + 'Felicidad', + 'Denia', + 'Natsuko', + 'Analyse', + 'Angellina', + 'Brizeida', + 'Jazira', + 'Terah', + 'Reana', + 'Jennalyn', + 'Jenaya', + 'Kelani', + 'Miyuki', + 'Aracelie', + 'Dannika', + 'Danity', + 'Cadie', + 'Breelyn', + 'Kayra', + 'Mayli', + 'Malarie', + 'Tequilla', + 'Gerilyn', + 'Mieko', + 'Belynda', + 'Shamiyah', + 'Reaghan', + 'Ziya', + 'Rozanne', + 'Joyanne', + 'Zamaria', + 'Luiza', + 'Tamanika', + 'Kimya', + 'Patriciaann', + 'Eilene', + 'Bryna', + 'Yena', + 'Yarelly', + 'Maddyn', + 'Khylie', + 'Khyla', + 'Margueritte', + 'Ramya', + 'Jenea', + 'Jennavie', + 'Jazzlene', + 'Marelly', + 'Manya', + 'Lillyanne', + 'Gyselle', + 'Niyati', + 'Moana', + 'Kenosha', + 'Ezmeralda', + 'Anvitha', + 'Avelyn', + 'Dahlila', + 'Emmaly', + 'Dayamy', + 'Anajulia', + 'Mandee', + 'Valli', + 'Sharan', + 'Leasia', + 'Shiquita', + 'Malana', + 'Nadeen', + 'Parneet', + 'Lynna', + 'Saskia', + 'Samaiya', + 'Saffron', + 'Vianka', + 'Evey', + 'Ebelin', + 'Anishka', + 'Aneth', + 'Addelynn', + 'Kayly', + 'Alyzae', + 'Anniyah', + 'Ayme', + 'Alexsa', + 'Aidsa', + 'Elyn', + 'Illianna', + 'Greenlee', + 'Tinesha', + 'Sherline', + 'Yvanna', + 'Joslin', + 'Estee', + 'Lusia', + 'Nhung', + 'Janielle', + 'Smithie', + 'Yohanna', + 'Shanette', + 'Marilena', + 'Blannie', + 'Meleana', + 'Malie', + 'Jannine', + 'Kuulei', + 'Kawehi', + 'Velna', + 'Kuuipo', + 'Keani', + 'Tiffeny', + 'Billi', + 'Conni', + 'Elexia', + 'Sheily', + 'Mehak', + 'Ardelia', + 'Phung', + 'Aleasha', + 'Toyia', + 'Kalliopi', + 'Carrieann', + 'Shayal', + 'Brandye', + 'Shatisha', + 'Neola', + 'Pallavi', + 'Symantha', + 'Mackenzee', + 'Shalawn', + 'Krimson', + 'Jaquelinne', + 'Sonal', + 'Calysta', + 'Kaylamarie', + 'Kirah', + 'Belicia', + 'Anicia', + 'Aerin', + 'Marisel', + 'Priscella', + 'Lei', + 'Imaan', + 'Haruka', + 'Kila', + 'Jerusha', + 'Deva', + 'Charon', + 'Leida', + 'Deadra', + 'Areana', + 'Iriana', + 'Drenda', + 'Saadia', + 'Danne', + 'Jossalyn', + 'Kennadie', + 'Makaya', + 'Daelynn', + 'Daffne', + 'Galia', + 'Naida', + 'Yaira', + 'Latania', + 'Damarys', + 'Mireille', + 'Maribell', + 'Luzelena', + 'Anacani', + 'Sahira', + 'Shaylin', + 'Sejal', + 'Subrina', + 'Julaine', + 'Saby', + 'Zoraya', + 'Atalie', + 'Deseray', + 'Nacole', + 'Jennell', + 'Laneisha', + 'Ivie', + 'Darnella', + 'Lashone', + 'Lekeisha', + 'Puanani', + 'Uilani', + 'Donyale', + 'Terriann', + 'Marianela', + 'Josalynn', + 'Avari', + 'Blonnie', + 'Makya', + 'Seriah', + 'Nori', + 'Roselee', + 'Verbie', + 'Borghild', + 'Marcene', + 'Syretta', + 'Bama', + 'Eulene', + 'Chantale', + 'Shontae', + 'Mabell', + 'Hellon', + 'Shantanique', + 'Janki', + 'Dhara', + 'Buna', + 'Naeemah', + 'Tacara', + 'Shirleyann', + 'Tshwanda', + 'Nadege', + 'Georganne', + 'Leondra', + 'Fredricka', + 'Margaree', + 'Quincee', + 'Oaklynn', + 'Arlean', + 'Judee', + 'Nyoka', + 'Khia', + 'Kendia', + 'Mahek', + 'Anasia', + 'Jenin', + 'Gerline', + 'Elwillie', + 'Annsley', + 'Juhi', + 'Zettie', + 'Shacara', + 'Shantique', + 'Marijo', + 'Shakara', + 'Ersie', + 'Bionca', + 'Kolleen', + 'Ertha', + 'Chioma', + 'Roneisha', + 'Courtenay', + 'Altie', + 'Arla', + 'Delainey', + 'Rainelle', + 'Lockie', + 'Rayonna', + 'Nasiyah', + 'Zori', + 'Carollee', + 'Mima', + 'Irja', + 'Willadean', + 'Sigrid', + 'Myong', + 'Khaliah', + 'Sakeenah', + 'Saleemah', + 'Emmersyn', + 'Miyeko', + 'Brooksie', + 'Brailynn', + 'Raghad', + 'Nadira', + 'Hassana', + 'Toshiye', + 'Fumiye', + 'Kelise', + 'Angelis', + 'Earla', + 'Dilia', + 'Arwa', + 'Shaylie', + 'Synai', + 'Tanijah', + 'Jalaysia', + 'Charnita', + 'Marit', + 'Gaelle', + 'Shandiin', + 'Janelis', + 'Gatha', + 'Alahna', + 'Aniyla', + 'Mikelle', + 'Skai', + 'Merlinda', + 'Tariyah', + 'Arietta', + 'Terrika', + 'Elenor', + 'Ruthanna', + 'Evaline', + 'Abigaelle', + 'Alayjah', + 'Naysa', + 'Camya', + 'Pachia', + 'Kamia', + 'Sylvania', + 'Ambree', + 'Oakleigh', + 'Zania', + 'Murielle', + 'Charlyn', + 'Zykira', + 'Jestine', + 'Simonne', + 'Willodene', + 'Lyndee', + 'Sophonie', + 'Saddie', + 'Darlis', + 'Lynnda', + 'Marysa', + 'Seleena', + 'Raevyn', + 'Lilikoi', + 'Maiyer', + 'Kymberli', + 'Shayda', + 'Cassidee', + 'Jadira', + 'Delora', + 'Afsheen', + 'Adira', + 'Amena', + 'Canary', + 'Humaira', + 'Derricka', + 'Fatiha', + 'Xia', + 'Jaquelyne', + 'Aurianna', + 'Sarahjane', + 'Sanaz', + 'Taleen', + 'Teara', + 'Taiz', + 'Sharai', + 'Magally', + 'Manon', + 'Maizie', + 'Manisha', + 'Marisleysis', + 'Anjela', + 'Youlanda', + 'Jermani', + 'Elysha', + 'Claritza', + 'Gissela', + 'Icela', + 'Alixandria', + 'Asley', + 'Analuisa', + 'Maddalena', + 'Cortnee', + 'Coretha', + 'Audreanna', + 'Manal', + 'Kadijatou', + 'Pollie', + 'Mysti', + 'Tiffiany', + 'Corean', + 'Amiree', + 'Anner', + 'Cleone', + 'Lavone', + 'Fredna', + 'Konnie', + 'Robbyn', + 'Alica', + 'Bessy', + 'Aleesa', + 'Analleli', + 'Mischelle', + 'Bethani', + 'Baillie', + 'Odessie', + 'Erlene', + 'Marcile', + 'Edona', + 'Tylah', + 'Tyrah', + 'Rainell', + 'Precilla', + 'Genever', + 'Ajanee', + 'Chera', + 'Amye', + 'Monserratt', + 'Moorea', + 'Richa', + 'Willetta', + 'Shawne', + 'Trisa', + 'Lasonia', + 'Cleona', + 'Alizea', + 'Anayely', + 'Emelly', + 'Fionna', + 'Cerena', + 'Julyana', + 'Kaile', + 'Jacklin', + 'Brianca', + 'Ashleyann', + 'Richardine', + 'Kelcee', + 'Keyaira', + 'Mabelle', + 'Brecklyn', + 'Samyah', + 'Ayonna', + 'Mesha', + 'Tyeshia', + 'Tiffiney', + 'Tyara', + 'Azuri', + 'Merideth', + 'Hermie', + 'Leaner', + 'Mendi', + 'Kanoelani', + 'Kadeidra', + 'Akeela', + 'Lin', + 'Mindel', + 'Lashell', + 'Meegan', + 'Ia', + 'Ellamae', + 'Jasmen', + 'Nechuma', + 'Romilda', + 'Hiilei', + 'Osmara', + 'Keidy', + 'Rianne', + 'Afia', + 'Teylor', + 'Raquelle', + 'Grizelda', + 'Tasfia', + 'Laquasha', + 'Tandra', + 'Maeghan', + 'Kameshia', + 'Alara', + 'Emina', + 'Delaina', + 'Jacquetta', + 'Christena', + 'Topanga', + 'Viviann', + 'Eboney', + 'Kasha', + 'Sativa', + 'Secilia', + 'Niomi', + 'Neena', + 'Tanji', + 'Shandy', + 'Corryn', + 'Esly', + 'Silka', + 'Sanaii', + 'Annais', + 'Kaitlynne', + 'Epiphany', + 'Maniya', + 'Mali', + 'Madigan', + 'Sanii', + 'Jaeleen', + 'Faria', + 'Maralyn', + 'Johnae', + 'Lekesha', + 'Sharry', + 'Latecia', + 'Kimberl', + 'Charita', + 'Modean', + 'Marrie', + 'Lielle', + 'Zeina', + 'Pessel', + 'Sameera', + 'Eleonora', + 'Jannatul', + 'Coryn', + 'Dustie', + 'Demitria', + 'Jacqlyn', + 'Nekisha', + 'Latrecia', + 'Rabecca', + 'Malaysha', + 'Lugenia', + 'Elese', + 'Myrissa', + 'Lucrecia', + 'Lysandra', + 'Tarryn', + 'Tammey', + 'Bonnita', + 'Shiffy', + 'Shirel', + 'Clariza', + 'Analis', + 'Rechy', + 'Nusaiba', + 'Manahil', + 'Chamisa', + 'Almetta', + 'Moncia', + 'Leba', + 'Jeilyn', + 'Earnesteen', + 'Mennie', + 'Kieara', + 'Sheina', + 'Yo', + 'Sharnice', + 'Ravin', + 'Daisi', + 'Britini', + 'Carlina', + 'Arisa', + 'Margy', + 'Whitnee', + 'Krysti', + 'Odean', + 'Darlys', + 'Janita', + 'Donnetta', + 'Guynell', + 'Neomia', + 'Loyalty', + 'Serra', + 'Kaysie', + 'Preciosa', + 'Earleen', + 'Shatoria', + 'Kourtnie', + 'Kana', + 'Jahnavi', + 'Kyarra', + 'Licet', + 'Railyn', + 'Delisha', + 'Flordia', + 'Arsema', + 'Kena', + 'Kaelah', + 'Kashia', + 'Emonie', + 'Izola', + 'Linsay', + 'Naibe', + 'Natallie', + 'Rosi', + 'Taline', + 'Cortina', + 'Annett', + 'Kadi', + 'Lindsi', + 'Lasasha', + 'Tamre', + 'Yenny', + 'Yasaman', + 'Shawnice', + 'Thi', + 'Jannel', + 'Kaleen', + 'Demitra', + 'Meisha', + 'Mahira', + 'Emmanuela', + 'Janaiya', + 'Rechel', + 'Nazifa', + 'Zeynep', + 'Shalena', + 'Hila', + 'Ailish', + 'Altovise', + 'Anabeth', + 'Anavictoria', + 'Averey', + 'Berlynn', + 'Alitza', + 'Adelynne', + 'Aiva', + 'Alenna', + 'Harlowe', + 'Camrynn', + 'Daphnie', + 'Ezri', + 'Lanna', + 'Lua', + 'Maddilynn', + 'Maeva', + 'Maytte', + 'Jovi', + 'Karalyn', + 'Kataleah', + 'Kaylana', + 'Milliana', + 'Surveen', + 'Veera', + 'Nimrat', + 'Nimrit', + 'Radha', + 'Roisin', + 'Senna', + 'Ruhi', + 'Saja', + 'Glenice', + 'Damiana', + 'Mikeria', + 'Lakeria', + 'Yulia', + 'Zanna', + 'Lynnae', + 'Illa', + 'Buelah', + 'Novis', + 'Johnye', + 'Valree', + 'Santiaga', + 'Modell', + 'Maydell', + 'Elfida', + 'Charlyne', + 'Argentina', + 'Terica', + 'Kiandra', + 'Tangi', + 'Pascuala', + 'Narcisa', + 'Macaria', + 'Thomasa', + 'Verta', + 'Eulogia', + 'Trellis', + 'Tavaria', + 'Dakayla', + 'Oneita', + 'Kimberlynn', + 'Aslee', + 'Jenascia', + 'Shamaria', + 'Lakely', + 'Etna', + 'Gilberte', + 'Glena', + 'Delorse', + 'Margrett', + 'Endia', + 'Buena', + 'Alvilda', + 'Domitila', + 'Jasmaine', + 'Jaquita', + 'Shontavia', + 'Roneshia', + 'Leasa', + 'Feliciana', + 'Allyana', + 'Anaia', + 'Annalyn', + 'Ayane', + 'Belladonna', + 'Adanely', + 'Akshaya', + 'Aleiyah', + 'Tereasa', + 'Antonisha', + 'Darlah', + 'Dhalia', + 'Dianelly', + 'Elika', + 'Camillia', + 'Leonila', + 'Manreet', + 'Jazzlin', + 'Kaiulani', + 'Kashvi', + 'Talayah', + 'Viana', + 'Ximenna', + 'Shaylah', + 'Quorra', + 'Anagha', + 'Annalea', + 'Jaleyah', + 'Bethanny', + 'Zophia', + 'Alegria', + 'Advika', + 'Taneika', + 'Marye', + 'Latorya', + 'Sayler', + 'Nara', + 'Nithya', + 'Phoenyx', + 'Saiya', + 'Mellany', + 'Yazlin', + 'Adalena', + 'Adya', + 'Aliviah', + 'Aalia', + 'Rickia', + 'Eliyana', + 'Arella', + 'Audris', + 'Auria', + 'Avantika', + 'Aylani', + 'Beya', + 'Camilah', + 'Kaede', + 'Laylonie', + 'Jayani', + 'Katara', + 'Hera', + 'Audrea', + 'Nataley', + 'Nazli', + 'Neyla', + 'Noya', + 'Srinidhi', + 'Pranavi', + 'Sareen', + 'Satya', + 'Terika', + 'Zamora', + 'Jimmye', + 'Brigida', + 'Shereka', + 'Widline', + 'Natori', + 'Dorthie', + 'Berit', + 'Aretta', + 'Svea', + 'Wenona', + 'Amera', + 'Nayah', + 'Lollie', + 'Genice', + 'Fabianna', + 'Nazaria', + 'Edra', + 'Jamariah', + 'Willine', + 'Madolyn', + 'Wanell', + 'Lucetta', + 'Eudora', + 'Adda', + 'Shariah', + 'Jaelle', + 'Jalena', + 'Annelle', + 'Solveig', + 'Autherine', + 'Nobie', + 'Izora', + 'Eudell', + 'Wyolene', + 'Mariangel', + 'Mayar', + 'Luevenia', + 'Eniyah', + 'Lilie', + 'Eliany', + 'Ivyonna', + 'Beadie', + 'Zeta', + 'Merita', + 'Valjean', + 'Delbra', + 'Alanys', + 'Camiyah', + 'Edyth', + 'Kanya', + 'Perina', + 'Catelynn', + 'Angelisse', + 'Relda', + 'Eathel', + 'Kerrington', + 'Lyriq', + 'Brita', + 'Meda', + 'Zanya', + 'Emileigh', + 'Aracelys', + 'Lisania', + 'Evalena', + 'Traniya', + 'Janiyla', + 'Syesha', + 'Ahmya', + 'Camora', + 'Armonie', + 'Beula', + 'Veva', + 'Kateria', + 'Harumi', + 'Kimiyo', + 'Tangie', + 'Amayrany', + 'Alexiah', + 'Alyn', + 'Tokie', + 'Masayo', + 'Makenzee', + 'Arieana', + 'Asayo', + 'Seirra', + 'Elfrida', + 'Ariona', + 'Masue', + 'Mizuki', + 'Liliane', + 'Malanie', + 'Sabreen', + 'Yuritza', + 'Shanautica', + 'Kateleen', + 'Montanna', + 'Tiona', + 'Theresia', + 'Vernia', + 'Mahayla', + 'Glynna', + 'Shaelynn', + 'Isabelly', + 'Aileth', + 'Ailie', + 'Melvia', + 'Sherrel', + 'Ivah', + 'Himani', + 'Marayah', + 'Melane', + 'Evanie', + 'Atalia', + 'Athalia', + 'Bethsy', + 'Betzi', + 'California', + 'Bryonna', + 'Yaretsy', + 'Zamara', + 'Sanyah', + 'Gaylynn', + 'Vitoria', + 'Yoshino', + 'Hatsumi', + 'Tatsuko', + 'Samika', + 'Maili', + 'Charnae', + 'Jamilla', + 'Vieno', + 'Rylei', + 'Vanita', + 'Hydia', + 'Carmyn', + 'Kenslie', + 'Maryhelen', + 'Lamees', + 'Lilley', + 'Haunani', + 'Pualani', + 'Mikiyah', + 'Lovina', + 'Janith', + 'Kanoe', + 'Anouk', + 'Mayerly', + 'Kiele', + 'Lexia', + 'Janani', + 'Berlinda', + 'Belma', + 'Inayah', + 'Saloma', + 'Anely', + 'Anjolina', + 'Devonna', + 'Nikhita', + 'Nayana', + 'Naidely', + 'Hina', + 'Ismerai', + 'Daisie', + 'Sitlaly', + 'Yahayra', + 'Trinidy', + 'Vallery', + 'Ceaira', + 'Floretta', + 'Lavena', + 'Shawntavia', + 'Dessa', + 'Tareva', + 'Iyanla', + 'Kania', + 'Shakiya', + 'Latora', + 'Hermila', + 'Clora', + 'Tiyanna', + 'Saydie', + 'Sherlene', + 'Trixie', + 'Nadiyah', + 'Zarria', + 'Saidy', + 'Sabriya', + 'Keirra', + 'Leeana', + 'Leianna', + 'Jaia', + 'Ishanvi', + 'Ailed', + 'Fathima', + 'Hansika', + 'Delailah', + 'Caliah', + 'Dayleen', + 'Jolisa', + 'Sallye', + 'Levonia', + 'Tula', + 'Kristene', + 'Alanni', + 'Aleiah', + 'Aeva', + 'Ilean', + 'Annet', + 'Lateshia', + 'Markesha', + 'Nikol', + 'Nadolyn', + 'Kimyatta', + 'Ercilia', + 'Sheliah', + 'Heiley', + 'Metztli', + 'Teyla', + 'Saranya', + 'Tanishka', + 'Kayana', + 'Donnamae', + 'Lajoyce', + 'Kemya', + 'Kemora', + 'Jozelyn', + 'Keili', + 'Jaydy', + 'Linzy', + 'Marelin', + 'Melaney', + 'Aleksa', + 'Alynah', + 'Elyza', + 'Emmery', + 'Angeleen', + 'Annica', + 'Bindi', + 'Demya', + 'Nayleen', + 'Sadee', + 'Samah', + 'Shylee', + 'Talula', + 'Vannia', + 'Yarelli', + 'Zohar', + 'Miangel', + 'Orla', + 'Sundra', + 'Korinne', + 'Taniesha', + 'Zaliyah', + 'Zionna', + 'Amariyah', + 'Loris', + 'Cruzita', + 'Landa', + 'Eduvina', + 'Ileanna', + 'Ileene', + 'Jesselle', + 'Daviana', + 'Eleny', + 'Marijane', + 'Okla', + 'Violanda', + 'Dorma', + 'Leoma', + 'Esperansa', + 'Shanreka', + 'Baudelia', + 'Teasia', + 'Aubrei', + 'Jeree', + 'Ortencia', + 'Melida', + 'Pernie', + 'Sweetie', + 'Arelly', + 'Ariday', + 'Bhavya', + 'Aiyanah', + 'Akshita', + 'Ginette', + 'Docia', + 'Pegeen', + 'Alaynah', + 'Allanah', + 'Daniah', + 'Loriana', + 'Kenly', + 'Kenli', + 'Kendahl', + 'Kenady', + 'Senora', + 'Hetal', + 'Aloha', + 'Barri', + 'Shaniquah', + 'Feather', + 'Rica', + 'Adriann', + 'Fleta', + 'Shontel', + 'Kynisha', + 'Nahima', + 'Myracle', + 'Syniah', + 'Jomarie', + 'Leeandra', + 'Maylie', + 'Marijose', + 'Jaley', + 'Sydnei', + 'Amariya', + 'Alysandra', + 'Damia', + 'Laurieann', + 'Lucecita', + 'Miosotis', + 'Shelvy', + 'Bernina', + 'Darice', + 'Dorrie', + 'Myrta', + 'Yoko', + 'Vara', + 'Joanmarie', + 'Kerryann', + 'Carmesa', + 'Kenzington', + 'Oaklyn', + 'Shelbia', + 'Arhianna', + 'Ardyn', + 'Amarachi', + 'Cydnee', + 'Chloey', + 'Brailee', + 'Aily', + 'Rosette', + 'Geryl', + 'Luba', + 'Marguerita', + 'Ayannah', + 'Deziyah', + 'Lurdes', + 'Dawnelle', + 'Reiko', + 'Brynli', + 'Tenlee', + 'Kynadee', + 'Emersen', + 'Josilyn', + 'Jazalyn', + 'Maleyah', + 'Cozette', + 'Xoe', + 'Syria', + 'Charyl', + 'Gita', + 'Aniaya', + 'Yulemni', + 'Joleigh', + 'Kenzy', + 'Logann', + 'Genesys', + 'Cherita', + 'Trenise', + 'Stpehanie', + 'Riann', + 'Matilyn', + 'Akisha', + 'Coralee', + 'Presli', + 'Yariana', + 'Edda', + 'Lisabeth', + 'Farm', + 'Dennice', + 'Deepa', + 'Chiffon', + 'Alyzea', + 'Alexas', + 'Emylee', + 'Joellyn', + 'Zo', + 'Marybell', + 'Sapna', + 'Khristina', + 'Kellyanne', + 'Chrystie', + 'Damary', + 'Graziella', + 'Tene', + 'Shakisha', + 'Shirelle', + 'Gwynne', + 'Insha', + 'Lydiann', + 'Cuba', + 'Cortnie', + 'Denelle', + 'Huyen', + 'Brieann', + 'Cindia', + 'Shalina', + 'Linnette', + 'Kiamesha', + 'Anecia', + 'Brinna', + 'Kewanna', + 'Malke', + 'Yira', + 'Rashidah', + 'Karicia', + 'Chrislyn', + 'Idali', + 'Zandria', + 'Ruta', + 'Toshi', + 'Daena', + 'Aneliz', + 'Cherese', + 'Brandalyn', + 'Brieanne', + 'Chistina', + 'Denys', + 'Nyisha', + 'Lissie', + 'Sherine', + 'Marisal', + 'Tuwana', + 'Zyonna', + 'Shady', + 'Patrisha', + 'Laniece', + 'Jessamyn', + 'Letticia', + 'Shirlie', + 'Miyo', + 'Marilouise', + 'Yukiye', + 'Ltanya', + 'Geralynn', + 'Anastazia', + 'Mitzie', + 'Lluliana', + 'Rozanna', + 'Magalie', + 'Salima', + 'Bevin', + 'Gaudy', + 'Ieasha', + 'Makia', + 'Sacheen', + 'Sherene', + 'Mataya', + 'Hatsuye', + 'Chiyeko', + 'Devanny', + 'Nasya', + 'Odyssey', + 'Tunisia', + 'Caldonia', + 'Marsi', + 'Mindee', + 'Tamy', + 'Sherill', + 'Tsitsiki', + 'Arva', + 'Gayleen', + 'Kimmy', + 'Lenette', + 'Roxan', + 'Leanora', + 'Charlena', + 'Claudina', + 'Danise', + 'Denell', + 'Eydie', + 'Irish', + 'Hydeia', + 'Nichele', + 'Ronica', + 'Temre', + 'Cindra', + 'Vincenta', + 'Zyra', + 'Larita', + 'Jodine', + 'Ewelina', + 'Madylin', + 'Kinzleigh', + 'Malone', + 'Layken', + 'Verity', + 'Tinleigh', + 'Sophi', + 'Skyleigh', + 'Stanislawa', + 'Rylinn', + 'Natalynn', + 'Marlei', + 'Rhylie', + 'Payslee', + 'Paxtyn', + 'Brittyn', + 'Alaynna', + 'Avory', + 'Aubriee', + 'Jacqui', + 'Aseel', + 'Jannell', + 'Simra', + 'Raneem', + 'Kellene', + 'Shellee', + 'Tish', + 'Lashauna', + 'Ashira', + 'Sharrie', + 'Donnette', + 'Milarain', + 'Toshia', + 'Shariyah', + 'Dariah', + 'Gustava', + 'Leotha', + 'Sherelle', + 'Lindi', + 'Luanna', + 'Shanan', + 'Arelys', + 'Nyema', + 'Errin', + 'Fredrica', + 'Dhriti', + 'Yashvi', + 'Gaile', + 'Ermalinda', + 'Gregorita', + 'Klynn', + 'Kaedence', + 'Zaila', + 'Yaritzi', + 'Taylyn', + 'Tailyn', + 'Milka', + 'Maesyn', + 'Macyn', + 'Riyah', + 'Alleigh', + 'Aracelli', + 'Hadlie', + 'Iza', + 'Riddhi', + 'Kathleene', + 'Darely', + 'Eleyna', + 'Analiya', + 'Fanchon', + 'Allyce', + 'Jasma', + 'Porschia', + 'Deberah', + 'Zoi', + 'Sherlyne', + 'Favour', + 'Shakari', + 'Mckenzy', + 'Makinzie', + 'Maahi', + 'Jacqualine', + 'Nancyann', + 'Ronne', + 'Charmane', + 'Martie', + 'Leane', + 'Kama', + 'Corrinne', + 'Vangie', + 'Jonni', + 'Michon', + 'Sharise', + 'Shawnie', + 'Joane', + 'Rosary', + 'Noretta', + 'Zaylynn', + 'Paislie', + 'Infinity', + 'Amaryllis', + 'Altair', + 'Cookie', + 'Danyella', + 'Collyns', + 'Chrislynn', + 'Bryley', + 'Brelynn', + 'Finleigh', + 'Evianna', + 'Flavia', + 'Wilhemina', + 'Jaeliana', + 'Taija', + 'Naiomi', + 'Jennika', + 'Jenika', + 'Jaicee', + 'Laurice', + 'Ashaunti', + 'Alyxandria', + 'Delfinia', + 'Tyiesha', + 'Petrita', + 'Fedelina', + 'Eufelia', + 'Marshae', + 'Marquesha', + 'Feloniz', + 'Tyliyah', + 'Nadene', + 'Natascha', + 'Shawnette', + 'Jamese', + 'Tashay', + 'Mckenzee', + 'Mckinsey', + 'Langley', + 'Kensleigh', + 'Karolyna', + 'Coralyn', + 'Grethel', + 'Baylei', + 'Ariany', + 'Mekenzie', + 'Whitlee', + 'Sayde', + 'Willena', + 'Tzipporah', + 'Afsana', + 'Kearra', + 'Marialy', + 'Quiara', + 'Jing', + 'Dorathea', + 'Rachelann', + 'Melissaann', + 'Jeanett', + 'Jensine', + 'Jessicaann', + 'Ellesse', + 'Kaula', + 'Calley', + 'Malkie', + 'Shenelle', + 'Sheela', + 'Steffi', + 'Shadia', + 'Marielis', + 'Saima', + 'Tiarah', + 'Reginia', + 'Shaquala', + 'Shadiamond', + 'Kallista', + 'Allee', + 'Allexis', + 'Nakeya', + 'Reshma', + 'Sosha', + 'Kendrea', + 'Imalay', + 'Kyong', + 'Sharmin', + 'Sorah', + 'Alayshia', + 'Katja', + 'Chavie', + 'Farzana', + 'Lanasia', + 'Khayla', + 'Jamella', + 'Diva', + 'Ericca', + 'Brettany', + 'Imunique', + 'Tiasia', + 'Tajae', + 'Sidra', + 'Chelbi', + 'Kourtni', + 'Lamisha', + 'Krystyn', + 'Maly', + 'Mirtha', + 'Nary', + 'Nuria', + 'Falicia', + 'Zilpha', + 'Keyasia', + 'Ranisha', + 'Garnetta', + 'Alexxus', + 'Hae', + 'Herma', + 'Tasheena', + 'Philicia', + 'Fotini', + 'Avanell', + 'Czarina', + 'Kindle', + 'Antoinet', + 'Constanc', + 'Cassondr', + 'Destanee', + 'Christinia', + 'Shalisa', + 'Stepahnie', + 'Sopheap', + 'Somaly', + 'Shalane', + 'Saran', + 'Alaycia', + 'Carolynne', + 'Nikolette', + 'Saphire', + 'Dominigue', + 'Channa', + 'Leva', + 'Starquasia', + 'Shyan', + 'Sabah', + 'Shakiera', + 'Nagely', + 'Hajar', + 'Keniya', + 'Anhthu', + 'Ashle', + 'Taira', + 'Meline', + 'Rebeckah', + 'Daritza', + 'Kaysha', + 'Kathrin', + 'Edit', + 'Jennae', + 'Kaja', + 'Molli', + 'Hildreth', + 'Elyssia', + 'Keandrea', + 'Courtlyn', + 'Cova', + 'Kyndle', + 'Kadisha', + 'Mitchelle', + 'Chabeli', + 'Ashlen', + 'Feiga', + 'Shakena', + 'Lakeia', + 'Jehan', + 'Karianne', + 'Renisha', + 'Crystalyn', + 'Blia', + 'Amanada', + 'Neiba', + 'Oyuki', + 'Lianet', + 'Javaria', + 'Praise', + 'Sagal', + 'Avaleigh', + 'Amoni', + 'Fadumo', + 'Debhora', + 'Sharol', + 'Sahalie', + 'Aleana', + 'Dezire', + 'Catalia', + 'Barbarann', + 'Raelin', + 'Reniyah', + 'Jeniyah', + 'Jaziya', + 'Wilhemenia', + 'Wavie', + 'Modestine', + 'Tariah', + 'Cathern', + 'Asenath', + 'Nakya', + 'Reeva', + 'Tkai', + 'Orva', + 'Theora', + 'Brookie', + 'Breyonna', + 'Ellagrace', + 'Kaliya', + 'Jemimah', + 'Ahna', + 'Zetta', + 'Tanyia', + 'Dicie', + 'Malasia', + 'Janvi', + 'Talaysia', + 'Kaybree', + 'Teia', + 'Robertha', + 'Tilda', + 'Marykatherine', + 'Gusta', + 'Gola', + 'Malta', + 'Nija', + 'Kaija', + 'Tamaria', + 'Chyann', + 'Davianna', + 'Gae', + 'Ruther', + 'Kennadee', + 'Arvella', + 'Ashonti', + 'Euphemia', + 'Teyanna', + 'Jahnya', + 'Jamariya', + 'Ceanna', + 'Francenia', + 'Charletta', + 'Catheryn', + 'Theodosia', + 'Magdaline', + 'Samariah', + 'Jamara', + 'Nehemie', + 'Mikenzie', + 'Marielys', + 'Keilany', + 'Bernardita', + 'Marketa', + 'Takya', + 'Frona', + 'Draxie', + 'Genell', + 'Celesta', + 'Deloria', + 'Sister', + 'Icy', + 'Mardi', + 'Florance', + 'Azari', + 'Ahmiyah', + 'Chaniya', + 'Rheda', + 'Kateland', + 'Rielle', + 'Kjersten', + 'Olivette', + 'Tita', + 'Tharon', + 'Briasia', + 'Pakou', + 'Raniah', + 'Janaria', + 'Jaliya', + 'Alexiana', + 'Alayja', + 'Ailea', + 'Camiya', + 'Versa', + 'Vertell', + 'Loyola', + 'Mckelle', + 'Ebonique', + 'Jaynie', + 'Shamiah', + 'Keela', + 'Laterrica', + 'Fidelia', + 'Annia', + 'Rosslyn', + 'Robynn', + 'Darlynn', + 'Shakiara', + 'Shakeira', + 'Olinda', + 'Kionna', + 'Annslee', + 'Rudine', + 'Teonna', + 'Rudene', + 'Latrece', + 'Wynette', + 'Damiya', + 'Zonnie', + 'Jenne', + 'Deeanne', + 'Doree', + 'Jennilyn', + 'Lari', + 'Lourie', + 'Tedi', + 'Deaira', + 'Deairra', + 'Fatuma', + 'Gearldean', + 'Genise', + 'Karlyn', + 'Arleta', + 'Alla', + 'Donie', + 'Lady', + 'Rheba', + 'Nuha', + 'Olita', + 'Elzina', + 'Lutricia', + 'Tauna', + 'Teasha', + 'Elberta', + 'Jeralyn', + 'Shaketa', + 'Elonda', + 'Lafondra', + 'Shelle', + 'Lamiya', + 'Lejla', + 'Labria', + 'Wessie', + 'Cleola', + 'Suad', + 'Andretta', + 'Piccola', + 'Jadalee', + 'Louanna', + 'Donabelle', + 'Shauntel', + 'Vannie', + 'Naomia', + 'Ludell', + 'Ikram', + 'Ariyonna', + 'Anaelle', + 'Pamila', + 'Scheryl', + 'Kandee', + 'Donella', + 'Vicie', + 'Tajah', + 'Jodeen', + 'Debborah', + 'Varvara', + 'Jalisha', + 'Paw', + 'Tranette', + 'Ruwayda', + 'Jeanice', + 'Lowana', + 'Curlie', + 'Viveca', + 'Tommi', + 'Lynnel', + 'Shawneen', + 'Tora', + 'Ikhlas', + 'Delene', + 'Jillyn', + 'Abria', + 'Blondine', + 'Katharyn', + 'Gini', + 'Lynnell', + 'Laurey', + 'Ikran', + 'Madell', + 'Dura', + 'Trenia', + 'Arsie', + 'Runell', + 'Lawan', + 'Georgeanna', + 'Nashay', + 'Lasha', + 'Michi', + 'Arloa', + 'Kazuye', + 'Arnette', + 'Morghan', + 'Allure', + 'Kiyo', + 'Fusaye', + 'Sebrena', + 'Kikuye', + 'Mykia', + 'Soon', + 'Kyung', + 'Maysa', + 'Manessa', + 'Ople', + 'Amyre', + 'Katera', + 'Danaya', + 'Dorothey', + 'Shahidah', + 'Soliana', + 'Concettina', + 'Delphie', + 'Aqueelah', + 'Cassadee', + 'Larayne', + 'Burnette', + 'Diona', + 'Stasha', + 'Sheria', + 'Luciel', + 'Anise', + 'Cumi', + 'Marillyn', + 'Domenique', + 'Sumiye', + 'Masaye', + 'Imojean', + 'Louetta', + 'Taimi', + 'Berdie', + 'Jyl', + 'Cyrilla', + 'Kearstin', + 'Tosca', + 'Billee', + 'Milda', + 'Rema', + 'Tyne', + 'Altamease', + 'Aleaha', + 'Malaina', + 'Jersie', + 'Nadyne', + 'Suhailah', + 'Reghan', + 'Burma', + 'Kamyra', + 'Geraldean', + 'Ivalee', + 'Waunita', + 'Aritza', + 'Madalynne', + 'Talaya', + 'Azura', + 'Aldonia', + 'Robinette', + 'Ameenah', + 'Abeer', + 'Yamilette', + 'Tanae', + 'Mertha', + 'Jamirah', + 'Chun', + 'Avayah', + 'Janayah', + 'Bena', + 'Mahiyah', + 'Karn', + 'Kristien', + 'Mikesha', + 'Eriel', + 'Kemoni', + 'Aziya', + 'Raigan', + 'Rissie', + 'Tenna', + 'Tambria', + 'Birdell', + 'Almena', + 'Jonisha', + 'Marcey', + 'Rosebud', + 'Lakevia', + 'Shateria', + 'Nelia', + 'Rilda', + 'Doshie', + 'Onzell', + 'Safiyyah', + 'Lorilee', + 'Shiane', + 'Gauri', + 'Ashiya', + 'Yaileen', + 'Vendetta', + 'Margaretmary', + 'Telisa', + 'Imogean', + 'Sheryn', + 'Nance', + 'Mariette', + 'Keerthana', + 'Rosellen', + 'Michelene', + 'Kamrie', + 'Mayci', + 'Jerzi', + 'Vermelle', + 'Tondra', + 'Dorethea', + 'Wannetta', + 'Tilly', + 'Brightyn', + 'Patt', + 'Lynae', + 'Willo', + 'Cloma', + 'Yailyn', + 'Takeria', + 'Janyiah', + 'Rasheema', + 'Nafeesa', + 'Rosene', + 'Kellianne', + 'Taccara', + 'Quanda', + 'Patsie', + 'Chaquita', + 'Shakelia', + 'Guerline', + 'Tashika', + 'Taneesha', + 'Fatme', + 'Marliss', + 'Hye', + 'Marjo', + 'Meggie', + 'Maye', + 'Walline', + 'Dodi', + 'Kristyna', + 'Aliyyah', + 'Latravia', + 'Diania', + 'Elta', + 'Oralee', + 'Nikkita', + 'Rasha', + 'Sharena', + 'Tecora', + 'Pluma', + 'Ovell', + 'Keeya', + 'Dayja', + 'Sherrian', + 'Jinnie', + 'Ekta', + 'Javonda', + 'Shantrice', + 'Dava', + 'Kimbley', + 'Lafonda', + 'Lasonja', + 'Hiilani', + 'Danay', + 'Avree', + 'Kelliann', + 'Keasha', + 'Kimmarie', + 'Jannely', + 'Manasi', + 'Moncerat', + 'Miyu', + 'Jullianna', + 'Joelene', + 'Ynez', + 'Yazmeen', + 'Yasamin', + 'Syann', + 'Surena', + 'Tresia', + 'Trecia', + 'Sonjia', + 'Hokulani', + 'Amarilys', + 'Bethzaida', + 'Noraida', + 'Dietra', + 'Nealie', + 'Charice', + 'Alicea', + 'Jozie', + 'Delzora', + 'Jordis', + 'Jolett', + 'Kahlen', + 'Kallee', + 'Natilee', + 'Pecolia', + 'Iyari', + 'Shandrell', + 'Quintella', + 'Monchel', + 'Tysha', + 'Vanetta', + 'Shawneequa', + 'Odesser', + 'Lareina', + 'Jannifer', + 'Kinya', + 'Lateesha', + 'Dvora', + 'Katrin', + 'Denene', + 'Diondra', + 'Ciclali', + 'Sula', + 'Talena', + 'Afrika', + 'Cheron', + 'Emireth', + 'Cadee', + 'Jlyn', + 'Jermya', + 'Alyia', + 'Sitlali', + 'Sissy', + 'Felita', + 'Kerith', + 'Wendolyn', + 'Chaundra', + 'Angle', + 'Gladies', + 'Meygan', + 'Sereniti', + 'Saryn', + 'Vielka', + 'Tirzah', + 'Lynnmarie', + 'Lisanne', + 'Yliana', + 'Yamilett', + 'Keyoka', + 'Laquanta', + 'Teneshia', + 'Trenna', + 'Veronda', + 'Fronie', + 'Carlette', + 'Lanetta', + 'Raynelle', + 'Tianne', + 'Siria', + 'Mayda', + 'Lorien', + 'Celica', + 'Tabbitha', + 'Kayanna', + 'Julitza', + 'Kylia', + 'Heavenlee', + 'Nikka', + 'Rachana', + 'Mekenna', + 'Maritere', + 'Ai', + 'Angelisa', + 'Anysa', + 'Basia', + 'Ilka', + 'Geanine', + 'Kedra', + 'Caila', + 'Deysy', + 'Emilyann', + 'Samera', + 'Mackinzie', + 'Lynzie', + 'Akela', + 'Navpreet', + 'Reylene', + 'Reyanna', + 'Kathlynn', + 'Kiaira', + 'Guiselle', + 'Brinn', + 'Jerelyn', + 'Lorel', + 'Alandra', + 'Ardyth', + 'Kloee', + 'Mellody', + 'Carlisa', + 'Martinique', + 'Damali', + 'Cassandre', + 'Ivanelle', + 'Janaan', + 'Shontay', + 'Tamieka', + 'Tashema', + 'Irmalinda', + 'Tayna', + 'Berdena', + 'Janika', + 'Shauntay', + 'Nikea', + 'Ekaterini', + 'Glendaly', + 'Vernee', + 'Kang', + 'Candise', + 'Jamica', + 'Andera', + 'Katheleen', + 'Annagrace', + 'Bradleigh', + 'Kissy', + 'Lachandra', + 'Tamikia', + 'Shevon', + 'Wardean', + 'Betina', + 'Marcee', + 'Evia', + 'Carry', + 'Marica', + 'Tiwana', + 'Stacye', + 'Theressa', + 'Torsha', + 'Allayna', + 'Betania', + 'Berania', + 'Claryssa', + 'Clarise', + 'Cassidi', + 'Mehana', + 'Janella', + 'Mackenzy', + 'Kaeleigh', + 'Sanoe', + 'Neysa', + 'Shawntee', + 'Shannah', + 'Tihani', + 'Willye', + 'Zalma', + 'Serrina', + 'Shealyn', + 'Hiiaka', + 'Jeselle', + 'Mitsy', + 'Kela', + 'Aquila', + 'Marikay', + 'Christella', + 'Tameria', + 'Ebelina', + 'Maricar', + 'Shalimar', + 'Yanin', + 'Xuan', + 'Tifany', + 'Thy', + 'Quynh', + 'Shronda', + 'Kysha', + 'Lular', + 'Danee', + 'Christyna', + 'Antonieta', + 'Chara', + 'Bich', + 'Tishana', + 'Sophy', + 'Shoshanna', + 'Adrea', + 'Lavaun', + 'Keryn', + 'Okema', + 'Njeri', + 'Ashaki', + 'Alegra', + 'Anapatricia', + 'Terena', + 'Tuere', + 'Ensley', + 'Geraline', + 'Corrinna', + 'Carlye', + 'Dawnielle', + 'Fancy', + 'Akiba', + 'Korrie', + 'Lavita', + 'Chisa', + 'Lakishia', + 'Mandisa', + 'Lalita', + 'Sakeena', + 'Noami', + 'Olivea', + 'Lucilla', + 'Marialuiza', + 'Radonna', + 'Magaline', + 'Minda', + 'Annah', + 'Mitsuyo', + 'Kameko', + 'Miyako', + 'Satsuki', + 'Hatsuyo', + 'Aimie', + 'Jalexis', + 'Haruyo', + 'Tokiko', + 'Matsuyo', + 'Myiah', + 'Natalye', + 'Priseis', + 'Yeraldi', + 'Natsue', + 'Nobue', + 'Zyria', + 'Tierany', + 'Samyia', + 'Rhema', + 'Chiyo', + 'Lailoni', + 'Momoka', + 'Miku', + 'Havanna', + 'Izela', + 'Kendy', + 'Rashanda', + 'Aleysha', + 'Sherlita', + 'Tamana', + 'Kikuyo', + 'Tapanga', + 'Shauntell', + 'Adithi', + 'Chiamaka', + 'Devika', + 'Angy', + 'Arwyn', + 'Aparna', + 'Anneka', + 'Betzayra', + 'Analuiza', + 'Blondie', + 'October', + 'Yarexi', + 'Yarethzi', + 'Annaclaire', + 'Rosabel', + 'Jerlene', + 'Clelia', + 'Jatara', + 'Anzley', + 'Zamaya', + 'Venera', + 'Kalleigh', + 'Jaylynne', + 'Kaylor', + 'Milli', + 'Nelsy', + 'Laycee', + 'Arayah', + 'Betzabe', + 'Bethzi', + 'Haidy', + 'Chayla', + 'Elizah', + 'Evoleth', + 'Edyn', + 'Cyniah', + 'December', + 'Amerika', + 'Analea', + 'Ayshia', + 'Alauna', + 'Shamica', + 'Peaches', + 'Shenee', + 'Letecia', + 'Arminda', + 'Yolander', + 'Amariona', + 'Kaithlyn', + 'Jasiya', + 'Niharika', + 'Sareena', + 'Maryana', + 'Melanye', + 'Solei', + 'Suhey', + 'Soyla', + 'Koral', + 'Lilee', + 'Mercede', + 'Pennye', + 'Yumeka', + 'Mazel', + 'Vani', + 'Pattiann', + 'Shirell', + 'Carmencita', + 'Delayla', + 'Hailyn', + 'Brena', + 'Daana', + 'Lenise', + 'Ryhanna', + 'Lorely', + 'Tiannah', + 'Zabdi', + 'Kammy', + 'Josslynn', + 'Keilee', + 'Kamrynn', + 'Itza', + 'Jaidy', + 'Cherly', + 'Ladeana', + 'Memory', + 'Maresa', + 'Shauntae', + 'Risha', + 'Ilisa', + 'Debraann', + 'Gavriela', + 'Jenai', + 'Suzzette', + 'Mailani', + 'Leiloni', + 'Manasa', + 'Malin', + 'Faythe', + 'Haylei', + 'Haili', + 'Gwenivere', + 'Jamilette', + 'Naydeline', + 'Sakshi', + 'Nayda', + 'Nuala', + 'Chelsae', + 'Berenize', + 'Bahar', + 'Arpi', + 'Tearra', + 'Metta', + 'Lethia', + 'Akanksha', + 'Danine', + 'Alayne', + 'Jeanann', + 'Loyda', + 'Yamna', + 'Marsela', + 'Jolinda', + 'Leina', + 'Mariane', + 'Kaydince', + 'Etsuko', + 'Tinika', + 'Lashona', + 'Chidinma', + 'Jazell', + 'Derenda', + 'Cylinda', + 'Amaiah', + 'Alyzza', + 'Abbygayle', + 'Tashae', + 'Tesa', + 'Sarra', + 'Tanasha', + 'Latoy', + 'Dawnell', + 'Corinn', + 'Charmain', + 'Odetta', + 'Kimiya', + 'Kiaya', + 'Mairin', + 'Maelani', + 'Halena', + 'Dorianne', + 'Ilia', + 'Cheyenna', + 'Noora', + 'Nareh', + 'Namrata', + 'Sholanda', + 'Sita', + 'Dunia', + 'Betzayda', + 'Analissa', + 'Amulya', + 'Annaka', + 'Anneth', + 'Anaalicia', + 'Noemie', + 'Leni', + 'Robyne', + 'Skyleen', + 'Tiphanie', + 'Belmira', + 'Francelina', + 'Kreindy', + 'Kiri', + 'Kristena', + 'Lawren', + 'Christyn', + 'Deicy', + 'Hollyann', + 'Jamela', + 'Eriko', + 'Sotheary', + 'Lekeshia', + 'Onica', + 'Micole', + 'Marlisa', + 'Aqsa', + 'Bayla', + 'Abigal', + 'Charny', + 'Shaquira', + 'Rabab', + 'Yasemin', + 'Keishla', + 'Donasia', + 'Ellamarie', + 'Darianny', + 'Dahiana', + 'Areeba', + 'Shaquasha', + 'Oneisha', + 'Daicy', + 'Karem', + 'Kymberlee', + 'Kayleena', + 'Katryna', + 'Jessicamae', + 'Gessica', + 'Jameela', + 'Janele', + 'Naylani', + 'Anagabriela', + 'Andraya', + 'Andreanna', + 'Artavia', + 'Alexanderia', + 'Laporche', + 'Laporsche', + 'Folasade', + 'Kirandeep', + 'Davia', + 'Davona', + 'Darbi', + 'Baylea', + 'Sylwia', + 'Glendy', + 'Ivet', + 'Fritzi', + 'Lusero', + 'Marlayna', + 'Marlissa', + 'Leanny', + 'Duaa', + 'Ruchama', + 'Orli', + 'Nabeeha', + 'Maurissa', + 'Shevawn', + 'Shauni', + 'Shellby', + 'Sindi', + 'Taralyn', + 'Tanzania', + 'Sinthia', + 'Ondrea', + 'Nhu', + 'Narine', + 'Naly', + 'Yanett', + 'Temmy', + 'Manar', + 'Maimuna', + 'Arielys', + 'Dalya', + 'Allyse', + 'Mariateresa', + 'Mariade', + 'Lashea', + 'Kimberlyann', + 'Cyntia', + 'Cystal', + 'Elisse', + 'Tonimarie', + 'Nashalie', + 'Shatasia', + 'Teigan', + 'Muntaha', + 'Zlata', + 'Zehra', + 'Shaterra', + 'Leeya', + 'Keysi', + 'Christabel', + 'Alfrieda', + 'Mehgan', + 'Hyacinth', + 'Shley', + 'Caterin', + 'Darnesha', + 'Amaranta', + 'Jazzmen', + 'Kelia', + 'Kassy', + 'Grasiela', + 'Sheindy', + 'Yenty', + 'Tahani', + 'Umme', + 'Mayla', + 'Maryon', + 'Kiyanna', + 'Dezeray', + 'Macaela', + 'Nalley', + 'Mikeisha', + 'Sylvana', + 'Smantha', + 'Virdiana', + 'Afiya', + 'Chanise', + 'Glorimar', + 'Hui', + 'Hendel', + 'Junia', + 'Gioia', + 'Elene', + 'Dorothie', + 'Elynor', + 'Mercades', + 'Arfa', + 'Abiha', + 'Aayat', + 'Amarianna', + 'Raynisha', + 'Pahola', + 'Sarin', + 'Marixa', + 'Shavonna', + 'Tannya', + 'Tijera', + 'Girtha', + 'Tameko', + 'Caresse', + 'Bernyce', + 'Allisha', + 'Branda', + 'Jahmya', + 'Haleema', + 'Hodaya', + 'Samina', + 'Sheva', + 'Theadora', + 'Skylyn', + 'Razan', + 'Somalia', + 'Thalya', + 'Quadasia', + 'Yanil', + 'Arabia', + 'Edina', + 'Briyanna', + 'Verdia', + 'Sehar', + 'Naama', + 'Timberly', + 'Reann', + 'Narissa', + 'Maggy', + 'Marriah', + 'Joua', + 'Kellsie', + 'Kelcy', + 'Evonna', + 'Jacqueleen', + 'Xee', + 'Zaynah', + 'Janique', + 'Jailin', + 'Aniqa', + 'Melana', + 'Mariame', + 'Aundria', + 'Anacaren', + 'Anahid', + 'Jassmine', + 'Keoshia', + 'Keyera', + 'Delmi', + 'Briselda', + 'Carlisha', + 'Brittnei', + 'Clarrisa', + 'Dezerae', + 'Banessa', + 'Ariele', + 'Cherrell', + 'Daissy', + 'Cecila', + 'Jady', + 'Kristelle', + 'Kristinamarie', + 'Korinna', + 'Kortnee', + 'Jasimine', + 'Jahnay', + 'Farhana', + 'Shaliyah', + 'Nemesis', + 'Shakerria', + 'Phoua', + 'Carylon', + 'Ironesha', + 'Lariza', + 'Anesa', + 'Elantra', + 'Deandria', + 'Denecia', + 'Chelsia', + 'Teighlor', + 'Suzannah', + 'Zelene', + 'Zeena', + 'Catriona', + 'Tamarra', + 'Tannaz', + 'Titiana', + 'Briany', + 'Lyana', + 'Maytal', + 'Antanasia', + 'Kierston', + 'Dashia', + 'Ismenia', + 'Annessa', + 'Carolena', + 'Miasia', + 'Mikhaila', + 'Lamiracle', + 'Kassey', + 'Markeshia', + 'Hilarie', + 'Necha', + 'Ziara', + 'Jahniyah', + 'Safiyah', + 'Tanaisha', + 'Shamyra', + 'Laportia', + 'Shavy', + 'Viktoriya', + 'Khrystyne', + 'Kristyne', + 'Juanisha', + 'Jerrika', + 'Channelle', + 'Jacquiline', + 'Rakia', + 'Tamarah', + 'Sarha', + 'Mishelle', + 'Nastasha', + 'Acadia', + 'Brittiney', + 'Mickaela', + 'Natavia', + 'Seryna', + 'Ardene', + 'Special', + 'Simranjit', + 'Marivi', + 'Natassja', + 'Neira', + 'Nikkie', + 'Asiana', + 'Dazhane', + 'Channell', + 'Adryana', + 'Mariluz', + 'Dajia', + 'Breigh', + 'Zelpha', + 'Lataya', + 'Glenny', + 'Sharene', + 'Shaguana', + 'Henrine', + 'Camesha', + 'Birdia', + 'Dynisha', + 'Sherina', + 'Ayde', + 'Danille', + 'Charday', + 'Almadelia', + 'Larena', + 'Charlestine', + 'Suellyn', + 'Marry', + 'Constantina', + 'Tandi', + 'Lacretia', + 'Noralba', + 'Latresha', + 'Latacha', + 'Talynn', + 'Rox', + 'Chasey', + 'Nyia', + 'Alyissa', + 'Karilyn', + 'Shevonne', + 'Genny', + 'Tamicka', + 'Doneisha', + 'Cyrena', + 'Daisia', + 'Ravina', + 'Berdia', + 'Aneesha', + 'Vashti', + 'Latrica', + 'Kennetha', + 'Aarti', + 'Raiza', + 'Elspeth', + 'Kyleen', + 'Ronika', + 'Lyndsy', + 'Jone', + 'Chanta', + 'Serita', + 'Margree', + 'Ruthel', + 'Ruthella', + 'Breunna', + 'Cyann', + 'Atlanta', + 'Danniela', + 'Junita', + 'Floella', + 'Brittane', + 'Avanelle', + 'Priscill', + 'Luvina', + 'Jeneva', + 'Teretha', + 'Clarita', + 'Ilce', + 'Jacqualyn', + 'Justene', + 'Daysia', + 'Taylore', + 'Sadi', + 'Verenis', + 'Shyenne', + 'Toriana', + 'Alvira', + 'Kalah', + 'Rajanee', + 'Reonna', + 'Mariadelaluz', + 'Mychaela', + 'Charnele', + 'Aeisha', + 'Shaquaya', + 'Shaakira', + 'Tayana', + 'Cozetta', + 'Kensey', + 'Jazsmin', + 'Kaitlyne', + 'Hollye', + 'Lavren', + 'Sarit', + 'Shanieka', + 'Margorie', + 'Virgene', + 'Dannia', + 'Clorissa', + 'Breahna', + 'Rayla', + 'Dellanira', + 'Megen', + 'Matalie', + 'Taraneh', + 'Teila', + 'Etter', + 'Cheetara', + 'Shetara', + 'Jamielee', + 'Kariann', + 'Karess', + 'Bea', + 'Leyda', + 'Misa', + 'Mareena', + 'Maisee', + 'Yvonna', + 'Yocelyne', + 'Yilda', + 'Sabrinna', + 'Sirenia', + 'Tyriel', + 'Darrielle', + 'Siedah', + 'Yuko', + 'Stevee', + 'Chrystle', + 'Shaterrica', + 'Janyll', + 'Evelisse', + 'Belkis', + 'Renesmae', + 'Sahily', + 'Zurie', + 'Edelia', + 'Sequoya', + 'Waldine', + 'Marinell', + 'Moya', + 'Lavenia', + 'Liboria', + 'Meliah', + 'Meliyah', + 'Mio', + 'Xitllali', + 'Nare', + 'Oliviah', + 'Mayrani', + 'Sravya', + 'Valeska', + 'Riona', + 'Lashaundra', + 'Phebe', + 'Yeira', + 'Zarai', + 'Ayanah', + 'Kriti', + 'Kaileah', + 'Donata', + 'Jenavee', + 'Daphnee', + 'Gurneet', + 'Emmalie', + 'Rowrenia', + 'Haisley', + 'Harbor', + 'Arilyn', + 'Aubrii', + 'Avielle', + 'Avyn', + 'Bethenny', + 'Arienne', + 'Anyeli', + 'Brilyn', + 'Cataleyah', + 'Chisom', + 'Dalis', + 'Malaiya', + 'Meela', + 'Karsynn', + 'Kaselyn', + 'Kashlyn', + 'Amorette', + 'Lenita', + 'Adabelle', + 'Allisyn', + 'Alyzah', + 'Aaralynn', + 'Avyanna', + 'Aylinn', + 'Bexley', + 'Blakeleigh', + 'Caeli', + 'Chizaram', + 'Avriana', + 'Clarity', + 'Juanelle', + 'Jerelene', + 'Eluteria', + 'Lamerle', + 'Aletheia', + 'Abrie', + 'Adelie', + 'Elleigh', + 'Emmelyn', + 'Emsley', + 'Everlynn', + 'Galileah', + 'Derrica', + 'Keondria', + 'Keneshia', + 'Amberley', + 'Valkyrie', + 'Yazleemar', + 'Maybree', + 'Shloka', + 'Neah', + 'Oluwatomisin', + 'Saydi', + 'Jessalynn', + 'Katalaya', + 'Katniss', + 'Kendalynn', + 'Davionna', + 'Mercie', + 'Danett', + 'Deetya', + 'Dilynn', + 'Dunya', + 'Camyla', + 'Elliotte', + 'Ivee', + 'Jadie', + 'Kyleah', + 'Laelani', + 'Mileah', + 'Nalanie', + 'Nixie', + 'Oviya', + 'Lakecia', + 'Sharnae', + 'Abbagail', + 'Derica', + 'Truly', + 'Tvisha', + 'Vedika', + 'Xiclaly', + 'Syra', + 'Idamae', + 'Dashanti', + 'Neita', + 'Siona', + 'Jourdyn', + 'Analyn', + 'Shamiracle', + 'Daylene', + 'Kadeesha', + 'Malgorzata', + 'Dashay', + 'Else', + 'Pixie', + 'Myleah', + 'Myleen', + 'Nadiah', + 'Sadhana', + 'Samai', + 'Seraphine', + 'Sereen', + 'Sharanya', + 'Simar', + 'Mahlia', + 'Inika', + 'Jennavieve', + 'Genevy', + 'Harshita', + 'Hennessey', + 'Zari', + 'Jamiracle', + 'Loveta', + 'Coleta', + 'Adabella', + 'Alesana', + 'Brinleigh', + 'Azlyn', + 'Braelee', + 'Shaquila', + 'Shanyia', + 'Jamilia', + 'Corlis', + 'Dulcie', + 'Desha', + 'Timya', + 'Rakiya', + 'Tyliah', + 'Taura', + 'Terasha', + 'Gaynel', + 'Roylene', + 'Janecia', + 'Alonda', + 'Tyneisha', + 'Fleurette', + 'Mayleigh', + 'Meklit', + 'Sarenity', + 'Gulianna', + 'Itzayanna', + 'Ivyana', + 'Jazmynn', + 'Esmie', + 'Favor', + 'Kimbella', + 'Shanavia', + 'Yaritzel', + 'Daun', + 'Tykerria', + 'Antoria', + 'Shykemmia', + 'Remona', + 'Lucrezia', + 'Cicily', + 'Aradhya', + 'Esmae', + 'Evah', + 'Jhene', + 'Katalia', + 'Cyrine', + 'Delayza', + 'Eleonor', + 'Arohi', + 'Aseneth', + 'Avarose', + 'Caia', + 'Hulene', + 'Valera', + 'Nasaria', + 'Makesha', + 'Zera', + 'Aahna', + 'Aariyah', + 'Aashvi', + 'Adalene', + 'Annaliyah', + 'Aira', + 'Alaska', + 'Amila', + 'Amour', + 'Kaylinn', + 'Isidora', + 'Marija', + 'Suha', + 'Marigold', + 'Mayzie', + 'Liesel', + 'Darielle', + 'Sapphira', + 'Scotland', + 'Serah', + 'Srinika', + 'Novah', + 'Primrose', + 'Latresa', + 'Theia', + 'Alleen', + 'Agness', + 'Estanislada', + 'Ellouise', + 'Emilija', + 'Glynnis', + 'Paulene', + 'Wilna', + 'Maedell', + 'Lometa', + 'Cressie', + 'Allyne', + 'Calleen', + 'Joaquina', + 'Lashelle', + 'Modene', + 'Jonie', + 'Minta', + 'Milady', + 'Jearlene', + 'Rithika', + 'Simrat', + 'Vonzella', + 'Venna', + 'Pabla', + 'Benilde', + 'Eniya', + 'Shakendra', + 'Ailen', + 'Aina', + 'Marionna', + 'Millette', + 'Emiyah', + 'Kayloni', + 'Keerat', + 'Keeva', + 'Lailany', + 'Mishka', + 'Naevia', + 'Nathania', + 'Nyari', + 'Jayah', + 'Kaavya', + 'Frankee', + 'Anahita', + 'Anella', + 'Elizabella', + 'Damara', + 'Juaquina', + 'Gracia', + 'Rozalyn', + 'Ruhani', + 'Novalie', + 'Mialani', + 'Minka', + 'Nessa', + 'Sissi', + 'Sitara', + 'Jaynee', + 'Jeyla', + 'Gizzelle', + 'Maila', + 'Maizy', + 'Lamaya', + 'Katalea', + 'Khamila', + 'Shekita', + 'Chinita', + 'Anshika', + 'Aerabella', + 'Azelia', + 'Cici', + 'Daleyssa', + 'Divinity', + 'Fermina', + 'Murline', + 'Mattye', + 'Devra', + 'Jakya', + 'Santresa', + 'Larene', + 'Deola', + 'Liliann', + 'Lexxi', + 'Kamori', + 'Myonna', + 'Yitzel', + 'Lindalee', + 'Tira', + 'Mairyn', + 'Riyana', + 'Shaleen', + 'Rhyleigh', + 'Fleeta', + 'Gabrielly', + 'Deajah', + 'Yarielis', + 'Arelie', + 'Amore', + 'Sacoria', + 'Hedda', + 'Wanza', + 'Janyth', + 'Yaslin', + 'Brianah', + 'Anyelin', + 'Shayleigh', + 'Lace', + 'Kurstin', + 'Zakhia', + 'Charvi', + 'Raylie', + 'Nyellie', + 'Natalyn', + 'Libra', + 'Khianna', + 'Jolena', + 'Genevive', + 'Jadine', + 'Deniya', + 'Madysin', + 'Porchia', + 'Layleen', + 'Kemiya', + 'Donesha', + 'Jewelene', + 'Sakari', + 'Narely', + 'Maylyn', + 'Halina', + 'Nelli', + 'Myangel', + 'British', + 'Adore', + 'Alainah', + 'Shadonna', + 'Aminta', + 'Marolyn', + 'Jalea', + 'Breelynn', + 'Carah', + 'Sagrario', + 'Akyra', + 'Kailei', + 'Kenza', + 'Renette', + 'Joanann', + 'Solimar', + 'Semira', + 'Harneet', + 'Jahayra', + 'Evanny', + 'Gyzelle', + 'Nathalee', + 'Dalphine', + 'Mane', + 'Merelyn', + 'Kayliana', + 'Aubryn', + 'Brooklyne', + 'Kimari', + 'Dandra', + 'Cilia', + 'Laren', + 'Denetra', + 'Kandise', + 'Makynli', + 'Janan', + 'Rosalea', + 'Ludean', + 'Syndey', + 'Shaney', + 'Vannary', + 'Reynalda', + 'Rainee', + 'Trishia', + 'Kirbie', + 'Kristyl', + 'Lynzi', + 'Shardai', + 'Yaricza', + 'Tarina', + 'Lynley', + 'Maniah', + 'Arcilia', + 'Keaundra', + 'Karrigan', + 'Madeliene', + 'Lessley', + 'Laurynn', + 'Ragen', + 'Essance', + 'Celsey', + 'Caitlen', + 'Dulse', + 'Sulamita', + 'Evlyn', + 'Dorace', + 'Marciana', + 'Tenecia', + 'Natarsha', + 'Analiza', + 'Ladene', + 'Tatumn', + 'Maricsa', + 'Lysa', + 'Leydi', + 'Limayri', + 'Rebbeca', + 'Amreen', + 'Saina', + 'Remedy', + 'Rael', + 'Nami', + 'Nalini', + 'Naiyah', + 'Moxie', + 'Olina', + 'Whitni', + 'Dayannara', + 'Diara', + 'Arma', + 'Giorgia', + 'Evee', + 'Bricia', + 'Brizeyda', + 'Chihiro', + 'Ayram', + 'Ayushi', + 'Isolde', + 'Husna', + 'Khrystal', + 'Kriston', + 'Raylena', + 'Porschea', + 'Samanthia', + 'Mylinda', + 'Ginelle', + 'Coreena', + 'Aryel', + 'Mallary', + 'Maciel', + 'Kursten', + 'Leandrea', + 'Mackensie', + 'Camri', + 'Itzamara', + 'Aryiah', + 'Alayssa', + 'Andreah', + 'Anberlin', + 'Amrie', + 'Breah', + 'Ryane', + 'Tonna', + 'Valisa', + 'Adryanna', + 'Ajia', + 'Robynne', + 'Brystal', + 'Brylynn', + 'Kaleigha', + 'Danyka', + 'Dannica', + 'Caylen', + 'Jonier', + 'Ruthy', + 'Mada', + 'Vaida', + 'Yeila', + 'Zoelle', + 'Elzora', + 'Samreen', + 'Seylah', + 'Sayla', + 'Allina', + 'Stellarose', + 'Starlett', + 'Simrit', + 'Shina', + 'Bernestine', + 'Tranisha', + 'Tiffanyann', + 'Adamarys', + 'Tylyn', + 'Shahrzad', + 'Addisson', + 'Aeriana', + 'Alaiya', + 'Anni', + 'Ariely', + 'Anvika', + 'Aneya', + 'Bani', + 'Ayame', + 'Ayaka', + 'Aviella', + 'Alabama', + 'Adalyne', + 'Teresea', + 'Ishana', + 'Hargun', + 'Jasnoor', + 'Deby', + 'Dannelle', + 'Swetha', + 'Catherina', + 'Bridgitt', + 'Birgit', + 'Calisi', + 'Defne', + 'Delsa', + 'Demiyah', + 'Cataleah', + 'Icel', + 'Ixel', + 'Jazman', + 'Jessicamarie', + 'Desaree', + 'Chika', + 'Estephani', + 'Dilcia', + 'Dartha', + 'Lesieli', + 'Breyona', + 'Waynette', + 'Verma', + 'Calletana', + 'Cherisa', + 'Casara', + 'Jil', + 'Shella', + 'Renell', + 'Venise', + 'Loura', + 'Kaylia', + 'Leileen', + 'Jessel', + 'Janesa', + 'Kaelly', + 'Julina', + 'Joselinne', + 'Juna', + 'Hazelle', + 'Mauricia', + 'Octaviana', + 'Rumalda', + 'Kataleyah', + 'Kimela', + 'Mosella', + 'Delone', + 'Shemekia', + 'Balinda', + 'Hazell', + 'Deboraha', + 'Gizell', + 'Camilia', + 'Avalina', + 'Audreyana', + 'Baran', + 'Genesee', + 'Elyzabeth', + 'Eliya', + 'Kathyleen', + 'Deeksha', + 'Scherry', + 'Angelyne', + 'Amiliana', + 'Amaira', + 'Jeani', + 'Alysen', + 'Alania', + 'Adiana', + 'Chinyere', + 'Lamesha', + 'Keiley', + 'Lanea', + 'Rosely', + 'Surabhi', + 'Dyanne', + 'Mallika', + 'Tabbatha', + 'Shilpa', + 'Morgyn', + 'Narali', + 'Jenevie', + 'Lovette', + 'Nayleah', + 'Navi', + 'Meili', + 'Nazly', + 'Nethra', + 'Earlee', + 'Layloni', + 'Kiannah', + 'Lilyanah', + 'Liannah', + 'Jaylenn', + 'Jiayi', + 'Kattleya', + 'Kanna', + 'Jimin', + 'Kaleesi', + 'Kailia', + 'Itzy', + 'Itzela', + 'Jasminemarie', + 'Malynda', + 'Jeweline', + 'Eloiza', + 'Carolin', + 'Helma', + 'Arlyle', + 'Giannina', + 'Constancia', + 'Elyce', + 'Montoya', + 'Marline', + 'Krystale', + 'Maghan', + 'Laquitta', + 'Elishia', + 'Aliciana', + 'Maralee', + 'Brunetta', + 'Cybil', + 'Dannell', + 'Cherene', + 'Agueda', + 'Guillerma', + 'Haillie', + 'Bobbe', + 'Gesselle', + 'Esthefany', + 'Sian', + 'Ouita', + 'Sasheen', + 'Abigaile', + 'Demarie', + 'Edwena', + 'Aamiyah', + 'Breaunna', + 'Bryssa', + 'Catlyn', + 'Xaviera', + 'Sierria', + 'Skyelar', + 'Aujanae', + 'Rika', + 'Roshelle', + 'Roxsana', + 'Zonia', + 'Tifanie', + 'Thavy', + 'Teala', + 'Tanea', + 'Loukisha', + 'Melita', + 'Keiona', + 'Maryfer', + 'Delcenia', + 'Akila', + 'Gwenevere', + 'Obdulia', + 'Texana', + 'Licette', + 'Larina', + 'Lany', + 'Yailine', + 'Yomara', + 'Zavia', + 'Sydne', + 'Mariadelourdes', + 'Margeaux', + 'Daneille', + 'Doni', + 'Donalee', + 'Darilyn', + 'Jennfier', + 'Jeanny', + 'Haliegh', + 'Dymon', + 'Callee', + 'Cydni', + 'Daesha', + 'Tamila', + 'Tresha', + 'Mckennah', + 'Shouana', + 'Xcaret', + 'Yeneisy', + 'Yumalai', + 'Ziana', + 'Hanny', + 'Shanisha', + 'Nissi', + 'Mirabel', + 'Miarose', + 'Valerya', + 'Rosalin', + 'Saliha', + 'Samayah', + 'Smriti', + 'Jozette', + 'Gari', + 'Jeanell', + 'Dyann', + 'Vonna', + 'Velina', + 'Salli', + 'Nonie', + 'Olena', + 'Camela', + 'Eufracia', + 'Ethelyne', + 'Yuhan', + 'Silveria', + 'Silvestra', + 'Thressa', + 'Tiahna', + 'Vasti', + 'Calee', + 'Florentine', + 'Sherre', + 'Almira', + 'Zitlalli', + 'Vianne', + 'Yaribeth', + 'Yarelie', + 'Robbye', + 'Jasminne', + 'Sophiah', + 'Saryah', + 'Hermalinda', + 'Sinclaire', + 'Korissa', + 'Lanee', + 'Keeana', + 'Parlee', + 'Luceal', + 'Jetta', + 'Mairani', + 'Tameisha', + 'Haruna', + 'Chasiti', + 'Leighanne', + 'Anaisabel', + 'Aanchal', + 'Alesa', + 'Annisa', + 'Brigitta', + 'Elideth', + 'Chua', + 'Cherrish', + 'Aleece', + 'Maizee', + 'Navie', + 'Philomene', + 'Jilian', + 'Jesi', + 'Kortnie', + 'Beija', + 'Delissa', + 'Shiree', + 'Silbia', + 'Tamura', + 'Aerianna', + 'Abegail', + 'Braniya', + 'Calyn', + 'Carlynn', + 'Anjana', + 'Angelik', + 'Alyzabeth', + 'Amorie', + 'Joannamarie', + 'Kerissa', + 'Kennesha', + 'Laruen', + 'Korrina', + 'Felisitas', + 'Gilma', + 'Essica', + 'Gerarda', + 'Petronila', + 'Dorotea', + 'Maguadalupe', + 'Najla', + 'Loana', + 'Illyana', + 'Amunique', + 'Antwanette', + 'Krystan', + 'Shaniquia', + 'Shanequia', + 'Rainy', + 'Raynesha', + 'Shayleen', + 'Stephanee', + 'Sharaya', + 'Nikkole', + 'Cecille', + 'Christyne', + 'Auriel', + 'Franki', + 'Zelina', + 'Deshanae', + 'Deshawna', + 'Tyneshia', + 'Tyrisha', + 'Deangela', + 'Dynasia', + 'Maigan', + 'Jericka', + 'Jackalyn', + 'Kayln', + 'Ceslie', + 'Bethaney', + 'Samanvi', + 'Saidee', + 'Rosibel', + 'Spirit', + 'Srishti', + 'Varnika', + 'Vanshika', + 'Rosha', + 'Rheya', + 'Yoyo', + 'Veyda', + 'Weslyn', + 'Palak', + 'Sieanna', + 'Riannah', + 'Lovetta', + 'Lota', + 'Florice', + 'Hortence', + 'Zuley', + 'Zoejane', + 'Zemira', + 'Mineola', + 'Senona', + 'Concepsion', + 'Conrada', + 'Dardanella', + 'Rhina', + 'Rubicela', + 'Raissa', + 'Porchea', + 'Latiana', + 'Landy', + 'Monee', + 'Maritssa', + 'Marjani', + 'Meosha', + 'Cecilie', + 'Britanie', + 'Brandilyn', + 'Khrystina', + 'Atenas', + 'Kristeena', + 'Kristell', + 'Kristianne', + 'Angelicia', + 'Alexandera', + 'Jaimy', + 'Jeneffer', + 'Hayde', + 'Vickye', + 'Suzzanne', + 'Susi', + 'Sherrilyn', + 'Sanda', + 'Janeal', + 'Stephnie', + 'Luwana', + 'Shenae', + 'Yaris', + 'Marzell', + 'Lashane', + 'Liandra', + 'Keionna', + 'Korri', + 'Marlet', + 'Marytza', + 'Lorraina', + 'Deepika', + 'Devi', + 'Fion', + 'Darrah', + 'Dalisha', + 'Karessa', + 'Karrisa', + 'Kasara', + 'Ismar', + 'Jacquilyn', + 'Janica', + 'Jeannett', + 'Samanatha', + 'Samra', + 'Sayda', + 'Breklyn', + 'Ashika', + 'Bita', + 'Allysha', + 'Areil', + 'Arlenne', + 'Artelia', + 'Janicia', + 'Corinthia', + 'Angellica', + 'Maygen', + 'Maygan', + 'Odelle', + 'Wenonah', + 'Perfecta', + 'Anjelika', + 'Solmaira', + 'Fredonia', + 'Burgandy', + 'Chelcee', + 'Kellsey', + 'Lyann', + 'Jazmon', + 'Ardie', + 'Latunya', + 'Benetta', + 'Delphina', + 'Ortensia', + 'Obelia', + 'Lurene', + 'Refujia', + 'Noriko', + 'Ladelle', + 'Lella', + 'Shanie', + 'Shawndra', + 'Zell', + 'Zela', + 'Wenda', + 'Troylene', + 'Merrilyn', + 'Kapri', + 'Timesha', + 'Gwendlyn', + 'Jenean', + 'Lamona', + 'Ladana', + 'Cina', + 'Cybele', + 'Eugina', + 'Anjeanette', + 'Vana', + 'Jeneal', + 'Cherlene', + 'Railee', + 'Palin', + 'Yuliet', + 'Rechelle', + 'Sherisse', + 'Pollyanna', + 'Tiphani', + 'Tiffanee', + 'Vanisha', + 'Yurico', + 'Junko', + 'Shannell', + 'Shalise', + 'Kimberlina', + 'Kerra', + 'Shantee', + 'Emmelia', + 'Micala', + 'Lexxus', + 'Candiss', + 'Chauntel', + 'Alese', + 'Margit', + 'Any', + 'Ambur', + 'Chrysta', + 'Janese', + 'Jinny', + 'Zaydee', + 'Makisha', + 'Carola', + 'Marjan', + 'Samanth', + 'Shaquinta', + 'Polette', + 'Riane', + 'Nitasha', + 'Kasarah', + 'Jillianne', + 'Keidra', + 'Karrah', + 'Kaytie', + 'Sondi', + 'Swayzie', + 'Laporcha', + 'Bridgit', + 'Chanika', + 'Antoniette', + 'Jessicia', + 'Francies', + 'Kaizley', + 'Negin', + 'Mistica', + 'Lorenia', + 'Kalise', + 'Kynslie', + 'Dene', + 'Jizel', + 'Jinger', + 'Jayli', + 'Jariya', + 'Joelynn', + 'Haylin', + 'Isabellah', + 'Ciria', + 'Dealva', + 'Barbarita', + 'Prudencia', + 'Wanna', + 'Marieli', + 'Madisynn', + 'Madalyne', + 'Artisha', + 'Everlyn', + 'Cyerra', + 'Liezl', + 'Kabao', + 'Karmina', + 'Kashmir', + 'Nani', + 'Mithra', + 'Mishika', + 'Milynn', + 'Mehr', + 'Marybella', + 'Maisey', + 'Maddy', + 'Lyah', + 'Marnee', + 'Machele', + 'Ladona', + 'Lorilei', + 'Liara', + 'Alahni', + 'Analaya', + 'Amalya', + 'Alyannah', + 'Aayla', + 'Aarini', + 'Arliz', + 'Cyra', + 'Asenet', + 'Avy', + 'Avaree', + 'Ciela', + 'Evangelyn', + 'Kaidynce', + 'Isella', + 'Ilaria', + 'Kattaleya', + 'Laveah', + 'Lareen', + 'Lanah', + 'Deema', + 'Hannaley', + 'Fiora', + 'Eviana', + 'Ellieana', + 'Elisabetta', + 'Dejanira', + 'Manaia', + 'Malibu', + 'Charlsey', + 'Kaytee', + 'Kinberly', + 'Cinderella', + 'Miana', + 'Kimm', + 'Koni', + 'Eraina', + 'Dory', + 'Deette', + 'Nysa', + 'Nyima', + 'Nikitha', + 'Anasophia', + 'Alissandra', + 'Alisi', + 'Corynn', + 'Aubreyana', + 'Anjani', + 'Oliana', + 'Nura', + 'Nihira', + 'Loveda', + 'Gayathri', + 'Kleigh', + 'Ladaisha', + 'Ilette', + 'Jillene', + 'Jalina', + 'Izellah', + 'Tiaira', + 'Mickala', + 'Macarena', + 'Rubina', + 'Shadow', + 'Emillie', + 'Morine', + 'Novell', + 'Oletta', + 'Pura', + 'Winna', + 'Synia', + 'Shyloh', + 'Kaizlee', + 'Raley', + 'Merly', + 'Na', + 'Yenia', + 'Shayanne', + 'Raeana', + 'Tiauna', + 'Tanairy', + 'Georganna', + 'Mahsa', + 'Maiquel', + 'Korena', + 'Yamel', + 'Shamonica', + 'Romesha', + 'Terrisha', + 'Hannan', + 'Hillarie', + 'Feliza', + 'Courtny', + 'Lyndsee', + 'Katelan', + 'Lakedra', + 'Elisabel', + 'Cynthya', + 'Dannah', + 'Darienne', + 'Dejanique', + 'Madalin', + 'Makynzi', + 'Gwendolynn', + 'Alaine', + 'Bridney', + 'Kimorah', + 'Klee', + 'Kynedi', + 'Loreley', + 'Parthenia', + 'Aubryana', + 'Aryannah', + 'Edeline', + 'Elen', + 'Raguel', + 'Marizela', + 'Michella', + 'Haasini', + 'Tristine', + 'Elis', + 'Pattye', + 'Tanishia', + 'Jenel', + 'Jurea', + 'Laini', + 'Britania', + 'Christabelle', + 'Dafney', + 'Laterica', + 'Angelmarie', + 'Asuzena', + 'Aleea', + 'Teneka', + 'Yicel', + 'Malisha', + 'Prairie', + 'Makelle', + 'Shaelee', + 'Dafina', + 'Hisaye', + 'Adayah', + 'Alexsia', + 'Allysen', + 'Takako', + 'Thamara', + 'Trinitie', + 'Shaneen', + 'Sueellen', + 'Telma', + 'Meyah', + 'Rorie', + 'Preslea', + 'Elbia', + 'Ginna', + 'Marja', + 'Marites', + 'Neisha', + 'Shir', + 'Shastelyn', + 'Saraih', + 'Unity', + 'Makinna', + 'Franchelle', + 'Azadeh', + 'Charito', + 'Joli', + 'Amyrah', + 'Sharlee', + 'Jasey', + 'Kortlynn', + 'Kiari', + 'Kyria', + 'Eleina', + 'Elany', + 'Daleah', + 'Sumi', + 'Kileigh', + 'Lorianna', + 'Macady', + 'Naviah', + 'Mattilyn', + 'Raylyn', + 'Bridgitte', + 'Hasina', + 'Johnelle', + 'Gwendlyon', + 'Itxel', + 'Iyanah', + 'Jeidy', + 'Jaidynn', + 'Jaslynne', + 'Zoii', + 'Tensley', + 'Yolando', + 'Keyarah', + 'Keyri', + 'Katherinne', + 'Thersa', + 'Sinahi', + 'Secret', + 'Vivika', + 'Yobana', + 'Hailley', + 'Haliey', + 'Isys', + 'Deyla', + 'Kassidee', + 'Jalie', + 'Florestela', + 'Cyla', + 'Samyuktha', + 'Libni', + 'Laritza', + 'Breannah', + 'Breya', + 'Keelin', + 'Jarelly', + 'Jenyfer', + 'Julyanna', + 'Kaetlyn', + 'Mixtli', + 'Mykaila', + 'Nasia', + 'Judieth', + 'Misako', + 'Bre', + 'Shaley', + 'Gelila', + 'Aariana', + 'Laquetta', + 'Shizu', + 'Annay', + 'Annai', + 'Breeze', + 'Mahum', + 'Harsimran', + 'Helaina', + 'Alexza', + 'Tangelia', + 'Shellye', + 'Blondena', + 'Keva', + 'Suzzane', + 'Vallorie', + 'Absidy', + 'Alis', + 'Alexxia', + 'Allura', + 'Ariba', + 'Annete', + 'Anett', + 'Deyanara', + 'Ellise', + 'Majorie', + 'Hibah', + 'Chaselyn', + 'Hennesy', + 'Gayatri', + 'Kathelyn', + 'Caylah', + 'Athyna', + 'Arpita', + 'Ciclaly', + 'Emmamarie', + 'Virjinia', + 'Tyna', + 'Cyd', + 'Glennda', + 'Littie', + 'Orlean', + 'Derinda', + 'Hether', + 'Clata', + 'Pleshette', + 'Maricelda', + 'Charmin', + 'Matsuye', + 'Tamitha', + 'Armanda', + 'Sayaka', + 'Lacresia', + 'Demonica', + 'Skie', + 'Trynity', + 'Sereena', + 'Shefali', + 'Rewa', + 'Reshonda', + 'Yalanda', + 'Anissia', + 'Layni', + 'Paolina', + 'Manaal', + 'Mariali', + 'Merina', + 'Milenia', + 'Millenia', + 'Moncerrath', + 'Monzerrath', + 'Kaydie', + 'Adianna', + 'Toluwalase', + 'Trysta', + 'Ainsleigh', + 'Alianah', + 'Meuy', + 'Meloney', + 'Talea', + 'Sheetal', + 'Shalana', + 'Venesa', + 'Teana', + 'Kiki', + 'Imee', + 'Aubryanna', + 'Allyanna', + 'Ambrie', + 'Amory', + 'Aniyha', + 'Caelynn', + 'Reita', + 'Rylann', + 'Aijah', + 'Aaliyha', + 'Alezandra', + 'Yeraldine', + 'Forestine', + 'Sameeha', + 'Caeley', + 'Britzy', + 'Blessin', + 'Armilda', + 'Birda', + 'Lorrine', + 'Krisalyn', + 'Linell', + 'Maryl', + 'Karole', + 'Maryela', + 'Mckinzy', + 'Madailein', + 'Kendi', + 'Kayda', + 'Jenasis', + 'Madelis', + 'Jamyiah', + 'Gabryela', + 'Catie', + 'Genessa', + 'Jamelia', + 'Jenene', + 'Nicholl', + 'Saralyn', + 'Taylah', + 'Xandra', + 'Jezlyn', + 'Zakayla', + 'Jaira', + 'Veena', + 'Shaden', + 'Sahiti', + 'Sahian', + 'Shelsey', + 'Sreya', + 'Zianna', + 'Angeleah', + 'Camily', + 'Lesvia', + 'Sonda', + 'Franceska', + 'Cytlaly', + 'Ylonda', + 'Issis', + 'Moon', + 'Joei', + 'Mariposa', + 'Ramandeep', + 'Preeti', + 'Niobe', + 'Sherran', + 'Nichola', + 'Letrice', + 'Waneda', + 'Meka', + 'Takeshia', + 'Leaann', + 'Girlie', + 'Olar', + 'Pearlena', + 'Carlean', + 'Dhanya', + 'Chastelin', + 'Aryanah', + 'Brihana', + 'Bijou', + 'Haifa', + 'Genesiss', + 'Genavie', + 'Enna', + 'Jazzel', + 'Japleen', + 'Iana', + 'Rahel', + 'Rylyn', + 'Pragya', + 'Yosselyn', + 'Yarelin', + 'Ellasyn', + 'Charlaine', + 'Zayli', + 'Taide', + 'Jodean', + 'Emilynn', + 'Channon', + 'Carinne', + 'Anaira', + 'Amisadai', + 'Caraline', + 'Danella', + 'Debanhy', + 'Devanee', + 'Koneta', + 'Jenie', + 'Hollee', + 'Marelie', + 'Mahathi', + 'Madilynne', + 'Lylia', + 'Loreli', + 'Lolah', + 'Lexine', + 'Maylynn', + 'Clarinda', + 'Marlynn', + 'Netra', + 'Makaylin', + 'Naira', + 'Naleah', + 'Mishel', + 'Myli', + 'Charlotta', + 'Arlisa', + 'Kaylynne', + 'Kamillah', + 'Ksenia', + 'Briseidy', + 'Aysel', + 'Anaily', + 'Eulean', + 'Adilee', + 'Abri', + 'Aidynn', + 'Alisyn', + 'Alicen', + 'Marveline', + 'Lupie', + 'Mariabelen', + 'Makenah', + 'Kyliegh', + 'Foye', + 'Yajahira', + 'Trenda', + 'Tya', + 'Nattaly', + 'Netanya', + 'Supriya', + 'Teja', + 'Srija', + 'Sherra', + 'Janissa', + 'Mysha', + 'Essfa', + 'Alexandrya', + 'Abi', + 'Takhia', + 'Jaeli', + 'Jaelynne', + 'Dianey', + 'Denisa', + 'Aleli', + 'Akina', + 'Aayushi', + 'Adanna', + 'Aunika', + 'Ithzel', + 'Caricia', + 'Kallyn', + 'Karmin', + 'Kindall', + 'Gredmarie', + 'Peace', + 'Jennalee', + 'Yaindhi', + 'Arcola', + 'Trannie', + 'Lyza', + 'Mackynzie', + 'Peggye', + 'Zenab', + 'Megyn', + 'Navina', + 'Naileah', + 'Maddelyn', + 'Luxe', + 'Arkie', + 'Belvia', + 'Edilia', + 'Monda', + 'Ridhi', + 'Peyten', + 'Sorayah', + 'Syrena', + 'Amberle', + 'Johnita', + 'Jerrye', + 'Alfa', + 'Jonita', + 'Lakie', + 'Jenalee', + 'Minami', + 'Morena', + 'Elsbeth', + 'Sylia', + 'Eunique', + 'Ellisa', + 'Lanai', + 'Jesselyn', + 'Jolissa', + 'Julizza', + 'Laquitha', + 'Jobina', + 'Wyvonne', + 'Shalese', + 'Deshannon', + 'Almendra', + 'Alisandra', + 'Geraldene', + 'Abygale', + 'Katelyne', + 'Kennede', + 'Karisia', + 'Lindzy', + 'Keyhla', + 'Emilea', + 'Dacey', + 'Jalah', + 'Adrienna', + 'Aisa', + 'Alaisha', + 'Brithney', + 'Calynn', + 'Cassity', + 'Brendy', + 'Reagen', + 'Myrah', + 'Montserrath', + 'Pheobe', + 'Nyeli', + 'Jocell', + 'Serenidy', + 'Issabela', + 'Hanalei', + 'Laelah', + 'Emmylou', + 'Geraldy', + 'Ovetta', + 'Analena', + 'Allyna', + 'Aliyanah', + 'Magdalyn', + 'Suann', + 'Ronee', + 'Amey', + 'Chirstina', + 'Trude', + 'Jearldine', + 'Maeleigh', + 'Lizzy', + 'Liviana', + 'Eithel', + 'Meryem', + 'Yaneisy', + 'Shatika', + 'Zeniyah', + 'Xaylee', + 'Pennelope', + 'Xochilth', + 'Jullie', + 'Saki', + 'Shaiann', + 'Haille', + 'Dannya', + 'Kerie', + 'Chianti', + 'Leza', + 'Koreen', + 'Letricia', + 'Lamanda', + 'Kinza', + 'Marisella', + 'Joelyn', + 'Cinde', + 'Chyrl', + 'Cece', + 'Boni', + 'Felecity', + 'Faithe', + 'Delayna', + 'Diamon', + 'Daley', + 'Darah', + 'France', + 'Kolina', + 'Kieu', + 'Grizel', + 'Shaleigh', + 'Shaylea', + 'Anitza', + 'Carrolyn', + 'Olimpia', + 'Jeannene', + 'Victoriana', + 'Azara', + 'Avelynn', + 'Aveah', + 'Ariam', + 'Devanie', + 'Daleisa', + 'Karelly', + 'Karalynn', + 'Keyleen', + 'Kendallyn', + 'Graceyn', + 'Falynn', + 'Evoleht', + 'Everlie', + 'Emri', + 'Hartlee', + 'Eleena', + 'Jailee', + 'Insiya', + 'Analysia', + 'Chalee', + 'Amzie', + 'Amilya', + 'Celisa', + 'Airabella', + 'Laketha', + 'Kyoko', + 'Saria', + 'Neli', + 'Melonee', + 'Neidy', + 'Nyanza', + 'Aizlynn', + 'Arthurine', + 'Mikhaela', + 'Adalae', + 'Parveen', + 'Lotoya', + 'Evanjelina', + 'Deborra', + 'Lunna', + 'Makylah', + 'Mckinleigh', + 'Mayalen', + 'Ladasia', + 'Javia', + 'Evian', + 'Jaelee', + 'Oluwatamilore', + 'Payzlee', + 'Reiley', + 'Samarra', + 'Chyler', + 'Areona', + 'Vanesha', + 'Tomisha', + 'Betzaira', + 'Dalana', + 'Destenie', + 'Brennah', + 'Cassidie', + 'Deziray', + 'Dimond', + 'Braeleigh', + 'Aylee', + 'Anastyn', + 'Amillia', + 'Jailyne', + 'Jissell', + 'Jailenne', + 'Inioluwa', + 'Jensyn', + 'Allia', + 'Evolett', + 'Emmalynne', + 'Emberlee', + 'Emaline', + 'Ellayna', + 'Kollins', + 'Keyly', + 'Livi', + 'Judeen', + 'Eleah', + 'Vonceil', + 'Kaaliyah', + 'Girtie', + 'Gianelle', + 'Iniya', + 'Harlynn', + 'Greidy', + 'Shayli', + 'Belina', + 'Auri', + 'Avangeline', + 'Alizey', + 'Arlynn', + 'Anelise', + 'Aneli', + 'Delmira', + 'Vanassa', + 'Ceana', + 'Ambre', + 'Florita', + 'Balbina', + 'Clova', + 'Danice', + 'Aydee', + 'Carlena', + 'Benicia', + 'Soumya', + 'Lissandra', + 'Ling', + 'Liahna', + 'Leonna', + 'Leilana', + 'Reeya', + 'Krisinda', + 'Maleiah', + 'Maiyah', + 'Mailin', + 'Lucciana', + 'Naydeen', + 'Nailani', + 'Miette', + 'Yeva', + 'Suley', + 'Shravya', + 'Kyia', + 'Shree', + 'Cerise', + 'Katriana', + 'Jaskiran', + 'Mone', + 'Latijera', + 'Rosicela', + 'Sidnee', + 'Rosisela', + 'Troi', + 'Victorya', + 'Creasie', + 'Latorsha', + 'Erienne', + 'Jovonna', + 'Jessia', + 'Jeny', + 'Dejia', + 'Destynie', + 'Barbi', + 'Marlinda', + 'Shakeitha', + 'Mistelle', + 'Ziona', + 'Zarahi', + 'Xiadani', + 'Zyrah', + 'Zoriah', + 'Pamla', + 'Cinamon', + 'Bernardette', + 'Makensie', + 'Lexani', + 'Miyana', + 'Costella', + 'Cliffie', + 'Lashune', + 'Windie', + 'Rhondalyn', + 'Avonelle', + 'Marcine', + 'Berneda', + 'Rosabelle', + 'Huldah', + 'Emagene', + 'Clarabell', + 'Marceil', + 'Ula', + 'Renika', + 'Shaterica', + 'Labrittany', + 'Zelia', + 'Aidy', + 'Abeeha', + 'Maebelle', + 'Farzona', + 'Bryelle', + 'Aphrodite', + 'Diyora', + 'Zilphia', + 'Ercell', + 'Starlynn', + 'Renad', + 'Reham', + 'Marwah', + 'Raaina', + 'Mehreen', + 'Chermaine', + 'Ameliah', + 'Hajra', + 'Anamika', + 'Caoimhe', + 'Tasheka', + 'Cladie', + 'Claretta', + 'Ratzy', + 'Parizoda', + 'Tzurty', + 'Simrah', + 'Miamor', + 'Mala', + 'Yittel', + 'Ranata', + 'Clellie', + 'Dewana', + 'Kenyada', + 'Sennie', + 'Estie', + 'Oprah', + 'Chessie', + 'Rumaisa', + 'Rosmery', + 'Shenell', + 'Cosima', + 'Ellyanna', + 'Hebe', + 'Aamira', + 'Beily', + 'Areesha', + 'Amilah', + 'Mahdiya', + 'Ramata', + 'Naava', + 'Cannie', + 'Dorraine', + 'Verlee', + 'Anija', + 'Garnita', + 'Lorenda', + 'Mikia', + 'Marvella', + 'Sharma', + 'Pamula', + 'Anmarie', + 'Valicia', + 'Collene', + 'Ronetta', + 'Floris', + 'Andora', + 'Berdina', + 'Ivadell', + 'Lorain', + 'Kevinisha', + 'Corielle', + 'Rinda', + 'Jodelle', + 'Arta', + 'Kalima', + 'Kalifa', + 'Liat', + 'Dashawna', + 'Jahnae', + 'Eylin', + 'Tahmina', + 'Sherin', + 'Niambi', + 'Tonjua', + 'Hanifah', + 'Maham', + 'Sokhna', + 'Carliss', + 'Nimra', + 'Quianna', + 'Shadai', + 'Renella', + 'Eliska', + 'Alima', + 'Agata', + 'Adenike', + 'Charizma', + 'Shirlean', + 'Joycelin', + 'Cyanne', + 'Ambika', + 'Albana', + 'Noshin', + 'Merve', + 'Sanjida', + 'Khiabet', + 'Maudrey', + 'Manuella', + 'Linder', + 'Bisma', + 'Shataya', + 'Shandel', + 'Samanthamarie', + 'Liron', + 'Liann', + 'Merdis', + 'Daquana', + 'Chanee', + 'Ezora', + 'Janiqua', + 'Jamielyn', + 'Kyesha', + 'Eulalie', + 'Montressa', + 'Alzina', + 'Monez', + 'Casmira', + 'Eileene', + 'Ethelmae', + 'Veneta', + 'Madiha', + 'Akeema', + 'Daneisha', + 'Cecely', + 'Gwendola', + 'Javonna', + 'Teshia', + 'Yaniris', + 'Valbona', + 'Corita', + 'Deshanna', + 'Kameka', + 'Armina', + 'Georgian', + 'Shakeera', + 'Saudia', + 'Stacyann', + 'Shenique', + 'Ura', + 'Felicie', + 'Ezola', + 'Janeece', + 'Chavely', + 'Ashling', + 'Nakea', + 'Shiana', + 'Shadasia', + 'Petronella', + 'Virgin', + 'Gunhild', + 'Brianni', + 'Grainne', + 'Aneisha', + 'Chaniece', + 'Zalika', + 'Tynasia', + 'Tashauna', + 'Shazia', + 'Shatiqua', + 'Sharissa', + 'Shanyce', + 'Shandell', + 'Shakeyla', + 'Vergia', + 'Geraldyne', + 'Dorita', + 'Nathasha', + 'Samanthajo', + 'Amela', + 'Afnan', + 'Halimah', + 'Dayatra', + 'Shontrell', + 'Tziry', + 'Shanyah', + 'Shawntell', + 'Schwanda', + 'Magalene', + 'Si', + 'Ramisa', + 'Ioanna', + 'Imane', + 'Hadar', + 'Ettel', + 'Coumba', + 'Chumy', + 'Shiran', + 'Lianny', + 'Kimara', + 'Nicha', + 'Chestine', + 'Fatmata', + 'Chedva', + 'Shaima', + 'Shailyn', + 'Zarin', + 'Zahrah', + 'Wania', + 'Tsering', + 'Syrai', + 'Suriyah', + 'No', + 'Niylah', + 'Meerab', + 'Emanuela', + 'Draizy', + 'Giabella', + 'Jeily', + 'Sofya', + 'Shantrelle', + 'Analisse', + 'Ramatoulaye', + 'Raima', + 'Sumaiyah', + 'Stori', + 'Tremeka', + 'Beila', + 'Clodagh', + 'Lyniah', + 'Giavana', + 'Tikisha', + 'Kesia', + 'Shawan', + 'Mazelle', + 'Lear', + 'Rosilyn', + 'Jnaya', + 'Jahnia', + 'Shi', + 'Henya', + 'Jhoselyn', + 'Doha', + 'Dilara', + 'Adelisa', + 'Dedria', + 'Troylynn', + 'Basha', + 'Fatimata', + 'Ama', + 'Ashantee', + 'Chania', + 'Donzella', + 'Ya', + 'Fahmida', + 'Iysis', + 'Neviah', + 'Anastasiya', + 'Brandel', + 'Afra', + 'Lendora', + 'Zisel', + 'Dwanda', + 'Ciarah', + 'Brighid', + 'Rafia', + 'Keamber', + 'Virdie', + 'Girtrude', + 'Nakaya', + 'Donis', + 'Anslei', + 'Alyene', + 'Audell', + 'Nahriah', + 'Zakeria', + 'Zoria', + 'Nikeria', + 'Kynley', + 'Karaline', + 'Jacquita', + 'Shonteria', + 'Carlyon', + 'Tykira', + 'Nykerria', + 'Lema', + 'Destyne', + 'Kansas', + 'Aryonna', + 'Iyannah', + 'Jamayah', + 'Serenitee', + 'Jood', + 'Willean', + 'Makyah', + 'Kameria', + 'Shelagh', + 'Zarriah', + 'Avionna', + 'Arilynn', + 'Vira', + 'Lelar', + 'Miyonna', + 'Jaionna', + 'Nakiah', + 'Rubby', + 'Henrene', + 'Perlie', + 'Tanyah', + 'Luretha', + 'Fannye', + 'Arquilla', + 'Albirta', + 'Annakate', + 'Akeria', + 'Teola', + 'Darthy', + 'Amberleigh', + 'Floriene', + 'Alleyne', + 'Karra', + 'Shaneika', + 'Nekita', + 'Niketa', + 'Kiaraliz', + 'Anacarolina', + 'Sharonica', + 'Renota', + 'Shambrica', + 'Mylea', + 'Jalicia', + 'Shantavious', + 'Antania', + 'Derika', + 'Rashunda', + 'Shandrea', + 'Teneisha', + 'Wachovia', + 'Jalecia', + 'Leimomi', + 'Lasondra', + 'Tela', + 'Caleah', + 'Iwalani', + 'Jamyri', + 'Azyria', + 'Napua', + 'Lahela', + 'Lehuanani', + 'Lameka', + 'Davelyn', + 'Filippa', + 'Tywanna', + 'Toini', + 'Pota', + 'Berthe', + 'Aliesha', + 'Iolanda', + 'Seaira', + 'Kealohilani', + 'Leialoha', + 'Chastidy', + 'Taimane', + 'Taylorann', + 'Briunna', + 'Tyrielle', + 'Alohilani', + 'Jakala', + 'Lakendria', + 'Tiffinie', + 'Laprecious', + 'Kaylaann', + 'Marigny', + 'Roise', + 'Kaidance', + 'Niyla', + 'Mahari', + 'Zya', + 'Ruthia', + 'Timara', + 'Caniya', + 'Keirah', + 'Arieonna', + 'Alydia', + 'Alivea', + 'Ahmani', + 'Elynn', + 'Earnstine', + 'Ramiya', + 'Morrigan', + 'Masiyah', + 'Harmoney', + 'Pearley', + 'Jearlean', + 'Korrine', + 'Chyanna', + 'Catena', + 'Pacita', + 'Kalle', + 'Alzira', + 'Tashayla', + 'Tsugie', + 'Yachiyo', + 'Shellia', + 'Sueno', + 'Kazuyo', + 'Kikumi', + 'Shizuka', + 'Chiyono', + 'Shigeno', + 'Tatsue', + 'Fumiyo', + 'Misayo', + 'Momoyo', + 'Hanayo', + 'Misae', + 'Dalaney', + 'Dewanda', + 'Itsuko', + 'Nyamal', + 'Claris', + 'Virlee', + 'Lulabelle', + 'Valada', + 'Neleigh', + 'Rafelita', + 'Placida', + 'Dulcinea', + 'Pita', + 'Heer', + 'Beren', + 'Ramoncita', + 'Orlinda', + 'Florette', + 'Deluvina', + 'Lugarda', + 'Crucita', + 'Rafaelita', + 'Pablita', + 'Lamaria', + 'Terriana', + 'Terrianna', + 'Dariyah', + 'Carmie', + 'Clotine', + 'Antha', + 'Takyla', + 'Peachie', + 'Akirah', + 'Captola', + 'Sadeel', + 'Dosha', + 'Miquela', + 'Anilah', + 'Erielle', + 'Janiylah', + 'Aubriel', + 'Priti', + 'Purvi', + 'Shakeemah', + 'Anjail', + 'Shaheerah', + 'Amneris', + 'Melverine', + 'Twilla', + 'Kruti', + 'Jalee', + 'Shareefah', + 'Muslimah', + 'Tauheedah', + 'Anabela', + 'Yakima', + 'Lyllian', + 'Tanajah', + 'Sakiyah', + 'Eun', + 'Yashika', + 'Ji', + 'Demiana', + 'Mariaeduard', + 'Snigdha', + 'Dala', + 'Kum', + 'Myung', + 'Hadiyah', + 'Gopi', + 'Cresta', + 'In', + 'Davita', + 'Talayeh', + 'Tracyann', + 'Petula', + 'Nerida', + 'Jeaneen', + 'Ilissa', + 'Letta', + 'Kishia', + 'Gesenia', + 'Bethsaida', + 'Tanija', + 'Ivelise', + 'Marines', + 'Angenette', + 'Alanda', + 'Lauraann', + 'Darnetta', + 'Alisande', + 'Jeniya', + 'Patria', + 'Tieysha', + 'Tasheen', + 'Ife', + 'Loredana', + 'Amyjo', + 'Chane', + 'Nilka', + 'Sharema', + 'Grazia', + 'Renna', + 'Tahesha', + 'Tarita', + 'Jannis', + 'Geriann', + 'Areatha', + 'Rosangel', + 'Kemba', + 'Noni', + 'Margaretann', + 'Kimberleigh', + 'Latisa', + 'Kiriaki', + 'Bobbyjo', + 'Walida', + 'Lynanne', + 'Niyanna', + 'Daziah', + 'Kharma', + 'Pier', + 'Marymargaret', + 'Lorrain', + 'Ketty', + 'Helane', + 'Tarnisha', + 'Sherrice', + 'Swati', + 'Donnajean', + 'Tunya', + 'Annmargaret', + 'Raffaella', + 'Pina', + 'Deneene', + 'Lorriane', + 'Shenise', + 'Ziyonna', + 'Evagelia', + 'Chantae', + 'Tasheema', + 'Meaghen', + 'Shanikqua', + 'Lynnox', + 'Taiesha', + 'Sharima', + 'Shantai', + 'Shaena', + 'Jamine', + 'Rasheena', + 'Tashi', + 'Magdala', + 'Edia', + 'Lasheka', + 'Tiasha', + 'Quanita', + 'Jomayra', + 'Nairoby', + 'Danamarie', + 'Roena', + 'Zasha', + 'Shatema', + 'Orissa', + 'Elvire', + 'Louisiana', + 'Hoda', + 'Kashana', + 'Jaquanna', + 'Jacqulin', + 'Annamari', + 'Marquia', + 'Elmire', + 'Viney', + 'Sonna', + 'Yokasta', + 'Esma', + 'Rella', + 'Deloras', + 'Janill', + 'Samanthan', + 'Ketsia', + 'Chaunte', + 'Aderonke', + 'Sheindel', + 'Shameen', + 'Karema', + 'Amalin', + 'Glendaliz', + 'Finesse', + 'Talibah', + 'Lakima', + 'Geeta', + 'Suehay', + 'Dorice', + 'Aesha', + 'Lateasha', + 'Kimitra', + 'Omolola', + 'Bobbette', + 'Deliah', + 'Carianne', + 'Chanah', + 'Laquandra', + 'Laquanna', + 'Yanick', + 'Nathifa', + 'Nakima', + 'Gayl', + 'Shamaine', + 'Saquana', + 'Nixzaliz', + 'Chaye', + 'Maleka', + 'Latima', + 'Yamira', + 'Tashanna', + 'Kathiria', + 'Jameika', + 'Jamesetta', + 'Moniqua', + 'Yamaris', + 'Tasheba', + 'Virgina', + 'Aviance', + 'Calogera', + 'Candita', + 'Kinga', + 'Alissia', + 'Onnolee', + 'Johnda', + 'Sebastiana', + 'Michelena', + 'Tecla', + 'Mirriam', + 'Sydel', + 'Glema', + 'Tatiyanna', + 'Patrycia', + 'Fortuna', + 'Ebba', + 'Carmelia', + 'Liddie', + 'Genella', + 'Detta', + 'Malvery', + 'Evelene', + 'Loretto', + 'Nunziata', + 'Jenan', + 'Keshawna', + 'Kinisha', + 'Tikia', + 'Sueanne', + 'Cira', + 'Charda', + 'Midge', + 'Annina', + 'Delcina', + 'Barbette', + 'Danah', + 'Isolina', + 'Tanita', + 'Gracemarie', + 'Halleigh', + 'Julita', + 'Kaprice', + 'Dorothyann', + 'Binnie', + 'Bettyjean', + 'Frayda', + 'Tashiana', + 'Breshey', + 'Charnise', + 'Tashena', + 'Meribeth', + 'Sandralee', + 'Heena', + 'Walda', + 'Latika', + 'Rashaunda', + 'Linde', + 'Rosaleen', + 'Illona', + 'Clydette', + 'Benay', + 'Damonica', + 'Anajah', + 'Louelle', + 'Lunette', + 'Faduma', + 'Nadeige', + 'Meylin', + 'Elverna', + 'Etrulia', + 'Ellaree', + 'Rushie', + 'Jayona', + 'Mauri', + 'Radiah', + 'Runette', + 'Terrah', + 'Joia', + 'Ezma', + 'Glenys', + 'Ramla', + 'Shatasha', + 'Berma', + 'Chanteria', + 'Chantrell', + 'Elvi', + 'Sharnell', + 'Rether', + 'Keshana', + 'Ranesha', + 'Earther', + 'Zahirah', + 'Anye', + 'Khori', + 'Saniyyah', + 'Teniola', + 'Anniemae', + 'Oluwadamilola', + 'Aldene', + 'Amellia', + 'Junice', + 'Carolene', + 'Ireoluwa', + 'Nasra', + 'Vernease', + 'Delrose', + 'Marysue', + 'Mirlande', + 'Lashannon', + 'Taijah', + 'Markiesha', + 'Syanne', + 'Jahiya', + 'Vyonne', + 'Reniya', + 'Ryana', + 'Idonia', + 'Loette', + 'Etheleen', + 'Ariyon', + 'Jeneane', + 'Jamea', + 'Airyana', + 'Natesha', + 'Bonnell', + 'Savilla', + 'Daneshia', + 'Deneshia', + 'Alexzandrea', + 'Martharee', + 'Elfreda', + 'Danyla', + 'Retaj', + 'Childnotnamed', + 'Kariana', + 'Ladeja', + 'Johnesha', + 'Nariya', + 'Zamariah', + 'Shanyla', + 'Zykiria', + 'Micaella', + 'Angeliyah', + 'Camara', + 'Kenniyah', + 'Keyani', + 'Renie', + 'Aldena', + 'Paytyn', + 'Perma', + 'Annamary', + 'Roniyah', + 'Zeniya', + 'Capitola', + 'Jaiana', + 'Lakiya', + 'Reida', + 'Ahniya', + 'Elanor', + 'Dorothee', + 'Joud', + 'Ludmilla', + 'Traniyah', + 'Kjerstin', + 'Jeylin', + 'Teona', + 'Marypat', + 'Jacquelynne', + 'Harmonii', + 'Kenyah', + 'Anora', + 'Deniyah', + 'Tyleah', + 'Samora', + 'Almeter', + 'Floride', + 'Lether', + 'Aviah', + 'Livie', + 'Federica', + 'Khalani', + 'Dericka', + 'Ronisue', + 'Raziah', + 'Emaya', + 'Christyana', + 'Rasheka', + 'Jahira', + 'Jalana', + 'Lateria', + 'Baneen', + 'Davisha', + 'Joyanna', + 'Janelys', + 'Raneisha', + 'Israa', + 'Shauntavia', + 'Shericka', + 'Deloma', + 'Maryetta', + 'Jeannetta', + 'Tymber', + 'Charmon', + 'Lanise', + 'Charlisa', + 'Bloneva', + 'Andrena', + 'Katena', + 'Latorria', + 'Letoya', + 'Quovadis', + 'Lakeisa', + 'Sihaam', + 'Charo', + 'Annaclara', + 'Margretta', + 'Nataki', + 'Tyjae', + 'Bahja', + 'Shequila', + 'Quadira', + 'Toinette', + 'Sumeya', + 'Takita', + 'Sherlonda', + 'Daejah', + 'Zyanna', + 'Antonique', + 'Linnae', + 'Georgean', + 'Charlane', + 'Jakerria', + 'Nimo', + 'Saprina', + 'Detrice', + 'Nicolly', + 'Nayara', + 'Seandra', + 'Demetrica', + 'Kayton', + 'Jalayna', + 'Emanuelly', + 'Dondra', + 'Michaeleen', + 'Aquinnah', + 'Lakrisha', + 'Latoia', + 'Bernessia', + 'Jaydaliz', + 'Deona', + 'Donyelle', + 'Kearsten', + 'Tashira', + 'Kaisa', + 'Korrin', + 'Onelia', + 'Shawntia', + 'Faylene', + 'Nafeesah', + 'Synetta', + 'Robertine', + 'Krystn', + 'Nyjae', + 'Nijae', + 'Cieara', + 'Ellerie', + 'Thomasenia', + 'Tiki', + 'Lougenia', + 'Joeann', + 'Marlyss', + 'Saralee', + 'Dayona', + 'Alainna', + 'Gennell', + 'Berline', + 'Latoiya', + 'Eyvonne', + 'Cherline', + 'Tequesta', + 'Loann', + 'Kerstyn', + 'Najmo', + 'Shanitra', + 'Marnice', + 'Tamyah', + 'Ave', + 'Cierrah', + 'Deborahann', + 'Davette', + 'Kennidy', + 'Breelle', + 'Lundon', + 'Imoni', + 'Shamyah', + 'Lindia', + 'Caylyn', + 'Ghadeer', + 'Amirrah', + 'Arlayne', + 'Norrine', + 'Vondell', + 'Ruqaya', + 'Azariya', + 'Narice', + 'Glenadine', + 'Lallie', + 'Conola', + 'Airlie', + 'Lorelie', + 'Levis', + 'Sanyia', + 'Mckaela', + 'Arlina', + 'Dellar', + 'Zorianna', + 'Zanyiah', + 'Maleya', + 'Niyana', + 'Amonie', + 'Aryia', + 'Autie', + 'Keileigh', + 'Kyndel', + 'Saliyah', + 'Naziah', + 'Bernette', + 'Vona', + 'Venie', + 'Tyashia', + 'Khaliya', + 'Mckensie', + 'Kerigan', + 'Kaniah', + 'Eria', + 'Maziyah', + 'Kiasia', + 'Anice', + 'Dera', + 'Georgena', + 'Ezelle', + 'Eavan', + 'Marlyne', + 'Lovella', + 'Westonia', + 'Keniah', + 'Janiaya', + 'Mertice', + 'Marget', + 'Zyeria', + 'Marquerite', + 'Minha', + 'Redonna', + 'Deetta', + 'Aiyla', + 'Majel', + 'Elnor', + 'Deronda', + 'Viona', + 'Rosaleigh', + 'Virgiline', + 'Reeda', + 'Minnah', + 'Keerthi', + 'Kaleyah', + 'Myanna', + 'Remas', + 'Noralee', + 'Idabelle', + 'Albena', + 'Ellory', + 'Areej', + 'Zariel', + 'Laverle', + 'Hjordis', + 'Hilja', + 'Ragna', + 'Cordella', + 'Irean', + 'Ottilia', + 'Gerane', + 'Locklyn', + 'Equilla', + 'Dellie', + 'Aarvi', + 'Mardella', + 'Leighanna', + 'Theone', + 'Ordella', + 'Lidwina', + 'Alyda', + 'Arlyss', + 'Evangelita', + 'Hee', + 'Cherell', + 'Charelle', + 'Shealynn', + 'Anesha', + 'Jasman', + 'Stephie', + 'Ok', + 'Tacarra', + 'Sharnita', + 'Jessic', + 'Dulcey', + 'Natina', + 'Sharvae', + 'Nachelle', + 'Jillane', + 'Tarri', + 'Ajena', + 'Allexus', + 'Labrenda', + 'Pammy', + 'Shemeika', + 'Ysela', + 'Meghin', + 'Marketta', + 'Porshe', + 'Kayti', + 'Taylour', + 'Shavonte', + 'Aivah', + 'Khloi', + 'Jerzie', + 'Nikesha', + 'Cherron', + 'Coralynn', + 'Alvita', + 'Carlita', + 'Albany', + 'Deshawnda', + 'Lacole', + 'Lameeka', + 'Mashawn', + 'Kimyata', + 'Keenya', + 'Baya', + 'Kiva', + 'Samona', + 'Meggin', + 'Chanita', + 'Danissa', + 'Lileigh', + 'Addeline', + 'Shemeeka', + 'Aprille', + 'Donice', + 'Tannisha', + 'Angelette', + 'Lakeita', + 'Marcelyn', + 'Lesta', + 'Claudene', + 'Marney', + 'Tonyia', + 'Nellora', + 'Kimyetta', + 'Ameliana', + 'Electa', + 'Sherl', + 'Jeniece', + 'Jawana', + 'Errica', + 'Braya', + 'Titania', + 'Guydra', + 'Valeta', + 'Danetta', + 'Sharia', + 'Hawraa', + 'Danaja', + 'Makalynn', + 'Tayonna', + 'Kyrene', + 'Arieona', + 'Dallie', + 'Ruie', + 'Ophia', + 'Odella', + 'Vessie', + 'Offie', + 'Evadean', + 'Ample', + 'Aleecia', + 'Shakyla', + 'Makynna', + 'Lakyra', + 'Korryn', + 'Araina', + 'Semiyah', + 'Ndea', + 'Areonna', + 'Jasia', + 'Xavia', + 'Merikay', + 'Keshara', + 'Jennetta', + 'Vergene', + 'Wilodean', + 'Wyona', + 'Avonell', + 'Datha', + 'Ellar', + 'Morene', + 'Laverda', + 'Loetta', + 'Emmogene', + 'Arbadella', + 'Camaria', + 'Rochella', + 'Indiya', + 'Shayma', + 'Orneta', + 'Clotene', + 'Genoa', + 'Lanyah', + 'Oneda', + 'Glendola', + 'Rosala', + 'Zelphia', + 'Suda', + 'Jerrilynn', + 'Orlena', + 'Lorella', + 'Bernadean', + 'Novice', + 'Pheba', + 'Rukaya', + 'Gathel', + 'Meron', + 'Asianae', + 'Arriel', + 'Whisper', + 'Talesha', + 'Morgann', + 'Madissen', + 'Dajanay', + 'Karil', + 'Sherrita', + 'Chery', + 'Lezlee', + 'Daytona', + 'Raegen', + 'Dalal', + 'Majerle', + 'Lama', + 'Daijanae', + 'Celicia', + 'Cheril', + 'Cornesha', + 'Aniza', + 'Clytie', + 'Persis', + 'Aino', + 'Lawandra', + 'Deshonda', + 'Catrena', + 'Temekia', + 'Camella', + 'Arnetra', + 'Latoyna', + 'Tekisha', + 'Nalee', + 'Jennife', + 'Daphanie', + 'Shewanda', + 'Cheronda', + 'Latayna', + 'Almerinda', + 'Danene', + 'Jadwiga', + 'Ellora', + 'Tanga', + 'Tamekka', + 'Lashond', + 'Shinika', + 'Khyleigh', + 'Baelyn', + 'Clarene', + 'Monyette', + 'Lakisa', + 'Audreyanna', + 'Malayjah', + 'Keia', + 'Lajessica', + 'Marquite', + 'Odessia', + 'Marketia', + 'Malayshia', + 'Laconya', + 'Brayla', + 'Germani', + 'Luberdie', + 'Angla', + 'Cona', + 'Katrinia', + 'Shaletha', + 'Eutha', + 'Elmyra', + 'Cleva', + 'Elnore', + 'Vila', + 'Evone', + 'Margert', + 'Pairlee', + 'Bernelle', + 'Diannie', + 'Alinda', + 'Emerine', + 'Rogena', + 'Genette', + 'Jearline', + 'Estalee', + 'Bertina', + 'Cassand', + 'Kisa', + 'Veronic', + 'Idalina', + 'Walsie', + 'Gwendol', + 'Orvilla', + 'Latonga', + 'Elizabe', + 'Bernece', + 'Charlen', + 'Dola', + 'Alaija', + 'Martia', + 'Shanica', + 'Shariya', + 'Yuliya', + 'Atleigh', + 'Flannery', + 'Loeta', + 'Zakiah', + 'Alayia', + 'Glee', + 'Embree', + 'Kasidy', + 'Zacaria', + 'Derriona', + 'Jakyria', + 'Kiauna', + 'Garnelle', + 'Tyriana', + 'Juliya', + 'Maddisen', + 'Auna', + 'Jameisha', + 'Lurleen', + 'Kourtlyn', + 'Chelan', + 'Verlinda', + 'Sherria', + 'Alzada', + 'Ketara', + 'Anaka', + 'Breion', + 'Shadestiny', + 'Shanterica', + 'Tenia', + 'Keiosha', + 'Jamyriah', + 'Jamyrie', + 'Jalacia', + 'Ronita', + 'Maryln', + 'Earsie', + 'Kyri', + 'Markiyah', + 'Malajah', + 'Alandria', + 'Shaquitta', + 'Raymona', + 'Paeton', + 'Yaritzy', + 'Jonesha', + 'Anda', + 'Khadjah', + 'Amyree', + 'Vernestine', + 'Lavetta', + 'Jniya', + 'Shakiyah', + 'Aasia', + 'Roniya', + 'Keleigh', + 'Makalyn', + 'Kadasia', + 'Johneisha', + 'Jakaya', + 'Kinzey', + 'Wendelyn', + 'Darielys', + 'Wyteria', + 'Yarieliz', + 'Taysia', + 'Carmya', + 'Erionna', + 'Shameria', + 'Kearia', + 'Graycie', + 'Jurnie', + 'Calypso', + 'Finlee', + 'Fynlee', + 'Sophee', + 'Lorali', + 'Shacoria', + 'Kadeejah', + 'Lakira', + 'Kelsay', + 'Angelys', + 'Moeshia', + 'Keundra', + 'Mayara', + 'Josi', + 'Annaluiza', + 'Jacquese', + 'Jillaine', + 'Annajulia', + 'Nayeliz', + 'Maire', + 'Jamonica', + 'Jadalys', + 'Missie', + 'Machell', + 'Liisa', + 'Jalaine', + 'Odester', + 'Veria', + 'Virda', + 'Arleene', + 'Cigi', + 'Eloda', + 'Kacelyn', + 'Cidalia', + 'Vadie', + 'Wydell', + 'Donnita', + 'Lousie', + 'Oreatha', + 'Berdine', + 'Cielita', + 'Lilas', + 'Verneda', + 'Armelia', + 'Glender', + 'Elizbeth', + 'Vanella', + 'Florean', + 'Vyolet', + 'Albertia', + 'Albirda', + 'Sylva', + 'Lakresha', + 'Matha', + 'Nerine', + 'Dezzie', + 'Lodell', + 'Rosielee', + 'Julane', + 'Lodena', + 'Brookley', + 'Kynadi', + 'Krymson', + 'Etoile', + 'Meighan', + 'Izella', + 'Jakaria', + 'Jaleria', + 'Clister', + 'Alberdia', + 'Zykeriah', + 'Mileigh', + 'Isola', + 'Mamye', + 'Eller', + 'Kamoria', + 'Lakelynn', + 'Aslean', + 'Bular', + 'Emmaclaire', + 'Dasie', + 'Denotra', + 'Everlene', + 'Lynleigh', + 'Iantha', + 'Quinetta', + 'Lillion', + 'Sophronia', + 'Japonica', + 'Beauty', + 'Pearlina', + 'Evella', + 'Jatana', + 'Kechia', + 'Conswella', + 'Malissia', + 'Alexina', + 'Demeka', + 'Muguette', + 'Vaudine', + 'Aprill', + 'Villa', + 'Florece', + 'Tonjia', + 'Bethania', + 'Makinlee', + 'Latondra', + 'Audery', + 'Ericia', + 'Miyoshi', + 'Betti', + 'Harlym', + 'Novelle', + 'Liller', + 'Pinkey', + 'Narcille', + 'Lasheika', + 'Leonise', + 'Lydie', + 'Olla', + 'Rejeanne', + 'Athelene', + 'Eloyse', + 'Edolia', + 'Clotile', + 'Ethelrine', + 'Devonda', + 'Nakeshia', + 'Tomesha', + 'Orena', + 'Karlyne', + 'Enolia', + 'Faynell', + 'Margia', + 'Marvelene', + 'Justilia', + 'Iceola', + 'Shantina', + 'Shinita', + 'Loula', + 'Ireta', + 'Vanessia', + 'Ramonia', + 'Monita', + 'Shalva', + 'Ong', + 'Remonia', + 'Sheral', + 'Angelean', + 'Phyllistine', + 'Brenetta', + 'Madgeline', + 'Zyairah', + 'Anjolaoluwa', + 'Clotiel', + 'Eldine', + 'Tylia', + 'Ifeoluwa', + 'Florestine', + 'Althia', + 'Ravonda', + 'Tsion', + 'Zyaira', + 'Wylodene', + 'Janesha', + 'Vonciel', + 'Ruthey', + 'Khiana', + 'Kadesia', + 'Murdis', + 'Zhana', + 'Jillayne', + 'Quatisha', + 'Jaquasia', + 'Michaila', + 'Mashayla', + 'Travia', + 'Tyrika', + 'Aldah', + 'Makaiya', + 'Maridee', + 'Kyndell', + 'Nykira', + 'Mazell', + 'Luecile', + 'Quatasia', + 'Khala', + 'Sible', + 'Jakera', + 'Ovella', + 'Lealer', + 'Juleen', + 'Rinette', + 'Laykin', + 'Ozite', + 'Shaquanta', + 'Quanetta', + 'Shannyn', + 'Lacrystal', + 'Everline', + 'Editha', + 'Toneka', + 'Reinette', + 'Maclovia', + 'Ledia', + 'Shakeeka', + 'Shakeeta', + 'Taquanna', + 'Miyisha', + 'Patrecia', + 'Wylodean', + 'Solita', + 'Dalisa', + 'Jatoya', + 'Texanna', + 'Yvetta', + 'Lectoria', + 'Cyntrell', + 'Monyae', + 'Ibtisam', + 'Miski', + 'Renesha', + 'Maelle', + 'Azhar', + 'Zamzam', + 'Jamera', + 'Tyranika', + 'Ladan', + 'Ruweyda', + 'Jabrea', + 'Sherrica', + 'Clyda', + 'Treniece', + 'Fonnie', + 'Bedie', + 'Kewanda', + 'Mozel', + 'Tramika', + 'Quessie', + 'Tyshay', + 'Ladasha', + 'Kaarin', + 'Mazzie', + 'Genora', + 'Monie', + 'Muntas', + 'Hayat', + 'Jovanda', + 'Appolonia', + 'Cuma', + 'Briante', + 'Reneisha', + 'Zenovia', + 'Allysia', + 'Aliene', + 'Raini', + 'Tyja', + 'Iriel', + 'Deshante', + 'Shatira', + 'Demri', + 'Ajaysia', + 'Ireon', + 'Idil', + 'Nawaal', + 'Riham', + 'Nyeisha', + 'Jonique', + 'Keneisha', + 'Ravan', + 'Khadra', + 'Dawanna', + 'Gavriella', + 'Myrene', + 'Jasamine', + 'Brione', + 'Earlisha', + 'Dazia', + 'Jalesia', + 'Cabrina', + 'Marieme', + 'Gloristine', + 'Cattie', + 'Damilola', + 'Evora', + 'Almarie', + 'Vauda', + 'Tanzie', + 'Truby', + 'Tayona', + 'Francelia', + 'Brona', + 'Jannice', + 'Weltha', + 'Phylliss', + 'Vieva', + 'Danera', + 'Saratha', + 'Colinda', + 'Suzonne', + 'Shelene', + 'Shelda', + 'Annye', + 'Kaola', + 'Modine', + 'Velvie', + 'Vetra', + 'Tyrhonda', + 'Malissie', + 'Shemica', + 'Rockell', + 'Adgie', + 'Lachanda', + 'Kwanza', + 'Keyanta', + 'Hazeleen', + 'Yarnell', + 'Mettie', + 'Kissie', + 'Jawanna', + 'Ilham', + 'Enchantra', + 'Lucielle', + 'Salmo', + 'Sabrin', + 'Nicy', + 'Rubell', + 'Willet', + 'Ronata', + 'Semiko', + 'Idman', + 'Meoshia', + 'Maie', + 'Eulala', + 'Tiyonna', + 'Sabarin', + 'Merlie', + 'Oneka', + 'Khiya', + 'Geralene', + 'Hubbie', + 'Patches', + 'Robenia', + 'Carita', + 'Veleka', + 'Tamla', + 'Zondra', + 'Cheramie', + 'Nimco', + 'Chauntelle', + 'Calonia', + 'Mulki', + 'Clydia', + 'Glida', + 'Fartun', + 'Fardowsa', + 'Iyona', + 'Dwanna', + 'Angila', + 'Carletha', + 'Blakley', + 'Valecia', + 'Songa', + 'Shya', + 'Kamber', + 'Siah', + 'Sloka', + 'Sophiagrace', + 'Sophiamarie', + 'Setayesh', + 'Roselie', + 'Samhitha', + 'Savreen', + 'Zanayah', + 'Yilia', + 'Zareena', + 'Yeilin', + 'Ulyana', + 'Tylie', + 'Vaani', + 'Vasilisa', + 'Videl', + 'Xylia', + 'Rubylee', + 'Jessye', + 'Itasca', + 'Bonifacia', + 'Bennye', + 'Estellene', + 'Daycee', + 'Vung', + 'Babe', + 'Lucyle', + 'Laurencia', + 'Frankye', + 'Clariece', + 'Alsace', + 'Ernesteen', + 'Zuma', + 'Loleta', + 'Matiana', + 'Thyra', + 'Thekla', + 'Miladie', + 'Moselle', + 'Waldene', + 'Thula', + 'Ethelda', + 'Elbira', + 'Eddye', + 'Lafaye', + 'Beryle', + 'Beanna', + 'Basilisa', + 'Bernardina', + 'Vontressa', + 'Elner', + 'Gladine', + 'Saketha', + 'Nellene', + 'Margurette', + 'Levada', + 'Alcie', + 'Beuna', + 'Miaa', + 'Miia', + 'Miral', + 'Lunabella', + 'Manvi', + 'Nahlia', + 'Quetzal', + 'Preet', + 'Navreet', + 'Prajna', + 'Analayah', + 'Aalaya', + 'Aaleah', + 'Aaria', + 'Aby', + 'Adeena', + 'Adelaine', + 'Adhara', + 'Alekhya', + 'Avaline', + 'Avina', + 'Azaliah', + 'Azayla', + 'Anwita', + 'Arna', + 'Asmi', + 'Cutina', + 'Jaydalynn', + 'Jerusalem', + 'Hiyab', + 'Icey', + 'Jaanvi', + 'Khalessi', + 'Khiara', + 'Leelah', + 'Ketzaly', + 'Kaliyanei', + 'Karolynn', + 'Kaylonnie', + 'Harveen', + 'Danilynn', + 'Decklyn', + 'Deleyza', + 'Charm', + 'Calina', + 'Cathaleya', + 'Dailynn', + 'Corra', + 'Cyrene', + 'Eveleen', + 'Fia', + 'Galina', + 'Gohar', + 'Gursirat', + 'Harleyquinn', + 'Evalin', + 'Eevee', + 'Eira', + 'Elara', + 'Ellaina', + 'Ellarose', + 'Erabella', + 'Teofila', + 'Calamity', + 'Sherion', + 'Niang', + 'Oreta', + 'Leita', + 'Maedelle', + 'Othello', + 'Meshell', + 'Alfreida', + 'Detria', + 'Cloda', + 'Ermine', + 'Gertrudes', + 'Zudora', + 'Benigna', + 'Dolorez', + 'Narcissa', + 'Eduviges', + 'Dionisia', + 'Crisanta', + 'Adreena', + 'Aivy', + 'Sharanda', + 'Amma', + 'Danitra', + 'Lashuna', + 'Yasheka', + 'Sheronica', + 'Ameliya', + 'Cayetana', + 'Benancia', + 'Tiya', + 'Umaiza', + 'Vicktoria', + 'Vidushi', + 'Yaretzie', + 'Siennah', + 'Sofiah', + 'Stuti', + 'Taitum', + 'Yuli', + 'Zarya', + 'Zeriah', + 'Sadiee', + 'Rubee', + 'Ryenn', + 'Sayana', + 'Ezabella', + 'Galya', + 'Hayzel', + 'Evalette', + 'Eleanna', + 'Elize', + 'Elleana', + 'Hiya', + 'Jezabelle', + 'Jazzy', + 'Jeraldin', + 'Jocabed', + 'Kaloni', + 'Jazmeen', + 'Jasmarie', + 'Ilani', + 'Ilany', + 'Ariannie', + 'Angelinne', + 'Delaynie', + 'Calise', + 'Bethlehem', + 'Cateleya', + 'Paitynn', + 'Peytin', + 'Rainie', + 'Rhylin', + 'Rosaly', + 'Nomi', + 'Mirai', + 'Moksha', + 'Mylin', + 'Nazeli', + 'Nilani', + 'Marcelene', + 'Victorina', + 'Laiah', + 'Leeyah', + 'Miaisabella', + 'Ravleen', + 'Lazara', + 'Zuleidy', + 'Shraddha', + 'Simarpreet', + 'Rinoa', + 'Ridhima', + 'Ryla', + 'Ryleeann', + 'Ryli', + 'Sahori', + 'Smrithi', + 'Yeslin', + 'Yanessa', + 'Zeltzin', + 'Sonakshi', + 'Sophea', + 'Carlissa', + 'Bryttani', + 'Albesa', + 'Bonnye', + 'Daksha', + 'Terria', + 'Davinah', + 'Enalina', + 'Evolette', + 'Dhwani', + 'Eleora', + 'Leea', + 'Lexii', + 'Meilyn', + 'Nevah', + 'Noga', + 'Prabhleen', + 'Quinley', + 'Mursal', + 'Naiara', + 'Navah', + 'Izumi', + 'Janelli', + 'Jniyah', + 'Klaryssa', + 'Kritika', + 'Laksmi', + 'Lalani', + 'Joselle', + 'Kashish', + 'Kenyana', + 'Laquishia', + 'Deshonna', + 'Sentoria', + 'Ernestene', + 'Maxima', + 'Senovia', + 'Nestora', + 'Valta', + 'Casady', + 'Daphene', + 'Chonita', + 'Omelia', + 'Odena', + 'Melchora', + 'Quetzally', + 'Thera', + 'Gabina', + 'Donaciana', + 'Riddhima', + 'Lakessa', + 'Lakeeta', + 'Katasha', + 'Chaitra', + 'Chizara', + 'Aveyah', + 'Elah', + 'Eliannah', + 'Ellanore', + 'Emmalia', + 'Dalexa', + 'Delara', + 'Donatella', + 'Aubreanna', + 'Aberdeen', + 'Aerilyn', + 'Aleksia', + 'Annarose', + 'Anthea', + 'Aoi', + 'Amberrose', + 'Anaeli', + 'Lilou', + 'Lumen', + 'Manasvi', + 'Lillybeth', + 'Keylani', + 'Lenya', + 'Lidya', + 'Mulan', + 'Nirvi', + 'Ondine', + 'Meenakshi', + 'Mathea', + 'Melyna', + 'Io', + 'Izelle', + 'Jailia', + 'Eztli', + 'Gali', + 'Hade', + 'Hafsah', + 'Hannahgrace', + 'Kayleah', + 'Kayleeann', + 'Kemily', + 'Jeylah', + 'Jiaqi', + 'Sherrika', + 'Daffney', + 'Solstice', + 'Soriah', + 'Sumayya', + 'Saory', + 'Shaily', + 'Shanzay', + 'Sharvi', + 'Xylina', + 'Yeimy', + 'Yizel', + 'Zaidee', + 'Ziah', + 'Jesucita', + 'Madalena', + 'Vontresa', + 'Tangee', + 'Shekina', + 'Sista', + 'Norvis', + 'Winnell', + 'Yoshida', + 'Nikiya', + 'Vidala', + 'Shandria', + 'Rozelle', + 'Maragret', + 'Sixta', + 'Theta', + 'Wylma', + 'Jobita', + 'Gaudalupe', + 'Lurlean', + 'Oveta', + 'Heriberta', + 'Bacilia', + 'Senorina', + 'Denika', + 'Akeisha', + 'Tamecia', + 'Jera', + 'Crestina', + 'Shwanda', + 'Kelbie', + 'Sanayah', + 'Zaliah', + 'Nadezhda', + 'Maaliyah', + 'Mahaley', + 'Raziyah', + 'Saraiya', + 'Cyriah', + 'Chaniyah', + 'Emmarae', + 'Eleen', + 'Ashland', + 'Briniyah', + 'Ainhoa', + 'Aviyah', + 'Atarah', + 'Lutrelle', + 'Clevie', + 'Blossie', + 'Cola', + 'Para', + 'Verdelle', + 'Beddie', + 'Lilliemae', + 'Jurell', + 'Bertice', + 'Fozie', + 'Oppie', + 'Rozia', + 'Rozie', + 'Epsie', + 'Karman', + 'Estoria', + 'Dynesha', + 'Sarae', + 'Xolani', + 'Talyah', + 'Zanaria', + 'Zamiah', + 'Starkeisha', + 'Alys', + 'Izaria', + 'Cayenne', + 'Damiah', + 'Alwilda', + 'Leoda', + 'Yariah', + 'Tuleen', + 'Rhelda', + 'Carlesha', + 'Alfretta', + 'Orma', + 'Ornella', + 'Nazyia', + 'Samorah', + 'Keyonni', + 'Jeriyah', + 'Jazariyah', + 'Demaria', + 'Mikeyla', + 'Malania', + 'Miyanna', + 'Neriyah', + 'Naelle', + 'Lazariah', + 'Rea', + 'Annaya', + 'Aleanna', + 'Baylin', + 'Aela', + 'Emmilyn', + 'Anila', + 'Rodnesha', + 'Janeliz', + 'Kseniya', + 'Nyana', + 'Zemirah', + 'Somya', + 'Yanna', + 'Terryn', + 'Naika', + 'Laiyla', + 'Lyrica', + 'Loralie', + 'Lilya', + 'Wonnie', + 'Runelle', + 'Tynleigh', + 'Loralye', + 'Arynn', + 'Melvis', + 'Akiyah', + 'Matline', + 'Ellean', + 'Wylean', + 'Marfa', + 'Elliemae', + 'Nancey', + 'Waltina', + 'Ommie', + 'Lonia', + 'Reaver', + 'Virdell', + 'Rosabell', + 'Sarahgrace', + 'Faustine', + 'Euretha', + 'Sussie', + 'Rebie', + 'Oveline', + 'Reathel', + 'Algia', + 'Mylissa', + 'Rethel', + 'Nakyla', + 'Necia', + 'Deanie', + 'Beckey', + 'Yasmen', + 'Yukari', + 'Zamyra', + 'Roselinda', + 'Takeko', + 'Vicke', + 'Mckala', + 'Hanae', + 'Elley', + 'Ellyssa', + 'Geanna', + 'Geetika', + 'Elenoa', + 'Elane', + 'Deeya', + 'Deviny', + 'Genecis', + 'Jasminerose', + 'Ireri', + 'Hailei', + 'Hannya', + 'Harshini', + 'Holiday', + 'Arista', + 'Dannae', + 'Melayna', + 'Meleni', + 'Mystique', + 'Nathalya', + 'Natsumi', + 'Sharlize', + 'Shine', + 'Sindhu', + 'Starlyn', + 'Sarika', + 'Sarine', + 'Seleen', + 'Khalea', + 'Kirti', + 'Jocilyn', + 'Maille', + 'Mariaceleste', + 'Leelee', + 'Leidi', + 'Libertad', + 'Lizvet', + 'Kierstan', + 'Adja', + 'Debbye', + 'Dorenda', + 'Kiyono', + 'Katsuko', + 'Katsue', + 'Misue', + 'Umeno', + 'Rayvin', + 'Sachie', + 'Kinue', + 'Danajah', + 'Denay', + 'Tsuneko', + 'Tamae', + 'Saeko', + 'Tsutako', + 'Sumako', + 'Momoe', + 'Tomoko', + 'Asae', + 'Nautika', + 'Kourtnee', + 'Keauna', + 'Maydeen', + 'Chianne', + 'Macala', + 'Briaunna', + 'Ceirra', + 'Kimberlea', + 'Normalinda', + 'Milinda', + 'Jonetta', + 'Seleta', + 'Chryl', + 'Aaminah', + 'Mersades', + 'Mickenzie', + 'Tahlor', + 'Kimetha', + 'Hopie', + 'Guadulupe', + 'Blakelynn', + 'Orfelinda', + 'Aubre', + 'Ajayla', + 'Makenlee', + 'Journii', + 'Janayla', + 'Talulah', + 'Siddhi', + 'Shaira', + 'Yuridiana', + 'Yulitza', + 'Tulsi', + 'Yatana', + 'Jaleya', + 'Ayrianna', + 'Damaya', + 'Myana', + 'Lanyiah', + 'Kadince', + 'Aunna', + 'Avrielle', + 'Khyli', + 'Kariyah', + 'Bralynn', + 'Derrianna', + 'Maryella', + 'Charlynn', + 'Ilma', + 'Tresea', + 'Mersadies', + 'Macenzie', + 'Terriona', + 'Telia', + 'Tamryn', + 'Tahari', + 'Solyana', + 'Lyrical', + 'Akie', + 'Teruyo', + 'Shizuyo', + 'Tsuruyo', + 'Daviona', + 'Marshelia', + 'Connye', + 'Marka', + 'Adelmira', + 'Dorelia', + 'Nirel', + 'Oceanna', + 'Neeka', + 'Sherolyn', + 'Sheralyn', + 'Sharlet', + 'Milenka', + 'Astha', + 'Angeleena', + 'Anysia', + 'Apoorva', + 'Bryanah', + 'Carolyna', + 'Cecy', + 'Anadalay', + 'Akaylah', + 'Aika', + 'Aasha', + 'Ahniah', + 'Adelayda', + 'Kyaira', + 'Manmeet', + 'Linsy', + 'Malini', + 'Mairany', + 'Haeley', + 'Evelen', + 'Jezel', + 'Jinelle', + 'Joleena', + 'Hikari', + 'Inari', + 'Itcel', + 'Lokelani', + 'Keikilani', + 'Sherilynn', + 'Jamieann', + 'Lajuanna', + 'Roselind', + 'Rhetta', + 'Alysah', + 'Ameyalli', + 'Abigayl', + 'Aizza', + 'Alaiza', + 'Aslyn', + 'Anjalee', + 'Annaliza', + 'Antara', + 'Areen', + 'Carra', + 'Katieann', + 'Kimla', + 'Xan', + 'Mikiala', + 'Chrissa', + 'Belanna', + 'Ankitha', + 'Celestial', + 'Chiana', + 'Akhila', + 'Alique', + 'Alyssamae', + 'Betheny', + 'Stepheny', + 'Brittanyann', + 'Adonna', + 'Barbarella', + 'Shalamar', + 'Flecia', + 'Dlisa', + 'Anabelia', + 'Velen', + 'Xotchil', + 'Yairis', + 'Lytzy', + 'Faizah', + 'Eilleen', + 'Elona', + 'Esteffany', + 'Jesyka', + 'Jhovana', + 'Jisell', + 'Joclyn', + 'Teel', + 'Sundee', + 'Mechell', + 'Lisia', + 'Nandita', + 'Natalina', + 'Nattalie', + 'Rosaelena', + 'Siclali', + 'Skyllar', + 'Taeya', + 'Sadey', + 'Sadira', + 'Sanae', + 'Serenah', + 'Shamila', + 'Brizza', + 'Chalisa', + 'Shakeela', + 'Gordean', + 'Akane', + 'Akansha', + 'Angeni', + 'Annalina', + 'Anushree', + 'Allexa', + 'Katelynd', + 'Raenette', + 'Airiel', + 'Matina', + 'Teira', + 'Deatra', + 'Darolyn', + 'Hilliary', + 'Roanna', + 'Prissy', + 'Monya', + 'Armelinda', + 'Ginnie', + 'Darenda', + 'Leslea', + 'Marcedes', + 'Jeweliana', + 'Jewelissa', + 'Josselyne', + 'Lavanya', + 'Koryn', + 'Khushpreet', + 'Kierah', + 'Cyana', + 'Deeana', + 'Bibianna', + 'Bryannah', + 'Heidie', + 'Desteni', + 'Elleanna', + 'Sierah', + 'Sumedha', + 'Shantall', + 'Yarissa', + 'Yerania', + 'Tifanny', + 'Mehek', + 'Mirely', + 'Mitra', + 'Mar', + 'Rohini', + 'Prerana', + 'Naizeth', + 'Naydeli', + 'Melveen', + 'Moani', + 'Endora', + 'Jackquline', + 'Stefanny', + 'Tamanna', + 'Sofija', + 'Zitlalic', + 'Ymani', + 'Jumana', + 'Kailene', + 'Josephyne', + 'Leiya', + 'Letzy', + 'Litsy', + 'Lizbett', + 'Lizveth', + 'Jaiya', + 'Dreanna', + 'Celestia', + 'Electra', + 'Sevanna', + 'Sidnie', + 'Semone', + 'Sharra', + 'Sharlette', + 'Selinda', + 'Saumya', + 'Meilan', + 'Melea', + 'Maleeha', + 'Mitali', + 'Rheana', + 'Ruchi', + 'Oasis', + 'Preethi', + 'Aungelique', + 'Kristl', + 'Tashala', + 'Darcell', + 'Rolinda', + 'Toye', + 'Shirlyn', + 'Yvonda', + 'Tymia', + 'Oteka', + 'Ladora', + 'Deashia', + 'Janautica', + 'Sonnet', + 'Sucely', + 'Suriah', + 'Tallula', + 'Sanna', + 'Seniyah', + 'Seri', + 'Yexalen', + 'Yumiko', + 'Zayana', + 'Zohal', + 'Valerye', + 'Yarisbeth', + 'Vivyana', + 'Xela', + 'Brithanny', + 'Jasira', + 'Jenessy', + 'Jezebelle', + 'Leahna', + 'Leilanee', + 'Leily', + 'Kohana', + 'Dorsa', + 'Elanna', + 'Caralyn', + 'Erilyn', + 'Halyn', + 'Helayna', + 'Lionor', + 'Maela', + 'Masha', + 'Myley', + 'Malaak', + 'Malai', + 'Mariapaula', + 'Nathalye', + 'Remie', + 'Parnika', + 'Neveen', + 'Cherith', + 'Orvella', + 'Aurion', + 'Shonterria', + 'Natoria', + 'Shaterria', + 'Clo', + 'Donnia', + 'Cana', + 'Niaya', + 'Brelyn', + 'Aalliyah', + 'Shaaron', + 'Doylene', + 'Lowanda', + 'Henryetta', + 'Obera', + 'Marykathryn', + 'Dema', + 'Arcadia', + 'Lodema', + 'Aloni', + 'Analya', + 'Aashritha', + 'Ayani', + 'Audreena', + 'Audrena', + 'Ariahna', + 'Antonela', + 'Atzi', + 'Amunet', + 'Jaala', + 'Keambria', + 'Kanaya', + 'Emya', + 'Deijah', + 'Dayjah', + 'Tiye', + 'Nyja', + 'Markesia', + 'Valla', + 'Cesaria', + 'Eusevia', + 'Elpidia', + 'Jaquisha', + 'Romanita', + 'Shauntia', + 'Chasmine', + 'Deneisha', + 'Quatesha', + 'Nicosha', + 'Shandricka', + 'Shambria', + 'Shakerra', + 'Santrice', + 'Quinesha', + 'Shantika', + 'Roderica', + 'Whitnie', + 'Piedad', + 'Koleta', + 'Brazil', + 'Aamina', + 'Adaleen', + 'Adyline', + 'Bricola', + 'Analeigha', + 'Anara', + 'Ladawna', + 'Ruperta', + 'Deaundra', + 'Jaleisa', + 'Keria', + 'Sharaine', + 'Shanekqua', + 'Shanekia', + 'Kenyanna', + 'Jacoria', + 'Airianna', + 'Amana', + 'Amariz', + 'Ammi', + 'Miaya', + 'Aaniya', + 'Anaisha', + 'Bellina', + 'Annasofia', + 'Archita', + 'Arianie', + 'Shaquandra', + 'Shakeyra', + 'Tiandra', + 'Soveida', + 'Gonzala', + 'Gaylia', + 'Freddye', + 'Roxi', + 'Neya', + 'Nitika', + 'Noriah', + 'Raha', + 'Briah', + 'Syrah', + 'Talise', + 'Tarynn', + 'Tianah', + 'Solay', + 'Saraiah', + 'Sherlynn', + 'Leylany', + 'Lilu', + 'Maelie', + 'Lexxie', + 'Monzeratt', + 'Nari', + 'Naveyah', + 'Mianna', + 'Maylea', + 'Mery', + 'Marene', + 'Zeba', + 'Xymena', + 'Yaremi', + 'Yari', + 'Yulie', + 'Lile', + 'Dafnee', + 'Indra', + 'Itzelle', + 'Evangaline', + 'Evelett', + 'Evely', + 'Ghazal', + 'Arnisha', + 'Kassia', + 'Kayah', + 'Kalliyan', + 'Diannia', + 'Damyah', + 'Torianna', + 'Talasia', + 'Zakira', + 'Zyah', + 'Masiya', + 'Rhyanna', + 'Kemaya', + 'Jadasia', + 'Kanijah', + 'Henleigh', + 'Ciella', + 'Dayanne', + 'Ivannia', + 'Heydy', + 'Fergie', + 'Fianna', + 'Goretti', + 'Gwynneth', + 'Gyanna', + 'Haidi', + 'Christabella', + 'Angelinah', + 'Anina', + 'Annya', + 'Alejah', + 'Bradie', + 'Breanah', + 'Arihana', + 'Aryona', + 'Ashwika', + 'Aylet', + 'Ayleth', + 'Meleena', + 'Micel', + 'Misel', + 'Naiema', + 'Meiling', + 'Malaia', + 'Rehanna', + 'Raengel', + 'Padma', + 'Majestic', + 'Katelen', + 'Jenaveve', + 'Jennessy', + 'Jewelisa', + 'Joelie', + 'Lyliana', + 'Mahati', + 'Sherral', + 'Kamariah', + 'Larsen', + 'Khaniya', + 'Jakiah', + 'Darionna', + 'Bristal', + 'Ahlana', + 'Aireanna', + 'Alaila', + 'Jarethzy', + 'Orfalinda', + 'Nataliah', + 'Nayra', + 'Nishika', + 'Meeya', + 'Sanaia', + 'Sensi', + 'Percilla', + 'Pranathi', + 'Kathrynn', + 'Katriel', + 'Jordanna', + 'Jessilyn', + 'Jilliana', + 'Madeira', + 'Laia', + 'Leala', + 'Courtlynn', + 'Ahriana', + 'Aliena', + 'Adalay', + 'Nakyia', + 'Niema', + 'Leeasia', + 'Evenny', + 'Dorismar', + 'Dyanara', + 'Elonna', + 'Estreya', + 'Ashmita', + 'Anureet', + 'Angeliah', + 'Annaliz', + 'Dallanara', + 'Danaly', + 'Carely', + 'Sevilla', + 'Aleigh', + 'Allianna', + 'Alamar', + 'Jaiah', + 'Shellsea', + 'Sheylin', + 'Sonoma', + 'Hayla', + 'Yoali', + 'Yzabel', + 'Zeenat', + 'Zienna', + 'Shirlynn', + 'Shilynn', + 'Raphaella', + 'Makyia', + 'Inola', + 'Omaria', + 'Michiah', + 'Anareli', + 'Anacamila', + 'Anahis', + 'Anapaola', + 'Clowie', + 'Brizia', + 'Alexssa', + 'Ailanie', + 'Aileene', + 'Francille', + 'Jatoria', + 'Jaquitta', + 'Sybol', + 'Landra', + 'Danyela', + 'Cubia', + 'Arabela', + 'Adelfina', + 'Quaniya', + 'Paulyne', + 'Vanteen', + 'Treba', + 'Kaylena', + 'Kaelynne', + 'Kalanie', + 'Lezli', + 'Lithzy', + 'Lanessa', + 'Laylene', + 'Leilaney', + 'Emmajean', + 'Francella', + 'Eiliyah', + 'Jadey', + 'Jamilett', + 'Ingris', + 'Tayanna', + 'Skarlette', + 'Sady', + 'Senia', + 'Yakeline', + 'Yenna', + 'Yesmin', + 'Meily', + 'Mikeila', + 'Miu', + 'Rakel', + 'Niveah', + 'Nyemah', + 'Gorgeous', + 'Zaraya', + 'Lavaeh', + 'Meila', + 'Labella', + 'Lilyona', + 'Zykierra', + 'Orfa', + 'Seriyah', + 'Shivali', + 'Sibylla', + 'Sua', + 'Ulani', + 'Vianet', + 'Yanell', + 'Yolette', + 'Yudany', + 'Suheidy', + 'Sukhpreet', + 'Syanna', + 'Tatevik', + 'Tayde', + 'Sameria', + 'Mikiya', + 'Claramae', + 'Audine', + 'Francile', + 'Tynia', + 'Goddess', + 'Samoria', + 'Llana', + 'Oveda', + 'Amelya', + 'Auda', + 'Disaya', + 'Zanyah', + 'Samiyyah', + 'Jaianna', + 'Ruqayyah', + 'Nakira', + 'Shamirah', + 'Ta', + 'Giani', + 'Brya', + 'Cyani', + 'Ashiyah', + 'Kahli', + 'Beauton', + 'Kashay', + 'Sadiyah', + 'Mikaya', + 'Nasira', + 'Nasirah', + 'Ariauna', + 'Yasirah', + 'Skyelynn', + 'Naailah', + 'Nyelle', + 'Adessa', + 'Ayriana', + 'Mirielle', + 'Munirah', + 'Layani', + 'Haniyah', + 'Ovida', + 'Haniyyah', + 'Layonna', + 'Jazmarie', + 'Wicahpi', + 'Cante', + 'Zamyah', + 'Tanyiah', + 'Shalita', + 'Salley', + 'Jnya', + 'Santasia', + 'Shaneque', + 'Quantina', + 'Temeika', + 'Narvis', + 'Pearlee', + 'Nykesha', + 'Orrie', + 'Mozter', + 'Earthalee', + 'Rozena', + 'Anniebell', + 'Hannie', + 'Pretto', + 'Caro', + 'Everlina', + 'Arnetha', + 'Glenora', + 'Asalee', + 'Parniece', + 'Rubena', + 'Wilhemena', + 'Perline', + 'Elloree', + 'Clorine', + 'Richardean', + 'Rovena', + 'Arthuree', + 'Mikea', + 'Charnice', + 'Tylashia', + 'Rebacca', + 'Caretha', + 'Dynasti', + 'Marvie', + 'Hermenia', + 'Tekela', + 'Trenace', + 'Valetta', + 'Topaz', + 'Debara', + 'Jaquasha', + 'Markeria', + 'Alkeria', + 'Salwa', + 'Tatayana', + 'Dianelys', + 'Beyounce', + 'Drena', + 'Julysa', + 'Shuntel', + 'Antasia', + 'Alyze', + 'Marytheresa', + 'Raechelle', + 'Trevia', + 'Tomara', + 'Jermeka', + 'Curtisha', + 'Kebrina', + 'Kayte', + 'Shakeila', + 'Ronnesha', + 'Shavontae', + 'Taquila', + 'Shaquia', + 'Lynnann', + 'Markevia', + 'Terrilynn', + 'Carime', + 'Quaneshia', + 'Shaylen', + 'Corneisha', + 'Rodneshia', + 'Nateria', + 'Marycatherine', + 'Ashlyne', + 'Reyne', + 'Natia', + 'Taquisha', + 'Mikeshia', + 'Khadeja', + 'Lismary', + 'Prisca', + 'Antwonette', + 'Anesia', + 'Clotilda', + 'Willavene', + 'Lovey', + 'Aleda', + 'Karita', + 'Rakiyah', + 'Nyasiah', + 'Timaya', + 'Gabryelle', + 'Caniyah', + 'Ethelreda', + 'Aryelle', + 'Trianna', + 'Yesli', + 'Yareliz', + 'Tanyla', + 'Keyshia', + 'Makinsey', + 'Daily', + 'Caylynn', + 'Kalyse', + 'Sarabelle', + 'Araminta', + 'Magdelene', + 'Kristalyn', + 'Lianni', + 'Layana', + 'Haedyn', + 'Teyona', + 'Taziyah', + 'Ranijah', + 'Darneisha', + 'Jahzaria', + 'Palmyra', + 'Altheda', + 'Armanii', + 'Blodwyn', + 'Colletta', + 'Yelenis', + 'Yazlyn', + 'Leira', + 'Anaysia', + 'Anayiah', + 'Valia', + 'Bambina', + 'Burnetta', + 'Clarabel', + 'Philomenia', + 'Lorma', + 'Janeka', + 'Danaisha', + 'Cayci', + 'Jermia', + 'Idalys', + 'Sarajane', + 'Shakenya', + 'Kashanti', + 'Lanika', + 'Ceira', + 'Deshanti', + 'Adianez', + 'Alannis', + 'Lubov', + 'Aylana', + 'Nephtalie', + 'Harlean', + 'Shelvey', + 'Yalissa', + 'Asianna', + 'Jahnyah', + 'Jahliyah', + 'Ellissa', + 'Gabrianna', + 'Katonya', + 'Elsia', + 'Ketina', + 'Kateena', + 'Claudean', + 'Chenita', + 'Belkys', + 'Kerryn', + 'Teria', + 'Charron', + 'Charnissa', + 'Alura', + 'Bashirah', + 'Gerldine', + 'Katilynn', + 'Trellany', + 'Lacheryl', + 'Twalla', + 'Sharnise', + 'Yoland', + 'Shanai', + 'Ikia', + 'Aquilla', + 'Shalandra', + 'Nekesha', + 'Sonni', + 'Kutana', + 'Sharnay', + 'Timitra', + 'Shareena', + 'Tyeesha', + 'Natara', + 'Amatullah', + 'Nydirah', + 'Shahadah', + 'Inetha', + 'Clatie', + 'Ladye', + 'Makalia', + 'Sabriyah', + 'Graple', + 'Lorell', + 'Vercie', + 'Rayona', + 'Dayshia', + 'Nakirah', + 'Mcneva', + 'Bunia', + 'Brooxie', + 'Delcia', + 'Naje', + 'Eilish', + 'Lashara', + 'Crystall', + 'Shearon', + 'Kafi', + 'Kea', + 'Shantrel', + 'Jeanni', + 'Andreia', + 'Myrlande', + 'Jennifier', + 'Damika', + 'Carloyn', + 'Lashera', + 'Kamika', + 'Chrisann', + 'Lashavia', + 'Ivis', + 'Quinisha', + 'Yanelys', + 'Taralee', + 'Ibis', + 'Jazma', + 'Shakevia', + 'Deneane', + 'Kimala', + 'Casee', + 'Audreana', + 'Shahida', + 'Latangela', + 'Lashira', + 'Lashawndra', + 'Sherrina', + 'Shawntrell', + 'Latronda', + 'Meghaan', + 'Ayasha', + 'Raushanah', + 'Serrita', + 'Tennile', + 'Keyonda', + 'Idalmis', + 'Telicia', + 'Takeia', + 'Aristea', + 'Letesha', + 'Badia', + 'Nykea', + 'Bilan', + 'Ieva', + 'Kimmi', + 'Geniel', + 'Tamberly', + 'Tammee', + 'Sherma', + 'Emira', + 'Agena', + 'Carrin', + 'Ladean', + 'Caera', + 'Shatha', + 'Utahna', + 'Lujean', + 'Joylyn', + 'Kathren', + 'Kristiane', + 'Lenee', + 'Angi', + 'Vichelle', + 'Rochele', + 'Shonnie', + 'Anastasija', + 'Clea', + 'Myrlene', + 'Dniyah', + 'Tashanti', + 'Sireen', + 'Vincie', + 'Wreatha', + 'Josphine', + 'Casimera', + 'Hildagarde', + 'Margeret', + 'Grettell', + 'Greenley', + 'Gloriana', + 'Eyleen', + 'Evaleigh', + 'Davanee', + 'Corley', + 'Liliah', + 'Leanah', + 'Kynzlie', + 'Kynzleigh', + 'Kolette', + 'Lively', + 'Makenlie', + 'Lochlyn', + 'Kinslie', + 'Jleigh', + 'Jeslynn', + 'Jenisis', + 'Jenisha', + 'Kensli', + 'Addalie', + 'Demia', + 'Cele', + 'Aderinsola', + 'Auriella', + 'Blyss', + 'Cashlynn', + 'Callyn', + 'Allyzon', + 'Aleiya', + 'Alazne', + 'Alayzia', + 'Ailah', + 'Annora', + 'Analynn', + 'Leonilda', + 'Minnette', + 'Onolee', + 'Michaelina', + 'Rosemond', + 'Milica', + 'Ednamae', + 'Floribel', + 'Nur', + 'Ndia', + 'Thecla', + 'Immaculate', + 'Mayfred', + 'Selda', + 'Vincenzia', + 'Vitina', + 'Tammatha', + 'Joley', + 'Kelene', + 'Kriste', + 'Liese', + 'Mariaemilia', + 'Lasaundra', + 'Letica', + 'Karene', + 'Devera', + 'Denyce', + 'Dawnn', + 'Maryum', + 'Giovannina', + 'Roze', + 'Reygan', + 'Quinlyn', + 'Stassi', + 'Meelah', + 'Novaleigh', + 'Navey', + 'Mirakle', + 'Naiovy', + 'Munachiso', + 'Montzerrat', + 'Misk', + 'Mireyah', + 'Temiloluwa', + 'Zaiya', + 'Varshini', + 'Tiwatope', + 'Tinlee', + 'Geneve', + 'Kotryna', + 'Janila', + 'Janeah', + 'Mollye', + 'Dody', + 'Doreena', + 'Chelle', + 'Javaeh', + 'Dim', + 'Jamylah', + 'Kamyia', + 'Ramie', + 'Kandie', + 'Kitt', + 'Gaylyn', + 'Marji', + 'Laurena', + 'Lorre', + 'Ronelle', + 'Kresta', + 'Jonylah', + 'Kornelia', + 'Mindie', + 'Kendis', + 'Dorri', + 'Seaneen', + 'Lorilyn', + 'Lolly', + 'Pati', + 'Shalayne', + 'Dorise', + 'Joani', + 'Yailene', + 'Batool', + 'Cyntha', + 'Coni', + 'Kae', + 'Cynia', + 'Rhonna', + 'Lynnetta', + 'Terrisa', + 'Nishi', + 'Delise', + 'Ladena', + 'Bronwen', + 'Tere', + 'Tippi', + 'Peggi', + 'Portland', + 'Sherrin', + 'Tacy', + 'Terie', + 'Dore', + 'Daphane', + 'Juliene', + 'Kamile', + 'Janeil', + 'Megin', + 'Shenandoah', + 'Rashada', + 'Disa', + 'Elita', + 'Kelee', + 'Genee', + 'Taneya', + 'Storie', + 'Sheza', + 'Rielyn', + 'Venicia', + 'Zamyria', + 'Yisell', + 'Appollonia', + 'Meryle', + 'Frann', + 'Lucyann', + 'Clarivel', + 'Marguarite', + 'Nelsa', + 'Reanetta', + 'Roshaunda', + 'Channie', + 'Bathsheba', + 'Jannessa', + 'Jakaylah', + 'Jesalyn', + 'Ellyson', + 'Hally', + 'Haelyn', + 'Gabbie', + 'Emmerie', + 'Makailyn', + 'Maddi', + 'Lirio', + 'Lexee', + 'Matalyn', + 'Kenzee', + 'Kenlei', + 'Kaydi', + 'Kynlei', + 'Krissa', + 'Adalin', + 'Alayiah', + 'Ellice', + 'Caydee', + 'Annalysa', + 'Anisty', + 'Abeni', + 'Aliha', + 'Aerith', + 'Adrie', + 'Peggyann', + 'Pietrina', + 'Amberlie', + 'Dabria', + 'Cylee', + 'Amyriah', + 'Ambry', + 'Berkleigh', + 'Azula', + 'Zaryiah', + 'Zanyia', + 'Gerardine', + 'Joycelynn', + 'Jeslin', + 'Kenzli', + 'Keisi', + 'Kayelynn', + 'Jaselyn', + 'Mckinnley', + 'Maryse', + 'Peightyn', + 'Latausha', + 'Lety', + 'Tekia', + 'Arasely', + 'Arlynne', + 'Noell', + 'Patrcia', + 'Morning', + 'Meika', + 'Tanda', + 'Terasa', + 'Tika', + 'Roshon', + 'Marlaine', + 'Stephaie', + 'Franne', + 'Ewa', + 'Tomeca', + 'Chequita', + 'Dierdra', + 'Doriann', + 'Tammika', + 'Jeananne', + 'Cythia', + 'Laconda', + 'Catiria', + 'Migna', + 'Latiesha', + 'Sharin', + 'Tekesha', + 'Elga', + 'Barbarajean', + 'Ilena', + 'Evett', + 'Timiko', + 'Kachina', + 'Desere', + 'Galadriel', + 'Lynea', + 'Laurajean', + 'Rukiya', + 'Sakara', + 'Snezana', + 'Tashonda', + 'Orquidea', + 'Myshia', + 'Latrease', + 'Monquie', + 'Robina', + 'Vesna', + 'Faline', + 'Glori', + 'Jennel', + 'Keyatta', + 'Dimitria', + 'Uzma', + 'Lalia', + 'Krystiana', + 'Kaedynce', + 'Juany', + 'Kesley', + 'Kennedee', + 'Keeleigh', + 'Paiten', + 'Neelah', + 'Naylee', + 'Sairy', + 'Rocsi', + 'Mckenzey', + 'Modesty', + 'Abbiegail', + 'Jasalyn', + 'Genises', + 'Emmory', + 'Elisea', + 'Dlaney', + 'Haelee', + 'Jadence', + 'Audryana', + 'Carizma', + 'Josanne', + 'Nashira', + 'Meesha', + 'Taneil', + 'Sobeida', + 'Zakyra', + 'Syndee', + 'Zipora', + 'Amita', + 'Bridie', + 'Hilde', + 'Aspasia', + 'Yalexi', + 'Tenleigh', + 'Anjannette', + 'Zniyah', + 'Zayley', + 'Kyerra', + 'Lynnsey', + 'Dashae', + 'Jasha', + 'Anjenette', + 'Lelania', + 'Mija', + 'Lorrene', + 'Shanyn', + 'Shindana', + 'Shamra', + 'Dove', + 'Drina', + 'Caralee', + 'Charmian', + 'Katrine', + 'Lagina', + 'Jahna', + 'Nesita', + 'Teriana', + 'Dajae', + 'Kyiah', + 'Keslyn', + 'Kayelee', + 'Kamberlyn', + 'Raygen', + 'Orchid', + 'Maleigh', + 'Mairim', + 'Amily', + 'Ameli', + 'Alie', + 'Adelai', + 'Eniola', + 'Enaya', + 'Brealynn', + 'Blakleigh', + 'Ayelene', + 'Camrie', + 'Dianely', + 'Delayne', + 'Cortlyn', + 'Jaylei', + 'Jaycelynn', + 'Jaleigha', + 'Iviana', + 'Kaedance', + 'Jewelz', + 'Jillianna', + 'Faithlyn', + 'Isabeau', + 'Irany', + 'Galiana', + 'Makynzee', + 'Maebry', + 'Merit', + 'Mckinzee', + 'Kinzee', + 'Kendrah', + 'Laityn', + 'Amberlin', + 'Ahliyah', + 'Raphaela', + 'Ameri', + 'Brecklynn', + 'Cristabel', + 'Annalucia', + 'Avri', + 'Averly', + 'Shalia', + 'Sheilla', + 'Dejana', + 'Tonnette', + 'Tracia', + 'Trese', + 'Lalanya', + 'Kristiann', + 'Zunaira', + 'Zinachidi', + 'Xayla', + 'Zaybree', + 'Zanae', + 'Xoey', + 'Sirenity', + 'Renesme', + 'Raeley', + 'Preslyn', + 'Nyx', + 'Nyelli', + 'Rozalynn', + 'Safaa', + 'Abaigeal', + 'Perle', + 'Ersilia', + 'Ethlyn', + 'Dashanae', + 'Dajana', + 'Tahja', + 'Shavona', + 'Vernisha', + 'Sunya', + 'Zenorah', + 'Dorota', + 'Ramsha', + 'Nirali', + 'Najia', + 'Maryclaire', + 'Ismay', + 'Alfonsina', + 'Letizia', + 'Lotta', + 'Honore', + 'Jamille', + 'Kashe', + 'Bonnielee', + 'Lorelle', + 'Gloriajean', + 'Trenae', + 'Tonesha', + 'Maxene', + 'Aliz', + 'Annelyse', + 'Avagrace', + 'Adanelly', + 'Dariella', + 'Colbi', + 'Tema', + 'Marlea', + 'Elleen', + 'Veroncia', + 'Shelina', + 'Sundae', + 'Jericca', + 'Liduvina', + 'Jenney', + 'Pascha', + 'Roshell', + 'Marlies', + 'Marny', + 'Judithann', + 'Nancylee', + 'Freyda', + 'Joyceann', + 'Caroleann', + 'Desirie', + 'Christol', + 'Shulamith', + 'Marlise', + 'Rocquel', + 'Tamsen', + 'Sukari', + 'Tinna', + 'Magdelena', + 'Ruba', + 'Patra', + 'Erryn', + 'Buffi', + 'Chantil', + 'Kerensa', + 'Annastacia', + 'Zailee', + 'Lamika', + 'Kashlynn', + 'Jaedynn', + 'Kaly', + 'Paisyn', + 'Seraiah', + 'Mckenzye', + 'Nhyla', + 'Chandrika', + 'Dawana', + 'Elesha', + 'Caryle', + 'Karrin', + 'Valency', + 'Kianga', + 'Shawndee', + 'Tamasha', + 'Rhodora', + 'Shivangi', + 'Vermont', + 'Diasia', + 'Aniyyah', + 'Azhane', + 'Katleyn', + 'Tynetta', + 'Negan', + 'Marilyne', + 'Leronia', + 'Charmie', + 'Lateefa', + 'Hassanah', + 'Louvinia', + 'Shirly', + 'Sanjna', + 'Andelyn', + 'Jaima', + 'Aftyn', + 'Atira', + 'Weslie', + 'Tayzlee', + 'Rossi', + 'Nayvie', + 'Livvy', + 'Brinklee', + 'Drinda', + 'Nazirah', + 'Krithika', + 'Taisley', + 'Starlee', + 'Bijal', + 'Hiral', + 'Gwynn', + 'Orlene', + 'Maurene', + 'Sweta', + 'Naasia', + 'Luvinia', + 'Sayoko', + 'Geannie', + 'Rupal', + 'Zerlina', + 'Nobu', + 'Taeko', + 'Miye', + 'Carnation', + 'Joplin', + 'Yayeko', + 'Sakaye', + 'Ernell', + 'Tazuko', + 'Bayyinah', + 'Konstantina', + 'Danuta', + 'Cariann', + 'Charnette', + 'Michiye', + 'Tejal', + 'Shaheedah', + 'Zakkiyya', + 'Latoyah', + 'Audre', + 'Tayeko', + 'Qadriyyah', + 'Nikema', + 'Wadeeah', + 'Quanika', + 'Fareeda', + 'Ivelis', + 'Karigan', + 'Yayoi', + 'Tauni', + 'Shailee', + 'Ronnah', + 'Roseana', + 'Rosalita', + 'Orlidia', + 'Mckall', + 'Seattle', + 'Lauree', + 'Georgi', + 'Jacolyn', + 'Meichele', + 'Starlet', + 'Shandee', + 'Miquelle', + 'Cathe', + 'Nondas', + 'Roben', + 'Manette', + 'Monzelle', + 'Genieve', + 'Rumaysa', + 'Dariya', + 'Brynnleigh', + 'Vicci', + 'Sharli', + 'Chandi', + 'Guadelupe', + 'Jamilyn', + 'Willadene', + 'Centhia', + 'Cheryal', + 'Normalee', + 'Wilmajean', + 'Roanne', + 'Dyane', + 'Jinx', + 'Jorene', + 'Ceceilia', + 'Arikka', + 'Latanza', + 'Lacinda', + 'Rus', + 'Sangeeta', + 'Demita', + 'Jerene', + 'Marcellina', + 'Zani', + 'Izzabelle', + 'Graycee', + 'Sajada', + 'Quinlee', + 'Brooklee', + 'Shulamis', + 'Bunnie', + 'Michaelyn', + 'Dhruvi', + 'Sreeja', + 'Tzipa', + 'Doreene', + 'Bedelia', + 'Eutimia', + 'Tomacita', + 'Jerra', + 'Rosela', + 'Ignacita', + 'Conferina', + 'Andreita', + 'Lugardita', + 'Estefanita', + 'Suetta', + 'Debbe', + 'Amadita', + 'Mardel', + 'Mliss', + 'Korla', + 'Felipita', + 'Erminda', + 'Chrys', + 'Karthika', + 'Guilianna', + 'Chasya', + 'Bryndee', + 'Taeler', + 'Sinforosa', + 'Brinnley', + 'Aviya', + 'Jayma', + 'Zimal', + 'Vivia', + 'Arielis', + 'Arshiya', + 'Adiba', + 'Afreen', + 'Ajooni', + 'Alianny', + 'Fariza', + 'Breina', + 'Sila', + 'Aaima', + 'Amesha', + 'Antigone', + 'Kayse', + 'Aurelie', + 'Marianny', + 'Naba', + 'Salimata', + 'Retal', + 'Pema', + 'Pesha', + 'Reemas', + 'Emunah', + 'Farzeen', + 'Safina', + 'Sema', + 'Seynabou', + 'Roza', + 'Romaisa', + 'Yehudit', + 'Tzivi', + 'Tzivy', + 'Zahro', + 'Jeylen', + 'Klea', + 'Namirah', + 'Lamiah', + 'Mahjabeen', + 'Daielle', + 'Ogechi', + 'Laresha', + 'Laqueta', + 'Anayla', + 'Bashy', + 'Naeema', + 'Sarrinah', + 'Sevinch', + 'Frimmy', + 'Hibba', + 'Fajr', + 'Rayhona', + 'Rokia', + 'Wafa', + 'Britne', + 'Crystalann', + 'Reah', + 'Maggi', + 'Lenae', + 'Kambra', + 'Tabita', + 'Tamlyn', + 'Thuytien', + 'Titianna', + 'Trenisha', + 'Yuan', + 'Yarithza', + 'Yarixa', + 'Satin', + 'Elizeth', + 'Gabiela', + 'Jackline', + 'Janisa', + 'Graviela', + 'Gudalupe', + 'Hena', + 'Bryanda', + 'Avilene', + 'Ayerim', + 'Breiana', + 'Nicoleanne', + 'Merisa', + 'Relina', + 'Rebecah', + 'Rachyl', + 'Kasaundra', + 'Katryn', + 'Jeaneth', + 'Jenah', + 'Jocely', + 'Jorgina', + 'Lindsee', + 'Lizvette', + 'Oleen', + 'Waveline', + 'Laurabelle', + 'Charma', + 'Gleneva', + 'Yesika', + 'Felina', + 'Nguyet', + 'Krissie', + 'Silvina', + 'Stephanny', + 'Teera', + 'Kristol', + 'Karisha', + 'Lorisa', + 'Iracema', + 'Temesha', + 'Tamber', + 'Shelisa', + 'Roshana', + 'Rheannon', + 'Amala', + 'Anabelen', + 'Daizhane', + 'Darbie', + 'Dezaree', + 'Dezhane', + 'Carrina', + 'Chessa', + 'Christinejoy', + 'Aliea', + 'Adalhi', + 'Alexandrina', + 'Abrina', + 'Madaleine', + 'Maressa', + 'Marki', + 'Koryna', + 'Lilibet', + 'Mystic', + 'Neyra', + 'Ivonna', + 'Jenalyn', + 'Truc', + 'Berneta', + 'Quinci', + 'Rachelanne', + 'Raylina', + 'Nykole', + 'Stephaney', + 'Seleni', + 'Marvene', + 'Melizza', + 'Aimme', + 'Anaissa', + 'Anhelica', + 'Celyna', + 'Azalie', + 'Bereniz', + 'Meliss', + 'Leanza', + 'Lenina', + 'Karrina', + 'Kalynne', + 'Kanwal', + 'Kazzandra', + 'Mandalyn', + 'Limairy', + 'Lizzete', + 'Lyly', + 'Coua', + 'Icsel', + 'Izamary', + 'Lakindra', + 'Rosezella', + 'Wilhelmine', + 'Clela', + 'Marvelle', + 'Jenafer', + 'Katye', + 'Eliabeth', + 'Angelicamaria', + 'Adrieanna', + 'Caludia', + 'Caycee', + 'Chenay', + 'Cherika', + 'Arpine', + 'Kimberlyanne', + 'Jully', + 'Jyoti', + 'Mariha', + 'Meganelizabeth', + 'Melysa', + 'Lashanay', + 'Jericha', + 'Eliset', + 'Esmirna', + 'Clarie', + 'Conny', + 'Derrisha', + 'Frania', + 'Jeena', + 'Gresia', + 'Hlee', + 'Emanie', + 'Liany', + 'Aisatou', + 'Ashya', + 'Nefertari', + 'Nyanna', + 'Mariem', + 'Michellee', + 'Amenda', + 'Markella', + 'Kiyara', + 'Issamar', + 'Cecilee', + 'Rehana', + 'Nube', + 'Simy', + 'Laneshia', + 'Vasthi', + 'Treanna', + 'Tria', + 'Tuongvi', + 'Brany', + 'Niza', + 'Shandale', + 'Shanley', + 'Shastina', + 'Sheyna', + 'Ronniesha', + 'Rubit', + 'Ruvi', + 'Siobhain', + 'Shauntal', + 'Linzie', + 'Linzi', + 'Fatimatou', + 'Efrat', + 'Jasmely', + 'Kadidia', + 'Kamily', + 'Meirav', + 'Areebah', + 'Fatim', + 'Nuzhat', + 'Saribel', + 'Zorah', + 'Ting', + 'Laporscha', + 'Mieshia', + 'Vanecia', + 'Brittne', + 'Denetria', + 'Deamber', + 'Cymone', + 'Arieal', + 'Araly', + 'Shamieka', + 'Deshay', + 'Britainy', + 'Matraca', + 'Krystyne', + 'Kristela', + 'Kindell', + 'Ceyda', + 'Jahnasia', + 'Halimatou', + 'Graciana', + 'Haja', + 'Safiatou', + 'Su', + 'Zaineb', + 'Yianna', + 'Shilat', + 'Zanai', + 'Zeinabou', + 'Jalysa', + 'Garcia', + 'Jinna', + 'Brytni', + 'Crystalmarie', + 'Kyrstie', + 'Labrea', + 'Laurita', + 'Kathleena', + 'Salimatou', + 'Martisha', + 'Damisha', + 'Londin', + 'Toree', + 'Yadria', + 'Yaminah', + 'Nili', + 'Pella', + 'Menna', + 'Minah', + 'Porshay', + 'Rahwa', + 'Parissa', + 'Nury', + 'Sheeva', + 'Sendi', + 'Aroush', + 'Jerlyn', + 'Momina', + 'Nylia', + 'Mahreen', + 'Mattingly', + 'Emanuella', + 'Ceylin', + 'Biana', + 'Ishrat', + 'Genendy', + 'Hindel', + 'Chavi', + 'Freidy', + 'Rouguiatou', + 'Osnas', + 'Yagmur', + 'Yitel', + 'Hudy', + 'Jamielynn', + 'Valyncia', + 'Cheyla', + 'Assa', + 'Tasmia', + 'Yaslene', + 'Zaima', + 'Jenisse', + 'Juliannah', + 'Reveca', + 'Amra', + 'Anaria', + 'Arlenis', + 'Anastassia', + 'Anique', + 'Arilene', + 'Adileni', + 'Chelcy', + 'Chelesa', + 'Columba', + 'Corri', + 'Briane', + 'Carine', + 'Deziah', + 'Jojo', + 'Jaidalyn', + 'Cecelie', + 'Meagon', + 'Raysha', + 'Mylinh', + 'Madelena', + 'Saniyya', + 'Shama', + 'Shifa', + 'Nyala', + 'Lafaun', + 'Ronnetta', + 'Rondia', + 'Christe', + 'Tynnetta', + 'Ethyle', + 'Bobi', + 'Rayetta', + 'Wilmina', + 'Tangala', + 'Chloris', + 'Marvyl', + 'Larinda', + 'Narcedalia', + 'Tiaa', + 'Terressa', + 'Missi', + 'Ardythe', + 'Briget', + 'Julya', + 'Emilyanne', + 'Ayano', + 'Eliane', + 'Tatem', + 'Roselani', + 'Zareen', + 'Yaxeni', + 'Marleena', + 'Nicolemarie', + 'Patzy', + 'Morgana', + 'Mirca', + 'Mystica', + 'Rosaicela', + 'Rosaysela', + 'Serrena', + 'Shiori', + 'Yannely', + 'Threasa', + 'Zohra', + 'Lanitra', + 'Laquinthia', + 'Deshundra', + 'Mirasol', + 'Lladira', + 'Tejuana', + 'Michaelann', + 'Normajean', + 'Leasha', + 'Kajuana', + 'Xianna', + 'Yaquelyn', + 'Marcea', + 'Mohini', + 'Jaysha', + 'Saysha', + 'Makamae', + 'Lynnett', + 'Mistee', + 'Kaysee', + 'Lizel', + 'Kiora', + 'Kla', + 'Lanay', + 'Kainani', + 'Pomaikai', + 'Piilani', + 'Aulii', + 'Khristi', + 'Delfa', + 'Toka', + 'Satonya', + 'Jammi', + 'Iolani', + 'Hinaea', + 'Ilihia', + 'Kulia', + 'Darcus', + 'Raejean', + 'Brisamar', + 'Francessca', + 'Dhamar', + 'Lehiwa', + 'Ajane', + 'Alexsys', + 'Jema', + 'Imara', + 'Itzanami', + 'Ivori', + 'Tabby', + 'Charnell', + 'Vanessamarie', + 'Vibiana', + 'Kameisha', + 'Edica', + 'Shanetra', + 'Shametria', + 'Quinette', + 'Abreanna', + 'Corazon', + 'Correna', + 'Lilac', + 'Najwa', + 'Moranda', + 'Monik', + 'Deise', + 'Edid', + 'Karinne', + 'Ilsa', + 'Irazema', + 'Pegge', + 'Chenique', + 'Temisha', + 'Cristella', + 'Christle', + 'Falan', + 'Mekesha', + 'Jonquil', + 'Latarya', + 'Maretta', + 'Sonceria', + 'Latamara', + 'Ladina', + 'Rozann', + 'Suz', + 'Aleja', + 'Wray', + 'Indica', + 'Harkiran', + 'Gemini', + 'Erikah', + 'Fey', + 'Gudelia', + 'Komalpreet', + 'Anah', + 'Angelicamarie', + 'Cammi', + 'Dejane', + 'Dejanay', + 'Cilicia', + 'Merla', + 'Janann', + 'Maurita', + 'Aireana', + 'Shuronda', + 'Shunte', + 'Lacrisha', + 'Kwana', + 'Krisi', + 'Kaysi', + 'Latressa', + 'Tyronza', + 'Debralee', + 'Crissie', + 'Crissa', + 'Jameca', + 'Alicha', + 'Ketra', + 'Chrisie', + 'Delecia', + 'Rokisha', + 'Natoshia', + 'Shajuana', + 'Jenipher', + 'Jenefer', + 'Anjanae', + 'Azita', + 'Clairissa', + 'Brezhane', + 'Keera', + 'Siarah', + 'Smita', + 'Savonna', + 'Raquelin', + 'Lorren', + 'Omunique', + 'Molina', + 'Nixaliz', + 'Melitza', + 'Shylo', + 'Teniqua', + 'Charmine', + 'Deonne', + 'Kima', + 'Galit', + 'Ikesha', + 'Jamala', + 'Cherl', + 'Ageliki', + 'Ydania', + 'Kortlyn', + 'Lisvet', + 'Khya', + 'Kearstyn', + 'Seline', + 'Stormey', + 'Rehma', + 'Mckynna', + 'Brynnan', + 'Abiola', + 'Ambriel', + 'Akaysha', + 'Hailea', + 'Fryda', + 'Fedra', + 'Dacie', + 'Deissy', + 'Deyna', + 'Mayling', + 'Tessy', + 'Yaa', + 'Shameca', + 'Shivon', + 'Taesha', + 'Dinamarie', + 'Ifeoma', + 'Ashlye', + 'Patriciajo', + 'Danute', + 'Amalyn', + 'Nakeia', + 'Takima', + 'Shavonn', + 'Katira', + 'Lakema', + 'Jahaida', + 'Marshelle', + 'Angeliki', + 'Carrianne', + 'Carrieanne', + 'Tarika', + 'Sherece', + 'Kalimah', + 'Kinda', + 'Sadiga', + 'Paraskevi', + 'Ayianna', + 'Alezay', + 'Cadynce', + 'Haely', + 'Heavenleigh', + 'Dajanique', + 'Lasharn', + 'Drita', + 'Genene', + 'Gittle', + 'Carriann', + 'Emerita', + 'Jenniferann', + 'Kammie', + 'Bryony', + 'Rupinder', + 'Tenise', + 'Yazmyn', + 'Maricris', + 'Rhianon', + 'Nicolet', + 'Mui', + 'Nacy', + 'Naoko', + 'Gaila', + 'Charene', + 'Bas', + 'Geni', + 'Lorez', + 'Taneeka', + 'Tanikqua', + 'Tulani', + 'Sotiria', + 'Sheeba', + 'Katiuscia', + 'Eleftheria', + 'Ghislaine', + 'Jamiylah', + 'Omotayo', + 'Yuleidy', + 'Tylene', + 'Zanetta', + 'Yizza', + 'Ngan', + 'Natassha', + 'Sophear', + 'Starkisha', + 'Stehanie', + 'Jasie', + 'Aprile', + 'Billiejean', + 'Wilnelia', + 'Yaasmiyn', + 'Ednita', + 'Engracia', + 'Grisell', + 'Christinamarie', + 'Eftihia', + 'Jenniefer', + 'Chantee', + 'Afua', + 'Shamea', + 'Shamina', + 'Vickiana', + 'Sharoya', + 'Shateema', + 'Aubrea', + 'Alexcis', + 'Wallis', + 'Jalyne', + 'Harlea', + 'Carisia', + 'Cheynne', + 'Daylee', + 'Kyera', + 'Latayvia', + 'Raashida', + 'Saajida', + 'Nakema', + 'Annalyssa', + 'Chivonne', + 'Lyndie', + 'Sabrian', + 'Rahcel', + 'Hoai', + 'Krisann', + 'Jilliane', + 'Saide', + 'Matti', + 'Raigen', + 'Tenea', + 'Staphanie', + 'Zitlally', + 'Yudelca', + 'Raysa', + 'Monea', + 'Shanigua', + 'Shirah', + 'Chemise', + 'Jajaira', + 'Tunisha', + 'Yelissa', + 'Yudelka', + 'Taria', + 'Taralynn', + 'Condol', + 'Nikima', + 'Syrianna', + 'Anndrea', + 'Charae', + 'Ebelia', + 'Comfort', + 'Denishia', + 'Lanyia', + 'Lahna', + 'Iraima', + 'Josaline', + 'Onyinyechi', + 'Mykalah', + 'Shamyia', + 'Sarely', + 'Makaylie', + 'Madasyn', + 'Carron', + 'Shawnetta', + 'Dorca', + 'Subrena', + 'Romanda', + 'Sallyanne', + 'Ahniyah', + 'Annalissa', + 'Anikah', + 'Anet', + 'Emelee', + 'Branae', + 'Rosemaria', + 'Kimerly', + 'Lorra', + 'Breda', + 'Graceanne', + 'Kathyann', + 'Letetia', + 'Allaina', + 'Anaceli', + 'Brendalee', + 'Aidaly', + 'Arlana', + 'Trinetta', + 'Tennesha', + 'Talonda', + 'Sherrilynn', + 'Maloree', + 'Laiya', + 'Kynlea', + 'Ludwika', + 'Raeli', + 'Yadirah', + 'Yveth', + 'Sabrie', + 'Dannielynn', + 'Breely', + 'Jozlin', + 'Jewelyssa', + 'Keylie', + 'Jazzalyn', + 'Ijeoma', + 'Jaydie', + 'Irianna', + 'Ronya', + 'Lynee', + 'Myrian', + 'Cristalle', + 'Delinah', + 'Arnetia', + 'Guisela', + 'Orna', + 'Samehesha', + 'Scherrie', + 'Marylynne', + 'Judianne', + 'Tomasina', + 'Sanora', + 'Cheray', + 'Gordana', + 'Torina', + 'Yolandra', + 'Tyese', + 'Sharine', + 'Marea', + 'Areti', + 'Sharmila', + 'Charrise', + 'Cyndia', + 'Cinzia', + 'Gecenia', + 'Tarshia', + 'Luwanda', + 'Negar', + 'Sharah', + 'Sherah', + 'Sokha', + 'Marium', + 'Taslin', + 'Taleyah', + 'Parys', + 'Odeth', + 'Mirabai', + 'Myree', + 'Tyhesha', + 'Soyini', + 'Liria', + 'Jenille', + 'Marivic', + 'Mey', + 'Adrena', + 'Cristyn', + 'Jodette', + 'Ilea', + 'Jennett', + 'Latoi', + 'Charrisse', + 'Correne', + 'Reannon', + 'Shanah', + 'Shavaun', + 'Shelena', + 'Macrina', + 'Lashonna', + 'Tecia', + 'Zobeida', + 'Casilda', + 'Ketsy', + 'Lizza', + 'Lucesita', + 'Anelis', + 'Amori', + 'Atlantis', + 'Aslynn', + 'Kimbery', + 'Yolunda', + 'Pasqua', + 'Magalis', + 'Yanellie', + 'Tryniti', + 'Tniya', + 'Ziza', + 'Nadina', + 'Lloana', + 'Shoshannah', + 'Tamarie', + 'Ronique', + 'Keatyn', + 'Matison', + 'Micalah', + 'Nataya', + 'Mama', + 'Bailea', + 'Sidrah', + 'Jazzman', + 'Deanndra', + 'Shawniece', + 'Polett', + 'Rathana', + 'Timisha', + 'Tristina', + 'Vanezza', + 'Shiri', + 'Stephanieann', + 'Genessy', + 'Hema', + 'Huma', + 'Alessandria', + 'Yarisa', + 'Oyindamola', + 'Tianni', + 'Monasia', + 'Kely', + 'Khady', + 'Pegah', + 'Casarah', + 'Cassara', + 'Chalise', + 'Arti', + 'Natanya', + 'Masuma', + 'Shellyann', + 'Taje', + 'Saher', + 'Kelsye', + 'Odaly', + 'Talicia', + 'Mollee', + 'Tashea', + 'Shima', + 'Janaia', + 'Jenia', + 'Jharline', + 'Chabely', + 'Chalon', + 'Charnesha', + 'Christna', + 'Melika', + 'Melis', + 'Lesleyann', + 'Maleeka', + 'Krystalyn', + 'Krystalynn', + 'Marnisha', + 'Mariele', + 'Michelleann', + 'Melessa', + 'Diasy', + 'Dioselina', + 'Jenita', + 'Jaynae', + 'Jeanae', + 'Hripsime', + 'Janete', + 'Lanique', + 'Ashlon', + 'Aroosa', + 'Enisa', + 'Danaysha', + 'Briani', + 'Arjeta', + 'Sapir', + 'Naysha', + 'Kharisma', + 'Laterra', + 'Yannet', + 'Aruna', + 'Anaja', + 'Fahima', + 'Dasmine', + 'Amberlea', + 'Latiera', + 'Kimanh', + 'Mayuri', + 'Meshelle', + 'Morgane', + 'Nahal', + 'Mariacristina', + 'Marlisha', + 'Elaura', + 'Kacia', + 'Neesha', + 'Tila', + 'Waynisha', + 'Witney', + 'Niloofar', + 'Solina', + 'Soo', + 'Stphanie', + 'Shanesha', + 'Sharrell', + 'Nene', + 'Bleona', + 'Hudes', + 'Isatu', + 'Aylssa', + 'Camerina', + 'Arrielle', + 'Allycia', + 'Anacecilia', + 'Anairis', + 'Courney', + 'Dashanique', + 'Cedrina', + 'Celida', + 'Taaliyah', + 'Clarrissa', + 'Egla', + 'Duyen', + 'Kendle', + 'Janil', + 'Adeola', + 'Jazmene', + 'Leesha', + 'Lyzeth', + 'Madeley', + 'Khrystyna', + 'Charisa', + 'Crystelle', + 'Carinna', + 'Channy', + 'Flory', + 'Glenisha', + 'Sheida', + 'Naara', + 'Nassim', + 'Ngozi', + 'Nidya', + 'Marche', + 'Mariaesther', + 'Shaleena', + 'Kioni', + 'Nayab', + 'Nzinga', + 'Fizza', + 'Diavion', + 'Zanib', + 'Tionni', + 'Temitope', + 'Nasreen', + 'Melaysia', + 'Maame', + 'Sameen', + 'Azka', + 'Basma', + 'Virjean', + 'Jarmila', + 'Louren', + 'Mckenize', + 'Malyn', + 'Mercadies', + 'Vika', + 'Suong', + 'Mariadel', + 'Mariatheresa', + 'Marison', + 'Meleane', + 'Shabana', + 'Salote', + 'Raquell', + 'Rekha', + 'Sibel', + 'Shavaughn', + 'Shaquoia', + 'Shatera', + 'Fatina', + 'Jestina', + 'Latasia', + 'Geraldin', + 'Shirleymae', + 'Lubna', + 'Maxiel', + 'Naquasha', + 'Dalissa', + 'Chaniqua', + 'Chanele', + 'Jahlisa', + 'Faatimah', + 'Abagayle', + 'Adwoa', + 'Angeliqu', + 'Gelisa', + 'Bradi', + 'Shantice', + 'Sharece', + 'Nyiesha', + 'Yanill', + 'Yocasta', + 'Stepheni', + 'Suleika', + 'Takeema', + 'Kerrilyn', + 'Jamiyla', + 'Josephin', + 'Margarit', + 'Ilaisaane', + 'Jamilee', + 'Corvette', + 'Janitza', + 'Lexey', + 'Jazzmyne', + 'Kirstan', + 'Kattia', + 'Yatzary', + 'Pricsilla', + 'Gisette', + 'Panayiota', + 'Pinar', + 'Rasheida', + 'Tiffay', + 'Venisha', + 'Jennier', + 'Margulia', + 'Katima', + 'Anjoli', + 'Evelise', + 'Chetara', + 'Jaquelynn', + 'Pessie', + 'Quintessa', + 'Orit', + 'Nelissa', + 'Shekia', + 'Sherrise', + 'Abbye', + 'Imagine', + 'Britlyn', + 'Baley', + 'Tanequa', + 'Tanique', + 'Nocole', + 'Sokhom', + 'Krystelle', + 'Marqui', + 'Mariaangelica', + 'Raiven', + 'Nini', + 'Lesliee', + 'Crystalee', + 'Amadi', + 'Suzett', + 'Thelda', + 'Wladyslawa', + 'Shaqueen', + 'Shayra', + 'Domingue', + 'Garine', + 'Johnanna', + 'Karia', + 'Jany', + 'Ardele', + 'Bilma', + 'Lindita', + 'Lisbel', + 'Lyasia', + 'Kianie', + 'Saidah', + 'Niasha', + 'Chantele', + 'Brette', + 'Cydnie', + 'Chealsea', + 'Jaritsa', + 'Hanaa', + 'Jordain', + 'Kerria', + 'Shannara', + 'Shaquna', + 'Sultana', + 'Tajana', + 'Taquasha', + 'Queenasia', + 'Wandalee', + 'Mikalyn', + 'Jossette', + 'Jazsmine', + 'Keairra', + 'Arleny', + 'Selest', + 'Sabryn', + 'Jilliann', + 'Janin', + 'Kayliegh', + 'Alyss', + 'Asuka', + 'Chenin', + 'Eiliana', + 'Fahm', + 'Cyndle', + 'Daniesha', + 'Saranda', + 'Shany', + 'Veridiana', + 'Yanai', + 'Melanieann', + 'Mishell', + 'Mariadelosangel', + 'Rupa', + 'Orabelle', + 'Taquasia', + 'Tyquasia', + 'Cecillia', + 'Jeanet', + 'Lucely', + 'Kar', + 'Niaja', + 'Naquana', + 'Joanny', + 'Anjelique', + 'Aquasia', + 'Ardita', + 'Jatasia', + 'Donika', + 'Fantasha', + 'Dominiqua', + 'Elecia', + 'Deyra', + 'Erial', + 'Bayle', + 'Ninoska', + 'Jonee', + 'Jullisa', + 'Lavasia', + 'Laniqua', +]; diff --git a/integration-tests/tests/seeder/lastNames.ts b/integration-tests/tests/seeder/lastNames.ts new file mode 100644 index 000000000..f69f2c629 --- /dev/null +++ b/integration-tests/tests/seeder/lastNames.ts @@ -0,0 +1,50000 @@ +export default [ + 'Smith', + 'Johnson', + 'Williams', + 'Brown', + 'Jones', + 'Miller', + 'Davis', + 'Garcia', + 'Rodriguez', + 'Wilson', + 'Martinez', + 'Anderson', + 'Taylor', + 'Thomas', + 'Hernandez', + 'Moore', + 'Martin', + 'Jackson', + 'Thompson', + 'White', + 'Lopez', + 'Lee', + 'Gonzalez', + 'Harris', + 'Clark', + 'Lewis', + 'Robinson', + 'Walker', + 'Perez', + 'Hall', + 'Young', + 'Allen', + 'Sanchez', + 'Wright', + 'King', + 'Scott', + 'Green', + 'Baker', + 'Adams', + 'Nelson', + 'Hill', + 'Ramirez', + 'Campbell', + 'Mitchell', + 'Roberts', + 'Carter', + 'Phillips', + 'Evans', + 'Turner', + 'Torres', + 'Parker', + 'Collins', + 'Edwards', + 'Stewart', + 'Flores', + 'Morris', + 'Nguyen', + 'Murphy', + 'Rivera', + 'Cook', + 'Rogers', + 'Morgan', + 'Peterson', + 'Cooper', + 'Reed', + 'Bailey', + 'Bell', + 'Gomez', + 'Kelly', + 'Howard', + 'Ward', + 'Cox', + 'Diaz', + 'Richardson', + 'Wood', + 'Watson', + 'Brooks', + 'Bennett', + 'Gray', + 'James', + 'Reyes', + 'Cruz', + 'Hughes', + 'Price', + 'Myers', + 'Long', + 'Foster', + 'Sanders', + 'Ross', + 'Morales', + 'Powell', + 'Sullivan', + 'Russell', + 'Ortiz', + 'Jenkins', + 'Gutierrez', + 'Perry', + 'Butler', + 'Barnes', + 'Fisher', + 'Henderson', + 'Coleman', + 'Simmons', + 'Patterson', + 'Jordan', + 'Reynolds', + 'Hamilton', + 'Graham', + 'Kim', + 'Gonzales', + 'Alexander', + 'Ramos', + 'Wallace', + 'Griffin', + 'West', + 'Cole', + 'Hayes', + 'Chavez', + 'Gibson', + 'Bryant', + 'Ellis', + 'Stevens', + 'Murray', + 'Ford', + 'Marshall', + 'Owens', + 'Mcdonald', + 'Harrison', + 'Ruiz', + 'Kennedy', + 'Wells', + 'Alvarez', + 'Woods', + 'Mendoza', + 'Castillo', + 'Olson', + 'Webb', + 'Washington', + 'Tucker', + 'Freeman', + 'Burns', + 'Henry', + 'Vasquez', + 'Snyder', + 'Simpson', + 'Crawford', + 'Jimenez', + 'Porter', + 'Mason', + 'Shaw', + 'Gordon', + 'Wagner', + 'Hunter', + 'Romero', + 'Hicks', + 'Dixon', + 'Hunt', + 'Palmer', + 'Robertson', + 'Black', + 'Holmes', + 'Stone', + 'Meyer', + 'Boyd', + 'Mills', + 'Warren', + 'Fox', + 'Rose', + 'Rice', + 'Moreno', + 'Schmidt', + 'Patel', + 'Ferguson', + 'Nichols', + 'Herrera', + 'Medina', + 'Ryan', + 'Fernandez', + 'Weaver', + 'Daniels', + 'Stephens', + 'Gardner', + 'Payne', + 'Kelley', + 'Dunn', + 'Pierce', + 'Arnold', + 'Tran', + 'Spencer', + 'Peters', + 'Hawkins', + 'Grant', + 'Hansen', + 'Castro', + 'Hoffman', + 'Hart', + 'Elliott', + 'Cunningham', + 'Knight', + 'Bradley', + 'Carroll', + 'Hudson', + 'Duncan', + 'Armstrong', + 'Berry', + 'Andrews', + 'Johnston', + 'Ray', + 'Lane', + 'Riley', + 'Carpenter', + 'Perkins', + 'Aguilar', + 'Silva', + 'Richards', + 'Willis', + 'Matthews', + 'Chapman', + 'Lawrence', + 'Garza', + 'Vargas', + 'Watkins', + 'Wheeler', + 'Larson', + 'Carlson', + 'Harper', + 'George', + 'Greene', + 'Burke', + 'Guzman', + 'Morrison', + 'Munoz', + 'Jacobs', + 'Obrien', + 'Lawson', + 'Franklin', + 'Lynch', + 'Bishop', + 'Carr', + 'Salazar', + 'Austin', + 'Mendez', + 'Gilbert', + 'Jensen', + 'Williamson', + 'Montgomery', + 'Harvey', + 'Oliver', + 'Howell', + 'Dean', + 'Hanson', + 'Weber', + 'Garrett', + 'Sims', + 'Burton', + 'Fuller', + 'Soto', + 'Mccoy', + 'Welch', + 'Chen', + 'Schultz', + 'Walters', + 'Reid', + 'Fields', + 'Walsh', + 'Little', + 'Fowler', + 'Bowman', + 'Davidson', + 'May', + 'Day', + 'Schneider', + 'Newman', + 'Brewer', + 'Lucas', + 'Holland', + 'Wong', + 'Banks', + 'Santos', + 'Curtis', + 'Pearson', + 'Delgado', + 'Valdez', + 'Pena', + 'Rios', + 'Douglas', + 'Sandoval', + 'Barrett', + 'Hopkins', + 'Keller', + 'Guerrero', + 'Stanley', + 'Bates', + 'Alvarado', + 'Beck', + 'Ortega', + 'Wade', + 'Estrada', + 'Contreras', + 'Barnett', + 'Caldwell', + 'Santiago', + 'Lambert', + 'Powers', + 'Chambers', + 'Nunez', + 'Craig', + 'Leonard', + 'Lowe', + 'Rhodes', + 'Byrd', + 'Gregory', + 'Shelton', + 'Frazier', + 'Becker', + 'Maldonado', + 'Fleming', + 'Vega', + 'Sutton', + 'Cohen', + 'Jennings', + 'Parks', + 'Mcdaniel', + 'Watts', + 'Barker', + 'Norris', + 'Vaughn', + 'Vazquez', + 'Holt', + 'Schwartz', + 'Steele', + 'Benson', + 'Neal', + 'Dominguez', + 'Horton', + 'Terry', + 'Wolfe', + 'Hale', + 'Lyons', + 'Graves', + 'Haynes', + 'Miles', + 'Park', + 'Warner', + 'Padilla', + 'Bush', + 'Thornton', + 'Mccarthy', + 'Mann', + 'Zimmerman', + 'Erickson', + 'Fletcher', + 'Mckinney', + 'Page', + 'Dawson', + 'Joseph', + 'Marquez', + 'Reeves', + 'Klein', + 'Espinoza', + 'Baldwin', + 'Moran', + 'Love', + 'Robbins', + 'Higgins', + 'Ball', + 'Cortez', + 'Le', + 'Griffith', + 'Bowen', + 'Sharp', + 'Cummings', + 'Ramsey', + 'Hardy', + 'Swanson', + 'Barber', + 'Acosta', + 'Luna', + 'Chandler', + 'Blair', + 'Daniel', + 'Cross', + 'Simon', + 'Dennis', + 'Oconnor', + 'Quinn', + 'Gross', + 'Navarro', + 'Moss', + 'Fitzgerald', + 'Doyle', + 'Mclaughlin', + 'Rojas', + 'Rodgers', + 'Stevenson', + 'Singh', + 'Yang', + 'Figueroa', + 'Harmon', + 'Newton', + 'Paul', + 'Manning', + 'Garner', + 'Mcgee', + 'Reese', + 'Francis', + 'Burgess', + 'Adkins', + 'Goodman', + 'Curry', + 'Brady', + 'Christensen', + 'Potter', + 'Walton', + 'Goodwin', + 'Mullins', + 'Molina', + 'Webster', + 'Fischer', + 'Campos', + 'Avila', + 'Sherman', + 'Todd', + 'Chang', + 'Blake', + 'Malone', + 'Wolf', + 'Hodges', + 'Juarez', + 'Gill', + 'Farmer', + 'Hines', + 'Gallagher', + 'Duran', + 'Hubbard', + 'Cannon', + 'Miranda', + 'Wang', + 'Saunders', + 'Tate', + 'Mack', + 'Hammond', + 'Carrillo', + 'Townsend', + 'Wise', + 'Ingram', + 'Barton', + 'Mejia', + 'Ayala', + 'Schroeder', + 'Hampton', + 'Rowe', + 'Parsons', + 'Frank', + 'Waters', + 'Strickland', + 'Osborne', + 'Maxwell', + 'Chan', + 'Deleon', + 'Norman', + 'Harrington', + 'Casey', + 'Patton', + 'Logan', + 'Bowers', + 'Mueller', + 'Glover', + 'Floyd', + 'Hartman', + 'Buchanan', + 'Cobb', + 'French', + 'Kramer', + 'Mccormick', + 'Clarke', + 'Tyler', + 'Gibbs', + 'Moody', + 'Conner', + 'Sparks', + 'Mcguire', + 'Leon', + 'Bauer', + 'Norton', + 'Pope', + 'Flynn', + 'Hogan', + 'Robles', + 'Salinas', + 'Yates', + 'Lindsey', + 'Lloyd', + 'Marsh', + 'Mcbride', + 'Owen', + 'Solis', + 'Pham', + 'Lang', + 'Pratt', + 'Lara', + 'Brock', + 'Ballard', + 'Trujillo', + 'Shaffer', + 'Drake', + 'Roman', + 'Aguirre', + 'Morton', + 'Stokes', + 'Lamb', + 'Pacheco', + 'Patrick', + 'Cochran', + 'Shepherd', + 'Cain', + 'Burnett', + 'Hess', + 'Li', + 'Cervantes', + 'Olsen', + 'Briggs', + 'Ochoa', + 'Cabrera', + 'Velasquez', + 'Montoya', + 'Roth', + 'Meyers', + 'Cardenas', + 'Fuentes', + 'Weiss', + 'Hoover', + 'Wilkins', + 'Nicholson', + 'Underwood', + 'Short', + 'Carson', + 'Morrow', + 'Colon', + 'Holloway', + 'Summers', + 'Bryan', + 'Petersen', + 'Mckenzie', + 'Serrano', + 'Wilcox', + 'Carey', + 'Clayton', + 'Poole', + 'Calderon', + 'Gallegos', + 'Greer', + 'Rivas', + 'Guerra', + 'Decker', + 'Collier', + 'Wall', + 'Whitaker', + 'Bass', + 'Flowers', + 'Davenport', + 'Conley', + 'Houston', + 'Huff', + 'Copeland', + 'Hood', + 'Monroe', + 'Massey', + 'Roberson', + 'Combs', + 'Franco', + 'Larsen', + 'Pittman', + 'Randall', + 'Skinner', + 'Wilkinson', + 'Kirby', + 'Cameron', + 'Bridges', + 'Anthony', + 'Richard', + 'Kirk', + 'Bruce', + 'Singleton', + 'Mathis', + 'Bradford', + 'Boone', + 'Abbott', + 'Charles', + 'Allison', + 'Sweeney', + 'Atkinson', + 'Horn', + 'Jefferson', + 'Rosales', + 'York', + 'Christian', + 'Phelps', + 'Farrell', + 'Castaneda', + 'Nash', + 'Dickerson', + 'Bond', + 'Wyatt', + 'Foley', + 'Chase', + 'Gates', + 'Vincent', + 'Mathews', + 'Hodge', + 'Garrison', + 'Trevino', + 'Villarreal', + 'Heath', + 'Dalton', + 'Valencia', + 'Callahan', + 'Hensley', + 'Atkins', + 'Huffman', + 'Roy', + 'Boyer', + 'Shields', + 'Lin', + 'Hancock', + 'Grimes', + 'Glenn', + 'Cline', + 'Delacruz', + 'Camacho', + 'Dillon', + 'Parrish', + 'Oneill', + 'Melton', + 'Booth', + 'Kane', + 'Berg', + 'Harrell', + 'Pitts', + 'Savage', + 'Wiggins', + 'Brennan', + 'Salas', + 'Marks', + 'Russo', + 'Sawyer', + 'Baxter', + 'Golden', + 'Hutchinson', + 'Liu', + 'Walter', + 'Mcdowell', + 'Wiley', + 'Rich', + 'Humphrey', + 'Johns', + 'Koch', + 'Suarez', + 'Hobbs', + 'Beard', + 'Gilmore', + 'Ibarra', + 'Keith', + 'Macias', + 'Khan', + 'Andrade', + 'Ware', + 'Stephenson', + 'Henson', + 'Wilkerson', + 'Dyer', + 'Mcclure', + 'Blackwell', + 'Mercado', + 'Tanner', + 'Eaton', + 'Clay', + 'Barron', + 'Beasley', + 'Oneal', + 'Preston', + 'Small', + 'Wu', + 'Zamora', + 'Macdonald', + 'Vance', + 'Snow', + 'Mcclain', + 'Stafford', + 'Orozco', + 'Barry', + 'English', + 'Shannon', + 'Kline', + 'Jacobson', + 'Woodard', + 'Huang', + 'Kemp', + 'Mosley', + 'Prince', + 'Merritt', + 'Hurst', + 'Villanueva', + 'Roach', + 'Nolan', + 'Lam', + 'Yoder', + 'Mccullough', + 'Lester', + 'Santana', + 'Valenzuela', + 'Winters', + 'Barrera', + 'Leach', + 'Orr', + 'Berger', + 'Mckee', + 'Strong', + 'Conway', + 'Stein', + 'Whitehead', + 'Bullock', + 'Escobar', + 'Knox', + 'Meadows', + 'Solomon', + 'Velez', + 'Odonnell', + 'Kerr', + 'Stout', + 'Blankenship', + 'Browning', + 'Kent', + 'Lozano', + 'Bartlett', + 'Pruitt', + 'Buck', + 'Barr', + 'Gaines', + 'Durham', + 'Gentry', + 'Mcintyre', + 'Sloan', + 'Rocha', + 'Melendez', + 'Herman', + 'Sexton', + 'Moon', + 'Hendricks', + 'Rangel', + 'Stark', + 'Lowery', + 'Hardin', + 'Hull', + 'Sellers', + 'Ellison', + 'Calhoun', + 'Gillespie', + 'Mora', + 'Knapp', + 'Mccall', + 'Morse', + 'Dorsey', + 'Weeks', + 'Nielsen', + 'Livingston', + 'Leblanc', + 'Mclean', + 'Bradshaw', + 'Glass', + 'Middleton', + 'Buckley', + 'Schaefer', + 'Frost', + 'Howe', + 'House', + 'Mcintosh', + 'Ho', + 'Pennington', + 'Reilly', + 'Hebert', + 'Mcfarland', + 'Hickman', + 'Noble', + 'Spears', + 'Conrad', + 'Arias', + 'Galvan', + 'Velazquez', + 'Huynh', + 'Frederick', + 'Randolph', + 'Cantu', + 'Fitzpatrick', + 'Mahoney', + 'Peck', + 'Villa', + 'Michael', + 'Donovan', + 'Mcconnell', + 'Walls', + 'Boyle', + 'Mayer', + 'Zuniga', + 'Giles', + 'Pineda', + 'Pace', + 'Hurley', + 'Mays', + 'Mcmillan', + 'Crosby', + 'Ayers', + 'Case', + 'Bentley', + 'Shepard', + 'Everett', + 'Pugh', + 'David', + 'Mcmahon', + 'Dunlap', + 'Bender', + 'Hahn', + 'Harding', + 'Acevedo', + 'Raymond', + 'Blackburn', + 'Duffy', + 'Landry', + 'Dougherty', + 'Bautista', + 'Shah', + 'Potts', + 'Arroyo', + 'Valentine', + 'Meza', + 'Gould', + 'Vaughan', + 'Fry', + 'Rush', + 'Avery', + 'Herring', + 'Dodson', + 'Clements', + 'Sampson', + 'Tapia', + 'Bean', + 'Lynn', + 'Crane', + 'Farley', + 'Cisneros', + 'Benton', + 'Ashley', + 'Mckay', + 'Finley', + 'Best', + 'Blevins', + 'Friedman', + 'Moses', + 'Sosa', + 'Blanchard', + 'Huber', + 'Frye', + 'Krueger', + 'Bernard', + 'Rosario', + 'Rubio', + 'Mullen', + 'Benjamin', + 'Haley', + 'Chung', + 'Moyer', + 'Choi', + 'Horne', + 'Yu', + 'Woodward', + 'Ali', + 'Nixon', + 'Hayden', + 'Rivers', + 'Estes', + 'Mccarty', + 'Richmond', + 'Stuart', + 'Maynard', + 'Brandt', + 'Oconnell', + 'Hanna', + 'Sanford', + 'Sheppard', + 'Church', + 'Burch', + 'Levy', + 'Rasmussen', + 'Coffey', + 'Ponce', + 'Faulkner', + 'Donaldson', + 'Schmitt', + 'Novak', + 'Costa', + 'Montes', + 'Booker', + 'Cordova', + 'Waller', + 'Arellano', + 'Maddox', + 'Mata', + 'Bonilla', + 'Stanton', + 'Compton', + 'Kaufman', + 'Dudley', + 'Mcpherson', + 'Beltran', + 'Dickson', + 'Mccann', + 'Villegas', + 'Proctor', + 'Hester', + 'Cantrell', + 'Daugherty', + 'Cherry', + 'Bray', + 'Davila', + 'Rowland', + 'Levine', + 'Madden', + 'Spence', + 'Good', + 'Irwin', + 'Werner', + 'Krause', + 'Petty', + 'Whitney', + 'Baird', + 'Hooper', + 'Pollard', + 'Zavala', + 'Jarvis', + 'Holden', + 'Haas', + 'Hendrix', + 'Mcgrath', + 'Bird', + 'Lucero', + 'Terrell', + 'Riggs', + 'Joyce', + 'Mercer', + 'Rollins', + 'Galloway', + 'Duke', + 'Odom', + 'Andersen', + 'Downs', + 'Hatfield', + 'Benitez', + 'Archer', + 'Huerta', + 'Travis', + 'Mcneil', + 'Hinton', + 'Zhang', + 'Hays', + 'Mayo', + 'Fritz', + 'Branch', + 'Mooney', + 'Ewing', + 'Ritter', + 'Esparza', + 'Frey', + 'Braun', + 'Gay', + 'Riddle', + 'Haney', + 'Kaiser', + 'Holder', + 'Chaney', + 'Mcknight', + 'Gamble', + 'Vang', + 'Cooley', + 'Carney', + 'Cowan', + 'Forbes', + 'Ferrell', + 'Davies', + 'Barajas', + 'Shea', + 'Osborn', + 'Bright', + 'Cuevas', + 'Bolton', + 'Murillo', + 'Lutz', + 'Duarte', + 'Kidd', + 'Key', + 'Cooke', + 'Goff', + 'Dejesus', + 'Marin', + 'Dotson', + 'Bonner', + 'Cotton', + 'Merrill', + 'Lindsay', + 'Lancaster', + 'Mcgowan', + 'Felix', + 'Salgado', + 'Slater', + 'Carver', + 'Guthrie', + 'Holman', + 'Fulton', + 'Snider', + 'Sears', + 'Witt', + 'Newell', + 'Byers', + 'Lehman', + 'Gorman', + 'Costello', + 'Donahue', + 'Delaney', + 'Albert', + 'Workman', + 'Rosas', + 'Springer', + 'Kinney', + 'Justice', + 'Odell', + 'Lake', + 'Donnelly', + 'Law', + 'Dailey', + 'Guevara', + 'Shoemaker', + 'Barlow', + 'Marino', + 'Winter', + 'Craft', + 'Katz', + 'Pickett', + 'Espinosa', + 'Maloney', + 'Daly', + 'Goldstein', + 'Crowley', + 'Vogel', + 'Kuhn', + 'Pearce', + 'Hartley', + 'Cleveland', + 'Palacios', + 'Mcfadden', + 'Britt', + 'Wooten', + 'Cortes', + 'Dillard', + 'Childers', + 'Alford', + 'Dodd', + 'Emerson', + 'Wilder', + 'Lange', + 'Goldberg', + 'Quintero', + 'Beach', + 'Enriquez', + 'Quintana', + 'Helms', + 'Mackey', + 'Finch', + 'Cramer', + 'Minor', + 'Flanagan', + 'Franks', + 'Corona', + 'Kendall', + 'Mccabe', + 'Hendrickson', + 'Moser', + 'Mcdermott', + 'Camp', + 'Mcleod', + 'Bernal', + 'Kaplan', + 'Medrano', + 'Lugo', + 'Tracy', + 'Bacon', + 'Crowe', + 'Richter', + 'Welsh', + 'Holley', + 'Ratliff', + 'Mayfield', + 'Talley', + 'Haines', + 'Dale', + 'Gibbons', + 'Hickey', + 'Byrne', + 'Kirkland', + 'Farris', + 'Correa', + 'Tillman', + 'Sweet', + 'Kessler', + 'England', + 'Hewitt', + 'Blanco', + 'Connolly', + 'Pate', + 'Elder', + 'Bruno', + 'Holcomb', + 'Hyde', + 'Mcallister', + 'Cash', + 'Christopher', + 'Whitfield', + 'Meeks', + 'Hatcher', + 'Fink', + 'Sutherland', + 'Noel', + 'Ritchie', + 'Rosa', + 'Leal', + 'Joyner', + 'Starr', + 'Morin', + 'Delarosa', + 'Connor', + 'Hilton', + 'Alston', + 'Gilliam', + 'Wynn', + 'Wills', + 'Jaramillo', + 'Oneil', + 'Nieves', + 'Britton', + 'Rankin', + 'Belcher', + 'Guy', + 'Chamberlain', + 'Tyson', + 'Puckett', + 'Downing', + 'Sharpe', + 'Boggs', + 'Truong', + 'Pierson', + 'Godfrey', + 'Mobley', + 'John', + 'Kern', + 'Dye', + 'Hollis', + 'Bravo', + 'Magana', + 'Rutherford', + 'Ng', + 'Tuttle', + 'Lim', + 'Romano', + 'Trejo', + 'Arthur', + 'Knowles', + 'Lyon', + 'Shirley', + 'Quinones', + 'Childs', + 'Dolan', + 'Head', + 'Reyna', + 'Saenz', + 'Hastings', + 'Kenney', + 'Cano', + 'Foreman', + 'Denton', + 'Villalobos', + 'Pryor', + 'Sargent', + 'Doherty', + 'Hopper', + 'Phan', + 'Womack', + 'Lockhart', + 'Ventura', + 'Dwyer', + 'Muller', + 'Galindo', + 'Grace', + 'Sorensen', + 'Courtney', + 'Parra', + 'Rodrigues', + 'Nicholas', + 'Ahmed', + 'Mcginnis', + 'Langley', + 'Madison', + 'Locke', + 'Jamison', + 'Nava', + 'Gustafson', + 'Sykes', + 'Dempsey', + 'Hamm', + 'Rodriquez', + 'Mcgill', + 'Xiong', + 'Esquivel', + 'Simms', + 'Kendrick', + 'Boyce', + 'Vigil', + 'Downey', + 'Mckenna', + 'Sierra', + 'Webber', + 'Kirkpatrick', + 'Dickinson', + 'Couch', + 'Burks', + 'Sheehan', + 'Slaughter', + 'Pike', + 'Whitley', + 'Magee', + 'Cheng', + 'Sinclair', + 'Cassidy', + 'Rutledge', + 'Burris', + 'Bowling', + 'Crabtree', + 'Mcnamara', + 'Avalos', + 'Vu', + 'Herron', + 'Broussard', + 'Abraham', + 'Garland', + 'Corbett', + 'Corbin', + 'Stinson', + 'Chin', + 'Burt', + 'Hutchins', + 'Woodruff', + 'Lau', + 'Brandon', + 'Singer', + 'Hatch', + 'Rossi', + 'Shafer', + 'Ott', + 'Goss', + 'Gregg', + 'Dewitt', + 'Tang', + 'Polk', + 'Worley', + 'Covington', + 'Saldana', + 'Heller', + 'Emery', + 'Swartz', + 'Cho', + 'Mccray', + 'Elmore', + 'Rosenberg', + 'Simons', + 'Clemons', + 'Beatty', + 'Harden', + 'Herbert', + 'Bland', + 'Rucker', + 'Manley', + 'Ziegler', + 'Grady', + 'Lott', + 'Rouse', + 'Gleason', + 'Mcclellan', + 'Abrams', + 'Vo', + 'Albright', + 'Meier', + 'Dunbar', + 'Ackerman', + 'Padgett', + 'Mayes', + 'Tipton', + 'Coffman', + 'Peralta', + 'Shapiro', + 'Roe', + 'Weston', + 'Plummer', + 'Helton', + 'Stern', + 'Fraser', + 'Stover', + 'Fish', + 'Schumacher', + 'Baca', + 'Curran', + 'Vinson', + 'Vera', + 'Clifton', + 'Ervin', + 'Eldridge', + 'Lowry', + 'Childress', + 'Becerra', + 'Gore', + 'Seymour', + 'Chu', + 'Field', + 'Akers', + 'Carrasco', + 'Bingham', + 'Sterling', + 'Greenwood', + 'Leslie', + 'Groves', + 'Manuel', + 'Swain', + 'Edmonds', + 'Muniz', + 'Thomson', + 'Crouch', + 'Walden', + 'Smart', + 'Tomlinson', + 'Alfaro', + 'Quick', + 'Goldman', + 'Mcelroy', + 'Yarbrough', + 'Funk', + 'Hong', + 'Portillo', + 'Lund', + 'Ngo', + 'Elkins', + 'Stroud', + 'Meredith', + 'Battle', + 'Mccauley', + 'Zapata', + 'Bloom', + 'Gee', + 'Givens', + 'Cardona', + 'Schafer', + 'Robison', + 'Gunter', + 'Griggs', + 'Tovar', + 'Teague', + 'Swift', + 'Bowden', + 'Schulz', + 'Blanton', + 'Buckner', + 'Whalen', + 'Pritchard', + 'Pierre', + 'Kang', + 'Metcalf', + 'Butts', + 'Kurtz', + 'Sanderson', + 'Tompkins', + 'Inman', + 'Crowder', + 'Dickey', + 'Hutchison', + 'Conklin', + 'Hoskins', + 'Holbrook', + 'Horner', + 'Neely', + 'Tatum', + 'Hollingsworth', + 'Draper', + 'Clement', + 'Lord', + 'Reece', + 'Feldman', + 'Kay', + 'Hagen', + 'Crews', + 'Bowles', + 'Post', + 'Jewell', + 'Daley', + 'Cordero', + 'Mckinley', + 'Velasco', + 'Masters', + 'Driscoll', + 'Burrell', + 'Valle', + 'Crow', + 'Devine', + 'Larkin', + 'Chappell', + 'Pollock', + 'Ly', + 'Kimball', + 'Schmitz', + 'Lu', + 'Rubin', + 'Self', + 'Barrios', + 'Pereira', + 'Phipps', + 'Mcmanus', + 'Nance', + 'Steiner', + 'Poe', + 'Crockett', + 'Jeffries', + 'Amos', + 'Nix', + 'Newsome', + 'Dooley', + 'Payton', + 'Rosen', + 'Swenson', + 'Connelly', + 'Tolbert', + 'Segura', + 'Esposito', + 'Coker', + 'Biggs', + 'Hinkle', + 'Thurman', + 'Drew', + 'Ivey', + 'Bullard', + 'Baez', + 'Neff', + 'Maher', + 'Stratton', + 'Egan', + 'Dubois', + 'Gallardo', + 'Blue', + 'Rainey', + 'Yeager', + 'Saucedo', + 'Ferreira', + 'Sprague', + 'Lacy', + 'Hurtado', + 'Heard', + 'Connell', + 'Stahl', + 'Aldridge', + 'Amaya', + 'Forrest', + 'Erwin', + 'Gunn', + 'Swan', + 'Butcher', + 'Rosado', + 'Godwin', + 'Hand', + 'Gabriel', + 'Otto', + 'Whaley', + 'Ludwig', + 'Clifford', + 'Grove', + 'Beaver', + 'Silver', + 'Dang', + 'Hammer', + 'Dick', + 'Boswell', + 'Mead', + 'Colvin', + 'Oleary', + 'Milligan', + 'Goins', + 'Ames', + 'Dodge', + 'Kaur', + 'Escobedo', + 'Arredondo', + 'Geiger', + 'Winkler', + 'Dunham', + 'Temple', + 'Babcock', + 'Billings', + 'Grimm', + 'Lilly', + 'Wesley', + 'Mcghee', + 'Siegel', + 'Painter', + 'Bower', + 'Purcell', + 'Block', + 'Aguilera', + 'Norwood', + 'Sheridan', + 'Cartwright', + 'Coates', + 'Davison', + 'Regan', + 'Ramey', + 'Koenig', + 'Kraft', + 'Bunch', + 'Engel', + 'Tan', + 'Winn', + 'Steward', + 'Link', + 'Vickers', + 'Bragg', + 'Piper', + 'Huggins', + 'Michel', + 'Healy', + 'Jacob', + 'Mcdonough', + 'Wolff', + 'Colbert', + 'Zepeda', + 'Hoang', + 'Dugan', + 'Meade', + 'Kilgore', + 'Guillen', + 'Do', + 'Hinojosa', + 'Goode', + 'Arrington', + 'Gary', + 'Snell', + 'Willard', + 'Renteria', + 'Chacon', + 'Gallo', + 'Hankins', + 'Montano', + 'Browne', + 'Peacock', + 'Ohara', + 'Cornell', + 'Sherwood', + 'Castellanos', + 'Thorpe', + 'Stiles', + 'Sadler', + 'Latham', + 'Redmond', + 'Greenberg', + 'Cote', + 'Waddell', + 'Dukes', + 'Diamond', + 'Bui', + 'Madrid', + 'Alonso', + 'Sheets', + 'Irvin', + 'Hurt', + 'Ferris', + 'Sewell', + 'Carlton', + 'Aragon', + 'Blackmon', + 'Hadley', + 'Hoyt', + 'Mcgraw', + 'Pagan', + 'Land', + 'Tidwell', + 'Lovell', + 'Miner', + 'Doss', + 'Dahl', + 'Delatorre', + 'Stanford', + 'Kauffman', + 'Vela', + 'Gagnon', + 'Winston', + 'Gomes', + 'Thacker', + 'Coronado', + 'Ash', + 'Jarrett', + 'Hager', + 'Samuels', + 'Metzger', + 'Raines', + 'Spivey', + 'Maurer', + 'Han', + 'Voss', + 'Henley', + 'Caballero', + 'Caruso', + 'Coulter', + 'North', + 'Finn', + 'Cahill', + 'Lanier', + 'Souza', + 'Mcwilliams', + 'Deal', + 'Urban', + 'Schaffer', + 'Houser', + 'Cummins', + 'Romo', + 'Crocker', + 'Bassett', + 'Kruse', + 'Bolden', + 'Ybarra', + 'Metz', + 'Root', + 'Mcmullen', + 'Hagan', + 'Crump', + 'Guidry', + 'Brantley', + 'Kearney', + 'Beal', + 'Toth', + 'Jorgensen', + 'Timmons', + 'Milton', + 'Tripp', + 'Hurd', + 'Sapp', + 'Whitman', + 'Messer', + 'Burgos', + 'Major', + 'Westbrook', + 'Castle', + 'Serna', + 'Carlisle', + 'Varela', + 'Cullen', + 'Wilhelm', + 'Bergeron', + 'Burger', + 'Posey', + 'Barnhart', + 'Hackett', + 'Madrigal', + 'Eubanks', + 'Sizemore', + 'Hilliard', + 'Hargrove', + 'Boucher', + 'Thomason', + 'Melvin', + 'Roper', + 'Barnard', + 'Fonseca', + 'Pedersen', + 'Quiroz', + 'Washburn', + 'Holliday', + 'Yee', + 'Rudolph', + 'Bermudez', + 'Coyle', + 'Gil', + 'Pina', + 'Goodrich', + 'Elias', + 'Lockwood', + 'Cabral', + 'Carranza', + 'Duvall', + 'Cornelius', + 'Mccollum', + 'Street', + 'Mcneal', + 'Connors', + 'Angel', + 'Paulson', + 'Hinson', + 'Keenan', + 'Sheldon', + 'Farr', + 'Eddy', + 'Samuel', + 'Ring', + 'Ledbetter', + 'Betts', + 'Fontenot', + 'Gifford', + 'Hannah', + 'Hanley', + 'Person', + 'Fountain', + 'Levin', + 'Stubbs', + 'Hightower', + 'Murdock', + 'Koehler', + 'Ma', + 'Engle', + 'Smiley', + 'Carmichael', + 'Sheffield', + 'Langston', + 'Mccracken', + 'Yost', + 'Trotter', + 'Story', + 'Starks', + 'Lujan', + 'Blount', + 'Cody', + 'Rushing', + 'Benoit', + 'Herndon', + 'Jacobsen', + 'Nieto', + 'Wiseman', + 'Layton', + 'Epps', + 'Shipley', + 'Leyva', + 'Reeder', + 'Brand', + 'Roland', + 'Fitch', + 'Rico', + 'Napier', + 'Cronin', + 'Mcqueen', + 'Paredes', + 'Trent', + 'Christiansen', + 'Spangler', + 'Pettit', + 'Langford', + 'Benavides', + 'Penn', + 'Paige', + 'Weir', + 'Dietz', + 'Prater', + 'Brewster', + 'Louis', + 'Diehl', + 'Pack', + 'Spaulding', + 'Ernst', + 'Aviles', + 'Nowak', + 'Olvera', + 'Rock', + 'Mansfield', + 'Aquino', + 'Ogden', + 'Stacy', + 'Rizzo', + 'Sylvester', + 'Gillis', + 'Sands', + 'Machado', + 'Lovett', + 'Duong', + 'Hyatt', + 'Landis', + 'Platt', + 'Bustamante', + 'Hedrick', + 'Pritchett', + 'Gaston', + 'Dobson', + 'Caudill', + 'Tackett', + 'Bateman', + 'Landers', + 'Carmona', + 'Gipson', + 'Uribe', + 'Mcneill', + 'Ledford', + 'Mims', + 'Abel', + 'Gold', + 'Smallwood', + 'Thorne', + 'Mchugh', + 'Dickens', + 'Leung', + 'Tobin', + 'Kowalski', + 'Medeiros', + 'Cope', + 'Quezada', + 'Kraus', + 'Overton', + 'Montalvo', + 'Staley', + 'Woody', + 'Hathaway', + 'Osorio', + 'Laird', + 'Dobbs', + 'Capps', + 'Putnam', + 'Lay', + 'Francisco', + 'Bernstein', + 'Adair', + 'Hutton', + 'Burkett', + 'Rhoades', + 'Yanez', + 'Richey', + 'Bledsoe', + 'Mccain', + 'Beyer', + 'Cates', + 'Roche', + 'Spicer', + 'Queen', + 'Doty', + 'Darling', + 'Darby', + 'Sumner', + 'Kincaid', + 'Hay', + 'Grossman', + 'Lacey', + 'Wilkes', + 'Humphries', + 'Paz', + 'Darnell', + 'Keys', + 'Kyle', + 'Lackey', + 'Vogt', + 'Locklear', + 'Kiser', + 'Presley', + 'Bryson', + 'Bergman', + 'Peoples', + 'Fair', + 'Mcclendon', + 'Corley', + 'Prado', + 'Christie', + 'Delong', + 'Skaggs', + 'Dill', + 'Shearer', + 'Judd', + 'Stapleton', + 'Flaherty', + 'Casillas', + 'Pinto', + 'Youngblood', + 'Haywood', + 'Toney', + 'Ricks', + 'Granados', + 'Crum', + 'Triplett', + 'Soriano', + 'Waite', + 'Hoff', + 'Anaya', + 'Crenshaw', + 'Jung', + 'Canales', + 'Cagle', + 'Denny', + 'Marcus', + 'Berman', + 'Munson', + 'Ocampo', + 'Bauman', + 'Corcoran', + 'Keen', + 'Zimmer', + 'Friend', + 'Ornelas', + 'Varner', + 'Pelletier', + 'Vernon', + 'Blum', + 'Albrecht', + 'Culver', + 'Schuster', + 'Cuellar', + 'Mccord', + 'Shultz', + 'Mcrae', + 'Moreland', + 'Calvert', + 'William', + 'Whittington', + 'Eckert', + 'Keene', + 'Mohr', + 'Hanks', + 'Kimble', + 'Cavanaugh', + 'Crowell', + 'Russ', + 'Feliciano', + 'Crain', + 'Busch', + 'Mccormack', + 'Drummond', + 'Omalley', + 'Aldrich', + 'Luke', + 'Greco', + 'Mott', + 'Oakes', + 'Mallory', + 'Mclain', + 'Burrows', + 'Otero', + 'Allred', + 'Eason', + 'Finney', + 'Weller', + 'Waldron', + 'Champion', + 'Jeffers', + 'Coon', + 'Rosenthal', + 'Huddleston', + 'Solano', + 'Hirsch', + 'Akins', + 'Olivares', + 'Song', + 'Sneed', + 'Benedict', + 'Bain', + 'Okeefe', + 'Hidalgo', + 'Matos', + 'Stallings', + 'Paris', + 'Gamez', + 'Kenny', + 'Quigley', + 'Marrero', + 'Fagan', + 'Dutton', + 'Pappas', + 'Atwood', + 'Mcgovern', + 'Bagley', + 'Read', + 'Lunsford', + 'Moseley', + 'Oakley', + 'Ashby', + 'Granger', + 'Shaver', + 'Hope', + 'Coe', + 'Burroughs', + 'Helm', + 'Neumann', + 'Ambrose', + 'Michaels', + 'Prescott', + 'Light', + 'Dumas', + 'Flood', + 'Stringer', + 'Currie', + 'Comer', + 'Fong', + 'Whitlock', + 'Lemus', + 'Hawley', + 'Ulrich', + 'Staples', + 'Boykin', + 'Knutson', + 'Grover', + 'Hobson', + 'Cormier', + 'Doran', + 'Thayer', + 'Woodson', + 'Whitt', + 'Hooker', + 'Kohler', + 'Vandyke', + 'Addison', + 'Schrader', + 'Haskins', + 'Whittaker', + 'Madsen', + 'Gauthier', + 'Burnette', + 'Keating', + 'Purvis', + 'Aleman', + 'Huston', + 'Pimentel', + 'Hamlin', + 'Gerber', + 'Hooks', + 'Schwab', + 'Honeycutt', + 'Schulte', + 'Alonzo', + 'Isaac', + 'Conroy', + 'Adler', + 'Eastman', + 'Cottrell', + 'Orourke', + 'Hawk', + 'Goldsmith', + 'Rader', + 'Crandall', + 'Reynoso', + 'Shook', + 'Abernathy', + 'Baer', + 'Olivas', + 'Grayson', + 'Bartley', + 'Henning', + 'Parr', + 'Duff', + 'Brunson', + 'Baum', + 'Ennis', + 'Laughlin', + 'Foote', + 'Valadez', + 'Adamson', + 'Begay', + 'Stovall', + 'Lincoln', + 'Cheung', + 'Malloy', + 'Rider', + 'Giordano', + 'Jansen', + 'Lopes', + 'Arnett', + 'Pendleton', + 'Gage', + 'Barragan', + 'Keyes', + 'Navarrete', + 'Amador', + 'Hoffmann', + 'Schilling', + 'Hawthorne', + 'Perdue', + 'Schreiber', + 'Arevalo', + 'Naylor', + 'Deluca', + 'Marcum', + 'Altman', + 'Mark', + 'Chadwick', + 'Doan', + 'Easley', + 'Ladd', + 'Woodall', + 'Betancourt', + 'Shin', + 'Maguire', + 'Bellamy', + 'Quintanilla', + 'Ham', + 'Sorenson', + 'Mattson', + 'Brenner', + 'Means', + 'Faust', + 'Calloway', + 'Ojeda', + 'Mcnally', + 'Dietrich', + 'Ransom', + 'Hare', + 'Felton', + 'Whiting', + 'Burkhart', + 'Clinton', + 'Schwarz', + 'Cleary', + 'Wetzel', + 'Reagan', + 'Stjohn', + 'Chow', + 'Hauser', + 'Dupree', + 'Brannon', + 'Lyles', + 'Prather', + 'Willoughby', + 'Sepulveda', + 'Nugent', + 'Pickens', + 'Mosher', + 'Joiner', + 'Stoner', + 'Dowling', + 'Trimble', + 'Valdes', + 'Cheek', + 'Scruggs', + 'Coy', + 'Tilley', + 'Barney', + 'Saylor', + 'Nagy', + 'Horvath', + 'Lai', + 'Corey', + 'Ruth', + 'Sauer', + 'Baron', + 'Thao', + 'Rowell', + 'Grubbs', + 'Schaeffer', + 'Hillman', + 'Sams', + 'Hogue', + 'Hutson', + 'Busby', + 'Nickerson', + 'Bruner', + 'Parham', + 'Rendon', + 'Anders', + 'Lombardo', + 'Iverson', + 'Kinsey', + 'Earl', + 'Borden', + 'Titus', + 'Jean', + 'Tellez', + 'Beavers', + 'Cornett', + 'Sotelo', + 'Kellogg', + 'Silverman', + 'Burnham', + 'Mcnair', + 'Jernigan', + 'Escamilla', + 'Barrow', + 'Coats', + 'London', + 'Redding', + 'Ruffin', + 'Yi', + 'Boudreaux', + 'Goodson', + 'Dowell', + 'Fenton', + 'Mock', + 'Dozier', + 'Bynum', + 'Gale', + 'Jolly', + 'Beckman', + 'Goddard', + 'Craven', + 'Whitmore', + 'Leary', + 'Mccloud', + 'Gamboa', + 'Kerns', + 'Brunner', + 'Negron', + 'Hough', + 'Cutler', + 'Ledesma', + 'Pyle', + 'Monahan', + 'Tabor', + 'Burk', + 'Leone', + 'Stauffer', + 'Hayward', + 'Driver', + 'Ruff', + 'Talbot', + 'Seals', + 'Boston', + 'Carbajal', + 'Fay', + 'Purdy', + 'Mcgregor', + 'Sun', + 'Orellana', + 'Gentile', + 'Mahan', + 'Brower', + 'Patino', + 'Thurston', + 'Shipman', + 'Torrez', + 'Aaron', + 'Weiner', + 'Call', + 'Wilburn', + 'Oliva', + 'Hairston', + 'Coley', + 'Hummel', + 'Arreola', + 'Watt', + 'Sharma', + 'Lentz', + 'Arce', + 'Power', + 'Longoria', + 'Wagoner', + 'Burr', + 'Hsu', + 'Tinsley', + 'Beebe', + 'Wray', + 'Nunn', + 'Prieto', + 'German', + 'Rowley', + 'Grubb', + 'Brito', + 'Royal', + 'Valentin', + 'Bartholomew', + 'Schuler', + 'Aranda', + 'Flint', + 'Hearn', + 'Venegas', + 'Unger', + 'Mattingly', + 'Boles', + 'Casas', + 'Barger', + 'Julian', + 'Dow', + 'Dobbins', + 'Vann', + 'Chester', + 'Strange', + 'Lemon', + 'Kahn', + 'Mckinnon', + 'Gannon', + 'Waggoner', + 'Conn', + 'Meek', + 'Cavazos', + 'Skelton', + 'Lo', + 'Kumar', + 'Toledo', + 'Lorenz', + 'Vallejo', + 'Starkey', + 'Kitchen', + 'Reaves', + 'Demarco', + 'Farrar', + 'Stearns', + 'Michaud', + 'Higginbotham', + 'Fernandes', + 'Isaacs', + 'Marion', + 'Guillory', + 'Priest', + 'Meehan', + 'Oliveira', + 'Palma', + 'Oswald', + 'Loomis', + 'Galvez', + 'Lind', + 'Mena', + 'Stclair', + 'Hinds', + 'Reardon', + 'Alley', + 'Barth', + 'Crook', + 'Bliss', + 'Nagel', + 'Banuelos', + 'Parish', + 'Harman', + 'Douglass', + 'Kearns', + 'Newcomb', + 'Mulligan', + 'Coughlin', + 'Way', + 'Fournier', + 'Lawler', + 'Kaminski', + 'Barbour', + 'Sousa', + 'Stump', + 'Alaniz', + 'Ireland', + 'Rudd', + 'Carnes', + 'Lundy', + 'Godinez', + 'Pulido', + 'Dennison', + 'Burdick', + 'Baumann', + 'Dove', + 'Stoddard', + 'Liang', + 'Dent', + 'Roark', + 'Mcmahan', + 'Bowser', + 'Parnell', + 'Mayberry', + 'Wakefield', + 'Arndt', + 'Ogle', + 'Worthington', + 'Durbin', + 'Escalante', + 'Pederson', + 'Weldon', + 'Vick', + 'Knott', + 'Ryder', + 'Zarate', + 'Irving', + 'Clemens', + 'Shelley', + 'Salter', + 'Jack', + 'Cloud', + 'Dasilva', + 'Muhammad', + 'Squires', + 'Rapp', + 'Dawkins', + 'Polanco', + 'Chatman', + 'Maier', + 'Yazzie', + 'Gruber', + 'Staton', + 'Blackman', + 'Mcdonnell', + 'Dykes', + 'Laws', + 'Whitten', + 'Pfeiffer', + 'Vidal', + 'Early', + 'Kelsey', + 'Baughman', + 'Dias', + 'Starnes', + 'Crespo', + 'Lombardi', + 'Kilpatrick', + 'Deaton', + 'Satterfield', + 'Wiles', + 'Weinstein', + 'Rowan', + 'Delossantos', + 'Hamby', + 'Estep', + 'Daigle', + 'Elam', + 'Creech', + 'Heck', + 'Chavis', + 'Echols', + 'Foss', + 'Trahan', + 'Strauss', + 'Vanhorn', + 'Winslow', + 'Rea', + 'Heaton', + 'Fairchild', + 'Minton', + 'Hitchcock', + 'Linton', + 'Handy', + 'Crouse', + 'Coles', + 'Upton', + 'Foy', + 'Herrington', + 'Mcclelland', + 'Hwang', + 'Rector', + 'Luther', + 'Kruger', + 'Salcedo', + 'Chance', + 'Gunderson', + 'Tharp', + 'Griffiths', + 'Graf', + 'Branham', + 'Humphreys', + 'Renner', + 'Lima', + 'Rooney', + 'Moya', + 'Almeida', + 'Gavin', + 'Coburn', + 'Ouellette', + 'Goetz', + 'Seay', + 'Parrott', + 'Harms', + 'Robb', + 'Storey', + 'Barbosa', + 'Barraza', + 'Loyd', + 'Merchant', + 'Donohue', + 'Carrier', + 'Diggs', + 'Chastain', + 'Sherrill', + 'Whipple', + 'Braswell', + 'Weathers', + 'Linder', + 'Chapa', + 'Bock', + 'Oh', + 'Lovelace', + 'Saavedra', + 'Ferrara', + 'Callaway', + 'Salmon', + 'Templeton', + 'Christy', + 'Harp', + 'Dowd', + 'Forrester', + 'Lawton', + 'Epstein', + 'Gant', + 'Tierney', + 'Seaman', + 'Corral', + 'Dowdy', + 'Zaragoza', + 'Morrissey', + 'Eller', + 'Chau', + 'Breen', + 'High', + 'Newberry', + 'Beam', + 'Yancey', + 'Jarrell', + 'Cerda', + 'Ellsworth', + 'Lofton', + 'Thibodeaux', + 'Pool', + 'Rinehart', + 'Arteaga', + 'Marlow', + 'Hacker', + 'Will', + 'Mackenzie', + 'Hook', + 'Gilliland', + 'Emmons', + 'Pickering', + 'Medley', + 'Willey', + 'Andrew', + 'Shell', + 'Randle', + 'Brinkley', + 'Pruett', + 'Tobias', + 'Edmondson', + 'Grier', + 'Saldivar', + 'Batista', + 'Askew', + 'Moeller', + 'Chavarria', + 'Augustine', + 'Troyer', + 'Layne', + 'Mcnulty', + 'Shank', + 'Desai', + 'Herrmann', + 'Hemphill', + 'Bearden', + 'Spear', + 'Keener', + 'Holguin', + 'Culp', + 'Braden', + 'Briscoe', + 'Bales', + 'Garvin', + 'Stockton', + 'Abreu', + 'Suggs', + 'Mccartney', + 'Ferrer', + 'Rhoads', + 'Ha', + 'Nevarez', + 'Singletary', + 'Chong', + 'Alcala', + 'Cheney', + 'Westfall', + 'Damico', + 'Snodgrass', + 'Devries', + 'Looney', + 'Hein', + 'Lyle', + 'Lockett', + 'Jacques', + 'Barkley', + 'Wahl', + 'Aponte', + 'Myrick', + 'Bolin', + 'Holm', + 'Slack', + 'Scherer', + 'Martino', + 'Bachman', + 'Ely', + 'Nesbitt', + 'Marroquin', + 'Bouchard', + 'Mast', + 'Jameson', + 'Hills', + 'Mireles', + 'Bueno', + 'Pease', + 'Vitale', + 'Alarcon', + 'Linares', + 'Schell', + 'Lipscomb', + 'Arriaga', + 'Bourgeois', + 'Markham', + 'Bonds', + 'Wisniewski', + 'Ivy', + 'Oldham', + 'Wendt', + 'Fallon', + 'Joy', + 'Stamper', + 'Babb', + 'Steinberg', + 'Asher', + 'Fuchs', + 'Blank', + 'Willett', + 'Heredia', + 'Croft', + 'Lytle', + 'Lance', + 'Lassiter', + 'Barrientos', + 'Condon', + 'Barfield', + 'Darden', + 'Araujo', + 'Noonan', + 'Guinn', + 'Burleson', + 'Belanger', + 'Main', + 'Traylor', + 'Messina', + 'Zeigler', + 'Danielson', + 'Millard', + 'Kenyon', + 'Radford', + 'Graff', + 'Beaty', + 'Baggett', + 'Salisbury', + 'Crisp', + 'Trout', + 'Lorenzo', + 'Parson', + 'Gann', + 'Garber', + 'Adcock', + 'Covarrubias', + 'Scales', + 'Acuna', + 'Thrasher', + 'Card', + 'Van', + 'Mabry', + 'Mohamed', + 'Montanez', + 'Stock', + 'Redd', + 'Willingham', + 'Redman', + 'Zambrano', + 'Gaffney', + 'Herr', + 'Schubert', + 'Devlin', + 'Pringle', + 'Houck', + 'Casper', + 'Rees', + 'Wing', + 'Ebert', + 'Jeter', + 'Cornejo', + 'Gillette', + 'Shockley', + 'Amato', + 'Girard', + 'Leggett', + 'Cheatham', + 'Bustos', + 'Epperson', + 'Dubose', + 'Seitz', + 'Frias', + 'East', + 'Schofield', + 'Steen', + 'Orlando', + 'Myles', + 'Caron', + 'Grey', + 'Denney', + 'Ontiveros', + 'Burden', + 'Jaeger', + 'Reich', + 'Witherspoon', + 'Najera', + 'Frantz', + 'Hammonds', + 'Xu', + 'Leavitt', + 'Gilchrist', + 'Adam', + 'Barone', + 'Forman', + 'Ceja', + 'Ragsdale', + 'Sisk', + 'Tubbs', + 'Elizondo', + 'Pressley', + 'Bollinger', + 'Linn', + 'Huntley', + 'Dewey', + 'Geary', + 'Carlos', + 'Ragland', + 'Mixon', + 'Mcarthur', + 'Baugh', + 'Tam', + 'Nobles', + 'Clevenger', + 'Lusk', + 'Foust', + 'Cooney', + 'Tamayo', + 'Robert', + 'Longo', + 'Overstreet', + 'Oglesby', + 'Mace', + 'Churchill', + 'Matson', + 'Hamrick', + 'Rockwell', + 'Trammell', + 'Wheatley', + 'Carrington', + 'Ferraro', + 'Ralston', + 'Clancy', + 'Mondragon', + 'Carl', + 'Hu', + 'Hopson', + 'Breaux', + 'Mccurdy', + 'Mares', + 'Mai', + 'Chisholm', + 'Matlock', + 'Aiken', + 'Cary', + 'Lemons', + 'Anguiano', + 'Herrick', + 'Crawley', + 'Montero', + 'Hassan', + 'Archuleta', + 'Farias', + 'Cotter', + 'Parris', + 'Felder', + 'Luu', + 'Pence', + 'Gilman', + 'Killian', + 'Naranjo', + 'Duggan', + 'Scarborough', + 'Swann', + 'Easter', + 'Ricketts', + 'France', + 'Bello', + 'Nadeau', + 'Still', + 'Rincon', + 'Cornwell', + 'Slade', + 'Fierro', + 'Mize', + 'Christianson', + 'Greenfield', + 'Mcafee', + 'Landrum', + 'Adame', + 'Dinh', + 'Lankford', + 'Lewandowski', + 'Rust', + 'Bundy', + 'Waterman', + 'Milner', + 'Mccrary', + 'Hite', + 'Curley', + 'Donald', + 'Duckworth', + 'Cecil', + 'Carrera', + 'Speer', + 'Birch', + 'Denson', + 'Beckwith', + 'Stack', + 'Durant', + 'Lantz', + 'Dorman', + 'Christman', + 'Spann', + 'Masterson', + 'Hostetler', + 'Kolb', + 'Brink', + 'Scanlon', + 'Nye', + 'Wylie', + 'Beverly', + 'Woo', + 'Spurlock', + 'Sommer', + 'Shelby', + 'Reinhardt', + 'Robledo', + 'Bertrand', + 'Ashton', + 'Cyr', + 'Edgar', + 'Doe', + 'Harkins', + 'Brubaker', + 'Stoll', + 'Dangelo', + 'Zhou', + 'Moulton', + 'Hannon', + 'Falk', + 'Rains', + 'Broughton', + 'Applegate', + 'Hudgins', + 'Slone', + 'Yoon', + 'Farnsworth', + 'Perales', + 'Reedy', + 'Milam', + 'Franz', + 'Ponder', + 'Ricci', + 'Fontaine', + 'Irizarry', + 'Puente', + 'New', + 'Selby', + 'Cazares', + 'Doughty', + 'Moffett', + 'Balderas', + 'Fine', + 'Smalley', + 'Carlin', + 'Trinh', + 'Dyson', + 'Galvin', + 'Valdivia', + 'Benner', + 'Low', + 'Turpin', + 'Lyman', + 'Billingsley', + 'Mcadams', + 'Cardwell', + 'Fraley', + 'Patten', + 'Holton', + 'Shanks', + 'Mcalister', + 'Canfield', + 'Sample', + 'Harley', + 'Cason', + 'Tomlin', + 'Ahmad', + 'Coyne', + 'Forte', + 'Riggins', + 'Littlejohn', + 'Forsythe', + 'Brinson', + 'Halverson', + 'Bach', + 'Stuckey', + 'Falcon', + 'Wenzel', + 'Talbert', + 'Champagne', + 'Mchenry', + 'Vest', + 'Shackelford', + 'Ordonez', + 'Collazo', + 'Boland', + 'Sisson', + 'Bigelow', + 'Wharton', + 'Hyman', + 'Brumfield', + 'Oates', + 'Mesa', + 'Morrell', + 'Beckett', + 'Reis', + 'Alves', + 'Chiu', + 'Larue', + 'Streeter', + 'Grogan', + 'Blakely', + 'Brothers', + 'Hatton', + 'Kimbrough', + 'Lauer', + 'Wallis', + 'Jett', + 'Pepper', + 'Hildebrand', + 'Rawls', + 'Mello', + 'Neville', + 'Bull', + 'Steffen', + 'Braxton', + 'Cowart', + 'Simpkins', + 'Mcneely', + 'Blalock', + 'Spain', + 'Shipp', + 'Lindquist', + 'Oreilly', + 'Butterfield', + 'Perrin', + 'Qualls', + 'Edge', + 'Havens', + 'Luong', + 'Switzer', + 'Troutman', + 'Fortner', + 'Tolliver', + 'Monk', + 'Poindexter', + 'Rupp', + 'Ferry', + 'Negrete', + 'Muse', + 'Gresham', + 'Beauchamp', + 'Schmid', + 'Barclay', + 'Chun', + 'Brice', + 'Faulk', + 'Watters', + 'Briones', + 'Guajardo', + 'Harwood', + 'Grissom', + 'Harlow', + 'Whelan', + 'Burdette', + 'Palumbo', + 'Paulsen', + 'Corrigan', + 'Garvey', + 'Levesque', + 'Dockery', + 'Delgadillo', + 'Gooch', + 'Cao', + 'Mullin', + 'Ridley', + 'Stanfield', + 'Noriega', + 'Dial', + 'Ceballos', + 'Nunes', + 'Newby', + 'Baumgartner', + 'Hussain', + 'Wyman', + 'Causey', + 'Gossett', + 'Ness', + 'Waugh', + 'Choate', + 'Carman', + 'Daily', + 'Kong', + 'Devore', + 'Irby', + 'Breeden', + 'Whatley', + 'Ellington', + 'Lamar', + 'Fultz', + 'Bair', + 'Zielinski', + 'Colby', + 'Houghton', + 'Grigsby', + 'Fortune', + 'Paxton', + 'Mcmillian', + 'Hammons', + 'Bronson', + 'Keck', + 'Wellman', + 'Ayres', + 'Whiteside', + 'Menard', + 'Roush', + 'Warden', + 'Espino', + 'Strand', + 'Haggerty', + 'Banda', + 'Krebs', + 'Fabian', + 'Bowie', + 'Branson', + 'Lenz', + 'Benavidez', + 'Keeler', + 'Newsom', + 'Ezell', + 'Jeffrey', + 'Pulliam', + 'Clary', + 'Byrnes', + 'Kopp', + 'Beers', + 'Smalls', + 'Sommers', + 'Gardiner', + 'Fennell', + 'Mancini', + 'Osullivan', + 'Sebastian', + 'Bruns', + 'Giron', + 'Parent', + 'Boyles', + 'Keefe', + 'Muir', + 'Wheat', + 'Vergara', + 'Shuler', + 'Pemberton', + 'South', + 'Brownlee', + 'Brockman', + 'Royer', + 'Fanning', + 'Herzog', + 'Morley', + 'Bethea', + 'Tong', + 'Needham', + 'Roque', + 'Mojica', + 'Bunn', + 'Francois', + 'Noe', + 'Kuntz', + 'Snowden', + 'Withers', + 'Harlan', + 'Seibert', + 'Limon', + 'Kiefer', + 'Bone', + 'Sell', + 'Allan', + 'Skidmore', + 'Wren', + 'Dunaway', + 'Finnegan', + 'Moe', + 'Wolford', + 'Seeley', + 'Kroll', + 'Lively', + 'Janssen', + 'Montague', + 'Rahman', + 'Boehm', + 'Nettles', + 'Dees', + 'Krieger', + 'Peek', + 'Hershberger', + 'Sage', + 'Custer', + 'Zheng', + 'Otoole', + 'Jaimes', + 'Elrod', + 'Somers', + 'Lira', + 'Nagle', + 'Grooms', + 'Soria', + 'Drury', + 'Keane', + 'Bostic', + 'Hartmann', + 'Pauley', + 'Murrell', + 'Manzo', + 'Morey', + 'Agee', + 'Hamel', + 'Tavares', + 'Dunning', + 'Mccloskey', + 'Plunkett', + 'Maples', + 'March', + 'Armenta', + 'Waldrop', + 'Espinal', + 'Fajardo', + 'Christenson', + 'Robins', + 'Bagwell', + 'Massie', + 'Leahy', + 'Urbina', + 'Medlin', + 'Zhu', + 'Pantoja', + 'Barbee', + 'Clawson', + 'Reiter', + 'Ko', + 'Crider', + 'Maxey', + 'Worrell', + 'Brackett', + 'Mclemore', + 'Younger', + 'Her', + 'Hardesty', + 'Danner', + 'Ragan', + 'Almanza', + 'Nielson', + 'Graber', + 'Mcintire', + 'Tirado', + 'Griswold', + 'Seifert', + 'Valles', + 'Laney', + 'Gupta', + 'Malik', + 'Libby', + 'Marvin', + 'Koontz', + 'Marr', + 'Kozlowski', + 'Lemke', + 'Brant', + 'Phelan', + 'Kemper', + 'Gooden', + 'Beaulieu', + 'Cardoza', + 'Healey', + 'Zhao', + 'Hardwick', + 'Kitchens', + 'Box', + 'Stepp', + 'Comstock', + 'Poston', + 'Sager', + 'Conti', + 'Borges', + 'Farrow', + 'Acker', + 'Glaser', + 'Antonio', + 'Lennon', + 'Gaither', + 'Freitas', + 'Alicea', + 'Mcmillen', + 'Chapin', + 'Ratcliff', + 'Lerma', + 'Severson', + 'Wilde', + 'Mortensen', + 'Winchester', + 'Flannery', + 'Villasenor', + 'Centeno', + 'Burkholder', + 'Horan', + 'Meador', + 'Ingle', + 'Roldan', + 'Estrella', + 'Pullen', + 'Newkirk', + 'Gaytan', + 'Lindberg', + 'Windham', + 'Gatlin', + 'Stoltzfus', + 'Behrens', + 'Cintron', + 'Broderick', + 'Solorzano', + 'Jaime', + 'Venable', + 'Culbertson', + 'Garay', + 'Caputo', + 'Grantham', + 'Hanlon', + 'Parry', + 'Crist', + 'Cosby', + 'Shore', + 'Everhart', + 'Dorn', + 'Turley', + 'Eng', + 'Valerio', + 'Rand', + 'Hiatt', + 'Mota', + 'Judge', + 'Kinder', + 'Colwell', + 'Ashworth', + 'Tejeda', + 'Sikes', + 'Oshea', + 'Westmoreland', + 'Faber', + 'Culpepper', + 'Logsdon', + 'Fugate', + 'Apodaca', + 'Lindley', + 'Samson', + 'Liles', + 'Mcclanahan', + 'Burge', + 'Vail', + 'Etheridge', + 'Boudreau', + 'Andres', + 'Noll', + 'Higgs', + 'Snead', + 'Layman', + 'Turk', + 'Nolen', + 'Wayne', + 'Betz', + 'Victor', + 'Lafferty', + 'Carbone', + 'Skipper', + 'Zeller', + 'Kasper', + 'Desantis', + 'Fogle', + 'Gandy', + 'Mendenhall', + 'Seward', + 'Schweitzer', + 'Gulley', + 'Stine', + 'Sowers', + 'Duenas', + 'Monson', + 'Brinkman', + 'Hubert', + 'Motley', + 'Pfeifer', + 'Weinberg', + 'Eggleston', + 'Isom', + 'Quinlan', + 'Gilley', + 'Jasso', + 'Loya', + 'Mull', + 'Reichert', + 'Wirth', + 'Reddy', + 'Hodgson', + 'Stowe', + 'Mccallum', + 'Ahrens', + 'Huey', + 'Mattox', + 'Dupont', + 'Aguayo', + 'Pak', + 'Tice', + 'Alba', + 'Colburn', + 'Currier', + 'Gaskins', + 'Harder', + 'Cohn', + 'Yoo', + 'Garnett', + 'Harter', + 'Wenger', + 'Charlton', + 'Littleton', + 'Minter', + 'Henriquez', + 'Cone', + 'Vines', + 'Kimmel', + 'Crooks', + 'Caraballo', + 'Searcy', + 'Peyton', + 'Renfro', + 'Groff', + 'Thorn', + 'Moua', + 'Jay', + 'Leigh', + 'Sanborn', + 'Wicker', + 'Martens', + 'Broome', + 'Abney', + 'Fisk', + 'Argueta', + 'Upchurch', + 'Alderman', + 'Tisdale', + 'Castellano', + 'Legg', + 'Wilbur', + 'Bills', + 'Dix', + 'Mauldin', + 'Isbell', + 'Mears', + 'Latimer', + 'Ashcraft', + 'Earley', + 'Tejada', + 'Partridge', + 'Anglin', + 'Caswell', + 'Easton', + 'Kirchner', + 'Mehta', + 'Lanham', + 'Blaylock', + 'Binder', + 'Catalano', + 'Handley', + 'Storm', + 'Albertson', + 'Free', + 'Tuck', + 'Keegan', + 'Moriarty', + 'Dexter', + 'Mancuso', + 'Allard', + 'Pino', + 'Chamberlin', + 'Moffitt', + 'Haag', + 'Schott', + 'Agnew', + 'Malcolm', + 'Hallman', + 'Heckman', + 'Karr', + 'Soares', + 'Alfonso', + 'Tom', + 'Wadsworth', + 'Schindler', + 'Garibay', + 'Kuykendall', + 'Penny', + 'Littlefield', + 'Mcnabb', + 'Sam', + 'Lea', + 'Berrios', + 'Murry', + 'Regalado', + 'Dehart', + 'Mohammed', + 'Counts', + 'Solorio', + 'Preciado', + 'Armendariz', + 'Martell', + 'Barksdale', + 'Frick', + 'Haller', + 'Broyles', + 'Doll', + 'Cable', + 'Delvalle', + 'Weems', + 'Kelleher', + 'Gagne', + 'Albers', + 'Kunz', + 'Hoy', + 'Hawes', + 'Guenther', + 'Johansen', + 'Chaffin', + 'Whitworth', + 'Wynne', + 'Mcmurray', + 'Luce', + 'Fiore', + 'Straub', + 'Majors', + 'Mcduffie', + 'Bohannon', + 'Rawlings', + 'Freed', + 'Sutter', + 'Lindstrom', + 'Buss', + 'Loera', + 'Hoyle', + 'Witte', + 'Tyree', + 'Luttrell', + 'Andrus', + 'Steed', + 'Thiel', + 'Cranford', + 'Fulmer', + 'Gable', + 'Porras', + 'Weis', + 'Maas', + 'Packard', + 'Noyes', + 'Kwon', + 'Knoll', + 'Marx', + 'Feeney', + 'Israel', + 'Bohn', + 'Cockrell', + 'Glick', + 'Cosgrove', + 'Keefer', + 'Mundy', + 'Batchelor', + 'Loveless', + 'Horowitz', + 'Haskell', + 'Kunkel', + 'Colson', + 'Hedges', + 'Staggs', + 'Swisher', + 'Lomeli', + 'Padron', + 'Cota', + 'Homan', + 'Musser', + 'Curtin', + 'Salerno', + 'Segovia', + 'Keeton', + 'Brandenburg', + 'Starling', + 'Tsai', + 'Mahon', + 'Klinger', + 'Paquette', + 'Haddad', + 'Mccune', + 'Mathew', + 'Shull', + 'Higdon', + 'Guest', + 'Shay', + 'Swafford', + 'Angulo', + 'Hackney', + 'Evers', + 'Sibley', + 'Woodworth', + 'Ostrander', + 'Mangum', + 'Smyth', + 'Quarles', + 'Mccarter', + 'Close', + 'Truitt', + 'Stpierre', + 'Mackay', + 'Bayer', + 'Timm', + 'Thatcher', + 'Bess', + 'Trinidad', + 'Jacoby', + 'Proffitt', + 'Concepcion', + 'Parkinson', + 'Carreon', + 'Ramon', + 'Monroy', + 'Leger', + 'Jauregui', + 'Glynn', + 'Taggart', + 'Neil', + 'Reddick', + 'Wiese', + 'Dover', + 'Wicks', + 'Hennessy', + 'Bittner', + 'Mcclung', + 'Mcwhorter', + 'Derrick', + 'Strom', + 'Beckham', + 'Kee', + 'Coombs', + 'Schrock', + 'Holtz', + 'Maki', + 'Willson', + 'Hulsey', + 'Whitson', + 'Haugen', + 'Lumpkin', + 'Scholl', + 'Gall', + 'Carvalho', + 'Kovach', + 'Vieira', + 'Millan', + 'Irvine', + 'Held', + 'Jolley', + 'Jasper', + 'Cadena', + 'Runyon', + 'Lomax', + 'Fahey', + 'Hoppe', + 'Bivens', + 'Ruggiero', + 'Hussey', + 'Ainsworth', + 'Hardman', + 'Ulloa', + 'Dugger', + 'Fitzsimmons', + 'Scroggins', + 'Sowell', + 'Toler', + 'Barba', + 'Biddle', + 'Rafferty', + 'Trapp', + 'Byler', + 'Brill', + 'Delagarza', + 'Thigpen', + 'Hiller', + 'Martins', + 'Jankowski', + 'Findley', + 'Hollins', + 'Stull', + 'Pollack', + 'Poirier', + 'Reno', + 'Bratton', + 'Jeffery', + 'Menendez', + 'Mcnutt', + 'Kohl', + 'Forster', + 'Clough', + 'Deloach', + 'Bader', + 'Hanes', + 'Sturm', + 'Tafoya', + 'Beall', + 'Coble', + 'Demers', + 'Kohn', + 'Santamaria', + 'Vaught', + 'Correia', + 'Mcgrew', + 'Sarmiento', + 'Roby', + 'Reinhart', + 'Rosenbaum', + 'Bernier', + 'Schiller', + 'Furman', + 'Grabowski', + 'Perryman', + 'Kidwell', + 'Sabo', + 'Saxton', + 'Noland', + 'Seaton', + 'Packer', + 'Seal', + 'Ruby', + 'Smoot', + 'Lavoie', + 'Putman', + 'Fairbanks', + 'Neill', + 'Florence', + 'Beattie', + 'Tarver', + 'Stephen', + 'Bolen', + 'Mccombs', + 'Freedman', + 'Barnhill', + 'Gaddis', + 'Goad', + 'Worden', + 'Canada', + 'Vickery', + 'Calvin', + 'Mcclintock', + 'Slocum', + 'Clausen', + 'Mccutcheon', + 'Ripley', + 'Razo', + 'Southard', + 'Bourne', + 'Aiello', + 'Knudsen', + 'Angeles', + 'Keeney', + 'Stacey', + 'Neeley', + 'Holly', + 'Gallant', + 'Eads', + 'Lafleur', + 'Fredrickson', + 'Popp', + 'Bobo', + 'Pardo', + 'Artis', + 'Lawless', + 'Shen', + 'Headley', + 'Pedraza', + 'Pickard', + 'Salvador', + 'Hofmann', + 'Davey', + 'Szymanski', + 'Dallas', + 'Erb', + 'Perea', + 'Alcantar', + 'Ashford', + 'Harry', + 'Crutchfield', + 'Goebel', + 'Ridgeway', + 'Mcvey', + 'Cordell', + 'Kovacs', + 'Florez', + 'Calkins', + 'Redden', + 'Ricker', + 'Salcido', + 'Farrington', + 'Reimer', + 'Mullis', + 'Mayhew', + 'Register', + 'Kaye', + 'Blocker', + 'Buford', + 'Munguia', + 'Cady', + 'Burley', + 'Sander', + 'Robinette', + 'Stubblefield', + 'Shuman', + 'Santillan', + 'Loy', + 'Deutsch', + 'Sales', + 'Langdon', + 'Mazur', + 'Clapp', + 'Teal', + 'Buffington', + 'Elliot', + 'Halstead', + 'Sturgeon', + 'Colley', + 'Koehn', + 'Bergstrom', + 'Dunne', + 'Pond', + 'Gantt', + 'Cousins', + 'Viera', + 'Wilks', + 'Haase', + 'Sweat', + 'Simonson', + 'Breedlove', + 'Munn', + 'Pitt', + 'Faircloth', + 'Peter', + 'Wheaton', + 'Howland', + 'Merriman', + 'Fusco', + 'Burney', + 'Bedford', + 'Baltazar', + 'Persaud', + 'Gerard', + 'Bourque', + 'Chao', + 'Slagle', + 'Kirsch', + 'Volk', + 'Heim', + 'Glasgow', + 'Borders', + 'Rauch', + 'Goforth', + 'Batson', + 'Basham', + 'Mount', + 'Peace', + 'Lazo', + 'Samples', + 'Amaro', + 'Slattery', + 'Ibrahim', + 'Weatherford', + 'Taft', + 'Santoro', + 'Aparicio', + 'Jiang', + 'Ritchey', + 'Goble', + 'Spring', + 'Strain', + 'Scully', + 'Villareal', + 'Toro', + 'Duval', + 'Jonas', + 'Neuman', + 'Wozniak', + 'Varney', + 'Dell', + 'Conover', + 'Landon', + 'Sigler', + 'Galbraith', + 'Boss', + 'Cepeda', + 'Back', + 'Mateo', + 'Peebles', + 'Arsenault', + 'Cathey', + 'Calabrese', + 'Dodds', + 'Gilbertson', + 'Hoke', + 'Greenlee', + 'Sauceda', + 'Vue', + 'Lehmann', + 'Zink', + 'Lapointe', + 'Laster', + 'Moy', + 'Ammons', + 'Llamas', + 'Foltz', + 'Fleck', + 'Chew', + 'Amaral', + 'Geer', + 'Su', + 'Carden', + 'Nunley', + 'Creel', + 'Clarkson', + 'Provost', + 'Covey', + 'Paine', + 'Wofford', + 'Frame', + 'Dube', + 'Grice', + 'Tully', + 'Molnar', + 'Luciano', + 'Bartels', + 'Winstead', + 'Canady', + 'Moreau', + 'Burnside', + 'Bratcher', + 'Infante', + 'Peterman', + 'Swope', + 'Freeland', + 'Vetter', + 'Lanning', + 'Marquis', + 'Schulze', + 'Thai', + 'Coppola', + 'Rayburn', + 'Conte', + 'Martz', + 'Showalter', + 'Quinonez', + 'Bandy', + 'Rao', + 'Bunting', + 'Belt', + 'Cruse', + 'Hamblin', + 'Himes', + 'Raney', + 'Merrell', + 'See', + 'Gough', + 'Maciel', + 'Wimberly', + 'Craddock', + 'Marquardt', + 'Wentz', + 'Meeker', + 'Sandberg', + 'Mosier', + 'Wasson', + 'Hundley', + 'Joe', + 'Shumaker', + 'Fortin', + 'Embry', + 'Olivarez', + 'Akin', + 'Seidel', + 'Coons', + 'Corrales', + 'Earle', + 'Matheny', + 'Kish', + 'Outlaw', + 'Lieberman', + 'Spalding', + 'Barnette', + 'Martel', + 'Hargis', + 'Kelso', + 'Merrick', + 'Fullerton', + 'Fries', + 'Doucette', + 'Clouse', + 'Prewitt', + 'Hawks', + 'Keaton', + 'Worthy', + 'Zook', + 'Montez', + 'Poore', + 'Autry', + 'Lemay', + 'Shifflett', + 'Forsyth', + 'Briseno', + 'Piazza', + 'Welker', + 'Tennant', + 'Heinz', + 'Haggard', + 'Leighton', + 'Brittain', + 'Begley', + 'Flanders', + 'Hermann', + 'Botello', + 'Mathias', + 'Hofer', + 'Hutto', + 'Godoy', + 'Cave', + 'Pagano', + 'Asbury', + 'Bowens', + 'Withrow', + 'Olivo', + 'Harbin', + 'Andre', + 'Sandlin', + 'Wertz', + 'Desimone', + 'Greiner', + 'Heinrich', + 'Whitcomb', + 'Dayton', + 'Petrie', + 'Hair', + 'Ketchum', + 'Shanahan', + 'Bianco', + 'Heil', + 'Cochrane', + 'Wegner', + 'Dagostino', + 'Couture', + 'Ling', + 'Wingate', + 'Arenas', + 'Keel', + 'Casteel', + 'Boothe', + 'Derosa', + 'Horst', + 'Rau', + 'Palermo', + 'Mccorkle', + 'Altamirano', + 'Nall', + 'Shumate', + 'Lightfoot', + 'Creamer', + 'Romeo', + 'Coffin', + 'Hutchings', + 'Jerome', + 'Hutcheson', + 'Damron', + 'Sorrell', + 'Nickel', + 'Sells', + 'Pinkerton', + 'Dao', + 'Dion', + 'Mcfarlane', + 'Ridenour', + 'Atwell', + 'Sturgill', + 'Schoen', + 'Partin', + 'Nemeth', + 'Almonte', + 'Pan', + 'Rickard', + 'Wentworth', + 'Sammons', + 'Sayre', + 'Southerland', + 'Parisi', + 'Ahn', + 'Carrion', + 'Testa', + 'Shorter', + 'Covert', + 'Gorham', + 'Alcantara', + 'Belton', + 'Bannister', + 'Sharkey', + 'Mccreary', + 'Pannell', + 'Scarbrough', + 'Keeling', + 'Gainey', + 'Mill', + 'Camarena', + 'Herbst', + 'Roller', + 'Wild', + 'Dellinger', + 'Lovejoy', + 'Manson', + 'Dupuis', + 'Clem', + 'Resendez', + 'Burkhardt', + 'Williford', + 'Mclendon', + 'Mazza', + 'Mccaffrey', + 'Lum', + 'Settle', + 'Hefner', + 'Dupre', + 'Louie', + 'Gunther', + 'Weimer', + 'Turnbull', + 'Bradbury', + 'Maness', + 'Urena', + 'Lor', + 'Sides', + 'Wick', + 'Monaco', + 'Gillen', + 'Ives', + 'Battaglia', + 'Ulmer', + 'Schreiner', + 'Caceres', + 'Sprouse', + 'Scoggins', + 'Ahern', + 'Tracey', + 'Terrazas', + 'Bracken', + 'Gurley', + 'Soliz', + 'Alcaraz', + 'Martines', + 'Weidner', + 'Criswell', + 'Wilbanks', + 'Hennessey', + 'Mendes', + 'Peak', + 'Ruelas', + 'Caudle', + 'Fuqua', + 'Jewett', + 'Chism', + 'Volpe', + 'Nino', + 'Logue', + 'Mcculloch', + 'Furr', + 'Kersey', + 'Shinn', + 'Yan', + 'Rausch', + 'Stinnett', + 'Mowery', + 'Rivero', + 'Weed', + 'Bertram', + 'Durand', + 'Gatewood', + 'Tilton', + 'Mahaffey', + 'Niles', + 'Mccue', + 'Vargo', + 'Holcombe', + 'Ralph', + 'Castleberry', + 'Snipes', + 'Wilt', + 'Vanmeter', + 'Nutter', + 'Mendiola', + 'Burchett', + 'Enos', + 'Jobe', + 'Kirkwood', + 'Pedroza', + 'Iglesias', + 'Leong', + 'Cromer', + 'Trice', + 'Magnuson', + 'Eagle', + 'Montenegro', + 'Troy', + 'Cato', + 'Edmond', + 'Hendrick', + 'Lebron', + 'Lathrop', + 'Budd', + 'Appel', + 'Knowlton', + 'Bianchi', + 'Camarillo', + 'Ginn', + 'Pulley', + 'True', + 'Gaddy', + 'Domingo', + 'Kingsley', + 'Loftus', + 'Denham', + 'Sifuentes', + 'Siler', + 'Hardison', + 'Kwan', + 'Pendergrass', + 'Frasier', + 'Hutchens', + 'Fort', + 'Montiel', + 'Fincher', + 'Eggers', + 'Moen', + 'Griffis', + 'Hauck', + 'Lister', + 'Lundberg', + 'Tanaka', + 'Cornish', + 'Whitlow', + 'Chou', + 'Griego', + 'Robson', + 'Prosser', + 'Ballinger', + 'Fogarty', + 'Allman', + 'Atchison', + 'Conaway', + 'Riddick', + 'Rupert', + 'Krug', + 'Pinkston', + 'Coggins', + 'Narvaez', + 'Earnest', + 'Fain', + 'Rash', + 'Olmstead', + 'Sherrod', + 'Beeler', + 'Spearman', + 'Poland', + 'Rousseau', + 'Hyland', + 'Rhea', + 'Son', + 'Redmon', + 'Wilke', + 'Valenti', + 'Paulino', + 'Geyer', + 'Blackwood', + 'Leclair', + 'Olguin', + 'Maestas', + 'Buckingham', + 'Blythe', + 'Samuelson', + 'Bounds', + 'Nakamura', + 'Batts', + 'Galarza', + 'Sisco', + 'Mcvay', + 'Hynes', + 'Mertz', + 'Tremblay', + 'Orosco', + 'Prentice', + 'Wilhite', + 'Seiler', + 'Archibald', + 'Wooldridge', + 'Winfield', + 'Oden', + 'Zelaya', + 'Chestnut', + 'Guardado', + 'Mccallister', + 'Canty', + 'Grasso', + 'Collett', + 'Hylton', + 'Easterling', + 'Deangelis', + 'Treadway', + 'Ferrari', + 'Ethridge', + 'Milburn', + 'Mercier', + 'Bickford', + 'Thibodeau', + 'Bolanos', + 'Fellows', + 'Hales', + 'Greathouse', + 'Buchholz', + 'Strunk', + 'Faison', + 'Purnell', + 'Clegg', + 'Steinmetz', + 'Wojcik', + 'Alcorn', + 'Ballesteros', + 'Basile', + 'Paez', + 'Armour', + 'Devito', + 'Tello', + 'Flick', + 'Yount', + 'Estevez', + 'Hitt', + 'Houle', + 'Cha', + 'Travers', + 'Cass', + 'Loper', + 'Getz', + 'Cade', + 'Gonsalves', + 'Lear', + 'Cromwell', + 'Stephan', + 'Ocasio', + 'Deluna', + 'Tolentino', + 'Picard', + 'Eaves', + 'Toscano', + 'Ault', + 'Osburn', + 'Ruvalcaba', + 'Szabo', + 'Kozak', + 'Bear', + 'Eck', + 'Deyoung', + 'Morehead', + 'Herrin', + 'Tillery', + 'Royster', + 'Kehoe', + 'Swank', + 'Yamamoto', + 'Schoonover', + 'Clanton', + 'Stutzman', + 'Swearingen', + 'Martinson', + 'Harrelson', + 'Leo', + 'Keyser', + 'Guyton', + 'Lucio', + 'Veal', + 'Vanwinkle', + 'Angelo', + 'Zamudio', + 'Haddock', + 'Quach', + 'Thomsen', + 'Curiel', + 'Badger', + 'Teel', + 'Hibbard', + 'Dvorak', + 'Ballew', + 'Falls', + 'Bostick', + 'Monaghan', + 'Segal', + 'Denning', + 'Bahr', + 'Serrato', + 'Toomey', + 'Lacroix', + 'Antoine', + 'Resendiz', + 'Sperry', + 'Rosser', + 'Bogan', + 'Gaspar', + 'Amin', + 'Schramm', + 'Lemaster', + 'Echevarria', + 'Lilley', + 'Poling', + 'Villagomez', + 'Conde', + 'Delrio', + 'Lerner', + 'Leroy', + 'Otis', + 'Durkin', + 'Lavender', + 'Schenk', + 'Ong', + 'Guess', + 'Alanis', + 'Jacobo', + 'Ramsay', + 'Henke', + 'Sledge', + 'Whited', + 'Frazer', + 'Fortier', + 'Macleod', + 'Pascual', + 'Casanova', + 'Olds', + 'Jenson', + 'Tijerina', + 'Flora', + 'Casto', + 'Rinaldi', + 'Blunt', + 'Fontana', + 'Minnick', + 'Larios', + 'Raynor', + 'Fung', + 'Marek', + 'Valladares', + 'Clemmons', + 'Gracia', + 'Rohrer', + 'Fryer', + 'Folsom', + 'Gearhart', + 'Sumpter', + 'Kraemer', + 'Aceves', + 'Pettigrew', + 'Mclaurin', + 'Southern', + 'Barrows', + 'Landeros', + 'Janes', + 'Deguzman', + 'Mcfall', + 'Fredericks', + 'Ashe', + 'Mauro', + 'Merino', + 'Windsor', + 'Taber', + 'Armijo', + 'Bricker', + 'Pitman', + 'Morrill', + 'Sanches', + 'Deboer', + 'Conlon', + 'Reuter', + 'Stegall', + 'Clemente', + 'Romine', + 'Dykstra', + 'Ehlers', + 'Tallman', + 'Lovato', + 'Brent', + 'Pearl', + 'Pyles', + 'Cloutier', + 'Mccurry', + 'Mckeever', + 'Graziano', + 'Heflin', + 'Garman', + 'Isaacson', + 'Mcreynolds', + 'Meister', + 'Stroup', + 'Everson', + 'Halsey', + 'Mcewen', + 'Sparkman', + 'Yager', + 'Bucher', + 'Berryman', + 'Derr', + 'Jester', + 'Mickelson', + 'Sayers', + 'Whiteman', + 'Riordan', + 'Mcinnis', + 'Jose', + 'Goolsby', + 'Stidham', + 'Donley', + 'Johnsen', + 'Stallworth', + 'Franke', + 'Silvers', + 'Reitz', + 'Nathan', + 'Brogan', + 'Cardoso', + 'Linville', + 'Baptiste', + 'Gorski', + 'Rey', + 'Hazen', + 'Damon', + 'Shores', + 'Boling', + 'Jablonski', + 'Lemieux', + 'Hecht', + 'Dong', + 'Langlois', + 'Burrow', + 'Hernandes', + 'Mcdevitt', + 'Pichardo', + 'Lew', + 'Stillwell', + 'Savoy', + 'Teixeira', + 'Matheson', + 'Hildreth', + 'Warfield', + 'Hogg', + 'Tiller', + 'Unruh', + 'Rudy', + 'Bristol', + 'Matias', + 'Buxton', + 'Ambriz', + 'Chiang', + 'Pomeroy', + 'Pogue', + 'Hammock', + 'Bethel', + 'Miguel', + 'Cassell', + 'Towns', + 'Bunker', + 'Mcmichael', + 'Kress', + 'Newland', + 'Whitehurst', + 'Fazio', + 'Batten', + 'Calvillo', + 'Wallen', + 'Lung', + 'Turney', + 'Sparrow', + 'Steadman', + 'Battles', + 'Berlin', + 'Lindgren', + 'Mckeon', + 'Luckett', + 'Spradlin', + 'Sherry', + 'Timmerman', + 'Utley', + 'Beale', + 'Driggers', + 'Hintz', + 'Pellegrino', + 'Hazel', + 'Grim', + 'Desmond', + 'Spellman', + 'Boren', + 'Staten', + 'Schlegel', + 'Maya', + 'Johnstone', + 'Harwell', + 'Pinson', + 'Barreto', + 'Spooner', + 'Candelaria', + 'Hammett', + 'Sessions', + 'Mckeown', + 'Mccool', + 'Gilson', + 'Knudson', + 'Irish', + 'Spruill', + 'Kling', + 'Gerlach', + 'Carnahan', + 'Markley', + 'Laporte', + 'Flanigan', + 'Spires', + 'Cushman', + 'Plante', + 'Schlosser', + 'Sachs', + 'Jamieson', + 'Hornsby', + 'Armstead', + 'Kremer', + 'Madera', + 'Thornburg', + 'Briley', + 'Garris', + 'Jorgenson', + 'Moorman', + 'Vuong', + 'Ard', + 'Irons', + 'Fiedler', + 'Jackman', + 'Kuehn', + 'Jenks', + 'Bristow', + 'Mosby', + 'Aldana', + 'Maclean', + 'Freund', + 'Creighton', + 'Smothers', + 'Melson', + 'Lundgren', + 'Donato', + 'Usher', + 'Thornhill', + 'Lowman', + 'Mariano', + 'Button', + 'Mcbee', + 'Cupp', + 'Wickham', + 'Destefano', + 'Nutt', + 'Rambo', + 'Voigt', + 'Talbott', + 'Saxon', + 'Cedillo', + 'Mattison', + 'Speed', + 'Reiss', + 'Nan', + 'Westphal', + 'Whittle', + 'Bernhardt', + 'Boatwright', + 'Bussey', + 'Rojo', + 'Eden', + 'Crites', + 'Place', + 'He', + 'Chaves', + 'Larose', + 'Thames', + 'Hoch', + 'Knotts', + 'Simone', + 'Binkley', + 'Koester', + 'Pettis', + 'Moye', + 'Napolitano', + 'Heffner', + 'Sasser', + 'Jessup', + 'Aguiar', + 'Ogrady', + 'Pippin', + 'Worth', + 'Shively', + 'Whitmire', + 'Rutter', + 'Cedeno', + 'Welborn', + 'Mcdougal', + 'Angell', + 'Sacco', + 'Hailey', + 'Neel', + 'Paniagua', + 'Pointer', + 'Rohde', + 'Holloman', + 'Strother', + 'Guffey', + 'Fenner', + 'Huntington', + 'Shane', + 'Yuen', + 'Gosnell', + 'Martini', + 'Loving', + 'Molloy', + 'Olmos', + 'Christ', + 'Oaks', + 'Ostrowski', + 'Badillo', + 'To', + 'Laplante', + 'Martindale', + 'Richie', + 'Pleasant', + 'Palomino', + 'Rodarte', + 'Stamps', + 'Peeples', + 'Ries', + 'Brownell', + 'Walz', + 'Arana', + 'Tenney', + 'Roddy', + 'Lindner', + 'Bolt', + 'Rigsby', + 'Matteson', + 'Fielder', + 'Randazzo', + 'Deanda', + 'Drayton', + 'Ridge', + 'Tarr', + 'Shade', + 'Upshaw', + 'Woodcock', + 'Miley', + 'Hargrave', + 'Langer', + 'Yun', + 'Wilkie', + 'Choe', + 'Ching', + 'Dugas', + 'Saul', + 'Corder', + 'Bobbitt', + 'Spurgeon', + 'Gladden', + 'Woodbury', + 'Tibbs', + 'Mcgarry', + 'Mcdaniels', + 'Weigel', + 'Bickel', + 'Michels', + 'Hughey', + 'Apple', + 'Bosley', + 'Nesmith', + 'Farber', + 'Ackley', + 'Goodin', + 'Almond', + 'Garrity', + 'Bettencourt', + 'Koss', + 'Falcone', + 'Lavigne', + 'Rainwater', + 'Nation', + 'Blodgett', + 'Dabney', + 'Mabe', + 'Trowbridge', + 'Lundquist', + 'Rosenberger', + 'Dombrowski', + 'Ferro', + 'Evangelista', + 'Bowlin', + 'Mckelvey', + 'Roderick', + 'Michalski', + 'Berkowitz', + 'Sato', + 'Mayorga', + 'Corwin', + 'Mckenney', + 'Salyer', + 'Walling', + 'Abell', + 'Palacio', + 'Lash', + 'Collado', + 'Gass', + 'Luis', + 'Cooksey', + 'Moll', + 'Miramontes', + 'Luster', + 'Shrader', + 'Toliver', + 'Hard', + 'Tu', + 'Sena', + 'Mckoy', + 'Wainwright', + 'Barela', + 'Keiser', + 'Hoag', + 'Backus', + 'Huskey', + 'Brannan', + 'Brumley', + 'Palm', + 'Boynton', + 'Krauss', + 'Steel', + 'Jurado', + 'Mulder', + 'Paterson', + 'Woolsey', + 'Smithson', + 'Joslin', + 'Richman', + 'Partida', + 'Grisham', + 'Wooden', + 'Gooding', + 'Fang', + 'Mcdade', + 'Spriggs', + 'Fishman', + 'Gabel', + 'Rutkowski', + 'Pride', + 'Beals', + 'Gaskin', + 'Friday', + 'Underhill', + 'Rodas', + 'Melo', + 'Sipes', + 'Zimmermann', + 'Mosqueda', + 'Haight', + 'Beeson', + 'Judy', + 'Bankston', + 'Pieper', + 'Siebert', + 'Horning', + 'Butt', + 'Bice', + 'Sills', + 'Philips', + 'Eisenberg', + 'Schumann', + 'Conger', + 'Bare', + 'Hume', + 'Nolasco', + 'Trainor', + 'Weatherly', + 'Huebner', + 'Bosch', + 'Gayle', + 'Kuhns', + 'Byron', + 'Glaze', + 'Poulin', + 'Enright', + 'Large', + 'Comeaux', + 'Rountree', + 'Tavarez', + 'Beardsley', + 'Rubino', + 'Fee', + 'Grider', + 'Bechtel', + 'Gaona', + 'Wallin', + 'Mashburn', + 'Dalrymple', + 'Gingerich', + 'Vaccaro', + 'Hass', + 'Manzano', + 'Tyner', + 'Loza', + 'Lowell', + 'Kaufmann', + 'Bischoff', + 'Doolittle', + 'Shivers', + 'Valente', + 'Bozeman', + 'Howes', + 'Felts', + 'Feller', + 'Justus', + 'Schnell', + 'Boettcher', + 'Ivory', + 'Thorson', + 'Corn', + 'Snook', + 'Heilman', + 'Baxley', + 'Hasty', + 'Wasserman', + 'Barringer', + 'Frankel', + 'Peltier', + 'Guarino', + 'Avina', + 'Sturdivant', + 'Lien', + 'Montemayor', + 'Giddens', + 'Valverde', + 'Burchfield', + 'Pang', + 'Holbert', + 'Rooks', + 'Erdman', + 'Mcmaster', + 'Iniguez', + 'Hartwell', + 'Menchaca', + 'Bordelon', + 'Farkas', + 'Chrisman', + 'Metzler', + 'Fredrick', + 'Porterfield', + 'Slayton', + 'Quesada', + 'Hembree', + 'Peel', + 'Woodley', + 'Mather', + 'Waltz', + 'Totten', + 'Forney', + 'Woolley', + 'Trombley', + 'Yarborough', + 'Javier', + 'Durr', + 'Macklin', + 'Macon', + 'Novotny', + 'Amundson', + 'Kidder', + 'Flagg', + 'Oxendine', + 'Arguello', + 'Marler', + 'Penrod', + 'Mallett', + 'Council', + 'Kinard', + 'Bremer', + 'Towne', + 'Harless', + 'Merkel', + 'Giese', + 'Fife', + 'Byars', + 'Grande', + 'Kuo', + 'Levi', + 'Darr', + 'Sanabria', + 'Pounds', + 'Roeder', + 'Keim', + 'Brush', + 'Dreyer', + 'Taveras', + 'Furlong', + 'Dorris', + 'Prior', + 'Musgrove', + 'Weiler', + 'Munro', + 'Leake', + 'Vollmer', + 'Musick', + 'Hetrick', + 'Perdomo', + 'Kester', + 'Lock', + 'Pine', + 'Baskin', + 'Bonham', + 'Heffernan', + 'Mandel', + 'Sarver', + 'Hamer', + 'Duckett', + 'Lozada', + 'Stocker', + 'Fulcher', + 'Damato', + 'Camargo', + 'Shephard', + 'Loftis', + 'Winfrey', + 'Rueda', + 'Ledezma', + 'Gottlieb', + 'Lamont', + 'Mackie', + 'Bowe', + 'Stockwell', + 'Groth', + 'Chavira', + 'Lohr', + 'Loftin', + 'Gilmer', + 'Cushing', + 'Brody', + 'Nowlin', + 'Holiday', + 'Shirk', + 'Archie', + 'Howerton', + 'Matthew', + 'Copley', + 'Marchese', + 'Echeverria', + 'Soper', + 'Cantwell', + 'Nelms', + 'Tuggle', + 'Dumont', + 'Bard', + 'Gower', + 'Mathes', + 'Yeung', + 'Buell', + 'Bastian', + 'Burd', + 'Broadway', + 'Peng', + 'Greenwell', + 'Vanover', + 'Correll', + 'Tindall', + 'Bill', + 'Mulcahy', + 'Dionne', + 'Rathbun', + 'Baeza', + 'Booher', + 'Fried', + 'Mcginley', + 'Lavin', + 'Atherton', + 'Donnell', + 'Bays', + 'Riedel', + 'Grenier', + 'Zachary', + 'Harold', + 'Styles', + 'Wisdom', + 'Raley', + 'Tamez', + 'Arena', + 'Morelli', + 'Hazelwood', + 'Somerville', + 'Lapp', + 'Rood', + 'Salem', + 'Pape', + 'Olivera', + 'Albritton', + 'Carvajal', + 'Zayas', + 'Myer', + 'Pohl', + 'Haynie', + 'Mariscal', + 'Wampler', + 'Rife', + 'Leeper', + 'Newhouse', + 'Rodney', + 'Vandenberg', + 'Spitzer', + 'Kingston', + 'Wessel', + 'Hartzell', + 'Durden', + 'Marques', + 'Born', + 'Scribner', + 'Rocco', + 'Germain', + 'Tinoco', + 'Valdovinos', + 'Musselman', + 'Vicente', + 'Parsley', + 'Crittenden', + 'Tibbetts', + 'Hulse', + 'Mccleary', + 'Barboza', + 'Velarde', + 'Brodie', + 'Beaudoin', + 'Moreira', + 'Maggard', + 'Jara', + 'Ferrante', + 'Overby', + 'Friesen', + 'Viola', + 'Nelsen', + 'Hash', + 'Doane', + 'Deese', + 'Messick', + 'Bay', + 'Anton', + 'Ingersoll', + 'Saucier', + 'Kwiatkowski', + 'Rawson', + 'Brophy', + 'Ladner', + 'Lehr', + 'Weil', + 'Yocum', + 'Brasher', + 'Denison', + 'Hutcherson', + 'Stowers', + 'Geller', + 'Fortenberry', + 'Stebbins', + 'Conyers', + 'Toole', + 'Stoker', + 'Roden', + 'Chitwood', + 'Beeman', + 'Fannin', + 'Strait', + 'Marlowe', + 'Greenwald', + 'Hann', + 'Stumpf', + 'Samaniego', + 'Colton', + 'Bogart', + 'Morel', + 'Montelongo', + 'Boylan', + 'Guido', + 'Wyrick', + 'Horsley', + 'Tenorio', + 'Sallee', + 'Morehouse', + 'Whyte', + 'Neilson', + 'Watanabe', + 'Magallanes', + 'Mudd', + 'Kieffer', + 'Brigham', + 'Dollar', + 'Huss', + 'Albanese', + 'Spiegel', + 'Hixson', + 'Rounds', + 'Orth', + 'Blanchette', + 'Vanderpool', + 'Pfaff', + 'Speck', + 'Shreve', + 'Sevilla', + 'Neri', + 'Rohr', + 'Ruble', + 'Vanpelt', + 'Rickman', + 'Caraway', + 'Berndt', + 'Mchale', + 'Ingalls', + 'Roybal', + 'Money', + 'Mcdougall', + 'Melancon', + 'Wellington', + 'Ingraham', + 'Ritz', + 'Lashley', + 'Marchand', + 'Schatz', + 'Heiser', + 'Eby', + 'Wimmer', + 'Orton', + 'Atchley', + 'Mumford', + 'Bahena', + 'Gammon', + 'Buehler', + 'Fike', + 'Plank', + 'Carrigan', + 'Kempf', + 'Cundiff', + 'So', + 'Sauls', + 'Mohler', + 'Grillo', + 'Prichard', + 'Pastor', + 'Prasad', + 'Babin', + 'Bontrager', + 'Weddle', + 'Alberts', + 'Theis', + 'Lemoine', + 'Hartnett', + 'Kingsbury', + 'Baran', + 'Birmingham', + 'Gault', + 'Thorp', + 'Wyant', + 'Obryan', + 'Santacruz', + 'Camara', + 'Whitehouse', + 'Evenson', + 'Halvorson', + 'Palmieri', + 'Hannan', + 'Dew', + 'Au', + 'Nolte', + 'Click', + 'Wooley', + 'Hung', + 'Eberhardt', + 'Rawlins', + 'Sadowski', + 'Sarabia', + 'Soule', + 'Millar', + 'Engstrom', + 'Cowles', + 'Runyan', + 'Mitchel', + 'Torrence', + 'Silverstein', + 'Hewett', + 'Pilgrim', + 'Yeh', + 'Rosenfeld', + 'Mulholland', + 'Hatley', + 'Fawcett', + 'Delrosario', + 'Chinn', + 'Bayless', + 'Dee', + 'Deane', + 'Arriola', + 'Duda', + 'Koster', + 'Rath', + 'Karl', + 'Weiland', + 'Lemmon', + 'Blaine', + 'Scofield', + 'Marston', + 'Gist', + 'Pinckney', + 'Moritz', + 'Mclellan', + 'Fulkerson', + 'Gaynor', + 'Pitre', + 'Warrick', + 'Cobbs', + 'Meacham', + 'Guerin', + 'Tedesco', + 'Passmore', + 'Northcutt', + 'Ison', + 'Cowell', + 'Ream', + 'Walther', + 'Meraz', + 'Tribble', + 'Bumgarner', + 'Gabbard', + 'Dawes', + 'Moncada', + 'Chilton', + 'Deweese', + 'Rigby', + 'Marte', + 'Baylor', + 'Valentino', + 'Shine', + 'August', + 'Billups', + 'Jarman', + 'Jacks', + 'Coffee', + 'Friedrich', + 'Marley', + 'Hasan', + 'Pennell', + 'Abercrombie', + 'Bazan', + 'Strickler', + 'Bruton', + 'Lamm', + 'Pender', + 'Wingfield', + 'Hoffer', + 'Zahn', + 'Chaplin', + 'Reinke', + 'Larosa', + 'Maupin', + 'Bunnell', + 'Hassell', + 'Guo', + 'Galan', + 'Paschal', + 'Browder', + 'Krantz', + 'Milne', + 'Pelayo', + 'Emanuel', + 'Mccluskey', + 'Edens', + 'Radtke', + 'Alger', + 'Duhon', + 'Probst', + 'Witmer', + 'Hoagland', + 'Saechao', + 'Pitcher', + 'Villalpando', + 'Carswell', + 'Roundtree', + 'Kuhlman', + 'Tait', + 'Shaughnessy', + 'Wei', + 'Cravens', + 'Sipe', + 'Islas', + 'Hollenbeck', + 'Lockard', + 'Perrone', + 'Tapp', + 'Santoyo', + 'Jaffe', + 'Klotz', + 'Gilpin', + 'Ehrlich', + 'Klug', + 'Stowell', + 'Ibanez', + 'Lazar', + 'Osman', + 'Larkins', + 'Donofrio', + 'Ericson', + 'Schenck', + 'Mouton', + 'Medlock', + 'Hubbell', + 'Bixler', + 'Nowicki', + 'Muro', + 'Homer', + 'Grijalva', + 'Ashmore', + 'Harbison', + 'Duffey', + 'Osgood', + 'Hardee', + 'Jain', + 'Wilber', + 'Bolling', + 'Lett', + 'Phillip', + 'Dipietro', + 'Lefebvre', + 'Batiste', + 'Mcswain', + 'Distefano', + 'Hack', + 'Strobel', + 'Kipp', + 'Doerr', + 'Radcliffe', + 'Cartagena', + 'Paradis', + 'Stilwell', + 'Mccrea', + 'Searles', + 'Frausto', + 'Hendershot', + 'Gosselin', + 'Islam', + 'Freese', + 'Stockman', + 'Burwell', + 'Vandiver', + 'Engler', + 'Geisler', + 'Barham', + 'Wiegand', + 'Goncalves', + 'Theriot', + 'Doucet', + 'Bridge', + 'Catron', + 'Blanks', + 'Rahn', + 'Schaub', + 'Hershey', + 'Strader', + 'Buckman', + 'Hartwig', + 'Campo', + 'Tsang', + 'Luck', + 'Bernardo', + 'Marker', + 'Pinkney', + 'Benefield', + 'Mcginty', + 'Bode', + 'Linden', + 'Manriquez', + 'Jaquez', + 'Bedard', + 'Flack', + 'Hesse', + 'Costanzo', + 'Boardman', + 'Carper', + 'Word', + 'Miracle', + 'Edmunds', + 'Bott', + 'Flemming', + 'Manns', + 'Kesler', + 'Piatt', + 'Tankersley', + 'Eberle', + 'Roney', + 'Belk', + 'Vansickle', + 'Varga', + 'Hillard', + 'Neubauer', + 'Quirk', + 'Chevalier', + 'Mintz', + 'Kocher', + 'Casarez', + 'Tinker', + 'Elmer', + 'Decarlo', + 'Cordes', + 'Berube', + 'Kimbrell', + 'Schick', + 'Papa', + 'Alderson', + 'Callaghan', + 'Renaud', + 'Pardue', + 'Krohn', + 'Bloomfield', + 'Coward', + 'Ligon', + 'Trask', + 'Wingo', + 'Book', + 'Crutcher', + 'Canter', + 'Teran', + 'Denman', + 'Stackhouse', + 'Chambliss', + 'Gourley', + 'Earls', + 'Frizzell', + 'Bergen', + 'Abdullah', + 'Sprinkle', + 'Fancher', + 'Urias', + 'Lavelle', + 'Baumgardner', + 'Kahler', + 'Baldridge', + 'Alejandro', + 'Plascencia', + 'Hix', + 'Rule', + 'Mix', + 'Petro', + 'Hadden', + 'Fore', + 'Humes', + 'Barnum', + 'Laing', + 'Maggio', + 'Sylvia', + 'Malinowski', + 'Fell', + 'Durst', + 'Plant', + 'Vaca', + 'Abarca', + 'Shirey', + 'Parton', + 'Ta', + 'Ramires', + 'Ochs', + 'Gaitan', + 'Ledoux', + 'Darrow', + 'Messenger', + 'Chalmers', + 'Schaller', + 'Derby', + 'Coakley', + 'Saleh', + 'Kirkman', + 'Orta', + 'Crabb', + 'Spinks', + 'Dinkins', + 'Harrigan', + 'Koller', + 'Dorr', + 'Carty', + 'Sturgis', + 'Shriver', + 'Macedo', + 'Feng', + 'Bentz', + 'Bedell', + 'Osuna', + 'Dibble', + 'Dejong', + 'Fender', + 'Parada', + 'Vanburen', + 'Chaffee', + 'Stott', + 'Sigmon', + 'Nicolas', + 'Salyers', + 'Magdaleno', + 'Deering', + 'Puentes', + 'Funderburk', + 'Jang', + 'Christopherson', + 'Sellars', + 'Marcotte', + 'Oster', + 'Liao', + 'Tudor', + 'Specht', + 'Chowdhury', + 'Landa', + 'Monge', + 'Brake', + 'Behnke', + 'Llewellyn', + 'Labelle', + 'Mangan', + 'Godsey', + 'Truax', + 'Lombard', + 'Thurmond', + 'Emerick', + 'Blume', + 'Mcginn', + 'Beer', + 'Marrs', + 'Zinn', + 'Rieger', + 'Dilley', + 'Thibault', + 'Witkowski', + 'Chi', + 'Fielding', + 'Tyrrell', + 'Peeler', + 'Northrup', + 'Augustin', + 'Toy', + 'Geist', + 'Schuman', + 'Fairley', + 'Duque', + 'Villatoro', + 'Dudek', + 'Sonnier', + 'Fritts', + 'Worsham', + 'Herold', + 'Mcgehee', + 'Caskey', + 'Boatright', + 'Lazaro', + 'Deck', + 'Palomo', + 'Cory', + 'Olivier', + 'Baines', + 'Fan', + 'Futrell', + 'Halpin', + 'Garrido', + 'Koonce', + 'Fogg', + 'Meneses', + 'Mulkey', + 'Restrepo', + 'Ducharme', + 'Slate', + 'Toussaint', + 'Sorrells', + 'Fitts', + 'Dickman', + 'Alfred', + 'Grimsley', + 'Settles', + 'Etienne', + 'Eggert', + 'Hague', + 'Caldera', + 'Hillis', + 'Hollander', + 'Haire', + 'Theriault', + 'Madigan', + 'Kiernan', + 'Parkhurst', + 'Lippert', + 'Jaynes', + 'Moniz', + 'Bost', + 'Bettis', + 'Sandy', + 'Kuhl', + 'Wilk', + 'Borrego', + 'Koon', + 'Penney', + 'Pizarro', + 'Stitt', + 'Koski', + 'Galicia', + 'Quiles', + 'Real', + 'Massa', + 'Crone', + 'Teeter', + 'Voorhees', + 'Hilbert', + 'Nabors', + 'Shupe', + 'Blood', + 'Mcauliffe', + 'Waits', + 'Blakley', + 'Stoltz', + 'Maes', + 'Munroe', + 'Rhoden', + 'Abeyta', + 'Milliken', + 'Harkness', + 'Almaraz', + 'Remington', + 'Raya', + 'Frierson', + 'Olszewski', + 'Quillen', + 'Westcott', + 'Fu', + 'Tolley', + 'Olive', + 'Mcclary', + 'Corbitt', + 'Lui', + 'Lachance', + 'Meagher', + 'Cowley', + 'Hudak', + 'Cress', + 'Mccrory', + 'Talavera', + 'Mclaren', + 'Laurent', + 'Bias', + 'Whetstone', + 'Hollister', + 'Quevedo', + 'Byerly', + 'Berryhill', + 'Folk', + 'Conners', + 'Kellum', + 'Haro', + 'Mallard', + 'Mccants', + 'Risner', + 'Barros', + 'Downes', + 'Mayers', + 'Loeffler', + 'Mink', + 'Hotchkiss', + 'Bartz', + 'Alt', + 'Hindman', + 'Bayne', + 'Bagby', + 'Colin', + 'Treadwell', + 'Hemingway', + 'Bane', + 'Heintz', + 'Fite', + 'Mccomb', + 'Carmody', + 'Kistler', + 'Olinger', + 'Vestal', + 'Byrum', + 'Seale', + 'Turnage', + 'Raber', + 'Prendergast', + 'Koons', + 'Nickell', + 'Benz', + 'Mcculley', + 'Lightner', + 'Hamill', + 'Castellon', + 'Chesser', + 'Moats', + 'Buie', + 'Svoboda', + 'Wold', + 'Macmillan', + 'Boring', + 'Terrill', + 'Loveland', + 'Gaskill', + 'Verdugo', + 'Yip', + 'Oviedo', + 'Hight', + 'Carmack', + 'Scheer', + 'Dreher', + 'Appleby', + 'Lally', + 'Kibler', + 'Marra', + 'Mcnamee', + 'Cooks', + 'Kavanaugh', + 'Carrico', + 'Alden', + 'Dillman', + 'Zamarripa', + 'Serra', + 'Gilligan', + 'Nester', + 'Sokol', + 'Latta', + 'Hanrahan', + 'Ballou', + 'Hollinger', + 'Lux', + 'Caton', + 'Hamann', + 'Sackett', + 'Leiva', + 'Emory', + 'Barden', + 'Houk', + 'Lees', + 'Deltoro', + 'Lowrey', + 'Mcevoy', + 'Hibbs', + 'Crossley', + 'Rego', + 'Melchor', + 'Tull', + 'Bramlett', + 'Hsieh', + 'Warwick', + 'Sayles', + 'Mapes', + 'Pabon', + 'Dearing', + 'Stamm', + 'Joshi', + 'Quan', + 'Larry', + 'Nordstrom', + 'Heisler', + 'Bigham', + 'Walston', + 'Solberg', + 'Bodnar', + 'Posada', + 'Mancilla', + 'Ovalle', + 'Harr', + 'Mccaskill', + 'Bromley', + 'Koerner', + 'Macpherson', + 'Trudeau', + 'Blais', + 'Kiley', + 'Lawlor', + 'Suter', + 'Rothman', + 'Oberg', + 'Seely', + 'Maxfield', + 'Truman', + 'Salvatore', + 'Fouts', + 'Goulet', + 'Munger', + 'Sikora', + 'Comeau', + 'Oliphant', + 'Baber', + 'Hensel', + 'Edelman', + 'Farina', + 'Albano', + 'Aycock', + 'Sung', + 'Deckard', + 'Steinke', + 'Silveira', + 'Servin', + 'Rex', + 'Franzen', + 'Hecker', + 'Gragg', + 'Mcgriff', + 'Ellingson', + 'Kerrigan', + 'An', + 'Bartel', + 'Priddy', + 'Hodson', + 'Tse', + 'Arbogast', + 'Arceneaux', + 'Leatherman', + 'Federico', + 'Pridgen', + 'Yim', + 'Kowalczyk', + 'Deberry', + 'Lejeune', + 'Elston', + 'Mielke', + 'Shelly', + 'Stambaugh', + 'Eagan', + 'Rivard', + 'Silvia', + 'Lawhorn', + 'Denis', + 'Hendry', + 'Wieland', + 'Levinson', + 'Marlin', + 'Gerdes', + 'Pfister', + 'Carder', + 'Pipkin', + 'Angle', + 'Hang', + 'Hagerty', + 'Rhinehart', + 'Gao', + 'Petit', + 'Mccraw', + 'Markle', + 'Lupo', + 'Busse', + 'Marble', + 'Bivins', + 'Storms', + 'Yuan', + 'Waldman', + 'Suh', + 'Wyckoff', + 'Stillman', + 'Piotrowski', + 'Abrego', + 'Gregoire', + 'Bogle', + 'Wortham', + 'Phung', + 'Brister', + 'Karnes', + 'Deming', + 'Ley', + 'Carrasquillo', + 'Curtiss', + 'Appleton', + 'Salley', + 'Borja', + 'Begum', + 'Phifer', + 'Shoup', + 'Cawley', + 'Deason', + 'Castanon', + 'Loucks', + 'Hagler', + 'Mcclinton', + 'Dulaney', + 'Hargett', + 'Mcardle', + 'Burcham', + 'Philpot', + 'Laroche', + 'Breland', + 'Hatten', + 'Karp', + 'Brummett', + 'Boatman', + 'Natale', + 'Pepe', + 'Mortimer', + 'Sink', + 'Voyles', + 'Reeve', + 'Honaker', + 'Loredo', + 'Ridgway', + 'Donner', + 'Lessard', + 'Dever', + 'Salomon', + 'Hickson', + 'Nicholls', + 'Bushey', + 'Osteen', + 'Reavis', + 'Rodman', + 'Barahona', + 'Knecht', + 'Hinman', + 'Faria', + 'Dana', + 'Bancroft', + 'Hatchett', + 'Hageman', + 'Klaus', + 'Castor', + 'Lampkin', + 'Dalessandro', + 'Riffle', + 'Korn', + 'Savoie', + 'Sandifer', + 'Mciver', + 'Magill', + 'Delafuente', + 'Widener', + 'Vermillion', + 'Dandrea', + 'Mader', + 'Woodman', + 'Milan', + 'Hollowell', + 'Schaaf', + 'Kao', + 'Nail', + 'Beaman', + 'Hawkes', + 'Mclane', + 'Marchant', + 'Scanlan', + 'Syed', + 'Peabody', + 'Uhl', + 'Schauer', + 'Azevedo', + 'Wolcott', + 'Mick', + 'Melgar', + 'Pilcher', + 'Burgin', + 'Weiser', + 'Daughtry', + 'Theisen', + 'Babbitt', + 'Petry', + 'Cotten', + 'Fick', + 'Eubank', + 'Tolson', + 'Judkins', + 'Cronk', + 'Wendel', + 'Monteiro', + 'Kissinger', + 'Banta', + 'Senn', + 'Fix', + 'Brehm', + 'Rittenhouse', + 'Banner', + 'Elwell', + 'Herd', + 'Araiza', + 'Hui', + 'Nowell', + 'Brett', + 'Hua', + 'Breeding', + 'Pawlowski', + 'Thompkins', + 'Bocanegra', + 'Bosworth', + 'Dutcher', + 'Cotto', + 'Beecher', + 'Callender', + 'Hamlett', + 'Benfield', + 'Claudio', + 'Reel', + 'Brookshire', + 'Helmick', + 'Ryals', + 'Winder', + 'Thom', + 'Robin', + 'Overman', + 'Furtado', + 'Dacosta', + 'Paddock', + 'Dancy', + 'Carpio', + 'Manzanares', + 'Zito', + 'Favela', + 'Beckley', + 'Adrian', + 'Flory', + 'Nestor', + 'Spell', + 'Speight', + 'Strawn', + 'Beckner', + 'Gause', + 'Berglund', + 'Ruppert', + 'Mincey', + 'Spinelli', + 'Suzuki', + 'Mizell', + 'Kirksey', + 'Bolduc', + 'Kilmer', + 'Wesson', + 'Brinker', + 'Urrutia', + 'Markey', + 'Brenneman', + 'Haupt', + 'Sievers', + 'Puga', + 'Halloran', + 'Birdsong', + 'Stancil', + 'Wiener', + 'Calvo', + 'Macy', + 'Cairns', + 'Kahl', + 'Vice', + 'Ordaz', + 'Grow', + 'Lafrance', + 'Dryden', + 'Studer', + 'Matney', + 'Edward', + 'Rackley', + 'Gurrola', + 'Demoss', + 'Woolard', + 'Oquinn', + 'Hambrick', + 'Christmas', + 'Robey', + 'Crayton', + 'Haber', + 'Arango', + 'Newcomer', + 'Groom', + 'Corson', + 'Harness', + 'Rossman', + 'Slaton', + 'Schutz', + 'Conant', + 'Tedder', + 'Sabin', + 'Lowder', + 'Womble', + 'Jin', + 'Monday', + 'Garmon', + 'Aronson', + 'Skeen', + 'Headrick', + 'Lefevre', + 'Whittemore', + 'Pelton', + 'Barner', + 'Hildebrandt', + 'Rick', + 'Helmer', + 'Grose', + 'Zak', + 'Schroder', + 'Mahler', + 'Keeley', + 'Flinn', + 'Jordon', + 'Ozuna', + 'Sand', + 'Henkel', + 'Turcotte', + 'Vining', + 'Bellinger', + 'Neese', + 'Hagerman', + 'Mcmillin', + 'Gaylord', + 'Harney', + 'Milano', + 'Carothers', + 'Depew', + 'Bucci', + 'Pirtle', + 'Hafner', + 'Dimas', + 'Howlett', + 'Reber', + 'Abram', + 'Davalos', + 'Zajac', + 'Pedro', + 'Goodall', + 'Kaylor', + 'Wrenn', + 'Gartner', + 'Kell', + 'Curl', + 'Leathers', + 'Spiller', + 'Beason', + 'Shattuck', + 'Brewington', + 'Pinon', + 'Nazario', + 'Wash', + 'Ruggles', + 'Matz', + 'Capers', + 'Dorsett', + 'Wilmoth', + 'Bracey', + 'Lenhart', + 'Devoe', + 'Choy', + 'Oswalt', + 'Capone', + 'Wayman', + 'Parikh', + 'Eastwood', + 'Cofield', + 'Rickert', + 'Mccandless', + 'Greenway', + 'Majewski', + 'Rigdon', + 'Armbruster', + 'Royce', + 'Sterner', + 'Swaim', + 'Flournoy', + 'Amezcua', + 'Delano', + 'Westerman', + 'Grau', + 'Claxton', + 'Veliz', + 'Haun', + 'Roscoe', + 'Mccafferty', + 'Ringer', + 'Volz', + 'Blessing', + 'Mcphail', + 'Thelen', + 'Gagliardi', + 'Scholz', + 'Genovese', + 'Boyette', + 'Squire', + 'Naughton', + 'Levitt', + 'Erskine', + 'Leffler', + 'Manchester', + 'Hallett', + 'Whitmer', + 'Gillett', + 'Groce', + 'Roos', + 'Bejarano', + 'Moskowitz', + 'Constantine', + 'Fidler', + 'Roll', + 'Schutte', + 'Ohare', + 'Warnock', + 'Wester', + 'Macgregor', + 'Golding', + 'Abner', + 'Burgett', + 'Bushnell', + 'Brazil', + 'Ascencio', + 'Hock', + 'Legrand', + 'Eversole', + 'Rome', + 'Radcliff', + 'Fuhrman', + 'Schmit', + 'Tew', + 'Caro', + 'Cowen', + 'Marriott', + 'Kephart', + 'Hartung', + 'Keil', + 'Benally', + 'Hazlett', + 'Avant', + 'Desrosiers', + 'Kwong', + 'Guyer', + 'Penner', + 'Avelar', + 'Cashman', + 'Stith', + 'Orona', + 'Rager', + 'Johanson', + 'Lanza', + 'Min', + 'Cool', + 'Heine', + 'Nissen', + 'Buenrostro', + 'Mcmullin', + 'Oropeza', + 'Hom', + 'Degroot', + 'Wescott', + 'Hulbert', + 'Shrum', + 'Muncy', + 'Littrell', + 'Forest', + 'Dyke', + 'Garces', + 'Cimino', + 'Gebhardt', + 'Hickerson', + 'Satterwhite', + 'Radke', + 'Luckey', + 'Coronel', + 'Pugliese', + 'Frazee', + 'Siddiqui', + 'Flatt', + 'Abbey', + 'Gerald', + 'Bodine', + 'Lora', + 'Youngs', + 'Catlett', + 'Alexis', + 'Luo', + 'Youmans', + 'Sherlock', + 'Kinser', + 'Wales', + 'Dinsmore', + 'Abramson', + 'Stricker', + 'Rumsey', + 'Showers', + 'Mickens', + 'Tallent', + 'Setzer', + 'Etter', + 'Allgood', + 'Pagel', + 'Jefferies', + 'Bissell', + 'Colombo', + 'Musgrave', + 'Kuehl', + 'Raab', + 'Kavanagh', + 'Beane', + 'Witcher', + 'Pattison', + 'Paulus', + 'Gong', + 'Mcgough', + 'Burkhalter', + 'Vanbuskirk', + 'Kite', + 'Sass', + 'Lalonde', + 'Gormley', + 'Baier', + 'Brauer', + 'Stricklin', + 'Napoli', + 'Brotherton', + 'Stansbury', + 'Loggins', + 'Sorrentino', + 'Poff', + 'Nieman', + 'Roebuck', + 'Reiner', + 'Hovey', + 'Walley', + 'Leech', + 'Gambino', + 'Hammack', + 'Burson', + 'Tatro', + 'Perrine', + 'Carley', + 'Stadler', + 'Nason', + 'Peckham', + 'Gervais', + 'Ables', + 'Turman', + 'Dore', + 'Peavy', + 'Addington', + 'Tobar', + 'Gilstrap', + 'Brumbaugh', + 'Gerhardt', + 'Slusher', + 'Nevins', + 'Garofalo', + 'Amick', + 'Barrick', + 'Race', + 'Daggett', + 'Manion', + 'Noah', + 'Kranz', + 'Runge', + 'Wysocki', + 'Gillum', + 'Verduzco', + 'Alvey', + 'Pettus', + 'Sim', + 'Cage', + 'Mckean', + 'Harrod', + 'Weatherspoon', + 'Takahashi', + 'Wingard', + 'Endres', + 'Skiles', + 'Wald', + 'Finger', + 'Reams', + 'Ussery', + 'Fricke', + 'Jaworski', + 'Cusick', + 'Stanek', + 'Shaner', + 'Massaro', + 'Ribeiro', + 'Eades', + 'Rue', + 'Scharf', + 'Standridge', + 'Wojciechowski', + 'Victoria', + 'Galbreath', + 'Lander', + 'Martinelli', + 'Raper', + 'Karas', + 'Tomas', + 'La', + 'Kizer', + 'Gastelum', + 'Delp', + 'Sansone', + 'Therrien', + 'Brookins', + 'Shi', + 'Hammel', + 'Polley', + 'Riddell', + 'Claiborne', + 'Lampe', + 'Benham', + 'Braddock', + 'Elwood', + 'Mcminn', + 'Amerson', + 'Leija', + 'Gambrell', + 'Nuno', + 'Mallon', + 'Gard', + 'Burford', + 'Halley', + 'Maley', + 'Eicher', + 'Caban', + 'Rubenstein', + 'Tighe', + 'Harbaugh', + 'Bergmann', + 'Runnels', + 'Carrizales', + 'Gustin', + 'Wight', + 'Dominick', + 'Cannady', + 'Brace', + 'Beauregard', + 'Weitzel', + 'Orcutt', + 'Abrahamson', + 'Jorge', + 'Mccown', + 'Harriman', + 'Nicol', + 'Gott', + 'Andino', + 'Tsosie', + 'Shumway', + 'Aucoin', + 'Bowes', + 'Hixon', + 'Broom', + 'Cate', + 'Desantiago', + 'Haug', + 'Pinedo', + 'Mowry', + 'Moyers', + 'Deangelo', + 'Mcshane', + 'Boley', + 'Tiffany', + 'Steger', + 'Woodford', + 'Whitford', + 'Collette', + 'Muth', + 'Mansour', + 'Schuh', + 'Fortney', + 'Khoury', + 'Livengood', + 'Haworth', + 'Rusk', + 'Mathieu', + 'Peppers', + 'Gehring', + 'Faris', + 'Diep', + 'Rae', + 'Hupp', + 'Escalera', + 'Gwin', + 'Engelhardt', + 'Bannon', + 'Menjivar', + 'Eberhart', + 'Kershaw', + 'Cottle', + 'Palomares', + 'Carrell', + 'Galaviz', + 'Willie', + 'Troxell', + 'Visser', + 'Xie', + 'Juan', + 'Spector', + 'Izzo', + 'Woodring', + 'Gilbreath', + 'Bey', + 'Giraldo', + 'Neary', + 'Ready', + 'Toland', + 'Benge', + 'Thrower', + 'Bemis', + 'Hostetter', + 'Dull', + 'Poulos', + 'Vanegas', + 'Abad', + 'Harker', + 'Mei', + 'Nigro', + 'Messner', + 'Peres', + 'Hardaway', + 'Crumpton', + 'Dingman', + 'Hipp', + 'Lemley', + 'Maloy', + 'Ye', + 'Neighbors', + 'Proulx', + 'Jamerson', + 'Finkelstein', + 'Payan', + 'Holler', + 'Simonds', + 'Toms', + 'Schulman', + 'Aguero', + 'Hinrichs', + 'Steffens', + 'Clapper', + 'Delao', + 'Knighton', + 'Jahn', + 'Mach', + 'Heal', + 'Detwiler', + 'Corso', + 'Toner', + 'Rook', + 'Brockway', + 'Coulson', + 'Delia', + 'Giddings', + 'Hermosillo', + 'Ballenger', + 'Persinger', + 'Delk', + 'Pedigo', + 'Burg', + 'Voelker', + 'Ecker', + 'Kile', + 'Propst', + 'Rascon', + 'Stultz', + 'Swindle', + 'Swindell', + 'Deaver', + 'Welty', + 'Sussman', + 'Southworth', + 'Child', + 'Coston', + 'Lei', + 'Spillman', + 'Hochstetler', + 'Veach', + 'Melcher', + 'Chipman', + 'Lebeau', + 'Summerville', + 'Peden', + 'Lizarraga', + 'Kingery', + 'Leos', + 'Fogel', + 'Eckman', + 'Burbank', + 'Castano', + 'Chartier', + 'Medellin', + 'Torrey', + 'Peake', + 'Swinney', + 'Aziz', + 'Reinert', + 'Borg', + 'Pires', + 'Brooke', + 'Forester', + 'Greaves', + 'Delapaz', + 'Hunnicutt', + 'Bierman', + 'Stringfellow', + 'Lavallee', + 'Farnham', + 'Gadson', + 'Gainer', + 'Kulp', + 'Liston', + 'Brooker', + 'Loudermilk', + 'Reza', + 'Henshaw', + 'Hinz', + 'Brammer', + 'Frisch', + 'Toombs', + 'Esquibel', + 'Feinberg', + 'Plaza', + 'Bly', + 'Encarnacion', + 'Cockerham', + 'Shealy', + 'Haile', + 'Nave', + 'Chenoweth', + 'Goto', + 'Ernest', + 'Staub', + 'Marty', + 'Huizar', + 'Lammers', + 'Mcavoy', + 'Dishman', + 'Giroux', + 'Dowdell', + 'Via', + 'Fenn', + 'Kain', + 'Breckenridge', + 'Egbert', + 'Steelman', + 'Gasper', + 'Riojas', + 'Parmer', + 'Creed', + 'Gillispie', + 'Edgerton', + 'Yen', + 'Calder', + 'Holmberg', + 'Kreider', + 'Landau', + 'Eley', + 'Lewallen', + 'Quimby', + 'Holladay', + 'Du', + 'Leland', + 'Hyder', + 'Omeara', + 'Acton', + 'Gaspard', + 'Kennard', + 'Renfroe', + 'Hayman', + 'Gladney', + 'Glidden', + 'Wilmot', + 'Pearsall', + 'Cahoon', + 'Hallock', + 'Grigg', + 'Boggess', + 'Lewin', + 'Doering', + 'Thach', + 'Mcatee', + 'Paulk', + 'Rusch', + 'Harrold', + 'Suttles', + 'Chiles', + 'Sawyers', + 'Roger', + 'Kwok', + 'Luevano', + 'Coelho', + 'Waldo', + 'Ewell', + 'Lagunas', + 'Rude', + 'Barrington', + 'Mccomas', + 'Whiteley', + 'Jeanbaptiste', + 'Darcy', + 'Lussier', + 'Kerley', + 'Fordham', + 'Moorehead', + 'Welton', + 'Nicely', + 'Constantino', + 'Townes', + 'Giglio', + 'Damian', + 'Mckibben', + 'Resnick', + 'Endicott', + 'Lindeman', + 'Killion', + 'Gwinn', + 'Beaumont', + 'Nord', + 'Miceli', + 'Fast', + 'Bidwell', + 'Sites', + 'Drum', + 'Maze', + 'Abshire', + 'Berner', + 'Rhyne', + 'Juliano', + 'Wortman', + 'Beggs', + 'Winchell', + 'Summerlin', + 'Thrash', + 'Biggers', + 'Buckles', + 'Barnwell', + 'Thomasson', + 'Wan', + 'Arneson', + 'Rodrigue', + 'Wroblewski', + 'Quiroga', + 'Fulk', + 'Dillingham', + 'Rone', + 'Mapp', + 'Sattler', + 'Letourneau', + 'Gaudet', + 'Mccaslin', + 'Gurule', + 'Huck', + 'Hudspeth', + 'Welter', + 'Wittman', + 'Hileman', + 'Ewald', + 'Yao', + 'Kindred', + 'Kato', + 'Nickels', + 'Tyndall', + 'Sanmiguel', + 'Mayle', + 'Alfano', + 'Eichelberger', + 'Bee', + 'Sheehy', + 'Rogan', + 'Philip', + 'Dilworth', + 'Midkiff', + 'Hudgens', + 'Killingsworth', + 'Russel', + 'Criss', + 'Liddell', + 'Eberly', + 'Khalil', + 'Lattimore', + 'Koval', + 'Maxson', + 'Schram', + 'Goodell', + 'Catlin', + 'Cofer', + 'Alva', + 'Sandler', + 'Kunkle', + 'Perron', + 'Bushman', + 'Edmonson', + 'Roa', + 'Nesbit', + 'Ahearn', + 'Garver', + 'Bible', + 'Barley', + 'Struble', + 'Oxford', + 'Wulf', + 'Marron', + 'Haught', + 'Bonnell', + 'Pigg', + 'Friel', + 'Almaguer', + 'Bowler', + 'Mitchem', + 'Fussell', + 'Lemos', + 'Savino', + 'Boisvert', + 'Torgerson', + 'Annis', + 'Dicks', + 'Ruhl', + 'Pepin', + 'Wildman', + 'Gendron', + 'Melanson', + 'Sherer', + 'Duty', + 'Cassel', + 'Croteau', + 'Rolon', + 'Staats', + 'Pass', + 'Larocca', + 'Sauter', + 'Sacks', + 'Boutwell', + 'Hunsaker', + 'Omara', + 'Mcbroom', + 'Lohman', + 'Treat', + 'Dufour', + 'Brashear', + 'Yepez', + 'Lao', + 'Telles', + 'Manis', + 'Mars', + 'Shilling', + 'Tingle', + 'Macaluso', + 'Rigney', + 'Clair', + 'Matsumoto', + 'Agosto', + 'Halbert', + 'Dabbs', + 'Eckstein', + 'Mercurio', + 'Berkley', + 'Wachter', + 'Langan', + 'Peach', + 'Carreno', + 'Lepore', + 'Howie', + 'Thaxton', + 'Arrowood', + 'Weinberger', + 'Eldred', + 'Hooten', + 'Raymer', + 'Feaster', + 'Bosco', + 'Cataldo', + 'Fears', + 'Eckhardt', + 'Mullinax', + 'Spratt', + 'Laboy', + 'Marsden', + 'Carlile', + 'Bustillos', + 'Crim', + 'Surratt', + 'Kurth', + 'Gaul', + 'Machuca', + 'Rolfe', + 'Lower', + 'Edmiston', + 'Millsap', + 'Dehaven', + 'Racine', + 'Coney', + 'Rinker', + 'Maddux', + 'Burmeister', + 'Fenwick', + 'Stocks', + 'Forde', + 'Pettway', + 'Balderrama', + 'Westover', + 'Bloch', + 'Burress', + 'Hunley', + 'Futch', + 'Chee', + 'Alvarenga', + 'Bostwick', + 'Cleaver', + 'Pelkey', + 'Bryce', + 'Pisano', + 'Qureshi', + 'Varghese', + 'Cunha', + 'Hellman', + 'Grass', + 'Luker', + 'Hazelton', + 'Cathcart', + 'Yamada', + 'Gallego', + 'Menke', + 'Yingling', + 'Merriweather', + 'Fleury', + 'Salmeron', + 'Metcalfe', + 'Brook', + 'Freitag', + 'Malek', + 'Obregon', + 'Blain', + 'Mellott', + 'Alam', + 'Bessette', + 'Moncrief', + 'Arvizu', + 'Botts', + 'Moorer', + 'Landreth', + 'Hulett', + 'Marinelli', + 'Falco', + 'Silvestri', + 'Gottschalk', + 'Thiele', + 'Kight', + 'Warrington', + 'Huckaby', + 'Ledet', + 'Charbonneau', + 'Crozier', + 'Mohan', + 'Stroh', + 'Bolinger', + 'Delvecchio', + 'Macfarlane', + 'Cribbs', + 'Mcloughlin', + 'Maynor', + 'Ming', + 'Digiovanni', + 'Truesdale', + 'Pfeffer', + 'Benn', + 'Chaparro', + 'Englert', + 'Spano', + 'Ogletree', + 'Yancy', + 'Swick', + 'Hallmark', + 'Mattern', + 'Tryon', + 'Plumb', + 'Martineau', + 'Man', + 'Grube', + 'Holst', + 'Nez', + 'Belden', + 'Aikens', + 'Litton', + 'Moorhead', + 'Dufresne', + 'Bonney', + 'Heyward', + 'Halliday', + 'Ito', + 'Crossman', + 'Gast', + 'Levan', + 'Wine', + 'Desouza', + 'Kornegay', + 'Nam', + 'Keough', + 'Stotts', + 'Dickenson', + 'Ousley', + 'Leduc', + 'Revels', + 'Dizon', + 'Arreguin', + 'Shockey', + 'Alegria', + 'Blades', + 'Ignacio', + 'Mellon', + 'Ebersole', + 'Sain', + 'Weissman', + 'Wargo', + 'Claypool', + 'Zorn', + 'Julien', + 'Hinshaw', + 'Alberto', + 'Garduno', + 'Kellar', + 'Rizo', + 'Labonte', + 'Humble', + 'Downer', + 'Lykins', + 'Tower', + 'Vanhouten', + 'Chairez', + 'Campa', + 'Blizzard', + 'Standley', + 'Reiser', + 'Whitener', + 'Menefee', + 'Nalley', + 'Lasher', + 'Strang', + 'Smock', + 'Moralez', + 'Kiel', + 'Moffatt', + 'Behm', + 'Hackworth', + 'Dirks', + 'Kratz', + 'Guillot', + 'Tittle', + 'Stlouis', + 'Seymore', + 'Searle', + 'Utter', + 'Wilborn', + 'Dortch', + 'Duron', + 'Cardinal', + 'Spikes', + 'Arambula', + 'Cutter', + 'Dibenedetto', + 'Botelho', + 'Bedwell', + 'Kilby', + 'Bottoms', + 'Cassady', + 'Rothwell', + 'Bilodeau', + 'Markowitz', + 'Baucom', + 'Valley', + 'Esqueda', + 'Depalma', + 'Laskowski', + 'Hopp', + 'Casale', + 'Perreault', + 'Shuster', + 'Wolter', + 'Raby', + 'Cyrus', + 'Tseng', + 'Georges', + 'Das', + 'Wilfong', + 'Schlueter', + 'Woolf', + 'Stickney', + 'Mcinerney', + 'Curcio', + 'Fowlkes', + 'Boldt', + 'Zander', + 'Shropshire', + 'Antonelli', + 'Froehlich', + 'Butterworth', + 'Stedman', + 'Broadnax', + 'Kroeger', + 'Kellner', + 'Monreal', + 'Armas', + 'Mcguinness', + 'Canterbury', + 'Weisman', + 'Hilburn', + 'Carruthers', + 'Pell', + 'Peele', + 'Devaney', + 'Owings', + 'Mar', + 'Liggett', + 'Breslin', + 'Soucy', + 'Aguila', + 'Weidman', + 'Mingo', + 'Tarango', + 'Winger', + 'Poteet', + 'Acree', + 'Mcnew', + 'Leatherwood', + 'Aubrey', + 'Waring', + 'Soler', + 'Roof', + 'Sunderland', + 'Blackford', + 'Rabe', + 'Hepler', + 'Leonardo', + 'Spina', + 'Smythe', + 'Alex', + 'Barta', + 'Bybee', + 'Campagna', + 'Pete', + 'Batchelder', + 'Gurney', + 'Wyche', + 'Schutt', + 'Rashid', + 'Almazan', + 'Pahl', + 'Perri', + 'Viramontes', + 'Cavender', + 'Snapp', + 'Newson', + 'Sandhu', + 'Fernando', + 'Stockdale', + 'Garfield', + 'Ealy', + 'Mcfarlin', + 'Bieber', + 'Callan', + 'Arruda', + 'Oquendo', + 'Levasseur', + 'Maple', + 'Kowal', + 'Kushner', + 'Naquin', + 'Shouse', + 'Mcquade', + 'Cai', + 'Smedley', + 'Gober', + 'Saiz', + 'Brunelle', + 'Arbuckle', + 'Landes', + 'Mak', + 'Korte', + 'Oxley', + 'Boger', + 'Mickey', + 'Lent', + 'Cureton', + 'Husted', + 'Eidson', + 'Boyett', + 'Kitts', + 'Shope', + 'Hance', + 'Jessen', + 'Litchfield', + 'Torre', + 'Cargill', + 'Herren', + 'Straight', + 'Merz', + 'Weese', + 'Sperling', + 'Lapierre', + 'Yung', + 'Doggett', + 'Cauley', + 'Hardeman', + 'Margolis', + 'Watford', + 'Seltzer', + 'Fullmer', + 'Timberlake', + 'Butz', + 'Duquette', + 'Olin', + 'Leverett', + 'Hartford', + 'Otte', + 'Beaton', + 'Grimaldi', + 'Marotta', + 'Carlsen', + 'Cullum', + 'Monte', + 'Haygood', + 'Middlebrooks', + 'Lazarus', + 'Shiver', + 'Ivie', + 'Niemi', + 'Lacombe', + 'Judson', + 'Ginsberg', + 'Firestone', + 'Izquierdo', + 'Deel', + 'Jacinto', + 'Towers', + 'Fritsch', + 'Albin', + 'Kaminsky', + 'Yin', + 'Wrobel', + 'Birdwell', + 'Krieg', + 'Danforth', + 'Florio', + 'Saito', + 'Clift', + 'Duck', + 'Matt', + 'Moxley', + 'Barbieri', + 'Klatt', + 'Saltzman', + 'Chesney', + 'Bojorquez', + 'Cosentino', + 'Lodge', + 'Converse', + 'Decastro', + 'Gerhart', + 'Music', + 'Danley', + 'Santangelo', + 'Bevins', + 'Coen', + 'Seibel', + 'Lindemann', + 'Dressler', + 'Newport', + 'Bedolla', + 'Lillie', + 'Rhone', + 'Penaloza', + 'Swart', + 'Niemeyer', + 'Pilkington', + 'Matta', + 'Hollifield', + 'Gillman', + 'Montana', + 'Maroney', + 'Stenger', + 'Loos', + 'Wert', + 'Brogdon', + 'Gandhi', + 'Bent', + 'Tabb', + 'Sikorski', + 'Hagedorn', + 'Hannigan', + 'Hoss', + 'Conlin', + 'Trott', + 'Fall', + 'Granado', + 'Bartell', + 'Rubalcava', + 'Neves', + 'Poynter', + 'Alton', + 'Paschall', + 'Waltman', + 'Parke', + 'Kittle', + 'Czarnecki', + 'Bloodworth', + 'Knorr', + 'Timms', + 'Derry', + 'Messier', + 'Saad', + 'Cozart', + 'Sutphin', + 'Puryear', + 'Gatto', + 'Whitacre', + 'Verdin', + 'Bloomer', + 'Brundage', + 'Brian', + 'Seger', + 'Clare', + 'Balch', + 'Tharpe', + 'Rayford', + 'Halter', + 'Barefoot', + 'Gonsalez', + 'Lomas', + 'Monzon', + 'Howarth', + 'Mccready', + 'Gudino', + 'Serafin', + 'Sanfilippo', + 'Minnich', + 'Eldredge', + 'Malave', + 'Greeley', + 'Sisneros', + 'Kangas', + 'Peery', + 'Lunn', + 'Lukas', + 'Bunce', + 'Riccio', + 'Thies', + 'Stivers', + 'Conard', + 'Mullaney', + 'Catalan', + 'Omar', + 'Theobald', + 'Jeffcoat', + 'Kucera', + 'Borkowski', + 'Coomer', + 'Mathison', + 'Croom', + 'Rushton', + 'Stites', + 'Pendley', + 'Till', + 'Oconner', + 'Forsberg', + 'Wages', + 'Fillmore', + 'Barcenas', + 'Gillard', + 'Leak', + 'Towle', + 'Esser', + 'Dunlop', + 'Quackenbush', + 'Archambault', + 'Buller', + 'Newlin', + 'Urquhart', + 'Shanley', + 'Mote', + 'Ippolito', + 'Rozier', + 'Reidy', + 'Gregor', + 'Swaney', + 'Bradfield', + 'Fudge', + 'More', + 'Tester', + 'Higley', + 'Dambrosio', + 'Bullington', + 'Highsmith', + 'Silas', + 'Felker', + 'Sawicki', + 'Beltz', + 'Albarran', + 'Aitken', + 'Findlay', + 'Looper', + 'Tooley', + 'Lasley', + 'Moynihan', + 'Ratcliffe', + 'Grizzle', + 'Souders', + 'Nussbaum', + 'Suber', + 'Macdougall', + 'Waddle', + 'Brawner', + 'Tucci', + 'Cosme', + 'Walk', + 'Gordy', + 'Tarrant', + 'Rosenblum', + 'Huth', + 'Bridgeman', + 'Hinkley', + 'Gehrke', + 'Boden', + 'Suazo', + 'Gambill', + 'Widner', + 'Chick', + 'Mccollough', + 'Hassler', + 'Odum', + 'Pawlak', + 'Prevost', + 'Slavin', + 'Fetters', + 'Beamon', + 'Renshaw', + 'Deng', + 'Plourde', + 'Holstein', + 'Rye', + 'Holliman', + 'Melville', + 'Messinger', + 'Turcios', + 'Garnica', + 'Feeley', + 'Mariani', + 'Otten', + 'Dorado', + 'Mortenson', + 'Meissner', + 'Scarlett', + 'Sweitzer', + 'Glisson', + 'Desjardins', + 'Penland', + 'Elledge', + 'Crumley', + 'Deen', + 'Shih', + 'Heuer', + 'Gloria', + 'Lail', + 'Mcandrew', + 'Mcnaughton', + 'Cortese', + 'Stgermain', + 'Hammon', + 'Leininger', + 'Flickinger', + 'Dement', + 'Bumgardner', + 'Tessier', + 'Fulford', + 'Cervantez', + 'Wisner', + 'Shulman', + 'Sabol', + 'Papp', + 'Strasser', + 'Sartin', + 'Rothstein', + 'Grote', + 'Beaudry', + 'Deville', + 'Roop', + 'Villar', + 'Bussell', + 'Bowyer', + 'Yoshida', + 'Hertz', + 'Countryman', + 'Hoey', + 'Roseberry', + 'Schock', + 'Boozer', + 'Mccowan', + 'Kirschner', + 'Lechner', + 'Winkelman', + 'Witham', + 'Thurber', + 'Depriest', + 'Chenault', + 'Moten', + 'Tillotson', + 'Guan', + 'Ketcham', + 'Jiles', + 'Grosso', + 'Nottingham', + 'Kellam', + 'Alejo', + 'Thoma', + 'Marchetti', + 'Holifield', + 'Fortson', + 'Leasure', + 'Mceachern', + 'Oceguera', + 'Carleton', + 'Weekley', + 'Kinsella', + 'Harvell', + 'Waldon', + 'Kean', + 'Chancellor', + 'Blosser', + 'Detweiler', + 'Presnell', + 'Beachy', + 'Lingle', + 'Plumley', + 'Knopp', + 'Gamache', + 'Atwater', + 'Caine', + 'Woodland', + 'Terwilliger', + 'Moller', + 'Cleland', + 'Cottingham', + 'Janke', + 'Willman', + 'Dann', + 'Mangrum', + 'Shuck', + 'Paden', + 'Adelman', + 'Brim', + 'Tullis', + 'Hertel', + 'Gallaher', + 'Leopold', + 'Donegan', + 'Popovich', + 'Gusman', + 'Chatham', + 'Schooley', + 'Pinder', + 'Heise', + 'Maines', + 'Nystrom', + 'Jahnke', + 'Poon', + 'Murphree', + 'Pelaez', + 'Risley', + 'Sohn', + 'Shim', + 'Armentrout', + 'Kastner', + 'Philpott', + 'Mao', + 'Pursley', + 'Mangold', + 'Mccourt', + 'Hollar', + 'Desmarais', + 'Debord', + 'Gullett', + 'Gaeta', + 'Bae', + 'Houlihan', + 'Gorton', + 'Steinman', + 'Santo', + 'Snelling', + 'Corpuz', + 'Look', + 'Scudder', + 'Treece', + 'Binns', + 'Sokolowski', + 'Harner', + 'Gallup', + 'Marti', + 'Teasley', + 'Markel', + 'Casiano', + 'Nicks', + 'Recinos', + 'Paradise', + 'Colman', + 'Orange', + 'Mele', + 'Medford', + 'Templin', + 'Zuber', + 'Mackin', + 'Brodsky', + 'Householder', + 'Wirtz', + 'Hackman', + 'Tippett', + 'Polson', + 'Colston', + 'Cerna', + 'Herald', + 'Shults', + 'Shubert', + 'Mertens', + 'Dave', + 'Duffield', + 'Vanness', + 'Mayne', + 'Driskell', + 'Percy', + 'Lauderdale', + 'Cipriano', + 'Theodore', + 'Colella', + 'Kiger', + 'Brownfield', + 'Stella', + 'Wideman', + 'Maye', + 'Chisolm', + 'Muldoon', + 'Fitzwater', + 'Harville', + 'Dixson', + 'Burkey', + 'Hartsfield', + 'Schade', + 'Brawley', + 'Pelfrey', + 'Tennyson', + 'Whitted', + 'Silvas', + 'Harbour', + 'Krupa', + 'Peraza', + 'Erdmann', + 'Halpern', + 'Finnerty', + 'Mackinnon', + 'Humbert', + 'Mccarley', + 'Doster', + 'Kugler', + 'Livesay', + 'Force', + 'Haberman', + 'Lamp', + 'Hector', + 'Charron', + 'Woosley', + 'Rein', + 'Ashburn', + 'Greenleaf', + 'Niemann', + 'Carillo', + 'Skelly', + 'Nunnally', + 'Renfrow', + 'Prickett', + 'Angus', + 'Bednar', + 'Nightingale', + 'Steinbach', + 'Warnick', + 'Jason', + 'Hans', + 'Lydon', + 'Rutland', + 'Alleman', + 'Hawn', + 'Malin', + 'Beech', + 'Auger', + 'Desilva', + 'Izaguirre', + 'Isham', + 'Mandujano', + 'Glasser', + 'Dimarco', + 'Berumen', + 'Nipper', + 'Pegram', + 'Sundberg', + 'Labbe', + 'Mcphee', + 'Crafton', + 'Agustin', + 'Cantor', + 'Beller', + 'Bang', + 'Lawyer', + 'Croy', + 'Kyles', + 'Winans', + 'Battista', + 'Jost', + 'Bakken', + 'Dandridge', + 'Mustafa', + 'Ice', + 'Eklund', + 'Montesdeoca', + 'Hermes', + 'Grimaldo', + 'Vannoy', + 'Grainger', + 'Lamas', + 'Tarantino', + 'Witter', + 'Worthen', + 'Basinger', + 'Cowden', + 'Hiles', + 'Mcanally', + 'Felipe', + 'Gallimore', + 'Kapp', + 'Makowski', + 'Copenhaver', + 'Ramer', + 'Gideon', + 'Bowker', + 'Wilkens', + 'Seeger', + 'Huntsman', + 'Palladino', + 'Jessee', + 'Kittrell', + 'Rolle', + 'Ciccone', + 'Kolar', + 'Brannen', + 'Bixby', + 'Pohlman', + 'Strachan', + 'Lesher', + 'Fleischer', + 'Umana', + 'Murphey', + 'Mcentire', + 'Rabon', + 'Mcauley', + 'Bunton', + 'Soileau', + 'Sheriff', + 'Borowski', + 'Mullens', + 'Larrabee', + 'Prouty', + 'Malley', + 'Sumrall', + 'Reisinger', + 'Surber', + 'Kasten', + 'Shoemake', + 'Yowell', + 'Bonin', + 'Bevan', + 'Bove', + 'Boe', + 'Hazard', + 'Slay', + 'Carraway', + 'Kaczmarek', + 'Armitage', + 'Lowther', + 'Sheaffer', + 'Farah', + 'Atencio', + 'Ung', + 'Kirkham', + 'Cavanagh', + 'Mccutchen', + 'Shoop', + 'Nickles', + 'Borchardt', + 'Durkee', + 'Maus', + 'Shedd', + 'Petrillo', + 'Brainard', + 'Eddings', + 'Fanelli', + 'Seo', + 'Heaney', + 'Drennan', + 'Mcgarvey', + 'Saddler', + 'Lucia', + 'Higa', + 'Gailey', + 'Groh', + 'Hinckley', + 'Griner', + 'Norfleet', + 'Caplan', + 'Rademacher', + 'Souder', + 'Autrey', + 'Eskridge', + 'Drumm', + 'Fiske', + 'Giffin', + 'Townley', + 'Derose', + 'Burrus', + 'Castrejon', + 'Emmert', + 'Cothran', + 'Hartsell', + 'Kilburn', + 'Riggle', + 'Trussell', + 'Mulvey', + 'Barto', + 'Crank', + 'Lovely', + 'Woodhouse', + 'Powe', + 'Pablo', + 'Zack', + 'Murchison', + 'Dicarlo', + 'Kessel', + 'Hagood', + 'Rost', + 'Edson', + 'Blakeney', + 'Fant', + 'Brodeur', + 'Jump', + 'Spry', + 'Laguna', + 'Lotz', + 'Bergquist', + 'Collard', + 'Mash', + 'Rideout', + 'Bilbrey', + 'Selman', + 'Fortunato', + 'Holzer', + 'Pifer', + 'Mcabee', + 'Talamantes', + 'Tollefson', + 'Pastore', + 'Crew', + 'Wilcher', + 'Kutz', + 'Stallard', + 'Ressler', + 'Fehr', + 'Piercy', + 'Lafond', + 'Digiacomo', + 'Schuck', + 'Winkle', + 'Graybill', + 'Plata', + 'Gribble', + 'Odle', + 'Fraga', + 'Bressler', + 'Moultrie', + 'Tung', + 'Charette', + 'Marvel', + 'Kerby', + 'Mori', + 'Hamman', + 'Favors', + 'Freeze', + 'Delisle', + 'Straw', + 'Dingle', + 'Elizalde', + 'Cabello', + 'Zalewski', + 'Funkhouser', + 'Abate', + 'Nero', + 'Holston', + 'Josey', + 'Schreck', + 'Shroyer', + 'Paquin', + 'Bing', + 'Chauvin', + 'Maria', + 'Melgoza', + 'Arms', + 'Caddell', + 'Pitchford', + 'Sternberg', + 'Rana', + 'Lovelady', + 'Strouse', + 'Macarthur', + 'Lechuga', + 'Wolfson', + 'Mcglynn', + 'Koo', + 'Stoops', + 'Tetreault', + 'Lepage', + 'Duren', + 'Hartz', + 'Kissel', + 'Gish', + 'Largent', + 'Henninger', + 'Janson', + 'Carrick', + 'Kenner', + 'Haack', + 'Diego', + 'Wacker', + 'Wardell', + 'Ballentine', + 'Smeltzer', + 'Bibb', + 'Winton', + 'Bibbs', + 'Reinhard', + 'Nilsen', + 'Edison', + 'Kalinowski', + 'June', + 'Hewlett', + 'Blaisdell', + 'Zeman', + 'Chon', + 'Board', + 'Nealy', + 'Moretti', + 'Wanner', + 'Bonnett', + 'Hardie', + 'Mains', + 'Cordeiro', + 'Karim', + 'Kautz', + 'Craver', + 'Colucci', + 'Congdon', + 'Mounts', + 'Kurz', + 'Eder', + 'Merryman', + 'Soles', + 'Dulin', + 'Lubin', + 'Mcgowen', + 'Hockenberry', + 'Work', + 'Mazzola', + 'Crandell', + 'Mcgrady', + 'Caruthers', + 'Govea', + 'Meng', + 'Fetter', + 'Trusty', + 'Weintraub', + 'Hurlburt', + 'Reiff', + 'Nowakowski', + 'Hoard', + 'Densmore', + 'Blumenthal', + 'Neale', + 'Schiff', + 'Raleigh', + 'Steiger', + 'Marmolejo', + 'Jessie', + 'Palafox', + 'Tutt', + 'Keister', + 'Core', + 'Im', + 'Wendell', + 'Bennet', + 'Canning', + 'Krull', + 'Patti', + 'Zucker', + 'Schlesinger', + 'Wiser', + 'Dunson', + 'Olmedo', + 'Hake', + 'Champlin', + 'Braley', + 'Wheelock', + 'Geier', + 'Janis', + 'Turek', + 'Grindstaff', + 'Schaffner', + 'Deas', + 'Sirois', + 'Polito', + 'Bergin', + 'Schall', + 'Vineyard', + 'Pellegrini', + 'Corrado', + 'Oleson', + 'List', + 'Dameron', + 'Parkin', + 'Flake', + 'Hollingshead', + 'Chancey', + 'Hufford', + 'Morell', + 'Kantor', + 'Chasteen', + 'Laborde', + 'Sessoms', + 'Hermanson', + 'Burnell', + 'Dewberry', + 'Tolman', + 'Glasscock', + 'Durfee', + 'Gilroy', + 'Wilkey', + 'Dungan', + 'Saravia', + 'Weigand', + 'Bigler', + 'Vancleave', + 'Burlingame', + 'Roseman', + 'Stiffler', + 'Gagliano', + 'Kates', + 'Awad', + 'Knepp', + 'Rondeau', + 'Bertsch', + 'Wolverton', + 'Walcott', + 'Poss', + 'Frisby', + 'Wexler', + 'Reinhold', + 'Krol', + 'Stuck', + 'Ricciardi', + 'Ardoin', + 'Michaelson', + 'Lillard', + 'Burciaga', + 'Birchfield', + 'Patch', + 'Silvey', + 'Simmonds', + 'Siu', + 'Press', + 'Deans', + 'Riegel', + 'Ismail', + 'Magallon', + 'Diller', + 'Hine', + 'Michalak', + 'Dones', + 'Deitz', + 'Gulledge', + 'Stroman', + 'Kobayashi', + 'Hafer', + 'Berk', + 'Landin', + 'Gilles', + 'Obryant', + 'Cheeks', + 'Gress', + 'Lutes', + 'Raphael', + 'Pizano', + 'Bachmann', + 'Cifuentes', + 'Earp', + 'Gilreath', + 'Peluso', + 'Hubbs', + 'Alvis', + 'Peer', + 'Dutra', + 'Stetson', + 'Constant', + 'Benford', + 'Sorto', + 'Cater', + 'Rosier', + 'Isenberg', + 'Shanklin', + 'Veloz', + 'Ramage', + 'Dunford', + 'Ku', + 'Hames', + 'Eddins', + 'Ruano', + 'Frink', + 'Flower', + 'Beadle', + 'Rochester', + 'Fontes', + 'Mefford', + 'Barwick', + 'Millen', + 'Stelly', + 'Cann', + 'Rayner', + 'Carruth', + 'Wendling', + 'Shutt', + 'Hazzard', + 'Maravilla', + 'Gregorio', + 'Pavlik', + 'Hudnall', + 'Aston', + 'Mcglothlin', + 'Weise', + 'Devereaux', + 'Belle', + 'Borst', + 'Burdett', + 'Frisbie', + 'Rummel', + 'Rentz', + 'Cobos', + 'Kimura', + 'Neu', + 'Winner', + 'Candelario', + 'Callis', + 'Basso', + 'Mckim', + 'Tai', + 'Eskew', + 'Lair', + 'Pye', + 'Knuth', + 'Scarberry', + 'Alter', + 'Mcgann', + 'Anson', + 'Drews', + 'Zuckerman', + 'Petrone', + 'Ludlow', + 'Bechtold', + 'Nair', + 'Rennie', + 'Rhine', + 'Fleetwood', + 'Sudduth', + 'Leftwich', + 'Hardiman', + 'Northrop', + 'Banker', + 'Killen', + 'Mastin', + 'Mcmurry', + 'Jasinski', + 'Taliaferro', + 'Mathers', + 'Sheikh', + 'Nuss', + 'Jesse', + 'Zabel', + 'Crotty', + 'Kamp', + 'Fleenor', + 'Halcomb', + 'Eady', + 'Vella', + 'Demars', + 'Ensley', + 'Delosreyes', + 'Zendejas', + 'Leeds', + 'Just', + 'Oday', + 'Dills', + 'Zeng', + 'Barriga', + 'Millican', + 'Cascio', + 'Eakin', + 'Argo', + 'Borland', + 'Cover', + 'Diorio', + 'Coria', + 'Lease', + 'Pinkham', + 'Reichard', + 'Guadalupe', + 'Hansel', + 'Bye', + 'Westerfield', + 'Gales', + 'Mickle', + 'Licata', + 'Cram', + 'Bracy', + 'Motta', + 'Imhoff', + 'Siegfried', + 'Merry', + 'Swiger', + 'Ton', + 'Hersey', + 'Marrone', + 'Ginter', + 'Miele', + 'Breton', + 'Scheffler', + 'Pray', + 'Stapp', + 'Bogard', + 'Towner', + 'Mcelhaney', + 'Bridgewater', + 'Waldner', + 'Quijano', + 'Galante', + 'Quesenberry', + 'Rourke', + 'Harshman', + 'Traver', + 'Alvares', + 'Mcgaha', + 'Nyberg', + 'Pharr', + 'Lerch', + 'Sok', + 'Rosson', + 'Wiggs', + 'Mcelveen', + 'Dimaggio', + 'Rettig', + 'Ahumada', + 'Hetzel', + 'Welling', + 'Chadwell', + 'Swink', + 'Mckinzie', + 'Kwak', + 'Chabot', + 'Tomaszewski', + 'Bonanno', + 'Lesko', + 'Teter', + 'Stalnaker', + 'Ober', + 'Hovis', + 'Hosey', + 'Chaudhry', + 'Fey', + 'Vital', + 'Earhart', + 'Heins', + 'Crowther', + 'Hanner', + 'Behr', + 'Billington', + 'Vogler', + 'Hersh', + 'Perlman', + 'Given', + 'Files', + 'Partain', + 'Coddington', + 'Jardine', + 'Grimmett', + 'Springs', + 'Macomber', + 'Horgan', + 'Arrieta', + 'Charley', + 'Josephson', + 'Tupper', + 'Provenzano', + 'Celaya', + 'Mcvicker', + 'Sigala', + 'Wimer', + 'Ayon', + 'Dossantos', + 'Norvell', + 'Lorenzen', + 'Pasquale', + 'Lambright', + 'Goings', + 'Defelice', + 'Wen', + 'Sigman', + 'Gaylor', + 'Rehm', + 'Carino', + 'Werth', + 'Forehand', + 'Hanke', + 'Lasalle', + 'Mitchum', + 'Priester', + 'Lefler', + 'Celis', + 'Lesser', + 'Fitz', + 'Wentzel', + 'Lavery', + 'Klassen', + 'Shiflett', + 'Hedden', + 'Henn', + 'Coursey', + 'Drain', + 'Delorenzo', + 'Haws', + 'Stansberry', + 'Trump', + 'Dantzler', + 'Chaidez', + 'Mcsweeney', + 'Griffen', + 'Trail', + 'Gandara', + 'Brunk', + 'Kennon', + 'Coss', + 'Blackmore', + 'Metts', + 'Gluck', + 'Blackshear', + 'Cogan', + 'Boney', + 'Encinas', + 'Adamski', + 'Roberge', + 'Schuette', + 'Valero', + 'Barroso', + 'Antunez', + 'Mohammad', + 'Housley', + 'Escoto', + 'Ullrich', + 'Helman', + 'Trost', + 'Lafave', + 'Faith', + 'Blaney', + 'Kershner', + 'Hoehn', + 'Roemer', + 'Isley', + 'Lipinski', + 'Claus', + 'Caulfield', + 'Paiz', + 'Leyba', + 'Robinett', + 'Lambeth', + 'Tarpley', + 'Essex', + 'Eilers', + 'Epley', + 'Murdoch', + 'Sandstrom', + 'Laux', + 'Domingue', + 'Grundy', + 'Bellows', + 'Spindler', + 'Boos', + 'Bhatt', + 'Tye', + 'Salamone', + 'Cirillo', + 'Troup', + 'Jemison', + 'Calzada', + 'Dowden', + 'Geraci', + 'Dunphy', + 'Sack', + 'Sloane', + 'Hathcock', + 'Yap', + 'Ronquillo', + 'Willette', + 'Partlow', + 'Dear', + 'Tunstall', + 'Kiss', + 'Huhn', + 'Seabolt', + 'Beene', + 'Sather', + 'Lockridge', + 'Despain', + 'Wines', + 'Mcalpine', + 'Wadley', + 'Dey', + 'Loring', + 'Meadors', + 'Buettner', + 'Lavalley', + 'Bugg', + 'Creek', + 'Millett', + 'Pumphrey', + 'Fregoso', + 'Merkle', + 'Sheffer', + 'Glassman', + 'Groover', + 'Sweatt', + 'Colunga', + 'Boykins', + 'Seng', + 'Stutz', + 'Brann', + 'Blakey', + 'Munos', + 'Geddes', + 'Avendano', + 'Molitor', + 'Diedrich', + 'Langham', + 'Kindle', + 'Lacour', + 'Buckler', + 'Corum', + 'Bakke', + 'Godin', + 'Kerner', + 'Tobey', + 'Kubiak', + 'Hoyer', + 'Hedge', + 'Priebe', + 'Callison', + 'Lahr', + 'Shears', + 'Snavely', + 'Blatt', + 'Mcpeak', + 'Tinney', + 'Sullins', + 'Bernhard', + 'Gibb', + 'Vaillancourt', + 'Paugh', + 'Funes', + 'Romans', + 'Maurice', + 'Lough', + 'Kerwin', + 'Sanger', + 'Vierra', + 'Markus', + 'Comfort', + 'Krall', + 'Spies', + 'Malcom', + 'Vizcarra', + 'Beamer', + 'Kellerman', + 'Mcroberts', + 'Waterhouse', + 'Stromberg', + 'Persons', + 'Whitesell', + 'Harty', + 'Rosenblatt', + 'Broadwater', + 'Clardy', + 'Shackleford', + 'Jacquez', + 'Brittingham', + 'Lindahl', + 'Feliz', + 'Danna', + 'Garwood', + 'Heron', + 'Southwick', + 'Dehoyos', + 'Cottrill', + 'Mellor', + 'Goldfarb', + 'Grieco', + 'Helgeson', + 'Vandusen', + 'Heinen', + 'Batt', + 'Ruch', + 'Garretson', + 'Pankey', + 'Caudillo', + 'Jakubowski', + 'Plowman', + 'Starcher', + 'Wessels', + 'Moose', + 'Rosner', + 'Louden', + 'Walczak', + 'Poulsen', + 'Mcchesney', + 'Karns', + 'Casares', + 'Cusack', + 'Cespedes', + 'Cornelison', + 'Crossland', + 'Hirst', + 'Mier', + 'Roberto', + 'Canchola', + 'Bosse', + 'Shetler', + 'Melendrez', + 'Giannini', + 'Six', + 'Traynor', + 'Knepper', + 'Lonergan', + 'Kessinger', + 'Hollon', + 'Weathersby', + 'Stouffer', + 'Gingrich', + 'Breault', + 'Pompa', + 'Vanhoose', + 'Burdine', + 'Lark', + 'Stiltner', + 'Wunderlich', + 'Yong', + 'Merrifield', + 'Willhite', + 'Geiser', + 'Lambrecht', + 'Keffer', + 'Carlo', + 'Germany', + 'Turgeon', + 'Dame', + 'Tristan', + 'Bova', + 'Doak', + 'Mannino', + 'Shotwell', + 'Bash', + 'Coots', + 'Feist', + 'Mahmood', + 'Schlabach', + 'Salzman', + 'Kass', + 'Bresnahan', + 'Stonge', + 'Tesch', + 'Grajeda', + 'Mccarron', + 'Mcelwee', + 'Spradling', + 'Mckown', + 'Colgan', + 'Piedra', + 'Collum', + 'Stoffel', + 'Won', + 'Gulick', + 'Devault', + 'Enders', + 'Yanes', + 'Lansing', + 'Ebner', + 'Deegan', + 'Boutin', + 'Fetzer', + 'Andresen', + 'Trigg', + 'Sale', + 'Polite', + 'Hummer', + 'Wille', + 'Bowerman', + 'Routh', + 'Iqbal', + 'Lakey', + 'Mcadoo', + 'Laflamme', + 'Boulware', + 'Guadarrama', + 'Campana', + 'Strayer', + 'Aho', + 'Emmett', + 'Wolters', + 'Bos', + 'Knighten', + 'Averill', + 'Bhakta', + 'Schumaker', + 'Stutts', + 'Mejias', + 'Byer', + 'Mahone', + 'Staab', + 'Riehl', + 'Briceno', + 'Zabala', + 'Lafountain', + 'Clemmer', + 'Mansell', + 'Rossetti', + 'Lafontaine', + 'Mager', + 'Adamo', + 'Bogue', + 'Northern', + 'Disney', + 'Masse', + 'Senter', + 'Yaeger', + 'Dahlberg', + 'Bisson', + 'Leitner', + 'Bolding', + 'Ormsby', + 'Berard', + 'Brazell', + 'Pickle', + 'Hord', + 'Mcguigan', + 'Glennon', + 'Aman', + 'Dearman', + 'Cauthen', + 'Rembert', + 'Delucia', + 'Enciso', + 'Slusser', + 'Kratzer', + 'Schoenfeld', + 'Gillam', + 'Rael', + 'Rhode', + 'Moton', + 'Eide', + 'Eliason', + 'Helfrich', + 'Bish', + 'Goodnight', + 'Campion', + 'Blow', + 'Gerken', + 'Goldenberg', + 'Mellinger', + 'Nations', + 'Maiden', + 'Anzalone', + 'Wagers', + 'Arguelles', + 'Christen', + 'Guth', + 'Stamey', + 'Bozarth', + 'Balogh', + 'Grammer', + 'Chafin', + 'Prine', + 'Freer', + 'Alder', + 'Latorre', + 'Zaleski', + 'Lindholm', + 'Belisle', + 'Zacharias', + 'Swinson', + 'Bazemore', + 'Glazer', + 'Acord', + 'Said', + 'Liggins', + 'Lueck', + 'Luedtke', + 'Blackstone', + 'Copper', + 'Riker', + 'Braud', + 'Demello', + 'Rode', + 'Haven', + 'Rhee', + 'Galligan', + 'Record', + 'Nilson', + 'Ansley', + 'Pera', + 'Gilliard', + 'Copp', + 'Haugh', + 'Dunigan', + 'Grinnell', + 'Garr', + 'Leonhardt', + 'Elswick', + 'Shahan', + 'Mike', + 'Boddie', + 'Casella', + 'Mauricio', + 'Millet', + 'Daye', + 'Claussen', + 'Pierrelouis', + 'Fleischman', + 'Embrey', + 'Durso', + 'Whisenant', + 'Rankins', + 'Lasky', + 'Askins', + 'Rupe', + 'Rochelle', + 'Burkes', + 'Kreger', + 'Mishler', + 'Heald', + 'Jager', + 'Player', + 'Linehan', + 'Horwitz', + 'Jacobi', + 'Maine', + 'Wiest', + 'Ostrom', + 'Sealy', + 'Jimerson', + 'Alverson', + 'Senior', + 'Hassett', + 'Colter', + 'Schleicher', + 'Marini', + 'Mcbrayer', + 'Arzola', + 'Sobel', + 'Frederickson', + 'Confer', + 'Tadlock', + 'Belmonte', + 'Lebrun', + 'Clyde', + 'Alleyne', + 'Lozoya', + 'Teller', + 'Husband', + 'Brigman', + 'Secrest', + 'Krajewski', + 'Neiman', + 'Trull', + 'Watterson', + 'Vanhook', + 'Sotomayor', + 'Woodrum', + 'Baskerville', + 'Finke', + 'Hohman', + 'Arp', + 'Hearne', + 'Mauk', + 'Danko', + 'Laurie', + 'Linderman', + 'Hutt', + 'Springfield', + 'Chmielewski', + 'Klimek', + 'Phinney', + 'Leboeuf', + 'Mcglone', + 'Holmquist', + 'Cogswell', + 'Nichol', + 'Klink', + 'Dunston', + 'Krawczyk', + 'Dart', + 'Woodside', + 'Smitherman', + 'Gasca', + 'Sala', + 'Foxworth', + 'Kammerer', + 'Auer', + 'Pegues', + 'Bukowski', + 'Koger', + 'Spitz', + 'Blomquist', + 'Creasy', + 'Bomar', + 'Holub', + 'Loney', + 'Garry', + 'Habib', + 'Chea', + 'Dupuy', + 'Seaver', + 'Sowards', + 'Julius', + 'Fulks', + 'Braithwaite', + 'Bretz', + 'Mccammon', + 'Sedillo', + 'Chiasson', + 'Oney', + 'Horstman', + 'Waites', + 'Mccusker', + 'Fenske', + 'Conwell', + 'Brokaw', + 'Cloyd', + 'Biles', + 'Aguinaga', + 'Astorga', + 'Demaio', + 'Liberty', + 'Kayser', + 'Ney', + 'Barthel', + 'Lennox', + 'Trautman', + 'Purser', + 'Pitzer', + 'Mattos', + 'Liss', + 'Clack', + 'Sias', + 'Bobb', + 'Stoller', + 'Robillard', + 'Almodovar', + 'Cribb', + 'Ebel', + 'Oyler', + 'Dail', + 'Ericksen', + 'Geis', + 'Everitt', + 'Cropper', + 'Meisner', + 'Skeens', + 'Frith', + 'Privett', + 'Braddy', + 'Bolick', + 'Severance', + 'Jeffreys', + 'Bethune', + 'Delcid', + 'Buzzard', + 'Broadbent', + 'Bono', + 'Addis', + 'Johannes', + 'Tims', + 'Castorena', + 'Simonsen', + 'Glidewell', + 'Mui', + 'Ogilvie', + 'Soukup', + 'Sunday', + 'Redwine', + 'Borton', + 'Schuyler', + 'Rudisill', + 'Beckford', + 'Pascua', + 'Garton', + 'Gilkey', + 'Applewhite', + 'Halterman', + 'Alsup', + 'Delreal', + 'Hubble', + 'Quijada', + 'Kropp', + 'Dunkle', + 'Lemire', + 'Lamontagne', + 'Dunkin', + 'Paulin', + 'Attaway', + 'Baugher', + 'Hornbeck', + 'Niehaus', + 'Nice', + 'Trimmer', + 'Canaday', + 'Maney', + 'Trexler', + 'Schmucker', + 'Edinger', + 'Massengill', + 'Rowlett', + 'Caviness', + 'Kam', + 'Chesnut', + 'Giardina', + 'Spaeth', + 'Gebhart', + 'Morano', + 'Salguero', + 'Buckland', + 'Reina', + 'Jumper', + 'Navas', + 'Thrift', + 'Spradley', + 'Bitner', + 'Ayer', + 'Harber', + 'Landaverde', + 'Mcmillion', + 'Naugle', + 'Dole', + 'Seagraves', + 'Smithers', + 'Frechette', + 'Weeden', + 'Caston', + 'Cavallaro', + 'Laureano', + 'Mandell', + 'Lowrance', + 'Baty', + 'Ronan', + 'Gigliotti', + 'Rossiter', + 'Mines', + 'Alatorre', + 'Markowski', + 'Berge', + 'Hatter', + 'Weakley', + 'Borrero', + 'Glazier', + 'Lavergne', + 'Sines', + 'Ingham', + 'Meltzer', + 'Rabinowitz', + 'Siciliano', + 'Canas', + 'Perna', + 'Struck', + 'Dare', + 'Nay', + 'Severino', + 'Mathewson', + 'Bouldin', + 'Topete', + 'Brunette', + 'Sin', + 'Hendren', + 'Brickey', + 'Ferrier', + 'Alessi', + 'Scheel', + 'Storer', + 'Matherne', + 'Mecham', + 'Spiker', + 'Hibbert', + 'Klingensmith', + 'Lefever', + 'Banning', + 'Bankhead', + 'Roan', + 'Brack', + 'Pascoe', + 'Davie', + 'Scheid', + 'Jim', + 'Tweedy', + 'Strahan', + 'Revis', + 'Fermin', + 'Obrian', + 'Motes', + 'Lobo', + 'Palmisano', + 'Faught', + 'Byington', + 'Garren', + 'Hungerford', + 'Vanzandt', + 'Gust', + 'Heater', + 'Klingler', + 'Delay', + 'Wear', + 'Hendley', + 'Threatt', + 'Gaughan', + 'Kunze', + 'Hessler', + 'Lindell', + 'Monteleone', + 'Palazzolo', + 'Shear', + 'Phares', + 'Cavalier', + 'Benning', + 'Urbanski', + 'Darrah', + 'Wager', + 'Mohn', + 'Vereen', + 'Beiler', + 'Hedlund', + 'Quade', + 'Wieczorek', + 'Cicero', + 'Hoekstra', + 'Scalf', + 'Ducote', + 'Havard', + 'Espiritu', + 'Beacham', + 'Bolger', + 'Schuller', + 'Sill', + 'Dice', + 'Lemmons', + 'Orlowski', + 'Lundeen', + 'Steck', + 'Stanfill', + 'Rakes', + 'Laine', + 'Haviland', + 'Durrett', + 'Naumann', + 'Donahoe', + 'Reif', + 'Franck', + 'Amoroso', + 'Belknap', + 'Tolle', + 'Perrotta', + 'Heyer', + 'Dougan', + 'Frakes', + 'Leath', + 'Poteat', + 'Violette', + 'Marine', + 'Zellner', + 'Granillo', + 'Fontanez', + 'Didonato', + 'Bradberry', + 'Morman', + 'Mentzer', + 'Lamoureux', + 'Sabatino', + 'Catania', + 'Wenner', + 'Pastrana', + 'Shenk', + 'Losey', + 'Hepburn', + 'Antonucci', + 'Egger', + 'Higbee', + 'Adames', + 'Reep', + 'Cavallo', + 'Bridwell', + 'Villalba', + 'Poor', + 'Peet', + 'Everette', + 'Arney', + 'Towery', + 'Sharon', + 'Trainer', + 'Marrow', + 'Cumming', + 'Rimmer', + 'Stanger', + 'Pinter', + 'Felt', + 'Parrett', + 'Garrard', + 'Benedetto', + 'Lingenfelter', + 'Resch', + 'Billy', + 'Mikesell', + 'Osterman', + 'Trueblood', + 'Redfern', + 'Calderone', + 'Placencia', + 'Wamsley', + 'Warr', + 'Varnado', + 'Harshbarger', + 'Topping', + 'Feltner', + 'Decosta', + 'Tart', + 'Blumberg', + 'Shaikh', + 'Culley', + 'Bork', + 'Thibeault', + 'Stolz', + 'Ramsdell', + 'Tedford', + 'Noto', + 'Poulson', + 'Daves', + 'Altieri', + 'Mendosa', + 'Kisner', + 'Grafton', + 'Remy', + 'Hartline', + 'Cripe', + 'Sher', + 'Mulvaney', + 'Ansari', + 'Hartfield', + 'Whitton', + 'Wathen', + 'Eisele', + 'Hinojos', + 'Backer', + 'Speaks', + 'Schuetz', + 'Novoa', + 'Marcos', + 'Mask', + 'Oboyle', + 'Kircher', + 'Stang', + 'Sibert', + 'Scala', + 'Zacarias', + 'Hendon', + 'Halvorsen', + 'Montalbano', + 'Zermeno', + 'Vancamp', + 'Grams', + 'Hornberger', + 'Binion', + 'Dewald', + 'Rives', + 'Sankey', + 'Kleinman', + 'Falconer', + 'Rumph', + 'Matus', + 'Swett', + 'Spinner', + 'Depasquale', + 'Gamino', + 'Olmsted', + 'Absher', + 'Culler', + 'Fryman', + 'Lampert', + 'Carlyle', + 'Terranova', + 'Dunagan', + 'Chouinard', + 'Wesolowski', + 'Hetherington', + 'Scalise', + 'Pendergast', + 'Marcano', + 'Joubert', + 'Scheller', + 'Whisenhunt', + 'Lenoir', + 'Mahar', + 'Vanlandingham', + 'Pecoraro', + 'You', + 'Natividad', + 'Daum', + 'Penick', + 'Eddington', + 'Deleo', + 'Soltis', + 'Santucci', + 'Costanza', + 'Hiner', + 'Farlow', + 'Hartsock', + 'Duprey', + 'Fann', + 'Safford', + 'Murtha', + 'Fessler', + 'Chien', + 'Paynter', + 'Devera', + 'Hoelscher', + 'Boltz', + 'Deacon', + 'Loo', + 'Enoch', + 'Dilorenzo', + 'Saville', + 'Mirza', + 'Takacs', + 'Drexler', + 'Lakin', + 'Geraghty', + 'Widmer', + 'Esteves', + 'Llanes', + 'Cerny', + 'Quist', + 'Hargraves', + 'Toma', + 'Tarter', + 'Chapple', + 'Alderete', + 'Michelson', + 'Clymer', + 'Batey', + 'Sealey', + 'Loughlin', + 'Preece', + 'Zurita', + 'Courville', + 'Desousa', + 'Shamblin', + 'Tingley', + 'Noles', + 'Misner', + 'Standifer', + 'Dinardo', + 'Dillow', + 'Bullis', + 'Carballo', + 'Everly', + 'Mulvihill', + 'Tincher', + 'Carle', + 'Lundin', + 'Birdsall', + 'Bainbridge', + 'Suttle', + 'Wightman', + 'Mower', + 'Mountain', + 'Bickham', + 'Durante', + 'Viveros', + 'Swinford', + 'Mcgruder', + 'Tapley', + 'Grable', + 'Gwynn', + 'Wiebe', + 'Stagg', + 'Dash', + 'Heitman', + 'Cluff', + 'Huertas', + 'Fortuna', + 'Lines', + 'Sly', + 'Halford', + 'Helsel', + 'Bicknell', + 'Blakeman', + 'Colangelo', + 'Olney', + 'Quinton', + 'Rothrock', + 'Renz', + 'Hone', + 'Prejean', + 'Oshiro', + 'Serio', + 'Latour', + 'Newbold', + 'Fitzhugh', + 'Songer', + 'Cardin', + 'Geter', + 'Barbera', + 'Abbas', + 'Caesar', + 'Blakeslee', + 'Camper', + 'Mcclurg', + 'Driskill', + 'Cancel', + 'Donelson', + 'Borrelli', + 'Donoghue', + 'Shoaf', + 'Tinajero', + 'Arzate', + 'Keesee', + 'Pasley', + 'Strode', + 'Morello', + 'Trantham', + 'Ackerson', + 'Jowers', + 'Brockington', + 'Barcia', + 'Lipp', + 'Dinger', + 'Ridings', + 'Canavan', + 'Rank', + 'Hagans', + 'Lampley', + 'Beckmann', + 'Bjork', + 'Raygoza', + 'Schirmer', + 'Longmire', + 'Schiavone', + 'Breuer', + 'Lore', + 'Stenson', + 'Koziol', + 'Channell', + 'Cale', + 'Trader', + 'Culberson', + 'Mundt', + 'Sickles', + 'Nemec', + 'Holl', + 'Stribling', + 'Berens', + 'Nauman', + 'Lehner', + 'Deem', + 'Castelli', + 'Billman', + 'Orndorff', + 'Gumm', + 'Davy', + 'Pelham', + 'Spotts', + 'Jurgens', + 'Sword', + 'Adorno', + 'Gorrell', + 'Boughton', + 'Bobadilla', + 'Mauer', + 'Moline', + 'Guay', + 'Holsinger', + 'Baranowski', + 'Gutierres', + 'Beveridge', + 'Marable', + 'Berkey', + 'Lamothe', + 'Spitler', + 'Carbaugh', + 'Hoopes', + 'Wilken', + 'Milford', + 'Bingaman', + 'Crippen', + 'Shock', + 'Yarnell', + 'Oman', + 'Wethington', + 'Kost', + 'Gaudette', + 'Spielman', + 'Foran', + 'Starke', + 'Eugene', + 'Birnbaum', + 'Navarrette', + 'Hussein', + 'Ranson', + 'Hedgepeth', + 'Doctor', + 'Higuera', + 'Brough', + 'Cookson', + 'Provencher', + 'Mendonca', + 'Gowen', + 'Summer', + 'Rutz', + 'Reader', + 'Doud', + 'Raven', + 'Toribio', + 'Peachey', + 'Gunning', + 'Bittle', + 'Vale', + 'Harnish', + 'Marano', + 'Aker', + 'Damore', + 'Utz', + 'Throckmorton', + 'Bulger', + 'Vanzant', + 'Pasillas', + 'Holmgren', + 'Corpus', + 'Longley', + 'Wetmore', + 'Carstens', + 'Line', + 'Percival', + 'Ayotte', + 'Batres', + 'Pipes', + 'Ludwick', + 'Alpert', + 'Pick', + 'Carlock', + 'Edmundson', + 'Feinstein', + 'Krouse', + 'Dahlgren', + 'Sasaki', + 'Lieb', + 'Londono', + 'Oloughlin', + 'Wardlaw', + 'Lineberry', + 'Castello', + 'Milstead', + 'Parmenter', + 'Riffe', + 'Pare', + 'Sitton', + 'Tarin', + 'Delcastillo', + 'Manor', + 'Calabro', + 'Elkin', + 'Grill', + 'Boaz', + 'Coco', + 'Chamblee', + 'Celestine', + 'Nick', + 'Stork', + 'Meekins', + 'Moise', + 'Devers', + 'Jun', + 'Kegley', + 'Brick', + 'Lobato', + 'Biggerstaff', + 'Kersten', + 'Jayne', + 'Nasser', + 'Southall', + 'Kempton', + 'Eaddy', + 'Paladino', + 'Berardi', + 'Pizzo', + 'Pulver', + 'Ohalloran', + 'Fromm', + 'Cranston', + 'Rowden', + 'Capobianco', + 'Kahle', + 'Thiessen', + 'Malott', + 'Houseman', + 'Maul', + 'Gallion', + 'Tressler', + 'Pauly', + 'Pellerin', + 'Sainz', + 'Firth', + 'Cryer', + 'Jeanlouis', + 'Mong', + 'Trawick', + 'Chronister', + 'Hayashi', + 'Posner', + 'Cueva', + 'Sherwin', + 'Lacasse', + 'Gorden', + 'Bohl', + 'Twigg', + 'Coan', + 'Hocker', + 'Goodale', + 'Urbano', + 'Loeb', + 'Perrault', + 'Frawley', + 'Carcamo', + 'Richburg', + 'Moffat', + 'Hennings', + 'Weyer', + 'Myatt', + 'Ullman', + 'Tunnell', + 'Hern', + 'Lopresti', + 'Sonnenberg', + 'Knisley', + 'Twomey', + 'Jaggers', + 'Tanksley', + 'Rachal', + 'Poppe', + 'Vos', + 'Kania', + 'Speakman', + 'Peirce', + 'Pound', + 'Romer', + 'Patty', + 'Millsaps', + 'Kyser', + 'Telford', + 'Hegarty', + 'Kellett', + 'Michaelis', + 'Halligan', + 'Maughan', + 'Herb', + 'Rainer', + 'Robichaud', + 'Fiscus', + 'Sickler', + 'Blom', + 'Lavine', + 'Medel', + 'Bolyard', + 'Secor', + 'Creekmore', + 'Magruder', + 'Haskin', + 'Laliberte', + 'Drago', + 'Bernabe', + 'Leader', + 'Cavin', + 'Lukens', + 'Vassallo', + 'Pletcher', + 'Fuson', + 'Hasson', + 'Huckabee', + 'Edington', + 'Eichler', + 'Hering', + 'Vong', + 'Mardis', + 'Gu', + 'Segarra', + 'Bilyeu', + 'Runion', + 'Fragoso', + 'Gama', + 'Dunton', + 'Frady', + 'Lewellen', + 'Crumpler', + 'Jeske', + 'Furlow', + 'Delapena', + 'Kale', + 'Massengale', + 'Hamlet', + 'Galli', + 'Esteban', + 'Greeson', + 'Shue', + 'Pollak', + 'Pinney', + 'Ruffner', + 'Maitland', + 'Steven', + 'Hockett', + 'Fraire', + 'Mulhern', + 'Elbert', + 'Hoggard', + 'Labarge', + 'Silcox', + 'Saez', + 'Sluder', + 'Stamp', + 'Darlington', + 'Mccarroll', + 'Pillow', + 'Palazzo', + 'Blaha', + 'Demaria', + 'Swanger', + 'Winningham', + 'Lippincott', + 'Dake', + 'Goldsberry', + 'Seidl', + 'Woolfolk', + 'Murawski', + 'Hobart', + 'Kimber', + 'Nilsson', + 'Stough', + 'Almendarez', + 'Nevels', + 'Fasano', + 'Salmons', + 'Denmark', + 'Lathan', + 'Mosely', + 'Stengel', + 'Mendieta', + 'Felice', + 'Drown', + 'Vidrine', + 'Callihan', + 'Polston', + 'Howze', + 'Eakins', + 'Leek', + 'Featherstone', + 'Lajoie', + 'Athey', + 'Asuncion', + 'Ashbaugh', + 'Orman', + 'Morrissette', + 'Peart', + 'Hamner', + 'Zell', + 'Dry', + 'Dieter', + 'Terrones', + 'Campuzano', + 'Reveles', + 'Bakker', + 'Banister', + 'Arceo', + 'Dhillon', + 'Normand', + 'Shavers', + 'Ginsburg', + 'Go', + 'Rubinstein', + 'Arens', + 'Clutter', + 'Jaques', + 'Traxler', + 'Hackler', + 'Cisco', + 'Starrett', + 'Ceron', + 'Gillenwater', + 'Ottinger', + 'Caster', + 'Blakemore', + 'Thorsen', + 'Molinar', + 'Baur', + 'Hower', + 'Haldeman', + 'Oliveri', + 'Mcalpin', + 'Standish', + 'Bengtson', + 'Strack', + 'Cordoba', + 'Blackstock', + 'Barna', + 'Schantz', + 'Hawkinson', + 'Breese', + 'Saba', + 'Camden', + 'Gwaltney', + 'Corliss', + 'Smit', + 'Cruise', + 'Mcneese', + 'Duggins', + 'Laub', + 'Burman', + 'Kenworthy', + 'Spohn', + 'Santini', + 'Nuttall', + 'Willison', + 'Stjean', + 'Shabazz', + 'Manes', + 'Gerry', + 'Mclamb', + 'Koepke', + 'Reeser', + 'Ogburn', + 'Wegener', + 'Risinger', + 'Carrero', + 'Livermore', + 'Brewton', + 'Harsh', + 'Utterback', + 'Lecompte', + 'Schnabel', + 'Ting', + 'Honea', + 'Stryker', + 'Foshee', + 'Baptista', + 'Gravely', + 'Courson', + 'Goyette', + 'Leitch', + 'Tasker', + 'Laurence', + 'Reneau', + 'Voight', + 'Tilson', + 'Range', + 'Hallam', + 'Dufrene', + 'Boice', + 'Shrewsbury', + 'Sturges', + 'Lenard', + 'Sistrunk', + 'Weitz', + 'Carnevale', + 'Hepner', + 'Wehner', + 'Callen', + 'Oshaughnessy', + 'Wingert', + 'Mouser', + 'Palmore', + 'Rugg', + 'Elia', + 'Alcazar', + 'Avitia', + 'Penton', + 'Brisco', + 'Ambrosio', + 'Wardlow', + 'Leaf', + 'Rowles', + 'Buggs', + 'Dittmer', + 'Schweizer', + 'Puleo', + 'Vaden', + 'Haughton', + 'Cardinale', + 'Seguin', + 'Ruddy', + 'Minard', + 'Stalker', + 'Bennington', + 'Hilt', + 'Works', + 'Broadus', + 'Engels', + 'Haddix', + 'Buster', + 'Recker', + 'Bopp', + 'Wilton', + 'Costantino', + 'Boots', + 'Falkner', + 'Tennison', + 'Mcgary', + 'Holz', + 'Lofgren', + 'Putney', + 'Christner', + 'Fruge', + 'Vassar', + 'Vankirk', + 'Spoon', + 'Pearlman', + 'Guertin', + 'Meece', + 'Sartain', + 'Petterson', + 'Primm', + 'Cardillo', + 'Dryer', + 'Hartshorn', + 'Dane', + 'Chaisson', + 'Espitia', + 'Creager', + 'Disalvo', + 'Janik', + 'Parente', + 'Paiva', + 'Slaven', + 'Tague', + 'Kujawa', + 'Gruver', + 'Foor', + 'Frampton', + 'Prokop', + 'Mettler', + 'Collis', + 'Lamkin', + 'Shuey', + 'Tepper', + 'Colyer', + 'Masi', + 'Trumble', + 'Guice', + 'Hurwitz', + 'Windle', + 'Mccully', + 'Cutting', + 'Stotler', + 'Grullon', + 'Wagstaff', + 'Morfin', + 'Dehaan', + 'Noon', + 'Flesher', + 'Ferri', + 'Covell', + 'Coll', + 'Lucy', + 'Albaugh', + 'Testerman', + 'Gordillo', + 'Jepson', + 'Brinkerhoff', + 'Calle', + 'Crowl', + 'Mcelwain', + 'Chumley', + 'Brockett', + 'Thoms', + 'Revell', + 'Garzon', + 'Polak', + 'Rothenberg', + 'Socha', + 'Vallejos', + 'Felty', + 'Peguero', + 'Ping', + 'Tso', + 'Charleston', + 'Fedor', + 'Haider', + 'Abe', + 'Enlow', + 'Fifer', + 'Bumpus', + 'Keele', + 'Mcdavid', + 'Panek', + 'Scholten', + 'Dyess', + 'Heatherly', + 'Donohoe', + 'Hoban', + 'Griffey', + 'Corry', + 'Mcclean', + 'Plyler', + 'Feathers', + 'Adkison', + 'Killeen', + 'Hoeft', + 'Myhre', + 'Fiorentino', + 'Mcbeth', + 'Erazo', + 'Madson', + 'Fulbright', + 'Wilds', + 'Petrucci', + 'Mcgaughey', + 'Monteith', + 'Murguia', + 'Hausman', + 'Zukowski', + 'Shute', + 'Brisson', + 'Lain', + 'Runkle', + 'Hickok', + 'Caffrey', + 'Million', + 'Elson', + 'Peay', + 'Haga', + 'Ancheta', + 'Cordle', + 'Blas', + 'Carmen', + 'Pettiford', + 'Dimartino', + 'Spahr', + 'Mozingo', + 'Backman', + 'Stgeorge', + 'Konrad', + 'Buhler', + 'Mcelrath', + 'Oliveros', + 'Edelstein', + 'Cadet', + 'Gilmartin', + 'Munday', + 'Roane', + 'Desalvo', + 'Lepe', + 'Symons', + 'Shearin', + 'Linkous', + 'Cheshire', + 'Klemm', + 'Beagle', + 'Pooler', + 'Dewalt', + 'Esch', + 'Finnell', + 'Sinnott', + 'Kepler', + 'Toups', + 'Riccardi', + 'Caylor', + 'Tillis', + 'Messmer', + 'Rothschild', + 'Boutte', + 'Zumwalt', + 'Bohrer', + 'Elgin', + 'Kinley', + 'Schechter', + 'Gowan', + 'Pyne', + 'Cousin', + 'Hunsinger', + 'Fishel', + 'Edenfield', + 'Nadler', + 'Warman', + 'Bruhn', + 'Swint', + 'Lizotte', + 'Nardone', + 'Troxel', + 'Grindle', + 'Labrie', + 'Tao', + 'Olea', + 'Schermerhorn', + 'Stier', + 'Hettinger', + 'Farthing', + 'Roux', + 'Max', + 'Amburgey', + 'Auerbach', + 'Janzen', + 'Ortez', + 'Alejandre', + 'Peiffer', + 'Molinaro', + 'Burleigh', + 'Benites', + 'Ringler', + 'Hou', + 'Haffner', + 'Nace', + 'Crosson', + 'Karcher', + 'Neufeld', + 'Bayles', + 'Riemer', + 'Amezquita', + 'Cadwell', + 'Petrosky', + 'Swallow', + 'Minnis', + 'Krupp', + 'Nardi', + 'Orsini', + 'Diez', + 'Updike', + 'Gasser', + 'Rogerson', + 'Speicher', + 'Dubay', + 'Hollaway', + 'Teets', + 'Keown', + 'Center', + 'Blanding', + 'Whisler', + 'Spurlin', + 'Collin', + 'Greenawalt', + 'Tomes', + 'Leister', + 'Chatfield', + 'Helwig', + 'Reimers', + 'Andress', + 'Norcross', + 'Melnick', + 'Yearwood', + 'Defazio', + 'Kubik', + 'Bhatia', + 'Uddin', + 'Belmont', + 'Haden', + 'Bench', + 'Chilson', + 'Pegg', + 'Cane', + 'Goehring', + 'Lino', + 'Tyus', + 'Furey', + 'Castleman', + 'Heywood', + 'Leedy', + 'Holleman', + 'Villeda', + 'Mcveigh', + 'Carreiro', + 'Hocking', + 'Azar', + 'Blough', + 'Lieu', + 'Marcial', + 'Coblentz', + 'Hossain', + 'Weisberg', + 'Gardea', + 'Hoyos', + 'Lipsey', + 'Reger', + 'Clouser', + 'Bewley', + 'Magness', + 'Goines', + 'Thome', + 'Odea', + 'Mannion', + 'Dansby', + 'Dipasquale', + 'Constable', + 'Truelove', + 'Hubler', + 'Ulibarri', + 'Wymer', + 'Cron', + 'Hugo', + 'Hilderbrand', + 'Milazzo', + 'Vasques', + 'Sproul', + 'Shuford', + 'Chavers', + 'Kral', + 'Vecchio', + 'Mehl', + 'Rymer', + 'Henriksen', + 'Taulbee', + 'Hagy', + 'Ammerman', + 'Kagan', + 'Galdamez', + 'Krick', + 'Owsley', + 'Mullikin', + 'Beery', + 'Eccles', + 'Kleinschmidt', + 'Kloss', + 'Oldenburg', + 'Ospina', + 'Harbert', + 'Andujar', + 'Florian', + 'Antone', + 'Mcmillon', + 'Ceniceros', + 'Rippy', + 'Adkisson', + 'Stange', + 'Balmer', + 'Mazurek', + 'Dahlke', + 'Girouard', + 'Nickelson', + 'Perera', + 'Tullos', + 'Cioffi', + 'Bogdan', + 'Olivieri', + 'Petree', + 'Speights', + 'Jantz', + 'Collings', + 'Zellers', + 'Yarber', + 'Lafollette', + 'Rink', + 'Currin', + 'Chua', + 'Hartle', + 'Larocque', + 'Cuthbertson', + 'Ehrhardt', + 'Mara', + 'Rieck', + 'Lumley', + 'Anderton', + 'Hennigan', + 'Fabrizio', + 'Hutter', + 'Bruning', + 'Korman', + 'Haring', + 'Monette', + 'Woodyard', + 'Goggins', + 'Balzer', + 'Philbrick', + 'Bruder', + 'Hansford', + 'Averett', + 'Teske', + 'Mauck', + 'Billiot', + 'Collie', + 'Caffey', + 'Manos', + 'Buchan', + 'Birk', + 'Abdallah', + 'Featherston', + 'Koh', + 'Valera', + 'Deyo', + 'Buono', + 'Aubin', + 'Doody', + 'Pigott', + 'Peloquin', + 'Maniscalco', + 'Eisenhauer', + 'Biller', + 'Farwell', + 'Hartzog', + 'Brazier', + 'Talton', + 'Mcdougald', + 'Midgett', + 'Strout', + 'Spiers', + 'Eiland', + 'Garth', + 'Sequeira', + 'Noyola', + 'Petri', + 'Goodyear', + 'Dineen', + 'Bernardi', + 'Berns', + 'Coolidge', + 'Dorfman', + 'Dittman', + 'Zeno', + 'Hauer', + 'Finlay', + 'Ziemba', + 'Spillane', + 'Kays', + 'Ekstrom', + 'Hile', + 'Mckinstry', + 'Lesley', + 'Courtright', + 'Kuhlmann', + 'Verma', + 'Cripps', + 'Wigley', + 'Nickens', + 'Petrick', + 'Delozier', + 'Hardcastle', + 'Yamaguchi', + 'Romig', + 'Venezia', + 'Reading', + 'Redford', + 'Heng', + 'Anselmo', + 'Getty', + 'Marten', + 'Badgett', + 'Eisner', + 'Holtzman', + 'Stell', + 'Hiser', + 'Dustin', + 'Bordeaux', + 'Debolt', + 'Trevizo', + 'Eckard', + 'Follett', + 'Lal', + 'Dark', + 'Buskirk', + 'Roca', + 'Todaro', + 'Campanella', + 'Lindsley', + 'Wickman', + 'Pritt', + 'Cutlip', + 'Pokorny', + 'Friedlander', + 'Saari', + 'Casias', + 'Macneil', + 'Clyburn', + 'Kravitz', + 'Edgington', + 'Portis', + 'Culbreth', + 'Cuff', + 'Brouillette', + 'Artz', + 'Trudell', + 'Pledger', + 'Markovich', + 'Pisani', + 'Faller', + 'Sergent', + 'Hail', + 'Stabile', + 'Wait', + 'Mcilwain', + 'Eriksen', + 'Nee', + 'Boll', + 'Catanzaro', + 'Giuliano', + 'Oldfield', + 'Banas', + 'Ickes', + 'Vachon', + 'Gleeson', + 'Bailes', + 'Biehl', + 'Woodham', + 'Troupe', + 'Mcgoldrick', + 'Cappello', + 'Kirkendall', + 'Baisden', + 'Joshua', + 'Nicoletti', + 'Roesch', + 'Deatherage', + 'Matter', + 'Sheth', + 'Tynes', + 'Shaheen', + 'Wilbert', + 'Toles', + 'Sanner', + 'Bury', + 'Boman', + 'Bose', + 'Millner', + 'Eisen', + 'Couto', + 'Ide', + 'Howells', + 'Jiminez', + 'Crampton', + 'Monti', + 'Jelinek', + 'Morford', + 'Yeomans', + 'Turnbow', + 'Rolland', + 'Scheetz', + 'Arends', + 'Repp', + 'Hohn', + 'Paton', + 'Govan', + 'Fabela', + 'Mroz', + 'Bourassa', + 'Rizzi', + 'Froelich', + 'Molinari', + 'Lunde', + 'Navarre', + 'Alexandre', + 'Dearborn', + 'Lakes', + 'Foxx', + 'Jerez', + 'Lamanna', + 'Talarico', + 'Butera', + 'Riner', + 'Gros', + 'Champ', + 'Phoenix', + 'Vandeventer', + 'Samora', + 'Behling', + 'Karpinski', + 'Hosier', + 'Tufts', + 'Hobby', + 'Rohrbach', + 'Youngman', + 'Yeary', + 'Paisley', + 'Ben', + 'Villalta', + 'Hempel', + 'Giblin', + 'Lunt', + 'Hagar', + 'Lapoint', + 'Singley', + 'Shows', + 'Kesterson', + 'Bollman', + 'Stansell', + 'Yon', + 'Gabaldon', + 'Simental', + 'Zastrow', + 'Enloe', + 'Sasso', + 'Harkey', + 'Sansom', + 'Twyman', + 'Haslam', + 'Sowa', + 'Hunsberger', + 'Norberg', + 'Hornback', + 'Hanshaw', + 'Axtell', + 'Hoge', + 'Gantz', + 'Mccullum', + 'Blazek', + 'Scher', + 'Carlucci', + 'Jeong', + 'Tillett', + 'Woolridge', + 'Carberry', + 'Reck', + 'Nevin', + 'Armes', + 'Sidhu', + 'Wiesner', + 'Auman', + 'Teeters', + 'Rigg', + 'Moloney', + 'Feld', + 'Lucier', + 'Cardone', + 'Kilian', + 'Conder', + 'Horta', + 'Murakami', + 'Schaff', + 'Dresser', + 'Spray', + 'Hott', + 'Capuano', + 'Englund', + 'Rothe', + 'Ferree', + 'Nolt', + 'Triana', + 'Sanjuan', + 'Oller', + 'Brathwaite', + 'Richert', + 'Holdren', + 'Goree', + 'Branstetter', + 'Schimmel', + 'Jessop', + 'Nellis', + 'Sevier', + 'Rabb', + 'Mcmorris', + 'Lindo', + 'Littles', + 'Polzin', + 'Ranieri', + 'Reale', + 'Sturtevant', + 'Arnone', + 'Zamorano', + 'Keever', + 'Clow', + 'Corr', + 'Blaser', + 'Sheetz', + 'Llanos', + 'Belew', + 'Rusnak', + 'Brandes', + 'Eichhorn', + 'Guida', + 'Pucci', + 'Streit', + 'Renn', + 'Partee', + 'Rappaport', + 'Rosso', + 'Defeo', + 'Greve', + 'Schoch', + 'Langevin', + 'Manna', + 'Towe', + 'Scoville', + 'Marco', + 'Gove', + 'Mckissick', + 'Dangerfield', + 'Mcwhirter', + 'Port', + 'Marrufo', + 'Nicosia', + 'Farren', + 'Kinsley', + 'Pearman', + 'Porch', + 'Mooneyham', + 'Buff', + 'Ruben', + 'Blanc', + 'Mellen', + 'Heiman', + 'Novack', + 'Heston', + 'Huie', + 'Justin', + 'Kincade', + 'Laverty', + 'Villavicencio', + 'Burkart', + 'Offutt', + 'Halliburton', + 'Polo', + 'Barbara', + 'Trammel', + 'Rosati', + 'Sakamoto', + 'Salo', + 'Heyman', + 'Rooker', + 'Sarno', + 'Leroux', + 'Virgen', + 'Collison', + 'Branum', + 'Mcmasters', + 'Divine', + 'Mcnatt', + 'Threadgill', + 'Desir', + 'Borchers', + 'Walkup', + 'Sy', + 'Greenbaum', + 'Vidales', + 'Mercedes', + 'Selph', + 'Bardwell', + 'Whorton', + 'Demartino', + 'Endsley', + 'Verner', + 'Hillier', + 'Mancha', + 'Ricard', + 'Postell', + 'Kummer', + 'Welsch', + 'Almanzar', + 'Brunet', + 'Deeds', + 'Romanowski', + 'Ocallaghan', + 'Cueto', + 'Terhune', + 'Truesdell', + 'Whisnant', + 'Lingo', + 'Aden', + 'Labrecque', + 'Braga', + 'Iles', + 'Garrick', + 'Knickerbocker', + 'Rasberry', + 'Hervey', + 'Schill', + 'Kiely', + 'Liddle', + 'Blakeley', + 'Marez', + 'Schoonmaker', + 'Swinton', + 'Fryar', + 'Exum', + 'Gouge', + 'Hoskinson', + 'Lupton', + 'Guild', + 'Davisson', + 'Chidester', + 'Gravitt', + 'Lenox', + 'Pyatt', + 'Moberg', + 'Overholt', + 'Whiddon', + 'Foti', + 'Lipps', + 'Shankle', + 'Xiao', + 'Balentine', + 'Cesar', + 'Barreras', + 'Schroer', + 'Ram', + 'Eames', + 'Gutman', + 'Pardee', + 'Damiano', + 'Houchin', + 'Porto', + 'Leclerc', + 'Mahaney', + 'Deardorff', + 'Garey', + 'Trotta', + 'Lachapelle', + 'Suiter', + 'Ewert', + 'Costner', + 'Bever', + 'Charpentier', + 'Milewski', + 'Coffelt', + 'Schorr', + 'Leis', + 'Dasher', + 'Cullins', + 'Eveland', + 'Hornung', + 'Swingle', + 'Eudy', + 'Motter', + 'Silk', + 'Gadd', + 'Sidwell', + 'Sandusky', + 'Auld', + 'Mazariegos', + 'Hirt', + 'Zane', + 'Rickett', + 'Ritenour', + 'Goin', + 'Dipaolo', + 'Wolfgang', + 'Inouye', + 'Branton', + 'Rakestraw', + 'Kimbro', + 'Craighead', + 'Sandefur', + 'Foerster', + 'Wipf', + 'Wilkin', + 'Shoffner', + 'Overcash', + 'Simonetti', + 'Toomer', + 'Albino', + 'Eshelman', + 'Rockwood', + 'Pineiro', + 'Reames', + 'Cray', + 'Wulff', + 'Heider', + 'Bath', + 'Colletti', + 'Fiala', + 'Greenstein', + 'Moles', + 'Bashaw', + 'Adamczyk', + 'Finkel', + 'Kistner', + 'Manzi', + 'Ferretti', + 'Demarest', + 'Ahlers', + 'Lack', + 'Wedel', + 'Kinzer', + 'Sechrist', + 'Stickler', + 'Easterday', + 'Mallette', + 'Loehr', + 'Gessner', + 'Croce', + 'Stanko', + 'Innes', + 'Farfan', + 'Heady', + 'Chambless', + 'Balbuena', + 'Decicco', + 'Winsor', + 'Pereyra', + 'Zoller', + 'Ingles', + 'Churchwell', + 'Westlake', + 'Villagran', + 'Soderberg', + 'Thill', + 'Timmer', + 'Mccaleb', + 'Mckernan', + 'Vandergriff', + 'Yoho', + 'Crispin', + 'Dorton', + 'Fults', + 'Borne', + 'Maxie', + 'Bloomquist', + 'Kung', + 'Budde', + 'Weinstock', + 'Honey', + 'Diener', + 'Horak', + 'Tsui', + 'Zirkle', + 'Plum', + 'Heitz', + 'Manrique', + 'Balcom', + 'Napper', + 'Boese', + 'Stefan', + 'Kime', + 'Gautreaux', + 'Leverette', + 'Lemaire', + 'Danford', + 'Hollman', + 'Kuzma', + 'Swinehart', + 'Merriam', + 'Novick', + 'Stankiewicz', + 'Parkes', + 'Englehart', + 'Polansky', + 'Leclaire', + 'Magner', + 'Masson', + 'Mass', + 'Coogan', + 'Jepsen', + 'Pittenger', + 'Bump', + 'Hain', + 'Burchell', + 'Chesley', + 'Cawthon', + 'Dance', + 'Piccolo', + 'Lucey', + 'Ordway', + 'Recio', + 'Ginther', + 'Hauge', + 'Lesperance', + 'Suhr', + 'Ding', + 'Ogg', + 'Skiba', + 'Scannell', + 'Gillies', + 'Brame', + 'Schipper', + 'Brune', + 'Stuber', + 'Pesce', + 'Stead', + 'Bushong', + 'Juneau', + 'Mccalla', + 'Feder', + 'Plaisance', + 'Tweed', + 'Hashimoto', + 'Mounce', + 'Diana', + 'Savala', + 'Vanek', + 'Lamson', + 'Dubin', + 'Killebrew', + 'Kan', + 'Nault', + 'Mulford', + 'Salamanca', + 'Linker', + 'Penrose', + 'Kowalewski', + 'Platz', + 'Kogan', + 'Martucci', + 'Gutowski', + 'Mattes', + 'Haigh', + 'Merida', + 'Ashman', + 'Batton', + 'Biondo', + 'Sweigart', + 'Sorg', + 'Barrier', + 'Gatling', + 'Geib', + 'Henrich', + 'Dabrowski', + 'Vara', + 'Weikel', + 'Jarosz', + 'Mummert', + 'Uriarte', + 'Fifield', + 'Locker', + 'Merlo', + 'Lasater', + 'Ripple', + 'Hopwood', + 'Sherrell', + 'Ruark', + 'Litz', + 'Kinkade', + 'Simkins', + 'Grandy', + 'Lemasters', + 'Wehr', + 'Jinks', + 'Alas', + 'Bale', + 'Stimpson', + 'Glickman', + 'Hage', + 'Seabrook', + 'Stirling', + 'Rozell', + 'Woodburn', + 'Braaten', + 'Sugg', + 'Linde', + 'Castille', + 'Grewal', + 'Blackwelder', + 'Hover', + 'Spurling', + 'Mckellar', + 'Muench', + 'Bovee', + 'Amado', + 'Yau', + 'Harger', + 'Lederer', + 'Seda', + 'Doney', + 'Kimes', + 'Western', + 'Foret', + 'Luera', + 'Warnke', + 'Bussard', + 'Cartier', + 'Andreasen', + 'Lagasse', + 'Topper', + 'Nyman', + 'Hallberg', + 'Whisman', + 'Cremeans', + 'Dewar', + 'Garrow', + 'Odaniel', + 'Stabler', + 'Bourg', + 'Appling', + 'Dahlstrom', + 'Fujimoto', + 'Prudhomme', + 'Gum', + 'Nau', + 'Hiers', + 'Rockett', + 'Sobczak', + 'Traub', + 'Bevis', + 'Tilghman', + 'Plasencia', + 'Sison', + 'Blau', + 'Abbate', + 'Sisler', + 'Rudder', + 'Trotman', + 'Brust', + 'Lederman', + 'Frahm', + 'Fredette', + 'Parise', + 'Urso', + 'Amann', + 'Kaul', + 'Woolery', + 'Thielen', + 'Symonds', + 'Marcy', + 'Wiltshire', + 'Sustaita', + 'Botkin', + 'Kernan', + 'Doolin', + 'Babineaux', + 'Greenspan', + 'Delacerda', + 'Kinnard', + 'Twitty', + 'Augustus', + 'Corriveau', + 'Stults', + 'Toman', + 'Sklar', + 'Leber', + 'Considine', + 'Ohearn', + 'Deforest', + 'Mcmann', + 'Farquhar', + 'Ferrel', + 'Bickley', + 'Manno', + 'Vreeland', + 'Berthiaume', + 'Mcentee', + 'Summerfield', + 'Woodrow', + 'Reynaga', + 'Soltero', + 'Tomko', + 'Jarboe', + 'Allmon', + 'Duplessis', + 'Sydnor', + 'Diallo', + 'Cogar', + 'Mandeville', + 'Shimizu', + 'Aubuchon', + 'Gabbert', + 'Ashlock', + 'Macri', + 'Weng', + 'Walser', + 'Teng', + 'Bailon', + 'Steeves', + 'Perillo', + 'Quattlebaum', + 'Knipp', + 'Delavega', + 'Kirtley', + 'Bramble', + 'Sublett', + 'Borchert', + 'Doria', + 'Session', + 'Merced', + 'Lundstrom', + 'Bluhm', + 'Cortinas', + 'Proper', + 'Sieber', + 'Mccay', + 'Wilford', + 'Asberry', + 'Muldrow', + 'Berning', + 'Hemenway', + 'Millman', + 'Ewers', + 'Timko', + 'Reding', + 'Sayer', + 'Pickel', + 'Cogburn', + 'Chappel', + 'Custodio', + 'Reichel', + 'Robeson', + 'Waid', + 'Wagler', + 'Sappington', + 'Bart', + 'Zazueta', + 'Najar', + 'Marko', + 'Nally', + 'States', + 'Bellard', + 'Marciano', + 'Killough', + 'Cosper', + 'Sangster', + 'Heinze', + 'Bortz', + 'Matamoros', + 'Nuckols', + 'Townsley', + 'Bak', + 'Ralls', + 'Ferrin', + 'Villela', + 'Siegrist', + 'Arora', + 'Collinsworth', + 'Masten', + 'Deer', + 'Balog', + 'Buchman', + 'Scaggs', + 'Holeman', + 'Lefkowitz', + 'Santora', + 'Funke', + 'Redfield', + 'Douthit', + 'Marciniak', + 'Twitchell', + 'Sheahan', + 'Dai', + 'Demuth', + 'Ganz', + 'Bruckner', + 'Wier', + 'Alamo', + 'Aultman', + 'Chubb', + 'Branco', + 'Courter', + 'Vivian', + 'Guin', + 'Witten', + 'Glen', + 'Hyer', + 'Crowson', + 'Arendt', + 'Cipolla', + 'Prochaska', + 'Schober', + 'Harte', + 'Arciniega', + 'Beier', + 'Middlebrook', + 'Dennard', + 'Vantassel', + 'Weekes', + 'Penley', + 'Lozier', + 'Lamberson', + 'Broomfield', + 'Nygaard', + 'Pascale', + 'Hyden', + 'Mundell', + 'Kamara', + 'Ehlert', + 'Mangus', + 'Bornstein', + 'Benedetti', + 'Erikson', + 'Quint', + 'Westman', + 'Basler', + 'Smoak', + 'Leavell', + 'Kerber', + 'Kopec', + 'Emrick', + 'Mattice', + 'Render', + 'Mccree', + 'Feldmann', + 'Cutright', + 'Randell', + 'Drucker', + 'Gilmour', + 'Marconi', + 'Stripling', + 'Mucha', + 'Shipe', + 'Chalk', + 'Martone', + 'Lema', + 'Ricardo', + 'Cobian', + 'Laufer', + 'Mistretta', + 'Shortt', + 'Menzel', + 'Wickline', + 'Oddo', + 'Chai', + 'Rabideau', + 'Stogner', + 'Mckie', + 'Luongo', + 'Trieu', + 'Breshears', + 'Sturdevant', + 'Abernethy', + 'Rohan', + 'Bonnette', + 'Steffes', + 'Straka', + 'Lawhon', + 'Shawver', + 'Guilford', + 'Wiltz', + 'Digregorio', + 'Warburton', + 'Fleshman', + 'Kerstetter', + 'Byram', + 'Obannon', + 'Dalessio', + 'Gatti', + 'Kalb', + 'Boris', + 'Graver', + 'Parkins', + 'Kollar', + 'Crothers', + 'Patin', + 'Cutshall', + 'Fern', + 'Derosier', + 'Goodrum', + 'Kaelin', + 'Baynes', + 'Beesley', + 'Macintyre', + 'Butters', + 'Kinsman', + 'Huffer', + 'Eslinger', + 'Prunty', + 'Boehmer', + 'Nusbaum', + 'Gouveia', + 'Mire', + 'Mccary', + 'Mikell', + 'Petrovich', + 'Melillo', + 'Kennelly', + 'Howley', + 'Merwin', + 'Cotner', + 'Kanter', + 'Sahagun', + 'Bodden', + 'Mcconville', + 'Leddy', + 'Auten', + 'Downie', + 'Armistead', + 'Goudy', + 'Gerhard', + 'Theiss', + 'Lauria', + 'Tuthill', + 'Ammon', + 'Ikeda', + 'Schultheis', + 'Zhong', + 'Pearcy', + 'Vass', + 'Essary', + 'Wendland', + 'Zehr', + 'Hartigan', + 'Ugalde', + 'Mossman', + 'Hartwick', + 'Joaquin', + 'Andreas', + 'Bartee', + 'Gajewski', + 'Gallaway', + 'Comerford', + 'Lieber', + 'Wireman', + 'Damm', + 'Yousif', + 'Kosinski', + 'Kelm', + 'Durrant', + 'Derouen', + 'Bonk', + 'Rubalcaba', + 'Opperman', + 'Decamp', + 'Fairfield', + 'Pauls', + 'Dicicco', + 'Northup', + 'Woerner', + 'Stegman', + 'Ritch', + 'Bedoya', + 'Jeanpierre', + 'Rioux', + 'Strohl', + 'Herrell', + 'Simonton', + 'Carriere', + 'Pridemore', + 'Karam', + 'Marple', + 'Topp', + 'Heiden', + 'Leibowitz', + 'Morabito', + 'Junker', + 'Calixto', + 'Hardt', + 'Silverio', + 'Swords', + 'Rickey', + 'Roussel', + 'Earles', + 'Bastien', + 'Defilippo', + 'Bigley', + 'Mosteller', + 'Issa', + 'Prout', + 'Grossi', + 'Bartos', + 'Lipman', + 'Colegrove', + 'Stpeter', + 'Vanfleet', + 'Fordyce', + 'Risher', + 'Royston', + 'Shoulders', + 'Mendel', + 'Statler', + 'Dantonio', + 'Inglis', + 'Fogleman', + 'Loveday', + 'Straus', + 'Luft', + 'Dam', + 'Chewning', + 'Winkel', + 'Bousquet', + 'Eckhart', + 'Dillinger', + 'Locascio', + 'Shellenberger', + 'Duerr', + 'Alcocer', + 'Licht', + 'Gingras', + 'Grassi', + 'Gately', + 'Padula', + 'Brien', + 'Nimmo', + 'Nell', + 'Bondurant', + 'Hughley', + 'Schalk', + 'Cabrales', + 'Heinemann', + 'Meunier', + 'Maddock', + 'Noone', + 'Brackin', + 'Dunnigan', + 'Sargeant', + 'Kinchen', + 'Veras', + 'Gile', + 'Bacchus', + 'Ang', + 'Cowgill', + 'Currey', + 'Garlick', + 'Manus', + 'Ballance', + 'Robitaille', + 'Begin', + 'Mijares', + 'Keogh', + 'Wicklund', + 'Mccurley', + 'Truett', + 'Pullin', + 'Alkire', + 'Loughran', + 'Mort', + 'Tatman', + 'Wanamaker', + 'Haralson', + 'Harrah', + 'Stucker', + 'Reda', + 'Pascal', + 'Holter', + 'Solares', + 'Bruck', + 'Mah', + 'Didomenico', + 'Korth', + 'Virgil', + 'Nishimura', + 'Vacca', + 'Stenberg', + 'Tomczak', + 'Sayler', + 'Chasse', + 'Blazer', + 'Sleeper', + 'Doiron', + 'Nunnery', + 'Ortman', + 'Maag', + 'Cali', + 'Ferrera', + 'Hotaling', + 'Festa', + 'Murr', + 'Sterrett', + 'Cuthbert', + 'Clayborn', + 'Pendergraft', + 'Yoakum', + 'Baily', + 'Overbey', + 'Warne', + 'Hokanson', + 'Tafolla', + 'Puglisi', + 'Wooster', + 'Nassar', + 'Lesniak', + 'Noack', + 'Beres', + 'Liberatore', + 'Guyette', + 'Duffin', + 'Ishmael', + 'Dolezal', + 'Larimer', + 'Musso', + 'Borman', + 'Deemer', + 'Hobgood', + 'Triggs', + 'Mau', + 'Wainscott', + 'Seth', + 'Hodnett', + 'Mckeehan', + 'Toon', + 'Evens', + 'Drost', + 'Roehl', + 'Trapani', + 'Bains', + 'Modica', + 'Arcos', + 'Knopf', + 'Salvo', + 'Garlock', + 'Lounsbury', + 'Hennen', + 'Drescher', + 'Morgenstern', + 'Studebaker', + 'Nordin', + 'Madore', + 'Joslyn', + 'Brousseau', + 'Addy', + 'Audette', + 'Santibanez', + 'Sauers', + 'Engelman', + 'Mauney', + 'Arechiga', + 'Eckel', + 'Jerry', + 'Pernell', + 'Sedlacek', + 'Mcnary', + 'Loewen', + 'Eyler', + 'Feather', + 'Mckinnie', + 'Bowersox', + 'Laclair', + 'Melby', + 'Thoman', + 'Hose', + 'Carmon', + 'Bartram', + 'Berggren', + 'Rogge', + 'Seto', + 'Court', + 'Deskins', + 'Barcus', + 'Putt', + 'Minick', + 'Durgin', + 'Hockman', + 'Keltner', + 'Legaspi', + 'Wallach', + 'Ranney', + 'Borger', + 'Wakeman', + 'Schoolcraft', + 'Souther', + 'Villani', + 'Sauder', + 'Chupp', + 'Slover', + 'Faul', + 'Degroat', + 'Hakim', + 'Brucker', + 'Moylan', + 'Castilleja', + 'Whetzel', + 'Eanes', + 'Brouwer', + 'Okelley', + 'Crimmins', + 'Bargas', + 'Jo', + 'Clover', + 'Adan', + 'Domingues', + 'Yelton', + 'Lobdell', + 'Mattis', + 'Escudero', + 'Pentecost', + 'Riser', + 'Lorentz', + 'Neace', + 'Caplinger', + 'Lipe', + 'Satterlee', + 'Labarbera', + 'Cullison', + 'Goggin', + 'Coke', + 'Keo', + 'Buckmaster', + 'Holtzclaw', + 'Lustig', + 'Ellinger', + 'Lollar', + 'Cork', + 'Mccrae', + 'Hilario', + 'Yawn', + 'Arnette', + 'Yuhas', + 'Wardle', + 'Pixley', + 'Leflore', + 'Fluker', + 'Krier', + 'Wind', + 'Ditto', + 'Rorie', + 'Ensminger', + 'Hunsucker', + 'Levenson', + 'Millington', + 'Gorsuch', + 'Willems', + 'Fredricks', + 'Agarwal', + 'Lariviere', + 'Don', + 'Chery', + 'Pfeil', + 'Wurtz', + 'Remillard', + 'Cozad', + 'Hodgkins', + 'Cohan', + 'Nurse', + 'Espana', + 'Giguere', + 'Hoskin', + 'Pettaway', + 'Keifer', + 'Yandell', + 'Frandsen', + 'Nawrocki', + 'Vila', + 'Pouliot', + 'Boulanger', + 'Pruden', + 'Strauch', + 'Lua', + 'Rohn', + 'Greig', + 'Lightsey', + 'Etheredge', + 'Hara', + 'Ensign', + 'Ruckman', + 'Senecal', + 'Sedgwick', + 'Maciejewski', + 'Morningstar', + 'Creswell', + 'Britten', + 'Godley', + 'Laubach', + 'Schwenk', + 'Hayhurst', + 'Cammarata', + 'Paxson', + 'Mcmurtry', + 'Marasco', + 'Weatherby', + 'Fales', + 'Fondren', + 'Deherrera', + 'Gaydos', + 'Defranco', + 'Bjorklund', + 'Silberman', + 'Maxon', + 'Rockey', + 'Brass', + 'Marcoux', + 'Marquette', + 'Marcello', + 'Veit', + 'Debose', + 'Cloninger', + 'Puccio', + 'Greenman', + 'Bross', + 'Lile', + 'Behan', + 'Plumlee', + 'Hampson', + 'Steverson', + 'Wininger', + 'Mcmullan', + 'Jude', + 'Sharif', + 'Rothermel', + 'Becher', + 'Keithley', + 'Gargano', + 'Morillo', + 'Dumond', + 'Johannsen', + 'Baney', + 'Lipton', + 'Railey', + 'Clowers', + 'Rotondo', + 'Simeone', + 'Hatt', + 'Schexnayder', + 'Snoddy', + 'Gelinas', + 'Mendelson', + 'Matherly', + 'Klock', + 'Clubb', + 'Dunkley', + 'Rosenzweig', + 'Chuang', + 'Gines', + 'Galasso', + 'Helland', + 'Rohrbaugh', + 'Avilez', + 'Czajkowski', + 'Olsson', + 'Lumsden', + 'Birt', + 'Ortego', + 'Acuff', + 'Yetter', + 'Tichenor', + 'Mork', + 'Skillman', + 'Row', + 'Lollis', + 'Wolk', + 'Demott', + 'Lazenby', + 'Bellew', + 'Brickner', + 'Ragusa', + 'Stice', + 'Herlihy', + 'Guillermo', + 'Estabrook', + 'Montijo', + 'Jenner', + 'Rayfield', + 'Donlon', + 'Greenhalgh', + 'Alberti', + 'Rix', + 'Holthaus', + 'Mistry', + 'Ruzicka', + 'Sievert', + 'Koopman', + 'Kalish', + 'Kehl', + 'Ponte', + 'Varnell', + 'Guss', + 'Kovac', + 'Hosmer', + 'Scrivner', + 'Tomblin', + 'Villafuerte', + 'Branscum', + 'Nitz', + 'Reider', + 'Gaunt', + 'Richerson', + 'Hemmer', + 'Vinyard', + 'Barrie', + 'Manalo', + 'Flynt', + 'Cadle', + 'Hau', + 'Uy', + 'Manfredi', + 'Deeter', + 'Resto', + 'Carnell', + 'Drane', + 'Cusumano', + 'Fein', + 'Schneck', + 'Stucky', + 'Heid', + 'Bruggeman', + 'Schweiger', + 'Vanetten', + 'Munsey', + 'Kiker', + 'Whittier', + 'Seeman', + 'Zerbe', + 'Hillyer', + 'Burkhead', + 'Gafford', + 'Gephart', + 'Braman', + 'Plott', + 'Henriques', + 'Coppock', + 'Mcandrews', + 'Valtierra', + 'Dileo', + 'Stiner', + 'Mikel', + 'Owensby', + 'Gupton', + 'Scurlock', + 'Gittens', + 'Degnan', + 'Guillaume', + 'Helmuth', + 'Nolin', + 'Mair', + 'Bergeson', + 'Paik', + 'Kinne', + 'Goodloe', + 'Nakagawa', + 'Raposo', + 'Defreitas', + 'Korb', + 'Hinkel', + 'Magers', + 'Althoff', + 'Rafael', + 'Akhtar', + 'Cashion', + 'Mcquillan', + 'Patricio', + 'Sweeny', + 'Meaux', + 'Tyre', + 'Demeo', + 'Trivedi', + 'Goodfellow', + 'Dunleavy', + 'Middaugh', + 'Barbato', + 'Pasco', + 'Harland', + 'Shorts', + 'Mowrey', + 'Dempster', + 'Knuckles', + 'Luebke', + 'Petrella', + 'Retana', + 'Licea', + 'Rundle', + 'Cape', + 'Lou', + 'Mcconkey', + 'Leeman', + 'Cabe', + 'Timothy', + 'Crochet', + 'Fulgham', + 'Glasco', + 'Backes', + 'Konopka', + 'Mcquaid', + 'Schley', + 'Abrahams', + 'Dahlin', + 'Iversen', + 'Chico', + 'Huffaker', + 'Modlin', + 'Laduke', + 'Marquart', + 'Motz', + 'Keech', + 'Louviere', + 'Como', + 'Fye', + 'Brightwell', + 'Yamashita', + 'Desrochers', + 'Richer', + 'Bourke', + 'Broadhead', + 'Pink', + 'Okamoto', + 'Chicas', + 'Vanatta', + 'Shick', + 'Furst', + 'Layfield', + 'Mcewan', + 'Baumgart', + 'Kappel', + 'Kucharski', + 'Quam', + 'Taub', + 'Houghtaling', + 'Sundquist', + 'Monks', + 'Wake', + 'Quiros', + 'Pursell', + 'Johansson', + 'Talkington', + 'Bast', + 'Stimson', + 'Hakes', + 'Loe', + 'Caggiano', + 'Schaper', + 'Chandra', + 'Tuma', + 'Arledge', + 'Romain', + 'Hornick', + 'Bridgman', + 'Livingstone', + 'Potvin', + 'Sparling', + 'Hause', + 'Trosclair', + 'Pless', + 'Szeto', + 'Clontz', + 'Lauber', + 'Detrick', + 'Dominique', + 'Mosser', + 'Degraff', + 'Liner', + 'Fleet', + 'Czerwinski', + 'Kopf', + 'Kovar', + 'Sheedy', + 'Zaremba', + 'Mina', + 'Sweeten', + 'Ou', + 'Musto', + 'Hennig', + 'Bangs', + 'Pasternak', + 'Berrier', + 'Smidt', + 'Brayton', + 'Claytor', + 'Ellerbe', + 'Reiman', + 'Larimore', + 'Ratzlaff', + 'Mudge', + 'Ni', + 'Spillers', + 'Cuomo', + 'Gerke', + 'Polizzi', + 'Harmer', + 'Apperson', + 'Regis', + 'Ugarte', + 'Paull', + 'Lagrange', + 'Dinwiddie', + 'Becton', + 'Gadsden', + 'Conforti', + 'Desoto', + 'Orme', + 'Filer', + 'Viers', + 'Lares', + 'Stair', + 'Hipps', + 'Kaneshiro', + 'Ladson', + 'Altizer', + 'Montejano', + 'Scalzo', + 'Sowder', + 'Ebeling', + 'Faucher', + 'Dicken', + 'Sartor', + 'Mcnerney', + 'Stage', + 'Mika', + 'Hice', + 'Grinstead', + 'Bartsch', + 'Mccumber', + 'Lenahan', + 'Liska', + 'Tietz', + 'Gauna', + 'Janda', + 'Bellis', + 'Shew', + 'Kelton', + 'Doby', + 'Golson', + 'Plaster', + 'Gonsales', + 'Krone', + 'Lape', + 'Lowrie', + 'Polly', + 'Gerardi', + 'Lamoreaux', + 'Bhatti', + 'Kimsey', + 'Buhl', + 'Arvin', + 'Gillian', + 'Benbow', + 'Roesler', + 'Stlaurent', + 'Canon', + 'Swihart', + 'Corea', + 'Petitt', + 'Spates', + 'Nappi', + 'Sebring', + 'Smelser', + 'Eckenrode', + 'Palos', + 'Disanto', + 'Tabares', + 'Okane', + 'Easterly', + 'Dendy', + 'Whigham', + 'Bednarz', + 'Wedge', + 'Edelen', + 'Stiff', + 'Borjas', + 'Obando', + 'Mcspadden', + 'Breed', + 'Dismuke', + 'Jarmon', + 'Serpa', + 'Lucky', + 'Cournoyer', + 'Hedberg', + 'Martine', + 'Michell', + 'Wittig', + 'Clodfelter', + 'Davids', + 'Gattis', + 'Kull', + 'Mascorro', + 'Schad', + 'Rine', + 'Bradburn', + 'Marie', + 'Czech', + 'Sunderman', + 'Wickersham', + 'Toohey', + 'Capozzi', + 'Poplin', + 'Markland', + 'Brosnan', + 'Fetterman', + 'Heiss', + 'Haglund', + 'Jourdan', + 'Turnipseed', + 'Tiernan', + 'Horrocks', + 'Barnhardt', + 'Sing', + 'Belford', + 'Baumgarten', + 'Klee', + 'Degeorge', + 'Caulder', + 'Gladstone', + 'Dancer', + 'Satchell', + 'Vento', + 'Larock', + 'Kimberly', + 'Hunn', + 'Harvin', + 'Krahn', + 'Ogorman', + 'Storch', + 'Coomes', + 'Bevilacqua', + 'Crotts', + 'Schillinger', + 'Morelock', + 'Hayworth', + 'Avis', + 'Cranmer', + 'Getchell', + 'Tena', + 'Buzzell', + 'Widman', + 'Barter', + 'Lafayette', + 'Asencio', + 'Embree', + 'Krell', + 'Siders', + 'Fuselier', + 'Whitby', + 'Elsner', + 'Pando', + 'Surface', + 'Rolf', + 'Highland', + 'Bufford', + 'Scheidt', + 'Defrancesco', + 'Fellers', + 'Carrol', + 'Germano', + 'Licon', + 'Hilty', + 'Ringo', + 'Dowler', + 'Glowacki', + 'Slabaugh', + 'Tomasello', + 'Messing', + 'Lavalle', + 'Milo', + 'Frerichs', + 'Plotkin', + 'Ziolkowski', + 'Gentle', + 'Knobloch', + 'Larochelle', + 'Duell', + 'Hurdle', + 'Speller', + 'Ceasar', + 'Vinci', + 'Mosquera', + 'Wyse', + 'Towler', + 'Ayoub', + 'Gullickson', + 'Spade', + 'Forshee', + 'Cliff', + 'Gholson', + 'Reichenbach', + 'Lockman', + 'Morones', + 'Storie', + 'Bissett', + 'Janney', + 'Durocher', + 'Fentress', + 'Troiano', + 'Boes', + 'Rouleau', + 'Rall', + 'Sultan', + 'Braggs', + 'Bethke', + 'Schacht', + 'Straley', + 'Mcfalls', + 'Fahy', + 'Winegar', + 'Gorecki', + 'Rudnick', + 'Wigginton', + 'Dedrick', + 'Sthilaire', + 'Lovette', + 'Hanneman', + 'Loch', + 'Moores', + 'Polen', + 'Anchondo', + 'Rosato', + 'Tindell', + 'Hunsicker', + 'Penna', + 'Privette', + 'Gayton', + 'Sliger', + 'Wink', + 'Brummer', + 'Crown', + 'Sommerville', + 'Mastrangelo', + 'Latimore', + 'Merlino', + 'Thoreson', + 'Kleiner', + 'Able', + 'Boose', + 'Loyola', + 'Jimenes', + 'Lapham', + 'Srinivasan', + 'Hammers', + 'Mo', + 'Evert', + 'Vanslyke', + 'Caywood', + 'Gremillion', + 'Rauscher', + 'Eckhoff', + 'Dearth', + 'Sinha', + 'Becerril', + 'Tuten', + 'Greenwalt', + 'Curlee', + 'Burgan', + 'Feagin', + 'Gallman', + 'Germann', + 'Swensen', + 'Vanallen', + 'Bissonnette', + 'Stoudt', + 'Handler', + 'Tanguay', + 'Lovins', + 'Smotherman', + 'Cutts', + 'Herod', + 'Maclin', + 'Arcuri', + 'Hackbarth', + 'Breazeale', + 'Rainville', + 'Crick', + 'Macintosh', + 'Bloss', + 'Fridley', + 'Stefanski', + 'Beauvais', + 'Koop', + 'Andes', + 'Blomberg', + 'Vallee', + 'Lanigan', + 'Blouin', + 'Rochon', + 'Dorazio', + 'Drouin', + 'Lamonica', + 'Wilbourn', + 'Spraggins', + 'Rieder', + 'Shugart', + 'Chacko', + 'Rutan', + 'Nutting', + 'Lawley', + 'Landy', + 'January', + 'Blowers', + 'Handel', + 'Doman', + 'Swiney', + 'Ettinger', + 'Jellison', + 'Veilleux', + 'Wiens', + 'Raimondi', + 'Spink', + 'Emond', + 'Yale', + 'Rachel', + 'Alldredge', + 'Lach', + 'Morlan', + 'Wayland', + 'Colquitt', + 'Gabrielson', + 'Mccarver', + 'Frances', + 'Granville', + 'Costigan', + 'Preuss', + 'Lentini', + 'Vansant', + 'Mosca', + 'Connally', + 'Frei', + 'Laplant', + 'Lago', + 'Leiter', + 'Trumbull', + 'Shaeffer', + 'Gongora', + 'Coady', + 'Fyffe', + 'Mance', + 'Worcester', + 'Zehner', + 'Bodie', + 'Burnes', + 'Pompey', + 'Teitelbaum', + 'Beaupre', + 'Visconti', + 'Mumma', + 'Markiewicz', + 'Piscitelli', + 'Moak', + 'Bourland', + 'Pennock', + 'Hannum', + 'Robichaux', + 'Folks', + 'Coppage', + 'Heffron', + 'Mullet', + 'Kimberlin', + 'Breneman', + 'Blandford', + 'Matthias', + 'Engebretson', + 'Roessler', + 'Allee', + 'Parkman', + 'Barge', + 'Ren', + 'Backstrom', + 'Bullen', + 'Lampman', + 'Loesch', + 'Echavarria', + 'Haman', + 'Cortina', + 'Elms', + 'Gordan', + 'Pabst', + 'Snelson', + 'Vanarsdale', + 'Pecora', + 'Rabago', + 'Enger', + 'Senger', + 'Dewees', + 'Semple', + 'Howey', + 'Westlund', + 'Daw', + 'Hagemann', + 'Mcpeek', + 'Vanderhoof', + 'Ohler', + 'Bohm', + 'Mazzone', + 'Arnott', + 'Bouton', + 'Fackler', + 'Giunta', + 'Stagner', + 'Tavera', + 'Poorman', + 'Buch', + 'Mangano', + 'Bonar', + 'Gerson', + 'Ranger', + 'Mccullar', + 'Wunder', + 'Bade', + 'Armand', + 'Chalfant', + 'Lichtenstein', + 'Turco', + 'Degraw', + 'Few', + 'Haigler', + 'Lis', + 'Bittinger', + 'Morrone', + 'Hodgdon', + 'Wittenberg', + 'Imes', + 'Dreiling', + 'Landwehr', + 'Maly', + 'Warlick', + 'Terpstra', + 'Bolte', + 'Stiller', + 'Stmartin', + 'Pankratz', + 'Albee', + 'Victory', + 'Lezama', + 'Brecht', + 'Monarrez', + 'Thurlow', + 'Laskey', + 'Bothwell', + 'Candler', + 'Esh', + 'Kalman', + 'Samano', + 'Yohe', + 'Regnier', + 'Leite', + 'Ballantyne', + 'Dan', + 'Fikes', + 'Cendejas', + 'Mikula', + 'Fairman', + 'Dragon', + 'Manzella', + 'Renninger', + 'Leaman', + 'Godbey', + 'Current', + 'Mirabal', + 'Boerner', + 'Depaz', + 'Birge', + 'Westberry', + 'Severin', + 'Weddington', + 'Longenecker', + 'Mccreery', + 'Lebel', + 'Nader', + 'Gan', + 'Auguste', + 'Colonna', + 'Paramo', + 'Minyard', + 'Duley', + 'Beil', + 'Salters', + 'Brindley', + 'Simmers', + 'Lumpkins', + 'Crisman', + 'Raulerson', + 'Lanz', + 'Deroche', + 'Kemmerer', + 'Bogner', + 'Mahn', + 'Willer', + 'Gunnels', + 'Warford', + 'Reason', + 'Scherr', + 'Digirolamo', + 'Hallowell', + 'Wilcoxson', + 'Gaillard', + 'Deshields', + 'Hively', + 'Sakai', + 'Creason', + 'Jaber', + 'Lapinski', + 'Bolivar', + 'Millwood', + 'Shumpert', + 'Fujii', + 'Plemmons', + 'Lamere', + 'Cleghorn', + 'Mccaw', + 'Seavey', + 'Zwick', + 'Hosler', + 'Lepley', + 'Marden', + 'Cornwall', + 'Gauger', + 'Hofmeister', + 'Bugarin', + 'Loose', + 'Guardiola', + 'Hertzog', + 'Bigger', + 'Heineman', + 'Retzlaff', + 'Rizzuto', + 'Flannigan', + 'Rathburn', + 'Moulder', + 'Town', + 'Gautier', + 'Hamid', + 'Torrance', + 'Walthall', + 'Windom', + 'Kleckner', + 'Kirwan', + 'Gasaway', + 'Pinkard', + 'Concannon', + 'Mcquiston', + 'Yow', + 'Eshleman', + 'Riggleman', + 'Foulk', + 'Bolles', + 'Craine', + 'Hinnant', + 'Gholston', + 'Lebo', + 'Torkelson', + 'Mancia', + 'Canale', + 'Celestin', + 'Neubert', + 'Schmaltz', + 'Highfill', + 'Fisch', + 'Matte', + 'Hoefer', + 'Flippin', + 'Mclin', + 'Mikkelson', + 'Gump', + 'Kilroy', + 'Ensor', + 'Klosterman', + 'Ruppel', + 'Steffey', + 'Sauve', + 'Cessna', + 'Apgar', + 'Jacobus', + 'Pettyjohn', + 'Northington', + 'Smithey', + 'Moro', + 'Dossett', + 'Mccroskey', + 'Yelverton', + 'Mascarenas', + 'Hebb', + 'Quinteros', + 'Giang', + 'Pontius', + 'Sipple', + 'Atkin', + 'Howington', + 'Hiebert', + 'Lingerfelt', + 'Schueler', + 'Sailer', + 'Smits', + 'Keeter', + 'Macrae', + 'Mease', + 'Shortridge', + 'Scates', + 'Amstutz', + 'Kuebler', + 'Cambron', + 'Eaker', + 'Finlayson', + 'Bookout', + 'Mullett', + 'Bank', + 'Schlenker', + 'Morlock', + 'Haskett', + 'Dade', + 'Gallucci', + 'Lahey', + 'Ryerson', + 'Crownover', + 'Banfield', + 'Mcclay', + 'Diggins', + 'Conerly', + 'Primus', + 'Syverson', + 'Prindle', + 'Blasingame', + 'Deford', + 'Garnes', + 'Hoisington', + 'Glasper', + 'Lorusso', + 'Hesson', + 'Youssef', + 'Threlkeld', + 'Talmadge', + 'Winfree', + 'Heacock', + 'Rawlinson', + 'Burse', + 'Diederich', + 'Niemiec', + 'Norby', + 'Bauder', + 'Scranton', + 'Prentiss', + 'Towles', + 'Henton', + 'Purifoy', + 'Pinzon', + 'Edler', + 'Ragin', + 'Albarado', + 'Cuadra', + 'Hoadley', + 'Devita', + 'Pavon', + 'Alday', + 'Goulding', + 'Millis', + 'Dalley', + 'Kolodziej', + 'Kropf', + 'Kuiper', + 'Crespin', + 'Xavier', + 'Sailor', + 'Lagrone', + 'Boehme', + 'Tidd', + 'Wilmore', + 'Ziemer', + 'Ropp', + 'Kettler', + 'Pilon', + 'Miron', + 'Salsbury', + 'Job', + 'Sensenig', + 'Cayton', + 'Nanney', + 'Rasch', + 'Silvestre', + 'Ladue', + 'Dampier', + 'Ackermann', + 'Friedel', + 'Kleiman', + 'Geronimo', + 'Ezzell', + 'Duclos', + 'Moor', + 'Neuhaus', + 'Lan', + 'Allender', + 'Tedeschi', + 'Langton', + 'Dawley', + 'Kearse', + 'Godina', + 'Guernsey', + 'Kober', + 'Bisbee', + 'Lamphere', + 'Kinman', + 'Wesner', + 'Malo', + 'Stroupe', + 'Millette', + 'Yeoman', + 'Baig', + 'Kirchoff', + 'Tsao', + 'Cristobal', + 'Mucci', + 'Pair', + 'Barefield', + 'Dewolf', + 'Fitzmaurice', + 'Mcaleer', + 'Natal', + 'Bara', + 'Macey', + 'Mclennan', + 'Fabre', + 'Vieyra', + 'Magno', + 'Eyre', + 'Chatterton', + 'Gilland', + 'Hurlbut', + 'Umberger', + 'Roloff', + 'Brambila', + 'Mazzeo', + 'Letson', + 'Norsworthy', + 'Bier', + 'Gioia', + 'Kapoor', + 'Marlatt', + 'Flippo', + 'Houde', + 'Baughn', + 'Blackledge', + 'Fly', + 'Dinkel', + 'Rathbone', + 'Bober', + 'Boydston', + 'Ferdinand', + 'Coletti', + 'Cuenca', + 'Deters', + 'Blagg', + 'Timmins', + 'Boyden', + 'Meads', + 'Narcisse', + 'Saelee', + 'Cosner', + 'Strawser', + 'Amico', + 'Dowdle', + 'Golub', + 'Silverberg', + 'Riles', + 'Balk', + 'Buhr', + 'Feltman', + 'Stickel', + 'Zapien', + 'Cargile', + 'Kulik', + 'Lazzaro', + 'Oberle', + 'Wickstrom', + 'Maeda', + 'Cockrum', + 'Boulton', + 'Sandford', + 'Culbert', + 'Dula', + 'Ament', + 'Chunn', + 'Owenby', + 'Wasilewski', + 'Wichman', + 'Oestreich', + 'Klos', + 'Orchard', + 'Hogge', + 'Presson', + 'Cordon', + 'Gans', + 'Leonardi', + 'Manjarrez', + 'Olander', + 'Drennen', + 'Wirt', + 'Tiger', + 'Dolce', + 'Hagstrom', + 'Hirsh', + 'Tally', + 'Crumbley', + 'Mcgreevy', + 'Amidon', + 'Olague', + 'Lint', + 'Poche', + 'Lipford', + 'Engen', + 'Mcelfresh', + 'Cuneo', + 'Krumm', + 'Haak', + 'Arocho', + 'Longworth', + 'Seamon', + 'Bronner', + 'Swartzentruber', + 'Chand', + 'Wilhoit', + 'Chapel', + 'Hitchens', + 'Brzezinski', + 'Heidenreich', + 'Ellenberger', + 'Gamblin', + 'Ormond', + 'Burchard', + 'Dibella', + 'Nicoll', + 'Simcox', + 'Strohm', + 'Dittmar', + 'Wycoff', + 'Grays', + 'Spero', + 'Vess', + 'Picone', + 'Greening', + 'Maynes', + 'Knauss', + 'Wojtowicz', + 'Chaput', + 'Soliman', + 'Ponton', + 'Carlino', + 'Kestner', + 'Kelch', + 'Dimauro', + 'Iorio', + 'Parenteau', + 'Pesina', + 'Clauson', + 'Stigall', + 'Keels', + 'Waldrep', + 'Wix', + 'Draeger', + 'Ertel', + 'Starner', + 'Charest', + 'Simoneaux', + 'Ivanov', + 'Thor', + 'Gravel', + 'Trottier', + 'Clendenin', + 'Kromer', + 'Benda', + 'Touchet', + 'Hornbuckle', + 'Avent', + 'Dombroski', + 'Friedland', + 'Radabaugh', + 'Vesely', + 'Wike', + 'Lax', + 'Messersmith', + 'Deoliveira', + 'Brey', + 'Cogdill', + 'Overturf', + 'Sova', + 'Pero', + 'Beaird', + 'Cevallos', + 'Defalco', + 'Taormina', + 'Thornberry', + 'Westervelt', + 'Macaulay', + 'Hajek', + 'Brugger', + 'Leff', + 'Ketterer', + 'Ono', + 'Mullenix', + 'Frison', + 'Gullo', + 'Calhoon', + 'Summey', + 'Hockaday', + 'Dimatteo', + 'Agan', + 'Patenaude', + 'Mary', + 'Tanis', + 'Obert', + 'Elton', + 'Randles', + 'Migliore', + 'Schmalz', + 'Vanvalkenburg', + 'Quinto', + 'Palmquist', + 'Hoops', + 'Naples', + 'Orear', + 'Eberhard', + 'Fitzgibbons', + 'Adkinson', + 'Gerace', + 'Elie', + 'Dressel', + 'Silber', + 'Otey', + 'Hsiao', + 'Kreutzer', + 'Tutor', + 'Roundy', + 'Haddox', + 'Bridgers', + 'Leto', + 'Daniell', + 'Pollitt', + 'Freda', + 'Mraz', + 'Engelbrecht', + 'Ariza', + 'Grand', + 'Pavone', + 'Everts', + 'Benes', + 'Reamer', + 'Faucett', + 'Eatmon', + 'Raymundo', + 'Zaman', + 'Devitt', + 'Master', + 'Carron', + 'Hoffner', + 'Sciortino', + 'Stringham', + 'Bookman', + 'Westberg', + 'Spahn', + 'Hise', + 'Waterbury', + 'Buckwalter', + 'Hug', + 'Overly', + 'Dingus', + 'Ince', + 'Haar', + 'Shain', + 'Heaps', + 'Oppenheimer', + 'Miyamoto', + 'Schreier', + 'Martello', + 'Atteberry', + 'Folger', + 'Macke', + 'Pal', + 'Lucchesi', + 'Osterhout', + 'Liriano', + 'Legge', + 'Barra', + 'Crumb', + 'Gwyn', + 'Forst', + 'Axelrod', + 'Samayoa', + 'Edgell', + 'Purkey', + 'Lannon', + 'Branam', + 'Yeo', + 'Hatmaker', + 'Borum', + 'Villagrana', + 'Lawing', + 'Bark', + 'Muirhead', + 'Eckles', + 'Weight', + 'Surles', + 'Cullinan', + 'Lagos', + 'Naber', + 'Sloat', + 'Foos', + 'Vine', + 'Milliner', + 'Reliford', + 'Dahlquist', + 'Gibney', + 'Moroney', + 'Stecker', + 'Bella', + 'Brickhouse', + 'Canela', + 'Kula', + 'Tartaglia', + 'Siewert', + 'Hitch', + 'Brickman', + 'Cheeseman', + 'Carollo', + 'Geissler', + 'Jiron', + 'Cossey', + 'Sroka', + 'Border', + 'Brownlow', + 'Ellenburg', + 'Cella', + 'Brinton', + 'Scurry', + 'Behrendt', + 'Carstensen', + 'Schendel', + 'Bodner', + 'Eddleman', + 'Stec', + 'Capasso', + 'Leu', + 'Kennett', + 'Ruane', + 'Critchfield', + 'Carbonell', + 'Mitcham', + 'Troncoso', + 'Mckeen', + 'Cammack', + 'Broach', + 'Culbreath', + 'Callejas', + 'Wurst', + 'Brookman', + 'Guerrier', + 'Seese', + 'Kitzmiller', + 'Graybeal', + 'Yardley', + 'Cheever', + 'Virgin', + 'Brimmer', + 'Swoboda', + 'Pandya', + 'Canton', + 'Magnus', + 'Draughn', + 'Dilts', + 'Tauber', + 'Vandegrift', + 'Rene', + 'Cousineau', + 'Joo', + 'Pimental', + 'Carpentier', + 'Eager', + 'Cumberland', + 'Eastridge', + 'Moberly', + 'Erhardt', + 'Meldrum', + 'Degennaro', + 'Desanto', + 'Manahan', + 'Gowdy', + 'Popham', + 'Mee', + 'Kinslow', + 'Harned', + 'Cartee', + 'Raiford', + 'Henrichs', + 'Maffei', + 'Seamans', + 'Heckel', + 'Toll', + 'Milian', + 'Mabrey', + 'Dall', + 'Lanford', + 'Carew', + 'Bascom', + 'Christofferson', + 'Hadfield', + 'Ferber', + 'Mestas', + 'Leith', + 'Abston', + 'Cuddy', + 'Svendsen', + 'Cowling', + 'Segars', + 'Nalls', + 'Hofstetter', + 'Badgley', + 'Mccaffery', + 'Burner', + 'Laymon', + 'Pinion', + 'Schooler', + 'Brun', + 'Aldaco', + 'Savarese', + 'Gravelle', + 'Belvin', + 'Brekke', + 'Dekker', + 'Ellefson', + 'Lurie', + 'Cassity', + 'Epperly', + 'Genova', + 'Dehn', + 'Fargo', + 'Vanderford', + 'Sine', + 'Horrell', + 'Napoleon', + 'Kamm', + 'Riel', + 'Gerena', + 'Check', + 'Devane', + 'Grissett', + 'Brendel', + 'Weyant', + 'Basurto', + 'Coppinger', + 'Grosse', + 'Saeed', + 'Lunceford', + 'Washam', + 'Benard', + 'Eastham', + 'Holleran', + 'Kiesel', + 'Risch', + 'Mccullen', + 'Vizcaino', + 'Fullen', + 'Westbrooks', + 'Babich', + 'Mauch', + 'Hensler', + 'Bryner', + 'Phillippi', + 'Santistevan', + 'Jalbert', + 'Vanorden', + 'Brantner', + 'Mcgrail', + 'Rustin', + 'Lebaron', + 'Genao', + 'Quast', + 'Hamburg', + 'Mensah', + 'Heckler', + 'Popa', + 'Mantooth', + 'Hargreaves', + 'Jury', + 'Seiber', + 'Calton', + 'Lafreniere', + 'Starbuck', + 'Gow', + 'Veazey', + 'Kneeland', + 'Woodberry', + 'Vallone', + 'Sutcliffe', + 'Loh', + 'Wiltse', + 'Choudhury', + 'Rollo', + 'Bjerke', + 'Huffstetler', + 'Ogren', + 'Legere', + 'Wilmer', + 'Conboy', + 'Pressler', + 'Hon', + 'Monger', + 'Devos', + 'Houtz', + 'Shurtleff', + 'Sedlak', + 'Carolan', + 'Luc', + 'Immel', + 'Guizar', + 'Kron', + 'Lusby', + 'Whitsett', + 'Pryce', + 'Mengel', + 'Youngberg', + 'Kluge', + 'Thrush', + 'Wilsey', + 'Santee', + 'Braham', + 'Palmeri', + 'Cousino', + 'Willits', + 'Gram', + 'Dearmond', + 'Fonville', + 'Sabatini', + 'Nehring', + 'Henne', + 'Prager', + 'Mederos', + 'Schuldt', + 'Weisz', + 'Mccart', + 'Warriner', + 'Bartelt', + 'Dimond', + 'Mccubbin', + 'Say', + 'Mickel', + 'Bracamonte', + 'Volkman', + 'Brindle', + 'Bitter', + 'Dickie', + 'Inge', + 'Brinegar', + 'Lerman', + 'Bohan', + 'Rondon', + 'Dilbeck', + 'Rumbaugh', + 'Simard', + 'Berke', + 'Ealey', + 'Knauer', + 'Michalek', + 'Smolinski', + 'Wurster', + 'Zullo', + 'Nott', + 'Claar', + 'Mayor', + 'Moir', + 'Hubbert', + 'Hankerson', + 'Mok', + 'Simko', + 'Mumm', + 'Sheely', + 'Abramowitz', + 'Pusateri', + 'Boomer', + 'Chappelle', + 'Demery', + 'Coniglio', + 'Asay', + 'Nova', + 'Biel', + 'Delancey', + 'Tocco', + 'Tant', + 'Melin', + 'Lacoste', + 'Derrico', + 'Stacks', + 'Watley', + 'Stoneking', + 'Westrick', + 'Pons', + 'Malm', + 'Parekh', + 'Loop', + 'Kitt', + 'Crisostomo', + 'Ecklund', + 'Tollison', + 'Dziedzic', + 'Pillsbury', + 'Baumer', + 'Matsuda', + 'Jeon', + 'Foye', + 'Peltz', + 'Candela', + 'Levey', + 'Organ', + 'Hathorn', + 'Galeano', + 'Nies', + 'Cabezas', + 'Barras', + 'Pier', + 'Truss', + 'Leist', + 'Lheureux', + 'Nakano', + 'Ladwig', + 'Grunwald', + 'Centers', + 'Sherrard', + 'Morais', + 'Juhl', + 'Ivers', + 'Dunfee', + 'Jolliff', + 'Breeze', + 'Tapper', + 'Goodridge', + 'Kelliher', + 'Finck', + 'Roose', + 'Gauvin', + 'Coil', + 'Pounders', + 'Lobb', + 'Stalcup', + 'Swanner', + 'Boivin', + 'Neer', + 'Laxton', + 'Pai', + 'Postma', + 'Janus', + 'Didier', + 'Engleman', + 'League', + 'Fray', + 'Aguillon', + 'Richins', + 'Tolar', + 'Criner', + 'Rowlands', + 'Verdi', + 'Utt', + 'Winders', + 'Turbeville', + 'Rada', + 'Mcnichols', + 'Boddy', + 'Binford', + 'Amey', + 'Schultze', + 'Sontag', + 'Saleem', + 'Przybylski', + 'Vanderlinden', + 'Vanfossen', + 'Longacre', + 'Heasley', + 'Southwell', + 'Decesare', + 'Munch', + 'Minix', + 'Hymes', + 'Klopp', + 'Militello', + 'Schuessler', + 'Velazco', + 'Jurek', + 'Claycomb', + 'Diemer', + 'Roser', + 'Huse', + 'Perkinson', + 'Musa', + 'Leavy', + 'Seidman', + 'Vroman', + 'Stalter', + 'Grieve', + 'Aron', + 'Purdie', + 'Dusek', + 'Rago', + 'Shepler', + 'Leopard', + 'Araya', + 'Rutt', + 'Voth', + 'Hittle', + 'Husain', + 'Gratton', + 'Seigler', + 'Coppedge', + 'Nicastro', + 'Fitzgibbon', + 'Sosebee', + 'Tank', + 'Troche', + 'Delph', + 'Ryland', + 'Mazzella', + 'Rai', + 'Strecker', + 'Epp', + 'Clower', + 'Porche', + 'Gelman', + 'Herrman', + 'Balser', + 'Tosh', + 'Bonn', + 'Cerrato', + 'Varley', + 'Dingess', + 'Goodspeed', + 'Boller', + 'Heimann', + 'Gottfried', + 'Super', + 'Falzone', + 'Bizzell', + 'Litwin', + 'Ji', + 'Rogowski', + 'Tindle', + 'Hoye', + 'Balfour', + 'Focht', + 'Manz', + 'Stender', + 'Sutterfield', + 'Bayes', + 'Mullings', + 'Dockter', + 'Figueiredo', + 'Kepner', + 'Posadas', + 'Nettleton', + 'Ruder', + 'Younce', + 'Flanary', + 'Scotti', + 'Bayliss', + 'Tandy', + 'Henrickson', + 'Volker', + 'Letts', + 'Joines', + 'Fewell', + 'Wherry', + 'Stelzer', + 'Stever', + 'Viator', + 'Catt', + 'Jeffords', + 'Guerriero', + 'Milby', + 'Jozwiak', + 'Slawson', + 'Portwood', + 'Billie', + 'Borunda', + 'Chinchilla', + 'Papadopoulos', + 'Lohse', + 'Mantz', + 'Gabriele', + 'Hosford', + 'Kohut', + 'Tardiff', + 'Puma', + 'Bodin', + 'Hodgins', + 'Boon', + 'Golightly', + 'Bogert', + 'Abdi', + 'Wigfall', + 'Fleischmann', + 'Nease', + 'Rayborn', + 'Zigler', + 'Reimann', + 'Malagon', + 'Puls', + 'Grogg', + 'Drinkwater', + 'Dacus', + 'Mcfee', + 'Domino', + 'Harjo', + 'Pascarella', + 'Spengler', + 'Copple', + 'Rollings', + 'Brew', + 'Brabham', + 'Nordquist', + 'Emig', + 'Riggio', + 'Sanson', + 'Gerardo', + 'Pereda', + 'Renken', + 'Stickley', + 'Milliron', + 'Rolling', + 'Hollie', + 'Biondi', + 'Fluharty', + 'Magyar', + 'Balsamo', + 'Imler', + 'Hanlin', + 'Dycus', + 'Kirkley', + 'Wimberley', + 'Finan', + 'Kulkarni', + 'Morreale', + 'Briner', + 'Pelzer', + 'Bouie', + 'Fenstermaker', + 'Gimenez', + 'Labella', + 'Scherrer', + 'Holzman', + 'Winer', + 'Wrigley', + 'Leighty', + 'Liptak', + 'Chamness', + 'Franko', + 'Arwood', + 'Tiner', + 'Schoenberger', + 'Gear', + 'Hereford', + 'Slezak', + 'Longfellow', + 'Cull', + 'Brashears', + 'Clear', + 'Zielke', + 'Arden', + 'Bonneau', + 'Muck', + 'Tarvin', + 'Beran', + 'Coulombe', + 'Toothman', + 'Ghosh', + 'Mcguirk', + 'Pinero', + 'Ruan', + 'Gartman', + 'Peed', + 'Cassano', + 'Forcier', + 'Haque', + 'Veatch', + 'Fodor', + 'Wetherington', + 'Barrette', + 'Bottorff', + 'Holmstrom', + 'Honda', + 'Kopecky', + 'Loaiza', + 'Castelan', + 'Haydon', + 'Lamotte', + 'Mutchler', + 'Mahmoud', + 'Gleaton', + 'Rebollar', + 'Moctezuma', + 'Tannehill', + 'Bernardino', + 'Walrath', + 'Adcox', + 'Heidt', + 'Rakowski', + 'Soza', + 'Limas', + 'Wysong', + 'Mannix', + 'Pattillo', + 'Corner', + 'Kuang', + 'Loflin', + 'Ledger', + 'Ivery', + 'Likens', + 'Mctaggart', + 'Hartin', + 'Prange', + 'Stenzel', + 'Shadle', + 'Karn', + 'Duplantis', + 'Garibaldi', + 'Batty', + 'Goulart', + 'Ranck', + 'Beekman', + 'Nicolosi', + 'Arizmendi', + 'Donoho', + 'Drewry', + 'Lenihan', + 'Spatz', + 'Wible', + 'Dimmick', + 'Stelter', + 'Seyler', + 'Stringfield', + 'Bonaparte', + 'Dematteo', + 'Petrey', + 'Bellino', + 'Cavaliere', + 'Thaler', + 'Heiner', + 'Lillis', + 'Hammes', + 'Rainbolt', + 'Hillyard', + 'Farnum', + 'Overmyer', + 'Replogle', + 'Sclafani', + 'Audet', + 'Santa', + 'Hollen', + 'Lineberger', + 'Bonnet', + 'Caples', + 'Dahlen', + 'Ruggieri', + 'Keppler', + 'Ryman', + 'Copas', + 'Lyda', + 'Pusey', + 'Bostrom', + 'Patnode', + 'Richeson', + 'Hamil', + 'Wyss', + 'Mcadam', + 'Dennett', + 'Lever', + 'Drinkard', + 'Ohl', + 'Restivo', + 'Vyas', + 'Moyle', + 'Blauvelt', + 'Gregson', + 'Scull', + 'Verret', + 'Stines', + 'Forsman', + 'Gehman', + 'Watrous', + 'Gunnell', + 'Choice', + 'Castaldo', + 'Pietrzak', + 'Goodsell', + 'Klima', + 'Stratman', + 'Foutz', + 'Massingill', + 'Huneycutt', + 'Zellmer', + 'Tefft', + 'Hamblen', + 'Baggs', + 'Mcgarity', + 'Alfieri', + 'Stetler', + 'Hershman', + 'Fuerst', + 'Granda', + 'Villafane', + 'Stocking', + 'Laguerre', + 'Salvato', + 'Mcniel', + 'Trim', + 'Goldston', + 'Tannenbaum', + 'Laforge', + 'Hawker', + 'Innis', + 'Rasheed', + 'Marbury', + 'Jules', + 'Harpster', + 'Hruska', + 'Mancillas', + 'Ruck', + 'Schloss', + 'Shy', + 'Leming', + 'Eich', + 'Allain', + 'Premo', + 'Goodner', + 'Karlin', + 'Natoli', + 'Sinn', + 'Althouse', + 'Bodiford', + 'Krishnan', + 'Snedeker', + 'Weigle', + 'Blohm', + 'Renwick', + 'Menzies', + 'Stonebraker', + 'Brunetti', + 'Crompton', + 'Hucks', + 'Maharaj', + 'Bangert', + 'Hepp', + 'Kammer', + 'Sutliff', + 'Doyon', + 'Hutsell', + 'Cumbie', + 'Dibiase', + 'Linke', + 'Sapienza', + 'Sprayberry', + 'Sundstrom', + 'Vanbeek', + 'Ewart', + 'Erlandson', + 'Knutsen', + 'Nicolai', + 'Oros', + 'Almquist', + 'Tedrow', + 'Diebold', + 'Bellman', + 'Sherrer', + 'Ehret', + 'Ota', + 'Seman', + 'Folse', + 'Amy', + 'Mcateer', + 'Steinhauer', + 'Vannatta', + 'Holle', + 'Carreras', + 'Anger', + 'Clinkscales', + 'Castiglione', + 'Zakrzewski', + 'Principe', + 'Artman', + 'Waiters', + 'Tarbox', + 'Sippel', + 'Belz', + 'Joachim', + 'Pipkins', + 'Peterkin', + 'Abalos', + 'Flock', + 'Brochu', + 'Tobler', + 'Mckinnis', + 'Gatson', + 'Cronan', + 'Manthey', + 'Oberholtzer', + 'Schiltz', + 'Skowronski', + 'Matute', + 'Castonguay', + 'Bechard', + 'Drees', + 'Carte', + 'Baysinger', + 'Kees', + 'Steve', + 'Ratchford', + 'Clopton', + 'Heimbach', + 'Selig', + 'Peavey', + 'Sidney', + 'Hilliker', + 'Oehler', + 'Essig', + 'Ownby', + 'Huling', + 'Aylward', + 'Matzke', + 'Mikkelsen', + 'Vandam', + 'Rodden', + 'Plunk', + 'Mcdonell', + 'Buechler', + 'Dahm', + 'Tarlton', + 'Funches', + 'Alvidrez', + 'Padua', + 'Pingel', + 'Cid', + 'Mcburney', + 'Brunton', + 'Dwight', + 'Bucio', + 'Schiffer', + 'Dyal', + 'Cyphers', + 'Gildea', + 'Wengerd', + 'Lappin', + 'Longwell', + 'Basil', + 'Acklin', + 'Cancino', + 'Kalina', + 'Tynan', + 'Raasch', + 'Fleener', + 'Dunmire', + 'Gent', + 'Cruickshank', + 'Baltimore', + 'Shum', + 'Vanpatten', + 'Costilla', + 'Grimshaw', + 'Loar', + 'Royse', + 'Amon', + 'Amendola', + 'Mcgonagle', + 'Alm', + 'Hausmann', + 'Heitzman', + 'Mailloux', + 'Brault', + 'Capra', + 'Levis', + 'Barillas', + 'Quandt', + 'Fedele', + 'Chittenden', + 'Cheesman', + 'Wildes', + 'Bolan', + 'Metoyer', + 'Ciccarelli', + 'Melara', + 'Gano', + 'Janowski', + 'Magoon', + 'Kuster', + 'Ofarrell', + 'Joplin', + 'Cannella', + 'Middendorf', + 'Putz', + 'Saephan', + 'Sieg', + 'Lainez', + 'Roten', + 'Buras', + 'Nock', + 'Manke', + 'Hymel', + 'Devaughn', + 'Braverman', + 'Fleisher', + 'Persson', + 'Sandidge', + 'Corsi', + 'Torok', + 'Steinhoff', + 'Corby', + 'Shorey', + 'Wooton', + 'Estell', + 'Bolander', + 'Vivar', + 'Cuesta', + 'Renick', + 'Isler', + 'Caprio', + 'Crissman', + 'Wann', + 'Matchett', + 'Calahan', + 'Escareno', + 'Liguori', + 'Helt', + 'Boner', + 'Luper', + 'Hoppes', + 'Ingold', + 'Gilleland', + 'Saathoff', + 'Szczepanski', + 'Yockey', + 'Veith', + 'Wasser', + 'Denniston', + 'Fretwell', + 'Goetsch', + 'Havel', + 'Banach', + 'Schaal', + 'Nisbet', + 'Depaul', + 'Escalona', + 'Gammons', + 'Schmelzer', + 'Wehrle', + 'Guglielmo', + 'Oberlander', + 'Wolski', + 'Dimick', + 'Rebello', + 'Braunstein', + 'Vanderveen', + 'Saini', + 'Meiners', + 'Metheny', + 'Schommer', + 'Kissell', + 'Burgoyne', + 'Walmsley', + 'Parmley', + 'Arthurs', + 'Worsley', + 'Hulme', + 'Campisi', + 'Parvin', + 'Ogawa', + 'Coder', + 'Gardener', + 'Taplin', + 'Nuzzo', + 'Linthicum', + 'Rosenstein', + 'Simoneau', + 'Preble', + 'Chae', + 'Nealon', + 'Stonecipher', + 'Medders', + 'Bencomo', + 'Durazo', + 'Scotto', + 'Klem', + 'Corman', + 'Byard', + 'Evan', + 'Dengler', + 'Kohls', + 'Seidler', + 'Clute', + 'Nebel', + 'Hohl', + 'Younker', + 'Parkerson', + 'Pullins', + 'Sweeting', + 'Wiersma', + 'Callanan', + 'Lisk', + 'Fassett', + 'Alloway', + 'Lafever', + 'Ollis', + 'Gracey', + 'Tune', + 'Ester', + 'Weingarten', + 'Swigart', + 'Frew', + 'Conkle', + 'Mendelsohn', + 'Belliveau', + 'Bacher', + 'Coto', + 'Ro', + 'Lipson', + 'Standard', + 'Hoerner', + 'Moldenhauer', + 'Trivette', + 'Colligan', + 'Cacho', + 'Emrich', + 'Condit', + 'Styer', + 'Paramore', + 'Cheramie', + 'Sprenger', + 'Kreps', + 'Curd', + 'Josephs', + 'Bruch', + 'Villano', + 'Banh', + 'Kennison', + 'Hilson', + 'Gathers', + 'Weinman', + 'Brickley', + 'Jetton', + 'Munford', + 'Charboneau', + 'Dittrich', + 'Boysen', + 'Newbury', + 'Hayner', + 'Pfau', + 'Wegman', + 'Eure', + 'Heinrichs', + 'Kresge', + 'Klepper', + 'Yohn', + 'Bergan', + 'Spells', + 'Reisman', + 'Schiffman', + 'Napoles', + 'Banegas', + 'Landman', + 'Hallenbeck', + 'Sever', + 'Hole', + 'Bown', + 'Barnaby', + 'Junior', + 'Deloatch', + 'Secrist', + 'Steigerwald', + 'Kallas', + 'Littell', + 'Clinger', + 'Rehman', + 'Cothern', + 'Class', + 'Sabino', + 'Mckain', + 'Werts', + 'Asmus', + 'Fierros', + 'Heffelfinger', + 'Henthorn', + 'Weirich', + 'Ashbrook', + 'Alber', + 'Calles', + 'Bragdon', + 'Gerow', + 'Hanger', + 'Machen', + 'Patt', + 'Harada', + 'Parmelee', + 'Decaro', + 'Sons', + 'Tindal', + 'Lubbers', + 'Ferland', + 'Bruni', + 'Boyes', + 'Danis', + 'Tigner', + 'Anzaldua', + 'Gaxiola', + 'Iacono', + 'Lizama', + 'Forbis', + 'Mcguffin', + 'Greenhill', + 'Baity', + 'Welcome', + 'Lauzon', + 'Nicodemus', + 'Rabin', + 'Teegarden', + 'Yunker', + 'Salim', + 'Dews', + 'Schueller', + 'Stogsdill', + 'Minch', + 'Ellett', + 'Villafana', + 'Shan', + 'Boler', + 'Kast', + 'Shrout', + 'Taff', + 'Willcox', + 'Kahan', + 'Gerth', + 'Sabella', + 'Procopio', + 'Vedder', + 'Heeter', + 'Banes', + 'Alaimo', + 'Raza', + 'Starkweather', + 'Mutter', + 'Manners', + 'Bohanan', + 'Virden', + 'Booze', + 'Wimbush', + 'Eickhoff', + 'Hankinson', + 'Swilley', + 'Killinger', + 'Labar', + 'Tallant', + 'Rosin', + 'Hillhouse', + 'Labarre', + 'Ryans', + 'Heintzelman', + 'Cottone', + 'Bickerstaff', + 'Westley', + 'Rotter', + 'Hey', + 'Dinapoli', + 'Lohmann', + 'Reetz', + 'Vences', + 'Mckiernan', + 'Thornsberry', + 'Hofman', + 'Murrieta', + 'Vanwormer', + 'Sen', + 'Pinheiro', + 'Jaco', + 'Maner', + 'Crosley', + 'Rogalski', + 'Hollandsworth', + 'Hinze', + 'Seawright', + 'Brosius', + 'Keehn', + 'Sweetman', + 'Vicknair', + 'Casler', + 'Hagopian', + 'Westhoff', + 'Lipari', + 'Poll', + 'Lintz', + 'Rosinski', + 'Henrie', + 'Crystal', + 'Wroten', + 'Perla', + 'Zawacki', + 'Mckillip', + 'Dorantes', + 'Wallick', + 'Hoots', + 'Witty', + 'Granata', + 'Janicki', + 'Petroff', + 'Emert', + 'Raskin', + 'Picou', + 'Caple', + 'Mcelyea', + 'Blackmer', + 'Busbee', + 'Pettengill', + 'Newberg', + 'Nickle', + 'Hedman', + 'Flavin', + 'Forgione', + 'Wachtel', + 'Meader', + 'Nale', + 'Westby', + 'Pulaski', + 'Schupp', + 'Troutt', + 'Fishburn', + 'Laprade', + 'Dealba', + 'Waymire', + 'Stiefel', + 'Carner', + 'Fallin', + 'Belin', + 'Anand', + 'Lesh', + 'Okada', + 'Whipkey', + 'Mang', + 'Harvill', + 'Caver', + 'Moskal', + 'Schaible', + 'Vandeusen', + 'Boyko', + 'Matteo', + 'Crisler', + 'Capehart', + 'Heide', + 'Holdsworth', + 'Mcdonagh', + 'Burlison', + 'Beshears', + 'Gills', + 'Cowger', + 'Gendreau', + 'Goering', + 'Hewes', + 'Whelchel', + 'Kier', + 'Tramel', + 'Mcsherry', + 'Morita', + 'Cissell', + 'Knaus', + 'Vangilder', + 'Karsten', + 'Linscott', + 'Ratner', + 'Catoe', + 'Scriven', + 'Gerstner', + 'Brobst', + 'Normandin', + 'Piasecki', + 'Tamura', + 'Balboa', + 'Nathanson', + 'Huizenga', + 'Renard', + 'Deshazo', + 'Ethier', + 'Fabiano', + 'Quisenberry', + 'Mcbryde', + 'Palencia', + 'Scaglione', + 'Friese', + 'Laughter', + 'Houchins', + 'Loman', + 'Garden', + 'Cromartie', + 'Borgman', + 'Hoffpauir', + 'Choquette', + 'Jarrard', + 'Fernald', + 'Barranco', + 'Levering', + 'Ansell', + 'Perl', + 'Caudell', + 'Ewen', + 'Ohanlon', + 'Swofford', + 'Reasoner', + 'Grout', + 'Rising', + 'Buttram', + 'Vandenheuvel', + 'Imel', + 'Rearick', + 'Harn', + 'Sorrels', + 'Biggins', + 'Renda', + 'Norden', + 'Matula', + 'Walch', + 'Broad', + 'Stokley', + 'Gully', + 'Barrientes', + 'Chilcote', + 'Freel', + 'Lage', + 'Farner', + 'Rubel', + 'Demko', + 'Shao', + 'Cupples', + 'Holderman', + 'Dunnam', + 'Hughs', + 'Foskey', + 'Darst', + 'Greenblatt', + 'Shiner', + 'Brasfield', + 'Simeon', + 'Maser', + 'Lacayo', + 'Priestley', + 'Pleasants', + 'Howse', + 'Iyer', + 'Perreira', + 'Baillargeon', + 'Revilla', + 'Yarger', + 'Gries', + 'Sheeley', + 'Prim', + 'Picazo', + 'Heinlein', + 'Merola', + 'Malhotra', + 'Wein', + 'Mchone', + 'Valliere', + 'Minner', + 'Blumer', + 'Hasse', + 'Kuester', + 'Landi', + 'Suits', + 'Primeaux', + 'Jarnagin', + 'Galle', + 'Greenlaw', + 'Qiu', + 'Lamarche', + 'Acheson', + 'Gothard', + 'Mendivil', + 'Bombard', + 'Mcquillen', + 'Munden', + 'Herzberg', + 'Ros', + 'Umstead', + 'Levins', + 'Pellegrin', + 'Castagna', + 'Alvord', + 'Huckins', + 'Wagnon', + 'Plemons', + 'Dolin', + 'Garica', + 'Lyttle', + 'Bazile', + 'Astudillo', + 'Gover', + 'Galati', + 'Seager', + 'Girardi', + 'Freels', + 'Bramblett', + 'Brancato', + 'Reppert', + 'Saetern', + 'Puig', + 'Prettyman', + 'Chagnon', + 'Heavner', + 'Schlichting', + 'Saladino', + 'Stall', + 'Loiselle', + 'Sedano', + 'Panos', + 'Heilig', + 'Ridgley', + 'Basilio', + 'Rapoza', + 'Furrow', + 'Oliveras', + 'Cordray', + 'Strausbaugh', + 'Culhane', + 'Iraheta', + 'Lamantia', + 'Shires', + 'Wilding', + 'Obanion', + 'Easterwood', + 'Hearns', + 'Manske', + 'Spiess', + 'Eckley', + 'Wootton', + 'Enochs', + 'Cheatwood', + 'Woodfin', + 'Akridge', + 'Mattocks', + 'Mcdougle', + 'Legette', + 'Neher', + 'Rhoton', + 'Vartanian', + 'Dunkel', + 'Wehmeyer', + 'Foutch', + 'Dille', + 'Halle', + 'Lowden', + 'Olesen', + 'Chace', + 'Hasbrouck', + 'Lesage', + 'Pappalardo', + 'Shinkle', + 'Ishii', + 'Peralez', + 'Gabler', + 'Fichter', + 'Mcnicholas', + 'Moshier', + 'Barbeau', + 'Bossert', + 'Trivett', + 'Bamford', + 'Lauterbach', + 'Gossman', + 'Epling', + 'Welk', + 'Daub', + 'Squier', + 'Dicus', + 'Siller', + 'Romaine', + 'Meriwether', + 'Bordner', + 'Baden', + 'Hagins', + 'Sica', + 'Mullane', + 'Jurgensen', + 'Tien', + 'Gertz', + 'Touchstone', + 'Bones', + 'Kimmons', + 'Prisco', + 'Kaser', + 'Drysdale', + 'Jelks', + 'Cerrone', + 'Wolfenbarger', + 'Deckert', + 'Ganley', + 'Fleeman', + 'Cubbage', + 'Woodie', + 'Schwan', + 'Siefert', + 'Rizvi', + 'Heier', + 'Khanna', + 'Leet', + 'Gratz', + 'Mullan', + 'Moorefield', + 'Fishback', + 'Whittenburg', + 'Casson', + 'Statham', + 'Red', + 'Coldiron', + 'Keplinger', + 'Reichman', + 'Brier', + 'Vavra', + 'Housman', + 'Kitson', + 'Fekete', + 'Rotella', + 'Onofre', + 'Orvis', + 'Beutler', + 'Cadwallader', + 'Gabor', + 'Emmanuel', + 'Moretz', + 'Suniga', + 'Mcmath', + 'Kinlaw', + 'Beringer', + 'Gaudreau', + 'Lirette', + 'Drye', + 'Oubre', + 'Gardella', + 'Reigle', + 'Zubia', + 'Mccardle', + 'Ambler', + 'Lucius', + 'Fizer', + 'Hilley', + 'Fischbach', + 'Borelli', + 'Gies', + 'Barks', + 'Sheard', + 'Hammontree', + 'Hogle', + 'Fagg', + 'Buitron', + 'Eiler', + 'Grandstaff', + 'Hank', + 'Wark', + 'Decoteau', + 'Depina', + 'Clabaugh', + 'Desiderio', + 'Kuchta', + 'Trang', + 'Abril', + 'Smathers', + 'Kaspar', + 'Melia', + 'Sandman', + 'Maltese', + 'Mccasland', + 'Rayl', + 'Meche', + 'Wiggin', + 'Saint', + 'Dorner', + 'Columbus', + 'Boatner', + 'Fresquez', + 'Sykora', + 'Shriner', + 'Drumheller', + 'Mahony', + 'Redinger', + 'Radloff', + 'Mitts', + 'Casperson', + 'Gammill', + 'Moraga', + 'Baratta', + 'Tow', + 'Ocon', + 'Cruce', + 'Bohannan', + 'Hurtt', + 'Mose', + 'Caines', + 'Heisey', + 'Pitcock', + 'Swiderski', + 'Shu', + 'Buda', + 'Whidden', + 'Busick', + 'Simas', + 'Croley', + 'Morrisey', + 'Saulsberry', + 'Crudup', + 'Bongiorno', + 'Beem', + 'Bunner', + 'Rosemond', + 'Freire', + 'Casado', + 'Merideth', + 'Selden', + 'Lamarre', + 'Fullwood', + 'Hartig', + 'Kerlin', + 'Lebowitz', + 'Kibbe', + 'Fannon', + 'Hotz', + 'Yerkes', + 'Re', + 'Waddington', + 'Akbar', + 'Baek', + 'Closson', + 'Miers', + 'Bonomo', + 'Wetherbee', + 'Taranto', + 'Henslee', + 'Bartle', + 'Hilger', + 'Asaro', + 'Mahr', + 'Strozier', + 'Agudelo', + 'Kulick', + 'Skoglund', + 'Yamasaki', + 'Schlemmer', + 'Hefley', + 'Waxman', + 'Radley', + 'Sanderlin', + 'Arispe', + 'Galang', + 'Morejon', + 'Stich', + 'Cesario', + 'Silvis', + 'Gurganus', + 'Shofner', + 'Funderburg', + 'Reddish', + 'Rybak', + 'Dingler', + 'Mankin', + 'Renna', + 'Alban', + 'Mckittrick', + 'Lippman', + 'Brenton', + 'Liebman', + 'Santillo', + 'Crigger', + 'Riney', + 'Mccraney', + 'Kluck', + 'Sosnowski', + 'Anspach', + 'Bourdon', + 'Modi', + 'Heer', + 'Mastroianni', + 'Musial', + 'Whiteaker', + 'Summa', + 'Herber', + 'Roselli', + 'Orris', + 'Bert', + 'Dedmon', + 'Kelson', + 'Paone', + 'Barstow', + 'Gerst', + 'Bettinger', + 'Castner', + 'Penman', + 'Broaddus', + 'Ohman', + 'Villalon', + 'Carwile', + 'Fluellen', + 'Ort', + 'Bommarito', + 'Shuff', + 'Cannata', + 'Westgate', + 'Bien', + 'Driggs', + 'Maisonet', + 'Costin', + 'Raine', + 'Banton', + 'Buterbaugh', + 'Katzman', + 'Coreas', + 'Rosalez', + 'Gose', + 'Robie', + 'Winburn', + 'Glancy', + 'Hild', + 'Strock', + 'Umanzor', + 'Hoglund', + 'Kesner', + 'Lynam', + 'Swayze', + 'Grizzard', + 'Fettig', + 'Macko', + 'Schrum', + 'Sours', + 'Yonker', + 'Ebanks', + 'Chiodo', + 'Meaney', + 'Paras', + 'Struthers', + 'Sicard', + 'Leveille', + 'Beckstead', + 'Calero', + 'Fuhrmann', + 'Lybarger', + 'Capo', + 'Adolph', + 'Raabe', + 'Gran', + 'Borel', + 'Ary', + 'Charland', + 'Huh', + 'Steinert', + 'Stemple', + 'Groat', + 'Zang', + 'Nath', + 'Ogara', + 'Pecina', + 'Simoes', + 'Breece', + 'Nascimento', + 'Usry', + 'Gain', + 'Brassfield', + 'Lochner', + 'Pietsch', + 'Wechsler', + 'Sum', + 'Teneyck', + 'Pelt', + 'Burnley', + 'Renzi', + 'Mujica', + 'Profitt', + 'Body', + 'Debusk', + 'Robidoux', + 'Pruneda', + 'Pomerantz', + 'Gonyea', + 'Crosier', + 'Currence', + 'Newborn', + 'Tolleson', + 'Conlan', + 'Dunsmore', + 'Tansey', + 'Clinard', + 'Staudt', + 'Oppenheim', + 'Gossard', + 'Osbourne', + 'Gilyard', + 'Lucido', + 'Tonkin', + 'Mitzel', + 'Sola', + 'Palombo', + 'Duane', + 'Mac', + 'Kerry', + 'Stills', + 'Viveiros', + 'Stallman', + 'Moos', + 'Follis', + 'Maris', + 'Hollier', + 'Gundlach', + 'Moler', + 'Schweigert', + 'Chartrand', + 'Finkle', + 'Meese', + 'Nigh', + 'Amundsen', + 'Brocato', + 'Dreier', + 'Glessner', + 'Weibel', + 'Fritch', + 'Retherford', + 'Rahim', + 'Markert', + 'Ronk', + 'Olmeda', + 'Gosney', + 'Keathley', + 'Luby', + 'Harrill', + 'Dinges', + 'Rocheleau', + 'Meisel', + 'Farrer', + 'Lute', + 'Apel', + 'Pincus', + 'Maida', + 'Jimmerson', + 'Baltz', + 'Cuccia', + 'Heenan', + 'Thieme', + 'Zoeller', + 'Larocco', + 'Abdalla', + 'Classen', + 'Hassinger', + 'Filler', + 'Pidgeon', + 'Hanford', + 'Espy', + 'Goodlett', + 'Jone', + 'Ruggeri', + 'Lisi', + 'Spada', + 'Gerrard', + 'Allbritton', + 'Brazelton', + 'Boggan', + 'Dufault', + 'Espejo', + 'Bodkin', + 'Penix', + 'Dockins', + 'Rascoe', + 'Swarthout', + 'Tritt', + 'Gouin', + 'Lamberth', + 'Bourn', + 'Barnhouse', + 'Guzzo', + 'Netherton', + 'Zamarron', + 'Rosenberry', + 'Dahms', + 'Anwar', + 'Whitesides', + 'Tidmore', + 'Longstreet', + 'Claunch', + 'Ehrhart', + 'Hullinger', + 'Xia', + 'Heideman', + 'Nicklas', + 'Prins', + 'Soni', + 'Dominquez', + 'Vogelsang', + 'Pew', + 'Chess', + 'Simmerman', + 'Brunell', + 'Matthes', + 'Kinnison', + 'Cansler', + 'Weekly', + 'Eger', + 'Garabedian', + 'Milliman', + 'Severns', + 'Magnusson', + 'Fossum', + 'Salamon', + 'Vandoren', + 'Gillingham', + 'Charney', + 'Nokes', + 'Lamon', + 'Irick', + 'Okeeffe', + 'Zou', + 'Kott', + 'Quillin', + 'Friar', + 'Drummer', + 'Catchings', + 'Hamada', + 'Scheck', + 'Setser', + 'Gobble', + 'Condra', + 'Bowley', + 'Deschamps', + 'Sylva', + 'Bartolome', + 'Warfel', + 'Veltri', + 'Speers', + 'Butner', + 'Delorme', + 'Giesler', + 'Sonntag', + 'Wetherell', + 'Ohagan', + 'Torbert', + 'Grandberry', + 'Ronning', + 'Howser', + 'Soden', + 'Rasco', + 'Clauss', + 'Beland', + 'Nicola', + 'Justiniano', + 'Varnum', + 'Fergus', + 'Lazcano', + 'Sartori', + 'Carnley', + 'Lucarelli', + 'Bergh', + 'Wellborn', + 'Bow', + 'Longshore', + 'Marcel', + 'Sumlin', + 'Atilano', + 'Dostal', + 'Westendorf', + 'Stiver', + 'Morency', + 'Herrod', + 'Bologna', + 'Valiente', + 'Weinert', + 'Gaertner', + 'Prock', + 'Spangenberg', + 'Tineo', + 'Cosio', + 'Maass', + 'Rist', + 'Oatman', + 'Waguespack', + 'Cardiel', + 'Grate', + 'Behrends', + 'Linger', + 'Pozo', + 'Scoggin', + 'Jenkinson', + 'Ake', + 'Redick', + 'Bonacci', + 'Rivet', + 'Declue', + 'Swing', + 'Chopra', + 'Leib', + 'Wallner', + 'Grimmer', + 'Wilmes', + 'Pirkle', + 'Stanhope', + 'Knop', + 'Culotta', + 'Dipaola', + 'Hipolito', + 'Gerling', + 'Sennett', + 'Fulghum', + 'Grothe', + 'Krout', + 'Onorato', + 'Donis', + 'Winbush', + 'Aoki', + 'Buscher', + 'Jarquin', + 'Lemanski', + 'Mcgrane', + 'Tardif', + 'Segundo', + 'Caba', + 'Sease', + 'Blinn', + 'Losee', + 'Kirschbaum', + 'Baskett', + 'Knights', + 'Goudeau', + 'Grondin', + 'Harting', + 'Szewczyk', + 'Wieder', + 'Conatser', + 'Romanelli', + 'Freshour', + 'Brizendine', + 'Rolen', + 'Guynn', + 'Laforest', + 'Doris', + 'Sandridge', + 'Dublin', + 'Blancas', + 'Duryea', + 'Naik', + 'Paradiso', + 'Scheele', + 'Westra', + 'Hassel', + 'Bertucci', + 'Fansler', + 'Flohr', + 'Solt', + 'Suess', + 'Keiper', + 'Downard', + 'Ivester', + 'Darley', + 'Seales', + 'Kolesar', + 'Overbeck', + 'Subramanian', + 'Panter', + 'Parshall', + 'Stannard', + 'Gravley', + 'Dhaliwal', + 'Shippy', + 'Dolphin', + 'Lepper', + 'Gorby', + 'Delmonte', + 'Piccirillo', + 'Besaw', + 'Alligood', + 'Rhymes', + 'Eisenman', + 'Deveau', + 'Tilden', + 'Girton', + 'Buser', + 'Rentschler', + 'Sopko', + 'Uriostegui', + 'Wasko', + 'Noffsinger', + 'Barkman', + 'Dyck', + 'Ferrero', + 'Kiehl', + 'Leffel', + 'Rybicki', + 'Hedstrom', + 'Bracamontes', + 'Zebrowski', + 'Blundell', + 'Brightman', + 'Hegwood', + 'Beecham', + 'Kolbe', + 'Bucy', + 'Bondi', + 'Borgen', + 'Gibbens', + 'Pullman', + 'Letcher', + 'Ferebee', + 'Kitterman', + 'Seefeldt', + 'Upham', + 'Thiede', + 'Bolster', + 'Bastin', + 'Bondy', + 'Mershon', + 'Nickson', + 'Drozd', + 'Schroyer', + 'Mcmenamin', + 'Reith', + 'Lovin', + 'San', + 'Henegar', + 'Haislip', + 'Barco', + 'Arter', + 'Malecki', + 'Teeple', + 'Walpole', + 'Feil', + 'Neitzel', + 'Ostler', + 'Parmar', + 'Vinton', + 'Jan', + 'Weldy', + 'Etherton', + 'Joya', + 'Saliba', + 'Schnur', + 'Belles', + 'Mcgeorge', + 'Olden', + 'Rarick', + 'Worrall', + 'Degen', + 'Froman', + 'Odowd', + 'Einhorn', + 'Fimbres', + 'Maresca', + 'Rocker', + 'Arend', + 'Biermann', + 'Guimond', + 'Mcgurk', + 'Goll', + 'Santilli', + 'Hadlock', + 'Teer', + 'Dillion', + 'Jorden', + 'Honore', + 'Bromberg', + 'Stoneman', + 'Blossom', + 'Guzik', + 'Stockstill', + 'Wax', + 'Anello', + 'Blasko', + 'Frese', + 'Berthold', + 'Morefield', + 'Baptist', + 'Legault', + 'Bouffard', + 'Bebout', + 'Darnall', + 'Buscemi', + 'Buentello', + 'Scroggs', + 'Gatton', + 'Turnquist', + 'Lucht', + 'Remick', + 'Godlewski', + 'Bradt', + 'Waldorf', + 'Zeringue', + 'Rowen', + 'Mowbray', + 'Parkey', + 'Engram', + 'Mazzarella', + 'Kirkbride', + 'Gridley', + 'Kaster', + 'Lorenzana', + 'Wareham', + 'Star', + 'Marshburn', + 'Everman', + 'Wolfram', + 'Zick', + 'Hyun', + 'Yerger', + 'Baham', + 'Gebhard', + 'Ruf', + 'Suchy', + 'Tieman', + 'Wenz', + 'Schiro', + 'Fout', + 'Abdo', + 'Hayter', + 'Cleaves', + 'Fritsche', + 'Meurer', + 'Riendeau', + 'Ventimiglia', + 'Cervera', + 'Mallow', + 'Allie', + 'Hanscom', + 'Viloria', + 'Dubon', + 'Leeson', + 'Ruffing', + 'Jonson', + 'Fenimore', + 'Gonzaga', + 'Schriver', + 'Traina', + 'Mecca', + 'Lantigua', + 'Baril', + 'Harford', + 'Bartow', + 'Asbell', + 'Rumley', + 'Brogden', + 'Derryberry', + 'Ketner', + 'Dakin', + 'Wass', + 'Fallis', + 'Wada', + 'Studdard', + 'Lecroy', + 'Fetty', + 'Nass', + 'Chute', + 'Parman', + 'Bevans', + 'Headen', + 'Hysell', + 'Merten', + 'Most', + 'Fuss', + 'Schrank', + 'Last', + 'Even', + 'Vaz', + 'Sifford', + 'Streets', + 'Claude', + 'Bronstein', + 'Sherburne', + 'Wadkins', + 'Gascon', + 'Seiter', + 'Steffan', + 'Cardozo', + 'Henricks', + 'Claflin', + 'Etzel', + 'Kulas', + 'Trinkle', + 'Ortegon', + 'Phaneuf', + 'Langworthy', + 'Barb', + 'Mazon', + 'Veney', + 'Redondo', + 'Tieu', + 'Laursen', + 'Nanez', + 'Votaw', + 'Walraven', + 'Abella', + 'Dsouza', + 'Bayley', + 'Townson', + 'Applebaum', + 'Mazzei', + 'Piche', + 'Rivenbark', + 'Urrea', + 'Dolph', + 'Bonifacio', + 'Shehan', + 'Glascock', + 'Verde', + 'Gadberry', + 'Trimm', + 'Dowe', + 'Khang', + 'Mulhall', + 'Selzer', + 'Raub', + 'Ore', + 'Copes', + 'Masuda', + 'Moscoso', + 'Zeitler', + 'Mollica', + 'Iler', + 'Leventhal', + 'Manders', + 'Prue', + 'Fergerson', + 'Brose', + 'Phu', + 'Debellis', + 'Haan', + 'Schoening', + 'Stager', + 'Demos', + 'Rumble', + 'Brunt', + 'Nivens', + 'Manigault', + 'Buendia', + 'Deschenes', + 'Wittmer', + 'Hamon', + 'Hentz', + 'Loud', + 'Oseguera', + 'Rayo', + 'Macfarland', + 'Mimms', + 'Grunewald', + 'Hartness', + 'Wynkoop', + 'Wallingford', + 'Juergens', + 'Meszaros', + 'Riehle', + 'Trego', + 'Neece', + 'Coggin', + 'Burrill', + 'Laurel', + 'Routt', + 'Rodger', + 'Krum', + 'Faulkenberry', + 'Labadie', + 'Hemming', + 'Fulp', + 'Jamal', + 'Deloney', + 'Fells', + 'Bohnert', + 'Kapadia', + 'Guill', + 'Coop', + 'Broadhurst', + 'Mccrimmon', + 'Bonfiglio', + 'Capetillo', + 'Chamorro', + 'Gargiulo', + 'Stoehr', + 'Schlecht', + 'Karlson', + 'Garten', + 'Remer', + 'Mebane', + 'Finnigan', + 'Bourdeau', + 'Espindola', + 'Shukla', + 'Petras', + 'Steinberger', + 'Casner', + 'Carico', + 'Seevers', + 'Westwood', + 'Hosea', + 'Mcphillips', + 'Nygren', + 'Wagaman', + 'Coghlan', + 'Sutherlin', + 'Sellman', + 'Bashore', + 'Mullican', + 'Stoneburner', + 'Montag', + 'Karst', + 'Murch', + 'Puffer', + 'Sabala', + 'Pauli', + 'Odonoghue', + 'Lassen', + 'Mattera', + 'Mcaninch', + 'Portugal', + 'Clingan', + 'Michener', + 'Munsell', + 'Streetman', + 'Harton', + 'Swarts', + 'Honig', + 'Jesus', + 'Rentas', + 'Trosper', + 'Coffield', + 'Burket', + 'Donaghy', + 'Byun', + 'Riess', + 'Mcqueary', + 'Stayton', + 'Ferron', + 'Wedding', + 'Tibbitts', + 'Frisbee', + 'Reinoso', + 'Lama', + 'Allyn', + 'Sheen', + 'Tyra', + 'Golder', + 'Veasey', + 'Schroth', + 'Kukla', + 'Narayan', + 'Vandemark', + 'Horace', + 'Kadlec', + 'Portnoy', + 'Reynosa', + 'Surprenant', + 'Savell', + 'Seagle', + 'Vandervort', + 'Eye', + 'Eccleston', + 'Blaise', + 'Glaspie', + 'Cressman', + 'Lahti', + 'Yocom', + 'Leppert', + 'Brendle', + 'Greenough', + 'Relyea', + 'Marinez', + 'Bouley', + 'Fincham', + 'Highley', + 'Goza', + 'Norrell', + 'Yusuf', + 'Ohm', + 'Thakkar', + 'Cosenza', + 'Efird', + 'Heger', + 'Dysart', + 'Mango', + 'Fitchett', + 'Kring', + 'Paolucci', + 'Menges', + 'Layden', + 'Mccleery', + 'Benko', + 'Sandor', + 'Blakney', + 'Zanders', + 'Gengler', + 'Fujita', + 'Huls', + 'Basquez', + 'Trepanier', + 'Spadaro', + 'Ankney', + 'Damiani', + 'Games', + 'Cherney', + 'Fitzsimons', + 'Dearmas', + 'Bonet', + 'Diem', + 'Shimp', + 'Agrawal', + 'Gaw', + 'Gahagan', + 'Fossett', + 'Kafka', + 'Dedios', + 'Coryell', + 'Bahe', + 'Wurm', + 'Wishart', + 'Dray', + 'Armer', + 'Khalid', + 'Gassaway', + 'Vawter', + 'Loew', + 'Coello', + 'Curren', + 'Gilder', + 'Letendre', + 'Sprecher', + 'Rexrode', + 'Minich', + 'Koepp', + 'Mulloy', + 'Bohman', + 'Gambrel', + 'Hackley', + 'Demasi', + 'Hoffert', + 'Kittredge', + 'Maltby', + 'Nyquist', + 'Schieber', + 'Kennell', + 'Calderwood', + 'Compean', + 'Romines', + 'Simonelli', + 'Pico', + 'Oda', + 'Holte', + 'Bate', + 'Learn', + 'Lowenstein', + 'Holtman', + 'Mingus', + 'Sessa', + 'Legendre', + 'Gerrish', + 'Schoenberg', + 'Liberman', + 'Mclachlan', + 'Higginson', + 'Vince', + 'Mallery', + 'Delamora', + 'Difranco', + 'Lein', + 'Haltom', + 'Dority', + 'Marcellus', + 'Heskett', + 'Harward', + 'Spinney', + 'Darwin', + 'Baylis', + 'Amodeo', + 'Schwandt', + 'Mcmorrow', + 'Foraker', + 'Fyfe', + 'Shingleton', + 'Blandon', + 'Waddy', + 'Ricca', + 'Scheffer', + 'Balliet', + 'Philipp', + 'Rish', + 'Hattaway', + 'Krejci', + 'Orduno', + 'Passarelli', + 'Skala', + 'Oram', + 'Raynes', + 'Hiett', + 'Tolan', + 'Kimbell', + 'Delara', + 'Farhat', + 'Kamps', + 'Mohney', + 'Escarcega', + 'Mell', + 'Mcquay', + 'Cannizzaro', + 'Deuel', + 'Losoya', + 'Goldin', + 'Zaidi', + 'Gillmore', + 'Buelow', + 'Maust', + 'Guerrera', + 'Bouck', + 'Bick', + 'Kelty', + 'Pines', + 'Braziel', + 'Bruening', + 'Frenzel', + 'Kenna', + 'Loria', + 'Koren', + 'Cornelio', + 'Poisson', + 'Raker', + 'Ptak', + 'Bohr', + 'Coury', + 'Failla', + 'Cipriani', + 'Delany', + 'Marmon', + 'Kinch', + 'Figgins', + 'Delfino', + 'Risser', + 'Hickox', + 'Fager', + 'Turpen', + 'Dalzell', + 'Falvey', + 'Leiker', + 'Mcgonigal', + 'Vaquera', + 'Weisser', + 'Viviano', + 'Shrock', + 'Minaya', + 'Chitty', + 'Costley', + 'Granberry', + 'Dimaria', + 'Roma', + 'Ortis', + 'Burnam', + 'Burruss', + 'Stoughton', + 'Cales', + 'Burrage', + 'Vanwagner', + 'Espada', + 'Mccuen', + 'Baize', + 'Pullum', + 'Gerrity', + 'Vicari', + 'Heuser', + 'Semler', + 'Fear', + 'Havener', + 'Kash', + 'Thibodaux', + 'Hadaway', + 'Smithwick', + 'Eisenhart', + 'Hodgin', + 'Cluck', + 'Godby', + 'Belli', + 'Demaree', + 'Beyers', + 'Jared', + 'Mall', + 'Defoe', + 'Chmura', + 'Hepworth', + 'Hintze', + 'Luk', + 'Vanriper', + 'Solari', + 'Atlas', + 'Outland', + 'Hanselman', + 'Scharff', + 'Rhein', + 'Milone', + 'Rochford', + 'Mynatt', + 'Lambdin', + 'Sandell', + 'Grounds', + 'Tabler', + 'Smartt', + 'Dejean', + 'Clayborne', + 'Vangorder', + 'Eastin', + 'Hiler', + 'Lisle', + 'Gramling', + 'Degarmo', + 'Malec', + 'Tinkham', + 'Vanauken', + 'Andrzejewski', + 'Rundell', + 'Happel', + 'Strine', + 'Koerber', + 'Haner', + 'Ashcroft', + 'Hille', + 'Cairo', + 'Upson', + 'Mooring', + 'Koury', + 'Vito', + 'Oberlin', + 'Christiano', + 'Redfearn', + 'Trower', + 'Hibbler', + 'Sumter', + 'Raftery', + 'Geise', + 'Wohl', + 'Gorney', + 'Peasley', + 'Heap', + 'Brazeal', + 'Mccleskey', + 'Yard', + 'Mcroy', + 'Amend', + 'Cutshaw', + 'Kazmierczak', + 'Strandberg', + 'Lasko', + 'Newlon', + 'File', + 'Bevill', + 'Silvera', + 'Arakaki', + 'Kelsch', + 'Ostendorf', + 'Cowie', + 'Hove', + 'Doles', + 'Bouvier', + 'Fecteau', + 'Hasegawa', + 'Paschke', + 'Taing', + 'Heldt', + 'Allaire', + 'Ochsner', + 'Giusti', + 'Reisner', + 'Swim', + 'Laidlaw', + 'Vanderbilt', + 'Atterberry', + 'Barthelemy', + 'Chalker', + 'Degregorio', + 'Mastro', + 'Patlan', + 'Gipe', + 'Roosa', + 'Filkins', + 'Styron', + 'Bryer', + 'Blackston', + 'Hagel', + 'Fralick', + 'Linhart', + 'Moura', + 'Pavia', + 'Pavao', + 'Furry', + 'Petrus', + 'Fairweather', + 'Blystone', + 'Co', + 'Divito', + 'Villicana', + 'Winch', + 'Tome', + 'Lanoue', + 'Biron', + 'Noell', + 'Mckeel', + 'Worthey', + 'Aten', + 'Eyer', + 'Zhen', + 'Tischler', + 'Luoma', + 'Opp', + 'Riggin', + 'Furness', + 'Wolbert', + 'Penning', + 'Draves', + 'Whitehill', + 'Dudgeon', + 'Kinkead', + 'Luca', + 'Rosell', + 'Macauley', + 'Goldner', + 'Ishikawa', + 'Kirchhoff', + 'Lamarca', + 'Miyashiro', + 'Weger', + 'Wuest', + 'Kreis', + 'Urbanek', + 'Palko', + 'Victorino', + 'Morado', + 'Burchette', + 'Holyfield', + 'Tulloch', + 'Twombly', + 'Munk', + 'Woolford', + 'Knisely', + 'Locher', + 'Eckart', + 'Rancourt', + 'Pyron', + 'Edney', + 'Besser', + 'Truex', + 'Monterroso', + 'Bruneau', + 'Province', + 'Permenter', + 'Nims', + 'Rollison', + 'Cabell', + 'Sylvain', + 'Salman', + 'Signorelli', + 'Vegas', + 'Maddy', + 'Bachelder', + 'Sevigny', + 'Stolte', + 'Chavarin', + 'Lukes', + 'Rather', + 'Gartland', + 'Kurek', + 'Nantz', + 'Savard', + 'Finegan', + 'No', + 'Chichester', + 'Newbill', + 'Mahnke', + 'Sax', + 'Sowinski', + 'Wendler', + 'Cadiz', + 'Male', + 'Mealey', + 'Brookes', + 'Enderle', + 'Valenta', + 'Tooker', + 'Whitbeck', + 'Threet', + 'Cavitt', + 'Murtagh', + 'Phalen', + 'Errico', + 'Merkley', + 'Ju', + 'Zachery', + 'Bramer', + 'Henline', + 'Noga', + 'Woelfel', + 'Deras', + 'Amen', + 'Aldape', + 'Bartling', + 'Claros', + 'Spurrier', + 'Ginder', + 'Fred', + 'Giberson', + 'Ryba', + 'Sommerfeld', + 'Dahle', + 'Endo', + 'Haddon', + 'Bowlby', + 'Wagener', + 'Ketter', + 'Balint', + 'Goheen', + 'Motsinger', + 'Celentano', + 'Drawdy', + 'Dennehy', + 'Mcelligott', + 'Nakamoto', + 'Deines', + 'Goldsby', + 'Drakeford', + 'Steffy', + 'Streich', + 'Villasana', + 'Cermak', + 'Prill', + 'Ellzey', + 'Gartrell', + 'Duffie', + 'Rother', + 'Buse', + 'Luz', + 'Groen', + 'Laviolette', + 'Roles', + 'Days', + 'Eash', + 'Haefner', + 'Font', + 'Mcree', + 'Bustillo', + 'Coughlan', + 'Bax', + 'Hoxie', + 'Barre', + 'Scaife', + 'Nowacki', + 'Reichardt', + 'Rogel', + 'Ivins', + 'Vanderburg', + 'Etchison', + 'Chesson', + 'Molden', + 'Giuliani', + 'Goodpaster', + 'Kriner', + 'Sturtz', + 'Tschida', + 'Henschel', + 'Asselin', + 'Kocsis', + 'Kroger', + 'Swayne', + 'Gallop', + 'Fraker', + 'Lauro', + 'Tuohy', + 'Scholes', + 'Croxton', + 'Fertig', + 'Gregerson', + 'Gundersen', + 'Lehrer', + 'Monsivais', + 'Pilla', + 'Weishaar', + 'Gutshall', + 'Winget', + 'Human', + 'Oberry', + 'Learned', + 'Marburger', + 'Teed', + 'Parrilla', + 'Due', + 'Hartzler', + 'Cieslak', + 'Feltz', + 'Geren', + 'Wile', + 'Waldrip', + 'Clore', + 'Stutler', + 'Feehan', + 'Lacher', + 'Felter', + 'Barakat', + 'Flippen', + 'Holsey', + 'Finkbeiner', + 'Istre', + 'Lengyel', + 'Lupercio', + 'Beegle', + 'Habel', + 'Hammill', + 'Kifer', + 'Buswell', + 'Deboard', + 'Guilliams', + 'Ahlstrom', + 'Beliveau', + 'Sasse', + 'Delker', + 'Letterman', + 'Avey', + 'Bohlen', + 'Piner', + 'Folmar', + 'Barile', + 'Komar', + 'Bonelli', + 'Lamay', + 'Cora', + 'Deere', + 'Sanon', + 'Deppe', + 'Emmerich', + 'Giannone', + 'Navarra', + 'Hudock', + 'Seaborn', + 'Burda', + 'Faz', + 'Stefani', + 'Beemer', + 'Vose', + 'Calandra', + 'Eno', + 'Figueredo', + 'Lauck', + 'Schwindt', + 'Dumais', + 'Hedger', + 'Capp', + 'Barreiro', + 'Buker', + 'Spruell', + 'Bertolini', + 'Hoar', + 'Tiemann', + 'Vandenbosch', + 'Winebrenner', + 'Maio', + 'Winship', + 'Brissette', + 'Hansell', + 'Elsey', + 'Hansard', + 'Gildersleeve', + 'Hambright', + 'Borba', + 'Konieczny', + 'Lundell', + 'Tiedemann', + 'Siegler', + 'Ying', + 'Mckinsey', + 'Olah', + 'Boersma', + 'Younkin', + 'Evanoff', + 'Nakashima', + 'Scalia', + 'Piro', + 'Colorado', + 'Felan', + 'Fuentez', + 'Blea', + 'Gowin', + 'Hanning', + 'Byrom', + 'Morant', + 'Bachand', + 'Mcsorley', + 'Peaslee', + 'Bardsley', + 'Stilson', + 'Severs', + 'Kincheloe', + 'Kyler', + 'Aurand', + 'Bento', + 'Hoeppner', + 'Mertes', + 'Pickrell', + 'Rustad', + 'Millikan', + 'Celestino', + 'Hovland', + 'Kurowski', + 'Zollinger', + 'Tallon', + 'Junkins', + 'Mizrahi', + 'Bomberger', + 'Farrand', + 'Curto', + 'Bona', + 'Donatelli', + 'Eppley', + 'Schurman', + 'Henao', + 'Tomberlin', + 'Provencio', + 'Speidel', + 'Cree', + 'Inskeep', + 'Yeates', + 'Hoggatt', + 'Hinkson', + 'Ficklin', + 'Mcnealy', + 'Cabanas', + 'Laycock', + 'Theroux', + 'Weymouth', + 'Mabie', + 'Hatchell', + 'Bohanon', + 'Bilger', + 'Nazarian', + 'Weist', + 'Depue', + 'Mangini', + 'Gelb', + 'Luman', + 'Blass', + 'Desroches', + 'Hearon', + 'Mcmiller', + 'Stoltenberg', + 'Parenti', + 'Daulton', + 'Smail', + 'Chisum', + 'Benefiel', + 'Tetrault', + 'Foland', + 'Reddington', + 'Mattei', + 'Custis', + 'Fransen', + 'Zylstra', + 'Salvaggio', + 'Factor', + 'Deshong', + 'Biederman', + 'Sirianni', + 'Steckler', + 'Thrall', + 'Dorsch', + 'Harpe', + 'Tell', + 'Galusha', + 'Guttman', + 'Raposa', + 'Jaros', + 'Lipka', + 'Shive', + 'Shand', + 'Brizuela', + 'Horvat', + 'Pisciotta', + 'Sorge', + 'Riebe', + 'Vanderlaan', + 'Isenhour', + 'Franson', + 'Goslin', + 'Amore', + 'Leachman', + 'Foulks', + 'Alamillo', + 'Scarpa', + 'Tickle', + 'Pettitt', + 'Orrell', + 'Fleckenstein', + 'Sapien', + 'Roye', + 'Mcmeans', + 'Sligh', + 'Landgraf', + 'Cecere', + 'Aune', + 'Ketron', + 'Welcher', + 'Tilford', + 'Maston', + 'Overall', + 'Fails', + 'Bah', + 'Ketterman', + 'Lindauer', + 'Saxe', + 'Majka', + 'Goodenough', + 'Panella', + 'Ramm', + 'Caley', + 'Christine', + 'Kinsler', + 'Pippen', + 'Murph', + 'Ammann', + 'Falkowski', + 'Madonna', + 'Seligman', + 'Rommel', + 'Lareau', + 'Melone', + 'Frasure', + 'Joyal', + 'Piekarski', + 'Porcelli', + 'Kennington', + 'Pica', + 'Ankrom', + 'Capron', + 'Chatmon', + 'Horrigan', + 'Morelos', + 'Noren', + 'Paolini', + 'Wildermuth', + 'Rossow', + 'Dorgan', + 'Pawlik', + 'Reiber', + 'Rothenberger', + 'Mcgonigle', + 'Oren', + 'Jeans', + 'Vivas', + 'Gerner', + 'Brzozowski', + 'Croyle', + 'Klick', + 'Vidaurri', + 'Wollman', + 'Brouillard', + 'Dejohn', + 'Meikle', + 'Grochowski', + 'Kaczor', + 'Philbin', + 'Sperber', + 'Vancil', + 'Zornes', + 'Strope', + 'Housel', + 'Minks', + 'Dike', + 'Jasmin', + 'Denicola', + 'Gokey', + 'Dominy', + 'Gillham', + 'Viray', + 'Herz', + 'Hursh', + 'Koeller', + 'Caicedo', + 'Near', + 'Harrel', + 'Veale', + 'Gustavson', + 'Lopiccolo', + 'Goldschmidt', + 'Loder', + 'Vannorman', + 'Maske', + 'Randel', + 'Pinner', + 'Buntin', + 'Roache', + 'Pinnock', + 'Dimaio', + 'Heckert', + 'Perrigo', + 'Schank', + 'Lisowski', + 'Brownstein', + 'Sharer', + 'Hambleton', + 'Maker', + 'Hursey', + 'Aguado', + 'Tian', + 'Rheaume', + 'Becraft', + 'Sowders', + 'Bratt', + 'Tebo', + 'Eid', + 'Reinecke', + 'Storck', + 'Pech', + 'Alspaugh', + 'Grell', + 'Purdue', + 'Jennette', + 'Pauling', + 'Wint', + 'Knupp', + 'Madewell', + 'Schwanke', + 'Tellier', + 'Washer', + 'Staff', + 'Keely', + 'Lisenby', + 'Walder', + 'Kennerly', + 'Ip', + 'Michalik', + 'Eichner', + 'Disbrow', + 'Bellomy', + 'Boesch', + 'Chirico', + 'Lietz', + 'Ploof', + 'Dyar', + 'Bai', + 'Lary', + 'Corbo', + 'Danaher', + 'Schiavo', + 'Giacalone', + 'Pentz', + 'Studley', + 'Doyal', + 'Edie', + 'Nathaniel', + 'Cambra', + 'Fenstermacher', + 'Garst', + 'Gaudio', + 'Zavaleta', + 'Castilla', + 'Griffeth', + 'Warthen', + 'Derringer', + 'Samsel', + 'Mattia', + 'Boelter', + 'Mathieson', + 'Estelle', + 'Frisk', + 'Hipple', + 'Garceau', + 'Ehrman', + 'Buchner', + 'Frailey', + 'Ganey', + 'Belser', + 'Leiby', + 'Schwind', + 'Hagberg', + 'Hooley', + 'Rafter', + 'Hasting', + 'Mcnab', + 'Piggott', + 'Millhouse', + 'Brescia', + 'Giancola', + 'Grob', + 'Uresti', + 'Tawney', + 'Huot', + 'Mizer', + 'Storrs', + 'Shobe', + 'Blade', + 'Baumbach', + 'Eppler', + 'Henningsen', + 'Kmetz', + 'Sepeda', + 'Pangburn', + 'Falgout', + 'Hurn', + 'Sholar', + 'Kendricks', + 'Brimhall', + 'Bucklin', + 'Hruby', + 'Hunziker', + 'Krenz', + 'Schwager', + 'Murley', + 'Crittendon', + 'Broady', + 'Kintz', + 'Entrekin', + 'Estey', + 'Sharrow', + 'Quarterman', + 'Gumbs', + 'Steely', + 'Machin', + 'Difiore', + 'Desch', + 'Wiedemann', + 'Tonn', + 'Villines', + 'Mcdole', + 'Bashir', + 'Beauford', + 'Crary', + 'Gallina', + 'Wolak', + 'Aburto', + 'Hasler', + 'Gullion', + 'Bracewell', + 'Rusher', + 'Sarvis', + 'Dargan', + 'Garbarino', + 'Pigeon', + 'Blasi', + 'Viens', + 'Reising', + 'Vosburgh', + 'Canipe', + 'Mcnett', + 'Bruss', + 'Shiflet', + 'Pinard', + 'Lattin', + 'Armbrust', + 'Peffer', + 'Shotts', + 'Arbaugh', + 'Hux', + 'First', + 'Bolds', + 'Ceaser', + 'Cephas', + 'Bormann', + 'Broadwell', + 'Qian', + 'Talamantez', + 'Vandermolen', + 'Maza', + 'Kinnear', + 'Bullins', + 'Arant', + 'Brodbeck', + 'Rolfes', + 'Wisneski', + 'Dague', + 'Dudas', + 'Greener', + 'Noguera', + 'Greeno', + 'Daddario', + 'Giambrone', + 'Menon', + 'Sherrick', + 'Spier', + 'Semon', + 'Fendley', + 'Crichton', + 'Moree', + 'Stratford', + 'Zobel', + 'Halladay', + 'Keesler', + 'Prewett', + 'Deavers', + 'Kamal', + 'Bottom', + 'Caves', + 'Harshaw', + 'Fretz', + 'Secord', + 'Seibold', + 'Pantaleon', + 'Greek', + 'Baumeister', + 'Kleven', + 'Kos', + 'Orban', + 'Papke', + 'Shatto', + 'Cui', + 'Boan', + 'Nevitt', + 'Hultgren', + 'Kreiser', + 'Veres', + 'Jent', + 'Merck', + 'Gibby', + 'Hosch', + 'Mallet', + 'Dock', + 'Dallman', + 'Loiacono', + 'Tetzlaff', + 'Arboleda', + 'Mclelland', + 'Willing', + 'Coonrod', + 'Cappiello', + 'Courtemanche', + 'Halperin', + 'Odegard', + 'Hornyak', + 'Stem', + 'Doner', + 'Saffold', + 'Hochman', + 'Ing', + 'Knudtson', + 'Laabs', + 'Selleck', + 'Bassler', + 'Kamin', + 'Hur', + 'Forward', + 'Finnie', + 'Blubaugh', + 'Hitz', + 'Litteral', + 'Mansur', + 'Rosenow', + 'Vermeulen', + 'Markarian', + 'Marceau', + 'Weisner', + 'Sharpless', + 'Cunniff', + 'Guilfoyle', + 'Lauver', + 'Lukasik', + 'Ripp', + 'Wierzbicki', + 'Wunsch', + 'Boothby', + 'Selfridge', + 'Mckey', + 'Vandermeer', + 'Vanhoy', + 'Edlund', + 'Eggen', + 'Bickett', + 'Hallum', + 'Brow', + 'Rhymer', + 'Buckalew', + 'Haughey', + 'Hentges', + 'Matthies', + 'Mccloy', + 'Simmon', + 'Concha', + 'Feingold', + 'Maglio', + 'Olaughlin', + 'Tassone', + 'Abbasi', + 'Oyola', + 'Mook', + 'Makin', + 'Carnegie', + 'Yue', + 'Sethi', + 'Duchene', + 'Mcnear', + 'Bartolo', + 'Hegedus', + 'Knoblauch', + 'Orner', + 'Hottinger', + 'Lovitt', + 'Harkless', + 'Anastasio', + 'Hohmann', + 'Mangione', + 'Dalby', + 'Urich', + 'Shuttleworth', + 'Guilbeau', + 'Bausch', + 'Demartini', + 'Difrancesco', + 'Schwalm', + 'Steere', + 'Guel', + 'Blanford', + 'Flax', + 'Fearon', + 'Severe', + 'Canto', + 'Krogh', + 'Meola', + 'Dykema', + 'Angelini', + 'Pooley', + 'Raff', + 'Rister', + 'Baehr', + 'Daubert', + 'Dechant', + 'Kliewer', + 'Hamdan', + 'Gaiser', + 'Lichty', + 'Pomerleau', + 'Uhler', + 'Membreno', + 'Printz', + 'Worman', + 'Thornley', + 'Burbridge', + 'Burdge', + 'Schnitzer', + 'Swanberg', + 'Steinkamp', + 'Heidel', + 'Karch', + 'Igo', + 'Mccausland', + 'Huskins', + 'Kuss', + 'Newbern', + 'Peete', + 'Godbolt', + 'Climer', + 'Neuenschwander', + 'Then', + 'Tietjen', + 'Trombetta', + 'Hawke', + 'Hazlewood', + 'Mayse', + 'Patillo', + 'Banos', + 'Kuck', + 'Lashbrook', + 'Sarkisian', + 'Goldberger', + 'Moravec', + 'Arey', + 'Crosswhite', + 'Elders', + 'Fricks', + 'Hercules', + 'Bester', + 'Erhart', + 'Kuper', + 'Sickels', + 'Mun', + 'Beddingfield', + 'Panetta', + 'Poplawski', + 'Lansford', + 'Negri', + 'Dawe', + 'Belair', + 'Lattimer', + 'Betty', + 'Raye', + 'Gobert', + 'Dragoo', + 'Horney', + 'Strawbridge', + 'Howery', + 'Bosarge', + 'Panzer', + 'Labrador', + 'Ransdell', + 'Trumbo', + 'Aubry', + 'Fenderson', + 'Fukuda', + 'Grosz', + 'Jacome', + 'Slick', + 'Kogut', + 'Haig', + 'Fouse', + 'Hufnagel', + 'Kehr', + 'Musselwhite', + 'Otwell', + 'Raddatz', + 'Oliverio', + 'Sluss', + 'Crossen', + 'Guidroz', + 'Mollett', + 'Sumler', + 'Chmiel', + 'Guinan', + 'Vita', + 'Wieser', + 'Ohlson', + 'Bubb', + 'Stennett', + 'Bugbee', + 'Minchew', + 'Grado', + 'Calcagno', + 'Losh', + 'Witzel', + 'Brandl', + 'Geoghegan', + 'Vanbrunt', + 'Smalling', + 'Carignan', + 'Schuelke', + 'Sienkiewicz', + 'Sollars', + 'Dames', + 'Malkin', + 'Rodriges', + 'Rozanski', + 'Tews', + 'Aust', + 'Bardin', + 'Voorhies', + 'Rines', + 'Courts', + 'Bannerman', + 'Martinsen', + 'Malick', + 'Collar', + 'Twilley', + 'Freiberg', + 'Latiolais', + 'Zehnder', + 'Mannon', + 'Becnel', + 'Cowans', + 'Arrigo', + 'Crago', + 'Curtsinger', + 'Gassman', + 'Marcelo', + 'Rosendahl', + 'Benito', + 'Cortright', + 'Carlon', + 'Kenton', + 'Hemminger', + 'Martinek', + 'Galeana', + 'Cobble', + 'Ruffino', + 'Wittrock', + 'Aberle', + 'Catanese', + 'Huezo', + 'Soules', + 'Ashraf', + 'Mera', + 'Gash', + 'Agnello', + 'Hauk', + 'Hayek', + 'Rahm', + 'Higham', + 'Kondo', + 'Almon', + 'Earwood', + 'Kriebel', + 'Philbrook', + 'Rimer', + 'Cuffee', + 'Wolfgram', + 'Wardwell', + 'Ridder', + 'Runner', + 'Houchens', + 'Vasser', + 'Charlesworth', + 'Dierks', + 'Molter', + 'Orosz', + 'Roudebush', + 'Coca', + 'Brost', + 'Lovern', + 'Brott', + 'Baudoin', + 'Prophet', + 'Bermea', + 'Ulm', + 'Bahl', + 'Ulery', + 'Caraveo', + 'Maez', + 'Corchado', + 'Baillie', + 'Colmenero', + 'Rebolledo', + 'Shevlin', + 'Mehaffey', + 'Hedin', + 'Pickell', + 'Spiro', + 'Coatney', + 'Gentner', + 'Fuhr', + 'Zeh', + 'Fuerte', + 'Knerr', + 'Nakata', + 'Voll', + 'Zach', + 'Gatica', + 'Rabalais', + 'Macek', + 'Petti', + 'Dickison', + 'Sheley', + 'Kinner', + 'Effinger', + 'Axelson', + 'Overbay', + 'Vancleve', + 'Speegle', + 'Muntz', + 'Sang', + 'Mcleroy', + 'Aleshire', + 'Holdridge', + 'Knouse', + 'Saling', + 'Zacher', + 'Zambrana', + 'Neblett', + 'Cichon', + 'Herdman', + 'Poli', + 'Schisler', + 'Antrim', + 'Babineau', + 'Coplin', + 'Straughn', + 'Watlington', + 'Burbach', + 'Campanelli', + 'Coletta', + 'Tennis', + 'Dymond', + 'Darosa', + 'Chard', + 'Delcampo', + 'Lyden', + 'Piland', + 'Eslick', + 'Beets', + 'Ransome', + 'Schuett', + 'Styers', + 'Fegley', + 'Corning', + 'Crume', + 'Villeneuve', + 'Schmeling', + 'Zeiger', + 'Blaker', + 'Ramsden', + 'Carol', + 'Roseboro', + 'Egner', + 'Filip', + 'Poitras', + 'Flanery', + 'Cothren', + 'Bridger', + 'Hoose', + 'Demas', + 'Kozel', + 'Marzano', + 'Penwell', + 'Rast', + 'Whicker', + 'Haslett', + 'Bibby', + 'Keese', + 'Montilla', + 'Sultana', + 'Resendes', + 'Vanscoy', + 'Dinan', + 'Bala', + 'Dirksen', + 'Ek', + 'Shimer', + 'Doshi', + 'Mayeux', + 'Streater', + 'Dattilo', + 'Marlar', + 'Senft', + 'Vanalstine', + 'Rehberg', + 'Vanderhoff', + 'Brenes', + 'Motto', + 'Sproles', + 'Toone', + 'Royall', + 'Beaudette', + 'Belding', + 'Berta', + 'Carmean', + 'Simonian', + 'Avera', + 'Martina', + 'Kind', + 'Buchheit', + 'Corrao', + 'Crumrine', + 'Wertman', + 'Lininger', + 'Pressman', + 'Slane', + 'Manges', + 'Theus', + 'Canizales', + 'Eugenio', + 'Ferrigno', + 'Ellard', + 'Stilley', + 'Crabbe', + 'Procter', + 'Baccus', + 'Hellmann', + 'Risk', + 'Schild', + 'Tostado', + 'Fessenden', + 'Glines', + 'Perone', + 'Carns', + 'Belote', + 'Deshotel', + 'Bottomley', + 'Delbosque', + 'Dubinsky', + 'Flinchum', + 'Berlanga', + 'Darland', + 'Daniele', + 'Jess', + 'Mungia', + 'Harlin', + 'Rocca', + 'Saltsman', + 'Trovato', + 'Dionisio', + 'Erbe', + 'Dauzat', + 'Laferriere', + 'Kear', + 'Brannigan', + 'Guard', + 'Roquemore', + 'Brehmer', + 'Kappes', + 'Kepley', + 'Labounty', + 'Sudol', + 'Walburn', + 'Bibeau', + 'Euler', + 'Brawn', + 'Pilot', + 'Bunger', + 'Earnhardt', + 'Fischetti', + 'Buitrago', + 'Calo', + 'Surette', + 'Martyn', + 'Tollett', + 'Tuller', + 'Noakes', + 'Marson', + 'Bongiovanni', + 'Novello', + 'Werling', + 'Wyland', + 'Palen', + 'Sigmund', + 'Salzer', + 'Abels', + 'Penson', + 'Cazarez', + 'Diblasi', + 'Jantzen', + 'Kittleson', + 'Hurlbert', + 'Shepardson', + 'Munz', + 'Bozek', + 'Woll', + 'Forth', + 'Colvard', + 'Baginski', + 'Beirne', + 'Lemmer', + 'Shover', + 'Lucci', + 'Hockensmith', + 'Mayhall', + 'Faucette', + 'Soloman', + 'Lembo', + 'Tarnowski', + 'Westerlund', + 'Gossage', + 'Bold', + 'Davi', + 'Crater', + 'Saia', + 'Spisak', + 'Zerr', + 'Penate', + 'Piel', + 'Raja', + 'Farney', + 'Cutrer', + 'Liverman', + 'Brar', + 'Nocera', + 'Coutu', + 'Rishel', + 'Spurr', + 'Kail', + 'Molino', + 'Favreau', + 'Mullinix', + 'Pospisil', + 'Rohloff', + 'Slavens', + 'Stumbo', + 'Ahl', + 'Hosking', + 'Speaker', + 'Tarkington', + 'Majeski', + 'Skoog', + 'Kirch', + 'Vannostrand', + 'Olmo', + 'Dorrell', + 'Newcombe', + 'Halls', + 'Riffel', + 'Luque', + 'Rolston', + 'Lokey', + 'Nicholes', + 'Gula', + 'Schrage', + 'Goshorn', + 'Woodell', + 'Ahmadi', + 'Austria', + 'Shaul', + 'Berwick', + 'Graczyk', + 'Lacourse', + 'Porcaro', + 'Rexroad', + 'Chrzanowski', + 'Abele', + 'Woodin', + 'Gillan', + 'Lone', + 'Orzechowski', + 'Fader', + 'Regina', + 'Ban', + 'Morriss', + 'Rickards', + 'Gannaway', + 'Tassin', + 'Accardi', + 'Engelke', + 'Kruk', + 'Mantilla', + 'Soderstrom', + 'Kriz', + 'Cantley', + 'Cangelosi', + 'Kalin', + 'Sobolewski', + 'Prinz', + 'Bessey', + 'Chittum', + 'Marcucci', + 'Annunziata', + 'Hegg', + 'Mishra', + 'Heppner', + 'Benningfield', + 'Rhoten', + 'Smolen', + 'Lewellyn', + 'Tall', + 'Comiskey', + 'Gobel', + 'Klump', + 'Stauber', + 'Tocci', + 'Gosser', + 'Tussey', + 'Summitt', + 'Ottman', + 'Vester', + 'Pasko', + 'Latshaw', + 'Kies', + 'Valderrama', + 'Leese', + 'Orduna', + 'Gilcrease', + 'Alli', + 'Berberich', + 'Delariva', + 'Harb', + 'Schmuck', + 'Spang', + 'Uecker', + 'Garfinkel', + 'Mcalexander', + 'Monty', + 'Leonetti', + 'Knipe', + 'Loudon', + 'Leisure', + 'Swearengin', + 'Tinnin', + 'Engelmann', + 'Noblitt', + 'Ruhland', + 'Shewmaker', + 'Smetana', + 'Vangundy', + 'Yzaguirre', + 'Nehls', + 'Sullens', + 'Mahurin', + 'Ferman', + 'Lenhardt', + 'Littman', + 'Udell', + 'Coutts', + 'Mcginness', + 'Nakayama', + 'Goguen', + 'Lass', + 'Tibbits', + 'Pafford', + 'Fett', + 'Ruis', + 'Trogdon', + 'Tarleton', + 'Isabell', + 'Paylor', + 'Grandison', + 'Bejar', + 'Highfield', + 'Peplinski', + 'Hammitt', + 'Mitton', + 'Dashiell', + 'Turrentine', + 'Rusin', + 'Sheeran', + 'Barrs', + 'Grund', + 'Kowalsky', + 'Mccaughey', + 'Orantes', + 'Oshields', + 'Tourville', + 'Szymczak', + 'Gagner', + 'Kemble', + 'Delangel', + 'Kaler', + 'Treanor', + 'Deems', + 'Ours', + 'Loss', + 'Remley', + 'Welles', + 'Bogardus', + 'Feher', + 'Grzybowski', + 'Meinert', + 'Mickelsen', + 'Opitz', + 'Osowski', + 'Paglia', + 'Srivastava', + 'Hirata', + 'Vandermark', + 'Maggi', + 'Gautreau', + 'Fonte', + 'Meck', + 'Mcquinn', + 'Criddle', + 'Hulin', + 'Fulmore', + 'Baldino', + 'Neugebauer', + 'Sletten', + 'Talcott', + 'Tessmer', + 'Vrooman', + 'Whitlatch', + 'Miano', + 'Arauz', + 'Lafon', + 'Cashin', + 'Carrow', + 'Feely', + 'Provo', + 'Botsford', + 'Chojnacki', + 'Pritts', + 'Duby', + 'Danos', + 'Mundo', + 'Strum', + 'Bealer', + 'Barmore', + 'Birkholz', + 'Hedgecock', + 'Vides', + 'Mcjunkin', + 'Paley', + 'Dennie', + 'Cosey', + 'Trombly', + 'Wagar', + 'Tope', + 'Venters', + 'Neptune', + 'Allshouse', + 'Kuczynski', + 'Beams', + 'Kilbourne', + 'Troxler', + 'Mcgahee', + 'Latson', + 'Miraglia', + 'Suda', + 'Prall', + 'Searls', + 'Tevis', + 'Vales', + 'Coberly', + 'Eichman', + 'Hiltz', + 'Mancera', + 'Mrozek', + 'Obermeyer', + 'Wiedeman', + 'Yoshimura', + 'Pascucci', + 'Denk', + 'Pita', + 'Abdul', + 'Schurr', + 'Huntoon', + 'Sund', + 'Blose', + 'Agostini', + 'Cogdell', + 'Hamburger', + 'Orwig', + 'Pelley', + 'Mcnelly', + 'Litten', + 'Osterberg', + 'Zepp', + 'Mathur', + 'Ardon', + 'Petre', + 'Schroeter', + 'Christoff', + 'Ridenhour', + 'Hibler', + 'Coachman', + 'Tadeo', + 'Vanderploeg', + 'Ference', + 'Connery', + 'Albro', + 'Bublitz', + 'Fagundes', + 'Purpura', + 'Deeb', + 'Melzer', + 'Haus', + 'Huffine', + 'Groner', + 'Laforce', + 'Burriss', + 'Longino', + 'Seldon', + 'Chicoine', + 'Neira', + 'Pintor', + 'Trager', + 'Garg', + 'Camilleri', + 'Limbaugh', + 'Marinello', + 'Sanz', + 'Hankey', + 'Aylor', + 'Homes', + 'Marro', + 'Stalder', + 'Creasey', + 'Blankinship', + 'Waldrup', + 'Aubert', + 'Quintanar', + 'Tarbell', + 'Mayton', + 'Baba', + 'Voltz', + 'Cuba', + 'Bracco', + 'Dimeo', + 'Cauble', + 'Rodela', + 'Sambrano', + 'Doten', + 'Jobes', + 'Laura', + 'Farrier', + 'Mixson', + 'Bassi', + 'Kroening', + 'Papineau', + 'Scheuerman', + 'Zertuche', + 'Cardella', + 'Taube', + 'Bazzi', + 'Sautter', + 'Tobon', + 'Venditti', + 'Nordman', + 'Loken', + 'Fortino', + 'Godbout', + 'Knaub', + 'Larabee', + 'Meserve', + 'Slama', + 'Junge', + 'Stamand', + 'Daigneault', + 'Fredericksen', + 'Loveall', + 'Clothier', + 'Kuehne', + 'Delahoussaye', + 'Bosquez', + 'Hildenbrand', + 'Muto', + 'Vanvliet', + 'Frederiksen', + 'Mero', + 'Rapier', + 'Feldt', + 'Mcpartland', + 'Stegner', + 'Veenstra', + 'Yeater', + 'Yeatts', + 'Rosenbloom', + 'Shepperd', + 'Marchbanks', + 'Tapscott', + 'Baynard', + 'Osby', + 'Cumberbatch', + 'Brassard', + 'Dahlman', + 'Doi', + 'Katona', + 'Niesen', + 'Slavik', + 'Macneill', + 'Marsala', + 'Fazekas', + 'Cudd', + 'Ocana', + 'Brimer', + 'Lachman', + 'Balla', + 'Shahid', + 'Gammage', + 'Canez', + 'Fickes', + 'Goldblatt', + 'Mcgeehan', + 'Westerberg', + 'Legler', + 'Stanberry', + 'Hillery', + 'Colosimo', + 'Florek', + 'Heckathorn', + 'Lenart', + 'Mcneilly', + 'Viles', + 'Davin', + 'Pierro', + 'Edman', + 'Patron', + 'Tipps', + 'Ardis', + 'Hassen', + 'Crase', + 'Gebert', + 'Predmore', + 'Entwistle', + 'Lourenco', + 'Snively', + 'Chivers', + 'Byas', + 'Edsall', + 'Sneddon', + 'Kloster', + 'Luedke', + 'Barcelo', + 'Corns', + 'Paula', + 'Tacker', + 'Marton', + 'Lyke', + 'Huitt', + 'Tinch', + 'Tagle', + 'Linnell', + 'Loden', + 'Witman', + 'Condrey', + 'Swindler', + 'Denby', + 'Mcdow', + 'Bennion', + 'Berkman', + 'Esguerra', + 'Kohli', + 'Leicht', + 'Platero', + 'Purtell', + 'Sarro', + 'Spera', + 'Wasielewski', + 'Nold', + 'Gander', + 'Coster', + 'Burn', + 'Sindelar', + 'Spivak', + 'Stangl', + 'Eakes', + 'Host', + 'Raybon', + 'Stickle', + 'Vitiello', + 'Borntrager', + 'Glorioso', + 'Winnie', + 'Blocher', + 'Che', + 'Godbold', + 'Blumenfeld', + 'Hallford', + 'Nuckolls', + 'Rasor', + 'Tardy', + 'Hayslett', + 'Kivett', + 'Pettry', + 'Klopfenstein', + 'Martelli', + 'Dunker', + 'Klass', + 'Denn', + 'Vessels', + 'Stukes', + 'Iannone', + 'Kovarik', + 'Perlmutter', + 'Som', + 'Kump', + 'Tack', + 'Warf', + 'Coffer', + 'Baas', + 'Balli', + 'Fleishman', + 'Lyall', + 'Meli', + 'Petrovic', + 'Sego', + 'Tignor', + 'Maule', + 'Stinchcomb', + 'Doxey', + 'Garbutt', + 'Drewes', + 'Prestridge', + 'Vivanco', + 'Weinmann', + 'Amrhein', + 'Schluter', + 'Cleek', + 'Rossignol', + 'Rezendes', + 'Marone', + 'Sloss', + 'Weary', + 'Leishman', + 'Searfoss', + 'Springman', + 'Wolfer', + 'Hires', + 'Mccampbell', + 'Casselman', + 'Frasca', + 'Lintner', + 'Preiss', + 'Neilsen', + 'Twiss', + 'Boughner', + 'Donnellan', + 'Rech', + 'Mccaulley', + 'Massenburg', + 'Dermody', + 'Neuberger', + 'Rifkin', + 'Ullom', + 'Marth', + 'Blacker', + 'Kase', + 'Garon', + 'Calaway', + 'Grange', + 'Yopp', + 'Service', + 'Blassingame', + 'Lockley', + 'Straughter', + 'Porath', + 'Situ', + 'Stansfield', + 'Eves', + 'Cianci', + 'Colindres', + 'Killam', + 'Luiz', + 'Stahlman', + 'Silvernail', + 'Moorhouse', + 'Langner', + 'Soucie', + 'Lucke', + 'Manly', + 'Huggard', + 'Higareda', + 'Matarazzo', + 'Jusino', + 'Winnett', + 'Matheney', + 'Bufkin', + 'Bilbo', + 'Levingston', + 'Auxier', + 'Guevarra', + 'Triolo', + 'Roder', + 'Clever', + 'Moodie', + 'Cabana', + 'Kiesling', + 'Lindblom', + 'Reuther', + 'Rubi', + 'Brinkmann', + 'Donati', + 'Cresswell', + 'Fortes', + 'Bayard', + 'Grayer', + 'Malveaux', + 'Hauger', + 'Hirschman', + 'Soroka', + 'Witek', + 'Pugsley', + 'Eoff', + 'Alewine', + 'Hastie', + 'Budzinski', + 'Burgard', + 'Hebel', + 'Kleist', + 'Lawhead', + 'Saporito', + 'Sugarman', + 'Sechler', + 'Cohoon', + 'Treadaway', + 'Silliman', + 'Horsey', + 'Chauhan', + 'Jovel', + 'Giorgio', + 'Waltrip', + 'Templeman', + 'Morning', + 'Fava', + 'Mcinturff', + 'Migliaccio', + 'Moncayo', + 'Pesek', + 'Olivero', + 'Devall', + 'Dauphin', + 'Banerjee', + 'Benway', + 'Bermejo', + 'Dacey', + 'Pilarski', + 'Pinnell', + 'Chia', + 'Pung', + 'Rahe', + 'Greenhaw', + 'Byrns', + 'Ancona', + 'Granato', + 'Luciani', + 'Shryock', + 'Sloop', + 'Murcia', + 'Croll', + 'Congleton', + 'Okelly', + 'Norville', + 'Flesch', + 'Murad', + 'Seddon', + 'Waybright', + 'Cremer', + 'Hagman', + 'Largo', + 'Solar', + 'Costales', + 'Gier', + 'Tober', + 'Reeb', + 'Lands', + 'Hoback', + 'Ingrassia', + 'Youngquist', + 'Tyrell', + 'Profit', + 'Collura', + 'Oldaker', + 'Vogl', + 'Spafford', + 'Laughman', + 'Goris', + 'Coghill', + 'Sweatman', + 'Rozelle', + 'Chatelain', + 'Fouch', + 'Legros', + 'Koza', + 'Vialpando', + 'Subia', + 'Danz', + 'Dosch', + 'Debruin', + 'Stefanik', + 'Gamber', + 'Saylors', + 'Cost', + 'Bernat', + 'Eastburn', + 'Getman', + 'Maillet', + 'Dogan', + 'Finklea', + 'Alongi', + 'Ballas', + 'Konkel', + 'Ryu', + 'Scoles', + 'Oles', + 'Algarin', + 'Seago', + 'Delaune', + 'Pettey', + 'Gettys', + 'Blanch', + 'Kea', + 'Cambridge', + 'Ciesielski', + 'Pribble', + 'Mayhugh', + 'Dery', + 'Allsup', + 'Hauptman', + 'Shoff', + 'Spath', + 'Lipsky', + 'Lakhani', + 'Lona', + 'Andrea', + 'Heist', + 'Herzig', + 'Insley', + 'Frasher', + 'Muise', + 'Kettle', + 'Catano', + 'Harkleroad', + 'Rominger', + 'Schreffler', + 'Bielecki', + 'Knarr', + 'Arvidson', + 'Harnden', + 'Galyon', + 'Rando', + 'Delima', + 'Constance', + 'Bosman', + 'Meinke', + 'Rosenquist', + 'Stickles', + 'Batz', + 'Eitel', + 'Kouba', + 'Marmol', + 'Rini', + 'Kinyon', + 'Munns', + 'Hilts', + 'Verrett', + 'Shead', + 'Staggers', + 'Naccarato', + 'Shupp', + 'Willeford', + 'Gayer', + 'Bran', + 'Krider', + 'Cue', + 'Dubiel', + 'Kawamoto', + 'Quayle', + 'Meckley', + 'Weingart', + 'Ivan', + 'Aller', + 'Pattee', + 'Pile', + 'Shinault', + 'Alzate', + 'Goudreau', + 'Weitzman', + 'Zurek', + 'Portman', + 'Tellis', + 'Achenbach', + 'Cranfill', + 'Scheib', + 'Rud', + 'Forgey', + 'Sardina', + 'Hayslip', + 'Fadden', + 'Ethington', + 'Jette', + 'Maberry', + 'Stecher', + 'Mcgahan', + 'Buffa', + 'Lehto', + 'Lesch', + 'Minier', + 'Niblett', + 'Behar', + 'Gochenour', + 'Thole', + 'Woodmansee', + 'Guse', + 'Breunig', + 'Deibert', + 'Levario', + 'Liming', + 'Oltman', + 'Vought', + 'Higby', + 'Lummus', + 'Casimir', + 'Grabow', + 'Helzer', + 'Madero', + 'Panico', + 'Ruud', + 'Beas', + 'Knebel', + 'Lorence', + 'Sizer', + 'Goodwill', + 'Darrell', + 'Dismukes', + 'Wimbish', + 'Kleine', + 'Prohaska', + 'Freeborn', + 'Caso', + 'Meis', + 'Bise', + 'Maxim', + 'Chumbley', + 'Eaglin', + 'Bergey', + 'Hillenbrand', + 'Pacifico', + 'Plath', + 'Rio', + 'Ristau', + 'Zych', + 'Whang', + 'Fister', + 'Forbush', + 'Lagarde', + 'Atha', + 'Hallinan', + 'Hesser', + 'Hoak', + 'Kohr', + 'Longnecker', + 'Nomura', + 'Raia', + 'Seybold', + 'Spagnola', + 'Majano', + 'Sanmartin', + 'Mangual', + 'Stanback', + 'Gangi', + 'Lauritzen', + 'Seeber', + 'Disla', + 'Frain', + 'Besse', + 'Makris', + 'Ducker', + 'Demps', + 'Laporta', + 'Pavey', + 'Reineke', + 'Najjar', + 'Mcclaskey', + 'Luff', + 'Vanderveer', + 'Mccoll', + 'Leamon', + 'Meinhardt', + 'Dinatale', + 'Laffoon', + 'Jenny', + 'Skipworth', + 'Folds', + 'Burstein', + 'Freas', + 'Lizardo', + 'Selle', + 'Vrabel', + 'Beranek', + 'Hakala', + 'Spataro', + 'Prahl', + 'Meas', + 'Haston', + 'Croker', + 'Carmouche', + 'Doolan', + 'Guerrieri', + 'Poulton', + 'Mauger', + 'Klose', + 'Husk', + 'Pharis', + 'Dipalma', + 'Hamaker', + 'Simek', + 'Strube', + 'Corl', + 'Bence', + 'Meigs', + 'Gillaspie', + 'Moring', + 'Eli', + 'Mccullers', + 'Erving', + 'Dopp', + 'Falbo', + 'Gensler', + 'Heroux', + 'Hertzler', + 'Muscarella', + 'Wittmann', + 'Willner', + 'Howton', + 'Brummitt', + 'Demar', + 'Hardrick', + 'Benavente', + 'Choo', + 'Tiscareno', + 'Bunge', + 'Helle', + 'Ogan', + 'Allbright', + 'Jervis', + 'Tompson', + 'Sheats', + 'Hebron', + 'Esters', + 'Fiorillo', + 'Narciso', + 'Slowik', + 'Kush', + 'Sole', + 'Bitting', + 'Bradham', + 'Goggans', + 'Rushin', + 'Huguley', + 'Kittelson', + 'Nadel', + 'Noggle', + 'Xue', + 'Alameda', + 'Hege', + 'Liberto', + 'Maron', + 'Aber', + 'Brodersen', + 'Clasen', + 'Couturier', + 'Godines', + 'Ozment', + 'Parga', + 'Rohm', + 'Voris', + 'Leaver', + 'Newhart', + 'Sabourin', + 'Kelling', + 'Repass', + 'Wigington', + 'Prioleau', + 'Antle', + 'Goucher', + 'Kreitzer', + 'Reuss', + 'Rosenfield', + 'Sliva', + 'Nolting', + 'Radel', + 'Quintal', + 'Lisa', + 'Temples', + 'Cavins', + 'Gazaway', + 'Hopewell', + 'Albury', + 'Broberg', + 'Khuu', + 'Zelinski', + 'Kurian', + 'Treacy', + 'Rake', + 'Tirrell', + 'Macdowell', + 'Smead', + 'Edgerly', + 'Fowles', + 'Yorke', + 'Goodwyn', + 'Sciacca', + 'Breitenbach', + 'Charity', + 'Greenidge', + 'Kendig', + 'Navarette', + 'Doremus', + 'Marcelino', + 'Ribera', + 'Luse', + 'Hasley', + 'Halton', + 'Jakes', + 'Balas', + 'Cheema', + 'Dettman', + 'Schachter', + 'Weisenberger', + 'Lehn', + 'Sailors', + 'Alcott', + 'Mancino', + 'Mineo', + 'Montz', + 'Stettler', + 'Brannock', + 'Shumake', + 'Blunk', + 'Feuerstein', + 'Mangino', + 'Bitzer', + 'Padden', + 'Wetter', + 'Blase', + 'Helvey', + 'Sabia', + 'Folden', + 'Wyllie', + 'Hoosier', + 'Gehringer', + 'Peifer', + 'Schneiderman', + 'Raj', + 'Gift', + 'Sue', + 'Wedgeworth', + 'Bischof', + 'Coviello', + 'Flor', + 'Barrentine', + 'Ells', + 'Dundas', + 'Baine', + 'Bouknight', + 'Koning', + 'Mallari', + 'Monje', + 'Wingler', + 'Stainbrook', + 'Mari', + 'Hemby', + 'Boateng', + 'Enfinger', + 'Esquer', + 'Salvatierra', + 'Tercero', + 'Porta', + 'Speth', + 'Plate', + 'Rockhold', + 'Hampshire', + 'Stipe', + 'Buescher', + 'Denault', + 'Fahnestock', + 'Vandehey', + 'Brouse', + 'Ciaccio', + 'Hund', + 'Wire', + 'Sherron', + 'Fairfax', + 'Owusu', + 'Cuervo', + 'Minjarez', + 'Zarco', + 'Vandyne', + 'Gedeon', + 'Kegler', + 'Ebron', + 'Murtaugh', + 'Pariseau', + 'Morvant', + 'Ellwood', + 'Beazley', + 'Farrelly', + 'Mccollom', + 'Alegre', + 'Dussault', + 'Goulette', + 'Hession', + 'Regier', + 'Speranza', + 'Spinella', + 'Maloof', + 'Nogueira', + 'Beaudin', + 'Sable', + 'Samford', + 'Marchan', + 'Rodriques', + 'Rhines', + 'Aldrete', + 'Creedon', + 'Laberge', + 'Sandel', + 'Spady', + 'Horsman', + 'Schimpf', + 'Sottile', + 'Than', + 'Ybanez', + 'Sagastume', + 'Vosburg', + 'Langlais', + 'Windley', + 'Bielski', + 'Meyerson', + 'Rizk', + 'Sparacino', + 'Winebarger', + 'Helsley', + 'Alward', + 'Wilker', + 'Clyne', + 'Bergren', + 'Gin', + 'Heberling', + 'Noh', + 'Rotz', + 'Laffey', + 'Zurawski', + 'Aliff', + 'Coover', + 'Steves', + 'Brain', + 'Greggs', + 'Burts', + 'Culwell', + 'Halbrook', + 'Marcantel', + 'Alsip', + 'Esslinger', + 'Kinnaird', + 'Rew', + 'Wimbley', + 'Dalal', + 'Litke', + 'Ostlund', + 'Petersheim', + 'Vezina', + 'Vickrey', + 'Vida', + 'Stachowiak', + 'Santizo', + 'Stow', + 'Hoel', + 'Parrino', + 'Elsberry', + 'Pharris', + 'Chiarello', + 'Konen', + 'Ogata', + 'Tousignant', + 'Turano', + 'Zoll', + 'Reser', + 'Ribble', + 'Dally', + 'Kersh', + 'Crivello', + 'Glantz', + 'Vanvleet', + 'Dy', + 'Woolwine', + 'Ager', + 'Romney', + 'Dedeaux', + 'Ringgold', + 'Mir', + 'Rexford', + 'Whitehair', + 'Wilczynski', + 'Kleinsasser', + 'Siemens', + 'Kindig', + 'Kemmer', + 'Fonda', + 'Litt', + 'Mcferrin', + 'Riche', + 'Beaudet', + 'Lasala', + 'Maglione', + 'Milani', + 'Moscato', + 'Pangilinan', + 'Haycraft', + 'Camilo', + 'Trafton', + 'Stroble', + 'Dollard', + 'Consiglio', + 'Kinnaman', + 'Mumaw', + 'Mustard', + 'Nees', + 'Rupprecht', + 'Gimbel', + 'Chamberland', + 'Lish', + 'Beedle', + 'Minder', + 'Broxton', + 'Cocco', + 'Vore', + 'Slough', + 'Pehrson', + 'Graney', + 'Reade', + 'Cozzi', + 'Mowrer', + 'Necaise', + 'Notaro', + 'Vanderwall', + 'Jeffs', + 'Lynd', + 'Perino', + 'Poyner', + 'Oscar', + 'Mihalik', + 'Coscia', + 'Zoellner', + 'Shippee', + 'Casimiro', + 'Phillippe', + 'Bartolotta', + 'Graciano', + 'Schnoor', + 'Aube', + 'Duguay', + 'Dickerman', + 'Santi', + 'Cude', + 'Haver', + 'Heidelberg', + 'Farquharson', + 'Bianchini', + 'Kasprzak', + 'Pizzi', + 'Urquiza', + 'Knee', + 'Lust', + 'Strayhorn', + 'Ader', + 'Canup', + 'Mira', + 'Saulnier', + 'Stalvey', + 'Takeuchi', + 'Updegraff', + 'Barletta', + 'Mikhail', + 'Abadie', + 'Cohee', + 'Sones', + 'Hird', + 'Mizelle', + 'Graddy', + 'Demay', + 'Escandon', + 'Kozar', + 'Lecuyer', + 'Tredway', + 'Danks', + 'Pry', + 'Mathena', + 'Gomer', + 'Moussa', + 'Journey', + 'Brison', + 'Denardo', + 'Digiorgio', + 'Worster', + 'Kottke', + 'Sayegh', + 'Aday', + 'Chain', + 'Digby', + 'Beeks', + 'Malpass', + 'Toft', + 'Fucci', + 'Stam', + 'Smoker', + 'Willms', + 'Bohner', + 'Sugar', + 'Tay', + 'Faye', + 'Melnik', + 'Pankow', + 'Stehle', + 'Vecchione', + 'Weatherwax', + 'Monterrosa', + 'Bodily', + 'Serino', + 'Jerkins', + 'Bosma', + 'Luczak', + 'Serafini', + 'Baze', + 'Hemmings', + 'Darrington', + 'Fraizer', + 'Henrikson', + 'Kok', + 'Larrison', + 'Mirabella', + 'Newhall', + 'Hollenbach', + 'Formica', + 'Haake', + 'Seim', + 'Zeledon', + 'Crabill', + 'Mensch', + 'Prevatt', + 'Riggan', + 'Gallien', + 'Erby', + 'Running', + 'Shisler', + 'Sidebottom', + 'Sladek', + 'Alejos', + 'Momin', + 'Bickers', + 'Smither', + 'Ahart', + 'Huseman', + 'Cantero', + 'Reiley', + 'Mcneeley', + 'Quill', + 'Binger', + 'Ellerbee', + 'Cearley', + 'Guilmette', + 'Helbig', + 'Nuzum', + 'Gravatt', + 'Turlington', + 'Deramus', + 'Casados', + 'Harrop', + 'Kardos', + 'Krehbiel', + 'Homa', + 'Agostino', + 'Candia', + 'Byerley', + 'Kincer', + 'Vitello', + 'Backhaus', + 'Burzynski', + 'Zaborowski', + 'Puebla', + 'Pedrick', + 'Hyson', + 'Mazyck', + 'Deno', + 'Yutzy', + 'Dubbs', + 'Shimek', + 'Saha', + 'Philipps', + 'Chretien', + 'Bramwell', + 'Mccalister', + 'Ebright', + 'Parkhill', + 'Rieke', + 'Karras', + 'Mcbain', + 'Gibbon', + 'Beckler', + 'Nordby', + 'Sipos', + 'Swider', + 'Treiber', + 'Weakland', + 'Zagorski', + 'Peavler', + 'Cirino', + 'Corzine', + 'Barbier', + 'Dolby', + 'Sheperd', + 'Vanderhorst', + 'Cornman', + 'Dippel', + 'Gramlich', + 'Hoffmeister', + 'Markwell', + 'Milks', + 'Schriner', + 'Cusimano', + 'Emberton', + 'Kimbler', + 'Merrow', + 'Huard', + 'Paulo', + 'Durrance', + 'Faherty', + 'Palmatier', + 'Rezac', + 'Speir', + 'Streicher', + 'Ackman', + 'Veitch', + 'Bedgood', + 'Pantano', + 'Raman', + 'Eusebio', + 'Coldwell', + 'Omer', + 'Swanigan', + 'Stepney', + 'Breiner', + 'Casebolt', + 'Deblasio', + 'Mascaro', + 'Maselli', + 'Overfield', + 'Enyart', + 'Litman', + 'Borer', + 'Dudash', + 'Mcniff', + 'Cherian', + 'Scearce', + 'Brakefield', + 'Hamed', + 'Cooperman', + 'Kinzel', + 'Mchargue', + 'Schiefelbein', + 'Varughese', + 'Brumm', + 'Novy', + 'Vicars', + 'Barratt', + 'Titsworth', + 'Mole', + 'Crisafulli', + 'Deitch', + 'Slager', + 'Tokarz', + 'Speelman', + 'Tunney', + 'Peal', + 'Chenevert', + 'Haggins', + 'Heitmann', + 'Scheuer', + 'Stuhr', + 'Zenner', + 'Wishon', + 'Arno', + 'Lauder', + 'Goertz', + 'Jew', + 'Knapik', + 'Lococo', + 'Murnane', + 'Pawloski', + 'Contino', + 'Holbrooks', + 'Carlstrom', + 'Heitkamp', + 'Muszynski', + 'Shelnutt', + 'Tortora', + 'Dietrick', + 'Kyzer', + 'Colt', + 'Propes', + 'Caffee', + 'Fankhauser', + 'Liotta', + 'Patil', + 'Broder', + 'Disher', + 'Telfer', + 'Lampkins', + 'Bartman', + 'Beauchemin', + 'Gatz', + 'Pedrosa', + 'Schuch', + 'Zorrilla', + 'Capote', + 'Vanderslice', + 'Boulden', + 'Kirkendoll', + 'Fausto', + 'Krom', + 'Ngai', + 'Sepe', + 'Domenech', + 'Dines', + 'Aschenbrenner', + 'Carias', + 'Inoue', + 'Montagna', + 'Pulsifer', + 'Rieman', + 'Seelye', + 'Yochum', + 'Defilippis', + 'Lacross', + 'Betances', + 'Jenne', + 'Rousey', + 'Brunswick', + 'Wadlington', + 'Brainerd', + 'Dauria', + 'Dinicola', + 'Fath', + 'Gemmell', + 'Rudman', + 'Urbaniak', + 'Fillion', + 'Brandel', + 'Devin', + 'Derrickson', + 'Jenkin', + 'Ebling', + 'Ferranti', + 'Lueders', + 'Alvear', + 'Gero', + 'Maury', + 'Estill', + 'Beadles', + 'Philyaw', + 'Tann', + 'Bednarski', + 'Nagata', + 'Partington', + 'Sobol', + 'Soohoo', + 'Welliver', + 'Yam', + 'Popejoy', + 'Berthelot', + 'Manwaring', + 'Cahn', + 'Layer', + 'Poarch', + 'Tee', + 'Arellanes', + 'Ehler', + 'Montalto', + 'Pavlick', + 'Rauh', + 'Mcnees', + 'Balke', + 'Alles', + 'Caperton', + 'Frier', + 'Thweatt', + 'Whitely', + 'Demby', + 'Kowalik', + 'Loffredo', + 'Solem', + 'Clampitt', + 'Dossey', + 'Fauver', + 'Toto', + 'Corlett', + 'Nickols', + 'Golston', + 'Graef', + 'Salsman', + 'Hartl', + 'Towell', + 'Lasseter', + 'Arata', + 'Diver', + 'Malan', + 'Lanter', + 'Justis', + 'Prime', + 'Ditzler', + 'Engelhart', + 'Plouffe', + 'Zaldivar', + 'Elser', + 'Witherow', + 'Mateer', + 'Rikard', + 'Dolson', + 'Mariner', + 'Amis', + 'Toby', + 'Evins', + 'Midgette', + 'Pinnix', + 'Blackard', + 'Huisman', + 'Lager', + 'Deloera', + 'Dutt', + 'Goodrow', + 'Morphis', + 'Quin', + 'Frankenfield', + 'Craycraft', + 'Mazer', + 'Meloy', + 'Lebouef', + 'Beresford', + 'Spiva', + 'Michie', + 'Jarreau', + 'Vallier', + 'Dunmore', + 'Cerra', + 'Ciulla', + 'Dauer', + 'Helling', + 'Jackowski', + 'Taboada', + 'Balistreri', + 'Blattner', + 'Cabot', + 'Lawver', + 'Cornette', + 'Arline', + 'Amsden', + 'Degner', + 'Ungar', + 'Birney', + 'Goldie', + 'Croston', + 'Wixon', + 'Alan', + 'Garneau', + 'Kolakowski', + 'Vitek', + 'Witherell', + 'Licari', + 'Badeaux', + 'Sammon', + 'Greenland', + 'Corlew', + 'Cashwell', + 'Aldinger', + 'Bilderback', + 'Kleeman', + 'Sisto', + 'Menz', + 'Bakos', + 'Ebbert', + 'Berliner', + 'Kin', + 'Cabaniss', + 'Ouzts', + 'Mccook', + 'Campfield', + 'Gulino', + 'Odriscoll', + 'Weyand', + 'Mcguckin', + 'Crean', + 'Boyington', + 'Bracero', + 'Carini', + 'Chawla', + 'Chaudhary', + 'Koehl', + 'Wahlstrom', + 'Francoeur', + 'Leveque', + 'Ledgerwood', + 'Paluch', + 'Wyble', + 'Latif', + 'Koen', + 'Eddie', + 'Mcgirt', + 'Boxley', + 'Exline', + 'Lujano', + 'Michalowski', + 'Rottman', + 'Throop', + 'Zech', + 'Baros', + 'Bohne', + 'Mule', + 'Monica', + 'Lasiter', + 'Alsop', + 'Pittard', + 'Whitefield', + 'Mccaskey', + 'Paek', + 'Reilley', + 'Wasik', + 'Bouma', + 'Garrigan', + 'Nett', + 'Mclarty', + 'Flemings', + 'Alcorta', + 'Spoor', + 'Mccranie', + 'Coverdale', + 'Guaman', + 'Jenness', + 'Knoop', + 'Scarpelli', + 'Schrecengost', + 'Toews', + 'Caughey', + 'Laska', + 'Helfer', + 'Bevers', + 'Forbus', + 'Mccrady', + 'Reasor', + 'Aggarwal', + 'Locicero', + 'Uber', + 'Vadnais', + 'Budnick', + 'Duhamel', + 'Stelling', + 'Kicklighter', + 'Basco', + 'Otts', + 'Tippins', + 'Bliven', + 'Gayheart', + 'Knauf', + 'Lalli', + 'Quigg', + 'Kingman', + 'Boros', + 'Henneman', + 'Lofland', + 'Pendarvis', + 'Keitt', + 'Gelfand', + 'Greaney', + 'Kindt', + 'Stimac', + 'Kirn', + 'Tokar', + 'Miura', + 'Wendorf', + 'Vigue', + 'Dorey', + 'Fegan', + 'Meares', + 'Thierry', + 'Ambrosino', + 'Coenen', + 'Kersting', + 'Leas', + 'Millward', + 'Petzold', + 'Morphew', + 'Filippone', + 'Stoffer', + 'Mani', + 'Clairmont', + 'Mccreight', + 'Cully', + 'Bissonette', + 'Kochan', + 'Linneman', + 'Parlier', + 'Bergner', + 'Sterns', + 'Steveson', + 'Clingerman', + 'Karg', + 'Medved', + 'Prakash', + 'Ulman', + 'Petroski', + 'Hagaman', + 'Huddle', + 'Auclair', + 'Shives', + 'Dunavant', + 'Glade', + 'Chauncey', + 'Pough', + 'Burgoon', + 'Pluta', + 'Couey', + 'Punch', + 'Colmenares', + 'Fosdick', + 'Henze', + 'Kaczynski', + 'Lomonaco', + 'Roepke', + 'Schenkel', + 'Schlatter', + 'Schoenherr', + 'Tripodi', + 'Zeiler', + 'Bunt', + 'Dolly', + 'Boyland', + 'Bickle', + 'Cincotta', + 'Crull', + 'Enfield', + 'Saltz', + 'Skelley', + 'Younts', + 'Bussiere', + 'Latona', + 'Sensabaugh', + 'Grosvenor', + 'Woolbright', + 'Shorty', + 'Brungardt', + 'Cardon', + 'Carlberg', + 'Clevinger', + 'Rucinski', + 'Vanhooser', + 'Westling', + 'Imperial', + 'Tyer', + 'Elzey', + 'Aslam', + 'Fesler', + 'Leiser', + 'Smitley', + 'Orgeron', + 'Scuderi', + 'Flatley', + 'Whiteford', + 'Tison', + 'Laurin', + 'Fortman', + 'Whitty', + 'Kirton', + 'Cassella', + 'Flom', + 'Seigel', + 'Cossette', + 'Bryden', + 'Gobin', + 'Hieb', + 'Marzullo', + 'Matuszak', + 'Rolph', + 'Spilman', + 'Vanvoorhis', + 'Sande', + 'Suydam', + 'Gledhill', + 'Krill', + 'Mackiewicz', + 'Templet', + 'Friedrichs', + 'Ruddell', + 'Kats', + 'Nourse', + 'Millender', + 'Wafer', + 'Fauntleroy', + 'Archibeque', + 'Maslowski', + 'Metzgar', + 'Pizana', + 'Mcguffey', + 'Estridge', + 'Vanalstyne', + 'Decuir', + 'Mcbean', + 'Hardnett', + 'Avilla', + 'Spadafora', + 'Weisel', + 'Kann', + 'Leyden', + 'Purdom', + 'Tappan', + 'Gunnells', + 'Slaten', + 'Hansley', + 'Chiappetta', + 'Rozek', + 'Tiede', + 'Winland', + 'Dubuque', + 'Heslin', + 'Bradway', + 'Eckels', + 'Saffell', + 'Germaine', + 'Apolinar', + 'Coloma', + 'Gawlik', + 'Chipps', + 'Hicklin', + 'Glanton', + 'Dalke', + 'Denlinger', + 'Kuipers', + 'Houpt', + 'Parcell', + 'Claeys', + 'Ferreri', + 'Greif', + 'Lucente', + 'Siems', + 'Yousef', + 'Llerena', + 'Rote', + 'Suero', + 'Malmberg', + 'Touchette', + 'Luton', + 'Wess', + 'Height', + 'Stampley', + 'Anastasi', + 'Bulman', + 'Deharo', + 'Laube', + 'Severt', + 'Midgley', + 'Colling', + 'Ell', + 'Burbage', + 'Commander', + 'Hubner', + 'Zurcher', + 'Arocha', + 'Nobile', + 'Tingler', + 'Ellman', + 'Lolley', + 'Pewitt', + 'Mcduff', + 'Hyler', + 'Goltz', + 'Kubota', + 'Lamberti', + 'Ohern', + 'Uhrig', + 'Dummer', + 'Keesling', + 'Litzinger', + 'Moriarity', + 'Servantes', + 'Rohe', + 'Stokely', + 'Weedon', + 'Pippins', + 'Dehner', + 'Krogman', + 'Luecke', + 'Rosete', + 'Zona', + 'Lowy', + 'Applebee', + 'Heather', + 'Cruikshank', + 'Linson', + 'Brandy', + 'Koser', + 'Ruel', + 'Ruppe', + 'Saeteurn', + 'Dewolfe', + 'Sawtelle', + 'Rudin', + 'Raver', + 'Bassham', + 'Yaw', + 'Segrest', + 'Belfiore', + 'Heeren', + 'Kotowski', + 'Luken', + 'Makela', + 'Ranallo', + 'Schug', + 'Seery', + 'Payson', + 'Caufield', + 'Lacefield', + 'Bratten', + 'Jr', + 'Buske', + 'Ternes', + 'Bivona', + 'Felber', + 'Rott', + 'Pitkin', + 'Pridmore', + 'Oyer', + 'Astle', + 'Jeppesen', + 'Shimabukuro', + 'Soltys', + 'Vieth', + 'Rasnick', + 'Calfee', + 'Brignac', + 'Lamy', + 'Facey', + 'Alper', + 'Borquez', + 'Cavalieri', + 'Niswonger', + 'Pajak', + 'Schwabe', + 'Ringel', + 'Abbe', + 'Fenley', + 'Churchman', + 'Haydel', + 'Stockard', + 'Adamek', + 'Ellerman', + 'Torpey', + 'Waldroup', + 'Hunte', + 'Bienaime', + 'Lazzara', + 'Nemitz', + 'Wingerter', + 'Boer', + 'Franken', + 'Lebow', + 'Manger', + 'Baisley', + 'Pane', + 'Gayden', + 'Bertelsen', + 'Curfman', + 'Leanos', + 'Nissley', + 'Odwyer', + 'Manzer', + 'Kollman', + 'Quon', + 'Holgate', + 'Cola', + 'Mckissack', + 'Cousar', + 'Bilski', + 'Boehler', + 'Kawamura', + 'April', + 'Mckelvy', + 'Lanni', + 'Roehm', + 'Salva', + 'Stackpole', + 'Stracener', + 'Masiello', + 'Barrus', + 'Tubb', + 'Brummel', + 'Devereux', + 'Foushee', + 'Corado', + 'Gladfelter', + 'Grewe', + 'Hodapp', + 'Swartwood', + 'Vacek', + 'Wrona', + 'Shaffner', + 'Ullah', + 'Heslop', + 'Mungo', + 'Haymon', + 'Behrend', + 'Falter', + 'Feola', + 'Gruner', + 'Picklesimer', + 'Riedl', + 'Stegeman', + 'Harpole', + 'Moyes', + 'Boulay', + 'Brighton', + 'Guise', + 'Laury', + 'Badilla', + 'Cypher', + 'Houdek', + 'Juhasz', + 'Klingbeil', + 'Pinales', + 'Fellman', + 'Daher', + 'Allmond', + 'Bal', + 'Crager', + 'Hillebrand', + 'Menezes', + 'Serpas', + 'Zager', + 'Alvardo', + 'Summerford', + 'Stillings', + 'Vandergrift', + 'Hanchett', + 'Minto', + 'Daughtery', + 'Gillon', + 'Rajan', + 'Vasko', + 'Wirick', + 'Woolever', + 'Caserta', + 'Welle', + 'Kimbrel', + 'Traywick', + 'Hands', + 'Spratley', + 'Iannuzzi', + 'Krikorian', + 'Runk', + 'Sood', + 'Riese', + 'Antunes', + 'Winsett', + 'Mans', + 'Capel', + 'Condron', + 'Nilles', + 'Petz', + 'Salemi', + 'Bainter', + 'Patchett', + 'Hirschfeld', + 'Murrin', + 'Lamey', + 'Mcglothin', + 'Hodo', + 'Hirth', + 'Kaltenbach', + 'Kensinger', + 'Leidy', + 'Shurtz', + 'Braatz', + 'Brafford', + 'Willet', + 'Clendening', + 'Basch', + 'Brockwell', + 'Oberman', + 'Palmateer', + 'Osornio', + 'Gehl', + 'Staker', + 'Mattila', + 'Dawn', + 'Cowherd', + 'Appleman', + 'Carbonaro', + 'Castruita', + 'Pilling', + 'Wenrich', + 'Christoffersen', + 'Hinzman', + 'Kaup', + 'Pettersen', + 'Jue', + 'Khalsa', + 'Mutz', + 'Remus', + 'Arch', + 'Shands', + 'Borek', + 'Buresh', + 'Egli', + 'Feldkamp', + 'Hampel', + 'Lichtenberg', + 'Morimoto', + 'Brasel', + 'Demelo', + 'Royalty', + 'Averitt', + 'Metivier', + 'Bradsher', + 'Avallone', + 'Demeter', + 'Masucci', + 'Musil', + 'Wichmann', + 'Broman', + 'Taunton', + 'Blewett', + 'Duhart', + 'Goo', + 'Hanus', + 'Mathai', + 'Shutts', + 'Taniguchi', + 'Vanleeuwen', + 'Delvillar', + 'Hane', + 'Givan', + 'Croskey', + 'Elamin', + 'Deffenbaugh', + 'Miklos', + 'Passalacqua', + 'Woessner', + 'Lapan', + 'Miah', + 'Coty', + 'Baksh', + 'Beehler', + 'Goel', + 'Wolfinger', + 'Goodhue', + 'Toal', + 'Mattoon', + 'Haq', + 'Nida', + 'Dant', + 'Varnadore', + 'Tippit', + 'Every', + 'Bohling', + 'Lichtenberger', + 'Louk', + 'Soderquist', + 'Werkheiser', + 'Willbanks', + 'Whitis', + 'Millikin', + 'Dietzel', + 'Frase', + 'Ishida', + 'Pilger', + 'Grajales', + 'Kole', + 'Roff', + 'Ballantine', + 'Basden', + 'Cadenas', + 'Caliendo', + 'Hotard', + 'Vidrio', + 'Lichtman', + 'Devinney', + 'Fugitt', + 'Proud', + 'Hults', + 'Galey', + 'Verna', + 'Newburn', + 'Lafortune', + 'Fobbs', + 'Azure', + 'Cheong', + 'Heft', + 'Aispuro', + 'Longstreth', + 'Lajeunesse', + 'Howle', + 'Galley', + 'Lovan', + 'Convery', + 'Malatesta', + 'Warnecke', + 'Glavin', + 'Reil', + 'Filson', + 'Poage', + 'Fountaine', + 'Nolley', + 'Raglin', + 'Backlund', + 'Doerfler', + 'Faunce', + 'Hooton', + 'Lightcap', + 'Stepanek', + 'Grosser', + 'Weld', + 'Filippi', + 'Youn', + 'Matis', + 'Harnett', + 'Ferrill', + 'Segers', + 'Ponds', + 'Cuyler', + 'Faile', + 'Flaugher', + 'Kuehner', + 'Giorgi', + 'Eckler', + 'Sergeant', + 'Twiggs', + 'Boeck', + 'Flach', + 'Iliff', + 'Mcmurtrey', + 'Mcnelis', + 'Steckel', + 'Rouillard', + 'Folkerts', + 'Mechling', + 'Whitcher', + 'Daws', + 'Joly', + 'Abt', + 'Eells', + 'Niccum', + 'Twining', + 'Grinder', + 'Melrose', + 'Yarbro', + 'Degenhardt', + 'Dimeglio', + 'Okamura', + 'Kriss', + 'Payette', + 'Chui', + 'Mowers', + 'Foose', + 'Kinzie', + 'Blick', + 'Rizer', + 'Alcock', + 'Sirmans', + 'Behrman', + 'Carsten', + 'Kopacz', + 'Randhawa', + 'Schwing', + 'Burkhard', + 'Cunanan', + 'Exley', + 'Balducci', + 'Leman', + 'Hyslop', + 'Burtch', + 'Hadnot', + 'Lanphear', + 'Finchum', + 'Voit', + 'Jock', + 'Wilhoite', + 'Officer', + 'Mayweather', + 'Ravenell', + 'Arehart', + 'Bonetti', + 'Cloer', + 'Galliher', + 'Niven', + 'Uyeda', + 'Coughenour', + 'Siddiqi', + 'Karimi', + 'Cupit', + 'Loupe', + 'Hammell', + 'Antley', + 'Ally', + 'Southers', + 'Haymond', + 'Hosley', + 'Broz', + 'Kinoshita', + 'Kohout', + 'Lipke', + 'Ostrow', + 'Teves', + 'Gaus', + 'Meiser', + 'Cravey', + 'Noss', + 'Drayer', + 'Crooms', + 'Carrano', + 'Mckechnie', + 'Uhrich', + 'Villalva', + 'Wilkening', + 'Benevides', + 'Kepple', + 'Pon', + 'Randol', + 'Leadbetter', + 'Russom', + 'Locklin', + 'Battiste', + 'Abundis', + 'Agosta', + 'Bartek', + 'Brillhart', + 'Hoffmaster', + 'Mehr', + 'Spanos', + 'Denker', + 'Kimberling', + 'Schon', + 'Felten', + 'Lightle', + 'Ramseur', + 'Branning', + 'Deblois', + 'Inocencio', + 'Maricle', + 'Nishimoto', + 'Oviatt', + 'Shunk', + 'Taddeo', + 'Villarruel', + 'Otterson', + 'Clune', + 'Seamster', + 'Dandy', + 'Cybulski', + 'Daza', + 'Eastep', + 'Faulhaber', + 'Friedberg', + 'Gentz', + 'Scola', + 'Sebesta', + 'Glinski', + 'Schoon', + 'Graeber', + 'Sinks', + 'Wee', + 'Summerall', + 'Deets', + 'Furnish', + 'Kelemen', + 'Maiorano', + 'Teachout', + 'Paquet', + 'Mcgahey', + 'Kill', + 'Horman', + 'Selders', + 'Cottman', + 'Delfin', + 'Fronk', + 'Seelig', + 'Visco', + 'Briles', + 'Castillon', + 'Suire', + 'Havey', + 'Arner', + 'Farver', + 'Marts', + 'Gean', + 'Hugh', + 'Stoney', + 'Townsel', + 'Sandquist', + 'Neidig', + 'Miser', + 'Leeth', + 'Hocutt', + 'Balcazar', + 'Caporale', + 'Guymon', + 'Horstmann', + 'Miedema', + 'Zickefoose', + 'Casterline', + 'Pfannenstiel', + 'Becht', + 'Myres', + 'Ried', + 'Vallery', + 'Bator', + 'Calise', + 'Cotterman', + 'Desautels', + 'Hinchey', + 'Kostka', + 'Orenstein', + 'Rosenau', + 'Skow', + 'Cuello', + 'Herder', + 'Cure', + 'Eadie', + 'Claggett', + 'Batie', + 'Kirwin', + 'Troia', + 'Sinnett', + 'Books', + 'Maize', + 'Tremble', + 'Sinkler', + 'Gallon', + 'Winkles', + 'Zion', + 'Walt', + 'Pearse', + 'Gathright', + 'Isakson', + 'Saeger', + 'Siegle', + 'Wittwer', + 'Modesto', + 'Bensen', + 'Royals', + 'Mccane', + 'Begaye', + 'Matuszewski', + 'Schrier', + 'Shimko', + 'Torchia', + 'Ausmus', + 'Casazza', + 'Mealer', + 'Yant', + 'Amar', + 'Callas', + 'Depaola', + 'Kintner', + 'Lech', + 'Marsico', + 'Boerger', + 'Rak', + 'Kellen', + 'Kennemer', + 'Carbo', + 'Rennick', + 'Brennen', + 'Dorrough', + 'Shealey', + 'Breyer', + 'Dilks', + 'Geske', + 'Hundt', + 'Occhipinti', + 'Strauser', + 'Schult', + 'Transue', + 'Holding', + 'Vanhorne', + 'Critchlow', + 'Steptoe', + 'Buerger', + 'Claassen', + 'Farinas', + 'Ruland', + 'Holsapple', + 'Mcclintic', + 'Bendel', + 'Muriel', + 'Mckeithan', + 'Shellman', + 'Balzano', + 'Bement', + 'Montesinos', + 'Ringle', + 'Sobotka', + 'Donahoo', + 'Dicker', + 'Harling', + 'Burkley', + 'Browner', + 'Iovino', + 'Kubala', + 'Labriola', + 'Morra', + 'Orloff', + 'Patchen', + 'Recchia', + 'Budge', + 'Glendenning', + 'Nethery', + 'Scholtz', + 'Aybar', + 'Buis', + 'Mattie', + 'Bonsall', + 'Conine', + 'Dettmer', + 'Gerding', + 'Plantz', + 'Vandorn', + 'Tremaine', + 'Ruddick', + 'Murrow', + 'Mceachin', + 'Bridgeforth', + 'Docherty', + 'Hultman', + 'Liechty', + 'Touchton', + 'Yokoyama', + 'Borth', + 'Daoud', + 'Mealy', + 'Hearst', + 'Stalling', + 'Drapeau', + 'Hellwig', + 'Longtin', + 'Rappa', + 'Tormey', + 'Vanantwerp', + 'Sabel', + 'Neagle', + 'Duet', + 'Liebert', + 'Lush', + 'Aly', + 'Behn', + 'Brereton', + 'Atienza', + 'Dubey', + 'Gennaro', + 'Miltenberger', + 'Nitschke', + 'Ragle', + 'Schumm', + 'Tangen', + 'Waibel', + 'Whitham', + 'Stallone', + 'Perritt', + 'Coody', + 'Hinch', + 'Depuy', + 'Dunkelberger', + 'Texeira', + 'Tomita', + 'Diers', + 'Elsasser', + 'Neve', + 'Clendenen', + 'Pettibone', + 'Dobyns', + 'Ciotti', + 'Dodrill', + 'Fridman', + 'Lepine', + 'Nygard', + 'Shreves', + 'Sollenberger', + 'Leinbach', + 'Diazdeleon', + 'Bourget', + 'Ramadan', + 'Allensworth', + 'Scarboro', + 'Prowell', + 'Ghee', + 'Edouard', + 'Duca', + 'Ziebell', + 'Kercher', + 'Greger', + 'Mas', + 'Shier', + 'Branca', + 'Melchior', + 'Cast', + 'Saner', + 'Beswick', + 'Carone', + 'Sobieski', + 'Zweifel', + 'Beahm', + 'Defrank', + 'Krebsbach', + 'Mericle', + 'Mcinnes', + 'Lown', + 'Brumback', + 'Clause', + 'Claborn', + 'Rollin', + 'Montford', + 'Beckles', + 'Grebe', + 'Groesbeck', + 'Guidi', + 'Mathisen', + 'Mukherjee', + 'Rotolo', + 'Seybert', + 'Odegaard', + 'Mackley', + 'Glatt', + 'Going', + 'Perks', + 'Sansbury', + 'Prude', + 'Bequette', + 'Difilippo', + 'Dodgen', + 'Terpening', + 'Vanepps', + 'Poncedeleon', + 'Qu', + 'Ullery', + 'Wisener', + 'Lok', + 'Lutton', + 'Bellah', + 'Kinsel', + 'Tone', + 'Carabajal', + 'Koll', + 'Shankar', + 'Edick', + 'Donathan', + 'Andree', + 'Perrino', + 'Moffit', + 'Gaddie', + 'Breidenbach', + 'Jespersen', + 'Larrick', + 'Mauriello', + 'Morgado', + 'Roh', + 'Svec', + 'Tebbe', + 'Thieman', + 'Cerezo', + 'Perkowski', + 'Colville', + 'Yarnall', + 'Chason', + 'Brach', + 'Meller', + 'Brayboy', + 'Salaam', + 'Keleher', + 'Kilbourn', + 'Lowenthal', + 'Rispoli', + 'Vanzee', + 'Vlahos', + 'Trojan', + 'Birdsell', + 'Defoor', + 'Mcclusky', + 'Barret', + 'Smoke', + 'Berkeley', + 'Cuadrado', + 'Galyean', + 'Gruen', + 'Gualtieri', + 'Kurland', + 'Sposato', + 'Stieber', + 'Weatherman', + 'Strausser', + 'Miera', + 'Edlin', + 'Gilford', + 'Mouzon', + 'Buczek', + 'Krapf', + 'Lucatero', + 'Amburn', + 'Peddicord', + 'Forero', + 'Domer', + 'Farish', + 'Segraves', + 'Sant', + 'Engles', + 'Douthitt', + 'Lall', + 'Wormley', + 'Geisel', + 'Hao', + 'Polhemus', + 'Slifer', + 'Mowen', + 'Markin', + 'Rape', + 'Bollin', + 'Bulloch', + 'Pouncey', + 'Rufus', + 'Goodlow', + 'Dammann', + 'Delgrosso', + 'Gadbois', + 'Leap', + 'Lorentzen', + 'Sprankle', + 'Stucki', + 'Vitela', + 'Walck', + 'Winkelmann', + 'Mund', + 'Bley', + 'Channel', + 'Griebel', + 'Nordberg', + 'Slinkard', + 'Orrick', + 'Crooker', + 'Groll', + 'Maradiaga', + 'Jolin', + 'Boni', + 'Prom', + 'Reder', + 'Easler', + 'Totty', + 'Arnaud', + 'Bohler', + 'Heikkila', + 'Kehler', + 'Klingenberg', + 'Matera', + 'Striegel', + 'Urzua', + 'Baldi', + 'Burling', + 'Osmond', + 'Rucks', + 'Diel', + 'Kassel', + 'Schewe', + 'Conkling', + 'Ricke', + 'Schack', + 'Shirah', + 'Brauner', + 'Carriker', + 'Mcduffy', + 'Bieker', + 'Credeur', + 'Fabry', + 'Holdeman', + 'Jeansonne', + 'Klett', + 'Kolstad', + 'Mustain', + 'Strub', + 'Ricketson', + 'Fairbairn', + 'Langel', + 'Fenster', + 'Slatton', + 'Ehrenberg', + 'Espinola', + 'Hannaford', + 'Hinderliter', + 'Siqueiros', + 'Ange', + 'Gillin', + 'Battin', + 'Belue', + 'Spigner', + 'Simien', + 'Gervasi', + 'Pallares', + 'Plotner', + 'Puri', + 'Swiatek', + 'Vanmatre', + 'Corp', + 'Devillier', + 'Bucholtz', + 'Bremner', + 'Jen', + 'Evanson', + 'Ghent', + 'Eastland', + 'Kappler', + 'Grahn', + 'Shadrick', + 'Kibby', + 'Chaires', + 'Kontos', + 'Petrov', + 'Pillai', + 'Chadbourne', + 'Sotolongo', + 'Allende', + 'Kells', + 'Hayford', + 'Hempstead', + 'Livers', + 'Farrior', + 'Authement', + 'Bitz', + 'Corkery', + 'Klawitter', + 'Mongold', + 'Somma', + 'Topham', + 'Defrancisco', + 'Noda', + 'Breon', + 'Thetford', + 'Rod', + 'Kisling', + 'Drouillard', + 'Dotts', + 'Gramajo', + 'Masek', + 'Volkert', + 'Vora', + 'Pietras', + 'Sheffler', + 'Shrestha', + 'Kono', + 'Panza', + 'Brunn', + 'Tatom', + 'Nasir', + 'Barris', + 'Bursey', + 'Elsea', + 'Kettner', + 'Martorana', + 'Lindow', + 'Chevez', + 'Pater', + 'Hennis', + 'Iman', + 'Stembridge', + 'Satcher', + 'Britz', + 'Hommel', + 'Llanas', + 'Pathak', + 'Schwartzman', + 'Janz', + 'Hickle', + 'Deakins', + 'Mantle', + 'Billing', + 'Veiga', + 'Darbonne', + 'Angelle', + 'Granderson', + 'Odoms', + 'Mondesir', + 'Ducksworth', + 'Anker', + 'Deneen', + 'Follmer', + 'Norred', + 'Whitecotton', + 'Halsted', + 'Schiele', + 'Reddin', + 'Pichon', + 'Eustice', + 'Finelli', + 'Kawasaki', + 'Kerekes', + 'Surrett', + 'Divers', + 'Kerney', + 'Bohlman', + 'Oberst', + 'Prough', + 'Tarwater', + 'Wangler', + 'Piceno', + 'Persico', + 'Lastra', + 'Fillman', + 'Barlett', + 'Cort', + 'Kuchar', + 'Plaisted', + 'Rufo', + 'Whitmarsh', + 'Fusaro', + 'Bajwa', + 'Belter', + 'Aldama', + 'Conlee', + 'Tweedie', + 'Greear', + 'Riviera', + 'Stormer', + 'Flannagan', + 'Heatley', + 'Feazell', + 'Bastidas', + 'Benninger', + 'Canseco', + 'Hanners', + 'Kreiner', + 'Pestana', + 'Simerly', + 'Such', + 'Tiedeman', + 'Weible', + 'Zawadzki', + 'Rayman', + 'Crose', + 'Sheeler', + 'Kirven', + 'Winford', + 'Mackall', + 'Balderson', + 'Calleja', + 'Klinefelter', + 'Lauffer', + 'Probert', + 'Melero', + 'Ravelo', + 'Degroff', + 'Pylant', + 'Ricco', + 'Varona', + 'Pickney', + 'Bachmeier', + 'Dulay', + 'Hanover', + 'Virgilio', + 'Spino', + 'Bohon', + 'Cantin', + 'Pettijohn', + 'Branigan', + 'Duhe', + 'Perine', + 'Thedford', + 'Shamburger', + 'Guarnieri', + 'Guptill', + 'Nyland', + 'Setliff', + 'Shreffler', + 'Viggiano', + 'Pries', + 'Sunde', + 'Bulmer', + 'Platts', + 'Jeremiah', + 'Fawley', + 'Jansson', + 'Rebelo', + 'Prochnow', + 'Waldeck', + 'Citron', + 'Roughton', + 'Ryckman', + 'Molano', + 'Cannaday', + 'Ned', + 'Beckerman', + 'Galaz', + 'Graziani', + 'Kawakami', + 'Limones', + 'Mousseau', + 'Riha', + 'Huser', + 'Casady', + 'Kirker', + 'Benish', + 'Tomczyk', + 'Hallahan', + 'Kue', + 'Siple', + 'Kandel', + 'Maring', + 'Bosak', + 'Gandolfo', + 'Reichart', + 'Robarge', + 'Shufelt', + 'Forry', + 'Richart', + 'Shireman', + 'Tozzi', + 'Trudel', + 'Tat', + 'Maday', + 'Faw', + 'Lawrie', + 'Mingle', + 'Yasin', + 'Cutrone', + 'Fairbrother', + 'Ficken', + 'Kluesner', + 'Lagana', + 'Schoenborn', + 'Greb', + 'Stromain', + 'Mcpeters', + 'Toepfer', + 'Wehrman', + 'Kozma', + 'Rohner', + 'Kittel', + 'Louderback', + 'Daughtrey', + 'Philippe', + 'Bargo', + 'Cullinane', + 'Fama', + 'Fredenburg', + 'Pedone', + 'Santillanes', + 'Zahner', + 'Zupan', + 'Dundon', + 'Gilfillan', + 'Grego', + 'Otter', + 'Jamil', + 'Beaubien', + 'Collingwood', + 'Quinney', + 'Botero', + 'Edstrom', + 'Flink', + 'Ortner', + 'Schmidtke', + 'Reichle', + 'Leder', + 'Pelosi', + 'Fiorito', + 'Berber', + 'Hislop', + 'Dunstan', + 'Favorite', + 'Wooding', + 'Gariepy', + 'Gottesman', + 'Guercio', + 'Konz', + 'Kothari', + 'Laguardia', + 'Lamphier', + 'Puetz', + 'Casagrande', + 'Quay', + 'Rieth', + 'Vowell', + 'Mcanulty', + 'Mian', + 'Lucus', + 'Alvizo', + 'Domanski', + 'Elling', + 'Maniaci', + 'Neumeyer', + 'Piraino', + 'Schroll', + 'Willsey', + 'Avellaneda', + 'Wilcoxen', + 'Murrey', + 'Bennette', + 'Boyajian', + 'Distler', + 'Lindamood', + 'Maclaren', + 'Onken', + 'Stefano', + 'Uselton', + 'Wilgus', + 'Rardin', + 'Boen', + 'Stillwagon', + 'Satter', + 'Allis', + 'Capell', + 'Nedd', + 'Arcand', + 'Breit', + 'Horwath', + 'Lakatos', + 'Roling', + 'Hessel', + 'Cusson', + 'Rockefeller', + 'Shiffer', + 'Briney', + 'Celeste', + 'Sayed', + 'Revelle', + 'Corker', + 'Baldonado', + 'Lokken', + 'Plymale', + 'Sugden', + 'Twist', + 'Parten', + 'Geil', + 'Sime', + 'Grisby', + 'Jeanty', + 'Baroni', + 'Ditullio', + 'Domenico', + 'Geiss', + 'Gemmill', + 'Leng', + 'Lewicki', + 'Weyandt', + 'Haycock', + 'Coonce', + 'Pillar', + 'Medcalf', + 'Sall', + 'Goldsborough', + 'Bergerson', + 'Daffron', + 'Hinchman', + 'Leibold', + 'Sarkissian', + 'Serratos', + 'Uhlig', + 'Wurth', + 'Ost', + 'Steinmann', + 'Saum', + 'Bullion', + 'Dejonge', + 'Assad', + 'Adelson', + 'Sholes', + 'Clermont', + 'Tabron', + 'Kilduff', + 'Millspaugh', + 'Partyka', + 'Santore', + 'Wensel', + 'Zima', + 'Raschke', + 'Simonis', + 'Tuell', + 'Obriant', + 'Lewter', + 'Nealey', + 'Baranski', + 'Bloomberg', + 'Franchi', + 'Klemme', + 'Raborn', + 'Wohlgemuth', + 'Basta', + 'Bernardini', + 'Canlas', + 'Yeargin', + 'Stingley', + 'Crosland', + 'Bob', + 'Ascher', + 'Dibona', + 'Farabaugh', + 'Kilcoyne', + 'Poblete', + 'Beato', + 'Teasdale', + 'Rossell', + 'Lawhorne', + 'Jama', + 'Behringer', + 'Hallstrom', + 'Kitzman', + 'Klenk', + 'Mctigue', + 'Onate', + 'Rodda', + 'Siegal', + 'Pepple', + 'Tash', + 'Gager', + 'Hing', + 'Yokley', + 'Epting', + 'Mangham', + 'Zackery', + 'Blackerby', + 'Canedo', + 'Glatz', + 'Hilker', + 'Hummell', + 'Mangels', + 'Gamel', + 'Gang', + 'Hooser', + 'Moates', + 'Mutch', + 'Lyerly', + 'Vesey', + 'Satterthwaite', + 'Calcote', + 'Saulsbury', + 'Averette', + 'Ates', + 'Rita', + 'Vicencio', + 'Wismer', + 'Mayoral', + 'Crader', + 'Levens', + 'Joel', + 'Haye', + 'Drager', + 'Eiden', + 'Escutia', + 'Inzunza', + 'Moroz', + 'Sepulvado', + 'Tomaselli', + 'Zartman', + 'Isaak', + 'Philippi', + 'Mcgeary', + 'Taha', + 'Buttler', + 'Crisci', + 'Kot', + 'Micek', + 'Mondello', + 'Petrarca', + 'Rossini', + 'Villalvazo', + 'Weedman', + 'Mitten', + 'Favre', + 'Varnes', + 'Betancur', + 'Bevington', + 'Bockman', + 'Feldstein', + 'Kujawski', + 'Siemer', + 'Soderlund', + 'Fricker', + 'Gerstein', + 'Kick', + 'Haff', + 'Brackman', + 'Hulen', + 'Nephew', + 'Birkett', + 'Gardenhire', + 'Garn', + 'Kellenberger', + 'Mogensen', + 'Murata', + 'Weisbrod', + 'Vilchis', + 'Meder', + 'Akey', + 'Mcmanis', + 'Delatte', + 'Guiles', + 'Turnbough', + 'Murrah', + 'Kilgo', + 'Marcelin', + 'Cecchini', + 'Chrysler', + 'Eick', + 'Fletes', + 'Luevanos', + 'Kurt', + 'Firman', + 'Hensen', + 'Champine', + 'Holford', + 'Appelbaum', + 'Ciampa', + 'Florentino', + 'Lorton', + 'Lubinski', + 'Moquin', + 'Welke', + 'Grinberg', + 'Bolstad', + 'Ade', + 'Outten', + 'Grear', + 'Haith', + 'Borntreger', + 'Steinhauser', + 'Facio', + 'Preslar', + 'Speirs', + 'Grasser', + 'Zuck', + 'Deslauriers', + 'Frates', + 'Mayville', + 'Suddeth', + 'Littlepage', + 'Aversa', + 'Chagolla', + 'Godshall', + 'Jordahl', + 'Oakland', + 'Monsen', + 'Rudolf', + 'Mccollister', + 'Mickles', + 'Flaig', + 'Friberg', + 'Grubaugh', + 'Sliwinski', + 'Stach', + 'Bechtol', + 'Pasch', + 'Keebler', + 'Fagin', + 'Mister', + 'Wynter', + 'Bednarek', + 'Blansett', + 'Crossett', + 'Kettering', + 'Lafata', + 'Raffa', + 'Roig', + 'Schopp', + 'Voegele', + 'Waldschmidt', + 'Clatterbuck', + 'Amer', + 'Kraut', + 'Furniss', + 'Edgecomb', + 'Aspinwall', + 'Buckelew', + 'Loranger', + 'Koppel', + 'Vernier', + 'Latino', + 'Hayton', + 'Girod', + 'Primrose', + 'Jetter', + 'Hyche', + 'Ottley', + 'Isidro', + 'Kort', + 'Mulroy', + 'Reznik', + 'Tozer', + 'Vanderheyden', + 'Kassab', + 'Paro', + 'Belen', + 'Vandever', + 'Harsch', + 'Rawley', + 'Gonder', + 'Delbridge', + 'Alumbaugh', + 'Basulto', + 'Hoehne', + 'Mccaig', + 'Qin', + 'Rasnake', + 'Tewksbury', + 'Ratajczak', + 'Reinbold', + 'Mcgillivray', + 'Nuccio', + 'Steinbeck', + 'Deland', + 'Callow', + 'Wootten', + 'Lytton', + 'Calix', + 'Stinger', + 'Slider', + 'Cadman', + 'Faulconer', + 'Higashi', + 'Lamping', + 'Sellner', + 'Walko', + 'Kilkenny', + 'Charter', + 'Gauntt', + 'Bronk', + 'Legare', + 'Hukill', + 'Kulikowski', + 'Kunde', + 'Michelsen', + 'Mottola', + 'Pasion', + 'Stimmel', + 'Deavila', + 'Lian', + 'Koga', + 'Kitchin', + 'Whitner', + 'Bucholz', + 'Kilbride', + 'Klumpp', + 'Osinski', + 'Petrich', + 'Saar', + 'Robards', + 'Flakes', + 'Accardo', + 'Gebauer', + 'Matyas', + 'Montesano', + 'Schiefer', + 'Zuehlke', + 'Swartout', + 'Gidley', + 'Burghardt', + 'Delcambre', + 'Jerman', + 'Laufenberg', + 'Paterno', + 'Piccione', + 'Wenning', + 'Wilhelmi', + 'Rathjen', + 'Bauch', + 'Hiott', + 'Bagnall', + 'Miskell', + 'Snellings', + 'Sally', + 'Bjornson', + 'Din', + 'Kroeker', + 'Mitra', + 'Saxena', + 'Hausler', + 'Scogin', + 'Jeronimo', + 'Holderfield', + 'Cruze', + 'Christina', + 'Beville', + 'Whitehorn', + 'Bembry', + 'Fludd', + 'Abboud', + 'Blomgren', + 'Friddle', + 'Jarvi', + 'Nastasi', + 'Tomich', + 'Peinado', + 'Rinaldo', + 'Proudfoot', + 'Down', + 'Lawry', + 'Noor', + 'Bachelor', + 'Mullenax', + 'Pocock', + 'Resler', + 'Sprunger', + 'Wiegel', + 'Wohlers', + 'Niedzwiecki', + 'Bourgoin', + 'Grist', + 'Nora', + 'Gude', + 'Mcgaughy', + 'Borror', + 'Bushee', + 'Crego', + 'Engberg', + 'Karle', + 'Raso', + 'Rayas', + 'Roehrig', + 'Villamil', + 'Croucher', + 'Candido', + 'Rockhill', + 'Dahn', + 'Philp', + 'Grasty', + 'Basnight', + 'Cacioppo', + 'Heavener', + 'Hoenig', + 'Janisch', + 'Labombard', + 'Sheng', + 'Wettstein', + 'Wymore', + 'Zuluaga', + 'Canova', + 'Maclennan', + 'Tuley', + 'Geddings', + 'Cayetano', + 'Bogar', + 'Malbrough', + 'Bradish', + 'Chiaramonte', + 'Eguia', + 'Loux', + 'Nemecek', + 'Ouimet', + 'Roxas', + 'Yoshioka', + 'Cossio', + 'Sleight', + 'Walla', + 'Younan', + 'Hee', + 'Bartlow', + 'Parchman', + 'Leaks', + 'Folz', + 'Knittel', + 'Lovvorn', + 'Melick', + 'Weingartner', + 'Eustace', + 'Robbs', + 'Jacquet', + 'Direnzo', + 'Domke', + 'Kestler', + 'Pavelka', + 'Pileggi', + 'Silvestro', + 'Leedom', + 'Kyte', + 'Espey', + 'Kincannon', + 'Robicheaux', + 'Lard', + 'Falkenstein', + 'Fino', + 'Kotz', + 'Lammert', + 'Markovic', + 'Mcwaters', + 'Shibata', + 'Garoutte', + 'Brum', + 'Hora', + 'Gundrum', + 'Leer', + 'Coller', + 'Delsignore', + 'Ebarb', + 'Heras', + 'Skolnick', + 'Sponseller', + 'Baltes', + 'Rabinovich', + 'Welden', + 'Papas', + 'Bingman', + 'Neto', + 'Burrough', + 'Ollie', + 'Deitrick', + 'Hermansen', + 'Datta', + 'Gebo', + 'Bulla', + 'Rippey', + 'Solon', + 'Draughon', + 'Sylvestre', + 'Outen', + 'Westfield', + 'Daoust', + 'Kuan', + 'Kubat', + 'Labuda', + 'Olejniczak', + 'Radomski', + 'Scheuermann', + 'Schunk', + 'Tuazon', + 'Wineland', + 'Gizzi', + 'Millay', + 'Hamp', + 'Murdaugh', + 'Hayles', + 'Plowden', + 'Lesure', + 'Artrip', + 'Kenneally', + 'Piehl', + 'Vandermeulen', + 'Camberos', + 'Hochberg', + 'Sinner', + 'Crass', + 'Gade', + 'Tedrick', + 'Nicholl', + 'Speece', + 'Chatterjee', + 'Gillihan', + 'Luzzi', + 'Obyrne', + 'Uchida', + 'Kidney', + 'Dorough', + 'Dangler', + 'Mcneel', + 'Ruley', + 'Mcloud', + 'Smarr', + 'Gayles', + 'Janiszewski', + 'Kubo', + 'Mckibbin', + 'Szatkowski', + 'Lehnert', + 'Mcilvain', + 'Mcclish', + 'Mcentyre', + 'Strawder', + 'Briere', + 'Headlee', + 'Leszczynski', + 'Mauser', + 'Rask', + 'Wisler', + 'Burba', + 'Shaulis', + 'Showman', + 'Proto', + 'Creasman', + 'Slye', + 'Dunwoody', + 'Ellingsworth', + 'Linebaugh', + 'Riva', + 'Um', + 'Muldowney', + 'Burlew', + 'Gettings', + 'Clingman', + 'Shield', + 'Trollinger', + 'Stiger', + 'Kellman', + 'Arviso', + 'Boettger', + 'Deak', + 'Deiter', + 'Hackenberg', + 'Langone', + 'Lichter', + 'Siano', + 'Wrinkle', + 'Dickert', + 'Boor', + 'Ludington', + 'Griffing', + 'Perin', + 'Woodby', + 'Quail', + 'Harriss', + 'Bilotta', + 'Chino', + 'Cocke', + 'Corbell', + 'Dearden', + 'Facundo', + 'Gaskell', + 'Grieser', + 'Houts', + 'Zuk', + 'Yamauchi', + 'Caouette', + 'Perham', + 'Hewson', + 'Keppel', + 'Artiaga', + 'Sa', + 'Ginger', + 'Goosby', + 'Bollig', + 'Grippo', + 'Hoffmeyer', + 'Klaas', + 'Rohlfing', + 'Stolp', + 'Vielma', + 'Gresh', + 'Mignone', + 'Parsell', + 'Sprout', + 'Hase', + 'Nadal', + 'Joye', + 'Butkus', + 'Donlan', + 'Fuhrer', + 'Grobe', + 'Haverkamp', + 'Janecek', + 'Pancoast', + 'Rathke', + 'Scheibe', + 'Schneller', + 'Scally', + 'Valeriano', + 'Fail', + 'Everage', + 'Murff', + 'Demayo', + 'Dieterich', + 'Kramp', + 'Macchia', + 'Ruyle', + 'Zuidema', + 'Tischer', + 'Palo', + 'Bahn', + 'Hartson', + 'Rosborough', + 'Hartke', + 'Hixenbaugh', + 'Matlack', + 'Hoefler', + 'Hsia', + 'Cech', + 'Donham', + 'Szafranski', + 'Jennison', + 'Emmer', + 'Christians', + 'Swigert', + 'Mclawhorn', + 'Costas', + 'Culligan', + 'Eisenstein', + 'Joos', + 'Villacorta', + 'Majerus', + 'Lukowski', + 'Byford', + 'Canepa', + 'Jeppson', + 'Larison', + 'Waechter', + 'Bleich', + 'Trigo', + 'Lill', + 'Mcisaac', + 'Oflaherty', + 'Dedman', + 'Lynes', + 'Everidge', + 'Armfield', + 'Cadieux', + 'Dembowski', + 'Flewelling', + 'Guadagno', + 'Lamendola', + 'Meidinger', + 'Muzzy', + 'Pacelli', + 'Pangle', + 'Denzer', + 'Sharman', + 'Venzor', + 'Shadwick', + 'Saine', + 'Lighty', + 'Twine', + 'Buehner', + 'Caruana', + 'Filipiak', + 'Fiori', + 'Kellison', + 'Odonovan', + 'Ragone', + 'Enyeart', + 'Coale', + 'Coombes', + 'Yarrington', + 'Leno', + 'Coad', + 'Well', + 'Labranche', + 'Banaszak', + 'Jovanovic', + 'Junk', + 'Kratochvil', + 'Marchi', + 'Mcnitt', + 'Monnin', + 'Portales', + 'Nazzaro', + 'Laramie', + 'Kohlman', + 'Pinette', + 'Craw', + 'Aldred', + 'Jolicoeur', + 'Nevers', + 'Boseman', + 'Apostol', + 'Barbaro', + 'Dirienzo', + 'Kimrey', + 'Knaack', + 'Marenco', + 'Meixner', + 'Placek', + 'Prigge', + 'Sablan', + 'Stoecker', + 'Ulrey', + 'Madonia', + 'Mariotti', + 'Hypes', + 'Teti', + 'Pothier', + 'Duer', + 'Reay', + 'Charlie', + 'Alix', + 'Cropp', + 'Wellons', + 'Haugland', + 'Malkowski', + 'Powley', + 'Query', + 'Stolle', + 'Twedt', + 'Grech', + 'Musson', + 'Larrimore', + 'Esper', + 'Suleiman', + 'Gillie', + 'Aaronson', + 'Brueggeman', + 'Kupfer', + 'Orf', + 'Pozzi', + 'Rayos', + 'Scheiner', + 'Schmoll', + 'Sirota', + 'Trickey', + 'Ahuja', + 'Halm', + 'Jaycox', + 'Carithers', + 'Bjorkman', + 'Klar', + 'Lembke', + 'Nordyke', + 'Primeau', + 'Wachs', + 'Wissinger', + 'Doonan', + 'Mikulski', + 'Murthy', + 'Raju', + 'Thrailkill', + 'Splawn', + 'Lockamy', + 'Brassell', + 'Mcshan', + 'Hawbaker', + 'Kracht', + 'Lahman', + 'Lauritsen', + 'Metzner', + 'Presser', + 'Rapoport', + 'Romani', + 'Wolken', + 'Bertone', + 'Bhat', + 'Lenzi', + 'Lefort', + 'Makar', + 'Melnyk', + 'Siguenza', + 'Ristow', + 'Piller', + 'Mcgaugh', + 'Lampton', + 'Delva', + 'Gethers', + 'Leday', + 'Bateson', + 'Beckstrom', + 'Bedsole', + 'Hauber', + 'Hodgkinson', + 'Croghan', + 'Glanz', + 'Gaver', + 'Pinkley', + 'Traynham', + 'Heffley', + 'Indelicato', + 'Lindblad', + 'Petrik', + 'Ptacek', + 'Capen', + 'Carrara', + 'Ortuno', + 'Lobue', + 'Corella', + 'Lybrand', + 'Myler', + 'Steer', + 'Mckamey', + 'Coman', + 'Auker', + 'Escue', + 'Knell', + 'Mahood', + 'Tillinghast', + 'Deremer', + 'Janak', + 'Naegele', + 'Patnaude', + 'Leahey', + 'Pupo', + 'Bouse', + 'Bradstreet', + 'Symes', + 'Callies', + 'Duncanson', + 'Blanche', + 'Span', + 'Shakir', + 'Finneran', + 'Lenker', + 'Mendola', + 'Navin', + 'Palka', + 'Spanier', + 'Stahler', + 'Vannatter', + 'Botta', + 'Gonser', + 'Edelson', + 'Brashier', + 'Golla', + 'Parramore', + 'Bigby', + 'El', + 'Habeck', + 'Kleinhans', + 'Knobel', + 'Pekar', + 'Remmers', + 'Dea', + 'Foo', + 'Plumer', + 'Combest', + 'Godbee', + 'Hilaire', + 'Lepak', + 'Sgro', + 'Vierling', + 'Harm', + 'Holtsclaw', + 'Gaetano', + 'Kindler', + 'Sabbagh', + 'Politte', + 'Amor', + 'Tilly', + 'Trone', + 'Callaham', + 'Roussell', + 'Asplund', + 'Cacciatore', + 'Dries', + 'Friedl', + 'Hartranft', + 'Kimmell', + 'Lengacher', + 'Scardino', + 'Werley', + 'Zappa', + 'Hust', + 'Seiden', + 'Bultman', + 'Withey', + 'Brandow', + 'Oler', + 'Ladouceur', + 'Celli', + 'Condie', + 'Egge', + 'Kleman', + 'Krafft', + 'Margulies', + 'Weier', + 'Mikels', + 'Pavel', + 'Sigel', + 'Foulke', + 'Kluttz', + 'Mcgown', + 'Acero', + 'Gering', + 'Knauff', + 'Ruesch', + 'Rydberg', + 'Shonk', + 'Weisgerber', + 'Wieber', + 'Zinser', + 'Lilienthal', + 'Crosbie', + 'Luckie', + 'Chenier', + 'Aceto', + 'Atnip', + 'Hisey', + 'Imhof', + 'Klocke', + 'Renderos', + 'Schaad', + 'Shoults', + 'Slevin', + 'Tenenbaum', + 'Vrana', + 'Dicesare', + 'Colarusso', + 'Killgore', + 'Courtois', + 'Tysinger', + 'Agard', + 'Brutus', + 'Woodfork', + 'Boeckman', + 'Breitenstein', + 'Downen', + 'Franzese', + 'Garbe', + 'Iannucci', + 'Kist', + 'Mccolgan', + 'Seib', + 'Sereno', + 'Varma', + 'Fought', + 'Barcomb', + 'Happ', + 'Yeaton', + 'Sharples', + 'Huson', + 'Askin', + 'Elliston', + 'Birks', + 'Allums', + 'Richarson', + 'Arterburn', + 'Auyeung', + 'Engman', + 'Segall', + 'Sjoberg', + 'Sturman', + 'Buys', + 'Basford', + 'Gaut', + 'Hollomon', + 'Antal', + 'Groseclose', + 'Motyka', + 'Reddell', + 'Ansel', + 'Fausett', + 'Girgis', + 'Brownson', + 'Pouncy', + 'Behler', + 'Ciesla', + 'Dewall', + 'Helmers', + 'Pizzuto', + 'Sao', + 'Hourigan', + 'Novelli', + 'Kuta', + 'Gau', + 'Verville', + 'Parkison', + 'Souter', + 'Whitelaw', + 'Vercher', + 'Coger', + 'Issac', + 'Cardamone', + 'Heneghan', + 'Herrero', + 'Plancarte', + 'Reach', + 'Sarinana', + 'Zweig', + 'Berkheimer', + 'Brosseau', + 'Angstadt', + 'Popoca', + 'Brode', + 'Presswood', + 'Hannibal', + 'Pigford', + 'Argento', + 'Dieringer', + 'Kinnett', + 'Maclachlan', + 'Perko', + 'Rosenkranz', + 'Kobus', + 'Merk', + 'Prevatte', + 'Kaya', + 'Didio', + 'Thong', + 'Cowin', + 'Tumlin', + 'Lopp', + 'Callier', + 'Sesay', + 'Beerman', + 'Creger', + 'Eyster', + 'Libbey', + 'Minear', + 'Pontious', + 'Stemen', + 'Strahl', + 'Trillo', + 'Dively', + 'Lackner', + 'Welte', + 'Likes', + 'Mazzoni', + 'Resh', + 'Oser', + 'Dilday', + 'Requena', + 'Bail', + 'Ellen', + 'Buchanon', + 'Almeda', + 'Dimino', + 'Griess', + 'Wetzler', + 'Kriegel', + 'Attanasio', + 'Reighard', + 'Alling', + 'Wiginton', + 'Penfield', + 'Barbe', + 'Alred', + 'Ridout', + 'Lucien', + 'Cerullo', + 'Esterline', + 'Garriott', + 'Hendershott', + 'Kaczmarczyk', + 'Pazos', + 'Racicot', + 'Kowaleski', + 'Lippold', + 'Bankert', + 'Emigh', + 'Cupps', + 'Jagger', + 'Leavens', + 'Lies', + 'Ater', + 'Bleau', + 'Pellot', + 'Crosslin', + 'Faulks', + 'Antwine', + 'Calixte', + 'Brod', + 'Hamad', + 'Junkin', + 'Koeppel', + 'Leifer', + 'Vannest', + 'Olcott', + 'Delange', + 'Hillen', + 'Merlin', + 'Gundy', + 'Hogans', + 'Arseneau', + 'Buzard', + 'Ewalt', + 'Persing', + 'Pursel', + 'Rohrs', + 'Sisemore', + 'Vilchez', + 'Bernath', + 'Rosenbalm', + 'Woolverton', + 'Gibbins', + 'Like', + 'Larsson', + 'Savidge', + 'Strohmeyer', + 'Trentham', + 'Wotring', + 'Boster', + 'Sewall', + 'Glore', + 'Burtis', + 'Marchman', + 'Fouche', + 'Okafor', + 'Khatri', + 'Lengel', + 'Pribyl', + 'Rodewald', + 'Cafaro', + 'Mattix', + 'Shingler', + 'Seawell', + 'Square', + 'Belnap', + 'Heidemann', + 'Kretz', + 'Nebeker', + 'Zemke', + 'Reiners', + 'Cassels', + 'Hout', + 'Favor', + 'Rattray', + 'Custard', + 'Bellucci', + 'Bucklew', + 'Casavant', + 'Davanzo', + 'Kleber', + 'Koeppen', + 'Kulpa', + 'Ledonne', + 'Scarano', + 'Schaar', + 'Staiger', + 'Trigueros', + 'Trobaugh', + 'Tufano', + 'Tschetter', + 'Labra', + 'Beverage', + 'Hulet', + 'Stairs', + 'Waggener', + 'Candy', + 'Kaba', + 'Feiner', + 'Ipock', + 'Nelligan', + 'Pottorff', + 'Beno', + 'Beausoleil', + 'Mayen', + 'Kalil', + 'Deller', + 'Cormack', + 'Hayne', + 'Below', + 'Bundick', + 'Avakian', + 'Desmet', + 'Dobler', + 'Dykeman', + 'Eckstrom', + 'Mahle', + 'Meers', + 'Bortner', + 'Kroon', + 'Lindenmuth', + 'Mcnichol', + 'Sechrest', + 'Abdulla', + 'Gaudin', + 'Lamers', + 'Luffman', + 'Marchione', + 'Paredez', + 'Polster', + 'Maresh', + 'Kristoff', + 'Rickel', + 'Frary', + 'Lorance', + 'Round', + 'Toye', + 'Claybrook', + 'Senegal', + 'Gayhart', + 'Mcmackin', + 'Sagan', + 'Sarkar', + 'Whistler', + 'Stutsman', + 'Alderfer', + 'Spainhour', + 'Karol', + 'Ke', + 'Mifflin', + 'Salah', + 'Alberty', + 'Hynson', + 'Beisel', + 'Castelo', + 'Dau', + 'Diliberto', + 'Dollins', + 'Fiorini', + 'Fritzler', + 'Hanan', + 'Hauschild', + 'Overholser', + 'Wrobleski', + 'Peil', + 'Bellon', + 'Buice', + 'Rolls', + 'Shack', + 'Arakelian', + 'Carpino', + 'Liou', + 'Lydick', + 'Supple', + 'Tammaro', + 'Walbridge', + 'Jandreau', + 'Riter', + 'Roeser', + 'Merson', + 'Bole', + 'Franey', + 'Berrett', + 'Carton', + 'Mcnish', + 'Earnhart', + 'Lehrman', + 'Lipski', + 'Mandelbaum', + 'Tanabe', + 'Mirabile', + 'Ocegueda', + 'Clementi', + 'Shake', + 'Buckle', + 'Rowsey', + 'Eifert', + 'Giesen', + 'Standiford', + 'Vallecillo', + 'Walworth', + 'Berkshire', + 'Feit', + 'Lande', + 'Fiddler', + 'Deputy', + 'Feemster', + 'Evelyn', + 'Bocchino', + 'Cozza', + 'Dirocco', + 'Kock', + 'Luisi', + 'Marcantonio', + 'Presti', + 'Rahimi', + 'Ridinger', + 'Sergi', + 'Viana', + 'Kabat', + 'Suriel', + 'Mester', + 'Bozman', + 'Huffines', + 'Linck', + 'Lodato', + 'Ownbey', + 'Pietz', + 'Rudnicki', + 'Schoener', + 'Schrag', + 'Spicher', + 'Sze', + 'Villella', + 'Steinle', + 'Seaberg', + 'Derks', + 'Mavis', + 'Luellen', + 'Garlington', + 'Nimmons', + 'Brevard', + 'Seabrooks', + 'Ahlquist', + 'Golembiewski', + 'Kochis', + 'Popov', + 'Poulter', + 'Redington', + 'Wingrove', + 'Krepps', + 'Viars', + 'Gallatin', + 'Gilham', + 'Jimison', + 'Glosson', + 'Campeau', + 'Goodhart', + 'Koth', + 'Lettieri', + 'Siragusa', + 'Sojka', + 'Tichy', + 'Viar', + 'Carrozza', + 'Chaffins', + 'Eagleson', + 'Prestwood', + 'Deshazer', + 'Ike', + 'Kubacki', + 'Minogue', + 'Sunseri', + 'Turnbaugh', + 'Heminger', + 'Delira', + 'Jani', + 'Platte', + 'Waterson', + 'Keeble', + 'Kiper', + 'Crigler', + 'Swaby', + 'Brisbin', + 'Galiano', + 'Negley', + 'Regal', + 'Stottlemyer', + 'Volkmann', + 'Herrold', + 'Cypert', + 'Markman', + 'Laman', + 'Williard', + 'Terrio', + 'Raulston', + 'Harrow', + 'Humiston', + 'Kantner', + 'Mcmonagle', + 'Polasek', + 'Ruocco', + 'Schelling', + 'Seip', + 'Woller', + 'Despres', + 'Melius', + 'Keiffer', + 'Voges', + 'Figg', + 'Judice', + 'Henery', + 'Dejarnette', + 'Prosper', + 'Duenez', + 'Frenette', + 'Jaimez', + 'Krist', + 'Kuch', + 'Schlachter', + 'Traeger', + 'Mrozinski', + 'Colberg', + 'Lade', + 'Been', + 'Revere', + 'Greely', + 'Belizaire', + 'Amberg', + 'Cerniglia', + 'Lattanzio', + 'Leitz', + 'Ocker', + 'Ratto', + 'Thornburgh', + 'Yule', + 'Hibner', + 'Puerto', + 'Shoultz', + 'Baley', + 'Linley', + 'Alfrey', + 'Bazaldua', + 'Deniz', + 'Lohnes', + 'Marder', + 'Pelland', + 'Urick', + 'Loberg', + 'Rempel', + 'Faux', + 'Tomkins', + 'Gail', + 'Mccardell', + 'Reuben', + 'Brabant', + 'Hutzler', + 'Liedtke', + 'Nowack', + 'Pittsley', + 'Pelc', + 'Darragh', + 'Pae', + 'Blanke', + 'Brinks', + 'Delap', + 'Brea', + 'Milsap', + 'Borneman', + 'Crofts', + 'Nakai', + 'Silguero', + 'Speciale', + 'Martindelcampo', + 'Vandenburg', + 'Wimsatt', + 'Harbor', + 'Mccorvey', + 'Bensinger', + 'Carhart', + 'Condo', + 'Lemen', + 'Malchow', + 'Vandewater', + 'Ventresca', + 'Morena', + 'Mendell', + 'Faustino', + 'Kleiber', + 'Alberson', + 'Lamonte', + 'Kiner', + 'Belgrave', + 'Blitz', + 'Dildine', + 'Gosch', + 'Grabill', + 'Klemp', + 'Larrea', + 'Pallas', + 'Leonhard', + 'Littler', + 'Dilling', + 'Weatherbee', + 'Robnett', + 'Lacount', + 'Brackins', + 'Counterman', + 'Divincenzo', + 'Dobrowolski', + 'Eppard', + 'Estepp', + 'Gahan', + 'Steininger', + 'Tancredi', + 'Wixom', + 'Combes', + 'Dena', + 'Warn', + 'Teems', + 'Askey', + 'Delmar', + 'Ogles', + 'Herriott', + 'Aguinaldo', + 'In', + 'Kinter', + 'Moul', + 'Santaniello', + 'Tringali', + 'Vanasse', + 'Vanwagoner', + 'Whitesel', + 'Vanderwal', + 'Friedmann', + 'Kalis', + 'Cayer', + 'Para', + 'Wander', + 'Cothron', + 'Betters', + 'Cloward', + 'Cusano', + 'Encinias', + 'Imai', + 'Lalone', + 'Saks', + 'Nosal', + 'Crossan', + 'Caverly', + 'Tewell', + 'Lowney', + 'Merle', + 'Meighan', + 'Labat', + 'Pou', + 'Linsey', + 'Gaviria', + 'Manthei', + 'Marquina', + 'Siegert', + 'Blondin', + 'Maskell', + 'Kimpel', + 'Cappel', + 'Tootle', + 'Folkes', + 'Mainor', + 'Offord', + 'Clagg', + 'Minshew', + 'Niebuhr', + 'Schanz', + 'Stotz', + 'Takeda', + 'Huelsman', + 'Madril', + 'Monico', + 'Stradley', + 'Thein', + 'Cannell', + 'Malson', + 'Ludden', + 'Couts', + 'Mishoe', + 'Dales', + 'Slemp', + 'Stueve', + 'Ziemann', + 'Fluke', + 'Vitali', + 'Monn', + 'Dooling', + 'Lambe', + 'Cail', + 'Louder', + 'Lotts', + 'Augusta', + 'Ando', + 'Depaolo', + 'Egolf', + 'Hibdon', + 'Marzan', + 'Mccawley', + 'Mcgivern', + 'Minjares', + 'Mullally', + 'Portner', + 'Vinciguerra', + 'Wolpert', + 'Yingst', + 'Checo', + 'Starck', + 'Ra', + 'Credle', + 'Baldauf', + 'Bamberger', + 'Besch', + 'Caulkins', + 'Huyck', + 'Portela', + 'Walberg', + 'Kutcher', + 'Hunger', + 'Trant', + 'Cumbee', + 'Cheadle', + 'Drewery', + 'Andrada', + 'Dollinger', + 'Dondero', + 'Salvati', + 'Sefton', + 'Siemers', + 'Sitz', + 'Smale', + 'Wenk', + 'Reschke', + 'Puglia', + 'Koob', + 'Overland', + 'Furrer', + 'Gohl', + 'Hegge', + 'Hentschel', + 'Huberty', + 'Krise', + 'Stasiak', + 'Tripoli', + 'Palomera', + 'Norling', + 'Smucker', + 'Hennes', + 'Metro', + 'Himmel', + 'Paolino', + 'Prato', + 'Wommack', + 'Mcpheeters', + 'Ronald', + 'Eppinger', + 'Cantey', + 'Appell', + 'Capellan', + 'Fielden', + 'Garfias', + 'Heit', + 'Janusz', + 'Pagliaro', + 'Pitz', + 'Winegardner', + 'Gregorich', + 'Schlager', + 'Selvidge', + 'Shultis', + 'Severn', + 'Buffum', + 'Crafts', + 'Antony', + 'Timpson', + 'Deveaux', + 'Maese', + 'Merlos', + 'Mojarro', + 'Policastro', + 'Tawil', + 'Flamm', + 'Aasen', + 'Lipkin', + 'Dyches', + 'Caulk', + 'Rampersad', + 'Pettie', + 'Hagwood', + 'Jedlicka', + 'Paoli', + 'Perkey', + 'Shaub', + 'Vires', + 'Glad', + 'Mandrell', + 'Angeli', + 'Antuna', + 'Bessler', + 'Cebula', + 'Heagy', + 'Mankowski', + 'Sitler', + 'Vanleuven', + 'Blanck', + 'Dannenberg', + 'Moren', + 'Hites', + 'Leckie', + 'Tham', + 'Dower', + 'Beans', + 'Alls', + 'Sipp', + 'Dygert', + 'Kubicek', + 'Matsumura', + 'Shiroma', + 'Smiddy', + 'Szilagyi', + 'Winkleman', + 'Zentz', + 'Niehoff', + 'Boedeker', + 'Dimmitt', + 'Trew', + 'Wilner', + 'Traughber', + 'Bardales', + 'Borbon', + 'Bramhall', + 'Crofoot', + 'Desilets', + 'Disch', + 'Kehrer', + 'Leffingwell', + 'Olalde', + 'Wawrzyniak', + 'Jagodzinski', + 'Schwerin', + 'Heiney', + 'Hirano', + 'Rueter', + 'Sarris', + 'Magnan', + 'Rigsbee', + 'Blay', + 'Edgeworth', + 'Hafford', + 'Legrande', + 'Netter', + 'Dulac', + 'Etherington', + 'Gaede', + 'Matranga', + 'Misch', + 'Gryder', + 'Kolman', + 'Reyer', + 'Landsman', + 'Huppert', + 'Steagall', + 'Heims', + 'Baldini', + 'Breithaupt', + 'Claypoole', + 'Feuer', + 'Heishman', + 'Pallotta', + 'Sponaugle', + 'Pershing', + 'Spaid', + 'Salt', + 'Giger', + 'Whetsel', + 'Balaban', + 'Baus', + 'Croke', + 'Heimer', + 'Milnes', + 'Onstott', + 'Wagman', + 'Magro', + 'Havlik', + 'Menge', + 'Talmage', + 'Aungst', + 'Dichiara', + 'Kuhr', + 'Milstein', + 'Sinatra', + 'Speiser', + 'Vise', + 'Panther', + 'Phair', + 'Commons', + 'Mincy', + 'Ashline', + 'Eagen', + 'Enns', + 'Epler', + 'Giltner', + 'Rexroat', + 'Schein', + 'Wellner', + 'Wickert', + 'Ardito', + 'Ihrig', + 'Schuerman', + 'Wentland', + 'Wohlford', + 'Stoy', + 'Kohan', + 'Ratley', + 'Hazell', + 'Coppin', + 'Blackshire', + 'Coolbaugh', + 'Essman', + 'Gandee', + 'Moccia', + 'Mullarkey', + 'Sugrue', + 'Woomer', + 'Arriaza', + 'Pipitone', + 'Heart', + 'Prothro', + 'Connaughton', + 'Covelli', + 'Lunger', + 'Mcilroy', + 'Morataya', + 'Swedberg', + 'Trembley', + 'Wiederhold', + 'Zappia', + 'Perret', + 'Glander', + 'Snedden', + 'Stonestreet', + 'Archey', + 'Arbour', + 'Cordaro', + 'Diskin', + 'Dumlao', + 'Fravel', + 'Spagnuolo', + 'Derossett', + 'Grigorian', + 'Mercadante', + 'Harcourt', + 'Norgaard', + 'Terhaar', + 'Touch', + 'Mccubbins', + 'Tadros', + 'Zabriskie', + 'Fontanilla', + 'Ruse', + 'Springsteen', + 'Getter', + 'Berrian', + 'Louissaint', + 'Cobbins', + 'Dorney', + 'Kugel', + 'Luth', + 'Poffenberger', + 'Sidoti', + 'Steinfeld', + 'Poley', + 'Dreger', + 'Ertl', + 'Capper', + 'Laswell', + 'Spragg', + 'Coltrane', + 'Winborne', + 'Langhorne', + 'Fambro', + 'Berkebile', + 'Bosserman', + 'Cygan', + 'Debonis', + 'Munsch', + 'Pflug', + 'Skowron', + 'Ediger', + 'Bosler', + 'Morden', + 'Virtue', + 'Orso', + 'Claire', + 'Damas', + 'Eichenlaub', + 'Gatchell', + 'Mikus', + 'Tjaden', + 'Tremper', + 'Tusing', + 'Longest', + 'Baires', + 'Dobos', + 'Deforge', + 'Kawa', + 'Hodder', + 'Thornell', + 'Mcgarrity', + 'Gotcher', + 'Judah', + 'Busey', + 'Perrier', + 'Hawthorn', + 'Captain', + 'Costlow', + 'Frohlich', + 'Gulla', + 'Hildebrant', + 'Hilgendorf', + 'Ramachandran', + 'Reaume', + 'Vollrath', + 'Lambertson', + 'Wyer', + 'Coit', + 'Dietsch', + 'Struve', + 'Vicario', + 'Ahlberg', + 'Warshaw', + 'Ryon', + 'Evatt', + 'Mobbs', + 'Gartin', + 'Kenley', + 'Marcell', + 'Bumpers', + 'Jans', + 'Karczewski', + 'Mazurkiewicz', + 'Nadolny', + 'Verrill', + 'Sitter', + 'Freyer', + 'Hindle', + 'Hergert', + 'Inda', + 'Magwood', + 'Basa', + 'Covello', + 'Pacini', + 'Ruoff', + 'Schenker', + 'Zwicker', + 'Popovic', + 'Augustyn', + 'Sutera', + 'Almy', + 'Keisler', + 'Vowels', + 'Lemond', + 'Abila', + 'Beardslee', + 'Benvenuto', + 'Deschaine', + 'Hodel', + 'Turbyfill', + 'Vejar', + 'Iddings', + 'Labrada', + 'Bowne', + 'Seel', + 'Stretch', + 'Haswell', + 'Rickerson', + 'Speas', + 'Southward', + 'Tony', + 'Burrier', + 'Casco', + 'Lorch', + 'Pietrowski', + 'Rabbitt', + 'Sefcik', + 'Trenary', + 'Trisler', + 'Zarazua', + 'Kube', + 'Riera', + 'Stmarie', + 'Starns', + 'Carmel', + 'Shire', + 'Britto', + 'Lacks', + 'Cifelli', + 'Dusenberry', + 'Lusher', + 'Mattioli', + 'Quiring', + 'Regner', + 'Shetty', + 'Stober', + 'Winemiller', + 'Zinke', + 'Heffington', + 'Santelli', + 'Figeroa', + 'Dishon', + 'Doble', + 'Canino', + 'Tahir', + 'Stamant', + 'Sharpton', + 'Sancho', + 'Linzy', + 'Ba', + 'Bonebrake', + 'Frenkel', + 'Irion', + 'Marines', + 'Lacava', + 'Drennon', + 'Fallen', + 'Whiten', + 'Bielawski', + 'Brasch', + 'Eichorn', + 'Gattuso', + 'Neis', + 'Tkach', + 'Usrey', + 'Walkowiak', + 'Dorame', + 'Orem', + 'Crombie', + 'Lowes', + 'Truscott', + 'Marlette', + 'Bushell', + 'Gosa', + 'Hillary', + 'Byfield', + 'Engdahl', + 'Ganser', + 'Hollars', + 'Lambros', + 'Matzen', + 'Moldovan', + 'Najarian', + 'Schoff', + 'Soo', + 'Spargo', + 'Wierenga', + 'Maysonet', + 'Dewan', + 'Bardo', + 'Figgs', + 'Bostian', + 'Graser', + 'Pecor', + 'Rodrigo', + 'Spilker', + 'Suen', + 'Nafziger', + 'Khouri', + 'Milling', + 'Benke', + 'Chapdelaine', + 'Darwish', + 'Merrigan', + 'Narayanan', + 'Neuner', + 'Wallman', + 'Caracciolo', + 'Uren', + 'Borge', + 'Garside', + 'Veasley', + 'Arquette', + 'Gastineau', + 'Helbling', + 'Maggiore', + 'Prell', + 'Vangelder', + 'Giaquinto', + 'Macha', + 'Jonsson', + 'Febus', + 'Lady', + 'Hughson', + 'Wickliffe', + 'Archila', + 'Bearce', + 'Harstad', + 'Krein', + 'Kulesza', + 'Levitan', + 'Nakasone', + 'Saraceno', + 'Stankus', + 'Shelden', + 'Hopping', + 'Diab', + 'Agar', + 'Mcpike', + 'Betterton', + 'Buzbee', + 'Dieguez', + 'Lins', + 'Phuong', + 'Pinegar', + 'Postel', + 'Beatrice', + 'Biddy', + 'Over', + 'Riding', + 'Rials', + 'Rance', + 'Simington', + 'Degraffenreid', + 'Sherard', + 'Clum', + 'Harkin', + 'Mallen', + 'Messerschmidt', + 'Patz', + 'Shatzer', + 'Stetz', + 'Beckert', + 'Worm', + 'Belmontes', + 'Narron', + 'Lyne', + 'Mckendrick', + 'Rester', + 'Archbold', + 'Whorley', + 'Monts', + 'Crapo', + 'Gribbin', + 'Lamborn', + 'Leverenz', + 'Mccarville', + 'Nishida', + 'Ryberg', + 'Smeal', + 'Piontek', + 'Routhier', + 'Willmon', + 'Proffit', + 'Sharrock', + 'Gasque', + 'Minott', + 'Corpening', + 'Capizzi', + 'Dubuc', + 'Gurevich', + 'Hohenstein', + 'Kotch', + 'Peper', + 'Rehbein', + 'Stortz', + 'Corvin', + 'Savant', + 'Ryle', + 'Madere', + 'Firmin', + 'Bitterman', + 'Bruso', + 'Guzzi', + 'Hefty', + 'Almada', + 'Mcninch', + 'Mangin', + 'On', + 'Hardage', + 'Garson', + 'Hisle', + 'Dease', + 'Critelli', + 'Digennaro', + 'Ehle', + 'Freestone', + 'Grieb', + 'Haubert', + 'Kelsay', + 'Loughman', + 'Neth', + 'Pen', + 'Ranta', + 'Sater', + 'Tomei', + 'Castiglia', + 'Kosek', + 'Zentner', + 'Nowland', + 'Klinedinst', + 'Karls', + 'Charon', + 'Cart', + 'Umphrey', + 'Laramore', + 'Mckenny', + 'Hamler', + 'Stoudemire', + 'Diercks', + 'Hodzic', + 'Huntzinger', + 'Runde', + 'Scavone', + 'Halbach', + 'Banales', + 'Thiry', + 'Waterfield', + 'Bebee', + 'Dass', + 'Caughman', + 'Admire', + 'Attebery', + 'Faubion', + 'Friess', + 'Goldsworthy', + 'Raburn', + 'Vantine', + 'Newswanger', + 'Manhart', + 'Grecco', + 'Meany', + 'Rumpf', + 'Dunlevy', + 'Franceschi', + 'Romanski', + 'Alwine', + 'Cahall', + 'Czaja', + 'Krawiec', + 'Mikolajczyk', + 'Neyman', + 'Perrotti', + 'Weideman', + 'Coppa', + 'Ingerson', + 'Avena', + 'Crunk', + 'Cadenhead', + 'Gittings', + 'Gloss', + 'Trowell', + 'Denard', + 'Funchess', + 'Kinnamon', + 'Mailhot', + 'Mollohan', + 'Polacek', + 'Pozos', + 'Rempe', + 'Schutter', + 'Shimkus', + 'Bedrosian', + 'Beede', + 'Conry', + 'Legan', + 'Pickford', + 'Chamblin', + 'Depinto', + 'Geibel', + 'Gilpatrick', + 'Hashmi', + 'Hermsen', + 'Petruzzi', + 'Robben', + 'Sorkin', + 'Gambardella', + 'Podgorski', + 'Langenfeld', + 'Yanke', + 'Zipperer', + 'Tillson', + 'Ariola', + 'Kelman', + 'Hert', + 'Fearn', + 'Goods', + 'Cervenka', + 'Kreft', + 'Kreidler', + 'Kuhar', + 'Leffew', + 'Maziarz', + 'Vollmar', + 'Zmuda', + 'Eisenhower', + 'Yelle', + 'Bhagat', + 'Kirst', + 'Gilkerson', + 'Kindel', + 'Argyle', + 'Bedingfield', + 'Manney', + 'Guion', + 'Rencher', + 'Plater', + 'Beitzel', + 'Camero', + 'Delaluz', + 'Fennelly', + 'Keenum', + 'Kingrey', + 'Mckillop', + 'Munyon', + 'Rorick', + 'Schrimsher', + 'Sohl', + 'Torbett', + 'Lynde', + 'Reiland', + 'Shepley', + 'Cudney', + 'Cather', + 'Abed', + 'Holen', + 'Jobson', + 'Husbands', + 'Marc', + 'Blatz', + 'Feucht', + 'Gunkel', + 'Margolin', + 'Messerly', + 'Womer', + 'Teston', + 'Ditch', + 'Marta', + 'Osier', + 'Awan', + 'Marcella', + 'Silvester', + 'Baugus', + 'Wilcoxon', + 'Nowling', + 'Torain', + 'Badalamenti', + 'Bartosh', + 'Czajka', + 'Savedra', + 'Shaker', + 'Shambaugh', + 'Stapley', + 'Goeke', + 'Schepers', + 'Tyo', + 'Rhodus', + 'Arencibia', + 'Kara', + 'Aitchison', + 'Parlin', + 'Benny', + 'Shakespeare', + 'Altomare', + 'Axe', + 'Bednarczyk', + 'Feasel', + 'Heikkinen', + 'Heyl', + 'Konecny', + 'Montalbo', + 'Semones', + 'Zuercher', + 'Dorrance', + 'Gehrig', + 'Kretzer', + 'Puchalski', + 'Asche', + 'Astacio', + 'Steers', + 'Jeanes', + 'Bamberg', + 'Matthis', + 'Maultsby', + 'Bunkley', + 'Afonso', + 'Danielsen', + 'Freier', + 'Graeff', + 'Gutknecht', + 'Jansky', + 'Lindenberg', + 'Macphee', + 'Pequeno', + 'Petrocelli', + 'Petrowski', + 'Prete', + 'Igoe', + 'Demonte', + 'Khatib', + 'Agin', + 'Siddall', + 'Mcdill', + 'Higginbottom', + 'Gallow', + 'Inniss', + 'Ballman', + 'Bieniek', + 'Casino', + 'Garringer', + 'Griese', + 'Heritage', + 'Zeitz', + 'Montanaro', + 'Qi', + 'Belcastro', + 'Brautigam', + 'Wakeland', + 'Keasler', + 'Oglesbee', + 'Saye', + 'Steppe', + 'Cichocki', + 'Melgarejo', + 'Primavera', + 'Rippe', + 'Sieger', + 'Stutes', + 'Tustin', + 'Vanloon', + 'Konkol', + 'Altmann', + 'Anderegg', + 'Bun', + 'Mcduffee', + 'Deo', + 'Persad', + 'Kindell', + 'Antillon', + 'Ast', + 'Kumm', + 'Lauricella', + 'Minkler', + 'Pilch', + 'Porreca', + 'Shoopman', + 'Skeels', + 'Chanthavong', + 'Hounshell', + 'Pitner', + 'Space', + 'Blackley', + 'Groomes', + 'Bleeker', + 'Duddy', + 'Inlow', + 'Knabe', + 'Lehmkuhl', + 'Salais', + 'Statz', + 'Sundin', + 'Woolston', + 'Hojnacki', + 'Drolet', + 'Gallivan', + 'Viner', + 'Hafley', + 'Hollan', + 'Phillis', + 'Montrose', + 'Colclough', + 'Coaxum', + 'Basel', + 'Campoverde', + 'Cirelli', + 'Delmonico', + 'Goh', + 'Goyal', + 'Hungate', + 'Lufkin', + 'Passaro', + 'Penta', + 'Quispe', + 'Ovalles', + 'Bulkley', + 'Show', + 'Purington', + 'Sockwell', + 'Mccluney', + 'Asato', + 'Buchta', + 'Cassara', + 'Cesena', + 'Empey', + 'Fass', + 'Gazda', + 'Giannetti', + 'Giuffre', + 'Jahns', + 'Jong', + 'Ruh', + 'Schmieder', + 'Sheerin', + 'Weinheimer', + 'Iwamoto', + 'Ouyang', + 'Uranga', + 'Ranalli', + 'Woolum', + 'Calabria', + 'Arrowsmith', + 'Cashen', + 'Vogan', + 'Giffen', + 'Sherk', + 'Denner', + 'Lanclos', + 'Whittlesey', + 'Dora', + 'Plain', + 'Bransford', + 'Bradwell', + 'Davitt', + 'Dehoff', + 'Lotito', + 'Roell', + 'Satterly', + 'Stahr', + 'Thiem', + 'Helberg', + 'Vause', + 'Willmore', + 'Seid', + 'Linebarger', + 'Geddis', + 'Bringhurst', + 'Damelio', + 'Fetterolf', + 'Galban', + 'Henkle', + 'Kamen', + 'Kaneko', + 'Kissane', + 'Rua', + 'Tehrani', + 'Tingey', + 'Lizardi', + 'Strick', + 'Halper', + 'Striker', + 'Amason', + 'Lesueur', + 'Tatem', + 'Bulluck', + 'Hobdy', + 'Flythe', + 'Brookover', + 'Fishbein', + 'Hartless', + 'Snelgrove', + 'Weikert', + 'Wissman', + 'Bourbeau', + 'Colclasure', + 'Sampley', + 'Shubin', + 'Rhoda', + 'Mcclane', + 'Meals', + 'Peets', + 'Anding', + 'Clewis', + 'Gaymon', + 'Bierly', + 'Brockmeyer', + 'Burnworth', + 'Dierking', + 'Patzer', + 'Seipel', + 'Shieh', + 'Pazmino', + 'Bailie', + 'Ducey', + 'Sessler', + 'Hornaday', + 'Andry', + 'Mowatt', + 'Charlot', + 'Buchholtz', + 'Gaulke', + 'Gondek', + 'Grossmann', + 'Hammerschmidt', + 'Heinle', + 'Huckabay', + 'Neathery', + 'Vanzile', + 'Vossler', + 'Schillaci', + 'Lem', + 'Paff', + 'Oja', + 'Broker', + 'Marlett', + 'Innocent', + 'Adsit', + 'Begg', + 'Kocian', + 'Maddalena', + 'Melamed', + 'Mikos', + 'Pio', + 'Poth', + 'Richwine', + 'Ruda', + 'Sackman', + 'Querry', + 'Padro', + 'Sober', + 'Ayscue', + 'Puff', + 'Hunton', + 'Woltz', + 'Alsobrook', + 'Baskins', + 'Daggs', + 'Brands', + 'Buechel', + 'Gonda', + 'Haberkorn', + 'Hartel', + 'Hazeltine', + 'Lantrip', + 'Leoni', + 'Licona', + 'Stanke', + 'Zwart', + 'Aplin', + 'Leatham', + 'Ace', + 'Ganter', + 'Bartolomeo', + 'Colgrove', + 'Halling', + 'Hesler', + 'Hainline', + 'Susi', + 'Kroner', + 'Sanden', + 'Rylander', + 'Basaldua', + 'Fujiwara', + 'Hengst', + 'Kapur', + 'Kienzle', + 'Miao', + 'Mutschler', + 'Orsi', + 'Pais', + 'Termini', + 'Yamane', + 'Zipp', + 'Wildey', + 'Bauerle', + 'Rehn', + 'Hipsher', + 'Staubin', + 'Esquilin', + 'Goley', + 'Buenaventura', + 'Frutos', + 'Gaugler', + 'Maclellan', + 'Mehring', + 'Stiers', + 'Gearheart', + 'Bong', + 'Maddocks', + 'Canary', + 'Urie', + 'Skillings', + 'Amir', + 'Bogus', + 'Oakman', + 'Barresi', + 'Cappelli', + 'Clausing', + 'Genest', + 'Grella', + 'Mulherin', + 'Roettger', + 'Corle', + 'Mantel', + 'Mody', + 'Delapp', + 'Dunnington', + 'Harvard', + 'Berquist', + 'Foglia', + 'Gilbride', + 'Krenek', + 'Gagnier', + 'Berney', + 'Bazzell', + 'Selvage', + 'Gullette', + 'Lavan', + 'Gunderman', + 'Holaday', + 'Horine', + 'Salata', + 'Slaybaugh', + 'Tobia', + 'Knick', + 'Tinkle', + 'Calcaterra', + 'Fauth', + 'Helmke', + 'Margiotta', + 'Mejorado', + 'Salomone', + 'Sevy', + 'Suri', + 'Vasconcellos', + 'Vetrano', + 'Flaten', + 'Sweetser', + 'Logston', + 'Varon', + 'Allsop', + 'Mickler', + 'Swails', + 'Conejo', + 'Derosia', + 'Hamre', + 'Hanvey', + 'Holscher', + 'Interiano', + 'Kleinberg', + 'Kravetz', + 'Reinking', + 'Schow', + 'Schur', + 'Vanbrocklin', + 'Yinger', + 'Zelenka', + 'Chagoya', + 'Sieben', + 'Devora', + 'Archambeau', + 'Burpee', + 'Shamp', + 'Stander', + 'Weaks', + 'Viney', + 'Halloway', + 'Artiga', + 'Clinkenbeard', + 'Kenison', + 'Loeza', + 'Schaap', + 'Simoni', + 'Frock', + 'Galea', + 'Graven', + 'Brookhart', + 'Gurr', + 'Mackintosh', + 'Arjona', + 'Busche', + 'Salvi', + 'Bedenbaugh', + 'Duan', + 'Clara', + 'Brundidge', + 'Akhter', + 'Amsler', + 'Bolz', + 'Bonura', + 'Brumbelow', + 'Droste', + 'Lohmeyer', + 'Lorah', + 'Louthan', + 'Botti', + 'Feigenbaum', + 'Thon', + 'Osbourn', + 'Peugh', + 'Viau', + 'Elsayed', + 'Hilyard', + 'Coram', + 'Alvin', + 'Milbourne', + 'Hickmon', + 'Basu', + 'Fasnacht', + 'Heathcock', + 'Matsui', + 'Oyama', + 'Stransky', + 'Blakesley', + 'Antes', + 'Flury', + 'Lacrosse', + 'Lull', + 'Clelland', + 'Rugh', + 'Hamelin', + 'Reta', + 'Barnet', + 'Ballow', + 'Pyburn', + 'Slayden', + 'Freshwater', + 'Fomby', + 'Bourquin', + 'Bowersock', + 'Calleros', + 'Dallmann', + 'Gootee', + 'Koelling', + 'Parfitt', + 'Pruss', + 'Tretter', + 'Bellini', + 'Gulden', + 'Pett', + 'Mcglasson', + 'Yerby', + 'Buth', + 'Curnow', + 'Goller', + 'Halderman', + 'Kulig', + 'Laue', + 'Roesner', + 'Samra', + 'Sorrow', + 'Vanbibber', + 'Mellin', + 'Villacis', + 'Hilborn', + 'Ditty', + 'Vasey', + 'Crall', + 'Sera', + 'Honeywell', + 'Blanchet', + 'Halim', + 'Nevius', + 'Ines', + 'Stuard', + 'Birr', + 'Curnutt', + 'Deibler', + 'Jaster', + 'Ouk', + 'Poppell', + 'Provence', + 'Rebman', + 'Schmick', + 'Terra', + 'Zea', + 'Hoven', + 'Loth', + 'Arreaga', + 'Cambre', + 'Roots', + 'Gains', + 'Jeancharles', + 'Cerritos', + 'Ihle', + 'Zambito', + 'Brueggemann', + 'Kluth', + 'Schwartzkopf', + 'Shott', + 'Mcglaughlin', + 'Decoster', + 'Northam', + 'Esau', + 'Fling', + 'Castile', + 'Milledge', + 'Desjarlais', + 'Laframboise', + 'Remigio', + 'Rudloff', + 'Utecht', + 'Enrique', + 'Wygant', + 'Fairbank', + 'Behl', + 'Meuse', + 'Pyke', + 'Fury', + 'Chowning', + 'Hyndman', + 'Donat', + 'Nuckles', + 'Cartledge', + 'Bilal', + 'Antonacci', + 'Huether', + 'Kha', + 'Mascia', + 'Rothberg', + 'Sieck', + 'Younes', + 'Sassaman', + 'Amparan', + 'Benesh', + 'Faraci', + 'Gaber', + 'Lehew', + 'Belzer', + 'Segoviano', + 'Teagle', + 'Burian', + 'Menne', + 'Niemeier', + 'Old', + 'Olenick', + 'Takemoto', + 'Tepe', + 'Test', + 'Zahler', + 'Matsuoka', + 'Hopf', + 'Misenheimer', + 'Mings', + 'Hullett', + 'Beutel', + 'Criscuolo', + 'Fedak', + 'Holtkamp', + 'Kretschmer', + 'Mongillo', + 'Mulrooney', + 'Panganiban', + 'Pollick', + 'Sgroi', + 'Shirkey', + 'Stodola', + 'Tozier', + 'Weidler', + 'Puskar', + 'Fiorello', + 'Stille', + 'Pomales', + 'Gladding', + 'Griffie', + 'Warmack', + 'Uzzell', + 'Stennis', + 'Buttrey', + 'Ekberg', + 'Harmsen', + 'Lieske', + 'Madriz', + 'Mohs', + 'Reininger', + 'Edgin', + 'Galla', + 'Chattin', + 'Frayer', + 'Brents', + 'Lasker', + 'Angelone', + 'Boulter', + 'Burritt', + 'Choudhry', + 'Claffey', + 'Elizarraras', + 'Gaumer', + 'Gawronski', + 'Henwood', + 'Lapine', + 'Bitar', + 'Himel', + 'Almand', + 'Brase', + 'Lala', + 'Salama', + 'Essick', + 'Longman', + 'Mone', + 'Reynard', + 'Brackney', + 'Cottam', + 'Donadio', + 'Geesey', + 'Laudenslager', + 'Mcgilvray', + 'Yano', + 'Bueche', + 'Irey', + 'Carneal', + 'Tinder', + 'Walke', + 'Baston', + 'Segar', + 'Brisbane', + 'Venson', + 'Arguijo', + 'Beitler', + 'Burek', + 'Burgener', + 'Collyer', + 'Donlin', + 'Duhaime', + 'Dworak', + 'Frech', + 'Kozik', + 'Montejo', + 'Nhan', + 'Quirarte', + 'Tram', + 'Deshpande', + 'Silverthorn', + 'Leard', + 'Sheller', + 'Alphin', + 'Boxer', + 'Shawn', + 'Pinnick', + 'Stigler', + 'Arpin', + 'Falkenberg', + 'Gerig', + 'Lemonds', + 'Salm', + 'Sarkis', + 'Paprocki', + 'Probasco', + 'Haithcock', + 'Carn', + 'Farrish', + 'Haliburton', + 'Copen', + 'Pieri', + 'Slaymaker', + 'Cardarelli', + 'Veneziano', + 'Melfi', + 'Solley', + 'Hymer', + 'Pleitez', + 'Hinsley', + 'Bruen', + 'Arita', + 'Dreisbach', + 'Fichtner', + 'Keckler', + 'Slaby', + 'Tanguma', + 'Wiberg', + 'Ferrucci', + 'Lick', + 'Maginnis', + 'Quaranta', + 'Bera', + 'Maybee', + 'Hennessee', + 'Kerrick', + 'Kabir', + 'Branscome', + 'Fullington', + 'Menser', + 'Brooking', + 'Patridge', + 'Gue', + 'Gowens', + 'Redus', + 'Ector', + 'Distasio', + 'Kissner', + 'Prada', + 'Sponsler', + 'Tempel', + 'Wedemeyer', + 'Degler', + 'Bodenhamer', + 'Sherbert', + 'Jefferis', + 'Belgarde', + 'Bevel', + 'Figaro', + 'Bertino', + 'Fabbri', + 'Kovacevic', + 'Kunst', + 'Leja', + 'Ruffo', + 'Stearman', + 'Trickett', + 'Zafar', + 'Valdivieso', + 'Curbelo', + 'Mabee', + 'Emma', + 'Arman', + 'Swasey', + 'Lyday', + 'Muff', + 'Rideaux', + 'Ahlgren', + 'Cobo', + 'Hanratty', + 'Litwiller', + 'Mallonee', + 'Glunt', + 'Moudy', + 'Hickam', + 'Mahmud', + 'Fate', + 'Hemsley', + 'Biery', + 'Buechner', + 'Fragale', + 'Hornbaker', + 'Lacorte', + 'Mateos', + 'Mickley', + 'Reusch', + 'Sabado', + 'Schnurr', + 'Gasior', + 'Konkle', + 'Okazaki', + 'Doubleday', + 'Couvillion', + 'Lupien', + 'Oder', + 'Ohair', + 'Win', + 'Quaintance', + 'Diltz', + 'Poythress', + 'Percell', + 'Weatherall', + 'Ainslie', + 'Brandner', + 'Byrge', + 'Cawood', + 'Heatwole', + 'Kerschner', + 'Looker', + 'Racz', + 'Skirvin', + 'Steitz', + 'Svenson', + 'Vermette', + 'Zupancic', + 'Monnier', + 'Scafidi', + 'Trousdale', + 'Bares', + 'Costantini', + 'Frees', + 'Kallio', + 'Methvin', + 'Prudencio', + 'Hayse', + 'Mahabir', + 'Wafford', + 'Borgmann', + 'Cogley', + 'Gigante', + 'Kurkowski', + 'Lavoy', + 'Wertheimer', + 'Wienke', + 'Goodling', + 'Danek', + 'Brinley', + 'Charlson', + 'Whitsell', + 'Lowen', + 'Minnix', + 'Lowers', + 'Palin', + 'Burgher', + 'Lorick', + 'Sobers', + 'Gavigan', + 'Italiano', + 'Liebl', + 'Prevette', + 'Wehunt', + 'Radin', + 'Guillotte', + 'Mode', + 'Halfacre', + 'Stjames', + 'Isabelle', + 'Meggs', + 'Burkard', + 'Giannotti', + 'Justo', + 'Kasprzyk', + 'Kuba', + 'Mino', + 'Morganti', + 'Schnelle', + 'Serfass', + 'Yacoub', + 'Thode', + 'Wykoff', + 'Macbeth', + 'Oxner', + 'Mayhue', + 'Saulter', + 'Budnik', + 'Gandarilla', + 'Michalec', + 'Eisel', + 'Newmark', + 'Placido', + 'Bellar', + 'Dollarhide', + 'Huett', + 'Copher', + 'Lacaze', + 'Dominic', + 'Bibler', + 'Boydstun', + 'Faas', + 'Grana', + 'Guardino', + 'Illig', + 'Luebbert', + 'Lyford', + 'Mcgettigan', + 'Repko', + 'Widmann', + 'Trevathan', + 'Ewan', + 'Mcray', + 'Footman', + 'Kerchner', + 'Leggio', + 'Bullinger', + 'Rushford', + 'Edel', + 'Leandro', + 'Burkman', + 'Grattan', + 'Tench', + 'Dartez', + 'Lemar', + 'Fane', + 'Zenon', + 'Sabb', + 'Blatchford', + 'Chilcoat', + 'Hahne', + 'Hanssen', + 'Mawhinney', + 'Pflueger', + 'Pol', + 'Vitelli', + 'Brierley', + 'Zundel', + 'Mcgillicuddy', + 'Adriano', + 'Mate', + 'Wilkison', + 'Ramnarine', + 'Peaks', + 'Bacote', + 'Barretto', + 'Benevento', + 'Gubler', + 'Koelsch', + 'Naas', + 'Patane', + 'Schnitzler', + 'Sprenkle', + 'Ulbrich', + 'Violante', + 'Rench', + 'Najarro', + 'Kristensen', + 'Poma', + 'Sara', + 'Jerrell', + 'Sarratt', + 'Mondy', + 'Antill', + 'Belleville', + 'Dworkin', + 'Holdaway', + 'Lenderman', + 'Murga', + 'Reiling', + 'Stasko', + 'Topel', + 'Verity', + 'Vinas', + 'Ziebarth', + 'Vanguilder', + 'Stoots', + 'Yantis', + 'Faries', + 'Tulley', + 'Baucum', + 'Fugett', + 'Harring', + 'Semien', + 'Dauphinais', + 'Furukawa', + 'Grilli', + 'Ohanian', + 'Ormiston', + 'Osegueda', + 'Wiegert', + 'Zier', + 'Chiesa', + 'Radecki', + 'Mongeon', + 'Stake', + 'Sweetland', + 'Shearon', + 'Lamore', + 'Mccuiston', + 'Minson', + 'Burditt', + 'Mcferren', + 'Covin', + 'Straker', + 'Elzy', + 'Althaus', + 'Anzures', + 'Glaeser', + 'Huseby', + 'Nitta', + 'Ribaudo', + 'Sobota', + 'Spieker', + 'Stefaniak', + 'Valois', + 'Vanwie', + 'Venturini', + 'Beltre', + 'Ewer', + 'Hartt', + 'Keaney', + 'Throne', + 'Edrington', + 'Inmon', + 'Isabel', + 'Brayman', + 'Devilbiss', + 'Krasner', + 'Malak', + 'Tito', + 'Vermeer', + 'Benigno', + 'Bosque', + 'Berridge', + 'Clines', + 'Brite', + 'Mcbeath', + 'Gleaves', + 'Koenen', + 'Kubicki', + 'Kudla', + 'Seiple', + 'Warkentin', + 'Choiniere', + 'Nassif', + 'Banko', + 'Muncie', + 'Garling', + 'Causby', + 'Mcgaw', + 'Burkeen', + 'Balan', + 'Georgia', + 'Hick', + 'Tumblin', + 'Badon', + 'Warrior', + 'Yearby', + 'Hiestand', + 'Hughart', + 'Proffer', + 'Sult', + 'Yepes', + 'Zachman', + 'Beddow', + 'Molyneux', + 'Camejo', + 'Stephany', + 'Cadogan', + 'Gosha', + 'Goodwine', + 'Harewood', + 'Burnsed', + 'Frappier', + 'Minardi', + 'Rieser', + 'Tabbert', + 'Marietta', + 'Butch', + 'Steil', + 'Canal', + 'Brundige', + 'Comas', + 'Hopkinson', + 'Shomo', + 'Kendle', + 'Bowsher', + 'Illingworth', + 'Kampa', + 'Manasco', + 'Mcdorman', + 'Theurer', + 'Widger', + 'Carbonneau', + 'Stachura', + 'Eriksson', + 'Trostle', + 'Foxworthy', + 'Lex', + 'Belman', + 'Isola', + 'Mckane', + 'Gearing', + 'Rimes', + 'Couillard', + 'Emanuele', + 'Pho', + 'Scimeca', + 'Skaar', + 'Vibbert', + 'Bilby', + 'Hink', + 'Gohn', + 'Nguy', + 'Perrett', + 'Bowland', + 'Comes', + 'Moffet', + 'Pauline', + 'Donalson', + 'Tilman', + 'Hansberry', + 'Acedo', + 'Camarda', + 'Devivo', + 'Eurich', + 'Jojola', + 'Railsback', + 'Rumfelt', + 'Stastny', + 'Strittmatter', + 'Houseknecht', + 'Rynearson', + 'Weinrich', + 'Kinghorn', + 'Astin', + 'Aguillard', + 'Hameed', + 'Drone', + 'Lonon', + 'Burgio', + 'Klimas', + 'Riegler', + 'Schiano', + 'Slonaker', + 'Deery', + 'Weissinger', + 'Cea', + 'Grenz', + 'Arent', + 'Sopher', + 'Jarratt', + 'Mitchener', + 'Conigliaro', + 'Dohm', + 'Feenstra', + 'Meiers', + 'Hetland', + 'Kinsinger', + 'Kmiec', + 'Teich', + 'Fukushima', + 'Kerins', + 'Cienfuegos', + 'Orlandi', + 'Bonser', + 'Okun', + 'Coate', + 'Rittenberry', + 'Mcclaine', + 'Dunklin', + 'Citizen', + 'Danzy', + 'Geers', + 'Georgeson', + 'Kikuchi', + 'Macinnis', + 'Malizia', + 'Mukai', + 'Plants', + 'Ehmann', + 'Haren', + 'Lachney', + 'Duchesne', + 'Collinson', + 'Connett', + 'Hostler', + 'Farnell', + 'Osler', + 'Triche', + 'Ballweg', + 'Bansal', + 'Galo', + 'Hollabaugh', + 'Hultquist', + 'Mcbrien', + 'Pelz', + 'Picciano', + 'Tashjian', + 'Thresher', + 'Uphoff', + 'Shawley', + 'Tomasek', + 'Aldaz', + 'Harig', + 'Kullman', + 'Vaness', + 'Isabella', + 'Munley', + 'Bissette', + 'Thackston', + 'Borgia', + 'Camire', + 'Charters', + 'Feiler', + 'Geisinger', + 'Racca', + 'Rasmusson', + 'Stonesifer', + 'Vidmar', + 'Arciga', + 'Bialek', + 'Baruch', + 'Kornfeld', + 'Harmeyer', + 'Picon', + 'Suppa', + 'Strate', + 'Hyre', + 'Verdon', + 'Reily', + 'Castell', + 'Foard', + 'Exner', + 'Furnari', + 'Guereca', + 'Hallgren', + 'Holsclaw', + 'Ketelsen', + 'Magnani', + 'Mehling', + 'Naser', + 'Seder', + 'Sparr', + 'Strnad', + 'Tatar', + 'Crecelius', + 'Knicely', + 'Vantassell', + 'Balsley', + 'Babbs', + 'Gowans', + 'Mcclam', + 'Batdorf', + 'Belsky', + 'Gull', + 'Letizia', + 'Ludlum', + 'Mascari', + 'Scheffel', + 'Spurgin', + 'Dignan', + 'Steffensen', + 'Freeberg', + 'Honan', + 'Hamric', + 'Woolman', + 'Valeri', + 'Saab', + 'Boyers', + 'Pardon', + 'Deasy', + 'Forshey', + 'Juntunen', + 'Kamel', + 'Macisaac', + 'Marinaro', + 'Milroy', + 'Parillo', + 'Rappold', + 'Schippers', + 'Smola', + 'Staniszewski', + 'Strasburg', + 'Epple', + 'Dewitte', + 'Hubley', + 'Queener', + 'Stoddart', + 'Briant', + 'Mcclurkin', + 'Binkowski', + 'Eberts', + 'Kilbane', + 'Kiraly', + 'Monsalve', + 'Othman', + 'Pasek', + 'Rinke', + 'Steinbrecher', + 'Trees', + 'Winther', + 'Boal', + 'Eber', + 'Funez', + 'Harryman', + 'Boyter', + 'Rill', + 'Jolliffe', + 'Dorian', + 'Demore', + 'Sebree', + 'Jeff', + 'Jolivette', + 'Elko', + 'Jividen', + 'Lenzen', + 'Marsee', + 'Milbrandt', + 'Orihuela', + 'Osterhoudt', + 'Parras', + 'Schnepp', + 'Tenaglia', + 'Thoren', + 'Diosdado', + 'Pingree', + 'Rutigliano', + 'Filbert', + 'Babel', + 'Stollings', + 'Hopes', + 'Bynes', + 'Brockmann', + 'Carta', + 'Deleeuw', + 'Demo', + 'Margeson', + 'Mckitrick', + 'Reyez', + 'Sidor', + 'Strehlow', + 'Timlin', + 'Wegrzyn', + 'Burgdorf', + 'Benzing', + 'Bonneville', + 'Clonts', + 'Camps', + 'Graydon', + 'Pasha', + 'Andreoli', + 'Cockerill', + 'Covino', + 'Hajjar', + 'Korpi', + 'Pohlmann', + 'Wente', + 'Wickwire', + 'Schaber', + 'Vonderhaar', + 'Manser', + 'Fitton', + 'Galindez', + 'Ares', + 'Longmore', + 'Buchert', + 'Delisi', + 'Gaulin', + 'Genco', + 'Helgerson', + 'Khawaja', + 'Radosevich', + 'Sannicolas', + 'Sterk', + 'Theberge', + 'Voiles', + 'Warchol', + 'Potthoff', + 'Runkel', + 'Stachowski', + 'Snay', + 'Share', + 'Conkey', + 'Pontes', + 'Mathies', + 'Brittian', + 'Allgeier', + 'Daughenbaugh', + 'Glock', + 'Meisinger', + 'Pantaleo', + 'Saitta', + 'Weick', + 'Burak', + 'Borda', + 'Rim', + 'Bunyard', + 'Neaves', + 'Mcilvaine', + 'Zee', + 'Buskey', + 'Roseborough', + 'Bellin', + 'Fasulo', + 'Grab', + 'Jia', + 'Knab', + 'Skalski', + 'Stensland', + 'Zajicek', + 'Echeverry', + 'Kolenda', + 'Cadden', + 'Delawder', + 'Propp', + 'Scheeler', + 'Clukey', + 'Loven', + 'Bogen', + 'Whittingham', + 'Barcelona', + 'Braasch', + 'Haubrich', + 'Kolberg', + 'Vendetti', + 'Sheesley', + 'Bartoli', + 'Knierim', + 'Amparo', + 'Lauth', + 'Rosero', + 'Burry', + 'Guynes', + 'Cumbo', + 'Pridgeon', + 'Aarons', + 'Alarid', + 'Arakawa', + 'Benzel', + 'Bywater', + 'Grosch', + 'Heth', + 'Logiudice', + 'Maisel', + 'Morquecho', + 'Wahlberg', + 'Teigen', + 'Bockelman', + 'Rehak', + 'Bitler', + 'Brion', + 'Niece', + 'Selvey', + 'Sudderth', + 'Ruddock', + 'Sandiford', + 'Aguas', + 'Folan', + 'Herwig', + 'Krupinski', + 'Mccarrick', + 'Mudgett', + 'Pancake', + 'Redner', + 'Wentzell', + 'Soliday', + 'Marschall', + 'Krakowski', + 'Rebholz', + 'Dold', + 'Giller', + 'Gassett', + 'Brazzell', + 'Bellow', + 'Tolen', + 'Gloster', + 'Gagliardo', + 'Harbuck', + 'Lorber', + 'Natarajan', + 'Sarna', + 'Schrack', + 'Vena', + 'Witzke', + 'Minassian', + 'Loi', + 'Rogue', + 'Trace', + 'Bomba', + 'Cozzens', + 'Evett', + 'Boze', + 'Petros', + 'Cotta', + 'Eisenmann', + 'Florea', + 'Hammersley', + 'Keohane', + 'Necessary', + 'Nodine', + 'Pekarek', + 'Sjogren', + 'Ruybal', + 'Arabie', + 'Huntsinger', + 'Eiseman', + 'Mehler', + 'Craner', + 'Vandine', + 'Gaffey', + 'Menna', + 'Royle', + 'Cordrey', + 'Gala', + 'Gauss', + 'Dacruz', + 'Cardell', + 'Devan', + 'Calmes', + 'Humber', + 'Stoute', + 'Balko', + 'Cera', + 'Griesbach', + 'Kissick', + 'Kloos', + 'Oertel', + 'Sedlock', + 'Stellato', + 'Tuite', + 'Bero', + 'Rinard', + 'Dambra', + 'Cinelli', + 'Tea', + 'Hicken', + 'Linch', + 'Dials', + 'Bennefield', + 'Hillsman', + 'Flemister', + 'Alvaro', + 'Goranson', + 'Henk', + 'Ryden', + 'Verhagen', + 'Wessling', + 'Willetts', + 'Neidlinger', + 'Pereida', + 'Lainhart', + 'Nemes', + 'Rudzinski', + 'Sward', + 'Rom', + 'Rosko', + 'Runions', + 'Henney', + 'Ridgely', + 'Tomson', + 'Arballo', + 'Bohorquez', + 'Brixey', + 'Durling', + 'Espina', + 'Esquivias', + 'Nungaray', + 'Ovando', + 'Zapf', + 'Pizza', + 'Arel', + 'Ballin', + 'Heathman', + 'Morison', + 'Troop', + 'Monfort', + 'Copland', + 'Harriott', + 'Mcwhite', + 'Amini', + 'Cirilo', + 'Gassner', + 'Gulbranson', + 'Kovatch', + 'Venne', + 'Terriquez', + 'Savin', + 'Amo', + 'Moris', + 'Crable', + 'Delaughter', + 'Greenhouse', + 'Eckardt', + 'Hendrixson', + 'Manansala', + 'Mongeau', + 'Panko', + 'Pichette', + 'Sliwa', + 'Tabak', + 'Determan', + 'Freeburg', + 'Portell', + 'Steller', + 'Buffkin', + 'Righter', + 'Mcguinn', + 'Corrie', + 'Tatham', + 'Smelley', + 'Terrel', + 'Selmon', + 'Blecha', + 'Eisler', + 'Engelking', + 'Goen', + 'Krey', + 'Mceldowney', + 'Plamondon', + 'Slovak', + 'Sorce', + 'Spagnolo', + 'Wambold', + 'Colborn', + 'Englander', + 'Monsour', + 'Pait', + 'Perricone', + 'Loveridge', + 'Cragg', + 'Dies', + 'Holsten', + 'Dagley', + 'Beverley', + 'Bayona', + 'Cam', + 'Chock', + 'Coppersmith', + 'Donath', + 'Guillemette', + 'Iannelli', + 'Potratz', + 'Selander', + 'Suk', + 'Waldvogel', + 'Olberding', + 'Giaimo', + 'Spoto', + 'Crocco', + 'Waskiewicz', + 'Krizan', + 'Vigo', + 'Boarman', + 'Ron', + 'Facer', + 'Garlow', + 'Filsaime', + 'Andersson', + 'Demski', + 'Derouin', + 'Diegel', + 'Feria', + 'Foth', + 'Hertzberg', + 'Jillson', + 'Kram', + 'Mammen', + 'Melhorn', + 'Monjaras', + 'Oslund', + 'Petrin', + 'Pinho', + 'Scheerer', + 'Shadden', + 'Sitzman', + 'Stumbaugh', + 'Wengert', + 'Gershon', + 'Mcelhinney', + 'Batterson', + 'Macqueen', + 'Janas', + 'Gladson', + 'Aull', + 'Wasinger', + 'Shemwell', + 'Seats', + 'Colas', + 'Allbee', + 'Fithian', + 'Fonner', + 'Gergen', + 'Lubrano', + 'Mannarino', + 'Piscopo', + 'Sydow', + 'Werle', + 'Aumiller', + 'Coplen', + 'Dardar', + 'Morrisette', + 'Mchaney', + 'Simes', + 'Gillison', + 'Emmel', + 'Klunk', + 'Luber', + 'Madeira', + 'Schlicht', + 'Tremain', + 'Cleaveland', + 'Boulet', + 'Golladay', + 'Enck', + 'Fera', + 'Hammar', + 'Hebner', + 'Ishee', + 'Nanni', + 'Palomar', + 'Pangborn', + 'Rogala', + 'Rushlow', + 'Wiedman', + 'Laber', + 'Schoenfelder', + 'Sonner', + 'Duffer', + 'Granier', + 'Sawin', + 'Dwiggins', + 'Jaso', + 'Popplewell', + 'Loren', + 'Ord', + 'Dearmon', + 'Hammen', + 'Misra', + 'Reindl', + 'Siordia', + 'Woodhead', + 'Yasuda', + 'Dockstader', + 'Kobs', + 'Tokarski', + 'Villers', + 'Mase', + 'Arrant', + 'Hedgpeth', + 'Eggleton', + 'Frederic', + 'Victorian', + 'Akerman', + 'Balazs', + 'Brandau', + 'Depietro', + 'Dillenbeck', + 'Goodnow', + 'Larner', + 'Mcmurtrie', + 'Salameh', + 'Swicegood', + 'Koshy', + 'Stdenis', + 'Deakin', + 'Izzi', + 'Teater', + 'Gramm', + 'Doig', + 'Blacklock', + 'Haymore', + 'Heggie', + 'Kirklin', + 'Kassa', + 'Ryles', + 'Tenner', + 'Ndiaye', + 'Burrola', + 'Faires', + 'Grega', + 'Krentz', + 'Needles', + 'Portz', + 'Ruedas', + 'Sitko', + 'Viernes', + 'Setter', + 'Tricarico', + 'Prest', + 'Olivar', + 'Whitsitt', + 'Labossiere', + 'Bellomo', + 'Burgeson', + 'Capriotti', + 'Drinnon', + 'Gulati', + 'Haffey', + 'Lasota', + 'Laughery', + 'Mees', + 'Melander', + 'Paoletti', + 'Petermann', + 'Zerby', + 'Burhans', + 'Lasseigne', + 'Vannote', + 'Wai', + 'Berson', + 'Gritton', + 'Searl', + 'Toller', + 'Brackeen', + 'Screws', + 'Hagens', + 'Billingslea', + 'Hyppolite', + 'Asmussen', + 'Bitton', + 'Diiorio', + 'Grigoryan', + 'Hauenstein', + 'Krukowski', + 'Mulcahey', + 'Perras', + 'Prak', + 'Reitzel', + 'Spackman', + 'Valenciano', + 'Wieck', + 'Yeagley', + 'Zanetti', + 'Goeller', + 'Azizi', + 'Grise', + 'Mogan', + 'Traverso', + 'Nangle', + 'Saladin', + 'Hardgrove', + 'Osei', + 'Fehrenbach', + 'Giesbrecht', + 'Halas', + 'Hetzler', + 'Orsak', + 'Salaz', + 'Surace', + 'Whipp', + 'Charlebois', + 'Stayer', + 'Stelmach', + 'Hitchings', + 'Senters', + 'Mcnaught', + 'Cordier', + 'Dawsey', + 'Barhorst', + 'Clauser', + 'Dibernardo', + 'Hawkey', + 'Hritz', + 'Patchin', + 'Raatz', + 'Seubert', + 'Slingerland', + 'Vanderwoude', + 'Aquilino', + 'Goertzen', + 'Navratil', + 'Mccuistion', + 'Vallin', + 'Moors', + 'Connely', + 'Fedrick', + 'Bontempo', + 'Dishong', + 'Felch', + 'Laino', + 'Minshall', + 'Montroy', + 'Plotts', + 'Radice', + 'Sachse', + 'Safran', + 'Schecter', + 'Traut', + 'Vasile', + 'Yadon', + 'Gorka', + 'Roelofs', + 'Suit', + 'Asbill', + 'Torrens', + 'Kimmey', + 'Ruger', + 'Vinzant', + 'Watkin', + 'Rawles', + 'Cubero', + 'Duch', + 'Endress', + 'Fangman', + 'Holben', + 'Holzapfel', + 'Karner', + 'Otteson', + 'Stangel', + 'Terrebonne', + 'Wagley', + 'Wisecup', + 'Bengston', + 'Leck', + 'Coalson', + 'Farooq', + 'Safi', + 'Smyers', + 'All', + 'Else', + 'Wason', + 'Nairn', + 'Panton', + 'Ahrendt', + 'Arvizo', + 'Klahn', + 'Robak', + 'Schier', + 'Start', + 'Tiano', + 'Kraatz', + 'Corzo', + 'Maranto', + 'Elm', + 'Eagles', + 'Acres', + 'Schoolfield', + 'Ancrum', + 'Ahner', + 'Augsburger', + 'Berna', + 'Danh', + 'Fruth', + 'Galluzzo', + 'Racette', + 'Selva', + 'Szekely', + 'Zirbel', + 'Hauff', + 'Markgraf', + 'Wonderly', + 'Rydell', + 'Julia', + 'Chris', + 'Simson', + 'Bridgeford', + 'Jeffress', + 'Brailsford', + 'Bluford', + 'Boser', + 'Fichera', + 'Meininger', + 'Meyerhoff', + 'Modzelewski', + 'Niese', + 'Pavlovich', + 'Radovich', + 'Ratz', + 'Frankowski', + 'Berti', + 'Geno', + 'Fares', + 'Marney', + 'Harwick', + 'Tata', + 'Bobby', + 'Dobbin', + 'Roosevelt', + 'Greenaway', + 'Janvier', + 'Oatis', + 'Beilke', + 'Brelsford', + 'Dowty', + 'Giudice', + 'Hetzer', + 'Imboden', + 'Irelan', + 'Nie', + 'Ramberg', + 'Rega', + 'Sproat', + 'Sytsma', + 'Unrein', + 'Davignon', + 'Ganoe', + 'Leinweber', + 'Mantell', + 'Troisi', + 'Sahr', + 'Esperanza', + 'Asper', + 'Lathem', + 'Eagleton', + 'Lamons', + 'Gaulden', + 'Bloodgood', + 'Cerone', + 'Claro', + 'Durfey', + 'Enamorado', + 'Herrada', + 'Maw', + 'Schlagel', + 'Signor', + 'Reisch', + 'Gruenwald', + 'Helbert', + 'Lorenzi', + 'Woodlief', + 'Huval', + 'Batman', + 'Meadow', + 'Croswell', + 'Bordonaro', + 'Earnshaw', + 'Freiburger', + 'Gunnoe', + 'Lamberton', + 'Martella', + 'Mischke', + 'Shelor', + 'Venuti', + 'Bilek', + 'Mcmains', + 'Balding', + 'Mestre', + 'Mcconnaughey', + 'Manso', + 'Decoste', + 'Egerton', + 'Alvino', + 'Arizpe', + 'Blaschke', + 'Foglesong', + 'Heyn', + 'Irigoyen', + 'Komorowski', + 'Lesinski', + 'Nghiem', + 'Rund', + 'Santiesteban', + 'Strahm', + 'Hendel', + 'Capes', + 'Carls', + 'Bon', + 'Sires', + 'Nichelson', + 'Brimm', + 'Aikins', + 'Berra', + 'Brazee', + 'Burkert', + 'Capalbo', + 'Criscione', + 'Feddersen', + 'Hofbauer', + 'Jacobowitz', + 'Mackowiak', + 'Mcenroe', + 'Philbeck', + 'Shimada', + 'Ticknor', + 'Wozny', + 'Biernacki', + 'Hirschi', + 'Polich', + 'Sokoloski', + 'Dolores', + 'Knoch', + 'Ge', + 'Groome', + 'Markell', + 'Fearing', + 'Mcclaren', + 'Hadsell', + 'Rumple', + 'Samudio', + 'Scardina', + 'Spinosa', + 'Abramov', + 'Siracusa', + 'Goren', + 'Rocchio', + 'Bibi', + 'Lamer', + 'Liddy', + 'Anna', + 'Coxe', + 'De', + 'Rodes', + 'Cheshier', + 'Coulon', + 'Closs', + 'Tigue', + 'Seville', + 'Hopkin', + 'Rodwell', + 'Bibbins', + 'Baldree', + 'Bawden', + 'Bishoff', + 'Costabile', + 'Dec', + 'Hillegass', + 'Infantino', + 'Mantia', + 'Mcamis', + 'Northcott', + 'Ruprecht', + 'Sanpedro', + 'Campione', + 'Muchow', + 'Ostby', + 'Mohl', + 'Pulice', + 'Vigna', + 'Thomann', + 'Lillibridge', + 'Manville', + 'Vives', + 'Bellanger', + 'Desormeaux', + 'Lovingood', + 'Stjulien', + 'Echeverri', + 'Florey', + 'Gieseke', + 'Maeder', + 'Marcinko', + 'Nuncio', + 'Quirino', + 'Versteeg', + 'Voelkel', + 'Wanless', + 'Morocho', + 'Monteagudo', + 'Aikin', + 'Bramley', + 'Bartleson', + 'Skeete', + 'Batra', + 'Dolloff', + 'Gehr', + 'Hellyer', + 'Hersch', + 'Hier', + 'Lannan', + 'Reffitt', + 'Carboni', + 'Schouten', + 'Burkle', + 'Riches', + 'Busa', + 'Rademaker', + 'Hult', + 'Synder', + 'Bossard', + 'Tunis', + 'Pamplin', + 'Oats', + 'Mcphaul', + 'Baik', + 'Kieser', + 'Pareja', + 'Raffaele', + 'Erhard', + 'Iwasaki', + 'Tonelli', + 'Mabey', + 'Debruyn', + 'Carrel', + 'Myron', + 'Arai', + 'Vallo', + 'Points', + 'Buteau', + 'Becknell', + 'Lue', + 'Antos', + 'Folkers', + 'Galletta', + 'Hissong', + 'Knoche', + 'Kundert', + 'Larussa', + 'Lobos', + 'Poitra', + 'Rinn', + 'Seamons', + 'Senko', + 'Villaverde', + 'Weatherholt', + 'Maliszewski', + 'Jurkowski', + 'Scism', + 'Hallas', + 'Collet', + 'Capello', + 'Lena', + 'Popper', + 'Aikman', + 'Blakes', + 'Cadigan', + 'Dupler', + 'Kazi', + 'Masri', + 'Matejka', + 'Mcgirr', + 'Pistone', + 'Prenger', + 'Ranes', + 'Thiemann', + 'Voeller', + 'Cockman', + 'Burtt', + 'Looby', + 'Bonnie', + 'Mcclenny', + 'Ridgell', + 'Nails', + 'Lesane', + 'Bertolino', + 'Doheny', + 'Fechter', + 'Holshouser', + 'Kierstead', + 'Krewson', + 'Lanahan', + 'Vig', + 'Wiswell', + 'Freytag', + 'Haselden', + 'Kuras', + 'Navar', + 'Raisor', + 'Finamore', + 'Kipper', + 'Morissette', + 'Laughton', + 'Awe', + 'Manier', + 'Cumby', + 'Cabada', + 'Hafen', + 'Kojima', + 'Massari', + 'Mctague', + 'Stehr', + 'Vandevelde', + 'Voong', + 'Wisely', + 'Girardin', + 'Bies', + 'Demaris', + 'Galles', + 'Goldstone', + 'Kai', + 'Cord', + 'Brigance', + 'Gomillion', + 'Drakes', + 'Bartkowiak', + 'Chica', + 'Draheim', + 'Honeyman', + 'Klapper', + 'Kniffen', + 'Knoblock', + 'Scherzer', + 'Tougas', + 'Toyama', + 'Urbach', + 'Walia', + 'Wattenbarger', + 'Marz', + 'Cesare', + 'Miro', + 'Kervin', + 'Godard', + 'Beiter', + 'Betcher', + 'Evarts', + 'Evensen', + 'Gaff', + 'Griffitts', + 'Grunden', + 'Hoffart', + 'Kroupa', + 'Maiers', + 'Mckendry', + 'Puett', + 'Shoe', + 'Stermer', + 'Wineinger', + 'Brocious', + 'Chudy', + 'Spofford', + 'Wessinger', + 'Weich', + 'Croff', + 'Ephraim', + 'Sallis', + 'Blasco', + 'Burningham', + 'Buschmann', + 'Forget', + 'Kulak', + 'Panozzo', + 'Pierpont', + 'Priolo', + 'Puhl', + 'Ruffolo', + 'Voisine', + 'Mancinelli', + 'Santacroce', + 'Vanvalkenburgh', + 'Veverka', + 'Desena', + 'Agner', + 'Boron', + 'Wheeling', + 'Plato', + 'Tonge', + 'Deibel', + 'Herriman', + 'Holroyd', + 'Huitron', + 'Hum', + 'Kreamer', + 'Lada', + 'Lucena', + 'Pao', + 'Planck', + 'Vanroekel', + 'Bodell', + 'Francia', + 'Anastasia', + 'Haxton', + 'Maile', + 'Warning', + 'Labeau', + 'Pujol', + 'Done', + 'Minney', + 'Hogsett', + 'Tayler', + 'Delancy', + 'Philson', + 'Allemand', + 'Buhrman', + 'Diefenbach', + 'Gawel', + 'Kovacic', + 'Kralik', + 'Lazor', + 'Mcnemar', + 'Warth', + 'Glanzer', + 'Keep', + 'Hochstein', + 'Febles', + 'Morneau', + 'Agostinelli', + 'Galeas', + 'Landen', + 'Lion', + 'Attwood', + 'Capshaw', + 'Willy', + 'Dekle', + 'Murrill', + 'Coby', + 'Falvo', + 'Kanagy', + 'Mihalko', + 'Schellenberg', + 'Sugimoto', + 'Lippard', + 'Sardo', + 'Suckow', + 'Demichele', + 'Kath', + 'Lappe', + 'Lego', + 'Schleifer', + 'Vold', + 'Kingsland', + 'Mitch', + 'Manlove', + 'Cuozzo', + 'Dauber', + 'Deininger', + 'Goldbach', + 'Halfmann', + 'Kazarian', + 'Marksberry', + 'Marzec', + 'Mcmurphy', + 'Oregan', + 'Paczkowski', + 'Pinsky', + 'Poynor', + 'Schertz', + 'Tetrick', + 'Umali', + 'Valenza', + 'Witherington', + 'Kesselring', + 'Nylund', + 'Cinnamon', + 'Rielly', + 'Surman', + 'Fowle', + 'Hains', + 'Sharlow', + 'Lones', + 'Durgan', + 'Savory', + 'Minger', + 'Okon', + 'Berends', + 'Binning', + 'Malina', + 'Loeser', + 'Marthaler', + 'Pacella', + 'Vasta', + 'Hinerman', + 'Goodchild', + 'Chuck', + 'Linney', + 'Beckworth', + 'Carrie', + 'Lovings', + 'Ginyard', + 'Bredeson', + 'Debiase', + 'Gorder', + 'Noce', + 'Redlin', + 'Schwinn', + 'Zins', + 'Burtner', + 'Kosakowski', + 'Erler', + 'Altom', + 'Husman', + 'Markos', + 'Thorman', + 'Fagen', + 'Voisin', + 'Gauldin', + 'Pressey', + 'Calbert', + 'Holness', + 'Alspach', + 'Broeker', + 'Danziger', + 'Klenke', + 'Popescu', + 'Schoenrock', + 'Schreckengost', + 'Syme', + 'Trick', + 'Plautz', + 'Beckel', + 'Dealmeida', + 'Winne', + 'Moron', + 'Seed', + 'Capozzoli', + 'Gawron', + 'Kobel', + 'Kouns', + 'Nunemaker', + 'Steinbacher', + 'Stookey', + 'Vidana', + 'Zoch', + 'Ohlinger', + 'Hudkins', + 'Ferren', + 'Gille', + 'Sheckler', + 'Kittell', + 'Roath', + 'Ziglar', + 'Brecher', + 'Coldren', + 'Degraaf', + 'Eddinger', + 'Joffe', + 'Luthy', + 'Metzinger', + 'Nayak', + 'Paule', + 'Prudente', + 'Wooddell', + 'Zuccaro', + 'Rineer', + 'Soos', + 'Manka', + 'Vandervoort', + 'Kitchell', + 'Casserly', + 'Watchman', + 'Poteete', + 'Dopson', + 'Mathurin', + 'Cataldi', + 'Crepeau', + 'Fackrell', + 'Goben', + 'Macinnes', + 'Scherf', + 'Shaddix', + 'Sorber', + 'Teichman', + 'Wydra', + 'Holzworth', + 'Baade', + 'Tinnell', + 'Tinkler', + 'Mauzy', + 'Alphonse', + 'Fullard', + 'Adger', + 'Akiyama', + 'Bloxham', + 'Coultas', + 'Esler', + 'Giebel', + 'Goswick', + 'Heikes', + 'Javed', + 'Linan', + 'Mooers', + 'Nemetz', + 'Pradhan', + 'Rainone', + 'Romito', + 'Treichel', + 'Vohs', + 'Grosskopf', + 'Weisinger', + 'Ruple', + 'Naff', + 'Meaders', + 'Lamarr', + 'Toppin', + 'Apicella', + 'Beecroft', + 'Boshears', + 'Breier', + 'Cuadros', + 'Umbarger', + 'Alioto', + 'Ravenscroft', + 'Vesper', + 'Oak', + 'Tigges', + 'Simmer', + 'Hanby', + 'Webre', + 'Lenk', + 'Mcelvain', + 'Boy', + 'Debarros', + 'Hickenbottom', + 'Quincy', + 'Billips', + 'Ollison', + 'Barbuto', + 'Clearwater', + 'Cronkhite', + 'Groleau', + 'Mehra', + 'Tessler', + 'Kegel', + 'Borenstein', + 'Newnam', + 'Crofton', + 'Phenix', + 'Dankert', + 'Hymas', + 'Lobel', + 'Marszalek', + 'Moceri', + 'Ottaviano', + 'Papazian', + 'Roedel', + 'Jochum', + 'Urquidez', + 'Lapin', + 'Garro', + 'Lamond', + 'Sessums', + 'Tooke', + 'Steadham', + 'Azam', + 'Bleier', + 'Buelna', + 'Bupp', + 'Burridge', + 'Derderian', + 'Derstine', + 'Halberg', + 'Katzer', + 'Meegan', + 'Ortmann', + 'Herschberger', + 'Sanroman', + 'Winiarski', + 'Alcon', + 'Picker', + 'Demille', + 'Huron', + 'Hankin', + 'Dahmen', + 'Fronczak', + 'Klingman', + 'Perugini', + 'Pettinato', + 'Powelson', + 'Saffer', + 'Schwenke', + 'Pals', + 'Estremera', + 'Sofia', + 'Arvelo', + 'Terrero', + 'Bankes', + 'Sais', + 'Netherland', + 'Odeh', + 'Sutphen', + 'Caddy', + 'Dorval', + 'Glaude', + 'Mcadory', + 'Eichinger', + 'Lesniewski', + 'Petito', + 'Pfohl', + 'Presler', + 'Rys', + 'Sano', + 'Willenborg', + 'Seppala', + 'Shibley', + 'Cajigas', + 'Gal', + 'Farag', + 'Pickles', + 'Rump', + 'Grills', + 'Mikes', + 'Adderley', + 'Altland', + 'Araki', + 'Beitz', + 'Brotzman', + 'Buonocore', + 'Fayard', + 'Gelber', + 'Jurewicz', + 'Lezcano', + 'Marsteller', + 'Minarik', + 'Opsahl', + 'Pranger', + 'Tiburcio', + 'Zollo', + 'Engh', + 'Henault', + 'Barrineau', + 'Pilkinton', + 'Pratte', + 'Niland', + 'Warda', + 'Southwood', + 'Clinch', + 'Halsell', + 'Mccaa', + 'Isreal', + 'Pinkett', + 'Asch', + 'Beauchesne', + 'Bruemmer', + 'Doebler', + 'Ehlinger', + 'Goelz', + 'Hashemi', + 'Karel', + 'Magiera', + 'Martorano', + 'Mooneyhan', + 'Cibrian', + 'Cavey', + 'Kosko', + 'Christo', + 'Cockrill', + 'Mansker', + 'Balls', + 'Degree', + 'Tiggs', + 'Alberico', + 'Clugston', + 'Elman', + 'Frueh', + 'Kampf', + 'Kochanski', + 'Leider', + 'Marsella', + 'Mckendree', + 'Moffa', + 'Quattrocchi', + 'Raval', + 'Snoke', + 'Akopyan', + 'Barrilleaux', + 'Cambria', + 'Kawaguchi', + 'Bonde', + 'Dawdy', + 'Willig', + 'Kazee', + 'Debow', + 'Beachum', + 'Vicks', + 'Aurelio', + 'Barocio', + 'Bonesteel', + 'Ezzo', + 'Gesell', + 'Krzeminski', + 'Madan', + 'Magda', + 'Manring', + 'Mcfaul', + 'Morera', + 'Purinton', + 'Retzer', + 'Schonfeld', + 'Staszak', + 'Stubbe', + 'Talerico', + 'Wikoff', + 'Zia', + 'Seyfried', + 'Diangelo', + 'Keach', + 'Shipton', + 'Shewmake', + 'Behrmann', + 'Hopps', + 'Paster', + 'Augenstein', + 'Castaldi', + 'Ferrufino', + 'Gregersen', + 'Hosseini', + 'Keniston', + 'Nadolski', + 'Ouimette', + 'Pellett', + 'Riebel', + 'Schwark', + 'Spelman', + 'Tesar', + 'Yahn', + 'Grossnickle', + 'Rosillo', + 'Dostie', + 'Noa', + 'Khalaf', + 'Cardosa', + 'Afzal', + 'Mercure', + 'Wheless', + 'Tailor', + 'Mcgarrah', + 'Miler', + 'Norfolk', + 'Crapps', + 'Dansereau', + 'Jenney', + 'Keast', + 'Lieser', + 'Mihm', + 'Porco', + 'Zelinsky', + 'Sleeth', + 'Mcelreath', + 'Hemann', + 'Capaldi', + 'Huggett', + 'Reagle', + 'Mayotte', + 'Liller', + 'Leen', + 'Demmer', + 'Tunison', + 'Woodbridge', + 'Haymes', + 'Cunning', + 'Blaze', + 'Eatman', + 'Ulysse', + 'Bagshaw', + 'Buczkowski', + 'Cardello', + 'Decola', + 'Diloreto', + 'Evola', + 'Glassburn', + 'Hazelbaker', + 'Holycross', + 'Minasian', + 'Regula', + 'Ruge', + 'Uhlman', + 'Lamprecht', + 'Shifflet', + 'Weikle', + 'Coupe', + 'Isherwood', + 'Dimon', + 'Pop', + 'Willhoite', + 'Bari', + 'Boise', + 'Doom', + 'Mccolley', + 'Bircher', + 'Wannamaker', + 'Eppes', + 'Pea', + 'Okeke', + 'Alpizar', + 'Arista', + 'Barbagallo', + 'Baumert', + 'Bhattacharya', + 'Gheen', + 'Hutchcraft', + 'Karlen', + 'Klier', + 'Ladnier', + 'Marrujo', + 'Reister', + 'Rorrer', + 'Tarpey', + 'Wisecarver', + 'Beydoun', + 'Fillinger', + 'Kemnitz', + 'Takata', + 'Leight', + 'Kross', + 'Junco', + 'Holmer', + 'Sando', + 'Biddix', + 'Dawood', + 'Frisco', + 'Flagler', + 'Arntz', + 'Bache', + 'Bundrick', + 'Glasson', + 'Los', + 'Scheiber', + 'Shellenbarger', + 'Steinmeyer', + 'Sura', + 'Tanski', + 'Teodoro', + 'Vanaken', + 'Jodoin', + 'Klinker', + 'Szydlowski', + 'Yamashiro', + 'Kutch', + 'Hoth', + 'Edwardson', + 'Gess', + 'Mohamad', + 'Goodine', + 'Carolina', + 'Blauser', + 'Emerich', + 'Flook', + 'Graul', + 'Gribben', + 'Herbold', + 'Kreutz', + 'Lavey', + 'Lukacs', + 'Maiorana', + 'Openshaw', + 'Plattner', + 'Sauro', + 'Schardt', + 'Tortorici', + 'Wendlandt', + 'Danowski', + 'Mcnellis', + 'Pinkowski', + 'Linz', + 'Virga', + 'Jardin', + 'Maclaughlin', + 'Rama', + 'Deline', + 'Kimbel', + 'Hagin', + 'Pottinger', + 'Detmer', + 'Ferrone', + 'Matthiesen', + 'Melchert', + 'Ruehl', + 'Takach', + 'Briese', + 'Elmendorf', + 'Valentini', + 'Hersom', + 'Bordeau', + 'Linsley', + 'Keatts', + 'Dina', + 'Boye', + 'Riviere', + 'Stodghill', + 'Madry', + 'Angelos', + 'Bou', + 'Ketterling', + 'Niemczyk', + 'Pardini', + 'Rippel', + 'Schieffer', + 'Schnee', + 'Shogren', + 'Sholl', + 'Ullmann', + 'Ure', + 'Curless', + 'Gonnella', + 'Tholen', + 'Valladolid', + 'Silbernagel', + 'Cohrs', + 'Shahin', + 'Beth', + 'Holmen', + 'Tippie', + 'Opie', + 'Sprowl', + 'Byam', + 'Bethany', + 'Saintil', + 'Auriemma', + 'Blust', + 'Dibello', + 'Digangi', + 'Farnam', + 'Farnan', + 'Linford', + 'Mcgroarty', + 'Meisenheimer', + 'Pagels', + 'Sauber', + 'Schwalbe', + 'Seemann', + 'Slivka', + 'Twardowski', + 'Wickey', + 'Zettler', + 'Zuchowski', + 'Feldhaus', + 'Baldock', + 'Cowman', + 'Carp', + 'Camera', + 'Balon', + 'Neveu', + 'Caminiti', + 'Carreira', + 'Gura', + 'Hershkowitz', + 'Killoran', + 'Narducci', + 'Reigel', + 'Saccone', + 'Tomasi', + 'Wieneke', + 'Sibrian', + 'Hashem', + 'Kellems', + 'Stouder', + 'Villamar', + 'Piette', + 'Wand', + 'Battey', + 'Staunton', + 'Bedore', + 'Hanel', + 'Jutras', + 'Kanner', + 'Mathiesen', + 'Northway', + 'Privitera', + 'Reichelt', + 'Zucco', + 'Roys', + 'Aderholt', + 'Lampson', + 'Olen', + 'Mcgarr', + 'Schools', + 'Leaphart', + 'Lykes', + 'Brightbill', + 'Koos', + 'Lahue', + 'Laplaca', + 'Naqvi', + 'Novo', + 'Puerta', + 'Siers', + 'Strutz', + 'Trimboli', + 'Waldie', + 'Goold', + 'Falke', + 'Corter', + 'Cartmell', + 'Brazel', + 'Farabee', + 'Majeed', + 'Hilden', + 'Kealoha', + 'Neider', + 'Parodi', + 'Rizza', + 'Rong', + 'Silberstein', + 'Snellgrove', + 'Trojanowski', + 'Warneke', + 'Wissler', + 'Yiu', + 'Grein', + 'Sak', + 'Daines', + 'Monzo', + 'Emmerson', + 'Lorraine', + 'Samaroo', + 'Edmund', + 'Cacace', + 'Dornan', + 'Eyman', + 'Hovanec', + 'Jeschke', + 'Limberg', + 'Maturo', + 'Pandey', + 'Somoza', + 'Streiff', + 'Wiemer', + 'Zablocki', + 'Crace', + 'Leinen', + 'Rucci', + 'Blyth', + 'Clemans', + 'Magid', + 'Ferrick', + 'Garriga', + 'Martir', + 'Tanton', + 'Hoon', + 'Echard', + 'Borrell', + 'Howden', + 'Gravett', + 'Lando', + 'Amacher', + 'Dalman', + 'Hollenbaugh', + 'Sigrist', + 'Tamashiro', + 'Therriault', + 'Villafranca', + 'Matthys', + 'Salois', + 'Sforza', + 'Swager', + 'Borah', + 'Sentell', + 'Besson', + 'Ghani', + 'Bilinski', + 'Holzinger', + 'Kus', + 'Lobianco', + 'Morawski', + 'Perz', + 'Sada', + 'Wollenberg', + 'Yusko', + 'Caughron', + 'Diffenderfer', + 'Slowinski', + 'Skiver', + 'Galland', + 'Hodes', + 'Boyne', + 'Towry', + 'Alers', + 'Hellums', + 'Certain', + 'Megginson', + 'Creer', + 'Coutee', + 'Strothers', + 'Stfleur', + 'Barga', + 'Bina', + 'Cellini', + 'Digiulio', + 'Douma', + 'Klement', + 'Mccambridge', + 'Parmeter', + 'Presto', + 'Salmi', + 'Seabaugh', + 'Barreda', + 'Nepomuceno', + 'Zent', + 'Yonce', + 'Loreto', + 'Honer', + 'Conquest', + 'Gathings', + 'Wims', + 'Upshur', + 'Aeschliman', + 'Casaus', + 'Dumke', + 'Earlywine', + 'Ferreyra', + 'Heyne', + 'Hudon', + 'Kuder', + 'Malia', + 'Brueckner', + 'Luchsinger', + 'Ornellas', + 'Ramseyer', + 'Weidemann', + 'Walbert', + 'Zola', + 'Linquist', + 'Storts', + 'Dente', + 'Lebleu', + 'Stockham', + 'Rollinson', + 'Auzenne', + 'Abebe', + 'Bartol', + 'Cozzolino', + 'Der', + 'Fata', + 'Gorr', + 'Janousek', + 'Moschella', + 'Riedy', + 'Dust', + 'Malmgren', + 'Puterbaugh', + 'Sacchetti', + 'Lascano', + 'Begnaud', + 'Duling', + 'Porteous', + 'Debnam', + 'Abron', + 'Delehanty', + 'Fazenbaker', + 'Flener', + 'Gora', + 'Herter', + 'Johann', + 'Keiter', + 'Lucca', + 'Passman', + 'Saindon', + 'Schoppe', + 'Skibinski', + 'Stueber', + 'Tegeler', + 'Jochim', + 'Buttner', + 'Crilly', + 'Swanton', + 'Muncey', + 'Negrin', + 'Thorburn', + 'Delpino', + 'Kinn', + 'Gaiter', + 'Obi', + 'Hohensee', + 'Rollman', + 'Scheff', + 'Shor', + 'Tumbleson', + 'Mccrum', + 'Knack', + 'Llano', + 'Saber', + 'Rosman', + 'Bankson', + 'Atkisson', + 'Kennel', + 'Cammon', + 'Bangura', + 'Cichy', + 'Gillikin', + 'Hiltner', + 'Lubben', + 'Mcqueeney', + 'Nasca', + 'Nordgren', + 'Ostermann', + 'Quito', + 'Sakowski', + 'Schut', + 'Stobaugh', + 'Alessio', + 'Gorelik', + 'Heinzman', + 'Westrich', + 'Nardella', + 'Cruzado', + 'Lansberry', + 'Dubreuil', + 'Nylander', + 'Rabel', + 'Moret', + 'Crout', + 'Ardrey', + 'Rolley', + 'Finks', + 'Cliett', + 'Caito', + 'Clingenpeel', + 'Delprete', + 'Dolen', + 'Heidrich', + 'Hinrichsen', + 'Jindra', + 'Madej', + 'Panzarella', + 'Sandin', + 'Seekins', + 'Shilts', + 'Sokoloff', + 'Maggart', + 'Pigman', + 'Travieso', + 'Denbow', + 'Dollison', + 'Gaye', + 'Binette', + 'Dutta', + 'Grandinetti', + 'Kitch', + 'Tangeman', + 'Finstad', + 'Rodkey', + 'Servis', + 'Tiwari', + 'Rodd', + 'Parfait', + 'Seck', + 'Delaurentis', + 'Dragan', + 'Fleig', + 'Giacobbe', + 'Hilligoss', + 'Kroh', + 'Lippe', + 'Maleski', + 'Perini', + 'Rutten', + 'Stauss', + 'Yoshikawa', + 'Dibattista', + 'Gilsdorf', + 'Riemenschneider', + 'Streck', + 'Gessler', + 'Springstead', + 'Zaki', + 'Lambie', + 'Barczak', + 'Ellerbrock', + 'Foresman', + 'Holstine', + 'Lemm', + 'Santillana', + 'Trautwein', + 'Unsworth', + 'Valderas', + 'Vaquero', + 'Vetsch', + 'Wadleigh', + 'Yonts', + 'Mcguiness', + 'Auvil', + 'Leeder', + 'Sprowls', + 'Cala', + 'Portalatin', + 'Casso', + 'Chirinos', + 'Less', + 'Baltzell', + 'Bo', + 'Whetsell', + 'Ledlow', + 'Fullbright', + 'Arnell', + 'Stainback', + 'Mcleish', + 'Lyn', + 'Bermeo', + 'Billet', + 'Craun', + 'Gladwell', + 'Goral', + 'Herbig', + 'Kluver', + 'Mermelstein', + 'Odette', + 'Poggi', + 'Schacher', + 'Thielman', + 'Cianciolo', + 'Ferrie', + 'Kapusta', + 'Kreager', + 'Messineo', + 'Rovira', + 'Stricklen', + 'Wansley', + 'Amell', + 'Baena', + 'Depaula', + 'Fickett', + 'Housewright', + 'Kreiger', + 'Legate', + 'Lutterman', + 'Men', + 'Pautz', + 'Swecker', + 'Tantillo', + 'Dudeck', + 'Bellas', + 'Marian', + 'Bienvenu', + 'Riden', + 'Hosein', + 'Couser', + 'Batterton', + 'Desantos', + 'Dieterle', + 'Drabek', + 'Grennan', + 'Greulich', + 'Ludlam', + 'Maltos', + 'Marcin', + 'Ostertag', + 'Rednour', + 'Tippetts', + 'Updyke', + 'Ormsbee', + 'Reutter', + 'Uyehara', + 'Musumeci', + 'Antonini', + 'Thistle', + 'Marcia', + 'Renne', + 'Jines', + 'Dorothy', + 'Menter', + 'Crosser', + 'Ditommaso', + 'Glueck', + 'Malta', + 'Mcgranahan', + 'Mensing', + 'Ostroff', + 'Rota', + 'Rothfuss', + 'Borcherding', + 'Haveman', + 'Swallows', + 'Heltzel', + 'Aloi', + 'Stipp', + 'Broda', + 'Darter', + 'Gressett', + 'Brasier', + 'Lana', + 'Crooke', + 'Seegers', + 'Sirmons', + 'Berberian', + 'Goers', + 'Losch', + 'Memon', + 'Paternoster', + 'Rierson', + 'Miyake', + 'Barndt', + 'Kirstein', + 'Azua', + 'Zeck', + 'Britain', + 'Lanman', + 'Gorges', + 'Clock', + 'Alman', + 'Callicutt', + 'Walford', + 'Searight', + 'Eakle', + 'Federici', + 'Hosack', + 'Jarecki', + 'Kauffmann', + 'Maras', + 'Nisley', + 'Sandahl', + 'Shidler', + 'Wnek', + 'Moneymaker', + 'Santander', + 'Schneeberger', + 'Luviano', + 'Gorin', + 'Negus', + 'Coulston', + 'Polin', + 'Winslett', + 'Anstett', + 'Cowsert', + 'Dipiazza', + 'Fitting', + 'Forslund', + 'Poquette', + 'Tibbets', + 'Tomasini', + 'Toor', + 'Starry', + 'Venema', + 'Cedano', + 'Carro', + 'Samons', + 'Matty', + 'Ellenwood', + 'Kilcrease', + 'Noblin', + 'Decatur', + 'Heckard', + 'Nard', + 'Beighley', + 'Delamater', + 'Eblen', + 'Heninger', + 'Kehn', + 'Rotunno', + 'Uppal', + 'Hynek', + 'Zenk', + 'Brasil', + 'Mu', + 'Julio', + 'Cassar', + 'Crisco', + 'Oriley', + 'Turton', + 'Goens', + 'Cargo', + 'Toure', + 'Breitbach', + 'Cahalan', + 'Chadha', + 'Kittinger', + 'Marnell', + 'Masias', + 'Matousek', + 'Mittal', + 'Nieblas', + 'Onan', + 'Purdum', + 'Tursi', + 'Esplin', + 'Etsitty', + 'Fratto', + 'Przybyla', + 'Cassin', + 'Nitti', + 'Arshad', + 'Sandoz', + 'Walzer', + 'Everton', + 'Russum', + 'Morland', + 'Fennel', + 'Viel', + 'Jarrells', + 'Vassell', + 'Frigo', + 'Kodama', + 'Naron', + 'Oelke', + 'Remaley', + 'Shean', + 'Cloonan', + 'Clayman', + 'Lasch', + 'Lepard', + 'Rewis', + 'Vankeuren', + 'Lightbody', + 'Houseworth', + 'Caison', + 'Denmon', + 'Rauls', + 'Sallie', + 'Humphery', + 'Showell', + 'Raysor', + 'Angotti', + 'Barbero', + 'Buxbaum', + 'Capella', + 'Horsch', + 'Kunselman', + 'Nishikawa', + 'Perotti', + 'Sprung', + 'Szucs', + 'Emch', + 'Kotula', + 'Mendizabal', + 'Yeaman', + 'Beste', + 'Kader', + 'Forker', + 'Wiggers', + 'Cotham', + 'Primo', + 'Fetterhoff', + 'Giarrusso', + 'Glosser', + 'Lumbreras', + 'Rosano', + 'Strohecker', + 'Wanek', + 'Waycaster', + 'Worthley', + 'Salasar', + 'Boulos', + 'Pulsipher', + 'Scheider', + 'Lorimer', + 'Alamilla', + 'Zapp', + 'Deis', + 'Tariq', + 'Kasey', + 'Famiglietti', + 'Flansburg', + 'Georgiou', + 'Groft', + 'Heistand', + 'Merker', + 'Stoeckel', + 'Tackitt', + 'Verbeck', + 'Weyers', + 'Wiltrout', + 'Brabec', + 'Caligiuri', + 'Dudzinski', + 'Grieger', + 'Benfer', + 'Pesta', + 'Wool', + 'Sunshine', + 'Oka', + 'Stamour', + 'Barrio', + 'Mathe', + 'Vanduyne', + 'Brager', + 'Mcphatter', + 'Ahluwalia', + 'Borys', + 'Dreibelbis', + 'Kalmbach', + 'Karwoski', + 'Moomaw', + 'Youngren', + 'Offerman', + 'Nine', + 'Symington', + 'Branan', + 'Turberville', + 'Heber', + 'Loughridge', + 'Vanderberg', + 'Mccannon', + 'Linda', + 'Dupee', + 'Cottom', + 'Mcphearson', + 'Razor', + 'Buchwald', + 'Fraze', + 'Grannis', + 'Krolikowski', + 'Lapidus', + 'Madruga', + 'Mcmartin', + 'Quinlivan', + 'Riaz', + 'Spittler', + 'Zahm', + 'Zender', + 'Eisman', + 'Hourihan', + 'Shirazi', + 'Herendeen', + 'Perdew', + 'Pendell', + 'Chernoff', + 'Lyell', + 'Clarey', + 'Macken', + 'Guthridge', + 'Redditt', + 'Bedi', + 'Debenedictis', + 'Distel', + 'Gapinski', + 'Iwanski', + 'Medici', + 'Schmutz', + 'Tuel', + 'Verburg', + 'Galgano', + 'Skogen', + 'Aymond', + 'Raymo', + 'Croney', + 'Carry', + 'Rhynes', + 'Lamour', + 'Shedrick', + 'Tookes', + 'Baltierra', + 'Leitzel', + 'Letchworth', + 'Montesino', + 'Preis', + 'Sanzone', + 'Shantz', + 'Teo', + 'Twohig', + 'Wajda', + 'Windisch', + 'Zinck', + 'Fiero', + 'Hornby', + 'Paget', + 'Serano', + 'Rodrick', + 'Lewison', + 'Dyas', + 'Delcarmen', + 'Garske', + 'Hontz', + 'Mcquown', + 'Melling', + 'Rolando', + 'Rosencrans', + 'Steichen', + 'Teeples', + 'Forseth', + 'Quijas', + 'Schraeder', + 'Vaidya', + 'Ventre', + 'Mountjoy', + 'Morr', + 'Leviner', + 'Paulette', + 'Dobie', + 'Brue', + 'Prier', + 'Biffle', + 'Neyland', + 'Valcourt', + 'Mckeithen', + 'Lemelle', + 'Alviar', + 'Auth', + 'Bahm', + 'Bierbaum', + 'Cazier', + 'Eschbach', + 'Etzler', + 'Nowlan', + 'Sahota', + 'Vanaman', + 'Zaugg', + 'Hogeland', + 'Choat', + 'Walmer', + 'Cepero', + 'Michal', + 'Foxwell', + 'Decoursey', + 'Molyneaux', + 'Peat', + 'Jeanfrancois', + 'Arevalos', + 'Bachert', + 'Beachler', + 'Berrones', + 'Clavijo', + 'Elsen', + 'Fuhs', + 'Hooven', + 'Johannessen', + 'Klausner', + 'Masso', + 'Puzio', + 'Sekula', + 'Smyser', + 'Stepanian', + 'Barg', + 'Trueman', + 'Constante', + 'Cubas', + 'Dowers', + 'Pratts', + 'Cockburn', + 'Counce', + 'Nappier', + 'Lindon', + 'Burrowes', + 'Cokley', + 'Tillmon', + 'Bao', + 'Inks', + 'Liberato', + 'Moehring', + 'Ryker', + 'Sar', + 'Swartzendruber', + 'Torgersen', + 'Treto', + 'Tungate', + 'Ricotta', + 'Weesner', + 'Willyard', + 'Callicoat', + 'Hoque', + 'Atkison', + 'Mcwherter', + 'Dubuisson', + 'Wanzer', + 'Stradford', + 'Abruzzo', + 'Amerman', + 'Bame', + 'Bantz', + 'Bleakley', + 'Galt', + 'Hoobler', + 'Jaquith', + 'Lessman', + 'Polinski', + 'Rasche', + 'Roeber', + 'Rubright', + 'Sarnowski', + 'Signore', + 'Solum', + 'Vankampen', + 'Vath', + 'Malmquist', + 'Mittelstadt', + 'Belyea', + 'Haverty', + 'Wickett', + 'Sansing', + 'Yeatman', + 'Brocker', + 'Wonders', + 'Both', + 'Rabun', + 'Rocke', + 'Meachum', + 'Blane', + 'Lapsley', + 'Biswas', + 'Derocher', + 'Haran', + 'Hehn', + 'Keshishian', + 'Kniffin', + 'Lacina', + 'Skolnik', + 'Spiewak', + 'Wileman', + 'Eble', + 'Kraynak', + 'Wiesen', + 'Micheli', + 'Scroggin', + 'Roch', + 'Denise', + 'Altenburg', + 'Hornstein', + 'Netto', + 'Opel', + 'Passey', + 'Roeske', + 'Schrantz', + 'Abrahamsen', + 'Powless', + 'Callais', + 'Desjardin', + 'Pirro', + 'Yonkers', + 'Macallister', + 'Dady', + 'Ruskin', + 'Escott', + 'Abbot', + 'Sankar', + 'Bolar', + 'Angelucci', + 'Biegel', + 'Cirone', + 'Damewood', + 'Flett', + 'Kronenberg', + 'Ky', + 'Nagler', + 'Perlstein', + 'Saperstein', + 'Tenbrink', + 'Vana', + 'Wnuk', + 'Bonnema', + 'Schoenecker', + 'Pichler', + 'Armendarez', + 'Oiler', + 'Rouch', + 'Boas', + 'Laracuente', + 'Milbourn', + 'Summy', + 'Counter', + 'Gracie', + 'Belfield', + 'Bynoe', + 'Jalloh', + 'Blazier', + 'Bochenek', + 'Broughman', + 'Chuong', + 'Cregger', + 'Estacio', + 'Kaleta', + 'Lanctot', + 'Mish', + 'Novosel', + 'Passero', + 'Ripplinger', + 'Vitt', + 'Walborn', + 'Friscia', + 'Memmott', + 'Tripi', + 'Weinhold', + 'Honn', + 'Gianni', + 'Poch', + 'Sagar', + 'Markum', + 'Primmer', + 'Belmore', + 'Rain', + 'Bevard', + 'Skyles', + 'Farland', + 'Mccleese', + 'Teachey', + 'Moulden', + 'Antolin', + 'Augello', + 'Borrayo', + 'Effler', + 'Hornak', + 'Hosman', + 'Leingang', + 'Limbach', + 'Oregel', + 'Ritzman', + 'Rochefort', + 'Schimke', + 'Stefanelli', + 'Vien', + 'Zurn', + 'Badolato', + 'Bieri', + 'Clarkin', + 'Folino', + 'Kelchner', + 'Pote', + 'Brahm', + 'Hoop', + 'Macbride', + 'Hunting', + 'Brule', + 'Wainright', + 'Rolison', + 'Bennie', + 'Banghart', + 'Bertke', + 'Bozzo', + 'Gadomski', + 'Granberg', + 'Kostecki', + 'Lemelin', + 'Levengood', + 'Puskas', + 'Swanstrom', + 'Willcutt', + 'Deitrich', + 'Grieves', + 'Ferran', + 'Boileau', + 'Kendra', + 'Trippe', + 'Mcconnel', + 'Cara', + 'Stephans', + 'Bachus', + 'Applin', + 'Utsey', + 'Auston', + 'Arras', + 'Bencosme', + 'Berntsen', + 'Decarolis', + 'Dettloff', + 'Duerksen', + 'Pavlovic', + 'Schwantes', + 'Sjostrom', + 'Sugiyama', + 'Sulak', + 'Virani', + 'Winberg', + 'Yoshimoto', + 'Comito', + 'Pandolfo', + 'Cathers', + 'Hardisty', + 'Collom', + 'Wain', + 'Worthing', + 'Leep', + 'Simo', + 'Boom', + 'Bald', + 'Applegarth', + 'Gilbreth', + 'Griest', + 'Jobin', + 'Matsuura', + 'Misko', + 'Scerbo', + 'Scheidler', + 'Sterba', + 'Tomaino', + 'Wixson', + 'Yadao', + 'Hietpas', + 'Gruss', + 'Fors', + 'Gosse', + 'Katt', + 'Virk', + 'Quebedeaux', + 'Barkey', + 'Salam', + 'Willford', + 'Tarry', + 'Chancy', + 'Beynon', + 'Eckes', + 'Eischen', + 'Felger', + 'Kimm', + 'Labate', + 'Mehan', + 'Netzer', + 'Strosnider', + 'Trezza', + 'Vial', + 'Waugaman', + 'Zieman', + 'Ankeny', + 'Digman', + 'Farino', + 'Faro', + 'Vasconcelos', + 'Nevill', + 'Rave', + 'Sabine', + 'Hagg', + 'Weightman', + 'Berton', + 'Fipps', + 'Knapper', + 'Camel', + 'Gilkes', + 'Aldous', + 'Delucca', + 'Dicke', + 'Evitts', + 'Hachey', + 'Rinck', + 'Treese', + 'Uher', + 'Victorio', + 'Vignola', + 'Willert', + 'Baun', + 'Wever', + 'Varn', + 'Yokum', + 'Dunk', + 'Maben', + 'Arzu', + 'Guider', + 'Bonhomme', + 'Majette', + 'Crislip', + 'Gresko', + 'Luppino', + 'Posch', + 'Potenza', + 'Rial', + 'Ruderman', + 'Shaff', + 'Balboni', + 'Solheim', + 'Mey', + 'Sittig', + 'Perman', + 'Sumners', + 'Deaner', + 'Keizer', + 'Reves', + 'Glanville', + 'Menzie', + 'Mccowen', + 'Steib', + 'Portee', + 'Azad', + 'Dallaire', + 'Denno', + 'Deptula', + 'Fischman', + 'Guilbault', + 'Imperato', + 'Koehne', + 'Menning', + 'Mirelez', + 'Stanislawski', + 'Streb', + 'Sumida', + 'Wolke', + 'Kerfoot', + 'Pirie', + 'Saracino', + 'Maslanka', + 'Slominski', + 'Nienaber', + 'Serena', + 'Kamper', + 'Matheis', + 'Westin', + 'Ishman', + 'Biagi', + 'Chiou', + 'Dieckmann', + 'Frieden', + 'Huestis', + 'Presutti', + 'Ribas', + 'Siedlecki', + 'Steege', + 'Uehara', + 'Petrosyan', + 'Siebold', + 'Turi', + 'Rady', + 'Vanorman', + 'Arif', + 'Hiland', + 'Naidu', + 'Clagett', + 'Ludy', + 'Bodley', + 'Avelino', + 'Citro', + 'Cuda', + 'Derbyshire', + 'Kruszewski', + 'Kupper', + 'Mahl', + 'Muratore', + 'Noecker', + 'Osmer', + 'Pasquariello', + 'Schlick', + 'Snover', + 'Strzelecki', + 'Studt', + 'Sunga', + 'Belmares', + 'Seifried', + 'Urioste', + 'Housh', + 'Babu', + 'Bures', + 'Augusto', + 'Faddis', + 'Pun', + 'Chopp', + 'Tullock', + 'Sea', + 'Boisseau', + 'Herbin', + 'Balcer', + 'Copus', + 'Eichenberger', + 'Enterline', + 'Gamarra', + 'Gursky', + 'Hovsepian', + 'Laffin', + 'Melena', + 'Rappe', + 'Soma', + 'Spira', + 'Spraker', + 'Teuscher', + 'Hochhalter', + 'Brenden', + 'Snee', + 'Polan', + 'Hataway', + 'Tirey', + 'Cobler', + 'Marren', + 'Ress', + 'Bennis', + 'Busha', + 'Galler', + 'Orea', + 'Nailor', + 'Magby', + 'Bridgett', + 'Island', + 'Camino', + 'Coderre', + 'Gangloff', + 'Gillilan', + 'Goergen', + 'Henthorne', + 'Heverly', + 'Loughry', + 'Records', + 'Schweikert', + 'Seeds', + 'Vanderwerf', + 'Westall', + 'Cristiano', + 'Biser', + 'Cartmill', + 'Greenly', + 'Kountz', + 'Craney', + 'Sheffey', + 'Gelin', + 'Gourdine', + 'Canham', + 'Edgmon', + 'Enz', + 'Feldpausch', + 'Hestand', + 'Kaus', + 'Kostelnik', + 'Ocanas', + 'Riggi', + 'Rohl', + 'Scheurer', + 'Sleeman', + 'Tosi', + 'Phegley', + 'Abelson', + 'Mclees', + 'Sinor', + 'Babson', + 'Whalley', + 'Manton', + 'Patteson', + 'Doyen', + 'Asad', + 'Thurmon', + 'Cassese', + 'Ditmore', + 'Duva', + 'Pilato', + 'Polaski', + 'Rzepka', + 'Sevin', + 'Sivak', + 'Speckman', + 'Stepien', + 'Switalski', + 'Valletta', + 'Knoth', + 'Niver', + 'Ciancio', + 'Giza', + 'Liebowitz', + 'Orengo', + 'Rothgeb', + 'Witz', + 'Airhart', + 'Gayman', + 'Belland', + 'Eury', + 'Randal', + 'Mcghie', + 'Briganti', + 'Hoopingarner', + 'Lugar', + 'Manfre', + 'Mongelli', + 'Squibb', + 'Vasil', + 'Cap', + 'Veillon', + 'Ege', + 'Spice', + 'Nevel', + 'Vanleer', + 'Petway', + 'Petitfrere', + 'Barcena', + 'Belville', + 'Brezina', + 'Ketcherside', + 'Knodel', + 'Krinsky', + 'Lundahl', + 'Mescher', + 'Pilat', + 'Sneller', + 'Staller', + 'Steinhaus', + 'Stensrud', + 'Szalay', + 'Tani', + 'Saviano', + 'Genna', + 'Emry', + 'Allin', + 'Harvel', + 'Harth', + 'Pay', + 'Harries', + 'Brannum', + 'Elijah', + 'Hoyte', + 'Bazinet', + 'Bhandari', + 'Brozek', + 'Cava', + 'Dalbey', + 'Delgiudice', + 'Klages', + 'Riffey', + 'Straube', + 'Zagar', + 'Zientek', + 'Dilger', + 'Hof', + 'Karwowski', + 'Rybarczyk', + 'Spiering', + 'Stamos', + 'Gangemi', + 'Olavarria', + 'Sardinas', + 'Magin', + 'Payano', + 'Deady', + 'Henricksen', + 'Kary', + 'Garnier', + 'Babic', + 'Behymer', + 'Billig', + 'Huegel', + 'Ishihara', + 'Mcglinchey', + 'Misuraca', + 'Petrosino', + 'Zizzo', + 'Reierson', + 'Wadman', + 'Brander', + 'Risko', + 'Basye', + 'Mcmakin', + 'Straughan', + 'Chesnutt', + 'Sima', + 'Ree', + 'Mankins', + 'Soberanis', + 'Greenup', + 'Commodore', + 'Carucci', + 'Defibaugh', + 'Finfrock', + 'Funston', + 'Grantz', + 'Guiney', + 'Ohrt', + 'Tinsman', + 'Godek', + 'Mcgrory', + 'Mikeska', + 'Kamer', + 'Lovas', + 'Kirshner', + 'Bevacqua', + 'Franqui', + 'Walts', + 'Doke', + 'Orsborn', + 'Tavernier', + 'Kibble', + 'Scipio', + 'Diop', + 'Antczak', + 'Bastida', + 'Callister', + 'Dusseau', + 'Ficarra', + 'Garcilazo', + 'Hughett', + 'Liebel', + 'Rodenbaugh', + 'Rosselli', + 'Teresi', + 'Bohnsack', + 'Steidl', + 'Vanderheiden', + 'Demma', + 'Dutson', + 'Mcmeekin', + 'Glassford', + 'Serrao', + 'Marriner', + 'Mcchristian', + 'Lias', + 'Blahnik', + 'Brunke', + 'Daleo', + 'Fullam', + 'Goetzinger', + 'Leva', + 'Rehder', + 'Ripperger', + 'Shindler', + 'Tussing', + 'Mayr', + 'Rozzi', + 'Bonsignore', + 'Te', + 'Graft', + 'Ok', + 'Clink', + 'Mccamey', + 'Goldring', + 'Tartt', + 'Fullilove', + 'Amodio', + 'Arkin', + 'Dettmann', + 'Ellingwood', + 'Figura', + 'Fritzinger', + 'Heilmann', + 'Hillstrom', + 'Marasigan', + 'Pavlov', + 'Totman', + 'Dokken', + 'Serpico', + 'Shumard', + 'Rathman', + 'Siegmund', + 'Woodhull', + 'Oregon', + 'Roselle', + 'Taul', + 'Maddix', + 'Nwosu', + 'Bavaro', + 'Carella', + 'Cowdrey', + 'Goodnough', + 'Koffler', + 'Mahajan', + 'Montalvan', + 'Morga', + 'Parrella', + 'Quiggle', + 'Rehrig', + 'Rotondi', + 'Tavenner', + 'Wigger', + 'Yax', + 'Bartko', + 'Netzel', + 'Zechman', + 'Socia', + 'Vea', + 'Wemple', + 'Matti', + 'Striplin', + 'Hollin', + 'Geddie', + 'Nolden', + 'Freeney', + 'Jeanjacques', + 'Bermudes', + 'Castrellon', + 'Catino', + 'Feeser', + 'Kreitz', + 'Maisano', + 'Melkonian', + 'Toste', + 'Vancura', + 'Bylsma', + 'Wiant', + 'Mcpheron', + 'Gere', + 'Geoffroy', + 'Fuston', + 'Petteway', + 'Barsky', + 'Bovard', + 'Buttars', + 'Christophersen', + 'Dudzik', + 'Ganger', + 'Hilgers', + 'Holzhauer', + 'Minervini', + 'Pong', + 'Rozycki', + 'Sulzer', + 'Tauscher', + 'Upright', + 'Verastegui', + 'Lobello', + 'Sandt', + 'Timbrook', + 'Yniguez', + 'Nuzzi', + 'Sakata', + 'Koran', + 'Veloso', + 'Cullers', + 'Culton', + 'Reynold', + 'Feagins', + 'Amaker', + 'Cafferty', + 'Coontz', + 'Iden', + 'Mazzotta', + 'Montanye', + 'Wandell', + 'Weiman', + 'Vik', + 'Staib', + 'Lasso', + 'Waynick', + 'Boniface', + 'Massingale', + 'Gainous', + 'Sharper', + 'Columbia', + 'Felkins', + 'Gatzke', + 'Heindel', + 'Ludeman', + 'Mcmunn', + 'Mogavero', + 'Ratti', + 'Rickabaugh', + 'Ripper', + 'Tessman', + 'Triano', + 'Vanderpol', + 'Langille', + 'Holten', + 'Steeley', + 'Solan', + 'Devaul', + 'Lindler', + 'Armor', + 'Fambrough', + 'Golliday', + 'Bognar', + 'Gamba', + 'Gettinger', + 'Hanzel', + 'Krumwiede', + 'Marcinkowski', + 'Nicolay', + 'Peppard', + 'Sisti', + 'Sundeen', + 'Senatore', + 'Diebel', + 'Demarais', + 'Letellier', + 'Goon', + 'Texidor', + 'Baughan', + 'Gunder', + 'Lalor', + 'Wigglesworth', + 'Aird', + 'Basey', + 'Afshar', + 'Anhalt', + 'Bondoc', + 'Bunten', + 'Daniello', + 'Kazmierski', + 'Marcott', + 'Petruska', + 'Trejos', + 'Droege', + 'Fukumoto', + 'Harju', + 'Hauf', + 'Yagi', + 'Mccallie', + 'Moulds', + 'Singleterry', + 'Ramkissoon', + 'Sanks', + 'Siggers', + 'Myrie', + 'Conteh', + 'Biss', + 'Brees', + 'Collopy', + 'Dashner', + 'Dehaas', + 'Delzer', + 'Fees', + 'Finocchiaro', + 'Forsgren', + 'Giampietro', + 'Levandowski', + 'Mallick', + 'Maudlin', + 'Micheletti', + 'Newhard', + 'Parmentier', + 'Pintado', + 'Pliego', + 'Radigan', + 'Selke', + 'Uptain', + 'Wigton', + 'Zabinski', + 'Becenti', + 'Guthmiller', + 'Malecha', + 'Eardley', + 'Muscat', + 'Ruhe', + 'Battersby', + 'Lamie', + 'Stan', + 'Dutch', + 'Duplechain', + 'Dildy', + 'Auch', + 'Baltzer', + 'Degaetano', + 'Mileski', + 'Parrillo', + 'Schoof', + 'Stires', + 'Villescas', + 'Knittle', + 'Degrave', + 'Deihl', + 'Moseman', + 'Prillaman', + 'Wakeley', + 'Jake', + 'Murden', + 'Shareef', + 'Yarbough', + 'Bothe', + 'Boutilier', + 'Breck', + 'Buschman', + 'Coccia', + 'Eberlein', + 'Harriger', + 'Neas', + 'Sullenger', + 'Walp', + 'Yaple', + 'Zinger', + 'Zufelt', + 'Marinaccio', + 'Viele', + 'Markee', + 'Melody', + 'Rooke', + 'Ales', + 'Mumphrey', + 'Bessinger', + 'Bialas', + 'Brugh', + 'Chum', + 'Diehm', + 'Frieze', + 'Hieber', + 'Malouf', + 'Maltz', + 'Mcmanaway', + 'Musante', + 'Pester', + 'Roda', + 'Snarr', + 'Tovey', + 'Buchmann', + 'Fluck', + 'Sadowsky', + 'Viteri', + 'Loewe', + 'Mullaly', + 'Lamboy', + 'Bouman', + 'Provencal', + 'Siddons', + 'Chelette', + 'Rachels', + 'Dynes', + 'Nobel', + 'Desselle', + 'Tillison', + 'Bajaj', + 'Bresee', + 'Hisel', + 'Mallo', + 'Meints', + 'Potocki', + 'Spore', + 'Steier', + 'Toothaker', + 'Wildt', + 'Darcangelo', + 'Karbowski', + 'Scaccia', + 'Lascola', + 'Duman', + 'Mccaul', + 'Rowton', + 'Setters', + 'Hendryx', + 'Belson', + 'Manny', + 'Winckler', + 'Longe', + 'Mclucas', + 'Lenon', + 'Linen', + 'Anstine', + 'Belkin', + 'Drozdowski', + 'Ender', + 'Ferra', + 'Lessig', + 'Marucci', + 'Nardo', + 'Nipp', + 'Passarella', + 'Roecker', + 'Siddique', + 'Stanczak', + 'Stavros', + 'Tomasetti', + 'Lagreca', + 'Seegmiller', + 'Keena', + 'Suddarth', + 'Wayt', + 'Matas', + 'Ryer', + 'Mortimore', + 'Durnell', + 'Pieters', + 'Slocumb', + 'Andaya', + 'Brymer', + 'Dufek', + 'Ekman', + 'Espericueta', + 'Feltes', + 'Hammann', + 'Heydt', + 'Inthavong', + 'Jagielski', + 'Nast', + 'Petrucelli', + 'Phippen', + 'Vanderzanden', + 'Whinery', + 'Zatarain', + 'Zelenak', + 'Aquilina', + 'Hougland', + 'Isais', + 'Canney', + 'Flath', + 'Ragon', + 'Len', + 'Violet', + 'Carra', + 'Everetts', + 'Lockey', + 'Dahmer', + 'Fuquay', + 'Alpers', + 'Borromeo', + 'Bringas', + 'Brumit', + 'Campanile', + 'Folts', + 'Hirai', + 'Kiessling', + 'Krogstad', + 'Ovitt', + 'Bhardwaj', + 'Hlavaty', + 'Monceaux', + 'Spatola', + 'Trunzo', + 'Girvin', + 'Shady', + 'Grimley', + 'Tagg', + 'Weddell', + 'Mcfadyen', + 'Reagin', + 'Philo', + 'Emily', + 'Codd', + 'Cherrington', + 'Skates', + 'Deary', + 'Ballester', + 'Barilla', + 'Cicchetti', + 'Dyche', + 'Goossen', + 'Graveline', + 'Hajduk', + 'Halliwell', + 'Kohnen', + 'Kupiec', + 'Machacek', + 'Manship', + 'Slinker', + 'Mallozzi', + 'Dotter', + 'Brazeau', + 'Manon', + 'Crofford', + 'Gauthreaux', + 'Petillo', + 'Bailor', + 'Ganesh', + 'Reaser', + 'Barren', + 'Adachi', + 'Aguiniga', + 'Cartrette', + 'Crady', + 'Hegland', + 'Isner', + 'Karasek', + 'Labrum', + 'Maroon', + 'Rullo', + 'Schull', + 'Stawicki', + 'Withee', + 'Penfold', + 'Foronda', + 'Claridge', + 'Coiner', + 'Guimaraes', + 'Mawyer', + 'Rivkin', + 'Kiggins', + 'Hackel', + 'Wey', + 'Fairhurst', + 'Albertini', + 'Gaal', + 'Flurry', + 'Patricia', + 'Savery', + 'Colen', + 'Cuthrell', + 'Maffett', + 'Dungey', + 'Luter', + 'Hurston', + 'Ahles', + 'Czapla', + 'Gallas', + 'Kotecki', + 'Lazzari', + 'Marcellino', + 'Valvo', + 'Vukovich', + 'Wisor', + 'Agler', + 'Wease', + 'Gallentine', + 'Christoph', + 'Poyer', + 'Norment', + 'Rhett', + 'Amabile', + 'Barish', + 'Heifner', + 'Kolarik', + 'Mcquarrie', + 'Morua', + 'Nahas', + 'Razzano', + 'Riegle', + 'Torralba', + 'Perfetti', + 'Stalzer', + 'Killman', + 'Lenning', + 'Wyler', + 'Soward', + 'Releford', + 'Battisti', + 'Bergum', + 'Catapano', + 'Doerner', + 'Ehlen', + 'Finken', + 'Genereux', + 'Hillegas', + 'Hopple', + 'Kaatz', + 'Lacson', + 'Macario', + 'Marzolf', + 'Muha', + 'Picha', + 'Springston', + 'Stooksbury', + 'Weide', + 'Glodowski', + 'Lueth', + 'Assaf', + 'Robuck', + 'Lamaster', + 'Foulkes', + 'Swopes', + 'Winkfield', + 'Aristizabal', + 'Aylesworth', + 'Bellotti', + 'Bittick', + 'Capistran', + 'Cizek', + 'Dinneen', + 'Ellender', + 'Friske', + 'Hoffa', + 'Klinge', + 'Kuklinski', + 'Luzier', + 'Martensen', + 'Rolin', + 'Shankles', + 'Siska', + 'Wiegman', + 'Winterbottom', + 'Crookston', + 'Gorospe', + 'Curci', + 'Lamberty', + 'Antonetti', + 'Sheer', + 'Durning', + 'Hootman', + 'Doub', + 'Klaiber', + 'Mayeaux', + 'Domingos', + 'Wheeless', + 'Vantrease', + 'Summerhill', + 'Agresta', + 'Annas', + 'Aquilar', + 'Crea', + 'Froese', + 'Medlen', + 'Peeters', + 'Rhudy', + 'Risse', + 'Schor', + 'Zimmerer', + 'Bombardier', + 'Halfhill', + 'Koppenhaver', + 'Kruckenberg', + 'Boccia', + 'Rella', + 'Carelli', + 'Overson', + 'Tamburro', + 'Rosamond', + 'Lie', + 'Mesquita', + 'Jennett', + 'Jewel', + 'Waye', + 'Bogucki', + 'Colpitts', + 'Galpin', + 'Hrdlicka', + 'Kading', + 'Kushnir', + 'Leano', + 'Liebig', + 'Mceuen', + 'Nestler', + 'Payer', + 'Santarelli', + 'Schrupp', + 'Schwarze', + 'Semrau', + 'Solanki', + 'Terzian', + 'Treloar', + 'Ureno', + 'Vohra', + 'Voshell', + 'Nakanishi', + 'Senese', + 'Dierker', + 'Quinley', + 'Monier', + 'Rounsaville', + 'Mcfaddin', + 'Defrance', + 'Joynes', + 'Levert', + 'Adragna', + 'Buczynski', + 'Cranor', + 'Englebert', + 'Furney', + 'Gorny', + 'Mockler', + 'Pavlicek', + 'Petrini', + 'Schadt', + 'Slagel', + 'Cumpston', + 'Priore', + 'Paonessa', + 'Carling', + 'Espaillat', + 'Hem', + 'Griffo', + 'Tomer', + 'Venn', + 'Giraud', + 'Becks', + 'Mungin', + 'Attard', + 'Brucato', + 'Dreyfus', + 'Droz', + 'Falck', + 'Firebaugh', + 'Fiser', + 'Hemmelgarn', + 'Hofacker', + 'Kreeger', + 'Rippee', + 'Ruehle', + 'Saputo', + 'Scovill', + 'Silbaugh', + 'Smolenski', + 'Spickler', + 'Swango', + 'Kaehler', + 'Mootz', + 'Noblett', + 'Zarcone', + 'Katzenberger', + 'Kita', + 'Brezinski', + 'Castles', + 'Padin', + 'Hinde', + 'Barretta', + 'Amiri', + 'Shelburne', + 'Mccoin', + 'Heaston', + 'Aldredge', + 'Milhouse', + 'Wilbon', + 'Cephus', + 'Barsness', + 'Belch', + 'Blatter', + 'Boyum', + 'Corvino', + 'Dagenais', + 'Doscher', + 'Elizarraraz', + 'Gierke', + 'Habegger', + 'Ketcher', + 'Kristiansen', + 'Oldroyd', + 'Sandage', + 'Tesoriero', + 'Unzueta', + 'Wollam', + 'Cefalu', + 'Achey', + 'Wegmann', + 'Lessner', + 'Bunk', + 'Mallin', + 'Polis', + 'Aronoff', + 'Portal', + 'Crock', + 'Escher', + 'Medler', + 'Pretty', + 'Younge', + 'Agbayani', + 'Brinkmeyer', + 'Castrillon', + 'Feick', + 'Gutmann', + 'Hagenbuch', + 'Hesseltine', + 'Houska', + 'Kimzey', + 'Kolasa', + 'Lentine', + 'Lobaugh', + 'Maimone', + 'Meshell', + 'Nardini', + 'Rosetti', + 'Siefker', + 'Sileo', + 'Silveria', + 'Argumedo', + 'Lesmeister', + 'Donnan', + 'Hermans', + 'Raggio', + 'Dupras', + 'Empson', + 'Bevier', + 'Tumey', + 'Donn', + 'Darville', + 'Douse', + 'Cheyne', + 'Dewing', + 'Jansma', + 'Mayeda', + 'Nield', + 'Obermiller', + 'Opfer', + 'Surma', + 'Tiffin', + 'Tirpak', + 'Wassel', + 'Blickenstaff', + 'Dorland', + 'Kulhanek', + 'Andras', + 'Estupinan', + 'Gonce', + 'Weast', + 'Souto', + 'Guirguis', + 'Glazebrook', + 'Dain', + 'Loyer', + 'Bensley', + 'Verge', + 'Tubman', + 'Onley', + 'Dais', + 'Barash', + 'Bullman', + 'Crispino', + 'Davino', + 'Isenhart', + 'Kneller', + 'Loschiavo', + 'Opper', + 'Pfleger', + 'Wahler', + 'Zelasko', + 'Havrilla', + 'Mintzer', + 'Devoll', + 'Giannelli', + 'Sees', + 'Barritt', + 'Mesta', + 'Sostre', + 'Rohman', + 'Padget', + 'Edds', + 'Slinger', + 'Borowicz', + 'Bregman', + 'Bubar', + 'Debartolo', + 'Desposito', + 'Grieshaber', + 'Ludtke', + 'Pagani', + 'Quiambao', + 'Schapiro', + 'Winward', + 'Bouska', + 'Olstad', + 'Rough', + 'Genz', + 'Husby', + 'Nealis', + 'Hyams', + 'Andrades', + 'Mcgibbon', + 'Edwin', + 'Buckhalter', + 'Baylon', + 'Fiene', + 'Fillingim', + 'Fiorenza', + 'Greenstreet', + 'Krager', + 'Laxson', + 'Noreen', + 'Roberds', + 'Rundquist', + 'Smelcer', + 'Tabone', + 'Train', + 'Zeoli', + 'Defries', + 'Kolp', + 'Maahs', + 'Mcnall', + 'Ehman', + 'Keeth', + 'Shackleton', + 'Hogarth', + 'Westbury', + 'Gulliver', + 'Oquin', + 'Holiman', + 'Saintlouis', + 'Vaughns', + 'Aichele', + 'Arbelaez', + 'Bathurst', + 'Bresler', + 'Cecena', + 'Drollinger', + 'Fellner', + 'Griesemer', + 'Harnois', + 'Hire', + 'Kraker', + 'Roylance', + 'Zaccaria', + 'Dinunzio', + 'Foisy', + 'Nordlund', + 'Peppler', + 'Kishbaugh', + 'Marcil', + 'Mcfarren', + 'Puello', + 'Supplee', + 'Boyea', + 'Depp', + 'Tift', + 'Wince', + 'Pam', + 'Ifill', + 'Brodt', + 'Caamano', + 'Gibler', + 'Litherland', + 'Miesner', + 'Pixler', + 'Schwimmer', + 'Suriano', + 'Abendroth', + 'Gillaspy', + 'Kumpf', + 'Schroepfer', + 'Boals', + 'Seneca', + 'Sasson', + 'Hindes', + 'Posten', + 'Lann', + 'Anctil', + 'Arebalo', + 'Beacom', + 'Boberg', + 'Coufal', + 'Didion', + 'Fromme', + 'Greenan', + 'Guerrette', + 'Hudec', + 'Kazmi', + 'Lucchese', + 'Mouw', + 'Savastano', + 'Schomer', + 'Shorb', + 'Storz', + 'Finazzo', + 'Knigge', + 'Pawlikowski', + 'Cercone', + 'Sutfin', + 'Valdespino', + 'Mccartin', + 'Yurko', + 'Treaster', + 'Peaden', + 'Russin', + 'Dibartolo', + 'Dona', + 'Skillern', + 'Brackens', + 'Amyx', + 'Bornemann', + 'Comtois', + 'Kaestner', + 'Kallenbach', + 'Krupka', + 'Lineback', + 'Lopata', + 'Mcclenahan', + 'Monteverde', + 'Otani', + 'Panchal', + 'Pawlicki', + 'Suman', + 'Vallance', + 'Zammit', + 'Liszewski', + 'Trunk', + 'Sharifi', + 'Lents', + 'Watkinson', + 'Willow', + 'Flaming', + 'Sol', + 'Dory', + 'Purchase', + 'Haris', + 'Bigsby', + 'Boonstra', + 'Emge', + 'Goodpasture', + 'Iwata', + 'Kau', + 'Syring', + 'Vlach', + 'Klaassen', + 'Vicuna', + 'Wasden', + 'Cattell', + 'Ridlon', + 'Fassler', + 'Scullion', + 'Hibbitts', + 'Mcgillis', + 'Pla', + 'Mustin', + 'Darty', + 'Minniefield', + 'Bloyd', + 'Calnan', + 'Casal', + 'Fickel', + 'Gamero', + 'Higuchi', + 'Huante', + 'Knies', + 'Letner', + 'Quang', + 'Teufel', + 'Topolski', + 'Tumminello', + 'Vanorder', + 'Slawinski', + 'Nyce', + 'Asmar', + 'Loudin', + 'Karen', + 'Budden', + 'Mothershed', + 'Fenelon', + 'Mccrorey', + 'Ashenfelter', + 'Auge', + 'Christison', + 'Cilley', + 'Corsetti', + 'Coxwell', + 'Critchley', + 'Griep', + 'Hausner', + 'Hiemstra', + 'Koprowski', + 'Kozicki', + 'Marling', + 'Marmo', + 'Noller', + 'Pich', + 'Recendez', + 'Renegar', + 'Rinne', + 'Zeis', + 'Buzzelli', + 'Lipham', + 'Schaner', + 'Kartchner', + 'Kealy', + 'Sinopoli', + 'Krishna', + 'Brinn', + 'Zachry', + 'Barbre', + 'Sharber', + 'Fritze', + 'Hanshew', + 'Lemere', + 'Maruyama', + 'Masker', + 'Melendy', + 'Pelto', + 'Rigo', + 'Rohling', + 'Scobee', + 'Sundell', + 'Tranter', + 'Vancuren', + 'Augustyniak', + 'Mehringer', + 'Sulkowski', + 'Gittins', + 'Twiford', + 'Dumm', + 'Jacklin', + 'Mcquaig', + 'Richison', + 'Jex', + 'Meritt', + 'Hegler', + 'Duboise', + 'Houze', + 'Akana', + 'Corsaro', + 'Delosangeles', + 'Guidice', + 'Maccallum', + 'Moes', + 'Steinhardt', + 'Stirewalt', + 'Wooters', + 'Schissler', + 'Sobeck', + 'Boyte', + 'Jilek', + 'Suder', + 'Kellis', + 'Blankenbaker', + 'Lank', + 'Mandigo', + 'Fremont', + 'Rideau', + 'Beidler', + 'Boda', + 'Gulotta', + 'Havelka', + 'Herberger', + 'Isenhower', + 'Lattanzi', + 'Pandolfi', + 'Shearman', + 'Wilmarth', + 'Dutkiewicz', + 'Mazzuca', + 'Tabarez', + 'Vermilyea', + 'Kray', + 'Vitti', + 'Packwood', + 'Paulos', + 'Howson', + 'Collman', + 'Ameen', + 'Berisha', + 'Capece', + 'Fantasia', + 'Galas', + 'Laszlo', + 'Luthi', + 'Maietta', + 'Mcconaghy', + 'Naab', + 'Nerio', + 'Pineau', + 'Rossbach', + 'Senne', + 'Unangst', + 'Kautzman', + 'Muhs', + 'Ripka', + 'Wehling', + 'Hoot', + 'Jee', + 'Megna', + 'Tirone', + 'Walle', + 'Brandi', + 'Lutter', + 'Mona', + 'Roley', + 'Mcfann', + 'Swader', + 'Cavett', + 'Delmore', + 'Walthour', + 'Goldson', + 'Biddinger', + 'Bjornstad', + 'Buesing', + 'Cerino', + 'Diede', + 'Hagle', + 'Hodgman', + 'Killmer', + 'Loa', + 'Matsunaga', + 'Micciche', + 'Newquist', + 'Poppen', + 'Shellhammer', + 'Tienda', + 'Tino', + 'Mihelich', + 'Garsia', + 'Orzel', + 'Ericsson', + 'Dose', + 'Kotter', + 'Amante', + 'Hanif', + 'Huckleberry', + 'Blandin', + 'Carvin', + 'Axton', + 'Delosrios', + 'Diekmann', + 'Failing', + 'Filipek', + 'Otting', + 'Rozman', + 'Sadeghi', + 'Slutsky', + 'Speake', + 'Szostak', + 'Tacy', + 'Kmiecik', + 'Macgillivray', + 'Yeakel', + 'Dykman', + 'Gorey', + 'Dowding', + 'Revel', + 'Geathers', + 'Cappa', + 'Davidoff', + 'Lukehart', + 'Mccutchan', + 'Neeb', + 'Nikolic', + 'Piorkowski', + 'Sandvig', + 'Schmidgall', + 'Stockbridge', + 'Thornock', + 'Valk', + 'Wiechmann', + 'Chait', + 'Gacek', + 'Schupbach', + 'Gemma', + 'Rus', + 'Barch', + 'Wyles', + 'Scrivener', + 'Salls', + 'Akram', + 'Mcclatchey', + 'Bromfield', + 'Burl', + 'Redwood', + 'Starkes', + 'Beaston', + 'Boggio', + 'Cantillo', + 'Cina', + 'Cryan', + 'Dubs', + 'Edmisten', + 'Fitzer', + 'Fugere', + 'Fundora', + 'Galvis', + 'Jafri', + 'Nalepa', + 'Peri', + 'Pippenger', + 'Rheault', + 'Rohrbacher', + 'Romberg', + 'Samek', + 'Stehlik', + 'Stepan', + 'Torrisi', + 'Wessner', + 'Zappala', + 'Bangerter', + 'Czerniak', + 'Mcshea', + 'Raczkowski', + 'Rohwer', + 'Spehar', + 'Lague', + 'Messman', + 'Angst', + 'Temme', + 'Tolles', + 'Lawn', + 'Ayars', + 'Austen', + 'Stansel', + 'Fairclough', + 'Tribbett', + 'Peevy', + 'Fraiser', + 'Caradine', + 'Fiegel', + 'Gignac', + 'Halpert', + 'Karels', + 'Knappenberger', + 'Prezioso', + 'Rohlfs', + 'Szot', + 'Varano', + 'Weinreich', + 'Butterbaugh', + 'Heying', + 'Vandewalle', + 'Yandle', + 'Thede', + 'Astor', + 'Blanchfield', + 'Hegeman', + 'Fels', + 'Miniard', + 'Lorio', + 'Muhammed', + 'Lazard', + 'Ehmke', + 'Hulst', + 'Imlay', + 'Kinzler', + 'Knaak', + 'Poehler', + 'Prusak', + 'Rakow', + 'Raupp', + 'Sucher', + 'Tanenbaum', + 'Burich', + 'Macmaster', + 'Shapley', + 'Thurgood', + 'Mires', + 'Gotay', + 'Attia', + 'Martis', + 'Greenley', + 'Fothergill', + 'Bonvillain', + 'Buffalo', + 'Dues', + 'Crute', + 'Cantone', + 'Dewit', + 'Dovel', + 'Klopfer', + 'Philhower', + 'Piatek', + 'Pion', + 'Rapaport', + 'Vanwert', + 'Wikstrom', + 'Graffeo', + 'Kissling', + 'Niday', + 'Soong', + 'Adami', + 'Hammersmith', + 'Keir', + 'Yo', + 'Grizzell', + 'Stclaire', + 'Swales', + 'Nole', + 'Pole', + 'Hartgrove', + 'Carrothers', + 'Carlone', + 'Ciano', + 'Finucane', + 'Fitterer', + 'Gellman', + 'Hakimi', + 'Janos', + 'Krings', + 'Malmstrom', + 'Markwardt', + 'Rodin', + 'Schau', + 'Scheible', + 'Orick', + 'Dine', + 'Tremmel', + 'Shon', + 'Wilms', + 'Bren', + 'Bertin', + 'Poster', + 'Jeng', + 'Stcharles', + 'Jenning', + 'Eutsey', + 'Fayne', + 'Gustave', + 'Mccargo', + 'Boruff', + 'Boschert', + 'Burmester', + 'Colello', + 'Conchas', + 'Devi', + 'Dishaw', + 'Funaro', + 'Gallen', + 'Hsueh', + 'Lanser', + 'Macaraeg', + 'Munster', + 'Petsch', + 'Routon', + 'Werkmeister', + 'Woznicki', + 'Boroff', + 'Cochenour', + 'Dibartolomeo', + 'Elzinga', + 'Heyen', + 'Lapaglia', + 'Schiel', + 'Rauda', + 'Woltman', + 'Carll', + 'Kanda', + 'Runnells', + 'Hazelett', + 'Arnwine', + 'Sherfield', + 'Borthwick', + 'Coyner', + 'Ensey', + 'Feinman', + 'Leyendecker', + 'Lickteig', + 'Lubeck', + 'Maccarone', + 'Minahan', + 'Plew', + 'Saur', + 'Schleich', + 'Sixtos', + 'Soller', + 'Valek', + 'Umland', + 'Swogger', + 'Iannacone', + 'Tomey', + 'Venuto', + 'Peru', + 'Adolf', + 'Lemme', + 'Bureau', + 'River', + 'Buffaloe', + 'Leacock', + 'Threat', + 'Boza', + 'Constancio', + 'Dandurand', + 'Hiscock', + 'Kaley', + 'Michaelsen', + 'Roberti', + 'Sicilia', + 'Sliker', + 'Sooter', + 'Steyer', + 'Tabora', + 'Vanderbeek', + 'Vanscyoc', + 'Piercey', + 'Sabater', + 'Bride', + 'Tippens', + 'Acquaviva', + 'Baublitz', + 'Mccanna', + 'Mckaig', + 'Merenda', + 'Obermeier', + 'Pechacek', + 'Pugmire', + 'Shaneyfelt', + 'Steuer', + 'Zeidler', + 'Bodenheimer', + 'Gaglio', + 'Maceachern', + 'Munsterman', + 'Rayle', + 'Wisnewski', + 'Baar', + 'Thi', + 'Foulds', + 'Rufino', + 'Chrisco', + 'Barrientez', + 'Lare', + 'Munnerlyn', + 'Pitter', + 'Koroma', + 'Caisse', + 'Espe', + 'Kerin', + 'Melchiorre', + 'Mentz', + 'Paasch', + 'Parrales', + 'Rhew', + 'Sigley', + 'Skiff', + 'Stockert', + 'Viglione', + 'Kraska', + 'Botto', + 'Ponzio', + 'Wolfley', + 'Wack', + 'Kilborn', + 'Dunnavant', + 'Pitney', + 'Dolman', + 'Biscoe', + 'Michelle', + 'Azcona', + 'Brasington', + 'Fazzino', + 'Hoefs', + 'Kohlmeyer', + 'Laser', + 'Morea', + 'Morrin', + 'Neuwirth', + 'Nicklaus', + 'Pennypacker', + 'Rueckert', + 'Schriefer', + 'Scovel', + 'Swyers', + 'Thebeau', + 'Mijangos', + 'Douville', + 'Tidball', + 'Smullen', + 'Lecount', + 'Pruiett', + 'Branche', + 'Arment', + 'Babiarz', + 'Char', + 'Granlund', + 'Hillock', + 'Kahrs', + 'Khong', + 'Lalley', + 'Laspina', + 'Pietila', + 'Ponciano', + 'Rosengren', + 'Slee', + 'Snowberger', + 'Weglarz', + 'Camarata', + 'Villalovos', + 'Buza', + 'Kenning', + 'Rohrig', + 'Sedor', + 'Perretta', + 'Hamberg', + 'Mongan', + 'Formby', + 'Portier', + 'Silcott', + 'Levell', + 'Barrantes', + 'Bellefeuille', + 'Beneke', + 'Bilbao', + 'Danahy', + 'Delahanty', + 'Deppen', + 'Dicostanzo', + 'Dudding', + 'Elmquist', + 'Handa', + 'Hatem', + 'Loverde', + 'Mesick', + 'Onofrio', + 'Ramesh', + 'Tiberio', + 'Trachtenberg', + 'Vanwagenen', + 'Cassada', + 'Pepitone', + 'Stillson', + 'Pfarr', + 'Radle', + 'Scallan', + 'Carlen', + 'Bermingham', + 'Sagers', + 'Llorens', + 'Turay', + 'Beamish', + 'Carlini', + 'Galipeau', + 'Heavey', + 'Kempker', + 'Masser', + 'Montellano', + 'Peine', + 'Pietro', + 'Plitt', + 'Pollman', + 'Rike', + 'Spees', + 'Vandervelde', + 'Vanwey', + 'Grundman', + 'Marinucci', + 'Molenda', + 'Shideler', + 'Turrubiartes', + 'Schaer', + 'Firkins', + 'Haid', + 'Parnes', + 'Pulse', + 'Masone', + 'Burpo', + 'Tharrington', + 'Winborn', + 'Petite', + 'Buttry', + 'Clason', + 'Eutsler', + 'Haberer', + 'Haft', + 'Kotler', + 'Meloche', + 'Raether', + 'Rengifo', + 'Roback', + 'Stangle', + 'Wilderman', + 'Chickering', + 'Gervacio', + 'Penaranda', + 'Schnieders', + 'Coyer', + 'Laramee', + 'Curts', + 'Bailiff', + 'Truby', + 'Molder', + 'Hedley', + 'Carbon', + 'Gudger', + 'Fontenette', + 'Askren', + 'Deshane', + 'Enriques', + 'Fake', + 'Jungers', + 'Krech', + 'Niemela', + 'Perfetto', + 'Ritt', + 'Soldano', + 'Stanish', + 'Strege', + 'Wichert', + 'Wolz', + 'Zimbelman', + 'Abplanalp', + 'Nikkel', + 'Oravec', + 'Coile', + 'Mizuno', + 'Fenlon', + 'Vanloo', + 'Callery', + 'Hortman', + 'Hashim', + 'Sorey', + 'Ajayi', + 'Alesi', + 'Alessandro', + 'Avants', + 'Bachtel', + 'Bonine', + 'Butkovich', + 'Cerros', + 'Colina', + 'Dayhoff', + 'Favata', + 'Haning', + 'Kamath', + 'Kosik', + 'Loughrey', + 'Mollo', + 'Nagi', + 'Nesler', + 'Nosek', + 'Ordoyne', + 'Politis', + 'Zwolinski', + 'Yaffe', + 'Sigal', + 'Burow', + 'Scarbro', + 'Buckel', + 'Broxson', + 'Goyer', + 'Goding', + 'Delee', + 'Jefferys', + 'Blissett', + 'Balian', + 'Brader', + 'Curreri', + 'Dickmann', + 'Eckerle', + 'Erives', + 'Fedewa', + 'Frisina', + 'Gropp', + 'Hinck', + 'Lamorte', + 'Litzenberger', + 'Proehl', + 'Struss', + 'Tamburello', + 'Digioia', + 'Galarneau', + 'Jurkiewicz', + 'Macnaughton', + 'Talsma', + 'Vlasak', + 'Weyrauch', + 'Yontz', + 'Kho', + 'Stgermaine', + 'Grauer', + 'Benware', + 'Rearden', + 'Molin', + 'Pendergrast', + 'Sivils', + 'Ellery', + 'Ikner', + 'Metayer', + 'Toran', + 'Seaberry', + 'Banderas', + 'Bannan', + 'Critzer', + 'Doescher', + 'Haakenson', + 'Hignite', + 'Hoeksema', + 'Inserra', + 'Korbel', + 'Kruzel', + 'Langen', + 'Mittelstaedt', + 'Popkin', + 'Schwarting', + 'Toral', + 'Ilagan', + 'Lamica', + 'Lierman', + 'Zimmerly', + 'Fosse', + 'Pagnotta', + 'Trenholm', + 'Clayson', + 'Cerutti', + 'Wollard', + 'Mcburnett', + 'Stallcup', + 'Magan', + 'Wonder', + 'Gillock', + 'Ellisor', + 'Clayburn', + 'Mabery', + 'Cariaga', + 'Crail', + 'Dieckman', + 'Joynt', + 'Kleinert', + 'Kutner', + 'Milla', + 'Nauta', + 'Rende', + 'Robare', + 'Santella', + 'Scianna', + 'Sevcik', + 'Smolik', + 'Staudinger', + 'Cedillos', + 'Shroff', + 'Ueda', + 'Yearout', + 'Zuno', + 'Pottle', + 'Klabunde', + 'Tusa', + 'Schomburg', + 'Alto', + 'Packett', + 'Muns', + 'Dante', + 'Jarnigan', + 'Londo', + 'Bigbee', + 'Isles', + 'Nembhard', + 'Appiah', + 'Hypolite', + 'Acebedo', + 'Arlt', + 'Champney', + 'Kawahara', + 'Lehan', + 'Pavlak', + 'Ritacco', + 'Seckinger', + 'Turvey', + 'Vanevery', + 'Wronski', + 'Bahnsen', + 'Clites', + 'Ellwanger', + 'Husak', + 'Lydic', + 'Zubiate', + 'Muehlbauer', + 'Neumeister', + 'Wellnitz', + 'Langstaff', + 'Gort', + 'Eve', + 'Stones', + 'Stanard', + 'Whichard', + 'Cheers', + 'Baldus', + 'Bertoni', + 'Chesebro', + 'Dino', + 'Dubray', + 'Icenhour', + 'Marquard', + 'Mette', + 'Potash', + 'Winterhalter', + 'Crupi', + 'Lascala', + 'Tauer', + 'Vandenburgh', + 'Mende', + 'Swarey', + 'Sarles', + 'Platter', + 'Dekeyser', + 'Jaye', + 'Pelle', + 'Caroll', + 'Rosette', + 'Shepperson', + 'Fooks', + 'Kennerson', + 'Bolser', + 'Chim', + 'Diefenderfer', + 'Frosch', + 'Holzwarth', + 'Kjos', + 'Langland', + 'Meland', + 'Stufflebeam', + 'Worland', + 'Barrales', + 'Chhay', + 'Corkern', + 'Creegan', + 'Golan', + 'Marceaux', + 'Matsuo', + 'Micallef', + 'Otsuka', + 'Rinella', + 'Creveling', + 'Krane', + 'Mcnay', + 'Detter', + 'Drexel', + 'Kibodeaux', + 'Shippey', + 'Medearis', + 'Samms', + 'Drzewiecki', + 'Fariss', + 'Glandon', + 'Heinecke', + 'Hendler', + 'Jungwirth', + 'Panepinto', + 'Rohleder', + 'Saragosa', + 'Stuller', + 'Wissel', + 'Atwal', + 'Tisch', + 'Esterly', + 'Mourad', + 'Brickell', + 'Bough', + 'Rubens', + 'Angevine', + 'Tolin', + 'Sago', + 'Apfel', + 'Ashdown', + 'Derusha', + 'Fiorino', + 'Koyama', + 'Matteucci', + 'Newbrough', + 'Seufert', + 'Stahley', + 'Tyburski', + 'Zaino', + 'Cdebaca', + 'Hormann', + 'Wangen', + 'Winterton', + 'Beagley', + 'Sowden', + 'Daul', + 'Errington', + 'Steber', + 'Emfinger', + 'Olan', + 'Fiveash', + 'Carriger', + 'Breakfield', + 'Ezekiel', + 'Wallington', + 'Hollimon', + 'Izzard', + 'Lyde', + 'Bellmore', + 'Benkert', + 'Bhargava', + 'Dacanay', + 'Dano', + 'Diprima', + 'Garlitz', + 'Hannemann', + 'Janiak', + 'Klann', + 'Kunce', + 'Malicki', + 'Mcgivney', + 'Nordeen', + 'Procell', + 'Rands', + 'Smeltz', + 'Sutch', + 'Wach', + 'Wentling', + 'Karapetyan', + 'Mcvicar', + 'Pennisi', + 'Perley', + 'Graner', + 'Hartney', + 'Shadley', + 'Pennebaker', + 'Cayce', + 'Marris', + 'Burges', + 'Odem', + 'Charvat', + 'Delgreco', + 'Diven', + 'Latu', + 'Mccallion', + 'Mcfeely', + 'Mon', + 'Nagai', + 'Obrecht', + 'Opdyke', + 'Pearlstein', + 'Pomroy', + 'Prothero', + 'Rado', + 'Roehr', + 'Seiffert', + 'Spake', + 'Stech', + 'Thakur', + 'Trzcinski', + 'Uvalle', + 'Vazques', + 'Anschutz', + 'Boecker', + 'Descoteaux', + 'Idol', + 'Stanzione', + 'Welp', + 'Schumer', + 'Ridner', + 'Kasner', + 'Auton', + 'Barca', + 'Ocheltree', + 'Biernat', + 'Mercuri', + 'Truslow', + 'Witters', + 'Mcelhannon', + 'Mccrackin', + 'Brabson', + 'Baumberger', + 'Double', + 'Garis', + 'Kasparian', + 'Kooistra', + 'Loser', + 'Mangone', + 'Massman', + 'Raimondo', + 'Sparacio', + 'Valli', + 'Viets', + 'Wessell', + 'Kieu', + 'Vonderheide', + 'Wojnar', + 'Furbee', + 'Heyden', + 'Lackie', + 'Ehrich', + 'Roupe', + 'Holy', + 'Care', + 'Isa', + 'Samad', + 'Rougeau', + 'Chavous', + 'Rattler', + 'Wedderburn', + 'President', + 'Blackham', + 'Bobak', + 'Crimi', + 'Durland', + 'Gargus', + 'Gitlin', + 'Levandoski', + 'Niu', + 'Piccirilli', + 'Sauvageau', + 'Schweers', + 'Talty', + 'Uthe', + 'Verga', + 'Warzecha', + 'Erisman', + 'Gallacher', + 'Shanholtz', + 'Fulgencio', + 'Migues', + 'Garin', + 'Heisel', + 'Stong', + 'Christiana', + 'Bonenfant', + 'Clancey', + 'Kindley', + 'Nill', + 'Mood', + 'Atterbury', + 'Tobe', + 'Eisenhardt', + 'Franceschini', + 'Heiland', + 'Kreuzer', + 'Lockaby', + 'Scarola', + 'Tessitore', + 'Warehime', + 'Kukowski', + 'Ruhlman', + 'Frymire', + 'Bartone', + 'Wrightson', + 'Langlinais', + 'Planas', + 'Darsey', + 'Darin', + 'Gammel', + 'Giroir', + 'Aspinall', + 'Hollywood', + 'Childres', + 'Copelin', + 'Teamer', + 'Okoro', + 'Abshier', + 'Arizaga', + 'Berenson', + 'Biegler', + 'Dugdale', + 'Erlich', + 'Gavino', + 'Haaland', + 'Lautenschlager', + 'Lilja', + 'Livingood', + 'Lockner', + 'Pyeatt', + 'Reist', + 'Rummell', + 'Schadler', + 'Snare', + 'Zawada', + 'Dumler', + 'Moncivais', + 'Sammarco', + 'Laraway', + 'Voorhis', + 'Detty', + 'Manko', + 'Zale', + 'Autin', + 'Quaid', + 'Denver', + 'Demario', + 'Nearing', + 'Amerine', + 'Bea', + 'Carraher', + 'Dierkes', + 'Dutko', + 'Hosek', + 'Kassner', + 'Meo', + 'Mesler', + 'Norquist', + 'Pacetti', + 'Pellerito', + 'Ryser', + 'Turnmire', + 'Caniglia', + 'Zollman', + 'Gerwig', + 'Denslow', + 'Stapler', + 'Majid', + 'Prestage', + 'Eargle', + 'Spight', + 'Argabright', + 'Borgeson', + 'Cipollone', + 'Dippold', + 'Korf', + 'Milhoan', + 'Pinelli', + 'Roblero', + 'Scolaro', + 'Sperl', + 'Svensson', + 'Bauguess', + 'Freimuth', + 'Luquin', + 'Barman', + 'Solivan', + 'Buel', + 'Birkeland', + 'Cafiero', + 'Degollado', + 'Demeyer', + 'Hoberg', + 'Homola', + 'Kadel', + 'Koslowski', + 'Lefrancois', + 'Macconnell', + 'Madill', + 'Nudelman', + 'Raucci', + 'Reidenbach', + 'Schermer', + 'Sergio', + 'Bucko', + 'Haegele', + 'Nibert', + 'Sidell', + 'Slape', + 'Hellard', + 'Russi', + 'Wilcock', + 'Verdejo', + 'Lessley', + 'Camille', + 'Topps', + 'Acampora', + 'Blacketer', + 'Clapham', + 'Efaw', + 'Louks', + 'Mersch', + 'Odden', + 'Schettler', + 'Schnarr', + 'Sieracki', + 'Skog', + 'Zobrist', + 'Corless', + 'Zunker', + 'Bega', + 'Victoriano', + 'Singler', + 'Keltz', + 'Valcarcel', + 'Curet', + 'Harvison', + 'Mccullah', + 'Cranfield', + 'Gardin', + 'Mewborn', + 'Bisel', + 'Carfagno', + 'Carli', + 'Chirino', + 'Fairless', + 'Gaboury', + 'Goetze', + 'Guitron', + 'Haut', + 'Krupski', + 'Lata', + 'Misiak', + 'Sawaya', + 'Schomaker', + 'Schulke', + 'Tin', + 'Dewhurst', + 'Krummel', + 'Hannahs', + 'Carlow', + 'Hemp', + 'Bowdoin', + 'Breda', + 'Chriss', + 'Kebede', + 'Binney', + 'Brasseaux', + 'Cunliffe', + 'Gantner', + 'Gillick', + 'Hottle', + 'Hren', + 'Irani', + 'Klitzke', + 'Luhrs', + 'Micale', + 'Oien', + 'Oppelt', + 'Rallo', + 'Ringwald', + 'Stonerock', + 'Strebel', + 'Tiberi', + 'Volner', + 'Whetstine', + 'Wrubel', + 'Brakebill', + 'Fechner', + 'Geurts', + 'Hoefling', + 'Misener', + 'Andros', + 'Dimock', + 'Rosendo', + 'Megill', + 'Gloyd', + 'Garney', + 'Andries', + 'Esco', + 'Rhames', + 'Draine', + 'Plair', + 'Jiggetts', + 'Atcheson', + 'Brienza', + 'Cerveny', + 'Depaoli', + 'Deroo', + 'Dorf', + 'Guidotti', + 'Heimlich', + 'Insalaco', + 'Kaczorowski', + 'Kinnunen', + 'Loureiro', + 'Lyster', + 'Pia', + 'Piccoli', + 'Quale', + 'Sadek', + 'Stenstrom', + 'Strause', + 'Tortorella', + 'Traweek', + 'Vanderwerff', + 'Varian', + 'Vink', + 'Waxler', + 'Wynia', + 'Annese', + 'Economou', + 'Whitsel', + 'Dougher', + 'Schnieder', + 'Cosman', + 'Farra', + 'Osmon', + 'Bardon', + 'Rampersaud', + 'Jane', + 'Kirts', + 'Chennault', + 'Thomison', + 'Graig', + 'Narine', + 'Gunner', + 'Aamodt', + 'Adinolfi', + 'Adolphson', + 'Aki', + 'Alderton', + 'Aloisio', + 'Bellavia', + 'Clutts', + 'Coughran', + 'Frasco', + 'Guinta', + 'Hatala', + 'Ibach', + 'Mecum', + 'Medero', + 'Neria', + 'Nery', + 'Pignataro', + 'Podesta', + 'Statzer', + 'Stombaugh', + 'Szczesny', + 'Kovaleski', + 'Ades', + 'Bauers', + 'Bern', + 'Horsfall', + 'Masood', + 'Cinque', + 'Stay', + 'Beare', + 'Donavan', + 'Ikerd', + 'Seney', + 'Layson', + 'Coler', + 'Tuft', + 'Tamplin', + 'Billinger', + 'Scrivens', + 'Bartolomei', + 'Baza', + 'Dimattia', + 'Dotterer', + 'Dushane', + 'Fulop', + 'Iacovelli', + 'Macnamara', + 'Mahlum', + 'Noteboom', + 'Rebstock', + 'Drechsler', + 'Itzkowitz', + 'Rigler', + 'Schrom', + 'Pirozzi', + 'Ferre', + 'Shiley', + 'Villanova', + 'Barona', + 'Farrel', + 'Shelman', + 'Nute', + 'Rowlette', + 'Tarrance', + 'Cadorette', + 'Christenberry', + 'Deocampo', + 'Farace', + 'Fesmire', + 'Kallman', + 'Koogler', + 'Pitsch', + 'Salce', + 'Schnepf', + 'Totaro', + 'Towey', + 'Urdiales', + 'Gotschall', + 'Brunett', + 'Dier', + 'Hainsworth', + 'Seabury', + 'Cornelious', + 'Altobelli', + 'Andreozzi', + 'Bohlmann', + 'Carranco', + 'Daubenspeck', + 'Delagrange', + 'Delo', + 'Faler', + 'Ficke', + 'Hellinger', + 'Hudman', + 'Ihde', + 'Landolfi', + 'Leiner', + 'Mosman', + 'Rang', + 'Tarbet', + 'Wineman', + 'Fehrman', + 'Guinto', + 'Icenogle', + 'Tomasik', + 'Looman', + 'Iriarte', + 'Denaro', + 'Montross', + 'Piersall', + 'Lauren', + 'Lablanc', + 'Kindrick', + 'Deriso', + 'Manker', + 'Maycock', + 'Cullens', + 'Frieson', + 'Clippinger', + 'Colavito', + 'Fassbender', + 'Fennessy', + 'Granada', + 'Gugliotta', + 'Guiliano', + 'Hirschberg', + 'Kerbs', + 'Kusch', + 'Limmer', + 'Malpica', + 'Mcaloon', + 'Morken', + 'Pytel', + 'Resnik', + 'Spangle', + 'Worstell', + 'Kerkhoff', + 'Kupka', + 'Stanczyk', + 'Storlie', + 'Thurow', + 'Caetano', + 'Ernandez', + 'Males', + 'Coopersmith', + 'Everest', + 'Leander', + 'Demeritt', + 'Thomes', + 'Codner', + 'Livsey', + 'Alcoser', + 'Arico', + 'Balestrieri', + 'Cavalli', + 'Florendo', + 'Gottshall', + 'Hinesley', + 'Lafuente', + 'Landess', + 'Ornstein', + 'Pettingill', + 'Romesburg', + 'Tokunaga', + 'Wiersema', + 'Janeway', + 'Pecha', + 'Steimel', + 'Sproule', + 'Sommerfield', + 'Mirsky', + 'Staines', + 'Pu', + 'Corbit', + 'Mcelmurry', + 'Wickes', + 'Yell', + 'Mordecai', + 'Aye', + 'Boldin', + 'China', + 'Fason', + 'Thibeaux', + 'Nesby', + 'Bergevin', + 'Besecker', + 'Dohrmann', + 'Fujioka', + 'Fyock', + 'Goralski', + 'Kirschenbaum', + 'Knipper', + 'Menor', + 'Mischler', + 'Nolder', + 'Odoherty', + 'Pickerill', + 'Poremba', + 'Swantek', + 'Difabio', + 'Kulka', + 'Servais', + 'Wickizer', + 'Melecio', + 'Zeek', + 'Fruit', + 'Agnes', + 'Bar', + 'Mccarrell', + 'Hopgood', + 'Califano', + 'Cratty', + 'Dishner', + 'Gabrielli', + 'Hamacher', + 'Hinote', + 'Jakob', + 'Klinkhammer', + 'Krasinski', + 'Krysiak', + 'Pardi', + 'Petrilli', + 'Razon', + 'Reifsnyder', + 'Reisig', + 'Reller', + 'Sassano', + 'Steinhart', + 'Wrede', + 'Zevallos', + 'Coombe', + 'Quesnel', + 'Rebuck', + 'Wantz', + 'Bendele', + 'Lacomb', + 'Hagge', + 'Donelan', + 'Kempe', + 'Po', + 'Varnadoe', + 'Constantin', + 'Deon', + 'Motte', + 'Beckum', + 'Parchment', + 'Meriweather', + 'Borucki', + 'Fatima', + 'Gerkin', + 'Guglielmi', + 'Hettich', + 'Hoerr', + 'Karlsson', + 'Kenealy', + 'Paolillo', + 'Pfenning', + 'Rueger', + 'Schildt', + 'Sem', + 'Vilches', + 'Dornbusch', + 'Erdahl', + 'Kleinhenz', + 'Moneypenny', + 'Tomasko', + 'Vandevender', + 'Cromley', + 'Tun', + 'Velasques', + 'Roble', + 'Burgo', + 'Waples', + 'Mabon', + 'Benincasa', + 'Buttermore', + 'Dalbec', + 'Eikenberry', + 'Fuehrer', + 'Hossler', + 'Lepp', + 'Opheim', + 'Sarsfield', + 'Strobl', + 'Strouth', + 'Tousley', + 'Wilczek', + 'Kleppe', + 'Muraoka', + 'Wiencek', + 'Pinckard', + 'Ahsan', + 'Welder', + 'Forton', + 'Lorden', + 'Stlawrence', + 'Marina', + 'Mcquire', + 'Randleman', + 'Pates', + 'Fluitt', + 'Scotland', + 'Clerk', + 'Townsell', + 'Arrasmith', + 'Baisch', + 'Berling', + 'Busler', + 'Curtice', + 'Ebinger', + 'Fleeger', + 'Geng', + 'Goettsch', + 'Henneberry', + 'Johannesen', + 'Mcilrath', + 'Perigo', + 'Phibbs', + 'Riske', + 'Scarcella', + 'Vandyken', + 'Barstad', + 'Dicamillo', + 'Ernsberger', + 'Guebara', + 'Peetz', + 'Newcome', + 'Alterman', + 'Weik', + 'Trier', + 'Yeats', + 'Hugg', + 'Crayne', + 'Ige', + 'Coach', + 'Archuletta', + 'Bodi', + 'Cadavid', + 'Ceccarelli', + 'Derksen', + 'Deutscher', + 'Genter', + 'Gogel', + 'Gorczyca', + 'Grohs', + 'Koplin', + 'Kozloski', + 'Lillo', + 'Oplinger', + 'Pulis', + 'Renk', + 'Repka', + 'Scavo', + 'Vitagliano', + 'Weinkauf', + 'Yellin', + 'Boehlke', + 'Montecalvo', + 'Castrillo', + 'Grenon', + 'Wellen', + 'Keelan', + 'Coville', + 'Rison', + 'Jourdain', + 'Chestnutt', + 'Sharpley', + 'Acharya', + 'Bartles', + 'Burruel', + 'Capelle', + 'Contos', + 'Friedrichsen', + 'Heaberlin', + 'Hermiz', + 'Iracheta', + 'Klutts', + 'Koziel', + 'Salto', + 'Scaturro', + 'Stasik', + 'Stitzel', + 'Wiseley', + 'Paccione', + 'Squyres', + 'Leverich', + 'Holderness', + 'Elvin', + 'Morand', + 'Lizana', + 'Woolen', + 'Amarante', + 'Arn', + 'Biedermann', + 'Daddio', + 'Davilla', + 'Forti', + 'Gripp', + 'Hanzlik', + 'Iannotti', + 'Larin', + 'Nakajima', + 'Novacek', + 'Pesch', + 'Regino', + 'Rosengarten', + 'Schleif', + 'Searing', + 'Sikkema', + 'Walstrom', + 'Guastella', + 'Hemstreet', + 'Rorabaugh', + 'Weisenburger', + 'Cannan', + 'Band', + 'Fowkes', + 'Bennetts', + 'Purviance', + 'Tippin', + 'Brossard', + 'Seigle', + 'Babyak', + 'Billiter', + 'Cartner', + 'Deetz', + 'Dorow', + 'Laur', + 'Leblond', + 'Lecomte', + 'Morando', + 'Reitman', + 'Sarria', + 'Scheu', + 'Timmermann', + 'Vaneck', + 'Vangorp', + 'Windhorst', + 'Kaeser', + 'Kosloski', + 'Cappuccio', + 'Knitter', + 'Evon', + 'Garbett', + 'Wickens', + 'Ruston', + 'Fregia', + 'Ashurst', + 'Ede', + 'Strider', + 'Reaux', + 'Castellani', + 'Debus', + 'Degracia', + 'Hineman', + 'Laning', + 'Litts', + 'Losito', + 'Massi', + 'Mazzara', + 'Schriber', + 'Seyfert', + 'Strength', + 'Treptow', + 'Yuhasz', + 'Kamrath', + 'Krigbaum', + 'Marrocco', + 'Wanta', + 'Yakubov', + 'Hy', + 'Sabedra', + 'Belling', + 'Deats', + 'Mahaffy', + 'Brodrick', + 'Mcneece', + 'Madding', + 'Mottley', + 'Asp', + 'Borgerding', + 'Conrady', + 'Dagenhart', + 'Defusco', + 'Duensing', + 'Ensz', + 'Fockler', + 'Gajda', + 'Masino', + 'Minster', + 'Naso', + 'Nifong', + 'Ohlsen', + 'Prairie', + 'Rosendale', + 'Rotman', + 'Salzano', + 'Samet', + 'Takagi', + 'Vandagriff', + 'Vespa', + 'Zaragosa', + 'Howdyshell', + 'Kilburg', + 'Mellado', + 'Mollet', + 'Varone', + 'Benne', + 'Dillehay', + 'Ruther', + 'Gullick', + 'Lasure', + 'Wilkenson', + 'Lawrance', + 'Amacker', + 'Wisher', + 'Pryer', + 'Torian', + 'Aragona', + 'Dains', + 'Darrigo', + 'Escajeda', + 'Fertitta', + 'Futral', + 'Kielty', + 'Kightlinger', + 'Lanuza', + 'Marich', + 'Mcenaney', + 'Mohrman', + 'Pressnell', + 'Prestia', + 'Scullin', + 'Seidner', + 'Steigerwalt', + 'Wassell', + 'Bonavita', + 'Bourgault', + 'Sentz', + 'Viswanathan', + 'Hanchey', + 'Volpi', + 'Wilensky', + 'Mathey', + 'Mages', + 'Raimo', + 'Cozine', + 'Sprow', + 'Petties', + 'Bracht', + 'Cayabyab', + 'Comp', + 'Flamenco', + 'Friederich', + 'Hori', + 'Husmann', + 'Isidoro', + 'Ketchem', + 'Krishnamurthy', + 'Kucinski', + 'Lalani', + 'Lamacchia', + 'Lecher', + 'Morante', + 'Schrieber', + 'Sciarra', + 'Vandamme', + 'Welz', + 'Bozich', + 'Cancilla', + 'Panduro', + 'Mcglade', + 'Wasmund', + 'Riso', + 'Moronta', + 'Kemple', + 'Rocks', + 'Sainsbury', + 'Solo', + 'Harnage', + 'Sturkie', + 'Hollingworth', + 'Denley', + 'Bumpass', + 'Lovick', + 'Bribiesca', + 'Dewilde', + 'Drohan', + 'Geringer', + 'Kokoszka', + 'Kronberg', + 'Lewinski', + 'Lunney', + 'Morehart', + 'Ty', + 'Vasseur', + 'Vona', + 'Wriston', + 'Casarrubias', + 'Copsey', + 'Rochette', + 'Macwilliams', + 'Natali', + 'Milanes', + 'Rux', + 'Woodcox', + 'Bernett', + 'Bronaugh', + 'Fulwood', + 'Bhalla', + 'Depalo', + 'Hench', + 'Huckeba', + 'Kasch', + 'Kisor', + 'Marinos', + 'Nakahara', + 'Parrent', + 'Rantz', + 'Schoenbeck', + 'Schwieterman', + 'Selk', + 'Swonger', + 'Walding', + 'Nunamaker', + 'Schuchardt', + 'Leverton', + 'Fiallo', + 'Viruet', + 'Fadel', + 'Robel', + 'Calley', + 'Renton', + 'Rack', + 'Brin', + 'Cocks', + 'Mcivor', + 'Bois', + 'Demary', + 'Bason', + 'Dowlen', + 'Prophete', + 'Collymore', + 'Beisner', + 'Briand', + 'Cumberledge', + 'Curro', + 'Cutcher', + 'Daponte', + 'Eckroth', + 'Edgemon', + 'Farinella', + 'Kobe', + 'Muilenburg', + 'Osiecki', + 'Cutsinger', + 'Biggar', + 'Maciver', + 'Quesinberry', + 'Rippetoe', + 'Baswell', + 'Caven', + 'Mimbs', + 'Hurlock', + 'Cham', + 'Cypress', + 'Emile', + 'Beitel', + 'Bellavance', + 'Casada', + 'Fandel', + 'Gillentine', + 'Gorelick', + 'Kassis', + 'Klim', + 'Kohnke', + 'Lutgen', + 'Nalbandian', + 'Schepis', + 'Troester', + 'Hartje', + 'Hippensteel', + 'Kiehn', + 'Kuenzi', + 'Greenburg', + 'Boroughs', + 'Catton', + 'Adney', + 'Olivencia', + 'Mcdermitt', + 'Ashwell', + 'Leazer', + 'Poag', + 'Prevo', + 'Porcher', + 'Hugley', + 'Salone', + 'Jupiter', + 'Bratz', + 'Ehresman', + 'Fauber', + 'Filippelli', + 'Kesling', + 'Kronk', + 'Mcelhiney', + 'Mcgreal', + 'Miyasato', + 'Moomey', + 'Nicolini', + 'Osberg', + 'Ostroski', + 'Sanzo', + 'Sybert', + 'Dimichele', + 'Gerrits', + 'Shatley', + 'Weider', + 'Faraj', + 'Paules', + 'Yarberry', + 'Lege', + 'Pembroke', + 'Clipper', + 'Filmore', + 'Crichlow', + 'Blaustein', + 'Boak', + 'Canzoneri', + 'Crescenzo', + 'Ebaugh', + 'Feig', + 'Jens', + 'Knoebel', + 'Mohammadi', + 'Montour', + 'Norgren', + 'Pasquini', + 'Prost', + 'Reh', + 'Rosal', + 'Thesing', + 'Titcomb', + 'Wolinski', + 'Zeitlin', + 'Depoy', + 'Guccione', + 'Ritsema', + 'Valent', + 'Drey', + 'Govoni', + 'Lonsdale', + 'Hultz', + 'Harvie', + 'Levison', + 'Colomb', + 'Dace', + 'Cleckley', + 'Godette', + 'Brentlinger', + 'Fetrow', + 'Giuffrida', + 'Kopka', + 'Kurtzman', + 'Panameno', + 'Pannone', + 'Parzych', + 'Seipp', + 'Stobbe', + 'Thulin', + 'Torosian', + 'Trani', + 'Zietlow', + 'Montufar', + 'Stohr', + 'Woloszyn', + 'Cimini', + 'Angles', + 'Nicasio', + 'Vi', + 'Em', + 'Couchman', + 'Hobbie', + 'Bluestein', + 'Phillipson', + 'Shiels', + 'Altice', + 'Williston', + 'Kone', + 'Tadesse', + 'Abbruzzese', + 'Badders', + 'Duxbury', + 'Egeland', + 'Freyre', + 'Haen', + 'Hineline', + 'Kniss', + 'Kothe', + 'Kyker', + 'Popelka', + 'Sanjose', + 'Slaugh', + 'Wecker', + 'Wiechman', + 'Bilello', + 'Keezer', + 'Knode', + 'Longhurst', + 'Wisser', + 'Cease', + 'Contrera', + 'Berroa', + 'Aguon', + 'Pott', + 'Blitch', + 'Suares', + 'Bein', + 'Acre', + 'Ailes', + 'Tutwiler', + 'Porte', + 'Ashwood', + 'Blackson', + 'Viverette', + 'Balthazar', + 'Kidane', + 'Allegretti', + 'Corbeil', + 'Crossno', + 'Cudworth', + 'Federspiel', + 'Hamstra', + 'Kibbey', + 'Lefevers', + 'Loomer', + 'Losada', + 'Medema', + 'Palmerin', + 'Peregoy', + 'Previte', + 'Riedinger', + 'Schlossberg', + 'Wilemon', + 'Lepkowski', + 'Mcdanel', + 'Commisso', + 'Baiza', + 'Fones', + 'Divis', + 'Diedrick', + 'Grave', + 'Bonkowski', + 'Cerami', + 'Drinkwine', + 'Hauke', + 'Heun', + 'Keilman', + 'Klemmer', + 'Mella', + 'Olarte', + 'Ryall', + 'Veltman', + 'Wlodarczyk', + 'Bashor', + 'Kubinski', + 'Vanacker', + 'Prouse', + 'Perrott', + 'Berrio', + 'Mccarney', + 'Seiders', + 'Jafari', + 'Louque', + 'Melder', + 'Grazier', + 'Gabay', + 'Hardway', + 'Sadiq', + 'Sully', + 'Durrell', + 'Barno', + 'Maybin', + 'Brazile', + 'Asante', + 'Awalt', + 'Badal', + 'Cucinotta', + 'Grenfell', + 'Hartis', + 'Herbster', + 'Hesch', + 'Klosowski', + 'Overfelt', + 'Pangelinan', + 'Pflum', + 'Rozema', + 'Spivack', + 'Vallez', + 'Vetere', + 'Villamor', + 'Wedekind', + 'Bobrowski', + 'Nguyenthi', + 'Nowaczyk', + 'Vis', + 'Pownall', + 'Susan', + 'Yanni', + 'Gest', + 'Balthrop', + 'Treasure', + 'Harston', + 'Frett', + 'Buttery', + 'Chiarelli', + 'Colledge', + 'Czaplicki', + 'Fahringer', + 'Fedder', + 'Gerstenberger', + 'Gretz', + 'Hallquist', + 'Hemme', + 'Kolling', + 'Krauth', + 'Liquori', + 'Podolsky', + 'Scheirer', + 'Sehgal', + 'Selinger', + 'Wintermute', + 'Chokshi', + 'Dimarzio', + 'Santoni', + 'Wetherby', + 'Flis', + 'Comley', + 'Boyt', + 'Farrah', + 'Mario', + 'Mcquilkin', + 'Tim', + 'Cusic', + 'Enge', + 'Millage', + 'Waheed', + 'Kenan', + 'Silmon', + 'Mcconico', + 'Bougher', + 'Braly', + 'Coriell', + 'Daignault', + 'Henschen', + 'Holsomback', + 'Johal', + 'Kellams', + 'Schaumburg', + 'Stockinger', + 'Urquidi', + 'Cabanillas', + 'Lindbloom', + 'Willinger', + 'Redpath', + 'Baller', + 'Juarbe', + 'Badia', + 'Elderkin', + 'Dessert', + 'Retter', + 'Mccollam', + 'Rivette', + 'Devins', + 'Hewell', + 'Penniman', + 'Arbuthnot', + 'Cotman', + 'Tezeno', + 'Albo', + 'Beezley', + 'Can', + 'Chesler', + 'Dehne', + 'Demchak', + 'Edberg', + 'Gotham', + 'Ingels', + 'Kaercher', + 'Kwiecinski', + 'Landolt', + 'Macdonnell', + 'Malicoat', + 'Meinen', + 'Niswander', + 'Pandit', + 'Pettet', + 'Pliska', + 'Ploch', + 'Ratigan', + 'Sampsel', + 'Sick', + 'Ciampi', + 'Mctighe', + 'Riester', + 'Salvucci', + 'Tornow', + 'Vencill', + 'Racey', + 'Haroldson', + 'Finder', + 'Dennen', + 'Stano', + 'Boys', + 'Camillo', + 'Woodfield', + 'Turrell', + 'Sami', + 'Annan', + 'Yeldell', + 'Madlock', + 'Manigo', + 'Arcila', + 'Bauza', + 'Bisceglia', + 'Crouthamel', + 'Debenedetto', + 'Delude', + 'Dorta', + 'Fairburn', + 'Garciagarcia', + 'Geeslin', + 'Kazanjian', + 'Loescher', + 'Mccarl', + 'Mulqueen', + 'Pultz', + 'Shutter', + 'Spacek', + 'Yamanaka', + 'Borkholder', + 'Halko', + 'Pieroni', + 'Proano', + 'Sarkisyan', + 'Riopelle', + 'Routson', + 'Fogelman', + 'Sou', + 'Tress', + 'Altemus', + 'Bosh', + 'Laroque', + 'Hueston', + 'Latin', + 'Taitt', + 'Lymon', + 'Chadd', + 'Challis', + 'Comella', + 'Drabik', + 'Entz', + 'Hagner', + 'Knobbe', + 'Luckenbill', + 'Macphail', + 'Mogg', + 'Paustian', + 'Rimel', + 'Schilke', + 'Folkman', + 'Lemery', + 'Quinby', + 'Cliburn', + 'Rowand', + 'Wambach', + 'Gammell', + 'Nobrega', + 'Hoggan', + 'Nightengale', + 'Alison', + 'Batte', + 'Borner', + 'Hudnell', + 'Casseus', + 'Boteler', + 'Cantos', + 'Contois', + 'Coventry', + 'Dezarn', + 'Eisenbarth', + 'Hegel', + 'Jahr', + 'Joss', + 'Lober', + 'Marcks', + 'Portilla', + 'Reinders', + 'Scouten', + 'Siri', + 'Sobocinski', + 'Tesh', + 'Veno', + 'Wheeldon', + 'Yankee', + 'Wanke', + 'Wollin', + 'Longobardi', + 'Mccarson', + 'Sampsell', + 'Harrer', + 'Bakewell', + 'Mcgalliard', + 'Truluck', + 'Bremmer', + 'Lois', + 'Goody', + 'Kassim', + 'Conniff', + 'Elenes', + 'Esker', + 'Groshong', + 'Hallisey', + 'Loree', + 'Marken', + 'Molle', + 'Muntean', + 'Ozaki', + 'Roen', + 'Rumer', + 'Shorr', + 'Tanzer', + 'Varady', + 'Hillmer', + 'Macari', + 'Schuld', + 'Swartzlander', + 'Tsuji', + 'Holahan', + 'Abee', + 'Rowse', + 'Pawley', + 'Samp', + 'Shad', + 'Wintz', + 'Rainford', + 'Cellucci', + 'Cumpton', + 'Dando', + 'Dress', + 'Funari', + 'Gouker', + 'Hemberger', + 'Latz', + 'Meckes', + 'Parrinello', + 'Picardi', + 'Pilz', + 'Pretzer', + 'Schriever', + 'Sodano', + 'Stetter', + 'Storti', + 'Tiu', + 'Zimmerle', + 'Dragone', + 'Engert', + 'Fullenkamp', + 'Rockafellow', + 'Siwek', + 'Zillmer', + 'Devol', + 'Milke', + 'Taira', + 'Richner', + 'Aros', + 'Mancil', + 'Yetman', + 'Hanney', + 'Kinion', + 'Ferrand', + 'Conyer', + 'Chahal', + 'Fulfer', + 'Gurski', + 'Horseman', + 'Liebe', + 'Nyhus', + 'Pernice', + 'Pesqueira', + 'Rieker', + 'Trautmann', + 'Yellowhair', + 'Schwanz', + 'Salinger', + 'Carvell', + 'Heymann', + 'Grad', + 'Pharo', + 'Pipher', + 'Magalhaes', + 'Kissee', + 'Winthrop', + 'Leid', + 'Sledd', + 'Bladen', + 'Rahaman', + 'Holdman', + 'Goldwire', + 'Lawal', + 'Sinkfield', + 'Bryk', + 'Butkiewicz', + 'Gagen', + 'Gettle', + 'Goede', + 'Hardenbrook', + 'Heinsohn', + 'Kovalcik', + 'Needleman', + 'Obeso', + 'Parziale', + 'Schaus', + 'Wadlow', + 'Haluska', + 'Stiteler', + 'Zaruba', + 'Tschirhart', + 'Biscardi', + 'Gopal', + 'Avella', + 'Ponto', + 'Levit', + 'Trevor', + 'Pimienta', + 'Plass', + 'Guthery', + 'Cordy', + 'Tuff', + 'Zellars', + 'Altier', + 'Berges', + 'Connick', + 'Deruyter', + 'Divita', + 'Frankovich', + 'Ingenito', + 'Kosman', + 'Lantis', + 'Lovering', + 'Sortino', + 'Waage', + 'Wildrick', + 'Barberio', + 'Domin', + 'Meisels', + 'Sender', + 'Giovanni', + 'Sanguinetti', + 'Beary', + 'Helmstetter', + 'Joens', + 'Beaven', + 'Kines', + 'Surrency', + 'Sheilds', + 'Chamber', + 'Albarez', + 'Ambrocio', + 'Arrellano', + 'Berrigan', + 'Bookwalter', + 'Caravella', + 'Higbie', + 'Lotter', + 'Lougee', + 'Manganiello', + 'Nobriga', + 'Roorda', + 'Serr', + 'Squillace', + 'Tejera', + 'Tipping', + 'Wohler', + 'Carreto', + 'Deignan', + 'Luebbers', + 'Engelhard', + 'Hollenback', + 'Baldo', + 'Gearin', + 'Bia', + 'Figueras', + 'Lule', + 'Libert', + 'Florida', + 'Wyne', + 'Mccright', + 'Jacko', + 'Cawthorne', + 'Rhue', + 'Betton', + 'Cisse', + 'Arth', + 'Bendickson', + 'Cangialosi', + 'Coltharp', + 'Cubias', + 'Czarnik', + 'Erpelding', + 'Erway', + 'Heister', + 'Mergen', + 'Murrietta', + 'Nachman', + 'Nusser', + 'Ostrem', + 'Pei', + 'Pescatore', + 'Reim', + 'Shaull', + 'Spranger', + 'Uphold', + 'Yslas', + 'Heinold', + 'Lindemuth', + 'Redeker', + 'Rochin', + 'Wisehart', + 'Carsey', + 'Nocella', + 'Combe', + 'Thacher', + 'Hammad', + 'Bene', + 'Yelvington', + 'Mccrone', + 'Driessen', + 'Saxby', + 'Maull', + 'Jeune', + 'Amorim', + 'Degrazia', + 'Doege', + 'Flinchbaugh', + 'Goodreau', + 'Hanisch', + 'Hoaglund', + 'Imamura', + 'Lafler', + 'Linne', + 'Profeta', + 'Reifschneider', + 'Santaana', + 'Scaffidi', + 'Shreeve', + 'Stadelman', + 'Dippolito', + 'Pizzuti', + 'Rodenberg', + 'Schartz', + 'Reiger', + 'Solie', + 'Willen', + 'Atallah', + 'Wyers', + 'Harpel', + 'Cleckler', + 'Fobes', + 'Sniffen', + 'Pedroso', + 'Samara', + 'Malcomb', + 'Penry', + 'Stearn', + 'Seller', + 'Abeita', + 'Bilotti', + 'Brosky', + 'Clewell', + 'Fraijo', + 'Gaskey', + 'Goodfriend', + 'Mesaros', + 'Musch', + 'Nulph', + 'Obarr', + 'Roat', + 'Sabato', + 'Sauerwein', + 'Schum', + 'Silsby', + 'Weyenberg', + 'Corrente', + 'Egloff', + 'Kohrs', + 'Sammartino', + 'Thoennes', + 'Carmer', + 'Madura', + 'Shang', + 'Faxon', + 'Monell', + 'Laden', + 'Yousuf', + 'Mcgauley', + 'Salmond', + 'Berhane', + 'Abood', + 'Bondar', + 'Buehrer', + 'Capelli', + 'Gersten', + 'Hambly', + 'Haymaker', + 'Kosar', + 'Lahaie', + 'Lecrone', + 'Lippy', + 'Pohle', + 'Shimmel', + 'Viall', + 'Yother', + 'Deviney', + 'Kosiba', + 'Wiederholt', + 'Sivley', + 'Wheelis', + 'Kanipe', + 'Braz', + 'Peacher', + 'Quadri', + 'Hancox', + 'Paye', + 'Curlin', + 'Broden', + 'Mckeller', + 'Baltodano', + 'Baquero', + 'Bolek', + 'Brede', + 'Bulson', + 'Christmann', + 'Cisler', + 'Delio', + 'Duffee', + 'Duzan', + 'Kuschel', + 'Mohon', + 'Nedrow', + 'Sengupta', + 'Timpe', + 'Veeder', + 'Zollner', + 'Zummo', + 'Hribar', + 'Laredo', + 'Mcdivitt', + 'Nazari', + 'Davern', + 'Heizer', + 'Orejel', + 'Haggett', + 'Flore', + 'Soley', + 'Bardell', + 'Comegys', + 'Bessent', + 'Shaheed', + 'Brugman', + 'Choudhary', + 'Fehl', + 'Fogt', + 'Heckmann', + 'Iacobucci', + 'Klaver', + 'Lumbert', + 'Mussman', + 'Pierotti', + 'Pihl', + 'Sandrock', + 'Scritchfield', + 'Siefken', + 'Stavropoulos', + 'Thomley', + 'Zenker', + 'Enke', + 'Knoke', + 'Rung', + 'Mikita', + 'Kunkler', + 'Deskin', + 'Egnor', + 'Vader', + 'Allers', + 'Pi', + 'Sproull', + 'Peller', + 'Kendell', + 'Jinkins', + 'Iglehart', + 'Brookens', + 'Darrough', + 'Winzer', + 'Amenta', + 'Aughenbaugh', + 'Barnick', + 'Conaty', + 'Eichmann', + 'Gilday', + 'Guhl', + 'Koskela', + 'Makuch', + 'Osoria', + 'Pujols', + 'Reinsch', + 'Reiswig', + 'Rosebrock', + 'Sahli', + 'Seitzinger', + 'Shermer', + 'Vasbinder', + 'Zanghi', + 'Flahive', + 'Mieczkowski', + 'Osmundson', + 'Willmann', + 'Agramonte', + 'Aven', + 'Vanderzee', + 'Fraher', + 'Kannan', + 'Shira', + 'Zetina', + 'Gilden', + 'Hingle', + 'Boutros', + 'Scutt', + 'Foree', + 'Gillins', + 'Screen', + 'Birden', + 'Guinyard', + 'Berreth', + 'Bertini', + 'Bousman', + 'Butchko', + 'Caras', + 'Donoso', + 'Gavilanes', + 'Karow', + 'Kouri', + 'Rediger', + 'Rininger', + 'Rosecrans', + 'Toops', + 'Vigliotti', + 'Cancio', + 'Karger', + 'Milholland', + 'Thielke', + 'Amster', + 'Rosch', + 'Elks', + 'Vasco', + 'Doshier', + 'Belasco', + 'Lean', + 'Dickason', + 'Suitt', + 'Tipler', + 'Obey', + 'Crear', + 'Redic', + 'Agredano', + 'Amarillas', + 'Arnesen', + 'Celedon', + 'Clapsaddle', + 'Coveney', + 'Demorest', + 'Gleich', + 'Guenthner', + 'Haverland', + 'Jaffee', + 'Kusek', + 'Manni', + 'Mysliwiec', + 'Nakama', + 'Ngan', + 'Ohmer', + 'Romanoff', + 'Salaiz', + 'Zeiders', + 'Bartholow', + 'Budke', + 'Centanni', + 'Koppelman', + 'Liberti', + 'Gatta', + 'Lovegrove', + 'Maggs', + 'Malay', + 'Blind', + 'Kerman', + 'Frans', + 'Rendleman', + 'Tyrone', + 'Ambers', + 'Rambert', + 'Killings', + 'Balicki', + 'Bohac', + 'Brisbois', + 'Cervone', + 'Curtner', + 'Ertle', + 'Fantozzi', + 'Feger', + 'Fineman', + 'Garate', + 'Goldy', + 'Gudmundson', + 'Harcrow', + 'Herdt', + 'Klapp', + 'Mirra', + 'Radu', + 'Saiki', + 'Unser', + 'Valko', + 'Verhoff', + 'Candelas', + 'Ireton', + 'Vanhuss', + 'Wierman', + 'Zawistowski', + 'Geiman', + 'Mess', + 'Full', + 'Fuertes', + 'Derickson', + 'Mccole', + 'Godden', + 'Mizzell', + 'Sane', + 'Shirer', + 'Fickling', + 'Marcelle', + 'Tramble', + 'Cappelletti', + 'Catterton', + 'Champeau', + 'Czyzewski', + 'Dirusso', + 'Herget', + 'Heupel', + 'Hinchliffe', + 'Levitsky', + 'Maheu', + 'Nakao', + 'Petsche', + 'Pilkenton', + 'Raska', + 'Rief', + 'Scheidegger', + 'Schmeltzer', + 'Sherlin', + 'Skarda', + 'Strassburg', + 'Sundaram', + 'Wuertz', + 'Bonanni', + 'Montante', + 'Ottesen', + 'Nading', + 'Bram', + 'Debell', + 'Sia', + 'Latch', + 'Largen', + 'Nack', + 'Smillie', + 'Debold', + 'Bruer', + 'Steedley', + 'Mckinny', + 'Radney', + 'Amadio', + 'Bearman', + 'Canny', + 'Cansino', + 'Cupo', + 'Ekstrand', + 'Forrer', + 'Imm', + 'Kawano', + 'Klingaman', + 'Kovacevich', + 'Lukasiewicz', + 'Mcdermid', + 'Michon', + 'Mincks', + 'Piano', + 'Ronayne', + 'Schaum', + 'Sciandra', + 'Villafan', + 'Wolin', + 'Schrager', + 'Strawderman', + 'Hable', + 'Skees', + 'Persky', + 'Defore', + 'Edmonston', + 'Base', + 'Barrell', + 'Cressey', + 'Husser', + 'Matin', + 'Mckennon', + 'Barak', + 'Buffone', + 'Clemence', + 'Delaguila', + 'Eberwein', + 'Eichholz', + 'Faraone', + 'Herington', + 'Kempa', + 'Kenefick', + 'Lahaye', + 'Larusso', + 'Osterloh', + 'Pfluger', + 'Pomponio', + 'Shiu', + 'Stokke', + 'Trembly', + 'Weck', + 'Alire', + 'Babayan', + 'Hustad', + 'Stumph', + 'Zwiebel', + 'Wicke', + 'Brauch', + 'Milos', + 'Haggart', + 'Mento', + 'Kennamer', + 'Thibeau', + 'Winge', + 'Lords', + 'Debaun', + 'Haw', + 'Mould', + 'Elison', + 'Etling', + 'Froemming', + 'Ghazarian', + 'Justesen', + 'Kawai', + 'Lensing', + 'Lindhorst', + 'Poveda', + 'Rabadan', + 'Vigeant', + 'Warnken', + 'Bermel', + 'Manry', + 'Suppes', + 'Stauder', + 'Dayley', + 'Lose', + 'Tappe', + 'Harle', + 'Mcquain', + 'Bettes', + 'Carline', + 'Cordner', + 'Habeeb', + 'Sisney', + 'Kyer', + 'Bruins', + 'Prosise', + 'Molton', + 'Blye', + 'Mccuin', + 'Babler', + 'Caiazzo', + 'Cereceres', + 'Ciaramitaro', + 'Corkran', + 'Crawshaw', + 'Degan', + 'Dunlavy', + 'Gronewold', + 'Hartner', + 'Kornacki', + 'Lapolla', + 'Mountz', + 'Mumpower', + 'Orefice', + 'Prats', + 'Repasky', + 'Schlee', + 'Sekhon', + 'Stanich', + 'Yilmaz', + 'Desisto', + 'Hanko', + 'Nichter', + 'Risenhoover', + 'Tomasso', + 'Blome', + 'Carda', + 'Ebrahimi', + 'Devor', + 'Pappa', + 'Caravello', + 'Lunday', + 'Slim', + 'Praytor', + 'Pickerel', + 'Wahab', + 'Breeland', + 'Flowe', + 'Brodnax', + 'Monds', + 'Sylla', + 'Bekele', + 'Mozee', + 'Beechy', + 'Birky', + 'Dellavalle', + 'Delmastro', + 'Dematteis', + 'Eckberg', + 'Eisenbraun', + 'Englehardt', + 'Fazzio', + 'Gedney', + 'Hana', + 'Keeran', + 'Lallier', + 'Martenson', + 'Mcelheny', + 'Paar', + 'Suski', + 'Vossen', + 'Westergaard', + 'Westermann', + 'Wiemann', + 'Golz', + 'Lofquist', + 'Pracht', + 'Tifft', + 'Ruhnke', + 'Schnider', + 'How', + 'Knaggs', + 'Bleck', + 'Whitelock', + 'Berringer', + 'Clepper', + 'Birkhead', + 'Pilson', + 'Inabinet', + 'Gentles', + 'Respress', + 'Crumble', + 'Bandera', + 'Bartunek', + 'Buerkle', + 'Dulong', + 'Eisinger', + 'Favero', + 'Giusto', + 'Guisinger', + 'Kiddy', + 'Krisher', + 'Lounsberry', + 'Morikawa', + 'Mowdy', + 'Penaflor', + 'Picariello', + 'Quirion', + 'Scali', + 'Scheibel', + 'Schlitt', + 'Sermeno', + 'Thalman', + 'Barraclough', + 'Boshart', + 'Glatfelter', + 'Hjelm', + 'Horlacher', + 'Muratalla', + 'Schepp', + 'Fogerty', + 'Mulero', + 'Manner', + 'Creecy', + 'Leftridge', + 'Ancira', + 'Anselmi', + 'Blew', + 'Coykendall', + 'Dembinski', + 'Emmerling', + 'Fawver', + 'Giard', + 'Heinzen', + 'Kasson', + 'Linam', + 'Lofaro', + 'Magnotta', + 'Pitzen', + 'Ripa', + 'Skowronek', + 'Sliter', + 'Stauch', + 'Szczepaniak', + 'Yerian', + 'Baccam', + 'Berres', + 'Helstrom', + 'Kocurek', + 'Kostelecky', + 'Corkins', + 'Fesperman', + 'Gibble', + 'Liranzo', + 'Karan', + 'Lavely', + 'Yorks', + 'Lisenbee', + 'Jerger', + 'Cockroft', + 'Brodhead', + 'Weathersbee', + 'Salih', + 'Pore', + 'Melbourne', + 'Code', + 'Scotton', + 'Addie', + 'Snipe', + 'Cuffie', + 'Haynesworth', + 'Borawski', + 'Borchard', + 'Cacciola', + 'Dedic', + 'Grzyb', + 'Hecox', + 'Horacek', + 'Nierman', + 'Nofziger', + 'Raup', + 'Rissler', + 'Segler', + 'Serviss', + 'Soon', + 'Tesmer', + 'Campanaro', + 'Curnutte', + 'Rabold', + 'Schreyer', + 'Siebenaler', + 'Zenteno', + 'Deveney', + 'Kuchera', + 'Ruden', + 'Skaff', + 'Sciulli', + 'Howeth', + 'Hanly', + 'Gola', + 'Forkner', + 'Rosene', + 'Beeker', + 'Mazo', + 'Lambson', + 'Younis', + 'Batch', + 'Ayo', + 'Ackles', + 'Hansbrough', + 'Terrance', + 'Bacani', + 'Cracraft', + 'Ebben', + 'Falzarano', + 'Ferreras', + 'Hovatter', + 'Jaskiewicz', + 'Killpack', + 'Kwasniewski', + 'Mahnken', + 'Natera', + 'Noboa', + 'Rapson', + 'Raybuck', + 'Shima', + 'Vahle', + 'Sheeks', + 'Laker', + 'Krok', + 'Debo', + 'Oberly', + 'Chelf', + 'Catala', + 'Airey', + 'Osten', + 'Golay', + 'Eliot', + 'Lebert', + 'Swaggerty', + 'Hue', + 'Seavers', + 'Bomer', + 'Bouyer', + 'Andazola', + 'Blancarte', + 'Brierly', + 'Centofanti', + 'Dalesandro', + 'Dickstein', + 'Kalas', + 'Langman', + 'Mouradian', + 'Okubo', + 'Overbaugh', + 'Popek', + 'Runnion', + 'Sannes', + 'Schamber', + 'Silfies', + 'Sinko', + 'Sit', + 'Cerrillo', + 'Gayler', + 'Kauth', + 'Culkin', + 'Peers', + 'Spidle', + 'Ballon', + 'Rasmus', + 'Queenan', + 'Reynaud', + 'Ambroise', + 'Mcclenton', + 'Adelmann', + 'Avellino', + 'Fickle', + 'Humm', + 'Hussong', + 'Iturralde', + 'Kritzer', + 'Lautzenheiser', + 'Linsky', + 'Malarkey', + 'Mallia', + 'Marban', + 'Mccance', + 'Nawaz', + 'Pallone', + 'Rindfleisch', + 'Schmall', + 'Sowle', + 'Stanco', + 'Whelpley', + 'Winning', + 'Kopczynski', + 'Pickup', + 'Tsou', + 'Phebus', + 'Munter', + 'Sisko', + 'Fico', + 'Mosco', + 'Rani', + 'Kon', + 'Baggott', + 'Brom', + 'Valerius', + 'Fines', + 'Megee', + 'Salsberry', + 'Sheff', + 'Mourning', + 'Archambeault', + 'Bhatnagar', + 'Budreau', + 'Dieffenbach', + 'Gildner', + 'Hevener', + 'Hippler', + 'Jonker', + 'Keef', + 'Kirlin', + 'Litvak', + 'Liz', + 'Mulhearn', + 'Popal', + 'Samaha', + 'Schwartzberg', + 'Sotello', + 'Weiskopf', + 'Neitzke', + 'Strelow', + 'Nitsch', + 'Lynne', + 'Olver', + 'Bange', + 'Boot', + 'Carmine', + 'Bellville', + 'Lafitte', + 'Condry', + 'Mccotter', + 'Spruiell', + 'Moman', + 'Legree', + 'Bongard', + 'Deiss', + 'Devoy', + 'Gusler', + 'Ianni', + 'Kolker', + 'Lagomarsino', + 'Leier', + 'Marbut', + 'Minsky', + 'Okumura', + 'Roza', + 'Siemon', + 'Vescio', + 'Wirkus', + 'Huizinga', + 'Lazalde', + 'Morici', + 'Ungaro', + 'Detamore', + 'Meer', + 'Erman', + 'Sherrow', + 'Laforte', + 'Pellman', + 'Bostock', + 'Lender', + 'Peagler', + 'Rhem', + 'Brisbon', + 'Angers', + 'Azbill', + 'Busto', + 'Coggeshall', + 'Cucci', + 'Defino', + 'Duey', + 'Fecht', + 'Grudzinski', + 'Guarneri', + 'Huesca', + 'Kolbeck', + 'Mennella', + 'Nishi', + 'Ohaver', + 'Porth', + 'Romanello', + 'Serrata', + 'Thoele', + 'Thornsbury', + 'Ulsh', + 'Vanderlinde', + 'Weninger', + 'Bonaventura', + 'Cura', + 'Filley', + 'Grabinski', + 'Kloc', + 'Kulinski', + 'Maruca', + 'Dantoni', + 'Grohman', + 'Starbird', + 'Rach', + 'Asman', + 'Mosso', + 'Slaney', + 'Kall', + 'Nevil', + 'Blann', + 'Frear', + 'Mosey', + 'Wrench', + 'Balkcom', + 'Liburd', + 'Yeboah', + 'Abbatiello', + 'Creviston', + 'Dunivan', + 'Durnin', + 'Eckerman', + 'Fennimore', + 'Gohlke', + 'Holtan', + 'Kochevar', + 'Kraushaar', + 'Landino', + 'Maack', + 'Montefusco', + 'Noguchi', + 'Norgard', + 'Olafson', + 'Paulick', + 'Petropoulos', + 'Principato', + 'Qazi', + 'Sammis', + 'Sida', + 'Sorum', + 'Vandal', + 'Vertrees', + 'Votta', + 'Wiesman', + 'Fleagle', + 'Panaro', + 'Stolarski', + 'Ogborn', + 'Petta', + 'Annett', + 'Campas', + 'Xing', + 'Lorey', + 'Restaino', + 'Forgue', + 'Rourk', + 'Modisette', + 'Aris', + 'Vandunk', + 'Dia', + 'Alverio', + 'Ancell', + 'Bieler', + 'Bouwman', + 'Campillo', + 'Cebreros', + 'Chant', + 'Cira', + 'Cragun', + 'Geppert', + 'Hemmert', + 'Kister', + 'Luger', + 'Ojala', + 'Pfeifle', + 'Piechocki', + 'Saldarriaga', + 'Skoda', + 'Vangorden', + 'Winberry', + 'Zeeb', + 'Gehm', + 'Oshima', + 'Tofte', + 'Tsoi', + 'Delman', + 'Harsha', + 'Finton', + 'Triola', + 'Bingle', + 'Delise', + 'Westergard', + 'Aul', + 'Celia', + 'Headings', + 'Mates', + 'Coste', + 'Venus', + 'Shearn', + 'Adell', + 'Minnifield', + 'Baxa', + 'Cieri', + 'Coppens', + 'Delahoz', + 'Fratus', + 'Gribbins', + 'Homann', + 'Ilg', + 'Majchrzak', + 'Mcclard', + 'Podolak', + 'Pollan', + 'Savio', + 'Schloemer', + 'Sesma', + 'Tilbury', + 'Torrico', + 'Vanduyn', + 'Eisert', + 'Levalley', + 'Silversmith', + 'Zanoni', + 'Grupe', + 'Marmolejos', + 'Marsch', + 'Martes', + 'Gorley', + 'Furbush', + 'Hughlett', + 'Stcyr', + 'Faustin', + 'Bushaw', + 'Cerbone', + 'Equihua', + 'Fiorella', + 'Ganzer', + 'Gugel', + 'Hladik', + 'Kalra', + 'Leuenberger', + 'Lusardi', + 'Nogales', + 'Schifano', + 'Swalley', + 'Tangney', + 'Zakarian', + 'Arenz', + 'Bottcher', + 'Gervasio', + 'Peschel', + 'Potteiger', + 'Teruya', + 'Tullier', + 'Lenhard', + 'Brusseau', + 'Streett', + 'Loan', + 'Fahmy', + 'Broadfoot', + 'Shugars', + 'Wilshire', + 'Mohabir', + 'Baye', + 'Sean', + 'Caruth', + 'Arroyos', + 'Campise', + 'Capparelli', + 'Desanti', + 'Dunsworth', + 'Fasching', + 'Heldman', + 'Keagle', + 'Kulesa', + 'Lawrenz', + 'Monhollen', + 'Niekamp', + 'Nucci', + 'Ostman', + 'Salzmann', + 'Schemmel', + 'Selin', + 'Stencel', + 'Zilka', + 'Friesner', + 'Onstad', + 'Poovey', + 'Squillante', + 'Tullo', + 'Uriegas', + 'Vigilante', + 'Lasswell', + 'Navedo', + 'Dunnagan', + 'Pevey', + 'Santino', + 'Waldren', + 'Leven', + 'Stinnette', + 'Eleazer', + 'Ragas', + 'Cockfield', + 'Lafontant', + 'Babinski', + 'Balash', + 'Hadler', + 'Kantz', + 'Latini', + 'Lavy', + 'Mally', + 'Maurin', + 'Mifsud', + 'Miguez', + 'Muma', + 'Needle', + 'Orrico', + 'Zalazar', + 'Chinen', + 'Coluccio', + 'Gibboney', + 'Knapke', + 'Moczygemba', + 'Leonguerrero', + 'Punzalan', + 'Lortz', + 'Rosel', + 'Mcclaran', + 'Weatherhead', + 'Mcgurn', + 'Sanville', + 'Goe', + 'Phang', + 'Briskey', + 'Bluitt', + 'Hapner', + 'Lamadrid', + 'Leuthold', + 'Litchford', + 'Scaduto', + 'Smoyer', + 'Stonehouse', + 'Streng', + 'Susman', + 'Swoyer', + 'Tempesta', + 'Tiedt', + 'Politi', + 'Ruotolo', + 'Schwendeman', + 'Siegenthaler', + 'Streff', + 'Strite', + 'Kroft', + 'Lewey', + 'Silbert', + 'Frie', + 'Bentson', + 'Coin', + 'Lupe', + 'Mousa', + 'Syler', + 'Fester', + 'Tenny', + 'Surgeon', + 'Blowe', + 'Metellus', + 'Borboa', + 'Danker', + 'Ferch', + 'Fritzsche', + 'Gudiel', + 'Kilmartin', + 'Nieland', + 'Soffer', + 'Yescas', + 'Chappelear', + 'Hincapie', + 'Landowski', + 'Barfoot', + 'Hesketh', + 'Mittelman', + 'Escorcia', + 'Meetze', + 'Coral', + 'Huddleson', + 'Hoo', + 'Googe', + 'Munir', + 'Reine', + 'Studstill', + 'Swims', + 'Ganaway', + 'Daise', + 'Blando', + 'Bream', + 'Cangemi', + 'Dicola', + 'Difalco', + 'Gleim', + 'Goerke', + 'Jauch', + 'Lashway', + 'Mckinlay', + 'Mura', + 'Polsky', + 'Roehrich', + 'Schwalbach', + 'Tegtmeier', + 'Theel', + 'Wuthrich', + 'Yabut', + 'Zara', + 'Ardizzone', + 'Blasius', + 'Deramo', + 'Heffern', + 'Rickels', + 'Wojtas', + 'Bue', + 'Garant', + 'Kitagawa', + 'Vorhees', + 'Randa', + 'Seider', + 'Bi', + 'Womac', + 'Santerre', + 'Mesmer', + 'Bailly', + 'Argue', + 'Spidell', + 'Manu', + 'General', + 'Exantus', + 'Neloms', + 'Piggee', + 'Agcaoili', + 'Ambrosini', + 'Balleza', + 'Bhavsar', + 'Brandstetter', + 'Cascone', + 'Deyton', + 'Fette', + 'Gershman', + 'Hanni', + 'Hitchner', + 'Manthe', + 'Marengo', + 'Ockerman', + 'Pergola', + 'Ratterree', + 'Shober', + 'Swezey', + 'Vadala', + 'Waszak', + 'Wishard', + 'Zhuang', + 'Bobst', + 'Filippini', + 'Giardino', + 'Johanning', + 'Kloepfer', + 'Dahan', + 'Rahmani', + 'Hett', + 'Sha', + 'Spaugh', + 'Darner', + 'Dagen', + 'Gaier', + 'Musco', + 'Holling', + 'Keahey', + 'Merricks', + 'Nur', + 'Andrick', + 'Demauro', + 'Haury', + 'Hsiung', + 'Kotarski', + 'Kriesel', + 'Leleux', + 'Nazar', + 'Oganesyan', + 'Polivka', + 'Sansoucie', + 'Serafino', + 'Stammer', + 'Tamm', + 'Wachowiak', + 'Zinda', + 'Goedde', + 'Pedregon', + 'Snader', + 'Witczak', + 'Kem', + 'Prabhu', + 'Purtle', + 'Nola', + 'Om', + 'Finster', + 'Bryans', + 'Mateus', + 'Bour', + 'Santy', + 'Mola', + 'Guile', + 'Denne', + 'Bol', + 'Mont', + 'Perro', + 'Haji', + 'Swinger', + 'Mitchelle', + 'Creary', + 'Leeks', + 'Barsotti', + 'Bolender', + 'Dohner', + 'Federman', + 'Lancour', + 'Lueken', + 'Pettinger', + 'Rathmann', + 'Schiess', + 'Schulenberg', + 'Troyan', + 'Dafoe', + 'Delahunt', + 'Domagala', + 'Ganske', + 'Grasmick', + 'Guinther', + 'Hlavac', + 'Klumb', + 'Susko', + 'Vanhandel', + 'Burget', + 'Thaker', + 'Winker', + 'Castellucci', + 'Guerette', + 'Garde', + 'Busher', + 'Usery', + 'Braker', + 'Blan', + 'Goar', + 'Loiseau', + 'Anderberg', + 'Bamber', + 'Biagini', + 'Dack', + 'Groeneveld', + 'Habig', + 'Howk', + 'Kutsch', + 'Mcgloin', + 'Nevares', + 'Piedrahita', + 'Puffenbarger', + 'Racer', + 'Stanaland', + 'Turck', + 'Vanvleck', + 'Velardi', + 'Verhoeven', + 'Wernick', + 'Wherley', + 'Zamzow', + 'Binegar', + 'Kaluza', + 'Kudrna', + 'Marbach', + 'Schwichtenberg', + 'Chay', + 'Lanthier', + 'Balling', + 'Parcher', + 'Venner', + 'Nolette', + 'Quant', + 'Grierson', + 'Quest', + 'Level', + 'Birkner', + 'Evancho', + 'Grinde', + 'Horiuchi', + 'Hoselton', + 'Kuk', + 'Maiello', + 'Matuska', + 'Melito', + 'Northey', + 'Pallante', + 'Porzio', + 'Rad', + 'Rizzolo', + 'Thull', + 'Urenda', + 'Dalfonso', + 'Harbold', + 'Kemerer', + 'Knapton', + 'Meeder', + 'Ruckle', + 'Segui', + 'Behne', + 'Bamburg', + 'Galen', + 'Hallen', + 'Herandez', + 'Chittick', + 'Deshon', + 'Verrier', + 'Sorel', + 'Neylon', + 'Thatch', + 'Bayly', + 'Beever', + 'Galka', + 'Gruhn', + 'Gsell', + 'Happe', + 'Hovan', + 'Marter', + 'Matarese', + 'Mellema', + 'Ollila', + 'Schempp', + 'Serda', + 'Skenandore', + 'Stemper', + 'Toupin', + 'Vandeven', + 'Yauger', + 'Koenigs', + 'Mullendore', + 'Ouellet', + 'Sullenberger', + 'Julson', + 'Pelot', + 'Clamp', + 'Berte', + 'Beese', + 'Matkin', + 'Erie', + 'Rosenburg', + 'Reap', + 'Stelle', + 'Rayon', + 'Hoit', + 'Hollyfield', + 'Kindall', + 'Agent', + 'Glascoe', + 'Holts', + 'Wynder', + 'Balderston', + 'Bernardy', + 'Blehm', + 'Casebeer', + 'Emler', + 'Farrugia', + 'Guzzardo', + 'Johnsrud', + 'Maffeo', + 'Mccartan', + 'Redburn', + 'Reesman', + 'Savas', + 'Shamoon', + 'Shown', + 'Spinale', + 'Tabaka', + 'Wedell', + 'Armato', + 'Bassford', + 'Bungard', + 'Faerber', + 'Freet', + 'Oesterle', + 'Vandeberg', + 'Bacha', + 'Stemm', + 'Edgett', + 'Karrick', + 'Girten', + 'Orgill', + 'Meridith', + 'Cullom', + 'Hennington', + 'Minns', + 'Appleberry', + 'Abare', + 'Annen', + 'Beierle', + 'Berish', + 'Cracchiolo', + 'Dilullo', + 'Kehm', + 'Kuhne', + 'Modglin', + 'Norland', + 'Petruzzelli', + 'Schabel', + 'Stauffacher', + 'Villena', + 'Wageman', + 'Willden', + 'Faiella', + 'Mangiaracina', + 'Petralia', + 'Witwer', + 'Tropp', + 'Bores', + 'Burkel', + 'Stanifer', + 'Teele', + 'Cornick', + 'Credit', + 'Dorvil', + 'Bonillas', + 'Callinan', + 'Colleran', + 'Finer', + 'Krach', + 'Lubas', + 'Lutman', + 'Marien', + 'Mccort', + 'Merica', + 'Mies', + 'Nicotra', + 'Novosad', + 'Priem', + 'Ramakrishnan', + 'Zolman', + 'Deitsch', + 'Georgi', + 'Haberstroh', + 'Kofoed', + 'Kreischer', + 'Nazareno', + 'Norkus', + 'Steimle', + 'Fellin', + 'Ghanem', + 'Kosch', + 'Pages', + 'Balthazor', + 'Corte', + 'Hoh', + 'Shrewsberry', + 'Beharry', + 'Waight', + 'Leconte', + 'Clowney', + 'Tesfaye', + 'Andis', + 'Brosch', + 'Bruckman', + 'Carducci', + 'Erbes', + 'Ferreiro', + 'Gatten', + 'Heggen', + 'Kackley', + 'Klamm', + 'Korff', + 'Lehane', + 'Mech', + 'Montanari', + 'Pousson', + 'Soderholm', + 'Strey', + 'Upp', + 'Wahlen', + 'Cedrone', + 'Steuber', + 'Vonfeldt', + 'Deridder', + 'Shams', + 'Barnas', + 'Bake', + 'Brownrigg', + 'Donohoo', + 'Mccorry', + 'Spruce', + 'Masden', + 'Porchia', + 'Fofana', + 'Bless', + 'Caler', + 'Calva', + 'Carnero', + 'Chakraborty', + 'Clenney', + 'Dockendorf', + 'Dziak', + 'Errickson', + 'Ewoldt', + 'Klippel', + 'Krass', + 'Luebbe', + 'Parlett', + 'Paternostro', + 'Peterka', + 'Petitti', + 'Puthoff', + 'Wessman', + 'Brossman', + 'Glotfelty', + 'Grabau', + 'Kortz', + 'Sienko', + 'Yonan', + 'Fakhoury', + 'Bunney', + 'Sillas', + 'Guerry', + 'Sedwick', + 'Okey', + 'Virgo', + 'Babers', + 'Casali', + 'Chiquito', + 'Correnti', + 'Doverspike', + 'Fryberger', + 'Golas', + 'Golob', + 'Hufstetler', + 'Inoa', + 'Lasser', + 'Nesheim', + 'Peveto', + 'Reckner', + 'Rydzewski', + 'Shartzer', + 'Smouse', + 'Tipple', + 'Wantland', + 'Wolfert', + 'Yordy', + 'Zuleta', + 'Heimerl', + 'Mccarren', + 'Cabeza', + 'Neice', + 'Kassem', + 'Hodgen', + 'Charrier', + 'Duggar', + 'Blacksmith', + 'Cush', + 'Trunnell', + 'Laventure', + 'Salahuddin', + 'Batalla', + 'Brahmbhatt', + 'Breslow', + 'Cua', + 'Deatley', + 'Digrazia', + 'Divirgilio', + 'Falin', + 'Freiberger', + 'Gladish', + 'Holyoak', + 'Lazos', + 'Loader', + 'Mcclafferty', + 'Meloni', + 'Muhr', + 'Salzwedel', + 'Schaab', + 'Shehadeh', + 'Suresh', + 'Verdusco', + 'Younglove', + 'Damman', + 'Fulco', + 'Neikirk', + 'Laver', + 'Biro', + 'Shill', + 'Labarr', + 'Kari', + 'Mcclory', + 'Torelli', + 'Knock', + 'Dormer', + 'Papin', + 'Stoneham', + 'Weathington', + 'Albus', + 'Andel', + 'Banville', + 'Cassens', + 'Chalifoux', + 'Dellaquila', + 'Depauw', + 'Deschene', + 'Genung', + 'Greider', + 'Luhman', + 'Mastropietro', + 'Mignogna', + 'Pisarski', + 'Terrien', + 'Thomure', + 'Tornabene', + 'Beheler', + 'Chimento', + 'Engelbert', + 'Gambone', + 'Goettl', + 'Jasperson', + 'Kovalenko', + 'Infinger', + 'Timbs', + 'Dasgupta', + 'Purdon', + 'Velie', + 'Eland', + 'Ankrum', + 'Narain', + 'Mcfarling', + 'Creagh', + 'Bunyan', + 'Rattigan', + 'Reddix', + 'Aumann', + 'Beilfuss', + 'Bogosian', + 'Bramel', + 'Burlingham', + 'Cruzan', + 'Demel', + 'Dorff', + 'Figley', + 'Friesz', + 'Huffstutler', + 'Mcdaris', + 'Meinecke', + 'Moench', + 'Newville', + 'Normile', + 'Pfund', + 'Pilar', + 'Seckman', + 'Szoke', + 'Zyla', + 'Freilich', + 'Hammerle', + 'Kopel', + 'Liskey', + 'Mesina', + 'Schlicher', + 'Dalen', + 'Bettin', + 'Malanga', + 'Dern', + 'Tuckey', + 'Warder', + 'Harren', + 'Siner', + 'Mahdi', + 'Ahmann', + 'Allor', + 'Claywell', + 'Corkill', + 'Follansbee', + 'Iseman', + 'Lawter', + 'Myslinski', + 'Sauser', + 'Tornatore', + 'Bhasin', + 'Governale', + 'Karstens', + 'Klocek', + 'Stempien', + 'Petrino', + 'Kohlmeier', + 'Igou', + 'Sari', + 'Mareno', + 'Bouche', + 'Romas', + 'Urey', + 'Sprott', + 'Ponzo', + 'Nevills', + 'Affolter', + 'Alleva', + 'Allgaier', + 'Azbell', + 'Branagan', + 'Fiebig', + 'Geremia', + 'Grabert', + 'Grahl', + 'Gruwell', + 'Koebel', + 'Krauter', + 'Kuhnert', + 'Kuperman', + 'Laverdiere', + 'Leuck', + 'Masella', + 'Mierzejewski', + 'Platek', + 'Samaan', + 'Selsor', + 'Vickroy', + 'Whitenack', + 'Zanella', + 'Cavagnaro', + 'Galioto', + 'Schoeneman', + 'Zanotti', + 'Bort', + 'Alpaugh', + 'Culverhouse', + 'Perona', + 'Wheelwright', + 'Amber', + 'Bradner', + 'Sedberry', + 'Goethe', + 'Swygert', + 'Nisbett', + 'Harts', + 'Pendelton', + 'Keita', + 'Addair', + 'Anania', + 'Armagost', + 'Brumett', + 'Butala', + 'Celmer', + 'Forquer', + 'Hagadorn', + 'Jalomo', + 'Koranda', + 'Lemmond', + 'Liske', + 'Mcglamery', + 'Ramiro', + 'Tickner', + 'Toso', + 'Tosti', + 'Beerbower', + 'Bichler', + 'Buege', + 'Cadotte', + 'Chiong', + 'Romberger', + 'Mandarino', + 'Deter', + 'Wallack', + 'Bligh', + 'Harer', + 'Terral', + 'Hobert', + 'Doren', + 'Affleck', + 'Marquess', + 'Lewton', + 'Covel', + 'Reff', + 'Gowins', + 'Claybrooks', + 'Artiles', + 'Brunelli', + 'Campusano', + 'Deshaies', + 'Elpers', + 'Fait', + 'Heathcote', + 'Katayama', + 'Landreneau', + 'Nardelli', + 'Padovano', + 'Pendry', + 'Santillano', + 'Ubaldo', + 'Wurz', + 'Bathke', + 'Fillers', + 'Reitano', + 'Patrone', + 'Mountford', + 'Farran', + 'Burdo', + 'Danish', + 'Windell', + 'Amrine', + 'Pilgreen', + 'Pross', + 'Bowery', + 'Girdner', + 'Stockley', + 'Chisom', + 'Bigos', + 'Cavallero', + 'Choma', + 'Chorba', + 'Doubek', + 'Eynon', + 'Fitzmorris', + 'Gergely', + 'Hilsabeck', + 'Hime', + 'Kafer', + 'Kilday', + 'Lairson', + 'Mccanless', + 'Meenan', + 'Mossburg', + 'Muscato', + 'Raap', + 'Ramp', + 'Reali', + 'Reinard', + 'Rivadeneira', + 'Schwenn', + 'Serbin', + 'Soeder', + 'Wagle', + 'Jablonowski', + 'Vanni', + 'Grapes', + 'Hilleary', + 'Mondor', + 'Natalie', + 'Seat', + 'Heming', + 'Waide', + 'Haverly', + 'Eva', + 'Marshman', + 'Mais', + 'Portlock', + 'Scoby', + 'Sharps', + 'Buday', + 'Bumbalough', + 'Burback', + 'Carano', + 'Eustis', + 'Flaim', + 'Fraticelli', + 'Grimme', + 'Heape', + 'Hoaglin', + 'Kreuser', + 'Odgers', + 'Pastorius', + 'Pavek', + 'Rogoff', + 'Skorupski', + 'Stene', + 'Tomasino', + 'Varble', + 'Vasek', + 'Woolums', + 'Arcaro', + 'Graley', + 'Larkey', + 'Ortlieb', + 'Piccone', + 'Verhey', + 'Inch', + 'Laroe', + 'Brockmeier', + 'Familia', + 'Soll', + 'Duplechin', + 'Blevens', + 'Gell', + 'Hipkins', + 'Kleinpeter', + 'Swindall', + 'Sabir', + 'Kinloch', + 'Muldrew', + 'Clausell', + 'Bouch', + 'Casciano', + 'Dewhirst', + 'Draney', + 'Fourman', + 'Fuente', + 'Ganci', + 'Gentzler', + 'Gerhold', + 'Ingoglia', + 'Jerabek', + 'Keisling', + 'Larivee', + 'Negro', + 'Pelchat', + 'Quilty', + 'Reinig', + 'Rubeck', + 'Rudick', + 'Rulli', + 'Spagnoli', + 'Wiltsie', + 'Vitolo', + 'Neuhauser', + 'Khurana', + 'Vint', + 'Kant', + 'Nead', + 'Deroy', + 'Ransford', + 'Stromer', + 'Buley', + 'Bloxom', + 'Rieves', + 'Bastos', + 'Deckman', + 'Duenes', + 'Hessling', + 'Kresse', + 'Langdale', + 'Penberthy', + 'Polyak', + 'Sagun', + 'Salehi', + 'Sas', + 'Soja', + 'Spieth', + 'Verhulst', + 'Walen', + 'Woodling', + 'Acierno', + 'Bergsma', + 'Biskup', + 'Buonomo', + 'Gores', + 'Koffman', + 'Redder', + 'Ishak', + 'Billow', + 'Ratledge', + 'Widder', + 'Margerum', + 'Bussing', + 'Caccamo', + 'Carozza', + 'Cwik', + 'Forner', + 'Goeden', + 'Greninger', + 'Hartenstein', + 'Hermida', + 'Krutz', + 'Kubes', + 'Kulow', + 'Lynott', + 'Mank', + 'Meinders', + 'Mikrut', + 'Moots', + 'Patek', + 'Pogorzelski', + 'Reinstein', + 'Ruiter', + 'Rupard', + 'Salvia', + 'Sissom', + 'Sligar', + 'Spendlove', + 'Vian', + 'Wissing', + 'Witucki', + 'Brossart', + 'Warhurst', + 'Staron', + 'Gilly', + 'Borck', + 'Mccarn', + 'Stanbery', + 'Aydelotte', + 'Etters', + 'Rho', + 'Menzer', + 'Knoble', + 'Luallen', + 'Meda', + 'Myre', + 'Nevils', + 'Seide', + 'Rouser', + 'Bernas', + 'Bressette', + 'Dohn', + 'Domina', + 'Filion', + 'Fossen', + 'Grunder', + 'Hofland', + 'Larranaga', + 'Launius', + 'Lento', + 'Mohrmann', + 'Papenfuss', + 'Polcyn', + 'Pollina', + 'Reinheimer', + 'Rueb', + 'Sacher', + 'Sauseda', + 'Whitwell', + 'Caspers', + 'Dejager', + 'Kastelic', + 'Kildow', + 'Sappenfield', + 'Schultes', + 'Tucciarone', + 'Gogan', + 'Sarti', + 'Percle', + 'Cagney', + 'Wasley', + 'Getts', + 'Sahm', + 'Brandle', + 'Osbon', + 'Febres', + 'Billett', + 'Pall', + 'Spearing', + 'Thursby', + 'Junious', + 'Allenbaugh', + 'Calamia', + 'Cregan', + 'Hostettler', + 'Leete', + 'Pirrone', + 'Ploeger', + 'Revak', + 'Sarlo', + 'Sayavong', + 'Schlichter', + 'Shonkwiler', + 'Soots', + 'Spak', + 'Thien', + 'Torgeson', + 'Urbanczyk', + 'Vredenburg', + 'Wormuth', + 'Yankovich', + 'Badertscher', + 'Holewinski', + 'Kalinoski', + 'Kwasny', + 'Neidert', + 'Remmel', + 'Uram', + 'Zettlemoyer', + 'Sanna', + 'Walthers', + 'Kinkaid', + 'Rummage', + 'Vane', + 'Morgen', + 'Stum', + 'Ainsley', + 'Mckelvie', + 'Barbin', + 'Shariff', + 'Blanchett', + 'Mayon', + 'Broadie', + 'Millien', + 'Azzarello', + 'Bocock', + 'Bohlander', + 'Brennecke', + 'Daman', + 'Dixit', + 'Goth', + 'Kocur', + 'Koslow', + 'Loncar', + 'Narez', + 'Oleksy', + 'Ouderkirk', + 'Rathe', + 'Sandmann', + 'Scarpino', + 'Siegman', + 'Soloway', + 'Tomeo', + 'Vantuyl', + 'Benesch', + 'Doornbos', + 'Gisler', + 'Nistler', + 'Pelzel', + 'Piecuch', + 'Schweiss', + 'Zieba', + 'Domangue', + 'Curti', + 'Iams', + 'Viger', + 'Sandefer', + 'Maybury', + 'Haneline', + 'Shappell', + 'Charlier', + 'Belardo', + 'Lynk', + 'Ocain', + 'Ismael', + 'Blacksher', + 'Lesesne', + 'Blash', + 'Fantroy', + 'Bucciarelli', + 'Deruiter', + 'Fetner', + 'Filla', + 'Frontera', + 'Furlan', + 'Goepfert', + 'Gorsline', + 'Gugino', + 'Kleis', + 'Kriger', + 'Lebarron', + 'Lesnick', + 'Losano', + 'Macquarrie', + 'Marczak', + 'Mazariego', + 'Moraes', + 'Murano', + 'Myint', + 'Philley', + 'Ruffalo', + 'Salyards', + 'Swab', + 'Trester', + 'Vlcek', + 'Abramo', + 'Kaczmarski', + 'Mastronardi', + 'Lafont', + 'Tomerlin', + 'Mchan', + 'Blanda', + 'Deandrade', + 'Klien', + 'Meno', + 'Maia', + 'Durall', + 'Lansdowne', + 'Cones', + 'Adley', + 'Taffe', + 'Ikard', + 'Sylve', + 'Bartok', + 'Farler', + 'Farnworth', + 'Gookin', + 'Guijarro', + 'Hazan', + 'Hosterman', + 'Klees', + 'Knust', + 'Leadingham', + 'Lefeber', + 'Maisch', + 'Muchmore', + 'Pini', + 'Polinsky', + 'Quakenbush', + 'Rought', + 'Ruta', + 'Tingen', + 'Urness', + 'Valade', + 'Wadle', + 'Hietala', + 'Hockenbury', + 'Ivanoff', + 'Mcevers', + 'Miyazaki', + 'Druckenmiller', + 'Neisler', + 'Vroom', + 'Berland', + 'Rizor', + 'Caris', + 'Jenison', + 'Folmer', + 'Si', + 'Pulling', + 'Houge', + 'Snuggs', + 'Enis', + 'Peeks', + 'Stacker', + 'Destin', + 'Ojo', + 'Barraco', + 'Childree', + 'Ciszewski', + 'Dicenzo', + 'Gowing', + 'Granquist', + 'Kapinos', + 'Khalili', + 'Kienitz', + 'Konrath', + 'Kosa', + 'Schilz', + 'Sealock', + 'Soucek', + 'Stefanko', + 'Trow', + 'Udy', + 'Fricano', + 'Hunnewell', + 'Sieler', + 'Stranahan', + 'Thammavongsa', + 'Zettel', + 'Cutrell', + 'Balter', + 'Clavel', + 'Thibert', + 'Ondo', + 'Senna', + 'Kun', + 'Maximo', + 'Wares', + 'Caldeira', + 'Furgerson', + 'Franklyn', + 'Christophe', + 'Bady', + 'Blanken', + 'Boike', + 'Cuen', + 'Davidian', + 'Glauser', + 'Gleave', + 'Guzy', + 'Halleck', + 'Kempfer', + 'Kenkel', + 'Kloth', + 'Knable', + 'Mcenery', + 'Pizzolato', + 'Schryver', + 'Seminara', + 'Shenoy', + 'Somera', + 'Stroop', + 'Weirick', + 'Yatsko', + 'Evanko', + 'Koegel', + 'Lastinger', + 'Schrenk', + 'Vitullo', + 'Holste', + 'Susa', + 'Pedley', + 'Cove', + 'Levett', + 'Gillyard', + 'Boeding', + 'Delpozo', + 'Denoyer', + 'Farese', + 'Floro', + 'Gavina', + 'Hargus', + 'Kisiel', + 'Konig', + 'Krotz', + 'Lundblad', + 'Masoner', + 'Mumper', + 'Nolf', + 'Sandgren', + 'Schussler', + 'Shallcross', + 'Singhal', + 'Standen', + 'Teta', + 'Vacanti', + 'Yokota', + 'Borski', + 'Filice', + 'Frankum', + 'Kleinsmith', + 'Plauche', + 'Spohr', + 'Goya', + 'Rosensteel', + 'Srey', + 'Touhey', + 'Launer', + 'Dome', + 'Mossey', + 'Mclay', + 'Sturgess', + 'Demond', + 'Buren', + 'Millin', + 'Riddles', + 'Arps', + 'Dugar', + 'Carradine', + 'Brasseur', + 'Burchill', + 'Champoux', + 'Chojnowski', + 'Cyphert', + 'Devincentis', + 'Donze', + 'Gaspari', + 'Harshberger', + 'Merchan', + 'Mulgrew', + 'Parma', + 'Pasqua', + 'Pierpoint', + 'Rozeboom', + 'Rumery', + 'Stahle', + 'Stierwalt', + 'Swander', + 'Tiegs', + 'Trabucco', + 'Withington', + 'Frericks', + 'Kilman', + 'Locastro', + 'Samonte', + 'Sanko', + 'Wisman', + 'Flecha', + 'Coplan', + 'Zafra', + 'Art', + 'Maxam', + 'Cavaness', + 'Willi', + 'Vanliew', + 'Fresh', + 'Bauserman', + 'Bergemann', + 'Buchler', + 'Curbow', + 'Dimascio', + 'Einstein', + 'Favila', + 'Galeno', + 'Granat', + 'Halteman', + 'Janczak', + 'Janicek', + 'Jundt', + 'Karren', + 'Modesitt', + 'Provance', + 'Reasons', + 'Riveron', + 'Salts', + 'Salvino', + 'Sawhney', + 'Shallenberger', + 'Sirk', + 'Tylka', + 'Baumler', + 'Mcmenamy', + 'Territo', + 'Thackeray', + 'Much', + 'Papageorge', + 'Rynders', + 'Bacigalupo', + 'Fulwider', + 'Hendricksen', + 'Lepre', + 'Mangel', + 'Dering', + 'Soda', + 'Bazar', + 'Dinning', + 'Portera', + 'Schatzman', + 'Kernodle', + 'Bashford', + 'Ferrebee', + 'Cortner', + 'Sanker', + 'Livings', + 'Jemmott', + 'Arzaga', + 'Cihak', + 'Cobarrubias', + 'Coey', + 'Coutinho', + 'Deneau', + 'Droll', + 'Hickel', + 'Hillmann', + 'Kitto', + 'Lefebre', + 'Lev', + 'Mato', + 'Mcomber', + 'Norlin', + 'Renstrom', + 'Rhyner', + 'Sacca', + 'Sangha', + 'Sutor', + 'Dwire', + 'Huyser', + 'Kressin', + 'Moilanen', + 'Picado', + 'Schmidlin', + 'Albor', + 'Zaldana', + 'Failor', + 'Dubberly', + 'Youse', + 'Mohiuddin', + 'Shiel', + 'Loran', + 'Hamme', + 'Castine', + 'Lanum', + 'Mcelderry', + 'Riggsbee', + 'Madkins', + 'Abts', + 'Bekker', + 'Boccio', + 'Florin', + 'Lienemann', + 'Madara', + 'Manganello', + 'Mcfetridge', + 'Medsker', + 'Minish', + 'Roberg', + 'Sajdak', + 'Schwall', + 'Sedivy', + 'Suto', + 'Wieberg', + 'Catherman', + 'Ficker', + 'Leckrone', + 'Lieder', + 'Rodak', + 'Tomek', + 'Everard', + 'Spong', + 'Glacken', + 'Polka', + 'Aley', + 'Farro', + 'Stanwood', + 'Petter', + 'Desrosier', + 'Kerl', + 'Goslee', + 'Burston', + 'Pennywell', + 'Birchard', + 'Federer', + 'Flicker', + 'Frangos', + 'Korhonen', + 'Kozikowski', + 'Kyger', + 'Mccoskey', + 'Standing', + 'Terada', + 'Trierweiler', + 'Trupiano', + 'Urbanowicz', + 'Viegas', + 'Ybarbo', + 'Brinlee', + 'Daddona', + 'Deisher', + 'Schwieger', + 'Farless', + 'Slaght', + 'Jarvie', + 'Hunkins', + 'Barrack', + 'Bisset', + 'Bruley', + 'Molen', + 'Milas', + 'Matts', + 'Wickware', + 'Timbers', + 'Minus', + 'Kennebrew', + 'Boorman', + 'Faughn', + 'Feight', + 'Githens', + 'Hazelrigg', + 'Hutzell', + 'Klang', + 'Kogler', + 'Lechtenberg', + 'Malachowski', + 'Orsburn', + 'Retz', + 'Saban', + 'Tak', + 'Underdahl', + 'Veldman', + 'Virnig', + 'Wanat', + 'Achord', + 'Drenth', + 'Heibel', + 'Hendee', + 'Raiche', + 'Saunier', + 'Wertheim', + 'Forand', + 'Stathis', + 'Raider', + 'Cassaro', + 'Cly', + 'Hagey', + 'Moad', + 'Rhody', + 'Fogler', + 'Hellen', + 'Sweezy', + 'Farid', + 'Suddreth', + 'Kenneth', + 'Pindell', + 'Corney', + 'Monsanto', + 'Laye', + 'Lingard', + 'Armwood', + 'Asif', + 'Axley', + 'Barkan', + 'Bittel', + 'Boesen', + 'Camilli', + 'Champa', + 'Dauenhauer', + 'Ehrmann', + 'Gangl', + 'Gatrell', + 'Gehret', + 'Hankel', + 'Kalbach', + 'Kessell', + 'Khatoon', + 'Lanese', + 'Manco', + 'Masteller', + 'Pruner', + 'Remmert', + 'Valasek', + 'Vater', + 'Yurick', + 'Zavalza', + 'Biesecker', + 'Frankenberg', + 'Hovorka', + 'Poissant', + 'Neises', + 'Moog', + 'Hadad', + 'Wittenburg', + 'Devere', + 'Hynds', + 'Sparkes', + 'Brailey', + 'Addo', + 'Accetta', + 'Altschuler', + 'Amescua', + 'Corredor', + 'Didonna', + 'Jencks', + 'Keady', + 'Keidel', + 'Mancebo', + 'Matusiak', + 'Rakoczy', + 'Reamy', + 'Sardella', + 'Slotnick', + 'Fotheringham', + 'Gettman', + 'Kunzler', + 'Manganaro', + 'Manygoats', + 'Huelskamp', + 'Newsham', + 'Kohen', + 'Cong', + 'Goulden', + 'Timmers', + 'Aderhold', + 'Shinall', + 'Cowser', + 'Uzzle', + 'Harps', + 'Balster', + 'Baringer', + 'Bechler', + 'Billick', + 'Chenard', + 'Ditta', + 'Fiallos', + 'Kampe', + 'Kretzschmar', + 'Manukyan', + 'Mcbreen', + 'Mcmanigal', + 'Miko', + 'Mol', + 'Orrego', + 'Penalosa', + 'Ronco', + 'Thum', + 'Tupa', + 'Vittitow', + 'Wierzba', + 'Gavitt', + 'Hampe', + 'Kowalkowski', + 'Neuroth', + 'Sterkel', + 'Herling', + 'Boldman', + 'Camus', + 'Drier', + 'Arcia', + 'Feagans', + 'Thompsen', + 'Maka', + 'Villalona', + 'Bonito', + 'Buist', + 'Dato', + 'Yankey', + 'Daluz', + 'Hollands', + 'Durio', + 'Bradly', + 'Daffin', + 'Chhabra', + 'Dettling', + 'Dolinger', + 'Flenniken', + 'Henrichsen', + 'Laduca', + 'Lashomb', + 'Leick', + 'Luchini', + 'Mcmanaman', + 'Minkoff', + 'Nobbe', + 'Oyster', + 'Quintela', + 'Robar', + 'Sakurai', + 'Solak', + 'Stolt', + 'Taddei', + 'Puopolo', + 'Schwarzkopf', + 'Stango', + 'Mcparland', + 'Schembri', + 'Standefer', + 'Dayan', + 'Sculley', + 'Bhuiyan', + 'Delauder', + 'Harrity', + 'Bree', + 'Haste', + 'Mcbay', + 'Garmany', + 'Maison', + 'Common', + 'Hanton', + 'Aigner', + 'Aliaga', + 'Boeve', + 'Cromie', + 'Demick', + 'Filipowicz', + 'Frickey', + 'Garrigus', + 'Heindl', + 'Hilmer', + 'Homeyer', + 'Lanterman', + 'Larch', + 'Masci', + 'Minami', + 'Palmiter', + 'Rufener', + 'Saal', + 'Sarmento', + 'Seewald', + 'Sestito', + 'Somarriba', + 'Sparano', + 'Vorce', + 'Wombles', + 'Zarr', + 'Antonson', + 'Bruzzese', + 'Chillemi', + 'Dannunzio', + 'Hogrefe', + 'Mastandrea', + 'Moynahan', + 'Wangerin', + 'Wedeking', + 'Ziobro', + 'Flegel', + 'Axsom', + 'Buzby', + 'Slowey', + 'Cuebas', + 'App', + 'Dar', + 'Robers', + 'Elting', + 'Demus', + 'Finkley', + 'Taborn', + 'Balogun', + 'Binstock', + 'Gebel', + 'Hinnenkamp', + 'Kosta', + 'Lamphear', + 'Linhares', + 'Luzader', + 'Mcconathy', + 'Motl', + 'Mroczkowski', + 'Reznicek', + 'Rieken', + 'Sadlowski', + 'Schlink', + 'Snuffer', + 'Tep', + 'Vaske', + 'Whisner', + 'Amesquita', + 'Demler', + 'Macdonell', + 'Rajala', + 'Sandate', + 'Kolk', + 'Bickerton', + 'Dugal', + 'Kirtland', + 'Neilan', + 'Doughman', + 'Crye', + 'Depena', + 'Quire', + 'Hafeez', + 'Rosse', + 'Devon', + 'Deboe', + 'Kitchings', + 'Blackett', + 'Acey', + 'Mcculler', + 'Obie', + 'Pleas', + 'Lurry', + 'Abid', + 'Bierlein', + 'Boisclair', + 'Cabanilla', + 'Celano', + 'Conrow', + 'Deeley', + 'Frankhouser', + 'Janowiak', + 'Jarchow', + 'Mcnicol', + 'Peixoto', + 'Pompeo', + 'Reitmeyer', + 'Scalera', + 'Schnorr', + 'Sideris', + 'Solesbee', + 'Stejskal', + 'Strole', + 'Tosto', + 'Wenke', + 'Dombek', + 'Gottschall', + 'Halbur', + 'Kuchler', + 'Kuyper', + 'Wruck', + 'Lorenc', + 'Search', + 'Chohan', + 'Monda', + 'Clowes', + 'Farson', + 'Rhoad', + 'Clavin', + 'Ramus', + 'Hayley', + 'Dolley', + 'Menton', + 'Dejarnett', + 'Challenger', + 'Branner', + 'Shed', + 'Dada', + 'Flewellen', + 'Volcy', + 'Allphin', + 'Barberena', + 'Bencivenga', + 'Bienkowski', + 'Bossi', + 'Corsini', + 'Dardis', + 'Falconi', + 'Fitzhenry', + 'Gaglione', + 'Handlin', + 'Kainz', + 'Lorge', + 'Nase', + 'Pavich', + 'Perelman', + 'Shanafelt', + 'Towsley', + 'Weill', + 'Zollars', + 'Appelt', + 'Cannizzo', + 'Carrubba', + 'Detar', + 'Dobrzynski', + 'Hashman', + 'Maassen', + 'Mccullagh', + 'Rettinger', + 'Roediger', + 'Rybolt', + 'Savoca', + 'Wortmann', + 'Boria', + 'Mairs', + 'Stream', + 'Larmore', + 'Sama', + 'Graden', + 'Hollinshead', + 'Mandy', + 'Gidney', + 'Demming', + 'Alexandra', + 'Caleb', + 'Abdullahi', + 'Cabal', + 'Dikeman', + 'Ellenbecker', + 'Fosnaugh', + 'Funck', + 'Heidorn', + 'Housden', + 'Ilic', + 'Illescas', + 'Kohlmann', + 'Lagman', + 'Larez', + 'Penafiel', + 'Pense', + 'Ragonese', + 'Reitan', + 'Shetterly', + 'Trapasso', + 'Zank', + 'Zecca', + 'Grisanti', + 'Hemker', + 'Mascolo', + 'Muhlenkamp', + 'Riemann', + 'Schindel', + 'Uncapher', + 'Zelman', + 'Koper', + 'Byrn', + 'Calzadilla', + 'Dilly', + 'Beiser', + 'Maller', + 'Bagg', + 'Winnick', + 'Sillman', + 'Bilton', + 'Esmond', + 'Sconyers', + 'Lemma', + 'Geralds', + 'Lazare', + 'Threats', + 'Accurso', + 'Boitnott', + 'Calcagni', + 'Chavera', + 'Corda', + 'Delisio', + 'Demont', + 'Eichel', + 'Faulds', + 'Ficek', + 'Gappa', + 'Graci', + 'Hammaker', + 'Heino', + 'Katcher', + 'Keslar', + 'Larsh', + 'Lashua', + 'Leising', + 'Magri', + 'Manbeck', + 'Mcwatters', + 'Mixer', + 'Moder', + 'Noori', + 'Pallo', + 'Pfingsten', + 'Plett', + 'Prehn', + 'Reyburn', + 'Savini', + 'Sebek', + 'Thang', + 'Lemberg', + 'Xiang', + 'Stiegler', + 'Groman', + 'Bowlen', + 'Grignon', + 'Morren', + 'Dini', + 'Mcaulay', + 'Ngu', + 'Bethell', + 'Warring', + 'Belyeu', + 'Ramcharan', + 'Mcjunkins', + 'Alms', + 'Ayub', + 'Brem', + 'Dresen', + 'Flori', + 'Geesaman', + 'Haugan', + 'Heppler', + 'Hermance', + 'Korinek', + 'Lograsso', + 'Madriaga', + 'Milbrath', + 'Radwan', + 'Riemersma', + 'Rivett', + 'Roggenbuck', + 'Stefanick', + 'Storment', + 'Ziegenfuss', + 'Blackhurst', + 'Daquila', + 'Maruska', + 'Rybka', + 'Schweer', + 'Tandon', + 'Hersman', + 'Galster', + 'Lemp', + 'Hantz', + 'Enderson', + 'Marchal', + 'Conly', + 'Bali', + 'Canaan', + 'Anstead', + 'Savary', + 'Andy', + 'Tisdell', + 'Livas', + 'Grinage', + 'Afanador', + 'Alviso', + 'Aracena', + 'Denio', + 'Dentremont', + 'Eldreth', + 'Gravois', + 'Huebsch', + 'Kalbfleisch', + 'Labree', + 'Mones', + 'Reitsma', + 'Schnapp', + 'Seek', + 'Shuping', + 'Tortorice', + 'Viscarra', + 'Wahlers', + 'Wittner', + 'Yake', + 'Zamani', + 'Carriveau', + 'Delage', + 'Gargan', + 'Goldade', + 'Golec', + 'Lapage', + 'Meinhart', + 'Mierzwa', + 'Riggenbach', + 'Schloesser', + 'Sedam', + 'Winkels', + 'Woldt', + 'Beckers', + 'Teach', + 'Feagan', + 'Booe', + 'Slates', + 'Bears', + 'Market', + 'Moone', + 'Verdun', + 'Ibe', + 'Jeudy', + 'Agudo', + 'Brisendine', + 'Casillo', + 'Chalupa', + 'Daversa', + 'Fissel', + 'Fleites', + 'Giarratano', + 'Glackin', + 'Granzow', + 'Hawver', + 'Hayashida', + 'Hovermale', + 'Huaman', + 'Jezek', + 'Lansdell', + 'Loughery', + 'Niedzielski', + 'Orellano', + 'Pebley', + 'Rojek', + 'Tomic', + 'Yellen', + 'Zerkle', + 'Boettner', + 'Decook', + 'Digilio', + 'Dinsdale', + 'Germer', + 'Kleve', + 'Marcinek', + 'Mendicino', + 'Pehl', + 'Revoir', + 'Osmun', + 'Bahner', + 'Shone', + 'Howald', + 'Kanode', + 'Amari', + 'Enix', + 'Levene', + 'Joffrion', + 'Lenis', + 'Carmicheal', + 'Njoku', + 'Coffel', + 'Ditter', + 'Grupp', + 'Kabel', + 'Kanzler', + 'Konop', + 'Lupi', + 'Mautz', + 'Mccahill', + 'Perella', + 'Perich', + 'Rion', + 'Ruvolo', + 'Torio', + 'Vipperman', + 'Bentivegna', + 'Formanek', + 'Smet', + 'Tarquinio', + 'Wesche', + 'Dearinger', + 'Makara', + 'Duba', + 'Iser', + 'Nicklow', + 'Wignall', + 'Wanger', + 'Goda', + 'Huckstep', + 'Basse', + 'Debruhl', + 'Hainey', + 'Damour', + 'Ebbs', + 'Armond', + 'Ewings', + 'Rease', + 'Okoye', + 'Arentz', + 'Baack', + 'Bellantoni', + 'Buckholz', + 'Cirigliano', + 'Colletta', + 'Dutka', + 'Everingham', + 'Gilardi', + 'Hudelson', + 'Klimczak', + 'Kneip', + 'Papaleo', + 'Peregrino', + 'Piechowski', + 'Prucha', + 'Ryburn', + 'Scholle', + 'Scholtes', + 'Socarras', + 'Wrightsman', + 'Yum', + 'Campau', + 'Dwinell', + 'Haupert', + 'Lotspeich', + 'Madar', + 'Casa', + 'Michals', + 'Rainier', + 'Tenpenny', + 'Lakeman', + 'Spadoni', + 'Cantrelle', + 'Mangal', + 'Chachere', + 'Swoope', + 'Carwell', + 'Voltaire', + 'Durrah', + 'Roulhac', + 'Aboytes', + 'Apuzzo', + 'Bielinski', + 'Bollenbacher', + 'Borjon', + 'Croak', + 'Dansie', + 'Espin', + 'Euceda', + 'Garone', + 'Garthwaite', + 'Hata', + 'Heu', + 'Hogenson', + 'Jahner', + 'Keesey', + 'Kotas', + 'Labrake', + 'Laitinen', + 'Laumann', + 'Miske', + 'Nickless', + 'Onishi', + 'Setty', + 'Shinnick', + 'Takayama', + 'Tassinari', + 'Tribe', + 'Bowdish', + 'Friesenhahn', + 'Hoffarth', + 'Wachowski', + 'Gudgel', + 'Gautney', + 'Matar', + 'Ellenberg', + 'Inghram', + 'Bevil', + 'Rasul', + 'Niblack', + 'Perkin', + 'Goring', + 'Potier', + 'Bachrach', + 'Bozza', + 'Budz', + 'Devens', + 'Ditzel', + 'Drahos', + 'Ducat', + 'Fahrner', + 'Friedline', + 'Geurin', + 'Goodenow', + 'Greenfeld', + 'Grunow', + 'Ingber', + 'Kashani', + 'Kochman', + 'Kozub', + 'Kukuk', + 'Leppo', + 'Liew', + 'Metheney', + 'Molony', + 'Montemurro', + 'Neiss', + 'Postlethwait', + 'Quaglia', + 'Ruszkowski', + 'Shertzer', + 'Titone', + 'Waldmann', + 'Wenninger', + 'Wheeland', + 'Zorich', + 'Mervine', + 'Weatherholtz', + 'Brotman', + 'Malenfant', + 'Nong', + 'Rogness', + 'Dibert', + 'Gallahan', + 'Gange', + 'Chilcott', + 'Axt', + 'Wiler', + 'Jacot', + 'Ory', + 'Abdon', + 'Fenter', + 'Bryars', + 'Ramroop', + 'Jacox', + 'Mainer', + 'Figures', + 'Alig', + 'Bires', + 'Cassata', + 'Cholewa', + 'Dispenza', + 'Eckmann', + 'Gauer', + 'Gloor', + 'Hattori', + 'Huster', + 'Kopplin', + 'Krugman', + 'Lancon', + 'Ledin', + 'Limb', + 'Marentes', + 'Minges', + 'Monacelli', + 'Monteon', + 'Naslund', + 'Nitsche', + 'Rapozo', + 'Rimkus', + 'Schwerdtfeger', + 'Vandenbos', + 'Balandran', + 'Biehn', + 'Briody', + 'Hackmann', + 'Kalka', + 'Keranen', + 'Lortie', + 'Mannella', + 'Shiffler', + 'Stempel', + 'Takaki', + 'Tomassi', + 'Reidel', + 'Ciprian', + 'Penza', + 'Vite', + 'Cormany', + 'Derousse', + 'Beus', + 'Shurley', + 'Courtwright', + 'Donna', + 'Karney', + 'Keats', + 'Harron', + 'Stjacques', + 'Regester', + 'Stoke', + 'Garron', + 'Sulaiman', + 'Fusilier', + 'Hence', + 'Altidor', + 'Rollerson', + 'Anfinson', + 'Badua', + 'Balmaceda', + 'Bringman', + 'Bystrom', + 'Goffinet', + 'Guindon', + 'Hilling', + 'Makepeace', + 'Mooradian', + 'Muzquiz', + 'Newcom', + 'Perrella', + 'Postlewait', + 'Raetz', + 'Riveros', + 'Saephanh', + 'Scharer', + 'Sheeder', + 'Sitar', + 'Umlauf', + 'Voegeli', + 'Yurkovich', + 'Chaudhari', + 'Chianese', + 'Clonch', + 'Gasparini', + 'Giambalvo', + 'Gindlesperger', + 'Rauen', + 'Riegert', + 'Collingsworth', + 'Stief', + 'Zeisler', + 'Kirsten', + 'Vessey', + 'Scherman', + 'Ledwith', + 'Goudie', + 'Ayre', + 'Salome', + 'Knoles', + 'Munyan', + 'Corbet', + 'Hagewood', + 'Humphry', + 'Bernardez', + 'Drummonds', + 'Lide', + 'Veals', + 'Andolina', + 'Anzaldo', + 'Aufiero', + 'Bakshi', + 'Berdan', + 'Birrell', + 'Colcord', + 'Dutro', + 'Eisenhour', + 'Falgoust', + 'Foertsch', + 'Forlenza', + 'Harroun', + 'Kurtenbach', + 'Livesey', + 'Luka', + 'Manseau', + 'Mcdaid', + 'Miska', + 'Overley', + 'Panzica', + 'Reish', + 'Riolo', + 'Roseland', + 'Shenberger', + 'Splinter', + 'Strupp', + 'Sturgell', + 'Swatzell', + 'Totherow', + 'Villarroel', + 'Wenig', + 'Zimny', + 'Brunetto', + 'Hiester', + 'Kasinger', + 'Laverde', + 'Mihalek', + 'Aquila', + 'Moreton', + 'Collums', + 'Ergle', + 'Keziah', + 'Bourbon', + 'Scaff', + 'Leamy', + 'Sublette', + 'Winkley', + 'Arlington', + 'Cuffe', + 'Guity', + 'Mcmickle', + 'Summerour', + 'Baggerly', + 'Biltz', + 'Calma', + 'Dephillips', + 'Graffam', + 'Holsopple', + 'Izumi', + 'Joerger', + 'Kesselman', + 'Kingdon', + 'Kinkel', + 'Knezevich', + 'Liebler', + 'Maceda', + 'Qualey', + 'Robeck', + 'Sciarrino', + 'Sooy', + 'Stahly', + 'Stieglitz', + 'Strike', + 'Unwin', + 'Urizar', + 'Volmer', + 'Winterstein', + 'Aronov', + 'Czyz', + 'Marrazzo', + 'Seagren', + 'Wiegmann', + 'Yearsley', + 'Brommer', + 'Sterne', + 'Armel', + 'Kryger', + 'Barten', + 'Bodwell', + 'Hollett', + 'Sharron', + 'Scobey', + 'Croson', + 'Gainor', + 'Axel', + 'Basore', + 'Bengel', + 'Chiem', + 'Desanctis', + 'Gillooly', + 'Groulx', + 'Hulings', + 'Koenigsberg', + 'Kuchinski', + 'Pagaduan', + 'Pataky', + 'Rietz', + 'Robello', + 'Schuchman', + 'Shek', + 'Brattain', + 'Gottwald', + 'Klapperich', + 'Kosky', + 'Ruegg', + 'Smid', + 'Taillon', + 'Klonowski', + 'Attar', + 'Mansoor', + 'Daus', + 'Falla', + 'Guyot', + 'Hasten', + 'Mcdowall', + 'Tugwell', + 'Remo', + 'Dishmon', + 'Leggette', + 'Sudler', + 'Prescod', + 'Benvenuti', + 'Bittenbender', + 'Burkland', + 'Crehan', + 'Donjuan', + 'Ewbank', + 'Fluegel', + 'Freiman', + 'Fuelling', + 'Grabner', + 'Gras', + 'Horr', + 'Jurich', + 'Kentner', + 'Laski', + 'Minero', + 'Olivos', + 'Porro', + 'Purves', + 'Smethers', + 'Spallone', + 'Stangler', + 'Gebbia', + 'Fowers', + 'Gaster', + 'Fero', + 'Gamon', + 'Wiss', + 'Strassner', + 'Cott', + 'Houp', + 'Fidel', + 'Parisien', + 'Daisy', + 'Calais', + 'Boers', + 'Bolle', + 'Caccavale', + 'Colantonio', + 'Columbo', + 'Goswami', + 'Hakanson', + 'Jelley', + 'Kahlon', + 'Lopezgarcia', + 'Marier', + 'Mesko', + 'Monter', + 'Mowell', + 'Piech', + 'Shortell', + 'Slechta', + 'Starman', + 'Tiemeyer', + 'Troutner', + 'Vandeveer', + 'Voorheis', + 'Woodhams', + 'Helget', + 'Kalk', + 'Kiester', + 'Lagace', + 'Obst', + 'Parrack', + 'Rennert', + 'Rodeheaver', + 'Schuermann', + 'Warmuth', + 'Wisnieski', + 'Yahnke', + 'Yurek', + 'Faver', + 'Belleau', + 'Moan', + 'Remsen', + 'Bonano', + 'Genson', + 'Genis', + 'Risen', + 'Franze', + 'Lauderback', + 'Ferns', + 'Cooler', + 'Mcwilliam', + 'Micheals', + 'Gotch', + 'Teat', + 'Bacus', + 'Banik', + 'Bernhart', + 'Doell', + 'Francese', + 'Gasbarro', + 'Gietzen', + 'Gossen', + 'Haberle', + 'Havlicek', + 'Henion', + 'Kevorkian', + 'Liem', + 'Loor', + 'Moede', + 'Mostafa', + 'Mottern', + 'Naito', + 'Nofsinger', + 'Omelia', + 'Pirog', + 'Pirone', + 'Plucinski', + 'Raghavan', + 'Robaina', + 'Seliga', + 'Stade', + 'Steinhilber', + 'Wedin', + 'Wieman', + 'Zemaitis', + 'Creps', + 'Gumina', + 'Inglett', + 'Jhaveri', + 'Kolasinski', + 'Salvesen', + 'Vallely', + 'Weseman', + 'Zysk', + 'Gourlay', + 'Zanger', + 'Delorey', + 'Sneider', + 'Tacey', + 'Valls', + 'Ossman', + 'Watton', + 'Breau', + 'Burell', + 'Villard', + 'Janice', + 'Honor', + 'Arterberry', + 'Sow', + 'Cucchiara', + 'Diemert', + 'Fluty', + 'Guadiana', + 'Ionescu', + 'Kearley', + 'Krzyzanowski', + 'Lavecchia', + 'Lundmark', + 'Melichar', + 'Mulkern', + 'Odonohue', + 'Payment', + 'Pinnow', + 'Popoff', + 'Prus', + 'Reinoehl', + 'Scarlata', + 'Schamp', + 'Schowalter', + 'Scinto', + 'Semmler', + 'Sheline', + 'Sigg', + 'Trauger', + 'Bleiler', + 'Carrino', + 'Hauth', + 'Kunsman', + 'Reicks', + 'Rotenberg', + 'Soltesz', + 'Wascher', + 'Mattina', + 'Tamblyn', + 'Bellanca', + 'Heward', + 'Seif', + 'Agha', + 'Gosling', + 'Defreese', + 'Lyvers', + 'Robley', + 'Hadi', + 'Ledyard', + 'Mitchner', + 'Berrien', + 'Clinkscale', + 'Affeldt', + 'Aung', + 'Azpeitia', + 'Boehnlein', + 'Cavan', + 'Ekdahl', + 'Ellyson', + 'Fahl', + 'Herrig', + 'Hulick', + 'Ihrke', + 'Kaeding', + 'Keagy', + 'Mehlman', + 'Minniear', + 'Paniccia', + 'Pleva', + 'Prestidge', + 'Pulford', + 'Quattrone', + 'Riquelme', + 'Rombach', + 'Sarwar', + 'Sivertsen', + 'Sprang', + 'Wardrop', + 'Anglemyer', + 'Bobek', + 'Scronce', + 'Snethen', + 'Stancliff', + 'Booton', + 'Pinal', + 'Weihe', + 'Bria', + 'Lopresto', + 'Awbrey', + 'Fogal', + 'Ning', + 'Hydrick', + 'Lumb', + 'Pommier', + 'Hendy', + 'Armon', + 'Spenser', + 'Beachem', + 'Decrescenzo', + 'Heaphy', + 'Kalata', + 'Kastl', + 'Kosel', + 'Kunert', + 'Laatsch', + 'Lanpher', + 'Malinski', + 'Mazzie', + 'Neuendorf', + 'Salloum', + 'Tays', + 'Yackel', + 'Calvario', + 'Feese', + 'Feldner', + 'Kness', + 'Kozuch', + 'Magat', + 'Pantalone', + 'Rilling', + 'Teska', + 'Fantauzzi', + 'Wartman', + 'Stansbery', + 'Sox', + 'Napp', + 'Schauf', + 'Cumings', + 'Coxon', + 'Labor', + 'Brash', + 'Egleston', + 'Quintin', + 'Oki', + 'Date', + 'Tuckett', + 'Devaux', + 'Hewins', + 'Abdelrahman', + 'Schumpert', + 'Dort', + 'Limbrick', + 'Linwood', + 'Delaine', + 'Liverpool', + 'Azimi', + 'Biever', + 'Craigo', + 'Eschete', + 'Fortini', + 'Francom', + 'Giacomini', + 'Girdler', + 'Halasz', + 'Hillin', + 'Inglese', + 'Isaza', + 'Lewman', + 'Ploetz', + 'Rampley', + 'Reifsteck', + 'Rossano', + 'Sanagustin', + 'Sotak', + 'Spainhower', + 'Stecklein', + 'Stolberg', + 'Teschner', + 'Thew', + 'Blaszczyk', + 'Caradonna', + 'Cillo', + 'Diluzio', + 'Hagemeyer', + 'Holstrom', + 'Jewkes', + 'Mcquaide', + 'Osterhaus', + 'Twaddle', + 'Wenck', + 'Yakel', + 'Zeiner', + 'Zulauf', + 'Mirabelli', + 'Gerold', + 'Sherr', + 'Ogando', + 'Achilles', + 'Woodlee', + 'Underdown', + 'Peirson', + 'Abdelaziz', + 'Bently', + 'Junes', + 'Furtick', + 'Muckle', + 'Freemon', + 'Jamar', + 'Scriber', + 'Michaux', + 'Cheatum', + 'Hollings', + 'Telfair', + 'Amadeo', + 'Bargar', + 'Berchtold', + 'Boomhower', + 'Camba', + 'Compo', + 'Dellavecchia', + 'Doring', + 'Doyel', + 'Geck', + 'Giovannini', + 'Herda', + 'Kopko', + 'Kuns', + 'Maciag', + 'Neenan', + 'Neglia', + 'Nienhuis', + 'Niznik', + 'Pieczynski', + 'Quintos', + 'Quirin', + 'Ravi', + 'Teaster', + 'Tipsword', + 'Troiani', + 'Consuegra', + 'Damaso', + 'Garavaglia', + 'Pischke', + 'Prowse', + 'Rumore', + 'Simcoe', + 'Slentz', + 'Sposito', + 'Sulser', + 'Weichel', + 'Sandobal', + 'Siver', + 'Vickerman', + 'Sham', + 'Gutridge', + 'Gracy', + 'Weatherington', + 'Benett', + 'Nottage', + 'Myricks', + 'Tukes', + 'Alcaide', + 'Curatolo', + 'Dalziel', + 'Fandrich', + 'Fisette', + 'Gianino', + 'Grether', + 'Hari', + 'Ichikawa', + 'Lantzy', + 'Monteforte', + 'Moskovitz', + 'Porritt', + 'Raz', + 'Rodenbeck', + 'Ryczek', + 'Strehle', + 'Vanduzer', + 'Voge', + 'Wiker', + 'Yanik', + 'Zangari', + 'Cahue', + 'Dellapenna', + 'Gohr', + 'Gurka', + 'Imburgia', + 'Langenberg', + 'Kivi', + 'Pikul', + 'Sexson', + 'Sharrer', + 'Aramburo', + 'Kadar', + 'Casasola', + 'Nina', + 'Borras', + 'Toledano', + 'Wykle', + 'Naeem', + 'Bailer', + 'Lalla', + 'Booty', + 'Turenne', + 'Merrit', + 'Duffus', + 'Hemmingway', + 'Asare', + 'Ahlborn', + 'Arroyave', + 'Brandenberger', + 'Carolus', + 'Coonan', + 'Dacunha', + 'Dost', + 'Filter', + 'Freudenberg', + 'Grabski', + 'Hengel', + 'Holohan', + 'Kohne', + 'Kollmann', + 'Levick', + 'Lupinacci', + 'Meservey', + 'Reisdorf', + 'Rodabaugh', + 'Shimon', + 'Soth', + 'Spall', + 'Tener', + 'Thier', + 'Welshans', + 'Chermak', + 'Ciolino', + 'Frantzen', + 'Grassman', + 'Okuda', + 'Passantino', + 'Schellinger', + 'Sneath', + 'Bolla', + 'Bobe', + 'Maves', + 'Matey', + 'Shafi', + 'Rothchild', + 'Ker', + 'Verrette', + 'Thorington', + 'Lathers', + 'Merriwether', + 'Bendall', + 'Bercier', + 'Botz', + 'Claybaugh', + 'Creson', + 'Dilone', + 'Gabehart', + 'Gencarelli', + 'Ghormley', + 'Hacking', + 'Haefele', + 'Haros', + 'Holderby', + 'Krotzer', + 'Nanda', + 'Oltmanns', + 'Orndoff', + 'Poniatowski', + 'Rosol', + 'Sheneman', + 'Shifrin', + 'Smay', + 'Swickard', + 'Thayne', + 'Tripathi', + 'Vonbehren', + 'Pummill', + 'Schnitker', + 'Steines', + 'Beechler', + 'Faron', + 'Villari', + 'Spickard', + 'Levings', + 'Polack', + 'Standre', + 'Castel', + 'Louise', + 'Janey', + 'Lindor', + 'Bulthuis', + 'Cantrall', + 'Cisnero', + 'Dangel', + 'Deborde', + 'Decena', + 'Grandon', + 'Gritz', + 'Heberlein', + 'Kestenbaum', + 'Kubitz', + 'Luers', + 'Naiman', + 'Ramaswamy', + 'Sek', + 'Slauson', + 'Walsworth', + 'Biehler', + 'Capano', + 'Casstevens', + 'Forgette', + 'Furnas', + 'Gilkison', + 'Janoski', + 'Jerde', + 'Mcclimans', + 'Rohlf', + 'Vliet', + 'Heeney', + 'Zapanta', + 'Lighthall', + 'Shallow', + 'Neils', + 'Raikes', + 'Clarkston', + 'Claud', + 'Guilbeaux', + 'Pennie', + 'Arizola', + 'Aud', + 'Checketts', + 'Corvera', + 'Easterbrook', + 'Gamm', + 'Grassel', + 'Guarin', + 'Hanf', + 'Hitsman', + 'Lackman', + 'Lubitz', + 'Lupian', + 'Olexa', + 'Omori', + 'Oscarson', + 'Picasso', + 'Plewa', + 'Schmahl', + 'Stolze', + 'Todisco', + 'Zarzycki', + 'Baluyot', + 'Cerrito', + 'Elenbaas', + 'Gavidia', + 'Heisner', + 'Karpowicz', + 'Neidhardt', + 'Silkwood', + 'Taras', + 'Dobias', + 'Widen', + 'Blandino', + 'Fanguy', + 'Probus', + 'Guilbert', + 'Shadowens', + 'Keepers', + 'Bruin', + 'Hitson', + 'Crymes', + 'Roston', + 'Beaubrun', + 'Arrambide', + 'Betti', + 'Brockhaus', + 'Bumanglag', + 'Cabreja', + 'Dicenso', + 'Hartlaub', + 'Hertlein', + 'Lapenna', + 'Rathje', + 'Rotert', + 'Salzberg', + 'Siniard', + 'Tomsic', + 'Wondra', + 'Zenger', + 'Norrod', + 'Opalka', + 'Osment', + 'Zhan', + 'Lemcke', + 'Meranda', + 'Joles', + 'Labay', + 'Monserrate', + 'Grime', + 'Martha', + 'Coltrain', + 'Vardaman', + 'Wragg', + 'Frater', + 'Offer', + 'Elcock', + 'Auble', + 'Bistline', + 'Chorney', + 'Colgate', + 'Dadamo', + 'Deol', + 'Discher', + 'Ertz', + 'Fletchall', + 'Galletti', + 'Geffre', + 'Grall', + 'Hoos', + 'Iezzi', + 'Kawecki', + 'Madamba', + 'Margolies', + 'Mccreedy', + 'Okimoto', + 'Oum', + 'Pangan', + 'Pasternack', + 'Plazola', + 'Prochazka', + 'Tewes', + 'Tramontana', + 'Yauch', + 'Zarling', + 'Zemanek', + 'Altshuler', + 'Bartkowski', + 'Cuoco', + 'Garcialopez', + 'Kauzlarich', + 'Shishido', + 'Zaun', + 'Hallin', + 'Starliper', + 'Belflower', + 'Kneece', + 'Genet', + 'Palmero', + 'Willmott', + 'Riek', + 'Belger', + 'Abbitt', + 'Statum', + 'Jacque', + 'Chisley', + 'Habersham', + 'Berardinelli', + 'Bodle', + 'Deshaw', + 'Ingalsbe', + 'Kirchgessner', + 'Kuna', + 'Pellow', + 'Pickler', + 'Pistole', + 'Rosenstock', + 'Salceda', + 'Sawatzky', + 'Schappell', + 'Scholer', + 'Shellabarger', + 'Spader', + 'Swadley', + 'Travelstead', + 'Varin', + 'Villwock', + 'Wiemers', + 'Bedoy', + 'Borowiak', + 'Celio', + 'Dornfeld', + 'Juhnke', + 'Livernois', + 'Sakaguchi', + 'Sandall', + 'Sivertson', + 'Whitcraft', + 'Anda', + 'Aprile', + 'Kritz', + 'Speier', + 'Karman', + 'Kise', + 'Madia', + 'Bodo', + 'Madole', + 'Harl', + 'Gach', + 'Stalls', + 'Holme', + 'Lomba', + 'Tutton', + 'Windon', + 'Bines', + 'Benoist', + 'Cirrincione', + 'Coday', + 'Delrosso', + 'Dlouhy', + 'Domenick', + 'Edelmann', + 'Goos', + 'Hamling', + 'Huda', + 'Hutzel', + 'Lanasa', + 'Loudenslager', + 'Lueras', + 'Magnussen', + 'Mcferran', + 'Nowinski', + 'Pikula', + 'Precht', + 'Quilici', + 'Robling', + 'Rusche', + 'Schettino', + 'Scibelli', + 'Soderman', + 'Spirito', + 'Teaford', + 'Updegrove', + 'Weygandt', + 'Zervos', + 'Brunker', + 'Demuro', + 'Eckenrod', + 'Emley', + 'Franek', + 'Frankenberger', + 'Longbrake', + 'Magallanez', + 'Stofko', + 'Zenz', + 'Galik', + 'Crevier', + 'Fina', + 'Harari', + 'Dudney', + 'Inga', + 'Sowles', + 'Folker', + 'Cressy', + 'Eckerson', + 'Gerringer', + 'Capito', + 'Huxtable', + 'Arcement', + 'Lansdown', + 'Amara', + 'Brazill', + 'Flye', + 'Currington', + 'Buffin', + 'Desta', + 'Cheuvront', + 'Fuoco', + 'Gerbino', + 'Hilyer', + 'Hogsed', + 'Kubis', + 'Lautner', + 'Loeber', + 'Meyn', + 'Mortell', + 'Nunziato', + 'Opdahl', + 'Panebianco', + 'Reffner', + 'Repsher', + 'Riccobono', + 'Wik', + 'Circle', + 'Hovde', + 'Keaveney', + 'Landsberg', + 'Pesavento', + 'Bedel', + 'Glas', + 'Thurn', + 'Jaffer', + 'Dantin', + 'Risi', + 'Many', + 'Egler', + 'Craghead', + 'Ann', + 'Turnbo', + 'Crumby', + 'Faciane', + 'Brummell', + 'Bujak', + 'Chaddock', + 'Cullop', + 'Eberling', + 'Ennen', + 'Frum', + 'Gassert', + 'Grothaus', + 'Hucke', + 'Lanphere', + 'Lozon', + 'Macadam', + 'Mezo', + 'Peretti', + 'Perlin', + 'Prestwich', + 'Redmann', + 'Ringley', + 'Rivenburg', + 'Sandow', + 'Spreitzer', + 'Stachnik', + 'Szczesniak', + 'Tworek', + 'Wogan', + 'Zygmunt', + 'Austad', + 'Chiappone', + 'Gelineau', + 'Lannom', + 'Livezey', + 'Monrroy', + 'Norem', + 'Oetting', + 'Ostberg', + 'Takeshita', + 'Gorsky', + 'Allcorn', + 'Pemble', + 'Josselyn', + 'Lanzo', + 'Hoare', + 'Ticer', + 'Netterville', + 'Lawes', + 'Lenton', + 'Garraway', + 'Cyprian', + 'Alferez', + 'Allocco', + 'Aslanian', + 'Brenna', + 'Carachure', + 'Devoss', + 'Dubas', + 'Garrabrant', + 'Gerloff', + 'Gerritsen', + 'Hobaugh', + 'Jasek', + 'Kulis', + 'Lenehan', + 'Lodes', + 'Mandich', + 'Manter', + 'Mcfatridge', + 'Mikolajczak', + 'Netz', + 'Perrelli', + 'Ribar', + 'Sekerak', + 'Shingledecker', + 'Talamante', + 'Taverna', + 'Thoresen', + 'Throneberry', + 'Vanacore', + 'Vieau', + 'Wermuth', + 'Zeidan', + 'Counihan', + 'Dircks', + 'Markovitz', + 'Panas', + 'Steffel', + 'Bergstedt', + 'Mohar', + 'Sonne', + 'Mitsch', + 'Aceituno', + 'Loker', + 'Treen', + 'Prunier', + 'Amberson', + 'Allington', + 'Artley', + 'Caffery', + 'Rhoney', + 'Nimmer', + 'Ledwell', + 'Barkus', + 'Fralin', + 'Locks', + 'Azzara', + 'Bartosik', + 'Bertelson', + 'Birman', + 'Brogna', + 'Cachola', + 'Dennington', + 'Enea', + 'Gallogly', + 'Grafe', + 'Jankowiak', + 'Kaas', + 'Karis', + 'Kostick', + 'Lentsch', + 'Locken', + 'Mathys', + 'Maxcy', + 'Monegro', + 'Olano', + 'Paske', + 'Raible', + 'Rowbotham', + 'Vanderbeck', + 'Vanosdol', + 'Wenzler', + 'Yglesias', + 'Eisenberger', + 'Grzelak', + 'Hamidi', + 'Hottel', + 'Markoff', + 'Santagata', + 'Seefeld', + 'Stachowicz', + 'Stiehl', + 'Staver', + 'Raad', + 'Sarber', + 'Rudge', + 'Connelley', + 'Danser', + 'Chumney', + 'Hind', + 'Desper', + 'Fergusson', + 'Ringwood', + 'Byles', + 'Alyea', + 'Benzinger', + 'Betzer', + 'Brix', + 'Chiarella', + 'Chiriboga', + 'Cicala', + 'Cohick', + 'Creeden', + 'Delligatti', + 'Garbacz', + 'Grossberg', + 'Habecker', + 'Inscoe', + 'Irias', + 'Karlsen', + 'Kilts', + 'Koetter', + 'Laflin', + 'Laperle', + 'Mizner', + 'Navia', + 'Nolet', + 'Procaccini', + 'Pula', + 'Scarfo', + 'Schmelz', + 'Taaffe', + 'Troth', + 'Vanlaningham', + 'Vosberg', + 'Whitchurch', + 'Benak', + 'Hanawalt', + 'Lindman', + 'Moschetti', + 'Rozas', + 'Sporleder', + 'Stopka', + 'Turowski', + 'Wahlgren', + 'Youngstrom', + 'Jabbour', + 'Myerson', + 'Perlow', + 'Cannone', + 'Kil', + 'Stiverson', + 'Cedar', + 'Sweeden', + 'Pourciau', + 'Salina', + 'Delmoral', + 'Balle', + 'Cohea', + 'Bute', + 'Rayne', + 'Cawthorn', + 'Conely', + 'Cartlidge', + 'Powel', + 'Nwankwo', + 'Centrella', + 'Delaura', + 'Deprey', + 'Dulude', + 'Garrod', + 'Gassen', + 'Greenberger', + 'Huneke', + 'Kunzman', + 'Laakso', + 'Oppermann', + 'Radich', + 'Rozen', + 'Schoffstall', + 'Swetnam', + 'Vitrano', + 'Wolber', + 'Amirault', + 'Przybysz', + 'Trzeciak', + 'Fontan', + 'Mathie', + 'Roswell', + 'Mcquitty', + 'Kye', + 'Lucious', + 'Chilcutt', + 'Difazio', + 'Diperna', + 'Gashi', + 'Goodstein', + 'Gruetzmacher', + 'Imus', + 'Krumholz', + 'Lanzetta', + 'Leaming', + 'Lehigh', + 'Lobosco', + 'Pardoe', + 'Pellicano', + 'Purtee', + 'Ramanathan', + 'Roszkowski', + 'Satre', + 'Steinborn', + 'Stinebaugh', + 'Thiesen', + 'Tierno', + 'Wrisley', + 'Yazdani', + 'Zwilling', + 'Berntson', + 'Gisclair', + 'Golliher', + 'Neumeier', + 'Stohl', + 'Swartley', + 'Wannemacher', + 'Wickard', + 'Duford', + 'Rosello', + 'Merfeld', + 'Arko', + 'Cotney', + 'Hai', + 'Milley', + 'Figueira', + 'Willes', + 'Helmes', + 'Abair', + 'Life', + 'Izard', + 'Duskin', + 'Moland', + 'Primer', + 'Hagos', + 'Anyanwu', + 'Balasubramanian', + 'Bluth', + 'Calk', + 'Chrzan', + 'Constanza', + 'Durney', + 'Ekholm', + 'Erny', + 'Ferrando', + 'Froberg', + 'Gonyer', + 'Guagliardo', + 'Hreha', + 'Kobza', + 'Kuruvilla', + 'Preziosi', + 'Ricciuti', + 'Rosiles', + 'Schiesser', + 'Schmoyer', + 'Slota', + 'Szeliga', + 'Verba', + 'Widjaja', + 'Wrzesinski', + 'Zufall', + 'Bumstead', + 'Dohrman', + 'Dommer', + 'Eisenmenger', + 'Glogowski', + 'Kaufhold', + 'Kuiken', + 'Ricklefs', + 'Sinyard', + 'Steenbergen', + 'Schweppe', + 'Chatwin', + 'Dingee', + 'Mittleman', + 'Menear', + 'Milot', + 'Riccardo', + 'Clemenson', + 'Mellow', + 'Gabe', + 'Rolla', + 'Vander', + 'Casselberry', + 'Hubbart', + 'Colvert', + 'Billingsly', + 'Burgman', + 'Cattaneo', + 'Duthie', + 'Hedtke', + 'Heidler', + 'Hertenstein', + 'Hudler', + 'Hustead', + 'Ibsen', + 'Krutsinger', + 'Mauceri', + 'Mersereau', + 'Morad', + 'Rentfro', + 'Rumrill', + 'Shedlock', + 'Sindt', + 'Soulier', + 'Squitieri', + 'Trageser', + 'Vatter', + 'Vollman', + 'Wagster', + 'Caselli', + 'Dibacco', + 'Gick', + 'Kachel', + 'Lukaszewski', + 'Minniti', + 'Neeld', + 'Zarrella', + 'Hedglin', + 'Jahan', + 'Nathe', + 'Starn', + 'Kana', + 'Bernet', + 'Rossa', + 'Barro', + 'Smylie', + 'Bowlds', + 'Mccalley', + 'Oniel', + 'Thaggard', + 'Cayson', + 'Sinegal', + 'Bergfeld', + 'Bickmore', + 'Boch', + 'Bushway', + 'Carneiro', + 'Cerio', + 'Colbath', + 'Eade', + 'Eavenson', + 'Epping', + 'Fredricksen', + 'Gramer', + 'Hassman', + 'Hinderer', + 'Kantrowitz', + 'Kaplowitz', + 'Kelner', + 'Lecates', + 'Lothrop', + 'Lupica', + 'Masterman', + 'Meeler', + 'Neumiller', + 'Newbauer', + 'Noyce', + 'Nulty', + 'Shanker', + 'Taheri', + 'Timblin', + 'Vitucci', + 'Zappone', + 'Femia', + 'Hejl', + 'Helmbrecht', + 'Kiesow', + 'Maschino', + 'Brougher', + 'Koff', + 'Reffett', + 'Langhoff', + 'Milman', + 'Sidener', + 'Levie', + 'Chaudry', + 'Rattan', + 'Finkler', + 'Bollen', + 'Booz', + 'Shipps', + 'Theall', + 'Scallion', + 'Furlough', + 'Landfair', + 'Albuquerque', + 'Beckstrand', + 'Colglazier', + 'Darcey', + 'Fahr', + 'Gabert', + 'Gertner', + 'Gettler', + 'Giovannetti', + 'Hulvey', + 'Juenger', + 'Kantola', + 'Kemmerling', + 'Leclere', + 'Liberati', + 'Lopezlopez', + 'Minerva', + 'Redlich', + 'Shoun', + 'Sickinger', + 'Vivier', + 'Yerdon', + 'Ziomek', + 'Dechert', + 'Delbene', + 'Galassi', + 'Rawdon', + 'Wesenberg', + 'Laurino', + 'Grosjean', + 'Levay', + 'Zike', + 'Stukey', + 'Loft', + 'Kool', + 'Hatchel', + 'Mainville', + 'Salis', + 'Greenslade', + 'Mantey', + 'Spratlin', + 'Fayette', + 'Marner', + 'Rolan', + 'Pain', + 'Colquhoun', + 'Brave', + 'Locust', + 'Sconiers', + 'Bahler', + 'Barrero', + 'Bartha', + 'Basnett', + 'Berghoff', + 'Bomgardner', + 'Brindisi', + 'Campoli', + 'Carawan', + 'Chhim', + 'Corro', + 'Crissey', + 'Deterding', + 'Dileonardo', + 'Dowis', + 'Hagemeier', + 'Heichel', + 'Kipfer', + 'Lemberger', + 'Maestri', + 'Mauri', + 'Nakatani', + 'Notestine', + 'Polakowski', + 'Schlobohm', + 'Segel', + 'Socci', + 'Stieg', + 'Thorstad', + 'Trausch', + 'Whitledge', + 'Wilkowski', + 'Barkdull', + 'Dubeau', + 'Ellingsen', + 'Hayduk', + 'Lauter', + 'Lizak', + 'Machamer', + 'Makarewicz', + 'Shuffield', + 'Heiserman', + 'Sandeen', + 'Plough', + 'Stemler', + 'Bossler', + 'Catalina', + 'Betley', + 'Bonello', + 'Pryde', + 'Nickey', + 'Schanck', + 'Single', + 'Mulberry', + 'Point', + 'Danson', + 'Flemmings', + 'Behnken', + 'Catone', + 'Cummiskey', + 'Currens', + 'Gersch', + 'Kitamura', + 'Meddaugh', + 'Montagne', + 'Nouri', + 'Olejnik', + 'Pintar', + 'Placke', + 'Quinter', + 'Rakers', + 'Stuteville', + 'Sullo', + 'Voelz', + 'Barabas', + 'Estock', + 'Hultberg', + 'Savitz', + 'Treml', + 'Vigneault', + 'Jezierski', + 'Zayed', + 'Dewell', + 'Yanko', + 'Moulin', + 'Whalin', + 'Elsworth', + 'Summit', + 'Esty', + 'Mahadeo', + 'Shular', + 'Amedee', + 'Bellerose', + 'Bendixen', + 'Briski', + 'Buysse', + 'Desa', + 'Dobry', + 'Dufner', + 'Fetterly', + 'Finau', + 'Gaudioso', + 'Giangrande', + 'Heuring', + 'Kitchel', + 'Latulippe', + 'Pombo', + 'Vancott', + 'Woofter', + 'Bojarski', + 'Cretella', + 'Heumann', + 'Limpert', + 'Mcneff', + 'Pluff', + 'Tumlinson', + 'Widick', + 'Yeargan', + 'Hanft', + 'Novinger', + 'Ruddle', + 'Wrye', + 'Felde', + 'Basic', + 'Babington', + 'Karson', + 'Forgy', + 'Rendall', + 'Icard', + 'Jann', + 'Ady', + 'Therrell', + 'Sroufe', + 'Maden', + 'Ganus', + 'Preddy', + 'Marberry', + 'Fonder', + 'Latty', + 'Leatherbury', + 'Mentor', + 'Brissett', + 'Mcglory', + 'Readus', + 'Akau', + 'Bellone', + 'Berendt', + 'Bok', + 'Broten', + 'Colosi', + 'Corio', + 'Gilani', + 'Huffmaster', + 'Kieler', + 'Leonor', + 'Lips', + 'Madron', + 'Missey', + 'Nabozny', + 'Panning', + 'Reinwald', + 'Ridener', + 'Silvio', + 'Soder', + 'Spieler', + 'Vaeth', + 'Vincenti', + 'Walczyk', + 'Washko', + 'Wiater', + 'Wilen', + 'Windish', + 'Consalvo', + 'Fioravanti', + 'Hinners', + 'Paduano', + 'Ranum', + 'Parlato', + 'Dweck', + 'Matern', + 'Cryder', + 'Rubert', + 'Furgason', + 'Virella', + 'Boylen', + 'Devenport', + 'Perrodin', + 'Hollingshed', + 'Pennix', + 'Bogdanski', + 'Carretero', + 'Cubillos', + 'Deponte', + 'Forrey', + 'Gatchalian', + 'Geisen', + 'Gombos', + 'Hartlage', + 'Huddy', + 'Kou', + 'Matsko', + 'Muffley', + 'Niazi', + 'Nodarse', + 'Pawelek', + 'Pyper', + 'Stahnke', + 'Udall', + 'Baldyga', + 'Chrostowski', + 'Frable', + 'Handshoe', + 'Helderman', + 'Lambing', + 'Marolf', + 'Maynez', + 'Bunde', + 'Coia', + 'Piersol', + 'Agne', + 'Manwarren', + 'Bolter', + 'Kirsh', + 'Limerick', + 'Degray', + 'Bossie', + 'Frizell', + 'Saulters', + 'Staple', + 'Raspberry', + 'Arvie', + 'Abler', + 'Caya', + 'Ceci', + 'Dado', + 'Dewoody', + 'Hartzel', + 'Haverstick', + 'Kagel', + 'Kinnan', + 'Krock', + 'Kubica', + 'Laun', + 'Leimbach', + 'Mecklenburg', + 'Messmore', + 'Milich', + 'Mor', + 'Nachreiner', + 'Novelo', + 'Poer', + 'Vaupel', + 'Wery', + 'Breisch', + 'Cashdollar', + 'Corbridge', + 'Craker', + 'Heiberger', + 'Landress', + 'Leichty', + 'Wiedmann', + 'Yankowski', + 'Rigel', + 'Eary', + 'Riggen', + 'Nazir', + 'Shambo', + 'Gingery', + 'Guyon', + 'Bogie', + 'Kar', + 'Manifold', + 'Lafavor', + 'Montas', + 'Yeadon', + 'Cutchin', + 'Burkins', + 'Achille', + 'Bulls', + 'Torry', + 'Bartkus', + 'Beshara', + 'Busalacchi', + 'Calkin', + 'Corkum', + 'Crilley', + 'Cuny', + 'Delgaudio', + 'Devenney', + 'Emanuelson', + 'Fiel', + 'Galanti', + 'Gravina', + 'Herzing', + 'Huckaba', + 'Jaquish', + 'Kellermann', + 'Ketola', + 'Klunder', + 'Kolinski', + 'Kosak', + 'Loscalzo', + 'Moehle', + 'Ressel', + 'Skora', + 'Steakley', + 'Traugott', + 'Volden', + 'Berrong', + 'Kehres', + 'Loeffelholz', + 'Mensinger', + 'Nudo', + 'Pargas', + 'Endy', + 'Corniel', + 'Azzam', + 'Soard', + 'Flud', + 'Shuffler', + 'Hiley', + 'Logwood', + 'Ducre', + 'Aikey', + 'Ardolino', + 'Bergstresser', + 'Cen', + 'Delpriore', + 'Divelbiss', + 'Fishkin', + 'Gaucin', + 'Hemmingsen', + 'Inscore', + 'Kathman', + 'Kempen', + 'Koble', + 'Maestre', + 'Mcmonigle', + 'Merendino', + 'Meske', + 'Pietrzyk', + 'Renfrew', + 'Shevchenko', + 'Wied', + 'Digeronimo', + 'Heberer', + 'Himmelberger', + 'Nordmeyer', + 'Pocius', + 'Sigurdson', + 'Simic', + 'Steury', + 'Kealey', + 'Sabat', + 'Verstraete', + 'Patchell', + 'Finigan', + 'Critz', + 'Janelle', + 'Cima', + 'Zachariah', + 'Lebon', + 'Kellough', + 'Whitehall', + 'Jaudon', + 'Civil', + 'Dokes', + 'Slappy', + 'Bernacki', + 'Castronovo', + 'Douty', + 'Formoso', + 'Handelman', + 'Hauswirth', + 'Janowicz', + 'Klostermann', + 'Lochridge', + 'Mcdiarmid', + 'Schmale', + 'Shaddox', + 'Sitzes', + 'Spaw', + 'Urbanik', + 'Voller', + 'Fujikawa', + 'Kimmet', + 'Klingel', + 'Stoffregen', + 'Thammavong', + 'Varelas', + 'Whobrey', + 'Mandella', + 'Montuori', + 'Safrit', + 'Turan', + 'Khokhar', + 'Sircy', + 'Sabio', + 'Fill', + 'Brandao', + 'Avans', + 'Mencer', + 'Sherley', + 'Mccadden', + 'Sydney', + 'Smack', + 'Lastrapes', + 'Rowser', + 'Moultry', + 'Faulcon', + 'Arnall', + 'Babiak', + 'Balsam', + 'Bezanson', + 'Bocook', + 'Bohall', + 'Celi', + 'Costillo', + 'Crom', + 'Crusan', + 'Dibari', + 'Donaho', + 'Followell', + 'Gaudino', + 'Gericke', + 'Gori', + 'Hurrell', + 'Jakubiak', + 'Kazemi', + 'Koslosky', + 'Massoud', + 'Niebla', + 'Noffke', + 'Panjwani', + 'Papandrea', + 'Patella', + 'Plambeck', + 'Plichta', + 'Prinkey', + 'Raptis', + 'Ruffini', + 'Shoen', + 'Temkin', + 'Thul', + 'Vandall', + 'Wyeth', + 'Zalenski', + 'Consoli', + 'Gumbert', + 'Milanowski', + 'Musolf', + 'Naeger', + 'Okonski', + 'Orrison', + 'Solache', + 'Verdone', + 'Woehler', + 'Yonke', + 'Risdon', + 'Orzech', + 'Bergland', + 'Collen', + 'Bloodsworth', + 'Furgeson', + 'Moch', + 'Callegari', + 'Alphonso', + 'Ozier', + 'Paulding', + 'Ringold', + 'Yarde', + 'Abbett', + 'Axford', + 'Capwell', + 'Datz', + 'Delillo', + 'Delisa', + 'Dicaprio', + 'Dimare', + 'Faughnan', + 'Fehrenbacher', + 'Gellert', + 'Ging', + 'Gladhill', + 'Goates', + 'Hammerstrom', + 'Hilbun', + 'Iodice', + 'Kadish', + 'Kilker', + 'Lurvey', + 'Maue', + 'Michna', + 'Parslow', + 'Pawelski', + 'Quenzer', + 'Raboin', + 'Sader', + 'Sawka', + 'Velis', + 'Wilczewski', + 'Willemsen', + 'Zebley', + 'Benscoter', + 'Denhartog', + 'Dolinsky', + 'Malacara', + 'Mccosh', + 'Modugno', + 'Tsay', + 'Vanvoorst', + 'Mincher', + 'Nickol', + 'Elster', + 'Kerce', + 'Brittan', + 'Quilter', + 'Spike', + 'Mcintee', + 'Boldon', + 'Balderama', + 'Cauffman', + 'Chovanec', + 'Difonzo', + 'Fagerstrom', + 'Galanis', + 'Jeziorski', + 'Krasowski', + 'Lansdale', + 'Laven', + 'Magallan', + 'Mahal', + 'Mehrer', + 'Naus', + 'Peltzer', + 'Petraitis', + 'Pritz', + 'Salway', + 'Savich', + 'Schmehl', + 'Teniente', + 'Tuccillo', + 'Wahlquist', + 'Wetz', + 'Brozovich', + 'Catalfamo', + 'Dioguardi', + 'Guzzetta', + 'Hanak', + 'Lipschutz', + 'Sholtis', + 'Bleecker', + 'Sattar', + 'Thivierge', + 'Camfield', + 'Heslep', + 'Tree', + 'Calvey', + 'Mcgowin', + 'Strickling', + 'Manderson', + 'Dieudonne', + 'Bonini', + 'Bruinsma', + 'Burgueno', + 'Cotugno', + 'Fukunaga', + 'Krog', + 'Lacerda', + 'Larrivee', + 'Lepera', + 'Pinilla', + 'Reichenberger', + 'Rovner', + 'Rubiano', + 'Saraiva', + 'Smolka', + 'Soboleski', + 'Tallmadge', + 'Wigand', + 'Wikle', + 'Bentsen', + 'Bierer', + 'Cohenour', + 'Dobberstein', + 'Holderbaum', + 'Polhamus', + 'Skousen', + 'Theiler', + 'Fornes', + 'Sisley', + 'Zingale', + 'Nimtz', + 'Prieur', + 'Mccaughan', + 'Fawaz', + 'Hobbins', + 'Killingbeck', + 'Roads', + 'Nicolson', + 'Mcculloh', + 'Verges', + 'Badley', + 'Shorten', + 'Litaker', + 'Laseter', + 'Stthomas', + 'Mcguffie', + 'Depass', + 'Flemons', + 'Ahola', + 'Armacost', + 'Bearse', + 'Downum', + 'Drechsel', + 'Farooqi', + 'Filosa', + 'Francesconi', + 'Kielbasa', + 'Latella', + 'Monarch', + 'Ozawa', + 'Papadakis', + 'Politano', + 'Poucher', + 'Roussin', + 'Safley', + 'Schwer', + 'Tesoro', + 'Tsan', + 'Wintersteen', + 'Zanni', + 'Barlage', + 'Brancheau', + 'Buening', + 'Dahlem', + 'Forni', + 'Gerety', + 'Gutekunst', + 'Leamer', + 'Liwanag', + 'Meech', + 'Wigal', + 'Bonta', + 'Cheetham', + 'Crespi', + 'Fahs', + 'Prow', + 'Postle', + 'Delacy', + 'Dufort', + 'Gallery', + 'Romey', + 'Aime', + 'Molock', + 'Dixion', + 'Carstarphen', + 'Appleyard', + 'Aylsworth', + 'Barberi', + 'Contini', + 'Cugini', + 'Eiben', + 'Faso', + 'Hartog', + 'Jelen', + 'Loayza', + 'Maugeri', + 'Mcgannon', + 'Osorno', + 'Paratore', + 'Sahagian', + 'Sarracino', + 'Scallon', + 'Sypniewski', + 'Teters', + 'Throgmorton', + 'Vogelpohl', + 'Walkowski', + 'Winchel', + 'Niedermeyer', + 'Jayroe', + 'Montello', + 'Neyer', + 'Milder', + 'Obar', + 'Stanis', + 'Pro', + 'Pin', + 'Fatheree', + 'Cotterell', + 'Reeds', + 'Comrie', + 'Zamor', + 'Gradney', + 'Poullard', + 'Betker', + 'Bondarenko', + 'Buchko', + 'Eischens', + 'Glavan', + 'Hannold', + 'Heafner', + 'Karaffa', + 'Krabbe', + 'Meinzer', + 'Olgin', + 'Raeder', + 'Sarff', + 'Senechal', + 'Sette', + 'Shovlin', + 'Slife', + 'Tallarico', + 'Trivino', + 'Wyszynski', + 'Audia', + 'Facemire', + 'Januszewski', + 'Klebba', + 'Kovacik', + 'Moroni', + 'Nieder', + 'Schorn', + 'Sundby', + 'Tehan', + 'Trias', + 'Kissler', + 'Margo', + 'Jefcoat', + 'Bulow', + 'Maire', + 'Vizcarrondo', + 'Ki', + 'Ayuso', + 'Mayhan', + 'Usman', + 'Blincoe', + 'Whidby', + 'Tinson', + 'Calarco', + 'Cena', + 'Ciccarello', + 'Cloe', + 'Consolo', + 'Davydov', + 'Decristofaro', + 'Delmundo', + 'Dubrow', + 'Ellinwood', + 'Gehling', + 'Halberstadt', + 'Hascall', + 'Hoeffner', + 'Huettl', + 'Iafrate', + 'Imig', + 'Khoo', + 'Krausz', + 'Kuether', + 'Kulla', + 'Marchesani', + 'Ormonde', + 'Platzer', + 'Preusser', + 'Rebel', + 'Reidhead', + 'Riehm', + 'Robertshaw', + 'Runco', + 'Sandino', + 'Spare', + 'Trefethen', + 'Tribby', + 'Yamazaki', + 'Ziesmer', + 'Calamari', + 'Deyoe', + 'Marullo', + 'Neidigh', + 'Salveson', + 'Senesac', + 'Ausburn', + 'Herner', + 'Seagrave', + 'Lormand', + 'Niblock', + 'Somes', + 'Naim', + 'Murren', + 'Callander', + 'Glassco', + 'Henri', + 'Jabbar', + 'Bordes', + 'Altemose', + 'Bagnell', + 'Belloso', + 'Beougher', + 'Birchall', + 'Cantara', + 'Demetriou', + 'Galford', + 'Hast', + 'Heiny', + 'Hieronymus', + 'Jehle', + 'Khachatryan', + 'Kristof', + 'Kubas', + 'Mano', + 'Munar', + 'Ogas', + 'Riccitelli', + 'Sidman', + 'Suchocki', + 'Tortorello', + 'Trombino', + 'Vullo', + 'Badura', + 'Clerkin', + 'Criollo', + 'Dashnaw', + 'Mednick', + 'Pickrel', + 'Mawson', + 'Hockey', + 'Alo', + 'Frankland', + 'Gaby', + 'Hoda', + 'Marchena', + 'Fawbush', + 'Cowing', + 'Aydelott', + 'Dieu', + 'Rise', + 'Morten', + 'Gunby', + 'Modeste', + 'Balcerzak', + 'Cutbirth', + 'Dejoseph', + 'Desaulniers', + 'Dimperio', + 'Dubord', + 'Gruszka', + 'Haske', + 'Hehr', + 'Kolander', + 'Kusiak', + 'Lampron', + 'Mapel', + 'Montie', + 'Mumme', + 'Naramore', + 'Raffel', + 'Ruter', + 'Sawa', + 'Sencion', + 'Somogyi', + 'Ventola', + 'Zabawa', + 'Alagna', + 'Burmaster', + 'Chirco', + 'Gjerde', + 'Hilgenberg', + 'Huntress', + 'Kochel', + 'Nist', + 'Schena', + 'Toolan', + 'Wurzer', + 'Masih', + 'Ritts', + 'Rousse', + 'Buckey', + 'Sausedo', + 'Dolle', + 'Bena', + 'Franca', + 'Commins', + 'Gago', + 'Pattie', + 'Brener', + 'Verley', + 'Griffy', + 'Heiskell', + 'Osley', + 'Babula', + 'Barbone', + 'Berzins', + 'Demirjian', + 'Dietze', + 'Haseltine', + 'Heinbaugh', + 'Henneke', + 'Korba', + 'Levitz', + 'Lorenzini', + 'Mansilla', + 'Peffley', + 'Poletti', + 'Portelli', + 'Rottinghaus', + 'Scifres', + 'Stadel', + 'Stettner', + 'Swauger', + 'Vanwart', + 'Vorhies', + 'Worst', + 'Yadav', + 'Yebra', + 'Kreiter', + 'Mroczek', + 'Pennella', + 'Stangelo', + 'Suchan', + 'Weiand', + 'Widhalm', + 'Wojcicki', + 'Gutzman', + 'Griffee', + 'Konicki', + 'Moorehouse', + 'Neighbor', + 'Butte', + 'Cooter', + 'Humpherys', + 'Morrish', + 'Stockhausen', + 'Slatter', + 'Cheely', + 'Yassin', + 'Bazil', + 'Mcsween', + 'Anastos', + 'Annunziato', + 'Bora', + 'Burkitt', + 'Cino', + 'Codding', + 'Criado', + 'Firestine', + 'Goecke', + 'Golda', + 'Holloran', + 'Homen', + 'Laubscher', + 'Memmer', + 'Navejar', + 'Peraino', + 'Petrizzo', + 'Pflieger', + 'Pint', + 'Porcello', + 'Raffety', + 'Riedesel', + 'Salado', + 'Scaletta', + 'Schuring', + 'Slaydon', + 'Solecki', + 'Spomer', + 'Waldridge', + 'Zawislak', + 'Bottone', + 'Helgesen', + 'Knippel', + 'Loutzenhiser', + 'Mallinson', + 'Malnar', + 'Pethtel', + 'Sissel', + 'Thorstenson', + 'Winokur', + 'Dittmann', + 'Fencl', + 'Kernen', + 'Gath', + 'Hiney', + 'Godman', + 'Hopton', + 'Tinley', + 'Wamble', + 'Greg', + 'Garrette', + 'Acoff', + 'Ausman', + 'Burggraf', + 'Colliver', + 'Dejulio', + 'Fedorchak', + 'Finocchio', + 'Grasse', + 'Harpold', + 'Hopman', + 'Kilzer', + 'Losasso', + 'Lovallo', + 'Neumayer', + 'Purohit', + 'Reddinger', + 'Scheper', + 'Valbuena', + 'Wenzl', + 'Eilerman', + 'Galbo', + 'Haydu', + 'Vipond', + 'Wesselman', + 'Yeagle', + 'Boutelle', + 'Odonnel', + 'Morocco', + 'Speak', + 'Ruckel', + 'Cornier', + 'Burbidge', + 'Esselman', + 'Daisey', + 'Juran', + 'Henard', + 'Trench', + 'Hurry', + 'Estis', + 'Allport', + 'Beedy', + 'Blower', + 'Bogacz', + 'Caldas', + 'Carriero', + 'Garand', + 'Gonterman', + 'Harbeck', + 'Husar', + 'Lizcano', + 'Lonardo', + 'Meneely', + 'Misiewicz', + 'Pagliuca', + 'Pember', + 'Rybacki', + 'Safar', + 'Seeberger', + 'Siharath', + 'Spoerl', + 'Tattersall', + 'Birchmeier', + 'Denunzio', + 'Dustman', + 'Franchini', + 'Gettel', + 'Goldrick', + 'Goodheart', + 'Keshishyan', + 'Mcgrogan', + 'Newingham', + 'Scheier', + 'Skorupa', + 'Utech', + 'Weidenbach', + 'Chaloupka', + 'Grater', + 'Libman', + 'Recore', + 'Savona', + 'Verbeke', + 'Lunetta', + 'Schlater', + 'Staffieri', + 'Troll', + 'Leyton', + 'Peto', + 'Trella', + 'Follin', + 'Morro', + 'Woodhall', + 'Krauser', + 'Salles', + 'Brunty', + 'Wadford', + 'Shaddock', + 'Minnie', + 'Mountcastle', + 'Butter', + 'Galentine', + 'Longsworth', + 'Edgecombe', + 'Babino', + 'Printup', + 'Humbles', + 'Vessel', + 'Relford', + 'Taite', + 'Aliberti', + 'Brostrom', + 'Budlong', + 'Bykowski', + 'Coursen', + 'Darga', + 'Doutt', + 'Gomberg', + 'Greaser', + 'Hilde', + 'Hirschy', + 'Mayorquin', + 'Mcartor', + 'Mechler', + 'Mein', + 'Montville', + 'Peskin', + 'Popiel', + 'Ricciardelli', + 'Terrana', + 'Urton', + 'Cardiff', + 'Foiles', + 'Humann', + 'Pokorney', + 'Seehafer', + 'Sporer', + 'Timme', + 'Tweten', + 'Widrick', + 'Harnack', + 'Chamlee', + 'Lafountaine', + 'Lowdermilk', + 'Akel', + 'Maulden', + 'Sloman', + 'Odonald', + 'Hitchman', + 'Pendergraph', + 'Klugh', + 'Mctier', + 'Stargell', + 'Hailu', + 'Kanu', + 'Abrahamian', + 'Ackerly', + 'Belongia', + 'Cudmore', + 'Jaskolski', + 'Kedzierski', + 'Licciardi', + 'Lowenberg', + 'Meitzler', + 'Metzer', + 'Mitcheltree', + 'Nishioka', + 'Pascuzzi', + 'Pelphrey', + 'Ramones', + 'Schuchard', + 'Smithee', + 'Bignell', + 'Blaszak', + 'Borello', + 'Fiacco', + 'Garrelts', + 'Guzowski', + 'Rychlik', + 'Siebers', + 'Speziale', + 'Zauner', + 'Corell', + 'Welt', + 'Koby', + 'Auletta', + 'Bursch', + 'Luckman', + 'Vanhoesen', + 'Russian', + 'Statton', + 'Yahya', + 'Boxx', + 'Haltiwanger', + 'Redhead', + 'Mcgregory', + 'Baccari', + 'Berrey', + 'Bogden', + 'Braniff', + 'Cafarelli', + 'Clavette', + 'Corallo', + 'Dealy', + 'Gilger', + 'Gitter', + 'Goldwasser', + 'Hillesheim', + 'Hulsizer', + 'Jankovic', + 'Limburg', + 'Lopera', + 'Mcaleese', + 'Mcclintick', + 'Montealegre', + 'Mosko', + 'Nogle', + 'Ordones', + 'Papesh', + 'Peragine', + 'Picco', + 'Podraza', + 'Ras', + 'Rezek', + 'Rork', + 'Schraufnagel', + 'Scipione', + 'Terlizzi', + 'Vanblarcom', + 'Yoshino', + 'Beaverson', + 'Behunin', + 'Isch', + 'Janiga', + 'Koeppe', + 'Laurich', + 'Vondrak', + 'Walkley', + 'Hottenstein', + 'Garms', + 'Macknight', + 'Seagroves', + 'Shehata', + 'Arons', + 'Liley', + 'Pressly', + 'Cowper', + 'Branon', + 'Abdella', + 'Milord', + 'Appenzeller', + 'Ardila', + 'Belgard', + 'Boop', + 'Burbano', + 'Capitano', + 'Carrig', + 'Conrey', + 'Donica', + 'Fineberg', + 'Gemberling', + 'Harrier', + 'Hufnagle', + 'Kitner', + 'Lessing', + 'Manoukian', + 'Menk', + 'Repetto', + 'Rhinesmith', + 'Stechschulte', + 'Yep', + 'Zuhlke', + 'Abundiz', + 'Buccellato', + 'Closser', + 'Gielow', + 'Nurmi', + 'Pelka', + 'Piscitello', + 'Shoaff', + 'Champlain', + 'Conran', + 'Leidig', + 'Carel', + 'Zahid', + 'Dimitri', + 'Sapia', + 'Labauve', + 'Khalifa', + 'Gonsoulin', + 'Parrot', + 'Propps', + 'Dunnaway', + 'Cayo', + 'Mccleod', + 'Bonifas', + 'Dirkes', + 'Farruggia', + 'Gut', + 'Heacox', + 'Herrejon', + 'Ipina', + 'Keatley', + 'Kowitz', + 'Kratky', + 'Langseth', + 'Nidiffer', + 'Plimpton', + 'Riesenberg', + 'Sulewski', + 'Tabar', + 'Takara', + 'Tomassetti', + 'Tweet', + 'Weltz', + 'Youtsey', + 'Franckowiak', + 'Geffert', + 'Glawe', + 'Hillestad', + 'Ladewig', + 'Luckow', + 'Radebaugh', + 'Ransbottom', + 'Stordahl', + 'Weimar', + 'Wiegers', + 'Jowett', + 'Tomb', + 'Waitt', + 'Beaudreau', + 'Notter', + 'Rijo', + 'Denike', + 'Mam', + 'Vent', + 'Gamage', + 'Carre', + 'Childrey', + 'Heaven', + 'Forge', + 'Beckom', + 'Collick', + 'Bovell', + 'Hardimon', + 'Shells', + 'Bolf', + 'Canete', + 'Cozby', + 'Dunlavey', + 'Febo', + 'Lamke', + 'Lant', + 'Larned', + 'Leiss', + 'Lofthouse', + 'Marohn', + 'Stradling', + 'Subramaniam', + 'Vitug', + 'Ziccardi', + 'Akamine', + 'Bellissimo', + 'Bottini', + 'Braund', + 'Cavasos', + 'Heltsley', + 'Landstrom', + 'Lisiecki', + 'Navejas', + 'Sobczyk', + 'Trela', + 'Yablonski', + 'Yocham', + 'Fier', + 'Laiche', + 'Zenor', + 'Grew', + 'Naval', + 'Garratt', + 'Sako', + 'Zollicoffer', + 'Momon', + 'Bensman', + 'Cirincione', + 'Dimitrov', + 'Domeier', + 'Gaska', + 'Gensel', + 'Gernert', + 'Groot', + 'Guarisco', + 'Llorente', + 'Ludemann', + 'Moisan', + 'Muzio', + 'Neiswender', + 'Ottaway', + 'Paslay', + 'Readinger', + 'Skok', + 'Spittle', + 'Sweany', + 'Tanzi', + 'Upadhyay', + 'Valone', + 'Varas', + 'Benecke', + 'Faulstich', + 'Hebda', + 'Jobst', + 'Schleis', + 'Shuart', + 'Treinen', + 'Fok', + 'Dentler', + 'Ginty', + 'Ronda', + 'Tess', + 'Scantlin', + 'Kham', + 'Murin', + 'Faubert', + 'Ocarroll', + 'Maranda', + 'Gadsby', + 'Mouse', + 'Lunden', + 'Asquith', + 'Batley', + 'Bazzle', + 'Hooke', + 'Macneal', + 'Desnoyers', + 'Verdier', + 'Biglow', + 'Leverson', + 'Becherer', + 'Cecilio', + 'Correale', + 'Ehinger', + 'Erney', + 'Fassnacht', + 'Humpal', + 'Korpela', + 'Kratt', + 'Kunes', + 'Lockyer', + 'Macho', + 'Manfredo', + 'Maturino', + 'Raineri', + 'Seiger', + 'Stant', + 'Tecson', + 'Tempest', + 'Traverse', + 'Vonk', + 'Wormington', + 'Yeske', + 'Erichsen', + 'Fiorelli', + 'Fouty', + 'Hodgkiss', + 'Lindenbaum', + 'Matusik', + 'Mazzocco', + 'Oldani', + 'Ronca', + 'Amero', + 'Ormand', + 'Cagley', + 'Teutsch', + 'Likins', + 'Blurton', + 'Lapier', + 'Rensch', + 'Howitt', + 'Kady', + 'Broce', + 'Gaba', + 'Summerson', + 'Faure', + 'Densley', + 'Matkins', + 'Boleware', + 'Rahming', + 'Degrate', + 'Broaden', + 'Barbian', + 'Brancaccio', + 'Dimiceli', + 'Doukas', + 'Fredell', + 'Fritchman', + 'Gahr', + 'Geerdes', + 'Heidrick', + 'Hernon', + 'Ipsen', + 'Koci', + 'Lato', + 'Lyng', + 'Montella', + 'Petraglia', + 'Redlinger', + 'Riedlinger', + 'Rodier', + 'Shenton', + 'Smigiel', + 'Spanbauer', + 'Swetland', + 'Sypolt', + 'Taubert', + 'Wallander', + 'Willers', + 'Ziller', + 'Bielak', + 'Careaga', + 'Droddy', + 'Girardot', + 'Kanouse', + 'Perusse', + 'Schwier', + 'Velo', + 'Westrum', + 'Bouza', + 'Calverley', + 'Shupert', + 'Simi', + 'Zieger', + 'Nicole', + 'Fergeson', + 'Guerrant', + 'Tongue', + 'Amison', + 'Darius', + 'Banasiak', + 'Cocca', + 'Dannemiller', + 'Frommer', + 'Guardia', + 'Herl', + 'Lippa', + 'Nappo', + 'Olaya', + 'Ozburn', + 'Patry', + 'Pontiff', + 'Rauth', + 'Reier', + 'Rolfs', + 'Sassone', + 'Servidio', + 'Shough', + 'Tencza', + 'Ernster', + 'Helminiak', + 'Mcmanamon', + 'Ottens', + 'Vinh', + 'Bula', + 'Elza', + 'Serres', + 'Holan', + 'Wetherill', + 'Balis', + 'Schexnider', + 'Harral', + 'Dulany', + 'Webley', + 'Addleman', + 'Antonopoulos', + 'Badman', + 'Czerwonka', + 'Deweerd', + 'Donaghey', + 'Duszynski', + 'Firkus', + 'Foell', + 'Goyne', + 'Hattabaugh', + 'Herbel', + 'Liebelt', + 'Lovera', + 'Quenneville', + 'Ramic', + 'Rissmiller', + 'Schlag', + 'Selover', + 'Seyer', + 'Stangeland', + 'Stutesman', + 'Suminski', + 'Sweger', + 'Tetlow', + 'Thornbury', + 'Votava', + 'Weberg', + 'Canniff', + 'Evetts', + 'Gutterman', + 'Kasparek', + 'Krenzer', + 'Luckenbaugh', + 'Mainwaring', + 'Vanderweide', + 'Balladares', + 'Riesterer', + 'Salmen', + 'Mirando', + 'Rockman', + 'Warnes', + 'Crispell', + 'Corban', + 'Chrystal', + 'Barlowe', + 'Perot', + 'Ka', + 'Stockett', + 'Montfort', + 'Reagor', + 'Coote', + 'Christon', + 'Dor', + 'Apt', + 'Bandel', + 'Bibbee', + 'Brunkhorst', + 'Dexheimer', + 'Disharoon', + 'Engelstad', + 'Glaza', + 'Locey', + 'Loughney', + 'Minotti', + 'Posa', + 'Renzulli', + 'Schlauch', + 'Shadix', + 'Sloboda', + 'Topor', + 'Vacha', + 'Cerulli', + 'Ciaravino', + 'Cisek', + 'Congrove', + 'Domzalski', + 'Fleitas', + 'Helfand', + 'Lehnen', + 'Moleski', + 'Walski', + 'Dazey', + 'Mckellips', + 'Kanne', + 'Deguire', + 'Macmurray', + 'Marcelli', + 'Creach', + 'Antrobus', + 'Hykes', + 'Barriere', + 'Avinger', + 'Handford', + 'Beaufort', + 'Abend', + 'Bozzi', + 'Burnsworth', + 'Crosthwaite', + 'Eilert', + 'Frigon', + 'Hanbury', + 'Hoilman', + 'Isaksen', + 'Juday', + 'Legarda', + 'Mcgourty', + 'Mittler', + 'Olkowski', + 'Pau', + 'Pescador', + 'Pinkerman', + 'Renno', + 'Rescigno', + 'Salsgiver', + 'Schlanger', + 'Sobek', + 'Stasi', + 'Talaga', + 'Tish', + 'Tropea', + 'Umphress', + 'Weisheit', + 'Bartolini', + 'Dassow', + 'Ferullo', + 'Fetherolf', + 'Kimery', + 'Kurihara', + 'Schneiter', + 'Sramek', + 'Swier', + 'Weinzierl', + 'Karrer', + 'Hurta', + 'Lodico', + 'Conkright', + 'Sandvik', + 'Pash', + 'Pinell', + 'Dougal', + 'Burnet', + 'Hoe', + 'Rann', + 'Curvin', + 'Route', + 'Outler', + 'Corprew', + 'Berhe', + 'Eleby', + 'Acoba', + 'Ante', + 'Baio', + 'Befort', + 'Brueck', + 'Chevere', + 'Ciani', + 'Farnes', + 'Hamar', + 'Hirschhorn', + 'Imbrogno', + 'Kegg', + 'Leever', + 'Mesker', + 'Nodal', + 'Olveda', + 'Paletta', + 'Pilant', + 'Rissman', + 'Sebold', + 'Siebel', + 'Smejkal', + 'Stai', + 'Vanderkolk', + 'Allday', + 'Canupp', + 'Dieck', + 'Hinders', + 'Karcz', + 'Shomaker', + 'Tuinstra', + 'Urquizo', + 'Wiltgen', + 'Withem', + 'Yanda', + 'Blizard', + 'Christenbury', + 'Helser', + 'Jing', + 'Stave', + 'Waddill', + 'Mairena', + 'Rebert', + 'Gara', + 'Shipes', + 'Hartsoe', + 'Bargeron', + 'Arne', + 'Ebrahim', + 'Basha', + 'Rozar', + 'Venter', + 'Mounger', + 'Marsalis', + 'Gildon', + 'Antkowiak', + 'Brus', + 'Cicalese', + 'Einspahr', + 'Faucheux', + 'Frix', + 'Gateley', + 'Hamberger', + 'Holdorf', + 'Hollibaugh', + 'Junod', + 'Keaveny', + 'Knechtel', + 'Kuffel', + 'Mcwhirt', + 'Navis', + 'Neave', + 'Rackers', + 'Romagnoli', + 'Shawhan', + 'Valvano', + 'Vina', + 'Wielgus', + 'Wojtaszek', + 'Bartnik', + 'Fiebelkorn', + 'Gertsch', + 'Morgenthaler', + 'Nambo', + 'Nemmers', + 'Nihart', + 'Nilges', + 'Pulgarin', + 'Recktenwald', + 'Vandenbrink', + 'Wion', + 'Cundy', + 'Burby', + 'Cu', + 'Vansciver', + 'Herne', + 'Doughtie', + 'Cowdery', + 'Woodle', + 'Lafosse', + 'Hodgens', + 'Mckune', + 'Car', + 'Callens', + 'Corsey', + 'Brimage', + 'Westry', + 'Arismendez', + 'Benenati', + 'Brine', + 'Brookbank', + 'Burfield', + 'Charnock', + 'Copado', + 'Demilio', + 'Elvira', + 'Fantini', + 'Ferko', + 'Flanagin', + 'Gotto', + 'Hartsough', + 'Heckart', + 'Herskowitz', + 'Hoene', + 'Ishibashi', + 'Kysar', + 'Leaverton', + 'Longfield', + 'Mischel', + 'Musleh', + 'Neyra', + 'Obeirne', + 'Ostrum', + 'Pedretti', + 'Pilkerton', + 'Plasse', + 'Reesor', + 'Roznowski', + 'Rusinko', + 'Sickle', + 'Spiteri', + 'Stash', + 'Syracuse', + 'Trachsel', + 'Weinand', + 'Gruenberg', + 'Gutkowski', + 'Morella', + 'Morneault', + 'Slivinski', + 'Blessinger', + 'Taketa', + 'Hussaini', + 'Obeid', + 'Seebeck', + 'Spayd', + 'Keasling', + 'Famularo', + 'Carne', + 'Lacosse', + 'Morino', + 'Gutzmer', + 'Spinola', + 'Deahl', + 'Crumm', + 'Folley', + 'Lennard', + 'Rowson', + 'Pickron', + 'Union', + 'Abraha', + 'Yohannes', + 'Whidbee', + 'Mccaster', + 'Batzel', + 'Borowy', + 'Disanti', + 'Druck', + 'Elsbury', + 'Eschmann', + 'Fehn', + 'Flesner', + 'Grawe', + 'Haapala', + 'Helvie', + 'Hudy', + 'Joswick', + 'Kilcullen', + 'Mabus', + 'Marzo', + 'Obradovich', + 'Oriordan', + 'Phy', + 'Scarff', + 'Schappert', + 'Scire', + 'Vandevander', + 'Weyland', + 'Anstey', + 'Feeback', + 'Komarek', + 'Kyllo', + 'Manivong', + 'Timberman', + 'Tinkey', + 'Zempel', + 'Haselhorst', + 'Herberg', + 'Laris', + 'Morter', + 'Fredman', + 'Reny', + 'Ferrall', + 'Silverthorne', + 'Shuttlesworth', + 'Stigers', + 'Koker', + 'Mollette', + 'Mansel', + 'Chrisp', + 'Glymph', + 'Preyer', + 'Worlds', + 'Arutyunyan', + 'Carrizosa', + 'Dambrosia', + 'Dantuono', + 'Delduca', + 'Florencio', + 'Garafola', + 'Habermehl', + 'Hanaway', + 'Harmes', + 'Heinonen', + 'Hellstrom', + 'Herzer', + 'Klahr', + 'Kobler', + 'Korner', + 'Lancia', + 'Leask', + 'Ledo', + 'Manzanarez', + 'Myung', + 'Prestigiacomo', + 'Serpe', + 'Tonche', + 'Ventrella', + 'Walrod', + 'Warga', + 'Wasmer', + 'Weins', + 'Zaccaro', + 'Bartus', + 'Fiumara', + 'Incorvaia', + 'Khatun', + 'Kisamore', + 'Riesen', + 'Santry', + 'Schmierer', + 'Talamo', + 'Zaccone', + 'Liddick', + 'Mcclune', + 'Hade', + 'Calcutt', + 'Gillet', + 'Husein', + 'Be', + 'Lavell', + 'Veley', + 'Buckholtz', + 'Naves', + 'Debrosse', + 'Palms', + 'Lacewell', + 'Tates', + 'Tekle', + 'Golphin', + 'Asleson', + 'Bartlebaugh', + 'Benter', + 'Bielefeld', + 'Cappetta', + 'Hanback', + 'Heeg', + 'Helf', + 'Hibberd', + 'Holsworth', + 'Kowalchuk', + 'Kruczek', + 'Lieurance', + 'Markwood', + 'Muckey', + 'Rasey', + 'Rautio', + 'Salek', + 'Schwaller', + 'Scibilia', + 'Speltz', + 'Stopper', + 'Struckman', + 'Surowiec', + 'Texter', + 'Venturi', + 'Wolfenden', + 'Zortman', + 'Dehler', + 'Gillogly', + 'Hoelzel', + 'Iida', + 'Paparella', + 'Petrea', + 'Pflaum', + 'Spampinato', + 'Spaur', + 'Umbaugh', + 'Cerney', + 'Athens', + 'Salvas', + 'Gardinier', + 'Ammar', + 'Arns', + 'Calvi', + 'Palazzola', + 'Starlin', + 'Quave', + 'Rhame', + 'Gulliford', + 'Nettle', + 'Picken', + 'Warde', + 'Pelissier', + 'Mcteer', + 'Freeny', + 'Tappin', + 'Bromell', + 'People', + 'Carthen', + 'Battenfield', + 'Bunte', + 'Estrin', + 'Fitzner', + 'Flattery', + 'Hlavacek', + 'Holecek', + 'Jorstad', + 'Jurczak', + 'Kraszewski', + 'Lencioni', + 'Mamula', + 'Mater', + 'Petrakis', + 'Safranek', + 'Santorelli', + 'Speyer', + 'Waterworth', + 'Worner', + 'Antonellis', + 'Codispoti', + 'Docken', + 'Economos', + 'Petrilla', + 'Puccinelli', + 'Rondinelli', + 'Leibel', + 'Santoya', + 'Hader', + 'Yeakley', + 'Dowse', + 'Hattan', + 'Lia', + 'Emel', + 'Corse', + 'Danes', + 'Rambin', + 'Dura', + 'Kyne', + 'Sanderford', + 'Mincer', + 'Rawl', + 'Staves', + 'Mccleave', + 'Faniel', + 'Abeln', + 'Asta', + 'Beymer', + 'Cresap', + 'Cryderman', + 'Gutwein', + 'Kaszuba', + 'Maland', + 'Marella', + 'Mcmannis', + 'Molenaar', + 'Olivarria', + 'Panfil', + 'Pieratt', + 'Ramthun', + 'Resurreccion', + 'Rosander', + 'Rostad', + 'Sallas', + 'Santone', + 'Schey', + 'Shasteen', + 'Spalla', + 'Sui', + 'Tannous', + 'Tarman', + 'Trayer', + 'Wolman', + 'Chausse', + 'Debacker', + 'Dozal', + 'Hach', + 'Klossner', + 'Kruchten', + 'Mahowald', + 'Rosenlund', + 'Steffenhagen', + 'Vanmaanen', + 'Wildasin', + 'Winiecki', + 'Dilauro', + 'Wygal', + 'Cadmus', + 'Smallman', + 'Sear', + 'Berch', + 'Nabor', + 'Bro', + 'Storr', + 'Goynes', + 'Chestang', + 'Alvillar', + 'Arya', + 'Aton', + 'Bors', + 'Brydon', + 'Castagno', + 'Catena', + 'Catterson', + 'Chhun', + 'Delrossi', + 'Garnsey', + 'Harbeson', + 'Holum', + 'Iglesia', + 'Kleen', + 'Lavallie', + 'Lossing', + 'Miyata', + 'Myszka', + 'Peth', + 'Pyka', + 'Radler', + 'Roggenkamp', + 'Sarra', + 'Schmeltz', + 'Schreifels', + 'Schrimpf', + 'Scrogham', + 'Sieminski', + 'Singson', + 'Stichter', + 'Vajda', + 'Vilardo', + 'Ziff', + 'Cegielski', + 'Fanara', + 'Mefferd', + 'Polanski', + 'Reining', + 'Roggow', + 'Sassi', + 'Wagenknecht', + 'Roadcap', + 'Tuman', + 'Demesa', + 'Surita', + 'Armando', + 'Macks', + 'Megan', + 'Angello', + 'Bosher', + 'Neugent', + 'Croslin', + 'Bumpas', + 'Gladman', + 'Demmons', + 'Mcnairy', + 'Sermons', + 'Okonkwo', + 'Alvira', + 'Barfuss', + 'Bersch', + 'Bustin', + 'Ciriello', + 'Cords', + 'Cuddeback', + 'Debono', + 'Delosh', + 'Haeger', + 'Ida', + 'Kneer', + 'Koppen', + 'Kottwitz', + 'Laib', + 'Matsushita', + 'Mckone', + 'Meester', + 'Ohashi', + 'Pickert', + 'Risso', + 'Vannice', + 'Vargason', + 'Vorpahl', + 'Gluth', + 'Goossens', + 'Kloeppel', + 'Krolczyk', + 'Lequire', + 'Nila', + 'Savoia', + 'Wassmer', + 'Bianca', + 'Rousselle', + 'Wittler', + 'Gillean', + 'Cervi', + 'Fremin', + 'Vanzanten', + 'Varvel', + 'Sween', + 'Peron', + 'Trudo', + 'Welford', + 'Scovil', + 'Beazer', + 'Cohill', + 'Estime', + 'Alcalde', + 'Bugay', + 'Bushard', + 'Dethloff', + 'Gahn', + 'Gronau', + 'Hogston', + 'Kleinfelter', + 'Ksiazek', + 'Lyness', + 'Marak', + 'Munafo', + 'Noorani', + 'Plonski', + 'Pontarelli', + 'Presas', + 'Ringenberg', + 'Sabillon', + 'Schaut', + 'Shankland', + 'Sheil', + 'Shugrue', + 'Soter', + 'Stankovich', + 'Arrants', + 'Boeckmann', + 'Boothroyd', + 'Dysinger', + 'Gersh', + 'Monnig', + 'Scheiderer', + 'Slifka', + 'Vilardi', + 'Podell', + 'Tarallo', + 'Goodroe', + 'Sardinha', + 'Blish', + 'Califf', + 'Dorion', + 'Dougall', + 'Hamza', + 'Boggus', + 'Mccan', + 'Branscomb', + 'Baatz', + 'Bendix', + 'Hartstein', + 'Hechler', + 'Komatsu', + 'Kooiman', + 'Loghry', + 'Lorson', + 'Mcgoff', + 'Moga', + 'Monsees', + 'Nigg', + 'Pacitti', + 'Shiffman', + 'Shoupe', + 'Snarski', + 'Vrba', + 'Wilmeth', + 'Yurchak', + 'Budney', + 'Estok', + 'Knipple', + 'Krzywicki', + 'Librizzi', + 'Obringer', + 'Poliquin', + 'Severtson', + 'Vecchiarelli', + 'Zelazny', + 'Eis', + 'Wildeman', + 'Gatt', + 'Gordin', + 'Dusenbury', + 'Prew', + 'Mander', + 'Tine', + 'Debarr', + 'Bann', + 'Mcguirt', + 'Vanloan', + 'Basdeo', + 'Kosh', + 'Bertha', + 'Mcglothen', + 'Youman', + 'Hallums', + 'Mcfield', + 'Asano', + 'Barbo', + 'Braver', + 'Bua', + 'Buetow', + 'Buttke', + 'Estela', + 'Kauk', + 'Kosmicki', + 'Kuecker', + 'Lahm', + 'Lienhard', + 'Lombera', + 'Menken', + 'Niederhauser', + 'Norcia', + 'Petrelli', + 'Phong', + 'Piontkowski', + 'Prihoda', + 'Raffo', + 'Sherpa', + 'Shinsky', + 'Skoczylas', + 'Sosinski', + 'Sua', + 'Sur', + 'Thorndike', + 'Trease', + 'Wessler', + 'Witting', + 'Ackroyd', + 'Bartnick', + 'Dziuba', + 'Lisko', + 'Muradyan', + 'Pistilli', + 'Riechers', + 'Saxman', + 'Rodi', + 'Venables', + 'Holway', + 'Vargus', + 'Oley', + 'Delmont', + 'Fuster', + 'Wyndham', + 'Whittenberg', + 'Chustz', + 'Swilling', + 'Moncure', + 'Housey', + 'Mckiver', + 'Shelvin', + 'Aslin', + 'Begeman', + 'Capek', + 'Christlieb', + 'Colasanti', + 'Daidone', + 'Detlefsen', + 'Elsass', + 'Faus', + 'Francke', + 'Hensarling', + 'Hollmann', + 'Isaacks', + 'Kocis', + 'Kofman', + 'Kwiatek', + 'Osterkamp', + 'Pickar', + 'Prellwitz', + 'Ramo', + 'Steenson', + 'Tomasulo', + 'Weinreb', + 'Wiard', + 'Ambs', + 'Baglio', + 'Frayre', + 'Hisaw', + 'Justman', + 'Morrical', + 'Sherfey', + 'Gera', + 'Ilgenfritz', + 'Silos', + 'Boge', + 'Darocha', + 'Hennon', + 'Hendriks', + 'Purrington', + 'Eunice', + 'Kirks', + 'Barbar', + 'Guichard', + 'Bonny', + 'Lobban', + 'Winrow', + 'Alavi', + 'Binner', + 'Canan', + 'Ciullo', + 'Cyran', + 'Doolen', + 'Enquist', + 'Fatzinger', + 'Forsell', + 'Harnisch', + 'Hirose', + 'Lunz', + 'Mcbrearty', + 'Mcgavin', + 'Minkin', + 'Ralphs', + 'Ruegsegger', + 'Shetter', + 'Slagter', + 'Tyminski', + 'Ubben', + 'Vanderschaaf', + 'Wigfield', + 'Zellman', + 'Bettenhausen', + 'Busker', + 'Jabs', + 'Mishkin', + 'Sturdy', + 'Vanstone', + 'Tierce', + 'Cormican', + 'Mazzucco', + 'Buenger', + 'Gallier', + 'Duma', + 'Rainbow', + 'Herlong', + 'Chriswell', + 'Litsey', + 'Wyke', + 'Kissoon', + 'Sesler', + 'Farve', + 'Lalanne', + 'Myhand', + 'Heggs', + 'Andujo', + 'Arcilla', + 'Bult', + 'Caponigro', + 'Commerford', + 'Ditmars', + 'Dressen', + 'Eggemeyer', + 'Forstner', + 'From', + 'Heldreth', + 'Hevia', + 'Leiphart', + 'Mastrocola', + 'Mcanelly', + 'Mccrillis', + 'Mellick', + 'Mogle', + 'Mummey', + 'Nishiyama', + 'Nordine', + 'Picinich', + 'Rafiq', + 'Savo', + 'Selvig', + 'Sestak', + 'Shafran', + 'Smithhart', + 'Soltani', + 'Stillion', + 'Szuch', + 'Tigert', + 'Trine', + 'Un', + 'Brest', + 'Callari', + 'Jaskowiak', + 'Maneval', + 'Sarchet', + 'Szuba', + 'Taubman', + 'Wandel', + 'Blok', + 'Pasquarello', + 'Sava', + 'Diekman', + 'Blight', + 'Lovgren', + 'Clemson', + 'Lince', + 'Kanady', + 'Whipps', + 'Coren', + 'Coye', + 'Patman', + 'Souffrant', + 'Bloodsaw', + 'Amano', + 'Cassaday', + 'Cutillo', + 'Dayrit', + 'Deringer', + 'Duwe', + 'Favazza', + 'Fennema', + 'Hackleman', + 'Harders', + 'Imperiale', + 'Kano', + 'Kingma', + 'Meuser', + 'Neiger', + 'Neitz', + 'Nied', + 'Prows', + 'Riss', + 'Rotundo', + 'Scheurich', + 'Stopa', + 'Tonks', + 'Veen', + 'Volante', + 'Maerz', + 'Nunnelley', + 'Sommerfeldt', + 'Spoonemore', + 'Wechter', + 'Wehrli', + 'Ackert', + 'Begun', + 'Dreyfuss', + 'Frezza', + 'Mako', + 'Nagao', + 'Lassetter', + 'Linse', + 'Raum', + 'Graca', + 'Enslow', + 'Bruff', + 'Hodgkin', + 'Coone', + 'Trippett', + 'Tippitt', + 'Sumerlin', + 'Carelock', + 'Whitelow', + 'Beightol', + 'Cappadona', + 'Carrizal', + 'Clendaniel', + 'Cresci', + 'Dietzman', + 'Figge', + 'Heyde', + 'Jarema', + 'Kyllonen', + 'Laminack', + 'Luddy', + 'Monical', + 'Mula', + 'Picotte', + 'Sandiego', + 'Seki', + 'Senner', + 'Starkman', + 'Stassi', + 'Stuckert', + 'Wiers', + 'Wieting', + 'Ziska', + 'Ardelean', + 'Hulslander', + 'Loewenstein', + 'Mearns', + 'Roese', + 'Sweaney', + 'Winick', + 'Zaring', + 'Farry', + 'Dulle', + 'Gunnerson', + 'Duden', + 'Arts', + 'Lame', + 'Mcquerry', + 'Smiles', + 'Pennick', + 'Adderly', + 'Becka', + 'Bluemel', + 'Bocek', + 'Bouwens', + 'Deren', + 'Dewitz', + 'Doland', + 'Ewton', + 'Funnell', + 'Gavel', + 'Haidar', + 'Kalkbrenner', + 'Kawashima', + 'Kueker', + 'Lutze', + 'Macareno', + 'Nenninger', + 'Schone', + 'Seever', + 'Sexauer', + 'Sibilia', + 'Sperrazza', + 'Vanderhoef', + 'Vanoss', + 'Werre', + 'Wotton', + 'Behney', + 'Bossart', + 'Ellithorpe', + 'Eyrich', + 'Fosco', + 'Fulginiti', + 'Grumbles', + 'Hoeger', + 'Kizziah', + 'Kloiber', + 'Kudo', + 'Majcher', + 'Stickels', + 'Stoler', + 'Umholtz', + 'Vasallo', + 'Wenker', + 'Wittmeyer', + 'Telesco', + 'Jha', + 'Maulding', + 'Campton', + 'Verble', + 'Mclure', + 'Bernardin', + 'Eison', + 'Coffie', + 'Ceesay', + 'Balakrishnan', + 'Barich', + 'Bigman', + 'Blumenstein', + 'Bonafede', + 'Cebulski', + 'Chesbro', + 'Cuaresma', + 'Demarino', + 'Derienzo', + 'Donmoyer', + 'Fairall', + 'Gelpi', + 'Giambra', + 'Hasselman', + 'Highlander', + 'Hunker', + 'Iyengar', + 'Kulaga', + 'Kuznicki', + 'Labus', + 'Limbert', + 'Molchan', + 'Neuharth', + 'Overgaard', + 'Paszkiewicz', + 'Plescia', + 'Redcay', + 'Ritzer', + 'Smirnov', + 'Valiquette', + 'Vannortwick', + 'Warstler', + 'Yantz', + 'Beardall', + 'Cimmino', + 'Crnkovich', + 'Konishi', + 'Kosowski', + 'Ragen', + 'Sebert', + 'Valla', + 'Venancio', + 'Maltez', + 'Skehan', + 'Abrantes', + 'Colfer', + 'Beman', + 'Wilhelmsen', + 'Wilking', + 'Rorer', + 'Shutes', + 'Albany', + 'Wearing', + 'Assefa', + 'Angeloni', + 'Bisher', + 'Blancett', + 'Briel', + 'Chiara', + 'Clearman', + 'Dengel', + 'Detert', + 'Fadely', + 'Flinders', + 'Garguilo', + 'Goes', + 'Hakimian', + 'Henehan', + 'Homewood', + 'Kalla', + 'Keirn', + 'Kerwood', + 'Laflam', + 'Lynskey', + 'Minhas', + 'Mow', + 'Olk', + 'Ostergaard', + 'Palecek', + 'Poirrier', + 'Raudenbush', + 'Schlottman', + 'Shatz', + 'Sieloff', + 'Stikeleather', + 'Swavely', + 'Tapanes', + 'Teehan', + 'Wendorff', + 'Wollner', + 'Bichsel', + 'Brandenburger', + 'Demattia', + 'Eggebrecht', + 'Koelzer', + 'Landrigan', + 'Morsch', + 'Pittinger', + 'Rewerts', + 'Schopf', + 'Tetro', + 'Westenberger', + 'Kieft', + 'Overy', + 'Cutrona', + 'Misa', + 'Erich', + 'Swapp', + 'Welchel', + 'Messa', + 'Ala', + 'Witbeck', + 'Mothershead', + 'Stofer', + 'Mcneice', + 'Ayling', + 'Zakaria', + 'Bu', + 'Rauf', + 'Richbourg', + 'Fristoe', + 'Dorch', + 'Mcclarin', + 'Privott', + 'Bonsu', + 'Ayson', + 'Bifulco', + 'Brungard', + 'Bub', + 'Budzynski', + 'Chizmar', + 'Coriz', + 'Corser', + 'Daughdrill', + 'Delre', + 'Elfers', + 'Fabrizi', + 'Gunawan', + 'Haecker', + 'Hammac', + 'Handwerk', + 'Larcom', + 'Liera', + 'Littlewood', + 'Luikart', + 'Pasquarella', + 'Radman', + 'Ranft', + 'Rigas', + 'Santin', + 'Sorbello', + 'Tayag', + 'Ureste', + 'Weidinger', + 'Yerena', + 'Aase', + 'Galyen', + 'Halferty', + 'Hindley', + 'Kunath', + 'Laprairie', + 'Oza', + 'Stohler', + 'Tokarczyk', + 'Yusupov', + 'Nogueras', + 'Jersey', + 'Eastes', + 'Agron', + 'Boso', + 'Kender', + 'Couse', + 'Moreta', + 'Larrow', + 'Degrace', + 'Sonier', + 'Tisdel', + 'Creque', + 'Esther', + 'Girtman', + 'Seraphin', + 'Wesby', + 'Kargbo', + 'Adjei', + 'Angeline', + 'Biby', + 'Brucks', + 'Bucaro', + 'Farman', + 'Gerdeman', + 'Hodsdon', + 'Hoying', + 'Kasperek', + 'Keinath', + 'Kidman', + 'Kleier', + 'Kuban', + 'Lacko', + 'Latourette', + 'Leffert', + 'Leonhart', + 'Mathern', + 'Ploss', + 'Poblano', + 'Raigoza', + 'Santor', + 'Schmitzer', + 'Sirico', + 'Skalsky', + 'Spreen', + 'Standlee', + 'Vonbargen', + 'Cederberg', + 'Cornforth', + 'Dercole', + 'Diblasio', + 'Fleer', + 'Fredlund', + 'Gehris', + 'Guck', + 'Lannen', + 'Lurz', + 'Mazzaferro', + 'Neukam', + 'Rookstool', + 'Scharrer', + 'Sevey', + 'Sicairos', + 'Skrocki', + 'Sneeringer', + 'Stefanowicz', + 'Zuleger', + 'Harmel', + 'Sendejo', + 'Bearer', + 'Shur', + 'Weers', + 'Norell', + 'Plotnick', + 'Cecchi', + 'Gandia', + 'Bastone', + 'Tole', + 'Tramell', + 'Willock', + 'Rhome', + 'Curington', + 'Rapley', + 'Hazley', + 'Todman', + 'Lathon', + 'Alperin', + 'Axtman', + 'Boeke', + 'Butson', + 'Cestaro', + 'Cosgriff', + 'Docter', + 'Eblin', + 'Filsinger', + 'Franzone', + 'Gareau', + 'Garfinkle', + 'Gatch', + 'Germosen', + 'Grzywacz', + 'Huesman', + 'Kasel', + 'Kazan', + 'Manalang', + 'Marando', + 'Marchio', + 'Massimino', + 'Mcneer', + 'Menger', + 'Milanese', + 'Monrreal', + 'Moretto', + 'Mulvany', + 'Petkus', + 'Rehling', + 'Rubbo', + 'Rudnik', + 'Settlemire', + 'Treon', + 'Yaklin', + 'Zittel', + 'Betzold', + 'Bohlin', + 'Churilla', + 'Conrath', + 'Ozbun', + 'Sciuto', + 'Stitz', + 'Sweigert', + 'Tamanaha', + 'Wallgren', + 'Eplin', + 'Ion', + 'Liford', + 'Orendorff', + 'Wootan', + 'Carmical', + 'Mince', + 'Stormes', + 'Lantry', + 'Sportsman', + 'Corron', + 'Padia', + 'Cunnington', + 'Pitta', + 'Ori', + 'Obara', + 'Gaultney', + 'Vanlue', + 'Emmitt', + 'Roddey', + 'Payen', + 'Elmi', + 'Culmer', + 'Mealing', + 'Allegra', + 'Bano', + 'Batterman', + 'Bickell', + 'Dager', + 'Drach', + 'Duchesneau', + 'Erdos', + 'Fedorko', + 'Fluhr', + 'Gassmann', + 'Gillig', + 'Goedert', + 'Golomb', + 'Hatler', + 'Jalali', + 'Joosten', + 'Koke', + 'Lausch', + 'Leisner', + 'Mallinger', + 'Marsolek', + 'Mashek', + 'Ognibene', + 'Oishi', + 'Outman', + 'Paganelli', + 'Passino', + 'Petrak', + 'Rosenwald', + 'Schroader', + 'Stehman', + 'Tenuta', + 'Todt', + 'Tritz', + 'Boerman', + 'Doeden', + 'Etcheverry', + 'Grissinger', + 'Gruenewald', + 'Lijewski', + 'Marcom', + 'Niebauer', + 'Rukavina', + 'Sakuma', + 'Woehrle', + 'Amores', + 'Krammes', + 'Shontz', + 'Bunning', + 'Widdowson', + 'Blankenburg', + 'Goans', + 'Longan', + 'Aboud', + 'Michelli', + 'Rivere', + 'Colla', + 'Lory', + 'Lougheed', + 'Wadel', + 'Chalkley', + 'Gaubert', + 'Goodlin', + 'Bommer', + 'Abbs', + 'Rashad', + 'Malachi', + 'Abrigo', + 'Akre', + 'Antolik', + 'Bachner', + 'Blegen', + 'Cona', + 'Diantonio', + 'Emde', + 'Enrico', + 'Follette', + 'Hagarty', + 'Hanser', + 'Hulsman', + 'Jelinski', + 'Kalisz', + 'Kolek', + 'Kough', + 'Ninneman', + 'Offield', + 'Perezgarcia', + 'Plude', + 'Printy', + 'Rosengrant', + 'Salminen', + 'Schamberger', + 'Teall', + 'Zipfel', + 'Bickler', + 'Casanas', + 'Holtzapple', + 'Sachdeva', + 'Scharnhorst', + 'Schnack', + 'Grode', + 'Strough', + 'Teare', + 'Korona', + 'Creelman', + 'Simper', + 'Marett', + 'Nadeem', + 'Pollet', + 'Eduardo', + 'Chipley', + 'Vanrossum', + 'Fabio', + 'Colona', + 'Whirley', + 'Hider', + 'Plaskett', + 'Trabue', + 'Gibert', + 'Cabiness', + 'Loyal', + 'Rayson', + 'Aloia', + 'Aukerman', + 'Broxterman', + 'Cada', + 'Catalanotto', + 'Condos', + 'Corriher', + 'Eliopoulos', + 'Furia', + 'Girolamo', + 'Haese', + 'Israelson', + 'Jaworowski', + 'Jirik', + 'Kalmar', + 'Leipold', + 'Lemmo', + 'Loja', + 'Loughmiller', + 'Matelski', + 'Mcrorie', + 'Moeckel', + 'Naill', + 'Raczka', + 'Rathgeber', + 'Shamoun', + 'Shannahan', + 'Simler', + 'Stamer', + 'Stonehocker', + 'Twersky', + 'Voeltz', + 'Willets', + 'Wolgamott', + 'Yamin', + 'Acri', + 'Dalgleish', + 'Ehrenreich', + 'Huish', + 'Huxley', + 'Pinkstaff', + 'Rincones', + 'Saric', + 'Shreiner', + 'Stitely', + 'Tippets', + 'Vanamburg', + 'Zbikowski', + 'Sharrett', + 'Suther', + 'Renta', + 'Balles', + 'Florentine', + 'Chrisley', + 'Offner', + 'Matheus', + 'Akens', + 'Dugue', + 'Rigaud', + 'Mohamud', + 'Magloire', + 'Stigger', + 'Andrist', + 'Chaudoin', + 'Clos', + 'Cragin', + 'Dinius', + 'Duignan', + 'Elk', + 'Frenz', + 'Frogge', + 'Giammarino', + 'Hackl', + 'Jaeckel', + 'Knieriem', + 'Lajara', + 'Lisak', + 'Luxton', + 'Merriott', + 'Montini', + 'Olender', + 'Orebaugh', + 'Orren', + 'Osika', + 'Sciascia', + 'Selvaggio', + 'Stoneback', + 'Sweis', + 'Torosyan', + 'Trupp', + 'Wardrip', + 'Wigle', + 'Beissel', + 'Brakke', + 'Carosella', + 'Dobek', + 'Eidem', + 'Homolka', + 'Kemery', + 'Kinderman', + 'Palla', + 'Puccini', + 'Szarek', + 'Vandehei', + 'Arca', + 'Jou', + 'Needs', + 'Habermann', + 'Hyle', + 'Jagoda', + 'Smigielski', + 'Guttierrez', + 'Awwad', + 'Maccormack', + 'Bassin', + 'Achee', + 'Demark', + 'Jardon', + 'Kelsoe', + 'Olear', + 'Comacho', + 'Rosetta', + 'Peddie', + 'Delsol', + 'Nwachukwu', + 'Bagdasarian', + 'Boehringer', + 'Bunke', + 'Burkhammer', + 'Delahoya', + 'Dietzen', + 'Ditmer', + 'Duchaine', + 'Felske', + 'Gumpert', + 'Hansson', + 'Hedeen', + 'Jalil', + 'Kalal', + 'Kanan', + 'Kaska', + 'Kaufer', + 'Knoff', + 'Kornblum', + 'Lanzi', + 'Obenchain', + 'Piatkowski', + 'Prugh', + 'Rima', + 'Shadduck', + 'Sodergren', + 'Spitzley', + 'Tauzin', + 'Weigelt', + 'Baldassarre', + 'Biglin', + 'Fuhriman', + 'Gaumond', + 'Ledvina', + 'Meckler', + 'Minteer', + 'Nesser', + 'Riederer', + 'Ruelle', + 'Turchi', + 'Alberg', + 'Vanderlip', + 'Halder', + 'Hop', + 'Larmon', + 'Bonfield', + 'Ketch', + 'Mannis', + 'Mcallen', + 'Alfonzo', + 'Sampey', + 'Guillet', + 'Madaris', + 'Lisby', + 'Crowner', + 'Frager', + 'Coar', + 'Crewe', + 'Levier', + 'Ligons', + 'Abello', + 'Brinsfield', + 'Buccieri', + 'Cantera', + 'Cieslinski', + 'Cragle', + 'Flater', + 'Grunert', + 'Higinbotham', + 'Janish', + 'Kuennen', + 'Lanners', + 'Lesiak', + 'Litvin', + 'Madueno', + 'Maffia', + 'Manetta', + 'Marschke', + 'Mourer', + 'Nordahl', + 'Nordan', + 'Pankowski', + 'Petron', + 'Qualley', + 'Recht', + 'Rosenbach', + 'Ruttenberg', + 'Saam', + 'Savarino', + 'Solana', + 'Stumpff', + 'Tsukamoto', + 'Vanlanen', + 'Wainer', + 'Kasza', + 'Kuehler', + 'Landgren', + 'Omahony', + 'Paullin', + 'Ramales', + 'Schmelzle', + 'Schnakenberg', + 'Touma', + 'Urgiles', + 'Vorndran', + 'Corne', + 'Higman', + 'Dutil', + 'Reef', + 'Racanelli', + 'Gladwin', + 'Jaspers', + 'Crutchley', + 'Homme', + 'Hughbanks', + 'Crismon', + 'Burdin', + 'Dise', + 'Enzor', + 'Hally', + 'Mccone', + 'Mckell', + 'Belo', + 'Moat', + 'Ijames', + 'Bussie', + 'Papillion', + 'Pratcher', + 'Baranek', + 'Bidlack', + 'Boyadjian', + 'Chern', + 'Conahan', + 'Dimuzio', + 'Erker', + 'Fregeau', + 'Gelsinger', + 'Gonzalo', + 'Heo', + 'Hoog', + 'Jovanovich', + 'Kaschak', + 'Kasik', + 'Katich', + 'Laible', + 'Mastel', + 'Muellner', + 'Pingleton', + 'Rexroth', + 'Schmitter', + 'Stick', + 'Strollo', + 'Traficante', + 'Veteto', + 'Wampole', + 'Winings', + 'Amalfitano', + 'Amiot', + 'Camaj', + 'Cuartas', + 'Drotar', + 'Eatherton', + 'Fioretti', + 'Fudala', + 'Gehrman', + 'Gittleman', + 'Heppe', + 'Maffucci', + 'Tammen', + 'Chovan', + 'Ginley', + 'Stipes', + 'Antigua', + 'Ironside', + 'Kuroda', + 'Lebar', + 'Laske', + 'Salay', + 'Gisi', + 'Mccormic', + 'Veron', + 'Robbin', + 'Morain', + 'Mayden', + 'Vanputten', + 'Triplet', + 'Ravenel', + 'Moragne', + 'Bowdry', + 'Agundez', + 'Allinson', + 'Bosko', + 'Buehrle', + 'Devey', + 'Gasiorowski', + 'Goettel', + 'Halleran', + 'Innocenti', + 'Orser', + 'Scarpati', + 'Scherff', + 'Schlott', + 'Skilling', + 'Speedy', + 'Staal', + 'Szafran', + 'Szczech', + 'Szczepanik', + 'Venturella', + 'Vert', + 'Vogelgesang', + 'Vollbrecht', + 'Wiehe', + 'Achterberg', + 'Fadness', + 'Groene', + 'Halbrooks', + 'Leavenworth', + 'Pruski', + 'Redifer', + 'Schmiesing', + 'Stanforth', + 'Stepanski', + 'Ziel', + 'Hefter', + 'Urman', + 'Muela', + 'Simpler', + 'Elick', + 'Shalabi', + 'Cooner', + 'Ferriera', + 'Templer', + 'Prashad', + 'Gorum', + 'Wheller', + 'Spratling', + 'Gutter', + 'Eke', + 'Rias', + 'Belcourt', + 'Bernards', + 'Camburn', + 'Cerqueira', + 'Conkel', + 'Deist', + 'Derobertis', + 'Desio', + 'Eimer', + 'Fayad', + 'Frommelt', + 'Guariglia', + 'Laba', + 'Labine', + 'Lanius', + 'Loconte', + 'Nop', + 'Omary', + 'Penninger', + 'Pentland', + 'Pinkus', + 'Richoux', + 'Sturrock', + 'Theil', + 'Vanvranken', + 'Bartoszek', + 'Bruski', + 'Engelken', + 'Kranich', + 'Mrazek', + 'Muralles', + 'Pienta', + 'Salido', + 'Sridhar', + 'Turkington', + 'Vellucci', + 'Verhage', + 'Derenzo', + 'Lucker', + 'Wands', + 'Parrow', + 'Branyon', + 'Houff', + 'Bossier', + 'Reels', + 'Rockmore', + 'Altmeyer', + 'Anacker', + 'Antoniou', + 'Berlinger', + 'Busser', + 'Caracci', + 'Caseres', + 'Corcino', + 'Demint', + 'Dhanani', + 'Erekson', + 'Farinacci', + 'Ganesan', + 'Gornick', + 'Gresser', + 'Kremers', + 'Kreuter', + 'Lesieur', + 'Linarez', + 'Mccrystal', + 'Morang', + 'Pucillo', + 'Spicuzza', + 'Tranchina', + 'Tullar', + 'Vantilburg', + 'Yeck', + 'Zandstra', + 'Zeleny', + 'Bearss', + 'Burgner', + 'Delich', + 'Fetsch', + 'Grom', + 'Kreisel', + 'Laprise', + 'Legarreta', + 'Musacchio', + 'Rembold', + 'Sjoblom', + 'Skalicky', + 'Sokolov', + 'Tuminello', + 'Vanskiver', + 'Zidek', + 'Severa', + 'Stables', + 'Guffy', + 'Lebeck', + 'Barradas', + 'Chanley', + 'Dayal', + 'Villafranco', + 'Droke', + 'Popwell', + 'Renier', + 'Bolten', + 'Mille', + 'Swagerty', + 'Grismore', + 'Brantly', + 'Divens', + 'Ottey', + 'Hagger', + 'Advincula', + 'Boschee', + 'Buckbee', + 'Carlan', + 'Casciato', + 'Cregar', + 'Fehring', + 'Ianniello', + 'Interrante', + 'Juedes', + 'Kosier', + 'Lizaola', + 'Lorenzetti', + 'Mccauslin', + 'Older', + 'Osuch', + 'Ramstad', + 'Sare', + 'Stavinoha', + 'Taborda', + 'Warmoth', + 'Weissmann', + 'Winograd', + 'Woeste', + 'Zywicki', + 'Blalack', + 'Chavoya', + 'Clickner', + 'Daigrepont', + 'Dissinger', + 'Kovalik', + 'Lemler', + 'Shortall', + 'Tucholski', + 'Vanmetre', + 'Zetino', + 'Niezgoda', + 'Recupero', + 'Booms', + 'Ramsburg', + 'Berka', + 'Mininger', + 'Tamer', + 'Baka', + 'Jago', + 'Bucks', + 'Laude', + 'Andrepont', + 'Gair', + 'Hayer', + 'Kitching', + 'Towson', + 'Slappey', + 'Syms', + 'Derico', + 'Badie', + 'Kenon', + 'Goffney', + 'Amigon', + 'Belsito', + 'Bergamo', + 'Caputi', + 'Delpilar', + 'Entsminger', + 'Gehres', + 'Geimer', + 'Hada', + 'Krolak', + 'Kruer', + 'Malaney', + 'Mancias', + 'Misiaszek', + 'Pring', + 'Salonga', + 'Schaefers', + 'Schmied', + 'Schwertfeger', + 'Scialabba', + 'Stemmer', + 'Stifter', + 'Suon', + 'Szczygiel', + 'Weisse', + 'Yackley', + 'Decasas', + 'Donado', + 'Drenning', + 'Eppich', + 'Kertesz', + 'Mihal', + 'Mochizuki', + 'Schiebel', + 'Schlageter', + 'Scruton', + 'Weckerly', + 'Wemhoff', + 'Wernette', + 'Zietz', + 'Iwanicki', + 'Ara', + 'Barson', + 'Resor', + 'Rampy', + 'Iskander', + 'Oharra', + 'Kope', + 'Soli', + 'Bodkins', + 'Bussa', + 'Maletta', + 'Clemen', + 'Vaneaton', + 'Berkel', + 'Salvage', + 'Gilchrest', + 'Whitter', + 'Bruster', + 'Mccowin', + 'Gullatt', + 'Cherubin', + 'Flamer', + 'Gueye', + 'Angerer', + 'Baray', + 'Barreca', + 'Bresson', + 'Brougham', + 'Buscaglia', + 'Candee', + 'Decelles', + 'Durflinger', + 'Dusenbery', + 'Enomoto', + 'Galliano', + 'Klooster', + 'Lowrimore', + 'Manda', + 'Morace', + 'Raisanen', + 'Ravenscraft', + 'Rutman', + 'Schmieg', + 'Schorsch', + 'Selim', + 'Stanchfield', + 'Stankowski', + 'Tolosa', + 'Uyeno', + 'Vancleef', + 'Kamdar', + 'Kazlauskas', + 'Kwasnik', + 'Pivonka', + 'Shrode', + 'Sellinger', + 'Deliz', + 'Longerbeam', + 'Schobert', + 'Shader', + 'Collister', + 'Curtright', + 'Franc', + 'Wakely', + 'Duree', + 'Laban', + 'Gascoigne', + 'Noy', + 'Hulon', + 'Michele', + 'Crowden', + 'Dolton', + 'Ryner', + 'Gene', + 'Tetterton', + 'Laffitte', + 'Laidler', + 'Hoston', + 'Akter', + 'Biebel', + 'Bohnenkamp', + 'Bottger', + 'Brecheisen', + 'Bumbarger', + 'Burgert', + 'Burtnett', + 'Coffing', + 'Corigliano', + 'Dault', + 'Dettinger', + 'Fenech', + 'Golaszewski', + 'Hernando', + 'Hoppel', + 'Kadrmas', + 'Khim', + 'Labrado', + 'Leh', + 'Michiels', + 'Milkovich', + 'Mosel', + 'Nestle', + 'Nunan', + 'Palomarez', + 'Peretz', + 'Perno', + 'Popowski', + 'Pottebaum', + 'Rallis', + 'Rase', + 'Rotramel', + 'Sokolik', + 'Sparlin', + 'Zipf', + 'Abruzzese', + 'Branin', + 'Cheslock', + 'Chimenti', + 'Czechowski', + 'Diveley', + 'Eisenbeis', + 'Eisenhut', + 'Friedt', + 'Gehlhausen', + 'Kamphaus', + 'Mctiernan', + 'Monnett', + 'Schue', + 'Steffensmeier', + 'Gens', + 'Schlotterbeck', + 'Ask', + 'Leser', + 'Renville', + 'Wisenbaker', + 'Kellow', + 'Mounsey', + 'Dupin', + 'Causer', + 'Yapp', + 'Stmary', + 'Bowditch', + 'Nickolson', + 'Molla', + 'Larke', + 'Kamau', + 'Cardinali', + 'Deely', + 'Deep', + 'Dietel', + 'Ferraris', + 'Fons', + 'Hahm', + 'Huy', + 'Imber', + 'Leichliter', + 'Longanecker', + 'Lordi', + 'Ludewig', + 'Maiolo', + 'Mckern', + 'Meyering', + 'Muhl', + 'Nylen', + 'Ohlendorf', + 'Palmgren', + 'Raffield', + 'Reusser', + 'Revette', + 'Ridolfi', + 'Rosemeyer', + 'Seber', + 'Silberberg', + 'Sitzmann', + 'Tayman', + 'Tygart', + 'Vertz', + 'Volkmer', + 'Bellemare', + 'Benanti', + 'Bialecki', + 'Biber', + 'Dipierro', + 'Dornbush', + 'Eichhorst', + 'Messana', + 'Neisen', + 'Ottoson', + 'Salmonson', + 'Turcott', + 'Vlachos', + 'Wojdyla', + 'Dagg', + 'Hernan', + 'Mannes', + 'Fent', + 'Tappen', + 'Hyers', + 'Gery', + 'Deam', + 'Channing', + 'Gesner', + 'Swaringen', + 'Lakins', + 'Cogbill', + 'Allsbrook', + 'Kennemore', + 'Sumrell', + 'Luma', + 'Rookard', + 'Shakoor', + 'Philbert', + 'Maragh', + 'Wordlaw', + 'Ofori', + 'Arseneault', + 'Arslanian', + 'Aydin', + 'Balthaser', + 'Bensch', + 'Boord', + 'Botting', + 'Brummet', + 'Cassiday', + 'Chubbuck', + 'Crance', + 'Dobis', + 'Dymek', + 'Kakar', + 'Kipnis', + 'Kooi', + 'Kovack', + 'Malzahn', + 'Melendes', + 'Micucci', + 'Miklas', + 'Molander', + 'Nungesser', + 'Razavi', + 'Reppond', + 'Reznick', + 'Rosten', + 'Schwegler', + 'Sielaff', + 'Sincavage', + 'Soave', + 'Socorro', + 'Tausch', + 'Tracz', + 'Vey', + 'Weltman', + 'Wittich', + 'Emswiler', + 'Etzkorn', + 'Kuchenbecker', + 'Lampi', + 'Pfahler', + 'Thronson', + 'Trefz', + 'Pont', + 'Hendrie', + 'Russon', + 'Coleson', + 'Gregori', + 'Herzfeld', + 'Tamas', + 'Oslin', + 'Warrell', + 'Basher', + 'Elizabeth', + 'Nickolas', + 'Prigmore', + 'Okray', + 'Cannedy', + 'Mercy', + 'Daigre', + 'Leggins', + 'Savannah', + 'Russaw', + 'Opoku', + 'Angier', + 'Behrle', + 'Budny', + 'Cislo', + 'Covalt', + 'Dershem', + 'Devincent', + 'Dhar', + 'Dombrosky', + 'Dragovich', + 'Drobny', + 'Fess', + 'Genthner', + 'Gierhart', + 'Hadzic', + 'Hehir', + 'Henle', + 'Heyd', + 'Hudlow', + 'Janko', + 'Kapral', + 'Kietzman', + 'Malburg', + 'Maret', + 'Mcever', + 'Sann', + 'Scheidel', + 'Schultheiss', + 'Sedita', + 'Sigl', + 'Starace', + 'Stoklosa', + 'Tainter', + 'Tamburrino', + 'Vankleeck', + 'Vannucci', + 'Wernecke', + 'Widmayer', + 'Agresti', + 'Boshell', + 'Dartt', + 'Dobkin', + 'Effertz', + 'Gaydosh', + 'Hocevar', + 'Kluger', + 'Mcguffee', + 'Pekala', + 'Tuchman', + 'Keylon', + 'Pletz', + 'Germond', + 'Keedy', + 'Meir', + 'Tromp', + 'Solly', + 'Baerga', + 'Jawad', + 'Chanda', + 'Scobie', + 'Snowball', + 'Pricer', + 'Graper', + 'Bally', + 'Mcfarlan', + 'Duncombe', + 'Mccory', + 'Costen', + 'Poplar', + 'Denkins', + 'Padmore', + 'Waithe', + 'Adduci', + 'Aldaba', + 'Berhow', + 'Cocuzza', + 'Dubroc', + 'Earnheart', + 'Eickholt', + 'Gutzwiller', + 'Heavin', + 'Himebaugh', + 'Jakubik', + 'Kiang', + 'Klusman', + 'Knueppel', + 'Neddo', + 'Oakey', + 'Rachlin', + 'Spegal', + 'Spizzirri', + 'Stavola', + 'Zika', + 'Beverlin', + 'Boehle', + 'Caltagirone', + 'Chernick', + 'Ciaccia', + 'Courchaine', + 'Covault', + 'Crihfield', + 'Fojtik', + 'Gronski', + 'Huwe', + 'Ostrovsky', + 'Quraishi', + 'Rauber', + 'Scalici', + 'Schuetze', + 'Advani', + 'Galer', + 'Rog', + 'Husson', + 'Karpen', + 'Ess', + 'Henman', + 'Slatten', + 'Bango', + 'Barkin', + 'Vessell', + 'Mayson', + 'Kittles', + 'Quince', + 'Beardmore', + 'Breceda', + 'Carmony', + 'Ciliberto', + 'Cotroneo', + 'Dimitroff', + 'Granahan', + 'Haacke', + 'Huska', + 'Jankiewicz', + 'Klipp', + 'Kostic', + 'Langarica', + 'Lanphier', + 'Maran', + 'Marmion', + 'Mclinden', + 'Mcpeake', + 'Minkel', + 'Nicolo', + 'Quihuis', + 'Siemsen', + 'Somero', + 'Spuhler', + 'Spychalski', + 'Stary', + 'Stitzer', + 'Stucke', + 'Tango', + 'Ticas', + 'Vivero', + 'Campen', + 'Fei', + 'Ganas', + 'Klipfel', + 'Vodicka', + 'Zajdel', + 'Ulin', + 'Bodey', + 'Moral', + 'Fellenz', + 'Charo', + 'Cliver', + 'Clasby', + 'Neeson', + 'Durell', + 'Hew', + 'Mcgray', + 'Breaker', + 'Haslem', + 'Verser', + 'Broner', + 'Mannings', + 'Darensbourg', + 'Petithomme', + 'Akbari', + 'Amdahl', + 'Boeger', + 'Bougie', + 'Buffo', + 'Cisar', + 'Deleonardis', + 'Diffee', + 'Dillen', + 'Dingley', + 'Dugo', + 'Fedora', + 'Habibi', + 'Hartland', + 'Hennelly', + 'Kachmar', + 'Louth', + 'Mughal', + 'Muska', + 'Narang', + 'Pontillo', + 'Roel', + 'Shehorn', + 'Smick', + 'Soliven', + 'Starzyk', + 'Swaminathan', + 'Teagarden', + 'Thune', + 'Vokes', + 'Volkov', + 'Weckesser', + 'Wigen', + 'Donaghue', + 'Ederer', + 'Glaus', + 'Gwozdz', + 'Kimler', + 'Kocak', + 'Lagerquist', + 'Pellecchia', + 'Ruminski', + 'Scholler', + 'Steurer', + 'Tlatelpa', + 'Zegarra', + 'Janssens', + 'Jass', + 'Ciriaco', + 'Kessner', + 'Georg', + 'Harre', + 'Brannam', + 'Beel', + 'Kaine', + 'Roher', + 'Evora', + 'Rittman', + 'Sion', + 'Millon', + 'Morre', + 'Bouler', + 'Seegars', + 'Jenifer', + 'Bernd', + 'Chahine', + 'Crisanto', + 'Desautel', + 'Dirosa', + 'Fehringer', + 'Fukui', + 'Hetz', + 'Hueber', + 'Ivanova', + 'Klecker', + 'Kulzer', + 'Machi', + 'Menn', + 'Mudry', + 'Niro', + 'Nyenhuis', + 'Pressel', + 'Prusinski', + 'Roske', + 'Shaefer', + 'Stear', + 'Stumpo', + 'Teas', + 'Tolsma', + 'Troha', + 'Vanveen', + 'Waltermire', + 'Zaretsky', + 'Zingg', + 'Arntson', + 'Dizdarevic', + 'Kassebaum', + 'Natzke', + 'Passanisi', + 'Rodebaugh', + 'Skonieczny', + 'Vanhoozer', + 'Wiechert', + 'Golonka', + 'Roycroft', + 'Robl', + 'Lisboa', + 'Brandis', + 'Symmes', + 'Nou', + 'Pawson', + 'Comins', + 'Ranker', + 'Silman', + 'Lonas', + 'Goldthwaite', + 'Aries', + 'Leckey', + 'Conolly', + 'Ezelle', + 'Degrasse', + 'Tarte', + 'Bonaventure', + 'Rambeau', + 'Alsobrooks', + 'Blumenberg', + 'Snape', + 'Delane', + 'Sarr', + 'Rankine', + 'Mcclarty', + 'Skipwith', + 'Mapps', + 'Poke', + 'Ahlman', + 'Brunkow', + 'Crissinger', + 'Critcher', + 'Cronce', + 'Earney', + 'Fischler', + 'Franta', + 'Haist', + 'Hirschfield', + 'Jacobe', + 'Karraker', + 'Kronenberger', + 'Layland', + 'Liscano', + 'Lohrman', + 'Luy', + 'Macik', + 'Makinen', + 'Mis', + 'Musarra', + 'Orbe', + 'Ortloff', + 'Potempa', + 'Presta', + 'Rebollo', + 'Rudden', + 'Schab', + 'Settlemyre', + 'Shaban', + 'Shiraishi', + 'Shrake', + 'Suba', + 'Tornquist', + 'Treglia', + 'Vanschaick', + 'Velten', + 'Waln', + 'Addeo', + 'Dacquisto', + 'Fenno', + 'Gilberg', + 'Halberstam', + 'Holck', + 'Landgrebe', + 'Lipa', + 'Luehrs', + 'Mkrtchyan', + 'Proscia', + 'Schucker', + 'Selner', + 'Sinisi', + 'Wandersee', + 'Weigold', + 'Winterrowd', + 'Stoutenburg', + 'Medinger', + 'Bittman', + 'Gerges', + 'Langelier', + 'Berdine', + 'Hartshorne', + 'Matters', + 'Lavere', + 'Delauter', + 'Caillouet', + 'Elford', + 'Derrington', + 'Mollison', + 'Erskin', + 'Doswell', + 'Loadholt', + 'Stepter', + 'Contee', + 'Adwell', + 'Banez', + 'Birchler', + 'Bodman', + 'Bransfield', + 'Butzer', + 'Cenci', + 'Fabro', + 'Fila', + 'Follman', + 'Geoffrion', + 'Hardegree', + 'Klindt', + 'Kuzniar', + 'Lapenta', + 'Lasorsa', + 'Lykens', + 'Madariaga', + 'Mcginnity', + 'Mezger', + 'Milleson', + 'Nisly', + 'Palau', + 'Salz', + 'Sholly', + 'Spartz', + 'Spevak', + 'Svehla', + 'Trafford', + 'Treu', + 'Winski', + 'Zervas', + 'Bautch', + 'Dybas', + 'Hillenburg', + 'Krahl', + 'Loretto', + 'Mcanany', + 'Meschke', + 'Panuco', + 'Pezzullo', + 'Pokorski', + 'Reinertson', + 'Spoden', + 'Steinbrenner', + 'Wedig', + 'Mom', + 'Furner', + 'Harpin', + 'Carlston', + 'Oo', + 'Betten', + 'Duro', + 'Veronica', + 'Klutz', + 'Coven', + 'Siles', + 'Carby', + 'Duvernay', + 'Gory', + 'Adamczak', + 'Adee', + 'Agius', + 'Bachicha', + 'Belka', + 'Bridenstine', + 'Cappella', + 'Chiao', + 'Georgiadis', + 'Hansmann', + 'Kettlewell', + 'Klemann', + 'Kracke', + 'Legacy', + 'Mateja', + 'Mcgarrigle', + 'Peitz', + 'Pergande', + 'Proia', + 'Reicher', + 'Rentfrow', + 'Rudkin', + 'Sahni', + 'Santopietro', + 'Sarin', + 'Schear', + 'Seckel', + 'Sopp', + 'Sorci', + 'Terbush', + 'Uplinger', + 'Vantol', + 'Zaro', + 'Cuppett', + 'Depetro', + 'Hofferber', + 'Kreifels', + 'Kuznetsov', + 'Matassa', + 'Mazanec', + 'Naegle', + 'Sphar', + 'Villaneda', + 'Wachholz', + 'Pastrano', + 'Pilotte', + 'Shedden', + 'Molt', + 'Dalia', + 'Bishara', + 'Dumoulin', + 'Dehnert', + 'Dilmore', + 'Termine', + 'Bracher', + 'Laplace', + 'Sherin', + 'Morine', + 'Garrott', + 'Banford', + 'Drumwright', + 'Linnen', + 'Belay', + 'Juste', + 'Moment', + 'Adamec', + 'Alessandrini', + 'Bolda', + 'Buonanno', + 'Corrow', + 'Couvillon', + 'Dahnke', + 'Durrani', + 'Errett', + 'Fingerhut', + 'Ittner', + 'Kandler', + 'Khosla', + 'Mascio', + 'Mesch', + 'Napolitan', + 'Packman', + 'Parady', + 'Saline', + 'Spatafore', + 'Squiers', + 'Stailey', + 'Stolar', + 'Strommen', + 'Vahey', + 'Vanbebber', + 'Wimpee', + 'Wolinsky', + 'Yambao', + 'Ciocca', + 'Fornwalt', + 'Giannattasio', + 'Herbers', + 'Korol', + 'Lindenberger', + 'Lysne', + 'Piacentini', + 'Vogeler', + 'Cassetta', + 'Hildebran', + 'Masoud', + 'Shiller', + 'Fisler', + 'Loll', + 'Wattles', + 'Carris', + 'Hippe', + 'Torregrossa', + 'Thain', + 'Enman', + 'Kanno', + 'Jeane', + 'Clendenning', + 'Halt', + 'Dorin', + 'Carnathan', + 'Bisch', + 'Simm', + 'Goatley', + 'July', + 'Oke', + 'Basley', + 'Dillahunt', + 'Times', + 'Mcglown', + 'Cohens', + 'Jeanphilippe', + 'Benshoof', + 'Bensing', + 'Bir', + 'Birnie', + 'Burklow', + 'Capili', + 'Cordts', + 'Falanga', + 'Farooqui', + 'Furber', + 'Godino', + 'Gollnick', + 'Harmening', + 'Hilpert', + 'Hrivnak', + 'Iribe', + 'Krienke', + 'Kuntzman', + 'Laslo', + 'Loso', + 'Omohundro', + 'Rabadi', + 'Reisenauer', + 'Rohrich', + 'Salak', + 'Schuckman', + 'Semmel', + 'Sendelbach', + 'Sidler', + 'Stegmann', + 'Sudbeck', + 'Tara', + 'Walcher', + 'Walkenhorst', + 'Wellbrock', + 'Capaldo', + 'Cotnoir', + 'Durrence', + 'Fralix', + 'Leibfried', + 'Schlarb', + 'Whitenight', + 'Grannan', + 'Mugford', + 'Filo', + 'Soh', + 'Deprez', + 'Semidey', + 'Vandivier', + 'Shawl', + 'Happy', + 'Gartley', + 'Jonathan', + 'Bouquet', + 'Warsaw', + 'Verne', + 'Furse', + 'Holms', + 'Bassette', + 'Fishburne', + 'Ambrosius', + 'Amrein', + 'Astorino', + 'Bedonie', + 'Bibee', + 'Brearley', + 'Chesher', + 'Colasurdo', + 'Deike', + 'Dimarino', + 'Felling', + 'Freid', + 'Gad', + 'Gambale', + 'Gieser', + 'Greff', + 'Halseth', + 'Hamor', + 'Hargens', + 'Hohenberger', + 'Hohler', + 'Illes', + 'Koscielniak', + 'Kotara', + 'Krygier', + 'Lopinto', + 'Mangas', + 'Mantione', + 'Mcendree', + 'Musich', + 'Nordling', + 'Panagopoulos', + 'Pollio', + 'Score', + 'Semaan', + 'Tortorelli', + 'Trabert', + 'Troung', + 'Vittorio', + 'Barkdoll', + 'Dombeck', + 'Ferriter', + 'Gancarz', + 'Gubbels', + 'Kertz', + 'Langenderfer', + 'Roppolo', + 'Siglin', + 'Trnka', + 'Vanderkooi', + 'Yaun', + 'Witkin', + 'Caryl', + 'Boies', + 'Carattini', + 'Hannes', + 'Harmison', + 'Mctavish', + 'Bille', + 'Sullivant', + 'Yeakey', + 'Respess', + 'Gooley', + 'Maura', + 'Jukes', + 'Oguin', + 'Demory', + 'Morson', + 'Hathorne', + 'Anklam', + 'Antaya', + 'Bentler', + 'Bettcher', + 'Bresette', + 'Broadrick', + 'Degante', + 'Demaray', + 'Dipinto', + 'Doberstein', + 'Dorminey', + 'Dorwart', + 'Gugliuzza', + 'Jesser', + 'Kjar', + 'Kujala', + 'Lemarr', + 'Lynds', + 'Novitsky', + 'Oropesa', + 'Scarpulla', + 'Schave', + 'Siravo', + 'Torma', + 'Uva', + 'Winkowski', + 'Boscia', + 'Buikema', + 'Byland', + 'Enneking', + 'Enstrom', + 'Gotsch', + 'Kulakowski', + 'Mattheis', + 'Niemuth', + 'Oberdorf', + 'Rabuck', + 'Shinners', + 'Struebing', + 'Dickes', + 'Hettrick', + 'Pille', + 'Vilar', + 'Blewitt', + 'Gutt', + 'Haseley', + 'Pennel', + 'Figuereo', + 'Lassalle', + 'Tannahill', + 'Teats', + 'Mumby', + 'Cheves', + 'Spark', + 'Ale', + 'Wally', + 'Lowndes', + 'Ballo', + 'Couper', + 'Alberta', + 'Puller', + 'Rochell', + 'Bachar', + 'Ballengee', + 'Bellizzi', + 'Boback', + 'Cammarano', + 'Dirr', + 'Findling', + 'Fruin', + 'Ghattas', + 'Kaliszewski', + 'Kammeyer', + 'Kwiecien', + 'Lamora', + 'Lehrke', + 'Macewen', + 'Nasta', + 'Neibert', + 'Ogaz', + 'Olesky', + 'Otano', + 'Prescher', + 'Romick', + 'Scibetta', + 'Slicker', + 'Ungerer', + 'Vanheel', + 'Wadas', + 'Weissert', + 'Armiger', + 'Brusca', + 'Christeson', + 'Crookshanks', + 'Demarinis', + 'Fahrney', + 'Heiple', + 'Howat', + 'Knoedler', + 'Kuske', + 'Leifheit', + 'Lukach', + 'Nauert', + 'Obremski', + 'Seidenberg', + 'Smigelski', + 'Visscher', + 'Wauneka', + 'Whitmoyer', + 'Wyand', + 'Ilardi', + 'Jackel', + 'Rackham', + 'Macgowan', + 'Braid', + 'Bringle', + 'Dirk', + 'Paci', + 'Wears', + 'Vanbergen', + 'Sidle', + 'Mellish', + 'Paino', + 'State', + 'Cargle', + 'Harcum', + 'Beyene', + 'Mwangi', + 'Anderle', + 'Cancienne', + 'Compeau', + 'Egle', + 'Farone', + 'Harke', + 'Hollopeter', + 'Jambor', + 'Jermyn', + 'Kadakia', + 'Kerker', + 'Langowski', + 'Lechman', + 'Nagengast', + 'Narvaiz', + 'Paola', + 'Partch', + 'Plucker', + 'Rawe', + 'Rohland', + 'Rosebrook', + 'Stanphill', + 'Stoltman', + 'Volkers', + 'Balingit', + 'Bausman', + 'Besler', + 'Dalto', + 'Edgren', + 'Hairfield', + 'Janek', + 'Kenoyer', + 'Koska', + 'Mihok', + 'Monjaraz', + 'Reisz', + 'Snedegar', + 'Vandezande', + 'Viscomi', + 'Kiene', + 'Dib', + 'Kuc', + 'Magley', + 'Swearingin', + 'Culliton', + 'Roome', + 'Fendrick', + 'Trindade', + 'Whaling', + 'Tarbutton', + 'Sider', + 'Swingler', + 'Lover', + 'Clarida', + 'Jocelyn', + 'Mervin', + 'Blaize', + 'Semper', + 'Bagsby', + 'Pree', + 'Dieujuste', + 'Anacleto', + 'Annable', + 'Bacci', + 'Bottari', + 'Cinco', + 'Delzell', + 'Dowless', + 'Drilling', + 'Egert', + 'Fanton', + 'Geerts', + 'Ghaffari', + 'Guggenheim', + 'Hankes', + 'Hediger', + 'Hornig', + 'Kauer', + 'Kossman', + 'Krasnow', + 'Lauman', + 'Lebsack', + 'Liendo', + 'Marhefka', + 'Noguez', + 'Oxman', + 'Pa', + 'Pella', + 'Pongratz', + 'Prisk', + 'Rajagopalan', + 'Rozo', + 'Vanvorst', + 'Wachob', + 'Avolio', + 'Banet', + 'Boissonneault', + 'Coglianese', + 'Crudele', + 'Dobratz', + 'Gerdts', + 'Koors', + 'Mazzanti', + 'Ozimek', + 'Vanhove', + 'Zern', + 'Kalama', + 'Mikelson', + 'Renehan', + 'Blecher', + 'Meath', + 'Bonus', + 'Wesch', + 'Kirkey', + 'Goldbeck', + 'Hun', + 'Morgans', + 'Strohman', + 'Lanagan', + 'Wyly', + 'Syers', + 'Berne', + 'Tondreau', + 'Witts', + 'Budhu', + 'Flott', + 'Alsbrooks', + 'Mabin', + 'Kingsberry', + 'Berend', + 'Brandeberry', + 'Carandang', + 'Ciavarella', + 'Foil', + 'Galano', + 'Garzia', + 'Golembeski', + 'Kossow', + 'Kren', + 'Lefave', + 'Macmahon', + 'Nilan', + 'Peregrina', + 'Pralle', + 'Sahakian', + 'Sarate', + 'Scalzi', + 'Soulliere', + 'Srock', + 'Stammen', + 'Sterry', + 'Tadych', + 'Trembath', + 'Watwood', + 'Wolske', + 'Woolson', + 'Aversano', + 'Chavana', + 'Digiuseppe', + 'Escano', + 'Harkrider', + 'Liebmann', + 'Soldan', + 'Swiatkowski', + 'Tomala', + 'Keay', + 'Lindstedt', + 'Maille', + 'Thurner', + 'Favia', + 'Guedes', + 'Simao', + 'Rambow', + 'Chriscoe', + 'Hiss', + 'Mcraney', + 'Barke', + 'Hobday', + 'Buri', + 'Sigle', + 'Bawa', + 'Lalande', + 'Bordon', + 'Friley', + 'Feild', + 'Arington', + 'Jons', + 'Funderburke', + 'Mccommons', + 'Troublefield', + 'Mable', + 'Hullum', + 'Wrice', + 'Cager', + 'Barse', + 'Braunschweig', + 'Dasch', + 'Fraioli', + 'Giefer', + 'Giovanniello', + 'Glahn', + 'Hatheway', + 'Holtrop', + 'Katsaros', + 'Koetting', + 'Malinoski', + 'Markov', + 'Mcclosky', + 'Mccormac', + 'Mertins', + 'Milito', + 'Mroczka', + 'Overdorf', + 'Palombi', + 'Peninger', + 'Provenza', + 'Quinnell', + 'Roady', + 'Ruthven', + 'Savitsky', + 'Shenefield', + 'Stapel', + 'Venkataraman', + 'Zachow', + 'Aaberg', + 'Bajorek', + 'Bankowski', + 'Barquero', + 'Delcamp', + 'Deshler', + 'Halili', + 'Hebenstreit', + 'Hirota', + 'Hladky', + 'Kliethermes', + 'Koestner', + 'Kroes', + 'Luepke', + 'Mckeough', + 'Mielcarek', + 'Nobis', + 'Olenik', + 'Plessinger', + 'Shillingburg', + 'Spadaccini', + 'Springborn', + 'Werden', + 'Willenbring', + 'Zyskowski', + 'Paucar', + 'Werst', + 'Wohlwend', + 'Nauss', + 'Alma', + 'Tebeau', + 'Paskett', + 'Spindle', + 'Twiddy', + 'Alomar', + 'Mi', + 'Billard', + 'Bails', + 'Channer', + 'Fripp', + 'Abreo', + 'Adamowicz', + 'Bocian', + 'Breden', + 'Breitkreutz', + 'Celona', + 'Chizek', + 'Chrestman', + 'Ciaramella', + 'Compher', + 'Crannell', + 'Dermer', + 'Duryee', + 'Feuerborn', + 'Garrels', + 'Gausman', + 'Grippi', + 'Guadamuz', + 'Hatlestad', + 'Heon', + 'Hokenson', + 'Kaden', + 'Kluever', + 'Lagares', + 'Mamone', + 'Mascola', + 'Matich', + 'Messimer', + 'Mezera', + 'Mongiello', + 'Moradi', + 'Nessler', + 'Nijjar', + 'Nin', + 'Pasquarelli', + 'Pawlowicz', + 'Petitto', + 'Petruccelli', + 'Pullano', + 'Rebar', + 'Romack', + 'Rosener', + 'Soland', + 'Solow', + 'Vandervelden', + 'Vazguez', + 'Vonruden', + 'Balmes', + 'Berninger', + 'Broecker', + 'Clogston', + 'Fontanella', + 'Gubbins', + 'Kampen', + 'Levenhagen', + 'Lyter', + 'Nagamine', + 'Regas', + 'Riecke', + 'Veltre', + 'Wojahn', + 'Angelino', + 'Mccomber', + 'Grisso', + 'Saran', + 'Pecore', + 'Sorter', + 'Encalada', + 'Robart', + 'Deerman', + 'Lori', + 'Mcnee', + 'Dagher', + 'Villars', + 'Chaplain', + 'Houtman', + 'Dingwall', + 'Akerson', + 'Donaway', + 'Dimmer', + 'Mittman', + 'Camm', + 'Kenedy', + 'Bilbro', + 'Brocks', + 'Mansaray', + 'Acebo', + 'Ahr', + 'Alayon', + 'Benyo', + 'Blatnik', + 'Degidio', + 'Dumire', + 'Elefante', + 'Gase', + 'Gilboy', + 'Gradillas', + 'Haverstock', + 'Heberle', + 'Hilmes', + 'Hjort', + 'Johnsey', + 'Lambiase', + 'Marland', + 'Mcevilly', + 'Mergenthaler', + 'Mini', + 'Noska', + 'Patrie', + 'Rohrback', + 'Seelbach', + 'Stopher', + 'Trzaska', + 'Vanessen', + 'Veillette', + 'Walizer', + 'Zapalac', + 'Andalon', + 'Beukema', + 'Cieslik', + 'Dukart', + 'Gerads', + 'Gilhooly', + 'Hinebaugh', + 'Jumonville', + 'Macchi', + 'Oldenkamp', + 'Plotz', + 'Robideau', + 'Streed', + 'Trochez', + 'Grames', + 'Beltram', + 'Fishbaugh', + 'Lais', + 'Ossa', + 'Wilden', + 'Erick', + 'Dosier', + 'Trust', + 'Swaine', + 'Darity', + 'Mccroy', + 'Yuille', + 'Cantave', + 'Barsanti', + 'Carbonara', + 'Cavanah', + 'Chrismer', + 'Cuestas', + 'Czaplewski', + 'Denes', + 'Dorio', + 'Geraldo', + 'Giebler', + 'Goewey', + 'Gorniak', + 'Grabe', + 'Guidera', + 'Hannig', + 'Herin', + 'Kadow', + 'Klauer', + 'Kleppinger', + 'Lerro', + 'Manoogian', + 'Mentzel', + 'Muramoto', + 'Ollinger', + 'Pacey', + 'Pufahl', + 'Quero', + 'Revuelta', + 'Rickles', + 'Rudie', + 'Ruggerio', + 'Salberg', + 'Schwoerer', + 'Stephani', + 'Stevick', + 'Strada', + 'Thorley', + 'Thrun', + 'Virts', + 'Wingett', + 'Balfe', + 'Branaman', + 'Brookshier', + 'Carlsson', + 'Chismar', + 'Habben', + 'Migdal', + 'Ozga', + 'Rivest', + 'Russman', + 'Schellhorn', + 'Staup', + 'Pietri', + 'Welby', + 'Cisney', + 'Hijazi', + 'Brines', + 'Calderin', + 'Mudrick', + 'Domine', + 'Parlow', + 'Ervine', + 'Banis', + 'Mathenia', + 'Carbin', + 'Rashed', + 'Mcgilvery', + 'Prichett', + 'Feimster', + 'Smoots', + 'Persley', + 'Desire', + 'Abadi', + 'Bercaw', + 'Bertz', + 'Bibian', + 'Brosious', + 'Brunken', + 'Calvano', + 'Chenette', + 'Chiusano', + 'Dendinger', + 'Diffley', + 'Eichenberg', + 'Gawne', + 'Gelardi', + 'Gottman', + 'Gulyas', + 'Hak', + 'Haydock', + 'Hettler', + 'Hinsch', + 'Kozlik', + 'Krebbs', + 'Krichbaum', + 'Loges', + 'Lyssy', + 'Mitnick', + 'Podolski', + 'Priego', + 'Radhakrishnan', + 'Reineck', + 'Ruggirello', + 'Samborski', + 'Schwalb', + 'Sitek', + 'Sprinkel', + 'Tkachuk', + 'Viscuso', + 'Working', + 'Zinner', + 'Anspaugh', + 'Anthes', + 'Bratsch', + 'Breining', + 'Cejka', + 'Delbuono', + 'Hugill', + 'Huyett', + 'Irlbeck', + 'Kilgus', + 'Langwell', + 'Margulis', + 'Meara', + 'Napierala', + 'Stanaway', + 'Worton', + 'Gaucher', + 'Bakeman', + 'Pasos', + 'Feazel', + 'Evitt', + 'Marrin', + 'Baskette', + 'Orne', + 'Ivens', + 'Burnstein', + 'Rodell', + 'Bowell', + 'Maraj', + 'Lango', + 'Boudoin', + 'Wider', + 'Walkins', + 'Raheem', + 'Talford', + 'Jeanmarie', + 'Drumgoole', + 'Arnot', + 'Bennick', + 'Buchinger', + 'Cleven', + 'Corsello', + 'Delucchi', + 'Dicocco', + 'Eachus', + 'Eilts', + 'Fandino', + 'Fyke', + 'Giammarco', + 'Gwartney', + 'Hawken', + 'Henkelman', + 'Jaggi', + 'Jurczyk', + 'Kamman', + 'Kattner', + 'Keator', + 'Klus', + 'Leidner', + 'Ligas', + 'Martus', + 'Maslow', + 'Piccinini', + 'Pysher', + 'Riga', + 'Siek', + 'Sizelove', + 'Vanostrand', + 'Vastine', + 'Viviani', + 'Youngerman', + 'Zahniser', + 'Brigante', + 'Burklund', + 'Cajina', + 'Coppolino', + 'Goytia', + 'Icenhower', + 'Ihnen', + 'Jablonsky', + 'Koepsell', + 'Mennenga', + 'Redenius', + 'Tengan', + 'Weishaupt', + 'Dorst', + 'Kief', + 'Busk', + 'Luba', + 'Quine', + 'Deshotels', + 'Roulston', + 'Diniz', + 'Chandley', + 'Saleeby', + 'Maro', + 'Faidley', + 'Burrous', + 'Ilyas', + 'Roster', + 'Clovis', + 'Bacot', + 'Pembleton', + 'Bellot', + 'Entzminger', + 'Ryce', + 'Posley', + 'Alvi', + 'Audino', + 'Bitters', + 'Boomershine', + 'Boyack', + 'Branda', + 'Bresnan', + 'Brusco', + 'Bunda', + 'Catanzarite', + 'Dohmen', + 'Elbaum', + 'Farago', + 'Ferrentino', + 'Gimpel', + 'Grzeskowiak', + 'Gutting', + 'Henandez', + 'Herbeck', + 'Hoben', + 'Hunnell', + 'Ibbotson', + 'Kida', + 'Kirchman', + 'Kubin', + 'Laplume', + 'Laskin', + 'Lefferts', + 'Leimer', + 'Locatelli', + 'Pitsenbarger', + 'Reum', + 'Rittgers', + 'Scadden', + 'Shammas', + 'Tatge', + 'Tiongson', + 'Wengler', + 'Wenrick', + 'Wortley', + 'Bretado', + 'Detloff', + 'Dlugosz', + 'Eisemann', + 'Embler', + 'Graffius', + 'Kienast', + 'Kucher', + 'Larew', + 'Lemmerman', + 'Maners', + 'Peckinpaugh', + 'Rupnow', + 'Schubring', + 'Staheli', + 'Stege', + 'Talwar', + 'Truszkowski', + 'Coda', + 'Comunale', + 'Holtry', + 'Newfield', + 'Blankley', + 'Devino', + 'Wahba', + 'Cathell', + 'Timson', + 'Setzler', + 'Shacklett', + 'Nicols', + 'Rocque', + 'Nest', + 'Freelove', + 'Neat', + 'Kina', + 'Caslin', + 'Creal', + 'Wyre', + 'Compere', + 'Brisker', + 'Givhan', + 'Menifee', + 'Hymon', + 'Boakye', + 'Aguillar', + 'Alpern', + 'Antico', + 'Attridge', + 'Bjorge', + 'Bordwell', + 'Brumbach', + 'Castronova', + 'Cowher', + 'Fakhouri', + 'Hanigan', + 'Heidecker', + 'Hosick', + 'Lorang', + 'Magadan', + 'Marovich', + 'Masur', + 'Nienow', + 'Passow', + 'Priola', + 'Prose', + 'Radillo', + 'Saracco', + 'Schlender', + 'Sellards', + 'Stirn', + 'Strathman', + 'Supan', + 'Taguchi', + 'Tufte', + 'Vanderleest', + 'Vanderpoel', + 'Vondra', + 'Wayment', + 'Wisinski', + 'Brodowski', + 'Cichowski', + 'Delarocha', + 'Demyan', + 'Dobies', + 'Hegner', + 'Karapetian', + 'Konieczka', + 'Lazarz', + 'Loughner', + 'Portanova', + 'Rosentreter', + 'Rothlisberger', + 'Schropp', + 'Trenkamp', + 'Flaharty', + 'Murfin', + 'Waner', + 'Baiz', + 'Dunegan', + 'Gillson', + 'Erne', + 'Mahin', + 'Hardgrave', + 'Felps', + 'Bevens', + 'Abdou', + 'Songy', + 'Boule', + 'Wisham', + 'Devonshire', + 'Havis', + 'Relf', + 'Pean', + 'Manago', + 'Brazzle', + 'Mckelvin', + 'Goulbourne', + 'Pinkins', + 'Yelder', + 'Akina', + 'Allerton', + 'Aminov', + 'Barsamian', + 'Biondolillo', + 'Bouchillon', + 'Bustle', + 'Dolney', + 'Dunkerley', + 'Farha', + 'Floor', + 'Gaustad', + 'Gilberti', + 'Helder', + 'Kolber', + 'Kuznia', + 'Longhi', + 'Mamaril', + 'Milhorn', + 'Mozo', + 'Norbury', + 'Okano', + 'Perkovich', + 'Rafanan', + 'Rulo', + 'Ruperto', + 'Scow', + 'Shadoan', + 'Smisek', + 'Steinfeldt', + 'Thobe', + 'Venturino', + 'Widell', + 'Broccoli', + 'Helmig', + 'Koegler', + 'Lewandoski', + 'Pequignot', + 'Radermacher', + 'Resetar', + 'Rostro', + 'Sebald', + 'Walgren', + 'Lottes', + 'Capraro', + 'Grine', + 'Gordner', + 'Crus', + 'Easom', + 'Bayle', + 'Barts', + 'Duguid', + 'Estel', + 'Peggs', + 'Cheaney', + 'Rossin', + 'Mackel', + 'Vassel', + 'Fils', + 'Senat', + 'Alarie', + 'Allar', + 'Brownlie', + 'Bumbaugh', + 'Caissie', + 'Cordone', + 'Critser', + 'Delconte', + 'Falzon', + 'Formosa', + 'Frerking', + 'Gadea', + 'Ganem', + 'Guzek', + 'Hauch', + 'Heese', + 'Hemmen', + 'Holzschuh', + 'Impson', + 'Jablon', + 'Kiedrowski', + 'Krob', + 'Kuhnle', + 'Laake', + 'Larouche', + 'Leaton', + 'Leyland', + 'Lorenson', + 'Macduff', + 'Maready', + 'Newberger', + 'Ohnstad', + 'Pinela', + 'Polino', + 'Postema', + 'Pyon', + 'Radziewicz', + 'Rathod', + 'Salopek', + 'Salvadore', + 'Sawchuk', + 'Trotto', + 'Vereb', + 'Auslander', + 'Beninati', + 'Blunck', + 'Decandia', + 'Deeney', + 'Escatel', + 'Foskett', + 'Hagmann', + 'Hussar', + 'Jakubek', + 'Kluender', + 'Mcelhinny', + 'Salatino', + 'Sangalang', + 'Schoenfeldt', + 'Stogdill', + 'Svitak', + 'Taravella', + 'Tezak', + 'Wieseler', + 'Komperda', + 'Reinitz', + 'Malis', + 'Duce', + 'Salib', + 'Keelin', + 'Labell', + 'Symmonds', + 'Gwynne', + 'Byus', + 'Burgy', + 'Delfosse', + 'Benskin', + 'Hedgepath', + 'Ursin', + 'Kinnebrew', + 'Tinnon', + 'Callum', + 'Allah', + 'Arduini', + 'Azucena', + 'Birkel', + 'Bowermaster', + 'Caires', + 'Chrobak', + 'Cottier', + 'Cropley', + 'Crotteau', + 'Dutan', + 'Ezernack', + 'Fabiani', + 'Fauser', + 'Feeny', + 'Ferdig', + 'Fliss', + 'Gallus', + 'Harlacher', + 'Hasselbach', + 'Honsinger', + 'Landberg', + 'Lohn', + 'Losinski', + 'Maung', + 'Melikian', + 'Nooney', + 'Oyervides', + 'Prum', + 'Riepe', + 'Seebach', + 'Sendejas', + 'Sprick', + 'Torino', + 'Weida', + 'Geschke', + 'Girgenti', + 'Klever', + 'Rathert', + 'Roszell', + 'Sarich', + 'Shimmin', + 'Trimpe', + 'Turrubiates', + 'Zelada', + 'Danzig', + 'Diamant', + 'Hannen', + 'Odland', + 'Puzzo', + 'Slyter', + 'Smaldone', + 'Ebey', + 'Beg', + 'Magel', + 'Tebbs', + 'Gali', + 'Winney', + 'Juba', + 'Stargel', + 'Waren', + 'Stann', + 'Ducasse', + 'Vaugh', + 'Lewers', + 'Stjuste', + 'Heckstall', + 'Bokhari', + 'Bonino', + 'Brummond', + 'Caterino', + 'Deatrick', + 'Decorte', + 'Demara', + 'Dubree', + 'Dulski', + 'Feck', + 'Foglio', + 'Heinzelman', + 'Jory', + 'Knoell', + 'Kronick', + 'Maclay', + 'Mastrogiovanni', + 'Reichling', + 'Rueff', + 'Sellitto', + 'Sensing', + 'Sheu', + 'Soberanes', + 'Stahlecker', + 'Wholey', + 'Yochim', + 'Zeiss', + 'Bojanowski', + 'Bonawitz', + 'Caporaso', + 'Dalesio', + 'Exposito', + 'Giovinazzo', + 'Palardy', + 'Rastogi', + 'Saenger', + 'Sirek', + 'Sonoda', + 'Sovereign', + 'Weimann', + 'Wirtanen', + 'Enerson', + 'Olliff', + 'Kallam', + 'Leggitt', + 'Goude', + 'Rampey', + 'Letsinger', + 'Walles', + 'Kater', + 'Betsill', + 'Creese', + 'Lisbon', + 'Abitz', + 'Bednarik', + 'Bendorf', + 'Berkovich', + 'Brevik', + 'Cassatt', + 'Ciarlo', + 'Cookman', + 'Cosma', + 'Defee', + 'Essner', + 'Fallas', + 'Holda', + 'Kemler', + 'Kovich', + 'Krimmel', + 'Landauer', + 'Meharg', + 'Moncus', + 'Nabi', + 'Redenbaugh', + 'Ruwe', + 'Scalisi', + 'Shughart', + 'Sloma', + 'Sovine', + 'Tomaso', + 'Trueba', + 'Urista', + 'Vanyo', + 'Wolanski', + 'Zettle', + 'Arvanitis', + 'Baeten', + 'Caponi', + 'Carrazco', + 'Galambos', + 'Hartsook', + 'Helseth', + 'Kobylarz', + 'Krugh', + 'Meckel', + 'Ohnemus', + 'Voytek', + 'Winegarden', + 'Zuba', + 'Piloto', + 'Shames', + 'Debella', + 'Keddy', + 'Perra', + 'Winks', + 'Hemrick', + 'Snowdon', + 'Cleere', + 'Leavey', + 'Courington', + 'Herson', + 'Nelon', + 'Bloise', + 'Mcphie', + 'Catledge', + 'Mcneary', + 'Hoffler', + 'Suell', + 'Coard', + 'Woolfork', + 'Biros', + 'Brouhard', + 'Dinovo', + 'Disano', + 'Emami', + 'Flegal', + 'Hardebeck', + 'Hobin', + 'Huttner', + 'Kloosterman', + 'Knutzen', + 'Kopinski', + 'Mailman', + 'Mankey', + 'Mccamish', + 'Mccorquodale', + 'Minichiello', + 'Miyasaki', + 'Osher', + 'Prutzman', + 'Sagen', + 'Shawgo', + 'Sokolow', + 'Southam', + 'Sulik', + 'Wiedel', + 'Wollschlager', + 'Cantalupo', + 'Cruser', + 'Denomme', + 'Dinardi', + 'Donahey', + 'Havlin', + 'Lasecki', + 'Margraf', + 'Mchaffie', + 'Mihaly', + 'Omlor', + 'Roope', + 'Schremp', + 'Vanhecke', + 'Washabaugh', + 'Zaunbrecher', + 'Joost', + 'Pensinger', + 'Kraner', + 'Mikles', + 'Delair', + 'Bukhari', + 'Earll', + 'Sans', + 'Gatliff', + 'Casteneda', + 'Shalom', + 'Fidalgo', + 'Leitao', + 'Degrange', + 'Fruits', + 'Kercheval', + 'Mew', + 'Chopin', + 'Seawood', + 'Agro', + 'Aliano', + 'Badour', + 'Betsch', + 'Buchbinder', + 'Cleavenger', + 'Collazos', + 'Cusmano', + 'Dienes', + 'Dittus', + 'Eggenberger', + 'Fierst', + 'Gingell', + 'Greever', + 'Grisales', + 'Hegstrom', + 'Justen', + 'Kalt', + 'Kirkhart', + 'Krage', + 'Kyzar', + 'Livolsi', + 'Neyhart', + 'Nunziata', + 'Orlich', + 'Parcel', + 'Peshlakai', + 'Schemm', + 'Segner', + 'Urieta', + 'Wolfman', + 'Coonradt', + 'Disilvestro', + 'Dobrowski', + 'Gramza', + 'Kotlyar', + 'Micka', + 'Miksch', + 'Mione', + 'Montone', + 'Palmerton', + 'Parrill', + 'Passafiume', + 'Rosoff', + 'Spaziani', + 'Venditto', + 'Wisch', + 'Fini', + 'Horky', + 'Perel', + 'Arzuaga', + 'Nasworthy', + 'Carland', + 'Elden', + 'Moises', + 'Maione', + 'Glace', + 'Laverdure', + 'Sieh', + 'Toulouse', + 'Hannam', + 'Cumber', + 'Rendell', + 'Hardey', + 'Maddison', + 'Brittle', + 'Helen', + 'Aina', + 'Allwood', + 'Fenty', + 'Herard', + 'Traore', + 'Ator', + 'Bedsaul', + 'Bickert', + 'Brendlinger', + 'Camuso', + 'Dutter', + 'Eastlick', + 'Fernholz', + 'Guza', + 'Heitzenrater', + 'Huo', + 'Isbill', + 'Katzenstein', + 'Keigley', + 'Kelnhofer', + 'Klarich', + 'Mangat', + 'Mathiason', + 'Murzyn', + 'Odenthal', + 'Pascarelli', + 'Passwaters', + 'Rotunda', + 'Schons', + 'Sein', + 'Sobon', + 'Stayner', + 'Tri', + 'Uhlir', + 'Viscusi', + 'Winstanley', + 'Xi', + 'Yodice', + 'Aerts', + 'Antosh', + 'Baldinger', + 'Brislin', + 'Christopoulos', + 'Faurot', + 'Fusselman', + 'Hamsher', + 'Henckel', + 'Macht', + 'Moellering', + 'Oclair', + 'Pavelko', + 'Poehlman', + 'Rajewski', + 'Richcreek', + 'Schmeichel', + 'Venkatesh', + 'Zemba', + 'Zuelke', + 'Dechellis', + 'Reddig', + 'Splain', + 'Claw', + 'Mottram', + 'Crise', + 'Villaflor', + 'Allocca', + 'Buttrum', + 'Cocking', + 'Mundie', + 'Tavis', + 'Saidi', + 'Latter', + 'Tuberville', + 'Spease', + 'Leatherberry', + 'Peatross', + 'Claridy', + 'Duerson', + 'Durley', + 'Mekonnen', + 'Thiam', + 'Aderman', + 'Al', + 'Andreu', + 'Beine', + 'Bowron', + 'Campi', + 'Chura', + 'Ciraulo', + 'Daywalt', + 'Fleek', + 'Friant', + 'Gahm', + 'Gongaware', + 'Grosh', + 'Heaslip', + 'Knape', + 'Kravets', + 'Kritikos', + 'Kumagai', + 'Kustra', + 'Madani', + 'Mich', + 'Norlander', + 'Paulhus', + 'Rabanal', + 'Saker', + 'Stupak', + 'Suchomel', + 'Vandenberghe', + 'Wehrenberg', + 'Zaccardi', + 'Davlin', + 'Dykhouse', + 'Grandfield', + 'Hullender', + 'Kallis', + 'Livshits', + 'Rihn', + 'Criger', + 'Michl', + 'Tutino', + 'Zulueta', + 'Cristo', + 'Meline', + 'Fetch', + 'Dung', + 'Shami', + 'Teale', + 'Cocker', + 'Eshbach', + 'Phagan', + 'Millea', + 'Tayloe', + 'Olivia', + 'Houchen', + 'Peddy', + 'Ferryman', + 'Boodram', + 'Maduro', + 'Fullman', + 'Landingham', + 'Pee', + 'Argenbright', + 'Aronowitz', + 'Baldenegro', + 'Barentine', + 'Bernasconi', + 'Bicking', + 'Bohle', + 'Camerer', + 'Dufford', + 'Ende', + 'Gessel', + 'Grauman', + 'Jaqua', + 'Kagawa', + 'Kalinski', + 'Kanz', + 'Klasen', + 'Koloski', + 'Kriete', + 'Litalien', + 'Maish', + 'Massar', + 'Muraski', + 'Pickelsimer', + 'Sagraves', + 'Servellon', + 'Shellito', + 'Shiveley', + 'Stanislaw', + 'Volland', + 'Biehle', + 'Cruey', + 'Eagar', + 'Ermis', + 'Goracke', + 'Mackert', + 'Malloch', + 'Merillat', + 'Rylee', + 'Schelin', + 'Tibbals', + 'Zandi', + 'Golde', + 'Steuart', + 'Jamie', + 'Lavis', + 'Bromwell', + 'Tregre', + 'Alkhatib', + 'Carvey', + 'Essa', + 'Wale', + 'Mccarey', + 'Brandley', + 'Hermon', + 'Stenhouse', + 'Oguinn', + 'Barclift', + 'Sylvan', + 'Smyre', + 'Ellerby', + 'Alemany', + 'Beyl', + 'Boven', + 'Bultema', + 'Buzan', + 'Cappo', + 'Cottongim', + 'Detore', + 'Dierolf', + 'Dueck', + 'Egelston', + 'Emard', + 'Eveleth', + 'Ferrini', + 'Fodera', + 'Hidy', + 'Kahley', + 'Karasik', + 'Klare', + 'Koudelka', + 'Lafleche', + 'Minturn', + 'Montemarano', + 'Plock', + 'Ratterman', + 'Reingold', + 'Rieber', + 'Schnackenberg', + 'Schrade', + 'Steffek', + 'Stehling', + 'Sticha', + 'Velaquez', + 'Weissberg', + 'Allnutt', + 'Barkhurst', + 'Bettendorf', + 'Canonico', + 'Deshmukh', + 'Dobosz', + 'Glab', + 'Kirkeby', + 'Menapace', + 'Parizek', + 'Pursifull', + 'Ragucci', + 'Raisch', + 'Schronce', + 'Tuason', + 'Duross', + 'Hainer', + 'Kinnick', + 'Rens', + 'Williamsen', + 'Hilke', + 'Hark', + 'Mellett', + 'Decarvalho', + 'Filyaw', + 'Sian', + 'Mccard', + 'Symon', + 'Grade', + 'Giboney', + 'Sadik', + 'Caul', + 'Gater', + 'Sulton', + 'Dungee', + 'Adriance', + 'Almas', + 'Andler', + 'Bellina', + 'Belshe', + 'Blouch', + 'Bradeen', + 'Brandwein', + 'Buechele', + 'Cristina', + 'Davidov', + 'Defiore', + 'Defrain', + 'Derasmo', + 'Dober', + 'Grosshans', + 'Hoek', + 'Hofstad', + 'Ingman', + 'Kille', + 'Langill', + 'Matic', + 'Niederer', + 'Novella', + 'Oelkers', + 'Percifield', + 'Phariss', + 'Pola', + 'Pompei', + 'Potthast', + 'Raden', + 'Radick', + 'Rendina', + 'Sicotte', + 'Sleep', + 'Wadhwa', + 'Buccheri', + 'Calogero', + 'Catrett', + 'Flemmer', + 'Mancinas', + 'Mcmichen', + 'Measel', + 'Pudlo', + 'Ruether', + 'Shusterman', + 'Stabley', + 'Teffeteller', + 'Waisanen', + 'Zappulla', + 'Symanski', + 'Mckenrick', + 'Moger', + 'Obispo', + 'Armenteros', + 'Roses', + 'Makki', + 'Faley', + 'Rumford', + 'Schonberg', + 'Hizer', + 'Blaydes', + 'Coor', + 'Mccalip', + 'Stancill', + 'Cal', + 'Murat', + 'Amie', + 'Placide', + 'Akpan', + 'Bembenek', + 'Bilyk', + 'Bizzarro', + 'Bugge', + 'Cunnane', + 'Degenhart', + 'Doehring', + 'Flammia', + 'Fritcher', + 'Godinho', + 'Gouger', + 'Heyboer', + 'Humenik', + 'Iannaccone', + 'Lacivita', + 'Lagunes', + 'Leitzke', + 'Luty', + 'Maute', + 'Micke', + 'Midura', + 'Nydam', + 'Rasp', + 'Rediker', + 'Requejo', + 'Roskos', + 'Ruckert', + 'Saldierna', + 'Salemme', + 'Tsuchiya', + 'Vallas', + 'Werder', + 'Arenivas', + 'Bartholomay', + 'Brozowski', + 'Dusza', + 'Frevert', + 'Giannopoulos', + 'Kormos', + 'Martos', + 'Mollenhauer', + 'Romanek', + 'Solinger', + 'Tomaro', + 'Zangara', + 'Buttrick', + 'Pardy', + 'Alvelo', + 'Breth', + 'Hemond', + 'Kayes', + 'Manne', + 'Grandchamp', + 'Gilbo', + 'Calame', + 'Clippard', + 'Gieger', + 'Penalver', + 'Ecton', + 'Totton', + 'Poyser', + 'Kettles', + 'Hosang', + 'Waker', + 'Maryland', + 'Girma', + 'Baribeau', + 'Boehnke', + 'Brunick', + 'Buhrow', + 'Cerreta', + 'Dascoli', + 'Eroh', + 'Fallert', + 'Fotopoulos', + 'Granholm', + 'Hebdon', + 'Hoelzer', + 'Hyser', + 'Lisanti', + 'Mastrianni', + 'Mewes', + 'Mulanax', + 'Nikolai', + 'Odekirk', + 'Ofallon', + 'Onnen', + 'Or', + 'Osso', + 'Ridpath', + 'Schara', + 'Schnipke', + 'Slayter', + 'Sodhi', + 'Steffler', + 'Stegemann', + 'Weisensel', + 'Bertling', + 'Dueitt', + 'Keehner', + 'Khaimov', + 'Kramlich', + 'Salkeld', + 'Ulbricht', + 'Vultaggio', + 'Dennin', + 'Mondo', + 'Kett', + 'Dom', + 'Kalan', + 'Yaney', + 'Nicley', + 'Carabello', + 'Ellegood', + 'Mcglocklin', + 'Figuero', + 'Pillard', + 'Wolfrey', + 'Leys', + 'Cobert', + 'Wahid', + 'Fede', + 'Ausbrooks', + 'Gums', + 'Gillion', + 'Mcgeachy', + 'Parran', + 'Likely', + 'Marbley', + 'Argote', + 'Bhullar', + 'Botros', + 'Brethauer', + 'Chell', + 'Conradi', + 'Covill', + 'Crays', + 'Crysler', + 'Handke', + 'Hanneken', + 'Hidrogo', + 'Hirayama', + 'Huebert', + 'Hurford', + 'Iskra', + 'Malczewski', + 'Menees', + 'Monforte', + 'Murdick', + 'Naclerio', + 'Nohr', + 'Pangallo', + 'Payeur', + 'Pozniak', + 'Rammel', + 'Schield', + 'Schrick', + 'Seifer', + 'Sperduto', + 'Stagliano', + 'Staubs', + 'Stromme', + 'Tourigny', + 'Traister', + 'Vandecar', + 'Wilhelms', + 'Wilinski', + 'Wittke', + 'Clougherty', + 'Crotwell', + 'Hannula', + 'Heavrin', + 'Heidinger', + 'Keehan', + 'Ortwein', + 'Palinkas', + 'Seivert', + 'Sloniker', + 'Yielding', + 'Lac', + 'Shove', + 'Venard', + 'Violett', + 'Foresta', + 'Gapp', + 'Dejongh', + 'Ambrosia', + 'Simkin', + 'Sastre', + 'Mcarthy', + 'Bering', + 'Sarah', + 'Hickling', + 'Sookdeo', + 'Val', + 'Colden', + 'Feltus', + 'Hailes', + 'Canizalez', + 'Cloke', + 'Connole', + 'Dancel', + 'Demmon', + 'Ehrler', + 'Fruchey', + 'Helinski', + 'Hepfer', + 'Katzen', + 'Kressler', + 'Lagrow', + 'Nethercutt', + 'Novitski', + 'Papale', + 'Pesola', + 'Petrosian', + 'Pies', + 'Prazak', + 'Preza', + 'Reiche', + 'Salle', + 'Savic', + 'Servello', + 'Sherbondy', + 'Solazzo', + 'Stabenow', + 'Walstad', + 'Yaden', + 'Zagal', + 'Zani', + 'Dimambro', + 'Engquist', + 'Fochtman', + 'Frasch', + 'Fuerstenberg', + 'Galus', + 'Gronowski', + 'Grossenbacher', + 'Hahs', + 'Iavarone', + 'Kerper', + 'Kravchenko', + 'Kwolek', + 'Lusignan', + 'Lybbert', + 'Maertens', + 'Mahany', + 'Medico', + 'Orrantia', + 'Reitmeier', + 'Sieve', + 'Sterbenz', + 'Tenpas', + 'Wischmeyer', + 'Zajkowski', + 'Cregg', + 'Shetley', + 'Tisher', + 'Coup', + 'Murdy', + 'Lysaght', + 'Sesco', + 'Koy', + 'Wakley', + 'Bertholf', + 'Swaner', + 'Stakes', + 'Gren', + 'Elahi', + 'Torney', + 'Gopaul', + 'Egland', + 'Gingles', + 'Aurich', + 'Biela', + 'Binz', + 'Blumenstock', + 'Boardwine', + 'Boehner', + 'Boening', + 'Crankshaw', + 'Decarli', + 'Fauble', + 'Georgopoulos', + 'Gieske', + 'Hasselbring', + 'Heeb', + 'Janosik', + 'Kalafut', + 'Karpf', + 'Kramm', + 'Lanyon', + 'Lewelling', + 'Lilla', + 'Marik', + 'Moyano', + 'Oppel', + 'Panagos', + 'Renovato', + 'Rohlman', + 'Rostron', + 'Todhunter', + 'Torello', + 'Umfleet', + 'Wien', + 'Youker', + 'Ytuarte', + 'Zavada', + 'Altvater', + 'Arnzen', + 'Blixt', + 'Elek', + 'Geiselman', + 'Hiltunen', + 'Jachim', + 'Kolenovic', + 'Kooyman', + 'Muecke', + 'Pierron', + 'Preisler', + 'Rogus', + 'Schoeller', + 'Solimine', + 'Speagle', + 'Courser', + 'Mascarenhas', + 'Dorer', + 'Scotten', + 'Goy', + 'Avers', + 'Blanca', + 'Choung', + 'Goleman', + 'Nanna', + 'Lave', + 'Seley', + 'Meggison', + 'Ripoll', + 'Mannan', + 'Bihm', + 'Tribbey', + 'Ports', + 'Asby', + 'Philibert', + 'Furby', + 'Keal', + 'Louallen', + 'Idris', + 'Artist', + 'Branford', + 'Sabree', + 'Ainley', + 'Amezola', + 'Andreason', + 'Athans', + 'Batiz', + 'Bostelman', + 'Bozic', + 'Butman', + 'Coiro', + 'Defina', + 'Garbo', + 'Gewirtz', + 'Hathcoat', + 'Heebner', + 'Helbing', + 'Kasler', + 'Kastler', + 'Kearby', + 'Krus', + 'Lezotte', + 'Lithgow', + 'Mealor', + 'Moltz', + 'Morcom', + 'Norbeck', + 'Novicki', + 'Osmani', + 'Posluszny', + 'Quiroa', + 'Rahal', + 'Roddenberry', + 'Rodino', + 'Sallade', + 'Saraceni', + 'Schmaus', + 'Stathopoulos', + 'Swatek', + 'Tupy', + 'Vonseggern', + 'Zens', + 'Ahonen', + 'Arrazola', + 'Avedisian', + 'Bachtell', + 'Bastarache', + 'Chavero', + 'Darienzo', + 'Giampa', + 'Gillott', + 'Hierholzer', + 'Kruckeberg', + 'Lafrenz', + 'Milkowski', + 'Missildine', + 'Passaretti', + 'Rogstad', + 'Saadeh', + 'Sielski', + 'Slavick', + 'Tieken', + 'Wittenmyer', + 'Yepiz', + 'Zimdars', + 'Rail', + 'Kook', + 'Jian', + 'Piet', + 'Sanjurjo', + 'Shampine', + 'Christel', + 'Hechavarria', + 'Blucher', + 'Crimm', + 'Lebreton', + 'Charbonnet', + 'Bolls', + 'Stroder', + 'Baise', + 'Mcnease', + 'Alen', + 'Priestly', + 'Mannie', + 'Doleman', + 'Areas', + 'Atayde', + 'Berent', + 'Bodmer', + 'Brodin', + 'Buntrock', + 'Eckrich', + 'Emberson', + 'Hilgert', + 'Hirn', + 'Holihan', + 'Hoshino', + 'Jeung', + 'Leece', + 'Leonardis', + 'Macera', + 'Mcferron', + 'Muster', + 'Naef', + 'Pecka', + 'Peloso', + 'Pensyl', + 'Reaney', + 'Reidinger', + 'Rockholt', + 'Tabrizi', + 'Trauth', + 'Trulock', + 'Tupou', + 'Asbridge', + 'Franzel', + 'Gesualdi', + 'Grimwood', + 'Hardinger', + 'Kondrat', + 'Koskinen', + 'Ludolph', + 'Marchesi', + 'Mehrtens', + 'Racioppi', + 'Sabey', + 'Stroebel', + 'Swendsen', + 'Vandewalker', + 'Korber', + 'Messler', + 'Mowat', + 'Kor', + 'Pua', + 'Sarazin', + 'Wayson', + 'Oland', + 'Bandi', + 'Fabel', + 'Frankl', + 'Rane', + 'Mozer', + 'Weaber', + 'Moustafa', + 'Robe', + 'Lindy', + 'Medaris', + 'Derden', + 'Benthall', + 'Ayler', + 'Osias', + 'Choyce', + 'Scantlebury', + 'Patmon', + 'Ahlgrim', + 'Boffa', + 'Brideau', + 'Bubeck', + 'Bubel', + 'Casio', + 'Casique', + 'Casten', + 'Colebank', + 'Demoura', + 'Devincenzo', + 'Elsesser', + 'Fauci', + 'Frentz', + 'Hemler', + 'Keitel', + 'Luan', + 'Luhn', + 'Luquette', + 'Mazurowski', + 'Mendibles', + 'Mickiewicz', + 'Minelli', + 'Mistler', + 'Nemer', + 'Nikolaus', + 'Offill', + 'Pezza', + 'Ruzich', + 'Skrzypek', + 'Swimmer', + 'Trucks', + 'Vaccarella', + 'Zeidman', + 'Brattin', + 'Deblock', + 'Dufrane', + 'Gural', + 'Hufstedler', + 'Kapuscinski', + 'Lyerla', + 'Musolino', + 'Neubecker', + 'Polus', + 'Protzman', + 'Retzloff', + 'Sachdev', + 'Sazama', + 'Shrider', + 'Tobolski', + 'Mcbane', + 'Clabo', + 'Fredrich', + 'Lace', + 'Bertran', + 'Kama', + 'Simonet', + 'Lippitt', + 'Thomlinson', + 'Vallot', + 'Dede', + 'Brimley', + 'Parler', + 'Standfield', + 'Goodie', + 'Isidore', + 'Philogene', + 'Abramczyk', + 'Andert', + 'Besancon', + 'Bieda', + 'Birkey', + 'Boquet', + 'Borak', + 'Bottino', + 'Breyfogle', + 'Crill', + 'Daffern', + 'Derrig', + 'Dimalanta', + 'Dresch', + 'Feulner', + 'Friede', + 'Furth', + 'Gamet', + 'Garramone', + 'Gaunce', + 'Gitto', + 'Guandique', + 'Hoxworth', + 'Hubers', + 'Ingwersen', + 'Junio', + 'Kassing', + 'Magrath', + 'Martelle', + 'Mcweeney', + 'Neris', + 'Nesheiwat', + 'Remlinger', + 'Rentmeester', + 'Schlein', + 'Schoneman', + 'Sterr', + 'Streib', + 'Szymanowski', + 'Trompeter', + 'Tullius', + 'Cherico', + 'Cremin', + 'Dominey', + 'Gotthardt', + 'Kowalke', + 'Onderdonk', + 'Pirrello', + 'Rumberger', + 'Schreur', + 'Westerhoff', + 'Maroni', + 'Dire', + 'Menta', + 'Hoeg', + 'Meise', + 'Standerfer', + 'Roam', + 'Tibbett', + 'Beevers', + 'Evrard', + 'Locklair', + 'Brester', + 'Sirmon', + 'Woodbeck', + 'Wires', + 'Durette', + 'Raul', + 'Stephanie', + 'Mcwain', + 'Skeeters', + 'Wilbourne', + 'Debroux', + 'Keyton', + 'Noris', + 'Fanta', + 'Goshen', + 'Kithcart', + 'Shepheard', + 'Sherod', + 'Buntyn', + 'Gissendanner', + 'Goodley', + 'Mckissic', + 'Bissinger', + 'Biswell', + 'Borruso', + 'Danese', + 'Eslava', + 'Gehle', + 'Gibeau', + 'Gionet', + 'Greth', + 'Gul', + 'Hambley', + 'Harshfield', + 'Helin', + 'Henken', + 'Hogland', + 'Hoxha', + 'Hurlbutt', + 'Kaminer', + 'Kien', + 'Kliebert', + 'Koivisto', + 'Kooken', + 'Laconte', + 'Lovo', + 'Manninen', + 'Maxham', + 'Mcleland', + 'Mclerran', + 'Milici', + 'Negrette', + 'Nicotera', + 'Nissan', + 'Philipson', + 'Pimenta', + 'Pinch', + 'Rietveld', + 'Seyller', + 'Shollenberger', + 'Sochacki', + 'Telleria', + 'Toda', + 'Unrue', + 'Vanbenschoten', + 'Versace', + 'Villada', + 'Watry', + 'Wirsing', + 'Zeimet', + 'Zynda', + 'Angelillo', + 'Fleissner', + 'Freehling', + 'Grewell', + 'Heick', + 'Kartes', + 'Kishi', + 'Kopke', + 'Laubenstein', + 'Leske', + 'Lohmeier', + 'Marotz', + 'Moccio', + 'Mullineaux', + 'Muzyka', + 'Ostermiller', + 'Penuelas', + 'Plagge', + 'Stolarz', + 'Wertenberger', + 'Sella', + 'Allinger', + 'Betzler', + 'Rosenkrantz', + 'Trimarchi', + 'Dionicio', + 'Frohman', + 'Landenberger', + 'Shillings', + 'Chill', + 'Leather', + 'Sonn', + 'Connel', + 'Fougere', + 'Alia', + 'Wisby', + 'Haisley', + 'Minion', + 'Mccathern', + 'Rozzell', + 'Armbrister', + 'Ryant', + 'Almeyda', + 'Bonjour', + 'Bordas', + 'Bozard', + 'Buccola', + 'Cihlar', + 'Dargis', + 'Faivre', + 'Fejes', + 'Grulke', + 'Harken', + 'Heimberger', + 'Hochmuth', + 'Keadle', + 'Kedrowski', + 'Kortman', + 'Krahenbuhl', + 'Krasniqi', + 'Kundrat', + 'Leistner', + 'Loguidice', + 'Mcauliff', + 'Mchatton', + 'Minella', + 'Muccio', + 'Normington', + 'Nuttle', + 'Orsino', + 'Reker', + 'Respicio', + 'Shein', + 'Teichert', + 'Varisco', + 'Accomando', + 'Amelio', + 'Burckhard', + 'Fleischhacker', + 'Hagglund', + 'Kessenich', + 'Langrehr', + 'Lauderbaugh', + 'Misquez', + 'Muneton', + 'Ourada', + 'Rulon', + 'Scholze', + 'Stellmach', + 'Sudano', + 'Thelander', + 'Yeckley', + 'Corsino', + 'Grage', + 'Isla', + 'Narramore', + 'Coolman', + 'Heatherington', + 'Newey', + 'Kunda', + 'Motts', + 'Tawfik', + 'Tindel', + 'Passon', + 'Sypher', + 'Conceicao', + 'Haraway', + 'Deamer', + 'Nored', + 'Mamo', + 'Mcgilberry', + 'Akerley', + 'Andreatta', + 'Aronhalt', + 'Barz', + 'Bebber', + 'Brubacher', + 'Cabriales', + 'Dyckman', + 'Ellers', + 'Finerty', + 'Hargan', + 'Haselton', + 'Hellmuth', + 'Hoffmeier', + 'Homrich', + 'Hrabak', + 'Intrieri', + 'Lebeda', + 'Lutzke', + 'Malka', + 'Mcglinn', + 'Nicklin', + 'Nusz', + 'Pennings', + 'Rebmann', + 'Rodocker', + 'Sacra', + 'Saksa', + 'Shehane', + 'Siever', + 'Snide', + 'Sotero', + 'Sponsel', + 'Therien', + 'Viti', + 'Wubben', + 'Zieske', + 'Billingham', + 'Bruschi', + 'Cullipher', + 'Eppolito', + 'Greuel', + 'Huq', + 'Matott', + 'Mohlman', + 'Monterroza', + 'Risberg', + 'Shvartsman', + 'Sigafoos', + 'Zehring', + 'Manuele', + 'Asghar', + 'Shelp', + 'Grieder', + 'Hippert', + 'Dani', + 'Beserra', + 'Kennan', + 'Scholfield', + 'Joh', + 'Swailes', + 'Pear', + 'Hell', + 'Kittler', + 'Pickeral', + 'Somerset', + 'Streat', + 'Tinner', + 'Landor', + 'Pretlow', + 'Tensley', + 'Abela', + 'Abramovich', + 'Acocella', + 'Avino', + 'Bacchi', + 'Bayliff', + 'Beganovic', + 'Belinsky', + 'Bilicki', + 'Borowiec', + 'Bucknam', + 'Calandro', + 'Ciszek', + 'Cooling', + 'Cundari', + 'Derk', + 'Ekern', + 'Engelson', + 'Fennessey', + 'Ferencz', + 'Filipkowski', + 'Frescas', + 'Frisinger', + 'Gegg', + 'Hanken', + 'Harbach', + 'Jipson', + 'Kasal', + 'Kinstler', + 'Langenbach', + 'Leccese', + 'Maalouf', + 'Mcinerny', + 'Mcpartlin', + 'Meth', + 'Mitzner', + 'Riano', + 'Saggese', + 'Schroff', + 'Skibicki', + 'Textor', + 'Vancampen', + 'Vukelich', + 'Wascom', + 'Workinger', + 'Xin', + 'Bronkema', + 'Gerstel', + 'Geving', + 'Gravlin', + 'Hannay', + 'Haughn', + 'Lippi', + 'Lonsway', + 'Paradowski', + 'Poust', + 'Thinnes', + 'Wassenaar', + 'Hemm', + 'Isip', + 'Pastorino', + 'Barkett', + 'Montalban', + 'Ballestero', + 'Floren', + 'Rossen', + 'Chuba', + 'Burrington', + 'Derman', + 'Wickland', + 'Dunman', + 'Beek', + 'Petitjean', + 'Michelin', + 'Chapell', + 'Pullam', + 'Adamcik', + 'Albarracin', + 'Batrez', + 'Berghuis', + 'Birkland', + 'Boulier', + 'Broderson', + 'Bruun', + 'Cicio', + 'Davidow', + 'Denova', + 'Dooner', + 'Espeland', + 'Fifita', + 'Guidone', + 'Hartnell', + 'Havranek', + 'Janca', + 'Klepac', + 'Langhorst', + 'Lippmann', + 'Merrihew', + 'Mondelli', + 'Monterosso', + 'Moster', + 'Noxon', + 'Poznanski', + 'Reents', + 'Samaras', + 'Silvius', + 'Srour', + 'Stasio', + 'Steffe', + 'Steimer', + 'Stracke', + 'Taney', + 'Theodorou', + 'Trickel', + 'Tunks', + 'Vavrek', + 'Whitfill', + 'Wohlfeil', + 'Zirkelbach', + 'Brissey', + 'Busboom', + 'Collignon', + 'Emling', + 'Fratzke', + 'Genrich', + 'Giglia', + 'Hayakawa', + 'Lupinski', + 'Pulvermacher', + 'Steinbrink', + 'Xayavong', + 'Yerkey', + 'Arlotta', + 'Calia', + 'Pfiffner', + 'Gostomski', + 'Declerck', + 'Demedeiros', + 'Dirickson', + 'Wo', + 'Hosie', + 'Chad', + 'Herbison', + 'Fleece', + 'Connon', + 'Dun', + 'Gaffin', + 'Plush', + 'Gravette', + 'Houseal', + 'Seaward', + 'Esson', + 'Mayhorn', + 'Surrell', + 'Horsford', + 'Mcduffey', + 'Huger', + 'Alexie', + 'Apsey', + 'Belke', + 'Bourcier', + 'Cardena', + 'Daun', + 'Dunworth', + 'Ehrsam', + 'Elizardo', + 'Elkhatib', + 'Emick', + 'Fernau', + 'Finnan', + 'Hitzeman', + 'Housand', + 'Kallstrom', + 'Katen', + 'Kerstein', + 'Kiracofe', + 'Klammer', + 'Largaespada', + 'Limoges', + 'Lodwick', + 'Lozito', + 'Madl', + 'Mauthe', + 'Mogel', + 'Newstrom', + 'Ninh', + 'Obrochta', + 'Opsal', + 'Ordiway', + 'Osentoski', + 'Paxman', + 'Plume', + 'Rickenbach', + 'Rinks', + 'Saltmarsh', + 'Scheuring', + 'Schwegel', + 'Skov', + 'Woodrome', + 'Zdanowicz', + 'Zera', + 'Basgall', + 'Bornhorst', + 'Clotfelter', + 'Coulthard', + 'Dresner', + 'Fischl', + 'Grahek', + 'Grefe', + 'Knightly', + 'Kuenzel', + 'Mccumbers', + 'Millstein', + 'Mulnix', + 'Weiher', + 'Yust', + 'Metter', + 'Polio', + 'Ayad', + 'Banke', + 'Lawlis', + 'Coba', + 'Twyford', + 'Burck', + 'Barthold', + 'Sames', + 'Jacquot', + 'Allsopp', + 'Mcglaun', + 'Hollinsworth', + 'Gillings', + 'Buchannon', + 'Bas', + 'Beaber', + 'Berto', + 'Bobrow', + 'Bochicchio', + 'Bohland', + 'Burghart', + 'Chaloux', + 'Costella', + 'Depace', + 'Dils', + 'Diviney', + 'Ehly', + 'Ermer', + 'Fussner', + 'Gunia', + 'Guterrez', + 'Holik', + 'Holster', + 'Kasperski', + 'Koscinski', + 'Lamoureaux', + 'Marotti', + 'Masullo', + 'Mcconahy', + 'Mehlhaff', + 'Mocarski', + 'Moosman', + 'Pavlich', + 'Pfisterer', + 'Ruacho', + 'Semrad', + 'Slemmer', + 'Stineman', + 'Toelle', + 'Vanderstelt', + 'Wagy', + 'Wuensch', + 'Wykes', + 'Zar', + 'Bouchie', + 'Friis', + 'Gehrt', + 'Hempfling', + 'Henkes', + 'Huggler', + 'Kelbaugh', + 'Petrenko', + 'Pfost', + 'Rubendall', + 'Shimel', + 'Stapf', + 'Sweeton', + 'Tsuda', + 'Vitanza', + 'Voytko', + 'Bibbo', + 'Hagee', + 'Majer', + 'Mangieri', + 'Pala', + 'Volle', + 'Cabassa', + 'Lipsett', + 'Macdougal', + 'Minar', + 'Eline', + 'Eskin', + 'Angeletti', + 'Lattner', + 'Kimple', + 'Marsan', + 'Tornes', + 'Moncur', + 'Sanderfer', + 'Crite', + 'Levels', + 'Valcin', + 'Motton', + 'Foggie', + 'Battistoni', + 'Bedient', + 'Bendt', + 'Bennison', + 'Bonnin', + 'Caridi', + 'Cedotal', + 'Choinski', + 'Cossin', + 'Devargas', + 'Deveny', + 'Dosher', + 'Dredge', + 'Fittro', + 'Gorgone', + 'Gourd', + 'Herra', + 'Holwerda', + 'Iannello', + 'Klintworth', + 'Kubena', + 'Leyvas', + 'Magowan', + 'Mendolia', + 'Nehme', + 'Pelikan', + 'Pfalzgraf', + 'Raith', + 'Reichenberg', + 'Reinertsen', + 'Sens', + 'Simer', + 'Spektor', + 'Sweda', + 'Wordell', + 'Blasing', + 'Dinoto', + 'Goblirsch', + 'Helming', + 'Hibshman', + 'Lamountain', + 'Latka', + 'Licausi', + 'Malerba', + 'Mentink', + 'Meskill', + 'Moening', + 'Montminy', + 'Ryno', + 'Sluka', + 'Solarz', + 'Swainston', + 'Tagliaferri', + 'Twichell', + 'Vertucci', + 'Voland', + 'Wolgast', + 'Bissen', + 'Duray', + 'Flaum', + 'Taves', + 'Caplin', + 'Hayat', + 'Pollett', + 'Baris', + 'Taher', + 'Anes', + 'Beza', + 'Pere', + 'Tipper', + 'Farrey', + 'Slott', + 'Sinquefield', + 'Bobbett', + 'Calico', + 'Eigner', + 'Gambrill', + 'Donigan', + 'Daney', + 'Natt', + 'Gettis', + 'Kincy', + 'Dolberry', + 'Curenton', + 'Elzie', + 'Beretta', + 'Carbine', + 'Carpenito', + 'Clarin', + 'Conrado', + 'Conradt', + 'Courteau', + 'Daft', + 'Debruler', + 'Delahunty', + 'Duerst', + 'Dzik', + 'Ellner', + 'Faeth', + 'Fournet', + 'Galinski', + 'Goldenstein', + 'Hanauer', + 'Higgason', + 'Hoeper', + 'Hollo', + 'Ildefonso', + 'Jocson', + 'Kasprowicz', + 'Kochanowski', + 'Labrosse', + 'Lazaroff', + 'Leino', + 'Levinsky', + 'Lopezhernandez', + 'Mckeague', + 'Otremba', + 'Paluzzi', + 'Pevehouse', + 'Polgar', + 'Raneri', + 'Rumler', + 'Sanantonio', + 'Schissel', + 'Senteno', + 'Sieling', + 'Smee', + 'Swiggum', + 'Tarnow', + 'Tavakoli', + 'Tholl', + 'Valdiviezo', + 'Willadsen', + 'Wilmouth', + 'Dudziak', + 'Eskenazi', + 'Garity', + 'Gravino', + 'Impastato', + 'Kuhner', + 'Mcclaflin', + 'Nein', + 'Precourt', + 'Rotenberry', + 'Sciara', + 'Arenson', + 'Coupland', + 'Sedler', + 'Pizer', + 'Him', + 'Combee', + 'Rhorer', + 'Gelles', + 'Baroody', + 'Basten', + 'Sprinkles', + 'Vanier', + 'Clementson', + 'Robberson', + 'Harten', + 'Kade', + 'Bhola', + 'Bahar', + 'Pellum', + 'Isadore', + 'Dixie', + 'Axline', + 'Backs', + 'Berdahl', + 'Billeter', + 'Bily', + 'Broerman', + 'Declercq', + 'Derleth', + 'Fanucchi', + 'Forkey', + 'Gallinger', + 'Gionfriddo', + 'Gretzinger', + 'Grima', + 'Helgren', + 'Hoelting', + 'Hundertmark', + 'Inscho', + 'Jernberg', + 'Kamiya', + 'Lekas', + 'Marchini', + 'Markuson', + 'Matsushima', + 'Meineke', + 'Mizrachi', + 'Moglia', + 'Nagele', + 'Naro', + 'Padillo', + 'Palleschi', + 'Palomba', + 'Purgason', + 'Qadri', + 'Recalde', + 'Rosiak', + 'Rumney', + 'Savitt', + 'Shibuya', + 'Szalkowski', + 'Wagg', + 'Wolsey', + 'Zumpano', + 'Benbrook', + 'Blasdel', + 'Carusone', + 'Karalis', + 'Koep', + 'Kohles', + 'Rumbo', + 'Siggins', + 'Unverzagt', + 'Eatherly', + 'Kapper', + 'Salser', + 'Wege', + 'Zinsmeister', + 'Alf', + 'Wish', + 'Falero', + 'Bur', + 'Imam', + 'Biven', + 'Merritts', + 'Kaigler', + 'Verdell', + 'Feggins', + 'Acerra', + 'Antenucci', + 'Benegas', + 'Bisesi', + 'Boshers', + 'Chap', + 'Clouatre', + 'Doxtater', + 'Dullea', + 'Eischeid', + 'Gundry', + 'Hinger', + 'Hodak', + 'Iseminger', + 'Juris', + 'Kirchen', + 'Knezevic', + 'Kobrin', + 'Krizek', + 'Leza', + 'Lusty', + 'Luttrull', + 'Mattke', + 'Mossbarger', + 'Narro', + 'Osland', + 'Ostwald', + 'Pepperman', + 'Pritzl', + 'Reasner', + 'Schimming', + 'Schulenburg', + 'Trefry', + 'Vigorito', + 'Bayardo', + 'Bieser', + 'Brinkmeier', + 'Camposano', + 'Cremeens', + 'Delgrande', + 'Demopoulos', + 'Deyarmin', + 'Grismer', + 'Jubb', + 'Kinker', + 'Lauf', + 'Mabile', + 'Muehl', + 'Orlick', + 'Pillado', + 'Pizzano', + 'Poppleton', + 'Quickel', + 'Stoneberg', + 'Szwed', + 'Zadrozny', + 'Ziemke', + 'Zupko', + 'Diesel', + 'Hornbrook', + 'Pillion', + 'Holaway', + 'Massad', + 'Rossmiller', + 'Parriott', + 'Toya', + 'Dross', + 'Burwick', + 'Kaman', + 'Bruna', + 'Milles', + 'Acrey', + 'Toogood', + 'Austell', + 'Chastang', + 'Jasmine', + 'Eckford', + 'Stiggers', + 'Saintvil', + 'Adeyemi', + 'Basto', + 'Bolon', + 'Brilliant', + 'Brockhoff', + 'Colao', + 'Emens', + 'Endler', + 'Fabris', + 'Falletta', + 'Felver', + 'Ferdon', + 'Golinski', + 'Gosdin', + 'Gronlund', + 'Guijosa', + 'Hainley', + 'Halama', + 'Heinicke', + 'Heldenbrand', + 'Helmkamp', + 'Hoctor', + 'Hoeck', + 'Kroboth', + 'Lamagna', + 'Lingg', + 'Locurto', + 'Marchewka', + 'Micco', + 'Mormino', + 'Newmeyer', + 'Ostrosky', + 'Redel', + 'Saccoccio', + 'Stavely', + 'Stidd', + 'Tonne', + 'Tonnesen', + 'Umbach', + 'Vardanyan', + 'Wank', + 'Wolven', + 'Cilento', + 'Delmonaco', + 'Denigris', + 'Gerbig', + 'Gradilla', + 'Grebner', + 'Landini', + 'Marohl', + 'Muenchow', + 'Niedermeier', + 'Nussbaumer', + 'Nycz', + 'Pizzino', + 'Schader', + 'Schuneman', + 'Takano', + 'Ureta', + 'Vanderloop', + 'Windholz', + 'Wombacher', + 'Woulfe', + 'Hamley', + 'Schickel', + 'Yuill', + 'Batta', + 'Galant', + 'Mofield', + 'Kint', + 'Barnell', + 'Ashmead', + 'Crossin', + 'Lasco', + 'Chasen', + 'Swire', + 'Gleghorn', + 'Bearfield', + 'Goodgame', + 'Daris', + 'Plump', + 'Derricott', + 'Burno', + 'Baylock', + 'Vanterpool', + 'Judon', + 'Mells', + 'Proby', + 'Bagan', + 'Batcheller', + 'Bjelland', + 'Boline', + 'Boullion', + 'Broomall', + 'Carcia', + 'Cassinelli', + 'Cerro', + 'Colantuono', + 'Dembeck', + 'Doto', + 'Eckersley', + 'Edell', + 'Ewy', + 'Goodness', + 'Huhta', + 'Kallen', + 'Keimig', + 'Kemppainen', + 'Koopmann', + 'Lacap', + 'Lehtinen', + 'Maciolek', + 'Marchuk', + 'Mcfate', + 'Mentel', + 'Minihan', + 'Mohsin', + 'Oppedisano', + 'Patriarca', + 'Raske', + 'Schueneman', + 'Shostak', + 'Sibal', + 'Spadafore', + 'Suitor', + 'Tavella', + 'Vy', + 'Wies', + 'Beadnell', + 'Bogusz', + 'Cleverly', + 'Dellorusso', + 'Dudenhoeffer', + 'Glendinning', + 'Glomb', + 'Heinkel', + 'Jiwani', + 'Lonigro', + 'Machala', + 'Marsicano', + 'Neuenfeldt', + 'Overlock', + 'Popko', + 'Russomanno', + 'Saxer', + 'Scicchitano', + 'Spiegelberg', + 'Spindel', + 'Timpone', + 'Vincelette', + 'Waidelich', + 'Wissink', + 'Woolstenhulme', + 'Danza', + 'Sleasman', + 'Frometa', + 'Savinon', + 'Higgerson', + 'Helmich', + 'Nahar', + 'Campus', + 'Hassey', + 'Mccorkel', + 'Tola', + 'Ferrington', + 'Nicolls', + 'Markes', + 'Edgley', + 'Dupriest', + 'Wah', + 'Mclester', + 'Scantling', + 'Goffe', + 'Battie', + 'Battershell', + 'Bearup', + 'Bisig', + 'Brouillet', + 'Canby', + 'Chaussee', + 'Colandrea', + 'Colocho', + 'Daube', + 'Dobransky', + 'Dolbow', + 'Dyk', + 'Elfrink', + 'Figel', + 'Hauter', + 'Henkels', + 'Keillor', + 'Kollasch', + 'Krabill', + 'Kubly', + 'Kvasnicka', + 'Leise', + 'Martirosyan', + 'Mihalic', + 'Montecinos', + 'Myren', + 'Okerlund', + 'Ozer', + 'Rajput', + 'Reihl', + 'Rimando', + 'Saffle', + 'Schmelter', + 'Tellado', + 'Wachsmuth', + 'Wussow', + 'Zylka', + 'Caiola', + 'Certo', + 'Disabatino', + 'Ehrke', + 'Lahmann', + 'Lamartina', + 'Manheim', + 'Mckevitt', + 'Nardozzi', + 'Neuzil', + 'Novotney', + 'Oldfather', + 'Sietsema', + 'Stemmler', + 'Stumm', + 'Ueno', + 'Weckwerth', + 'Berrocal', + 'Nolde', + 'Alava', + 'Revier', + 'Sester', + 'Saller', + 'Tonga', + 'Kala', + 'Reveron', + 'Homesley', + 'Pagett', + 'Blackie', + 'Raimer', + 'Fitt', + 'Kimbley', + 'Amory', + 'Cabler', + 'Juett', + 'Crate', + 'Burres', + 'Siddle', + 'Barnfield', + 'Bordenave', + 'Cubit', + 'Elem', + 'Hardmon', + 'Augspurger', + 'Barriger', + 'Bau', + 'Bloomingdale', + 'Busta', + 'Canoy', + 'Carapia', + 'Cavenaugh', + 'Conkin', + 'Coppernoll', + 'Daloia', + 'Debruyne', + 'Egly', + 'Esmail', + 'Estorga', + 'Gladu', + 'Gladue', + 'Harvath', + 'Hirschmann', + 'Juel', + 'Kappus', + 'Kopriva', + 'Krul', + 'Lavorgna', + 'Maginn', + 'Malphrus', + 'Mcilhenny', + 'Perazzo', + 'Peredo', + 'Pineo', + 'Rigoni', + 'Robleto', + 'Schoene', + 'Sevillano', + 'Stears', + 'Stoltzfoos', + 'Sutley', + 'Terracciano', + 'Villacres', + 'Yoak', + 'Brensinger', + 'Brodzinski', + 'Cordial', + 'Cornacchia', + 'Corralejo', + 'Demarchi', + 'Dziuk', + 'Hirzel', + 'Keirns', + 'Kocourek', + 'Kupec', + 'Nazaryan', + 'Oftedahl', + 'Pignatelli', + 'Pundt', + 'Repinski', + 'Ryther', + 'Sampedro', + 'Shemanski', + 'Siess', + 'Trettel', + 'Urquilla', + 'Vantil', + 'Vicens', + 'Dunahoo', + 'Safer', + 'Romaniello', + 'Tallo', + 'Cavell', + 'Cobern', + 'Yarrow', + 'Serge', + 'Adel', + 'Allum', + 'Pruit', + 'Wali', + 'Forson', + 'Bells', + 'Blyden', + 'Andreotti', + 'Bagnato', + 'Beauchaine', + 'Biedrzycki', + 'Brabo', + 'Brodman', + 'Bruyere', + 'Canizares', + 'Chio', + 'Coudriet', + 'Dara', + 'Dhawan', + 'Diclemente', + 'Doro', + 'Elvir', + 'Fivecoat', + 'Frate', + 'Furuya', + 'Greis', + 'Halbleib', + 'Heuerman', + 'Hoener', + 'Holberg', + 'Hoogendoorn', + 'Inclan', + 'Jokinen', + 'Kretchmer', + 'Lafromboise', + 'Mccomsey', + 'Mckiddy', + 'Pelky', + 'Plaia', + 'Ponti', + 'Reichl', + 'Schicker', + 'Sotto', + 'Staehle', + 'Thau', + 'Turchin', + 'Zill', + 'Aicher', + 'Arrigoni', + 'Bertagnolli', + 'Binetti', + 'Dahlheimer', + 'Delashmit', + 'Disque', + 'Hemmerling', + 'Hovater', + 'Kachur', + 'Massmann', + 'Schlup', + 'Turkovich', + 'Underberg', + 'Wambolt', + 'Vassey', + 'Larney', + 'Brisky', + 'Minas', + 'Kata', + 'Magar', + 'Arlen', + 'Corporan', + 'Westland', + 'Detherage', + 'Reen', + 'Morale', + 'Hoes', + 'Baynham', + 'Norrington', + 'Lartigue', + 'Hakeem', + 'Kendrix', + 'Cazeau', + 'Amadi', + 'Mczeal', + 'Alwin', + 'Barcellos', + 'Bastedo', + 'Bintz', + 'Brackenbury', + 'Brockel', + 'Bucek', + 'Cecala', + 'Dapper', + 'Dettore', + 'Dowdall', + 'Dralle', + 'Essenmacher', + 'Evaristo', + 'Fecher', + 'Feldmeier', + 'Fetherston', + 'Futterman', + 'Garlinghouse', + 'Germani', + 'Gotz', + 'Hoen', + 'Janikowski', + 'Kiess', + 'Lagerstrom', + 'Lozinski', + 'Magnone', + 'Markow', + 'Mayall', + 'Mehdi', + 'Mineau', + 'Morgenroth', + 'Nitzsche', + 'Nordell', + 'Pavlock', + 'Peruzzi', + 'Pettine', + 'Pinos', + 'Polidoro', + 'Rahl', + 'Rudis', + 'Ryback', + 'Santellan', + 'Scharfenberg', + 'Schnake', + 'Schwake', + 'Seeling', + 'Senk', + 'Siron', + 'Speich', + 'Summerhays', + 'Torno', + 'Vangieson', + 'Wiacek', + 'Begnoche', + 'Carrejo', + 'Chervenak', + 'Edminster', + 'Halonen', + 'Macumber', + 'Mazeika', + 'Mikami', + 'Minetti', + 'Mosbrucker', + 'Mundis', + 'Onder', + 'Prowant', + 'Pyo', + 'Sedlack', + 'Stanbro', + 'Woehl', + 'Wrage', + 'Carpentieri', + 'Guedry', + 'Hodde', + 'Waggy', + 'Weitman', + 'Handal', + 'Gosman', + 'Mckeone', + 'Oliveria', + 'Soutar', + 'Glance', + 'Surprise', + 'Milius', + 'Crammer', + 'Mclear', + 'Borris', + 'Malon', + 'Mane', + 'Arrick', + 'Brazzel', + 'Matthewson', + 'Philemon', + 'Selvy', + 'Lites', + 'Deadwyler', + 'Marzette', + 'Alipio', + 'Arancibia', + 'Arrona', + 'Basista', + 'Blethen', + 'Brull', + 'Colaianni', + 'Dreese', + 'Giammona', + 'Giovanetti', + 'Grandmaison', + 'Grondahl', + 'Gulli', + 'Hellenbrand', + 'Iturbe', + 'Koesters', + 'Kondracki', + 'Konitzer', + 'Kubic', + 'Lauerman', + 'Mcfadin', + 'Musquiz', + 'Papalia', + 'Porrazzo', + 'Prien', + 'Reichley', + 'Treichler', + 'Ursua', + 'Vanblaricom', + 'Wich', + 'Windler', + 'Wos', + 'Zampino', + 'Alexopoulos', + 'Bambrick', + 'Beabout', + 'Brechtel', + 'Buroker', + 'Dahler', + 'Everding', + 'Furno', + 'Gikas', + 'Gilkeson', + 'Hubka', + 'Konwinski', + 'Krisko', + 'Kuligowski', + 'Maltbie', + 'Molstad', + 'Nonnemacher', + 'Nowotny', + 'Odisho', + 'Remsburg', + 'Rollyson', + 'Siegmann', + 'Slaubaugh', + 'Wasco', + 'Carlyon', + 'Chanin', + 'Cominsky', + 'Karber', + 'Aynes', + 'Swamy', + 'Kolden', + 'Rochel', + 'Julin', + 'Demarcus', + 'Malena', + 'Morice', + 'Burst', + 'Sukhu', + 'Mccravy', + 'Rinehardt', + 'Veazie', + 'Isaiah', + 'Bradby', + 'Poellnitz', + 'Agyemang', + 'Agate', + 'Aschoff', + 'Beenken', + 'Bogenschutz', + 'Casamento', + 'Correira', + 'Ebers', + 'Ellertson', + 'Forcum', + 'Gortney', + 'Jarriel', + 'Jasmer', + 'Kennebeck', + 'Kimpton', + 'Lad', + 'Lasek', + 'Licavoli', + 'Lipper', + 'Luedecke', + 'Maqueda', + 'Matsen', + 'Mest', + 'Neang', + 'Neault', + 'Newlun', + 'Oetken', + 'Rodick', + 'Rollinger', + 'Sabins', + 'Schalow', + 'Sheils', + 'Spilde', + 'Virzi', + 'Watz', + 'Wehrly', + 'Boscarino', + 'Chavolla', + 'Dasaro', + 'Eisenbach', + 'Ignatowski', + 'Kievit', + 'Kuzminski', + 'Lickliter', + 'Moravek', + 'Pawling', + 'Prause', + 'Redler', + 'Wunschel', + 'Suchanek', + 'Eyring', + 'Loge', + 'Tout', + 'Fross', + 'Swiss', + 'Deforrest', + 'Umphlett', + 'Herran', + 'Matton', + 'Passe', + 'Ode', + 'Della', + 'Caillier', + 'Baten', + 'Chesterfield', + 'Odneal', + 'Azeez', + 'Salami', + 'Ramson', + 'Mcvea', + 'Pittmon', + 'Cheatom', + 'Dorsainvil', + 'Cheeseboro', + 'Lavalais', + 'Allegro', + 'Bressi', + 'Brocklehurst', + 'Cassarino', + 'Dario', + 'Gazzola', + 'Glinka', + 'Goffredo', + 'Halabi', + 'Kroeze', + 'Lenig', + 'Marciel', + 'Marcussen', + 'Massoni', + 'Mayernik', + 'Nawrot', + 'Palazzi', + 'Pfefferkorn', + 'Placeres', + 'Polimeni', + 'Recendiz', + 'Sawdey', + 'Seidell', + 'Suchecki', + 'Titzer', + 'Virag', + 'Vitulli', + 'Wiltfong', + 'Wolden', + 'Woolworth', + 'Yandow', + 'Zeiter', + 'Zogg', + 'Brosh', + 'Dunsmoor', + 'Gucciardo', + 'Gumz', + 'Luginbill', + 'Mathwig', + 'Pannullo', + 'Raitt', + 'Reutzel', + 'Sonnen', + 'Bahri', + 'Guiffre', + 'Hons', + 'Platner', + 'Balaguer', + 'Lapre', + 'Rabbani', + 'Talent', + 'Hoster', + 'Thal', + 'Apo', + 'Duggin', + 'Kirley', + 'Burnard', + 'Lourie', + 'Wilham', + 'Craton', + 'Griff', + 'Falwell', + 'Upperman', + 'Laverne', + 'Wi', + 'Foucher', + 'Sudberry', + 'Oriol', + 'Cowens', + 'Marshell', + 'Chargois', + 'Bordley', + 'Artale', + 'Boeker', + 'Cookston', + 'Dattilio', + 'Dewinter', + 'Ditton', + 'Droessler', + 'Dusch', + 'Eltringham', + 'Feige', + 'Giel', + 'Grigas', + 'Hannagan', + 'Haubner', + 'Henzler', + 'Kippes', + 'Kneebone', + 'Lozeau', + 'Mallek', + 'Mandato', + 'Mangiapane', + 'Matusek', + 'Newgard', + 'Notte', + 'Purdin', + 'Ramaker', + 'Reddoch', + 'Rensing', + 'Rohrman', + 'Romm', + 'Rudiger', + 'Torti', + 'Travaglini', + 'Uno', + 'Wojciak', + 'Yannuzzi', + 'Zeien', + 'Arpino', + 'Borgstrom', + 'Burkemper', + 'Cristino', + 'Detjen', + 'Gienger', + 'Glockner', + 'Grillot', + 'Jentz', + 'Kendzierski', + 'Klebe', + 'Knippenberg', + 'Kusler', + 'Olofson', + 'Orlov', + 'Rindt', + 'Stallbaumer', + 'Troost', + 'Turri', + 'Uzelac', + 'Weichert', + 'Sweazy', + 'Alcivar', + 'Canner', + 'Lottman', + 'Salame', + 'Berkes', + 'Pickren', + 'Ganson', + 'Odonell', + 'Geron', + 'Kasa', + 'Banbury', + 'Tinnel', + 'Umble', + 'Flow', + 'Kirt', + 'Rhule', + 'Diles', + 'Seeney', + 'Givans', + 'Mckethan', + 'Crusoe', + 'Darko', + 'Mucker', + 'Kizzee', + 'Daniely', + 'Nutall', + 'Angove', + 'Appelhans', + 'Balder', + 'Blatchley', + 'Botkins', + 'Brisk', + 'Burandt', + 'Clowdus', + 'Debauche', + 'Deily', + 'Group', + 'Hoecker', + 'Holsonback', + 'Humpert', + 'Jacquin', + 'Jurica', + 'Karnik', + 'Krontz', + 'Lapiana', + 'Lenzo', + 'Luscombe', + 'Madey', + 'Mirabito', + 'Neifert', + 'Pennino', + 'Piechota', + 'Pizzimenti', + 'Reeg', + 'Roarty', + 'Routzahn', + 'Salsedo', + 'Schuff', + 'Silveri', + 'Steckman', + 'Supak', + 'Swackhamer', + 'Trusler', + 'Vizzini', + 'Wences', + 'Whelton', + 'Zachar', + 'Albertsen', + 'Bischel', + 'Brigandi', + 'Campoy', + 'Castagnola', + 'Doenges', + 'Flessner', + 'Garbers', + 'Jezewski', + 'Kozlov', + 'Niedbalski', + 'Schillo', + 'Schoepke', + 'Schranz', + 'Trulson', + 'Vanwyhe', + 'Versluis', + 'Zavadil', + 'Brau', + 'Rudell', + 'Golen', + 'Meter', + 'Sherrin', + 'Tolly', + 'Mandala', + 'Calcano', + 'Lewing', + 'Sedeno', + 'Ramalho', + 'Haggar', + 'Borns', + 'Matherson', + 'Cobin', + 'Turnley', + 'Pone', + 'Tuner', + 'Crandle', + 'Sturkey', + 'Heggins', + 'Tisby', + 'Allbaugh', + 'Baars', + 'Bethard', + 'Brenizer', + 'Bussman', + 'Casebier', + 'Castanos', + 'Climaco', + 'Dux', + 'Farrens', + 'Frediani', + 'Gaccione', + 'Garciaperez', + 'Hoppa', + 'Juckett', + 'Klinkner', + 'Kooy', + 'Krinke', + 'Locy', + 'Lovecchio', + 'Lukin', + 'Machia', + 'Mand', + 'Maslin', + 'Mehrotra', + 'Nicolet', + 'Peyser', + 'Reckart', + 'Roanhorse', + 'Rokicki', + 'Sargis', + 'Sciullo', + 'Shevchuk', + 'Sindoni', + 'Slankard', + 'Sobiech', + 'Stoneberger', + 'Stys', + 'Tuzzolino', + 'Waligora', + 'Wiland', + 'Clabough', + 'Drawbaugh', + 'Figurski', + 'Gibeault', + 'Gojcaj', + 'Hartfiel', + 'Inbody', + 'Konarski', + 'Kruszka', + 'Letarte', + 'Lillich', + 'Mccandlish', + 'Mollenkopf', + 'Oltmann', + 'Pfenninger', + 'Ruediger', + 'Schaben', + 'Shauger', + 'Wilczak', + 'Wolanin', + 'Ziehm', + 'Bassinger', + 'Brannick', + 'Schlereth', + 'Capri', + 'Roscher', + 'Pasqual', + 'Lallo', + 'Sweney', + 'Rozario', + 'Hamblet', + 'Muckleroy', + 'Frankson', + 'Moure', + 'Shrieves', + 'Bosket', + 'Strowbridge', + 'Hawkin', + 'Cooperwood', + 'Agena', + 'Barrowman', + 'Belko', + 'Blasdell', + 'Brobeck', + 'Chieffo', + 'Cooperrider', + 'Dickard', + 'Erion', + 'Fradkin', + 'Hattery', + 'Hefferon', + 'Hofstra', + 'Hoiland', + 'Jirak', + 'Klugman', + 'Klundt', + 'Knope', + 'Lawniczak', + 'Luckenbach', + 'Manzione', + 'Mccombie', + 'Minden', + 'Mousel', + 'Ridling', + 'Rightmire', + 'Ritzel', + 'Santori', + 'Semmens', + 'Snyders', + 'Spargur', + 'Staszewski', + 'Swiech', + 'Tasso', + 'Veldhuizen', + 'Vuolo', + 'Wojnarowski', + 'Yoe', + 'Bachler', + 'Cimo', + 'Hippen', + 'Klimaszewski', + 'Kohlhepp', + 'Kovacich', + 'Kretsch', + 'Lacoursiere', + 'Lopezmartinez', + 'Marsiglia', + 'Metzker', + 'Murchie', + 'Paradee', + 'Pfefferle', + 'Rothert', + 'Skellenger', + 'Tourangeau', + 'Beumer', + 'Thunder', + 'Uden', + 'Broe', + 'Moxon', + 'Kassin', + 'Murton', + 'Hockley', + 'Vinet', + 'Suthers', + 'Bayman', + 'Cokeley', + 'Ailey', + 'Crossfield', + 'Desha', + 'Dowson', + 'Acheampong', + 'Boomsma', + 'Buer', + 'Caratachea', + 'Dascenzo', + 'Debes', + 'Degroote', + 'Dillie', + 'Dorsi', + 'Dorward', + 'Eyestone', + 'Geister', + 'Gonia', + 'Heiler', + 'Hin', + 'Hoheisel', + 'Horger', + 'Hulce', + 'Kainer', + 'Kerkman', + 'Kloehn', + 'Krempasky', + 'Kuehnel', + 'Leetch', + 'Lio', + 'Lohrey', + 'Lucchetti', + 'Machnik', + 'Majeske', + 'Martire', + 'Mores', + 'Oyen', + 'Pappert', + 'Platas', + 'Podany', + 'Prata', + 'Radoncic', + 'Sainato', + 'Salada', + 'Serota', + 'Tatsch', + 'Torbeck', + 'Vilhauer', + 'Waltner', + 'Wauters', + 'Welge', + 'Yoss', + 'Bigwood', + 'Brunsman', + 'Civitello', + 'Compston', + 'Cuccaro', + 'Denholm', + 'Emmick', + 'Gadzinski', + 'Goedken', + 'Graumann', + 'Hackert', + 'Hardacre', + 'Hehl', + 'Magliocco', + 'Marotto', + 'Ozanich', + 'Pidcock', + 'Schlangen', + 'Scoma', + 'Sobecki', + 'Spreng', + 'Thalmann', + 'Wolfrum', + 'Groninger', + 'Howatt', + 'Kindy', + 'Swor', + 'Ledden', + 'Voyer', + 'Colli', + 'Andrae', + 'Duchemin', + 'Boker', + 'Malter', + 'Snooks', + 'Morss', + 'Haylett', + 'Mitter', + 'Fairey', + 'Kenerson', + 'Albea', + 'Ellerson', + 'Alcindor', + 'Gadison', + 'Arabia', + 'Bundren', + 'Calica', + 'Cartaya', + 'Cielo', + 'Ebbers', + 'Entler', + 'Friedly', + 'Granja', + 'Landt', + 'Lorensen', + 'Michelini', + 'Oliveto', + 'Piela', + 'Reust', + 'Roussos', + 'Sanluis', + 'Seier', + 'Sobolik', + 'Stader', + 'Stetzer', + 'Tetley', + 'Zirbes', + 'Bridenbaugh', + 'Chinnici', + 'Crabbs', + 'Evilsizer', + 'Favaloro', + 'Haeberle', + 'Hopfensperger', + 'Kijowski', + 'Kingbird', + 'Leikam', + 'Montavon', + 'Petrossian', + 'Quizhpi', + 'Spoelstra', + 'Testani', + 'Plaut', + 'Windt', + 'Dubie', + 'Kozinski', + 'Sorell', + 'Nish', + 'Katon', + 'Soy', + 'Pelcher', + 'Sayres', + 'Waitman', + 'Relph', + 'Hearld', + 'Farewell', + 'Giordani', + 'Canida', + 'Martian', + 'Suliman', + 'Mckesson', + 'Randon', + 'Eastmond', + 'Willaims', + 'Collington', + 'Hardge', + 'Asevedo', + 'Beauchene', + 'Bebeau', + 'Bobick', + 'Bogacki', + 'Bolich', + 'Bonadonna', + 'Butsch', + 'Coltrin', + 'Corbello', + 'Dastrup', + 'Dunshee', + 'Firpo', + 'Foister', + 'Franssen', + 'Fredriksen', + 'Gfeller', + 'Glassner', + 'Johanns', + 'Korson', + 'Langsam', + 'Linstrom', + 'Longstaff', + 'Lukic', + 'Maler', + 'Marteney', + 'Milardo', + 'Rhatigan', + 'Ruetz', + 'Semel', + 'Senske', + 'Shatswell', + 'Simmering', + 'Tasch', + 'Vanskike', + 'Verano', + 'Viscardi', + 'Weidmann', + 'Doubet', + 'Farraj', + 'Fritter', + 'Griesinger', + 'Horkey', + 'Hornik', + 'Izatt', + 'Klayman', + 'Mantei', + 'Notz', + 'Oberholzer', + 'Petko', + 'Rueth', + 'Rygiel', + 'Tumolo', + 'Unterreiner', + 'Urgo', + 'Weisbecker', + 'Weniger', + 'Zarro', + 'Zunino', + 'Goldmann', + 'Verderber', + 'Glennie', + 'Shere', + 'Lamos', + 'Face', + 'Sparger', + 'Donnay', + 'Kage', + 'Leason', + 'Mcgue', + 'Brickle', + 'Mae', + 'Thomaston', + 'Dunnell', + 'Tillie', + 'Miggins', + 'Geffrard', + 'Aubel', + 'Backe', + 'Beaumier', + 'Bloor', + 'Brackbill', + 'Brandvold', + 'Bylund', + 'Carbary', + 'Catrambone', + 'Dapolito', + 'Dillenburg', + 'Elliff', + 'Fehnel', + 'Ferriss', + 'Gellner', + 'Graw', + 'Guilbeault', + 'Hautala', + 'Hollenberg', + 'Imparato', + 'Kaner', + 'Kley', + 'Lanzer', + 'Laterza', + 'Legner', + 'Lombardozzi', + 'Mcerlean', + 'Mcgilton', + 'Mohring', + 'Neeper', + 'Pollinger', + 'Pullara', + 'Sagona', + 'Scripter', + 'Skillen', + 'Streeper', + 'Tritch', + 'Vayda', + 'Verbeek', + 'Wenberg', + 'Youngers', + 'Bayus', + 'Cobaugh', + 'Dolak', + 'Forys', + 'Genther', + 'Jankovich', + 'Kneale', + 'Komp', + 'Kreher', + 'Kuwahara', + 'Mclouth', + 'Melland', + 'Molesky', + 'Neustadt', + 'Oesterling', + 'Quirke', + 'Roeper', + 'Stantz', + 'Vandenboom', + 'Venhuizen', + 'Westermeyer', + 'Embury', + 'Cozort', + 'Crispo', + 'Woollard', + 'Thiery', + 'Lecy', + 'Terris', + 'Stencil', + 'Yero', + 'Bollard', + 'Chander', + 'Shepp', + 'Younkins', + 'Jon', + 'Anselm', + 'Deveraux', + 'Better', + 'Birth', + 'Hoskie', + 'Kirtz', + 'Encalade', + 'Aprea', + 'Bernick', + 'Bialy', + 'Bolenbaugh', + 'Chinea', + 'Cwiklinski', + 'Dunavan', + 'Dunckel', + 'Essen', + 'Ferner', + 'Gallick', + 'Gruba', + 'Hauss', + 'Intriago', + 'Javaid', + 'Kaney', + 'Klemens', + 'Kuriakose', + 'Leyda', + 'Losurdo', + 'Mcelhone', + 'Methot', + 'Morioka', + 'Mundorf', + 'Nocito', + 'Nordmann', + 'Oommen', + 'Pfahl', + 'Piquette', + 'Prinsen', + 'Sacramento', + 'Shenker', + 'Skidgel', + 'Sobalvarro', + 'Soldo', + 'Synan', + 'Tostenson', + 'Trotti', + 'Vienneau', + 'Vigneau', + 'Waitkus', + 'Wiess', + 'Bartmess', + 'Comparan', + 'Dalonzo', + 'Dutrow', + 'Fleegle', + 'Fronek', + 'Handrich', + 'Hazelip', + 'Heinig', + 'Macapagal', + 'Masciarelli', + 'Pitstick', + 'Radakovich', + 'Ripberger', + 'Schwebel', + 'Slomski', + 'Stinchfield', + 'Zegers', + 'Zeiser', + 'Kimmer', + 'Rippon', + 'Satz', + 'Bosques', + 'Mcnickle', + 'Yarwood', + 'Babar', + 'Ghazi', + 'Mcquary', + 'Africa', + 'Sofer', + 'Marsland', + 'Curby', + 'Odor', + 'Gillem', + 'Selmer', + 'Delmas', + 'Lamison', + 'Lanes', + 'Shadd', + 'Goard', + 'Haylock', + 'Sermon', + 'Meachem', + 'Vernet', + 'Akiona', + 'Avitabile', + 'Berkson', + 'Bisono', + 'Busic', + 'Caroselli', + 'Corradi', + 'Delval', + 'Egley', + 'Elkind', + 'Everling', + 'Ferrario', + 'Frumkin', + 'Gelder', + 'Gironda', + 'Glasheen', + 'Goette', + 'Gotts', + 'Haub', + 'Herro', + 'Hudzik', + 'Hula', + 'Inboden', + 'Isensee', + 'Kiesewetter', + 'Koetje', + 'Laughridge', + 'Lovewell', + 'Meeuwsen', + 'Mokry', + 'Navarez', + 'Plake', + 'Quain', + 'Reppucci', + 'Sorn', + 'Tallerico', + 'Uselman', + 'Verrastro', + 'Wineberg', + 'Blazina', + 'Falardeau', + 'Garavito', + 'Gellerman', + 'Havins', + 'Kurdziel', + 'Liedel', + 'Lofstrom', + 'Pakula', + 'Presby', + 'Ringstad', + 'Rokosz', + 'Schuchart', + 'Seckler', + 'Verderame', + 'Veselka', + 'Asfour', + 'Delanoy', + 'Fromer', + 'Koba', + 'Kostrzewa', + 'Melle', + 'Merkey', + 'Scalese', + 'Oritz', + 'Kilgour', + 'Piker', + 'Janet', + 'Huge', + 'Hails', + 'Dobey', + 'Escoe', + 'Rasool', + 'Gilcrest', + 'Codrington', + 'Jeangilles', + 'Outley', + 'Bambach', + 'Beaulac', + 'Begue', + 'Bobeck', + 'Buccino', + 'Carrigg', + 'Cranney', + 'Denninger', + 'Dicioccio', + 'Eapen', + 'Fargnoli', + 'Fatica', + 'Fernicola', + 'Forse', + 'Freck', + 'Gardipee', + 'Gibas', + 'Goeman', + 'Guadian', + 'Hlad', + 'Jakab', + 'Kishimoto', + 'Krenn', + 'Lagesse', + 'Lhommedieu', + 'Lusch', + 'Mausolf', + 'Mazzocchi', + 'Mcdavitt', + 'Noseworthy', + 'Passante', + 'Placzek', + 'Quamme', + 'Ringgenberg', + 'Spiegelman', + 'Vinluan', + 'Wachsman', + 'Bacigalupi', + 'Baechle', + 'Baetz', + 'Barsch', + 'Colbaugh', + 'Devoto', + 'Dimercurio', + 'Dosanjh', + 'Dukeman', + 'Ferger', + 'Garinger', + 'Grelle', + 'Guyett', + 'Harpenau', + 'Hundal', + 'Kamerer', + 'Klomp', + 'Licklider', + 'Martinec', + 'Matzek', + 'Nixdorf', + 'Pankonin', + 'Pogosyan', + 'Schweickert', + 'Smethurst', + 'Stroope', + 'Zwack', + 'Tebbetts', + 'Stains', + 'Tosado', + 'Carles', + 'Rings', + 'Hebard', + 'Choplin', + 'Townshend', + 'Doorn', + 'Aja', + 'Picking', + 'Oneall', + 'Logie', + 'Aro', + 'Dua', + 'Heney', + 'Manard', + 'Atchinson', + 'Breech', + 'Brashers', + 'Addams', + 'Nooner', + 'Barsh', + 'Orum', + 'Dancey', + 'Bamba', + 'Kareem', + 'Theard', + 'Marseille', + 'Molette', + 'Getachew', + 'Saintfleur', + 'Frimpong', + 'Anglada', + 'Attardo', + 'Barreira', + 'Bleicher', + 'Bonecutter', + 'Bricco', + 'Compian', + 'Creppel', + 'Cuadras', + 'Cuccio', + 'Cutsforth', + 'Dinino', + 'Eskelson', + 'Freemyer', + 'Friedhoff', + 'Grandt', + 'Holzmann', + 'Hoverson', + 'Hurteau', + 'Iacona', + 'Jergens', + 'Kingham', + 'Leiterman', + 'Leugers', + 'Leyh', + 'Lotti', + 'Majkowski', + 'Mossberg', + 'Nuffer', + 'Oaxaca', + 'Pagenkopf', + 'Paille', + 'Petzoldt', + 'Rogalla', + 'Siddens', + 'Siddoway', + 'Spatafora', + 'Tufo', + 'Weismann', + 'Werntz', + 'Wilz', + 'Ammirati', + 'Benninghoff', + 'Escarsega', + 'Fessel', + 'Hurless', + 'Jastrzebski', + 'Klingerman', + 'Kurilla', + 'Kuzmin', + 'Meserole', + 'Politz', + 'Pollino', + 'Rettke', + 'Sinay', + 'Strebeck', + 'Strycharz', + 'Suhre', + 'Thumm', + 'Trybus', + 'Uhrin', + 'Weisberger', + 'Zeger', + 'Carringer', + 'Sitts', + 'Lungren', + 'Iiams', + 'Sudbury', + 'Surrette', + 'Chellis', + 'Yore', + 'Joice', + 'Foot', + 'Ausley', + 'Scioneaux', + 'Mcaffee', + 'Pinn', + 'Maina', + 'Dorce', + 'Agrusa', + 'Albornoz', + 'Arave', + 'Bacallao', + 'Bendavid', + 'Bochner', + 'Bortle', + 'Carragher', + 'Chalfin', + 'Courtade', + 'Dagle', + 'Debuhr', + 'Fowble', + 'Galinsky', + 'Hardigree', + 'Haulk', + 'Hendron', + 'Herringshaw', + 'Jayaraman', + 'Koestler', + 'Konicek', + 'Kutscher', + 'Lachowicz', + 'Lafauci', + 'Lansky', + 'Lazarski', + 'Lolli', + 'Ludvigsen', + 'Manternach', + 'Martorelli', + 'Mcquillin', + 'Mikaelian', + 'Northcraft', + 'Nyborg', + 'Palone', + 'Peckman', + 'Schwebach', + 'Simbeck', + 'Sittler', + 'Udovich', + 'Viesca', + 'Yazell', + 'Zimmers', + 'Bielen', + 'Cohron', + 'Dearcos', + 'Feezor', + 'Hilgart', + 'Karriker', + 'Klingberg', + 'Leisenring', + 'Napora', + 'Nedved', + 'Okeson', + 'Seratt', + 'Trautner', + 'Trimarco', + 'Turkel', + 'Bronder', + 'Itani', + 'Verona', + 'Blackbird', + 'Laque', + 'Karpel', + 'Louro', + 'Hamson', + 'Ashland', + 'Gruel', + 'Breer', + 'Wesely', + 'Bebo', + 'Conery', + 'Mccarry', + 'Cradic', + 'Aytes', + 'Dikes', + 'Soltau', + 'Debois', + 'Berko', + 'Callins', + 'Anastacio', + 'Balbi', + 'Bata', + 'Bechel', + 'Borsuk', + 'Chihuahua', + 'Cindric', + 'Denapoli', + 'Dotzler', + 'Dusing', + 'Dziekan', + 'Eifler', + 'Franchino', + 'Garritano', + 'Herrarte', + 'Jaskot', + 'Kettell', + 'Kingsford', + 'Marsters', + 'Oshel', + 'Overacker', + 'Pagliarulo', + 'Pannier', + 'Pyun', + 'Rardon', + 'Reville', + 'Rogozinski', + 'Scatena', + 'Schoeppner', + 'Senkbeil', + 'Silkey', + 'Takhar', + 'Whitebread', + 'Wiech', + 'Adelsberger', + 'Aslinger', + 'Bhattacharyya', + 'Brege', + 'Burright', + 'Cafarella', + 'Chlebowski', + 'Decaprio', + 'Dilello', + 'Dresher', + 'Finkbiner', + 'Gerlich', + 'Ignasiak', + 'Kataoka', + 'Kearl', + 'Pingitore', + 'Sellick', + 'Sinning', + 'Stojanovic', + 'Vanasten', + 'Vanluven', + 'Westerfeld', + 'Mahala', + 'Biancardi', + 'Velardo', + 'Payes', + 'Debello', + 'Kyes', + 'Reever', + 'Joung', + 'Coran', + 'Perrow', + 'Linzer', + 'Birchett', + 'Poles', + 'Cajuste', + 'Albergo', + 'Andal', + 'Belaire', + 'Borell', + 'Bruehl', + 'Celani', + 'Cerruti', + 'Crellin', + 'Delcarlo', + 'Dubach', + 'Elicker', + 'Fialkowski', + 'Ganim', + 'Gladieux', + 'Glendening', + 'Glomski', + 'Kalp', + 'Kavan', + 'Kawabata', + 'Kever', + 'Kisch', + 'Maiorino', + 'Masaki', + 'Mcgeough', + 'Miyoshi', + 'Nand', + 'Nitka', + 'Novakovich', + 'Penagos', + 'Pierini', + 'Rassi', + 'Rorke', + 'Rosenboom', + 'Rossmann', + 'Scarfone', + 'Scarsella', + 'Siedschlag', + 'Sobotta', + 'Studnicka', + 'Teeling', + 'Tegtmeyer', + 'Woznick', + 'Beske', + 'Dersch', + 'Deschepper', + 'Duffner', + 'Geroux', + 'Lindvall', + 'Linnemann', + 'Roethler', + 'Scanlin', + 'Schaecher', + 'Schmude', + 'Schwertner', + 'Shimamoto', + 'Stratmann', + 'Stufflebean', + 'Ulatowski', + 'Witkop', + 'Landrus', + 'Sahin', + 'Araque', + 'Massett', + 'Meanor', + 'Sebo', + 'Delic', + 'Bryand', + 'Frederico', + 'Portuondo', + 'Verry', + 'Browe', + 'Winecoff', + 'Gipp', + 'Khamis', + 'Ingrum', + 'Gilliand', + 'Poinsett', + 'Hagley', + 'Valliant', + 'Henly', + 'Bingley', + 'Romulus', + 'Moyd', + 'Abascal', + 'Adelstein', + 'Arabian', + 'Barcelos', + 'Barot', + 'Cabacungan', + 'Darco', + 'Dickmeyer', + 'Gindi', + 'Grone', + 'Haberland', + 'Hachem', + 'Humbarger', + 'Insco', + 'Kravchuk', + 'Mackowski', + 'Madrazo', + 'Malesky', + 'Markowicz', + 'Mcconnon', + 'Meiring', + 'Micalizzi', + 'Moeser', + 'Mortier', + 'Muegge', + 'Ollar', + 'Pamperin', + 'Pusch', + 'Remache', + 'Roginski', + 'Rothbauer', + 'Sellin', + 'Stachurski', + 'Stelmack', + 'Suprenant', + 'Totzke', + 'Uemura', + 'Vandercook', + 'Yott', + 'Zaher', + 'Autio', + 'Barnhard', + 'Brys', + 'Chisenhall', + 'Deiters', + 'Fetsko', + 'Finzel', + 'Gangwer', + 'Grygiel', + 'Heidelberger', + 'Kommer', + 'Latchford', + 'Liszka', + 'Mcconaha', + 'Miazga', + 'Nettesheim', + 'Oelschlager', + 'Rafuse', + 'Reichow', + 'Santosuosso', + 'Sebastiani', + 'Serratore', + 'Spenner', + 'Steffenson', + 'Strehl', + 'Tropeano', + 'Vanstraten', + 'Vegh', + 'Virrueta', + 'Wilhide', + 'Prey', + 'Ullmer', + 'Ferraz', + 'Mazor', + 'Vinje', + 'Mory', + 'Rody', + 'Dowen', + 'Bord', + 'Rajkumar', + 'Qadir', + 'Turbin', + 'Rorex', + 'Wilmott', + 'Grandpre', + 'Bucker', + 'Reasonover', + 'Holoman', + 'Mustapha', + 'Warsame', + 'Laday', + 'Whack', + 'Blahut', + 'Boxell', + 'Britnell', + 'Buehl', + 'Burri', + 'Cesaro', + 'Degrand', + 'Demetro', + 'Fadeley', + 'Fischel', + 'Florer', + 'Givler', + 'Gockley', + 'Iuliano', + 'Koral', + 'Kotlarz', + 'Kraai', + 'Kvamme', + 'Latchaw', + 'Lopeman', + 'Manocchio', + 'Martinezgarcia', + 'Minehart', + 'Narasimhan', + 'Nier', + 'Niziolek', + 'Oliff', + 'Piascik', + 'Pitera', + 'Pronovost', + 'Roseboom', + 'Rosevear', + 'Runkles', + 'Santmyer', + 'Skillin', + 'Stamas', + 'Storbeck', + 'Teicher', + 'Titterington', + 'Tomkinson', + 'Tzeng', + 'Vukovic', + 'Wescoat', + 'Algeo', + 'Aronow', + 'Balbach', + 'Brockbank', + 'Caloca', + 'Caughlin', + 'Devincenzi', + 'Doetsch', + 'Filby', + 'Godar', + 'Keeven', + 'Marchetta', + 'Quiram', + 'Rudeen', + 'Siemen', + 'Suderman', + 'Tacke', + 'Walby', + 'Fram', + 'Maccarthy', + 'Fana', + 'Kimberley', + 'Richens', + 'Doser', + 'Bigford', + 'Brazie', + 'Haroon', + 'Mcginniss', + 'Knipfer', + 'Seltz', + 'Laton', + 'Balow', + 'Cramp', + 'Edger', + 'Alonge', + 'Beagles', + 'Ken', + 'Peary', + 'Lifsey', + 'Acy', + 'Lightbourne', + 'Antwi', + 'Arntzen', + 'Bracknell', + 'Brewbaker', + 'Carville', + 'Cinquemani', + 'Corales', + 'Corgan', + 'Craze', + 'Dechristopher', + 'Eltzroth', + 'Fjelstad', + 'Forinash', + 'Gudenkauf', + 'Hapeman', + 'Hassing', + 'Hurm', + 'Jaurigue', + 'Kneisel', + 'Kulwicki', + 'Lookingbill', + 'Moist', + 'Naderi', + 'Nicoli', + 'Nicoson', + 'Olvey', + 'Remaly', + 'Stare', + 'Steinruck', + 'Switala', + 'Tada', + 'Toves', + 'Traber', + 'Tuohey', + 'Venti', + 'Vinal', + 'Wahle', + 'Yarosh', + 'Balinski', + 'Bauknecht', + 'Bernauer', + 'Bink', + 'Chudzik', + 'Coppess', + 'Corrick', + 'Gruener', + 'Kutter', + 'Malkiewicz', + 'Marking', + 'Mcgrain', + 'Melberg', + 'Ohmann', + 'Pellicane', + 'Regehr', + 'Schmoldt', + 'Schmuhl', + 'Starmer', + 'Stiens', + 'Whilden', + 'Yearick', + 'Desmith', + 'Habiger', + 'Papay', + 'Study', + 'Toot', + 'Franzoni', + 'Neuhoff', + 'Boreman', + 'Sayas', + 'Hinks', + 'Dax', + 'Sasnett', + 'Hannis', + 'Rotan', + 'Haze', + 'Jennifer', + 'Barganier', + 'Milson', + 'Kinnie', + 'Boyde', + 'Dyce', + 'Cuttino', + 'Neals', + 'Mccovery', + 'Abaya', + 'Balz', + 'Bezold', + 'Breighner', + 'Buttacavoli', + 'Cattani', + 'Detzel', + 'Douthat', + 'Dunay', + 'Eicholtz', + 'Eirich', + 'Felkner', + 'Friedenberg', + 'Haskew', + 'Henes', + 'Jamroz', + 'Kelter', + 'Kutzer', + 'Laughner', + 'Livoti', + 'Magistro', + 'Makinson', + 'Manwell', + 'Mckimmy', + 'Mcwethy', + 'Pacholski', + 'Pankau', + 'Poh', + 'Purewal', + 'Remedios', + 'Ringuette', + 'Rocchi', + 'Rojero', + 'Sabina', + 'Schiffner', + 'Sellen', + 'Setaro', + 'Soledad', + 'Stoermer', + 'Tal', + 'Vanwyk', + 'Waack', + 'Xenos', + 'Yoakam', + 'Zweber', + 'Apachito', + 'Belluomini', + 'Cancelliere', + 'Cervini', + 'Davidovich', + 'Deguia', + 'Doxtator', + 'Errera', + 'Eshbaugh', + 'Mandt', + 'Pautler', + 'Raczynski', + 'Roemmich', + 'Rosamilia', + 'Shelhamer', + 'Vandevoorde', + 'Vanengen', + 'Vindiola', + 'Weyman', + 'Dufur', + 'Reaver', + 'Bugh', + 'Starley', + 'Macmullen', + 'Mataya', + 'Bucknell', + 'Taitano', + 'Coole', + 'Huguet', + 'Top', + 'Rockford', + 'Carrithers', + 'Garrell', + 'Toppins', + 'Mayner', + 'Dantes', + 'Tones', + 'Dauphine', + 'Shillingford', + 'Massiah', + 'Angermeier', + 'Arrizon', + 'Azer', + 'Badami', + 'Beeck', + 'Buddenhagen', + 'Cheyney', + 'Danielski', + 'Delgiorno', + 'Enslin', + 'Erber', + 'Fluegge', + 'Fresco', + 'Frishman', + 'Geigle', + 'Gervase', + 'Giangregorio', + 'Glauber', + 'Hedding', + 'Janota', + 'Labore', + 'Ladley', + 'Levee', + 'Lipuma', + 'Lomanto', + 'Magos', + 'Mangen', + 'Miltner', + 'Mitschke', + 'Pingley', + 'Puertas', + 'Schwed', + 'Seminario', + 'Sinsel', + 'Sliney', + 'Spielmann', + 'Standage', + 'Waas', + 'Cooprider', + 'Delguercio', + 'Dockham', + 'Dohse', + 'Doubrava', + 'Emerine', + 'Frazzini', + 'Godown', + 'Heidbreder', + 'Ladow', + 'Lariccia', + 'Molzahn', + 'Opiela', + 'Ordorica', + 'Otterness', + 'Owczarzak', + 'Rafalski', + 'Smigel', + 'Urbas', + 'Andon', + 'Kota', + 'Ruzzo', + 'Pheasant', + 'Proch', + 'Sullinger', + 'Ezra', + 'Portes', + 'Mynhier', + 'Depree', + 'Slight', + 'Selley', + 'Daughety', + 'Shamel', + 'Glasby', + 'Casher', + 'Brisby', + 'Whittley', + 'Brye', + 'Mackins', + 'Allam', + 'Berwanger', + 'Borgmeyer', + 'Brumlow', + 'Cashmore', + 'Clementz', + 'Coopman', + 'Corti', + 'Danzer', + 'Deater', + 'Delprado', + 'Dibuono', + 'Dwan', + 'Edling', + 'Ekins', + 'Feighner', + 'Galica', + 'Gasparro', + 'Geisert', + 'Gilvin', + 'Glotzbach', + 'Goostree', + 'Hollenkamp', + 'Hronek', + 'Kamins', + 'Khun', + 'Klimowicz', + 'Langella', + 'Letz', + 'Lindh', + 'Lycan', + 'Magouirk', + 'Mcbryar', + 'Milonas', + 'Patalano', + 'Petrides', + 'Plocher', + 'Signer', + 'Sinagra', + 'Taibi', + 'Thissen', + 'Thueson', + 'Tietje', + 'Trebilcock', + 'Zelek', + 'Alavez', + 'Beyersdorf', + 'Ferraiolo', + 'Flodin', + 'Fulwiler', + 'Gieselman', + 'Heisinger', + 'Hutmacher', + 'Laraia', + 'Lempke', + 'Marchiano', + 'Mendia', + 'Milberger', + 'Murri', + 'Willhelm', + 'Yannone', + 'Diss', + 'Golab', + 'Meuth', + 'Strebe', + 'Berenguer', + 'Cunard', + 'Girvan', + 'Pacer', + 'Nate', + 'Weare', + 'Dile', + 'Donate', + 'Pamer', + 'Charlet', + 'Roades', + 'Krah', + 'Merton', + 'Debrito', + 'Montel', + 'Guimont', + 'Caire', + 'Olley', + 'Ausborn', + 'Ramdass', + 'Stores', + 'Hush', + 'Watler', + 'Robotham', + 'Stanislaus', + 'Bellevue', + 'Almeter', + 'Bartold', + 'Bathgate', + 'Bollier', + 'Boundy', + 'Bushart', + 'Buzek', + 'Cauthon', + 'Daudelin', + 'Delguidice', + 'Depaolis', + 'Dysert', + 'Forsee', + 'Goglia', + 'Gruenhagen', + 'Guilfoil', + 'Guldin', + 'Gurnee', + 'Henzel', + 'Jurney', + 'Kable', + 'Korenek', + 'Kussman', + 'Liese', + 'Mauss', + 'Mexicano', + 'Morini', + 'Oathout', + 'Paragas', + 'Phommachanh', + 'Pixton', + 'Pucciarelli', + 'Rabine', + 'Ramlow', + 'Ravert', + 'Redhouse', + 'Renault', + 'Rybinski', + 'Sahlin', + 'Scherger', + 'Schoeffler', + 'Smolinsky', + 'Stadnik', + 'Stallsmith', + 'Timoney', + 'Whiteeagle', + 'Woodsmall', + 'Zinter', + 'Bargmann', + 'Basich', + 'Bossio', + 'Coutant', + 'Curcuru', + 'Duitsman', + 'Hunkele', + 'Kingry', + 'Kotek', + 'Mancusi', + 'Orama', + 'Paszek', + 'Schrodt', + 'Schuknecht', + 'Torsiello', + 'Troise', + 'Wernimont', + 'Wipperfurth', + 'Wissner', + 'Zahradnik', + 'Deasis', + 'Pac', + 'Vowles', + 'Montesi', + 'Carie', + 'Name', + 'Broy', + 'Hillson', + 'Exton', + 'Skerritt', + 'Ude', + 'Allston', + 'Cliatt', + 'Chevis', + 'Poitier', + 'Barrasso', + 'Bartnicki', + 'Broski', + 'Cobleigh', + 'Crickenberger', + 'Cruces', + 'Cumba', + 'Diodato', + 'Dipietrantonio', + 'Eyerly', + 'Fedler', + 'Fetting', + 'Francavilla', + 'Frein', + 'Gasparyan', + 'Gingold', + 'Gunnarson', + 'Houy', + 'Huelsmann', + 'Jeppsen', + 'Labreck', + 'Lefton', + 'Maenza', + 'Mauritz', + 'Mingione', + 'Mullany', + 'Mussell', + 'Muston', + 'Paraiso', + 'Peelman', + 'Penuel', + 'Piccola', + 'Punt', + 'Ramella', + 'Rauser', + 'Reas', + 'Reino', + 'Schlack', + 'Sebastiano', + 'Sgambati', + 'Shackett', + 'Szpak', + 'Thalacker', + 'Theissen', + 'Tutko', + 'Astarita', + 'Blazejewski', + 'Dejaynes', + 'Djordjevic', + 'Eckenroth', + 'Estala', + 'Giacomo', + 'Glaub', + 'Golubski', + 'Guerreiro', + 'Housholder', + 'Kashuba', + 'Klute', + 'Lennartz', + 'Messamore', + 'Rovito', + 'Schreurs', + 'Starcevich', + 'Starkel', + 'Szczerba', + 'Thomassen', + 'Varkey', + 'Yorio', + 'Guba', + 'Unzicker', + 'Howry', + 'Bido', + 'Farella', + 'Frane', + 'Werry', + 'Cornia', + 'Postal', + 'Humphres', + 'Ran', + 'Macnair', + 'Duston', + 'Aveni', + 'Mcconn', + 'Sistare', + 'Wadell', + 'Naraine', + 'Mubarak', + 'Lonzo', + 'Shyne', + 'Tilmon', + 'Symonette', + 'Shinholster', + 'Oree', + 'Ogarro', + 'Quashie', + 'Almario', + 'Antonsen', + 'Armetta', + 'Avetisyan', + 'Bania', + 'Barricklow', + 'Bloemker', + 'Cannavo', + 'Dolliver', + 'Espenshade', + 'Falor', + 'Fukuhara', + 'Gemme', + 'Goldfinger', + 'Gonya', + 'Hamamoto', + 'Hindi', + 'Hiraldo', + 'Holquin', + 'Janco', + 'Janow', + 'Lemming', + 'Macchio', + 'Mago', + 'Mavity', + 'Mcnamer', + 'Mushrush', + 'Niskanen', + 'Ohms', + 'Pawluk', + 'Popple', + 'Poser', + 'Schiavi', + 'Stram', + 'Streight', + 'Stueck', + 'Vansandt', + 'Vivona', + 'Vongphakdy', + 'Zalar', + 'Zipper', + 'Altic', + 'Billmeyer', + 'Boghosian', + 'Bohlke', + 'Cisewski', + 'Gabrielsen', + 'Gianotti', + 'Heffler', + 'Holian', + 'Kannenberg', + 'Lenius', + 'Manuelito', + 'Mugavero', + 'Reinier', + 'Rekowski', + 'Sadlier', + 'Scialdone', + 'Stromquist', + 'Vittetoe', + 'Vorwald', + 'Widrig', + 'Audi', + 'Peral', + 'Devery', + 'Gato', + 'Sower', + 'Vanes', + 'Bonnes', + 'Hense', + 'Counsell', + 'Frankie', + 'Colford', + 'Wanser', + 'Mickels', + 'Briddell', + 'Washinton', + 'Antilla', + 'Baxendale', + 'Beining', + 'Belveal', + 'Boedecker', + 'Bottenfield', + 'Bufano', + 'Castellana', + 'Chaikin', + 'Cherne', + 'Costilow', + 'Dzialo', + 'Goeken', + 'Gombert', + 'Hammerman', + 'Hansman', + 'Hartling', + 'Kalani', + 'Klich', + 'Kolodziejski', + 'Kramar', + 'Lapinsky', + 'Latterell', + 'Lipsitz', + 'Loma', + 'Lukenbill', + 'Marxen', + 'Metallo', + 'Molner', + 'Niquette', + 'Ostrand', + 'Pelster', + 'Previti', + 'Rennaker', + 'Roering', + 'Roode', + 'Saltos', + 'Sangiovanni', + 'Schiraldi', + 'Schlafer', + 'Schwering', + 'Seedorf', + 'Sklenar', + 'Spinello', + 'Steinhorst', + 'Urueta', + 'Vonstein', + 'Bonczek', + 'Casalino', + 'Chiaro', + 'Doffing', + 'Downham', + 'Gillotti', + 'Hearl', + 'Karges', + 'Kunesh', + 'Langeland', + 'Maertz', + 'Mattinson', + 'Mignano', + 'Pasquinelli', + 'Petracca', + 'Pherigo', + 'Pikus', + 'Reichmuth', + 'Schwegman', + 'Schwerdt', + 'Seelman', + 'Winquist', + 'Wyka', + 'Yahr', + 'Bunkers', + 'Delnegro', + 'Norder', + 'Manas', + 'Polites', + 'Grape', + 'Jares', + 'Surges', + 'Asa', + 'Copeman', + 'Askar', + 'Goman', + 'Whitmyer', + 'Cohran', + 'Imbert', + 'Beaner', + 'Hugger', + 'Petion', + 'Lauture', + 'Andringa', + 'Athanas', + 'Butrick', + 'Caronna', + 'Dedominicis', + 'Eligio', + 'Fasick', + 'Hilinski', + 'Hinely', + 'Idler', + 'Janosko', + 'Kempner', + 'Klosinski', + 'Lapeyrouse', + 'Lindroth', + 'Marcon', + 'Meding', + 'Peppin', + 'Quizon', + 'Rectenwald', + 'Roessner', + 'Roets', + 'Schonberger', + 'Szostek', + 'Wassink', + 'Whan', + 'Yeakle', + 'Alguire', + 'Bielenberg', + 'Bisaillon', + 'Bonenberger', + 'Centola', + 'Colaizzi', + 'Deroos', + 'Eberlin', + 'Ehrig', + 'Ferenc', + 'Freiermuth', + 'Fruchter', + 'Garnto', + 'Huxford', + 'Knous', + 'Luttman', + 'Mulry', + 'Schirm', + 'Stankovic', + 'Authier', + 'Derise', + 'Doo', + 'Kessen', + 'Maline', + 'Porada', + 'Vasconez', + 'Haseman', + 'Tonner', + 'Woodroof', + 'Bedrossian', + 'Cranmore', + 'Dodaro', + 'Hommes', + 'Harmony', + 'Peno', + 'Mccommon', + 'Colver', + 'Olinde', + 'Oba', + 'Colone', + 'Warbington', + 'Monie', + 'Whitmill', + 'Moxey', + 'Canion', + 'Mcclenney', + 'Hallmon', + 'Austill', + 'Berni', + 'Boehning', + 'Bueso', + 'Cefalo', + 'Conneely', + 'Demicco', + 'Dieppa', + 'Duris', + 'Durnil', + 'Erxleben', + 'Hashimi', + 'Hedquist', + 'Koc', + 'Lamattina', + 'Lassman', + 'Ligman', + 'Lukins', + 'Mackler', + 'Manolis', + 'Mou', + 'Oblak', + 'Omahoney', + 'Paolo', + 'Pollok', + 'Priess', + 'Reeh', + 'Rempfer', + 'Rickerd', + 'Schoettle', + 'Serritella', + 'Steedman', + 'Suss', + 'Tanimoto', + 'Thaden', + 'Thelin', + 'Vanwingerden', + 'Wacha', + 'Weldin', + 'Youkhana', + 'Bazzano', + 'Behring', + 'Caliri', + 'Cocchi', + 'Croissant', + 'Dibbern', + 'Figiel', + 'Flygare', + 'Grieshop', + 'Iten', + 'Kaupp', + 'Linnane', + 'Plybon', + 'Rappleye', + 'Romanik', + 'Saefong', + 'Schetter', + 'Schryer', + 'Siwik', + 'Snitker', + 'Tomasic', + 'Wavra', + 'Auen', + 'Thone', + 'Marso', + 'Shadid', + 'Cake', + 'Louvier', + 'Macia', + 'Areola', + 'Kardell', + 'Strome', + 'Coogle', + 'Delis', + 'Pistorius', + 'Raybourn', + 'Sula', + 'Math', + 'Sanda', + 'Renaldo', + 'Pat', + 'Florance', + 'Brank', + 'Alice', + 'Rosebrough', + 'Quiett', + 'Henigan', + 'Mcclees', + 'Dase', + 'Bagot', + 'Kings', + 'Lanehart', + 'Barbary', + 'Stitts', + 'Aurora', + 'Baldoni', + 'Barkalow', + 'Bohnet', + 'Bosshart', + 'Decapua', + 'Denbo', + 'Deneault', + 'Dinse', + 'Dul', + 'Estle', + 'Filipski', + 'Fishell', + 'Fluckiger', + 'Glassberg', + 'Janick', + 'Juda', + 'Kibbee', + 'Kreisler', + 'Lawther', + 'Levangie', + 'Lichtenwalner', + 'Lucking', + 'Meiner', + 'Mileham', + 'Milz', + 'Reposa', + 'Rinehimer', + 'Rupley', + 'Sandez', + 'Schinke', + 'Sharpnack', + 'Sineath', + 'Tax', + 'Thumma', + 'Urda', + 'Widdison', + 'Bergdoll', + 'Bruhl', + 'Chesmore', + 'Delfavero', + 'Ferderer', + 'Haueter', + 'Hirshberg', + 'Hollobaugh', + 'Lalama', + 'Mckeag', + 'Mehlhoff', + 'Mirchandani', + 'Orwick', + 'Puskarich', + 'Schlotzhauer', + 'Stoiber', + 'Swetz', + 'Basara', + 'Magaw', + 'Amble', + 'Hawe', + 'Toren', + 'Parilla', + 'Gowell', + 'Selkirk', + 'Edris', + 'Ariel', + 'Kihara', + 'Dunkerson', + 'Halk', + 'Mooty', + 'Tippen', + 'Fullenwider', + 'Herford', + 'Salton', + 'Feider', + 'Buckhannon', + 'Mckneely', + 'Milon', + 'Whiters', + 'Barasch', + 'Baria', + 'Basques', + 'Beavin', + 'Borre', + 'Branz', + 'Broers', + 'Conca', + 'Cortopassi', + 'Courchesne', + 'Crisanti', + 'Cumpian', + 'Dagan', + 'Dekay', + 'Demartin', + 'Dewaard', + 'Dowland', + 'Duffell', + 'Ebersol', + 'Faiola', + 'Frontz', + 'Fryling', + 'Garczynski', + 'Hanway', + 'Huettner', + 'Janovsky', + 'Johndrow', + 'Kahana', + 'Kaniewski', + 'Kulish', + 'Lich', + 'Lincks', + 'Loppnow', + 'Macnab', + 'Mcconaughy', + 'Melroy', + 'Noviello', + 'Orn', + 'Pacas', + 'Peppel', + 'Polidori', + 'Radi', + 'Riesgo', + 'Romanoski', + 'Sagrero', + 'Schirripa', + 'Spack', + 'Sternhagen', + 'Tamburri', + 'Traczyk', + 'Uballe', + 'Vandruff', + 'Voght', + 'Weant', + 'Weinel', + 'Angerman', + 'Boultinghouse', + 'Dolinar', + 'Dripps', + 'Dubow', + 'Ehrhard', + 'Janvrin', + 'Lazear', + 'Liddiard', + 'Madayag', + 'Mirkin', + 'Monticello', + 'Mulka', + 'Oliger', + 'Pierceall', + 'Pittner', + 'Polkowski', + 'Prindiville', + 'Rasnic', + 'Tellefsen', + 'Uffelman', + 'Vandenbergh', + 'Weisenbach', + 'Wiedmeyer', + 'Wintle', + 'Wisz', + 'Yorba', + 'Holtmeyer', + 'Tabet', + 'Laham', + 'Barsoum', + 'Henner', + 'Idle', + 'Shaft', + 'Rennels', + 'Swarm', + 'Forgie', + 'Khaled', + 'Avon', + 'Hewey', + 'Grober', + 'Pipe', + 'Macfadden', + 'Keath', + 'Fergason', + 'Polland', + 'Brownley', + 'Haslip', + 'Crocket', + 'Tines', + 'Juniel', + 'Opara', + 'Bethley', + 'Ambuehl', + 'Bagheri', + 'Baquera', + 'Bertoli', + 'Bisek', + 'Borroto', + 'Botten', + 'Bovenzi', + 'Bruntz', + 'Buehring', + 'Canche', + 'Cicco', + 'Dambach', + 'Delellis', + 'Deniston', + 'Dirico', + 'Feagle', + 'Frayne', + 'Haagenson', + 'Janicke', + 'Kashyap', + 'Kastel', + 'Kruck', + 'Langi', + 'Lapka', + 'Marschner', + 'Megia', + 'Nesta', + 'Nevala', + 'Oblinger', + 'Picchi', + 'Rodeffer', + 'Salkin', + 'Scavuzzo', + 'Sladky', + 'Soyars', + 'Suchil', + 'Thielbar', + 'Timoteo', + 'Vanhise', + 'Varden', + 'Waldoch', + 'Watling', + 'Werk', + 'Becvar', + 'Betteridge', + 'Bolliger', + 'Bonifield', + 'Buchberger', + 'Caprara', + 'Castrogiovanni', + 'Fallaw', + 'Geeting', + 'Hiegel', + 'Hulgan', + 'Kokesh', + 'Lanting', + 'Mcphetridge', + 'Nuxoll', + 'Soun', + 'Strothman', + 'Triska', + 'Vensel', + 'Wesolek', + 'Wixted', + 'Wolgemuth', + 'Yedinak', + 'Anthis', + 'Manfred', + 'Agans', + 'Lafoe', + 'Mcginnes', + 'Folwell', + 'Galvao', + 'Carmo', + 'Valin', + 'Woon', + 'Degregory', + 'Evangelist', + 'Coast', + 'Strater', + 'Decou', + 'Pears', + 'Nellums', + 'Kynard', + 'Boursiquot', + 'Ruffins', + 'Akhavan', + 'Baloga', + 'Barany', + 'Buche', + 'Davoli', + 'Fennewald', + 'Figler', + 'Frede', + 'Gannett', + 'Ghannam', + 'Handlon', + 'Herridge', + 'Jakel', + 'Kamphuis', + 'Kattan', + 'Kemplin', + 'Klecka', + 'Korver', + 'Kozakiewicz', + 'Linenberger', + 'Lofaso', + 'Lorman', + 'Lueder', + 'Mcconahay', + 'Mcternan', + 'Mench', + 'Norenberg', + 'Oro', + 'Ostenson', + 'Pant', + 'Peardon', + 'Pertuit', + 'Ritzert', + 'Salvetti', + 'Sandner', + 'Sheek', + 'Sniegowski', + 'Sorbo', + 'Sperbeck', + 'Sump', + 'Supinski', + 'Sweetin', + 'Toenjes', + 'Velotta', + 'Venier', + 'Veracruz', + 'Wender', + 'Yamagata', + 'Arostegui', + 'Balestra', + 'Blumstein', + 'Carras', + 'Grauberger', + 'Howdeshell', + 'Murayama', + 'Nippert', + 'Notch', + 'Reisert', + 'Sebren', + 'Tetzloff', + 'Venneman', + 'Douds', + 'Lineman', + 'Powles', + 'Huet', + 'Matto', + 'Roes', + 'Dillin', + 'Lagan', + 'Bakes', + 'Yann', + 'Canterberry', + 'Milum', + 'Hinderman', + 'Linzey', + 'Ballen', + 'Ventress', + 'Prysock', + 'Bangle', + 'Blinder', + 'Bugaj', + 'Carlisi', + 'Dimario', + 'Dzikowski', + 'Gaetz', + 'Galves', + 'Ghazal', + 'Golebiewski', + 'Hadsall', + 'Hogberg', + 'Krammer', + 'Kreisher', + 'Lamia', + 'Luhmann', + 'Lupa', + 'Michelotti', + 'Nesci', + 'Paape', + 'Posthumus', + 'Reth', + 'Sassman', + 'Schlechter', + 'Schlie', + 'Schumacker', + 'Seliger', + 'Shanholtzer', + 'Strojny', + 'Taglieri', + 'Tibbles', + 'Tregoning', + 'Valine', + 'Zeiset', + 'Antu', + 'Bierwirth', + 'Birenbaum', + 'Boeder', + 'Dobkins', + 'Fenoglio', + 'Jentsch', + 'Marcinkiewicz', + 'Mruk', + 'Muhlbauer', + 'Namba', + 'Oettinger', + 'Rigor', + 'Rothweiler', + 'Schmader', + 'Schork', + 'Vandevoort', + 'Brenny', + 'Neels', + 'Fodge', + 'Que', + 'Dalpe', + 'Guerard', + 'Lammey', + 'Alfredo', + 'Corrin', + 'Quarry', + 'Reise', + 'Derrow', + 'Worrel', + 'Tennent', + 'Cassis', + 'Winson', + 'Cornet', + 'Garlin', + 'Saucer', + 'Ursery', + 'Saffo', + 'Battee', + 'Ackerley', + 'Ackland', + 'Allmendinger', + 'Altamura', + 'Anastas', + 'Artola', + 'Baldassari', + 'Bayron', + 'Bouwkamp', + 'Buonopane', + 'Chronis', + 'Coffaro', + 'Dech', + 'Delfierro', + 'Depaulo', + 'Digges', + 'Dowda', + 'Drab', + 'Feijoo', + 'Formato', + 'Friedli', + 'Hanahan', + 'Hegna', + 'Igarashi', + 'Kamai', + 'Kory', + 'Kuzel', + 'Lewkowicz', + 'Lumbra', + 'Mccreadie', + 'Meisch', + 'Montoro', + 'Pamintuan', + 'Petrow', + 'Pulcini', + 'Shewell', + 'Spitznagel', + 'Swedlund', + 'Terhorst', + 'Wilberg', + 'Willwerth', + 'Affinito', + 'Baune', + 'Beichner', + 'Boutell', + 'Challender', + 'Ellestad', + 'Gomm', + 'Hochstatter', + 'Jasko', + 'Kielar', + 'Kimmerle', + 'Kirshenbaum', + 'Kotila', + 'Lecker', + 'Manross', + 'Mcnevin', + 'Neuburger', + 'Verderosa', + 'Wiltsey', + 'Caminero', + 'Gianfrancesco', + 'Shiverdecker', + 'Amman', + 'Flavell', + 'Oconor', + 'Shure', + 'Hanagan', + 'Bokor', + 'Mashaw', + 'Ground', + 'Brittenham', + 'Pinera', + 'Smaltz', + 'Hold', + 'Gallamore', + 'Delon', + 'Hearing', + 'Rynes', + 'Cocklin', + 'Cassie', + 'Calligan', + 'Josue', + 'Congo', + 'Tennell', + 'Blyther', + 'Azarian', + 'Bauernfeind', + 'Beeghly', + 'Berget', + 'Brayfield', + 'Cerasoli', + 'Dedecker', + 'Gloeckner', + 'Herriges', + 'Hoganson', + 'Ivancic', + 'Jakeway', + 'Kayne', + 'Kitko', + 'Kohlbeck', + 'Krabbenhoft', + 'Kumari', + 'Lauri', + 'Leiber', + 'Minke', + 'Montecino', + 'Moutray', + 'Munshi', + 'Ohlin', + 'Portocarrero', + 'Rados', + 'Roedl', + 'Rossing', + 'Schake', + 'Simonin', + 'Staffa', + 'Stroschein', + 'Titman', + 'Treder', + 'Vonada', + 'Xenakis', + 'Aulds', + 'Benedick', + 'Boulais', + 'Butikofer', + 'Butorac', + 'Contento', + 'Goetting', + 'Goldammer', + 'Hopke', + 'Koppes', + 'Phetteplace', + 'Roehrs', + 'Schul', + 'Slabach', + 'Steinmiller', + 'Sucharski', + 'Vorwerk', + 'Wahlert', + 'Wheatcraft', + 'Abellera', + 'Jutte', + 'Baumgarner', + 'Tijerino', + 'Awadallah', + 'Horen', + 'Lina', + 'Stanbrough', + 'College', + 'Jarry', + 'Keas', + 'Mordan', + 'Ramnauth', + 'Rena', + 'Wa', + 'Petters', + 'Ramnath', + 'Hellams', + 'Mamon', + 'Cheese', + 'Meggett', + 'Anttila', + 'Beilman', + 'Binsfeld', + 'Brining', + 'Brubeck', + 'Carcione', + 'Chandran', + 'Chaudhuri', + 'Cogliano', + 'Dimaano', + 'Dols', + 'Doughten', + 'Ehrenfeld', + 'Elena', + 'Fausnaugh', + 'Fetz', + 'Fogelson', + 'Fraleigh', + 'Gaza', + 'Giesey', + 'Gockel', + 'Gougeon', + 'Granito', + 'Grassia', + 'Hauserman', + 'Idrovo', + 'Iwan', + 'Janning', + 'Kaffenberger', + 'Kichline', + 'Kimoto', + 'Kolodny', + 'Kortum', + 'Lafevers', + 'Lodi', + 'Longton', + 'Ludke', + 'Manganelli', + 'Mccuan', + 'Merryfield', + 'Mezquita', + 'Morandi', + 'Neibauer', + 'Oran', + 'Ozaeta', + 'Pacha', + 'Palese', + 'Perala', + 'Pisarcik', + 'Pobanz', + 'Pommer', + 'Pontrelli', + 'Prabhakar', + 'Rehmann', + 'Scheunemann', + 'Severini', + 'Skalla', + 'Srinivas', + 'Stadtmiller', + 'Trentman', + 'Trinka', + 'Tutterow', + 'Vari', + 'Wence', + 'Zeff', + 'Anagnos', + 'Arvayo', + 'Bihl', + 'Darbyshire', + 'Deeg', + 'Domagalski', + 'Estenson', + 'Finkenbinder', + 'Gaboriault', + 'Kastens', + 'Lacek', + 'Merkin', + 'Mersman', + 'Nicolaus', + 'Offerdahl', + 'Pallett', + 'Platten', + 'Quesnell', + 'Skene', + 'Sondag', + 'Wolfrom', + 'Mineer', + 'Sor', + 'Canard', + 'Mcmeen', + 'Tur', + 'Giner', + 'Mackrell', + 'Alic', + 'Sampath', + 'Baby', + 'Beales', + 'Kadri', + 'Minot', + 'Bienvenue', + 'Millirons', + 'Woodstock', + 'Landing', + 'Limehouse', + 'Andonian', + 'Armentor', + 'Asai', + 'Cutaia', + 'Darji', + 'Delsanto', + 'Deutch', + 'Droge', + 'Emme', + 'Flenner', + 'Gaida', + 'Gladd', + 'Guettler', + 'Guggisberg', + 'Guier', + 'Habenicht', + 'Heininger', + 'Helfman', + 'Hiscox', + 'Holtorf', + 'Hovious', + 'Juul', + 'Lacock', + 'Lepisto', + 'Malanowski', + 'Marineau', + 'Matza', + 'Meffert', + 'Nuon', + 'Oneto', + 'Padmanabhan', + 'Pantuso', + 'Pesci', + 'Rosenbluth', + 'Rubano', + 'Sedlar', + 'Sferrazza', + 'Sifuentez', + 'Simione', + 'Torossian', + 'Vaux', + 'Weilbacher', + 'Wiatrek', + 'Brzoska', + 'Caltabiano', + 'Csaszar', + 'Eyerman', + 'Geissinger', + 'Gioffre', + 'Grilliot', + 'Grotz', + 'Harrower', + 'Jaroszewski', + 'Jokerst', + 'Kamali', + 'Kampmann', + 'Klemz', + 'Koike', + 'Lista', + 'Mcconkie', + 'Mencia', + 'Missler', + 'Olshefski', + 'Omdahl', + 'Penunuri', + 'Scheckel', + 'Schreiter', + 'Swackhammer', + 'Taflinger', + 'Tegethoff', + 'Ummel', + 'Wetsel', + 'Wissmann', + 'Porr', + 'Ramser', + 'Russett', + 'Clucas', + 'Matlin', + 'Noblet', + 'Boyan', + 'Koman', + 'Lope', + 'Deman', + 'Latendresse', + 'Bound', + 'Rijos', + 'Bouillon', + 'Crunkleton', + 'Jayson', + 'Anne', + 'Staude', + 'Sturn', + 'Burdell', + 'Arther', + 'Yett', + 'Woolcock', + 'Clemon', + 'Saintjean', + 'Sainvil', + 'Coverson', + 'Barroga', + 'Benedicto', + 'Borin', + 'Budrow', + 'Cuddihy', + 'Forness', + 'Gohman', + 'Hepker', + 'Hilscher', + 'Holien', + 'Holstad', + 'Hopfer', + 'Hulburt', + 'Kalter', + 'Kuehnle', + 'Lachica', + 'Macioce', + 'Massimo', + 'Matsubara', + 'Meaker', + 'Mehmedovic', + 'Minckler', + 'Miralles', + 'Mostek', + 'Oshita', + 'Parthasarathy', + 'Roszak', + 'Rottenberg', + 'Rydman', + 'Shankman', + 'Sprong', + 'Stenerson', + 'Strubel', + 'Tavano', + 'Thornberg', + 'Trumpower', + 'Whittinghill', + 'Altenhofen', + 'Bartolucci', + 'Debski', + 'Dekoning', + 'Dottavio', + 'Emminger', + 'Hodkinson', + 'Hurtubise', + 'Lauridsen', + 'Leinberger', + 'Luskin', + 'Pask', + 'Rehfeld', + 'Spagna', + 'Szumski', + 'Szymborski', + 'Teem', + 'Tritschler', + 'Tschantz', + 'Tsutsui', + 'Vanecek', + 'Haddaway', + 'Colombe', + 'Mayol', + 'Shivley', + 'Maturin', + 'Babe', + 'Bovey', + 'Bathe', + 'Belliard', + 'Loner', + 'Arrow', + 'Billa', + 'Mcneish', + 'Kinton', + 'Scarber', + 'Donson', + 'Atherley', + 'Abdulaziz', + 'Age', + 'Carreker', + 'Tory', + 'Leduff', + 'Wattley', + 'Altergott', + 'Belitz', + 'Bidinger', + 'Blauch', + 'Cariker', + 'Condren', + 'Curiale', + 'Dronet', + 'Elstad', + 'Esquerra', + 'Fread', + 'Gilb', + 'Goga', + 'Gonyo', + 'Grudzien', + 'Hino', + 'Ishler', + 'Jacober', + 'Kilty', + 'Kuhrt', + 'Lairmore', + 'Lamba', + 'Lorek', + 'Lucich', + 'Marcou', + 'Mcgath', + 'Menze', + 'Mindel', + 'Nabb', + 'Ottosen', + 'Pann', + 'Ratkowski', + 'Saurer', + 'Sedore', + 'Shonka', + 'Soberano', + 'Sossamon', + 'Stdennis', + 'Stillinger', + 'Tager', + 'Tersigni', + 'Tissue', + 'Trampe', + 'Twite', + 'Whitling', + 'Wiebusch', + 'Abundez', + 'Bisping', + 'Candella', + 'Dahill', + 'Groebner', + 'Gulbrandsen', + 'Hasenauer', + 'Heesch', + 'Hipwell', + 'Kamrowski', + 'Keyworth', + 'Kleinschmit', + 'Legorreta', + 'Minium', + 'Mixter', + 'Neiswonger', + 'Purk', + 'Rinkenberger', + 'Rosenkrans', + 'Rozenberg', + 'Simenson', + 'Soltes', + 'Storino', + 'Viereck', + 'Schaafsma', + 'Craigie', + 'Amorin', + 'Latner', + 'Bowmer', + 'Nasby', + 'Bada', + 'Rami', + 'Mcglashan', + 'Reede', + 'Police', + 'Cobey', + 'Dahir', + 'Dirden', + 'Destine', + 'Akkerman', + 'Azzopardi', + 'Blankenhorn', + 'Bolio', + 'Brandhorst', + 'Buchter', + 'Canul', + 'Cocozza', + 'Collantes', + 'Cronic', + 'Cullifer', + 'Delpizzo', + 'Demoranville', + 'Dolder', + 'Dvorsky', + 'Eggett', + 'Elgersma', + 'Episcopo', + 'Esses', + 'Fehlman', + 'Gansen', + 'Garciamartinez', + 'Goldwater', + 'Gushue', + 'Hittner', + 'Igel', + 'Jupin', + 'Kostoff', + 'Kruschke', + 'Kuechler', + 'Labs', + 'Lacerte', + 'Lagle', + 'Leischner', + 'Linders', + 'Marulanda', + 'Meindl', + 'Melman', + 'Menden', + 'Orbach', + 'Patak', + 'Patras', + 'Petroni', + 'Rabenold', + 'Rapisarda', + 'Rodenburg', + 'Roelle', + 'Schar', + 'Scherbarth', + 'Simar', + 'Thoen', + 'Trana', + 'Tuch', + 'Turko', + 'Wamser', + 'Weinfeld', + 'Wirz', + 'Zatorski', + 'Zbinden', + 'Aksamit', + 'Asebedo', + 'Biello', + 'Bouchey', + 'Callejo', + 'Espanol', + 'Flathers', + 'Kunka', + 'Liaw', + 'Mckowen', + 'Mitrano', + 'Needler', + 'Och', + 'Paolella', + 'Patricelli', + 'Recine', + 'Rengel', + 'Spinler', + 'Wagenaar', + 'Winnicki', + 'Eichert', + 'Dabb', + 'Imrie', + 'Antoni', + 'Lardner', + 'Maund', + 'Schou', + 'Brittin', + 'Anthon', + 'Was', + 'Nevis', + 'Delamar', + 'Mcnorton', + 'Tankard', + 'Boardley', + 'Garcon', + 'Wimes', + 'Antell', + 'Belmarez', + 'Boff', + 'Boughan', + 'Cando', + 'Carrender', + 'Carrieri', + 'Charnley', + 'Cittadino', + 'Cwynar', + 'Deupree', + 'Doepke', + 'Fasone', + 'Fauteux', + 'Foody', + 'Fornal', + 'Fust', + 'Gasner', + 'Gloe', + 'Gorter', + 'Grumbine', + 'Hancher', + 'Hapke', + 'Heckendorn', + 'Heinlen', + 'Hilgeman', + 'Kahre', + 'Kakos', + 'Kops', + 'Lahn', + 'Leiferman', + 'Lothamer', + 'Mallis', + 'Napierkowski', + 'Orbin', + 'Panno', + 'Piacente', + 'Posas', + 'Ragasa', + 'Sonora', + 'Stupka', + 'Tio', + 'Valido', + 'Weyrick', + 'Argall', + 'Arrighi', + 'Bohlken', + 'Desrocher', + 'Distad', + 'Erkkila', + 'Gherardi', + 'Goughnour', + 'Koltz', + 'Koperski', + 'Lafalce', + 'Lucken', + 'Meleski', + 'Mortellaro', + 'Nagorski', + 'Pedrotti', + 'Pruyn', + 'Revard', + 'Saffran', + 'Schnoebelen', + 'Sermersheim', + 'Skroch', + 'Vandervliet', + 'Alwood', + 'Bosso', + 'Hor', + 'Licerio', + 'Septer', + 'Labo', + 'Lessa', + 'Ooley', + 'Gorgas', + 'Medal', + 'Coull', + 'Creely', + 'Bolland', + 'Ishaq', + 'Legore', + 'Alicia', + 'Fillingame', + 'Levers', + 'Flight', + 'Woodrick', + 'Berrie', + 'Buckels', + 'Pigue', + 'Crosse', + 'Speakes', + 'Wynes', + 'Mussa', + 'Highbaugh', + 'Venning', + 'Dupas', + 'Mccastle', + 'Andreoni', + 'Bakula', + 'Besemer', + 'Blier', + 'Braaksma', + 'Brocco', + 'Cajas', + 'Campano', + 'Crapser', + 'Dentinger', + 'Deziel', + 'Dragos', + 'Ekblad', + 'Gargis', + 'Gilberto', + 'Guadron', + 'Hollern', + 'Leibensperger', + 'Lindaman', + 'Lumadue', + 'Mault', + 'Mieses', + 'Nanninga', + 'Nudd', + 'Ouch', + 'Ramin', + 'Reggio', + 'Ruttan', + 'Saccomanno', + 'Scheaffer', + 'Sohm', + 'Spaniol', + 'Stenner', + 'Strieter', + 'Takashima', + 'Vaid', + 'Venzke', + 'Wallwork', + 'Zaffuto', + 'Zaucha', + 'Zemel', + 'Zinni', + 'Alltop', + 'Ciolek', + 'Empie', + 'Flitton', + 'Gullikson', + 'Hassebrock', + 'Kanitz', + 'Kirschenmann', + 'Krivanek', + 'Loseke', + 'Mckercher', + 'Melching', + 'Nham', + 'Ormerod', + 'Randlett', + 'Reifel', + 'Sawada', + 'Sofranko', + 'Stoia', + 'Umeda', + 'Eagon', + 'Hucker', + 'Kenniston', + 'Salus', + 'Ayyad', + 'Camey', + 'Dacy', + 'Joa', + 'Peerson', + 'Rossy', + 'Aure', + 'Keetch', + 'Sprigg', + 'Southgate', + 'Parden', + 'Andris', + 'Bossman', + 'Blondell', + 'Carmickle', + 'Pelly', + 'Mceachron', + 'Marry', + 'Burel', + 'Shark', + 'Flash', + 'Rickenbacker', + 'Foots', + 'Sillah', + 'Almgren', + 'Awtrey', + 'Berganza', + 'Boehne', + 'Bralley', + 'Brosnahan', + 'Caddick', + 'Chandonnet', + 'Cullimore', + 'Darroch', + 'Eimers', + 'Flam', + 'Howerter', + 'Jerzak', + 'Kabler', + 'Kirkes', + 'Kopper', + 'Krakow', + 'Linskey', + 'Lizzi', + 'Luria', + 'Marcrum', + 'Mathy', + 'Matulich', + 'Miskin', + 'Moghadam', + 'Nagarajan', + 'Packham', + 'Papania', + 'Paup', + 'Rippeon', + 'Rolli', + 'Rubey', + 'Scherzinger', + 'Scrima', + 'Sharar', + 'Shoberg', + 'Stupar', + 'Tendler', + 'Tobiason', + 'Vanvooren', + 'Zisa', + 'Bindel', + 'Flasch', + 'Graetz', + 'Heintzman', + 'Kosanke', + 'Longden', + 'Mahfouz', + 'Mormile', + 'Nannini', + 'Olaes', + 'Panik', + 'Putzier', + 'Radilla', + 'Schaedler', + 'Schoepf', + 'Sianez', + 'Taucher', + 'Wiebelhaus', + 'Banka', + 'Console', + 'Derego', + 'Vile', + 'Colgin', + 'Drage', + 'Josten', + 'Luckadoo', + 'Ryen', + 'Bako', + 'Ow', + 'Patient', + 'Elmes', + 'Mossa', + 'Colee', + 'Comber', + 'Tippy', + 'Perrell', + 'Axon', + 'Rickson', + 'Postlewaite', + 'Lafargue', + 'Guffin', + 'Cains', + 'Dewindt', + 'Cathy', + 'Tallie', + 'Ausby', + 'Alires', + 'Baz', + 'Bergeman', + 'Bodensteiner', + 'Borghi', + 'Dematos', + 'Denzler', + 'Dorko', + 'Duffett', + 'Dykas', + 'Emerton', + 'Fenger', + 'Fosberg', + 'Gwinner', + 'Kniess', + 'Lerew', + 'Lohner', + 'Lun', + 'Maita', + 'Mandler', + 'Marcoe', + 'Nikolov', + 'Paschen', + 'Paver', + 'Prosperi', + 'Rackliff', + 'Roever', + 'Ruberg', + 'Ruest', + 'Schnick', + 'Schuur', + 'Sowash', + 'Zanca', + 'Brecheen', + 'Brusky', + 'Chauca', + 'Debernardi', + 'Froio', + 'Gadway', + 'Karoly', + 'Kintzel', + 'Kneisley', + 'Kruser', + 'Lindfors', + 'Lwin', + 'Oursler', + 'Peruski', + 'Petteys', + 'Rottmann', + 'Schroeck', + 'Stenglein', + 'Vigen', + 'Wempe', + 'Zehren', + 'Wollen', + 'Dismore', + 'Santalucia', + 'Laza', + 'Pesnell', + 'Litle', + 'Markson', + 'Piercefield', + 'Jerrett', + 'Virginia', + 'Demonbreun', + 'Tugman', + 'Ramoutar', + 'Bazin', + 'Ola', + 'Alamin', + 'Adebayo', + 'Berkland', + 'Bernt', + 'Briguglio', + 'Bulnes', + 'Burack', + 'Cantoran', + 'Giardini', + 'Goetzke', + 'Graziosi', + 'Guberman', + 'Kamaka', + 'Karvonen', + 'Kitz', + 'Kopera', + 'Krempa', + 'Linkenhoker', + 'Mascioli', + 'Matlick', + 'Mcmahill', + 'Medaglia', + 'Mirarchi', + 'Mondry', + 'Muhlestein', + 'Murty', + 'Orender', + 'Pesantez', + 'Postiglione', + 'Reisen', + 'Riff', + 'Scarantino', + 'Seelinger', + 'Seher', + 'Sharum', + 'Sorice', + 'Staebler', + 'Tanney', + 'Tech', + 'Tramontano', + 'Trude', + 'Vasudevan', + 'Wareing', + 'Westerhold', + 'Wohlfarth', + 'Achorn', + 'Boesel', + 'Calabaza', + 'Dunkleberger', + 'Erck', + 'Fanger', + 'Felmlee', + 'Friebel', + 'Gabrys', + 'Godsil', + 'Goldhammer', + 'Gourneau', + 'Kaseman', + 'Keysor', + 'Mccargar', + 'Mittag', + 'Narum', + 'Schoeneck', + 'Stenquist', + 'Sunderlin', + 'Tarazon', + 'Tietze', + 'Wemmer', + 'Witthuhn', + 'Durango', + 'Simerson', + 'Beber', + 'Bjorn', + 'Neuville', + 'Preas', + 'Reitter', + 'Senf', + 'Mcclatchy', + 'Sanor', + 'Benney', + 'Sarrazin', + 'Woodliff', + 'Bramlet', + 'Cullin', + 'Wessells', + 'Higgens', + 'Rout', + 'Craigen', + 'Ackers', + 'Wickliff', + 'Hofler', + 'Pilgram', + 'Mcfayden', + 'Dillworth', + 'Robenson', + 'Mateen', + 'Ambrogio', + 'Aoun', + 'Aranas', + 'Balsiger', + 'Bonzo', + 'Busam', + 'Casassa', + 'Ciborowski', + 'Cotterill', + 'Cressler', + 'Cristales', + 'Crumpacker', + 'Daloisio', + 'Damasco', + 'Depolo', + 'Diguglielmo', + 'Dominik', + 'Esbenshade', + 'Fineran', + 'Formisano', + 'Gandolfi', + 'Geidel', + 'Gerwitz', + 'Grammatico', + 'Idleman', + 'Iwinski', + 'Kerth', + 'Lacouture', + 'Lafoy', + 'Lapid', + 'Lardizabal', + 'Lembcke', + 'Maga', + 'Mahrt', + 'Maniatis', + 'Martinezlopez', + 'Martinovich', + 'Milham', + 'Muscatello', + 'Perezperez', + 'Quiocho', + 'Rickner', + 'Sackrider', + 'Schwarm', + 'Schwebke', + 'Scollard', + 'Seader', + 'Shutters', + 'Skare', + 'Slothower', + 'Steeber', + 'Want', + 'Cherubini', + 'Coslett', + 'Degener', + 'Dulak', + 'Faull', + 'Freyman', + 'Gatchel', + 'Ginzburg', + 'Gronberg', + 'Landeck', + 'Lehenbauer', + 'Lubke', + 'Mcconaughey', + 'Mendonsa', + 'Minnehan', + 'Palaguachi', + 'Peedin', + 'Raithel', + 'Rezabek', + 'Rolfson', + 'Schuitema', + 'Sjodin', + 'Underkoffler', + 'Verrilli', + 'Yogi', + 'Zimpfer', + 'Zingaro', + 'Butrum', + 'Ritson', + 'Martinka', + 'Cashatt', + 'Kearn', + 'Sawtell', + 'Boyster', + 'Broyhill', + 'Cockerell', + 'Thane', + 'Resende', + 'Pealer', + 'Perrot', + 'Everhardt', + 'Breach', + 'Bry', + 'Juma', + 'Mclaine', + 'Paddy', + 'Hennesy', + 'Ledee', + 'Web', + 'Delone', + 'Louison', + 'Hamiel', + 'Tutson', + 'Bellingham', + 'Brenn', + 'Bussen', + 'Charrette', + 'Denenberg', + 'Depascale', + 'Derner', + 'Dondlinger', + 'Favro', + 'Frana', + 'Goeser', + 'Guerrini', + 'Hamideh', + 'Hetu', + 'Hnat', + 'Hollerbach', + 'Kenagy', + 'Kregel', + 'Lammi', + 'Laubacher', + 'Madarang', + 'Mangine', + 'Marut', + 'Mcmahen', + 'Memoli', + 'Milko', + 'Morash', + 'Mulvehill', + 'Nelles', + 'Perfecto', + 'Perkes', + 'Pesantes', + 'Peschke', + 'Polyakov', + 'Preheim', + 'Prust', + 'Reha', + 'Richardt', + 'Rockers', + 'Sartwell', + 'Schedler', + 'Scheler', + 'Skop', + 'Stefko', + 'Tatlock', + 'Tiley', + 'Waldecker', + 'Weinbaum', + 'Aguallo', + 'Benassi', + 'Bezio', + 'Bockover', + 'Dobesh', + 'Encina', + 'Eversman', + 'Haverfield', + 'Heigl', + 'Holzhauser', + 'Liebenow', + 'Mesenbrink', + 'Mittendorf', + 'Normoyle', + 'Pickart', + 'Rosselot', + 'Shigley', + 'Skufca', + 'Stroot', + 'Walth', + 'Wernert', + 'Lahood', + 'Ragain', + 'Stumpe', + 'Kolle', + 'Minerd', + 'Dickeson', + 'Koone', + 'Stoessel', + 'Kington', + 'Soe', + 'Wailes', + 'Monet', + 'Mccullars', + 'Huguenin', + 'Warnell', + 'Calip', + 'Sandles', + 'Fayson', + 'Balik', + 'Bauermeister', + 'Bianculli', + 'Bin', + 'Bring', + 'Busenbark', + 'Canevari', + 'Crile', + 'Dyment', + 'Egelhoff', + 'Elbe', + 'Estudillo', + 'Feigel', + 'Flammer', + 'Folta', + 'Ghuman', + 'Hefferan', + 'Hennick', + 'Hosner', + 'Kilner', + 'Liuzzi', + 'Maj', + 'Massing', + 'Nicolaisen', + 'Ohlrich', + 'Ozdemir', + 'Piccininni', + 'Prem', + 'Primiano', + 'Reek', + 'Riling', + 'Rohweder', + 'Rosasco', + 'Sandau', + 'Santarsiero', + 'Schuhmacher', + 'Stenseth', + 'Stilts', + 'Strohmeier', + 'Thorell', + 'Torr', + 'Vaswani', + 'Yono', + 'Amadon', + 'Ballowe', + 'Betke', + 'Borgwardt', + 'Decelle', + 'Dibiasio', + 'Fieldhouse', + 'Hegyi', + 'Heuberger', + 'Kreiling', + 'Montney', + 'Sammut', + 'Senseney', + 'Takenaka', + 'Tramonte', + 'Zalesky', + 'Zumstein', + 'Bents', + 'Vandersluis', + 'Wieringa', + 'Houlton', + 'Lippens', + 'Maino', + 'Keeny', + 'Bethards', + 'Guillette', + 'Lenn', + 'Minge', + 'Masley', + 'Christley', + 'Gabrielle', + 'Bruington', + 'Perren', + 'Ander', + 'Leeb', + 'Callicott', + 'Peaster', + 'Hardister', + 'Daughtridge', + 'Mclauchlin', + 'Culliver', + 'Missouri', + 'Aloisi', + 'Barua', + 'Bezek', + 'Broshears', + 'Busbin', + 'Cajamarca', + 'Dellarocco', + 'Dezeeuw', + 'Ferrelli', + 'Fieber', + 'Fredin', + 'Giovannoni', + 'Glasner', + 'Grenda', + 'Haberl', + 'Heimsoth', + 'Heinl', + 'Hellickson', + 'Hernandezlopez', + 'Huckeby', + 'Jungman', + 'Langhans', + 'Lingelbach', + 'Manera', + 'Maneri', + 'Marzella', + 'Mennen', + 'Molesworth', + 'Nagano', + 'Narula', + 'Niner', + 'Nordhoff', + 'Olazabal', + 'Perfect', + 'Plonka', + 'Pund', + 'Reincke', + 'Schimek', + 'Seegert', + 'Summar', + 'Tanori', + 'Trethewey', + 'Wehler', + 'Wirthlin', + 'Wolaver', + 'Zuver', + 'Bendure', + 'Bither', + 'Bungert', + 'Chaviano', + 'Derhammer', + 'Disbro', + 'Facchini', + 'Hoefle', + 'Hoepner', + 'Kimmes', + 'Korus', + 'Manfredonia', + 'Neuser', + 'Samarin', + 'Sanghera', + 'Sherburn', + 'Shiplett', + 'Steckelberg', + 'Faist', + 'Cardy', + 'Colan', + 'Goodbar', + 'Boro', + 'Moden', + 'Hardick', + 'Esteve', + 'Rawling', + 'Benet', + 'Nabers', + 'Atkerson', + 'Countess', + 'Thwaites', + 'Caroline', + 'Whisonant', + 'Alridge', + 'Pamphile', + 'Abdelnour', + 'Allebach', + 'Armenti', + 'Baudendistel', + 'Biers', + 'Bockrath', + 'Borgert', + 'Bovino', + 'Burgamy', + 'Cadiente', + 'Calabretta', + 'Cariveau', + 'Christoffel', + 'Daigler', + 'Dannels', + 'Darnold', + 'Decock', + 'Dominski', + 'Fest', + 'Forren', + 'Freise', + 'Galperin', + 'Hackbart', + 'Holtzer', + 'Idell', + 'Kapala', + 'Kohlenberg', + 'Kolton', + 'Lemburg', + 'Lievanos', + 'Maranan', + 'Marchitto', + 'Masini', + 'Mayabb', + 'Mccrossen', + 'Metrick', + 'Molinelli', + 'Oehlert', + 'Parlee', + 'Pizzini', + 'Polachek', + 'Salmans', + 'Selbe', + 'Sickman', + 'Stegmaier', + 'Sulek', + 'Thall', + 'Tiznado', + 'Tonini', + 'Trostel', + 'Warshawsky', + 'Aument', + 'Byrer', + 'Dechaine', + 'Fearnow', + 'Gallicchio', + 'Gertler', + 'Greubel', + 'Hironaka', + 'Kashner', + 'Kleffner', + 'Korthals', + 'Kundinger', + 'Lenger', + 'Lingafelter', + 'Luczynski', + 'Ostermeier', + 'Petrasek', + 'Righetti', + 'Tvedt', + 'Weindel', + 'Wurtzel', + 'Zumbro', + 'Wikel', + 'Burdi', + 'Ozturk', + 'Parmele', + 'Oteri', + 'Alexa', + 'Erven', + 'Keng', + 'Fare', + 'Sade', + 'Saw', + 'Jaquay', + 'Pillay', + 'Kearsley', + 'Kirkby', + 'Game', + 'Herst', + 'Vallie', + 'Bayon', + 'Whitler', + 'Pe', + 'Lockerman', + 'Cogle', + 'Rouzer', + 'Curling', + 'Mandley', + 'Kleckley', + 'Buckson', + 'Risby', + 'Averhart', + 'Almendariz', + 'Angelopoulos', + 'Brallier', + 'Decaire', + 'Deloria', + 'Derham', + 'Drudge', + 'Eckelberry', + 'Ehling', + 'Engebretsen', + 'Ercole', + 'Fiscal', + 'Gabino', + 'Gelvin', + 'Giannetto', + 'Godeaux', + 'Goshert', + 'Hedrich', + 'Ioannou', + 'Jungbluth', + 'Kia', + 'Krusemark', + 'Lader', + 'Lythgoe', + 'Malinak', + 'Mcinvale', + 'Melis', + 'Metsker', + 'Minasyan', + 'Nuhfer', + 'Omana', + 'Parco', + 'Pha', + 'Phanthavong', + 'Proa', + 'Sarli', + 'Schirtzinger', + 'Schlotter', + 'Sharrar', + 'Spielberg', + 'Stelzner', + 'Tschudy', + 'Utke', + 'Weipert', + 'Yera', + 'Berkemeier', + 'Bothun', + 'Dalporto', + 'Deschler', + 'Dragonetti', + 'Hasz', + 'Holtzinger', + 'Kallal', + 'Kesinger', + 'Kilfoyle', + 'Kobylinski', + 'Kramme', + 'Kreh', + 'Lindseth', + 'Plaugher', + 'Rehfeldt', + 'Repine', + 'Roudabush', + 'Swoveland', + 'Teper', + 'Tucek', + 'Wadding', + 'Wenzlick', + 'Ghobrial', + 'Golberg', + 'Soyka', + 'Matura', + 'Moras', + 'Natter', + 'Apps', + 'Imran', + 'Rossel', + 'Harne', + 'Les', + 'Silla', + 'Deblanc', + 'Rhinehardt', + 'Delaware', + 'Alkins', + 'Laidley', + 'Maree', + 'Cassells', + 'Abdulrahman', + 'Cange', + 'Devone', + 'Eustache', + 'Negash', + 'Tanks', + 'Sivels', + 'Cabbagestalk', + 'Ahlin', + 'Akard', + 'Barbaree', + 'Bielat', + 'Bressman', + 'Capurro', + 'Cortazar', + 'Dauphinee', + 'Dornak', + 'Eckl', + 'Eisenhuth', + 'Fazzini', + 'Fraim', + 'Glaab', + 'Glod', + 'Guedea', + 'Hearty', + 'Hinostroza', + 'Honold', + 'Jostes', + 'Korzeniewski', + 'Lobell', + 'Lopardo', + 'Middlekauff', + 'Monfils', + 'Oshana', + 'Schiappa', + 'Schubach', + 'Servantez', + 'Shaler', + 'Siverson', + 'Slimp', + 'Slovacek', + 'Staat', + 'Strassman', + 'Waffle', + 'Wuebker', + 'Beigel', + 'Berardo', + 'Berkery', + 'Bloyer', + 'Cronkright', + 'Cuautle', + 'Devenny', + 'Ghrist', + 'Gipple', + 'Gwilliam', + 'Hunzeker', + 'Ierardi', + 'Kathol', + 'Kienle', + 'Krack', + 'Loeper', + 'Minchey', + 'Pecht', + 'Schaberg', + 'Schollmeyer', + 'Siniscalchi', + 'Toback', + 'Tramp', + 'Vandaele', + 'Witzig', + 'Wivell', + 'Moros', + 'Saso', + 'Gares', + 'Heagle', + 'Murrillo', + 'Stankey', + 'Shamon', + 'Avram', + 'Achor', + 'Ovens', + 'Rames', + 'Perris', + 'Kernes', + 'Semmes', + 'Thaw', + 'Stevison', + 'Clemetson', + 'Belmar', + 'Guster', + 'Bascomb', + 'Adrien', + 'Jeanpaul', + 'Alabi', + 'Jallow', + 'Atamian', + 'Basque', + 'Bubier', + 'Casad', + 'Czekaj', + 'Dejoy', + 'Dulworth', + 'Fatula', + 'Favale', + 'Feutz', + 'Freundlich', + 'Frid', + 'Gagan', + 'Gaughran', + 'Guderian', + 'Hagemeister', + 'Haser', + 'Leibman', + 'Meddings', + 'Narlock', + 'Offenberger', + 'Pesa', + 'Poupard', + 'Raus', + 'Repetti', + 'Revello', + 'Robarts', + 'Rowin', + 'Saltarelli', + 'Sanghvi', + 'Schleyer', + 'Silba', + 'Steuck', + 'Stoffers', + 'Tangredi', + 'Taussig', + 'Tiso', + 'Wehmeier', + 'Zwiefelhofer', + 'Bartelson', + 'Brabender', + 'Cornfield', + 'Davtyan', + 'Delnero', + 'Frontino', + 'Gathman', + 'Graessle', + 'Hinchcliff', + 'Houdeshell', + 'Kapler', + 'Karabin', + 'Kerestes', + 'Lemmen', + 'Merkt', + 'Mitro', + 'Nahm', + 'Nancarrow', + 'Novakowski', + 'Parraz', + 'Revolorio', + 'Schamel', + 'Scowden', + 'Steever', + 'Suastegui', + 'Villarin', + 'Wuellner', + 'Dooly', + 'Erno', + 'Arbelo', + 'Groshek', + 'Boliver', + 'Gane', + 'Bees', + 'Dowds', + 'Newmann', + 'Kewley', + 'Stile', + 'Lobe', + 'Skeet', + 'Burgen', + 'Mckamie', + 'Hubanks', + 'Suleman', + 'Billey', + 'Efferson', + 'Mcleary', + 'Housen', + 'Shambley', + 'Fanfan', + 'Bacca', + 'Battaglini', + 'Bonfanti', + 'Bongers', + 'Butzin', + 'Caira', + 'Councilman', + 'Crounse', + 'Dadisman', + 'Donais', + 'Estabrooks', + 'Fornoff', + 'Froh', + 'Gaige', + 'Garofolo', + 'Grivas', + 'Jacuinde', + 'Kalmus', + 'Kientz', + 'Kostenko', + 'Kras', + 'Lagoy', + 'Larzelere', + 'Lizer', + 'Maric', + 'Mayette', + 'Mcfeeters', + 'Meadowcroft', + 'Newgent', + 'Parpart', + 'Pauwels', + 'Perriello', + 'Persichetti', + 'Proietti', + 'Siefring', + 'Simones', + 'Taliercio', + 'Thilges', + 'Thumann', + 'Thun', + 'Tuomi', + 'Uhde', + 'Umscheid', + 'Uran', + 'Velador', + 'Veltkamp', + 'Waddoups', + 'Yeley', + 'Bihn', + 'Bladow', + 'Boeh', + 'Chadderdon', + 'Ensing', + 'Fasbender', + 'Folkert', + 'Goellner', + 'Heitmeyer', + 'Iovine', + 'Klinke', + 'Nessel', + 'Perleberg', + 'Rajagopal', + 'Sackmann', + 'Sapio', + 'Schickling', + 'Schliep', + 'Siminski', + 'Sirrine', + 'Sporn', + 'Stockburger', + 'Tangonan', + 'Tarkowski', + 'Tartaglione', + 'Traum', + 'Vanoverbeke', + 'Weirauch', + 'Wellendorf', + 'Wonnacott', + 'Camplin', + 'Leth', + 'Meltz', + 'Cavero', + 'Florido', + 'Tremont', + 'Riviello', + 'Piotter', + 'Munce', + 'Trescott', + 'Eben', + 'Vaillant', + 'Furches', + 'Bazen', + 'Esse', + 'Losier', + 'Zahir', + 'Lazier', + 'Lightell', + 'Christal', + 'Behe', + 'Blayney', + 'Buchalter', + 'Demarsh', + 'Dhondt', + 'Diefendorf', + 'Dillavou', + 'Dombkowski', + 'Duchow', + 'Fettes', + 'Gallaga', + 'Gallet', + 'Haaf', + 'Hartinger', + 'Jech', + 'Klas', + 'Kostal', + 'Kubler', + 'Leisey', + 'Leisinger', + 'Marinas', + 'Mcpeck', + 'Miccio', + 'Mikkola', + 'Morath', + 'Olthoff', + 'Pacific', + 'Penado', + 'Petronio', + 'Pirani', + 'Pitones', + 'Pociask', + 'Ratay', + 'Riesberg', + 'Ruberto', + 'Sabet', + 'Sabic', + 'Simonich', + 'Skains', + 'Skarzynski', + 'Spreeman', + 'Steig', + 'Struckhoff', + 'Trolinger', + 'Uliano', + 'Vaquerano', + 'Zukas', + 'Zwahlen', + 'Amborn', + 'Amspacher', + 'Azzaro', + 'Bartoletti', + 'Berkstresser', + 'Buboltz', + 'Ekstein', + 'Fohl', + 'Heinzel', + 'Hellmer', + 'Kapfer', + 'Kurka', + 'Mccreless', + 'Miyahira', + 'Nebergall', + 'Orlosky', + 'Pajor', + 'Quartararo', + 'Rahilly', + 'Rzasa', + 'Sabas', + 'Slutz', + 'Speros', + 'Stumpp', + 'Tamburo', + 'Tesler', + 'Tonkovich', + 'Urbieta', + 'Vallandingham', + 'Youngdahl', + 'Juliana', + 'Rienstra', + 'Prideaux', + 'Coval', + 'Hausen', + 'Seith', + 'Ny', + 'Bian', + 'Gressman', + 'Yanick', + 'Mannina', + 'Nater', + 'Gurry', + 'Vaile', + 'Sortor', + 'Woodington', + 'Apollo', + 'Mozley', + 'Patience', + 'Hearron', + 'Milloy', + 'Huntsberry', + 'Polidore', + 'Ridges', + 'Bonton', + 'Mercadel', + 'Alikhan', + 'Antis', + 'Bartosiewicz', + 'Brems', + 'Clopper', + 'Colato', + 'Collver', + 'Daino', + 'Degrande', + 'Dellis', + 'Depner', + 'Disantis', + 'Dolecki', + 'Dollens', + 'Eliasen', + 'Fasig', + 'Favinger', + 'Furuta', + 'Gharibian', + 'Gombar', + 'Gordo', + 'Gornik', + 'Gulas', + 'Khoshaba', + 'Laurita', + 'Liby', + 'Linhardt', + 'Lookabaugh', + 'Lorincz', + 'Mautner', + 'Mcquigg', + 'Meine', + 'Melaragno', + 'Meroney', + 'Mikesh', + 'Miu', + 'Monasterio', + 'Navarete', + 'Orendain', + 'Puricelli', + 'Riede', + 'Rubis', + 'Sandness', + 'Schellhase', + 'Stehlin', + 'Sunder', + 'Teaney', + 'Terman', + 'Tith', + 'Totino', + 'Tudisco', + 'Urwin', + 'Vandrunen', + 'Vasicek', + 'Youtz', + 'Berwald', + 'Bilow', + 'Bubolz', + 'Cieslewicz', + 'Denbleyker', + 'Ensinger', + 'Gantenbein', + 'Gurnsey', + 'Herceg', + 'Kless', + 'Kollias', + 'Leppek', + 'Naeve', + 'Oncale', + 'Pastran', + 'Pinyan', + 'Porrata', + 'Pustejovsky', + 'Renko', + 'Scioli', + 'Sinkhorn', + 'Sporrer', + 'Tomkiewicz', + 'Weisbeck', + 'Gautam', + 'Gleed', + 'Shave', + 'Crotzer', + 'Demarr', + 'Reckard', + 'Coyt', + 'Norberto', + 'Ury', + 'Crispen', + 'Parcells', + 'Meiklejohn', + 'Risden', + 'Bracker', + 'Askari', + 'Hyneman', + 'Auberry', + 'Bruney', + 'Weakly', + 'Ysaguirre', + 'Calender', + 'Benison', + 'Nazaire', + 'Pondexter', + 'Fryson', + 'Aguino', + 'Antonino', + 'Babilonia', + 'Banfill', + 'Beger', + 'Berardino', + 'Bizub', + 'Contractor', + 'Convey', + 'Cossairt', + 'Cruzen', + 'Dible', + 'Dorning', + 'Ellena', + 'Fafard', + 'Fano', + 'Favaro', + 'Feeler', + 'Foulger', + 'Gulbrandson', + 'Heckaman', + 'Heimerman', + 'Herms', + 'Hotchkin', + 'Jinright', + 'Kisler', + 'Kontz', + 'Kryder', + 'Lopezperez', + 'Lumm', + 'Mcelravy', + 'Meditz', + 'Melucci', + 'Meras', + 'Miyahara', + 'Musella', + 'Nelis', + 'Nhem', + 'Olivan', + 'Popson', + 'Presgraves', + 'Reindel', + 'Riege', + 'Rivenburgh', + 'Sahl', + 'Selberg', + 'Tashiro', + 'Todorov', + 'Toutant', + 'Turski', + 'Vankuren', + 'Westrup', + 'Beeney', + 'Bickhart', + 'Borkenhagen', + 'Bukoski', + 'Citrin', + 'Civello', + 'Forstrom', + 'Froning', + 'Geiler', + 'Hargadon', + 'Hemric', + 'Jeffus', + 'Klingele', + 'Kooiker', + 'Lizalde', + 'Nardiello', + 'Pestka', + 'Pignato', + 'Pudwill', + 'Rabelo', + 'Remund', + 'Skluzacek', + 'Stegenga', + 'Steidle', + 'Stenz', + 'Terlecki', + 'Vanselow', + 'Waskey', + 'Azhar', + 'Wroe', + 'Tool', + 'Leibert', + 'Vary', + 'Scovell', + 'Derick', + 'Arrey', + 'Cavness', + 'Garley', + 'Sholtz', + 'Legard', + 'Heyliger', + 'Thorns', + 'Sowells', + 'Alemu', + 'Aragones', + 'Ayllon', + 'Baab', + 'Blankenbeckler', + 'Brengle', + 'Burick', + 'Deuser', + 'Disabato', + 'Doddridge', + 'Dolinski', + 'Economy', + 'Ems', + 'Hagenow', + 'Iwen', + 'Kiesler', + 'Lehrmann', + 'Loisel', + 'Mallicoat', + 'Mansouri', + 'Marse', + 'Mccartt', + 'Menninger', + 'Montee', + 'Nappa', + 'Ohanesian', + 'Podgurski', + 'Prosch', + 'Puder', + 'Ritthaler', + 'Rodelo', + 'Shipper', + 'Shorkey', + 'Sirna', + 'Smedberg', + 'Smink', + 'Strahle', + 'Troeger', + 'Twaddell', + 'Vandyk', + 'Wandrey', + 'Yaworski', + 'Zagami', + 'Duecker', + 'Finlinson', + 'Frysinger', + 'Grush', + 'Knackstedt', + 'Morozov', + 'Murgia', + 'Naffziger', + 'Ontko', + 'Piltz', + 'Roskelley', + 'Sonderman', + 'Garrand', + 'Kopack', + 'Theys', + 'Sanseverino', + 'Budai', + 'Selwyn', + 'Assante', + 'Nary', + 'Fildes', + 'Tano', + 'Hogen', + 'Gennett', + 'Melka', + 'Thorner', + 'Grandjean', + 'Dury', + 'Gerrald', + 'Quilling', + 'Mccallon', + 'Preister', + 'Kydd', + 'Cranshaw', + 'Folson', + 'Roker', + 'Dockett', + 'Stfort', + 'Haymer', + 'Njie', + 'Adamik', + 'Aredondo', + 'Bathrick', + 'Beldin', + 'Blackwater', + 'Branscom', + 'Cappucci', + 'Cartelli', + 'Carullo', + 'Cunneen', + 'Davee', + 'Deboy', + 'Defrates', + 'Esham', + 'Furio', + 'Garverick', + 'Gimlin', + 'Gosline', + 'Gromer', + 'Halbig', + 'Hasbrook', + 'Holgerson', + 'Hupfer', + 'Jochem', + 'Kihn', + 'Klotzbach', + 'Lantagne', + 'Leichter', + 'Lerette', + 'Lupu', + 'Machorro', + 'Mieles', + 'Mikulec', + 'Mirante', + 'Nasrallah', + 'Piccini', + 'Pinkhasov', + 'Poplaski', + 'Pottenger', + 'Rahrig', + 'Ranganathan', + 'Ravan', + 'Righi', + 'Rogacki', + 'Sadlon', + 'Salafia', + 'Schlitz', + 'Slayback', + 'Stetzel', + 'Tamargo', + 'Tenore', + 'Verkuilen', + 'Vuncannon', + 'Waggle', + 'Bacorn', + 'Boerema', + 'Cimorelli', + 'Ciresi', + 'Dethlefs', + 'Dimarzo', + 'Ficco', + 'Floresca', + 'Gnau', + 'Hefel', + 'Holbein', + 'Klepacki', + 'Konigsberg', + 'Lienau', + 'Malsam', + 'Meidl', + 'Nawabi', + 'Netzley', + 'Renbarger', + 'Rumbold', + 'Sarafian', + 'Sonnenfeld', + 'Tindol', + 'Trettin', + 'Tuckerman', + 'Vanderweele', + 'Weppler', + 'Westbay', + 'Zaveri', + 'Boran', + 'Deighan', + 'Rothery', + 'Yom', + 'Gatley', + 'Caldron', + 'Lucado', + 'Dromgoole', + 'Novell', + 'Sherriff', + 'Gerrick', + 'Balgobin', + 'Danger', + 'Sookram', + 'Daron', + 'Knibbs', + 'Faggart', + 'Beidleman', + 'Russey', + 'Lagrand', + 'Bluett', + 'Glaspy', + 'Baldon', + 'Trueheart', + 'Cradle', + 'Asfaw', + 'Ballinas', + 'Bogdon', + 'Brizzi', + 'Carrio', + 'Cherny', + 'Crogan', + 'Depierro', + 'Dhami', + 'Dresden', + 'Finnicum', + 'Geltz', + 'Granade', + 'Granieri', + 'Guia', + 'Hashagen', + 'Hollick', + 'Jicha', + 'Jollie', + 'Kathan', + 'Malara', + 'Manabat', + 'Mehall', + 'Midcap', + 'Mitre', + 'Newburg', + 'Parveen', + 'Pianka', + 'Plouff', + 'Posillico', + 'Ransier', + 'Reano', + 'Roskam', + 'Rufer', + 'Schnetzer', + 'Scorsone', + 'Sitterly', + 'Skilton', + 'Sohail', + 'Starin', + 'Stavish', + 'Tufaro', + 'Vano', + 'Vinsant', + 'Vlahakis', + 'Vondrasek', + 'Waldroop', + 'Wamboldt', + 'Achatz', + 'Bomkamp', + 'Fetzner', + 'Gemmer', + 'Haroutunian', + 'Hurtig', + 'Juncaj', + 'Kleban', + 'Knier', + 'Kopischke', + 'Kugelman', + 'Lacoss', + 'Meulemans', + 'Neyens', + 'Niccoli', + 'Oberhaus', + 'Penkala', + 'Podoll', + 'Roupp', + 'Scozzari', + 'Siverling', + 'Uhls', + 'Werber', + 'Grealish', + 'Montieth', + 'Haik', + 'Kuri', + 'Kanaan', + 'Prenatt', + 'Dingledine', + 'Mccamy', + 'Balin', + 'Droney', + 'Clyatt', + 'Ramone', + 'Anglen', + 'Mathus', + 'Bagent', + 'Lamarque', + 'Arscott', + 'Romes', + 'Speigner', + 'Latouche', + 'Tripplett', + 'Eversley', + 'Aquirre', + 'Bernales', + 'Bouthillier', + 'Cavendish', + 'Detienne', + 'Dewbre', + 'Dimuro', + 'Dosh', + 'Dunklee', + 'Duyck', + 'Emilio', + 'Ence', + 'Garofano', + 'Gellis', + 'Haertel', + 'Handyside', + 'Hornburg', + 'Jenniges', + 'Kallhoff', + 'Klontz', + 'Langsdorf', + 'Leabo', + 'Lorette', + 'Maracle', + 'Merta', + 'Muoio', + 'Nierenberg', + 'Oborn', + 'Osorto', + 'Ruscitti', + 'Santaella', + 'Spinnato', + 'Stentz', + 'Stocke', + 'Sundt', + 'Thorup', + 'Tresch', + 'Urdaneta', + 'Uttech', + 'Vosler', + 'Wieand', + 'Zacharia', + 'Zeleznik', + 'Zoucha', + 'Zuch', + 'Abrell', + 'Atiyeh', + 'Aydt', + 'Cleeton', + 'Crisan', + 'Cwikla', + 'Denz', + 'Diesing', + 'Emmi', + 'Fringer', + 'Gibbard', + 'Graunke', + 'Gschwind', + 'Hafele', + 'Hoogland', + 'Howsare', + 'Kesecker', + 'Kilgallon', + 'Kleyman', + 'Kufahl', + 'Laut', + 'Malstrom', + 'Michetti', + 'Nosbisch', + 'Rasner', + 'Rosekrans', + 'Schnebly', + 'Staebell', + 'Theilen', + 'Tieszen', + 'Mellone', + 'Burcher', + 'Feister', + 'Hoage', + 'Irmen', + 'Derwin', + 'Dien', + 'Markins', + 'Egnew', + 'Dunlow', + 'Brickel', + 'Curt', + 'Smyly', + 'Whedbee', + 'Larman', + 'Boisselle', + 'Jaquess', + 'Bowns', + 'Nile', + 'Boyson', + 'Phillipps', + 'Weech', + 'Pillars', + 'Cauldwell', + 'Wynns', + 'Toca', + 'Scorza', + 'Ramsaran', + 'Arkwright', + 'Gurganious', + 'Jubert', + 'Beed', + 'Kellem', + 'Gervin', + 'Yarn', + 'Bookhart', + 'Sullen', + 'Moncrieffe', + 'Eze', + 'Agyeman', + 'Aldea', + 'Amodei', + 'Attig', + 'Bergthold', + 'Blaskowski', + 'Blitzer', + 'Bowring', + 'Brenning', + 'Chappuis', + 'Cordasco', + 'Cosens', + 'Denoble', + 'Dochterman', + 'Domek', + 'Embleton', + 'Georgiades', + 'Gintz', + 'Grooters', + 'Hoell', + 'Honse', + 'Jagiello', + 'Jaskulski', + 'Kaluzny', + 'Keske', + 'Khiev', + 'Koeneman', + 'Majestic', + 'Mandile', + 'Marandola', + 'Mcinroy', + 'Nienhaus', + 'Peckenpaugh', + 'Raquel', + 'Rossler', + 'Rusconi', + 'Schaffert', + 'Schipani', + 'Sittner', + 'Sweezey', + 'Swenor', + 'Tagliaferro', + 'Tubby', + 'Ulep', + 'Vallette', + 'Westergren', + 'Yaros', + 'Yasui', + 'Anway', + 'Bannick', + 'Biasi', + 'Breitling', + 'Catarino', + 'Dunaj', + 'Giovanelli', + 'Hemmerich', + 'Iott', + 'Knotek', + 'Kraeger', + 'Laskaris', + 'Lomboy', + 'Oleski', + 'Reibel', + 'Rightmyer', + 'Salmela', + 'Salow', + 'Siebels', + 'Spielvogel', + 'Streitmatter', + 'Ucci', + 'Windmiller', + 'Wojtkiewicz', + 'Zirkel', + 'Markie', + 'Nedeau', + 'Froehle', + 'Jesson', + 'Regala', + 'Boody', + 'Hayen', + 'Ose', + 'Loewy', + 'Radliff', + 'Davia', + 'Sky', + 'Halker', + 'Alu', + 'Ey', + 'Badawi', + 'Yeargain', + 'Jeanette', + 'Doublin', + 'Nolton', + 'Streety', + 'Blueford', + 'Abeles', + 'Aldava', + 'Alsteen', + 'Altadonna', + 'Apa', + 'Behlke', + 'Bellisario', + 'Bienstock', + 'Brenan', + 'Capley', + 'Castoro', + 'Demir', + 'Evinger', + 'Gartside', + 'Gellatly', + 'Goldinger', + 'Grabel', + 'Henkin', + 'Herrle', + 'Honegger', + 'Kunin', + 'Larmer', + 'Lizano', + 'Lorino', + 'Malcomson', + 'Matesic', + 'Mathiasen', + 'Mccolm', + 'Meenach', + 'Mullady', + 'Neiderer', + 'Ogier', + 'Omura', + 'Plog', + 'Pomplun', + 'Procida', + 'Raisbeck', + 'Rastetter', + 'Reither', + 'Rettberg', + 'Roblee', + 'Rossitto', + 'Scahill', + 'Schmoker', + 'Segreto', + 'Shelstad', + 'Shwartz', + 'Sondgeroth', + 'Supnet', + 'Swartzbaugh', + 'Tkachenko', + 'Urbani', + 'Vanslooten', + 'Varricchio', + 'Villarino', + 'Whiston', + 'Wyffels', + 'Yehle', + 'Basinski', + 'Belvedere', + 'Bernabei', + 'Bolotin', + 'Bresett', + 'Dabkowski', + 'Dalsanto', + 'Gotwalt', + 'Hellberg', + 'Hunke', + 'Kroenke', + 'Leppla', + 'Luginbuhl', + 'Mimnaugh', + 'Mullenbach', + 'Nearhood', + 'Raser', + 'Resendis', + 'Seydel', + 'Sozio', + 'Stillions', + 'Stormont', + 'Strimple', + 'Toruno', + 'Trouten', + 'Tryba', + 'Vandalen', + 'Wilhelmy', + 'Orland', + 'Loui', + 'Morcos', + 'Radell', + 'Artus', + 'Truxillo', + 'Copelan', + 'Bress', + 'Unthank', + 'Sudlow', + 'Branden', + 'Rowzee', + 'Montreuil', + 'Sollers', + 'Umar', + 'Coulibaly', + 'Allegretto', + 'Andreen', + 'Bielicki', + 'Bustard', + 'Cardosi', + 'Carkhuff', + 'Cetina', + 'Clouthier', + 'Dolata', + 'Fiola', + 'Fjeld', + 'Gawthrop', + 'Glastetter', + 'Hamlyn', + 'Hanten', + 'Huerter', + 'Kreiss', + 'Lestrange', + 'Litzau', + 'Luberto', + 'Menconi', + 'Milosevic', + 'Munera', + 'Nachtigal', + 'Nethers', + 'Nicolaou', + 'Olund', + 'Paddack', + 'Pfiester', + 'Pilley', + 'Polendo', + 'Porcayo', + 'Preast', + 'Runquist', + 'Saccente', + 'Santoli', + 'Saragoza', + 'Selway', + 'Smestad', + 'Stebner', + 'Toben', + 'Trapnell', + 'Urschel', + 'Verno', + 'Vidovich', + 'Walterscheid', + 'Yoh', + 'Zmijewski', + 'Allwein', + 'Bessire', + 'Broering', + 'Budzik', + 'Denherder', + 'Goerner', + 'Goldbaum', + 'Grussing', + 'Huaracha', + 'Ippoliti', + 'Kanak', + 'Kaucher', + 'Kious', + 'Kirkner', + 'Kratzke', + 'Kubisiak', + 'Kueny', + 'Mazzilli', + 'Mazzo', + 'Mcclenathan', + 'Mehlberg', + 'Miotke', + 'Nihiser', + 'Olheiser', + 'Oravetz', + 'Radwanski', + 'Shinsato', + 'Vandekamp', + 'Zagata', + 'Abert', + 'Llera', + 'Thommen', + 'Wirkkala', + 'Brasuell', + 'Shawler', + 'Mourey', + 'Gavia', + 'Morgano', + 'Newill', + 'Rathel', + 'Wist', + 'Braner', + 'Soman', + 'Koskey', + 'Searson', + 'Brocksmith', + 'Peale', + 'Couzens', + 'Shall', + 'Anis', + 'Stanly', + 'Cauthorn', + 'Kinkle', + 'Laughinghouse', + 'Mellette', + 'Rox', + 'Demetrius', + 'Cullars', + 'Summons', + 'Banwart', + 'Bartl', + 'Bebb', + 'Bobier', + 'Bogdanoff', + 'Bollmann', + 'Borrowman', + 'Borseth', + 'Buttitta', + 'Canelo', + 'Cassedy', + 'Cata', + 'Crivelli', + 'Daane', + 'Dhingra', + 'Dipple', + 'Dovidio', + 'Duesler', + 'Eissler', + 'Ent', + 'Falotico', + 'Goodrick', + 'Goupil', + 'Huels', + 'Keithly', + 'Killilea', + 'Klausing', + 'Kludt', + 'Licitra', + 'Llerenas', + 'Merolla', + 'Oatley', + 'Osmanovic', + 'Poudrier', + 'Raben', + 'Realmuto', + 'Reczek', + 'Ricchio', + 'Rossner', + 'Rozak', + 'Sandora', + 'Schuenemann', + 'Seres', + 'Shoptaw', + 'Splitt', + 'Tonkinson', + 'Willardson', + 'Winterberg', + 'Zayac', + 'Bobzien', + 'Buhman', + 'Carotenuto', + 'Chynoweth', + 'Defenbaugh', + 'Dipiero', + 'Duve', + 'Goonan', + 'Gragert', + 'Hangartner', + 'Heemstra', + 'Hensch', + 'Hollatz', + 'Jakubowicz', + 'Kapaun', + 'Kiener', + 'Landesman', + 'Lenzini', + 'Longbottom', + 'Parde', + 'Pincock', + 'Schlicker', + 'Shankel', + 'Vidas', + 'Waisner', + 'Zilberman', + 'Allcock', + 'Durban', + 'Javid', + 'Shoda', + 'Edes', + 'Boxwell', + 'Dezern', + 'Rubley', + 'Angelica', + 'Jeannette', + 'Planer', + 'Pata', + 'Lothridge', + 'Lucks', + 'Bais', + 'Sandra', + 'Enwright', + 'Maxton', + 'Radway', + 'Hoof', + 'Morisset', + 'Danzey', + 'Ancar', + 'Mcwright', + 'Leggs', + 'Monestime', + 'Massaquoi', + 'Barkow', + 'Bastyr', + 'Bautz', + 'Behanna', + 'Bewick', + 'Bezdek', + 'Bielby', + 'Bretschneider', + 'Bugher', + 'Carchi', + 'Chapp', + 'Conser', + 'Crete', + 'Derflinger', + 'Elsbernd', + 'Freimark', + 'Gerwin', + 'Grunfeld', + 'Harpham', + 'Hoeschen', + 'Holmlund', + 'Horch', + 'Hulsebus', + 'Kassabian', + 'Konczal', + 'Korell', + 'Lacuesta', + 'Lantier', + 'Larowe', + 'Lietzke', + 'Lunny', + 'Masin', + 'Massicotte', + 'Michalsky', + 'Notarianni', + 'Pautsch', + 'Poppy', + 'Sukup', + 'Suleski', + 'Tafel', + 'Wanninger', + 'Zaffino', + 'Zody', + 'Arganbright', + 'Bohmer', + 'Cintora', + 'Connatser', + 'Dlugos', + 'Fariello', + 'Fedie', + 'Felicetti', + 'Garno', + 'Gottsch', + 'Gratzer', + 'Gubser', + 'Kappelman', + 'Kuechle', + 'Laningham', + 'Latsch', + 'Longie', + 'Luscher', + 'Lybeck', + 'Rhude', + 'Setterlund', + 'Sobh', + 'Sonneborn', + 'Villamizar', + 'Wolstenholme', + 'Zacek', + 'Leppanen', + 'Casdorph', + 'Pinsker', + 'Reutov', + 'Rede', + 'Sheck', + 'Bakley', + 'Radde', + 'Moher', + 'Khader', + 'Rossie', + 'Scriver', + 'Provine', + 'Debarge', + 'Darke', + 'Griswell', + 'Naji', + 'Frere', + 'Cheevers', + 'Schnyder', + 'Curb', + 'Luten', + 'Cashaw', + 'Agerton', + 'Barnier', + 'Bluestone', + 'Boward', + 'Boyar', + 'Briano', + 'Bryngelson', + 'Calef', + 'Caraher', + 'Castelluccio', + 'Conk', + 'Crewse', + 'Demarzo', + 'Deutschman', + 'Eckrote', + 'Edmister', + 'Ferg', + 'Ghan', + 'Giampaolo', + 'Goedecke', + 'Gonet', + 'Gradel', + 'Gregston', + 'Grzesiak', + 'Guallpa', + 'Hanline', + 'Hardyman', + 'Hogate', + 'Houg', + 'Justiss', + 'Kaps', + 'Klopf', + 'Kniskern', + 'Laneve', + 'Lenhoff', + 'Lojewski', + 'Melott', + 'Milillo', + 'Passage', + 'Pereyda', + 'Plack', + 'Poet', + 'Prospero', + 'Quadros', + 'Revelo', + 'Rogier', + 'Sanabia', + 'Tragesser', + 'Vanarsdall', + 'Vanausdal', + 'Verbrugge', + 'Wandler', + 'Zoss', + 'Balzarini', + 'Brotz', + 'Bulin', + 'Bumann', + 'Cancro', + 'Centner', + 'Deblasi', + 'Duesing', + 'Friedley', + 'Frieling', + 'Heinke', + 'Holzheimer', + 'Klinck', + 'Knouff', + 'Kuczek', + 'Leible', + 'Lerum', + 'Liddicoat', + 'Mikowski', + 'Nonaka', + 'Ohlman', + 'Picaso', + 'Plamann', + 'Porretta', + 'Prajapati', + 'Rancour', + 'Stepka', + 'Studzinski', + 'Vaysman', + 'Wallenstein', + 'Wunderlin', + 'Pattinson', + 'Siskind', + 'Sitzer', + 'Thuman', + 'Barella', + 'Brillon', + 'Arnholt', + 'Karge', + 'Dohman', + 'Morone', + 'Macie', + 'Aken', + 'Lye', + 'Student', + 'Westen', + 'Bonsell', + 'Komara', + 'Hafiz', + 'Stickland', + 'Morina', + 'Creekmur', + 'Hussien', + 'Walrond', + 'Louischarles', + 'Alkema', + 'Angert', + 'Arcidiacono', + 'Ashkar', + 'Bookbinder', + 'Bootz', + 'Cilia', + 'Devilla', + 'Difatta', + 'Enberg', + 'Enderby', + 'Forbess', + 'Frutiger', + 'Graefe', + 'Guenette', + 'Hauschildt', + 'Keirsey', + 'Kolka', + 'Kopelman', + 'Lewan', + 'Mcluckie', + 'Mia', + 'Moebius', + 'Oestreicher', + 'Oprea', + 'Ortolano', + 'Padovani', + 'Pensabene', + 'Phimmasone', + 'Pointon', + 'Punches', + 'Schertzer', + 'Seoane', + 'Skramstad', + 'Sorlie', + 'Syfert', + 'Tasca', + 'Townzen', + 'Wernli', + 'Wurzel', + 'Yazdi', + 'Devendorf', + 'Featherly', + 'Frush', + 'Heringer', + 'Iwai', + 'Kallenberger', + 'Kobashigawa', + 'Langbehn', + 'Livecchi', + 'Middlesworth', + 'Niess', + 'Osterlund', + 'Ruz', + 'Seiwert', + 'Vanwieren', + 'Wernet', + 'Grabbe', + 'Gaugh', + 'Mcclarren', + 'Raudales', + 'Urry', + 'Clere', + 'Lacer', + 'Mathia', + 'Mccrumb', + 'Cotrell', + 'Mannor', + 'Medine', + 'Tittsworth', + 'Hughston', + 'Buick', + 'Limes', + 'Hams', + 'Thagard', + 'Leavelle', +]; diff --git a/integration-tests/tests/seeder/mysql.test.ts b/integration-tests/tests/seeder/mysql.test.ts new file mode 100644 index 000000000..5ae7f9f15 --- /dev/null +++ b/integration-tests/tests/seeder/mysql.test.ts @@ -0,0 +1,490 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import type { MySql2Database } from 'drizzle-orm/mysql2'; +import { drizzle } from 'drizzle-orm/mysql2'; +import { reset, seed } from 'drizzle-seed'; +import getPort from 'get-port'; +import type { Connection } from 'mysql2/promise'; +import { createConnection } from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import * as schema from './mysqlSchema.ts'; + +let mysqlContainer: Docker.Container; +let client: Connection; +let db: MySql2Database; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +const createNorthwindTables = async () => { + await db.execute( + sql` + CREATE TABLE \`customer\` ( + \`id\` varchar(256) NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text, + \`region\` text, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + \`fax\` text, + CONSTRAINT \`customer_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`order_detail\` ( + \`unit_price\` float NOT NULL, + \`quantity\` int NOT NULL, + \`discount\` float NOT NULL, + \`order_id\` int NOT NULL, + \`product_id\` int NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`employee\` ( + \`id\` int NOT NULL, + \`last_name\` text NOT NULL, + \`first_name\` text, + \`title\` text NOT NULL, + \`title_of_courtesy\` text NOT NULL, + \`birth_date\` timestamp NOT NULL, + \`hire_date\` timestamp NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`home_phone\` text NOT NULL, + \`extension\` int NOT NULL, + \`notes\` text NOT NULL, + \`reports_to\` int, + \`photo_path\` text, + CONSTRAINT \`employee_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`order\` ( + \`id\` int NOT NULL, + \`order_date\` timestamp NOT NULL, + \`required_date\` timestamp NOT NULL, + \`shipped_date\` timestamp, + \`ship_via\` int NOT NULL, + \`freight\` float NOT NULL, + \`ship_name\` text NOT NULL, + \`ship_city\` text NOT NULL, + \`ship_region\` text, + \`ship_postal_code\` text, + \`ship_country\` text NOT NULL, + \`customer_id\` varchar(256) NOT NULL, + \`employee_id\` int NOT NULL, + CONSTRAINT \`order_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`product\` ( + \`id\` int NOT NULL, + \`name\` text NOT NULL, + \`quantity_per_unit\` text NOT NULL, + \`unit_price\` float NOT NULL, + \`units_in_stock\` int NOT NULL, + \`units_on_order\` int NOT NULL, + \`reorder_level\` int NOT NULL, + \`discontinued\` int NOT NULL, + \`supplier_id\` int NOT NULL, + CONSTRAINT \`product_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`supplier\` ( + \`id\` int NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`region\` text, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + CONSTRAINT \`supplier_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order_detail\` ADD CONSTRAINT \`order_detail_order_id_order_id_fk\` FOREIGN KEY (\`order_id\`) REFERENCES \`order\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order_detail\` ADD CONSTRAINT \`order_detail_product_id_product_id_fk\` FOREIGN KEY (\`product_id\`) REFERENCES \`product\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`employee\` ADD CONSTRAINT \`employee_reports_to_employee_id_fk\` FOREIGN KEY (\`reports_to\`) REFERENCES \`employee\`(\`id\`) ON DELETE no action ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order\` ADD CONSTRAINT \`order_customer_id_customer_id_fk\` FOREIGN KEY (\`customer_id\`) REFERENCES \`customer\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order\` ADD CONSTRAINT \`order_employee_id_employee_id_fk\` FOREIGN KEY (\`employee_id\`) REFERENCES \`employee\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`product\` ADD CONSTRAINT \`product_supplier_id_supplier_id_fk\` FOREIGN KEY (\`supplier_id\`) REFERENCES \`supplier\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); +}; + +const createAllDataTypesTable = async () => { + await db.execute( + sql` + CREATE TABLE \`all_data_types\` ( + \`integer\` int, + \`tinyint\` tinyint, + \`smallint\` smallint, + \`mediumint\` mediumint, + \`bigint\` bigint, + \`bigint_number\` bigint, + \`real\` real, + \`decimal\` decimal, + \`double\` double, + \`float\` float, + \`serial\` serial AUTO_INCREMENT, + \`binary\` binary(255), + \`varbinary\` varbinary(256), + \`char\` char(255), + \`varchar\` varchar(256), + \`text\` text, + \`boolean\` boolean, + \`date_string\` date, + \`date\` date, + \`datetime\` datetime, + \`datetimeString\` datetime, + \`time\` time, + \`year\` year, + \`timestamp_date\` timestamp, + \`timestamp_string\` timestamp, + \`json\` json, + \`popularity\` enum('unknown','known','popular') + ); + `, + ); +}; + +const createAllGeneratorsTables = async () => { + await db.execute( + sql` + CREATE TABLE \`datetime_table\` ( + \`datetime\` datetime + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`year_table\` ( + \`year\` year + ); + `, + ); +}; + +beforeAll(async () => { + const connectionString = await createDockerDB(); + + const sleep = 1000; + let timeLeft = 40000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + db = drizzle(client); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } + + await createNorthwindTables(); + await createAllDataTypesTable(); + await createAllGeneratorsTables(); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +// All data types test ------------------------------- +test('basic seed test for all mysql data types', async () => { + await seed(db, schema, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); + +// All generators test------------------------------- +const count = 10000; + +test('datetime generator test', async () => { + await seed(db, { datetimeTable: schema.datetimeTable }).refine((funcs) => ({ + datetimeTable: { + count, + columns: { + datetime: funcs.datetime(), + }, + }, + })); + + const data = await db.select().from(schema.datetimeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('year generator test', async () => { + await seed(db, { yearTable: schema.yearTable }).refine((funcs) => ({ + yearTable: { + count, + columns: { + year: funcs.year(), + }, + }, + })); + + const data = await db.select().from(schema.yearTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); diff --git a/integration-tests/tests/seeder/mysqlSchema.ts b/integration-tests/tests/seeder/mysqlSchema.ts new file mode 100644 index 000000000..2caa97fa0 --- /dev/null +++ b/integration-tests/tests/seeder/mysqlSchema.ts @@ -0,0 +1,167 @@ +import type { AnyMySqlColumn } from 'drizzle-orm/mysql-core'; +import { + bigint, + binary, + boolean, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + mysqlEnum, + mysqlTable, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, +} from 'drizzle-orm/mysql-core'; + +export const customers = mysqlTable('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = mysqlTable( + 'employee', + { + id: int('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: int('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: int('reports_to').references((): AnyMySqlColumn => employees.id), + photoPath: text('photo_path'), + }, +); + +export const orders = mysqlTable('order', { + id: int('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: int('ship_via').notNull(), + freight: float('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: varchar('customer_id', { length: 256 }) + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: int('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = mysqlTable('supplier', { + id: int('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = mysqlTable('product', { + id: int('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: float('unit_price').notNull(), + unitsInStock: int('units_in_stock').notNull(), + unitsOnOrder: int('units_on_order').notNull(), + reorderLevel: int('reorder_level').notNull(), + discontinued: int('discontinued').notNull(), + + supplierId: int('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = mysqlTable('order_detail', { + unitPrice: float('unit_price').notNull(), + quantity: int('quantity').notNull(), + discount: float('discount').notNull(), + + orderId: int('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: int('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); + +// All data types table ------------------------------- +export const allDataTypes = mysqlTable('all_data_types', { + int: int('integer'), + tinyint: tinyint('tinyint'), + smallint: smallint('smallint'), + mediumint: mediumint('mediumint'), + biginteger: bigint('bigint', { mode: 'bigint' }), + bigintNumber: bigint('bigint_number', { mode: 'number' }), + real: real('real'), + decimal: decimal('decimal'), + double: double('double'), + float: float('float'), + serial: serial('serial'), + binary: binary('binary', { length: 255 }), + varbinary: varbinary('varbinary', { length: 256 }), + char: char('char', { length: 255 }), + varchar: varchar('varchar', { length: 256 }), + text: text('text'), + boolean: boolean('boolean'), + dateString: date('date_string', { mode: 'string' }), + date: date('date', { mode: 'date' }), + datetime: datetime('datetime', { mode: 'date' }), + datetimeString: datetime('datetimeString', { mode: 'string' }), + time: time('time'), + year: year('year'), + timestampDate: timestamp('timestamp_date', { mode: 'date' }), + timestampString: timestamp('timestamp_string', { mode: 'string' }), + json: json('json'), + mysqlEnum: mysqlEnum('popularity', ['unknown', 'known', 'popular']), +}); + +// All generators tables ------------------------------- +export const datetimeTable = mysqlTable('datetime_table', { + datetime: datetime('datetime'), +}); + +export const yearTable = mysqlTable('year_table', { + year: year('year'), +}); diff --git a/integration-tests/tests/seeder/pg.test.ts b/integration-tests/tests/seeder/pg.test.ts new file mode 100644 index 000000000..d9cbca2e5 --- /dev/null +++ b/integration-tests/tests/seeder/pg.test.ts @@ -0,0 +1,1759 @@ +import { PGlite } from '@electric-sql/pglite'; +import { sql } from 'drizzle-orm'; +import type { PgliteDatabase } from 'drizzle-orm/pglite'; +import { drizzle } from 'drizzle-orm/pglite'; +import { reset, seed } from 'drizzle-seed'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import firstNames from './firstNames.ts'; +import lastNames from './lastNames.ts'; +import * as schema from './pgSchema.ts'; + +let client: PGlite; +let db: PgliteDatabase; + +const createNorthwindTables = async () => { + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."customer" ( + "id" varchar(256) PRIMARY KEY NOT NULL, + "company_name" text NOT NULL, + "contact_name" text NOT NULL, + "contact_title" text NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "postal_code" text, + "region" text, + "country" text NOT NULL, + "phone" text NOT NULL, + "fax" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."order_detail" ( + "unit_price" numeric NOT NULL, + "quantity" integer NOT NULL, + "discount" numeric NOT NULL, + "order_id" integer NOT NULL, + "product_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."employee" ( + "id" integer PRIMARY KEY NOT NULL, + "last_name" text NOT NULL, + "first_name" text, + "title" text NOT NULL, + "title_of_courtesy" text NOT NULL, + "birth_date" timestamp NOT NULL, + "hire_date" timestamp NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "postal_code" text NOT NULL, + "country" text NOT NULL, + "home_phone" text NOT NULL, + "extension" integer NOT NULL, + "notes" text NOT NULL, + "reports_to" integer, + "photo_path" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."order" ( + "id" integer PRIMARY KEY NOT NULL, + "order_date" timestamp NOT NULL, + "required_date" timestamp NOT NULL, + "shipped_date" timestamp, + "ship_via" integer NOT NULL, + "freight" numeric NOT NULL, + "ship_name" text NOT NULL, + "ship_city" text NOT NULL, + "ship_region" text, + "ship_postal_code" text, + "ship_country" text NOT NULL, + "customer_id" text NOT NULL, + "employee_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."product" ( + "id" integer PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "quantity_per_unit" text NOT NULL, + "unit_price" numeric NOT NULL, + "units_in_stock" integer NOT NULL, + "units_on_order" integer NOT NULL, + "reorder_level" integer NOT NULL, + "discontinued" integer NOT NULL, + "supplier_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."supplier" ( + "id" integer PRIMARY KEY NOT NULL, + "company_name" text NOT NULL, + "contact_name" text NOT NULL, + "contact_title" text NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "region" text, + "postal_code" text NOT NULL, + "country" text NOT NULL, + "phone" text NOT NULL + ); + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order_detail" ADD CONSTRAINT "order_detail_order_id_order_id_fk" FOREIGN KEY ("order_id") REFERENCES "seeder_lib_pg"."order"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order_detail" ADD CONSTRAINT "order_detail_product_id_product_id_fk" FOREIGN KEY ("product_id") REFERENCES "seeder_lib_pg"."product"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."employee" ADD CONSTRAINT "employee_reports_to_employee_id_fk" FOREIGN KEY ("reports_to") REFERENCES "seeder_lib_pg"."employee"("id") ON DELETE no action ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order" ADD CONSTRAINT "order_customer_id_customer_id_fk" FOREIGN KEY ("customer_id") REFERENCES "seeder_lib_pg"."customer"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order" ADD CONSTRAINT "order_employee_id_employee_id_fk" FOREIGN KEY ("employee_id") REFERENCES "seeder_lib_pg"."employee"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."product" ADD CONSTRAINT "product_supplier_id_supplier_id_fk" FOREIGN KEY ("supplier_id") REFERENCES "seeder_lib_pg"."supplier"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); +}; + +const createAllDataTypesTable = async () => { + await db.execute( + sql` + DO $$ BEGIN + CREATE TYPE "seeder_lib_pg"."mood_enum" AS ENUM('sad', 'ok', 'happy'); + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."all_data_types" ( + "integer" integer, + "smallint" smallint, + "bigint" bigint, + "bigint_number" bigint, + "serial" serial NOT NULL, + "smallserial" "smallserial" NOT NULL, + "bigserial" bigserial, + "bigserial_number" bigserial NOT NULL, + "boolean" boolean, + "text" text, + "varchar" varchar(256), + "char" char(256), + "numeric" numeric, + "decimal" numeric, + "real" real, + "double_precision" double precision, + "json" json, + "jsonb" jsonb, + "time" time, + "timestamp_date" timestamp, + "timestamp_string" timestamp, + "date_string" date, + "date" date, + "interval" interval, + "point" "point", + "point_tuple" "point", + "line" "line", + "line_tuple" "line", + "mood_enum" "seeder_lib_pg"."mood_enum" + ); + `, + ); +}; + +const createAllGeneratorsTables = async () => { + await db.execute( + sql` + DO $$ BEGIN + CREATE TYPE "seeder_lib_pg"."enum" AS ENUM('sad', 'ok', 'happy'); + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."boolean_table" ( + "boolean" boolean + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_table" ( + "city" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_unique_table" ( + "city_unique" varchar(256), + CONSTRAINT "city_unique_table_city_unique_unique" UNIQUE("city_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_table" ( + "company_name" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_unique_table" ( + "company_name_unique" varchar(256), + CONSTRAINT "company_name_unique_table_company_name_unique_unique" UNIQUE("company_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_table" ( + "country" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_unique_table" ( + "country_unique" varchar(256), + CONSTRAINT "country_unique_table_country_unique_unique" UNIQUE("country_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."date_table" ( + "date" date + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."default_table" ( + "default_string" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."email_table" ( + "email" varchar(256), + CONSTRAINT "email_table_email_unique" UNIQUE("email") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."enum_table" ( + "mood_enum" "seeder_lib_pg"."enum" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."first_name_table" ( + "first_name" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."first_name_unique_table" ( + "first_name_unique" varchar(256), + CONSTRAINT "first_name_unique_table_first_name_unique_unique" UNIQUE("first_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name__table" ( + "full_name_" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name_unique_table" ( + "full_name_unique" varchar(256), + CONSTRAINT "full_name_unique_table_full_name_unique_unique" UNIQUE("full_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_primary_key_table" ( + "int_primary_key" integer, + CONSTRAINT "int_primary_key_table_int_primary_key_unique" UNIQUE("int_primary_key") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_table" ( + "int" integer + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_unique_table" ( + "int_unique" integer, + CONSTRAINT "int_unique_table_int_unique_unique" UNIQUE("int_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_table" ( + "interval" interval + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_unique_table" ( + "interval_unique" interval, + CONSTRAINT "interval_unique_table_interval_unique_unique" UNIQUE("interval_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."job_title_table" ( + "job_title" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."json_table" ( + "json" json + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_table" ( + "last_name" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_unique_table" ( + "last_name_unique" varchar(256), + CONSTRAINT "last_name_unique_table_last_name_unique_unique" UNIQUE("last_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."line_table" ( + "line" "line" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."lorem_ipsum_table" ( + "lorem_ipsum" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_table" ( + "number" real + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_unique_table" ( + "number_unique" real, + CONSTRAINT "number_unique_table_number_unique_unique" UNIQUE("number_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."phone_number_table" ( + "phoneNumber" varchar(256), + "phone_number_template" varchar(256), + "phone_number_prefixes" varchar(256), + CONSTRAINT "phone_number_table_phoneNumber_unique" UNIQUE("phoneNumber"), + CONSTRAINT "phone_number_table_phone_number_template_unique" UNIQUE("phone_number_template"), + CONSTRAINT "phone_number_table_phone_number_prefixes_unique" UNIQUE("phone_number_prefixes") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."point_table" ( + "point" "point" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_table" ( + "postcode" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_unique_table" ( + "postcode_unique" varchar(256), + CONSTRAINT "postcode_unique_table_postcode_unique_unique" UNIQUE("postcode_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."state_table" ( + "state" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_table" ( + "street_address" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_unique_table" ( + "street_address_unique" varchar(256), + CONSTRAINT "street_address_unique_table_street_address_unique_unique" UNIQUE("street_address_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_table" ( + "string" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_unique_table" ( + "string_unique" varchar(256), + CONSTRAINT "string_unique_table_string_unique_unique" UNIQUE("string_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."time_table" ( + "time" time + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."timestamp_table" ( + "timestamp" timestamp + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_table" ( + "values_from_array_not_null" varchar(256) NOT NULL, + "values_from_array_weighted_not_null" varchar(256) NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_unique_table" ( + "values_from_array" varchar(256), + "values_from_array_not_null" varchar(256) NOT NULL, + "values_from_array_weighted" varchar(256), + "values_from_array_weighted_not_null" varchar(256) NOT NULL, + CONSTRAINT "values_from_array_unique_table_values_from_array_unique" UNIQUE("values_from_array"), + CONSTRAINT "values_from_array_unique_table_values_from_array_not_null_unique" UNIQUE("values_from_array_not_null"), + CONSTRAINT "values_from_array_unique_table_values_from_array_weighted_unique" UNIQUE("values_from_array_weighted"), + CONSTRAINT "values_from_array_unique_table_values_from_array_weighted_not_null_unique" UNIQUE("values_from_array_weighted_not_null") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."weighted_random_table" ( + "weighted_random" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."weighted_random_with_unique_gens_table" ( + "weighted_random_with_unique_gens" varchar(256), + CONSTRAINT "weighted_random_with_unique_gens_table_weighted_random_with_unique_gens_unique" UNIQUE("weighted_random_with_unique_gens") + ); + `, + ); +}; + +beforeAll(async () => { + client = new PGlite(); + + db = drizzle(client); + + await db.execute(sql`CREATE SCHEMA "seeder_lib_pg";`); + + await createNorthwindTables(); + await createAllDataTypesTable(); + await createAllGeneratorsTables(); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +afterAll(async () => { + await client.close(); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +// All data types test ------------------------------- +test('basic seed test for all postgres data types', async () => { + await seed(db, { allDataTypes: schema.allDataTypes }, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); + +// All generators test------------------------------- +const count = 10000; + +test('enum generator test', async () => { + await seed(db, { enumTable: schema.enumTable }).refine(() => ({ + enumTable: { + count, + }, + })); + + const data = await db.select().from(schema.enumTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('default generator test', async () => { + await seed(db, { defaultTable: schema.defaultTable }).refine((funcs) => ({ + defaultTable: { + count, + columns: { + defaultString: funcs.default({ defaultValue: 'default string' }), + }, + }, + })); + + const data = await db.select().from(schema.defaultTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('valuesFromArray generator test', async () => { + await seed(db, { valuesFromArrayTable: schema.valuesFromArrayTable }).refine((funcs) => ({ + valuesFromArrayTable: { + count, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ values: lastNames }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames, weight: 0.3 }, + { values: firstNames, weight: 0.7 }, + ], + }), + }, + }, + })); + + const data = await db.select().from(schema.valuesFromArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('valuesFromArray unique generator test', async () => { + // valuesFromArrayUniqueTable----------------------------------------------------------------------------------- + await seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }, { seed: 1 }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArray: funcs.valuesFromArray({ values: lastNames.slice(0, 20), isUnique: true }), + valuesFromArrayNotNull: funcs.valuesFromArray({ values: lastNames, isUnique: true }), + valuesFromArrayWeighted: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 20000), weight: 0.3 }, + { values: lastNames.slice(20000), weight: 0.7 }, + ], + isUnique: true, + }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 14920), weight: 0.3 }, + { values: lastNames.slice(14920), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })); + + const data = await db.select().from(schema.valuesFromArrayUniqueTable); + // console.log(valuesFromArrayUniqueTableData); + const predicate = data.length !== 0 && data.every((row) => + row['valuesFromArrayWeightedNotNull'] !== null + && row['valuesFromArrayNotNull'] !== null + ); + expect(predicate).toBe(true); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 20000), weight: 0.3 }, + { values: lastNames.slice(20000), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow( + /^weighted values arrays is too small to generate values with specified probability for unique not null column\..+/, + ); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ + values: lastNames.slice(20), + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow('there are no enough values to fill unique column.'); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }, { seed: 1 }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49999, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ + values: lastNames, + isUnique: true, + }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 14854), weight: 0.3 }, + { values: lastNames.slice(14854), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow('there are no enough values to fill unique column.'); +}); + +test('intPrimaryKey generator test', async () => { + await seed(db, { intPrimaryKeyTable: schema.intPrimaryKeyTable }).refine((funcs) => ({ + intPrimaryKeyTable: { + count, + columns: { + intPrimaryKey: funcs.intPrimaryKey(), + }, + }, + })); + + const data = await db.select().from(schema.intPrimaryKeyTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('number generator test', async () => { + await seed(db, { numberTable: schema.numberTable }).refine((funcs) => ({ + numberTable: { + count, + columns: { + number: funcs.number(), + }, + }, + })); + + const data = await db.select().from(schema.numberTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('number unique generator test', async () => { + // numberUniqueTable----------------------------------------------------------------------------------- + await seed(db, { numberUniqueTable: schema.numberUniqueTable }).refine((funcs) => ({ + numberUniqueTable: { + count: 20070, + columns: { + numberUnique: funcs.number({ isUnique: true, minValue: -100.23, maxValue: 100.46 }), + }, + }, + })); + + const data = await db.select().from(schema.numberUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && val >= -100.23 && val <= 100.46) + ); + expect(predicate).toBe(true); + + await expect( + seed(db, { numberUniqueTable: schema.numberUniqueTable }).refine((funcs) => ({ + numberUniqueTable: { + count: 20071, + columns: { + numberUnique: funcs.number({ isUnique: true, minValue: -100.23, maxValue: 100.46 }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); +}); + +test('int generator test', async () => { + await seed(db, { intTable: schema.intTable }).refine((funcs) => ({ + intTable: { + count, + columns: { + int: funcs.int(), + }, + }, + })); + + const data = await db.select().from(schema.intTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('int unique generator test', async () => { + // intUniqueTable----------------------------------------------------------------------------------- + await seed(db, { intUniqueTable: schema.intUniqueTable }).refine((funcs) => ({ + intUniqueTable: { + count: 201, + columns: { + intUnique: funcs.int({ isUnique: true, minValue: -100, maxValue: 100 }), + }, + }, + })); + + const data = await db.select().from(schema.intUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { intUniqueTable: schema.intUniqueTable }).refine((funcs) => ({ + intUniqueTable: { + count: 202, + columns: { + intUnique: funcs.int({ isUnique: true, minValue: -100, maxValue: 100 }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); +}); + +test('boolean generator test', async () => { + await seed(db, { booleanTable: schema.booleanTable }).refine((funcs) => ({ + booleanTable: { + count, + columns: { + boolean: funcs.boolean(), + }, + }, + })); + + const data = await db.select().from(schema.booleanTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('date generator test', async () => { + await seed(db, { dateTable: schema.dateTable }).refine((funcs) => ({ + dateTable: { + count, + columns: { + date: funcs.date(), + }, + }, + })); + + const data = await db.select().from(schema.dateTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('time generator test', async () => { + await seed(db, { timeTable: schema.timeTable }).refine((funcs) => ({ + timeTable: { + count, + columns: { + time: funcs.time(), + }, + }, + })); + + const data = await db.select().from(schema.timeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('timestamp generator test', async () => { + await seed(db, { timestampTable: schema.timestampTable }).refine((funcs) => ({ + timestampTable: { + count, + columns: { + timestamp: funcs.timestamp(), + }, + }, + })); + + const data = await db.select().from(schema.timestampTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('json generator test', async () => { + await seed(db, { jsonTable: schema.jsonTable }).refine((funcs) => ({ + jsonTable: { + count, + columns: { + json: funcs.json(), + }, + }, + })); + + const data = await db.select().from(schema.jsonTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('interval generator test', async () => { + await seed(db, { intervalTable: schema.intervalTable }).refine((funcs) => ({ + intervalTable: { + count, + columns: { + interval: funcs.interval(), + }, + }, + })); + + const data = await db.select().from(schema.intervalTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('interval unique generator test', async () => { + // intervalUniqueTable----------------------------------------------------------------------------------- + await seed(db, { intervalUniqueTable: schema.intervalUniqueTable }).refine((funcs) => ({ + intervalUniqueTable: { + count, + columns: { + intervalUnique: funcs.interval({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.intervalUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('string generator test', async () => { + await seed(db, { stringTable: schema.stringTable }).refine((funcs) => ({ + stringTable: { + count, + columns: { + string: funcs.string(), + }, + }, + })); + + const data = await db.select().from(schema.stringTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('string unique generator test', async () => { + await seed(db, { stringUniqueTable: schema.stringUniqueTable }).refine((funcs) => ({ + stringUniqueTable: { + count, + columns: { + stringUnique: funcs.string({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.stringUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('email generator test', async () => { + await seed(db, { emailTable: schema.emailTable }).refine((funcs) => ({ + emailTable: { + count, + columns: { + email: funcs.email(), + }, + }, + })); + + const data = await db.select().from(schema.emailTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('firstName generator test', async () => { + await seed(db, { firstNameTable: schema.firstNameTable }).refine((funcs) => ({ + firstNameTable: { + count, + columns: { + firstName: funcs.firstName(), + }, + }, + })); + + const data = await db.select().from(schema.firstNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('firstName unique generator test', async () => { + // firstNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { firstNameUniqueTable: schema.firstNameUniqueTable }).refine((funcs) => ({ + firstNameUniqueTable: { + count: 30274, + columns: { + firstNameUnique: funcs.firstName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.firstNameUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { firstNameUniqueTable: schema.firstNameUniqueTable }, { count: 30275 }).refine((funcs) => ({ + firstNameUniqueTable: { + count: 30275, + columns: { + firstNameUnique: funcs.firstName({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique first names.'); +}); + +test('lastName generator test', async () => { + await seed(db, { lastNameTable: schema.lastNameTable }).refine((funcs) => ({ + lastNameTable: { + count, + columns: { + lastName: funcs.lastName(), + }, + }, + })); + + const data = await db.select().from(schema.lastNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('lastName unique generator test', async () => { + // lastNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { lastNameUniqueTable: schema.lastNameUniqueTable }).refine((funcs) => ({ + lastNameUniqueTable: { + count: 49998, + columns: { + lastNameUnique: funcs.lastName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.lastNameUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { lastNameUniqueTable: schema.lastNameUniqueTable }).refine((funcs) => ({ + lastNameUniqueTable: { + count: 49999, + columns: { + lastNameUnique: funcs.lastName({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique last names.'); +}); + +test('fullName generator test', async () => { + await seed(db, { fullNameTable: schema.fullNameTable }).refine((funcs) => ({ + fullNameTable: { + count, + columns: { + fullName: funcs.fullName(), + }, + }, + })); + + const data = await db.select().from(schema.fullNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('fullName unique generator test', async () => { + // fullNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { fullNameUniqueTable: schema.fullNameUniqueTable }).refine((funcs) => ({ + fullNameUniqueTable: { + count, + columns: { + fullNameUnique: funcs.fullName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.fullNameUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('country generator test', async () => { + await seed(db, { countryTable: schema.countryTable }).refine((funcs) => ({ + countryTable: { + count, + columns: { + country: funcs.country(), + }, + }, + })); + + const data = await db.select().from(schema.countryTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('country unique generator test', async () => { + // countryUniqueTable----------------------------------------------------------------------------------- + await seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ + countryUniqueTable: { + count: 167, + columns: { + countryUnique: funcs.country({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.countryUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ + countryUniqueTable: { + count: 168, + columns: { + countryUnique: funcs.country({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique countries.'); +}); + +test('city generator test', async () => { + await seed(db, { cityTable: schema.cityTable }).refine((funcs) => ({ + cityTable: { + count, + columns: { + city: funcs.city(), + }, + }, + })); + + const data = await db.select().from(schema.cityTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('city unique generator test', async () => { + // cityUniqueTable----------------------------------------------------------------------------------- + await reset(db, { cityUniqueTable: schema.cityUniqueTable }); + await seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ + cityUniqueTable: { + count: 42984, + columns: { + cityUnique: funcs.city({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.cityUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ + cityUniqueTable: { + count: 42985, + columns: { + cityUnique: funcs.city({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique cities.'); +}); + +test('streetAddress generator test', async () => { + await seed(db, { streetAddressTable: schema.streetAddressTable }).refine((funcs) => ({ + streetAddressTable: { + count, + columns: { + streetAddress: funcs.streetAddress(), + }, + }, + })); + + const data = await db.select().from(schema.streetAddressTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('streetAddress unique generator test', async () => { + await seed(db, { streetAddressUniqueTable: schema.streetAddressUniqueTable }).refine((funcs) => ({ + streetAddressUniqueTable: { + count, + columns: { + streetAddressUnique: funcs.streetAddress({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.streetAddressUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('jobTitle generator test', async () => { + await seed(db, { jobTitleTable: schema.jobTitleTable }).refine((funcs) => ({ + jobTitleTable: { + count, + columns: { + jobTitle: funcs.jobTitle(), + }, + }, + })); + + const data = await db.select().from(schema.jobTitleTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('postcode generator test', async () => { + await seed(db, { postcodeTable: schema.postcodeTable }).refine((funcs) => ({ + postcodeTable: { + count, + columns: { + postcode: funcs.postcode(), + }, + }, + })); + + const data = await db.select().from(schema.postcodeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('postcode unique generator test', async () => { + await seed(db, { postcodeUniqueTable: schema.postcodeUniqueTable }).refine((funcs) => ({ + postcodeUniqueTable: { + count, + columns: { + postcodeUnique: funcs.postcode({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.postcodeUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('state generator test', async () => { + await seed(db, { stateTable: schema.stateTable }).refine((funcs) => ({ + stateTable: { + count, + columns: { + state: funcs.state(), + }, + }, + })); + + const data = await db.select().from(schema.stateTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('companyName generator test', async () => { + await seed(db, { companyNameTable: schema.companyNameTable }).refine((funcs) => ({ + companyNameTable: { + count, + columns: { + companyName: funcs.companyName(), + }, + }, + })); + + const data = await db.select().from(schema.companyNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('companyName unique generator test', async () => { + await seed(db, { companyNameUniqueTable: schema.companyNameUniqueTable }).refine((funcs) => ({ + companyNameUniqueTable: { + count, + columns: { + companyNameUnique: funcs.companyName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.companyNameUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('loremIpsum generator test', async () => { + await seed(db, { loremIpsumTable: schema.loremIpsumTable }).refine((funcs) => ({ + loremIpsumTable: { + count, + columns: { + loremIpsum: funcs.loremIpsum(), + }, + }, + })); + + const data = await db.select().from(schema.loremIpsumTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('point generator test', async () => { + await seed(db, { pointTable: schema.pointTable }).refine((funcs) => ({ + pointTable: { + count, + columns: { + point: funcs.point(), + }, + }, + })); + + const data = await db.select().from(schema.pointTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('point unique generator test', async () => { + await reset(db, { pointTable: schema.pointTable }); + await seed(db, { pointTable: schema.pointTable }).refine((funcs) => ({ + pointTable: { + count, + columns: { + point: funcs.point({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.pointTable); + // every value in each row does not equal undefined. + let predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + // using Set because PGlite does not support unique point + const pointStrsSet = new Set(data.map((row) => row.point!.map(String).join(','))); + predicate = pointStrsSet.size === data.length; + expect(predicate).toBe(true); +}); + +test('line generator test', async () => { + await seed(db, { lineTable: schema.lineTable }).refine((funcs) => ({ + lineTable: { + count, + columns: { + line: funcs.line(), + }, + }, + })); + + const data = await db.select().from(schema.lineTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('line unique generator test', async () => { + await reset(db, { lineTable: schema.lineTable }); + await seed(db, { lineTable: schema.lineTable }).refine((funcs) => ({ + lineTable: { + count, + columns: { + line: funcs.line({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.lineTable); + // every value in each row does not equal undefined. + let predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + // using Set because PGlite does not support unique point + const lineStrsSet = new Set(data.map((row) => row.line!.map(String).join(','))); + predicate = lineStrsSet.size === data.length; + expect(predicate).toBe(true); +}); + +test('phoneNumber generator test', async () => { + await seed(db, { phoneNumberTable: schema.phoneNumberTable }).refine((funcs) => ({ + phoneNumberTable: { + count, + columns: { + phoneNumber: funcs.phoneNumber(), + phoneNumberPrefixes: funcs.phoneNumber({ + prefixes: ['+380 99', '+380 67', '+1'], + generatedDigitsNumbers: [7, 7, 10], + }), + phoneNumberTemplate: funcs.phoneNumber({ template: '+380 ## ## ### ##' }), + }, + }, + })); + + const data = await db.select().from(schema.phoneNumberTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('weightedRandom generator test', async () => { + await seed(db, { weightedRandomTable: schema.weightedRandomTable }).refine((funcs) => ({ + weightedRandomTable: { + count, + columns: { + weightedRandom: funcs.weightedRandom([ + { value: funcs.default({ defaultValue: 'default value' }), weight: 0.3 }, + { value: funcs.loremIpsum(), weight: 0.7 }, + ]), + }, + }, + })); + + const data = await db.select().from(schema.weightedRandomTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('weightedRandom with unique gens generator test', async () => { + await seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 10000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.3, value: funcs.email() }, + { weight: 0.7, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })); + + const data = await db.select().from(schema.weightedRandomWithUniqueGensTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 40000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.1, value: funcs.email() }, + { weight: 0.9, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique first names.'); + + await expect( + seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 10000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.2, value: funcs.email() }, + { weight: 0.9, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })), + ).rejects.toThrow("sum of all weights don't equal to 1; 1.1 !== 1"); +}); diff --git a/integration-tests/tests/seeder/pgSchema.ts b/integration-tests/tests/seeder/pgSchema.ts new file mode 100644 index 000000000..ffb2e9783 --- /dev/null +++ b/integration-tests/tests/seeder/pgSchema.ts @@ -0,0 +1,351 @@ +import type { AnyPgColumn } from 'drizzle-orm/pg-core'; +import { + bigint, + bigserial, + boolean, + char, + date, + decimal, + doublePrecision, + integer, + interval, + json, + jsonb, + line, + numeric, + pgEnum, + pgSchema, + point, + real, + serial, + smallint, + smallserial, + text, + time, + timestamp, + varchar, +} from 'drizzle-orm/pg-core'; + +export const schema = pgSchema('seeder_lib_pg'); + +export const customers = schema.table('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = schema.table( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to').references((): AnyPgColumn => employees.id), + photoPath: text('photo_path'), + }, +); + +export const orders = schema.table('order', { + id: integer('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = schema.table('supplier', { + id: integer('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = schema.table('product', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = schema.table('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); + +// All data types table ------------------------------- +export const moodEnum = pgEnum('mood_enum', ['sad', 'ok', 'happy']); + +export const allDataTypes = schema.table('all_data_types', { + integer: integer('integer'), + smallint: smallint('smallint'), + biginteger: bigint('bigint', { mode: 'bigint' }), + bigintNumber: bigint('bigint_number', { mode: 'number' }), + serial: serial('serial'), + smallserial: smallserial('smallserial'), + bigserial: bigserial('bigserial', { mode: 'bigint' }), + bigserialNumber: bigserial('bigserial_number', { mode: 'number' }), + boolean: boolean('boolean'), + text: text('text'), + varchar: varchar('varchar', { length: 256 }), + char: char('char', { length: 256 }), + numeric: numeric('numeric'), + decimal: decimal('decimal'), + real: real('real'), + doublePrecision: doublePrecision('double_precision'), + json: json('json'), + jsonb: jsonb('jsonb'), + time: time('time'), + timestampDate: timestamp('timestamp_date', { mode: 'date' }), + timestampString: timestamp('timestamp_string', { mode: 'string' }), + dateString: date('date_string', { mode: 'string' }), + date: date('date', { mode: 'date' }), + interval: interval('interval'), + point: point('point', { mode: 'xy' }), + pointTuple: point('point_tuple', { mode: 'tuple' }), + line: line('line', { mode: 'abc' }), + lineTuple: line('line_tuple', { mode: 'tuple' }), + moodEnum: moodEnum('mood_enum'), +}); + +// All generators tables ------------------------------- +export const enumTable = schema.table('enum_table', { + mood: moodEnum('mood_enum'), +}); + +export const defaultTable = schema.table('default_table', { + defaultString: text('default_string'), +}); + +export const valuesFromArrayTable = schema.table('values_from_array_table', { + valuesFromArrayNotNull: varchar('values_from_array_not_null', { length: 256 }).notNull(), + valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).notNull(), +}); + +export const valuesFromArrayUniqueTable = schema.table('values_from_array_unique_table', { + valuesFromArray: varchar('values_from_array', { length: 256 }).unique(), + valuesFromArrayNotNull: varchar('values_from_array_not_null', { length: 256 }).unique().notNull(), + valuesFromArrayWeighted: varchar('values_from_array_weighted', { length: 256 }).unique(), + valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).unique().notNull(), +}); + +export const intPrimaryKeyTable = schema.table('int_primary_key_table', { + intPrimaryKey: integer('int_primary_key').unique(), +}); + +export const numberTable = schema.table('number_table', { + number: real('number'), +}); + +export const numberUniqueTable = schema.table('number_unique_table', { + numberUnique: real('number_unique').unique(), +}); + +export const intTable = schema.table('int_table', { + int: integer('int'), +}); + +export const intUniqueTable = schema.table('int_unique_table', { + intUnique: integer('int_unique').unique(), +}); + +export const booleanTable = schema.table('boolean_table', { + boolean: boolean('boolean'), +}); + +export const dateTable = schema.table('date_table', { + date: date('date'), +}); + +export const timeTable = schema.table('time_table', { + time: time('time'), +}); + +export const timestampTable = schema.table('timestamp_table', { + timestamp: timestamp('timestamp'), +}); + +export const jsonTable = schema.table('json_table', { + json: json('json'), +}); + +export const intervalTable = schema.table('interval_table', { + interval: interval('interval'), +}); + +export const intervalUniqueTable = schema.table('interval_unique_table', { + intervalUnique: interval('interval_unique').unique(), +}); + +export const stringTable = schema.table('string_table', { + string: text('string'), +}); + +export const stringUniqueTable = schema.table('string_unique_table', { + stringUnique: varchar('string_unique', { length: 256 }).unique(), +}); + +export const emailTable = schema.table('email_table', { + email: varchar('email', { length: 256 }).unique(), +}); + +export const firstNameTable = schema.table('first_name_table', { + firstName: varchar('first_name', { length: 256 }), +}); + +export const firstNameUniqueTable = schema.table('first_name_unique_table', { + firstNameUnique: varchar('first_name_unique', { length: 256 }).unique(), +}); + +export const lastNameTable = schema.table('last_name_table', { + lastName: varchar('last_name', { length: 256 }), +}); + +export const lastNameUniqueTable = schema.table('last_name_unique_table', { + lastNameUnique: varchar('last_name_unique', { length: 256 }).unique(), +}); + +export const fullNameTable = schema.table('full_name__table', { + fullName: varchar('full_name_', { length: 256 }), +}); + +export const fullNameUniqueTable = schema.table('full_name_unique_table', { + fullNameUnique: varchar('full_name_unique', { length: 256 }).unique(), +}); + +export const countryTable = schema.table('country_table', { + country: varchar('country', { length: 256 }), +}); + +export const countryUniqueTable = schema.table('country_unique_table', { + countryUnique: varchar('country_unique', { length: 256 }).unique(), +}); + +export const cityTable = schema.table('city_table', { + city: varchar('city', { length: 256 }), +}); + +export const cityUniqueTable = schema.table('city_unique_table', { + cityUnique: varchar('city_unique', { length: 256 }).unique(), +}); + +export const streetAddressTable = schema.table('street_address_table', { + streetAddress: varchar('street_address', { length: 256 }), +}); + +export const streetAddressUniqueTable = schema.table('street_address_unique_table', { + streetAddressUnique: varchar('street_address_unique', { length: 256 }).unique(), +}); + +export const jobTitleTable = schema.table('job_title_table', { + jobTitle: text('job_title'), +}); + +export const postcodeTable = schema.table('postcode_table', { + postcode: varchar('postcode', { length: 256 }), +}); + +export const postcodeUniqueTable = schema.table('postcode_unique_table', { + postcodeUnique: varchar('postcode_unique', { length: 256 }).unique(), +}); + +export const stateTable = schema.table('state_table', { + state: text('state'), +}); + +export const companyNameTable = schema.table('company_name_table', { + companyName: text('company_name'), +}); + +export const companyNameUniqueTable = schema.table('company_name_unique_table', { + companyNameUnique: varchar('company_name_unique', { length: 256 }).unique(), +}); + +export const loremIpsumTable = schema.table('lorem_ipsum_table', { + loremIpsum: text('lorem_ipsum'), +}); + +export const pointTable = schema.table('point_table', { + point: point('point'), +}); + +export const lineTable = schema.table('line_table', { + line: line('line'), +}); + +// export const pointUniqueTable = schema.table("point_unique_table", { +// pointUnique: point("point_unique").unique(), +// }); + +// export const lineUniqueTable = schema.table("line_unique_table", { +// lineUnique: line("line_unique").unique(), +// }); + +export const phoneNumberTable = schema.table('phone_number_table', { + phoneNumber: varchar('phoneNumber', { length: 256 }).unique(), + phoneNumberTemplate: varchar('phone_number_template', { length: 256 }).unique(), + phoneNumberPrefixes: varchar('phone_number_prefixes', { length: 256 }).unique(), +}); + +export const weightedRandomTable = schema.table('weighted_random_table', { + weightedRandom: varchar('weighted_random', { length: 256 }), +}); + +export const weightedRandomWithUniqueGensTable = schema.table('weighted_random_with_unique_gens_table', { + weightedRandomWithUniqueGens: varchar('weighted_random_with_unique_gens', { length: 256 }).unique(), +}); diff --git a/integration-tests/tests/seeder/sqlite.test.ts b/integration-tests/tests/seeder/sqlite.test.ts new file mode 100644 index 000000000..f9d124401 --- /dev/null +++ b/integration-tests/tests/seeder/sqlite.test.ts @@ -0,0 +1,322 @@ +import BetterSqlite3 from 'better-sqlite3'; +import { sql } from 'drizzle-orm'; +import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import { reset, seed } from 'drizzle-seed'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import * as schema from './sqliteSchema.ts'; + +let client: BetterSqlite3.Database; +let db: BetterSQLite3Database; + +beforeAll(async () => { + client = new BetterSqlite3(':memory:'); + + db = drizzle(client); + + db.run( + sql.raw(` + CREATE TABLE \`customer\` ( + \`id\` text PRIMARY KEY NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text, + \`region\` text, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + \`fax\` text +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`order_detail\` ( + \`unit_price\` numeric NOT NULL, + \`quantity\` integer NOT NULL, + \`discount\` numeric NOT NULL, + \`order_id\` integer NOT NULL, + \`product_id\` integer NOT NULL, + FOREIGN KEY (\`order_id\`) REFERENCES \`order\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`product_id\`) REFERENCES \`product\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`employee\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`last_name\` text NOT NULL, + \`first_name\` text, + \`title\` text NOT NULL, + \`title_of_courtesy\` text NOT NULL, + \`birth_date\` integer NOT NULL, + \`hire_date\` integer NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`home_phone\` text NOT NULL, + \`extension\` integer NOT NULL, + \`notes\` text NOT NULL, + \`reports_to\` integer, + \`photo_path\` text, + FOREIGN KEY (\`reports_to\`) REFERENCES \`employee\`(\`id\`) ON UPDATE no action ON DELETE no action +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`order\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`order_date\` integer NOT NULL, + \`required_date\` integer NOT NULL, + \`shipped_date\` integer, + \`ship_via\` integer NOT NULL, + \`freight\` numeric NOT NULL, + \`ship_name\` text NOT NULL, + \`ship_city\` text NOT NULL, + \`ship_region\` text, + \`ship_postal_code\` text, + \`ship_country\` text NOT NULL, + \`customer_id\` text NOT NULL, + \`employee_id\` integer NOT NULL, + FOREIGN KEY (\`customer_id\`) REFERENCES \`customer\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`employee_id\`) REFERENCES \`employee\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`product\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`name\` text NOT NULL, + \`quantity_per_unit\` text NOT NULL, + \`unit_price\` numeric NOT NULL, + \`units_in_stock\` integer NOT NULL, + \`units_on_order\` integer NOT NULL, + \`reorder_level\` integer NOT NULL, + \`discontinued\` integer NOT NULL, + \`supplier_id\` integer NOT NULL, + FOREIGN KEY (\`supplier_id\`) REFERENCES \`supplier\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`supplier\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`region\` text, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`phone\` text NOT NULL +); + `), + ); + + // All data types test ------------------------------- + db.run( + sql.raw(` + CREATE TABLE \`all_data_types\` ( + \`integer_number\` integer, + \`integer_boolean\` integer, + \`integer_timestamp\` integer, + \`integer_timestampms\` integer, + \`real\` real, + \`text\` text, + \`text_json\` text, + \`blob_bigint\` blob, + \`blob_buffer\` blob, + \`blob_json\` blob, + \`numeric\` numeric +); + `), + ); +}); + +afterAll(async () => { + client.close(); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +// All data types test ------------------------------- +test('basic seed test for all sqlite data types', async () => { + // migrate(db, { migrationsFolder: path.join(__dirname, "sqliteMigrations") }); + + await seed(db, { allDataTypes: schema.allDataTypes }, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); diff --git a/integration-tests/tests/seeder/sqliteSchema.ts b/integration-tests/tests/seeder/sqliteSchema.ts new file mode 100644 index 000000000..338833659 --- /dev/null +++ b/integration-tests/tests/seeder/sqliteSchema.ts @@ -0,0 +1,122 @@ +import { blob, foreignKey, integer, numeric, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const customers = sqliteTable('customer', { + id: text('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = sqliteTable( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: integer('birth_date', { mode: 'timestamp' }).notNull(), + hireDate: integer('hire_date', { mode: 'timestamp' }).notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to'), + photoPath: text('photo_path'), + }, + (table) => ({ + reportsToFk: foreignKey(() => ({ + columns: [table.reportsTo], + foreignColumns: [table.id], + })), + }), +); + +export const orders = sqliteTable('order', { + id: integer('id').primaryKey(), + orderDate: integer('order_date', { mode: 'timestamp' }).notNull(), + requiredDate: integer('required_date', { mode: 'timestamp' }).notNull(), + shippedDate: integer('shipped_date', { mode: 'timestamp' }), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = sqliteTable('supplier', { + id: integer('id').primaryKey({ autoIncrement: true }), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = sqliteTable('product', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = sqliteTable('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); + +// All data types table ------------------------------- +export const allDataTypes = sqliteTable('all_data_types', { + integerNumber: integer('integer_number', { mode: 'number' }), + integerBoolean: integer('integer_boolean', { mode: 'boolean' }), + integerTimestamp: integer('integer_timestamp', { mode: 'timestamp' }), + integerTimestampms: integer('integer_timestampms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { mode: 'text' }), + textJson: text('text_json', { mode: 'json' }), + blobBigint: blob('blob_bigint', { mode: 'bigint' }), + blobBuffer: blob('blob_buffer', { mode: 'buffer' }), + blobJson: blob('blob_json', { mode: 'json' }), + numeric: numeric('numeric'), +}); diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 5187d2cfc..dba55dcf2 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -5,6 +5,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { include: [ + 'tests/seeder/**/*.test.ts', 'tests/extensions/postgis/**/*', 'tests/relational/**/*.test.ts', 'tests/pg/**/*.test.ts', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f5d886131..03af2db5b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.3.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.3.0)(mysql2@3.11.0)(pg@8.13.0)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.0)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -78,7 +78,7 @@ importers: version: 0.8.16(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) tsx: specifier: ^4.10.5 version: 4.10.5 @@ -316,7 +316,7 @@ importers: version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -352,7 +352,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.4(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 0.29.4(typescript@5.6.3) better-sqlite3: specifier: ^8.4.0 version: 8.7.0 @@ -364,7 +364,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -400,7 +400,7 @@ importers: version: 3.14.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -411,6 +411,88 @@ importers: specifier: ^7.2.2 version: 7.2.2 + drizzle-seed: + dependencies: + pure-rand: + specifier: ^6.1.0 + version: 6.1.0 + devDependencies: + '@arethetypeswrong/cli': + specifier: ^0.16.1 + version: 0.16.4 + '@electric-sql/pglite': + specifier: ^0.1.5 + version: 0.1.5 + '@rollup/plugin-terser': + specifier: ^0.4.4 + version: 0.4.4(rollup@4.24.0) + '@rollup/plugin-typescript': + specifier: ^11.1.6 + version: 11.1.6(rollup@4.24.0)(tslib@2.7.0)(typescript@5.6.3) + '@types/better-sqlite3': + specifier: ^7.6.11 + version: 7.6.11 + '@types/dockerode': + specifier: ^3.3.31 + version: 3.3.31 + '@types/node': + specifier: ^22.5.4 + version: 22.7.5 + '@types/pg': + specifier: ^8.11.6 + version: 8.11.6 + '@types/uuid': + specifier: ^10.0.0 + version: 10.0.0 + better-sqlite3: + specifier: ^11.1.2 + version: 11.3.0 + cpy: + specifier: ^11.1.0 + version: 11.1.0 + dockerode: + specifier: ^4.0.2 + version: 4.0.2 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + drizzle-kit: + specifier: workspace:./drizzle-kit/dist + version: link:drizzle-kit/dist + drizzle-orm: + specifier: workspace:./drizzle-orm/dist + version: link:drizzle-orm/dist + get-port: + specifier: ^7.1.0 + version: 7.1.0 + mysql2: + specifier: ^3.3.3 + version: 3.3.3 + pg: + specifier: ^8.12.0 + version: 8.13.0 + resolve-tspaths: + specifier: ^0.8.19 + version: 0.8.22(typescript@5.6.3) + rollup: + specifier: ^4.21.2 + version: 4.24.0 + tslib: + specifier: ^2.7.0 + version: 2.7.0 + tsx: + specifier: ^4.19.0 + version: 4.19.1 + uuid: + specifier: ^10.0.0 + version: 10.0.0 + vitest: + specifier: ^2.0.5 + version: 2.1.2(@types/node@22.7.5)(lightningcss@1.25.1)(terser@5.31.0) + zx: + specifier: ^8.1.5 + version: 8.1.9 + drizzle-typebox: devDependencies: '@rollup/plugin-terser': @@ -418,7 +500,7 @@ importers: version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 11.1.1(rollup@3.27.2)(tslib@2.7.0)(typescript@5.6.3) '@sinclair/typebox': specifier: ^0.29.6 version: 0.29.6 @@ -439,7 +521,7 @@ importers: version: 3.27.2 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -454,7 +536,7 @@ importers: version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 11.1.1(rollup@3.27.2)(tslib@2.7.0)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 version: 18.15.10 @@ -475,7 +557,7 @@ importers: version: 0.30.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -490,7 +572,7 @@ importers: version: 0.4.1(rollup@3.20.7) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 11.1.0(rollup@3.20.7)(tslib@2.7.0)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 version: 18.15.10 @@ -508,7 +590,7 @@ importers: version: 3.20.7 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -580,7 +662,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.4(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 0.29.4(typescript@5.6.3) async-retry: specifier: ^1.3.3 version: 1.3.3 @@ -596,6 +678,9 @@ importers: drizzle-prisma-generator: specifier: ^0.1.2 version: 0.1.4 + drizzle-seed: + specifier: workspace:../drizzle-seed/dist + version: link:../drizzle-seed/dist drizzle-typebox: specifier: workspace:../drizzle-typebox/dist version: link:../drizzle-typebox/dist @@ -701,7 +786,7 @@ importers: version: 7.0.3 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 10.9.2(@types/node@20.12.12)(typescript@5.6.3) tsx: specifier: ^4.14.0 version: 4.16.2 @@ -710,7 +795,7 @@ importers: version: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) zx: specifier: ^7.2.2 version: 7.2.2 @@ -733,10 +818,19 @@ packages: engines: {node: '>=18'} hasBin: true + '@arethetypeswrong/cli@0.16.4': + resolution: {integrity: sha512-qMmdVlJon5FtA+ahn0c1oAVNxiq4xW5lqFiTZ21XHIeVwAVIQ+uRz4UEivqRMsjVV1grzRgJSKqaOrq1MvlVyQ==} + engines: {node: '>=18'} + hasBin: true + '@arethetypeswrong/core@0.15.1': resolution: {integrity: sha512-FYp6GBAgsNz81BkfItRz8RLZO03w5+BaeiPma1uCfmxTnxbtuMrI/dbzGiOk8VghO108uFI0oJo0OkewdSHw7g==} engines: {node: '>=18'} + '@arethetypeswrong/core@0.16.4': + resolution: {integrity: sha512-RI3HXgSuKTfcBf1hSEg1P9/cOvmI0flsMm6/QL3L3wju4AlHDqd55JFPfXs4pzgEAgy5L9pul4/HPPz99x2GvA==} + engines: {node: '>=18'} + '@ava/typescript@5.0.0': resolution: {integrity: sha512-2twsQz2fUd95QK1MtKuEnjkiN47SKHZfi/vWj040EN6Eo2ZW3SNcAwncJqXXoMTYZTWtBRXYp3Fg8z+JkFI9aQ==} engines: {node: ^18.18 || ^20.8 || ^21 || ^22} @@ -1991,9 +2085,11 @@ packages: '@esbuild-kit/core-utils@3.1.0': resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-kit/esm-loader@2.5.5': resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-plugins/node-globals-polyfill@0.2.3': resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} @@ -2980,10 +3076,12 @@ packages: '@humanwhocodes/config-array@0.11.11': resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.13': resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} @@ -2996,9 +3094,11 @@ packages: '@humanwhocodes/object-schema@1.2.1': resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.1': resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} @@ -3075,6 +3175,9 @@ packages: '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/trace-mapping@0.3.18': resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} @@ -3402,6 +3505,15 @@ packages: rollup: optional: true + '@rollup/plugin-terser@0.4.4': + resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/plugin-typescript@11.1.0': resolution: {integrity: sha512-86flrfE+bSHB69znnTV6kVjkncs2LBMhcTCyxWgRxLyfXfQrxg4UwlAqENnjrrxnSNS/XKCDJCl8EkdFJVHOxw==} engines: {node: '>=14.0.0'} @@ -3428,6 +3540,19 @@ packages: tslib: optional: true + '@rollup/plugin-typescript@11.1.6': + resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.14.0||^3.0.0||^4.0.0 + tslib: '*' + typescript: '>=3.7.0' + peerDependenciesMeta: + rollup: + optional: true + tslib: + optional: true + '@rollup/pluginutils@5.0.2': resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} engines: {node: '>=14.0.0'} @@ -3437,19 +3562,23 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.18.0': - resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} - cpu: [arm] - os: [android] + '@rollup/pluginutils@5.1.2': + resolution: {integrity: sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true '@rollup/rollup-android-arm-eabi@4.18.1': resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.18.0': - resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} - cpu: [arm64] + '@rollup/rollup-android-arm-eabi@4.24.0': + resolution: {integrity: sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==} + cpu: [arm] os: [android] '@rollup/rollup-android-arm64@4.18.1': @@ -3457,19 +3586,19 @@ packages: cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.18.0': - resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} + '@rollup/rollup-android-arm64@4.24.0': + resolution: {integrity: sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==} cpu: [arm64] - os: [darwin] + os: [android] '@rollup/rollup-darwin-arm64@4.18.1': resolution: {integrity: sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.18.0': - resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} - cpu: [x64] + '@rollup/rollup-darwin-arm64@4.24.0': + resolution: {integrity: sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==} + cpu: [arm64] os: [darwin] '@rollup/rollup-darwin-x64@4.18.1': @@ -3477,18 +3606,18 @@ packages: cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.18.0': - resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} - cpu: [arm] - os: [linux] + '@rollup/rollup-darwin-x64@4.24.0': + resolution: {integrity: sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==} + cpu: [x64] + os: [darwin] '@rollup/rollup-linux-arm-gnueabihf@4.18.1': resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.18.0': - resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==} + '@rollup/rollup-linux-arm-gnueabihf@4.24.0': + resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==} cpu: [arm] os: [linux] @@ -3497,9 +3626,9 @@ packages: cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.18.0': - resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==} - cpu: [arm64] + '@rollup/rollup-linux-arm-musleabihf@4.24.0': + resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==} + cpu: [arm] os: [linux] '@rollup/rollup-linux-arm64-gnu@4.18.1': @@ -3507,8 +3636,8 @@ packages: cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.18.0': - resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==} + '@rollup/rollup-linux-arm64-gnu@4.24.0': + resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==} cpu: [arm64] os: [linux] @@ -3517,9 +3646,9 @@ packages: cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': - resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} - cpu: [ppc64] + '@rollup/rollup-linux-arm64-musl@4.24.0': + resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==} + cpu: [arm64] os: [linux] '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': @@ -3527,9 +3656,9 @@ packages: cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.18.0': - resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==} - cpu: [riscv64] + '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': + resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==} + cpu: [ppc64] os: [linux] '@rollup/rollup-linux-riscv64-gnu@4.18.1': @@ -3537,9 +3666,9 @@ packages: cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.18.0': - resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} - cpu: [s390x] + '@rollup/rollup-linux-riscv64-gnu@4.24.0': + resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==} + cpu: [riscv64] os: [linux] '@rollup/rollup-linux-s390x-gnu@4.18.1': @@ -3547,9 +3676,9 @@ packages: cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.18.0': - resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==} - cpu: [x64] + '@rollup/rollup-linux-s390x-gnu@4.24.0': + resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==} + cpu: [s390x] os: [linux] '@rollup/rollup-linux-x64-gnu@4.18.1': @@ -3557,8 +3686,8 @@ packages: cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.18.0': - resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==} + '@rollup/rollup-linux-x64-gnu@4.24.0': + resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==} cpu: [x64] os: [linux] @@ -3567,19 +3696,19 @@ packages: cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.18.0': - resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==} - cpu: [arm64] - os: [win32] + '@rollup/rollup-linux-x64-musl@4.24.0': + resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==} + cpu: [x64] + os: [linux] '@rollup/rollup-win32-arm64-msvc@4.18.1': resolution: {integrity: sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.18.0': - resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==} - cpu: [ia32] + '@rollup/rollup-win32-arm64-msvc@4.24.0': + resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==} + cpu: [arm64] os: [win32] '@rollup/rollup-win32-ia32-msvc@4.18.1': @@ -3587,9 +3716,9 @@ packages: cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.18.0': - resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==} - cpu: [x64] + '@rollup/rollup-win32-ia32-msvc@4.24.0': + resolution: {integrity: sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==} + cpu: [ia32] os: [win32] '@rollup/rollup-win32-x64-msvc@4.18.1': @@ -3597,6 +3726,11 @@ packages: cpu: [x64] os: [win32] + '@rollup/rollup-win32-x64-msvc@4.24.0': + resolution: {integrity: sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==} + cpu: [x64] + os: [win32] + '@segment/loosely-validate-event@2.0.0': resolution: {integrity: sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==} @@ -3619,6 +3753,10 @@ packages: resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} + '@sindresorhus/merge-streams@2.3.0': + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + '@sinonjs/commons@3.0.1': resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} @@ -3991,6 +4129,9 @@ packages: '@types/better-sqlite3@7.6.10': resolution: {integrity: sha512-TZBjD+yOsyrUJGmcUj6OS3JADk3+UZcNv3NOBqGkM09bZdi28fNZw8ODqbMOLfKCu7RYCO62/ldq1iHbzxqoPw==} + '@types/better-sqlite3@7.6.11': + resolution: {integrity: sha512-i8KcD3PgGtGBLl3+mMYA8PdKkButvPyARxA7IQAd6qeslht13qxb1zzO8dRCtE7U3IoJS782zDBAeoKiM695kg==} + '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} @@ -4003,6 +4144,9 @@ packages: '@types/dockerode@3.3.29': resolution: {integrity: sha512-5PRRq/yt5OT/Jf77ltIdz4EiR9+VLnPF+HpU4xGFwUqmV24Co2HKBNW3w+slqZ1CYchbcDeqJASHDYWzZCcMiQ==} + '@types/dockerode@3.3.31': + resolution: {integrity: sha512-42R9eoVqJDSvVspV89g7RwRqfNExgievLNWoHkg7NoWIqAmavIbgQBb4oc0qRtHkxE+I3Xxvqv7qVXFABKPBTg==} + '@types/emscripten@1.39.11': resolution: {integrity: sha512-dOeX2BeNA7j6BTEqJQL3ut0bRCfsyQMd5i4FT8JfHfYhAOuJPCGh0dQFbxVJxUyQ+75x6enhDdndGb624/QszA==} @@ -4012,6 +4156,9 @@ packages: '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/express-serve-static-core@4.19.0': resolution: {integrity: sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==} @@ -4072,6 +4219,9 @@ packages: '@types/node@20.12.12': resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} + '@types/node@22.7.5': + resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@types/normalize-package-data@2.4.1': resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} @@ -4120,6 +4270,9 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@types/uuid@9.0.8': resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} @@ -4355,15 +4508,42 @@ packages: '@vitest/expect@1.6.0': resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} + '@vitest/expect@2.1.2': + resolution: {integrity: sha512-FEgtlN8mIUSEAAnlvn7mP8vzaWhEaAEvhSXCqrsijM7K6QqjB11qoRZYEd4AKSCDz8p0/+yH5LzhZ47qt+EyPg==} + + '@vitest/mocker@2.1.2': + resolution: {integrity: sha512-ExElkCGMS13JAJy+812fw1aCv2QO/LBK6CyO4WOPAzLTmve50gydOlWhgdBJPx2ztbADUq3JVI0C5U+bShaeEA==} + peerDependencies: + '@vitest/spy': 2.1.2 + msw: ^2.3.5 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.2': + resolution: {integrity: sha512-FIoglbHrSUlOJPDGIrh2bjX1sNars5HbxlcsFKCtKzu4+5lpsRhOCVcuzp0fEhAGHkPZRIXVNzPcpSlkoZ3LuA==} + '@vitest/runner@1.6.0': resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} + '@vitest/runner@2.1.2': + resolution: {integrity: sha512-UCsPtvluHO3u7jdoONGjOSil+uON5SSvU9buQh3lP7GgUXHp78guN1wRmZDX4wGK6J10f9NUtP6pO+SFquoMlw==} + '@vitest/snapshot@1.6.0': resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} + '@vitest/snapshot@2.1.2': + resolution: {integrity: sha512-xtAeNsZ++aRIYIUsek7VHzry/9AcxeULlegBvsdLncLmNCR6tR8SRjn8BbDP4naxtccvzTqZ+L1ltZlRCfBZFA==} + '@vitest/spy@1.6.0': resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} + '@vitest/spy@2.1.2': + resolution: {integrity: sha512-GSUi5zoy+abNRJwmFhBDC0yRuVUn8WMlQscvnbbXdKLXX9dE59YbfwXxuJ/mth6eeqIzofU8BB5XDo/Ns/qK2A==} + '@vitest/ui@1.6.0': resolution: {integrity: sha512-k3Lyo+ONLOgylctiGovRKy7V4+dIN2yxstX3eY5cWFXH6WP+ooVX79YSyi0GagdTQzLmT43BF27T0s6dOIPBXA==} peerDependencies: @@ -4372,6 +4552,9 @@ packages: '@vitest/utils@1.6.0': resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} + '@vitest/utils@2.1.2': + resolution: {integrity: sha512-zMO2KdYy6mx56btx9JvAqAZ6EyS3g49krMPPrgOp1yxGZiA93HumGk+bZ5jIZtOg5/VBYl5eBmGRQHqq4FG6uQ==} + '@xata.io/client@0.29.4': resolution: {integrity: sha512-dRff4E/wINr0SYIlOHwApo0h8jzpAHVf2RcbGMkK9Xrddbe90KmCEx/gue9hLhBOoCCp6qUht2h9BsuVPruymw==} peerDependencies: @@ -4454,6 +4637,10 @@ packages: resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==} engines: {node: '>=14.16'} + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} + ansi-fragments@0.2.1: resolution: {integrity: sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==} @@ -4507,6 +4694,7 @@ packages: are-we-there-yet@3.0.1: resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -4585,6 +4773,10 @@ packages: assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + ast-types@0.15.2: resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} engines: {node: '>=4'} @@ -4677,6 +4869,9 @@ packages: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} + better-sqlite3@11.3.0: + resolution: {integrity: sha512-iHt9j8NPYF3oKCNOO5ZI4JwThjt3Z6J6XrcwG85VNMVzv1ByqrHWv5VILEbCMFWDsoHhXvQ7oC8vgRXFAKgl9w==} + better-sqlite3@8.7.0: resolution: {integrity: sha512-99jZU4le+f3G6aIl6PmmV0cxUIWqKieHxsiF7G34CVFiE+/UabpYqkU0NJIkY/96mQKikHeBjtR27vFfs5JpEw==} @@ -4727,10 +4922,6 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -4875,6 +5066,10 @@ packages: resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} engines: {node: '>=4'} + chai@5.1.1: + resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} + engines: {node: '>=12'} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -4897,6 +5092,10 @@ packages: check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -4934,6 +5133,9 @@ packages: ci-parallel-vars@1.0.1: resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} + cjs-module-lexer@1.4.1: + resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} + clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} @@ -4962,6 +5164,11 @@ packages: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} + cli-highlight@2.1.11: + resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} @@ -4970,6 +5177,10 @@ packages: resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} engines: {node: 10.* || >= 12.*} + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + cli-truncate@3.1.0: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5134,6 +5345,10 @@ packages: resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} engines: {node: '>=12.13'} + copy-file@11.0.0: + resolution: {integrity: sha512-mFsNh/DIANLqFt5VHZoGirdg7bK5+oTWlhnGu6tgRhzBlnEKWaPX2xrFaLltii/6rmhqFMJqffUgknuRdpYlHw==} + engines: {node: '>=18'} + core-js-compat@3.37.1: resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} @@ -5161,6 +5376,10 @@ packages: resolution: {integrity: sha512-VC2Gs20JcTyeQob6UViBLnyP0bYHkBh6EiKzot9vi2DmeGlFT9Wd7VG3NBrkNx/jYvFBeyDOMMHdHQhbtKLgHQ==} engines: {node: '>=16'} + cpy@11.1.0: + resolution: {integrity: sha512-QGHetPSSuprVs+lJmMDcivvrBwTKASzXQ5qxFvRC2RFESjjod71bDvFvhxTjDgkNjrrb72AI6JPjfYwxrIy33A==} + engines: {node: '>=18'} + create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -5271,6 +5490,15 @@ packages: supports-color: optional: true + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} @@ -5283,6 +5511,10 @@ packages: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -5386,10 +5618,18 @@ packages: resolution: {integrity: sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ==} engines: {node: '>= 8.0'} + docker-modem@5.0.3: + resolution: {integrity: sha512-89zhop5YVhcPEt5FpUFGr3cDyceGhq/F9J+ZndQ4KfqNvfbJpPMfgeixFgUj5OjCYAboElqODxY5Z1EBsSa6sg==} + engines: {node: '>= 8.0'} + dockerode@3.3.5: resolution: {integrity: sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA==} engines: {node: '>= 8.0'} + dockerode@4.0.2: + resolution: {integrity: sha512-9wM1BVpVMFr2Pw3eJNXrYYt6DT9k0xMcsSCjtPvyQ+xa1iPg/Mo3T/gUcwI0B2cczqCeCYRPF8yFYDwtFXT0+w==} + engines: {node: '>= 8.0'} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -5544,6 +5784,10 @@ packages: engines: {node: '>=4'} hasBin: true + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + eol@0.9.1: resolution: {integrity: sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==} @@ -5897,16 +6141,19 @@ packages: eslint@8.50.0: resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.53.0: resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true esm@3.2.25: @@ -6112,10 +6359,6 @@ packages: file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -6273,6 +6516,7 @@ packages: gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. generate-function@2.3.1: resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} @@ -6413,6 +6657,10 @@ packages: resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + globby@14.0.2: + resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==} + engines: {node: '>=18'} + globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} @@ -6505,6 +6753,9 @@ packages: resolution: {integrity: sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==} engines: {node: '>=8'} + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + hono@4.0.1: resolution: {integrity: sha512-S9cREGPJIAK437RhroOf1PGlJPIlt5itl69OmQ6onPLo5pdCbSHGL8v4uAKxrdHjcTyuoyvKPqWm5jv0dGkdFA==} engines: {node: '>=16.0.0'} @@ -7092,10 +7343,12 @@ packages: libsql@0.3.19: resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] libsql@0.4.1: resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -7287,9 +7540,11 @@ packages: loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} - lru-cache@10.2.2: - resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} - engines: {node: 14 || >=16.14} + loupe@3.1.2: + resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -7306,10 +7561,6 @@ packages: resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} engines: {node: '>=16.14'} - lru-cache@9.1.2: - resolution: {integrity: sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==} - engines: {node: 14 || >=16.14} - lru-queue@0.1.0: resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} @@ -7319,6 +7570,9 @@ packages: magic-string@0.30.10: resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} + make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -7346,6 +7600,12 @@ packages: peerDependencies: marked: '>=1 <12' + marked-terminal@7.1.0: + resolution: {integrity: sha512-+pvwa14KZL74MVXjYdPR3nSInhGhNvPce/3mqLVZT2oUvt654sL1XImFuLZ1pkA866IYZ3ikDTOFUIC7XzpZZg==} + engines: {node: '>=16.0.0'} + peerDependencies: + marked: '>=1 <14' + marked@9.1.6: resolution: {integrity: sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==} engines: {node: '>= 16'} @@ -7469,10 +7729,6 @@ packages: engines: {node: '>=18'} hasBin: true - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - micromatch@4.0.7: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} @@ -7782,6 +8038,7 @@ packages: npmlog@6.0.2: resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. npx-import@1.1.4: resolution: {integrity: sha512-3ShymTWOgqGyNlh5lMJAejLuIv3W1K3fbI5Ewc6YErZU3Sp0PqsNs8UIU1O8z5+KVl/Du5ag56Gza9vdorGEoA==} @@ -7911,10 +8168,18 @@ packages: resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-event@6.0.1: + resolution: {integrity: sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==} + engines: {node: '>=16.17'} + p-filter@3.0.0: resolution: {integrity: sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-filter@4.1.0: + resolution: {integrity: sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==} + engines: {node: '>=18'} + p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} @@ -7963,10 +8228,18 @@ packages: resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==} engines: {node: '>=16'} + p-map@7.0.2: + resolution: {integrity: sha512-z4cYYMMdKHzw4O5UkWJImbZynVIo0lSGTXc7bzB1e/rrDqkgGUNysK/o4bTr+0+xKvvLoTyGqYC4Fgljy9qe1Q==} + engines: {node: '>=18'} + p-timeout@5.1.0: resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} engines: {node: '>=12'} + p-timeout@6.1.2: + resolution: {integrity: sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==} + engines: {node: '>=14.16'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -7994,6 +8267,15 @@ packages: resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==} engines: {node: '>=10'} + parse5-htmlparser2-tree-adapter@6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + + parse5@5.1.1: + resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -8050,12 +8332,20 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + path-type@5.0.0: + resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} + engines: {node: '>=12'} + pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + pause-stream@0.0.11: resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} @@ -8068,6 +8358,9 @@ packages: pg-connection-string@2.6.4: resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} + pg-connection-string@2.7.0: + resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==} + pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} @@ -8081,9 +8374,17 @@ packages: peerDependencies: pg: '>=8.0' + pg-pool@3.7.0: + resolution: {integrity: sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==} + peerDependencies: + pg: '>=8.0' + pg-protocol@1.6.1: resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==} + pg-protocol@1.7.0: + resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==} + pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} @@ -8101,6 +8402,15 @@ packages: pg-native: optional: true + pg@8.13.0: + resolution: {integrity: sha512-34wkUTh3SxTClfoHB3pQ7bIMvw9dpFU1audQQeZG837fmHfHpr14n/AELVDoOYVDW2h5RDWU78tFjkD+erSBsw==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + pgpass@1.0.5: resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} @@ -8342,6 +8652,9 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qrcode-terminal@0.11.0: resolution: {integrity: sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==} hasBin: true @@ -8538,6 +8851,12 @@ packages: peerDependencies: typescript: '>=3.0.3' + resolve-tspaths@0.8.22: + resolution: {integrity: sha512-x9loBJyTLdx3grlcNpH/Y2t8IkfadtbzYhzpo683C6olazn0/4Y3cfSBiqDA0f2vSmq5tITKJCN9e1ezBh6jhA==} + hasBin: true + peerDependencies: + typescript: '>=3.0.3' + resolve.exports@2.0.2: resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} engines: {node: '>=10'} @@ -8550,10 +8869,6 @@ packages: resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} hasBin: true - resolve@1.22.4: - resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} - hasBin: true - resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -8598,6 +8913,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@5.0.0: @@ -8625,13 +8941,13 @@ packages: engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true - rollup@4.18.0: - resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} + rollup@4.18.1: + resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rollup@4.18.1: - resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==} + rollup@4.24.0: + resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -8809,6 +9125,10 @@ packages: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + slice-ansi@2.1.0: resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} engines: {node: '>=6'} @@ -8828,6 +9148,9 @@ packages: smob@0.0.6: resolution: {integrity: sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw==} + smob@1.5.0: + resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + socks-proxy-agent@6.2.1: resolution: {integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==} engines: {node: '>= 10'} @@ -9205,14 +9528,32 @@ packages: tinybench@2.8.0: resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.0: + resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} + tinypool@0.8.4: resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} engines: {node: '>=14.0.0'} + tinypool@1.0.1: + resolution: {integrity: sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + tinyspy@2.2.1: resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} engines: {node: '>=14.0.0'} + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -9305,6 +9646,9 @@ packages: tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + tsup@7.2.0: resolution: {integrity: sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==} engines: {node: '>=16.14'} @@ -9360,6 +9704,11 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tsx@4.19.1: + resolution: {integrity: sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA==} + engines: {node: '>=18.0.0'} + hasBin: true + tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -9504,6 +9853,16 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@5.6.1-rc: + resolution: {integrity: sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + ua-parser-js@1.0.38: resolution: {integrity: sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==} @@ -9516,6 +9875,9 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici@5.28.2: resolution: {integrity: sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==} engines: {node: '>=14.0'} @@ -9547,6 +9909,10 @@ packages: resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} engines: {node: '>=4'} + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + unique-filename@1.1.1: resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} @@ -9615,6 +9981,10 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + uuid@7.0.3: resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==} hasBin: true @@ -9664,6 +10034,11 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true + vite-node@2.1.2: + resolution: {integrity: sha512-HPcGNN5g/7I2OtPjLqgOtCRu/qhVvBxTUD3qzitmL0SrG1cWFzxzhMDWussxSbrRYWqnKf8P2jiNhPMSN+ymsQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + vite-tsconfig-paths@4.3.2: resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} peerDependencies: @@ -9753,23 +10128,48 @@ packages: jsdom: optional: true - vlq@1.0.1: - resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} - - walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - - wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - - web-streams-polyfill@3.2.1: - resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} - engines: {node: '>= 8'} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - webidl-conversions@4.0.2: + vitest@2.1.2: + resolution: {integrity: sha512-veNjLizOMkRrJ6xxb+pvxN6/QAWg95mzcRjtmkepXdN87FNfxAss9RKe2far/G9cQpipfgP2taqg0KiWsquj8A==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.2 + '@vitest/ui': 2.1.2 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + vlq@1.0.1: + resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + web-streams-polyfill@3.2.1: + resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} + engines: {node: '>= 8'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} webidl-conversions@5.0.0: @@ -9830,6 +10230,11 @@ packages: engines: {node: '>=8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} @@ -10034,6 +10439,11 @@ packages: engines: {node: '>= 16.0.0'} hasBin: true + zx@8.1.9: + resolution: {integrity: sha512-UHuLHphHmsBYKkAchkSrEN4nzDyagafqC9HUxtc1J7eopaScW6H9dsLJ1lmkAntnLtDTGoM8fa+jrJrXiIfKFA==} + engines: {node: '>= 12.17.0'} + hasBin: true + snapshots: '@aashutoshrathi/word-wrap@1.2.6': {} @@ -10055,6 +10465,16 @@ snapshots: marked-terminal: 6.2.0(marked@9.1.6) semver: 7.6.2 + '@arethetypeswrong/cli@0.16.4': + dependencies: + '@arethetypeswrong/core': 0.16.4 + chalk: 4.1.2 + cli-table3: 0.6.3 + commander: 10.0.1 + marked: 9.1.6 + marked-terminal: 7.1.0(marked@9.1.6) + semver: 7.6.2 + '@arethetypeswrong/core@0.15.1': dependencies: '@andrewbranch/untar.js': 1.0.3 @@ -10064,6 +10484,16 @@ snapshots: typescript: 5.3.3 validate-npm-package-name: 5.0.0 + '@arethetypeswrong/core@0.16.4': + dependencies: + '@andrewbranch/untar.js': 1.0.3 + cjs-module-lexer: 1.4.1 + fflate: 0.8.2 + lru-cache: 10.4.3 + semver: 7.6.2 + typescript: 5.6.1-rc + validate-npm-package-name: 5.0.0 + '@ava/typescript@5.0.0': dependencies: escape-string-regexp: 5.0.0 @@ -10112,7 +10542,7 @@ snapshots: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10149,7 +10579,7 @@ snapshots: '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -10199,7 +10629,7 @@ snapshots: '@smithy/util-stream': 2.2.0 '@smithy/util-utf8': 2.3.0 '@smithy/util-waiter': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -10207,8 +10637,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10253,7 +10683,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10290,15 +10720,15 @@ snapshots: '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/client-sso-oidc@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10335,9 +10765,8 @@ snapshots: '@smithy/util-middleware': 3.0.0 '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.478.0': @@ -10378,7 +10807,7 @@ snapshots: '@smithy/util-endpoints': 1.2.0 '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -10421,7 +10850,7 @@ snapshots: '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -10464,7 +10893,7 @@ snapshots: '@smithy/util-middleware': 3.0.0 '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -10509,52 +10938,7 @@ snapshots: '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 fast-xml-parser: 4.2.5 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-sts@3.569.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -10564,7 +10948,7 @@ snapshots: '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.569.0 '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 '@aws-sdk/middleware-logger': 3.568.0 '@aws-sdk/middleware-recursion-detection': 3.567.0 @@ -10599,16 +10983,16 @@ snapshots: '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0': + '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10645,8 +11029,9 @@ snapshots: '@smithy/util-middleware': 3.0.0 '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/core@3.477.0': @@ -10656,7 +11041,7 @@ snapshots: '@smithy/signature-v4': 2.3.0 '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/core@3.567.0': dependencies: @@ -10666,7 +11051,7 @@ snapshots: '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 fast-xml-parser: 4.2.5 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/core@3.582.0': dependencies: @@ -10676,7 +11061,7 @@ snapshots: '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 fast-xml-parser: 4.2.5 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-cognito-identity@3.569.0': dependencies: @@ -10684,7 +11069,7 @@ snapshots: '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -10693,21 +11078,21 @@ snapshots: '@aws-sdk/types': 3.468.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-env@3.568.0': dependencies: '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-env@3.577.0': dependencies: '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-http@3.568.0': dependencies: @@ -10719,7 +11104,7 @@ snapshots: '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-http@3.582.0': dependencies: @@ -10731,7 +11116,7 @@ snapshots: '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 '@smithy/util-stream': 3.0.1 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-ini@3.478.0': dependencies: @@ -10744,27 +11129,10 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) @@ -10777,7 +11145,7 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -10788,20 +11156,20 @@ snapshots: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -10811,7 +11179,7 @@ snapshots: '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -10828,27 +11196,8 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': @@ -10864,7 +11213,7 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - '@aws-sdk/client-sts' @@ -10877,13 +11226,13 @@ snapshots: '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - '@aws-sdk/client-sts' @@ -10902,7 +11251,7 @@ snapshots: '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - '@aws-sdk/client-sts' @@ -10914,7 +11263,7 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-process@3.568.0': dependencies: @@ -10922,7 +11271,7 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-process@3.577.0': dependencies: @@ -10930,7 +11279,7 @@ snapshots: '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-sso@3.478.0': dependencies: @@ -10940,7 +11289,7 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -10952,7 +11301,7 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -10965,7 +11314,7 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -10978,7 +11327,7 @@ snapshots: '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -10988,31 +11337,23 @@ snapshots: '@aws-sdk/types': 3.468.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': dependencies: - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: @@ -11026,12 +11367,12 @@ snapshots: '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -11041,60 +11382,60 @@ snapshots: '@aws-sdk/types': 3.468.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-host-header@3.567.0': dependencies: '@aws-sdk/types': 3.567.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-host-header@3.577.0': dependencies: '@aws-sdk/types': 3.577.0 '@smithy/protocol-http': 4.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-logger@3.468.0': dependencies: '@aws-sdk/types': 3.468.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-logger@3.568.0': dependencies: '@aws-sdk/types': 3.567.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-logger@3.577.0': dependencies: '@aws-sdk/types': 3.577.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-recursion-detection@3.468.0': dependencies: '@aws-sdk/types': 3.468.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-recursion-detection@3.567.0': dependencies: '@aws-sdk/types': 3.567.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-recursion-detection@3.577.0': dependencies: '@aws-sdk/types': 3.577.0 '@smithy/protocol-http': 4.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-signing@3.468.0': dependencies: @@ -11104,7 +11445,7 @@ snapshots: '@smithy/signature-v4': 2.3.0 '@smithy/types': 2.12.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-user-agent@3.478.0': dependencies: @@ -11112,7 +11453,7 @@ snapshots: '@aws-sdk/util-endpoints': 3.478.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-user-agent@3.567.0': dependencies: @@ -11120,7 +11461,7 @@ snapshots: '@aws-sdk/util-endpoints': 3.567.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-user-agent@3.583.0': dependencies: @@ -11128,7 +11469,7 @@ snapshots: '@aws-sdk/util-endpoints': 3.583.0 '@smithy/protocol-http': 4.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/region-config-resolver@3.470.0': dependencies: @@ -11136,7 +11477,7 @@ snapshots: '@smithy/types': 2.12.0 '@smithy/util-config-provider': 2.3.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/region-config-resolver@3.567.0': dependencies: @@ -11145,7 +11486,7 @@ snapshots: '@smithy/types': 2.12.0 '@smithy/util-config-provider': 2.3.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/region-config-resolver@3.577.0': dependencies: @@ -11154,7 +11495,7 @@ snapshots: '@smithy/types': 3.0.0 '@smithy/util-config-provider': 3.0.0 '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/token-providers@3.478.0': dependencies: @@ -11194,7 +11535,7 @@ snapshots: '@smithy/util-endpoints': 1.2.0 '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -11205,110 +11546,110 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/types@3.468.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/types@3.567.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/types@3.577.0': dependencies: '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-endpoints@3.478.0': dependencies: '@aws-sdk/types': 3.468.0 '@smithy/util-endpoints': 1.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-endpoints@3.567.0': dependencies: '@aws-sdk/types': 3.567.0 '@smithy/types': 2.12.0 '@smithy/util-endpoints': 1.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-endpoints@3.583.0': dependencies: '@aws-sdk/types': 3.577.0 '@smithy/types': 3.0.0 '@smithy/util-endpoints': 2.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-locate-window@3.568.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-user-agent-browser@3.468.0': dependencies: '@aws-sdk/types': 3.468.0 '@smithy/types': 2.12.0 bowser: 2.11.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-user-agent-browser@3.567.0': dependencies: '@aws-sdk/types': 3.567.0 '@smithy/types': 2.12.0 bowser: 2.11.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-user-agent-browser@3.577.0': dependencies: '@aws-sdk/types': 3.577.0 '@smithy/types': 3.0.0 bowser: 2.11.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-user-agent-node@3.470.0': dependencies: '@aws-sdk/types': 3.468.0 '@smithy/node-config-provider': 2.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-user-agent-node@3.568.0': dependencies: '@aws-sdk/types': 3.567.0 '@smithy/node-config-provider': 2.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-user-agent-node@3.577.0': dependencies: '@aws-sdk/types': 3.577.0 '@smithy/node-config-provider': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-utf8-browser@3.259.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@babel/code-frame@7.10.4': dependencies: @@ -11344,7 +11685,7 @@ snapshots: '@babel/traverse': 7.24.6 '@babel/types': 7.24.6 convert-source-map: 2.0.0 - debug: 4.3.5 + debug: 4.3.7 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -11405,7 +11746,7 @@ snapshots: '@babel/core': 7.24.6 '@babel/helper-compilation-targets': 7.24.6 '@babel/helper-plugin-utils': 7.24.6 - debug: 4.3.5 + debug: 4.3.7 lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -12277,7 +12618,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - debug: 4.3.5 + debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -12862,7 +13203,7 @@ snapshots: '@eslint/eslintrc@3.1.0': dependencies: ajv: 6.12.6 - debug: 4.3.5 + debug: 4.3.7 espree: 10.0.1 globals: 14.0.0 ignore: 5.3.1 @@ -12890,7 +13231,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -12908,7 +13249,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -12919,7 +13260,7 @@ snapshots: chalk: 4.1.2 ci-info: 3.9.0 connect: 3.7.0 - debug: 4.3.5 + debug: 4.3.7 env-editor: 0.4.2 fast-glob: 3.3.2 find-yarn-workspace-root: 2.0.0 @@ -12987,7 +13328,7 @@ snapshots: '@expo/plist': 0.1.3 '@expo/sdk-runtime-versions': 1.0.0 chalk: 4.1.2 - debug: 4.3.5 + debug: 4.3.7 find-up: 5.0.0 getenv: 1.0.0 glob: 7.1.6 @@ -13032,14 +13373,14 @@ snapshots: rimraf: 2.7.1 sudo-prompt: 8.2.5 tmp: 0.0.33 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - supports-color '@expo/env@0.3.0': dependencies: chalk: 4.1.2 - debug: 4.3.5 + debug: 4.3.7 dotenv: 16.4.5 dotenv-expand: 11.0.6 getenv: 1.0.0 @@ -13078,7 +13419,7 @@ snapshots: '@expo/json-file': 8.3.3 '@expo/spawn-async': 1.7.2 chalk: 4.1.2 - debug: 4.3.5 + debug: 4.3.7 find-yarn-workspace-root: 2.0.0 fs-extra: 9.1.0 getenv: 1.0.0 @@ -13124,7 +13465,7 @@ snapshots: '@expo/image-utils': 0.5.1(encoding@0.1.13) '@expo/json-file': 8.3.3 '@react-native/normalize-colors': 0.74.83 - debug: 4.3.5 + debug: 4.3.7 expo-modules-autolinking: 1.11.1 fs-extra: 9.1.0 resolve-from: 5.0.0 @@ -13313,6 +13654,8 @@ snapshots: '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/trace-mapping@0.3.18': dependencies: '@jridgewell/resolve-uri': 3.1.0 @@ -13429,7 +13772,7 @@ snapshots: '@miniflare/shared@2.14.2': dependencies: - '@types/better-sqlite3': 7.6.10 + '@types/better-sqlite3': 7.6.11 kleur: 4.1.5 npx-import: 1.1.4 picomatch: 2.3.1 @@ -13482,10 +13825,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) '@opentelemetry/api@1.8.0': {} @@ -13622,7 +13965,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13632,7 +13975,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13659,14 +14002,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13755,16 +14098,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13779,7 +14122,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13793,7 +14136,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13816,12 +14159,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) optionalDependencies: '@types/react': 18.3.1 @@ -13852,23 +14195,40 @@ snapshots: optionalDependencies: rollup: 3.27.2 - '@rollup/plugin-typescript@11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@rollup/plugin-terser@0.4.4(rollup@4.24.0)': + dependencies: + serialize-javascript: 6.0.1 + smob: 1.5.0 + terser: 5.31.0 + optionalDependencies: + rollup: 4.24.0 + + '@rollup/plugin-typescript@11.1.0(rollup@3.20.7)(tslib@2.7.0)(typescript@5.6.3)': dependencies: '@rollup/pluginutils': 5.0.2(rollup@3.20.7) resolve: 1.22.1 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 optionalDependencies: rollup: 3.20.7 - tslib: 2.6.2 + tslib: 2.7.0 - '@rollup/plugin-typescript@11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@rollup/plugin-typescript@11.1.1(rollup@3.27.2)(tslib@2.7.0)(typescript@5.6.3)': dependencies: '@rollup/pluginutils': 5.0.2(rollup@3.27.2) resolve: 1.22.2 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 optionalDependencies: rollup: 3.27.2 - tslib: 2.6.2 + tslib: 2.7.0 + + '@rollup/plugin-typescript@11.1.6(rollup@4.24.0)(tslib@2.7.0)(typescript@5.6.3)': + dependencies: + '@rollup/pluginutils': 5.1.2(rollup@4.24.0) + resolve: 1.22.8 + typescript: 5.6.3 + optionalDependencies: + rollup: 4.24.0 + tslib: 2.7.0 '@rollup/pluginutils@5.0.2(rollup@3.20.7)': dependencies: @@ -13886,102 +14246,110 @@ snapshots: optionalDependencies: rollup: 3.27.2 - '@rollup/rollup-android-arm-eabi@4.18.0': - optional: true + '@rollup/pluginutils@5.1.2(rollup@4.24.0)': + dependencies: + '@types/estree': 1.0.5 + estree-walker: 2.0.2 + picomatch: 2.3.1 + optionalDependencies: + rollup: 4.24.0 '@rollup/rollup-android-arm-eabi@4.18.1': optional: true - '@rollup/rollup-android-arm64@4.18.0': + '@rollup/rollup-android-arm-eabi@4.24.0': optional: true '@rollup/rollup-android-arm64@4.18.1': optional: true - '@rollup/rollup-darwin-arm64@4.18.0': + '@rollup/rollup-android-arm64@4.24.0': optional: true '@rollup/rollup-darwin-arm64@4.18.1': optional: true - '@rollup/rollup-darwin-x64@4.18.0': + '@rollup/rollup-darwin-arm64@4.24.0': optional: true '@rollup/rollup-darwin-x64@4.18.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.18.0': + '@rollup/rollup-darwin-x64@4.24.0': optional: true '@rollup/rollup-linux-arm-gnueabihf@4.18.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.18.0': + '@rollup/rollup-linux-arm-gnueabihf@4.24.0': optional: true '@rollup/rollup-linux-arm-musleabihf@4.18.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.18.0': + '@rollup/rollup-linux-arm-musleabihf@4.24.0': optional: true '@rollup/rollup-linux-arm64-gnu@4.18.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.18.0': + '@rollup/rollup-linux-arm64-gnu@4.24.0': optional: true '@rollup/rollup-linux-arm64-musl@4.18.1': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': + '@rollup/rollup-linux-arm64-musl@4.24.0': optional: true '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.18.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': optional: true '@rollup/rollup-linux-riscv64-gnu@4.18.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.18.0': + '@rollup/rollup-linux-riscv64-gnu@4.24.0': optional: true '@rollup/rollup-linux-s390x-gnu@4.18.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.18.0': + '@rollup/rollup-linux-s390x-gnu@4.24.0': optional: true '@rollup/rollup-linux-x64-gnu@4.18.1': optional: true - '@rollup/rollup-linux-x64-musl@4.18.0': + '@rollup/rollup-linux-x64-gnu@4.24.0': optional: true '@rollup/rollup-linux-x64-musl@4.18.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.18.0': + '@rollup/rollup-linux-x64-musl@4.24.0': optional: true '@rollup/rollup-win32-arm64-msvc@4.18.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.18.0': + '@rollup/rollup-win32-arm64-msvc@4.24.0': optional: true '@rollup/rollup-win32-ia32-msvc@4.18.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.18.0': + '@rollup/rollup-win32-ia32-msvc@4.24.0': optional: true '@rollup/rollup-win32-x64-msvc@4.18.1': optional: true + '@rollup/rollup-win32-x64-msvc@4.24.0': + optional: true + '@segment/loosely-validate-event@2.0.0': dependencies: component-type: 1.2.2 @@ -14001,6 +14369,8 @@ snapshots: '@sindresorhus/is@4.6.0': {} + '@sindresorhus/merge-streams@2.3.0': {} + '@sinonjs/commons@3.0.1': dependencies: type-detect: 4.0.8 @@ -14012,12 +14382,12 @@ snapshots: '@smithy/abort-controller@2.2.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/abort-controller@3.0.0': dependencies: '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/config-resolver@2.2.0': dependencies: @@ -14025,7 +14395,7 @@ snapshots: '@smithy/types': 2.12.0 '@smithy/util-config-provider': 2.3.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/config-resolver@3.0.0': dependencies: @@ -14033,7 +14403,7 @@ snapshots: '@smithy/types': 3.0.0 '@smithy/util-config-provider': 3.0.0 '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/core@1.4.2': dependencies: @@ -14044,7 +14414,7 @@ snapshots: '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/core@2.0.1': dependencies: @@ -14055,7 +14425,7 @@ snapshots: '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/credential-provider-imds@2.3.0': dependencies: @@ -14063,7 +14433,7 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 '@smithy/url-parser': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/credential-provider-imds@3.0.0': dependencies: @@ -14071,37 +14441,37 @@ snapshots: '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 '@smithy/url-parser': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/eventstream-codec@2.2.0': dependencies: '@aws-crypto/crc32': 3.0.0 '@smithy/types': 2.12.0 '@smithy/util-hex-encoding': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/eventstream-serde-browser@2.2.0': dependencies: '@smithy/eventstream-serde-universal': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/eventstream-serde-config-resolver@2.2.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/eventstream-serde-node@2.2.0': dependencies: '@smithy/eventstream-serde-universal': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/eventstream-serde-universal@2.2.0': dependencies: '@smithy/eventstream-codec': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/fetch-http-handler@2.5.0': dependencies: @@ -14109,7 +14479,7 @@ snapshots: '@smithy/querystring-builder': 2.2.0 '@smithy/types': 2.12.0 '@smithy/util-base64': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/fetch-http-handler@3.0.1': dependencies: @@ -14117,51 +14487,51 @@ snapshots: '@smithy/querystring-builder': 3.0.0 '@smithy/types': 3.0.0 '@smithy/util-base64': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/hash-node@2.2.0': dependencies: '@smithy/types': 2.12.0 '@smithy/util-buffer-from': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/hash-node@3.0.0': dependencies: '@smithy/types': 3.0.0 '@smithy/util-buffer-from': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/invalid-dependency@2.2.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/invalid-dependency@3.0.0': dependencies: '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/is-array-buffer@2.2.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/is-array-buffer@3.0.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/middleware-content-length@2.2.0': dependencies: '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/middleware-content-length@3.0.0': dependencies: '@smithy/protocol-http': 4.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/middleware-endpoint@2.5.1': dependencies: @@ -14171,7 +14541,7 @@ snapshots: '@smithy/types': 2.12.0 '@smithy/url-parser': 2.2.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/middleware-endpoint@3.0.0': dependencies: @@ -14181,7 +14551,7 @@ snapshots: '@smithy/types': 3.0.0 '@smithy/url-parser': 3.0.0 '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/middleware-retry@2.3.1': dependencies: @@ -14192,7 +14562,7 @@ snapshots: '@smithy/types': 2.12.0 '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 uuid: 9.0.1 '@smithy/middleware-retry@3.0.1': @@ -14204,42 +14574,42 @@ snapshots: '@smithy/types': 3.0.0 '@smithy/util-middleware': 3.0.0 '@smithy/util-retry': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 uuid: 9.0.1 '@smithy/middleware-serde@2.3.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/middleware-serde@3.0.0': dependencies: '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/middleware-stack@2.2.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/middleware-stack@3.0.0': dependencies: '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/node-config-provider@2.3.0': dependencies: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/node-config-provider@3.0.0': dependencies: '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/node-http-handler@2.5.0': dependencies: @@ -14247,7 +14617,7 @@ snapshots: '@smithy/protocol-http': 3.3.0 '@smithy/querystring-builder': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/node-http-handler@3.0.0': dependencies: @@ -14255,49 +14625,49 @@ snapshots: '@smithy/protocol-http': 4.0.0 '@smithy/querystring-builder': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/property-provider@2.2.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/property-provider@3.0.0': dependencies: '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/protocol-http@3.3.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/protocol-http@4.0.0': dependencies: '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/querystring-builder@2.2.0': dependencies: '@smithy/types': 2.12.0 '@smithy/util-uri-escape': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/querystring-builder@3.0.0': dependencies: '@smithy/types': 3.0.0 '@smithy/util-uri-escape': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/querystring-parser@2.2.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/querystring-parser@3.0.0': dependencies: '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/service-error-classification@2.1.5': dependencies: @@ -14310,12 +14680,12 @@ snapshots: '@smithy/shared-ini-file-loader@2.4.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/shared-ini-file-loader@3.0.0': dependencies: '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/signature-v4@2.3.0': dependencies: @@ -14325,7 +14695,7 @@ snapshots: '@smithy/util-middleware': 2.2.0 '@smithy/util-uri-escape': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/signature-v4@3.0.0': dependencies: @@ -14335,7 +14705,7 @@ snapshots: '@smithy/util-middleware': 3.0.0 '@smithy/util-uri-escape': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/smithy-client@2.5.1': dependencies: @@ -14344,7 +14714,7 @@ snapshots: '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/smithy-client@3.0.1': dependencies: @@ -14353,73 +14723,73 @@ snapshots: '@smithy/protocol-http': 4.0.0 '@smithy/types': 3.0.0 '@smithy/util-stream': 3.0.1 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/types@2.12.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/types@3.0.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/url-parser@2.2.0': dependencies: '@smithy/querystring-parser': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/url-parser@3.0.0': dependencies: '@smithy/querystring-parser': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-base64@2.3.0': dependencies: '@smithy/util-buffer-from': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-base64@3.0.0': dependencies: '@smithy/util-buffer-from': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-body-length-browser@2.2.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-body-length-browser@3.0.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-body-length-node@2.3.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-body-length-node@3.0.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-buffer-from@2.2.0': dependencies: '@smithy/is-array-buffer': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-buffer-from@3.0.0': dependencies: '@smithy/is-array-buffer': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-config-provider@2.3.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-config-provider@3.0.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-defaults-mode-browser@2.2.1': dependencies: @@ -14427,7 +14797,7 @@ snapshots: '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 bowser: 2.11.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-defaults-mode-browser@3.0.1': dependencies: @@ -14435,7 +14805,7 @@ snapshots: '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 bowser: 2.11.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-defaults-mode-node@2.3.1': dependencies: @@ -14445,7 +14815,7 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-defaults-mode-node@3.0.1': dependencies: @@ -14455,49 +14825,49 @@ snapshots: '@smithy/property-provider': 3.0.0 '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-endpoints@1.2.0': dependencies: '@smithy/node-config-provider': 2.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-endpoints@2.0.0': dependencies: '@smithy/node-config-provider': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-hex-encoding@2.2.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-hex-encoding@3.0.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-middleware@2.2.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-middleware@3.0.0': dependencies: '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-retry@2.2.0': dependencies: '@smithy/service-error-classification': 2.1.5 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-retry@3.0.0': dependencies: '@smithy/service-error-classification': 3.0.0 '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-stream@2.2.0': dependencies: @@ -14508,7 +14878,7 @@ snapshots: '@smithy/util-buffer-from': 2.2.0 '@smithy/util-hex-encoding': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-stream@3.0.1': dependencies: @@ -14519,31 +14889,31 @@ snapshots: '@smithy/util-buffer-from': 3.0.0 '@smithy/util-hex-encoding': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-uri-escape@2.2.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-uri-escape@3.0.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-utf8@2.3.0': dependencies: '@smithy/util-buffer-from': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-utf8@3.0.0': dependencies: '@smithy/util-buffer-from': 3.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-waiter@2.2.0': dependencies: '@smithy/abort-controller': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@tidbcloud/serverless@0.1.1': {} @@ -14584,6 +14954,10 @@ snapshots: dependencies: '@types/node': 20.12.12 + '@types/better-sqlite3@7.6.11': + dependencies: + '@types/node': 20.12.12 + '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 @@ -14604,12 +14978,20 @@ snapshots: '@types/node': 20.12.12 '@types/ssh2': 1.15.0 + '@types/dockerode@3.3.31': + dependencies: + '@types/docker-modem': 3.0.6 + '@types/node': 20.12.12 + '@types/ssh2': 1.15.0 + '@types/emscripten@1.39.11': {} '@types/estree@1.0.1': {} '@types/estree@1.0.5': {} + '@types/estree@1.0.6': {} + '@types/express-serve-static-core@4.19.0': dependencies: '@types/node': 20.12.12 @@ -14680,6 +15062,10 @@ snapshots: dependencies: undici-types: 5.26.5 + '@types/node@22.7.5': + dependencies: + undici-types: 6.19.8 + '@types/normalize-package-data@2.4.1': {} '@types/pg@8.11.6': @@ -14735,6 +15121,8 @@ snapshots: '@types/stack-utils@2.0.3': {} + '@types/uuid@10.0.0': {} + '@types/uuid@9.0.8': {} '@types/which@3.0.0': {} @@ -15072,22 +15460,56 @@ snapshots: '@vitest/utils': 1.6.0 chai: 4.4.1 + '@vitest/expect@2.1.2': + dependencies: + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@22.7.5)(lightningcss@1.25.1)(terser@5.31.0))': + dependencies: + '@vitest/spy': 2.1.2 + estree-walker: 3.0.3 + magic-string: 0.30.11 + optionalDependencies: + vite: 5.3.3(@types/node@22.7.5)(lightningcss@1.25.1)(terser@5.31.0) + + '@vitest/pretty-format@2.1.2': + dependencies: + tinyrainbow: 1.2.0 + '@vitest/runner@1.6.0': dependencies: '@vitest/utils': 1.6.0 p-limit: 5.0.0 pathe: 1.1.2 + '@vitest/runner@2.1.2': + dependencies: + '@vitest/utils': 2.1.2 + pathe: 1.1.2 + '@vitest/snapshot@1.6.0': dependencies: magic-string: 0.30.10 pathe: 1.1.2 pretty-format: 29.7.0 + '@vitest/snapshot@2.1.2': + dependencies: + '@vitest/pretty-format': 2.1.2 + magic-string: 0.30.11 + pathe: 1.1.2 + '@vitest/spy@1.6.0': dependencies: tinyspy: 2.2.1 + '@vitest/spy@2.1.2': + dependencies: + tinyspy: 3.0.2 + '@vitest/ui@1.6.0(vitest@1.6.0)': dependencies: '@vitest/utils': 1.6.0 @@ -15106,9 +15528,15 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 - '@xata.io/client@0.29.4(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@vitest/utils@2.1.2': dependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + '@vitest/pretty-format': 2.1.2 + loupe: 3.1.2 + tinyrainbow: 1.2.0 + + '@xata.io/client@0.29.4(typescript@5.6.3)': + dependencies: + typescript: 5.6.3 '@xmldom/xmldom@0.7.13': {} @@ -15182,6 +15610,10 @@ snapshots: dependencies: type-fest: 3.13.1 + ansi-escapes@7.0.0: + dependencies: + environment: 1.1.0 + ansi-fragments@0.2.1: dependencies: colorette: 1.4.0 @@ -15322,13 +15754,15 @@ snapshots: assertion-error@1.1.0: {} + assertion-error@2.0.1: {} + ast-types@0.15.2: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 ast-types@0.16.1: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 astral-regex@1.0.0: {} @@ -15473,6 +15907,11 @@ snapshots: dependencies: open: 8.4.2 + better-sqlite3@11.3.0: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.2 + better-sqlite3@8.7.0: dependencies: bindings: 1.5.0 @@ -15541,10 +15980,6 @@ snapshots: dependencies: balanced-match: 1.0.2 - braces@3.0.2: - dependencies: - fill-range: 7.0.1 - braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -15644,7 +16079,7 @@ snapshots: '@npmcli/fs': 3.1.1 fs-minipass: 3.0.3 glob: 10.4.1 - lru-cache: 10.2.2 + lru-cache: 10.4.3 minipass: 7.1.2 minipass-collect: 2.0.1 minipass-flush: 1.0.5 @@ -15692,7 +16127,7 @@ snapshots: capnp-ts@0.7.0: dependencies: debug: 4.3.4 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - supports-color @@ -15715,6 +16150,14 @@ snapshots: pathval: 1.1.1 type-detect: 4.0.8 + chai@5.1.1: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.2 + pathval: 2.0.0 + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -15736,6 +16179,8 @@ snapshots: dependencies: get-func-name: 2.0.2 + check-error@2.1.1: {} + chokidar@3.5.3: dependencies: anymatch: 3.1.3 @@ -15783,6 +16228,8 @@ snapshots: ci-parallel-vars@1.0.1: {} + cjs-module-lexer@1.4.1: {} + clean-regexp@1.0.0: dependencies: escape-string-regexp: 1.0.5 @@ -15811,6 +16258,15 @@ snapshots: dependencies: restore-cursor: 3.1.0 + cli-highlight@2.1.11: + dependencies: + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.0 + cli-spinners@2.9.2: {} cli-table3@0.6.3: @@ -15819,6 +16275,12 @@ snapshots: optionalDependencies: '@colors/colors': 1.5.0 + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + cli-truncate@3.1.0: dependencies: slice-ansi: 5.0.0 @@ -15980,6 +16442,11 @@ snapshots: dependencies: is-what: 4.1.16 + copy-file@11.0.0: + dependencies: + graceful-fs: 4.2.11 + p-event: 6.0.1 + core-js-compat@3.37.1: dependencies: browserslist: 4.23.0 @@ -16021,6 +16488,15 @@ snapshots: p-filter: 3.0.0 p-map: 6.0.0 + cpy@11.1.0: + dependencies: + copy-file: 11.0.0 + globby: 14.0.2 + junk: 4.0.1 + micromatch: 4.0.7 + p-filter: 4.1.0 + p-map: 7.0.2 + create-require@1.1.1: {} cross-env@7.0.3: @@ -16116,6 +16592,10 @@ snapshots: dependencies: ms: 2.1.2 + debug@4.3.7: + dependencies: + ms: 2.1.3 + decamelize@1.2.0: {} decompress-response@6.0.0: @@ -16126,6 +16606,8 @@ snapshots: dependencies: type-detect: 4.0.8 + deep-eql@5.0.2: {} + deep-extend@0.6.0: {} deep-is@0.1.4: {} @@ -16217,6 +16699,15 @@ snapshots: transitivePeerDependencies: - supports-color + docker-modem@5.0.3: + dependencies: + debug: 4.3.5 + readable-stream: 3.6.2 + split-ca: 1.0.1 + ssh2: 1.15.0 + transitivePeerDependencies: + - supports-color + dockerode@3.3.5: dependencies: '@balena/dockerignore': 1.0.2 @@ -16225,6 +16716,14 @@ snapshots: transitivePeerDependencies: - supports-color + dockerode@4.0.2: + dependencies: + '@balena/dockerignore': 1.0.2 + docker-modem: 5.0.3 + tar-fs: 2.0.1 + transitivePeerDependencies: + - supports-color + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -16281,7 +16780,7 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.3.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.3.0)(mysql2@3.11.0)(pg@8.13.0)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.0)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 '@cloudflare/workers-types': 4.20240524.0 @@ -16289,16 +16788,16 @@ snapshots: '@neondatabase/serverless': 0.9.3 '@opentelemetry/api': 1.8.0 '@planetscale/database': 1.18.0 - '@types/better-sqlite3': 7.6.10 + '@types/better-sqlite3': 7.6.11 '@types/pg': 8.11.6 '@types/sql.js': 1.4.9 '@vercel/postgres': 0.8.0 - better-sqlite3: 9.6.0 + better-sqlite3: 11.3.0 bun-types: 1.0.3 - knex: 2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7) + knex: 2.5.1(better-sqlite3@11.3.0)(mysql2@3.11.0)(pg@8.13.0)(sqlite3@5.1.7) kysely: 0.25.0 mysql2: 3.11.0 - pg: 8.11.5 + pg: 8.13.0 postgres: 3.4.4 sql.js: 1.10.3 sqlite3: 5.1.7 @@ -16343,6 +16842,8 @@ snapshots: envinfo@7.13.0: {} + environment@1.1.0: {} + eol@0.9.1: {} err-code@2.0.3: @@ -16789,7 +17290,7 @@ snapshots: dependencies: debug: 3.2.7 is-core-module: 2.13.0 - resolve: 1.22.4 + resolve: 1.22.8 transitivePeerDependencies: - supports-color @@ -17122,35 +17623,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) expo-modules-autolinking@1.11.1: dependencies: @@ -17164,24 +17665,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -17244,7 +17745,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.7 fast-glob@3.3.2: dependencies: @@ -17314,10 +17815,6 @@ snapshots: file-uri-to-path@1.0.0: {} - fill-range@7.0.1: - dependencies: - to-regex-range: 5.0.1 - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -17663,6 +18160,15 @@ snapshots: merge2: 1.4.1 slash: 4.0.0 + globby@14.0.2: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.2 + ignore: 5.3.1 + path-type: 5.0.0 + slash: 5.1.0 + unicorn-magic: 0.1.0 + globrex@0.1.2: {} gopd@1.0.1: @@ -17676,7 +18182,7 @@ snapshots: graphql-tag@2.12.6(graphql@15.8.0): dependencies: graphql: 15.8.0 - tslib: 2.6.2 + tslib: 2.7.0 graphql@15.8.0: {} @@ -17742,6 +18248,8 @@ snapshots: dependencies: source-map: 0.7.4 + highlight.js@10.7.3: {} + hono@4.0.1: {} hono@4.5.0: {} @@ -18264,7 +18772,7 @@ snapshots: kleur@4.1.5: {} - knex@2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7): + knex@2.5.1(better-sqlite3@11.3.0)(mysql2@3.11.0)(pg@8.13.0)(sqlite3@5.1.7): dependencies: colorette: 2.0.19 commander: 10.0.1 @@ -18281,14 +18789,15 @@ snapshots: tarn: 3.0.2 tildify: 2.0.0 optionalDependencies: - better-sqlite3: 8.7.0 - mysql2: 3.3.3 - pg: 8.11.5 + better-sqlite3: 11.3.0 + mysql2: 3.11.0 + pg: 8.13.0 sqlite3: 5.1.7 transitivePeerDependencies: - supports-color + optional: true - knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7): + knex@2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7): dependencies: colorette: 2.0.19 commander: 10.0.1 @@ -18305,13 +18814,12 @@ snapshots: tarn: 3.0.2 tildify: 2.0.0 optionalDependencies: - better-sqlite3: 9.6.0 - mysql2: 3.11.0 + better-sqlite3: 8.7.0 + mysql2: 3.3.3 pg: 8.11.5 sqlite3: 5.1.7 transitivePeerDependencies: - supports-color - optional: true kysely@0.25.0: {} @@ -18502,7 +19010,9 @@ snapshots: dependencies: get-func-name: 2.0.2 - lru-cache@10.2.2: {} + loupe@3.1.2: {} + + lru-cache@10.4.3: {} lru-cache@5.1.1: dependencies: @@ -18516,8 +19026,6 @@ snapshots: lru-cache@8.0.5: {} - lru-cache@9.1.2: {} - lru-queue@0.1.0: dependencies: es5-ext: 0.10.62 @@ -18530,6 +19038,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 + magic-string@0.30.11: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + make-dir@2.1.0: dependencies: pify: 4.0.1 @@ -18580,6 +19092,16 @@ snapshots: node-emoji: 2.1.3 supports-hyperlinks: 3.0.0 + marked-terminal@7.1.0(marked@9.1.6): + dependencies: + ansi-escapes: 7.0.0 + chalk: 5.3.0 + cli-highlight: 2.1.11 + cli-table3: 0.6.5 + marked: 9.1.6 + node-emoji: 2.1.3 + supports-hyperlinks: 3.0.0 + marked@9.1.6: {} marky@1.2.5: {} @@ -18657,12 +19179,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18738,13 +19260,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18758,7 +19280,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -18784,7 +19306,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -18792,7 +19314,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -18801,7 +19323,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -18809,11 +19331,6 @@ snapshots: - supports-color - utf-8-validate - micromatch@4.0.5: - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - micromatch@4.0.7: dependencies: braces: 3.0.3 @@ -19096,7 +19613,7 @@ snapshots: normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.4 + resolve: 1.22.8 semver: 5.7.2 validate-npm-package-license: 3.0.4 @@ -19280,10 +19797,18 @@ snapshots: dependencies: p-timeout: 5.1.0 + p-event@6.0.1: + dependencies: + p-timeout: 6.1.2 + p-filter@3.0.0: dependencies: p-map: 5.5.0 + p-filter@4.1.0: + dependencies: + p-map: 7.0.2 + p-finally@1.0.0: {} p-limit@2.3.0: @@ -19328,8 +19853,12 @@ snapshots: p-map@6.0.0: {} + p-map@7.0.2: {} + p-timeout@5.1.0: {} + p-timeout@6.1.2: {} + p-try@2.2.0: {} parent-module@1.0.1: @@ -19356,6 +19885,14 @@ snapshots: dependencies: pngjs: 3.4.0 + parse5-htmlparser2-tree-adapter@6.0.1: + dependencies: + parse5: 6.0.1 + + parse5@5.1.1: {} + + parse5@6.0.1: {} + parseurl@1.3.3: {} password-prompt@1.1.3: @@ -19381,12 +19918,12 @@ snapshots: path-scurry@1.10.1: dependencies: - lru-cache: 9.1.2 + lru-cache: 10.4.3 minipass: 5.0.0 path-scurry@1.11.1: dependencies: - lru-cache: 10.2.2 + lru-cache: 10.4.3 minipass: 7.1.2 path-to-regexp@0.1.7: {} @@ -19395,10 +19932,14 @@ snapshots: path-type@4.0.0: {} + path-type@5.0.0: {} + pathe@1.1.2: {} pathval@1.1.1: {} + pathval@2.0.0: {} + pause-stream@0.0.11: dependencies: through: 2.3.8 @@ -19410,6 +19951,8 @@ snapshots: pg-connection-string@2.6.4: {} + pg-connection-string@2.7.0: {} + pg-int8@1.0.1: {} pg-numeric@1.0.2: {} @@ -19418,8 +19961,14 @@ snapshots: dependencies: pg: 8.11.5 + pg-pool@3.7.0(pg@8.13.0): + dependencies: + pg: 8.13.0 + pg-protocol@1.6.1: {} + pg-protocol@1.7.0: {} + pg-types@2.2.0: dependencies: pg-int8: 1.0.1 @@ -19448,6 +19997,16 @@ snapshots: optionalDependencies: pg-cloudflare: 1.1.1 + pg@8.13.0: + dependencies: + pg-connection-string: 2.7.0 + pg-pool: 3.7.0(pg@8.13.0) + pg-protocol: 1.7.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + pgpass@1.0.5: dependencies: split2: 4.2.0 @@ -19495,13 +20054,13 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))): dependencies: lilconfig: 2.1.0 yaml: 2.3.1 optionalDependencies: postcss: 8.4.39 - ts-node: 10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-node: 10.9.2(@types/node@22.7.5)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) postcss-load-config@6.0.1(postcss@8.4.39)(tsx@3.14.0)(yaml@2.4.2): dependencies: @@ -19653,6 +20212,8 @@ snapshots: punycode@2.3.1: {} + pure-rand@6.1.0: {} + qrcode-terminal@0.11.0: {} qs@6.11.0: @@ -19687,10 +20248,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8): + react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19703,19 +20264,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19734,14 +20295,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8) + react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -19805,7 +20366,7 @@ snapshots: ast-types: 0.15.2 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.6.2 + tslib: 2.7.0 recast@0.23.9: dependencies: @@ -19813,7 +20374,7 @@ snapshots: esprima: 4.0.1 source-map: 0.6.1 tiny-invariant: 1.3.3 - tslib: 2.6.2 + tslib: 2.7.0 rechoir@0.8.0: dependencies: @@ -19904,6 +20465,13 @@ snapshots: fast-glob: 3.3.1 typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + resolve-tspaths@0.8.22(typescript@5.6.3): + dependencies: + ansi-colors: 4.1.3 + commander: 12.1.0 + fast-glob: 3.3.2 + typescript: 5.6.3 + resolve.exports@2.0.2: {} resolve@1.22.1: @@ -19918,12 +20486,6 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - resolve@1.22.4: - dependencies: - is-core-module: 2.13.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - resolve@1.22.8: dependencies: is-core-module: 2.13.1 @@ -19994,28 +20556,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - rollup@4.18.0: - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.18.0 - '@rollup/rollup-android-arm64': 4.18.0 - '@rollup/rollup-darwin-arm64': 4.18.0 - '@rollup/rollup-darwin-x64': 4.18.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.18.0 - '@rollup/rollup-linux-arm-musleabihf': 4.18.0 - '@rollup/rollup-linux-arm64-gnu': 4.18.0 - '@rollup/rollup-linux-arm64-musl': 4.18.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0 - '@rollup/rollup-linux-riscv64-gnu': 4.18.0 - '@rollup/rollup-linux-s390x-gnu': 4.18.0 - '@rollup/rollup-linux-x64-gnu': 4.18.0 - '@rollup/rollup-linux-x64-musl': 4.18.0 - '@rollup/rollup-win32-arm64-msvc': 4.18.0 - '@rollup/rollup-win32-ia32-msvc': 4.18.0 - '@rollup/rollup-win32-x64-msvc': 4.18.0 - fsevents: 2.3.3 - rollup@4.18.1: dependencies: '@types/estree': 1.0.5 @@ -20038,13 +20578,35 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.18.1 fsevents: 2.3.3 + rollup@4.24.0: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.24.0 + '@rollup/rollup-android-arm64': 4.24.0 + '@rollup/rollup-darwin-arm64': 4.24.0 + '@rollup/rollup-darwin-x64': 4.24.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.24.0 + '@rollup/rollup-linux-arm-musleabihf': 4.24.0 + '@rollup/rollup-linux-arm64-gnu': 4.24.0 + '@rollup/rollup-linux-arm64-musl': 4.24.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.24.0 + '@rollup/rollup-linux-riscv64-gnu': 4.24.0 + '@rollup/rollup-linux-s390x-gnu': 4.24.0 + '@rollup/rollup-linux-x64-gnu': 4.24.0 + '@rollup/rollup-linux-x64-musl': 4.24.0 + '@rollup/rollup-win32-arm64-msvc': 4.24.0 + '@rollup/rollup-win32-ia32-msvc': 4.24.0 + '@rollup/rollup-win32-x64-msvc': 4.24.0 + fsevents: 2.3.3 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 rxjs@7.8.1: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 sade@1.8.1: dependencies: @@ -20234,6 +20796,8 @@ snapshots: slash@4.0.0: {} + slash@5.1.0: {} + slice-ansi@2.1.0: dependencies: ansi-styles: 3.2.1 @@ -20252,6 +20816,8 @@ snapshots: smob@0.0.6: {} + smob@1.5.0: {} + socks-proxy-agent@6.2.1: dependencies: agent-base: 6.0.2 @@ -20555,7 +21121,7 @@ snapshots: synckit@0.9.1: dependencies: '@pkgr/core': 0.1.1 - tslib: 2.6.2 + tslib: 2.7.0 tar-fs@2.0.1: dependencies: @@ -20671,10 +21237,20 @@ snapshots: tinybench@2.8.0: {} + tinybench@2.9.0: {} + + tinyexec@0.3.0: {} + tinypool@0.8.4: {} + tinypool@1.0.1: {} + + tinyrainbow@1.2.0: {} + tinyspy@2.2.1: {} + tinyspy@3.0.2: {} + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -20723,7 +21299,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -20737,14 +21313,37 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 + typescript: 5.6.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.7.5 + acorn: 8.11.3 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + optional: true tsconfck@3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): optionalDependencies: typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + tsconfck@3.0.3(typescript@5.6.3): + optionalDependencies: + typescript: 5.6.3 + tsconfig-paths@3.14.2: dependencies: '@types/json5': 0.0.29 @@ -20756,7 +21355,9 @@ snapshots: tslib@2.6.2: {} - tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + tslib@2.7.0: {} + + tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): dependencies: bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 @@ -20766,7 +21367,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))) resolve-from: 5.0.0 rollup: 3.27.2 source-map: 0.8.0-beta.0 @@ -20832,6 +21433,13 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tsx@4.19.1: + dependencies: + esbuild: 0.23.0 + get-tsconfig: 4.7.5 + optionalDependencies: + fsevents: 2.3.3 + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 @@ -20972,6 +21580,10 @@ snapshots: typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme): {} + typescript@5.6.1-rc: {} + + typescript@5.6.3: {} + ua-parser-js@1.0.38: {} ufo@1.5.3: {} @@ -20985,6 +21597,8 @@ snapshots: undici-types@5.26.5: {} + undici-types@6.19.8: {} + undici@5.28.2: dependencies: '@fastify/busboy': 2.1.1 @@ -21015,6 +21629,8 @@ snapshots: unicode-property-aliases-ecmascript@2.1.0: {} + unicorn-magic@0.1.0: {} + unique-filename@1.1.1: dependencies: unique-slug: 2.0.2 @@ -21073,6 +21689,8 @@ snapshots: utils-merge@1.0.1: {} + uuid@10.0.0: {} + uuid@7.0.3: {} uuid@8.3.2: {} @@ -21179,33 +21797,49 @@ snapshots: - supports-color - terser - vite-tsconfig-paths@4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)): + vite-node@2.1.2(@types/node@22.7.5)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + cac: 6.7.14 + debug: 4.3.7 + pathe: 1.1.2 + vite: 5.3.3(@types/node@22.7.5)(lightningcss@1.25.1)(terser@5.31.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vite-tsconfig-paths@4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 tsconfck: 3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) optionalDependencies: - vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)): + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + tsconfck: 3.0.3(typescript@5.6.3) optionalDependencies: - vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)): + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + tsconfck: 3.0.3(typescript@5.6.3) optionalDependencies: vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: @@ -21216,7 +21850,7 @@ snapshots: dependencies: esbuild: 0.20.2 postcss: 8.4.38 - rollup: 4.18.0 + rollup: 4.24.0 optionalDependencies: '@types/node': 18.15.10 fsevents: 2.3.3 @@ -21227,7 +21861,7 @@ snapshots: dependencies: esbuild: 0.20.2 postcss: 8.4.38 - rollup: 4.18.0 + rollup: 4.24.0 optionalDependencies: '@types/node': 18.19.33 fsevents: 2.3.3 @@ -21238,7 +21872,7 @@ snapshots: dependencies: esbuild: 0.20.2 postcss: 8.4.38 - rollup: 4.18.0 + rollup: 4.24.0 optionalDependencies: '@types/node': 20.10.1 fsevents: 2.3.3 @@ -21249,7 +21883,7 @@ snapshots: dependencies: esbuild: 0.20.2 postcss: 8.4.38 - rollup: 4.18.0 + rollup: 4.24.0 optionalDependencies: '@types/node': 20.12.12 fsevents: 2.3.3 @@ -21260,7 +21894,7 @@ snapshots: dependencies: esbuild: 0.21.5 postcss: 8.4.39 - rollup: 4.18.0 + rollup: 4.24.0 optionalDependencies: '@types/node': 18.15.10 fsevents: 2.3.3 @@ -21271,7 +21905,7 @@ snapshots: dependencies: esbuild: 0.21.5 postcss: 8.4.39 - rollup: 4.18.0 + rollup: 4.24.0 optionalDependencies: '@types/node': 18.19.33 fsevents: 2.3.3 @@ -21282,7 +21916,7 @@ snapshots: dependencies: esbuild: 0.21.5 postcss: 8.4.39 - rollup: 4.18.0 + rollup: 4.24.0 optionalDependencies: '@types/node': 20.10.1 fsevents: 2.3.3 @@ -21293,13 +21927,24 @@ snapshots: dependencies: esbuild: 0.21.5 postcss: 8.4.39 - rollup: 4.18.0 + rollup: 4.24.0 optionalDependencies: '@types/node': 20.12.12 fsevents: 2.3.3 lightningcss: 1.25.1 terser: 5.31.0 + vite@5.3.3(@types/node@22.7.5)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.39 + rollup: 4.24.0 + optionalDependencies: + '@types/node': 22.7.5 + fsevents: 2.3.3 + lightningcss: 1.25.1 + terser: 5.31.0 + vitest@1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): dependencies: '@vitest/expect': 1.6.0 @@ -21436,6 +22081,39 @@ snapshots: - supports-color - terser + vitest@2.1.2(@types/node@22.7.5)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + '@vitest/expect': 2.1.2 + '@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@22.7.5)(lightningcss@1.25.1)(terser@5.31.0)) + '@vitest/pretty-format': 2.1.2 + '@vitest/runner': 2.1.2 + '@vitest/snapshot': 2.1.2 + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 + debug: 4.3.7 + magic-string: 0.30.11 + pathe: 1.1.2 + std-env: 3.7.0 + tinybench: 2.9.0 + tinyexec: 0.3.0 + tinypool: 1.0.1 + tinyrainbow: 1.2.0 + vite: 5.3.3(@types/node@22.7.5)(lightningcss@1.25.1)(terser@5.31.0) + vite-node: 2.1.2(@types/node@22.7.5)(lightningcss@1.25.1)(terser@5.31.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.7.5 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - stylus + - sugarss + - supports-color + - terser + vlq@1.0.1: {} walker@1.0.8: @@ -21520,6 +22198,11 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + wide-align@1.1.5: dependencies: string-width: 4.2.3 @@ -21594,15 +22277,17 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8): + ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8): + ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: @@ -21727,3 +22412,8 @@ snapshots: webpod: 0.0.2 which: 3.0.1 yaml: 2.4.2 + + zx@8.1.9: + optionalDependencies: + '@types/fs-extra': 11.0.4 + '@types/node': 20.12.12 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7cf196659..72d3f184a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,3 +6,4 @@ packages: - drizzle-valibot - integration-tests - eslint-plugin-drizzle + - drizzle-seed From 20acc2fb11c98b8f06074f98d1ff06cc054abf12 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 11 Oct 2024 10:32:14 +0300 Subject: [PATCH 233/492] Fix test --- drizzle-kit/tests/push/pg.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 85c717084..de6ed9dbd 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -2349,6 +2349,18 @@ test('db has checks. Push with same names', async () => { checkConstraint: check('some_check', sql`some new value`), })), }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); }); test('enums ordering', async () => { From e5841405ac49bf6071a2d47e459500eb2137f6d1 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 11 Oct 2024 18:30:28 +0300 Subject: [PATCH 234/492] Fix view tests --- drizzle-kit/tests/introspect/mysql.test.ts | 2 +- drizzle-kit/tests/introspect/pg.test.ts | 2 +- drizzle-kit/tests/introspect/sqlite.test.ts | 2 +- drizzle-kit/tests/introspect/sqlite/view-1.ts | 10 ---------- drizzle-orm/src/entity.ts | 2 +- 5 files changed, 4 insertions(+), 14 deletions(-) delete mode 100644 drizzle-kit/tests/introspect/sqlite/view-1.ts diff --git a/drizzle-kit/tests/introspect/mysql.test.ts b/drizzle-kit/tests/introspect/mysql.test.ts index 6b96f7324..fcbd86d8c 100644 --- a/drizzle-kit/tests/introspect/mysql.test.ts +++ b/drizzle-kit/tests/introspect/mysql.test.ts @@ -192,7 +192,7 @@ test('view #1', async () => { }); test('view #2', async () => { - await client.query(`drop view some_view;`); + // await client.query(`drop view some_view;`); const users = mysqlTable('some_users', { id: int('id') }); const testView = mysqlView('some_view', { id: int('id') }).algorithm('temptable').sqlSecurity('definer').as( diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index 2a1974fd9..2491bbf27 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -515,7 +515,7 @@ test('introspect materialized view in other schema', async () => { const { statements, sqlStatements } = await introspectPgToFile( client, schema, - 'introspect-view-in-other-schema', + 'introspect-mat-view-in-other-schema', ['new_schema'], ); diff --git a/drizzle-kit/tests/introspect/sqlite.test.ts b/drizzle-kit/tests/introspect/sqlite.test.ts index 325d41db6..e8cfe0e68 100644 --- a/drizzle-kit/tests/introspect/sqlite.test.ts +++ b/drizzle-kit/tests/introspect/sqlite.test.ts @@ -56,7 +56,7 @@ test('generated always column virtual: link to another column', async () => { expect(sqlStatements.length).toBe(0); }); -test.only('view #1', async () => { +test('view #1', async () => { const sqlite = new Database(':memory:'); const users = sqliteTable('users', { id: int('id') }); diff --git a/drizzle-kit/tests/introspect/sqlite/view-1.ts b/drizzle-kit/tests/introspect/sqlite/view-1.ts deleted file mode 100644 index c963fea9d..000000000 --- a/drizzle-kit/tests/introspect/sqlite/view-1.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { sqliteTable, AnySQLiteColumn, integer, sqliteView } from "drizzle-orm/sqlite-core" - import { sql } from "drizzle-orm" - -export const users = sqliteTable("users", { - id: integer(), -}); - -export const someView = sqliteView("some_view", { - id: integer(), -}).as(sql`SELECT * FROM "users"`); \ No newline at end of file diff --git a/drizzle-orm/src/entity.ts b/drizzle-orm/src/entity.ts index d9ab3d36a..2b6dfb4de 100644 --- a/drizzle-orm/src/entity.ts +++ b/drizzle-orm/src/entity.ts @@ -26,7 +26,7 @@ export function is>(value: any, type: T): valu ); } - let cls = value.constructor; + let cls = Object.getPrototypeOf(value).constructor; if (cls) { // Traverse the prototype chain to find the entityKind while (cls) { From f9ec55568581bf25025325a87b30852955667da7 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 11 Oct 2024 18:40:57 +0300 Subject: [PATCH 235/492] Check tests with docker --- drizzle-kit/tests/push/mysql-push.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drizzle-kit/tests/push/mysql-push.test.ts b/drizzle-kit/tests/push/mysql-push.test.ts index 8ec5a036d..1e72602a1 100644 --- a/drizzle-kit/tests/push/mysql-push.test.ts +++ b/drizzle-kit/tests/push/mysql-push.test.ts @@ -2,7 +2,6 @@ import Docker from 'dockerode'; import { sql } from 'drizzle-orm'; import { int, mysqlTable, mysqlView } from 'drizzle-orm/mysql-core'; -import fs from 'fs'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; import { diffTestSchemasPushMysql } from 'tests/schemaDiffer'; @@ -41,7 +40,7 @@ async function createDockerDB(): Promise { } beforeAll(async () => { - const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(); + const connectionString = process.env.MYSQL_LOCAL_CONNECTION_STRING ?? await createDockerDB(); const sleep = 1000; let timeLeft = 20000; From 7aba24f545a7962a5f22ce84acb8c58280285d85 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 14 Oct 2024 13:16:04 +0300 Subject: [PATCH 236/492] Update tests --- integration-tests/tests/mysql/mysql-common.ts | 110 +++++++++++------- integration-tests/tests/sqlite/libsql.test.ts | 6 + .../tests/sqlite/sqlite-common.ts | 42 ++++++- 3 files changed, 107 insertions(+), 51 deletions(-) diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 8c56ccfd8..45b96f391 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3830,54 +3830,74 @@ export function tests(driver?: string) { { name: 'Carl', verified: false }, ]); }); - }); - test('Object keys as column names', async (ctx) => { - const { db } = ctx.mysql; - - // Tests the following: - // Column with required config - // Column with optional config without providing a value - // Column with optional config providing a value - // Column without config - const users = mysqlTable('users', { - id: bigint({ mode: 'number' }).autoincrement().primaryKey(), - createdAt: timestamp(), - updatedAt: timestamp({ fsp: 3 }), - admin: boolean(), - }); - - await db.execute(sql`drop table if exists users`); - await db.execute( - sql` - create table users ( - \`id\` bigint auto_increment primary key, - \`createdAt\` timestamp, - \`updatedAt\` timestamp(3), - \`admin\` boolean - ) - `, - ); - - await db.insert(users).values([ - { createdAt: sql`now() - interval 30 day`, updatedAt: sql`now() - interval 1 day`, admin: true }, - { createdAt: sql`now() - interval 1 day`, updatedAt: sql`now() - interval 30 day`, admin: true }, - { createdAt: sql`now() - interval 1 day`, updatedAt: sql`now() - interval 1 day`, admin: false }, - ]); - const result = await db - .select({ id: users.id, admin: users.admin }) - .from(users) - .where( - and( - gt(users.createdAt, sql`now() - interval 7 day`), - gt(users.updatedAt, sql`now() - interval 7 day`), - ), + test('delete with limit and order by', async (ctx) => { + const { db } = ctx.mysql; + + await db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await db.delete(usersTable).where(eq(usersTable.verified, false)).limit(1).orderBy(asc(usersTable.name)); + + const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy( + asc(usersTable.name), + ); + expect(result).toStrictEqual([ + { name: 'Barry', verified: false }, + { name: 'Carl', verified: false }, + ]); + }); + + test('Object keys as column names', async (ctx) => { + const { db } = ctx.mysql; + + // Tests the following: + // Column with required config + // Column with optional config without providing a value + // Column with optional config providing a value + // Column without config + const users = mysqlTable('users', { + id: bigint({ mode: 'number' }).autoincrement().primaryKey(), + createdAt: timestamp(), + updatedAt: timestamp({ fsp: 3 }), + admin: boolean(), + }); + + await db.execute(sql`drop table if exists users`); + await db.execute( + sql` + create table users ( + \`id\` bigint auto_increment primary key, + \`createdAt\` timestamp, + \`updatedAt\` timestamp(3), + \`admin\` boolean + ) + `, ); - expect(result).toEqual([ - { id: 3, admin: false }, - ]); + await db.insert(users).values([ + { createdAt: sql`now() - interval 30 day`, updatedAt: sql`now() - interval 1 day`, admin: true }, + { createdAt: sql`now() - interval 1 day`, updatedAt: sql`now() - interval 30 day`, admin: true }, + { createdAt: sql`now() - interval 1 day`, updatedAt: sql`now() - interval 1 day`, admin: false }, + ]); + const result = await db + .select({ id: users.id, admin: users.admin }) + .from(users) + .where( + and( + gt(users.createdAt, sql`now() - interval 7 day`), + gt(users.updatedAt, sql`now() - interval 7 day`), + ), + ); - await db.execute(sql`drop table users`); + expect(result).toEqual([ + { id: 3, admin: false }, + ]); + + await db.execute(sql`drop table users`); + }); }); } diff --git a/integration-tests/tests/sqlite/libsql.test.ts b/integration-tests/tests/sqlite/libsql.test.ts index 71d3b289e..b99d7e9bf 100644 --- a/integration-tests/tests/sqlite/libsql.test.ts +++ b/integration-tests/tests/sqlite/libsql.test.ts @@ -4,6 +4,7 @@ import { sql } from 'drizzle-orm'; import { drizzle, type LibSQLDatabase } from 'drizzle-orm/libsql'; import { migrate } from 'drizzle-orm/libsql/migrator'; import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { skipTests } from '~/common'; import { randomString } from '~/utils'; import { anotherUsersMigratorTable, tests, usersMigratorTable } from './sqlite-common'; @@ -87,4 +88,9 @@ test('migrator : migrate with custom table', async () => { await db.run(sql`drop table ${sql.identifier(customTable)}`); }); +skipTests([ + 'delete with limit and order by', + 'update with limit and order by', +]); + tests(); diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 0d6a4669b..f31bdbbd2 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2890,14 +2890,44 @@ export function tests() { test('update with limit and order by', async (ctx) => { const { db } = ctx.sqlite; - // Limit and order by may not be supported by all SQLite databases, so we just verify that the query is correct - const query = db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)).toSQL(); + await db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); - expect(query).toStrictEqual({ - sql: 'update "users" set "verified" = ? order by "users"."name" asc limit ?', - params: [1, 2], - }); + await db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); + + const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy( + asc(usersTable.name), + ); + + expect(result).toStrictEqual([ + { name: 'Alan', verified: true }, + { name: 'Barry', verified: true }, + { name: 'Carl', verified: false }, + ]); + }); + + test('delete with limit and order by', async (ctx) => { + const { db } = ctx.sqlite; + + await db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await db.delete(usersTable).where(eq(usersTable.verified, false)).limit(1).orderBy(asc(usersTable.name)); + + const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy( + asc(usersTable.name), + ); + expect(result).toStrictEqual([ + { name: 'Barry', verified: false }, + { name: 'Carl', verified: false }, + ]); }); }); From 9390b9e1930dffbcc407b294b176aee4998bb060 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 14 Oct 2024 13:23:11 +0300 Subject: [PATCH 237/492] Skip sqljs --- integration-tests/tests/sqlite/sql-js.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integration-tests/tests/sqlite/sql-js.test.ts b/integration-tests/tests/sqlite/sql-js.test.ts index ec3d7b583..4c733835f 100644 --- a/integration-tests/tests/sqlite/sql-js.test.ts +++ b/integration-tests/tests/sqlite/sql-js.test.ts @@ -58,5 +58,7 @@ skipTests([ */ 'transaction rollback', 'nested transaction rollback', + 'delete with limit and order by', + 'update with limit and order by', ]); tests(); From f664b149d1f4583673c4e1f7706f847700781e1d Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 14 Oct 2024 13:49:10 +0300 Subject: [PATCH 238/492] Add ignore on neon --- integration-tests/vitest.config.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 034bad147..cbd18f591 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -19,14 +19,12 @@ export default defineConfig({ ...(process.env.SKIP_EXTERNAL_DB_TESTS ? [ 'tests/relational/mysql.planetscale.test.ts', - 'tests/neon-http-batch.test.ts', - 'tests/neon-serverless.test.ts', + 'tests/pg/neon-serverless.test.ts', 'tests/mysql/tidb-serverless.test.ts', 'tests/mysql/mysql-planetscale.test.ts', 'tests/sqlite/libsql.test.ts', 'tests/mysql/tidb-serverless.test.ts', 'tests/sqlite/libsql-batch.test.ts', - 'tests/pg/neon-http.test.ts', 'tests/pg/neon-http-batch.test.ts', ] From 3fdf1b6dd6a8234291c52706041f11c132361b43 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 14 Oct 2024 14:18:04 +0300 Subject: [PATCH 239/492] removed console logs in tests --- drizzle-kit/tests/pg-enums.test.ts | 1 - drizzle-kit/tests/schemaDiffer.ts | 3 --- 2 files changed, 4 deletions(-) diff --git a/drizzle-kit/tests/pg-enums.test.ts b/drizzle-kit/tests/pg-enums.test.ts index 2d7f44a22..99a3dca7e 100644 --- a/drizzle-kit/tests/pg-enums.test.ts +++ b/drizzle-kit/tests/pg-enums.test.ts @@ -651,7 +651,6 @@ test('shuffle enum values', async () => { `ALTER TABLE "new_schema"."table" ALTER COLUMN "column" SET DATA TYPE "public"."enum" USING "column"::"public"."enum";`, ); - console.log('statements: ', statements); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ columnsWithEnum: [ diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 92524d06a..745396de0 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -614,15 +614,12 @@ export const diffTestSchemasPush = async ( const shouldRunApply = sqlStatementsToRun.runApply === undefined ? true : sqlStatementsToRun.runApply; for (const st of sqlStatementsToRun.before ?? []) { - console.log(st); await client.query(st); } - console.log('here'); if (shouldRunApply) { const res = await applyPgDiffs(left, casing); for (const st of res.sqlStatements) { - console.log(st); await client.query(st); } } From dd55e59a508b27266e698a4a182fc3e8424169d7 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 14 Oct 2024 18:02:12 +0300 Subject: [PATCH 240/492] Updated drizzle constructors, removed monodriver --- drizzle-orm/src/aws-data-api/pg/driver.ts | 43 +- drizzle-orm/src/better-sqlite3/driver.ts | 70 +- drizzle-orm/src/bun-sqlite/driver.ts | 91 ++- drizzle-orm/src/connect.ts | 2 - drizzle-orm/src/libsql/driver.ts | 53 +- drizzle-orm/src/monodriver.ts | 659 ------------------ drizzle-orm/src/monomigrator.ts | 109 --- drizzle-orm/src/mysql2/driver.ts | 55 +- drizzle-orm/src/neon-http/driver.ts | 64 +- drizzle-orm/src/neon-serverless/driver.ts | 69 +- drizzle-orm/src/node-postgres/driver.ts | 60 +- drizzle-orm/src/pglite/driver.ts | 59 +- .../src/planetscale-serverless/driver.ts | 58 +- drizzle-orm/src/postgres-js/driver.ts | 57 +- drizzle-orm/src/tidb-serverless/driver.ts | 56 +- drizzle-orm/src/utils.ts | 4 + drizzle-orm/src/vercel-postgres/driver.ts | 51 +- 17 files changed, 755 insertions(+), 805 deletions(-) delete mode 100644 drizzle-orm/src/connect.ts delete mode 100644 drizzle-orm/src/monodriver.ts delete mode 100644 drizzle-orm/src/monomigrator.ts diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index 5218766ae..571c85800 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -1,3 +1,4 @@ +import { RDSDataClient, type RDSDataClientConfig } from '@aws-sdk/client-rds-data'; import { entityKind, is } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -14,7 +15,7 @@ import { } from '~/relations.ts'; import { Param, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import { Table } from '~/table.ts'; -import type { DrizzleConfig, UpdateSet } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError, UpdateSet } from '~/utils.ts'; import type { AwsDataApiClient, AwsDataApiPgQueryResult, AwsDataApiPgQueryResultHKT } from './session.ts'; import { AwsDataApiSession } from './session.ts'; @@ -87,7 +88,7 @@ export class AwsPgDialect extends PgDialect { } } -export function drizzle = Record>( +function construct = Record>( client: AwsDataApiClient, config: DrizzleAwsDataApiPgConfig, ): AwsDataApiPgDatabase & { @@ -120,3 +121,41 @@ export function drizzle = Record = Record, + TClient extends AwsDataApiClient = RDSDataClient, +>( + ...params: IfNotImported< + RDSDataClientConfig, + [ImportTypeError<'@aws-sdk/client-rds-data'>], + [ + TClient, + DrizzleAwsDataApiPgConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: RDSDataClientConfig & Omit; + }) + ), + ] + > +): AwsDataApiPgDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof RDSDataClient) { + return construct(params[0] as TClient, params[1] as DrizzleAwsDataApiPgConfig) as any; + } + + const { connection, ...drizzleConfig } = params[0] as { + connection: RDSDataClientConfig & Omit; + } & DrizzleConfig; + const { resourceArn, database, secretArn, ...rdsConfig } = connection; + + const instance = new RDSDataClient(rdsConfig); + const db = construct(instance, { resourceArn, database, secretArn, ...drizzleConfig }); + + return db as any; +} diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index b53d2cd38..8afc63272 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -1,4 +1,4 @@ -import type { Database, RunResult } from 'better-sqlite3'; +import Client, { type Database, type Options, type RunResult } from 'better-sqlite3'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { @@ -9,16 +9,25 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { BetterSQLiteSession } from './session.ts'; +export type DrizzleBetterSQLite3DatabaseConfig = + | ({ + source?: + | string + | Buffer; + } & Options) + | string + | undefined; + export class BetterSQLite3Database = Record> extends BaseSQLiteDatabase<'sync', RunResult, TSchema> { static override readonly [entityKind]: string = 'BetterSQLite3Database'; } -export function drizzle = Record>( +function construct = Record>( client: Database, config: DrizzleConfig = {}, ): BetterSQLite3Database & { @@ -51,3 +60,58 @@ export function drizzle = Record = Record, + TClient extends Database = Database, +>( + ...params: IfNotImported< + Database, + [ImportTypeError<'better-sqlite3'>], + | [] + | [ + TClient | string, + ] + | [ + TClient | string, + DrizzleConfig, + ] + | [ + ( + & DrizzleConfig + & ({ + connection: DrizzleBetterSQLite3DatabaseConfig; + }) + ), + ] + > +): BetterSQLite3Database & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params instanceof Client) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as { + connection: DrizzleBetterSQLite3DatabaseConfig; + } & DrizzleConfig; + + if (typeof connection === 'object') { + const { source, ...options } = connection; + + const instance = new Client(source, options); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Client(connection); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Client(params[0]); + + return construct(instance, params[1]) as any; +} diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index 171573e78..4433d8508 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -1,6 +1,6 @@ /// -import type { Database } from 'bun:sqlite'; +import { Database } from 'bun:sqlite'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { @@ -11,7 +11,7 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { SQLiteBunSession } from './session.ts'; export class BunSQLiteDatabase< @@ -20,7 +20,35 @@ export class BunSQLiteDatabase< static override readonly [entityKind]: string = 'BunSQLiteDatabase'; } -export function drizzle = Record>( +type DrizzleBunSqliteDatabaseOptions = { + /** + * Open the database as read-only (no write operations, no create). + * + * Equivalent to {@link constants.SQLITE_OPEN_READONLY} + */ + readonly?: boolean; + /** + * Allow creating a new database + * + * Equivalent to {@link constants.SQLITE_OPEN_CREATE} + */ + create?: boolean; + /** + * Open the database as read-write + * + * Equivalent to {@link constants.SQLITE_OPEN_READWRITE} + */ + readwrite?: boolean; +}; + +export type DrizzleBunSqliteDatabaseConfig = + | ({ + source?: string; + } & DrizzleBunSqliteDatabaseOptions) + | string + | undefined; + +function construct = Record>( client: Database, config: DrizzleConfig = {}, ): BunSQLiteDatabase & { @@ -53,3 +81,60 @@ export function drizzle = Record = Record, + TClient extends Database = Database, +>( + ...params: IfNotImported< + Database, + [ImportTypeError<'bun-types'>], + | [] + | [ + TClient | string, + ] + | [ + TClient | string, + DrizzleConfig, + ] + | [ + ( + & DrizzleConfig + & ({ + connection: DrizzleBunSqliteDatabaseConfig; + }) + ), + ] + > +): BunSQLiteDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params instanceof Database) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as { + connection: DrizzleBunSqliteDatabaseConfig | string | undefined; + } & DrizzleConfig; + + if (typeof connection === 'object') { + const { source, ...opts } = connection; + + const options = Object.values(opts).filter((v) => v !== undefined).length ? opts : undefined; + + const instance = new Database(source, options); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Database(connection); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Database(params[0]); + + return construct(instance, params[1]) as any; +} diff --git a/drizzle-orm/src/connect.ts b/drizzle-orm/src/connect.ts deleted file mode 100644 index 6e26b2922..000000000 --- a/drizzle-orm/src/connect.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './monodriver.ts'; -export * from './monomigrator.ts'; diff --git a/drizzle-orm/src/libsql/driver.ts b/drizzle-orm/src/libsql/driver.ts index 2ff0720b1..0aa60943c 100644 --- a/drizzle-orm/src/libsql/driver.ts +++ b/drizzle-orm/src/libsql/driver.ts @@ -1,4 +1,7 @@ -import type { Client, ResultSet } from '@libsql/client'; +import { type Client, type Config, createClient, type ResultSet } from '@libsql/client'; +import { HttpClient } from '@libsql/client/http'; +import { Sqlite3Client } from '@libsql/client/sqlite3'; +import { WsClient } from '@libsql/client/ws'; import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -11,7 +14,7 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { LibSQLSession } from './session.ts'; export class LibSQLDatabase< @@ -29,7 +32,7 @@ export class LibSQLDatabase< } } -export function drizzle< +function construct< TSchema extends Record = Record, >(client: Client, config: DrizzleConfig = {}): LibSQLDatabase & { $client: Client; @@ -61,3 +64,47 @@ export function drizzle< return db as any; } + +export function drizzle< + TSchema extends Record = Record, + TClient extends Client = Client, +>( + ...params: IfNotImported< + Client, + [ImportTypeError<'@libsql/client'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + }) + ), + ] + > +): LibSQLDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof WsClient || params[0] instanceof HttpClient || params[0] instanceof Sqlite3Client) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'string') { + const instance = createClient({ + url: params[0], + }); + + return construct(instance, params[1]) as any; + } + + const { connection, ...drizzleConfig } = params[0] as any as { connection: Config } & DrizzleConfig; + + const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection); + + return construct(instance, drizzleConfig) as any; +} diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts deleted file mode 100644 index 9af80db06..000000000 --- a/drizzle-orm/src/monodriver.ts +++ /dev/null @@ -1,659 +0,0 @@ -/* eslint-disable import/extensions */ -import type { RDSDataClient, RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; -import type { PGlite, PGliteOptions } from '@electric-sql/pglite'; -import type { Client as LibsqlClient, Config as LibsqlConfig } from '@libsql/client'; -import type { - HTTPTransactionOptions as NeonHttpConfig, - NeonQueryFunction, - Pool as NeonServerlessPool, - PoolConfig as NeonServerlessConfig, - QueryResult, - QueryResultRow, -} from '@neondatabase/serverless'; -import type { Client as PlanetscaleClient, Config as PlanetscaleConfig } from '@planetscale/database'; -import type { Config as TiDBServerlessConfig, Connection as TiDBConnection } from '@tidbcloud/serverless'; -import type { VercelPool } from '@vercel/postgres'; -import type { Database as BetterSQLite3Database, Options as BetterSQLite3Options } from 'better-sqlite3'; -import type { Database as BunDatabase } from 'bun:sqlite'; -import type { Pool as Mysql2Pool, PoolOptions as Mysql2Config } from 'mysql2'; -import type { Pool as NodePgPool, PoolConfig as NodePgPoolConfig } from 'pg'; -import type { - Options as PostgresJSOptions, - PostgresType as PostgresJSPostgresType, - Sql as PostgresJsClient, -} from 'postgres'; -import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg/index.ts'; -import type { BetterSQLite3Database as DrizzleBetterSQLite3Database } from './better-sqlite3/index.ts'; -import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; -import type { AnyD1Database, DrizzleD1Database } from './d1/index.ts'; -import type { LibSQLDatabase } from './libsql/index.ts'; -import type { MySql2Database, MySql2DrizzleConfig } from './mysql2/index.ts'; -import type { NeonHttpDatabase } from './neon-http/index.ts'; -import type { NeonDatabase } from './neon-serverless/index.ts'; -import type { NodePgDatabase } from './node-postgres/driver.ts'; -import type { PgliteDatabase } from './pglite/driver.ts'; -import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; -import type { PostgresJsDatabase } from './postgres-js/index.ts'; -import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; -import type { DrizzleConfig, IfNotImported } from './utils.ts'; -import type { VercelPgDatabase } from './vercel-postgres/index.ts'; - -type BunSqliteDatabaseOptions = { - /** - * Open the database as read-only (no write operations, no create). - * - * Equivalent to {@link constants.SQLITE_OPEN_READONLY} - */ - readonly?: boolean; - /** - * Allow creating a new database - * - * Equivalent to {@link constants.SQLITE_OPEN_CREATE} - */ - create?: boolean; - /** - * Open the database as read-write - * - * Equivalent to {@link constants.SQLITE_OPEN_READWRITE} - */ - readwrite?: boolean; -}; - -type BunSqliteDatabaseConfig = - | ({ - source?: string; - } & BunSqliteDatabaseOptions) - | string - | undefined; - -type BetterSQLite3DatabaseConfig = - | ({ - source?: - | string - | Buffer; - } & BetterSQLite3Options) - | string - | undefined; - -type MonodriverNeonHttpConfig = - | ({ - connectionString: string; - } & NeonHttpConfig) - | string; - -type AwsDataApiConnectionConfig = RDSConfig & Omit; - -type DatabaseClient = - | 'node-postgres' - | 'postgres-js' - | 'neon-websocket' - | 'neon-http' - | 'vercel-postgres' - | 'aws-data-api-pg' - | 'planetscale' - | 'mysql2' - | 'tidb-serverless' - | 'libsql' - | 'turso' - | 'd1' - | 'bun:sqlite' - | 'better-sqlite3' - | 'pglite'; - -type ClientDrizzleInstanceMap> = { - 'node-postgres': NodePgDatabase; - 'postgres-js': PostgresJsDatabase; - 'neon-websocket': NeonDatabase; - 'neon-http': NeonHttpDatabase; - 'vercel-postgres': VercelPgDatabase; - 'aws-data-api-pg': AwsDataApiPgDatabase; - planetscale: PlanetScaleDatabase; - mysql2: MySql2Database; - 'tidb-serverless': TiDBServerlessDatabase; - libsql: LibSQLDatabase; - turso: LibSQLDatabase; - d1: DrizzleD1Database; - 'bun:sqlite': BunSQLiteDatabase; - 'better-sqlite3': DrizzleBetterSQLite3Database; - pglite: PgliteDatabase; -}; - -type Primitive = string | number | boolean | undefined | null; - -type ClientInstanceMap = { - 'node-postgres': NodePgPool; - 'postgres-js': PostgresJsClient; - 'neon-websocket': NeonServerlessPool; - 'neon-http': NeonQueryFunction; - 'vercel-postgres': - & VercelPool - & ((strings: TemplateStringsArray, ...values: Primitive[]) => Promise>); - 'aws-data-api-pg': RDSDataClient; - planetscale: PlanetscaleClient; - mysql2: Mysql2Pool; - 'tidb-serverless': TiDBConnection; - libsql: LibsqlClient; - turso: LibsqlClient; - d1: AnyD1Database; - 'bun:sqlite': BunDatabase; - 'better-sqlite3': BetterSQLite3Database; - pglite: PGlite; -}; - -type ClientTypeImportErrorMap = { - 'node-postgres': 'pg`, `@types/pg'; - 'postgres-js': 'postgres'; - 'neon-websocket': '@neondatabase/serverless'; - 'neon-http': '@neondatabase/serverless'; - 'vercel-postgres': '@vercel/postgres'; - 'aws-data-api-pg': '@aws-sdk/client-rds-data'; - planetscale: '@planetscale/database'; - mysql2: 'mysql2'; - 'tidb-serverless': '@tidbcloud/serverless'; - libsql: '@libsql/client'; - turso: '@libsql/client'; - d1: '@cloudflare/workers-types` or `@miniflare/d1'; - 'bun:sqlite': 'bun-types'; - 'better-sqlite3': 'better-sqlite3'; - pglite: '@electric-sql/pglite'; -}; - -type ImportTypeError = - `Please install \`${ClientTypeImportErrorMap[TClient]}\`to allow Drizzle ORM to connect to the database`; - -type InitializerParams = { - 'node-postgres': { - connection: string | NodePgPoolConfig; - }; - 'postgres-js': { - connection: string | ({ url?: string } & PostgresJSOptions>); - }; - 'neon-websocket': { - connection: string | NeonServerlessConfig; - }; - 'neon-http': { - connection: MonodriverNeonHttpConfig; - }; - 'vercel-postgres': {}; - 'aws-data-api-pg': { - connection: AwsDataApiConnectionConfig; - }; - planetscale: { - connection: PlanetscaleConfig | string; - }; - mysql2: { - connection: Mysql2Config | string; - }; - 'tidb-serverless': { - connection: TiDBServerlessConfig | string; - }; - libsql: { - connection: LibsqlConfig | string; - }; - turso: { - connection: LibsqlConfig | string; - }; - d1: { - connection: AnyD1Database; - }; - 'bun:sqlite': { - connection?: BunSqliteDatabaseConfig; - }; - 'better-sqlite3': { - connection?: BetterSQLite3DatabaseConfig; - }; - pglite: { - connection?: (PGliteOptions & { dataDir?: string }) | string; - }; -}; - -type DetermineClient< - TClient extends DatabaseClient, - TSchema extends Record, -> = - & ClientDrizzleInstanceMap< - TSchema - >[TClient] - & { - $client: ClientInstanceMap[TClient]; - }; - -const importError = (libName: string) => { - throw new Error( - `Please install '${libName}' to allow Drizzle ORM to connect to the database`, - ); -}; - -function assertUnreachable(_: never | undefined): never { - throw new Error("Didn't expect to get here"); -} - -export async function drizzle< - TClient extends DatabaseClient, - TSchema extends Record = Record, ->( - client: TClient, - ...params: TClient extends 'bun:sqlite' | 'better-sqlite3' | 'pglite' ? ( - [] | [ - ( - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & DrizzleConfig - ), - ] | [string] - ) - : TClient extends 'vercel-postgres' ? ([] | [ - ( - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & DrizzleConfig - ), - ]) - : TClient extends - 'postgres-js' | 'tidb-serverless' | 'libsql' | 'turso' | 'planetscale' | 'neon-http' | 'node-postgres' ? ( - [ - ( - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & DrizzleConfig - ), - ] | [string] - ) - : TClient extends 'mysql2' ? ( - [ - ( - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & MySql2DrizzleConfig - ), - ] | [string] - ) - : TClient extends 'neon-websocket' ? ( - | [ - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & DrizzleConfig - & { - ws?: any; - }, - ] - | [string] - ) - : [ - ( - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & DrizzleConfig - ), - ] -): Promise> { - switch (client) { - case 'node-postgres': { - const defpg = await import('pg').catch(() => importError('pg')); - const { drizzle } = await import('./node-postgres/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as - & { connection: NodePgPoolConfig | string } - & DrizzleConfig; - - const instance = typeof connection === 'string' - ? new defpg.default.Pool({ - connectionString: connection, - }) - : new defpg.default.Pool(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = typeof params[0] === 'string' - ? new defpg.default.Pool({ - connectionString: params[0], - }) - : new defpg.default.Pool(params[0]); - const db = drizzle(instance); - - return db as any; - } - case 'aws-data-api-pg': { - const { connection, ...drizzleConfig } = params[0] as { - connection: AwsDataApiConnectionConfig; - } & DrizzleConfig; - const { resourceArn, database, secretArn, ...rdsConfig } = connection; - - const { RDSDataClient } = await import('@aws-sdk/client-rds-data').catch(() => - importError('@aws-sdk/client-rds-data') - ); - const { drizzle } = await import('./aws-data-api/pg/index.ts'); - - const instance = new RDSDataClient(rdsConfig); - const db = drizzle(instance, { resourceArn, database, secretArn, ...drizzleConfig }); - - return db as any; - } - case 'better-sqlite3': { - const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); - const { drizzle } = await import('./better-sqlite3/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: BetterSQLite3DatabaseConfig; - } & DrizzleConfig; - - if (typeof connection === 'object') { - const { source, ...options } = connection; - - const instance = new Client(source, options); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new Client(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new Client(params[0]); - const db = drizzle(instance); - - return db as any; - } - case 'bun:sqlite': { - const { Database: Client } = await import('bun:sqlite').catch(() => { - throw new Error(`Please use bun to use 'bun:sqlite' for Drizzle ORM to connect to database`); - }); - const { drizzle } = await import('./bun-sqlite/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: BunSqliteDatabaseConfig | string | undefined; - } & DrizzleConfig; - - if (typeof connection === 'object') { - const { source, ...opts } = connection; - - const options = Object.values(opts).filter((v) => v !== undefined).length ? opts : undefined; - - const instance = new Client(source, options); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new Client(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new Client(params[0]); - const db = drizzle(instance); - - return db as any; - } - case 'd1': { - const { connection, ...drizzleConfig } = params[0] as { connection: AnyD1Database } & DrizzleConfig; - - const { drizzle } = await import('./d1/index.ts'); - - const db = drizzle(connection, drizzleConfig); - - return db as any; - } - case 'libsql': - case 'turso': { - const { createClient } = await import('@libsql/client').catch(() => importError('@libsql/client')); - const { drizzle } = await import('./libsql/index.ts'); - - if (typeof params[0] === 'string') { - const instance = createClient({ - url: params[0], - }); - const db = drizzle(instance); - - return db as any; - } - - const { connection, ...drizzleConfig } = params[0] as any as { connection: LibsqlConfig } & DrizzleConfig; - - const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - case 'mysql2': { - const { createPool } = await import('mysql2/promise').catch(() => importError('mysql2')); - const { drizzle } = await import('./mysql2/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as - & { connection: Mysql2Config | string } - & MySql2DrizzleConfig; - - const instance = createPool(connection as Mysql2Config); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const connectionString = params[0]!; - const instance = createPool(connectionString); - - const db = drizzle(instance); - - return db as any; - } - case 'neon-http': { - const { neon } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); - const { drizzle } = await import('./neon-http/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { connection: MonodriverNeonHttpConfig } & DrizzleConfig; - - if (typeof connection === 'object') { - const { connectionString, ...options } = connection; - - const instance = neon(connectionString, options); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = neon(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = neon(params[0]!); - const db = drizzle(instance); - - return db as any; - } - case 'neon-websocket': { - const { Pool, neonConfig } = await import('@neondatabase/serverless').catch(() => - importError('@neondatabase/serverless') - ); - const { drizzle } = await import('./neon-serverless/index.ts'); - if (typeof params[0] === 'string') { - const instance = new Pool({ - connectionString: params[0], - }); - - const db = drizzle(instance); - - return db as any; - } - - if (typeof params[0] === 'object') { - const { connection, ws, ...drizzleConfig } = params[0] as { - connection?: NeonServerlessConfig | string; - ws?: any; - } & DrizzleConfig; - - if (ws) { - neonConfig.webSocketConstructor = ws; - } - - const instance = typeof connection === 'string' - ? new Pool({ - connectionString: connection, - }) - : new Pool(connection); - - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new Pool(); - const db = drizzle(instance); - - return db as any; - } - case 'planetscale': { - const { Client } = await import('@planetscale/database').catch(() => importError('@planetscale/database')); - const { drizzle } = await import('./planetscale-serverless/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as - & { connection: PlanetscaleConfig | string } - & DrizzleConfig; - - const instance = typeof connection === 'string' - ? new Client({ - url: connection, - }) - : new Client( - connection, - ); - const db = drizzle(instance, drizzleConfig); - return db as any; - } - - const instance = new Client({ - url: params[0], - }); - const db = drizzle(instance); - - return db as any; - } - case 'postgres-js': { - const { default: client } = await import('postgres').catch(() => importError('postgres')); - const { drizzle } = await import('./postgres-js/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: { url?: string } & PostgresJSOptions>; - } & DrizzleConfig; - - if (typeof connection === 'object' && connection.url !== undefined) { - const { url, ...config } = connection; - - const instance = client(url, config); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = client(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = client(params[0]!); - const db = drizzle(instance); - - return db as any; - } - case 'tidb-serverless': { - const { connect } = await import('@tidbcloud/serverless').catch(() => importError('@tidbcloud/serverless')); - const { drizzle } = await import('./tidb-serverless/index.ts'); - - if (typeof params[0] === 'string') { - const instance = connect({ - url: params[0], - }); - const db = drizzle(instance); - - return db as any; - } - - const { connection, ...drizzleConfig } = params[0] as - & { connection: TiDBServerlessConfig | string } - & DrizzleConfig; - - const instance = typeof connection === 'string' - ? connect({ - url: connection, - }) - : connect(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - case 'vercel-postgres': { - const drizzleConfig = params[0] as DrizzleConfig | undefined; - const { sql } = await import('@vercel/postgres').catch(() => importError('@vercel/postgres')); - const { drizzle } = await import('./vercel-postgres/index.ts'); - - const db = drizzle(sql, drizzleConfig); - - return db as any; - } - - case 'pglite': { - const { PGlite } = await import('@electric-sql/pglite').catch(() => importError('@electric-sql/pglite')); - const { drizzle } = await import('./pglite/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: PGliteOptions & { dataDir: string }; - } & DrizzleConfig; - - if (typeof connection === 'object') { - const { dataDir, ...options } = connection; - - const instance = new PGlite(dataDir, options); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new PGlite(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new PGlite(params[0]); - const db = drizzle(instance); - - return db as any; - } - } - - assertUnreachable(client); -} diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts deleted file mode 100644 index 9f4a748e0..000000000 --- a/drizzle-orm/src/monomigrator.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* eslint-disable import/extensions */ -import type { AwsDataApiPgDatabase } from './aws-data-api/pg/index.ts'; -import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; -import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; -import type { DrizzleD1Database } from './d1/index.ts'; -import { entityKind } from './entity.ts'; -import type { LibSQLDatabase } from './libsql/index.ts'; -import type { MigrationConfig } from './migrator.ts'; -import type { MySql2Database } from './mysql2/index.ts'; -import type { NeonHttpDatabase } from './neon-http/index.ts'; -import type { NeonDatabase } from './neon-serverless/index.ts'; -import type { NodePgDatabase } from './node-postgres/index.ts'; -import type { PgliteDatabase } from './pglite/driver.ts'; -import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; -import type { PostgresJsDatabase } from './postgres-js/index.ts'; -import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; -import type { VercelPgDatabase } from './vercel-postgres/index.ts'; - -export async function migrate( - db: - | AwsDataApiPgDatabase - | BetterSQLite3Database - | BunSQLiteDatabase - | DrizzleD1Database - | LibSQLDatabase - | MySql2Database - | NeonHttpDatabase - | NeonDatabase - | NodePgDatabase - | PlanetScaleDatabase - | PostgresJsDatabase - | VercelPgDatabase - | TiDBServerlessDatabase - | PgliteDatabase, - config: MigrationConfig, -) { - switch (( db).constructor[entityKind]) { - case 'AwsDataApiPgDatabase': { - const { migrate } = await import('./aws-data-api/pg/migrator.ts'); - - return migrate(db as AwsDataApiPgDatabase, config as MigrationConfig); - } - case 'BetterSQLite3Database': { - const { migrate } = await import('./better-sqlite3/migrator.ts'); - - return migrate(db as BetterSQLite3Database, config as MigrationConfig); - } - case 'BunSQLiteDatabase': { - const { migrate } = await import('./bun-sqlite/migrator.ts'); - - return migrate(db as BunSQLiteDatabase, config as MigrationConfig); - } - case 'D1Database': { - const { migrate } = await import('./d1/migrator.ts'); - - return migrate(db as DrizzleD1Database, config as MigrationConfig); - } - case 'LibSQLDatabase': { - const { migrate } = await import('./libsql/migrator.ts'); - - return migrate(db as LibSQLDatabase, config as MigrationConfig); - } - case 'MySql2Database': { - const { migrate } = await import('./mysql2/migrator.ts'); - - return migrate(db as MySql2Database, config as MigrationConfig); - } - case 'NeonHttpDatabase': { - const { migrate } = await import('./neon-http/migrator.ts'); - - return migrate(db as NeonHttpDatabase, config as MigrationConfig); - } - case 'NeonServerlessDatabase': { - const { migrate } = await import('./neon-serverless/migrator.ts'); - - return migrate(db as NeonDatabase, config as MigrationConfig); - } - case 'NodePgDatabase': { - const { migrate } = await import('./node-postgres/migrator.ts'); - - return migrate(db as NodePgDatabase, config as MigrationConfig); - } - case 'PlanetScaleDatabase': { - const { migrate } = await import('./planetscale-serverless/migrator.ts'); - - return migrate(db as PlanetScaleDatabase, config as MigrationConfig); - } - case 'PostgresJsDatabase': { - const { migrate } = await import('./postgres-js/migrator.ts'); - - return migrate(db as PostgresJsDatabase, config as MigrationConfig); - } - case 'TiDBServerlessDatabase': { - const { migrate } = await import('./tidb-serverless/migrator.ts'); - - return migrate(db as TiDBServerlessDatabase, config as MigrationConfig); - } - case 'VercelPgDatabase': { - const { migrate } = await import('./vercel-postgres/migrator.ts'); - - return migrate(db as VercelPgDatabase, config as MigrationConfig); - } - case 'PgliteDatabase': { - const { migrate } = await import('./pglite/migrator.ts'); - - return migrate(db as PgliteDatabase, config as MigrationConfig); - } - } -} diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index 842db2d06..ca113d88d 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -1,4 +1,5 @@ -import type { Connection as CallbackConnection, Pool as CallbackPool } from 'mysql2'; +import { EventEmitter } from 'events'; +import { type Connection as CallbackConnection, createPool, type Pool as CallbackPool, type PoolOptions } from 'mysql2'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -11,7 +12,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { DrizzleError } from '../errors.ts'; import type { MySql2Client, MySql2PreparedQueryHKT, MySql2QueryResultHKT } from './session.ts'; import { MySql2Session } from './session.ts'; @@ -50,7 +51,7 @@ export type MySql2DrizzleConfig = Record & Omit, 'schema'> & ({ schema: TSchema; mode: Mode } | { schema?: undefined; mode?: Mode }); -export function drizzle< +function construct< TSchema extends Record = Record, TClient extends MySql2Client | CallbackConnection | CallbackPool = MySql2Client | CallbackConnection | CallbackPool, >( @@ -106,3 +107,51 @@ interface CallbackClient { function isCallbackClient(client: any): client is CallbackClient { return typeof client.promise === 'function'; } + +export function drizzle< + TSchema extends Record = Record, + TClient extends MySql2Client | CallbackPool | CallbackConnection = CallbackPool, +>( + ...params: IfNotImported< + CallbackPool, + [ImportTypeError<'mysql2'>], + [ + TClient | string, + ] | [ + TClient | string, + MySql2DrizzleConfig, + ] | [ + ( + & MySql2DrizzleConfig + & ({ + connection: string | PoolOptions; + }) + ), + ] + > +): MySql2Database & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof EventEmitter) { + return construct(params[0] as TClient, params[1] as MySql2DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as + & { connection: PoolOptions | string } + & MySql2DrizzleConfig; + + const instance = createPool(connection as PoolOptions); + const db = construct(instance, drizzleConfig); + + return db as any; + } + + const connectionString = params[0]!; + const instance = createPool({ + uri: connectionString, + }); + + return construct(instance, params[1]) as any; +} diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index cadda2da9..8b0e97931 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -1,5 +1,5 @@ -import type { NeonQueryFunction } from '@neondatabase/serverless'; -import { types } from '@neondatabase/serverless'; +import type { HTTPTransactionOptions, NeonQueryFunction } from '@neondatabase/serverless'; +import { neon, types } from '@neondatabase/serverless'; import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; @@ -8,7 +8,7 @@ import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig } from '~/relations.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { type NeonHttpClient, type NeonHttpQueryResultHKT, NeonHttpSession } from './session.ts'; export interface NeonDriverOptions { @@ -55,7 +55,7 @@ export class NeonHttpDatabase< } } -export function drizzle< +function construct< TSchema extends Record = Record, TClient extends NeonQueryFunction = NeonQueryFunction, >( @@ -97,3 +97,59 @@ export function drizzle< return db as any; } + +export function drizzle< + TSchema extends Record = Record, + TClient extends NeonQueryFunction = NeonQueryFunction, +>( + ...params: IfNotImported< + HTTPTransactionOptions, + [ImportTypeError<'@neondatabase/serverless'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | HTTPTransactionOptions; + }) + ), + ] + > +): NeonHttpDatabase & { + $client: TClient; +} { + if ((params[0] as any)[Symbol.toStringTag] === 'NeonQueryPromise') { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as + & { + connection?: + | ({ + connectionString: string; + } & HTTPTransactionOptions) + | string; + } + & DrizzleConfig; + + if (typeof connection === 'object') { + const { connectionString, ...options } = connection; + + const instance = neon(connectionString, options); + + return construct(instance, drizzleConfig) as any; + } + + const instance = neon(connection!); + + return construct(instance, drizzleConfig) as any; + } + + const instance = neon(params[0] as string); + return construct(instance, params[1]) as any; +} diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index 985046c07..cac0fd829 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -1,3 +1,4 @@ +import { neonConfig, Pool, type PoolConfig } from '@neondatabase/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -9,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { NeonClient, NeonQueryResultHKT } from './session.ts'; import { NeonSession } from './session.ts'; @@ -40,7 +41,7 @@ export class NeonDatabase< static override readonly [entityKind]: string = 'NeonServerlessDatabase'; } -export function drizzle< +function construct< TSchema extends Record = Record, TClient extends NeonClient = NeonClient, >( @@ -77,3 +78,67 @@ export function drizzle< return db as any; } + +export function drizzle< + TSchema extends Record = Record, + TClient extends NeonClient = Pool, +>( + ...params: IfNotImported< + Pool, + [ImportTypeError<'@neondatabase/serverless'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | PoolConfig; + }) + & { + ws?: any; + } + ), + ] + > +): NeonDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof Pool) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'string') { + const instance = new Pool({ + connectionString: params[0], + }); + + construct(instance); + } + + if (typeof params[0] === 'object') { + const { connection, ws, ...drizzleConfig } = params[0] as { + connection?: PoolConfig | string; + ws?: any; + } & DrizzleConfig; + + if (ws) { + neonConfig.webSocketConstructor = ws; + } + + const instance = typeof connection === 'string' + ? new Pool({ + connectionString: connection, + }) + : new Pool(connection); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Pool(); + + return construct(instance, params[1]) as any; +} diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index 5679258de..e345a3866 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -1,3 +1,4 @@ +import pg, { type Pool, type PoolConfig } from 'pg'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -9,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { NodePgClient, NodePgQueryResultHKT } from './session.ts'; import { NodePgSession } from './session.ts'; @@ -40,7 +41,7 @@ export class NodePgDatabase< static override readonly [entityKind]: string = 'NodePgDatabase'; } -export function drizzle< +function construct< TSchema extends Record = Record, TClient extends NodePgClient = NodePgClient, >( @@ -77,3 +78,58 @@ export function drizzle< return db as any; } + +export function drizzle< + TSchema extends Record = Record, + TClient extends NodePgClient = Pool, +>( + ...params: IfNotImported< + Pool, + [ImportTypeError<'pg'>], + | [ + TClient | string, + ] + | [ + TClient | string, + DrizzleConfig, + ] + | [ + ( + & DrizzleConfig + & ({ + connection: string | PoolConfig; + }) + ), + ] + > +): NodePgDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof pg.Pool || params[0] instanceof pg.ClientBase) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as ( + & ({ connection?: PoolConfig | string; driver?: TClient }) + & DrizzleConfig + ); + + const instance = typeof connection === 'string' + ? new pg.Pool({ + connectionString: connection, + }) + : new pg.Pool(connection!); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new pg.Pool({ + connectionString: params[0], + }); + + return construct(instance, params[1] as DrizzleConfig | undefined) as any; +} + +drizzle('', {}); diff --git a/drizzle-orm/src/pglite/driver.ts b/drizzle-orm/src/pglite/driver.ts index c8683d540..3667ebcc4 100644 --- a/drizzle-orm/src/pglite/driver.ts +++ b/drizzle-orm/src/pglite/driver.ts @@ -1,3 +1,4 @@ +import { PGlite, type PGliteOptions } from '@electric-sql/pglite'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -9,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { PgliteClient, PgliteQueryResultHKT } from './session.ts'; import { PgliteSession } from './session.ts'; @@ -40,7 +41,7 @@ export class PgliteDatabase< static override readonly [entityKind]: string = 'PgliteDatabase'; } -export function drizzle = Record>( +function construct = Record>( client: PgliteClient, config: DrizzleConfig = {}, ): PgliteDatabase & { @@ -74,3 +75,57 @@ export function drizzle = Record = Record, + TClient extends PGlite = PGlite, +>( + ...params: IfNotImported< + PGlite, + [ImportTypeError<'@electric-sql/pglite'>], + | [] + | [ + TClient | string, + ] + | [ + TClient | string, + DrizzleConfig, + ] + | [ + ( + & DrizzleConfig + & ({ + connection?: (PGliteOptions & { dataDir?: string }) | string; + }) + ), + ] + > +): PgliteDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof PGlite) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as { + connection: PGliteOptions & { dataDir: string }; + } & DrizzleConfig; + + if (typeof connection === 'object') { + const { dataDir, ...options } = connection; + + const instance = new PGlite(dataDir, options); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new PGlite(connection); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new PGlite(params[0]); + return construct(instance, params[1]) as any; +} diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index 69da8ce83..621c30b10 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -1,4 +1,4 @@ -import type { Connection } from '@planetscale/database'; +import type { Config, Connection } from '@planetscale/database'; import { Client } from '@planetscale/database'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; @@ -11,7 +11,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { PlanetScalePreparedQueryHKT, PlanetscaleQueryResultHKT } from './session.ts'; import { PlanetscaleSession } from './session.ts'; @@ -25,7 +25,7 @@ export class PlanetScaleDatabase< static override readonly [entityKind]: string = 'PlanetScaleDatabase'; } -export function drizzle< +function construct< TSchema extends Record = Record, TClient extends Client | Connection = Client | Connection, >( @@ -95,3 +95,55 @@ Starting from version 0.30.0, you will encounter an error if you attempt to use return db as any; } + +export function drizzle< + TSchema extends Record = Record, + TClient extends Client = Client, +>( + ...params: IfNotImported< + Config, + [ImportTypeError<'@planetscale/database'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + }) + ), + ] + > +): PlanetScaleDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof Client) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as + & { connection: Config | string } + & DrizzleConfig; + + const instance = typeof connection === 'string' + ? new Client({ + url: connection, + }) + : new Client( + connection, + ); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Client({ + url: params[0], + }); + + return construct(instance, params[1]) as any; +} diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index 0927e96ac..5b62f241e 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -1,4 +1,4 @@ -import type { Sql } from 'postgres'; +import client, { type Options, type PostgresType, type Sql } from 'postgres'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { PgDatabase } from '~/pg-core/db.ts'; @@ -9,7 +9,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { PostgresJsQueryResultHKT } from './session.ts'; import { PostgresJsSession } from './session.ts'; @@ -19,7 +19,7 @@ export class PostgresJsDatabase< static override readonly [entityKind]: string = 'PostgresJsDatabase'; } -export function drizzle = Record>( +function construct = Record>( client: Sql, config: DrizzleConfig = {}, ): PostgresJsDatabase & { @@ -62,3 +62,54 @@ export function drizzle = Record = Record, + TClient extends Sql = Sql, +>( + ...params: IfNotImported< + Options, + [ImportTypeError<'postgres'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | ({ url?: string } & Options>); + }) + ), + ] + > +): PostgresJsDatabase & { + $client: TClient; +} { + if (typeof params[0] === 'function') { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, ...drizzleConfig } = params[0] as { + connection: { url?: string } & Options>; + } & DrizzleConfig; + + if (typeof connection === 'object' && connection.url !== undefined) { + const { url, ...config } = connection; + + const instance = client(url, config); + return construct(instance, drizzleConfig) as any; + } + + const instance = client(connection); + return construct(instance, drizzleConfig) as any; + } + + const instance = client(params[0] as string); + + const db = construct(instance, params[1]); + + return db as any; +} diff --git a/drizzle-orm/src/tidb-serverless/driver.ts b/drizzle-orm/src/tidb-serverless/driver.ts index 2a7b1d986..b8b440970 100644 --- a/drizzle-orm/src/tidb-serverless/driver.ts +++ b/drizzle-orm/src/tidb-serverless/driver.ts @@ -1,4 +1,4 @@ -import type { Connection } from '@tidbcloud/serverless'; +import { type Config, connect, Connection } from '@tidbcloud/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { TiDBServerlessPreparedQueryHKT, TiDBServerlessQueryResultHKT } from './session.ts'; import { TiDBServerlessSession } from './session.ts'; @@ -24,7 +24,7 @@ export class TiDBServerlessDatabase< static override readonly [entityKind]: string = 'TiDBServerlessDatabase'; } -export function drizzle = Record>( +function construct = Record>( client: Connection, config: DrizzleConfig = {}, ): TiDBServerlessDatabase & { @@ -57,3 +57,53 @@ export function drizzle = Record = Record, + TClient extends Connection = Connection, +>( + ...params: IfNotImported< + Config, + [ImportTypeError<'@tidbcloud/serverless'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + }) + ), + ] + > +): TiDBServerlessDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof Connection) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'string') { + const instance = connect({ + url: params[0], + }); + + return construct(instance, params[1]) as any; + } + + const { connection, ...drizzleConfig } = params[0] as + & { connection: Config | string } + & DrizzleConfig; + + const instance = typeof connection === 'string' + ? connect({ + url: connection, + }) + : connect(connection); + + return construct(instance, drizzleConfig) as any; +} diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index c073448e3..be8b12454 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -236,4 +236,8 @@ export function getColumnNameAndConfig< config: typeof a === 'object' ? a : b as TConfig, }; } + export type IfNotImported = unknown extends T ? Y : N; + +export type ImportTypeError = + `Please install \`${TPackageName}\`to allow Drizzle ORM to connect to the database`; diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 5932a9fe5..1695ec8ec 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -1,3 +1,4 @@ +import { type QueryResult, type QueryResultRow, sql, type VercelPool } from '@vercel/postgres'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -9,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { type VercelPgClient, type VercelPgQueryResultHKT, VercelPgSession } from './session.ts'; export interface VercelPgDriverOptions { @@ -39,7 +40,7 @@ export class VercelPgDatabase< static override readonly [entityKind]: string = 'VercelPgDatabase'; } -export function drizzle = Record>( +function construct = Record>( client: VercelPgClient, config: DrizzleConfig = {}, ): VercelPgDatabase & { @@ -73,3 +74,49 @@ export function drizzle = Record = Record, + TClient extends VercelPgClient = + & VercelPool + & ((strings: TemplateStringsArray, ...values: Primitive[]) => Promise>), +>( + ...params: IfNotImported< + VercelPool, + [ImportTypeError<'@vercel/postgres'>], + [] | [ + TClient, + ] | [ + TClient, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection?: TClient; + }) + ), + ] + > +): VercelPgDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (typeof params[0] === 'function') { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (!params[0] || !(params[0] as { connection?: TClient }).connection) { + return construct(sql, params[0] as DrizzleConfig | undefined) as any; + } + + const { connection, ...drizzleConfig } = params[0] as ({ connection: TClient } & DrizzleConfig); + return construct(connection, drizzleConfig) as any; +} + +drizzle(sql, { + logger: true, + casing: 'camelCase', +}); From 98ca84f8f5c9edf6f47f446dbf25c17008240a22 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 14 Oct 2024 18:12:38 +0300 Subject: [PATCH 241/492] Fixed type error --- drizzle-orm/src/better-sqlite3/driver.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 8afc63272..89f1ddc3c 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -63,17 +63,16 @@ function construct = Record = Record, - TClient extends Database = Database, >( ...params: IfNotImported< Database, [ImportTypeError<'better-sqlite3'>], | [] | [ - TClient | string, + Database | string, ] | [ - TClient | string, + Database | string, DrizzleConfig, ] | [ @@ -86,11 +85,11 @@ export function drizzle< ] > ): BetterSQLite3Database & { - $client: TClient; + $client: Database; } { // eslint-disable-next-line no-instanceof/no-instanceof if (params instanceof Client) { - return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + return construct(params[0] as Database, params[1] as DrizzleConfig | undefined) as any; } if (typeof params[0] === 'object') { From 503ee014f7ab7ecec71b1026b0defa1a9b15fa52 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Mon, 14 Oct 2024 18:37:03 +0300 Subject: [PATCH 242/492] Fixed sqlite instance checks --- drizzle-orm/src/better-sqlite3/driver.ts | 2 +- drizzle-orm/src/bun-sqlite/driver.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 89f1ddc3c..ff3b7c4d9 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -88,7 +88,7 @@ export function drizzle< $client: Database; } { // eslint-disable-next-line no-instanceof/no-instanceof - if (params instanceof Client) { + if (params[0] instanceof Client) { return construct(params[0] as Database, params[1] as DrizzleConfig | undefined) as any; } diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index 4433d8508..484592a7c 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -110,7 +110,7 @@ export function drizzle< $client: TClient; } { // eslint-disable-next-line no-instanceof/no-instanceof - if (params instanceof Database) { + if (params[0] instanceof Database) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } From 13482c7d293095b363b781c690d104a137f7f47b Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Tue, 15 Oct 2024 10:56:05 +0300 Subject: [PATCH 243/492] Fixed mysql rename view sql statement --- drizzle-kit/src/sqlgenerator.ts | 2 +- drizzle-kit/tests/introspect/pg.test.ts | 2 -- drizzle-kit/tests/mysql-views.test.ts | 6 +++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 62346bdcf..586175e28 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -597,7 +597,7 @@ class MySqlRenameViewConvertor extends Convertor { convert(st: JsonRenameViewStatement) { const { nameFrom: from, nameTo: to } = st; - return `RENAME TABLE \`${from}\` RENAME TO \`${to}\`;`; + return `RENAME TABLE \`${from}\` TO \`${to}\`;`; } } diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index d9cc2eb75..bd8b15ab9 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -466,8 +466,6 @@ test('introspect checks from different schemas with same names', async () => { ['public', 'schema2'], ); - console.log('statements: ', statements); - expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); diff --git a/drizzle-kit/tests/mysql-views.test.ts b/drizzle-kit/tests/mysql-views.test.ts index 9a5b5db56..39cd6c09e 100644 --- a/drizzle-kit/tests/mysql-views.test.ts +++ b/drizzle-kit/tests/mysql-views.test.ts @@ -161,7 +161,7 @@ test('rename view', async () => { nameTo: 'new_some_view', }); expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` RENAME TO \`new_some_view\`;`); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); }); test('rename view and alter meta options', async () => { @@ -201,7 +201,7 @@ test('rename view and alter meta options', async () => { withCheckOption: 'cascaded', }); expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` RENAME TO \`new_some_view\`;`); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); expect(sqlStatements[1]).toBe(`ALTER ALGORITHM = undefined SQL SECURITY definer VIEW \`new_some_view\` AS SELECT * FROM \`users\` @@ -478,7 +478,7 @@ test('rename and alter view ".as" value', async () => { }); expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` RENAME TO \`new_some_view\`;`); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); expect(sqlStatements[1]).toBe(`CREATE OR REPLACE ALGORITHM = temptable SQL SECURITY invoker VIEW \`new_some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) From bff08bf444f300cfa94a447de69e1ac2aea57e84 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 15 Oct 2024 12:43:00 +0300 Subject: [PATCH 244/492] Fixed tests, added MockDriver & mock support for reworked drivers --- drizzle-orm/src/aws-data-api/pg/driver.ts | 39 ++++- drizzle-orm/src/better-sqlite3/driver.ts | 28 ++- drizzle-orm/src/bun-sqlite/driver.ts | 28 ++- drizzle-orm/src/libsql/driver.ts | 21 ++- drizzle-orm/src/mock.ts | 8 + drizzle-orm/src/mysql2/driver.ts | 18 +- drizzle-orm/src/neon-http/driver.ts | 18 +- drizzle-orm/src/neon-serverless/driver.ts | 18 +- drizzle-orm/src/node-postgres/driver.ts | 26 ++- drizzle-orm/src/pglite/driver.ts | 24 ++- drizzle-orm/src/postgres-js/driver.ts | 33 ++-- drizzle-orm/src/tidb-serverless/driver.ts | 21 ++- drizzle-orm/src/vercel-postgres/driver.ts | 24 ++- .../tests/replicas/mysql.test.ts | 161 +++++++++--------- .../tests/replicas/postgres.test.ts | 161 +++++++++--------- .../tests/replicas/sqlite.test.ts | 161 +++++++++--------- integration-tests/vitest.config.ts | 1 + 17 files changed, 497 insertions(+), 293 deletions(-) create mode 100644 drizzle-orm/src/mock.ts diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index 571c85800..f2556109d 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -2,6 +2,7 @@ import { RDSDataClient, type RDSDataClientConfig } from '@aws-sdk/client-rds-dat import { entityKind, is } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import type { PgColumn, PgInsertConfig, PgTable, TableConfig } from '~/pg-core/index.ts'; @@ -134,28 +135,52 @@ export function drizzle< DrizzleAwsDataApiPgConfig, ] | [ ( - & DrizzleConfig - & ({ - connection: RDSDataClientConfig & Omit; - }) + | ( + & DrizzleConfig + & { + connection: RDSDataClientConfig & Omit; + } + ) + | ( + & DrizzleAwsDataApiPgConfig + & { + client: TClient; + } + ) ), + ] | [ + MockDriver, + ] | [ + MockDriver, + DrizzleAwsDataApiPgConfig, ] > ): AwsDataApiPgDatabase & { $client: TClient; } { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as DrizzleAwsDataApiPgConfig) as any; + } + // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof RDSDataClient) { return construct(params[0] as TClient, params[1] as DrizzleAwsDataApiPgConfig) as any; } + if ((params[0] as { client?: TClient }).client) { + const { client, ...drizzleConfig } = params[0] as { + client: TClient; + } & DrizzleAwsDataApiPgConfig; + + return construct(client, drizzleConfig) as any; + } + const { connection, ...drizzleConfig } = params[0] as { connection: RDSDataClientConfig & Omit; } & DrizzleConfig; const { resourceArn, database, secretArn, ...rdsConfig } = connection; const instance = new RDSDataClient(rdsConfig); - const db = construct(instance, { resourceArn, database, secretArn, ...drizzleConfig }); - - return db as any; + return construct(instance, { resourceArn, database, secretArn, ...drizzleConfig }) as any; } diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index ff3b7c4d9..c6eeb63d5 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -1,6 +1,7 @@ import Client, { type Database, type Options, type RunResult } from 'better-sqlite3'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, @@ -79,23 +80,42 @@ export function drizzle< ( & DrizzleConfig & ({ - connection: DrizzleBetterSQLite3DatabaseConfig; + connection?: DrizzleBetterSQLite3DatabaseConfig; + } | { + client: Database; }) ), ] + | [ + MockDriver, + ] + | [ + MockDriver, + DrizzleConfig, + ] > ): BetterSQLite3Database & { $client: Database; } { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as DrizzleConfig) as any; + } + // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof Client) { return construct(params[0] as Database, params[1] as DrizzleConfig | undefined) as any; } if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: DrizzleBetterSQLite3DatabaseConfig; - } & DrizzleConfig; + const { connection, client, ...drizzleConfig } = params[0] as + & { + connection?: DrizzleBetterSQLite3DatabaseConfig; + client?: Database; + } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; if (typeof connection === 'object') { const { source, ...options } = connection; diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index 484592a7c..79620eb5e 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -3,6 +3,7 @@ import { Database } from 'bun:sqlite'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, @@ -101,23 +102,42 @@ export function drizzle< ( & DrizzleConfig & ({ - connection: DrizzleBunSqliteDatabaseConfig; + connection?: DrizzleBunSqliteDatabaseConfig; + } | { + client: TClient; }) ), ] + | [ + MockDriver, + ] + | [ + MockDriver, + DrizzleConfig, + ] > ): BunSQLiteDatabase & { $client: TClient; } { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as DrizzleConfig) as any; + } + // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof Database) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: DrizzleBunSqliteDatabaseConfig | string | undefined; - } & DrizzleConfig; + const { connection, client, ...drizzleConfig } = params[0] as + & ({ + connection?: DrizzleBunSqliteDatabaseConfig | string; + client?: TClient; + }) + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; if (typeof connection === 'object') { const { source, ...opts } = connection; diff --git a/drizzle-orm/src/libsql/driver.ts b/drizzle-orm/src/libsql/driver.ts index 0aa60943c..85b1d36a7 100644 --- a/drizzle-orm/src/libsql/driver.ts +++ b/drizzle-orm/src/libsql/driver.ts @@ -5,6 +5,7 @@ import { WsClient } from '@libsql/client/ws'; import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, @@ -82,13 +83,25 @@ export function drizzle< & DrizzleConfig & ({ connection: string | Config; + } | { + client: TClient; }) ), + ] | [ + MockDriver, + ] | [ + MockDriver, + DrizzleConfig, ] > ): LibSQLDatabase & { $client: TClient; } { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as DrizzleConfig) as any; + } + // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof WsClient || params[0] instanceof HttpClient || params[0] instanceof Sqlite3Client) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; @@ -102,9 +115,13 @@ export function drizzle< return construct(instance, params[1]) as any; } - const { connection, ...drizzleConfig } = params[0] as any as { connection: Config } & DrizzleConfig; + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config; client?: TClient } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; - const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection); + const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection!); return construct(instance, drizzleConfig) as any; } diff --git a/drizzle-orm/src/mock.ts b/drizzle-orm/src/mock.ts new file mode 100644 index 000000000..a5f258077 --- /dev/null +++ b/drizzle-orm/src/mock.ts @@ -0,0 +1,8 @@ +import { entityKind } from './entity.ts'; + +export class MockDriver { + /** @internal */ + static readonly [entityKind] = 'MockDriver'; +} + +export const mock = new MockDriver(); diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index ca113d88d..1a86336c0 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -3,6 +3,7 @@ import { type Connection as CallbackConnection, createPool, type Pool as Callbac import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { MySqlDatabase } from '~/mysql-core/db.ts'; import { MySqlDialect } from '~/mysql-core/dialect.ts'; import type { Mode } from '~/mysql-core/session.ts'; @@ -125,23 +126,34 @@ export function drizzle< & MySql2DrizzleConfig & ({ connection: string | PoolOptions; + } | { + client: TClient; }) ), - ] + ] | [ + MockDriver, + ] | [MockDriver, MySql2DrizzleConfig] > ): MySql2Database & { $client: TClient; } { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as MySql2DrizzleConfig) as any; + } + // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof EventEmitter) { return construct(params[0] as TClient, params[1] as MySql2DrizzleConfig | undefined) as any; } if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as - & { connection: PoolOptions | string } + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: PoolOptions | string; client?: TClient } & MySql2DrizzleConfig; + if (client) return construct(client, drizzleConfig) as any; + const instance = createPool(connection as PoolOptions); const db = construct(instance, drizzleConfig); diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index 8b0e97931..b4387e308 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -4,6 +4,7 @@ import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig } from '~/relations.ts'; @@ -115,28 +116,43 @@ export function drizzle< & DrizzleConfig & ({ connection: string | HTTPTransactionOptions; + } | { + client: TClient; }) ), + ] | [ + MockDriver, + ] | [ + MockDriver, + DrizzleConfig, ] > ): NeonHttpDatabase & { $client: TClient; } { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as DrizzleConfig) as any; + } + if ((params[0] as any)[Symbol.toStringTag] === 'NeonQueryPromise') { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as + const { connection, client, ...drizzleConfig } = params[0] as & { connection?: | ({ connectionString: string; } & HTTPTransactionOptions) | string; + client?: TClient; } & DrizzleConfig; + if (client) return construct(client, drizzleConfig); + if (typeof connection === 'object') { const { connectionString, ...options } = connection; diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index cac0fd829..02bff0b6e 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -2,6 +2,7 @@ import { neonConfig, Pool, type PoolConfig } from '@neondatabase/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { @@ -96,16 +97,28 @@ export function drizzle< & DrizzleConfig & ({ connection: string | PoolConfig; + } | { + client: TClient; }) & { ws?: any; } ), + ] | [ + MockDriver, + ] | [ + MockDriver, + DrizzleConfig, ] > ): NeonDatabase & { $client: TClient; } { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as DrizzleConfig) as any; + } + // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof Pool) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; @@ -120,15 +133,18 @@ export function drizzle< } if (typeof params[0] === 'object') { - const { connection, ws, ...drizzleConfig } = params[0] as { + const { connection, client, ws, ...drizzleConfig } = params[0] as { connection?: PoolConfig | string; ws?: any; + client?: TClient; } & DrizzleConfig; if (ws) { neonConfig.webSocketConstructor = ws; } + if (client) return construct(client, drizzleConfig); + const instance = typeof connection === 'string' ? new Pool({ connectionString: connection, diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index e345a3866..86d15e262 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -1,7 +1,9 @@ +import { EventEmitter } from 'events'; import pg, { type Pool, type PoolConfig } from 'pg'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { @@ -98,24 +100,40 @@ export function drizzle< & DrizzleConfig & ({ connection: string | PoolConfig; + } | { + client: TClient; }) ), ] + | [ + MockDriver, + ] + | [ + MockDriver, + DrizzleConfig, + ] > ): NodePgDatabase & { $client: TClient; } { // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof pg.Pool || params[0] instanceof pg.ClientBase) { + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as DrizzleConfig) as any; + } + + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof EventEmitter) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as ( - & ({ connection?: PoolConfig | string; driver?: TClient }) + const { connection, client, ...drizzleConfig } = params[0] as ( + & ({ connection?: PoolConfig | string; client?: TClient }) & DrizzleConfig ); + if (client) return construct(client, drizzleConfig); + const instance = typeof connection === 'string' ? new pg.Pool({ connectionString: connection, @@ -131,5 +149,3 @@ export function drizzle< return construct(instance, params[1] as DrizzleConfig | undefined) as any; } - -drizzle('', {}); diff --git a/drizzle-orm/src/pglite/driver.ts b/drizzle-orm/src/pglite/driver.ts index 3667ebcc4..e59313a10 100644 --- a/drizzle-orm/src/pglite/driver.ts +++ b/drizzle-orm/src/pglite/driver.ts @@ -2,6 +2,7 @@ import { PGlite, type PGliteOptions } from '@electric-sql/pglite'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { @@ -96,22 +97,39 @@ export function drizzle< & DrizzleConfig & ({ connection?: (PGliteOptions & { dataDir?: string }) | string; + } | { + client: TClient; }) ), ] + | [ + MockDriver, + ] + | [ + MockDriver, + DrizzleConfig, + ] > ): PgliteDatabase & { $client: TClient; } { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as DrizzleConfig) as any; + } + // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof PGlite) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: PGliteOptions & { dataDir: string }; - } & DrizzleConfig; + const { connection, client, ...drizzleConfig } = params[0] as { + connection?: PGliteOptions & { dataDir: string }; + client?: TClient; + } & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; if (typeof connection === 'object') { const { dataDir, ...options } = connection; diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index 5b62f241e..bdf7a8b32 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -1,6 +1,7 @@ -import client, { type Options, type PostgresType, type Sql } from 'postgres'; +import pgClient, { type Options, type PostgresType, type Sql } from 'postgres'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { @@ -80,36 +81,46 @@ export function drizzle< & DrizzleConfig & ({ connection: string | ({ url?: string } & Options>); + } | { + client: TClient; }) ), - ] + ] | [ + MockDriver, + ] | [MockDriver, DrizzleConfig] > ): PostgresJsDatabase & { $client: TClient; } { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as DrizzleConfig) as any; + } + if (typeof params[0] === 'function') { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: { url?: string } & Options>; - } & DrizzleConfig; + const { connection, client, ...drizzleConfig } = params[0] as { + connection?: { url?: string } & Options>; + client?: TClient; + } & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; if (typeof connection === 'object' && connection.url !== undefined) { const { url, ...config } = connection; - const instance = client(url, config); + const instance = pgClient(url, config); return construct(instance, drizzleConfig) as any; } - const instance = client(connection); + const instance = pgClient(connection); return construct(instance, drizzleConfig) as any; } - const instance = client(params[0] as string); - - const db = construct(instance, params[1]); + const instance = pgClient(params[0] as string); - return db as any; + return construct(instance, params[1]) as any; } diff --git a/drizzle-orm/src/tidb-serverless/driver.ts b/drizzle-orm/src/tidb-serverless/driver.ts index b8b440970..e34899fc5 100644 --- a/drizzle-orm/src/tidb-serverless/driver.ts +++ b/drizzle-orm/src/tidb-serverless/driver.ts @@ -2,6 +2,7 @@ import { type Config, connect, Connection } from '@tidbcloud/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { MySqlDatabase } from '~/mysql-core/db.ts'; import { MySqlDialect } from '~/mysql-core/dialect.ts'; import { @@ -75,13 +76,25 @@ export function drizzle< & DrizzleConfig & ({ connection: string | Config; + } | { + client: TClient; }) ), + ] | [ + MockDriver, + ] | [ + MockDriver, + TSchema, ] > ): TiDBServerlessDatabase & { $client: TClient; } { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as DrizzleConfig) as any; + } + // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof Connection) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; @@ -95,15 +108,17 @@ export function drizzle< return construct(instance, params[1]) as any; } - const { connection, ...drizzleConfig } = params[0] as - & { connection: Config | string } + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config | string; client?: TClient } & DrizzleConfig; + if (client) return construct(client, drizzleConfig) as any; + const instance = typeof connection === 'string' ? connect({ url: connection, }) - : connect(connection); + : connect(connection!); return construct(instance, drizzleConfig) as any; } diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 1695ec8ec..5123fb55e 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -2,6 +2,7 @@ import { type QueryResult, type QueryResultRow, sql, type VercelPool } from '@ve import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; +import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/index.ts'; import { @@ -95,28 +96,33 @@ export function drizzle< ( & DrizzleConfig & ({ - connection?: TClient; + client?: TClient; }) ), + ] | [ + MockDriver, + ] | [ + MockDriver, + DrizzleConfig, ] > ): VercelPgDatabase & { $client: TClient; } { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof MockDriver) { + return construct(params[0] as any, params[1] as DrizzleConfig) as any; + } + // eslint-disable-next-line no-instanceof/no-instanceof if (typeof params[0] === 'function') { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } - if (!params[0] || !(params[0] as { connection?: TClient }).connection) { + if (!params[0] || !(params[0] as { client?: TClient }).client) { return construct(sql, params[0] as DrizzleConfig | undefined) as any; } - const { connection, ...drizzleConfig } = params[0] as ({ connection: TClient } & DrizzleConfig); - return construct(connection, drizzleConfig) as any; + const { client, ...drizzleConfig } = params[0] as ({ client?: TClient } & DrizzleConfig); + return construct(client ?? sql, drizzleConfig) as any; } - -drizzle(sql, { - logger: true, - casing: 'camelCase', -}); diff --git a/integration-tests/tests/replicas/mysql.test.ts b/integration-tests/tests/replicas/mysql.test.ts index a7de02411..dd806c6fd 100644 --- a/integration-tests/tests/replicas/mysql.test.ts +++ b/integration-tests/tests/replicas/mysql.test.ts @@ -1,4 +1,5 @@ import { sql } from 'drizzle-orm'; +import { mock } from 'drizzle-orm/mock'; import { boolean, mysqlTable, serial, text, withReplicas } from 'drizzle-orm/mysql-core'; import { drizzle } from 'drizzle-orm/mysql2'; import { describe, expect, it, vi } from 'vitest'; @@ -15,9 +16,9 @@ const users = mysqlTable('users', { describe('[select] read replicas mysql', () => { it('primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -35,9 +36,9 @@ describe('[select] read replicas mysql', () => { }); it('random replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -64,8 +65,8 @@ describe('[select] read replicas mysql', () => { }); it('single read replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -84,8 +85,8 @@ describe('[select] read replicas mysql', () => { }); it('single read replica select + primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -105,9 +106,9 @@ describe('[select] read replicas mysql', () => { }); it('always first read select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -134,9 +135,9 @@ describe('[select] read replicas mysql', () => { describe('[selectDistinct] read replicas mysql', () => { it('primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -153,9 +154,9 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('random replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -181,8 +182,8 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('single read replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -201,8 +202,8 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('single read replica selectDistinct + primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -222,9 +223,9 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('always first read selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -250,9 +251,9 @@ describe('[selectDistinct] read replicas mysql', () => { describe('[with] read replicas mysql', () => { it('primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -273,9 +274,9 @@ describe('[with] read replicas mysql', () => { }); it('random replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -299,8 +300,8 @@ describe('[with] read replicas mysql', () => { }); it('single read replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -317,8 +318,8 @@ describe('[with] read replicas mysql', () => { }); it('single read replica with + primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -336,9 +337,9 @@ describe('[with] read replicas mysql', () => { }); it('always first read with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -367,9 +368,9 @@ describe('[with] read replicas mysql', () => { describe('[update] replicas mysql', () => { it('primary update', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -402,9 +403,9 @@ describe('[update] replicas mysql', () => { describe('[delete] replicas mysql', () => { it('primary delete', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -438,9 +439,9 @@ describe('[delete] replicas mysql', () => { describe('[insert] replicas mysql', () => { it('primary insert', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -473,9 +474,9 @@ describe('[insert] replicas mysql', () => { describe('[execute] replicas mysql', () => { it('primary execute', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -515,9 +516,9 @@ describe('[execute] replicas mysql', () => { describe('[transaction] replicas mysql', () => { it('primary transaction', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -558,9 +559,9 @@ describe('[transaction] replicas mysql', () => { describe('[findFirst] read replicas mysql', () => { it('primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2]); @@ -578,9 +579,9 @@ describe('[findFirst] read replicas mysql', () => { }); it('random replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -607,8 +608,8 @@ describe('[findFirst] read replicas mysql', () => { }); it('single read replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -625,8 +626,8 @@ describe('[findFirst] read replicas mysql', () => { }); it('single read replica findFirst + primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -644,9 +645,9 @@ describe('[findFirst] read replicas mysql', () => { }); it('always first read findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -670,9 +671,9 @@ describe('[findFirst] read replicas mysql', () => { describe('[findMany] read replicas mysql', () => { it('primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2]); @@ -691,9 +692,9 @@ describe('[findMany] read replicas mysql', () => { }); it('random replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -724,8 +725,8 @@ describe('[findMany] read replicas mysql', () => { }); it('single read replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -748,8 +749,8 @@ describe('[findMany] read replicas mysql', () => { }); it('single read replica findMany + primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -774,9 +775,9 @@ describe('[findMany] read replicas mysql', () => { }); it('always first read findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; diff --git a/integration-tests/tests/replicas/postgres.test.ts b/integration-tests/tests/replicas/postgres.test.ts index 6165ae413..2d36f80ef 100644 --- a/integration-tests/tests/replicas/postgres.test.ts +++ b/integration-tests/tests/replicas/postgres.test.ts @@ -1,4 +1,5 @@ import { sql } from 'drizzle-orm'; +import { mock } from 'drizzle-orm/mock'; import { drizzle } from 'drizzle-orm/node-postgres'; import { boolean, jsonb, pgTable, serial, text, timestamp, withReplicas } from 'drizzle-orm/pg-core'; import { describe, expect, it, vi } from 'vitest'; @@ -17,9 +18,9 @@ const users = pgTable('users', { describe('[select] read replicas postgres', () => { it('primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -37,9 +38,9 @@ describe('[select] read replicas postgres', () => { }); it('random replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -66,8 +67,8 @@ describe('[select] read replicas postgres', () => { }); it('single read replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -86,8 +87,8 @@ describe('[select] read replicas postgres', () => { }); it('single read replica select + primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -107,9 +108,9 @@ describe('[select] read replicas postgres', () => { }); it('always first read select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -136,9 +137,9 @@ describe('[select] read replicas postgres', () => { describe('[selectDistinct] read replicas postgres', () => { it('primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -155,9 +156,9 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('random replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -183,8 +184,8 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('single read replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -203,8 +204,8 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('single read replica selectDistinct + primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -224,9 +225,9 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('always first read selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -252,9 +253,9 @@ describe('[selectDistinct] read replicas postgres', () => { describe('[with] read replicas postgres', () => { it('primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -275,9 +276,9 @@ describe('[with] read replicas postgres', () => { }); it('random replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -301,8 +302,8 @@ describe('[with] read replicas postgres', () => { }); it('single read replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -319,8 +320,8 @@ describe('[with] read replicas postgres', () => { }); it('single read replica with + primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -338,9 +339,9 @@ describe('[with] read replicas postgres', () => { }); it('always first read with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -369,9 +370,9 @@ describe('[with] read replicas postgres', () => { describe('[update] replicas postgres', () => { it('primary update', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -404,9 +405,9 @@ describe('[update] replicas postgres', () => { describe('[delete] replicas postgres', () => { it('primary delete', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -440,9 +441,9 @@ describe('[delete] replicas postgres', () => { describe('[insert] replicas postgres', () => { it('primary insert', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -475,9 +476,9 @@ describe('[insert] replicas postgres', () => { describe('[execute] replicas postgres', () => { it('primary execute', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -517,9 +518,9 @@ describe('[execute] replicas postgres', () => { describe('[transaction] replicas postgres', () => { it('primary transaction', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -560,9 +561,9 @@ describe('[transaction] replicas postgres', () => { describe('[findFirst] read replicas postgres', () => { it('primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -580,9 +581,9 @@ describe('[findFirst] read replicas postgres', () => { }); it('random replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -611,8 +612,8 @@ describe('[findFirst] read replicas postgres', () => { }); it('single read replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -629,8 +630,8 @@ describe('[findFirst] read replicas postgres', () => { }); it('single read replica findFirst + primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -648,9 +649,9 @@ describe('[findFirst] read replicas postgres', () => { }); it('always first read findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -674,9 +675,9 @@ describe('[findFirst] read replicas postgres', () => { describe('[findMany] read replicas postgres', () => { it('primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -697,9 +698,9 @@ describe('[findMany] read replicas postgres', () => { }); it('random replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -734,8 +735,8 @@ describe('[findMany] read replicas postgres', () => { }); it('single read replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -762,8 +763,8 @@ describe('[findMany] read replicas postgres', () => { }); it('single read replica findMany + primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -792,9 +793,9 @@ describe('[findMany] read replicas postgres', () => { }); it('always first read findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; diff --git a/integration-tests/tests/replicas/sqlite.test.ts b/integration-tests/tests/replicas/sqlite.test.ts index 4093a6298..08f33ecf8 100644 --- a/integration-tests/tests/replicas/sqlite.test.ts +++ b/integration-tests/tests/replicas/sqlite.test.ts @@ -1,5 +1,6 @@ import { sql } from 'drizzle-orm'; import { drizzle } from 'drizzle-orm/libsql'; +import { mock } from 'drizzle-orm/mock'; import { int, sqliteTable, text, withReplicas } from 'drizzle-orm/sqlite-core'; import { describe, expect, it, vi } from 'vitest'; @@ -15,9 +16,9 @@ const users = sqliteTable('users', { describe('[select] read replicas sqlite', () => { it('primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -35,9 +36,9 @@ describe('[select] read replicas sqlite', () => { }); it('random replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -64,8 +65,8 @@ describe('[select] read replicas sqlite', () => { }); it('single read replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -84,8 +85,8 @@ describe('[select] read replicas sqlite', () => { }); it('single read replica select + primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -105,9 +106,9 @@ describe('[select] read replicas sqlite', () => { }); it('always first read select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -134,9 +135,9 @@ describe('[select] read replicas sqlite', () => { describe('[selectDistinct] read replicas sqlite', () => { it('primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -153,9 +154,9 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('random replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -181,8 +182,8 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('single read replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -201,8 +202,8 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('single read replica selectDistinct + primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -222,9 +223,9 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('always first read selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -250,9 +251,9 @@ describe('[selectDistinct] read replicas sqlite', () => { describe('[with] read replicas sqlite', () => { it('primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -273,9 +274,9 @@ describe('[with] read replicas sqlite', () => { }); it('random replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -299,8 +300,8 @@ describe('[with] read replicas sqlite', () => { }); it('single read replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -317,8 +318,8 @@ describe('[with] read replicas sqlite', () => { }); it('single read replica with + primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); const db = withReplicas(primaryDb, [read1]); @@ -336,9 +337,9 @@ describe('[with] read replicas sqlite', () => { }); it('always first read with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -367,9 +368,9 @@ describe('[with] read replicas sqlite', () => { describe('[update] replicas sqlite', () => { it('primary update', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -402,9 +403,9 @@ describe('[update] replicas sqlite', () => { describe('[delete] replicas sqlite', () => { it('primary delete', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -438,9 +439,9 @@ describe('[delete] replicas sqlite', () => { describe('[insert] replicas sqlite', () => { it('primary insert', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -473,9 +474,9 @@ describe('[insert] replicas sqlite', () => { describe('[execute] replicas sqlite', () => { it('primary execute', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -511,9 +512,9 @@ describe('[execute] replicas sqlite', () => { describe('[transaction] replicas sqlite', () => { it('primary transaction', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle(mock); + const read1 = drizzle(mock); + const read2 = drizzle(mock); const db = withReplicas(primaryDb, [read1, read2]); @@ -554,9 +555,9 @@ describe('[transaction] replicas sqlite', () => { describe('[findFirst] read replicas sqlite', () => { it('primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -574,9 +575,9 @@ describe('[findFirst] read replicas sqlite', () => { }); it('random replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -603,8 +604,8 @@ describe('[findFirst] read replicas sqlite', () => { }); it('single read replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -621,8 +622,8 @@ describe('[findFirst] read replicas sqlite', () => { }); it('single read replica findFirst + primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -640,9 +641,9 @@ describe('[findFirst] read replicas sqlite', () => { }); it('always first read findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -666,9 +667,9 @@ describe('[findFirst] read replicas sqlite', () => { describe('[findMany] read replicas sqlite', () => { it('primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -687,9 +688,9 @@ describe('[findMany] read replicas sqlite', () => { }); it('random replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -720,8 +721,8 @@ describe('[findMany] read replicas sqlite', () => { }); it('single read replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -744,8 +745,8 @@ describe('[findMany] read replicas sqlite', () => { }); it('single read replica findMany + primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -770,9 +771,9 @@ describe('[findMany] read replicas sqlite', () => { }); it('always first read findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle(mock, { schema: { usersTable } }); + const read1 = drizzle(mock, { schema: { usersTable } }); + const read2 = drizzle(mock, { schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index cbd18f591..3952eca49 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -14,6 +14,7 @@ export default defineConfig({ 'tests/imports/**/*', 'tests/extensions/vectors/**/*', 'tests/version.test.ts', + 'tests/pg/node-postgres.test.ts', ], exclude: [ ...(process.env.SKIP_EXTERNAL_DB_TESTS From 00e689eaf0bcfa081335bacece8fdd51d2e93a1d Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 15 Oct 2024 15:11:46 +0300 Subject: [PATCH 245/492] Added `drizzle.mock()`, reworked replicas tests --- drizzle-orm/src/aws-data-api/pg/driver.ts | 21 ++- drizzle-orm/src/better-sqlite3/driver.ts | 23 ++- drizzle-orm/src/bun-sqlite/driver.ts | 23 ++- drizzle-orm/src/libsql/driver.ts | 21 ++- drizzle-orm/src/mock.ts | 8 - drizzle-orm/src/mysql2/driver.ts | 20 ++- drizzle-orm/src/neon-http/driver.ts | 21 ++- drizzle-orm/src/neon-serverless/driver.ts | 21 ++- drizzle-orm/src/node-postgres/driver.ts | 23 ++- drizzle-orm/src/pglite/driver.ts | 23 ++- .../src/planetscale-serverless/driver.ts | 10 ++ drizzle-orm/src/postgres-js/driver.ts | 20 ++- drizzle-orm/src/tidb-serverless/driver.ts | 35 ++-- drizzle-orm/src/vercel-postgres/driver.ts | 21 ++- .../tests/replicas/mysql.test.ts | 161 +++++++++--------- .../tests/replicas/postgres.test.ts | 161 +++++++++--------- .../tests/replicas/sqlite.test.ts | 161 +++++++++--------- 17 files changed, 378 insertions(+), 395 deletions(-) delete mode 100644 drizzle-orm/src/mock.ts diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index f2556109d..1d59bea62 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -2,7 +2,6 @@ import { RDSDataClient, type RDSDataClientConfig } from '@aws-sdk/client-rds-dat import { entityKind, is } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import type { PgColumn, PgInsertConfig, PgTable, TableConfig } from '~/pg-core/index.ts'; @@ -148,21 +147,11 @@ export function drizzle< } ) ), - ] | [ - MockDriver, - ] | [ - MockDriver, - DrizzleAwsDataApiPgConfig, ] > ): AwsDataApiPgDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as DrizzleAwsDataApiPgConfig) as any; - } - // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof RDSDataClient) { return construct(params[0] as TClient, params[1] as DrizzleAwsDataApiPgConfig) as any; @@ -184,3 +173,13 @@ export function drizzle< const instance = new RDSDataClient(rdsConfig); return construct(instance, { resourceArn, database, secretArn, ...drizzleConfig }) as any; } + +export namespace drizzle { + export function mock = Record>( + config: DrizzleAwsDataApiPgConfig, + ): AwsDataApiPgDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index c6eeb63d5..14e6644bc 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -1,7 +1,6 @@ import Client, { type Database, type Options, type RunResult } from 'better-sqlite3'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, @@ -86,22 +85,10 @@ export function drizzle< }) ), ] - | [ - MockDriver, - ] - | [ - MockDriver, - DrizzleConfig, - ] > ): BetterSQLite3Database & { $client: Database; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as DrizzleConfig) as any; - } - // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof Client) { return construct(params[0] as Database, params[1] as DrizzleConfig | undefined) as any; @@ -134,3 +121,13 @@ export function drizzle< return construct(instance, params[1]) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): BetterSQLite3Database & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index 79620eb5e..91a2e370b 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -3,7 +3,6 @@ import { Database } from 'bun:sqlite'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, @@ -108,22 +107,10 @@ export function drizzle< }) ), ] - | [ - MockDriver, - ] - | [ - MockDriver, - DrizzleConfig, - ] > ): BunSQLiteDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as DrizzleConfig) as any; - } - // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof Database) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; @@ -158,3 +145,13 @@ export function drizzle< return construct(instance, params[1]) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): BunSQLiteDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/libsql/driver.ts b/drizzle-orm/src/libsql/driver.ts index 85b1d36a7..c5e3957d2 100644 --- a/drizzle-orm/src/libsql/driver.ts +++ b/drizzle-orm/src/libsql/driver.ts @@ -5,7 +5,6 @@ import { WsClient } from '@libsql/client/ws'; import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, @@ -87,21 +86,11 @@ export function drizzle< client: TClient; }) ), - ] | [ - MockDriver, - ] | [ - MockDriver, - DrizzleConfig, ] > ): LibSQLDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as DrizzleConfig) as any; - } - // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof WsClient || params[0] instanceof HttpClient || params[0] instanceof Sqlite3Client) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; @@ -125,3 +114,13 @@ export function drizzle< return construct(instance, drizzleConfig) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): LibSQLDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/mock.ts b/drizzle-orm/src/mock.ts deleted file mode 100644 index a5f258077..000000000 --- a/drizzle-orm/src/mock.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { entityKind } from './entity.ts'; - -export class MockDriver { - /** @internal */ - static readonly [entityKind] = 'MockDriver'; -} - -export const mock = new MockDriver(); diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index 1a86336c0..0bf11684f 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -3,7 +3,6 @@ import { type Connection as CallbackConnection, createPool, type Pool as Callbac import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { MySqlDatabase } from '~/mysql-core/db.ts'; import { MySqlDialect } from '~/mysql-core/dialect.ts'; import type { Mode } from '~/mysql-core/session.ts'; @@ -130,18 +129,11 @@ export function drizzle< client: TClient; }) ), - ] | [ - MockDriver, - ] | [MockDriver, MySql2DrizzleConfig] + ] > ): MySql2Database & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as MySql2DrizzleConfig) as any; - } - // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof EventEmitter) { return construct(params[0] as TClient, params[1] as MySql2DrizzleConfig | undefined) as any; @@ -167,3 +159,13 @@ export function drizzle< return construct(instance, params[1]) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: MySql2DrizzleConfig, + ): MySql2Database & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index b4387e308..17f92f13a 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -4,7 +4,6 @@ import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig } from '~/relations.ts'; @@ -120,21 +119,11 @@ export function drizzle< client: TClient; }) ), - ] | [ - MockDriver, - ] | [ - MockDriver, - DrizzleConfig, ] > ): NeonHttpDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as DrizzleConfig) as any; - } - if ((params[0] as any)[Symbol.toStringTag] === 'NeonQueryPromise') { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } @@ -169,3 +158,13 @@ export function drizzle< const instance = neon(params[0] as string); return construct(instance, params[1]) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): NeonHttpDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index 02bff0b6e..0e23a317b 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -2,7 +2,6 @@ import { neonConfig, Pool, type PoolConfig } from '@neondatabase/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { @@ -104,21 +103,11 @@ export function drizzle< ws?: any; } ), - ] | [ - MockDriver, - ] | [ - MockDriver, - DrizzleConfig, ] > ): NeonDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as DrizzleConfig) as any; - } - // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof Pool) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; @@ -158,3 +147,13 @@ export function drizzle< return construct(instance, params[1]) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): NeonDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index 86d15e262..b9bb063d8 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -3,7 +3,6 @@ import pg, { type Pool, type PoolConfig } from 'pg'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { @@ -105,22 +104,10 @@ export function drizzle< }) ), ] - | [ - MockDriver, - ] - | [ - MockDriver, - DrizzleConfig, - ] > ): NodePgDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as DrizzleConfig) as any; - } - // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof EventEmitter) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; @@ -149,3 +136,13 @@ export function drizzle< return construct(instance, params[1] as DrizzleConfig | undefined) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): NodePgDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/pglite/driver.ts b/drizzle-orm/src/pglite/driver.ts index e59313a10..89d37d1f9 100644 --- a/drizzle-orm/src/pglite/driver.ts +++ b/drizzle-orm/src/pglite/driver.ts @@ -2,7 +2,6 @@ import { PGlite, type PGliteOptions } from '@electric-sql/pglite'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { @@ -102,22 +101,10 @@ export function drizzle< }) ), ] - | [ - MockDriver, - ] - | [ - MockDriver, - DrizzleConfig, - ] > ): PgliteDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as DrizzleConfig) as any; - } - // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof PGlite) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; @@ -147,3 +134,13 @@ export function drizzle< const instance = new PGlite(params[0]); return construct(instance, params[1]) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): PgliteDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index 621c30b10..75da22ec9 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -147,3 +147,13 @@ export function drizzle< return construct(instance, params[1]) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): PlanetScaleDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index bdf7a8b32..5c2979c84 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -1,7 +1,6 @@ import pgClient, { type Options, type PostgresType, type Sql } from 'postgres'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { @@ -85,18 +84,11 @@ export function drizzle< client: TClient; }) ), - ] | [ - MockDriver, - ] | [MockDriver, DrizzleConfig] + ] > ): PostgresJsDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as DrizzleConfig) as any; - } - if (typeof params[0] === 'function') { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } @@ -124,3 +116,13 @@ export function drizzle< return construct(instance, params[1]) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): PostgresJsDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/tidb-serverless/driver.ts b/drizzle-orm/src/tidb-serverless/driver.ts index e34899fc5..01f54af6e 100644 --- a/drizzle-orm/src/tidb-serverless/driver.ts +++ b/drizzle-orm/src/tidb-serverless/driver.ts @@ -2,7 +2,6 @@ import { type Config, connect, Connection } from '@tidbcloud/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { MySqlDatabase } from '~/mysql-core/db.ts'; import { MySqlDialect } from '~/mysql-core/dialect.ts'; import { @@ -72,29 +71,17 @@ export function drizzle< TClient | string, DrizzleConfig, ] | [ - ( - & DrizzleConfig - & ({ - connection: string | Config; - } | { - client: TClient; - }) - ), - ] | [ - MockDriver, - ] | [ - MockDriver, - TSchema, + & ({ + connection: string | Config; + } | { + client: TClient; + }) + & DrizzleConfig, ] > ): TiDBServerlessDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as DrizzleConfig) as any; - } - // eslint-disable-next-line no-instanceof/no-instanceof if (params[0] instanceof Connection) { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; @@ -122,3 +109,13 @@ export function drizzle< return construct(instance, drizzleConfig) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): TiDBServerlessDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 5123fb55e..5e6c44c27 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -2,7 +2,6 @@ import { type QueryResult, type QueryResultRow, sql, type VercelPool } from '@ve import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; -import { MockDriver } from '~/mock.ts'; import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/index.ts'; import { @@ -99,21 +98,11 @@ export function drizzle< client?: TClient; }) ), - ] | [ - MockDriver, - ] | [ - MockDriver, - DrizzleConfig, ] > ): VercelPgDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof MockDriver) { - return construct(params[0] as any, params[1] as DrizzleConfig) as any; - } - // eslint-disable-next-line no-instanceof/no-instanceof if (typeof params[0] === 'function') { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; @@ -126,3 +115,13 @@ export function drizzle< const { client, ...drizzleConfig } = params[0] as ({ client?: TClient } & DrizzleConfig); return construct(client ?? sql, drizzleConfig) as any; } + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): VercelPgDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/integration-tests/tests/replicas/mysql.test.ts b/integration-tests/tests/replicas/mysql.test.ts index dd806c6fd..673a8da65 100644 --- a/integration-tests/tests/replicas/mysql.test.ts +++ b/integration-tests/tests/replicas/mysql.test.ts @@ -1,5 +1,4 @@ import { sql } from 'drizzle-orm'; -import { mock } from 'drizzle-orm/mock'; import { boolean, mysqlTable, serial, text, withReplicas } from 'drizzle-orm/mysql-core'; import { drizzle } from 'drizzle-orm/mysql2'; import { describe, expect, it, vi } from 'vitest'; @@ -16,9 +15,9 @@ const users = mysqlTable('users', { describe('[select] read replicas mysql', () => { it('primary select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -36,9 +35,9 @@ describe('[select] read replicas mysql', () => { }); it('random replica select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -65,8 +64,8 @@ describe('[select] read replicas mysql', () => { }); it('single read replica select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -85,8 +84,8 @@ describe('[select] read replicas mysql', () => { }); it('single read replica select + primary select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -106,9 +105,9 @@ describe('[select] read replicas mysql', () => { }); it('always first read select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -135,9 +134,9 @@ describe('[select] read replicas mysql', () => { describe('[selectDistinct] read replicas mysql', () => { it('primary selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -154,9 +153,9 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('random replica selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -182,8 +181,8 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('single read replica selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -202,8 +201,8 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('single read replica selectDistinct + primary selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -223,9 +222,9 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('always first read selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -251,9 +250,9 @@ describe('[selectDistinct] read replicas mysql', () => { describe('[with] read replicas mysql', () => { it('primary with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -274,9 +273,9 @@ describe('[with] read replicas mysql', () => { }); it('random replica with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -300,8 +299,8 @@ describe('[with] read replicas mysql', () => { }); it('single read replica with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -318,8 +317,8 @@ describe('[with] read replicas mysql', () => { }); it('single read replica with + primary with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -337,9 +336,9 @@ describe('[with] read replicas mysql', () => { }); it('always first read with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -368,9 +367,9 @@ describe('[with] read replicas mysql', () => { describe('[update] replicas mysql', () => { it('primary update', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -403,9 +402,9 @@ describe('[update] replicas mysql', () => { describe('[delete] replicas mysql', () => { it('primary delete', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -439,9 +438,9 @@ describe('[delete] replicas mysql', () => { describe('[insert] replicas mysql', () => { it('primary insert', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -474,9 +473,9 @@ describe('[insert] replicas mysql', () => { describe('[execute] replicas mysql', () => { it('primary execute', async () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -516,9 +515,9 @@ describe('[execute] replicas mysql', () => { describe('[transaction] replicas mysql', () => { it('primary transaction', async () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -559,9 +558,9 @@ describe('[transaction] replicas mysql', () => { describe('[findFirst] read replicas mysql', () => { it('primary findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2]); @@ -579,9 +578,9 @@ describe('[findFirst] read replicas mysql', () => { }); it('random replica findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -608,8 +607,8 @@ describe('[findFirst] read replicas mysql', () => { }); it('single read replica findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -626,8 +625,8 @@ describe('[findFirst] read replicas mysql', () => { }); it('single read replica findFirst + primary findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -645,9 +644,9 @@ describe('[findFirst] read replicas mysql', () => { }); it('always first read findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -671,9 +670,9 @@ describe('[findFirst] read replicas mysql', () => { describe('[findMany] read replicas mysql', () => { it('primary findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2]); @@ -692,9 +691,9 @@ describe('[findMany] read replicas mysql', () => { }); it('random replica findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -725,8 +724,8 @@ describe('[findMany] read replicas mysql', () => { }); it('single read replica findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -749,8 +748,8 @@ describe('[findMany] read replicas mysql', () => { }); it('single read replica findMany + primary findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -775,9 +774,9 @@ describe('[findMany] read replicas mysql', () => { }); it('always first read findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle(mock, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; diff --git a/integration-tests/tests/replicas/postgres.test.ts b/integration-tests/tests/replicas/postgres.test.ts index 2d36f80ef..0860aac6a 100644 --- a/integration-tests/tests/replicas/postgres.test.ts +++ b/integration-tests/tests/replicas/postgres.test.ts @@ -1,5 +1,4 @@ import { sql } from 'drizzle-orm'; -import { mock } from 'drizzle-orm/mock'; import { drizzle } from 'drizzle-orm/node-postgres'; import { boolean, jsonb, pgTable, serial, text, timestamp, withReplicas } from 'drizzle-orm/pg-core'; import { describe, expect, it, vi } from 'vitest'; @@ -18,9 +17,9 @@ const users = pgTable('users', { describe('[select] read replicas postgres', () => { it('primary select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -38,9 +37,9 @@ describe('[select] read replicas postgres', () => { }); it('random replica select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -67,8 +66,8 @@ describe('[select] read replicas postgres', () => { }); it('single read replica select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -87,8 +86,8 @@ describe('[select] read replicas postgres', () => { }); it('single read replica select + primary select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -108,9 +107,9 @@ describe('[select] read replicas postgres', () => { }); it('always first read select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -137,9 +136,9 @@ describe('[select] read replicas postgres', () => { describe('[selectDistinct] read replicas postgres', () => { it('primary selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -156,9 +155,9 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('random replica selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -184,8 +183,8 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('single read replica selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -204,8 +203,8 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('single read replica selectDistinct + primary selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -225,9 +224,9 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('always first read selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -253,9 +252,9 @@ describe('[selectDistinct] read replicas postgres', () => { describe('[with] read replicas postgres', () => { it('primary with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -276,9 +275,9 @@ describe('[with] read replicas postgres', () => { }); it('random replica with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -302,8 +301,8 @@ describe('[with] read replicas postgres', () => { }); it('single read replica with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -320,8 +319,8 @@ describe('[with] read replicas postgres', () => { }); it('single read replica with + primary with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -339,9 +338,9 @@ describe('[with] read replicas postgres', () => { }); it('always first read with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -370,9 +369,9 @@ describe('[with] read replicas postgres', () => { describe('[update] replicas postgres', () => { it('primary update', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -405,9 +404,9 @@ describe('[update] replicas postgres', () => { describe('[delete] replicas postgres', () => { it('primary delete', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -441,9 +440,9 @@ describe('[delete] replicas postgres', () => { describe('[insert] replicas postgres', () => { it('primary insert', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -476,9 +475,9 @@ describe('[insert] replicas postgres', () => { describe('[execute] replicas postgres', () => { it('primary execute', async () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -518,9 +517,9 @@ describe('[execute] replicas postgres', () => { describe('[transaction] replicas postgres', () => { it('primary transaction', async () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -561,9 +560,9 @@ describe('[transaction] replicas postgres', () => { describe('[findFirst] read replicas postgres', () => { it('primary findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -581,9 +580,9 @@ describe('[findFirst] read replicas postgres', () => { }); it('random replica findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -612,8 +611,8 @@ describe('[findFirst] read replicas postgres', () => { }); it('single read replica findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -630,8 +629,8 @@ describe('[findFirst] read replicas postgres', () => { }); it('single read replica findFirst + primary findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -649,9 +648,9 @@ describe('[findFirst] read replicas postgres', () => { }); it('always first read findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -675,9 +674,9 @@ describe('[findFirst] read replicas postgres', () => { describe('[findMany] read replicas postgres', () => { it('primary findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -698,9 +697,9 @@ describe('[findMany] read replicas postgres', () => { }); it('random replica findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -735,8 +734,8 @@ describe('[findMany] read replicas postgres', () => { }); it('single read replica findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -763,8 +762,8 @@ describe('[findMany] read replicas postgres', () => { }); it('single read replica findMany + primary findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -793,9 +792,9 @@ describe('[findMany] read replicas postgres', () => { }); it('always first read findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; diff --git a/integration-tests/tests/replicas/sqlite.test.ts b/integration-tests/tests/replicas/sqlite.test.ts index 08f33ecf8..aab55bbfd 100644 --- a/integration-tests/tests/replicas/sqlite.test.ts +++ b/integration-tests/tests/replicas/sqlite.test.ts @@ -1,6 +1,5 @@ import { sql } from 'drizzle-orm'; import { drizzle } from 'drizzle-orm/libsql'; -import { mock } from 'drizzle-orm/mock'; import { int, sqliteTable, text, withReplicas } from 'drizzle-orm/sqlite-core'; import { describe, expect, it, vi } from 'vitest'; @@ -16,9 +15,9 @@ const users = sqliteTable('users', { describe('[select] read replicas sqlite', () => { it('primary select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -36,9 +35,9 @@ describe('[select] read replicas sqlite', () => { }); it('random replica select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -65,8 +64,8 @@ describe('[select] read replicas sqlite', () => { }); it('single read replica select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -85,8 +84,8 @@ describe('[select] read replicas sqlite', () => { }); it('single read replica select + primary select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -106,9 +105,9 @@ describe('[select] read replicas sqlite', () => { }); it('always first read select', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -135,9 +134,9 @@ describe('[select] read replicas sqlite', () => { describe('[selectDistinct] read replicas sqlite', () => { it('primary selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -154,9 +153,9 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('random replica selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -182,8 +181,8 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('single read replica selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -202,8 +201,8 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('single read replica selectDistinct + primary selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -223,9 +222,9 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('always first read selectDistinct', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -251,9 +250,9 @@ describe('[selectDistinct] read replicas sqlite', () => { describe('[with] read replicas sqlite', () => { it('primary with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -274,9 +273,9 @@ describe('[with] read replicas sqlite', () => { }); it('random replica with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -300,8 +299,8 @@ describe('[with] read replicas sqlite', () => { }); it('single read replica with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -318,8 +317,8 @@ describe('[with] read replicas sqlite', () => { }); it('single read replica with + primary with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -337,9 +336,9 @@ describe('[with] read replicas sqlite', () => { }); it('always first read with', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -368,9 +367,9 @@ describe('[with] read replicas sqlite', () => { describe('[update] replicas sqlite', () => { it('primary update', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -403,9 +402,9 @@ describe('[update] replicas sqlite', () => { describe('[delete] replicas sqlite', () => { it('primary delete', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -439,9 +438,9 @@ describe('[delete] replicas sqlite', () => { describe('[insert] replicas sqlite', () => { it('primary insert', () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -474,9 +473,9 @@ describe('[insert] replicas sqlite', () => { describe('[execute] replicas sqlite', () => { it('primary execute', async () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -512,9 +511,9 @@ describe('[execute] replicas sqlite', () => { describe('[transaction] replicas sqlite', () => { it('primary transaction', async () => { - const primaryDb = drizzle(mock); - const read1 = drizzle(mock); - const read2 = drizzle(mock); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -555,9 +554,9 @@ describe('[transaction] replicas sqlite', () => { describe('[findFirst] read replicas sqlite', () => { it('primary findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -575,9 +574,9 @@ describe('[findFirst] read replicas sqlite', () => { }); it('random replica findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -604,8 +603,8 @@ describe('[findFirst] read replicas sqlite', () => { }); it('single read replica findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -622,8 +621,8 @@ describe('[findFirst] read replicas sqlite', () => { }); it('single read replica findFirst + primary findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -641,9 +640,9 @@ describe('[findFirst] read replicas sqlite', () => { }); it('always first read findFirst', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -667,9 +666,9 @@ describe('[findFirst] read replicas sqlite', () => { describe('[findMany] read replicas sqlite', () => { it('primary findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -688,9 +687,9 @@ describe('[findMany] read replicas sqlite', () => { }); it('random replica findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -721,8 +720,8 @@ describe('[findMany] read replicas sqlite', () => { }); it('single read replica findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -745,8 +744,8 @@ describe('[findMany] read replicas sqlite', () => { }); it('single read replica findMany + primary findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -771,9 +770,9 @@ describe('[findMany] read replicas sqlite', () => { }); it('always first read findMany', () => { - const primaryDb = drizzle(mock, { schema: { usersTable } }); - const read1 = drizzle(mock, { schema: { usersTable } }); - const read2 = drizzle(mock, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; From 74c5acf6fabf57f99ead030dd29c7802733eba4f Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 15 Oct 2024 15:53:49 +0300 Subject: [PATCH 246/492] Fixed neon client identification --- drizzle-orm/src/neon-http/driver.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index 17f92f13a..24c52e6e7 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -124,7 +124,8 @@ export function drizzle< ): NeonHttpDatabase & { $client: TClient; } { - if ((params[0] as any)[Symbol.toStringTag] === 'NeonQueryPromise') { + // eslint-disable-next-line no-instanceof/no-instanceof + if (typeof params[0] === 'function') { return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } From a88d6b64cee70ff9ed8da3f063634e91d21e1781 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 15 Oct 2024 16:45:53 +0300 Subject: [PATCH 247/492] Removed `bun-sqlite` from import tests --- integration-tests/tests/imports/index.test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/integration-tests/tests/imports/index.test.ts b/integration-tests/tests/imports/index.test.ts index dee96e84f..875d1d24c 100644 --- a/integration-tests/tests/imports/index.test.ts +++ b/integration-tests/tests/imports/index.test.ts @@ -18,7 +18,10 @@ it('dynamic imports check for CommonJS', async () => { const promises: ProcessPromise[] = []; for (const [i, key] of Object.keys(pj['exports']).entries()) { const o1 = path.join('drizzle-orm', key); - if (o1.startsWith('drizzle-orm/pglite') || o1.startsWith('drizzle-orm/expo-sqlite')) { + if ( + o1.startsWith('drizzle-orm/bun-sqlite') || o1.startsWith('drizzle-orm/pglite') + || o1.startsWith('drizzle-orm/expo-sqlite') + ) { continue; } fs.writeFileSync(`${IMPORTS_FOLDER}/imports_${i}.cjs`, 'requ'); @@ -43,7 +46,7 @@ it('dynamic imports check for ESM', async () => { const promises: ProcessPromise[] = []; for (const [i, key] of Object.keys(pj['exports']).entries()) { const o1 = path.join('drizzle-orm', key); - if (o1.startsWith('drizzle-orm/expo-sqlite')) { + if (o1.startsWith('drizzle-orm/bun-sqlite') || o1.startsWith('drizzle-orm/expo-sqlite')) { continue; } fs.writeFileSync(`${IMPORTS_FOLDER}/imports_${i}.mjs`, 'imp'); From b02cc93e880debee850059987b4d84d2fc9a5955 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 15 Oct 2024 17:57:59 +0300 Subject: [PATCH 248/492] Added missing connectionString param --- drizzle-orm/src/neon-http/driver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index 24c52e6e7..f79fd9de3 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -114,7 +114,7 @@ export function drizzle< ( & DrizzleConfig & ({ - connection: string | HTTPTransactionOptions; + connection: string | ({ connectionString: string } & HTTPTransactionOptions); } | { client: TClient; }) From 9a563af0f75a0ccfdc20e6d3b21c6c124dc96fb3 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Tue, 15 Oct 2024 20:12:47 +0300 Subject: [PATCH 249/492] Fixed broken connection, added missing cases --- drizzle-orm/src/mysql2/driver.ts | 13 ++++++++++--- drizzle-orm/src/neon-serverless/driver.ts | 12 +++--------- drizzle-orm/src/planetscale-serverless/driver.ts | 10 +++++++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index 0bf11684f..ef34604e3 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -1,5 +1,6 @@ import { EventEmitter } from 'events'; import { type Connection as CallbackConnection, createPool, type Pool as CallbackPool, type PoolOptions } from 'mysql2'; +import type { Connection, Pool } from 'mysql2/promise'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -53,7 +54,7 @@ export type MySql2DrizzleConfig = Record function construct< TSchema extends Record = Record, - TClient extends MySql2Client | CallbackConnection | CallbackPool = MySql2Client | CallbackConnection | CallbackPool, + TClient extends Pool | Connection | CallbackPool | CallbackConnection = CallbackPool, >( client: TClient, config: MySql2DrizzleConfig = {}, @@ -108,9 +109,11 @@ function isCallbackClient(client: any): client is CallbackClient { return typeof client.promise === 'function'; } +export type AnyMySql2Connection = Pool | Connection | CallbackPool | CallbackConnection; + export function drizzle< TSchema extends Record = Record, - TClient extends MySql2Client | CallbackPool | CallbackConnection = CallbackPool, + TClient extends AnyMySql2Connection = CallbackPool, >( ...params: IfNotImported< CallbackPool, @@ -146,7 +149,11 @@ export function drizzle< if (client) return construct(client, drizzleConfig) as any; - const instance = createPool(connection as PoolOptions); + const instance = typeof connection === 'string' + ? createPool({ + uri: connection, + }) + : createPool(connection!); const db = construct(instance, drizzleConfig); return db as any; diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index 0e23a317b..c0f962e96 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -113,14 +113,6 @@ export function drizzle< return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } - if (typeof params[0] === 'string') { - const instance = new Pool({ - connectionString: params[0], - }); - - construct(instance); - } - if (typeof params[0] === 'object') { const { connection, client, ws, ...drizzleConfig } = params[0] as { connection?: PoolConfig | string; @@ -143,7 +135,9 @@ export function drizzle< return construct(instance, drizzleConfig) as any; } - const instance = new Pool(); + const instance = new Pool({ + connectionString: params[0], + }); return construct(instance, params[1]) as any; } diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index 75da22ec9..1865673bf 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -113,6 +113,8 @@ export function drizzle< & DrizzleConfig & ({ connection: string | Config; + } | { + client: TClient; }) ), ] @@ -126,16 +128,18 @@ export function drizzle< } if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as - & { connection: Config | string } + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config | string; client?: TClient } & DrizzleConfig; + if (client) return construct(client, drizzleConfig) as any; + const instance = typeof connection === 'string' ? new Client({ url: connection, }) : new Client( - connection, + connection!, ); return construct(instance, drizzleConfig) as any; From 89e39c68cbd52801c16254dee17d523704408451 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 15 Oct 2024 21:51:21 +0300 Subject: [PATCH 250/492] Updated versions for orm and kit --- changelogs/drizzle-kit/0.26.0.md | 122 +++++++++++++++++++++++++++++++ changelogs/drizzle-orm/0.35.0.md | 85 +++++++++++++++++++++ drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- 4 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 changelogs/drizzle-kit/0.26.0.md create mode 100644 changelogs/drizzle-orm/0.35.0.md diff --git a/changelogs/drizzle-kit/0.26.0.md b/changelogs/drizzle-kit/0.26.0.md new file mode 100644 index 000000000..8e054812b --- /dev/null +++ b/changelogs/drizzle-kit/0.26.0.md @@ -0,0 +1,122 @@ +# New Features + +## Checks support in `drizzle-kit` + +You can use drizzle-kit to manage your `check` constraint defined in drizzle-orm schema definition + +For example current drizzle table: + +```ts +import { sql } from "drizzle-orm"; +import { check, pgTable } from "drizzle-orm/pg-core"; + +export const users = pgTable( + "users", + (c) => ({ + id: c.uuid().defaultRandom().primaryKey(), + username: c.text().notNull(), + age: c.integer(), + }), + (table) => ({ + checkConstraint: check("age_check", sql`${table.age} > 21`), + }) +); +``` + +will be generated into + +```sql +CREATE TABLE IF NOT EXISTS "users" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "username" text NOT NULL, + "age" integer, + CONSTRAINT "age_check" CHECK ("users"."age" > 21) +); +``` + +The same is supported in all dialects + +### Limitations + +- `generate` will work as expected for all check constraint changes. +- `push` will detect only check renames and will recreate the constraint. All other changes to SQL won't be detected and will be ignored. + +So, if you want to change the constraint's SQL definition using only `push`, you would need to manually comment out the constraint, `push`, then put it back with the new SQL definition and `push` one more time. + +## Views support in `drizzle-kit` + +You can use drizzle-kit to manage your `views` defined in drizzle-orm schema definition. It will work with all existing dialects and view options + +### PostgreSQL + +For example current drizzle table: + +```ts +import { sql } from "drizzle-orm"; +import { + check, + pgMaterializedView, + pgTable, + pgView, +} from "drizzle-orm/pg-core"; + +export const users = pgTable( + "users", + (c) => ({ + id: c.uuid().defaultRandom().primaryKey(), + username: c.text().notNull(), + age: c.integer(), + }), + (table) => ({ + checkConstraint: check("age_check", sql`${table.age} > 21`), + }) +); + +export const simpleView = pgView("simple_users_view").as((qb) => + qb.select().from(users) +); + +export const materializedView = pgMaterializedView( + "materialized_users_view" +).as((qb) => qb.select().from(users)); +``` + +will be generated into + +```sql +CREATE TABLE IF NOT EXISTS "users" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "username" text NOT NULL, + "age" integer, + CONSTRAINT "age_check" CHECK ("users"."age" > 21) +); + +CREATE VIEW "public"."simple_users_view" AS (select "id", "username", "age" from "users"); + +CREATE MATERIALIZED VIEW "public"."materialized_users_view" AS (select "id", "username", "age" from "users"); +``` + +Views supported in all dialects, but materialized views are supported only in PostgreSQL + +#### Limitations + +- `generate` will work as expected for all view changes +- `push` limitations: + +1. If you want to change the view's SQL definition using only `push`, you would need to manually comment out the view, `push`, then put it back with the new SQL definition and `push` one more time. + +## Updates for PostgreSQL enums behavior + +We've updated enum behavior in Drizzle with PostgreSQL: + +- Add value after or before in enum: With this change, Drizzle will now respect the order of values in the enum and allow adding new values after or before a specific one. + +- Support for dropping a value from an enum: In this case, Drizzle will attempt to alter all columns using the enum to text, then drop the existing enum and create a new one with the updated set of values. After that, all columns previously using the enum will be altered back to the new enum. + +> If the deleted enum value was used by a column, this process will result in a database error. + +- Support for dropping an enum + +- Support for moving enums between schemas + +- Support for renaming enums diff --git a/changelogs/drizzle-orm/0.35.0.md b/changelogs/drizzle-orm/0.35.0.md new file mode 100644 index 000000000..92bafdff1 --- /dev/null +++ b/changelogs/drizzle-orm/0.35.0.md @@ -0,0 +1,85 @@ +# Important change after 0.34.0 release + +## Updated the init Drizzle database API + +The API from version 0.34.0 turned out to be unusable and needs to be changed. You can read more about our decisions in [this discussion](https://github.com/drizzle-team/drizzle-orm/discussions/3097) + +If you still want to use the new API introduced in 0.34.0, which can create driver clients for you under the hood, you can now do so +```ts +import { drizzle } from "drizzle-orm/node-postgres"; + +const db = drizzle(process.env.DATABASE_URL); +// or +const db = drizzle({ + connection: process.env.DATABASE_URL +}); +const db = drizzle({ + connection: { + user: "...", + password: "...", + host: "...", + port: 4321, + db: "...", + }, +}); + +// if you need to pass logger or schema +const db = drizzle({ + connection: process.env.DATABASE_URL, + logger: true, + schema: schema, +}); +``` + +in order to not introduce breaking change - we will still leave support for deprecated API until V1 release. +It will degrade autocomplete performance in connection params due to `DatabaseDriver` | `ConnectionParams` types collision, +but that's a decent compromise against breaking changes + +```ts +import { drizzle } from "drizzle-orm/node-postgres"; +import { Pool } from "pg"; + +const client = new Pool({ connectionString: process.env.DATABASE_URL }); +const db = drizzle(client); // deprecated but available + +// new version +const db = drizzle({ + client: client, +}); +``` + +# New Features + +## New .orderBy() and .limit() functions in update and delete statements SQLite and MySQL + +You now have more options for the `update` and `delete` query builders in MySQL and SQLite + +**Example** + +```ts +await db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); + +await db.delete(usersTable).where(eq(usersTable.verified, false)).limit(1).orderBy(asc(usersTable.name)); +``` + +## New `drizzle.mock()` function + +There were cases where you didn't need to provide a driver to the Drizzle object, and this served as a workaround +```ts +const db = drizzle({} as any) +``` + +Now you can do this using a mock function +```ts +const db = drizzle.mock() +``` + +There is no valid production use case for this, but we used it in situations where we needed to check types, etc., without making actual database calls or dealing with driver creation. If anyone was using it, please switch to using mocks now + +# Internal updates + +- Upgraded TS in codebase to the version 5.6.3 + +# Bug fixes + +- [[BUG]: New $count API error with @neondatabase/serverless](https://github.com/drizzle-team/drizzle-orm/issues/3081) \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index cf771296a..ce2de1468 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.25.0", + "version": "0.26.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index cef1a7aef..bd3221754 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.34.1", + "version": "0.35.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { From 6f4fc4c552845a1b61179753e23e980e55d99d38 Mon Sep 17 00:00:00 2001 From: Andrii Sherman Date: Tue, 15 Oct 2024 21:57:54 +0300 Subject: [PATCH 251/492] Beta (#3129) * Check for Pg: -added check constraints to migrate, pull, push - added tests * added check constraints to mysql added some tests * - added sqlite, turso checks - added and updated tests * removed console.log merged beta to branch * rewrote introspect tests added introspect tests for checks * added progress callbacks for introspect with checks * updated tests for introspect * Implement limit and order by in MySQL * Add limit and order by to update and delete in SQLite * Format * Update SQLite test * Format * added postgresql generate handling for views * added support for views and materialized views in postgres (push + introspect + generate) * fixed build errors * added alter for using * added psql rename views and change schema handlings * added generate for mysql views * added introspect for mysql views * Added sqlite and libsql view handling * added all tests for all dialect views. updated introspect tests * Updated introspect tests * minor fixes * fixed numeric introspect in pg * fixed introspect numeric in pg * fixed introspect numeric pg * fixed sqlite + libsql alter existing handling * updated psql introspect + sqlite introspect for views * added progress callback to views. changed query columns for materialized views * updated pg introspect columns query. updated mysql test. * Updated enum handling for generate. Adde drop, add value, rename, set schema. Updated tests * made test for enum ordering for push * Added neon-serverless (websocket) tests, fixed neon-serverless session's lack of own count procedure (issue #3081) * fixed lockfile * Added leftover data deletion, imported table from common instead of re-creating locally * Fixed lack of custom schema cleanup on locally remade skipped tests of neon-serverless * squash add + drop enum values to drop only * Upgrade to TS 5.6.3 * removed commented code * Remove global set for node-postgres, neon and vercel; move to on per-query * Fix import * Fix test * Fix view tests * Check tests with docker * Update tests * Skip sqljs * Add ignore on neon * removed console logs in tests * Updated drizzle constructors, removed monodriver * Fixed type error * Fixed sqlite instance checks * Fixed mysql rename view sql statement * Fixed tests, added MockDriver & mock support for reworked drivers * Added `drizzle.mock()`, reworked replicas tests * Fixed neon client identification * Removed `bun-sqlite` from import tests * Added missing connectionString param * Fixed broken connection, added missing cases * Updated versions for orm and kit --------- Co-authored-by: Aleksandr Sherman Co-authored-by: Mario564 Co-authored-by: Sukairo-02 Co-authored-by: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> --- changelogs/drizzle-kit/0.26.0.md | 122 ++ changelogs/drizzle-orm/0.35.0.md | 85 + drizzle-kit/package.json | 2 +- drizzle-kit/src/@types/utils.ts | 6 + drizzle-kit/src/api.ts | 16 +- drizzle-kit/src/cli/commands/introspect.ts | 16 +- .../src/cli/commands/libSqlPushUtils.ts | 9 + drizzle-kit/src/cli/commands/migrate.ts | 82 +- drizzle-kit/src/cli/commands/pgPushUtils.ts | 151 +- drizzle-kit/src/cli/commands/push.ts | 7 + .../src/cli/commands/sqlitePushUtils.ts | 9 + drizzle-kit/src/cli/views.ts | 19 +- drizzle-kit/src/introspect-mysql.ts | 87 + drizzle-kit/src/introspect-pg.ts | 345 ++- drizzle-kit/src/introspect-sqlite.ts | 70 +- drizzle-kit/src/jsonDiffer.js | 130 ++ drizzle-kit/src/jsonStatements.ts | 382 +++- drizzle-kit/src/serializer/index.ts | 12 +- drizzle-kit/src/serializer/mysqlImports.ts | 13 +- drizzle-kit/src/serializer/mysqlSchema.ts | 77 +- drizzle-kit/src/serializer/mysqlSerializer.ts | 238 +- drizzle-kit/src/serializer/pgImports.ts | 40 +- drizzle-kit/src/serializer/pgSchema.ts | 76 + drizzle-kit/src/serializer/pgSerializer.ts | 1411 +++++++----- drizzle-kit/src/serializer/sqliteImports.ts | 14 +- drizzle-kit/src/serializer/sqliteSchema.ts | 42 +- .../src/serializer/sqliteSerializer.ts | 230 +- drizzle-kit/src/snapshotsDiffer.ts | 777 ++++++- drizzle-kit/src/sqlgenerator.ts | 522 ++++- drizzle-kit/src/statementCombiner.ts | 30 +- drizzle-kit/tests/introspect/libsql.test.ts | 35 + drizzle-kit/tests/introspect/mysql.test.ts | 77 +- drizzle-kit/tests/introspect/pg.test.ts | 222 ++ drizzle-kit/tests/introspect/sqlite.test.ts | 48 +- drizzle-kit/tests/libsql-checks.test.ts | 308 +++ drizzle-kit/tests/libsql-statements.test.ts | 7 + drizzle-kit/tests/libsql-views.test.ts | 218 ++ drizzle-kit/tests/mysql-checks.test.ts | 291 +++ drizzle-kit/tests/mysql-schemas.test.ts | 1 + drizzle-kit/tests/mysql-views.test.ts | 553 +++++ drizzle-kit/tests/mysql.test.ts | 8 + drizzle-kit/tests/pg-checks.test.ts | 280 +++ drizzle-kit/tests/pg-enums.test.ts | 256 ++- drizzle-kit/tests/pg-identity.test.ts | 3 + drizzle-kit/tests/pg-tables.test.ts | 10 + drizzle-kit/tests/pg-views.test.ts | 1911 +++++++++++++++++ drizzle-kit/tests/push/libsql.test.ts | 350 +++ drizzle-kit/tests/push/mysql-push.test.ts | 345 +++ drizzle-kit/tests/push/pg.test.ts | 1166 ++++++---- drizzle-kit/tests/push/sqlite.test.ts | 264 ++- drizzle-kit/tests/schemaDiffer.ts | 1091 ++++++---- drizzle-kit/tests/sqlite-checks.test.ts | 308 +++ drizzle-kit/tests/sqlite-columns.test.ts | 12 + drizzle-kit/tests/sqlite-generated.test.ts | 6 + drizzle-kit/tests/sqlite-tables.test.ts | 9 + drizzle-kit/tests/sqlite-views.test.ts | 218 ++ .../libsql-statements-combiner.test.ts | 63 + .../sqlite-statements-combiner.test.ts | 41 + drizzle-orm/package.json | 4 +- drizzle-orm/src/aws-data-api/pg/driver.ts | 71 +- drizzle-orm/src/aws-data-api/pg/session.ts | 6 +- drizzle-orm/src/better-sqlite3/driver.ts | 88 +- drizzle-orm/src/better-sqlite3/session.ts | 6 +- drizzle-orm/src/bun-sqlite/driver.ts | 110 +- drizzle-orm/src/bun-sqlite/session.ts | 6 +- drizzle-orm/src/connect.ts | 2 - drizzle-orm/src/d1/driver.ts | 2 +- drizzle-orm/src/d1/session.ts | 6 +- drizzle-orm/src/entity.ts | 2 +- drizzle-orm/src/errors.ts | 2 +- drizzle-orm/src/expo-sqlite/driver.ts | 2 +- drizzle-orm/src/expo-sqlite/session.ts | 6 +- drizzle-orm/src/libsql/driver.ts | 71 +- drizzle-orm/src/libsql/session.ts | 6 +- drizzle-orm/src/monodriver.ts | 659 ------ drizzle-orm/src/monomigrator.ts | 109 - drizzle-orm/src/mysql-core/columns/bigint.ts | 8 +- drizzle-orm/src/mysql-core/columns/binary.ts | 4 +- drizzle-orm/src/mysql-core/columns/boolean.ts | 4 +- drizzle-orm/src/mysql-core/columns/char.ts | 4 +- drizzle-orm/src/mysql-core/columns/common.ts | 8 +- drizzle-orm/src/mysql-core/columns/custom.ts | 4 +- .../src/mysql-core/columns/date.common.ts | 4 +- drizzle-orm/src/mysql-core/columns/date.ts | 8 +- .../src/mysql-core/columns/datetime.ts | 8 +- drizzle-orm/src/mysql-core/columns/decimal.ts | 4 +- drizzle-orm/src/mysql-core/columns/double.ts | 4 +- drizzle-orm/src/mysql-core/columns/enum.ts | 4 +- drizzle-orm/src/mysql-core/columns/float.ts | 4 +- drizzle-orm/src/mysql-core/columns/int.ts | 4 +- drizzle-orm/src/mysql-core/columns/json.ts | 4 +- .../src/mysql-core/columns/mediumint.ts | 4 +- drizzle-orm/src/mysql-core/columns/real.ts | 4 +- drizzle-orm/src/mysql-core/columns/serial.ts | 4 +- .../src/mysql-core/columns/smallint.ts | 4 +- drizzle-orm/src/mysql-core/columns/text.ts | 4 +- drizzle-orm/src/mysql-core/columns/time.ts | 4 +- .../src/mysql-core/columns/timestamp.ts | 8 +- drizzle-orm/src/mysql-core/columns/tinyint.ts | 4 +- .../src/mysql-core/columns/varbinary.ts | 4 +- drizzle-orm/src/mysql-core/columns/varchar.ts | 4 +- drizzle-orm/src/mysql-core/columns/year.ts | 4 +- drizzle-orm/src/mysql-core/dialect.ts | 42 +- .../src/mysql-core/query-builders/count.ts | 2 +- .../src/mysql-core/query-builders/delete.ts | 41 +- .../src/mysql-core/query-builders/insert.ts | 2 +- .../src/mysql-core/query-builders/query.ts | 2 +- .../src/mysql-core/query-builders/select.ts | 4 +- .../src/mysql-core/query-builders/update.ts | 42 +- drizzle-orm/src/mysql-core/session.ts | 2 +- drizzle-orm/src/mysql-core/table.ts | 2 +- drizzle-orm/src/mysql-core/view-base.ts | 2 +- drizzle-orm/src/mysql-core/view.ts | 14 +- drizzle-orm/src/mysql-proxy/driver.ts | 2 +- drizzle-orm/src/mysql-proxy/session.ts | 6 +- drizzle-orm/src/mysql2/driver.ts | 80 +- drizzle-orm/src/mysql2/session.ts | 6 +- drizzle-orm/src/neon-http/driver.ts | 82 +- drizzle-orm/src/neon-http/session.ts | 6 +- drizzle-orm/src/neon-serverless/driver.ts | 89 +- drizzle-orm/src/neon-serverless/session.ts | 55 +- drizzle-orm/src/node-postgres/driver.ts | 86 +- drizzle-orm/src/node-postgres/session.ts | 46 +- drizzle-orm/src/op-sqlite/driver.ts | 2 +- drizzle-orm/src/op-sqlite/session.ts | 6 +- drizzle-orm/src/pg-core/columns/bigint.ts | 8 +- drizzle-orm/src/pg-core/columns/bigserial.ts | 8 +- drizzle-orm/src/pg-core/columns/boolean.ts | 4 +- drizzle-orm/src/pg-core/columns/char.ts | 4 +- drizzle-orm/src/pg-core/columns/cidr.ts | 4 +- drizzle-orm/src/pg-core/columns/common.ts | 8 +- drizzle-orm/src/pg-core/columns/custom.ts | 4 +- .../src/pg-core/columns/date.common.ts | 2 +- drizzle-orm/src/pg-core/columns/date.ts | 8 +- .../src/pg-core/columns/double-precision.ts | 4 +- drizzle-orm/src/pg-core/columns/enum.ts | 4 +- drizzle-orm/src/pg-core/columns/inet.ts | 4 +- drizzle-orm/src/pg-core/columns/int.common.ts | 2 +- drizzle-orm/src/pg-core/columns/integer.ts | 4 +- drizzle-orm/src/pg-core/columns/interval.ts | 4 +- drizzle-orm/src/pg-core/columns/json.ts | 4 +- drizzle-orm/src/pg-core/columns/jsonb.ts | 4 +- drizzle-orm/src/pg-core/columns/line.ts | 8 +- drizzle-orm/src/pg-core/columns/macaddr.ts | 4 +- drizzle-orm/src/pg-core/columns/macaddr8.ts | 4 +- drizzle-orm/src/pg-core/columns/numeric.ts | 4 +- drizzle-orm/src/pg-core/columns/point.ts | 8 +- .../columns/postgis_extension/geometry.ts | 8 +- drizzle-orm/src/pg-core/columns/real.ts | 4 +- drizzle-orm/src/pg-core/columns/serial.ts | 4 +- drizzle-orm/src/pg-core/columns/smallint.ts | 4 +- .../src/pg-core/columns/smallserial.ts | 4 +- drizzle-orm/src/pg-core/columns/text.ts | 4 +- drizzle-orm/src/pg-core/columns/time.ts | 4 +- drizzle-orm/src/pg-core/columns/timestamp.ts | 8 +- drizzle-orm/src/pg-core/columns/uuid.ts | 4 +- drizzle-orm/src/pg-core/columns/varchar.ts | 4 +- .../pg-core/columns/vector_extension/bit.ts | 4 +- .../columns/vector_extension/halfvec.ts | 4 +- .../columns/vector_extension/sparsevec.ts | 4 +- .../columns/vector_extension/vector.ts | 4 +- .../src/pg-core/query-builders/count.ts | 2 +- .../src/pg-core/query-builders/delete.ts | 2 +- .../src/pg-core/query-builders/insert.ts | 2 +- .../src/pg-core/query-builders/query.ts | 2 +- drizzle-orm/src/pg-core/query-builders/raw.ts | 2 +- .../refresh-materialized-view.ts | 2 +- .../src/pg-core/query-builders/select.ts | 4 +- .../src/pg-core/query-builders/update.ts | 2 +- drizzle-orm/src/pg-core/session.ts | 2 +- drizzle-orm/src/pg-core/table.ts | 2 +- drizzle-orm/src/pg-core/view-base.ts | 2 +- drizzle-orm/src/pg-core/view.ts | 64 +- drizzle-orm/src/pg-proxy/driver.ts | 2 +- drizzle-orm/src/pg-proxy/session.ts | 6 +- drizzle-orm/src/pglite/driver.ts | 76 +- drizzle-orm/src/pglite/session.ts | 6 +- .../src/planetscale-serverless/driver.ts | 74 +- .../src/planetscale-serverless/session.ts | 6 +- drizzle-orm/src/postgres-js/driver.ts | 72 +- drizzle-orm/src/postgres-js/session.ts | 6 +- drizzle-orm/src/prisma/mysql/driver.ts | 2 +- drizzle-orm/src/prisma/mysql/session.ts | 4 +- drizzle-orm/src/prisma/pg/driver.ts | 2 +- drizzle-orm/src/prisma/pg/session.ts | 4 +- drizzle-orm/src/prisma/sqlite/session.ts | 4 +- drizzle-orm/src/relations.ts | 4 +- drizzle-orm/src/sql-js/session.ts | 6 +- drizzle-orm/src/sqlite-core/columns/blob.ts | 12 +- drizzle-orm/src/sqlite-core/columns/common.ts | 4 +- drizzle-orm/src/sqlite-core/columns/custom.ts | 4 +- .../src/sqlite-core/columns/integer.ts | 16 +- .../src/sqlite-core/columns/numeric.ts | 4 +- drizzle-orm/src/sqlite-core/columns/real.ts | 4 +- drizzle-orm/src/sqlite-core/columns/text.ts | 8 +- drizzle-orm/src/sqlite-core/dialect.ts | 61 +- .../src/sqlite-core/query-builders/count.ts | 2 +- .../src/sqlite-core/query-builders/delete.ts | 41 +- .../src/sqlite-core/query-builders/insert.ts | 2 +- .../src/sqlite-core/query-builders/query.ts | 4 +- .../src/sqlite-core/query-builders/raw.ts | 2 +- .../src/sqlite-core/query-builders/select.ts | 4 +- .../src/sqlite-core/query-builders/update.ts | 47 +- drizzle-orm/src/sqlite-core/session.ts | 4 +- drizzle-orm/src/sqlite-core/table.ts | 2 +- drizzle-orm/src/sqlite-core/utils.ts | 3 +- drizzle-orm/src/sqlite-core/view-base.ts | 2 +- drizzle-orm/src/sqlite-core/view.ts | 18 +- drizzle-orm/src/sqlite-proxy/driver.ts | 2 +- drizzle-orm/src/sqlite-proxy/session.ts | 6 +- drizzle-orm/src/subquery.ts | 2 +- drizzle-orm/src/tidb-serverless/driver.ts | 70 +- drizzle-orm/src/tidb-serverless/session.ts | 6 +- drizzle-orm/src/utils.ts | 8 + drizzle-orm/src/vercel-postgres/driver.ts | 67 +- drizzle-orm/src/vercel-postgres/session.ts | 45 +- drizzle-orm/src/xata-http/driver.ts | 2 +- drizzle-orm/src/xata-http/session.ts | 6 +- drizzle-orm/type-tests/mysql/delete.ts | 4 + drizzle-orm/type-tests/mysql/tables.ts | 4 - drizzle-orm/type-tests/mysql/update.ts | 4 + drizzle-orm/type-tests/pg/tables.ts | 16 +- drizzle-orm/type-tests/sqlite/delete.ts | 4 + drizzle-orm/type-tests/sqlite/update.ts | 4 + integration-tests/package.json | 9 +- integration-tests/tests/bun/sqlite-nw.test.ts | 1 + integration-tests/tests/bun/sqlite.test.ts | 1 + integration-tests/tests/common.ts | 2 +- integration-tests/tests/imports/index.test.ts | 7 +- integration-tests/tests/mysql/mysql-common.ts | 131 +- .../tests/pg/neon-serverless.test.ts | 582 +++++ integration-tests/tests/pg/pg-common.ts | 4 +- .../tests/replicas/mysql.test.ts | 160 +- .../tests/replicas/postgres.test.ts | 160 +- .../tests/replicas/sqlite.test.ts | 160 +- .../tests/sqlite/d1-batch.test.ts | 1 + integration-tests/tests/sqlite/libsql.test.ts | 6 + integration-tests/tests/sqlite/sql-js.test.ts | 2 + .../tests/sqlite/sqlite-common.ts | 42 + integration-tests/vitest.config.ts | 4 +- package.json | 7 +- ...ipt@5.4.5.patch => typescript@5.6.3.patch} | 0 pnpm-lock.yaml | 640 ++++-- 243 files changed, 14561 insertions(+), 3410 deletions(-) create mode 100644 changelogs/drizzle-kit/0.26.0.md create mode 100644 changelogs/drizzle-orm/0.35.0.md create mode 100644 drizzle-kit/tests/introspect/libsql.test.ts create mode 100644 drizzle-kit/tests/libsql-checks.test.ts create mode 100644 drizzle-kit/tests/libsql-views.test.ts create mode 100644 drizzle-kit/tests/mysql-checks.test.ts create mode 100644 drizzle-kit/tests/mysql-views.test.ts create mode 100644 drizzle-kit/tests/pg-checks.test.ts create mode 100644 drizzle-kit/tests/pg-views.test.ts create mode 100644 drizzle-kit/tests/push/mysql-push.test.ts create mode 100644 drizzle-kit/tests/sqlite-checks.test.ts create mode 100644 drizzle-kit/tests/sqlite-views.test.ts delete mode 100644 drizzle-orm/src/connect.ts delete mode 100644 drizzle-orm/src/monodriver.ts delete mode 100644 drizzle-orm/src/monomigrator.ts create mode 100644 integration-tests/tests/pg/neon-serverless.test.ts rename patches/{typescript@5.4.5.patch => typescript@5.6.3.patch} (100%) diff --git a/changelogs/drizzle-kit/0.26.0.md b/changelogs/drizzle-kit/0.26.0.md new file mode 100644 index 000000000..8e054812b --- /dev/null +++ b/changelogs/drizzle-kit/0.26.0.md @@ -0,0 +1,122 @@ +# New Features + +## Checks support in `drizzle-kit` + +You can use drizzle-kit to manage your `check` constraint defined in drizzle-orm schema definition + +For example current drizzle table: + +```ts +import { sql } from "drizzle-orm"; +import { check, pgTable } from "drizzle-orm/pg-core"; + +export const users = pgTable( + "users", + (c) => ({ + id: c.uuid().defaultRandom().primaryKey(), + username: c.text().notNull(), + age: c.integer(), + }), + (table) => ({ + checkConstraint: check("age_check", sql`${table.age} > 21`), + }) +); +``` + +will be generated into + +```sql +CREATE TABLE IF NOT EXISTS "users" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "username" text NOT NULL, + "age" integer, + CONSTRAINT "age_check" CHECK ("users"."age" > 21) +); +``` + +The same is supported in all dialects + +### Limitations + +- `generate` will work as expected for all check constraint changes. +- `push` will detect only check renames and will recreate the constraint. All other changes to SQL won't be detected and will be ignored. + +So, if you want to change the constraint's SQL definition using only `push`, you would need to manually comment out the constraint, `push`, then put it back with the new SQL definition and `push` one more time. + +## Views support in `drizzle-kit` + +You can use drizzle-kit to manage your `views` defined in drizzle-orm schema definition. It will work with all existing dialects and view options + +### PostgreSQL + +For example current drizzle table: + +```ts +import { sql } from "drizzle-orm"; +import { + check, + pgMaterializedView, + pgTable, + pgView, +} from "drizzle-orm/pg-core"; + +export const users = pgTable( + "users", + (c) => ({ + id: c.uuid().defaultRandom().primaryKey(), + username: c.text().notNull(), + age: c.integer(), + }), + (table) => ({ + checkConstraint: check("age_check", sql`${table.age} > 21`), + }) +); + +export const simpleView = pgView("simple_users_view").as((qb) => + qb.select().from(users) +); + +export const materializedView = pgMaterializedView( + "materialized_users_view" +).as((qb) => qb.select().from(users)); +``` + +will be generated into + +```sql +CREATE TABLE IF NOT EXISTS "users" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "username" text NOT NULL, + "age" integer, + CONSTRAINT "age_check" CHECK ("users"."age" > 21) +); + +CREATE VIEW "public"."simple_users_view" AS (select "id", "username", "age" from "users"); + +CREATE MATERIALIZED VIEW "public"."materialized_users_view" AS (select "id", "username", "age" from "users"); +``` + +Views supported in all dialects, but materialized views are supported only in PostgreSQL + +#### Limitations + +- `generate` will work as expected for all view changes +- `push` limitations: + +1. If you want to change the view's SQL definition using only `push`, you would need to manually comment out the view, `push`, then put it back with the new SQL definition and `push` one more time. + +## Updates for PostgreSQL enums behavior + +We've updated enum behavior in Drizzle with PostgreSQL: + +- Add value after or before in enum: With this change, Drizzle will now respect the order of values in the enum and allow adding new values after or before a specific one. + +- Support for dropping a value from an enum: In this case, Drizzle will attempt to alter all columns using the enum to text, then drop the existing enum and create a new one with the updated set of values. After that, all columns previously using the enum will be altered back to the new enum. + +> If the deleted enum value was used by a column, this process will result in a database error. + +- Support for dropping an enum + +- Support for moving enums between schemas + +- Support for renaming enums diff --git a/changelogs/drizzle-orm/0.35.0.md b/changelogs/drizzle-orm/0.35.0.md new file mode 100644 index 000000000..92bafdff1 --- /dev/null +++ b/changelogs/drizzle-orm/0.35.0.md @@ -0,0 +1,85 @@ +# Important change after 0.34.0 release + +## Updated the init Drizzle database API + +The API from version 0.34.0 turned out to be unusable and needs to be changed. You can read more about our decisions in [this discussion](https://github.com/drizzle-team/drizzle-orm/discussions/3097) + +If you still want to use the new API introduced in 0.34.0, which can create driver clients for you under the hood, you can now do so +```ts +import { drizzle } from "drizzle-orm/node-postgres"; + +const db = drizzle(process.env.DATABASE_URL); +// or +const db = drizzle({ + connection: process.env.DATABASE_URL +}); +const db = drizzle({ + connection: { + user: "...", + password: "...", + host: "...", + port: 4321, + db: "...", + }, +}); + +// if you need to pass logger or schema +const db = drizzle({ + connection: process.env.DATABASE_URL, + logger: true, + schema: schema, +}); +``` + +in order to not introduce breaking change - we will still leave support for deprecated API until V1 release. +It will degrade autocomplete performance in connection params due to `DatabaseDriver` | `ConnectionParams` types collision, +but that's a decent compromise against breaking changes + +```ts +import { drizzle } from "drizzle-orm/node-postgres"; +import { Pool } from "pg"; + +const client = new Pool({ connectionString: process.env.DATABASE_URL }); +const db = drizzle(client); // deprecated but available + +// new version +const db = drizzle({ + client: client, +}); +``` + +# New Features + +## New .orderBy() and .limit() functions in update and delete statements SQLite and MySQL + +You now have more options for the `update` and `delete` query builders in MySQL and SQLite + +**Example** + +```ts +await db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); + +await db.delete(usersTable).where(eq(usersTable.verified, false)).limit(1).orderBy(asc(usersTable.name)); +``` + +## New `drizzle.mock()` function + +There were cases where you didn't need to provide a driver to the Drizzle object, and this served as a workaround +```ts +const db = drizzle({} as any) +``` + +Now you can do this using a mock function +```ts +const db = drizzle.mock() +``` + +There is no valid production use case for this, but we used it in situations where we needed to check types, etc., without making actual database calls or dealing with driver creation. If anyone was using it, please switch to using mocks now + +# Internal updates + +- Upgraded TS in codebase to the version 5.6.3 + +# Bug fixes + +- [[BUG]: New $count API error with @neondatabase/serverless](https://github.com/drizzle-team/drizzle-orm/issues/3081) \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index cf771296a..ce2de1468 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.25.0", + "version": "0.26.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-kit/src/@types/utils.ts b/drizzle-kit/src/@types/utils.ts index 3f14151a4..04e7e125f 100644 --- a/drizzle-kit/src/@types/utils.ts +++ b/drizzle-kit/src/@types/utils.ts @@ -4,6 +4,8 @@ declare global { squashSpaces(): string; capitalise(): string; camelCase(): string; + snake_case(): string; + concatIf(it: string, condition: boolean): string; } @@ -44,6 +46,10 @@ String.prototype.concatIf = function(it: string, condition: boolean) { return condition ? `${this}${it}` : String(this); }; +String.prototype.snake_case = function() { + return this && this.length > 0 ? `${this.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)}` : String(this); +}; + Array.prototype.random = function() { return this[~~(Math.random() * this.length)]; }; diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 51e5dfcfc..a5b8bfe69 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -1,14 +1,16 @@ import { randomUUID } from 'crypto'; -import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; import { LibSQLDatabase } from 'drizzle-orm/libsql'; import type { MySql2Database } from 'drizzle-orm/mysql2'; import { PgDatabase } from 'drizzle-orm/pg-core'; import { columnsResolver, enumsResolver, + mySqlViewsResolver, schemasResolver, sequencesResolver, + sqliteViewsResolver, tablesResolver, + viewsResolver, } from './cli/commands/migrate'; import { pgPushIntrospect } from './cli/commands/pgIntrospect'; import { pgSuggestions } from './cli/commands/pgPushUtils'; @@ -45,6 +47,8 @@ export const generateDrizzleJson = ( prepared.enums, prepared.schemas, prepared.sequences, + prepared.views, + prepared.matViews, casing, schemaFilters, ); @@ -76,6 +80,7 @@ export const generateMigration = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, ); @@ -119,6 +124,7 @@ export const pushSchema = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, 'push', @@ -151,7 +157,7 @@ export const generateSQLiteDrizzleJson = async ( const id = randomUUID(); - const snapshot = generateSqliteSnapshot(prepared.tables, casing); + const snapshot = generateSqliteSnapshot(prepared.tables, prepared.views, casing); return { ...snapshot, @@ -177,6 +183,7 @@ export const generateSQLiteMigration = async ( squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, ); @@ -217,6 +224,7 @@ export const pushSQLiteSchema = async ( squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, 'push', @@ -255,7 +263,7 @@ export const generateMySQLDrizzleJson = async ( const id = randomUUID(); - const snapshot = generateMySqlSnapshot(prepared.tables, casing); + const snapshot = generateMySqlSnapshot(prepared.tables, prepared.views, casing); return { ...snapshot, @@ -281,6 +289,7 @@ export const generateMySQLMigration = async ( squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, ); @@ -322,6 +331,7 @@ export const pushMySQLSchema = async ( squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, 'push', diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index acd569dea..257150dc0 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -14,7 +14,12 @@ import { dryPg, type PgSchema, squashPgScheme } from '../../serializer/pgSchema' import { fromDatabase as fromPostgresDatabase } from '../../serializer/pgSerializer'; import { drySQLite, type SQLiteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase } from '../../serializer/sqliteSerializer'; -import { applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, applySqliteSnapshotsDiff } from '../../snapshotsDiffer'; +import { + applyLibSQLSnapshotsDiff, + applyMysqlSnapshotsDiff, + applyPgSnapshotsDiff, + applySqliteSnapshotsDiff, +} from '../../snapshotsDiffer'; import { prepareOutFolder } from '../../utils'; import type { Casing, Prefix } from '../validations/common'; import { LibSQLCredentials } from '../validations/libsql'; @@ -25,9 +30,12 @@ import { IntrospectProgress } from '../views'; import { columnsResolver, enumsResolver, + mySqlViewsResolver, schemasResolver, sequencesResolver, + sqliteViewsResolver, tablesResolver, + viewsResolver, writeResult, } from './migrate'; @@ -100,6 +108,7 @@ export const introspectPostgres = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, dryPg, schema, ); @@ -210,6 +219,7 @@ export const introspectMysql = async ( squashMysqlScheme(schema), tablesResolver, columnsResolver, + mySqlViewsResolver, dryMySql, schema, ); @@ -321,6 +331,7 @@ export const introspectSqlite = async ( squashSqliteScheme(schema), tablesResolver, columnsResolver, + sqliteViewsResolver, drySQLite, schema, ); @@ -427,11 +438,12 @@ export const introspectLibSQL = async ( const { snapshots, journal } = prepareOutFolder(out, 'sqlite'); if (snapshots.length === 0) { - const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( + const { sqlStatements, _meta } = await applyLibSQLSnapshotsDiff( squashSqliteScheme(drySQLite), squashSqliteScheme(schema), tablesResolver, columnsResolver, + sqliteViewsResolver, drySQLite, schema, ); diff --git a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts index 01bb61334..31e90c872 100644 --- a/drizzle-kit/src/cli/commands/libSqlPushUtils.ts +++ b/drizzle-kit/src/cli/commands/libSqlPushUtils.ts @@ -40,9 +40,17 @@ export const _moveDataStatements = ( const compositePKs = Object.values( json.tables[tableName].compositePrimaryKeys, ).map((it) => SQLiteSquasher.unsquashPK(it)); + const checkConstraints = Object.values(json.tables[tableName].checkConstraints); const fks = referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)); + const mappedCheckConstraints: string[] = checkConstraints.map((it) => + it.replaceAll(`"${tableName}".`, `"${newTableName}".`) + .replaceAll(`\`${tableName}\`.`, `\`${newTableName}\`.`) + .replaceAll(`${tableName}.`, `${newTableName}.`) + .replaceAll(`'${tableName}'.`, `\`${newTableName}\`.`) + ); + // create new table statements.push( new SQLiteCreateTableConvertor().convert({ @@ -51,6 +59,7 @@ export const _moveDataStatements = ( columns: tableColumns, referenceData: fks, compositePKs, + checkConstraints: mappedCheckConstraints, }), ); diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index b24fa77bc..c4f1e65d1 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -13,9 +13,9 @@ import { render } from 'hanji'; import path, { join } from 'path'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; -import { MySqlSchema, mysqlSchema, squashMysqlScheme } from '../../serializer/mysqlSchema'; -import { PgSchema, pgSchema, squashPgScheme } from '../../serializer/pgSchema'; -import { SQLiteSchema, sqliteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; +import { MySqlSchema, mysqlSchema, squashMysqlScheme, ViewSquashed } from '../../serializer/mysqlSchema'; +import { PgSchema, pgSchema, squashPgScheme, View } from '../../serializer/pgSchema'; +import { SQLiteSchema, sqliteSchema, squashSqliteScheme, View as SQLiteView } from '../../serializer/sqliteSchema'; import { applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, @@ -92,6 +92,72 @@ export const tablesResolver = async ( } }; +export const viewsResolver = async ( + input: ResolverInput, +): Promise> => { + try { + const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict( + input.created, + input.deleted, + 'view', + ); + + return { + created: created, + deleted: deleted, + moved: moved, + renamed: renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const mySqlViewsResolver = async ( + input: ResolverInput, +): Promise> => { + try { + const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict( + input.created, + input.deleted, + 'view', + ); + + return { + created: created, + deleted: deleted, + moved: moved, + renamed: renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const sqliteViewsResolver = async ( + input: ResolverInput, +): Promise> => { + try { + const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict( + input.created, + input.deleted, + 'view', + ); + + return { + created: created, + deleted: deleted, + moved: moved, + renamed: renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; + export const sequencesResolver = async ( input: ResolverInput, ): Promise> => { @@ -200,6 +266,7 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => { sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, ); @@ -245,6 +312,7 @@ export const preparePgPush = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, 'push', @@ -328,6 +396,7 @@ export const prepareMySQLPush = async ( squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, 'push', @@ -381,6 +450,7 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, ); @@ -441,6 +511,7 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, ); @@ -502,6 +573,7 @@ export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => { squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, ); @@ -540,6 +612,7 @@ export const prepareSQLitePush = async ( squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, 'push', @@ -572,6 +645,7 @@ export const prepareLibSQLPush = async ( squashedCur, tablesResolver, columnsResolver, + sqliteViewsResolver, validatedPrev, validatedCur, 'push', @@ -665,7 +739,7 @@ export const promptColumnsConflicts = async ( export const promptNamedWithSchemasConflict = async ( newItems: T[], missingItems: T[], - entity: 'table' | 'enum' | 'sequence', + entity: 'table' | 'enum' | 'sequence' | 'view', ): Promise<{ created: T[]; renamed: { from: T; to: T }[]; diff --git a/drizzle-kit/src/cli/commands/pgPushUtils.ts b/drizzle-kit/src/cli/commands/pgPushUtils.ts index eee0dc954..a8e2570df 100644 --- a/drizzle-kit/src/cli/commands/pgPushUtils.ts +++ b/drizzle-kit/src/cli/commands/pgPushUtils.ts @@ -47,15 +47,9 @@ function tableNameWithSchemaFrom( renamedSchemas: Record, renamedTables: Record, ) { - const newSchemaName = schema - ? renamedSchemas[schema] - ? renamedSchemas[schema] - : schema - : undefined; + const newSchemaName = schema ? (renamedSchemas[schema] ? renamedSchemas[schema] : schema) : undefined; - const newTableName = renamedTables[ - concatSchemaAndTableName(newSchemaName, tableName) - ] + const newTableName = renamedTables[concatSchemaAndTableName(newSchemaName, tableName)] ? renamedTables[concatSchemaAndTableName(newSchemaName, tableName)] : tableName; @@ -71,6 +65,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { const columnsToRemove: string[] = []; const schemasToRemove: string[] = []; const tablesToTruncate: string[] = []; + const matViewsToRemove: string[] = []; let renamedSchemas: Record = {}; let renamedTables: Record = {}; @@ -79,53 +74,44 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { if (statement.type === 'rename_schema') { renamedSchemas[statement.to] = statement.from; } else if (statement.type === 'rename_table') { - renamedTables[ - concatSchemaAndTableName(statement.toSchema, statement.tableNameTo) - ] = statement.tableNameFrom; + renamedTables[concatSchemaAndTableName(statement.toSchema, statement.tableNameTo)] = statement.tableNameFrom; } else if (statement.type === 'drop_table') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); if (count > 0) { - infoToPrint.push( - `· You're about to delete ${ - chalk.underline( - statement.tableName, - ) - } table with ${count} items`, - ); + infoToPrint.push(`· You're about to delete ${chalk.underline(statement.tableName)} table with ${count} items`); // statementsToExecute.push( // `truncate table ${tableNameWithSchemaFrom(statement)} cascade;` // ); tablesToRemove.push(statement.tableName); shouldAskForApprove = true; } + } else if (statement.type === 'drop_view' && statement.materialized) { + const res = await db.query(`select count(*) as count from "${statement.schema ?? 'public'}"."${statement.name}"`); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete "${chalk.underline(statement.name)}" materialized view with ${count} items`, + ); + + matViewsToRemove.push(statement.name); + shouldAskForApprove = true; + } } else if (statement.type === 'alter_table_drop_column') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); if (count > 0) { infoToPrint.push( `· You're about to delete ${ - chalk.underline( - statement.columnName, - ) + chalk.underline(statement.columnName) } column in ${statement.tableName} table with ${count} items`, ); columnsToRemove.push(`${statement.tableName}_${statement.columnName}`); @@ -137,48 +123,30 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { ); const count = Number(res[0].count); if (count > 0) { - infoToPrint.push( - `· You're about to delete ${ - chalk.underline( - statement.name, - ) - } schema with ${count} tables`, - ); + infoToPrint.push(`· You're about to delete ${chalk.underline(statement.name)} schema with ${count} tables`); schemasToRemove.push(statement.name); shouldAskForApprove = true; } } else if (statement.type === 'alter_table_alter_column_set_type') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); if (count > 0) { infoToPrint.push( - `· You're about to change ${ - chalk.underline( - statement.columnName, - ) - } column type from ${ + `· You're about to change ${chalk.underline(statement.columnName)} column type from ${ + chalk.underline(statement.oldDataType) + } to ${ chalk.underline( - statement.oldDataType, + statement.newDataType, ) - } to ${chalk.underline(statement.newDataType)} with ${count} items`, + } with ${count} items`, ); statementsToExecute.push( `truncate table ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) } cascade;`, ); tablesToTruncate.push(statement.tableName); @@ -187,21 +155,14 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { } else if (statement.type === 'alter_table_alter_column_drop_pk') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); if (count > 0) { infoToPrint.push( `· You're about to change ${ - chalk.underline( - statement.tableName, - ) + chalk.underline(statement.tableName) } primary key. This statements may fail and you table may left without primary key`, ); @@ -219,9 +180,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { const pkNameResponse = await db.query( `SELECT constraint_name FROM information_schema.table_constraints WHERE table_schema = '${ - typeof statement.schema === 'undefined' || statement.schema === '' - ? 'public' - : statement.schema + typeof statement.schema === 'undefined' || statement.schema === '' ? 'public' : statement.schema }' AND table_name = '${statement.tableName}' AND constraint_type = 'PRIMARY KEY';`, @@ -233,39 +192,24 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { // we will generate statement for drop pk here and not after all if-else statements continue; } else if (statement.type === 'alter_table_add_column') { - if ( - statement.column.notNull - && typeof statement.column.default === 'undefined' - ) { + if (statement.column.notNull && typeof statement.column.default === 'undefined') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); if (count > 0) { infoToPrint.push( `· You're about to add not-null ${ - chalk.underline( - statement.column.name, - ) + chalk.underline(statement.column.name) } column without default value, which contains ${count} items`, ); tablesToTruncate.push(statement.tableName); statementsToExecute.push( `truncate table ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) } cascade;`, ); @@ -275,12 +219,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { } else if (statement.type === 'create_unique_constraint') { const res = await db.query( `select count(*) as count from ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) }`, ); const count = Number(res[0].count); @@ -298,21 +237,13 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { } table?\n`, ); const { status, data } = await render( - new Select([ - 'No, add the constraint without truncating the table', - `Yes, truncate the table`, - ]), + new Select(['No, add the constraint without truncating the table', `Yes, truncate the table`]), ); if (data?.index === 1) { tablesToTruncate.push(statement.tableName); statementsToExecute.push( `truncate table ${ - tableNameWithSchemaFrom( - statement.schema, - statement.tableName, - renamedSchemas, - renamedTables, - ) + tableNameWithSchemaFrom(statement.schema, statement.tableName, renamedSchemas, renamedTables) } cascade;`, ); shouldAskForApprove = true; @@ -323,12 +254,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { if (typeof stmnt !== 'undefined') { if (statement.type === 'drop_table') { statementsToExecute.push( - `DROP TABLE ${ - concatSchemaAndTableName( - statement.schema, - statement.tableName, - ) - } CASCADE;`, + `DROP TABLE ${concatSchemaAndTableName(statement.schema, statement.tableName)} CASCADE;`, ); } else { statementsToExecute.push(...stmnt); @@ -340,6 +266,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { statementsToExecute, shouldAskForApprove, infoToPrint, + matViewsToRemove: [...new Set(matViewsToRemove)], columnsToRemove: [...new Set(columnsToRemove)], schemasToRemove: [...new Set(schemasToRemove)], tablesToTruncate: [...new Set(tablesToTruncate)], diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index d4bd70d08..f84f84d9c 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -183,6 +183,7 @@ export const pgPush = async ( statementsToExecute, columnsToRemove, tablesToRemove, + matViewsToRemove, tablesToTruncate, infoToPrint, schemasToRemove, @@ -238,6 +239,12 @@ export const pgPush = async ( tablesToTruncate.length > 0 ? ` truncate ${tablesToTruncate.length} ${tablesToTruncate.length > 1 ? 'tables' : 'table'}` : '' + }${ + matViewsToRemove.length > 0 + ? ` remove ${matViewsToRemove.length} ${ + matViewsToRemove.length > 1 ? 'materialized views' : 'materialize view' + },` + : ' ' }` .replace(/(^,)|(,$)/g, '') .replace(/ +(?= )/g, ''), diff --git a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts index bcc2d19db..a18b36945 100644 --- a/drizzle-kit/src/cli/commands/sqlitePushUtils.ts +++ b/drizzle-kit/src/cli/commands/sqlitePushUtils.ts @@ -27,6 +27,14 @@ export const _moveDataStatements = ( const compositePKs = Object.values( json.tables[tableName].compositePrimaryKeys, ).map((it) => SQLiteSquasher.unsquashPK(it)); + const checkConstraints = Object.values(json.tables[tableName].checkConstraints); + + const mappedCheckConstraints: string[] = checkConstraints.map((it) => + it.replaceAll(`"${tableName}".`, `"${newTableName}".`) + .replaceAll(`\`${tableName}\`.`, `\`${newTableName}\`.`) + .replaceAll(`${tableName}.`, `${newTableName}.`) + .replaceAll(`'${tableName}'.`, `\`${newTableName}\`.`) + ); const fks = referenceData.map((it) => SQLiteSquasher.unsquashPushFK(it)); @@ -38,6 +46,7 @@ export const _moveDataStatements = ( columns: tableColumns, referenceData: fks, compositePKs, + checkConstraints: mappedCheckConstraints, }), ); diff --git a/drizzle-kit/src/cli/views.ts b/drizzle-kit/src/cli/views.ts index 56e0331df..fd4a68d71 100644 --- a/drizzle-kit/src/cli/views.ts +++ b/drizzle-kit/src/cli/views.ts @@ -166,7 +166,7 @@ export class ResolveSelect extends Prompt< constructor( private readonly base: T, data: (RenamePropmtItem | T)[], - private readonly entityType: 'table' | 'enum' | 'sequence', + private readonly entityType: 'table' | 'enum' | 'sequence' | 'view', ) { super(); this.on('attach', (terminal) => terminal.toggleCursor('hide')); @@ -330,7 +330,9 @@ export type IntrospectStage = | 'columns' | 'enums' | 'indexes' - | 'fks'; + | 'checks' + | 'fks' + | 'views'; type IntrospectState = { [key in IntrospectStage]: { count: number; @@ -369,6 +371,16 @@ export class IntrospectProgress extends TaskView { name: 'foreign keys', status: 'fetching', }, + checks: { + count: 0, + name: 'check constraints', + status: 'fetching', + }, + views: { + count: 0, + name: 'views', + status: 'fetching', + }, }; constructor(private readonly hasEnums: boolean = false) { @@ -422,6 +434,9 @@ export class IntrospectProgress extends TaskView { info += this.hasEnums ? this.statusText(spin, this.state.enums) : ''; info += this.statusText(spin, this.state.indexes); info += this.statusText(spin, this.state.fks); + info += this.statusText(spin, this.state.checks); + info += this.statusText(spin, this.state.views); + return info; } } diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index 8c1aa3a76..ea287713f 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -4,6 +4,7 @@ import './@types/utils'; import type { Casing } from './cli/validations/common'; import { assertUnreachable } from './global'; import { + CheckConstraint, Column, ForeignKey, Index, @@ -155,11 +156,15 @@ export const schemaToTypeScript = ( const uniqueImports = Object.values(it.uniqueConstraints).map( (it) => 'unique', ); + const checkImports = Object.values(it.checkConstraint).map( + (it) => 'check', + ); res.mysql.push(...idxImports); res.mysql.push(...fkImpots); res.mysql.push(...pkImports); res.mysql.push(...uniqueImports); + res.mysql.push(...checkImports); const columnImports = Object.values(it.columns) .map((col) => { @@ -186,6 +191,31 @@ export const schemaToTypeScript = ( { mysql: [] as string[] }, ); + Object.values(schema.views).forEach((it) => { + imports.mysql.push('mysqlView'); + + const columnImports = Object.values(it.columns) + .map((col) => { + let patched = importsPatch[col.type] ?? col.type; + patched = patched.startsWith('varchar(') ? 'varchar' : patched; + patched = patched.startsWith('char(') ? 'char' : patched; + patched = patched.startsWith('binary(') ? 'binary' : patched; + patched = patched.startsWith('decimal(') ? 'decimal' : patched; + patched = patched.startsWith('smallint(') ? 'smallint' : patched; + patched = patched.startsWith('enum(') ? 'mysqlEnum' : patched; + patched = patched.startsWith('datetime(') ? 'datetime' : patched; + patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; + patched = patched.startsWith('int(') ? 'int' : patched; + patched = patched.startsWith('double(') ? 'double' : patched; + return patched; + }) + .filter((type) => { + return mysqlImportsList.has(type); + }); + + imports.mysql.push(...columnImports); + }); + const tableStatements = Object.values(schema.tables).map((table) => { const func = 'mysqlTable'; let statement = ''; @@ -217,6 +247,7 @@ export const schemaToTypeScript = ( || filteredFKs.length > 0 || Object.keys(table.compositePrimaryKeys).length > 0 || Object.keys(table.uniqueConstraints).length > 0 + || Object.keys(table.checkConstraint).length > 0 ) { statement += ',\n'; statement += '(table) => {\n'; @@ -235,6 +266,10 @@ export const schemaToTypeScript = ( Object.values(table.uniqueConstraints), withCasing, ); + statement += createTableChecks( + Object.values(table.checkConstraint), + withCasing, + ); statement += '\t}\n'; statement += '}'; } @@ -243,6 +278,37 @@ export const schemaToTypeScript = ( return statement; }); + const viewsStatements = Object.values(schema.views).map((view) => { + const { columns, name, algorithm, definition, sqlSecurity, withCheckOption } = view; + const func = 'mysqlView'; + let statement = ''; + + if (imports.mysql.includes(withCasing(name))) { + statement = `// Table name is in conflict with ${ + withCasing( + view.name, + ) + } import.\n// Please change to any other name, that is not in imports list\n`; + } + statement += `export const ${withCasing(name)} = ${func}("${name}", {\n`; + statement += createTableColumns( + Object.values(columns), + [], + withCasing, + casing, + name, + schema, + ); + statement += '})'; + + statement += algorithm ? `.algorithm("${algorithm}")` : ''; + statement += sqlSecurity ? `.sqlSecurity("${sqlSecurity}")` : ''; + statement += withCheckOption ? `.withCheckOption("${withCheckOption}")` : ''; + statement += `.as(sql\`${definition?.replaceAll('`', '\\`')}\`);`; + + return statement; + }); + const uniqueMySqlImports = [ 'mysqlTable', 'mysqlSchema', @@ -257,6 +323,8 @@ export const schemaToTypeScript = ( let decalrations = ''; decalrations += tableStatements.join('\n\n'); + decalrations += '\n'; + decalrations += viewsStatements.join('\n\n'); const file = importsTs + decalrations; @@ -855,6 +923,25 @@ const createTableUniques = ( return statement; }; +const createTableChecks = ( + checks: CheckConstraint[], + casing: (value: string) => string, +): string => { + let statement = ''; + + checks.forEach((it) => { + const checkKey = casing(it.name); + + statement += `\t\t${checkKey}: `; + statement += 'check('; + statement += `"${it.name}", `; + statement += `sql\`${it.value.replace(/`/g, '\\`')}\`)`; + statement += `,\n`; + }); + + return statement; +}; + const createTablePKs = ( pks: PrimaryKey[], casing: (value: string) => string, diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index 8eed3d35f..1b57f0115 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -14,6 +14,7 @@ import { Casing } from './cli/validations/common'; import { vectorOps } from './extensions/vector'; import { assertUnreachable } from './global'; import { + CheckConstraint, Column, ForeignKey, Index, @@ -133,9 +134,7 @@ const intervalConfig = (str: string) => { if (keys.length === 0) return; let statement = '{ '; - statement += keys - .map((it: keyof typeof json) => `${it}: ${json[it]}`) - .join(', '); + statement += keys.map((it: keyof typeof json) => `${it}: ${json[it]}`).join(', '); statement += ' }'; return statement; }; @@ -207,10 +206,7 @@ export const relationsToTypeScriptForStudio = ( ...relations, }; - const relationsConfig = extractTablesRelationalConfig( - relationalSchema, - createTableRelationsHelpers, - ); + const relationsConfig = extractTablesRelationalConfig(relationalSchema, createTableRelationsHelpers); let result = ''; @@ -239,45 +235,29 @@ export const relationsToTypeScriptForStudio = ( if (is(relation, Many)) { hasMany = true; relationsObjAsStr += `\t\t${relation.fieldName}: many(${ - relationsConfig.tableNamesMap[relation.referencedTableName].split( - '.', - )[1] - }${ - typeof relation.relationName !== 'undefined' - ? `, { relationName: "${relation.relationName}"}` - : '' - }),`; + relationsConfig.tableNamesMap[relation.referencedTableName].split('.')[1] + }${typeof relation.relationName !== 'undefined' ? `, { relationName: "${relation.relationName}"}` : ''}),`; } if (is(relation, One)) { hasOne = true; relationsObjAsStr += `\t\t${relation.fieldName}: one(${ - relationsConfig.tableNamesMap[relation.referencedTableName].split( - '.', - )[1] + relationsConfig.tableNamesMap[relation.referencedTableName].split('.')[1] }, { fields: [${ relation.config?.fields.map( (c) => - `${ - relationsConfig.tableNamesMap[ - getTableName(relation.sourceTable) - ].split('.')[1] - }.${findColumnKey(relation.sourceTable, c.name)}`, + `${relationsConfig.tableNamesMap[getTableName(relation.sourceTable)].split('.')[1]}.${ + findColumnKey(relation.sourceTable, c.name) + }`, ) }], references: [${ relation.config?.references.map( (c) => - `${ - relationsConfig.tableNamesMap[ - getTableName(relation.referencedTable) - ].split('.')[1] - }.${findColumnKey(relation.referencedTable, c.name)}`, + `${relationsConfig.tableNamesMap[getTableName(relation.referencedTable)].split('.')[1]}.${ + findColumnKey(relation.referencedTable, c.name) + }`, ) - }]${ - typeof relation.relationName !== 'undefined' - ? `, relationName: "${relation.relationName}"` - : '' - }}),`; + }]${typeof relation.relationName !== 'undefined' ? `, relationName: "${relation.relationName}"` : ''}}),`; } }); @@ -325,10 +305,7 @@ export const paramNameFor = (name: string, schema?: string) => { return `${name}${schemaSuffix}`; }; -export const schemaToTypeScript = ( - schema: PgSchemaInternal, - casing: Casing, -) => { +export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => { // collectFKs Object.values(schema.tables).forEach((table) => { Object.values(table.foreignKeys).forEach((fk) => { @@ -343,28 +320,23 @@ export const schemaToTypeScript = ( }), ); - const enumTypes = Object.values(schema.enums).reduce( - (acc, cur) => { - acc.add(`${cur.schema}.${cur.name}`); - return acc; - }, - new Set(), - ); + const enumTypes = Object.values(schema.enums).reduce((acc, cur) => { + acc.add(`${cur.schema}.${cur.name}`); + return acc; + }, new Set()); const imports = Object.values(schema.tables).reduce( (res, it) => { - const idxImports = Object.values(it.indexes).map((idx) => idx.isUnique ? 'uniqueIndex' : 'index'); + const idxImports = Object.values(it.indexes).map((idx) => (idx.isUnique ? 'uniqueIndex' : 'index')); const fkImpots = Object.values(it.foreignKeys).map((it) => 'foreignKey'); - if ( - Object.values(it.foreignKeys).some((it) => isCyclic(it) && !isSelf(it)) - ) { + if (Object.values(it.foreignKeys).some((it) => isCyclic(it) && !isSelf(it))) { res.pg.push('type AnyPgColumn'); } - const pkImports = Object.values(it.compositePrimaryKeys).map( - (it) => 'primaryKey', - ); - const uniqueImports = Object.values(it.uniqueConstraints).map( - (it) => 'unique', + const pkImports = Object.values(it.compositePrimaryKeys).map((it) => 'primaryKey'); + const uniqueImports = Object.values(it.uniqueConstraints).map((it) => 'unique'); + + const checkImports = Object.values(it.checkConstraints).map( + (it) => 'check', ); if (it.schema && it.schema !== 'public' && it.schema !== '') { @@ -375,6 +347,7 @@ export const schemaToTypeScript = ( res.pg.push(...fkImpots); res.pg.push(...pkImports); res.pg.push(...uniqueImports); + res.pg.push(...checkImports); const columnImports = Object.values(it.columns) .map((col) => { @@ -399,6 +372,35 @@ export const schemaToTypeScript = ( { pg: [] as string[] }, ); + Object.values(schema.views).forEach((it) => { + if (it.schema && it.schema !== 'public' && it.schema !== '') { + imports.pg.push('pgSchema'); + } else if (it.schema === 'public') { + it.materialized ? imports.pg.push('pgMaterializedView') : imports.pg.push('pgView'); + } + + Object.values(it.columns).forEach(() => { + const columnImports = Object.values(it.columns) + .map((col) => { + let patched: string = (importsPatch[col.type] || col.type).replace('[]', ''); + patched = patched === 'double precision' ? 'doublePrecision' : patched; + patched = patched.startsWith('varchar(') ? 'varchar' : patched; + patched = patched.startsWith('char(') ? 'char' : patched; + patched = patched.startsWith('numeric(') ? 'numeric' : patched; + patched = patched.startsWith('time(') ? 'time' : patched; + patched = patched.startsWith('timestamp(') ? 'timestamp' : patched; + patched = patched.startsWith('vector(') ? 'vector' : patched; + patched = patched.startsWith('geometry(') ? 'geometry' : patched; + return patched; + }) + .filter((type) => { + return pgImportsList.has(type); + }); + + imports.pg.push(...columnImports); + }); + }); + Object.values(schema.sequences).forEach((it) => { if (it.schema && it.schema !== 'public' && it.schema !== '') { imports.pg.push('pgSchema'); @@ -503,15 +505,12 @@ export const schemaToTypeScript = ( || Object.values(table.foreignKeys).length > 0 || Object.keys(table.compositePrimaryKeys).length > 0 || Object.keys(table.uniqueConstraints).length > 0 + || Object.keys(table.checkConstraints).length > 0 ) { statement += ',\n'; statement += '(table) => {\n'; statement += '\treturn {\n'; - statement += createTableIndexes( - table.name, - Object.values(table.indexes), - casing, - ); + statement += createTableIndexes(table.name, Object.values(table.indexes), casing); statement += createTableFKs(Object.values(table.foreignKeys), schemas, casing); statement += createTablePKs( Object.values(table.compositePrimaryKeys), @@ -521,6 +520,10 @@ export const schemaToTypeScript = ( Object.values(table.uniqueConstraints), casing, ); + statement += createTableChecks( + Object.values(table.checkConstraints), + casing, + ); statement += '\t}\n'; statement += '}'; } @@ -529,13 +532,46 @@ export const schemaToTypeScript = ( return statement; }); + const viewsStatements = Object.values(schema.views) + .map((it) => { + const viewSchema = schemas[it.schema]; + + const paramName = paramNameFor(it.name, viewSchema); + + const func = viewSchema + ? (it.materialized ? `${viewSchema}.materializedView` : `${viewSchema}.view`) + : it.materialized + ? 'pgMaterializedView' + : 'pgView'; + + const withOption = it.with ?? ''; + + const as = `sql\`${it.definition}\``; + + const tablespace = it.tablespace ?? ''; + + const columns = createTableColumns( + '', + Object.values(it.columns), + [], + enumTypes, + schemas, + casing, + schema.internal, + ); + + let statement = `export const ${withCasing(paramName, casing)} = ${func}("${it.name}", {${columns}})`; + statement += tablespace ? `.tablespace("${tablespace}")` : ''; + statement += withOption ? `.with(${JSON.stringify(withOption)})` : ''; + statement += `.as(${as});`; + + return statement; + }) + .join('\n\n'); + const uniquePgImports = ['pgTable', ...new Set(imports.pg)]; - const importsTs = `import { ${ - uniquePgImports.join( - ', ', - ) - } } from "drizzle-orm/pg-core" + const importsTs = `import { ${uniquePgImports.join(', ')} } from "drizzle-orm/pg-core" import { sql } from "drizzle-orm"\n\n`; let decalrations = schemaStatements; @@ -543,6 +579,8 @@ export const schemaToTypeScript = ( decalrations += sequencesStatements; decalrations += '\n'; decalrations += tableStatements.join('\n\n'); + decalrations += '\n'; + decalrations += viewsStatements; const file = importsTs + decalrations; @@ -586,9 +624,7 @@ const buildArrayDefault = (defaultValue: string, typeName: string): string => { // } else if (typeName === 'boolean') { // return value === 't' ? 'true' : 'false'; if (typeName === 'json' || typeName === 'jsonb') { - return value - .substring(1, value.length - 1) - .replaceAll('\\', ''); + return value.substring(1, value.length - 1).replaceAll('\\', ''); } return value; // } @@ -652,9 +688,9 @@ const mapDefault = ( if (lowered.startsWith('numeric')) { defaultValue = defaultValue - ? defaultValue.startsWith(`'`) && defaultValue.endsWith(`'`) + ? (defaultValue.startsWith(`'`) && defaultValue.endsWith(`'`) ? defaultValue.substring(1, defaultValue.length - 1) - : defaultValue + : defaultValue) : undefined; return defaultValue ? `.default('${mapColumnDefault(defaultValue, isExpression)}')` : ''; } @@ -663,7 +699,7 @@ const mapDefault = ( return defaultValue === 'now()' ? '.defaultNow()' : defaultValue === 'CURRENT_TIMESTAMP' - ? '.default(sql\`CURRENT_TIMESTAMP\`)' + ? '.default(sql`CURRENT_TIMESTAMP`)' : defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -766,12 +802,9 @@ const column = ( const lowered = type.toLowerCase().replace('[]', ''); if (enumTypes.has(`${typeSchema}.${type.replace('[]', '')}`)) { - let out = `${withCasing(name, casing)}: ${ - withCasing( - paramNameFor(type.replace('[]', ''), typeSchema), - casing, - ) - }(${dbColumnName({ name, casing })})`; + let out = `${withCasing(name, casing)}: ${withCasing(paramNameFor(type.replace('[]', ''), typeSchema), casing)}(${ + dbColumnName({ name, casing }) + })`; return out; } @@ -784,12 +817,9 @@ const column = ( } if (lowered.startsWith('bigserial')) { - return `${ - withCasing( - name, - casing, - ) - }: bigserial(${dbColumnName({ name, casing, withMode: true })}{ mode: "bigint" })`; + return `${withCasing(name, casing)}: bigserial(${ + dbColumnName({ name, casing, withMode: true }) + }{ mode: "bigint" })`; } if (lowered.startsWith('integer')) { @@ -830,14 +860,10 @@ const column = ( } if (lowered.startsWith('numeric')) { - let params: - | { precision: string | undefined; scale: string | undefined } - | undefined; + let params: { precision: string | undefined; scale: string | undefined } | undefined; if (lowered.length > 7) { - const [precision, scale] = lowered - .slice(8, lowered.length - 1) - .split(','); + const [precision, scale] = lowered.slice(8, lowered.length - 1).split(','); params = { precision, scale }; } @@ -852,11 +878,7 @@ const column = ( const withTimezone = lowered.includes('with time zone'); // const split = lowered.split(" "); let precision = lowered.startsWith('timestamp(') - ? Number( - lowered - .split(' ')[0] - .substring('timestamp('.length, lowered.split(' ')[0].length - 1), - ) + ? Number(lowered.split(' ')[0].substring('timestamp('.length, lowered.split(' ')[0].length - 1)) : null; precision = precision ? precision : null; @@ -877,11 +899,7 @@ const column = ( const withTimezone = lowered.includes('with time zone'); let precision = lowered.startsWith('time(') - ? Number( - lowered - .split(' ')[0] - .substring('time('.length, lowered.split(' ')[0].length - 1), - ) + ? Number(lowered.split(' ')[0].substring('time('.length, lowered.split(' ')[0].length - 1)) : null; precision = precision ? precision : null; @@ -953,16 +971,8 @@ const column = ( if (lowered.startsWith('varchar')) { let out: string; if (lowered.length !== 7) { - out = `${ - withCasing( - name, - casing, - ) - }: varchar(${dbColumnName({ name, casing, withMode: true })}{ length: ${ - lowered.substring( - 8, - lowered.length - 1, - ) + out = `${withCasing(name, casing)}: varchar(${dbColumnName({ name, casing, withMode: true })}{ length: ${ + lowered.substring(8, lowered.length - 1) } })`; } else { out = `${withCasing(name, casing)}: varchar(${dbColumnName({ name, casing })})`; @@ -1015,16 +1025,8 @@ const column = ( if (lowered.startsWith('vector')) { let out: string; if (lowered.length !== 6) { - out = `${ - withCasing( - name, - casing, - ) - }: vector(${dbColumnName({ name, casing, withMode: true })}{ dimensions: ${ - lowered.substring( - 7, - lowered.length - 1, - ) + out = `${withCasing(name, casing)}: vector(${dbColumnName({ name, casing, withMode: true })}{ dimensions: ${ + lowered.substring(7, lowered.length - 1) } })`; } else { out = `${withCasing(name, casing)}: vector(${dbColumnName({ name, casing })})`; @@ -1036,16 +1038,8 @@ const column = ( if (lowered.startsWith('char')) { let out: string; if (lowered.length !== 4) { - out = `${ - withCasing( - name, - casing, - ) - }: char(${dbColumnName({ name, casing, withMode: true })}{ length: ${ - lowered.substring( - 5, - lowered.length - 1, - ) + out = `${withCasing(name, casing)}: char(${dbColumnName({ name, casing, withMode: true })}{ length: ${ + lowered.substring(5, lowered.length - 1) } })`; } else { out = `${withCasing(name, casing)}: char(${dbColumnName({ name, casing })})`; @@ -1108,27 +1102,15 @@ const createTableColumns = ( statement += columnStatement; // Provide just this in column function if (internals?.tables[tableName]?.columns[it.name]?.isArray) { - statement += dimensionsInArray( - internals?.tables[tableName]?.columns[it.name]?.dimensions, - ); + statement += dimensionsInArray(internals?.tables[tableName]?.columns[it.name]?.dimensions); } - statement += mapDefault( - tableName, - it.type, - it.name, - enumTypes, - it.typeSchema ?? 'public', - it.default, - internals, - ); + statement += mapDefault(tableName, it.type, it.name, enumTypes, it.typeSchema ?? 'public', it.default, internals); statement += it.primaryKey ? '.primaryKey()' : ''; statement += it.notNull && !it.identity ? '.notNull()' : ''; statement += it.identity ? generateIdentityParams(it.identity) : ''; - statement += it.generated - ? `.generatedAlwaysAs(sql\`${it.generated.as}\`)` - : ''; + statement += it.generated ? `.generatedAlwaysAs(sql\`${it.generated.as}\`)` : ''; // const fks = fkByColumnName[it.name]; // Andrii: I switched it off until we will get a custom naem setting in references @@ -1169,21 +1151,13 @@ const createTableColumns = ( return statement; }; -const createTableIndexes = ( - tableName: string, - idxs: Index[], - casing: Casing, -): string => { +const createTableIndexes = (tableName: string, idxs: Index[], casing: Casing): string => { let statement = ''; idxs.forEach((it) => { // we have issue when index is called as table called - let idxKey = it.name.startsWith(tableName) && it.name !== tableName - ? it.name.slice(tableName.length + 1) - : it.name; - idxKey = idxKey.endsWith('_index') - ? idxKey.slice(0, -'_index'.length) + '_idx' - : idxKey; + let idxKey = it.name.startsWith(tableName) && it.name !== tableName ? it.name.slice(tableName.length + 1) : it.name; + idxKey = idxKey.endsWith('_index') ? idxKey.slice(0, -'_index'.length) + '_idx' : idxKey; idxKey = withCasing(idxKey, casing); @@ -1206,11 +1180,7 @@ const createTableIndexes = ( } else { return `table.${withCasing(it.expression, casing)}${it.asc ? '.asc()' : '.desc()'}${ it.nulls === 'first' ? '.nullsFirst()' : '.nullsLast()' - }${ - it.opclass && vectorOps.includes(it.opclass) - ? `.op("${it.opclass}")` - : '' - }`; + }${it.opclass && vectorOps.includes(it.opclass) ? `.op("${it.opclass}")` : ''}`; } }) .join(', ') @@ -1224,15 +1194,11 @@ const createTableIndexes = ( reversedString += `${key}: "${mappedWith[key]}",`; } } - reversedString = reversedString.length > 1 - ? reversedString.slice(0, reversedString.length - 1) - : reversedString; + reversedString = reversedString.length > 1 ? reversedString.slice(0, reversedString.length - 1) : reversedString; return `${reversedString}}`; } - statement += it.with && Object.keys(it.with).length > 0 - ? `.with(${reverseLogic(it.with)})` - : ''; + statement += it.with && Object.keys(it.with).length > 0 ? `.with(${reverseLogic(it.with)})` : ''; statement += `,\n`; }); @@ -1261,10 +1227,7 @@ const createTablePKs = (pks: PrimaryKey[], casing: Casing): string => { return statement; }; -const createTableUniques = ( - unqs: UniqueConstraint[], - casing: Casing, -): string => { +const createTableUniques = (unqs: UniqueConstraint[], casing: Casing): string => { let statement = ''; unqs.forEach((it) => { @@ -1273,11 +1236,7 @@ const createTableUniques = ( statement += `\t\t${idxKey}: `; statement += 'unique('; statement += `"${it.name}")`; - statement += `.on(${ - it.columns - .map((it) => `table.${withCasing(it, casing)}`) - .join(', ') - })`; + statement += `.on(${it.columns.map((it) => `table.${withCasing(it, casing)}`).join(', ')})`; statement += it.nullsNotDistinct ? `.nullsNotDistinct()` : ''; statement += `,\n`; }); @@ -1285,11 +1244,25 @@ const createTableUniques = ( return statement; }; -const createTableFKs = ( - fks: ForeignKey[], - schemas: Record, +const createTableChecks = ( + checkConstraints: CheckConstraint[], casing: Casing, -): string => { +) => { + let statement = ''; + + checkConstraints.forEach((it) => { + const checkKey = withCasing(it.name, casing); + statement += `\t\t${checkKey}: `; + statement += 'check('; + statement += `"${it.name}", `; + statement += `sql\`${it.value}\`)`; + statement += `,\n`; + }); + + return statement; +}; + +const createTableFKs = (fks: ForeignKey[], schemas: Record, casing: Casing): string => { let statement = ''; fks.forEach((it) => { @@ -1299,26 +1272,16 @@ const createTableFKs = ( const isSelf = it.tableTo === it.tableFrom; const tableTo = isSelf ? 'table' : `${withCasing(paramName, casing)}`; statement += `\t\t${withCasing(it.name, casing)}: foreignKey({\n`; - statement += `\t\t\tcolumns: [${ - it.columnsFrom - .map((i) => `table.${withCasing(i, casing)}`) - .join(', ') - }],\n`; + statement += `\t\t\tcolumns: [${it.columnsFrom.map((i) => `table.${withCasing(i, casing)}`).join(', ')}],\n`; statement += `\t\t\tforeignColumns: [${ - it.columnsTo - .map((i) => `${tableTo}.${withCasing(i, casing)}`) - .join(', ') + it.columnsTo.map((i) => `${tableTo}.${withCasing(i, casing)}`).join(', ') }],\n`; statement += `\t\t\tname: "${it.name}"\n`; statement += `\t\t})`; - statement += it.onUpdate && it.onUpdate !== 'no action' - ? `.onUpdate("${it.onUpdate}")` - : ''; + statement += it.onUpdate && it.onUpdate !== 'no action' ? `.onUpdate("${it.onUpdate}")` : ''; - statement += it.onDelete && it.onDelete !== 'no action' - ? `.onDelete("${it.onDelete}")` - : ''; + statement += it.onDelete && it.onDelete !== 'no action' ? `.onDelete("${it.onDelete}")` : ''; statement += `,\n`; }); diff --git a/drizzle-kit/src/introspect-sqlite.ts b/drizzle-kit/src/introspect-sqlite.ts index 422e58f86..e21f2a5c4 100644 --- a/drizzle-kit/src/introspect-sqlite.ts +++ b/drizzle-kit/src/introspect-sqlite.ts @@ -3,6 +3,7 @@ import { toCamelCase } from 'drizzle-orm/casing'; import './@types/utils'; import type { Casing } from './cli/validations/common'; import { assertUnreachable } from './global'; +import { CheckConstraint } from './serializer/mysqlSchema'; import type { Column, ForeignKey, @@ -91,11 +92,15 @@ export const schemaToTypeScript = ( const uniqueImports = Object.values(it.uniqueConstraints).map( (it) => 'unique', ); + const checkImports = Object.values(it.checkConstraints).map( + (it) => 'check', + ); res.sqlite.push(...idxImports); res.sqlite.push(...fkImpots); res.sqlite.push(...pkImports); res.sqlite.push(...uniqueImports); + res.sqlite.push(...checkImports); const columnImports = Object.values(it.columns) .map((col) => { @@ -111,6 +116,20 @@ export const schemaToTypeScript = ( { sqlite: [] as string[] }, ); + Object.values(schema.views).forEach((it) => { + imports.sqlite.push('sqliteView'); + + const columnImports = Object.values(it.columns) + .map((col) => { + return col.type; + }) + .filter((type) => { + return sqliteImportsList.has(type); + }); + + imports.sqlite.push(...columnImports); + }); + const tableStatements = Object.values(schema.tables).map((table) => { const func = 'sqliteTable'; let statement = ''; @@ -140,6 +159,7 @@ export const schemaToTypeScript = ( || filteredFKs.length > 0 || Object.keys(table.compositePrimaryKeys).length > 0 || Object.keys(table.uniqueConstraints).length > 0 + || Object.keys(table.checkConstraints).length > 0 ) { statement += ',\n'; statement += '(table) => {\n'; @@ -158,6 +178,10 @@ export const schemaToTypeScript = ( Object.values(table.uniqueConstraints), casing, ); + statement += createTableChecks( + Object.values(table.checkConstraints), + casing, + ); statement += '\t}\n'; statement += '}'; } @@ -166,6 +190,30 @@ export const schemaToTypeScript = ( return statement; }); + const viewsStatements = Object.values(schema.views).map((view) => { + const func = 'sqliteView'; + + let statement = ''; + if (imports.sqlite.includes(withCasing(view.name, casing))) { + statement = `// Table name is in conflict with ${ + withCasing( + view.name, + casing, + ) + } import.\n// Please change to any other name, that is not in imports list\n`; + } + statement += `export const ${withCasing(view.name, casing)} = ${func}("${view.name}", {\n`; + statement += createTableColumns( + Object.values(view.columns), + [], + casing, + ); + statement += '})'; + statement += `.as(sql\`${view.definition?.replaceAll('`', '\\`')}\`);`; + + return statement; + }); + const uniqueSqliteImports = [ 'sqliteTable', 'AnySQLiteColumn', @@ -179,7 +227,9 @@ export const schemaToTypeScript = ( } } from "drizzle-orm/sqlite-core" import { sql } from "drizzle-orm"\n\n`; - const decalrations = tableStatements.join('\n\n'); + let decalrations = tableStatements.join('\n\n'); + decalrations += '\n\n'; + decalrations += viewsStatements.join('\n\n'); const file = importsTs + decalrations; @@ -417,6 +467,24 @@ const createTableUniques = ( return statement; }; +const createTableChecks = ( + checks: CheckConstraint[], + casing: Casing, +): string => { + let statement = ''; + + checks.forEach((it) => { + const checkKey = withCasing(it.name, casing); + + statement += `\t\t${checkKey}: `; + statement += 'check('; + statement += `"${it.name}", `; + statement += `sql\`${it.value}\`)`; + statement += `,\n`; + }); + + return statement; +}; const createTablePKs = (pks: PrimaryKey[], casing: Casing): string => { let statement = ''; diff --git a/drizzle-kit/src/jsonDiffer.js b/drizzle-kit/src/jsonDiffer.js index 113d7e0a4..b5a0e3652 100644 --- a/drizzle-kit/src/jsonDiffer.js +++ b/drizzle-kit/src/jsonDiffer.js @@ -158,6 +158,7 @@ export function applyJsonDiff(json1, json2) { difference.tables = difference.tables || {}; difference.enums = difference.enums || {}; difference.sequences = difference.sequences || {}; + difference.views = difference.views || {}; // remove added/deleted schemas const schemaKeys = Object.keys(difference.schemas); @@ -239,6 +240,85 @@ export function applyJsonDiff(json1, json2) { return json2.sequences[it[0]]; }); + const viewsEntries = Object.entries(difference.views); + + const alteredViews = viewsEntries.filter((it) => !(it[0].includes('__added') || it[0].includes('__deleted'))).map( + ([nameWithSchema, view]) => { + const deletedWithOption = view.with__deleted; + + const addedWithOption = view.with__added; + + const deletedWith = Object.fromEntries( + Object.entries(view.with || {}).filter((it) => it[0].endsWith('__deleted')).map(([key, value]) => { + return [key.replace('__deleted', ''), value]; + }), + ); + + const addedWith = Object.fromEntries( + Object.entries(view.with || {}).filter((it) => it[0].endsWith('__added')).map(([key, value]) => { + return [key.replace('__added', ''), value]; + }), + ); + + const alterWith = Object.fromEntries( + Object.entries(view.with || {}).filter((it) => + typeof it[1].__old !== 'undefined' && typeof it[1].__new !== 'undefined' + ).map( + (it) => { + return [it[0], it[1].__new]; + }, + ), + ); + + const alteredSchema = view.schema; + + const alteredDefinition = view.definition; + + const alteredExisting = view.isExisting; + + const addedTablespace = view.tablespace__added; + const droppedTablespace = view.tablespace__deleted; + const alterTablespaceTo = view.tablespace; + + let alteredTablespace; + if (addedTablespace) alteredTablespace = { __new: addedTablespace, __old: 'pg_default' }; + if (droppedTablespace) alteredTablespace = { __new: 'pg_default', __old: droppedTablespace }; + if (alterTablespaceTo) alteredTablespace = alterTablespaceTo; + + const addedUsing = view.using__added; + const droppedUsing = view.using__deleted; + const alterUsingTo = view.using; + + let alteredUsing; + if (addedUsing) alteredUsing = { __new: addedUsing, __old: 'heap' }; + if (droppedUsing) alteredUsing = { __new: 'heap', __old: droppedUsing }; + if (alterUsingTo) alteredUsing = alterUsingTo; + + const alteredMeta = view.meta; + + return Object.fromEntries( + Object.entries({ + name: json2.views[nameWithSchema].name, + schema: json2.views[nameWithSchema].schema, + // pg + deletedWithOption: deletedWithOption, + addedWithOption: addedWithOption, + deletedWith: Object.keys(deletedWith).length ? deletedWith : undefined, + addedWith: Object.keys(addedWith).length ? addedWith : undefined, + alteredWith: Object.keys(alterWith).length ? alterWith : undefined, + alteredSchema, + alteredTablespace, + alteredUsing, + // mysql + alteredMeta, + // common + alteredDefinition, + alteredExisting, + }).filter(([_, value]) => value !== undefined), + ); + }, + ); + const alteredTablesWithColumns = Object.values(difference.tables).map( (table) => { return findAlternationsInTable(table); @@ -249,6 +329,7 @@ export function applyJsonDiff(json1, json2) { alteredTablesWithColumns, alteredEnums, alteredSequences, + alteredViews, }; } @@ -346,6 +427,24 @@ const findAlternationsInTable = (table) => { }), ); + const addedCheckConstraints = Object.fromEntries( + Object.entries(table.checkConstraints || {}).filter((it) => { + return it[0].endsWith('__added'); + }), + ); + + const deletedCheckConstraints = Object.fromEntries( + Object.entries(table.checkConstraints || {}).filter((it) => { + return it[0].endsWith('__deleted'); + }), + ); + + const alteredCheckConstraints = Object.fromEntries( + Object.entries(table.checkConstraints || {}).filter((it) => { + return !it[0].endsWith('__deleted') && !it[0].endsWith('__added'); + }), + ); + const mappedAltered = altered.map((it) => alternationsInColumn(it)).filter(Boolean); return { @@ -364,11 +463,15 @@ const findAlternationsInTable = (table) => { addedUniqueConstraints, deletedUniqueConstraints, alteredUniqueConstraints, + addedCheckConstraints, + deletedCheckConstraints, + alteredCheckConstraints, }; }; const alternationsInColumn = (column) => { const altered = [column]; + const result = altered .filter((it) => { if ('type' in it && it.type.__old.replace(' (', '(') === it.type.__new.replace(' (', '(')) { @@ -632,6 +735,33 @@ const alternationsInColumn = (column) => { } return it; }) + .map((it) => { + if ('' in it) { + return { + ...it, + autoincrement: { + type: 'changed', + old: it.autoincrement.__old, + new: it.autoincrement.__new, + }, + }; + } + if ('autoincrement__added' in it) { + const { autoincrement__added, ...others } = it; + return { + ...others, + autoincrement: { type: 'added', value: it.autoincrement__added }, + }; + } + if ('autoincrement__deleted' in it) { + const { autoincrement__deleted, ...others } = it; + return { + ...others, + autoincrement: { type: 'deleted', value: it.autoincrement__deleted }, + }; + } + return it; + }) .filter(Boolean); return result[0]; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 47cb08908..4285c4687 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -1,14 +1,15 @@ import chalk from 'chalk'; -import { getNewTableName, getOldTableName } from './cli/commands/sqlitePushUtils'; +import { getNewTableName } from './cli/commands/sqlitePushUtils'; import { warning } from './cli/views'; -import { CommonSquashedSchema, Dialect } from './schemaValidator'; -import { MySqlKitInternals, MySqlSchema, MySqlSquasher } from './serializer/mysqlSchema'; -import { Index, PgSchema, PgSquasher } from './serializer/pgSchema'; +import { CommonSquashedSchema } from './schemaValidator'; +import { MySqlKitInternals, MySqlSchema, MySqlSquasher, View as MySqlView } from './serializer/mysqlSchema'; +import { Index, MatViewWithOption, PgSchema, PgSquasher, View as PgView, ViewWithOption } from './serializer/pgSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, SQLiteSchemaSquashed, SQLiteSquasher, + View as SqliteView, } from './serializer/sqliteSchema'; import { AlteredColumn, Column, Sequence, Table } from './snapshotsDiffer'; @@ -27,6 +28,7 @@ export interface JsonSqliteCreateTableStatement { }[]; compositePKs: string[][]; uniqueConstraints?: string[]; + checkConstraints?: string[]; } export interface JsonCreateTableStatement { @@ -37,6 +39,7 @@ export interface JsonCreateTableStatement { compositePKs: string[]; compositePkName?: string; uniqueConstraints?: string[]; + checkConstraints?: string[]; internals?: MySqlKitInternals; } @@ -55,6 +58,7 @@ export interface JsonRecreateTableStatement { }[]; compositePKs: string[][]; uniqueConstraints?: string[]; + checkConstraints: string[]; } export interface JsonDropTableStatement { @@ -106,6 +110,15 @@ export interface JsonAddValueToEnumStatement { before: string; } +export interface JsonDropValueFromEnumStatement { + type: 'alter_type_drop_value'; + name: string; + schema: string; + deletedValues: string[]; + newValues: string[]; + columnsWithEnum: { schema: string; table: string; column: string }[]; +} + export interface JsonCreateSequenceStatement { type: 'create_sequence'; name: string; @@ -234,6 +247,20 @@ export interface JsonAlterUniqueConstraint { newConstraintName?: string; } +export interface JsonCreateCheckConstraint { + type: 'create_check_constraint'; + tableName: string; + data: string; + schema?: string; +} + +export interface JsonDeleteCheckConstraint { + type: 'delete_check_constraint'; + tableName: string; + constraintName: string; + schema?: string; +} + export interface JsonCreateCompositePK { type: 'create_composite_pk'; tableName: string; @@ -524,6 +551,105 @@ export interface JsonRenameSchema { to: string; } +export type JsonCreatePgViewStatement = { + type: 'create_view'; +} & Omit; + +export type JsonCreateMySqlViewStatement = { + type: 'mysql_create_view'; + replace: boolean; +} & Omit; + +export type JsonCreateSqliteViewStatement = { + type: 'sqlite_create_view'; +} & Omit; + +export interface JsonDropViewStatement { + type: 'drop_view'; + name: string; + schema?: string; + materialized?: boolean; +} + +export interface JsonRenameViewStatement { + type: 'rename_view'; + nameTo: string; + nameFrom: string; + schema: string; + materialized?: boolean; +} + +export interface JsonRenameMySqlViewStatement { + type: 'rename_view'; + nameTo: string; + nameFrom: string; + schema: string; + materialized?: boolean; +} + +export interface JsonAlterViewAlterSchemaStatement { + type: 'alter_view_alter_schema'; + fromSchema: string; + toSchema: string; + name: string; + materialized?: boolean; +} + +export type JsonAlterViewAddWithOptionStatement = + & { + type: 'alter_view_add_with_option'; + schema: string; + name: string; + } + & ({ + materialized: true; + with: MatViewWithOption; + } | { + materialized: false; + with: ViewWithOption; + }); + +export type JsonAlterViewDropWithOptionStatement = + & { + type: 'alter_view_drop_with_option'; + schema: string; + name: string; + } + & ({ + materialized: true; + with: MatViewWithOption; + } | { + materialized: false; + with: ViewWithOption; + }); + +export interface JsonAlterViewAlterTablespaceStatement { + type: 'alter_view_alter_tablespace'; + toTablespace: string; + name: string; + schema: string; + materialized: true; +} + +export interface JsonAlterViewAlterUsingStatement { + type: 'alter_view_alter_using'; + toUsing: string; + name: string; + schema: string; + materialized: true; +} + +export type JsonAlterMySqlViewStatement = { + type: 'alter_mysql_view'; +} & Omit; + +export type JsonAlterViewStatement = + | JsonAlterViewAlterSchemaStatement + | JsonAlterViewAddWithOptionStatement + | JsonAlterViewDropWithOptionStatement + | JsonAlterViewAlterTablespaceStatement + | JsonAlterViewAlterUsingStatement; + export type JsonAlterColumnStatement = | JsonRenameColumnStatement | JsonAlterColumnTypeStatement @@ -582,14 +708,24 @@ export type JsonStatement = | JsonDropSequenceStatement | JsonCreateSequenceStatement | JsonMoveSequenceStatement - | JsonRenameSequenceStatement; + | JsonRenameSequenceStatement + | JsonCreatePgViewStatement + | JsonDropViewStatement + | JsonRenameViewStatement + | JsonAlterViewStatement + | JsonCreateMySqlViewStatement + | JsonAlterMySqlViewStatement + | JsonCreateSqliteViewStatement + | JsonCreateCheckConstraint + | JsonDeleteCheckConstraint + | JsonDropValueFromEnumStatement; export const preparePgCreateTableJson = ( table: Table, // TODO: remove? json2: PgSchema, ): JsonCreateTableStatement => { - const { name, schema, columns, compositePrimaryKeys, uniqueConstraints } = table; + const { name, schema, columns, compositePrimaryKeys, uniqueConstraints, checkConstraints } = table; const tableKey = `${schema || 'public'}.${name}`; // TODO: @AndriiSherman. We need this, will add test cases @@ -607,6 +743,7 @@ export const preparePgCreateTableJson = ( compositePKs: Object.values(compositePrimaryKeys), compositePkName: compositePkName, uniqueConstraints: Object.values(uniqueConstraints), + checkConstraints: Object.values(checkConstraints), }; }; @@ -619,7 +756,7 @@ export const prepareMySqlCreateTableJson = ( // if previously it was an expression or column internals: MySqlKitInternals, ): JsonCreateTableStatement => { - const { name, schema, columns, compositePrimaryKeys, uniqueConstraints } = table; + const { name, schema, columns, compositePrimaryKeys, uniqueConstraints, checkConstraints } = table; return { type: 'create_table', @@ -635,6 +772,7 @@ export const prepareMySqlCreateTableJson = ( : '', uniqueConstraints: Object.values(uniqueConstraints), internals, + checkConstraints: Object.values(checkConstraints), }; }; @@ -642,7 +780,7 @@ export const prepareSQLiteCreateTable = ( table: Table, action?: 'push' | undefined, ): JsonSqliteCreateTableStatement => { - const { name, columns, uniqueConstraints } = table; + const { name, columns, uniqueConstraints, checkConstraints } = table; const references: string[] = Object.values(table.foreignKeys); @@ -663,6 +801,7 @@ export const prepareSQLiteCreateTable = ( referenceData: fks, compositePKs: composites, uniqueConstraints: Object.values(uniqueConstraints), + checkConstraints: Object.values(checkConstraints), }; }; @@ -717,6 +856,36 @@ export const prepareAddValuesToEnumJson = ( }); }; +export const prepareDropEnumValues = ( + name: string, + schema: string, + removedValues: string[], + json2: PgSchema, +): JsonDropValueFromEnumStatement[] => { + if (!removedValues.length) return []; + + const affectedColumns: { schema: string; table: string; column: string }[] = []; + + for (const tableKey in json2.tables) { + const table = json2.tables[tableKey]; + for (const columnKey in table.columns) { + const column = table.columns[columnKey]; + if (column.type === name && column.typeSchema === schema) { + affectedColumns.push({ schema: table.schema || 'public', table: table.name, column: column.name }); + } + } + } + + return [{ + type: 'alter_type_drop_value', + name: name, + schema: schema, + deletedValues: removedValues, + newValues: json2.enums[`${schema}.${name}`].values, + columnsWithEnum: affectedColumns, + }]; +}; + export const prepareDropEnumJson = ( name: string, schema: string, @@ -2331,6 +2500,36 @@ export const prepareDeleteUniqueConstraintPg = ( }); }; +export const prepareAddCheckConstraint = ( + tableName: string, + schema: string, + check: Record, +): JsonCreateCheckConstraint[] => { + return Object.values(check).map((it) => { + return { + type: 'create_check_constraint', + tableName, + data: it, + schema, + } as JsonCreateCheckConstraint; + }); +}; + +export const prepareDeleteCheckConstraint = ( + tableName: string, + schema: string, + check: Record, +): JsonDeleteCheckConstraint[] => { + return Object.values(check).map((it) => { + return { + type: 'delete_check_constraint', + tableName, + constraintName: PgSquasher.unsquashCheck(it).name, + schema, + } as JsonDeleteCheckConstraint; + }); +}; + // add create table changes // add handler to make drop and add and not alter(looking at __old and __new) // add serializer for mysql and sqlite + types @@ -2425,3 +2624,170 @@ export const prepareAlterCompositePrimaryKeyMySql = ( } as JsonAlterCompositePK; }); }; + +export const preparePgCreateViewJson = ( + name: string, + schema: string, + definition: string, + materialized: boolean, + withNoData: boolean = false, + withOption?: any, + using?: string, + tablespace?: string, +): JsonCreatePgViewStatement => { + return { + type: 'create_view', + name: name, + schema: schema, + definition: definition, + with: withOption, + materialized: materialized, + withNoData, + using, + tablespace, + }; +}; + +export const prepareMySqlCreateViewJson = ( + name: string, + definition: string, + meta: string, + replace: boolean = false, +): JsonCreateMySqlViewStatement => { + const { algorithm, sqlSecurity, withCheckOption } = MySqlSquasher.unsquashView(meta); + return { + type: 'mysql_create_view', + name: name, + definition: definition, + algorithm, + sqlSecurity, + withCheckOption, + replace, + }; +}; + +export const prepareSqliteCreateViewJson = ( + name: string, + definition: string, +): JsonCreateSqliteViewStatement => { + return { + type: 'sqlite_create_view', + name: name, + definition: definition, + }; +}; + +export const prepareDropViewJson = ( + name: string, + schema?: string, + materialized?: boolean, +): JsonDropViewStatement => { + const resObject: JsonDropViewStatement = { name, type: 'drop_view' }; + + if (schema) resObject['schema'] = schema; + + if (materialized) resObject['materialized'] = materialized; + + return resObject; +}; + +export const prepareRenameViewJson = ( + to: string, + from: string, + schema?: string, + materialized?: boolean, +): JsonRenameViewStatement => { + const resObject: JsonRenameViewStatement = { + type: 'rename_view', + nameTo: to, + nameFrom: from, + }; + + if (schema) resObject['schema'] = schema; + if (materialized) resObject['materialized'] = materialized; + + return resObject; +}; + +export const preparePgAlterViewAlterSchemaJson = ( + to: string, + from: string, + name: string, + materialized?: boolean, +): JsonAlterViewAlterSchemaStatement => { + const returnObject: JsonAlterViewAlterSchemaStatement = { + type: 'alter_view_alter_schema', + fromSchema: from, + toSchema: to, + name, + }; + + if (materialized) returnObject['materialized'] = materialized; + return returnObject; +}; + +export const preparePgAlterViewAddWithOptionJson = ( + name: string, + schema: string, + materialized: boolean, + withOption: MatViewWithOption | ViewWithOption, +): JsonAlterViewAddWithOptionStatement => { + return { + type: 'alter_view_add_with_option', + name, + schema, + materialized: materialized, + with: withOption, + } as JsonAlterViewAddWithOptionStatement; +}; + +export const preparePgAlterViewDropWithOptionJson = ( + name: string, + schema: string, + materialized: boolean, + withOption: MatViewWithOption | ViewWithOption, +): JsonAlterViewDropWithOptionStatement => { + return { + type: 'alter_view_drop_with_option', + name, + schema, + materialized: materialized, + with: withOption, + } as JsonAlterViewDropWithOptionStatement; +}; + +export const preparePgAlterViewAlterTablespaceJson = ( + name: string, + schema: string, + materialized: boolean, + to: string, +): JsonAlterViewAlterTablespaceStatement => { + return { + type: 'alter_view_alter_tablespace', + name, + schema, + materialized: materialized, + toTablespace: to, + } as JsonAlterViewAlterTablespaceStatement; +}; + +export const preparePgAlterViewAlterUsingJson = ( + name: string, + schema: string, + materialized: boolean, + to: string, +): JsonAlterViewAlterUsingStatement => { + return { + type: 'alter_view_alter_using', + name, + schema, + materialized: materialized, + toUsing: to, + } as JsonAlterViewAlterUsingStatement; +}; + +export const prepareMySqlAlterView = ( + view: Omit, +): JsonAlterMySqlViewStatement => { + return { type: 'alter_mysql_view', ...view }; +}; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index 8f2543d61..05e4a6f37 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -51,9 +51,9 @@ export const serializeMySql = async ( const { prepareFromMySqlImports } = await import('./mysqlImports'); const { generateMySqlSnapshot } = await import('./mysqlSerializer'); - const { tables } = await prepareFromMySqlImports(filenames); + const { tables, views } = await prepareFromMySqlImports(filenames); - return generateMySqlSnapshot(tables, casing); + return generateMySqlSnapshot(tables, views, casing); }; export const serializePg = async ( @@ -66,11 +66,11 @@ export const serializePg = async ( const { prepareFromPgImports } = await import('./pgImports'); const { generatePgSnapshot } = await import('./pgSerializer'); - const { tables, enums, schemas, sequences } = await prepareFromPgImports( + const { tables, enums, schemas, sequences, views, matViews } = await prepareFromPgImports( filenames, ); - return generatePgSnapshot(tables, enums, schemas, sequences, casing, schemaFilter); + return generatePgSnapshot(tables, enums, schemas, sequences, views, matViews, casing, schemaFilter); }; export const serializeSQLite = async ( @@ -81,8 +81,8 @@ export const serializeSQLite = async ( const { prepareFromSqliteImports } = await import('./sqliteImports'); const { generateSqliteSnapshot } = await import('./sqliteSerializer'); - const { tables } = await prepareFromSqliteImports(filenames); - return generateSqliteSnapshot(tables, casing); + const { tables, views } = await prepareFromSqliteImports(filenames); + return generateSqliteSnapshot(tables, views, casing); }; export const prepareFilenames = (path: string | string[]) => { diff --git a/drizzle-kit/src/serializer/mysqlImports.ts b/drizzle-kit/src/serializer/mysqlImports.ts index d9899026b..a8e8ead39 100644 --- a/drizzle-kit/src/serializer/mysqlImports.ts +++ b/drizzle-kit/src/serializer/mysqlImports.ts @@ -1,22 +1,28 @@ import { is } from 'drizzle-orm'; -import { AnyMySqlTable, MySqlTable } from 'drizzle-orm/mysql-core'; +import { AnyMySqlTable, MySqlTable, MySqlView } from 'drizzle-orm/mysql-core'; import { safeRegister } from '../cli/commands/utils'; export const prepareFromExports = (exports: Record) => { const tables: AnyMySqlTable[] = []; + const views: MySqlView[] = []; const i0values = Object.values(exports); i0values.forEach((t) => { if (is(t, MySqlTable)) { tables.push(t); } + + if (is(t, MySqlView)) { + views.push(t); + } }); - return { tables }; + return { tables, views }; }; export const prepareFromMySqlImports = async (imports: string[]) => { const tables: AnyMySqlTable[] = []; + const views: MySqlView[] = []; const { unregister } = await safeRegister(); for (let i = 0; i < imports.length; i++) { @@ -25,7 +31,8 @@ export const prepareFromMySqlImports = async (imports: string[]) => { const prepared = prepareFromExports(i0); tables.push(...prepared.tables); + views.push(...prepared.views); } unregister(); - return { tables: Array.from(new Set(tables)) }; + return { tables: Array.from(new Set(tables)), views }; }; diff --git a/drizzle-kit/src/serializer/mysqlSchema.ts b/drizzle-kit/src/serializer/mysqlSchema.ts index 5bc62ab2f..0255afc10 100644 --- a/drizzle-kit/src/serializer/mysqlSchema.ts +++ b/drizzle-kit/src/serializer/mysqlSchema.ts @@ -1,5 +1,5 @@ import { any, boolean, enum as enumType, literal, object, record, string, TypeOf, union } from 'zod'; -import { mapValues, originUUID, snapshotVersion } from '../global'; +import { mapValues, originUUID } from '../global'; // ------- V3 -------- const index = object({ @@ -52,6 +52,11 @@ const uniqueConstraint = object({ columns: string().array(), }).strict(); +const checkConstraint = object({ + name: string(), + value: string(), +}).strict(); + const tableV4 = object({ name: string(), schema: string().optional(), @@ -67,8 +72,23 @@ const table = object({ foreignKeys: record(string(), fk), compositePrimaryKeys: record(string(), compositePK), uniqueConstraints: record(string(), uniqueConstraint).default({}), + checkConstraint: record(string(), checkConstraint).default({}), }).strict(); +const viewMeta = object({ + algorithm: enumType(['undefined', 'merge', 'temptable']), + sqlSecurity: enumType(['definer', 'invoker']), + withCheckOption: enumType(['local', 'cascaded']).optional(), +}).strict(); + +export const view = object({ + name: string(), + columns: record(string(), column), + definition: string().optional(), + isExisting: boolean(), +}).strict().merge(viewMeta); +type SquasherViewMeta = Omit, 'definer'>; + export const kitInternals = object({ tables: record( string(), @@ -128,6 +148,7 @@ export const schemaInternal = object({ version: literal('5'), dialect: dialect, tables: record(string(), table), + views: record(string(), view), _meta: object({ tables: record(string(), string()), columns: record(string(), string()), @@ -155,12 +176,20 @@ const tableSquashed = object({ foreignKeys: record(string(), string()), compositePrimaryKeys: record(string(), string()), uniqueConstraints: record(string(), string()).default({}), + checkConstraints: record(string(), string()).default({}), }).strict(); +const viewSquashed = view.omit({ + algorithm: true, + sqlSecurity: true, + withCheckOption: true, +}).extend({ meta: string() }); + export const schemaSquashed = object({ version: literal('5'), dialect: dialect, tables: record(string(), tableSquashed), + views: record(string(), viewSquashed), }).strict(); export const schemaSquashedV4 = object({ @@ -186,6 +215,9 @@ export type Index = TypeOf; export type ForeignKey = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; +export type CheckConstraint = TypeOf; +export type View = TypeOf; +export type ViewSquashed = TypeOf; export const MySqlSquasher = { squashIdx: (idx: Index) => { @@ -247,6 +279,27 @@ export const MySqlSquasher = { }); return result; }, + squashCheck: (input: CheckConstraint): string => { + return `${input.name};${input.value}`; + }, + unsquashCheck: (input: string): CheckConstraint => { + const [name, value] = input.split(';'); + + return { name, value }; + }, + squashView: (view: View): string => { + return `${view.algorithm};${view.sqlSecurity};${view.withCheckOption}`; + }, + unsquashView: (meta: string): SquasherViewMeta => { + const [algorithm, sqlSecurity, withCheckOption] = meta.split(';'); + const toReturn = { + algorithm: algorithm, + sqlSecurity: sqlSecurity, + withCheckOption: withCheckOption !== 'undefined' ? withCheckOption : undefined, + }; + + return viewMeta.parse(toReturn); + }, }; export const squashMysqlSchemeV4 = ( @@ -304,6 +357,10 @@ export const squashMysqlScheme = (json: MySqlSchema): MySqlSchemaSquashed => { }, ); + const squashedCheckConstraints = mapValues(it[1].checkConstraint, (check) => { + return MySqlSquasher.squashCheck(check); + }); + return [ it[0], { @@ -313,14 +370,31 @@ export const squashMysqlScheme = (json: MySqlSchema): MySqlSchemaSquashed => { foreignKeys: squashedFKs, compositePrimaryKeys: squashedPKs, uniqueConstraints: squashedUniqueConstraints, + checkConstraints: squashedCheckConstraints, }, ]; }), ); + + const mappedViews = Object.fromEntries( + Object.entries(json.views).map(([key, value]) => { + const meta = MySqlSquasher.squashView(value); + + return [key, { + name: value.name, + isExisting: value.isExisting, + columns: value.columns, + definition: value.definition, + meta, + }]; + }), + ); + return { version: '5', dialect: json.dialect, tables: mappedTables, + views: mappedViews, }; }; @@ -340,6 +414,7 @@ export const dryMySql = mysqlSchema.parse({ prevId: '', tables: {}, schemas: {}, + views: {}, _meta: { schemas: {}, tables: {}, diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index da52ac2fb..5ac717525 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -1,7 +1,7 @@ import chalk from 'chalk'; import { getTableName, is } from 'drizzle-orm'; import { SQL } from 'drizzle-orm'; -import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; +import { getViewConfig, MySqlColumn, MySqlView } from 'drizzle-orm/mysql-core'; import { AnyMySqlTable, MySqlDialect, type PrimaryKey as PrimaryKeyORM, uniqueKeyName } from 'drizzle-orm/mysql-core'; import { getTableConfig } from 'drizzle-orm/mysql-core'; import { RowDataPacket } from 'mysql2/promise'; @@ -9,6 +9,7 @@ import { CasingType } from 'src/cli/validations/common'; import { withStyle } from '../cli/validations/outputs'; import { IntrospectStage, IntrospectStatus } from '../cli/views'; import { + CheckConstraint, Column, ForeignKey, Index, @@ -17,11 +18,10 @@ import { PrimaryKey, Table, UniqueConstraint, + View, } from '../serializer/mysqlSchema'; import { type DB, getColumnCasing } from '../utils'; import { sqlToStr } from '.'; -// import { MySqlColumnWithAutoIncrement } from "drizzle-orm/mysql-core"; -// import { MySqlDateBaseColumn } from "drizzle-orm/mysql-core"; export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; @@ -29,11 +29,14 @@ export const indexName = (tableName: string, columns: string[]) => { export const generateMySqlSnapshot = ( tables: AnyMySqlTable[], + views: MySqlView[], casing: CasingType | undefined, ): MySqlSchemaInternal => { const dialect = new MySqlDialect({ casing }); const result: Record = {}; + const resultViews: Record = {}; const internal: MySqlKitInternals = { tables: {}, indexes: {} }; + for (const table of tables) { const { name: tableName, @@ -41,14 +44,20 @@ export const generateMySqlSnapshot = ( indexes, foreignKeys, schema, + checks, primaryKeys, uniqueConstraints, } = getTableConfig(table); + const columnsObject: Record = {}; const indexesObject: Record = {}; const foreignKeysObject: Record = {}; const primaryKeysObject: Record = {}; const uniqueConstraintObject: Record = {}; + const checkConstraintObject: Record = {}; + + // this object will help to identify same check names + let checksInTable: Record = {}; columns.forEach((column) => { const name = getColumnCasing(column, casing); @@ -347,6 +356,39 @@ export const generateMySqlSnapshot = ( }; }); + checks.forEach((check) => { + check; + const checkName = check.name; + if (typeof checksInTable[tableName] !== 'undefined') { + if (checksInTable[tableName].includes(check.name)) { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated check constraint name in ${ + chalk.underline.blue( + tableName, + ) + }. Please rename your check constraint in the ${ + chalk.underline.blue( + tableName, + ) + } table`, + ) + }`, + ); + process.exit(1); + } + checksInTable[tableName].push(checkName); + } else { + checksInTable[tableName] = [check.name]; + } + + checkConstraintObject[checkName] = { + name: checkName, + value: dialect.sqlToQuery(check.value).sql, + }; + }); + // only handle tables without schemas if (!schema) { result[tableName] = { @@ -356,14 +398,126 @@ export const generateMySqlSnapshot = ( foreignKeys: foreignKeysObject, compositePrimaryKeys: primaryKeysObject, uniqueConstraints: uniqueConstraintObject, + checkConstraint: checkConstraintObject, }; } } + for (const view of views) { + const { + isExisting, + name, + query, + schema, + selectedFields, + algorithm, + sqlSecurity, + withCheckOption, + } = getViewConfig(view); + + const columnsObject: Record = {}; + + const existingView = resultViews[name]; + if (typeof existingView !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated view name across ${ + chalk.underline.blue( + schema ?? 'public', + ) + } schema. Please rename your view`, + ) + }`, + ); + process.exit(1); + } + + for (const key in selectedFields) { + if (is(selectedFields[key], MySqlColumn)) { + const column = selectedFields[key]; + + const notNull: boolean = column.notNull; + const sqlTypeLowered = column.getSQLType().toLowerCase(); + const autoIncrement = typeof (column as any).autoIncrement === 'undefined' + ? false + : (column as any).autoIncrement; + + const generated = column.generated; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + primaryKey: false, + // If field is autoincrement it's notNull by default + // notNull: autoIncrement ? true : notNull, + notNull, + autoincrement: autoIncrement, + onUpdate: (column as any).hasOnUpdateNow, + generated: generated + ? { + as: is(generated.as, SQL) + ? dialect.sqlToQuery(generated.as as SQL).sql + : typeof generated.as === 'function' + ? dialect.sqlToQuery(generated.as() as SQL).sql + : (generated.as as any), + type: generated.mode ?? 'stored', + } + : undefined, + }; + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default, casing); + } else { + if (typeof column.default === 'string') { + columnToSet.default = `'${column.default}'`; + } else { + if (sqlTypeLowered === 'json') { + columnToSet.default = `'${JSON.stringify(column.default)}'`; + } else if (column.default instanceof Date) { + if (sqlTypeLowered === 'date') { + columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; + } else if ( + sqlTypeLowered.startsWith('datetime') + || sqlTypeLowered.startsWith('timestamp') + ) { + columnToSet.default = `'${ + column.default + .toISOString() + .replace('T', ' ') + .slice(0, 23) + }'`; + } + } else { + columnToSet.default = column.default; + } + } + if (['blob', 'text', 'json'].includes(column.getSQLType())) { + columnToSet.default = `(${columnToSet.default})`; + } + } + } + columnsObject[column.name] = columnToSet; + } + } + + resultViews[name] = { + columns: columnsObject, + name, + isExisting, + definition: isExisting ? undefined : dialect.sqlToQuery(query!).sql, + withCheckOption, + algorithm: algorithm ?? 'undefined', // set default values + sqlSecurity: sqlSecurity ?? 'definer', // set default values + }; + } + return { version: '5', dialect: 'mysql', tables: result, + views: resultViews, _meta: { tables: {}, columns: {}, @@ -418,6 +572,8 @@ export const fromDatabase = async ( let tablesCount = new Set(); let indexesCount = 0; let foreignKeysCount = 0; + let checksCount = 0; + let viewsCount = 0; const idxs = await db.query( `select * from INFORMATION_SCHEMA.STATISTICS @@ -561,6 +717,7 @@ export const fromDatabase = async ( indexes: {}, foreignKeys: {}, uniqueConstraints: {}, + checkConstraint: {}, }; } else { result[tableName]!.columns[columnName] = newColumn; @@ -734,16 +891,91 @@ export const fromDatabase = async ( } } + const views = await db.query( + `select * from INFORMATION_SCHEMA.VIEWS WHERE table_schema = '${inputSchema}';`, + ); + + const resultViews: Record = {}; + + viewsCount = views.length; + if (progressCallback) { + progressCallback('views', viewsCount, 'fetching'); + } + for await (const view of views) { + const viewName = view['TABLE_NAME']; + const definition = view['VIEW_DEFINITION']; + + const withCheckOption = view['CHECK_OPTION'] === 'NONE' ? undefined : view['CHECK_OPTION'].toLowerCase(); + const sqlSecurity = view['SECURITY_TYPE'].toLowerCase(); + + const [createSqlStatement] = await db.query(`SHOW CREATE VIEW \`${viewName}\`;`); + const algorithmMatch = createSqlStatement['Create View'].match(/ALGORITHM=([^ ]+)/); + const algorithm = algorithmMatch ? algorithmMatch[1].toLowerCase() : undefined; + + const columns = result[viewName].columns; + delete result[viewName]; + + resultViews[viewName] = { + columns: columns, + isExisting: false, + name: viewName, + algorithm, + definition, + sqlSecurity, + withCheckOption, + }; + } + if (progressCallback) { progressCallback('indexes', indexesCount, 'done'); // progressCallback("enums", 0, "fetching"); progressCallback('enums', 0, 'done'); + progressCallback('views', viewsCount, 'done'); + } + + const checkConstraints = await db.query( + `SELECT + tc.table_name, + tc.constraint_name, + cc.check_clause +FROM + information_schema.table_constraints tc +JOIN + information_schema.check_constraints cc + ON tc.constraint_name = cc.constraint_name +WHERE + tc.constraint_schema = '${inputSchema}' +AND + tc.constraint_type = 'CHECK';`, + ); + + checksCount += checkConstraints.length; + if (progressCallback) { + progressCallback('checks', checksCount, 'fetching'); + } + for (const checkConstraintRow of checkConstraints) { + const constraintName = checkConstraintRow['CONSTRAINT_NAME']; + const constraintValue = checkConstraintRow['CHECK_CLAUSE']; + const tableName = checkConstraintRow['TABLE_NAME']; + + const tableInResult = result[tableName]; + // if (typeof tableInResult === 'undefined') continue; + + tableInResult.checkConstraint[constraintName] = { + name: constraintName, + value: constraintValue, + }; + } + + if (progressCallback) { + progressCallback('checks', checksCount, 'done'); } return { version: '5', dialect: 'mysql', tables: result, + views: resultViews, _meta: { tables: {}, columns: {}, diff --git a/drizzle-kit/src/serializer/pgImports.ts b/drizzle-kit/src/serializer/pgImports.ts index ffedd084c..e0b3fb743 100644 --- a/drizzle-kit/src/serializer/pgImports.ts +++ b/drizzle-kit/src/serializer/pgImports.ts @@ -1,5 +1,17 @@ import { is } from 'drizzle-orm'; -import { AnyPgTable, isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable } from 'drizzle-orm/pg-core'; +import { + AnyPgTable, + isPgEnum, + isPgMaterializedView, + isPgSequence, + isPgView, + PgEnum, + PgMaterializedView, + PgSchema, + PgSequence, + PgTable, + PgView, +} from 'drizzle-orm/pg-core'; import { safeRegister } from '../cli/commands/utils'; export const prepareFromExports = (exports: Record) => { @@ -7,6 +19,8 @@ export const prepareFromExports = (exports: Record) => { const enums: PgEnum[] = []; const schemas: PgSchema[] = []; const sequences: PgSequence[] = []; + const views: PgView[] = []; + const matViews: PgMaterializedView[] = []; const i0values = Object.values(exports); i0values.forEach((t) => { @@ -22,19 +36,29 @@ export const prepareFromExports = (exports: Record) => { schemas.push(t); } + if (isPgView(t)) { + views.push(t); + } + + if (isPgMaterializedView(t)) { + matViews.push(t); + } + if (isPgSequence(t)) { sequences.push(t); } }); - return { tables, enums, schemas, sequences }; + return { tables, enums, schemas, sequences, views, matViews }; }; export const prepareFromPgImports = async (imports: string[]) => { - let tables: AnyPgTable[] = []; - let enums: PgEnum[] = []; - let schemas: PgSchema[] = []; - let sequences: PgSequence[] = []; + const tables: AnyPgTable[] = []; + const enums: PgEnum[] = []; + const schemas: PgSchema[] = []; + const sequences: PgSequence[] = []; + const views: PgView[] = []; + const matViews: PgMaterializedView[] = []; const { unregister } = await safeRegister(); for (let i = 0; i < imports.length; i++) { @@ -47,8 +71,10 @@ export const prepareFromPgImports = async (imports: string[]) => { enums.push(...prepared.enums); schemas.push(...prepared.schemas); sequences.push(...prepared.sequences); + views.push(...prepared.views); + matViews.push(...prepared.matViews); } unregister(); - return { tables: Array.from(new Set(tables)), enums, schemas, sequences }; + return { tables: Array.from(new Set(tables)), enums, schemas, sequences, views, matViews }; }; diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index 5860a6fef..d4d27cb86 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -185,6 +185,11 @@ const column = object({ .optional(), }).strict(); +const checkConstraint = object({ + name: string(), + value: string(), +}).strict(); + const columnSquashed = object({ name: string(), type: string(), @@ -220,6 +225,48 @@ const uniqueConstraint = object({ nullsNotDistinct: boolean(), }).strict(); +const viewWithOption = object({ + checkOption: enumType(['local', 'cascaded']).optional(), + securityBarrier: boolean().optional(), + securityInvoker: boolean().optional(), +}).strict(); + +const matViewWithOption = object({ + fillfactor: number().optional(), + toastTupleTarget: number().optional(), + parallelWorkers: number().optional(), + autovacuumEnabled: boolean().optional(), + vacuumIndexCleanup: enumType(['auto', 'off', 'on']).optional(), + vacuumTruncate: boolean().optional(), + autovacuumVacuumThreshold: number().optional(), + autovacuumVacuumScaleFactor: number().optional(), + autovacuumVacuumCostDelay: number().optional(), + autovacuumVacuumCostLimit: number().optional(), + autovacuumFreezeMinAge: number().optional(), + autovacuumFreezeMaxAge: number().optional(), + autovacuumFreezeTableAge: number().optional(), + autovacuumMultixactFreezeMinAge: number().optional(), + autovacuumMultixactFreezeMaxAge: number().optional(), + autovacuumMultixactFreezeTableAge: number().optional(), + logAutovacuumMinDuration: number().optional(), + userCatalogTable: boolean().optional(), +}).strict(); + +export const mergedViewWithOption = viewWithOption.merge(matViewWithOption).strict(); + +export const view = object({ + name: string(), + schema: string(), + columns: record(string(), column), + definition: string().optional(), + materialized: boolean(), + with: mergedViewWithOption.optional(), + isExisting: boolean(), + withNoData: boolean().optional(), + using: string().optional(), + tablespace: string().optional(), +}).strict(); + const tableV4 = object({ name: string(), schema: string(), @@ -266,6 +313,7 @@ const table = object({ foreignKeys: record(string(), fk), compositePrimaryKeys: record(string(), compositePK), uniqueConstraints: record(string(), uniqueConstraint).default({}), + checkConstraints: record(string(), checkConstraint).default({}), }).strict(); const schemaHash = object({ @@ -368,6 +416,7 @@ export const pgSchemaInternal = object({ tables: record(string(), table), enums: record(string(), enumSchema), schemas: record(string(), string()), + views: record(string(), view).default({}), sequences: record(string(), sequenceSchema).default({}), _meta: object({ schemas: record(string(), string()), @@ -385,6 +434,7 @@ const tableSquashed = object({ foreignKeys: record(string(), string()), compositePrimaryKeys: record(string(), string()), uniqueConstraints: record(string(), string()), + checkConstraints: record(string(), string()), }).strict(); const tableSquashedV4 = object({ @@ -417,6 +467,7 @@ export const pgSchemaSquashed = object({ tables: record(string(), tableSquashed), enums: record(string(), enumSchema), schemas: record(string(), string()), + views: record(string(), view), sequences: record(string(), sequenceSquashed), }).strict(); @@ -445,7 +496,12 @@ export type Index = TypeOf; export type ForeignKey = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; +export type View = TypeOf; +export type MatViewWithOption = TypeOf; +export type ViewWithOption = TypeOf; + export type PgKitInternals = TypeOf; +export type CheckConstraint = TypeOf; export type PgSchemaV1 = TypeOf; export type PgSchemaV2 = TypeOf; @@ -627,6 +683,17 @@ export const PgSquasher = { cycle: splitted[7] === 'true', }; }, + squashCheck: (check: CheckConstraint) => { + return `${check.name};${check.value}`; + }, + unsquashCheck: (input: string): CheckConstraint => { + const [ + name, + value, + ] = input.split(';'); + + return { name, value }; + }, }; export const squashPgScheme = ( @@ -671,6 +738,13 @@ export const squashPgScheme = ( }, ); + const squashedChecksContraints = mapValues( + it[1].checkConstraints, + (check) => { + return PgSquasher.squashCheck(check); + }, + ); + return [ it[0], { @@ -681,6 +755,7 @@ export const squashPgScheme = ( foreignKeys: squashedFKs, compositePrimaryKeys: squashedPKs, uniqueConstraints: squashedUniqueConstraints, + checkConstraints: squashedChecksContraints, }, ]; }), @@ -705,6 +780,7 @@ export const squashPgScheme = ( tables: mappedTables, enums: json.enums, schemas: json.schemas, + views: json.views, sequences: mappedSequences, }; }; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index cc7b18725..3c54b01f4 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -4,14 +4,17 @@ import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; import { AnyPgTable, ExtraConfigColumn, + getMaterializedViewConfig, + getViewConfig, IndexedColumn, PgColumn, PgDialect, PgEnum, PgEnumColumn, - PgInteger, + PgMaterializedView, PgSchema, PgSequence, + PgView, uniqueKeyName, } from 'drizzle-orm/pg-core'; import { getTableConfig } from 'drizzle-orm/pg-core'; @@ -20,6 +23,7 @@ import { vectorOps } from 'src/extensions/vector'; import { withStyle } from '../cli/validations/outputs'; import type { IntrospectStage, IntrospectStatus } from '../cli/views'; import type { + CheckConstraint, Column as Column, Enum, ForeignKey, @@ -31,6 +35,7 @@ import type { Sequence, Table, UniqueConstraint, + View, } from '../serializer/pgSchema'; import { type DB, getColumnCasing, isPgArrayType } from '../utils'; import { sqlToStr } from '.'; @@ -39,30 +44,16 @@ export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; }; -function stringFromIdentityProperty( - field: string | number | undefined, -): string | undefined { - return typeof field === 'string' - ? (field as string) - : typeof field === 'undefined' - ? undefined - : String(field); +function stringFromIdentityProperty(field: string | number | undefined): string | undefined { + return typeof field === 'string' ? (field as string) : typeof field === 'undefined' ? undefined : String(field); } function maxRangeForIdentityBasedOn(columnType: string) { - return columnType === 'integer' - ? '2147483647' - : columnType === 'bigint' - ? '9223372036854775807' - : '32767'; + return columnType === 'integer' ? '2147483647' : columnType === 'bigint' ? '9223372036854775807' : '32767'; } function minRangeForIdentityBasedOn(columnType: string) { - return columnType === 'integer' - ? '-2147483648' - : columnType === 'bitint' - ? '-9223372036854775808' - : '-32768'; + return columnType === 'integer' ? '-2147483648' : columnType === 'bitint' ? '-9223372036854775808' : '-32768'; } function stringFromDatabaseIdentityProperty(field: any): string | undefined { @@ -89,20 +80,12 @@ function buildArrayString(array: any[], sqlType: string): string { if (sqlType === 'date') { return `"${value.toISOString().split('T')[0]}"`; } else if (sqlType === 'timestamp') { - return `"${ - value.toISOString() - .replace('T', ' ') - .slice(0, 23) - }"`; + return `"${value.toISOString().replace('T', ' ').slice(0, 23)}"`; } else { return `"${value.toISOString()}"`; } } else if (typeof value === 'object') { - return `"${ - JSON - .stringify(value) - .replaceAll('"', '\\"') - }"`; + return `"${JSON.stringify(value).replaceAll('"', '\\"')}"`; } return `"${value}"`; @@ -117,11 +100,14 @@ export const generatePgSnapshot = ( enums: PgEnum[], schemas: PgSchema[], sequences: PgSequence[], + views: PgView[], + matViews: PgMaterializedView[], casing: CasingType | undefined, schemaFilter?: string[], ): PgSchemaInternal => { const dialect = new PgDialect({ casing }); const result: Record = {}; + const resultViews: Record = {}; const sequencesToReturn: Record = {}; // This object stores unique names for indexes and will be used to detect if you have the same names for indexes @@ -129,16 +115,12 @@ export const generatePgSnapshot = ( const indexesInSchema: Record = {}; for (const table of tables) { - const { - name: tableName, - columns, - indexes, - foreignKeys, - checks, - schema, - primaryKeys, - uniqueConstraints, - } = getTableConfig(table); + // This object stores unique names for checks and will be used to detect if you have the same names for checks + // within the same PostgreSQL table + const checksInTable: Record = {}; + + const { name: tableName, columns, indexes, foreignKeys, checks, schema, primaryKeys, uniqueConstraints } = + getTableConfig(table); if (schemaFilter && !schemaFilter.includes(schema ?? 'public')) { continue; @@ -146,6 +128,7 @@ export const generatePgSnapshot = ( const columnsObject: Record = {}; const indexesObject: Record = {}; + const checksObject: Record = {}; const foreignKeysObject: Record = {}; const primaryKeysObject: Record = {}; const uniqueConstraintObject: Record = {}; @@ -156,21 +139,15 @@ export const generatePgSnapshot = ( const primaryKey: boolean = column.primary; const sqlTypeLowered = column.getSQLType().toLowerCase(); - const typeSchema = is(column, PgEnumColumn) - ? column.enum.schema || 'public' - : undefined; + const typeSchema = is(column, PgEnumColumn) ? column.enum.schema || 'public' : undefined; const generated = column.generated; const identity = column.generatedIdentity; const increment = stringFromIdentityProperty(identity?.sequenceOptions?.increment) ?? '1'; const minValue = stringFromIdentityProperty(identity?.sequenceOptions?.minValue) - ?? (parseFloat(increment) < 0 - ? minRangeForIdentityBasedOn(column.columnType) - : '1'); + ?? (parseFloat(increment) < 0 ? minRangeForIdentityBasedOn(column.columnType) : '1'); const maxValue = stringFromIdentityProperty(identity?.sequenceOptions?.maxValue) - ?? (parseFloat(increment) < 0 - ? '-1' - : maxRangeForIdentityBasedOn(column.getSQLType())); + ?? (parseFloat(increment) < 0 ? '-1' : maxRangeForIdentityBasedOn(column.getSQLType())); const startWith = stringFromIdentityProperty(identity?.sequenceOptions?.startWith) ?? (parseFloat(increment) < 0 ? maxValue : minValue); const cache = stringFromIdentityProperty(identity?.sequenceOptions?.cache) ?? '1'; @@ -224,7 +201,7 @@ export const generatePgSnapshot = ( chalk.underline.blue( name, ) - } column is confilcting with a unique constraint name already defined for ${ + } column is conflicting with a unique constraint name already defined for ${ chalk.underline.blue( existingUnique.columns.join(','), ) @@ -248,31 +225,17 @@ export const generatePgSnapshot = ( columnToSet.default = `'${column.default}'`; } else { if (sqlTypeLowered === 'jsonb' || sqlTypeLowered === 'json') { - columnToSet.default = `'${ - JSON.stringify( - column.default, - ) - }'::${sqlTypeLowered}`; + columnToSet.default = `'${JSON.stringify(column.default)}'::${sqlTypeLowered}`; } else if (column.default instanceof Date) { if (sqlTypeLowered === 'date') { columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; } else if (sqlTypeLowered === 'timestamp') { - columnToSet.default = `'${ - column.default - .toISOString() - .replace('T', ' ') - .slice(0, 23) - }'`; + columnToSet.default = `'${column.default.toISOString().replace('T', ' ').slice(0, 23)}'`; } else { columnToSet.default = `'${column.default.toISOString()}'`; } } else if (isPgArrayType(sqlTypeLowered) && Array.isArray(column.default)) { - columnToSet.default = `'${ - buildArrayString( - column.default, - sqlTypeLowered, - ) - }'`; + columnToSet.default = `'${buildArrayString(column.default, sqlTypeLowered)}'`; } else { // Should do for all types // columnToSet.default = `'${column.default}'::${sqlTypeLowered}`; @@ -310,24 +273,16 @@ export const generatePgSnapshot = ( if (typeof existingUnique !== 'undefined') { console.log( `\n${ - withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ - chalk.underline.blue( - tableName, - ) - } table. - The unique constraint ${ - chalk.underline.blue( - name, - ) - } on the ${ - chalk.underline.blue( - columnNames.join(','), - ) - } columns is confilcting with a unique constraint name already defined for ${ - chalk.underline.blue( - existingUnique.columns.join(','), - ) - } columns\n`) + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${chalk.underline.blue(tableName)} table. + The unique constraint ${chalk.underline.blue(name)} on the ${ + chalk.underline.blue( + columnNames.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue(existingUnique.columns.join(',')) + } columns\n`, + ) }`, ); process.exit(1); @@ -392,11 +347,7 @@ export const generatePgSnapshot = ( console.log( `\n${ withStyle.errorWarning( - `Please specify an index name in ${ - getTableName( - value.config.table, - ) - } table that has "${ + `Please specify an index name in ${getTableName(value.config.table)} table that has "${ dialect.sqlToQuery(it).sql }" expression. We can generate index names for indexes on columns only; for expressions in indexes, you need to specify the name yourself.`, ) @@ -430,9 +381,7 @@ export const generatePgSnapshot = ( } type without specifying an operator class. Vector extension doesn't have a default operator class, so you need to specify one of the available options. Here is a list of available op classes for the vector extension: [${ vectorOps .map((it) => `${chalk.underline(`${it}`)}`) - .join( - ', ', - ) + .join(', ') }].\n\nYou can specify it using current syntax: ${ chalk.underline( `index("${value.config.name}").using("${value.config.method}", table.${name}.op("${ @@ -448,9 +397,7 @@ export const generatePgSnapshot = ( indexColumnNames.push(name); }); - const name = value.config.name - ? value.config.name - : indexName(tableName, indexColumnNames); + const name = value.config.name ? value.config.name : indexName(tableName, indexColumnNames); let indexColumns: IndexColumnType[] = columns.map( (it): IndexColumnType => { @@ -485,9 +432,7 @@ export const generatePgSnapshot = ( `\n${ withStyle.errorWarning( `We\'ve found duplicated index name across ${ - chalk.underline.blue( - schema ?? 'public', - ) + chalk.underline.blue(schema ?? 'public') } schema. Please rename your index in either the ${ chalk.underline.blue( tableName, @@ -507,15 +452,50 @@ export const generatePgSnapshot = ( name, columns: indexColumns, isUnique: value.config.unique ?? false, - where: value.config.where - ? dialect.sqlToQuery(value.config.where).sql - : undefined, + where: value.config.where ? dialect.sqlToQuery(value.config.where).sql : undefined, concurrently: value.config.concurrently ?? false, method: value.config.method ?? 'btree', with: value.config.with ?? {}, }; }); + checks.forEach((check) => { + const checkName = check.name; + + if (typeof checksInTable[`"${schema ?? 'public'}"."${tableName}"`] !== 'undefined') { + if (checksInTable[`"${schema ?? 'public'}"."${tableName}"`].includes(check.name)) { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated check constraint name across ${ + chalk.underline.blue( + schema ?? 'public', + ) + } schema in ${ + chalk.underline.blue( + tableName, + ) + }. Please rename your check constraint in either the ${ + chalk.underline.blue( + tableName, + ) + } table or the table with the duplicated check contraint name`, + ) + }`, + ); + process.exit(1); + } + checksInTable[`"${schema ?? 'public'}"."${tableName}"`].push(checkName); + } else { + checksInTable[`"${schema ?? 'public'}"."${tableName}"`] = [check.name]; + } + + checksObject[checkName] = { + name: checkName, + value: dialect.sqlToQuery(check.value).sql, + }; + }); + const tableKey = `${schema ?? 'public'}.${tableName}`; result[tableKey] = { @@ -526,15 +506,13 @@ export const generatePgSnapshot = ( foreignKeys: foreignKeysObject, compositePrimaryKeys: primaryKeysObject, uniqueConstraints: uniqueConstraintObject, + checkConstraints: checksObject, }; } for (const sequence of sequences) { const name = sequence.seqName!; - if ( - typeof sequencesToReturn[`${sequence.schema ?? 'public'}.${name}`] - === 'undefined' - ) { + if (typeof sequencesToReturn[`${sequence.schema ?? 'public'}.${name}`] === 'undefined') { const increment = stringFromIdentityProperty(sequence?.seqOptions?.increment) ?? '1'; const minValue = stringFromIdentityProperty(sequence?.seqOptions?.minValue) ?? (parseFloat(increment) < 0 ? '-9223372036854775808' : '1'); @@ -559,6 +537,172 @@ export const generatePgSnapshot = ( } } + const combinedViews = [...views, ...matViews]; + for (const view of combinedViews) { + let viewName; + let schema; + let query; + let selectedFields; + let isExisting; + let withOption; + let tablespace; + let using; + let withNoData; + let materialized: boolean = false; + + if (is(view, PgView)) { + ({ name: viewName, schema, query, selectedFields, isExisting, with: withOption } = getViewConfig(view)); + } else { + ({ name: viewName, schema, query, selectedFields, isExisting, with: withOption, tablespace, using, withNoData } = + getMaterializedViewConfig(view)); + + materialized = true; + } + + const viewSchema = schema ?? 'public'; + + const viewKey = `${viewSchema}.${viewName}`; + + const columnsObject: Record = {}; + const uniqueConstraintObject: Record = {}; + + const existingView = resultViews[viewKey]; + if (typeof existingView !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated view name across ${ + chalk.underline.blue(schema ?? 'public') + } schema. Please rename your view`, + ) + }`, + ); + process.exit(1); + } + + for (const key in selectedFields) { + if (is(selectedFields[key], PgColumn)) { + const column = selectedFields[key]; + + const notNull: boolean = column.notNull; + const primaryKey: boolean = column.primary; + const sqlTypeLowered = column.getSQLType().toLowerCase(); + + const typeSchema = is(column, PgEnumColumn) ? column.enum.schema || 'public' : undefined; + const generated = column.generated; + const identity = column.generatedIdentity; + + const increment = stringFromIdentityProperty(identity?.sequenceOptions?.increment) ?? '1'; + const minValue = stringFromIdentityProperty(identity?.sequenceOptions?.minValue) + ?? (parseFloat(increment) < 0 ? minRangeForIdentityBasedOn(column.columnType) : '1'); + const maxValue = stringFromIdentityProperty(identity?.sequenceOptions?.maxValue) + ?? (parseFloat(increment) < 0 ? '-1' : maxRangeForIdentityBasedOn(column.getSQLType())); + const startWith = stringFromIdentityProperty(identity?.sequenceOptions?.startWith) + ?? (parseFloat(increment) < 0 ? maxValue : minValue); + const cache = stringFromIdentityProperty(identity?.sequenceOptions?.cache) ?? '1'; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + typeSchema: typeSchema, + primaryKey, + notNull, + generated: generated + ? { + as: is(generated.as, SQL) + ? dialect.sqlToQuery(generated.as as SQL).sql + : typeof generated.as === 'function' + ? dialect.sqlToQuery(generated.as() as SQL).sql + : (generated.as as any), + type: 'stored', + } + : undefined, + identity: identity + ? { + type: identity.type, + name: identity.sequenceName ?? `${viewName}_${column.name}_seq`, + schema: schema ?? 'public', + increment, + startWith, + minValue, + maxValue, + cache, + cycle: identity?.sequenceOptions?.cycle ?? false, + } + : undefined, + }; + + if (column.isUnique) { + const existingUnique = uniqueConstraintObject[column.uniqueName!]; + if (typeof existingUnique !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${chalk.underline.blue(viewName)} table. + The unique constraint ${chalk.underline.blue(column.uniqueName)} on the ${ + chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue(existingUnique.columns.join(',')) + } columns\n`, + ) + }`, + ); + process.exit(1); + } + uniqueConstraintObject[column.uniqueName!] = { + name: column.uniqueName!, + nullsNotDistinct: column.uniqueType === 'not distinct', + columns: [columnToSet.name], + }; + } + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default, casing); + } else { + if (typeof column.default === 'string') { + columnToSet.default = `'${column.default}'`; + } else { + if (sqlTypeLowered === 'jsonb' || sqlTypeLowered === 'json') { + columnToSet.default = `'${JSON.stringify(column.default)}'::${sqlTypeLowered}`; + } else if (column.default instanceof Date) { + if (sqlTypeLowered === 'date') { + columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; + } else if (sqlTypeLowered === 'timestamp') { + columnToSet.default = `'${column.default.toISOString().replace('T', ' ').slice(0, 23)}'`; + } else { + columnToSet.default = `'${column.default.toISOString()}'`; + } + } else if (isPgArrayType(sqlTypeLowered) && Array.isArray(column.default)) { + columnToSet.default = `'${buildArrayString(column.default, sqlTypeLowered)}'`; + } else { + // Should do for all types + // columnToSet.default = `'${column.default}'::${sqlTypeLowered}`; + columnToSet.default = column.default; + } + } + } + } + columnsObject[column.name] = columnToSet; + } + } + + resultViews[viewKey] = { + columns: columnsObject, + definition: isExisting ? undefined : dialect.sqlToQuery(query!).sql, + name: viewName, + schema: viewSchema, + isExisting, + with: withOption, + withNoData, + materialized, + tablespace, + using, + }; + } + const enumsToReturn: Record = enums.reduce<{ [key: string]: Enum; }>((map, obj) => { @@ -576,9 +720,7 @@ export const generatePgSnapshot = ( schemas .filter((it) => { if (schemaFilter) { - return ( - schemaFilter.includes(it.schemaName) && it.schemaName !== 'public' - ); + return schemaFilter.includes(it.schemaName) && it.schemaName !== 'public'; } else { return it.schemaName !== 'public'; } @@ -593,6 +735,7 @@ export const generatePgSnapshot = ( enums: enumsToReturn, schemas: schemasObject, sequences: sequencesToReturn, + views: resultViews, _meta: { schemas: {}, tables: {}, @@ -609,28 +752,37 @@ const trimChar = (str: string, char: string) => { while (end > start && str[end - 1] === char) --end; // this.toString() due to ava deep equal issue with String { "value" } - return start > 0 || end < str.length - ? str.substring(start, end) - : str.toString(); + return start > 0 || end < str.length ? str.substring(start, end) : str.toString(); }; export const fromDatabase = async ( db: DB, tablesFilter: (table: string) => boolean = () => true, schemaFilters: string[], - progressCallback?: ( - stage: IntrospectStage, - count: number, - status: IntrospectStatus, - ) => void, + progressCallback?: (stage: IntrospectStage, count: number, status: IntrospectStatus) => void, ): Promise => { const result: Record = {}; + const views: Record = {}; const internals: PgKitInternals = { tables: {} }; - const where = schemaFilters.map((t) => `table_schema = '${t}'`).join(' or '); - - const allTables = await db.query( - `SELECT table_schema, table_name FROM information_schema.tables${where === '' ? '' : ` WHERE ${where}`};`, + const where = schemaFilters.map((t) => `n.nspname = '${t}'`).join(' or '); + + const allTables = await db.query<{ table_schema: string; table_name: string; type: string }>( + `SELECT + n.nspname AS table_schema, + c.relname AS table_name, + CASE + WHEN c.relkind = 'r' THEN 'table' + WHEN c.relkind = 'v' THEN 'view' + WHEN c.relkind = 'm' THEN 'materialized_view' + END AS type +FROM + pg_catalog.pg_class c +JOIN + pg_catalog.pg_namespace n ON n.oid = c.relnamespace +WHERE + c.relkind IN ('r', 'v', 'm') + ${where === '' ? '' : ` AND ${where}`};`, ); const schemas = new Set(allTables.map((it) => it.table_schema)); @@ -656,6 +808,8 @@ export const fromDatabase = async ( let indexesCount = 0; let foreignKeysCount = 0; let tableCount = 0; + let checksCount = 0; + let viewsCount = 0; const sequencesToReturn: Record = {}; @@ -690,9 +844,7 @@ export const fromDatabase = async ( }; } - const whereEnums = schemaFilters - .map((t) => `n.nspname = '${t}'`) - .join(' or '); + const whereEnums = schemaFilters.map((t) => `n.nspname = '${t}'`).join(' or '); const allEnums = await db.query( `select n.nspname as enum_schema, @@ -730,73 +882,64 @@ export const fromDatabase = async ( const sequencesInColumns: string[] = []; - const all = allTables.map((row) => { - return new Promise(async (res, rej) => { - const tableName = row.table_name as string; - if (!tablesFilter(tableName)) return res(''); - tableCount += 1; - const tableSchema = row.table_schema; - - try { - const columnToReturn: Record = {}; - const indexToReturn: Record = {}; - const foreignKeysToReturn: Record = {}; - const primaryKeys: Record = {}; - const uniqueConstrains: Record = {}; - - const tableResponse = await db.query( - `SELECT a.attrelid::regclass::text, a.attname, is_nullable, a.attndims as array_dimensions - , CASE WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[]) - AND EXISTS ( - SELECT FROM pg_attrdef ad - WHERE ad.adrelid = a.attrelid - AND ad.adnum = a.attnum - AND pg_get_expr(ad.adbin, ad.adrelid) - = 'nextval(''' - || (pg_get_serial_sequence (a.attrelid::regclass::text - , a.attname))::regclass - || '''::regclass)' - ) - THEN CASE a.atttypid - WHEN 'int'::regtype THEN 'serial' - WHEN 'int8'::regtype THEN 'bigserial' - WHEN 'int2'::regtype THEN 'smallserial' - END - ELSE format_type(a.atttypid, a.atttypmod) - END AS data_type, INFORMATION_SCHEMA.COLUMNS.table_name, ns.nspname as type_schema, - pg_get_serial_sequence('"${tableSchema}"."${tableName}"', a.attname)::regclass as seq_name, INFORMATION_SCHEMA.COLUMNS.column_name, - INFORMATION_SCHEMA.COLUMNS.column_default, INFORMATION_SCHEMA.COLUMNS.data_type as additional_dt, - INFORMATION_SCHEMA.COLUMNS.udt_name as enum_name, - INFORMATION_SCHEMA.COLUMNS.is_generated, generation_expression, - INFORMATION_SCHEMA.COLUMNS.is_identity,INFORMATION_SCHEMA.COLUMNS.identity_generation, - INFORMATION_SCHEMA.COLUMNS.identity_start, INFORMATION_SCHEMA.COLUMNS.identity_increment, - INFORMATION_SCHEMA.COLUMNS.identity_maximum, INFORMATION_SCHEMA.COLUMNS.identity_minimum, - INFORMATION_SCHEMA.COLUMNS.identity_cycle - FROM pg_attribute a - JOIN INFORMATION_SCHEMA.COLUMNS ON INFORMATION_SCHEMA.COLUMNS.column_name = a.attname - JOIN pg_type t ON t.oid = a.atttypid LEFT JOIN pg_namespace ns ON ns.oid = t.typnamespace - WHERE a.attrelid = '"${tableSchema}"."${tableName}"'::regclass and INFORMATION_SCHEMA.COLUMNS.table_name = '${tableName}' and INFORMATION_SCHEMA.COLUMNS.table_schema = '${tableSchema}' - AND a.attnum > 0 - AND NOT a.attisdropped - ORDER BY a.attnum;`, - ); - - const tableConstraints = await db.query( - `SELECT c.column_name, c.data_type, constraint_type, constraint_name, constraint_schema + const all = allTables + .filter((it) => it.type === 'table') + .map((row) => { + return new Promise(async (res, rej) => { + const tableName = row.table_name as string; + if (!tablesFilter(tableName)) return res(''); + tableCount += 1; + const tableSchema = row.table_schema; + + try { + const columnToReturn: Record = {}; + const indexToReturn: Record = {}; + const foreignKeysToReturn: Record = {}; + const primaryKeys: Record = {}; + const uniqueConstrains: Record = {}; + const checkConstraints: Record = {}; + + const tableResponse = await getColumnsInfoQuery({ schema: tableSchema, table: tableName, db }); + + const tableConstraints = await db.query( + `SELECT c.column_name, c.data_type, constraint_type, constraint_name, constraint_schema FROM information_schema.table_constraints tc JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name) JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema AND tc.table_name = c.table_name AND ccu.column_name = c.column_name WHERE tc.table_name = '${tableName}' and constraint_schema = '${tableSchema}';`, - ); + ); - columnsCount += tableResponse.length; - if (progressCallback) { - progressCallback('columns', columnsCount, 'fetching'); - } + const tableChecks = await db.query(`SELECT + tc.constraint_name, + tc.constraint_type, + pg_get_constraintdef(con.oid) AS constraint_definition + FROM + information_schema.table_constraints AS tc + JOIN pg_constraint AS con + ON tc.constraint_name = con.conname + AND con.conrelid = ( + SELECT oid + FROM pg_class + WHERE relname = tc.table_name + AND relnamespace = ( + SELECT oid + FROM pg_namespace + WHERE nspname = tc.constraint_schema + ) + ) + WHERE + tc.table_name = '${tableName}' + AND tc.constraint_schema = '${tableSchema}' + AND tc.constraint_type = 'CHECK';`); + + columnsCount += tableResponse.length; + if (progressCallback) { + progressCallback('columns', columnsCount, 'fetching'); + } - const tableForeignKeys = await db.query( - `SELECT + const tableForeignKeys = await db.query( + `SELECT con.contype AS constraint_type, nsp.nspname AS constraint_schema, con.conname AS constraint_name, @@ -833,254 +976,244 @@ export const fromDatabase = async ( nsp.nspname = '${tableSchema}' AND rel.relname = '${tableName}' AND con.contype IN ('f');`, - ); + ); - foreignKeysCount += tableForeignKeys.length; - if (progressCallback) { - progressCallback('fks', foreignKeysCount, 'fetching'); - } - for (const fk of tableForeignKeys) { - // const tableFrom = fk.table_name; - const columnFrom: string = fk.column_name; - const tableTo = fk.foreign_table_name; - const columnTo: string = fk.foreign_column_name; - const schemaTo: string = fk.foreign_table_schema; - const foreignKeyName = fk.constraint_name; - const onUpdate = fk.update_rule?.toLowerCase(); - const onDelete = fk.delete_rule?.toLowerCase(); - - if (typeof foreignKeysToReturn[foreignKeyName] !== 'undefined') { - foreignKeysToReturn[foreignKeyName].columnsFrom.push(columnFrom); - foreignKeysToReturn[foreignKeyName].columnsTo.push(columnTo); - } else { - foreignKeysToReturn[foreignKeyName] = { - name: foreignKeyName, - tableFrom: tableName, - tableTo, - schemaTo, - columnsFrom: [columnFrom], - columnsTo: [columnTo], - onDelete, - onUpdate, - }; + foreignKeysCount += tableForeignKeys.length; + if (progressCallback) { + progressCallback('fks', foreignKeysCount, 'fetching'); } + for (const fk of tableForeignKeys) { + // const tableFrom = fk.table_name; + const columnFrom: string = fk.column_name; + const tableTo = fk.foreign_table_name; + const columnTo: string = fk.foreign_column_name; + const schemaTo: string = fk.foreign_table_schema; + const foreignKeyName = fk.constraint_name; + const onUpdate = fk.update_rule?.toLowerCase(); + const onDelete = fk.delete_rule?.toLowerCase(); + + if (typeof foreignKeysToReturn[foreignKeyName] !== 'undefined') { + foreignKeysToReturn[foreignKeyName].columnsFrom.push(columnFrom); + foreignKeysToReturn[foreignKeyName].columnsTo.push(columnTo); + } else { + foreignKeysToReturn[foreignKeyName] = { + name: foreignKeyName, + tableFrom: tableName, + tableTo, + schemaTo, + columnsFrom: [columnFrom], + columnsTo: [columnTo], + onDelete, + onUpdate, + }; + } - foreignKeysToReturn[foreignKeyName].columnsFrom = [ - ...new Set(foreignKeysToReturn[foreignKeyName].columnsFrom), - ]; + foreignKeysToReturn[foreignKeyName].columnsFrom = [ + ...new Set(foreignKeysToReturn[foreignKeyName].columnsFrom), + ]; - foreignKeysToReturn[foreignKeyName].columnsTo = [ - ...new Set(foreignKeysToReturn[foreignKeyName].columnsTo), - ]; - } + foreignKeysToReturn[foreignKeyName].columnsTo = [...new Set(foreignKeysToReturn[foreignKeyName].columnsTo)]; + } - const uniqueConstrainsRows = tableConstraints.filter( - (mapRow) => mapRow.constraint_type === 'UNIQUE', - ); + const uniqueConstrainsRows = tableConstraints.filter((mapRow) => mapRow.constraint_type === 'UNIQUE'); - for (const unqs of uniqueConstrainsRows) { - // const tableFrom = fk.table_name; - const columnName: string = unqs.column_name; - const constraintName: string = unqs.constraint_name; + for (const unqs of uniqueConstrainsRows) { + // const tableFrom = fk.table_name; + const columnName: string = unqs.column_name; + const constraintName: string = unqs.constraint_name; - if (typeof uniqueConstrains[constraintName] !== 'undefined') { - uniqueConstrains[constraintName].columns.push(columnName); - } else { - uniqueConstrains[constraintName] = { - columns: [columnName], - nullsNotDistinct: false, + if (typeof uniqueConstrains[constraintName] !== 'undefined') { + uniqueConstrains[constraintName].columns.push(columnName); + } else { + uniqueConstrains[constraintName] = { + columns: [columnName], + nullsNotDistinct: false, + name: constraintName, + }; + } + } + + checksCount += tableChecks.length; + if (progressCallback) { + progressCallback('checks', checksCount, 'fetching'); + } + for (const checks of tableChecks) { + // CHECK (((email)::text <> 'test@gmail.com'::text)) + // Where (email) is column in table + let checkValue: string = checks.constraint_definition; + const constraintName: string = checks.constraint_name; + + checkValue = checkValue.replace(/^CHECK\s*\(\(/, '').replace(/\)\)\s*$/, ''); + + checkConstraints[constraintName] = { name: constraintName, + value: checkValue, }; } - } - for (const columnResponse of tableResponse) { - const columnName = columnResponse.attname; - const columnAdditionalDT = columnResponse.additional_dt; - const columnDimensions = columnResponse.array_dimensions; - const enumType: string = columnResponse.enum_name; - let columnType: string = columnResponse.data_type; - const typeSchema = columnResponse.type_schema; - const defaultValueRes: string = columnResponse.column_default; - - const isGenerated = columnResponse.is_generated === 'ALWAYS'; - const generationExpression = columnResponse.generation_expression; - const isIdentity = columnResponse.is_identity === 'YES'; - const identityGeneration = columnResponse.identity_generation === 'ALWAYS' - ? 'always' - : 'byDefault'; - const identityStart = columnResponse.identity_start; - const identityIncrement = columnResponse.identity_increment; - const identityMaximum = columnResponse.identity_maximum; - const identityMinimum = columnResponse.identity_minimum; - const identityCycle = columnResponse.identity_cycle === 'YES'; - const identityName = columnResponse.seq_name; - - const primaryKey = tableConstraints.filter( - (mapRow) => - columnName === mapRow.column_name - && mapRow.constraint_type === 'PRIMARY KEY', - ); + for (const columnResponse of tableResponse) { + const columnName = columnResponse.column_name; + const columnAdditionalDT = columnResponse.additional_dt; + const columnDimensions = columnResponse.array_dimensions; + const enumType: string = columnResponse.enum_name; + let columnType: string = columnResponse.data_type; + const typeSchema = columnResponse.type_schema; + const defaultValueRes: string = columnResponse.column_default; + + const isGenerated = columnResponse.is_generated === 'ALWAYS'; + const generationExpression = columnResponse.generation_expression; + const isIdentity = columnResponse.is_identity === 'YES'; + const identityGeneration = columnResponse.identity_generation === 'ALWAYS' ? 'always' : 'byDefault'; + const identityStart = columnResponse.identity_start; + const identityIncrement = columnResponse.identity_increment; + const identityMaximum = columnResponse.identity_maximum; + const identityMinimum = columnResponse.identity_minimum; + const identityCycle = columnResponse.identity_cycle === 'YES'; + const identityName = columnResponse.seq_name; + + const primaryKey = tableConstraints.filter((mapRow) => + columnName === mapRow.column_name && mapRow.constraint_type === 'PRIMARY KEY' + ); - const cprimaryKey = tableConstraints.filter( - (mapRow) => mapRow.constraint_type === 'PRIMARY KEY', - ); + const cprimaryKey = tableConstraints.filter((mapRow) => mapRow.constraint_type === 'PRIMARY KEY'); - if (cprimaryKey.length > 1) { - const tableCompositePkName = await db.query( - `SELECT conname AS primary_key + if (cprimaryKey.length > 1) { + const tableCompositePkName = await db.query( + `SELECT conname AS primary_key FROM pg_constraint join pg_class on (pg_class.oid = conrelid) WHERE contype = 'p' AND connamespace = $1::regnamespace AND pg_class.relname = $2;`, - [tableSchema, tableName], - ); - primaryKeys[tableCompositePkName[0].primary_key] = { - name: tableCompositePkName[0].primary_key, - columns: cprimaryKey.map((c: any) => c.column_name), - }; - } - - let columnTypeMapped = columnType; + [tableSchema, tableName], + ); + primaryKeys[tableCompositePkName[0].primary_key] = { + name: tableCompositePkName[0].primary_key, + columns: cprimaryKey.map((c: any) => c.column_name), + }; + } - // Set default to internal object - if (columnAdditionalDT === 'ARRAY') { - if (typeof internals.tables[tableName] === 'undefined') { - internals.tables[tableName] = { - columns: { - [columnName]: { - isArray: true, - dimensions: columnDimensions, - rawType: columnTypeMapped.substring( - 0, - columnTypeMapped.length - 2, - ), + let columnTypeMapped = columnType; + + // Set default to internal object + if (columnAdditionalDT === 'ARRAY') { + if (typeof internals.tables[tableName] === 'undefined') { + internals.tables[tableName] = { + columns: { + [columnName]: { + isArray: true, + dimensions: columnDimensions, + rawType: columnTypeMapped.substring(0, columnTypeMapped.length - 2), + }, }, - }, - }; - } else { - if ( - typeof internals.tables[tableName]!.columns[columnName] - === 'undefined' - ) { - internals.tables[tableName]!.columns[columnName] = { - isArray: true, - dimensions: columnDimensions, - rawType: columnTypeMapped.substring( - 0, - columnTypeMapped.length - 2, - ), }; + } else { + if (typeof internals.tables[tableName]!.columns[columnName] === 'undefined') { + internals.tables[tableName]!.columns[columnName] = { + isArray: true, + dimensions: columnDimensions, + rawType: columnTypeMapped.substring(0, columnTypeMapped.length - 2), + }; + } } } - } - const defaultValue = defaultForColumn( - columnResponse, - internals, - tableName, - ); - if ( - defaultValue === 'NULL' - || (defaultValueRes && defaultValueRes.startsWith('(') && defaultValueRes.endsWith(')')) - ) { - if (typeof internals!.tables![tableName] === 'undefined') { - internals!.tables![tableName] = { - columns: { - [columnName]: { - isDefaultAnExpression: true, + const defaultValue = defaultForColumn(columnResponse, internals, tableName); + if ( + defaultValue === 'NULL' + || (defaultValueRes && defaultValueRes.startsWith('(') && defaultValueRes.endsWith(')')) + ) { + if (typeof internals!.tables![tableName] === 'undefined') { + internals!.tables![tableName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, }, - }, - }; - } else { - if ( - typeof internals!.tables![tableName]!.columns[columnName] - === 'undefined' - ) { - internals!.tables![tableName]!.columns[columnName] = { - isDefaultAnExpression: true, }; } else { - internals!.tables![tableName]!.columns[ - columnName - ]!.isDefaultAnExpression = true; + if (typeof internals!.tables![tableName]!.columns[columnName] === 'undefined') { + internals!.tables![tableName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![tableName]!.columns[columnName]!.isDefaultAnExpression = true; + } } } - } - const isSerial = columnType === 'serial'; - - if (columnTypeMapped.startsWith('numeric(')) { - columnTypeMapped = columnTypeMapped.replace(',', ', '); - } + const isSerial = columnType === 'serial'; - if (columnAdditionalDT === 'ARRAY') { - for (let i = 1; i < Number(columnDimensions); i++) { - columnTypeMapped += '[]'; + if (columnTypeMapped.startsWith('numeric(')) { + columnTypeMapped = columnTypeMapped.replace(',', ', '); } - } - columnTypeMapped = columnTypeMapped - .replace('character varying', 'varchar') - .replace(' without time zone', '') - // .replace("timestamp without time zone", "timestamp") - .replace('character', 'char'); - - columnTypeMapped = trimChar(columnTypeMapped, '"'); - - columnToReturn[columnName] = { - name: columnName, - type: - // filter vectors, but in future we should filter any extension that was installed by user - columnAdditionalDT === 'USER-DEFINED' - && !['vector', 'geometry'].includes(enumType) - ? enumType - : columnTypeMapped, - typeSchema: enumsToReturn[`${typeSchema}.${enumType}`] !== undefined - ? enumsToReturn[`${typeSchema}.${enumType}`].schema - : undefined, - primaryKey: primaryKey.length === 1 && cprimaryKey.length < 2, - // default: isSerial ? undefined : defaultValue, - notNull: columnResponse.is_nullable === 'NO', - generated: isGenerated - ? { as: generationExpression, type: 'stored' } - : undefined, - identity: isIdentity - ? { - type: identityGeneration, - name: identityName, - increment: stringFromDatabaseIdentityProperty(identityIncrement), - minValue: stringFromDatabaseIdentityProperty(identityMinimum), - maxValue: stringFromDatabaseIdentityProperty(identityMaximum), - startWith: stringFromDatabaseIdentityProperty(identityStart), - cache: sequencesToReturn[identityName]?.cache - ? sequencesToReturn[identityName]?.cache - : sequencesToReturn[`${tableSchema}.${identityName}`]?.cache - ? sequencesToReturn[`${tableSchema}.${identityName}`]?.cache - : undefined, - cycle: identityCycle, - schema: tableSchema, + if (columnAdditionalDT === 'ARRAY') { + for (let i = 1; i < Number(columnDimensions); i++) { + columnTypeMapped += '[]'; } - : undefined, - }; + } - if (identityName && typeof identityName === 'string') { - // remove "" from sequence name - delete sequencesToReturn[ - `${tableSchema}.${ - identityName.startsWith('"') && identityName.endsWith('"') ? identityName.slice(1, -1) : identityName - }` - ]; - delete sequencesToReturn[identityName]; - } + columnTypeMapped = columnTypeMapped + .replace('character varying', 'varchar') + .replace(' without time zone', '') + // .replace("timestamp without time zone", "timestamp") + .replace('character', 'char'); + + columnTypeMapped = trimChar(columnTypeMapped, '"'); + + columnToReturn[columnName] = { + name: columnName, + type: + // filter vectors, but in future we should filter any extension that was installed by user + columnAdditionalDT === 'USER-DEFINED' + && !['vector', 'geometry'].includes(enumType) + ? enumType + : columnTypeMapped, + typeSchema: enumsToReturn[`${typeSchema}.${enumType}`] !== undefined + ? enumsToReturn[`${typeSchema}.${enumType}`].schema + : undefined, + primaryKey: primaryKey.length === 1 && cprimaryKey.length < 2, + // default: isSerial ? undefined : defaultValue, + notNull: columnResponse.is_nullable === 'NO', + generated: isGenerated + ? { as: generationExpression, type: 'stored' } + : undefined, + identity: isIdentity + ? { + type: identityGeneration, + name: identityName, + increment: stringFromDatabaseIdentityProperty(identityIncrement), + minValue: stringFromDatabaseIdentityProperty(identityMinimum), + maxValue: stringFromDatabaseIdentityProperty(identityMaximum), + startWith: stringFromDatabaseIdentityProperty(identityStart), + cache: sequencesToReturn[identityName]?.cache + ? sequencesToReturn[identityName]?.cache + : sequencesToReturn[`${tableSchema}.${identityName}`]?.cache + ? sequencesToReturn[`${tableSchema}.${identityName}`]?.cache + : undefined, + cycle: identityCycle, + schema: tableSchema, + } + : undefined, + }; - if (!isSerial && typeof defaultValue !== 'undefined') { - columnToReturn[columnName].default = defaultValue; + if (identityName && typeof identityName === 'string') { + // remove "" from sequence name + delete sequencesToReturn[ + `${tableSchema}.${ + identityName.startsWith('"') && identityName.endsWith('"') ? identityName.slice(1, -1) : identityName + }` + ]; + delete sequencesToReturn[identityName]; + } + + if (!isSerial && typeof defaultValue !== 'undefined') { + columnToReturn[columnName].default = defaultValue; + } } - } - const dbIndexes = await db.query( - `SELECT DISTINCT ON (t.relname, ic.relname, k.i) t.relname as table_name, ic.relname AS indexname, + const dbIndexes = await db.query( + `SELECT DISTINCT ON (t.relname, ic.relname, k.i) t.relname as table_name, ic.relname AS indexname, k.i AS index_order, i.indisunique as is_unique, am.amname as method, @@ -1116,10 +1249,10 @@ export const fromDatabase = async ( WHERE c.nspname = '${tableSchema}' AND t.relname = '${tableName}';`, - ); + ); - const dbIndexFromConstraint = await db.query( - `SELECT + const dbIndexFromConstraint = await db.query( + `SELECT idx.indexrelname AS index_name, idx.relname AS table_name, schemaname, @@ -1130,89 +1263,90 @@ export const fromDatabase = async ( pg_constraint con ON con.conindid = idx.indexrelid WHERE idx.relname = '${tableName}' and schemaname = '${tableSchema}' group by index_name, table_name,schemaname, generated_by_constraint;`, - ); + ); - const idxsInConsteraint = dbIndexFromConstraint - .filter((it) => it.generated_by_constraint === 1) - .map((it) => it.index_name); - - for (const dbIndex of dbIndexes) { - const indexName: string = dbIndex.indexname; - const indexColumnName: string = dbIndex.column_name; - const indexIsUnique = dbIndex.is_unique; - const indexMethod = dbIndex.method; - const indexWith: string[] = dbIndex.with; - const indexWhere: string = dbIndex.where; - const opclass: string = dbIndex.opcname; - const isExpression = dbIndex.is_expression === 1; - - const desc: boolean = dbIndex.descending; - const nullsFirst: boolean = dbIndex.nulls_first; - - const mappedWith: Record = {}; - - if (indexWith !== null) { - indexWith - // .slice(1, indexWith.length - 1) - // .split(",") - .forEach((it) => { - const splitted = it.split('='); - mappedWith[splitted[0]] = splitted[1]; - }); - } + const idxsInConsteraint = dbIndexFromConstraint.filter((it) => it.generated_by_constraint === 1).map((it) => + it.index_name + ); - if (idxsInConsteraint.includes(indexName)) continue; + for (const dbIndex of dbIndexes) { + const indexName: string = dbIndex.indexname; + const indexColumnName: string = dbIndex.column_name; + const indexIsUnique = dbIndex.is_unique; + const indexMethod = dbIndex.method; + const indexWith: string[] = dbIndex.with; + const indexWhere: string = dbIndex.where; + const opclass: string = dbIndex.opcname; + const isExpression = dbIndex.is_expression === 1; + + const desc: boolean = dbIndex.descending; + const nullsFirst: boolean = dbIndex.nulls_first; + + const mappedWith: Record = {}; + + if (indexWith !== null) { + indexWith + // .slice(1, indexWith.length - 1) + // .split(",") + .forEach((it) => { + const splitted = it.split('='); + mappedWith[splitted[0]] = splitted[1]; + }); + } - if (typeof indexToReturn[indexName] !== 'undefined') { - indexToReturn[indexName].columns.push({ - expression: indexColumnName, - asc: !desc, - nulls: nullsFirst ? 'first' : 'last', - opclass, - isExpression, - }); - } else { - indexToReturn[indexName] = { - name: indexName, - columns: [ - { - expression: indexColumnName, - asc: !desc, - nulls: nullsFirst ? 'first' : 'last', - opclass, - isExpression, - }, - ], - isUnique: indexIsUnique, - // should not be a part of diff detecs - concurrently: false, - method: indexMethod, - where: indexWhere === null ? undefined : indexWhere, - with: mappedWith, - }; + if (idxsInConsteraint.includes(indexName)) continue; + + if (typeof indexToReturn[indexName] !== 'undefined') { + indexToReturn[indexName].columns.push({ + expression: indexColumnName, + asc: !desc, + nulls: nullsFirst ? 'first' : 'last', + opclass, + isExpression, + }); + } else { + indexToReturn[indexName] = { + name: indexName, + columns: [ + { + expression: indexColumnName, + asc: !desc, + nulls: nullsFirst ? 'first' : 'last', + opclass, + isExpression, + }, + ], + isUnique: indexIsUnique, + // should not be a part of diff detecs + concurrently: false, + method: indexMethod, + where: indexWhere === null ? undefined : indexWhere, + with: mappedWith, + }; + } } - } - indexesCount += Object.keys(indexToReturn).length; - if (progressCallback) { - progressCallback('indexes', indexesCount, 'fetching'); + indexesCount += Object.keys(indexToReturn).length; + if (progressCallback) { + progressCallback('indexes', indexesCount, 'fetching'); + } + result[`${tableSchema}.${tableName}`] = { + name: tableName, + schema: tableSchema !== 'public' ? tableSchema : '', + columns: columnToReturn, + indexes: indexToReturn, + foreignKeys: foreignKeysToReturn, + compositePrimaryKeys: primaryKeys, + uniqueConstraints: uniqueConstrains, + checkConstraints: checkConstraints, + }; + } catch (e) { + rej(e); + return; } - result[`${tableSchema}.${tableName}`] = { - name: tableName, - schema: tableSchema !== 'public' ? tableSchema : '', - columns: columnToReturn, - indexes: indexToReturn, - foreignKeys: foreignKeysToReturn, - compositePrimaryKeys: primaryKeys, - uniqueConstraints: uniqueConstrains, - }; - } catch (e) { - rej(e); - return; - } - res(''); + res(''); + }); }); - }); if (progressCallback) { progressCallback('tables', tableCount, 'done'); @@ -1221,10 +1355,241 @@ export const fromDatabase = async ( for await (const _ of all) { } + const allViews = allTables + .filter((it) => it.type === 'view' || it.type === 'materialized_view') + .map((row) => { + return new Promise(async (res, rej) => { + const viewName = row.table_name as string; + if (!tablesFilter(viewName)) return res(''); + tableCount += 1; + const viewSchema = row.table_schema; + + try { + const columnToReturn: Record = {}; + + const viewResponses = await getColumnsInfoQuery({ schema: viewSchema, table: viewName, db }); + + for (const viewResponse of viewResponses) { + const columnName = viewResponse.column_name; + const columnAdditionalDT = viewResponse.additional_dt; + const columnDimensions = viewResponse.array_dimensions; + const enumType: string = viewResponse.enum_name; + let columnType: string = viewResponse.data_type; + const typeSchema = viewResponse.type_schema; + // const defaultValueRes: string = viewResponse.column_default; + + const isGenerated = viewResponse.is_generated === 'ALWAYS'; + const generationExpression = viewResponse.generation_expression; + const isIdentity = viewResponse.is_identity === 'YES'; + const identityGeneration = viewResponse.identity_generation === 'ALWAYS' ? 'always' : 'byDefault'; + const identityStart = viewResponse.identity_start; + const identityIncrement = viewResponse.identity_increment; + const identityMaximum = viewResponse.identity_maximum; + const identityMinimum = viewResponse.identity_minimum; + const identityCycle = viewResponse.identity_cycle === 'YES'; + const identityName = viewResponse.seq_name; + const defaultValueRes = viewResponse.column_default; + + const primaryKey = viewResponse.constraint_type === 'PRIMARY KEY'; + + let columnTypeMapped = columnType; + + // Set default to internal object + if (columnAdditionalDT === 'ARRAY') { + if (typeof internals.tables[viewName] === 'undefined') { + internals.tables[viewName] = { + columns: { + [columnName]: { + isArray: true, + dimensions: columnDimensions, + rawType: columnTypeMapped.substring(0, columnTypeMapped.length - 2), + }, + }, + }; + } else { + if (typeof internals.tables[viewName]!.columns[columnName] === 'undefined') { + internals.tables[viewName]!.columns[columnName] = { + isArray: true, + dimensions: columnDimensions, + rawType: columnTypeMapped.substring(0, columnTypeMapped.length - 2), + }; + } + } + } + + const defaultValue = defaultForColumn(viewResponse, internals, viewName); + if ( + defaultValue === 'NULL' + || (defaultValueRes && defaultValueRes.startsWith('(') && defaultValueRes.endsWith(')')) + ) { + if (typeof internals!.tables![viewName] === 'undefined') { + internals!.tables![viewName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, + }, + }; + } else { + if (typeof internals!.tables![viewName]!.columns[columnName] === 'undefined') { + internals!.tables![viewName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![viewName]!.columns[columnName]!.isDefaultAnExpression = true; + } + } + } + + const isSerial = columnType === 'serial'; + + if (columnTypeMapped.startsWith('numeric(')) { + columnTypeMapped = columnTypeMapped.replace(',', ', '); + } + + if (columnAdditionalDT === 'ARRAY') { + for (let i = 1; i < Number(columnDimensions); i++) { + columnTypeMapped += '[]'; + } + } + + columnTypeMapped = columnTypeMapped + .replace('character varying', 'varchar') + .replace(' without time zone', '') + // .replace("timestamp without time zone", "timestamp") + .replace('character', 'char'); + + columnTypeMapped = trimChar(columnTypeMapped, '"'); + + columnToReturn[columnName] = { + name: columnName, + type: + // filter vectors, but in future we should filter any extension that was installed by user + columnAdditionalDT === 'USER-DEFINED' && !['vector', 'geometry'].includes(enumType) + ? enumType + : columnTypeMapped, + typeSchema: enumsToReturn[`${typeSchema}.${enumType}`] !== undefined + ? enumsToReturn[`${typeSchema}.${enumType}`].schema + : undefined, + primaryKey: primaryKey, + notNull: viewResponse.is_nullable === 'NO', + generated: isGenerated ? { as: generationExpression, type: 'stored' } : undefined, + identity: isIdentity + ? { + type: identityGeneration, + name: identityName, + increment: stringFromDatabaseIdentityProperty(identityIncrement), + minValue: stringFromDatabaseIdentityProperty(identityMinimum), + maxValue: stringFromDatabaseIdentityProperty(identityMaximum), + startWith: stringFromDatabaseIdentityProperty(identityStart), + cache: sequencesToReturn[identityName]?.cache + ? sequencesToReturn[identityName]?.cache + : sequencesToReturn[`${viewSchema}.${identityName}`]?.cache + ? sequencesToReturn[`${viewSchema}.${identityName}`]?.cache + : undefined, + cycle: identityCycle, + schema: viewSchema, + } + : undefined, + }; + + if (identityName) { + // remove "" from sequence name + delete sequencesToReturn[ + `${viewSchema}.${ + identityName.startsWith('"') && identityName.endsWith('"') ? identityName.slice(1, -1) : identityName + }` + ]; + delete sequencesToReturn[identityName]; + } + + if (!isSerial && typeof defaultValue !== 'undefined') { + columnToReturn[columnName].default = defaultValue; + } + } + + const [viewInfo] = await db.query<{ + view_name: string; + schema_name: string; + definition: string; + tablespace_name: string | null; + options: string[] | null; + location: string | null; + }>(` + SELECT + c.relname AS view_name, + n.nspname AS schema_name, + pg_get_viewdef(c.oid, true) AS definition, + ts.spcname AS tablespace_name, + c.reloptions AS options, + pg_tablespace_location(ts.oid) AS location +FROM + pg_class c +JOIN + pg_namespace n ON c.relnamespace = n.oid +LEFT JOIN + pg_tablespace ts ON c.reltablespace = ts.oid +WHERE + (c.relkind = 'm' OR c.relkind = 'v') + AND n.nspname = '${viewSchema}' + AND c.relname = '${viewName}';`); + + const resultWith: { [key: string]: string | boolean | number } = {}; + if (viewInfo.options) { + viewInfo.options.forEach((pair) => { + const splitted = pair.split('='); + const key = splitted[0]; + const value = splitted[1]; + + if (value === 'true') { + resultWith[key] = true; + } else if (value === 'false') { + resultWith[key] = false; + } else if (!isNaN(Number(value))) { + resultWith[key] = Number(value); + } else { + resultWith[key] = value; + } + }); + } + + const definition = viewInfo.definition.replace(/\s+/g, ' ').replace(';', '').trim(); + // { "check_option":"cascaded","security_barrier":true} -> // { "checkOption":"cascaded","securityBarrier":true} + const withOption = Object.values(resultWith).length + ? Object.fromEntries(Object.entries(resultWith).map(([key, value]) => [key.camelCase(), value])) + : undefined; + + const materialized = row.type === 'materialized_view'; + + views[`${viewSchema}.${viewName}`] = { + name: viewName, + schema: viewSchema, + columns: columnToReturn, + isExisting: false, + definition: definition, + materialized: materialized, + with: withOption, + tablespace: viewInfo.tablespace_name ?? undefined, + }; + } catch (e) { + rej(e); + return; + } + res(''); + }); + }); + + viewsCount = allViews.length; + + for await (const _ of allViews) { + } + if (progressCallback) { progressCallback('columns', columnsCount, 'done'); progressCallback('indexes', indexesCount, 'done'); progressCallback('fks', foreignKeysCount, 'done'); + progressCallback('checks', checksCount, 'done'); + progressCallback('views', viewsCount, 'done'); } const schemasObject = Object.fromEntries([...schemas].map((it) => [it, it])); @@ -1236,6 +1601,7 @@ export const fromDatabase = async ( enums: enumsToReturn, schemas: schemasObject, sequences: sequencesToReturn, + views: views, _meta: { schemas: {}, tables: {}, @@ -1246,18 +1612,14 @@ export const fromDatabase = async ( }; const defaultForColumn = (column: any, internals: PgKitInternals, tableName: string) => { - const columnName = column.attname; + const columnName = column.column_name; const isArray = internals?.tables[tableName]?.columns[columnName]?.isArray ?? false; if (column.column_default === null) { return undefined; } - if ( - column.data_type === 'serial' - || column.data_type === 'smallserial' - || column.data_type === 'bigserial' - ) { + if (column.data_type === 'serial' || column.data_type === 'smallserial' || column.data_type === 'bigserial') { return undefined; } @@ -1275,7 +1637,8 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str if (isArray) { return `'{${ - columnDefaultAsString.slice(2, -2) + columnDefaultAsString + .slice(2, -2) .split(/\s*,\s*/g) .map((value) => { if (['integer', 'smallint', 'bigint', 'double precision', 'real'].includes(column.data_type.slice(0, -2))) { @@ -1296,9 +1659,7 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str }}'`; } - if ( - ['integer', 'smallint', 'bigint', 'double precision', 'real'].includes(column.data_type) - ) { + if (['integer', 'smallint', 'bigint', 'double precision', 'real'].includes(column.data_type)) { if (/^-?[\d.]+(?:e-?\d+)?$/.test(columnDefaultAsString)) { return Number(columnDefaultAsString); } else { @@ -1311,21 +1672,19 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str }, }; } else { - if ( - typeof internals!.tables![tableName]!.columns[columnName] - === 'undefined' - ) { + if (typeof internals!.tables![tableName]!.columns[columnName] === 'undefined') { internals!.tables![tableName]!.columns[columnName] = { isDefaultAnExpression: true, }; } else { - internals!.tables![tableName]!.columns[ - columnName - ]!.isDefaultAnExpression = true; + internals!.tables![tableName]!.columns[columnName]!.isDefaultAnExpression = true; } } return columnDefaultAsString; } + } else if (column.data_type.includes('numeric')) { + // if numeric(1,1) and used '99' -> psql stores like '99'::numeric + return columnDefaultAsString.includes("'") ? columnDefaultAsString : `'${columnDefaultAsString}'`; } else if (column.data_type === 'json' || column.data_type === 'jsonb') { const jsonWithoutSpaces = JSON.stringify(JSON.parse(columnDefaultAsString.slice(1, -1))); return `'${jsonWithoutSpaces}'::${column.data_type}`; @@ -1336,6 +1695,76 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str } else if (columnDefaultAsString.startsWith("'") && columnDefaultAsString.endsWith("'")) { return columnDefaultAsString; } else { - return `${columnDefaultAsString.replace(/\\/g, '\`\\')}`; + return `${columnDefaultAsString.replace(/\\/g, '`\\')}`; } }; + +const getColumnsInfoQuery = ({ schema, table, db }: { schema: string; table: string; db: DB }) => { + return db.query( + `SELECT + a.attrelid::regclass::text AS table_name, -- Table, view, or materialized view name + a.attname AS column_name, -- Column name + CASE + WHEN NOT a.attisdropped THEN + CASE + WHEN a.attnotnull THEN 'NO' + ELSE 'YES' + END + ELSE NULL + END AS is_nullable, -- NULL or NOT NULL constraint + a.attndims AS array_dimensions, -- Array dimensions + CASE + WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[]) + AND EXISTS ( + SELECT FROM pg_attrdef ad + WHERE ad.adrelid = a.attrelid + AND ad.adnum = a.attnum + AND pg_get_expr(ad.adbin, ad.adrelid) = 'nextval(''' + || pg_get_serial_sequence(a.attrelid::regclass::text, a.attname)::regclass || '''::regclass)' + ) + THEN CASE a.atttypid + WHEN 'int'::regtype THEN 'serial' + WHEN 'int8'::regtype THEN 'bigserial' + WHEN 'int2'::regtype THEN 'smallserial' + END + ELSE format_type(a.atttypid, a.atttypmod) + END AS data_type, -- Column data type +-- ns.nspname AS type_schema, -- Schema name + pg_get_serial_sequence('"${schema}"."${table}"', a.attname)::regclass AS seq_name, -- Serial sequence (if any) + c.column_default, -- Column default value + c.data_type AS additional_dt, -- Data type from information_schema + c.udt_name AS enum_name, -- Enum type (if applicable) + c.is_generated, -- Is it a generated column? + c.generation_expression, -- Generation expression (if generated) + c.is_identity, -- Is it an identity column? + c.identity_generation, -- Identity generation strategy (ALWAYS or BY DEFAULT) + c.identity_start, -- Start value of identity column + c.identity_increment, -- Increment for identity column + c.identity_maximum, -- Maximum value for identity column + c.identity_minimum, -- Minimum value for identity column + c.identity_cycle, -- Does the identity column cycle? + enum_ns.nspname AS type_schema -- Schema of the enum type +FROM + pg_attribute a +JOIN + pg_class cls ON cls.oid = a.attrelid -- Join pg_class to get table/view/materialized view info +JOIN + pg_namespace ns ON ns.oid = cls.relnamespace -- Join namespace to get schema info +LEFT JOIN + information_schema.columns c ON c.column_name = a.attname + AND c.table_schema = ns.nspname + AND c.table_name = cls.relname -- Match schema and table/view name +LEFT JOIN + pg_type enum_t ON enum_t.oid = a.atttypid -- Join to get the type info +LEFT JOIN + pg_namespace enum_ns ON enum_ns.oid = enum_t.typnamespace -- Join to get the enum schema +WHERE + a.attnum > 0 -- Valid column numbers only + AND NOT a.attisdropped -- Skip dropped columns + AND cls.relkind IN ('r', 'v', 'm') -- Include regular tables ('r'), views ('v'), and materialized views ('m') + AND ns.nspname = '${schema}' -- Filter by schema + AND cls.relname = '${table}' -- Filter by table name +ORDER BY + a.attnum; -- Order by column number`, + ); +}; diff --git a/drizzle-kit/src/serializer/sqliteImports.ts b/drizzle-kit/src/serializer/sqliteImports.ts index 534427e47..0164604d1 100644 --- a/drizzle-kit/src/serializer/sqliteImports.ts +++ b/drizzle-kit/src/serializer/sqliteImports.ts @@ -1,21 +1,28 @@ import { is } from 'drizzle-orm'; -import { AnySQLiteTable, SQLiteTable } from 'drizzle-orm/sqlite-core'; +import { AnySQLiteTable, SQLiteTable, SQLiteView } from 'drizzle-orm/sqlite-core'; import { safeRegister } from '../cli/commands/utils'; export const prepareFromExports = (exports: Record) => { const tables: AnySQLiteTable[] = []; + const views: SQLiteView[] = []; + const i0values = Object.values(exports); i0values.forEach((t) => { if (is(t, SQLiteTable)) { tables.push(t); } + + if (is(t, SQLiteView)) { + views.push(t); + } }); - return { tables }; + return { tables, views }; }; export const prepareFromSqliteImports = async (imports: string[]) => { const tables: AnySQLiteTable[] = []; + const views: SQLiteView[] = []; const { unregister } = await safeRegister(); for (let i = 0; i < imports.length; i++) { @@ -25,9 +32,10 @@ export const prepareFromSqliteImports = async (imports: string[]) => { const prepared = prepareFromExports(i0); tables.push(...prepared.tables); + views.push(...prepared.views); } unregister(); - return { tables: Array.from(new Set(tables)) }; + return { tables: Array.from(new Set(tables)), views }; }; diff --git a/drizzle-kit/src/serializer/sqliteSchema.ts b/drizzle-kit/src/serializer/sqliteSchema.ts index a8114e3a8..54587c3e0 100644 --- a/drizzle-kit/src/serializer/sqliteSchema.ts +++ b/drizzle-kit/src/serializer/sqliteSchema.ts @@ -1,5 +1,5 @@ import { any, boolean, enum as enumType, literal, object, record, string, TypeOf, union } from 'zod'; -import { customMapEntries, mapEntries, mapValues, originUUID } from '../global'; +import { customMapEntries, mapValues, originUUID } from '../global'; // ------- V3 -------- const index = object({ @@ -49,6 +49,11 @@ const uniqueConstraint = object({ columns: string().array(), }).strict(); +const checkConstraint = object({ + name: string(), + value: string(), +}).strict(); + const table = object({ name: string(), columns: record(string(), column), @@ -56,6 +61,14 @@ const table = object({ foreignKeys: record(string(), fk), compositePrimaryKeys: record(string(), compositePK), uniqueConstraints: record(string(), uniqueConstraint).default({}), + checkConstraints: record(string(), checkConstraint).default({}), +}).strict(); + +export const view = object({ + name: string(), + columns: record(string(), column), + definition: string().optional(), + isExisting: boolean(), }).strict(); // use main dialect @@ -77,6 +90,7 @@ export const schemaInternalV4 = object({ version: literal('4'), dialect: dialect, tables: record(string(), table), + views: record(string(), view), enums: object({}), }).strict(); @@ -108,6 +122,7 @@ export const schemaInternal = object({ version: latestVersion, dialect: dialect, tables: record(string(), table), + views: record(string(), view), enums: object({}), _meta: object({ tables: record(string(), string()), @@ -128,12 +143,14 @@ const tableSquashed = object({ foreignKeys: record(string(), string()), compositePrimaryKeys: record(string(), string()), uniqueConstraints: record(string(), string()).default({}), + checkConstraints: record(string(), string()).default({}), }).strict(); export const schemaSquashed = object({ version: latestVersion, dialect: dialect, tables: record(string(), tableSquashed), + views: record(string(), view), enums: any(), }).strict(); @@ -150,6 +167,8 @@ export type Index = TypeOf; export type ForeignKey = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; +export type CheckConstraint = TypeOf; +export type View = TypeOf; export const SQLiteSquasher = { squashIdx: (idx: Index) => { @@ -233,6 +252,17 @@ export const SQLiteSquasher = { unsquashPK: (pk: string) => { return pk.split(','); }, + squashCheck: (check: CheckConstraint) => { + return `${check.name};${check.value}`; + }, + unsquashCheck: (input: string): CheckConstraint => { + const [ + name, + value, + ] = input.split(';'); + + return { name, value }; + }, }; export const squashSqliteScheme = ( @@ -268,6 +298,13 @@ export const squashSqliteScheme = ( }, ); + const squashedCheckConstraints = mapValues( + it[1].checkConstraints, + (check) => { + return SQLiteSquasher.squashCheck(check); + }, + ); + return [ it[0], { @@ -277,6 +314,7 @@ export const squashSqliteScheme = ( foreignKeys: squashedFKs, compositePrimaryKeys: squashedPKs, uniqueConstraints: squashedUniqueConstraints, + checkConstraints: squashedCheckConstraints, }, ]; }), @@ -286,6 +324,7 @@ export const squashSqliteScheme = ( version: '6', dialect: json.dialect, tables: mappedTables, + views: json.views, enums: json.enums, }; }; @@ -296,6 +335,7 @@ export const drySQLite = schema.parse({ id: originUUID, prevId: '', tables: {}, + views: {}, enums: {}, _meta: { tables: {}, diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index f1d28f759..3977705a6 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -5,14 +5,18 @@ import { // AnySQLiteColumnBuilder, AnySQLiteTable, getTableConfig, + getViewConfig, SQLiteBaseInteger, + SQLiteColumn, SQLiteSyncDialect, + SQLiteView, uniqueKeyName, } from 'drizzle-orm/sqlite-core'; import { CasingType } from 'src/cli/validations/common'; import { withStyle } from '../cli/validations/outputs'; import type { IntrospectStage, IntrospectStatus } from '../cli/views'; import type { + CheckConstraint, Column, ForeignKey, Index, @@ -21,16 +25,20 @@ import type { SQLiteSchemaInternal, Table, UniqueConstraint, + View, } from '../serializer/sqliteSchema'; import { getColumnCasing, type SQLiteDB } from '../utils'; import { sqlToStr } from '.'; export const generateSqliteSnapshot = ( tables: AnySQLiteTable[], + views: SQLiteView[], casing: CasingType | undefined, ): SQLiteSchemaInternal => { const dialect = new SQLiteSyncDialect({ casing }); const result: Record = {}; + const resultViews: Record = {}; + const internal: SQLiteKitInternals = { indexes: {} }; for (const table of tables) { // const tableName = getTableName(table); @@ -39,11 +47,15 @@ export const generateSqliteSnapshot = ( const foreignKeysObject: Record = {}; const primaryKeysObject: Record = {}; const uniqueConstraintObject: Record = {}; + const checkConstraintObject: Record = {}; + + const checksInTable: Record = {}; const { name: tableName, columns, indexes, + checks, foreignKeys: tableForeignKeys, primaryKeys, uniqueConstraints, @@ -271,6 +283,38 @@ export const generateSqliteSnapshot = ( } }); + checks.forEach((check) => { + const checkName = check.name; + if (typeof checksInTable[tableName] !== 'undefined') { + if (checksInTable[tableName].includes(check.name)) { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated check constraint name in ${ + chalk.underline.blue( + tableName, + ) + }. Please rename your check constraint in the ${ + chalk.underline.blue( + tableName, + ) + } table`, + ) + }`, + ); + process.exit(1); + } + checksInTable[tableName].push(checkName); + } else { + checksInTable[tableName] = [check.name]; + } + + checkConstraintObject[checkName] = { + name: checkName, + value: dialect.sqlToQuery(check.value).sql, + }; + }); + result[tableName] = { name: tableName, columns: columnsObject, @@ -278,6 +322,79 @@ export const generateSqliteSnapshot = ( foreignKeys: foreignKeysObject, compositePrimaryKeys: primaryKeysObject, uniqueConstraints: uniqueConstraintObject, + checkConstraints: checkConstraintObject, + }; + } + + for (const view of views) { + const { name, isExisting, selectedFields, query, schema } = getViewConfig(view); + + const columnsObject: Record = {}; + + const existingView = resultViews[name]; + if (typeof existingView !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated view name across ${ + chalk.underline.blue( + schema ?? 'public', + ) + } schema. Please rename your view`, + ) + }`, + ); + process.exit(1); + } + + for (const key in selectedFields) { + if (is(selectedFields[key], SQLiteColumn)) { + const column = selectedFields[key]; + const notNull: boolean = column.notNull; + const primaryKey: boolean = column.primary; + const generated = column.generated; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + primaryKey, + notNull, + autoincrement: is(column, SQLiteBaseInteger) + ? column.autoIncrement + : false, + generated: generated + ? { + as: is(generated.as, SQL) + ? `(${dialect.sqlToQuery(generated.as as SQL, 'indexes').sql})` + : typeof generated.as === 'function' + ? `(${dialect.sqlToQuery(generated.as() as SQL, 'indexes').sql})` + : `(${generated.as as any})`, + type: generated.mode ?? 'virtual', + } + : undefined, + }; + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default, casing); + } else { + columnToSet.default = typeof column.default === 'string' + ? `'${column.default}'` + : typeof column.default === 'object' + || Array.isArray(column.default) + ? `'${JSON.stringify(column.default)}'` + : column.default; + } + } + columnsObject[column.name] = columnToSet; + } + } + + resultViews[name] = { + columns: columnsObject, + name, + isExisting, + definition: isExisting ? undefined : dialect.sqlToQuery(query!).sql, }; } @@ -285,6 +402,7 @@ export const generateSqliteSnapshot = ( version: '6', dialect: 'sqlite', tables: result, + views: resultViews, enums: {}, _meta: { tables: {}, @@ -389,6 +507,8 @@ export const fromDatabase = async ( ) => void, ): Promise => { const result: Record = {}; + const resultViews: Record = {}; + const columns = await db.query<{ tableName: string; columnName: string; @@ -399,11 +519,12 @@ export const fromDatabase = async ( seq: number; hidden: number; sql: string; + type: 'view' | 'table'; }>( `SELECT - m.name as "tableName", p.name as "columnName", p.type as "columnType", p."notnull" as "notNull", p.dflt_value as "defaultValue", p.pk as pk, p.hidden as hidden, m.sql + m.name as "tableName", p.name as "columnName", p.type as "columnType", p."notnull" as "notNull", p.dflt_value as "defaultValue", p.pk as pk, p.hidden as hidden, m.sql, m.type as type FROM sqlite_master AS m JOIN pragma_table_xinfo(m.name) AS p - WHERE m.type = 'table' + WHERE (m.type = 'table' OR m.type = 'view') and m.tbl_name != 'sqlite_sequence' and m.tbl_name != 'sqlite_stat1' and m.tbl_name != '_litestream_seq' @@ -435,6 +556,8 @@ export const fromDatabase = async ( let tablesCount = new Set(); let indexesCount = 0; let foreignKeysCount = 0; + let checksCount = 0; + let viewsCount = 0; // append primaryKeys by table const tableToPk: { [tname: string]: string[] } = {}; @@ -447,7 +570,10 @@ export const fromDatabase = async ( for (const column of columns) { if (!tablesFilter(column.tableName)) continue; - columnsCount += 1; + // TODO + if (column.type !== 'view') { + columnsCount += 1; + } if (progressCallback) { progressCallback('columns', columnsCount, 'fetching'); } @@ -526,6 +652,7 @@ export const fromDatabase = async ( indexes: {}, foreignKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }; } else { result[tableName]!.columns[columnName] = newColumn; @@ -696,10 +823,107 @@ WHERE progressCallback('enums', 0, 'done'); } + const views = await db.query( + `SELECT name AS view_name, sql AS sql FROM sqlite_master WHERE type = 'view';`, + ); + + viewsCount = views.length; + + if (progressCallback) { + progressCallback('views', viewsCount, 'fetching'); + } + for (const view of views) { + const viewName = view['view_name']; + const sql = view['sql']; + + const regex = new RegExp(`\\bAS\\b\\s+(SELECT.+)$`, 'i'); + const match = sql.match(regex); + + if (!match) { + console.log('Could not process view'); + process.exit(1); + } + + const viewDefinition = match[1] as string; + + const columns = result[viewName].columns; + delete result[viewName]; + + resultViews[viewName] = { + columns: columns, + isExisting: false, + name: viewName, + definition: viewDefinition, + }; + } + if (progressCallback) { + progressCallback('views', viewsCount, 'done'); + } + + const namedCheckPattern = /CONSTRAINT\s*["']?(\w+)["']?\s*CHECK\s*\((.*?)\)/gi; + const unnamedCheckPattern = /CHECK\s*\((.*?)\)/gi; + let checkCounter = 0; + const checkConstraints: Record = {}; + const checks = await db.query<{ tableName: string; sql: string }>(`SELECT name as "tableName", sql as "sql" + FROM sqlite_master + WHERE type = 'table' AND name != 'sqlite_sequence';`); + for (const check of checks) { + if (!tablesFilter(check.tableName)) continue; + + const { tableName, sql } = check; + + // Find named CHECK constraints + let namedChecks = [...sql.matchAll(namedCheckPattern)]; + if (namedChecks.length > 0) { + namedChecks.forEach(([_, checkName, checkValue]) => { + checkConstraints[checkName] = { + name: checkName, + value: checkValue.trim(), + }; + }); + } else { + // If no named constraints, find unnamed CHECK constraints and assign names + let unnamedChecks = [...sql.matchAll(unnamedCheckPattern)]; + unnamedChecks.forEach(([_, checkValue]) => { + let checkName = `${tableName}_check_${++checkCounter}`; + checkConstraints[checkName] = { + name: checkName, + value: checkValue.trim(), + }; + }); + } + + checksCount += Object.values(checkConstraints).length; + if (progressCallback) { + progressCallback('checks', checksCount, 'fetching'); + } + + const table = result[tableName]; + + if (!table) { + result[tableName] = { + name: tableName, + columns: {}, + compositePrimaryKeys: {}, + indexes: {}, + foreignKeys: {}, + uniqueConstraints: {}, + checkConstraints: checkConstraints, + }; + } else { + result[tableName]!.checkConstraints = checkConstraints; + } + } + + if (progressCallback) { + progressCallback('checks', checksCount, 'done'); + } + return { version: '6', dialect: 'sqlite', tables: result, + views: resultViews, enums: {}, _meta: { tables: {}, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 64ea8e465..bae4c100a 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -5,7 +5,6 @@ import { enum as enumType, literal, never, - number, object, record, string, @@ -22,18 +21,28 @@ import { _prepareSqliteAddColumns, JsonAddColumnStatement, JsonAlterCompositePK, + JsonAlterMySqlViewStatement, JsonAlterTableSetSchema, JsonAlterUniqueConstraint, + JsonAlterViewStatement, + JsonCreateCheckConstraint, JsonCreateCompositePK, + JsonCreateMySqlViewStatement, + JsonCreatePgViewStatement, JsonCreateReferenceStatement, + JsonCreateSqliteViewStatement, JsonCreateUniqueConstraint, + JsonDeleteCheckConstraint, JsonDeleteCompositePK, JsonDeleteUniqueConstraint, JsonDropColumnStatement, + JsonDropViewStatement, JsonReferenceStatement, JsonRenameColumnStatement, + JsonRenameViewStatement, JsonSqliteAddColumnStatement, JsonStatement, + prepareAddCheckConstraint, prepareAddCompositePrimaryKeyMySql, prepareAddCompositePrimaryKeyPg, prepareAddCompositePrimaryKeySqlite, @@ -50,38 +59,51 @@ import { prepareCreateReferencesJson, prepareCreateSchemasJson, prepareCreateSequenceJson, + prepareDeleteCheckConstraint, prepareDeleteCompositePrimaryKeyMySql, prepareDeleteCompositePrimaryKeyPg, prepareDeleteCompositePrimaryKeySqlite, prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDeleteUniqueConstraintPg as prepareDeleteUniqueConstraint, prepareDropEnumJson, + prepareDropEnumValues, prepareDropIndexesJson, prepareDropReferencesJson, prepareDropSequenceJson, prepareDropTableJson, + prepareDropViewJson, prepareLibSQLCreateReferencesJson, prepareLibSQLDropReferencesJson, prepareMoveEnumJson, prepareMoveSequenceJson, + prepareMySqlAlterView, prepareMySqlCreateTableJson, + prepareMySqlCreateViewJson, preparePgAlterColumns, + preparePgAlterViewAddWithOptionJson, + preparePgAlterViewAlterSchemaJson, + preparePgAlterViewAlterTablespaceJson, + preparePgAlterViewAlterUsingJson, + preparePgAlterViewDropWithOptionJson, preparePgCreateIndexesJson, preparePgCreateTableJson, + preparePgCreateViewJson, prepareRenameColumns, prepareRenameEnumJson, prepareRenameSchemasJson, prepareRenameSequenceJson, prepareRenameTableJson, + prepareRenameViewJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, + prepareSqliteCreateViewJson, } from './jsonStatements'; import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; -import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher } from './serializer/mysqlSchema'; -import { PgSchema, PgSchemaSquashed, sequenceSquashed } from './serializer/pgSchema'; -import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; +import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher, ViewSquashed } from './serializer/mysqlSchema'; +import { mergedViewWithOption, PgSchema, PgSchemaSquashed, sequenceSquashed, View } from './serializer/pgSchema'; +import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher, View as SqliteView } from './serializer/sqliteSchema'; import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; import { copy, prepareMigrationMeta } from './utils'; @@ -207,6 +229,7 @@ const tableScheme = object({ foreignKeys: record(string(), string()), compositePrimaryKeys: record(string(), string()).default({}), uniqueConstraints: record(string(), string()).default({}), + checkConstraints: record(string(), string()).default({}), }).strict(); export const alteredTableScheme = object({ @@ -249,22 +272,84 @@ export const alteredTableScheme = object({ __old: string(), }), ), + addedCheckConstraints: record( + string(), + string(), + ), + deletedCheckConstraints: record( + string(), + string(), + ), + alteredCheckConstraints: record( + string(), + object({ + __new: string(), + __old: string(), + }), + ), }).strict(); +const alteredViewCommon = object({ + name: string(), + alteredDefinition: object({ + __old: string(), + __new: string(), + }).strict().optional(), + alteredExisting: object({ + __old: boolean(), + __new: boolean(), + }).strict().optional(), +}); + +export const alteredPgViewSchema = alteredViewCommon.merge( + object({ + schema: string(), + deletedWithOption: mergedViewWithOption.optional(), + addedWithOption: mergedViewWithOption.optional(), + addedWith: mergedViewWithOption.optional(), + deletedWith: mergedViewWithOption.optional(), + alteredWith: mergedViewWithOption.optional(), + alteredSchema: object({ + __old: string(), + __new: string(), + }).strict().optional(), + alteredTablespace: object({ + __old: string(), + __new: string(), + }).strict().optional(), + alteredUsing: object({ + __old: string(), + __new: string(), + }).strict().optional(), + }).strict(), +); + +const alteredMySqlViewSchema = alteredViewCommon.merge( + object({ + alteredMeta: object({ + __old: string(), + __new: string(), + }).strict().optional(), + }).strict(), +); + export const diffResultScheme = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: changedEnumSchema.array(), alteredSequences: sequenceSquashed.array(), + alteredViews: alteredPgViewSchema.array(), }).strict(); export const diffResultSchemeMysql = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: never().array(), + alteredViews: alteredMySqlViewSchema.array(), }); export const diffResultSchemeSQLite = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: never().array(), + alteredViews: alteredViewCommon.array(), }); export type Column = TypeOf; @@ -390,6 +475,9 @@ export const applyPgSnapshotsDiff = async ( columnsResolver: ( input: ColumnsResolverInput, ) => Promise>, + viewsResolver: ( + input: ResolverInput, + ) => Promise>, prevFull: PgSchema, curFull: PgSchema, action?: 'push' | undefined, @@ -720,11 +808,49 @@ export const applyPgSnapshotsDiff = async ( }, ); - const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + const viewsDiff = diffSchemasOrTables(json1.views, json2.views); + + const { + created: createdViews, + deleted: deletedViews, + renamed: renamedViews, + moved: movedViews, + } = await viewsResolver({ + created: viewsDiff.added, + deleted: viewsDiff.deleted, + }); + + const renamesViewDic: Record = {}; + renamedViews.forEach((it) => { + renamesViewDic[`${it.from.schema}.${it.from.name}`] = { to: it.to.name, from: it.from.name }; + }); + + const movedViewDic: Record = {}; + movedViews.forEach((it) => { + movedViewDic[`${it.schemaFrom}.${it.name}`] = { to: it.schemaTo, from: it.schemaFrom }; + }); + + const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + viewsPatchedSnap1.views = mapEntries( + viewsPatchedSnap1.views, + (viewKey, viewValue) => { + const rename = renamesViewDic[`${viewValue.schema}.${viewValue.name}`]; + const moved = movedViewDic[`${viewValue.schema}.${viewValue.name}`]; + + if (rename) { + viewValue.name = rename.to; + viewKey = `${viewValue.schema}.${viewValue.name}`; + } + + if (moved) viewKey = `${moved.to}.${viewValue.name}`; + + return [viewKey, viewValue]; + }, + ); + + const diffResult = applyJsonDiff(viewsPatchedSnap1, json2); - // no diffs const typedResult: DiffResult = diffResultScheme.parse(diffResult); - // const typedResult: DiffResult = {}; const jsonStatements: JsonStatement[] = []; @@ -791,6 +917,9 @@ export const applyPgSnapshotsDiff = async ( }); } + const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + const jsonCreatedCheckConstraints: JsonCreateCheckConstraint[] = []; + for (let it of alteredTables) { // This part is needed to make sure that same columns in a table are not triggered for change // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name @@ -841,6 +970,8 @@ export const applyPgSnapshotsDiff = async ( let addedUniqueConstraints: JsonCreateUniqueConstraint[] = []; let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + let createCheckConstraints: JsonCreateCheckConstraint[] = []; + let deleteCheckConstraints: JsonDeleteCheckConstraint[] = []; addedUniqueConstraints = prepareAddUniqueConstraint( it.name, @@ -867,6 +998,28 @@ export const applyPgSnapshotsDiff = async ( ); } + createCheckConstraints = prepareAddCheckConstraint(it.name, it.schema, it.addedCheckConstraints); + deleteCheckConstraints = prepareDeleteCheckConstraint( + it.name, + it.schema, + it.deletedCheckConstraints, + ); + + if (it.alteredCheckConstraints && action !== 'push') { + const added: Record = {}; + const deleted: Record = {}; + + for (const k of Object.keys(it.alteredCheckConstraints)) { + added[k] = it.alteredCheckConstraints[k].__new; + deleted[k] = it.alteredCheckConstraints[k].__old; + } + createCheckConstraints.push(...prepareAddCheckConstraint(it.name, it.schema, added)); + deleteCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); + } + + jsonCreatedCheckConstraints.push(...createCheckConstraints); + jsonDeletedCheckConstraints.push(...deleteCheckConstraints); + jsonAddedCompositePKs.push(...addedCompositePKs); jsonDeletedCompositePKs.push(...deletedCompositePKs); jsonAlteredCompositePKs.push(...alteredCompositePKs); @@ -1002,30 +1155,6 @@ export const applyPgSnapshotsDiff = async ( // - create table with generated // - alter - should be not triggered, but should get warning - // TODO: - // let hasEnumValuesDeletions = false; - // let enumValuesDeletions: { name: string; schema: string; values: string[] }[] = - // []; - // for (let alteredEnum of typedResult.alteredEnums) { - // if (alteredEnum.deletedValues.length > 0) { - // hasEnumValuesDeletions = true; - // enumValuesDeletions.push({ - // name: alteredEnum.name, - // schema: alteredEnum.schema, - // values: alteredEnum.deletedValues, - // }); - // } - // } - // if (hasEnumValuesDeletions) { - // console.log(error("Deletion of enum values is prohibited in Postgres - see here")); - // for(let entry of enumValuesDeletions){ - // console.log(error(`You're trying to delete ${chalk.blue(`[${entry.values.join(", ")}]`)} values from ${chalk.blue(`${entry.schema}.${entry.name}`)}`)) - // } - // } - // if (hasEnumValuesDeletions && action === "push") { - // process.exit(1); - // } - const createEnums = createdEnums.map((it) => { return prepareCreateEnumJson(it.name, it.schema, it.values); }) ?? []; @@ -1042,14 +1171,17 @@ export const applyPgSnapshotsDiff = async ( return prepareRenameEnumJson(it.from.name, it.to.name, it.to.schema); }); - // todo: block enum rename, enum value rename and enun deletion for now const jsonAlterEnumsWithAddedValues = typedResult.alteredEnums .map((it) => { return prepareAddValuesToEnumJson(it.name, it.schema, it.addedValues); }) .flat() ?? []; - /////////// + const jsonAlterEnumsWithDroppedValues = typedResult.alteredEnums + .map((it) => { + return prepareDropEnumValues(it.name, it.schema, it.deletedValues, curFull); + }) + .flat() ?? []; const createSequences = createdSequences.map((it) => { return prepareCreateSequenceJson(it); @@ -1091,6 +1223,156 @@ export const applyPgSnapshotsDiff = async ( return preparePgCreateTableJson(it, curFull); }); + const createViews: JsonCreatePgViewStatement[] = []; + const dropViews: JsonDropViewStatement[] = []; + const renameViews: JsonRenameViewStatement[] = []; + const alterViews: JsonAlterViewStatement[] = []; + + createViews.push( + ...createdViews.filter((it) => !it.isExisting).map((it) => { + return preparePgCreateViewJson( + it.name, + it.schema, + it.definition!, + it.materialized, + it.withNoData, + it.with, + it.using, + it.tablespace, + ); + }), + ); + + dropViews.push( + ...deletedViews.filter((it) => !it.isExisting).map((it) => { + return prepareDropViewJson(it.name, it.schema, it.materialized); + }), + ); + + renameViews.push( + ...renamedViews.filter((it) => !it.to.isExisting && !json1.views[`${it.from.schema}.${it.from.name}`].isExisting) + .map((it) => { + return prepareRenameViewJson(it.to.name, it.from.name, it.to.schema, it.to.materialized); + }), + ); + + alterViews.push( + ...movedViews.filter((it) => + !json2.views[`${it.schemaTo}.${it.name}`].isExisting && !json1.views[`${it.schemaFrom}.${it.name}`].isExisting + ).map((it) => { + return preparePgAlterViewAlterSchemaJson( + it.schemaTo, + it.schemaFrom, + it.name, + json2.views[`${it.schemaTo}.${it.name}`].materialized, + ); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[`${it.schema}.${it.name}`].isExisting); + + for (const alteredView of alteredViews) { + const viewKey = `${alteredView.schema}.${alteredView.name}`; + + const { materialized, with: withOption, definition, withNoData, using, tablespace } = json2.views[viewKey]; + + if (alteredView.alteredExisting || (alteredView.alteredDefinition && action !== 'push')) { + dropViews.push(prepareDropViewJson(alteredView.name, alteredView.schema, materialized)); + + createViews.push( + preparePgCreateViewJson( + alteredView.name, + alteredView.schema, + definition!, + materialized, + withNoData, + withOption, + using, + tablespace, + ), + ); + + continue; + } + + if (alteredView.addedWithOption) { + alterViews.push( + preparePgAlterViewAddWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.addedWithOption, + ), + ); + } + + if (alteredView.deletedWithOption) { + alterViews.push( + preparePgAlterViewDropWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.deletedWithOption, + ), + ); + } + + if (alteredView.addedWith) { + alterViews.push( + preparePgAlterViewAddWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.addedWith, + ), + ); + } + + if (alteredView.deletedWith) { + alterViews.push( + preparePgAlterViewDropWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.deletedWith, + ), + ); + } + + if (alteredView.alteredWith) { + alterViews.push( + preparePgAlterViewAddWithOptionJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.alteredWith, + ), + ); + } + + if (alteredView.alteredTablespace) { + alterViews.push( + preparePgAlterViewAlterTablespaceJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.alteredTablespace.__new, + ), + ); + } + + if (alteredView.alteredUsing) { + alterViews.push( + preparePgAlterViewAlterUsingJson( + alteredView.name, + alteredView.schema, + materialized, + alteredView.alteredUsing.__new, + ), + ); + } + } + jsonStatements.push(...createSchemas); jsonStatements.push(...renameSchemas); jsonStatements.push(...createEnums); @@ -1105,12 +1387,17 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...createTables); + jsonStatements.push(...dropViews); + jsonStatements.push(...renameViews); + jsonStatements.push(...alterViews); + jsonStatements.push(...jsonDropTables); jsonStatements.push(...jsonSetTableSchemas); jsonStatements.push(...jsonRenameTables); jsonStatements.push(...jsonRenameColumnsStatements); jsonStatements.push(...jsonDeletedUniqueConstraints); + jsonStatements.push(...jsonDeletedCheckConstraints); jsonStatements.push(...jsonDroppedReferencesForAlteredTables); @@ -1133,8 +1420,12 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...jsonAlteredCompositePKs); jsonStatements.push(...jsonAddedUniqueConstraints); + jsonStatements.push(...jsonCreatedCheckConstraints); jsonStatements.push(...jsonAlteredUniqueConstraints); + jsonStatements.push(...jsonAlterEnumsWithDroppedValues); + + jsonStatements.push(...createViews); jsonStatements.push(...dropEnums); jsonStatements.push(...dropSequences); @@ -1169,7 +1460,25 @@ export const applyPgSnapshotsDiff = async ( return true; }); - const sqlStatements = fromJson(filteredJsonStatements, 'postgresql'); + // enum filters + // Need to find add and drop enum values in same enum and remove add values + const filteredEnumsJsonStatements = filteredJsonStatements.filter((st) => { + if (st.type === 'alter_type_add_value') { + if ( + jsonStatements.find( + (it) => + it.type === 'alter_type_drop_value' + && it.name === st.name + && it.schema === st.schema, + ) + ) { + return false; + } + } + return true; + }); + + const sqlStatements = fromJson(filteredEnumsJsonStatements, 'postgresql'); const uniqueSqlStatements: string[] = []; sqlStatements.forEach((ss) => { @@ -1190,7 +1499,7 @@ export const applyPgSnapshotsDiff = async ( const _meta = prepareMigrationMeta(rSchemas, rTables, rColumns); return { - statements: filteredJsonStatements, + statements: filteredEnumsJsonStatements, sqlStatements: uniqueSqlStatements, _meta, }; @@ -1205,6 +1514,9 @@ export const applyMysqlSnapshotsDiff = async ( columnsResolver: ( input: ColumnsResolverInput, ) => Promise>, + viewsResolver: ( + input: ResolverInput, + ) => Promise>, prevFull: MySqlSchema, curFull: MySqlSchema, action?: 'push' | undefined, @@ -1352,7 +1664,38 @@ export const applyMysqlSnapshotsDiff = async ( }, ); - const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + const viewsDiff = diffSchemasOrTables(json1.views, json2.views); + + const { + created: createdViews, + deleted: deletedViews, + renamed: renamedViews, // renamed or moved + } = await viewsResolver({ + created: viewsDiff.added, + deleted: viewsDiff.deleted, + }); + + const renamesViewDic: Record = {}; + renamedViews.forEach((it) => { + renamesViewDic[it.from.name] = { to: it.to.name, from: it.from.name }; + }); + + const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + viewsPatchedSnap1.views = mapEntries( + viewsPatchedSnap1.views, + (viewKey, viewValue) => { + const rename = renamesViewDic[viewValue.name]; + + if (rename) { + viewValue.name = rename.to; + viewKey = rename.to; + } + + return [viewKey, viewValue]; + }, + ); + + const diffResult = applyJsonDiff(viewsPatchedSnap1, json2); const typedResult: DiffResultMysql = diffResultSchemeMysql.parse(diffResult); @@ -1387,6 +1730,9 @@ export const applyMysqlSnapshotsDiff = async ( const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + const jsonCreatedCheckConstraints: JsonCreateCheckConstraint[] = []; + const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames .map((it) => prepareRenameColumns(it.table, '', it.renames)) .flat(); @@ -1448,6 +1794,9 @@ export const applyMysqlSnapshotsDiff = async ( let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + let createdCheckConstraints: JsonCreateCheckConstraint[] = []; + let deletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + addedUniqueConstraints = prepareAddUniqueConstraint( it.name, it.schema, @@ -1473,6 +1822,26 @@ export const applyMysqlSnapshotsDiff = async ( ); } + createdCheckConstraints = prepareAddCheckConstraint(it.name, it.schema, it.addedCheckConstraints); + deletedCheckConstraints = prepareDeleteCheckConstraint( + it.name, + it.schema, + it.deletedCheckConstraints, + ); + + // skip for push + if (it.alteredCheckConstraints && action !== 'push') { + const added: Record = {}; + const deleted: Record = {}; + + for (const k of Object.keys(it.alteredCheckConstraints)) { + added[k] = it.alteredCheckConstraints[k].__new; + deleted[k] = it.alteredCheckConstraints[k].__old; + } + createdCheckConstraints.push(...prepareAddCheckConstraint(it.name, it.schema, added)); + deletedCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); + } + jsonAddedCompositePKs.push(...addedCompositePKs); jsonDeletedCompositePKs.push(...deletedCompositePKs); jsonAlteredCompositePKs.push(...alteredCompositePKs); @@ -1480,6 +1849,9 @@ export const applyMysqlSnapshotsDiff = async ( jsonAddedUniqueConstraints.push(...addedUniqueConstraints); jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + + jsonCreatedCheckConstraints.push(...createdCheckConstraints); + jsonDeletedCheckConstraints.push(...deletedCheckConstraints); }); const rColumns = jsonRenameColumnsStatements.map((it) => { @@ -1593,13 +1965,85 @@ export const applyMysqlSnapshotsDiff = async ( curFull.internal, ); }); + + const createViews: JsonCreateMySqlViewStatement[] = []; + const dropViews: JsonDropViewStatement[] = []; + const renameViews: JsonRenameViewStatement[] = []; + const alterViews: JsonAlterMySqlViewStatement[] = []; + + createViews.push( + ...createdViews.filter((it) => !it.isExisting).map((it) => { + return prepareMySqlCreateViewJson( + it.name, + it.definition!, + it.meta, + ); + }), + ); + + dropViews.push( + ...deletedViews.filter((it) => !it.isExisting).map((it) => { + return prepareDropViewJson(it.name); + }), + ); + + renameViews.push( + ...renamedViews.filter((it) => !it.to.isExisting && !json1.views[it.from.name].isExisting).map((it) => { + return prepareRenameViewJson(it.to.name, it.from.name); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[it.name].isExisting); + + for (const alteredView of alteredViews) { + const { definition, meta } = json2.views[alteredView.name]; + + if (alteredView.alteredExisting) { + dropViews.push(prepareDropViewJson(alteredView.name)); + + createViews.push( + prepareMySqlCreateViewJson( + alteredView.name, + definition!, + meta, + ), + ); + + continue; + } + + if (alteredView.alteredDefinition && action !== 'push') { + createViews.push( + prepareMySqlCreateViewJson( + alteredView.name, + definition!, + meta, + true, + ), + ); + continue; + } + + if (alteredView.alteredMeta) { + const view = curFull['views'][alteredView.name]; + alterViews.push( + prepareMySqlAlterView(view), + ); + } + } + jsonStatements.push(...jsonMySqlCreateTables); jsonStatements.push(...jsonDropTables); jsonStatements.push(...jsonRenameTables); jsonStatements.push(...jsonRenameColumnsStatements); + jsonStatements.push(...dropViews); + jsonStatements.push(...renameViews); + jsonStatements.push(...alterViews); + jsonStatements.push(...jsonDeletedUniqueConstraints); + jsonStatements.push(...jsonDeletedCheckConstraints); jsonStatements.push(...jsonDroppedReferencesForAlteredTables); @@ -1618,6 +2062,7 @@ export const applyMysqlSnapshotsDiff = async ( jsonStatements.push(...jsonCreateReferencesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForCreatedTables); + jsonStatements.push(...jsonCreatedCheckConstraints); jsonStatements.push(...jsonCreatedReferencesForAlteredTables); jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); @@ -1628,7 +2073,7 @@ export const applyMysqlSnapshotsDiff = async ( // jsonStatements.push(...jsonAddedCompositePKs); jsonStatements.push(...jsonAlteredCompositePKs); - jsonStatements.push(...jsonAddedUniqueConstraints); + jsonStatements.push(...createViews); jsonStatements.push(...jsonAlteredUniqueConstraints); @@ -1663,6 +2108,9 @@ export const applySqliteSnapshotsDiff = async ( columnsResolver: ( input: ColumnsResolverInput, ) => Promise>, + viewsResolver: ( + input: ResolverInput, + ) => Promise>, prevFull: SQLiteSchema, curFull: SQLiteSchema, action?: 'push' | undefined, @@ -1775,7 +2223,37 @@ export const applySqliteSnapshotsDiff = async ( }, ); - const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + const viewsDiff = diffSchemasOrTables(json1.views, json2.views); + + const { + created: createdViews, + deleted: deletedViews, + renamed: renamedViews, // renamed or moved + } = await viewsResolver({ + created: viewsDiff.added, + deleted: viewsDiff.deleted, + }); + + const renamesViewDic: Record = {}; + renamedViews.forEach((it) => { + renamesViewDic[it.from.name] = { to: it.to.name, from: it.from.name }; + }); + + const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + viewsPatchedSnap1.views = mapEntries( + viewsPatchedSnap1.views, + (viewKey, viewValue) => { + const rename = renamesViewDic[viewValue.name]; + + if (rename) { + viewValue.name = rename.to; + } + + return [viewKey, viewValue]; + }, + ); + + const diffResult = applyJsonDiff(viewsPatchedSnap1, json2); const typedResult = diffResultSchemeSQLite.parse(diffResult); @@ -1841,6 +2319,9 @@ export const applySqliteSnapshotsDiff = async ( const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + const jsonCreatedCheckConstraints: JsonCreateCheckConstraint[] = []; + allAltered.forEach((it) => { // This part is needed to make sure that same columns in a table are not triggered for change // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name @@ -1911,6 +2392,54 @@ export const applySqliteSnapshotsDiff = async ( ); } + let createdCheckConstraints: JsonCreateCheckConstraint[] = []; + let deletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + + addedUniqueConstraints = prepareAddUniqueConstraint( + it.name, + it.schema, + it.addedUniqueConstraints, + ); + deletedUniqueConstraints = prepareDeleteUniqueConstraint( + it.name, + it.schema, + it.deletedUniqueConstraints, + ); + if (it.alteredUniqueConstraints) { + const added: Record = {}; + const deleted: Record = {}; + for (const k of Object.keys(it.alteredUniqueConstraints)) { + added[k] = it.alteredUniqueConstraints[k].__new; + deleted[k] = it.alteredUniqueConstraints[k].__old; + } + addedUniqueConstraints.push( + ...prepareAddUniqueConstraint(it.name, it.schema, added), + ); + deletedUniqueConstraints.push( + ...prepareDeleteUniqueConstraint(it.name, it.schema, deleted), + ); + } + + createdCheckConstraints = prepareAddCheckConstraint(it.name, it.schema, it.addedCheckConstraints); + deletedCheckConstraints = prepareDeleteCheckConstraint( + it.name, + it.schema, + it.deletedCheckConstraints, + ); + + // skip for push + if (it.alteredCheckConstraints && action !== 'push') { + const added: Record = {}; + const deleted: Record = {}; + + for (const k of Object.keys(it.alteredCheckConstraints)) { + added[k] = it.alteredCheckConstraints[k].__new; + deleted[k] = it.alteredCheckConstraints[k].__old; + } + createdCheckConstraints.push(...prepareAddCheckConstraint(it.name, it.schema, added)); + deletedCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); + } + jsonAddedCompositePKs.push(...addedCompositePKs); jsonDeletedCompositePKs.push(...deletedCompositePKs); jsonAlteredCompositePKs.push(...alteredCompositePKs); @@ -1918,6 +2447,9 @@ export const applySqliteSnapshotsDiff = async ( jsonAddedUniqueConstraints.push(...addedUniqueConstraints); jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + + jsonCreatedCheckConstraints.push(...createdCheckConstraints); + jsonDeletedCheckConstraints.push(...deletedCheckConstraints); }); const rColumns = jsonRenameColumnsStatements.map((it) => { @@ -2016,6 +2548,52 @@ export const applySqliteSnapshotsDiff = async ( (t) => t.type === 'delete_reference', ); + const createViews: JsonCreateSqliteViewStatement[] = []; + const dropViews: JsonDropViewStatement[] = []; + + createViews.push( + ...createdViews.filter((it) => !it.isExisting).map((it) => { + return prepareSqliteCreateViewJson( + it.name, + it.definition!, + ); + }), + ); + + dropViews.push( + ...deletedViews.filter((it) => !it.isExisting).map((it) => { + return prepareDropViewJson(it.name); + }), + ); + + dropViews.push( + ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { + return prepareDropViewJson(it.from.name); + }), + ); + createViews.push( + ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { + return prepareSqliteCreateViewJson(it.to.name, it.to.definition!); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[it.name].isExisting); + + for (const alteredView of alteredViews) { + const { definition } = json2.views[alteredView.name]; + + if (alteredView.alteredExisting || (alteredView.alteredDefinition && action !== 'push')) { + dropViews.push(prepareDropViewJson(alteredView.name)); + + createViews.push( + prepareSqliteCreateViewJson( + alteredView.name, + definition!, + ), + ); + } + } + const jsonStatements: JsonStatement[] = []; jsonStatements.push(...jsonCreateTables); @@ -2024,6 +2602,7 @@ export const applySqliteSnapshotsDiff = async ( jsonStatements.push(...jsonRenameColumnsStatements); jsonStatements.push(...jsonDroppedReferencesForAlteredTables); + jsonStatements.push(...jsonDeletedCheckConstraints); // Will need to drop indexes before changing any columns in table // Then should go column alternations and then index creation @@ -2037,6 +2616,8 @@ export const applySqliteSnapshotsDiff = async ( jsonStatements.push(...jsonCreateIndexesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); + jsonStatements.push(...jsonCreatedCheckConstraints); + jsonStatements.push(...jsonCreatedReferencesForAlteredTables); jsonStatements.push(...jsonDropColumnsStatemets); @@ -2047,6 +2628,9 @@ export const applySqliteSnapshotsDiff = async ( jsonStatements.push(...jsonAlteredUniqueConstraints); + jsonStatements.push(...dropViews); + jsonStatements.push(...createViews); + const combinedJsonStatements = sqliteCombineStatements(jsonStatements, json2, action); const sqlStatements = fromJson(combinedJsonStatements, 'sqlite'); @@ -2079,6 +2663,9 @@ export const applyLibSQLSnapshotsDiff = async ( columnsResolver: ( input: ColumnsResolverInput, ) => Promise>, + viewsResolver: ( + input: ResolverInput, + ) => Promise>, prevFull: SQLiteSchema, curFull: SQLiteSchema, action?: 'push', @@ -2190,7 +2777,37 @@ export const applyLibSQLSnapshotsDiff = async ( }, ); - const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + const viewsDiff = diffSchemasOrTables(json1.views, json2.views); + + const { + created: createdViews, + deleted: deletedViews, + renamed: renamedViews, // renamed or moved + } = await viewsResolver({ + created: viewsDiff.added, + deleted: viewsDiff.deleted, + }); + + const renamesViewDic: Record = {}; + renamedViews.forEach((it) => { + renamesViewDic[it.from.name] = { to: it.to.name, from: it.from.name }; + }); + + const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + viewsPatchedSnap1.views = mapEntries( + viewsPatchedSnap1.views, + (viewKey, viewValue) => { + const rename = renamesViewDic[viewValue.name]; + + if (rename) { + viewValue.name = rename.to; + } + + return [viewKey, viewValue]; + }, + ); + + const diffResult = applyJsonDiff(viewsPatchedSnap1, json2); const typedResult = diffResultSchemeSQLite.parse(diffResult); @@ -2271,6 +2888,9 @@ export const applyLibSQLSnapshotsDiff = async ( const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + const jsonCreatedCheckConstraints: JsonCreateCheckConstraint[] = []; + allAltered.forEach((it) => { // This part is needed to make sure that same columns in a table are not triggered for change // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name @@ -2316,6 +2936,9 @@ export const applyLibSQLSnapshotsDiff = async ( let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + let createdCheckConstraints: JsonCreateCheckConstraint[] = []; + let deletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + addedUniqueConstraints = prepareAddUniqueConstraint( it.name, it.schema, @@ -2342,6 +2965,26 @@ export const applyLibSQLSnapshotsDiff = async ( ); } + createdCheckConstraints = prepareAddCheckConstraint(it.name, it.schema, it.addedCheckConstraints); + deletedCheckConstraints = prepareDeleteCheckConstraint( + it.name, + it.schema, + it.deletedCheckConstraints, + ); + + // skip for push + if (it.alteredCheckConstraints && action !== 'push') { + const added: Record = {}; + const deleted: Record = {}; + + for (const k of Object.keys(it.alteredCheckConstraints)) { + added[k] = it.alteredCheckConstraints[k].__new; + deleted[k] = it.alteredCheckConstraints[k].__old; + } + createdCheckConstraints.push(...prepareAddCheckConstraint(it.name, it.schema, added)); + deletedCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); + } + jsonAddedCompositePKs.push(...addedCompositePKs); jsonDeletedCompositePKs.push(...deletedCompositePKs); jsonAlteredCompositePKs.push(...alteredCompositePKs); @@ -2349,6 +2992,9 @@ export const applyLibSQLSnapshotsDiff = async ( jsonAddedUniqueConstraints.push(...addedUniqueConstraints); jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + + jsonCreatedCheckConstraints.push(...createdCheckConstraints); + jsonDeletedCheckConstraints.push(...deletedCheckConstraints); }); const jsonTableAlternations = allAltered @@ -2439,6 +3085,53 @@ export const applyLibSQLSnapshotsDiff = async ( (t) => t.type === 'delete_reference', ); + const createViews: JsonCreateSqliteViewStatement[] = []; + const dropViews: JsonDropViewStatement[] = []; + + createViews.push( + ...createdViews.filter((it) => !it.isExisting).map((it) => { + return prepareSqliteCreateViewJson( + it.name, + it.definition!, + ); + }), + ); + + dropViews.push( + ...deletedViews.filter((it) => !it.isExisting).map((it) => { + return prepareDropViewJson(it.name); + }), + ); + + // renames + dropViews.push( + ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { + return prepareDropViewJson(it.from.name); + }), + ); + createViews.push( + ...renamedViews.filter((it) => !it.to.isExisting).map((it) => { + return prepareSqliteCreateViewJson(it.to.name, it.to.definition!); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[it.name].isExisting); + + for (const alteredView of alteredViews) { + const { definition } = json2.views[alteredView.name]; + + if (alteredView.alteredExisting || (alteredView.alteredDefinition && action !== 'push')) { + dropViews.push(prepareDropViewJson(alteredView.name)); + + createViews.push( + prepareSqliteCreateViewJson( + alteredView.name, + definition!, + ), + ); + } + } + const jsonStatements: JsonStatement[] = []; jsonStatements.push(...jsonCreateTables); @@ -2448,6 +3141,8 @@ export const applyLibSQLSnapshotsDiff = async ( jsonStatements.push(...jsonDroppedReferencesForAlteredTables); + jsonStatements.push(...jsonDeletedCheckConstraints); + // Will need to drop indexes before changing any columns in table // Then should go column alternations and then index creation jsonStatements.push(...jsonDropIndexesForAllAlteredTables); @@ -2459,6 +3154,10 @@ export const applyLibSQLSnapshotsDiff = async ( jsonStatements.push(...jsonCreateIndexesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); + jsonStatements.push(...jsonCreatedCheckConstraints); + + jsonStatements.push(...dropViews); + jsonStatements.push(...createViews); jsonStatements.push(...jsonCreatedReferencesForAlteredTables); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 374b30581..586175e28 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -1,5 +1,4 @@ import { BREAKPOINT } from './cli/commands/migrate'; -import { Driver } from './cli/validations/common'; import { JsonAddColumnStatement, JsonAddValueToEnumStatement, @@ -21,33 +20,50 @@ import { JsonAlterColumnSetPrimaryKeyStatement, JsonAlterColumnTypeStatement, JsonAlterCompositePK, + JsonAlterMySqlViewStatement, JsonAlterReferenceStatement, JsonAlterSequenceStatement, JsonAlterTableRemoveFromSchema, JsonAlterTableSetNewSchema, JsonAlterTableSetSchema, + JsonAlterViewAddWithOptionStatement, + JsonAlterViewAlterSchemaStatement, + JsonAlterViewAlterTablespaceStatement, + JsonAlterViewAlterUsingStatement, + JsonAlterViewDropWithOptionStatement, + JsonCreateCheckConstraint, JsonCreateCompositePK, JsonCreateEnumStatement, JsonCreateIndexStatement, + JsonCreateMySqlViewStatement, + JsonCreatePgViewStatement, JsonCreateReferenceStatement, JsonCreateSchema, JsonCreateSequenceStatement, + JsonCreateSqliteViewStatement, JsonCreateTableStatement, JsonCreateUniqueConstraint, + JsonDeleteCheckConstraint, JsonDeleteCompositePK, JsonDeleteReferenceStatement, JsonDeleteUniqueConstraint, JsonDropColumnStatement, + JsonDropEnumStatement, JsonDropIndexStatement, JsonDropSequenceStatement, JsonDropTableStatement, + JsonDropValueFromEnumStatement, + JsonDropViewStatement, + JsonMoveEnumStatement, JsonMoveSequenceStatement, JsonPgCreateIndexStatement, JsonRecreateTableStatement, JsonRenameColumnStatement, + JsonRenameEnumStatement, JsonRenameSchema, JsonRenameSequenceStatement, JsonRenameTableStatement, + JsonRenameViewStatement, JsonSqliteAddColumnStatement, JsonSqliteCreateTableStatement, JsonStatement, @@ -145,7 +161,7 @@ class PgCreateTableConvertor extends Convertor { } convert(st: JsonCreateTableStatement) { - const { tableName, schema, columns, compositePKs, uniqueConstraints } = st; + const { tableName, schema, columns, compositePKs, uniqueConstraints, checkConstraints } = st; let statement = ''; const name = schema ? `"${schema}"."${tableName}"` : `"${tableName}"`; @@ -230,6 +246,15 @@ class PgCreateTableConvertor extends Convertor { // statement += `\n`; } } + + if (typeof checkConstraints !== 'undefined' && checkConstraints.length > 0) { + for (const checkConstraint of checkConstraints) { + statement += ',\n'; + const unsquashedCheck = PgSquasher.unsquashCheck(checkConstraint); + statement += `\tCONSTRAINT "${unsquashedCheck.name}" CHECK (${unsquashedCheck.value})`; + } + } + statement += `\n);`; statement += `\n`; @@ -247,6 +272,7 @@ class MySqlCreateTableConvertor extends Convertor { tableName, columns, schema, + checkConstraints, compositePKs, uniqueConstraints, internals, @@ -307,6 +333,15 @@ class MySqlCreateTableConvertor extends Convertor { } } + if (typeof checkConstraints !== 'undefined' && checkConstraints.length > 0) { + for (const checkConstraint of checkConstraints) { + statement += ',\n'; + const unsquashedCheck = MySqlSquasher.unsquashCheck(checkConstraint); + + statement += `\tCONSTRAINT \`${unsquashedCheck.name}\` CHECK(${unsquashedCheck.value})`; + } + } + statement += `\n);`; statement += `\n`; return statement; @@ -325,6 +360,7 @@ export class SQLiteCreateTableConvertor extends Convertor { referenceData, compositePKs, uniqueConstraints, + checkConstraints, } = st; let statement = ''; @@ -384,11 +420,22 @@ export class SQLiteCreateTableConvertor extends Convertor { ) { for (const uniqueConstraint of uniqueConstraints) { statement += ',\n'; - const unsquashedUnique = MySqlSquasher.unsquashUnique(uniqueConstraint); + const unsquashedUnique = SQLiteSquasher.unsquashUnique(uniqueConstraint); statement += `\tCONSTRAINT ${unsquashedUnique.name} UNIQUE(\`${unsquashedUnique.columns.join(`\`,\``)}\`)`; } } + if ( + typeof checkConstraints !== 'undefined' + && checkConstraints.length > 0 + ) { + for (const check of checkConstraints) { + statement += ',\n'; + const { value, name } = SQLiteSquasher.unsquashCheck(check); + statement += `\tCONSTRAINT "${name}" CHECK(${value})`; + } + } + statement += `\n`; statement += `);`; statement += `\n`; @@ -396,6 +443,256 @@ export class SQLiteCreateTableConvertor extends Convertor { } } +class PgCreateViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_view' && dialect === 'postgresql'; + } + + convert(st: JsonCreatePgViewStatement) { + const { definition, name: viewName, schema, with: withOption, materialized, withNoData, tablespace, using } = st; + + const name = schema ? `"${schema}"."${viewName}"` : `"${viewName}"`; + + let statement = materialized ? `CREATE MATERIALIZED VIEW ${name}` : `CREATE VIEW ${name}`; + + if (using) statement += ` USING "${using}"`; + + const options: string[] = []; + if (withOption) { + statement += ` WITH (`; + + Object.entries(withOption).forEach(([key, value]) => { + if (typeof value === 'undefined') return; + + options.push(`${key.snake_case()} = ${value}`); + }); + + statement += options.join(', '); + + statement += `)`; + } + + if (tablespace) statement += ` TABLESPACE ${tablespace}`; + + statement += ` AS (${definition})`; + + if (withNoData) statement += ` WITH NO DATA`; + + statement += `;`; + + return statement; + } +} + +class MySqlCreateViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'mysql_create_view' && dialect === 'mysql'; + } + + convert(st: JsonCreateMySqlViewStatement) { + const { definition, name, algorithm, sqlSecurity, withCheckOption, replace } = st; + + let statement = `CREATE `; + statement += replace ? `OR REPLACE ` : ''; + statement += algorithm ? `ALGORITHM = ${algorithm}\n` : ''; + statement += sqlSecurity ? `SQL SECURITY ${sqlSecurity}\n` : ''; + statement += `VIEW \`${name}\` AS (${definition})`; + statement += withCheckOption ? `\nWITH ${withCheckOption} CHECK OPTION` : ''; + + statement += ';'; + + return statement; + } +} + +class SqliteCreateViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'sqlite_create_view' && (dialect === 'sqlite' || dialect === 'turso'); + } + + convert(st: JsonCreateSqliteViewStatement) { + const { definition, name } = st; + + return `CREATE VIEW \`${name}\` AS ${definition};`; + } +} + +class PgDropViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_view' && dialect === 'postgresql'; + } + + convert(st: JsonDropViewStatement) { + const { name: viewName, schema, materialized } = st; + + const name = schema ? `"${schema}"."${viewName}"` : `"${viewName}"`; + + return `DROP${materialized ? ' MATERIALIZED' : ''} VIEW ${name};`; + } +} + +class MySqlDropViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_view' && dialect === 'mysql'; + } + + convert(st: JsonDropViewStatement) { + const { name } = st; + + return `DROP VIEW \`${name}\`;`; + } +} + +class SqliteDropViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_view' && (dialect === 'sqlite' || dialect === 'turso'); + } + + convert(st: JsonDropViewStatement) { + const { name } = st; + + return `DROP VIEW \`${name}\`;`; + } +} + +class MySqlAlterViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_mysql_view' && dialect === 'mysql'; + } + + convert(st: JsonAlterMySqlViewStatement) { + const { name, algorithm, definition, sqlSecurity, withCheckOption } = st; + + let statement = `ALTER `; + statement += algorithm ? `ALGORITHM = ${algorithm}\n` : ''; + statement += sqlSecurity ? `SQL SECURITY ${sqlSecurity}\n` : ''; + statement += `VIEW \`${name}\` AS ${definition}`; + statement += withCheckOption ? `\nWITH ${withCheckOption} CHECK OPTION` : ''; + + statement += ';'; + + return statement; + } +} + +class PgRenameViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'rename_view' && dialect === 'postgresql'; + } + + convert(st: JsonRenameViewStatement) { + const { nameFrom: from, nameTo: to, schema, materialized } = st; + + const nameFrom = `"${schema}"."${from}"`; + + return `ALTER${materialized ? ' MATERIALIZED' : ''} VIEW ${nameFrom} RENAME TO "${to}";`; + } +} + +class MySqlRenameViewConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'rename_view' && dialect === 'mysql'; + } + + convert(st: JsonRenameViewStatement) { + const { nameFrom: from, nameTo: to } = st; + + return `RENAME TABLE \`${from}\` TO \`${to}\`;`; + } +} + +class PgAlterViewSchemaConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_view_alter_schema' && dialect === 'postgresql'; + } + + convert(st: JsonAlterViewAlterSchemaStatement) { + const { fromSchema, toSchema, name, materialized } = st; + + const statement = `ALTER${ + materialized ? ' MATERIALIZED' : '' + } VIEW "${fromSchema}"."${name}" SET SCHEMA "${toSchema}";`; + + return statement; + } +} + +class PgAlterViewAddWithOptionConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_view_add_with_option' && dialect === 'postgresql'; + } + + convert(st: JsonAlterViewAddWithOptionStatement) { + const { schema, with: withOption, name, materialized } = st; + + let statement = `ALTER${materialized ? ' MATERIALIZED' : ''} VIEW "${schema}"."${name}" SET (`; + + const options: string[] = []; + + Object.entries(withOption).forEach(([key, value]) => { + options.push(`${key.snake_case()} = ${value}`); + }); + + statement += options.join(', '); + + statement += `);`; + + return statement; + } +} + +class PgAlterViewDropWithOptionConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_view_drop_with_option' && dialect === 'postgresql'; + } + + convert(st: JsonAlterViewDropWithOptionStatement) { + const { schema, name, materialized, with: withOptions } = st; + + let statement = `ALTER${materialized ? ' MATERIALIZED' : ''} VIEW "${schema}"."${name}" RESET (`; + + const options: string[] = []; + + Object.entries(withOptions).forEach(([key, value]) => { + options.push(`${key.snake_case()}`); + }); + + statement += options.join(', '); + + statement += ');'; + + return statement; + } +} + +class PgAlterViewAlterTablespaceConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_view_alter_tablespace' && dialect === 'postgresql'; + } + + convert(st: JsonAlterViewAlterTablespaceStatement) { + const { schema, name, toTablespace } = st; + + const statement = `ALTER MATERIALIZED VIEW "${schema}"."${name}" SET TABLESPACE ${toTablespace};`; + + return statement; + } +} + +class PgAlterViewAlterUsingConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_view_alter_using' && dialect === 'postgresql'; + } + + convert(st: JsonAlterViewAlterUsingStatement) { + const { schema, name, toUsing } = st; + + const statement = `ALTER MATERIALIZED VIEW "${schema}"."${name}" SET ACCESS METHOD "${toUsing}";`; + + return statement; + } +} + class PgAlterTableAlterColumnSetGenerated extends Convertor { override can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -573,6 +870,38 @@ class PgAlterTableDropUniqueConstraintConvertor extends Convertor { } } +class PgAlterTableAddCheckConstraintConvertor extends Convertor { + can(statement: JsonCreateCheckConstraint, dialect: Dialect): boolean { + return ( + statement.type === 'create_check_constraint' && dialect === 'postgresql' + ); + } + convert(statement: JsonCreateCheckConstraint): string { + const unsquashed = PgSquasher.unsquashCheck(statement.data); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${unsquashed.name}" CHECK (${unsquashed.value});`; + } +} + +class PgAlterTableDeleteCheckConstraintConvertor extends Convertor { + can(statement: JsonDeleteCheckConstraint, dialect: Dialect): boolean { + return ( + statement.type === 'delete_check_constraint' && dialect === 'postgresql' + ); + } + convert(statement: JsonDeleteCheckConstraint): string { + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.constraintName}";`; + } +} + class MySQLAlterTableAddUniqueConstraintConvertor extends Convertor { can(statement: JsonCreateUniqueConstraint, dialect: Dialect): boolean { return statement.type === 'create_unique_constraint' && dialect === 'mysql'; @@ -597,6 +926,33 @@ class MySQLAlterTableDropUniqueConstraintConvertor extends Convertor { } } +class MySqlAlterTableAddCheckConstraintConvertor extends Convertor { + can(statement: JsonCreateCheckConstraint, dialect: Dialect): boolean { + return ( + statement.type === 'create_check_constraint' && dialect === 'mysql' + ); + } + convert(statement: JsonCreateCheckConstraint): string { + const unsquashed = MySqlSquasher.unsquashCheck(statement.data); + const { tableName } = statement; + + return `ALTER TABLE \`${tableName}\` ADD CONSTRAINT \`${unsquashed.name}\` CHECK (${unsquashed.value});`; + } +} + +class MySqlAlterTableDeleteCheckConstraintConvertor extends Convertor { + can(statement: JsonDeleteCheckConstraint, dialect: Dialect): boolean { + return ( + statement.type === 'delete_check_constraint' && dialect === 'mysql' + ); + } + convert(statement: JsonDeleteCheckConstraint): string { + const { tableName } = statement; + + return `ALTER TABLE \`${tableName}\` DROP CONSTRAINT \`${statement.constraintName}\`;`; + } +} + class CreatePgSequenceConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_sequence' && dialect === 'postgresql'; @@ -694,22 +1050,39 @@ class CreateTypeEnumConvertor extends Convertor { convert(st: JsonCreateEnumStatement) { const { name, values, schema } = st; - const tableNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; + const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; let valuesStatement = '('; valuesStatement += values.map((it) => `'${it}'`).join(', '); valuesStatement += ')'; - let statement = 'DO $$ BEGIN'; - statement += '\n'; - statement += ` CREATE TYPE ${tableNameWithSchema} AS ENUM${valuesStatement};`; - statement += '\n'; - statement += 'EXCEPTION'; - statement += '\n'; - statement += ' WHEN duplicate_object THEN null;'; - statement += '\n'; - statement += 'END $$;'; - statement += '\n'; + // TODO do we need this? + // let statement = 'DO $$ BEGIN'; + // statement += '\n'; + let statement = `CREATE TYPE ${enumNameWithSchema} AS ENUM${valuesStatement};`; + // statement += '\n'; + // statement += 'EXCEPTION'; + // statement += '\n'; + // statement += ' WHEN duplicate_object THEN null;'; + // statement += '\n'; + // statement += 'END $$;'; + // statement += '\n'; + return statement; + } +} + +class DropTypeEnumConvertor extends Convertor { + can(statement: JsonStatement): boolean { + return statement.type === 'drop_type_enum'; + } + + convert(st: JsonDropEnumStatement) { + const { name, schema } = st; + + const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; + + let statement = `DROP TYPE ${enumNameWithSchema};`; + return statement; } } @@ -720,9 +1093,74 @@ class AlterTypeAddValueConvertor extends Convertor { } convert(st: JsonAddValueToEnumStatement) { - const { name, schema, value } = st; - const schemaPrefix = schema && schema !== 'public' ? `"${schema}".` : ''; - return `ALTER TYPE ${schemaPrefix}"${name}" ADD VALUE '${value}';`; + const { name, schema, value, before } = st; + + const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; + + return `ALTER TYPE ${enumNameWithSchema} ADD VALUE '${value}'${before.length ? ` BEFORE '${before}'` : ''};`; + } +} + +class AlterTypeSetSchemaConvertor extends Convertor { + can(statement: JsonStatement): boolean { + return statement.type === 'move_type_enum'; + } + + convert(st: JsonMoveEnumStatement) { + const { name, schemaFrom, schemaTo } = st; + + const enumNameWithSchema = schemaFrom ? `"${schemaFrom}"."${name}"` : `"${name}"`; + + return `ALTER TYPE ${enumNameWithSchema} SET SCHEMA "${schemaTo}";`; + } +} + +class AlterRenameTypeConvertor extends Convertor { + can(statement: JsonStatement): boolean { + return statement.type === 'rename_type_enum'; + } + + convert(st: JsonRenameEnumStatement) { + const { nameTo, nameFrom, schema } = st; + + const enumNameWithSchema = schema ? `"${schema}"."${nameFrom}"` : `"${nameFrom}"`; + + return `ALTER TYPE ${enumNameWithSchema} RENAME TO "${nameTo}";`; + } +} + +class AlterTypeDropValueConvertor extends Convertor { + can(statement: JsonStatement): boolean { + return statement.type === 'alter_type_drop_value'; + } + + convert(st: JsonDropValueFromEnumStatement) { + const { columnsWithEnum, name, newValues, schema } = st; + + const statements: string[] = []; + + for (const withEnum of columnsWithEnum) { + statements.push( + `ALTER TABLE "${withEnum.schema}"."${withEnum.table}" ALTER COLUMN "${withEnum.column}" SET DATA TYPE text;`, + ); + } + + statements.push(new DropTypeEnumConvertor().convert({ name: name, schema, type: 'drop_type_enum' })); + + statements.push(new CreateTypeEnumConvertor().convert({ + name: name, + schema: schema, + values: newValues, + type: 'create_type_enum', + })); + + for (const withEnum of columnsWithEnum) { + statements.push( + `ALTER TABLE "${withEnum.schema}"."${withEnum.table}" ALTER COLUMN "${withEnum.column}" SET DATA TYPE "${schema}"."${name}" USING "${withEnum.column}"::"${schema}"."${name}";`, + ); + } + + return statements; } } @@ -1450,7 +1888,9 @@ export class LibSQLModifyColumn extends Convertor { || statement.type === 'alter_table_alter_column_drop_notnull' || statement.type === 'alter_table_alter_column_set_notnull' || statement.type === 'alter_table_alter_column_set_default' - || statement.type === 'alter_table_alter_column_drop_default') + || statement.type === 'alter_table_alter_column_drop_default' + || statement.type === 'create_check_constraint' + || statement.type === 'delete_check_constraint') && dialect === 'turso' ); } @@ -2368,7 +2808,7 @@ class SQLiteRecreateTableConvertor extends Convertor { } convert(statement: JsonRecreateTableStatement): string | string[] { - const { tableName, columns, compositePKs, referenceData } = statement; + const { tableName, columns, compositePKs, referenceData, checkConstraints } = statement; const columnNames = columns.map((it) => `"${it.name}"`).join(', '); const newTableName = `__new_${tableName}`; @@ -2377,6 +2817,12 @@ class SQLiteRecreateTableConvertor extends Convertor { sqlStatements.push(`PRAGMA foreign_keys=OFF;`); + // map all possible variants + const mappedCheckConstraints: string[] = checkConstraints.map((it) => + it.replaceAll(`"${tableName}".`, `"${newTableName}".`).replaceAll(`\`${tableName}\`.`, `\`${newTableName}\`.`) + .replaceAll(`${tableName}.`, `${newTableName}.`).replaceAll(`'${tableName}'.`, `'${newTableName}'.`) + ); + // create new table sqlStatements.push( new SQLiteCreateTableConvertor().convert({ @@ -2385,6 +2831,7 @@ class SQLiteRecreateTableConvertor extends Convertor { columns, referenceData, compositePKs, + checkConstraints: mappedCheckConstraints, }), ); @@ -2428,13 +2875,18 @@ class LibSQLRecreateTableConvertor extends Convertor { } convert(statement: JsonRecreateTableStatement): string[] { - const { tableName, columns, compositePKs, referenceData } = statement; + const { tableName, columns, compositePKs, referenceData, checkConstraints } = statement; const columnNames = columns.map((it) => `"${it.name}"`).join(', '); const newTableName = `__new_${tableName}`; const sqlStatements: string[] = []; + const mappedCheckConstraints: string[] = checkConstraints.map((it) => + it.replaceAll(`"${tableName}".`, `"${newTableName}".`).replaceAll(`\`${tableName}\`.`, `\`${newTableName}\`.`) + .replaceAll(`${tableName}.`, `${newTableName}.`).replaceAll(`'${tableName}'.`, `\`${newTableName}\`.`) + ); + sqlStatements.push(`PRAGMA foreign_keys=OFF;`); // create new table @@ -2445,6 +2897,7 @@ class LibSQLRecreateTableConvertor extends Convertor { columns, referenceData, compositePKs, + checkConstraints: mappedCheckConstraints, }), ); @@ -2486,7 +2939,29 @@ convertors.push(new SQLiteCreateTableConvertor()); convertors.push(new SQLiteRecreateTableConvertor()); convertors.push(new LibSQLRecreateTableConvertor()); +convertors.push(new PgCreateViewConvertor()); +convertors.push(new PgDropViewConvertor()); +convertors.push(new PgRenameViewConvertor()); +convertors.push(new PgAlterViewSchemaConvertor()); +convertors.push(new PgAlterViewAddWithOptionConvertor()); +convertors.push(new PgAlterViewDropWithOptionConvertor()); +convertors.push(new PgAlterViewAlterTablespaceConvertor()); +convertors.push(new PgAlterViewAlterUsingConvertor()); + +convertors.push(new MySqlCreateViewConvertor()); +convertors.push(new MySqlDropViewConvertor()); +convertors.push(new MySqlRenameViewConvertor()); +convertors.push(new MySqlAlterViewConvertor()); + +convertors.push(new SqliteCreateViewConvertor()); +convertors.push(new SqliteDropViewConvertor()); + convertors.push(new CreateTypeEnumConvertor()); +convertors.push(new DropTypeEnumConvertor()); +convertors.push(new AlterTypeAddValueConvertor()); +convertors.push(new AlterTypeSetSchemaConvertor()); +convertors.push(new AlterRenameTypeConvertor()); +convertors.push(new AlterTypeDropValueConvertor()); convertors.push(new CreatePgSequenceConvertor()); convertors.push(new DropPgSequenceConvertor()); @@ -2519,6 +2994,11 @@ convertors.push(new PgAlterTableAlterColumnSetTypeConvertor()); convertors.push(new PgAlterTableAddUniqueConstraintConvertor()); convertors.push(new PgAlterTableDropUniqueConstraintConvertor()); +convertors.push(new PgAlterTableAddCheckConstraintConvertor()); +convertors.push(new PgAlterTableDeleteCheckConstraintConvertor()); +convertors.push(new MySqlAlterTableAddCheckConstraintConvertor()); +convertors.push(new MySqlAlterTableDeleteCheckConstraintConvertor()); + convertors.push(new MySQLAlterTableAddUniqueConstraintConvertor()); convertors.push(new MySQLAlterTableDropUniqueConstraintConvertor()); @@ -2530,8 +3010,6 @@ convertors.push(new PgDropIndexConvertor()); convertors.push(new SqliteDropIndexConvertor()); convertors.push(new MySqlDropIndexConvertor()); -convertors.push(new AlterTypeAddValueConvertor()); - convertors.push(new PgAlterTableAlterColumnSetPrimaryKeyConvertor()); convertors.push(new PgAlterTableAlterColumnDropPrimaryKeyConvertor()); convertors.push(new PgAlterTableAlterColumnSetNotNullConvertor()); diff --git a/drizzle-kit/src/statementCombiner.ts b/drizzle-kit/src/statementCombiner.ts index 2f7b6ddbe..f3ca9789c 100644 --- a/drizzle-kit/src/statementCombiner.ts +++ b/drizzle-kit/src/statementCombiner.ts @@ -10,7 +10,7 @@ export const prepareLibSQLRecreateTable = ( table: SQLiteSchemaSquashed['tables'][keyof SQLiteSchemaSquashed['tables']], action?: 'push', ): (JsonRecreateTableStatement | JsonCreateIndexStatement)[] => { - const { name, columns, uniqueConstraints, indexes } = table; + const { name, columns, uniqueConstraints, indexes, checkConstraints } = table; const composites: string[][] = Object.values(table.compositePrimaryKeys).map( (it) => SQLiteSquasher.unsquashPK(it), @@ -29,6 +29,7 @@ export const prepareLibSQLRecreateTable = ( compositePKs: composites, referenceData: fks, uniqueConstraints: Object.values(uniqueConstraints), + checkConstraints: Object.values(checkConstraints), }, ]; @@ -42,7 +43,7 @@ export const prepareSQLiteRecreateTable = ( table: SQLiteSchemaSquashed['tables'][keyof SQLiteSchemaSquashed['tables']], action?: 'push', ): JsonStatement[] => { - const { name, columns, uniqueConstraints, indexes } = table; + const { name, columns, uniqueConstraints, indexes, checkConstraints } = table; const composites: string[][] = Object.values(table.compositePrimaryKeys).map( (it) => SQLiteSquasher.unsquashPK(it), @@ -61,6 +62,7 @@ export const prepareSQLiteRecreateTable = ( compositePKs: composites, referenceData: fks, uniqueConstraints: Object.values(uniqueConstraints), + checkConstraints: Object.values(checkConstraints), }, ]; @@ -86,6 +88,8 @@ export const libSQLCombineStatements = ( || statement.type === 'create_composite_pk' || statement.type === 'alter_composite_pk' || statement.type === 'delete_composite_pk' + || statement.type === 'create_check_constraint' + || statement.type === 'delete_check_constraint' ) { const tableName = statement.tableName; @@ -122,16 +126,6 @@ export const libSQLCombineStatements = ( ) { const { tableName, columnName, columnPk } = statement; - // const columnIsPartOfUniqueIndex = Object.values( - // json2.tables[tableName].indexes, - // ).some((it) => { - // const unsquashIndex = SQLiteSquasher.unsquashIdx(it); - - // return ( - // unsquashIndex.columns.includes(columnName) && unsquashIndex.isUnique - // ); - // }); - const columnIsPartOfForeignKey = Object.values( json2.tables[tableName].foreignKeys, ).some((it) => { @@ -332,19 +326,21 @@ export const sqliteCombineStatements = ( || statement.type === 'delete_composite_pk' || statement.type === 'create_unique_constraint' || statement.type === 'delete_unique_constraint' + || statement.type === 'create_check_constraint' + || statement.type === 'delete_check_constraint' ) { const tableName = statement.tableName; const statementsForTable = newStatements[tableName]; if (!statementsForTable) { - newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + newStatements[tableName] = prepareSQLiteRecreateTable(json2.tables[tableName], action); continue; } if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); - const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + const preparedStatements = prepareSQLiteRecreateTable(json2.tables[tableName], action); if (wasRename) { newStatements[tableName].push(...preparedStatements); @@ -364,13 +360,13 @@ export const sqliteCombineStatements = ( const statementsForTable = newStatements[tableName]; if (!statementsForTable) { - newStatements[tableName] = prepareLibSQLRecreateTable(json2.tables[tableName], action); + newStatements[tableName] = prepareSQLiteRecreateTable(json2.tables[tableName], action); continue; } if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); - const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + const preparedStatements = prepareSQLiteRecreateTable(json2.tables[tableName], action); if (wasRename) { newStatements[tableName].push(...preparedStatements); @@ -409,7 +405,7 @@ export const sqliteCombineStatements = ( if (!statementsForTable.some(({ type }) => type === 'recreate_table')) { const wasRename = statementsForTable.some(({ type }) => type === 'rename_table'); - const preparedStatements = prepareLibSQLRecreateTable(json2.tables[tableName], action); + const preparedStatements = prepareSQLiteRecreateTable(json2.tables[tableName], action); if (wasRename) { newStatements[tableName].push(...preparedStatements); diff --git a/drizzle-kit/tests/introspect/libsql.test.ts b/drizzle-kit/tests/introspect/libsql.test.ts new file mode 100644 index 000000000..9211989ca --- /dev/null +++ b/drizzle-kit/tests/introspect/libsql.test.ts @@ -0,0 +1,35 @@ +import { createClient } from '@libsql/client'; +import { sql } from 'drizzle-orm'; +import { int, sqliteTable, sqliteView } from 'drizzle-orm/sqlite-core'; +import fs from 'fs'; +import { introspectLibSQLToFile, introspectMySQLToFile, introspectSQLiteToFile } from 'tests/schemaDiffer'; +import { expect, test } from 'vitest'; + +if (!fs.existsSync('tests/introspect/libsql')) { + fs.mkdirSync('tests/introspect/libsql'); +} + +test('view #1', async () => { + const turso = createClient({ + url: ':memory:', + }); + + const users = sqliteTable('users', { id: int('id') }); + const testView = sqliteView('some_view', { id: int('id') }).as( + sql`SELECT * FROM ${users}`, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectLibSQLToFile( + turso, + schema, + 'view-1', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/introspect/mysql.test.ts b/drizzle-kit/tests/introspect/mysql.test.ts index e35b34f40..024300bea 100644 --- a/drizzle-kit/tests/introspect/mysql.test.ts +++ b/drizzle-kit/tests/introspect/mysql.test.ts @@ -1,6 +1,6 @@ import Docker from 'dockerode'; import { SQL, sql } from 'drizzle-orm'; -import { char, int, mysqlTable, text, varchar } from 'drizzle-orm/mysql-core'; +import { char, check, int, mysqlTable, mysqlView, serial, text, varchar } from 'drizzle-orm/mysql-core'; import * as fs from 'fs'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; @@ -165,3 +165,78 @@ test('Default value of character type column: varchar', async () => { await client.query(`drop table users;`); }); + +test('introspect checks', async () => { + const schema = { + users: mysqlTable('users', { + id: serial('id'), + name: varchar('name', { length: 255 }), + age: int('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'introspect-checks', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`drop table users;`); +}); + +test('view #1', async () => { + const users = mysqlTable('users', { id: int('id') }); + const testView = mysqlView('some_view', { id: int('id') }).as( + sql`select \`drizzle\`.\`users\`.\`id\` AS \`id\` from \`drizzle\`.\`users\``, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'view-1', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`drop view some_view;`); + await client.query(`drop table users;`); +}); + +test('view #2', async () => { + // await client.query(`drop view some_view;`); + + const users = mysqlTable('some_users', { id: int('id') }); + const testView = mysqlView('some_view', { id: int('id') }).algorithm('temptable').sqlSecurity('definer').as( + sql`SELECT * FROM ${users}`, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'view-2', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`drop table some_users;`); +}); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index e65c0f904..bd8b15ab9 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -5,6 +5,7 @@ import { bigserial, boolean, char, + check, cidr, date, doublePrecision, @@ -17,8 +18,10 @@ import { macaddr8, numeric, pgEnum, + pgMaterializedView, pgSchema, pgTable, + pgView, real, serial, smallint, @@ -29,9 +32,14 @@ import { uuid, varchar, } from 'drizzle-orm/pg-core'; +import fs from 'fs'; import { introspectPgToFile } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; +if (!fs.existsSync('tests/introspect/postgres')) { + fs.mkdirSync('tests/introspect/postgres'); +} + test('basic introspect test', async () => { const client = new PGlite(); @@ -227,6 +235,8 @@ test('instrospect all column types', async () => { smallint: smallint('smallint').default(10), integer: integer('integer').default(10), numeric: numeric('numeric', { precision: 3, scale: 1 }).default('99.9'), + numeric2: numeric('numeric2', { precision: 1, scale: 1 }).default('99.9'), + numeric3: numeric('numeric3').default('99.9'), bigint: bigint('bigint', { mode: 'number' }).default(100), boolean: boolean('boolean').default(true), text: text('test').default('abc'), @@ -405,3 +415,215 @@ test('introspect enum with similar name to native type', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('introspect checks', async () => { + const client = new PGlite(); + + const schema = { + users: pgTable('users', { + id: serial('id'), + name: varchar('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-checks', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect checks from different schemas with same names', async () => { + const client = new PGlite(); + + const mySchema = pgSchema('schema2'); + const schema = { + mySchema, + users: pgTable('users', { + id: serial('id'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + usersInMySchema: mySchema.table('users', { + id: serial('id'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} < 1`), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-checks-diff-schema-same-names', + ['public', 'schema2'], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect view #1', async () => { + const client = new PGlite(); + + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = pgView('some_view').as((qb) => qb.select().from(users)); + const schema = { + view, + users, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-view', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect view #2', async () => { + const client = new PGlite(); + + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = pgView('some_view', { id: integer('asd') }).with({ checkOption: 'cascaded' }).as( + sql`SELECT * FROM ${users}`, + ); + const schema = { + view, + users, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-view-2', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect view in other schema', async () => { + const client = new PGlite(); + + const newSchema = pgSchema('new_schema'); + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = newSchema.view('some_view', { id: integer('asd') }).with({ checkOption: 'cascaded' }).as( + sql`SELECT * FROM ${users}`, + ); + const schema = { + view, + users, + newSchema, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-view-in-other-schema', + ['new_schema'], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect materialized view in other schema', async () => { + const client = new PGlite(); + + const newSchema = pgSchema('new_schema'); + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = newSchema.materializedView('some_view', { id: integer('asd') }).with({ autovacuumEnabled: true }).as( + sql`SELECT * FROM ${users}`, + ); + const schema = { + view, + users, + newSchema, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-mat-view-in-other-schema', + ['new_schema'], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect materialized view #1', async () => { + const client = new PGlite(); + + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = pgMaterializedView('some_view').using('heap').withNoData().as((qb) => qb.select().from(users)); + const schema = { + view, + users, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-materialized-view', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect materialized view #2', async () => { + const client = new PGlite(); + + const users = pgTable('users', { + id: serial('id').primaryKey().notNull(), + name: varchar('users'), + }); + + const view = pgMaterializedView('some_view', { id: integer('asd') }).with({ autovacuumFreezeMinAge: 1 }).as( + sql`SELECT * FROM ${users}`, + ); + const schema = { + view, + users, + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-materialized-view-2', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/introspect/sqlite.test.ts b/drizzle-kit/tests/introspect/sqlite.test.ts index 18473e87b..89cdf590e 100644 --- a/drizzle-kit/tests/introspect/sqlite.test.ts +++ b/drizzle-kit/tests/introspect/sqlite.test.ts @@ -1,6 +1,6 @@ import Database from 'better-sqlite3'; import { SQL, sql } from 'drizzle-orm'; -import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { check, int, sqliteTable, sqliteView, text } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { introspectSQLiteToFile } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; @@ -55,3 +55,49 @@ test('generated always column virtual: link to another column', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('introspect checks', async () => { + const sqlite = new Database(':memory:'); + + const schema = { + users: sqliteTable('users', { + id: int('id'), + name: text('name'), + age: int('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const { statements, sqlStatements } = await introspectSQLiteToFile( + sqlite, + schema, + 'introspect-checks', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('view #1', async () => { + const sqlite = new Database(':memory:'); + + const users = sqliteTable('users', { id: int('id') }); + const testView = sqliteView('some_view', { id: int('id') }).as( + sql`SELECT * FROM ${users}`, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectSQLiteToFile( + sqlite, + schema, + 'view-1', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/libsql-checks.test.ts b/drizzle-kit/tests/libsql-checks.test.ts new file mode 100644 index 000000000..2a3abf2dc --- /dev/null +++ b/drizzle-kit/tests/libsql-checks.test.ts @@ -0,0 +1,308 @@ +import { sql } from 'drizzle-orm'; +import { check, int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasLibSQL } from './schemaDiffer'; + +test('create table with check', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasLibSQL({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_create_table', + tableName: 'users', + columns: [ + { + name: 'id', + type: 'integer', + notNull: true, + primaryKey: true, + autoincrement: false, + }, + { + name: 'age', + type: 'integer', + notNull: false, + primaryKey: false, + autoincrement: false, + }, + ], + compositePKs: [], + checkConstraints: ['some_check_name;"users"."age" > 21'], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("users"."age" > 21) +);\n`); +}); + +test('add check contraint to existing table', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }), + }; + + const { sqlStatements, statements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: ['some_check_name;"users"."age" > 21'], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('drop check contraint to existing table', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }), + }; + + const { sqlStatements, statements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('rename check constraint', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('new_some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [`new_some_check_name;"users"."age" > 21`], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "new_some_check_name" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('rename check constraint', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 10`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [`some_check_name;"users"."age" > 10`], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("__new_users"."age" > 10) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('create checks with same names', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + name: text('name'), + }, (table) => ({ + checkConstraint1: check('some_check_name', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name', sql`${table.name} != 'Alex'`), + })), + }; + + await expect(diffTestSchemasLibSQL({}, to, [])).rejects.toThrowError(); +}); diff --git a/drizzle-kit/tests/libsql-statements.test.ts b/drizzle-kit/tests/libsql-statements.test.ts index 8221e52e0..a7cbc0602 100644 --- a/drizzle-kit/tests/libsql-statements.test.ts +++ b/drizzle-kit/tests/libsql-statements.test.ts @@ -33,6 +33,7 @@ test('drop autoincrement', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -66,6 +67,7 @@ test('set autoincrement', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -427,6 +429,7 @@ test('drop foriegn key', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); @@ -512,6 +515,7 @@ test('alter foriegn key', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); @@ -615,6 +619,7 @@ test('add foriegn key for multiple columns', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], } as JsonRecreateTableStatement); expect(sqlStatements.length).toBe(6); @@ -709,6 +714,7 @@ test('drop foriegn key for multiple columns', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); @@ -850,6 +856,7 @@ test('recreate table with nested references', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); diff --git a/drizzle-kit/tests/libsql-views.test.ts b/drizzle-kit/tests/libsql-views.test.ts new file mode 100644 index 000000000..bf5cdb04e --- /dev/null +++ b/drizzle-kit/tests/libsql-views.test.ts @@ -0,0 +1,218 @@ +import { sql } from 'drizzle-orm'; +import { int, sqliteTable, sqliteView } from 'drizzle-orm/sqlite-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasLibSQL } from './schemaDiffer'; + +test('create view', async () => { + const users = sqliteTable('users', { id: int('id').default(1) }); + const view = sqliteView('view').as((qb) => qb.select().from(users)); + const to = { + users: users, + testView: view, + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_create_table', + tableName: 'users', + columns: [{ + autoincrement: false, + default: 1, + name: 'id', + type: 'integer', + primaryKey: false, + notNull: false, + }], + compositePKs: [], + uniqueConstraints: [], + referenceData: [], + checkConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'view', + definition: 'select "id" from "users"', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer DEFAULT 1 +);\n`); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`view\` AS select "id" from "users";`); +}); + +test('drop view', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `DROP VIEW \`view\`;`, + ); +}); + +test('alter view', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users WHERE users.id = 1`), + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + name: 'view', + type: 'sqlite_create_view', + definition: 'SELECT * FROM users WHERE users.id = 1', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `DROP VIEW \`view\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE VIEW \`view\` AS SELECT * FROM users WHERE users.id = 1;`, + ); +}); + +test('create view with existing flag', async () => { + const view = sqliteView('view', {}).existing(); + const to = { + testView: view, + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL({}, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop view with existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + }; + + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view with existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).existing(), + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, ['view->new_view']); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view and drop existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, ['view->new_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'new_view', + definition: 'SELECT * FROM users', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe('DROP VIEW `view`;'); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users;`); +}); + +test('rename view and alter ".as"', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users WHERE 1=1`), + }; + const { statements, sqlStatements } = await diffTestSchemasLibSQL(from, to, ['view->new_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'new_view', + definition: 'SELECT * FROM users WHERE 1=1', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe('DROP VIEW `view`;'); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users WHERE 1=1;`); +}); diff --git a/drizzle-kit/tests/mysql-checks.test.ts b/drizzle-kit/tests/mysql-checks.test.ts new file mode 100644 index 000000000..82e7a5104 --- /dev/null +++ b/drizzle-kit/tests/mysql-checks.test.ts @@ -0,0 +1,291 @@ +import { sql } from 'drizzle-orm'; +import { check, int, mysqlTable, serial, varchar } from 'drizzle-orm/mysql-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasMysql } from './schemaDiffer'; + +test('create table with check', async (t) => { + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + columns: [ + { + name: 'id', + type: 'serial', + notNull: true, + primaryKey: false, + autoincrement: true, + }, + { + name: 'age', + type: 'int', + notNull: false, + primaryKey: false, + autoincrement: false, + }, + ], + compositePKs: [ + 'users_id;id', + ], + checkConstraints: ['some_check_name;\`users\`.\`age\` > 21'], + compositePkName: 'users_id', + uniqueConstraints: [], + schema: undefined, + internals: { + tables: {}, + indexes: {}, + }, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` serial AUTO_INCREMENT NOT NULL, +\t\`age\` int, +\tCONSTRAINT \`users_id\` PRIMARY KEY(\`id\`), +\tCONSTRAINT \`some_check_name\` CHECK(\`users\`.\`age\` > 21) +);\n`); +}); + +test('add check contraint to existing table', async (t) => { + const from = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }), + }; + + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_check_constraint', + tableName: 'users', + data: 'some_check_name;\`users\`.\`age\` > 21', + schema: '', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` ADD CONSTRAINT \`some_check_name\` CHECK (\`users\`.\`age\` > 21);`, + ); +}); + +test('drop check contraint in existing table', async (t) => { + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }), + }; + + const from = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'delete_check_constraint', + tableName: 'users', + schema: '', + constraintName: 'some_check_name', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` DROP CONSTRAINT \`some_check_name\`;`, + ); +}); + +test('rename check constraint', async (t) => { + const from = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('new_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + constraintName: 'some_check_name', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + data: 'new_check_name;\`users\`.\`age\` > 21', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` DROP CONSTRAINT \`some_check_name\`;`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`users\` ADD CONSTRAINT \`new_check_name\` CHECK (\`users\`.\`age\` > 21);`, + ); +}); + +test('alter check constraint', async (t) => { + const from = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('new_check_name', sql`${table.age} > 10`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql(from, to, []); + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + constraintName: 'some_check_name', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + data: 'new_check_name;\`users\`.\`age\` > 10', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` DROP CONSTRAINT \`some_check_name\`;`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`users\` ADD CONSTRAINT \`new_check_name\` CHECK (\`users\`.\`age\` > 10);`, + ); +}); + +test('alter multiple check constraints', async (t) => { + const from = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + name: varchar('name', { length: 255 }), + }, (table) => ({ + checkConstraint1: check('some_check_name_1', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name_2', sql`${table.name} != 'Alex'`), + })), + }; + + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + name: varchar('name', { length: 255 }), + }, (table) => ({ + checkConstraint1: check('some_check_name_3', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name_4', sql`${table.name} != 'Alex'`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasMysql(from, to, []); + expect(statements.length).toBe(4); + expect(statements[0]).toStrictEqual({ + constraintName: 'some_check_name_1', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + constraintName: 'some_check_name_2', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[2]).toStrictEqual({ + data: 'some_check_name_3;\`users\`.\`age\` > 21', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + expect(statements[3]).toStrictEqual({ + data: "some_check_name_4;\`users\`.\`name\` != 'Alex'", + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE \`users\` DROP CONSTRAINT \`some_check_name_1\`;`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE \`users\` DROP CONSTRAINT \`some_check_name_2\`;`, + ); + expect(sqlStatements[2]).toBe( + `ALTER TABLE \`users\` ADD CONSTRAINT \`some_check_name_3\` CHECK (\`users\`.\`age\` > 21);`, + ); + expect(sqlStatements[3]).toBe( + `ALTER TABLE \`users\` ADD CONSTRAINT \`some_check_name_4\` CHECK (\`users\`.\`name\` != \'Alex\');`, + ); +}); + +test('create checks with same names', async (t) => { + const to = { + users: mysqlTable('users', { + id: serial('id').primaryKey(), + age: int('age'), + name: varchar('name', { length: 255 }), + }, (table) => ({ + checkConstraint1: check('some_check_name', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name', sql`${table.name} != 'Alex'`), + })), + }; + + await expect(diffTestSchemasMysql({}, to, [])).rejects.toThrowError(); +}); diff --git a/drizzle-kit/tests/mysql-schemas.test.ts b/drizzle-kit/tests/mysql-schemas.test.ts index 826585d86..6776700e3 100644 --- a/drizzle-kit/tests/mysql-schemas.test.ts +++ b/drizzle-kit/tests/mysql-schemas.test.ts @@ -129,6 +129,7 @@ test('add table to schema #3', async () => { }, compositePkName: '', compositePKs: [], + checkConstraints: [], }); }); diff --git a/drizzle-kit/tests/mysql-views.test.ts b/drizzle-kit/tests/mysql-views.test.ts new file mode 100644 index 000000000..39cd6c09e --- /dev/null +++ b/drizzle-kit/tests/mysql-views.test.ts @@ -0,0 +1,553 @@ +import { sql } from 'drizzle-orm'; +import { int, mysqlTable, mysqlView } from 'drizzle-orm/mysql-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasMysql } from './schemaDiffer'; + +test('create view #1', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: mysqlView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'mysql_create_view', + name: 'some_view', + algorithm: 'undefined', + replace: false, + definition: 'select `id` from `users`', + withCheckOption: undefined, + sqlSecurity: 'definer', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE ALGORITHM = undefined +SQL SECURITY definer +VIEW \`some_view\` AS (select \`id\` from \`users\`);`); +}); + +test('create view #2', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'mysql_create_view', + name: 'some_view', + algorithm: 'merge', + replace: false, + definition: 'SELECT * FROM \`users\`', + withCheckOption: 'cascaded', + sqlSecurity: 'definer', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS (SELECT * FROM \`users\`) +WITH cascaded CHECK OPTION;`); +}); + +test('create view with existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: mysqlView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop view', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP VIEW \`some_view\`;`); +}); + +test('drop view with existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); +}); + +test('rename view and alter meta options', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'undefined', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'new_some_view', + sqlSecurity: 'definer', + type: 'alter_mysql_view', + withCheckOption: 'cascaded', + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`ALTER ALGORITHM = undefined +SQL SECURITY definer +VIEW \`new_some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('rename view with existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('add meta to view', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'merge', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_mysql_view', + withCheckOption: 'cascaded', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('add meta to view with existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).existing(), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter meta to view', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'merge', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_mysql_view', + withCheckOption: 'cascaded', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('alter meta to view with existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop meta from view', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'undefined', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_mysql_view', + withCheckOption: undefined, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = undefined +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\`;`); +}); + +test('drop meta from view existing flag', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + + view: mysqlView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter view ".as" value', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'some_view', + sqlSecurity: 'invoker', + type: 'mysql_create_view', + withCheckOption: 'cascaded', + replace: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE OR REPLACE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); + +test('rename and alter view ".as" value', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + nameFrom: 'some_view', + nameTo: 'new_some_view', + type: 'rename_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'new_some_view', + sqlSecurity: 'invoker', + type: 'mysql_create_view', + withCheckOption: 'cascaded', + replace: true, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`CREATE OR REPLACE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`new_some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); + +test('set existing', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop existing', async () => { + const users = mysqlTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: mysqlView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: mysqlView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'new_some_view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'new_some_view', + sqlSecurity: 'invoker', + type: 'mysql_create_view', + withCheckOption: 'cascaded', + replace: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP VIEW \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`CREATE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`new_some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); diff --git a/drizzle-kit/tests/mysql.test.ts b/drizzle-kit/tests/mysql.test.ts index b7e8cc1cf..29f2e869a 100644 --- a/drizzle-kit/tests/mysql.test.ts +++ b/drizzle-kit/tests/mysql.test.ts @@ -35,6 +35,7 @@ test('add table #1', async () => { }, uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); }); @@ -64,6 +65,7 @@ test('add table #2', async () => { compositePKs: ['users_id;id'], compositePkName: 'users_id', uniqueConstraints: [], + checkConstraints: [], internals: { tables: {}, indexes: {}, @@ -108,6 +110,7 @@ test('add table #3', async () => { compositePKs: ['users_pk;id'], uniqueConstraints: [], compositePkName: 'users_pk', + checkConstraints: [], internals: { tables: {}, indexes: {}, @@ -136,6 +139,7 @@ test('add table #4', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'create_table', @@ -149,6 +153,7 @@ test('add table #4', async () => { }, uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); }); @@ -192,6 +197,7 @@ test('add table #6', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'drop_table', @@ -227,6 +233,7 @@ test('add table #7', async () => { indexes: {}, }, compositePkName: '', + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'rename_table', @@ -316,6 +323,7 @@ test('change table schema #2', async () => { uniqueConstraints: [], compositePkName: '', compositePKs: [], + checkConstraints: [], internals: { tables: {}, indexes: {}, diff --git a/drizzle-kit/tests/pg-checks.test.ts b/drizzle-kit/tests/pg-checks.test.ts new file mode 100644 index 000000000..1f5e5e1c5 --- /dev/null +++ b/drizzle-kit/tests/pg-checks.test.ts @@ -0,0 +1,280 @@ +import { sql } from 'drizzle-orm'; +import { check, integer, pgTable, serial, varchar } from 'drizzle-orm/pg-core'; +import { JsonCreateTableStatement } from 'src/jsonStatements'; +import { expect, test } from 'vitest'; +import { diffTestSchemas } from './schemaDiffer'; + +test('create table with check', async (t) => { + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [ + { + name: 'id', + type: 'serial', + notNull: true, + primaryKey: true, + }, + { + name: 'age', + type: 'integer', + notNull: false, + primaryKey: false, + }, + ], + compositePKs: [], + checkConstraints: ['some_check_name;"users"."age" > 21'], + compositePkName: '', + uniqueConstraints: [], + } as JsonCreateTableStatement); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" serial PRIMARY KEY NOT NULL, +\t"age" integer, +\tCONSTRAINT "some_check_name" CHECK ("users"."age" > 21) +);\n`); +}); + +test('add check contraint to existing table', async (t) => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }), + }; + + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemas(from, to, []); + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_check_constraint', + tableName: 'users', + schema: '', + data: 'some_check_name;"users"."age" > 21', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "users" ADD CONSTRAINT "some_check_name" CHECK ("users"."age" > 21);`, + ); +}); + +test('drop check contraint in existing table', async (t) => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }), + }; + + const { sqlStatements, statements } = await diffTestSchemas(from, to, []); + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'delete_check_constraint', + tableName: 'users', + schema: '', + constraintName: 'some_check_name', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "users" DROP CONSTRAINT "some_check_name";`, + ); +}); + +test('rename check constraint', async (t) => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('new_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemas(from, to, []); + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + constraintName: 'some_check_name', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + data: 'new_check_name;"users"."age" > 21', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "users" DROP CONSTRAINT "some_check_name";`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE "users" ADD CONSTRAINT "new_check_name" CHECK ("users"."age" > 21);`, + ); +}); + +test('alter check constraint', async (t) => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + }, (table) => ({ + checkConstraint: check('new_check_name', sql`${table.age} > 10`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemas(from, to, []); + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + constraintName: 'some_check_name', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + data: 'new_check_name;"users"."age" > 10', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "users" DROP CONSTRAINT "some_check_name";`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE "users" ADD CONSTRAINT "new_check_name" CHECK ("users"."age" > 10);`, + ); +}); + +test('alter multiple check constraints', async (t) => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + name: varchar('name'), + }, (table) => ({ + checkConstraint1: check('some_check_name_1', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name_2', sql`${table.name} != 'Alex'`), + })), + }; + + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + name: varchar('name'), + }, (table) => ({ + checkConstraint1: check('some_check_name_3', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name_4', sql`${table.name} != 'Alex'`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemas(from, to, []); + expect(statements.length).toBe(4); + expect(statements[0]).toStrictEqual({ + constraintName: 'some_check_name_1', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[1]).toStrictEqual({ + constraintName: 'some_check_name_2', + schema: '', + tableName: 'users', + type: 'delete_check_constraint', + }); + expect(statements[2]).toStrictEqual({ + data: 'some_check_name_3;"users"."age" > 21', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + expect(statements[3]).toStrictEqual({ + data: 'some_check_name_4;"users"."name" != \'Alex\'', + schema: '', + tableName: 'users', + type: 'create_check_constraint', + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "users" DROP CONSTRAINT "some_check_name_1";`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE "users" DROP CONSTRAINT "some_check_name_2";`, + ); + expect(sqlStatements[2]).toBe( + `ALTER TABLE "users" ADD CONSTRAINT "some_check_name_3" CHECK ("users"."age" > 21);`, + ); + expect(sqlStatements[3]).toBe( + `ALTER TABLE "users" ADD CONSTRAINT "some_check_name_4" CHECK ("users"."name" != \'Alex\');`, + ); +}); + +test('create checks with same names', async (t) => { + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + age: integer('age'), + name: varchar('name'), + }, (table) => ({ + checkConstraint1: check('some_check_name', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name', sql`${table.name} != 'Alex'`), + })), + }; + + await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); +}); diff --git a/drizzle-kit/tests/pg-enums.test.ts b/drizzle-kit/tests/pg-enums.test.ts index cd8877a43..99a3dca7e 100644 --- a/drizzle-kit/tests/pg-enums.test.ts +++ b/drizzle-kit/tests/pg-enums.test.ts @@ -7,8 +7,10 @@ test('enums #1', async () => { enum: pgEnum('enum', ['value']), }; - const { statements } = await diffTestSchemas({}, to, []); + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value');`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ name: 'enum', @@ -24,8 +26,10 @@ test('enums #2', async () => { enum: folder.enum('enum', ['value']), }; - const { statements } = await diffTestSchemas({}, to, []); + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TYPE "folder"."enum" AS ENUM('value');`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ name: 'enum', @@ -40,8 +44,10 @@ test('enums #3', async () => { enum: pgEnum('enum', ['value']), }; - const { statements } = await diffTestSchemas(from, {}, []); + const { statements, sqlStatements } = await diffTestSchemas(from, {}, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'drop_type_enum', @@ -57,8 +63,10 @@ test('enums #4', async () => { enum: folder.enum('enum', ['value']), }; - const { statements } = await diffTestSchemas(from, {}, []); + const { statements, sqlStatements } = await diffTestSchemas(from, {}, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP TYPE "folder"."enum";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'drop_type_enum', @@ -81,8 +89,10 @@ test('enums #5', async () => { enum: folder2.enum('enum', ['value']), }; - const { statements } = await diffTestSchemas(from, to, ['folder1->folder2']); + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['folder1->folder2']); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER SCHEMA "folder1" RENAME TO "folder2";\n`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'rename_schema', @@ -107,10 +117,12 @@ test('enums #6', async () => { enum: folder2.enum('enum', ['value']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'folder1.enum->folder2.enum', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "folder1"."enum" SET SCHEMA "folder2";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -129,8 +141,10 @@ test('enums #7', async () => { enum: pgEnum('enum', ['value1', 'value2']), }; - const { statements } = await diffTestSchemas(from, to, []); + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum" ADD VALUE 'value2';`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'alter_type_add_value', @@ -150,8 +164,11 @@ test('enums #8', async () => { enum: pgEnum('enum', ['value1', 'value2', 'value3']), }; - const { statements } = await diffTestSchemas(from, to, []); + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum" ADD VALUE 'value2';`); + expect(sqlStatements[1]).toBe(`ALTER TYPE "public"."enum" ADD VALUE 'value3';`); expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ type: 'alter_type_add_value', @@ -179,8 +196,10 @@ test('enums #9', async () => { enum: pgEnum('enum', ['value1', 'value2', 'value3']), }; - const { statements } = await diffTestSchemas(from, to, []); + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum" ADD VALUE 'value2' BEFORE 'value3';`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'alter_type_add_value', @@ -201,8 +220,10 @@ test('enums #10', async () => { enum: schema.enum('enum', ['value1', 'value2']), }; - const { statements } = await diffTestSchemas(from, to, []); + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "folder"."enum" ADD VALUE 'value2';`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'alter_type_add_value', @@ -223,10 +244,12 @@ test('enums #11', async () => { enum: pgEnum('enum', ['value1']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'folder1.enum->public.enum', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "folder1"."enum" SET SCHEMA "public";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -246,10 +269,12 @@ test('enums #12', async () => { enum: schema1.enum('enum', ['value1']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'public.enum->folder1.enum', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum" SET SCHEMA "folder1";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -268,10 +293,12 @@ test('enums #13', async () => { enum: pgEnum('enum2', ['value1']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'public.enum1->public.enum2', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum1" RENAME TO "enum2";`); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'rename_type_enum', @@ -292,10 +319,13 @@ test('enums #14', async () => { enum: folder2.enum('enum2', ['value1']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'folder1.enum1->folder2.enum2', ]); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TYPE "folder1"."enum1" SET SCHEMA "folder2";`); + expect(sqlStatements[1]).toBe(`ALTER TYPE "folder2"."enum1" RENAME TO "enum2";`); expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -322,10 +352,16 @@ test('enums #15', async () => { enum: folder2.enum('enum2', ['value1', 'value2', 'value3', 'value4']), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'folder1.enum1->folder2.enum2', ]); + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe(`ALTER TYPE "folder1"."enum1" SET SCHEMA "folder2";`); + expect(sqlStatements[1]).toBe(`ALTER TYPE "folder2"."enum1" RENAME TO "enum2";`); + expect(sqlStatements[2]).toBe(`ALTER TYPE "folder2"."enum2" ADD VALUE 'value2' BEFORE 'value4';`); + expect(sqlStatements[3]).toBe(`ALTER TYPE "folder2"."enum2" ADD VALUE 'value3' BEFORE 'value4';`); + expect(statements.length).toBe(4); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -373,10 +409,13 @@ test('enums #16', async () => { }), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'public.enum1->public.enum2', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum1" RENAME TO "enum2";`); + expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'rename_type_enum', @@ -405,10 +444,14 @@ test('enums #17', async () => { }), }; - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'public.enum1->schema.enum1', ]); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER TYPE "public"."enum1" SET SCHEMA "schema";`); + + expect(sqlStatements.length).toBe(1); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -440,10 +483,14 @@ test('enums #18', async () => { }; // change name and schema of the enum, no table changes - const { statements } = await diffTestSchemas(from, to, [ + const { statements, sqlStatements } = await diffTestSchemas(from, to, [ 'schema1.enum1->schema2.enum2', ]); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER TYPE "schema1"."enum1" SET SCHEMA "schema2";`); + expect(sqlStatements[1]).toBe(`ALTER TYPE "schema2"."enum1" RENAME TO "enum2";`); + expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ type: 'move_type_enum', @@ -458,3 +505,176 @@ test('enums #18', async () => { schema: 'schema2', }); }); + +test('drop enum value', async () => { + const enum1 = pgEnum('enum', ['value1', 'value2', 'value3']); + + const from = { + enum1, + }; + + const enum2 = pgEnum('enum', ['value1', 'value3']); + const to = { + enum2, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP TYPE "public"."enum";`); + expect(sqlStatements[1]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value1', 'value3');`); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columnsWithEnum: [], + deletedValues: [ + 'value2', + ], + name: 'enum', + newValues: [ + 'value1', + 'value3', + ], + schema: 'public', + type: 'alter_type_drop_value', + }); +}); + +test('drop enum value. enum is columns data type', async () => { + const enum1 = pgEnum('enum', ['value1', 'value2', 'value3']); + + const schema = pgSchema('new_schema'); + + const from = { + schema, + enum1, + table: pgTable('table', { + column: enum1('column'), + }), + table2: schema.table('table', { + column: enum1('column'), + }), + }; + + const enum2 = pgEnum('enum', ['value1', 'value3']); + const to = { + schema, + enum2, + table: pgTable('table', { + column: enum1('column'), + }), + table2: schema.table('table', { + column: enum1('column'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE text;`); + expect(sqlStatements[1]).toBe(`ALTER TABLE "new_schema"."table" ALTER COLUMN "column" SET DATA TYPE text;`); + expect(sqlStatements[2]).toBe(`DROP TYPE "public"."enum";`); + expect(sqlStatements[3]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value1', 'value3');`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE "public"."enum" USING "column"::"public"."enum";`, + ); + expect(sqlStatements[5]).toBe( + `ALTER TABLE "new_schema"."table" ALTER COLUMN "column" SET DATA TYPE "public"."enum" USING "column"::"public"."enum";`, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columnsWithEnum: [ + { + column: 'column', + schema: 'public', + table: 'table', + }, + { + column: 'column', + schema: 'new_schema', + table: 'table', + }, + ], + deletedValues: [ + 'value2', + ], + name: 'enum', + newValues: [ + 'value1', + 'value3', + ], + schema: 'public', + type: 'alter_type_drop_value', + }); +}); + +test('shuffle enum values', async () => { + const enum1 = pgEnum('enum', ['value1', 'value2', 'value3']); + + const schema = pgSchema('new_schema'); + + const from = { + schema, + enum1, + table: pgTable('table', { + column: enum1('column'), + }), + table2: schema.table('table', { + column: enum1('column'), + }), + }; + + const enum2 = pgEnum('enum', ['value1', 'value3', 'value2']); + const to = { + schema, + enum2, + table: pgTable('table', { + column: enum1('column'), + }), + table2: schema.table('table', { + column: enum1('column'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe(`ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE text;`); + expect(sqlStatements[1]).toBe(`ALTER TABLE "new_schema"."table" ALTER COLUMN "column" SET DATA TYPE text;`); + expect(sqlStatements[2]).toBe(`DROP TYPE "public"."enum";`); + expect(sqlStatements[3]).toBe(`CREATE TYPE "public"."enum" AS ENUM('value1', 'value3', 'value2');`); + expect(sqlStatements[4]).toBe( + `ALTER TABLE "public"."table" ALTER COLUMN "column" SET DATA TYPE "public"."enum" USING "column"::"public"."enum";`, + ); + expect(sqlStatements[5]).toBe( + `ALTER TABLE "new_schema"."table" ALTER COLUMN "column" SET DATA TYPE "public"."enum" USING "column"::"public"."enum";`, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columnsWithEnum: [ + { + column: 'column', + schema: 'public', + table: 'table', + }, + { + column: 'column', + schema: 'new_schema', + table: 'table', + }, + ], + deletedValues: [ + 'value3', + ], + name: 'enum', + newValues: [ + 'value1', + 'value3', + 'value2', + ], + schema: 'public', + type: 'alter_type_drop_value', + }); +}); diff --git a/drizzle-kit/tests/pg-identity.test.ts b/drizzle-kit/tests/pg-identity.test.ts index 906d812d4..7e0854b67 100644 --- a/drizzle-kit/tests/pg-identity.test.ts +++ b/drizzle-kit/tests/pg-identity.test.ts @@ -48,6 +48,7 @@ test('create table: identity always/by default - no params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -86,6 +87,7 @@ test('create table: identity always/by default - few params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -128,6 +130,7 @@ test('create table: identity always/by default - all params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index 79a21a695..0648459b4 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -35,6 +35,7 @@ test('add table #1', async () => { columns: [], compositePKs: [], uniqueConstraints: [], + checkConstraints: [], compositePkName: '', }); }); @@ -63,6 +64,7 @@ test('add table #2', async () => { ], compositePKs: [], uniqueConstraints: [], + checkConstraints: [], compositePkName: '', }); }); @@ -102,6 +104,7 @@ test('add table #3', async () => { ], compositePKs: ['id;users_pk'], uniqueConstraints: [], + checkConstraints: [], compositePkName: 'users_pk', }); }); @@ -122,6 +125,7 @@ test('add table #4', async () => { columns: [], compositePKs: [], uniqueConstraints: [], + checkConstraints: [], compositePkName: '', }); expect(statements[1]).toStrictEqual({ @@ -131,6 +135,7 @@ test('add table #4', async () => { columns: [], compositePKs: [], uniqueConstraints: [], + checkConstraints: [], compositePkName: '', }); }); @@ -157,6 +162,7 @@ test('add table #5', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); }); @@ -180,6 +186,7 @@ test('add table #6', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'drop_table', @@ -211,6 +218,7 @@ test('add table #7', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'rename_table', @@ -267,6 +275,7 @@ test('multiproject schema add table #1', async () => { compositePKs: [], compositePkName: '', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -360,6 +369,7 @@ test('add schema + table #1', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + checkConstraints: [], }); }); diff --git a/drizzle-kit/tests/pg-views.test.ts b/drizzle-kit/tests/pg-views.test.ts new file mode 100644 index 000000000..2874caf5b --- /dev/null +++ b/drizzle-kit/tests/pg-views.test.ts @@ -0,0 +1,1911 @@ +import { sql } from 'drizzle-orm'; +import { integer, pgMaterializedView, pgSchema, pgTable, pgView } from 'drizzle-orm/pg-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemas } from './schemaDiffer'; + +test('create table and view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view: pgView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + checkConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view', + definition: `select "id" from "users"`, + schema: 'public', + with: undefined, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (select "id" from "users");`); +}); + +test('create table and view #2', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + checkConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view', + definition: `SELECT * FROM "users"`, + schema: 'public', + with: undefined, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (SELECT * FROM "users");`); +}); + +test('create table and view #3', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgView('some_view1', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }).as(sql`SELECT * FROM ${users}`), + view2: pgView('some_view2').with({ + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(3); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + checkConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view1', + definition: `SELECT * FROM "users"`, + schema: 'public', + with: { + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + expect(statements[2]).toStrictEqual({ + type: 'create_view', + name: 'some_view2', + definition: `select "id" from "users"`, + schema: 'public', + with: { + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(3); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe( + `CREATE VIEW "public"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "users");`, + ); + expect(sqlStatements[2]).toBe( + `CREATE VIEW "public"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "users");`, + ); +}); + +test('create table and view #4', async () => { + const schema = pgSchema('new_schema'); + + const users = schema.table('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + schema, + users: users, + view1: schema.view('some_view1', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }).as(sql`SELECT * FROM ${users}`), + view2: schema.view('some_view2').with({ + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(4); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: 'new_schema', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + checkConstraints: [], + }); + expect(statements[2]).toStrictEqual({ + type: 'create_view', + name: 'some_view1', + definition: `SELECT * FROM "new_schema"."users"`, + schema: 'new_schema', + with: { + checkOption: 'local', + securityBarrier: false, + securityInvoker: true, + }, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + expect(statements[3]).toStrictEqual({ + type: 'create_view', + name: 'some_view2', + definition: `select "id" from "new_schema"."users"`, + schema: 'new_schema', + with: { + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: false, + }, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(4); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); + expect(sqlStatements[1]).toBe(`CREATE TABLE IF NOT EXISTS "new_schema"."users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[2]).toBe( + `CREATE VIEW "new_schema"."some_view1" WITH (check_option = local, security_barrier = false, security_invoker = true) AS (SELECT * FROM "new_schema"."users");`, + ); + expect(sqlStatements[3]).toBe( + `CREATE VIEW "new_schema"."some_view2" WITH (check_option = cascaded, security_barrier = true, security_invoker = false) AS (select "id" from "new_schema"."users");`, + ); +}); + +test('create table and view #5', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + view2: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); +}); + +test('create table and view #6', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgView('some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + columns: [ + { + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + ], + compositePKs: [], + compositePkName: '', + schema: '', + tableName: 'users', + type: 'create_table', + uniqueConstraints: [], + checkConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + definition: 'SELECT * FROM "users"', + name: 'some_view', + schema: 'public', + type: 'create_view', + with: { + checkOption: 'cascaded', + }, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe( + `CREATE VIEW "public"."some_view" WITH (check_option = cascaded) AS (SELECT * FROM "users");`, + ); +}); + +test('create view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + }; + + const to = { + users: users, + view1: pgView('some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('create table and materialized view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + checkConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view', + definition: `select "id" from "users"`, + schema: 'public', + with: undefined, + materialized: true, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe(`CREATE MATERIALIZED VIEW "public"."some_view" AS (select "id" from "users");`); +}); + +test('create table and materialized view #2', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + checkConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view', + definition: `SELECT * FROM "users"`, + schema: 'public', + with: undefined, + materialized: true, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe(`CREATE MATERIALIZED VIEW "public"."some_view" AS (SELECT * FROM "users");`); +}); + +test('create table and materialized view #3', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgMaterializedView('some_view1', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + view2: pgMaterializedView('some_view2').tablespace('some_tablespace').using('heap').withNoData().with({ + autovacuumEnabled: true, + autovacuumFreezeMaxAge: 1, + autovacuumFreezeMinAge: 1, + autovacuumFreezeTableAge: 1, + autovacuumMultixactFreezeMaxAge: 1, + autovacuumMultixactFreezeMinAge: 1, + autovacuumMultixactFreezeTableAge: 1, + autovacuumVacuumCostDelay: 1, + autovacuumVacuumCostLimit: 1, + autovacuumVacuumScaleFactor: 1, + autovacuumVacuumThreshold: 1, + fillfactor: 1, + logAutovacuumMinDuration: 1, + parallelWorkers: 1, + toastTupleTarget: 1, + userCatalogTable: true, + vacuumIndexCleanup: 'off', + vacuumTruncate: false, + }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(3); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: '', + columns: [{ + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }], + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + checkConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + type: 'create_view', + name: 'some_view1', + definition: `SELECT * FROM "users"`, + schema: 'public', + with: undefined, + materialized: true, + withNoData: false, + using: undefined, + tablespace: undefined, + }); + expect(statements[2]).toStrictEqual({ + type: 'create_view', + name: 'some_view2', + definition: `select "id" from "users"`, + schema: 'public', + with: { + autovacuumEnabled: true, + autovacuumFreezeMaxAge: 1, + autovacuumFreezeMinAge: 1, + autovacuumFreezeTableAge: 1, + autovacuumMultixactFreezeMaxAge: 1, + autovacuumMultixactFreezeMinAge: 1, + autovacuumMultixactFreezeTableAge: 1, + autovacuumVacuumCostDelay: 1, + autovacuumVacuumCostLimit: 1, + autovacuumVacuumScaleFactor: 1, + autovacuumVacuumThreshold: 1, + fillfactor: 1, + logAutovacuumMinDuration: 1, + parallelWorkers: 1, + toastTupleTarget: 1, + userCatalogTable: true, + vacuumIndexCleanup: 'off', + vacuumTruncate: false, + }, + materialized: true, + tablespace: 'some_tablespace', + using: 'heap', + withNoData: true, + }); + + expect(sqlStatements.length).toBe(3); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe( + `CREATE MATERIALIZED VIEW "public"."some_view1" AS (SELECT * FROM "users");`, + ); + expect(sqlStatements[2]).toBe( + `CREATE MATERIALIZED VIEW "public"."some_view2" USING "heap" WITH (autovacuum_enabled = true, autovacuum_freeze_max_age = 1, autovacuum_freeze_min_age = 1, autovacuum_freeze_table_age = 1, autovacuum_multixact_freeze_max_age = 1, autovacuum_multixact_freeze_min_age = 1, autovacuum_multixact_freeze_table_age = 1, autovacuum_vacuum_cost_delay = 1, autovacuum_vacuum_cost_limit = 1, autovacuum_vacuum_scale_factor = 1, autovacuum_vacuum_threshold = 1, fillfactor = 1, log_autovacuum_min_duration = 1, parallel_workers = 1, toast_tuple_target = 1, user_catalog_table = true, vacuum_index_cleanup = off, vacuum_truncate = false) TABLESPACE some_tablespace AS (select "id" from "users") WITH NO DATA;`, + ); +}); + +test('create table and materialized view #4', async () => { + // same names + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + view2: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + await expect(diffTestSchemas({}, to, [])).rejects.toThrowError(); +}); + +test('create table and materialized view #5', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + const to = { + users: users, + view1: pgMaterializedView('some_view', { id: integer('id') }).with({ autovacuumFreezeMinAge: 14 }).as( + sql`SELECT * FROM ${users}`, + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + columns: [ + { + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + ], + compositePKs: [], + compositePkName: '', + schema: '', + tableName: 'users', + type: 'create_table', + uniqueConstraints: [], + checkConstraints: [], + }); + expect(statements[1]).toEqual({ + definition: 'SELECT * FROM "users"', + name: 'some_view', + schema: 'public', + type: 'create_view', + with: { + autovacuumFreezeMinAge: 14, + }, + materialized: true, + tablespace: undefined, + using: undefined, + withNoData: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( +\t"id" integer PRIMARY KEY NOT NULL +);\n`); + expect(sqlStatements[1]).toBe( + `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_freeze_min_age = 14) AS (SELECT * FROM "users");`, + ); +}); + +test('create materialized view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + }; + + const to = { + users: users, + view1: pgMaterializedView('some_view', { id: integer('id') }).with({ autovacuumEnabled: true }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view', + schema: 'public', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP VIEW "public"."some_view";`); +}); + +test('drop view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop materialized view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM ${users}`), + }; + + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view', + schema: 'public', + materialized: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."some_view";`); +}); + +test('drop materialized view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view #1', async () => { + const from = { + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + view: pgView('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + schema: 'public', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER VIEW "public"."some_view" RENAME TO "new_some_view";`); +}); + +test('rename view with existing flag', async () => { + const from = { + view: pgView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + view: pgView('new_some_view', { id: integer('id') }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename materialized view #1', async () => { + const from = { + view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + view: pgMaterializedView('new_some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + schema: 'public', + materialized: true, + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER MATERIALIZED VIEW "public"."some_view" RENAME TO "new_some_view";`); +}); + +test('rename materialized view with existing flag', async () => { + const from = { + view: pgMaterializedView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + view: pgMaterializedView('new_some_view', { id: integer('id') }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('view alter schema', async () => { + const schema = pgSchema('new_schema'); + + const from = { + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + schema, + view: schema.view('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(statements[1]).toStrictEqual({ + type: 'alter_view_alter_schema', + toSchema: 'new_schema', + fromSchema: 'public', + name: 'some_view', + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); + expect(sqlStatements[1]).toBe(`ALTER VIEW "public"."some_view" SET SCHEMA "new_schema";`); +}); + +test('view alter schema with existing flag', async () => { + const schema = pgSchema('new_schema'); + + const from = { + view: pgView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + schema, + view: schema.view('some_view', { id: integer('id') }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); +}); + +test('view alter schema for materialized', async () => { + const schema = pgSchema('new_schema'); + + const from = { + view: pgMaterializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + schema, + view: schema.materializedView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(statements[1]).toStrictEqual({ + type: 'alter_view_alter_schema', + toSchema: 'new_schema', + fromSchema: 'public', + name: 'some_view', + materialized: true, + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); + expect(sqlStatements[1]).toBe(`ALTER MATERIALIZED VIEW "public"."some_view" SET SCHEMA "new_schema";`); +}); + +test('view alter schema for materialized with existing flag', async () => { + const schema = pgSchema('new_schema'); + + const from = { + view: pgMaterializedView('some_view', { id: integer('id') }).existing(), + }; + + const to = { + schema, + view: schema.materializedView('some_view', { id: integer('id') }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->new_schema.some_view']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_schema', + name: 'new_schema', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); +}); + +test('add with option to view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').as((qb) => qb.select().from(users)), + }; + + const to = { + users, + view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true }).as((qb) => + qb.select().from(users) + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_add_with_option', + with: { + checkOption: 'cascaded', + securityBarrier: true, + }, + materialized: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER VIEW "public"."some_view" SET (check_option = cascaded, security_barrier = true);`, + ); +}); + +test('add with option to view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', {}).existing(), + }; + + const to = { + users, + view: pgView('some_view', {}).with({ checkOption: 'cascaded', securityBarrier: true }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('add with option to materialized view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), + }; + + const to = { + users, + view: pgMaterializedView('some_view').with({ autovacuumMultixactFreezeMaxAge: 3 }).as((qb) => + qb.select().from(users) + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_add_with_option', + with: { + autovacuumMultixactFreezeMaxAge: 3, + }, + materialized: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET (autovacuum_multixact_freeze_max_age = 3);`, + ); +}); + +test('add with option to materialized view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', {}).existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', {}).with({ autovacuumMultixactFreezeMaxAge: 3 }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop with option from view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_drop_with_option', + materialized: false, + with: { + checkOption: 'cascaded', + securityBarrier: true, + securityInvoker: true, + }, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER VIEW "public"."some_view" RESET (check_option, security_barrier, security_invoker);`, + ); +}); + +test('drop with option from view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', {}).with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }) + .existing(), + }; + + const to = { + users, + view: pgView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop with option from materialized view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, autovacuumFreezeMaxAge: 10 }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgMaterializedView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_drop_with_option', + materialized: true, + with: { + autovacuumEnabled: true, + autovacuumFreezeMaxAge: 10, + }, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" RESET (autovacuum_enabled, autovacuum_freeze_max_age);`, + ); +}); + +test('drop with option from materialized view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true, autovacuumFreezeMaxAge: 10 }).existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter with option in view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').with({ securityBarrier: true, securityInvoker: true }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgView('some_view').with({ securityBarrier: true }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_drop_with_option', + with: { + securityInvoker: true, + }, + materialized: false, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER VIEW "public"."some_view" RESET (security_invoker);`, + ); +}); + +test('alter with option in view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', {}).with({ securityBarrier: true, securityInvoker: true }).existing(), + }; + + const to = { + users, + view: pgView('some_view', {}).with({ securityBarrier: true }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter with option in materialized view #1', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, autovacuumVacuumScaleFactor: 1 }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgMaterializedView('some_view').with({ autovacuumEnabled: true }).as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'some_view', + schema: 'public', + type: 'alter_view_drop_with_option', + with: { + autovacuumVacuumScaleFactor: 1, + }, + materialized: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" RESET (autovacuum_vacuum_scale_factor);`, + ); +}); + +test('alter with option in materialized view with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true, autovacuumVacuumScaleFactor: 1 }) + .existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', {}).with({ autovacuumEnabled: true }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter with option in view #2', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view').with({ checkOption: 'local', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.selectDistinct().from(users) + ), + }; + + const to = { + users, + view: pgView('some_view').with({ checkOption: 'cascaded', securityBarrier: true, securityInvoker: true }).as((qb) => + qb.selectDistinct().from(users) + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_view_add_with_option', + name: 'some_view', + schema: 'public', + with: { + checkOption: 'cascaded', + }, + materialized: false, + }); + + expect(sqlStatements.length).toBe(1); + + expect(sqlStatements[0]).toBe( + `ALTER VIEW "public"."some_view" SET (check_option = cascaded);`, + ); +}); + +test('alter with option in materialized view #2', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view').with({ autovacuumEnabled: true, fillfactor: 1 }).as((qb) => + qb.select().from(users) + ), + }; + + const to = { + users, + view: pgMaterializedView('some_view').with({ autovacuumEnabled: false, fillfactor: 1 }).as((qb) => + qb.select().from(users) + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'alter_view_add_with_option', + name: 'some_view', + schema: 'public', + with: { + autovacuumEnabled: false, + }, + materialized: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET (autovacuum_enabled = false);`, + ); +}); + +test('alter view ".as" value', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: true, + securityInvoker: true, + }).as(sql`SELECT '123'`), + }; + + const to = { + users, + view: pgView('some_view', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: true, + securityInvoker: true, + }).as(sql`SELECT '1234'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual( + { + name: 'some_view', + schema: 'public', + type: 'drop_view', + }, + ); + expect(statements[1]).toStrictEqual( + { + definition: "SELECT '1234'", + name: 'some_view', + schema: 'public', + type: 'create_view', + materialized: false, + with: { + checkOption: 'local', + securityBarrier: true, + securityInvoker: true, + }, + withNoData: false, + tablespace: undefined, + using: undefined, + }, + ); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe('DROP VIEW "public"."some_view";'); + expect(sqlStatements[1]).toBe( + `CREATE VIEW "public"."some_view" WITH (check_option = local, security_barrier = true, security_invoker = true) AS (SELECT '1234');`, + ); +}); + +test('alter view ".as" value with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: true, + securityInvoker: true, + }).existing(), + }; + + const to = { + users, + view: pgView('some_view', { id: integer('id') }).with({ + checkOption: 'local', + securityBarrier: true, + securityInvoker: true, + }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter materialized view ".as" value', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT '123'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT '1234'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual( + { + name: 'some_view', + schema: 'public', + type: 'drop_view', + materialized: true, + }, + ); + expect(statements[1]).toStrictEqual( + { + definition: "SELECT '1234'", + name: 'some_view', + schema: 'public', + type: 'create_view', + with: { + autovacuumVacuumCostLimit: 1, + }, + materialized: true, + withNoData: false, + tablespace: undefined, + using: undefined, + }, + ); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe('DROP MATERIALIZED VIEW "public"."some_view";'); + expect(sqlStatements[1]).toBe( + `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_vacuum_cost_limit = 1) AS (SELECT '1234');`, + ); +}); + +test('alter materialized view ".as" value with existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop existing flag', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toEqual({ + type: 'drop_view', + name: 'some_view', + schema: 'public', + materialized: true, + }); + expect(statements[1]).toEqual({ + definition: "SELECT 'asd'", + materialized: true, + name: 'some_view', + schema: 'public', + tablespace: undefined, + type: 'create_view', + using: undefined, + with: { + autovacuumVacuumCostLimit: 1, + }, + withNoData: false, + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."some_view";`); + expect(sqlStatements[1]).toBe( + `CREATE MATERIALIZED VIEW "public"."some_view" WITH (autovacuum_vacuum_cost_limit = 1) AS (SELECT 'asd');`, + ); +}); + +test('alter tablespace - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('some_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_tablespace', + name: 'some_view', + schema: 'public', + materialized: true, + toTablespace: 'new_tablespace', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE new_tablespace;`, + ); +}); + +test('set tablespace - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_tablespace', + name: 'some_view', + schema: 'public', + materialized: true, + toTablespace: 'new_tablespace', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE new_tablespace;`, + ); +}); + +test('drop tablespace - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_tablespace', + name: 'some_view', + schema: 'public', + materialized: true, + toTablespace: 'pg_default', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET TABLESPACE pg_default;`, + ); +}); + +test('set existing - materialized', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('new_some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + autovacuumFreezeMinAge: 1, + }).withNoData().existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(0); + + expect(sqlStatements.length).toBe(0); +}); + +test('drop existing - materialized', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('new_tablespace').with({ + autovacuumVacuumCostLimit: 1, + }).existing(), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + autovacuumFreezeMinAge: 1, + }).withNoData().as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(2); + + expect(sqlStatements.length).toBe(2); +}); + +test('set existing', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgView('some_view', { id: integer('id') }).with({ + checkOption: 'cascaded', + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgView('new_some_view', { id: integer('id') }).with({ + checkOption: 'cascaded', + securityBarrier: true, + }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(0); + + expect(sqlStatements.length).toBe(0); +}); + +test('alter using - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('some_tablespace').using('some_using').with( + { + autovacuumVacuumCostLimit: 1, + }, + ).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).tablespace('some_tablespace').using('new_using').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_using', + name: 'some_view', + schema: 'public', + materialized: true, + toUsing: 'new_using', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET ACCESS METHOD "new_using";`, + ); +}); + +test('set using - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).using('new_using').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_using', + name: 'some_view', + schema: 'public', + materialized: true, + toUsing: 'new_using', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET ACCESS METHOD "new_using";`, + ); +}); + +test('drop using - materialize', async () => { + const users = pgTable('users', { + id: integer('id').primaryKey().notNull(), + }); + + const from = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).using('new_using').with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const to = { + users, + view: pgMaterializedView('some_view', { id: integer('id') }).with({ + autovacuumVacuumCostLimit: 1, + }).as(sql`SELECT 'asd'`), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toEqual({ + type: 'alter_view_alter_using', + name: 'some_view', + schema: 'public', + materialized: true, + toUsing: 'heap', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."some_view" SET ACCESS METHOD "heap";`, + ); +}); + +test('rename view and alter view', async () => { + const from = { + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + view: pgView('new_some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).as( + sql`SELECT * FROM "users"`, + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->public.new_some_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + schema: 'public', + }); + expect(statements[1]).toStrictEqual({ + materialized: false, + name: 'new_some_view', + schema: 'public', + type: 'alter_view_add_with_option', + with: { + checkOption: 'cascaded', + }, + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER VIEW "public"."some_view" RENAME TO "new_some_view";`); + expect(sqlStatements[1]).toBe(`ALTER VIEW "public"."new_some_view" SET (check_option = cascaded);`); +}); + +test('moved schema and alter view', async () => { + const schema = pgSchema('my_schema'); + const from = { + schema, + view: pgView('some_view', { id: integer('id') }).as(sql`SELECT * FROM "users"`), + }; + + const to = { + schema, + view: schema.view('some_view', { id: integer('id') }).with({ checkOption: 'cascaded' }).as( + sql`SELECT * FROM "users"`, + ), + }; + + const { statements, sqlStatements } = await diffTestSchemas(from, to, ['public.some_view->my_schema.some_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + fromSchema: 'public', + name: 'some_view', + toSchema: 'my_schema', + type: 'alter_view_alter_schema', + }); + expect(statements[1]).toStrictEqual({ + name: 'some_view', + schema: 'my_schema', + type: 'alter_view_add_with_option', + materialized: false, + with: { + checkOption: 'cascaded', + }, + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`ALTER VIEW "public"."some_view" SET SCHEMA "my_schema";`); + expect(sqlStatements[1]).toBe(`ALTER VIEW "my_schema"."some_view" SET (check_option = cascaded);`); +}); diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 89ec008ca..1877f34e1 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -3,6 +3,7 @@ import chalk from 'chalk'; import { sql } from 'drizzle-orm'; import { blob, + check, foreignKey, getTableConfig, index, @@ -11,6 +12,7 @@ import { numeric, real, sqliteTable, + sqliteView, text, uniqueIndex, } from 'drizzle-orm/sqlite-core'; @@ -389,6 +391,7 @@ test('drop autoincrement. drop column with data', async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(4); @@ -491,6 +494,7 @@ test('change autoincrement. table is part of foreign key', async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(4); @@ -752,6 +756,7 @@ test('recreate table with nested references', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(4); @@ -860,6 +865,7 @@ test('recreate table with added column not null and without default', async (t) tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(4); @@ -1047,3 +1053,347 @@ test('drop not null with two indexes', async (t) => { expect(tablesToRemove!.length).toBe(0); expect(tablesToTruncate!.length).toBe(0); }); + +test('add check constraint to table', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: ['some_check;"users"."age" > 21'], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer, +\tCONSTRAINT "some_check" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[1]).toBe( + 'INSERT INTO `__new_users`("id", "name", "age") SELECT "id", "name", "age" FROM `users`;', + ); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop check constraint', async (t) => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + name: 'id', + notNull: true, + generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'text', + }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer +);\n`); + expect(sqlStatements[1]).toBe( + 'INSERT INTO `__new_users`("id", "name", "age") SELECT "id", "name", "age" FROM `users`;', + ); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('db has checks. Push with same names', async () => { + const turso = createClient({ + url: ':memory:', + }); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`some new value`), + })), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + false, + [], + ); + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('create view', async () => { + const turso = createClient({ + url: ':memory:', + }); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + }; + + const schema2 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([ + { + definition: 'select "id" from "test"', + name: 'view', + type: 'sqlite_create_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `CREATE VIEW \`view\` AS select "id" from "test";`, + ]); +}); + +test('drop view', async () => { + const turso = createClient({ + url: ':memory:', + }); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const schema2 = { + test: table, + }; + + const { statements, sqlStatements } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([ + { + name: 'view', + type: 'drop_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'DROP VIEW \`view\`;', + ]); +}); + +test('alter view ".as"', async () => { + const turso = createClient({ + url: ':memory:', + }); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushLibSQL( + turso, + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/push/mysql-push.test.ts b/drizzle-kit/tests/push/mysql-push.test.ts new file mode 100644 index 000000000..ba64ccddb --- /dev/null +++ b/drizzle-kit/tests/push/mysql-push.test.ts @@ -0,0 +1,345 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import { check, int, mysqlTable, mysqlView } from 'drizzle-orm/mysql-core'; +import fs from 'fs'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { diffTestSchemasPushMysql } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, expect, test } from 'vitest'; + +let client: Connection; +let mysqlContainer: Docker.Container; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +beforeAll(async () => { + const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +if (!fs.existsSync('tests/push/mysql')) { + fs.mkdirSync('tests/push/mysql'); +} + +test('add check constraint to table', async () => { + const schema1 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + const schema2 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }, (table) => ({ + checkConstraint1: check('some_check1', sql`${table.values} < 100`), + checkConstraint2: check('some_check2', sql`'test' < 100`), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'create_check_constraint', + tableName: 'test', + schema: '', + data: 'some_check1;\`test\`.\`values\` < 100', + }, + { + data: "some_check2;'test' < 100", + schema: '', + tableName: 'test', + type: 'create_check_constraint', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE \`test\` ADD CONSTRAINT \`some_check1\` CHECK (\`test\`.\`values\` < 100);', + `ALTER TABLE \`test\` ADD CONSTRAINT \`some_check2\` CHECK ('test' < 100);`, + ]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('drop check constraint to table', async () => { + const schema1 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }, (table) => ({ + checkConstraint1: check('some_check1', sql`${table.values} < 100`), + checkConstraint2: check('some_check2', sql`'test' < 100`), + })), + }; + const schema2 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'delete_check_constraint', + tableName: 'test', + schema: '', + constraintName: 'some_check1', + }, + { + constraintName: 'some_check2', + schema: '', + tableName: 'test', + type: 'delete_check_constraint', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE \`test\` DROP CONSTRAINT \`some_check1\`;', + `ALTER TABLE \`test\` DROP CONSTRAINT \`some_check2\`;`, + ]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('db has checks. Push with same names', async () => { + const schema1 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values').default(1), + }, (table) => ({ + checkConstraint: check('some_check', sql`${table.values} < 100`), + })), + }; + const schema2 = { + test: mysqlTable('test', { + id: int('id').primaryKey(), + values: int('values').default(1), + }, (table) => ({ + checkConstraint: check('some_check', sql`some new value`), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('create view', async () => { + const table = mysqlTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + }; + + const schema2 = { + test: table, + view: mysqlView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + definition: 'select \`id\` from \`test\`', + name: 'view', + type: 'mysql_create_view', + replace: false, + sqlSecurity: 'definer', + withCheckOption: undefined, + algorithm: 'undefined', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `CREATE ALGORITHM = undefined +SQL SECURITY definer +VIEW \`view\` AS (select \`id\` from \`test\`);`, + ]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('drop view', async () => { + const table = mysqlTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: mysqlView('view').as((qb) => qb.select().from(table)), + }; + + const schema2 = { + test: table, + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + name: 'view', + type: 'drop_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'DROP VIEW \`view\`;', + ]); + await client.query(`DROP TABLE \`test\`;`); + await client.query(`DROP VIEW \`view\`;`); +}); + +test('alter view ".as"', async () => { + const table = mysqlTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: mysqlView('view').as((qb) => qb.select().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: mysqlView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`DROP TABLE \`test\`;`); + await client.query(`DROP VIEW \`view\`;`); +}); + +test('alter meta options with distinct in definition', async () => { + const table = mysqlTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: mysqlView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('merge').as(( + qb, + ) => qb.selectDistinct().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: mysqlView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('undefined').as((qb) => + qb.selectDistinct().from(table) + ), + }; + + await expect(diffTestSchemasPushMysql( + client, + schema1, + schema2, + [], + 'drizzle', + false, + )).rejects.toThrowError(); + + await client.query(`DROP TABLE \`test\`;`); +}); diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index cb1a97122..fb2ffdc8d 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -1,9 +1,11 @@ import { PGlite } from '@electric-sql/pglite'; +import chalk from 'chalk'; import { bigint, bigserial, boolean, char, + check, date, doublePrecision, index, @@ -13,9 +15,11 @@ import { jsonb, numeric, pgEnum, + pgMaterializedView, pgSchema, pgSequence, pgTable, + pgView, real, serial, smallint, @@ -25,13 +29,12 @@ import { uniqueIndex, uuid, varchar, - vector, } from 'drizzle-orm/pg-core'; import { drizzle } from 'drizzle-orm/pglite'; -import { SQL, sql } from 'drizzle-orm/sql'; +import { eq, SQL, sql } from 'drizzle-orm/sql'; import { pgSuggestions } from 'src/cli/commands/pgPushUtils'; -import { diffTestSchemasPush } from 'tests/schemaDiffer'; -import { afterEach, expect, test } from 'vitest'; +import { diffTestSchemas, diffTestSchemasPush } from 'tests/schemaDiffer'; +import { expect, test } from 'vitest'; import { DialectSuite, run } from './common'; const pgSuite: DialectSuite = { @@ -40,10 +43,7 @@ const pgSuite: DialectSuite = { const customSchema = pgSchema('schemass'); - const transactionStatusEnum = customSchema.enum( - 'TransactionStatusEnum', - ['PENDING', 'FAILED', 'SUCCESS'], - ); + const transactionStatusEnum = customSchema.enum('TransactionStatusEnum', ['PENDING', 'FAILED', 'SUCCESS']); const enumname = pgEnum('enumname', ['three', 'two', 'one']); @@ -53,11 +53,7 @@ const pgSuite: DialectSuite = { enumname: pgEnum('enumname', ['three', 'two', 'one']), customSchema: customSchema, - transactionStatusEnum: customSchema.enum('TransactionStatusEnum', [ - 'PENDING', - 'FAILED', - 'SUCCESS', - ]), + transactionStatusEnum: customSchema.enum('TransactionStatusEnum', ['PENDING', 'FAILED', 'SUCCESS']), allSmallSerials: pgTable('schema_test', { columnAll: uuid('column_all').defaultRandom(), @@ -95,15 +91,9 @@ const pgSuite: DialectSuite = { withTimezone: true, mode: 'string', }).defaultNow(), - columnAll: timestamp('column_all', { mode: 'string' }).default( - '2023-03-01 12:47:29.792', - ), - column: timestamp('column', { mode: 'string' }).default( - sql`'2023-02-28 16:18:31.18'`, - ), - column2: timestamp('column2', { mode: 'string', precision: 3 }).default( - sql`'2023-02-28 16:18:31.18'`, - ), + columnAll: timestamp('column_all', { mode: 'string' }).default('2023-03-01 12:47:29.792'), + column: timestamp('column', { mode: 'string' }).default(sql`'2023-02-28 16:18:31.18'`), + column2: timestamp('column2', { mode: 'string', precision: 3 }).default(sql`'2023-02-28 16:18:31.18'`), }), allUuids: customSchema.table('all_uuids', { @@ -113,9 +103,7 @@ const pgSuite: DialectSuite = { allDates: customSchema.table('all_dates', { column_date_now: date('column_date_now').defaultNow(), - column_all: date('column_all', { mode: 'date' }) - .default(new Date()) - .notNull(), + column_all: date('column_all', { mode: 'date' }).default(new Date()).notNull(), column: date('column'), }), @@ -126,9 +114,7 @@ const pgSuite: DialectSuite = { }), allBigints: pgTable('all_bigints', { - columnAll: bigint('column_all', { mode: 'number' }) - .default(124) - .notNull(), + columnAll: bigint('column_all', { mode: 'number' }).default(124).notNull(), column: bigint('column', { mode: 'number' }), }), @@ -146,9 +132,7 @@ const pgSuite: DialectSuite = { columnMinToSec: interval('column_min_to_sec', { fields: 'minute to second', }), - columnWithoutFields: interval('column_without_fields') - .default('00:00:01') - .notNull(), + columnWithoutFields: interval('column_without_fields').default('00:00:01').notNull(), column: interval('column'), column5: interval('column5', { fields: 'minute to second', @@ -200,9 +184,7 @@ const pgSuite: DialectSuite = { }), allJsonb: customSchema.table('all_jsonb', { - columnDefaultObject: jsonb('column_default_object') - .default({ hello: 'world world' }) - .notNull(), + columnDefaultObject: jsonb('column_default_object').default({ hello: 'world world' }).notNull(), columnDefaultArray: jsonb('column_default_array').default({ hello: { 'world world': ['foo', 'bar'] }, }), @@ -210,9 +192,7 @@ const pgSuite: DialectSuite = { }), allJson: customSchema.table('all_json', { - columnDefaultObject: json('column_default_object') - .default({ hello: 'world world' }) - .notNull(), + columnDefaultObject: json('column_default_object').default({ hello: 'world world' }).notNull(), columnDefaultArray: json('column_default_array').default({ hello: { 'world world': ['foo', 'bar'] }, foo: 'bar', @@ -228,22 +208,16 @@ const pgSuite: DialectSuite = { }), allNumerics: customSchema.table('all_numerics', { - columnAll: numeric('column_all', { precision: 1, scale: 1 }) - .default('32') - .notNull(), + columnAll: numeric('column_all', { precision: 1, scale: 1 }).default('32').notNull(), column: numeric('column'), columnPrimary: numeric('column_primary').primaryKey().notNull(), }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema1, - [], - false, - ['public', 'schemass'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema1, [], false, [ + 'public', + 'schemass', + ]); expect(statements.length).toBe(0); }, @@ -276,14 +250,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(2); expect(statements[0]).toStrictEqual({ schema: '', @@ -370,20 +337,11 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema2.users.name}`), }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -427,20 +385,11 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema2.users.name}`), }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -478,9 +427,7 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema1.users.name}`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema1.users.name}`), }), }; const schema2 = { @@ -492,14 +439,7 @@ const pgSuite: DialectSuite = { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -516,9 +456,7 @@ const pgSuite: DialectSuite = { type: 'alter_table_alter_column_drop_generated', }, ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "users" ALTER COLUMN "gen_name" DROP EXPRESSION;', - ]); + expect(sqlStatements).toStrictEqual(['ALTER TABLE "users" ALTER COLUMN "gen_name" DROP EXPRESSION;']); }, async alterGeneratedConstraint() { @@ -529,9 +467,7 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema1.users.name}`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema1.users.name}`), }), }; const schema2 = { @@ -539,20 +475,11 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema2.users.name} || 'hello'`), }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([]); expect(sqlStatements).toStrictEqual([]); @@ -567,20 +494,11 @@ const pgSuite: DialectSuite = { id: integer('id'), id2: integer('id2'), name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - ), + generatedName: text('gen_name').generatedAlwaysAs((): SQL => sql`${schema2.users.name} || 'hello'`), }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -620,6 +538,7 @@ const pgSuite: DialectSuite = { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -638,14 +557,7 @@ const pgSuite: DialectSuite = { seq: pgSequence('my_seq', { startWith: 100 }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(0); }, @@ -661,20 +573,13 @@ const pgSuite: DialectSuite = { }, (t) => ({ removeColumn: index('removeColumn').on(t.name, t.id), - addColumn: index('addColumn') - .on(t.name.desc()) - .with({ fillfactor: 70 }), + addColumn: index('addColumn').on(t.name.desc()).with({ fillfactor: 70 }), removeExpression: index('removeExpression') .on(t.name.desc(), sql`name`) .concurrently(), addExpression: index('addExpression').on(t.id.desc()), - changeExpression: index('changeExpression').on( - t.id.desc(), - sql`name`, - ), - changeName: index('changeName') - .on(t.name.desc(), t.id.asc().nullsLast()) - .with({ fillfactor: 70 }), + changeExpression: index('changeExpression').on(t.id.desc(), sql`name`), + changeName: index('changeName').on(t.name.desc(), t.id.asc().nullsLast()).with({ fillfactor: 70 }), changeWith: index('changeWith').on(t.name).with({ fillfactor: 70 }), changeUsing: index('changeUsing').on(t.name), }), @@ -690,17 +595,10 @@ const pgSuite: DialectSuite = { }, (t) => ({ removeColumn: index('removeColumn').on(t.name), - addColumn: index('addColumn') - .on(t.name.desc(), t.id.nullsLast()) - .with({ fillfactor: 70 }), - removeExpression: index('removeExpression') - .on(t.name.desc()) - .concurrently(), + addColumn: index('addColumn').on(t.name.desc(), t.id.nullsLast()).with({ fillfactor: 70 }), + removeExpression: index('removeExpression').on(t.name.desc()).concurrently(), addExpression: index('addExpression').on(t.id.desc()), - changeExpression: index('changeExpression').on( - t.id.desc(), - sql`name desc`, - ), + changeExpression: index('changeExpression').on(t.id.desc(), sql`name desc`), changeName: index('newName') .on(t.name.desc(), sql`name`) .with({ fillfactor: 70 }), @@ -710,14 +608,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(sqlStatements).toStrictEqual([ 'DROP INDEX IF EXISTS "changeName";', @@ -748,9 +639,7 @@ const pgSuite: DialectSuite = { name: text('name'), }, (t) => ({ - indx: index() - .on(t.name.desc(), t.id.asc().nullsLast()) - .with({ fillfactor: 70 }), + indx: index().on(t.name.desc(), t.id.asc().nullsLast()).with({ fillfactor: 70 }), }), ), }; @@ -762,14 +651,7 @@ const pgSuite: DialectSuite = { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ @@ -780,9 +662,7 @@ const pgSuite: DialectSuite = { }); expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe( - `DROP INDEX IF EXISTS "users_name_id_index";`, - ); + expect(sqlStatements[0]).toBe(`DROP INDEX IF EXISTS "users_name_id_index";`); }, async indexesToBeNotTriggered() { @@ -832,14 +712,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(0); }, @@ -883,14 +756,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(0); }, @@ -956,14 +822,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); const query = async (sql: string, params?: any[]) => { const result = await client.query(sql, params ?? []); return result.rows as any[]; @@ -971,9 +830,7 @@ const pgSuite: DialectSuite = { const { statementsToExecute } = await pgSuggestions({ query }, statements); - expect(statementsToExecute).toStrictEqual([ - 'ALTER TABLE "User" ALTER COLUMN "email" SET NOT NULL;', - ]); + expect(statementsToExecute).toStrictEqual(['ALTER TABLE "User" ALTER COLUMN "email" SET NOT NULL;']); }, async addNotNullWithDataNoRollback() { @@ -1038,14 +895,7 @@ const pgSuite: DialectSuite = { ), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); const query = async (sql: string, params?: any[]) => { const result = await client.query(sql, params ?? []); return result.rows as any[]; @@ -1053,14 +903,9 @@ const pgSuite: DialectSuite = { await db.insert(schema1.users).values({ id: 'str', email: 'email@gmail' }); - const { statementsToExecute, shouldAskForApprove } = await pgSuggestions( - { query }, - statements, - ); + const { statementsToExecute, shouldAskForApprove } = await pgSuggestions({ query }, statements); - expect(statementsToExecute).toStrictEqual([ - 'ALTER TABLE "User" ALTER COLUMN "email" SET NOT NULL;', - ]); + expect(statementsToExecute).toStrictEqual(['ALTER TABLE "User" ALTER COLUMN "email" SET NOT NULL;']); expect(shouldAskForApprove).toBeFalsy(); }, @@ -1143,14 +988,7 @@ test('full sequence: no changes', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); @@ -1185,14 +1023,7 @@ test('basic sequence: change fields', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1260,9 +1091,7 @@ test('basic sequence: change name', async () => { type: 'rename_sequence', }, ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";', - ]); + expect(sqlStatements).toStrictEqual(['ALTER SEQUENCE "public"."my_seq" RENAME TO "my_seq2";']); for (const st of sqlStatements) { await client.query(st); @@ -1348,14 +1177,7 @@ test('create table: identity always/by default - no params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1388,6 +1210,7 @@ test('create table: identity always/by default - no params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1415,14 +1238,7 @@ test('create table: identity always/by default - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1455,6 +1271,7 @@ test('create table: identity always/by default - few params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1488,14 +1305,7 @@ test('create table: identity always/by default - all params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1528,6 +1338,7 @@ test('create table: identity always/by default - all params', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1556,14 +1367,7 @@ test('no diff: identity always/by default - no params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([]); expect(sqlStatements).toStrictEqual([]); @@ -1596,14 +1400,7 @@ test('no diff: identity always/by default - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([]); expect(sqlStatements).toStrictEqual([]); @@ -1656,14 +1453,7 @@ test('no diff: identity always/by default - all params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([]); expect(sqlStatements).toStrictEqual([]); @@ -1684,14 +1474,7 @@ test('drop identity from a column - no params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1701,9 +1484,7 @@ test('drop identity from a column - no params', async () => { type: 'alter_table_alter_column_drop_identity', }, ]); - expect(sqlStatements).toStrictEqual([ - `ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`, - ]); + expect(sqlStatements).toStrictEqual([`ALTER TABLE \"users\" ALTER COLUMN \"id\" DROP IDENTITY;`]); for (const st of sqlStatements) { await client.query(st); @@ -1735,14 +1516,7 @@ test('drop identity from a column - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1810,14 +1584,7 @@ test('drop identity from a column - all params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1865,14 +1632,7 @@ test('alter identity from a column - no params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1884,9 +1644,7 @@ test('alter identity from a column - no params', async () => { type: 'alter_table_alter_column_change_identity', }, ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "users" ALTER COLUMN "id" SET START WITH 100;', - ]); + expect(sqlStatements).toStrictEqual(['ALTER TABLE "users" ALTER COLUMN "id" SET START WITH 100;']); for (const st of sqlStatements) { await client.query(st); @@ -1912,14 +1670,7 @@ test('alter identity from a column - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -1960,14 +1711,7 @@ test('alter identity from a column - by default to always', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2011,14 +1755,7 @@ test('alter identity from a column - always to by default', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2063,14 +1800,7 @@ test('add column with identity - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2128,14 +1858,7 @@ test('add identity to column - few params', async () => { }), }; - const { statements, sqlStatements } = await diffTestSchemasPush( - client, - schema1, - schema2, - [], - false, - ['public'], - ); + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(statements).toStrictEqual([ { @@ -2178,6 +1901,177 @@ test('add array column - empty array default', async () => { }), }; + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements).toStrictEqual([ + { + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'" }, + }, + ]); + expect(sqlStatements).toStrictEqual(['ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{}\';']); +}); + +test('add array column - default', async () => { + const client = new PGlite(); + + const schema1 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + }), + }; + const schema2 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().default([1, 2, 3]), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements).toStrictEqual([ + { + type: 'alter_table_add_column', + tableName: 'test', + schema: '', + column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'" }, + }, + ]); + expect(sqlStatements).toStrictEqual(['ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\';']); +}); + +test('create view', async () => { + const client = new PGlite(); + + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + }; + + const schema2 = { + test: table, + view: pgView('view').as((qb) => qb.selectDistinct().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements).toStrictEqual([ + { + definition: 'select distinct "id" from "test"', + name: 'view', + schema: 'public', + type: 'create_view', + with: undefined, + materialized: false, + tablespace: undefined, + using: undefined, + withNoData: false, + }, + ]); + expect(sqlStatements).toStrictEqual(['CREATE VIEW "public"."view" AS (select distinct "id" from "test");']); +}); + +test('add check constraint to table', async () => { + const client = new PGlite(); + + const schema1 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().default([1, 2, 3]), + }), + }; + const schema2 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').array().default([1, 2, 3]), + }, (table) => ({ + checkConstraint1: check('some_check1', sql`${table.values} < 100`), + checkConstraint2: check('some_check2', sql`'test' < 100`), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements).toStrictEqual([ + { + type: 'create_check_constraint', + tableName: 'test', + schema: '', + data: 'some_check1;"test"."values" < 100', + }, + { + data: "some_check2;'test' < 100", + schema: '', + tableName: 'test', + type: 'create_check_constraint', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "test" ADD CONSTRAINT "some_check1" CHECK ("test"."values" < 100);', + `ALTER TABLE "test" ADD CONSTRAINT "some_check2" CHECK ('test' < 100);`, + ]); +}); + +test('create materialized view', async () => { + const client = new PGlite(); + + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + }; + + const schema2 = { + test: table, + view: pgMaterializedView('view') + .withNoData() + .using('heap') + .as((qb) => qb.selectDistinct().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements).toStrictEqual([ + { + definition: 'select distinct "id" from "test"', + name: 'view', + schema: 'public', + type: 'create_view', + with: undefined, + materialized: true, + tablespace: undefined, + using: 'heap', + withNoData: true, + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE MATERIALIZED VIEW "public"."view" USING "heap" AS (select distinct "id" from "test") WITH NO DATA;', + ]); +}); + +test('drop check constraint', async () => { + const client = new PGlite(); + + const schema1 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').default(1), + }, (table) => ({ + checkConstraint: check('some_check', sql`${table.values} < 100`), + })), + }; + const schema2 = { + test: pgTable('test', { + id: serial('id').primaryKey(), + values: integer('values').default(1), + }), + }; + const { statements, sqlStatements } = await diffTestSchemasPush( client, schema1, @@ -2189,30 +2083,35 @@ test('add array column - empty array default', async () => { expect(statements).toStrictEqual([ { - type: 'alter_table_add_column', + type: 'delete_check_constraint', tableName: 'test', schema: '', - column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{}'" }, + constraintName: 'some_check', }, ]); expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{}\';', + 'ALTER TABLE "test" DROP CONSTRAINT "some_check";', ]); }); -test('add array column - default', async () => { +test('db has checks. Push with same names', async () => { const client = new PGlite(); const schema1 = { test: pgTable('test', { id: serial('id').primaryKey(), - }), + values: integer('values').default(1), + }, (table) => ({ + checkConstraint: check('some_check', sql`${table.values} < 100`), + })), }; const schema2 = { test: pgTable('test', { id: serial('id').primaryKey(), - values: integer('values').array().default([1, 2, 3]), - }), + values: integer('values').default(1), + }, (table) => ({ + checkConstraint: check('some_check', sql`some new value`), + })), }; const { statements, sqlStatements } = await diffTestSchemasPush( @@ -2224,15 +2123,548 @@ test('add array column - default', async () => { ['public'], ); + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); +}); + +test('drop view', async () => { + const client = new PGlite(); + + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgView('view').as((qb) => qb.selectDistinct().from(table)), + }; + + const schema2 = { + test: table, + }; + + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + expect(statements).toStrictEqual([ { - type: 'alter_table_add_column', - tableName: 'test', - schema: '', - column: { name: 'values', type: 'integer[]', primaryKey: false, notNull: false, default: "'{1,2,3}'" }, + name: 'view', + schema: 'public', + type: 'drop_view', }, ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE "test" ADD COLUMN "values" integer[] DEFAULT \'{1,2,3}\';', + expect(sqlStatements).toStrictEqual(['DROP VIEW "public"."view";']); +}); + +test('drop materialized view', async () => { + const client = new PGlite(); + + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgMaterializedView('view').as((qb) => qb.selectDistinct().from(table)), + }; + + const schema2 = { + test: table, + }; + + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements).toStrictEqual([ + { + name: 'view', + schema: 'public', + type: 'drop_view', + materialized: true, + }, ]); + expect(sqlStatements).toStrictEqual(['DROP MATERIALIZED VIEW "public"."view";']); +}); + +test('push view with same name', async () => { + const client = new PGlite(); + + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgView('view').as((qb) => qb.selectDistinct().from(table)), + }; + + const schema2 = { + test: table, + view: pgView('view').as((qb) => qb.selectDistinct().from(table).where(eq(table.id, 1))), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); +}); + +test('push materialized view with same name', async () => { + const client = new PGlite(); + + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgMaterializedView('view').as((qb) => qb.selectDistinct().from(table)), + }; + + const schema2 = { + test: table, + view: pgMaterializedView('view').as((qb) => qb.selectDistinct().from(table).where(eq(table.id, 1))), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); +}); + +test('add with options for materialized view', async () => { + const client = new PGlite(); + + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgMaterializedView('view').as((qb) => qb.selectDistinct().from(table)), + }; + + const schema2 = { + test: table, + view: pgMaterializedView('view') + .with({ autovacuumFreezeTableAge: 1, autovacuumEnabled: false }) + .as((qb) => qb.selectDistinct().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'view', + schema: 'public', + type: 'alter_view_add_with_option', + with: { + autovacuumFreezeTableAge: 1, + autovacuumEnabled: false, + }, + materialized: true, + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."view" SET (autovacuum_enabled = false, autovacuum_freeze_table_age = 1);`, + ); +}); + +test('add with options to materialized', async () => { + const client = new PGlite(); + + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgMaterializedView('view').as((qb) => qb.selectDistinct().from(table)), + }; + + const schema2 = { + test: table, + view: pgMaterializedView('view') + .with({ autovacuumVacuumCostDelay: 100, vacuumTruncate: false }) + .as((qb) => qb.selectDistinct().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'view', + schema: 'public', + type: 'alter_view_add_with_option', + with: { + autovacuumVacuumCostDelay: 100, + vacuumTruncate: false, + }, + materialized: true, + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER MATERIALIZED VIEW "public"."view" SET (vacuum_truncate = false, autovacuum_vacuum_cost_delay = 100);`, + ); +}); + +test('add with options to materialized with existing flag', async () => { + const client = new PGlite(); + + const table = pgTable('test', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgMaterializedView('view', {}).as(sql`SELECT id FROM "test"`), + }; + + const schema2 = { + test: table, + view: pgMaterializedView('view', {}).with({ autovacuumVacuumCostDelay: 100, vacuumTruncate: false }).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop mat view with data', async () => { + const client = new PGlite(); + + const table = pgTable('table', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgMaterializedView('view', {}).as(sql`SELECT * FROM ${table}`), + }; + + const schema2 = { + test: table, + }; + + const seedStatements = [`INSERT INTO "public"."table" ("id") VALUES (1), (2), (3)`]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + matViewsToRemove, + } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + { after: seedStatements }, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + materialized: true, + name: 'view', + schema: 'public', + type: 'drop_view', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."view";`); + expect(infoToPrint!.length).toBe(1); + expect(infoToPrint![0]).toBe(`· You're about to delete "${chalk.underline('view')}" materialized view with 3 items`); + expect(columnsToRemove!.length).toBe(0); + expect(schemasToRemove!.length).toBe(0); + expect(shouldAskForApprove).toBe(true); + expect(tablesToRemove!.length).toBe(0); + expect(matViewsToRemove!.length).toBe(1); +}); + +test('drop mat view without data', async () => { + const client = new PGlite(); + + const table = pgTable('table', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgMaterializedView('view', {}).as(sql`SELECT * FROM ${table}`), + }; + + const schema2 = { + test: table, + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + matViewsToRemove, + } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + materialized: true, + name: 'view', + schema: 'public', + type: 'drop_view', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP MATERIALIZED VIEW "public"."view";`); + expect(infoToPrint!.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(schemasToRemove!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(matViewsToRemove!.length).toBe(0); +}); + +test('drop view with data', async () => { + const client = new PGlite(); + + const table = pgTable('table', { + id: serial('id').primaryKey(), + }); + const schema1 = { + test: table, + view: pgView('view', {}).as(sql`SELECT * FROM ${table}`), + }; + + const schema2 = { + test: table, + }; + + const seedStatements = [`INSERT INTO "public"."table" ("id") VALUES (1), (2), (3)`]; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + matViewsToRemove, + } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + { after: seedStatements }, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'view', + schema: 'public', + type: 'drop_view', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP VIEW "public"."view";`); + expect(infoToPrint!.length).toBe(0); + expect(columnsToRemove!.length).toBe(0); + expect(schemasToRemove!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(matViewsToRemove!.length).toBe(0); +}); + +test('enums ordering', async () => { + const enum1 = pgEnum('enum_users_customer_and_ship_to_settings_roles', [ + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'custMgf', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ]); + const schema1 = {}; + + const schema2 = { + enum1, + }; + + const { sqlStatements: createEnum } = await diffTestSchemas(schema1, schema2, []); + + const enum2 = pgEnum('enum_users_customer_and_ship_to_settings_roles', [ + 'addedToTop', + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'custMgf', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ]); + const schema3 = { + enum2, + }; + + const { sqlStatements: addedValueSql } = await diffTestSchemas(schema2, schema3, []); + + const enum3 = pgEnum('enum_users_customer_and_ship_to_settings_roles', [ + 'addedToTop', + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'addedToMiddle', + 'custMgf', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ]); + const schema4 = { + enum3, + }; + + const client = new PGlite(); + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema3, + schema4, + [], + false, + ['public'], + undefined, + { before: [...createEnum, ...addedValueSql], runApply: false }, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + before: 'custMgf', + name: 'enum_users_customer_and_ship_to_settings_roles', + schema: 'public', + type: 'alter_type_add_value', + value: 'addedToMiddle', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `ALTER TYPE "public"."enum_users_customer_and_ship_to_settings_roles" ADD VALUE 'addedToMiddle' BEFORE 'custMgf';`, + ); +}); + +test('drop enum values', async () => { + const newSchema = pgSchema('mySchema'); + const enum3 = pgEnum('enum_users_customer_and_ship_to_settings_roles', [ + 'addedToTop', + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'addedToMiddle', + 'custMgf', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ]); + const schema1 = { + enum3, + table: pgTable('enum_table', { + id: enum3(), + }), + newSchema, + table1: newSchema.table('enum_table', { + id: enum3(), + }), + }; + + const enum4 = pgEnum('enum_users_customer_and_ship_to_settings_roles', [ + 'addedToTop', + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ]); + const schema2 = { + enum4, + table: pgTable('enum_table', { + id: enum4(), + }), + newSchema, + table1: newSchema.table('enum_table', { + id: enum4(), + }), + }; + + const client = new PGlite(); + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public', 'mySchema'], + undefined, + ); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'enum_users_customer_and_ship_to_settings_roles', + schema: 'public', + type: 'alter_type_drop_value', + newValues: [ + 'addedToTop', + 'custAll', + 'custAdmin', + 'custClerk', + 'custInvoiceManager', + 'custApprover', + 'custOrderWriter', + 'custBuyer', + ], + deletedValues: ['addedToMiddle', 'custMgf'], + columnsWithEnum: [{ + column: 'id', + schema: 'public', + table: 'enum_table', + }, { + column: 'id', + schema: 'mySchema', + table: 'enum_table', + }], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe( + `ALTER TABLE "public"."enum_table" ALTER COLUMN "id" SET DATA TYPE text;`, + ); + expect(sqlStatements[1]).toBe( + `ALTER TABLE "mySchema"."enum_table" ALTER COLUMN "id" SET DATA TYPE text;`, + ); + expect(sqlStatements[2]).toBe( + `DROP TYPE "public"."enum_users_customer_and_ship_to_settings_roles";`, + ); + expect(sqlStatements[3]).toBe( + `CREATE TYPE "public"."enum_users_customer_and_ship_to_settings_roles" AS ENUM('addedToTop', 'custAll', 'custAdmin', 'custClerk', 'custInvoiceManager', 'custApprover', 'custOrderWriter', 'custBuyer');`, + ); + expect(sqlStatements[4]).toBe( + `ALTER TABLE "public"."enum_table" ALTER COLUMN "id" SET DATA TYPE "public"."enum_users_customer_and_ship_to_settings_roles" USING "id"::"public"."enum_users_customer_and_ship_to_settings_roles";`, + ); + expect(sqlStatements[5]).toBe( + `ALTER TABLE "mySchema"."enum_table" ALTER COLUMN "id" SET DATA TYPE "public"."enum_users_customer_and_ship_to_settings_roles" USING "id"::"public"."enum_users_customer_and_ship_to_settings_roles";`, + ); }); diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index aea5cd379..5ac6f996c 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -1,7 +1,9 @@ import Database from 'better-sqlite3'; import chalk from 'chalk'; +import { sql } from 'drizzle-orm'; import { blob, + check, foreignKey, getTableConfig, int, @@ -9,10 +11,11 @@ import { numeric, real, sqliteTable, + sqliteView, text, uniqueIndex, } from 'drizzle-orm/sqlite-core'; -import { diffTestSchemasPushSqlite } from 'tests/schemaDiffer'; +import { diffTestSchemasPushSqlite, introspectSQLiteToFile } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; test('nothing changed in schema', async (t) => { @@ -67,6 +70,7 @@ test('nothing changed in schema', async (t) => { tablesToRemove, tablesToTruncate, } = await diffTestSchemasPushSqlite(client, schema1, schema1, [], false); + expect(sqlStatements.length).toBe(0); expect(statements.length).toBe(0); expect(columnsToRemove!.length).toBe(0); @@ -378,6 +382,7 @@ test('drop autoincrement. drop column with data', async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(4); @@ -494,6 +499,7 @@ test('drop autoincrement. drop column with data with pragma off', async (t) => { }, ], uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(4); @@ -598,6 +604,7 @@ test('change autoincrement. other table references current', async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); @@ -717,6 +724,7 @@ test('drop not null, add not null', async (t) => { expect(statements!.length).toBe(2); expect(statements![0]).toStrictEqual({ + checkConstraints: [], columns: [ { autoincrement: true, @@ -742,6 +750,7 @@ test('drop not null, add not null', async (t) => { uniqueConstraints: [], }); expect(statements![1]).toStrictEqual({ + checkConstraints: [], columns: [ { autoincrement: true, @@ -868,6 +877,7 @@ test('rename table and change data type', async (t) => { tableName: 'new_users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(5); @@ -946,6 +956,7 @@ test('rename column and change data type', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(4); @@ -1053,6 +1064,7 @@ test('recreate table with nested references', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(6); @@ -1161,6 +1173,7 @@ test('recreate table with added column not null and without default with data', tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(4); @@ -1189,12 +1202,12 @@ test('recreate table with added column not null and without default with data', expect(tablesToTruncate![0]).toBe('users'); }); -test('recreate table with added column not null and without default with data', async (t) => { +test('add check constraint to table', async (t) => { const client = new Database(':memory:'); const schema1 = { users: sqliteTable('users', { - id: int('id').primaryKey({ autoIncrement: true }), + id: int('id').primaryKey({ autoIncrement: false }), name: text('name'), age: integer('age'), }), @@ -1205,8 +1218,9 @@ test('recreate table with added column not null and without default with data', id: int('id').primaryKey({ autoIncrement: false }), name: text('name'), age: integer('age'), - newColumn: text('new_column').notNull(), - }), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), }; const { @@ -1251,31 +1265,117 @@ test('recreate table with added column not null and without default with data', primaryKey: false, type: 'integer', }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: ['some_check;"users"."age" > 21'], + }); + + expect(sqlStatements!.length).toBe(4); + expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`name\` text, +\t\`age\` integer, +\tCONSTRAINT "some_check" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[1]).toBe( + 'INSERT INTO `__new_users`("id", "name", "age") SELECT "id", "name", "age" FROM `users`;', + ); + expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements![3]).toBe( + `ALTER TABLE \`__new_users\` RENAME TO \`users\`;`, + ); + + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('drop check constraint', async (t) => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements!.length).toBe(1); + expect(statements![0]).toStrictEqual({ + columns: [ { autoincrement: false, - name: 'new_column', + name: 'id', notNull: true, generated: undefined, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + name: 'name', + notNull: false, + generated: undefined, primaryKey: false, type: 'text', }, + { + autoincrement: false, + name: 'age', + notNull: false, + generated: undefined, + primaryKey: false, + type: 'integer', + }, ], compositePKs: [], referenceData: [], tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements!.length).toBe(4); expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` ( \t\`id\` integer PRIMARY KEY NOT NULL, \t\`name\` text, -\t\`age\` integer, -\t\`new_column\` text NOT NULL +\t\`age\` integer );\n`); expect(sqlStatements[1]).toBe( - 'INSERT INTO `__new_users`("id", "name", "age", "new_column") SELECT "id", "name", "age", "new_column" FROM `users`;', + 'INSERT INTO `__new_users`("id", "name", "age") SELECT "id", "name", "age" FROM `users`;', ); expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`); expect(sqlStatements![3]).toBe( @@ -1288,3 +1388,149 @@ test('recreate table with added column not null and without default with data', expect(tablesToRemove!.length).toBe(0); expect(tablesToTruncate!.length).toBe(0); }); + +test('db has checks. Push with same names', async () => { + const client = new Database(':memory:'); + + const schema1 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const schema2 = { + users: sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: false }), + name: text('name'), + age: integer('age'), + }, (table) => ({ + someCheck: check('some_check', sql`some new value`), + })), + }; + + const { + statements, + sqlStatements, + columnsToRemove, + infoToPrint, + schemasToRemove, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + false, + [], + ); + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); + expect(columnsToRemove!.length).toBe(0); + expect(infoToPrint!.length).toBe(0); + expect(shouldAskForApprove).toBe(false); + expect(tablesToRemove!.length).toBe(0); + expect(tablesToTruncate!.length).toBe(0); +}); + +test('create view', async () => { + const client = new Database(':memory:'); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + }; + + const schema2 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([ + { + definition: 'select "id" from "test"', + name: 'view', + type: 'sqlite_create_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `CREATE VIEW \`view\` AS select "id" from "test";`, + ]); +}); + +test('drop view', async () => { + const client = new Database(':memory:'); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const schema2 = { + test: table, + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([ + { + name: 'view', + type: 'drop_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'DROP VIEW \`view\`;', + ]); +}); + +test('alter view ".as"', async () => { + const client = new Database(':memory:'); + + const table = sqliteTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: sqliteView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 22a79ef72..3001887e1 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -1,35 +1,52 @@ import { PGlite } from '@electric-sql/pglite'; import { Client } from '@libsql/client/.'; import { Database } from 'better-sqlite3'; +import { randomUUID } from 'crypto'; import { is } from 'drizzle-orm'; -import { MySqlSchema, MySqlTable } from 'drizzle-orm/mysql-core'; -import { isPgEnum, isPgSequence, PgEnum, PgSchema, PgSequence, PgTable } from 'drizzle-orm/pg-core'; -import { SQLiteTable } from 'drizzle-orm/sqlite-core'; +import { MySqlSchema, MySqlTable, MySqlView } from 'drizzle-orm/mysql-core'; +import { + getMaterializedViewConfig, + isPgEnum, + isPgMaterializedView, + isPgSequence, + isPgView, + PgEnum, + PgMaterializedView, + PgSchema, + PgSequence, + PgTable, + PgView, +} from 'drizzle-orm/pg-core'; +import { SQLiteTable, SQLiteView } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; import { libSqlLogSuggestionsAndReturn } from 'src/cli/commands/libSqlPushUtils'; import { columnsResolver, enumsResolver, + mySqlViewsResolver, Named, schemasResolver, sequencesResolver, + sqliteViewsResolver, tablesResolver, + viewsResolver, } from 'src/cli/commands/migrate'; +import { pgSuggestions } from 'src/cli/commands/pgPushUtils'; import { logSuggestionsAndReturn } from 'src/cli/commands/sqlitePushUtils'; import { CasingType } from 'src/cli/validations/common'; import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql'; import { schemaToTypeScript } from 'src/introspect-pg'; import { schemaToTypeScript as schemaToTypeScriptSQLite } from 'src/introspect-sqlite'; import { prepareFromMySqlImports } from 'src/serializer/mysqlImports'; -import { mysqlSchema, squashMysqlScheme } from 'src/serializer/mysqlSchema'; +import { mysqlSchema, squashMysqlScheme, ViewSquashed } from 'src/serializer/mysqlSchema'; import { generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; import { fromDatabase as fromMySqlDatabase } from 'src/serializer/mysqlSerializer'; import { prepareFromPgImports } from 'src/serializer/pgImports'; -import { pgSchema, squashPgScheme } from 'src/serializer/pgSchema'; +import { pgSchema, squashPgScheme, View } from 'src/serializer/pgSchema'; import { fromDatabase, generatePgSnapshot } from 'src/serializer/pgSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; -import { sqliteSchema, squashSqliteScheme } from 'src/serializer/sqliteSchema'; +import { sqliteSchema, squashSqliteScheme, View as SqliteView } from 'src/serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase } from 'src/serializer/sqliteSerializer'; import { generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; import { @@ -50,19 +67,15 @@ import { export type PostgresSchema = Record< string, - PgTable | PgEnum | PgSchema | PgSequence + PgTable | PgEnum | PgSchema | PgSequence | PgView | PgMaterializedView >; -export type MysqlSchema = Record | MySqlSchema>; -export type SqliteSchema = Record>; +export type MysqlSchema = Record | MySqlSchema | MySqlView>; +export type SqliteSchema = Record | SQLiteView>; export const testSchemasResolver = (renames: Set) => async (input: ResolverInput): Promise> => { try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { return { created: input.created, renamed: [], @@ -114,297 +127,476 @@ export const testSchemasResolver = } }; -export const testSequencesResolver = (renames: Set) => -async ( - input: ResolverInput, -): Promise> => { - try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } - - let createdSequences = [...input.created]; - let deletedSequences = [...input.deleted]; +export const testSequencesResolver = + (renames: Set) => async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - const result: { - created: Sequence[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Sequence; to: Sequence }[]; - deleted: Sequence[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + let createdSequences = [...input.created]; + let deletedSequences = [...input.deleted]; - for (let rename of renames) { - const [from, to] = rename.split('->'); + const result: { + created: Sequence[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Sequence; to: Sequence }[]; + deleted: Sequence[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const idxFrom = deletedSequences.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; - }); + for (let rename of renames) { + const [from, to] = rename.split('->'); - if (idxFrom >= 0) { - const idxTo = createdSequences.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const idxFrom = deletedSequences.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; }); - const tableFrom = deletedSequences[idxFrom]; - const tableTo = createdSequences[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, + if (idxFrom >= 0) { + const idxTo = createdSequences.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - } - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedSequences[idxFrom], - to: createdSequences[idxTo], - }); + const tableFrom = deletedSequences[idxFrom]; + const tableTo = createdSequences[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, + }); + } + + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedSequences[idxFrom], + to: createdSequences[idxTo], + }); + } + + delete createdSequences[idxTo]; + delete deletedSequences[idxFrom]; + + createdSequences = createdSequences.filter(Boolean); + deletedSequences = deletedSequences.filter(Boolean); } + } - delete createdSequences[idxTo]; - delete deletedSequences[idxFrom]; + result.created = createdSequences; + result.deleted = deletedSequences; - createdSequences = createdSequences.filter(Boolean); - deletedSequences = deletedSequences.filter(Boolean); - } + return result; + } catch (e) { + console.error(e); + throw e; } + }; - result.created = createdSequences; - result.deleted = deletedSequences; +export const testEnumsResolver = + (renames: Set) => async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - return result; - } catch (e) { - console.error(e); - throw e; - } -}; + let createdEnums = [...input.created]; + let deletedEnums = [...input.deleted]; -export const testEnumsResolver = (renames: Set) => -async ( - input: ResolverInput, -): Promise> => { - try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; + const result: { + created: Enum[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Enum; to: Enum }[]; + deleted: Enum[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedEnums.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdEnums.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; + }); + + const tableFrom = deletedEnums[idxFrom]; + const tableTo = createdEnums[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, + }); + } + + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedEnums[idxFrom], + to: createdEnums[idxTo], + }); + } + + delete createdEnums[idxTo]; + delete deletedEnums[idxFrom]; + + createdEnums = createdEnums.filter(Boolean); + deletedEnums = deletedEnums.filter(Boolean); + } + } + + result.created = createdEnums; + result.deleted = deletedEnums; + + return result; + } catch (e) { + console.error(e); + throw e; } + }; - let createdEnums = [...input.created]; - let deletedEnums = [...input.deleted]; +export const testTablesResolver = + (renames: Set) => async (input: ResolverInput
): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - const result: { - created: Enum[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Enum; to: Enum }[]; - deleted: Enum[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + let createdTables = [...input.created]; + let deletedTables = [...input.deleted]; - for (let rename of renames) { - const [from, to] = rename.split('->'); + const result: { + created: Table[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Table; to: Table }[]; + deleted: Table[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const idxFrom = deletedEnums.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; - }); + for (let rename of renames) { + const [from, to] = rename.split('->'); - if (idxFrom >= 0) { - const idxTo = createdEnums.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const idxFrom = deletedTables.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; }); - const tableFrom = deletedEnums[idxFrom]; - const tableTo = createdEnums[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, + if (idxFrom >= 0) { + const idxTo = createdTables.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - } - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedEnums[idxFrom], - to: createdEnums[idxTo], - }); + const tableFrom = deletedTables[idxFrom]; + const tableTo = createdTables[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, + }); + } + + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedTables[idxFrom], + to: createdTables[idxTo], + }); + } + + delete createdTables[idxTo]; + delete deletedTables[idxFrom]; + + createdTables = createdTables.filter(Boolean); + deletedTables = deletedTables.filter(Boolean); } + } - delete createdEnums[idxTo]; - delete deletedEnums[idxFrom]; + result.created = createdTables; + result.deleted = deletedTables; - createdEnums = createdEnums.filter(Boolean); - deletedEnums = deletedEnums.filter(Boolean); - } + return result; + } catch (e) { + console.error(e); + throw e; } + }; - result.created = createdEnums; - result.deleted = deletedEnums; +export const testColumnsResolver = + (renames: Set) => async (input: ColumnsResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + tableName: input.tableName, + schema: input.schema, + created: input.created, + renamed: [], + deleted: input.deleted, + }; + } - return result; - } catch (e) { - console.error(e); - throw e; - } -}; + let createdColumns = [...input.created]; + let deletedColumns = [...input.deleted]; + + const renamed: { from: Column; to: Column }[] = []; + + const schema = input.schema || 'public'; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedColumns.findIndex((it) => { + return `${schema}.${input.tableName}.${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdColumns.findIndex((it) => { + return `${schema}.${input.tableName}.${it.name}` === to; + }); + + renamed.push({ + from: deletedColumns[idxFrom], + to: createdColumns[idxTo], + }); + + delete createdColumns[idxTo]; + delete deletedColumns[idxFrom]; + + createdColumns = createdColumns.filter(Boolean); + deletedColumns = deletedColumns.filter(Boolean); + } + } -export const testTablesResolver = (renames: Set) => -async ( - input: ResolverInput
, -): Promise> => { - try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, + tableName: input.tableName, + schema: input.schema, + created: createdColumns, + deleted: deletedColumns, + renamed, }; + } catch (e) { + console.error(e); + throw e; } + }; - let createdTables = [...input.created]; - let deletedTables = [...input.deleted]; +export const testViewsResolver = + (renames: Set) => async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - const result: { - created: Table[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Table; to: Table }[]; - deleted: Table[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; - for (let rename of renames) { - const [from, to] = rename.split('->'); + const result: { + created: View[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: View; to: View }[]; + deleted: View[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const idxFrom = deletedTables.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; - }); + for (let rename of renames) { + const [from, to] = rename.split('->'); - if (idxFrom >= 0) { - const idxTo = createdTables.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; }); - const tableFrom = deletedTables[idxFrom]; - const tableTo = createdTables[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - } - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedTables[idxFrom], - to: createdTables[idxTo], - }); + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, + }); + } + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); } + } - delete createdTables[idxTo]; - delete deletedTables[idxFrom]; + result.created = createdViews; + result.deleted = deletedViews; - createdTables = createdTables.filter(Boolean); - deletedTables = deletedTables.filter(Boolean); - } + return result; + } catch (e) { + console.error(e); + throw e; } + }; - result.created = createdTables; - result.deleted = deletedTables; +export const testViewsResolverMySql = + (renames: Set) => + async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - return result; - } catch (e) { - console.error(e); - throw e; - } -}; + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; -export const testColumnsResolver = (renames: Set) => -async ( - input: ColumnsResolverInput, -): Promise> => { - try { - if ( - input.created.length === 0 - || input.deleted.length === 0 - || renames.size === 0 - ) { - return { - tableName: input.tableName, - schema: input.schema, - created: input.created, - renamed: [], - deleted: input.deleted, - }; - } + const result: { + created: ViewSquashed[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: ViewSquashed; to: ViewSquashed }[]; + deleted: ViewSquashed[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - let createdColumns = [...input.created]; - let deletedColumns = [...input.deleted]; + for (let rename of renames) { + const [from, to] = rename.split('->'); - const renamed: { from: Column; to: Column }[] = []; + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); - const schema = input.schema || 'public'; + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; + }); - for (let rename of renames) { - const [from, to] = rename.split('->'); + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, + }); + } + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } + } - const idxFrom = deletedColumns.findIndex((it) => { - return `${schema}.${input.tableName}.${it.name}` === from; - }); + result.created = createdViews; + result.deleted = deletedViews; - if (idxFrom >= 0) { - const idxTo = createdColumns.findIndex((it) => { - return `${schema}.${input.tableName}.${it.name}` === to; - }); + return result; + } catch (e) { + console.error(e); + throw e; + } + }; + +export const testViewsResolverSqlite = + (renames: Set) => async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } + + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; + + const result: { + created: SqliteView[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: SqliteView; to: SqliteView }[]; + deleted: SqliteView[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; + + for (let rename of renames) { + const [from, to] = rename.split('->'); - renamed.push({ - from: deletedColumns[idxFrom], - to: createdColumns[idxTo], + const idxFrom = deletedViews.findIndex((it) => { + return it.name === from; }); - delete createdColumns[idxTo]; - delete deletedColumns[idxFrom]; + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return it.name === to; + }); + + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } - createdColumns = createdColumns.filter(Boolean); - deletedColumns = deletedColumns.filter(Boolean); + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } } - } - return { - tableName: input.tableName, - schema: input.schema, - created: createdColumns, - deleted: deletedColumns, - renamed, - }; - } catch (e) { - console.error(e); - throw e; - } -}; + result.created = createdViews; + result.deleted = deletedViews; + + return result; + } catch (e) { + console.error(e); + throw e; + } + }; export const diffTestSchemasPush = async ( client: PGlite, @@ -414,12 +606,45 @@ export const diffTestSchemasPush = async ( cli: boolean = false, schemas: string[] = ['public'], casing?: CasingType | undefined, + sqlStatementsToRun: { before?: string[]; after?: string[]; runApply?: boolean } = { + before: [], + after: [], + runApply: true, + }, ) => { - const { sqlStatements } = await applyPgDiffs(left, casing); - for (const st of sqlStatements) { + const shouldRunApply = sqlStatementsToRun.runApply === undefined ? true : sqlStatementsToRun.runApply; + + for (const st of sqlStatementsToRun.before ?? []) { + await client.query(st); + } + + if (shouldRunApply) { + const res = await applyPgDiffs(left, casing); + for (const st of res.sqlStatements) { + await client.query(st); + } + } + + for (const st of sqlStatementsToRun.after ?? []) { await client.query(st); } + const materializedViewsForRefresh = Object.values(left).filter((it) => + isPgMaterializedView(it) + ) as PgMaterializedView[]; + + // refresh all mat views + for (const view of materializedViewsForRefresh) { + const viewConf = getMaterializedViewConfig(view); + if (viewConf.isExisting) continue; + + await client.exec( + `REFRESH MATERIALIZED VIEW "${viewConf.schema ?? 'public'}"."${viewConf.name}"${ + viewConf.withNoData ? ' WITH NO DATA;' : ';' + }`, + ); + } + // do introspect into PgSchemaInternal const introspectedSchema = await fromDatabase( { @@ -440,11 +665,17 @@ export const diffTestSchemasPush = async ( const leftSequences = Object.values(right).filter((it) => isPgSequence(it)) as PgSequence[]; + const leftViews = Object.values(right).filter((it) => isPgView(it)) as PgView[]; + + const leftMaterializedViews = Object.values(right).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; + const serialized2 = generatePgSnapshot( leftTables, leftEnums, leftSchemas, leftSequences, + leftViews, + leftMaterializedViews, casing, ); @@ -484,11 +715,41 @@ export const diffTestSchemasPush = async ( testSequencesResolver(renames), testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolver(renames), validatedPrev, validatedCur, 'push', ); - return { sqlStatements, statements }; + + const { + shouldAskForApprove, + statementsToExecute, + columnsToRemove, + tablesToRemove, + tablesToTruncate, + infoToPrint, + schemasToRemove, + matViewsToRemove, + } = await pgSuggestions( + { + query: async (sql: string, params: any[] = []) => { + return (await client.query(sql, params)).rows as T[]; + }, + }, + statements, + ); + + return { + sqlStatements: statementsToExecute, + statements, + shouldAskForApprove, + columnsToRemove, + tablesToRemove, + tablesToTruncate, + infoToPrint, + schemasToRemove, + matViewsToRemove, + }; } else { const { sqlStatements, statements } = await applyPgSnapshotsDiff( sn1, @@ -498,6 +759,7 @@ export const diffTestSchemasPush = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, 'push', @@ -514,6 +776,7 @@ export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | unde prevId: '0', tables: {}, enums: {}, + views: {}, schemas: {}, sequences: {}, _meta: { @@ -531,7 +794,11 @@ export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | unde const sequences = Object.values(sn).filter((it) => isPgSequence(it)) as PgSequence[]; - const serialized1 = generatePgSnapshot(tables, enums, schemas, sequences, casing); + const views = Object.values(sn).filter((it) => isPgView(it)) as PgView[]; + + const materializedViews = Object.values(sn).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; + + const serialized1 = generatePgSnapshot(tables, enums, schemas, sequences, views, materializedViews, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -556,6 +823,7 @@ export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | unde testSequencesResolver(new Set()), testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolver(new Set()), validatedPrev, validatedCur, ); @@ -585,11 +853,21 @@ export const diffTestSchemas = async ( const rightSequences = Object.values(right).filter((it) => isPgSequence(it)) as PgSequence[]; + const leftViews = Object.values(left).filter((it) => isPgView(it)) as PgView[]; + + const rightViews = Object.values(right).filter((it) => isPgView(it)) as PgView[]; + + const leftMaterializedViews = Object.values(left).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; + + const rightMaterializedViews = Object.values(right).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; + const serialized1 = generatePgSnapshot( leftTables, leftEnums, leftSchemas, leftSequences, + leftViews, + leftMaterializedViews, casing, ); const serialized2 = generatePgSnapshot( @@ -597,6 +875,8 @@ export const diffTestSchemas = async ( rightEnums, rightSchemas, rightSequences, + rightViews, + rightMaterializedViews, casing, ); @@ -636,6 +916,7 @@ export const diffTestSchemas = async ( testSequencesResolver(renames), testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolver(renames), validatedPrev, validatedCur, ); @@ -649,6 +930,7 @@ export const diffTestSchemas = async ( sequencesResolver, tablesResolver, columnsResolver, + viewsResolver, validatedPrev, validatedCur, ); @@ -682,7 +964,9 @@ export const diffTestSchemasPushMysql = async ( const leftTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - const serialized2 = generateMySqlSnapshot(leftTables, casing); + const leftViews = Object.values(right).filter((it) => is(it, MySqlView)) as MySqlView[]; + + const serialized2 = generateMySqlSnapshot(leftTables, leftViews, casing); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -717,6 +1001,7 @@ export const diffTestSchemasPushMysql = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverMySql(renames), validatedPrev, validatedCur, 'push', @@ -728,6 +1013,7 @@ export const diffTestSchemasPushMysql = async ( sn2, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, 'push', @@ -742,6 +1028,7 @@ export const applyMySqlDiffs = async (sn: MysqlSchema, casing: CasingType | unde dialect: 'mysql', id: '0', prevId: '0', + views: {}, tables: {}, enums: {}, schemas: {}, @@ -754,7 +1041,9 @@ export const applyMySqlDiffs = async (sn: MysqlSchema, casing: CasingType | unde const tables = Object.values(sn).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - const serialized1 = generateMySqlSnapshot(tables, casing); + const views = Object.values(sn).filter((it) => is(it, MySqlView)) as MySqlView[]; + + const serialized1 = generateMySqlSnapshot(tables, views, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -776,6 +1065,7 @@ export const applyMySqlDiffs = async (sn: MysqlSchema, casing: CasingType | unde sn1, testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolverMySql(new Set()), validatedPrev, validatedCur, ); @@ -791,10 +1081,14 @@ export const diffTestSchemasMysql = async ( ) => { const leftTables = Object.values(left).filter((it) => is(it, MySqlTable)) as MySqlTable[]; + const leftViews = Object.values(left).filter((it) => is(it, MySqlView)) as MySqlView[]; + const rightTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - const serialized1 = generateMySqlSnapshot(leftTables, casing); - const serialized2 = generateMySqlSnapshot(rightTables, casing); + const rightViews = Object.values(right).filter((it) => is(it, MySqlView)) as MySqlView[]; + + const serialized1 = generateMySqlSnapshot(leftTables, leftViews, casing); + const serialized2 = generateMySqlSnapshot(rightTables, rightViews, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -829,6 +1123,7 @@ export const diffTestSchemasMysql = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverMySql(renames), validatedPrev, validatedCur, ); @@ -840,6 +1135,7 @@ export const diffTestSchemasMysql = async ( sn2, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, ); @@ -880,7 +1176,9 @@ export const diffTestSchemasPushSqlite = async ( const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized2 = generateSqliteSnapshot(rightTables, casing); + const rightViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized2 = generateSqliteSnapshot(rightTables, rightViews, casing); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -912,6 +1210,7 @@ export const diffTestSchemasPushSqlite = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverSqlite(renames), sch1, sch2, 'push', @@ -956,6 +1255,7 @@ export const diffTestSchemasPushSqlite = async ( sn2, tablesResolver, columnsResolver, + sqliteViewsResolver, sch1, sch2, 'push', @@ -992,20 +1292,15 @@ export async function diffTestSchemasPushLibSQL( run: async (query: string) => { await client.execute(query); }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, }, undefined, ); const leftTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized2 = generateSqliteSnapshot(leftTables, casing); + const leftViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized2 = generateSqliteSnapshot(leftTables, leftViews, casing); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1037,40 +1332,28 @@ export async function diffTestSchemasPushLibSQL( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverSqlite(renames), sch1, sch2, 'push', ); - const { - statementsToExecute, - columnsToRemove, - infoToPrint, - shouldAskForApprove, - tablesToRemove, - tablesToTruncate, - } = await libSqlLogSuggestionsAndReturn( - { - query: async (sql: string, params?: any[]) => { - const res = await client.execute({ sql, args: params || [] }); - return res.rows as T[]; + const { statementsToExecute, columnsToRemove, infoToPrint, shouldAskForApprove, tablesToRemove, tablesToTruncate } = + await libSqlLogSuggestionsAndReturn( + { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); + }, }, - run: async (query: string) => { - await client.execute(query); - }, - batch: async ( - queries: { query: string; values?: any[] | undefined }[], - ) => { - await client.batch( - queries.map((it) => ({ sql: it.query, args: it.values ?? [] })), - ); - }, - }, - statements, - sn1, - sn2, - _meta!, - ); + statements, + sn1, + sn2, + _meta!, + ); return { sqlStatements: statementsToExecute, @@ -1087,6 +1370,7 @@ export async function diffTestSchemasPushLibSQL( sn2, tablesResolver, columnsResolver, + sqliteViewsResolver, sch1, sch2, 'push', @@ -1107,6 +1391,7 @@ export const applySqliteDiffs = async ( prevId: '0', tables: {}, enums: {}, + views: {}, schemas: {}, _meta: { schemas: {}, @@ -1117,7 +1402,9 @@ export const applySqliteDiffs = async ( const tables = Object.values(sn).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(tables, casing); + const views = Object.values(sn).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized1 = generateSqliteSnapshot(tables, views, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -1136,6 +1423,7 @@ export const applySqliteDiffs = async ( sn1, testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolverSqlite(new Set()), dryRun, sch1, action, @@ -1155,6 +1443,7 @@ export const applyLibSQLDiffs = async ( id: '0', prevId: '0', tables: {}, + views: {}, enums: {}, schemas: {}, _meta: { @@ -1166,7 +1455,9 @@ export const applyLibSQLDiffs = async ( const tables = Object.values(sn).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(tables, casing); + const views = Object.values(sn).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized1 = generateSqliteSnapshot(tables, views, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -1185,6 +1476,7 @@ export const applyLibSQLDiffs = async ( sn1, testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolverSqlite(new Set()), dryRun, sch1, action, @@ -1202,10 +1494,14 @@ export const diffTestSchemasSqlite = async ( ) => { const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + const leftViews = Object.values(left).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(leftTables, casing); - const serialized2 = generateSqliteSnapshot(rightTables, casing); + const rightViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized1 = generateSqliteSnapshot(leftTables, leftViews, casing); + const serialized2 = generateSqliteSnapshot(rightTables, rightViews, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1237,6 +1533,7 @@ export const diffTestSchemasSqlite = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverSqlite(renames), sch1, sch2, ); @@ -1248,6 +1545,7 @@ export const diffTestSchemasSqlite = async ( sn2, tablesResolver, columnsResolver, + sqliteViewsResolver, sch1, sch2, ); @@ -1263,10 +1561,14 @@ export const diffTestSchemasLibSQL = async ( ) => { const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + const leftViews = Object.values(left).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; - const serialized1 = generateSqliteSnapshot(leftTables, casing); - const serialized2 = generateSqliteSnapshot(rightTables, casing); + const rightViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[]; + + const serialized1 = generateSqliteSnapshot(leftTables, leftViews, casing); + const serialized2 = generateSqliteSnapshot(rightTables, rightViews, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1298,6 +1600,7 @@ export const diffTestSchemasLibSQL = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), + testViewsResolverSqlite(renames), sch1, sch2, ); @@ -1309,6 +1612,7 @@ export const diffTestSchemasLibSQL = async ( sn2, tablesResolver, columnsResolver, + sqliteViewsResolver, sch1, sch2, ); @@ -1342,19 +1646,34 @@ export const introspectPgToFile = async ( schemas, ); + const { version: initV, dialect: initD, ...initRest } = introspectedSchema; + + const initSch = { + version: '7', + dialect: 'postgresql', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashPgScheme(initSch); + const validatedCur = pgSchema.parse(initSch); + + // write to ts file const file = schemaToTypeScript(introspectedSchema, 'camel'); - fs.writeFileSync(`tests/introspect/${testName}.ts`, file.file); + fs.writeFileSync(`tests/introspect/postgres/${testName}.ts`, file.file); - const response = await prepareFromPgImports([ - `tests/introspect/${testName}.ts`, - ]); + // generate snapshot from ts file + const response = await prepareFromPgImports([`tests/introspect/postgres/${testName}.ts`]); const afterFileImports = generatePgSnapshot( response.tables, response.enums, response.schemas, response.sequences, + response.views, + response.matViews, casing, ); @@ -1371,51 +1690,20 @@ export const introspectPgToFile = async ( const sn2AfterIm = squashPgScheme(sch2); const validatedCurAfterImport = pgSchema.parse(sch2); - const leftTables = Object.values(initSchema).filter((it) => is(it, PgTable)) as PgTable[]; - - const leftSchemas = Object.values(initSchema).filter((it) => is(it, PgSchema)) as PgSchema[]; - - const leftEnums = Object.values(initSchema).filter((it) => isPgEnum(it)) as PgEnum[]; - - const leftSequences = Object.values(initSchema).filter((it) => isPgSequence(it)) as PgSequence[]; - - const initSnapshot = generatePgSnapshot( - leftTables, - leftEnums, - leftSchemas, - leftSequences, - casing, - ); - - const { version: initV, dialect: initD, ...initRest } = initSnapshot; - - const initSch = { - version: '7', - dialect: 'postgresql', - id: '0', - prevId: '0', - ...initRest, - } as const; - - const initSn = squashPgScheme(initSch); - const validatedCur = pgSchema.parse(initSch); - - const { - sqlStatements: afterFileSqlStatements, - statements: afterFileStatements, - } = await applyPgSnapshotsDiff( - sn2AfterIm, + const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyPgSnapshotsDiff( initSn, + sn2AfterIm, testSchemasResolver(new Set()), testEnumsResolver(new Set()), testSequencesResolver(new Set()), testTablesResolver(new Set()), testColumnsResolver(new Set()), - validatedCurAfterImport, + testViewsResolver(new Set()), validatedCur, + validatedCurAfterImport, ); - fs.rmSync(`tests/introspect/${testName}.ts`); + fs.rmSync(`tests/introspect/postgres/${testName}.ts`); return { sqlStatements: afterFileSqlStatements, @@ -1447,15 +1735,26 @@ export const introspectMySQLToFile = async ( schema, ); + const { version: initV, dialect: initD, ...initRest } = introspectedSchema; + + const initSch = { + version: '5', + dialect: 'mysql', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashMysqlScheme(initSch); + const validatedCur = mysqlSchema.parse(initSch); + const file = schemaToTypeScriptMySQL(introspectedSchema, 'camel'); fs.writeFileSync(`tests/introspect/mysql/${testName}.ts`, file.file); - const response = await prepareFromMySqlImports([ - `tests/introspect/mysql/${testName}.ts`, - ]); + const response = await prepareFromMySqlImports([`tests/introspect/mysql/${testName}.ts`]); - const afterFileImports = generateMySqlSnapshot(response.tables, casing); + const afterFileImports = generateMySqlSnapshot(response.tables, response.views, casing); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -1470,31 +1769,12 @@ export const introspectMySQLToFile = async ( const sn2AfterIm = squashMysqlScheme(sch2); const validatedCurAfterImport = mysqlSchema.parse(sch2); - const leftTables = Object.values(initSchema).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - - const initSnapshot = generateMySqlSnapshot(leftTables, casing); - - const { version: initV, dialect: initD, ...initRest } = initSnapshot; - - const initSch = { - version: '5', - dialect: 'mysql', - id: '0', - prevId: '0', - ...initRest, - } as const; - - const initSn = squashMysqlScheme(initSch); - const validatedCur = mysqlSchema.parse(initSch); - - const { - sqlStatements: afterFileSqlStatements, - statements: afterFileStatements, - } = await applyMysqlSnapshotsDiff( + const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyMysqlSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolverMySql(new Set()), validatedCurAfterImport, validatedCur, ); @@ -1532,15 +1812,27 @@ export const introspectSQLiteToFile = async ( undefined, ); + const { version: initV, dialect: initD, ...initRest } = introspectedSchema; + + const initSch = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashSqliteScheme(initSch); + + const validatedCur = sqliteSchema.parse(initSch); + const file = schemaToTypeScriptSQLite(introspectedSchema, 'camel'); fs.writeFileSync(`tests/introspect/sqlite/${testName}.ts`, file.file); - const response = await prepareFromSqliteImports([ - `tests/introspect/sqlite/${testName}.ts`, - ]); + const response = await prepareFromSqliteImports([`tests/introspect/sqlite/${testName}.ts`]); - const afterFileImports = generateSqliteSnapshot(response.tables, casing); + const afterFileImports = generateSqliteSnapshot(response.tables, response.views, casing); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -1555,11 +1847,50 @@ export const introspectSQLiteToFile = async ( const sn2AfterIm = squashSqliteScheme(sch2); const validatedCurAfterImport = sqliteSchema.parse(sch2); - const leftTables = Object.values(initSchema).filter((it) => is(it, SQLiteTable)) as SQLiteTable[]; + const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applySqliteSnapshotsDiff( + sn2AfterIm, + initSn, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + testViewsResolverSqlite(new Set()), + validatedCurAfterImport, + validatedCur, + ); + + fs.rmSync(`tests/introspect/sqlite/${testName}.ts`); - const initSnapshot = generateSqliteSnapshot(leftTables, casing); + return { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + }; +}; - const { version: initV, dialect: initD, ...initRest } = initSnapshot; +export const introspectLibSQLToFile = async ( + client: Client, + initSchema: SqliteSchema, + testName: string, + casing?: CasingType | undefined, +) => { + // put in db + const { sqlStatements } = await applyLibSQLDiffs(initSchema); + for (const st of sqlStatements) { + client.execute(st); + } + + // introspect to schema + const introspectedSchema = await fromSqliteDatabase( + { + query: async (sql: string, params: any[] = []) => { + return (await client.execute({ sql, args: params })).rows as T[]; + }, + run: async (query: string) => { + client.execute(query); + }, + }, + undefined, + ); + + const { version: initV, dialect: initD, ...initRest } = introspectedSchema; const initSch = { version: '6', @@ -1570,21 +1901,41 @@ export const introspectSQLiteToFile = async ( } as const; const initSn = squashSqliteScheme(initSch); + const validatedCur = sqliteSchema.parse(initSch); - const { - sqlStatements: afterFileSqlStatements, - statements: afterFileStatements, - } = await applySqliteSnapshotsDiff( + const file = schemaToTypeScriptSQLite(introspectedSchema, 'camel'); + + fs.writeFileSync(`tests/introspect/libsql/${testName}.ts`, file.file); + + const response = await prepareFromSqliteImports([`tests/introspect/libsql/${testName}.ts`]); + + const afterFileImports = generateSqliteSnapshot(response.tables, response.views, casing); + + const { version: v2, dialect: d2, ...rest2 } = afterFileImports; + + const sch2 = { + version: '6', + dialect: 'sqlite', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn2AfterIm = squashSqliteScheme(sch2); + const validatedCurAfterImport = sqliteSchema.parse(sch2); + + const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyLibSQLSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), testColumnsResolver(new Set()), + testViewsResolverSqlite(new Set()), validatedCurAfterImport, validatedCur, ); - fs.rmSync(`tests/introspect/sqlite/${testName}.ts`); + fs.rmSync(`tests/introspect/libsql/${testName}.ts`); return { sqlStatements: afterFileSqlStatements, diff --git a/drizzle-kit/tests/sqlite-checks.test.ts b/drizzle-kit/tests/sqlite-checks.test.ts new file mode 100644 index 000000000..d1824e441 --- /dev/null +++ b/drizzle-kit/tests/sqlite-checks.test.ts @@ -0,0 +1,308 @@ +import { sql } from 'drizzle-orm'; +import { check, int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSqlite } from './schemaDiffer'; + +test('create table with check', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasSqlite({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_create_table', + tableName: 'users', + columns: [ + { + name: 'id', + type: 'integer', + notNull: true, + primaryKey: true, + autoincrement: false, + }, + { + name: 'age', + type: 'integer', + notNull: false, + primaryKey: false, + autoincrement: false, + }, + ], + compositePKs: [], + checkConstraints: ['some_check_name;"users"."age" > 21'], + referenceData: [], + uniqueConstraints: [], + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("users"."age" > 21) +);\n`); +}); + +test('add check contraint to existing table', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }), + }; + + const { sqlStatements, statements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: ['some_check_name;"users"."age" > 21'], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('drop check contraint to existing table', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }), + }; + + const { sqlStatements, statements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('rename check constraint', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('new_some_check_name', sql`${table.age} > 21`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [`new_some_check_name;"users"."age" > 21`], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "new_some_check_name" CHECK("__new_users"."age" > 21) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('rename check constraint', async (t) => { + const from = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 21`), + })), + }; + + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + }, (table) => ({ + checkConstraint: check('some_check_name', sql`${table.age} > 10`), + })), + }; + + const { sqlStatements, statements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + columns: [ + { + autoincrement: false, + generated: undefined, + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + { + autoincrement: false, + generated: undefined, + name: 'age', + notNull: false, + primaryKey: false, + type: 'integer', + }, + ], + compositePKs: [], + referenceData: [], + tableName: 'users', + type: 'recreate_table', + uniqueConstraints: [], + checkConstraints: [`some_check_name;"users"."age" > 10`], + }); + + expect(sqlStatements.length).toBe(6); + expect(sqlStatements[0]).toBe('PRAGMA foreign_keys=OFF;'); + expect(sqlStatements[1]).toBe(`CREATE TABLE \`__new_users\` ( +\t\`id\` integer PRIMARY KEY NOT NULL, +\t\`age\` integer, +\tCONSTRAINT "some_check_name" CHECK("__new_users"."age" > 10) +);\n`); + expect(sqlStatements[2]).toBe(`INSERT INTO \`__new_users\`("id", "age") SELECT "id", "age" FROM \`users\`;`); + expect(sqlStatements[3]).toBe(`DROP TABLE \`users\`;`); + expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); + expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); +}); + +test('create checks with same names', async (t) => { + const to = { + users: sqliteTable('users', { + id: int('id').primaryKey(), + age: int('age'), + name: text('name'), + }, (table) => ({ + checkConstraint1: check('some_check_name', sql`${table.age} > 21`), + checkConstraint2: check('some_check_name', sql`${table.name} != 'Alex'`), + })), + }; + + await expect(diffTestSchemasSqlite({}, to, [])).rejects.toThrowError(); +}); diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index 04dbb940c..b7b4c7f6b 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -37,6 +37,7 @@ test('create table with id', async (t) => { uniqueConstraints: [], referenceData: [], compositePKs: [], + checkConstraints: [], }); }); @@ -363,6 +364,7 @@ test('add foreign key #1', async (t) => { }], tableName: 'users', uniqueConstraints: [], + checkConstraints: [], } as JsonRecreateTableStatement, ); }); @@ -426,6 +428,7 @@ test('add foreign key #2', async (t) => { }], tableName: 'users', uniqueConstraints: [], + checkConstraints: [], } as JsonRecreateTableStatement); }); @@ -584,6 +587,7 @@ test('alter table add composite pk', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -621,6 +625,7 @@ test('alter column drop not null', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -658,6 +663,7 @@ test('alter column add not null', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -696,6 +702,7 @@ test('alter column add default', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -733,6 +740,7 @@ test('alter column drop default', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -771,6 +779,7 @@ test('alter column add default not null', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); }); @@ -813,6 +822,7 @@ test('alter column add default not null with indexes', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ data: 'index_name;name;false;', @@ -869,6 +879,7 @@ test('alter column drop default not null', async (t) => { referenceData: [], tableName: 'table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); expect(sqlStatements[0]).toBe(`PRAGMA foreign_keys=OFF;`); @@ -997,6 +1008,7 @@ test('recreate table with nested references', async (t) => { tableName: 'users', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }); expect(sqlStatements.length).toBe(6); diff --git a/drizzle-kit/tests/sqlite-generated.test.ts b/drizzle-kit/tests/sqlite-generated.test.ts index 749dde825..2d3ceed97 100644 --- a/drizzle-kit/tests/sqlite-generated.test.ts +++ b/drizzle-kit/tests/sqlite-generated.test.ts @@ -508,6 +508,7 @@ test('generated as callback: add table with column with stored generated constra tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -576,6 +577,7 @@ test('generated as callback: add table with column with virtual generated constr tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1076,6 +1078,7 @@ test('generated as sql: add table with column with stored generated constraint', tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1144,6 +1147,7 @@ test('generated as sql: add table with column with virtual generated constraint' tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1644,6 +1648,7 @@ test('generated as string: add table with column with stored generated constrain tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ @@ -1712,6 +1717,7 @@ test('generated as string: add table with column with virtual generated constrai tableName: 'users', type: 'sqlite_create_table', uniqueConstraints: [], + checkConstraints: [], }, ]); expect(sqlStatements).toStrictEqual([ diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index 81ac7f100..0390ff28e 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -28,6 +28,7 @@ test('add table #1', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); }); @@ -56,6 +57,7 @@ test('add table #2', async () => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }); }); @@ -95,6 +97,7 @@ test('add table #3', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); }); @@ -114,6 +117,7 @@ test('add table #4', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'sqlite_create_table', @@ -122,6 +126,7 @@ test('add table #4', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); }); @@ -148,6 +153,7 @@ test('add table #6', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ type: 'drop_table', @@ -185,6 +191,7 @@ test('add table #7', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); }); @@ -222,6 +229,7 @@ test('add table #8', async () => { ], compositePKs: [], uniqueConstraints: [], + checkConstraints: [], referenceData: [ { columnsFrom: ['reportee_id'], @@ -277,6 +285,7 @@ test('add table #9', async () => { compositePKs: [], uniqueConstraints: [], referenceData: [], + checkConstraints: [], }); expect(statements[1]).toStrictEqual({ diff --git a/drizzle-kit/tests/sqlite-views.test.ts b/drizzle-kit/tests/sqlite-views.test.ts new file mode 100644 index 000000000..8021ba37e --- /dev/null +++ b/drizzle-kit/tests/sqlite-views.test.ts @@ -0,0 +1,218 @@ +import { sql } from 'drizzle-orm'; +import { int, sqliteTable, sqliteView } from 'drizzle-orm/sqlite-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSqlite } from './schemaDiffer'; + +test('create view', async () => { + const users = sqliteTable('users', { id: int('id').default(1) }); + const view = sqliteView('view').as((qb) => qb.select().from(users)); + const to = { + users: users, + testView: view, + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'sqlite_create_table', + tableName: 'users', + columns: [{ + autoincrement: false, + default: 1, + name: 'id', + type: 'integer', + primaryKey: false, + notNull: false, + }], + compositePKs: [], + uniqueConstraints: [], + referenceData: [], + checkConstraints: [], + }); + expect(statements[1]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'view', + definition: 'select "id" from "users"', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`CREATE TABLE \`users\` ( +\t\`id\` integer DEFAULT 1 +);\n`); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`view\` AS select "id" from "users";`); +}); + +test('drop view', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + `DROP VIEW \`view\`;`, + ); +}); + +test('alter view', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users WHERE users.id = 1`), + }; + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + name: 'view', + type: 'sqlite_create_view', + definition: 'SELECT * FROM users WHERE users.id = 1', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe( + `DROP VIEW \`view\`;`, + ); + expect(sqlStatements[1]).toBe( + `CREATE VIEW \`view\` AS SELECT * FROM users WHERE users.id = 1;`, + ); +}); + +test('create view with existing flag', async () => { + const view = sqliteView('view', {}).existing(); + const to = { + testView: view, + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite({}, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop view with existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + }; + + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view with existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).existing(), + }; + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, ['view->new_view']); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view and drop existing flag', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).existing(), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, ['view->new_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'new_view', + definition: 'SELECT * FROM users', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP VIEW \`view\`;`); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users;`); +}); + +test('rename view and alter ".as"', async () => { + const users = sqliteTable('users', { + id: int('id').primaryKey({ autoIncrement: true }), + }); + + const from = { + users: users, + testView: sqliteView('view', { id: int('id') }).as(sql`SELECT * FROM users`), + }; + const to = { + users, + testView: sqliteView('new_view', { id: int('id') }).as(sql`SELECT * FROM users WHERE 1=1`), + }; + const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, ['view->new_view']); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + type: 'sqlite_create_view', + name: 'new_view', + definition: 'SELECT * FROM users WHERE 1=1', + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe('DROP VIEW `view`;'); + expect(sqlStatements[1]).toBe(`CREATE VIEW \`new_view\` AS SELECT * FROM users WHERE 1=1;`); +}); diff --git a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts index 47447decd..449b61c6c 100644 --- a/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/libsql-statements-combiner.test.ts @@ -83,9 +83,11 @@ test(`rename table and drop index`, async (t) => { user_id_iq_pk: 'id,iq', }, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -122,9 +124,11 @@ test(`rename table and drop index`, async (t) => { new_user_id_iq_pk: 'id,iq', }, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -242,6 +246,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, autoincrement2: { name: 'autoincrement2', @@ -258,6 +263,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, dropNotNull: { name: 'dropNotNull', @@ -274,9 +280,11 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -297,6 +305,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, autoincrement2: { name: 'autoincrement2', @@ -313,6 +322,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, dropNotNull: { name: 'dropNotNull', @@ -329,9 +339,11 @@ test(`drop, set autoincrement. drop not null`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -350,6 +362,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'recreate_table', @@ -366,6 +379,7 @@ test(`drop, set autoincrement. drop not null`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'alter_table_alter_column_drop_notnull', @@ -498,6 +512,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, pk1: { name: 'pk1', @@ -514,6 +529,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, pk2: { name: 'pk2', @@ -530,6 +546,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, ref_table: { name: 'ref_table', @@ -546,9 +563,11 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -572,6 +591,7 @@ test(`drop and set primary key. create reference`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, pk1: { name: 'pk1', @@ -588,6 +608,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, pk2: { name: 'pk2', @@ -604,6 +625,7 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, ref_table: { name: 'ref_table', @@ -620,9 +642,11 @@ test(`drop and set primary key. create reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -641,6 +665,7 @@ test(`drop and set primary key. create reference`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'recreate_table', @@ -657,6 +682,7 @@ test(`drop and set primary key. create reference`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'create_reference', @@ -761,6 +787,7 @@ test(`set and drop multiple columns reference`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, fk2: { name: 'fk2', @@ -784,6 +811,7 @@ test(`set and drop multiple columns reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, ref_table: { name: 'ref_table', @@ -807,9 +835,11 @@ test(`set and drop multiple columns reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -837,6 +867,7 @@ test(`set and drop multiple columns reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, fk2: { name: 'fk2', @@ -863,6 +894,7 @@ test(`set and drop multiple columns reference`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, ref_table: { name: 'ref_table', @@ -886,9 +918,11 @@ test(`set and drop multiple columns reference`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -914,6 +948,7 @@ test(`set and drop multiple columns reference`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'recreate_table', @@ -947,6 +982,7 @@ test(`set and drop multiple columns reference`, async (t) => { }, ], uniqueConstraints: [], + checkConstraints: [], }, ]; expect(libSQLCombineStatements(statements, json2)).toStrictEqual( @@ -1054,6 +1090,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, simple: { name: 'simple', @@ -1070,6 +1107,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, unique: { name: 'unique', @@ -1088,9 +1126,11 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -1111,6 +1151,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, simple: { name: 'simple', @@ -1127,6 +1168,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, unique: { name: 'unique', @@ -1145,9 +1187,11 @@ test(`set new type for primary key, unique and normal column`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -1166,6 +1210,7 @@ test(`set new type for primary key, unique and normal column`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, { type: 'alter_table_alter_column_set_type', @@ -1261,6 +1306,7 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1284,9 +1330,11 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -1330,6 +1378,7 @@ test(`add columns. set fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1353,9 +1402,11 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -1457,6 +1508,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1480,9 +1532,11 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -1526,6 +1580,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1549,9 +1604,11 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -1632,6 +1689,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1655,9 +1713,11 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -1701,6 +1761,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1724,9 +1785,11 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements = [ diff --git a/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts b/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts index 2fcaf6436..20f953da6 100644 --- a/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts +++ b/drizzle-kit/tests/statements-combiner/sqlite-statements-combiner.test.ts @@ -60,9 +60,11 @@ test(`renamed column and altered this column type`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -97,9 +99,11 @@ test(`renamed column and altered this column type`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -132,6 +136,7 @@ test(`renamed column and altered this column type`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, ]; expect(sqliteCombineStatements(statements, json2)).toStrictEqual( @@ -188,9 +193,11 @@ test(`renamed column and droped column "test"`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -225,9 +232,11 @@ test(`renamed column and droped column "test"`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements: JsonStatement[] = [ @@ -301,9 +310,11 @@ test(`droped column that is part of composite pk`, async (t) => { user_id_iq_pk: 'id,iq', }, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -331,9 +342,11 @@ test(`droped column that is part of composite pk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements: JsonStatement[] = [ @@ -359,6 +372,7 @@ test(`droped column that is part of composite pk`, async (t) => { compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, ]; expect(sqliteCombineStatements(statements, json2)).toStrictEqual( @@ -466,6 +480,7 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -496,9 +511,11 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -535,6 +552,7 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -565,9 +583,11 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements: JsonStatement[] = [ @@ -613,6 +633,7 @@ test(`drop column "ref"."name", rename column "ref"."age". dropped primary key " compositePKs: [], referenceData: [], uniqueConstraints: [], + checkConstraints: [], }, ]; @@ -649,6 +670,7 @@ test(`create reference on exising column (table includes unique index). expect t foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, unique: { name: 'unique', @@ -674,9 +696,11 @@ test(`create reference on exising column (table includes unique index). expect t foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -697,6 +721,7 @@ test(`create reference on exising column (table includes unique index). expect t foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, unique: { name: 'unique', @@ -724,9 +749,11 @@ test(`create reference on exising column (table includes unique index). expect t }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements: JsonStatement[] = [ @@ -762,6 +789,7 @@ test(`create reference on exising column (table includes unique index). expect t }, ], uniqueConstraints: [], + checkConstraints: [], }, { data: 'unique_unique_unique;unique;true;', @@ -839,6 +867,7 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -862,9 +891,11 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -908,6 +939,7 @@ test(`add columns. set fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -931,9 +963,11 @@ test(`add columns. set fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements = [ @@ -987,6 +1021,7 @@ test(`add columns. set fk`, async (t) => { tableName: 'ref', type: 'recreate_table', uniqueConstraints: [], + checkConstraints: [], }, ]; expect(sqliteCombineStatements(statements, json2)).toStrictEqual( @@ -1053,6 +1088,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1076,9 +1112,11 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const json2: SQLiteSchemaSquashed = { version: '6', @@ -1122,6 +1160,7 @@ test(`add column and fk`, async (t) => { }, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, user: { name: 'user', @@ -1145,9 +1184,11 @@ test(`add column and fk`, async (t) => { foreignKeys: {}, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraints: {}, }, }, enums: {}, + views: {}, }; const newJsonStatements = [ diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 829441886..bd3221754 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.34.1", + "version": "0.35.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -162,7 +162,7 @@ "@cloudflare/workers-types": "^4.20230904.0", "@electric-sql/pglite": "^0.1.1", "@libsql/client": "^0.10.0", - "@miniflare/d1": "^2.14.2", + "@miniflare/d1": "^2.14.4", "@neondatabase/serverless": "^0.9.0", "@op-engineering/op-sqlite": "^2.0.16", "@opentelemetry/api": "^1.4.1", diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index 479cc32fe..1d59bea62 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -1,3 +1,4 @@ +import { RDSDataClient, type RDSDataClientConfig } from '@aws-sdk/client-rds-data'; import { entityKind, is } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -14,7 +15,7 @@ import { } from '~/relations.ts'; import { Param, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import { Table } from '~/table.ts'; -import type { DrizzleConfig, UpdateSet } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError, UpdateSet } from '~/utils.ts'; import type { AwsDataApiClient, AwsDataApiPgQueryResult, AwsDataApiPgQueryResultHKT } from './session.ts'; import { AwsDataApiSession } from './session.ts'; @@ -36,7 +37,7 @@ export interface DrizzleAwsDataApiPgConfig< export class AwsDataApiPgDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'AwsDataApiPgDatabase'; + static override readonly [entityKind]: string = 'AwsDataApiPgDatabase'; override execute< TRow extends Record = Record, @@ -46,7 +47,7 @@ export class AwsDataApiPgDatabase< } export class AwsPgDialect extends PgDialect { - static readonly [entityKind]: string = 'AwsPgDialect'; + static override readonly [entityKind]: string = 'AwsPgDialect'; override escapeParam(num: number): string { return `:${num + 1}`; @@ -87,7 +88,7 @@ export class AwsPgDialect extends PgDialect { } } -export function drizzle = Record>( +function construct = Record>( client: AwsDataApiClient, config: DrizzleAwsDataApiPgConfig, ): AwsDataApiPgDatabase & { @@ -120,3 +121,65 @@ export function drizzle = Record = Record, + TClient extends AwsDataApiClient = RDSDataClient, +>( + ...params: IfNotImported< + RDSDataClientConfig, + [ImportTypeError<'@aws-sdk/client-rds-data'>], + [ + TClient, + DrizzleAwsDataApiPgConfig, + ] | [ + ( + | ( + & DrizzleConfig + & { + connection: RDSDataClientConfig & Omit; + } + ) + | ( + & DrizzleAwsDataApiPgConfig + & { + client: TClient; + } + ) + ), + ] + > +): AwsDataApiPgDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof RDSDataClient) { + return construct(params[0] as TClient, params[1] as DrizzleAwsDataApiPgConfig) as any; + } + + if ((params[0] as { client?: TClient }).client) { + const { client, ...drizzleConfig } = params[0] as { + client: TClient; + } & DrizzleAwsDataApiPgConfig; + + return construct(client, drizzleConfig) as any; + } + + const { connection, ...drizzleConfig } = params[0] as { + connection: RDSDataClientConfig & Omit; + } & DrizzleConfig; + const { resourceArn, database, secretArn, ...rdsConfig } = connection; + + const instance = new RDSDataClient(rdsConfig); + return construct(instance, { resourceArn, database, secretArn, ...drizzleConfig }) as any; +} + +export namespace drizzle { + export function mock = Record>( + config: DrizzleAwsDataApiPgConfig, + ): AwsDataApiPgDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/aws-data-api/pg/session.ts b/drizzle-orm/src/aws-data-api/pg/session.ts index 4fc43ddf6..974f6d3ff 100644 --- a/drizzle-orm/src/aws-data-api/pg/session.ts +++ b/drizzle-orm/src/aws-data-api/pg/session.ts @@ -27,7 +27,7 @@ export type AwsDataApiClient = RDSDataClient; export class AwsDataApiPreparedQuery< T extends PreparedQueryConfig & { values: AwsDataApiPgQueryResult }, > extends PgPreparedQuery { - static readonly [entityKind]: string = 'AwsDataApiPreparedQuery'; + static override readonly [entityKind]: string = 'AwsDataApiPreparedQuery'; private rawQuery: ExecuteStatementCommand; @@ -154,7 +154,7 @@ export class AwsDataApiSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'AwsDataApiSession'; + static override readonly [entityKind]: string = 'AwsDataApiSession'; /** @internal */ readonly rawQuery: AwsDataApiQueryBase; @@ -239,7 +239,7 @@ export class AwsDataApiTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'AwsDataApiTransaction'; + static override readonly [entityKind]: string = 'AwsDataApiTransaction'; override async transaction( transaction: (tx: AwsDataApiTransaction) => Promise, diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 50660e4d6..14e6644bc 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -1,4 +1,4 @@ -import type { Database, RunResult } from 'better-sqlite3'; +import Client, { type Database, type Options, type RunResult } from 'better-sqlite3'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { @@ -9,16 +9,25 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { BetterSQLiteSession } from './session.ts'; +export type DrizzleBetterSQLite3DatabaseConfig = + | ({ + source?: + | string + | Buffer; + } & Options) + | string + | undefined; + export class BetterSQLite3Database = Record> extends BaseSQLiteDatabase<'sync', RunResult, TSchema> { - static readonly [entityKind]: string = 'BetterSQLite3Database'; + static override readonly [entityKind]: string = 'BetterSQLite3Database'; } -export function drizzle = Record>( +function construct = Record>( client: Database, config: DrizzleConfig = {}, ): BetterSQLite3Database & { @@ -51,3 +60,74 @@ export function drizzle = Record = Record, +>( + ...params: IfNotImported< + Database, + [ImportTypeError<'better-sqlite3'>], + | [] + | [ + Database | string, + ] + | [ + Database | string, + DrizzleConfig, + ] + | [ + ( + & DrizzleConfig + & ({ + connection?: DrizzleBetterSQLite3DatabaseConfig; + } | { + client: Database; + }) + ), + ] + > +): BetterSQLite3Database & { + $client: Database; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof Client) { + return construct(params[0] as Database, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, client, ...drizzleConfig } = params[0] as + & { + connection?: DrizzleBetterSQLite3DatabaseConfig; + client?: Database; + } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + if (typeof connection === 'object') { + const { source, ...options } = connection; + + const instance = new Client(source, options); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Client(connection); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Client(params[0]); + + return construct(instance, params[1]) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): BetterSQLite3Database & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/better-sqlite3/session.ts b/drizzle-orm/src/better-sqlite3/session.ts index 5b8d29b81..8a02eb37e 100644 --- a/drizzle-orm/src/better-sqlite3/session.ts +++ b/drizzle-orm/src/better-sqlite3/session.ts @@ -26,7 +26,7 @@ export class BetterSQLiteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'sync', RunResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'BetterSQLiteSession'; + static override readonly [entityKind]: string = 'BetterSQLiteSession'; private logger: Logger; @@ -73,7 +73,7 @@ export class BetterSQLiteTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'sync', RunResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'BetterSQLiteTransaction'; + static override readonly [entityKind]: string = 'BetterSQLiteTransaction'; override transaction(transaction: (tx: BetterSQLiteTransaction) => T): T { const savepointName = `sp${this.nestedIndex}`; @@ -93,7 +93,7 @@ export class BetterSQLiteTransaction< export class PreparedQuery extends PreparedQueryBase< { type: 'sync'; run: RunResult; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'BetterSQLitePreparedQuery'; + static override readonly [entityKind]: string = 'BetterSQLitePreparedQuery'; constructor( private stmt: Statement, diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index abcc09224..91a2e370b 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -1,6 +1,6 @@ /// -import type { Database } from 'bun:sqlite'; +import { Database } from 'bun:sqlite'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { @@ -11,16 +11,44 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { SQLiteBunSession } from './session.ts'; export class BunSQLiteDatabase< TSchema extends Record = Record, > extends BaseSQLiteDatabase<'sync', void, TSchema> { - static readonly [entityKind]: string = 'BunSQLiteDatabase'; + static override readonly [entityKind]: string = 'BunSQLiteDatabase'; } -export function drizzle = Record>( +type DrizzleBunSqliteDatabaseOptions = { + /** + * Open the database as read-only (no write operations, no create). + * + * Equivalent to {@link constants.SQLITE_OPEN_READONLY} + */ + readonly?: boolean; + /** + * Allow creating a new database + * + * Equivalent to {@link constants.SQLITE_OPEN_CREATE} + */ + create?: boolean; + /** + * Open the database as read-write + * + * Equivalent to {@link constants.SQLITE_OPEN_READWRITE} + */ + readwrite?: boolean; +}; + +export type DrizzleBunSqliteDatabaseConfig = + | ({ + source?: string; + } & DrizzleBunSqliteDatabaseOptions) + | string + | undefined; + +function construct = Record>( client: Database, config: DrizzleConfig = {}, ): BunSQLiteDatabase & { @@ -53,3 +81,77 @@ export function drizzle = Record = Record, + TClient extends Database = Database, +>( + ...params: IfNotImported< + Database, + [ImportTypeError<'bun-types'>], + | [] + | [ + TClient | string, + ] + | [ + TClient | string, + DrizzleConfig, + ] + | [ + ( + & DrizzleConfig + & ({ + connection?: DrizzleBunSqliteDatabaseConfig; + } | { + client: TClient; + }) + ), + ] + > +): BunSQLiteDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof Database) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, client, ...drizzleConfig } = params[0] as + & ({ + connection?: DrizzleBunSqliteDatabaseConfig | string; + client?: TClient; + }) + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + if (typeof connection === 'object') { + const { source, ...opts } = connection; + + const options = Object.values(opts).filter((v) => v !== undefined).length ? opts : undefined; + + const instance = new Database(source, options); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Database(connection); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Database(params[0]); + + return construct(instance, params[1]) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): BunSQLiteDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/bun-sqlite/session.ts b/drizzle-orm/src/bun-sqlite/session.ts index ff4da3e6e..fd02e4f00 100644 --- a/drizzle-orm/src/bun-sqlite/session.ts +++ b/drizzle-orm/src/bun-sqlite/session.ts @@ -28,7 +28,7 @@ export class SQLiteBunSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'sync', void, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLiteBunSession'; + static override readonly [entityKind]: string = 'SQLiteBunSession'; private logger: Logger; @@ -83,7 +83,7 @@ export class SQLiteBunTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'sync', void, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLiteBunTransaction'; + static override readonly [entityKind]: string = 'SQLiteBunTransaction'; override transaction(transaction: (tx: SQLiteBunTransaction) => T): T { const savepointName = `sp${this.nestedIndex}`; @@ -103,7 +103,7 @@ export class SQLiteBunTransaction< export class PreparedQuery extends PreparedQueryBase< { type: 'sync'; run: void; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'SQLiteBunPreparedQuery'; + static override readonly [entityKind]: string = 'SQLiteBunPreparedQuery'; constructor( private stmt: Statement, diff --git a/drizzle-orm/src/connect.ts b/drizzle-orm/src/connect.ts deleted file mode 100644 index 6e26b2922..000000000 --- a/drizzle-orm/src/connect.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './monodriver.ts'; -export * from './monomigrator.ts'; diff --git a/drizzle-orm/src/d1/driver.ts b/drizzle-orm/src/d1/driver.ts index 6ec8a5294..7b4bbdfb6 100644 --- a/drizzle-orm/src/d1/driver.ts +++ b/drizzle-orm/src/d1/driver.ts @@ -24,7 +24,7 @@ export type AnyD1Database = IfNotImported< export class DrizzleD1Database< TSchema extends Record = Record, > extends BaseSQLiteDatabase<'async', D1Result, TSchema> { - static readonly [entityKind]: string = 'D1Database'; + static override readonly [entityKind]: string = 'D1Database'; /** @internal */ declare readonly session: SQLiteD1Session>; diff --git a/drizzle-orm/src/d1/session.ts b/drizzle-orm/src/d1/session.ts index 0f2989c12..61ef49315 100644 --- a/drizzle-orm/src/d1/session.ts +++ b/drizzle-orm/src/d1/session.ts @@ -28,7 +28,7 @@ export class SQLiteD1Session< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'async', D1Result, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLiteD1Session'; + static override readonly [entityKind]: string = 'SQLiteD1Session'; private logger: Logger; @@ -116,7 +116,7 @@ export class D1Transaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'async', D1Result, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'D1Transaction'; + static override readonly [entityKind]: string = 'D1Transaction'; override async transaction(transaction: (tx: D1Transaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex}`; @@ -151,7 +151,7 @@ function d1ToRawMapping(results: any) { export class D1PreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: D1Response; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'D1PreparedQuery'; + static override readonly [entityKind]: string = 'D1PreparedQuery'; /** @internal */ customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown; diff --git a/drizzle-orm/src/entity.ts b/drizzle-orm/src/entity.ts index d9ab3d36a..2b6dfb4de 100644 --- a/drizzle-orm/src/entity.ts +++ b/drizzle-orm/src/entity.ts @@ -26,7 +26,7 @@ export function is>(value: any, type: T): valu ); } - let cls = value.constructor; + let cls = Object.getPrototypeOf(value).constructor; if (cls) { // Traverse the prototype chain to find the entityKind while (cls) { diff --git a/drizzle-orm/src/errors.ts b/drizzle-orm/src/errors.ts index ede6e0a59..a72615c9b 100644 --- a/drizzle-orm/src/errors.ts +++ b/drizzle-orm/src/errors.ts @@ -11,7 +11,7 @@ export class DrizzleError extends Error { } export class TransactionRollbackError extends DrizzleError { - static readonly [entityKind]: string = 'TransactionRollbackError'; + static override readonly [entityKind]: string = 'TransactionRollbackError'; constructor() { super({ message: 'Rollback' }); diff --git a/drizzle-orm/src/expo-sqlite/driver.ts b/drizzle-orm/src/expo-sqlite/driver.ts index d9cf47b01..6d9ebe375 100644 --- a/drizzle-orm/src/expo-sqlite/driver.ts +++ b/drizzle-orm/src/expo-sqlite/driver.ts @@ -15,7 +15,7 @@ import { ExpoSQLiteSession } from './session.ts'; export class ExpoSQLiteDatabase = Record> extends BaseSQLiteDatabase<'sync', SQLiteRunResult, TSchema> { - static readonly [entityKind]: string = 'ExpoSQLiteDatabase'; + static override readonly [entityKind]: string = 'ExpoSQLiteDatabase'; } export function drizzle = Record>( diff --git a/drizzle-orm/src/expo-sqlite/session.ts b/drizzle-orm/src/expo-sqlite/session.ts index d87236bc2..9fcc4b93c 100644 --- a/drizzle-orm/src/expo-sqlite/session.ts +++ b/drizzle-orm/src/expo-sqlite/session.ts @@ -26,7 +26,7 @@ export class ExpoSQLiteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'sync', SQLiteRunResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'ExpoSQLiteSession'; + static override readonly [entityKind]: string = 'ExpoSQLiteSession'; private logger: Logger; @@ -80,7 +80,7 @@ export class ExpoSQLiteTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'sync', SQLiteRunResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'ExpoSQLiteTransaction'; + static override readonly [entityKind]: string = 'ExpoSQLiteTransaction'; override transaction(transaction: (tx: ExpoSQLiteTransaction) => T): T { const savepointName = `sp${this.nestedIndex}`; @@ -100,7 +100,7 @@ export class ExpoSQLiteTransaction< export class ExpoSQLitePreparedQuery extends SQLitePreparedQuery< { type: 'sync'; run: SQLiteRunResult; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'ExpoSQLitePreparedQuery'; + static override readonly [entityKind]: string = 'ExpoSQLitePreparedQuery'; constructor( private stmt: SQLiteStatement, diff --git a/drizzle-orm/src/libsql/driver.ts b/drizzle-orm/src/libsql/driver.ts index 1e87e7555..c5e3957d2 100644 --- a/drizzle-orm/src/libsql/driver.ts +++ b/drizzle-orm/src/libsql/driver.ts @@ -1,4 +1,7 @@ -import type { Client, ResultSet } from '@libsql/client'; +import { type Client, type Config, createClient, type ResultSet } from '@libsql/client'; +import { HttpClient } from '@libsql/client/http'; +import { Sqlite3Client } from '@libsql/client/sqlite3'; +import { WsClient } from '@libsql/client/ws'; import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -11,13 +14,13 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { LibSQLSession } from './session.ts'; export class LibSQLDatabase< TSchema extends Record = Record, > extends BaseSQLiteDatabase<'async', ResultSet, TSchema> { - static readonly [entityKind]: string = 'LibSQLDatabase'; + static override readonly [entityKind]: string = 'LibSQLDatabase'; /** @internal */ declare readonly session: LibSQLSession>; @@ -29,7 +32,7 @@ export class LibSQLDatabase< } } -export function drizzle< +function construct< TSchema extends Record = Record, >(client: Client, config: DrizzleConfig = {}): LibSQLDatabase & { $client: Client; @@ -61,3 +64,63 @@ export function drizzle< return db as any; } + +export function drizzle< + TSchema extends Record = Record, + TClient extends Client = Client, +>( + ...params: IfNotImported< + Client, + [ImportTypeError<'@libsql/client'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] + > +): LibSQLDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof WsClient || params[0] instanceof HttpClient || params[0] instanceof Sqlite3Client) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'string') { + const instance = createClient({ + url: params[0], + }); + + return construct(instance, params[1]) as any; + } + + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config; client?: TClient } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection!); + + return construct(instance, drizzleConfig) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): LibSQLDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/libsql/session.ts b/drizzle-orm/src/libsql/session.ts index 640977734..617ebe342 100644 --- a/drizzle-orm/src/libsql/session.ts +++ b/drizzle-orm/src/libsql/session.ts @@ -27,7 +27,7 @@ export class LibSQLSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'async', ResultSet, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'LibSQLSession'; + static override readonly [entityKind]: string = 'LibSQLSession'; private logger: Logger; @@ -132,7 +132,7 @@ export class LibSQLTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'async', ResultSet, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'LibSQLTransaction'; + static override readonly [entityKind]: string = 'LibSQLTransaction'; override async transaction(transaction: (tx: LibSQLTransaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex}`; @@ -152,7 +152,7 @@ export class LibSQLTransaction< export class LibSQLPreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: ResultSet; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'LibSQLPreparedQuery'; + static override readonly [entityKind]: string = 'LibSQLPreparedQuery'; constructor( private client: Client, diff --git a/drizzle-orm/src/monodriver.ts b/drizzle-orm/src/monodriver.ts deleted file mode 100644 index 9af80db06..000000000 --- a/drizzle-orm/src/monodriver.ts +++ /dev/null @@ -1,659 +0,0 @@ -/* eslint-disable import/extensions */ -import type { RDSDataClient, RDSDataClientConfig as RDSConfig } from '@aws-sdk/client-rds-data'; -import type { PGlite, PGliteOptions } from '@electric-sql/pglite'; -import type { Client as LibsqlClient, Config as LibsqlConfig } from '@libsql/client'; -import type { - HTTPTransactionOptions as NeonHttpConfig, - NeonQueryFunction, - Pool as NeonServerlessPool, - PoolConfig as NeonServerlessConfig, - QueryResult, - QueryResultRow, -} from '@neondatabase/serverless'; -import type { Client as PlanetscaleClient, Config as PlanetscaleConfig } from '@planetscale/database'; -import type { Config as TiDBServerlessConfig, Connection as TiDBConnection } from '@tidbcloud/serverless'; -import type { VercelPool } from '@vercel/postgres'; -import type { Database as BetterSQLite3Database, Options as BetterSQLite3Options } from 'better-sqlite3'; -import type { Database as BunDatabase } from 'bun:sqlite'; -import type { Pool as Mysql2Pool, PoolOptions as Mysql2Config } from 'mysql2'; -import type { Pool as NodePgPool, PoolConfig as NodePgPoolConfig } from 'pg'; -import type { - Options as PostgresJSOptions, - PostgresType as PostgresJSPostgresType, - Sql as PostgresJsClient, -} from 'postgres'; -import type { AwsDataApiPgDatabase, DrizzleAwsDataApiPgConfig } from './aws-data-api/pg/index.ts'; -import type { BetterSQLite3Database as DrizzleBetterSQLite3Database } from './better-sqlite3/index.ts'; -import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; -import type { AnyD1Database, DrizzleD1Database } from './d1/index.ts'; -import type { LibSQLDatabase } from './libsql/index.ts'; -import type { MySql2Database, MySql2DrizzleConfig } from './mysql2/index.ts'; -import type { NeonHttpDatabase } from './neon-http/index.ts'; -import type { NeonDatabase } from './neon-serverless/index.ts'; -import type { NodePgDatabase } from './node-postgres/driver.ts'; -import type { PgliteDatabase } from './pglite/driver.ts'; -import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; -import type { PostgresJsDatabase } from './postgres-js/index.ts'; -import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; -import type { DrizzleConfig, IfNotImported } from './utils.ts'; -import type { VercelPgDatabase } from './vercel-postgres/index.ts'; - -type BunSqliteDatabaseOptions = { - /** - * Open the database as read-only (no write operations, no create). - * - * Equivalent to {@link constants.SQLITE_OPEN_READONLY} - */ - readonly?: boolean; - /** - * Allow creating a new database - * - * Equivalent to {@link constants.SQLITE_OPEN_CREATE} - */ - create?: boolean; - /** - * Open the database as read-write - * - * Equivalent to {@link constants.SQLITE_OPEN_READWRITE} - */ - readwrite?: boolean; -}; - -type BunSqliteDatabaseConfig = - | ({ - source?: string; - } & BunSqliteDatabaseOptions) - | string - | undefined; - -type BetterSQLite3DatabaseConfig = - | ({ - source?: - | string - | Buffer; - } & BetterSQLite3Options) - | string - | undefined; - -type MonodriverNeonHttpConfig = - | ({ - connectionString: string; - } & NeonHttpConfig) - | string; - -type AwsDataApiConnectionConfig = RDSConfig & Omit; - -type DatabaseClient = - | 'node-postgres' - | 'postgres-js' - | 'neon-websocket' - | 'neon-http' - | 'vercel-postgres' - | 'aws-data-api-pg' - | 'planetscale' - | 'mysql2' - | 'tidb-serverless' - | 'libsql' - | 'turso' - | 'd1' - | 'bun:sqlite' - | 'better-sqlite3' - | 'pglite'; - -type ClientDrizzleInstanceMap> = { - 'node-postgres': NodePgDatabase; - 'postgres-js': PostgresJsDatabase; - 'neon-websocket': NeonDatabase; - 'neon-http': NeonHttpDatabase; - 'vercel-postgres': VercelPgDatabase; - 'aws-data-api-pg': AwsDataApiPgDatabase; - planetscale: PlanetScaleDatabase; - mysql2: MySql2Database; - 'tidb-serverless': TiDBServerlessDatabase; - libsql: LibSQLDatabase; - turso: LibSQLDatabase; - d1: DrizzleD1Database; - 'bun:sqlite': BunSQLiteDatabase; - 'better-sqlite3': DrizzleBetterSQLite3Database; - pglite: PgliteDatabase; -}; - -type Primitive = string | number | boolean | undefined | null; - -type ClientInstanceMap = { - 'node-postgres': NodePgPool; - 'postgres-js': PostgresJsClient; - 'neon-websocket': NeonServerlessPool; - 'neon-http': NeonQueryFunction; - 'vercel-postgres': - & VercelPool - & ((strings: TemplateStringsArray, ...values: Primitive[]) => Promise>); - 'aws-data-api-pg': RDSDataClient; - planetscale: PlanetscaleClient; - mysql2: Mysql2Pool; - 'tidb-serverless': TiDBConnection; - libsql: LibsqlClient; - turso: LibsqlClient; - d1: AnyD1Database; - 'bun:sqlite': BunDatabase; - 'better-sqlite3': BetterSQLite3Database; - pglite: PGlite; -}; - -type ClientTypeImportErrorMap = { - 'node-postgres': 'pg`, `@types/pg'; - 'postgres-js': 'postgres'; - 'neon-websocket': '@neondatabase/serverless'; - 'neon-http': '@neondatabase/serverless'; - 'vercel-postgres': '@vercel/postgres'; - 'aws-data-api-pg': '@aws-sdk/client-rds-data'; - planetscale: '@planetscale/database'; - mysql2: 'mysql2'; - 'tidb-serverless': '@tidbcloud/serverless'; - libsql: '@libsql/client'; - turso: '@libsql/client'; - d1: '@cloudflare/workers-types` or `@miniflare/d1'; - 'bun:sqlite': 'bun-types'; - 'better-sqlite3': 'better-sqlite3'; - pglite: '@electric-sql/pglite'; -}; - -type ImportTypeError = - `Please install \`${ClientTypeImportErrorMap[TClient]}\`to allow Drizzle ORM to connect to the database`; - -type InitializerParams = { - 'node-postgres': { - connection: string | NodePgPoolConfig; - }; - 'postgres-js': { - connection: string | ({ url?: string } & PostgresJSOptions>); - }; - 'neon-websocket': { - connection: string | NeonServerlessConfig; - }; - 'neon-http': { - connection: MonodriverNeonHttpConfig; - }; - 'vercel-postgres': {}; - 'aws-data-api-pg': { - connection: AwsDataApiConnectionConfig; - }; - planetscale: { - connection: PlanetscaleConfig | string; - }; - mysql2: { - connection: Mysql2Config | string; - }; - 'tidb-serverless': { - connection: TiDBServerlessConfig | string; - }; - libsql: { - connection: LibsqlConfig | string; - }; - turso: { - connection: LibsqlConfig | string; - }; - d1: { - connection: AnyD1Database; - }; - 'bun:sqlite': { - connection?: BunSqliteDatabaseConfig; - }; - 'better-sqlite3': { - connection?: BetterSQLite3DatabaseConfig; - }; - pglite: { - connection?: (PGliteOptions & { dataDir?: string }) | string; - }; -}; - -type DetermineClient< - TClient extends DatabaseClient, - TSchema extends Record, -> = - & ClientDrizzleInstanceMap< - TSchema - >[TClient] - & { - $client: ClientInstanceMap[TClient]; - }; - -const importError = (libName: string) => { - throw new Error( - `Please install '${libName}' to allow Drizzle ORM to connect to the database`, - ); -}; - -function assertUnreachable(_: never | undefined): never { - throw new Error("Didn't expect to get here"); -} - -export async function drizzle< - TClient extends DatabaseClient, - TSchema extends Record = Record, ->( - client: TClient, - ...params: TClient extends 'bun:sqlite' | 'better-sqlite3' | 'pglite' ? ( - [] | [ - ( - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & DrizzleConfig - ), - ] | [string] - ) - : TClient extends 'vercel-postgres' ? ([] | [ - ( - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & DrizzleConfig - ), - ]) - : TClient extends - 'postgres-js' | 'tidb-serverless' | 'libsql' | 'turso' | 'planetscale' | 'neon-http' | 'node-postgres' ? ( - [ - ( - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & DrizzleConfig - ), - ] | [string] - ) - : TClient extends 'mysql2' ? ( - [ - ( - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & MySql2DrizzleConfig - ), - ] | [string] - ) - : TClient extends 'neon-websocket' ? ( - | [ - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & DrizzleConfig - & { - ws?: any; - }, - ] - | [string] - ) - : [ - ( - & IfNotImported< - ClientInstanceMap[TClient], - { connection: ImportTypeError }, - InitializerParams[TClient] - > - & DrizzleConfig - ), - ] -): Promise> { - switch (client) { - case 'node-postgres': { - const defpg = await import('pg').catch(() => importError('pg')); - const { drizzle } = await import('./node-postgres/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as - & { connection: NodePgPoolConfig | string } - & DrizzleConfig; - - const instance = typeof connection === 'string' - ? new defpg.default.Pool({ - connectionString: connection, - }) - : new defpg.default.Pool(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = typeof params[0] === 'string' - ? new defpg.default.Pool({ - connectionString: params[0], - }) - : new defpg.default.Pool(params[0]); - const db = drizzle(instance); - - return db as any; - } - case 'aws-data-api-pg': { - const { connection, ...drizzleConfig } = params[0] as { - connection: AwsDataApiConnectionConfig; - } & DrizzleConfig; - const { resourceArn, database, secretArn, ...rdsConfig } = connection; - - const { RDSDataClient } = await import('@aws-sdk/client-rds-data').catch(() => - importError('@aws-sdk/client-rds-data') - ); - const { drizzle } = await import('./aws-data-api/pg/index.ts'); - - const instance = new RDSDataClient(rdsConfig); - const db = drizzle(instance, { resourceArn, database, secretArn, ...drizzleConfig }); - - return db as any; - } - case 'better-sqlite3': { - const { default: Client } = await import('better-sqlite3').catch(() => importError('better-sqlite3')); - const { drizzle } = await import('./better-sqlite3/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: BetterSQLite3DatabaseConfig; - } & DrizzleConfig; - - if (typeof connection === 'object') { - const { source, ...options } = connection; - - const instance = new Client(source, options); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new Client(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new Client(params[0]); - const db = drizzle(instance); - - return db as any; - } - case 'bun:sqlite': { - const { Database: Client } = await import('bun:sqlite').catch(() => { - throw new Error(`Please use bun to use 'bun:sqlite' for Drizzle ORM to connect to database`); - }); - const { drizzle } = await import('./bun-sqlite/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: BunSqliteDatabaseConfig | string | undefined; - } & DrizzleConfig; - - if (typeof connection === 'object') { - const { source, ...opts } = connection; - - const options = Object.values(opts).filter((v) => v !== undefined).length ? opts : undefined; - - const instance = new Client(source, options); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new Client(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new Client(params[0]); - const db = drizzle(instance); - - return db as any; - } - case 'd1': { - const { connection, ...drizzleConfig } = params[0] as { connection: AnyD1Database } & DrizzleConfig; - - const { drizzle } = await import('./d1/index.ts'); - - const db = drizzle(connection, drizzleConfig); - - return db as any; - } - case 'libsql': - case 'turso': { - const { createClient } = await import('@libsql/client').catch(() => importError('@libsql/client')); - const { drizzle } = await import('./libsql/index.ts'); - - if (typeof params[0] === 'string') { - const instance = createClient({ - url: params[0], - }); - const db = drizzle(instance); - - return db as any; - } - - const { connection, ...drizzleConfig } = params[0] as any as { connection: LibsqlConfig } & DrizzleConfig; - - const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - case 'mysql2': { - const { createPool } = await import('mysql2/promise').catch(() => importError('mysql2')); - const { drizzle } = await import('./mysql2/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as - & { connection: Mysql2Config | string } - & MySql2DrizzleConfig; - - const instance = createPool(connection as Mysql2Config); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const connectionString = params[0]!; - const instance = createPool(connectionString); - - const db = drizzle(instance); - - return db as any; - } - case 'neon-http': { - const { neon } = await import('@neondatabase/serverless').catch(() => importError('@neondatabase/serverless')); - const { drizzle } = await import('./neon-http/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { connection: MonodriverNeonHttpConfig } & DrizzleConfig; - - if (typeof connection === 'object') { - const { connectionString, ...options } = connection; - - const instance = neon(connectionString, options); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = neon(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = neon(params[0]!); - const db = drizzle(instance); - - return db as any; - } - case 'neon-websocket': { - const { Pool, neonConfig } = await import('@neondatabase/serverless').catch(() => - importError('@neondatabase/serverless') - ); - const { drizzle } = await import('./neon-serverless/index.ts'); - if (typeof params[0] === 'string') { - const instance = new Pool({ - connectionString: params[0], - }); - - const db = drizzle(instance); - - return db as any; - } - - if (typeof params[0] === 'object') { - const { connection, ws, ...drizzleConfig } = params[0] as { - connection?: NeonServerlessConfig | string; - ws?: any; - } & DrizzleConfig; - - if (ws) { - neonConfig.webSocketConstructor = ws; - } - - const instance = typeof connection === 'string' - ? new Pool({ - connectionString: connection, - }) - : new Pool(connection); - - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new Pool(); - const db = drizzle(instance); - - return db as any; - } - case 'planetscale': { - const { Client } = await import('@planetscale/database').catch(() => importError('@planetscale/database')); - const { drizzle } = await import('./planetscale-serverless/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as - & { connection: PlanetscaleConfig | string } - & DrizzleConfig; - - const instance = typeof connection === 'string' - ? new Client({ - url: connection, - }) - : new Client( - connection, - ); - const db = drizzle(instance, drizzleConfig); - return db as any; - } - - const instance = new Client({ - url: params[0], - }); - const db = drizzle(instance); - - return db as any; - } - case 'postgres-js': { - const { default: client } = await import('postgres').catch(() => importError('postgres')); - const { drizzle } = await import('./postgres-js/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: { url?: string } & PostgresJSOptions>; - } & DrizzleConfig; - - if (typeof connection === 'object' && connection.url !== undefined) { - const { url, ...config } = connection; - - const instance = client(url, config); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = client(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = client(params[0]!); - const db = drizzle(instance); - - return db as any; - } - case 'tidb-serverless': { - const { connect } = await import('@tidbcloud/serverless').catch(() => importError('@tidbcloud/serverless')); - const { drizzle } = await import('./tidb-serverless/index.ts'); - - if (typeof params[0] === 'string') { - const instance = connect({ - url: params[0], - }); - const db = drizzle(instance); - - return db as any; - } - - const { connection, ...drizzleConfig } = params[0] as - & { connection: TiDBServerlessConfig | string } - & DrizzleConfig; - - const instance = typeof connection === 'string' - ? connect({ - url: connection, - }) - : connect(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - case 'vercel-postgres': { - const drizzleConfig = params[0] as DrizzleConfig | undefined; - const { sql } = await import('@vercel/postgres').catch(() => importError('@vercel/postgres')); - const { drizzle } = await import('./vercel-postgres/index.ts'); - - const db = drizzle(sql, drizzleConfig); - - return db as any; - } - - case 'pglite': { - const { PGlite } = await import('@electric-sql/pglite').catch(() => importError('@electric-sql/pglite')); - const { drizzle } = await import('./pglite/index.ts'); - - if (typeof params[0] === 'object') { - const { connection, ...drizzleConfig } = params[0] as { - connection: PGliteOptions & { dataDir: string }; - } & DrizzleConfig; - - if (typeof connection === 'object') { - const { dataDir, ...options } = connection; - - const instance = new PGlite(dataDir, options); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new PGlite(connection); - const db = drizzle(instance, drizzleConfig); - - return db as any; - } - - const instance = new PGlite(params[0]); - const db = drizzle(instance); - - return db as any; - } - } - - assertUnreachable(client); -} diff --git a/drizzle-orm/src/monomigrator.ts b/drizzle-orm/src/monomigrator.ts deleted file mode 100644 index 9f4a748e0..000000000 --- a/drizzle-orm/src/monomigrator.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* eslint-disable import/extensions */ -import type { AwsDataApiPgDatabase } from './aws-data-api/pg/index.ts'; -import type { BetterSQLite3Database } from './better-sqlite3/index.ts'; -import type { BunSQLiteDatabase } from './bun-sqlite/index.ts'; -import type { DrizzleD1Database } from './d1/index.ts'; -import { entityKind } from './entity.ts'; -import type { LibSQLDatabase } from './libsql/index.ts'; -import type { MigrationConfig } from './migrator.ts'; -import type { MySql2Database } from './mysql2/index.ts'; -import type { NeonHttpDatabase } from './neon-http/index.ts'; -import type { NeonDatabase } from './neon-serverless/index.ts'; -import type { NodePgDatabase } from './node-postgres/index.ts'; -import type { PgliteDatabase } from './pglite/driver.ts'; -import type { PlanetScaleDatabase } from './planetscale-serverless/index.ts'; -import type { PostgresJsDatabase } from './postgres-js/index.ts'; -import type { TiDBServerlessDatabase } from './tidb-serverless/index.ts'; -import type { VercelPgDatabase } from './vercel-postgres/index.ts'; - -export async function migrate( - db: - | AwsDataApiPgDatabase - | BetterSQLite3Database - | BunSQLiteDatabase - | DrizzleD1Database - | LibSQLDatabase - | MySql2Database - | NeonHttpDatabase - | NeonDatabase - | NodePgDatabase - | PlanetScaleDatabase - | PostgresJsDatabase - | VercelPgDatabase - | TiDBServerlessDatabase - | PgliteDatabase, - config: MigrationConfig, -) { - switch (( db).constructor[entityKind]) { - case 'AwsDataApiPgDatabase': { - const { migrate } = await import('./aws-data-api/pg/migrator.ts'); - - return migrate(db as AwsDataApiPgDatabase, config as MigrationConfig); - } - case 'BetterSQLite3Database': { - const { migrate } = await import('./better-sqlite3/migrator.ts'); - - return migrate(db as BetterSQLite3Database, config as MigrationConfig); - } - case 'BunSQLiteDatabase': { - const { migrate } = await import('./bun-sqlite/migrator.ts'); - - return migrate(db as BunSQLiteDatabase, config as MigrationConfig); - } - case 'D1Database': { - const { migrate } = await import('./d1/migrator.ts'); - - return migrate(db as DrizzleD1Database, config as MigrationConfig); - } - case 'LibSQLDatabase': { - const { migrate } = await import('./libsql/migrator.ts'); - - return migrate(db as LibSQLDatabase, config as MigrationConfig); - } - case 'MySql2Database': { - const { migrate } = await import('./mysql2/migrator.ts'); - - return migrate(db as MySql2Database, config as MigrationConfig); - } - case 'NeonHttpDatabase': { - const { migrate } = await import('./neon-http/migrator.ts'); - - return migrate(db as NeonHttpDatabase, config as MigrationConfig); - } - case 'NeonServerlessDatabase': { - const { migrate } = await import('./neon-serverless/migrator.ts'); - - return migrate(db as NeonDatabase, config as MigrationConfig); - } - case 'NodePgDatabase': { - const { migrate } = await import('./node-postgres/migrator.ts'); - - return migrate(db as NodePgDatabase, config as MigrationConfig); - } - case 'PlanetScaleDatabase': { - const { migrate } = await import('./planetscale-serverless/migrator.ts'); - - return migrate(db as PlanetScaleDatabase, config as MigrationConfig); - } - case 'PostgresJsDatabase': { - const { migrate } = await import('./postgres-js/migrator.ts'); - - return migrate(db as PostgresJsDatabase, config as MigrationConfig); - } - case 'TiDBServerlessDatabase': { - const { migrate } = await import('./tidb-serverless/migrator.ts'); - - return migrate(db as TiDBServerlessDatabase, config as MigrationConfig); - } - case 'VercelPgDatabase': { - const { migrate } = await import('./vercel-postgres/migrator.ts'); - - return migrate(db as VercelPgDatabase, config as MigrationConfig); - } - case 'PgliteDatabase': { - const { migrate } = await import('./pglite/migrator.ts'); - - return migrate(db as PgliteDatabase, config as MigrationConfig); - } - } -} diff --git a/drizzle-orm/src/mysql-core/columns/bigint.ts b/drizzle-orm/src/mysql-core/columns/bigint.ts index 5882b1025..7411c07ce 100644 --- a/drizzle-orm/src/mysql-core/columns/bigint.ts +++ b/drizzle-orm/src/mysql-core/columns/bigint.ts @@ -18,7 +18,7 @@ export type MySqlBigInt53BuilderInitial = MySqlBigInt53Bui export class MySqlBigInt53Builder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt53Builder'; + static override readonly [entityKind]: string = 'MySqlBigInt53Builder'; constructor(name: T['name'], unsigned: boolean = false) { super(name, 'number', 'MySqlBigInt53'); @@ -39,7 +39,7 @@ export class MySqlBigInt53Builder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt53'; + static override readonly [entityKind]: string = 'MySqlBigInt53'; getSQLType(): string { return `bigint${this.config.unsigned ? ' unsigned' : ''}`; @@ -66,7 +66,7 @@ export type MySqlBigInt64BuilderInitial = MySqlBigInt64Bui export class MySqlBigInt64Builder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt64Builder'; + static override readonly [entityKind]: string = 'MySqlBigInt64Builder'; constructor(name: T['name'], unsigned: boolean = false) { super(name, 'bigint', 'MySqlBigInt64'); @@ -87,7 +87,7 @@ export class MySqlBigInt64Builder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlBigInt64'; + static override readonly [entityKind]: string = 'MySqlBigInt64'; getSQLType(): string { return `bigint${this.config.unsigned ? ' unsigned' : ''}`; diff --git a/drizzle-orm/src/mysql-core/columns/binary.ts b/drizzle-orm/src/mysql-core/columns/binary.ts index 7297d7b0a..7031b565c 100644 --- a/drizzle-orm/src/mysql-core/columns/binary.ts +++ b/drizzle-orm/src/mysql-core/columns/binary.ts @@ -19,7 +19,7 @@ export class MySqlBinaryBuilder { - static readonly [entityKind]: string = 'MySqlBinaryBuilder'; + static override readonly [entityKind]: string = 'MySqlBinaryBuilder'; constructor(name: T['name'], length: number | undefined) { super(name, 'string', 'MySqlBinary'); @@ -38,7 +38,7 @@ export class MySqlBinary> ex T, MySqlBinaryConfig > { - static readonly [entityKind]: string = 'MySqlBinary'; + static override readonly [entityKind]: string = 'MySqlBinary'; length: number | undefined = this.config.length; diff --git a/drizzle-orm/src/mysql-core/columns/boolean.ts b/drizzle-orm/src/mysql-core/columns/boolean.ts index d1df78570..9e786b6f9 100644 --- a/drizzle-orm/src/mysql-core/columns/boolean.ts +++ b/drizzle-orm/src/mysql-core/columns/boolean.ts @@ -17,7 +17,7 @@ export type MySqlBooleanBuilderInitial = MySqlBooleanBuild export class MySqlBooleanBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlBooleanBuilder'; + static override readonly [entityKind]: string = 'MySqlBooleanBuilder'; constructor(name: T['name']) { super(name, 'boolean', 'MySqlBoolean'); @@ -35,7 +35,7 @@ export class MySqlBooleanBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlBoolean'; + static override readonly [entityKind]: string = 'MySqlBoolean'; getSQLType(): string { return 'boolean'; diff --git a/drizzle-orm/src/mysql-core/columns/char.ts b/drizzle-orm/src/mysql-core/columns/char.ts index 019c035ba..efcb7e65a 100644 --- a/drizzle-orm/src/mysql-core/columns/char.ts +++ b/drizzle-orm/src/mysql-core/columns/char.ts @@ -19,7 +19,7 @@ export class MySqlCharBuilder > { - static readonly [entityKind]: string = 'MySqlCharBuilder'; + static override readonly [entityKind]: string = 'MySqlCharBuilder'; constructor(name: T['name'], config: MySqlCharConfig) { super(name, 'string', 'MySqlChar'); @@ -41,7 +41,7 @@ export class MySqlCharBuilder> extends MySqlColumn> { - static readonly [entityKind]: string = 'MySqlChar'; + static override readonly [entityKind]: string = 'MySqlChar'; readonly length: number | undefined = this.config.length; override readonly enumValues = this.config.enum; diff --git a/drizzle-orm/src/mysql-core/columns/common.ts b/drizzle-orm/src/mysql-core/columns/common.ts index a0a192477..9babc31da 100644 --- a/drizzle-orm/src/mysql-core/columns/common.ts +++ b/drizzle-orm/src/mysql-core/columns/common.ts @@ -47,7 +47,7 @@ export abstract class MySqlColumnBuilder< > extends ColumnBuilder implements MySqlColumnBuilderBase { - static readonly [entityKind]: string = 'MySqlColumnBuilder'; + static override readonly [entityKind]: string = 'MySqlColumnBuilder'; private foreignKeyConfigs: ReferenceConfig[] = []; @@ -101,7 +101,7 @@ export abstract class MySqlColumn< T extends ColumnBaseConfig = ColumnBaseConfig, TRuntimeConfig extends object = object, > extends Column { - static readonly [entityKind]: string = 'MySqlColumn'; + static override readonly [entityKind]: string = 'MySqlColumn'; constructor( override readonly table: MySqlTable, @@ -127,7 +127,7 @@ export abstract class MySqlColumnBuilderWithAutoIncrement< TRuntimeConfig extends object = object, TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, > extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlColumnBuilderWithAutoIncrement'; + static override readonly [entityKind]: string = 'MySqlColumnBuilderWithAutoIncrement'; constructor(name: NonNullable, dataType: T['dataType'], columnType: T['columnType']) { super(name, dataType, columnType); @@ -145,7 +145,7 @@ export abstract class MySqlColumnWithAutoIncrement< T extends ColumnBaseConfig = ColumnBaseConfig, TRuntimeConfig extends object = object, > extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlColumnWithAutoIncrement'; + static override readonly [entityKind]: string = 'MySqlColumnWithAutoIncrement'; readonly autoIncrement: boolean = this.config.autoIncrement; } diff --git a/drizzle-orm/src/mysql-core/columns/custom.ts b/drizzle-orm/src/mysql-core/columns/custom.ts index 35ca19d3d..711b27813 100644 --- a/drizzle-orm/src/mysql-core/columns/custom.ts +++ b/drizzle-orm/src/mysql-core/columns/custom.ts @@ -35,7 +35,7 @@ export class MySqlCustomColumnBuilder { - static readonly [entityKind]: string = 'MySqlCustomColumnBuilder'; + static override readonly [entityKind]: string = 'MySqlCustomColumnBuilder'; constructor( name: T['name'], @@ -59,7 +59,7 @@ export class MySqlCustomColumnBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlCustomColumn'; + static override readonly [entityKind]: string = 'MySqlCustomColumn'; private sqlName: string; private mapTo?: (value: T['data']) => T['driverParam']; diff --git a/drizzle-orm/src/mysql-core/columns/date.common.ts b/drizzle-orm/src/mysql-core/columns/date.common.ts index 3fd8aa612..75faad5b8 100644 --- a/drizzle-orm/src/mysql-core/columns/date.common.ts +++ b/drizzle-orm/src/mysql-core/columns/date.common.ts @@ -18,7 +18,7 @@ export abstract class MySqlDateColumnBaseBuilder< TRuntimeConfig extends object = object, TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, > extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateColumnBuilder'; + static override readonly [entityKind]: string = 'MySqlDateColumnBuilder'; defaultNow() { return this.default(sql`(now())`); @@ -36,7 +36,7 @@ export abstract class MySqlDateBaseColumn< T extends ColumnBaseConfig, TRuntimeConfig extends object = object, > extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateColumn'; + static override readonly [entityKind]: string = 'MySqlDateColumn'; readonly hasOnUpdateNow: boolean = this.config.hasOnUpdateNow; } diff --git a/drizzle-orm/src/mysql-core/columns/date.ts b/drizzle-orm/src/mysql-core/columns/date.ts index 17ad8d8be..318fac65d 100644 --- a/drizzle-orm/src/mysql-core/columns/date.ts +++ b/drizzle-orm/src/mysql-core/columns/date.ts @@ -16,7 +16,7 @@ export type MySqlDateBuilderInitial = MySqlDateBuilder<{ }>; export class MySqlDateBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateBuilder'; + static override readonly [entityKind]: string = 'MySqlDateBuilder'; constructor(name: T['name']) { super(name, 'date', 'MySqlDate'); @@ -31,7 +31,7 @@ export class MySqlDateBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDate'; + static override readonly [entityKind]: string = 'MySqlDate'; constructor( table: AnyMySqlTable<{ name: T['tableName'] }>, @@ -62,7 +62,7 @@ export type MySqlDateStringBuilderInitial = MySqlDateStrin export class MySqlDateStringBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateStringBuilder'; + static override readonly [entityKind]: string = 'MySqlDateStringBuilder'; constructor(name: T['name']) { super(name, 'string', 'MySqlDateString'); @@ -80,7 +80,7 @@ export class MySqlDateStringBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateString'; + static override readonly [entityKind]: string = 'MySqlDateString'; constructor( table: AnyMySqlTable<{ name: T['tableName'] }>, diff --git a/drizzle-orm/src/mysql-core/columns/datetime.ts b/drizzle-orm/src/mysql-core/columns/datetime.ts index 39b0bae32..61b062e8f 100644 --- a/drizzle-orm/src/mysql-core/columns/datetime.ts +++ b/drizzle-orm/src/mysql-core/columns/datetime.ts @@ -18,7 +18,7 @@ export type MySqlDateTimeBuilderInitial = MySqlDateTimeBui export class MySqlDateTimeBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateTimeBuilder'; + static override readonly [entityKind]: string = 'MySqlDateTimeBuilder'; constructor(name: T['name'], config: MySqlDatetimeConfig | undefined) { super(name, 'date', 'MySqlDateTime'); @@ -37,7 +37,7 @@ export class MySqlDateTimeBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateTime'; + static override readonly [entityKind]: string = 'MySqlDateTime'; readonly fsp: number | undefined; @@ -76,7 +76,7 @@ export type MySqlDateTimeStringBuilderInitial = MySqlDateT export class MySqlDateTimeStringBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlDateTimeStringBuilder'; + static override readonly [entityKind]: string = 'MySqlDateTimeStringBuilder'; constructor(name: T['name'], config: MySqlDatetimeConfig | undefined) { super(name, 'string', 'MySqlDateTimeString'); @@ -95,7 +95,7 @@ export class MySqlDateTimeStringBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlDateTimeString'; + static override readonly [entityKind]: string = 'MySqlDateTimeString'; readonly fsp: number | undefined; diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index 3b01923e4..1e5f78679 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -18,7 +18,7 @@ export type MySqlDecimalBuilderInitial = MySqlDecimalBuild export class MySqlDecimalBuilder< T extends ColumnBuilderBaseConfig<'string', 'MySqlDecimal'>, > extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDecimalBuilder'; + static override readonly [entityKind]: string = 'MySqlDecimalBuilder'; constructor(name: T['name'], precision?: number, scale?: number) { super(name, 'string', 'MySqlDecimal'); @@ -40,7 +40,7 @@ export class MySqlDecimalBuilder< export class MySqlDecimal> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDecimal'; + static override readonly [entityKind]: string = 'MySqlDecimal'; readonly precision: number | undefined = this.config.precision; readonly scale: number | undefined = this.config.scale; diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index 0324025b8..c9f95fd04 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -18,7 +18,7 @@ export type MySqlDoubleBuilderInitial = MySqlDoubleBuilder export class MySqlDoubleBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDoubleBuilder'; + static override readonly [entityKind]: string = 'MySqlDoubleBuilder'; constructor(name: T['name'], config: MySqlDoubleConfig | undefined) { super(name, 'number', 'MySqlDouble'); @@ -37,7 +37,7 @@ export class MySqlDoubleBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlDouble'; + static override readonly [entityKind]: string = 'MySqlDouble'; precision: number | undefined = this.config.precision; scale: number | undefined = this.config.scale; diff --git a/drizzle-orm/src/mysql-core/columns/enum.ts b/drizzle-orm/src/mysql-core/columns/enum.ts index de1d41cdd..6a586ca7c 100644 --- a/drizzle-orm/src/mysql-core/columns/enum.ts +++ b/drizzle-orm/src/mysql-core/columns/enum.ts @@ -19,7 +19,7 @@ export type MySqlEnumColumnBuilderInitial> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlEnumColumnBuilder'; + static override readonly [entityKind]: string = 'MySqlEnumColumnBuilder'; constructor(name: T['name'], values: T['enumValues']) { super(name, 'string', 'MySqlEnumColumn'); @@ -40,7 +40,7 @@ export class MySqlEnumColumnBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlEnumColumn'; + static override readonly [entityKind]: string = 'MySqlEnumColumn'; override readonly enumValues = this.config.enumValues; diff --git a/drizzle-orm/src/mysql-core/columns/float.ts b/drizzle-orm/src/mysql-core/columns/float.ts index 88b989077..d7c3e586b 100644 --- a/drizzle-orm/src/mysql-core/columns/float.ts +++ b/drizzle-orm/src/mysql-core/columns/float.ts @@ -17,7 +17,7 @@ export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ export class MySqlFloatBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlFloatBuilder'; + static override readonly [entityKind]: string = 'MySqlFloatBuilder'; constructor(name: T['name']) { super(name, 'number', 'MySqlFloat'); @@ -32,7 +32,7 @@ export class MySqlFloatBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlFloat'; + static override readonly [entityKind]: string = 'MySqlFloat'; getSQLType(): string { return 'float'; diff --git a/drizzle-orm/src/mysql-core/columns/int.ts b/drizzle-orm/src/mysql-core/columns/int.ts index 4902bc593..aca0ea61e 100644 --- a/drizzle-orm/src/mysql-core/columns/int.ts +++ b/drizzle-orm/src/mysql-core/columns/int.ts @@ -18,7 +18,7 @@ export type MySqlIntBuilderInitial = MySqlIntBuilder<{ export class MySqlIntBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlIntBuilder'; + static override readonly [entityKind]: string = 'MySqlIntBuilder'; constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlInt'); @@ -36,7 +36,7 @@ export class MySqlIntBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlInt'; + static override readonly [entityKind]: string = 'MySqlInt'; getSQLType(): string { return `int${this.config.unsigned ? ' unsigned' : ''}`; diff --git a/drizzle-orm/src/mysql-core/columns/json.ts b/drizzle-orm/src/mysql-core/columns/json.ts index d57cf963c..ecb73ed82 100644 --- a/drizzle-orm/src/mysql-core/columns/json.ts +++ b/drizzle-orm/src/mysql-core/columns/json.ts @@ -15,7 +15,7 @@ export type MySqlJsonBuilderInitial = MySqlJsonBuilder<{ }>; export class MySqlJsonBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlJsonBuilder'; + static override readonly [entityKind]: string = 'MySqlJsonBuilder'; constructor(name: T['name']) { super(name, 'json', 'MySqlJson'); @@ -30,7 +30,7 @@ export class MySqlJsonBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlJson'; + static override readonly [entityKind]: string = 'MySqlJson'; getSQLType(): string { return 'json'; diff --git a/drizzle-orm/src/mysql-core/columns/mediumint.ts b/drizzle-orm/src/mysql-core/columns/mediumint.ts index 237090179..764969d31 100644 --- a/drizzle-orm/src/mysql-core/columns/mediumint.ts +++ b/drizzle-orm/src/mysql-core/columns/mediumint.ts @@ -19,7 +19,7 @@ export type MySqlMediumIntBuilderInitial = MySqlMediumIntB export class MySqlMediumIntBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlMediumIntBuilder'; + static override readonly [entityKind]: string = 'MySqlMediumIntBuilder'; constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlMediumInt'); @@ -40,7 +40,7 @@ export class MySqlMediumIntBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlMediumInt'; + static override readonly [entityKind]: string = 'MySqlMediumInt'; getSQLType(): string { return `mediumint${this.config.unsigned ? ' unsigned' : ''}`; diff --git a/drizzle-orm/src/mysql-core/columns/real.ts b/drizzle-orm/src/mysql-core/columns/real.ts index 2a921f1aa..8b9eca794 100644 --- a/drizzle-orm/src/mysql-core/columns/real.ts +++ b/drizzle-orm/src/mysql-core/columns/real.ts @@ -21,7 +21,7 @@ export class MySqlRealBuilder { - static readonly [entityKind]: string = 'MySqlRealBuilder'; + static override readonly [entityKind]: string = 'MySqlRealBuilder'; constructor(name: T['name'], config: MySqlRealConfig | undefined) { super(name, 'number', 'MySqlReal'); @@ -41,7 +41,7 @@ export class MySqlReal> extend T, MySqlRealConfig > { - static readonly [entityKind]: string = 'MySqlReal'; + static override readonly [entityKind]: string = 'MySqlReal'; precision: number | undefined = this.config.precision; scale: number | undefined = this.config.scale; diff --git a/drizzle-orm/src/mysql-core/columns/serial.ts b/drizzle-orm/src/mysql-core/columns/serial.ts index 43af900a1..88485d6b2 100644 --- a/drizzle-orm/src/mysql-core/columns/serial.ts +++ b/drizzle-orm/src/mysql-core/columns/serial.ts @@ -33,7 +33,7 @@ export type MySqlSerialBuilderInitial = IsAutoincrement< export class MySqlSerialBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSerialBuilder'; + static override readonly [entityKind]: string = 'MySqlSerialBuilder'; constructor(name: T['name']) { super(name, 'number', 'MySqlSerial'); @@ -52,7 +52,7 @@ export class MySqlSerialBuilder, > extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSerial'; + static override readonly [entityKind]: string = 'MySqlSerial'; getSQLType(): string { return 'serial'; diff --git a/drizzle-orm/src/mysql-core/columns/smallint.ts b/drizzle-orm/src/mysql-core/columns/smallint.ts index e6801e214..482ff89ea 100644 --- a/drizzle-orm/src/mysql-core/columns/smallint.ts +++ b/drizzle-orm/src/mysql-core/columns/smallint.ts @@ -19,7 +19,7 @@ export type MySqlSmallIntBuilderInitial = MySqlSmallIntBui export class MySqlSmallIntBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSmallIntBuilder'; + static override readonly [entityKind]: string = 'MySqlSmallIntBuilder'; constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlSmallInt'); @@ -40,7 +40,7 @@ export class MySqlSmallIntBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlSmallInt'; + static override readonly [entityKind]: string = 'MySqlSmallInt'; getSQLType(): string { return `smallint${this.config.unsigned ? ' unsigned' : ''}`; diff --git a/drizzle-orm/src/mysql-core/columns/text.ts b/drizzle-orm/src/mysql-core/columns/text.ts index c90362dc5..18434a532 100644 --- a/drizzle-orm/src/mysql-core/columns/text.ts +++ b/drizzle-orm/src/mysql-core/columns/text.ts @@ -21,7 +21,7 @@ export class MySqlTextBuilder { - static readonly [entityKind]: string = 'MySqlTextBuilder'; + static override readonly [entityKind]: string = 'MySqlTextBuilder'; constructor(name: T['name'], textType: MySqlTextColumnType, config: MySqlTextConfig) { super(name, 'string', 'MySqlText'); @@ -40,7 +40,7 @@ export class MySqlTextBuilder> extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlText'; + static override readonly [entityKind]: string = 'MySqlText'; private textType: MySqlTextColumnType = this.config.textType; diff --git a/drizzle-orm/src/mysql-core/columns/time.ts b/drizzle-orm/src/mysql-core/columns/time.ts index e862d9fa3..408453947 100644 --- a/drizzle-orm/src/mysql-core/columns/time.ts +++ b/drizzle-orm/src/mysql-core/columns/time.ts @@ -19,7 +19,7 @@ export class MySqlTimeBuilder { - static readonly [entityKind]: string = 'MySqlTimeBuilder'; + static override readonly [entityKind]: string = 'MySqlTimeBuilder'; constructor( name: T['name'], @@ -40,7 +40,7 @@ export class MySqlTimeBuilder, > extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlTime'; + static override readonly [entityKind]: string = 'MySqlTime'; readonly fsp: number | undefined = this.config.fsp; diff --git a/drizzle-orm/src/mysql-core/columns/timestamp.ts b/drizzle-orm/src/mysql-core/columns/timestamp.ts index 07649ba94..892f8e603 100644 --- a/drizzle-orm/src/mysql-core/columns/timestamp.ts +++ b/drizzle-orm/src/mysql-core/columns/timestamp.ts @@ -18,7 +18,7 @@ export type MySqlTimestampBuilderInitial = MySqlTimestampB export class MySqlTimestampBuilder> extends MySqlDateColumnBaseBuilder { - static readonly [entityKind]: string = 'MySqlTimestampBuilder'; + static override readonly [entityKind]: string = 'MySqlTimestampBuilder'; constructor(name: T['name'], config: MySqlTimestampConfig | undefined) { super(name, 'date', 'MySqlTimestamp'); @@ -39,7 +39,7 @@ export class MySqlTimestampBuilder> extends MySqlDateBaseColumn { - static readonly [entityKind]: string = 'MySqlTimestamp'; + static override readonly [entityKind]: string = 'MySqlTimestamp'; readonly fsp: number | undefined = this.config.fsp; @@ -70,7 +70,7 @@ export type MySqlTimestampStringBuilderInitial = MySqlTime export class MySqlTimestampStringBuilder> extends MySqlDateColumnBaseBuilder { - static readonly [entityKind]: string = 'MySqlTimestampStringBuilder'; + static override readonly [entityKind]: string = 'MySqlTimestampStringBuilder'; constructor(name: T['name'], config: MySqlTimestampConfig | undefined) { super(name, 'string', 'MySqlTimestampString'); @@ -91,7 +91,7 @@ export class MySqlTimestampStringBuilder> extends MySqlDateBaseColumn { - static readonly [entityKind]: string = 'MySqlTimestampString'; + static override readonly [entityKind]: string = 'MySqlTimestampString'; readonly fsp: number | undefined = this.config.fsp; diff --git a/drizzle-orm/src/mysql-core/columns/tinyint.ts b/drizzle-orm/src/mysql-core/columns/tinyint.ts index a9d7e967b..ee4ccdaa7 100644 --- a/drizzle-orm/src/mysql-core/columns/tinyint.ts +++ b/drizzle-orm/src/mysql-core/columns/tinyint.ts @@ -19,7 +19,7 @@ export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuild export class MySqlTinyIntBuilder> extends MySqlColumnBuilderWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlTinyIntBuilder'; + static override readonly [entityKind]: string = 'MySqlTinyIntBuilder'; constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlTinyInt'); @@ -40,7 +40,7 @@ export class MySqlTinyIntBuilder> extends MySqlColumnWithAutoIncrement { - static readonly [entityKind]: string = 'MySqlTinyInt'; + static override readonly [entityKind]: string = 'MySqlTinyInt'; getSQLType(): string { return `tinyint${this.config.unsigned ? ' unsigned' : ''}`; diff --git a/drizzle-orm/src/mysql-core/columns/varbinary.ts b/drizzle-orm/src/mysql-core/columns/varbinary.ts index ed6b90b7a..bc0dde635 100644 --- a/drizzle-orm/src/mysql-core/columns/varbinary.ts +++ b/drizzle-orm/src/mysql-core/columns/varbinary.ts @@ -18,7 +18,7 @@ export type MySqlVarBinaryBuilderInitial = MySqlVarBinaryB export class MySqlVarBinaryBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlVarBinaryBuilder'; + static override readonly [entityKind]: string = 'MySqlVarBinaryBuilder'; /** @internal */ constructor(name: T['name'], config: MySqlVarbinaryOptions) { @@ -40,7 +40,7 @@ export class MySqlVarBinaryBuilder, > extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlVarBinary'; + static override readonly [entityKind]: string = 'MySqlVarBinary'; length: number | undefined = this.config.length; diff --git a/drizzle-orm/src/mysql-core/columns/varchar.ts b/drizzle-orm/src/mysql-core/columns/varchar.ts index b05cf7523..32cfda7e9 100644 --- a/drizzle-orm/src/mysql-core/columns/varchar.ts +++ b/drizzle-orm/src/mysql-core/columns/varchar.ts @@ -20,7 +20,7 @@ export type MySqlVarCharBuilderInitial> extends MySqlColumnBuilder> { - static readonly [entityKind]: string = 'MySqlVarCharBuilder'; + static override readonly [entityKind]: string = 'MySqlVarCharBuilder'; /** @internal */ constructor(name: T['name'], config: MySqlVarCharConfig) { @@ -43,7 +43,7 @@ export class MySqlVarCharBuilder> extends MySqlColumn> { - static readonly [entityKind]: string = 'MySqlVarChar'; + static override readonly [entityKind]: string = 'MySqlVarChar'; readonly length: number | undefined = this.config.length; diff --git a/drizzle-orm/src/mysql-core/columns/year.ts b/drizzle-orm/src/mysql-core/columns/year.ts index 27a81f887..8a7a44410 100644 --- a/drizzle-orm/src/mysql-core/columns/year.ts +++ b/drizzle-orm/src/mysql-core/columns/year.ts @@ -15,7 +15,7 @@ export type MySqlYearBuilderInitial = MySqlYearBuilder<{ }>; export class MySqlYearBuilder> extends MySqlColumnBuilder { - static readonly [entityKind]: string = 'MySqlYearBuilder'; + static override readonly [entityKind]: string = 'MySqlYearBuilder'; constructor(name: T['name']) { super(name, 'number', 'MySqlYear'); @@ -32,7 +32,7 @@ export class MySqlYearBuilder, > extends MySqlColumn { - static readonly [entityKind]: string = 'MySqlYear'; + static override readonly [entityKind]: string = 'MySqlYear'; getSQLType(): string { return `year`; diff --git a/drizzle-orm/src/mysql-core/dialect.ts b/drizzle-orm/src/mysql-core/dialect.ts index ee28af04d..af4f11905 100644 --- a/drizzle-orm/src/mysql-core/dialect.ts +++ b/drizzle-orm/src/mysql-core/dialect.ts @@ -18,7 +18,7 @@ import { type TablesRelationalConfig, } from '~/relations.ts'; import { Param, SQL, sql, View } from '~/sql/sql.ts'; -import type { Name, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; +import type { Name, Placeholder, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { getTableName, getTableUniqueName, Table } from '~/table.ts'; import { type Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; @@ -112,7 +112,7 @@ export class MySqlDialect { return sql.join(withSqlChunks); } - buildDeleteQuery({ table, where, returning, withList }: MySqlDeleteConfig): SQL { + buildDeleteQuery({ table, where, returning, withList, limit, orderBy }: MySqlDeleteConfig): SQL { const withSql = this.buildWithCTE(withList); const returningSql = returning @@ -121,7 +121,11 @@ export class MySqlDialect { const whereSql = where ? sql` where ${where}` : undefined; - return sql`${withSql}delete from ${table}${whereSql}${returningSql}`; + const orderBySql = this.buildOrderBy(orderBy); + + const limitSql = this.buildLimit(limit); + + return sql`${withSql}delete from ${table}${whereSql}${orderBySql}${limitSql}${returningSql}`; } buildUpdateSet(table: MySqlTable, set: UpdateSet): SQL { @@ -145,7 +149,7 @@ export class MySqlDialect { })); } - buildUpdateQuery({ table, set, where, returning, withList }: MySqlUpdateConfig): SQL { + buildUpdateQuery({ table, set, where, returning, withList, limit, orderBy }: MySqlUpdateConfig): SQL { const withSql = this.buildWithCTE(withList); const setSql = this.buildUpdateSet(table, set); @@ -156,7 +160,11 @@ export class MySqlDialect { const whereSql = where ? sql` where ${where}` : undefined; - return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}`; + const orderBySql = this.buildOrderBy(orderBy); + + const limitSql = this.buildLimit(limit); + + return sql`${withSql}update ${table} set ${setSql}${whereSql}${orderBySql}${limitSql}${returningSql}`; } /** @@ -221,6 +229,16 @@ export class MySqlDialect { return sql.join(chunks); } + private buildLimit(limit: number | Placeholder | undefined): SQL | undefined { + return typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined; + } + + private buildOrderBy(orderBy: (MySqlColumn | SQL | SQL.Aliased)[] | undefined): SQL | undefined { + return orderBy && orderBy.length > 0 ? sql` order by ${sql.join(orderBy, sql`, `)}` : undefined; + } + buildSelectQuery( { withList, @@ -328,19 +346,11 @@ export class MySqlDialect { const havingSql = having ? sql` having ${having}` : undefined; - let orderBySql; - if (orderBy && orderBy.length > 0) { - orderBySql = sql` order by ${sql.join(orderBy, sql`, `)}`; - } + const orderBySql = this.buildOrderBy(orderBy); - let groupBySql; - if (groupBy && groupBy.length > 0) { - groupBySql = sql` group by ${sql.join(groupBy, sql`, `)}`; - } + const groupBySql = groupBy && groupBy.length > 0 ? sql` group by ${sql.join(groupBy, sql`, `)}` : undefined; - const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) - ? sql` limit ${limit}` - : undefined; + const limitSql = this.buildLimit(limit); const offsetSql = offset ? sql` offset ${offset}` : undefined; diff --git a/drizzle-orm/src/mysql-core/query-builders/count.ts b/drizzle-orm/src/mysql-core/query-builders/count.ts index e61b27011..9a0241c70 100644 --- a/drizzle-orm/src/mysql-core/query-builders/count.ts +++ b/drizzle-orm/src/mysql-core/query-builders/count.ts @@ -9,7 +9,7 @@ export class MySqlCountBuilder< > extends SQL implements Promise, SQLWrapper { private sql: SQL; - static readonly [entityKind] = 'MySqlCountBuilder'; + static override readonly [entityKind] = 'MySqlCountBuilder'; [Symbol.toStringTag] = 'MySqlCountBuilder'; private session: TSession; diff --git a/drizzle-orm/src/mysql-core/query-builders/delete.ts b/drizzle-orm/src/mysql-core/query-builders/delete.ts index e9a48da8e..22a3e1be3 100644 --- a/drizzle-orm/src/mysql-core/query-builders/delete.ts +++ b/drizzle-orm/src/mysql-core/query-builders/delete.ts @@ -11,8 +11,12 @@ import type { } from '~/mysql-core/session.ts'; import type { MySqlTable } from '~/mysql-core/table.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; +import type { ValueOrArray } from '~/utils.ts'; +import type { MySqlColumn } from '../columns/common.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; export type MySqlDeleteWithout< @@ -39,6 +43,8 @@ export type MySqlDelete< export interface MySqlDeleteConfig { where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (MySqlColumn | SQL | SQL.Aliased)[]; table: MySqlTable; returning?: SelectedFieldsOrdered; withList?: Subquery[]; @@ -86,7 +92,7 @@ export class MySqlDeleteBase< // eslint-disable-next-line @typescript-eslint/no-unused-vars TExcludedMethods extends string = never, > extends QueryPromise> implements SQLWrapper { - static readonly [entityKind]: string = 'MySqlDelete'; + static override readonly [entityKind]: string = 'MySqlDelete'; private config: MySqlDeleteConfig; @@ -134,6 +140,37 @@ export class MySqlDeleteBase< return this as any; } + orderBy( + builder: (deleteTable: TTable) => ValueOrArray, + ): MySqlDeleteWithout; + orderBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): MySqlDeleteWithout; + orderBy( + ...columns: + | [(deleteTable: TTable) => ValueOrArray] + | (MySqlColumn | SQL | SQL.Aliased)[] + ): MySqlDeleteWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (MySqlColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): MySqlDeleteWithout { + this.config.limit = limit; + return this as any; + } + /** @internal */ getSQL(): SQL { return this.dialect.buildDeleteQuery(this.config); diff --git a/drizzle-orm/src/mysql-core/query-builders/insert.ts b/drizzle-orm/src/mysql-core/query-builders/insert.ts index 97e61de74..fe9f7d7ba 100644 --- a/drizzle-orm/src/mysql-core/query-builders/insert.ts +++ b/drizzle-orm/src/mysql-core/query-builders/insert.ts @@ -190,7 +190,7 @@ export class MySqlInsertBase< RunnableQuery : TReturning[], 'mysql'>, SQLWrapper { - static readonly [entityKind]: string = 'MySqlInsert'; + static override readonly [entityKind]: string = 'MySqlInsert'; declare protected $table: TTable; diff --git a/drizzle-orm/src/mysql-core/query-builders/query.ts b/drizzle-orm/src/mysql-core/query-builders/query.ts index 955f73428..16d294598 100644 --- a/drizzle-orm/src/mysql-core/query-builders/query.ts +++ b/drizzle-orm/src/mysql-core/query-builders/query.ts @@ -77,7 +77,7 @@ export class MySqlRelationalQuery< TPreparedQueryHKT extends PreparedQueryHKTBase, TResult, > extends QueryPromise { - static readonly [entityKind]: string = 'MySqlRelationalQuery'; + static override readonly [entityKind]: string = 'MySqlRelationalQuery'; declare protected $brand: 'MySqlRelationalQuery'; diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index a5a0ca69a..95f67827b 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -132,7 +132,7 @@ export abstract class MySqlSelectQueryBuilderBase< TResult extends any[] = SelectResult[], TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > extends TypedQueryBuilder { - static readonly [entityKind]: string = 'MySqlSelectQueryBuilder'; + static override readonly [entityKind]: string = 'MySqlSelectQueryBuilder'; override readonly _: { readonly hkt: THKT; @@ -942,7 +942,7 @@ export class MySqlSelectBase< TResult, TSelectedFields > { - static readonly [entityKind]: string = 'MySqlSelect'; + static override readonly [entityKind]: string = 'MySqlSelect'; prepare(): MySqlSelectPrepare { if (!this.session) { diff --git a/drizzle-orm/src/mysql-core/query-builders/update.ts b/drizzle-orm/src/mysql-core/query-builders/update.ts index 7884599cf..9efc4e325 100644 --- a/drizzle-orm/src/mysql-core/query-builders/update.ts +++ b/drizzle-orm/src/mysql-core/query-builders/update.ts @@ -12,13 +12,18 @@ import type { } from '~/mysql-core/session.ts'; import type { MySqlTable } from '~/mysql-core/table.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; -import { mapUpdateSet, type UpdateSet } from '~/utils.ts'; +import { Table } from '~/table.ts'; +import { mapUpdateSet, type UpdateSet, type ValueOrArray } from '~/utils.ts'; +import type { MySqlColumn } from '../columns/common.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; export interface MySqlUpdateConfig { where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (MySqlColumn | SQL | SQL.Aliased)[]; set: UpdateSet; table: MySqlTable; returning?: SelectedFieldsOrdered; @@ -120,7 +125,7 @@ export class MySqlUpdateBase< // eslint-disable-next-line @typescript-eslint/no-unused-vars TExcludedMethods extends string = never, > extends QueryPromise> implements SQLWrapper { - static readonly [entityKind]: string = 'MySqlUpdate'; + static override readonly [entityKind]: string = 'MySqlUpdate'; private config: MySqlUpdateConfig; @@ -173,6 +178,37 @@ export class MySqlUpdateBase< return this as any; } + orderBy( + builder: (updateTable: TTable) => ValueOrArray, + ): MySqlUpdateWithout; + orderBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): MySqlUpdateWithout; + orderBy( + ...columns: + | [(updateTable: TTable) => ValueOrArray] + | (MySqlColumn | SQL | SQL.Aliased)[] + ): MySqlUpdateWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (MySqlColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): MySqlUpdateWithout { + this.config.limit = limit; + return this as any; + } + /** @internal */ getSQL(): SQL { return this.dialect.buildUpdateQuery(this.config); diff --git a/drizzle-orm/src/mysql-core/session.ts b/drizzle-orm/src/mysql-core/session.ts index 021d4276d..326b0ad61 100644 --- a/drizzle-orm/src/mysql-core/session.ts +++ b/drizzle-orm/src/mysql-core/session.ts @@ -130,7 +130,7 @@ export abstract class MySqlTransaction< TFullSchema extends Record = Record, TSchema extends TablesRelationalConfig = Record, > extends MySqlDatabase { - static readonly [entityKind]: string = 'MySqlTransaction'; + static override readonly [entityKind]: string = 'MySqlTransaction'; constructor( dialect: MySqlDialect, diff --git a/drizzle-orm/src/mysql-core/table.ts b/drizzle-orm/src/mysql-core/table.ts index 36c366d61..e09278dc5 100644 --- a/drizzle-orm/src/mysql-core/table.ts +++ b/drizzle-orm/src/mysql-core/table.ts @@ -24,7 +24,7 @@ export type TableConfig = TableConfigBase; export const InlineForeignKeys = Symbol.for('drizzle:MySqlInlineForeignKeys'); export class MySqlTable extends Table { - static readonly [entityKind]: string = 'MySqlTable'; + static override readonly [entityKind]: string = 'MySqlTable'; declare protected $columns: T['columns']; diff --git a/drizzle-orm/src/mysql-core/view-base.ts b/drizzle-orm/src/mysql-core/view-base.ts index 46b1527d9..fa8a25cfa 100644 --- a/drizzle-orm/src/mysql-core/view-base.ts +++ b/drizzle-orm/src/mysql-core/view-base.ts @@ -7,7 +7,7 @@ export abstract class MySqlViewBase< TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, > extends View { - static readonly [entityKind]: string = 'MySqlViewBase'; + static override readonly [entityKind]: string = 'MySqlViewBase'; declare readonly _: View['_'] & { readonly viewBrand: 'MySqlViewBase'; diff --git a/drizzle-orm/src/mysql-core/view.ts b/drizzle-orm/src/mysql-core/view.ts index 4cc7d416c..6054e022c 100644 --- a/drizzle-orm/src/mysql-core/view.ts +++ b/drizzle-orm/src/mysql-core/view.ts @@ -14,7 +14,6 @@ import { MySqlViewConfig } from './view-common.ts'; export interface ViewBuilderConfig { algorithm?: 'undefined' | 'merge' | 'temptable'; - definer?: string; sqlSecurity?: 'definer' | 'invoker'; withCheckOption?: 'cascaded' | 'local'; } @@ -41,13 +40,6 @@ export class ViewBuilderCore, - ): this { - this.config.definer = definer; - return this; - } - sqlSecurity( sqlSecurity: Exclude, ): this { @@ -64,7 +56,7 @@ export class ViewBuilderCore extends ViewBuilderCore<{ name: TName }> { - static readonly [entityKind]: string = 'MySqlViewBuilder'; + static override readonly [entityKind]: string = 'MySqlViewBuilder'; as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), @@ -98,7 +90,7 @@ export class ManualViewBuilder< TName extends string = string, TColumns extends Record = Record, > extends ViewBuilderCore<{ name: TName; columns: TColumns }> { - static readonly [entityKind]: string = 'MySqlManualViewBuilder'; + static override readonly [entityKind]: string = 'MySqlManualViewBuilder'; private columns: Record; @@ -157,7 +149,7 @@ export class MySqlView< TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, > extends MySqlViewBase { - static readonly [entityKind]: string = 'MySqlView'; + static override readonly [entityKind]: string = 'MySqlView'; declare protected $MySqlViewBrand: 'MySqlView'; diff --git a/drizzle-orm/src/mysql-proxy/driver.ts b/drizzle-orm/src/mysql-proxy/driver.ts index badefb02e..bb0c21134 100644 --- a/drizzle-orm/src/mysql-proxy/driver.ts +++ b/drizzle-orm/src/mysql-proxy/driver.ts @@ -14,7 +14,7 @@ import { type MySqlRemotePreparedQueryHKT, type MySqlRemoteQueryResultHKT, MySql export class MySqlRemoteDatabase< TSchema extends Record = Record, > extends MySqlDatabase { - static readonly [entityKind]: string = 'MySqlRemoteDatabase'; + static override readonly [entityKind]: string = 'MySqlRemoteDatabase'; } export type RemoteCallback = ( diff --git a/drizzle-orm/src/mysql-proxy/session.ts b/drizzle-orm/src/mysql-proxy/session.ts index 03039cfb2..e72875e79 100644 --- a/drizzle-orm/src/mysql-proxy/session.ts +++ b/drizzle-orm/src/mysql-proxy/session.ts @@ -30,7 +30,7 @@ export class MySqlRemoteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlSession { - static readonly [entityKind]: string = 'MySqlRemoteSession'; + static override readonly [entityKind]: string = 'MySqlRemoteSession'; private logger: Logger; @@ -81,7 +81,7 @@ export class MySqlProxyTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlTransaction { - static readonly [entityKind]: string = 'MySqlProxyTransaction'; + static override readonly [entityKind]: string = 'MySqlProxyTransaction'; override async transaction( _transaction: (tx: MySqlProxyTransaction) => Promise, @@ -91,7 +91,7 @@ export class MySqlProxyTransaction< } export class PreparedQuery extends PreparedQueryBase { - static readonly [entityKind]: string = 'MySqlProxyPreparedQuery'; + static override readonly [entityKind]: string = 'MySqlProxyPreparedQuery'; constructor( private client: RemoteCallback, diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index 13e296ab9..ef34604e3 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -1,4 +1,6 @@ -import type { Connection as CallbackConnection, Pool as CallbackPool } from 'mysql2'; +import { EventEmitter } from 'events'; +import { type Connection as CallbackConnection, createPool, type Pool as CallbackPool, type PoolOptions } from 'mysql2'; +import type { Connection, Pool } from 'mysql2/promise'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -11,7 +13,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { DrizzleError } from '../errors.ts'; import type { MySql2Client, MySql2PreparedQueryHKT, MySql2QueryResultHKT } from './session.ts'; import { MySql2Session } from './session.ts'; @@ -43,16 +45,16 @@ export { MySqlDatabase } from '~/mysql-core/db.ts'; export class MySql2Database< TSchema extends Record = Record, > extends MySqlDatabase { - static readonly [entityKind]: string = 'MySql2Database'; + static override readonly [entityKind]: string = 'MySql2Database'; } export type MySql2DrizzleConfig = Record> = & Omit, 'schema'> & ({ schema: TSchema; mode: Mode } | { schema?: undefined; mode?: Mode }); -export function drizzle< +function construct< TSchema extends Record = Record, - TClient extends MySql2Client | CallbackConnection | CallbackPool = MySql2Client | CallbackConnection | CallbackPool, + TClient extends Pool | Connection | CallbackPool | CallbackConnection = CallbackPool, >( client: TClient, config: MySql2DrizzleConfig = {}, @@ -106,3 +108,71 @@ interface CallbackClient { function isCallbackClient(client: any): client is CallbackClient { return typeof client.promise === 'function'; } + +export type AnyMySql2Connection = Pool | Connection | CallbackPool | CallbackConnection; + +export function drizzle< + TSchema extends Record = Record, + TClient extends AnyMySql2Connection = CallbackPool, +>( + ...params: IfNotImported< + CallbackPool, + [ImportTypeError<'mysql2'>], + [ + TClient | string, + ] | [ + TClient | string, + MySql2DrizzleConfig, + ] | [ + ( + & MySql2DrizzleConfig + & ({ + connection: string | PoolOptions; + } | { + client: TClient; + }) + ), + ] + > +): MySql2Database & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof EventEmitter) { + return construct(params[0] as TClient, params[1] as MySql2DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: PoolOptions | string; client?: TClient } + & MySql2DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' + ? createPool({ + uri: connection, + }) + : createPool(connection!); + const db = construct(instance, drizzleConfig); + + return db as any; + } + + const connectionString = params[0]!; + const instance = createPool({ + uri: connectionString, + }); + + return construct(instance, params[1]) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: MySql2DrizzleConfig, + ): MySql2Database & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/mysql2/session.ts b/drizzle-orm/src/mysql2/session.ts index ab11d1f17..7ca21c4a6 100644 --- a/drizzle-orm/src/mysql2/session.ts +++ b/drizzle-orm/src/mysql2/session.ts @@ -41,7 +41,7 @@ export type MySqlQueryResult< > = [T extends ResultSetHeader ? T : T[], FieldPacket[]]; export class MySql2PreparedQuery extends MySqlPreparedQuery { - static readonly [entityKind]: string = 'MySql2PreparedQuery'; + static override readonly [entityKind]: string = 'MySql2PreparedQuery'; private rawQuery: QueryOptions; private query: QueryOptions; @@ -190,7 +190,7 @@ export class MySql2Session< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlSession { - static readonly [entityKind]: string = 'MySql2Session'; + static override readonly [entityKind]: string = 'MySql2Session'; private logger: Logger; private mode: Mode; @@ -301,7 +301,7 @@ export class MySql2Transaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlTransaction { - static readonly [entityKind]: string = 'MySql2Transaction'; + static override readonly [entityKind]: string = 'MySql2Transaction'; override async transaction(transaction: (tx: MySql2Transaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex + 1}`; diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index e85204a62..f79fd9de3 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -1,5 +1,5 @@ -import type { NeonQueryFunction } from '@neondatabase/serverless'; -import { types } from '@neondatabase/serverless'; +import type { HTTPTransactionOptions, NeonQueryFunction } from '@neondatabase/serverless'; +import { neon, types } from '@neondatabase/serverless'; import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; @@ -8,7 +8,7 @@ import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig } from '~/relations.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { type NeonHttpClient, type NeonHttpQueryResultHKT, NeonHttpSession } from './session.ts'; export interface NeonDriverOptions { @@ -43,7 +43,7 @@ export class NeonHttpDriver { export class NeonHttpDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'NeonHttpDatabase'; + static override readonly [entityKind]: string = 'NeonHttpDatabase'; /** @internal */ declare readonly session: NeonHttpSession>; @@ -55,7 +55,7 @@ export class NeonHttpDatabase< } } -export function drizzle< +function construct< TSchema extends Record = Record, TClient extends NeonQueryFunction = NeonQueryFunction, >( @@ -97,3 +97,75 @@ export function drizzle< return db as any; } + +export function drizzle< + TSchema extends Record = Record, + TClient extends NeonQueryFunction = NeonQueryFunction, +>( + ...params: IfNotImported< + HTTPTransactionOptions, + [ImportTypeError<'@neondatabase/serverless'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | ({ connectionString: string } & HTTPTransactionOptions); + } | { + client: TClient; + }) + ), + ] + > +): NeonHttpDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (typeof params[0] === 'function') { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, client, ...drizzleConfig } = params[0] as + & { + connection?: + | ({ + connectionString: string; + } & HTTPTransactionOptions) + | string; + client?: TClient; + } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig); + + if (typeof connection === 'object') { + const { connectionString, ...options } = connection; + + const instance = neon(connectionString, options); + + return construct(instance, drizzleConfig) as any; + } + + const instance = neon(connection!); + + return construct(instance, drizzleConfig) as any; + } + + const instance = neon(params[0] as string); + return construct(instance, params[1]) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): NeonHttpDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/neon-http/session.ts b/drizzle-orm/src/neon-http/session.ts index 4dd768d3e..cd4a855e7 100644 --- a/drizzle-orm/src/neon-http/session.ts +++ b/drizzle-orm/src/neon-http/session.ts @@ -25,7 +25,7 @@ const queryConfig = { } as const; export class NeonHttpPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'NeonHttpPreparedQuery'; + static override readonly [entityKind]: string = 'NeonHttpPreparedQuery'; constructor( private client: NeonHttpClient, @@ -94,7 +94,7 @@ export class NeonHttpSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'NeonHttpSession'; + static override readonly [entityKind]: string = 'NeonHttpSession'; private logger: Logger; @@ -182,7 +182,7 @@ export class NeonTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'NeonHttpTransaction'; + static override readonly [entityKind]: string = 'NeonHttpTransaction'; override async transaction(_transaction: (tx: NeonTransaction) => Promise): Promise { throw new Error('No transactions support in neon-http driver'); diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index 7ee72814b..c0f962e96 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -1,4 +1,4 @@ -import { types } from '@neondatabase/serverless'; +import { neonConfig, Pool, type PoolConfig } from '@neondatabase/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { NeonClient, NeonQueryResultHKT } from './session.ts'; import { NeonSession } from './session.ts'; @@ -26,7 +26,6 @@ export class NeonDriver { private dialect: PgDialect, private options: NeonDriverOptions = {}, ) { - this.initMappers(); } createSession( @@ -34,22 +33,15 @@ export class NeonDriver { ): NeonSession, TablesRelationalConfig> { return new NeonSession(this.client, this.dialect, schema, { logger: this.options.logger }); } - - initMappers() { - types.setTypeParser(types.builtins.TIMESTAMPTZ, (val) => val); - types.setTypeParser(types.builtins.TIMESTAMP, (val) => val); - types.setTypeParser(types.builtins.DATE, (val) => val); - types.setTypeParser(types.builtins.INTERVAL, (val) => val); - } } export class NeonDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'NeonServerlessDatabase'; + static override readonly [entityKind]: string = 'NeonServerlessDatabase'; } -export function drizzle< +function construct< TSchema extends Record = Record, TClient extends NeonClient = NeonClient, >( @@ -86,3 +78,76 @@ export function drizzle< return db as any; } + +export function drizzle< + TSchema extends Record = Record, + TClient extends NeonClient = Pool, +>( + ...params: IfNotImported< + Pool, + [ImportTypeError<'@neondatabase/serverless'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | PoolConfig; + } | { + client: TClient; + }) + & { + ws?: any; + } + ), + ] + > +): NeonDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof Pool) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, client, ws, ...drizzleConfig } = params[0] as { + connection?: PoolConfig | string; + ws?: any; + client?: TClient; + } & DrizzleConfig; + + if (ws) { + neonConfig.webSocketConstructor = ws; + } + + if (client) return construct(client, drizzleConfig); + + const instance = typeof connection === 'string' + ? new Pool({ + connectionString: connection, + }) + : new Pool(connection); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Pool({ + connectionString: params[0], + }); + + return construct(instance, params[1]) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): NeonDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/neon-serverless/session.ts b/drizzle-orm/src/neon-serverless/session.ts index 82c405333..6f144e3fb 100644 --- a/drizzle-orm/src/neon-serverless/session.ts +++ b/drizzle-orm/src/neon-serverless/session.ts @@ -6,6 +6,7 @@ import { type QueryConfig, type QueryResult, type QueryResultRow, + types, } from '@neondatabase/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; @@ -16,13 +17,13 @@ import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.type import type { PgQueryResultHKT, PgTransactionConfig, PreparedQueryConfig } from '~/pg-core/session.ts'; import { PgPreparedQuery, PgSession } from '~/pg-core/session.ts'; import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; +import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; export type NeonClient = Pool | PoolClient | Client; export class NeonPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'NeonPreparedQuery'; + static override readonly [entityKind]: string = 'NeonPreparedQuery'; private rawQueryConfig: QueryConfig; private queryConfig: QueryArrayConfig; @@ -41,11 +42,49 @@ export class NeonPreparedQuery extends PgPrepared this.rawQueryConfig = { name, text: queryString, + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val: any) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val: any) => val; + } + if (typeId === types.builtins.DATE) { + return (val: any) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val: any) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; this.queryConfig = { name, text: queryString, rowMode: 'array', + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val: any) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val: any) => val; + } + if (typeId === types.builtins.DATE) { + return (val: any) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val: any) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; } @@ -93,7 +132,7 @@ export class NeonSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'NeonSession'; + static override readonly [entityKind]: string = 'NeonSession'; private logger: Logger; @@ -143,6 +182,14 @@ export class NeonSession< return this.client.query(query, params); } + override async count(sql: SQL): Promise { + const res = await this.execute<{ rows: [{ count: string }] }>(sql); + + return Number( + res['rows'][0]['count'], + ); + } + override async transaction( transaction: (tx: NeonTransaction) => Promise, config: PgTransactionConfig = {}, @@ -171,7 +218,7 @@ export class NeonTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'NeonTransaction'; + static override readonly [entityKind]: string = 'NeonTransaction'; override async transaction(transaction: (tx: NeonTransaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex + 1}`; diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index 79a99a3fa..b9bb063d8 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -1,4 +1,5 @@ -import pg from 'pg'; +import { EventEmitter } from 'events'; +import pg, { type Pool, type PoolConfig } from 'pg'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -10,12 +11,10 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { NodePgClient, NodePgQueryResultHKT } from './session.ts'; import { NodePgSession } from './session.ts'; -const { types } = pg; - export interface PgDriverOptions { logger?: Logger; } @@ -28,7 +27,6 @@ export class NodePgDriver { private dialect: PgDialect, private options: PgDriverOptions = {}, ) { - this.initMappers(); } createSession( @@ -36,22 +34,15 @@ export class NodePgDriver { ): NodePgSession, TablesRelationalConfig> { return new NodePgSession(this.client, this.dialect, schema, { logger: this.options.logger }); } - - initMappers() { - types.setTypeParser(types.builtins.TIMESTAMPTZ, (val) => val); - types.setTypeParser(types.builtins.TIMESTAMP, (val) => val); - types.setTypeParser(types.builtins.DATE, (val) => val); - types.setTypeParser(types.builtins.INTERVAL, (val) => val); - } } export class NodePgDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'NodePgDatabase'; + static override readonly [entityKind]: string = 'NodePgDatabase'; } -export function drizzle< +function construct< TSchema extends Record = Record, TClient extends NodePgClient = NodePgClient, >( @@ -88,3 +79,70 @@ export function drizzle< return db as any; } + +export function drizzle< + TSchema extends Record = Record, + TClient extends NodePgClient = Pool, +>( + ...params: IfNotImported< + Pool, + [ImportTypeError<'pg'>], + | [ + TClient | string, + ] + | [ + TClient | string, + DrizzleConfig, + ] + | [ + ( + & DrizzleConfig + & ({ + connection: string | PoolConfig; + } | { + client: TClient; + }) + ), + ] + > +): NodePgDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof EventEmitter) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, client, ...drizzleConfig } = params[0] as ( + & ({ connection?: PoolConfig | string; client?: TClient }) + & DrizzleConfig + ); + + if (client) return construct(client, drizzleConfig); + + const instance = typeof connection === 'string' + ? new pg.Pool({ + connectionString: connection, + }) + : new pg.Pool(connection!); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new pg.Pool({ + connectionString: params[0], + }); + + return construct(instance, params[1] as DrizzleConfig | undefined) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): NodePgDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/node-postgres/session.ts b/drizzle-orm/src/node-postgres/session.ts index ef6779354..a925d7018 100644 --- a/drizzle-orm/src/node-postgres/session.ts +++ b/drizzle-orm/src/node-postgres/session.ts @@ -12,12 +12,12 @@ import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; -const { Pool } = pg; +const { Pool, types } = pg; export type NodePgClient = pg.Pool | PoolClient | Client; export class NodePgPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'NodePgPreparedQuery'; + static override readonly [entityKind]: string = 'NodePgPreparedQuery'; private rawQueryConfig: QueryConfig; private queryConfig: QueryArrayConfig; @@ -36,11 +36,49 @@ export class NodePgPreparedQuery extends PgPrepar this.rawQueryConfig = { name, text: queryString, + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val) => val; + } + if (typeId === types.builtins.DATE) { + return (val) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; this.queryConfig = { name, text: queryString, rowMode: 'array', + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val) => val; + } + if (typeId === types.builtins.DATE) { + return (val) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; } @@ -109,7 +147,7 @@ export class NodePgSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'NodePgSession'; + static override readonly [entityKind]: string = 'NodePgSession'; private logger: Logger; @@ -177,7 +215,7 @@ export class NodePgTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'NodePgTransaction'; + static override readonly [entityKind]: string = 'NodePgTransaction'; override async transaction(transaction: (tx: NodePgTransaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex + 1}`; diff --git a/drizzle-orm/src/op-sqlite/driver.ts b/drizzle-orm/src/op-sqlite/driver.ts index ac8b1f310..06b9d57f4 100644 --- a/drizzle-orm/src/op-sqlite/driver.ts +++ b/drizzle-orm/src/op-sqlite/driver.ts @@ -15,7 +15,7 @@ import { OPSQLiteSession } from './session.ts'; export class OPSQLiteDatabase< TSchema extends Record = Record, > extends BaseSQLiteDatabase<'async', QueryResult, TSchema> { - static readonly [entityKind]: string = 'OPSQLiteDatabase'; + static override readonly [entityKind]: string = 'OPSQLiteDatabase'; } export function drizzle = Record>( diff --git a/drizzle-orm/src/op-sqlite/session.ts b/drizzle-orm/src/op-sqlite/session.ts index f7a08a56b..c1ac63071 100644 --- a/drizzle-orm/src/op-sqlite/session.ts +++ b/drizzle-orm/src/op-sqlite/session.ts @@ -26,7 +26,7 @@ export class OPSQLiteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'async', QueryResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'OPSQLiteSession'; + static override readonly [entityKind]: string = 'OPSQLiteSession'; private logger: Logger; @@ -79,7 +79,7 @@ export class OPSQLiteTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'async', QueryResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'OPSQLiteTransaction'; + static override readonly [entityKind]: string = 'OPSQLiteTransaction'; override transaction(transaction: (tx: OPSQLiteTransaction) => T): T { const savepointName = `sp${this.nestedIndex}`; @@ -99,7 +99,7 @@ export class OPSQLiteTransaction< export class OPSQLitePreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: QueryResult; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'OPSQLitePreparedQuery'; + static override readonly [entityKind]: string = 'OPSQLitePreparedQuery'; constructor( private client: OPSQLiteConnection, diff --git a/drizzle-orm/src/pg-core/columns/bigint.ts b/drizzle-orm/src/pg-core/columns/bigint.ts index ef6be9eff..23e1e7f15 100644 --- a/drizzle-orm/src/pg-core/columns/bigint.ts +++ b/drizzle-orm/src/pg-core/columns/bigint.ts @@ -20,7 +20,7 @@ export type PgBigInt53BuilderInitial = PgBigInt53Builder<{ export class PgBigInt53Builder> extends PgIntColumnBaseBuilder { - static readonly [entityKind]: string = 'PgBigInt53Builder'; + static override readonly [entityKind]: string = 'PgBigInt53Builder'; constructor(name: T['name']) { super(name, 'number', 'PgBigInt53'); @@ -35,7 +35,7 @@ export class PgBigInt53Builder> extends PgColumn { - static readonly [entityKind]: string = 'PgBigInt53'; + static override readonly [entityKind]: string = 'PgBigInt53'; getSQLType(): string { return 'bigint'; @@ -62,7 +62,7 @@ export type PgBigInt64BuilderInitial = PgBigInt64Builder<{ export class PgBigInt64Builder> extends PgIntColumnBaseBuilder { - static readonly [entityKind]: string = 'PgBigInt64Builder'; + static override readonly [entityKind]: string = 'PgBigInt64Builder'; constructor(name: T['name']) { super(name, 'bigint', 'PgBigInt64'); @@ -80,7 +80,7 @@ export class PgBigInt64Builder> extends PgColumn { - static readonly [entityKind]: string = 'PgBigInt64'; + static override readonly [entityKind]: string = 'PgBigInt64'; getSQLType(): string { return 'bigint'; diff --git a/drizzle-orm/src/pg-core/columns/bigserial.ts b/drizzle-orm/src/pg-core/columns/bigserial.ts index 775234cb2..ed4224354 100644 --- a/drizzle-orm/src/pg-core/columns/bigserial.ts +++ b/drizzle-orm/src/pg-core/columns/bigserial.ts @@ -28,7 +28,7 @@ export type PgBigSerial53BuilderInitial = NotNull< export class PgBigSerial53Builder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgBigSerial53Builder'; + static override readonly [entityKind]: string = 'PgBigSerial53Builder'; constructor(name: string) { super(name, 'number', 'PgBigSerial53'); @@ -48,7 +48,7 @@ export class PgBigSerial53Builder> extends PgColumn { - static readonly [entityKind]: string = 'PgBigSerial53'; + static override readonly [entityKind]: string = 'PgBigSerial53'; getSQLType(): string { return 'bigserial'; @@ -79,7 +79,7 @@ export type PgBigSerial64BuilderInitial = NotNull< export class PgBigSerial64Builder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgBigSerial64Builder'; + static override readonly [entityKind]: string = 'PgBigSerial64Builder'; constructor(name: string) { super(name, 'bigint', 'PgBigSerial64'); @@ -98,7 +98,7 @@ export class PgBigSerial64Builder> extends PgColumn { - static readonly [entityKind]: string = 'PgBigSerial64'; + static override readonly [entityKind]: string = 'PgBigSerial64'; getSQLType(): string { return 'bigserial'; diff --git a/drizzle-orm/src/pg-core/columns/boolean.ts b/drizzle-orm/src/pg-core/columns/boolean.ts index 19139243a..cd30895c7 100644 --- a/drizzle-orm/src/pg-core/columns/boolean.ts +++ b/drizzle-orm/src/pg-core/columns/boolean.ts @@ -15,7 +15,7 @@ export type PgBooleanBuilderInitial = PgBooleanBuilder<{ }>; export class PgBooleanBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgBooleanBuilder'; + static override readonly [entityKind]: string = 'PgBooleanBuilder'; constructor(name: T['name']) { super(name, 'boolean', 'PgBoolean'); @@ -30,7 +30,7 @@ export class PgBooleanBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgBoolean'; + static override readonly [entityKind]: string = 'PgBoolean'; getSQLType(): string { return 'boolean'; diff --git a/drizzle-orm/src/pg-core/columns/char.ts b/drizzle-orm/src/pg-core/columns/char.ts index a3b8853be..6629f08cc 100644 --- a/drizzle-orm/src/pg-core/columns/char.ts +++ b/drizzle-orm/src/pg-core/columns/char.ts @@ -19,7 +19,7 @@ export class PgCharBuilder T, { length: number | undefined; enumValues: T['enumValues'] } > { - static readonly [entityKind]: string = 'PgCharBuilder'; + static override readonly [entityKind]: string = 'PgCharBuilder'; constructor(name: T['name'], config: PgCharConfig) { super(name, 'string', 'PgChar'); @@ -38,7 +38,7 @@ export class PgCharBuilder export class PgChar> extends PgColumn { - static readonly [entityKind]: string = 'PgChar'; + static override readonly [entityKind]: string = 'PgChar'; readonly length = this.config.length; override readonly enumValues = this.config.enumValues; diff --git a/drizzle-orm/src/pg-core/columns/cidr.ts b/drizzle-orm/src/pg-core/columns/cidr.ts index 8ab375ba1..6caa3dc25 100644 --- a/drizzle-orm/src/pg-core/columns/cidr.ts +++ b/drizzle-orm/src/pg-core/columns/cidr.ts @@ -15,7 +15,7 @@ export type PgCidrBuilderInitial = PgCidrBuilder<{ }>; export class PgCidrBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgCidrBuilder'; + static override readonly [entityKind]: string = 'PgCidrBuilder'; constructor(name: T['name']) { super(name, 'string', 'PgCidr'); @@ -30,7 +30,7 @@ export class PgCidrBuilder } export class PgCidr> extends PgColumn { - static readonly [entityKind]: string = 'PgCidr'; + static override readonly [entityKind]: string = 'PgCidr'; getSQLType(): string { return 'cidr'; diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index 84118ef20..c2fbe8cb9 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -46,7 +46,7 @@ export abstract class PgColumnBuilder< { private foreignKeyConfigs: ReferenceConfig[] = []; - static readonly [entityKind]: string = 'PgColumnBuilder'; + static override readonly [entityKind]: string = 'PgColumnBuilder'; array(size?: number): PgArrayBuilder< & { @@ -134,7 +134,7 @@ export abstract class PgColumn< TRuntimeConfig extends object = {}, TTypeConfig extends object = {}, > extends Column { - static readonly [entityKind]: string = 'PgColumn'; + static override readonly [entityKind]: string = 'PgColumn'; constructor( override readonly table: PgTable, @@ -152,7 +152,7 @@ export type IndexedExtraConfigType = { order?: 'asc' | 'desc'; nulls?: 'first' | export class ExtraConfigColumn< T extends ColumnBaseConfig = ColumnBaseConfig, > extends PgColumn { - static readonly [entityKind]: string = 'ExtraConfigColumn'; + static override readonly [entityKind]: string = 'ExtraConfigColumn'; override getSQLType(): string { return this.getSQLType(); @@ -292,7 +292,7 @@ export class PgArray< > extends PgColumn { readonly size: number | undefined; - static readonly [entityKind]: string = 'PgArray'; + static override readonly [entityKind]: string = 'PgArray'; constructor( table: AnyPgTable<{ name: T['tableName'] }>, diff --git a/drizzle-orm/src/pg-core/columns/custom.ts b/drizzle-orm/src/pg-core/columns/custom.ts index 44fdec1b2..b59169ed6 100644 --- a/drizzle-orm/src/pg-core/columns/custom.ts +++ b/drizzle-orm/src/pg-core/columns/custom.ts @@ -35,7 +35,7 @@ export class PgCustomColumnBuilder { - static readonly [entityKind]: string = 'PgCustomColumnBuilder'; + static override readonly [entityKind]: string = 'PgCustomColumnBuilder'; constructor( name: T['name'], @@ -59,7 +59,7 @@ export class PgCustomColumnBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgCustomColumn'; + static override readonly [entityKind]: string = 'PgCustomColumn'; private sqlName: string; private mapTo?: (value: T['data']) => T['driverParam']; diff --git a/drizzle-orm/src/pg-core/columns/date.common.ts b/drizzle-orm/src/pg-core/columns/date.common.ts index c2a46d1ce..e8bfbf2b1 100644 --- a/drizzle-orm/src/pg-core/columns/date.common.ts +++ b/drizzle-orm/src/pg-core/columns/date.common.ts @@ -7,7 +7,7 @@ export abstract class PgDateColumnBaseBuilder< T extends ColumnBuilderBaseConfig, TRuntimeConfig extends object = object, > extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgDateColumnBaseBuilder'; + static override readonly [entityKind]: string = 'PgDateColumnBaseBuilder'; defaultNow() { return this.default(sql`now()`); diff --git a/drizzle-orm/src/pg-core/columns/date.ts b/drizzle-orm/src/pg-core/columns/date.ts index 812ec4e92..1d295b97a 100644 --- a/drizzle-orm/src/pg-core/columns/date.ts +++ b/drizzle-orm/src/pg-core/columns/date.ts @@ -17,7 +17,7 @@ export type PgDateBuilderInitial = PgDateBuilder<{ }>; export class PgDateBuilder> extends PgDateColumnBaseBuilder { - static readonly [entityKind]: string = 'PgDateBuilder'; + static override readonly [entityKind]: string = 'PgDateBuilder'; constructor(name: T['name']) { super(name, 'date', 'PgDate'); @@ -32,7 +32,7 @@ export class PgDateBuilder> } export class PgDate> extends PgColumn { - static readonly [entityKind]: string = 'PgDate'; + static override readonly [entityKind]: string = 'PgDate'; getSQLType(): string { return 'date'; @@ -60,7 +60,7 @@ export type PgDateStringBuilderInitial = PgDateStringBuild export class PgDateStringBuilder> extends PgDateColumnBaseBuilder { - static readonly [entityKind]: string = 'PgDateStringBuilder'; + static override readonly [entityKind]: string = 'PgDateStringBuilder'; constructor(name: T['name']) { super(name, 'string', 'PgDateString'); @@ -78,7 +78,7 @@ export class PgDateStringBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgDateString'; + static override readonly [entityKind]: string = 'PgDateString'; getSQLType(): string { return 'date'; diff --git a/drizzle-orm/src/pg-core/columns/double-precision.ts b/drizzle-orm/src/pg-core/columns/double-precision.ts index 8e454169f..77245ea45 100644 --- a/drizzle-orm/src/pg-core/columns/double-precision.ts +++ b/drizzle-orm/src/pg-core/columns/double-precision.ts @@ -17,7 +17,7 @@ export type PgDoublePrecisionBuilderInitial = PgDoublePrec export class PgDoublePrecisionBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgDoublePrecisionBuilder'; + static override readonly [entityKind]: string = 'PgDoublePrecisionBuilder'; constructor(name: T['name']) { super(name, 'number', 'PgDoublePrecision'); @@ -35,7 +35,7 @@ export class PgDoublePrecisionBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgDoublePrecision'; + static override readonly [entityKind]: string = 'PgDoublePrecision'; getSQLType(): string { return 'double precision'; diff --git a/drizzle-orm/src/pg-core/columns/enum.ts b/drizzle-orm/src/pg-core/columns/enum.ts index d35ec89d9..7712ca606 100644 --- a/drizzle-orm/src/pg-core/columns/enum.ts +++ b/drizzle-orm/src/pg-core/columns/enum.ts @@ -36,7 +36,7 @@ export function isPgEnum(obj: unknown): obj is PgEnum<[string, ...string[]]> { export class PgEnumColumnBuilder< T extends ColumnBuilderBaseConfig<'string', 'PgEnumColumn'> & { enumValues: [string, ...string[]] }, > extends PgColumnBuilder }> { - static readonly [entityKind]: string = 'PgEnumColumnBuilder'; + static override readonly [entityKind]: string = 'PgEnumColumnBuilder'; constructor(name: T['name'], enumInstance: PgEnum) { super(name, 'string', 'PgEnumColumn'); @@ -57,7 +57,7 @@ export class PgEnumColumnBuilder< export class PgEnumColumn & { enumValues: [string, ...string[]] }> extends PgColumn }> { - static readonly [entityKind]: string = 'PgEnumColumn'; + static override readonly [entityKind]: string = 'PgEnumColumn'; readonly enum = this.config.enum; override readonly enumValues = this.config.enum.enumValues; diff --git a/drizzle-orm/src/pg-core/columns/inet.ts b/drizzle-orm/src/pg-core/columns/inet.ts index a675359b3..6b6210fcf 100644 --- a/drizzle-orm/src/pg-core/columns/inet.ts +++ b/drizzle-orm/src/pg-core/columns/inet.ts @@ -15,7 +15,7 @@ export type PgInetBuilderInitial = PgInetBuilder<{ }>; export class PgInetBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgInetBuilder'; + static override readonly [entityKind]: string = 'PgInetBuilder'; constructor(name: T['name']) { super(name, 'string', 'PgInet'); @@ -30,7 +30,7 @@ export class PgInetBuilder } export class PgInet> extends PgColumn { - static readonly [entityKind]: string = 'PgInet'; + static override readonly [entityKind]: string = 'PgInet'; getSQLType(): string { return 'inet'; diff --git a/drizzle-orm/src/pg-core/columns/int.common.ts b/drizzle-orm/src/pg-core/columns/int.common.ts index 07c26ba9e..c473b8d04 100644 --- a/drizzle-orm/src/pg-core/columns/int.common.ts +++ b/drizzle-orm/src/pg-core/columns/int.common.ts @@ -14,7 +14,7 @@ export abstract class PgIntColumnBaseBuilder< T, { generatedIdentity: GeneratedIdentityConfig } > { - static readonly [entityKind]: string = 'PgIntColumnBaseBuilder'; + static override readonly [entityKind]: string = 'PgIntColumnBaseBuilder'; generatedAlwaysAsIdentity( sequence?: PgSequenceOptions & { name?: string }, diff --git a/drizzle-orm/src/pg-core/columns/integer.ts b/drizzle-orm/src/pg-core/columns/integer.ts index 0feb388f3..bb70f9b41 100644 --- a/drizzle-orm/src/pg-core/columns/integer.ts +++ b/drizzle-orm/src/pg-core/columns/integer.ts @@ -18,7 +18,7 @@ type PgIntegerBuilderInitial = PgIntegerBuilder<{ export class PgIntegerBuilder> extends PgIntColumnBaseBuilder { - static readonly [entityKind]: string = 'PgIntegerBuilder'; + static override readonly [entityKind]: string = 'PgIntegerBuilder'; constructor(name: T['name']) { super(name, 'number', 'PgInteger'); @@ -33,7 +33,7 @@ export class PgIntegerBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgInteger'; + static override readonly [entityKind]: string = 'PgInteger'; getSQLType(): string { return 'integer'; diff --git a/drizzle-orm/src/pg-core/columns/interval.ts b/drizzle-orm/src/pg-core/columns/interval.ts index 3ae6557a3..4d3ed4588 100644 --- a/drizzle-orm/src/pg-core/columns/interval.ts +++ b/drizzle-orm/src/pg-core/columns/interval.ts @@ -19,7 +19,7 @@ export type PgIntervalBuilderInitial = PgIntervalBuilder<{ export class PgIntervalBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgIntervalBuilder'; + static override readonly [entityKind]: string = 'PgIntervalBuilder'; constructor( name: T['name'], @@ -40,7 +40,7 @@ export class PgIntervalBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgInterval'; + static override readonly [entityKind]: string = 'PgInterval'; readonly fields: IntervalConfig['fields'] = this.config.intervalConfig.fields; readonly precision: IntervalConfig['precision'] = this.config.intervalConfig.precision; diff --git a/drizzle-orm/src/pg-core/columns/json.ts b/drizzle-orm/src/pg-core/columns/json.ts index 7e232db5e..3c440c7d2 100644 --- a/drizzle-orm/src/pg-core/columns/json.ts +++ b/drizzle-orm/src/pg-core/columns/json.ts @@ -17,7 +17,7 @@ export type PgJsonBuilderInitial = PgJsonBuilder<{ export class PgJsonBuilder> extends PgColumnBuilder< T > { - static readonly [entityKind]: string = 'PgJsonBuilder'; + static override readonly [entityKind]: string = 'PgJsonBuilder'; constructor(name: T['name']) { super(name, 'json', 'PgJson'); @@ -32,7 +32,7 @@ export class PgJsonBuilder> } export class PgJson> extends PgColumn { - static readonly [entityKind]: string = 'PgJson'; + static override readonly [entityKind]: string = 'PgJson'; constructor(table: AnyPgTable<{ name: T['tableName'] }>, config: PgJsonBuilder['config']) { super(table, config); diff --git a/drizzle-orm/src/pg-core/columns/jsonb.ts b/drizzle-orm/src/pg-core/columns/jsonb.ts index 89d1be86a..3407730db 100644 --- a/drizzle-orm/src/pg-core/columns/jsonb.ts +++ b/drizzle-orm/src/pg-core/columns/jsonb.ts @@ -15,7 +15,7 @@ export type PgJsonbBuilderInitial = PgJsonbBuilder<{ }>; export class PgJsonbBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgJsonbBuilder'; + static override readonly [entityKind]: string = 'PgJsonbBuilder'; constructor(name: T['name']) { super(name, 'json', 'PgJsonb'); @@ -30,7 +30,7 @@ export class PgJsonbBuilder } export class PgJsonb> extends PgColumn { - static readonly [entityKind]: string = 'PgJsonb'; + static override readonly [entityKind]: string = 'PgJsonb'; constructor(table: AnyPgTable<{ name: T['tableName'] }>, config: PgJsonbBuilder['config']) { super(table, config); diff --git a/drizzle-orm/src/pg-core/columns/line.ts b/drizzle-orm/src/pg-core/columns/line.ts index cd4b70a66..014140797 100644 --- a/drizzle-orm/src/pg-core/columns/line.ts +++ b/drizzle-orm/src/pg-core/columns/line.ts @@ -17,7 +17,7 @@ export type PgLineBuilderInitial = PgLineBuilder<{ }>; export class PgLineBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgLineBuilder'; + static override readonly [entityKind]: string = 'PgLineBuilder'; constructor(name: T['name']) { super(name, 'array', 'PgLine'); @@ -35,7 +35,7 @@ export class PgLineBuilder> } export class PgLineTuple> extends PgColumn { - static readonly [entityKind]: string = 'PgLine'; + static override readonly [entityKind]: string = 'PgLine'; getSQLType(): string { return 'line'; @@ -62,7 +62,7 @@ export type PgLineABCBuilderInitial = PgLineABCBuilder<{ }>; export class PgLineABCBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgLineABCBuilder'; + static override readonly [entityKind]: string = 'PgLineABCBuilder'; constructor(name: T['name']) { super(name, 'json', 'PgLineABC'); @@ -80,7 +80,7 @@ export class PgLineABCBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgLineABC'; + static override readonly [entityKind]: string = 'PgLineABC'; getSQLType(): string { return 'line'; diff --git a/drizzle-orm/src/pg-core/columns/macaddr.ts b/drizzle-orm/src/pg-core/columns/macaddr.ts index b43d4ab40..bfc4511f4 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr.ts @@ -15,7 +15,7 @@ export type PgMacaddrBuilderInitial = PgMacaddrBuilder<{ }>; export class PgMacaddrBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgMacaddrBuilder'; + static override readonly [entityKind]: string = 'PgMacaddrBuilder'; constructor(name: T['name']) { super(name, 'string', 'PgMacaddr'); @@ -30,7 +30,7 @@ export class PgMacaddrBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgMacaddr'; + static override readonly [entityKind]: string = 'PgMacaddr'; getSQLType(): string { return 'macaddr'; diff --git a/drizzle-orm/src/pg-core/columns/macaddr8.ts b/drizzle-orm/src/pg-core/columns/macaddr8.ts index 00af8c031..6c4218de0 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr8.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr8.ts @@ -15,7 +15,7 @@ export type PgMacaddr8BuilderInitial = PgMacaddr8Builder<{ }>; export class PgMacaddr8Builder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgMacaddr8Builder'; + static override readonly [entityKind]: string = 'PgMacaddr8Builder'; constructor(name: T['name']) { super(name, 'string', 'PgMacaddr8'); @@ -30,7 +30,7 @@ export class PgMacaddr8Builder> extends PgColumn { - static readonly [entityKind]: string = 'PgMacaddr8'; + static override readonly [entityKind]: string = 'PgMacaddr8'; getSQLType(): string { return 'macaddr8'; diff --git a/drizzle-orm/src/pg-core/columns/numeric.ts b/drizzle-orm/src/pg-core/columns/numeric.ts index a661df21e..efeb4ab97 100644 --- a/drizzle-orm/src/pg-core/columns/numeric.ts +++ b/drizzle-orm/src/pg-core/columns/numeric.ts @@ -22,7 +22,7 @@ export class PgNumericBuilder { - static readonly [entityKind]: string = 'PgNumericBuilder'; + static override readonly [entityKind]: string = 'PgNumericBuilder'; constructor(name: T['name'], precision?: number, scale?: number) { super(name, 'string', 'PgNumeric'); @@ -39,7 +39,7 @@ export class PgNumericBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgNumeric'; + static override readonly [entityKind]: string = 'PgNumeric'; readonly precision: number | undefined; readonly scale: number | undefined; diff --git a/drizzle-orm/src/pg-core/columns/point.ts b/drizzle-orm/src/pg-core/columns/point.ts index 584e395f9..827579ad8 100644 --- a/drizzle-orm/src/pg-core/columns/point.ts +++ b/drizzle-orm/src/pg-core/columns/point.ts @@ -19,7 +19,7 @@ export type PgPointTupleBuilderInitial = PgPointTupleBuild export class PgPointTupleBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgPointTupleBuilder'; + static override readonly [entityKind]: string = 'PgPointTupleBuilder'; constructor(name: string) { super(name, 'array', 'PgPointTuple'); @@ -37,7 +37,7 @@ export class PgPointTupleBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgPointTuple'; + static override readonly [entityKind]: string = 'PgPointTuple'; getSQLType(): string { return 'point'; @@ -69,7 +69,7 @@ export type PgPointObjectBuilderInitial = PgPointObjectBui export class PgPointObjectBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgPointObjectBuilder'; + static override readonly [entityKind]: string = 'PgPointObjectBuilder'; constructor(name: string) { super(name, 'json', 'PgPointObject'); @@ -87,7 +87,7 @@ export class PgPointObjectBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgPointObject'; + static override readonly [entityKind]: string = 'PgPointObject'; getSQLType(): string { return 'point'; diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts index 18e6c946d..853c3dff9 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts @@ -18,7 +18,7 @@ export type PgGeometryBuilderInitial = PgGeometryBuilder<{ }>; export class PgGeometryBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgGeometryBuilder'; + static override readonly [entityKind]: string = 'PgGeometryBuilder'; constructor(name: T['name']) { super(name, 'array', 'PgGeometry'); @@ -36,7 +36,7 @@ export class PgGeometryBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgGeometry'; + static override readonly [entityKind]: string = 'PgGeometry'; getSQLType(): string { return 'geometry(point)'; @@ -64,7 +64,7 @@ export type PgGeometryObjectBuilderInitial = PgGeometryObj export class PgGeometryObjectBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgGeometryObjectBuilder'; + static override readonly [entityKind]: string = 'PgGeometryObjectBuilder'; constructor(name: T['name']) { super(name, 'json', 'PgGeometryObject'); @@ -82,7 +82,7 @@ export class PgGeometryObjectBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgGeometryObject'; + static override readonly [entityKind]: string = 'PgGeometryObject'; getSQLType(): string { return 'geometry(point)'; diff --git a/drizzle-orm/src/pg-core/columns/real.ts b/drizzle-orm/src/pg-core/columns/real.ts index f39527a45..0e3de4b2e 100644 --- a/drizzle-orm/src/pg-core/columns/real.ts +++ b/drizzle-orm/src/pg-core/columns/real.ts @@ -18,7 +18,7 @@ export class PgRealBuilder T, { length: number | undefined } > { - static readonly [entityKind]: string = 'PgRealBuilder'; + static override readonly [entityKind]: string = 'PgRealBuilder'; constructor(name: T['name'], length?: number) { super(name, 'number', 'PgReal'); @@ -34,7 +34,7 @@ export class PgRealBuilder } export class PgReal> extends PgColumn { - static readonly [entityKind]: string = 'PgReal'; + static override readonly [entityKind]: string = 'PgReal'; constructor(table: AnyPgTable<{ name: T['tableName'] }>, config: PgRealBuilder['config']) { super(table, config); diff --git a/drizzle-orm/src/pg-core/columns/serial.ts b/drizzle-orm/src/pg-core/columns/serial.ts index a4d7f8e30..6a0196c38 100644 --- a/drizzle-orm/src/pg-core/columns/serial.ts +++ b/drizzle-orm/src/pg-core/columns/serial.ts @@ -25,7 +25,7 @@ export type PgSerialBuilderInitial = NotNull< >; export class PgSerialBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgSerialBuilder'; + static override readonly [entityKind]: string = 'PgSerialBuilder'; constructor(name: T['name']) { super(name, 'number', 'PgSerial'); @@ -42,7 +42,7 @@ export class PgSerialBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgSerial'; + static override readonly [entityKind]: string = 'PgSerial'; getSQLType(): string { return 'serial'; diff --git a/drizzle-orm/src/pg-core/columns/smallint.ts b/drizzle-orm/src/pg-core/columns/smallint.ts index 20204cd3c..1cdfe141f 100644 --- a/drizzle-orm/src/pg-core/columns/smallint.ts +++ b/drizzle-orm/src/pg-core/columns/smallint.ts @@ -18,7 +18,7 @@ export type PgSmallIntBuilderInitial = PgSmallIntBuilder<{ export class PgSmallIntBuilder> extends PgIntColumnBaseBuilder { - static readonly [entityKind]: string = 'PgSmallIntBuilder'; + static override readonly [entityKind]: string = 'PgSmallIntBuilder'; constructor(name: T['name']) { super(name, 'number', 'PgSmallInt'); @@ -33,7 +33,7 @@ export class PgSmallIntBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgSmallInt'; + static override readonly [entityKind]: string = 'PgSmallInt'; getSQLType(): string { return 'smallint'; diff --git a/drizzle-orm/src/pg-core/columns/smallserial.ts b/drizzle-orm/src/pg-core/columns/smallserial.ts index ec2204034..456dc47f7 100644 --- a/drizzle-orm/src/pg-core/columns/smallserial.ts +++ b/drizzle-orm/src/pg-core/columns/smallserial.ts @@ -27,7 +27,7 @@ export type PgSmallSerialBuilderInitial = NotNull< export class PgSmallSerialBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgSmallSerialBuilder'; + static override readonly [entityKind]: string = 'PgSmallSerialBuilder'; constructor(name: T['name']) { super(name, 'number', 'PgSmallSerial'); @@ -47,7 +47,7 @@ export class PgSmallSerialBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgSmallSerial'; + static override readonly [entityKind]: string = 'PgSmallSerial'; getSQLType(): string { return 'smallserial'; diff --git a/drizzle-orm/src/pg-core/columns/text.ts b/drizzle-orm/src/pg-core/columns/text.ts index 522135e5c..6845f0e74 100644 --- a/drizzle-orm/src/pg-core/columns/text.ts +++ b/drizzle-orm/src/pg-core/columns/text.ts @@ -18,7 +18,7 @@ type PgTextBuilderInitial, > extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgTextBuilder'; + static override readonly [entityKind]: string = 'PgTextBuilder'; constructor( name: T['name'], @@ -39,7 +39,7 @@ export class PgTextBuilder< export class PgText> extends PgColumn { - static readonly [entityKind]: string = 'PgText'; + static override readonly [entityKind]: string = 'PgText'; override readonly enumValues = this.config.enumValues; diff --git a/drizzle-orm/src/pg-core/columns/time.ts b/drizzle-orm/src/pg-core/columns/time.ts index e2b29f1f7..9b3ff51e0 100644 --- a/drizzle-orm/src/pg-core/columns/time.ts +++ b/drizzle-orm/src/pg-core/columns/time.ts @@ -21,7 +21,7 @@ export class PgTimeBuilder T, { withTimezone: boolean; precision: number | undefined } > { - static readonly [entityKind]: string = 'PgTimeBuilder'; + static override readonly [entityKind]: string = 'PgTimeBuilder'; constructor( name: T['name'], @@ -42,7 +42,7 @@ export class PgTimeBuilder } export class PgTime> extends PgColumn { - static readonly [entityKind]: string = 'PgTime'; + static override readonly [entityKind]: string = 'PgTime'; readonly withTimezone: boolean; readonly precision: number | undefined; diff --git a/drizzle-orm/src/pg-core/columns/timestamp.ts b/drizzle-orm/src/pg-core/columns/timestamp.ts index 08474bf68..6879106e0 100644 --- a/drizzle-orm/src/pg-core/columns/timestamp.ts +++ b/drizzle-orm/src/pg-core/columns/timestamp.ts @@ -22,7 +22,7 @@ export class PgTimestampBuilder { - static readonly [entityKind]: string = 'PgTimestampBuilder'; + static override readonly [entityKind]: string = 'PgTimestampBuilder'; constructor( name: T['name'], @@ -43,7 +43,7 @@ export class PgTimestampBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgTimestamp'; + static override readonly [entityKind]: string = 'PgTimestamp'; readonly withTimezone: boolean; readonly precision: number | undefined; @@ -84,7 +84,7 @@ export class PgTimestampStringBuilder { - static readonly [entityKind]: string = 'PgTimestampStringBuilder'; + static override readonly [entityKind]: string = 'PgTimestampStringBuilder'; constructor( name: T['name'], @@ -108,7 +108,7 @@ export class PgTimestampStringBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgTimestampString'; + static override readonly [entityKind]: string = 'PgTimestampString'; readonly withTimezone: boolean; readonly precision: number | undefined; diff --git a/drizzle-orm/src/pg-core/columns/uuid.ts b/drizzle-orm/src/pg-core/columns/uuid.ts index 851036d8d..d0e5a6830 100644 --- a/drizzle-orm/src/pg-core/columns/uuid.ts +++ b/drizzle-orm/src/pg-core/columns/uuid.ts @@ -16,7 +16,7 @@ export type PgUUIDBuilderInitial = PgUUIDBuilder<{ }>; export class PgUUIDBuilder> extends PgColumnBuilder { - static readonly [entityKind]: string = 'PgUUIDBuilder'; + static override readonly [entityKind]: string = 'PgUUIDBuilder'; constructor(name: T['name']) { super(name, 'string', 'PgUUID'); @@ -38,7 +38,7 @@ export class PgUUIDBuilder } export class PgUUID> extends PgColumn { - static readonly [entityKind]: string = 'PgUUID'; + static override readonly [entityKind]: string = 'PgUUID'; getSQLType(): string { return 'uuid'; diff --git a/drizzle-orm/src/pg-core/columns/varchar.ts b/drizzle-orm/src/pg-core/columns/varchar.ts index bc9d1b160..78ee0db96 100644 --- a/drizzle-orm/src/pg-core/columns/varchar.ts +++ b/drizzle-orm/src/pg-core/columns/varchar.ts @@ -19,7 +19,7 @@ export class PgVarcharBuilder { - static readonly [entityKind]: string = 'PgVarcharBuilder'; + static override readonly [entityKind]: string = 'PgVarcharBuilder'; constructor(name: T['name'], config: PgVarcharConfig) { super(name, 'string', 'PgVarchar'); @@ -38,7 +38,7 @@ export class PgVarcharBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgVarchar'; + static override readonly [entityKind]: string = 'PgVarchar'; readonly length = this.config.length; override readonly enumValues = this.config.enumValues; diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts index a841c28e5..81eea6b2f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts @@ -21,7 +21,7 @@ export class PgBinaryVectorBuilder { - static readonly [entityKind]: string = 'PgBinaryVectorBuilder'; + static override readonly [entityKind]: string = 'PgBinaryVectorBuilder'; constructor(name: string, config: PgBinaryVectorConfig) { super(name, 'string', 'PgBinaryVector'); @@ -42,7 +42,7 @@ export class PgBinaryVectorBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgBinaryVector'; + static override readonly [entityKind]: string = 'PgBinaryVector'; readonly dimensions = this.config.dimensions; diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts index 7218f8114..e12d0d22f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts @@ -19,7 +19,7 @@ export class PgHalfVectorBuilder { - static readonly [entityKind]: string = 'PgHalfVectorBuilder'; + static override readonly [entityKind]: string = 'PgHalfVectorBuilder'; constructor(name: string, config: PgHalfVectorConfig) { super(name, 'array', 'PgHalfVector'); @@ -40,7 +40,7 @@ export class PgHalfVectorBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgHalfVector'; + static override readonly [entityKind]: string = 'PgHalfVector'; readonly dimensions = this.config.dimensions; diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts index 2bdbf1ac3..3881b338f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts @@ -21,7 +21,7 @@ export class PgSparseVectorBuilder { - static readonly [entityKind]: string = 'PgSparseVectorBuilder'; + static override readonly [entityKind]: string = 'PgSparseVectorBuilder'; constructor(name: string, config: PgSparseVectorConfig) { super(name, 'string', 'PgSparseVector'); @@ -42,7 +42,7 @@ export class PgSparseVectorBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgSparseVector'; + static override readonly [entityKind]: string = 'PgSparseVector'; readonly dimensions = this.config.dimensions; diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts index b6ad9caff..eaac075dc 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts @@ -19,7 +19,7 @@ export class PgVectorBuilder { - static readonly [entityKind]: string = 'PgVectorBuilder'; + static override readonly [entityKind]: string = 'PgVectorBuilder'; constructor(name: string, config: PgVectorConfig) { super(name, 'array', 'PgVector'); @@ -37,7 +37,7 @@ export class PgVectorBuilder> extends PgColumn { - static readonly [entityKind]: string = 'PgVector'; + static override readonly [entityKind]: string = 'PgVector'; readonly dimensions = this.config.dimensions; diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index c823f7c6f..af16fda01 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -8,7 +8,7 @@ export class PgCountBuilder< > extends SQL implements Promise, SQLWrapper { private sql: SQL; - static readonly [entityKind] = 'PgCountBuilder'; + static override readonly [entityKind] = 'PgCountBuilder'; [Symbol.toStringTag] = 'PgCountBuilder'; private session: TSession; diff --git a/drizzle-orm/src/pg-core/query-builders/delete.ts b/drizzle-orm/src/pg-core/query-builders/delete.ts index dc127f167..b42d46711 100644 --- a/drizzle-orm/src/pg-core/query-builders/delete.ts +++ b/drizzle-orm/src/pg-core/query-builders/delete.ts @@ -128,7 +128,7 @@ export class PgDeleteBase< RunnableQuery : TReturning[], 'pg'>, SQLWrapper { - static readonly [entityKind]: string = 'PgDelete'; + static override readonly [entityKind]: string = 'PgDelete'; private config: PgDeleteConfig; diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index 02bcb972c..9f494ab50 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -166,7 +166,7 @@ export class PgInsertBase< RunnableQuery : TReturning[], 'pg'>, SQLWrapper { - static readonly [entityKind]: string = 'PgInsert'; + static override readonly [entityKind]: string = 'PgInsert'; private config: PgInsertConfig; diff --git a/drizzle-orm/src/pg-core/query-builders/query.ts b/drizzle-orm/src/pg-core/query-builders/query.ts index 17cea6cff..07f485669 100644 --- a/drizzle-orm/src/pg-core/query-builders/query.ts +++ b/drizzle-orm/src/pg-core/query-builders/query.ts @@ -65,7 +65,7 @@ export class RelationalQueryBuilder extends QueryPromise implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'PgRelationalQuery'; + static override readonly [entityKind]: string = 'PgRelationalQuery'; declare readonly _: { readonly dialect: 'pg'; diff --git a/drizzle-orm/src/pg-core/query-builders/raw.ts b/drizzle-orm/src/pg-core/query-builders/raw.ts index 871581dfb..d08c1ee14 100644 --- a/drizzle-orm/src/pg-core/query-builders/raw.ts +++ b/drizzle-orm/src/pg-core/query-builders/raw.ts @@ -9,7 +9,7 @@ export interface PgRaw extends QueryPromise, RunnableQuery extends QueryPromise implements RunnableQuery, SQLWrapper, PreparedQuery { - static readonly [entityKind]: string = 'PgRaw'; + static override readonly [entityKind]: string = 'PgRaw'; declare readonly _: { readonly dialect: 'pg'; diff --git a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts index d2bedac68..62ade9139 100644 --- a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts +++ b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts @@ -30,7 +30,7 @@ export class PgRefreshMaterializedView extends QueryPromise> implements RunnableQuery, 'pg'>, SQLWrapper { - static readonly [entityKind]: string = 'PgRefreshMaterializedView'; + static override readonly [entityKind]: string = 'PgRefreshMaterializedView'; private config: { view: PgMaterializedView; diff --git a/drizzle-orm/src/pg-core/query-builders/select.ts b/drizzle-orm/src/pg-core/query-builders/select.ts index d2406995b..6e9a961c0 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.ts @@ -139,7 +139,7 @@ export abstract class PgSelectQueryBuilderBase< TResult extends any[] = SelectResult[], TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > extends TypedQueryBuilder { - static readonly [entityKind]: string = 'PgSelectQueryBuilder'; + static override readonly [entityKind]: string = 'PgSelectQueryBuilder'; override readonly _: { readonly dialect: 'pg'; @@ -947,7 +947,7 @@ export class PgSelectBase< TResult, TSelectedFields > implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'PgSelect'; + static override readonly [entityKind]: string = 'PgSelect'; /** @internal */ _prepare(name?: string): PgSelectPrepare { diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index ec404ac22..2c63dacc0 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -159,7 +159,7 @@ export class PgUpdateBase< RunnableQuery : TReturning[], 'pg'>, SQLWrapper { - static readonly [entityKind]: string = 'PgUpdate'; + static override readonly [entityKind]: string = 'PgUpdate'; private config: PgUpdateConfig; diff --git a/drizzle-orm/src/pg-core/session.ts b/drizzle-orm/src/pg-core/session.ts index ea820f2d8..d909e82db 100644 --- a/drizzle-orm/src/pg-core/session.ts +++ b/drizzle-orm/src/pg-core/session.ts @@ -105,7 +105,7 @@ export abstract class PgTransaction< TFullSchema extends Record = Record, TSchema extends TablesRelationalConfig = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'PgTransaction'; + static override readonly [entityKind]: string = 'PgTransaction'; constructor( dialect: PgDialect, diff --git a/drizzle-orm/src/pg-core/table.ts b/drizzle-orm/src/pg-core/table.ts index c09a56233..5bf9a9895 100644 --- a/drizzle-orm/src/pg-core/table.ts +++ b/drizzle-orm/src/pg-core/table.ts @@ -24,7 +24,7 @@ export type TableConfig = TableConfigBase; export const InlineForeignKeys = Symbol.for('drizzle:PgInlineForeignKeys'); export class PgTable extends Table { - static readonly [entityKind]: string = 'PgTable'; + static override readonly [entityKind]: string = 'PgTable'; /** @internal */ static override readonly Symbol = Object.assign({}, Table.Symbol, { diff --git a/drizzle-orm/src/pg-core/view-base.ts b/drizzle-orm/src/pg-core/view-base.ts index 87f76ac24..d3f52a501 100644 --- a/drizzle-orm/src/pg-core/view-base.ts +++ b/drizzle-orm/src/pg-core/view-base.ts @@ -6,7 +6,7 @@ export abstract class PgViewBase< TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, > extends View { - static readonly [entityKind]: string = 'PgViewBase'; + static override readonly [entityKind]: string = 'PgViewBase'; declare readonly _: View['_'] & { readonly viewBrand: 'PgViewBase'; diff --git a/drizzle-orm/src/pg-core/view.ts b/drizzle-orm/src/pg-core/view.ts index 22c510dce..2f88d7e17 100644 --- a/drizzle-orm/src/pg-core/view.ts +++ b/drizzle-orm/src/pg-core/view.ts @@ -1,10 +1,11 @@ import type { BuildColumns } from '~/column-builder.ts'; -import { entityKind } from '~/entity.ts'; +import { entityKind, is } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; import type { ColumnsSelection, SQL } from '~/sql/sql.ts'; import { getTableColumns } from '~/utils.ts'; +import type { RequireAtLeastOne } from '~/utils.ts'; import type { PgColumn, PgColumnBuilderBase } from './columns/common.ts'; import { QueryBuilder } from './query-builders/query-builder.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; @@ -12,11 +13,11 @@ import { pgTable } from './table.ts'; import { PgViewBase } from './view-base.ts'; import { PgViewConfig } from './view-common.ts'; -export interface ViewWithConfig { +export type ViewWithConfig = RequireAtLeastOne<{ checkOption: 'local' | 'cascaded'; securityBarrier: boolean; securityInvoker: boolean; -} +}>; export class DefaultViewBuilderCore { static readonly [entityKind]: string = 'PgDefaultViewBuilderCore'; @@ -42,7 +43,7 @@ export class DefaultViewBuilderCore extends DefaultViewBuilderCore<{ name: TName }> { - static readonly [entityKind]: string = 'PgViewBuilder'; + static override readonly [entityKind]: string = 'PgViewBuilder'; as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), @@ -76,7 +77,7 @@ export class ManualViewBuilder< TName extends string = string, TColumns extends Record = Record, > extends DefaultViewBuilderCore<{ name: TName; columns: TColumns }> { - static readonly [entityKind]: string = 'PgManualViewBuilder'; + static override readonly [entityKind]: string = 'PgManualViewBuilder'; private columns: Record; @@ -130,9 +131,26 @@ export class ManualViewBuilder< } } -export interface PgMaterializedViewWithConfig { - [Key: string]: string | number | boolean | SQL; -} +export type PgMaterializedViewWithConfig = RequireAtLeastOne<{ + fillfactor: number; + toastTupleTarget: number; + parallelWorkers: number; + autovacuumEnabled: boolean; + vacuumIndexCleanup: 'auto' | 'off' | 'on'; + vacuumTruncate: boolean; + autovacuumVacuumThreshold: number; + autovacuumVacuumScaleFactor: number; + autovacuumVacuumCostDelay: number; + autovacuumVacuumCostLimit: number; + autovacuumFreezeMinAge: number; + autovacuumFreezeMaxAge: number; + autovacuumFreezeTableAge: number; + autovacuumMultixactFreezeMinAge: number; + autovacuumMultixactFreezeMaxAge: number; + autovacuumMultixactFreezeTableAge: number; + logAutovacuumMinDuration: number; + userCatalogTable: boolean; +}>; export class MaterializedViewBuilderCore { static readonly [entityKind]: string = 'PgMaterializedViewBuilderCore'; @@ -178,7 +196,7 @@ export class MaterializedViewBuilderCore extends MaterializedViewBuilderCore<{ name: TName }> { - static readonly [entityKind]: string = 'PgMaterializedViewBuilder'; + static override readonly [entityKind]: string = 'PgMaterializedViewBuilder'; as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), @@ -217,7 +235,7 @@ export class ManualMaterializedViewBuilder< TName extends string = string, TColumns extends Record = Record, > extends MaterializedViewBuilderCore<{ name: TName; columns: TColumns }> { - static readonly [entityKind]: string = 'PgManualMaterializedViewBuilder'; + static override readonly [entityKind]: string = 'PgManualMaterializedViewBuilder'; private columns: Record; @@ -233,7 +251,12 @@ export class ManualMaterializedViewBuilder< existing(): PgMaterializedViewWithSelection> { return new Proxy( new PgMaterializedView({ - pgConfig: undefined, + pgConfig: { + tablespace: this.config.tablespace, + using: this.config.using, + with: this.config.with, + withNoData: this.config.withNoData, + }, config: { name: this.name, schema: this.schema, @@ -253,7 +276,12 @@ export class ManualMaterializedViewBuilder< as(query: SQL): PgMaterializedViewWithSelection> { return new Proxy( new PgMaterializedView({ - pgConfig: undefined, + pgConfig: { + tablespace: this.config.tablespace, + using: this.config.using, + with: this.config.with, + withNoData: this.config.withNoData, + }, config: { name: this.name, schema: this.schema, @@ -276,7 +304,7 @@ export class PgView< TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, > extends PgViewBase { - static readonly [entityKind]: string = 'PgView'; + static override readonly [entityKind]: string = 'PgView'; [PgViewConfig]: { with?: ViewWithConfig; @@ -315,7 +343,7 @@ export class PgMaterializedView< TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection, > extends PgViewBase { - static readonly [entityKind]: string = 'PgMaterializedView'; + static override readonly [entityKind]: string = 'PgMaterializedView'; readonly [PgMaterializedViewConfig]: { readonly with?: PgMaterializedViewWithConfig; @@ -398,3 +426,11 @@ export function pgMaterializedView( ): MaterializedViewBuilder | ManualMaterializedViewBuilder { return pgMaterializedViewWithSchema(name, columns, undefined); } + +export function isPgView(obj: unknown): obj is PgView { + return is(obj, PgView); +} + +export function isPgMaterializedView(obj: unknown): obj is PgMaterializedView { + return is(obj, PgMaterializedView); +} diff --git a/drizzle-orm/src/pg-proxy/driver.ts b/drizzle-orm/src/pg-proxy/driver.ts index 8ccd9ba02..955dc2bb4 100644 --- a/drizzle-orm/src/pg-proxy/driver.ts +++ b/drizzle-orm/src/pg-proxy/driver.ts @@ -14,7 +14,7 @@ import { type PgRemoteQueryResultHKT, PgRemoteSession } from './session.ts'; export class PgRemoteDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'PgRemoteDatabase'; + static override readonly [entityKind]: string = 'PgRemoteDatabase'; } export type RemoteCallback = ( diff --git a/drizzle-orm/src/pg-proxy/session.ts b/drizzle-orm/src/pg-proxy/session.ts index 1a30c0a3c..9d433502c 100644 --- a/drizzle-orm/src/pg-proxy/session.ts +++ b/drizzle-orm/src/pg-proxy/session.ts @@ -21,7 +21,7 @@ export class PgRemoteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'PgRemoteSession'; + static override readonly [entityKind]: string = 'PgRemoteSession'; private logger: Logger; @@ -66,7 +66,7 @@ export class PgProxyTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'PgProxyTransaction'; + static override readonly [entityKind]: string = 'PgProxyTransaction'; override async transaction( _transaction: (tx: PgProxyTransaction) => Promise, @@ -76,7 +76,7 @@ export class PgProxyTransaction< } export class PreparedQuery extends PreparedQueryBase { - static readonly [entityKind]: string = 'PgProxyPreparedQuery'; + static override readonly [entityKind]: string = 'PgProxyPreparedQuery'; constructor( private client: RemoteCallback, diff --git a/drizzle-orm/src/pglite/driver.ts b/drizzle-orm/src/pglite/driver.ts index b6cb8bd7e..89d37d1f9 100644 --- a/drizzle-orm/src/pglite/driver.ts +++ b/drizzle-orm/src/pglite/driver.ts @@ -1,3 +1,4 @@ +import { PGlite, type PGliteOptions } from '@electric-sql/pglite'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -9,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { PgliteClient, PgliteQueryResultHKT } from './session.ts'; import { PgliteSession } from './session.ts'; @@ -37,10 +38,10 @@ export class PgliteDriver { export class PgliteDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'PgliteDatabase'; + static override readonly [entityKind]: string = 'PgliteDatabase'; } -export function drizzle = Record>( +function construct = Record>( client: PgliteClient, config: DrizzleConfig = {}, ): PgliteDatabase & { @@ -74,3 +75,72 @@ export function drizzle = Record = Record, + TClient extends PGlite = PGlite, +>( + ...params: IfNotImported< + PGlite, + [ImportTypeError<'@electric-sql/pglite'>], + | [] + | [ + TClient | string, + ] + | [ + TClient | string, + DrizzleConfig, + ] + | [ + ( + & DrizzleConfig + & ({ + connection?: (PGliteOptions & { dataDir?: string }) | string; + } | { + client: TClient; + }) + ), + ] + > +): PgliteDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof PGlite) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, client, ...drizzleConfig } = params[0] as { + connection?: PGliteOptions & { dataDir: string }; + client?: TClient; + } & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + if (typeof connection === 'object') { + const { dataDir, ...options } = connection; + + const instance = new PGlite(dataDir, options); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new PGlite(connection); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new PGlite(params[0]); + return construct(instance, params[1]) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): PgliteDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/pglite/session.ts b/drizzle-orm/src/pglite/session.ts index ebf7701a6..18c341fc6 100644 --- a/drizzle-orm/src/pglite/session.ts +++ b/drizzle-orm/src/pglite/session.ts @@ -15,7 +15,7 @@ import { types } from '@electric-sql/pglite'; export type PgliteClient = PGlite; export class PglitePreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'PglitePreparedQuery'; + static override readonly [entityKind]: string = 'PglitePreparedQuery'; private rawQueryConfig: QueryOptions; private queryConfig: QueryOptions; @@ -89,7 +89,7 @@ export class PgliteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'PgliteSession'; + static override readonly [entityKind]: string = 'PgliteSession'; private logger: Logger; @@ -153,7 +153,7 @@ export class PgliteTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'PgliteTransaction'; + static override readonly [entityKind]: string = 'PgliteTransaction'; override async transaction(transaction: (tx: PgliteTransaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex + 1}`; diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index 2b851f75b..1865673bf 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -1,4 +1,4 @@ -import type { Connection } from '@planetscale/database'; +import type { Config, Connection } from '@planetscale/database'; import { Client } from '@planetscale/database'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; @@ -11,7 +11,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { PlanetScalePreparedQueryHKT, PlanetscaleQueryResultHKT } from './session.ts'; import { PlanetscaleSession } from './session.ts'; @@ -22,10 +22,10 @@ export interface PlanetscaleSDriverOptions { export class PlanetScaleDatabase< TSchema extends Record = Record, > extends MySqlDatabase { - static readonly [entityKind]: string = 'PlanetScaleDatabase'; + static override readonly [entityKind]: string = 'PlanetScaleDatabase'; } -export function drizzle< +function construct< TSchema extends Record = Record, TClient extends Client | Connection = Client | Connection, >( @@ -95,3 +95,69 @@ Starting from version 0.30.0, you will encounter an error if you attempt to use return db as any; } + +export function drizzle< + TSchema extends Record = Record, + TClient extends Client = Client, +>( + ...params: IfNotImported< + Config, + [ImportTypeError<'@planetscale/database'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] + > +): PlanetScaleDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof Client) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config | string; client?: TClient } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' + ? new Client({ + url: connection, + }) + : new Client( + connection!, + ); + + return construct(instance, drizzleConfig) as any; + } + + const instance = new Client({ + url: params[0], + }); + + return construct(instance, params[1]) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): PlanetScaleDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/planetscale-serverless/session.ts b/drizzle-orm/src/planetscale-serverless/session.ts index 987529d7c..4e6a0f432 100644 --- a/drizzle-orm/src/planetscale-serverless/session.ts +++ b/drizzle-orm/src/planetscale-serverless/session.ts @@ -18,7 +18,7 @@ import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; export class PlanetScalePreparedQuery extends MySqlPreparedQuery { - static readonly [entityKind]: string = 'PlanetScalePreparedQuery'; + static override readonly [entityKind]: string = 'PlanetScalePreparedQuery'; private rawQuery = { as: 'object' } as const; private query = { as: 'array' } as const; @@ -106,7 +106,7 @@ export class PlanetscaleSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlSession { - static readonly [entityKind]: string = 'PlanetscaleSession'; + static override readonly [entityKind]: string = 'PlanetscaleSession'; private logger: Logger; private client: Client | Transaction | Connection; @@ -191,7 +191,7 @@ export class PlanetScaleTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlTransaction { - static readonly [entityKind]: string = 'PlanetScaleTransaction'; + static override readonly [entityKind]: string = 'PlanetScaleTransaction'; constructor( dialect: MySqlDialect, diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index 641e413d0..5c2979c84 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -1,4 +1,4 @@ -import type { Sql } from 'postgres'; +import pgClient, { type Options, type PostgresType, type Sql } from 'postgres'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { PgDatabase } from '~/pg-core/db.ts'; @@ -9,17 +9,17 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { PostgresJsQueryResultHKT } from './session.ts'; import { PostgresJsSession } from './session.ts'; export class PostgresJsDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'PostgresJsDatabase'; + static override readonly [entityKind]: string = 'PostgresJsDatabase'; } -export function drizzle = Record>( +function construct = Record>( client: Sql, config: DrizzleConfig = {}, ): PostgresJsDatabase & { @@ -62,3 +62,67 @@ export function drizzle = Record = Record, + TClient extends Sql = Sql, +>( + ...params: IfNotImported< + Options, + [ImportTypeError<'postgres'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | ({ url?: string } & Options>); + } | { + client: TClient; + }) + ), + ] + > +): PostgresJsDatabase & { + $client: TClient; +} { + if (typeof params[0] === 'function') { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'object') { + const { connection, client, ...drizzleConfig } = params[0] as { + connection?: { url?: string } & Options>; + client?: TClient; + } & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + if (typeof connection === 'object' && connection.url !== undefined) { + const { url, ...config } = connection; + + const instance = pgClient(url, config); + return construct(instance, drizzleConfig) as any; + } + + const instance = pgClient(connection); + return construct(instance, drizzleConfig) as any; + } + + const instance = pgClient(params[0] as string); + + return construct(instance, params[1]) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): PostgresJsDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/postgres-js/session.ts b/drizzle-orm/src/postgres-js/session.ts index 05179ebdb..7509e2a00 100644 --- a/drizzle-orm/src/postgres-js/session.ts +++ b/drizzle-orm/src/postgres-js/session.ts @@ -13,7 +13,7 @@ import { tracer } from '~/tracing.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; export class PostgresJsPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'PostgresJsPreparedQuery'; + static override readonly [entityKind]: string = 'PostgresJsPreparedQuery'; constructor( private client: Sql, @@ -95,7 +95,7 @@ export class PostgresJsSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'PostgresJsSession'; + static override readonly [entityKind]: string = 'PostgresJsSession'; logger: Logger; @@ -164,7 +164,7 @@ export class PostgresJsTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'PostgresJsTransaction'; + static override readonly [entityKind]: string = 'PostgresJsTransaction'; constructor( dialect: PgDialect, diff --git a/drizzle-orm/src/prisma/mysql/driver.ts b/drizzle-orm/src/prisma/mysql/driver.ts index 586832948..c6ca143df 100644 --- a/drizzle-orm/src/prisma/mysql/driver.ts +++ b/drizzle-orm/src/prisma/mysql/driver.ts @@ -13,7 +13,7 @@ import { PrismaMySqlSession } from './session.ts'; export class PrismaMySqlDatabase extends MySqlDatabase> { - static readonly [entityKind]: string = 'PrismaMySqlDatabase'; + static override readonly [entityKind]: string = 'PrismaMySqlDatabase'; constructor(client: PrismaClient, logger: Logger | undefined) { const dialect = new MySqlDialect(); diff --git a/drizzle-orm/src/prisma/mysql/session.ts b/drizzle-orm/src/prisma/mysql/session.ts index a6b12a0c3..fc3807bc5 100644 --- a/drizzle-orm/src/prisma/mysql/session.ts +++ b/drizzle-orm/src/prisma/mysql/session.ts @@ -19,7 +19,7 @@ export class PrismaMySqlPreparedQuery extends MySqlPreparedQuery | undefined): AsyncGenerator { throw new Error('Method not implemented.'); } - static readonly [entityKind]: string = 'PrismaMySqlPreparedQuery'; + static override readonly [entityKind]: string = 'PrismaMySqlPreparedQuery'; constructor( private readonly prisma: PrismaClient, @@ -41,7 +41,7 @@ export interface PrismaMySqlSessionOptions { } export class PrismaMySqlSession extends MySqlSession { - static readonly [entityKind]: string = 'PrismaMySqlSession'; + static override readonly [entityKind]: string = 'PrismaMySqlSession'; private readonly logger: Logger; diff --git a/drizzle-orm/src/prisma/pg/driver.ts b/drizzle-orm/src/prisma/pg/driver.ts index 23678f09f..f9038d8a1 100644 --- a/drizzle-orm/src/prisma/pg/driver.ts +++ b/drizzle-orm/src/prisma/pg/driver.ts @@ -11,7 +11,7 @@ import type { PrismaPgQueryResultHKT } from './session.ts'; import { PrismaPgSession } from './session.ts'; export class PrismaPgDatabase extends PgDatabase> { - static readonly [entityKind]: string = 'PrismaPgDatabase'; + static override readonly [entityKind]: string = 'PrismaPgDatabase'; constructor(client: PrismaClient, logger: Logger | undefined) { const dialect = new PgDialect(); diff --git a/drizzle-orm/src/prisma/pg/session.ts b/drizzle-orm/src/prisma/pg/session.ts index 077326ef3..b93f6f14b 100644 --- a/drizzle-orm/src/prisma/pg/session.ts +++ b/drizzle-orm/src/prisma/pg/session.ts @@ -14,7 +14,7 @@ import type { Query, SQL } from '~/sql/sql.ts'; import { fillPlaceholders } from '~/sql/sql.ts'; export class PrismaPgPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'PrismaPgPreparedQuery'; + static override readonly [entityKind]: string = 'PrismaPgPreparedQuery'; constructor( private readonly prisma: PrismaClient, @@ -44,7 +44,7 @@ export interface PrismaPgSessionOptions { } export class PrismaPgSession extends PgSession { - static readonly [entityKind]: string = 'PrismaPgSession'; + static override readonly [entityKind]: string = 'PrismaPgSession'; private readonly logger: Logger; diff --git a/drizzle-orm/src/prisma/sqlite/session.ts b/drizzle-orm/src/prisma/sqlite/session.ts index 3dbdc6f1a..3a10fddbd 100644 --- a/drizzle-orm/src/prisma/sqlite/session.ts +++ b/drizzle-orm/src/prisma/sqlite/session.ts @@ -19,7 +19,7 @@ type PreparedQueryConfig = Omit; export class PrismaSQLitePreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: []; all: T['all']; get: T['get']; values: never; execute: T['execute'] } > { - static readonly [entityKind]: string = 'PrismaSQLitePreparedQuery'; + static override readonly [entityKind]: string = 'PrismaSQLitePreparedQuery'; constructor( private readonly prisma: PrismaClient, @@ -60,7 +60,7 @@ export interface PrismaSQLiteSessionOptions { } export class PrismaSQLiteSession extends SQLiteSession<'async', unknown, Record, Record> { - static readonly [entityKind]: string = 'PrismaSQLiteSession'; + static override readonly [entityKind]: string = 'PrismaSQLiteSession'; private readonly logger: Logger; diff --git a/drizzle-orm/src/relations.ts b/drizzle-orm/src/relations.ts index 99780897e..ed49c138f 100644 --- a/drizzle-orm/src/relations.ts +++ b/drizzle-orm/src/relations.ts @@ -66,7 +66,7 @@ export class One< TTableName extends string = string, TIsNullable extends boolean = boolean, > extends Relation { - static readonly [entityKind]: string = 'One'; + static override readonly [entityKind]: string = 'One'; declare protected $relationBrand: 'One'; @@ -98,7 +98,7 @@ export class One< } export class Many extends Relation { - static readonly [entityKind]: string = 'Many'; + static override readonly [entityKind]: string = 'Many'; declare protected $relationBrand: 'Many'; diff --git a/drizzle-orm/src/sql-js/session.ts b/drizzle-orm/src/sql-js/session.ts index 4325cd13f..0a09babbd 100644 --- a/drizzle-orm/src/sql-js/session.ts +++ b/drizzle-orm/src/sql-js/session.ts @@ -25,7 +25,7 @@ export class SQLJsSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'sync', void, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLJsSession'; + static override readonly [entityKind]: string = 'SQLJsSession'; private logger: Logger; @@ -90,7 +90,7 @@ export class SQLJsTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'sync', void, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLJsTransaction'; + static override readonly [entityKind]: string = 'SQLJsTransaction'; override transaction(transaction: (tx: SQLJsTransaction) => T): T { const savepointName = `sp${this.nestedIndex + 1}`; @@ -110,7 +110,7 @@ export class SQLJsTransaction< export class PreparedQuery extends PreparedQueryBase< { type: 'sync'; run: void; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'SQLJsPreparedQuery'; + static override readonly [entityKind]: string = 'SQLJsPreparedQuery'; constructor( private stmt: Statement, diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index 96e8d7f69..b7cd90be1 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -20,7 +20,7 @@ export type SQLiteBigIntBuilderInitial = SQLiteBigIntBuild export class SQLiteBigIntBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteBigIntBuilder'; + static override readonly [entityKind]: string = 'SQLiteBigIntBuilder'; constructor(name: T['name']) { super(name, 'bigint', 'SQLiteBigInt'); @@ -35,7 +35,7 @@ export class SQLiteBigIntBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteBigInt'; + static override readonly [entityKind]: string = 'SQLiteBigInt'; getSQLType(): string { return 'blob'; @@ -63,7 +63,7 @@ export type SQLiteBlobJsonBuilderInitial = SQLiteBlobJsonB export class SQLiteBlobJsonBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteBlobJsonBuilder'; + static override readonly [entityKind]: string = 'SQLiteBlobJsonBuilder'; constructor(name: T['name']) { super(name, 'json', 'SQLiteBlobJson'); @@ -81,7 +81,7 @@ export class SQLiteBlobJsonBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteBlobJson'; + static override readonly [entityKind]: string = 'SQLiteBlobJson'; getSQLType(): string { return 'blob'; @@ -109,7 +109,7 @@ export type SQLiteBlobBufferBuilderInitial = SQLiteBlobBuf export class SQLiteBlobBufferBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteBlobBufferBuilder'; + static override readonly [entityKind]: string = 'SQLiteBlobBufferBuilder'; constructor(name: T['name']) { super(name, 'buffer', 'SQLiteBlobBuffer'); @@ -124,7 +124,7 @@ export class SQLiteBlobBufferBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteBlobBuffer'; + static override readonly [entityKind]: string = 'SQLiteBlobBuffer'; getSQLType(): string { return 'blob'; diff --git a/drizzle-orm/src/sqlite-core/columns/common.ts b/drizzle-orm/src/sqlite-core/columns/common.ts index a0cdd755d..0fd985537 100644 --- a/drizzle-orm/src/sqlite-core/columns/common.ts +++ b/drizzle-orm/src/sqlite-core/columns/common.ts @@ -43,7 +43,7 @@ export abstract class SQLiteColumnBuilder< > extends ColumnBuilder implements SQLiteColumnBuilderBase { - static readonly [entityKind]: string = 'SQLiteColumnBuilder'; + static override readonly [entityKind]: string = 'SQLiteColumnBuilder'; private foreignKeyConfigs: ReferenceConfig[] = []; @@ -102,7 +102,7 @@ export abstract class SQLiteColumn< T extends ColumnBaseConfig = ColumnBaseConfig, TRuntimeConfig extends object = object, > extends Column { - static readonly [entityKind]: string = 'SQLiteColumn'; + static override readonly [entityKind]: string = 'SQLiteColumn'; constructor( override readonly table: SQLiteTable, diff --git a/drizzle-orm/src/sqlite-core/columns/custom.ts b/drizzle-orm/src/sqlite-core/columns/custom.ts index 293dd09ad..6ece801c5 100644 --- a/drizzle-orm/src/sqlite-core/columns/custom.ts +++ b/drizzle-orm/src/sqlite-core/columns/custom.ts @@ -35,7 +35,7 @@ export class SQLiteCustomColumnBuilder { - static readonly [entityKind]: string = 'SQLiteCustomColumnBuilder'; + static override readonly [entityKind]: string = 'SQLiteCustomColumnBuilder'; constructor( name: T['name'], @@ -59,7 +59,7 @@ export class SQLiteCustomColumnBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteCustomColumn'; + static override readonly [entityKind]: string = 'SQLiteCustomColumn'; private sqlName: string; private mapTo?: (value: T['data']) => T['driverParam']; diff --git a/drizzle-orm/src/sqlite-core/columns/integer.ts b/drizzle-orm/src/sqlite-core/columns/integer.ts index 449c6357d..10595b9a5 100644 --- a/drizzle-orm/src/sqlite-core/columns/integer.ts +++ b/drizzle-orm/src/sqlite-core/columns/integer.ts @@ -29,7 +29,7 @@ export abstract class SQLiteBaseIntegerBuilder< {}, { primaryKeyHasDefault: true } > { - static readonly [entityKind]: string = 'SQLiteBaseIntegerBuilder'; + static override readonly [entityKind]: string = 'SQLiteBaseIntegerBuilder'; constructor(name: T['name'], dataType: T['dataType'], columnType: T['columnType']) { super(name, dataType, columnType); @@ -54,7 +54,7 @@ export abstract class SQLiteBaseInteger< T extends ColumnBaseConfig, TRuntimeConfig extends object = object, > extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteBaseInteger'; + static override readonly [entityKind]: string = 'SQLiteBaseInteger'; readonly autoIncrement: boolean = this.config.autoIncrement; @@ -76,7 +76,7 @@ export type SQLiteIntegerBuilderInitial = SQLiteIntegerBui export class SQLiteIntegerBuilder> extends SQLiteBaseIntegerBuilder { - static readonly [entityKind]: string = 'SQLiteIntegerBuilder'; + static override readonly [entityKind]: string = 'SQLiteIntegerBuilder'; constructor(name: T['name']) { super(name, 'number', 'SQLiteInteger'); @@ -93,7 +93,7 @@ export class SQLiteIntegerBuilder> extends SQLiteBaseInteger { - static readonly [entityKind]: string = 'SQLiteInteger'; + static override readonly [entityKind]: string = 'SQLiteInteger'; } export type SQLiteTimestampBuilderInitial = SQLiteTimestampBuilder<{ @@ -109,7 +109,7 @@ export type SQLiteTimestampBuilderInitial = SQLiteTimestam export class SQLiteTimestampBuilder> extends SQLiteBaseIntegerBuilder { - static readonly [entityKind]: string = 'SQLiteTimestampBuilder'; + static override readonly [entityKind]: string = 'SQLiteTimestampBuilder'; constructor(name: T['name'], mode: 'timestamp' | 'timestamp_ms') { super(name, 'date', 'SQLiteTimestamp'); @@ -138,7 +138,7 @@ export class SQLiteTimestampBuilder> extends SQLiteBaseInteger { - static readonly [entityKind]: string = 'SQLiteTimestamp'; + static override readonly [entityKind]: string = 'SQLiteTimestamp'; readonly mode: 'timestamp' | 'timestamp_ms' = this.config.mode; @@ -171,7 +171,7 @@ export type SQLiteBooleanBuilderInitial = SQLiteBooleanBui export class SQLiteBooleanBuilder> extends SQLiteBaseIntegerBuilder { - static readonly [entityKind]: string = 'SQLiteBooleanBuilder'; + static override readonly [entityKind]: string = 'SQLiteBooleanBuilder'; constructor(name: T['name'], mode: 'boolean') { super(name, 'boolean', 'SQLiteBoolean'); @@ -191,7 +191,7 @@ export class SQLiteBooleanBuilder> extends SQLiteBaseInteger { - static readonly [entityKind]: string = 'SQLiteBoolean'; + static override readonly [entityKind]: string = 'SQLiteBoolean'; readonly mode: 'boolean' = this.config.mode; diff --git a/drizzle-orm/src/sqlite-core/columns/numeric.ts b/drizzle-orm/src/sqlite-core/columns/numeric.ts index 331547736..93dfc4c3d 100644 --- a/drizzle-orm/src/sqlite-core/columns/numeric.ts +++ b/drizzle-orm/src/sqlite-core/columns/numeric.ts @@ -17,7 +17,7 @@ export type SQLiteNumericBuilderInitial = SQLiteNumericBui export class SQLiteNumericBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteNumericBuilder'; + static override readonly [entityKind]: string = 'SQLiteNumericBuilder'; constructor(name: T['name']) { super(name, 'string', 'SQLiteNumeric'); @@ -35,7 +35,7 @@ export class SQLiteNumericBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteNumeric'; + static override readonly [entityKind]: string = 'SQLiteNumeric'; getSQLType(): string { return 'numeric'; diff --git a/drizzle-orm/src/sqlite-core/columns/real.ts b/drizzle-orm/src/sqlite-core/columns/real.ts index 693780e9d..cd7cf5d01 100644 --- a/drizzle-orm/src/sqlite-core/columns/real.ts +++ b/drizzle-orm/src/sqlite-core/columns/real.ts @@ -17,7 +17,7 @@ export type SQLiteRealBuilderInitial = SQLiteRealBuilder<{ export class SQLiteRealBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteRealBuilder'; + static override readonly [entityKind]: string = 'SQLiteRealBuilder'; constructor(name: T['name']) { super(name, 'number', 'SQLiteReal'); @@ -32,7 +32,7 @@ export class SQLiteRealBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteReal'; + static override readonly [entityKind]: string = 'SQLiteReal'; getSQLType(): string { return 'real'; diff --git a/drizzle-orm/src/sqlite-core/columns/text.ts b/drizzle-orm/src/sqlite-core/columns/text.ts index 033c2cb99..84c71fb20 100644 --- a/drizzle-orm/src/sqlite-core/columns/text.ts +++ b/drizzle-orm/src/sqlite-core/columns/text.ts @@ -19,7 +19,7 @@ export class SQLiteTextBuilder { - static readonly [entityKind]: string = 'SQLiteTextBuilder'; + static override readonly [entityKind]: string = 'SQLiteTextBuilder'; constructor(name: T['name'], config: SQLiteTextConfig<'text', T['enumValues']>) { super(name, 'string', 'SQLiteText'); @@ -38,7 +38,7 @@ export class SQLiteTextBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteText'; + static override readonly [entityKind]: string = 'SQLiteText'; override readonly enumValues = this.config.enumValues; @@ -69,7 +69,7 @@ export type SQLiteTextJsonBuilderInitial = SQLiteTextJsonB export class SQLiteTextJsonBuilder> extends SQLiteColumnBuilder { - static readonly [entityKind]: string = 'SQLiteTextJsonBuilder'; + static override readonly [entityKind]: string = 'SQLiteTextJsonBuilder'; constructor(name: T['name']) { super(name, 'json', 'SQLiteTextJson'); @@ -89,7 +89,7 @@ export class SQLiteTextJsonBuilder> extends SQLiteColumn { - static readonly [entityKind]: string = 'SQLiteTextJson'; + static override readonly [entityKind]: string = 'SQLiteTextJson'; getSQLType(): string { return 'text'; diff --git a/drizzle-orm/src/sqlite-core/dialect.ts b/drizzle-orm/src/sqlite-core/dialect.ts index d3822be5e..8995148c1 100644 --- a/drizzle-orm/src/sqlite-core/dialect.ts +++ b/drizzle-orm/src/sqlite-core/dialect.ts @@ -17,7 +17,7 @@ import { type TableRelationalConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { Name } from '~/sql/index.ts'; +import type { Name, Placeholder } from '~/sql/index.ts'; import { and, eq } from '~/sql/index.ts'; import { Param, type QueryWithTypings, SQL, sql, type SQLChunk } from '~/sql/sql.ts'; import { SQLiteColumn } from '~/sqlite-core/columns/index.ts'; @@ -75,7 +75,7 @@ export abstract class SQLiteDialect { return sql.join(withSqlChunks); } - buildDeleteQuery({ table, where, returning, withList }: SQLiteDeleteConfig): SQL { + buildDeleteQuery({ table, where, returning, withList, limit, orderBy }: SQLiteDeleteConfig): SQL { const withSql = this.buildWithCTE(withList); const returningSql = returning @@ -84,7 +84,11 @@ export abstract class SQLiteDialect { const whereSql = where ? sql` where ${where}` : undefined; - return sql`${withSql}delete from ${table}${whereSql}${returningSql}`; + const orderBySql = this.buildOrderBy(orderBy); + + const limitSql = this.buildLimit(limit); + + return sql`${withSql}delete from ${table}${whereSql}${returningSql}${orderBySql}${limitSql}`; } buildUpdateSet(table: SQLiteTable, set: UpdateSet): SQL { @@ -108,7 +112,7 @@ export abstract class SQLiteDialect { })); } - buildUpdateQuery({ table, set, where, returning, withList }: SQLiteUpdateConfig): SQL { + buildUpdateQuery({ table, set, where, returning, withList, limit, orderBy }: SQLiteUpdateConfig): SQL { const withSql = this.buildWithCTE(withList); const setSql = this.buildUpdateSet(table, set); @@ -119,7 +123,11 @@ export abstract class SQLiteDialect { const whereSql = where ? sql` where ${where}` : undefined; - return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}`; + const orderBySql = this.buildOrderBy(orderBy); + + const limitSql = this.buildLimit(limit); + + return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}${orderBySql}${limitSql}`; } /** @@ -185,6 +193,28 @@ export abstract class SQLiteDialect { return sql.join(chunks); } + private buildLimit(limit: number | Placeholder | undefined): SQL | undefined { + return typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined; + } + + private buildOrderBy(orderBy: (SQLiteColumn | SQL | SQL.Aliased)[] | undefined): SQL | undefined { + const orderByList: (SQLiteColumn | SQL | SQL.Aliased)[] = []; + + if (orderBy) { + for (const [index, orderByValue] of orderBy.entries()) { + orderByList.push(orderByValue); + + if (index < orderBy.length - 1) { + orderByList.push(sql`, `); + } + } + } + + return orderByList.length > 0 ? sql` order by ${sql.join(orderByList)}` : undefined; + } + buildSelectQuery( { withList, @@ -280,17 +310,6 @@ export abstract class SQLiteDialect { const havingSql = having ? sql` having ${having}` : undefined; - const orderByList: (SQLiteColumn | SQL | SQL.Aliased)[] = []; - if (orderBy) { - for (const [index, orderByValue] of orderBy.entries()) { - orderByList.push(orderByValue); - - if (index < orderBy.length - 1) { - orderByList.push(sql`, `); - } - } - } - const groupByList: (SQL | AnyColumn | SQL.Aliased)[] = []; if (groupBy) { for (const [index, groupByValue] of groupBy.entries()) { @@ -304,11 +323,9 @@ export abstract class SQLiteDialect { const groupBySql = groupByList.length > 0 ? sql` group by ${sql.join(groupByList)}` : undefined; - const orderBySql = orderByList.length > 0 ? sql` order by ${sql.join(orderByList)}` : undefined; + const orderBySql = this.buildOrderBy(orderBy); - const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) - ? sql` limit ${limit}` - : undefined; + const limitSql = this.buildLimit(limit); const offsetSql = offset ? sql` offset ${offset}` : undefined; @@ -745,7 +762,7 @@ export abstract class SQLiteDialect { } export class SQLiteSyncDialect extends SQLiteDialect { - static readonly [entityKind]: string = 'SQLiteSyncDialect'; + static override readonly [entityKind]: string = 'SQLiteSyncDialect'; migrate( migrations: MigrationMeta[], @@ -797,7 +814,7 @@ export class SQLiteSyncDialect extends SQLiteDialect { } export class SQLiteAsyncDialect extends SQLiteDialect { - static readonly [entityKind]: string = 'SQLiteAsyncDialect'; + static override readonly [entityKind]: string = 'SQLiteAsyncDialect'; async migrate( migrations: MigrationMeta[], diff --git a/drizzle-orm/src/sqlite-core/query-builders/count.ts b/drizzle-orm/src/sqlite-core/query-builders/count.ts index 424276825..1c1234034 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/count.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/count.ts @@ -9,7 +9,7 @@ export class SQLiteCountBuilder< > extends SQL implements Promise, SQLWrapper { private sql: SQL; - static readonly [entityKind] = 'SQLiteCountBuilderAsync'; + static override readonly [entityKind] = 'SQLiteCountBuilderAsync'; [Symbol.toStringTag] = 'SQLiteCountBuilderAsync'; private session: TSession; diff --git a/drizzle-orm/src/sqlite-core/query-builders/delete.ts b/drizzle-orm/src/sqlite-core/query-builders/delete.ts index 1a028c09a..53e8d6227 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/delete.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/delete.ts @@ -2,12 +2,14 @@ import { entityKind } from '~/entity.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteDialect } from '~/sqlite-core/dialect.ts'; import type { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; import type { Subquery } from '~/subquery.ts'; -import { type DrizzleTypeError, orderSelectedFields } from '~/utils.ts'; +import { Table } from '~/table.ts'; +import { type DrizzleTypeError, orderSelectedFields, type ValueOrArray } from '~/utils.ts'; import type { SQLiteColumn } from '../columns/common.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; @@ -37,6 +39,8 @@ export type SQLiteDelete< export interface SQLiteDeleteConfig { where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (SQLiteColumn | SQL | SQL.Aliased)[]; table: SQLiteTable; returning?: SelectedFieldsOrdered; withList?: Subquery[]; @@ -136,7 +140,7 @@ export class SQLiteDeleteBase< > extends QueryPromise implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'SQLiteDelete'; + static override readonly [entityKind]: string = 'SQLiteDelete'; /** @internal */ config: SQLiteDeleteConfig; @@ -185,6 +189,37 @@ export class SQLiteDeleteBase< return this as any; } + orderBy( + builder: (deleteTable: TTable) => ValueOrArray, + ): SQLiteDeleteWithout; + orderBy(...columns: (SQLiteColumn | SQL | SQL.Aliased)[]): SQLiteDeleteWithout; + orderBy( + ...columns: + | [(deleteTable: TTable) => ValueOrArray] + | (SQLiteColumn | SQL | SQL.Aliased)[] + ): SQLiteDeleteWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (SQLiteColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): SQLiteDeleteWithout { + this.config.limit = limit; + return this as any; + } + /** * Adds a `returning` clause to the query. * diff --git a/drizzle-orm/src/sqlite-core/query-builders/insert.ts b/drizzle-orm/src/sqlite-core/query-builders/insert.ts index b0861fade..4f20666c4 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/insert.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/insert.ts @@ -199,7 +199,7 @@ export class SQLiteInsertBase< > extends QueryPromise implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'SQLiteInsert'; + static override readonly [entityKind]: string = 'SQLiteInsert'; /** @internal */ config: SQLiteInsertConfig; diff --git a/drizzle-orm/src/sqlite-core/query-builders/query.ts b/drizzle-orm/src/sqlite-core/query-builders/query.ts index 9ae47f9ce..ef93e992a 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/query.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/query.ts @@ -98,7 +98,7 @@ export class RelationalQueryBuilder< export class SQLiteRelationalQuery extends QueryPromise implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'SQLiteAsyncRelationalQuery'; + static override readonly [entityKind]: string = 'SQLiteAsyncRelationalQuery'; declare readonly _: { readonly dialect: 'sqlite'; @@ -199,7 +199,7 @@ export class SQLiteRelationalQuery exte } export class SQLiteSyncRelationalQuery extends SQLiteRelationalQuery<'sync', TResult> { - static readonly [entityKind]: string = 'SQLiteSyncRelationalQuery'; + static override readonly [entityKind]: string = 'SQLiteSyncRelationalQuery'; sync(): TResult { return this.executeRaw(); diff --git a/drizzle-orm/src/sqlite-core/query-builders/raw.ts b/drizzle-orm/src/sqlite-core/query-builders/raw.ts index 10ddb38bd..488f45afe 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/raw.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/raw.ts @@ -15,7 +15,7 @@ export interface SQLiteRaw extends QueryPromise, RunnableQuery export class SQLiteRaw extends QueryPromise implements RunnableQuery, SQLWrapper, PreparedQuery { - static readonly [entityKind]: string = 'SQLiteRaw'; + static override readonly [entityKind]: string = 'SQLiteRaw'; declare readonly _: { readonly dialect: 'sqlite'; diff --git a/drizzle-orm/src/sqlite-core/query-builders/select.ts b/drizzle-orm/src/sqlite-core/query-builders/select.ts index b7f4b0465..d9fce748a 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/select.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/select.ts @@ -137,7 +137,7 @@ export abstract class SQLiteSelectQueryBuilderBase< TResult extends any[] = SelectResult[], TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > extends TypedQueryBuilder { - static readonly [entityKind]: string = 'SQLiteSelectQueryBuilder'; + static override readonly [entityKind]: string = 'SQLiteSelectQueryBuilder'; override readonly _: { readonly dialect: 'sqlite'; @@ -854,7 +854,7 @@ export class SQLiteSelectBase< TResult, TSelectedFields > implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'SQLiteSelect'; + static override readonly [entityKind]: string = 'SQLiteSelect'; /** @internal */ _prepare(isOneTimeQuery = true): SQLiteSelectPrepare { diff --git a/drizzle-orm/src/sqlite-core/query-builders/update.ts b/drizzle-orm/src/sqlite-core/query-builders/update.ts index 0238b748f..f49337107 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/update.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/update.ts @@ -3,17 +3,27 @@ import { entityKind } from '~/entity.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteDialect } from '~/sqlite-core/dialect.ts'; import type { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; import type { Subquery } from '~/subquery.ts'; -import { type DrizzleTypeError, mapUpdateSet, orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { Table } from '~/table.ts'; +import { + type DrizzleTypeError, + mapUpdateSet, + orderSelectedFields, + type UpdateSet, + type ValueOrArray, +} from '~/utils.ts'; import type { SQLiteColumn } from '../columns/common.ts'; import type { SelectedFields, SelectedFieldsOrdered } from './select.types.ts'; export interface SQLiteUpdateConfig { where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (SQLiteColumn | SQL | SQL.Aliased)[]; set: UpdateSet; table: SQLiteTable; returning?: SelectedFieldsOrdered; @@ -169,7 +179,7 @@ export class SQLiteUpdateBase< > extends QueryPromise implements RunnableQuery, SQLWrapper { - static readonly [entityKind]: string = 'SQLiteUpdate'; + static override readonly [entityKind]: string = 'SQLiteUpdate'; /** @internal */ config: SQLiteUpdateConfig; @@ -223,6 +233,37 @@ export class SQLiteUpdateBase< return this as any; } + orderBy( + builder: (updateTable: TTable) => ValueOrArray, + ): SQLiteUpdateWithout; + orderBy(...columns: (SQLiteColumn | SQL | SQL.Aliased)[]): SQLiteUpdateWithout; + orderBy( + ...columns: + | [(updateTable: TTable) => ValueOrArray] + | (SQLiteColumn | SQL | SQL.Aliased)[] + ): SQLiteUpdateWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (SQLiteColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): SQLiteUpdateWithout { + this.config.limit = limit; + return this as any; + } + /** * Adds a `returning` clause to the query. * diff --git a/drizzle-orm/src/sqlite-core/session.ts b/drizzle-orm/src/sqlite-core/session.ts index d291b6fdf..9e6924ca0 100644 --- a/drizzle-orm/src/sqlite-core/session.ts +++ b/drizzle-orm/src/sqlite-core/session.ts @@ -20,7 +20,7 @@ export interface PreparedQueryConfig { } export class ExecuteResultSync extends QueryPromise { - static readonly [entityKind]: string = 'ExecuteResultSync'; + static override readonly [entityKind]: string = 'ExecuteResultSync'; constructor(private resultCb: () => T) { super(); @@ -209,7 +209,7 @@ export abstract class SQLiteTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends BaseSQLiteDatabase { - static readonly [entityKind]: string = 'SQLiteTransaction'; + static override readonly [entityKind]: string = 'SQLiteTransaction'; constructor( resultType: TResultType, diff --git a/drizzle-orm/src/sqlite-core/table.ts b/drizzle-orm/src/sqlite-core/table.ts index c223e2d6f..d7c5a060b 100644 --- a/drizzle-orm/src/sqlite-core/table.ts +++ b/drizzle-orm/src/sqlite-core/table.ts @@ -24,7 +24,7 @@ export type TableConfig = TableConfigBase>; export const InlineForeignKeys = Symbol.for('drizzle:SQLiteInlineForeignKeys'); export class SQLiteTable extends Table { - static readonly [entityKind]: string = 'SQLiteTable'; + static override readonly [entityKind]: string = 'SQLiteTable'; /** @internal */ static override readonly Symbol = Object.assign({}, Table.Symbol, { diff --git a/drizzle-orm/src/sqlite-core/utils.ts b/drizzle-orm/src/sqlite-core/utils.ts index 2312466c4..33ae2c248 100644 --- a/drizzle-orm/src/sqlite-core/utils.ts +++ b/drizzle-orm/src/sqlite-core/utils.ts @@ -11,7 +11,6 @@ import type { PrimaryKey } from './primary-keys.ts'; import { PrimaryKeyBuilder } from './primary-keys.ts'; import { SQLiteTable } from './table.ts'; import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; -import { SQLiteViewConfig } from './view-common.ts'; import type { SQLiteView } from './view.ts'; export function getTableConfig(table: TTable) { @@ -61,6 +60,6 @@ export function getViewConfig< >(view: SQLiteView) { return { ...view[ViewBaseConfig], - ...view[SQLiteViewConfig], + // ...view[SQLiteViewConfig], }; } diff --git a/drizzle-orm/src/sqlite-core/view-base.ts b/drizzle-orm/src/sqlite-core/view-base.ts index ac3328905..dd2f306a9 100644 --- a/drizzle-orm/src/sqlite-core/view-base.ts +++ b/drizzle-orm/src/sqlite-core/view-base.ts @@ -7,7 +7,7 @@ export abstract class SQLiteViewBase< TExisting extends boolean = boolean, TSelection extends ColumnsSelection = ColumnsSelection, > extends View { - static readonly [entityKind]: string = 'SQLiteViewBase'; + static override readonly [entityKind]: string = 'SQLiteViewBase'; declare _: View['_'] & { viewBrand: 'SQLiteView'; diff --git a/drizzle-orm/src/sqlite-core/view.ts b/drizzle-orm/src/sqlite-core/view.ts index d1f11969e..03ef08025 100644 --- a/drizzle-orm/src/sqlite-core/view.ts +++ b/drizzle-orm/src/sqlite-core/view.ts @@ -10,7 +10,6 @@ import { QueryBuilder } from './query-builders/query-builder.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import { sqliteTable } from './table.ts'; import { SQLiteViewBase } from './view-base.ts'; -import { SQLiteViewConfig } from './view-common.ts'; export interface ViewBuilderConfig { algorithm?: 'undefined' | 'merge' | 'temptable'; @@ -37,7 +36,7 @@ export class ViewBuilderCore< } export class ViewBuilder extends ViewBuilderCore<{ name: TName }> { - static readonly [entityKind]: string = 'SQLiteViewBuilder'; + static override readonly [entityKind]: string = 'SQLiteViewBuilder'; as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), @@ -55,7 +54,7 @@ export class ViewBuilder extends ViewBuilderCore< const aliasedSelectedFields = qb.getSelectedFields(); return new Proxy( new SQLiteView({ - sqliteConfig: this.config, + // sqliteConfig: this.config, config: { name: this.name, schema: undefined, @@ -74,7 +73,7 @@ export class ManualViewBuilder< > extends ViewBuilderCore< { name: TName; columns: TColumns } > { - static readonly [entityKind]: string = 'SQLiteManualViewBuilder'; + static override readonly [entityKind]: string = 'SQLiteManualViewBuilder'; private columns: Record; @@ -89,7 +88,6 @@ export class ManualViewBuilder< existing(): SQLiteViewWithSelection> { return new Proxy( new SQLiteView({ - sqliteConfig: undefined, config: { name: this.name, schema: undefined, @@ -109,7 +107,6 @@ export class ManualViewBuilder< as(query: SQL): SQLiteViewWithSelection> { return new Proxy( new SQLiteView({ - sqliteConfig: this.config, config: { name: this.name, schema: undefined, @@ -132,13 +129,9 @@ export class SQLiteView< TExisting extends boolean = boolean, TSelection extends ColumnsSelection = ColumnsSelection, > extends SQLiteViewBase { - static readonly [entityKind]: string = 'SQLiteView'; + static override readonly [entityKind]: string = 'SQLiteView'; - /** @internal */ - [SQLiteViewConfig]: ViewBuilderConfig | undefined; - - constructor({ sqliteConfig, config }: { - sqliteConfig: ViewBuilderConfig | undefined; + constructor({ config }: { config: { name: TName; schema: string | undefined; @@ -147,7 +140,6 @@ export class SQLiteView< }; }) { super(config); - this[SQLiteViewConfig] = sqliteConfig; } } diff --git a/drizzle-orm/src/sqlite-proxy/driver.ts b/drizzle-orm/src/sqlite-proxy/driver.ts index e3f2b2af7..e11e977c1 100644 --- a/drizzle-orm/src/sqlite-proxy/driver.ts +++ b/drizzle-orm/src/sqlite-proxy/driver.ts @@ -15,7 +15,7 @@ export interface SqliteRemoteResult { export class SqliteRemoteDatabase< TSchema extends Record = Record, > extends BaseSQLiteDatabase<'async', SqliteRemoteResult, TSchema> { - static readonly [entityKind]: string = 'SqliteRemoteDatabase'; + static override readonly [entityKind]: string = 'SqliteRemoteDatabase'; /** @internal */ declare readonly session: SQLiteRemoteSession>; diff --git a/drizzle-orm/src/sqlite-proxy/session.ts b/drizzle-orm/src/sqlite-proxy/session.ts index 398913568..93d277d69 100644 --- a/drizzle-orm/src/sqlite-proxy/session.ts +++ b/drizzle-orm/src/sqlite-proxy/session.ts @@ -27,7 +27,7 @@ export class SQLiteRemoteSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteSession<'async', SqliteRemoteResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLiteRemoteSession'; + static override readonly [entityKind]: string = 'SQLiteRemoteSession'; private logger: Logger; @@ -108,7 +108,7 @@ export class SQLiteProxyTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends SQLiteTransaction<'async', SqliteRemoteResult, TFullSchema, TSchema> { - static readonly [entityKind]: string = 'SQLiteProxyTransaction'; + static override readonly [entityKind]: string = 'SQLiteProxyTransaction'; override async transaction( transaction: (tx: SQLiteProxyTransaction) => Promise, @@ -130,7 +130,7 @@ export class SQLiteProxyTransaction< export class RemotePreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: SqliteRemoteResult; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { - static readonly [entityKind]: string = 'SQLiteProxyPreparedQuery'; + static override readonly [entityKind]: string = 'SQLiteProxyPreparedQuery'; private method: SQLiteExecuteMethod; diff --git a/drizzle-orm/src/subquery.ts b/drizzle-orm/src/subquery.ts index 320ec46e6..37fe48d86 100644 --- a/drizzle-orm/src/subquery.ts +++ b/drizzle-orm/src/subquery.ts @@ -42,5 +42,5 @@ export class WithSubquery< TAlias extends string = string, TSelection extends Record = Record, > extends Subquery { - static readonly [entityKind]: string = 'WithSubquery'; + static override readonly [entityKind]: string = 'WithSubquery'; } diff --git a/drizzle-orm/src/tidb-serverless/driver.ts b/drizzle-orm/src/tidb-serverless/driver.ts index ec82e61ff..01f54af6e 100644 --- a/drizzle-orm/src/tidb-serverless/driver.ts +++ b/drizzle-orm/src/tidb-serverless/driver.ts @@ -1,4 +1,4 @@ -import type { Connection } from '@tidbcloud/serverless'; +import { type Config, connect, Connection } from '@tidbcloud/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import type { TiDBServerlessPreparedQueryHKT, TiDBServerlessQueryResultHKT } from './session.ts'; import { TiDBServerlessSession } from './session.ts'; @@ -21,10 +21,10 @@ export interface TiDBServerlessSDriverOptions { export class TiDBServerlessDatabase< TSchema extends Record = Record, > extends MySqlDatabase { - static readonly [entityKind]: string = 'TiDBServerlessDatabase'; + static override readonly [entityKind]: string = 'TiDBServerlessDatabase'; } -export function drizzle = Record>( +function construct = Record>( client: Connection, config: DrizzleConfig = {}, ): TiDBServerlessDatabase & { @@ -57,3 +57,65 @@ export function drizzle = Record = Record, + TClient extends Connection = Connection, +>( + ...params: IfNotImported< + Config, + [ImportTypeError<'@tidbcloud/serverless'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + & ({ + connection: string | Config; + } | { + client: TClient; + }) + & DrizzleConfig, + ] + > +): TiDBServerlessDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (params[0] instanceof Connection) { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (typeof params[0] === 'string') { + const instance = connect({ + url: params[0], + }); + + return construct(instance, params[1]) as any; + } + + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config | string; client?: TClient } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' + ? connect({ + url: connection, + }) + : connect(connection!); + + return construct(instance, drizzleConfig) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): TiDBServerlessDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/tidb-serverless/session.ts b/drizzle-orm/src/tidb-serverless/session.ts index b01b9f948..279c60f3b 100644 --- a/drizzle-orm/src/tidb-serverless/session.ts +++ b/drizzle-orm/src/tidb-serverless/session.ts @@ -22,7 +22,7 @@ const executeRawConfig = { fullResult: true } satisfies ExecuteOptions; const queryConfig = { arrayMode: true } satisfies ExecuteOptions; export class TiDBServerlessPreparedQuery extends MySqlPreparedQuery { - static readonly [entityKind]: string = 'TiDBPreparedQuery'; + static override readonly [entityKind]: string = 'TiDBPreparedQuery'; constructor( private client: Tx | Connection, @@ -97,7 +97,7 @@ export class TiDBServerlessSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlSession { - static readonly [entityKind]: string = 'TiDBServerlessSession'; + static override readonly [entityKind]: string = 'TiDBServerlessSession'; private logger: Logger; private client: Tx | Connection; @@ -172,7 +172,7 @@ export class TiDBServerlessTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends MySqlTransaction { - static readonly [entityKind]: string = 'TiDBServerlessTransaction'; + static override readonly [entityKind]: string = 'TiDBServerlessTransaction'; constructor( dialect: MySqlDialect, diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index c073448e3..20abd0a5a 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -236,4 +236,12 @@ export function getColumnNameAndConfig< config: typeof a === 'object' ? a : b as TConfig, }; } + export type IfNotImported = unknown extends T ? Y : N; + +export type ImportTypeError = + `Please install \`${TPackageName}\`to allow Drizzle ORM to connect to the database`; + +export type RequireAtLeastOne = Keys extends any + ? Required> & Partial> + : never; diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 52a55db2c..5e6c44c27 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -1,4 +1,4 @@ -import { types } from '@vercel/postgres'; +import { type QueryResult, type QueryResultRow, sql, type VercelPool } from '@vercel/postgres'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; import { type VercelPgClient, type VercelPgQueryResultHKT, VercelPgSession } from './session.ts'; export interface VercelPgDriverOptions { @@ -25,7 +25,6 @@ export class VercelPgDriver { private dialect: PgDialect, private options: VercelPgDriverOptions = {}, ) { - this.initMappers(); } createSession( @@ -33,22 +32,15 @@ export class VercelPgDriver { ): VercelPgSession, TablesRelationalConfig> { return new VercelPgSession(this.client, this.dialect, schema, { logger: this.options.logger }); } - - initMappers() { - types.setTypeParser(types.builtins.TIMESTAMPTZ, (val) => val); - types.setTypeParser(types.builtins.TIMESTAMP, (val) => val); - types.setTypeParser(types.builtins.DATE, (val) => val); - types.setTypeParser(types.builtins.INTERVAL, (val) => val); - } } export class VercelPgDatabase< TSchema extends Record = Record, > extends PgDatabase { - static readonly [entityKind]: string = 'VercelPgDatabase'; + static override readonly [entityKind]: string = 'VercelPgDatabase'; } -export function drizzle = Record>( +function construct = Record>( client: VercelPgClient, config: DrizzleConfig = {}, ): VercelPgDatabase & { @@ -82,3 +74,54 @@ export function drizzle = Record = Record, + TClient extends VercelPgClient = + & VercelPool + & ((strings: TemplateStringsArray, ...values: Primitive[]) => Promise>), +>( + ...params: IfNotImported< + VercelPool, + [ImportTypeError<'@vercel/postgres'>], + [] | [ + TClient, + ] | [ + TClient, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + client?: TClient; + }) + ), + ] + > +): VercelPgDatabase & { + $client: TClient; +} { + // eslint-disable-next-line no-instanceof/no-instanceof + if (typeof params[0] === 'function') { + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + } + + if (!params[0] || !(params[0] as { client?: TClient }).client) { + return construct(sql, params[0] as DrizzleConfig | undefined) as any; + } + + const { client, ...drizzleConfig } = params[0] as ({ client?: TClient } & DrizzleConfig); + return construct(client ?? sql, drizzleConfig) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): VercelPgDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/vercel-postgres/session.ts b/drizzle-orm/src/vercel-postgres/session.ts index 51a987905..a901f24c8 100644 --- a/drizzle-orm/src/vercel-postgres/session.ts +++ b/drizzle-orm/src/vercel-postgres/session.ts @@ -3,6 +3,7 @@ import { type QueryConfig, type QueryResult, type QueryResultRow, + types, type VercelClient, VercelPool, type VercelPoolClient, @@ -20,7 +21,7 @@ import { type Assume, mapResultRow } from '~/utils.ts'; export type VercelPgClient = VercelPool | VercelClient | VercelPoolClient; export class VercelPgPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'VercelPgPreparedQuery'; + static override readonly [entityKind]: string = 'VercelPgPreparedQuery'; private rawQuery: QueryConfig; private queryConfig: QueryArrayConfig; @@ -39,11 +40,49 @@ export class VercelPgPreparedQuery extends PgPrep this.rawQuery = { name, text: queryString, + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val: any) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val: any) => val; + } + if (typeId === types.builtins.DATE) { + return (val: any) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val: any) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; this.queryConfig = { name, text: queryString, rowMode: 'array', + types: { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === types.builtins.TIMESTAMPTZ) { + return (val: any) => val; + } + if (typeId === types.builtins.TIMESTAMP) { + return (val: any) => val; + } + if (typeId === types.builtins.DATE) { + return (val: any) => val; + } + if (typeId === types.builtins.INTERVAL) { + return (val: any) => val; + } + // @ts-ignore + return types.getTypeParser(typeId, format); + }, + }, }; } @@ -92,7 +131,7 @@ export class VercelPgSession< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgSession { - static readonly [entityKind]: string = 'VercelPgSession'; + static override readonly [entityKind]: string = 'VercelPgSession'; private logger: Logger; @@ -170,7 +209,7 @@ export class VercelPgTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, > extends PgTransaction { - static readonly [entityKind]: string = 'VercelPgTransaction'; + static override readonly [entityKind]: string = 'VercelPgTransaction'; override async transaction( transaction: (tx: VercelPgTransaction) => Promise, diff --git a/drizzle-orm/src/xata-http/driver.ts b/drizzle-orm/src/xata-http/driver.ts index 82986f298..ce275a88d 100644 --- a/drizzle-orm/src/xata-http/driver.ts +++ b/drizzle-orm/src/xata-http/driver.ts @@ -40,7 +40,7 @@ export class XataHttpDriver { export class XataHttpDatabase = Record> extends PgDatabase { - static readonly [entityKind]: string = 'XataHttpDatabase'; + static override readonly [entityKind]: string = 'XataHttpDatabase'; /** @internal */ declare readonly session: XataHttpSession>; diff --git a/drizzle-orm/src/xata-http/session.ts b/drizzle-orm/src/xata-http/session.ts index c666ba09d..df4cc1003 100644 --- a/drizzle-orm/src/xata-http/session.ts +++ b/drizzle-orm/src/xata-http/session.ts @@ -22,7 +22,7 @@ export interface QueryResults { } export class XataHttpPreparedQuery extends PgPreparedQuery { - static readonly [entityKind]: string = 'XataHttpPreparedQuery'; + static override readonly [entityKind]: string = 'XataHttpPreparedQuery'; constructor( private client: XataHttpClient, @@ -84,7 +84,7 @@ export class XataHttpSession, TSchem TSchema > { - static readonly [entityKind]: string = 'XataHttpSession'; + static override readonly [entityKind]: string = 'XataHttpSession'; private logger: Logger; @@ -152,7 +152,7 @@ export class XataTransaction, TSchem TSchema > { - static readonly [entityKind]: string = 'XataHttpTransaction'; + static override readonly [entityKind]: string = 'XataHttpTransaction'; override async transaction(_transaction: (tx: XataTransaction) => Promise): Promise { throw new Error('No transactions support in Xata Http driver'); diff --git a/drizzle-orm/type-tests/mysql/delete.ts b/drizzle-orm/type-tests/mysql/delete.ts index c3e5afbb2..84c827ba8 100644 --- a/drizzle-orm/type-tests/mysql/delete.ts +++ b/drizzle-orm/type-tests/mysql/delete.ts @@ -59,3 +59,7 @@ Expect>; .where(sql``) .where(sql``); } + +{ + db.delete(users).where(sql``).limit(1).orderBy(sql``); +} diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index 5c9f7029f..aca5c63d7 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -186,7 +186,6 @@ export const classes = mysqlTable('classes_table', ({ serial, text }) => ({ export const newYorkers = mysqlView('new_yorkers') .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as((qb) => { const sq = qb @@ -243,7 +242,6 @@ Expect< { const newYorkers = customSchema.view('new_yorkers') .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as((qb) => { const sq = qb @@ -304,7 +302,6 @@ Expect< cityId: int('city_id'), }) .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as( sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ @@ -359,7 +356,6 @@ Expect< cityId: int('city_id'), }) .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as( sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ diff --git a/drizzle-orm/type-tests/mysql/update.ts b/drizzle-orm/type-tests/mysql/update.ts index dc6967f44..abb127b5d 100644 --- a/drizzle-orm/type-tests/mysql/update.ts +++ b/drizzle-orm/type-tests/mysql/update.ts @@ -24,3 +24,7 @@ import { users } from './tables.ts'; // @ts-expect-error method was already called .where(sql``); } + +{ + db.update(users).set({}).where(sql``).limit(1).orderBy(sql``); +} diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index 068f8fcf6..0ae1d8488 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -506,8 +506,8 @@ export const newYorkers2 = pgMaterializedView('new_yorkers') .using('btree') .with({ fillfactor: 90, - toast_tuple_target: 0.5, - autovacuum_enabled: true, + toastTupleTarget: 0.5, + autovacuumEnabled: true, }) .tablespace('custom_tablespace') .withNoData() @@ -568,8 +568,8 @@ Expect< .using('btree') .with({ fillfactor: 90, - toast_tuple_target: 0.5, - autovacuum_enabled: true, + toastTupleTarget: 0.5, + autovacuumEnabled: true, }) .tablespace('custom_tablespace') .withNoData() @@ -634,8 +634,8 @@ Expect< .using('btree') .with({ fillfactor: 90, - toast_tuple_target: 0.5, - autovacuum_enabled: true, + toastTupleTarget: 0.5, + autovacuumEnabled: true, }) .tablespace('custom_tablespace') .withNoData() @@ -694,8 +694,8 @@ Expect< .using('btree') .with({ fillfactor: 90, - toast_tuple_target: 0.5, - autovacuum_enabled: true, + toastTupleTarget: 0.5, + autovacuumEnabled: true, }) .tablespace('custom_tablespace') .withNoData() diff --git a/drizzle-orm/type-tests/sqlite/delete.ts b/drizzle-orm/type-tests/sqlite/delete.ts index fcc754740..d943077c8 100644 --- a/drizzle-orm/type-tests/sqlite/delete.ts +++ b/drizzle-orm/type-tests/sqlite/delete.ts @@ -152,3 +152,7 @@ Expect>; // @ts-expect-error method was already called .returning(); } + +{ + db.delete(users).where(sql``).limit(1).orderBy(sql``); +} diff --git a/drizzle-orm/type-tests/sqlite/update.ts b/drizzle-orm/type-tests/sqlite/update.ts index aa1f8051f..cea386b98 100644 --- a/drizzle-orm/type-tests/sqlite/update.ts +++ b/drizzle-orm/type-tests/sqlite/update.ts @@ -133,3 +133,7 @@ Expect>; // @ts-expect-error method was already called .where(sql``); } + +{ + db.update(users).set({}).where(sql``).limit(1).orderBy(sql``); +} diff --git a/integration-tests/package.json b/integration-tests/package.json index 78f36fe30..2b26ec374 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -15,6 +15,7 @@ "license": "Apache-2.0", "private": true, "devDependencies": { + "@cloudflare/workers-types": "^4.20241004.0", "@libsql/client": "^0.10.0", "@neondatabase/serverless": "0.9.0", "@originjs/vite-plugin-commonjs": "^1.0.3", @@ -28,6 +29,7 @@ "@types/pg": "^8.10.1", "@types/sql.js": "^1.4.4", "@types/uuid": "^9.0.1", + "@types/ws": "^8.5.10", "@vitest/ui": "^1.6.0", "ava": "^5.3.0", "axios": "^1.4.0", @@ -42,8 +44,8 @@ "@aws-sdk/client-rds-data": "^3.549.0", "@aws-sdk/credential-providers": "^3.549.0", "@electric-sql/pglite": "^0.1.1", - "@miniflare/d1": "^2.14.2", - "@miniflare/shared": "^2.14.2", + "@miniflare/d1": "^2.14.4", + "@miniflare/shared": "^2.14.4", "@planetscale/database": "^1.16.0", "@prisma/client": "5.14.0", "@tidbcloud/serverless": "^0.1.1", @@ -70,7 +72,8 @@ "sst": "^3.0.4", "uuid": "^9.0.0", "uvu": "^0.5.6", - "vitest": "^1.6.0", + "vitest": "^2.1.2", + "ws": "^8.16.0", "zod": "^3.20.2" } } diff --git a/integration-tests/tests/bun/sqlite-nw.test.ts b/integration-tests/tests/bun/sqlite-nw.test.ts index f6c11a698..d61d1ab4e 100644 --- a/integration-tests/tests/bun/sqlite-nw.test.ts +++ b/integration-tests/tests/bun/sqlite-nw.test.ts @@ -1,3 +1,4 @@ +/// import { Database } from 'bun:sqlite'; import { DefaultLogger, sql } from 'drizzle-orm'; import type { BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite'; diff --git a/integration-tests/tests/bun/sqlite.test.ts b/integration-tests/tests/bun/sqlite.test.ts index faa3f8eb1..0065b1928 100644 --- a/integration-tests/tests/bun/sqlite.test.ts +++ b/integration-tests/tests/bun/sqlite.test.ts @@ -1,3 +1,4 @@ +/// import { Database } from 'bun:sqlite'; import { DefaultLogger, sql } from 'drizzle-orm'; import type { BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite'; diff --git a/integration-tests/tests/common.ts b/integration-tests/tests/common.ts index 55daa43ce..0a4a61e94 100644 --- a/integration-tests/tests/common.ts +++ b/integration-tests/tests/common.ts @@ -2,7 +2,7 @@ import { beforeEach } from 'vitest'; export function skipTests(names: string[]) { beforeEach((ctx) => { - if (ctx.task.suite.name === 'common' && names.includes(ctx.task.name)) { + if (ctx.task.suite?.name === 'common' && names.includes(ctx.task.name)) { ctx.skip(); } }); diff --git a/integration-tests/tests/imports/index.test.ts b/integration-tests/tests/imports/index.test.ts index dee96e84f..875d1d24c 100644 --- a/integration-tests/tests/imports/index.test.ts +++ b/integration-tests/tests/imports/index.test.ts @@ -18,7 +18,10 @@ it('dynamic imports check for CommonJS', async () => { const promises: ProcessPromise[] = []; for (const [i, key] of Object.keys(pj['exports']).entries()) { const o1 = path.join('drizzle-orm', key); - if (o1.startsWith('drizzle-orm/pglite') || o1.startsWith('drizzle-orm/expo-sqlite')) { + if ( + o1.startsWith('drizzle-orm/bun-sqlite') || o1.startsWith('drizzle-orm/pglite') + || o1.startsWith('drizzle-orm/expo-sqlite') + ) { continue; } fs.writeFileSync(`${IMPORTS_FOLDER}/imports_${i}.cjs`, 'requ'); @@ -43,7 +46,7 @@ it('dynamic imports check for ESM', async () => { const promises: ProcessPromise[] = []; for (const [i, key] of Object.keys(pj['exports']).entries()) { const o1 = path.join('drizzle-orm', key); - if (o1.startsWith('drizzle-orm/expo-sqlite')) { + if (o1.startsWith('drizzle-orm/bun-sqlite') || o1.startsWith('drizzle-orm/expo-sqlite')) { continue; } fs.writeFileSync(`${IMPORTS_FOLDER}/imports_${i}.mjs`, 'imp'); diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index eaee85bf6..45b96f391 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3809,54 +3809,95 @@ export function tests(driver?: string) { expect(users.length).toBeGreaterThan(0); }); - }); - test('Object keys as column names', async (ctx) => { - const { db } = ctx.mysql; - - // Tests the following: - // Column with required config - // Column with optional config without providing a value - // Column with optional config providing a value - // Column without config - const users = mysqlTable('users', { - id: bigint({ mode: 'number' }).autoincrement().primaryKey(), - createdAt: timestamp(), - updatedAt: timestamp({ fsp: 3 }), - admin: boolean(), - }); - - await db.execute(sql`drop table if exists users`); - await db.execute( - sql` - create table users ( - \`id\` bigint auto_increment primary key, - \`createdAt\` timestamp, - \`updatedAt\` timestamp(3), - \`admin\` boolean - ) - `, - ); - - await db.insert(users).values([ - { createdAt: sql`now() - interval 30 day`, updatedAt: sql`now() - interval 1 day`, admin: true }, - { createdAt: sql`now() - interval 1 day`, updatedAt: sql`now() - interval 30 day`, admin: true }, - { createdAt: sql`now() - interval 1 day`, updatedAt: sql`now() - interval 1 day`, admin: false }, - ]); - const result = await db - .select({ id: users.id, admin: users.admin }) - .from(users) - .where( - and( - gt(users.createdAt, sql`now() - interval 7 day`), - gt(users.updatedAt, sql`now() - interval 7 day`), - ), + test('update with limit and order by', async (ctx) => { + const { db } = ctx.mysql; + + await db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); + + const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy( + asc(usersTable.name), + ); + expect(result).toStrictEqual([ + { name: 'Alan', verified: true }, + { name: 'Barry', verified: true }, + { name: 'Carl', verified: false }, + ]); + }); + + test('delete with limit and order by', async (ctx) => { + const { db } = ctx.mysql; + + await db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await db.delete(usersTable).where(eq(usersTable.verified, false)).limit(1).orderBy(asc(usersTable.name)); + + const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy( + asc(usersTable.name), + ); + expect(result).toStrictEqual([ + { name: 'Barry', verified: false }, + { name: 'Carl', verified: false }, + ]); + }); + + test('Object keys as column names', async (ctx) => { + const { db } = ctx.mysql; + + // Tests the following: + // Column with required config + // Column with optional config without providing a value + // Column with optional config providing a value + // Column without config + const users = mysqlTable('users', { + id: bigint({ mode: 'number' }).autoincrement().primaryKey(), + createdAt: timestamp(), + updatedAt: timestamp({ fsp: 3 }), + admin: boolean(), + }); + + await db.execute(sql`drop table if exists users`); + await db.execute( + sql` + create table users ( + \`id\` bigint auto_increment primary key, + \`createdAt\` timestamp, + \`updatedAt\` timestamp(3), + \`admin\` boolean + ) + `, ); - expect(result).toEqual([ - { id: 3, admin: false }, - ]); + await db.insert(users).values([ + { createdAt: sql`now() - interval 30 day`, updatedAt: sql`now() - interval 1 day`, admin: true }, + { createdAt: sql`now() - interval 1 day`, updatedAt: sql`now() - interval 30 day`, admin: true }, + { createdAt: sql`now() - interval 1 day`, updatedAt: sql`now() - interval 1 day`, admin: false }, + ]); + const result = await db + .select({ id: users.id, admin: users.admin }) + .from(users) + .where( + and( + gt(users.createdAt, sql`now() - interval 7 day`), + gt(users.updatedAt, sql`now() - interval 7 day`), + ), + ); - await db.execute(sql`drop table users`); + expect(result).toEqual([ + { id: 3, admin: false }, + ]); + + await db.execute(sql`drop table users`); + }); }); } diff --git a/integration-tests/tests/pg/neon-serverless.test.ts b/integration-tests/tests/pg/neon-serverless.test.ts new file mode 100644 index 000000000..5a77809fa --- /dev/null +++ b/integration-tests/tests/pg/neon-serverless.test.ts @@ -0,0 +1,582 @@ +import { neonConfig, Pool } from '@neondatabase/serverless'; +import retry from 'async-retry'; +import { eq, sql } from 'drizzle-orm'; +import { drizzle, type NeonDatabase } from 'drizzle-orm/neon-serverless'; +import { migrate } from 'drizzle-orm/neon-serverless/migrator'; +import { pgTable, serial, timestamp } from 'drizzle-orm/pg-core'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import ws from 'ws'; +import { skipTests } from '~/common'; +import { randomString } from '~/utils'; +import { mySchema, tests, usersMigratorTable, usersMySchemaTable, usersTable } from './pg-common'; + +const ENABLE_LOGGING = false; + +let db: NeonDatabase; +let client: Pool; + +beforeAll(async () => { + const connectionString = process.env['NEON_CONNECTION_STRING']; + if (!connectionString) { + throw new Error('NEON_CONNECTION_STRING is not defined'); + } + + neonConfig.webSocketConstructor = ws; + + client = await retry(async () => { + client = new Pool({ connectionString }); + + const cnt = await client.connect(); + cnt.release(); + + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); +}); + +beforeEach((ctx) => { + ctx.pg = { + db, + }; +}); + +test('migrator : default migration strategy', async () => { + await db.execute(sql`drop table if exists all_columns`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); + + await migrate(db, { migrationsFolder: './drizzle2/pg' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table all_columns`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table "drizzle"."__drizzle_migrations"`); +}); + +test('migrator : migrate with custom schema', async () => { + await db.execute(sql`drop table if exists all_columns`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); + + await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsSchema: 'custom_migrations' }); + + // test if the custom migrations table was created + const { rowCount } = await db.execute(sql`select * from custom_migrations."__drizzle_migrations";`); + expect(rowCount && rowCount > 0).toBeTruthy(); + + // test if the migrated table are working as expected + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + const result = await db.select().from(usersMigratorTable); + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table all_columns`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table custom_migrations."__drizzle_migrations"`); +}); + +test('migrator : migrate with custom table', async () => { + const customTable = randomString(); + await db.execute(sql`drop table if exists all_columns`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); + + await migrate(db, { migrationsFolder: './drizzle2/pg', migrationsTable: customTable }); + + // test if the custom migrations table was created + const { rowCount } = await db.execute(sql`select * from "drizzle".${sql.identifier(customTable)};`); + expect(rowCount && rowCount > 0).toBeTruthy(); + + // test if the migrated table are working as expected + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + const result = await db.select().from(usersMigratorTable); + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table all_columns`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table "drizzle".${sql.identifier(customTable)}`); +}); + +test('migrator : migrate with custom table and custom schema', async () => { + const customTable = randomString(); + await db.execute(sql`drop table if exists all_columns`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); + + await migrate(db, { + migrationsFolder: './drizzle2/pg', + migrationsTable: customTable, + migrationsSchema: 'custom_migrations', + }); + + // test if the custom migrations table was created + const { rowCount } = await db.execute( + sql`select * from custom_migrations.${sql.identifier(customTable)};`, + ); + expect(rowCount && rowCount > 0).toBeTruthy(); + + // test if the migrated table are working as expected + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + const result = await db.select().from(usersMigratorTable); + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table all_columns`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table custom_migrations.${sql.identifier(customTable)}`); +}); + +test('all date and time columns without timezone first case mode string', async () => { + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'string', precision: 6 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(6) not null + ) + `); + + // 1. Insert date in string format without timezone in it + await db.insert(table).values([ + { timestamp: '2022-01-01 02:00:00.123456' }, + ]); + + // 2, Select in string format and check that values are the same + const result = await db.select().from(table); + + expect(result).toEqual([{ id: 1, timestamp: '2022-01-01 02:00:00.123456' }]); + + // 3. Select as raw query and check that values are the same + const result2 = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + expect(result2.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 02:00:00.123456' }]); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('all date and time columns without timezone second case mode string', async () => { + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'string', precision: 6 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(6) not null + ) + `); + + // 1. Insert date in string format with timezone in it + await db.insert(table).values([ + { timestamp: '2022-01-01T02:00:00.123456-02' }, + ]); + + // 2, Select as raw query and check that values are the same + const result = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + expect(result.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 02:00:00.123456' }]); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('all date and time columns without timezone third case mode date', async () => { + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'date', precision: 3 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(3) not null + ) + `); + + const insertedDate = new Date('2022-01-01 20:00:00.123+04'); + + // 1. Insert date as new date + await db.insert(table).values([ + { timestamp: insertedDate }, + ]); + + // 2, Select as raw query as string + const result = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + // 3. Compare both dates using orm mapping - Need to add 'Z' to tell JS that it is UTC + expect(new Date(result.rows[0]!.timestamp_string + 'Z').getTime()).toBe(insertedDate.getTime()); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('test mode string for timestamp with timezone', async () => { + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'string', withTimezone: true, precision: 6 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(6) with time zone not null + ) + `); + + const timestampString = '2022-01-01 00:00:00.123456-0200'; + + // 1. Insert date in string format with timezone in it + await db.insert(table).values([ + { timestamp: timestampString }, + ]); + + // 2. Select date in string format and check that the values are the same + const result = await db.select().from(table); + + // 2.1 Notice that postgres will return the date in UTC, but it is exactly the same + expect(result).toEqual([{ id: 1, timestamp: '2022-01-01 02:00:00.123456+00' }]); + + // 3. Select as raw query and checke that values are the same + const result2 = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + // 3.1 Notice that postgres will return the date in UTC, but it is exactlt the same + expect(result2.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 02:00:00.123456+00' }]); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('test mode date for timestamp with timezone', async () => { + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'date', withTimezone: true, precision: 3 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(3) with time zone not null + ) + `); + + const timestampString = new Date('2022-01-01 00:00:00.456-0200'); + + // 1. Insert date in string format with timezone in it + await db.insert(table).values([ + { timestamp: timestampString }, + ]); + + // 2. Select date in string format and check that the values are the same + const result = await db.select().from(table); + + // 2.1 Notice that postgres will return the date in UTC, but it is exactly the same + expect(result).toEqual([{ id: 1, timestamp: timestampString }]); + + // 3. Select as raw query and checke that values are the same + const result2 = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + // 3.1 Notice that postgres will return the date in UTC, but it is exactlt the same + expect(result2.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 02:00:00.456+00' }]); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('test mode string for timestamp with timezone in UTC timezone', async () => { + // get current timezone from db + const timezone = await db.execute<{ TimeZone: string }>(sql`show timezone`); + + // set timezone to UTC + await db.execute(sql`set time zone 'UTC'`); + + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'string', withTimezone: true, precision: 6 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(6) with time zone not null + ) + `); + + const timestampString = '2022-01-01 00:00:00.123456-0200'; + + // 1. Insert date in string format with timezone in it + await db.insert(table).values([ + { timestamp: timestampString }, + ]); + + // 2. Select date in string format and check that the values are the same + const result = await db.select().from(table); + + // 2.1 Notice that postgres will return the date in UTC, but it is exactly the same + expect(result).toEqual([{ id: 1, timestamp: '2022-01-01 02:00:00.123456+00' }]); + + // 3. Select as raw query and checke that values are the same + const result2 = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + // 3.1 Notice that postgres will return the date in UTC, but it is exactlt the same + expect(result2.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 02:00:00.123456+00' }]); + + await db.execute(sql`set time zone '${sql.raw(timezone.rows[0]!.TimeZone)}'`); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test.skip('test mode string for timestamp with timezone in different timezone', async () => { + // get current timezone from db + const timezone = await db.execute<{ TimeZone: string }>(sql`show timezone`); + + // set timezone to HST (UTC - 10) + await db.execute(sql`set time zone 'HST'`); + + const table = pgTable('all_columns', { + id: serial('id').primaryKey(), + timestamp: timestamp('timestamp_string', { mode: 'string', withTimezone: true, precision: 6 }).notNull(), + }); + + await db.execute(sql`drop table if exists ${table}`); + + await db.execute(sql` + create table ${table} ( + id serial primary key, + timestamp_string timestamp(6) with time zone not null + ) + `); + + const timestampString = '2022-01-01 00:00:00.123456-1000'; + + // 1. Insert date in string format with timezone in it + await db.insert(table).values([ + { timestamp: timestampString }, + ]); + + // 2. Select date in string format and check that the values are the same + const result = await db.select().from(table); + + expect(result).toEqual([{ id: 1, timestamp: '2022-01-01 00:00:00.123456-10' }]); + + // 3. Select as raw query and checke that values are the same + const result2 = await db.execute<{ + id: number; + timestamp_string: string; + }>(sql`select * from ${table}`); + + expect(result2.rows).toEqual([{ id: 1, timestamp_string: '2022-01-01 00:00:00.123456+00' }]); + + await db.execute(sql`set time zone '${sql.raw(timezone.rows[0]!.TimeZone)}'`); + + await db.execute(sql`drop table if exists ${table}`); +}); + +test('select all fields', async (ctx) => { + const { db } = ctx.pg; + + const now = Date.now(); + + await db.insert(usersTable).values({ name: 'John' }); + const result = await db.select().from(usersTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + expect(Math.abs(result[0]!.createdAt.getTime() - now)).toBeLessThan(3000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('update with returning all fields', async (ctx) => { + const { db } = ctx.pg; + + const now = Date.now(); + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning(); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + expect(Math.abs(users[0]!.createdAt.getTime() - now)).toBeLessThan(3000); + expect(users).toEqual([ + { id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }, + ]); +}); + +test('delete with returning all fields', async (ctx) => { + const { db } = ctx.pg; + + const now = Date.now(); + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')).returning(); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + expect(Math.abs(users[0]!.createdAt.getTime() - now)).toBeLessThan(3000); + expect(users).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: users[0]!.createdAt }, + ]); +}); + +test('mySchema :: select all fields', async (ctx) => { + const { db } = ctx.pg; + + const now = Date.now(); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const result = await db.select().from(usersMySchemaTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + expect(Math.abs(result[0]!.createdAt.getTime() - now)).toBeLessThan(3000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('mySchema :: delete with returning all fields', async (ctx) => { + const { db } = ctx.pg; + + const now = Date.now(); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const users = await db.delete(usersMySchemaTable).where(eq(usersMySchemaTable.name, 'John')).returning(); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + expect(Math.abs(users[0]!.createdAt.getTime() - now)).toBeLessThan(3000); + expect(users).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); +}); + +skipTests([ + 'migrator : default migration strategy', + 'migrator : migrate with custom schema', + 'migrator : migrate with custom table', + 'migrator : migrate with custom table and custom schema', + 'insert via db.execute + select via db.execute', + 'insert via db.execute + returning', + 'insert via db.execute w/ query builder', + 'all date and time columns without timezone first case mode string', + 'all date and time columns without timezone third case mode date', + 'test mode string for timestamp with timezone', + 'test mode date for timestamp with timezone', + 'test mode string for timestamp with timezone in UTC timezone', + 'nested transaction rollback', + 'transaction rollback', + 'nested transaction', + 'transaction', + 'timestamp timezone', + 'test $onUpdateFn and $onUpdate works as $default', + 'select all fields', + 'update with returning all fields', + 'delete with returning all fields', + 'mySchema :: select all fields', + 'mySchema :: delete with returning all fields', +]); +tests(); + +beforeEach(async () => { + await db.execute(sql`drop schema if exists public cascade`); + await db.execute(sql`drop schema if exists ${mySchema} cascade`); + + await db.execute(sql`create schema public`); + await db.execute(sql`create schema ${mySchema}`); + + await db.execute( + sql` + create table users ( + id serial primary key, + name text not null, + verified boolean not null default false, + jsonb jsonb, + created_at timestamptz not null default now() + ) + `, + ); + + await db.execute( + sql` + create table ${usersMySchemaTable} ( + id serial primary key, + name text not null, + verified boolean not null default false, + jsonb jsonb, + created_at timestamptz not null default now() + ) + `, + ); +}); + +test('insert via db.execute + select via db.execute', async () => { + await db.execute( + sql`insert into ${usersTable} (${sql.identifier(usersTable.name.name)}) values (${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>( + sql`select id, name from "users"`, + ); + expect(result.rows).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert via db.execute + returning', async () => { + const inserted = await db.execute<{ id: number; name: string }>( + sql`insert into ${usersTable} (${ + sql.identifier( + usersTable.name.name, + ) + }) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, + ); + expect(inserted.rows).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert via db.execute w/ query builder', async () => { + const inserted = await db.execute>( + db + .insert(usersTable) + .values({ name: 'John' }) + .returning({ id: usersTable.id, name: usersTable.name }), + ); + expect(inserted.rows).toEqual([{ id: 1, name: 'John' }]); +}); diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 0ea8f250f..78eecf328 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -179,9 +179,9 @@ const aggregateTable = pgTable('aggregate_table', { }); // To test another schema and multischema -const mySchema = pgSchema('mySchema'); +export const mySchema = pgSchema('mySchema'); -const usersMySchemaTable = mySchema.table('users', { +export const usersMySchemaTable = mySchema.table('users', { id: serial('id').primaryKey(), name: text('name').notNull(), verified: boolean('verified').notNull().default(false), diff --git a/integration-tests/tests/replicas/mysql.test.ts b/integration-tests/tests/replicas/mysql.test.ts index a7de02411..673a8da65 100644 --- a/integration-tests/tests/replicas/mysql.test.ts +++ b/integration-tests/tests/replicas/mysql.test.ts @@ -15,9 +15,9 @@ const users = mysqlTable('users', { describe('[select] read replicas mysql', () => { it('primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -35,9 +35,9 @@ describe('[select] read replicas mysql', () => { }); it('random replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -64,8 +64,8 @@ describe('[select] read replicas mysql', () => { }); it('single read replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -84,8 +84,8 @@ describe('[select] read replicas mysql', () => { }); it('single read replica select + primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -105,9 +105,9 @@ describe('[select] read replicas mysql', () => { }); it('always first read select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -134,9 +134,9 @@ describe('[select] read replicas mysql', () => { describe('[selectDistinct] read replicas mysql', () => { it('primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -153,9 +153,9 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('random replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -181,8 +181,8 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('single read replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -201,8 +201,8 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('single read replica selectDistinct + primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -222,9 +222,9 @@ describe('[selectDistinct] read replicas mysql', () => { }); it('always first read selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -250,9 +250,9 @@ describe('[selectDistinct] read replicas mysql', () => { describe('[with] read replicas mysql', () => { it('primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -273,9 +273,9 @@ describe('[with] read replicas mysql', () => { }); it('random replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -299,8 +299,8 @@ describe('[with] read replicas mysql', () => { }); it('single read replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -317,8 +317,8 @@ describe('[with] read replicas mysql', () => { }); it('single read replica with + primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -336,9 +336,9 @@ describe('[with] read replicas mysql', () => { }); it('always first read with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -367,9 +367,9 @@ describe('[with] read replicas mysql', () => { describe('[update] replicas mysql', () => { it('primary update', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -402,9 +402,9 @@ describe('[update] replicas mysql', () => { describe('[delete] replicas mysql', () => { it('primary delete', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -438,9 +438,9 @@ describe('[delete] replicas mysql', () => { describe('[insert] replicas mysql', () => { it('primary insert', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -473,9 +473,9 @@ describe('[insert] replicas mysql', () => { describe('[execute] replicas mysql', () => { it('primary execute', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -515,9 +515,9 @@ describe('[execute] replicas mysql', () => { describe('[transaction] replicas mysql', () => { it('primary transaction', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -558,9 +558,9 @@ describe('[transaction] replicas mysql', () => { describe('[findFirst] read replicas mysql', () => { it('primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2]); @@ -578,9 +578,9 @@ describe('[findFirst] read replicas mysql', () => { }); it('random replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -607,8 +607,8 @@ describe('[findFirst] read replicas mysql', () => { }); it('single read replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -625,8 +625,8 @@ describe('[findFirst] read replicas mysql', () => { }); it('single read replica findFirst + primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -644,9 +644,9 @@ describe('[findFirst] read replicas mysql', () => { }); it('always first read findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -670,9 +670,9 @@ describe('[findFirst] read replicas mysql', () => { describe('[findMany] read replicas mysql', () => { it('primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2]); @@ -691,9 +691,9 @@ describe('[findMany] read replicas mysql', () => { }); it('random replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -724,8 +724,8 @@ describe('[findMany] read replicas mysql', () => { }); it('single read replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -748,8 +748,8 @@ describe('[findMany] read replicas mysql', () => { }); it('single read replica findMany + primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1]); @@ -774,9 +774,9 @@ describe('[findMany] read replicas mysql', () => { }); it('always first read findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); - const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const primaryDb = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read1 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); + const read2 = drizzle.mock({ schema: { usersTable }, mode: 'default' }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; diff --git a/integration-tests/tests/replicas/postgres.test.ts b/integration-tests/tests/replicas/postgres.test.ts index 6165ae413..0860aac6a 100644 --- a/integration-tests/tests/replicas/postgres.test.ts +++ b/integration-tests/tests/replicas/postgres.test.ts @@ -17,9 +17,9 @@ const users = pgTable('users', { describe('[select] read replicas postgres', () => { it('primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -37,9 +37,9 @@ describe('[select] read replicas postgres', () => { }); it('random replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -66,8 +66,8 @@ describe('[select] read replicas postgres', () => { }); it('single read replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -86,8 +86,8 @@ describe('[select] read replicas postgres', () => { }); it('single read replica select + primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -107,9 +107,9 @@ describe('[select] read replicas postgres', () => { }); it('always first read select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -136,9 +136,9 @@ describe('[select] read replicas postgres', () => { describe('[selectDistinct] read replicas postgres', () => { it('primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -155,9 +155,9 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('random replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -183,8 +183,8 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('single read replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -203,8 +203,8 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('single read replica selectDistinct + primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -224,9 +224,9 @@ describe('[selectDistinct] read replicas postgres', () => { }); it('always first read selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -252,9 +252,9 @@ describe('[selectDistinct] read replicas postgres', () => { describe('[with] read replicas postgres', () => { it('primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -275,9 +275,9 @@ describe('[with] read replicas postgres', () => { }); it('random replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -301,8 +301,8 @@ describe('[with] read replicas postgres', () => { }); it('single read replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -319,8 +319,8 @@ describe('[with] read replicas postgres', () => { }); it('single read replica with + primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -338,9 +338,9 @@ describe('[with] read replicas postgres', () => { }); it('always first read with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -369,9 +369,9 @@ describe('[with] read replicas postgres', () => { describe('[update] replicas postgres', () => { it('primary update', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -404,9 +404,9 @@ describe('[update] replicas postgres', () => { describe('[delete] replicas postgres', () => { it('primary delete', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -440,9 +440,9 @@ describe('[delete] replicas postgres', () => { describe('[insert] replicas postgres', () => { it('primary insert', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -475,9 +475,9 @@ describe('[insert] replicas postgres', () => { describe('[execute] replicas postgres', () => { it('primary execute', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -517,9 +517,9 @@ describe('[execute] replicas postgres', () => { describe('[transaction] replicas postgres', () => { it('primary transaction', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -560,9 +560,9 @@ describe('[transaction] replicas postgres', () => { describe('[findFirst] read replicas postgres', () => { it('primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -580,9 +580,9 @@ describe('[findFirst] read replicas postgres', () => { }); it('random replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -611,8 +611,8 @@ describe('[findFirst] read replicas postgres', () => { }); it('single read replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -629,8 +629,8 @@ describe('[findFirst] read replicas postgres', () => { }); it('single read replica findFirst + primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -648,9 +648,9 @@ describe('[findFirst] read replicas postgres', () => { }); it('always first read findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -674,9 +674,9 @@ describe('[findFirst] read replicas postgres', () => { describe('[findMany] read replicas postgres', () => { it('primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -697,9 +697,9 @@ describe('[findMany] read replicas postgres', () => { }); it('random replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -734,8 +734,8 @@ describe('[findMany] read replicas postgres', () => { }); it('single read replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -762,8 +762,8 @@ describe('[findMany] read replicas postgres', () => { }); it('single read replica findMany + primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -792,9 +792,9 @@ describe('[findMany] read replicas postgres', () => { }); it('always first read findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; diff --git a/integration-tests/tests/replicas/sqlite.test.ts b/integration-tests/tests/replicas/sqlite.test.ts index 4093a6298..aab55bbfd 100644 --- a/integration-tests/tests/replicas/sqlite.test.ts +++ b/integration-tests/tests/replicas/sqlite.test.ts @@ -15,9 +15,9 @@ const users = sqliteTable('users', { describe('[select] read replicas sqlite', () => { it('primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -35,9 +35,9 @@ describe('[select] read replicas sqlite', () => { }); it('random replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -64,8 +64,8 @@ describe('[select] read replicas sqlite', () => { }); it('single read replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -84,8 +84,8 @@ describe('[select] read replicas sqlite', () => { }); it('single read replica select + primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -105,9 +105,9 @@ describe('[select] read replicas sqlite', () => { }); it('always first read select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -134,9 +134,9 @@ describe('[select] read replicas sqlite', () => { describe('[selectDistinct] read replicas sqlite', () => { it('primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -153,9 +153,9 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('random replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -181,8 +181,8 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('single read replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -201,8 +201,8 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('single read replica selectDistinct + primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -222,9 +222,9 @@ describe('[selectDistinct] read replicas sqlite', () => { }); it('always first read selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -250,9 +250,9 @@ describe('[selectDistinct] read replicas sqlite', () => { describe('[with] read replicas sqlite', () => { it('primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -273,9 +273,9 @@ describe('[with] read replicas sqlite', () => { }); it('random replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -299,8 +299,8 @@ describe('[with] read replicas sqlite', () => { }); it('single read replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -317,8 +317,8 @@ describe('[with] read replicas sqlite', () => { }); it('single read replica with + primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -336,9 +336,9 @@ describe('[with] read replicas sqlite', () => { }); it('always first read with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -367,9 +367,9 @@ describe('[with] read replicas sqlite', () => { describe('[update] replicas sqlite', () => { it('primary update', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -402,9 +402,9 @@ describe('[update] replicas sqlite', () => { describe('[delete] replicas sqlite', () => { it('primary delete', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -438,9 +438,9 @@ describe('[delete] replicas sqlite', () => { describe('[insert] replicas sqlite', () => { it('primary insert', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -473,9 +473,9 @@ describe('[insert] replicas sqlite', () => { describe('[execute] replicas sqlite', () => { it('primary execute', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -511,9 +511,9 @@ describe('[execute] replicas sqlite', () => { describe('[transaction] replicas sqlite', () => { it('primary transaction', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -554,9 +554,9 @@ describe('[transaction] replicas sqlite', () => { describe('[findFirst] read replicas sqlite', () => { it('primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -574,9 +574,9 @@ describe('[findFirst] read replicas sqlite', () => { }); it('random replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -603,8 +603,8 @@ describe('[findFirst] read replicas sqlite', () => { }); it('single read replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -621,8 +621,8 @@ describe('[findFirst] read replicas sqlite', () => { }); it('single read replica findFirst + primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -640,9 +640,9 @@ describe('[findFirst] read replicas sqlite', () => { }); it('always first read findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -666,9 +666,9 @@ describe('[findFirst] read replicas sqlite', () => { describe('[findMany] read replicas sqlite', () => { it('primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -687,9 +687,9 @@ describe('[findMany] read replicas sqlite', () => { }); it('random replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -720,8 +720,8 @@ describe('[findMany] read replicas sqlite', () => { }); it('single read replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -744,8 +744,8 @@ describe('[findMany] read replicas sqlite', () => { }); it('single read replica findMany + primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -770,9 +770,9 @@ describe('[findMany] read replicas sqlite', () => { }); it('always first read findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; diff --git a/integration-tests/tests/sqlite/d1-batch.test.ts b/integration-tests/tests/sqlite/d1-batch.test.ts index 2c46a6fe4..dba22cd4d 100644 --- a/integration-tests/tests/sqlite/d1-batch.test.ts +++ b/integration-tests/tests/sqlite/d1-batch.test.ts @@ -1,3 +1,4 @@ +/// import 'dotenv/config'; import { D1Database, D1DatabaseAPI } from '@miniflare/d1'; import { createSQLiteDB } from '@miniflare/shared'; diff --git a/integration-tests/tests/sqlite/libsql.test.ts b/integration-tests/tests/sqlite/libsql.test.ts index 71d3b289e..b99d7e9bf 100644 --- a/integration-tests/tests/sqlite/libsql.test.ts +++ b/integration-tests/tests/sqlite/libsql.test.ts @@ -4,6 +4,7 @@ import { sql } from 'drizzle-orm'; import { drizzle, type LibSQLDatabase } from 'drizzle-orm/libsql'; import { migrate } from 'drizzle-orm/libsql/migrator'; import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { skipTests } from '~/common'; import { randomString } from '~/utils'; import { anotherUsersMigratorTable, tests, usersMigratorTable } from './sqlite-common'; @@ -87,4 +88,9 @@ test('migrator : migrate with custom table', async () => { await db.run(sql`drop table ${sql.identifier(customTable)}`); }); +skipTests([ + 'delete with limit and order by', + 'update with limit and order by', +]); + tests(); diff --git a/integration-tests/tests/sqlite/sql-js.test.ts b/integration-tests/tests/sqlite/sql-js.test.ts index ec3d7b583..4c733835f 100644 --- a/integration-tests/tests/sqlite/sql-js.test.ts +++ b/integration-tests/tests/sqlite/sql-js.test.ts @@ -58,5 +58,7 @@ skipTests([ */ 'transaction rollback', 'nested transaction rollback', + 'delete with limit and order by', + 'update with limit and order by', ]); tests(); diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 9d2489184..f31bdbbd2 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -2887,6 +2887,48 @@ export function tests() { { count: 3 }, ]); }); + + test('update with limit and order by', async (ctx) => { + const { db } = ctx.sqlite; + + await db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); + + const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy( + asc(usersTable.name), + ); + + expect(result).toStrictEqual([ + { name: 'Alan', verified: true }, + { name: 'Barry', verified: true }, + { name: 'Carl', verified: false }, + ]); + }); + + test('delete with limit and order by', async (ctx) => { + const { db } = ctx.sqlite; + + await db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await db.delete(usersTable).where(eq(usersTable.verified, false)).limit(1).orderBy(asc(usersTable.name)); + + const result = await db.select({ name: usersTable.name, verified: usersTable.verified }).from(usersTable).orderBy( + asc(usersTable.name), + ); + expect(result).toStrictEqual([ + { name: 'Barry', verified: false }, + { name: 'Carl', verified: false }, + ]); + }); }); test('table configs: unique third param', () => { diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 5187d2cfc..3952eca49 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -14,18 +14,18 @@ export default defineConfig({ 'tests/imports/**/*', 'tests/extensions/vectors/**/*', 'tests/version.test.ts', + 'tests/pg/node-postgres.test.ts', ], exclude: [ ...(process.env.SKIP_EXTERNAL_DB_TESTS ? [ 'tests/relational/mysql.planetscale.test.ts', - 'tests/neon-http-batch.test.ts', + 'tests/pg/neon-serverless.test.ts', 'tests/mysql/tidb-serverless.test.ts', 'tests/mysql/mysql-planetscale.test.ts', 'tests/sqlite/libsql.test.ts', 'tests/mysql/tidb-serverless.test.ts', 'tests/sqlite/libsql-batch.test.ts', - 'tests/pg/neon-http.test.ts', 'tests/pg/neon-http-batch.test.ts', ] diff --git a/package.json b/package.json index 4e7bd4e91..b0fda61c8 100755 --- a/package.json +++ b/package.json @@ -35,12 +35,7 @@ "tsup": "^7.2.0", "tsx": "^4.10.5", "turbo": "^1.10.14", - "typescript": "5.4.5" - }, - "pnpm": { - "patchedDependencies": { - "typescript@5.4.5": "patches/typescript@5.4.5.patch" - } + "typescript": "5.6.3" }, "packageManager": "pnpm@9.7.0" } diff --git a/patches/typescript@5.4.5.patch b/patches/typescript@5.6.3.patch similarity index 100% rename from patches/typescript@5.4.5.patch rename to patches/typescript@5.6.3.patch diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f5d886131..d2400e16d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,11 +4,6 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -patchedDependencies: - typescript@5.4.5: - hash: q3iy4fwdhi5sis3wty7d4nbsme - path: patches/typescript@5.4.5.patch - importers: .: @@ -21,13 +16,13 @@ importers: version: 4.2.0(prettier@3.0.3) '@typescript-eslint/eslint-plugin': specifier: ^6.7.3 - version: 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/experimental-utils': specifier: ^5.62.0 - version: 5.62.0(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 5.62.0(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^6.7.3 - version: 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 6.7.3(eslint@8.50.0)(typescript@5.6.3) bun-types: specifier: ^1.0.3 version: 1.0.3 @@ -45,7 +40,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -54,7 +49,7 @@ importers: version: link:eslint/eslint-plugin-drizzle-internal eslint-plugin-import: specifier: ^2.28.1 - version: 2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0) + version: 2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0) eslint-plugin-no-instanceof: specifier: ^1.0.1 version: 1.0.1 @@ -63,7 +58,7 @@ importers: version: 48.0.1(eslint@8.50.0) eslint-plugin-unused-imports: specifier: ^3.0.0 - version: 3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0) + version: 3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0) glob: specifier: ^10.3.10 version: 10.3.10 @@ -75,10 +70,10 @@ importers: version: 0.23.9 resolve-tspaths: specifier: ^0.8.16 - version: 0.8.16(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 0.8.16(typescript@5.6.3) tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3) tsx: specifier: ^4.10.5 version: 4.10.5 @@ -86,8 +81,8 @@ importers: specifier: ^1.10.14 version: 1.10.14 typescript: - specifier: 5.4.5 - version: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + specifier: 5.6.3 + version: 5.6.3 drizzle-kit: dependencies: @@ -169,10 +164,10 @@ importers: version: 8.5.11 '@typescript-eslint/eslint-plugin': specifier: ^7.2.0 - version: 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/parser': specifier: ^7.2.0 - version: 7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 7.16.1(eslint@8.57.0)(typescript@5.4.5) '@vercel/postgres': specifier: ^0.8.0 version: 0.8.0 @@ -265,19 +260,19 @@ importers: version: 2.2.1 tsup: specifier: ^8.0.2 - version: 8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(yaml@2.4.2) + version: 8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.4.5)(yaml@2.4.2) tsx: specifier: ^3.12.1 version: 3.14.0 typescript: specifier: ^5.4.3 - version: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + version: 5.4.5 uuid: specifier: ^9.0.1 version: 9.0.1 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.4.5)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.4.0 version: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -309,8 +304,8 @@ importers: specifier: ^0.10.0 version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@miniflare/d1': - specifier: ^2.14.2 - version: 2.14.2 + specifier: ^2.14.4 + version: 2.14.4 '@neondatabase/serverless': specifier: ^0.9.0 version: 0.9.0 @@ -352,7 +347,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.4(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 0.29.4(typescript@5.6.3) better-sqlite3: specifier: ^8.4.0 version: 8.7.0 @@ -400,7 +395,7 @@ importers: version: 3.14.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -418,7 +413,7 @@ importers: version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.6.3) '@sinclair/typebox': specifier: ^0.29.6 version: 0.29.6 @@ -439,7 +434,7 @@ importers: version: 3.27.2 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -454,7 +449,7 @@ importers: version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 version: 18.15.10 @@ -475,7 +470,7 @@ importers: version: 0.30.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -490,7 +485,7 @@ importers: version: 0.4.1(rollup@3.20.7) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 version: 18.15.10 @@ -508,7 +503,7 @@ importers: version: 3.20.7 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -553,16 +548,16 @@ importers: version: 3.583.0 '@aws-sdk/credential-providers': specifier: ^3.549.0 - version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0) + version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@electric-sql/pglite': specifier: ^0.1.1 version: 0.1.5 '@miniflare/d1': - specifier: ^2.14.2 - version: 2.14.2 + specifier: ^2.14.4 + version: 2.14.4 '@miniflare/shared': - specifier: ^2.14.2 - version: 2.14.2 + specifier: ^2.14.4 + version: 2.14.4 '@planetscale/database': specifier: ^1.16.0 version: 1.18.0 @@ -580,7 +575,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.4(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 0.29.4(typescript@5.6.3) async-retry: specifier: ^1.3.3 version: 1.3.3 @@ -642,12 +637,18 @@ importers: specifier: ^0.5.6 version: 0.5.6 vitest: - specifier: ^1.6.0 - version: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + specifier: ^2.1.2 + version: 2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + ws: + specifier: ^8.16.0 + version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) zod: specifier: ^3.20.2 version: 3.23.7 devDependencies: + '@cloudflare/workers-types': + specifier: ^4.20241004.0 + version: 4.20241004.0 '@libsql/client': specifier: ^0.10.0 version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) @@ -687,9 +688,12 @@ importers: '@types/uuid': specifier: ^9.0.1 version: 9.0.8 + '@types/ws': + specifier: ^8.5.10 + version: 8.5.11 '@vitest/ui': specifier: ^1.6.0 - version: 1.6.0(vitest@1.6.0) + version: 1.6.0(vitest@2.1.2) ava: specifier: ^5.3.0 version: 5.3.0(@ava/typescript@5.0.0) @@ -701,7 +705,7 @@ importers: version: 7.0.3 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + version: 10.9.2(@types/node@20.12.12)(typescript@5.6.3) tsx: specifier: ^4.14.0 version: 4.16.2 @@ -710,7 +714,7 @@ importers: version: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) zx: specifier: ^7.2.2 version: 7.2.2 @@ -1937,6 +1941,9 @@ packages: '@cloudflare/workers-types@4.20240524.0': resolution: {integrity: sha512-GpSr4uE7y39DU9f0+wmrL76xd03wn0jy1ClITaa3ZZltKjirAV8TW1GzHrvvKyVGx6u3lekrFnB1HzVHsCYHDQ==} + '@cloudflare/workers-types@4.20241004.0': + resolution: {integrity: sha512-3LrPvtecs4umknOF1bTPNLHUG/ZjeSE6PYBQ/tbO7lwaVhjZTaTugiaCny2byrZupBlVNuubQVktcAgMfw0C1A==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -3075,6 +3082,9 @@ packages: '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/trace-mapping@0.3.18': resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} @@ -3170,24 +3180,24 @@ packages: cpu: [x64] os: [win32] - '@miniflare/core@2.14.2': - resolution: {integrity: sha512-n/smm5ZTg7ilGM4fxO7Gxhbe573oc8Za06M3b2fO+lPWqF6NJcEKdCC+sJntVFbn3Cbbd2G1ChISmugPfmlCkQ==} + '@miniflare/core@2.14.4': + resolution: {integrity: sha512-FMmZcC1f54YpF4pDWPtdQPIO8NXfgUxCoR9uyrhxKJdZu7M6n8QKopPVNuaxR40jcsdxb7yKoQoFWnHfzJD9GQ==} engines: {node: '>=16.13'} - '@miniflare/d1@2.14.2': - resolution: {integrity: sha512-3NPJyBLbFfzz9VAAdIZrDRdRpyslVCJoZHQk0/0CX3z2mJIfcQzjZhox2cYCFNH8NMJ7pRg6AeSMPYAnDKECDg==} + '@miniflare/d1@2.14.4': + resolution: {integrity: sha512-pMBVq9XWxTDdm+RRCkfXZP+bREjPg1JC8s8C0JTovA9OGmLQXqGTnFxIaS9vf1d8k3uSUGhDzPTzHr0/AUW1gA==} engines: {node: '>=16.7'} - '@miniflare/queues@2.14.2': - resolution: {integrity: sha512-OylkRs4lOWKvGnX+Azab3nx+1qwC87M36/hkgAU1RRvVDCOxOrYLvNLUczFfgmgMBwpYsmmW8YOIASlI3p4Qgw==} + '@miniflare/queues@2.14.4': + resolution: {integrity: sha512-aXQ5Ik8Iq1KGMBzGenmd6Js/jJgqyYvjom95/N9GptCGpiVWE5F0XqC1SL5rCwURbHN+aWY191o8XOFyY2nCUA==} engines: {node: '>=16.7'} - '@miniflare/shared@2.14.2': - resolution: {integrity: sha512-dDnYIztz10zDQjaFJ8Gy9UaaBWZkw3NyhFdpX6tAeyPA/2lGvkftc42MYmNi8s5ljqkZAtKgWAJnSf2K75NCJw==} + '@miniflare/shared@2.14.4': + resolution: {integrity: sha512-upl4RSB3hyCnITOFmRZjJj4A72GmkVrtfZTilkdq5Qe5TTlzsjVeDJp7AuNUM9bM8vswRo+N5jOiot6O4PVwwQ==} engines: {node: '>=16.13'} - '@miniflare/watcher@2.14.2': - resolution: {integrity: sha512-/TL0np4uYDl+6MdseDApZmDdlJ6Y7AY5iDY0TvUQJG9nyBoCjX6w0Zn4SiKDwO6660rPtSqZ5c7HzbPhGb5vsA==} + '@miniflare/watcher@2.14.4': + resolution: {integrity: sha512-PYn05ET2USfBAeXF6NZfWl0O32KVyE8ncQ/ngysrh3hoIV7l3qGGH7ubeFx+D8VWQ682qYhwGygUzQv2j1tGGg==} engines: {node: '>=16.13'} '@neon-rs/load@0.0.4': @@ -4355,15 +4365,42 @@ packages: '@vitest/expect@1.6.0': resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} + '@vitest/expect@2.1.2': + resolution: {integrity: sha512-FEgtlN8mIUSEAAnlvn7mP8vzaWhEaAEvhSXCqrsijM7K6QqjB11qoRZYEd4AKSCDz8p0/+yH5LzhZ47qt+EyPg==} + + '@vitest/mocker@2.1.2': + resolution: {integrity: sha512-ExElkCGMS13JAJy+812fw1aCv2QO/LBK6CyO4WOPAzLTmve50gydOlWhgdBJPx2ztbADUq3JVI0C5U+bShaeEA==} + peerDependencies: + '@vitest/spy': 2.1.2 + msw: ^2.3.5 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.2': + resolution: {integrity: sha512-FIoglbHrSUlOJPDGIrh2bjX1sNars5HbxlcsFKCtKzu4+5lpsRhOCVcuzp0fEhAGHkPZRIXVNzPcpSlkoZ3LuA==} + '@vitest/runner@1.6.0': resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} + '@vitest/runner@2.1.2': + resolution: {integrity: sha512-UCsPtvluHO3u7jdoONGjOSil+uON5SSvU9buQh3lP7GgUXHp78guN1wRmZDX4wGK6J10f9NUtP6pO+SFquoMlw==} + '@vitest/snapshot@1.6.0': resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} + '@vitest/snapshot@2.1.2': + resolution: {integrity: sha512-xtAeNsZ++aRIYIUsek7VHzry/9AcxeULlegBvsdLncLmNCR6tR8SRjn8BbDP4naxtccvzTqZ+L1ltZlRCfBZFA==} + '@vitest/spy@1.6.0': resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} + '@vitest/spy@2.1.2': + resolution: {integrity: sha512-GSUi5zoy+abNRJwmFhBDC0yRuVUn8WMlQscvnbbXdKLXX9dE59YbfwXxuJ/mth6eeqIzofU8BB5XDo/Ns/qK2A==} + '@vitest/ui@1.6.0': resolution: {integrity: sha512-k3Lyo+ONLOgylctiGovRKy7V4+dIN2yxstX3eY5cWFXH6WP+ooVX79YSyi0GagdTQzLmT43BF27T0s6dOIPBXA==} peerDependencies: @@ -4372,6 +4409,9 @@ packages: '@vitest/utils@1.6.0': resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} + '@vitest/utils@2.1.2': + resolution: {integrity: sha512-zMO2KdYy6mx56btx9JvAqAZ6EyS3g49krMPPrgOp1yxGZiA93HumGk+bZ5jIZtOg5/VBYl5eBmGRQHqq4FG6uQ==} + '@xata.io/client@0.29.4': resolution: {integrity: sha512-dRff4E/wINr0SYIlOHwApo0h8jzpAHVf2RcbGMkK9Xrddbe90KmCEx/gue9hLhBOoCCp6qUht2h9BsuVPruymw==} peerDependencies: @@ -4585,6 +4625,10 @@ packages: assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + ast-types@0.15.2: resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} engines: {node: '>=4'} @@ -4875,6 +4919,10 @@ packages: resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} engines: {node: '>=4'} + chai@5.1.1: + resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} + engines: {node: '>=12'} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -4897,6 +4945,10 @@ packages: check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -5271,6 +5323,15 @@ packages: supports-color: optional: true + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} @@ -5283,6 +5344,10 @@ packages: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -7287,6 +7352,9 @@ packages: loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + loupe@3.1.2: + resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} + lru-cache@10.2.2: resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} engines: {node: 14 || >=16.14} @@ -7319,6 +7387,9 @@ packages: magic-string@0.30.10: resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} + make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -8056,6 +8127,10 @@ packages: pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + pause-stream@0.0.11: resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} @@ -9205,14 +9280,32 @@ packages: tinybench@2.8.0: resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.0: + resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} + tinypool@0.8.4: resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} engines: {node: '>=14.0.0'} + tinypool@1.0.1: + resolution: {integrity: sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + tinyspy@2.2.1: resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} engines: {node: '>=14.0.0'} + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -9504,6 +9597,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + ua-parser-js@1.0.38: resolution: {integrity: sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==} @@ -9516,10 +9614,6 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici@5.28.2: - resolution: {integrity: sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==} - engines: {node: '>=14.0'} - undici@5.28.4: resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} engines: {node: '>=14.0'} @@ -9664,6 +9758,11 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true + vite-node@2.1.2: + resolution: {integrity: sha512-HPcGNN5g/7I2OtPjLqgOtCRu/qhVvBxTUD3qzitmL0SrG1cWFzxzhMDWussxSbrRYWqnKf8P2jiNhPMSN+ymsQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + vite-tsconfig-paths@4.3.2: resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} peerDependencies: @@ -9753,6 +9852,31 @@ packages: jsdom: optional: true + vitest@2.1.2: + resolution: {integrity: sha512-veNjLizOMkRrJ6xxb+pvxN6/QAWg95mzcRjtmkepXdN87FNfxAss9RKe2far/G9cQpipfgP2taqg0KiWsquj8A==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.2 + '@vitest/ui': 2.1.2 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vlq@1.0.1: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} @@ -9830,6 +9954,11 @@ packages: engines: {node: '>=8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} @@ -10782,12 +10911,12 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -10870,13 +10999,13 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -10957,10 +11086,10 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': dependencies: '@aws-sdk/client-sso': 3.568.0 - '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11014,7 +11143,7 @@ snapshots: '@smithy/types': 3.0.0 tslib: 2.6.2 - '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': dependencies: '@aws-sdk/client-cognito-identity': 3.569.0 '@aws-sdk/client-sso': 3.568.0 @@ -11022,10 +11151,10 @@ snapshots: '@aws-sdk/credential-provider-cognito-identity': 3.569.0 '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -11207,7 +11336,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': dependencies: '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.567.0 @@ -11344,7 +11473,7 @@ snapshots: '@babel/traverse': 7.24.6 '@babel/types': 7.24.6 convert-source-map: 2.0.0 - debug: 4.3.5 + debug: 4.3.7 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -11405,7 +11534,7 @@ snapshots: '@babel/core': 7.24.6 '@babel/helper-compilation-targets': 7.24.6 '@babel/helper-plugin-utils': 7.24.6 - debug: 4.3.5 + debug: 4.3.7 lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -12277,7 +12406,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - debug: 4.3.5 + debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -12330,6 +12459,8 @@ snapshots: '@cloudflare/workers-types@4.20240524.0': {} + '@cloudflare/workers-types@4.20241004.0': {} + '@colors/colors@1.5.0': optional: true @@ -12862,7 +12993,7 @@ snapshots: '@eslint/eslintrc@3.1.0': dependencies: ajv: 6.12.6 - debug: 4.3.5 + debug: 4.3.7 espree: 10.0.1 globals: 14.0.0 ignore: 5.3.1 @@ -12919,7 +13050,7 @@ snapshots: chalk: 4.1.2 ci-info: 3.9.0 connect: 3.7.0 - debug: 4.3.5 + debug: 4.3.7 env-editor: 0.4.2 fast-glob: 3.3.2 find-yarn-workspace-root: 2.0.0 @@ -12987,7 +13118,7 @@ snapshots: '@expo/plist': 0.1.3 '@expo/sdk-runtime-versions': 1.0.0 chalk: 4.1.2 - debug: 4.3.5 + debug: 4.3.7 find-up: 5.0.0 getenv: 1.0.0 glob: 7.1.6 @@ -13039,7 +13170,7 @@ snapshots: '@expo/env@0.3.0': dependencies: chalk: 4.1.2 - debug: 4.3.5 + debug: 4.3.7 dotenv: 16.4.5 dotenv-expand: 11.0.6 getenv: 1.0.0 @@ -13078,7 +13209,7 @@ snapshots: '@expo/json-file': 8.3.3 '@expo/spawn-async': 1.7.2 chalk: 4.1.2 - debug: 4.3.5 + debug: 4.3.7 find-yarn-workspace-root: 2.0.0 fs-extra: 9.1.0 getenv: 1.0.0 @@ -13124,7 +13255,7 @@ snapshots: '@expo/image-utils': 0.5.1(encoding@0.1.13) '@expo/json-file': 8.3.3 '@react-native/normalize-colors': 0.74.83 - debug: 4.3.5 + debug: 4.3.7 expo-modules-autolinking: 1.11.1 fs-extra: 9.1.0 resolve-from: 5.0.0 @@ -13313,6 +13444,8 @@ snapshots: '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/trace-mapping@0.3.18': dependencies: '@jridgewell/resolve-uri': 3.1.0 @@ -13405,38 +13538,38 @@ snapshots: '@libsql/win32-x64-msvc@0.4.1': optional: true - '@miniflare/core@2.14.2': + '@miniflare/core@2.14.4': dependencies: '@iarna/toml': 2.2.5 - '@miniflare/queues': 2.14.2 - '@miniflare/shared': 2.14.2 - '@miniflare/watcher': 2.14.2 + '@miniflare/queues': 2.14.4 + '@miniflare/shared': 2.14.4 + '@miniflare/watcher': 2.14.4 busboy: 1.6.0 dotenv: 10.0.0 kleur: 4.1.5 set-cookie-parser: 2.6.0 - undici: 5.28.2 + undici: 5.28.4 urlpattern-polyfill: 4.0.3 - '@miniflare/d1@2.14.2': + '@miniflare/d1@2.14.4': dependencies: - '@miniflare/core': 2.14.2 - '@miniflare/shared': 2.14.2 + '@miniflare/core': 2.14.4 + '@miniflare/shared': 2.14.4 - '@miniflare/queues@2.14.2': + '@miniflare/queues@2.14.4': dependencies: - '@miniflare/shared': 2.14.2 + '@miniflare/shared': 2.14.4 - '@miniflare/shared@2.14.2': + '@miniflare/shared@2.14.4': dependencies: '@types/better-sqlite3': 7.6.10 kleur: 4.1.5 npx-import: 1.1.4 picomatch: 2.3.1 - '@miniflare/watcher@2.14.2': + '@miniflare/watcher@2.14.4': dependencies: - '@miniflare/shared': 2.14.2 + '@miniflare/shared': 2.14.4 '@neon-rs/load@0.0.4': {} @@ -13852,20 +13985,20 @@ snapshots: optionalDependencies: rollup: 3.27.2 - '@rollup/plugin-typescript@11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@rollup/plugin-typescript@11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.6.3)': dependencies: '@rollup/pluginutils': 5.0.2(rollup@3.20.7) resolve: 1.22.1 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 optionalDependencies: rollup: 3.20.7 tslib: 2.6.2 - '@rollup/plugin-typescript@11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@rollup/plugin-typescript@11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.6.3)': dependencies: '@rollup/pluginutils': 5.0.2(rollup@3.27.2) resolve: 1.22.2 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 optionalDependencies: rollup: 3.27.2 tslib: 2.6.2 @@ -14753,13 +14886,13 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3)': dependencies: '@eslint-community/regexpp': 4.9.0 - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/scope-manager': 6.7.3 - '@typescript-eslint/type-utils': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) - '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/type-utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/visitor-keys': 6.7.3 debug: 4.3.4 eslint: 8.50.0 @@ -14767,33 +14900,33 @@ snapshots: ignore: 5.2.4 natural-compare: 1.4.0 semver: 7.6.2 - ts-api-utils: 1.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/scope-manager': 7.16.1 - '@typescript-eslint/type-utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) - '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/type-utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/visitor-keys': 7.16.1 eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@typescript-eslint/experimental-utils@5.62.0(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/experimental-utils@5.62.0(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/utils': 5.62.0(eslint@8.50.0)(typescript@5.6.3) eslint: 8.50.0 transitivePeerDependencies: - supports-color @@ -14812,29 +14945,29 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3)': dependencies: '@typescript-eslint/scope-manager': 6.7.3 '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) '@typescript-eslint/visitor-keys': 6.7.3 debug: 4.3.4 eslint: 8.50.0 optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@typescript-eslint/scope-manager': 7.16.1 '@typescript-eslint/types': 7.16.1 - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) '@typescript-eslint/visitor-keys': 7.16.1 debug: 4.3.4 eslint: 8.57.0 optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -14871,27 +15004,27 @@ snapshots: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/visitor-keys': 7.16.1 - '@typescript-eslint/type-utils@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/type-utils@6.7.3(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) - '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) debug: 4.3.4 eslint: 8.50.0 - ts-api-utils: 1.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/type-utils@7.16.1(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) - '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) + '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) debug: 4.3.4 eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -14903,7 +15036,7 @@ snapshots: '@typescript-eslint/types@7.16.1': {} - '@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/typescript-estree@5.62.0(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 @@ -14911,9 +15044,9 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.2 - tsutils: 3.21.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + tsutils: 3.21.0(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -14931,7 +15064,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@6.7.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/typescript-estree@6.7.3(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 6.7.3 '@typescript-eslint/visitor-keys': 6.7.3 @@ -14939,13 +15072,13 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.2 - ts-api-utils: 1.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.16.1(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/typescript-estree@7.16.1(typescript@5.4.5)': dependencies: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/visitor-keys': 7.16.1 @@ -14954,20 +15087,20 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.4 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/utils@5.62.0(eslint@8.50.0)(typescript@5.6.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) '@types/json-schema': 7.0.13 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.3) eslint: 8.50.0 eslint-scope: 5.1.1 semver: 7.6.2 @@ -14989,26 +15122,26 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/utils@6.7.3(eslint@8.50.0)(typescript@5.6.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) '@types/json-schema': 7.0.13 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 6.7.3 '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) eslint: 8.50.0 semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@7.16.1(eslint@8.57.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@typescript-eslint/utils@7.16.1(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@typescript-eslint/scope-manager': 7.16.1 '@typescript-eslint/types': 7.16.1 - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) eslint: 8.57.0 transitivePeerDependencies: - supports-color @@ -15072,22 +15205,56 @@ snapshots: '@vitest/utils': 1.6.0 chai: 4.4.1 + '@vitest/expect@2.1.2': + dependencies: + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0))': + dependencies: + '@vitest/spy': 2.1.2 + estree-walker: 3.0.3 + magic-string: 0.30.11 + optionalDependencies: + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + + '@vitest/pretty-format@2.1.2': + dependencies: + tinyrainbow: 1.2.0 + '@vitest/runner@1.6.0': dependencies: '@vitest/utils': 1.6.0 p-limit: 5.0.0 pathe: 1.1.2 + '@vitest/runner@2.1.2': + dependencies: + '@vitest/utils': 2.1.2 + pathe: 1.1.2 + '@vitest/snapshot@1.6.0': dependencies: magic-string: 0.30.10 pathe: 1.1.2 pretty-format: 29.7.0 + '@vitest/snapshot@2.1.2': + dependencies: + '@vitest/pretty-format': 2.1.2 + magic-string: 0.30.11 + pathe: 1.1.2 + '@vitest/spy@1.6.0': dependencies: tinyspy: 2.2.1 + '@vitest/spy@2.1.2': + dependencies: + tinyspy: 3.0.2 + '@vitest/ui@1.6.0(vitest@1.6.0)': dependencies: '@vitest/utils': 1.6.0 @@ -15098,6 +15265,18 @@ snapshots: picocolors: 1.0.1 sirv: 2.0.4 vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + optional: true + + '@vitest/ui@1.6.0(vitest@2.1.2)': + dependencies: + '@vitest/utils': 1.6.0 + fast-glob: 3.3.2 + fflate: 0.8.2 + flatted: 3.3.1 + pathe: 1.1.2 + picocolors: 1.0.1 + sirv: 2.0.4 + vitest: 2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) '@vitest/utils@1.6.0': dependencies: @@ -15106,9 +15285,15 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 - '@xata.io/client@0.29.4(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))': + '@vitest/utils@2.1.2': dependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + '@vitest/pretty-format': 2.1.2 + loupe: 3.1.2 + tinyrainbow: 1.2.0 + + '@xata.io/client@0.29.4(typescript@5.6.3)': + dependencies: + typescript: 5.6.3 '@xmldom/xmldom@0.7.13': {} @@ -15322,6 +15507,8 @@ snapshots: assertion-error@1.1.0: {} + assertion-error@2.0.1: {} + ast-types@0.15.2: dependencies: tslib: 2.6.2 @@ -15715,6 +15902,14 @@ snapshots: pathval: 1.1.1 type-detect: 4.0.8 + chai@5.1.1: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.2 + pathval: 2.0.0 + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -15736,6 +15931,8 @@ snapshots: dependencies: get-func-name: 2.0.2 + check-error@2.1.1: {} + chokidar@3.5.3: dependencies: anymatch: 3.1.3 @@ -16116,6 +16313,10 @@ snapshots: dependencies: ms: 2.1.2 + debug@4.3.7: + dependencies: + ms: 2.1.3 + decamelize@1.2.0: {} decompress-response@6.0.0: @@ -16126,6 +16327,8 @@ snapshots: dependencies: type-detect: 4.0.8 + deep-eql@5.0.2: {} + deep-extend@0.6.0: {} deep-is@0.1.4: {} @@ -16281,10 +16484,10 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20240524.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 - '@cloudflare/workers-types': 4.20240524.0 + '@cloudflare/workers-types': 4.20241004.0 '@libsql/client': 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': 0.9.3 '@opentelemetry/api': 1.8.0 @@ -16793,17 +16996,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0): + eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0): dependencies: array-includes: 3.1.6 array.prototype.findlastindex: 1.2.2 @@ -16813,7 +17016,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) has: 1.0.3 is-core-module: 2.13.0 is-glob: 4.0.3 @@ -16824,7 +17027,7 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.14.2 optionalDependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -16860,12 +17063,12 @@ snapshots: semver: 7.6.2 strip-indent: 3.0.0 - eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0): + eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0): dependencies: eslint: 8.50.0 eslint-rule-composer: 0.3.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(eslint@8.50.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3) eslint-rule-composer@0.3.0: {} @@ -18502,6 +18705,8 @@ snapshots: dependencies: get-func-name: 2.0.2 + loupe@3.1.2: {} + lru-cache@10.2.2: {} lru-cache@5.1.1: @@ -18530,6 +18735,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 + magic-string@0.30.11: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + make-dir@2.1.0: dependencies: pify: 4.0.1 @@ -19399,6 +19608,8 @@ snapshots: pathval@1.1.1: {} + pathval@2.0.0: {} + pause-stream@0.0.11: dependencies: through: 2.3.8 @@ -19495,13 +19706,13 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)): dependencies: lilconfig: 2.1.0 yaml: 2.3.1 optionalDependencies: postcss: 8.4.39 - ts-node: 10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + ts-node: 10.9.2(@types/node@20.12.12)(typescript@5.6.3) postcss-load-config@6.0.1(postcss@8.4.39)(tsx@3.14.0)(yaml@2.4.2): dependencies: @@ -19897,12 +20108,12 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve-tspaths@0.8.16(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + resolve-tspaths@0.8.16(typescript@5.6.3): dependencies: ansi-colors: 4.1.3 commander: 11.0.0 fast-glob: 3.3.1 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 resolve.exports@2.0.2: {} @@ -20671,10 +20882,20 @@ snapshots: tinybench@2.8.0: {} + tinybench@2.9.0: {} + + tinyexec@0.3.0: {} + tinypool@0.8.4: {} + tinypool@1.0.1: {} + + tinyrainbow@1.2.0: {} + tinyspy@2.2.1: {} + tinyspy@3.0.2: {} + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -20711,19 +20932,19 @@ snapshots: dependencies: typescript: 5.2.2 - ts-api-utils@1.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + ts-api-utils@1.0.3(typescript@5.6.3): dependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 - ts-api-utils@1.3.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + ts-api-utils@1.3.0(typescript@5.4.5): dependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 ts-expose-internals-conditionally@1.0.0-empty.0: {} ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -20737,13 +20958,17 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - tsconfck@3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + tsconfck@3.0.3(typescript@5.4.5): optionalDependencies: - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 + + tsconfck@3.0.3(typescript@5.6.3): + optionalDependencies: + typescript: 5.6.3 tsconfig-paths@3.14.2: dependencies: @@ -20756,7 +20981,7 @@ snapshots: tslib@2.6.2: {} - tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)))(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3): dependencies: bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 @@ -20766,7 +20991,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)) resolve-from: 5.0.0 rollup: 3.27.2 source-map: 0.8.0-beta.0 @@ -20774,12 +20999,12 @@ snapshots: tree-kill: 1.2.2 optionalDependencies: postcss: 8.4.39 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - ts-node - tsup@8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(yaml@2.4.2): + tsup@8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.4.5)(yaml@2.4.2): dependencies: bundle-require: 5.0.0(esbuild@0.23.0) cac: 6.7.14 @@ -20798,17 +21023,17 @@ snapshots: tree-kill: 1.2.2 optionalDependencies: postcss: 8.4.39 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.4.5 transitivePeerDependencies: - jiti - supports-color - tsx - yaml - tsutils@3.21.0(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)): + tsutils@3.21.0(typescript@5.6.3): dependencies: tslib: 1.14.1 - typescript: 5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme) + typescript: 5.6.3 tsx@3.14.0: dependencies: @@ -20970,7 +21195,9 @@ snapshots: typescript@5.3.3: {} - typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme): {} + typescript@5.4.5: {} + + typescript@5.6.3: {} ua-parser-js@1.0.38: {} @@ -20985,10 +21212,6 @@ snapshots: undici-types@5.26.5: {} - undici@5.28.2: - dependencies: - '@fastify/busboy': 2.1.1 - undici@5.28.4: dependencies: '@fastify/busboy': 2.1.1 @@ -21179,33 +21402,49 @@ snapshots: - supports-color - terser - vite-tsconfig-paths@4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)): + vite-node@2.1.2(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + cac: 6.7.14 + debug: 4.3.7 + pathe: 1.1.2 + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + tsconfck: 3.0.3(typescript@5.4.5) optionalDependencies: - vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)): + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + tsconfck: 3.0.3(typescript@5.6.3) optionalDependencies: - vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@4.3.2(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme))(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)): + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5(patch_hash=q3iy4fwdhi5sis3wty7d4nbsme)) + tsconfck: 3.0.3(typescript@5.6.3) optionalDependencies: vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: @@ -21436,6 +21675,40 @@ snapshots: - supports-color - terser + vitest@2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + '@vitest/expect': 2.1.2 + '@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) + '@vitest/pretty-format': 2.1.2 + '@vitest/runner': 2.1.2 + '@vitest/snapshot': 2.1.2 + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 + debug: 4.3.7 + magic-string: 0.30.11 + pathe: 1.1.2 + std-env: 3.7.0 + tinybench: 2.9.0 + tinyexec: 0.3.0 + tinypool: 1.0.1 + tinyrainbow: 1.2.0 + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + vite-node: 2.1.2(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.12.12 + '@vitest/ui': 1.6.0(vitest@2.1.2) + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - stylus + - sugarss + - supports-color + - terser + vlq@1.0.1: {} walker@1.0.8: @@ -21520,6 +21793,11 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + wide-align@1.1.5: dependencies: string-width: 4.2.3 From 64b3c85953d35bf37342ba8cb2b48f2ad08ee7a8 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 15 Oct 2024 22:46:02 +0300 Subject: [PATCH 252/492] Update to 0.26.1 version --- changelogs/drizzle-kit/0.26.1.md | 1 + drizzle-kit/package.json | 2 +- drizzle-kit/src/serializer/mysqlSchema.ts | 2 +- drizzle-kit/src/serializer/sqliteSchema.ts | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 changelogs/drizzle-kit/0.26.1.md diff --git a/changelogs/drizzle-kit/0.26.1.md b/changelogs/drizzle-kit/0.26.1.md new file mode 100644 index 000000000..da488ede8 --- /dev/null +++ b/changelogs/drizzle-kit/0.26.1.md @@ -0,0 +1 @@ +- Fix `data is malformed` for views \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index ce2de1468..ab45203ba 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.26.0", + "version": "0.26.1", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-kit/src/serializer/mysqlSchema.ts b/drizzle-kit/src/serializer/mysqlSchema.ts index 0255afc10..3a6fb9179 100644 --- a/drizzle-kit/src/serializer/mysqlSchema.ts +++ b/drizzle-kit/src/serializer/mysqlSchema.ts @@ -148,7 +148,7 @@ export const schemaInternal = object({ version: literal('5'), dialect: dialect, tables: record(string(), table), - views: record(string(), view), + views: record(string(), view).default({}), _meta: object({ tables: record(string(), string()), columns: record(string(), string()), diff --git a/drizzle-kit/src/serializer/sqliteSchema.ts b/drizzle-kit/src/serializer/sqliteSchema.ts index 54587c3e0..8fd98d99d 100644 --- a/drizzle-kit/src/serializer/sqliteSchema.ts +++ b/drizzle-kit/src/serializer/sqliteSchema.ts @@ -90,7 +90,7 @@ export const schemaInternalV4 = object({ version: literal('4'), dialect: dialect, tables: record(string(), table), - views: record(string(), view), + views: record(string(), view).default({}), enums: object({}), }).strict(); @@ -122,7 +122,7 @@ export const schemaInternal = object({ version: latestVersion, dialect: dialect, tables: record(string(), table), - views: record(string(), view), + views: record(string(), view).default({}), enums: object({}), _meta: object({ tables: record(string(), string()), From a3592140e1599796de3fb6327f207386a61716e9 Mon Sep 17 00:00:00 2001 From: Andrii Sherman Date: Wed, 16 Oct 2024 10:30:51 +0300 Subject: [PATCH 253/492] Upgraded internal versions (#3138) * Upgraded internal versions * Add release notes --------- Co-authored-by: Aleksandr Sherman --- changelogs/drizzle-kit/0.26.2.md | 1 + changelogs/drizzle-orm/0.35.1.md | 1 + drizzle-kit/package.json | 2 +- drizzle-kit/src/cli/utils.ts | 2 +- drizzle-orm/package.json | 2 +- drizzle-orm/src/version.ts | 2 +- 6 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 changelogs/drizzle-kit/0.26.2.md create mode 100644 changelogs/drizzle-orm/0.35.1.md diff --git a/changelogs/drizzle-kit/0.26.2.md b/changelogs/drizzle-kit/0.26.2.md new file mode 100644 index 000000000..59e29de14 --- /dev/null +++ b/changelogs/drizzle-kit/0.26.2.md @@ -0,0 +1 @@ +- Updated internal versions for the drizzle-kit and drizzle-orm packages. Changes were introduced in the last minor release, and you are required to upgrade both packages to ensure they work as expected \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.35.1.md b/changelogs/drizzle-orm/0.35.1.md new file mode 100644 index 000000000..59e29de14 --- /dev/null +++ b/changelogs/drizzle-orm/0.35.1.md @@ -0,0 +1 @@ +- Updated internal versions for the drizzle-kit and drizzle-orm packages. Changes were introduced in the last minor release, and you are required to upgrade both packages to ensure they work as expected \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index ab45203ba..5b9ac0934 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.26.1", + "version": "0.26.2", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-kit/src/cli/utils.ts b/drizzle-kit/src/cli/utils.ts index 0a5d7862e..4f665ec05 100644 --- a/drizzle-kit/src/cli/utils.ts +++ b/drizzle-kit/src/cli/utils.ts @@ -74,7 +74,7 @@ export const assertEitherPackage = async ( process.exit(1); }; -const requiredApiVersion = 8; +const requiredApiVersion = 9; export const assertOrmCoreVersion = async () => { try { const { compatibilityVersion } = await import('drizzle-orm/version'); diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index bd3221754..32af69b83 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.35.0", + "version": "0.35.1", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { diff --git a/drizzle-orm/src/version.ts b/drizzle-orm/src/version.ts index d670a0575..87f7e2ae9 100644 --- a/drizzle-orm/src/version.ts +++ b/drizzle-orm/src/version.ts @@ -1,4 +1,4 @@ // @ts-ignore - imported using Rollup json plugin export { version as npmVersion } from '../package.json'; // In version 7, we changed the PostgreSQL indexes API -export const compatibilityVersion = 8; +export const compatibilityVersion = 9; From 50d026477ff951a117e84edf9f2d4740ca659ec7 Mon Sep 17 00:00:00 2001 From: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> Date: Fri, 18 Oct 2024 12:32:27 +0300 Subject: [PATCH 254/492] Updated drivers fixes (#3150) * Fixed drivers, added isConfig util & tests, added driver-init tests, updated pglite, added new `.env` variable requirement for tests * Restored tests * Fixed unthrown errors * Add release notes and bump version --------- Co-authored-by: AndriiSherman --- changelogs/drizzle-orm/0.35.2.md | 6 + drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 4 +- drizzle-orm/src/better-sqlite3/driver.ts | 15 +- drizzle-orm/src/bun-sqlite/driver.ts | 15 +- drizzle-orm/src/libsql/driver.ts | 26 +- drizzle-orm/src/mysql2/driver.ts | 22 +- drizzle-orm/src/neon-http/driver.ts | 13 +- drizzle-orm/src/neon-serverless/driver.ts | 19 +- drizzle-orm/src/node-postgres/driver.ts | 22 +- drizzle-orm/src/pglite/driver.ts | 13 +- .../src/planetscale-serverless/driver.ts | 19 +- drizzle-orm/src/postgres-js/driver.ts | 14 +- drizzle-orm/src/tidb-serverless/driver.ts | 33 +- drizzle-orm/src/utils.ts | 68 +++- drizzle-orm/src/vercel-postgres/driver.ts | 23 +- integration-tests/.env.example | 1 + .../commonjs/better-sqlite3.test.cjs | 124 ++++++++ .../driver-init/commonjs/libsql.test.cjs | 97 ++++++ .../driver-init/commonjs/mysql2.test.cjs | 153 +++++++++ .../driver-init/commonjs/neon-http.test.cjs | 92 ++++++ .../driver-init/commonjs/neon-ws.test.cjs | 211 +++++++++++++ .../driver-init/commonjs/node-pg.test.cjs | 201 ++++++++++++ .../driver-init/commonjs/pglite.test.cjs | 88 ++++++ .../driver-init/commonjs/planetscale.test.cjs | 146 +++++++++ .../driver-init/commonjs/postgres-js.test.cjs | 81 +++++ .../js-tests/driver-init/commonjs/schema.cjs | 21 ++ .../driver-init/commonjs/tidb.test.cjs | 88 ++++++ .../driver-init/commonjs/vercel.test.cjs | 229 ++++++++++++++ .../module/better-sqlite3.test.mjs | 124 ++++++++ .../driver-init/module/libsql.test.mjs | 97 ++++++ .../driver-init/module/mysql2.test.mjs | 153 +++++++++ .../driver-init/module/neon-http.test.mjs | 92 ++++++ .../driver-init/module/neon-ws.test.mjs | 211 +++++++++++++ .../driver-init/module/node-pg.test.mjs | 201 ++++++++++++ .../driver-init/module/pglite.test.mjs | 88 ++++++ .../driver-init/module/planetscale.test.mjs | 146 +++++++++ .../driver-init/module/postgres-js.test.mjs | 81 +++++ .../js-tests/driver-init/module/schema.mjs | 21 ++ .../js-tests/driver-init/module/tidb.test.mjs | 88 ++++++ .../driver-init/module/vercel.test.mjs | 229 ++++++++++++++ integration-tests/package.json | 2 +- .../tests/utils/is-config.test.ts | 298 ++++++++++++++++++ integration-tests/vitest.config.ts | 17 + pnpm-lock.yaml | 44 +-- 45 files changed, 3582 insertions(+), 156 deletions(-) create mode 100644 changelogs/drizzle-orm/0.35.2.md create mode 100644 integration-tests/js-tests/driver-init/commonjs/better-sqlite3.test.cjs create mode 100644 integration-tests/js-tests/driver-init/commonjs/libsql.test.cjs create mode 100644 integration-tests/js-tests/driver-init/commonjs/mysql2.test.cjs create mode 100644 integration-tests/js-tests/driver-init/commonjs/neon-http.test.cjs create mode 100644 integration-tests/js-tests/driver-init/commonjs/neon-ws.test.cjs create mode 100644 integration-tests/js-tests/driver-init/commonjs/node-pg.test.cjs create mode 100644 integration-tests/js-tests/driver-init/commonjs/pglite.test.cjs create mode 100644 integration-tests/js-tests/driver-init/commonjs/planetscale.test.cjs create mode 100644 integration-tests/js-tests/driver-init/commonjs/postgres-js.test.cjs create mode 100644 integration-tests/js-tests/driver-init/commonjs/schema.cjs create mode 100644 integration-tests/js-tests/driver-init/commonjs/tidb.test.cjs create mode 100644 integration-tests/js-tests/driver-init/commonjs/vercel.test.cjs create mode 100644 integration-tests/js-tests/driver-init/module/better-sqlite3.test.mjs create mode 100644 integration-tests/js-tests/driver-init/module/libsql.test.mjs create mode 100644 integration-tests/js-tests/driver-init/module/mysql2.test.mjs create mode 100644 integration-tests/js-tests/driver-init/module/neon-http.test.mjs create mode 100644 integration-tests/js-tests/driver-init/module/neon-ws.test.mjs create mode 100644 integration-tests/js-tests/driver-init/module/node-pg.test.mjs create mode 100644 integration-tests/js-tests/driver-init/module/pglite.test.mjs create mode 100644 integration-tests/js-tests/driver-init/module/planetscale.test.mjs create mode 100644 integration-tests/js-tests/driver-init/module/postgres-js.test.mjs create mode 100644 integration-tests/js-tests/driver-init/module/schema.mjs create mode 100644 integration-tests/js-tests/driver-init/module/tidb.test.mjs create mode 100644 integration-tests/js-tests/driver-init/module/vercel.test.mjs create mode 100644 integration-tests/tests/utils/is-config.test.ts diff --git a/changelogs/drizzle-orm/0.35.2.md b/changelogs/drizzle-orm/0.35.2.md new file mode 100644 index 000000000..1df586618 --- /dev/null +++ b/changelogs/drizzle-orm/0.35.2.md @@ -0,0 +1,6 @@ +- Fix issues with importing in several environments after updating the Drizzle driver implementation + +We've added approximately 240 tests to check the ESM and CJS builds for all the drivers we have. You can check them [here](https://github.com/drizzle-team/drizzle-orm/tree/main/integration-tests/js-tests/driver-init) + +- Fixed [[BUG]: Type Error in PgTransaction Missing $client Property After Upgrading to drizzle-orm@0.35.1](https://github.com/drizzle-team/drizzle-orm/issues/3140) +- Fixed [[BUG]: New critical Build error drizzle 0.35.0 deploying on Cloudflare ](https://github.com/drizzle-team/drizzle-orm/issues/3137) \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 5b9ac0934..7499a7ec1 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -51,7 +51,7 @@ "@arethetypeswrong/cli": "^0.15.3", "@aws-sdk/client-rds-data": "^3.556.0", "@cloudflare/workers-types": "^4.20230518.0", - "@electric-sql/pglite": "^0.1.5", + "@electric-sql/pglite": "^0.2.12", "@hono/node-server": "^1.9.0", "@hono/zod-validator": "^0.2.1", "@libsql/client": "^0.10.0", diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 32af69b83..ceceab709 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.35.1", + "version": "0.35.2", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -160,7 +160,7 @@ "devDependencies": { "@aws-sdk/client-rds-data": "^3.549.0", "@cloudflare/workers-types": "^4.20230904.0", - "@electric-sql/pglite": "^0.1.1", + "@electric-sql/pglite": "^0.2.12", "@libsql/client": "^0.10.0", "@miniflare/d1": "^2.14.4", "@neondatabase/serverless": "^0.9.0", diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 14e6644bc..0fe7364bd 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -9,7 +9,7 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import { BetterSQLiteSession } from './session.ts'; export type DrizzleBetterSQLite3DatabaseConfig = @@ -89,12 +89,13 @@ export function drizzle< ): BetterSQLite3Database & { $client: Database; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof Client) { - return construct(params[0] as Database, params[1] as DrizzleConfig | undefined) as any; + if (params[0] === undefined || typeof params[0] === 'string') { + const instance = params[0] === undefined ? new Client() : new Client(params[0]); + + return construct(instance, params[1]) as any; } - if (typeof params[0] === 'object') { + if (isConfig(params[0])) { const { connection, client, ...drizzleConfig } = params[0] as & { connection?: DrizzleBetterSQLite3DatabaseConfig; @@ -117,9 +118,7 @@ export function drizzle< return construct(instance, drizzleConfig) as any; } - const instance = new Client(params[0]); - - return construct(instance, params[1]) as any; + return construct(params[0] as Database, params[1] as DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index 91a2e370b..7510fe58e 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -11,7 +11,7 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import { SQLiteBunSession } from './session.ts'; export class BunSQLiteDatabase< @@ -111,12 +111,13 @@ export function drizzle< ): BunSQLiteDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof Database) { - return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + if (params[0] === undefined || typeof params[0] === 'string') { + const instance = params[0] === undefined ? new Database() : new Database(params[0]); + + return construct(instance, params[1]) as any; } - if (typeof params[0] === 'object') { + if (isConfig(params[0])) { const { connection, client, ...drizzleConfig } = params[0] as & ({ connection?: DrizzleBunSqliteDatabaseConfig | string; @@ -141,9 +142,7 @@ export function drizzle< return construct(instance, drizzleConfig) as any; } - const instance = new Database(params[0]); - - return construct(instance, params[1]) as any; + return construct(params[0] as Database, params[1] as DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/drizzle-orm/src/libsql/driver.ts b/drizzle-orm/src/libsql/driver.ts index c5e3957d2..378ae15d2 100644 --- a/drizzle-orm/src/libsql/driver.ts +++ b/drizzle-orm/src/libsql/driver.ts @@ -1,7 +1,4 @@ import { type Client, type Config, createClient, type ResultSet } from '@libsql/client'; -import { HttpClient } from '@libsql/client/http'; -import { Sqlite3Client } from '@libsql/client/sqlite3'; -import { WsClient } from '@libsql/client/ws'; import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -14,7 +11,7 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import { LibSQLSession } from './session.ts'; export class LibSQLDatabase< @@ -91,11 +88,6 @@ export function drizzle< ): LibSQLDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof WsClient || params[0] instanceof HttpClient || params[0] instanceof Sqlite3Client) { - return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; - } - if (typeof params[0] === 'string') { const instance = createClient({ url: params[0], @@ -104,15 +96,19 @@ export function drizzle< return construct(instance, params[1]) as any; } - const { connection, client, ...drizzleConfig } = params[0] as - & { connection?: Config; client?: TClient } - & DrizzleConfig; + if (isConfig(params[0])) { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config; client?: TClient } + & DrizzleConfig; - if (client) return construct(client, drizzleConfig) as any; + if (client) return construct(client, drizzleConfig) as any; - const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection!); + const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection!); + + return construct(instance, drizzleConfig) as any; + } - return construct(instance, drizzleConfig) as any; + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index ef34604e3..ec791e571 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -1,4 +1,3 @@ -import { EventEmitter } from 'events'; import { type Connection as CallbackConnection, createPool, type Pool as CallbackPool, type PoolOptions } from 'mysql2'; import type { Connection, Pool } from 'mysql2/promise'; import { entityKind } from '~/entity.ts'; @@ -13,7 +12,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import { DrizzleError } from '../errors.ts'; import type { MySql2Client, MySql2PreparedQueryHKT, MySql2QueryResultHKT } from './session.ts'; import { MySql2Session } from './session.ts'; @@ -137,12 +136,16 @@ export function drizzle< ): MySql2Database & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof EventEmitter) { - return construct(params[0] as TClient, params[1] as MySql2DrizzleConfig | undefined) as any; + if (typeof params[0] === 'string') { + const connectionString = params[0]!; + const instance = createPool({ + uri: connectionString, + }); + + return construct(instance, params[1]) as any; } - if (typeof params[0] === 'object') { + if (isConfig(params[0])) { const { connection, client, ...drizzleConfig } = params[0] as & { connection?: PoolOptions | string; client?: TClient } & MySql2DrizzleConfig; @@ -159,12 +162,7 @@ export function drizzle< return db as any; } - const connectionString = params[0]!; - const instance = createPool({ - uri: connectionString, - }); - - return construct(instance, params[1]) as any; + return construct(params[0] as TClient, params[1] as MySql2DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index f79fd9de3..4ef1dc36a 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -8,7 +8,7 @@ import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig } from '~/relations.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import { type NeonHttpClient, type NeonHttpQueryResultHKT, NeonHttpSession } from './session.ts'; export interface NeonDriverOptions { @@ -124,12 +124,12 @@ export function drizzle< ): NeonHttpDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (typeof params[0] === 'function') { - return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + if (typeof params[0] === 'string') { + const instance = neon(params[0] as string); + return construct(instance, params[1]) as any; } - if (typeof params[0] === 'object') { + if (isConfig(params[0])) { const { connection, client, ...drizzleConfig } = params[0] as & { connection?: @@ -156,8 +156,7 @@ export function drizzle< return construct(instance, drizzleConfig) as any; } - const instance = neon(params[0] as string); - return construct(instance, params[1]) as any; + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index c0f962e96..a1975c78b 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import type { NeonClient, NeonQueryResultHKT } from './session.ts'; import { NeonSession } from './session.ts'; @@ -108,12 +108,15 @@ export function drizzle< ): NeonDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof Pool) { - return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + if (typeof params[0] === 'string') { + const instance = new Pool({ + connectionString: params[0], + }); + + return construct(instance, params[1]) as any; } - if (typeof params[0] === 'object') { + if (isConfig(params[0])) { const { connection, client, ws, ...drizzleConfig } = params[0] as { connection?: PoolConfig | string; ws?: any; @@ -135,11 +138,7 @@ export function drizzle< return construct(instance, drizzleConfig) as any; } - const instance = new Pool({ - connectionString: params[0], - }); - - return construct(instance, params[1]) as any; + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index b9bb063d8..4b5b5eaab 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -1,4 +1,3 @@ -import { EventEmitter } from 'events'; import pg, { type Pool, type PoolConfig } from 'pg'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; @@ -11,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import type { NodePgClient, NodePgQueryResultHKT } from './session.ts'; import { NodePgSession } from './session.ts'; @@ -86,7 +85,7 @@ export function drizzle< >( ...params: IfNotImported< Pool, - [ImportTypeError<'pg'>], + [ImportTypeError<'@types/pg` `pg'>], | [ TClient | string, ] @@ -108,12 +107,15 @@ export function drizzle< ): NodePgDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof EventEmitter) { - return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + if (typeof params[0] === 'string') { + const instance = new pg.Pool({ + connectionString: params[0], + }); + + return construct(instance, params[1] as DrizzleConfig | undefined) as any; } - if (typeof params[0] === 'object') { + if (isConfig(params[0])) { const { connection, client, ...drizzleConfig } = params[0] as ( & ({ connection?: PoolConfig | string; client?: TClient }) & DrizzleConfig @@ -130,11 +132,7 @@ export function drizzle< return construct(instance, drizzleConfig) as any; } - const instance = new pg.Pool({ - connectionString: params[0], - }); - - return construct(instance, params[1] as DrizzleConfig | undefined) as any; + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/drizzle-orm/src/pglite/driver.ts b/drizzle-orm/src/pglite/driver.ts index 89d37d1f9..ee6aaa252 100644 --- a/drizzle-orm/src/pglite/driver.ts +++ b/drizzle-orm/src/pglite/driver.ts @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import type { PgliteClient, PgliteQueryResultHKT } from './session.ts'; import { PgliteSession } from './session.ts'; @@ -105,12 +105,12 @@ export function drizzle< ): PgliteDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof PGlite) { - return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + if (params[0] === undefined || typeof params[0] === 'string') { + const instance = new PGlite(params[0]); + return construct(instance, params[1]) as any; } - if (typeof params[0] === 'object') { + if (isConfig(params[0])) { const { connection, client, ...drizzleConfig } = params[0] as { connection?: PGliteOptions & { dataDir: string }; client?: TClient; @@ -131,8 +131,7 @@ export function drizzle< return construct(instance, drizzleConfig) as any; } - const instance = new PGlite(params[0]); - return construct(instance, params[1]) as any; + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index 1865673bf..47988e5f3 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -11,7 +11,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import type { PlanetScalePreparedQueryHKT, PlanetscaleQueryResultHKT } from './session.ts'; import { PlanetscaleSession } from './session.ts'; @@ -122,12 +122,15 @@ export function drizzle< ): PlanetScaleDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof Client) { - return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + if (typeof params[0] === 'string') { + const instance = new Client({ + url: params[0], + }); + + return construct(instance, params[1]) as any; } - if (typeof params[0] === 'object') { + if (isConfig(params[0])) { const { connection, client, ...drizzleConfig } = params[0] as & { connection?: Config | string; client?: TClient } & DrizzleConfig; @@ -145,11 +148,7 @@ export function drizzle< return construct(instance, drizzleConfig) as any; } - const instance = new Client({ - url: params[0], - }); - - return construct(instance, params[1]) as any; + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index 5c2979c84..5d1ff6755 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -9,7 +9,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import type { PostgresJsQueryResultHKT } from './session.ts'; import { PostgresJsSession } from './session.ts'; @@ -89,11 +89,13 @@ export function drizzle< ): PostgresJsDatabase & { $client: TClient; } { - if (typeof params[0] === 'function') { - return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; + if (typeof params[0] === 'string') { + const instance = pgClient(params[0] as string); + + return construct(instance, params[1]) as any; } - if (typeof params[0] === 'object') { + if (isConfig(params[0])) { const { connection, client, ...drizzleConfig } = params[0] as { connection?: { url?: string } & Options>; client?: TClient; @@ -112,9 +114,7 @@ export function drizzle< return construct(instance, drizzleConfig) as any; } - const instance = pgClient(params[0] as string); - - return construct(instance, params[1]) as any; + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/drizzle-orm/src/tidb-serverless/driver.ts b/drizzle-orm/src/tidb-serverless/driver.ts index 01f54af6e..62fbfb9ab 100644 --- a/drizzle-orm/src/tidb-serverless/driver.ts +++ b/drizzle-orm/src/tidb-serverless/driver.ts @@ -1,4 +1,4 @@ -import { type Config, connect, Connection } from '@tidbcloud/serverless'; +import { type Config, connect, type Connection } from '@tidbcloud/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import type { TiDBServerlessPreparedQueryHKT, TiDBServerlessQueryResultHKT } from './session.ts'; import { TiDBServerlessSession } from './session.ts'; @@ -82,11 +82,6 @@ export function drizzle< ): TiDBServerlessDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (params[0] instanceof Connection) { - return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; - } - if (typeof params[0] === 'string') { const instance = connect({ url: params[0], @@ -95,19 +90,23 @@ export function drizzle< return construct(instance, params[1]) as any; } - const { connection, client, ...drizzleConfig } = params[0] as - & { connection?: Config | string; client?: TClient } - & DrizzleConfig; + if (isConfig(params[0])) { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config | string; client?: TClient } + & DrizzleConfig; - if (client) return construct(client, drizzleConfig) as any; + if (client) return construct(client, drizzleConfig) as any; - const instance = typeof connection === 'string' - ? connect({ - url: connection, - }) - : connect(connection!); + const instance = typeof connection === 'string' + ? connect({ + url: connection, + }) + : connect(connection!); + + return construct(instance, drizzleConfig) as any; + } - return construct(instance, drizzleConfig) as any; + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index 20abd0a5a..8d563d0da 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -240,8 +240,74 @@ export function getColumnNameAndConfig< export type IfNotImported = unknown extends T ? Y : N; export type ImportTypeError = - `Please install \`${TPackageName}\`to allow Drizzle ORM to connect to the database`; + `Please install \`${TPackageName}\` to allow Drizzle ORM to connect to the database`; export type RequireAtLeastOne = Keys extends any ? Required> & Partial> : never; + +type ExpectedConfigShape = { + logger?: boolean | { + logQuery(query: string, params: unknown[]): void; + }; + schema?: Record; + casing?: 'snake_case' | 'camelCase'; +}; + +// If this errors, you must update config shape checker function with new config specs +const _: DrizzleConfig = {} as ExpectedConfigShape; +const __: ExpectedConfigShape = {} as DrizzleConfig; + +export function isConfig(data: any): boolean { + if (typeof data !== 'object' || data === null) return false; + + if (data.constructor.name !== 'Object') return false; + + if ('logger' in data) { + const type = typeof data['logger']; + if ( + type !== 'boolean' && (type !== 'object' || typeof data['logger']['logQuery'] !== 'function') + && type !== 'undefined' + ) return false; + + return true; + } + + if ('schema' in data) { + const type = typeof data['logger']; + if (type !== 'object' && type !== 'undefined') return false; + + return true; + } + + if ('casing' in data) { + const type = typeof data['logger']; + if (type !== 'string' && type !== 'undefined') return false; + + return true; + } + + if ('mode' in data) { + if (data['mode'] !== 'default' || data['mode'] !== 'planetscale' || data['mode'] !== undefined) return false; + + return true; + } + + if ('connection' in data) { + const type = typeof data['connection']; + if (type !== 'string' && type !== 'object' && type !== 'undefined') return false; + + return true; + } + + if ('client' in data) { + const type = typeof data['client']; + if (type !== 'object' && type !== 'undefined') return false; + + return true; + } + + if (Object.keys(data).length === 0) return true; + + return false; +} diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 5e6c44c27..44606a079 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -1,4 +1,4 @@ -import { type QueryResult, type QueryResultRow, sql, type VercelPool } from '@vercel/postgres'; +import { sql, type VercelPool } from '@vercel/postgres'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError } from '~/utils.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import { type VercelPgClient, type VercelPgQueryResultHKT, VercelPgSession } from './session.ts'; export interface VercelPgDriverOptions { @@ -75,13 +75,9 @@ function construct = Record = Record, - TClient extends VercelPgClient = - & VercelPool - & ((strings: TemplateStringsArray, ...values: Primitive[]) => Promise>), + TClient extends VercelPgClient = typeof sql, >( ...params: IfNotImported< VercelPool, @@ -103,17 +99,12 @@ export function drizzle< ): VercelPgDatabase & { $client: TClient; } { - // eslint-disable-next-line no-instanceof/no-instanceof - if (typeof params[0] === 'function') { - return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; - } - - if (!params[0] || !(params[0] as { client?: TClient }).client) { - return construct(sql, params[0] as DrizzleConfig | undefined) as any; + if (isConfig(params[0])) { + const { client, ...drizzleConfig } = params[0] as ({ client?: TClient } & DrizzleConfig); + return construct(client ?? sql, drizzleConfig) as any; } - const { client, ...drizzleConfig } = params[0] as ({ client?: TClient } & DrizzleConfig); - return construct(client ?? sql, drizzleConfig) as any; + return construct((params[0] ?? sql) as TClient, params[1] as DrizzleConfig | undefined) as any; } export namespace drizzle { diff --git a/integration-tests/.env.example b/integration-tests/.env.example index 50b3c95f2..c2e01d4f6 100644 --- a/integration-tests/.env.example +++ b/integration-tests/.env.example @@ -9,3 +9,4 @@ AWS_DATA_API_DB= AWS_DATA_API_SECRET_ARN= AWS_DATA_API_RESOURCE_ARN= AWS_TEST_PROFILE= +VERCEL_CONNECTION_STRING= # For driver-init, utils/is-config tests. Must not be local DB - breaks with Vercel drivers \ No newline at end of file diff --git a/integration-tests/js-tests/driver-init/commonjs/better-sqlite3.test.cjs b/integration-tests/js-tests/driver-init/commonjs/better-sqlite3.test.cjs new file mode 100644 index 000000000..1a9941e30 --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/better-sqlite3.test.cjs @@ -0,0 +1,124 @@ +require('dotenv/config'); +const Database = require('better-sqlite3'); +const { drizzle } = require('drizzle-orm/better-sqlite3'); +const { sqlite: schema } = require('./schema.cjs'); +import { describe, expect } from 'vitest'; + +describe('better-sqlite3', async (it) => { + it('drizzle()', async () => { + const db = drizzle(); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + }); + + it('drizzle(string)', async () => { + const db = drizzle(':memory:'); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle(':memory:', { + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: ':memory:', + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + source: ':memory:', + }, + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: {}, ...config})', async () => { + const db = drizzle({ + connection: {}, + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({...config})', async () => { + const db = drizzle({ + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = new Database(':memory:'); + const db = drizzle(client); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + }); + + it('drizzle(client, config)', async () => { + const client = new Database(':memory:'); + const db = drizzle(client, { + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Database(':memory:'); + const db = drizzle({ + client, + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/commonjs/libsql.test.cjs b/integration-tests/js-tests/driver-init/commonjs/libsql.test.cjs new file mode 100644 index 000000000..e070af1bc --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/libsql.test.cjs @@ -0,0 +1,97 @@ +require('dotenv/config'); +const { createClient } = require('@libsql/client'); +const { drizzle } = require('drizzle-orm/libsql'); +const { sqlite: schema } = require('./schema.cjs'); +import { describe, expect } from 'vitest'; + +describe('libsql', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle(':memory:'); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle(':memory:', { + schema, + }); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: ':memory:', + schema, + }); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + url: ':memory:', + }, + schema, + }); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = createClient({ + url: ':memory:', + }); + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + }); + + it('drizzle(client, config)', async () => { + const client = createClient({ + url: ':memory:', + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = createClient({ + url: ':memory:', + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/commonjs/mysql2.test.cjs b/integration-tests/js-tests/driver-init/commonjs/mysql2.test.cjs new file mode 100644 index 000000000..44a0987d1 --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/mysql2.test.cjs @@ -0,0 +1,153 @@ +require('dotenv/config'); +const { drizzle } = require('drizzle-orm/mysql2'); +const { createPool, createConnection, Connection } = require('mysql2'); +const { mysql: schema } = require('./schema.cjs'); +import { describe, expect } from 'vitest'; + +if (!process.env['MYSQL_CONNECTION_STRING']) { + throw new Error('MYSQL_CONNECTION_STRING is not defined'); +} + +describe('mysql2', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle( + process.env['MYSQL_CONNECTION_STRING'], + ); + + await db.$client.execute(`SELECT 1`); + + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle( + process.env['MYSQL_CONNECTION_STRING'], + { + schema, + mode: 'default', + }, + ); + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['MYSQL_CONNECTION_STRING'], + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + uri: process.env['MYSQL_CONNECTION_STRING'], + }, + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = createPool({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle(client, config)', async () => { + const client = createPool({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = createPool({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const db = drizzle({ + client, + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); +}); + +describe('mysql2:connection', async (it) => { + it('drizzle(client)', async () => { + const client = createConnection({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client.getConnection).toStrictEqual(undefined); + }); + + it('drizzle(client, config)', async () => { + const client = createConnection({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = createConnection({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const db = drizzle({ + client, + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/commonjs/neon-http.test.cjs b/integration-tests/js-tests/driver-init/commonjs/neon-http.test.cjs new file mode 100644 index 000000000..ad68b96a3 --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/neon-http.test.cjs @@ -0,0 +1,92 @@ +require('dotenv/config'); +const { neon: pg } = require('@neondatabase/serverless'); +const { drizzle } = require('drizzle-orm/neon-http'); +const { pg: schema } = require('./schema.cjs'); +import { describe, expect } from 'vitest'; + +if (!process.env['NEON_CONNECTION_STRING']) { + throw new Error('NEON_CONNECTION_STRING is not defined'); +} + +describe('neon-http', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle( + process.env['NEON_CONNECTION_STRING'], + ); + + await db.$client('SELECT 1;'); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle( + process.env['NEON_CONNECTION_STRING'], + { + schema, + }, + ); + + await db.$client('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['NEON_CONNECTION_STRING'], + schema, + }); + + await db.$client('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + connectionString: process.env['NEON_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = pg( + process.env['NEON_CONNECTION_STRING'], + ); + const db = drizzle(client); + + await db.$client('SELECT 1;'); + }); + + it('drizzle(client, config)', async () => { + const client = pg( + process.env['NEON_CONNECTION_STRING'], + ); + const db = drizzle(client, { + schema, + }); + + await db.$client('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = pg( + process.env['NEON_CONNECTION_STRING'], + ); + const db = drizzle({ + client, + schema, + }); + + await db.$client('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/commonjs/neon-ws.test.cjs b/integration-tests/js-tests/driver-init/commonjs/neon-ws.test.cjs new file mode 100644 index 000000000..28b5026c6 --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/neon-ws.test.cjs @@ -0,0 +1,211 @@ +require('dotenv/config'); +const { neonConfig, Pool, Client } = require('@neondatabase/serverless'); +const { drizzle } = require('drizzle-orm/neon-serverless'); +const { pg: schema } = require('./schema.cjs'); +const ws = require('ws'); +import { describe, expect } from 'vitest'; + +neonConfig.webSocketConstructor = ws; + +if (!process.env['NEON_CONNECTION_STRING']) { + throw new Error('NEON_CONNECTION_STRING is not defined'); +} + +describe('neon-ws', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle( + process.env['NEON_CONNECTION_STRING'], + ); + + await db.$client.query('SELECT 1;'); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle( + process.env['NEON_CONNECTION_STRING'], + { + schema, + }, + ); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['NEON_CONNECTION_STRING'], + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + connectionString: process.env['NEON_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle(client)', async () => { + const client = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle(client, config)', async () => { + const client = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Pool); + }); +}); + +describe('neon-ws:Client', async (it) => { + it('drizzle(client)', async () => { + const client = new Client({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + + await client.connect(); + + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); + + it('drizzle(client, config)', async () => { + const client = new Client({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Client({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); +}); + +describe('neon-ws:PoolClient', async (it) => { + it('drizzle(client)', async () => { + const pool = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + + client.release(); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); + + it('drizzle(client, config)', async () => { + const pool = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + + client.release(); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); + + it('drizzle({client, ...config})', async () => { + const pool = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle({ + client, + schema, + }); + + await db.$client.query('SELECT 1;'); + + client.release(); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); +}); diff --git a/integration-tests/js-tests/driver-init/commonjs/node-pg.test.cjs b/integration-tests/js-tests/driver-init/commonjs/node-pg.test.cjs new file mode 100644 index 000000000..53338d061 --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/node-pg.test.cjs @@ -0,0 +1,201 @@ +require('dotenv/config'); +const { drizzle } = require('drizzle-orm/node-postgres'); +const pg = require('pg'); +const { pg: schema } = require('./schema.cjs'); +import { describe, expect } from 'vitest'; + +const Pool = pg.Pool; +const Client = pg.Client; + +if (!process.env['PG_CONNECTION_STRING']) { + throw new Error('PG_CONNECTION_STRING is not defined'); +} + +describe('node-pg', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle(process.env['PG_CONNECTION_STRING']); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle(process.env['PG_CONNECTION_STRING'], { + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['PG_CONNECTION_STRING'], + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + connectionString: process.env['PG_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle(client, config)', async () => { + const client = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('node-pg:Client', async (it) => { + it('drizzle(client)', async () => { + const client = new Client({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(client, config)', async () => { + const client = new Client({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Client({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('node-pg:PoolClient', async (it) => { + it('drizzle(client)', async () => { + const pool = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const client = await pool.connect(); + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(client, config)', async () => { + const pool = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const client = await pool.connect(); + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const pool = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const client = await pool.connect(); + const db = drizzle({ + client, + schema, + }); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/commonjs/pglite.test.cjs b/integration-tests/js-tests/driver-init/commonjs/pglite.test.cjs new file mode 100644 index 000000000..a00afb041 --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/pglite.test.cjs @@ -0,0 +1,88 @@ +require('dotenv/config'); +const { drizzle } = require('drizzle-orm/pglite'); +const { pg: schema } = require('./schema.cjs'); +const { PGlite: Database } = require('@electric-sql/pglite'); +import { describe, expect } from 'vitest'; + +describe('pglite', async (it) => { + it('drizzle()', async () => { + const db = drizzle(); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + }); + + it('drizzle(string)', async () => { + const db = drizzle('memory://'); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle('memory://', { + schema, + }); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: {}, ...config})', async () => { + const db = drizzle({ + connection: {}, + schema, + }); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({...config})', async () => { + const db = drizzle({ + schema, + }); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = new Database('memory://'); + const db = drizzle(client); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + }); + + it('drizzle(client, config)', async () => { + const client = new Database('memory://'); + const db = drizzle(client, { + schema, + }); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Database('memory://'); + const db = drizzle({ + client, + schema, + }); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/commonjs/planetscale.test.cjs b/integration-tests/js-tests/driver-init/commonjs/planetscale.test.cjs new file mode 100644 index 000000000..2a7bffec1 --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/planetscale.test.cjs @@ -0,0 +1,146 @@ +require('dotenv/config'); +const { Client, Connection } = require('@planetscale/database'); +const { drizzle } = require('drizzle-orm/planetscale-serverless'); +const { mysql: schema } = require('./schema.cjs'); +import { describe, expect } from 'vitest'; + +if (!process.env['PLANETSCALE_CONNECTION_STRING']) { + throw new Error('PLANETSCALE_CONNECTION_STRING is not defined'); +} + +describe('planetscale', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle( + process.env['PLANETSCALE_CONNECTION_STRING'], + ); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle( + process.env['PLANETSCALE_CONNECTION_STRING'], + { + schema, + }, + ); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['PLANETSCALE_CONNECTION_STRING'], + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = new Client({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(client, config)', async () => { + const client = new Client({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Client({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('planetscale:Connection', async (it) => { + it('drizzle(client)', async () => { + const client = new Connection({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Client); + expect(db.$client).toBeInstanceOf(Connection); + }); + + it('drizzle(client, config)', async () => { + const client = new Connection({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Client); + expect(db.$client).toBeInstanceOf(Connection); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Connection({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Client); + expect(db.$client).toBeInstanceOf(Connection); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/commonjs/postgres-js.test.cjs b/integration-tests/js-tests/driver-init/commonjs/postgres-js.test.cjs new file mode 100644 index 000000000..da79953f3 --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/postgres-js.test.cjs @@ -0,0 +1,81 @@ +require('dotenv/config'); +const { drizzle } = require('drizzle-orm/postgres-js'); +const pg = require('postgres'); +const { pg: schema } = require('./schema.cjs'); +import { describe, expect } from 'vitest'; + +if (!process.env['PG_CONNECTION_STRING']) { + throw new Error('PG_CONNECTION_STRING is not defined'); +} + +describe('postgres-js', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle(process.env['PG_CONNECTION_STRING']); + + await db.$client.unsafe('SELECT 1;'); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle(process.env['PG_CONNECTION_STRING'], { + schema, + }); + + await db.$client.unsafe('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['PG_CONNECTION_STRING'], + schema, + }); + + await db.$client.unsafe('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + url: process.env['PG_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client.unsafe('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = pg(process.env['PG_CONNECTION_STRING']); + const db = drizzle(client); + + await db.$client.unsafe('SELECT 1;'); + }); + + it('drizzle(client, config)', async () => { + const client = pg(process.env['PG_CONNECTION_STRING']); + const db = drizzle(client, { + schema, + }); + + await db.$client.unsafe('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = pg(process.env['PG_CONNECTION_STRING']); + const db = drizzle({ + client, + schema, + }); + + await db.$client.unsafe('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/commonjs/schema.cjs b/integration-tests/js-tests/driver-init/commonjs/schema.cjs new file mode 100644 index 000000000..7015a068d --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/schema.cjs @@ -0,0 +1,21 @@ +const { int: mysqlInt, mysqlTable } = require('drizzle-orm/mysql-core'); +const { integer: pgInt, pgTable } = require('drizzle-orm/pg-core'); +const { integer: sqliteInt, sqliteTable } = require('drizzle-orm/sqlite-core'); + +module.exports.sqlite = { + User: sqliteTable('test', { + id: sqliteInt('id').primaryKey().notNull(), + }), +}; + +module.exports.pg = { + User: pgTable('test', { + id: pgInt('id').primaryKey().notNull(), + }), +}; + +module.exports.mysql = { + User: mysqlTable('test', { + id: mysqlInt('id').primaryKey().notNull(), + }), +}; diff --git a/integration-tests/js-tests/driver-init/commonjs/tidb.test.cjs b/integration-tests/js-tests/driver-init/commonjs/tidb.test.cjs new file mode 100644 index 000000000..a64588b8a --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/tidb.test.cjs @@ -0,0 +1,88 @@ +require('dotenv/config'); +const { connect } = require('@tidbcloud/serverless'); +const { drizzle } = require('drizzle-orm/tidb-serverless'); +const { mysql: schema } = require('./schema.cjs'); +import { describe, expect } from 'vitest'; + +if (!process.env['TIDB_CONNECTION_STRING']) { + throw new Error('TIDB_CONNECTION_STRING is not defined'); +} + +describe('tidb', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle( + process.env['TIDB_CONNECTION_STRING'], + ); + + await db.$client.execute(`SELECT 1`); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle( + process.env['TIDB_CONNECTION_STRING'], + { + schema, + }, + ); + + await db.$client.execute('SELECT 1;'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['TIDB_CONNECTION_STRING'], + schema, + }); + + await db.$client.execute('SELECT 1;'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + url: process.env['TIDB_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client.execute('SELECT 1;'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = connect({ + url: process.env['TIDB_CONNECTION_STRING'], + }); + + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + }); + + it('drizzle(client, config)', async () => { + const client = connect({ + url: process.env['TIDB_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.execute('SELECT 1;'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = connect({ + url: process.env['TIDB_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.execute('SELECT 1;'); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/commonjs/vercel.test.cjs b/integration-tests/js-tests/driver-init/commonjs/vercel.test.cjs new file mode 100644 index 000000000..ad418a26e --- /dev/null +++ b/integration-tests/js-tests/driver-init/commonjs/vercel.test.cjs @@ -0,0 +1,229 @@ +require('dotenv/config'); +const vc = require('@vercel/postgres'); +const { drizzle } = require('drizzle-orm/vercel-postgres'); +const { pg: schema } = require('./schema.cjs'); +import { describe, expect } from 'vitest'; +const { sql, createClient, createPool } = vc; + +const Pool = vc.VercelPool; +const Client = vc.VercelClient; + +if (!process.env['VERCEL_CONNECTION_STRING']) { + throw new Error('VERCEL_CONNECTION_STRING is not defined'); +} + +// Used for non-pooled connection +if (!process.env['NEON_CONNECTION_STRING']) { + throw new Error('NEON_CONNECTION_STRING is not defined'); +} +process.env['POSTGRES_URL'] = process.env['VERCEL_CONNECTION_STRING']; + +describe('vercel:sql', async (it) => { + it('drizzle()', async () => { + const db = drizzle(); + + await sql.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeTypeOf('function'); + }); + + it('drizzle(client)', async () => { + const db = drizzle(sql); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeTypeOf('function'); + }); + + it('drizzle(client, config)', async () => { + const db = drizzle(sql, { + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeTypeOf('function'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const db = drizzle({ + client: sql, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeTypeOf('function'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({...config})', async () => { + const db = drizzle({ + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeTypeOf('function'); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('vercel:Pool', async (it) => { + it('drizzle(client)', async () => { + const client = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle(client, config)', async () => { + const client = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const db = drizzle({ + client: client, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('vercel:Client', async (it) => { + it('drizzle(client)', async () => { + const client = createClient({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(client, config)', async () => { + const client = createClient({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = createClient({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle({ + client: client, + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('vercel:PoolClient', async (it) => { + it('drizzle(client)', async () => { + const pool = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(client, config)', async () => { + const pool = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const pool = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle({ + client: client, + schema, + }); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/module/better-sqlite3.test.mjs b/integration-tests/js-tests/driver-init/module/better-sqlite3.test.mjs new file mode 100644 index 000000000..063eb958f --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/better-sqlite3.test.mjs @@ -0,0 +1,124 @@ +import 'dotenv/config'; +import Database from 'better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import { describe, expect } from 'vitest'; +import { sqlite as schema } from './schema.mjs'; + +describe('better-sqlite3', async (it) => { + it('drizzle()', async () => { + const db = drizzle(); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + }); + + it('drizzle(string)', async () => { + const db = drizzle(':memory:'); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle(':memory:', { + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: ':memory:', + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + source: ':memory:', + }, + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: {}, ...config})', async () => { + const db = drizzle({ + connection: {}, + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({...config})', async () => { + const db = drizzle({ + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = new Database(':memory:'); + const db = drizzle(client); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + }); + + it('drizzle(client, config)', async () => { + const client = new Database(':memory:'); + const db = drizzle(client, { + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Database(':memory:'); + const db = drizzle({ + client, + schema, + }); + + await db.$client.exec('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/module/libsql.test.mjs b/integration-tests/js-tests/driver-init/module/libsql.test.mjs new file mode 100644 index 000000000..816d0eb0e --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/libsql.test.mjs @@ -0,0 +1,97 @@ +import 'dotenv/config'; +import { createClient } from '@libsql/client'; +import { drizzle } from 'drizzle-orm/libsql'; +import { describe, expect } from 'vitest'; +import { sqlite as schema } from './schema.mjs'; + +describe('libsql', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle(':memory:'); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle(':memory:', { + schema, + }); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: ':memory:', + schema, + }); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + url: ':memory:', + }, + schema, + }); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = createClient({ + url: ':memory:', + }); + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + }); + + it('drizzle(client, config)', async () => { + const client = createClient({ + url: ':memory:', + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = createClient({ + url: ':memory:', + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.execute('SELECT 1;'); + + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/module/mysql2.test.mjs b/integration-tests/js-tests/driver-init/module/mysql2.test.mjs new file mode 100644 index 000000000..1a1565c67 --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/mysql2.test.mjs @@ -0,0 +1,153 @@ +import 'dotenv/config'; +import { drizzle } from 'drizzle-orm/mysql2'; +import { Connection, createConnection, createPool } from 'mysql2'; +import { describe, expect } from 'vitest'; +import { mysql as schema } from './schema.mjs'; + +if (!process.env['MYSQL_CONNECTION_STRING']) { + throw new Error('MYSQL_CONNECTION_STRING is not defined'); +} + +describe('mysql2', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle( + process.env['MYSQL_CONNECTION_STRING'], + ); + + await db.$client.execute(`SELECT 1`); + + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle( + process.env['MYSQL_CONNECTION_STRING'], + { + schema, + mode: 'default', + }, + ); + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['MYSQL_CONNECTION_STRING'], + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + uri: process.env['MYSQL_CONNECTION_STRING'], + }, + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = createPool({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle(client, config)', async () => { + const client = createPool({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = createPool({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const db = drizzle({ + client, + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).not.toStrictEqual(undefined); + }); +}); + +describe('mysql2:connection', async (it) => { + it('drizzle(client)', async () => { + const client = createConnection({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client.getConnection).toStrictEqual(undefined); + }); + + it('drizzle(client, config)', async () => { + const client = createConnection({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = createConnection({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const db = drizzle({ + client, + schema, + mode: 'default', + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client.getConnection).toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/module/neon-http.test.mjs b/integration-tests/js-tests/driver-init/module/neon-http.test.mjs new file mode 100644 index 000000000..b9c07f4d9 --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/neon-http.test.mjs @@ -0,0 +1,92 @@ +import 'dotenv/config'; +import { neon as pg } from '@neondatabase/serverless'; +import { drizzle } from 'drizzle-orm/neon-http'; +import { describe, expect } from 'vitest'; +import { pg as schema } from './schema.mjs'; + +if (!process.env['NEON_CONNECTION_STRING']) { + throw new Error('NEON_CONNECTION_STRING is not defined'); +} + +describe('neon-http', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle( + process.env['NEON_CONNECTION_STRING'], + ); + + await db.$client('SELECT 1;'); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle( + process.env['NEON_CONNECTION_STRING'], + { + schema, + }, + ); + + await db.$client('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['NEON_CONNECTION_STRING'], + schema, + }); + + await db.$client('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + connectionString: process.env['NEON_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = pg( + process.env['NEON_CONNECTION_STRING'], + ); + const db = drizzle(client); + + await db.$client('SELECT 1;'); + }); + + it('drizzle(client, config)', async () => { + const client = pg( + process.env['NEON_CONNECTION_STRING'], + ); + const db = drizzle(client, { + schema, + }); + + await db.$client('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = pg( + process.env['NEON_CONNECTION_STRING'], + ); + const db = drizzle({ + client, + schema, + }); + + await db.$client('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/module/neon-ws.test.mjs b/integration-tests/js-tests/driver-init/module/neon-ws.test.mjs new file mode 100644 index 000000000..5a045b76a --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/neon-ws.test.mjs @@ -0,0 +1,211 @@ +import 'dotenv/config'; +import { Client, neonConfig, Pool } from '@neondatabase/serverless'; +import { drizzle } from 'drizzle-orm/neon-serverless'; +import { describe, expect } from 'vitest'; +import ws from 'ws'; +import { pg as schema } from './schema.mjs'; + +neonConfig.webSocketConstructor = ws; + +if (!process.env['NEON_CONNECTION_STRING']) { + throw new Error('NEON_CONNECTION_STRING is not defined'); +} + +describe('neon-ws', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle( + process.env['NEON_CONNECTION_STRING'], + ); + + await db.$client.query('SELECT 1;'); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle( + process.env['NEON_CONNECTION_STRING'], + { + schema, + }, + ); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['NEON_CONNECTION_STRING'], + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + connectionString: process.env['NEON_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle(client)', async () => { + const client = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle(client, config)', async () => { + const client = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Pool); + }); +}); + +describe('neon-ws:Client', async (it) => { + it('drizzle(client)', async () => { + const client = new Client({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + + await client.connect(); + + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); + + it('drizzle(client, config)', async () => { + const client = new Client({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Client({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); +}); + +describe('neon-ws:PoolClient', async (it) => { + it('drizzle(client)', async () => { + const pool = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + + client.release(); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); + + it('drizzle(client, config)', async () => { + const pool = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + + client.release(); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); + + it('drizzle({client, ...config})', async () => { + const pool = new Pool({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle({ + client, + schema, + }); + + await db.$client.query('SELECT 1;'); + + client.release(); + + expect(db.query.User).not.toStrictEqual(undefined); + expect(db.$client).toBeInstanceOf(Client); + expect(db.$client).not.toBeInstanceOf(Pool); + }); +}); diff --git a/integration-tests/js-tests/driver-init/module/node-pg.test.mjs b/integration-tests/js-tests/driver-init/module/node-pg.test.mjs new file mode 100644 index 000000000..75dd391f1 --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/node-pg.test.mjs @@ -0,0 +1,201 @@ +import 'dotenv/config'; +import { drizzle } from 'drizzle-orm/node-postgres'; +import pg from 'pg'; +import { describe, expect } from 'vitest'; +import { pg as schema } from './schema.mjs'; + +const Pool = pg.Pool; +const Client = pg.Client; + +if (!process.env['PG_CONNECTION_STRING']) { + throw new Error('PG_CONNECTION_STRING is not defined'); +} + +describe('node-pg', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle(process.env['PG_CONNECTION_STRING']); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle(process.env['PG_CONNECTION_STRING'], { + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['PG_CONNECTION_STRING'], + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + connectionString: process.env['PG_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle(client, config)', async () => { + const client = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('node-pg:Client', async (it) => { + it('drizzle(client)', async () => { + const client = new Client({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(client, config)', async () => { + const client = new Client({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Client({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('node-pg:PoolClient', async (it) => { + it('drizzle(client)', async () => { + const pool = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const client = await pool.connect(); + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(client, config)', async () => { + const pool = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const client = await pool.connect(); + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const pool = new Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + const client = await pool.connect(); + const db = drizzle({ + client, + schema, + }); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/module/pglite.test.mjs b/integration-tests/js-tests/driver-init/module/pglite.test.mjs new file mode 100644 index 000000000..bb67f383b --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/pglite.test.mjs @@ -0,0 +1,88 @@ +import 'dotenv/config'; +import { PGlite as Database } from '@electric-sql/pglite'; +import { drizzle } from 'drizzle-orm/pglite'; +import { describe, expect } from 'vitest'; +import { pg as schema } from './schema.mjs'; + +describe('pglite', async (it) => { + it('drizzle()', async () => { + const db = drizzle(); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + }); + + it('drizzle(string)', async () => { + const db = drizzle('memory://'); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle('memory://', { + schema, + }); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: {}, ...config})', async () => { + const db = drizzle({ + connection: {}, + schema, + }); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({...config})', async () => { + const db = drizzle({ + schema, + }); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = new Database('memory://'); + const db = drizzle(client); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + }); + + it('drizzle(client, config)', async () => { + const client = new Database('memory://'); + const db = drizzle(client, { + schema, + }); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Database('memory://'); + const db = drizzle({ + client, + schema, + }); + + await db.$client.exec('SELECT 1;'); + await db.$client.close(); + + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/module/planetscale.test.mjs b/integration-tests/js-tests/driver-init/module/planetscale.test.mjs new file mode 100644 index 000000000..c56537b06 --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/planetscale.test.mjs @@ -0,0 +1,146 @@ +import 'dotenv/config'; +import { Client, Connection } from '@planetscale/database'; +import { drizzle } from 'drizzle-orm/planetscale-serverless'; +import { describe, expect } from 'vitest'; +import { mysql as schema } from './schema.mjs'; + +if (!process.env['PLANETSCALE_CONNECTION_STRING']) { + throw new Error('PLANETSCALE_CONNECTION_STRING is not defined'); +} + +describe('planetscale', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle( + process.env['PLANETSCALE_CONNECTION_STRING'], + ); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle( + process.env['PLANETSCALE_CONNECTION_STRING'], + { + schema, + }, + ); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['PLANETSCALE_CONNECTION_STRING'], + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = new Client({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(client, config)', async () => { + const client = new Client({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Client({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('planetscale:Connection', async (it) => { + it('drizzle(client)', async () => { + const client = new Connection({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Client); + expect(db.$client).toBeInstanceOf(Connection); + }); + + it('drizzle(client, config)', async () => { + const client = new Connection({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Client); + expect(db.$client).toBeInstanceOf(Connection); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = new Connection({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.execute('SELECT 1;'); + + expect(db.$client).not.toBeInstanceOf(Client); + expect(db.$client).toBeInstanceOf(Connection); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/module/postgres-js.test.mjs b/integration-tests/js-tests/driver-init/module/postgres-js.test.mjs new file mode 100644 index 000000000..40925aceb --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/postgres-js.test.mjs @@ -0,0 +1,81 @@ +import 'dotenv/config'; +import { drizzle } from 'drizzle-orm/postgres-js'; +import pg from 'postgres'; +import { describe, expect } from 'vitest'; +import { pg as schema } from './schema.mjs'; + +if (!process.env['PG_CONNECTION_STRING']) { + throw new Error('PG_CONNECTION_STRING is not defined'); +} + +describe('postgres-js', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle(process.env['PG_CONNECTION_STRING']); + + await db.$client.unsafe('SELECT 1;'); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle(process.env['PG_CONNECTION_STRING'], { + schema, + }); + + await db.$client.unsafe('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['PG_CONNECTION_STRING'], + schema, + }); + + await db.$client.unsafe('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + url: process.env['PG_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client.unsafe('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = pg(process.env['PG_CONNECTION_STRING']); + const db = drizzle(client); + + await db.$client.unsafe('SELECT 1;'); + }); + + it('drizzle(client, config)', async () => { + const client = pg(process.env['PG_CONNECTION_STRING']); + const db = drizzle(client, { + schema, + }); + + await db.$client.unsafe('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = pg(process.env['PG_CONNECTION_STRING']); + const db = drizzle({ + client, + schema, + }); + + await db.$client.unsafe('SELECT 1;'); + + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/module/schema.mjs b/integration-tests/js-tests/driver-init/module/schema.mjs new file mode 100644 index 000000000..9c0d4d689 --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/schema.mjs @@ -0,0 +1,21 @@ +import { int as mysqlInt, mysqlTable } from 'drizzle-orm/mysql-core'; +import { integer as pgInt, pgTable } from 'drizzle-orm/pg-core'; +import { integer as sqliteInt, sqliteTable } from 'drizzle-orm/sqlite-core'; + +export const sqlite = { + User: sqliteTable('test', { + id: sqliteInt('id').primaryKey().notNull(), + }), +}; + +export const pg = { + User: pgTable('test', { + id: pgInt('id').primaryKey().notNull(), + }), +}; + +export const mysql = { + User: mysqlTable('test', { + id: mysqlInt('id').primaryKey().notNull(), + }), +}; diff --git a/integration-tests/js-tests/driver-init/module/tidb.test.mjs b/integration-tests/js-tests/driver-init/module/tidb.test.mjs new file mode 100644 index 000000000..0cd62f00a --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/tidb.test.mjs @@ -0,0 +1,88 @@ +import 'dotenv/config'; +import { connect } from '@tidbcloud/serverless'; +import { drizzle } from 'drizzle-orm/tidb-serverless'; +import { describe, expect } from 'vitest'; +import { mysql as schema } from './schema.mjs'; + +if (!process.env['TIDB_CONNECTION_STRING']) { + throw new Error('TIDB_CONNECTION_STRING is not defined'); +} + +describe('tidb', async (it) => { + it('drizzle(string)', async () => { + const db = drizzle( + process.env['TIDB_CONNECTION_STRING'], + ); + + await db.$client.execute(`SELECT 1`); + }); + + it('drizzle(string, config)', async () => { + const db = drizzle( + process.env['TIDB_CONNECTION_STRING'], + { + schema, + }, + ); + + await db.$client.execute('SELECT 1;'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: string, ...config})', async () => { + const db = drizzle({ + connection: process.env['TIDB_CONNECTION_STRING'], + schema, + }); + + await db.$client.execute('SELECT 1;'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({connection: params, ...config})', async () => { + const db = drizzle({ + connection: { + url: process.env['TIDB_CONNECTION_STRING'], + }, + schema, + }); + + await db.$client.execute('SELECT 1;'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle(client)', async () => { + const client = connect({ + url: process.env['TIDB_CONNECTION_STRING'], + }); + + const db = drizzle(client); + + await db.$client.execute('SELECT 1;'); + }); + + it('drizzle(client, config)', async () => { + const client = connect({ + url: process.env['TIDB_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.execute('SELECT 1;'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = connect({ + url: process.env['TIDB_CONNECTION_STRING'], + }); + const db = drizzle({ + client, + schema, + }); + + await db.$client.execute('SELECT 1;'); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/js-tests/driver-init/module/vercel.test.mjs b/integration-tests/js-tests/driver-init/module/vercel.test.mjs new file mode 100644 index 000000000..0ef7c460e --- /dev/null +++ b/integration-tests/js-tests/driver-init/module/vercel.test.mjs @@ -0,0 +1,229 @@ +import 'dotenv/config'; +import { createClient, createPool, sql, VercelClient, VercelPool } from '@vercel/postgres'; +import { drizzle } from 'drizzle-orm/vercel-postgres'; +import { describe, expect } from 'vitest'; +import { pg as schema } from './schema.mjs'; + +const Pool = VercelPool; +const Client = VercelClient; + +if (!process.env['VERCEL_CONNECTION_STRING']) { + throw new Error('VERCEL_CONNECTION_STRING is not defined'); +} + +// Used for non-pooled connection +if (!process.env['NEON_CONNECTION_STRING']) { + throw new Error('NEON_CONNECTION_STRING is not defined'); +} + +process.env['POSTGRES_URL'] = process.env['VERCEL_CONNECTION_STRING']; + +describe('vercel:sql', async (it) => { + it('drizzle()', async () => { + const db = drizzle(); + + await sql.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeTypeOf('function'); + }); + + it('drizzle(client)', async () => { + const db = drizzle(sql); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeTypeOf('function'); + }); + + it('drizzle(client, config)', async () => { + const db = drizzle(sql, { + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeTypeOf('function'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const db = drizzle({ + client: sql, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeTypeOf('function'); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({...config})', async () => { + const db = drizzle({ + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).toBeTypeOf('function'); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('vercel:Pool', async (it) => { + it('drizzle(client)', async () => { + const client = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).toBeInstanceOf(Pool); + }); + + it('drizzle(client, config)', async () => { + const client = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const db = drizzle({ + client: client, + schema, + }); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).toBeInstanceOf(Pool); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('vercel:Client', async (it) => { + it('drizzle(client)', async () => { + const client = createClient({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle(client); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(client, config)', async () => { + const client = createClient({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle(client, { + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const client = createClient({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + const db = drizzle({ + client: client, + schema, + }); + + await client.connect(); + + await db.$client.query('SELECT 1;'); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); + +describe('vercel:PoolClient', async (it) => { + it('drizzle(client)', async () => { + const pool = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle(client); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + }); + + it('drizzle(client, config)', async () => { + const pool = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle(client, { + schema, + }); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); + + it('drizzle({client, ...config})', async () => { + const pool = createPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + const client = await pool.connect(); + + const db = drizzle({ + client: client, + schema, + }); + + await db.$client.query('SELECT 1;'); + client.release(); + + expect(db.$client).not.toBeTypeOf('function'); + expect(db.$client).not.toBeInstanceOf(Pool); + expect(db.$client).toBeInstanceOf(Client); + expect(db.query.User).not.toStrictEqual(undefined); + }); +}); diff --git a/integration-tests/package.json b/integration-tests/package.json index 2b26ec374..775103111 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -43,7 +43,7 @@ "dependencies": { "@aws-sdk/client-rds-data": "^3.549.0", "@aws-sdk/credential-providers": "^3.549.0", - "@electric-sql/pglite": "^0.1.1", + "@electric-sql/pglite": "^0.2.12", "@miniflare/d1": "^2.14.4", "@miniflare/shared": "^2.14.4", "@planetscale/database": "^1.16.0", diff --git a/integration-tests/tests/utils/is-config.test.ts b/integration-tests/tests/utils/is-config.test.ts new file mode 100644 index 000000000..5e55aaa08 --- /dev/null +++ b/integration-tests/tests/utils/is-config.test.ts @@ -0,0 +1,298 @@ +import 'dotenv/config'; +import { PGlite as pglite } from '@electric-sql/pglite'; +import { createClient as libsql } from '@libsql/client'; +import { Client as neonClient, neon, neonConfig, Pool as neonPool } from '@neondatabase/serverless'; +import { connect as planetscale } from '@planetscale/database'; +import { connect as tidb } from '@tidbcloud/serverless'; +import { createClient as vcClient, createPool as vcPool, sql as vcSql } from '@vercel/postgres'; +import betterSqlite3 from 'better-sqlite3'; +import { type DrizzleConfig, isConfig } from 'drizzle-orm'; +import { createConnection as ms2Connection, createPool as ms2Pool } from 'mysql2'; +import { createConnection as ms2pConnection, createPool as ms2pPool } from 'mysql2/promise'; +import pg from 'pg'; +import postgres from 'postgres'; +import { describe, expect } from 'vitest'; +import ws from 'ws'; + +neonConfig.webSocketConstructor = ws; + +if ( + !process.env['PG_CONNECTION_STRING'] || !process.env['MYSQL_CONNECTION_STRING'] + || !process.env['PLANETSCALE_CONNECTION_STRING'] || !process.env['TIDB_CONNECTION_STRING'] + || !process.env['NEON_CONNECTION_STRING'] || !process.env['VERCEL_CONNECTION_STRING'] +) { + throw new Error('process.env is missing some connection strings!'); +} + +process.env['POSTGRES_URL'] = process.env['VERCEL_CONNECTION_STRING']; + +describe('Objects', (it) => { + it('Passes configs', () => { + expect(isConfig({} as DrizzleConfig)).toEqual(true); + + expect( + isConfig({ + casing: 'camelCase', + } as DrizzleConfig), + ).toEqual(true); + + expect( + isConfig({ + logger: true, + } as DrizzleConfig), + ).toEqual(true); + + expect( + isConfig({ + logger: { + logQuery: () => {}, + }, + } as DrizzleConfig), + ).toEqual(true); + + expect( + isConfig({ + schema: { + any: true, + }, + } as DrizzleConfig), + ).toEqual(true); + + expect( + isConfig({ + casing: 'camelCase', + logger: true, + schema: { + any: true, + }, + } as DrizzleConfig), + ).toEqual(true); + + expect( + isConfig({ + casing: 'camelCase', + trash: true, + } as DrizzleConfig), + ).toEqual(true); + }); + + it('Rejects non-configs', () => { + expect(isConfig('')).toEqual(false); + + expect(isConfig('data')).toEqual(false); + + expect(isConfig(true)).toEqual(false); + + expect(isConfig(false)).toEqual(false); + + expect(isConfig(null)).toEqual(false); + + expect(isConfig(undefined)).toEqual(false); + + expect(isConfig(5)).toEqual(false); + + expect(isConfig(BigInt(5))).toEqual(false); + + expect(isConfig(new Date())).toEqual(false); + + expect( + isConfig({ + trash: true, + } as DrizzleConfig), + ).toEqual(false); + }); +}); + +describe('Rejects drivers', (it) => { + it('libsql', () => { + const cl = libsql({ + url: ':memory:', + }); + + expect(isConfig(cl)).toEqual(false); + }); + + it('better-sqlite3', () => { + const cl = new betterSqlite3(':memory:'); + + expect(isConfig(cl)).toEqual(false); + }); + + it('pglite', () => { + const cl = new pglite('memory://'); + + expect(isConfig(cl)).toEqual(false); + }); + + it('node-postgres:Pool', () => { + const cl = new pg.Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + + expect(isConfig(cl)).toEqual(false); + }); + + it('node-postgres:Client', async () => { + const cl = new pg.Client({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + + const res = isConfig(cl); + + await cl.end(); + + expect(res).toEqual(false); + }); + + it('node-postgres:PoolClient', async () => { + const cl = new pg.Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + + const con = await cl.connect(); + + const res = isConfig(con); + + con.release(); + + expect(res).toEqual(false); + }); + + it('postgres-js', () => { + const cl = postgres(process.env['PG_CONNECTION_STRING']!); + + expect(isConfig(cl)).toEqual(false); + }); + + it('vercel:sql', () => { + expect(isConfig(vcSql)).toEqual(false); + }); + + it('vercel:Pool', () => { + const cl = vcPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + + expect(isConfig(cl)).toEqual(false); + }); + + it('vercel:Client', async () => { + const cl = vcClient({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + + const res = isConfig(cl); + + expect(res).toEqual(false); + }); + + it('vercel:PoolClient', async () => { + const cl = vcPool({ + connectionString: process.env['VERCEL_CONNECTION_STRING'], + }); + + const con = await cl.connect(); + + const res = isConfig(con); + + con.release(); + + expect(res).toEqual(false); + }); + + it('neon-serverless:Pool', async () => { + const cl = new neonPool({ + connectionString: process.env['NEON_CONNECTION_STRING']!, + }); + + expect(isConfig(cl)).toEqual(false); + }); + + it('neon-serverless:Client', async () => { + const cl = new neonClient({ + connectionString: process.env['NEON_CONNECTION_STRING']!, + }); + + const res = isConfig(cl); + + await cl.end(); + + expect(res).toEqual(false); + }); + + it('neon-serverless:PoolClient', async () => { + const cl = new neonPool({ + connectionString: process.env['NEON_CONNECTION_STRING']!, + }); + + const con = await cl.connect(); + + const res = isConfig(con); + + con.release(); + + expect(res).toEqual(false); + }); + + it('neon-http', async () => { + const cl = neon(process.env['NEON_CONNECTION_STRING']!); + + expect(isConfig(cl)).toEqual(false); + }); + + it('planetscale', async () => { + const cl = planetscale({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + + expect(isConfig(cl)).toEqual(false); + }); + + it('mysql2:Pool', async () => { + const cl = ms2Pool({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + expect(isConfig(cl)).toEqual(false); + }); + + it('mysql2:Connection', async () => { + const cl = ms2Connection({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + expect(isConfig(cl)).toEqual(false); + }); + + it('mysql2/promise:Pool', async () => { + const cl = await ms2pPool({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const res = isConfig(cl); + + await cl.end(); + + expect(res).toEqual(false); + }); + + it('mysql2/promise:Connection', async () => { + const cl = await ms2pConnection({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const res = isConfig(cl); + + await cl.end(); + + expect(res).toEqual(false); + }); + + it('tidb', async () => { + const cl = tidb({ + url: process.env['TIDB_CONNECTION_STRING'], + }); + + expect(isConfig(cl)).toEqual(false); + }); +}); diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 3952eca49..1b07615b5 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -15,6 +15,9 @@ export default defineConfig({ 'tests/extensions/vectors/**/*', 'tests/version.test.ts', 'tests/pg/node-postgres.test.ts', + 'tests/utils/is-config.test.ts', + 'js-tests/driver-init/commonjs/*.test.cjs', + 'js-tests/driver-init/module/*.test.mjs', ], exclude: [ ...(process.env.SKIP_EXTERNAL_DB_TESTS @@ -28,6 +31,17 @@ export default defineConfig({ 'tests/sqlite/libsql-batch.test.ts', 'tests/pg/neon-http.test.ts', 'tests/pg/neon-http-batch.test.ts', + 'tests/utils/is-config.test.ts', // Uses external DBs in some cases + 'tests/driver-init/commonjs/neon-http.test.cjs', + 'tests/driver-init/commonjs/neon-ws.test.cjs', + 'tests/driver-init/commonjs/planetscale.test.cjs', + 'tests/driver-init/commonjs/tidb.test.cjs', + 'tests/driver-init/commonjs/vercel.test.cjs', + 'tests/driver-init/module/neon-http.test.mjs', + 'tests/driver-init/module/neon-ws.test.mjs', + 'tests/driver-init/module/planetscale.test.mjs', + 'tests/driver-init/module/tidb.test.mjs', + 'tests/driver-init/module/vercel.test.mjs', ] : []), 'tests/pg/awsdatapi.test.ts', @@ -37,6 +51,9 @@ export default defineConfig({ // Have a strange "invalid SQL: ERROR: must be owner of schema public" error. Will need to check with xata team 'tests/pg/xata-http.test.ts', 'tests/pg/neon-http-batch.ts', + // todo: remove + 'tests/driver-init/module/vercel.test.mjs', + 'tests/driver-init/commonjs/vercel.test.cjs', ], typecheck: { tsconfig: 'tsconfig.json', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2400e16d..39e4d5c44 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -109,8 +109,8 @@ importers: specifier: ^4.20230518.0 version: 4.20240524.0 '@electric-sql/pglite': - specifier: ^0.1.5 - version: 0.1.5 + specifier: ^0.2.12 + version: 0.2.12 '@hono/node-server': specifier: ^1.9.0 version: 1.12.0 @@ -298,8 +298,8 @@ importers: specifier: ^4.20230904.0 version: 4.20240512.0 '@electric-sql/pglite': - specifier: ^0.1.1 - version: 0.1.5 + specifier: ^0.2.12 + version: 0.2.12 '@libsql/client': specifier: ^0.10.0 version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) @@ -548,10 +548,10 @@ importers: version: 3.583.0 '@aws-sdk/credential-providers': specifier: ^3.549.0 - version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0) '@electric-sql/pglite': - specifier: ^0.1.1 - version: 0.1.5 + specifier: ^0.2.12 + version: 0.2.12 '@miniflare/d1': specifier: ^2.14.4 version: 2.14.4 @@ -1993,8 +1993,8 @@ packages: '@drizzle-team/studio@0.0.5': resolution: {integrity: sha512-ps5qF0tMxWRVu+V5gvCRrQNqlY92aTnIKdq27gm9LZMSdaKYZt6AVvSK1dlUMzs6Rt0Jm80b+eWct6xShBKhIw==} - '@electric-sql/pglite@0.1.5': - resolution: {integrity: sha512-eymv4ONNvoPZQTvOQIi5dbpR+J5HzEv0qQH9o/y3gvNheJV/P/NFcrbsfJZYTsDKoq7DKrTiFNexsRkJKy8x9Q==} + '@electric-sql/pglite@0.2.12': + resolution: {integrity: sha512-J/X42ujcoFEbOkgRyoNqZB5qcqrnJRWVlwpH3fKYoJkTz49N91uAK/rDSSG/85WRas9nC9mdV4FnMTxnQWE/rw==} '@esbuild-kit/core-utils@3.1.0': resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} @@ -10911,12 +10911,12 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -10999,13 +10999,13 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -11086,10 +11086,10 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-sso': 3.568.0 - '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11143,7 +11143,7 @@ snapshots: '@smithy/types': 3.0.0 tslib: 2.6.2 - '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-cognito-identity': 3.569.0 '@aws-sdk/client-sso': 3.568.0 @@ -11151,10 +11151,10 @@ snapshots: '@aws-sdk/credential-provider-cognito-identity': 3.569.0 '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -11336,7 +11336,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.567.0 @@ -12493,7 +12493,7 @@ snapshots: '@drizzle-team/studio@0.0.5': {} - '@electric-sql/pglite@0.1.5': {} + '@electric-sql/pglite@0.2.12': {} '@esbuild-kit/core-utils@3.1.0': dependencies: From 4c0beffd89f4c8241b33245cf966dfbc7780eac8 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 18 Oct 2024 13:11:57 +0300 Subject: [PATCH 255/492] Skip vercel and fix pglite --- integration-tests/tests/pg/pglite.test.ts | 4 ++ .../tests/utils/is-config.test.ts | 38 ++++++++++--------- integration-tests/vitest.config.ts | 24 ++++++------ pnpm-lock.yaml | 26 ++++++------- 4 files changed, 49 insertions(+), 43 deletions(-) diff --git a/integration-tests/tests/pg/pglite.test.ts b/integration-tests/tests/pg/pglite.test.ts index 37cd3fe62..2a3d6a2ff 100644 --- a/integration-tests/tests/pg/pglite.test.ts +++ b/integration-tests/tests/pg/pglite.test.ts @@ -86,6 +86,10 @@ skipTests([ 'subquery with view', 'mySchema :: materialized view', 'select count()', + // not working in 0.2.12 + 'select with group by as sql + column', + 'select with group by as column + sql', + 'mySchema :: select with group by as column + sql', ]); tests(); diff --git a/integration-tests/tests/utils/is-config.test.ts b/integration-tests/tests/utils/is-config.test.ts index 5e55aaa08..e3d8d95e8 100644 --- a/integration-tests/tests/utils/is-config.test.ts +++ b/integration-tests/tests/utils/is-config.test.ts @@ -4,7 +4,7 @@ import { createClient as libsql } from '@libsql/client'; import { Client as neonClient, neon, neonConfig, Pool as neonPool } from '@neondatabase/serverless'; import { connect as planetscale } from '@planetscale/database'; import { connect as tidb } from '@tidbcloud/serverless'; -import { createClient as vcClient, createPool as vcPool, sql as vcSql } from '@vercel/postgres'; +import { createClient as vcClient, sql as vcSql } from '@vercel/postgres'; import betterSqlite3 from 'better-sqlite3'; import { type DrizzleConfig, isConfig } from 'drizzle-orm'; import { createConnection as ms2Connection, createPool as ms2Pool } from 'mysql2'; @@ -19,12 +19,14 @@ neonConfig.webSocketConstructor = ws; if ( !process.env['PG_CONNECTION_STRING'] || !process.env['MYSQL_CONNECTION_STRING'] || !process.env['PLANETSCALE_CONNECTION_STRING'] || !process.env['TIDB_CONNECTION_STRING'] - || !process.env['NEON_CONNECTION_STRING'] || !process.env['VERCEL_CONNECTION_STRING'] + || !process.env['NEON_CONNECTION_STRING'] + // todo get back after we will have a pool for vercel + // || !process.env['VERCEL_CONNECTION_STRING'] ) { throw new Error('process.env is missing some connection strings!'); } -process.env['POSTGRES_URL'] = process.env['VERCEL_CONNECTION_STRING']; +// process.env['POSTGRES_URL'] = process.env['VERCEL_CONNECTION_STRING']; describe('Objects', (it) => { it('Passes configs', () => { @@ -168,13 +170,13 @@ describe('Rejects drivers', (it) => { expect(isConfig(vcSql)).toEqual(false); }); - it('vercel:Pool', () => { - const cl = vcPool({ - connectionString: process.env['VERCEL_CONNECTION_STRING'], - }); + // it('vercel:Pool', () => { + // const cl = vcPool({ + // connectionString: process.env['VERCEL_CONNECTION_STRING'], + // }); - expect(isConfig(cl)).toEqual(false); - }); + // expect(isConfig(cl)).toEqual(false); + // }); it('vercel:Client', async () => { const cl = vcClient({ @@ -186,19 +188,19 @@ describe('Rejects drivers', (it) => { expect(res).toEqual(false); }); - it('vercel:PoolClient', async () => { - const cl = vcPool({ - connectionString: process.env['VERCEL_CONNECTION_STRING'], - }); + // it('vercel:PoolClient', async () => { + // const cl = vcPool({ + // connectionString: process.env['VERCEL_CONNECTION_STRING'], + // }); - const con = await cl.connect(); + // const con = await cl.connect(); - const res = isConfig(con); + // const res = isConfig(con); - con.release(); + // con.release(); - expect(res).toEqual(false); - }); + // expect(res).toEqual(false); + // }); it('neon-serverless:Pool', async () => { const cl = new neonPool({ diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 1b07615b5..118f91234 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -32,16 +32,16 @@ export default defineConfig({ 'tests/pg/neon-http.test.ts', 'tests/pg/neon-http-batch.test.ts', 'tests/utils/is-config.test.ts', // Uses external DBs in some cases - 'tests/driver-init/commonjs/neon-http.test.cjs', - 'tests/driver-init/commonjs/neon-ws.test.cjs', - 'tests/driver-init/commonjs/planetscale.test.cjs', - 'tests/driver-init/commonjs/tidb.test.cjs', - 'tests/driver-init/commonjs/vercel.test.cjs', - 'tests/driver-init/module/neon-http.test.mjs', - 'tests/driver-init/module/neon-ws.test.mjs', - 'tests/driver-init/module/planetscale.test.mjs', - 'tests/driver-init/module/tidb.test.mjs', - 'tests/driver-init/module/vercel.test.mjs', + 'tests/js-tests/driver-init/commonjs/neon-http.test.cjs', + 'tests/js-tests/driver-init/commonjs/neon-ws.test.cjs', + 'tests/js-tests/driver-init/commonjs/planetscale.test.cjs', + 'tests/js-tests/driver-init/commonjs/tidb.test.cjs', + 'tests/js-tests/driver-init/commonjs/vercel.test.cjs', + 'tests/js-tests/driver-init/module/neon-http.test.mjs', + 'tests/js-tests/driver-init/module/neon-ws.test.mjs', + 'tests/js-tests/driver-init/module/planetscale.test.mjs', + 'tests/js-tests/driver-init/module/tidb.test.mjs', + 'tests/js-tests/driver-init/module/vercel.test.mjs', ] : []), 'tests/pg/awsdatapi.test.ts', @@ -52,8 +52,8 @@ export default defineConfig({ 'tests/pg/xata-http.test.ts', 'tests/pg/neon-http-batch.ts', // todo: remove - 'tests/driver-init/module/vercel.test.mjs', - 'tests/driver-init/commonjs/vercel.test.cjs', + 'tests/js-tests/driver-init/module/vercel.test.mjs', + 'tests/js-tests/driver-init/commonjs/vercel.test.cjs', ], typecheck: { tsconfig: 'tsconfig.json', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39e4d5c44..c064253b8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -548,7 +548,7 @@ importers: version: 3.583.0 '@aws-sdk/credential-providers': specifier: ^3.549.0 - version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0) + version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@electric-sql/pglite': specifier: ^0.2.12 version: 0.2.12 @@ -10911,12 +10911,12 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -10999,13 +10999,13 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -11086,10 +11086,10 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': dependencies: '@aws-sdk/client-sso': 3.568.0 - '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11143,7 +11143,7 @@ snapshots: '@smithy/types': 3.0.0 tslib: 2.6.2 - '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': dependencies: '@aws-sdk/client-cognito-identity': 3.569.0 '@aws-sdk/client-sso': 3.568.0 @@ -11151,10 +11151,10 @@ snapshots: '@aws-sdk/credential-provider-cognito-identity': 3.569.0 '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -11336,7 +11336,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': dependencies: '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.567.0 From 6c4c3c50d3d6d4dda421c514c76e66c400120264 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 18 Oct 2024 13:53:04 +0300 Subject: [PATCH 256/492] Fix ignores in vitest --- integration-tests/vitest.config.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 118f91234..5465c4047 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -32,16 +32,16 @@ export default defineConfig({ 'tests/pg/neon-http.test.ts', 'tests/pg/neon-http-batch.test.ts', 'tests/utils/is-config.test.ts', // Uses external DBs in some cases - 'tests/js-tests/driver-init/commonjs/neon-http.test.cjs', - 'tests/js-tests/driver-init/commonjs/neon-ws.test.cjs', - 'tests/js-tests/driver-init/commonjs/planetscale.test.cjs', - 'tests/js-tests/driver-init/commonjs/tidb.test.cjs', - 'tests/js-tests/driver-init/commonjs/vercel.test.cjs', - 'tests/js-tests/driver-init/module/neon-http.test.mjs', - 'tests/js-tests/driver-init/module/neon-ws.test.mjs', - 'tests/js-tests/driver-init/module/planetscale.test.mjs', - 'tests/js-tests/driver-init/module/tidb.test.mjs', - 'tests/js-tests/driver-init/module/vercel.test.mjs', + 'js-tests/driver-init/commonjs/neon-http.test.cjs', + 'js-tests/driver-init/commonjs/neon-ws.test.cjs', + 'js-tests/driver-init/commonjs/planetscale.test.cjs', + 'js-tests/driver-init/commonjs/tidb.test.cjs', + 'js-tests/driver-init/commonjs/vercel.test.cjs', + 'js-tests/driver-init/module/neon-http.test.mjs', + 'js-tests/driver-init/module/neon-ws.test.mjs', + 'js-tests/driver-init/module/planetscale.test.mjs', + 'js-tests/driver-init/module/tidb.test.mjs', + 'js-tests/driver-init/module/vercel.test.mjs', ] : []), 'tests/pg/awsdatapi.test.ts', @@ -52,8 +52,8 @@ export default defineConfig({ 'tests/pg/xata-http.test.ts', 'tests/pg/neon-http-batch.ts', // todo: remove - 'tests/js-tests/driver-init/module/vercel.test.mjs', - 'tests/js-tests/driver-init/commonjs/vercel.test.cjs', + 'js-tests/driver-init/module/vercel.test.mjs', + 'js-tests/driver-init/commonjs/vercel.test.cjs', ], typecheck: { tsconfig: 'tsconfig.json', From 0fcf975a8566341c758984859204da29e059c202 Mon Sep 17 00:00:00 2001 From: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:02:45 +0300 Subject: [PATCH 257/492] Split libsql (#3170) * Separated different libsql versions into different import paths, adapted tests, added `@libsql/client-wasm` peer and dev dep * Switched default libsql driver initializer to new initializer type, adapted tests * Fixed tests * Excluded ESM-only libsql/wasm package from CJS import tests * Tests for libsql submodules * Fixed imports in tests * Added remote libsql envs * Modified workflows to include required env params * Modified tests for `libsql/http`,`libsql/ws` * Crash prevention on tests after failed view tests in sqlite, increased msDelay for `libsql/ws`/`libsql/http` tests * Add 0.35.3 version release notes * Fixed planetscale driver rejecting `Connection` on type level * No Connection in planetscale, only client * Remove connection tests --------- Co-authored-by: AndriiSherman --- .github/workflows/release-feature-branch.yaml | 2 + .github/workflows/release-latest.yaml | 2 + changelogs/drizzle-orm/0.35.3.md | 80 ++++++++ drizzle-orm/package.json | 4 +- drizzle-orm/src/libsql/driver-core.ts | 64 ++++++ drizzle-orm/src/libsql/driver.ts | 64 +----- drizzle-orm/src/libsql/http/index.ts | 62 ++++++ drizzle-orm/src/libsql/node/index.ts | 62 ++++++ drizzle-orm/src/libsql/sqlite3/index.ts | 62 ++++++ drizzle-orm/src/libsql/wasm/index.ts | 62 ++++++ drizzle-orm/src/libsql/web/index.ts | 62 ++++++ drizzle-orm/src/libsql/ws/index.ts | 62 ++++++ .../src/planetscale-serverless/driver.ts | 23 +-- integration-tests/.env.example | 2 + .../driver-init/commonjs/planetscale.test.cjs | 47 +---- .../driver-init/module/planetscale.test.mjs | 47 +---- integration-tests/tests/imports/index.test.ts | 2 +- .../tests/sqlite/libsql-http.test.ts | 186 +++++++++++++++++ .../tests/sqlite/libsql-node.test.ts | 97 +++++++++ .../tests/sqlite/libsql-sqlite3.test.ts | 97 +++++++++ .../tests/sqlite/libsql-ws.test.ts | 187 ++++++++++++++++++ .../tests/sqlite/sqlite-common.ts | 6 +- pnpm-lock.yaml | 155 ++++++++------- 23 files changed, 1189 insertions(+), 248 deletions(-) create mode 100644 changelogs/drizzle-orm/0.35.3.md create mode 100644 drizzle-orm/src/libsql/driver-core.ts create mode 100644 drizzle-orm/src/libsql/http/index.ts create mode 100644 drizzle-orm/src/libsql/node/index.ts create mode 100644 drizzle-orm/src/libsql/sqlite3/index.ts create mode 100644 drizzle-orm/src/libsql/wasm/index.ts create mode 100644 drizzle-orm/src/libsql/web/index.ts create mode 100644 drizzle-orm/src/libsql/ws/index.ts create mode 100644 integration-tests/tests/sqlite/libsql-http.test.ts create mode 100644 integration-tests/tests/sqlite/libsql-node.test.ts create mode 100644 integration-tests/tests/sqlite/libsql-sqlite3.test.ts create mode 100644 integration-tests/tests/sqlite/libsql-ws.test.ts diff --git a/.github/workflows/release-feature-branch.yaml b/.github/workflows/release-feature-branch.yaml index 5c2d76fb7..eb360da2d 100644 --- a/.github/workflows/release-feature-branch.yaml +++ b/.github/workflows/release-feature-branch.yaml @@ -151,6 +151,8 @@ jobs: XATA_API_KEY: ${{ secrets.XATA_API_KEY }} XATA_BRANCH: ${{ secrets.XATA_BRANCH }} LIBSQL_URL: file:local.db + LIBSQL_REMOTE_URL: ${{ secrets.LIBSQL_REMOTE_URL }} + LIBSQL_REMOTE_TOKEN: ${{ secrets.LIBSQL_REMOTE_TOKEN }} run: | if [[ ${{ github.event_name }} != "push" && "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]]; then export SKIP_EXTERNAL_DB_TESTS=1 diff --git a/.github/workflows/release-latest.yaml b/.github/workflows/release-latest.yaml index d81a0bcab..f9292b2e0 100644 --- a/.github/workflows/release-latest.yaml +++ b/.github/workflows/release-latest.yaml @@ -154,6 +154,8 @@ jobs: XATA_API_KEY: ${{ secrets.XATA_API_KEY }} XATA_BRANCH: ${{ secrets.XATA_BRANCH }} LIBSQL_URL: file:local.db + LIBSQL_REMOTE_URL: ${{ secrets.LIBSQL_REMOTE_URL }} + LIBSQL_REMOTE_TOKEN: ${{ secrets.LIBSQL_REMOTE_TOKEN }} run: | if [[ "${{ matrix.package }}" == "drizzle-orm" ]]; then pnpm test --filter ${{ matrix.package }} --filter integration-tests diff --git a/changelogs/drizzle-orm/0.35.3.md b/changelogs/drizzle-orm/0.35.3.md new file mode 100644 index 000000000..b25658e93 --- /dev/null +++ b/changelogs/drizzle-orm/0.35.3.md @@ -0,0 +1,80 @@ +# New LibSQL driver modules + +Drizzle now has native support for all `@libsql/client` driver variations: + +1. `@libsql/client` - defaults to node import, automatically changes to web if target or platform is set for bundler, e.g. `esbuild --platform=browser` + +```ts +import { drizzle } from 'drizzle-orm/libsql'; + +const db = drizzle({ connection: { + url: process.env.DATABASE_URL, + authToken: process.env.DATABASE_AUTH_TOKEN +}}); +``` + +2. `@libsql/client/node` node compatible module, supports :memory:, file, wss, http and turso connection protocols + +```ts +import { drizzle } from 'drizzle-orm/libsql/node'; + +const db = drizzle({ connection: { + url: process.env.DATABASE_URL, + authToken: process.env.DATABASE_AUTH_TOKEN +}}); +``` + +3. `@libsql/client/web` module for fullstack web frameworks like next, nuxt, astro, etc. + +```ts +import { drizzle } from 'drizzle-orm/libsql/web'; + +const db = drizzle({ connection: { + url: process.env.DATABASE_URL, + authToken: process.env.DATABASE_AUTH_TOKEN +}}); +``` + +4. `@libsql/client/http` module for http and https connection protocols + +```ts +import { drizzle } from 'drizzle-orm/libsql/http'; + +const db = drizzle({ connection: { + url: process.env.DATABASE_URL, + authToken: process.env.DATABASE_AUTH_TOKEN +}}); +``` + +5. `@libsql/client/ws` module for ws and wss connection protocols + +```ts +import { drizzle } from 'drizzle-orm/libsql/ws'; + +const db = drizzle({ connection: { + url: process.env.DATABASE_URL, + authToken: process.env.DATABASE_AUTH_TOKEN +}}); +``` + +6. `@libsql/client/sqlite3` module for :memory: and file connection protocols + +```ts +import { drizzle } from 'drizzle-orm/libsql/wasm'; + +const db = drizzle({ connection: { + url: process.env.DATABASE_URL, + authToken: process.env.DATABASE_AUTH_TOKEN +}}); +``` + +7. `@libsql/client-wasm` Separate experimental package for WASM + +```ts +import { drizzle } from 'drizzle-orm/libsql'; + +const db = drizzle({ connection: { + url: process.env.DATABASE_URL, + authToken: process.env.DATABASE_AUTH_TOKEN +}}); +``` diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index ceceab709..8622fea11 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.35.2", + "version": "0.35.3", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -47,6 +47,7 @@ "@cloudflare/workers-types": ">=3", "@electric-sql/pglite": ">=0.1.1", "@libsql/client": ">=0.10.0", + "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.1", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", @@ -162,6 +163,7 @@ "@cloudflare/workers-types": "^4.20230904.0", "@electric-sql/pglite": "^0.2.12", "@libsql/client": "^0.10.0", + "@libsql/client-wasm": "^0.10.0", "@miniflare/d1": "^2.14.4", "@neondatabase/serverless": "^0.9.0", "@op-engineering/op-sqlite": "^2.0.16", diff --git a/drizzle-orm/src/libsql/driver-core.ts b/drizzle-orm/src/libsql/driver-core.ts new file mode 100644 index 000000000..1bee47d7b --- /dev/null +++ b/drizzle-orm/src/libsql/driver-core.ts @@ -0,0 +1,64 @@ +import type { Client, ResultSet } from '@libsql/client'; +import type { BatchItem, BatchResponse } from '~/batch.ts'; +import { entityKind } from '~/entity.ts'; +import { DefaultLogger } from '~/logger.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type ExtractTablesWithRelations, + type RelationalSchemaConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; +import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; +import type { DrizzleConfig } from '~/utils.ts'; +import { LibSQLSession } from './session.ts'; + +export class LibSQLDatabase< + TSchema extends Record = Record, +> extends BaseSQLiteDatabase<'async', ResultSet, TSchema> { + static override readonly [entityKind]: string = 'LibSQLDatabase'; + + /** @internal */ + declare readonly session: LibSQLSession>; + + async batch, T extends Readonly<[U, ...U[]]>>( + batch: T, + ): Promise> { + return this.session.batch(batch) as Promise>; + } +} + +/** @internal */ +export function construct< + TSchema extends Record = Record, +>(client: Client, config: DrizzleConfig = {}): LibSQLDatabase & { + $client: Client; +} { + const dialect = new SQLiteAsyncDialect({ casing: config.casing }); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const session = new LibSQLSession(client, dialect, schema, { logger }, undefined); + const db = new LibSQLDatabase('async', dialect, session, schema) as LibSQLDatabase; + ( db).$client = client; + + return db as any; +} diff --git a/drizzle-orm/src/libsql/driver.ts b/drizzle-orm/src/libsql/driver.ts index 378ae15d2..bf0ef6662 100644 --- a/drizzle-orm/src/libsql/driver.ts +++ b/drizzle-orm/src/libsql/driver.ts @@ -1,66 +1,8 @@ -import { type Client, type Config, createClient, type ResultSet } from '@libsql/client'; -import type { BatchItem, BatchResponse } from '~/batch.ts'; -import { entityKind } from '~/entity.ts'; -import { DefaultLogger } from '~/logger.ts'; -import { - createTableRelationsHelpers, - extractTablesRelationalConfig, - type ExtractTablesWithRelations, - type RelationalSchemaConfig, - type TablesRelationalConfig, -} from '~/relations.ts'; -import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; -import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; +import { type Client, type Config, createClient } from '@libsql/client'; import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; -import { LibSQLSession } from './session.ts'; +import { construct as construct, type LibSQLDatabase } from './driver-core.ts'; -export class LibSQLDatabase< - TSchema extends Record = Record, -> extends BaseSQLiteDatabase<'async', ResultSet, TSchema> { - static override readonly [entityKind]: string = 'LibSQLDatabase'; - - /** @internal */ - declare readonly session: LibSQLSession>; - - async batch, T extends Readonly<[U, ...U[]]>>( - batch: T, - ): Promise> { - return this.session.batch(batch) as Promise>; - } -} - -function construct< - TSchema extends Record = Record, ->(client: Client, config: DrizzleConfig = {}): LibSQLDatabase & { - $client: Client; -} { - const dialect = new SQLiteAsyncDialect({ casing: config.casing }); - let logger; - if (config.logger === true) { - logger = new DefaultLogger(); - } else if (config.logger !== false) { - logger = config.logger; - } - - let schema: RelationalSchemaConfig | undefined; - if (config.schema) { - const tablesConfig = extractTablesRelationalConfig( - config.schema, - createTableRelationsHelpers, - ); - schema = { - fullSchema: config.schema, - schema: tablesConfig.tables, - tableNamesMap: tablesConfig.tableNamesMap, - }; - } - - const session = new LibSQLSession(client, dialect, schema, { logger }, undefined); - const db = new LibSQLDatabase('async', dialect, session, schema) as LibSQLDatabase; - ( db).$client = client; - - return db as any; -} +export { LibSQLDatabase } from './driver-core.ts'; export function drizzle< TSchema extends Record = Record, diff --git a/drizzle-orm/src/libsql/http/index.ts b/drizzle-orm/src/libsql/http/index.ts new file mode 100644 index 000000000..fddf910f5 --- /dev/null +++ b/drizzle-orm/src/libsql/http/index.ts @@ -0,0 +1,62 @@ +import { type Client, type Config, createClient } from '@libsql/client/http'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { construct, type LibSQLDatabase } from '../driver-core.ts'; + +export function drizzle< + TSchema extends Record = Record, + TClient extends Client = Client, +>( + ...params: IfNotImported< + Client, + [ImportTypeError<'@libsql/client'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] + > +): LibSQLDatabase & { + $client: TClient; +} { + if (typeof params[0] === 'string') { + const instance = createClient({ + url: params[0], + }); + + return construct(instance, params[1]) as any; + } + + if (isConfig(params[0])) { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config; client?: TClient } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection!); + + return construct(instance, drizzleConfig) as any; + } + + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): LibSQLDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/libsql/node/index.ts b/drizzle-orm/src/libsql/node/index.ts new file mode 100644 index 000000000..003a5c899 --- /dev/null +++ b/drizzle-orm/src/libsql/node/index.ts @@ -0,0 +1,62 @@ +import { type Client, type Config, createClient } from '@libsql/client/node'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { construct, type LibSQLDatabase } from '../driver-core.ts'; + +export function drizzle< + TSchema extends Record = Record, + TClient extends Client = Client, +>( + ...params: IfNotImported< + Client, + [ImportTypeError<'@libsql/client'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] + > +): LibSQLDatabase & { + $client: TClient; +} { + if (typeof params[0] === 'string') { + const instance = createClient({ + url: params[0], + }); + + return construct(instance, params[1]) as any; + } + + if (isConfig(params[0])) { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config; client?: TClient } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection!); + + return construct(instance, drizzleConfig) as any; + } + + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): LibSQLDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/libsql/sqlite3/index.ts b/drizzle-orm/src/libsql/sqlite3/index.ts new file mode 100644 index 000000000..0f17ef935 --- /dev/null +++ b/drizzle-orm/src/libsql/sqlite3/index.ts @@ -0,0 +1,62 @@ +import { type Client, type Config, createClient } from '@libsql/client/sqlite3'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { construct, type LibSQLDatabase } from '../driver-core.ts'; + +export function drizzle< + TSchema extends Record = Record, + TClient extends Client = Client, +>( + ...params: IfNotImported< + Client, + [ImportTypeError<'@libsql/client'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] + > +): LibSQLDatabase & { + $client: TClient; +} { + if (typeof params[0] === 'string') { + const instance = createClient({ + url: params[0], + }); + + return construct(instance, params[1]) as any; + } + + if (isConfig(params[0])) { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config; client?: TClient } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection!); + + return construct(instance, drizzleConfig) as any; + } + + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): LibSQLDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/libsql/wasm/index.ts b/drizzle-orm/src/libsql/wasm/index.ts new file mode 100644 index 000000000..23c4f4dcc --- /dev/null +++ b/drizzle-orm/src/libsql/wasm/index.ts @@ -0,0 +1,62 @@ +import { type Client, type Config, createClient } from '@libsql/client-wasm'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { construct, type LibSQLDatabase } from '../driver-core.ts'; + +export function drizzle< + TSchema extends Record = Record, + TClient extends Client = Client, +>( + ...params: IfNotImported< + Client, + [ImportTypeError<'@libsql/client-wasm'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] + > +): LibSQLDatabase & { + $client: TClient; +} { + if (typeof params[0] === 'string') { + const instance = createClient({ + url: params[0], + }); + + return construct(instance, params[1]) as any; + } + + if (isConfig(params[0])) { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config; client?: TClient } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection!); + + return construct(instance, drizzleConfig) as any; + } + + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): LibSQLDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/libsql/web/index.ts b/drizzle-orm/src/libsql/web/index.ts new file mode 100644 index 000000000..e7c31c9bb --- /dev/null +++ b/drizzle-orm/src/libsql/web/index.ts @@ -0,0 +1,62 @@ +import { type Client, type Config, createClient } from '@libsql/client/web'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { construct, type LibSQLDatabase } from '../driver-core.ts'; + +export function drizzle< + TSchema extends Record = Record, + TClient extends Client = Client, +>( + ...params: IfNotImported< + Client, + [ImportTypeError<'@libsql/client'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] + > +): LibSQLDatabase & { + $client: TClient; +} { + if (typeof params[0] === 'string') { + const instance = createClient({ + url: params[0], + }); + + return construct(instance, params[1]) as any; + } + + if (isConfig(params[0])) { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config; client?: TClient } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection!); + + return construct(instance, drizzleConfig) as any; + } + + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): LibSQLDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/libsql/ws/index.ts b/drizzle-orm/src/libsql/ws/index.ts new file mode 100644 index 000000000..115ec9b24 --- /dev/null +++ b/drizzle-orm/src/libsql/ws/index.ts @@ -0,0 +1,62 @@ +import { type Client, type Config, createClient } from '@libsql/client/ws'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { construct, type LibSQLDatabase } from '../driver-core.ts'; + +export function drizzle< + TSchema extends Record = Record, + TClient extends Client = Client, +>( + ...params: IfNotImported< + Client, + [ImportTypeError<'@libsql/client'>], + [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] + > +): LibSQLDatabase & { + $client: TClient; +} { + if (typeof params[0] === 'string') { + const instance = createClient({ + url: params[0], + }); + + return construct(instance, params[1]) as any; + } + + if (isConfig(params[0])) { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: Config; client?: TClient } + & DrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' ? createClient({ url: connection }) : createClient(connection!); + + return construct(instance, drizzleConfig) as any; + } + + return construct(params[0] as TClient, params[1] as DrizzleConfig | undefined) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: DrizzleConfig, + ): LibSQLDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index 47988e5f3..e8309e10a 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -1,4 +1,4 @@ -import type { Config, Connection } from '@planetscale/database'; +import type { Config } from '@planetscale/database'; import { Client } from '@planetscale/database'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; @@ -27,7 +27,7 @@ export class PlanetScaleDatabase< function construct< TSchema extends Record = Record, - TClient extends Client | Connection = Client | Connection, + TClient extends Client = Client, >( client: TClient, config: DrizzleConfig = {}, @@ -37,22 +37,7 @@ function construct< // Client is not Drizzle Object, so we can ignore this rule here // eslint-disable-next-line no-instanceof/no-instanceof if (!(client instanceof Client)) { - // Should use error on 0.30.0 release - // throw new DrizzleError({ - // message: `You need to pass an instance of Client: - - // import { Client } from "@planetscale/database"; - - // const client = new Client({ - // host: process.env["DATABASE_HOST"], - // username: process.env["DATABASE_USERNAME"], - // password: process.env["DATABASE_PASSWORD"], - // }); - - // const db = drizzle(client); - // `, - // }); - console.log(`Warning: You need to pass an instance of Client: + throw new Error(`Warning: You need to pass an instance of Client: import { Client } from "@planetscale/database"; @@ -63,8 +48,6 @@ const client = new Client({ }); const db = drizzle(client); - -Starting from version 0.30.0, you will encounter an error if you attempt to use anything other than a Client instance.\nPlease make the necessary changes now to prevent any runtime errors in the future `); } diff --git a/integration-tests/.env.example b/integration-tests/.env.example index c2e01d4f6..ceff7d132 100644 --- a/integration-tests/.env.example +++ b/integration-tests/.env.example @@ -5,6 +5,8 @@ TIDB_CONNECTION_STRING= NEON_CONNECTION_STRING= LIBSQL_URL="file:local.db" LIBSQL_AUTH_TOKEN="ey..." # For Turso only +LIBSQL_REMOTE_URL="libsql://..." +LIBSQL_REMOTE_TOKEN="ey..." AWS_DATA_API_DB= AWS_DATA_API_SECRET_ARN= AWS_DATA_API_RESOURCE_ARN= diff --git a/integration-tests/js-tests/driver-init/commonjs/planetscale.test.cjs b/integration-tests/js-tests/driver-init/commonjs/planetscale.test.cjs index 2a7bffec1..0894d30c2 100644 --- a/integration-tests/js-tests/driver-init/commonjs/planetscale.test.cjs +++ b/integration-tests/js-tests/driver-init/commonjs/planetscale.test.cjs @@ -1,5 +1,5 @@ require('dotenv/config'); -const { Client, Connection } = require('@planetscale/database'); +const { Client } = require('@planetscale/database'); const { drizzle } = require('drizzle-orm/planetscale-serverless'); const { mysql: schema } = require('./schema.cjs'); import { describe, expect } from 'vitest'; @@ -99,48 +99,3 @@ describe('planetscale', async (it) => { expect(db.query.User).not.toStrictEqual(undefined); }); }); - -describe('planetscale:Connection', async (it) => { - it('drizzle(client)', async () => { - const client = new Connection({ - url: process.env['PLANETSCALE_CONNECTION_STRING'], - }); - const db = drizzle(client); - - await db.$client.execute('SELECT 1;'); - - expect(db.$client).not.toBeInstanceOf(Client); - expect(db.$client).toBeInstanceOf(Connection); - }); - - it('drizzle(client, config)', async () => { - const client = new Connection({ - url: process.env['PLANETSCALE_CONNECTION_STRING'], - }); - const db = drizzle(client, { - schema, - }); - - await db.$client.execute('SELECT 1;'); - - expect(db.$client).not.toBeInstanceOf(Client); - expect(db.$client).toBeInstanceOf(Connection); - expect(db.query.User).not.toStrictEqual(undefined); - }); - - it('drizzle({client, ...config})', async () => { - const client = new Connection({ - url: process.env['PLANETSCALE_CONNECTION_STRING'], - }); - const db = drizzle({ - client, - schema, - }); - - await db.$client.execute('SELECT 1;'); - - expect(db.$client).not.toBeInstanceOf(Client); - expect(db.$client).toBeInstanceOf(Connection); - expect(db.query.User).not.toStrictEqual(undefined); - }); -}); diff --git a/integration-tests/js-tests/driver-init/module/planetscale.test.mjs b/integration-tests/js-tests/driver-init/module/planetscale.test.mjs index c56537b06..0a68b7e9f 100644 --- a/integration-tests/js-tests/driver-init/module/planetscale.test.mjs +++ b/integration-tests/js-tests/driver-init/module/planetscale.test.mjs @@ -1,5 +1,5 @@ import 'dotenv/config'; -import { Client, Connection } from '@planetscale/database'; +import { Client } from '@planetscale/database'; import { drizzle } from 'drizzle-orm/planetscale-serverless'; import { describe, expect } from 'vitest'; import { mysql as schema } from './schema.mjs'; @@ -99,48 +99,3 @@ describe('planetscale', async (it) => { expect(db.query.User).not.toStrictEqual(undefined); }); }); - -describe('planetscale:Connection', async (it) => { - it('drizzle(client)', async () => { - const client = new Connection({ - url: process.env['PLANETSCALE_CONNECTION_STRING'], - }); - const db = drizzle(client); - - await db.$client.execute('SELECT 1;'); - - expect(db.$client).not.toBeInstanceOf(Client); - expect(db.$client).toBeInstanceOf(Connection); - }); - - it('drizzle(client, config)', async () => { - const client = new Connection({ - url: process.env['PLANETSCALE_CONNECTION_STRING'], - }); - const db = drizzle(client, { - schema, - }); - - await db.$client.execute('SELECT 1;'); - - expect(db.$client).not.toBeInstanceOf(Client); - expect(db.$client).toBeInstanceOf(Connection); - expect(db.query.User).not.toStrictEqual(undefined); - }); - - it('drizzle({client, ...config})', async () => { - const client = new Connection({ - url: process.env['PLANETSCALE_CONNECTION_STRING'], - }); - const db = drizzle({ - client, - schema, - }); - - await db.$client.execute('SELECT 1;'); - - expect(db.$client).not.toBeInstanceOf(Client); - expect(db.$client).toBeInstanceOf(Connection); - expect(db.query.User).not.toStrictEqual(undefined); - }); -}); diff --git a/integration-tests/tests/imports/index.test.ts b/integration-tests/tests/imports/index.test.ts index 875d1d24c..7a44942fa 100644 --- a/integration-tests/tests/imports/index.test.ts +++ b/integration-tests/tests/imports/index.test.ts @@ -20,7 +20,7 @@ it('dynamic imports check for CommonJS', async () => { const o1 = path.join('drizzle-orm', key); if ( o1.startsWith('drizzle-orm/bun-sqlite') || o1.startsWith('drizzle-orm/pglite') - || o1.startsWith('drizzle-orm/expo-sqlite') + || o1.startsWith('drizzle-orm/expo-sqlite') || o1.startsWith('drizzle-orm/libsql/wasm') ) { continue; } diff --git a/integration-tests/tests/sqlite/libsql-http.test.ts b/integration-tests/tests/sqlite/libsql-http.test.ts new file mode 100644 index 000000000..bd4f66879 --- /dev/null +++ b/integration-tests/tests/sqlite/libsql-http.test.ts @@ -0,0 +1,186 @@ +import { type Client, createClient } from '@libsql/client/http'; +import retry from 'async-retry'; +import { asc, eq, getTableColumns, sql } from 'drizzle-orm'; +import type { LibSQLDatabase } from 'drizzle-orm/libsql'; +import { drizzle } from 'drizzle-orm/libsql/http'; +import { migrate } from 'drizzle-orm/libsql/migrator'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { skipTests } from '~/common'; +import { randomString } from '~/utils'; +import { anotherUsersMigratorTable, tests, usersMigratorTable, usersOnUpdate } from './sqlite-common'; + +const ENABLE_LOGGING = false; + +let db: LibSQLDatabase; +let client: Client; + +beforeAll(async () => { + const url = process.env['LIBSQL_REMOTE_URL']; + const authToken = process.env['LIBSQL_REMOTE_TOKEN']; + if (!url) { + throw new Error('LIBSQL_REMOTE_URL is not set'); + } + client = await retry(async () => { + client = createClient({ url, authToken }); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.close(); + }, + }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + client?.close(); +}); + +beforeEach((ctx) => { + ctx.sqlite = { + db, + }; +}); + +test('migrator', async () => { + await db.run(sql`drop table if exists another_users`); + await db.run(sql`drop table if exists users12`); + await db.run(sql`drop table if exists __drizzle_migrations`); + + await migrate(db, { migrationsFolder: './drizzle2/sqlite' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result = await db.select().from(usersMigratorTable).all(); + + await db.insert(anotherUsersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result2 = await db.select().from(anotherUsersMigratorTable).all(); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + expect(result2).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.run(sql`drop table another_users`); + await db.run(sql`drop table users12`); + await db.run(sql`drop table __drizzle_migrations`); +}); + +test('migrator : migrate with custom table', async () => { + const customTable = randomString(); + await db.run(sql`drop table if exists another_users`); + await db.run(sql`drop table if exists users12`); + await db.run(sql`drop table if exists ${sql.identifier(customTable)}`); + + await migrate(db, { migrationsFolder: './drizzle2/sqlite', migrationsTable: customTable }); + + // test if the custom migrations table was created + const res = await db.all(sql`select * from ${sql.identifier(customTable)};`); + expect(res.length > 0).toBeTruthy(); + + // test if the migrated table are working as expected + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + const result = await db.select().from(usersMigratorTable); + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.run(sql`drop table another_users`); + await db.run(sql`drop table users12`); + await db.run(sql`drop table ${sql.identifier(customTable)}`); +}); + +test('test $onUpdateFn and $onUpdate works as $default', async (ctx) => { + const { db } = ctx.sqlite; + + await db.run(sql`drop table if exists ${usersOnUpdate}`); + + await db.run( + sql` + create table ${usersOnUpdate} ( + id integer primary key autoincrement, + name text not null, + update_counter integer default 1 not null, + updated_at integer, + always_null text + ) + `, + ); + + await db.insert(usersOnUpdate).values([ + { name: 'John' }, + { name: 'Jane' }, + { name: 'Jack' }, + { name: 'Jill' }, + ]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + + const justDates = await db.select({ updatedAt }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + const response = await db.select({ ...rest }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + expect(response).toEqual([ + { name: 'John', id: 1, updateCounter: 1, alwaysNull: null }, + { name: 'Jane', id: 2, updateCounter: 1, alwaysNull: null }, + { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, + { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, + ]); + const msDelay = 750; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); + } +}); + +test('test $onUpdateFn and $onUpdate works updating', async (ctx) => { + const { db } = ctx.sqlite; + + await db.run(sql`drop table if exists ${usersOnUpdate}`); + + await db.run( + sql` + create table ${usersOnUpdate} ( + id integer primary key autoincrement, + name text not null, + update_counter integer default 1, + updated_at integer, + always_null text + ) + `, + ); + + await db.insert(usersOnUpdate).values([ + { name: 'John', alwaysNull: 'this will be null after updating' }, + { name: 'Jane' }, + { name: 'Jack' }, + { name: 'Jill' }, + ]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + + await db.update(usersOnUpdate).set({ name: 'Angel' }).where(eq(usersOnUpdate.id, 1)); + await db.update(usersOnUpdate).set({ updateCounter: null }).where(eq(usersOnUpdate.id, 2)); + + const justDates = await db.select({ updatedAt }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + const response = await db.select({ ...rest }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + expect(response).toEqual([ + { name: 'Angel', id: 1, updateCounter: 2, alwaysNull: null }, + { name: 'Jane', id: 2, updateCounter: null, alwaysNull: null }, + { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, + { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, + ]); + const msDelay = 750; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); + } +}); + +skipTests([ + 'delete with limit and order by', + 'update with limit and order by', + 'test $onUpdateFn and $onUpdate works as $default', + 'test $onUpdateFn and $onUpdate works updating', +]); + +tests(); diff --git a/integration-tests/tests/sqlite/libsql-node.test.ts b/integration-tests/tests/sqlite/libsql-node.test.ts new file mode 100644 index 000000000..bfe2c1574 --- /dev/null +++ b/integration-tests/tests/sqlite/libsql-node.test.ts @@ -0,0 +1,97 @@ +import { type Client, createClient } from '@libsql/client/node'; +import retry from 'async-retry'; +import { sql } from 'drizzle-orm'; +import type { LibSQLDatabase } from 'drizzle-orm/libsql'; +import { migrate } from 'drizzle-orm/libsql/migrator'; +import { drizzle } from 'drizzle-orm/libsql/node'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { skipTests } from '~/common'; +import { randomString } from '~/utils'; +import { anotherUsersMigratorTable, tests, usersMigratorTable } from './sqlite-common'; + +const ENABLE_LOGGING = false; + +let db: LibSQLDatabase; +let client: Client; + +beforeAll(async () => { + const url = process.env['LIBSQL_URL']; + const authToken = process.env['LIBSQL_AUTH_TOKEN']; + if (!url) { + throw new Error('LIBSQL_URL is not set'); + } + client = await retry(async () => { + client = createClient({ url, authToken }); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.close(); + }, + }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + client?.close(); +}); + +beforeEach((ctx) => { + ctx.sqlite = { + db, + }; +}); + +test('migrator', async () => { + await db.run(sql`drop table if exists another_users`); + await db.run(sql`drop table if exists users12`); + await db.run(sql`drop table if exists __drizzle_migrations`); + + await migrate(db, { migrationsFolder: './drizzle2/sqlite' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result = await db.select().from(usersMigratorTable).all(); + + await db.insert(anotherUsersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result2 = await db.select().from(anotherUsersMigratorTable).all(); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + expect(result2).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.run(sql`drop table another_users`); + await db.run(sql`drop table users12`); + await db.run(sql`drop table __drizzle_migrations`); +}); + +test('migrator : migrate with custom table', async () => { + const customTable = randomString(); + await db.run(sql`drop table if exists another_users`); + await db.run(sql`drop table if exists users12`); + await db.run(sql`drop table if exists ${sql.identifier(customTable)}`); + + await migrate(db, { migrationsFolder: './drizzle2/sqlite', migrationsTable: customTable }); + + // test if the custom migrations table was created + const res = await db.all(sql`select * from ${sql.identifier(customTable)};`); + expect(res.length > 0).toBeTruthy(); + + // test if the migrated table are working as expected + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + const result = await db.select().from(usersMigratorTable); + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.run(sql`drop table another_users`); + await db.run(sql`drop table users12`); + await db.run(sql`drop table ${sql.identifier(customTable)}`); +}); + +skipTests([ + 'delete with limit and order by', + 'update with limit and order by', +]); + +tests(); diff --git a/integration-tests/tests/sqlite/libsql-sqlite3.test.ts b/integration-tests/tests/sqlite/libsql-sqlite3.test.ts new file mode 100644 index 000000000..8d8419f17 --- /dev/null +++ b/integration-tests/tests/sqlite/libsql-sqlite3.test.ts @@ -0,0 +1,97 @@ +import { type Client, createClient } from '@libsql/client/sqlite3'; +import retry from 'async-retry'; +import { sql } from 'drizzle-orm'; +import type { LibSQLDatabase } from 'drizzle-orm/libsql'; +import { migrate } from 'drizzle-orm/libsql/migrator'; +import { drizzle } from 'drizzle-orm/libsql/sqlite3'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { skipTests } from '~/common'; +import { randomString } from '~/utils'; +import { anotherUsersMigratorTable, tests, usersMigratorTable } from './sqlite-common'; + +const ENABLE_LOGGING = false; + +let db: LibSQLDatabase; +let client: Client; + +beforeAll(async () => { + const url = ':memory:'; + client = await retry(async () => { + client = createClient({ url }); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.close(); + }, + }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + client?.close(); +}); + +beforeEach((ctx) => { + ctx.sqlite = { + db, + }; +}); + +test('migrator', async () => { + await db.run(sql`drop table if exists another_users`); + await db.run(sql`drop table if exists users12`); + await db.run(sql`drop table if exists __drizzle_migrations`); + + await migrate(db, { migrationsFolder: './drizzle2/sqlite' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result = await db.select().from(usersMigratorTable).all(); + + await db.insert(anotherUsersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result2 = await db.select().from(anotherUsersMigratorTable).all(); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + expect(result2).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.run(sql`drop table another_users`); + await db.run(sql`drop table users12`); + await db.run(sql`drop table __drizzle_migrations`); +}); + +test('migrator : migrate with custom table', async () => { + const customTable = randomString(); + await db.run(sql`drop table if exists another_users`); + await db.run(sql`drop table if exists users12`); + await db.run(sql`drop table if exists ${sql.identifier(customTable)}`); + + await migrate(db, { migrationsFolder: './drizzle2/sqlite', migrationsTable: customTable }); + + // test if the custom migrations table was created + const res = await db.all(sql`select * from ${sql.identifier(customTable)};`); + expect(res.length > 0).toBeTruthy(); + + // test if the migrated table are working as expected + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + const result = await db.select().from(usersMigratorTable); + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.run(sql`drop table another_users`); + await db.run(sql`drop table users12`); + await db.run(sql`drop table ${sql.identifier(customTable)}`); +}); + +skipTests([ + 'delete with limit and order by', + 'update with limit and order by', + 'transaction', + 'transaction rollback', + 'nested transaction', + 'nested transaction rollback', +]); + +tests(); diff --git a/integration-tests/tests/sqlite/libsql-ws.test.ts b/integration-tests/tests/sqlite/libsql-ws.test.ts new file mode 100644 index 000000000..6d84d6c9e --- /dev/null +++ b/integration-tests/tests/sqlite/libsql-ws.test.ts @@ -0,0 +1,187 @@ +import { type Client, createClient } from '@libsql/client/ws'; +import retry from 'async-retry'; +import { asc, eq, getTableColumns, sql } from 'drizzle-orm'; +import type { LibSQLDatabase } from 'drizzle-orm/libsql'; +import { migrate } from 'drizzle-orm/libsql/migrator'; +import { drizzle } from 'drizzle-orm/libsql/ws'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { skipTests } from '~/common'; +import { randomString } from '~/utils'; +import { anotherUsersMigratorTable, tests, usersMigratorTable, usersOnUpdate } from './sqlite-common'; + +const ENABLE_LOGGING = false; + +let db: LibSQLDatabase; +let client: Client; + +beforeAll(async () => { + const url = process.env['LIBSQL_REMOTE_URL']; + const authToken = process.env['LIBSQL_REMOTE_TOKEN']; + if (!url) { + throw new Error('LIBSQL_REMOTE_URL is not set'); + } + client = await retry(async () => { + client = createClient({ url, authToken }); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.close(); + }, + }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + client?.close(); +}); + +beforeEach((ctx) => { + ctx.sqlite = { + db, + }; +}); + +test('migrator', async () => { + await db.run(sql`drop table if exists another_users`); + await db.run(sql`drop table if exists users12`); + await db.run(sql`drop table if exists __drizzle_migrations`); + + await migrate(db, { migrationsFolder: './drizzle2/sqlite' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result = await db.select().from(usersMigratorTable).all(); + + await db.insert(anotherUsersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result2 = await db.select().from(anotherUsersMigratorTable).all(); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + expect(result2).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.run(sql`drop table another_users`); + await db.run(sql`drop table users12`); + await db.run(sql`drop table __drizzle_migrations`); +}); + +test('migrator : migrate with custom table', async () => { + const customTable = randomString(); + await db.run(sql`drop table if exists another_users`); + await db.run(sql`drop table if exists users12`); + await db.run(sql`drop table if exists ${sql.identifier(customTable)}`); + + await migrate(db, { migrationsFolder: './drizzle2/sqlite', migrationsTable: customTable }); + + // test if the custom migrations table was created + const res = await db.all(sql`select * from ${sql.identifier(customTable)};`); + expect(res.length > 0).toBeTruthy(); + + // test if the migrated table are working as expected + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + const result = await db.select().from(usersMigratorTable); + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.run(sql`drop table another_users`); + await db.run(sql`drop table users12`); + await db.run(sql`drop table ${sql.identifier(customTable)}`); +}); + +test('test $onUpdateFn and $onUpdate works as $default', async (ctx) => { + const { db } = ctx.sqlite; + + await db.run(sql`drop table if exists ${usersOnUpdate}`); + + await db.run( + sql` + create table ${usersOnUpdate} ( + id integer primary key autoincrement, + name text not null, + update_counter integer default 1 not null, + updated_at integer, + always_null text + ) + `, + ); + + await db.insert(usersOnUpdate).values([ + { name: 'John' }, + { name: 'Jane' }, + { name: 'Jack' }, + { name: 'Jill' }, + ]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + + const justDates = await db.select({ updatedAt }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + const response = await db.select({ ...rest }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + expect(response).toEqual([ + { name: 'John', id: 1, updateCounter: 1, alwaysNull: null }, + { name: 'Jane', id: 2, updateCounter: 1, alwaysNull: null }, + { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, + { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, + ]); + const msDelay = 750; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); + } +}); + +test('test $onUpdateFn and $onUpdate works updating', async (ctx) => { + const { db } = ctx.sqlite; + + await db.run(sql`drop table if exists ${usersOnUpdate}`); + + await db.run( + sql` + create table ${usersOnUpdate} ( + id integer primary key autoincrement, + name text not null, + update_counter integer default 1, + updated_at integer, + always_null text + ) + `, + ); + + await db.insert(usersOnUpdate).values([ + { name: 'John', alwaysNull: 'this will be null after updating' }, + { name: 'Jane' }, + { name: 'Jack' }, + { name: 'Jill' }, + ]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + + await db.update(usersOnUpdate).set({ name: 'Angel' }).where(eq(usersOnUpdate.id, 1)); + await db.update(usersOnUpdate).set({ updateCounter: null }).where(eq(usersOnUpdate.id, 2)); + + const justDates = await db.select({ updatedAt }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + const response = await db.select({ ...rest }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + expect(response).toEqual([ + { name: 'Angel', id: 1, updateCounter: 2, alwaysNull: null }, + { name: 'Jane', id: 2, updateCounter: null, alwaysNull: null }, + { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, + { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, + ]); + const msDelay = 750; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); + } +}); + +skipTests([ + 'delete with limit and order by', + 'update with limit and order by', + 'join view as subquery', + 'test $onUpdateFn and $onUpdate works as $default', + 'test $onUpdateFn and $onUpdate works updating', +]); + +tests(); diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index f31bdbbd2..83beff74d 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -63,7 +63,7 @@ export const usersTable = sqliteTable('users', { createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(sql`strftime('%s', 'now')`), }); -const usersOnUpdate = sqliteTable('users_on_update', { +export const usersOnUpdate = sqliteTable('users_on_update', { id: integer('id').primaryKey({ autoIncrement: true }), name: text('name').notNull(), updateCounter: integer('update_counter').default(sql`1`).$onUpdateFn(() => sql`update_counter + 1`), @@ -1388,7 +1388,7 @@ export function tests() { cityId: integer('city_id').notNull(), }).existing(); - await db.run(sql`create view new_yorkers as ${getViewConfig(newYorkers1).query}`); + await db.run(sql`create view if not exists new_yorkers as ${getViewConfig(newYorkers1).query}`); await db.insert(citiesTable).values([{ name: 'New York' }, { name: 'Paris' }]).run(); @@ -1782,7 +1782,7 @@ export function tests() { await db.run( sql`create table ${users} (id integer not null primary key, name text not null, city_id integer not null)`, ); - await db.run(sql`create view ${newYorkers} as ${getViewConfig(newYorkers).query}`); + await db.run(sql`create view if not exists ${newYorkers} as ${getViewConfig(newYorkers).query}`); db.insert(users).values([ { name: 'John', cityId: 1 }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c064253b8..20ff6ca0f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -303,6 +303,9 @@ importers: '@libsql/client': specifier: ^0.10.0 version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + '@libsql/client-wasm': + specifier: ^0.10.0 + version: 0.10.0 '@miniflare/d1': specifier: ^2.14.4 version: 2.14.4 @@ -311,7 +314,7 @@ importers: version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -359,7 +362,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -548,7 +551,7 @@ importers: version: 3.583.0 '@aws-sdk/credential-providers': specifier: ^3.549.0 - version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0) '@electric-sql/pglite': specifier: ^0.2.12 version: 0.2.12 @@ -3094,6 +3097,11 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@libsql/client-wasm@0.10.0': + resolution: {integrity: sha512-xSlpGdBGEr4mRtjCnDejTqtDpct2ng8cqHUQs+S4xG1yv0h+hLdzOtQJSY9JV9T/2MWWDfdCiEntPs2SdErSJA==} + bundledDependencies: + - '@libsql/libsql-wasm-experimental' + '@libsql/client@0.10.0': resolution: {integrity: sha512-2ERn08T4XOVx34yBtUPq0RDjAdd9TJ5qNH/izugr208ml2F94mk92qC64kXyDVQINodWJvp3kAdq6P4zTtCZ7g==} @@ -10911,12 +10919,12 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -10999,13 +11007,13 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -11086,10 +11094,10 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-sso': 3.568.0 - '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11143,7 +11151,7 @@ snapshots: '@smithy/types': 3.0.0 tslib: 2.6.2 - '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-cognito-identity': 3.569.0 '@aws-sdk/client-sso': 3.568.0 @@ -11151,10 +11159,10 @@ snapshots: '@aws-sdk/credential-provider-cognito-identity': 3.569.0 '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)) + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 @@ -11336,7 +11344,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0))': + '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.567.0 @@ -13021,7 +13029,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -13039,7 +13047,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13461,6 +13469,11 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 + '@libsql/client-wasm@0.10.0': + dependencies: + '@libsql/core': 0.10.0 + js-base64: 3.7.7 + '@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: '@libsql/core': 0.10.0 @@ -13615,10 +13628,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) '@opentelemetry/api@1.8.0': {} @@ -13755,7 +13768,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13765,7 +13778,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13792,14 +13805,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13888,16 +13901,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13912,7 +13925,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13926,7 +13939,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -13949,12 +13962,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) optionalDependencies: '@types/react': 18.3.1 @@ -15264,7 +15277,7 @@ snapshots: pathe: 1.1.2 picocolors: 1.0.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + vitest: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) optional: true '@vitest/ui@1.6.0(vitest@2.1.2)': @@ -17325,35 +17338,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) expo-modules-autolinking@1.11.1: dependencies: @@ -17367,24 +17380,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -18866,12 +18879,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18947,13 +18960,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18967,7 +18980,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -18993,7 +19006,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -19001,7 +19014,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -19010,7 +19023,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -19898,10 +19911,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8): + react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19914,19 +19927,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19945,14 +19958,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8) + react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -21872,15 +21885,17 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8): + ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8): + ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From 526996bd2ea20d5b1a0d65e743b47e23329d441c Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 21 Oct 2024 22:57:51 +0300 Subject: [PATCH 258/492] Make delays higher --- integration-tests/tests/sqlite/libsql-http.test.ts | 4 ++-- integration-tests/tests/sqlite/libsql-ws.test.ts | 5 +++-- integration-tests/vitest.config.ts | 3 +++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/integration-tests/tests/sqlite/libsql-http.test.ts b/integration-tests/tests/sqlite/libsql-http.test.ts index bd4f66879..576d8d48a 100644 --- a/integration-tests/tests/sqlite/libsql-http.test.ts +++ b/integration-tests/tests/sqlite/libsql-http.test.ts @@ -124,7 +124,7 @@ test('test $onUpdateFn and $onUpdate works as $default', async (ctx) => { { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, ]); - const msDelay = 750; + const msDelay = 1750; for (const eachUser of justDates) { expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); @@ -169,7 +169,7 @@ test('test $onUpdateFn and $onUpdate works updating', async (ctx) => { { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, ]); - const msDelay = 750; + const msDelay = 1750; for (const eachUser of justDates) { expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); diff --git a/integration-tests/tests/sqlite/libsql-ws.test.ts b/integration-tests/tests/sqlite/libsql-ws.test.ts index 6d84d6c9e..86810a36f 100644 --- a/integration-tests/tests/sqlite/libsql-ws.test.ts +++ b/integration-tests/tests/sqlite/libsql-ws.test.ts @@ -124,7 +124,7 @@ test('test $onUpdateFn and $onUpdate works as $default', async (ctx) => { { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, ]); - const msDelay = 750; + const msDelay = 1250; for (const eachUser of justDates) { expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); @@ -169,7 +169,7 @@ test('test $onUpdateFn and $onUpdate works updating', async (ctx) => { { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, ]); - const msDelay = 750; + const msDelay = 1250; for (const eachUser of justDates) { expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); @@ -182,6 +182,7 @@ skipTests([ 'join view as subquery', 'test $onUpdateFn and $onUpdate works as $default', 'test $onUpdateFn and $onUpdate works updating', + 'prepared statement reuse', ]); tests(); diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 5465c4047..84ea9b1c8 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -54,6 +54,9 @@ export default defineConfig({ // todo: remove 'js-tests/driver-init/module/vercel.test.mjs', 'js-tests/driver-init/commonjs/vercel.test.cjs', + // move back after decide on speed + 'tests/sqlite/libsql-ws.test.ts', + 'tests/sqlite/libsql-http.test.ts', ], typecheck: { tsconfig: 'tsconfig.json', From 89ee20116dce932fc9278530ce9775ffda589052 Mon Sep 17 00:00:00 2001 From: Pedro Rodrigues <44656907+Rodriguespn@users.noreply.github.com> Date: Wed, 2 Oct 2024 01:23:29 +0100 Subject: [PATCH 259/492] [SingleStore] Add SingleStore connector (#32) --- drizzle-kit/src/api.ts | 110 + drizzle-kit/src/cli/commands/introspect.ts | 102 +- drizzle-kit/src/cli/commands/migrate.ts | 148 + drizzle-kit/src/cli/commands/push.ts | 155 +- .../src/cli/commands/singlestoreIntrospect.ts | 53 + .../src/cli/commands/singlestorePushUtils.ts | 352 + drizzle-kit/src/cli/commands/singlestoreUp.ts | 1 + drizzle-kit/src/cli/commands/utils.ts | 87 +- drizzle-kit/src/cli/connections.ts | 80 + drizzle-kit/src/cli/schema.ts | 68 +- drizzle-kit/src/cli/validations/outputs.ts | 11 +- .../src/cli/validations/singlestore.ts | 61 + drizzle-kit/src/index.ts | 23 +- drizzle-kit/src/introspect-singlestore.ts | 780 ++ drizzle-kit/src/jsonStatements.ts | 461 +- drizzle-kit/src/migrationPreparator.ts | 45 +- drizzle-kit/src/schemaValidator.ts | 6 +- drizzle-kit/src/serializer/index.ts | 16 + .../src/serializer/singlestoreImports.ts | 38 + .../src/serializer/singlestoreSchema.ts | 203 + .../src/serializer/singlestoreSerializer.ts | 606 ++ drizzle-kit/src/serializer/studio.ts | 84 +- drizzle-kit/src/snapshotsDiffer.ts | 428 ++ drizzle-kit/src/sqlgenerator.ts | 801 ++- drizzle-kit/src/utils.ts | 3 + .../tests/push/singlestore-push.test.ts | 335 + drizzle-kit/tests/push/singlestore.test.ts | 699 ++ drizzle-kit/tests/schemaDiffer.ts | 376 +- .../tests/singlestore-generated.test.ts | 1290 ++++ drizzle-kit/tests/singlestore-schemas.test.ts | 155 + drizzle-kit/tests/singlestore-views.test.ts | 553 ++ drizzle-kit/tests/singlestore.test.ts | 578 ++ drizzle-kit/tests/testsinglestore.ts | 29 + drizzle-kit/tests/validations.test.ts | 169 + drizzle-kit/tests/wrap-param.test.ts | 3 + drizzle-orm/src/column-builder.ts | 9 +- drizzle-orm/src/singlestore-core/alias.ts | 11 + drizzle-orm/src/singlestore-core/checks.ts | 32 + .../src/singlestore-core/columns/all.ts | 55 + .../src/singlestore-core/columns/bigint.ts | 120 + .../src/singlestore-core/columns/binary.ts | 70 + .../src/singlestore-core/columns/boolean.ts | 58 + .../src/singlestore-core/columns/char.ts | 75 + .../src/singlestore-core/columns/common.ts | 116 + .../src/singlestore-core/columns/custom.ts | 235 + .../singlestore-core/columns/date.common.ts | 41 + .../src/singlestore-core/columns/date.ts | 123 + .../src/singlestore-core/columns/datetime.ts | 143 + .../src/singlestore-core/columns/decimal.ts | 75 + .../src/singlestore-core/columns/double.ts | 75 + .../src/singlestore-core/columns/enum.ts | 70 + .../src/singlestore-core/columns/float.ts | 51 + .../src/singlestore-core/columns/index.ts | 25 + .../src/singlestore-core/columns/int.ts | 71 + .../src/singlestore-core/columns/json.ts | 53 + .../src/singlestore-core/columns/mediumint.ts | 68 + .../src/singlestore-core/columns/real.ts | 81 + .../src/singlestore-core/columns/serial.ts | 76 + .../src/singlestore-core/columns/smallint.ts | 68 + .../src/singlestore-core/columns/text.ts | 116 + .../src/singlestore-core/columns/time.ts | 73 + .../src/singlestore-core/columns/timestamp.ts | 127 + .../src/singlestore-core/columns/tinyint.ts | 68 + .../src/singlestore-core/columns/varbinary.ts | 66 + .../src/singlestore-core/columns/varchar.ts | 75 + .../src/singlestore-core/columns/year.ts | 51 + drizzle-orm/src/singlestore-core/db.ts | 566 ++ drizzle-orm/src/singlestore-core/dialect.ts | 866 +++ .../src/singlestore-core/expressions.ts | 25 + drizzle-orm/src/singlestore-core/index.ts | 16 + drizzle-orm/src/singlestore-core/indexes.ts | 191 + .../src/singlestore-core/primary-keys.ts | 63 + .../singlestore-core/query-builders/attach.ts | 198 + .../singlestore-core/query-builders/branch.ts | 186 + .../singlestore-core/query-builders/count.ts | 79 + .../query-builders/createMilestone.ts | 136 + .../singlestore-core/query-builders/delete.ts | 207 + .../singlestore-core/query-builders/detach.ts | 172 + .../query-builders/dropMilestone.ts | 136 + .../singlestore-core/query-builders/index.ts | 12 + .../singlestore-core/query-builders/insert.ts | 305 + .../query-builders/optimizeTable.ts | 158 + .../query-builders/query-builder.ts | 114 + .../singlestore-core/query-builders/query.ts | 141 + .../singlestore-core/query-builders/select.ts | 1084 +++ .../query-builders/select.types.ts | 457 ++ .../singlestore-core/query-builders/update.ts | 251 + drizzle-orm/src/singlestore-core/schema.ts | 41 + drizzle-orm/src/singlestore-core/session.ts | 159 + .../sql/expressions/conditions.ts | 22 + .../singlestore-core/sql/expressions/index.ts | 1 + drizzle-orm/src/singlestore-core/sql/index.ts | 1 + drizzle-orm/src/singlestore-core/subquery.ts | 17 + drizzle-orm/src/singlestore-core/table.ts | 142 + .../src/singlestore-core/unique-constraint.ts | 64 + drizzle-orm/src/singlestore-core/utils.ts | 56 + drizzle-orm/src/singlestore-core/view-base.ts | 15 + .../src/singlestore-core/view-common.ts | 1 + drizzle-orm/src/singlestore-core/view.ts | 208 + drizzle-orm/src/singlestore-proxy/driver.ts | 54 + drizzle-orm/src/singlestore-proxy/index.ts | 2 + drizzle-orm/src/singlestore-proxy/migrator.ts | 52 + drizzle-orm/src/singlestore-proxy/session.ts | 178 + drizzle-orm/src/singlestore/driver.ts | 92 + drizzle-orm/src/singlestore/index.ts | 2 + drizzle-orm/src/singlestore/migrator.ts | 11 + drizzle-orm/src/singlestore/session.ts | 339 + .../type-tests/singlestore/1000columns.ts | 904 +++ drizzle-orm/type-tests/singlestore/db.ts | 12 + drizzle-orm/type-tests/singlestore/delete.ts | 61 + .../singlestore/generated-columns.ts | 158 + drizzle-orm/type-tests/singlestore/insert.ts | 135 + drizzle-orm/type-tests/singlestore/select.ts | 606 ++ .../type-tests/singlestore/set-operators.ts | 223 + .../type-tests/singlestore/subquery.ts | 97 + drizzle-orm/type-tests/singlestore/tables.ts | 751 ++ drizzle-orm/type-tests/singlestore/update.ts | 26 + drizzle-orm/type-tests/singlestore/with.ts | 80 + integration-tests/.env.example | 1 + .../singlestore/0000_nostalgic_carnage.sql | 20 + .../singlestore/meta/0000_snapshot.json | 132 + .../drizzle2/singlestore/meta/_journal.json | 13 + .../tests/relational/singlestore.schema.ts | 106 + .../tests/relational/singlestore.test.ts | 6402 +++++++++++++++++ .../tests/replicas/singlestore.test.ts | 805 +++ .../tests/singlestore/singlestore-common.ts | 3432 +++++++++ .../singlestore/singlestore-custom.test.ts | 827 +++ .../singlestore/singlestore-prefixed.test.ts | 1572 ++++ .../singlestore/singlestore-proxy.test.ts | 140 + .../tests/singlestore/singlestore.test.ts | 51 + integration-tests/vitest.config.ts | 4 + package.json | 3 +- pnpm-lock.yaml | 2 +- 133 files changed, 34581 insertions(+), 88 deletions(-) create mode 100644 drizzle-kit/src/cli/commands/singlestoreIntrospect.ts create mode 100644 drizzle-kit/src/cli/commands/singlestorePushUtils.ts create mode 100644 drizzle-kit/src/cli/commands/singlestoreUp.ts create mode 100644 drizzle-kit/src/cli/validations/singlestore.ts create mode 100644 drizzle-kit/src/introspect-singlestore.ts create mode 100644 drizzle-kit/src/serializer/singlestoreImports.ts create mode 100644 drizzle-kit/src/serializer/singlestoreSchema.ts create mode 100644 drizzle-kit/src/serializer/singlestoreSerializer.ts create mode 100644 drizzle-kit/tests/push/singlestore-push.test.ts create mode 100644 drizzle-kit/tests/push/singlestore.test.ts create mode 100644 drizzle-kit/tests/singlestore-generated.test.ts create mode 100644 drizzle-kit/tests/singlestore-schemas.test.ts create mode 100644 drizzle-kit/tests/singlestore-views.test.ts create mode 100644 drizzle-kit/tests/singlestore.test.ts create mode 100644 drizzle-kit/tests/testsinglestore.ts create mode 100644 drizzle-orm/src/singlestore-core/alias.ts create mode 100644 drizzle-orm/src/singlestore-core/checks.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/all.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/bigint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/binary.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/boolean.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/char.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/common.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/custom.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/date.common.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/date.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/datetime.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/decimal.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/double.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/enum.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/float.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/index.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/int.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/json.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/mediumint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/real.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/serial.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/smallint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/text.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/time.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/timestamp.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/tinyint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/varbinary.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/varchar.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/year.ts create mode 100644 drizzle-orm/src/singlestore-core/db.ts create mode 100644 drizzle-orm/src/singlestore-core/dialect.ts create mode 100644 drizzle-orm/src/singlestore-core/expressions.ts create mode 100644 drizzle-orm/src/singlestore-core/index.ts create mode 100644 drizzle-orm/src/singlestore-core/indexes.ts create mode 100644 drizzle-orm/src/singlestore-core/primary-keys.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/attach.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/branch.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/count.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/delete.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/detach.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/index.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/insert.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/query-builder.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/query.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/select.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/select.types.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/update.ts create mode 100644 drizzle-orm/src/singlestore-core/schema.ts create mode 100644 drizzle-orm/src/singlestore-core/session.ts create mode 100644 drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts create mode 100644 drizzle-orm/src/singlestore-core/sql/expressions/index.ts create mode 100644 drizzle-orm/src/singlestore-core/sql/index.ts create mode 100644 drizzle-orm/src/singlestore-core/subquery.ts create mode 100644 drizzle-orm/src/singlestore-core/table.ts create mode 100644 drizzle-orm/src/singlestore-core/unique-constraint.ts create mode 100644 drizzle-orm/src/singlestore-core/utils.ts create mode 100644 drizzle-orm/src/singlestore-core/view-base.ts create mode 100644 drizzle-orm/src/singlestore-core/view-common.ts create mode 100644 drizzle-orm/src/singlestore-core/view.ts create mode 100644 drizzle-orm/src/singlestore-proxy/driver.ts create mode 100644 drizzle-orm/src/singlestore-proxy/index.ts create mode 100644 drizzle-orm/src/singlestore-proxy/migrator.ts create mode 100644 drizzle-orm/src/singlestore-proxy/session.ts create mode 100644 drizzle-orm/src/singlestore/driver.ts create mode 100644 drizzle-orm/src/singlestore/index.ts create mode 100644 drizzle-orm/src/singlestore/migrator.ts create mode 100644 drizzle-orm/src/singlestore/session.ts create mode 100644 drizzle-orm/type-tests/singlestore/1000columns.ts create mode 100644 drizzle-orm/type-tests/singlestore/db.ts create mode 100644 drizzle-orm/type-tests/singlestore/delete.ts create mode 100644 drizzle-orm/type-tests/singlestore/generated-columns.ts create mode 100644 drizzle-orm/type-tests/singlestore/insert.ts create mode 100644 drizzle-orm/type-tests/singlestore/select.ts create mode 100644 drizzle-orm/type-tests/singlestore/set-operators.ts create mode 100644 drizzle-orm/type-tests/singlestore/subquery.ts create mode 100644 drizzle-orm/type-tests/singlestore/tables.ts create mode 100644 drizzle-orm/type-tests/singlestore/update.ts create mode 100644 drizzle-orm/type-tests/singlestore/with.ts create mode 100644 integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql create mode 100644 integration-tests/drizzle2/singlestore/meta/0000_snapshot.json create mode 100644 integration-tests/drizzle2/singlestore/meta/_journal.json create mode 100644 integration-tests/tests/relational/singlestore.schema.ts create mode 100644 integration-tests/tests/relational/singlestore.test.ts create mode 100644 integration-tests/tests/replicas/singlestore.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore-common.ts create mode 100644 integration-tests/tests/singlestore/singlestore-custom.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore-prefixed.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore-proxy.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore.test.ts diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index a5b8bfe69..e843bb2f2 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'; import { LibSQLDatabase } from 'drizzle-orm/libsql'; import type { MySql2Database } from 'drizzle-orm/mysql2'; import { PgDatabase } from 'drizzle-orm/pg-core'; +import { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; import { columnsResolver, enumsResolver, @@ -25,12 +26,19 @@ import { generateMySqlSnapshot } from './serializer/mysqlSerializer'; import { prepareFromExports } from './serializer/pgImports'; import { PgSchema as PgSchemaKit, pgSchema, squashPgScheme } from './serializer/pgSchema'; import { generatePgSnapshot } from './serializer/pgSerializer'; +import { + SingleStoreSchema as SingleStoreSchemaKit, + singlestoreSchema, + squashSingleStoreScheme, +} from './serializer/singlestoreSchema'; +import { generateSingleStoreSnapshot } from './serializer/singlestoreSerializer'; import { SQLiteSchema as SQLiteSchemaKit, sqliteSchema, squashSqliteScheme } from './serializer/sqliteSchema'; import { generateSqliteSnapshot } from './serializer/sqliteSerializer'; import type { DB, SQLiteDB } from './utils'; export type DrizzleSnapshotJSON = PgSchemaKit; export type DrizzleSQLiteSnapshotJSON = SQLiteSchemaKit; export type DrizzleMySQLSnapshotJSON = MySQLSchemaKit; +export type DrizzleSingleStoreSnapshotJSON = SingleStoreSchemaKit; export const generateDrizzleJson = ( imports: Record, @@ -355,6 +363,108 @@ export const pushMySQLSchema = async ( }; }; +// SingleStore + +export const generateSingleStoreDrizzleJson = async ( + imports: Record, + prevId?: string, +): Promise => { + const { prepareFromExports } = await import('./serializer/singlestoreImports'); + + const prepared = prepareFromExports(imports); + + const id = randomUUID(); + + const snapshot = generateSingleStoreSnapshot(prepared.tables); + + return { + ...snapshot, + id, + prevId: prevId ?? originUUID, + }; +}; + +export const generateSingleStoreMigration = async ( + prev: DrizzleSingleStoreSnapshotJSON, + cur: DrizzleSingleStoreSnapshotJSON, +) => { + const { applySingleStoreSnapshotsDiff } = await import('./snapshotsDiffer'); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + ); + + return sqlStatements; +}; + +export const pushSingleStoreSchema = async ( + imports: Record, + drizzleInstance: SingleStoreDriverDatabase, + databaseName: string, +) => { + const { applySingleStoreSnapshotsDiff } = await import('./snapshotsDiffer'); + const { logSuggestionsAndReturn } = await import( + './cli/commands/singlestorePushUtils' + ); + const { singlestorePushIntrospect } = await import( + './cli/commands/singlestoreIntrospect' + ); + const { sql } = await import('drizzle-orm'); + + const db: DB = { + query: async (query: string, params?: any[]) => { + const res = await drizzleInstance.execute(sql.raw(query)); + return res[0] as unknown as any[]; + }, + }; + const cur = await generateSingleStoreDrizzleJson(imports); + const { schema: prev } = await singlestorePushIntrospect(db, databaseName, []); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { statements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + ); + + const { shouldAskForApprove, statementsToExecute, infoToPrint } = await logSuggestionsAndReturn( + db, + statements, + validatedCur, + ); + + return { + hasDataLoss: shouldAskForApprove, + warnings: infoToPrint, + statementsToExecute, + apply: async () => { + for (const dStmnt of statementsToExecute) { + await db.query(dStmnt); + } + }, + }; +}; + export const upPgSnapshot = (snapshot: Record) => { if (snapshot.version === '5') { return upPgV7(upPgV6(snapshot)); diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 257150dc0..4953d403a 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -4,20 +4,24 @@ import { render, renderWithTask } from 'hanji'; import { Minimatch } from 'minimatch'; import { join } from 'path'; import { plural, singular } from 'pluralize'; +import { drySingleStore, SingleStoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; import { assertUnreachable, originUUID } from '../../global'; import { schemaToTypeScript as mysqlSchemaToTypeScript } from '../../introspect-mysql'; import { paramNameFor, schemaToTypeScript as postgresSchemaToTypeScript } from '../../introspect-pg'; +import { schemaToTypeScript as singlestoreSchemaToTypeScript } from '../../introspect-singlestore'; import { schemaToTypeScript as sqliteSchemaToTypeScript } from '../../introspect-sqlite'; import { dryMySql, MySqlSchema, squashMysqlScheme } from '../../serializer/mysqlSchema'; import { fromDatabase as fromMysqlDatabase } from '../../serializer/mysqlSerializer'; import { dryPg, type PgSchema, squashPgScheme } from '../../serializer/pgSchema'; import { fromDatabase as fromPostgresDatabase } from '../../serializer/pgSerializer'; +import { fromDatabase as fromSingleStoreDatabase } from '../../serializer/singlestoreSerializer'; import { drySQLite, type SQLiteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase } from '../../serializer/sqliteSerializer'; import { applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, } from '../../snapshotsDiffer'; import { prepareOutFolder } from '../../utils'; @@ -25,6 +29,7 @@ import type { Casing, Prefix } from '../validations/common'; import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; import type { PostgresCredentials } from '../validations/postgres'; +import { SingleStoreCredentials } from '../validations/singlestore'; import type { SqliteCredentials } from '../validations/sqlite'; import { IntrospectProgress } from '../views'; import { @@ -203,7 +208,6 @@ export const introspectMysql = async ( const schema = { id: originUUID, prevId: '', ...res } as MySqlSchema; const ts = mysqlSchemaToTypeScript(schema, casing); const relationsTs = relationsToTypeScript(schema, casing); - const { internal, ...schemaWithoutInternals } = schema; const schemaFile = join(out, 'schema.ts'); writeFileSync(schemaFile, ts.file); @@ -265,6 +269,102 @@ export const introspectMysql = async ( process.exit(0); }; +export const introspectSingleStore = async ( + casing: Casing, + out: string, + breakpoints: boolean, + credentials: SingleStoreCredentials, + tablesFilter: string[], + prefix: Prefix, +) => { + const { connectToSingleStore } = await import('../connections'); + const { db, database } = await connectToSingleStore(credentials); + + const matchers = tablesFilter.map((it) => { + return new Minimatch(it); + }); + + const filter = (tableName: string) => { + if (matchers.length === 0) return true; + + let flags: boolean[] = []; + + for (let matcher of matchers) { + if (matcher.negate) { + if (!matcher.match(tableName)) { + flags.push(false); + } + } + + if (matcher.match(tableName)) { + flags.push(true); + } + } + + if (flags.length > 0) { + return flags.every(Boolean); + } + return false; + }; + + const progress = new IntrospectProgress(); + const res = await renderWithTask( + progress, + fromSingleStoreDatabase(db, database, filter, (stage, count, status) => { + progress.update(stage, count, status); + }), + ); + + const schema = { id: originUUID, prevId: '', ...res } as SingleStoreSchema; + const ts = singlestoreSchemaToTypeScript(schema, casing); + const { internal, ...schemaWithoutInternals } = schema; + + const schemaFile = join(out, 'schema.ts'); + writeFileSync(schemaFile, ts.file); + console.log(); + + const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + + if (snapshots.length === 0) { + const { sqlStatements, _meta } = await applySingleStoreSnapshotsDiff( + squashSingleStoreScheme(drySingleStore), + squashSingleStoreScheme(schema), + tablesResolver, + columnsResolver, + drySingleStore, + schema, + ); + + writeResult({ + cur: schema, + sqlStatements, + journal, + _meta, + outFolder: out, + breakpoints, + type: 'introspect', + prefixMode: prefix, + }); + } else { + render( + `[${ + chalk.blue( + 'i', + ) + }] No SQL generated, you already have migrations in project`, + ); + } + + render( + `[${ + chalk.green( + '✓', + ) + }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + ); + process.exit(0); +}; + export const introspectSqlite = async ( casing: Casing, out: string, diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index c4f1e65d1..9411d95f2 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -4,6 +4,8 @@ import { prepareMySqlMigrationSnapshot, preparePgDbPushSnapshot, preparePgMigrationSnapshot, + prepareSingleStoreDbPushSnapshot, + prepareSingleStoreMigrationSnapshot, prepareSQLiteDbPushSnapshot, prepareSqliteMigrationSnapshot, } from '../../migrationPreparator'; @@ -11,6 +13,7 @@ import { import chalk from 'chalk'; import { render } from 'hanji'; import path, { join } from 'path'; +import { SingleStoreSchema, singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme, ViewSquashed } from '../../serializer/mysqlSchema'; @@ -20,6 +23,7 @@ import { applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, Column, ColumnsResolverInput, @@ -470,6 +474,150 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { } }; +// Not needed for now +function singleStoreSchemaSuggestions( + curSchema: TypeOf, + prevSchema: TypeOf, +) { + const suggestions: string[] = []; + const usedSuggestions: string[] = []; + const suggestionTypes = { + // TODO: Check if SingleStore has serial type + serial: withStyle.errorWarning( + `We deprecated the use of 'serial' for SingleStore starting from version 0.20.0. In SingleStore, 'serial' is simply an alias for 'bigint unsigned not null auto_increment unique,' which creates all constraints and indexes for you. This may make the process less explicit for both users and drizzle-kit push commands`, + ), + }; + + for (const table of Object.values(curSchema.tables)) { + for (const column of Object.values(table.columns)) { + if (column.type === 'serial') { + if (!usedSuggestions.includes('serial')) { + suggestions.push(suggestionTypes['serial']); + } + + const uniqueForSerial = Object.values( + prevSchema.tables[table.name].uniqueConstraints, + ).find((it) => it.columns[0] === column.name); + + suggestions.push( + `\n` + + withStyle.suggestion( + `We are suggesting to change ${ + chalk.blue( + column.name, + ) + } column in ${ + chalk.blueBright( + table.name, + ) + } table from serial to bigint unsigned\n\n${ + chalk.blueBright( + `bigint("${column.name}", { mode: "number", unsigned: true }).notNull().autoincrement().unique(${ + uniqueForSerial?.name ? `"${uniqueForSerial?.name}"` : '' + })`, + ) + }`, + ), + ); + } + } + } + + return suggestions; +} + +// Intersect with prepareAnMigrate +export const prepareSingleStorePush = async ( + schemaPath: string | string[], + snapshot: SingleStoreSchema, +) => { + try { + const { prev, cur } = await prepareSingleStoreDbPushSnapshot( + snapshot, + schemaPath, + ); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + ); + + return { sqlStatements, statements, validatedCur, validatedPrev }; + } catch (e) { + console.error(e); + process.exit(1); + } +}; + +export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { + const outFolder = config.out; + const schemaPath = config.schema; + + try { + // TODO: remove + assertV1OutFolder(outFolder); + + const { snapshots, journal } = prepareMigrationFolder(outFolder, 'singlestore'); + const { prev, cur, custom } = await prepareSingleStoreMigrationSnapshot( + snapshots, + schemaPath, + ); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + if (config.custom) { + writeResult({ + cur: custom, + sqlStatements: [], + journal, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + type: 'custom', + prefixMode: config.prefix, + }); + return; + } + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements, statements, _meta } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + ); + + writeResult({ + cur, + sqlStatements, + journal, + _meta, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + prefixMode: config.prefix, + }); + } catch (e) { + console.error(e); + } +}; + export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index f84f84d9c..edf92f708 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -7,10 +7,18 @@ import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; import { withStyle } from '../validations/outputs'; import type { PostgresCredentials } from '../validations/postgres'; +import { SingleStoreCredentials } from '../validations/singlestore'; import type { SqliteCredentials } from '../validations/sqlite'; import { libSqlLogSuggestionsAndReturn } from './libSqlPushUtils'; -import { filterStatements, logSuggestionsAndReturn } from './mysqlPushUtils'; +import { + filterStatements as mySqlFilterStatements, + logSuggestionsAndReturn as mySqlLogSuggestionsAndReturn, +} from './mysqlPushUtils'; import { pgSuggestions } from './pgPushUtils'; +import { + filterStatements as singleStoreFilterStatements, + logSuggestionsAndReturn as singleStoreLogSuggestionsAndReturn, +} from './singlestorePushUtils'; import { logSuggestionsAndReturn as sqliteSuggestions } from './sqlitePushUtils'; export const mysqlPush = async ( @@ -32,7 +40,7 @@ export const mysqlPush = async ( const statements = await prepareMySQLPush(schemaPath, schema, casing); - const filteredStatements = filterStatements( + const filteredStatements = mySqlFilterStatements( statements.statements ?? [], statements.validatedCur, statements.validatedPrev, @@ -49,8 +57,7 @@ export const mysqlPush = async ( tablesToRemove, tablesToTruncate, infoToPrint, - schemasToRemove, - } = await logSuggestionsAndReturn( + } = await mySqlLogSuggestionsAndReturn( db, filteredStatements, statements.validatedCur, @@ -153,6 +160,145 @@ export const mysqlPush = async ( } }; +export const singlestorePush = async ( + schemaPath: string | string[], + credentials: SingleStoreCredentials, + tablesFilter: string[], + strict: boolean, + verbose: boolean, + force: boolean, +) => { + const { connectToSingleStore } = await import('../connections'); + const { singlestorePushIntrospect } = await import('./singlestoreIntrospect'); + + const { db, database } = await connectToSingleStore(credentials); + + const { schema } = await singlestorePushIntrospect(db, database, tablesFilter); + const { prepareSingleStorePush } = await import('./migrate'); + + const statements = await prepareSingleStorePush(schemaPath, schema); + + const filteredStatements = singleStoreFilterStatements( + statements.statements ?? [], + statements.validatedCur, + statements.validatedPrev, + ); + + try { + if (filteredStatements.length === 0) { + render(`[${chalk.blue('i')}] No changes detected`); + } else { + const { + shouldAskForApprove, + statementsToExecute, + columnsToRemove, + tablesToRemove, + tablesToTruncate, + infoToPrint, + schemasToRemove, + } = await singleStoreLogSuggestionsAndReturn( + db, + filteredStatements, + statements.validatedCur, + ); + + const filteredSqlStatements = fromJson(filteredStatements, 'singlestore'); + + const uniqueSqlStatementsToExecute: string[] = []; + statementsToExecute.forEach((ss) => { + if (!uniqueSqlStatementsToExecute.includes(ss)) { + uniqueSqlStatementsToExecute.push(ss); + } + }); + const uniqueFilteredSqlStatements: string[] = []; + filteredSqlStatements.forEach((ss) => { + if (!uniqueFilteredSqlStatements.includes(ss)) { + uniqueFilteredSqlStatements.push(ss); + } + }); + + if (verbose) { + console.log(); + console.log( + withStyle.warning('You are about to execute current statements:'), + ); + console.log(); + console.log( + [...uniqueSqlStatementsToExecute, ...uniqueFilteredSqlStatements] + .map((s) => chalk.blue(s)) + .join('\n'), + ); + console.log(); + } + + if (!force && strict) { + if (!shouldAskForApprove) { + const { status, data } = await render( + new Select(['No, abort', `Yes, I want to execute all statements`]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + } + + if (!force && shouldAskForApprove) { + console.log(withStyle.warning('Found data-loss statements:')); + console.log(infoToPrint.join('\n')); + console.log(); + console.log( + chalk.red.bold( + 'THIS ACTION WILL CAUSE DATA LOSS AND CANNOT BE REVERTED\n', + ), + ); + + console.log(chalk.white('Do you still want to push changes?')); + + const { status, data } = await render( + new Select([ + 'No, abort', + `Yes, I want to${ + tablesToRemove.length > 0 + ? ` remove ${tablesToRemove.length} ${tablesToRemove.length > 1 ? 'tables' : 'table'},` + : ' ' + }${ + columnsToRemove.length > 0 + ? ` remove ${columnsToRemove.length} ${columnsToRemove.length > 1 ? 'columns' : 'column'},` + : ' ' + }${ + tablesToTruncate.length > 0 + ? ` truncate ${tablesToTruncate.length} ${tablesToTruncate.length > 1 ? 'tables' : 'table'}` + : '' + }` + .replace(/(^,)|(,$)/g, '') + .replace(/ +(?= )/g, ''), + ]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + + for (const dStmnt of uniqueSqlStatementsToExecute) { + await db.query(dStmnt); + } + + for (const statement of uniqueFilteredSqlStatements) { + await db.query(statement); + } + if (filteredStatements.length > 0) { + render(`[${chalk.green('✓')}] Changes applied`); + } else { + render(`[${chalk.blue('i')}] No changes detected`); + } + } + } catch (e) { + console.log(e); + } +}; + export const pgPush = async ( schemaPath: string | string[], verbose: boolean, @@ -299,7 +445,6 @@ export const sqlitePush = async ( tablesToRemove, tablesToTruncate, infoToPrint, - schemasToRemove, } = await sqliteSuggestions( db, statements.statements, diff --git a/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts b/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts new file mode 100644 index 000000000..27d8c59c5 --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts @@ -0,0 +1,53 @@ +import { renderWithTask } from 'hanji'; +import { Minimatch } from 'minimatch'; +import { originUUID } from '../../global'; +import type { SingleStoreSchema } from '../../serializer/singlestoreSchema'; +import { fromDatabase } from '../../serializer/singlestoreSerializer'; +import type { DB } from '../../utils'; +import { ProgressView } from '../views'; + +export const singlestorePushIntrospect = async ( + db: DB, + databaseName: string, + filters: string[], +) => { + const matchers = filters.map((it) => { + return new Minimatch(it); + }); + + const filter = (tableName: string) => { + if (matchers.length === 0) return true; + + let flags: boolean[] = []; + + for (let matcher of matchers) { + if (matcher.negate) { + if (!matcher.match(tableName)) { + flags.push(false); + } + } + + if (matcher.match(tableName)) { + flags.push(true); + } + } + + if (flags.length > 0) { + return flags.every(Boolean); + } + return false; + }; + + const progress = new ProgressView( + 'Pulling schema from database...', + 'Pulling schema from database...', + ); + const res = await renderWithTask( + progress, + fromDatabase(db, databaseName, filter), + ); + + const schema = { id: originUUID, prevId: '', ...res } as SingleStoreSchema; + const { internal, ...schemaWithoutInternals } = schema; + return { schema: schemaWithoutInternals }; +}; diff --git a/drizzle-kit/src/cli/commands/singlestorePushUtils.ts b/drizzle-kit/src/cli/commands/singlestorePushUtils.ts new file mode 100644 index 000000000..80fad9b2d --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestorePushUtils.ts @@ -0,0 +1,352 @@ +import chalk from 'chalk'; +import { render } from 'hanji'; +import { TypeOf } from 'zod'; +import { JsonAlterColumnTypeStatement, JsonStatement } from '../../jsonStatements'; +import { singlestoreSchema, SingleStoreSquasher } from '../../serializer/singlestoreSchema'; +import type { DB } from '../../utils'; +import { Select } from '../selector-ui'; +import { withStyle } from '../validations/outputs'; + +export const filterStatements = ( + statements: JsonStatement[], + currentSchema: TypeOf, + prevSchema: TypeOf, +) => { + return statements.filter((statement) => { + if (statement.type === 'alter_table_alter_column_set_type') { + // Don't need to handle it on migrations step and introspection + // but for both it should be skipped + if ( + statement.oldDataType.startsWith('tinyint') + && statement.newDataType.startsWith('boolean') + ) { + return false; + } + + if ( + statement.oldDataType.startsWith('bigint unsigned') + && statement.newDataType.startsWith('serial') + ) { + return false; + } + + if ( + statement.oldDataType.startsWith('serial') + && statement.newDataType.startsWith('bigint unsigned') + ) { + return false; + } + } else if (statement.type === 'alter_table_alter_column_set_default') { + if ( + statement.newDefaultValue === false + && statement.oldDefaultValue === 0 + && statement.newDataType === 'boolean' + ) { + return false; + } + if ( + statement.newDefaultValue === true + && statement.oldDefaultValue === 1 + && statement.newDataType === 'boolean' + ) { + return false; + } + } else if (statement.type === 'delete_unique_constraint') { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); + // only if constraint was removed from a serial column, than treat it as removed + // const serialStatement = statements.find( + // (it) => it.type === "alter_table_alter_column_set_type" + // ) as JsonAlterColumnTypeStatement; + // if ( + // serialStatement?.oldDataType.startsWith("bigint unsigned") && + // serialStatement?.newDataType.startsWith("serial") && + // serialStatement.columnName === + // SingleStoreSquasher.unsquashUnique(statement.data).columns[0] + // ) { + // return false; + // } + // Check if uniqueindex was only on this column, that is serial + + // if now serial and was not serial and was unique index + if ( + unsquashed.columns.length === 1 + && currentSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .type === 'serial' + && prevSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .type === 'serial' + && currentSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .name === unsquashed.columns[0] + ) { + return false; + } + } else if (statement.type === 'alter_table_alter_column_drop_notnull') { + // only if constraint was removed from a serial column, than treat it as removed + const serialStatement = statements.find( + (it) => it.type === 'alter_table_alter_column_set_type', + ) as JsonAlterColumnTypeStatement; + if ( + serialStatement?.oldDataType.startsWith('bigint unsigned') + && serialStatement?.newDataType.startsWith('serial') + && serialStatement.columnName === statement.columnName + && serialStatement.tableName === statement.tableName + ) { + return false; + } + if (statement.newDataType === 'serial' && !statement.columnNotNull) { + return false; + } + if (statement.columnAutoIncrement) { + return false; + } + } + + return true; + }); +}; + +export const logSuggestionsAndReturn = async ( + db: DB, + statements: JsonStatement[], + json2: TypeOf, +) => { + let shouldAskForApprove = false; + const statementsToExecute: string[] = []; + const infoToPrint: string[] = []; + + const tablesToRemove: string[] = []; + const columnsToRemove: string[] = []; + const schemasToRemove: string[] = []; + const tablesToTruncate: string[] = []; + + for (const statement of statements) { + if (statement.type === 'drop_table') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.tableName, + ) + } table with ${count} items`, + ); + tablesToRemove.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_drop_column') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.columnName, + ) + } column in ${statement.tableName} table with ${count} items`, + ); + columnsToRemove.push(`${statement.tableName}_${statement.columnName}`); + shouldAskForApprove = true; + } + } else if (statement.type === 'drop_schema') { + const res = await db.query( + `select count(*) as count from information_schema.tables where table_schema = \`${statement.name}\`;`, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.name, + ) + } schema with ${count} tables`, + ); + schemasToRemove.push(statement.name); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_alter_column_set_type') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to change ${ + chalk.underline( + statement.columnName, + ) + } column type from ${ + chalk.underline( + statement.oldDataType, + ) + } to ${chalk.underline(statement.newDataType)} with ${count} items`, + ); + statementsToExecute.push(`truncate table ${statement.tableName};`); + tablesToTruncate.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_alter_column_drop_default') { + if (statement.columnNotNull) { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to remove default value from ${ + chalk.underline( + statement.columnName, + ) + } not-null column with ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + // shouldAskForApprove = true; + } else if (statement.type === 'alter_table_alter_column_set_notnull') { + if (typeof statement.columnDefault === 'undefined') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to set not-null constraint to ${ + chalk.underline( + statement.columnName, + ) + } column without default, which contains ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + } else if (statement.type === 'alter_table_alter_column_drop_pk') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + // if drop pk and json2 has autoincrement in table -> exit process with error + if ( + Object.values(json2.tables[statement.tableName].columns).filter( + (column) => column.autoincrement, + ).length > 0 + ) { + console.log( + `${ + withStyle.errorWarning( + `You have removed the primary key from a ${statement.tableName} table without removing the auto-increment property from this table. As the database error states: 'there can be only one auto column, and it must be defined as a key. Make sure to remove autoincrement from ${statement.tableName} table`, + ) + }`, + ); + process.exit(1); + } + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to change ${ + chalk.underline( + statement.tableName, + ) + } primary key. This statements may fail and you table may left without primary key`, + ); + + tablesToTruncate.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'delete_composite_pk') { + // if drop pk and json2 has autoincrement in table -> exit process with error + if ( + Object.values(json2.tables[statement.tableName].columns).filter( + (column) => column.autoincrement, + ).length > 0 + ) { + console.log( + `${ + withStyle.errorWarning( + `You have removed the primary key from a ${statement.tableName} table without removing the auto-increment property from this table. As the database error states: 'there can be only one auto column, and it must be defined as a key. Make sure to remove autoincrement from ${statement.tableName} table`, + ) + }`, + ); + process.exit(1); + } + } else if (statement.type === 'alter_table_add_column') { + if ( + statement.column.notNull + && typeof statement.column.default === 'undefined' + ) { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + statement.column.name, + ) + } column without default value, which contains ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + } else if (statement.type === 'create_unique_constraint') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + const unsquashedUnique = SingleStoreSquasher.unsquashUnique(statement.data); + console.log( + `· You're about to add ${ + chalk.underline( + unsquashedUnique.name, + ) + } unique constraint to the table, which contains ${count} items. If this statement fails, you will receive an error from the database. Do you want to truncate ${ + chalk.underline( + statement.tableName, + ) + } table?\n`, + ); + const { status, data } = await render( + new Select([ + 'No, add the constraint without truncating the table', + `Yes, truncate the table`, + ]), + ); + if (data?.index === 1) { + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + shouldAskForApprove = true; + } + } + } + } + + return { + statementsToExecute, + shouldAskForApprove, + infoToPrint, + columnsToRemove: [...new Set(columnsToRemove)], + schemasToRemove: [...new Set(schemasToRemove)], + tablesToTruncate: [...new Set(tablesToTruncate)], + tablesToRemove: [...new Set(tablesToRemove)], + }; +}; diff --git a/drizzle-kit/src/cli/commands/singlestoreUp.ts b/drizzle-kit/src/cli/commands/singlestoreUp.ts new file mode 100644 index 000000000..dc5004ed0 --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestoreUp.ts @@ -0,0 +1 @@ +export const upSinglestoreHandler = (out: string) => {}; diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index e58e23435..127e1eb88 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -30,13 +30,18 @@ import { postgresCredentials, printConfigConnectionIssues as printIssuesPg, } from '../validations/postgres'; +import { + printConfigConnectionIssues as printIssuesSingleStore, + SingleStoreCredentials, + singlestoreCredentials, +} from '../validations/singlestore'; import { printConfigConnectionIssues as printIssuesSqlite, SqliteCredentials, sqliteCredentials, } from '../validations/sqlite'; import { studioCliParams, studioConfig } from '../validations/studio'; -import { error, grey } from '../views'; +import { error } from '../views'; // NextJs default config is target: es5, which esbuild-register can't consume const assertES5 = async (unregister: () => void) => { @@ -221,6 +226,10 @@ export const preparePushConfig = async ( dialect: 'turso'; credentials: LibSQLCredentials; } + | { + dialect: 'singlestore'; + credentials: SingleStoreCredentials; + } ) & { schemaPath: string | string[]; verbose: boolean; @@ -322,6 +331,25 @@ export const preparePushConfig = async ( }; } + if (config.dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(config); + if (!parsed.success) { + printIssuesSingleStore(config); + process.exit(1); + } + + return { + dialect: 'singlestore', + schemaPath: config.schema, + strict: config.strict ?? false, + verbose: config.verbose ?? false, + force: (options.force as boolean) ?? false, + credentials: parsed.data, + tablesFilter, + schemasFilter, + }; + } + if (config.dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(config); if (!parsed.success) { @@ -384,6 +412,10 @@ export const preparePullConfig = async ( dialect: 'turso'; credentials: LibSQLCredentials; } + | { + dialect: 'singlestore'; + credentials: SingleStoreCredentials; + } ) & { out: string; breakpoints: boolean; @@ -471,6 +503,25 @@ export const preparePullConfig = async ( }; } + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(config); + if (!parsed.success) { + printIssuesSingleStore(config); + process.exit(1); + } + + return { + dialect: 'singlestore', + out: config.out, + breakpoints: config.breakpoints, + casing: config.casing, + credentials: parsed.data, + tablesFilter, + schemasFilter, + prefix: config.migrations?.prefix || 'index', + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(config); if (!parsed.success) { @@ -560,6 +611,23 @@ export const prepareStudioConfig = async (options: Record) => { credentials, }; } + + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesSingleStore(flattened as Record); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + schema, + host, + port, + credentials, + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(flattened); if (!parsed.success) { @@ -645,6 +713,23 @@ export const prepareMigrateConfig = async (configPath: string | undefined) => { table, }; } + + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesSingleStore(flattened as Record); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + out, + credentials, + schema, + table, + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(flattened); if (!parsed.success) { diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 6c4b44634..5b90937d8 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -19,6 +19,7 @@ import { LibSQLCredentials } from './validations/libsql'; import type { MysqlCredentials } from './validations/mysql'; import { withStyle } from './validations/outputs'; import type { PostgresCredentials } from './validations/postgres'; +import { SingleStoreCredentials } from './validations/singlestore'; import type { SqliteCredentials } from './validations/sqlite'; export const preparePostgresDB = async ( @@ -326,6 +327,85 @@ export const preparePostgresDB = async ( process.exit(1); }; +const parseSingleStoreCredentials = (credentials: SingleStoreCredentials) => { + if ('url' in credentials) { + const url = credentials.url; + + const connectionUrl = new URL(url); + const pathname = connectionUrl.pathname; + + const database = pathname.split('/')[pathname.split('/').length - 1]; + if (!database) { + console.error( + 'You should specify a database name in connection string (singlestore://USER:PASSWORD@HOST:PORT/DATABASE)', + ); + process.exit(1); + } + return { database, url }; + } else { + return { + database: credentials.database, + credentials, + }; + } +}; + +export const connectToSingleStore = async ( + it: SingleStoreCredentials, +): Promise<{ + db: DB; + proxy: Proxy; + database: string; + migrate: (config: MigrationConfig) => Promise; +}> => { + const result = parseSingleStoreCredentials(it); + + if (await checkPackage('mysql2')) { + const { createConnection } = await import('mysql2/promise'); + const { drizzle } = await import('drizzle-orm/singlestore'); + const { migrate } = await import('drizzle-orm/singlestore/migrator'); + + const connection = result.url + ? await createConnection(result.url) + : await createConnection(result.credentials!); // needed for some reason! + + const db = drizzle(connection); + const migrateFn = async (config: MigrationConfig) => { + return migrate(db, config); + }; + + await connection.connect(); + const query: DB['query'] = async ( + sql: string, + params?: any[], + ): Promise => { + const res = await connection.execute(sql, params); + return res[0] as any; + }; + + const proxy: Proxy = async (params: ProxyParams) => { + const result = await connection.query({ + sql: params.sql, + values: params.params, + rowsAsArray: params.mode === 'array', + }); + return result[0] as any[]; + }; + + return { + db: { query }, + proxy, + database: result.database, + migrate: migrateFn, + }; + } + + console.error( + "To connect to SingleStore database - please install 'singlestore' driver", + ); + process.exit(1); +}; + const parseMysqlCredentials = (credentials: MysqlCredentials) => { if ('url' in credentials) { const url = credentials.url; diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index aaded5cdf..33a33d0fc 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -1,11 +1,19 @@ +import { boolean, command, number, string } from '@drizzle-team/brocli'; import chalk from 'chalk'; -import { checkHandler } from './commands/check'; -import { assertOrmCoreVersion, assertPackages, assertStudioNodeVersion, ormVersionGt } from './utils'; +import 'dotenv/config'; +import { mkdirSync } from 'fs'; +import { renderWithTask } from 'hanji'; +import { dialects } from 'src/schemaValidator'; import '../@types/utils'; +import { assertUnreachable } from '../global'; +import { drizzleForLibSQL, type Setup } from '../serializer/studio'; import { assertV1OutFolder } from '../utils'; +import { certs } from '../utils/certs'; +import { checkHandler } from './commands/check'; import { dropMigration } from './commands/drop'; import { upMysqlHandler } from './commands/mysqlUp'; import { upPgHandler } from './commands/pgUp'; +import { upSinglestoreHandler } from './commands/singlestoreUp'; import { upSqliteHandler } from './commands/sqliteUp'; import { prepareCheckParams, @@ -16,21 +24,14 @@ import { preparePushConfig, prepareStudioConfig, } from './commands/utils'; +import { assertOrmCoreVersion, assertPackages, assertStudioNodeVersion, ormVersionGt } from './utils'; import { assertCollisions, drivers, prefixes } from './validations/common'; import { withStyle } from './validations/outputs'; -import 'dotenv/config'; -import { boolean, command, number, string } from '@drizzle-team/brocli'; -import { mkdirSync } from 'fs'; -import { renderWithTask } from 'hanji'; -import { dialects } from 'src/schemaValidator'; -import { assertUnreachable } from '../global'; -import { drizzleForLibSQL, type Setup } from '../serializer/studio'; -import { certs } from '../utils/certs'; import { grey, MigrateProgress } from './views'; const optionDialect = string('dialect') .enum(...dialects) - .desc(`Database dialect: 'postgresql', 'mysql', 'sqlite' or 'turso'`); + .desc(`Database dialect: 'postgresql', 'mysql', 'sqlite', 'turso' or 'singlestore'`); const optionOut = string().desc("Output folder, 'drizzle' by default"); const optionConfig = string().desc('Path to drizzle config file'); const optionBreakpoints = boolean().desc( @@ -81,6 +82,7 @@ export const generate = command({ prepareAndMigrateMysql, prepareAndMigrateSqlite, prepareAndMigrateLibSQL, + prepareAndMigrateSingleStore, } = await import('./commands/migrate'); const dialect = opts.dialect; @@ -92,6 +94,8 @@ export const generate = command({ await prepareAndMigrateSqlite(opts); } else if (dialect === 'turso') { await prepareAndMigrateLibSQL(opts); + } else if (dialect === 'singlestore') { + await prepareAndMigrateSqlite(opts); } else { assertUnreachable(dialect); } @@ -154,6 +158,17 @@ export const migrate = command({ migrationsSchema: schema, }), ); + } else if (dialect === 'singlestore') { + const { connectToSingleStore } = await import('./connections'); + const { migrate } = await connectToSingleStore(credentials); + await renderWithTask( + new MigrateProgress(), + migrate({ + migrationsFolder: out, + migrationsTable: table, + migrationsSchema: schema, + }), + ); } else if (dialect === 'sqlite') { const { connectToSQLite } = await import('./connections'); const { migrate } = await connectToSQLite(credentials); @@ -338,6 +353,16 @@ export const push = command({ force, casing, ); + } else if (dialect === 'singlestore') { + const { singlestorePush } = await import('./commands/push'); + await singlestorePush( + schemaPath, + credentials, + tablesFilter, + strict, + verbose, + force, + ); } else { assertUnreachable(dialect); } @@ -396,6 +421,10 @@ export const up = command({ if (dialect === 'sqlite' || dialect === 'turso') { upSqliteHandler(out); } + + if (dialect === 'singlestore') { + upSinglestoreHandler(out); + } }, }); @@ -527,6 +556,16 @@ export const pull = command({ tablesFilter, prefix, ); + } else if (dialect === 'singlestore') { + const { introspectSingleStore } = await import('./commands/introspect'); + await introspectSingleStore( + casing, + out, + breakpoints, + credentials, + tablesFilter, + prefix, + ); } else { assertUnreachable(dialect); } @@ -587,6 +626,8 @@ export const studio = command({ drizzleForMySQL, prepareSQLiteSchema, drizzleForSQLite, + prepareSingleStoreSchema, + drizzleForSingleStore, } = await import('../serializer/studio'); let setup: Setup; @@ -632,6 +673,11 @@ export const studio = command({ ? await prepareSQLiteSchema(schemaPath) : { schema: {}, relations: {}, files: [] }; setup = await drizzleForLibSQL(credentials, schema, relations, files); + } else if (dialect === 'singlestore') { + const { schema, relations, files } = schemaPath + ? await prepareSingleStoreSchema(schemaPath) + : { schema: {}, relations: {}, files: [] }; + setup = await drizzleForSingleStore(credentials, schema, relations, files); } else { assertUnreachable(dialect); } diff --git a/drizzle-kit/src/cli/validations/outputs.ts b/drizzle-kit/src/cli/validations/outputs.ts index 6b92829d5..ad0423b97 100644 --- a/drizzle-kit/src/cli/validations/outputs.ts +++ b/drizzle-kit/src/cli/validations/outputs.ts @@ -26,7 +26,7 @@ export const outputs = { ), noDialect: () => withStyle.error( - `Please specify 'dialect' param in config, either of 'pg', 'mysql' or 'sqlite'`, + `Please specify 'dialect' param in config, either of 'pg', 'mysql', 'sqlite' or singlestore`, ), }, common: { @@ -79,4 +79,13 @@ export const outputs = { introspect: {}, push: {}, }, + singlestore: { + connection: { + driver: () => withStyle.error(`Only "mysql2" is available options for "--driver"`), + required: () => + withStyle.error( + `Either "url" or "host", "database" are required for database connection`, + ), + }, + }, }; diff --git a/drizzle-kit/src/cli/validations/singlestore.ts b/drizzle-kit/src/cli/validations/singlestore.ts new file mode 100644 index 000000000..ebe0cc5f0 --- /dev/null +++ b/drizzle-kit/src/cli/validations/singlestore.ts @@ -0,0 +1,61 @@ +import { boolean, coerce, object, string, TypeOf, union } from 'zod'; +import { error } from '../views'; +import { wrapParam } from './common'; +import { outputs } from './outputs'; + +export const singlestoreCredentials = union([ + object({ + host: string().min(1), + port: coerce.number().min(1).optional(), + user: string().min(1).optional(), + password: string().min(1).optional(), + database: string().min(1), + ssl: union([ + string(), + object({ + pfx: string().optional(), + key: string().optional(), + passphrase: string().optional(), + cert: string().optional(), + ca: union([string(), string().array()]).optional(), + crl: union([string(), string().array()]).optional(), + ciphers: string().optional(), + rejectUnauthorized: boolean().optional(), + }), + ]).optional(), + }), + object({ + url: string().min(1), + }), +]); + +export type SingleStoreCredentials = TypeOf; + +export const printCliConnectionIssues = (options: any) => { + const { uri, host, database } = options || {}; + + if (!uri && (!host || !database)) { + console.log(outputs.singlestore.connection.required()); + } +}; + +export const printConfigConnectionIssues = ( + options: Record, +) => { + if ('url' in options) { + let text = `Please provide required params for SingleStore driver:\n`; + console.log(error(text)); + console.log(wrapParam('url', options.url, false, 'url')); + process.exit(1); + } + + let text = `Please provide required params for SingleStore driver:\n`; + console.log(error(text)); + console.log(wrapParam('host', options.host)); + console.log(wrapParam('port', options.port, true)); + console.log(wrapParam('user', options.user, true)); + console.log(wrapParam('password', options.password, true, 'secret')); + console.log(wrapParam('database', options.database)); + console.log(wrapParam('ssl', options.ssl, true)); + process.exit(1); +}; diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 750d491ac..d5b73123d 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -23,7 +23,7 @@ type Verify = U; * **Config** usage: * * `dialect` - mandatory and is responsible for explicitly providing a databse dialect you are using for all the commands - * *Possible values*: `postgresql`, `mysql`, `sqlite` + * *Possible values*: `postgresql`, `mysql`, `sqlite`, `singlestore * * See https://orm.drizzle.team/kit-docs/config-reference#dialect * @@ -64,7 +64,7 @@ type Verify = U; * * `breakpoints` - param lets you enable/disable SQL statement breakpoints in generated migrations. * It’s optional and true by default, it’s necessary to properly apply migrations on databases, - * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite) and + * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite, SingleStore) and * Drizzle ORM has to apply them sequentially one by one. * * See https://orm.drizzle.team/kit-docs/config-reference#breakpoints @@ -207,6 +207,21 @@ export type Config = driver: Verify; } | {} + | { + dialect: Verify; + dbCredentials: + | { + host: string; + port?: number; + user?: string; + password?: string; + database: string; + ssl?: string | SslOptions; + } + | { + url: string; + }; + } ); /** @@ -216,7 +231,7 @@ export type Config = * **Config** usage: * * `dialect` - mandatory and is responsible for explicitly providing a databse dialect you are using for all the commands - * *Possible values*: `postgresql`, `mysql`, `sqlite` + * *Possible values*: `postgresql`, `mysql`, `sqlite`, `singlestore` * * See https://orm.drizzle.team/kit-docs/config-reference#dialect * @@ -257,7 +272,7 @@ export type Config = * * `breakpoints` - param lets you enable/disable SQL statement breakpoints in generated migrations. * It’s optional and true by default, it’s necessary to properly apply migrations on databases, - * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite) and + * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite, SingleStore) and * Drizzle ORM has to apply them sequentially one by one. * * See https://orm.drizzle.team/kit-docs/config-reference#breakpoints diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts new file mode 100644 index 000000000..8aa6e3dd7 --- /dev/null +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -0,0 +1,780 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +import './@types/utils'; +import type { Casing } from './cli/validations/common'; +import { Column, Index, PrimaryKey, SingleStoreSchemaInternal, UniqueConstraint } from './serializer/singlestoreSchema'; +import { indexName } from './serializer/singlestoreSerializer'; + +// time precision to fsp +// {mode: "string"} for timestamp by default + +const singlestoreImportsList = new Set([ + 'singlestoreTable', + 'singlestoreEnum', + 'bigint', + 'binary', + 'boolean', + 'char', + 'date', + 'datetime', + 'decimal', + 'double', + 'float', + 'int', + 'json', + // TODO: add new type BSON + // TODO: add new type Blob + // TODO: add new type UUID + // TODO: add new type GUID + // TODO: add new type Vector + // TODO: add new type GeoPoint + 'mediumint', + 'real', + 'serial', + 'smallint', + 'text', + 'tinytext', + 'mediumtext', + 'longtext', + 'time', + 'timestamp', + 'tinyint', + 'varbinary', + 'varchar', + 'year', + 'enum', +]); + +const objToStatement = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `"${it}": "${json[it]}"`).join(', '); + statement += ' }'; + return statement; +}; + +const objToStatement2 = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: "${json[it]}"`).join(', '); // no "" for keys + statement += ' }'; + return statement; +}; + +const timeConfig = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: ${json[it]}`).join(', '); + statement += ' }'; + return statement; +}; + +const binaryConfig = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: ${json[it]}`).join(', '); + statement += ' }'; + return statement; +}; + +const importsPatch = { + 'double precision': 'doublePrecision', + 'timestamp without time zone': 'timestamp', +} as Record; + +const relations = new Set(); + +const prepareCasing = (casing?: Casing) => (value: string) => { + if (typeof casing === 'undefined') { + return value; + } + if (casing === 'camel') { + return value.camelCase(); + } + + return value; +}; + +export const schemaToTypeScript = ( + schema: SingleStoreSchemaInternal, + casing: Casing, +) => { + const withCasing = prepareCasing(casing); + + const imports = Object.values(schema.tables).reduce( + (res, it) => { + const idxImports = Object.values(it.indexes).map((idx) => idx.isUnique ? 'uniqueIndex' : 'index'); + const pkImports = Object.values(it.compositePrimaryKeys).map( + (it) => 'primaryKey', + ); + const uniqueImports = Object.values(it.uniqueConstraints).map( + (it) => 'unique', + ); + + res.singlestore.push(...idxImports); + res.singlestore.push(...pkImports); + res.singlestore.push(...uniqueImports); + + const columnImports = Object.values(it.columns) + .map((col) => { + let patched = importsPatch[col.type] ?? col.type; + patched = patched.startsWith('varchar(') ? 'varchar' : patched; + patched = patched.startsWith('char(') ? 'char' : patched; + patched = patched.startsWith('binary(') ? 'binary' : patched; + patched = patched.startsWith('decimal(') ? 'decimal' : patched; + patched = patched.startsWith('smallint(') ? 'smallint' : patched; + patched = patched.startsWith('enum(') ? 'singlestoreEnum' : patched; + patched = patched.startsWith('datetime(') ? 'datetime' : patched; + patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; + patched = patched.startsWith('int(') ? 'int' : patched; + return patched; + }) + .filter((type) => { + return singlestoreImportsList.has(type); + }); + + res.singlestore.push(...columnImports); + return res; + }, + { singlestore: [] as string[] }, + ); + + const tableStatements = Object.values(schema.tables).map((table) => { + const func = 'singlestoreTable'; + let statement = ''; + if (imports.singlestore.includes(withCasing(table.name))) { + statement = `// Table name is in conflict with ${ + withCasing( + table.name, + ) + } import.\n// Please change to any other name, that is not in imports list\n`; + } + statement += `export const ${withCasing(table.name)} = ${func}("${table.name}", {\n`; + statement += createTableColumns( + Object.values(table.columns), + withCasing, + table.name, + schema, + ); + statement += '}'; + + if ( + Object.keys(table.indexes).length > 0 + || Object.keys(table.compositePrimaryKeys).length > 0 + || Object.keys(table.uniqueConstraints).length > 0 + ) { + statement += ',\n'; + statement += '(table) => {\n'; + statement += '\treturn {\n'; + statement += createTableIndexes( + table.name, + Object.values(table.indexes), + withCasing, + ); + statement += createTablePKs( + Object.values(table.compositePrimaryKeys), + withCasing, + ); + statement += createTableUniques( + Object.values(table.uniqueConstraints), + withCasing, + ); + statement += '\t}\n'; + statement += '}'; + } + + statement += ');'; + return statement; + }); + + const uniqueSingleStoreImports = [ + 'singlestoreTable', + 'singlestoreSchema', + 'AnySingleStoreColumn', + ...new Set(imports.singlestore), + ]; + const importsTs = `import { ${ + uniqueSingleStoreImports.join( + ', ', + ) + } } from "drizzle-orm/singlestore-core"\nimport { sql } from "drizzle-orm"\n\n`; + + let decalrations = ''; + decalrations += tableStatements.join('\n\n'); + + const file = importsTs + decalrations; + + const schemaEntry = ` + { + ${ + Object.values(schema.tables) + .map((it) => withCasing(it.name)) + .join(',') + } + } + `; + + return { + file, // backward compatible, print to file + imports: importsTs, + decalrations, + schemaEntry, + }; +}; + +const mapColumnDefault = (defaultValue: any, isExpression?: boolean) => { + if (isExpression) { + return `sql\`${defaultValue}\``; + } + + return defaultValue; +}; + +const mapColumnDefaultForJson = (defaultValue: any) => { + if ( + typeof defaultValue === 'string' + && defaultValue.startsWith("('") + && defaultValue.endsWith("')") + ) { + return defaultValue.substring(2, defaultValue.length - 2); + } + + return defaultValue; +}; + +const column = ( + type: string, + name: string, + casing: (value: string) => string, + defaultValue?: any, + autoincrement?: boolean, + onUpdate?: boolean, + isExpression?: boolean, +) => { + let lowered = type; + if (!type.startsWith('enum(')) { + lowered = type.toLowerCase(); + } + + if (lowered === 'serial') { + return `${casing(name)}: serial("${name}")`; + } + + if (lowered.startsWith('int')) { + const isUnsigned = lowered.startsWith('int unsigned'); + let out = `${casing(name)}: int("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('tinyint')) { + const isUnsigned = lowered.startsWith('tinyint unsigned'); + // let out = `${name.camelCase()}: tinyint("${name}")`; + let out: string = `${casing(name)}: tinyint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('smallint')) { + const isUnsigned = lowered.startsWith('smallint unsigned'); + let out = `${casing(name)}: smallint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('mediumint')) { + const isUnsigned = lowered.startsWith('mediumint unsigned'); + let out = `${casing(name)}: mediumint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('bigint')) { + const isUnsigned = lowered.startsWith('bigint unsigned'); + let out = `${casing(name)}: bigint("${name}", { mode: "number"${isUnsigned ? ', unsigned: true' : ''} })`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'boolean') { + let out = `${casing(name)}: boolean("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('double')) { + let params: + | { precision: string | undefined; scale: string | undefined } + | undefined; + + if (lowered.length > 6) { + const [precision, scale] = lowered + .slice(7, lowered.length - 1) + .split(','); + params = { precision, scale }; + } + + let out = params + ? `${casing(name)}: double("${name}", ${timeConfig(params)})` + : `${casing(name)}: double("${name}")`; + + // let out = `${name.camelCase()}: double("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'float') { + let out = `${casing(name)}: float("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'real') { + let out = `${casing(name)}: real("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('timestamp')) { + const keyLength = 'timestamp'.length + 1; + let fsp = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + fsp = fsp ? fsp : null; + + const params = timeConfig({ fsp, mode: "'string'" }); + + let out = params + ? `${casing(name)}: timestamp("${name}", ${params})` + : `${casing(name)}: timestamp("${name}")`; + + // TODO: check if SingleStore has defaultNow() or now() + defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + + // TODO: check if SingleStore has onUpdateNow() + let onUpdateNow = onUpdate ? '.onUpdateNow()' : ''; + out += onUpdateNow; + + return out; + } + + if (lowered.startsWith('time')) { + const keyLength = 'time'.length + 1; + let fsp = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + fsp = fsp ? fsp : null; + + const params = timeConfig({ fsp }); + + let out = params + ? `${casing(name)}: time("${name}", ${params})` + : `${casing(name)}: time("${name}")`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered === 'date') { + let out = `// you can use { mode: 'date' }, if you want to have Date as type for this column\n\t${ + casing( + name, + ) + }: date("${name}", { mode: 'string' })`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has text can't have default value + if (lowered === 'text') { + let out = `${casing(name)}: text("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has tinytext can't have default value + if (lowered === 'tinytext') { + let out = `${casing(name)}: tinytext("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has mediumtext can't have default value + if (lowered === 'mediumtext') { + let out = `${casing(name)}: mediumtext("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has longtext can't have default value + if (lowered === 'longtext') { + let out = `${casing(name)}: longtext("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'year') { + let out = `${casing(name)}: year("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql json can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has json can't have default value + if (lowered === 'json') { + let out = `${casing(name)}: json("${name}")`; + + out += defaultValue + ? `.default(${mapColumnDefaultForJson(defaultValue)})` + : ''; + + return out; + } + + // TODO: add new type BSON + + // TODO: add new type Blob + + // TODO: add new type UUID + + // TODO: add new type GUID + + // TODO: add new type Vector + + // TODO: add new type GeoPoint + + if (lowered.startsWith('varchar')) { + let out: string = `${ + casing( + name, + ) + }: varchar("${name}", { length: ${ + lowered.substring( + 'varchar'.length + 1, + lowered.length - 1, + ) + } })`; + + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('char')) { + let out: string = `${ + casing( + name, + ) + }: char("${name}", { length: ${ + lowered.substring( + 'char'.length + 1, + lowered.length - 1, + ) + } })`; + + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('datetime')) { + let out = `// you can use { mode: 'date' }, if you want to have Date as type for this column\n\t`; + + const fsp = lowered.startsWith('datetime(') + ? lowered.substring('datetime'.length + 1, lowered.length - 1) + : undefined; + + out = fsp + ? `${ + casing( + name, + ) + }: datetime("${name}", { mode: 'string', fsp: ${ + lowered.substring( + 'datetime'.length + 1, + lowered.length - 1, + ) + } })` + : `${casing(name)}: datetime("${name}", { mode: 'string'})`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('decimal')) { + let params: + | { precision: string | undefined; scale: string | undefined } + | undefined; + + if (lowered.length > 7) { + const [precision, scale] = lowered + .slice(8, lowered.length - 1) + .split(','); + params = { precision, scale }; + } + + let out = params + ? `${casing(name)}: decimal("${name}", ${timeConfig(params)})` + : `${casing(name)}: decimal("${name}")`; + + defaultValue = typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('binary')) { + const keyLength = 'binary'.length + 1; + let length = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + length = length ? length : null; + + const params = binaryConfig({ length }); + + let out = params + ? `${casing(name)}: binary("${name}", ${params})` + : `${casing(name)}: binary("${name}")`; + + defaultValue = defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('enum')) { + const values = lowered.substring('enum'.length + 1, lowered.length - 1); + let out = `${casing(name)}: singlestoreEnum("${name}", [${values}])`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('varbinary')) { + const keyLength = 'varbinary'.length + 1; + let length = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + length = length ? length : null; + + const params = binaryConfig({ length }); + + let out = params + ? `${casing(name)}: varbinary("${name}", ${params})` + : `${casing(name)}: varbinary("${name}")`; + + defaultValue = defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + console.log('uknown', type); + return `// Warning: Can't parse ${type} from database\n\t// ${type}Type: ${type}("${name}")`; +}; + +const createTableColumns = ( + columns: Column[], + casing: (val: string) => string, + tableName: string, + schema: SingleStoreSchemaInternal, +): string => { + let statement = ''; + + columns.forEach((it) => { + statement += '\t'; + statement += column( + it.type, + it.name, + casing, + it.default, + it.autoincrement, + it.onUpdate, + schema.internal?.tables![tableName]?.columns[it.name] + ?.isDefaultAnExpression ?? false, + ); + statement += it.primaryKey ? '.primaryKey()' : ''; + statement += it.notNull ? '.notNull()' : ''; + + statement += it.generated + ? `.generatedAlwaysAs(sql\`${ + it.generated.as.replace( + /`/g, + '\\`', + ) + }\`, { mode: "${it.generated.type}" })` + : ''; + + statement += ',\n'; + }); + + return statement; +}; + +const createTableIndexes = ( + tableName: string, + idxs: Index[], + casing: (value: string) => string, +): string => { + let statement = ''; + + idxs.forEach((it) => { + let idxKey = it.name.startsWith(tableName) && it.name !== tableName + ? it.name.slice(tableName.length + 1) + : it.name; + idxKey = idxKey.endsWith('_index') + ? idxKey.slice(0, -'_index'.length) + '_idx' + : idxKey; + + idxKey = casing(idxKey); + + const indexGeneratedName = indexName(tableName, it.columns); + const escapedIndexName = indexGeneratedName === it.name ? '' : `"${it.name}"`; + + statement += `\t\t${idxKey}: `; + statement += it.isUnique ? 'uniqueIndex(' : 'index('; + statement += `${escapedIndexName})`; + statement += `.on(${ + it.columns + .map((it) => `table.${casing(it)}`) + .join(', ') + }),`; + statement += `\n`; + }); + + return statement; +}; + +const createTableUniques = ( + unqs: UniqueConstraint[], + casing: (value: string) => string, +): string => { + let statement = ''; + + unqs.forEach((it) => { + const idxKey = casing(it.name); + + statement += `\t\t${idxKey}: `; + statement += 'unique('; + statement += `"${it.name}")`; + statement += `.on(${ + it.columns + .map((it) => `table.${casing(it)}`) + .join(', ') + }),`; + statement += `\n`; + }); + + return statement; +}; + +const createTablePKs = ( + pks: PrimaryKey[], + casing: (value: string) => string, +): string => { + let statement = ''; + + pks.forEach((it) => { + let idxKey = casing(it.name); + + statement += `\t\t${idxKey}: `; + statement += 'primaryKey({ columns: ['; + statement += `${ + it.columns + .map((c) => { + return `table.${casing(c)}`; + }) + .join(', ') + }]${it.name ? `, name: "${it.name}"` : ''}}`; + statement += '),'; + statement += `\n`; + }); + + return statement; +}; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 4285c4687..bf4539397 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -4,6 +4,7 @@ import { warning } from './cli/views'; import { CommonSquashedSchema } from './schemaValidator'; import { MySqlKitInternals, MySqlSchema, MySqlSquasher, View as MySqlView } from './serializer/mysqlSchema'; import { Index, MatViewWithOption, PgSchema, PgSquasher, View as PgView, ViewWithOption } from './serializer/pgSchema'; +import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, @@ -40,7 +41,7 @@ export interface JsonCreateTableStatement { compositePkName?: string; uniqueConstraints?: string[]; checkConstraints?: string[]; - internals?: MySqlKitInternals; + internals?: MySqlKitInternals | SingleStoreKitInternals; } export interface JsonRecreateTableStatement { @@ -193,7 +194,7 @@ export interface JsonCreateIndexStatement { tableName: string; data: string; schema: string; - internal?: MySqlKitInternals | SQLiteKitInternals; + internal?: MySqlKitInternals | SQLiteKitInternals | SingleStoreKitInternals; } export interface JsonPgCreateIndexStatement { @@ -776,6 +777,34 @@ export const prepareMySqlCreateTableJson = ( }; }; +export const prepareSingleStoreCreateTableJson = ( + table: Table, + // TODO: remove? + json2: SingleStoreSchema, + // we need it to know if some of the indexes(and in future other parts) are expressions or columns + // didn't change singlestoreserialaizer, because it will break snapshots and diffs and it's hard to detect + // if previously it was an expression or column + internals: SingleStoreKitInternals, +): JsonCreateTableStatement => { + const { name, schema, columns, compositePrimaryKeys, uniqueConstraints } = table; + + return { + type: 'create_table', + tableName: name, + schema, + columns: Object.values(columns), + compositePKs: Object.values(compositePrimaryKeys), + compositePkName: Object.values(compositePrimaryKeys).length > 0 + ? json2.tables[name].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(Object.values(compositePrimaryKeys)[0]) + .name + ].name + : '', + uniqueConstraints: Object.values(uniqueConstraints), + internals, + }; +}; + export const prepareSQLiteCreateTable = ( table: Table, action?: 'push' | undefined, @@ -1026,7 +1055,7 @@ export const prepareDeleteSchemasJson = ( export const prepareRenameColumns = ( tableName: string, - // TODO: split for pg and mysql+sqlite without schema + // TODO: split for pg and mysql+sqlite and singlestore without schema schema: string, pairs: { from: Column; to: Column }[], ): JsonRenameColumnStatement[] => { @@ -1456,6 +1485,363 @@ export const prepareAlterColumnsMysql = ( return [...dropPkStatements, ...setPkStatements, ...statements]; }; +export const prepareAlterColumnsSingleStore = ( + tableName: string, + schema: string, + columns: AlteredColumn[], + // TODO: remove? + json1: CommonSquashedSchema, + json2: CommonSquashedSchema, + action?: 'push' | undefined, +): JsonAlterColumnStatement[] => { + let statements: JsonAlterColumnStatement[] = []; + let dropPkStatements: JsonAlterColumnDropPrimaryKeyStatement[] = []; + let setPkStatements: JsonAlterColumnSetPrimaryKeyStatement[] = []; + + for (const column of columns) { + const columnName = typeof column.name !== 'string' ? column.name.new : column.name; + + const table = json2.tables[tableName]; + const snapshotColumn = table.columns[columnName]; + + const columnType = snapshotColumn.type; + const columnDefault = snapshotColumn.default; + const columnOnUpdate = 'onUpdate' in snapshotColumn ? snapshotColumn.onUpdate : undefined; + const columnNotNull = table.columns[columnName].notNull; + + const columnAutoIncrement = 'autoincrement' in snapshotColumn + ? snapshotColumn.autoincrement ?? false + : false; + + const columnPk = table.columns[columnName].primaryKey; + + if (column.autoincrement?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'changed') { + const type = column.autoincrement.new + ? 'alter_table_alter_column_set_autoincrement' + : 'alter_table_alter_column_drop_autoincrement'; + + statements.push({ + type, + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + } + + for (const column of columns) { + const columnName = typeof column.name !== 'string' ? column.name.new : column.name; + + // I used any, because those fields are available only for mysql and singlestore dialect + // For other dialects it will become undefined, that is fine for json statements + const columnType = json2.tables[tableName].columns[columnName].type; + const columnDefault = json2.tables[tableName].columns[columnName].default; + const columnGenerated = json2.tables[tableName].columns[columnName].generated; + const columnOnUpdate = (json2.tables[tableName].columns[columnName] as any) + .onUpdate; + const columnNotNull = json2.tables[tableName].columns[columnName].notNull; + const columnAutoIncrement = ( + json2.tables[tableName].columns[columnName] as any + ).autoincrement; + const columnPk = (json2.tables[tableName].columns[columnName] as any) + .primaryKey; + + const compositePk = json2.tables[tableName].compositePrimaryKeys[ + `${tableName}_${columnName}` + ]; + + if (typeof column.name !== 'string') { + statements.push({ + type: 'alter_table_rename_column', + tableName, + oldColumnName: column.name.old, + newColumnName: column.name.new, + schema, + }); + } + + if (column.type?.type === 'changed') { + statements.push({ + type: 'alter_table_alter_column_set_type', + tableName, + columnName, + newDataType: column.type.new, + oldDataType: column.type.old, + schema, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if ( + column.primaryKey?.type === 'deleted' + || (column.primaryKey?.type === 'changed' + && !column.primaryKey.new + && typeof compositePk === 'undefined') + ) { + dropPkStatements.push({ + //// + type: 'alter_table_alter_column_drop_pk', + tableName, + columnName, + schema, + }); + } + + if (column.default?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_default', + tableName, + columnName, + newDefaultValue: column.default.value, + schema, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.default?.type === 'changed') { + statements.push({ + type: 'alter_table_alter_column_set_default', + tableName, + columnName, + newDefaultValue: column.default.new, + oldDefaultValue: column.default.old, + schema, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.default?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_default', + tableName, + columnName, + schema, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.notNull?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_notnull', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.notNull?.type === 'changed') { + const type = column.notNull.new + ? 'alter_table_alter_column_set_notnull' + : 'alter_table_alter_column_drop_notnull'; + statements.push({ + type: type, + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.notNull?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_notnull', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.generated?.type === 'added') { + if (columnGenerated?.type === 'virtual') { + // TODO: Change warning message according to SingleStore docs + warning( + `You are trying to add virtual generated constraint to ${ + chalk.blue( + columnName, + ) + } column. As MySQL docs mention: "Nongenerated columns can be altered to stored but not virtual generated columns". We will drop an existing column and add it with a virtual generated statement. This means that the data previously stored in this column will be wiped, and new data will be generated on each read for this column\n`, + ); + } + statements.push({ + type: 'alter_table_alter_column_set_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if (column.generated?.type === 'changed' && action !== 'push') { + statements.push({ + type: 'alter_table_alter_column_alter_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if (column.generated?.type === 'deleted') { + if (columnGenerated?.type === 'virtual') { + // TODO: Change warning message according to SingleStore docs + warning( + `You are trying to remove virtual generated constraint from ${ + chalk.blue( + columnName, + ) + } column. As MySQL docs mention: "Stored but not virtual generated columns can be altered to nongenerated columns. The stored generated values become the values of the nongenerated column". We will drop an existing column and add it without a virtual generated statement. This means that this column will have no data after migration\n`, + ); + } + statements.push({ + type: 'alter_table_alter_column_drop_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + oldColumn: json1.tables[tableName].columns[columnName], + }); + } + + if ( + column.primaryKey?.type === 'added' + || (column.primaryKey?.type === 'changed' && column.primaryKey.new) + ) { + const wasAutoincrement = statements.filter( + (it) => it.type === 'alter_table_alter_column_set_autoincrement', + ); + if (wasAutoincrement.length === 0) { + setPkStatements.push({ + type: 'alter_table_alter_column_set_pk', + tableName, + schema, + columnName, + }); + } + } + + if (column.onUpdate?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_on_update', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.onUpdate?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_on_update', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + } + + return [...dropPkStatements, ...setPkStatements, ...statements]; +}; + export const preparePgAlterColumns = ( _tableName: string, schema: string, @@ -2791,3 +3177,72 @@ export const prepareMySqlAlterView = ( ): JsonAlterMySqlViewStatement => { return { type: 'alter_mysql_view', ...view }; }; + +export const prepareAddCompositePrimaryKeySingleStore = ( + tableName: string, + pks: Record, + // TODO: remove? + json1: SingleStoreSchema, + json2: SingleStoreSchema, +): JsonCreateCompositePK[] => { + const res: JsonCreateCompositePK[] = []; + for (const it of Object.values(pks)) { + const unsquashed = SingleStoreSquasher.unsquashPK(it); + + if ( + unsquashed.columns.length === 1 + && json1.tables[tableName]?.columns[unsquashed.columns[0]]?.primaryKey + ) { + continue; + } + + res.push({ + type: 'create_composite_pk', + tableName, + data: it, + constraintName: json2.tables[tableName].compositePrimaryKeys[unsquashed.name].name, + } as JsonCreateCompositePK); + } + return res; +}; + +export const prepareDeleteCompositePrimaryKeySingleStore = ( + tableName: string, + pks: Record, + // TODO: remove? + json1: SingleStoreSchema, +): JsonDeleteCompositePK[] => { + return Object.values(pks).map((it) => { + return { + type: 'delete_composite_pk', + tableName, + data: it, + constraintName: json1.tables[tableName].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(it).name + ].name, + } as JsonDeleteCompositePK; + }); +}; + +export const prepareAlterCompositePrimaryKeySingleStore = ( + tableName: string, + pks: Record, + // TODO: remove? + json1: SingleStoreSchema, + json2: SingleStoreSchema, +): JsonAlterCompositePK[] => { + return Object.values(pks).map((it) => { + return { + type: 'alter_composite_pk', + tableName, + old: it.__old, + new: it.__new, + oldConstraintName: json1.tables[tableName].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(it.__old).name + ].name, + newConstraintName: json2.tables[tableName].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(it.__new).name + ].name, + } as JsonAlterCompositePK; + }); +}; diff --git a/drizzle-kit/src/migrationPreparator.ts b/drizzle-kit/src/migrationPreparator.ts index d61f804ca..262f4dcba 100644 --- a/drizzle-kit/src/migrationPreparator.ts +++ b/drizzle-kit/src/migrationPreparator.ts @@ -1,9 +1,10 @@ import { randomUUID } from 'crypto'; import fs from 'fs'; import { CasingType } from './cli/validations/common'; -import { serializeMySql, serializePg, serializeSQLite } from './serializer'; +import { serializeMySql, serializePg, serializeSingleStore, serializeSQLite } from './serializer'; import { dryMySql, MySqlSchema, mysqlSchema } from './serializer/mysqlSchema'; import { dryPg, PgSchema, pgSchema, PgSchemaInternal } from './serializer/pgSchema'; +import { drySingleStore, SingleStoreSchema, singlestoreSchema } from './serializer/singlestoreSchema'; import { drySQLite, SQLiteSchema, sqliteSchema } from './serializer/sqliteSchema'; export const prepareMySqlDbPushSnapshot = async ( @@ -22,6 +23,21 @@ export const prepareMySqlDbPushSnapshot = async ( return { prev, cur: result }; }; +export const prepareSingleStoreDbPushSnapshot = async ( + prev: SingleStoreSchema, + schemaPath: string | string[], +): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema }> => { + const serialized = await serializeSingleStore(schemaPath); + + const id = randomUUID(); + const idPrev = prev.id; + + const { version, dialect, ...rest } = serialized; + const result: SingleStoreSchema = { version, dialect, id, prevId: idPrev, ...rest }; + + return { prev, cur: result }; +}; + export const prepareSQLiteDbPushSnapshot = async ( prev: SQLiteSchema, schemaPath: string | string[], @@ -89,6 +105,33 @@ export const prepareMySqlMigrationSnapshot = async ( return { prev: prevSnapshot, cur: result, custom }; }; +export const prepareSingleStoreMigrationSnapshot = async ( + migrationFolders: string[], + schemaPath: string | string[], +): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema; custom: SingleStoreSchema }> => { + const prevSnapshot = singlestoreSchema.parse( + preparePrevSnapshot(migrationFolders, drySingleStore), + ); + const serialized = await serializeSingleStore(schemaPath); + + const id = randomUUID(); + const idPrev = prevSnapshot.id; + + const { version, dialect, ...rest } = serialized; + const result: SingleStoreSchema = { version, dialect, id, prevId: idPrev, ...rest }; + + const { id: _ignoredId, prevId: _ignoredPrevId, ...prevRest } = prevSnapshot; + + // that's for custom migrations, when we need new IDs, but old snapshot + const custom: SingleStoreSchema = { + id, + prevId: idPrev, + ...prevRest, + }; + + return { prev: prevSnapshot, cur: result, custom }; +}; + export const prepareSqliteMigrationSnapshot = async ( snapshots: string[], schemaPath: string | string[], diff --git a/drizzle-kit/src/schemaValidator.ts b/drizzle-kit/src/schemaValidator.ts index 6ad29a544..e91b5ab11 100644 --- a/drizzle-kit/src/schemaValidator.ts +++ b/drizzle-kit/src/schemaValidator.ts @@ -1,9 +1,10 @@ import { enum as enumType, TypeOf, union } from 'zod'; import { mysqlSchema, mysqlSchemaSquashed } from './serializer/mysqlSchema'; import { pgSchema, pgSchemaSquashed } from './serializer/pgSchema'; +import { singlestoreSchema, singlestoreSchemaSquashed } from './serializer/singlestoreSchema'; import { sqliteSchema, SQLiteSchemaSquashed } from './serializer/sqliteSchema'; -export const dialects = ['postgresql', 'mysql', 'sqlite', 'turso'] as const; +export const dialects = ['postgresql', 'mysql', 'sqlite', 'turso', 'singlestore'] as const; export const dialect = enumType(dialects); export type Dialect = (typeof dialects)[number]; @@ -13,9 +14,10 @@ const commonSquashedSchema = union([ pgSchemaSquashed, mysqlSchemaSquashed, SQLiteSchemaSquashed, + singlestoreSchemaSquashed, ]); -const commonSchema = union([pgSchema, mysqlSchema, sqliteSchema]); +const commonSchema = union([pgSchema, mysqlSchema, sqliteSchema, singlestoreSchema]); export type CommonSquashedSchema = TypeOf; export type CommonSchema = TypeOf; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index 05e4a6f37..44e86a8bf 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -8,6 +8,7 @@ import { CasingType } from 'src/cli/validations/common'; import { error } from '../cli/views'; import type { MySqlSchemaInternal } from './mysqlSchema'; import type { PgSchemaInternal } from './pgSchema'; +import { SingleStoreSchemaInternal } from './singlestoreSchema'; import type { SQLiteSchemaInternal } from './sqliteSchema'; export const sqlToStr = (sql: SQL, casing: CasingType | undefined) => { @@ -85,6 +86,21 @@ export const serializeSQLite = async ( return generateSqliteSnapshot(tables, views, casing); }; +export const serializeSingleStore = async ( + path: string | string[], +): Promise => { + const filenames = prepareFilenames(path); + + console.log(chalk.gray(`Reading schema files:\n${filenames.join('\n')}\n`)); + + const { prepareFromSingleStoreImports } = await import('./singlestoreImports'); + const { generateSingleStoreSnapshot } = await import('./singlestoreSerializer'); + + const { tables } = await prepareFromSingleStoreImports(filenames); + + return generateSingleStoreSnapshot(tables); +}; + export const prepareFilenames = (path: string | string[]) => { if (typeof path === 'string') { path = [path]; diff --git a/drizzle-kit/src/serializer/singlestoreImports.ts b/drizzle-kit/src/serializer/singlestoreImports.ts new file mode 100644 index 000000000..fe9cf04ff --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreImports.ts @@ -0,0 +1,38 @@ +import { is } from 'drizzle-orm'; +import { AnySingleStoreTable, SingleStoreTable, SingleStoreView } from 'drizzle-orm/singlestore-core'; +import { safeRegister } from '../cli/commands/utils'; + +export const prepareFromExports = (exports: Record) => { + const tables: AnySingleStoreTable[] = []; + const views: SingleStoreView[] = []; + + const i0values = Object.values(exports); + i0values.forEach((t) => { + if (is(t, SingleStoreTable)) { + tables.push(t); + } + + if (is(t, SingleStoreView)) { + views.push(t); + } + }); + + return { tables, views }; +}; + +export const prepareFromSingleStoreImports = async (imports: string[]) => { + const tables: AnySingleStoreTable[] = []; + const views: SingleStoreView[] = []; + + const { unregister } = await safeRegister(); + for (let i = 0; i < imports.length; i++) { + const it = imports[i]; + const i0: Record = require(`${it}`); + const prepared = prepareFromExports(i0); + + tables.push(...prepared.tables); + views.push(...prepared.views); + } + unregister(); + return { tables: Array.from(new Set(tables)), views }; +}; diff --git a/drizzle-kit/src/serializer/singlestoreSchema.ts b/drizzle-kit/src/serializer/singlestoreSchema.ts new file mode 100644 index 000000000..a0bbae1bf --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreSchema.ts @@ -0,0 +1,203 @@ +import { any, boolean, enum as enumType, literal, object, record, string, TypeOf, union } from 'zod'; +import { mapValues, originUUID, snapshotVersion } from '../global'; + +// ------- V3 -------- +const index = object({ + name: string(), + columns: string().array(), + isUnique: boolean(), + using: enumType(['btree', 'hash']).optional(), + algorithm: enumType(['default', 'inplace', 'copy']).optional(), + lock: enumType(['default', 'none', 'shared', 'exclusive']).optional(), +}).strict(); + +const column = object({ + name: string(), + type: string(), + primaryKey: boolean(), + notNull: boolean(), + autoincrement: boolean().optional(), + default: any().optional(), + onUpdate: any().optional(), + generated: object({ + type: enumType(['stored', 'virtual']), + as: string(), + }).optional(), +}).strict(); + +const compositePK = object({ + name: string(), + columns: string().array(), +}).strict(); + +const uniqueConstraint = object({ + name: string(), + columns: string().array(), +}).strict(); + +const table = object({ + name: string(), + columns: record(string(), column), + indexes: record(string(), index), + compositePrimaryKeys: record(string(), compositePK), + uniqueConstraints: record(string(), uniqueConstraint).default({}), +}).strict(); + +export const kitInternals = object({ + tables: record( + string(), + object({ + columns: record( + string(), + object({ isDefaultAnExpression: boolean().optional() }).optional(), + ), + }).optional(), + ).optional(), + indexes: record( + string(), + object({ + columns: record( + string(), + object({ isExpression: boolean().optional() }).optional(), + ), + }).optional(), + ).optional(), +}).optional(); + +// use main dialect +const dialect = literal('singlestore'); + +const schemaHash = object({ + id: string(), + prevId: string(), +}); + +export const schemaInternal = object({ + version: literal('1'), + dialect: dialect, + tables: record(string(), table), + _meta: object({ + tables: record(string(), string()), + columns: record(string(), string()), + }), + internal: kitInternals, +}).strict(); + +export const schema = schemaInternal.merge(schemaHash); + +const tableSquashed = object({ + name: string(), + columns: record(string(), column), + indexes: record(string(), string()), + compositePrimaryKeys: record(string(), string()), + uniqueConstraints: record(string(), string()).default({}), +}).strict(); + +export const schemaSquashed = object({ + version: literal('1'), + dialect: dialect, + tables: record(string(), tableSquashed), +}).strict(); + +export type Dialect = TypeOf; +export type Column = TypeOf; +export type Table = TypeOf; +export type SingleStoreSchema = TypeOf; +export type SingleStoreSchemaInternal = TypeOf; +export type SingleStoreKitInternals = TypeOf; +export type SingleStoreSchemaSquashed = TypeOf; +export type Index = TypeOf; +export type PrimaryKey = TypeOf; +export type UniqueConstraint = TypeOf; + +export const SingleStoreSquasher = { + squashIdx: (idx: Index) => { + index.parse(idx); + return `${idx.name};${idx.columns.join(',')};${idx.isUnique};${idx.using ?? ''};${idx.algorithm ?? ''};${ + idx.lock ?? '' + }`; + }, + unsquashIdx: (input: string): Index => { + const [name, columnsString, isUnique, using, algorithm, lock] = input.split(';'); + const destructed = { + name, + columns: columnsString.split(','), + isUnique: isUnique === 'true', + using: using ? using : undefined, + algorithm: algorithm ? algorithm : undefined, + lock: lock ? lock : undefined, + }; + return index.parse(destructed); + }, + squashPK: (pk: PrimaryKey) => { + return `${pk.name};${pk.columns.join(',')}`; + }, + unsquashPK: (pk: string): PrimaryKey => { + const splitted = pk.split(';'); + return { name: splitted[0], columns: splitted[1].split(',') }; + }, + squashUnique: (unq: UniqueConstraint) => { + return `${unq.name};${unq.columns.join(',')}`; + }, + unsquashUnique: (unq: string): UniqueConstraint => { + const [name, columns] = unq.split(';'); + return { name, columns: columns.split(',') }; + }, +}; + +export const squashSingleStoreScheme = (json: SingleStoreSchema): SingleStoreSchemaSquashed => { + const mappedTables = Object.fromEntries( + Object.entries(json.tables).map((it) => { + const squashedIndexes = mapValues(it[1].indexes, (index) => { + return SingleStoreSquasher.squashIdx(index); + }); + + const squashedPKs = mapValues(it[1].compositePrimaryKeys, (pk) => { + return SingleStoreSquasher.squashPK(pk); + }); + + const squashedUniqueConstraints = mapValues( + it[1].uniqueConstraints, + (unq) => { + return SingleStoreSquasher.squashUnique(unq); + }, + ); + + return [ + it[0], + { + name: it[1].name, + columns: it[1].columns, + indexes: squashedIndexes, + compositePrimaryKeys: squashedPKs, + uniqueConstraints: squashedUniqueConstraints, + }, + ]; + }), + ); + return { + version: '1', + dialect: json.dialect, + tables: mappedTables, + }; +}; + +export const singlestoreSchema = schema; +export const singlestoreSchemaSquashed = schemaSquashed; + +// no prev version +export const backwardCompatibleSingleStoreSchema = union([singlestoreSchema, schema]); + +export const drySingleStore = singlestoreSchema.parse({ + version: '1', + dialect: 'singlestore', + id: originUUID, + prevId: '', + tables: {}, + schemas: {}, + _meta: { + schemas: {}, + tables: {}, + columns: {}, + }, +}); diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts new file mode 100644 index 000000000..d96004c8f --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -0,0 +1,606 @@ +import chalk from 'chalk'; +import { is, SQL } from 'drizzle-orm'; +import { + AnySingleStoreTable, + getTableConfig, + type PrimaryKey as PrimaryKeyORM, + SingleStoreDialect, + SingleStoreView, + uniqueKeyName, +} from 'drizzle-orm/singlestore-core'; +import { RowDataPacket } from 'mysql2/promise'; +import { withStyle } from '../cli/validations/outputs'; +import { IntrospectStage, IntrospectStatus } from '../cli/views'; + +import type { DB } from '../utils'; +import { sqlToStr } from '.'; +import { + Column, + Index, + PrimaryKey, + SingleStoreKitInternals, + SingleStoreSchemaInternal, + Table, + UniqueConstraint, +} from './singlestoreSchema'; +import { CasingType } from 'src/cli/validations/common'; + +const dialect = new SingleStoreDialect(); + +export const indexName = (tableName: string, columns: string[]) => { + return `${tableName}_${columns.join('_')}_index`; +}; + +export const generateSingleStoreSnapshot = ( + tables: AnySingleStoreTable[], + views: SingleStoreView[], + casing: CasingType | undefined, +): SingleStoreSchemaInternal => { + const result: Record = {}; + const internal: SingleStoreKitInternals = { tables: {}, indexes: {} }; + for (const table of tables) { + const { + name: tableName, + columns, + indexes, + schema, + primaryKeys, + uniqueConstraints, + } = getTableConfig(table); + const columnsObject: Record = {}; + const indexesObject: Record = {}; + const primaryKeysObject: Record = {}; + const uniqueConstraintObject: Record = {}; + + columns.forEach((column) => { + const notNull: boolean = column.notNull; + const sqlTypeLowered = column.getSQLType().toLowerCase(); + const autoIncrement = typeof (column as any).autoIncrement === 'undefined' + ? false + : (column as any).autoIncrement; + + const generated = column.generated; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + primaryKey: false, + // If field is autoincrement it's notNull by default + // notNull: autoIncrement ? true : notNull, + notNull, + autoincrement: autoIncrement, + onUpdate: (column as any).hasOnUpdateNow, + generated: generated + ? { + as: is(generated.as, SQL) + ? dialect.sqlToQuery(generated.as as SQL).sql + : typeof generated.as === 'function' + ? dialect.sqlToQuery(generated.as() as SQL).sql + : (generated.as as any), + type: generated.mode ?? 'stored', + } + : undefined, + }; + + if (column.primary) { + primaryKeysObject[`${tableName}_${column.name}`] = { + name: `${tableName}_${column.name}`, + columns: [column.name], + }; + } + + if (column.isUnique) { + const existingUnique = uniqueConstraintObject[column.uniqueName!]; + if (typeof existingUnique !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. + The unique constraint ${ + chalk.underline.blue( + column.uniqueName, + ) + } on the ${ + chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`) + }`, + ); + process.exit(1); + } + uniqueConstraintObject[column.uniqueName!] = { + name: column.uniqueName!, + columns: [columnToSet.name], + }; + } + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default, casing); + } else { + if (typeof column.default === 'string') { + columnToSet.default = `'${column.default}'`; + } else { + if (sqlTypeLowered === 'json') { + columnToSet.default = `'${JSON.stringify(column.default)}'`; + } else if (column.default instanceof Date) { + if (sqlTypeLowered === 'date') { + columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; + } else if ( + sqlTypeLowered.startsWith('datetime') + || sqlTypeLowered.startsWith('timestamp') + ) { + columnToSet.default = `'${ + column.default + .toISOString() + .replace('T', ' ') + .slice(0, 23) + }'`; + } + } else { + columnToSet.default = column.default; + } + } + if (['blob', 'text', 'json'].includes(column.getSQLType())) { + columnToSet.default = `(${columnToSet.default})`; + } + } + } + columnsObject[column.name] = columnToSet; + }); + + primaryKeys.map((pk: PrimaryKeyORM) => { + const columnNames = pk.columns.map((c: any) => c.name); + primaryKeysObject[pk.getName()] = { + name: pk.getName(), + columns: columnNames, + }; + + // all composite pk's should be treated as notNull + for (const column of pk.columns) { + columnsObject[column.name].notNull = true; + } + }); + + uniqueConstraints?.map((unq) => { + const columnNames = unq.columns.map((c) => c.name); + + const name = unq.name ?? uniqueKeyName(table, columnNames); + + const existingUnique = uniqueConstraintObject[name]; + if (typeof existingUnique !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. \nThe unique constraint ${ + chalk.underline.blue( + name, + ) + } on the ${ + chalk.underline.blue( + columnNames.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`, + ) + }`, + ); + process.exit(1); + } + + uniqueConstraintObject[name] = { + name: unq.name!, + columns: columnNames, + }; + }); + + indexes.forEach((value) => { + const columns = value.config.columns; + const name = value.config.name; + + let indexColumns = columns.map((it) => { + if (is(it, SQL)) { + const sql = dialect.sqlToQuery(it, 'indexes').sql; + if (typeof internal!.indexes![name] === 'undefined') { + internal!.indexes![name] = { + columns: { + [sql]: { + isExpression: true, + }, + }, + }; + } else { + if (typeof internal!.indexes![name]?.columns[sql] === 'undefined') { + internal!.indexes![name]!.columns[sql] = { + isExpression: true, + }; + } else { + internal!.indexes![name]!.columns[sql]!.isExpression = true; + } + } + return sql; + } else { + return `${it.name}`; + } + }); + + if (value.config.unique) { + if (typeof uniqueConstraintObject[name] !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. \nThe unique index ${ + chalk.underline.blue( + name, + ) + } on the ${ + chalk.underline.blue( + indexColumns.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + uniqueConstraintObject[name].columns.join(','), + ) + } columns\n`, + ) + }`, + ); + process.exit(1); + } + } + + indexesObject[name] = { + name, + columns: indexColumns, + isUnique: value.config.unique ?? false, + using: value.config.using, + algorithm: value.config.algorythm, + lock: value.config.lock, + }; + }); + + // only handle tables without schemas + if (!schema) { + result[tableName] = { + name: tableName, + columns: columnsObject, + indexes: indexesObject, + compositePrimaryKeys: primaryKeysObject, + uniqueConstraints: uniqueConstraintObject, + }; + } + } + + return { + version: '1', + dialect: 'singlestore', + tables: result, + _meta: { + tables: {}, + columns: {}, + }, + internal, + }; +}; + +function clearDefaults(defaultValue: any, collate: string) { + if (typeof collate === 'undefined' || collate === null) { + collate = `utf8mb4`; + } + + let resultDefault = defaultValue; + collate = `_${collate}`; + if (defaultValue.startsWith(collate)) { + resultDefault = resultDefault + .substring(collate.length, defaultValue.length) + .replace(/\\/g, ''); + if (resultDefault.startsWith("'") && resultDefault.endsWith("'")) { + return `('${resultDefault.substring(1, resultDefault.length - 1)}')`; + } else { + return `'${resultDefault}'`; + } + } else { + return `(${resultDefault})`; + } +} + +export const fromDatabase = async ( + db: DB, + inputSchema: string, + tablesFilter: (table: string) => boolean = (table) => true, + progressCallback?: ( + stage: IntrospectStage, + count: number, + status: IntrospectStatus, + ) => void, +): Promise => { + const result: Record = {}; + const internals: SingleStoreKitInternals = { tables: {}, indexes: {} }; + + const columns = await db.query(`select * from information_schema.columns + where table_schema = '${inputSchema}' and table_name != '__drizzle_migrations' + order by table_name, ordinal_position;`); + + const response = columns as RowDataPacket[]; + + const schemas: string[] = []; + + let columnsCount = 0; + let tablesCount = new Set(); + let indexesCount = 0; + let foreignKeysCount = 0; + + const idxs = await db.query( + `select * from INFORMATION_SCHEMA.STATISTICS + WHERE INFORMATION_SCHEMA.STATISTICS.TABLE_SCHEMA = '${inputSchema}' and INFORMATION_SCHEMA.STATISTICS.INDEX_NAME != 'PRIMARY';`, + ); + + const idxRows = idxs as RowDataPacket[]; + + for (const column of response) { + if (!tablesFilter(column['TABLE_NAME'] as string)) continue; + + columnsCount += 1; + if (progressCallback) { + progressCallback('columns', columnsCount, 'fetching'); + } + const schema: string = column['TABLE_SCHEMA']; + const tableName = column['TABLE_NAME']; + + tablesCount.add(`${schema}.${tableName}`); + if (progressCallback) { + progressCallback('columns', tablesCount.size, 'fetching'); + } + const columnName: string = column['COLUMN_NAME']; + const isNullable = column['IS_NULLABLE'] === 'YES'; // 'YES', 'NO' + const dataType = column['DATA_TYPE']; // varchar + const columnType = column['COLUMN_TYPE']; // varchar(256) + const isPrimary = column['COLUMN_KEY'] === 'PRI'; // 'PRI', '' + const columnDefault: string = column['COLUMN_DEFAULT']; + const collation: string = column['CHARACTER_SET_NAME']; + const geenratedExpression: string = column['GENERATION_EXPRESSION']; + + let columnExtra = column['EXTRA']; + let isAutoincrement = false; // 'auto_increment', '' + let isDefaultAnExpression = false; // 'auto_increment', '' + + if (typeof column['EXTRA'] !== 'undefined') { + columnExtra = column['EXTRA']; + isAutoincrement = column['EXTRA'] === 'auto_increment'; // 'auto_increment', '' + isDefaultAnExpression = column['EXTRA'].includes('DEFAULT_GENERATED'); // 'auto_increment', '' + } + + // if (isPrimary) { + // if (typeof tableToPk[tableName] === "undefined") { + // tableToPk[tableName] = [columnName]; + // } else { + // tableToPk[tableName].push(columnName); + // } + // } + + if (schema !== inputSchema) { + schemas.push(schema); + } + + const table = result[tableName]; + + // let changedType = columnType.replace("bigint unsigned", "serial") + let changedType = columnType; + + if (columnType === 'bigint unsigned' && !isNullable && isAutoincrement) { + // check unique here + const uniqueIdx = idxRows.filter( + (it) => + it['COLUMN_NAME'] === columnName + && it['TABLE_NAME'] === tableName + && it['NON_UNIQUE'] === 0, + ); + if (uniqueIdx && uniqueIdx.length === 1) { + changedType = columnType.replace('bigint unsigned', 'serial'); + } + } + + if (columnType.startsWith('tinyint')) { + changedType = 'tinyint'; + } + + let onUpdate: boolean | undefined = undefined; + if ( + columnType.startsWith('timestamp') + && typeof columnExtra !== 'undefined' + && columnExtra.includes('on update CURRENT_TIMESTAMP') + ) { + onUpdate = true; + } + + const newColumn: Column = { + default: columnDefault === null + ? undefined + : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) + && !columnType.startsWith('decimal') + ? Number(columnDefault) + : isDefaultAnExpression + ? clearDefaults(columnDefault, collation) + : `'${columnDefault}'`, + autoincrement: isAutoincrement, + name: columnName, + type: changedType, + primaryKey: false, + notNull: !isNullable, + onUpdate, + generated: geenratedExpression + ? { + as: geenratedExpression, + type: columnExtra === 'VIRTUAL GENERATED' ? 'virtual' : 'stored', + } + : undefined, + }; + + // Set default to internal object + if (isDefaultAnExpression) { + if (typeof internals!.tables![tableName] === 'undefined') { + internals!.tables![tableName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, + }, + }; + } else { + if ( + typeof internals!.tables![tableName]!.columns[columnName] + === 'undefined' + ) { + internals!.tables![tableName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![tableName]!.columns[ + columnName + ]!.isDefaultAnExpression = true; + } + } + } + + if (!table) { + result[tableName] = { + name: tableName, + columns: { + [columnName]: newColumn, + }, + compositePrimaryKeys: {}, + indexes: {}, + uniqueConstraints: {}, + }; + } else { + result[tableName]!.columns[columnName] = newColumn; + } + } + + const tablePks = await db.query( + `SELECT table_name, column_name, ordinal_position + FROM information_schema.table_constraints t + LEFT JOIN information_schema.key_column_usage k + USING(constraint_name,table_schema,table_name) + WHERE t.constraint_type='PRIMARY KEY' + and table_name != '__drizzle_migrations' + AND t.table_schema = '${inputSchema}' + ORDER BY ordinal_position`, + ); + + const tableToPk: { [tname: string]: string[] } = {}; + + const tableToPkRows = tablePks as RowDataPacket[]; + for (const tableToPkRow of tableToPkRows) { + const tableName: string = tableToPkRow['TABLE_NAME']; + const columnName: string = tableToPkRow['COLUMN_NAME']; + const position: string = tableToPkRow['ordinal_position']; + + if (typeof result[tableName] === 'undefined') { + continue; + } + + if (typeof tableToPk[tableName] === 'undefined') { + tableToPk[tableName] = [columnName]; + } else { + tableToPk[tableName].push(columnName); + } + } + + for (const [key, value] of Object.entries(tableToPk)) { + // if (value.length > 1) { + result[key].compositePrimaryKeys = { + [`${key}_${value.join('_')}`]: { + name: `${key}_${value.join('_')}`, + columns: value, + }, + }; + // } else if (value.length === 1) { + // result[key].columns[value[0]].primaryKey = true; + // } else { + // } + } + if (progressCallback) { + progressCallback('columns', columnsCount, 'done'); + progressCallback('tables', tablesCount.size, 'done'); + } + + for (const idxRow of idxRows) { + const tableSchema = idxRow['TABLE_SCHEMA']; + const tableName = idxRow['TABLE_NAME']; + const constraintName = idxRow['INDEX_NAME']; + const columnName: string = idxRow['COLUMN_NAME']; + const isUnique = idxRow['NON_UNIQUE'] === 0; + + const tableInResult = result[tableName]; + if (typeof tableInResult === 'undefined') continue; + + // if (tableInResult.columns[columnName].type === "serial") continue; + + indexesCount += 1; + if (progressCallback) { + progressCallback('indexes', indexesCount, 'fetching'); + } + + if (isUnique) { + if ( + typeof tableInResult.uniqueConstraints[constraintName] !== 'undefined' + ) { + tableInResult.uniqueConstraints[constraintName]!.columns.push( + columnName, + ); + } else { + tableInResult.uniqueConstraints[constraintName] = { + name: constraintName, + columns: [columnName], + }; + } + } else { + if (typeof tableInResult.indexes[constraintName] !== 'undefined') { + tableInResult.indexes[constraintName]!.columns.push(columnName); + } else { + tableInResult.indexes[constraintName] = { + name: constraintName, + columns: [columnName], + isUnique: isUnique, + }; + } + } + } + + if (progressCallback) { + progressCallback('indexes', indexesCount, 'done'); + // progressCallback("enums", 0, "fetching"); + progressCallback('enums', 0, 'done'); + } + + return { + version: '1', + dialect: 'singlestore', + tables: result, + _meta: { + tables: {}, + columns: {}, + }, + internal: internals, + }; +}; diff --git a/drizzle-kit/src/serializer/studio.ts b/drizzle-kit/src/serializer/studio.ts index e83bd21a2..12ea8207c 100644 --- a/drizzle-kit/src/serializer/studio.ts +++ b/drizzle-kit/src/serializer/studio.ts @@ -15,6 +15,11 @@ import { } from 'drizzle-orm'; import { AnyMySqlTable, getTableConfig as mysqlTableConfig, MySqlTable } from 'drizzle-orm/mysql-core'; import { AnyPgTable, getTableConfig as pgTableConfig, PgTable } from 'drizzle-orm/pg-core'; +import { + AnySingleStoreTable, + getTableConfig as singlestoreTableConfig, + SingleStoreTable, +} from 'drizzle-orm/singlestore-core'; import { AnySQLiteTable, getTableConfig as sqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; import fs from 'fs'; import { Hono } from 'hono'; @@ -27,6 +32,7 @@ import { z } from 'zod'; import { safeRegister } from '../cli/commands/utils'; import type { MysqlCredentials } from '../cli/validations/mysql'; import type { PostgresCredentials } from '../cli/validations/postgres'; +import type { SingleStoreCredentials } from '../cli/validations/singlestore'; import type { SqliteCredentials } from '../cli/validations/sqlite'; import { prepareFilenames } from '.'; @@ -44,7 +50,7 @@ type SchemaFile = { export type Setup = { dbHash: string; - dialect: 'postgresql' | 'mysql' | 'sqlite'; + dialect: 'postgresql' | 'mysql' | 'sqlite' | 'singlestore'; driver?: 'aws-data-api' | 'd1-http' | 'turso' | 'pglite'; proxy: (params: ProxyParams) => Promise; customDefaults: CustomDefault[]; @@ -171,6 +177,43 @@ export const prepareSQLiteSchema = async (path: string | string[]) => { return { schema: sqliteSchema, relations, files }; }; +export const prepareSingleStoreSchema = async (path: string | string[]) => { + const imports = prepareFilenames(path); + const singlestoreSchema: Record> = { + public: {}, + }; + const relations: Record = {}; + + // files content as string + const files = imports.map((it, index) => ({ + // get the file name from the path + name: it.split('/').pop() || `schema${index}.ts`, + content: fs.readFileSync(it, 'utf-8'), + })); + + const { unregister } = await safeRegister(); + for (let i = 0; i < imports.length; i++) { + const it = imports[i]; + + const i0: Record = require(`${it}`); + const i0values = Object.entries(i0); + + i0values.forEach(([k, t]) => { + if (is(t, SingleStoreTable)) { + const schema = singlestoreTableConfig(t).schema || 'public'; + singlestoreSchema[schema][k] = t; + } + + if (is(t, Relations)) { + relations[k] = t; + } + }); + } + unregister(); + + return { schema: singlestoreSchema, relations, files }; +}; + const getCustomDefaults = >( schema: Record>, ): CustomDefault[] => { @@ -186,8 +229,10 @@ const getCustomDefaults = >( tableConfig = pgTableConfig(table); } else if (is(table, MySqlTable)) { tableConfig = mysqlTableConfig(table); - } else { + } else if (is(table, SQLiteTable)) { tableConfig = sqliteTableConfig(table); + } else { + tableConfig = singlestoreTableConfig(table); } tableConfig.columns.map((column) => { @@ -345,6 +390,39 @@ export const drizzleForLibSQL = async ( }; }; +export const drizzleForSingleStore = async ( + credentials: SingleStoreCredentials, + singlestoreSchema: Record>, + relations: Record, + schemaFiles?: SchemaFile[], +): Promise => { + const { connectToSingleStore } = await import('../cli/connections'); + const { proxy } = await connectToSingleStore(credentials); + + const customDefaults = getCustomDefaults(singlestoreSchema); + + let dbUrl: string; + + if ('url' in credentials) { + dbUrl = credentials.url; + } else { + dbUrl = + `singlestore://${credentials.user}:${credentials.password}@${credentials.host}:${credentials.port}/${credentials.database}`; + } + + const dbHash = createHash('sha256').update(dbUrl).digest('hex'); + + return { + dbHash, + dialect: 'singlestore', + proxy, + customDefaults, + schema: singlestoreSchema, + relations, + schemaFiles, + }; +}; + export const extractRelations = (tablesConfig: { tables: TablesRelationalConfig; tableNamesMap: Record; @@ -370,6 +448,8 @@ export const extractRelations = (tablesConfig: { refSchema = mysqlTableConfig(refTable).schema; } else if (is(refTable, SQLiteTable)) { refSchema = undefined; + } else if (is(refTable, SingleStoreTable)) { + refSchema = singlestoreTableConfig(refTable).schema; } else { throw new Error('unsupported dialect'); } diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index bae4c100a..14c19cb43 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -45,12 +45,15 @@ import { prepareAddCheckConstraint, prepareAddCompositePrimaryKeyMySql, prepareAddCompositePrimaryKeyPg, + prepareAddCompositePrimaryKeySingleStore, prepareAddCompositePrimaryKeySqlite, prepareAddUniqueConstraintPg as prepareAddUniqueConstraint, prepareAddValuesToEnumJson, prepareAlterColumnsMysql, + prepareAlterColumnsSingleStore, prepareAlterCompositePrimaryKeyMySql, prepareAlterCompositePrimaryKeyPg, + prepareAlterCompositePrimaryKeySingleStore, prepareAlterCompositePrimaryKeySqlite, prepareAlterReferencesJson, prepareAlterSequenceJson, @@ -62,6 +65,7 @@ import { prepareDeleteCheckConstraint, prepareDeleteCompositePrimaryKeyMySql, prepareDeleteCompositePrimaryKeyPg, + prepareDeleteCompositePrimaryKeySingleStore, prepareDeleteCompositePrimaryKeySqlite, prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDeleteUniqueConstraintPg as prepareDeleteUniqueConstraint, @@ -94,6 +98,7 @@ import { prepareRenameSequenceJson, prepareRenameTableJson, prepareRenameViewJson, + prepareSingleStoreCreateTableJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, prepareSqliteCreateViewJson, @@ -103,6 +108,7 @@ import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher, ViewSquashed } from './serializer/mysqlSchema'; import { mergedViewWithOption, PgSchema, PgSchemaSquashed, sequenceSquashed, View } from './serializer/pgSchema'; +import { SingleStoreSchema, SingleStoreSchemaSquashed, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher, View as SqliteView } from './serializer/sqliteSchema'; import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; import { copy, prepareMigrationMeta } from './utils'; @@ -346,6 +352,11 @@ export const diffResultSchemeMysql = object({ alteredViews: alteredMySqlViewSchema.array(), }); +export const diffResultSchemeSingleStore = object({ + alteredTablesWithColumns: alteredTableScheme.array(), + alteredEnums: never().array(), +}); + export const diffResultSchemeSQLite = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: never().array(), @@ -360,6 +371,7 @@ export type Table = TypeOf; export type AlteredTable = TypeOf; export type DiffResult = TypeOf; export type DiffResultMysql = TypeOf; +export type DiffResultSingleStore = TypeOf; export type DiffResultSQLite = TypeOf; export interface ResolverInput { @@ -2099,6 +2111,422 @@ export const applyMysqlSnapshotsDiff = async ( }; }; +export const applySingleStoreSnapshotsDiff = async ( + json1: SingleStoreSchemaSquashed, + json2: SingleStoreSchemaSquashed, + tablesResolver: ( + input: ResolverInput
, + ) => Promise>, + columnsResolver: ( + input: ColumnsResolverInput, + ) => Promise>, + viewsResolver: ( + input: ResolverInput, + ) => Promise>, + prevFull: SingleStoreSchema, + curFull: SingleStoreSchema, + action?: 'push' | undefined, +): Promise<{ + statements: JsonStatement[]; + sqlStatements: string[]; + _meta: + | { + schemas: {}; + tables: {}; + columns: {}; + } + | undefined; +}> => { + // squash indexes and fks + + // squash uniqueIndexes and uniqueConstraint into constraints object + // it should be done for singlestore only because it has no diffs for it + for (const tableName in json1.tables) { + const table = json1.tables[tableName]; + for (const indexName in table.indexes) { + const index = SingleStoreSquasher.unsquashIdx(table.indexes[indexName]); + if (index.isUnique) { + table.uniqueConstraints[indexName] = SingleStoreSquasher.squashUnique({ + name: index.name, + columns: index.columns, + }); + delete json1.tables[tableName].indexes[index.name]; + } + } + } + + for (const tableName in json2.tables) { + const table = json2.tables[tableName]; + for (const indexName in table.indexes) { + const index = SingleStoreSquasher.unsquashIdx(table.indexes[indexName]); + if (index.isUnique) { + table.uniqueConstraints[indexName] = SingleStoreSquasher.squashUnique({ + name: index.name, + columns: index.columns, + }); + delete json2.tables[tableName].indexes[index.name]; + } + } + } + + const tablesDiff = diffSchemasOrTables(json1.tables, json2.tables); + + const { + created: createdTables, + deleted: deletedTables, + renamed: renamedTables, // renamed or moved + } = await tablesResolver({ + created: tablesDiff.added, + deleted: tablesDiff.deleted, + }); + + const tablesPatchedSnap1 = copy(json1); + tablesPatchedSnap1.tables = mapEntries(tablesPatchedSnap1.tables, (_, it) => { + const { name } = nameChangeFor(it, renamedTables); + it.name = name; + return [name, it]; + }); + + const res = diffColumns(tablesPatchedSnap1.tables, json2.tables); + const columnRenames = [] as { + table: string; + renames: { from: Column; to: Column }[]; + }[]; + + const columnCreates = [] as { + table: string; + columns: Column[]; + }[]; + + const columnDeletes = [] as { + table: string; + columns: Column[]; + }[]; + + for (let entry of Object.values(res)) { + const { renamed, created, deleted } = await columnsResolver({ + tableName: entry.name, + schema: entry.schema, + deleted: entry.columns.deleted, + created: entry.columns.added, + }); + + if (created.length > 0) { + columnCreates.push({ + table: entry.name, + columns: created, + }); + } + + if (deleted.length > 0) { + columnDeletes.push({ + table: entry.name, + columns: deleted, + }); + } + + if (renamed.length > 0) { + columnRenames.push({ + table: entry.name, + renames: renamed, + }); + } + } + + const columnRenamesDict = columnRenames.reduce( + (acc, it) => { + acc[it.table] = it.renames; + return acc; + }, + {} as Record< + string, + { + from: Named; + to: Named; + }[] + >, + ); + + const columnsPatchedSnap1 = copy(tablesPatchedSnap1); + columnsPatchedSnap1.tables = mapEntries( + columnsPatchedSnap1.tables, + (tableKey, tableValue) => { + const patchedColumns = mapKeys( + tableValue.columns, + (columnKey, column) => { + const rens = columnRenamesDict[tableValue.name] || []; + const newName = columnChangeFor(columnKey, rens); + column.name = newName; + return newName; + }, + ); + + tableValue.columns = patchedColumns; + return [tableKey, tableValue]; + }, + ); + + const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + + const typedResult: DiffResultSingleStore = diffResultSchemeSingleStore.parse(diffResult); + + const jsonStatements: JsonStatement[] = []; + + const jsonCreateIndexesForCreatedTables = createdTables + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.indexes, + curFull.internal, + ); + }) + .flat(); + + const jsonDropTables = deletedTables.map((it) => { + return prepareDropTableJson(it); + }); + + const jsonRenameTables = renamedTables.map((it) => { + return prepareRenameTableJson(it.from, it.to); + }); + + const alteredTables = typedResult.alteredTablesWithColumns; + + const jsonAddedCompositePKs: JsonCreateCompositePK[] = []; + const jsonDeletedCompositePKs: JsonDeleteCompositePK[] = []; + const jsonAlteredCompositePKs: JsonAlterCompositePK[] = []; + + const jsonAddedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames + .map((it) => prepareRenameColumns(it.table, '', it.renames)) + .flat(); + + const jsonAddColumnsStatemets: JsonAddColumnStatement[] = columnCreates + .map((it) => _prepareAddColumns(it.table, '', it.columns)) + .flat(); + + const jsonDropColumnsStatemets: JsonDropColumnStatement[] = columnDeletes + .map((it) => _prepareDropColumns(it.table, '', it.columns)) + .flat(); + + alteredTables.forEach((it) => { + // This part is needed to make sure that same columns in a table are not triggered for change + // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name + // We double-check that pk with same set of columns are both in added and deleted diffs + let addedColumns: string[] = []; + for (const addedPkName of Object.keys(it.addedCompositePKs)) { + const addedPkColumns = it.addedCompositePKs[addedPkName]; + addedColumns = SingleStoreSquasher.unsquashPK(addedPkColumns).columns; + } + + let deletedColumns: string[] = []; + for (const deletedPkName of Object.keys(it.deletedCompositePKs)) { + const deletedPkColumns = it.deletedCompositePKs[deletedPkName]; + deletedColumns = SingleStoreSquasher.unsquashPK(deletedPkColumns).columns; + } + + // Don't need to sort, but need to add tests for it + // addedColumns.sort(); + // deletedColumns.sort(); + const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); + + let addedCompositePKs: JsonCreateCompositePK[] = []; + let deletedCompositePKs: JsonDeleteCompositePK[] = []; + let alteredCompositePKs: JsonAlterCompositePK[] = []; + + addedCompositePKs = prepareAddCompositePrimaryKeySingleStore( + it.name, + it.addedCompositePKs, + prevFull, + curFull, + ); + deletedCompositePKs = prepareDeleteCompositePrimaryKeySingleStore( + it.name, + it.deletedCompositePKs, + prevFull, + ); + // } + alteredCompositePKs = prepareAlterCompositePrimaryKeySingleStore( + it.name, + it.alteredCompositePKs, + prevFull, + curFull, + ); + + // add logic for unique constraints + let addedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + addedUniqueConstraints = prepareAddUniqueConstraint( + it.name, + it.schema, + it.addedUniqueConstraints, + ); + deletedUniqueConstraints = prepareDeleteUniqueConstraint( + it.name, + it.schema, + it.deletedUniqueConstraints, + ); + if (it.alteredUniqueConstraints) { + const added: Record = {}; + const deleted: Record = {}; + for (const k of Object.keys(it.alteredUniqueConstraints)) { + added[k] = it.alteredUniqueConstraints[k].__new; + deleted[k] = it.alteredUniqueConstraints[k].__old; + } + addedUniqueConstraints.push( + ...prepareAddUniqueConstraint(it.name, it.schema, added), + ); + deletedUniqueConstraints.push( + ...prepareDeleteUniqueConstraint(it.name, it.schema, deleted), + ); + } + + jsonAddedCompositePKs.push(...addedCompositePKs); + jsonDeletedCompositePKs.push(...deletedCompositePKs); + jsonAlteredCompositePKs.push(...alteredCompositePKs); + + jsonAddedUniqueConstraints.push(...addedUniqueConstraints); + jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); + jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + }); + + const rColumns = jsonRenameColumnsStatements.map((it) => { + const tableName = it.tableName; + const schema = it.schema; + return { + from: { schema, table: tableName, column: it.oldColumnName }, + to: { schema, table: tableName, column: it.newColumnName }, + }; + }); + + const jsonTableAlternations = alteredTables + .map((it) => { + return prepareAlterColumnsSingleStore( + it.name, + it.schema, + it.altered, + json1, + json2, + action, + ); + }) + .flat(); + + const jsonCreateIndexesForAllAlteredTables = alteredTables + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.addedIndexes || {}, + curFull.internal, + ); + }) + .flat(); + + const jsonDropIndexesForAllAlteredTables = alteredTables + .map((it) => { + return prepareDropIndexesJson( + it.name, + it.schema, + it.deletedIndexes || {}, + ); + }) + .flat(); + + alteredTables.forEach((it) => { + const droppedIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__old; + return current; + }, + {} as Record, + ); + const createdIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__new; + return current; + }, + {} as Record, + ); + + jsonCreateIndexesForAllAlteredTables.push( + ...prepareCreateIndexesJson(it.name, it.schema, createdIndexes || {}), + ); + jsonDropIndexesForAllAlteredTables.push( + ...prepareDropIndexesJson(it.name, it.schema, droppedIndexes || {}), + ); + }); + + const jsonSingleStoreCreateTables = createdTables.map((it) => { + return prepareSingleStoreCreateTableJson( + it, + curFull as SingleStoreSchema, + curFull.internal, + ); + }); + jsonStatements.push(...jsonSingleStoreCreateTables); + + jsonStatements.push(...jsonDropTables); + jsonStatements.push(...jsonRenameTables); + jsonStatements.push(...jsonRenameColumnsStatements); + + jsonStatements.push(...jsonDeletedUniqueConstraints); + + // Will need to drop indexes before changing any columns in table + // Then should go column alternations and then index creation + jsonStatements.push(...jsonDropIndexesForAllAlteredTables); + + jsonStatements.push(...jsonDeletedCompositePKs); + jsonStatements.push(...jsonTableAlternations); + jsonStatements.push(...jsonAddedCompositePKs); + + jsonStatements.push(...jsonAddedUniqueConstraints); + jsonStatements.push(...jsonDeletedUniqueConstraints); + + jsonStatements.push(...jsonAddColumnsStatemets); + + jsonStatements.push(...jsonCreateIndexesForCreatedTables); + + jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); + + jsonStatements.push(...jsonDropColumnsStatemets); + + // jsonStatements.push(...jsonDeletedCompositePKs); + // jsonStatements.push(...jsonAddedCompositePKs); + jsonStatements.push(...jsonAlteredCompositePKs); + + jsonStatements.push(...jsonAddedUniqueConstraints); + + jsonStatements.push(...jsonAlteredUniqueConstraints); + + const sqlStatements = fromJson(jsonStatements, 'singlestore'); + + const uniqueSqlStatements: string[] = []; + sqlStatements.forEach((ss) => { + if (!uniqueSqlStatements.includes(ss)) { + uniqueSqlStatements.push(ss); + } + }); + + const rTables = renamedTables.map((it) => { + return { from: it.from, to: it.to }; + }); + + const _meta = prepareMigrationMeta([], rTables, rColumns); + + return { + statements: jsonStatements, + sqlStatements: uniqueSqlStatements, + _meta, + }; +}; + export const applySqliteSnapshotsDiff = async ( json1: SQLiteSchemaSquashed, json2: SQLiteSchemaSquashed, diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 586175e28..3769fe1ce 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -71,6 +71,7 @@ import { import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; import { PgSquasher } from './serializer/pgSchema'; +import { SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; export const pgNativeTypes = new Set([ @@ -347,6 +348,81 @@ class MySqlCreateTableConvertor extends Convertor { return statement; } } +class SingleStoreCreateTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_table' && dialect === 'singlestore'; + } + + convert(st: JsonCreateTableStatement) { + const { + tableName, + columns, + schema, + compositePKs, + uniqueConstraints, + internals, + } = st; + + let statement = ''; + statement += `CREATE TABLE \`${tableName}\` (\n`; + for (let i = 0; i < columns.length; i++) { + const column = columns[i]; + + const primaryKeyStatement = column.primaryKey ? ' PRIMARY KEY' : ''; + const notNullStatement = column.notNull ? ' NOT NULL' : ''; + const defaultStatement = column.default !== undefined ? ` DEFAULT ${column.default}` : ''; + + const onUpdateStatement = column.onUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + + const autoincrementStatement = column.autoincrement + ? ' AUTO_INCREMENT' + : ''; + + const generatedStatement = column.generated + ? ` GENERATED ALWAYS AS (${column.generated?.as}) ${column.generated?.type.toUpperCase()}` + : ''; + + statement += '\t' + + `\`${column.name}\` ${column.type}${autoincrementStatement}${primaryKeyStatement}${notNullStatement}${defaultStatement}${onUpdateStatement}${generatedStatement}`; + statement += i === columns.length - 1 ? '' : ',\n'; + } + + if (typeof compositePKs !== 'undefined' && compositePKs.length > 0) { + statement += ',\n'; + const compositePK = SingleStoreSquasher.unsquashPK(compositePKs[0]); + statement += `\tCONSTRAINT \`${st.compositePkName}\` PRIMARY KEY(\`${compositePK.columns.join(`\`,\``)}\`)`; + } + + if ( + typeof uniqueConstraints !== 'undefined' + && uniqueConstraints.length > 0 + ) { + for (const uniqueConstraint of uniqueConstraints) { + statement += ',\n'; + const unsquashedUnique = SingleStoreSquasher.unsquashUnique(uniqueConstraint); + + const uniqueString = unsquashedUnique.columns + .map((it) => { + return internals?.indexes + ? internals?.indexes[unsquashedUnique.name]?.columns[it] + ?.isExpression + ? it + : `\`${it}\`` + : `\`${it}\``; + }) + .join(','); + + statement += `\tCONSTRAINT \`${unsquashedUnique.name}\` UNIQUE(${uniqueString})`; + } + } + + statement += `\n);`; + statement += `\n`; + return statement; + } +} export class SQLiteCreateTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { @@ -940,6 +1016,29 @@ class MySqlAlterTableAddCheckConstraintConvertor extends Convertor { } } +class SingleStoreAlterTableAddUniqueConstraintConvertor extends Convertor { + can(statement: JsonCreateUniqueConstraint, dialect: Dialect): boolean { + return statement.type === 'create_unique_constraint' && dialect === 'singlestore'; + } + convert(statement: JsonCreateUniqueConstraint): string { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); + + return `ALTER TABLE \`${statement.tableName}\` ADD CONSTRAINT \`${unsquashed.name}\` UNIQUE(\`${ + unsquashed.columns.join('`,`') + }\`);`; + } +} +class SingleStoreAlterTableDropUniqueConstraintConvertor extends Convertor { + can(statement: JsonDeleteUniqueConstraint, dialect: Dialect): boolean { + return statement.type === 'delete_unique_constraint' && dialect === 'singlestore'; + } + convert(statement: JsonDeleteUniqueConstraint): string { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); + + return `ALTER TABLE \`${statement.tableName}\` DROP INDEX \`${unsquashed.name}\`;`; + } +} + class MySqlAlterTableDeleteCheckConstraintConvertor extends Convertor { can(statement: JsonDeleteCheckConstraint, dialect: Dialect): boolean { return ( @@ -1191,6 +1290,17 @@ class MySQLDropTableConvertor extends Convertor { } } +class SingleStoreDropTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_table' && dialect === 'singlestore'; + } + + convert(statement: JsonDropTableStatement) { + const { tableName } = statement; + return `DROP TABLE \`${tableName}\`;`; + } +} + export class SQLiteDropTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'drop_table' && (dialect === 'sqlite' || dialect === 'turso'); @@ -1239,6 +1349,17 @@ class MySqlRenameTableConvertor extends Convertor { } } +class SingleStoreRenameTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'rename_table' && dialect === 'singlestore'; + } + + convert(statement: JsonRenameTableStatement) { + const { tableNameFrom, tableNameTo } = statement; + return `RENAME TABLE \`${tableNameFrom}\` TO \`${tableNameTo}\`;`; + } +} + class PgAlterTableRenameColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1270,6 +1391,19 @@ class MySqlAlterTableRenameColumnConvertor extends Convertor { } } +class SingleStoreAlterTableRenameColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + statement.type === 'alter_table_rename_column' && dialect === 'singlestore' + ); + } + + convert(statement: JsonRenameColumnStatement) { + const { tableName, oldColumnName, newColumnName } = statement; + return `ALTER TABLE \`${tableName}\` RENAME COLUMN \`${oldColumnName}\` TO \`${newColumnName}\`;`; + } +} + class SQLiteAlterTableRenameColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1312,6 +1446,17 @@ class MySqlAlterTableDropColumnConvertor extends Convertor { } } +class SingleStoreAlterTableDropColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_table_drop_column' && dialect === 'singlestore'; + } + + convert(statement: JsonDropColumnStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` DROP COLUMN \`${columnName}\`;`; + } +} + class SQLiteAlterTableDropColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'alter_table_drop_column' && (dialect === 'sqlite' || dialect === 'turso'); @@ -1421,6 +1566,37 @@ class MySqlAlterTableAddColumnConvertor extends Convertor { } } +class SingleStoreAlterTableAddColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_table_add_column' && dialect === 'singlestore'; + } + + convert(statement: JsonAddColumnStatement) { + const { tableName, column } = statement; + const { + name, + type, + notNull, + primaryKey, + autoincrement, + onUpdate, + generated, + } = column; + + const defaultStatement = `${column.default !== undefined ? ` DEFAULT ${column.default}` : ''}`; + const notNullStatement = `${notNull ? ' NOT NULL' : ''}`; + const primaryKeyStatement = `${primaryKey ? ' PRIMARY KEY' : ''}`; + const autoincrementStatement = `${autoincrement ? ' AUTO_INCREMENT' : ''}`; + const onUpdateStatement = `${onUpdate ? ' ON UPDATE CURRENT_TIMESTAMP' : ''}`; + + const generatedStatement = generated + ? ` GENERATED ALWAYS AS (${generated?.as}) ${generated?.type.toUpperCase()}` + : ''; + + return `ALTER TABLE \`${tableName}\` ADD \`${name}\` ${type}${primaryKeyStatement}${autoincrementStatement}${defaultStatement}${notNullStatement}${onUpdateStatement}${generatedStatement};`; + } +} + export class SQLiteAlterTableAddColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2224,74 +2400,428 @@ class MySqlModifyColumn extends Convertor { } } -class PgAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { +class SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_composite_pk' && dialect === 'postgresql'; + return ( + statement.type === 'alter_table_alter_column_alter_generated' + && dialect === 'singlestore' + ); } - convert(statement: JsonCreateCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.data); - - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; - - return `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.constraintName}" PRIMARY KEY("${ - columns.join('","') - }");`; - } -} -class PgAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'delete_composite_pk' && dialect === 'postgresql'; - } + convert(statement: JsonAlterColumnAlterGeneratedStatement) { + const { + tableName, + columnName, + schema, + columnNotNull: notNull, + columnDefault, + columnOnUpdate, + columnAutoIncrement, + columnPk, + columnGenerated, + } = statement; - convert(statement: JsonDeleteCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.data); + const tableNameWithSchema = schema + ? `\`${schema}\`.\`${tableName}\`` + : `\`${tableName}\``; - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; + const addColumnStatement = new SingleStoreAlterTableAddColumnConvertor().convert({ + schema, + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull, + default: columnDefault, + onUpdate: columnOnUpdate, + autoincrement: columnAutoIncrement, + primaryKey: columnPk, + generated: columnGenerated, + }, + type: 'alter_table_add_column', + }); - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.constraintName}";`; + return [ + `ALTER TABLE ${tableNameWithSchema} drop column \`${columnName}\`;`, + addColumnStatement, + ]; } } -class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { +class SingleStoreAlterTableAlterColumnSetDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_composite_pk' && dialect === 'postgresql'; - } - - convert(statement: JsonAlterCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.old); - const { name: newName, columns: newColumns } = PgSquasher.unsquashPK( - statement.new, + return ( + statement.type === 'alter_table_alter_column_set_default' + && dialect === 'singlestore' ); + } - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; - - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT ${statement.oldConstraintName};\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newConstraintName} PRIMARY KEY(${ - newColumns.join(',') - });`; + convert(statement: JsonAlterColumnSetDefaultStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` ALTER COLUMN \`${columnName}\` SET DEFAULT ${statement.newDefaultValue};`; } } -class MySqlAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { +class SingleStoreAlterTableAlterColumnDropDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_composite_pk' && dialect === 'mysql'; + return ( + statement.type === 'alter_table_alter_column_drop_default' + && dialect === 'singlestore' + ); } - convert(statement: JsonCreateCompositePK) { - const { name, columns } = MySqlSquasher.unsquashPK(statement.data); - return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY(\`${columns.join('`,`')}\`);`; + convert(statement: JsonAlterColumnDropDefaultStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` ALTER COLUMN \`${columnName}\` DROP DEFAULT;`; } } -class MySqlAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'delete_composite_pk' && dialect === 'mysql'; +class SingleStoreAlterTableAddPk extends Convertor { + can(statement: JsonStatement, dialect: string): boolean { + return ( + statement.type === 'alter_table_alter_column_set_pk' + && dialect === 'singlestore' + ); + } + convert(statement: JsonAlterColumnSetPrimaryKeyStatement): string { + return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY (\`${statement.columnName}\`);`; + } +} + +class SingleStoreAlterTableDropPk extends Convertor { + can(statement: JsonStatement, dialect: string): boolean { + return ( + statement.type === 'alter_table_alter_column_drop_pk' + && dialect === 'singlestore' + ); + } + convert(statement: JsonAlterColumnDropPrimaryKeyStatement): string { + return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY`; + } +} + +type SingleStoreModifyColumnStatement = + | JsonAlterColumnDropNotNullStatement + | JsonAlterColumnSetNotNullStatement + | JsonAlterColumnTypeStatement + | JsonAlterColumnDropOnUpdateStatement + | JsonAlterColumnSetOnUpdateStatement + | JsonAlterColumnDropAutoincrementStatement + | JsonAlterColumnSetAutoincrementStatement + | JsonAlterColumnSetDefaultStatement + | JsonAlterColumnDropDefaultStatement + | JsonAlterColumnSetGeneratedStatement + | JsonAlterColumnDropGeneratedStatement; + +class SingleStoreModifyColumn extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + (statement.type === 'alter_table_alter_column_set_type' + || statement.type === 'alter_table_alter_column_set_notnull' + || statement.type === 'alter_table_alter_column_drop_notnull' + || statement.type === 'alter_table_alter_column_drop_on_update' + || statement.type === 'alter_table_alter_column_set_on_update' + || statement.type === 'alter_table_alter_column_set_autoincrement' + || statement.type === 'alter_table_alter_column_drop_autoincrement' + || statement.type === 'alter_table_alter_column_set_default' + || statement.type === 'alter_table_alter_column_drop_default' + || statement.type === 'alter_table_alter_column_set_generated' + || statement.type === 'alter_table_alter_column_drop_generated') + && dialect === 'singlestore' + ); + } + + convert(statement: SingleStoreModifyColumnStatement) { + const { tableName, columnName } = statement; + let columnType = ``; + let columnDefault: any = ''; + let columnNotNull = ''; + let columnOnUpdate = ''; + let columnAutoincrement = ''; + let primaryKey = statement.columnPk ? ' PRIMARY KEY' : ''; + let columnGenerated = ''; + + if (statement.type === 'alter_table_alter_column_drop_notnull') { + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_notnull') { + columnNotNull = ` NOT NULL`; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_drop_on_update') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnOnUpdate = ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_on_update') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = ` ON UPDATE CURRENT_TIMESTAMP`; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if ( + statement.type === 'alter_table_alter_column_set_autoincrement' + ) { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = ' AUTO_INCREMENT'; + } else if ( + statement.type === 'alter_table_alter_column_drop_autoincrement' + ) { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = ''; + } else if (statement.type === 'alter_table_alter_column_set_default') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = ` DEFAULT ${statement.newDefaultValue}`; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_drop_default') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_generated') { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + + if (statement.columnGenerated?.type === 'virtual') { + return [ + new SingleStoreAlterTableDropColumnConvertor().convert({ + type: 'alter_table_drop_column', + tableName: statement.tableName, + columnName: statement.columnName, + schema: statement.schema, + }), + new SingleStoreAlterTableAddColumnConvertor().convert({ + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull: statement.columnNotNull, + default: statement.columnDefault, + onUpdate: statement.columnOnUpdate, + autoincrement: statement.columnAutoIncrement, + primaryKey: statement.columnPk, + generated: statement.columnGenerated, + }, + schema: statement.schema, + type: 'alter_table_add_column', + }), + ]; + } else { + columnGenerated = statement.columnGenerated + ? ` GENERATED ALWAYS AS (${statement.columnGenerated?.as}) ${statement.columnGenerated?.type.toUpperCase()}` + : ''; + } + } else if (statement.type === 'alter_table_alter_column_drop_generated') { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + + if (statement.oldColumn?.generated?.type === 'virtual') { + return [ + new SingleStoreAlterTableDropColumnConvertor().convert({ + type: 'alter_table_drop_column', + tableName: statement.tableName, + columnName: statement.columnName, + schema: statement.schema, + }), + new SingleStoreAlterTableAddColumnConvertor().convert({ + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull: statement.columnNotNull, + default: statement.columnDefault, + onUpdate: statement.columnOnUpdate, + autoincrement: statement.columnAutoIncrement, + primaryKey: statement.columnPk, + generated: statement.columnGenerated, + }, + schema: statement.schema, + type: 'alter_table_add_column', + }), + ]; + } + } else { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + columnGenerated = statement.columnGenerated + ? ` GENERATED ALWAYS AS (${statement.columnGenerated?.as}) ${statement.columnGenerated?.type.toUpperCase()}` + : ''; + } + + // Seems like getting value from simple json2 shanpshot makes dates be dates + columnDefault = columnDefault instanceof Date + ? columnDefault.toISOString() + : columnDefault; + + return `ALTER TABLE \`${tableName}\` MODIFY COLUMN \`${columnName}\`${columnType}${columnAutoincrement}${columnNotNull}${columnDefault}${columnOnUpdate}${columnGenerated};`; + } +} +class SqliteAlterTableAlterColumnDropDefaultConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + statement.type === 'alter_table_alter_column_drop_default' + && dialect === 'sqlite' + ); + } + + convert(statement: JsonAlterColumnDropDefaultStatement) { + return ( + '/*\n SQLite does not support "Drop default from column" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' + ); + } +} + +class PgAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonCreateCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.data); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.constraintName}" PRIMARY KEY("${ + columns.join('","') + }");`; + } +} +class PgAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonDeleteCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.data); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.constraintName}";`; + } +} + +class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonAlterCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.old); + const { name: newName, columns: newColumns } = PgSquasher.unsquashPK( + statement.new, + ); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT ${statement.oldConstraintName};\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newConstraintName} PRIMARY KEY(${ + newColumns.join(',') + });`; + } +} + +class MySqlAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'mysql'; + } + + convert(statement: JsonCreateCompositePK) { + const { name, columns } = MySqlSquasher.unsquashPK(statement.data); + return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY(\`${columns.join('`,`')}\`);`; + } +} + +class MySqlAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'mysql'; } convert(statement: JsonDeleteCompositePK) { @@ -2314,6 +2844,125 @@ class MySqlAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { } } +class SingleStoreAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'singlestore'; + } + + convert(statement: JsonCreateCompositePK) { + const { name, columns } = SingleStoreSquasher.unsquashPK(statement.data); + return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY(\`${columns.join('`,`')}\`);`; + } +} + +class SingleStoreAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'singlestore'; + } + + convert(statement: JsonDeleteCompositePK) { + const { name, columns } = SingleStoreSquasher.unsquashPK(statement.data); + return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY;`; + } +} + +class SingleStoreAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_composite_pk' && dialect === 'singlestore'; + } + + convert(statement: JsonAlterCompositePK) { + const { name, columns } = SingleStoreSquasher.unsquashPK(statement.old); + const { name: newName, columns: newColumns } = SingleStoreSquasher.unsquashPK( + statement.new, + ); + return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY, ADD PRIMARY KEY(\`${newColumns.join('`,`')}\`);`; + } +} + +class SqliteAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'sqlite'; + } + + convert(statement: JsonCreateCompositePK) { + let msg = '/*\n'; + msg += `You're trying to add PRIMARY KEY(${statement.data}) to '${statement.tableName}' table\n`; + msg += 'SQLite does not support adding primary key to an already created table\n'; + msg += 'You can do it in 3 steps with drizzle orm:\n'; + msg += ' - create new mirror table with needed pk, rename current table to old_table, generate SQL\n'; + msg += ' - migrate old data from one table to another\n'; + msg += ' - delete old_table in schema, generate sql\n\n'; + msg += 'or create manual migration like below:\n\n'; + msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; + msg += 'CREATE TABLE table_name (\n'; + msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; + msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; + msg += '\t...\n'; + msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; + msg += ' );\n'; + msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; + msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; + msg += '*/\n'; + return msg; + } +} +class SqliteAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'sqlite'; + } + + convert(statement: JsonDeleteCompositePK) { + let msg = '/*\n'; + msg += `You're trying to delete PRIMARY KEY(${statement.data}) from '${statement.tableName}' table\n`; + msg += 'SQLite does not supportprimary key deletion from existing table\n'; + msg += 'You can do it in 3 steps with drizzle orm:\n'; + msg += ' - create new mirror table table without pk, rename current table to old_table, generate SQL\n'; + msg += ' - migrate old data from one table to another\n'; + msg += ' - delete old_table in schema, generate sql\n\n'; + msg += 'or create manual migration like below:\n\n'; + msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; + msg += 'CREATE TABLE table_name (\n'; + msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; + msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; + msg += '\t...\n'; + msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; + msg += ' );\n'; + msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; + msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; + msg += '*/\n'; + return msg; + } +} + +class SqliteAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_composite_pk' && dialect === 'sqlite'; + } + + convert(statement: JsonAlterCompositePK) { + let msg = '/*\n'; + msg += 'SQLite does not support altering primary key\n'; + msg += 'You can do it in 3 steps with drizzle orm:\n'; + msg += ' - create new mirror table with needed pk, rename current table to old_table, generate SQL\n'; + msg += ' - migrate old data from one table to another\n'; + msg += ' - delete old_table in schema, generate sql\n\n'; + msg += 'or create manual migration like below:\n\n'; + msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; + msg += 'CREATE TABLE table_name (\n'; + msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; + msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; + msg += '\t...\n'; + msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; + msg += ' );\n'; + msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; + msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; + msg += '*/\n'; + + return msg; + } +} + class PgAlterTableAlterColumnSetPrimaryKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2656,6 +3305,32 @@ class CreateMySqlIndexConvertor extends Convertor { } } +class CreateSingleStoreIndexConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_index' && dialect === 'singlestore'; + } + + convert(statement: JsonCreateIndexStatement): string { + // should be changed + const { name, columns, isUnique } = SingleStoreSquasher.unsquashIdx( + statement.data, + ); + const indexPart = isUnique ? 'UNIQUE INDEX' : 'INDEX'; + + const uniqueString = columns + .map((it) => { + return statement.internal?.indexes + ? statement.internal?.indexes[name]?.columns[it]?.isExpression + ? it + : `\`${it}\`` + : `\`${it}\``; + }) + .join(','); + + return `CREATE ${indexPart} \`${name}\` ON \`${statement.tableName}\` (${uniqueString});`; + } +} + export class CreateSqliteIndexConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_index' && (dialect === 'sqlite' || dialect === 'turso'); @@ -2800,6 +3475,17 @@ class MySqlDropIndexConvertor extends Convertor { } } +class SingleStoreDropIndexConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_index' && dialect === 'singlestore'; + } + + convert(statement: JsonDropIndexStatement): string { + const { name } = SingleStoreSquasher.unsquashIdx(statement.data); + return `DROP INDEX \`${name}\` ON \`${statement.tableName}\`;`; + } +} + class SQLiteRecreateTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2935,6 +3621,7 @@ class LibSQLRecreateTableConvertor extends Convertor { const convertors: Convertor[] = []; convertors.push(new PgCreateTableConvertor()); convertors.push(new MySqlCreateTableConvertor()); +convertors.push(new SingleStoreCreateTableConvertor()); convertors.push(new SQLiteCreateTableConvertor()); convertors.push(new SQLiteRecreateTableConvertor()); convertors.push(new LibSQLRecreateTableConvertor()); @@ -2971,22 +3658,27 @@ convertors.push(new AlterPgSequenceConvertor()); convertors.push(new PgDropTableConvertor()); convertors.push(new MySQLDropTableConvertor()); +convertors.push(new SingleStoreDropTableConvertor()); convertors.push(new SQLiteDropTableConvertor()); convertors.push(new PgRenameTableConvertor()); convertors.push(new MySqlRenameTableConvertor()); +convertors.push(new SingleStoreRenameTableConvertor()); convertors.push(new SqliteRenameTableConvertor()); convertors.push(new PgAlterTableRenameColumnConvertor()); convertors.push(new MySqlAlterTableRenameColumnConvertor()); +convertors.push(new SingleStoreAlterTableRenameColumnConvertor()); convertors.push(new SQLiteAlterTableRenameColumnConvertor()); convertors.push(new PgAlterTableDropColumnConvertor()); convertors.push(new MySqlAlterTableDropColumnConvertor()); +convertors.push(new SingleStoreAlterTableDropColumnConvertor()); convertors.push(new SQLiteAlterTableDropColumnConvertor()); convertors.push(new PgAlterTableAddColumnConvertor()); convertors.push(new MySqlAlterTableAddColumnConvertor()); +convertors.push(new SingleStoreAlterTableAddColumnConvertor()); convertors.push(new SQLiteAlterTableAddColumnConvertor()); convertors.push(new PgAlterTableAlterColumnSetTypeConvertor()); @@ -3002,13 +3694,18 @@ convertors.push(new MySqlAlterTableDeleteCheckConstraintConvertor()); convertors.push(new MySQLAlterTableAddUniqueConstraintConvertor()); convertors.push(new MySQLAlterTableDropUniqueConstraintConvertor()); +convertors.push(new SingleStoreAlterTableAddUniqueConstraintConvertor()); +convertors.push(new SingleStoreAlterTableDropUniqueConstraintConvertor()); + convertors.push(new CreatePgIndexConvertor()); convertors.push(new CreateMySqlIndexConvertor()); +convertors.push(new CreateSingleStoreIndexConvertor()); convertors.push(new CreateSqliteIndexConvertor()); convertors.push(new PgDropIndexConvertor()); convertors.push(new SqliteDropIndexConvertor()); convertors.push(new MySqlDropIndexConvertor()); +convertors.push(new SingleStoreDropIndexConvertor()); convertors.push(new PgAlterTableAlterColumnSetPrimaryKeyConvertor()); convertors.push(new PgAlterTableAlterColumnDropPrimaryKeyConvertor()); @@ -3024,6 +3721,8 @@ convertors.push(new PgAlterTableAlterColumnAlterrGeneratedConvertor()); convertors.push(new MySqlAlterTableAlterColumnAlterrGeneratedConvertor()); +convertors.push(new SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor()); + convertors.push(new SqliteAlterTableAlterColumnDropGeneratedConvertor()); convertors.push(new SqliteAlterTableAlterColumnAlterGeneratedConvertor()); convertors.push(new SqliteAlterTableAlterColumnSetExpressionConvertor()); @@ -3033,6 +3732,8 @@ convertors.push(new LibSQLModifyColumn()); // convertors.push(new MySqlAlterTableAlterColumnSetDefaultConvertor()); // convertors.push(new MySqlAlterTableAlterColumnDropDefaultConvertor()); +convertors.push(new SingleStoreModifyColumn()); + convertors.push(new PgCreateForeignKeyConvertor()); convertors.push(new MySqlCreateForeignKeyConvertor()); @@ -3064,6 +3765,12 @@ convertors.push(new MySqlAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new MySqlAlterTableAddPk()); convertors.push(new MySqlAlterTableAlterCompositePrimaryKeyConvertor()); +convertors.push(new SingleStoreAlterTableDeleteCompositePrimaryKeyConvertor()); +convertors.push(new SingleStoreAlterTableDropPk()); +convertors.push(new SingleStoreAlterTableCreateCompositePrimaryKeyConvertor()); +convertors.push(new SingleStoreAlterTableAddPk()); +convertors.push(new SingleStoreAlterTableAlterCompositePrimaryKeyConvertor()); + export function fromJson( statements: JsonStatement[], dialect: Exclude, diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index c13467da3..927e0ff51 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -11,6 +11,7 @@ import { assertUnreachable, snapshotVersion } from './global'; import type { Dialect } from './schemaValidator'; import { backwardCompatibleMysqlSchema } from './serializer/mysqlSchema'; import { backwardCompatiblePgSchema } from './serializer/pgSchema'; +import { backwardCompatibleSingleStoreSchema } from './serializer/singlestoreSchema'; import { backwardCompatibleSqliteSchema } from './serializer/sqliteSchema'; import type { ProxyParams } from './serializer/studio'; @@ -124,6 +125,8 @@ const validatorForDialect = (dialect: Dialect) => { return { validator: backwardCompatibleSqliteSchema, version: 6 }; case 'mysql': return { validator: backwardCompatibleMysqlSchema, version: 5 }; + case 'singlestore': + return { validator: backwardCompatibleSingleStoreSchema, version: 1 }; } }; diff --git a/drizzle-kit/tests/push/singlestore-push.test.ts b/drizzle-kit/tests/push/singlestore-push.test.ts new file mode 100644 index 000000000..5db899fc0 --- /dev/null +++ b/drizzle-kit/tests/push/singlestore-push.test.ts @@ -0,0 +1,335 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import { int, singlestoreTable, singlestoreView } from 'drizzle-orm/singlestore-core'; +import fs from 'fs'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { diffTestSchemasPushSingleStore } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, expect, test } from 'vitest'; + +let client: Connection; +let singlestoreContainer: Docker.Container; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + ); + + singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return `singlestore://root:singlestore@localhost:${port}/`; +} + +beforeAll(async () => { + const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); + throw lastError; + } +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); +}); + +if (!fs.existsSync('tests/push/singlestore')) { + fs.mkdirSync('tests/push/singlestore'); +} + +test('add check constraint to table', async () => { + const schema1 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + const schema2 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'create_check_constraint', + tableName: 'test', + schema: '', + data: 'some_check1;\`test\`.\`values\` < 100', + }, + { + data: "some_check2;'test' < 100", + schema: '', + tableName: 'test', + type: 'create_check_constraint', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE \`test\` ADD CONSTRAINT \`some_check1\` CHECK (\`test\`.\`values\` < 100);', + `ALTER TABLE \`test\` ADD CONSTRAINT \`some_check2\` CHECK ('test' < 100);`, + ]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('drop check constraint to table', async () => { + const schema1 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + const schema2 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'delete_check_constraint', + tableName: 'test', + schema: '', + constraintName: 'some_check1', + }, + { + constraintName: 'some_check2', + schema: '', + tableName: 'test', + type: 'delete_check_constraint', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE \`test\` DROP CONSTRAINT \`some_check1\`;', + `ALTER TABLE \`test\` DROP CONSTRAINT \`some_check2\`;`, + ]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('db has checks. Push with same names', async () => { + const schema1 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values').default(1), + }), + }; + const schema2 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values').default(1), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('create view', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + }; + + const schema2 = { + test: table, + view: singlestoreView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + definition: 'select \`id\` from \`test\`', + name: 'view', + type: 'singlestore_create_view', + replace: false, + sqlSecurity: 'definer', + withCheckOption: undefined, + algorithm: 'undefined', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `CREATE ALGORITHM = undefined +SQL SECURITY definer +VIEW \`view\` AS (select \`id\` from \`test\`);`, + ]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('drop view', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: singlestoreView('view').as((qb) => qb.select().from(table)), + }; + + const schema2 = { + test: table, + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + name: 'view', + type: 'drop_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'DROP VIEW \`view\`;', + ]); + await client.query(`DROP TABLE \`test\`;`); + await client.query(`DROP VIEW \`view\`;`); +}); + +test('alter view ".as"', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: singlestoreView('view').as((qb) => qb.select().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: singlestoreView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`DROP TABLE \`test\`;`); + await client.query(`DROP VIEW \`view\`;`); +}); + +test('alter meta options with distinct in definition', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: singlestoreView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('merge').as(( + qb, + ) => qb.selectDistinct().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: singlestoreView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('undefined').as((qb) => + qb.selectDistinct().from(table) + ), + }; + + await expect(diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + )).rejects.toThrowError(); + + await client.query(`DROP TABLE \`test\`;`); +}); diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts new file mode 100644 index 000000000..7f3ea755d --- /dev/null +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -0,0 +1,699 @@ +import Docker from 'dockerode'; +import { SQL, sql } from 'drizzle-orm'; +import { + bigint, + binary, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + singlestoreEnum, + singlestoreTable, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, +} from 'drizzle-orm/singlestore-core'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { diffTestSchemasSingleStore, diffTestSchemasPushSingleStore } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { expect } from 'vitest'; +import { DialectSuite, run } from './common'; + +async function createDockerDB(context: any): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + ); + + context.singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await context.singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return `singlestore://root:singlestore@localhost:${port}/`; +} + +const singlestoreSuite: DialectSuite = { + allTypes: async function(context: any): Promise { + const schema1 = { + allBigInts: singlestoreTable('all_big_ints', { + simple: bigint('simple', { mode: 'number' }), + columnNotNull: bigint('column_not_null', { mode: 'number' }).notNull(), + columnDefault: bigint('column_default', { mode: 'number' }).default(12), + columnDefaultSql: bigint('column_default_sql', { + mode: 'number', + }).default(12), + }), + allBools: singlestoreTable('all_bools', { + simple: tinyint('simple'), + columnNotNull: tinyint('column_not_null').notNull(), + columnDefault: tinyint('column_default').default(1), + }), + allChars: singlestoreTable('all_chars', { + simple: char('simple', { length: 1 }), + columnNotNull: char('column_not_null', { length: 45 }).notNull(), + // columnDefault: char("column_default", { length: 1 }).default("h"), + columnDefaultSql: char('column_default_sql', { length: 1 }).default( + 'h', + ), + }), + allDateTimes: singlestoreTable('all_date_times', { + simple: datetime('simple', { mode: 'string', fsp: 1 }), + columnNotNull: datetime('column_not_null', { + mode: 'string', + }).notNull(), + columnDefault: datetime('column_default', { mode: 'string' }).default( + '2023-03-01 14:05:29', + ), + }), + allDates: singlestoreTable('all_dates', { + simple: date('simple', { mode: 'string' }), + column_not_null: date('column_not_null', { mode: 'string' }).notNull(), + column_default: date('column_default', { mode: 'string' }).default( + '2023-03-01', + ), + }), + allDecimals: singlestoreTable('all_decimals', { + simple: decimal('simple', { precision: 1, scale: 0 }), + columnNotNull: decimal('column_not_null', { + precision: 45, + scale: 3, + }).notNull(), + columnDefault: decimal('column_default', { + precision: 10, + scale: 0, + }).default('100'), + columnDefaultSql: decimal('column_default_sql', { + precision: 10, + scale: 0, + }).default('101'), + }), + + allDoubles: singlestoreTable('all_doubles', { + simple: double('simple'), + columnNotNull: double('column_not_null').notNull(), + columnDefault: double('column_default').default(100), + columnDefaultSql: double('column_default_sql').default(101), + }), + + allEnums: singlestoreTable('all_enums', { + simple: singlestoreEnum('simple', ['hi', 'hello']), + }), + + allEnums1: singlestoreTable('all_enums1', { + simple: singlestoreEnum('simple', ['hi', 'hello']).default('hi'), + }), + + allFloats: singlestoreTable('all_floats', { + columnNotNull: float('column_not_null').notNull(), + columnDefault: float('column_default').default(100), + columnDefaultSql: float('column_default_sql').default(101), + }), + + allInts: singlestoreTable('all_ints', { + simple: int('simple'), + columnNotNull: int('column_not_null').notNull(), + columnDefault: int('column_default').default(100), + columnDefaultSql: int('column_default_sql').default(101), + }), + + allIntsRef: singlestoreTable('all_ints_ref', { + simple: int('simple'), + columnNotNull: int('column_not_null').notNull(), + columnDefault: int('column_default').default(100), + columnDefaultSql: int('column_default_sql').default(101), + }), + + allJsons: singlestoreTable('all_jsons', { + columnDefaultObject: json('column_default_object') + .default({ hello: 'world world' }) + .notNull(), + columnDefaultArray: json('column_default_array').default({ + hello: { 'world world': ['foo', 'bar'] }, + foo: 'bar', + fe: 23, + }), + column: json('column'), + }), + + allMInts: singlestoreTable('all_m_ints', { + simple: mediumint('simple'), + columnNotNull: mediumint('column_not_null').notNull(), + columnDefault: mediumint('column_default').default(100), + columnDefaultSql: mediumint('column_default_sql').default(101), + }), + + allReals: singlestoreTable('all_reals', { + simple: double('simple', { precision: 5, scale: 2 }), + columnNotNull: double('column_not_null').notNull(), + columnDefault: double('column_default').default(100), + columnDefaultSql: double('column_default_sql').default(101), + }), + + allSInts: singlestoreTable('all_s_ints', { + simple: smallint('simple'), + columnNotNull: smallint('column_not_null').notNull(), + columnDefault: smallint('column_default').default(100), + columnDefaultSql: smallint('column_default_sql').default(101), + }), + + allSmallSerials: singlestoreTable('all_small_serials', { + columnAll: serial('column_all').primaryKey().notNull(), + }), + + allTInts: singlestoreTable('all_t_ints', { + simple: tinyint('simple'), + columnNotNull: tinyint('column_not_null').notNull(), + columnDefault: tinyint('column_default').default(10), + columnDefaultSql: tinyint('column_default_sql').default(11), + }), + + allTexts: singlestoreTable('all_texts', { + simple: text('simple'), + columnNotNull: text('column_not_null').notNull(), + columnDefault: text('column_default').default('hello'), + columnDefaultSql: text('column_default_sql').default('hello'), + }), + + allTimes: singlestoreTable('all_times', { + simple: time('simple', { fsp: 1 }), + columnNotNull: time('column_not_null').notNull(), + columnDefault: time('column_default').default('22:12:12'), + }), + + allTimestamps: singlestoreTable('all_timestamps', { + columnDateNow: timestamp('column_date_now', { + fsp: 1, + mode: 'string', + }).default(sql`(now())`), + columnAll: timestamp('column_all', { mode: 'string' }) + .default('2023-03-01 14:05:29') + .notNull(), + column: timestamp('column', { mode: 'string' }).default( + '2023-02-28 16:18:31', + ), + }), + + allVarChars: singlestoreTable('all_var_chars', { + simple: varchar('simple', { length: 100 }), + columnNotNull: varchar('column_not_null', { length: 45 }).notNull(), + columnDefault: varchar('column_default', { length: 100 }).default( + 'hello', + ), + columnDefaultSql: varchar('column_default_sql', { + length: 100, + }).default('hello'), + }), + + allVarbinaries: singlestoreTable('all_varbinaries', { + simple: varbinary('simple', { length: 100 }), + columnNotNull: varbinary('column_not_null', { length: 100 }).notNull(), + columnDefault: varbinary('column_default', { length: 12 }).default( + sql`(uuid_to_bin(uuid()))`, + ), + }), + + allYears: singlestoreTable('all_years', { + simple: year('simple'), + columnNotNull: year('column_not_null').notNull(), + columnDefault: year('column_default').default(2022), + }), + + binafry: singlestoreTable('binary', { + simple: binary('simple', { length: 1 }), + columnNotNull: binary('column_not_null', { length: 1 }).notNull(), + columnDefault: binary('column_default', { length: 12 }).default( + sql`(uuid_to_bin(uuid()))`, + ), + }), + }; + + const { statements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema1, + [], + 'drizzle', + false, + ); + expect(statements.length).toBe(2); + expect(statements).toEqual([ + { + type: 'delete_unique_constraint', + tableName: 'all_small_serials', + data: 'column_all;column_all', + schema: '', + }, + { + type: 'delete_unique_constraint', + tableName: 'all_small_serials', + data: 'column_all;column_all', + schema: '', + }, + ]); + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema1, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + addBasicIndexes: function(context?: any): Promise { + return {} as any; + }, + changeIndexFields: function(context?: any): Promise { + return {} as any; + }, + dropIndex: function(context?: any): Promise { + return {} as any; + }, + indexesToBeNotTriggered: function(context?: any): Promise { + return {} as any; + }, + indexesTestCase1: function(context?: any): Promise { + return {} as any; + }, + async case1() { + // TODO: implement if needed + expect(true).toBe(true); + }, + addNotNull: function(context?: any): Promise { + return {} as any; + }, + addNotNullWithDataNoRollback: function(context?: any): Promise { + return {} as any; + }, + addBasicSequences: function(context?: any): Promise { + return {} as any; + }, + addGeneratedColumn: async function(context: any): Promise { + const schema1 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const schema2 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'stored' }, + ), + generatedName1: text('gen_name1').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'virtual' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + column: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + { + column: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + name: 'gen_name1', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + "ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); + + for (const st of sqlStatements) { + await context.client.query(st); + } + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema2, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + addGeneratedToColumn: async function(context: any): Promise { + const schema1 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name'), + generatedName1: text('gen_name1'), + }), + }; + const schema2 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'stored' }, + ), + generatedName1: text('gen_name1').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'virtual' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name1', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', + "ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); + + for (const st of sqlStatements) { + await context.client.query(st); + } + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema2, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + dropGeneratedConstraint: async function(context: any): Promise { + const schema1 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name}`, + { mode: 'stored' }, + ), + generatedName1: text('gen_name1').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name}`, + { mode: 'virtual' }, + ), + }), + }; + const schema2 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name'), + generatedName1: text('gen_name1'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + oldColumn: { + autoincrement: false, + default: undefined, + generated: { + as: '`name`', + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name1', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + oldColumn: { + autoincrement: false, + default: undefined, + generated: { + as: '`name`', + type: 'virtual', + }, + name: 'gen_name1', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', + 'ALTER TABLE `users` ADD `gen_name1` text;', + ]); + + for (const st of sqlStatements) { + await context.client.query(st); + } + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema2, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + alterGeneratedConstraint: async function(context: any): Promise { + const schema1 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name}`, + { mode: 'stored' }, + ), + generatedName1: text('gen_name1').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name}`, + { mode: 'virtual' }, + ), + }), + }; + const schema2 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'stored' }, + ), + generatedName1: text('gen_name1').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'virtual' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema2, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + createTableWithGeneratedConstraint: function(context?: any): Promise { + return {} as any; + }, +}; + +run( + singlestoreSuite, + async (context: any) => { + const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(context); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + context.client = await createConnection(connectionString); + await context.client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await context.client?.end().catch(console.error); + await context.singlestoreContainer?.stop().catch(console.error); + throw lastError; + } + }, + async (context: any) => { + await context.client?.end().catch(console.error); + await context.singlestoreContainer?.stop().catch(console.error); + }, +); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 3001887e1..9683809d1 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -1,7 +1,6 @@ import { PGlite } from '@electric-sql/pglite'; import { Client } from '@libsql/client/.'; import { Database } from 'better-sqlite3'; -import { randomUUID } from 'crypto'; import { is } from 'drizzle-orm'; import { MySqlSchema, MySqlTable, MySqlView } from 'drizzle-orm/mysql-core'; import { @@ -17,6 +16,7 @@ import { PgTable, PgView, } from 'drizzle-orm/pg-core'; +import { SingleStoreSchema, SingleStoreTable, SingleStoreView } from 'drizzle-orm/singlestore-core'; import { SQLiteTable, SQLiteView } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; @@ -37,22 +37,28 @@ import { logSuggestionsAndReturn } from 'src/cli/commands/sqlitePushUtils'; import { CasingType } from 'src/cli/validations/common'; import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql'; import { schemaToTypeScript } from 'src/introspect-pg'; +import { schemaToTypeScript as schemaToTypeScriptSingleStore } from 'src/introspect-singlestore'; import { schemaToTypeScript as schemaToTypeScriptSQLite } from 'src/introspect-sqlite'; import { prepareFromMySqlImports } from 'src/serializer/mysqlImports'; import { mysqlSchema, squashMysqlScheme, ViewSquashed } from 'src/serializer/mysqlSchema'; -import { generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; -import { fromDatabase as fromMySqlDatabase } from 'src/serializer/mysqlSerializer'; +import { fromDatabase as fromMySqlDatabase, generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; import { prepareFromPgImports } from 'src/serializer/pgImports'; import { pgSchema, squashPgScheme, View } from 'src/serializer/pgSchema'; import { fromDatabase, generatePgSnapshot } from 'src/serializer/pgSerializer'; +import { prepareFromSingleStoreImports } from 'src/serializer/singlestoreImports'; +import { singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; +import { + fromDatabase as fromSingleStoreDatabase, + generateSingleStoreSnapshot, +} from 'src/serializer/singlestoreSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; import { sqliteSchema, squashSqliteScheme, View as SqliteView } from 'src/serializer/sqliteSchema'; -import { fromDatabase as fromSqliteDatabase } from 'src/serializer/sqliteSerializer'; -import { generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; +import { fromDatabase as fromSqliteDatabase, generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; import { applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, Column, ColumnsResolverInput, @@ -71,6 +77,7 @@ export type PostgresSchema = Record< >; export type MysqlSchema = Record | MySqlSchema | MySqlView>; export type SqliteSchema = Record | SQLiteView>; +export type SinglestoreSchema = Record | SingleStoreSchema | SingleStoreView>; export const testSchemasResolver = (renames: Set) => async (input: ResolverInput): Promise> => { @@ -536,6 +543,77 @@ export const testViewsResolverMySql = } }; +export const testViewsResolverSingleStore = + (renames: Set) => + async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } + + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; + + const result: { + created: ViewSquashed[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: ViewSquashed; to: ViewSquashed }[]; + deleted: ViewSquashed[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; + }); + + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, + }); + } + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } + } + + result.created = createdViews; + result.deleted = deletedViews; + + return result; + } catch (e) { + console.error(e); + throw e; + } + }; + export const testViewsResolverSqlite = (renames: Set) => async (input: ResolverInput): Promise> => { try { @@ -1142,6 +1220,209 @@ export const diffTestSchemasMysql = async ( return { sqlStatements, statements }; }; +export const diffTestSchemasSingleStore = async ( + left: SinglestoreSchema, + right: SinglestoreSchema, + renamesArr: string[], + cli: boolean = false, + casing?: CasingType | undefined, +) => { + const leftTables = Object.values(left).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const leftViews = Object.values(left).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + + const rightTables = Object.values(right).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const rightViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + + const serialized1 = generateSingleStoreSnapshot(leftTables, leftViews, casing); + const serialized2 = generateSingleStoreSnapshot(rightTables, rightViews, casing); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashSingleStoreScheme(sch1); + const sn2 = squashSingleStoreScheme(sch2); + + const validatedPrev = singlestoreSchema.parse(sch1); + const validatedCur = singlestoreSchema.parse(sch2); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + sn1, + sn2, + testTablesResolver(renames), + testColumnsResolver(renames), + testViewsResolverMySql(renames), + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; + } + + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + mySqlViewsResolver, + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; +}; + +export const diffTestSchemasPushSinglestore = async ( + client: Connection, + left: SingleStoreSchema, + right: SingleStoreSchema, + renamesArr: string[], + schema: string, + cli: boolean = false, + casing?: CasingType | undefined, +) => { + const { sqlStatements } = await applySingleStoreDiffs(left, casing); + for (const st of sqlStatements) { + await client.query(st); + } + // do introspect into PgSchemaInternal + const introspectedSchema = await fromSingleStoreDatabase( + { + query: async (sql: string, params?: any[]) => { + const res = await client.execute(sql, params); + return res[0] as any; + }, + }, + schema, + ); + + const leftTables = Object.values(right).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const leftViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + + const serialized2 = generateSingleStoreSnapshot(leftTables, leftViews, casing); + + const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashSingleStoreScheme(sch1); + const sn2 = squashSingleStoreScheme(sch2); + + const validatedPrev = singlestoreSchema.parse(sch1); + const validatedCur = singlestoreSchema.parse(sch2); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + sn1, + sn2, + testTablesResolver(renames), + testColumnsResolver(renames), + testViewsResolverSingleStore(renames), + validatedPrev, + validatedCur, + 'push', + ); + return { sqlStatements, statements }; + } else { + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + mySqlViewsResolver, + validatedPrev, + validatedCur, + 'push', + ); + return { sqlStatements, statements }; + } +}; + +export const applySingleStoreDiffs = async (sn: SingleStoreSchema, casing: CasingType | undefined) => { + const dryRun = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + tables: {}, + enums: {}, + schemas: {}, + _meta: { + schemas: {}, + tables: {}, + columns: {}, + }, + } as const; + + const tables = Object.values(sn).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const views = Object.values(sn).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + + const serialized1 = generateSingleStoreSnapshot(tables, views, casing); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + + const sch1 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sn1 = squashSingleStoreScheme(sch1); + + const validatedPrev = singlestoreSchema.parse(dryRun); + const validatedCur = singlestoreSchema.parse(sch1); + + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + dryRun, + sn1, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + testViewsResolverSingleStore(new Set()), + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; +}; + export const diffTestSchemasPushSqlite = async ( client: Database, left: SqliteSchema, @@ -1787,6 +2068,91 @@ export const introspectMySQLToFile = async ( }; }; +export const introspectSingleStoreToFile = async ( + client: Connection, + initSchema: SingleStoreSchema, + testName: string, + schema: string, + casing?: CasingType | undefined, +) => { + // put in db + const { sqlStatements } = await applySingleStoreDiffs(initSchema, casing); + for (const st of sqlStatements) { + await client.query(st); + } + + // introspect to schema + const introspectedSchema = await fromSingleStoreDatabase( + { + query: async (sql: string, params?: any[] | undefined) => { + const res = await client.execute(sql, params); + return res[0] as any; + }, + }, + schema, + ); + + const file = schemaToTypeScriptSingleStore(introspectedSchema, 'camel'); + + fs.writeFileSync(`tests/introspect/singlestore/${testName}.ts`, file.file); + + const response = await prepareFromSingleStoreImports([ + `tests/introspect/singlestore/${testName}.ts`, + ]); + + const afterFileImports = generateSingleStoreSnapshot(response.tables, response.views, casing); + + const { version: v2, dialect: d2, ...rest2 } = afterFileImports; + + const sch2 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn2AfterIm = squashSingleStoreScheme(sch2); + const validatedCurAfterImport = singlestoreSchema.parse(sch2); + + const leftTables = Object.values(initSchema).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const initSnapshot = generateSingleStoreSnapshot(leftTables, response.views, casing); + + const { version: initV, dialect: initD, ...initRest } = initSnapshot; + + const initSch = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashSingleStoreScheme(initSch); + const validatedCur = singlestoreSchema.parse(initSch); + + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applySingleStoreSnapshotsDiff( + sn2AfterIm, + initSn, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + testViewsResolverSingleStore(new Set()), + validatedCurAfterImport, + validatedCur, + ); + + fs.rmSync(`tests/introspect/singlestore/${testName}.ts`); + + return { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + }; +}; + export const introspectSQLiteToFile = async ( client: Database, initSchema: SqliteSchema, diff --git a/drizzle-kit/tests/singlestore-generated.test.ts b/drizzle-kit/tests/singlestore-generated.test.ts new file mode 100644 index 000000000..8944f3b21 --- /dev/null +++ b/drizzle-kit/tests/singlestore-generated.test.ts @@ -0,0 +1,1290 @@ +import { SQL, sql } from 'drizzle-orm'; +import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +test('generated as callback: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as callback: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs((): SQL => sql`${from.users.name} || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as callback: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs((): SQL => sql`${from.users.name} || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as callback: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name} || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as callback: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name} || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as callback: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as callback: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as callback: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +// --- + +test('generated as sql: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as sql: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(sql`\`users\`.\`name\` || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as sql: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(sql`\`users\`.\`name\` || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as sql: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as sql: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as sql: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as sql: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as sql: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +// --- + +test('generated as string: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as string: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(`\`users\`.\`name\` || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as string: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(`\`users\`.\`name\` || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as string: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as string: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as string: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``, { + mode: 'virtual', + }), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as string: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as string: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); diff --git a/drizzle-kit/tests/singlestore-schemas.test.ts b/drizzle-kit/tests/singlestore-schemas.test.ts new file mode 100644 index 000000000..db9fe0480 --- /dev/null +++ b/drizzle-kit/tests/singlestore-schemas.test.ts @@ -0,0 +1,155 @@ +import { singlestoreSchema, singlestoreTable } from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +// We don't manage databases(schemas) in MySQL with Drizzle Kit +test('add schema #1', async () => { + const to = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(0); +}); + +test('add schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('delete schema #1', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, {}, []); + + expect(statements.length).toBe(0); +}); + +test('delete schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('rename schema #1', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + const to = { + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev->dev2']); + + expect(statements.length).toBe(0); +}); + +test('rename schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + devSchema1: singlestoreSchema('dev1'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #1', async () => { + const dev = singlestoreSchema('dev'); + const from = {}; + const to = { + dev, + users: dev.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #2', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev }; + const to = { + dev, + users: dev.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #3', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev }; + const to = { + dev, + usersInDev: dev.table('users', {}), + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePkName: '', + compositePKs: [], + }); +}); + +test('remove table from schema #1', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev, users: dev.table('users', {}) }; + const to = { + dev, + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('remove table from schema #2', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev, users: dev.table('users', {}) }; + const to = {}; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/singlestore-views.test.ts b/drizzle-kit/tests/singlestore-views.test.ts new file mode 100644 index 000000000..70add76fc --- /dev/null +++ b/drizzle-kit/tests/singlestore-views.test.ts @@ -0,0 +1,553 @@ +import { sql } from 'drizzle-orm'; +import { int, singlestoreTable, singlestoreView } from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +test('create view #1', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: singlestoreView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'singlestore_create_view', + name: 'some_view', + algorithm: 'undefined', + replace: false, + definition: 'select `id` from `users`', + withCheckOption: undefined, + sqlSecurity: 'definer', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE ALGORITHM = undefined +SQL SECURITY definer +VIEW \`some_view\` AS (select \`id\` from \`users\`);`); +}); + +test('create view #2', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'singlestore_create_view', + name: 'some_view', + algorithm: 'merge', + replace: false, + definition: 'SELECT * FROM \`users\`', + withCheckOption: 'cascaded', + sqlSecurity: 'definer', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS (SELECT * FROM \`users\`) +WITH cascaded CHECK OPTION;`); +}); + +test('create view with existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop view', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP VIEW \`some_view\`;`); +}); + +test('drop view with existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); +}); + +test('rename view and alter meta options', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'undefined', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'new_some_view', + sqlSecurity: 'definer', + type: 'alter_singlestore_view', + withCheckOption: 'cascaded', + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`ALTER ALGORITHM = undefined +SQL SECURITY definer +VIEW \`new_some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('rename view with existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('add meta to view', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'merge', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_singlestore_view', + withCheckOption: 'cascaded', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('add meta to view with existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).existing(), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter meta to view', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'merge', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_singlestore_view', + withCheckOption: 'cascaded', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('alter meta to view with existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop meta from view', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'undefined', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_singlestore_view', + withCheckOption: undefined, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = undefined +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\`;`); +}); + +test('drop meta from view existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter view ".as" value', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'some_view', + sqlSecurity: 'invoker', + type: 'singlestore_create_view', + withCheckOption: 'cascaded', + replace: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE OR REPLACE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); + +test('rename and alter view ".as" value', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + nameFrom: 'some_view', + nameTo: 'new_some_view', + type: 'rename_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'new_some_view', + sqlSecurity: 'invoker', + type: 'singlestore_create_view', + withCheckOption: 'cascaded', + replace: true, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`CREATE OR REPLACE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`new_some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); + +test('set existing', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop existing', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'new_some_view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'new_some_view', + sqlSecurity: 'invoker', + type: 'singlestore_create_view', + withCheckOption: 'cascaded', + replace: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP VIEW \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`CREATE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`new_some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); diff --git a/drizzle-kit/tests/singlestore.test.ts b/drizzle-kit/tests/singlestore.test.ts new file mode 100644 index 000000000..63abf1755 --- /dev/null +++ b/drizzle-kit/tests/singlestore.test.ts @@ -0,0 +1,578 @@ +import { sql } from 'drizzle-orm'; +import { + index, + json, + primaryKey, + serial, + singlestoreSchema, + singlestoreTable, + text, + uniqueIndex, +} from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +test('add table #1', async () => { + const to = { + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + uniqueConstraints: [], + compositePkName: '', + }); +}); + +test('add table #2', async () => { + const to = { + users: singlestoreTable('users', { + id: serial('id').primaryKey(), + }), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [ + { + name: 'id', + notNull: true, + primaryKey: false, + type: 'serial', + autoincrement: true, + }, + ], + compositePKs: ['users_id;id'], + compositePkName: 'users_id', + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('add table #3', async () => { + const to = { + users: singlestoreTable( + 'users', + { + id: serial('id'), + }, + (t) => { + return { + pk: primaryKey({ + name: 'users_pk', + columns: [t.id], + }), + }; + }, + ), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [ + { + name: 'id', + notNull: true, + primaryKey: false, + type: 'serial', + autoincrement: true, + }, + ], + compositePKs: ['users_pk;id'], + uniqueConstraints: [], + compositePkName: 'users_pk', + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('add table #4', async () => { + const to = { + users: singlestoreTable('users', {}), + posts: singlestoreTable('posts', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_table', + tableName: 'posts', + schema: undefined, + columns: [], + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + uniqueConstraints: [], + compositePkName: '', + }); +}); + +test('add table #5', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + }; + + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('add table #6', async () => { + const from = { + users1: singlestoreTable('users1', {}), + }; + + const to = { + users2: singlestoreTable('users2', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users2', + schema: undefined, + columns: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'drop_table', + tableName: 'users1', + schema: undefined, + }); +}); + +test('add table #7', async () => { + const from = { + users1: singlestoreTable('users1', {}), + }; + + const to = { + users: singlestoreTable('users', {}), + users2: singlestoreTable('users2', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'public.users1->public.users2', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + compositePKs: [], + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'rename_table', + tableNameFrom: 'users1', + tableNameTo: 'users2', + fromSchema: undefined, + toSchema: undefined, + }); +}); + +test('add schema + table #1', async () => { + const schema = singlestoreSchema('folder'); + + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(0); +}); + +test('change schema with tables #1', async () => { + const schema = singlestoreSchema('folder'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema, + users: schema.table('users', {}), + }; + const to = { + schema2, + users: schema2.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder->folder2', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #1', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + users: singlestoreTable('users', {}), + }; + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'public.users->folder.users', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_table', + tableName: 'users', + schema: undefined, + }); +}); + +test('change table schema #2', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + users: schema.table('users', {}), + }; + const to = { + schema, + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder.users->public.users', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + uniqueConstraints: [], + compositePkName: '', + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('change table schema #3', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + schema2, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, + users: schema2.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #4', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, // add schema + users: schema2.table('users', {}), // move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #5', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, // remove schema + users: schema1.table('users', {}), + }; + const to = { + schema2, // add schema + users: schema2.table('users', {}), // move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #5', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + schema2, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, + users: schema2.table('users2', {}), // rename and move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users2', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #6', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + users: schema1.table('users', {}), + }; + const to = { + schema2, // rename schema + users: schema2.table('users2', {}), // rename table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1->folder2', + 'folder2.users->folder2.users2', + ]); + + expect(statements.length).toBe(0); +}); + +test('add table #10', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({}), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT ('{}')\n);\n", + ); +}); + +test('add table #11', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default([]), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT ('[]')\n);\n", + ); +}); + +test('add table #12', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default([1, 2, 3]), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT ('[1,2,3]')\n);\n", + ); +}); + +test('add table #13', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({ key: 'value' }), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + 'CREATE TABLE `table` (\n\t`json` json DEFAULT (\'{"key":"value"}\')\n);\n', + ); +}); + +test('add table #14', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({ + key: 'value', + arr: [1, 2, 3], + }), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + 'CREATE TABLE `table` (\n\t`json` json DEFAULT (\'{"key":"value","arr":[1,2,3]}\')\n);\n', + ); +}); + +// TODO: add bson type tests + +// TODO: add blob type tests + +// TODO: add uuid type tests + +// TODO: add guid type tests + +// TODO: add vector type tests + +// TODO: add geopoint type tests + +test('drop index', async () => { + const from = { + users: singlestoreTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + idx: index('name_idx').on(t.name), + }; + }, + ), + }; + + const to = { + users: singlestoreTable('table', { + name: text('name'), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe('DROP INDEX `name_idx` ON `table`;'); +}); + +test('add table with indexes', async () => { + const from = {}; + + const to = { + users: singlestoreTable( + 'users', + { + id: serial('id').primaryKey(), + name: text('name'), + email: text('email'), + }, + (t) => ({ + uniqueExpr: uniqueIndex('uniqueExpr').on(sql`(lower(${t.email}))`), + indexExpr: index('indexExpr').on(sql`(lower(${t.email}))`), + indexExprMultiple: index('indexExprMultiple').on( + sql`(lower(${t.email}))`, + sql`(lower(${t.email}))`, + ), + + uniqueCol: uniqueIndex('uniqueCol').on(t.email), + indexCol: index('indexCol').on(t.email), + indexColMultiple: index('indexColMultiple').on(t.email, t.email), + + indexColExpr: index('indexColExpr').on( + sql`(lower(${t.email}))`, + t.email, + ), + }), + ), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements).toStrictEqual([ + `CREATE TABLE \`users\` (\n\t\`id\` serial AUTO_INCREMENT NOT NULL,\n\t\`name\` text,\n\t\`email\` text,\n\tCONSTRAINT \`users_id\` PRIMARY KEY(\`id\`),\n\tCONSTRAINT \`uniqueExpr\` UNIQUE((lower(\`email\`))),\n\tCONSTRAINT \`uniqueCol\` UNIQUE(\`email\`) +); +`, + 'CREATE INDEX `indexExpr` ON `users` ((lower(`email`)));', + 'CREATE INDEX `indexExprMultiple` ON `users` ((lower(`email`)),(lower(`email`)));', + 'CREATE INDEX `indexCol` ON `users` (`email`);', + 'CREATE INDEX `indexColMultiple` ON `users` (`email`,`email`);', + 'CREATE INDEX `indexColExpr` ON `users` ((lower(`email`)),`email`);', + ]); +}); diff --git a/drizzle-kit/tests/testsinglestore.ts b/drizzle-kit/tests/testsinglestore.ts new file mode 100644 index 000000000..1dc97d9c3 --- /dev/null +++ b/drizzle-kit/tests/testsinglestore.ts @@ -0,0 +1,29 @@ +import { index, singlestoreTable, text } from 'drizzle-orm/singlestore-core'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +const from = { + users: singlestoreTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + idx: index('name_idx').on(t.name), + }; + }, + ), +}; + +const to = { + users: singlestoreTable('table', { + name: text('name'), + }), +}; + +diffTestSchemasSingleStore(from, to, []).then((res) => { + const { statements, sqlStatements } = res; + + console.log(statements); + console.log(sqlStatements); +}); diff --git a/drizzle-kit/tests/validations.test.ts b/drizzle-kit/tests/validations.test.ts index 82731ee25..8a64603bb 100644 --- a/drizzle-kit/tests/validations.test.ts +++ b/drizzle-kit/tests/validations.test.ts @@ -1,5 +1,6 @@ import { mysqlCredentials } from 'src/cli/validations/mysql'; import { postgresCredentials } from 'src/cli/validations/postgres'; +import { singlestoreCredentials } from 'src/cli/validations/singlestore'; import { sqliteCredentials } from 'src/cli/validations/sqlite'; import { expect, test } from 'vitest'; @@ -698,3 +699,171 @@ test('mysql #17', () => { }); }).toThrowError(); }); + +test('singlestore #1', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: 'database', + host: 'host', + }), + ).toStrictEqual({ + database: 'database', + host: 'host', + }); +}); + +test('singlestore #2', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: 'database', + host: 'host', + }), + ).toStrictEqual({ + database: 'database', + host: 'host', + }); +}); + +test('singlestore #3', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + port: 1234, + user: 'user', + password: 'password', + database: 'database', + ssl: 'require', + }), + ).toStrictEqual({ + host: 'host', + port: 1234, + user: 'user', + password: 'password', + database: 'database', + ssl: 'require', + }); +}); + +test('singlestore #4', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + database: 'database', + ssl: 'allow', + }), + ).toStrictEqual({ + host: 'host', + database: 'database', + ssl: 'allow', + }); +}); + +test('singlestore #5', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + database: 'database', + ssl: { + ca: 'ca', + cert: 'cert', + }, + }), + ).toStrictEqual({ + host: 'host', + database: 'database', + ssl: { + ca: 'ca', + cert: 'cert', + }, + }); +}); + +test('singlestore #6', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + }); + }).toThrowError(); +}); + +test('singlestore #7', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + url: undefined, + }); + }).toThrowError(); +}); + +test('singlestore #8', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + url: '', + }); + }).toThrowError(); +}); + +test('singlestore #9', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: '', + database: '', + }); + }).toThrowError(); +}); + +test('singlestore #10', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: '', + }); + }).toThrowError(); +}); + +test('singlestore #11', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: '', + }); + }).toThrowError(); +}); + +test('singlestore #12', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: ' ', + host: '', + }); + }).toThrowError(); +}); + +test('singlestore #13', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: '', + host: ' ', + }); + }).toThrowError(); +}); + +test('singlestore #14', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: ' ', + host: ' ', + port: '', + }); + }).toThrowError(); +}); diff --git a/drizzle-kit/tests/wrap-param.test.ts b/drizzle-kit/tests/wrap-param.test.ts index 542998bda..a27d27d45 100644 --- a/drizzle-kit/tests/wrap-param.test.ts +++ b/drizzle-kit/tests/wrap-param.test.ts @@ -7,6 +7,9 @@ test('wrapParam', () => { expect(wrapParam('url', 'mysql://user:password@localhost:3306/database', false, 'url')).toBe( ` [${chalk.green('✓')}] url: 'mysql://user:****@localhost:3306/database'`, ); + expect(wrapParam('url', 'singlestore://user:password@localhost:3306/database', false, 'url')).toBe( + ` [${chalk.green('✓')}] url: 'singlestore://user:****@localhost:3306/database'`, + ); expect(wrapParam('url', 'postgresql://user:password@localhost:5432/database', false, 'url')).toBe( ` [${chalk.green('✓')}] url: 'postgresql://user:****@localhost:5432/database'`, ); diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index fb7da9ef6..13d9d363f 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -2,6 +2,7 @@ import { entityKind } from '~/entity.ts'; import type { Column } from './column.ts'; import type { MySqlColumn } from './mysql-core/index.ts'; import type { ExtraConfigColumn, PgColumn, PgSequenceOptions } from './pg-core/index.ts'; +import type { SingleStoreColumn } from './singlestore-core/index.ts'; import type { SQL } from './sql/sql.ts'; import type { SQLiteColumn } from './sqlite-core/index.ts'; import type { Assume, Simplify } from './utils.ts'; @@ -17,7 +18,7 @@ export type ColumnDataType = | 'custom' | 'buffer'; -export type Dialect = 'pg' | 'mysql' | 'sqlite' | 'common'; +export type Dialect = 'pg' | 'mysql' | 'sqlite' | 'singlestore' | 'common'; export type GeneratedStorageMode = 'virtual' | 'stored'; @@ -307,7 +308,8 @@ export type BuildColumn< TTableName extends string, TBuilder extends ColumnBuilderBase, TDialect extends Dialect, -> = TDialect extends 'pg' ? PgColumn> +> = TDialect extends 'singlestore' ? SingleStoreColumn> + : TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : TDialect extends 'common' ? Column> @@ -349,7 +351,8 @@ export type BuildExtraConfigColumns< & {}; export type ChangeColumnTableName = - TDialect extends 'pg' ? PgColumn> + TDialect extends 'singlestore' ? SingleStoreColumn> + : TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : never; diff --git a/drizzle-orm/src/singlestore-core/alias.ts b/drizzle-orm/src/singlestore-core/alias.ts new file mode 100644 index 000000000..08e7ecc67 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/alias.ts @@ -0,0 +1,11 @@ +import { TableAliasProxyHandler } from '~/alias.ts'; +import type { BuildAliasTable } from './query-builders/select.types.ts'; +import type { SingleStoreTable } from './table.ts'; +import type { SingleStoreViewBase } from './view-base.ts'; + +export function alias( + table: TTable, + alias: TAlias, +): BuildAliasTable { + return new Proxy(table, new TableAliasProxyHandler(alias, false)) as any; +} diff --git a/drizzle-orm/src/singlestore-core/checks.ts b/drizzle-orm/src/singlestore-core/checks.ts new file mode 100644 index 000000000..29fdb7680 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/checks.ts @@ -0,0 +1,32 @@ +import { entityKind } from '~/entity.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { SingleStoreTable } from './table.ts'; + +export class CheckBuilder { + static readonly [entityKind]: string = 'SingleStoreCheckBuilder'; + + protected brand!: 'SingleStoreConstraintBuilder'; + + constructor(public name: string, public value: SQL) {} + + /** @internal */ + build(table: SingleStoreTable): Check { + return new Check(table, this); + } +} + +export class Check { + static readonly [entityKind]: string = 'SingleStoreCheck'; + + readonly name: string; + readonly value: SQL; + + constructor(public table: SingleStoreTable, builder: CheckBuilder) { + this.name = builder.name; + this.value = builder.value; + } +} + +export function check(name: string, value: SQL): CheckBuilder { + return new CheckBuilder(name, value); +} diff --git a/drizzle-orm/src/singlestore-core/columns/all.ts b/drizzle-orm/src/singlestore-core/columns/all.ts new file mode 100644 index 000000000..66d289e3f --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/all.ts @@ -0,0 +1,55 @@ +import { bigint } from './bigint.ts'; +import { binary } from './binary.ts'; +import { boolean } from './boolean.ts'; +import { char } from './char.ts'; +import { customType } from './custom.ts'; +import { date } from './date.ts'; +import { datetime } from './datetime.ts'; +import { decimal } from './decimal.ts'; +import { double } from './double.ts'; +import { singlestoreEnum } from './enum.ts'; +import { float } from './float.ts'; +import { int } from './int.ts'; +import { json } from './json.ts'; +import { mediumint } from './mediumint.ts'; +import { real } from './real.ts'; +import { serial } from './serial.ts'; +import { smallint } from './smallint.ts'; +import { text } from './text.ts'; +import { time } from './time.ts'; +import { timestamp } from './timestamp.ts'; +import { tinyint } from './tinyint.ts'; +import { varbinary } from './varbinary.ts'; +import { varchar } from './varchar.ts'; +import { year } from './year.ts'; + +export function getSingleStoreColumnBuilders() { + return { + bigint, + binary, + boolean, + char, + customType, + date, + datetime, + decimal, + double, + singlestoreEnum, + float, + int, + json, + mediumint, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, + }; +} + +export type SingleStoreColumnBuilders = ReturnType; diff --git a/drizzle-orm/src/singlestore-core/columns/bigint.ts b/drizzle-orm/src/singlestore-core/columns/bigint.ts new file mode 100644 index 000000000..1e6b64c49 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/bigint.ts @@ -0,0 +1,120 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreBigInt53BuilderInitial = SingleStoreBigInt53Builder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreBigInt53'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBigInt53Builder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt53Builder'; + + constructor(name: T['name'], unsigned: boolean = false) { + super(name, 'number', 'SingleStoreBigInt53'); + this.config.unsigned = unsigned; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBigInt53> { + return new SingleStoreBigInt53>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBigInt53> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt53'; + + getSQLType(): string { + return `bigint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'number') { + return value; + } + return Number(value); + } +} + +export type SingleStoreBigInt64BuilderInitial = SingleStoreBigInt64Builder<{ + name: TName; + dataType: 'bigint'; + columnType: 'SingleStoreBigInt64'; + data: bigint; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBigInt64Builder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt64Builder'; + + constructor(name: T['name'], unsigned: boolean = false) { + super(name, 'bigint', 'SingleStoreBigInt64'); + this.config.unsigned = unsigned; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBigInt64> { + return new SingleStoreBigInt64>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBigInt64> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt64'; + + getSQLType(): string { + return `bigint${this.config.unsigned ? ' unsigned' : ''}`; + } + + // eslint-disable-next-line unicorn/prefer-native-coercion-functions + override mapFromDriverValue(value: string): bigint { + return BigInt(value); + } +} + +export interface SingleStoreBigIntConfig { + mode: T; + unsigned?: boolean; +} + +export function bigint( + config: SingleStoreBigIntConfig, +): TMode extends 'number' ? SingleStoreBigInt53BuilderInitial<''> : SingleStoreBigInt64BuilderInitial<''>; +export function bigint( + name: TName, + config: SingleStoreBigIntConfig, +): TMode extends 'number' ? SingleStoreBigInt53BuilderInitial : SingleStoreBigInt64BuilderInitial; +export function bigint(a?: string | SingleStoreBigIntConfig, b?: SingleStoreBigIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config.mode === 'number') { + return new SingleStoreBigInt53Builder(name, config.unsigned); + } + return new SingleStoreBigInt64Builder(name, config.unsigned); +} diff --git a/drizzle-orm/src/singlestore-core/columns/binary.ts b/drizzle-orm/src/singlestore-core/columns/binary.ts new file mode 100644 index 000000000..153456447 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/binary.ts @@ -0,0 +1,70 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreBinaryBuilderInitial = SingleStoreBinaryBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreBinary'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBinaryBuilder> + extends SingleStoreColumnBuilder< + T, + SingleStoreBinaryConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreBinaryBuilder'; + + constructor(name: T['name'], length: number | undefined) { + super(name, 'string', 'SingleStoreBinary'); + this.config.length = length; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBinary> { + return new SingleStoreBinary>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBinary> extends SingleStoreColumn< + T, + SingleStoreBinaryConfig +> { + static override readonly [entityKind]: string = 'SingleStoreBinary'; + + length: number | undefined = this.config.length; + + getSQLType(): string { + return this.length === undefined ? `binary` : `binary(${this.length})`; + } +} + +export interface SingleStoreBinaryConfig { + length?: number; +} + +export function binary(): SingleStoreBinaryBuilderInitial<''>; +export function binary( + config?: SingleStoreBinaryConfig, +): SingleStoreBinaryBuilderInitial<''>; +export function binary( + name: TName, + config?: SingleStoreBinaryConfig, +): SingleStoreBinaryBuilderInitial; +export function binary(a?: string | SingleStoreBinaryConfig, b: SingleStoreBinaryConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreBinaryBuilder(name, config.length); +} diff --git a/drizzle-orm/src/singlestore-core/columns/boolean.ts b/drizzle-orm/src/singlestore-core/columns/boolean.ts new file mode 100644 index 000000000..bf48ff1da --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/boolean.ts @@ -0,0 +1,58 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreBooleanBuilderInitial = SingleStoreBooleanBuilder<{ + name: TName; + dataType: 'boolean'; + columnType: 'SingleStoreBoolean'; + data: boolean; + driverParam: number | boolean; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBooleanBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreBooleanBuilder'; + + constructor(name: T['name']) { + super(name, 'boolean', 'SingleStoreBoolean'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBoolean> { + return new SingleStoreBoolean>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBoolean> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreBoolean'; + + getSQLType(): string { + return 'boolean'; + } + + override mapFromDriverValue(value: number | boolean): boolean { + if (typeof value === 'boolean') { + return value; + } + return value === 1; + } +} + +export function boolean(): SingleStoreBooleanBuilderInitial<''>; +export function boolean(name: TName): SingleStoreBooleanBuilderInitial; +export function boolean(name?: string) { + return new SingleStoreBooleanBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/char.ts b/drizzle-orm/src/singlestore-core/columns/char.ts new file mode 100644 index 000000000..512460f92 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/char.ts @@ -0,0 +1,75 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreCharBuilderInitial = + SingleStoreCharBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; + }>; + +export class SingleStoreCharBuilder> + extends SingleStoreColumnBuilder< + T, + SingleStoreCharConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreCharBuilder'; + + constructor(name: T['name'], config: SingleStoreCharConfig) { + super(name, 'string', 'SingleStoreChar'); + this.config.length = config.length; + this.config.enum = config.enum; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreChar & { enumValues: T['enumValues'] }> { + return new SingleStoreChar & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreChar> + extends SingleStoreColumn> +{ + static override readonly [entityKind]: string = 'SingleStoreChar'; + + readonly length: number | undefined = this.config.length; + override readonly enumValues = this.config.enum; + + getSQLType(): string { + return this.length === undefined ? `char` : `char(${this.length})`; + } +} + +export interface SingleStoreCharConfig< + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, +> { + length?: number; + enum?: TEnum; +} + +export function char(): SingleStoreCharBuilderInitial<'', [string, ...string[]]>; +export function char>( + config?: SingleStoreCharConfig>, +): SingleStoreCharBuilderInitial<'', Writable>; +export function char>( + name: TName, + config?: SingleStoreCharConfig>, +): SingleStoreCharBuilderInitial>; +export function char(a?: string | SingleStoreCharConfig, b: SingleStoreCharConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreCharBuilder(name, config as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts new file mode 100644 index 000000000..63a6dbf29 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -0,0 +1,116 @@ +import { ColumnBuilder } from '~/column-builder.ts'; +import type { + ColumnBuilderBase, + ColumnBuilderBaseConfig, + ColumnBuilderExtraConfig, + ColumnBuilderRuntimeConfig, + ColumnDataType, + HasDefault, + HasGenerated, + IsAutoincrement, + MakeColumnConfig, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { Column } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable, SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { Update } from '~/utils.ts'; +import { uniqueKeyName } from '../unique-constraint.ts'; + +export interface SingleStoreColumnBuilderBase< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, + TTypeConfig extends object = object, +> extends ColumnBuilderBase {} + +export interface SingleStoreGeneratedColumnConfig { + mode?: 'virtual' | 'stored'; +} + +export abstract class SingleStoreColumnBuilder< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig & { + data: any; + }, + TRuntimeConfig extends object = object, + TTypeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends ColumnBuilder + implements SingleStoreColumnBuilderBase +{ + static override readonly [entityKind]: string = 'SingleStoreColumnBuilder'; + + unique(name?: string): this { + this.config.isUnique = true; + this.config.uniqueName = name; + return this; + } + + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SingleStoreGeneratedColumnConfig): HasGenerated { + this.config.generated = { + as, + type: 'always', + mode: config?.mode ?? 'virtual', + }; + return this as any; + } + + /** @internal */ + abstract build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreColumn>; +} + +// To understand how to use `SingleStoreColumn` and `AnySingleStoreColumn`, see `Column` and `AnyColumn` documentation. +export abstract class SingleStoreColumn< + T extends ColumnBaseConfig = ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends Column { + static override readonly [entityKind]: string = 'SingleStoreColumn'; + + constructor( + override readonly table: SingleStoreTable, + config: ColumnBuilderRuntimeConfig, + ) { + if (!config.uniqueName) { + config.uniqueName = uniqueKeyName(table, [config.name]); + } + super(table, config); + } +} + +export type AnySingleStoreColumn> = {}> = + SingleStoreColumn< + Required, TPartial>> + >; + +export interface SingleStoreColumnWithAutoIncrementConfig { + autoIncrement: boolean; +} + +export abstract class SingleStoreColumnBuilderWithAutoIncrement< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, + TRuntimeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends SingleStoreColumnBuilder { + static override readonly [entityKind]: string = 'SingleStoreColumnBuilderWithAutoIncrement'; + + constructor(name: NonNullable, dataType: T['dataType'], columnType: T['columnType']) { + super(name, dataType, columnType); + this.config.autoIncrement = false; + } + + autoincrement(): IsAutoincrement> { + this.config.autoIncrement = true; + this.config.hasDefault = true; + return this as IsAutoincrement>; + } +} + +export abstract class SingleStoreColumnWithAutoIncrement< + T extends ColumnBaseConfig = ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreColumnWithAutoIncrement'; + + readonly autoIncrement: boolean = this.config.autoIncrement; +} diff --git a/drizzle-orm/src/singlestore-core/columns/custom.ts b/drizzle-orm/src/singlestore-core/columns/custom.ts new file mode 100644 index 000000000..964e077d7 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/custom.ts @@ -0,0 +1,235 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/sql.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type ConvertCustomConfig> = + & { + name: TName; + dataType: 'custom'; + columnType: 'SingleStoreCustomColumn'; + data: T['data']; + driverParam: T['driverData']; + enumValues: undefined; + generated: undefined; + } + & (T['notNull'] extends true ? { notNull: true } : {}) + & (T['default'] extends true ? { hasDefault: true } : {}); + +export interface SingleStoreCustomColumnInnerConfig { + customTypeValues: CustomTypeValues; +} + +export class SingleStoreCustomColumnBuilder> + extends SingleStoreColumnBuilder< + T, + { + fieldConfig: CustomTypeValues['config']; + customTypeParams: CustomTypeParams; + }, + { + singlestoreColumnBuilderBrand: 'SingleStoreCustomColumnBuilderBrand'; + } + > +{ + static override readonly [entityKind]: string = 'SingleStoreCustomColumnBuilder'; + + constructor( + name: T['name'], + fieldConfig: CustomTypeValues['config'], + customTypeParams: CustomTypeParams, + ) { + super(name, 'custom', 'SingleStoreCustomColumn'); + this.config.fieldConfig = fieldConfig; + this.config.customTypeParams = customTypeParams; + } + + /** @internal */ + build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreCustomColumn> { + return new SingleStoreCustomColumn>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreCustomColumn> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreCustomColumn'; + + private sqlName: string; + private mapTo?: (value: T['data']) => T['driverParam']; + private mapFrom?: (value: T['driverParam']) => T['data']; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreCustomColumnBuilder['config'], + ) { + super(table, config); + this.sqlName = config.customTypeParams.dataType(config.fieldConfig); + this.mapTo = config.customTypeParams.toDriver; + this.mapFrom = config.customTypeParams.fromDriver; + } + + getSQLType(): string { + return this.sqlName; + } + + override mapFromDriverValue(value: T['driverParam']): T['data'] { + return typeof this.mapFrom === 'function' ? this.mapFrom(value) : value as T['data']; + } + + override mapToDriverValue(value: T['data']): T['driverParam'] { + return typeof this.mapTo === 'function' ? this.mapTo(value) : value as T['data']; + } +} + +export type CustomTypeValues = { + /** + * Required type for custom column, that will infer proper type model + * + * Examples: + * + * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar` + * + * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer` + */ + data: unknown; + + /** + * Type helper, that represents what type database driver is accepting for specific database data type + */ + driverData?: unknown; + + /** + * What config type should be used for {@link CustomTypeParams} `dataType` generation + */ + config?: Record; + + /** + * Whether the config argument should be required or not + * @default false + */ + configRequired?: boolean; + + /** + * If your custom data type should be notNull by default you can use `notNull: true` + * + * @example + * const customSerial = customType<{ data: number, notNull: true, default: true }>({ + * dataType() { + * return 'serial'; + * }, + * }); + */ + notNull?: boolean; + + /** + * If your custom data type has default you can use `default: true` + * + * @example + * const customSerial = customType<{ data: number, notNull: true, default: true }>({ + * dataType() { + * return 'serial'; + * }, + * }); + */ + default?: boolean; +}; + +export interface CustomTypeParams { + /** + * Database data type string representation, that is used for migrations + * @example + * ``` + * `jsonb`, `text` + * ``` + * + * If database data type needs additional params you can use them from `config` param + * @example + * ``` + * `varchar(256)`, `numeric(2,3)` + * ``` + * + * To make `config` be of specific type please use config generic in {@link CustomTypeValues} + * + * @example + * Usage example + * ``` + * dataType() { + * return 'boolean'; + * }, + * ``` + * Or + * ``` + * dataType(config) { + * return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`; + * } + * ``` + */ + dataType: (config: T['config'] | (Equal extends true ? never : undefined)) => string; + + /** + * Optional mapping function, between user input and driver + * @example + * For example, when using jsonb we need to map JS/TS object to string before writing to database + * ``` + * toDriver(value: TData): string { + * return JSON.stringify(value); + * } + * ``` + */ + toDriver?: (value: T['data']) => T['driverData'] | SQL; + + /** + * Optional mapping function, that is responsible for data mapping from database to JS/TS code + * @example + * For example, when using timestamp we need to map string Date representation to JS Date + * ``` + * fromDriver(value: string): Date { + * return new Date(value); + * }, + * ``` + */ + fromDriver?: (value: T['driverData']) => T['data']; +} + +/** + * Custom singlestore database data type generator + */ +export function customType( + customTypeParams: CustomTypeParams, +): Equal extends true ? { + & T['config']>( + fieldConfig: TConfig, + ): SingleStoreCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig: T['config'], + ): SingleStoreCustomColumnBuilder>; + } + : { + (): SingleStoreCustomColumnBuilder>; + & T['config']>( + fieldConfig?: TConfig, + ): SingleStoreCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig?: T['config'], + ): SingleStoreCustomColumnBuilder>; + } +{ + return ( + a?: TName | T['config'], + b?: T['config'], + ): SingleStoreCustomColumnBuilder> => { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreCustomColumnBuilder(name as ConvertCustomConfig['name'], config, customTypeParams); + }; +} diff --git a/drizzle-orm/src/singlestore-core/columns/date.common.ts b/drizzle-orm/src/singlestore-core/columns/date.common.ts new file mode 100644 index 000000000..8afac71d0 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/date.common.ts @@ -0,0 +1,41 @@ +import type { + ColumnBuilderBaseConfig, + ColumnBuilderExtraConfig, + ColumnDataType, + HasDefault, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import { sql } from '~/sql/sql.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export interface SingleStoreDateColumnBaseConfig { + hasOnUpdateNow: boolean; +} + +export abstract class SingleStoreDateColumnBaseBuilder< + T extends ColumnBuilderBaseConfig, + TRuntimeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends SingleStoreColumnBuilder { + static override readonly [entityKind]: string = 'SingleStoreDateColumnBuilder'; + + defaultNow() { + return this.default(sql`(now())`); + } + + onUpdateNow(): HasDefault { + this.config.hasOnUpdateNow = true; + this.config.hasDefault = true; + return this as HasDefault; + } +} + +export abstract class SingleStoreDateBaseColumn< + T extends ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreDateColumn'; + + readonly hasOnUpdateNow: boolean = this.config.hasOnUpdateNow; +} diff --git a/drizzle-orm/src/singlestore-core/columns/date.ts b/drizzle-orm/src/singlestore-core/columns/date.ts new file mode 100644 index 000000000..70da74f3a --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/date.ts @@ -0,0 +1,123 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreDateBuilderInitial = SingleStoreDateBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'SingleStoreDate'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreDateBuilder'; + + constructor(name: T['name']) { + super(name, 'date', 'SingleStoreDate'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDate> { + return new SingleStoreDate>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDate> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreDate'; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return `date`; + } + + override mapFromDriverValue(value: string): Date { + return new Date(value); + } +} + +export type SingleStoreDateStringBuilderInitial = SingleStoreDateStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreDateString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateStringBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreDateStringBuilder'; + + constructor(name: T['name']) { + super(name, 'string', 'SingleStoreDateString'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateString> { + return new SingleStoreDateString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDateString> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreDateString'; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateStringBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return `date`; + } +} + +export interface SingleStoreDateConfig { + mode?: TMode; +} + +export function date(): SingleStoreDateBuilderInitial<''>; +export function date( + config?: SingleStoreDateConfig, +): Equal extends true ? SingleStoreDateStringBuilderInitial<''> : SingleStoreDateBuilderInitial<''>; +export function date( + name: TName, + config?: SingleStoreDateConfig, +): Equal extends true ? SingleStoreDateStringBuilderInitial + : SingleStoreDateBuilderInitial; +export function date(a?: string | SingleStoreDateConfig, b?: SingleStoreDateConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config?.mode === 'string') { + return new SingleStoreDateStringBuilder(name); + } + return new SingleStoreDateBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts new file mode 100644 index 000000000..aaaa11708 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -0,0 +1,143 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreDateTimeBuilderInitial = SingleStoreDateTimeBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'SingleStoreDateTime'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateTimeBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreDateTimeBuilder'; + + constructor(name: T['name'], config: SingleStoreDatetimeConfig | undefined) { + super(name, 'date', 'SingleStoreDateTime'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateTime> { + return new SingleStoreDateTime>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDateTime> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreDateTime'; + + readonly fsp: number | undefined; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateTimeBuilder['config'], + ) { + super(table, config); + this.fsp = config.fsp; + } + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `datetime${precision}`; + } + + override mapToDriverValue(value: Date): unknown { + return value.toISOString().replace('T', ' ').replace('Z', ''); + } + + override mapFromDriverValue(value: string): Date { + return new Date(value.replace(' ', 'T') + 'Z'); + } +} + +export type SingleStoreDateTimeStringBuilderInitial = SingleStoreDateTimeStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreDateTimeString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateTimeStringBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreDateTimeStringBuilder'; + + constructor(name: T['name'], config: SingleStoreDatetimeConfig | undefined) { + super(name, 'string', 'SingleStoreDateTimeString'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateTimeString> { + return new SingleStoreDateTimeString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDateTimeString> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreDateTimeString'; + + readonly fsp: number | undefined; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateTimeStringBuilder['config'], + ) { + super(table, config); + this.fsp = config.fsp; + } + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `datetime${precision}`; + } +} + +export type DatetimeFsp = 0 | 1 | 2 | 3 | 4 | 5 | 6; + +export interface SingleStoreDatetimeConfig { + mode?: TMode; + fsp?: DatetimeFsp; +} + +export function datetime(): SingleStoreDateTimeBuilderInitial<''>; +export function datetime( + config?: SingleStoreDatetimeConfig, +): Equal extends true ? SingleStoreDateTimeStringBuilderInitial<''> + : SingleStoreDateTimeBuilderInitial<''>; +export function datetime( + name: TName, + config?: SingleStoreDatetimeConfig, +): Equal extends true ? SingleStoreDateTimeStringBuilderInitial + : SingleStoreDateTimeBuilderInitial; +export function datetime(a?: string | SingleStoreDatetimeConfig, b?: SingleStoreDatetimeConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config?.mode === 'string') { + return new SingleStoreDateTimeStringBuilder(name, config); + } + return new SingleStoreDateTimeBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts new file mode 100644 index 000000000..112ca86ee --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -0,0 +1,75 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreDecimalBuilderInitial = SingleStoreDecimalBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreDecimal'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDecimalBuilder< + T extends ColumnBuilderBaseConfig<'string', 'SingleStoreDecimal'>, +> extends SingleStoreColumnBuilderWithAutoIncrement { + static override readonly [entityKind]: string = 'SingleStoreDecimalBuilder'; + + constructor(name: T['name'], precision?: number, scale?: number) { + super(name, 'string', 'SingleStoreDecimal'); + this.config.precision = precision; + this.config.scale = scale; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDecimal> { + return new SingleStoreDecimal>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDecimal> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreDecimal'; + + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + + getSQLType(): string { + if (this.precision !== undefined && this.scale !== undefined) { + return `decimal(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + return 'decimal'; + } else { + return `decimal(${this.precision})`; + } + } +} + +export interface SingleStoreDecimalConfig { + precision?: number; + scale?: number; +} + +export function decimal(): SingleStoreDecimalBuilderInitial<''>; +export function decimal( + config: SingleStoreDecimalConfig, +): SingleStoreDecimalBuilderInitial<''>; +export function decimal( + name: TName, + config?: SingleStoreDecimalConfig, +): SingleStoreDecimalBuilderInitial; +export function decimal(a?: string | SingleStoreDecimalConfig, b: SingleStoreDecimalConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreDecimalBuilder(name, config.precision, config.scale); +} diff --git a/drizzle-orm/src/singlestore-core/columns/double.ts b/drizzle-orm/src/singlestore-core/columns/double.ts new file mode 100644 index 000000000..6335b5937 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/double.ts @@ -0,0 +1,75 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreDoubleBuilderInitial = SingleStoreDoubleBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreDouble'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDoubleBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreDoubleBuilder'; + + constructor(name: T['name'], config: SingleStoreDoubleConfig | undefined) { + super(name, 'number', 'SingleStoreDouble'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDouble> { + return new SingleStoreDouble>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDouble> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreDouble'; + + precision: number | undefined = this.config.precision; + scale: number | undefined = this.config.scale; + + getSQLType(): string { + if (this.precision !== undefined && this.scale !== undefined) { + return `double(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + return 'double'; + } else { + return `double(${this.precision})`; + } + } +} + +export interface SingleStoreDoubleConfig { + precision?: number; + scale?: number; +} + +export function double(): SingleStoreDoubleBuilderInitial<''>; +export function double( + config?: SingleStoreDoubleConfig, +): SingleStoreDoubleBuilderInitial<''>; +export function double( + name: TName, + config?: SingleStoreDoubleConfig, +): SingleStoreDoubleBuilderInitial; +export function double(a?: string | SingleStoreDoubleConfig, b?: SingleStoreDoubleConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreDoubleBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/enum.ts b/drizzle-orm/src/singlestore-core/columns/enum.ts new file mode 100644 index 000000000..00b61393e --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/enum.ts @@ -0,0 +1,70 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreEnumColumnBuilderInitial = + SingleStoreEnumColumnBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreEnumColumn'; + data: TEnum[number]; + driverParam: string; + enumValues: TEnum; + generated: undefined; + }>; + +export class SingleStoreEnumColumnBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreEnumColumnBuilder'; + + constructor(name: T['name'], values: T['enumValues']) { + super(name, 'string', 'SingleStoreEnumColumn'); + this.config.enumValues = values; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreEnumColumn & { enumValues: T['enumValues'] }> { + return new SingleStoreEnumColumn & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreEnumColumn> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreEnumColumn'; + + override readonly enumValues = this.config.enumValues; + + getSQLType(): string { + return `enum(${this.enumValues!.map((value) => `'${value}'`).join(',')})`; + } +} + +export function singlestoreEnum>( + values: T | Writable, +): SingleStoreEnumColumnBuilderInitial<'', Writable>; +export function singlestoreEnum>( + name: TName, + values: T | Writable, +): SingleStoreEnumColumnBuilderInitial>; +export function singlestoreEnum( + a?: string | readonly [string, ...string[]] | [string, ...string[]], + b?: readonly [string, ...string[]] | [string, ...string[]], +): any { + const { name, config: values } = getColumnNameAndConfig(a, b); + + if (values.length === 0) { + throw new Error(`You have an empty array for "${name}" enum values`); + } + + return new SingleStoreEnumColumnBuilder(name, values as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts new file mode 100644 index 000000000..07a685170 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -0,0 +1,51 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreFloatBuilderInitial = SingleStoreFloatBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreFloat'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreFloatBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreFloatBuilder'; + + constructor(name: T['name']) { + super(name, 'number', 'SingleStoreFloat'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreFloat> { + return new SingleStoreFloat>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreFloat> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreFloat'; + + getSQLType(): string { + return 'float'; + } +} + +export function float(): SingleStoreFloatBuilderInitial<''>; +export function float(name: TName): SingleStoreFloatBuilderInitial; +export function float(name?: string) { + return new SingleStoreFloatBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/index.ts b/drizzle-orm/src/singlestore-core/columns/index.ts new file mode 100644 index 000000000..b51f0fac4 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/index.ts @@ -0,0 +1,25 @@ +export * from './bigint.ts'; +export * from './binary.ts'; +export * from './boolean.ts'; +export * from './char.ts'; +export * from './common.ts'; +export * from './custom.ts'; +export * from './date.ts'; +export * from './datetime.ts'; +export * from './decimal.ts'; +export * from './double.ts'; +export * from './enum.ts'; +export * from './float.ts'; +export * from './int.ts'; +export * from './json.ts'; +export * from './mediumint.ts'; +export * from './real.ts'; +export * from './serial.ts'; +export * from './smallint.ts'; +export * from './text.ts'; +export * from './time.ts'; +export * from './timestamp.ts'; +export * from './tinyint.ts'; +export * from './varbinary.ts'; +export * from './varchar.ts'; +export * from './year.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/int.ts b/drizzle-orm/src/singlestore-core/columns/int.ts new file mode 100644 index 000000000..b6a661f66 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/int.ts @@ -0,0 +1,71 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreIntBuilderInitial = SingleStoreIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreInt> { + return new SingleStoreInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreInt'; + + getSQLType(): string { + return `int${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export interface SingleStoreIntConfig { + unsigned?: boolean; +} + +export function int(): SingleStoreIntBuilderInitial<''>; +export function int( + config?: SingleStoreIntConfig, +): SingleStoreIntBuilderInitial<''>; +export function int( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreIntBuilderInitial; +export function int(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/json.ts b/drizzle-orm/src/singlestore-core/columns/json.ts new file mode 100644 index 000000000..97ff759d1 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/json.ts @@ -0,0 +1,53 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreJsonBuilderInitial = SingleStoreJsonBuilder<{ + name: TName; + dataType: 'json'; + columnType: 'SingleStoreJson'; + data: unknown; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreJsonBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreJsonBuilder'; + + constructor(name: T['name']) { + super(name, 'json', 'SingleStoreJson'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreJson> { + return new SingleStoreJson>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreJson> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreJson'; + + getSQLType(): string { + return 'json'; + } + + override mapToDriverValue(value: T['data']): string { + return JSON.stringify(value); + } +} + +export function json(): SingleStoreJsonBuilderInitial<''>; +export function json(name: TName): SingleStoreJsonBuilderInitial; +export function json(name?: string) { + return new SingleStoreJsonBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/mediumint.ts b/drizzle-orm/src/singlestore-core/columns/mediumint.ts new file mode 100644 index 000000000..4a5fa80f9 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/mediumint.ts @@ -0,0 +1,68 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; + +export type SingleStoreMediumIntBuilderInitial = SingleStoreMediumIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreMediumInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreMediumIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreMediumIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreMediumInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreMediumInt> { + return new SingleStoreMediumInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreMediumInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreMediumInt'; + + getSQLType(): string { + return `mediumint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function mediumint(): SingleStoreMediumIntBuilderInitial<''>; +export function mediumint( + config?: SingleStoreIntConfig, +): SingleStoreMediumIntBuilderInitial<''>; +export function mediumint( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreMediumIntBuilderInitial; +export function mediumint(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreMediumIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/real.ts b/drizzle-orm/src/singlestore-core/columns/real.ts new file mode 100644 index 000000000..53d15345c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/real.ts @@ -0,0 +1,81 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreRealBuilderInitial = SingleStoreRealBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreReal'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreRealBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement< + T, + SingleStoreRealConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreRealBuilder'; + + constructor(name: T['name'], config: SingleStoreRealConfig | undefined) { + super(name, 'number', 'SingleStoreReal'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreReal> { + return new SingleStoreReal>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreReal> + extends SingleStoreColumnWithAutoIncrement< + T, + SingleStoreRealConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreReal'; + + precision: number | undefined = this.config.precision; + scale: number | undefined = this.config.scale; + + getSQLType(): string { + if (this.precision !== undefined && this.scale !== undefined) { + return `real(${this.precision}, ${this.scale})`; + } else if (this.precision === undefined) { + return 'real'; + } else { + return `real(${this.precision})`; + } + } +} + +export interface SingleStoreRealConfig { + precision?: number; + scale?: number; +} + +export function real(): SingleStoreRealBuilderInitial<''>; +export function real( + config?: SingleStoreRealConfig, +): SingleStoreRealBuilderInitial<''>; +export function real( + name: TName, + config?: SingleStoreRealConfig, +): SingleStoreRealBuilderInitial; +export function real(a?: string | SingleStoreRealConfig, b: SingleStoreRealConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreRealBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/serial.ts b/drizzle-orm/src/singlestore-core/columns/serial.ts new file mode 100644 index 000000000..df415d47e --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/serial.ts @@ -0,0 +1,76 @@ +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + HasDefault, + IsAutoincrement, + IsPrimaryKey, + MakeColumnConfig, + NotNull, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreSerialBuilderInitial = IsAutoincrement< + IsPrimaryKey< + NotNull< + HasDefault< + SingleStoreSerialBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + enumValues: undefined; + generated: undefined; + }> + > + > + > +>; + +export class SingleStoreSerialBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreSerialBuilder'; + + constructor(name: T['name']) { + super(name, 'number', 'SingleStoreSerial'); + this.config.hasDefault = true; + this.config.autoIncrement = true; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreSerial> { + return new SingleStoreSerial>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreSerial< + T extends ColumnBaseConfig<'number', 'SingleStoreSerial'>, +> extends SingleStoreColumnWithAutoIncrement { + static override readonly [entityKind]: string = 'SingleStoreSerial'; + + getSQLType(): string { + return 'serial'; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function serial(): SingleStoreSerialBuilderInitial<''>; +export function serial(name: TName): SingleStoreSerialBuilderInitial; +export function serial(name?: string) { + return new SingleStoreSerialBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/smallint.ts b/drizzle-orm/src/singlestore-core/columns/smallint.ts new file mode 100644 index 000000000..3f504b68c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/smallint.ts @@ -0,0 +1,68 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; + +export type SingleStoreSmallIntBuilderInitial = SingleStoreSmallIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreSmallInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreSmallIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreSmallIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreSmallInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreSmallInt> { + return new SingleStoreSmallInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreSmallInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreSmallInt'; + + getSQLType(): string { + return `smallint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function smallint(): SingleStoreSmallIntBuilderInitial<''>; +export function smallint( + config?: SingleStoreIntConfig, +): SingleStoreSmallIntBuilderInitial<''>; +export function smallint( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreSmallIntBuilderInitial; +export function smallint(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreSmallIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/text.ts b/drizzle-orm/src/singlestore-core/columns/text.ts new file mode 100644 index 000000000..425da550f --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/text.ts @@ -0,0 +1,116 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreTextColumnType = 'tinytext' | 'text' | 'mediumtext' | 'longtext'; + +export type SingleStoreTextBuilderInitial = + SingleStoreTextBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreText'; + data: TEnum[number]; + driverParam: string; + enumValues: TEnum; + generated: undefined; + }>; + +export class SingleStoreTextBuilder> + extends SingleStoreColumnBuilder< + T, + { textType: SingleStoreTextColumnType; enumValues: T['enumValues'] } + > +{ + static override readonly [entityKind]: string = 'SingleStoreTextBuilder'; + + constructor(name: T['name'], textType: SingleStoreTextColumnType, config: SingleStoreTextConfig) { + super(name, 'string', 'SingleStoreText'); + this.config.textType = textType; + this.config.enumValues = config.enum; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreText> { + return new SingleStoreText>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreText> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreText'; + + private textType: SingleStoreTextColumnType = this.config.textType; + + override readonly enumValues = this.config.enumValues; + + getSQLType(): string { + return this.textType; + } +} + +export interface SingleStoreTextConfig< + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, +> { + enum?: TEnum; +} + +export function text(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function text>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function text>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function text(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'text', config as any); +} + +export function tinytext(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function tinytext>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function tinytext>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function tinytext(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'tinytext', config as any); +} + +export function mediumtext(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function mediumtext>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function mediumtext>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function mediumtext(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'mediumtext', config as any); +} + +export function longtext(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function longtext>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function longtext>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function longtext(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'longtext', config as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/time.ts b/drizzle-orm/src/singlestore-core/columns/time.ts new file mode 100644 index 000000000..be43041a7 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/time.ts @@ -0,0 +1,73 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreTimeBuilderInitial = SingleStoreTimeBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreTime'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTimeBuilder> + extends SingleStoreColumnBuilder< + T, + TimeConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreTimeBuilder'; + + constructor( + name: T['name'], + config: TimeConfig | undefined, + ) { + super(name, 'string', 'SingleStoreTime'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTime> { + return new SingleStoreTime>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreTime< + T extends ColumnBaseConfig<'string', 'SingleStoreTime'>, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreTime'; + + readonly fsp: number | undefined = this.config.fsp; + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `time${precision}`; + } +} + +export type TimeConfig = { + fsp?: 0 | 1 | 2 | 3 | 4 | 5 | 6; +}; + +export function time(): SingleStoreTimeBuilderInitial<''>; +export function time( + config?: TimeConfig, +): SingleStoreTimeBuilderInitial<''>; +export function time( + name: TName, + config?: TimeConfig, +): SingleStoreTimeBuilderInitial; +export function time(a?: string | TimeConfig, b?: TimeConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTimeBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts new file mode 100644 index 000000000..747fb44bf --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -0,0 +1,127 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreDateBaseColumn, SingleStoreDateColumnBaseBuilder } from './date.common.ts'; + +export type SingleStoreTimestampBuilderInitial = SingleStoreTimestampBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'SingleStoreTimestamp'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTimestampBuilder> + extends SingleStoreDateColumnBaseBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreTimestampBuilder'; + + constructor(name: T['name'], config: SingleStoreTimestampConfig | undefined) { + super(name, 'date', 'SingleStoreTimestamp'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTimestamp> { + return new SingleStoreTimestamp>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreTimestamp> + extends SingleStoreDateBaseColumn +{ + static override readonly [entityKind]: string = 'SingleStoreTimestamp'; + + readonly fsp: number | undefined = this.config.fsp; + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `timestamp${precision}`; + } + + override mapFromDriverValue(value: string): Date { + return new Date(value + '+0000'); + } + + override mapToDriverValue(value: Date): string { + return value.toISOString().slice(0, -1).replace('T', ' '); + } +} + +export type SingleStoreTimestampStringBuilderInitial = SingleStoreTimestampStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreTimestampString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTimestampStringBuilder< + T extends ColumnBuilderBaseConfig<'string', 'SingleStoreTimestampString'>, +> extends SingleStoreDateColumnBaseBuilder { + static override readonly [entityKind]: string = 'SingleStoreTimestampStringBuilder'; + + constructor(name: T['name'], config: SingleStoreTimestampConfig | undefined) { + super(name, 'string', 'SingleStoreTimestampString'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTimestampString> { + return new SingleStoreTimestampString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreTimestampString> + extends SingleStoreDateBaseColumn +{ + static override readonly [entityKind]: string = 'SingleStoreTimestampString'; + + readonly fsp: number | undefined = this.config.fsp; + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `timestamp${precision}`; + } +} + +export type TimestampFsp = 0 | 1 | 2 | 3 | 4 | 5 | 6; + +export interface SingleStoreTimestampConfig { + mode?: TMode; + fsp?: TimestampFsp; +} + +export function timestamp(): SingleStoreTimestampBuilderInitial<''>; +export function timestamp( + config?: SingleStoreTimestampConfig, +): Equal extends true ? SingleStoreTimestampStringBuilderInitial<''> + : SingleStoreTimestampBuilderInitial<''>; +export function timestamp( + name: TName, + config?: SingleStoreTimestampConfig, +): Equal extends true ? SingleStoreTimestampStringBuilderInitial + : SingleStoreTimestampBuilderInitial; +export function timestamp(a?: string | SingleStoreTimestampConfig, b: SingleStoreTimestampConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config?.mode === 'string') { + return new SingleStoreTimestampStringBuilder(name, config); + } + return new SingleStoreTimestampBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/tinyint.ts b/drizzle-orm/src/singlestore-core/columns/tinyint.ts new file mode 100644 index 000000000..090619a6d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/tinyint.ts @@ -0,0 +1,68 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; + +export type SingleStoreTinyIntBuilderInitial = SingleStoreTinyIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreTinyInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTinyIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreTinyIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreTinyInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTinyInt> { + return new SingleStoreTinyInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreTinyInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreTinyInt'; + + getSQLType(): string { + return `tinyint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function tinyint(): SingleStoreTinyIntBuilderInitial<''>; +export function tinyint( + config?: SingleStoreIntConfig, +): SingleStoreTinyIntBuilderInitial<''>; +export function tinyint( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreTinyIntBuilderInitial; +export function tinyint(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTinyIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/varbinary.ts b/drizzle-orm/src/singlestore-core/columns/varbinary.ts new file mode 100644 index 000000000..c55aa8071 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/varbinary.ts @@ -0,0 +1,66 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreVarBinaryBuilderInitial = SingleStoreVarBinaryBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreVarBinary'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreVarBinaryBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreVarBinaryBuilder'; + + /** @internal */ + constructor(name: T['name'], config: SingleStoreVarbinaryOptions) { + super(name, 'string', 'SingleStoreVarBinary'); + this.config.length = config?.length; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreVarBinary> { + return new SingleStoreVarBinary>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreVarBinary< + T extends ColumnBaseConfig<'string', 'SingleStoreVarBinary'>, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreVarBinary'; + + length: number | undefined = this.config.length; + + getSQLType(): string { + return this.length === undefined ? `varbinary` : `varbinary(${this.length})`; + } +} + +export interface SingleStoreVarbinaryOptions { + length: number; +} + +export function varbinary( + config: SingleStoreVarbinaryOptions, +): SingleStoreVarBinaryBuilderInitial<''>; +export function varbinary( + name: TName, + config: SingleStoreVarbinaryOptions, +): SingleStoreVarBinaryBuilderInitial; +export function varbinary(a?: string | SingleStoreVarbinaryOptions, b?: SingleStoreVarbinaryOptions) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreVarBinaryBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/varchar.ts b/drizzle-orm/src/singlestore-core/columns/varchar.ts new file mode 100644 index 000000000..2c39491d7 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/varchar.ts @@ -0,0 +1,75 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreVarCharBuilderInitial = + SingleStoreVarCharBuilder< + { + name: TName; + dataType: 'string'; + columnType: 'SingleStoreVarChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; + } + >; + +export class SingleStoreVarCharBuilder> + extends SingleStoreColumnBuilder> +{ + static override readonly [entityKind]: string = 'SingleStoreVarCharBuilder'; + + /** @internal */ + constructor(name: T['name'], config: SingleStoreVarCharConfig) { + super(name, 'string', 'SingleStoreVarChar'); + this.config.length = config.length; + this.config.enum = config.enum; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreVarChar & { enumValues: T['enumValues'] }> { + return new SingleStoreVarChar & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreVarChar> + extends SingleStoreColumn> +{ + static override readonly [entityKind]: string = 'SingleStoreVarChar'; + + readonly length: number | undefined = this.config.length; + + override readonly enumValues = this.config.enum; + + getSQLType(): string { + return this.length === undefined ? `varchar` : `varchar(${this.length})`; + } +} + +export interface SingleStoreVarCharConfig< + TEnum extends string[] | readonly string[] | undefined = string[] | readonly string[] | undefined, +> { + length: number; + enum?: TEnum; +} + +export function varchar>( + config: SingleStoreVarCharConfig>, +): SingleStoreVarCharBuilderInitial<'', Writable>; +export function varchar>( + name: TName, + config: SingleStoreVarCharConfig>, +): SingleStoreVarCharBuilderInitial>; +export function varchar(a?: string | SingleStoreVarCharConfig, b?: SingleStoreVarCharConfig): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreVarCharBuilder(name, config as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/year.ts b/drizzle-orm/src/singlestore-core/columns/year.ts new file mode 100644 index 000000000..37f3d55a3 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/year.ts @@ -0,0 +1,51 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreYearBuilderInitial = SingleStoreYearBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreYear'; + data: number; + driverParam: number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreYearBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreYearBuilder'; + + constructor(name: T['name']) { + super(name, 'number', 'SingleStoreYear'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreYear> { + return new SingleStoreYear>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreYear< + T extends ColumnBaseConfig<'number', 'SingleStoreYear'>, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreYear'; + + getSQLType(): string { + return `year`; + } +} + +export function year(): SingleStoreYearBuilderInitial<''>; +export function year(name: TName): SingleStoreYearBuilderInitial; +export function year(name?: string) { + return new SingleStoreYearBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts new file mode 100644 index 000000000..63cf97da4 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -0,0 +1,566 @@ +import type { ResultSetHeader } from 'mysql2/promise'; +import { entityKind } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import { WithSubquery } from '~/subquery.ts'; +import type { DrizzleTypeError } from '~/utils.ts'; +import type { SingleStoreDialect } from './dialect.ts'; +import { SingleStoreAttachBase } from './query-builders/attach.ts'; +import { SingleStoreBranchBase } from './query-builders/branch.ts'; +import { SingleStoreCreateMilestoneBase } from './query-builders/createMilestone.ts'; +import { SingleStoreDetachBase } from './query-builders/detach.ts'; +import { SingleStoreDropMilestoneBase } from './query-builders/dropMilestone.ts'; +import { + QueryBuilder, + SingleStoreDeleteBase, + SingleStoreInsertBuilder, + SingleStoreSelectBuilder, + SingleStoreUpdateBuilder, +} from './query-builders/index.ts'; +import type { OptimizeTableArgument } from './query-builders/optimizeTable.ts'; +import { SingleStoreOptimizeTableBase } from './query-builders/optimizeTable.ts'; +import { RelationalQueryBuilder } from './query-builders/query.ts'; +import type { SelectedFields } from './query-builders/select.types.ts'; +import type { + PreparedQueryHKTBase, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, + SingleStoreTransaction, + SingleStoreTransactionConfig, +} from './session.ts'; +import type { WithSubqueryWithSelection } from './subquery.ts'; +import type { SingleStoreTable } from './table.ts'; + +export class SingleStoreDatabase< + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record = {}, + TSchema extends TablesRelationalConfig = ExtractTablesWithRelations, +> { + static readonly [entityKind]: string = 'SingleStoreDatabase'; + + declare readonly _: { + readonly schema: TSchema | undefined; + readonly fullSchema: TFullSchema; + readonly tableNamesMap: Record; + }; + + query: TFullSchema extends Record + ? DrizzleTypeError<'Seems like the schema generic is missing - did you forget to add it to your DB type?'> + : { + [K in keyof TSchema]: RelationalQueryBuilder; + }; + + constructor( + /** @internal */ + readonly dialect: SingleStoreDialect, + /** @internal */ + readonly session: SingleStoreSession, + schema: RelationalSchemaConfig | undefined, + ) { + this._ = schema + ? { + schema: schema.schema, + fullSchema: schema.fullSchema as TFullSchema, + tableNamesMap: schema.tableNamesMap, + } + : { + schema: undefined, + fullSchema: {} as TFullSchema, + tableNamesMap: {}, + }; + this.query = {} as typeof this['query']; + if (this._.schema) { + for (const [tableName, columns] of Object.entries(this._.schema)) { + (this.query as SingleStoreDatabase>['query'])[tableName] = + new RelationalQueryBuilder( + schema!.fullSchema, + this._.schema, + this._.tableNamesMap, + schema!.fullSchema[tableName] as SingleStoreTable, + columns, + dialect, + session, + ); + } + } + } + + /** + * Creates a subquery that defines a temporary named result set as a CTE. + * + * It is useful for breaking down complex queries into simpler parts and for reusing the result set in subsequent parts of the query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#with-clause} + * + * @param alias The alias for the subquery. + * + * Failure to provide an alias will result in a DrizzleTypeError, preventing the subquery from being referenced in other queries. + * + * @example + * + * ```ts + * // Create a subquery with alias 'sq' and use it in the select query + * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42))); + * + * const result = await db.with(sq).select().from(sq); + * ``` + * + * To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query, you need to add aliases to them: + * + * ```ts + * // Select an arbitrary SQL value as a field in a CTE and reference it in the main query + * const sq = db.$with('sq').as(db.select({ + * name: sql`upper(${users.name})`.as('name'), + * }) + * .from(users)); + * + * const result = await db.with(sq).select({ name: sq.name }).from(sq); + * ``` + */ + $with(alias: TAlias) { + return { + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): WithSubqueryWithSelection { + if (typeof qb === 'function') { + qb = qb(new QueryBuilder()); + } + + return new Proxy( + new WithSubquery(qb.getSQL(), qb.getSelectedFields() as SelectedFields, alias, true), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as WithSubqueryWithSelection; + }, + }; + } + + /** + * Incorporates a previously defined CTE (using `$with`) into the main query. + * + * This method allows the main query to reference a temporary named result set. + * + * See docs: {@link https://orm.drizzle.team/docs/select#with-clause} + * + * @param queries The CTEs to incorporate into the main query. + * + * @example + * + * ```ts + * // Define a subquery 'sq' as a CTE using $with + * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42))); + * + * // Incorporate the CTE 'sq' into the main query and select from it + * const result = await db.with(sq).select().from(sq); + * ``` + */ + with(...queries: WithSubquery[]) { + const self = this; + + /** + * Creates a select query. + * + * Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select} + * + * @param fields The selection object. + * + * @example + * + * ```ts + * // Select all columns and all rows from the 'cars' table + * const allCars: Car[] = await db.select().from(cars); + * + * // Select specific columns and all rows from the 'cars' table + * const carsIdsAndBrands: { id: number; brand: string }[] = await db.select({ + * id: cars.id, + * brand: cars.brand + * }) + * .from(cars); + * ``` + * + * Like in SQL, you can use arbitrary expressions as selection fields, not just table columns: + * + * ```ts + * // Select specific columns along with expression and all rows from the 'cars' table + * const carsIdsAndLowerNames: { id: number; lowerBrand: string }[] = await db.select({ + * id: cars.id, + * lowerBrand: sql`lower(${cars.brand})`, + * }) + * .from(cars); + * ``` + */ + function select(): SingleStoreSelectBuilder; + function select( + fields: TSelection, + ): SingleStoreSelectBuilder; + function select(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: self.session, + dialect: self.dialect, + withList: queries, + }); + } + + /** + * Adds `distinct` expression to the select query. + * + * Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select#distinct} + * + * @param fields The selection object. + * + * @example + * ```ts + * // Select all unique rows from the 'cars' table + * await db.selectDistinct() + * .from(cars) + * .orderBy(cars.id, cars.brand, cars.color); + * + * // Select all unique brands from the 'cars' table + * await db.selectDistinct({ brand: cars.brand }) + * .from(cars) + * .orderBy(cars.brand); + * ``` + */ + function selectDistinct(): SingleStoreSelectBuilder; + function selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + function selectDistinct( + fields?: SelectedFields, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: self.session, + dialect: self.dialect, + withList: queries, + distinct: true, + }); + } + + /** + * Creates an update query. + * + * Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated. + * + * Use `.set()` method to specify which values to update. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param table The table to update. + * + * @example + * + * ```ts + * // Update all rows in the 'cars' table + * await db.update(cars).set({ color: 'red' }); + * + * // Update rows with filters and conditions + * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW')); + * ``` + */ + function update( + table: TTable, + ): SingleStoreUpdateBuilder { + return new SingleStoreUpdateBuilder(table, self.session, self.dialect, queries); + } + + /** + * Creates a delete query. + * + * Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param table The table to delete from. + * + * @example + * + * ```ts + * // Delete all rows in the 'cars' table + * await db.delete(cars); + * + * // Delete rows with filters and conditions + * await db.delete(cars).where(eq(cars.color, 'green')); + * ``` + */ + function delete_( + table: TTable, + ): SingleStoreDeleteBase { + return new SingleStoreDeleteBase(table, self.session, self.dialect, queries); + } + + return { select, selectDistinct, update, delete: delete_ }; + } + + /** + * Creates a select query. + * + * Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select} + * + * @param fields The selection object. + * + * @example + * + * ```ts + * // Select all columns and all rows from the 'cars' table + * const allCars: Car[] = await db.select().from(cars); + * + * // Select specific columns and all rows from the 'cars' table + * const carsIdsAndBrands: { id: number; brand: string }[] = await db.select({ + * id: cars.id, + * brand: cars.brand + * }) + * .from(cars); + * ``` + * + * Like in SQL, you can use arbitrary expressions as selection fields, not just table columns: + * + * ```ts + * // Select specific columns along with expression and all rows from the 'cars' table + * const carsIdsAndLowerNames: { id: number; lowerBrand: string }[] = await db.select({ + * id: cars.id, + * lowerBrand: sql`lower(${cars.brand})`, + * }) + * .from(cars); + * ``` + */ + select(): SingleStoreSelectBuilder; + select( + fields: TSelection, + ): SingleStoreSelectBuilder; + select(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ fields: fields ?? undefined, session: this.session, dialect: this.dialect }); + } + + /** + * Adds `distinct` expression to the select query. + * + * Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select#distinct} + * + * @param fields The selection object. + * + * @example + * ```ts + * // Select all unique rows from the 'cars' table + * await db.selectDistinct() + * .from(cars) + * .orderBy(cars.id, cars.brand, cars.color); + * + * // Select all unique brands from the 'cars' table + * await db.selectDistinct({ brand: cars.brand }) + * .from(cars) + * .orderBy(cars.brand); + * ``` + */ + selectDistinct(): SingleStoreSelectBuilder; + selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + selectDistinct(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: this.session, + dialect: this.dialect, + distinct: true, + }); + } + + /** + * Creates an update query. + * + * Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated. + * + * Use `.set()` method to specify which values to update. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param table The table to update. + * + * @example + * + * ```ts + * // Update all rows in the 'cars' table + * await db.update(cars).set({ color: 'red' }); + * + * // Update rows with filters and conditions + * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW')); + * ``` + */ + update( + table: TTable, + ): SingleStoreUpdateBuilder { + return new SingleStoreUpdateBuilder(table, this.session, this.dialect); + } + + /** + * Creates an insert query. + * + * Calling this method will create new rows in a table. Use `.values()` method to specify which values to insert. + * + * See docs: {@link https://orm.drizzle.team/docs/insert} + * + * @param table The table to insert into. + * + * @example + * + * ```ts + * // Insert one row + * await db.insert(cars).values({ brand: 'BMW' }); + * + * // Insert multiple rows + * await db.insert(cars).values([{ brand: 'BMW' }, { brand: 'Porsche' }]); + * ``` + */ + insert( + table: TTable, + ): SingleStoreInsertBuilder { + return new SingleStoreInsertBuilder(table, this.session, this.dialect); + } + + /** + * Creates a delete query. + * + * Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param table The table to delete from. + * + * @example + * + * ```ts + * // Delete all rows in the 'cars' table + * await db.delete(cars); + * + * // Delete rows with filters and conditions + * await db.delete(cars).where(eq(cars.color, 'green')); + * ``` + */ + delete( + table: TTable, + ): SingleStoreDeleteBase { + return new SingleStoreDeleteBase(table, this.session, this.dialect); + } + + execute( + query: SQLWrapper, + ): Promise> { + return this.session.execute(query.getSQL()); + } + + transaction( + transaction: ( + tx: SingleStoreTransaction, + config?: SingleStoreTransactionConfig, + ) => Promise, + config?: SingleStoreTransactionConfig, + ): Promise { + return this.session.transaction(transaction, config); + } + + detach( + database: TDatabase, + ): SingleStoreDetachBase { + return new SingleStoreDetachBase(database, this.session, this.dialect); + } + + attach( + database: TDatabase, + ): SingleStoreAttachBase { + return new SingleStoreAttachBase(database, this.session, this.dialect); + } + + branch( + database: TDatabase, + branchName: string, + ): SingleStoreBranchBase { + return new SingleStoreBranchBase(database, branchName, this.session, this.dialect); + } + + createMilestone( + milestone: TMilestone, + ): SingleStoreCreateMilestoneBase { + return new SingleStoreCreateMilestoneBase(milestone, this.session, this.dialect); + } + + dropMilestone( + milestone: TMilestone, + ): SingleStoreDropMilestoneBase { + return new SingleStoreDropMilestoneBase(milestone, this.session, this.dialect); + } + + optimizeTable< + TTable extends SingleStoreTable, + TArg extends OptimizeTableArgument, + >( + table: TTable, + arg: TArg | undefined = undefined, + ): SingleStoreOptimizeTableBase { + return new SingleStoreOptimizeTableBase(table, arg, this.session, this.dialect); + } +} + +export type SingleStoreWithReplicas = Q & { $primary: Q }; + +export const withReplicas = < + HKT extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, + Q extends SingleStoreDatabase< + HKT, + TPreparedQueryHKT, + TFullSchema, + TSchema extends Record ? ExtractTablesWithRelations : TSchema + >, +>( + primary: Q, + replicas: [Q, ...Q[]], + getReplica: (replicas: Q[]) => Q = () => replicas[Math.floor(Math.random() * replicas.length)]!, +): SingleStoreWithReplicas => { + const select: Q['select'] = (...args: []) => getReplica(replicas).select(...args); + const selectDistinct: Q['selectDistinct'] = (...args: []) => getReplica(replicas).selectDistinct(...args); + const $with: Q['with'] = (...args: []) => getReplica(replicas).with(...args); + + const update: Q['update'] = (...args: [any]) => primary.update(...args); + const insert: Q['insert'] = (...args: [any]) => primary.insert(...args); + const $delete: Q['delete'] = (...args: [any]) => primary.delete(...args); + const execute: Q['execute'] = (...args: [any]) => primary.execute(...args); + const transaction: Q['transaction'] = (...args: [any, any]) => primary.transaction(...args); + + return { + ...primary, + update, + insert, + delete: $delete, + execute, + transaction, + $primary: primary, + select, + selectDistinct, + with: $with, + get query() { + return getReplica(replicas).query; + }, + }; +}; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts new file mode 100644 index 000000000..9e942cba8 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -0,0 +1,866 @@ +import { aliasedTable, aliasedTableColumn, mapColumnsInAliasedSQLToAlias, mapColumnsInSQLToAlias } from '~/alias.ts'; +import { CasingCache } from '~/casing.ts'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import { DrizzleError } from '~/errors.ts'; +import { and, eq } from '~/expressions.ts'; +import type { MigrationConfig, MigrationMeta } from '~/migrator.ts'; +import { + type BuildRelationalQueryResult, + type DBQueryConfig, + getOperators, + getOrderByOperators, + Many, + normalizeRelation, + One, + type Relation, + type TableRelationalConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import { Param, SQL, sql, View } from '~/sql/sql.ts'; +import type { Name, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; +import { Subquery } from '~/subquery.ts'; +import { getTableName, getTableUniqueName, Table } from '~/table.ts'; +import { orderSelectedFields } from '~/utils.ts'; +import type { Casing, UpdateSet } from '~/utils.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import { SingleStoreColumn } from './columns/common.ts'; +import type { SingleStoreAttachConfig } from './query-builders/attach.ts'; +import type { SingleStoreBranchConfig } from './query-builders/branch.ts'; +import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; +import type { SingleStoreDeleteConfig } from './query-builders/delete.ts'; +import type { SingleStoreDetachConfig } from './query-builders/detach.ts'; +import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; +import type { SingleStoreInsertConfig } from './query-builders/insert.ts'; +import type { SingleStoreOptimizeTableConfig } from './query-builders/optimizeTable.ts'; +import type { + SelectedFieldsOrdered, + SingleStoreSelectConfig, + SingleStoreSelectJoinConfig, +} from './query-builders/select.types.ts'; +import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; +import type { SingleStoreSession } from './session.ts'; +import { SingleStoreTable } from './table.ts'; +import { SingleStoreViewBase } from './view-base.ts'; + +export interface SingleStoreDialectConfig { + casing?: Casing; +} + +export class SingleStoreDialect { + static readonly [entityKind]: string = 'SingleStoreDialect'; + + /** @internal */ + readonly casing: CasingCache; + + constructor(config?: SingleStoreDialectConfig) { + this.casing = new CasingCache(config?.casing); + } + + async migrate( + migrations: MigrationMeta[], + session: SingleStoreSession, + config: Omit, + ): Promise { + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; + const migrationTableCreate = sql` + create table if not exists ${sql.identifier(migrationsTable)} ( + id serial primary key, + hash text not null, + created_at bigint + ) + `; + await session.execute(migrationTableCreate); + + const dbMigrations = await session.all<{ id: number; hash: string; created_at: string }>( + sql`select id, hash, created_at from ${sql.identifier(migrationsTable)} order by created_at desc limit 1`, + ); + + const lastDbMigration = dbMigrations[0]; + + await session.transaction(async (tx) => { + for (const migration of migrations) { + if ( + !lastDbMigration + || Number(lastDbMigration.created_at) < migration.folderMillis + ) { + for (const stmt of migration.sql) { + await tx.execute(sql.raw(stmt)); + } + await tx.execute( + sql`insert into ${ + sql.identifier(migrationsTable) + } (\`hash\`, \`created_at\`) values(${migration.hash}, ${migration.folderMillis})`, + ); + } + } + }); + } + + escapeName(name: string): string { + return `\`${name}\``; + } + + escapeParam(_num: number): string { + return `?`; + } + + escapeString(str: string): string { + return `'${str.replace(/'/g, "''")}'`; + } + + private buildWithCTE(queries: Subquery[] | undefined): SQL | undefined { + if (!queries?.length) return undefined; + + const withSqlChunks = [sql`with `]; + for (const [i, w] of queries.entries()) { + withSqlChunks.push(sql`${sql.identifier(w._.alias)} as (${w._.sql})`); + if (i < queries.length - 1) { + withSqlChunks.push(sql`, `); + } + } + withSqlChunks.push(sql` `); + return sql.join(withSqlChunks); + } + + buildDeleteQuery({ table, where, returning, withList }: SingleStoreDeleteConfig): SQL { + const withSql = this.buildWithCTE(withList); + + const returningSql = returning + ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` + : undefined; + + const whereSql = where ? sql` where ${where}` : undefined; + + return sql`${withSql}delete from ${table}${whereSql}${returningSql}`; + } + + buildDetachQuery({ database, milestone, workspace }: SingleStoreDetachConfig): SQL { + const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; + + const workspaceSql = workspace ? sql` from workspace ${workspace}` : undefined; + + return sql`detach database ${database}${milestoneSql}${workspaceSql}`; + } + + buildAttachQuery( + { database, milestone, time, databaseAlias, readOnly, ...rest }: SingleStoreAttachConfig | SingleStoreBranchConfig, + ): SQL { + const asSql = databaseAlias ? sql` as ${sql.identifier(databaseAlias)}` : undefined; + const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; + const timeSql = time ? sql` at time ${time}` : undefined; + const readOnlySql = readOnly ? sql` read only` : undefined; + const fromWorkspaceGroupSql = 'fromWorkspaceGroup' in rest + ? sql` from workspace group ${rest.fromWorkspaceGroup}` + : undefined; + + return sql`attach database ${ + sql.raw(database) + }${fromWorkspaceGroupSql}${readOnlySql}${asSql}${milestoneSql}${timeSql}`; + } + + buildCreateMilestoneQuery({ database, milestone }: SingleStoreCreateMilestoneConfig): SQL { + const forSql = database ? sql` for ${sql.identifier(database)}` : undefined; + + return sql`create milestone ${milestone}${forSql}`; + } + + buildDropMilestoneQuery({ database, milestone }: SingleStoreDropMilestoneConfig): SQL { + const forSql = database ? sql` for ${sql.identifier(database)}` : undefined; + + return sql`drop milestone ${milestone}${forSql}`; + } + + buildOptimizeTable({ table, arg, selection }: SingleStoreOptimizeTableConfig): SQL { + const argSql = arg ? sql` ${sql.raw(arg)}` : undefined; + + let warmBlobCacheForColumnSql = undefined; + if (selection) { + const selectionField = selection.length > 0 + ? selection.map((column) => { + return { path: [], field: column }; + }) + : [{ path: [], field: sql.raw('*') }]; + warmBlobCacheForColumnSql = sql` warm blob cache for column ${ + this.buildSelection(selectionField, { isSingleTable: true }) + }`; + } + + return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; + } + + buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { + const tableColumns = table[Table.Symbol.Columns]; + + const columnNames = Object.keys(tableColumns).filter((colName) => + set[colName] !== undefined || tableColumns[colName]?.onUpdateFn !== undefined + ); + + const setSize = columnNames.length; + return sql.join(columnNames.flatMap((colName, i) => { + const col = tableColumns[colName]!; + + const value = set[colName] ?? sql.param(col.onUpdateFn!(), col); + const res = sql`${sql.identifier(col.name)} = ${value}`; + + if (i < setSize - 1) { + return [res, sql.raw(', ')]; + } + return [res]; + })); + } + + buildUpdateQuery({ table, set, where, returning, withList }: SingleStoreUpdateConfig): SQL { + const withSql = this.buildWithCTE(withList); + + const setSql = this.buildUpdateSet(table, set); + + const returningSql = returning + ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` + : undefined; + + const whereSql = where ? sql` where ${where}` : undefined; + + return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}`; + } + + /** + * Builds selection SQL with provided fields/expressions + * + * Examples: + * + * `select from` + * + * `insert ... returning ` + * + * If `isSingleTable` is true, then columns won't be prefixed with table name + */ + private buildSelection( + fields: SelectedFieldsOrdered, + { isSingleTable = false }: { isSingleTable?: boolean } = {}, + ): SQL { + const columnsLen = fields.length; + + const chunks = fields + .flatMap(({ field }, i) => { + const chunk: SQLChunk[] = []; + + if (is(field, SQL.Aliased) && field.isSelectionField) { + chunk.push(sql.identifier(field.fieldAlias)); + } else if (is(field, SQL.Aliased) || is(field, SQL)) { + const query = is(field, SQL.Aliased) ? field.sql : field; + + if (isSingleTable) { + chunk.push( + new SQL( + query.queryChunks.map((c) => { + if (is(c, SingleStoreColumn)) { + return sql.identifier(c.name); + } + return c; + }), + ), + ); + } else { + chunk.push(query); + } + + if (is(field, SQL.Aliased)) { + chunk.push(sql` as ${sql.identifier(field.fieldAlias)}`); + } + } else if (is(field, Column)) { + if (isSingleTable) { + chunk.push(sql.identifier(field.name)); + } else { + chunk.push(field); + } + } + + if (i < columnsLen - 1) { + chunk.push(sql`, `); + } + + return chunk; + }); + + return sql.join(chunks); + } + + buildSelectQuery( + { + withList, + fields, + fieldsFlat, + where, + having, + table, + joins, + orderBy, + groupBy, + limit, + offset, + lockingClause, + distinct, + setOperators, + }: SingleStoreSelectConfig, + ): SQL { + const fieldsList = fieldsFlat ?? orderSelectedFields(fields); + for (const f of fieldsList) { + if ( + is(f.field, Column) + && getTableName(f.field.table) + !== (is(table, Subquery) + ? table._.alias + : is(table, SingleStoreViewBase) + ? table[ViewBaseConfig].name + : is(table, SQL) + ? undefined + : getTableName(table)) + && !((table) => + joins?.some(({ alias }) => + alias === (table[Table.Symbol.IsAlias] ? getTableName(table) : table[Table.Symbol.BaseName]) + ))(f.field.table) + ) { + const tableName = getTableName(f.field.table); + throw new Error( + `Your "${ + f.path.join('->') + }" field references a column "${tableName}"."${f.field.name}", but the table "${tableName}" is not part of the query! Did you forget to join it?`, + ); + } + } + + const isSingleTable = !joins || joins.length === 0; + + const withSql = this.buildWithCTE(withList); + + const distinctSql = distinct ? sql` distinct` : undefined; + + const selection = this.buildSelection(fieldsList, { isSingleTable }); + + const tableSql = (() => { + if (is(table, Table) && table[Table.Symbol.OriginalName] !== table[Table.Symbol.Name]) { + return sql`${sql.identifier(table[Table.Symbol.OriginalName])} ${sql.identifier(table[Table.Symbol.Name])}`; + } + + return table; + })(); + + const joinsArray: SQL[] = []; + + if (joins) { + for (const [index, joinMeta] of joins.entries()) { + if (index === 0) { + joinsArray.push(sql` `); + } + const table = joinMeta.table; + const lateralSql = joinMeta.lateral ? sql` lateral` : undefined; + + if (is(table, SingleStoreTable)) { + const tableName = table[SingleStoreTable.Symbol.Name]; + const tableSchema = table[SingleStoreTable.Symbol.Schema]; + const origTableName = table[SingleStoreTable.Symbol.OriginalName]; + const alias = tableName === origTableName ? undefined : joinMeta.alias; + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ + tableSchema ? sql`${sql.identifier(tableSchema)}.` : undefined + }${sql.identifier(origTableName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + ); + } else if (is(table, View)) { + const viewName = table[ViewBaseConfig].name; + const viewSchema = table[ViewBaseConfig].schema; + const origViewName = table[ViewBaseConfig].originalName; + const alias = viewName === origViewName ? undefined : joinMeta.alias; + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ + viewSchema ? sql`${sql.identifier(viewSchema)}.` : undefined + }${sql.identifier(origViewName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + ); + } else { + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${table} on ${joinMeta.on}`, + ); + } + if (index < joins.length - 1) { + joinsArray.push(sql` `); + } + } + } + + const joinsSql = sql.join(joinsArray); + + const whereSql = where ? sql` where ${where}` : undefined; + + const havingSql = having ? sql` having ${having}` : undefined; + + let orderBySql; + if (orderBy && orderBy.length > 0) { + orderBySql = sql` order by ${sql.join(orderBy, sql`, `)}`; + } + + let groupBySql; + if (groupBy && groupBy.length > 0) { + groupBySql = sql` group by ${sql.join(groupBy, sql`, `)}`; + } + + const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined; + + const offsetSql = offset ? sql` offset ${offset}` : undefined; + + let lockingClausesSql; + if (lockingClause) { + const { config, strength } = lockingClause; + lockingClausesSql = sql` for ${sql.raw(strength)}`; + if (config.noWait) { + lockingClausesSql.append(sql` no wait`); + } else if (config.skipLocked) { + lockingClausesSql.append(sql` skip locked`); + } + } + + const finalQuery = + sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`; + + if (setOperators.length > 0) { + return this.buildSetOperations(finalQuery, setOperators); + } + + return finalQuery; + } + + buildSetOperations(leftSelect: SQL, setOperators: SingleStoreSelectConfig['setOperators']): SQL { + const [setOperator, ...rest] = setOperators; + + if (!setOperator) { + throw new Error('Cannot pass undefined values to any set operator'); + } + + if (rest.length === 0) { + return this.buildSetOperationQuery({ leftSelect, setOperator }); + } + + // Some recursive magic here + return this.buildSetOperations( + this.buildSetOperationQuery({ leftSelect, setOperator }), + rest, + ); + } + + buildSetOperationQuery({ + leftSelect, + setOperator: { type, isAll, rightSelect, limit, orderBy, offset }, + }: { leftSelect: SQL; setOperator: SingleStoreSelectConfig['setOperators'][number] }): SQL { + const leftChunk = sql`(${leftSelect.getSQL()}) `; + const rightChunk = sql`(${rightSelect.getSQL()})`; + + let orderBySql; + if (orderBy && orderBy.length > 0) { + const orderByValues: (SQL | Name)[] = []; + + // The next bit is necessary because the sql operator replaces ${table.column} with `table`.`column` + // which is invalid SingleStore syntax, Table from one of the SELECTs cannot be used in global ORDER clause + for (const orderByUnit of orderBy) { + if (is(orderByUnit, SingleStoreColumn)) { + orderByValues.push(sql.identifier(orderByUnit.name)); + } else if (is(orderByUnit, SQL)) { + for (let i = 0; i < orderByUnit.queryChunks.length; i++) { + const chunk = orderByUnit.queryChunks[i]; + + if (is(chunk, SingleStoreColumn)) { + orderByUnit.queryChunks[i] = sql.identifier(chunk.name); + } + } + + orderByValues.push(sql`${orderByUnit}`); + } else { + orderByValues.push(sql`${orderByUnit}`); + } + } + + orderBySql = sql` order by ${sql.join(orderByValues, sql`, `)} `; + } + + const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined; + + const operatorChunk = sql.raw(`${type} ${isAll ? 'all ' : ''}`); + + const offsetSql = offset ? sql` offset ${offset}` : undefined; + + return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; + } + + buildInsertQuery( + { table, values, ignore, onConflict }: SingleStoreInsertConfig, + ): { sql: SQL; generatedIds: Record[] } { + // const isSingleValue = values.length === 1; + const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = []; + const columns: Record = table[Table.Symbol.Columns]; + const colEntries: [string, SingleStoreColumn][] = Object.entries(columns).filter(([_, col]) => + !col.shouldDisableInsert() + ); + + const insertOrder = colEntries.map(([, column]) => sql.identifier(column.name)); + const generatedIdsResponse: Record[] = []; + + for (const [valueIndex, value] of values.entries()) { + const generatedIds: Record = {}; + + const valueList: (SQLChunk | SQL)[] = []; + for (const [fieldName, col] of colEntries) { + const colValue = value[fieldName]; + if (colValue === undefined || (is(colValue, Param) && colValue.value === undefined)) { + // eslint-disable-next-line unicorn/no-negated-condition + if (col.defaultFn !== undefined) { + const defaultFnResult = col.defaultFn(); + generatedIds[fieldName] = defaultFnResult; + const defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col); + valueList.push(defaultValue); + // eslint-disable-next-line unicorn/no-negated-condition + } else if (!col.default && col.onUpdateFn !== undefined) { + const onUpdateFnResult = col.onUpdateFn(); + const newValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col); + valueList.push(newValue); + } else { + valueList.push(sql`default`); + } + } else { + if (col.defaultFn && is(colValue, Param)) { + generatedIds[fieldName] = colValue.value; + } + valueList.push(colValue); + } + } + + generatedIdsResponse.push(generatedIds); + valuesSqlList.push(valueList); + if (valueIndex < values.length - 1) { + valuesSqlList.push(sql`, `); + } + } + + const valuesSql = sql.join(valuesSqlList); + + const ignoreSql = ignore ? sql` ignore` : undefined; + + const onConflictSql = onConflict ? sql` on duplicate key ${onConflict}` : undefined; + + return { + sql: sql`insert${ignoreSql} into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}`, + generatedIds: generatedIdsResponse, + }; + } + + sqlToQuery(sql: SQL, invokeSource?: 'indexes' | undefined): QueryWithTypings { + return sql.toQuery({ + casing: this.casing, + escapeName: this.escapeName, + escapeParam: this.escapeParam, + escapeString: this.escapeString, + invokeSource, + }); + } + + buildRelationalQuery({ + fullSchema, + schema, + tableNamesMap, + table, + tableConfig, + queryConfig: config, + tableAlias, + nestedQueryRelation, + joinOn, + }: { + fullSchema: Record; + schema: TablesRelationalConfig; + tableNamesMap: Record; + table: SingleStoreTable; + tableConfig: TableRelationalConfig; + queryConfig: true | DBQueryConfig<'many', true>; + tableAlias: string; + nestedQueryRelation?: Relation; + joinOn?: SQL; + }): BuildRelationalQueryResult { + let selection: BuildRelationalQueryResult['selection'] = []; + let limit, offset, orderBy: SingleStoreSelectConfig['orderBy'], where; + const joins: SingleStoreSelectJoinConfig[] = []; + + if (config === true) { + const selectionEntries = Object.entries(tableConfig.columns); + selection = selectionEntries.map(( + [key, value], + ) => ({ + dbKey: value.name, + tsKey: key, + field: aliasedTableColumn(value as SingleStoreColumn, tableAlias), + relationTableTsKey: undefined, + isJson: false, + selection: [], + })); + } else { + const aliasedColumns = Object.fromEntries( + Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value, tableAlias)]), + ); + + if (config.where) { + const whereSql = typeof config.where === 'function' + ? config.where(aliasedColumns, getOperators()) + : config.where; + where = whereSql && mapColumnsInSQLToAlias(whereSql, tableAlias); + } + + const fieldsSelection: { tsKey: string; value: SingleStoreColumn | SQL.Aliased }[] = []; + let selectedColumns: string[] = []; + + // Figure out which columns to select + if (config.columns) { + let isIncludeMode = false; + + for (const [field, value] of Object.entries(config.columns)) { + if (value === undefined) { + continue; + } + + if (field in tableConfig.columns) { + if (!isIncludeMode && value === true) { + isIncludeMode = true; + } + selectedColumns.push(field); + } + } + + if (selectedColumns.length > 0) { + selectedColumns = isIncludeMode + ? selectedColumns.filter((c) => config.columns?.[c] === true) + : Object.keys(tableConfig.columns).filter((key) => !selectedColumns.includes(key)); + } + } else { + // Select all columns if selection is not specified + selectedColumns = Object.keys(tableConfig.columns); + } + + for (const field of selectedColumns) { + const column = tableConfig.columns[field]! as SingleStoreColumn; + fieldsSelection.push({ tsKey: field, value: column }); + } + + let selectedRelations: { + tsKey: string; + queryConfig: true | DBQueryConfig<'many', false>; + relation: Relation; + }[] = []; + + // Figure out which relations to select + if (config.with) { + selectedRelations = Object.entries(config.with) + .filter((entry): entry is [typeof entry[0], NonNullable] => !!entry[1]) + .map(([tsKey, queryConfig]) => ({ tsKey, queryConfig, relation: tableConfig.relations[tsKey]! })); + } + + let extras; + + // Figure out which extras to select + if (config.extras) { + extras = typeof config.extras === 'function' + ? config.extras(aliasedColumns, { sql }) + : config.extras; + for (const [tsKey, value] of Object.entries(extras)) { + fieldsSelection.push({ + tsKey, + value: mapColumnsInAliasedSQLToAlias(value, tableAlias), + }); + } + } + + // Transform `fieldsSelection` into `selection` + // `fieldsSelection` shouldn't be used after this point + for (const { tsKey, value } of fieldsSelection) { + selection.push({ + dbKey: is(value, SQL.Aliased) ? value.fieldAlias : tableConfig.columns[tsKey]!.name, + tsKey, + field: is(value, Column) ? aliasedTableColumn(value, tableAlias) : value, + relationTableTsKey: undefined, + isJson: false, + selection: [], + }); + } + + let orderByOrig = typeof config.orderBy === 'function' + ? config.orderBy(aliasedColumns, getOrderByOperators()) + : config.orderBy ?? []; + if (!Array.isArray(orderByOrig)) { + orderByOrig = [orderByOrig]; + } + orderBy = orderByOrig.map((orderByValue) => { + if (is(orderByValue, Column)) { + return aliasedTableColumn(orderByValue, tableAlias) as SingleStoreColumn; + } + return mapColumnsInSQLToAlias(orderByValue, tableAlias); + }); + + limit = config.limit; + offset = config.offset; + + // Process all relations + for ( + const { + tsKey: selectedRelationTsKey, + queryConfig: selectedRelationConfigValue, + relation, + } of selectedRelations + ) { + const normalizedRelation = normalizeRelation(schema, tableNamesMap, relation); + const relationTableName = getTableUniqueName(relation.referencedTable); + const relationTableTsName = tableNamesMap[relationTableName]!; + const relationTableAlias = `${tableAlias}_${selectedRelationTsKey}`; + const joinOn = and( + ...normalizedRelation.fields.map((field, i) => + eq( + aliasedTableColumn(normalizedRelation.references[i]!, relationTableAlias), + aliasedTableColumn(field, tableAlias), + ) + ), + ); + const builtRelation = this.buildRelationalQuery({ + fullSchema, + schema, + tableNamesMap, + table: fullSchema[relationTableTsName] as SingleStoreTable, + tableConfig: schema[relationTableTsName]!, + queryConfig: is(relation, One) + ? (selectedRelationConfigValue === true + ? { limit: 1 } + : { ...selectedRelationConfigValue, limit: 1 }) + : selectedRelationConfigValue, + tableAlias: relationTableAlias, + joinOn, + nestedQueryRelation: relation, + }); + const field = sql`coalesce(${sql.identifier(relationTableAlias)}.${sql.identifier('data')}, "[]")`.as( + selectedRelationTsKey, + ); + joins.push({ + on: sql`true`, + table: new Subquery(builtRelation.sql as SQL, {}, relationTableAlias), + alias: relationTableAlias, + joinType: 'left', + lateral: true, + }); + selection.push({ + dbKey: selectedRelationTsKey, + tsKey: selectedRelationTsKey, + field, + relationTableTsKey: relationTableTsName, + isJson: true, + selection: builtRelation.selection, + }); + } + } + + if (selection.length === 0) { + throw new DrizzleError({ message: `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}")` }); + } + + let result; + + where = and(joinOn, where); + + if (nestedQueryRelation) { + let field = sql`JSON_BUILD_OBJECT(${ + sql.join( + selection.map(({ field, tsKey, isJson }, index) => + isJson + ? sql`${index}, ${sql.identifier(`${tableAlias}_${tsKey}`)}.${sql.identifier('data')}` + : is(field, SQL.Aliased) + ? sql`${index}, ${field.sql}` + : sql`${index}, ${field}` + ), + sql`, `, + ) + })`; + if (is(nestedQueryRelation, Many)) { + field = sql`json_agg(${field})`; + } + const nestedSelection = [{ + dbKey: 'data', + tsKey: 'data', + field: field.as('data'), + isJson: true, + relationTableTsKey: tableConfig.tsName, + selection, + }]; + + const needsSubquery = limit !== undefined || offset !== undefined || (orderBy?.length ?? 0) > 0; + + if (needsSubquery) { + result = this.buildSelectQuery({ + table: aliasedTable(table, tableAlias), + fields: {}, + fieldsFlat: [ + { + path: [], + field: sql.raw('*'), + }, + ...(((orderBy?.length ?? 0) > 0) + ? [{ + path: [], + field: sql`row_number() over (order by ${sql.join(orderBy!, sql`, `)})`, + }] + : []), + ], + where, + limit, + offset, + setOperators: [], + }); + + where = undefined; + limit = undefined; + offset = undefined; + orderBy = undefined; + } else { + result = aliasedTable(table, tableAlias); + } + + result = this.buildSelectQuery({ + table: is(result, SingleStoreTable) ? result : new Subquery(result, {}, tableAlias), + fields: {}, + fieldsFlat: nestedSelection.map(({ field }) => ({ + path: [], + field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field, + })), + joins, + where, + limit, + offset, + orderBy, + setOperators: [], + }); + } else { + result = this.buildSelectQuery({ + table: aliasedTable(table, tableAlias), + fields: {}, + fieldsFlat: selection.map(({ field }) => ({ + path: [], + field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field, + })), + joins, + where, + limit, + offset, + orderBy, + setOperators: [], + }); + } + + return { + tableTsKey: tableConfig.tsName, + sql: result, + selection, + }; + } +} diff --git a/drizzle-orm/src/singlestore-core/expressions.ts b/drizzle-orm/src/singlestore-core/expressions.ts new file mode 100644 index 000000000..6d4284d18 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/expressions.ts @@ -0,0 +1,25 @@ +import { bindIfParam } from '~/expressions.ts'; +import type { Placeholder, SQL, SQLChunk, SQLWrapper } from '~/sql/sql.ts'; +import { sql } from '~/sql/sql.ts'; +import type { SingleStoreColumn } from './columns/index.ts'; + +export * from '~/expressions.ts'; + +export function concat(column: SingleStoreColumn | SQL.Aliased, value: string | Placeholder | SQLWrapper): SQL { + return sql`${column} || ${bindIfParam(value, column)}`; +} + +export function substring( + column: SingleStoreColumn | SQL.Aliased, + { from, for: _for }: { from?: number | Placeholder | SQLWrapper; for?: number | Placeholder | SQLWrapper }, +): SQL { + const chunks: SQLChunk[] = [sql`substring(`, column]; + if (from !== undefined) { + chunks.push(sql` from `, bindIfParam(from, column)); + } + if (_for !== undefined) { + chunks.push(sql` for `, bindIfParam(_for, column)); + } + chunks.push(sql`)`); + return sql.join(chunks); +} diff --git a/drizzle-orm/src/singlestore-core/index.ts b/drizzle-orm/src/singlestore-core/index.ts new file mode 100644 index 000000000..4da014404 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/index.ts @@ -0,0 +1,16 @@ +export * from './alias.ts'; +export * from './columns/index.ts'; +export * from './db.ts'; +export * from './dialect.ts'; +export * from './indexes.ts'; +export * from './primary-keys.ts'; +export * from './query-builders/index.ts'; +export * from './schema.ts'; +export * from './session.ts'; +export * from './sql/index.ts'; +export * from './subquery.ts'; +export * from './table.ts'; +export * from './unique-constraint.ts'; +export * from './utils.ts'; +export * from './view-common.ts'; +export * from './view.ts'; diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts new file mode 100644 index 000000000..172f524f5 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -0,0 +1,191 @@ +import { entityKind } from '~/entity.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; +import type { SingleStoreTable } from './table.ts'; + +interface IndexConfig { + name: string; + + columns: IndexColumn[]; + + /** + * If true, the index will be created as `create unique index` instead of `create index`. + */ + unique?: boolean; + + /** + * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. + */ + using?: 'btree' | 'hash'; + + /** + * If set, the index will be created as `create index ... algorythm { 'default' | 'inplace' | 'copy' }`. + */ + algorythm?: 'default' | 'inplace' | 'copy'; + + /** + * If set, adds locks to the index creation. + */ + lock?: 'default' | 'none' | 'shared' | 'exclusive'; +} + +export type IndexColumn = SingleStoreColumn | SQL; + +export class IndexBuilderOn { + static readonly [entityKind]: string = 'SingleStoreIndexBuilderOn'; + + constructor(private name: string, private unique: boolean) {} + + on(...columns: [IndexColumn, ...IndexColumn[]]): IndexBuilder { + return new IndexBuilder(this.name, columns, this.unique); + } +} + +export interface AnyIndexBuilder { + build(table: SingleStoreTable): Index; +} + +export interface AnyFullTextIndexBuilder { + build(table: SingleStoreTable): FullTextIndex; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface IndexBuilder extends AnyIndexBuilder {} + +export class IndexBuilder implements AnyIndexBuilder { + static readonly [entityKind]: string = 'SingleStoreIndexBuilder'; + + /** @internal */ + config: IndexConfig; + + constructor(name: string, columns: IndexColumn[], unique: boolean) { + this.config = { + name, + columns, + unique, + }; + } + + using(using: IndexConfig['using']): this { + this.config.using = using; + return this; + } + + algorythm(algorythm: IndexConfig['algorythm']): this { + this.config.algorythm = algorythm; + return this; + } + + lock(lock: IndexConfig['lock']): this { + this.config.lock = lock; + return this; + } + + /** @internal */ + build(table: SingleStoreTable): Index { + return new Index(this.config, table); + } +} + +export class Index { + static readonly [entityKind]: string = 'SingleStoreIndex'; + + readonly config: IndexConfig & { table: SingleStoreTable }; + + constructor(config: IndexConfig, table: SingleStoreTable) { + this.config = { ...config, table }; + } +} + +export type GetColumnsTableName = TColumns extends + AnySingleStoreColumn<{ tableName: infer TTableName extends string }> | AnySingleStoreColumn< + { tableName: infer TTableName extends string } + >[] ? TTableName + : never; + +export function index(name: string): IndexBuilderOn { + return new IndexBuilderOn(name, false); +} + +export function uniqueIndex(name: string): IndexBuilderOn { + return new IndexBuilderOn(name, true); +} + +interface FullTextIndexConfig { + version?: number; +} + +interface FullTextIndexFullConfig extends FullTextIndexConfig { + columns: IndexColumn[]; + + name: string; +} + +export class FullTextIndexBuilderOn { + static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilderOn'; + + constructor(private name: string, private config: FullTextIndexConfig) {} + + on(...columns: [IndexColumn, ...IndexColumn[]]): FullTextIndexBuilder { + return new FullTextIndexBuilder({ + name: this.name, + columns: columns, + ...this.config, + }); + } +} + +export interface FullTextIndexBuilder extends AnyFullTextIndexBuilder {} + +export class FullTextIndexBuilder implements AnyFullTextIndexBuilder { + static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilder'; + + /** @internal */ + config: FullTextIndexFullConfig; + + constructor(config: FullTextIndexFullConfig) { + this.config = config; + } + + /** @internal */ + build(table: SingleStoreTable): FullTextIndex { + return new FullTextIndex(this.config, table); + } +} + +export class FullTextIndex { + static readonly [entityKind]: string = 'SingleStoreFullTextIndex'; + + readonly config: FullTextIndexConfig & { table: SingleStoreTable }; + + constructor(config: FullTextIndexConfig, table: SingleStoreTable) { + this.config = { ...config, table }; + } +} + +export function fulltext(name: string, config: FullTextIndexConfig): FullTextIndexBuilderOn { + return new FullTextIndexBuilderOn(name, config); +} + +export type SortKeyColumn = SingleStoreColumn | SQL; + +export class SortKeyBuilder { + static readonly [entityKind]: string = 'SingleStoreSortKeyBuilder'; + + constructor(private columns: SortKeyColumn[]) {} + + /** @internal */ + build(table: SingleStoreTable): SortKey { + return new SortKey(this.columns, table); + } +} + +export class SortKey { + static readonly [entityKind]: string = 'SingleStoreSortKey'; + + constructor(public columns: SortKeyColumn[], public table: SingleStoreTable) {} +} + +export function sortKey(...columns: SortKeyColumn[]): SortKeyBuilder { + return new SortKeyBuilder(columns); +} diff --git a/drizzle-orm/src/singlestore-core/primary-keys.ts b/drizzle-orm/src/singlestore-core/primary-keys.ts new file mode 100644 index 000000000..47dc0a19c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/primary-keys.ts @@ -0,0 +1,63 @@ +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; +import { SingleStoreTable } from './table.ts'; + +export function primaryKey< + TTableName extends string, + TColumn extends AnySingleStoreColumn<{ tableName: TTableName }>, + TColumns extends AnySingleStoreColumn<{ tableName: TTableName }>[], +>(config: { name?: string; columns: [TColumn, ...TColumns] }): PrimaryKeyBuilder; +/** + * @deprecated: Please use primaryKey({ columns: [] }) instead of this function + * @param columns + */ +export function primaryKey< + TTableName extends string, + TColumns extends AnySingleStoreColumn<{ tableName: TTableName }>[], +>(...columns: TColumns): PrimaryKeyBuilder; +export function primaryKey(...config: any) { + if (config[0].columns) { + return new PrimaryKeyBuilder(config[0].columns, config[0].name); + } + return new PrimaryKeyBuilder(config); +} + +export class PrimaryKeyBuilder { + static readonly [entityKind]: string = 'SingleStorePrimaryKeyBuilder'; + + /** @internal */ + columns: SingleStoreColumn[]; + + /** @internal */ + name?: string; + + constructor( + columns: SingleStoreColumn[], + name?: string, + ) { + this.columns = columns; + this.name = name; + } + + /** @internal */ + build(table: SingleStoreTable): PrimaryKey { + return new PrimaryKey(table, this.columns, this.name); + } +} + +export class PrimaryKey { + static readonly [entityKind]: string = 'SingleStorePrimaryKey'; + + readonly columns: SingleStoreColumn[]; + readonly name?: string; + + constructor(readonly table: SingleStoreTable, columns: SingleStoreColumn[], name?: string) { + this.columns = columns; + this.name = name; + } + + getName(): string { + return this.name + ?? `${this.table[SingleStoreTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/attach.ts b/drizzle-orm/src/singlestore-core/query-builders/attach.ts new file mode 100644 index 000000000..ca894ced1 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/attach.ts @@ -0,0 +1,198 @@ +import { entityKind } from '~/entity.ts'; +import { DrizzleError } from '~/errors.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreAttachWithout< + T extends AnySingleStoreAttachBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreAttachBase< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreAttach< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreAttachBase; + +export interface SingleStoreAttachConfig { + milestone?: string | undefined; + time?: Date | undefined; + database: string; + databaseAlias?: string | undefined; + readOnly?: boolean | undefined; +} + +export type SingleStoreAttachPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreAttachDynamic = SingleStoreAttach< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreAttachBase = SingleStoreAttachBase; + +export interface SingleStoreAttachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly database: TDatabase; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreAttachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreAttach'; + + private config: SingleStoreAttachConfig; + + constructor( + private database: TDatabase, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { database }; + } + + as(dabataseAlias: string): SingleStoreAttachWithout { + if (this.config.readOnly) { + throw new DrizzleError({ message: 'Cannot set both databaseAlias and readOnly' }); + } + this.config.databaseAlias = dabataseAlias; + return this as any; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Attach all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Attach all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Attach all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + // TODO(singlestore): docs + atMilestone(milestone: string): SingleStoreAttachWithout { + if (this.config.time) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } + this.config.milestone = milestone; + return this as any; + } + + // TODO(singlestore): docs + atTime(time: Date): SingleStoreAttachWithout { + if (this.config.milestone) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } + this.config.time = time; + return this as any; + } + + // TODO(singlestore): docs + readOnly(): SingleStoreAttachWithout { + if (this.config.databaseAlias) { + throw new DrizzleError({ message: 'Cannot set both databaseAlias and readOnly' }); + } + this.config.readOnly = true; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildAttachQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreAttachPrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreAttachPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreAttachDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/branch.ts b/drizzle-orm/src/singlestore-core/query-builders/branch.ts new file mode 100644 index 000000000..21e2fe0ac --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/branch.ts @@ -0,0 +1,186 @@ +import { entityKind } from '~/entity.ts'; +import { DrizzleError } from '~/errors.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { SingleStoreAttachConfig } from './attach.ts'; + +export type SingleStoreBranchWithout< + T extends AnySingleStoreBranchBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreBranchBase< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreBranch< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreBranchBase; + +export interface SingleStoreBranchConfig extends SingleStoreAttachConfig { + databaseAlias: string; + fromWorkspaceGroup?: string | undefined; +} + +export type SingleStoreBranchPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreBranchDynamic = SingleStoreBranch< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreBranchBase = SingleStoreBranchBase; + +export interface SingleStoreBranchBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly database: TDatabase; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreBranchBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreBranch'; + + private config: SingleStoreBranchConfig; + + constructor( + private database: TDatabase, + private branchName: string, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { database, databaseAlias: branchName }; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Attach all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Attach all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Attach all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + // TODO(singlestore): docs + atMilestone(milestone: string): SingleStoreBranchWithout { + if (this.config.time) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } + this.config.milestone = milestone; + return this as any; + } + + // TODO(singlestore): docs + atTime(time: Date): SingleStoreBranchWithout { + if (this.config.milestone) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } + this.config.time = time; + return this as any; + } + + // TODO(singlestore): docs + fromWorkspaceGroup(groupID: string): SingleStoreBranchWithout { + this.config.fromWorkspaceGroup = groupID; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildAttachQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreBranchPrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreBranchPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreBranchDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/count.ts b/drizzle-orm/src/singlestore-core/query-builders/count.ts new file mode 100644 index 000000000..931e76a6f --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/count.ts @@ -0,0 +1,79 @@ +import { entityKind } from '~/entity.ts'; +import { SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; +import type { SingleStoreSession } from '../session.ts'; +import type { SingleStoreTable } from '../table.ts'; +import type { SingleStoreViewBase } from '../view-base.ts'; + +export class SingleStoreCountBuilder< + TSession extends SingleStoreSession, +> extends SQL implements Promise, SQLWrapper { + private sql: SQL; + + static override readonly [entityKind] = 'SingleStoreCountBuilder'; + [Symbol.toStringTag] = 'SingleStoreCountBuilder'; + + private session: TSession; + + private static buildEmbeddedCount( + source: SingleStoreTable | SingleStoreViewBase | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; + } + + private static buildCount( + source: SingleStoreTable | SingleStoreViewBase | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`select count(*) as count from ${source}${sql.raw(' where ').if(filters)}${filters}`; + } + + constructor( + readonly params: { + source: SingleStoreTable | SingleStoreViewBase | SQL | SQLWrapper; + filters?: SQL; + session: TSession; + }, + ) { + super(SingleStoreCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); + + this.mapWith(Number); + + this.session = params.session; + + this.sql = SingleStoreCountBuilder.buildCount( + params.source, + params.filters, + ); + } + + then( + onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, + ): Promise { + return Promise.resolve(this.session.count(this.sql)) + .then( + onfulfilled, + onrejected, + ); + } + + catch( + onRejected?: ((reason: any) => never | PromiseLike) | null | undefined, + ): Promise { + return this.then(undefined, onRejected); + } + + finally(onFinally?: (() => void) | null | undefined): Promise { + return this.then( + (value) => { + onFinally?.(); + return value; + }, + (reason) => { + onFinally?.(); + throw reason; + }, + ); + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts b/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts new file mode 100644 index 000000000..0444d6bf8 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts @@ -0,0 +1,136 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreCreateMilestoneWithout< + T extends AnySingleStoreCreateMilestoneBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreCreateMilestoneBase< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreCreateMilestone< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreCreateMilestoneBase; + +export interface SingleStoreCreateMilestoneConfig { + milestone: string; + database?: string | undefined; +} + +export type SingleStoreCreateMilestonePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreCreateMilestoneDynamic = SingleStoreCreateMilestone< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreCreateMilestoneBase = SingleStoreCreateMilestoneBase; + +export interface SingleStoreCreateMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly milestone: TMilestone; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreCreateMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreCreateMilestone'; + + private config: SingleStoreCreateMilestoneConfig; + + constructor( + private milestone: TMilestone, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { milestone }; + } + + // TODO(singlestore): docs + for(database: string): SingleStoreCreateMilestoneWithout { + this.config.database = database; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildCreateMilestoneQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreCreateMilestonePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreCreateMilestonePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreCreateMilestoneDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/delete.ts b/drizzle-orm/src/singlestore-core/query-builders/delete.ts new file mode 100644 index 000000000..1f41d29ba --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/delete.ts @@ -0,0 +1,207 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; +import type { ValueOrArray } from '~/utils.ts'; +import type { SingleStoreColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; + +export type SingleStoreDeleteWithout< + T extends AnySingleStoreDeleteBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreDeleteBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreDelete< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreDeleteBase; + +export interface SingleStoreDeleteConfig { + where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + table: SingleStoreTable; + returning?: SelectedFieldsOrdered; + withList?: Subquery[]; +} + +export type SingleStoreDeletePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreDeleteDynamic = SingleStoreDelete< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreDeleteBase = SingleStoreDeleteBase; + +export interface SingleStoreDeleteBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreDeleteBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreDelete'; + + private config: SingleStoreDeleteConfig; + + constructor( + private table: TTable, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + withList?: Subquery[], + ) { + super(); + this.config = { table, withList }; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Delete all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Delete all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Delete all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where(where: SQL | undefined): SingleStoreDeleteWithout { + this.config.where = where; + return this as any; + } + + orderBy( + builder: (deleteTable: TTable) => ValueOrArray, + ): SingleStoreDeleteWithout; + orderBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreDeleteWithout; + orderBy( + ...columns: + | [(deleteTable: TTable) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreDeleteWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): SingleStoreDeleteWithout { + this.config.limit = limit; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildDeleteQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreDeletePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + this.config.returning, + ) as SingleStoreDeletePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreDeleteDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/detach.ts b/drizzle-orm/src/singlestore-core/query-builders/detach.ts new file mode 100644 index 000000000..2b74873e2 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/detach.ts @@ -0,0 +1,172 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreDetachWithout< + T extends AnySingleStoreDetachBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreDetachBase< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreDetach< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreDetachBase; + +export interface SingleStoreDetachConfig { + milestone?: string | undefined; + database: string; + workspace?: string | undefined; +} + +export type SingleStoreDetachPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreDetachDynamic = SingleStoreDetach< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreDetachBase = SingleStoreDetachBase; + +export interface SingleStoreDetachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly database: TDatabase; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreDetachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreDetach'; + + private config: SingleStoreDetachConfig; + + constructor( + private database: TDatabase, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { database }; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Detach all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Detach all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Detach all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + // TODO(singlestore): docs + atMilestone(milestone: string): SingleStoreDetachWithout { + this.config.milestone = milestone; + return this as any; + } + + // TODO(singlestore): docs + fromWorkspace(workspace: string): SingleStoreDetachWithout { + this.config.workspace = workspace; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildDetachQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreDetachPrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreDetachPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreDetachDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts b/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts new file mode 100644 index 000000000..66047c991 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts @@ -0,0 +1,136 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreDropMilestoneWithout< + T extends AnySingleStoreDropMilestoneBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreDropMilestoneBase< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreDropMilestone< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreDropMilestoneBase; + +export interface SingleStoreDropMilestoneConfig { + milestone: string; + database?: string | undefined; +} + +export type SingleStoreDropMilestonePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreDropMilestoneDynamic = SingleStoreDropMilestone< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreDropMilestoneBase = SingleStoreDropMilestoneBase; + +export interface SingleStoreDropMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly milestone: TMilestone; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreDropMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreDropMilestone'; + + private config: SingleStoreDropMilestoneConfig; + + constructor( + private milestone: TMilestone, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { milestone }; + } + + // TODO(singlestore): docs + for(database: string): SingleStoreDropMilestoneWithout { + this.config.database = database; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildDropMilestoneQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreDropMilestonePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreDropMilestonePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreDropMilestoneDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/index.ts b/drizzle-orm/src/singlestore-core/query-builders/index.ts new file mode 100644 index 000000000..95de476cd --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/index.ts @@ -0,0 +1,12 @@ +export * from './attach.ts'; +export * from './branch.ts'; +export * from './count.ts'; +export * from './createMilestone.ts'; +export * from './delete.ts'; +export * from './detach.ts'; +export * from './insert.ts'; +export * from './optimizeTable.ts'; +export * from './query-builder.ts'; +export * from './select.ts'; +export * from './select.types.ts'; +export * from './update.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/insert.ts b/drizzle-orm/src/singlestore-core/query-builders/insert.ts new file mode 100644 index 000000000..78a19c784 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/insert.ts @@ -0,0 +1,305 @@ +import { entityKind, is } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { RunnableQuery } from '~/runnable-query.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; +import { Param, SQL, sql } from '~/sql/sql.ts'; +import type { InferModelFromColumns } from '~/table.ts'; +import { Table } from '~/table.ts'; +import { mapUpdateSet, orderSelectedFields } from '~/utils.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; +import type { SingleStoreUpdateSetSource } from './update.ts'; + +export interface SingleStoreInsertConfig { + table: TTable; + values: Record[]; + ignore: boolean; + onConflict?: SQL; + returning?: SelectedFieldsOrdered; +} + +export type AnySingleStoreInsertConfig = SingleStoreInsertConfig; + +export type SingleStoreInsertValue = + & { + [Key in keyof TTable['$inferInsert']]: TTable['$inferInsert'][Key] | SQL | Placeholder; + } + & {}; + +export class SingleStoreInsertBuilder< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> { + static readonly [entityKind]: string = 'SingleStoreInsertBuilder'; + + private shouldIgnore = false; + + constructor( + private table: TTable, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) {} + + ignore(): this { + this.shouldIgnore = true; + return this; + } + + values(value: SingleStoreInsertValue): SingleStoreInsertBase; + values(values: SingleStoreInsertValue[]): SingleStoreInsertBase; + values( + values: SingleStoreInsertValue | SingleStoreInsertValue[], + ): SingleStoreInsertBase { + values = Array.isArray(values) ? values : [values]; + if (values.length === 0) { + throw new Error('values() must be called with at least one value'); + } + const mappedValues = values.map((entry) => { + const result: Record = {}; + const cols = this.table[Table.Symbol.Columns]; + for (const colKey of Object.keys(entry)) { + const colValue = entry[colKey as keyof typeof entry]; + result[colKey] = is(colValue, SQL) ? colValue : new Param(colValue, cols[colKey]); + } + return result; + }); + + return new SingleStoreInsertBase(this.table, mappedValues, this.shouldIgnore, this.session, this.dialect); + } +} + +export type SingleStoreInsertWithout< + T extends AnySingleStoreInsert, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + T['_']['returning'], + TDynamic, + T['_']['excludedMethods'] | '$returning' + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreInsertDynamic = SingleStoreInsert< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + T['_']['returning'] +>; + +export type SingleStoreInsertPrepare< + T extends AnySingleStoreInsert, + TReturning extends Record | undefined = undefined, +> = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[]; + iterator: never; + }, + true +>; + +export type SingleStoreInsertOnDuplicateKeyUpdateConfig = { + set: SingleStoreUpdateSetSource; +}; + +export type SingleStoreInsert< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TReturning extends Record | undefined = Record | undefined, +> = SingleStoreInsertBase; + +export type SingleStoreInsertReturning< + T extends AnySingleStoreInsert, + TDynamic extends boolean, +> = SingleStoreInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + InferModelFromColumns>, + TDynamic, + T['_']['excludedMethods'] | '$returning' +>; + +export type AnySingleStoreInsert = SingleStoreInsertBase; + +export interface SingleStoreInsertBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TReturning extends Record | undefined = undefined, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends + QueryPromise : TReturning[]>, + RunnableQuery< + TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[], + 'singlestore' + >, + SQLWrapper +{ + readonly _: { + readonly dialect: 'singlestore'; + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly returning: TReturning; + readonly result: TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[]; + }; +} + +export type PrimaryKeyKeys> = { + [K in keyof T]: T[K]['_']['isPrimaryKey'] extends true ? T[K]['_']['isAutoincrement'] extends true ? K + : T[K]['_']['hasRuntimeDefault'] extends true ? T[K]['_']['isPrimaryKey'] extends true ? K : never + : never + : T[K]['_']['hasRuntimeDefault'] extends true ? T[K]['_']['isPrimaryKey'] extends true ? K : never + : never; +}[keyof T]; + +export type GetPrimarySerialOrDefaultKeys> = { + [K in PrimaryKeyKeys]: T[K]; +}; + +export class SingleStoreInsertBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TReturning extends Record | undefined = undefined, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise : TReturning[]> + implements + RunnableQuery< + TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[], + 'singlestore' + >, + SQLWrapper +{ + static override readonly [entityKind]: string = 'SingleStoreInsert'; + + declare protected $table: TTable; + + private config: SingleStoreInsertConfig; + + constructor( + table: TTable, + values: SingleStoreInsertConfig['values'], + ignore: boolean, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { table, values, ignore }; + } + + /** + * Adds an `on duplicate key update` clause to the query. + * + * Calling this method will update update the row if any unique index conflicts. SingleStore will automatically determine the conflict target based on the primary key and unique indexes. + * + * See docs: {@link https://orm.drizzle.team/docs/insert#on-duplicate-key-update} + * + * @param config The `set` clause + * + * @example + * ```ts + * await db.insert(cars) + * .values({ id: 1, brand: 'BMW'}) + * .onDuplicateKeyUpdate({ set: { brand: 'Porsche' }}); + * ``` + * + * While SingleStore does not directly support doing nothing on conflict, you can perform a no-op by setting any column's value to itself and achieve the same effect: + * + * ```ts + * import { sql } from 'drizzle-orm'; + * + * await db.insert(cars) + * .values({ id: 1, brand: 'BMW' }) + * .onDuplicateKeyUpdate({ set: { id: sql`id` } }); + * ``` + */ + onDuplicateKeyUpdate( + config: SingleStoreInsertOnDuplicateKeyUpdateConfig, + ): SingleStoreInsertWithout { + const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set)); + this.config.onConflict = sql`update ${setSql}`; + return this as any; + } + + $returningId(): SingleStoreInsertWithout< + SingleStoreInsertReturning, + TDynamic, + '$returningId' + > { + const returning: SelectedFieldsOrdered = []; + for (const [key, value] of Object.entries(this.config.table[Table.Symbol.Columns])) { + if (value.primary) { + returning.push({ field: value, path: [key] }); + } + } + this.config.returning = orderSelectedFields(this.config.table[Table.Symbol.Columns]); + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildInsertQuery(this.config).sql; + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreInsertPrepare { + const { sql, generatedIds } = this.dialect.buildInsertQuery(this.config); + return this.session.prepareQuery( + this.dialect.sqlToQuery(sql), + undefined, + undefined, + generatedIds, + this.config.returning, + ) as SingleStoreInsertPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreInsertDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts new file mode 100644 index 000000000..3e174c869 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts @@ -0,0 +1,158 @@ +import { entityKind } from '~/entity.ts'; +import type { ColumnBaseConfig, ColumnDataType } from '~/index.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { SingleStoreColumn } from '../columns/common.ts'; +import type { SingleStoreTable } from '../table.ts'; + +export type OptimizeTableArgument = + | 'FULL' + | 'FLUSH' + | 'FIX_ALTER' + | 'INDEX'; + +export type SingleStoreOptimizeTableWithout< + T extends AnySingleStoreOptimizeTableBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreOptimizeTableBase< + T['_']['table'], + T['_']['arg'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreOptimizeTable< + TTable extends SingleStoreTable = SingleStoreTable, + TArg extends OptimizeTableArgument = OptimizeTableArgument, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreOptimizeTableBase; + +export interface SingleStoreOptimizeTableConfig { + table: SingleStoreTable; + arg?: OptimizeTableArgument | undefined; + selection?: SingleStoreColumn, object>[] | undefined; +} + +export type SingleStoreOptimizeTablePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreOptimizeTableDynamic = SingleStoreOptimizeTable< + T['_']['table'], + T['_']['arg'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreOptimizeTableBase = SingleStoreOptimizeTableBase; + +export interface SingleStoreOptimizeTableBase< + TTable extends SingleStoreTable, + TArg extends OptimizeTableArgument, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly table: TTable; + readonly arg: TArg | undefined; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreOptimizeTableBase< + TTable extends SingleStoreTable, + TArg extends OptimizeTableArgument, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreOptimizeTable'; + + private config: SingleStoreOptimizeTableConfig; + + constructor( + private table: TTable, + private arg: TArg | undefined, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { table, arg }; + } + + // TODO(singlestore): docs + warmBlobCacheForColumn( + ...selection: SingleStoreColumn, object>[] + ): SingleStoreOptimizeTableWithout { + if (this.config.arg) { + throw new Error('Cannot call warmBlobCacheForColumn with an argument'); + } + this.config.selection = selection; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildOptimizeTable(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreOptimizeTablePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreOptimizeTablePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreOptimizeTableDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts b/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts new file mode 100644 index 000000000..29d6c2290 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts @@ -0,0 +1,114 @@ +import { entityKind, is } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreDialectConfig } from '~/singlestore-core/dialect.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { WithSubqueryWithSelection } from '~/singlestore-core/subquery.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import { WithSubquery } from '~/subquery.ts'; +import { SingleStoreSelectBuilder } from './select.ts'; +import type { SelectedFields } from './select.types.ts'; + +export class QueryBuilder { + static readonly [entityKind]: string = 'SingleStoreQueryBuilder'; + + private dialect: SingleStoreDialect | undefined; + private dialectConfig: SingleStoreDialectConfig | undefined; + + constructor(dialect?: SingleStoreDialect | SingleStoreDialectConfig) { + this.dialect = is(dialect, SingleStoreDialect) ? dialect : undefined; + this.dialectConfig = is(dialect, SingleStoreDialect) ? undefined : dialect; + } + + $with(alias: TAlias) { + const queryBuilder = this; + + return { + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): WithSubqueryWithSelection { + if (typeof qb === 'function') { + qb = qb(queryBuilder); + } + + return new Proxy( + new WithSubquery(qb.getSQL(), qb.getSelectedFields() as SelectedFields, alias, true), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as WithSubqueryWithSelection; + }, + }; + } + + with(...queries: WithSubquery[]) { + const self = this; + + function select(): SingleStoreSelectBuilder; + function select( + fields: TSelection, + ): SingleStoreSelectBuilder; + function select( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: self.getDialect(), + withList: queries, + }); + } + + function selectDistinct(): SingleStoreSelectBuilder; + function selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + function selectDistinct( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: self.getDialect(), + withList: queries, + distinct: true, + }); + } + + return { select, selectDistinct }; + } + + select(): SingleStoreSelectBuilder; + select(fields: TSelection): SingleStoreSelectBuilder; + select( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: this.getDialect(), + }); + } + + selectDistinct(): SingleStoreSelectBuilder; + selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + selectDistinct( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: this.getDialect(), + distinct: true, + }); + } + + // Lazy load dialect to avoid circular dependency + private getDialect() { + if (!this.dialect) { + this.dialect = new SingleStoreDialect(this.dialectConfig); + } + + return this.dialect; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/query.ts b/drizzle-orm/src/singlestore-core/query-builders/query.ts new file mode 100644 index 000000000..c15f7ad59 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/query.ts @@ -0,0 +1,141 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { + type BuildQueryResult, + type BuildRelationalQueryResult, + type DBQueryConfig, + mapRelationalRow, + type TableRelationalConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import type { Query, QueryWithTypings, SQL } from '~/sql/sql.ts'; +import type { KnownKeysOnly } from '~/utils.ts'; +import type { SingleStoreDialect } from '../dialect.ts'; +import type { + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreSession, +} from '../session.ts'; +import type { SingleStoreTable } from '../table.ts'; + +export class RelationalQueryBuilder< + TPreparedQueryHKT extends PreparedQueryHKTBase, + TSchema extends TablesRelationalConfig, + TFields extends TableRelationalConfig, +> { + static readonly [entityKind]: string = 'SingleStoreRelationalQueryBuilder'; + + constructor( + private fullSchema: Record, + private schema: TSchema, + private tableNamesMap: Record, + private table: SingleStoreTable, + private tableConfig: TableRelationalConfig, + private dialect: SingleStoreDialect, + private session: SingleStoreSession, + ) {} + + findMany>( + config?: KnownKeysOnly>, + ): SingleStoreRelationalQuery[]> { + return new SingleStoreRelationalQuery( + this.fullSchema, + this.schema, + this.tableNamesMap, + this.table, + this.tableConfig, + this.dialect, + this.session, + config ? (config as DBQueryConfig<'many', true>) : {}, + 'many', + ); + } + + findFirst, 'limit'>>( + config?: KnownKeysOnly, 'limit'>>, + ): SingleStoreRelationalQuery | undefined> { + return new SingleStoreRelationalQuery( + this.fullSchema, + this.schema, + this.tableNamesMap, + this.table, + this.tableConfig, + this.dialect, + this.session, + config ? { ...(config as DBQueryConfig<'many', true> | undefined), limit: 1 } : { limit: 1 }, + 'first', + ); + } +} + +export class SingleStoreRelationalQuery< + TPreparedQueryHKT extends PreparedQueryHKTBase, + TResult, +> extends QueryPromise { + static override readonly [entityKind]: string = 'SingleStoreRelationalQuery'; + + declare protected $brand: 'SingleStoreRelationalQuery'; + + constructor( + private fullSchema: Record, + private schema: TablesRelationalConfig, + private tableNamesMap: Record, + private table: SingleStoreTable, + private tableConfig: TableRelationalConfig, + private dialect: SingleStoreDialect, + private session: SingleStoreSession, + private config: DBQueryConfig<'many', true> | true, + private queryMode: 'many' | 'first', + ) { + super(); + } + + prepare() { + const { query, builtQuery } = this._toSQL(); + return this.session.prepareQuery( + builtQuery, + undefined, + (rawRows) => { + const rows = rawRows.map((row) => mapRelationalRow(this.schema, this.tableConfig, row, query.selection)); + if (this.queryMode === 'first') { + return rows[0] as TResult; + } + return rows as TResult; + }, + ) as PreparedQueryKind; + } + + private _getQuery() { + return this.dialect.buildRelationalQuery({ + fullSchema: this.fullSchema, + schema: this.schema, + tableNamesMap: this.tableNamesMap, + table: this.table, + tableConfig: this.tableConfig, + queryConfig: this.config, + tableAlias: this.tableConfig.tsName, + }); + } + + private _toSQL(): { query: BuildRelationalQueryResult; builtQuery: QueryWithTypings } { + const query = this._getQuery(); + + const builtQuery = this.dialect.sqlToQuery(query.sql as SQL); + + return { builtQuery, query }; + } + + /** @internal */ + getSQL(): SQL { + return this._getQuery().sql as SQL; + } + + toSQL(): Query { + return this._toSQL().builtQuery; + } + + override execute(): Promise { + return this.prepare().execute(); + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.ts b/drizzle-orm/src/singlestore-core/query-builders/select.ts new file mode 100644 index 000000000..0fcefaf85 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/select.ts @@ -0,0 +1,1084 @@ +import { entityKind, is } from '~/entity.ts'; +import { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { + BuildSubquerySelection, + GetSelectTableName, + GetSelectTableSelection, + JoinNullability, + JoinType, + SelectMode, + SelectResult, + SetOperator, +} from '~/query-builders/select.types.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreColumn } from '~/singlestore-core/columns/index.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + PreparedQueryHKTBase, + SingleStorePreparedQueryConfig, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SubqueryWithSelection } from '~/singlestore-core/subquery.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { ColumnsSelection, Query } from '~/sql/sql.ts'; +import { SQL, View } from '~/sql/sql.ts'; +import { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; +import { + applyMixins, + getTableColumns, + getTableLikeName, + haveSameKeys, + orderSelectedFields, + type ValueOrArray, +} from '~/utils.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import { SingleStoreViewBase } from '../view-base.ts'; +import type { + AnySingleStoreSelect, + CreateSingleStoreSelectFromBuilderMode, + GetSingleStoreSetOperators, + LockConfig, + LockStrength, + SelectedFields, + SetOperatorRightSelect, + SingleStoreCreateSetOperatorFn, + SingleStoreJoinFn, + SingleStoreSelectConfig, + SingleStoreSelectDynamic, + SingleStoreSelectHKT, + SingleStoreSelectHKTBase, + SingleStoreSelectPrepare, + SingleStoreSelectWithout, + SingleStoreSetOperatorExcludedMethods, + SingleStoreSetOperatorWithResult, +} from './select.types.ts'; + +export class SingleStoreSelectBuilder< + TSelection extends SelectedFields | undefined, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TBuilderMode extends 'db' | 'qb' = 'db', +> { + static readonly [entityKind]: string = 'SingleStoreSelectBuilder'; + + private fields: TSelection; + private session: SingleStoreSession | undefined; + private dialect: SingleStoreDialect; + private withList: Subquery[] = []; + private distinct: boolean | undefined; + + constructor( + config: { + fields: TSelection; + session: SingleStoreSession | undefined; + dialect: SingleStoreDialect; + withList?: Subquery[]; + distinct?: boolean; + }, + ) { + this.fields = config.fields; + this.session = config.session; + this.dialect = config.dialect; + if (config.withList) { + this.withList = config.withList; + } + this.distinct = config.distinct; + } + + from( + source: TFrom, + ): CreateSingleStoreSelectFromBuilderMode< + TBuilderMode, + GetSelectTableName, + TSelection extends undefined ? GetSelectTableSelection : TSelection, + TSelection extends undefined ? 'single' : 'partial', + TPreparedQueryHKT + > { + const isPartialSelect = !!this.fields; + + let fields: SelectedFields; + if (this.fields) { + fields = this.fields; + } else if (is(source, Subquery)) { + // This is required to use the proxy handler to get the correct field values from the subquery + fields = Object.fromEntries( + Object.keys(source._.selectedFields).map(( + key, + ) => [key, source[key as unknown as keyof typeof source] as unknown as SelectedFields[string]]), + ); + } else if (is(source, SingleStoreViewBase)) { + fields = source[ViewBaseConfig].selectedFields as SelectedFields; + } else if (is(source, SQL)) { + fields = {}; + } else { + fields = getTableColumns(source); + } + + return new SingleStoreSelectBase( + { + table: source, + fields, + isPartialSelect, + session: this.session, + dialect: this.dialect, + withList: this.withList, + distinct: this.distinct, + }, + ) as any; + } +} + +export abstract class SingleStoreSelectQueryBuilderBase< + THKT extends SingleStoreSelectHKTBase, + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends TypedQueryBuilder { + static override readonly [entityKind]: string = 'SingleStoreSelectQueryBuilder'; + + override readonly _: { + readonly hkt: THKT; + readonly tableName: TTableName; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; + }; + + protected config: SingleStoreSelectConfig; + protected joinsNotNullableMap: Record; + private tableName: string | undefined; + private isPartialSelect: boolean; + /** @internal */ + readonly session: SingleStoreSession | undefined; + protected dialect: SingleStoreDialect; + + constructor( + { table, fields, isPartialSelect, session, dialect, withList, distinct }: { + table: SingleStoreSelectConfig['table']; + fields: SingleStoreSelectConfig['fields']; + isPartialSelect: boolean; + session: SingleStoreSession | undefined; + dialect: SingleStoreDialect; + withList: Subquery[]; + distinct: boolean | undefined; + }, + ) { + super(); + this.config = { + withList, + table, + fields: { ...fields }, + distinct, + setOperators: [], + }; + this.isPartialSelect = isPartialSelect; + this.session = session; + this.dialect = dialect; + this._ = { + selectedFields: fields as TSelectedFields, + } as this['_']; + this.tableName = getTableLikeName(table); + this.joinsNotNullableMap = typeof this.tableName === 'string' ? { [this.tableName]: true } : {}; + } + + private createJoin( + joinType: TJoinType, + ): SingleStoreJoinFn { + return ( + table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL, + on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, + ) => { + const baseTableName = this.tableName; + const tableName = getTableLikeName(table); + + if (typeof tableName === 'string' && this.config.joins?.some((join) => join.alias === tableName)) { + throw new Error(`Alias "${tableName}" is already used in this query`); + } + + if (!this.isPartialSelect) { + // If this is the first join and this is not a partial select and we're not selecting from raw SQL, "move" the fields from the main table to the nested object + if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === 'string') { + this.config.fields = { + [baseTableName]: this.config.fields, + }; + } + if (typeof tableName === 'string' && !is(table, SQL)) { + const selection = is(table, Subquery) + ? table._.selectedFields + : is(table, View) + ? table[ViewBaseConfig].selectedFields + : table[Table.Symbol.Columns]; + this.config.fields[tableName] = selection; + } + } + + if (typeof on === 'function') { + on = on( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + + if (!this.config.joins) { + this.config.joins = []; + } + + this.config.joins.push({ on, table, joinType, alias: tableName }); + + if (typeof tableName === 'string') { + switch (joinType) { + case 'left': { + this.joinsNotNullableMap[tableName] = false; + break; + } + case 'right': { + this.joinsNotNullableMap = Object.fromEntries( + Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]), + ); + this.joinsNotNullableMap[tableName] = true; + break; + } + case 'inner': { + this.joinsNotNullableMap[tableName] = true; + break; + } + case 'full': { + this.joinsNotNullableMap = Object.fromEntries( + Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]), + ); + this.joinsNotNullableMap[tableName] = false; + break; + } + } + } + + return this as any; + }; + } + + /** + * Executes a `left join` operation by adding another table to the current query. + * + * Calling this method associates each row of the table with the corresponding row from the joined table, if a match is found. If no matching row exists, it sets all columns of the joined table to null. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#left-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User; pets: Pet | null }[] = await db.select() + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + leftJoin = this.createJoin('left'); + + /** + * Executes a `right join` operation by adding another table to the current query. + * + * Calling this method associates each row of the joined table with the corresponding row from the main table, if a match is found. If no matching row exists, it sets all columns of the main table to null. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#right-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User | null; pets: Pet }[] = await db.select() + * .from(users) + * .rightJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number | null; petId: number }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .rightJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + rightJoin = this.createJoin('right'); + + /** + * Executes an `inner join` operation, creating a new table by combining rows from two tables that have matching values. + * + * Calling this method retrieves rows that have corresponding entries in both joined tables. Rows without matching entries in either table are excluded, resulting in a table that includes only matching pairs. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#inner-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User; pets: Pet }[] = await db.select() + * .from(users) + * .innerJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number; petId: number }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .innerJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + innerJoin = this.createJoin('inner'); + + /** + * Executes a `full join` operation by combining rows from two tables into a new table. + * + * Calling this method retrieves all rows from both main and joined tables, merging rows with matching values and filling in `null` for non-matching columns. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#full-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User | null; pets: Pet | null }[] = await db.select() + * .from(users) + * .fullJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number | null; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .fullJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + fullJoin = this.createJoin('full'); + + private createSetOperator( + type: SetOperator, + isAll: boolean, + ): >( + rightSelection: + | ((setOperators: GetSingleStoreSetOperators) => SetOperatorRightSelect) + | SetOperatorRightSelect, + ) => SingleStoreSelectWithout< + this, + TDynamic, + SingleStoreSetOperatorExcludedMethods, + true + > { + return (rightSelection) => { + const rightSelect = (typeof rightSelection === 'function' + ? rightSelection(getSingleStoreSetOperators()) + : rightSelection) as TypedQueryBuilder< + any, + TResult + >; + + if (!haveSameKeys(this.getSelectedFields(), rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + + this.config.setOperators.push({ type, isAll, rightSelect }); + return this as any; + }; + } + + /** + * Adds `union` set operator to the query. + * + * Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union} + * + * @example + * + * ```ts + * // Select all unique names from customers and users tables + * await db.select({ name: users.name }) + * .from(users) + * .union( + * db.select({ name: customers.name }).from(customers) + * ); + * // or + * import { union } from 'drizzle-orm/singlestore-core' + * + * await union( + * db.select({ name: users.name }).from(users), + * db.select({ name: customers.name }).from(customers) + * ); + * ``` + */ + union = this.createSetOperator('union', false); + + /** + * Adds `union all` set operator to the query. + * + * Calling this method will combine the result-set of the `select` statements and keep all duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union-all} + * + * @example + * + * ```ts + * // Select all transaction ids from both online and in-store sales + * await db.select({ transaction: onlineSales.transactionId }) + * .from(onlineSales) + * .unionAll( + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * // or + * import { unionAll } from 'drizzle-orm/singlestore-core' + * + * await unionAll( + * db.select({ transaction: onlineSales.transactionId }).from(onlineSales), + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * ``` + */ + unionAll = this.createSetOperator('union', true); + + /** + * Adds `intersect` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets and eliminate duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect} + * + * @example + * + * ```ts + * // Select course names that are offered in both departments A and B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .intersect( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * import { intersect } from 'drizzle-orm/singlestore-core' + * + * await intersect( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ + intersect = this.createSetOperator('intersect', false); + + /** + * Adds `except` set operator to the query. + * + * Calling this method will retrieve all unique rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except} + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .except( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * import { except } from 'drizzle-orm/singlestore-core' + * + * await except( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ + except = this.createSetOperator('except', false); + + /** + * Adds `minus` set operator to the query. + * + * This is an alias of `except` supported by SingleStore. + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .minus( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * import { minus } from 'drizzle-orm/singlestore-core' + * + * await minus( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ + minus = this.createSetOperator('except', false); + + /** @internal */ + addSetOperators(setOperators: SingleStoreSelectConfig['setOperators']): SingleStoreSelectWithout< + this, + TDynamic, + SingleStoreSetOperatorExcludedMethods, + true + > { + this.config.setOperators.push(...setOperators); + return this as any; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will select only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/select#filtering} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be selected. + * + * ```ts + * // Select all cars with green color + * await db.select().from(cars).where(eq(cars.color, 'green')); + * // or + * await db.select().from(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Select all BMW cars with a green color + * await db.select().from(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Select all cars with the green or blue color + * await db.select().from(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where( + where: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): SingleStoreSelectWithout { + if (typeof where === 'function') { + where = where( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + this.config.where = where; + return this as any; + } + + /** + * Adds a `having` clause to the query. + * + * Calling this method will select only those rows that fulfill a specified condition. It is typically used with aggregate functions to filter the aggregated data based on a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/select#aggregations} + * + * @param having the `having` clause. + * + * @example + * + * ```ts + * // Select all brands with more than one car + * await db.select({ + * brand: cars.brand, + * count: sql`cast(count(${cars.id}) as int)`, + * }) + * .from(cars) + * .groupBy(cars.brand) + * .having(({ count }) => gt(count, 1)); + * ``` + */ + having( + having: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): SingleStoreSelectWithout { + if (typeof having === 'function') { + having = having( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + this.config.having = having; + return this as any; + } + + /** + * Adds a `group by` clause to the query. + * + * Calling this method will group rows that have the same values into summary rows, often used for aggregation purposes. + * + * See docs: {@link https://orm.drizzle.team/docs/select#aggregations} + * + * @example + * + * ```ts + * // Group and count people by their last names + * await db.select({ + * lastName: people.lastName, + * count: sql`cast(count(*) as int)` + * }) + * .from(people) + * .groupBy(people.lastName); + * ``` + */ + groupBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): SingleStoreSelectWithout; + groupBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreSelectWithout; + groupBy( + ...columns: + | [(aliases: this['_']['selection']) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreSelectWithout { + if (typeof columns[0] === 'function') { + const groupBy = columns[0]( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as TSelection, + ); + this.config.groupBy = Array.isArray(groupBy) ? groupBy : [groupBy]; + } else { + this.config.groupBy = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + } + return this as any; + } + + /** + * Adds an `order by` clause to the query. + * + * Calling this method will sort the result-set in ascending or descending order. By default, the sort order is ascending. + * + * See docs: {@link https://orm.drizzle.team/docs/select#order-by} + * + * @example + * + * ``` + * // Select cars ordered by year + * await db.select().from(cars).orderBy(cars.year); + * ``` + * + * You can specify whether results are in ascending or descending order with the `asc()` and `desc()` operators. + * + * ```ts + * // Select cars ordered by year in descending order + * await db.select().from(cars).orderBy(desc(cars.year)); + * + * // Select cars ordered by year and price + * await db.select().from(cars).orderBy(asc(cars.year), desc(cars.price)); + * ``` + */ + orderBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): SingleStoreSelectWithout; + orderBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreSelectWithout; + orderBy( + ...columns: + | [(aliases: this['_']['selection']) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreSelectWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as TSelection, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } + } else { + const orderByArray = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } + } + return this as any; + } + + /** + * Adds a `limit` clause to the query. + * + * Calling this method will set the maximum number of rows that will be returned by this query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset} + * + * @param limit the `limit` clause. + * + * @example + * + * ```ts + * // Get the first 10 people from this query. + * await db.select().from(people).limit(10); + * ``` + */ + limit(limit: number): SingleStoreSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.limit = limit; + } else { + this.config.limit = limit; + } + return this as any; + } + + /** + * Adds an `offset` clause to the query. + * + * Calling this method will skip a number of rows when returning results from this query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset} + * + * @param offset the `offset` clause. + * + * @example + * + * ```ts + * // Get the 10th-20th people from this query. + * await db.select().from(people).offset(10).limit(10); + * ``` + */ + offset(offset: number): SingleStoreSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.offset = offset; + } else { + this.config.offset = offset; + } + return this as any; + } + + /** + * Adds a `for` clause to the query. + * + * Calling this method will specify a lock strength for this query that controls how strictly it acquires exclusive access to the rows being queried. + * + * @param strength the lock strength. + * @param config the lock configuration. + */ + for(strength: LockStrength, config: LockConfig = {}): SingleStoreSelectWithout { + this.config.lockingClause = { strength, config }; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildSelectQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + as( + alias: TAlias, + ): SubqueryWithSelection { + return new Proxy( + new Subquery(this.getSQL(), this.config.fields, alias), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as SubqueryWithSelection; + } + + /** @internal */ + override getSelectedFields(): this['_']['selectedFields'] { + return new Proxy( + this.config.fields, + new SelectionProxyHandler({ alias: this.tableName, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as this['_']['selectedFields']; + } + + $dynamic(): SingleStoreSelectDynamic { + return this as any; + } +} + +export interface SingleStoreSelectBase< + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends + SingleStoreSelectQueryBuilderBase< + SingleStoreSelectHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + QueryPromise +{} + +export class SingleStoreSelectBase< + TTableName extends string | undefined, + TSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, +> extends SingleStoreSelectQueryBuilderBase< + SingleStoreSelectHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields +> { + static override readonly [entityKind]: string = 'SingleStoreSelect'; + + prepare(): SingleStoreSelectPrepare { + if (!this.session) { + throw new Error('Cannot execute a query on a query builder. Please use a database instance instead.'); + } + const fieldsList = orderSelectedFields(this.config.fields); + const query = this.session.prepareQuery< + SingleStorePreparedQueryConfig & { execute: SelectResult[] }, + TPreparedQueryHKT + >(this.dialect.sqlToQuery(this.getSQL()), fieldsList); + query.joinsNotNullableMap = this.joinsNotNullableMap; + return query as SingleStoreSelectPrepare; + } + + execute = ((placeholderValues) => { + return this.prepare().execute(placeholderValues); + }) as ReturnType['execute']; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); +} + +applyMixins(SingleStoreSelectBase, [QueryPromise]); + +function createSetOperator(type: SetOperator, isAll: boolean): SingleStoreCreateSetOperatorFn { + return (leftSelect, rightSelect, ...restSelects) => { + const setOperators = [rightSelect, ...restSelects].map((select) => ({ + type, + isAll, + rightSelect: select as AnySingleStoreSelect, + })); + + for (const setOperator of setOperators) { + if (!haveSameKeys((leftSelect as any).getSelectedFields(), setOperator.rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + } + + return (leftSelect as AnySingleStoreSelect).addSetOperators(setOperators) as any; + }; +} + +const getSingleStoreSetOperators = () => ({ + union, + unionAll, + intersect, + except, + minus, +}); + +/** + * Adds `union` set operator to the query. + * + * Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union} + * + * @example + * + * ```ts + * // Select all unique names from customers and users tables + * import { union } from 'drizzle-orm/singlestore-core' + * + * await union( + * db.select({ name: users.name }).from(users), + * db.select({ name: customers.name }).from(customers) + * ); + * // or + * await db.select({ name: users.name }) + * .from(users) + * .union( + * db.select({ name: customers.name }).from(customers) + * ); + * ``` + */ +export const union = createSetOperator('union', false); + +/** + * Adds `union all` set operator to the query. + * + * Calling this method will combine the result-set of the `select` statements and keep all duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union-all} + * + * @example + * + * ```ts + * // Select all transaction ids from both online and in-store sales + * import { unionAll } from 'drizzle-orm/singlestore-core' + * + * await unionAll( + * db.select({ transaction: onlineSales.transactionId }).from(onlineSales), + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * // or + * await db.select({ transaction: onlineSales.transactionId }) + * .from(onlineSales) + * .unionAll( + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * ``` + */ +export const unionAll = createSetOperator('union', true); + +/** + * Adds `intersect` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets and eliminate duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect} + * + * @example + * + * ```ts + * // Select course names that are offered in both departments A and B + * import { intersect } from 'drizzle-orm/singlestore-core' + * + * await intersect( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .intersect( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ +export const intersect = createSetOperator('intersect', false); + +/** + * Adds `except` set operator to the query. + * + * Calling this method will retrieve all unique rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except} + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * import { except } from 'drizzle-orm/singlestore-core' + * + * await except( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .except( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ +export const except = createSetOperator('except', false); + +/** + * Adds `minus` set operator to the query. + * + * This is an alias of `except` supported by SingleStore. + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * import { minus } from 'drizzle-orm/singlestore-core' + * + * await minus( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .minus( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ +export const minus = createSetOperator('except', true); diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts new file mode 100644 index 000000000..6db1cc357 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts @@ -0,0 +1,457 @@ +import type { + SelectedFields as SelectedFieldsBase, + SelectedFieldsFlat as SelectedFieldsFlatBase, + SelectedFieldsOrdered as SelectedFieldsOrderedBase, +} from '~/operations.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { + AppendToNullabilityMap, + AppendToResult, + BuildSubquerySelection, + GetSelectTableName, + JoinNullability, + JoinType, + MapColumnsToTableAlias, + SelectMode, + SelectResult, + SetOperator, +} from '~/query-builders/select.types.ts'; +import type { SingleStoreColumn } from '~/singlestore-core/columns/index.ts'; +import type { SingleStoreTable, SingleStoreTableWithColumns } from '~/singlestore-core/table.ts'; +import type { ColumnsSelection, Placeholder, SQL, View } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import type { Table, UpdateTableConfig } from '~/table.ts'; +import type { Assume, ValidateShape } from '~/utils.ts'; +import type { PreparedQueryHKTBase, PreparedQueryKind, SingleStorePreparedQueryConfig } from '../session.ts'; +import type { SingleStoreViewBase } from '../view-base.ts'; +import type { SingleStoreViewWithSelection } from '../view.ts'; +import type { SingleStoreSelectBase, SingleStoreSelectQueryBuilderBase } from './select.ts'; + +export interface SingleStoreSelectJoinConfig { + on: SQL | undefined; + table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL; + alias: string | undefined; + joinType: JoinType; + lateral?: boolean; +} + +export type BuildAliasTable = TTable extends Table + ? SingleStoreTableWithColumns< + UpdateTableConfig; + }> + > + : TTable extends View ? SingleStoreViewWithSelection< + TAlias, + TTable['_']['existing'], + MapColumnsToTableAlias + > + : never; + +export interface SingleStoreSelectConfig { + withList?: Subquery[]; + fields: Record; + fieldsFlat?: SelectedFieldsOrdered; + where?: SQL; + having?: SQL; + table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL; + limit?: number | Placeholder; + offset?: number | Placeholder; + joins?: SingleStoreSelectJoinConfig[]; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + groupBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + lockingClause?: { + strength: LockStrength; + config: LockConfig; + }; + distinct?: boolean; + setOperators: { + rightSelect: TypedQueryBuilder; + type: SetOperator; + isAll: boolean; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + limit?: number | Placeholder; + offset?: number | Placeholder; + }[]; +} + +export type SingleStoreJoin< + T extends AnySingleStoreSelectQueryBuilder, + TDynamic extends boolean, + TJoinType extends JoinType, + TJoinedTable extends SingleStoreTable | Subquery | SingleStoreViewBase | SQL, + TJoinedName extends GetSelectTableName = GetSelectTableName, +> = T extends any ? SingleStoreSelectWithout< + SingleStoreSelectKind< + T['_']['hkt'], + T['_']['tableName'], + AppendToResult< + T['_']['tableName'], + T['_']['selection'], + TJoinedName, + TJoinedTable extends SingleStoreTable ? TJoinedTable['_']['columns'] + : TJoinedTable extends Subquery ? Assume + : never, + T['_']['selectMode'] + >, + T['_']['selectMode'] extends 'partial' ? T['_']['selectMode'] : 'multiple', + T['_']['preparedQueryHKT'], + AppendToNullabilityMap, + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + T['_']['excludedMethods'] + > + : never; + +export type SingleStoreJoinFn< + T extends AnySingleStoreSelectQueryBuilder, + TDynamic extends boolean, + TJoinType extends JoinType, +> = < + TJoinedTable extends SingleStoreTable | Subquery | SingleStoreViewBase | SQL, + TJoinedName extends GetSelectTableName = GetSelectTableName, +>( + table: TJoinedTable, + on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, +) => SingleStoreJoin; + +export type SelectedFieldsFlat = SelectedFieldsFlatBase; + +export type SelectedFields = SelectedFieldsBase; + +export type SelectedFieldsOrdered = SelectedFieldsOrderedBase; + +export type LockStrength = 'update' | 'share'; + +export type LockConfig = { + noWait: true; + skipLocked?: undefined; +} | { + noWait?: undefined; + skipLocked: true; +} | { + noWait?: undefined; + skipLocked?: undefined; +}; + +export interface SingleStoreSelectHKTBase { + tableName: string | undefined; + selection: unknown; + selectMode: SelectMode; + preparedQueryHKT: unknown; + nullabilityMap: unknown; + dynamic: boolean; + excludedMethods: string; + result: unknown; + selectedFields: unknown; + _type: unknown; +} + +export type SingleStoreSelectKind< + T extends SingleStoreSelectHKTBase, + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record, + TDynamic extends boolean, + TExcludedMethods extends string, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, +> = (T & { + tableName: TTableName; + selection: TSelection; + selectMode: TSelectMode; + preparedQueryHKT: TPreparedQueryHKT; + nullabilityMap: TNullabilityMap; + dynamic: TDynamic; + excludedMethods: TExcludedMethods; + result: TResult; + selectedFields: TSelectedFields; +})['_type']; + +export interface SingleStoreSelectQueryBuilderHKT extends SingleStoreSelectHKTBase { + _type: SingleStoreSelectQueryBuilderBase< + SingleStoreSelectQueryBuilderHKT, + this['tableName'], + Assume, + this['selectMode'], + Assume, + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume + >; +} + +export interface SingleStoreSelectHKT extends SingleStoreSelectHKTBase { + _type: SingleStoreSelectBase< + this['tableName'], + Assume, + this['selectMode'], + Assume, + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume + >; +} + +export type SingleStoreSetOperatorExcludedMethods = + | 'where' + | 'having' + | 'groupBy' + | 'session' + | 'leftJoin' + | 'rightJoin' + | 'innerJoin' + | 'fullJoin' + | 'for'; + +export type SingleStoreSelectWithout< + T extends AnySingleStoreSelectQueryBuilder, + TDynamic extends boolean, + K extends keyof T & string, + TResetExcluded extends boolean = false, +> = TDynamic extends true ? T : Omit< + SingleStoreSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['preparedQueryHKT'], + T['_']['nullabilityMap'], + TDynamic, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K, + T['_']['result'], + T['_']['selectedFields'] + >, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K +>; + +export type SingleStoreSelectPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: T['_']['result']; + iterator: T['_']['result'][number]; + }, + true +>; + +export type SingleStoreSelectDynamic = SingleStoreSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['preparedQueryHKT'], + T['_']['nullabilityMap'], + true, + never, + T['_']['result'], + T['_']['selectedFields'] +>; + +export type CreateSingleStoreSelectFromBuilderMode< + TBuilderMode extends 'db' | 'qb', + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> = TBuilderMode extends 'db' ? SingleStoreSelectBase + : SingleStoreSelectQueryBuilderBase< + SingleStoreSelectQueryBuilderHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT + >; + +export type SingleStoreSelectQueryBuilder< + THKT extends SingleStoreSelectHKTBase = SingleStoreSelectQueryBuilderHKT, + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = ColumnsSelection, + TSelectMode extends SelectMode = SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = Record, + TResult extends any[] = unknown[], + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> = SingleStoreSelectQueryBuilderBase< + THKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + true, + never, + TResult, + TSelectedFields +>; + +export type AnySingleStoreSelectQueryBuilder = SingleStoreSelectQueryBuilderBase< + any, + any, + any, + any, + any, + any, + any, + any, + any +>; + +export type AnySingleStoreSetOperatorInterface = SingleStoreSetOperatorInterface< + any, + any, + any, + any, + any, + any, + any, + any, + any +>; + +export interface SingleStoreSetOperatorInterface< + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> { + _: { + readonly hkt: SingleStoreSelectHKT; + readonly tableName: TTableName; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; + }; +} + +export type SingleStoreSetOperatorWithResult = SingleStoreSetOperatorInterface< + any, + any, + any, + any, + any, + any, + any, + TResult, + any +>; + +export type SingleStoreSelect< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TNullabilityMap extends Record = Record, +> = SingleStoreSelectBase; + +export type AnySingleStoreSelect = SingleStoreSelectBase; + +export type SingleStoreSetOperator< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = Record, +> = SingleStoreSelectBase< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + true, + SingleStoreSetOperatorExcludedMethods +>; + +export type SetOperatorRightSelect< + TValue extends SingleStoreSetOperatorWithResult, + TResult extends any[], +> = TValue extends SingleStoreSetOperatorInterface + ? ValidateShape< + TValueResult[number], + TResult[number], + TypedQueryBuilder + > + : TValue; + +export type SetOperatorRestSelect< + TValue extends readonly SingleStoreSetOperatorWithResult[], + TResult extends any[], +> = TValue extends [infer First, ...infer Rest] + ? First extends SingleStoreSetOperatorInterface + ? Rest extends AnySingleStoreSetOperatorInterface[] ? [ + ValidateShape>, + ...SetOperatorRestSelect, + ] + : ValidateShape[]> + : never + : TValue; + +export type SingleStoreCreateSetOperatorFn = < + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TValue extends SingleStoreSetOperatorWithResult, + TRest extends SingleStoreSetOperatorWithResult[], + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +>( + leftSelect: SingleStoreSetOperatorInterface< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + rightSelect: SetOperatorRightSelect, + ...restSelects: SetOperatorRestSelect +) => SingleStoreSelectWithout< + SingleStoreSelectBase< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + false, + SingleStoreSetOperatorExcludedMethods, + true +>; + +export type GetSingleStoreSetOperators = { + union: SingleStoreCreateSetOperatorFn; + intersect: SingleStoreCreateSetOperatorFn; + except: SingleStoreCreateSetOperatorFn; + unionAll: SingleStoreCreateSetOperatorFn; + minus: SingleStoreCreateSetOperatorFn; +}; diff --git a/drizzle-orm/src/singlestore-core/query-builders/update.ts b/drizzle-orm/src/singlestore-core/query-builders/update.ts new file mode 100644 index 000000000..40ca97662 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/update.ts @@ -0,0 +1,251 @@ +import type { GetColumnData } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; +import { mapUpdateSet, type UpdateSet, type ValueOrArray } from '~/utils.ts'; +import type { SingleStoreColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; + +export interface SingleStoreUpdateConfig { + where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + set: UpdateSet; + table: SingleStoreTable; + returning?: SelectedFieldsOrdered; + withList?: Subquery[]; +} + +export type SingleStoreUpdateSetSource = + & { + [Key in keyof TTable['$inferInsert']]?: + | GetColumnData + | SQL; + } + & {}; + +export class SingleStoreUpdateBuilder< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> { + static readonly [entityKind]: string = 'SingleStoreUpdateBuilder'; + + declare readonly _: { + readonly table: TTable; + }; + + constructor( + private table: TTable, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + private withList?: Subquery[], + ) {} + + set(values: SingleStoreUpdateSetSource): SingleStoreUpdateBase { + return new SingleStoreUpdateBase( + this.table, + mapUpdateSet(this.table, values), + this.session, + this.dialect, + this.withList, + ); + } +} + +export type SingleStoreUpdateWithout< + T extends AnySingleStoreUpdateBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T : Omit< + SingleStoreUpdateBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K +>; + +export type SingleStoreUpdatePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +export type SingleStoreUpdateDynamic = SingleStoreUpdate< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +export type SingleStoreUpdate< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreUpdateBase; + +export type AnySingleStoreUpdateBase = SingleStoreUpdateBase; + +export interface SingleStoreUpdateBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise>, SQLWrapper { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreUpdateBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreUpdate'; + + private config: SingleStoreUpdateConfig; + + constructor( + table: TTable, + set: UpdateSet, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + withList?: Subquery[], + ) { + super(); + this.config = { set, table, withList }; + } + + /** + * Adds a 'where' clause to the query. + * + * Calling this method will update only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param where the 'where' clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be updated. + * + * ```ts + * // Update all cars with green color + * db.update(cars).set({ color: 'red' }) + * .where(eq(cars.color, 'green')); + * // or + * db.update(cars).set({ color: 'red' }) + * .where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Update all BMW cars with a green color + * db.update(cars).set({ color: 'red' }) + * .where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Update all cars with the green or blue color + * db.update(cars).set({ color: 'red' }) + * .where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where(where: SQL | undefined): SingleStoreUpdateWithout { + this.config.where = where; + return this as any; + } + + orderBy( + builder: (updateTable: TTable) => ValueOrArray, + ): SingleStoreUpdateWithout; + orderBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreUpdateWithout; + orderBy( + ...columns: + | [(updateTable: TTable) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreUpdateWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): SingleStoreUpdateWithout { + this.config.limit = limit; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildUpdateQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreUpdatePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + this.config.returning, + ) as SingleStoreUpdatePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreUpdateDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts new file mode 100644 index 000000000..82da44a49 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -0,0 +1,41 @@ +import { entityKind, is } from '~/entity.ts'; +import { type SingleStoreTableFn, singlestoreTableWithSchema } from './table.ts'; +import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; + +export class SingleStoreSchema { + static readonly [entityKind]: string = 'SingleStoreSchema'; + + constructor( + public readonly schemaName: TName, + ) {} + + table: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, this.schemaName); + }; + + view = ((name, columns) => { + return singlestoreViewWithSchema(name, columns, this.schemaName); + }) as typeof singlestoreView; +} + +/** @deprecated - use `instanceof SingleStoreSchema` */ +export function isSingleStoreSchema(obj: unknown): obj is SingleStoreSchema { + return is(obj, SingleStoreSchema); +} + +/** + * Create a SingleStore schema. + * https://dev.mysql.com/doc/refman/8.0/en/create-database.html + * TODO(singlestore) + * + * @param name singlestore use schema name + * @returns SingleStore schema + */ +export function singlestoreDatabase(name: TName) { + return new SingleStoreSchema(name); +} + +/** + * @see singlestoreDatabase + */ +export const singlestoreSchema = singlestoreDatabase; diff --git a/drizzle-orm/src/singlestore-core/session.ts b/drizzle-orm/src/singlestore-core/session.ts new file mode 100644 index 000000000..1b7f076d6 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/session.ts @@ -0,0 +1,159 @@ +import { entityKind } from '~/entity.ts'; +import { TransactionRollbackError } from '~/errors.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { type Query, type SQL, sql } from '~/sql/sql.ts'; +import type { Assume, Equal } from '~/utils.ts'; +import { SingleStoreDatabase } from './db.ts'; +import type { SingleStoreDialect } from './dialect.ts'; +import type { SelectedFieldsOrdered } from './query-builders/select.types.ts'; + +export type Mode = 'default' | 'planetscale'; + +export interface SingleStoreQueryResultHKT { + readonly $brand: 'SingleStoreQueryResultHKT'; + readonly row: unknown; + readonly type: unknown; +} + +export interface AnySingleStoreQueryResultHKT extends SingleStoreQueryResultHKT { + readonly type: any; +} + +export type SingleStoreQueryResultKind = (TKind & { + readonly row: TRow; +})['type']; + +export interface SingleStorePreparedQueryConfig { + execute: unknown; + iterator: unknown; +} + +export interface SingleStorePreparedQueryHKT { + readonly $brand: 'SingleStorePreparedQueryHKT'; + readonly config: unknown; + readonly type: unknown; +} + +export type PreparedQueryKind< + TKind extends SingleStorePreparedQueryHKT, + TConfig extends SingleStorePreparedQueryConfig, + TAssume extends boolean = false, +> = Equal extends true + ? Assume<(TKind & { readonly config: TConfig })['type'], SingleStorePreparedQuery> + : (TKind & { readonly config: TConfig })['type']; + +export abstract class SingleStorePreparedQuery { + static readonly [entityKind]: string = 'SingleStorePreparedQuery'; + + /** @internal */ + joinsNotNullableMap?: Record; + + abstract execute(placeholderValues?: Record): Promise; + + abstract iterator(placeholderValues?: Record): AsyncGenerator; +} + +export interface SingleStoreTransactionConfig { + withConsistentSnapshot?: boolean; + accessMode?: 'read only' | 'read write'; + isolationLevel: 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable'; +} + +export abstract class SingleStoreSession< + TQueryResult extends SingleStoreQueryResultHKT = SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TFullSchema extends Record = Record, + TSchema extends TablesRelationalConfig = Record, +> { + static readonly [entityKind]: string = 'SingleStoreSession'; + + constructor(protected dialect: SingleStoreDialect) {} + + abstract prepareQuery< + T extends SingleStorePreparedQueryConfig, + TPreparedQueryHKT extends SingleStorePreparedQueryHKT, + >( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind; + + execute(query: SQL): Promise { + return this.prepareQuery( + this.dialect.sqlToQuery(query), + undefined, + ).execute(); + } + + abstract all(query: SQL): Promise; + + async count(sql: SQL): Promise { + const res = await this.execute<[[{ count: string }]]>(sql); + + return Number( + res[0][0]['count'], + ); + } + + abstract transaction( + transaction: (tx: SingleStoreTransaction) => Promise, + config?: SingleStoreTransactionConfig, + ): Promise; + + protected getSetTransactionSQL(config: SingleStoreTransactionConfig): SQL | undefined { + const parts: string[] = []; + + if (config.isolationLevel) { + parts.push(`isolation level ${config.isolationLevel}`); + } + + return parts.length ? sql`set transaction ${sql.raw(parts.join(' '))}` : undefined; + } + + protected getStartTransactionSQL(config: SingleStoreTransactionConfig): SQL | undefined { + const parts: string[] = []; + + if (config.withConsistentSnapshot) { + parts.push('with consistent snapshot'); + } + + if (config.accessMode) { + parts.push(config.accessMode); + } + + return parts.length ? sql`start transaction ${sql.raw(parts.join(' '))}` : undefined; + } +} + +export abstract class SingleStoreTransaction< + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record = Record, + TSchema extends TablesRelationalConfig = Record, +> extends SingleStoreDatabase { + static override readonly [entityKind]: string = 'SingleStoreTransaction'; + + constructor( + dialect: SingleStoreDialect, + session: SingleStoreSession, + protected schema: RelationalSchemaConfig | undefined, + protected readonly nestedIndex: number, + ) { + super(dialect, session, schema); + } + + rollback(): never { + throw new TransactionRollbackError(); + } + + /** Nested transactions (aka savepoints) only work with InnoDB engine. */ + abstract override transaction( + transaction: (tx: SingleStoreTransaction) => Promise, + ): Promise; +} + +export interface PreparedQueryHKTBase extends SingleStorePreparedQueryHKT { + type: SingleStorePreparedQuery>; +} diff --git a/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts new file mode 100644 index 000000000..95cffabdd --- /dev/null +++ b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts @@ -0,0 +1,22 @@ +import { bindIfParam } from '~/sql/expressions/conditions.ts'; +import { type SQL, sql } from '~/sql/sql.ts'; +import type { Table } from '~/table'; + +/** + * Test that two values match. + * + * ## Examples + * + * ```ts + * // Select cars made by Ford + * db.select().from(cars) + * .where(match(cars.make, 'Ford')) + * ``` + * + * @see isNull for a way to test equality to NULL. + */ +export function match< + TTable extends Table, +>(left: TTable, right: unknown): SQL { + return sql`MATCH (TABLE ${left}) AGAINST (${bindIfParam(right, left)})`; +} diff --git a/drizzle-orm/src/singlestore-core/sql/expressions/index.ts b/drizzle-orm/src/singlestore-core/sql/expressions/index.ts new file mode 100644 index 000000000..81cb13770 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/sql/expressions/index.ts @@ -0,0 +1 @@ +export * from './conditions.ts'; diff --git a/drizzle-orm/src/singlestore-core/sql/index.ts b/drizzle-orm/src/singlestore-core/sql/index.ts new file mode 100644 index 000000000..16ca76679 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/sql/index.ts @@ -0,0 +1 @@ +export * from './expressions/index.ts'; diff --git a/drizzle-orm/src/singlestore-core/subquery.ts b/drizzle-orm/src/singlestore-core/subquery.ts new file mode 100644 index 000000000..a4605c56d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/subquery.ts @@ -0,0 +1,17 @@ +import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import type { Subquery, WithSubquery } from '~/subquery.ts'; + +export type SubqueryWithSelection< + TSelection extends ColumnsSelection, + TAlias extends string, +> = + & Subquery> + & AddAliasToSelection; + +export type WithSubqueryWithSelection< + TSelection extends ColumnsSelection, + TAlias extends string, +> = + & WithSubquery> + & AddAliasToSelection; diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts new file mode 100644 index 000000000..db24a8587 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -0,0 +1,142 @@ +import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts'; +import { entityKind } from '~/entity.ts'; +import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; +import type { CheckBuilder } from './checks.ts'; +import { getSingleStoreColumnBuilders, type SingleStoreColumnBuilders } from './columns/all.ts'; +import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; +import type { AnyIndexBuilder } from './indexes.ts'; +import type { PrimaryKeyBuilder } from './primary-keys.ts'; +import type { UniqueConstraintBuilder } from './unique-constraint.ts'; + +export type SingleStoreTableExtraConfig = Record< + string, + | AnyIndexBuilder + | CheckBuilder + | PrimaryKeyBuilder + | UniqueConstraintBuilder +>; + +export type TableConfig = TableConfigBase; + +/** @internal */ +export const InlineForeignKeys = Symbol.for('drizzle:SingleStoreInlineForeignKeys'); + +export class SingleStoreTable extends Table { + static override readonly [entityKind]: string = 'SingleStoreTable'; + + declare protected $columns: T['columns']; + + /** @internal */ + static override readonly Symbol = Object.assign({}, Table.Symbol, {}); + + /** @internal */ + override [Table.Symbol.Columns]!: NonNullable; + + /** @internal */ + override [Table.Symbol.ExtraConfigBuilder]: + | ((self: Record) => SingleStoreTableExtraConfig) + | undefined = undefined; +} + +export type AnySingleStoreTable = {}> = SingleStoreTable< + UpdateTableConfig +>; + +export type SingleStoreTableWithColumns = + & SingleStoreTable + & { + [Key in keyof T['columns']]: T['columns'][Key]; + }; + +export function singlestoreTableWithSchema< + TTableName extends string, + TSchemaName extends string | undefined, + TColumnsMap extends Record, +>( + name: TTableName, + columns: TColumnsMap | ((columnTypes: SingleStoreColumnBuilders) => TColumnsMap), + extraConfig: + | ((self: BuildColumns) => SingleStoreTableExtraConfig) + | undefined, + schema: TSchemaName, + baseName = name, +): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; +}> { + const rawTable = new SingleStoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); + + const parsedColumns: TColumnsMap = typeof columns === 'function' ? columns(getSingleStoreColumnBuilders()) : columns; + + const builtColumns = Object.fromEntries( + Object.entries(parsedColumns).map(([name, colBuilderBase]) => { + const colBuilder = colBuilderBase as SingleStoreColumnBuilder; + const column = colBuilder.build(rawTable); + return [name, column]; + }), + ) as unknown as BuildColumns; + + const table = Object.assign(rawTable, builtColumns); + + table[Table.Symbol.Columns] = builtColumns; + table[Table.Symbol.ExtraConfigColumns] = builtColumns as unknown as BuildExtraConfigColumns< + TTableName, + TColumnsMap, + 'singlestore' + >; + + if (extraConfig) { + table[SingleStoreTable.Symbol.ExtraConfigBuilder] = extraConfig as unknown as ( + self: Record, + ) => SingleStoreTableExtraConfig; + } + + return table; +} + +export interface SingleStoreTableFn { + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: TColumnsMap, + extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfig, + ): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: SingleStoreColumnBuilders) => TColumnsMap, + extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfig, + ): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>; +} + +export const singlestoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, undefined, name); +}; + +export function singlestoreTableCreator(customizeTableName: (name: string) => string): SingleStoreTableFn { + return (name, columns, extraConfig) => { + return singlestoreTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); + }; +} diff --git a/drizzle-orm/src/singlestore-core/unique-constraint.ts b/drizzle-orm/src/singlestore-core/unique-constraint.ts new file mode 100644 index 000000000..faa4f3216 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/unique-constraint.ts @@ -0,0 +1,64 @@ +import { entityKind } from '~/entity.ts'; +import type { SingleStoreColumn } from './columns/index.ts'; +import { SingleStoreTable } from './table.ts'; + +export function unique(name?: string): UniqueOnConstraintBuilder { + return new UniqueOnConstraintBuilder(name); +} + +export function uniqueKeyName(table: SingleStoreTable, columns: string[]) { + return `${table[SingleStoreTable.Symbol.Name]}_${columns.join('_')}_unique`; +} + +export class UniqueConstraintBuilder { + static readonly [entityKind]: string = 'SingleStoreUniqueConstraintBuilder'; + + /** @internal */ + columns: SingleStoreColumn[]; + + constructor( + columns: SingleStoreColumn[], + private name?: string, + ) { + this.columns = columns; + } + + /** @internal */ + build(table: SingleStoreTable): UniqueConstraint { + return new UniqueConstraint(table, this.columns, this.name); + } +} + +export class UniqueOnConstraintBuilder { + static readonly [entityKind]: string = 'SingleStoreUniqueOnConstraintBuilder'; + + /** @internal */ + name?: string; + + constructor( + name?: string, + ) { + this.name = name; + } + + on(...columns: [SingleStoreColumn, ...SingleStoreColumn[]]) { + return new UniqueConstraintBuilder(columns, this.name); + } +} + +export class UniqueConstraint { + static readonly [entityKind]: string = 'SingleStoreUniqueConstraint'; + + readonly columns: SingleStoreColumn[]; + readonly name?: string; + readonly nullsNotDistinct: boolean = false; + + constructor(readonly table: SingleStoreTable, columns: SingleStoreColumn[], name?: string) { + this.columns = columns; + this.name = name ?? uniqueKeyName(this.table, this.columns.map((column) => column.name)); + } + + getName() { + return this.name; + } +} diff --git a/drizzle-orm/src/singlestore-core/utils.ts b/drizzle-orm/src/singlestore-core/utils.ts new file mode 100644 index 000000000..e6412161d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/utils.ts @@ -0,0 +1,56 @@ +import { is } from '~/entity.ts'; +import { Table } from '~/table.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import type { Index } from './indexes.ts'; +import { IndexBuilder } from './indexes.ts'; +import type { PrimaryKey } from './primary-keys.ts'; +import { PrimaryKeyBuilder } from './primary-keys.ts'; +import { SingleStoreTable } from './table.ts'; +import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; +import { SingleStoreViewConfig } from './view-common.ts'; +import type { SingleStoreView } from './view.ts'; + +export function getTableConfig(table: SingleStoreTable) { + const columns = Object.values(table[SingleStoreTable.Symbol.Columns]); + const indexes: Index[] = []; + const primaryKeys: PrimaryKey[] = []; + const uniqueConstraints: UniqueConstraint[] = []; + const name = table[Table.Symbol.Name]; + const schema = table[Table.Symbol.Schema]; + const baseName = table[Table.Symbol.BaseName]; + + const extraConfigBuilder = table[SingleStoreTable.Symbol.ExtraConfigBuilder]; + + if (extraConfigBuilder !== undefined) { + const extraConfig = extraConfigBuilder(table[SingleStoreTable.Symbol.Columns]); + for (const builder of Object.values(extraConfig)) { + if (is(builder, IndexBuilder)) { + indexes.push(builder.build(table)); + } else if (is(builder, UniqueConstraintBuilder)) { + uniqueConstraints.push(builder.build(table)); + } else if (is(builder, PrimaryKeyBuilder)) { + primaryKeys.push(builder.build(table)); + } + } + } + + return { + columns, + indexes, + primaryKeys, + uniqueConstraints, + name, + schema, + baseName, + }; +} + +export function getViewConfig< + TName extends string = string, + TExisting extends boolean = boolean, +>(view: SingleStoreView) { + return { + ...view[ViewBaseConfig], + ...view[SingleStoreViewConfig], + }; +} diff --git a/drizzle-orm/src/singlestore-core/view-base.ts b/drizzle-orm/src/singlestore-core/view-base.ts new file mode 100644 index 000000000..1ad8d62d5 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view-base.ts @@ -0,0 +1,15 @@ +import { entityKind } from '~/entity.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import { View } from '~/sql/sql.ts'; + +export abstract class SingleStoreViewBase< + TName extends string = string, + TExisting extends boolean = boolean, + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> extends View { + static override readonly [entityKind]: string = 'SingleStoreViewBase'; + + declare readonly _: View['_'] & { + readonly viewBrand: 'SingleStoreViewBase'; + }; +} diff --git a/drizzle-orm/src/singlestore-core/view-common.ts b/drizzle-orm/src/singlestore-core/view-common.ts new file mode 100644 index 000000000..d29c3d5ad --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view-common.ts @@ -0,0 +1 @@ +export const SingleStoreViewConfig = Symbol.for('drizzle:SingleStoreViewConfig'); diff --git a/drizzle-orm/src/singlestore-core/view.ts b/drizzle-orm/src/singlestore-core/view.ts new file mode 100644 index 000000000..ce0fe4dd3 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view.ts @@ -0,0 +1,208 @@ +import type { BuildColumns } from '~/column-builder.ts'; +import { entityKind } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { ColumnsSelection, SQL } from '~/sql/sql.ts'; +import { getTableColumns } from '~/utils.ts'; +import type { SingleStoreColumn, SingleStoreColumnBuilderBase } from './columns/index.ts'; +import { QueryBuilder } from './query-builders/query-builder.ts'; +import type { SelectedFields } from './query-builders/select.types.ts'; +import { singlestoreTable } from './table.ts'; +import { SingleStoreViewBase } from './view-base.ts'; +import { SingleStoreViewConfig } from './view-common.ts'; + +export interface ViewBuilderConfig { + algorithm?: 'undefined' | 'merge' | 'temptable'; + definer?: string; + sqlSecurity?: 'definer' | 'invoker'; + withCheckOption?: 'cascaded' | 'local'; +} + +export class ViewBuilderCore { + static readonly [entityKind]: string = 'SingleStoreViewBuilder'; + + declare readonly _: { + readonly name: TConfig['name']; + readonly columns: TConfig['columns']; + }; + + constructor( + protected name: TConfig['name'], + protected schema: string | undefined, + ) {} + + protected config: ViewBuilderConfig = {}; + + algorithm( + algorithm: Exclude, + ): this { + this.config.algorithm = algorithm; + return this; + } + + definer( + definer: Exclude, + ): this { + this.config.definer = definer; + return this; + } + + sqlSecurity( + sqlSecurity: Exclude, + ): this { + this.config.sqlSecurity = sqlSecurity; + return this; + } + + withCheckOption( + withCheckOption?: Exclude, + ): this { + this.config.withCheckOption = withCheckOption ?? 'cascaded'; + return this; + } +} + +export class ViewBuilder extends ViewBuilderCore<{ name: TName }> { + static override readonly [entityKind]: string = 'SingleStoreViewBuilder'; + + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): SingleStoreViewWithSelection> { + if (typeof qb === 'function') { + qb = qb(new QueryBuilder()); + } + const selectionProxy = new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }); + const aliasedSelection = new Proxy(qb.getSelectedFields(), selectionProxy); + return new Proxy( + new SingleStoreView({ + singlestoreConfig: this.config, + config: { + name: this.name, + schema: this.schema, + selectedFields: aliasedSelection, + query: qb.getSQL().inlineParams(), + }, + }), + selectionProxy as any, + ) as SingleStoreViewWithSelection>; + } +} + +export class ManualViewBuilder< + TName extends string = string, + TColumns extends Record = Record, +> extends ViewBuilderCore<{ name: TName; columns: TColumns }> { + static override readonly [entityKind]: string = 'SingleStoreManualViewBuilder'; + + private columns: Record; + + constructor( + name: TName, + columns: TColumns, + schema: string | undefined, + ) { + super(name, schema); + this.columns = getTableColumns(singlestoreTable(name, columns)) as BuildColumns; + } + + existing(): SingleStoreViewWithSelection> { + return new Proxy( + new SingleStoreView({ + singlestoreConfig: undefined, + config: { + name: this.name, + schema: this.schema, + selectedFields: this.columns, + query: undefined, + }, + }), + new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }), + ) as SingleStoreViewWithSelection>; + } + + as(query: SQL): SingleStoreViewWithSelection> { + return new Proxy( + new SingleStoreView({ + singlestoreConfig: this.config, + config: { + name: this.name, + schema: this.schema, + selectedFields: this.columns, + query: query.inlineParams(), + }, + }), + new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }), + ) as SingleStoreViewWithSelection>; + } +} + +export class SingleStoreView< + TName extends string = string, + TExisting extends boolean = boolean, + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> extends SingleStoreViewBase { + static override readonly [entityKind]: string = 'SingleStoreView'; + + declare protected $SingleStoreViewBrand: 'SingleStoreView'; + + [SingleStoreViewConfig]: ViewBuilderConfig | undefined; + + constructor({ singlestoreConfig, config }: { + singlestoreConfig: ViewBuilderConfig | undefined; + config: { + name: TName; + schema: string | undefined; + selectedFields: SelectedFields; + query: SQL | undefined; + }; + }) { + super(config); + this[SingleStoreViewConfig] = singlestoreConfig; + } +} + +export type SingleStoreViewWithSelection< + TName extends string, + TExisting extends boolean, + TSelectedFields extends ColumnsSelection, +> = SingleStoreView & TSelectedFields; + +/** @internal */ +export function singlestoreViewWithSchema( + name: string, + selection: Record | undefined, + schema: string | undefined, +): ViewBuilder | ManualViewBuilder { + if (selection) { + return new ManualViewBuilder(name, selection, schema); + } + return new ViewBuilder(name, schema); +} + +export function singlestoreView(name: TName): ViewBuilder; +export function singlestoreView>( + name: TName, + columns: TColumns, +): ManualViewBuilder; +export function singlestoreView( + name: string, + selection?: Record, +): ViewBuilder | ManualViewBuilder { + return singlestoreViewWithSchema(name, selection, undefined); +} diff --git a/drizzle-orm/src/singlestore-proxy/driver.ts b/drizzle-orm/src/singlestore-proxy/driver.ts new file mode 100644 index 000000000..f54180c66 --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/driver.ts @@ -0,0 +1,54 @@ +import { DefaultLogger } from '~/logger.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type RelationalSchemaConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { DrizzleConfig } from '~/utils.ts'; +import { + type SingleStoreRemotePreparedQueryHKT, + type SingleStoreRemoteQueryResultHKT, + SingleStoreRemoteSession, +} from './session.ts'; + +export type SingleStoreRemoteDatabase< + TSchema extends Record = Record, +> = SingleStoreDatabase; + +export type RemoteCallback = ( + sql: string, + params: any[], + method: 'all' | 'execute', +) => Promise<{ rows: any[]; insertId?: number; affectedRows?: number }>; + +export function drizzle = Record>( + callback: RemoteCallback, + config: DrizzleConfig = {}, +): SingleStoreRemoteDatabase { + const dialect = new SingleStoreDialect(); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const session = new SingleStoreRemoteSession(callback, dialect, schema, { logger }); + return new SingleStoreDatabase(dialect, session, schema) as SingleStoreRemoteDatabase; +} diff --git a/drizzle-orm/src/singlestore-proxy/index.ts b/drizzle-orm/src/singlestore-proxy/index.ts new file mode 100644 index 000000000..b1b6a52e7 --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/singlestore-proxy/migrator.ts b/drizzle-orm/src/singlestore-proxy/migrator.ts new file mode 100644 index 000000000..2ed0172fb --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/migrator.ts @@ -0,0 +1,52 @@ +import type { MigrationConfig } from '~/migrator.ts'; +import { readMigrationFiles } from '~/migrator.ts'; +import { sql } from '~/sql/sql.ts'; +import type { SingleStoreRemoteDatabase } from './driver.ts'; + +export type ProxyMigrator = (migrationQueries: string[]) => Promise; + +export async function migrate>( + db: SingleStoreRemoteDatabase, + callback: ProxyMigrator, + config: MigrationConfig, +) { + const migrations = readMigrationFiles(config); + + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; + const migrationTableCreate = sql` + create table if not exists ${sql.identifier(migrationsTable)} ( + id serial primary key, + hash text not null, + created_at bigint + ) + `; + await db.execute(migrationTableCreate); + + const dbMigrations = await db.select({ + id: sql.raw('id'), + hash: sql.raw('hash'), + created_at: sql.raw('created_at'), + }).from(sql.identifier(migrationsTable).getSQL()).orderBy( + sql.raw('created_at desc'), + ).limit(1); + + const lastDbMigration = dbMigrations[0]; + + const queriesToRun: string[] = []; + + for (const migration of migrations) { + if ( + !lastDbMigration + || Number(lastDbMigration.created_at) < migration.folderMillis + ) { + queriesToRun.push( + ...migration.sql, + `insert into ${ + sql.identifier(migrationsTable).value + } (\`hash\`, \`created_at\`) values('${migration.hash}', '${migration.folderMillis}')`, + ); + } + } + + await callback(queriesToRun); +} diff --git a/drizzle-orm/src/singlestore-proxy/session.ts b/drizzle-orm/src/singlestore-proxy/session.ts new file mode 100644 index 000000000..f7b404860 --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/session.ts @@ -0,0 +1,178 @@ +import type { FieldPacket, ResultSetHeader } from 'mysql2/promise'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import { SingleStoreTransaction } from '~/singlestore-core/index.ts'; +import type { SelectedFieldsOrdered } from '~/singlestore-core/query-builders/select.types.ts'; +import type { + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStorePreparedQueryHKT, + SingleStoreQueryResultHKT, + SingleStoreTransactionConfig, +} from '~/singlestore-core/session.ts'; +import { SingleStorePreparedQuery as PreparedQueryBase, SingleStoreSession } from '~/singlestore-core/session.ts'; +import { fillPlaceholders } from '~/sql/sql.ts'; +import type { Query, SQL } from '~/sql/sql.ts'; +import { type Assume, mapResultRow } from '~/utils.ts'; +import type { RemoteCallback } from './driver.ts'; + +export type SingleStoreRawQueryResult = [ResultSetHeader, FieldPacket[]]; + +export interface SingleStoreRemoteSessionOptions { + logger?: Logger; +} + +export class SingleStoreRemoteSession< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreSession { + static override readonly [entityKind]: string = 'SingleStoreRemoteSession'; + + private logger: Logger; + + constructor( + private client: RemoteCallback, + dialect: SingleStoreDialect, + private schema: RelationalSchemaConfig | undefined, + options: SingleStoreRemoteSessionOptions, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + } + + prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind { + return new PreparedQuery( + this.client, + query.sql, + query.params, + this.logger, + fields, + customResultMapper, + generatedIds, + returningIds, + ) as PreparedQueryKind; + } + + override all(query: SQL): Promise { + const querySql = this.dialect.sqlToQuery(query); + this.logger.logQuery(querySql.sql, querySql.params); + return this.client(querySql.sql, querySql.params, 'all').then(({ rows }) => rows) as Promise; + } + + override async transaction( + _transaction: (tx: SingleStoreProxyTransaction) => Promise, + _config?: SingleStoreTransactionConfig, + ): Promise { + throw new Error('Transactions are not supported by the SingleStore Proxy driver'); + } +} + +export class SingleStoreProxyTransaction< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreTransaction< + SingleStoreRemoteQueryResultHKT, + SingleStoreRemotePreparedQueryHKT, + TFullSchema, + TSchema +> { + static override readonly [entityKind]: string = 'SingleStoreProxyTransaction'; + + override async transaction( + _transaction: (tx: SingleStoreProxyTransaction) => Promise, + ): Promise { + throw new Error('Transactions are not supported by the SingleStore Proxy driver'); + } +} + +export class PreparedQuery extends PreparedQueryBase { + static override readonly [entityKind]: string = 'SingleStoreProxyPreparedQuery'; + + constructor( + private client: RemoteCallback, + private queryString: string, + private params: unknown[], + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + private customResultMapper?: (rows: unknown[][]) => T['execute'], + // Keys that were used in $default and the value that was generated for them + private generatedIds?: Record[], + // Keys that should be returned, it has the column with all properries + key from object + private returningIds?: SelectedFieldsOrdered, + ) { + super(); + } + + async execute(placeholderValues: Record | undefined = {}): Promise { + const params = fillPlaceholders(this.params, placeholderValues); + + const { fields, client, queryString, logger, joinsNotNullableMap, customResultMapper, returningIds, generatedIds } = + this; + + logger.logQuery(queryString, params); + + if (!fields && !customResultMapper) { + const { rows: data } = await client(queryString, params, 'execute'); + + const insertId = data[0].insertId as number; + const affectedRows = data[0].affectedRows; + + if (returningIds) { + const returningResponse = []; + let j = 0; + for (let i = insertId; i < insertId + affectedRows; i++) { + for (const column of returningIds) { + const key = returningIds[0]!.path[0]!; + if (is(column.field, Column)) { + // @ts-ignore + if (column.field.primary && column.field.autoIncrement) { + returningResponse.push({ [key]: i }); + } + if (column.field.defaultFn && generatedIds) { + // generatedIds[rowIdx][key] + returningResponse.push({ [key]: generatedIds[j]![key] }); + } + } + } + j++; + } + + return returningResponse; + } + + return data; + } + + const { rows } = await client(queryString, params, 'all'); + + if (customResultMapper) { + return customResultMapper(rows); + } + + return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + } + + override iterator( + _placeholderValues: Record = {}, + ): AsyncGenerator { + throw new Error('Streaming is not supported by the SingleStore Proxy driver'); + } +} + +export interface SingleStoreRemoteQueryResultHKT extends SingleStoreQueryResultHKT { + type: SingleStoreRawQueryResult; +} + +export interface SingleStoreRemotePreparedQueryHKT extends SingleStorePreparedQueryHKT { + type: PreparedQuery>; +} diff --git a/drizzle-orm/src/singlestore/driver.ts b/drizzle-orm/src/singlestore/driver.ts new file mode 100644 index 000000000..ffc5c2795 --- /dev/null +++ b/drizzle-orm/src/singlestore/driver.ts @@ -0,0 +1,92 @@ +import type { Connection as CallbackConnection, Pool as CallbackPool } from 'mysql2'; +import { entityKind } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { DefaultLogger } from '~/logger.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type RelationalSchemaConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { DrizzleConfig } from '~/utils.ts'; +import type { + Mode, + SingleStoreDriverClient, + SingleStoreDriverPreparedQueryHKT, + SingleStoreDriverQueryResultHKT, +} from './session.ts'; +import { SingleStoreDriverSession } from './session.ts'; + +export interface SingleStoreDriverOptions { + logger?: Logger; +} + +export class SingleStoreDriver { + static readonly [entityKind]: string = 'SingleStoreDriver'; + + constructor( + private client: SingleStoreDriverClient, + private dialect: SingleStoreDialect, + private options: SingleStoreDriverOptions = {}, + ) { + } + + createSession( + schema: RelationalSchemaConfig | undefined, + ): SingleStoreDriverSession, TablesRelationalConfig> { + return new SingleStoreDriverSession(this.client, this.dialect, schema, { logger: this.options.logger }); + } +} + +export { SingleStoreDatabase } from '~/singlestore-core/db.ts'; + +export type SingleStoreDriverDatabase< + TSchema extends Record = Record, +> = SingleStoreDatabase; + +export type SingleStoreDriverDrizzleConfig = Record> = + & Omit, 'schema'> + & ({ schema: TSchema; mode: Mode } | { schema?: undefined; mode?: Mode }); + +export function drizzle = Record>( + client: SingleStoreDriverClient | CallbackConnection | CallbackPool, + config: DrizzleConfig = {}, +): SingleStoreDriverDatabase { + const dialect = new SingleStoreDialect(); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + if (isCallbackClient(client)) { + client = client.promise(); + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const driver = new SingleStoreDriver(client as SingleStoreDriverClient, dialect, { logger }); + const session = driver.createSession(schema); + return new SingleStoreDatabase(dialect, session, schema) as SingleStoreDriverDatabase; +} + +interface CallbackClient { + promise(): SingleStoreDriverClient; +} + +function isCallbackClient(client: any): client is CallbackClient { + return typeof client.promise === 'function'; +} diff --git a/drizzle-orm/src/singlestore/index.ts b/drizzle-orm/src/singlestore/index.ts new file mode 100644 index 000000000..b1b6a52e7 --- /dev/null +++ b/drizzle-orm/src/singlestore/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/singlestore/migrator.ts b/drizzle-orm/src/singlestore/migrator.ts new file mode 100644 index 000000000..6f342c0c5 --- /dev/null +++ b/drizzle-orm/src/singlestore/migrator.ts @@ -0,0 +1,11 @@ +import type { MigrationConfig } from '~/migrator.ts'; +import { readMigrationFiles } from '~/migrator.ts'; +import type { SingleStoreDriverDatabase } from './driver.ts'; + +export async function migrate>( + db: SingleStoreDriverDatabase, + config: MigrationConfig, +) { + const migrations = readMigrationFiles(config); + await db.dialect.migrate(migrations, db.session, config); +} diff --git a/drizzle-orm/src/singlestore/session.ts b/drizzle-orm/src/singlestore/session.ts new file mode 100644 index 000000000..e03171262 --- /dev/null +++ b/drizzle-orm/src/singlestore/session.ts @@ -0,0 +1,339 @@ +import type { Connection as CallbackConnection } from 'mysql2'; +import type { + Connection, + FieldPacket, + OkPacket, + Pool, + PoolConnection, + QueryOptions, + ResultSetHeader, + RowDataPacket, +} from 'mysql2/promise'; +import { once } from 'node:events'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { SelectedFieldsOrdered } from '~/singlestore-core/query-builders/select.types.ts'; +import { + type PreparedQueryKind, + SingleStorePreparedQuery, + type SingleStorePreparedQueryConfig, + type SingleStorePreparedQueryHKT, + type SingleStoreQueryResultHKT, + SingleStoreSession, + SingleStoreTransaction, + type SingleStoreTransactionConfig, +} from '~/singlestore-core/session.ts'; +import { fillPlaceholders, sql } from '~/sql/sql.ts'; +import type { Query, SQL } from '~/sql/sql.ts'; +import { type Assume, mapResultRow } from '~/utils.ts'; + +// must keep this type here for compatibility with DrizzleConfig +export type Mode = 'default'; + +export type SingleStoreDriverClient = Pool | Connection; + +export type SingleStoreRawQueryResult = [ResultSetHeader, FieldPacket[]]; +export type SingleStoreQueryResultType = RowDataPacket[][] | RowDataPacket[] | OkPacket | OkPacket[] | ResultSetHeader; +export type SingleStoreQueryResult< + T = any, +> = [T extends ResultSetHeader ? T : T[], FieldPacket[]]; + +export class SingleStoreDriverPreparedQuery + extends SingleStorePreparedQuery +{ + static override readonly [entityKind]: string = 'SingleStoreDriverPreparedQuery'; + + private rawQuery: QueryOptions; + private query: QueryOptions; + + constructor( + private client: SingleStoreDriverClient, + queryString: string, + private params: unknown[], + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + private customResultMapper?: (rows: unknown[][]) => T['execute'], + // Keys that were used in $default and the value that was generated for them + private generatedIds?: Record[], + // Keys that should be returned, it has the column with all properries + key from object + private returningIds?: SelectedFieldsOrdered, + ) { + super(); + this.rawQuery = { + sql: queryString, + // rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }; + this.query = { + sql: queryString, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }; + } + + async execute(placeholderValues: Record = {}): Promise { + const params = fillPlaceholders(this.params, placeholderValues); + + this.logger.logQuery(this.rawQuery.sql, params); + + const { fields, client, rawQuery, query, joinsNotNullableMap, customResultMapper, returningIds, generatedIds } = + this; + if (!fields && !customResultMapper) { + const res = await client.query(rawQuery, params); + const insertId = res[0].insertId; + const affectedRows = res[0].affectedRows; + // for each row, I need to check keys from + if (returningIds) { + const returningResponse = []; + let j = 0; + for (let i = insertId; i < insertId + affectedRows; i++) { + for (const column of returningIds) { + const key = returningIds[0]!.path[0]!; + if (is(column.field, Column)) { + // @ts-ignore + if (column.field.primary && column.field.autoIncrement) { + returningResponse.push({ [key]: i }); + } + if (column.field.defaultFn && generatedIds) { + // generatedIds[rowIdx][key] + returningResponse.push({ [key]: generatedIds[j]![key] }); + } + } + } + j++; + } + + return returningResponse; + } + return res; + } + + const result = await client.query(query, params); + const rows = result[0]; + + if (customResultMapper) { + return customResultMapper(rows); + } + + return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + } + + async *iterator( + placeholderValues: Record = {}, + ): AsyncGenerator { + const params = fillPlaceholders(this.params, placeholderValues); + const conn = ((isPool(this.client) ? await this.client.getConnection() : this.client) as {} as { + connection: CallbackConnection; + }).connection; + + const { fields, query, rawQuery, joinsNotNullableMap, client, customResultMapper } = this; + const hasRowsMapper = Boolean(fields || customResultMapper); + const driverQuery = hasRowsMapper ? conn.query(query, params) : conn.query(rawQuery, params); + + const stream = driverQuery.stream(); + + function dataListener() { + stream.pause(); + } + + stream.on('data', dataListener); + + try { + const onEnd = once(stream, 'end'); + const onError = once(stream, 'error'); + + while (true) { + stream.resume(); + const row = await Promise.race([onEnd, onError, new Promise((resolve) => stream.once('data', resolve))]); + if (row === undefined || (Array.isArray(row) && row.length === 0)) { + break; + } else if (row instanceof Error) { // eslint-disable-line no-instanceof/no-instanceof + throw row; + } else { + if (hasRowsMapper) { + if (customResultMapper) { + const mappedRow = customResultMapper([row as unknown[]]); + yield (Array.isArray(mappedRow) ? mappedRow[0] : mappedRow); + } else { + yield mapResultRow(fields!, row as unknown[], joinsNotNullableMap); + } + } else { + yield row as T['execute']; + } + } + } + } finally { + stream.off('data', dataListener); + if (isPool(client)) { + conn.end(); + } + } + } +} + +export interface SingleStoreDriverSessionOptions { + logger?: Logger; +} + +export class SingleStoreDriverSession< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreSession { + static override readonly [entityKind]: string = 'SingleStoreDriverSession'; + + private logger: Logger; + + constructor( + private client: SingleStoreDriverClient, + dialect: SingleStoreDialect, + private schema: RelationalSchemaConfig | undefined, + private options: SingleStoreDriverSessionOptions, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + } + + prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind { + // Add returningId fields + // Each driver gets them from response from database + return new SingleStoreDriverPreparedQuery( + this.client, + query.sql, + query.params, + this.logger, + fields, + customResultMapper, + generatedIds, + returningIds, + ) as PreparedQueryKind; + } + + /** + * @internal + * What is its purpose? + */ + async query(query: string, params: unknown[]): Promise { + this.logger.logQuery(query, params); + const result = await this.client.query({ + sql: query, + values: params, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + return result; + } + + override all(query: SQL): Promise { + const querySql = this.dialect.sqlToQuery(query); + this.logger.logQuery(querySql.sql, querySql.params); + return this.client.execute(querySql.sql, querySql.params).then((result) => result[0]) as Promise; + } + + override async transaction( + transaction: (tx: SingleStoreDriverTransaction) => Promise, + config?: SingleStoreTransactionConfig, + ): Promise { + const session = isPool(this.client) + ? new SingleStoreDriverSession( + await this.client.getConnection(), + this.dialect, + this.schema, + this.options, + ) + : this; + const tx = new SingleStoreDriverTransaction( + this.dialect, + session as SingleStoreSession, + this.schema, + 0, + ); + if (config) { + const startTransactionSql = this.getStartTransactionSQL(config); + await (startTransactionSql ? tx.execute(startTransactionSql) : tx.execute(sql`begin`)); + } else { + await tx.execute(sql`begin`); + } + try { + const result = await transaction(tx); + await tx.execute(sql`commit`); + return result; + } catch (err) { + await tx.execute(sql`rollback`); + throw err; + } finally { + if (isPool(this.client)) { + (session.client as PoolConnection).release(); + } + } + } +} + +export class SingleStoreDriverTransaction< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreTransaction< + SingleStoreDriverQueryResultHKT, + SingleStoreDriverPreparedQueryHKT, + TFullSchema, + TSchema +> { + static override readonly [entityKind]: string = 'SingleStoreDriverTransaction'; + + override async transaction( + transaction: (tx: SingleStoreDriverTransaction) => Promise, + ): Promise { + const savepointName = `sp${this.nestedIndex + 1}`; + const tx = new SingleStoreDriverTransaction( + this.dialect, + this.session, + this.schema, + this.nestedIndex + 1, + ); + await tx.execute(sql.raw(`savepoint ${savepointName}`)); + try { + const result = await transaction(tx); + await tx.execute(sql.raw(`release savepoint ${savepointName}`)); + return result; + } catch (err) { + await tx.execute(sql.raw(`rollback to savepoint ${savepointName}`)); + throw err; + } + } +} + +function isPool(client: SingleStoreDriverClient): client is Pool { + return 'getConnection' in client; +} + +export interface SingleStoreDriverQueryResultHKT extends SingleStoreQueryResultHKT { + type: SingleStoreRawQueryResult; +} + +export interface SingleStoreDriverPreparedQueryHKT extends SingleStorePreparedQueryHKT { + type: SingleStoreDriverPreparedQuery>; +} diff --git a/drizzle-orm/type-tests/singlestore/1000columns.ts b/drizzle-orm/type-tests/singlestore/1000columns.ts new file mode 100644 index 000000000..f84640858 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/1000columns.ts @@ -0,0 +1,904 @@ +import { bigint, double, singlestoreTable, varchar } from '~/singlestore-core/index.ts'; + +singlestoreTable('test', { + col0: double('col1').primaryKey().autoincrement().default(0), + col1: double('col1').primaryKey().autoincrement().default(0), + col2: double('col1').primaryKey().autoincrement().default(0), + col3: double('col1').primaryKey().autoincrement().default(0), + col4: double('col1').primaryKey().autoincrement().default(0), + col5: double('col1').primaryKey().autoincrement().default(0), + col6: double('col1').primaryKey().autoincrement().default(0), + col8: double('col1').primaryKey().autoincrement().default(0), + col9: double('col1').primaryKey().autoincrement().default(0), + col10: double('col1').primaryKey().autoincrement().default(0), + col11: double('col1').primaryKey().autoincrement().default(0), + col12: double('col1').primaryKey().autoincrement().default(0), + col13: double('col1').primaryKey().autoincrement().default(0), + col14: double('col1').primaryKey().autoincrement().default(0), + col15: double('col1').primaryKey().autoincrement().default(0), + col16: double('col1').primaryKey().autoincrement().default(0), + col18: double('col1').primaryKey().autoincrement().default(0), + col19: double('col1').primaryKey().autoincrement().default(0), + col20: double('col1').primaryKey().autoincrement().default(0), + col21: double('col1').primaryKey().autoincrement().default(0), + col22: double('col1').primaryKey().autoincrement().default(0), + col23: double('col1').primaryKey().autoincrement().default(0), + col24: double('col1').primaryKey().autoincrement().default(0), + col25: double('col1').primaryKey().autoincrement().default(0), + col26: double('col1').primaryKey().autoincrement().default(0), + col28: double('col1').primaryKey().autoincrement().default(0), + col29: double('col1').primaryKey().autoincrement().default(0), + col30: double('col1').primaryKey().autoincrement().default(0), + col31: double('col1').primaryKey().autoincrement().default(0), + col32: double('col1').primaryKey().autoincrement().default(0), + col33: double('col1').primaryKey().autoincrement().default(0), + col34: double('col1').primaryKey().autoincrement().default(0), + col35: double('col1').primaryKey().autoincrement().default(0), + col36: double('col1').primaryKey().autoincrement().default(0), + col38: double('col1').primaryKey().autoincrement().default(0), + col39: double('col1').primaryKey().autoincrement().default(0), + col40: double('col1').primaryKey().autoincrement().default(0), + col41: double('col1').primaryKey().autoincrement().default(0), + col42: double('col1').primaryKey().autoincrement().default(0), + col43: double('col1').primaryKey().autoincrement().default(0), + col44: double('col1').primaryKey().autoincrement().default(0), + col45: double('col1').primaryKey().autoincrement().default(0), + col46: double('col1').primaryKey().autoincrement().default(0), + col48: double('col1').primaryKey().autoincrement().default(0), + col49: double('col1').primaryKey().autoincrement().default(0), + col50: double('col1').primaryKey().autoincrement().default(0), + col51: double('col1').primaryKey().autoincrement().default(0), + col52: double('col1').primaryKey().autoincrement().default(0), + col53: double('col1').primaryKey().autoincrement().default(0), + col54: double('col1').primaryKey().autoincrement().default(0), + col55: double('col1').primaryKey().autoincrement().default(0), + col56: double('col1').primaryKey().autoincrement().default(0), + col58: double('col1').primaryKey().autoincrement().default(0), + col59: double('col1').primaryKey().autoincrement().default(0), + col60: double('col1').primaryKey().autoincrement().default(0), + col61: double('col1').primaryKey().autoincrement().default(0), + col62: double('col1').primaryKey().autoincrement().default(0), + col63: double('col1').primaryKey().autoincrement().default(0), + col64: double('col1').primaryKey().autoincrement().default(0), + col65: double('col1').primaryKey().autoincrement().default(0), + col66: double('col1').primaryKey().autoincrement().default(0), + col68: double('col1').primaryKey().autoincrement().default(0), + col69: double('col1').primaryKey().autoincrement().default(0), + col70: double('col1').primaryKey().autoincrement().default(0), + col71: double('col1').primaryKey().autoincrement().default(0), + col72: double('col1').primaryKey().autoincrement().default(0), + col73: double('col1').primaryKey().autoincrement().default(0), + col74: double('col1').primaryKey().autoincrement().default(0), + col75: double('col1').primaryKey().autoincrement().default(0), + col76: double('col1').primaryKey().autoincrement().default(0), + col78: double('col1').primaryKey().autoincrement().default(0), + col79: double('col1').primaryKey().autoincrement().default(0), + col80: double('col1').primaryKey().autoincrement().default(0), + col81: double('col1').primaryKey().autoincrement().default(0), + col82: double('col1').primaryKey().autoincrement().default(0), + col83: double('col1').primaryKey().autoincrement().default(0), + col84: double('col1').primaryKey().autoincrement().default(0), + col85: double('col1').primaryKey().autoincrement().default(0), + col86: double('col1').primaryKey().autoincrement().default(0), + col88: double('col1').primaryKey().autoincrement().default(0), + col89: double('col1').primaryKey().autoincrement().default(0), + col90: double('col1').primaryKey().autoincrement().default(0), + col91: double('col1').primaryKey().autoincrement().default(0), + col92: double('col1').primaryKey().autoincrement().default(0), + col93: double('col1').primaryKey().autoincrement().default(0), + col94: double('col1').primaryKey().autoincrement().default(0), + col95: double('col1').primaryKey().autoincrement().default(0), + col96: double('col1').primaryKey().autoincrement().default(0), + col98: double('col1').primaryKey().autoincrement().default(0), + col99: double('col1').primaryKey().autoincrement().default(0), + col100: double('col1').primaryKey().autoincrement().default(0), + col101: double('col1').primaryKey().autoincrement().default(0), + col102: double('col1').primaryKey().autoincrement().default(0), + col103: double('col1').primaryKey().autoincrement().default(0), + col104: double('col1').primaryKey().autoincrement().default(0), + col105: double('col1').primaryKey().autoincrement().default(0), + col106: double('col1').primaryKey().autoincrement().default(0), + col108: double('col1').primaryKey().autoincrement().default(0), + col109: double('col1').primaryKey().autoincrement().default(0), + col110: double('col11').primaryKey().autoincrement().default(0), + col111: double('col11').primaryKey().autoincrement().default(0), + col112: double('col11').primaryKey().autoincrement().default(0), + col113: double('col11').primaryKey().autoincrement().default(0), + col114: double('col11').primaryKey().autoincrement().default(0), + col115: double('col11').primaryKey().autoincrement().default(0), + col116: double('col11').primaryKey().autoincrement().default(0), + col118: double('col11').primaryKey().autoincrement().default(0), + col119: double('col11').primaryKey().autoincrement().default(0), + col120: double('col11').primaryKey().autoincrement().default(0), + col121: double('col11').primaryKey().autoincrement().default(0), + col122: double('col11').primaryKey().autoincrement().default(0), + col123: double('col11').primaryKey().autoincrement().default(0), + col124: double('col11').primaryKey().autoincrement().default(0), + col125: double('col11').primaryKey().autoincrement().default(0), + col126: double('col11').primaryKey().autoincrement().default(0), + col128: double('col11').primaryKey().autoincrement().default(0), + col129: double('col11').primaryKey().autoincrement().default(0), + col130: double('col11').primaryKey().autoincrement().default(0), + col131: double('col11').primaryKey().autoincrement().default(0), + col132: double('col11').primaryKey().autoincrement().default(0), + col133: double('col11').primaryKey().autoincrement().default(0), + col134: double('col11').primaryKey().autoincrement().default(0), + col135: double('col11').primaryKey().autoincrement().default(0), + col136: double('col11').primaryKey().autoincrement().default(0), + col138: double('col11').primaryKey().autoincrement().default(0), + col139: double('col11').primaryKey().autoincrement().default(0), + col140: double('col11').primaryKey().autoincrement().default(0), + col141: double('col11').primaryKey().autoincrement().default(0), + col142: double('col11').primaryKey().autoincrement().default(0), + col143: double('col11').primaryKey().autoincrement().default(0), + col144: double('col11').primaryKey().autoincrement().default(0), + col145: double('col11').primaryKey().autoincrement().default(0), + col146: double('col11').primaryKey().autoincrement().default(0), + col148: double('col11').primaryKey().autoincrement().default(0), + col149: double('col11').primaryKey().autoincrement().default(0), + col150: double('col11').primaryKey().autoincrement().default(0), + col151: double('col11').primaryKey().autoincrement().default(0), + col152: double('col11').primaryKey().autoincrement().default(0), + col153: double('col11').primaryKey().autoincrement().default(0), + col154: double('col11').primaryKey().autoincrement().default(0), + col155: double('col11').primaryKey().autoincrement().default(0), + col156: double('col11').primaryKey().autoincrement().default(0), + col158: double('col11').primaryKey().autoincrement().default(0), + col159: double('col11').primaryKey().autoincrement().default(0), + col160: double('col11').primaryKey().autoincrement().default(0), + col161: double('col11').primaryKey().autoincrement().default(0), + col162: double('col11').primaryKey().autoincrement().default(0), + col163: double('col11').primaryKey().autoincrement().default(0), + col164: double('col11').primaryKey().autoincrement().default(0), + col165: double('col11').primaryKey().autoincrement().default(0), + col166: double('col11').primaryKey().autoincrement().default(0), + col168: double('col11').primaryKey().autoincrement().default(0), + col169: double('col11').primaryKey().autoincrement().default(0), + col170: double('col11').primaryKey().autoincrement().default(0), + col171: double('col11').primaryKey().autoincrement().default(0), + col172: double('col11').primaryKey().autoincrement().default(0), + col173: double('col11').primaryKey().autoincrement().default(0), + col174: double('col11').primaryKey().autoincrement().default(0), + col175: double('col11').primaryKey().autoincrement().default(0), + col176: double('col11').primaryKey().autoincrement().default(0), + col178: double('col11').primaryKey().autoincrement().default(0), + col179: double('col11').primaryKey().autoincrement().default(0), + col180: double('col11').primaryKey().autoincrement().default(0), + col181: double('col11').primaryKey().autoincrement().default(0), + col182: double('col11').primaryKey().autoincrement().default(0), + col183: double('col11').primaryKey().autoincrement().default(0), + col184: double('col11').primaryKey().autoincrement().default(0), + col185: double('col11').primaryKey().autoincrement().default(0), + col186: double('col11').primaryKey().autoincrement().default(0), + col188: double('col11').primaryKey().autoincrement().default(0), + col189: double('col11').primaryKey().autoincrement().default(0), + col190: double('col11').primaryKey().autoincrement().default(0), + col191: double('col11').primaryKey().autoincrement().default(0), + col192: double('col11').primaryKey().autoincrement().default(0), + col193: double('col11').primaryKey().autoincrement().default(0), + col194: double('col11').primaryKey().autoincrement().default(0), + col195: double('col11').primaryKey().autoincrement().default(0), + col196: double('col11').primaryKey().autoincrement().default(0), + col198: double('col11').primaryKey().autoincrement().default(0), + col199: double('col11').primaryKey().autoincrement().default(0), + col200: double('col2').primaryKey().autoincrement().default(0), + col201: double('col2').primaryKey().autoincrement().default(0), + col202: double('col2').primaryKey().autoincrement().default(0), + col203: double('col2').primaryKey().autoincrement().default(0), + col204: double('col2').primaryKey().autoincrement().default(0), + col205: double('col2').primaryKey().autoincrement().default(0), + col206: double('col2').primaryKey().autoincrement().default(0), + col208: double('col2').primaryKey().autoincrement().default(0), + col209: double('col2').primaryKey().autoincrement().default(0), + col210: double('col21').primaryKey().autoincrement().default(0), + col211: double('col21').primaryKey().autoincrement().default(0), + col212: double('col21').primaryKey().autoincrement().default(0), + col213: double('col21').primaryKey().autoincrement().default(0), + col214: double('col21').primaryKey().autoincrement().default(0), + col215: double('col21').primaryKey().autoincrement().default(0), + col216: double('col21').primaryKey().autoincrement().default(0), + col218: double('col21').primaryKey().autoincrement().default(0), + col219: double('col21').primaryKey().autoincrement().default(0), + col220: double('col21').primaryKey().autoincrement().default(0), + col221: double('col21').primaryKey().autoincrement().default(0), + col222: double('col21').primaryKey().autoincrement().default(0), + col223: double('col21').primaryKey().autoincrement().default(0), + col224: double('col21').primaryKey().autoincrement().default(0), + col225: double('col21').primaryKey().autoincrement().default(0), + col226: double('col21').primaryKey().autoincrement().default(0), + col228: double('col21').primaryKey().autoincrement().default(0), + col229: double('col21').primaryKey().autoincrement().default(0), + col230: double('col21').primaryKey().autoincrement().default(0), + col231: double('col21').primaryKey().autoincrement().default(0), + col232: double('col21').primaryKey().autoincrement().default(0), + col233: double('col21').primaryKey().autoincrement().default(0), + col234: double('col21').primaryKey().autoincrement().default(0), + col235: double('col21').primaryKey().autoincrement().default(0), + col236: double('col21').primaryKey().autoincrement().default(0), + col238: double('col21').primaryKey().autoincrement().default(0), + col239: double('col21').primaryKey().autoincrement().default(0), + col240: double('col21').primaryKey().autoincrement().default(0), + col241: double('col21').primaryKey().autoincrement().default(0), + col242: double('col21').primaryKey().autoincrement().default(0), + col243: double('col21').primaryKey().autoincrement().default(0), + col244: double('col21').primaryKey().autoincrement().default(0), + col245: double('col21').primaryKey().autoincrement().default(0), + col246: double('col21').primaryKey().autoincrement().default(0), + col248: double('col21').primaryKey().autoincrement().default(0), + col249: double('col21').primaryKey().autoincrement().default(0), + col250: double('col21').primaryKey().autoincrement().default(0), + col251: double('col21').primaryKey().autoincrement().default(0), + col252: double('col21').primaryKey().autoincrement().default(0), + col253: double('col21').primaryKey().autoincrement().default(0), + col254: double('col21').primaryKey().autoincrement().default(0), + col255: double('col21').primaryKey().autoincrement().default(0), + col256: double('col21').primaryKey().autoincrement().default(0), + col258: double('col21').primaryKey().autoincrement().default(0), + col259: double('col21').primaryKey().autoincrement().default(0), + col260: double('col21').primaryKey().autoincrement().default(0), + col261: double('col21').primaryKey().autoincrement().default(0), + col262: double('col21').primaryKey().autoincrement().default(0), + col263: double('col21').primaryKey().autoincrement().default(0), + col264: double('col21').primaryKey().autoincrement().default(0), + col265: double('col21').primaryKey().autoincrement().default(0), + col266: double('col21').primaryKey().autoincrement().default(0), + col268: double('col21').primaryKey().autoincrement().default(0), + col269: double('col21').primaryKey().autoincrement().default(0), + col270: double('col21').primaryKey().autoincrement().default(0), + col271: double('col21').primaryKey().autoincrement().default(0), + col272: double('col21').primaryKey().autoincrement().default(0), + col273: double('col21').primaryKey().autoincrement().default(0), + col274: double('col21').primaryKey().autoincrement().default(0), + col275: double('col21').primaryKey().autoincrement().default(0), + col276: double('col21').primaryKey().autoincrement().default(0), + col278: double('col21').primaryKey().autoincrement().default(0), + col279: double('col21').primaryKey().autoincrement().default(0), + col280: double('col21').primaryKey().autoincrement().default(0), + col281: double('col21').primaryKey().autoincrement().default(0), + col282: double('col21').primaryKey().autoincrement().default(0), + col283: double('col21').primaryKey().autoincrement().default(0), + col284: double('col21').primaryKey().autoincrement().default(0), + col285: double('col21').primaryKey().autoincrement().default(0), + col286: double('col21').primaryKey().autoincrement().default(0), + col288: double('col21').primaryKey().autoincrement().default(0), + col289: double('col21').primaryKey().autoincrement().default(0), + col290: double('col21').primaryKey().autoincrement().default(0), + col291: double('col21').primaryKey().autoincrement().default(0), + col292: double('col21').primaryKey().autoincrement().default(0), + col293: double('col21').primaryKey().autoincrement().default(0), + col294: double('col21').primaryKey().autoincrement().default(0), + col295: double('col21').primaryKey().autoincrement().default(0), + col296: double('col21').primaryKey().autoincrement().default(0), + col298: double('col21').primaryKey().autoincrement().default(0), + col299: double('col21').primaryKey().autoincrement().default(0), + col300: double('col3').primaryKey().autoincrement().default(0), + col301: double('col3').primaryKey().autoincrement().default(0), + col302: double('col3').primaryKey().autoincrement().default(0), + col303: double('col3').primaryKey().autoincrement().default(0), + col304: double('col3').primaryKey().autoincrement().default(0), + col305: double('col3').primaryKey().autoincrement().default(0), + col306: double('col3').primaryKey().autoincrement().default(0), + col308: double('col3').primaryKey().autoincrement().default(0), + col309: double('col3').primaryKey().autoincrement().default(0), + col310: double('col31').primaryKey().autoincrement().default(0), + col311: double('col31').primaryKey().autoincrement().default(0), + col312: double('col31').primaryKey().autoincrement().default(0), + col313: double('col31').primaryKey().autoincrement().default(0), + col314: double('col31').primaryKey().autoincrement().default(0), + col315: double('col31').primaryKey().autoincrement().default(0), + col316: double('col31').primaryKey().autoincrement().default(0), + col318: double('col31').primaryKey().autoincrement().default(0), + col319: double('col31').primaryKey().autoincrement().default(0), + col320: double('col31').primaryKey().autoincrement().default(0), + col321: double('col31').primaryKey().autoincrement().default(0), + col322: double('col31').primaryKey().autoincrement().default(0), + col323: double('col31').primaryKey().autoincrement().default(0), + col324: double('col31').primaryKey().autoincrement().default(0), + col325: double('col31').primaryKey().autoincrement().default(0), + col326: double('col31').primaryKey().autoincrement().default(0), + col328: double('col31').primaryKey().autoincrement().default(0), + col329: double('col31').primaryKey().autoincrement().default(0), + col330: double('col31').primaryKey().autoincrement().default(0), + col331: double('col31').primaryKey().autoincrement().default(0), + col332: double('col31').primaryKey().autoincrement().default(0), + col333: double('col31').primaryKey().autoincrement().default(0), + col334: double('col31').primaryKey().autoincrement().default(0), + col335: double('col31').primaryKey().autoincrement().default(0), + col336: double('col31').primaryKey().autoincrement().default(0), + col338: double('col31').primaryKey().autoincrement().default(0), + col339: double('col31').primaryKey().autoincrement().default(0), + col340: double('col31').primaryKey().autoincrement().default(0), + col341: double('col31').primaryKey().autoincrement().default(0), + col342: double('col31').primaryKey().autoincrement().default(0), + col343: double('col31').primaryKey().autoincrement().default(0), + col344: double('col31').primaryKey().autoincrement().default(0), + col345: double('col31').primaryKey().autoincrement().default(0), + col346: double('col31').primaryKey().autoincrement().default(0), + col348: double('col31').primaryKey().autoincrement().default(0), + col349: double('col31').primaryKey().autoincrement().default(0), + col350: double('col31').primaryKey().autoincrement().default(0), + col351: double('col31').primaryKey().autoincrement().default(0), + col352: double('col31').primaryKey().autoincrement().default(0), + col353: double('col31').primaryKey().autoincrement().default(0), + col354: double('col31').primaryKey().autoincrement().default(0), + col355: double('col31').primaryKey().autoincrement().default(0), + col356: double('col31').primaryKey().autoincrement().default(0), + col358: double('col31').primaryKey().autoincrement().default(0), + col359: double('col31').primaryKey().autoincrement().default(0), + col360: double('col31').primaryKey().autoincrement().default(0), + col361: double('col31').primaryKey().autoincrement().default(0), + col362: double('col31').primaryKey().autoincrement().default(0), + col363: double('col31').primaryKey().autoincrement().default(0), + col364: double('col31').primaryKey().autoincrement().default(0), + col365: double('col31').primaryKey().autoincrement().default(0), + col366: double('col31').primaryKey().autoincrement().default(0), + col368: double('col31').primaryKey().autoincrement().default(0), + col369: double('col31').primaryKey().autoincrement().default(0), + col370: double('col31').primaryKey().autoincrement().default(0), + col371: double('col31').primaryKey().autoincrement().default(0), + col372: double('col31').primaryKey().autoincrement().default(0), + col373: double('col31').primaryKey().autoincrement().default(0), + col374: double('col31').primaryKey().autoincrement().default(0), + col375: double('col31').primaryKey().autoincrement().default(0), + col376: double('col31').primaryKey().autoincrement().default(0), + col378: double('col31').primaryKey().autoincrement().default(0), + col379: double('col31').primaryKey().autoincrement().default(0), + col380: double('col31').primaryKey().autoincrement().default(0), + col381: double('col31').primaryKey().autoincrement().default(0), + col382: double('col31').primaryKey().autoincrement().default(0), + col383: double('col31').primaryKey().autoincrement().default(0), + col384: double('col31').primaryKey().autoincrement().default(0), + col385: double('col31').primaryKey().autoincrement().default(0), + col386: double('col31').primaryKey().autoincrement().default(0), + col388: double('col31').primaryKey().autoincrement().default(0), + col389: double('col31').primaryKey().autoincrement().default(0), + col390: double('col31').primaryKey().autoincrement().default(0), + col391: double('col31').primaryKey().autoincrement().default(0), + col392: double('col31').primaryKey().autoincrement().default(0), + col393: double('col31').primaryKey().autoincrement().default(0), + col394: double('col31').primaryKey().autoincrement().default(0), + col395: double('col31').primaryKey().autoincrement().default(0), + col396: double('col31').primaryKey().autoincrement().default(0), + col398: double('col31').primaryKey().autoincrement().default(0), + col399: double('col31').primaryKey().autoincrement().default(0), + col400: double('col4').primaryKey().autoincrement().default(0), + col401: double('col4').primaryKey().autoincrement().default(0), + col402: double('col4').primaryKey().autoincrement().default(0), + col403: double('col4').primaryKey().autoincrement().default(0), + col404: double('col4').primaryKey().autoincrement().default(0), + col405: double('col4').primaryKey().autoincrement().default(0), + col406: double('col4').primaryKey().autoincrement().default(0), + col408: double('col4').primaryKey().autoincrement().default(0), + col409: double('col4').primaryKey().autoincrement().default(0), + col410: double('col41').primaryKey().autoincrement().default(0), + col411: double('col41').primaryKey().autoincrement().default(0), + col412: double('col41').primaryKey().autoincrement().default(0), + col413: double('col41').primaryKey().autoincrement().default(0), + col414: double('col41').primaryKey().autoincrement().default(0), + col415: double('col41').primaryKey().autoincrement().default(0), + col416: double('col41').primaryKey().autoincrement().default(0), + col418: double('col41').primaryKey().autoincrement().default(0), + col419: double('col41').primaryKey().autoincrement().default(0), + col420: double('col41').primaryKey().autoincrement().default(0), + col421: double('col41').primaryKey().autoincrement().default(0), + col422: double('col41').primaryKey().autoincrement().default(0), + col423: double('col41').primaryKey().autoincrement().default(0), + col424: double('col41').primaryKey().autoincrement().default(0), + col425: double('col41').primaryKey().autoincrement().default(0), + col426: double('col41').primaryKey().autoincrement().default(0), + col428: double('col41').primaryKey().autoincrement().default(0), + col429: double('col41').primaryKey().autoincrement().default(0), + col430: double('col41').primaryKey().autoincrement().default(0), + col431: double('col41').primaryKey().autoincrement().default(0), + col432: double('col41').primaryKey().autoincrement().default(0), + col433: double('col41').primaryKey().autoincrement().default(0), + col434: double('col41').primaryKey().autoincrement().default(0), + col435: double('col41').primaryKey().autoincrement().default(0), + col436: double('col41').primaryKey().autoincrement().default(0), + col438: double('col41').primaryKey().autoincrement().default(0), + col439: double('col41').primaryKey().autoincrement().default(0), + col440: double('col41').primaryKey().autoincrement().default(0), + col441: double('col41').primaryKey().autoincrement().default(0), + col442: double('col41').primaryKey().autoincrement().default(0), + col443: double('col41').primaryKey().autoincrement().default(0), + col444: double('col41').primaryKey().autoincrement().default(0), + col445: double('col41').primaryKey().autoincrement().default(0), + col446: double('col41').primaryKey().autoincrement().default(0), + col448: double('col41').primaryKey().autoincrement().default(0), + col449: double('col41').primaryKey().autoincrement().default(0), + col450: double('col41').primaryKey().autoincrement().default(0), + col451: double('col41').primaryKey().autoincrement().default(0), + col452: double('col41').primaryKey().autoincrement().default(0), + col453: double('col41').primaryKey().autoincrement().default(0), + col454: double('col41').primaryKey().autoincrement().default(0), + col455: double('col41').primaryKey().autoincrement().default(0), + col456: double('col41').primaryKey().autoincrement().default(0), + col458: double('col41').primaryKey().autoincrement().default(0), + col459: double('col41').primaryKey().autoincrement().default(0), + col460: double('col41').primaryKey().autoincrement().default(0), + col461: double('col41').primaryKey().autoincrement().default(0), + col462: double('col41').primaryKey().autoincrement().default(0), + col463: double('col41').primaryKey().autoincrement().default(0), + col464: double('col41').primaryKey().autoincrement().default(0), + col465: double('col41').primaryKey().autoincrement().default(0), + col466: double('col41').primaryKey().autoincrement().default(0), + col468: double('col41').primaryKey().autoincrement().default(0), + col469: double('col41').primaryKey().autoincrement().default(0), + col470: double('col41').primaryKey().autoincrement().default(0), + col471: double('col41').primaryKey().autoincrement().default(0), + col472: double('col41').primaryKey().autoincrement().default(0), + col473: double('col41').primaryKey().autoincrement().default(0), + col474: double('col41').primaryKey().autoincrement().default(0), + col475: double('col41').primaryKey().autoincrement().default(0), + col476: double('col41').primaryKey().autoincrement().default(0), + col478: double('col41').primaryKey().autoincrement().default(0), + col479: double('col41').primaryKey().autoincrement().default(0), + col480: double('col41').primaryKey().autoincrement().default(0), + col481: double('col41').primaryKey().autoincrement().default(0), + col482: double('col41').primaryKey().autoincrement().default(0), + col483: double('col41').primaryKey().autoincrement().default(0), + col484: double('col41').primaryKey().autoincrement().default(0), + col485: double('col41').primaryKey().autoincrement().default(0), + col486: double('col41').primaryKey().autoincrement().default(0), + col488: double('col41').primaryKey().autoincrement().default(0), + col489: double('col41').primaryKey().autoincrement().default(0), + col490: double('col41').primaryKey().autoincrement().default(0), + col491: double('col41').primaryKey().autoincrement().default(0), + col492: double('col41').primaryKey().autoincrement().default(0), + col493: double('col41').primaryKey().autoincrement().default(0), + col494: double('col41').primaryKey().autoincrement().default(0), + col495: double('col41').primaryKey().autoincrement().default(0), + col496: double('col41').primaryKey().autoincrement().default(0), + col498: double('col41').primaryKey().autoincrement().default(0), + col499: double('col41').primaryKey().autoincrement().default(0), + col500: double('col5').primaryKey().autoincrement().default(0), + col501: double('col5').primaryKey().autoincrement().default(0), + col502: double('col5').primaryKey().autoincrement().default(0), + col503: double('col5').primaryKey().autoincrement().default(0), + col504: double('col5').primaryKey().autoincrement().default(0), + col505: double('col5').primaryKey().autoincrement().default(0), + col506: double('col5').primaryKey().autoincrement().default(0), + col508: double('col5').primaryKey().autoincrement().default(0), + col509: double('col5').primaryKey().autoincrement().default(0), + col510: double('col51').primaryKey().autoincrement().default(0), + col511: double('col51').primaryKey().autoincrement().default(0), + col512: double('col51').primaryKey().autoincrement().default(0), + col513: double('col51').primaryKey().autoincrement().default(0), + col514: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col515: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col516: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col518: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col519: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col520: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col521: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col522: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col523: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col524: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col525: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col526: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col528: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col529: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col530: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col531: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col532: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col533: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col534: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col535: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col536: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col538: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col539: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col540: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col541: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col542: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col543: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col544: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col545: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col546: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col548: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col549: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col550: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col551: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col552: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col553: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col554: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col555: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col556: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col558: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col559: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col560: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col561: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col562: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col563: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col564: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col565: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col566: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col568: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col569: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col570: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col571: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col572: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col573: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col574: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col575: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col576: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col578: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col579: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col580: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col581: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col582: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col583: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col584: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col585: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col586: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col588: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col589: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col590: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col591: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col592: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col593: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col594: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col595: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col596: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col598: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col599: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col600: bigint('col6', { mode: 'number' }).primaryKey().autoincrement().default(0), + col601: double('col6').primaryKey().autoincrement().default(0), + col602: double('col6').primaryKey().autoincrement().default(0), + col603: double('col6').primaryKey().autoincrement().default(0), + col604: double('col6').primaryKey().autoincrement().default(0), + col605: double('col6').primaryKey().autoincrement().default(0), + col606: double('col6').primaryKey().autoincrement().default(0), + col608: double('col6').primaryKey().autoincrement().default(0), + col609: double('col6').primaryKey().autoincrement().default(0), + col610: double('col61').primaryKey().autoincrement().default(0), + col611: double('col61').primaryKey().autoincrement().default(0), + col612: double('col61').primaryKey().autoincrement().default(0), + col613: double('col61').primaryKey().autoincrement().default(0), + col614: double('col61').primaryKey().autoincrement().default(0), + col615: double('col61').primaryKey().autoincrement().default(0), + col616: double('col61').primaryKey().autoincrement().default(0), + col618: double('col61').primaryKey().autoincrement().default(0), + col619: double('col61').primaryKey().autoincrement().default(0), + col620: double('col61').primaryKey().autoincrement().default(0), + col621: double('col61').primaryKey().autoincrement().default(0), + col622: double('col61').primaryKey().autoincrement().default(0), + col623: double('col61').primaryKey().autoincrement().default(0), + col624: double('col61').primaryKey().autoincrement().default(0), + col625: double('col61').primaryKey().autoincrement().default(0), + col626: double('col61').primaryKey().autoincrement().default(0), + col628: double('col61').primaryKey().autoincrement().default(0), + col629: double('col61').primaryKey().autoincrement().default(0), + col630: double('col61').primaryKey().autoincrement().default(0), + col631: double('col61').primaryKey().autoincrement().default(0), + col632: double('col61').primaryKey().autoincrement().default(0), + col633: double('col61').primaryKey().autoincrement().default(0), + col634: double('col61').primaryKey().autoincrement().default(0), + col635: double('col61').primaryKey().autoincrement().default(0), + col636: double('col61').primaryKey().autoincrement().default(0), + col638: double('col61').primaryKey().autoincrement().default(0), + col639: double('col61').primaryKey().autoincrement().default(0), + col640: double('col61').primaryKey().autoincrement().default(0), + col641: double('col61').primaryKey().autoincrement().default(0), + col642: double('col61').primaryKey().autoincrement().default(0), + col643: double('col61').primaryKey().autoincrement().default(0), + col644: double('col61').primaryKey().autoincrement().default(0), + col645: double('col61').primaryKey().autoincrement().default(0), + col646: double('col61').primaryKey().autoincrement().default(0), + col648: double('col61').primaryKey().autoincrement().default(0), + col649: double('col61').primaryKey().autoincrement().default(0), + col650: double('col61').primaryKey().autoincrement().default(0), + col651: double('col61').primaryKey().autoincrement().default(0), + col652: double('col61').primaryKey().autoincrement().default(0), + col653: double('col61').primaryKey().autoincrement().default(0), + col654: double('col61').primaryKey().autoincrement().default(0), + col655: double('col61').primaryKey().autoincrement().default(0), + col656: double('col61').primaryKey().autoincrement().default(0), + col658: double('col61').primaryKey().autoincrement().default(0), + col659: double('col61').primaryKey().autoincrement().default(0), + col660: double('col61').primaryKey().autoincrement().default(0), + col661: double('col61').primaryKey().autoincrement().default(0), + col662: double('col61').primaryKey().autoincrement().default(0), + col663: double('col61').primaryKey().autoincrement().default(0), + col664: double('col61').primaryKey().autoincrement().default(0), + col665: double('col61').primaryKey().autoincrement().default(0), + col666: double('col61').primaryKey().autoincrement().default(0), + col668: double('col61').primaryKey().autoincrement().default(0), + col669: double('col61').primaryKey().autoincrement().default(0), + col670: double('col61').primaryKey().autoincrement().default(0), + col671: double('col61').primaryKey().autoincrement().default(0), + col672: double('col61').primaryKey().autoincrement().default(0), + col673: double('col61').primaryKey().autoincrement().default(0), + col674: double('col61').primaryKey().autoincrement().default(0), + col675: double('col61').primaryKey().autoincrement().default(0), + col676: double('col61').primaryKey().autoincrement().default(0), + col678: double('col61').primaryKey().autoincrement().default(0), + col679: double('col61').primaryKey().autoincrement().default(0), + col680: double('col61').primaryKey().autoincrement().default(0), + col681: double('col61').primaryKey().autoincrement().default(0), + col682: double('col61').primaryKey().autoincrement().default(0), + col683: double('col61').primaryKey().autoincrement().default(0), + col684: double('col61').primaryKey().autoincrement().default(0), + col685: double('col61').primaryKey().autoincrement().default(0), + col686: double('col61').primaryKey().autoincrement().default(0), + col688: double('col61').primaryKey().autoincrement().default(0), + col689: double('col61').primaryKey().autoincrement().default(0), + col690: double('col61').primaryKey().autoincrement().default(0), + col691: double('col61').primaryKey().autoincrement().default(0), + col692: double('col61').primaryKey().autoincrement().default(0), + col693: double('col61').primaryKey().autoincrement().default(0), + col694: double('col61').primaryKey().autoincrement().default(0), + col695: double('col61').primaryKey().autoincrement().default(0), + col696: double('col61').primaryKey().autoincrement().default(0), + col698: double('col61').primaryKey().autoincrement().default(0), + col699: double('col61').primaryKey().autoincrement().default(0), + col700: double('col7').primaryKey().autoincrement().default(0), + col701: double('col7').primaryKey().autoincrement().default(0), + col702: double('col7').primaryKey().autoincrement().default(0), + col703: double('col7').primaryKey().autoincrement().default(0), + col704: double('col7').primaryKey().autoincrement().default(0), + col705: double('col7').primaryKey().autoincrement().default(0), + col706: double('col7').primaryKey().autoincrement().default(0), + col708: double('col7').primaryKey().autoincrement().default(0), + col709: double('col7').primaryKey().autoincrement().default(0), + col710: double('col71').primaryKey().autoincrement().default(0), + col711: double('col71').primaryKey().autoincrement().default(0), + col712: double('col71').primaryKey().autoincrement().default(0), + col713: double('col71').primaryKey().autoincrement().default(0), + col714: double('col71').primaryKey().autoincrement().default(0), + col715: double('col71').primaryKey().autoincrement().default(0), + col716: double('col71').primaryKey().autoincrement().default(0), + col718: double('col71').primaryKey().autoincrement().default(0), + col719: double('col71').primaryKey().autoincrement().default(0), + col720: double('col71').primaryKey().autoincrement().default(0), + col721: double('col71').primaryKey().autoincrement().default(0), + col722: double('col71').primaryKey().autoincrement().default(0), + col723: double('col71').primaryKey().autoincrement().default(0), + col724: double('col71').primaryKey().autoincrement().default(0), + col725: double('col71').primaryKey().autoincrement().default(0), + col726: double('col71').primaryKey().autoincrement().default(0), + col728: double('col71').primaryKey().autoincrement().default(0), + col729: double('col71').primaryKey().autoincrement().default(0), + col730: double('col71').primaryKey().autoincrement().default(0), + col731: double('col71').primaryKey().autoincrement().default(0), + col732: double('col71').primaryKey().autoincrement().default(0), + col733: double('col71').primaryKey().autoincrement().default(0), + col734: double('col71').primaryKey().autoincrement().default(0), + col735: double('col71').primaryKey().autoincrement().default(0), + col736: double('col71').primaryKey().autoincrement().default(0), + col738: double('col71').primaryKey().autoincrement().default(0), + col739: double('col71').primaryKey().autoincrement().default(0), + col740: double('col71').primaryKey().autoincrement().default(0), + col741: double('col71').primaryKey().autoincrement().default(0), + col742: double('col71').primaryKey().autoincrement().default(0), + col743: double('col71').primaryKey().autoincrement().default(0), + col744: double('col71').primaryKey().autoincrement().default(0), + col745: double('col71').primaryKey().autoincrement().default(0), + col746: double('col71').primaryKey().autoincrement().default(0), + col748: double('col71').primaryKey().autoincrement().default(0), + col749: double('col71').primaryKey().autoincrement().default(0), + col750: double('col71').primaryKey().autoincrement().default(0), + col751: double('col71').primaryKey().autoincrement().default(0), + col752: double('col71').primaryKey().autoincrement().default(0), + col753: double('col71').primaryKey().autoincrement().default(0), + col754: double('col71').primaryKey().autoincrement().default(0), + col755: double('col71').primaryKey().autoincrement().default(0), + col756: double('col71').primaryKey().autoincrement().default(0), + col758: double('col71').primaryKey().autoincrement().default(0), + col759: double('col71').primaryKey().autoincrement().default(0), + col760: double('col71').primaryKey().autoincrement().default(0), + col761: double('col71').primaryKey().autoincrement().default(0), + col762: double('col71').primaryKey().autoincrement().default(0), + col763: double('col71').primaryKey().autoincrement().default(0), + col764: double('col71').primaryKey().autoincrement().default(0), + col765: double('col71').primaryKey().autoincrement().default(0), + col766: double('col71').primaryKey().autoincrement().default(0), + col768: double('col71').primaryKey().autoincrement().default(0), + col769: double('col71').primaryKey().autoincrement().default(0), + col770: double('col71').primaryKey().autoincrement().default(0), + col771: double('col71').primaryKey().autoincrement().default(0), + col772: double('col71').primaryKey().autoincrement().default(0), + col773: double('col71').primaryKey().autoincrement().default(0), + col774: double('col71').primaryKey().autoincrement().default(0), + col775: double('col71').primaryKey().autoincrement().default(0), + col776: double('col71').primaryKey().autoincrement().default(0), + col778: double('col71').primaryKey().autoincrement().default(0), + col779: double('col71').primaryKey().autoincrement().default(0), + col780: double('col71').primaryKey().autoincrement().default(0), + col781: double('col71').primaryKey().autoincrement().default(0), + col782: double('col71').primaryKey().autoincrement().default(0), + col783: double('col71').primaryKey().autoincrement().default(0), + col784: double('col71').primaryKey().autoincrement().default(0), + col785: double('col71').primaryKey().autoincrement().default(0), + col786: double('col71').primaryKey().autoincrement().default(0), + col788: double('col71').primaryKey().autoincrement().default(0), + col789: double('col71').primaryKey().autoincrement().default(0), + col790: double('col71').primaryKey().autoincrement().default(0), + col791: double('col71').primaryKey().autoincrement().default(0), + col792: double('col71').primaryKey().autoincrement().default(0), + col793: double('col71').primaryKey().autoincrement().default(0), + col794: double('col71').primaryKey().autoincrement().default(0), + col795: double('col71').primaryKey().autoincrement().default(0), + col796: double('col71').primaryKey().autoincrement().default(0), + col798: double('col71').primaryKey().autoincrement().default(0), + col799: double('col71').primaryKey().autoincrement().default(0), + col800: double('col8').primaryKey().autoincrement().default(0), + col801: double('col8').primaryKey().autoincrement().default(0), + col802: double('col8').primaryKey().autoincrement().default(0), + col803: double('col8').primaryKey().autoincrement().default(0), + col804: double('col8').primaryKey().autoincrement().default(0), + col805: double('col8').primaryKey().autoincrement().default(0), + col806: double('col8').primaryKey().autoincrement().default(0), + col808: double('col8').primaryKey().autoincrement().default(0), + col809: double('col8').primaryKey().autoincrement().default(0), + col810: double('col81').primaryKey().autoincrement().default(0), + col811: double('col81').primaryKey().autoincrement().default(0), + col812: double('col81').primaryKey().autoincrement().default(0), + col813: double('col81').primaryKey().autoincrement().default(0), + col814: double('col81').primaryKey().autoincrement().default(0), + col815: double('col81').primaryKey().autoincrement().default(0), + col816: double('col81').primaryKey().autoincrement().default(0), + col818: double('col81').primaryKey().autoincrement().default(0), + col819: double('col81').primaryKey().autoincrement().default(0), + col820: double('col81').primaryKey().autoincrement().default(0), + col821: double('col81').primaryKey().autoincrement().default(0), + col822: double('col81').primaryKey().autoincrement().default(0), + col823: double('col81').primaryKey().autoincrement().default(0), + col824: double('col81').primaryKey().autoincrement().default(0), + col825: double('col81').primaryKey().autoincrement().default(0), + col826: double('col81').primaryKey().autoincrement().default(0), + col828: double('col81').primaryKey().autoincrement().default(0), + col829: double('col81').primaryKey().autoincrement().default(0), + col830: double('col81').primaryKey().autoincrement().default(0), + col831: double('col81').primaryKey().autoincrement().default(0), + col832: double('col81').primaryKey().autoincrement().default(0), + col833: double('col81').primaryKey().autoincrement().default(0), + col834: double('col81').primaryKey().autoincrement().default(0), + col835: double('col81').primaryKey().autoincrement().default(0), + col836: double('col81').primaryKey().autoincrement().default(0), + col838: double('col81').primaryKey().autoincrement().default(0), + col839: double('col81').primaryKey().autoincrement().default(0), + col840: double('col81').primaryKey().autoincrement().default(0), + col841: double('col81').primaryKey().autoincrement().default(0), + col842: double('col81').primaryKey().autoincrement().default(0), + col843: double('col81').primaryKey().autoincrement().default(0), + col844: double('col81').primaryKey().autoincrement().default(0), + col845: double('col81').primaryKey().autoincrement().default(0), + col846: double('col81').primaryKey().autoincrement().default(0), + col848: double('col81').primaryKey().autoincrement().default(0), + col849: double('col81').primaryKey().autoincrement().default(0), + col850: double('col81').primaryKey().autoincrement().default(0), + col851: double('col81').primaryKey().autoincrement().default(0), + col852: double('col81').primaryKey().autoincrement().default(0), + col853: double('col81').primaryKey().autoincrement().default(0), + col854: double('col81').primaryKey().autoincrement().default(0), + col855: double('col81').primaryKey().autoincrement().default(0), + col856: double('col81').primaryKey().autoincrement().default(0), + col858: double('col81').primaryKey().autoincrement().default(0), + col859: double('col81').primaryKey().autoincrement().default(0), + col860: double('col81').primaryKey().autoincrement().default(0), + col861: double('col81').primaryKey().autoincrement().default(0), + col862: double('col81').primaryKey().autoincrement().default(0), + col863: double('col81').primaryKey().autoincrement().default(0), + col864: double('col81').primaryKey().autoincrement().default(0), + col865: double('col81').primaryKey().autoincrement().default(0), + col866: double('col81').primaryKey().autoincrement().default(0), + col868: double('col81').primaryKey().autoincrement().default(0), + col869: double('col81').primaryKey().autoincrement().default(0), + col870: double('col81').primaryKey().autoincrement().default(0), + col871: double('col81').primaryKey().autoincrement().default(0), + col872: double('col81').primaryKey().autoincrement().default(0), + col873: double('col81').primaryKey().autoincrement().default(0), + col874: double('col81').primaryKey().autoincrement().default(0), + col875: double('col81').primaryKey().autoincrement().default(0), + col876: double('col81').primaryKey().autoincrement().default(0), + col878: double('col81').primaryKey().autoincrement().default(0), + col879: double('col81').primaryKey().autoincrement().default(0), + col880: double('col81').primaryKey().autoincrement().default(0), + col881: double('col81').primaryKey().autoincrement().default(0), + col882: double('col81').primaryKey().autoincrement().default(0), + col883: double('col81').primaryKey().autoincrement().default(0), + col884: double('col81').primaryKey().autoincrement().default(0), + col885: double('col81').primaryKey().autoincrement().default(0), + col886: double('col81').primaryKey().autoincrement().default(0), + col888: double('col81').primaryKey().autoincrement().default(0), + col889: double('col81').primaryKey().autoincrement().default(0), + col890: double('col81').primaryKey().autoincrement().default(0), + col891: double('col81').primaryKey().autoincrement().default(0), + col892: double('col81').primaryKey().autoincrement().default(0), + col893: double('col81').primaryKey().autoincrement().default(0), + col894: double('col81').primaryKey().autoincrement().default(0), + col895: double('col81').primaryKey().autoincrement().default(0), + col896: double('col81').primaryKey().autoincrement().default(0), + col898: double('col81').primaryKey().autoincrement().default(0), + col899: double('col81').primaryKey().autoincrement().default(0), + col900: double('col9').primaryKey().autoincrement().default(0), + col901: double('col9').primaryKey().autoincrement().default(0), + col902: double('col9').primaryKey().autoincrement().default(0), + col903: double('col9').primaryKey().autoincrement().default(0), + col904: double('col9').primaryKey().autoincrement().default(0), + col905: double('col9').primaryKey().autoincrement().default(0), + col906: double('col9').primaryKey().autoincrement().default(0), + col908: double('col9').primaryKey().autoincrement().default(0), + col909: double('col9').primaryKey().autoincrement().default(0), + col910: double('col91').primaryKey().autoincrement().default(0), + col911: double('col91').primaryKey().autoincrement().default(0), + col912: double('col91').primaryKey().autoincrement().default(0), + col913: double('col91').primaryKey().autoincrement().default(0), + col914: double('col91').primaryKey().autoincrement().default(0), + col915: double('col91').primaryKey().autoincrement().default(0), + col916: double('col91').primaryKey().autoincrement().default(0), + col918: double('col91').primaryKey().autoincrement().default(0), + col919: double('col91').primaryKey().autoincrement().default(0), + col920: double('col91').primaryKey().autoincrement().default(0), + col921: double('col91').primaryKey().autoincrement().default(0), + col922: double('col91').primaryKey().autoincrement().default(0), + col923: double('col91').primaryKey().autoincrement().default(0), + col924: double('col91').primaryKey().autoincrement().default(0), + col925: double('col91').primaryKey().autoincrement().default(0), + col926: double('col91').primaryKey().autoincrement().default(0), + col928: double('col91').primaryKey().autoincrement().default(0), + col929: double('col91').primaryKey().autoincrement().default(0), + col930: double('col91').primaryKey().autoincrement().default(0), + col931: double('col91').primaryKey().autoincrement().default(0), + col932: double('col91').primaryKey().autoincrement().default(0), + col933: double('col91').primaryKey().autoincrement().default(0), + col934: double('col91').primaryKey().autoincrement().default(0), + col935: double('col91').primaryKey().autoincrement().default(0), + col936: double('col91').primaryKey().autoincrement().default(0), + col938: double('col91').primaryKey().autoincrement().default(0), + col939: double('col91').primaryKey().autoincrement().default(0), + col940: double('col91').primaryKey().autoincrement().default(0), + col941: double('col91').primaryKey().autoincrement().default(0), + col942: double('col91').primaryKey().autoincrement().default(0), + col943: double('col91').primaryKey().autoincrement().default(0), + col944: varchar('col91', { length: 200 }).primaryKey().default('0'), + col945: varchar('col91', { length: 200 }).primaryKey().default('0'), + col946: varchar('col91', { length: 200 }).primaryKey().default('0'), + col948: varchar('col91', { length: 200 }).primaryKey().default('0'), + col949: varchar('col91', { length: 200 }).primaryKey().default('0'), + col950: varchar('col91', { length: 200 }).primaryKey().default('0'), + col951: varchar('col91', { length: 200 }).primaryKey().default('0'), + col952: varchar('col91', { length: 200 }).primaryKey().default('0'), + col953: varchar('col91', { length: 200 }).primaryKey().default('0'), + col954: varchar('col91', { length: 200 }).primaryKey().default('0'), + col955: varchar('col91', { length: 200 }).primaryKey().default('0'), + col956: varchar('col91', { length: 200 }).primaryKey().default('0'), + col958: varchar('col91', { length: 200 }).primaryKey().default('0'), + col959: varchar('col91', { length: 200 }).primaryKey().default('0'), + col960: varchar('col91', { length: 200 }).primaryKey().default('0'), + col961: varchar('col91', { length: 200 }).primaryKey().default('0'), + col962: varchar('col91', { length: 200 }).primaryKey().default('0'), + col963: varchar('col91', { length: 200 }).primaryKey().default('0'), + col964: varchar('col91', { length: 200 }).primaryKey().default('0'), + col965: varchar('col91', { length: 200 }).primaryKey().default('0'), + col966: varchar('col91', { length: 200 }).primaryKey().default('0'), + col968: varchar('col91', { length: 200 }).primaryKey().default('0'), + col969: varchar('col91', { length: 200 }).primaryKey().default('0'), + col970: varchar('col91', { length: 200 }).primaryKey().default('0'), + col971: varchar('col91', { length: 200 }).primaryKey().default('0'), + col972: varchar('col91', { length: 200 }).primaryKey().default('0'), + col973: varchar('col91', { length: 200 }).primaryKey().default('0'), + col974: varchar('col91', { length: 200 }).primaryKey().default('0'), + col975: varchar('col91', { length: 200 }).primaryKey().default('0'), + col976: varchar('col91', { length: 200 }).primaryKey().default('0'), + col978: varchar('col91', { length: 200 }).primaryKey().default('0'), + col979: varchar('col91', { length: 200 }).primaryKey().default('0'), + col980: varchar('col91', { length: 200 }).primaryKey().default('0'), + col981: varchar('col91', { length: 200 }).primaryKey().default('0'), + col982: varchar('col91', { length: 200 }).primaryKey().default('0'), + col983: varchar('col91', { length: 200 }).primaryKey().default('0'), + col984: varchar('col91', { length: 200 }).primaryKey().default('0'), + col985: varchar('col91', { length: 200 }).primaryKey().default('0'), + col986: varchar('col91', { length: 200 }).primaryKey().default('0'), + col988: varchar('col91', { length: 200 }).primaryKey().default('0'), + col989: varchar('col91', { length: 200 }).primaryKey().default('0'), + col990: varchar('col91', { length: 200 }).primaryKey().default('0'), + col991: varchar('col91', { length: 200 }).primaryKey().default('0'), + col992: varchar('col91', { length: 200 }).primaryKey().default('0'), + col993: varchar('col91', { length: 200 }).primaryKey().default('0'), + col994: varchar('col91', { length: 200 }).primaryKey().default('0'), + col995: varchar('col91', { length: 200 }).primaryKey().default('0'), + col996: varchar('col91', { length: 200 }).primaryKey().default('0'), + col998: varchar('col91', { length: 200 }).primaryKey().default('0'), + col999: varchar('col91', { length: 200 }).primaryKey().default('0'), +}); diff --git a/drizzle-orm/type-tests/singlestore/db.ts b/drizzle-orm/type-tests/singlestore/db.ts new file mode 100644 index 000000000..f9bc6ff5f --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/db.ts @@ -0,0 +1,12 @@ +import { createPool } from 'mysql2/promise'; +import { drizzle } from '~/singlestore/index.ts'; + +const pool = createPool({}); + +export const db = drizzle(pool); + +{ + drizzle(pool); + drizzle(pool, {}); + drizzle(pool, { schema: {} }); +} diff --git a/drizzle-orm/type-tests/singlestore/delete.ts b/drizzle-orm/type-tests/singlestore/delete.ts new file mode 100644 index 000000000..0fce8882e --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/delete.ts @@ -0,0 +1,61 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { eq } from '~/expressions.ts'; +import type { SingleStoreDelete } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +const deleteAll = await db.delete(users); +Expect>; + +const deleteAllStmt = db.delete(users).prepare(); +const deleteAllPrepared = await deleteAllStmt.execute(); +Expect>; + +const deleteWhere = await db.delete(users).where(eq(users.id, 1)); +Expect>; + +const deleteWhereStmt = db.delete(users).where(eq(users.id, 1)).prepare(); +const deleteWherePrepared = await deleteWhereStmt.execute(); +Expect>; + +const deleteReturningAll = await db.delete(users); +Expect>; + +const deleteReturningAllStmt = db.delete(users).prepare(); +const deleteReturningAllPrepared = await deleteReturningAllStmt.execute(); +Expect>; + +const deleteReturningPartial = await db.delete(users); +Expect>; + +const deleteReturningPartialStmt = db.delete(users).prepare(); +const deleteReturningPartialPrepared = await deleteReturningPartialStmt.execute(); +Expect>; + +{ + function dynamic(qb: T) { + return qb.where(sql``); + } + + const qbBase = db.delete(users).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .delete(users) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); + + db + .delete(users) + .$dynamic() + .where(sql``) + .where(sql``); +} diff --git a/drizzle-orm/type-tests/singlestore/generated-columns.ts b/drizzle-orm/type-tests/singlestore/generated-columns.ts new file mode 100644 index 000000000..e5b17a9b1 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/generated-columns.ts @@ -0,0 +1,158 @@ +import { type Equal, Expect } from 'type-tests/utils'; +import { type InferInsertModel, type InferSelectModel, sql } from '~/index'; +import { drizzle } from '~/singlestore'; +import { serial, singlestoreTable, text, varchar } from '~/singlestore-core'; +import { db } from './db'; + +const users = singlestoreTable( + 'users', + { + id: serial('id').primaryKey(), + firstName: varchar('first_name', { length: 255 }), + lastName: varchar('last_name', { length: 255 }), + email: text('email').notNull(), + fullName: text('full_name').generatedAlwaysAs(sql`concat_ws(first_name, ' ', last_name)`), + upperName: text('upper_name').generatedAlwaysAs( + sql` case when first_name is null then null else upper(first_name) end `, + ).$type(), // There is no way for drizzle to detect nullability in these cases. This is how the user can work around it + }, +); +{ + type User = typeof users.$inferSelect; + type NewUser = typeof users.$inferInsert; + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }, + User + > + >(); + + Expect< + Equal< + { + email: string; + id?: number | undefined; + firstName?: string | null | undefined; + lastName?: string | null | undefined; + }, + NewUser + > + >(); +} + +{ + type User = InferSelectModel; + type NewUser = InferInsertModel; + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }, + User + > + >(); + + Expect< + Equal< + { + email: string; + id?: number | undefined; + firstName?: string | null | undefined; + lastName?: string | null | undefined; + }, + NewUser + > + >(); +} + +{ + const dbUsers = await db.select().from(users); + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }[], + typeof dbUsers + > + >(); +} + +{ + const db = drizzle({} as any, { schema: { users } }); + + const dbUser = await db.query.users.findFirst(); + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + } | undefined, + typeof dbUser + > + >(); +} + +{ + const db = drizzle({} as any, { schema: { users } }); + + const dbUser = await db.query.users.findMany(); + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }[], + typeof dbUser + > + >(); +} + +{ + // @ts-expect-error - Can't use the fullName because it's a generated column + await db.insert(users).values({ + firstName: 'test', + lastName: 'test', + email: 'test', + fullName: 'test', + }); +} + +{ + await db.update(users).set({ + firstName: 'test', + lastName: 'test', + email: 'test', + // @ts-expect-error - Can't use the fullName because it's a generated column + fullName: 'test', + }); +} diff --git a/drizzle-orm/type-tests/singlestore/insert.ts b/drizzle-orm/type-tests/singlestore/insert.ts new file mode 100644 index 000000000..738bf669d --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/insert.ts @@ -0,0 +1,135 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { int, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import type { SingleStoreInsert } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +const singlestoreInsertReturning = await db.insert(users).values({ + // ^? + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).$returningId(); + +Expect>; + +const insert = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertPrepared = await insertStmt.execute(); +Expect>; + +const insertSql = await db.insert(users).values({ + homeCity: sql`123`, + class: 'A', + age1: 1, + enumCol: sql`foobar`, +}); +Expect>; + +const insertSqlStmt = db.insert(users).values({ + homeCity: sql`123`, + class: 'A', + age1: 1, + enumCol: sql`foobar`, +}).prepare(); +const insertSqlPrepared = await insertSqlStmt.execute(); +Expect>; + +const insertReturning = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertReturningStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertReturningPrepared = await insertReturningStmt.execute(); +Expect>; + +const insertReturningPartial = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertReturningPartialStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertReturningPartialPrepared = await insertReturningPartialStmt.execute(); +Expect>; + +const insertReturningSql = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: sql`2 + 2`, + enumCol: 'a', +}); +Expect>; + +const insertReturningSqlStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: sql`2 + 2`, + enumCol: 'a', +}).prepare(); +const insertReturningSqlPrepared = await insertReturningSqlStmt.execute(); +Expect>; + +{ + const users = singlestoreTable('users', { + id: int('id').autoincrement().primaryKey(), + name: text('name').notNull(), + age: int('age'), + occupation: text('occupation'), + }); + + await db.insert(users).values({ name: 'John Wick', age: 58, occupation: 'housekeeper' }); +} + +{ + function dynamic(qb: T) { + return qb.onDuplicateKeyUpdate({ set: {} }); + } + + const qbBase = db.insert(users).values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0 }).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + + Expect>; +} + +{ + db + .insert(users) + .values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0 }) + .onDuplicateKeyUpdate({ set: {} }) + // @ts-expect-error method was already called + .onDuplicateKeyUpdate({ set: {} }); +} diff --git a/drizzle-orm/type-tests/singlestore/select.ts b/drizzle-orm/type-tests/singlestore/select.ts new file mode 100644 index 000000000..10a7551a7 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/select.ts @@ -0,0 +1,606 @@ +import { + and, + between, + eq, + exists, + gt, + gte, + ilike, + inArray, + isNotNull, + isNull, + like, + lt, + lte, + ne, + not, + notBetween, + notExists, + notIlike, + notInArray, + notLike, + or, +} from '~/expressions.ts'; +import { alias } from '~/singlestore-core/alias.ts'; +import { param, sql } from '~/sql/sql.ts'; + +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { QueryBuilder, type SingleStoreSelect, type SingleStoreSelectQueryBuilder } from '~/singlestore-core/index.ts'; +import { db } from './db.ts'; +import { cities, classes, newYorkers, users } from './tables.ts'; + +const city = alias(cities, 'city'); +const city1 = alias(cities, 'city1'); + +const join = await db + .select({ + users, + cities, + city, + city1: { + id: city1.id, + }, + }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)) + .rightJoin(city, eq(city.id, users.id)) + .rightJoin(city1, eq(city1.id, users.id)); + +Expect< + Equal< + { + users: { + id: number; + text: string | null; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + } | null; + cities: { + id: number; + name: string; + population: number | null; + } | null; + city: { + id: number; + name: string; + population: number | null; + } | null; + city1: { + id: number; + }; + }[], + typeof join + > +>; + +const join2 = await db + .select({ + userId: users.id, + cityId: cities.id, + }) + .from(users) + .fullJoin(cities, eq(users.id, cities.id)); + +Expect< + Equal< + { + userId: number | null; + cityId: number | null; + }[], + typeof join2 + > +>; + +const join3 = await db + .select({ + userId: users.id, + cityId: cities.id, + classId: classes.id, + }) + .from(users) + .fullJoin(cities, eq(users.id, cities.id)) + .rightJoin(classes, eq(users.id, classes.id)); + +Expect< + Equal< + { + userId: number | null; + cityId: number | null; + classId: number; + }[], + typeof join3 + > +>; + +db + .select() + .from(users) + .where(exists(db.select().from(cities).where(eq(users.homeCity, cities.id)))); + +function mapFunkyFuncResult(valueFromDriver: unknown) { + return { + foo: (valueFromDriver as Record)['foo'], + }; +} + +const age = 1; + +const allOperators = await db + .select({ + col2: sql`5 - ${users.id} + 1`, // unknown + col3: sql`${users.id} + 1`, // number + col33: sql`${users.id} + 1`.mapWith(users.id), // number + col34: sql`${users.id} + 1`.mapWith(mapFunkyFuncResult), // number + col4: sql`one_or_another(${users.id}, ${users.class})`, // string | number + col5: sql`true`, // unknown + col6: sql`true`, // boolean + col7: sql`random()`, // number + col8: sql`some_funky_func(${users.id})`.mapWith(mapFunkyFuncResult), // { foo: string } + col9: sql`greatest(${users.createdAt}, ${param(new Date(), users.createdAt)})`, // unknown + col10: sql`date_or_false(${users.createdAt}, ${param(new Date(), users.createdAt)})`, // Date | boolean + col11: sql`${users.age1} + ${age}`, // unknown + col12: sql`${users.age1} + ${param(age, users.age1)}`, // unknown + col13: sql`lower(${users.class})`, // unknown + col14: sql`length(${users.class})`, // number + count: sql`count(*)::int`, // number + }) + .from(users) + .where(and( + eq(users.id, 1), + ne(users.id, 1), + or(eq(users.id, 1), ne(users.id, 1)), + not(eq(users.id, 1)), + gt(users.id, 1), + gte(users.id, 1), + lt(users.id, 1), + lte(users.id, 1), + inArray(users.id, [1, 2, 3]), + inArray(users.id, db.select({ id: users.id }).from(users)), + inArray(users.id, sql`select id from ${users}`), + notInArray(users.id, [1, 2, 3]), + notInArray(users.id, db.select({ id: users.id }).from(users)), + notInArray(users.id, sql`select id from ${users}`), + isNull(users.subClass), + isNotNull(users.id), + exists(db.select({ id: users.id }).from(users)), + exists(sql`select id from ${users}`), + notExists(db.select({ id: users.id }).from(users)), + notExists(sql`select id from ${users}`), + between(users.id, 1, 2), + notBetween(users.id, 1, 2), + like(users.id, '%1%'), + notLike(users.id, '%1%'), + ilike(users.id, '%1%'), + notIlike(users.id, '%1%'), + )); + +Expect< + Equal<{ + col2: unknown; + col3: number; + col33: number; + col34: { foo: any }; + col4: string | number; + col5: unknown; + col6: boolean; + col7: number; + col8: { + foo: any; + }; + col9: unknown; + col10: boolean | Date; + col11: unknown; + col12: unknown; + col13: unknown; + col14: number; + count: number; + }[], typeof allOperators> +>; + +const textSelect = await db + .select({ + t: users.text, + }) + .from(users); + +Expect>; + +const homeCity = alias(cities, 'homeCity'); +const c = alias(classes, 'c'); +const otherClass = alias(classes, 'otherClass'); +const anotherClass = alias(classes, 'anotherClass'); +const friend = alias(users, 'friend'); +const currentCity = alias(cities, 'currentCity'); +const subscriber = alias(users, 'subscriber'); +const closestCity = alias(cities, 'closestCity'); + +const megaJoin = await db + .select({ + user: { + id: users.id, + maxAge: sql`max(${users.age1})`, + }, + city: { + id: cities.id, + }, + homeCity, + c, + otherClass, + anotherClass, + friend, + currentCity, + subscriber, + closestCity, + }) + .from(users) + .innerJoin(cities, sql`${users.id} = ${cities.id}`) + .innerJoin(homeCity, sql`${users.homeCity} = ${homeCity.id}`) + .innerJoin(c, eq(c.id, users.class)) + .innerJoin(otherClass, sql`${c.id} = ${otherClass.id}`) + .innerJoin(anotherClass, sql`${users.class} = ${anotherClass.id}`) + .innerJoin(friend, sql`${users.id} = ${friend.id}`) + .innerJoin(currentCity, sql`${homeCity.id} = ${currentCity.id}`) + .innerJoin(subscriber, sql`${users.class} = ${subscriber.id}`) + .innerJoin(closestCity, sql`${users.currentCity} = ${closestCity.id}`) + .where(and(sql`${users.age1} > 0`, eq(cities.id, 1))) + .limit(1) + .offset(1); + +Expect< + Equal< + { + user: { + id: number; + maxAge: unknown; + }; + city: { + id: number; + }; + homeCity: { + id: number; + name: string; + population: number | null; + }; + c: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + otherClass: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + anotherClass: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + friend: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + currentCity: { + id: number; + name: string; + population: number | null; + }; + subscriber: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + closestCity: { + id: number; + name: string; + population: number | null; + }; + }[], + typeof megaJoin + > +>; + +const friends = alias(users, 'friends'); + +const join4 = await db + .select({ + user: { + id: users.id, + }, + city: { + id: cities.id, + }, + class: classes, + friend: friends, + }) + .from(users) + .innerJoin(cities, sql`${users.id} = ${cities.id}`) + .innerJoin(classes, sql`${cities.id} = ${classes.id}`) + .innerJoin(friends, sql`${friends.id} = ${users.id}`) + .where(sql`${users.age1} > 0`); + +Expect< + Equal<{ + user: { + id: number; + }; + city: { + id: number; + }; + class: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + friend: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + }[], typeof join4> +>; + +{ + const authenticated = false as boolean; + + const result = await db + .select({ + id: users.id, + ...(authenticated ? { city: users.homeCity } : {}), + }) + .from(users); + + Expect< + Equal< + { + id: number; + city?: number; + }[], + typeof result + > + >; +} + +await db.select().from(users).for('update'); +await db.select().from(users).for('share', { skipLocked: true }); +await db.select().from(users).for('update', { noWait: true }); +await db + .select() + .from(users) + // @ts-expect-error - can't use both skipLocked and noWait + .for('share', { noWait: true, skipLocked: true }); + +{ + const result = await db.select().from(newYorkers); + Expect< + Equal< + { + userId: number; + cityId: number | null; + }[], + typeof result + > + >; +} + +{ + const result = await db.select({ userId: newYorkers.userId }).from(newYorkers); + Expect< + Equal< + { + userId: number; + }[], + typeof result + > + >; +} + +{ + const query = db.select().from(users).prepare().iterator(); + for await (const row of query) { + Expect>(); + } +} + +{ + db + .select() + .from(users) + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + .limit(10) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const qb = db.select().from(users).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +{ + // TODO: add to docs + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const query = new QueryBuilder().select().from(users).$dynamic(); + dynamic(query); +} + +{ + // TODO: add to docs + function paginated(qb: T, page: number) { + return qb.limit(10).offset((page - 1) * 10); + } + + const qb = db.select().from(users).$dynamic(); + const result = await paginated(qb, 1); + + Expect>; +} + +{ + db + .select() + .from(users) + .where(sql``) + .limit(10) + // @ts-expect-error method was already called + .where(sql``); + + db + .select() + .from(users) + .having(sql``) + .limit(10) + // @ts-expect-error method was already called + .having(sql``); + + db + .select() + .from(users) + .groupBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .groupBy(sql``); + + db + .select() + .from(users) + .orderBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .orderBy(sql``); + + db + .select() + .from(users) + .limit(10) + .where(sql``) + // @ts-expect-error method was already called + .limit(10); + + db + .select() + .from(users) + .offset(10) + .limit(10) + // @ts-expect-error method was already called + .offset(10); + + db + .select() + .from(users) + .for('update') + .limit(10) + // @ts-expect-error method was already called + .for('update'); +} diff --git a/drizzle-orm/type-tests/singlestore/set-operators.ts b/drizzle-orm/type-tests/singlestore/set-operators.ts new file mode 100644 index 000000000..aa4f21b9c --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/set-operators.ts @@ -0,0 +1,223 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import { eq } from '~/expressions.ts'; +import { except, intersect, type SingleStoreSetOperator, union, unionAll } from '~/singlestore-core/index.ts'; +import { sql } from '~/sql/index.ts'; +import { db } from './db.ts'; +import { cities, classes, newYorkers, users } from './tables.ts'; + +const unionTest = await db + .select({ id: users.id }) + .from(users) + .union( + db + .select({ id: users.id }) + .from(users), + ); + +Expect>; + +const unionAllTest = await db + .select({ id: users.id, age: users.age1 }) + .from(users) + .unionAll( + db.select({ id: users.id, age: users.age1 }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)), + ); + +Expect>; + +const intersectTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .intersect(({ intersect }) => + intersect( + db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users), + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ) + ); + +Expect>; + +const exceptTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .except( + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ); + +Expect>; + +const union2Test = await union(db.select().from(cities), db.select().from(cities), db.select().from(cities)); + +Expect>; + +const unionAll2Test = await unionAll( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select().from(cities), +); + +Expect>; + +const intersect2Test = await intersect( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), +); + +Expect>; + +const except2Test = await except( + db.select({ + userId: newYorkers.userId, + }) + .from(newYorkers), + db.select({ + userId: newYorkers.userId, + }).from(newYorkers), +); + +Expect>; + +const unionfull = await union(db.select().from(users), db.select().from(users)).orderBy(sql``).limit(1).offset(2); + +Expect< + Equal<{ + id: number; + text: string | null; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }[], typeof unionfull> +>; + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +union(db.select().from(users), db.select().from(users)) + .offset(1) + // @ts-expect-error - method was already called + .offset(2); + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +{ + function dynamic(qb: T) { + return qb.orderBy(sql``).limit(1).offset(2); + } + + const qb = union(db.select().from(users), db.select().from(users)).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + .intersect(({ intersect }) => intersect(db.select().from(users), db.select().from(users))); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select().from(classes).union(db.select({ id: classes.id }).from(classes)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes).where(sql``)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes)); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + db.select({ id: cities.id, name: cities.name }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select().from(cities), +); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities), + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``).limit(3).$dynamic(), + db.select({ id: cities.id, name: cities.name }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: newYorkers.userId }).from(newYorkers), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities).where(sql``), + db.select({ id: sql`${cities.id}` }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities).where(sql``), +); diff --git a/drizzle-orm/type-tests/singlestore/subquery.ts b/drizzle-orm/type-tests/singlestore/subquery.ts new file mode 100644 index 000000000..e8ee4e80b --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/subquery.ts @@ -0,0 +1,97 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, eq } from '~/expressions.ts'; +import { alias, int, serial, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import { sql } from '~/sql/sql.ts'; +import type { DrizzleTypeError, Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = singlestoreTable('names', { + id: serial('id').primaryKey(), + name: text('name'), + authorId: int('author_id'), +}); + +const n1 = db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: sql`count(1)::int`.as('count1'), + }) + .from(names) + .groupBy(names.id, names.name, names.authorId) + .as('n1'); + +const n2 = db + .select({ + id: names.id, + authorId: names.authorId, + totalCount: sql`count(1)::int`.as('totalCount'), + }) + .from(names) + .groupBy(names.id, names.authorId) + .as('n2'); + +const result = await db + .select({ + name: n1.name, + authorId: n1.authorId, + count1: n1.count1, + totalCount: n2.totalCount, + }) + .from(n1) + .innerJoin(n2, and(eq(n2.id, n1.id), eq(n2.authorId, n1.authorId))); + +Expect< + Equal< + { + name: string | null; + authorId: number | null; + count1: number; + totalCount: number; + }[], + typeof result + > +>; + +const names2 = alias(names, 'names2'); + +const sq1 = db + .select({ + id: names.id, + name: names.name, + id2: names2.id, + }) + .from(names) + .leftJoin(names2, eq(names.name, names2.name)) + .as('sq1'); + +const res = await db.select().from(sq1); + +Expect< + Equal< + { + id: number; + name: string | null; + id2: number | null; + }[], + typeof res + > +>; + +{ + const sq = db.select({ count: sql`count(1)::int` }).from(names).as('sq'); + Expect ? true : false>; +} + +const sqUnion = db.select().from(names).union(db.select().from(names2)).as('sqUnion'); + +const resUnion = await db.select().from(sqUnion); + +Expect< + Equal<{ + id: number; + name: string | null; + authorId: number | null; + }[], typeof resUnion> +>; diff --git a/drizzle-orm/type-tests/singlestore/tables.ts b/drizzle-orm/type-tests/singlestore/tables.ts new file mode 100644 index 000000000..18ed96a30 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/tables.ts @@ -0,0 +1,751 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import { eq, gt } from '~/expressions.ts'; +import type { BuildColumn, InferSelectModel, Simplify } from '~/index.ts'; +import { + bigint, + char, + customType, + date, + datetime, + decimal, + index, + int, + json, + longtext, + mediumtext, + primaryKey, + serial, + type SingleStoreColumn, + singlestoreEnum, + singlestoreSchema, + singlestoreTable, + text, + timestamp, + tinytext, + unique, + uniqueIndex, + varchar, +} from '~/singlestore-core/index.ts'; + +import { singlestoreView, type SingleStoreViewWithSelection } from '~/singlestore-core/view.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; + +export const users = singlestoreTable( + 'users_table', + { + id: serial('id').primaryKey(), + homeCity: int('home_city') + .notNull(), + currentCity: int('current_city'), + serialNullable: serial('serial1'), + serialNotNull: serial('serial2').notNull(), + class: text('class', { enum: ['A', 'C'] }).notNull(), + subClass: text('sub_class', { enum: ['B', 'D'] }), + text: text('text'), + age1: int('age1').notNull(), + createdAt: timestamp('created_at', { mode: 'date' }).notNull().defaultNow(), + enumCol: singlestoreEnum('enum_col', ['a', 'b', 'c']).notNull(), + }, + (users) => ({ + usersAge1Idx: uniqueIndex('usersAge1Idx').on(users.class), + usersAge2Idx: index('usersAge2Idx').on(users.class), + uniqueClass: uniqueIndex('uniqueClass') + .on(users.class, users.subClass) + .lock('default') + .algorythm('copy') + .using(`btree`), + pk: primaryKey(users.age1, users.class), + }), +); + +export const cities = singlestoreTable('cities_table', { + id: serial('id').primaryKey(), + name: text('name_db').notNull(), + population: int('population').default(0), +}, (cities) => ({ + citiesNameIdx: index('citiesNameIdx').on(cities.id), +})); + +Expect< + Equal< + { + id: SingleStoreColumn<{ + name: 'id'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + isPrimaryKey: true; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isAutoincrement: true; + hasRuntimeDefault: false; + }, object>; + name: SingleStoreColumn<{ + name: 'name_db'; + tableName: 'cities_table'; + dataType: 'string'; + columnType: 'SingleStoreText'; + data: string; + driverParam: string; + notNull: true; + hasDefault: false; + isPrimaryKey: false; + enumValues: [string, ...string[]]; + baseColumn: never; + generated: undefined; + isAutoincrement: false; + hasRuntimeDefault: false; + }, object>; + population: SingleStoreColumn<{ + name: 'population'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + notNull: false; + hasDefault: true; + isPrimaryKey: false; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isAutoincrement: false; + hasRuntimeDefault: false; + }, object>; + }, + typeof cities._.columns + > +>; + +Expect< + Equal<{ + id: number; + name_db: string; + population: number | null; + }, InferSelectModel> +>; + +Expect< + Equal<{ + id?: number; + name: string; + population?: number | null; + }, typeof cities.$inferInsert> +>; + +export const customSchema = singlestoreSchema('custom_schema'); + +export const citiesCustom = customSchema.table('cities_table', { + id: serial('id').primaryKey(), + name: text('name_db').notNull(), + population: int('population').default(0), +}, (cities) => ({ + citiesNameIdx: index('citiesNameIdx').on(cities.id), +})); + +Expect>; + +export const classes = singlestoreTable('classes_table', { + id: serial('id').primaryKey(), + class: text('class', { enum: ['A', 'C'] }), + subClass: text('sub_class', { enum: ['B', 'D'] }).notNull(), +}); + +/* export const classes2 = singlestoreTable('classes_table', { + id: serial().primaryKey(), + class: text({ enum: ['A', 'C'] }).$dbName('class_db'), + subClass: text({ enum: ['B', 'D'] }).notNull(), +}); */ + +export const newYorkers = singlestoreView('new_yorkers') + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + +Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: false; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > +>; + +{ + const newYorkers = customSchema.view('new_yorkers') + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: false; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = singlestoreView('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }) + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as( + sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ + eq(cities.id, users.homeCity) + } where ${gt(users.age1, 18)}`, + ); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = customSchema.view('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }) + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as( + sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ + eq(cities.id, users.homeCity) + } where ${gt(users.age1, 18)}`, + ); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = singlestoreView('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }).existing(); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', true, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = customSchema.view('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }).existing(); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', true, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const customText = customType<{ data: string }>({ + dataType() { + return 'text'; + }, + }); + + const t = customText('name').notNull(); + Expect< + Equal< + { + brand: 'Column'; + name: 'name'; + tableName: 'table'; + dataType: 'custom'; + columnType: 'SingleStoreCustomColumn'; + data: string; + driverParam: unknown; + notNull: true; + hasDefault: false; + enumValues: undefined; + baseColumn: never; + dialect: 'singlestore'; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }, + Simplify['_']> + > + >; +} + +{ + singlestoreTable('test', { + bigint: bigint('bigint', { mode: 'bigint' }), + number: bigint('number', { mode: 'number' }), + date: date('date').default(new Date()), + date2: date('date2', { mode: 'date' }).default(new Date()), + date3: date('date3', { mode: 'string' }).default('2020-01-01'), + date4: date('date4', { mode: undefined }).default(new Date()), + datetime: datetime('datetime').default(new Date()), + datetime2: datetime('datetime2', { mode: 'date' }).default(new Date()), + datetime3: datetime('datetime3', { mode: 'string' }).default('2020-01-01'), + datetime4: datetime('datetime4', { mode: undefined }).default(new Date()), + timestamp: timestamp('timestamp').default(new Date()), + timestamp2: timestamp('timestamp2', { mode: 'date' }).default(new Date()), + timestamp3: timestamp('timestamp3', { mode: 'string' }).default('2020-01-01'), + timestamp4: timestamp('timestamp4', { mode: undefined }).default(new Date()), + }); +} + +{ + singlestoreTable('test', { + col1: decimal('col1').default('1'), + }); +} + +{ + const test = singlestoreTable('test', { + test1: singlestoreEnum('test', ['a', 'b', 'c'] as const).notNull(), + test2: singlestoreEnum('test', ['a', 'b', 'c']).notNull(), + test3: varchar('test', { length: 255, enum: ['a', 'b', 'c'] as const }).notNull(), + test4: varchar('test', { length: 255, enum: ['a', 'b', 'c'] }).notNull(), + test5: text('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test6: text('test', { enum: ['a', 'b', 'c'] }).notNull(), + test7: tinytext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test8: tinytext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test9: mediumtext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test10: mediumtext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test11: longtext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test12: longtext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test13: char('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test14: char('test', { enum: ['a', 'b', 'c'] }).notNull(), + test15: text('test').notNull(), + }); + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; +} + +{ // All types with generated columns + const test = singlestoreTable('test', { + test1: singlestoreEnum('test', ['a', 'b', 'c'] as const).generatedAlwaysAs(sql``), + test2: singlestoreEnum('test', ['a', 'b', 'c']).generatedAlwaysAs(sql``), + test3: varchar('test', { length: 255, enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test4: varchar('test', { length: 255, enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test5: text('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test6: text('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test7: tinytext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test8: tinytext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test9: mediumtext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test10: mediumtext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test11: longtext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test12: longtext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test13: char('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test14: char('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test15: text('test').generatedAlwaysAs(sql``), + }); + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; +} + +{ + const getUsersTable = (schemaName: TSchema) => { + return singlestoreSchema(schemaName).table('users', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }); + }; + + const users1 = getUsersTable('id1'); + Expect>; + + const users2 = getUsersTable('id2'); + Expect>; +} + +{ + const internalStaff = singlestoreTable('internal_staff', { + userId: int('user_id').notNull(), + }); + + const customUser = singlestoreTable('custom_user', { + id: int('id').notNull(), + }); + + const ticket = singlestoreTable('ticket', { + staffId: int('staff_id').notNull(), + }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin( + customUser, + eq(internalStaff.userId, customUser.id), + ).as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + Expect< + Equal<{ + internal_staff: { + internal_staff: { + userId: number; + }; + custom_user: { + id: number | null; + }; + } | null; + ticket: { + staffId: number; + }; + }[], typeof mainQuery> + >; +} + +{ + const newYorkers = singlestoreView('new_yorkers') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + + await db.select().from(newYorkers).leftJoin(newYorkers, eq(newYorkers.userId, newYorkers.userId)); +} + +{ + const test = singlestoreTable('test', { + id: text('id').$defaultFn(() => crypto.randomUUID()).primaryKey(), + }); + + Expect< + Equal<{ + id?: string; + }, typeof test.$inferInsert> + >; +} + +{ + singlestoreTable('test', { + id: int('id').$default(() => 1), + id2: int('id').$defaultFn(() => 1), + // @ts-expect-error - should be number + id3: int('id').$default(() => '1'), + // @ts-expect-error - should be number + id4: int('id').$defaultFn(() => '1'), + }); +} +{ + const emailLog = singlestoreTable( + 'email_log', + { + id: int('id', { unsigned: true }).autoincrement().notNull(), + clientId: int('id_client', { unsigned: true }), + receiverEmail: varchar('receiver_email', { length: 255 }).notNull(), + messageId: varchar('message_id', { length: 255 }), + contextId: int('context_id', { unsigned: true }), + contextType: singlestoreEnum('context_type', ['test']).$type<['test']>(), + action: varchar('action', { length: 80 }).$type<['test']>(), + events: json('events').$type<{ t: 'test' }[]>(), + createdAt: timestamp('created_at', { mode: 'string' }).defaultNow().notNull(), + updatedAt: timestamp('updated_at', { mode: 'string' }).defaultNow().onUpdateNow(), + }, + (table) => { + return { + emailLogId: primaryKey({ columns: [table.id], name: 'email_log_id' }), + emailLogMessageIdUnique: unique('email_log_message_id_unique').on(table.messageId), + }; + }, + ); + + Expect< + Equal<{ + receiverEmail: string; + id?: number | undefined; + createdAt?: string | undefined; + clientId?: number | null | undefined; + messageId?: string | null | undefined; + contextId?: number | null | undefined; + contextType?: ['test'] | null | undefined; + action?: ['test'] | null | undefined; + events?: + | { + t: 'test'; + }[] + | null + | undefined; + updatedAt?: string | null | undefined; + }, typeof emailLog.$inferInsert> + >; +} diff --git a/drizzle-orm/type-tests/singlestore/update.ts b/drizzle-orm/type-tests/singlestore/update.ts new file mode 100644 index 000000000..3f10ae2e4 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/update.ts @@ -0,0 +1,26 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import type { SingleStoreUpdate } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/session.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +{ + function dynamic(qb: T) { + return qb.where(sql``); + } + + const qbBase = db.update(users).set({}).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .update(users) + .set({}) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); +} diff --git a/drizzle-orm/type-tests/singlestore/with.ts b/drizzle-orm/type-tests/singlestore/with.ts new file mode 100644 index 000000000..77309e32a --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/with.ts @@ -0,0 +1,80 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { gt, inArray } from '~/expressions.ts'; +import { int, serial, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; + +const orders = singlestoreTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull(), + amount: int('amount').notNull(), + quantity: int('quantity').notNull(), + generated: text('generatedText').generatedAlwaysAs(sql``), +}); + +{ + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: orders.region, + totalSales: orders.amount, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`sum(${orders.quantity})`, + productSales: sql`sum(${orders.amount})`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))); + + Expect< + Equal<{ + region: string; + product: string; + productUnits: number; + productSales: number; + }[], typeof result> + >; + + const allOrdersWith = db.$with('all_orders_with').as(db.select().from(orders)); + const allFromWith = await db.with(allOrdersWith).select().from(allOrdersWith); + + Expect< + Equal<{ + id: number; + region: string; + product: string; + amount: number; + quantity: number; + generated: string | null; + }[], typeof allFromWith> + >; +} diff --git a/integration-tests/.env.example b/integration-tests/.env.example index ceff7d132..cad737330 100644 --- a/integration-tests/.env.example +++ b/integration-tests/.env.example @@ -1,5 +1,6 @@ PG_CONNECTION_STRING="postgres://postgres:postgres@localhost:55432/postgres" MYSQL_CONNECTION_STRING="mysql://root:mysql@127.0.0.1:33306/drizzle" +SINGLESTORE_CONNECTION_STRING="singlestore://root:singlestore@localhost:3306/drizzle" PLANETSCALE_CONNECTION_STRING= TIDB_CONNECTION_STRING= NEON_CONNECTION_STRING= diff --git a/integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql b/integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql new file mode 100644 index 000000000..50efe47da --- /dev/null +++ b/integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql @@ -0,0 +1,20 @@ +CREATE TABLE `cities_migration` ( + `id` int, + `fullname_name` text, + `state` text +); +--> statement-breakpoint +CREATE TABLE `users_migration` ( + `id` int PRIMARY KEY NOT NULL, + `full_name` text, + `phone` int, + `invited_by` int, + `city_id` int, + `date` timestamp DEFAULT now() +); +--> statement-breakpoint +CREATE TABLE `users12` ( + `id` serial AUTO_INCREMENT PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `email` text NOT NULL +); diff --git a/integration-tests/drizzle2/singlestore/meta/0000_snapshot.json b/integration-tests/drizzle2/singlestore/meta/0000_snapshot.json new file mode 100644 index 000000000..63d5ad187 --- /dev/null +++ b/integration-tests/drizzle2/singlestore/meta/0000_snapshot.json @@ -0,0 +1,132 @@ +{ + "version": "1", + "dialect": "singlestore", + "id": "8e8c8378-0496-40f6-88e3-98aab8282b1f", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "cities_migration": { + "name": "cities_migration", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fullname_name": { + "name": "fullname_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {} + }, + "users_migration": { + "name": "users_migration", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "full_name": { + "name": "full_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "invited_by": { + "name": "invited_by", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "city_id": { + "name": "city_id", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "date": { + "name": "date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {} + }, + "users12": { + "name": "users12", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "my_unique_index": { + "name": "my_unique_index", + "columns": [ + "name" + ], + "isUnique": true, + "using": "btree" + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {} + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} diff --git a/integration-tests/drizzle2/singlestore/meta/_journal.json b/integration-tests/drizzle2/singlestore/meta/_journal.json new file mode 100644 index 000000000..49e74f169 --- /dev/null +++ b/integration-tests/drizzle2/singlestore/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "dialect": "singlestore", + "entries": [ + { + "idx": 0, + "version": "1", + "when": 1680270921944, + "tag": "0000_nostalgic_carnage", + "breakpoints": true + } + ] +} diff --git a/integration-tests/tests/relational/singlestore.schema.ts b/integration-tests/tests/relational/singlestore.schema.ts new file mode 100644 index 000000000..ca3386ba0 --- /dev/null +++ b/integration-tests/tests/relational/singlestore.schema.ts @@ -0,0 +1,106 @@ +import { bigint, boolean, primaryKey, serial, singlestoreTable, text, timestamp } from 'drizzle-orm/singlestore-core'; + +import { relations } from 'drizzle-orm'; + +export const usersTable = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + invitedBy: bigint('invited_by', { mode: 'number' }), +}); +export const usersConfig = relations(usersTable, ({ one, many }) => ({ + invitee: one(usersTable, { + fields: [usersTable.invitedBy], + references: [usersTable.id], + }), + usersToGroups: many(usersToGroupsTable), + posts: many(postsTable), + comments: many(commentsTable), +})); + +export const groupsTable = singlestoreTable('groups', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + description: text('description'), +}); +export const groupsConfig = relations(groupsTable, ({ many }) => ({ + usersToGroups: many(usersToGroupsTable), +})); + +export const usersToGroupsTable = singlestoreTable( + 'users_to_groups', + { + id: serial('id').primaryKey(), + userId: bigint('user_id', { mode: 'number' }).notNull(), + groupId: bigint('group_id', { mode: 'number' }).notNull(), + }, + (t) => ({ + pk: primaryKey(t.userId, t.groupId), + }), +); +export const usersToGroupsConfig = relations(usersToGroupsTable, ({ one }) => ({ + group: one(groupsTable, { + fields: [usersToGroupsTable.groupId], + references: [groupsTable.id], + }), + user: one(usersTable, { + fields: [usersToGroupsTable.userId], + references: [usersTable.id], + }), +})); + +export const postsTable = singlestoreTable('posts', { + id: serial('id').primaryKey(), + content: text('content').notNull(), + ownerId: bigint('owner_id', { mode: 'number' }), + createdAt: timestamp('created_at') + .notNull() + .defaultNow(), +}); +export const postsConfig = relations(postsTable, ({ one, many }) => ({ + author: one(usersTable, { + fields: [postsTable.ownerId], + references: [usersTable.id], + }), + comments: many(commentsTable), +})); + +export const commentsTable = singlestoreTable('comments', { + id: serial('id').primaryKey(), + content: text('content').notNull(), + creator: bigint('creator', { mode: 'number' }), + postId: bigint('post_id', { mode: 'number' }), + createdAt: timestamp('created_at') + .notNull() + .defaultNow(), +}); +export const commentsConfig = relations(commentsTable, ({ one, many }) => ({ + post: one(postsTable, { + fields: [commentsTable.postId], + references: [postsTable.id], + }), + author: one(usersTable, { + fields: [commentsTable.creator], + references: [usersTable.id], + }), + likes: many(commentLikesTable), +})); + +export const commentLikesTable = singlestoreTable('comment_likes', { + id: serial('id').primaryKey(), + creator: bigint('creator', { mode: 'number' }), + commentId: bigint('comment_id', { mode: 'number' }), + createdAt: timestamp('created_at') + .notNull() + .defaultNow(), +}); +export const commentLikesConfig = relations(commentLikesTable, ({ one }) => ({ + comment: one(commentsTable, { + fields: [commentLikesTable.commentId], + references: [commentsTable.id], + }), + author: one(usersTable, { + fields: [commentLikesTable.creator], + references: [usersTable.id], + }), +})); diff --git a/integration-tests/tests/relational/singlestore.test.ts b/integration-tests/tests/relational/singlestore.test.ts new file mode 100644 index 000000000..50aa2e8f4 --- /dev/null +++ b/integration-tests/tests/relational/singlestore.test.ts @@ -0,0 +1,6402 @@ +import retry from 'async-retry'; +import Docker from 'dockerode'; +import 'dotenv/config'; +import { desc, DrizzleError, eq, gt, gte, or, placeholder, sql, TransactionRollbackError } from 'drizzle-orm'; +import { drizzle, type SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +import getPort from 'get-port'; +import * as mysql from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, beforeEach, expect, expectTypeOf, test } from 'vitest'; +import * as schema from './singlestore.schema.ts'; + +const { usersTable, postsTable, commentsTable, usersToGroupsTable, groupsTable } = schema; + +const ENABLE_LOGGING = false; + +/* + Test cases: + - querying nested relation without PK with additional fields +*/ + +declare module 'vitest' { + export interface TestContext { + docker: Docker; + singlestoreContainer: Docker.Container; + singlestoreDb: SingleStoreDriverDatabase; + singlestoreClient: mysql.Connection; + } +} + +let globalDocker: Docker; +let singlestoreContainer: Docker.Container; +let db: SingleStoreDriverDatabase; +let client: mysql.Connection; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + ); + + singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return `singlestore://root:singlestore@localhost:${port}/`; +} + +beforeAll(async () => { + const connectionString = process.env['SINGLESTORE_CONNECTION_STRING'] ?? (await createDockerDB()); + client = await retry(async () => { + client = await mysql.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + db = drizzle(client, { schema, logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); +}); + +beforeEach(async (ctx) => { + ctx.singlestoreDb = db; + ctx.singlestoreClient = client; + ctx.docker = globalDocker; + ctx.singlestoreContainer = singlestoreContainer; + + await ctx.singlestoreDb.execute(sql`drop table if exists \`users\``); + await ctx.singlestoreDb.execute(sql`drop table if exists \`groups\``); + await ctx.singlestoreDb.execute(sql`drop table if exists \`users_to_groups\``); + await ctx.singlestoreDb.execute(sql`drop table if exists \`posts\``); + await ctx.singlestoreDb.execute(sql`drop table if exists \`comments\``); + await ctx.singlestoreDb.execute(sql`drop table if exists \`comment_likes\``); + + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`users\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`name\` text NOT NULL, + \`verified\` boolean DEFAULT false NOT NULL, + \`invited_by\` bigint + ); + `, + ); + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`groups\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`name\` text NOT NULL, + \`description\` text + ); + `, + ); + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`users_to_groups\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`user_id\` bigint, + \`group_id\` bigint + ); + `, + ); + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`posts\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`content\` text NOT NULL, + \`owner_id\` bigint, + \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL + ); + `, + ); + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`comments\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`content\` text NOT NULL, + \`creator\` bigint, + \`post_id\` bigint, + \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL + ); + `, + ); + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`comment_likes\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`creator\` bigint, + \`comment_id\` bigint, + \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL + ); + `, + ); +}); + +/* + [Find Many] One relation users+posts +*/ + +test('[Find Many] Get users with posts', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + with: { + posts: true, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithPosts.length).eq(3); + expect(usersWithPosts[0]?.posts.length).eq(1); + expect(usersWithPosts[1]?.posts.length).eq(1); + expect(usersWithPosts[2]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[2]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ id: 3, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find Many] Get users with posts + limit posts', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + with: { + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithPosts.length).eq(3); + expect(usersWithPosts[0]?.posts.length).eq(1); + expect(usersWithPosts[1]?.posts.length).eq(1); + expect(usersWithPosts[2]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[2]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find Many] Get users with posts + limit posts and users', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + limit: 2, + with: { + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithPosts.length).eq(2); + expect(usersWithPosts[0]?.posts.length).eq(1); + expect(usersWithPosts[1]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts + custom fields', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + with: { + posts: true, + }, + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lowerName: string; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithPosts.length).toEqual(3); + expect(usersWithPosts[0]?.posts.length).toEqual(3); + expect(usersWithPosts[1]?.posts.length).toEqual(2); + expect(usersWithPosts[2]?.posts.length).toEqual(2); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + lowerName: 'dan', + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }, { + id: 2, + ownerId: 1, + content: 'Post1.2', + createdAt: usersWithPosts[0]?.posts[1]?.createdAt, + }, { id: 3, ownerId: 1, content: 'Post1.3', createdAt: usersWithPosts[0]?.posts[2]?.createdAt }], + }); + expect(usersWithPosts[1]).toEqual({ + id: 2, + name: 'Andrew', + lowerName: 'andrew', + verified: false, + invitedBy: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }, { + id: 5, + ownerId: 2, + content: 'Post2.1', + createdAt: usersWithPosts[1]?.posts[1]?.createdAt, + }], + }); + expect(usersWithPosts[2]).toEqual({ + id: 3, + name: 'Alex', + lowerName: 'alex', + verified: false, + invitedBy: null, + posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }, { + id: 7, + ownerId: 3, + content: 'Post3.1', + createdAt: usersWithPosts[2]?.posts[1]?.createdAt, + }], + }); +}); + +test.skip('[Find Many] Get users with posts + custom fields + limits', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + limit: 1, + with: { + posts: { + limit: 1, + }, + }, + extras: (usersTable, { sql }) => ({ + lowerName: sql`lower(${usersTable.name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lowerName: string; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).toEqual(1); + expect(usersWithPosts[0]?.posts.length).toEqual(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + lowerName: 'dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find Many] Get users with posts + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: '1' }, + { ownerId: 1, content: '2' }, + { ownerId: 1, content: '3' }, + { ownerId: 2, content: '4' }, + { ownerId: 2, content: '5' }, + { ownerId: 3, content: '6' }, + { ownerId: 3, content: '7' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + with: { + posts: { + orderBy: (postsTable, { desc }) => [desc(postsTable.content)], + }, + }, + orderBy: (usersTable, { desc }) => [desc(usersTable.id)], + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(3); + expect(usersWithPosts[0]?.posts.length).eq(2); + expect(usersWithPosts[1]?.posts.length).eq(2); + expect(usersWithPosts[2]?.posts.length).eq(3); + + expect(usersWithPosts[2]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 3, ownerId: 1, content: '3', createdAt: usersWithPosts[2]?.posts[2]?.createdAt }, { + id: 2, + ownerId: 1, + content: '2', + createdAt: usersWithPosts[2]?.posts[1]?.createdAt, + }, { id: 1, ownerId: 1, content: '1', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ + id: 5, + ownerId: 2, + content: '5', + createdAt: usersWithPosts[1]?.posts[1]?.createdAt, + }, { id: 4, ownerId: 2, content: '4', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[0]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ + id: 7, + ownerId: 3, + content: '7', + createdAt: usersWithPosts[0]?.posts[1]?.createdAt, + }, { id: 6, ownerId: 3, content: '6', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + where: (({ id }, { eq }) => eq(id, 1)), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts + where + partial', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: { + id: true, + name: true, + }, + with: { + posts: { + columns: { + id: true, + content: true, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + posts: { + id: number; + content: string; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + posts: [{ id: 1, content: 'Post1' }], + }); +}); + +test('[Find Many] Get users with posts + where + partial. Did not select posts id, but used it in where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: { + id: true, + name: true, + }, + with: { + posts: { + columns: { + id: true, + content: true, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + posts: { + id: number; + content: string; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + posts: [{ id: 1, content: 'Post1' }], + }); +}); + +test('[Find Many] Get users with posts + where + partial(true + false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: { + id: true, + name: false, + }, + with: { + posts: { + columns: { + id: true, + content: false, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + posts: { + id: number; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + posts: [{ id: 1 }], + }); +}); + +test('[Find Many] Get users with posts + where + partial(false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: { + name: false, + }, + with: { + posts: { + columns: { + content: false, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts in transaction', async (t) => { + const { singlestoreDb: db } = t; + + let usersWithPosts: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[] = []; + + await db.transaction(async (tx) => { + await tx.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await tx.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + usersWithPosts = await tx.query.usersTable.findMany({ + where: (({ id }, { eq }) => eq(id, 1)), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + }); + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts in rollbacked transaction', async (t) => { + const { singlestoreDb: db } = t; + + let usersWithPosts: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[] = []; + + await expect(db.transaction(async (tx) => { + await tx.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await tx.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + tx.rollback(); + + usersWithPosts = await tx.query.usersTable.findMany({ + where: (({ id }, { eq }) => eq(id, 1)), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + }); + })).rejects.toThrowError(new TransactionRollbackError()); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(0); +}); + +// select only custom +test('[Find Many] Get only custom fields', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { id: 1, ownerId: 1, content: 'Post1' }, + { id: 2, ownerId: 1, content: 'Post1.2' }, + { id: 3, ownerId: 1, content: 'Post1.3' }, + { id: 4, ownerId: 2, content: 'Post2' }, + { id: 5, ownerId: 2, content: 'Post2.1' }, + { id: 6, ownerId: 3, content: 'Post3' }, + { id: 7, ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: {}, + with: { + posts: { + columns: {}, + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + lowerName: string; + posts: { + lowerName: string; + }[]; + }[]>(); + + // General Assertions + expect(usersWithPosts).toHaveLength(3); + + // Helper function to find user by lowerName + const findUser = (lowerName: string) => usersWithPosts.find((user) => user.lowerName === lowerName); + + // Assertions for each user + const dan = findUser('dan'); + const andrew = findUser('andrew'); + const alex = findUser('alex'); + + expect(dan).toBeDefined(); + expect(andrew).toBeDefined(); + expect(alex).toBeDefined(); + + // Verify the number of posts for each user + expect(dan?.posts).toHaveLength(3); + expect(andrew?.posts).toHaveLength(2); + expect(alex?.posts).toHaveLength(2); + + // Define expected posts for each user + const expectedDanPosts = ['post1', 'post1.2', 'post1.3']; + const expectedAndrewPosts = ['post2', 'post2.1']; + const expectedAlexPosts = ['post3', 'post3.1']; + + // Helper function to extract lowerNames from posts + const getPostLowerNames = (posts: { lowerName: string }[]) => posts.map((post) => post.lowerName); + + // Assertions for Dan's posts + expect(getPostLowerNames(dan!.posts)).toEqual(expect.arrayContaining(expectedDanPosts)); + expect(getPostLowerNames(dan!.posts)).toHaveLength(expectedDanPosts.length); + + // Assertions for Andrew's posts + expect(getPostLowerNames(andrew!.posts)).toEqual(expect.arrayContaining(expectedAndrewPosts)); + expect(getPostLowerNames(andrew!.posts)).toHaveLength(expectedAndrewPosts.length); + + // Assertions for Alex's posts + expect(getPostLowerNames(alex!.posts)).toEqual(expect.arrayContaining(expectedAlexPosts)); + expect(getPostLowerNames(alex!.posts)).toHaveLength(expectedAlexPosts.length); +}); + +// select only custom with where clause (Order Agnostic) +test('[Find Many] Get only custom fields + where', async (t) => { + const { singlestoreDb: db } = t; + + // Insert Users + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + // Insert Posts + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + // Query Users with Posts where users.id = 1 and posts.id >= 2 + const usersWithPosts = await db.query.usersTable.findMany({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + lowerName: string; + posts: { + lowerName: string; + }[]; + }[]>(); + + // General Assertions + expect(usersWithPosts).toHaveLength(1); + + // Since we expect only one user, we can extract it directly + const danWithPosts = usersWithPosts[0]; + + // Assert that the user exists and has the correct lowerName + expect(danWithPosts).toBeDefined(); + expect(danWithPosts?.lowerName).toBe('dan'); + + // Assert that the user has the expected number of posts + expect(danWithPosts?.posts).toHaveLength(2); + + // Define the expected posts + const expectedPosts = ['post1.2', 'post1.3']; + + // Extract the lowerName of each post + const actualPostLowerNames = danWithPosts?.posts.map((post) => post.lowerName); + + // Assert that all expected posts are present, regardless of order + for (const expectedPost of expectedPosts) { + expect(actualPostLowerNames).toContain(expectedPost); + } + + // Additionally, ensure no unexpected posts are present + expect(actualPostLowerNames).toHaveLength(expectedPosts.length); +}); + +test.skip('[Find Many] Get only custom fields + where + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + limit: 1, + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + lowerName: string; + posts: { + lowerName: string; + }[]; + }[]>(); + + expect(usersWithPosts.length).toEqual(1); + expect(usersWithPosts[0]?.posts.length).toEqual(1); + + expect(usersWithPosts).toContainEqual({ + lowerName: 'dan', + posts: [{ lowerName: 'post1.2' }], + }); +}); + +test.skip('[Find Many] Get only custom fields + where + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + orderBy: [desc(postsTable.id)], + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + lowerName: string; + posts: { + lowerName: string; + }[]; + }[]>(); + + expect(usersWithPosts.length).toEqual(1); + expect(usersWithPosts[0]?.posts.length).toEqual(2); + + expect(usersWithPosts).toContainEqual({ + lowerName: 'dan', + posts: [{ lowerName: 'post1.3' }, { lowerName: 'post1.2' }], + }); +}); + +// select only custom find one (Order Agnostic) +test('[Find One] Get only custom fields (Order Agnostic)', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + // Query to find the first user without any specific order + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: {}, + with: { + posts: { + columns: {}, + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + lowerName: string; + posts: { + lowerName: string; + }[]; + } | undefined + >(); + + // General Assertions + expect(usersWithPosts).toBeDefined(); + + // Since findFirst without orderBy can return any user, we'll verify the returned user and their posts + if (usersWithPosts) { + // Define expected users and their corresponding posts + const expectedUsers: { [key: string]: string[] } = { + dan: ['post1', 'post1.2', 'post1.3'], + andrew: ['post2', 'post2.1'], + alex: ['post3', 'post3.1'], + }; + + // Verify that the returned user is one of the expected users + expect(Object.keys(expectedUsers)).toContain(usersWithPosts.lowerName); + + // Get the expected posts for the returned user + const expectedPosts = expectedUsers[usersWithPosts.lowerName] as string[]; + + // Verify the number of posts + expect(usersWithPosts.posts).toHaveLength(expectedPosts.length); + + // Extract the lowerName of each post + const actualPostLowerNames = usersWithPosts.posts.map((post) => post.lowerName); + + // Assert that all expected posts are present, regardless of order + for (const expectedPost of expectedPosts) { + expect(actualPostLowerNames).toContain(expectedPost.toLowerCase()); + } + } +}); + +// select only custom find one with where clause (Order Agnostic) +test('[Find One] Get only custom fields + where (Order Agnostic)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + // Query to find the first user with id = 1 and posts with id >= 2 + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + lowerName: string; + posts: { + lowerName: string; + }[]; + } | undefined + >(); + + // General Assertions + expect(usersWithPosts).toBeDefined(); + + if (usersWithPosts) { + // Assert that the returned user has the expected lowerName + expect(usersWithPosts.lowerName).toBe('dan'); + + // Assert that the user has exactly two posts + expect(usersWithPosts.posts).toHaveLength(2); + + // Define the expected posts + const expectedPosts = ['post1.2', 'post1.3']; + + // Extract the lowerName of each post + const actualPostLowerNames = usersWithPosts.posts.map((post) => post.lowerName); + + // Assert that all expected posts are present, regardless of order + for (const expectedPost of expectedPosts) { + expect(actualPostLowerNames).toContain(expectedPost.toLowerCase()); + } + + // Additionally, ensure no unexpected posts are present + expect(actualPostLowerNames).toHaveLength(expectedPosts.length); + } +}); + +test.skip('[Find One] Get only custom fields + where + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + limit: 1, + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + lowerName: string; + posts: { + lowerName: string; + }[]; + } | undefined + >(); + + expect(usersWithPosts?.posts.length).toEqual(1); + + expect(usersWithPosts).toEqual({ + lowerName: 'dan', + posts: [{ lowerName: 'post1.2' }], + }); +}); + +test.skip('[Find One] Get only custom fields + where + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + orderBy: [desc(postsTable.id)], + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + lowerName: string; + posts: { + lowerName: string; + }[]; + } | undefined + >(); + + expect(usersWithPosts?.posts.length).toEqual(2); + + expect(usersWithPosts).toEqual({ + lowerName: 'dan', + posts: [{ lowerName: 'post1.3' }, { lowerName: 'post1.2' }], + }); +}); + +// columns {} +test('[Find Many] Get select {}', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await expect( + async () => + await db.query.usersTable.findMany({ + columns: {}, + }), + ).rejects.toThrow(DrizzleError); +}); + +// columns {} +test('[Find One] Get select {}', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await expect(async () => + await db.query.usersTable.findFirst({ + columns: {}, + }) + ).rejects.toThrow(DrizzleError); +}); + +// deep select {} +test('[Find Many] Get deep select {}', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + await expect(async () => + await db.query.usersTable.findMany({ + columns: {}, + with: { + posts: { + columns: {}, + }, + }, + }) + ).rejects.toThrow(DrizzleError); +}); + +// deep select {} +test('[Find One] Get deep select {}', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + await expect(async () => + await db.query.usersTable.findFirst({ + columns: {}, + with: { + posts: { + columns: {}, + }, + }, + }) + ).rejects.toThrow(DrizzleError); +}); + +/* + Prepared statements for users+posts +*/ +test.skip('[Find Many] Get users with posts + prepared limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const prepared = db.query.usersTable.findMany({ + with: { + posts: { + limit: placeholder('limit'), + }, + }, + }).prepare(); + + const usersWithPosts = await prepared.execute({ limit: 1 }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(3); + expect(usersWithPosts[0]?.posts.length).eq(1); + expect(usersWithPosts[1]?.posts.length).eq(1); + expect(usersWithPosts[2]?.posts.length).eq(1); + + expect(usersWithPosts).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find Many] Get users with posts + prepared limit + offset', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const prepared = db.query.usersTable.findMany({ + limit: placeholder('uLimit'), + offset: placeholder('uOffset'), + with: { + posts: { + limit: placeholder('pLimit'), + }, + }, + }).prepare(); + + const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1 }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(2); + expect(usersWithPosts[0]?.posts.length).eq(1); + expect(usersWithPosts[1]?.posts.length).eq(1); + + expect(usersWithPosts).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts + prepared where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const prepared = db.query.usersTable.findMany({ + where: (({ id }, { eq }) => eq(id, placeholder('id'))), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + }).prepare(); + + const usersWithPosts = await prepared.execute({ id: 1 }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find Many] Get users with posts + prepared + limit + offset + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const prepared = db.query.usersTable.findMany({ + limit: placeholder('uLimit'), + offset: placeholder('uOffset'), + where: (({ id }, { eq, or }) => or(eq(id, placeholder('id')), eq(id, 3))), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, placeholder('pid'))), + limit: placeholder('pLimit'), + }, + }, + }).prepare(); + + const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +/* + [Find One] One relation users+posts +*/ + +test('[Find One] Get users with posts', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: true, + }, + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + // General Assertions + expect(usersWithPosts).toBeDefined(); + + if (usersWithPosts) { + const { id, name, posts } = usersWithPosts; + + // Verify that the user is one of the inserted users + const validUsers: { [key: number]: string } = { + 1: 'dan', + 2: 'andrew', + 3: 'alex', + }; + expect(validUsers[id]).toBe(name.toLowerCase()); + + // Assert that the user has exactly one post + expect(posts).toHaveLength(1); + + const post = posts[0]; + + // Verify that the post belongs to the user + expect(post?.ownerId).toBe(id); + + // Verify that the post content matches the user + const expectedPostContent = `Post${id}`; + expect(post?.content.toLowerCase()).toBe(expectedPostContent.toLowerCase()); + + // Optionally, verify the presence of `createdAt` + expect(post?.createdAt).toBeInstanceOf(Date); + } +}); + +test.skip('[Find One] Get users with posts + limit posts', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find One] Get users with posts no results found', async (t) => { + const { singlestoreDb: db } = t; + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts).toBeUndefined(); +}); + +test.skip('[Find One] Get users with posts + limit posts and users', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +test('[Find One] Get users with posts + custom fields', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: true, + }, + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lowerName: string; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + // General Assertions + expect(usersWithPosts).toBeDefined(); + + if (usersWithPosts) { + const { id, lowerName, posts } = usersWithPosts; + + // Define valid users and their expected lower names + const validUsers: { [key: number]: string } = { + 1: 'dan', + 2: 'andrew', + 3: 'alex', + }; + + // Verify that the returned user's lowerName matches the expected value + expect(validUsers[id]).toBe(lowerName); + + // Define the expected posts based on the user ID + const expectedPostsByUser: Record = { + 1: ['post1', 'post1.2', 'post1.3'], + 2: ['post2', 'post2.1'], + 3: ['post3', 'post3.1'], + }; + + // Get the expected posts for the returned user + const expectedPosts = expectedPostsByUser[id] || []; + + // Extract the lowerName of each post + const actualPostContents = posts.map((post) => post.content.toLowerCase()); + + // Assert that all expected posts are present, regardless of order + for (const expectedPost of expectedPosts) { + expect(actualPostContents).toContain(expectedPost.toLowerCase()); + } + + // Optionally, ensure that no unexpected posts are present + expect(actualPostContents).toHaveLength(expectedPosts.length); + } +}); + +test.skip('[Find One] Get users with posts + custom fields + limits', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: { + limit: 1, + }, + }, + extras: (usersTable, { sql }) => ({ + lowerName: sql`lower(${usersTable.name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lowerName: string; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).toEqual(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + lowerName: 'dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find One] Get users with posts + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: '1' }, + { ownerId: 1, content: '2' }, + { ownerId: 1, content: '3' }, + { ownerId: 2, content: '4' }, + { ownerId: 2, content: '5' }, + { ownerId: 3, content: '6' }, + { ownerId: 3, content: '7' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: { + orderBy: (postsTable, { desc }) => [desc(postsTable.content)], + }, + }, + orderBy: (usersTable, { desc }) => [desc(usersTable.id)], + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(2); + + expect(usersWithPosts).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ + id: 7, + ownerId: 3, + content: '7', + createdAt: usersWithPosts?.posts[1]?.createdAt, + }, { id: 6, ownerId: 3, content: '6', createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +test('[Find One] Get users with posts + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + where: (({ id }, { eq }) => eq(id, 1)), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +test('[Find One] Get users with posts + where + partial', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: { + id: true, + name: true, + }, + with: { + posts: { + columns: { + id: true, + content: true, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + posts: { + id: number; + content: string; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + posts: [{ id: 1, content: 'Post1' }], + }); +}); + +test('[Find One] Get users with posts + where + partial. Did not select posts id, but used it in where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: { + id: true, + name: true, + }, + with: { + posts: { + columns: { + id: true, + content: true, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + posts: { + id: number; + content: string; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + posts: [{ id: 1, content: 'Post1' }], + }); +}); + +test('[Find One] Get users with posts + where + partial(true + false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: { + id: true, + name: false, + }, + with: { + posts: { + columns: { + id: true, + content: false, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + posts: { + id: number; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + posts: [{ id: 1 }], + }); +}); + +test('[Find One] Get users with posts + where + partial(false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: { + name: false, + }, + with: { + posts: { + columns: { + content: false, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +/* + One relation users+users. Self referencing +*/ + +test.skip('Get user with invitee', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + with: { + invitee: true, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithInvitee.length).eq(4); + expect(usersWithInvitee[0]?.invitee).toBeNull(); + expect(usersWithInvitee[1]?.invitee).toBeNull(); + expect(usersWithInvitee[2]?.invitee).not.toBeNull(); + expect(usersWithInvitee[3]?.invitee).not.toBeNull(); + + expect(usersWithInvitee[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[2]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + }); + expect(usersWithInvitee[3]).toEqual({ + id: 4, + name: 'John', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user + limit with invitee', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew', invitedBy: 1 }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + with: { + invitee: true, + }, + limit: 2, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user with invitee and custom fields', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), + with: { + invitee: { + extras: (invitee, { sql }) => ({ lower: sql`lower(${invitee.name})`.as('lower_name') }), + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + } | null; + }[] + >(); + + usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithInvitee.length).eq(4); + expect(usersWithInvitee[0]?.invitee).toBeNull(); + expect(usersWithInvitee[1]?.invitee).toBeNull(); + expect(usersWithInvitee[2]?.invitee).not.toBeNull(); + expect(usersWithInvitee[3]?.invitee).not.toBeNull(); + + expect(usersWithInvitee[0]).toEqual({ + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[1]).toEqual({ + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[2]).toEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, + }); + expect(usersWithInvitee[3]).toEqual({ + id: 4, + name: 'John', + lower: 'john', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', lower: 'andrew', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user with invitee and custom fields + limits', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), + limit: 3, + with: { + invitee: { + extras: (invitee, { sql }) => ({ lower: sql`lower(${invitee.name})`.as('lower_name') }), + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + } | null; + }[] + >(); + + usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithInvitee.length).eq(3); + expect(usersWithInvitee[0]?.invitee).toBeNull(); + expect(usersWithInvitee[1]?.invitee).toBeNull(); + expect(usersWithInvitee[2]?.invitee).not.toBeNull(); + + expect(usersWithInvitee[0]).toEqual({ + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[1]).toEqual({ + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[2]).toEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user with invitee + order by', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + orderBy: (users, { desc }) => [desc(users.id)], + with: { + invitee: true, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(4); + expect(usersWithInvitee[3]?.invitee).toBeNull(); + expect(usersWithInvitee[2]?.invitee).toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + + expect(usersWithInvitee[3]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[2]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[1]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + }); + expect(usersWithInvitee[0]).toEqual({ + id: 4, + name: 'John', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user with invitee + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + with: { + invitee: true, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + }); + expect(usersWithInvitee).toContainEqual({ + id: 4, + name: 'John', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user with invitee + where + partial', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + columns: { + id: true, + name: true, + }, + with: { + invitee: { + columns: { + id: true, + name: true, + }, + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + invitee: { + id: number; + name: string; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee).toContainEqual({ + id: 3, + name: 'Alex', + invitee: { id: 1, name: 'Dan' }, + }); + expect(usersWithInvitee).toContainEqual({ + id: 4, + name: 'John', + invitee: { id: 2, name: 'Andrew' }, + }); +}); + +test.skip('Get user with invitee + where + partial. Did not select users id, but used it in where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + columns: { + name: true, + }, + with: { + invitee: { + columns: { + id: true, + name: true, + }, + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + name: string; + invitee: { + id: number; + name: string; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee).toContainEqual({ + name: 'Alex', + invitee: { id: 1, name: 'Dan' }, + }); + expect(usersWithInvitee).toContainEqual({ + name: 'John', + invitee: { id: 2, name: 'Andrew' }, + }); +}); + +test.skip('Get user with invitee + where + partial(true+false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + columns: { + id: true, + name: true, + verified: false, + }, + with: { + invitee: { + columns: { + id: true, + name: true, + verified: false, + }, + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + invitee: { + id: number; + name: string; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee).toContainEqual({ + id: 3, + name: 'Alex', + invitee: { id: 1, name: 'Dan' }, + }); + expect(usersWithInvitee).toContainEqual({ + id: 4, + name: 'John', + invitee: { id: 2, name: 'Andrew' }, + }); +}); + +test.skip('Get user with invitee + where + partial(false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + columns: { + verified: false, + }, + with: { + invitee: { + columns: { + name: false, + }, + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + invitedBy: number | null; + invitee: { + id: number; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee).toContainEqual({ + id: 3, + name: 'Alex', + invitedBy: 1, + invitee: { id: 1, verified: false, invitedBy: null }, + }); + expect(usersWithInvitee).toContainEqual({ + id: 4, + name: 'John', + invitedBy: 2, + invitee: { id: 2, verified: false, invitedBy: null }, + }); +}); + +/* + Two first-level relations users+users and users+posts +*/ + +test.skip('Get user with invitee and posts', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const response = await db.query.usersTable.findMany({ + with: { + invitee: true, + posts: true, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(4); + + expect(response[0]?.invitee).toBeNull(); + expect(response[1]?.invitee).toBeNull(); + expect(response[2]?.invitee).not.toBeNull(); + expect(response[3]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: response[0]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: response[1]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [{ id: 3, ownerId: 3, content: 'Post3', createdAt: response[2]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 4, + name: 'John', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + posts: [], + }); +}); + +test.skip('Get user with invitee and posts + limit posts and users', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const response = await db.query.usersTable.findMany({ + limit: 3, + with: { + invitee: true, + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(3); + + expect(response[0]?.invitee).toBeNull(); + expect(response[1]?.invitee).toBeNull(); + expect(response[2]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: response[0]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 3, ownerId: 2, content: 'Post2', createdAt: response[1]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [{ id: 5, ownerId: 3, content: 'Post3', createdAt: response[2]?.posts[0]?.createdAt }], + }); +}); + +test.skip('Get user with invitee and posts + limits + custom fields in each', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const response = await db.query.usersTable.findMany({ + limit: 3, + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), + with: { + invitee: { + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_invitee_name') }), + }, + posts: { + limit: 1, + extras: (posts, { sql }) => ({ lower: sql`lower(${posts.content})`.as('lower_content') }), + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + lower: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(3); + + expect(response[0]?.invitee).toBeNull(); + expect(response[1]?.invitee).toBeNull(); + expect(response[2]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', lower: 'post1', createdAt: response[0]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 3, ownerId: 2, content: 'Post2', lower: 'post2', createdAt: response[1]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, + posts: [{ id: 5, ownerId: 3, content: 'Post3', lower: 'post3', createdAt: response[2]?.posts[0]?.createdAt }], + }); +}); + +test.skip('Get user with invitee and posts + custom fields in each', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const response = await db.query.usersTable.findMany({ + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), + with: { + invitee: { + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), + }, + posts: { + extras: (posts, { sql }) => ({ lower: sql`lower(${posts.content})`.as('lower_name') }), + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + lower: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + response[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + response[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + response[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(4); + + expect(response[0]?.invitee).toBeNull(); + expect(response[1]?.invitee).toBeNull(); + expect(response[2]?.invitee).not.toBeNull(); + expect(response[3]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(2); + expect(response[1]?.posts.length).eq(2); + expect(response[2]?.posts.length).eq(2); + expect(response[3]?.posts.length).eq(0); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', lower: 'post1', createdAt: response[0]?.posts[0]?.createdAt }, { + id: 2, + ownerId: 1, + content: 'Post1.1', + lower: 'post1.1', + createdAt: response[0]?.posts[1]?.createdAt, + }], + }); + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 3, ownerId: 2, content: 'Post2', lower: 'post2', createdAt: response[1]?.posts[0]?.createdAt }, { + id: 4, + ownerId: 2, + content: 'Post2.1', + lower: 'post2.1', + createdAt: response[1]?.posts[1]?.createdAt, + }], + }); + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, + posts: [{ id: 5, ownerId: 3, content: 'Post3', lower: 'post3', createdAt: response[2]?.posts[0]?.createdAt }, { + id: 6, + ownerId: 3, + content: 'Post3.1', + lower: 'post3.1', + createdAt: response[2]?.posts[1]?.createdAt, + }], + }); + expect(response).toContainEqual({ + id: 4, + name: 'John', + lower: 'john', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', lower: 'andrew', verified: false, invitedBy: null }, + posts: [], + }); +}); + +test.skip('Get user with invitee and posts + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const response = await db.query.usersTable.findMany({ + orderBy: (users, { desc }) => [desc(users.id)], + with: { + invitee: true, + posts: { + orderBy: (posts, { desc }) => [desc(posts.id)], + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(response.length).eq(4); + + expect(response[3]?.invitee).toBeNull(); + expect(response[2]?.invitee).toBeNull(); + expect(response[1]?.invitee).not.toBeNull(); + expect(response[0]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(0); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(2); + expect(response[3]?.posts.length).eq(2); + + expect(response[3]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 2, ownerId: 1, content: 'Post1.1', createdAt: response[3]?.posts[0]?.createdAt }, { + id: 1, + ownerId: 1, + content: 'Post1', + createdAt: response[3]?.posts[1]?.createdAt, + }], + }); + expect(response[2]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2.1', createdAt: response[2]?.posts[0]?.createdAt }, { + id: 3, + ownerId: 2, + content: 'Post2', + createdAt: response[2]?.posts[1]?.createdAt, + }], + }); + expect(response[1]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [{ + id: 5, + ownerId: 3, + content: 'Post3', + createdAt: response[3]?.posts[1]?.createdAt, + }], + }); + expect(response[0]).toEqual({ + id: 4, + name: 'John', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + posts: [], + }); +}); + +test.skip('Get user with invitee and posts + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const response = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 2), eq(users.id, 3))), + with: { + invitee: true, + posts: { + where: (posts, { eq }) => (eq(posts.ownerId, 2)), + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(2); + + expect(response[0]?.invitee).toBeNull(); + expect(response[1]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(0); + + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: response[0]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [], + }); +}); + +test.skip('Get user with invitee and posts + limit posts and users + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const response = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + limit: 1, + with: { + invitee: true, + posts: { + where: (posts, { eq }) => (eq(posts.ownerId, 3)), + limit: 1, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(response.length).eq(1); + + expect(response[0]?.invitee).not.toBeNull(); + expect(response[0]?.posts.length).eq(1); + + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [{ id: 5, ownerId: 3, content: 'Post3', createdAt: response[0]?.posts[0]?.createdAt }], + }); +}); + +test.skip('Get user with invitee and posts + orderBy + where + custom', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const response = await db.query.usersTable.findMany({ + orderBy: [desc(usersTable.id)], + where: or(eq(usersTable.id, 3), eq(usersTable.id, 4)), + extras: { + lower: sql`lower(${usersTable.name})`.as('lower_name'), + }, + with: { + invitee: true, + posts: { + where: eq(postsTable.ownerId, 3), + orderBy: [desc(postsTable.id)], + extras: { + lower: sql`lower(${postsTable.content})`.as('lower_name'), + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lower: string; + posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(response.length).eq(2); + + expect(response[1]?.invitee).not.toBeNull(); + expect(response[0]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(0); + expect(response[1]?.posts.length).eq(1); + + expect(response[1]).toEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [{ + id: 5, + ownerId: 3, + content: 'Post3', + lower: 'post3', + createdAt: response[1]?.posts[0]?.createdAt, + }], + }); + expect(response[0]).toEqual({ + id: 4, + name: 'John', + lower: 'john', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + posts: [], + }); +}); + +test.skip('Get user with invitee and posts + orderBy + where + partial + custom', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const response = await db.query.usersTable.findMany({ + orderBy: [desc(usersTable.id)], + where: or(eq(usersTable.id, 3), eq(usersTable.id, 4)), + extras: { + lower: sql`lower(${usersTable.name})`.as('lower_name'), + }, + columns: { + id: true, + name: true, + }, + with: { + invitee: { + columns: { + id: true, + name: true, + }, + extras: { + lower: sql`lower(${usersTable.name})`.as('lower_name'), + }, + }, + posts: { + columns: { + id: true, + content: true, + }, + where: eq(postsTable.ownerId, 3), + orderBy: [desc(postsTable.id)], + extras: { + lower: sql`lower(${postsTable.content})`.as('lower_name'), + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + lower: string; + posts: { id: number; lower: string; content: string }[]; + invitee: { + id: number; + name: string; + lower: string; + } | null; + }[] + >(); + + expect(response.length).eq(2); + + expect(response[1]?.invitee).not.toBeNull(); + expect(response[0]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(0); + expect(response[1]?.posts.length).eq(1); + + expect(response[1]).toEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + invitee: { id: 1, name: 'Dan', lower: 'dan' }, + posts: [{ + id: 5, + content: 'Post3', + lower: 'post3', + }], + }); + expect(response[0]).toEqual({ + id: 4, + name: 'John', + lower: 'john', + invitee: { id: 2, name: 'Andrew', lower: 'andrew' }, + posts: [], + }); +}); + +/* + One two-level relation users+posts+comments +*/ + +test.skip('Get user with posts and posts with comments', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { id: 1, ownerId: 1, content: 'Post1' }, + { id: 2, ownerId: 2, content: 'Post2' }, + { id: 3, ownerId: 3, content: 'Post3' }, + ]); + + await db.insert(commentsTable).values([ + { postId: 1, content: 'Comment1', creator: 2 }, + { postId: 2, content: 'Comment2', creator: 2 }, + { postId: 3, content: 'Comment3', creator: 3 }, + ]); + + const response = await db.query.usersTable.findMany({ + with: { + posts: { + with: { + comments: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + comments: { + id: number; + content: string; + createdAt: Date; + creator: number | null; + postId: number | null; + }[]; + }[]; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(3); + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(1); + + expect(response[0]?.posts[0]?.comments.length).eq(1); + expect(response[1]?.posts[0]?.comments.length).eq(1); + expect(response[2]?.posts[0]?.comments.length).eq(1); + + expect(response[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ + id: 1, + ownerId: 1, + content: 'Post1', + createdAt: response[0]?.posts[0]?.createdAt, + comments: [ + { + id: 1, + content: 'Comment1', + creator: 2, + postId: 1, + createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, + }, + ], + }], + }); + expect(response[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ + id: 2, + ownerId: 2, + content: 'Post2', + createdAt: response[1]?.posts[0]?.createdAt, + comments: [ + { + id: 2, + content: 'Comment2', + creator: 2, + postId: 2, + createdAt: response[1]?.posts[0]?.comments[0]?.createdAt, + }, + ], + }], + }); + // expect(response[2]).toEqual({ + // id: 3, + // name: 'Alex', + // verified: false, + // invitedBy: null, + // posts: [{ + // id: 3, + // ownerId: 3, + // content: 'Post3', + // createdAt: response[2]?.posts[0]?.createdAt, + // comments: [ + // { + // id: , + // content: 'Comment3', + // creator: 3, + // postId: 3, + // createdAt: response[2]?.posts[0]?.comments[0]?.createdAt, + // }, + // ], + // }], + // }); +}); + +// Get user with limit posts and limit comments + +// Get user with custom field + post + comment with custom field + +// Get user with limit + posts orderBy + comment orderBy + +// Get user with where + posts where + comment where + +// Get user with where + posts partial where + comment where + +// Get user with where + posts partial where + comment partial(false) where + +// Get user with where partial(false) + posts partial where partial(false) + comment partial(false+true) where + +// Get user with where + posts partial where + comment where. Didn't select field from where in posts + +// Get user with where + posts partial where + comment where. Didn't select field from where for all + +// Get with limit+offset in each + +/* + One two-level + One first-level relation users+posts+comments and users+users +*/ + +/* + One three-level relation users+posts+comments+comment_owner +*/ + +test.skip('Get user with posts and posts with comments and comments with owner', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { id: 1, ownerId: 1, content: 'Post1' }, + { id: 2, ownerId: 2, content: 'Post2' }, + { id: 3, ownerId: 3, content: 'Post3' }, + ]); + + await db.insert(commentsTable).values([ + { postId: 1, content: 'Comment1', creator: 2 }, + { postId: 2, content: 'Comment2', creator: 2 }, + { postId: 3, content: 'Comment3', creator: 3 }, + ]); + + const response = await db.query.usersTable.findMany({ + with: { + posts: { + with: { + comments: { + with: { + author: true, + }, + }, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + comments: { + id: number; + content: string; + createdAt: Date; + creator: number | null; + postId: number | null; + author: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[]; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(3); + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(1); + + expect(response[0]?.posts[0]?.comments.length).eq(1); + expect(response[1]?.posts[0]?.comments.length).eq(1); + expect(response[2]?.posts[0]?.comments.length).eq(1); + + expect(response[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ + id: 1, + ownerId: 1, + content: 'Post1', + createdAt: response[0]?.posts[0]?.createdAt, + comments: [ + { + id: 1, + content: 'Comment1', + creator: 2, + author: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + postId: 1, + createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, + }, + ], + }], + }); + expect(response[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ + id: 2, + ownerId: 2, + content: 'Post2', + createdAt: response[1]?.posts[0]?.createdAt, + comments: [ + { + id: 2, + content: 'Comment2', + creator: 2, + author: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + postId: 2, + createdAt: response[1]?.posts[0]?.comments[0]?.createdAt, + }, + ], + }], + }); +}); + +test.skip('Get user with posts and posts with comments and comments with owner where exists', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { id: 1, ownerId: 1, content: 'Post1' }, + { id: 2, ownerId: 2, content: 'Post2' }, + { id: 3, ownerId: 3, content: 'Post3' }, + ]); + + await db.insert(commentsTable).values([ + { postId: 1, content: 'Comment1', creator: 2 }, + { postId: 2, content: 'Comment2', creator: 2 }, + { postId: 3, content: 'Comment3', creator: 3 }, + ]); + + const response = await db.query.usersTable.findMany({ + with: { + posts: { + with: { + comments: { + with: { + author: true, + }, + }, + }, + }, + }, + where: (table, { exists, eq }) => exists(db.select({ one: sql`1` }).from(usersTable).where(eq(sql`1`, table.id))), + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + comments: { + id: number; + content: string; + createdAt: Date; + creator: number | null; + postId: number | null; + author: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[]; + }[]; + }[]>(); + + expect(response.length).eq(1); + expect(response[0]?.posts.length).eq(1); + + expect(response[0]?.posts[0]?.comments.length).eq(1); + + expect(response[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ + id: 1, + ownerId: 1, + content: 'Post1', + createdAt: response[0]?.posts[0]?.createdAt, + comments: [ + { + id: 1, + content: 'Comment1', + creator: 2, + author: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + postId: 1, + createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, + }, + ], + }], + }); +}); + +/* + One three-level relation + 1 first-level relatioon + 1. users+posts+comments+comment_owner + 2. users+users +*/ + +/* + One four-level relation users+posts+comments+coment_likes +*/ + +/* + [Find Many] Many-to-many cases + + Users+users_to_groups+groups +*/ + +test.skip('[Find Many] Get users with groups', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + with: { + usersToGroups: { + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + expect(response[2]?.usersToGroups.length).toEqual(2); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + description: null, + }, + }, { + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get groups with users', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + with: { + usersToGroups: { + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(2); + expect(response[2]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }, { + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 3, + name: 'Group3', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get users with groups + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + limit: 2, + with: { + usersToGroups: { + limit: 1, + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get groups with users + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + limit: 2, + with: { + usersToGroups: { + limit: 1, + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get users with groups + limit + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + limit: 1, + where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.groupId, 1), + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(1); + + expect(response[0]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get groups with users + limit + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + limit: 1, + where: gt(groupsTable.id, 1), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.userId, 2), + limit: 1, + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(1); + + expect(response[0]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get users with groups + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.groupId, 2), + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(0); + expect(response[1]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get groups with users + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + where: gt(groupsTable.id, 1), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.userId, 2), + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(0); + + expect(response).toContainEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 3, + name: 'Group3', + description: null, + usersToGroups: [], + }); +}); + +test.skip('[Find Many] Get users with groups + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + orderBy: (users, { desc }) => [desc(users.id)], + with: { + usersToGroups: { + orderBy: [desc(usersToGroupsTable.groupId)], + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(2); + expect(response[1]?.usersToGroups.length).toEqual(1); + expect(response[2]?.usersToGroups.length).toEqual(1); + + expect(response[2]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); + + expect(response[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); + + expect(response[0]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + description: null, + }, + }, { + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get groups with users + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + orderBy: [desc(groupsTable.id)], + with: { + usersToGroups: { + orderBy: (utg, { desc }) => [desc(utg.userId)], + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[]>(); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(2); + expect(response[2]?.usersToGroups.length).toEqual(1); + + expect(response[2]).toEqual({ + id: 1, + name: 'Group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response[1]).toEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }, { + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response[0]).toEqual({ + id: 3, + name: 'Group3', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get users with groups + orderBy + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + orderBy: (users, { desc }) => [desc(users.id)], + limit: 2, + with: { + usersToGroups: { + limit: 1, + orderBy: [desc(usersToGroupsTable.groupId)], + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + + expect(response[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); + + expect(response[0]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + description: null, + }, + }], + }); +}); + +/* + [Find One] Many-to-many cases + + Users+users_to_groups+groups +*/ + +test.skip('[Find One] Get users with groups', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + with: { + usersToGroups: { + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); +}); + +test.skip('[Find One] Get groups with users', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findFirst({ + with: { + usersToGroups: { + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 1, + name: 'Group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find One] Get users with groups + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + with: { + usersToGroups: { + limit: 1, + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); +}); + +test.skip('[Find One] Get groups with users + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findFirst({ + with: { + usersToGroups: { + limit: 1, + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 1, + name: 'Group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find One] Get users with groups + limit + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.groupId, 1), + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); +}); + +test.skip('[Find One] Get groups with users + limit + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findFirst({ + where: gt(groupsTable.id, 1), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.userId, 2), + limit: 1, + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find One] Get users with groups + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.groupId, 2), + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(0); + + expect(response).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [], + }); +}); + +test.skip('[Find One] Get groups with users + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findFirst({ + where: gt(groupsTable.id, 1), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.userId, 2), + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find One] Get users with groups + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + orderBy: (users, { desc }) => [desc(users.id)], + with: { + usersToGroups: { + orderBy: [desc(usersToGroupsTable.groupId)], + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(2); + + expect(response).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + description: null, + }, + }, { + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); +}); + +test.skip('[Find One] Get groups with users + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findFirst({ + orderBy: [desc(groupsTable.id)], + with: { + usersToGroups: { + orderBy: (utg, { desc }) => [desc(utg.userId)], + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 3, + name: 'Group3', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find One] Get users with groups + orderBy + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + orderBy: (users, { desc }) => [desc(users.id)], + with: { + usersToGroups: { + limit: 1, + orderBy: [desc(usersToGroupsTable.groupId)], + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + description: null, + }, + }], + }); +}); + +test.skip('Get groups with users + orderBy + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + orderBy: [desc(groupsTable.id)], + limit: 2, + with: { + usersToGroups: { + limit: 1, + orderBy: (utg, { desc }) => [desc(utg.userId)], + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[] + >(); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + + expect(response[1]).toEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response[0]).toEqual({ + id: 3, + name: 'Group3', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('Get users with groups + custom', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + extras: { + lower: sql`lower(${usersTable.name})`.as('lower_name'), + }, + with: { + usersToGroups: { + columns: {}, + with: { + group: { + extras: { + lower: sql`lower(${groupsTable.name})`.as('lower_name'), + }, + }, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lower: string; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + lower: string; + }; + }[]; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + expect(response[2]?.usersToGroups.length).toEqual(2); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + lower: 'group1', + description: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + lower: 'group2', + description: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + lower: 'group3', + description: null, + }, + }, { + group: { + id: 2, + name: 'Group2', + lower: 'group2', + description: null, + }, + }], + }); +}); + +test.skip('Get groups with users + custom', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + extras: (table, { sql }) => ({ + lower: sql`lower(${table.name})`.as('lower_name'), + }), + with: { + usersToGroups: { + columns: {}, + with: { + user: { + extras: (table, { sql }) => ({ + lower: sql`lower(${table.name})`.as('lower_name'), + }), + }, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + lower: string; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lower: string; + }; + }[]; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(2); + expect(response[2]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Group1', + lower: 'group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Group2', + lower: 'group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + }, + }, { + user: { + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 3, + name: 'Group3', + lower: 'group3', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test('.toSQL()', () => { + const query = db.query.usersTable.findFirst().toSQL(); + + expect(query).toHaveProperty('sql', expect.any(String)); + expect(query).toHaveProperty('params', expect.any(Array)); +}); + +// + custom + where + orderby + +// + custom + where + orderby + limit + +// + partial + +// + partial(false) + +// + partial + orderBy + where (all not selected) + +/* + One four-level relation users+posts+comments+coment_likes + + users+users_to_groups+groups +*/ + +/* + Really hard case + 1. users+posts+comments+coment_likes + 2. users+users_to_groups+groups + 3. users+users +*/ diff --git a/integration-tests/tests/replicas/singlestore.test.ts b/integration-tests/tests/replicas/singlestore.test.ts new file mode 100644 index 000000000..76d84c972 --- /dev/null +++ b/integration-tests/tests/replicas/singlestore.test.ts @@ -0,0 +1,805 @@ +import { sql } from 'drizzle-orm'; +import { drizzle } from 'drizzle-orm/singlestore'; +import { boolean, serial, singlestoreTable, text, withReplicas } from 'drizzle-orm/singlestore-core'; +import { describe, expect, it, vi } from 'vitest'; + +const usersTable = singlestoreTable('users', { + id: serial('id' as string).primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), +}); + +const users = singlestoreTable('users', { + id: serial('id' as string).primaryKey(), +}); + +describe('[select] read replicas singlestore', () => { + it('primary select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + const query = db.$primary.select().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(query.toSQL().sql).toEqual('select `id` from `users`'); + + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + const query1 = db.select({ count: sql`count(*)`.as('count') }).from(users).limit(1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(query1.toSQL().sql).toEqual('select count(*) as `count` from `users` limit ?'); + + const query2 = db.select().from(users); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); + + it('single read replica select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + const query1 = db.select().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select `id` from `users`'); + + const query2 = db.select().from(users); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); + + it('single read replica select + primary select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + const query1 = db.select({ id: users.id }).from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select `id` from `users`'); + + const query2 = db.$primary.select().from(users); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); + + it('always first read select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + const query1 = db.select().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('select `id` from `users`'); + + const query2 = db.select().from(users); + + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); +}); + +describe('[selectDistinct] read replicas singlestore', () => { + it('primary selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + const query = db.$primary.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('random replica selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.selectDistinct().from(users); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('single read replica selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.selectDistinct().from(users); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('single read replica selectDistinct + primary selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.$primary.selectDistinct().from(users); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('always first read selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.selectDistinct().from(users); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); +}); + +describe('[with] read replicas singlestore', () => { + it('primary with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + const obj1 = {} as any; + const obj2 = {} as any; + const obj3 = {} as any; + const obj4 = {} as any; + + db.$primary.with(obj1, obj2, obj3, obj4); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(obj1, obj2, obj3, obj4); + }); + + it('random replica with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica with + primary with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.with(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + const obj1 = {} as any; + const obj2 = {} as any; + const obj3 = {} as any; + + db.with(obj1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledWith(obj1); + + db.with(obj2, obj3); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledWith(obj2, obj3); + }); +}); + +describe('[update] replicas singlestore', () => { + it('primary update', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'update'); + const spyRead1 = vi.spyOn(read1, 'update'); + const spyRead2 = vi.spyOn(read2, 'update'); + + const query1 = db.update(users).set({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('update `users` set `id` = ?'); + + const query2 = db.update(users).set({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query2.toSQL().sql).toEqual('update `users` set `id` = ?'); + + const query3 = db.$primary.update(users).set({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query3.toSQL().sql).toEqual('update `users` set `id` = ?'); + }); +}); + +describe('[delete] replicas singlestore', () => { + it('primary delete', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'delete'); + const spyRead1 = vi.spyOn(read1, 'delete'); + const spyRead2 = vi.spyOn(read2, 'delete'); + + const query1 = db.delete(users); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(users); + expect(query1.toSQL().sql).toEqual('delete from `users`'); + + const query2 = db.delete(users); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenNthCalledWith(2, users); + expect(query2.toSQL().sql).toEqual('delete from `users`'); + + db.$primary.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[insert] replicas singlestore', () => { + it('primary insert', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'insert'); + const spyRead1 = vi.spyOn(read1, 'insert'); + const spyRead2 = vi.spyOn(read2, 'insert'); + + const query = db.insert(users).values({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(users); + expect(query.toSQL().sql).toEqual('insert into `users` (`id`) values (?)'); + + db.insert(users); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenNthCalledWith(2, users); + + db.$primary.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[execute] replicas singlestore', () => { + it('primary execute', async () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'execute'); + const spyRead1 = vi.spyOn(read1, 'execute'); + const spyRead2 = vi.spyOn(read2, 'execute'); + + expect(db.execute(sql``)).rejects.toThrow(); + + // try { + // db.execute(sql``); + // } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.execute(sql``)).rejects.toThrow(); + // try { + // db.execute(sql``); + // } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.execute(sql``)).rejects.toThrow(); + // try { + // db.execute(sql``); + // } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[transaction] replicas singlestore', () => { + it('primary transaction', async () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'transaction'); + const spyRead1 = vi.spyOn(read1, 'transaction'); + const spyRead2 = vi.spyOn(read2, 'transaction'); + const txFn1 = async (tx: any) => { + tx.select().from({} as any); + }; + + expect(db.transaction(txFn1)).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(txFn1); + + const txFn2 = async (tx: any) => { + tx.select().from({} as any); + }; + + expect(db.transaction(txFn2)).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenNthCalledWith(2, txFn2); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[findFirst] read replicas singlestore', () => { + it('primary findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + const obj = {} as any; + + db.$primary.query.usersTable.findFirst(obj); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(obj); + }); + + it('random replica findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + const par1 = {} as any; + + db.query.usersTable.findFirst(par1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledWith(par1); + + const query = db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + expect(query.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable` limit ?'); + }); + + it('single read replica findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica findFirst + primary findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.query.usersTable.findFirst(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[findMany] read replicas singlestore', () => { + it('primary findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + const obj = {} as any; + + const query = db.$primary.query.usersTable.findMany(obj); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(obj); + expect(query.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + }); + + it('random replica findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + const obj1 = {} as any; + const obj2 = {} as any; + + const query1 = db.query.usersTable.findMany(obj1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + expect(spyRead1).toHaveBeenCalledWith(obj1); + + const query2 = db.query.usersTable.findMany(obj2); + + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + expect(spyRead2).toHaveBeenCalledWith(obj2); + }); + + it('single read replica findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const obj1 = {} as any; + const obj2 = {} as any; + + const query1 = db.query.usersTable.findMany(obj1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledWith(obj1); + expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + + const query2 = db.query.usersTable.findMany(obj2); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenNthCalledWith(2, obj2); + expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + }); + + it('single read replica findMany + primary findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const obj1 = {} as any; + const obj2 = {} as any; + + const query1 = db.query.usersTable.findMany(obj1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledWith(obj1); + expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + + const query2 = db.$primary.query.usersTable.findMany(obj2); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyPrimary).toHaveBeenNthCalledWith(1, obj2); + expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + }); + + it('always first read findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + const obj1 = {} as any; + const obj2 = {} as any; + + const query1 = db.query.usersTable.findMany(obj1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledWith(obj1); + expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + + const query2 = db.query.usersTable.findMany(obj2); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenNthCalledWith(2, obj2); + expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + }); +}); diff --git a/integration-tests/tests/singlestore/singlestore-common.ts b/integration-tests/tests/singlestore/singlestore-common.ts new file mode 100644 index 000000000..037c27202 --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-common.ts @@ -0,0 +1,3432 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import 'dotenv/config'; +import Docker from 'dockerode'; +import { + and, + asc, + avg, + avgDistinct, + count, + countDistinct, + eq, + exists, + getTableColumns, + gt, + gte, + inArray, + lt, + max, + min, + Name, + notInArray, + placeholder, + sql, + sum, + sumDistinct, + TransactionRollbackError, +} from 'drizzle-orm'; +import type { SingleStoreDatabase } from 'drizzle-orm/singlestore-core'; +import { + alias, + bigint, + boolean, + date, + datetime, + decimal, + except, + getTableConfig, + getViewConfig, + int, + intersect, + json, + mediumint, + primaryKey, + serial, + singlestoreEnum, + singlestoreSchema, + singlestoreTable, + singlestoreTableCreator, + singlestoreView, + smallint, + text, + time, + timestamp, + tinyint, + union, + unionAll, + unique, + uniqueIndex, + uniqueKeyName, + varchar, + year, +} from 'drizzle-orm/singlestore-core'; +import { migrate } from 'drizzle-orm/singlestore/migrator'; +import getPort from 'get-port'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeEach, describe, expect, expectTypeOf, test } from 'vitest'; +import { Expect, toLocalDate } from '~/utils.ts'; +import type { Equal } from '~/utils.ts'; + +type TestSingleStoreDB = SingleStoreDatabase; + +declare module 'vitest' { + interface TestContext { + singlestore: { + db: TestSingleStoreDB; + }; + } +} + +const ENABLE_LOGGING = false; + +const usersTable = singlestoreTable('userstest', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: json('jsonb').$type(), + createdAt: timestamp('created_at', { fsp: 6 }).notNull().defaultNow(), +}); + +const users2Table = singlestoreTable('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id'), +}); + +const citiesTable = singlestoreTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +const usersOnUpdate = singlestoreTable('users_on_update', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + updateCounter: int('update_counter').default(sql`1`).$onUpdateFn(() => sql`update_counter + 1`), + updatedAt: datetime('updated_at', { mode: 'date', fsp: 6 }).$onUpdateFn(() => new Date()), + alwaysNull: text('always_null').$type().$onUpdateFn(() => null), // need to add $type because $onUpdate add a default value +}); + +const datesTable = singlestoreTable('datestable', { + date: date('date'), + dateAsString: date('date_as_string', { mode: 'string' }), + time: time('time', { fsp: 1 }), + datetime: datetime('datetime', { fsp: 6 }), + datetimeAsString: datetime('datetime_as_string', { fsp: 6, mode: 'string' }), + timestamp: timestamp('timestamp', { fsp: 6 }), + timestampAsString: timestamp('timestamp_as_string', { fsp: 6, mode: 'string' }), + year: year('year'), +}); + +const coursesTable = singlestoreTable('courses', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + categoryId: int('category_id'), +}); + +const courseCategoriesTable = singlestoreTable('course_categories', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +const orders = singlestoreTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull().$default(() => 'random_string'), + amount: int('amount').notNull(), + quantity: int('quantity').notNull(), +}); + +const usersMigratorTable = singlestoreTable('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}, (table) => { + return { + name: uniqueIndex('').on(table.name).using('btree'), + }; +}); + +// To test aggregate functions +const aggregateTable = singlestoreTable('aggregate_table', { + id: serial('id').notNull(), + name: text('name').notNull(), + a: int('a'), + b: int('b'), + c: int('c'), + nullOnly: int('null_only'), +}); + +// To test another schema and multischema +const mySchema = singlestoreSchema(`mySchema`); + +const usersMySchemaTable = mySchema.table('userstest', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: json('jsonb').$type(), + createdAt: timestamp('created_at', { fsp: 6 }).notNull().defaultNow(), +}); + +const users2MySchemaTable = mySchema.table('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id'), +}); + +const citiesMySchemaTable = mySchema.table('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +let singlestoreContainer: Docker.Container; +export async function createDockerDB(): Promise<{ connectionString: string; container: Docker.Container }> { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + ); + + singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return { + connectionString: `singlestore://root:singlestore@localhost:${port}/`, + container: singlestoreContainer, + }; +} + +// Tests are slow so we keep track of the test number +let testRunNumber = 0; + +export function tests(driver?: string) { + describe('common', () => { + afterAll(async () => { + await singlestoreContainer?.stop().catch(console.error); + }); + + beforeEach(async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`drop table if exists userstest`); + await db.execute(sql`drop table if exists users2`); + await db.execute(sql`drop table if exists cities`); + + await db.execute(sql`drop schema if exists \`mySchema\``); + await db.execute(sql`create schema if not exists \`mySchema\``); + + await db.execute( + sql` + create table userstest ( + id serial primary key, + name text not null, + verified boolean not null default false, + jsonb json, + created_at timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table users2 ( + id serial primary key, + name text not null, + city_id int + ) + `, + ); + + await db.execute( + sql` + create table cities ( + id serial primary key, + name text not null + ) + `, + ); + + // mySchema + await db.execute( + sql` + create table \`mySchema\`.\`userstest\` ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table \`mySchema\`.\`cities\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.execute( + sql` + create table \`mySchema\`.\`users2\` ( + \`id\` serial primary key, + \`name\` text not null, + \`city_id\` int + ) + `, + ); + + testRunNumber += 1; + console.log(`Test number: ${testRunNumber}`); + }); + + async function setupReturningFunctionsTest(db: SingleStoreDatabase) { + await db.execute(sql`drop table if exists \`users_default_fn\``); + await db.execute( + sql` + create table \`users_default_fn\` ( + \`id\` varchar(256) primary key, + \`name\` text not null + ); + `, + ); + } + + async function setupSetOperationTest(db: TestSingleStoreDB) { + await db.execute(sql`drop table if exists \`users2\``); + await db.execute(sql`drop table if exists \`cities\``); + await db.execute( + sql` + create table \`users2\` ( + \`id\` serial primary key, + \`name\` text not null, + \`city_id\` int + ) + `, + ); + + await db.execute( + sql` + create table \`cities\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.insert(citiesTable).values([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 3 }, + { id: 4, name: 'Peter', cityId: 3 }, + { id: 5, name: 'Ben', cityId: 2 }, + { id: 6, name: 'Jill', cityId: 1 }, + { id: 7, name: 'Mary', cityId: 2 }, + { id: 8, name: 'Sally', cityId: 1 }, + ]); + } + + async function setupAggregateFunctionsTest(db: TestSingleStoreDB) { + await db.execute(sql`drop table if exists \`aggregate_table\``); + await db.execute( + sql` + create table \`aggregate_table\` ( + \`id\` integer primary key auto_increment not null, + \`name\` text not null, + \`a\` integer, + \`b\` integer, + \`c\` integer, + \`null_only\` integer + ); + `, + ); + await db.insert(aggregateTable).values([ + { id: 1, name: 'value 1', a: 5, b: 10, c: 20 }, + { id: 2, name: 'value 1', a: 5, b: 20, c: 30 }, + { id: 3, name: 'value 2', a: 10, b: 50, c: 60 }, + { id: 4, name: 'value 3', a: 20, b: 20, c: null }, + { id: 5, name: 'value 4', a: null, b: 90, c: 120 }, + { id: 6, name: 'value 5', a: 80, b: 10, c: null }, + { id: 7, name: 'value 6', a: null, b: null, c: 150 }, + ]); + } + + test('table config: unsigned ints', async () => { + const unsignedInts = singlestoreTable('cities1', { + bigint: bigint('bigint', { mode: 'number', unsigned: true }), + int: int('int', { unsigned: true }), + smallint: smallint('smallint', { unsigned: true }), + mediumint: mediumint('mediumint', { unsigned: true }), + tinyint: tinyint('tinyint', { unsigned: true }), + }); + + const tableConfig = getTableConfig(unsignedInts); + + const bigintColumn = tableConfig.columns.find((c) => c.name === 'bigint')!; + const intColumn = tableConfig.columns.find((c) => c.name === 'int')!; + const smallintColumn = tableConfig.columns.find((c) => c.name === 'smallint')!; + const mediumintColumn = tableConfig.columns.find((c) => c.name === 'mediumint')!; + const tinyintColumn = tableConfig.columns.find((c) => c.name === 'tinyint')!; + + expect(bigintColumn.getSQLType()).toBe('bigint unsigned'); + expect(intColumn.getSQLType()).toBe('int unsigned'); + expect(smallintColumn.getSQLType()).toBe('smallint unsigned'); + expect(mediumintColumn.getSQLType()).toBe('mediumint unsigned'); + expect(tinyintColumn.getSQLType()).toBe('tinyint unsigned'); + }); + + test('table config: signed ints', async () => { + const unsignedInts = singlestoreTable('cities1', { + bigint: bigint('bigint', { mode: 'number' }), + int: int('int'), + smallint: smallint('smallint'), + mediumint: mediumint('mediumint'), + tinyint: tinyint('tinyint'), + }); + + const tableConfig = getTableConfig(unsignedInts); + + const bigintColumn = tableConfig.columns.find((c) => c.name === 'bigint')!; + const intColumn = tableConfig.columns.find((c) => c.name === 'int')!; + const smallintColumn = tableConfig.columns.find((c) => c.name === 'smallint')!; + const mediumintColumn = tableConfig.columns.find((c) => c.name === 'mediumint')!; + const tinyintColumn = tableConfig.columns.find((c) => c.name === 'tinyint')!; + + expect(bigintColumn.getSQLType()).toBe('bigint'); + expect(intColumn.getSQLType()).toBe('int'); + expect(smallintColumn.getSQLType()).toBe('smallint'); + expect(mediumintColumn.getSQLType()).toBe('mediumint'); + expect(tinyintColumn.getSQLType()).toBe('tinyint'); + }); + + test('table config: primary keys name', async () => { + const table = singlestoreTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: primaryKey({ columns: [t.id, t.name], name: 'custom_pk' }), + })); + + const tableConfig = getTableConfig(table); + + expect(tableConfig.primaryKeys).toHaveLength(1); + expect(tableConfig.primaryKeys[0]!.getName()).toBe('custom_pk'); + }); + + test('table configs: unique third param', async () => { + const cities1Table = singlestoreTable('cities1', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: unique('custom_name').on(t.name, t.state), + f1: unique('custom_name1').on(t.name, t.state), + })); + + const tableConfig = getTableConfig(cities1Table); + + expect(tableConfig.uniqueConstraints).toHaveLength(2); + + expect(tableConfig.uniqueConstraints[0]?.name).toBe('custom_name'); + expect(tableConfig.uniqueConstraints[0]?.columns.map((t) => t.name)).toEqual(['name', 'state']); + + expect(tableConfig.uniqueConstraints[1]?.name).toBe('custom_name1'); + expect(tableConfig.uniqueConstraints[1]?.columns.map((t) => t.name)).toEqual(['name', 'state']); + }); + + test('table configs: unique in column', async () => { + const cities1Table = singlestoreTable('cities1', { + id: serial('id').primaryKey(), + name: text('name').notNull().unique(), + state: text('state').unique('custom'), + field: text('field').unique('custom_field'), + }); + + const tableConfig = getTableConfig(cities1Table); + + const columnName = tableConfig.columns.find((it) => it.name === 'name'); + expect(columnName?.uniqueName).toBe(uniqueKeyName(cities1Table, [columnName!.name])); + expect(columnName?.isUnique).toBeTruthy(); + + const columnState = tableConfig.columns.find((it) => it.name === 'state'); + expect(columnState?.uniqueName).toBe('custom'); + expect(columnState?.isUnique).toBeTruthy(); + + const columnField = tableConfig.columns.find((it) => it.name === 'field'); + expect(columnField?.uniqueName).toBe('custom_field'); + expect(columnField?.isUnique).toBeTruthy(); + }); + + test('select all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('select sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('select typed sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('select with empty array in inArray', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + const result = await db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(inArray(usersTable.id, [])) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([]); + }); + + test('select with empty array in notInArray', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + const result = await db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(notInArray(usersTable.id, [])) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'JOHN' }, { name: 'JANE' }, { name: 'JANE' }]); + }); + + test('select distinct', async (ctx) => { + const { db } = ctx.singlestore; + + const usersDistinctTable = singlestoreTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${usersDistinctTable}`); + await db.execute(sql`create table ${usersDistinctTable} (id int, name text)`); + + await db.insert(usersDistinctTable).values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]); + const users = await db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ); + + await db.execute(sql`drop table ${usersDistinctTable}`); + + expect(users).toEqual([{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); + }); + + test('insert returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + const [result, _] = await db.insert(usersTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); + }); + + test('delete returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); + }); + + test('update returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + expect(users[0].changedRows).toBe(1); + }); + + test('update with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select().from(usersTable).where(eq(usersTable.id, 1)); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 2000); + expect(users).toEqual([{ id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); + }); + + test('update with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); + }); + + test('delete with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); + }); + + test('delete with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); + }); + + test('insert + select', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); + }); + + test('json insert', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); + }); + + test('insert with overridden default values', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('insert many', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); + }); + + test('insert many with returning', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + + expect(result[0].affectedRows).toBe(4); + }); + + test('select with group by as field', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.name) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); + }); + + test('select with exists', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const user = alias(usersTable, 'user'); + const result = await db.select({ name: usersTable.name }).from(usersTable).where( + exists( + db.select({ one: sql`1` }).from(user).where(and(eq(usersTable.name, 'John'), eq(user.id, usersTable.id))), + ), + ) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }]); + }); + + test('select with group by as sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); + }); + + test('$default function', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`orders\``); + await db.execute( + sql` + create table \`orders\` ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values({ id: 1, region: 'Ukraine', amount: 1, quantity: 1 }); + const selectedOrder = await db.select().from(orders); + + expect(selectedOrder).toEqual([{ + id: 1, + amount: 1, + quantity: 1, + region: 'Ukraine', + product: 'random_string', + }]); + }); + + test('$default with empty array', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`s_orders\``); + await db.execute( + sql` + create table \`s_orders\` ( + \`id\` serial primary key, + \`region\` text default 'Ukraine', + \`product\` text not null + ) + `, + ); + + const users = singlestoreTable('s_orders', { + id: serial('id').primaryKey(), + region: text('region').default('Ukraine'), + product: text('product').$defaultFn(() => 'random_string'), + }); + + await db.insert(users).values({ id: 1 }); + const selectedOrder = await db.select().from(users); + + expect(selectedOrder).toEqual([{ + id: 1, + region: 'Ukraine', + product: 'random_string', + }]); + }); + + test('select with group by as sql + column', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + }); + + test('select with group by as column + sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + }); + + test('select with group by complex query', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + expect(result).toEqual([{ name: 'Jane' }]); + }); + + test('build query', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: `select \`id\`, \`name\` from \`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + params: [], + }); + }); + + test('Query check: Insert all defaults in 1 row', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + const query = db + .insert(users) + .values({}) + .toSQL(); + + expect(query).toEqual({ + sql: 'insert into `users` (`id`, `name`, `state`) values (default, default, default)', + params: [], + }); + }); + + test('Query check: Insert all defaults in multiple rows', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state').default('UA'), + }); + + const query = db + .insert(users) + .values([{}, {}]) + .toSQL(); + + expect(query).toEqual({ + sql: + 'insert into `users` (`id`, `name`, `state`) values (default, default, default), (default, default, default)', + params: [], + }); + }); + + test('Insert all defaults in 1 row', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('empty_insert_single', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial primary key, name text default 'Dan', state text)`, + ); + + await db.insert(users).values({ id: 1 }); + + const res = await db.select().from(users); + + expect(res).toEqual([{ id: 1, name: 'Dan', state: null }]); + }); + + test('Insert all defaults in multiple rows', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('empty_insert_multiple', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial primary key, name text default 'Dan', state text)`, + ); + + await db.insert(users).values([{ id: 1 }, { id: 2 }]); + + const res = await db.select().from(users).orderBy(asc(users.id)); + + expect(res).toEqual([{ id: 1, name: 'Dan', state: null }, { id: 2, name: 'Dan', state: null }]); + }); + + test('build query insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.insert(usersTable) + .values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }) + .onDuplicateKeyUpdate({ set: { id: 1, name: 'John1' } }) + .toSQL(); + + expect(query).toEqual({ + sql: + 'insert into `userstest` (`id`, `name`, `verified`, `jsonb`, `created_at`) values (?, ?, default, ?, default) on duplicate key update `id` = ?, `name` = ?', + params: [1, 'John', '["foo","bar"]', 1, 'John1'], + }); + }); + + test('insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John1' }]); + }); + + test('insert conflict', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await expect((async () => { + db.insert(usersTable).values({ id: 1, name: 'John1' }); + })()).resolves.not.toThrowError(); + }); + + test('insert conflict with ignore', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .ignore() + .values({ id: 1, name: 'John1' }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John' }]); + }); + + test('insert sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`${'John'}` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('partial join with alias', async (ctx) => { + const { db } = ctx.singlestore; + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }).from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }]); + }); + + test('full join with alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select().from(users) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(users.id, 10)) + .orderBy(asc(users.id)); + + expect(result).toEqual([{ + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); + }); + + test('select from alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(user) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(user.id, 10)) + .orderBy(asc(user.id)); + + expect(result).toEqual([{ + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); + }); + + test('insert with spaces', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); + }); + + test('prepared statement', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const statement = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .prepare(); + const result = await statement.execute(); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('insert: placeholders on columns with encoder', async (ctx) => { + const { db } = ctx.singlestore; + + const date = new Date('2024-08-07T15:30:00Z'); + + const statement = db.insert(usersTable).values({ + id: 1, + name: 'John', + createdAt: sql.placeholder('createdAt'), + }).prepare(); + + await statement.execute({ createdAt: date }); + + const result = await db + .select({ + id: usersTable.id, + createdAt: usersTable.createdAt, + }) + .from(usersTable); + + expect(result).toEqual([ + { id: 1, createdAt: date }, + ]); + }); + + test('prepared statement reuse', async (ctx) => { + const { db } = ctx.singlestore; + + const stmt = db.insert(usersTable).values({ + verified: true, + id: placeholder('id'), + name: placeholder('name'), + }).prepare(); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ id: i + 1, name: `John ${i}` }); + } + + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); + }); + + test('prepared statement with placeholder in .where', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .where(eq(usersTable.id, placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('migrator', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists cities_migration`); + await db.execute(sql`drop table if exists users_migration`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists __drizzle_migrations`); + + await migrate(db, { migrationsFolder: './drizzle2/singlestore' }); + + await db.insert(usersMigratorTable).values({ id: 1, name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table cities_migration`); + await db.execute(sql`drop table users_migration`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table __drizzle_migrations`); + }); + + test('insert via db.execute + select via db.execute', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute( + sql`insert into ${usersTable} (${new Name(usersTable.id.name)},${new Name( + usersTable.name.name, + )}) values (1,${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>(sql`select id, name from ${usersTable}`); + expect(result[0]).toEqual([{ id: 1, name: 'John' }]); + }); + + test('insert via db.execute w/ query builder', async (ctx) => { + const { db } = ctx.singlestore; + + const inserted = await db.execute( + db.insert(usersTable).values({ id: 1, name: 'John' }), + ); + expect(inserted[0].affectedRows).toBe(1); + }); + + test('insert + select all possible dates', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute( + sql` + create table \`datestable\` ( + \`date\` date, + \`date_as_string\` date, + \`time\` time, + \`datetime\` datetime, + \`datetime_as_string\` datetime, + \`timestamp\` timestamp(6), + \`timestamp_as_string\` timestamp(6), + \`year\` year + ) + `, + ); + + const date = new Date('2022-11-11'); + const dateWithMilliseconds = new Date('2022-11-11 12:12:12.123'); + + await db.insert(datesTable).values({ + date: date, + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: date, + year: 22, + datetimeAsString: '2022-11-11 12:12:12', + timestamp: dateWithMilliseconds, + timestampAsString: '2022-11-11 12:12:12.123', + }); + + const res = await db.select().from(datesTable); + + expect(res[0]?.date).toBeInstanceOf(Date); + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(typeof res[0]?.dateAsString).toBe('string'); + expect(typeof res[0]?.datetimeAsString).toBe('string'); + + expect(res).toEqual([{ + date: toLocalDate(new Date('2022-11-11')), + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: new Date('2022-11-11'), + year: 2022, + datetimeAsString: '2022-11-11 12:12:12', + timestamp: new Date('2022-11-11 12:12:12.123'), + timestampAsString: '2022-11-11 12:12:12.123000', + }]); + + await db.execute(sql`drop table if exists \`datestable\``); + }); + + const tableWithEnums = singlestoreTable('enums_test_case', { + id: serial('id').primaryKey(), + enum1: singlestoreEnum('enum1', ['a', 'b', 'c']).notNull(), + enum2: singlestoreEnum('enum2', ['a', 'b', 'c']).default('a'), + enum3: singlestoreEnum('enum3', ['a', 'b', 'c']).notNull().default('b'), + }); + + test('SingleStore enum test case #1', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`enums_test_case\``); + + await db.execute(sql` + create table \`enums_test_case\` ( + \`id\` serial primary key, + \`enum1\` ENUM('a', 'b', 'c') not null, + \`enum2\` ENUM('a', 'b', 'c') default 'a', + \`enum3\` ENUM('a', 'b', 'c') not null default 'b' + ) + `); + + await db.insert(tableWithEnums).values([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum3: 'c' }, + { id: 3, enum1: 'a' }, + ]); + + const res = await db.select().from(tableWithEnums).orderBy(asc(tableWithEnums.id)); + + await db.execute(sql`drop table \`enums_test_case\``); + + expect(res).toEqual([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum2: 'a', enum3: 'c' }, + { id: 3, enum1: 'a', enum2: 'a', enum3: 'b' }, + ]); + }); + + test('left join (flat object fields)', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + userId: users2Table.id, + userName: users2Table.name, + cityId: citiesTable.id, + cityName: citiesTable.name, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(users2Table.id); + + expect(res).toEqual([ + { userId: 1, userName: 'John', cityId: 1, cityName: 'Paris' }, + { userId: 2, userName: 'Jane', cityId: null, cityName: null }, + ]); + }); + + test('left join (grouped fields)', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + id: users2Table.id, + user: { + name: users2Table.name, + nameUpper: sql`upper(${users2Table.name})`, + }, + city: { + id: citiesTable.id, + name: citiesTable.name, + nameUpper: sql`upper(${citiesTable.name})`, + }, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + id: 1, + user: { name: 'John', nameUpper: 'JOHN' }, + city: { id: 1, name: 'Paris', nameUpper: 'PARIS' }, + }, + { + id: 2, + user: { name: 'Jane', nameUpper: 'JANE' }, + city: null, + }, + ]); + }); + + test('left join (all fields)', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select().from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + users2: { + id: 1, + name: 'John', + cityId: 1, + }, + cities: { + id: 1, + name: 'Paris', + }, + }, + { + users2: { + id: 2, + name: 'Jane', + cityId: null, + }, + cities: null, + }, + ]); + }); + + test('join subquery', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`courses\``); + await db.execute(sql`drop table if exists \`course_categories\``); + + await db.execute( + sql` + create table \`course_categories\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.execute( + sql` + create table \`courses\` ( + \`id\` serial primary key, + \`name\` text not null, + \`category_id\` int + ) + `, + ); + + await db.insert(courseCategoriesTable).values([ + { id: 1, name: 'Category 1' }, + { id: 2, name: 'Category 2' }, + { id: 3, name: 'Category 3' }, + { id: 4, name: 'Category 4' }, + ]); + + await db.insert(coursesTable).values([ + { id: 1, name: 'Development', categoryId: 2 }, + { id: 2, name: 'IT & Software', categoryId: 3 }, + { id: 3, name: 'Marketing', categoryId: 4 }, + { id: 4, name: 'Design', categoryId: 1 }, + ]); + + const sq2 = db + .select({ + categoryId: courseCategoriesTable.id, + category: courseCategoriesTable.name, + total: sql`count(${courseCategoriesTable.id})`, + }) + .from(courseCategoriesTable) + .groupBy(courseCategoriesTable.id, courseCategoriesTable.name) + .as('sq2'); + + const res = await db + .select({ + courseName: coursesTable.name, + categoryId: sq2.categoryId, + }) + .from(coursesTable) + .leftJoin(sq2, eq(coursesTable.categoryId, sq2.categoryId)) + .orderBy(coursesTable.name); + + expect(res).toEqual([ + { courseName: 'Design', categoryId: 1 }, + { courseName: 'Development', categoryId: 2 }, + { courseName: 'IT & Software', categoryId: 3 }, + { courseName: 'Marketing', categoryId: 4 }, + ]); + + await db.execute(sql`drop table if exists \`courses\``); + await db.execute(sql`drop table if exists \`course_categories\``); + }); + + test('with ... select', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`orders\``); + await db.execute( + sql` + create table \`orders\` ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: regionalSales.region, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`cast(sum(${orders.quantity}) as unsigned)`, + productSales: sql`cast(sum(${orders.amount}) as unsigned)`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))) + .groupBy(orders.region, orders.product) + .orderBy(orders.region, orders.product); + + expect(result).toEqual([ + { + region: 'Europe', + product: 'A', + productUnits: 3, + productSales: 30, + }, + { + region: 'Europe', + product: 'B', + productUnits: 5, + productSales: 50, + }, + { + region: 'US', + product: 'A', + productUnits: 7, + productSales: 70, + }, + { + region: 'US', + product: 'B', + productUnits: 9, + productSales: 90, + }, + ]); + }); + + test('with ... update', async (ctx) => { + const { db } = ctx.singlestore; + + const products = singlestoreTable('products', { + id: serial('id').primaryKey(), + price: decimal('price', { + precision: 15, + scale: 2, + }).notNull(), + cheap: boolean('cheap').notNull().default(false), + }); + + await db.execute(sql`drop table if exists ${products}`); + await db.execute(sql` + create table ${products} ( + id serial primary key, + price decimal(15, 2) not null, + cheap boolean not null default false + ) + `); + + await db.insert(products).values([ + { id: 1, price: '10.99' }, + { id: 2, price: '25.85' }, + { id: 3, price: '32.99' }, + { id: 4, price: '2.50' }, + { id: 5, price: '4.59' }, + ]); + + const averagePrice = db + .$with('average_price') + .as( + db + .select({ + value: sql`avg(${products.price})`.as('value'), + }) + .from(products), + ); + + await db + .with(averagePrice) + .update(products) + .set({ + cheap: true, + }) + .where(lt(products.price, sql`(select * from ${averagePrice})`)); + + const result = await db + .select({ + id: products.id, + }) + .from(products) + .where(eq(products.cheap, true)) + .orderBy(asc(products.id)); + + expect(result).toEqual([ + { id: 1 }, + { id: 4 }, + { id: 5 }, + ]); + }); + + test('with ... delete', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`orders\``); + await db.execute( + sql` + create table \`orders\` ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values([ + { id: 1, region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { id: 2, region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { id: 3, region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { id: 4, region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { id: 5, region: 'US', product: 'A', amount: 30, quantity: 3 }, + { id: 6, region: 'US', product: 'A', amount: 40, quantity: 4 }, + { id: 7, region: 'US', product: 'B', amount: 40, quantity: 4 }, + { id: 8, region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const averageAmount = db + .$with('average_amount') + .as( + db + .select({ + value: sql`avg(${orders.amount})`.as('value'), + }) + .from(orders), + ); + + await db + .with(averageAmount) + .delete(orders) + .where(gt(orders.amount, sql`(select * from ${averageAmount})`)); + + const result = await db + .select({ + id: orders.id, + }) + .from(orders) + .orderBy(asc(orders.id)); + + expect(result).toEqual([ + { id: 1 }, + { id: 2 }, + { id: 3 }, + { id: 4 }, + { id: 5 }, + ]); + }); + + test('select from subquery sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(users2Table).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]); + + const sq = db + .select({ name: sql`concat(${users2Table.name}, " modified")`.as('name') }) + .from(users2Table) + .orderBy(asc(users2Table.id)) + .as('sq'); + + const res = await db.select({ name: sq.name }).from(sq); + + expect(res).toEqual([{ name: 'John modified' }, { name: 'Jane modified' }]); + }); + + test('select a field without joining its table', (ctx) => { + const { db } = ctx.singlestore; + + expect(() => db.select({ name: users2Table.name }).from(usersTable).prepare()).toThrowError(); + }); + + test('select all fields from subquery without alias', (ctx) => { + const { db } = ctx.singlestore; + + const sq = db.$with('sq').as(db.select({ name: sql`upper(${users2Table.name})` }).from(users2Table)); + + expect(() => db.select().from(sq).prepare()).toThrowError(); + }); + + test('select count()', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }]); + + const res = await db.select({ count: sql`count(*)` }).from(usersTable); + + expect(res).toEqual([{ count: 2 }]); + }); + + test('select for ...', (ctx) => { + const { db } = ctx.singlestore; + + { + const query = db.select().from(users2Table).for('update').toSQL(); + expect(query.sql).toMatch(/ for update$/); + } + { + const query = db.select().from(users2Table).for('share', { skipLocked: true }).toSQL(); + expect(query.sql).toMatch(/ for share skip locked$/); + } + { + const query = db.select().from(users2Table).for('update', { noWait: true }).toSQL(); + expect(query.sql).toMatch(/ for update no wait$/); + } + }); + + test('having', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable).values([{ id: 1, name: 'London' }, { id: 2, name: 'Paris' }, { + id: 3, + name: 'New York', + }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane', cityId: 1 }, { + id: 3, + name: 'Jack', + cityId: 2, + }]); + + const result = await db + .select({ + id: citiesTable.id, + name: sql`upper(${citiesTable.name})`.as('upper_name'), + usersCount: sql`count(${users2Table.id})`.as('users_count'), + }) + .from(citiesTable) + .leftJoin(users2Table, eq(users2Table.cityId, citiesTable.id)) + .where(({ name }) => sql`length(${name}) >= 3`) + .groupBy(citiesTable.id) + .having(({ usersCount }) => sql`${usersCount} > 0`) + .orderBy(({ name }) => name); + + expect(result).toEqual([ + { + id: 1, + name: 'LONDON', + usersCount: 2, + }, + { + id: 2, + name: 'PARIS', + usersCount: 1, + }, + ]); + }); + + test('view', async (ctx) => { + const { db } = ctx.singlestore; + + const newYorkers1 = singlestoreView('new_yorkers') + .as((qb) => qb.select().from(users2Table).where(eq(users2Table.cityId, 1))); + + const newYorkers2 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).as(sql`select * from ${users2Table} where ${eq(users2Table.cityId, 1)}`); + + const newYorkers3 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).existing(); + + await db.execute(sql`create view new_yorkers as ${getViewConfig(newYorkers1).query}`); + + await db.insert(citiesTable).values([{ id: 1, name: 'New York' }, { id: 2, name: 'Paris' }]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2).orderBy(asc(newYorkers2.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3).orderBy(asc(newYorkers3.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop view ${newYorkers1}`); + }); + + test('select from raw sql', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.select({ + id: sql`id`, + name: sql`name`, + }).from(sql`(select 1 as id, 'John' as name) as users`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John' }, + ]); + }); + + test('select from raw sql with joins', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db + .select({ + id: sql`users.id`, + name: sql`users.name`, + userCity: sql`users.city`, + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, sql`cities.id = users.id`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John', userCity: 'New York', cityName: 'Paris' }, + ]); + }); + + test('join on aliased sql from select', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db + .select({ + userId: sql`users.id`.as('userId'), + name: sql`users.name`, + userCity: sql`users.city`, + cityId: sql`cities.id`.as('cityId'), + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, (cols) => eq(cols.cityId, cols.userId)); + + Expect< + Equal<{ userId: number; name: string; userCity: string; cityId: number; cityName: string }[], typeof result> + >; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); + }); + + test('join on aliased sql from with clause', async (ctx) => { + const { db } = ctx.singlestore; + + const users = db.$with('users').as( + db.select({ + id: sql`id`.as('userId'), + name: sql`name`.as('userName'), + city: sql`city`.as('city'), + }).from( + sql`(select 1 as id, 'John' as name, 'New York' as city) as users`, + ), + ); + + const cities = db.$with('cities').as( + db.select({ + id: sql`id`.as('cityId'), + name: sql`name`.as('cityName'), + }).from( + sql`(select 1 as id, 'Paris' as name) as cities`, + ), + ); + + const result = await db + .with(users, cities) + .select({ + userId: users.id, + name: users.name, + userCity: users.city, + cityId: cities.id, + cityName: cities.name, + }) + .from(users) + .leftJoin(cities, (cols) => eq(cols.cityId, cols.userId)); + + Expect< + Equal<{ userId: number; name: string; userCity: string; cityId: number; cityName: string }[], typeof result> + >; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); + }); + + test('prefixed table', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `myprefix_${name}`); + + const users = singlestoreTable('test_prefixed_table_with_unique_name', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table myprefix_test_prefixed_table_with_unique_name (id int not null primary key, name text not null)`, + ); + + await db.insert(users).values({ id: 1, name: 'John' }); + + const result = await db.select().from(users); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + + await db.execute(sql`drop table ${users}`); + }); + + test('orderBy with aliased column', (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ + test: sql`something`.as('test'), + }).from(users2Table).orderBy((fields) => fields.test).toSQL(); + + expect(query.sql).toBe('select something as `test` from `users2` order by `test`'); + }); + + test('timestamp timezone', async (ctx) => { + const { db } = ctx.singlestore; + + const date = new Date(Date.parse('2020-01-01T12:34:56+07:00')); + + await db.insert(usersTable).values({ id: 1, name: 'With default times' }); + await db.insert(usersTable).values({ + id: 2, + name: 'Without default times', + createdAt: date, + }); + const users = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + + // check that the timestamps are set correctly for default times + expect(Math.abs(users[0]!.createdAt.getTime() - Date.now())).toBeLessThan(2000); + + // check that the timestamps are set correctly for non default times + expect(Math.abs(users[1]!.createdAt.getTime() - date.getTime())).toBeLessThan(2000); + }); + + test('transaction', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_transactions', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + const products = singlestoreTable('products_transactions', { + id: serial('id').primaryKey(), + price: int('price').notNull(), + stock: int('stock').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop table if exists ${products}`); + + await db.execute(sql`create table users_transactions (id serial not null primary key, balance int not null)`); + await db.execute( + sql`create table products_transactions (id serial not null primary key, price int not null, stock int not null)`, + ); + + const [{ insertId: userId }] = await db.insert(users).values({ id: 1, balance: 100 }); + const user = await db.select().from(users).where(eq(users.id, userId)).then((rows) => rows[0]!); + const [{ insertId: productId }] = await db.insert(products).values({ id: 1, price: 10, stock: 10 }); + const product = await db.select().from(products).where(eq(products.id, productId)).then((rows) => rows[0]!); + + await db.transaction(async (tx) => { + await tx.update(users).set({ balance: user.balance - product.price }).where(eq(users.id, user.id)); + await tx.update(products).set({ stock: product.stock - 1 }).where(eq(products.id, product.id)); + }); + + const result = await db.select().from(users); + + expect(result).toEqual([{ id: 1, balance: 90 }]); + + await db.execute(sql`drop table ${users}`); + await db.execute(sql`drop table ${products}`); + }); + + test('transaction rollback', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_transactions_rollback', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table users_transactions_rollback (id serial not null primary key, balance int not null)`, + ); + + await expect((async () => { + await db.transaction(async (tx) => { + await tx.insert(users).values({ balance: 100 }); + tx.rollback(); + }); + })()).rejects.toThrowError(TransactionRollbackError); + + const result = await db.select().from(users); + + expect(result).toEqual([]); + + await db.execute(sql`drop table ${users}`); + }); + + test('join subquery with join', async (ctx) => { + const { db } = ctx.singlestore; + + const internalStaff = singlestoreTable('internal_staff', { + userId: int('user_id').notNull(), + }); + + const customUser = singlestoreTable('custom_user', { + id: int('id').notNull(), + }); + + const ticket = singlestoreTable('ticket', { + staffId: int('staff_id').notNull(), + }); + + await db.execute(sql`drop table if exists ${internalStaff}`); + await db.execute(sql`drop table if exists ${customUser}`); + await db.execute(sql`drop table if exists ${ticket}`); + + await db.execute(sql`create table internal_staff (user_id integer not null)`); + await db.execute(sql`create table custom_user (id integer not null)`); + await db.execute(sql`create table ticket (staff_id integer not null)`); + + await db.insert(internalStaff).values({ userId: 1 }); + await db.insert(customUser).values({ id: 1 }); + await db.insert(ticket).values({ staffId: 1 }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin(customUser, eq(internalStaff.userId, customUser.id)) + .as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + expect(mainQuery).toEqual([{ + ticket: { staffId: 1 }, + internal_staff: { + internal_staff: { userId: 1 }, + custom_user: { id: 1 }, + }, + }]); + + await db.execute(sql`drop table ${internalStaff}`); + await db.execute(sql`drop table ${customUser}`); + await db.execute(sql`drop table ${ticket}`); + }); + + test('subquery with view', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_subquery_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.$with('sq').as(db.select().from(newYorkers)); + const result = await db.with(sq).select().from(sq).orderBy(asc(sq.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 1 }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); + }); + + test('join view as subquery', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_join_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.select().from(newYorkers).as('new_yorkers_sq'); + + const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id)).orderBy(asc(users.id)); + + expect(result).toEqual([ + { + users_join_view: { id: 1, name: 'John', cityId: 1 }, + new_yorkers_sq: { id: 1, name: 'John', cityId: 1 }, + }, + { + users_join_view: { id: 2, name: 'Jane', cityId: 2 }, + new_yorkers_sq: null, + }, + { + users_join_view: { id: 3, name: 'Jack', cityId: 1 }, + new_yorkers_sq: { id: 3, name: 'Jack', cityId: 1 }, + }, + { + users_join_view: { id: 4, name: 'Jill', cityId: 2 }, + new_yorkers_sq: null, + }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); + }); + + test('select iterator', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const iter = db.select().from(users) + .orderBy(asc(users.id)) + .iterator(); + + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + test('select iterator w/ prepared statement', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const prepared = db.select().from(users) + .orderBy(asc(users.id)) + .prepare(); + const iter = prepared.iterator(); + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + test('insert undefined', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.insert(users).values({ name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); + }); + + test('update undefined', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.update(users).set({ name: undefined }); + })()).rejects.toThrowError(); + + await expect((async () => { + await db.update(users).set({ id: 1, name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); + }); + + test('utc config for datetime', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute( + sql` + create table \`datestable\` ( + \`datetime_utc\` datetime(6), + \`datetime\` datetime(6) + ) + `, + ); + const datesTable = singlestoreTable('datestable', { + datetimeUTC: datetime('datetime_utc', { fsp: 6, mode: 'date' }), + datetime: datetime('datetime', { fsp: 6 }), + }); + + const dateObj = new Date('2022-11-11'); + const dateUtc = new Date('2022-11-11T12:12:12.122Z'); + + await db.insert(datesTable).values({ + datetimeUTC: dateUtc, + datetime: dateObj, + }); + + const res = await db.select().from(datesTable); + + const [rawSelect] = await db.execute(sql`select \`datetime_utc\` from \`datestable\``); + const selectedRow = (rawSelect as unknown as [{ datetime_utc: string }])[0]; + + expect(selectedRow.datetime_utc).toBe('2022-11-11 12:12:12.122000'); + expect(new Date(selectedRow.datetime_utc.replace(' ', 'T') + 'Z')).toEqual(dateUtc); + + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(res[0]?.datetimeUTC).toBeInstanceOf(Date); + + expect(res).toEqual([{ + datetimeUTC: dateUtc, + datetime: new Date('2022-11-11'), + }]); + + await db.execute(sql`drop table if exists \`datestable\``); + }); + + // TODO (https://memsql.atlassian.net/browse/MCDB-63261) allow chaining limit and orderby in subquery + test('set operations (union) from query builder with subquery', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + const citiesQuery = db + .select({ + id: citiesTable.id, + name: citiesTable.name, + orderCol: sql`0`.as('orderCol'), + }) + .from(citiesTable); + + const usersQuery = db + .select({ + id: users2Table.id, + name: users2Table.name, + orderCol: sql`1`.as('orderCol'), + }) + .from(users2Table); + + const unionQuery = db + .select({ + id: sql`id`, + name: sql`name`, + }) + .from( + citiesQuery.union(usersQuery).as('combined'), + ) + .orderBy(sql`orderCol`, sql`id`) + .limit(8); + + const result = await unionQuery; + + expect(result).toHaveLength(8); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Jack' }, + { id: 4, name: 'Peter' }, + { id: 5, name: 'Ben' }, + ]); + + // union should throw if selected fields are not in the same order + await expect((async () => { + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).union( + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (union) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const result = await union( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + { id: 1, name: 'John' }, + ]); + + await expect((async () => { + union( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (union all) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).orderBy(asc(sql`id`)).limit(2).unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).orderBy(asc(sql`id`)).limit(2), + ).as('sq'); + + const result = await db.select().from(sq).orderBy(asc(sql`id`)).limit(3); + + expect(result).toHaveLength(3); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + ]); + + await expect((async () => { + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).limit(2).unionAll( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).limit(2), + ).orderBy(asc(sql`id`)); + })()).rejects.toThrowError(); + }); + + test('set operations (union all) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).as('sq'); + + const result = await db.select().from(sq).limit(1); + + expect(result).toHaveLength(1); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + ]); + + await expect((async () => { + unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(1); + })()).rejects.toThrowError(); + }); + + test('set operations (intersect) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ) + .as('sq'); + + const result = await db.select().from(sq).orderBy(asc(sql`id`)); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await expect((async () => { + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (intersect) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = await intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).as('sq'); + + const result = await db.select().from(sq).limit(1); + + expect(result).toHaveLength(0); + + expect(result).toEqual([]); + + await expect((async () => { + intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(1); + })()).rejects.toThrowError(); + }); + + test('set operations (except) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const result = await db + .select() + .from(citiesTable).except( + db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + + expect(result).toHaveLength(1); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + ]); + }); + + test('set operations (except) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = await except( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable), + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).as('sq'); + + const result = await db.select().from(sq).limit(3); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await expect((async () => { + except( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable), + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(3); + })()).rejects.toThrowError(); + }); + + test('set operations (mixed) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq1 = unionAll( + db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + db.select().from(citiesTable).where(eq(citiesTable.id, 2)), + ).as('sq1'); + + const sq2 = await db.select().from(sq1).orderBy(asc(sql`id`)).as('sq2'); + + const sq3 = await db.select().from(sq2).limit(1).offset(1).as('sq3'); + + const result = await db + .select() + .from(citiesTable) + .except( + db + .select() + .from(sq3), + ); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 3, name: 'Tampa' }, + { id: 1, name: 'New York' }, + ]); + + await expect((async () => { + db + .select() + .from(citiesTable).except( + ({ unionAll }) => + unionAll( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + db.select().from(citiesTable).where(eq(citiesTable.id, 2)), + ), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (mixed all) as function with subquery', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq1 = except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 7)), + ).as('sq1'); + + const sq2 = await db.select().from(sq1).orderBy(asc(sql`id`)).as('sq2'); + + const sq3 = await db.select().from(sq2).limit(1).as('sq3'); + + const result = await union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db.select().from(sq3), + db + .select().from(citiesTable).where(gt(citiesTable.id, 1)), + ); + + expect(result).toHaveLength(4); + + // multiple results possible as a result of the filters >= 5 and ==7 because singlestore doesn't guarantee order + // dynamically validate results + const hasValidEntry = (entry: { id: number; name: string }) => { + if (entry.id === 1) return entry.name === 'John'; + if (entry.id > 1 && entry.id < 5) return entry.name === 'Tampa' || entry.name === 'London'; + if (entry.id >= 5 && entry.id !== 7) return true; // Accept any entry with id >= 5 and not 7 + return false; + }; + + for (const entry of result) { + expect(hasValidEntry(entry)).toBe(true); + } + + await expect((async () => { + union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 7)), + ).limit(1), + db + .select().from(citiesTable).where(gt(citiesTable.id, 1)), + ); + })()).rejects.toThrowError(); + }); + + test('aggregate function: count', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: count() }).from(table); + const result2 = await db.select({ value: count(table.a) }).from(table); + const result3 = await db.select({ value: countDistinct(table.name) }).from(table); + + expect(result1[0]?.value).toBe(7); + expect(result2[0]?.value).toBe(5); + expect(result3[0]?.value).toBe(6); + }); + + test('aggregate function: avg', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: avg(table.b) }).from(table); + const result2 = await db.select({ value: avg(table.nullOnly) }).from(table); + const result3 = await db.select({ value: avgDistinct(table.b) }).from(table); + + expect(result1[0]?.value).toBe('33.3333'); + expect(result2[0]?.value).toBe(null); + expect(result3[0]?.value).toBe('42.5000'); + }); + + test('aggregate function: sum', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: sum(table.b) }).from(table); + const result2 = await db.select({ value: sum(table.nullOnly) }).from(table); + const result3 = await db.select({ value: sumDistinct(table.b) }).from(table); + + expect(result1[0]?.value).toBe('200'); + expect(result2[0]?.value).toBe(null); + expect(result3[0]?.value).toBe('170'); + }); + + test('aggregate function: max', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: max(table.b) }).from(table); + const result2 = await db.select({ value: max(table.nullOnly) }).from(table); + + expect(result1[0]?.value).toBe(90); + expect(result2[0]?.value).toBe(null); + }); + + test('aggregate function: min', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: min(table.b) }).from(table); + const result2 = await db.select({ value: min(table.nullOnly) }).from(table); + + expect(result1[0]?.value).toBe(10); + expect(result2[0]?.value).toBe(null); + }); + + test('test $onUpdateFn and $onUpdate works as $default', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists ${usersOnUpdate}`); + + await db.execute( + sql` + create table ${usersOnUpdate} ( + id serial not null primary key, + name text not null, + update_counter integer default 1 not null, + updated_at datetime(6), + always_null text + ) + `, + ); + + await db.insert(usersOnUpdate).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Jack' }, + { id: 4, name: 'Jill' }, + ]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + + const justDates = await db.select({ updatedAt }).from(usersOnUpdate); + + const response = await db.select({ ...rest }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + expect(response).toEqual([ + { name: 'John', id: 1, updateCounter: 1, alwaysNull: null }, + { name: 'Jane', id: 2, updateCounter: 1, alwaysNull: null }, + { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, + { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, + ]); + const msDelay = 750; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); + } + }); + + test('test $onUpdateFn and $onUpdate works updating', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists ${usersOnUpdate}`); + + await db.execute( + sql` + create table ${usersOnUpdate} ( + id serial not null primary key, + name text not null, + update_counter integer default 1 not null, + updated_at datetime(6), + always_null text + ) + `, + ); + + await db.insert(usersOnUpdate).values([ + { id: 1, name: 'John', alwaysNull: 'this will will be null after updating' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Jack' }, + { id: 4, name: 'Jill' }, + ]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + const initial = await db.select({ id: usersOnUpdate.id, updatedAt: usersOnUpdate.updatedAt }).from(usersOnUpdate); + + await db.update(usersOnUpdate).set({ name: 'Angel' }).where(eq(usersOnUpdate.id, 1)); + + const justDates = await db.select({ id: usersOnUpdate.id, updatedAt: usersOnUpdate.updatedAt }).from( + usersOnUpdate, + ); + + const response = await db.select().from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + expect(response).toEqual([ + { id: 1, name: 'Angel', updateCounter: 2, updatedAt: expect.any(Date), alwaysNull: null }, + { id: 2, name: 'Jane', updateCounter: 1, updatedAt: expect.any(Date), alwaysNull: null }, + { id: 3, name: 'Jack', updateCounter: 1, updatedAt: expect.any(Date), alwaysNull: null }, + { id: 4, name: 'Jill', updateCounter: 1, updatedAt: expect.any(Date), alwaysNull: null }, + ]); + + const initialRecord = initial.find((record) => record.id === 1); + const updatedRecord = justDates.find((record) => record.id === 1); + + expect(initialRecord?.updatedAt?.valueOf()).not.toBe(updatedRecord?.updatedAt?.valueOf()); + + const msDelay = 1000; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); + } + }); + + // mySchema tests + test('mySchema :: select all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersMySchemaTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('mySchema :: select sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersMySchemaTable.name})`, + }).from(usersMySchemaTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('mySchema :: select typed sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersMySchemaTable.name})`, + }).from(usersMySchemaTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('mySchema :: select distinct', async (ctx) => { + const { db } = ctx.singlestore; + + const usersDistinctTable = singlestoreTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${usersDistinctTable}`); + await db.execute(sql`create table ${usersDistinctTable} (id int, name text)`); + + await db.insert(usersDistinctTable).values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]); + const users = await db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ); + + await db.execute(sql`drop table ${usersDistinctTable}`); + + expect(users).toEqual([{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); + }); + + test('mySchema :: insert returning sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + const [result, _] = await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); + }); + + test('mySchema :: delete returning sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const users = await db.delete(usersMySchemaTable).where(eq(usersMySchemaTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); + }); + + test('mySchema :: update with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersMySchemaTable).set({ name: 'Jane' }).where( + eq(usersMySchemaTable.name, 'John'), + ); + + const users = await db.select({ id: usersMySchemaTable.id, name: usersMySchemaTable.name }).from( + usersMySchemaTable, + ) + .where( + eq(usersMySchemaTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); + }); + + test('mySchema :: delete with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersMySchemaTable).where(eq(usersMySchemaTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); + }); + + test('mySchema :: insert + select', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersMySchemaTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersMySchemaTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersMySchemaTable).orderBy(asc(usersMySchemaTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); + }); + + test('mySchema :: insert with overridden default values', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersMySchemaTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('mySchema :: insert many', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersMySchemaTable.id, + name: usersMySchemaTable.name, + jsonb: usersMySchemaTable.jsonb, + verified: usersMySchemaTable.verified, + }).from(usersMySchemaTable) + .orderBy(asc(usersMySchemaTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); + }); + + test('mySchema :: select with group by as field', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { + id: 3, + name: 'Jane', + }]); + + const result = await db.select({ name: usersMySchemaTable.name }).from(usersMySchemaTable) + .groupBy(usersMySchemaTable.name) + .orderBy(asc(usersMySchemaTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); + }); + + test('mySchema :: select with group by as column + sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { + id: 3, + name: 'Jane', + }]); + + const result = await db.select({ name: usersMySchemaTable.name }).from(usersMySchemaTable) + .groupBy(usersMySchemaTable.id, sql`${usersMySchemaTable.name}`) + .orderBy(asc(usersMySchemaTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + }); + + test('mySchema :: build query', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ id: usersMySchemaTable.id, name: usersMySchemaTable.name }).from(usersMySchemaTable) + .groupBy(usersMySchemaTable.id, usersMySchemaTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: + `select \`id\`, \`name\` from \`mySchema\`.\`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + params: [], + }); + }); + + test('mySchema :: insert with spaces', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersMySchemaTable.id, name: usersMySchemaTable.name }).from( + usersMySchemaTable, + ); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); + }); + + test('mySchema :: prepared statement with placeholder in .where', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersMySchemaTable.id, + name: usersMySchemaTable.name, + }).from(usersMySchemaTable) + .where(eq(usersMySchemaTable.id, sql.placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('mySchema :: select from tables with same name from different schema using alias', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.execute(sql`drop table if exists \`userstest\``); + await db.execute( + sql` + create table \`userstest\` ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.insert(usersMySchemaTable).values({ id: 10, name: 'Ivan' }); + await db.insert(usersTable).values({ id: 11, name: 'Hans' }); + + const customerAlias = alias(usersTable, 'customer'); + + const result = await db + .select().from(usersMySchemaTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersMySchemaTable.id, 10)); + + expect(result).toEqual([{ + userstest: { + id: 10, + name: 'Ivan', + verified: false, + jsonb: null, + createdAt: result[0]!.userstest.createdAt, + }, + customer: { + id: 11, + name: 'Hans', + verified: false, + jsonb: null, + createdAt: result[0]!.customer!.createdAt, + }, + }]); + }); + + test('insert $returningId: serial as id', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values({ id: 1, name: 'John' }).$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + id: number; + }[]>(); + + expect(result).toStrictEqual([{ id: 1 }]); + }); + + test('insert $returningId: serial as id, batch insert', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'John1' }]) + .$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + id: number; + }[]>(); + + // singlestore auto increments when batch inserting, so the ids increment by one + expect(result).toStrictEqual([{ id: 2 }, { id: 3 }]); + }); + + test('insert $returningId: $default as primary key', async (ctx) => { + const { db } = ctx.singlestore; + + const uniqueKeys = ['ao865jf3mcmkfkk8o5ri495z', 'dyqs529eom0iczo2efxzbcut']; + let iterator = 0; + + const usersTableDefFn = singlestoreTable('users_default_fn', { + customId: varchar('id', { length: 256 }).primaryKey().$defaultFn(() => { + const value = uniqueKeys[iterator]!; + iterator++; + return value; + }), + name: text('name').notNull(), + }); + + await setupReturningFunctionsTest(db); + + const result = await db.insert(usersTableDefFn).values([{ name: 'John' }, { name: 'John1' }]) + // ^? + .$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + customId: string; + }[]>(); + + expect(result).toStrictEqual([{ customId: 'ao865jf3mcmkfkk8o5ri495z' }, { + customId: 'dyqs529eom0iczo2efxzbcut', + }]); + }); + + test('insert $returningId: $default as primary key with value', async (ctx) => { + const { db } = ctx.singlestore; + + const uniqueKeys = ['ao865jf3mcmkfkk8o5ri495z', 'dyqs529eom0iczo2efxzbcut']; + let iterator = 0; + + const usersTableDefFn = singlestoreTable('users_default_fn', { + customId: varchar('id', { length: 256 }).primaryKey().$defaultFn(() => { + const value = uniqueKeys[iterator]!; + iterator++; + return value; + }), + name: text('name').notNull(), + }); + + await setupReturningFunctionsTest(db); + + const result = await db.insert(usersTableDefFn).values([{ name: 'John', customId: 'test' }, { name: 'John1' }]) + // ^? + .$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + customId: string; + }[]>(); + + expect(result).toStrictEqual([{ customId: 'test' }, { customId: 'ao865jf3mcmkfkk8o5ri495z' }]); + }); + + test('mySchema :: view', async (ctx) => { + const { db } = ctx.singlestore; + + const newYorkers1 = mySchema.view('new_yorkers') + .as((qb) => qb.select().from(users2MySchemaTable).where(eq(users2MySchemaTable.cityId, 1))); + + const newYorkers2 = mySchema.view('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).as(sql`select * from ${users2MySchemaTable} where ${eq(users2MySchemaTable.cityId, 1)}`); + + const newYorkers3 = mySchema.view('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).existing(); + + await db.execute(sql`create view ${newYorkers1} as ${getViewConfig(newYorkers1).query}`); + + await db.insert(citiesMySchemaTable).values([{ id: 1, name: 'New York' }, { id: 2, name: 'Paris' }]); + + await db.insert(users2MySchemaTable).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2).orderBy(asc(newYorkers2.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3).orderBy(asc(newYorkers3.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop view ${newYorkers1}`); + }); + + test('limit 0', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .select() + .from(usersTable) + .limit(0); + + expect(users).toEqual([]); + }); + + test('limit -1', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .select() + .from(usersTable) + .limit(-1); + + expect(users.length).toBeGreaterThan(0); + }); + }); +} diff --git a/integration-tests/tests/singlestore/singlestore-custom.test.ts b/integration-tests/tests/singlestore/singlestore-custom.test.ts new file mode 100644 index 000000000..b05cd756b --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-custom.test.ts @@ -0,0 +1,827 @@ +import retry from 'async-retry'; +import type Docker from 'dockerode'; +import { asc, eq, Name, placeholder, sql } from 'drizzle-orm'; +import type { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +import { drizzle } from 'drizzle-orm/singlestore'; +import { + alias, + binary, + customType, + date, + datetime, + serial, + singlestoreEnum, + singlestoreTable, + singlestoreTableCreator, + text, + time, + varchar, + year, +} from 'drizzle-orm/singlestore-core'; +import { migrate } from 'drizzle-orm/singlestore/migrator'; +import * as mysql2 from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { toLocalDate } from '~/utils'; +import { createDockerDB } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +let db: SingleStoreDriverDatabase; +let client: mysql2.Connection; +let container: Docker.Container | undefined; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr, container: contrainerObj } = await createDockerDB(); + connectionString = conStr; + container = contrainerObj; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); + await container?.stop().catch(console.error); +}); + +beforeEach((ctx) => { + ctx.singlestore = { + db, + }; +}); + +const customSerial = customType<{ data: number; notNull: true; default: true }>({ + dataType() { + return 'serial'; + }, +}); + +const customText = customType<{ data: string }>({ + dataType() { + return 'text'; + }, +}); + +const customBoolean = customType<{ data: boolean }>({ + dataType() { + return 'boolean'; + }, + fromDriver(value) { + if (typeof value === 'boolean') { + return value; + } + return value === 1; + }, +}); + +const customJson = (name: string) => + customType<{ data: TData; driverData: string }>({ + dataType() { + return 'json'; + }, + toDriver(value: TData): string { + return JSON.stringify(value); + }, + })(name); + +const customTimestamp = customType< + { data: Date; driverData: string; config: { fsp: number } } +>({ + dataType(config) { + const precision = config?.fsp === undefined ? '' : ` (${config.fsp})`; + return `timestamp${precision}`; + }, + fromDriver(value: string): Date { + return new Date(value); + }, +}); + +const customBinary = customType<{ data: string; driverData: Buffer; config: { length: number } }>({ + dataType(config) { + return config?.length === undefined + ? `binary` + : `binary(${config.length})`; + }, + + toDriver(value) { + return sql`UNHEX(${value})`; + }, + + fromDriver(value) { + return value.toString('hex'); + }, +}); + +const usersTable = singlestoreTable('userstest', { + id: customSerial('id').primaryKey(), + name: customText('name').notNull(), + verified: customBoolean('verified').notNull().default(false), + jsonb: customJson('jsonb'), + createdAt: customTimestamp('created_at', { fsp: 6 }).notNull().default(sql`now()`), +}); + +const datesTable = singlestoreTable('datestable', { + date: date('date'), + dateAsString: date('date_as_string', { mode: 'string' }), + time: time('time', { fsp: 1 }), + datetime: datetime('datetime', { fsp: 6 }), + datetimeAsString: datetime('datetime_as_string', { fsp: 6, mode: 'string' }), + year: year('year'), +}); + +export const testTable = singlestoreTable('test_table', { + id: customBinary('id', { length: 16 }).primaryKey(), + sqlId: binary('sql_id', { length: 16 }), + rawId: varchar('raw_id', { length: 64 }), +}); + +const usersMigratorTable = singlestoreTable('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}); + +beforeEach(async () => { + await db.execute(sql`drop table if exists \`userstest\``); + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute(sql`drop table if exists \`test_table\``); + // await ctx.db.execute(sql`create schema public`); + await db.execute( + sql` + create table \`userstest\` ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table \`datestable\` ( + \`date\` date, + \`date_as_string\` date, + \`time\` time, + \`datetime\` datetime, + \`datetime_as_string\` datetime, + \`year\` year + ) + `, + ); + + await db.execute( + sql` + create table \`test_table\` ( + \`id\` binary(16) primary key, + \`sql_id\` binary(16), + \`raw_id\` varchar(64) + ) + `, + ); +}); + +test('select all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('select sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('select typed sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('insert returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + const [result, _] = await db.insert(usersTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); +}); + +test('delete returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); +}); + +test('update returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + expect(users[0].changedRows).toBe(1); +}); + +test('update with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select().from(usersTable).where(eq(usersTable.id, 1)); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 2000); + expect(users).toEqual([{ id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); +}); + +test('update with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); +}); + +test('delete with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('delete with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('insert + select', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); +}); + +test('json insert', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); +}); + +test('insert with overridden default values', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('insert many', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }).from(usersTable).orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); +}); + +test('insert many with returning', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + + expect(result[0].affectedRows).toBe(4); +}); + +test('select with group by as field', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.name).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql + column', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by as column + sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by complex query', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + expect(result).toEqual([{ name: 'Jane' }]); +}); + +test('build query', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: `select \`id\`, \`name\` from \`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + params: [], + }); +}); + +test('build query insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }) + .toSQL(); + + expect(query).toEqual({ + sql: + 'insert into `userstest` (`id`, `name`, `verified`, `jsonb`, `created_at`) values (default, ?, default, ?, default) on duplicate key update `name` = ?', + params: ['John', '["foo","bar"]', 'John1'], + }); +}); + +test('insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John1' }]); +}); + +test('insert conflict', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await expect((async () => { + db.insert(usersTable).values({ id: 1, name: 'John1' }); + })()).resolves.not.toThrowError(); +}); + +test('insert conflict with ignore', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .ignore() + .values({ id: 1, name: 'John1' }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`${'John'}` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('partial join with alias', async (ctx) => { + const { db } = ctx.singlestore; + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }).from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }]); +}); + +test('full join with alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select().from(users) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(users.id, 10)) + .orderBy(asc(users.id)); + + expect(result).toEqual([{ + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('select from alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(user) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(user.id, 10)) + .orderBy(asc(user.id)); + + expect(result).toEqual([{ + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('insert with spaces', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); +}); + +test('prepared statement', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const statement = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .prepare(); + const result = await statement.execute(); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('prepared statement reuse', async (ctx) => { + const { db } = ctx.singlestore; + + const stmt = db.insert(usersTable).values({ + id: placeholder('id'), + verified: true, + name: placeholder('name'), + }).prepare(); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ id: i + 1, name: `John ${i}` }); + } + + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }).from(usersTable).orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); +}); + +test('prepared statement with placeholder in .where', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .where(eq(usersTable.id, placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('migrator', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists cities_migration`); + await db.execute(sql`drop table if exists users_migration`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists __drizzle_migrations`); + + await migrate(db, { migrationsFolder: './drizzle2/singlestore' }); + + await db.insert(usersMigratorTable).values({ id: 1, name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table cities_migration`); + await db.execute(sql`drop table users_migration`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table __drizzle_migrations`); +}); + +test('insert via db.execute + select via db.execute', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute( + sql`insert into ${usersTable} (${new Name(usersTable.id.name)}, ${new Name( + usersTable.name.name, + )}) values (1,${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>(sql`select id, name from ${usersTable}`); + expect(result[0]).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert via db.execute w/ query builder', async (ctx) => { + const { db } = ctx.singlestore; + + const inserted = await db.execute( + db.insert(usersTable).values({ name: 'John' }), + ); + expect(inserted[0].affectedRows).toBe(1); +}); + +test('insert + select all possible dates', async (ctx) => { + const { db } = ctx.singlestore; + + const date = new Date('2022-11-11'); + + await db.insert(datesTable).values({ + date: date, + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: date, + year: 22, + datetimeAsString: '2022-11-11 12:12:12', + }); + + const res = await db.select().from(datesTable); + + expect(res[0]?.date).toBeInstanceOf(Date); + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(res[0]?.dateAsString).toBeTypeOf('string'); + expect(res[0]?.datetimeAsString).toBeTypeOf('string'); + + expect(res).toEqual([{ + date: toLocalDate(new Date('2022-11-11')), + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: new Date('2022-11-11'), + year: 2022, + datetimeAsString: '2022-11-11 12:12:12', + }]); +}); + +const tableWithEnums = singlestoreTable('enums_test_case', { + id: serial('id').primaryKey(), + enum1: singlestoreEnum('enum1', ['a', 'b', 'c']).notNull(), + enum2: singlestoreEnum('enum2', ['a', 'b', 'c']).default('a'), + enum3: singlestoreEnum('enum3', ['a', 'b', 'c']).notNull().default('b'), +}); + +test('SingleStore enum test case #1', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`enums_test_case\``); + + await db.execute(sql` + create table \`enums_test_case\` ( + \`id\` serial primary key, + \`enum1\` ENUM('a', 'b', 'c') not null, + \`enum2\` ENUM('a', 'b', 'c') default 'a', + \`enum3\` ENUM('a', 'b', 'c') not null default 'b' + ) + `); + + await db.insert(tableWithEnums).values([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum3: 'c' }, + { id: 3, enum1: 'a' }, + ]); + + const res = await db.select().from(tableWithEnums).orderBy(asc(tableWithEnums.id)); + + await db.execute(sql`drop table \`enums_test_case\``); + + expect(res).toEqual([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum2: 'a', enum3: 'c' }, + { id: 3, enum1: 'a', enum2: 'a', enum3: 'b' }, + ]); +}); + +test('custom binary', async (ctx) => { + const { db } = ctx.singlestore; + + const id = uuid().replace(/-/g, ''); + await db.insert(testTable).values({ + id, + sqlId: sql`UNHEX(${id})`, + rawId: id, + }); + + const res = await db.select().from(testTable); + + expect(res).toEqual([{ + id, + sqlId: Buffer.from(id, 'hex'), + rawId: id, + }]); +}); diff --git a/integration-tests/tests/singlestore/singlestore-prefixed.test.ts b/integration-tests/tests/singlestore/singlestore-prefixed.test.ts new file mode 100644 index 000000000..224ad433d --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-prefixed.test.ts @@ -0,0 +1,1572 @@ +import retry from 'async-retry'; +import type Docker from 'dockerode'; +import type { Equal } from 'drizzle-orm'; +import { asc, eq, getTableName, gt, inArray, Name, sql, TransactionRollbackError } from 'drizzle-orm'; +import type { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +import { drizzle } from 'drizzle-orm/singlestore'; +import { + alias, + boolean, + date, + datetime, + getViewConfig, + int, + json, + serial, + singlestoreEnum, + singlestoreTable as singlestoreTableRaw, + singlestoreTableCreator, + singlestoreView, + text, + time, + timestamp, + uniqueIndex, + year, +} from 'drizzle-orm/singlestore-core'; +import { migrate } from 'drizzle-orm/singlestore/migrator'; +import * as mysql2 from 'mysql2/promise'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { Expect, toLocalDate } from '~/utils'; +import { createDockerDB } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +let db: SingleStoreDriverDatabase; +let client: mysql2.Connection; +let container: Docker.Container | undefined; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr, container: contrainerObj } = await createDockerDB(); + connectionString = conStr; + container = contrainerObj; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); + await container?.stop().catch(console.error); +}); + +const tablePrefix = 'drizzle_tests_'; + +const singlestoreTable = singlestoreTableCreator((name) => `${tablePrefix}${name}`); +const usersTable = singlestoreTable('userstest', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: json('jsonb').$type(), + createdAt: timestamp('created_at', { fsp: 6 }).notNull().defaultNow(), +}); + +const users2Table = singlestoreTable('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id'), +}); + +const citiesTable = singlestoreTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +beforeEach(async () => { + await db.execute(sql`drop table if exists ${usersTable}`); + await db.execute(sql`drop table if exists ${users2Table}`); + await db.execute(sql`drop table if exists ${citiesTable}`); + + await db.execute( + sql` + create table ${usersTable} ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table ${users2Table} ( + \`id\` serial primary key, + \`name\` text not null, + \`city_id\` int + ) + `, + ); + + await db.execute( + sql` + create table ${citiesTable} ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); +}); + +test('select all fields', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('select sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('select typed sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('select distinct', async () => { + const usersDistinctTable = singlestoreTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${usersDistinctTable}`); + await db.execute(sql`create table ${usersDistinctTable} (id int, name text)`); + + await db.insert(usersDistinctTable).values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]); + const users = await db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ); + + await db.execute(sql`drop table ${usersDistinctTable}`); + + expect(users).toEqual([{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); +}); + +test('insert returning sql', async () => { + const [result, _] = await db.insert(usersTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); +}); + +test('delete returning sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); +}); + +test('update returning sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + expect(users[0].changedRows).toBe(1); +}); + +test('update with returning all fields', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select().from(usersTable).where(eq(usersTable.id, 1)); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 2000); + expect(users).toEqual([{ id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); +}); + +test('update with returning partial', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); +}); + +test('delete with returning all fields', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('delete with returning partial', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('insert + select', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); +}); + +test('json insert', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); +}); + +test('insert with overridden default values', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('insert many', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); +}); + +test('insert many with returning', async () => { + const result = await db.insert(usersTable).values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + + expect(result[0].affectedRows).toBe(4); +}); + +test('select with group by as field', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.name) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql + column', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by as column + sql', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by complex query', async () => { + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + expect(result).toEqual([{ name: 'Jane' }]); +}); + +test('build query', async () => { + const query = db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: `select \`id\`, \`name\` from \`${getTableName(usersTable)}\` group by \`${ + getTableName(usersTable) + }\`.\`id\`, \`${getTableName(usersTable)}\`.\`name\``, + params: [], + }); +}); + +test('build query insert with onDuplicate', async () => { + const query = db.insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }) + .toSQL(); + + expect(query).toEqual({ + sql: `insert into \`${ + getTableName(usersTable) + }\` (\`id\`, \`name\`, \`verified\`, \`jsonb\`, \`created_at\`) values (default, ?, default, ?, default) on duplicate key update \`name\` = ?`, + params: ['John', '["foo","bar"]', 'John1'], + }); +}); + +test('insert with onDuplicate', async () => { + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John1' }]); +}); + +test('insert conflict', async () => { + await db.insert(usersTable) + .values({ name: 'John' }); + + await expect((async () => { + db.insert(usersTable).values({ id: 1, name: 'John1' }); + })()).resolves.not.toThrowError(); +}); + +test('insert conflict with ignore', async () => { + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .ignore() + .values({ id: 1, name: 'John1' }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert sql', async () => { + await db.insert(usersTable).values({ id: 1, name: sql`${'John'}` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('partial join with alias', async () => { + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }).from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }]); +}); + +test('full join with alias', async () => { + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select().from(users) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(users.id, 10)) + .orderBy(asc(users.id)); + + expect(result).toEqual([{ + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('select from alias', async () => { + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(user) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(user.id, 10)) + .orderBy(asc(user.id)); + + expect(result).toEqual([{ + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('insert with spaces', async () => { + await db.insert(usersTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); +}); + +test('prepared statement', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const statement = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .prepare(); + const result = await statement.execute(); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('prepared statement reuse', async () => { + const stmt = db.insert(usersTable).values({ + verified: true, + id: sql.placeholder('id'), + name: sql.placeholder('name'), + }).prepare(); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ id: i + 1, name: `John ${i}` }); + } + + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); +}); + +test('prepared statement with placeholder in .where', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('migrator', async () => { + const usersMigratorTable = singlestoreTableRaw('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), + }, (table) => { + return { + name: uniqueIndex('').on(table.name).using('btree'), + }; + }); + + await db.execute(sql.raw(`drop table if exists cities_migration`)); + await db.execute(sql.raw(`drop table if exists users_migration`)); + await db.execute(sql.raw(`drop table if exists users12`)); + await db.execute(sql.raw(`drop table if exists __drizzle_migrations`)); + + await migrate(db, { migrationsFolder: './drizzle2/singlestore' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql.raw(`drop table cities_migration`)); + await db.execute(sql.raw(`drop table users_migration`)); + await db.execute(sql.raw(`drop table users12`)); + await db.execute(sql.raw(`drop table __drizzle_migrations`)); +}); + +test('insert via db.execute + select via db.execute', async () => { + await db.execute( + sql`insert into ${usersTable} (${new Name(usersTable.id.name)}, ${new Name( + usersTable.name.name, + )}) values (1, ${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>(sql`select id, name from ${usersTable}`); + expect(result[0]).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert via db.execute w/ query builder', async () => { + const inserted = await db.execute( + db.insert(usersTable).values({ name: 'John' }), + ); + expect(inserted[0].affectedRows).toBe(1); +}); + +test('insert + select all possible dates', async () => { + const datesTable = singlestoreTable('datestable', { + date: date('date'), + dateAsString: date('date_as_string', { mode: 'string' }), + time: time('time', { fsp: 1 }), + datetime: datetime('datetime', { fsp: 6 }), + datetimeAsString: datetime('datetime_as_string', { fsp: 6, mode: 'string' }), + year: year('year'), + }); + + await db.execute(sql`drop table if exists ${datesTable}`); + await db.execute( + sql` + create table ${datesTable} ( + \`date\` date, + \`date_as_string\` date, + \`time\` time, + \`datetime\` datetime, + \`datetime_as_string\` datetime, + \`year\` year + ) + `, + ); + + const d = new Date('2022-11-11'); + + await db.insert(datesTable).values({ + date: d, + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: d, + year: 22, + datetimeAsString: '2022-11-11 12:12:12', + }); + + const res = await db.select().from(datesTable); + + expect(res[0]?.date).toBeInstanceOf(Date); + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(typeof res[0]?.dateAsString).toBe('string'); + expect(typeof res[0]?.datetimeAsString).toBe('string'); + + expect(res).toEqual([{ + date: toLocalDate(new Date('2022-11-11')), + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: new Date('2022-11-11'), + year: 2022, + datetimeAsString: '2022-11-11 12:12:12', + }]); + + await db.execute(sql`drop table ${datesTable}`); +}); + +test('SingleStore enum test case #1', async () => { + const tableWithEnums = singlestoreTable('enums_test_case', { + id: serial('id').primaryKey(), + enum1: singlestoreEnum('enum1', ['a', 'b', 'c']).notNull(), + enum2: singlestoreEnum('enum2', ['a', 'b', 'c']).default('a'), + enum3: singlestoreEnum('enum3', ['a', 'b', 'c']).notNull().default('b'), + }); + + await db.execute(sql`drop table if exists ${tableWithEnums}`); + + await db.execute(sql` + create table ${tableWithEnums} ( + \`id\` serial primary key, + \`enum1\` ENUM('a', 'b', 'c') not null, + \`enum2\` ENUM('a', 'b', 'c') default 'a', + \`enum3\` ENUM('a', 'b', 'c') not null default 'b' + ) + `); + + await db.insert(tableWithEnums).values([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum3: 'c' }, + { id: 3, enum1: 'a' }, + ]); + + const res = await db.select().from(tableWithEnums).orderBy(asc(tableWithEnums.id)); + + await db.execute(sql`drop table ${tableWithEnums}`); + + expect(res).toEqual([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum2: 'a', enum3: 'c' }, + { id: 3, enum1: 'a', enum2: 'a', enum3: 'b' }, + ]); +}); + +test('left join (flat object fields)', async () => { + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + userId: users2Table.id, + userName: users2Table.name, + cityId: citiesTable.id, + cityName: citiesTable.name, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { userId: 1, userName: 'John', cityId: 1, cityName: 'Paris' }, + { userId: 2, userName: 'Jane', cityId: null, cityName: null }, + ]); +}); + +test('left join (grouped fields)', async () => { + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + id: users2Table.id, + user: { + name: users2Table.name, + nameUpper: sql`upper(${users2Table.name})`, + }, + city: { + id: citiesTable.id, + name: citiesTable.name, + nameUpper: sql`upper(${citiesTable.name})`, + }, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + id: 1, + user: { name: 'John', nameUpper: 'JOHN' }, + city: { id: 1, name: 'Paris', nameUpper: 'PARIS' }, + }, + { + id: 2, + user: { name: 'Jane', nameUpper: 'JANE' }, + city: null, + }, + ]); +}); + +test('left join (all fields)', async () => { + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select().from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + users2: { + id: 1, + name: 'John', + cityId: 1, + }, + cities: { + id: 1, + name: 'Paris', + }, + }, + { + users2: { + id: 2, + name: 'Jane', + cityId: null, + }, + cities: null, + }, + ]); +}); + +test('join subquery', async () => { + const coursesTable = singlestoreTable('courses', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + categoryId: int('category_id'), + }); + + const courseCategoriesTable = singlestoreTable('course_categories', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${coursesTable}`); + await db.execute(sql`drop table if exists ${courseCategoriesTable}`); + + await db.execute( + sql` + create table ${courseCategoriesTable} ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.execute( + sql` + create table ${coursesTable} ( + \`id\` serial primary key, + \`name\` text not null, + \`category_id\` int + ) + `, + ); + + await db.insert(courseCategoriesTable).values([ + { id: 1, name: 'Category 1' }, + { id: 2, name: 'Category 2' }, + { id: 3, name: 'Category 3' }, + { id: 4, name: 'Category 4' }, + ]); + + await db.insert(coursesTable).values([ + { id: 1, name: 'Development', categoryId: 2 }, + { id: 2, name: 'IT & Software', categoryId: 3 }, + { id: 3, name: 'Marketing', categoryId: 4 }, + { id: 4, name: 'Design', categoryId: 1 }, + ]); + + const sq2 = db + .select({ + categoryId: courseCategoriesTable.id, + category: courseCategoriesTable.name, + total: sql`count(${courseCategoriesTable.id})`, + }) + .from(courseCategoriesTable) + .groupBy(courseCategoriesTable.id, courseCategoriesTable.name) + .orderBy(courseCategoriesTable.id) + .as('sq2'); + + const res = await db + .select({ + courseName: coursesTable.name, + categoryId: sq2.categoryId, + }) + .from(coursesTable) + .leftJoin(sq2, eq(coursesTable.categoryId, sq2.categoryId)) + .orderBy(coursesTable.name); + + await db.execute(sql`drop table ${coursesTable}`); + await db.execute(sql`drop table ${courseCategoriesTable}`); + + expect(res).toEqual([ + { courseName: 'Design', categoryId: 1 }, + { courseName: 'Development', categoryId: 2 }, + { courseName: 'IT & Software', categoryId: 3 }, + { courseName: 'Marketing', categoryId: 4 }, + ]); +}); + +test('with ... select', async () => { + const orders = singlestoreTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull(), + amount: int('amount').notNull(), + quantity: int('quantity').notNull(), + }); + + await db.execute(sql`drop table if exists ${orders}`); + await db.execute( + sql` + create table ${orders} ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: regionalSales.region, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`cast(sum(${orders.quantity}) as unsigned)`, + productSales: sql`cast(sum(${orders.amount}) as unsigned)`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))) + .groupBy(orders.region, orders.product) + .orderBy(orders.region, orders.product); + + await db.execute(sql`drop table ${orders}`); + + expect(result).toEqual([ + { + region: 'Europe', + product: 'A', + productUnits: 3, + productSales: 30, + }, + { + region: 'Europe', + product: 'B', + productUnits: 5, + productSales: 50, + }, + { + region: 'US', + product: 'A', + productUnits: 7, + productSales: 70, + }, + { + region: 'US', + product: 'B', + productUnits: 9, + productSales: 90, + }, + ]); +}); + +test('select from subquery sql', async () => { + await db.insert(users2Table).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]); + + const sq = db + .select({ name: sql`concat(${users2Table.name}, " modified")`.as('name') }) + .from(users2Table) + .orderBy(asc(users2Table.id)) + .as('sq'); + + const res = await db.select({ name: sq.name }).from(sq); + + expect(res).toEqual([{ name: 'John modified' }, { name: 'Jane modified' }]); +}); + +test('select a field without joining its table', () => { + expect(() => db.select({ name: users2Table.name }).from(usersTable).prepare()).toThrowError(); +}); + +test('select all fields from subquery without alias', () => { + const sq = db.$with('sq').as(db.select({ name: sql`upper(${users2Table.name})` }).from(users2Table)); + + expect(() => db.select().from(sq).prepare()).toThrowError(); +}); + +test('select count()', async () => { + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }]); + + const res = await db.select({ count: sql`count(*)` }).from(usersTable); + + expect(res).toEqual([{ count: 2 }]); +}); + +test('select for ...', () => { + { + const query = db.select().from(users2Table).for('update').toSQL(); + expect(query.sql).toMatch(/ for update$/); + } + { + const query = db.select().from(users2Table).for('share', { skipLocked: true }).toSQL(); + expect(query.sql).toMatch(/ for share skip locked$/); + } + { + const query = db.select().from(users2Table).for('update', { noWait: true }).toSQL(); + expect(query.sql).toMatch(/ for update no wait$/); + } +}); + +test('having', async () => { + await db.insert(citiesTable).values([{ id: 1, name: 'London' }, { id: 2, name: 'Paris' }, { + id: 3, + name: 'New York', + }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane', cityId: 1 }, { + id: 3, + name: 'Jack', + cityId: 2, + }]); + + const result = await db + .select({ + id: citiesTable.id, + name: sql`upper(${citiesTable.name})`.as('upper_name'), + usersCount: sql`count(${users2Table.id})`.as('users_count'), + }) + .from(citiesTable) + .leftJoin(users2Table, eq(users2Table.cityId, citiesTable.id)) + .where(({ name }) => sql`length(${name}) >= 3`) + .groupBy(citiesTable.id) + .having(({ usersCount }) => sql`${usersCount} > 0`) + .orderBy(({ name }) => name); + + expect(result).toEqual([ + { + id: 1, + name: 'LONDON', + usersCount: 2, + }, + { + id: 2, + name: 'PARIS', + usersCount: 1, + }, + ]); +}); + +test('view', async () => { + const newYorkers1 = singlestoreView('new_yorkers') + .as((qb) => qb.select().from(users2Table).where(eq(users2Table.cityId, 1))); + + const newYorkers2 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).as(sql`select * from ${users2Table} where ${eq(users2Table.cityId, 1)}`); + + const newYorkers3 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).existing(); + + await db.execute(sql`create view new_yorkers as ${getViewConfig(newYorkers1).query}`); + + await db.insert(citiesTable).values([{ name: 'New York' }, { name: 'Paris' }]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2).orderBy(asc(newYorkers2.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3).orderBy(asc(newYorkers3.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop view ${newYorkers1}`); +}); + +test('select from raw sql', async () => { + const result = await db.select({ + id: sql`id`, + name: sql`name`, + }).from(sql`(select 1 as id, 'John' as name) as users`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John' }, + ]); +}); + +test('select from raw sql with joins', async () => { + const result = await db + .select({ + id: sql`users.id`, + name: sql`users.name`, + userCity: sql`users.city`, + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, sql`cities.id = users.id`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John', userCity: 'New York', cityName: 'Paris' }, + ]); +}); + +test('join on aliased sql from select', async () => { + const result = await db + .select({ + userId: sql`users.id`.as('userId'), + name: sql`users.name`, + userCity: sql`users.city`, + cityId: sql`cities.id`.as('cityId'), + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, (cols) => eq(cols.cityId, cols.userId)); + + Expect>; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); +}); + +test('join on aliased sql from with clause', async () => { + const users = db.$with('users').as( + db.select({ + id: sql`id`.as('userId'), + name: sql`name`.as('userName'), + city: sql`city`.as('city'), + }).from( + sql`(select 1 as id, 'John' as name, 'New York' as city) as users`, + ), + ); + + const cities = db.$with('cities').as( + db.select({ + id: sql`id`.as('cityId'), + name: sql`name`.as('cityName'), + }).from( + sql`(select 1 as id, 'Paris' as name) as cities`, + ), + ); + + const result = await db + .with(users, cities) + .select({ + userId: users.id, + name: users.name, + userCity: users.city, + cityId: cities.id, + cityName: cities.name, + }) + .from(users) + .leftJoin(cities, (cols) => eq(cols.cityId, cols.userId)); + + Expect>; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); +}); + +test('prefixed table', async () => { + const singlestoreTable = singlestoreTableCreator((name) => `myprefix_${name}`); + + const users = singlestoreTable('test_prefixed_table_with_unique_name', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table myprefix_test_prefixed_table_with_unique_name (id int not null primary key, name text not null)`, + ); + + await db.insert(users).values({ id: 1, name: 'John' }); + + const result = await db.select().from(users); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('orderBy with aliased column', () => { + const query = db.select({ + test: sql`something`.as('test'), + }).from(users2Table).orderBy((fields) => fields.test).toSQL(); + + expect(query.sql).toBe(`select something as \`test\` from \`${getTableName(users2Table)}\` order by \`test\``); +}); + +test('timestamp timezone', async () => { + const date = new Date(Date.parse('2020-01-01T12:34:56+07:00')); + + await db.insert(usersTable).values({ id: 1, name: 'With default times' }); + await db.insert(usersTable).values({ + id: 2, + name: 'Without default times', + createdAt: date, + }); + const users = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + + // check that the timestamps are set correctly for default times + expect(Math.abs(users[0]!.createdAt.getTime() - Date.now())).toBeLessThan(2000); + + // check that the timestamps are set correctly for non default times + expect(Math.abs(users[1]!.createdAt.getTime() - date.getTime())).toBeLessThan(2000); +}); + +test('transaction', async () => { + const users = singlestoreTable('users_transactions', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + const products = singlestoreTable('products_transactions', { + id: serial('id').primaryKey(), + price: int('price').notNull(), + stock: int('stock').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop table if exists ${products}`); + + await db.execute(sql`create table ${users} (id serial not null primary key, balance int not null)`); + await db.execute( + sql`create table ${products} (id serial not null primary key, price int not null, stock int not null)`, + ); + + const [{ insertId: userId }] = await db.insert(users).values({ id: 1, balance: 100 }); + const user = await db.select().from(users).where(eq(users.id, userId)).then((rows) => rows[0]!); + const [{ insertId: productId }] = await db.insert(products).values({ id: 1, price: 10, stock: 10 }); + const product = await db.select().from(products).where(eq(products.id, productId)).then((rows) => rows[0]!); + + await db.transaction(async (tx) => { + await tx.update(users).set({ balance: user.balance - product.price }).where(eq(users.id, user.id)); + await tx.update(products).set({ stock: product.stock - 1 }).where(eq(products.id, product.id)); + }); + + const result = await db.select().from(users); + + await db.execute(sql`drop table ${users}`); + await db.execute(sql`drop table ${products}`); + + expect(result).toEqual([{ id: 1, balance: 90 }]); +}); + +test('transaction rollback', async () => { + const users = singlestoreTable('users_transactions_rollback', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, balance int not null)`, + ); + + await expect((async () => { + await db.transaction(async (tx) => { + await tx.insert(users).values({ balance: 100 }); + tx.rollback(); + }); + })()).rejects.toThrowError(TransactionRollbackError); + + const result = await db.select().from(users); + + await db.execute(sql`drop table ${users}`); + + expect(result).toEqual([]); +}); + +test('join subquery with join', async () => { + const internalStaff = singlestoreTable('internal_staff', { + userId: int('user_id').notNull(), + }); + + const customUser = singlestoreTable('custom_user', { + id: int('id').notNull(), + }); + + const ticket = singlestoreTable('ticket', { + staffId: int('staff_id').notNull(), + }); + + await db.execute(sql`drop table if exists ${internalStaff}`); + await db.execute(sql`drop table if exists ${customUser}`); + await db.execute(sql`drop table if exists ${ticket}`); + + await db.execute(sql`create table ${internalStaff} (user_id integer not null)`); + await db.execute(sql`create table ${customUser} (id integer not null)`); + await db.execute(sql`create table ${ticket} (staff_id integer not null)`); + + await db.insert(internalStaff).values({ userId: 1 }); + await db.insert(customUser).values({ id: 1 }); + await db.insert(ticket).values({ staffId: 1 }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin(customUser, eq(internalStaff.userId, customUser.id)) + .as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + await db.execute(sql`drop table ${internalStaff}`); + await db.execute(sql`drop table ${customUser}`); + await db.execute(sql`drop table ${ticket}`); + + expect(mainQuery).toEqual([{ + ticket: { staffId: 1 }, + internal_staff: { + internal_staff: { userId: 1 }, + custom_user: { id: 1 }, + }, + }]); +}); + +test('subquery with view', async () => { + const users = singlestoreTable('users_subquery_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.$with('sq').as(db.select().from(newYorkers)); + const result = await db.with(sq).select().from(sq).orderBy(asc(sq.id)); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); + + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 1 }, + ]); +}); + +test('join view as subquery', async () => { + const users = singlestoreTable('users_join_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.select().from(newYorkers).as('new_yorkers_sq'); + + const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id)).orderBy(asc(users.id)); + + expect(result).toEqual([ + { + users_join_view: { id: 1, name: 'John', cityId: 1 }, + new_yorkers_sq: { id: 1, name: 'John', cityId: 1 }, + }, + { + users_join_view: { id: 2, name: 'Jane', cityId: 2 }, + new_yorkers_sq: null, + }, + { + users_join_view: { id: 3, name: 'Jack', cityId: 1 }, + new_yorkers_sq: { id: 3, name: 'Jack', cityId: 1 }, + }, + { + users_join_view: { id: 4, name: 'Jill', cityId: 2 }, + new_yorkers_sq: null, + }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); +}); + +test('select iterator', async () => { + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const iter = db.select().from(users) + .orderBy(asc(users.id)) + .iterator(); + + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); +}); + +test('select iterator w/ prepared statement', async () => { + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const prepared = db.select().from(users) + .orderBy(asc(users.id)) + .prepare(); + const iter = prepared.iterator(); + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); +}); + +test('insert undefined', async () => { + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.insert(users).values({ name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); +}); + +test('update undefined', async () => { + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.update(users).set({ name: undefined }); + })()).rejects.toThrowError(); + + await expect((async () => { + await db.update(users).set({ id: 1, name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); +}); diff --git a/integration-tests/tests/singlestore/singlestore-proxy.test.ts b/integration-tests/tests/singlestore/singlestore-proxy.test.ts new file mode 100644 index 000000000..51dc48a4a --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-proxy.test.ts @@ -0,0 +1,140 @@ +import retry from 'async-retry'; +import type { SingleStoreRemoteDatabase } from 'drizzle-orm/singlestore-proxy'; +import { drizzle as proxyDrizzle } from 'drizzle-orm/singlestore-proxy'; +import * as mysql2 from 'mysql2/promise'; +import { afterAll, beforeAll, beforeEach } from 'vitest'; +import { skipTests } from '~/common'; +import { createDockerDB, tests } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +// eslint-disable-next-line drizzle-internal/require-entity-kind +class ServerSimulator { + constructor(private db: mysql2.Connection) {} + + async query(sql: string, params: any[], method: 'all' | 'execute') { + if (method === 'all') { + try { + const result = await this.db.query({ + sql, + values: params, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + + return { data: result[0] as any }; + } catch (e: any) { + return { error: e }; + } + } else if (method === 'execute') { + try { + const result = await this.db.query({ + sql, + values: params, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + + return { data: result as any }; + } catch (e: any) { + return { error: e }; + } + } else { + return { error: 'Unknown method value' }; + } + } + + async migrations(queries: string[]) { + await this.db.query('START TRANSACTION'); + try { + for (const query of queries) { + await this.db.query(query); + } + await this.db.query('COMMIT'); + } catch (e) { + await this.db.query('ROLLBACK'); + throw e; + } + + return {}; + } +} + +let db: SingleStoreRemoteDatabase; +let client: mysql2.Connection; +let serverSimulator: ServerSimulator; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr } = await createDockerDB(); + connectionString = conStr; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + + serverSimulator = new ServerSimulator(client); + db = proxyDrizzle(async (sql, params, method) => { + try { + const response = await serverSimulator.query(sql, params, method); + + if (response.error !== undefined) { + throw response.error; + } + + return { rows: response.data }; + } catch (e: any) { + console.error('Error from singlestore proxy server:', e.message); + throw e; + } + }, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); +}); + +beforeEach((ctx) => { + ctx.singlestore = { + db, + }; +}); + +skipTests([ + 'select iterator w/ prepared statement', + 'select iterator', + 'nested transaction rollback', + 'nested transaction', + 'transaction rollback', + 'transaction', + 'transaction with options (set isolationLevel)', + 'migrator', +]); + +tests(); diff --git a/integration-tests/tests/singlestore/singlestore.test.ts b/integration-tests/tests/singlestore/singlestore.test.ts new file mode 100644 index 000000000..bfb1ee5b7 --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore.test.ts @@ -0,0 +1,51 @@ +import retry from 'async-retry'; +import { drizzle } from 'drizzle-orm/singlestore'; +import type { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +import * as mysql2 from 'mysql2/promise'; +import { afterAll, beforeAll, beforeEach } from 'vitest'; +import { createDockerDB, tests } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +let db: SingleStoreDriverDatabase; +let client: mysql2.Connection; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr } = await createDockerDB(); + connectionString = conStr; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); +}); + +beforeEach((ctx) => { + ctx.singlestore = { + db, + }; +}); + +tests(); diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 84ea9b1c8..3ec77a7ba 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -15,9 +15,13 @@ export default defineConfig({ 'tests/extensions/vectors/**/*', 'tests/version.test.ts', 'tests/pg/node-postgres.test.ts', +<<<<<<< HEAD 'tests/utils/is-config.test.ts', 'js-tests/driver-init/commonjs/*.test.cjs', 'js-tests/driver-init/module/*.test.mjs', +======= + 'tests/singlestore/**/*.test.ts', +>>>>>>> 78db5cf6 ([SingleStore] Add SingleStore connector (#32)) ], exclude: [ ...(process.env.SKIP_EXTERNAL_DB_TESTS diff --git a/package.json b/package.json index b0fda61c8..df2346c7e 100755 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "test": "turbo run test --color", "t": "pnpm test", "test:types": "turbo run test:types --color", - "lint": "concurrently -n eslint,dprint \"eslint --ext ts .\" \"dprint check --list-different\"" + "lint": "concurrently -n eslint,dprint \"eslint --ext ts .\" \"dprint check --list-different\"", + "lint:fix": "concurrently -n eslint,dprint \"eslint --ext ts --fix .\" \"dprint fmt\"" }, "devDependencies": { "@arethetypeswrong/cli": "^0.15.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 20ff6ca0f..61391c129 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22019,4 +22019,4 @@ snapshots: ps-tree: 1.2.0 webpod: 0.0.2 which: 3.0.1 - yaml: 2.4.2 + yaml: 2.4.2 \ No newline at end of file From b813ee5ab63ae612e04bde6b7df2742138a154e0 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 23 Oct 2024 18:05:19 +0100 Subject: [PATCH 260/492] rebase singlestore connector with last commit: https://github.com/drizzle-team/drizzle-orm/commit/526996bd2ea20d5b1a0d65e743b47e23329d441c --- drizzle-kit/package.json | 1 + drizzle-kit/src/api.ts | 9 +- drizzle-kit/src/cli/commands/migrate.ts | 37 ++++- drizzle-kit/src/cli/connections.ts | 10 +- drizzle-kit/src/jsonStatements.ts | 42 ++++- drizzle-kit/src/migrationPreparator.ts | 6 +- drizzle-kit/src/serializer/index.ts | 5 +- .../src/serializer/singlestoreSchema.ts | 54 ++++++ .../src/serializer/singlestoreSerializer.ts | 155 +++++++++++++++++- drizzle-kit/src/snapshotsDiffer.ts | 154 ++++++++++++++++- drizzle-kit/tests/push/singlestore.test.ts | 8 +- drizzle-kit/tests/schemaDiffer.ts | 11 +- drizzle-kit/vitest.config.ts | 4 + drizzle-orm/package.json | 1 + drizzle-orm/src/column-builder.ts | 8 +- .../src/singlestore-core/columns/common.ts | 2 +- .../singlestore-core/query-builders/index.ts | 1 - drizzle-orm/src/singlestore-core/table.ts | 6 +- .../src/singlestore-core/unique-constraint.ts | 5 +- integration-tests/vitest.config.ts | 5 +- pnpm-lock.yaml | 2 +- 21 files changed, 476 insertions(+), 50 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 7499a7ec1..625eb56b5 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -7,6 +7,7 @@ "orm", "pg", "mysql", + "singlestore", "postgresql", "postgres", "sqlite", diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index e843bb2f2..2986430c5 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -9,6 +9,7 @@ import { mySqlViewsResolver, schemasResolver, sequencesResolver, + singleStoreViewsResolver, sqliteViewsResolver, tablesResolver, viewsResolver, @@ -368,6 +369,7 @@ export const pushMySQLSchema = async ( export const generateSingleStoreDrizzleJson = async ( imports: Record, prevId?: string, + casing?: CasingType, ): Promise => { const { prepareFromExports } = await import('./serializer/singlestoreImports'); @@ -375,7 +377,7 @@ export const generateSingleStoreDrizzleJson = async ( const id = randomUUID(); - const snapshot = generateSingleStoreSnapshot(prepared.tables); + const snapshot = generateSingleStoreSnapshot(prepared.tables, prepared.views, casing); return { ...snapshot, @@ -401,8 +403,10 @@ export const generateSingleStoreMigration = async ( squashedCur, tablesResolver, columnsResolver, + singleStoreViewsResolver, validatedPrev, validatedCur, + 'push', ); return sqlStatements; @@ -423,7 +427,7 @@ export const pushSingleStoreSchema = async ( const { sql } = await import('drizzle-orm'); const db: DB = { - query: async (query: string, params?: any[]) => { + query: async (query: string) => { const res = await drizzleInstance.execute(sql.raw(query)); return res[0] as unknown as any[]; }, @@ -442,6 +446,7 @@ export const pushSingleStoreSchema = async ( squashedCur, tablesResolver, columnsResolver, + singleStoreViewsResolver, validatedPrev, validatedCur, 'push', diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 9411d95f2..b3ad1033a 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -13,7 +13,12 @@ import { import chalk from 'chalk'; import { render } from 'hanji'; import path, { join } from 'path'; -import { SingleStoreSchema, singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; +import { + SingleStoreSchema, + singlestoreSchema, + squashSingleStoreScheme, + ViewSquashed as SingleStoreViewSquashed, +} from 'src/serializer/singlestoreSchema'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme, ViewSquashed } from '../../serializer/mysqlSchema'; @@ -140,6 +145,28 @@ export const mySqlViewsResolver = async ( } }; +export const singleStoreViewsResolver = async ( + input: ResolverInput, +): Promise> => { + try { + const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict( + input.created, + input.deleted, + 'view', + ); + + return { + created: created, + deleted: deleted, + moved: moved, + renamed: renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; + export const sqliteViewsResolver = async ( input: ResolverInput, ): Promise> => { @@ -530,11 +557,13 @@ function singleStoreSchemaSuggestions( export const prepareSingleStorePush = async ( schemaPath: string | string[], snapshot: SingleStoreSchema, + casing: CasingType | undefined, ) => { try { const { prev, cur } = await prepareSingleStoreDbPushSnapshot( snapshot, schemaPath, + casing, ); const validatedPrev = singlestoreSchema.parse(prev); @@ -548,6 +577,7 @@ export const prepareSingleStorePush = async ( squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, 'push', @@ -563,6 +593,7 @@ export const prepareSingleStorePush = async ( export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; + const casing = config.casing; try { // TODO: remove @@ -572,6 +603,7 @@ export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { const { prev, cur, custom } = await prepareSingleStoreMigrationSnapshot( snapshots, schemaPath, + casing, ); const validatedPrev = singlestoreSchema.parse(prev); @@ -594,11 +626,12 @@ export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { const squashedPrev = squashSingleStoreScheme(validatedPrev); const squashedCur = squashSingleStoreScheme(validatedCur); - const { sqlStatements, statements, _meta } = await applySingleStoreSnapshotsDiff( + const { sqlStatements, _meta } = await applySingleStoreSnapshotsDiff( squashedPrev, squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, ); diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 5b90937d8..e1bea6589 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -58,7 +58,7 @@ export const preparePostgresDB = async ( ); const db = drizzle(rdsClient, config); - const migrateFn = async (config: string | MigrationConfig) => { + const migrateFn = async (config: MigrationConfig) => { return migrate(db, config); }; @@ -165,7 +165,7 @@ export const preparePostgresDB = async ( : new pg.default.Pool({ ...credentials, ssl, max: 1 }); const db = drizzle(client); - const migrateFn = async (config: string | MigrationConfig) => { + const migrateFn = async (config: MigrationConfig) => { return migrate(db, config); }; @@ -200,7 +200,7 @@ export const preparePostgresDB = async ( : postgres.default({ ...credentials, max: 1 }); const db = drizzle(client); - const migrateFn = async (config: string | MigrationConfig) => { + const migrateFn = async (config: MigrationConfig) => { return migrate(db, config); }; @@ -248,7 +248,7 @@ export const preparePostgresDB = async ( await client.connect(); const db = drizzle(client); - const migrateFn = async (config: string | MigrationConfig) => { + const migrateFn = async (config: MigrationConfig) => { return migrate(db, config); }; @@ -300,7 +300,7 @@ export const preparePostgresDB = async ( neonConfig.webSocketConstructor = ws; const db = drizzle(client); - const migrateFn = async (config: string | MigrationConfig) => { + const migrateFn = async (config: MigrationConfig) => { return migrate(db, config); }; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index bf4539397..99ae2a2d8 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -4,7 +4,12 @@ import { warning } from './cli/views'; import { CommonSquashedSchema } from './schemaValidator'; import { MySqlKitInternals, MySqlSchema, MySqlSquasher, View as MySqlView } from './serializer/mysqlSchema'; import { Index, MatViewWithOption, PgSchema, PgSquasher, View as PgView, ViewWithOption } from './serializer/pgSchema'; -import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; +import { + SingleStoreKitInternals, + SingleStoreSchema, + SingleStoreSquasher, + View as SingleStoreView, +} from './serializer/singlestoreSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, @@ -561,6 +566,11 @@ export type JsonCreateMySqlViewStatement = { replace: boolean; } & Omit; +export type JsonCreateSingleStoreViewStatement = { + type: 'singlestore_create_view'; + replace: boolean; +} & Omit; + export type JsonCreateSqliteViewStatement = { type: 'sqlite_create_view'; } & Omit; @@ -644,6 +654,10 @@ export type JsonAlterMySqlViewStatement = { type: 'alter_mysql_view'; } & Omit; +export type JsonAlterSingleStoreViewStatement = { + type: 'alter_singlestore_view'; +} & Omit; + export type JsonAlterViewStatement = | JsonAlterViewAlterSchemaStatement | JsonAlterViewAddWithOptionStatement @@ -716,6 +730,8 @@ export type JsonStatement = | JsonAlterViewStatement | JsonCreateMySqlViewStatement | JsonAlterMySqlViewStatement + | JsonCreateSingleStoreViewStatement + | JsonAlterSingleStoreViewStatement | JsonCreateSqliteViewStatement | JsonCreateCheckConstraint | JsonDeleteCheckConstraint @@ -3052,6 +3068,24 @@ export const prepareMySqlCreateViewJson = ( }; }; +export const prepareSingleStoreCreateViewJson = ( + name: string, + definition: string, + meta: string, + replace: boolean = false, +): JsonCreateSingleStoreViewStatement => { + const { algorithm, sqlSecurity, withCheckOption } = SingleStoreSquasher.unsquashView(meta); + return { + type: 'singlestore_create_view', + name: name, + definition: definition, + algorithm, + sqlSecurity, + withCheckOption, + replace, + }; +}; + export const prepareSqliteCreateViewJson = ( name: string, definition: string, @@ -3178,6 +3212,12 @@ export const prepareMySqlAlterView = ( return { type: 'alter_mysql_view', ...view }; }; +export const prepareSingleStoreAlterView = ( + view: Omit, +): JsonAlterSingleStoreViewStatement => { + return { type: 'alter_singlestore_view', ...view }; +}; + export const prepareAddCompositePrimaryKeySingleStore = ( tableName: string, pks: Record, diff --git a/drizzle-kit/src/migrationPreparator.ts b/drizzle-kit/src/migrationPreparator.ts index 262f4dcba..4e67e8174 100644 --- a/drizzle-kit/src/migrationPreparator.ts +++ b/drizzle-kit/src/migrationPreparator.ts @@ -26,8 +26,9 @@ export const prepareMySqlDbPushSnapshot = async ( export const prepareSingleStoreDbPushSnapshot = async ( prev: SingleStoreSchema, schemaPath: string | string[], + casing: CasingType | undefined, ): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema }> => { - const serialized = await serializeSingleStore(schemaPath); + const serialized = await serializeSingleStore(schemaPath, casing); const id = randomUUID(); const idPrev = prev.id; @@ -108,11 +109,12 @@ export const prepareMySqlMigrationSnapshot = async ( export const prepareSingleStoreMigrationSnapshot = async ( migrationFolders: string[], schemaPath: string | string[], + casing: CasingType | undefined, ): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema; custom: SingleStoreSchema }> => { const prevSnapshot = singlestoreSchema.parse( preparePrevSnapshot(migrationFolders, drySingleStore), ); - const serialized = await serializeSingleStore(schemaPath); + const serialized = await serializeSingleStore(schemaPath, casing); const id = randomUUID(); const idPrev = prevSnapshot.id; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index 44e86a8bf..4d728c047 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -88,6 +88,7 @@ export const serializeSQLite = async ( export const serializeSingleStore = async ( path: string | string[], + casing: CasingType | undefined, ): Promise => { const filenames = prepareFilenames(path); @@ -96,9 +97,9 @@ export const serializeSingleStore = async ( const { prepareFromSingleStoreImports } = await import('./singlestoreImports'); const { generateSingleStoreSnapshot } = await import('./singlestoreSerializer'); - const { tables } = await prepareFromSingleStoreImports(filenames); + const { tables, views } = await prepareFromSingleStoreImports(filenames); - return generateSingleStoreSnapshot(tables); + return generateSingleStoreSnapshot(tables, views, casing); }; export const prepareFilenames = (path: string | string[]) => { diff --git a/drizzle-kit/src/serializer/singlestoreSchema.ts b/drizzle-kit/src/serializer/singlestoreSchema.ts index a0bbae1bf..501ccfe40 100644 --- a/drizzle-kit/src/serializer/singlestoreSchema.ts +++ b/drizzle-kit/src/serializer/singlestoreSchema.ts @@ -43,6 +43,20 @@ const table = object({ uniqueConstraints: record(string(), uniqueConstraint).default({}), }).strict(); +const viewMeta = object({ + algorithm: enumType(['undefined', 'merge', 'temptable']), + sqlSecurity: enumType(['definer', 'invoker']), + withCheckOption: enumType(['local', 'cascaded']).optional(), +}).strict(); + +export const view = object({ + name: string(), + columns: record(string(), column), + definition: string().optional(), + isExisting: boolean(), +}).strict().merge(viewMeta); +type SquasherViewMeta = Omit, 'definer'>; + export const kitInternals = object({ tables: record( string(), @@ -76,6 +90,7 @@ export const schemaInternal = object({ version: literal('1'), dialect: dialect, tables: record(string(), table), + views: record(string(), view).default({}), _meta: object({ tables: record(string(), string()), columns: record(string(), string()), @@ -93,10 +108,17 @@ const tableSquashed = object({ uniqueConstraints: record(string(), string()).default({}), }).strict(); +const viewSquashed = view.omit({ + algorithm: true, + sqlSecurity: true, + withCheckOption: true, +}).extend({ meta: string() }); + export const schemaSquashed = object({ version: literal('1'), dialect: dialect, tables: record(string(), tableSquashed), + views: record(string(), viewSquashed), }).strict(); export type Dialect = TypeOf; @@ -109,6 +131,8 @@ export type SingleStoreSchemaSquashed = TypeOf; export type Index = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; +export type View = TypeOf; +export type ViewSquashed = TypeOf; export const SingleStoreSquasher = { squashIdx: (idx: Index) => { @@ -143,6 +167,19 @@ export const SingleStoreSquasher = { const [name, columns] = unq.split(';'); return { name, columns: columns.split(',') }; }, + squashView: (view: View): string => { + return `${view.algorithm};${view.sqlSecurity};${view.withCheckOption}`; + }, + unsquashView: (meta: string): SquasherViewMeta => { + const [algorithm, sqlSecurity, withCheckOption] = meta.split(';'); + const toReturn = { + algorithm: algorithm, + sqlSecurity: sqlSecurity, + withCheckOption: withCheckOption !== 'undefined' ? withCheckOption : undefined, + }; + + return viewMeta.parse(toReturn); + }, }; export const squashSingleStoreScheme = (json: SingleStoreSchema): SingleStoreSchemaSquashed => { @@ -175,10 +212,26 @@ export const squashSingleStoreScheme = (json: SingleStoreSchema): SingleStoreSch ]; }), ); + + const mappedViews = Object.fromEntries( + Object.entries(json.views).map(([key, value]) => { + const meta = SingleStoreSquasher.squashView(value); + + return [key, { + name: value.name, + isExisting: value.isExisting, + columns: value.columns, + definition: value.definition, + meta, + }]; + }), + ); + return { version: '1', dialect: json.dialect, tables: mappedTables, + views: mappedViews, }; }; @@ -195,6 +248,7 @@ export const drySingleStore = singlestoreSchema.parse({ prevId: '', tables: {}, schemas: {}, + views: {}, _meta: { schemas: {}, tables: {}, diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index d96004c8f..922296540 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -3,6 +3,7 @@ import { is, SQL } from 'drizzle-orm'; import { AnySingleStoreTable, getTableConfig, + getViewConfig, type PrimaryKey as PrimaryKeyORM, SingleStoreDialect, SingleStoreView, @@ -12,6 +13,8 @@ import { RowDataPacket } from 'mysql2/promise'; import { withStyle } from '../cli/validations/outputs'; import { IntrospectStage, IntrospectStatus } from '../cli/views'; +import { SingleStoreColumn } from 'drizzle-orm/singlestore-core/columns'; +import { CasingType } from 'src/cli/validations/common'; import type { DB } from '../utils'; import { sqlToStr } from '.'; import { @@ -22,8 +25,8 @@ import { SingleStoreSchemaInternal, Table, UniqueConstraint, + View, } from './singlestoreSchema'; -import { CasingType } from 'src/cli/validations/common'; const dialect = new SingleStoreDialect(); @@ -36,7 +39,9 @@ export const generateSingleStoreSnapshot = ( views: SingleStoreView[], casing: CasingType | undefined, ): SingleStoreSchemaInternal => { + const dialect = new SingleStoreDialect({ casing }); const result: Record = {}; + const resultViews: Record = {}; const internal: SingleStoreKitInternals = { tables: {}, indexes: {} }; for (const table of tables) { const { @@ -290,10 +295,120 @@ export const generateSingleStoreSnapshot = ( } } + for (const view of views) { + const { + isExisting, + name, + query, + schema, + selectedFields, + algorithm, + sqlSecurity, + withCheckOption, + } = getViewConfig(view); + + const columnsObject: Record = {}; + + const existingView = resultViews[name]; + if (typeof existingView !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated view name across ${ + chalk.underline.blue( + schema ?? 'public', + ) + } schema. Please rename your view`, + ) + }`, + ); + process.exit(1); + } + for (const key in selectedFields) { + if (is(selectedFields[key], SingleStoreColumn)) { + const column = selectedFields[key]; + + const notNull: boolean = column.notNull; + const sqlTypeLowered = column.getSQLType().toLowerCase(); + const autoIncrement = typeof (column as any).autoIncrement === 'undefined' + ? false + : (column as any).autoIncrement; + + const generated = column.generated; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + primaryKey: false, + // If field is autoincrement it's notNull by default + // notNull: autoIncrement ? true : notNull, + notNull, + autoincrement: autoIncrement, + onUpdate: (column as any).hasOnUpdateNow, + generated: generated + ? { + as: is(generated.as, SQL) + ? dialect.sqlToQuery(generated.as as SQL).sql + : typeof generated.as === 'function' + ? dialect.sqlToQuery(generated.as() as SQL).sql + : (generated.as as any), + type: generated.mode ?? 'stored', + } + : undefined, + }; + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default, casing); + } else { + if (typeof column.default === 'string') { + columnToSet.default = `'${column.default}'`; + } else { + if (sqlTypeLowered === 'json') { + columnToSet.default = `'${JSON.stringify(column.default)}'`; + } else if (column.default instanceof Date) { + if (sqlTypeLowered === 'date') { + columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; + } else if ( + sqlTypeLowered.startsWith('datetime') + || sqlTypeLowered.startsWith('timestamp') + ) { + columnToSet.default = `'${ + column.default + .toISOString() + .replace('T', ' ') + .slice(0, 23) + }'`; + } + } else { + columnToSet.default = column.default; + } + } + if (['blob', 'text', 'json'].includes(column.getSQLType())) { + columnToSet.default = `(${columnToSet.default})`; + } + } + } + columnsObject[column.name] = columnToSet; + } + } + + resultViews[name] = { + columns: columnsObject, + name, + isExisting, + definition: isExisting ? undefined : dialect.sqlToQuery(query!).sql, + withCheckOption, + algorithm: algorithm ?? 'undefined', // set default values + sqlSecurity: sqlSecurity ?? 'definer', // set default values + }; + } + return { version: '1', dialect: 'singlestore', tables: result, + views: resultViews, _meta: { tables: {}, columns: {}, @@ -347,7 +462,7 @@ export const fromDatabase = async ( let columnsCount = 0; let tablesCount = new Set(); let indexesCount = 0; - let foreignKeysCount = 0; + let viewsCount = 0; const idxs = await db.query( `select * from INFORMATION_SCHEMA.STATISTICS @@ -587,6 +702,41 @@ export const fromDatabase = async ( } } + const views = await db.query( + `select * from INFORMATION_SCHEMA.VIEWS WHERE table_schema = '${inputSchema}';`, + ); + + const resultViews: Record = {}; + + viewsCount = views.length; + if (progressCallback) { + progressCallback('views', viewsCount, 'fetching'); + } + for await (const view of views) { + const viewName = view['TABLE_NAME']; + const definition = view['VIEW_DEFINITION']; + + const withCheckOption = view['CHECK_OPTION'] === 'NONE' ? undefined : view['CHECK_OPTION'].toLowerCase(); + const sqlSecurity = view['SECURITY_TYPE'].toLowerCase(); + + const [createSqlStatement] = await db.query(`SHOW CREATE VIEW \`${viewName}\`;`); + const algorithmMatch = createSqlStatement['Create View'].match(/ALGORITHM=([^ ]+)/); + const algorithm = algorithmMatch ? algorithmMatch[1].toLowerCase() : undefined; + + const columns = result[viewName].columns; + delete result[viewName]; + + resultViews[viewName] = { + columns: columns, + isExisting: false, + name: viewName, + algorithm, + definition, + sqlSecurity, + withCheckOption, + }; + } + if (progressCallback) { progressCallback('indexes', indexesCount, 'done'); // progressCallback("enums", 0, "fetching"); @@ -597,6 +747,7 @@ export const fromDatabase = async ( version: '1', dialect: 'singlestore', tables: result, + views: resultViews, _meta: { tables: {}, columns: {}, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 14c19cb43..db14ebb9b 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -22,6 +22,7 @@ import { JsonAddColumnStatement, JsonAlterCompositePK, JsonAlterMySqlViewStatement, + JsonAlterSingleStoreViewStatement, JsonAlterTableSetSchema, JsonAlterUniqueConstraint, JsonAlterViewStatement, @@ -30,6 +31,7 @@ import { JsonCreateMySqlViewStatement, JsonCreatePgViewStatement, JsonCreateReferenceStatement, + JsonCreateSingleStoreViewStatement, JsonCreateSqliteViewStatement, JsonCreateUniqueConstraint, JsonDeleteCheckConstraint, @@ -50,7 +52,6 @@ import { prepareAddUniqueConstraintPg as prepareAddUniqueConstraint, prepareAddValuesToEnumJson, prepareAlterColumnsMysql, - prepareAlterColumnsSingleStore, prepareAlterCompositePrimaryKeyMySql, prepareAlterCompositePrimaryKeyPg, prepareAlterCompositePrimaryKeySingleStore, @@ -98,7 +99,9 @@ import { prepareRenameSequenceJson, prepareRenameTableJson, prepareRenameViewJson, + prepareSingleStoreAlterView, prepareSingleStoreCreateTableJson, + prepareSingleStoreCreateViewJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, prepareSqliteCreateViewJson, @@ -2140,7 +2143,11 @@ export const applySingleStoreSnapshotsDiff = async ( // squash indexes and fks // squash uniqueIndexes and uniqueConstraint into constraints object - // it should be done for singlestore only because it has no diffs for it + // it should be done for mysql only because it has no diffs for it + + // TODO: @AndriiSherman + // Add an upgrade to v6 and move all snaphosts to this strcutre + // After that we can generate mysql in 1 object directly(same as sqlite) for (const tableName in json1.tables) { const table = json1.tables[tableName]; for (const indexName in table.indexes) { @@ -2266,9 +2273,40 @@ export const applySingleStoreSnapshotsDiff = async ( }, ); - const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + const viewsDiff = diffSchemasOrTables(json1.views, json2.views); - const typedResult: DiffResultSingleStore = diffResultSchemeSingleStore.parse(diffResult); + const { + created: createdViews, + deleted: deletedViews, + renamed: renamedViews, // renamed or moved + } = await viewsResolver({ + created: viewsDiff.added, + deleted: viewsDiff.deleted, + }); + + const renamesViewDic: Record = {}; + renamedViews.forEach((it) => { + renamesViewDic[it.from.name] = { to: it.to.name, from: it.from.name }; + }); + + const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + viewsPatchedSnap1.views = mapEntries( + viewsPatchedSnap1.views, + (viewKey, viewValue) => { + const rename = renamesViewDic[viewValue.name]; + + if (rename) { + viewValue.name = rename.to; + viewKey = rename.to; + } + + return [viewKey, viewValue]; + }, + ); + + const diffResult = applyJsonDiff(viewsPatchedSnap1, json2); + + const typedResult: DiffResultMysql = diffResultSchemeMysql.parse(diffResult); const jsonStatements: JsonStatement[] = []; @@ -2301,6 +2339,9 @@ export const applySingleStoreSnapshotsDiff = async ( const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + const jsonCreatedCheckConstraints: JsonCreateCheckConstraint[] = []; + const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames .map((it) => prepareRenameColumns(it.table, '', it.renames)) .flat(); @@ -2362,6 +2403,9 @@ export const applySingleStoreSnapshotsDiff = async ( let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + let createdCheckConstraints: JsonCreateCheckConstraint[] = []; + let deletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + addedUniqueConstraints = prepareAddUniqueConstraint( it.name, it.schema, @@ -2387,6 +2431,26 @@ export const applySingleStoreSnapshotsDiff = async ( ); } + createdCheckConstraints = prepareAddCheckConstraint(it.name, it.schema, it.addedCheckConstraints); + deletedCheckConstraints = prepareDeleteCheckConstraint( + it.name, + it.schema, + it.deletedCheckConstraints, + ); + + // skip for push + if (it.alteredCheckConstraints && action !== 'push') { + const added: Record = {}; + const deleted: Record = {}; + + for (const k of Object.keys(it.alteredCheckConstraints)) { + added[k] = it.alteredCheckConstraints[k].__new; + deleted[k] = it.alteredCheckConstraints[k].__old; + } + createdCheckConstraints.push(...prepareAddCheckConstraint(it.name, it.schema, added)); + deletedCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); + } + jsonAddedCompositePKs.push(...addedCompositePKs); jsonDeletedCompositePKs.push(...deletedCompositePKs); jsonAlteredCompositePKs.push(...alteredCompositePKs); @@ -2394,6 +2458,9 @@ export const applySingleStoreSnapshotsDiff = async ( jsonAddedUniqueConstraints.push(...addedUniqueConstraints); jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + + jsonCreatedCheckConstraints.push(...createdCheckConstraints); + jsonDeletedCheckConstraints.push(...deletedCheckConstraints); }); const rColumns = jsonRenameColumnsStatements.map((it) => { @@ -2407,7 +2474,7 @@ export const applySingleStoreSnapshotsDiff = async ( const jsonTableAlternations = alteredTables .map((it) => { - return prepareAlterColumnsSingleStore( + return prepareAlterColumnsMysql( it.name, it.schema, it.altered, @@ -2470,13 +2537,85 @@ export const applySingleStoreSnapshotsDiff = async ( curFull.internal, ); }); + + const createViews: JsonCreateSingleStoreViewStatement[] = []; + const dropViews: JsonDropViewStatement[] = []; + const renameViews: JsonRenameViewStatement[] = []; + const alterViews: JsonAlterSingleStoreViewStatement[] = []; + + createViews.push( + ...createdViews.filter((it) => !it.isExisting).map((it) => { + return prepareSingleStoreCreateViewJson( + it.name, + it.definition!, + it.meta, + ); + }), + ); + + dropViews.push( + ...deletedViews.filter((it) => !it.isExisting).map((it) => { + return prepareDropViewJson(it.name); + }), + ); + + renameViews.push( + ...renamedViews.filter((it) => !it.to.isExisting && !json1.views[it.from.name].isExisting).map((it) => { + return prepareRenameViewJson(it.to.name, it.from.name); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[it.name].isExisting); + + for (const alteredView of alteredViews) { + const { definition, meta } = json2.views[alteredView.name]; + + if (alteredView.alteredExisting) { + dropViews.push(prepareDropViewJson(alteredView.name)); + + createViews.push( + prepareSingleStoreCreateViewJson( + alteredView.name, + definition!, + meta, + ), + ); + + continue; + } + + if (alteredView.alteredDefinition && action !== 'push') { + createViews.push( + prepareSingleStoreCreateViewJson( + alteredView.name, + definition!, + meta, + true, + ), + ); + continue; + } + + if (alteredView.alteredMeta) { + const view = curFull['views'][alteredView.name]; + alterViews.push( + prepareSingleStoreAlterView(view), + ); + } + } + jsonStatements.push(...jsonSingleStoreCreateTables); jsonStatements.push(...jsonDropTables); jsonStatements.push(...jsonRenameTables); jsonStatements.push(...jsonRenameColumnsStatements); + jsonStatements.push(...dropViews); + jsonStatements.push(...renameViews); + jsonStatements.push(...alterViews); + jsonStatements.push(...jsonDeletedUniqueConstraints); + jsonStatements.push(...jsonDeletedCheckConstraints); // Will need to drop indexes before changing any columns in table // Then should go column alternations and then index creation @@ -2492,6 +2631,7 @@ export const applySingleStoreSnapshotsDiff = async ( jsonStatements.push(...jsonAddColumnsStatemets); jsonStatements.push(...jsonCreateIndexesForCreatedTables); + jsonStatements.push(...jsonCreatedCheckConstraints); jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); @@ -2501,11 +2641,11 @@ export const applySingleStoreSnapshotsDiff = async ( // jsonStatements.push(...jsonAddedCompositePKs); jsonStatements.push(...jsonAlteredCompositePKs); - jsonStatements.push(...jsonAddedUniqueConstraints); + jsonStatements.push(...createViews); jsonStatements.push(...jsonAlteredUniqueConstraints); - const sqlStatements = fromJson(jsonStatements, 'singlestore'); + const sqlStatements = fromJson(jsonStatements, 'mysql'); const uniqueSqlStatements: string[] = []; sqlStatements.forEach((ss) => { diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 7f3ea755d..182c89b66 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -12,9 +12,9 @@ import { int, json, mediumint, + serial, singlestoreEnum, singlestoreTable, - serial, smallint, text, time, @@ -26,7 +26,7 @@ import { } from 'drizzle-orm/singlestore-core'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; -import { diffTestSchemasSingleStore, diffTestSchemasPushSingleStore } from 'tests/schemaDiffer'; +import { diffTestSchemasPushSingleStore, diffTestSchemasSingleStore } from 'tests/schemaDiffer'; import { v4 as uuid } from 'uuid'; import { expect } from 'vitest'; import { DialectSuite, run } from './common'; @@ -667,7 +667,7 @@ const singlestoreSuite: DialectSuite = { run( singlestoreSuite, async (context: any) => { - const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(context); + const connectionString = process.env.SINGLESTORE_CONNECTION_STRING ?? await createDockerDB(context); const sleep = 1000; let timeLeft = 20000; @@ -686,7 +686,7 @@ run( } } while (timeLeft > 0); if (!connected) { - console.error('Cannot connect to MySQL'); + console.error('Cannot connect to SingleStore'); await context.client?.end().catch(console.error); await context.singlestoreContainer?.stop().catch(console.error); throw lastError; diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 9683809d1..798074785 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -1290,10 +1290,10 @@ export const diffTestSchemasSingleStore = async ( return { sqlStatements, statements }; }; -export const diffTestSchemasPushSinglestore = async ( +export const diffTestSchemasPushSingleStore = async ( client: Connection, - left: SingleStoreSchema, - right: SingleStoreSchema, + left: SinglestoreSchema, + right: SinglestoreSchema, renamesArr: string[], schema: string, cli: boolean = false, @@ -1374,13 +1374,14 @@ export const diffTestSchemasPushSinglestore = async ( } }; -export const applySingleStoreDiffs = async (sn: SingleStoreSchema, casing: CasingType | undefined) => { +export const applySingleStoreDiffs = async (sn: SinglestoreSchema, casing: CasingType | undefined) => { const dryRun = { version: '1', dialect: 'singlestore', id: '0', prevId: '0', tables: {}, + views: {}, enums: {}, schemas: {}, _meta: { @@ -2070,7 +2071,7 @@ export const introspectMySQLToFile = async ( export const introspectSingleStoreToFile = async ( client: Connection, - initSchema: SingleStoreSchema, + initSchema: SinglestoreSchema, testName: string, schema: string, casing?: CasingType | undefined, diff --git a/drizzle-kit/vitest.config.ts b/drizzle-kit/vitest.config.ts index 602e96ede..8f22123dd 100644 --- a/drizzle-kit/vitest.config.ts +++ b/drizzle-kit/vitest.config.ts @@ -7,6 +7,10 @@ export default defineConfig({ 'tests/**/*.test.ts', ], + exclude: [ + 'tests/**/singlestore-generated.test.ts', + ], + typecheck: { tsconfig: 'tsconfig.json', }, diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 8622fea11..09726d336 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -28,6 +28,7 @@ "orm", "pg", "mysql", + "singlestore", "postgresql", "postgres", "sqlite", diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index 13d9d363f..5236d2e05 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -308,9 +308,9 @@ export type BuildColumn< TTableName extends string, TBuilder extends ColumnBuilderBase, TDialect extends Dialect, -> = TDialect extends 'singlestore' ? SingleStoreColumn> - : TDialect extends 'pg' ? PgColumn> +> = TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> + : TDialect extends 'singlestore' ? SingleStoreColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : TDialect extends 'common' ? Column> : never; @@ -351,8 +351,8 @@ export type BuildExtraConfigColumns< & {}; export type ChangeColumnTableName = - TDialect extends 'singlestore' ? SingleStoreColumn> - : TDialect extends 'pg' ? PgColumn> + TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> + : TDialect extends 'singlestore' ? SingleStoreColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : never; diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts index 63a6dbf29..6ccd64f1e 100644 --- a/drizzle-orm/src/singlestore-core/columns/common.ts +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -1,4 +1,3 @@ -import { ColumnBuilder } from '~/column-builder.ts'; import type { ColumnBuilderBase, ColumnBuilderBaseConfig, @@ -10,6 +9,7 @@ import type { IsAutoincrement, MakeColumnConfig, } from '~/column-builder.ts'; +import { ColumnBuilder } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { Column } from '~/column.ts'; import { entityKind } from '~/entity.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/index.ts b/drizzle-orm/src/singlestore-core/query-builders/index.ts index 95de476cd..5963612e0 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/index.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/index.ts @@ -1,6 +1,5 @@ export * from './attach.ts'; export * from './branch.ts'; -export * from './count.ts'; export * from './createMilestone.ts'; export * from './delete.ts'; export * from './detach.ts'; diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index db24a8587..4cc8973ee 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -1,7 +1,6 @@ import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; -import type { CheckBuilder } from './checks.ts'; import { getSingleStoreColumnBuilders, type SingleStoreColumnBuilders } from './columns/all.ts'; import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; import type { AnyIndexBuilder } from './indexes.ts'; @@ -11,16 +10,12 @@ import type { UniqueConstraintBuilder } from './unique-constraint.ts'; export type SingleStoreTableExtraConfig = Record< string, | AnyIndexBuilder - | CheckBuilder | PrimaryKeyBuilder | UniqueConstraintBuilder >; export type TableConfig = TableConfigBase; -/** @internal */ -export const InlineForeignKeys = Symbol.for('drizzle:SingleStoreInlineForeignKeys'); - export class SingleStoreTable extends Table { static override readonly [entityKind]: string = 'SingleStoreTable'; @@ -78,6 +73,7 @@ export function singlestoreTableWithSchema< const builtColumns = Object.fromEntries( Object.entries(parsedColumns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as SingleStoreColumnBuilder; + colBuilder.setName(name); const column = colBuilder.build(rawTable); return [name, column]; }), diff --git a/drizzle-orm/src/singlestore-core/unique-constraint.ts b/drizzle-orm/src/singlestore-core/unique-constraint.ts index faa4f3216..511e466dc 100644 --- a/drizzle-orm/src/singlestore-core/unique-constraint.ts +++ b/drizzle-orm/src/singlestore-core/unique-constraint.ts @@ -1,13 +1,14 @@ import { entityKind } from '~/entity.ts'; +import { TableName } from '~/table.utils.ts'; import type { SingleStoreColumn } from './columns/index.ts'; -import { SingleStoreTable } from './table.ts'; +import type { SingleStoreTable } from './table.ts'; export function unique(name?: string): UniqueOnConstraintBuilder { return new UniqueOnConstraintBuilder(name); } export function uniqueKeyName(table: SingleStoreTable, columns: string[]) { - return `${table[SingleStoreTable.Symbol.Name]}_${columns.join('_')}_unique`; + return `${table[TableName]}_${columns.join('_')}_unique`; } export class UniqueConstraintBuilder { diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 3ec77a7ba..f90a4f125 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -9,19 +9,16 @@ export default defineConfig({ 'tests/relational/**/*.test.ts', 'tests/pg/**/*.test.ts', 'tests/mysql/**/*.test.ts', + 'tests/singlestore/**/*.test.ts', 'tests/sqlite/**/*.test.ts', 'tests/replicas/**/*', 'tests/imports/**/*', 'tests/extensions/vectors/**/*', 'tests/version.test.ts', 'tests/pg/node-postgres.test.ts', -<<<<<<< HEAD 'tests/utils/is-config.test.ts', 'js-tests/driver-init/commonjs/*.test.cjs', 'js-tests/driver-init/module/*.test.mjs', -======= - 'tests/singlestore/**/*.test.ts', ->>>>>>> 78db5cf6 ([SingleStore] Add SingleStore connector (#32)) ], exclude: [ ...(process.env.SKIP_EXTERNAL_DB_TESTS diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 61391c129..20ff6ca0f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22019,4 +22019,4 @@ snapshots: ps-tree: 1.2.0 webpod: 0.0.2 which: 3.0.1 - yaml: 2.4.2 \ No newline at end of file + yaml: 2.4.2 From 05e88e44857b0f6017be1e2d1d5ebee53c7336ca Mon Sep 17 00:00:00 2001 From: Andrii Sherman Date: Thu, 24 Oct 2024 22:49:19 +0300 Subject: [PATCH 261/492] Rls schema definition (#3193) * Add pgPolicy * Add all policies for generate logic * Add all policies api and pgRole into generate and pull * Add roles generate and introspect logic Add generate tests for roles * Finish all logic for roles and policies in Postgres * Add neon import * Fix tests for kit and orm * Update pglite tests * Fix role import * Update naming for crudPolicy keys * Fix sql to query mapping in policy * Create policies separately * Add roles to policy name * Fix tests after policy update * Add rls fixes and 3 param as array * Add policies to counter in drizzle pull * Fix tests * Fix serializer and tests * Make pglite 0.2.5 for now * Update deps * Add enableRLS() * Add enableRLS function for pg tables * Fix tests * Add rls for supabase --------- Co-authored-by: Dan Kochetov --- drizzle-kit/pnpm-lock.yaml | 7603 ----------------- drizzle-kit/src/api.ts | 7 + drizzle-kit/src/cli/commands/introspect.ts | 17 +- drizzle-kit/src/cli/commands/migrate.ts | 113 +- drizzle-kit/src/cli/commands/pgIntrospect.ts | 4 +- drizzle-kit/src/cli/commands/pgPushUtils.ts | 10 +- drizzle-kit/src/cli/commands/push.ts | 4 +- drizzle-kit/src/cli/commands/utils.ts | 6 +- drizzle-kit/src/cli/schema.ts | 2 + drizzle-kit/src/cli/validations/cli.ts | 11 +- drizzle-kit/src/cli/views.ts | 81 +- drizzle-kit/src/index.ts | 3 + drizzle-kit/src/introspect-pg.ts | 81 +- drizzle-kit/src/jsonDiffer.js | 76 + drizzle-kit/src/jsonStatements.ts | 220 +- drizzle-kit/src/serializer/index.ts | 4 +- drizzle-kit/src/serializer/pgImports.ts | 12 +- drizzle-kit/src/serializer/pgSchema.ts | 49 + drizzle-kit/src/serializer/pgSerializer.ts | 223 +- drizzle-kit/src/snapshotsDiffer.ts | 392 +- drizzle-kit/src/sqlgenerator.ts | 201 +- drizzle-kit/tests/introspect/pg.test.ts | 238 + drizzle-kit/tests/mysql.test.ts | 2 + drizzle-kit/tests/pg-checks.test.ts | 2 + drizzle-kit/tests/pg-identity.test.ts | 6 + drizzle-kit/tests/pg-tables.test.ts | 23 + drizzle-kit/tests/pg-views.test.ts | 18 + drizzle-kit/tests/push/libsql.test.ts | 1 + drizzle-kit/tests/push/pg.test.ts | 1309 +++ drizzle-kit/tests/rls/pg-policy.test.ts | 801 ++ drizzle-kit/tests/rls/pg-role.test.ts | 234 + drizzle-kit/tests/schemaDiffer.ts | 163 +- drizzle-kit/tests/sqlite-tables.test.ts | 1 + drizzle-orm/package.json | 2 +- drizzle-orm/src/neon/index.ts | 1 + drizzle-orm/src/neon/rls.ts | 65 + drizzle-orm/src/pg-core/index.ts | 2 + drizzle-orm/src/pg-core/policies.ts | 47 + drizzle-orm/src/pg-core/roles.ts | 41 + drizzle-orm/src/pg-core/table.ts | 79 +- drizzle-orm/src/pg-core/utils.ts | 10 +- drizzle-orm/src/supabase/index.ts | 1 + drizzle-orm/src/supabase/rls.ts | 7 + drizzle-orm/src/table.ts | 2 +- drizzle-orm/type-tests/pg/tables.ts | 22 +- integration-tests/package.json | 3 +- integration-tests/tests/pg/pg-common.ts | 123 + .../tests/pg/rls/rls.definition.test.ts | 16 + pnpm-lock.yaml | 8 +- 49 files changed, 4662 insertions(+), 7684 deletions(-) delete mode 100644 drizzle-kit/pnpm-lock.yaml create mode 100644 drizzle-kit/tests/rls/pg-policy.test.ts create mode 100644 drizzle-kit/tests/rls/pg-role.test.ts create mode 100644 drizzle-orm/src/neon/index.ts create mode 100644 drizzle-orm/src/neon/rls.ts create mode 100644 drizzle-orm/src/pg-core/policies.ts create mode 100644 drizzle-orm/src/pg-core/roles.ts create mode 100644 drizzle-orm/src/supabase/index.ts create mode 100644 drizzle-orm/src/supabase/rls.ts create mode 100644 integration-tests/tests/pg/rls/rls.definition.test.ts diff --git a/drizzle-kit/pnpm-lock.yaml b/drizzle-kit/pnpm-lock.yaml deleted file mode 100644 index 8f4d58f55..000000000 --- a/drizzle-kit/pnpm-lock.yaml +++ /dev/null @@ -1,7603 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -patchedDependencies: - difflib@0.2.4: - hash: jq4t3ysdpnbunjeje4v7nrqn2q - path: patches/difflib@0.2.4.patch - -importers: - - .: - dependencies: - '@esbuild-kit/esm-loader': - specifier: ^2.5.5 - version: 2.6.5 - esbuild: - specifier: ^0.19.7 - version: 0.19.12 - esbuild-register: - specifier: ^3.5.0 - version: 3.5.0(esbuild@0.19.12) - devDependencies: - '@arethetypeswrong/cli': - specifier: ^0.15.3 - version: 0.15.3 - '@aws-sdk/client-rds-data': - specifier: ^3.556.0 - version: 3.577.0 - '@cloudflare/workers-types': - specifier: ^4.20230518.0 - version: 4.20240512.0 - '@electric-sql/pglite': - specifier: ^0.1.5 - version: 0.1.5 - '@hono/node-server': - specifier: ^1.9.0 - version: 1.11.1 - '@hono/zod-validator': - specifier: ^0.2.1 - version: 0.2.1(hono@4.3.9)(zod@3.23.8) - '@libsql/client': - specifier: ^0.4.2 - version: 0.4.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) - '@neondatabase/serverless': - specifier: ^0.9.1 - version: 0.9.3 - '@originjs/vite-plugin-commonjs': - specifier: ^1.0.3 - version: 1.0.3 - '@planetscale/database': - specifier: ^1.16.0 - version: 1.18.0 - '@types/better-sqlite3': - specifier: ^7.6.4 - version: 7.6.10 - '@types/dockerode': - specifier: ^3.3.28 - version: 3.3.29 - '@types/glob': - specifier: ^8.1.0 - version: 8.1.0 - '@types/json-diff': - specifier: ^1.0.3 - version: 1.0.3 - '@types/minimatch': - specifier: ^5.1.2 - version: 5.1.2 - '@types/node': - specifier: ^18.11.15 - version: 18.19.33 - '@types/pg': - specifier: ^8.10.7 - version: 8.11.6 - '@types/pluralize': - specifier: ^0.0.33 - version: 0.0.33 - '@types/semver': - specifier: ^7.5.5 - version: 7.5.8 - '@types/uuid': - specifier: ^9.0.8 - version: 9.0.8 - '@types/ws': - specifier: ^8.5.10 - version: 8.5.10 - '@typescript-eslint/eslint-plugin': - specifier: ^7.2.0 - version: 7.10.0(@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': - specifier: ^7.2.0 - version: 7.10.0(eslint@8.57.0)(typescript@5.4.5) - '@vercel/postgres': - specifier: ^0.8.0 - version: 0.8.0 - ava: - specifier: ^5.1.0 - version: 5.3.1 - better-sqlite3: - specifier: ^9.4.3 - version: 9.6.0 - camelcase: - specifier: ^7.0.1 - version: 7.0.1 - chalk: - specifier: ^5.2.0 - version: 5.3.0 - commander: - specifier: ^12.1.0 - version: 12.1.0 - dockerode: - specifier: ^3.3.4 - version: 3.3.5 - dotenv: - specifier: ^16.0.3 - version: 16.4.5 - drizzle-kit: - specifier: 0.21.2 - version: 0.21.2 - drizzle-orm: - specifier: 0.32.0-85c8008 - version: 0.32.0-85c8008(@aws-sdk/client-rds-data@3.577.0)(@cloudflare/workers-types@4.20240512.0)(@electric-sql/pglite@0.1.5)(@libsql/client@0.4.3(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(mysql2@2.3.3)(pg@8.11.5)(postgres@3.4.4) - env-paths: - specifier: ^3.0.0 - version: 3.0.0 - esbuild-node-externals: - specifier: ^1.9.0 - version: 1.13.1(esbuild@0.19.12) - eslint: - specifier: ^8.57.0 - version: 8.57.0 - eslint-config-prettier: - specifier: ^9.1.0 - version: 9.1.0(eslint@8.57.0) - eslint-plugin-prettier: - specifier: ^5.1.3 - version: 5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8) - get-port: - specifier: ^6.1.2 - version: 6.1.2 - glob: - specifier: ^8.1.0 - version: 8.1.0 - hanji: - specifier: ^0.0.5 - version: 0.0.5 - hono: - specifier: ^4.1.5 - version: 4.3.9 - json-diff: - specifier: 1.0.6 - version: 1.0.6 - minimatch: - specifier: ^7.4.3 - version: 7.4.6 - mysql2: - specifier: 2.3.3 - version: 2.3.3 - node-fetch: - specifier: ^3.3.2 - version: 3.3.2 - pg: - specifier: ^8.11.5 - version: 8.11.5 - pluralize: - specifier: ^8.0.0 - version: 8.0.0 - postgres: - specifier: ^3.4.4 - version: 3.4.4 - prettier: - specifier: ^2.8.1 - version: 2.8.8 - semver: - specifier: ^7.5.4 - version: 7.6.2 - superjson: - specifier: ^2.2.1 - version: 2.2.1 - tsup: - specifier: ^8.0.2 - version: 8.0.2(postcss@8.4.38)(typescript@5.4.5) - tsx: - specifier: ^3.12.1 - version: 3.14.0 - typescript: - specifier: ^5.4.3 - version: 5.4.5 - uuid: - specifier: ^9.0.1 - version: 9.0.1 - vite-tsconfig-paths: - specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5)(vite@5.2.11(@types/node@18.19.33)) - vitest: - specifier: ^1.4.0 - version: 1.6.0(@types/node@18.19.33) - wrangler: - specifier: ^3.22.1 - version: 3.57.0(@cloudflare/workers-types@4.20240512.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3) - ws: - specifier: ^8.16.0 - version: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - zod: - specifier: ^3.20.2 - version: 3.23.8 - zx: - specifier: ^7.2.2 - version: 7.2.3 - -packages: - - '@andrewbranch/untar.js@1.0.3': - resolution: {integrity: sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw==} - - '@arethetypeswrong/cli@0.15.3': - resolution: {integrity: sha512-sIMA9ZJBWDEg1+xt5RkAEflZuf8+PO8SdKj17x6PtETuUho+qlZJg4DgmKc3q+QwQ9zOB5VLK6jVRbFdNLdUIA==} - engines: {node: '>=18'} - hasBin: true - - '@arethetypeswrong/core@0.15.1': - resolution: {integrity: sha512-FYp6GBAgsNz81BkfItRz8RLZO03w5+BaeiPma1uCfmxTnxbtuMrI/dbzGiOk8VghO108uFI0oJo0OkewdSHw7g==} - engines: {node: '>=18'} - - '@aws-crypto/ie11-detection@3.0.0': - resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} - - '@aws-crypto/sha256-browser@3.0.0': - resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} - - '@aws-crypto/sha256-js@3.0.0': - resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} - - '@aws-crypto/supports-web-crypto@3.0.0': - resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} - - '@aws-crypto/util@3.0.0': - resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} - - '@aws-sdk/client-rds-data@3.577.0': - resolution: {integrity: sha512-24a27II6UkNhe2RB6ZwtQPcM3QB/DuRcKvzMmfvipgWS72Q5FEtuq3CO66IObWUel/pxi3ucE6mSvVCFnm7tBQ==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sso-oidc@3.577.0': - resolution: {integrity: sha512-njmKSPDWueWWYVFpFcZ2P3fI6/pdQVDa0FgCyYZhOnJLgEHZIcBBg1AsnkVWacBuLopp9XVt2m+7hO6ugY1/1g==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sso@3.577.0': - resolution: {integrity: sha512-BwujdXrydlk6UEyPmewm5GqG4nkQ6OVyRhS/SyZP/6UKSFv2/sf391Cmz0hN0itUTH1rR4XeLln8XCOtarkrzg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sts@3.577.0': - resolution: {integrity: sha512-509Kklimva1XVlhGbpTpeX3kOP6ORpm44twJxDHpa9TURbmoaxj7veWlnLCbDorxDTrbsDghvYZshvcLsojVpg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/core@3.576.0': - resolution: {integrity: sha512-KDvDlbeipSTIf+ffKtTg1m419TK7s9mZSWC8bvuZ9qx6/sjQFOXIKOVqyuli6DnfxGbvRcwoRuY99OcCH1N/0w==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-env@3.577.0': - resolution: {integrity: sha512-Jxu255j0gToMGEiqufP8ZtKI8HW90lOLjwJ3LrdlD/NLsAY0tOQf1fWc53u28hWmmNGMxmCrL2p66IOgMDhDUw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-http@3.577.0': - resolution: {integrity: sha512-n++yhCp67b9+ZRGEdY1jhamB5E/O+QsIDOPSuRmdaSGMCOd82oUEKPgIVEU1bkqxDsBxgiEWuvtfhK6sNiDS0A==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-ini@3.577.0': - resolution: {integrity: sha512-q7lHPtv6BjRvChUE3m0tIaEZKxPTaZ1B3lKxGYsFl3VLAu5N8yGCUKwuA1izf4ucT+LyKscVGqK6VDZx1ev3nw==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sts': ^3.577.0 - - '@aws-sdk/credential-provider-node@3.577.0': - resolution: {integrity: sha512-epZ1HOMsrXBNczc0HQpv0VMjqAEpc09DUA7Rg3gUJfn8umhML7A7bXnUyqPA+S54q397UYg1leQKdSn23OiwQQ==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-process@3.577.0': - resolution: {integrity: sha512-Gin6BWtOiXxIgITrJ3Nwc+Y2P1uVT6huYR4EcbA/DJUPWyO0n9y5UFLewPvVbLkRn15JeEqErBLUrHclkiOKtw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-sso@3.577.0': - resolution: {integrity: sha512-iVm5SQvS7EgZTJsRaqUOmDQpBQPPPat42SCbWFvFQOLrl8qewq8OP94hFS5w2mP62zngeYzqhJnDel79HXbxew==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-web-identity@3.577.0': - resolution: {integrity: sha512-ZGHGNRaCtJJmszb9UTnC7izNCtRUttdPlLdMkh41KPS32vfdrBDHs1JrpbZijItRj1xKuOXsiYSXLAaHGcLh8Q==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sts': ^3.577.0 - - '@aws-sdk/middleware-host-header@3.577.0': - resolution: {integrity: sha512-9ca5MJz455CODIVXs0/sWmJm7t3QO4EUa1zf8pE8grLpzf0J94bz/skDWm37Pli13T3WaAQBHCTiH2gUVfCsWg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/middleware-logger@3.577.0': - resolution: {integrity: sha512-aPFGpGjTZcJYk+24bg7jT4XdIp42mFXSuPt49lw5KygefLyJM/sB0bKKqPYYivW0rcuZ9brQ58eZUNthrzYAvg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/middleware-recursion-detection@3.577.0': - resolution: {integrity: sha512-pn3ZVEd2iobKJlR3H+bDilHjgRnNrQ6HMmK9ZzZw89Ckn3Dcbv48xOv4RJvu0aU8SDLl/SNCxppKjeLDTPGBNA==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/middleware-user-agent@3.577.0': - resolution: {integrity: sha512-P55HAXgwmiHHpFx5JEPvOnAbfhN7v6sWv9PBQs+z2tC7QiBcPS0cdJR6PfV7J1n4VPK52/OnrK3l9VxdQ7Ms0g==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/region-config-resolver@3.577.0': - resolution: {integrity: sha512-4ChCFACNwzqx/xjg3zgFcW8Ali6R9C95cFECKWT/7CUM1D0MGvkclSH2cLarmHCmJgU6onKkJroFtWp0kHhgyg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/token-providers@3.577.0': - resolution: {integrity: sha512-0CkIZpcC3DNQJQ1hDjm2bdSy/Xjs7Ny5YvSsacasGOkNfk+FdkiQy6N67bZX3Zbc9KIx+Nz4bu3iDeNSNplnnQ==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sso-oidc': ^3.577.0 - - '@aws-sdk/types@3.577.0': - resolution: {integrity: sha512-FT2JZES3wBKN/alfmhlo+3ZOq/XJ0C7QOZcDNrpKjB0kqYoKjhVKZ/Hx6ArR0czkKfHzBBEs6y40ebIHx2nSmA==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/util-endpoints@3.577.0': - resolution: {integrity: sha512-FjuUz1Kdy4Zly2q/c58tpdqHd6z7iOdU/caYzoc8jwgAHBDBbIJNQLCU9hXJnPV2M8pWxQDyIZsoVwtmvErPzw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/util-locate-window@3.568.0': - resolution: {integrity: sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/util-user-agent-browser@3.577.0': - resolution: {integrity: sha512-zEAzHgR6HWpZOH7xFgeJLc6/CzMcx4nxeQolZxVZoB5pPaJd3CjyRhZN0xXeZB0XIRCWmb4yJBgyiugXLNMkLA==} - - '@aws-sdk/util-user-agent-node@3.577.0': - resolution: {integrity: sha512-XqvtFjbSMtycZTWVwDe8DRWovuoMbA54nhUoZwVU6rW9OSD6NZWGR512BUGHFaWzW0Wg8++Dj10FrKTG2XtqfA==} - engines: {node: '>=16.0.0'} - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true - - '@aws-sdk/util-utf8-browser@3.259.0': - resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} - - '@balena/dockerignore@1.0.2': - resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} - - '@cloudflare/kv-asset-handler@0.3.2': - resolution: {integrity: sha512-EeEjMobfuJrwoctj7FA1y1KEbM0+Q1xSjobIEyie9k4haVEBB7vkDvsasw1pM3rO39mL2akxIAzLMUAtrMHZhA==} - engines: {node: '>=16.13'} - - '@cloudflare/workerd-darwin-64@1.20240512.0': - resolution: {integrity: sha512-VMp+CsSHFALQiBzPdQ5dDI4T1qwLu0mQ0aeKVNDosXjueN0f3zj/lf+mFil5/9jBbG3t4mG0y+6MMnalP9Lobw==} - engines: {node: '>=16'} - cpu: [x64] - os: [darwin] - - '@cloudflare/workerd-darwin-arm64@1.20240512.0': - resolution: {integrity: sha512-lZktXGmzMrB5rJqY9+PmnNfv1HKlj/YLZwMjPfF0WVKHUFdvQbAHsi7NlKv6mW9uIvlZnS+K4sIkWc0MDXcRnA==} - engines: {node: '>=16'} - cpu: [arm64] - os: [darwin] - - '@cloudflare/workerd-linux-64@1.20240512.0': - resolution: {integrity: sha512-wrHvqCZZqXz6Y3MUTn/9pQNsvaoNjbJpuA6vcXsXu8iCzJi911iVW2WUEBX+MpUWD+mBIP0oXni5tTlhkokOPw==} - engines: {node: '>=16'} - cpu: [x64] - os: [linux] - - '@cloudflare/workerd-linux-arm64@1.20240512.0': - resolution: {integrity: sha512-YPezHMySL9J9tFdzxz390eBswQ//QJNYcZolz9Dgvb3FEfdpK345cE/bsWbMOqw5ws2f82l388epoenghtYvAg==} - engines: {node: '>=16'} - cpu: [arm64] - os: [linux] - - '@cloudflare/workerd-windows-64@1.20240512.0': - resolution: {integrity: sha512-SxKapDrIYSscMR7lGIp/av0l6vokjH4xQ9ACxHgXh+OdOus9azppSmjaPyw4/ePvg7yqpkaNjf9o258IxWtvKQ==} - engines: {node: '>=16'} - cpu: [x64] - os: [win32] - - '@cloudflare/workers-types@4.20240512.0': - resolution: {integrity: sha512-o2yTEWg+YK/I1t/Me+dA0oarO0aCbjibp6wSeaw52DSE9tDyKJ7S+Qdyw/XsMrKn4t8kF6f/YOba+9O4MJfW9w==} - - '@colors/colors@1.5.0': - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - - '@electric-sql/pglite@0.1.5': - resolution: {integrity: sha512-eymv4ONNvoPZQTvOQIi5dbpR+J5HzEv0qQH9o/y3gvNheJV/P/NFcrbsfJZYTsDKoq7DKrTiFNexsRkJKy8x9Q==} - - '@esbuild-kit/core-utils@3.3.2': - resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} - - '@esbuild-kit/esm-loader@2.6.5': - resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} - - '@esbuild-plugins/node-globals-polyfill@0.2.3': - resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} - peerDependencies: - esbuild: '*' - - '@esbuild-plugins/node-modules-polyfill@0.2.2': - resolution: {integrity: sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==} - peerDependencies: - esbuild: '*' - - '@esbuild/aix-ppc64@0.19.12': - resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - - '@esbuild/aix-ppc64@0.20.2': - resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.17.19': - resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.18.20': - resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.19.12': - resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.20.2': - resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.17.19': - resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-arm@0.18.20': - resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-arm@0.19.12': - resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-arm@0.20.2': - resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.17.19': - resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.18.20': - resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.19.12': - resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.20.2': - resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.17.19': - resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.18.20': - resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.19.12': - resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.20.2': - resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.17.19': - resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/darwin-x64@0.18.20': - resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/darwin-x64@0.19.12': - resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/darwin-x64@0.20.2': - resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.17.19': - resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.18.20': - resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.19.12': - resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.20.2': - resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.17.19': - resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.18.20': - resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.19.12': - resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.20.2': - resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.17.19': - resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.18.20': - resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.19.12': - resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.20.2': - resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.17.19': - resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.18.20': - resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.19.12': - resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.20.2': - resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.17.19': - resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.18.20': - resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.19.12': - resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.20.2': - resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.14.54': - resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.17.19': - resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.18.20': - resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.19.12': - resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.20.2': - resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.17.19': - resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.18.20': - resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.19.12': - resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.20.2': - resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.17.19': - resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.18.20': - resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.19.12': - resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.20.2': - resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.17.19': - resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.18.20': - resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.19.12': - resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.20.2': - resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.17.19': - resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.18.20': - resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.19.12': - resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.20.2': - resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.17.19': - resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.18.20': - resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.19.12': - resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.20.2': - resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-x64@0.17.19': - resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.18.20': - resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.19.12': - resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.20.2': - resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-x64@0.17.19': - resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.18.20': - resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.19.12': - resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.20.2': - resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/sunos-x64@0.17.19': - resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.18.20': - resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.19.12': - resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.20.2': - resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.17.19': - resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.18.20': - resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.19.12': - resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.20.2': - resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.17.19': - resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.18.20': - resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.19.12': - resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.20.2': - resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.17.19': - resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.18.20': - resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.19.12': - resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.20.2': - resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.10.0': - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/js@8.57.0': - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@ewoudenberg/difflib@0.1.0': - resolution: {integrity: sha512-OU5P5mJyD3OoWYMWY+yIgwvgNS9cFAU10f+DDuvtogcWQOoJIsQ4Hy2McSfUfhKjq8L0FuWVb4Rt7kgA+XK86A==} - - '@fastify/busboy@2.1.1': - resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} - engines: {node: '>=14'} - - '@hono/node-server@1.11.1': - resolution: {integrity: sha512-GW1Iomhmm1o4Z+X57xGby8A35Cu9UZLL7pSMdqDBkD99U5cywff8F+8hLk5aBTzNubnsFAvWQ/fZjNwPsEn9lA==} - engines: {node: '>=18.14.1'} - - '@hono/zod-validator@0.2.1': - resolution: {integrity: sha512-HFoxln7Q6JsE64qz2WBS28SD33UB2alp3aRKmcWnNLDzEL1BLsWfbdX6e1HIiUprHYTIXf5y7ax8eYidKUwyaA==} - peerDependencies: - hono: '>=3.9.0' - zod: ^3.19.1 - - '@humanwhocodes/config-array@0.11.14': - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jridgewell/gen-mapping@0.3.5': - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} - engines: {node: '>=6.0.0'} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.4.15': - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - - '@libsql/client@0.4.3': - resolution: {integrity: sha512-AUYKnSPqAsFBVWBvmtrb4dG3pQlvTKT92eztAest9wQU2iJkabH8WzHLDb3dKFWKql7/kiCqvBQUVpozDwhekQ==} - - '@libsql/core@0.4.3': - resolution: {integrity: sha512-r28iYBtaLBW9RRgXPFh6cGCsVI/rwRlOzSOpAu/1PVTm6EJ3t233pUf97jETVHU0vjdr1d8VvV6fKAvJkokqCw==} - - '@libsql/darwin-arm64@0.2.0': - resolution: {integrity: sha512-+qyT2W/n5CFH1YZWv2mxW4Fsoo4dX9Z9M/nvbQqZ7H84J8hVegvVAsIGYzcK8xAeMEcpU5yGKB1Y9NoDY4hOSQ==} - cpu: [arm64] - os: [darwin] - - '@libsql/darwin-x64@0.2.0': - resolution: {integrity: sha512-hwmO2mF1n8oDHKFrUju6Jv+n9iFtTf5JUK+xlnIE3Td0ZwGC/O1R/Z/btZTd9nD+vsvakC8SJT7/Q6YlWIkhEw==} - cpu: [x64] - os: [darwin] - - '@libsql/hrana-client@0.5.6': - resolution: {integrity: sha512-mjQoAmejZ1atG+M3YR2ZW+rg6ceBByH/S/h17ZoYZkqbWrvohFhXyz2LFxj++ARMoY9m6w3RJJIRdJdmnEUlFg==} - - '@libsql/isomorphic-fetch@0.1.12': - resolution: {integrity: sha512-MRo4UcmjAGAa3ac56LoD5OE13m2p0lu0VEtZC2NZMcogM/jc5fU9YtMQ3qbPjFJ+u2BBjFZgMPkQaLS1dlMhpg==} - - '@libsql/isomorphic-ws@0.1.5': - resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} - - '@libsql/linux-arm64-gnu@0.2.0': - resolution: {integrity: sha512-1w2lPXIYtnBaK5t/Ej5E8x7lPiE+jP3KATI/W4yei5Z/ONJh7jQW5PJ7sYU95vTME3hWEM1FXN6kvzcpFAte7w==} - cpu: [arm64] - os: [linux] - - '@libsql/linux-arm64-musl@0.2.0': - resolution: {integrity: sha512-lkblBEJ7xuNiWNjP8DDq0rqoWccszfkUS7Efh5EjJ+GDWdCBVfh08mPofIZg0fZVLWQCY3j+VZCG1qZfATBizg==} - cpu: [arm64] - os: [linux] - - '@libsql/linux-x64-gnu@0.2.0': - resolution: {integrity: sha512-+x/d289KeJydwOhhqSxKT+6MSQTCfLltzOpTzPccsvdt5fxg8CBi+gfvEJ4/XW23Sa+9bc7zodFP0i6MOlxX7w==} - cpu: [x64] - os: [linux] - - '@libsql/linux-x64-musl@0.2.0': - resolution: {integrity: sha512-5Xn0c5A6vKf9D1ASpgk7mef//FuY7t5Lktj/eiU4n3ryxG+6WTpqstTittJUgepVjcleLPYxIhQAYeYwTYH1IQ==} - cpu: [x64] - os: [linux] - - '@libsql/win32-x64-msvc@0.2.0': - resolution: {integrity: sha512-rpK+trBIpRST15m3cMYg5aPaX7kvCIottxY7jZPINkKAaScvfbn9yulU/iZUM9YtuK96Y1ZmvwyVIK/Y5DzoMQ==} - cpu: [x64] - os: [win32] - - '@neon-rs/load@0.0.4': - resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==} - - '@neondatabase/serverless@0.7.2': - resolution: {integrity: sha512-wU3WA2uTyNO7wjPs3Mg0G01jztAxUxzd9/mskMmtPwPTjf7JKWi9AW5/puOGXLxmZ9PVgRFeBVRVYq5nBPhsCg==} - - '@neondatabase/serverless@0.9.3': - resolution: {integrity: sha512-6ZBK8asl2Z3+ADEaELvbaVVGVlmY1oAzkxxZfpmXPKFuJhbDN+5fU3zYBamsahS/Ch1zE+CVWB3R+8QEI2LMSw==} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@originjs/vite-plugin-commonjs@1.0.3': - resolution: {integrity: sha512-KuEXeGPptM2lyxdIEJ4R11+5ztipHoE7hy8ClZt3PYaOVQ/pyngd2alaSrPnwyFeOW1UagRBaQ752aA1dTMdOQ==} - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@pkgr/core@0.1.1': - resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - - '@planetscale/database@1.18.0': - resolution: {integrity: sha512-t2XdOfrVgcF7AW791FtdPS27NyNqcE1SpoXgk3HpziousvUMsJi4Q6NL3JyOBpsMOrvk94749o8yyonvX5quPw==} - engines: {node: '>=16'} - - '@rollup/rollup-android-arm-eabi@4.17.2': - resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.17.2': - resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.17.2': - resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.17.2': - resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-linux-arm-gnueabihf@4.17.2': - resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.17.2': - resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.17.2': - resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.17.2': - resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': - resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.17.2': - resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.17.2': - resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.17.2': - resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.17.2': - resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-win32-arm64-msvc@4.17.2': - resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.17.2': - resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.17.2': - resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==} - cpu: [x64] - os: [win32] - - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - - '@sindresorhus/is@4.6.0': - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} - - '@smithy/abort-controller@3.0.0': - resolution: {integrity: sha512-p6GlFGBt9K4MYLu72YuJ523NVR4A8oHlC5M2JO6OmQqN8kAc/uh1JqLE+FizTokrSJGg0CSvC+BrsmGzKtsZKA==} - engines: {node: '>=16.0.0'} - - '@smithy/config-resolver@3.0.0': - resolution: {integrity: sha512-2GzOfADwYLQugYkKQhIyZyQlM05K+tMKvRnc6eFfZcpJGRfKoMUMYdPlBKmqHwQFXQKBrGV6cxL9oymWgDzvFw==} - engines: {node: '>=16.0.0'} - - '@smithy/core@2.0.1': - resolution: {integrity: sha512-rcMkjvwxH/bER+oZUPR0yTA0ELD6m3A+d92+CFkdF6HJFCBB1bXo7P5pm21L66XwTN01B6bUhSCQ7cymWRD8zg==} - engines: {node: '>=16.0.0'} - - '@smithy/credential-provider-imds@3.0.0': - resolution: {integrity: sha512-lfmBiFQcA3FsDAPxNfY0L7CawcWtbyWsBOHo34nF095728JLkBX4Y9q/VPPE2r7fqMVK+drmDigqE2/SSQeVRA==} - engines: {node: '>=16.0.0'} - - '@smithy/fetch-http-handler@3.0.1': - resolution: {integrity: sha512-uaH74i5BDj+rBwoQaXioKpI0SHBJFtOVwzrCpxZxphOW0ki5jhj7dXvDMYM2IJem8TpdFvS2iC08sjOblfFGFg==} - - '@smithy/hash-node@3.0.0': - resolution: {integrity: sha512-84qXstNemP3XS5jcof0el6+bDfjzuvhJPQTEfro3lgtbCtKgzPm3MgiS6ehXVPjeQ5+JS0HqmTz8f/RYfzHVxw==} - engines: {node: '>=16.0.0'} - - '@smithy/invalid-dependency@3.0.0': - resolution: {integrity: sha512-F6wBBaEFgJzj0s4KUlliIGPmqXemwP6EavgvDqYwCH40O5Xr2iMHvS8todmGVZtuJCorBkXsYLyTu4PuizVq5g==} - - '@smithy/is-array-buffer@3.0.0': - resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==} - engines: {node: '>=16.0.0'} - - '@smithy/middleware-content-length@3.0.0': - resolution: {integrity: sha512-3C4s4d/iGobgCtk2tnWW6+zSTOBg1PRAm2vtWZLdriwTroFbbWNSr3lcyzHdrQHnEXYCC5K52EbpfodaIUY8sg==} - engines: {node: '>=16.0.0'} - - '@smithy/middleware-endpoint@3.0.0': - resolution: {integrity: sha512-aXOAWztw/5qAfp0NcA2OWpv6ZI/E+Dh9mByif7i91D/0iyYNUcKvskmXiowKESFkuZ7PIMd3VOR4fTibZDs2OQ==} - engines: {node: '>=16.0.0'} - - '@smithy/middleware-retry@3.0.1': - resolution: {integrity: sha512-hBhSEuL841FhJBK/19WpaGk5YWSzFk/P2UaVjANGKRv3eYNO8Y1lANWgqnuPWjOyCEWMPr58vELFDWpxvRKANw==} - engines: {node: '>=16.0.0'} - - '@smithy/middleware-serde@3.0.0': - resolution: {integrity: sha512-I1vKG1foI+oPgG9r7IMY1S+xBnmAn1ISqployvqkwHoSb8VPsngHDTOgYGYBonuOKndaWRUGJZrKYYLB+Ane6w==} - engines: {node: '>=16.0.0'} - - '@smithy/middleware-stack@3.0.0': - resolution: {integrity: sha512-+H0jmyfAyHRFXm6wunskuNAqtj7yfmwFB6Fp37enytp2q047/Od9xetEaUbluyImOlGnGpaVGaVfjwawSr+i6Q==} - engines: {node: '>=16.0.0'} - - '@smithy/node-config-provider@3.0.0': - resolution: {integrity: sha512-buqfaSdDh0zo62EPLf8rGDvcpKwGpO5ho4bXS2cdFhlOta7tBkWJt+O5uiaAeICfIOfPclNOndshDNSanX2X9g==} - engines: {node: '>=16.0.0'} - - '@smithy/node-http-handler@3.0.0': - resolution: {integrity: sha512-3trD4r7NOMygwLbUJo4eodyQuypAWr7uvPnebNJ9a70dQhVn+US8j/lCnvoJS6BXfZeF7PkkkI0DemVJw+n+eQ==} - engines: {node: '>=16.0.0'} - - '@smithy/property-provider@3.0.0': - resolution: {integrity: sha512-LmbPgHBswdXCrkWWuUwBm9w72S2iLWyC/5jet9/Y9cGHtzqxi+GVjfCfahkvNV4KXEwgnH8EMpcrD9RUYe0eLQ==} - engines: {node: '>=16.0.0'} - - '@smithy/protocol-http@4.0.0': - resolution: {integrity: sha512-qOQZOEI2XLWRWBO9AgIYuHuqjZ2csyr8/IlgFDHDNuIgLAMRx2Bl8ck5U5D6Vh9DPdoaVpuzwWMa0xcdL4O/AQ==} - engines: {node: '>=16.0.0'} - - '@smithy/querystring-builder@3.0.0': - resolution: {integrity: sha512-bW8Fi0NzyfkE0TmQphDXr1AmBDbK01cA4C1Z7ggwMAU5RDz5AAv/KmoRwzQAS0kxXNf/D2ALTEgwK0U2c4LtRg==} - engines: {node: '>=16.0.0'} - - '@smithy/querystring-parser@3.0.0': - resolution: {integrity: sha512-UzHwthk0UEccV4dHzPySnBy34AWw3V9lIqUTxmozQ+wPDAO9csCWMfOLe7V9A2agNYy7xE+Pb0S6K/J23JSzfQ==} - engines: {node: '>=16.0.0'} - - '@smithy/service-error-classification@3.0.0': - resolution: {integrity: sha512-3BsBtOUt2Gsnc3X23ew+r2M71WwtpHfEDGhHYHSDg6q1t8FrWh15jT25DLajFV1H+PpxAJ6gqe9yYeRUsmSdFA==} - engines: {node: '>=16.0.0'} - - '@smithy/shared-ini-file-loader@3.0.0': - resolution: {integrity: sha512-REVw6XauXk8xE4zo5aGL7Rz4ywA8qNMUn8RtWeTRQsgAlmlvbJ7CEPBcaXU2NDC3AYBgYAXrGyWD8XrN8UGDog==} - engines: {node: '>=16.0.0'} - - '@smithy/signature-v4@3.0.0': - resolution: {integrity: sha512-kXFOkNX+BQHe2qnLxpMEaCRGap9J6tUGLzc3A9jdn+nD4JdMwCKTJ+zFwQ20GkY+mAXGatyTw3HcoUlR39HwmA==} - engines: {node: '>=16.0.0'} - - '@smithy/smithy-client@3.0.1': - resolution: {integrity: sha512-KAiFY4Y4jdHxR+4zerH/VBhaFKM8pbaVmJZ/CWJRwtM/CmwzTfXfvYwf6GoUwiHepdv+lwiOXCuOl6UBDUEINw==} - engines: {node: '>=16.0.0'} - - '@smithy/types@3.0.0': - resolution: {integrity: sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==} - engines: {node: '>=16.0.0'} - - '@smithy/url-parser@3.0.0': - resolution: {integrity: sha512-2XLazFgUu+YOGHtWihB3FSLAfCUajVfNBXGGYjOaVKjLAuAxx3pSBY3hBgLzIgB17haf59gOG3imKqTy8mcrjw==} - - '@smithy/util-base64@3.0.0': - resolution: {integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==} - engines: {node: '>=16.0.0'} - - '@smithy/util-body-length-browser@3.0.0': - resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==} - - '@smithy/util-body-length-node@3.0.0': - resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==} - engines: {node: '>=16.0.0'} - - '@smithy/util-buffer-from@3.0.0': - resolution: {integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==} - engines: {node: '>=16.0.0'} - - '@smithy/util-config-provider@3.0.0': - resolution: {integrity: sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==} - engines: {node: '>=16.0.0'} - - '@smithy/util-defaults-mode-browser@3.0.1': - resolution: {integrity: sha512-nW5kEzdJn1Bn5TF+gOPHh2rcPli8JU9vSSXLbfg7uPnfR1TMRQqs9zlYRhIb87NeSxIbpdXOI94tvXSy+fvDYg==} - engines: {node: '>= 10.0.0'} - - '@smithy/util-defaults-mode-node@3.0.1': - resolution: {integrity: sha512-TFk+Qb+elLc/MOhtSp+50fstyfZ6avQbgH2d96xUBpeScu+Al9elxv+UFAjaTHe0HQe5n+wem8ZLpXvU8lwV6Q==} - engines: {node: '>= 10.0.0'} - - '@smithy/util-endpoints@2.0.0': - resolution: {integrity: sha512-+exaXzEY3DNt2qtA2OtRNSDlVrE4p32j1JSsQkzA5AdP0YtJNjkYbYhJxkFmPYcjI1abuwopOZCwUmv682QkiQ==} - engines: {node: '>=16.0.0'} - - '@smithy/util-hex-encoding@3.0.0': - resolution: {integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==} - engines: {node: '>=16.0.0'} - - '@smithy/util-middleware@3.0.0': - resolution: {integrity: sha512-q5ITdOnV2pXHSVDnKWrwgSNTDBAMHLptFE07ua/5Ty5WJ11bvr0vk2a7agu7qRhrCFRQlno5u3CneU5EELK+DQ==} - engines: {node: '>=16.0.0'} - - '@smithy/util-retry@3.0.0': - resolution: {integrity: sha512-nK99bvJiziGv/UOKJlDvFF45F00WgPLKVIGUfAK+mDhzVN2hb/S33uW2Tlhg5PVBoqY7tDVqL0zmu4OxAHgo9g==} - engines: {node: '>=16.0.0'} - - '@smithy/util-stream@3.0.1': - resolution: {integrity: sha512-7F7VNNhAsfMRA8I986YdOY5fE0/T1/ZjFF6OLsqkvQVNP3vZ/szYDfGCyphb7ioA09r32K/0qbSFfNFU68aSzA==} - engines: {node: '>=16.0.0'} - - '@smithy/util-uri-escape@3.0.0': - resolution: {integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==} - engines: {node: '>=16.0.0'} - - '@smithy/util-utf8@3.0.0': - resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==} - engines: {node: '>=16.0.0'} - - '@types/better-sqlite3@7.6.10': - resolution: {integrity: sha512-TZBjD+yOsyrUJGmcUj6OS3JADk3+UZcNv3NOBqGkM09bZdi28fNZw8ODqbMOLfKCu7RYCO62/ldq1iHbzxqoPw==} - - '@types/docker-modem@3.0.6': - resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} - - '@types/dockerode@3.3.29': - resolution: {integrity: sha512-5PRRq/yt5OT/Jf77ltIdz4EiR9+VLnPF+HpU4xGFwUqmV24Co2HKBNW3w+slqZ1CYchbcDeqJASHDYWzZCcMiQ==} - - '@types/estree@1.0.5': - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - - '@types/fs-extra@11.0.4': - resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} - - '@types/glob@8.1.0': - resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} - - '@types/json-diff@1.0.3': - resolution: {integrity: sha512-Qvxm8fpRMv/1zZR3sQWImeRK2mBYJji20xF51Fq9Gt//Ed18u0x6/FNLogLS1xhfUWTEmDyqveJqn95ltB6Kvw==} - - '@types/jsonfile@6.1.4': - resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} - - '@types/minimatch@5.1.2': - resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - - '@types/minimist@1.2.5': - resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} - - '@types/node-fetch@2.6.11': - resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} - - '@types/node-forge@1.3.11': - resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} - - '@types/node@18.19.33': - resolution: {integrity: sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A==} - - '@types/pg@8.11.6': - resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==} - - '@types/pg@8.6.6': - resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==} - - '@types/pluralize@0.0.33': - resolution: {integrity: sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==} - - '@types/ps-tree@1.1.6': - resolution: {integrity: sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==} - - '@types/semver@7.5.8': - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - - '@types/ssh2@1.15.0': - resolution: {integrity: sha512-YcT8jP5F8NzWeevWvcyrrLB3zcneVjzYY9ZDSMAMboI+2zR1qYWFhwsyOFVzT7Jorn67vqxC0FRiw8YyG9P1ww==} - - '@types/uuid@9.0.8': - resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} - - '@types/which@3.0.3': - resolution: {integrity: sha512-2C1+XoY0huExTbs8MQv1DuS5FS86+SEjdM9F/+GS61gg5Hqbtj8ZiDSx8MfWcyei907fIPbfPGCOrNUTnVHY1g==} - - '@types/ws@8.5.10': - resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} - - '@typescript-eslint/eslint-plugin@7.10.0': - resolution: {integrity: sha512-PzCr+a/KAef5ZawX7nbyNwBDtM1HdLIT53aSA2DDlxmxMngZ43O8SIePOeX8H5S+FHXeI6t97mTt/dDdzY4Fyw==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/parser@7.10.0': - resolution: {integrity: sha512-2EjZMA0LUW5V5tGQiaa2Gys+nKdfrn2xiTIBLR4fxmPmVSvgPcKNW+AE/ln9k0A4zDUti0J/GZXMDupQoI+e1w==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/scope-manager@7.10.0': - resolution: {integrity: sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/type-utils@7.10.0': - resolution: {integrity: sha512-D7tS4WDkJWrVkuzgm90qYw9RdgBcrWmbbRkrLA4d7Pg3w0ttVGDsvYGV19SH8gPR5L7OtcN5J1hTtyenO9xE9g==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/types@7.10.0': - resolution: {integrity: sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/typescript-estree@7.10.0': - resolution: {integrity: sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/utils@7.10.0': - resolution: {integrity: sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - - '@typescript-eslint/visitor-keys@7.10.0': - resolution: {integrity: sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@ungap/structured-clone@1.2.0': - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - - '@vercel/postgres@0.8.0': - resolution: {integrity: sha512-/QUV9ExwaNdKooRjOQqvrKNVnRvsaXeukPNI5DB1ovUTesglfR/fparw7ngo1KUWWKIVpEj2TRrA+ObRHRdaLg==} - engines: {node: '>=14.6'} - - '@vitest/expect@1.6.0': - resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} - - '@vitest/runner@1.6.0': - resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} - - '@vitest/snapshot@1.6.0': - resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} - - '@vitest/spy@1.6.0': - resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} - - '@vitest/utils@1.6.0': - resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} - - acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - - aggregate-error@4.0.1: - resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} - engines: {node: '>=12'} - - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ansi-escapes@6.2.1: - resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} - engines: {node: '>=14.16'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.0.1: - resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - - ansicolors@0.3.2: - resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} - - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - array-find-index@1.0.2: - resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} - engines: {node: '>=0.10.0'} - - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - - arrgv@1.0.2: - resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} - engines: {node: '>=8.0.0'} - - arrify@3.0.0: - resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} - engines: {node: '>=12'} - - as-table@1.0.55: - resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} - - asn1@0.2.6: - resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} - - assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - ava@5.3.1: - resolution: {integrity: sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==} - engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} - hasBin: true - peerDependencies: - '@ava/typescript': '*' - peerDependenciesMeta: - '@ava/typescript': - optional: true - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - bcrypt-pbkdf@1.0.2: - resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} - - better-sqlite3@9.6.0: - resolution: {integrity: sha512-yR5HATnqeYNVnkaUTf4bOP2dJSnyhP4puJN/QPRyx4YkBEEUxib422n2XzPqDEHjQQqazoYoADdAm5vE15+dAQ==} - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - - blake3-wasm@2.1.5: - resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} - - blueimp-md5@2.19.0: - resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} - - bowser@2.11.0: - resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - - bufferutil@4.0.8: - resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} - engines: {node: '>=6.14.2'} - - buildcheck@0.0.6: - resolution: {integrity: sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==} - engines: {node: '>=10.0.0'} - - bundle-require@4.1.0: - resolution: {integrity: sha512-FeArRFM+ziGkRViKRnSTbHZc35dgmR9yNog05Kn0+ItI59pOAISGvnnIwW1WgFZQW59IxD9QpJnUPkdIPfZuXg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - peerDependencies: - esbuild: '>=0.17' - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - callsites@4.1.0: - resolution: {integrity: sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==} - engines: {node: '>=12.20'} - - camelcase@7.0.1: - resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} - engines: {node: '>=14.16'} - - capnp-ts@0.7.0: - resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} - - cardinal@2.1.1: - resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} - hasBin: true - - cbor@8.1.0: - resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} - engines: {node: '>=12.19'} - - chai@4.4.1: - resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} - engines: {node: '>=4'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chalk@5.3.0: - resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - - char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - - check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - - chunkd@2.0.1: - resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} - - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - - ci-parallel-vars@1.0.1: - resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} - - clean-stack@4.2.0: - resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} - engines: {node: '>=12'} - - clean-yaml-object@0.1.0: - resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} - engines: {node: '>=0.10.0'} - - cli-color@2.0.4: - resolution: {integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==} - engines: {node: '>=0.10'} - - cli-table3@0.6.5: - resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} - engines: {node: 10.* || >= 12.*} - - cli-truncate@3.1.0: - resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - code-excerpt@4.0.0: - resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - colors@1.4.0: - resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} - engines: {node: '>=0.1.90'} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - - commander@12.1.0: - resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} - engines: {node: '>=18'} - - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - - common-path-prefix@3.0.0: - resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - concordance@5.0.4: - resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} - engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} - - confbox@0.1.7: - resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} - - convert-to-spaces@2.0.1: - resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - cookie@0.5.0: - resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} - engines: {node: '>= 0.6'} - - copy-anything@3.0.5: - resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} - engines: {node: '>=12.13'} - - cpu-features@0.0.10: - resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==} - engines: {node: '>=10.0.0'} - - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - - currently-unhandled@0.4.1: - resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} - engines: {node: '>=0.10.0'} - - d@1.0.2: - resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} - engines: {node: '>=0.12'} - - data-uri-to-buffer@2.0.2: - resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} - - data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} - - date-time@3.1.0: - resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} - engines: {node: '>=6'} - - debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - - deep-eql@4.1.3: - resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} - engines: {node: '>=6'} - - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - denque@2.1.0: - resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} - engines: {node: '>=0.10'} - - detect-libc@2.0.2: - resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} - engines: {node: '>=8'} - - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} - engines: {node: '>=8'} - - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - difflib@0.2.4: - resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} - - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - - docker-modem@3.0.8: - resolution: {integrity: sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ==} - engines: {node: '>= 8.0'} - - dockerode@3.3.5: - resolution: {integrity: sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA==} - engines: {node: '>= 8.0'} - - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - - dotenv@16.4.5: - resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} - engines: {node: '>=12'} - - dreamopt@0.8.0: - resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==} - engines: {node: '>=0.4.0'} - - drizzle-kit@0.21.2: - resolution: {integrity: sha512-U87IhZyCt/9d0ZT/Na3KFJVY31tSxtTx/n9UMcWFpW/5c2Ede39xiCG5efNV/0iimsv97UIRtDI0ldLBW5lbcg==} - hasBin: true - - drizzle-orm@0.32.0-85c8008: - resolution: {integrity: sha512-gHLqGZz0eqAvSw4vq46sHRV8qLHxrbuCVlwaVZ1t4ntyH8csyCKEXTWO78cBJwYUpz7BCSzqVX+5ZYa/QM+/Gw==} - peerDependencies: - '@aws-sdk/client-rds-data': '>=3' - '@cloudflare/workers-types': '>=3' - '@electric-sql/pglite': '>=0.1.1' - '@libsql/client': '*' - '@neondatabase/serverless': '>=0.1' - '@op-engineering/op-sqlite': '>=2' - '@opentelemetry/api': ^1.4.1 - '@planetscale/database': '>=1' - '@tidbcloud/serverless': '*' - '@types/better-sqlite3': '*' - '@types/pg': '*' - '@types/react': '>=18' - '@types/sql.js': '*' - '@vercel/postgres': '>=0.8.0' - '@xata.io/client': '*' - better-sqlite3: '>=7' - bun-types: '*' - expo-sqlite: '>=13.2.0' - knex: '*' - kysely: '*' - mysql2: '>=2' - pg: '>=8' - postgres: '>=3' - react: '>=18' - sql.js: '>=1' - sqlite3: '>=5' - peerDependenciesMeta: - '@aws-sdk/client-rds-data': - optional: true - '@cloudflare/workers-types': - optional: true - '@electric-sql/pglite': - optional: true - '@libsql/client': - optional: true - '@neondatabase/serverless': - optional: true - '@op-engineering/op-sqlite': - optional: true - '@opentelemetry/api': - optional: true - '@planetscale/database': - optional: true - '@tidbcloud/serverless': - optional: true - '@types/better-sqlite3': - optional: true - '@types/pg': - optional: true - '@types/react': - optional: true - '@types/sql.js': - optional: true - '@vercel/postgres': - optional: true - '@xata.io/client': - optional: true - better-sqlite3: - optional: true - bun-types: - optional: true - expo-sqlite: - optional: true - knex: - optional: true - kysely: - optional: true - mysql2: - optional: true - pg: - optional: true - postgres: - optional: true - react: - optional: true - sql.js: - optional: true - sqlite3: - optional: true - - duplexer@0.1.2: - resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} - - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - emittery@1.0.3: - resolution: {integrity: sha512-tJdCJitoy2lrC2ldJcqN4vkqJ00lT+tOWNT1hBJjO/3FDMJa5TTIiYGCKGkn/WfCyOzUMObeohbVTj00fhiLiA==} - engines: {node: '>=14.16'} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - emojilib@2.4.0: - resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} - - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - - env-paths@3.0.0: - resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - es5-ext@0.10.64: - resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} - engines: {node: '>=0.10'} - - es6-iterator@2.0.3: - resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - - es6-symbol@3.1.4: - resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} - engines: {node: '>=0.12'} - - es6-weak-map@2.0.3: - resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} - - esbuild-android-64@0.14.54: - resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - esbuild-android-arm64@0.14.54: - resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - esbuild-darwin-64@0.14.54: - resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - esbuild-darwin-arm64@0.14.54: - resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - esbuild-freebsd-64@0.14.54: - resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - esbuild-freebsd-arm64@0.14.54: - resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - esbuild-linux-32@0.14.54: - resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - esbuild-linux-64@0.14.54: - resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - esbuild-linux-arm64@0.14.54: - resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - esbuild-linux-arm@0.14.54: - resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - esbuild-linux-mips64le@0.14.54: - resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - esbuild-linux-ppc64le@0.14.54: - resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - esbuild-linux-riscv64@0.14.54: - resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - esbuild-linux-s390x@0.14.54: - resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - esbuild-netbsd-64@0.14.54: - resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - esbuild-node-externals@1.13.1: - resolution: {integrity: sha512-ho4Lokc6iMB1lWbb2tWJ6otien+3Kfoaxe0fy7NUNgVuLnfmlW+GRINftTVUGtTVY/dapuwUu/CvFylYNwzkMA==} - engines: {node: '>=12'} - peerDependencies: - esbuild: 0.12 - 0.21 - - esbuild-openbsd-64@0.14.54: - resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - esbuild-register@3.5.0: - resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==} - peerDependencies: - esbuild: '>=0.12 <1' - - esbuild-sunos-64@0.14.54: - resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - esbuild-windows-32@0.14.54: - resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - esbuild-windows-64@0.14.54: - resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - esbuild-windows-arm64@0.14.54: - resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - esbuild@0.14.54: - resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.17.19: - resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.18.20: - resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.19.12: - resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.20.2: - resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} - engines: {node: '>=12'} - hasBin: true - - escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} - engines: {node: '>=6'} - - escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - escape-string-regexp@5.0.0: - resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} - engines: {node: '>=12'} - - eslint-config-prettier@9.1.0: - resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - - eslint-plugin-prettier@5.1.3: - resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - '@types/eslint': '>=8.0.0' - eslint: '>=8.0.0' - eslint-config-prettier: '*' - prettier: '>=3.0.0' - peerDependenciesMeta: - '@types/eslint': - optional: true - eslint-config-prettier: - optional: true - - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - - esniff@2.0.1: - resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} - engines: {node: '>=0.10'} - - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - - esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - estree-walker@0.6.1: - resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - event-emitter@0.3.5: - resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} - - event-stream@3.3.4: - resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} - - execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - - exit-hook@2.2.1: - resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} - engines: {node: '>=6'} - - expand-template@2.0.3: - resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} - engines: {node: '>=6'} - - ext@1.7.0: - resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fast-xml-parser@4.2.5: - resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} - hasBin: true - - fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - - fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} - - fflate@0.8.2: - resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} - - figures@5.0.0: - resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} - engines: {node: '>=14'} - - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - find-up@6.3.0: - resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - - flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - - foreground-child@3.1.1: - resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} - engines: {node: '>=14'} - - form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - - formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - - from@0.1.7: - resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} - - fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - - fs-extra@11.2.0: - resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} - engines: {node: '>=14.14'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - fx@34.0.0: - resolution: {integrity: sha512-/fZih3/WLsrtlaj2mahjWxAmyuikmcl3D5kKPqLtFmEilLsy9wp0+/vEmfvYXXhwJc+ajtCFDCf+yttXmPMHSQ==} - hasBin: true - - generate-function@2.3.1: - resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - - get-port@6.1.2: - resolution: {integrity: sha512-BrGGraKm2uPqurfGVj/z97/zv8dPleC6x9JBNRTrDNtCkkRF4rPwrQXFgL7+I+q8QSdU4ntLQX2D7KIxSy8nGw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - get-source@2.0.12: - resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} - - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - - get-tsconfig@4.7.5: - resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} - - github-from-package@0.0.0: - resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - - glob@10.3.15: - resolution: {integrity: sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==} - engines: {node: '>=16 || 14 >=14.18'} - hasBin: true - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - - glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} - - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - - globby@13.2.2: - resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - hanji@0.0.5: - resolution: {integrity: sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - heap@0.2.7: - resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} - - hono@4.3.9: - resolution: {integrity: sha512-6c5LVE23HnIS8iBhY+XPmYJlPeeClznOi7mBNsAsJCgxo8Ciz75LTjqRUf5wv4RYq8kL+1KPLUZHCtKmbZssNg==} - engines: {node: '>=16.0.0'} - - human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore-by-default@2.1.0: - resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} - engines: {node: '>=10 <11 || >=12 <13 || >=14'} - - ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} - engines: {node: '>= 4'} - - import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - indent-string@5.0.0: - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} - engines: {node: '>=12'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - - irregular-plurals@3.5.0: - resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} - engines: {node: '>=8'} - - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - - is-error@2.2.2: - resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-fullwidth-code-point@4.0.0: - resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} - engines: {node: '>=12'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - - is-plain-object@5.0.0: - resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} - engines: {node: '>=0.10.0'} - - is-promise@2.2.2: - resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} - - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - - is-property@1.0.2: - resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - is-unicode-supported@1.3.0: - resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} - engines: {node: '>=12'} - - is-what@4.1.16: - resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} - engines: {node: '>=12.13'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - jackspeak@2.3.6: - resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} - engines: {node: '>=14'} - - joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} - - js-base64@3.7.7: - resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} - - js-string-escape@1.0.1: - resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} - engines: {node: '>= 0.8'} - - js-tokens@9.0.0: - resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==} - - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-diff@0.9.0: - resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==} - hasBin: true - - json-diff@1.0.6: - resolution: {integrity: sha512-tcFIPRdlc35YkYdGxcamJjllUhXWv4n2rK9oJ2RsAzV4FBkuV4ojKEDgcZ+kpKxDmJKv+PFK65+1tVVOnSeEqA==} - hasBin: true - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - libsql@0.2.0: - resolution: {integrity: sha512-ELBRqhpJx5Dap0187zKQnntZyk4EjlDHSrjIVL8t+fQ5e8IxbQTeYgZgigMjB1EvrETdkm0Y0VxBGhzPQ+t0Jg==} - cpu: [x64, arm64] - os: [darwin, linux, win32] - - lilconfig@3.1.1: - resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==} - engines: {node: '>=14'} - - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - load-json-file@7.0.1: - resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - load-tsconfig@0.2.5: - resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - local-pkg@0.5.0: - resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} - engines: {node: '>=14'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - locate-path@7.2.0: - resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - - lodash.throttle@4.1.1: - resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - - long@4.0.0: - resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} - - loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} - - lru-cache@10.2.2: - resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} - engines: {node: 14 || >=16.14} - - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - - lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} - - lru-queue@0.1.0: - resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} - - magic-string@0.25.9: - resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - - magic-string@0.30.10: - resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} - - map-age-cleaner@0.1.3: - resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} - engines: {node: '>=6'} - - map-stream@0.1.0: - resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} - - marked-terminal@6.2.0: - resolution: {integrity: sha512-ubWhwcBFHnXsjYNsu+Wndpg0zhY4CahSpPlA70PlO0rR9r2sZpkyU+rkCsOWH+KMEkx847UpALON+HWgxowFtw==} - engines: {node: '>=16.0.0'} - peerDependencies: - marked: '>=1 <12' - - marked@9.1.6: - resolution: {integrity: sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==} - engines: {node: '>= 16'} - hasBin: true - - matcher@5.0.0: - resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - md5-hex@3.0.1: - resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} - engines: {node: '>=8'} - - mem@9.0.2: - resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} - engines: {node: '>=12.20'} - - memoizee@0.4.15: - resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime@3.0.0: - resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} - engines: {node: '>=10.0.0'} - hasBin: true - - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - - miniflare@3.20240512.0: - resolution: {integrity: sha512-X0PlKR0AROKpxFoJNmRtCMIuJxj+ngEcyTOlEokj2rAQ0TBwUhB4/1uiPvdI6ofW5NugPOD1uomAv+gLjwsLDQ==} - engines: {node: '>=16.13'} - hasBin: true - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - - minimatch@7.4.6: - resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} - engines: {node: '>=10'} - - minimatch@9.0.4: - resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} - engines: {node: '>=16 || 14 >=14.17'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass@7.1.1: - resolution: {integrity: sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==} - engines: {node: '>=16 || 14 >=14.17'} - - mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - - mlly@1.7.0: - resolution: {integrity: sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==} - - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - mustache@4.2.0: - resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} - hasBin: true - - mysql2@2.3.3: - resolution: {integrity: sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==} - engines: {node: '>= 8.0'} - - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - - named-placeholders@1.1.3: - resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} - engines: {node: '>=12.0.0'} - - nan@2.19.0: - resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} - - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - napi-build-utils@1.0.2: - resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - next-tick@1.1.0: - resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} - - node-abi@3.62.0: - resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==} - engines: {node: '>=10'} - - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - - node-emoji@2.1.3: - resolution: {integrity: sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==} - engines: {node: '>=18'} - - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - - node-fetch@3.3.1: - resolution: {integrity: sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - node-forge@1.3.1: - resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} - engines: {node: '>= 6.13.0'} - - node-gyp-build@4.8.1: - resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} - hasBin: true - - nofilter@3.1.0: - resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} - engines: {node: '>=12.19'} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - obuf@1.1.2: - resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - p-defer@1.0.0: - resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} - engines: {node: '>=4'} - - p-event@5.0.1: - resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-limit@4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - p-limit@5.0.0: - resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} - engines: {node: '>=18'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - p-locate@6.0.0: - resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - p-map@5.5.0: - resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} - engines: {node: '>=12'} - - p-timeout@5.1.0: - resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} - engines: {node: '>=12'} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse-ms@3.0.0: - resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} - engines: {node: '>=12'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-exists@5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - path-to-regexp@6.2.2: - resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} - - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - - pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - - pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - - pause-stream@0.0.11: - resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} - - pg-cloudflare@1.1.1: - resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} - - pg-connection-string@2.6.4: - resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} - - pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - - pg-numeric@1.0.2: - resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} - engines: {node: '>=4'} - - pg-pool@3.6.2: - resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==} - peerDependencies: - pg: '>=8.0' - - pg-protocol@1.6.1: - resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==} - - pg-types@2.2.0: - resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} - engines: {node: '>=4'} - - pg-types@4.0.2: - resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} - engines: {node: '>=10'} - - pg@8.11.5: - resolution: {integrity: sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==} - engines: {node: '>= 8.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true - - pgpass@1.0.5: - resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - - picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} - engines: {node: '>= 6'} - - pkg-conf@4.0.0: - resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - pkg-types@1.1.1: - resolution: {integrity: sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==} - - plur@5.1.0: - resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - - postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} - engines: {node: ^10 || ^12 || >=14} - - postgres-array@2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - - postgres-array@3.0.2: - resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} - engines: {node: '>=12'} - - postgres-bytea@1.0.0: - resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} - engines: {node: '>=0.10.0'} - - postgres-bytea@3.0.0: - resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} - engines: {node: '>= 6'} - - postgres-date@1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} - - postgres-date@2.1.0: - resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} - engines: {node: '>=12'} - - postgres-interval@1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} - - postgres-interval@3.0.0: - resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} - engines: {node: '>=12'} - - postgres-range@1.1.4: - resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} - - postgres@3.4.4: - resolution: {integrity: sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==} - engines: {node: '>=12'} - - prebuild-install@7.1.2: - resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} - engines: {node: '>=10'} - hasBin: true - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} - - prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - pretty-ms@8.0.0: - resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} - engines: {node: '>=14.16'} - - printable-characters@1.0.42: - resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} - - ps-tree@1.2.0: - resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} - engines: {node: '>= 0.10'} - hasBin: true - - pump@3.0.0: - resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - - redeyed@2.1.1: - resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - resolve.exports@2.0.2: - resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} - engines: {node: '>=10'} - - resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true - - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true - - rollup-plugin-inject@3.0.2: - resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==} - deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject. - - rollup-plugin-node-polyfills@0.2.1: - resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==} - - rollup-pluginutils@2.8.2: - resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - - rollup@4.17.2: - resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - selfsigned@2.4.1: - resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} - engines: {node: '>=10'} - - semver@7.6.2: - resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} - engines: {node: '>=10'} - hasBin: true - - seq-queue@0.0.5: - resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} - - serialize-error@7.0.1: - resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} - engines: {node: '>=10'} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - - simple-get@4.0.1: - resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} - - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - skin-tone@2.0.0: - resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} - engines: {node: '>=8'} - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - slash@4.0.0: - resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} - engines: {node: '>=12'} - - slice-ansi@5.0.0: - resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} - engines: {node: '>=12'} - - source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} - engines: {node: '>=0.10.0'} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} - - sourcemap-codec@1.4.8: - resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} - deprecated: Please use @jridgewell/sourcemap-codec instead - - split-ca@1.0.1: - resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} - - split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - - split@0.3.3: - resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} - - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - - sqlstring@2.3.3: - resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} - engines: {node: '>= 0.6'} - - ssh2@1.15.0: - resolution: {integrity: sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==} - engines: {node: '>=10.16.0'} - - stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - stacktracey@2.1.8: - resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==} - - std-env@3.7.0: - resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} - - stoppable@1.1.0: - resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} - engines: {node: '>=4', npm: '>=6'} - - stream-combiner@0.0.4: - resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - strip-literal@2.1.0: - resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==} - - strnum@1.0.5: - resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} - - sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - - superjson@2.2.1: - resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} - engines: {node: '>=16'} - - supertap@3.0.1: - resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-hyperlinks@3.0.0: - resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} - engines: {node: '>=14.18'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - synckit@0.8.8: - resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} - engines: {node: ^14.18.0 || >=16.0.0} - - tar-fs@2.0.1: - resolution: {integrity: sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==} - - tar-fs@2.1.1: - resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} - - tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} - - temp-dir@3.0.0: - resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} - engines: {node: '>=14.16'} - - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - - through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - - time-zone@1.0.0: - resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} - engines: {node: '>=4'} - - timers-ext@0.1.7: - resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==} - - tinybench@2.8.0: - resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} - - tinypool@0.8.4: - resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} - engines: {node: '>=14.0.0'} - - tinyspy@2.2.1: - resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} - engines: {node: '>=14.0.0'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - - tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - - ts-api-utils@1.3.0: - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' - - ts-expose-internals-conditionally@1.0.0-empty.0: - resolution: {integrity: sha512-F8m9NOF6ZhdOClDVdlM8gj3fDCav4ZIFSs/EI3ksQbAAXVSCN/Jh5OCJDDZWBuBy9psFc6jULGDlPwjMYMhJDw==} - - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - - tsconfck@3.0.3: - resolution: {integrity: sha512-4t0noZX9t6GcPTfBAbIbbIU4pfpCwh0ueq3S4O/5qXI1VwK1outmxhe9dOiEWqMz3MW2LKgDTpqWV+37IWuVbA==} - engines: {node: ^18 || >=20} - hasBin: true - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - - tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - - tsup@8.0.2: - resolution: {integrity: sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - '@microsoft/api-extractor': ^7.36.0 - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.5.0' - peerDependenciesMeta: - '@microsoft/api-extractor': - optional: true - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true - - tsx@3.14.0: - resolution: {integrity: sha512-xHtFaKtHxM9LOklMmJdI3BEnQq/D5F73Of2E1GDrITi9sgoVkvIsrQUTY1G8FlmGtA+awCI4EBlTRRYxkL2sRg==} - hasBin: true - - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - - tweetnacl@0.14.5: - resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - - type-fest@0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} - - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - - type@2.7.2: - resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} - - typescript@5.3.3: - resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} - engines: {node: '>=14.17'} - hasBin: true - - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} - engines: {node: '>=14.17'} - hasBin: true - - ufo@1.5.3: - resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} - - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - - undici@5.28.4: - resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} - engines: {node: '>=14.0'} - - unicode-emoji-modifier-base@1.0.0: - resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} - engines: {node: '>=4'} - - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - utf-8-validate@6.0.3: - resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==} - engines: {node: '>=6.14.2'} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - - validate-npm-package-name@5.0.1: - resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - vite-node@1.6.0: - resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - - vite-tsconfig-paths@4.3.2: - resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} - peerDependencies: - vite: '*' - peerDependenciesMeta: - vite: - optional: true - - vite@5.2.11: - resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - - vitest@1.6.0: - resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 1.6.0 - '@vitest/ui': 1.6.0 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - - webpod@0.0.2: - resolution: {integrity: sha512-cSwwQIeg8v4i3p4ajHhwgR7N6VyxAf+KYSSsY6Pd3aETE+xEU4vbitz7qQkB0I321xnhDdgtxuiSfk5r/FVtjg==} - hasBin: true - - well-known-symbols@2.0.0: - resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} - engines: {node: '>=6'} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - which@3.0.1: - resolution: {integrity: sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - hasBin: true - - why-is-node-running@2.2.2: - resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} - engines: {node: '>=8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - - workerd@1.20240512.0: - resolution: {integrity: sha512-VUBmR1PscAPHEE0OF/G2K7/H1gnr9aDWWZzdkIgWfNKkv8dKFCT75H+GJtUHjfwqz3rYCzaNZmatSXOpLGpF8A==} - engines: {node: '>=16'} - hasBin: true - - wrangler@3.57.0: - resolution: {integrity: sha512-izK3AZtlFoTq8N0EZjLOQ7hqwsjaXCc1cbNKuhsLJjDX1jB1YZBDPhIhtXL4VVzkJAcH+0Zw2gguOePFCHNaxw==} - engines: {node: '>=16.17.0'} - hasBin: true - peerDependencies: - '@cloudflare/workers-types': ^4.20240512.0 - peerDependenciesMeta: - '@cloudflare/workers-types': - optional: true - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - write-file-atomic@5.0.1: - resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - ws@8.14.2: - resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - ws@8.17.0: - resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - - xxhash-wasm@1.0.2: - resolution: {integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - - yaml@2.4.2: - resolution: {integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==} - engines: {node: '>= 14'} - hasBin: true - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - yocto-queue@1.0.0: - resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} - engines: {node: '>=12.20'} - - youch@3.3.3: - resolution: {integrity: sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==} - - zod@3.23.8: - resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} - - zx@7.2.3: - resolution: {integrity: sha512-QODu38nLlYXg/B/Gw7ZKiZrvPkEsjPN3LQ5JFXM7h0JvwhEdPNNl+4Ao1y4+o3CLNiDUNcwzQYZ4/Ko7kKzCMA==} - engines: {node: '>= 16.0.0'} - hasBin: true - -snapshots: - - '@andrewbranch/untar.js@1.0.3': {} - - '@arethetypeswrong/cli@0.15.3': - dependencies: - '@arethetypeswrong/core': 0.15.1 - chalk: 4.1.2 - cli-table3: 0.6.5 - commander: 10.0.1 - marked: 9.1.6 - marked-terminal: 6.2.0(marked@9.1.6) - semver: 7.6.2 - - '@arethetypeswrong/core@0.15.1': - dependencies: - '@andrewbranch/untar.js': 1.0.3 - fflate: 0.8.2 - semver: 7.6.2 - ts-expose-internals-conditionally: 1.0.0-empty.0 - typescript: 5.3.3 - validate-npm-package-name: 5.0.1 - - '@aws-crypto/ie11-detection@3.0.0': - dependencies: - tslib: 1.14.1 - - '@aws-crypto/sha256-browser@3.0.0': - dependencies: - '@aws-crypto/ie11-detection': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-crypto/supports-web-crypto': 3.0.0 - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-locate-window': 3.568.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - - '@aws-crypto/sha256-js@3.0.0': - dependencies: - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.577.0 - tslib: 1.14.1 - - '@aws-crypto/supports-web-crypto@3.0.0': - dependencies: - tslib: 1.14.1 - - '@aws-crypto/util@3.0.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - - '@aws-sdk/client-rds-data@3.577.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.577.0(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/client-sts': 3.577.0 - '@aws-sdk/core': 3.576.0 - '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.577.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.577.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0)': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.577.0 - '@aws-sdk/core': 3.576.0 - '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.577.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.577.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sts' - - aws-crt - - '@aws-sdk/client-sso@3.577.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.576.0 - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.577.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.577.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-sts@3.577.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.577.0(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/core': 3.576.0 - '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.577.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.577.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/core@3.576.0': - dependencies: - '@smithy/core': 2.0.1 - '@smithy/protocol-http': 4.0.0 - '@smithy/signature-v4': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - fast-xml-parser: 4.2.5 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-env@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-http@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/node-http-handler': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/util-stream': 3.0.1 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-ini@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0)': - dependencies: - '@aws-sdk/client-sts': 3.577.0 - '@aws-sdk/credential-provider-env': 3.577.0 - '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0)) - '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/types': 3.577.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - - '@aws-sdk/credential-provider-node@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0)': - dependencies: - '@aws-sdk/credential-provider-env': 3.577.0 - '@aws-sdk/credential-provider-http': 3.577.0 - '@aws-sdk/credential-provider-ini': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0)) - '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/types': 3.577.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - - aws-crt - - '@aws-sdk/credential-provider-process@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-sso@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))': - dependencies: - '@aws-sdk/client-sso': 3.577.0 - '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0)) - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - - '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.577.0)': - dependencies: - '@aws-sdk/client-sts': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/middleware-host-header@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/middleware-logger@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/middleware-recursion-detection@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/middleware-user-agent@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.577.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/region-config-resolver@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))': - dependencies: - '@aws-sdk/client-sso-oidc': 3.577.0(@aws-sdk/client-sts@3.577.0) - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/types@3.577.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/util-endpoints@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/types': 3.0.0 - '@smithy/util-endpoints': 2.0.0 - tslib: 2.6.2 - - '@aws-sdk/util-locate-window@3.568.0': - dependencies: - tslib: 2.6.2 - - '@aws-sdk/util-user-agent-browser@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/types': 3.0.0 - bowser: 2.11.0 - tslib: 2.6.2 - - '@aws-sdk/util-user-agent-node@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/util-utf8-browser@3.259.0': - dependencies: - tslib: 2.6.2 - - '@balena/dockerignore@1.0.2': {} - - '@cloudflare/kv-asset-handler@0.3.2': - dependencies: - mime: 3.0.0 - - '@cloudflare/workerd-darwin-64@1.20240512.0': - optional: true - - '@cloudflare/workerd-darwin-arm64@1.20240512.0': - optional: true - - '@cloudflare/workerd-linux-64@1.20240512.0': - optional: true - - '@cloudflare/workerd-linux-arm64@1.20240512.0': - optional: true - - '@cloudflare/workerd-windows-64@1.20240512.0': - optional: true - - '@cloudflare/workers-types@4.20240512.0': {} - - '@colors/colors@1.5.0': - optional: true - - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - - '@electric-sql/pglite@0.1.5': {} - - '@esbuild-kit/core-utils@3.3.2': - dependencies: - esbuild: 0.18.20 - source-map-support: 0.5.21 - - '@esbuild-kit/esm-loader@2.6.5': - dependencies: - '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.7.5 - - '@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19)': - dependencies: - esbuild: 0.17.19 - - '@esbuild-plugins/node-modules-polyfill@0.2.2(esbuild@0.17.19)': - dependencies: - esbuild: 0.17.19 - escape-string-regexp: 4.0.0 - rollup-plugin-node-polyfills: 0.2.1 - - '@esbuild/aix-ppc64@0.19.12': - optional: true - - '@esbuild/aix-ppc64@0.20.2': - optional: true - - '@esbuild/android-arm64@0.17.19': - optional: true - - '@esbuild/android-arm64@0.18.20': - optional: true - - '@esbuild/android-arm64@0.19.12': - optional: true - - '@esbuild/android-arm64@0.20.2': - optional: true - - '@esbuild/android-arm@0.17.19': - optional: true - - '@esbuild/android-arm@0.18.20': - optional: true - - '@esbuild/android-arm@0.19.12': - optional: true - - '@esbuild/android-arm@0.20.2': - optional: true - - '@esbuild/android-x64@0.17.19': - optional: true - - '@esbuild/android-x64@0.18.20': - optional: true - - '@esbuild/android-x64@0.19.12': - optional: true - - '@esbuild/android-x64@0.20.2': - optional: true - - '@esbuild/darwin-arm64@0.17.19': - optional: true - - '@esbuild/darwin-arm64@0.18.20': - optional: true - - '@esbuild/darwin-arm64@0.19.12': - optional: true - - '@esbuild/darwin-arm64@0.20.2': - optional: true - - '@esbuild/darwin-x64@0.17.19': - optional: true - - '@esbuild/darwin-x64@0.18.20': - optional: true - - '@esbuild/darwin-x64@0.19.12': - optional: true - - '@esbuild/darwin-x64@0.20.2': - optional: true - - '@esbuild/freebsd-arm64@0.17.19': - optional: true - - '@esbuild/freebsd-arm64@0.18.20': - optional: true - - '@esbuild/freebsd-arm64@0.19.12': - optional: true - - '@esbuild/freebsd-arm64@0.20.2': - optional: true - - '@esbuild/freebsd-x64@0.17.19': - optional: true - - '@esbuild/freebsd-x64@0.18.20': - optional: true - - '@esbuild/freebsd-x64@0.19.12': - optional: true - - '@esbuild/freebsd-x64@0.20.2': - optional: true - - '@esbuild/linux-arm64@0.17.19': - optional: true - - '@esbuild/linux-arm64@0.18.20': - optional: true - - '@esbuild/linux-arm64@0.19.12': - optional: true - - '@esbuild/linux-arm64@0.20.2': - optional: true - - '@esbuild/linux-arm@0.17.19': - optional: true - - '@esbuild/linux-arm@0.18.20': - optional: true - - '@esbuild/linux-arm@0.19.12': - optional: true - - '@esbuild/linux-arm@0.20.2': - optional: true - - '@esbuild/linux-ia32@0.17.19': - optional: true - - '@esbuild/linux-ia32@0.18.20': - optional: true - - '@esbuild/linux-ia32@0.19.12': - optional: true - - '@esbuild/linux-ia32@0.20.2': - optional: true - - '@esbuild/linux-loong64@0.14.54': - optional: true - - '@esbuild/linux-loong64@0.17.19': - optional: true - - '@esbuild/linux-loong64@0.18.20': - optional: true - - '@esbuild/linux-loong64@0.19.12': - optional: true - - '@esbuild/linux-loong64@0.20.2': - optional: true - - '@esbuild/linux-mips64el@0.17.19': - optional: true - - '@esbuild/linux-mips64el@0.18.20': - optional: true - - '@esbuild/linux-mips64el@0.19.12': - optional: true - - '@esbuild/linux-mips64el@0.20.2': - optional: true - - '@esbuild/linux-ppc64@0.17.19': - optional: true - - '@esbuild/linux-ppc64@0.18.20': - optional: true - - '@esbuild/linux-ppc64@0.19.12': - optional: true - - '@esbuild/linux-ppc64@0.20.2': - optional: true - - '@esbuild/linux-riscv64@0.17.19': - optional: true - - '@esbuild/linux-riscv64@0.18.20': - optional: true - - '@esbuild/linux-riscv64@0.19.12': - optional: true - - '@esbuild/linux-riscv64@0.20.2': - optional: true - - '@esbuild/linux-s390x@0.17.19': - optional: true - - '@esbuild/linux-s390x@0.18.20': - optional: true - - '@esbuild/linux-s390x@0.19.12': - optional: true - - '@esbuild/linux-s390x@0.20.2': - optional: true - - '@esbuild/linux-x64@0.17.19': - optional: true - - '@esbuild/linux-x64@0.18.20': - optional: true - - '@esbuild/linux-x64@0.19.12': - optional: true - - '@esbuild/linux-x64@0.20.2': - optional: true - - '@esbuild/netbsd-x64@0.17.19': - optional: true - - '@esbuild/netbsd-x64@0.18.20': - optional: true - - '@esbuild/netbsd-x64@0.19.12': - optional: true - - '@esbuild/netbsd-x64@0.20.2': - optional: true - - '@esbuild/openbsd-x64@0.17.19': - optional: true - - '@esbuild/openbsd-x64@0.18.20': - optional: true - - '@esbuild/openbsd-x64@0.19.12': - optional: true - - '@esbuild/openbsd-x64@0.20.2': - optional: true - - '@esbuild/sunos-x64@0.17.19': - optional: true - - '@esbuild/sunos-x64@0.18.20': - optional: true - - '@esbuild/sunos-x64@0.19.12': - optional: true - - '@esbuild/sunos-x64@0.20.2': - optional: true - - '@esbuild/win32-arm64@0.17.19': - optional: true - - '@esbuild/win32-arm64@0.18.20': - optional: true - - '@esbuild/win32-arm64@0.19.12': - optional: true - - '@esbuild/win32-arm64@0.20.2': - optional: true - - '@esbuild/win32-ia32@0.17.19': - optional: true - - '@esbuild/win32-ia32@0.18.20': - optional: true - - '@esbuild/win32-ia32@0.19.12': - optional: true - - '@esbuild/win32-ia32@0.20.2': - optional: true - - '@esbuild/win32-x64@0.17.19': - optional: true - - '@esbuild/win32-x64@0.18.20': - optional: true - - '@esbuild/win32-x64@0.19.12': - optional: true - - '@esbuild/win32-x64@0.20.2': - optional: true - - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': - dependencies: - eslint: 8.57.0 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.10.0': {} - - '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@8.57.0': {} - - '@ewoudenberg/difflib@0.1.0': - dependencies: - heap: 0.2.7 - - '@fastify/busboy@2.1.1': {} - - '@hono/node-server@1.11.1': {} - - '@hono/zod-validator@0.2.1(hono@4.3.9)(zod@3.23.8)': - dependencies: - hono: 4.3.9 - zod: 3.23.8 - - '@humanwhocodes/config-array@0.11.14': - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/object-schema@2.0.3': {} - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.8 - - '@jridgewell/gen-mapping@0.3.5': - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.25 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/set-array@1.2.1': {} - - '@jridgewell/sourcemap-codec@1.4.15': {} - - '@jridgewell/trace-mapping@0.3.25': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - - '@libsql/client@0.4.3(bufferutil@4.0.8)(utf-8-validate@6.0.3)': - dependencies: - '@libsql/core': 0.4.3 - '@libsql/hrana-client': 0.5.6(bufferutil@4.0.8)(utf-8-validate@6.0.3) - js-base64: 3.7.7 - optionalDependencies: - libsql: 0.2.0 - transitivePeerDependencies: - - bufferutil - - encoding - - utf-8-validate - - '@libsql/core@0.4.3': - dependencies: - js-base64: 3.7.7 - - '@libsql/darwin-arm64@0.2.0': - optional: true - - '@libsql/darwin-x64@0.2.0': - optional: true - - '@libsql/hrana-client@0.5.6(bufferutil@4.0.8)(utf-8-validate@6.0.3)': - dependencies: - '@libsql/isomorphic-fetch': 0.1.12 - '@libsql/isomorphic-ws': 0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3) - js-base64: 3.7.7 - node-fetch: 3.3.2 - transitivePeerDependencies: - - bufferutil - - encoding - - utf-8-validate - - '@libsql/isomorphic-fetch@0.1.12': - dependencies: - '@types/node-fetch': 2.6.11 - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - - '@libsql/isomorphic-ws@0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3)': - dependencies: - '@types/ws': 8.5.10 - ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@libsql/linux-arm64-gnu@0.2.0': - optional: true - - '@libsql/linux-arm64-musl@0.2.0': - optional: true - - '@libsql/linux-x64-gnu@0.2.0': - optional: true - - '@libsql/linux-x64-musl@0.2.0': - optional: true - - '@libsql/win32-x64-msvc@0.2.0': - optional: true - - '@neon-rs/load@0.0.4': - optional: true - - '@neondatabase/serverless@0.7.2': - dependencies: - '@types/pg': 8.6.6 - - '@neondatabase/serverless@0.9.3': - dependencies: - '@types/pg': 8.11.6 - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 - - '@originjs/vite-plugin-commonjs@1.0.3': - dependencies: - esbuild: 0.14.54 - - '@pkgjs/parseargs@0.11.0': - optional: true - - '@pkgr/core@0.1.1': {} - - '@planetscale/database@1.18.0': {} - - '@rollup/rollup-android-arm-eabi@4.17.2': - optional: true - - '@rollup/rollup-android-arm64@4.17.2': - optional: true - - '@rollup/rollup-darwin-arm64@4.17.2': - optional: true - - '@rollup/rollup-darwin-x64@4.17.2': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.17.2': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.17.2': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.17.2': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.17.2': - optional: true - - '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.17.2': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.17.2': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.17.2': - optional: true - - '@rollup/rollup-linux-x64-musl@4.17.2': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.17.2': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.17.2': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.17.2': - optional: true - - '@sinclair/typebox@0.27.8': {} - - '@sindresorhus/is@4.6.0': {} - - '@smithy/abort-controller@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/config-resolver@3.0.0': - dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 - - '@smithy/core@2.0.1': - dependencies: - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 - - '@smithy/credential-provider-imds@3.0.0': - dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - tslib: 2.6.2 - - '@smithy/fetch-http-handler@3.0.1': - dependencies: - '@smithy/protocol-http': 4.0.0 - '@smithy/querystring-builder': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-base64': 3.0.0 - tslib: 2.6.2 - - '@smithy/hash-node@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - '@smithy/util-buffer-from': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - - '@smithy/invalid-dependency@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/is-array-buffer@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/middleware-content-length@3.0.0': - dependencies: - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/middleware-endpoint@3.0.0': - dependencies: - '@smithy/middleware-serde': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 - - '@smithy/middleware-retry@3.0.1': - dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/service-error-classification': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - tslib: 2.6.2 - uuid: 9.0.1 - - '@smithy/middleware-serde@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/middleware-stack@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/node-config-provider@3.0.0': - dependencies: - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/node-http-handler@3.0.0': - dependencies: - '@smithy/abort-controller': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/querystring-builder': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/property-provider@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/protocol-http@4.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/querystring-builder@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - '@smithy/util-uri-escape': 3.0.0 - tslib: 2.6.2 - - '@smithy/querystring-parser@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/service-error-classification@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - - '@smithy/shared-ini-file-loader@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/signature-v4@3.0.0': - dependencies: - '@smithy/is-array-buffer': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-hex-encoding': 3.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-uri-escape': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - - '@smithy/smithy-client@3.0.1': - dependencies: - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-stream': 3.0.1 - tslib: 2.6.2 - - '@smithy/types@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/url-parser@3.0.0': - dependencies: - '@smithy/querystring-parser': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-base64@3.0.0': - dependencies: - '@smithy/util-buffer-from': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-body-length-browser@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/util-body-length-node@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/util-buffer-from@3.0.0': - dependencies: - '@smithy/is-array-buffer': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-config-provider@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/util-defaults-mode-browser@3.0.1': - dependencies: - '@smithy/property-provider': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - bowser: 2.11.0 - tslib: 2.6.2 - - '@smithy/util-defaults-mode-node@3.0.1': - dependencies: - '@smithy/config-resolver': 3.0.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-endpoints@2.0.0': - dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-hex-encoding@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/util-middleware@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-retry@3.0.0': - dependencies: - '@smithy/service-error-classification': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-stream@3.0.1': - dependencies: - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/node-http-handler': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-buffer-from': 3.0.0 - '@smithy/util-hex-encoding': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-uri-escape@3.0.0': - dependencies: - tslib: 2.6.2 - - '@smithy/util-utf8@3.0.0': - dependencies: - '@smithy/util-buffer-from': 3.0.0 - tslib: 2.6.2 - - '@types/better-sqlite3@7.6.10': - dependencies: - '@types/node': 18.19.33 - - '@types/docker-modem@3.0.6': - dependencies: - '@types/node': 18.19.33 - '@types/ssh2': 1.15.0 - - '@types/dockerode@3.3.29': - dependencies: - '@types/docker-modem': 3.0.6 - '@types/node': 18.19.33 - '@types/ssh2': 1.15.0 - - '@types/estree@1.0.5': {} - - '@types/fs-extra@11.0.4': - dependencies: - '@types/jsonfile': 6.1.4 - '@types/node': 18.19.33 - - '@types/glob@8.1.0': - dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 18.19.33 - - '@types/json-diff@1.0.3': {} - - '@types/jsonfile@6.1.4': - dependencies: - '@types/node': 18.19.33 - - '@types/minimatch@5.1.2': {} - - '@types/minimist@1.2.5': {} - - '@types/node-fetch@2.6.11': - dependencies: - '@types/node': 18.19.33 - form-data: 4.0.0 - - '@types/node-forge@1.3.11': - dependencies: - '@types/node': 18.19.33 - - '@types/node@18.19.33': - dependencies: - undici-types: 5.26.5 - - '@types/pg@8.11.6': - dependencies: - '@types/node': 18.19.33 - pg-protocol: 1.6.1 - pg-types: 4.0.2 - - '@types/pg@8.6.6': - dependencies: - '@types/node': 18.19.33 - pg-protocol: 1.6.1 - pg-types: 2.2.0 - - '@types/pluralize@0.0.33': {} - - '@types/ps-tree@1.1.6': {} - - '@types/semver@7.5.8': {} - - '@types/ssh2@1.15.0': - dependencies: - '@types/node': 18.19.33 - - '@types/uuid@9.0.8': {} - - '@types/which@3.0.3': {} - - '@types/ws@8.5.10': - dependencies: - '@types/node': 18.19.33 - - '@typescript-eslint/eslint-plugin@7.10.0(@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': - dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.10.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.10.0 - '@typescript-eslint/type-utils': 7.10.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.10.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.10.0 - eslint: 8.57.0 - graphemer: 1.4.0 - ignore: 5.3.1 - natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.5) - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5)': - dependencies: - '@typescript-eslint/scope-manager': 7.10.0 - '@typescript-eslint/types': 7.10.0 - '@typescript-eslint/typescript-estree': 7.10.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.10.0 - debug: 4.3.4 - eslint: 8.57.0 - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@7.10.0': - dependencies: - '@typescript-eslint/types': 7.10.0 - '@typescript-eslint/visitor-keys': 7.10.0 - - '@typescript-eslint/type-utils@7.10.0(eslint@8.57.0)(typescript@5.4.5)': - dependencies: - '@typescript-eslint/typescript-estree': 7.10.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.10.0(eslint@8.57.0)(typescript@5.4.5) - debug: 4.3.4 - eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.4.5) - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@7.10.0': {} - - '@typescript-eslint/typescript-estree@7.10.0(typescript@5.4.5)': - dependencies: - '@typescript-eslint/types': 7.10.0 - '@typescript-eslint/visitor-keys': 7.10.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.4 - semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.4.5) - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@7.10.0(eslint@8.57.0)(typescript@5.4.5)': - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 7.10.0 - '@typescript-eslint/types': 7.10.0 - '@typescript-eslint/typescript-estree': 7.10.0(typescript@5.4.5) - eslint: 8.57.0 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/visitor-keys@7.10.0': - dependencies: - '@typescript-eslint/types': 7.10.0 - eslint-visitor-keys: 3.4.3 - - '@ungap/structured-clone@1.2.0': {} - - '@vercel/postgres@0.8.0': - dependencies: - '@neondatabase/serverless': 0.7.2 - bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) - - '@vitest/expect@1.6.0': - dependencies: - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - chai: 4.4.1 - - '@vitest/runner@1.6.0': - dependencies: - '@vitest/utils': 1.6.0 - p-limit: 5.0.0 - pathe: 1.1.2 - - '@vitest/snapshot@1.6.0': - dependencies: - magic-string: 0.30.10 - pathe: 1.1.2 - pretty-format: 29.7.0 - - '@vitest/spy@1.6.0': - dependencies: - tinyspy: 2.2.1 - - '@vitest/utils@1.6.0': - dependencies: - diff-sequences: 29.6.3 - estree-walker: 3.0.3 - loupe: 2.3.7 - pretty-format: 29.7.0 - - acorn-jsx@5.3.2(acorn@8.11.3): - dependencies: - acorn: 8.11.3 - - acorn-walk@8.3.2: {} - - acorn@8.11.3: {} - - aggregate-error@4.0.1: - dependencies: - clean-stack: 4.2.0 - indent-string: 5.0.0 - - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ansi-escapes@6.2.1: {} - - ansi-regex@5.0.1: {} - - ansi-regex@6.0.1: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@5.2.0: {} - - ansi-styles@6.2.1: {} - - ansicolors@0.3.2: {} - - any-promise@1.3.0: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - - argparse@2.0.1: {} - - array-find-index@1.0.2: {} - - array-union@2.1.0: {} - - arrgv@1.0.2: {} - - arrify@3.0.0: {} - - as-table@1.0.55: - dependencies: - printable-characters: 1.0.42 - - asn1@0.2.6: - dependencies: - safer-buffer: 2.1.2 - - assertion-error@1.1.0: {} - - asynckit@0.4.0: {} - - ava@5.3.1: - dependencies: - acorn: 8.11.3 - acorn-walk: 8.3.2 - ansi-styles: 6.2.1 - arrgv: 1.0.2 - arrify: 3.0.0 - callsites: 4.1.0 - cbor: 8.1.0 - chalk: 5.3.0 - chokidar: 3.6.0 - chunkd: 2.0.1 - ci-info: 3.9.0 - ci-parallel-vars: 1.0.1 - clean-yaml-object: 0.1.0 - cli-truncate: 3.1.0 - code-excerpt: 4.0.0 - common-path-prefix: 3.0.0 - concordance: 5.0.4 - currently-unhandled: 0.4.1 - debug: 4.3.4 - emittery: 1.0.3 - figures: 5.0.0 - globby: 13.2.2 - ignore-by-default: 2.1.0 - indent-string: 5.0.0 - is-error: 2.2.2 - is-plain-object: 5.0.0 - is-promise: 4.0.0 - matcher: 5.0.0 - mem: 9.0.2 - ms: 2.1.3 - p-event: 5.0.1 - p-map: 5.5.0 - picomatch: 2.3.1 - pkg-conf: 4.0.0 - plur: 5.1.0 - pretty-ms: 8.0.0 - resolve-cwd: 3.0.0 - stack-utils: 2.0.6 - strip-ansi: 7.1.0 - supertap: 3.0.1 - temp-dir: 3.0.0 - write-file-atomic: 5.0.1 - yargs: 17.7.2 - transitivePeerDependencies: - - supports-color - - balanced-match@1.0.2: {} - - base64-js@1.5.1: {} - - bcrypt-pbkdf@1.0.2: - dependencies: - tweetnacl: 0.14.5 - - better-sqlite3@9.6.0: - dependencies: - bindings: 1.5.0 - prebuild-install: 7.1.2 - - binary-extensions@2.3.0: {} - - bindings@1.5.0: - dependencies: - file-uri-to-path: 1.0.0 - - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - - blake3-wasm@2.1.5: {} - - blueimp-md5@2.19.0: {} - - bowser@2.11.0: {} - - brace-expansion@1.1.11: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.1: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.2: - dependencies: - fill-range: 7.1.1 - - buffer-from@1.1.2: {} - - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - bufferutil@4.0.8: - dependencies: - node-gyp-build: 4.8.1 - - buildcheck@0.0.6: - optional: true - - bundle-require@4.1.0(esbuild@0.19.12): - dependencies: - esbuild: 0.19.12 - load-tsconfig: 0.2.5 - - cac@6.7.14: {} - - callsites@3.1.0: {} - - callsites@4.1.0: {} - - camelcase@7.0.1: {} - - capnp-ts@0.7.0: - dependencies: - debug: 4.3.4 - tslib: 2.6.2 - transitivePeerDependencies: - - supports-color - - cardinal@2.1.1: - dependencies: - ansicolors: 0.3.2 - redeyed: 2.1.1 - - cbor@8.1.0: - dependencies: - nofilter: 3.1.0 - - chai@4.4.1: - dependencies: - assertion-error: 1.1.0 - check-error: 1.0.3 - deep-eql: 4.1.3 - get-func-name: 2.0.2 - loupe: 2.3.7 - pathval: 1.1.1 - type-detect: 4.0.8 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chalk@5.3.0: {} - - char-regex@1.0.2: {} - - check-error@1.0.3: - dependencies: - get-func-name: 2.0.2 - - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - - chownr@1.1.4: {} - - chunkd@2.0.1: {} - - ci-info@3.9.0: {} - - ci-parallel-vars@1.0.1: {} - - clean-stack@4.2.0: - dependencies: - escape-string-regexp: 5.0.0 - - clean-yaml-object@0.1.0: {} - - cli-color@2.0.4: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - memoizee: 0.4.15 - timers-ext: 0.1.7 - - cli-table3@0.6.5: - dependencies: - string-width: 4.2.3 - optionalDependencies: - '@colors/colors': 1.5.0 - - cli-truncate@3.1.0: - dependencies: - slice-ansi: 5.0.0 - string-width: 5.1.2 - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - code-excerpt@4.0.0: - dependencies: - convert-to-spaces: 2.0.1 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - colors@1.4.0: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - commander@10.0.1: {} - - commander@12.1.0: {} - - commander@4.1.1: {} - - commander@9.5.0: {} - - common-path-prefix@3.0.0: {} - - concat-map@0.0.1: {} - - concordance@5.0.4: - dependencies: - date-time: 3.1.0 - esutils: 2.0.3 - fast-diff: 1.3.0 - js-string-escape: 1.0.1 - lodash: 4.17.21 - md5-hex: 3.0.1 - semver: 7.6.2 - well-known-symbols: 2.0.0 - - confbox@0.1.7: {} - - convert-to-spaces@2.0.1: {} - - cookie@0.5.0: {} - - copy-anything@3.0.5: - dependencies: - is-what: 4.1.16 - - cpu-features@0.0.10: - dependencies: - buildcheck: 0.0.6 - nan: 2.19.0 - optional: true - - cross-spawn@7.0.3: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - currently-unhandled@0.4.1: - dependencies: - array-find-index: 1.0.2 - - d@1.0.2: - dependencies: - es5-ext: 0.10.64 - type: 2.7.2 - - data-uri-to-buffer@2.0.2: {} - - data-uri-to-buffer@4.0.1: {} - - date-time@3.1.0: - dependencies: - time-zone: 1.0.0 - - debug@4.3.4: - dependencies: - ms: 2.1.2 - - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - - deep-eql@4.1.3: - dependencies: - type-detect: 4.0.8 - - deep-extend@0.6.0: {} - - deep-is@0.1.4: {} - - delayed-stream@1.0.0: {} - - denque@2.1.0: {} - - detect-libc@2.0.2: - optional: true - - detect-libc@2.0.3: {} - - diff-sequences@29.6.3: {} - - difflib@0.2.4(patch_hash=jq4t3ysdpnbunjeje4v7nrqn2q): - dependencies: - heap: 0.2.7 - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - docker-modem@3.0.8: - dependencies: - debug: 4.3.4 - readable-stream: 3.6.2 - split-ca: 1.0.1 - ssh2: 1.15.0 - transitivePeerDependencies: - - supports-color - - dockerode@3.3.5: - dependencies: - '@balena/dockerignore': 1.0.2 - docker-modem: 3.0.8 - tar-fs: 2.0.1 - transitivePeerDependencies: - - supports-color - - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - - dotenv@16.4.5: {} - - dreamopt@0.8.0: - dependencies: - wordwrap: 1.0.0 - - drizzle-kit@0.21.2: - dependencies: - '@esbuild-kit/esm-loader': 2.6.5 - commander: 9.5.0 - env-paths: 3.0.0 - esbuild: 0.19.12 - esbuild-register: 3.5.0(esbuild@0.19.12) - glob: 8.1.0 - hanji: 0.0.5 - json-diff: 0.9.0 - zod: 3.23.8 - transitivePeerDependencies: - - supports-color - - drizzle-orm@0.32.0-85c8008(@aws-sdk/client-rds-data@3.577.0)(@cloudflare/workers-types@4.20240512.0)(@electric-sql/pglite@0.1.5)(@libsql/client@0.4.3(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(mysql2@2.3.3)(pg@8.11.5)(postgres@3.4.4): - optionalDependencies: - '@aws-sdk/client-rds-data': 3.577.0 - '@cloudflare/workers-types': 4.20240512.0 - '@electric-sql/pglite': 0.1.5 - '@libsql/client': 0.4.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) - '@neondatabase/serverless': 0.9.3 - '@planetscale/database': 1.18.0 - '@types/better-sqlite3': 7.6.10 - '@types/pg': 8.11.6 - '@vercel/postgres': 0.8.0 - better-sqlite3: 9.6.0 - mysql2: 2.3.3 - pg: 8.11.5 - postgres: 3.4.4 - - duplexer@0.1.2: {} - - eastasianwidth@0.2.0: {} - - emittery@1.0.3: {} - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - emojilib@2.4.0: {} - - end-of-stream@1.4.4: - dependencies: - once: 1.4.0 - - env-paths@3.0.0: {} - - es5-ext@0.10.64: - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esniff: 2.0.1 - next-tick: 1.1.0 - - es6-iterator@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-symbol: 3.1.4 - - es6-symbol@3.1.4: - dependencies: - d: 1.0.2 - ext: 1.7.0 - - es6-weak-map@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - - esbuild-android-64@0.14.54: - optional: true - - esbuild-android-arm64@0.14.54: - optional: true - - esbuild-darwin-64@0.14.54: - optional: true - - esbuild-darwin-arm64@0.14.54: - optional: true - - esbuild-freebsd-64@0.14.54: - optional: true - - esbuild-freebsd-arm64@0.14.54: - optional: true - - esbuild-linux-32@0.14.54: - optional: true - - esbuild-linux-64@0.14.54: - optional: true - - esbuild-linux-arm64@0.14.54: - optional: true - - esbuild-linux-arm@0.14.54: - optional: true - - esbuild-linux-mips64le@0.14.54: - optional: true - - esbuild-linux-ppc64le@0.14.54: - optional: true - - esbuild-linux-riscv64@0.14.54: - optional: true - - esbuild-linux-s390x@0.14.54: - optional: true - - esbuild-netbsd-64@0.14.54: - optional: true - - esbuild-node-externals@1.13.1(esbuild@0.19.12): - dependencies: - esbuild: 0.19.12 - find-up: 5.0.0 - tslib: 2.6.2 - - esbuild-openbsd-64@0.14.54: - optional: true - - esbuild-register@3.5.0(esbuild@0.19.12): - dependencies: - debug: 4.3.4 - esbuild: 0.19.12 - transitivePeerDependencies: - - supports-color - - esbuild-sunos-64@0.14.54: - optional: true - - esbuild-windows-32@0.14.54: - optional: true - - esbuild-windows-64@0.14.54: - optional: true - - esbuild-windows-arm64@0.14.54: - optional: true - - esbuild@0.14.54: - optionalDependencies: - '@esbuild/linux-loong64': 0.14.54 - esbuild-android-64: 0.14.54 - esbuild-android-arm64: 0.14.54 - esbuild-darwin-64: 0.14.54 - esbuild-darwin-arm64: 0.14.54 - esbuild-freebsd-64: 0.14.54 - esbuild-freebsd-arm64: 0.14.54 - esbuild-linux-32: 0.14.54 - esbuild-linux-64: 0.14.54 - esbuild-linux-arm: 0.14.54 - esbuild-linux-arm64: 0.14.54 - esbuild-linux-mips64le: 0.14.54 - esbuild-linux-ppc64le: 0.14.54 - esbuild-linux-riscv64: 0.14.54 - esbuild-linux-s390x: 0.14.54 - esbuild-netbsd-64: 0.14.54 - esbuild-openbsd-64: 0.14.54 - esbuild-sunos-64: 0.14.54 - esbuild-windows-32: 0.14.54 - esbuild-windows-64: 0.14.54 - esbuild-windows-arm64: 0.14.54 - - esbuild@0.17.19: - optionalDependencies: - '@esbuild/android-arm': 0.17.19 - '@esbuild/android-arm64': 0.17.19 - '@esbuild/android-x64': 0.17.19 - '@esbuild/darwin-arm64': 0.17.19 - '@esbuild/darwin-x64': 0.17.19 - '@esbuild/freebsd-arm64': 0.17.19 - '@esbuild/freebsd-x64': 0.17.19 - '@esbuild/linux-arm': 0.17.19 - '@esbuild/linux-arm64': 0.17.19 - '@esbuild/linux-ia32': 0.17.19 - '@esbuild/linux-loong64': 0.17.19 - '@esbuild/linux-mips64el': 0.17.19 - '@esbuild/linux-ppc64': 0.17.19 - '@esbuild/linux-riscv64': 0.17.19 - '@esbuild/linux-s390x': 0.17.19 - '@esbuild/linux-x64': 0.17.19 - '@esbuild/netbsd-x64': 0.17.19 - '@esbuild/openbsd-x64': 0.17.19 - '@esbuild/sunos-x64': 0.17.19 - '@esbuild/win32-arm64': 0.17.19 - '@esbuild/win32-ia32': 0.17.19 - '@esbuild/win32-x64': 0.17.19 - - esbuild@0.18.20: - optionalDependencies: - '@esbuild/android-arm': 0.18.20 - '@esbuild/android-arm64': 0.18.20 - '@esbuild/android-x64': 0.18.20 - '@esbuild/darwin-arm64': 0.18.20 - '@esbuild/darwin-x64': 0.18.20 - '@esbuild/freebsd-arm64': 0.18.20 - '@esbuild/freebsd-x64': 0.18.20 - '@esbuild/linux-arm': 0.18.20 - '@esbuild/linux-arm64': 0.18.20 - '@esbuild/linux-ia32': 0.18.20 - '@esbuild/linux-loong64': 0.18.20 - '@esbuild/linux-mips64el': 0.18.20 - '@esbuild/linux-ppc64': 0.18.20 - '@esbuild/linux-riscv64': 0.18.20 - '@esbuild/linux-s390x': 0.18.20 - '@esbuild/linux-x64': 0.18.20 - '@esbuild/netbsd-x64': 0.18.20 - '@esbuild/openbsd-x64': 0.18.20 - '@esbuild/sunos-x64': 0.18.20 - '@esbuild/win32-arm64': 0.18.20 - '@esbuild/win32-ia32': 0.18.20 - '@esbuild/win32-x64': 0.18.20 - - esbuild@0.19.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.19.12 - '@esbuild/android-arm': 0.19.12 - '@esbuild/android-arm64': 0.19.12 - '@esbuild/android-x64': 0.19.12 - '@esbuild/darwin-arm64': 0.19.12 - '@esbuild/darwin-x64': 0.19.12 - '@esbuild/freebsd-arm64': 0.19.12 - '@esbuild/freebsd-x64': 0.19.12 - '@esbuild/linux-arm': 0.19.12 - '@esbuild/linux-arm64': 0.19.12 - '@esbuild/linux-ia32': 0.19.12 - '@esbuild/linux-loong64': 0.19.12 - '@esbuild/linux-mips64el': 0.19.12 - '@esbuild/linux-ppc64': 0.19.12 - '@esbuild/linux-riscv64': 0.19.12 - '@esbuild/linux-s390x': 0.19.12 - '@esbuild/linux-x64': 0.19.12 - '@esbuild/netbsd-x64': 0.19.12 - '@esbuild/openbsd-x64': 0.19.12 - '@esbuild/sunos-x64': 0.19.12 - '@esbuild/win32-arm64': 0.19.12 - '@esbuild/win32-ia32': 0.19.12 - '@esbuild/win32-x64': 0.19.12 - - esbuild@0.20.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.20.2 - '@esbuild/android-arm': 0.20.2 - '@esbuild/android-arm64': 0.20.2 - '@esbuild/android-x64': 0.20.2 - '@esbuild/darwin-arm64': 0.20.2 - '@esbuild/darwin-x64': 0.20.2 - '@esbuild/freebsd-arm64': 0.20.2 - '@esbuild/freebsd-x64': 0.20.2 - '@esbuild/linux-arm': 0.20.2 - '@esbuild/linux-arm64': 0.20.2 - '@esbuild/linux-ia32': 0.20.2 - '@esbuild/linux-loong64': 0.20.2 - '@esbuild/linux-mips64el': 0.20.2 - '@esbuild/linux-ppc64': 0.20.2 - '@esbuild/linux-riscv64': 0.20.2 - '@esbuild/linux-s390x': 0.20.2 - '@esbuild/linux-x64': 0.20.2 - '@esbuild/netbsd-x64': 0.20.2 - '@esbuild/openbsd-x64': 0.20.2 - '@esbuild/sunos-x64': 0.20.2 - '@esbuild/win32-arm64': 0.20.2 - '@esbuild/win32-ia32': 0.20.2 - '@esbuild/win32-x64': 0.20.2 - - escalade@3.1.2: {} - - escape-string-regexp@2.0.0: {} - - escape-string-regexp@4.0.0: {} - - escape-string-regexp@5.0.0: {} - - eslint-config-prettier@9.1.0(eslint@8.57.0): - dependencies: - eslint: 8.57.0 - - eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8): - dependencies: - eslint: 8.57.0 - prettier: 2.8.8 - prettier-linter-helpers: 1.0.0 - synckit: 0.8.8 - optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@8.57.0) - - eslint-scope@7.2.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint@8.57.0: - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.10.0 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.5.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.1 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - esniff@2.0.1: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-emitter: 0.3.5 - type: 2.7.2 - - espree@9.6.1: - dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) - eslint-visitor-keys: 3.4.3 - - esprima@4.0.1: {} - - esquery@1.5.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - estree-walker@0.6.1: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.5 - - esutils@2.0.3: {} - - event-emitter@0.3.5: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - - event-stream@3.3.4: - dependencies: - duplexer: 0.1.2 - from: 0.1.7 - map-stream: 0.1.0 - pause-stream: 0.0.11 - split: 0.3.3 - stream-combiner: 0.0.4 - through: 2.3.8 - - execa@5.1.1: - dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - - execa@8.0.1: - dependencies: - cross-spawn: 7.0.3 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 - - exit-hook@2.2.1: {} - - expand-template@2.0.3: {} - - ext@1.7.0: - dependencies: - type: 2.7.2 - - fast-deep-equal@3.1.3: {} - - fast-diff@1.3.0: {} - - fast-glob@3.3.2: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fast-xml-parser@4.2.5: - dependencies: - strnum: 1.0.5 - - fastq@1.17.1: - dependencies: - reusify: 1.0.4 - - fetch-blob@3.2.0: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 - - fflate@0.8.2: {} - - figures@5.0.0: - dependencies: - escape-string-regexp: 5.0.0 - is-unicode-supported: 1.3.0 - - file-entry-cache@6.0.1: - dependencies: - flat-cache: 3.2.0 - - file-uri-to-path@1.0.0: {} - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - find-up@6.3.0: - dependencies: - locate-path: 7.2.0 - path-exists: 5.0.0 - - flat-cache@3.2.0: - dependencies: - flatted: 3.3.1 - keyv: 4.5.4 - rimraf: 3.0.2 - - flatted@3.3.1: {} - - foreground-child@3.1.1: - dependencies: - cross-spawn: 7.0.3 - signal-exit: 4.1.0 - - form-data@4.0.0: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - - formdata-polyfill@4.0.10: - dependencies: - fetch-blob: 3.2.0 - - from@0.1.7: {} - - fs-constants@1.0.0: {} - - fs-extra@11.2.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs.realpath@1.0.0: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - fx@34.0.0: {} - - generate-function@2.3.1: - dependencies: - is-property: 1.0.2 - - get-caller-file@2.0.5: {} - - get-func-name@2.0.2: {} - - get-port@6.1.2: {} - - get-source@2.0.12: - dependencies: - data-uri-to-buffer: 2.0.2 - source-map: 0.6.1 - - get-stream@6.0.1: {} - - get-stream@8.0.1: {} - - get-tsconfig@4.7.5: - dependencies: - resolve-pkg-maps: 1.0.0 - - github-from-package@0.0.0: {} - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob-to-regexp@0.4.1: {} - - glob@10.3.15: - dependencies: - foreground-child: 3.1.1 - jackspeak: 2.3.6 - minimatch: 9.0.4 - minipass: 7.1.1 - path-scurry: 1.11.1 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - glob@8.1.0: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - - globals@13.24.0: - dependencies: - type-fest: 0.20.2 - - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.1 - merge2: 1.4.1 - slash: 3.0.0 - - globby@13.2.2: - dependencies: - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.1 - merge2: 1.4.1 - slash: 4.0.0 - - globrex@0.1.2: {} - - graceful-fs@4.2.11: {} - - graphemer@1.4.0: {} - - hanji@0.0.5: - dependencies: - lodash.throttle: 4.1.1 - sisteransi: 1.0.5 - - has-flag@4.0.0: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - heap@0.2.7: {} - - hono@4.3.9: {} - - human-signals@2.1.0: {} - - human-signals@5.0.0: {} - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - ieee754@1.2.1: {} - - ignore-by-default@2.1.0: {} - - ignore@5.3.1: {} - - import-fresh@3.3.0: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - indent-string@5.0.0: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - ini@1.3.8: {} - - irregular-plurals@3.5.0: {} - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - - is-core-module@2.13.1: - dependencies: - hasown: 2.0.2 - - is-error@2.2.2: {} - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-fullwidth-code-point@4.0.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-number@7.0.0: {} - - is-path-inside@3.0.3: {} - - is-plain-object@5.0.0: {} - - is-promise@2.2.2: {} - - is-promise@4.0.0: {} - - is-property@1.0.2: {} - - is-stream@2.0.1: {} - - is-stream@3.0.0: {} - - is-unicode-supported@1.3.0: {} - - is-what@4.1.16: {} - - isexe@2.0.0: {} - - jackspeak@2.3.6: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - - joycon@3.1.1: {} - - js-base64@3.7.7: {} - - js-string-escape@1.0.1: {} - - js-tokens@9.0.0: {} - - js-yaml@3.14.1: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - - json-buffer@3.0.1: {} - - json-diff@0.9.0: - dependencies: - cli-color: 2.0.4 - difflib: 0.2.4(patch_hash=jq4t3ysdpnbunjeje4v7nrqn2q) - dreamopt: 0.8.0 - - json-diff@1.0.6: - dependencies: - '@ewoudenberg/difflib': 0.1.0 - colors: 1.4.0 - dreamopt: 0.8.0 - - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - jsonfile@6.1.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - libsql@0.2.0: - dependencies: - '@neon-rs/load': 0.0.4 - detect-libc: 2.0.2 - optionalDependencies: - '@libsql/darwin-arm64': 0.2.0 - '@libsql/darwin-x64': 0.2.0 - '@libsql/linux-arm64-gnu': 0.2.0 - '@libsql/linux-arm64-musl': 0.2.0 - '@libsql/linux-x64-gnu': 0.2.0 - '@libsql/linux-x64-musl': 0.2.0 - '@libsql/win32-x64-msvc': 0.2.0 - optional: true - - lilconfig@3.1.1: {} - - lines-and-columns@1.2.4: {} - - load-json-file@7.0.1: {} - - load-tsconfig@0.2.5: {} - - local-pkg@0.5.0: - dependencies: - mlly: 1.7.0 - pkg-types: 1.1.1 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - locate-path@7.2.0: - dependencies: - p-locate: 6.0.0 - - lodash.merge@4.6.2: {} - - lodash.sortby@4.7.0: {} - - lodash.throttle@4.1.1: {} - - lodash@4.17.21: {} - - long@4.0.0: {} - - loupe@2.3.7: - dependencies: - get-func-name: 2.0.2 - - lru-cache@10.2.2: {} - - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - - lru-cache@7.18.3: {} - - lru-queue@0.1.0: - dependencies: - es5-ext: 0.10.64 - - magic-string@0.25.9: - dependencies: - sourcemap-codec: 1.4.8 - - magic-string@0.30.10: - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - - map-age-cleaner@0.1.3: - dependencies: - p-defer: 1.0.0 - - map-stream@0.1.0: {} - - marked-terminal@6.2.0(marked@9.1.6): - dependencies: - ansi-escapes: 6.2.1 - cardinal: 2.1.1 - chalk: 5.3.0 - cli-table3: 0.6.5 - marked: 9.1.6 - node-emoji: 2.1.3 - supports-hyperlinks: 3.0.0 - - marked@9.1.6: {} - - matcher@5.0.0: - dependencies: - escape-string-regexp: 5.0.0 - - md5-hex@3.0.1: - dependencies: - blueimp-md5: 2.19.0 - - mem@9.0.2: - dependencies: - map-age-cleaner: 0.1.3 - mimic-fn: 4.0.0 - - memoizee@0.4.15: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-weak-map: 2.0.3 - event-emitter: 0.3.5 - is-promise: 2.2.2 - lru-queue: 0.1.0 - next-tick: 1.1.0 - timers-ext: 0.1.7 - - merge-stream@2.0.0: {} - - merge2@1.4.1: {} - - micromatch@4.0.5: - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime@3.0.0: {} - - mimic-fn@2.1.0: {} - - mimic-fn@4.0.0: {} - - mimic-response@3.1.0: {} - - miniflare@3.20240512.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - acorn: 8.11.3 - acorn-walk: 8.3.2 - capnp-ts: 0.7.0 - exit-hook: 2.2.1 - glob-to-regexp: 0.4.1 - stoppable: 1.1.0 - undici: 5.28.4 - workerd: 1.20240512.0 - ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - youch: 3.3.3 - zod: 3.23.8 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.11 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.1 - - minimatch@7.4.6: - dependencies: - brace-expansion: 2.0.1 - - minimatch@9.0.4: - dependencies: - brace-expansion: 2.0.1 - - minimist@1.2.8: {} - - minipass@7.1.1: {} - - mkdirp-classic@0.5.3: {} - - mlly@1.7.0: - dependencies: - acorn: 8.11.3 - pathe: 1.1.2 - pkg-types: 1.1.1 - ufo: 1.5.3 - - ms@2.1.2: {} - - ms@2.1.3: {} - - mustache@4.2.0: {} - - mysql2@2.3.3: - dependencies: - denque: 2.1.0 - generate-function: 2.3.1 - iconv-lite: 0.6.3 - long: 4.0.0 - lru-cache: 6.0.0 - named-placeholders: 1.1.3 - seq-queue: 0.0.5 - sqlstring: 2.3.3 - - mz@2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - - named-placeholders@1.1.3: - dependencies: - lru-cache: 7.18.3 - - nan@2.19.0: - optional: true - - nanoid@3.3.7: {} - - napi-build-utils@1.0.2: {} - - natural-compare@1.4.0: {} - - next-tick@1.1.0: {} - - node-abi@3.62.0: - dependencies: - semver: 7.6.2 - - node-domexception@1.0.0: {} - - node-emoji@2.1.3: - dependencies: - '@sindresorhus/is': 4.6.0 - char-regex: 1.0.2 - emojilib: 2.4.0 - skin-tone: 2.0.0 - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - node-fetch@3.3.1: - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - - node-fetch@3.3.2: - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - - node-forge@1.3.1: {} - - node-gyp-build@4.8.1: {} - - nofilter@3.1.0: {} - - normalize-path@3.0.0: {} - - npm-run-path@4.0.1: - dependencies: - path-key: 3.1.1 - - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - - object-assign@4.1.1: {} - - obuf@1.1.2: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - p-defer@1.0.0: {} - - p-event@5.0.1: - dependencies: - p-timeout: 5.1.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-limit@4.0.0: - dependencies: - yocto-queue: 1.0.0 - - p-limit@5.0.0: - dependencies: - yocto-queue: 1.0.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - p-locate@6.0.0: - dependencies: - p-limit: 4.0.0 - - p-map@5.5.0: - dependencies: - aggregate-error: 4.0.1 - - p-timeout@5.1.0: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse-ms@3.0.0: {} - - path-exists@4.0.0: {} - - path-exists@5.0.0: {} - - path-is-absolute@1.0.1: {} - - path-key@3.1.1: {} - - path-key@4.0.0: {} - - path-parse@1.0.7: {} - - path-scurry@1.11.1: - dependencies: - lru-cache: 10.2.2 - minipass: 7.1.1 - - path-to-regexp@6.2.2: {} - - path-type@4.0.0: {} - - pathe@1.1.2: {} - - pathval@1.1.1: {} - - pause-stream@0.0.11: - dependencies: - through: 2.3.8 - - pg-cloudflare@1.1.1: - optional: true - - pg-connection-string@2.6.4: {} - - pg-int8@1.0.1: {} - - pg-numeric@1.0.2: {} - - pg-pool@3.6.2(pg@8.11.5): - dependencies: - pg: 8.11.5 - - pg-protocol@1.6.1: {} - - pg-types@2.2.0: - dependencies: - pg-int8: 1.0.1 - postgres-array: 2.0.0 - postgres-bytea: 1.0.0 - postgres-date: 1.0.7 - postgres-interval: 1.2.0 - - pg-types@4.0.2: - dependencies: - pg-int8: 1.0.1 - pg-numeric: 1.0.2 - postgres-array: 3.0.2 - postgres-bytea: 3.0.0 - postgres-date: 2.1.0 - postgres-interval: 3.0.0 - postgres-range: 1.1.4 - - pg@8.11.5: - dependencies: - pg-connection-string: 2.6.4 - pg-pool: 3.6.2(pg@8.11.5) - pg-protocol: 1.6.1 - pg-types: 2.2.0 - pgpass: 1.0.5 - optionalDependencies: - pg-cloudflare: 1.1.1 - - pgpass@1.0.5: - dependencies: - split2: 4.2.0 - - picocolors@1.0.1: {} - - picomatch@2.3.1: {} - - pirates@4.0.6: {} - - pkg-conf@4.0.0: - dependencies: - find-up: 6.3.0 - load-json-file: 7.0.1 - - pkg-types@1.1.1: - dependencies: - confbox: 0.1.7 - mlly: 1.7.0 - pathe: 1.1.2 - - plur@5.1.0: - dependencies: - irregular-plurals: 3.5.0 - - pluralize@8.0.0: {} - - postcss-load-config@4.0.2(postcss@8.4.38): - dependencies: - lilconfig: 3.1.1 - yaml: 2.4.2 - optionalDependencies: - postcss: 8.4.38 - - postcss@8.4.38: - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 - - postgres-array@2.0.0: {} - - postgres-array@3.0.2: {} - - postgres-bytea@1.0.0: {} - - postgres-bytea@3.0.0: - dependencies: - obuf: 1.1.2 - - postgres-date@1.0.7: {} - - postgres-date@2.1.0: {} - - postgres-interval@1.2.0: - dependencies: - xtend: 4.0.2 - - postgres-interval@3.0.0: {} - - postgres-range@1.1.4: {} - - postgres@3.4.4: {} - - prebuild-install@7.1.2: - dependencies: - detect-libc: 2.0.3 - expand-template: 2.0.3 - github-from-package: 0.0.0 - minimist: 1.2.8 - mkdirp-classic: 0.5.3 - napi-build-utils: 1.0.2 - node-abi: 3.62.0 - pump: 3.0.0 - rc: 1.2.8 - simple-get: 4.0.1 - tar-fs: 2.1.1 - tunnel-agent: 0.6.0 - - prelude-ls@1.2.1: {} - - prettier-linter-helpers@1.0.0: - dependencies: - fast-diff: 1.3.0 - - prettier@2.8.8: {} - - pretty-format@29.7.0: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - - pretty-ms@8.0.0: - dependencies: - parse-ms: 3.0.0 - - printable-characters@1.0.42: {} - - ps-tree@1.2.0: - dependencies: - event-stream: 3.3.4 - - pump@3.0.0: - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - - punycode@2.3.1: {} - - queue-microtask@1.2.3: {} - - rc@1.2.8: - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - - react-is@18.3.1: {} - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - - redeyed@2.1.1: - dependencies: - esprima: 4.0.1 - - require-directory@2.1.1: {} - - resolve-cwd@3.0.0: - dependencies: - resolve-from: 5.0.0 - - resolve-from@4.0.0: {} - - resolve-from@5.0.0: {} - - resolve-pkg-maps@1.0.0: {} - - resolve.exports@2.0.2: {} - - resolve@1.22.8: - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - reusify@1.0.4: {} - - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - - rollup-plugin-inject@3.0.2: - dependencies: - estree-walker: 0.6.1 - magic-string: 0.25.9 - rollup-pluginutils: 2.8.2 - - rollup-plugin-node-polyfills@0.2.1: - dependencies: - rollup-plugin-inject: 3.0.2 - - rollup-pluginutils@2.8.2: - dependencies: - estree-walker: 0.6.1 - - rollup@4.17.2: - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.17.2 - '@rollup/rollup-android-arm64': 4.17.2 - '@rollup/rollup-darwin-arm64': 4.17.2 - '@rollup/rollup-darwin-x64': 4.17.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.17.2 - '@rollup/rollup-linux-arm-musleabihf': 4.17.2 - '@rollup/rollup-linux-arm64-gnu': 4.17.2 - '@rollup/rollup-linux-arm64-musl': 4.17.2 - '@rollup/rollup-linux-powerpc64le-gnu': 4.17.2 - '@rollup/rollup-linux-riscv64-gnu': 4.17.2 - '@rollup/rollup-linux-s390x-gnu': 4.17.2 - '@rollup/rollup-linux-x64-gnu': 4.17.2 - '@rollup/rollup-linux-x64-musl': 4.17.2 - '@rollup/rollup-win32-arm64-msvc': 4.17.2 - '@rollup/rollup-win32-ia32-msvc': 4.17.2 - '@rollup/rollup-win32-x64-msvc': 4.17.2 - fsevents: 2.3.3 - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: {} - - selfsigned@2.4.1: - dependencies: - '@types/node-forge': 1.3.11 - node-forge: 1.3.1 - - semver@7.6.2: {} - - seq-queue@0.0.5: {} - - serialize-error@7.0.1: - dependencies: - type-fest: 0.13.1 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - siginfo@2.0.0: {} - - signal-exit@3.0.7: {} - - signal-exit@4.1.0: {} - - simple-concat@1.0.1: {} - - simple-get@4.0.1: - dependencies: - decompress-response: 6.0.0 - once: 1.4.0 - simple-concat: 1.0.1 - - sisteransi@1.0.5: {} - - skin-tone@2.0.0: - dependencies: - unicode-emoji-modifier-base: 1.0.0 - - slash@3.0.0: {} - - slash@4.0.0: {} - - slice-ansi@5.0.0: - dependencies: - ansi-styles: 6.2.1 - is-fullwidth-code-point: 4.0.0 - - source-map-js@1.2.0: {} - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - source-map@0.8.0-beta.0: - dependencies: - whatwg-url: 7.1.0 - - sourcemap-codec@1.4.8: {} - - split-ca@1.0.1: {} - - split2@4.2.0: {} - - split@0.3.3: - dependencies: - through: 2.3.8 - - sprintf-js@1.0.3: {} - - sqlstring@2.3.3: {} - - ssh2@1.15.0: - dependencies: - asn1: 0.2.6 - bcrypt-pbkdf: 1.0.2 - optionalDependencies: - cpu-features: 0.0.10 - nan: 2.19.0 - - stack-utils@2.0.6: - dependencies: - escape-string-regexp: 2.0.0 - - stackback@0.0.2: {} - - stacktracey@2.1.8: - dependencies: - as-table: 1.0.55 - get-source: 2.0.12 - - std-env@3.7.0: {} - - stoppable@1.1.0: {} - - stream-combiner@0.0.4: - dependencies: - duplexer: 0.1.2 - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.1.0: - dependencies: - ansi-regex: 6.0.1 - - strip-final-newline@2.0.0: {} - - strip-final-newline@3.0.0: {} - - strip-json-comments@2.0.1: {} - - strip-json-comments@3.1.1: {} - - strip-literal@2.1.0: - dependencies: - js-tokens: 9.0.0 - - strnum@1.0.5: {} - - sucrase@3.35.0: - dependencies: - '@jridgewell/gen-mapping': 0.3.5 - commander: 4.1.1 - glob: 10.3.15 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.6 - ts-interface-checker: 0.1.13 - - superjson@2.2.1: - dependencies: - copy-anything: 3.0.5 - - supertap@3.0.1: - dependencies: - indent-string: 5.0.0 - js-yaml: 3.14.1 - serialize-error: 7.0.1 - strip-ansi: 7.1.0 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-hyperlinks@3.0.0: - dependencies: - has-flag: 4.0.0 - supports-color: 7.2.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - synckit@0.8.8: - dependencies: - '@pkgr/core': 0.1.1 - tslib: 2.6.2 - - tar-fs@2.0.1: - dependencies: - chownr: 1.1.4 - mkdirp-classic: 0.5.3 - pump: 3.0.0 - tar-stream: 2.2.0 - - tar-fs@2.1.1: - dependencies: - chownr: 1.1.4 - mkdirp-classic: 0.5.3 - pump: 3.0.0 - tar-stream: 2.2.0 - - tar-stream@2.2.0: - dependencies: - bl: 4.1.0 - end-of-stream: 1.4.4 - fs-constants: 1.0.0 - inherits: 2.0.4 - readable-stream: 3.6.2 - - temp-dir@3.0.0: {} - - text-table@0.2.0: {} - - thenify-all@1.6.0: - dependencies: - thenify: 3.3.1 - - thenify@3.3.1: - dependencies: - any-promise: 1.3.0 - - through@2.3.8: {} - - time-zone@1.0.0: {} - - timers-ext@0.1.7: - dependencies: - es5-ext: 0.10.64 - next-tick: 1.1.0 - - tinybench@2.8.0: {} - - tinypool@0.8.4: {} - - tinyspy@2.2.1: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - tr46@0.0.3: {} - - tr46@1.0.1: - dependencies: - punycode: 2.3.1 - - tree-kill@1.2.2: {} - - ts-api-utils@1.3.0(typescript@5.4.5): - dependencies: - typescript: 5.4.5 - - ts-expose-internals-conditionally@1.0.0-empty.0: {} - - ts-interface-checker@0.1.13: {} - - tsconfck@3.0.3(typescript@5.4.5): - optionalDependencies: - typescript: 5.4.5 - - tslib@1.14.1: {} - - tslib@2.6.2: {} - - tsup@8.0.2(postcss@8.4.38)(typescript@5.4.5): - dependencies: - bundle-require: 4.1.0(esbuild@0.19.12) - cac: 6.7.14 - chokidar: 3.6.0 - debug: 4.3.4 - esbuild: 0.19.12 - execa: 5.1.1 - globby: 11.1.0 - joycon: 3.1.1 - postcss-load-config: 4.0.2(postcss@8.4.38) - resolve-from: 5.0.0 - rollup: 4.17.2 - source-map: 0.8.0-beta.0 - sucrase: 3.35.0 - tree-kill: 1.2.2 - optionalDependencies: - postcss: 8.4.38 - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - ts-node - - tsx@3.14.0: - dependencies: - esbuild: 0.18.20 - get-tsconfig: 4.7.5 - source-map-support: 0.5.21 - optionalDependencies: - fsevents: 2.3.3 - - tunnel-agent@0.6.0: - dependencies: - safe-buffer: 5.2.1 - - tweetnacl@0.14.5: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-detect@4.0.8: {} - - type-fest@0.13.1: {} - - type-fest@0.20.2: {} - - type@2.7.2: {} - - typescript@5.3.3: {} - - typescript@5.4.5: {} - - ufo@1.5.3: {} - - undici-types@5.26.5: {} - - undici@5.28.4: - dependencies: - '@fastify/busboy': 2.1.1 - - unicode-emoji-modifier-base@1.0.0: {} - - universalify@2.0.1: {} - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - utf-8-validate@6.0.3: - dependencies: - node-gyp-build: 4.8.1 - - util-deprecate@1.0.2: {} - - uuid@9.0.1: {} - - validate-npm-package-name@5.0.1: {} - - vite-node@1.6.0(@types/node@18.19.33): - dependencies: - cac: 6.7.14 - debug: 4.3.4 - pathe: 1.1.2 - picocolors: 1.0.1 - vite: 5.2.11(@types/node@18.19.33) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - stylus - - sugarss - - supports-color - - terser - - vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.2.11(@types/node@18.19.33)): - dependencies: - debug: 4.3.4 - globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5) - optionalDependencies: - vite: 5.2.11(@types/node@18.19.33) - transitivePeerDependencies: - - supports-color - - typescript - - vite@5.2.11(@types/node@18.19.33): - dependencies: - esbuild: 0.20.2 - postcss: 8.4.38 - rollup: 4.17.2 - optionalDependencies: - '@types/node': 18.19.33 - fsevents: 2.3.3 - - vitest@1.6.0(@types/node@18.19.33): - dependencies: - '@vitest/expect': 1.6.0 - '@vitest/runner': 1.6.0 - '@vitest/snapshot': 1.6.0 - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - acorn-walk: 8.3.2 - chai: 4.4.1 - debug: 4.3.4 - execa: 8.0.1 - local-pkg: 0.5.0 - magic-string: 0.30.10 - pathe: 1.1.2 - picocolors: 1.0.1 - std-env: 3.7.0 - strip-literal: 2.1.0 - tinybench: 2.8.0 - tinypool: 0.8.4 - vite: 5.2.11(@types/node@18.19.33) - vite-node: 1.6.0(@types/node@18.19.33) - why-is-node-running: 2.2.2 - optionalDependencies: - '@types/node': 18.19.33 - transitivePeerDependencies: - - less - - lightningcss - - sass - - stylus - - sugarss - - supports-color - - terser - - web-streams-polyfill@3.3.3: {} - - webidl-conversions@3.0.1: {} - - webidl-conversions@4.0.2: {} - - webpod@0.0.2: {} - - well-known-symbols@2.0.0: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - whatwg-url@7.1.0: - dependencies: - lodash.sortby: 4.7.0 - tr46: 1.0.1 - webidl-conversions: 4.0.2 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - which@3.0.1: - dependencies: - isexe: 2.0.0 - - why-is-node-running@2.2.2: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - word-wrap@1.2.5: {} - - wordwrap@1.0.0: {} - - workerd@1.20240512.0: - optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20240512.0 - '@cloudflare/workerd-darwin-arm64': 1.20240512.0 - '@cloudflare/workerd-linux-64': 1.20240512.0 - '@cloudflare/workerd-linux-arm64': 1.20240512.0 - '@cloudflare/workerd-windows-64': 1.20240512.0 - - wrangler@3.57.0(@cloudflare/workers-types@4.20240512.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3): - dependencies: - '@cloudflare/kv-asset-handler': 0.3.2 - '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) - '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) - blake3-wasm: 2.1.5 - chokidar: 3.6.0 - esbuild: 0.17.19 - miniflare: 3.20240512.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - nanoid: 3.3.7 - path-to-regexp: 6.2.2 - resolve: 1.22.8 - resolve.exports: 2.0.2 - selfsigned: 2.4.1 - source-map: 0.6.1 - xxhash-wasm: 1.0.2 - optionalDependencies: - '@cloudflare/workers-types': 4.20240512.0 - fsevents: 2.3.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - - wrappy@1.0.2: {} - - write-file-atomic@5.0.1: - dependencies: - imurmurhash: 0.1.4 - signal-exit: 4.1.0 - - ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): - optionalDependencies: - bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - - ws@8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): - optionalDependencies: - bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - - xtend@4.0.2: {} - - xxhash-wasm@1.0.2: {} - - y18n@5.0.8: {} - - yallist@4.0.0: {} - - yaml@2.4.2: {} - - yargs-parser@21.1.1: {} - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.1.2 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yocto-queue@0.1.0: {} - - yocto-queue@1.0.0: {} - - youch@3.3.3: - dependencies: - cookie: 0.5.0 - mustache: 4.2.0 - stacktracey: 2.1.8 - - zod@3.23.8: {} - - zx@7.2.3: - dependencies: - '@types/fs-extra': 11.0.4 - '@types/minimist': 1.2.5 - '@types/node': 18.19.33 - '@types/ps-tree': 1.1.6 - '@types/which': 3.0.3 - chalk: 5.3.0 - fs-extra: 11.2.0 - fx: 34.0.0 - globby: 13.2.2 - minimist: 1.2.8 - node-fetch: 3.3.1 - ps-tree: 1.2.0 - webpod: 0.0.2 - which: 3.0.1 - yaml: 2.4.2 diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index a5b8bfe69..d5b53cc9a 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -6,6 +6,8 @@ import { columnsResolver, enumsResolver, mySqlViewsResolver, + policyResolver, + roleResolver, schemasResolver, sequencesResolver, sqliteViewsResolver, @@ -47,6 +49,7 @@ export const generateDrizzleJson = ( prepared.enums, prepared.schemas, prepared.sequences, + prepared.roles, prepared.views, prepared.matViews, casing, @@ -78,6 +81,8 @@ export const generateMigration = async ( schemasResolver, enumsResolver, sequencesResolver, + policyResolver, + roleResolver, tablesResolver, columnsResolver, viewsResolver, @@ -122,6 +127,8 @@ export const pushSchema = async ( schemasResolver, enumsResolver, sequencesResolver, + policyResolver, + roleResolver, tablesResolver, columnsResolver, viewsResolver, diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 257150dc0..782116d97 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -21,6 +21,7 @@ import { applySqliteSnapshotsDiff, } from '../../snapshotsDiffer'; import { prepareOutFolder } from '../../utils'; +import { Entities } from '../validations/cli'; import type { Casing, Prefix } from '../validations/common'; import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; @@ -31,6 +32,7 @@ import { columnsResolver, enumsResolver, mySqlViewsResolver, + policyResolver, schemasResolver, sequencesResolver, sqliteViewsResolver, @@ -47,6 +49,7 @@ export const introspectPostgres = async ( tablesFilter: string[], schemasFilter: string[], prefix: Prefix, + entities: Entities, ) => { const { preparePostgresDB } = await import('../connections'); const db = await preparePostgresDB(credentials); @@ -79,11 +82,18 @@ export const introspectPostgres = async ( }; const progress = new IntrospectProgress(true); + const res = await renderWithTask( progress, - fromPostgresDatabase(db, filter, schemasFilter, (stage, count, status) => { - progress.update(stage, count, status); - }), + fromPostgresDatabase( + db, + filter, + schemasFilter, + entities, + (stage, count, status) => { + progress.update(stage, count, status); + }, + ), ); const schema = { id: originUUID, prevId: '', ...res } as PgSchema; @@ -106,6 +116,7 @@ export const introspectPostgres = async ( schemasResolver, enumsResolver, sequencesResolver, + policyResolver, tablesResolver, columnsResolver, viewsResolver, diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index c4f1e65d1..b5674e875 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -14,7 +14,7 @@ import path, { join } from 'path'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme, ViewSquashed } from '../../serializer/mysqlSchema'; -import { PgSchema, pgSchema, squashPgScheme, View } from '../../serializer/pgSchema'; +import { PgSchema, pgSchema, Policy, Role, squashPgScheme, View } from '../../serializer/pgSchema'; import { SQLiteSchema, sqliteSchema, squashSqliteScheme, View as SQLiteView } from '../../serializer/sqliteSchema'; import { applyLibSQLSnapshotsDiff, @@ -28,6 +28,8 @@ import { ResolverInput, ResolverOutput, ResolverOutputWithMoved, + RolesResolverInput, + RolesResolverOutput, Sequence, Table, } from '../../snapshotsDiffer'; @@ -41,6 +43,7 @@ import { ResolveColumnSelect, ResolveSchemasSelect, ResolveSelect, + ResolveSelectNamed, schema, } from '../views'; import { GenerateConfig } from './utils'; @@ -180,6 +183,38 @@ export const sequencesResolver = async ( } }; +export const roleResolver = async ( + input: RolesResolverInput, +): Promise> => { + const result = await promptNamedConflict( + input.created, + input.deleted, + 'role', + ); + return { + created: result.created, + deleted: result.deleted, + renamed: result.renamed, + }; +}; + +export const policyResolver = async ( + input: ColumnsResolverInput, +): Promise> => { + const result = await promptColumnsConflicts( + input.tableName, + input.created, + input.deleted, + ); + return { + tableName: input.tableName, + schema: input.schema, + created: result.created, + deleted: result.deleted, + renamed: result.renamed, + }; +}; + export const enumsResolver = async ( input: ResolverInput, ): Promise> => { @@ -264,6 +299,8 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => { schemasResolver, enumsResolver, sequencesResolver, + policyResolver, + roleResolver, tablesResolver, columnsResolver, viewsResolver, @@ -310,6 +347,8 @@ export const preparePgPush = async ( schemasResolver, enumsResolver, sequencesResolver, + policyResolver, + roleResolver, tablesResolver, columnsResolver, viewsResolver, @@ -736,6 +775,78 @@ export const promptColumnsConflicts = async ( return result; }; +export const promptNamedConflict = async ( + newItems: T[], + missingItems: T[], + entity: 'role', +): Promise<{ + created: T[]; + renamed: { from: T; to: T }[]; + deleted: T[]; +}> => { + if (missingItems.length === 0 || newItems.length === 0) { + return { + created: newItems, + renamed: [], + deleted: missingItems, + }; + } + + const result: { + created: T[]; + renamed: { from: T; to: T }[]; + deleted: T[]; + } = { created: [], renamed: [], deleted: [] }; + let index = 0; + let leftMissing = [...missingItems]; + do { + const created = newItems[index]; + const renames: RenamePropmtItem[] = leftMissing.map((it) => { + return { from: it, to: created }; + }); + + const promptData: (RenamePropmtItem | T)[] = [created, ...renames]; + + const { status, data } = await render( + new ResolveSelectNamed(created, promptData, entity), + ); + if (status === 'aborted') { + console.error('ERROR'); + process.exit(1); + } + + if (isRenamePromptItem(data)) { + console.log( + `${chalk.yellow('~')} ${data.from.name} › ${data.to.name} ${ + chalk.gray( + `${entity} will be renamed/moved`, + ) + }`, + ); + + if (data.from.name !== data.to.name) { + result.renamed.push(data); + } + + delete leftMissing[leftMissing.indexOf(data.from)]; + leftMissing = leftMissing.filter(Boolean); + } else { + console.log( + `${chalk.green('+')} ${data.name} ${ + chalk.gray( + `${entity} will be created`, + ) + }`, + ); + result.created.push(created); + } + index += 1; + } while (index < newItems.length); + console.log(chalk.gray(`--- all ${entity} conflicts resolved ---\n`)); + result.deleted.push(...leftMissing); + return result; +}; + export const promptNamedWithSchemasConflict = async ( newItems: T[], missingItems: T[], diff --git a/drizzle-kit/src/cli/commands/pgIntrospect.ts b/drizzle-kit/src/cli/commands/pgIntrospect.ts index dbd3ba238..020ed031b 100644 --- a/drizzle-kit/src/cli/commands/pgIntrospect.ts +++ b/drizzle-kit/src/cli/commands/pgIntrospect.ts @@ -4,12 +4,14 @@ import { originUUID } from '../../global'; import type { PgSchema } from '../../serializer/pgSchema'; import { fromDatabase } from '../../serializer/pgSerializer'; import type { DB } from '../../utils'; +import { Entities } from '../validations/cli'; import { ProgressView } from '../views'; export const pgPushIntrospect = async ( db: DB, filters: string[], schemaFilters: string[], + entities: Entities = { roles: true }, ) => { const matchers = filters.map((it) => { return new Minimatch(it); @@ -43,7 +45,7 @@ export const pgPushIntrospect = async ( ); const res = await renderWithTask( progress, - fromDatabase(db, filter, schemaFilters), + fromDatabase(db, filter, schemaFilters, entities), ); const schema = { id: originUUID, prevId: '', ...res } as PgSchema; diff --git a/drizzle-kit/src/cli/commands/pgPushUtils.ts b/drizzle-kit/src/cli/commands/pgPushUtils.ts index a8e2570df..b53fec3e7 100644 --- a/drizzle-kit/src/cli/commands/pgPushUtils.ts +++ b/drizzle-kit/src/cli/commands/pgPushUtils.ts @@ -252,18 +252,12 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { } const stmnt = fromJson([statement], 'postgresql'); if (typeof stmnt !== 'undefined') { - if (statement.type === 'drop_table') { - statementsToExecute.push( - `DROP TABLE ${concatSchemaAndTableName(statement.schema, statement.tableName)} CASCADE;`, - ); - } else { - statementsToExecute.push(...stmnt); - } + statementsToExecute.push(...stmnt); } } return { - statementsToExecute, + statementsToExecute: [...new Set(statementsToExecute)], shouldAskForApprove, infoToPrint, matViewsToRemove: [...new Set(matViewsToRemove)], diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index f84f84d9c..7ef690d81 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -2,6 +2,7 @@ import chalk from 'chalk'; import { render } from 'hanji'; import { fromJson } from '../../sqlgenerator'; import { Select } from '../selector-ui'; +import { Entities } from '../validations/cli'; import { CasingType } from '../validations/common'; import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; @@ -160,6 +161,7 @@ export const pgPush = async ( credentials: PostgresCredentials, tablesFilter: string[], schemasFilter: string[], + entities: Entities, force: boolean, casing: CasingType | undefined, ) => { @@ -167,7 +169,7 @@ export const pgPush = async ( const { pgPushIntrospect } = await import('./pgIntrospect'); const db = await preparePostgresDB(credentials); - const { schema } = await pgPushIntrospect(db, tablesFilter, schemasFilter); + const { schema } = await pgPushIntrospect(db, tablesFilter, schemasFilter, entities); const { preparePgPush } = await import('./migrate'); diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index e58e23435..a4c018aa5 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -6,7 +6,7 @@ import { object, string } from 'zod'; import { assertUnreachable } from '../../global'; import { type Dialect, dialect } from '../../schemaValidator'; import { prepareFilenames } from '../../serializer'; -import { pullParams, pushParams } from '../validations/cli'; +import { Entities, pullParams, pushParams } from '../validations/cli'; import { Casing, CasingType, @@ -391,6 +391,7 @@ export const preparePullConfig = async ( tablesFilter: string[]; schemasFilter: string[]; prefix: Prefix; + entities: Entities; } > => { const raw = flattenPull( @@ -450,6 +451,7 @@ export const preparePullConfig = async ( tablesFilter, schemasFilter, prefix: config.migrations?.prefix || 'index', + entities: config.entities, }; } @@ -468,6 +470,7 @@ export const preparePullConfig = async ( tablesFilter, schemasFilter, prefix: config.migrations?.prefix || 'index', + entities: config.entities, }; } @@ -486,6 +489,7 @@ export const preparePullConfig = async ( tablesFilter, schemasFilter, prefix: config.migrations?.prefix || 'index', + entities: config.entities, }; } diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index aaded5cdf..9886d2b61 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -450,6 +450,7 @@ export const pull = command({ tablesFilter, schemasFilter, prefix, + entities, } = config; mkdirSync(out, { recursive: true }); @@ -496,6 +497,7 @@ export const pull = command({ tablesFilter, schemasFilter, prefix, + entities, ); } else if (dialect === 'mysql') { const { introspectMysql } = await import('./commands/introspect'); diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index aa92f7c6d..ef271e299 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -1,4 +1,4 @@ -import { boolean, intersection, literal, object, string, TypeOf, union } from 'zod'; +import { array, boolean, intersection, literal, object, string, TypeOf, union } from 'zod'; import { dialect } from '../../schemaValidator'; import { casing, casingType, prefix } from './common'; @@ -44,8 +44,17 @@ export const pullParams = object({ migrations: object({ prefix: prefix.optional().default('index'), }).optional(), + entities: object({ + roles: boolean().or(object({ + provider: string().optional(), + include: string().array().optional(), + exclude: string().array().optional(), + })).optional().default(false), + }).optional(), }).passthrough(); +export type Entities = TypeOf['entities']; + export type PullParams = TypeOf; export const configCheck = object({ diff --git a/drizzle-kit/src/cli/views.ts b/drizzle-kit/src/cli/views.ts index fd4a68d71..ef00ab8c4 100644 --- a/drizzle-kit/src/cli/views.ts +++ b/drizzle-kit/src/cli/views.ts @@ -158,6 +158,77 @@ export const tableKey = (it: NamedWithSchema) => { : `${it.schema}.${it.name}`; }; +export class ResolveSelectNamed extends Prompt< + RenamePropmtItem | T +> { + private readonly state: SelectState | T>; + + constructor( + private readonly base: T, + data: (RenamePropmtItem | T)[], + private readonly entityType: 'role', + ) { + super(); + this.on('attach', (terminal) => terminal.toggleCursor('hide')); + this.state = new SelectState(data); + this.state.bind(this); + this.base = base; + } + + render(status: 'idle' | 'submitted' | 'aborted'): string { + if (status === 'submitted' || status === 'aborted') { + return ''; + } + const key = this.base.name; + + let text = `\nIs ${chalk.bold.blue(key)} ${this.entityType} created or renamed from another ${this.entityType}?\n`; + + const isSelectedRenamed = isRenamePromptItem( + this.state.items[this.state.selectedIdx], + ); + + const selectedPrefix = isSelectedRenamed + ? chalk.yellow('❯ ') + : chalk.green('❯ '); + + const labelLength: number = this.state.items + .filter((it) => isRenamePromptItem(it)) + .map((_) => { + const it = _ as RenamePropmtItem; + const keyFrom = it.from.name; + return key.length + 3 + keyFrom.length; + }) + .reduce((a, b) => { + if (a > b) { + return a; + } + return b; + }, 0); + + const entityType = this.entityType; + this.state.items.forEach((it, idx) => { + const isSelected = idx === this.state.selectedIdx; + const isRenamed = isRenamePromptItem(it); + + const title = isRenamed + ? `${it.from.name} › ${it.to.name}`.padEnd(labelLength, ' ') + : it.name.padEnd(labelLength, ' '); + + const label = isRenamed + ? `${chalk.yellow('~')} ${title} ${chalk.gray(`rename ${entityType}`)}` + : `${chalk.green('+')} ${title} ${chalk.gray(`create ${entityType}`)}`; + + text += isSelected ? `${selectedPrefix}${label}` : ` ${label}`; + text += idx != this.state.items.length - 1 ? '\n' : ''; + }); + return text; + } + + result(): RenamePropmtItem | T { + return this.state.items[this.state.selectedIdx]!; + } +} + export class ResolveSelect extends Prompt< RenamePropmtItem | T > { @@ -166,7 +237,7 @@ export class ResolveSelect extends Prompt< constructor( private readonly base: T, data: (RenamePropmtItem | T)[], - private readonly entityType: 'table' | 'enum' | 'sequence' | 'view', + private readonly entityType: 'table' | 'enum' | 'sequence' | 'view' | 'role', ) { super(); this.on('attach', (terminal) => terminal.toggleCursor('hide')); @@ -330,9 +401,11 @@ export type IntrospectStage = | 'columns' | 'enums' | 'indexes' + | 'policies' | 'checks' | 'fks' | 'views'; + type IntrospectState = { [key in IntrospectStage]: { count: number; @@ -371,6 +444,11 @@ export class IntrospectProgress extends TaskView { name: 'foreign keys', status: 'fetching', }, + policies: { + count: 0, + name: 'policies', + status: 'fetching', + }, checks: { count: 0, name: 'check constraints', @@ -434,6 +512,7 @@ export class IntrospectProgress extends TaskView { info += this.hasEnums ? this.statusText(spin, this.state.enums) : ''; info += this.statusText(spin, this.state.indexes); info += this.statusText(spin, this.state.fks); + info += this.statusText(spin, this.state.policies); info += this.statusText(spin, this.state.checks); info += this.statusText(spin, this.state.views); diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 750d491ac..4a57e59e3 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -126,6 +126,9 @@ export type Config = introspect?: { casing: 'camel' | 'preserve'; }; + entities?: { + roles?: boolean | { provider?: 'supabase' | 'neon' | string & {}; exclude?: string[]; include?: string[] }; + }; } & ( | { diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index 1b57f0115..ed26e8117 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -20,6 +20,7 @@ import { Index, PgKitInternals, PgSchemaInternal, + Policy, PrimaryKey, UniqueConstraint, } from './serializer/pgSchema'; @@ -339,6 +340,10 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => (it) => 'check', ); + const policiesImports = Object.values(it.policies).map( + (it) => 'pgPolicy', + ); + if (it.schema && it.schema !== 'public' && it.schema !== '') { res.pg.push('pgSchema'); } @@ -347,6 +352,7 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => res.pg.push(...fkImpots); res.pg.push(...pkImports); res.pg.push(...uniqueImports); + res.pg.push(...policiesImports); res.pg.push(...checkImports); const columnImports = Object.values(it.columns) @@ -417,6 +423,10 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => } }); + if (Object.keys(schema.roles).length > 0) { + imports.pg.push('pgRole'); + } + const enumStatements = Object.values(schema.enums) .map((it) => { const enumSchema = schemas[it.schema]; @@ -468,7 +478,7 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => })\n`; }) .join('') - .concat('\n'); + .concat(''); const schemaStatements = Object.entries(schemas) // .filter((it) => it[0] !== "public") @@ -477,6 +487,24 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => }) .join(''); + const rolesNameToTsKey: Record = {}; + + const rolesStatements = Object.entries(schema.roles) + .map((it) => { + const fields = it[1]; + rolesNameToTsKey[fields.name] = it[0]; + return `export const ${withCasing(it[0], casing)} = pgRole("${fields.name}", ${ + !fields.createDb && !fields.createRole && fields.inherit + ? '' + : `${ + `, { ${fields.createDb ? `createDb: true,` : ''}${fields.createRole ? ` createRole: true,` : ''}${ + !fields.inherit ? ` inherit: false ` : '' + }`.trimChar(',') + }}` + } );\n`; + }) + .join(''); + const tableStatements = Object.values(schema.tables).map((table) => { const tableSchema = schemas[table.schema]; const paramName = paramNameFor(table.name, tableSchema); @@ -503,11 +531,12 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => if ( Object.keys(table.indexes).length > 0 || Object.values(table.foreignKeys).length > 0 + || Object.values(table.policies).length > 0 || Object.keys(table.compositePrimaryKeys).length > 0 || Object.keys(table.uniqueConstraints).length > 0 || Object.keys(table.checkConstraints).length > 0 ) { - statement += ',\n'; + statement += ', '; statement += '(table) => {\n'; statement += '\treturn {\n'; statement += createTableIndexes(table.name, Object.values(table.indexes), casing); @@ -520,6 +549,11 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => Object.values(table.uniqueConstraints), casing, ); + statement += createTablePolicies( + Object.values(table.policies), + casing, + rolesNameToTsKey, + ); statement += createTableChecks( Object.values(table.checkConstraints), casing, @@ -571,10 +605,15 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => const uniquePgImports = ['pgTable', ...new Set(imports.pg)]; - const importsTs = `import { ${uniquePgImports.join(', ')} } from "drizzle-orm/pg-core" - import { sql } from "drizzle-orm"\n\n`; + const importsTs = `import { ${ + uniquePgImports.join( + ', ', + ) + } } from "drizzle-orm/pg-core" +import { sql } from "drizzle-orm"\n\n`; let decalrations = schemaStatements; + decalrations += rolesStatements; decalrations += enumStatements; decalrations += sequencesStatements; decalrations += '\n'; @@ -1227,7 +1266,39 @@ const createTablePKs = (pks: PrimaryKey[], casing: Casing): string => { return statement; }; -const createTableUniques = (unqs: UniqueConstraint[], casing: Casing): string => { +// get a map of db role name to ts key +// if to by key is in this map - no quotes, otherwise - quotes + +const createTablePolicies = ( + policies: Policy[], + casing: Casing, + rolesNameToTsKey: Record = {}, +): string => { + let statement = ''; + + policies.forEach((it) => { + const idxKey = withCasing(it.name, casing); + + const mappedItTo = it.to?.map((v) => { + return rolesNameToTsKey[v] ? withCasing(rolesNameToTsKey[v], casing) : `"${v}"`; + }); + + statement += `\t\t${idxKey}: `; + statement += 'pgPolicy('; + statement += `"${it.name}", { `; + statement += `as: "${it.as?.toLowerCase()}", for: "${it.for?.toLowerCase()}", to: [${mappedItTo?.join(', ')}]${ + it.using ? `, using: sql\`${it.using}\`` : '' + }${it.withCheck ? `, withCheck: sql\`${it.withCheck}\` ` : ''}`; + statement += ` }),\n`; + }); + + return statement; +}; + +const createTableUniques = ( + unqs: UniqueConstraint[], + casing: Casing, +): string => { let statement = ''; unqs.forEach((it) => { diff --git a/drizzle-kit/src/jsonDiffer.js b/drizzle-kit/src/jsonDiffer.js index b5a0e3652..78155c8bd 100644 --- a/drizzle-kit/src/jsonDiffer.js +++ b/drizzle-kit/src/jsonDiffer.js @@ -146,6 +146,49 @@ export function diffColumns(left, right) { return alteredTables; } +export function diffPolicies(left, right) { + left = JSON.parse(JSON.stringify(left)); + right = JSON.parse(JSON.stringify(right)); + const result = diff(left, right) ?? {}; + + const alteredTables = Object.fromEntries( + Object.entries(result) + .filter((it) => { + return !(it[0].includes('__added') || it[0].includes('__deleted')); + }) + .map((tableEntry) => { + // const entry = { name: it, ...result[it] } + const deletedPolicies = Object.entries(tableEntry[1].policies ?? {}) + .filter((it) => { + return it[0].endsWith('__deleted'); + }) + .map((it) => { + return it[1]; + }); + + const addedPolicies = Object.entries(tableEntry[1].policies ?? {}) + .filter((it) => { + return it[0].endsWith('__added'); + }) + .map((it) => { + return it[1]; + }); + + tableEntry[1].policies = { + added: addedPolicies, + deleted: deletedPolicies, + }; + const table = left[tableEntry[0]]; + return [ + tableEntry[0], + { name: table.name, schema: table.schema, ...tableEntry[1] }, + ]; + }), + ); + + return alteredTables; +} + export function applyJsonDiff(json1, json2) { json1 = JSON.parse(JSON.stringify(json1)); json2 = JSON.parse(JSON.stringify(json2)); @@ -158,6 +201,7 @@ export function applyJsonDiff(json1, json2) { difference.tables = difference.tables || {}; difference.enums = difference.enums || {}; difference.sequences = difference.sequences || {}; + difference.roles = difference.roles || {}; difference.views = difference.views || {}; // remove added/deleted schemas @@ -240,6 +284,12 @@ export function applyJsonDiff(json1, json2) { return json2.sequences[it[0]]; }); + const rolesEntries = Object.entries(difference.roles); + const alteredRoles = rolesEntries + .filter((it) => !(it[0].includes('__added') || it[0].includes('__deleted'))) + .map((it) => { + return json2.roles[it[0]]; + }); const viewsEntries = Object.entries(difference.views); const alteredViews = viewsEntries.filter((it) => !(it[0].includes('__added') || it[0].includes('__deleted'))).map( @@ -329,6 +379,7 @@ export function applyJsonDiff(json1, json2) { alteredTablesWithColumns, alteredEnums, alteredSequences, + alteredRoles, alteredViews, }; } @@ -367,6 +418,28 @@ const findAlternationsInTable = (table) => { }), ); + const deletedPolicies = Object.fromEntries( + Object.entries(table.policies__deleted || {}) + .concat( + Object.entries(table.policies || {}).filter((it) => it[0].includes('__deleted')), + ) + .map((entry) => [entry[0].replace('__deleted', ''), entry[1]]), + ); + + const addedPolicies = Object.fromEntries( + Object.entries(table.policies__added || {}) + .concat( + Object.entries(table.policies || {}).filter((it) => it[0].includes('__added')), + ) + .map((entry) => [entry[0].replace('__added', ''), entry[1]]), + ); + + const alteredPolicies = Object.fromEntries( + Object.entries(table.policies || {}).filter((it) => { + return !it[0].endsWith('__deleted') && !it[0].endsWith('__added'); + }), + ); + const deletedForeignKeys = Object.fromEntries( Object.entries(table.foreignKeys__deleted || {}) .concat( @@ -463,6 +536,9 @@ const findAlternationsInTable = (table) => { addedUniqueConstraints, deletedUniqueConstraints, alteredUniqueConstraints, + deletedPolicies, + addedPolicies, + alteredPolicies, addedCheckConstraints, deletedCheckConstraints, alteredCheckConstraints, diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 4285c4687..0d248422d 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -3,7 +3,16 @@ import { getNewTableName } from './cli/commands/sqlitePushUtils'; import { warning } from './cli/views'; import { CommonSquashedSchema } from './schemaValidator'; import { MySqlKitInternals, MySqlSchema, MySqlSquasher, View as MySqlView } from './serializer/mysqlSchema'; -import { Index, MatViewWithOption, PgSchema, PgSquasher, View as PgView, ViewWithOption } from './serializer/pgSchema'; +import { + Index, + MatViewWithOption, + PgSchema, + PgSquasher, + Policy, + Role, + View as PgView, + ViewWithOption, +} from './serializer/pgSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, @@ -39,8 +48,10 @@ export interface JsonCreateTableStatement { compositePKs: string[]; compositePkName?: string; uniqueConstraints?: string[]; + policies?: string[]; checkConstraints?: string[]; internals?: MySqlKitInternals; + isRLSEnabled?: boolean; } export interface JsonRecreateTableStatement { @@ -65,6 +76,7 @@ export interface JsonDropTableStatement { type: 'drop_table'; tableName: string; schema: string; + policies?: string[]; } export interface JsonRenameTableStatement { @@ -110,6 +122,40 @@ export interface JsonAddValueToEnumStatement { before: string; } +////// + +export interface JsonCreateRoleStatement { + type: 'create_role'; + name: string; + values: { + inherit?: boolean; + createDb?: boolean; + createRole?: boolean; + }; +} + +export interface JsonDropRoleStatement { + type: 'drop_role'; + name: string; +} +export interface JsonRenameRoleStatement { + type: 'rename_role'; + nameFrom: string; + nameTo: string; +} + +export interface JsonAlterRoleStatement { + type: 'alter_role'; + name: string; + values: { + inherit?: boolean; + createDb?: boolean; + createRole?: boolean; + }; +} + +////// + export interface JsonDropValueFromEnumStatement { type: 'alter_type_drop_value'; name: string; @@ -188,6 +234,48 @@ export interface JsonSqliteAddColumnStatement { referenceData?: string; } +export interface JsonCreatePolicyStatement { + type: 'create_policy'; + tableName: string; + data: Policy; + schema: string; +} + +export interface JsonDropPolicyStatement { + type: 'drop_policy'; + tableName: string; + data: Policy; + schema: string; +} + +export interface JsonRenamePolicyStatement { + type: 'rename_policy'; + tableName: string; + oldName: string; + newName: string; + schema: string; +} + +export interface JsonEnableRLSStatement { + type: 'enable_rls'; + tableName: string; + schema: string; +} + +export interface JsonDisableRLSStatement { + type: 'disable_rls'; + tableName: string; + schema: string; +} + +export interface JsonAlterPolicyStatement { + type: 'alter_policy'; + tableName: string; + oldData: string; + newData: string; + schema: string; +} + export interface JsonCreateIndexStatement { type: 'create_index'; tableName: string; @@ -709,6 +797,16 @@ export type JsonStatement = | JsonCreateSequenceStatement | JsonMoveSequenceStatement | JsonRenameSequenceStatement + | JsonDropPolicyStatement + | JsonCreatePolicyStatement + | JsonAlterPolicyStatement + | JsonRenamePolicyStatement + | JsonEnableRLSStatement + | JsonDisableRLSStatement + | JsonRenameRoleStatement + | JsonCreateRoleStatement + | JsonDropRoleStatement + | JsonAlterRoleStatement | JsonCreatePgViewStatement | JsonDropViewStatement | JsonRenameViewStatement @@ -725,7 +823,8 @@ export const preparePgCreateTableJson = ( // TODO: remove? json2: PgSchema, ): JsonCreateTableStatement => { - const { name, schema, columns, compositePrimaryKeys, uniqueConstraints, checkConstraints } = table; + const { name, schema, columns, compositePrimaryKeys, uniqueConstraints, checkConstraints, policies, isRLSEnabled } = + table; const tableKey = `${schema || 'public'}.${name}`; // TODO: @AndriiSherman. We need this, will add test cases @@ -743,7 +842,9 @@ export const preparePgCreateTableJson = ( compositePKs: Object.values(compositePrimaryKeys), compositePkName: compositePkName, uniqueConstraints: Object.values(uniqueConstraints), + policies: Object.values(policies), checkConstraints: Object.values(checkConstraints), + isRLSEnabled: isRLSEnabled ?? false, }; }; @@ -810,6 +911,7 @@ export const prepareDropTableJson = (table: Table): JsonDropTableStatement => { type: 'drop_table', tableName: table.name, schema: table.schema, + policies: table.policies ? Object.values(table.policies) : [], }; }; @@ -990,6 +1092,56 @@ export const prepareRenameSequenceJson = ( //////////// +export const prepareCreateRoleJson = ( + role: Role, +): JsonCreateRoleStatement => { + return { + type: 'create_role', + name: role.name, + values: { + createDb: role.createDb, + createRole: role.createRole, + inherit: role.inherit, + }, + }; +}; + +export const prepareAlterRoleJson = ( + role: Role, +): JsonAlterRoleStatement => { + return { + type: 'alter_role', + name: role.name, + values: { + createDb: role.createDb, + createRole: role.createRole, + inherit: role.inherit, + }, + }; +}; + +export const prepareDropRoleJson = ( + name: string, +): JsonDropRoleStatement => { + return { + type: 'drop_role', + name: name, + }; +}; + +export const prepareRenameRoleJson = ( + nameFrom: string, + nameTo: string, +): JsonRenameRoleStatement => { + return { + type: 'rename_role', + nameFrom, + nameTo, + }; +}; + +////////// + export const prepareCreateSchemasJson = ( values: string[], ): JsonCreateSchema[] => { @@ -2128,6 +2280,70 @@ export const prepareSqliteAlterColumns = ( return [...dropPkStatements, ...setPkStatements, ...statements]; }; +export const prepareRenamePolicyJsons = ( + tableName: string, + schema: string, + renames: { + from: Policy; + to: Policy; + }[], +): JsonRenamePolicyStatement[] => { + return renames.map((it) => { + return { + type: 'rename_policy', + tableName: tableName, + oldName: it.from.name, + newName: it.to.name, + schema, + }; + }); +}; + +export const prepareCreatePolicyJsons = ( + tableName: string, + schema: string, + policies: Policy[], +): JsonCreatePolicyStatement[] => { + return policies.map((it) => { + return { + type: 'create_policy', + tableName, + data: it, + schema, + }; + }); +}; + +export const prepareDropPolicyJsons = ( + tableName: string, + schema: string, + policies: Policy[], +): JsonDropPolicyStatement[] => { + return policies.map((it) => { + return { + type: 'drop_policy', + tableName, + data: it, + schema, + }; + }); +}; + +export const prepareAlterPolicyJson = ( + tableName: string, + schema: string, + oldPolicy: string, + newPolicy: string, +): JsonAlterPolicyStatement => { + return { + type: 'alter_policy', + tableName, + oldData: oldPolicy, + newData: newPolicy, + schema, + }; +}; + export const preparePgCreateIndexesJson = ( tableName: string, schema: string, diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index 05e4a6f37..6347c2182 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -66,11 +66,11 @@ export const serializePg = async ( const { prepareFromPgImports } = await import('./pgImports'); const { generatePgSnapshot } = await import('./pgSerializer'); - const { tables, enums, schemas, sequences, views, matViews } = await prepareFromPgImports( + const { tables, enums, schemas, sequences, views, matViews, roles } = await prepareFromPgImports( filenames, ); - return generatePgSnapshot(tables, enums, schemas, sequences, views, matViews, casing, schemaFilter); + return generatePgSnapshot(tables, enums, schemas, sequences, roles, views, matViews, casing, schemaFilter); }; export const serializeSQLite = async ( diff --git a/drizzle-kit/src/serializer/pgImports.ts b/drizzle-kit/src/serializer/pgImports.ts index e0b3fb743..c1ecdb04c 100644 --- a/drizzle-kit/src/serializer/pgImports.ts +++ b/drizzle-kit/src/serializer/pgImports.ts @@ -7,6 +7,7 @@ import { isPgView, PgEnum, PgMaterializedView, + PgRole, PgSchema, PgSequence, PgTable, @@ -19,6 +20,7 @@ export const prepareFromExports = (exports: Record) => { const enums: PgEnum[] = []; const schemas: PgSchema[] = []; const sequences: PgSequence[] = []; + const roles: PgRole[] = []; const views: PgView[] = []; const matViews: PgMaterializedView[] = []; @@ -47,9 +49,13 @@ export const prepareFromExports = (exports: Record) => { if (isPgSequence(t)) { sequences.push(t); } + + if (is(t, PgRole)) { + roles.push(t); + } }); - return { tables, enums, schemas, sequences, views, matViews }; + return { tables, enums, schemas, sequences, views, matViews, roles }; }; export const prepareFromPgImports = async (imports: string[]) => { @@ -58,6 +64,7 @@ export const prepareFromPgImports = async (imports: string[]) => { const schemas: PgSchema[] = []; const sequences: PgSequence[] = []; const views: PgView[] = []; + let roles: PgRole[] = []; const matViews: PgMaterializedView[] = []; const { unregister } = await safeRegister(); @@ -73,8 +80,9 @@ export const prepareFromPgImports = async (imports: string[]) => { sequences.push(...prepared.sequences); views.push(...prepared.views); matViews.push(...prepared.matViews); + roles.push(...prepared.roles); } unregister(); - return { tables: Array.from(new Set(tables)), enums, schemas, sequences, views, matViews }; + return { tables: Array.from(new Set(tables)), enums, schemas, sequences, views, matViews, roles }; }; diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index d4d27cb86..52c5a192a 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -148,6 +148,13 @@ export const sequenceSchema = object({ schema: string(), }).strict(); +export const roleSchema = object({ + name: string(), + createDb: boolean().optional(), + createRole: boolean().optional(), + inherit: boolean().optional(), +}).strict(); + export const sequenceSquashed = object({ name: string(), schema: string(), @@ -225,6 +232,15 @@ const uniqueConstraint = object({ nullsNotDistinct: boolean(), }).strict(); +const policy = object({ + name: string(), + as: enumType(['PERMISSIVE', 'RESTRICTIVE']).optional(), + for: enumType(['ALL', 'SELECT', 'INSERT', 'UPDATE', 'DELETE']).optional(), + to: string().array().optional(), + using: string().optional(), + withCheck: string().optional(), +}).strict(); + const viewWithOption = object({ checkOption: enumType(['local', 'cascaded']).optional(), securityBarrier: boolean().optional(), @@ -313,7 +329,9 @@ const table = object({ foreignKeys: record(string(), fk), compositePrimaryKeys: record(string(), compositePK), uniqueConstraints: record(string(), uniqueConstraint).default({}), + policies: record(string(), policy).default({}), checkConstraints: record(string(), checkConstraint).default({}), + isRLSEnabled: boolean().default(false), }).strict(); const schemaHash = object({ @@ -418,6 +436,7 @@ export const pgSchemaInternal = object({ schemas: record(string(), string()), views: record(string(), view).default({}), sequences: record(string(), sequenceSchema).default({}), + roles: record(string(), roleSchema).default({}), _meta: object({ schemas: record(string(), string()), tables: record(string(), string()), @@ -434,7 +453,9 @@ const tableSquashed = object({ foreignKeys: record(string(), string()), compositePrimaryKeys: record(string(), string()), uniqueConstraints: record(string(), string()), + policies: record(string(), string()), checkConstraints: record(string(), string()), + isRLSEnabled: boolean().default(false), }).strict(); const tableSquashedV4 = object({ @@ -469,6 +490,7 @@ export const pgSchemaSquashed = object({ schemas: record(string(), string()), views: record(string(), view), sequences: record(string(), sequenceSquashed), + roles: record(string(), roleSchema).default({}), }).strict(); export const pgSchemaV3 = pgSchemaInternalV3.merge(schemaHash); @@ -480,6 +502,7 @@ export const pgSchema = pgSchemaInternal.merge(schemaHash); export type Enum = TypeOf; export type Sequence = TypeOf; +export type Role = TypeOf; export type Column = TypeOf; export type TableV3 = TypeOf; export type TableV4 = TypeOf; @@ -496,6 +519,7 @@ export type Index = TypeOf; export type ForeignKey = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; +export type Policy = TypeOf; export type View = TypeOf; export type MatViewWithOption = TypeOf; export type ViewWithOption = TypeOf; @@ -605,6 +629,23 @@ export const PgSquasher = { fk.onUpdate ?? '' };${fk.onDelete ?? ''};${fk.schemaTo || 'public'}`; }, + squashPolicy: (policy: Policy) => { + return `${policy.name}--${policy.as}--${policy.for}--${policy.to?.join(',')}--${policy.using}--${policy.withCheck}`; + }, + unsquashPolicy: (policy: string): Policy => { + const splitted = policy.split('--'); + return { + name: splitted[0], + as: splitted[1] as Policy['as'], + for: splitted[2] as Policy['for'], + to: splitted[3].split(','), + using: splitted[4] !== 'undefined' ? splitted[4] : undefined, + withCheck: splitted[5] !== 'undefined' ? splitted[5] : undefined, + }; + }, + squashPolicyPush: (policy: Policy) => { + return `${policy.name}--${policy.as}--${policy.for}--${policy.to?.join(',')}`; + }, squashPK: (pk: PrimaryKey) => { return `${pk.columns.join(',')};${pk.name}`; }, @@ -738,6 +779,11 @@ export const squashPgScheme = ( }, ); + const squashedPolicies = mapValues(it[1].policies, (policy) => { + return action === 'push' + ? PgSquasher.squashPolicyPush(policy) + : PgSquasher.squashPolicy(policy); + }); const squashedChecksContraints = mapValues( it[1].checkConstraints, (check) => { @@ -755,7 +801,9 @@ export const squashPgScheme = ( foreignKeys: squashedFKs, compositePrimaryKeys: squashedPKs, uniqueConstraints: squashedUniqueConstraints, + policies: squashedPolicies, checkConstraints: squashedChecksContraints, + isRLSEnabled: it[1].isRLSEnabled ?? false, }, ]; }), @@ -782,6 +830,7 @@ export const squashPgScheme = ( schemas: json.schemas, views: json.views, sequences: mappedSequences, + roles: json.roles, }; }; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 3c54b01f4..98848918a 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -12,6 +12,7 @@ import { PgEnum, PgEnumColumn, PgMaterializedView, + PgRole, PgSchema, PgSequence, PgView, @@ -31,7 +32,9 @@ import type { IndexColumnType, PgKitInternals, PgSchemaInternal, + Policy, PrimaryKey, + Role, Sequence, Table, UniqueConstraint, @@ -53,7 +56,7 @@ function maxRangeForIdentityBasedOn(columnType: string) { } function minRangeForIdentityBasedOn(columnType: string) { - return columnType === 'integer' ? '-2147483648' : columnType === 'bitint' ? '-9223372036854775808' : '-32768'; + return columnType === 'integer' ? '-2147483648' : columnType === 'bigint' ? '-9223372036854775808' : '-32768'; } function stringFromDatabaseIdentityProperty(field: any): string | undefined { @@ -66,7 +69,7 @@ function stringFromDatabaseIdentityProperty(field: any): string | undefined { : String(field); } -function buildArrayString(array: any[], sqlType: string): string { +export function buildArrayString(array: any[], sqlType: string): string { sqlType = sqlType.split('[')[0]; const values = array .map((value) => { @@ -100,6 +103,7 @@ export const generatePgSnapshot = ( enums: PgEnum[], schemas: PgSchema[], sequences: PgSequence[], + roles: PgRole[], views: PgView[], matViews: PgMaterializedView[], casing: CasingType | undefined, @@ -109,6 +113,7 @@ export const generatePgSnapshot = ( const result: Record = {}; const resultViews: Record = {}; const sequencesToReturn: Record = {}; + const rolesToReturn: Record = {}; // This object stores unique names for indexes and will be used to detect if you have the same names for indexes // within the same PostgreSQL schema @@ -119,8 +124,18 @@ export const generatePgSnapshot = ( // within the same PostgreSQL table const checksInTable: Record = {}; - const { name: tableName, columns, indexes, foreignKeys, checks, schema, primaryKeys, uniqueConstraints } = - getTableConfig(table); + const { + name: tableName, + columns, + indexes, + foreignKeys, + checks, + schema, + primaryKeys, + uniqueConstraints, + policies, + enableRLS, + } = getTableConfig(table); if (schemaFilter && !schemaFilter.includes(schema ?? 'public')) { continue; @@ -132,6 +147,7 @@ export const generatePgSnapshot = ( const foreignKeysObject: Record = {}; const primaryKeysObject: Record = {}; const uniqueConstraintObject: Record = {}; + const policiesObject: Record = {}; columns.forEach((column) => { const name = getColumnCasing(column, casing); @@ -459,6 +475,37 @@ export const generatePgSnapshot = ( }; }); + policies.forEach((policy) => { + const mappedTo = []; + + if (!policy.to) { + mappedTo.push('public'); + } else { + if (policy.to && typeof policy.to === 'string') { + mappedTo.push(policy.to); + } else if (policy.to && is(policy.to, PgRole)) { + mappedTo.push(policy.to.name); + } else if (policy.to && Array.isArray(policy.to)) { + policy.to.forEach((it) => { + if (typeof it === 'string') { + mappedTo.push(it); + } else if (is(it, PgRole)) { + mappedTo.push(it.name); + } + }); + } + } + + policiesObject[policy.name] = { + name: policy.name, + as: policy.as?.toUpperCase() as Policy['as'] ?? 'PERMISSIVE', + for: policy.for?.toUpperCase() as Policy['for'] ?? 'ALL', + to: mappedTo.sort(), + using: is(policy.using, SQL) ? dialect.sqlToQuery(policy.using).sql : undefined, + withCheck: is(policy.withCheck, SQL) ? dialect.sqlToQuery(policy.withCheck).sql : undefined, + }; + }); + checks.forEach((check) => { const checkName = check.name; @@ -506,7 +553,9 @@ export const generatePgSnapshot = ( foreignKeys: foreignKeysObject, compositePrimaryKeys: primaryKeysObject, uniqueConstraints: uniqueConstraintObject, + policies: policiesObject, checkConstraints: checksObject, + isRLSEnabled: enableRLS, }; } @@ -537,6 +586,16 @@ export const generatePgSnapshot = ( } } + for (const role of roles) { + if (!(role as any)._existing) { + rolesToReturn[role.name] = { + name: role.name, + createDb: (role as any).createDb === undefined ? false : (role as any).createDb, + createRole: (role as any).createRole === undefined ? false : (role as any).createRole, + inherit: (role as any).inherit === undefined ? true : (role as any).inherit, + }; + } + } const combinedViews = [...views, ...matViews]; for (const view of combinedViews) { let viewName; @@ -735,6 +794,7 @@ export const generatePgSnapshot = ( enums: enumsToReturn, schemas: schemasObject, sequences: sequencesToReturn, + roles: rolesToReturn, views: resultViews, _meta: { schemas: {}, @@ -755,11 +815,64 @@ const trimChar = (str: string, char: string) => { return start > 0 || end < str.length ? str.substring(start, end) : str.toString(); }; +function prepareRoles(entities?: { + roles: boolean | { + provider?: string | undefined; + include?: string[] | undefined; + exclude?: string[] | undefined; + }; +}) { + let useRoles: boolean = false; + const includeRoles: string[] = []; + const excludeRoles: string[] = []; + + if (entities && entities.roles) { + if (typeof entities.roles === 'object') { + if (entities.roles.provider) { + if (entities.roles.provider === 'supabase') { + excludeRoles.push(...[ + 'anon', + 'authenticator', + 'authenticated', + 'service_role', + 'supabase_auth_admin', + 'supabase_storage_admin', + 'dashboard_user', + 'supabase_admin', + ]); + } else if (entities.roles.provider === 'neon') { + excludeRoles.push(...['authenticated', 'anonymous']); + } + } + if (entities.roles.include) { + includeRoles.push(...entities.roles.include); + } + if (entities.roles.exclude) { + excludeRoles.push(...entities.roles.exclude); + } + } else { + useRoles = entities.roles; + } + } + return { useRoles, includeRoles, excludeRoles }; +} + export const fromDatabase = async ( db: DB, tablesFilter: (table: string) => boolean = () => true, schemaFilters: string[], - progressCallback?: (stage: IntrospectStage, count: number, status: IntrospectStatus) => void, + entities?: { + roles: boolean | { + provider?: string | undefined; + include?: string[] | undefined; + exclude?: string[] | undefined; + }; + }, + progressCallback?: ( + stage: IntrospectStage, + count: number, + status: IntrospectStatus, + ) => void, ): Promise => { const result: Record = {}; const views: Record = {}; @@ -767,7 +880,7 @@ export const fromDatabase = async ( const where = schemaFilters.map((t) => `n.nspname = '${t}'`).join(' or '); - const allTables = await db.query<{ table_schema: string; table_name: string; type: string }>( + const allTables = await db.query<{ table_schema: string; table_name: string; type: string; rls_enabled: boolean }>( `SELECT n.nspname AS table_schema, c.relname AS table_name, @@ -775,7 +888,8 @@ export const fromDatabase = async ( WHEN c.relkind = 'r' THEN 'table' WHEN c.relkind = 'v' THEN 'view' WHEN c.relkind = 'm' THEN 'materialized_view' - END AS type + END AS type, + c.relrowsecurity AS rls_enabled FROM pg_catalog.pg_class c JOIN @@ -880,6 +994,96 @@ WHERE progressCallback('enums', Object.keys(enumsToReturn).length, 'done'); } + const allRoles = await db.query< + { rolname: string; rolinherit: boolean; rolcreatedb: boolean; rolcreaterole: boolean } + >( + `SELECT rolname, rolinherit, rolcreatedb, rolcreaterole FROM pg_roles;`, + ); + + const rolesToReturn: Record = {}; + + const preparedRoles = prepareRoles(entities); + + if ( + preparedRoles.useRoles || !(preparedRoles.includeRoles.length === 0 && preparedRoles.excludeRoles.length === 0) + ) { + for (const dbRole of allRoles) { + if ( + preparedRoles.useRoles + ) { + rolesToReturn[dbRole.rolname] = { + createDb: dbRole.rolcreatedb, + createRole: dbRole.rolcreatedb, + inherit: dbRole.rolinherit, + name: dbRole.rolname, + }; + } else { + if (preparedRoles.includeRoles.length === 0 && preparedRoles.excludeRoles.length === 0) continue; + if ( + preparedRoles.includeRoles.includes(dbRole.rolname) && preparedRoles.excludeRoles.includes(dbRole.rolname) + ) continue; + if (preparedRoles.excludeRoles.includes(dbRole.rolname)) continue; + if (!preparedRoles.includeRoles.includes(dbRole.rolname)) continue; + + rolesToReturn[dbRole.rolname] = { + createDb: dbRole.rolcreatedb, + createRole: dbRole.rolcreaterole, + inherit: dbRole.rolinherit, + name: dbRole.rolname, + }; + } + } + } + + const wherePolicies = schemaFilters + .map((t) => `schemaname = '${t}'`) + .join(' or '); + + const policiesByTable: Record> = {}; + + const allPolicies = await db.query< + { + schemaname: string; + tablename: string; + name: string; + as: string; + to: string[]; + for: string; + using: string; + withCheck: string; + } + >(`SELECT schemaname, tablename, policyname as name, permissive as "as", roles as to, cmd as for, qual as using, with_check as "withCheck" FROM pg_policies${ + wherePolicies === '' ? '' : ` WHERE ${wherePolicies}` + };`); + + for (const dbPolicy of allPolicies) { + const { tablename, schemaname, to, withCheck, using, ...rest } = dbPolicy; + const tableForPolicy = policiesByTable[`${schemaname}.${tablename}`]; + + const parsedTo = to; + + const parsedWithCheck = withCheck === null ? undefined : withCheck; + const parsedUsing = using === null ? undefined : using; + + if (tableForPolicy) { + tableForPolicy[dbPolicy.name] = { ...rest, to: parsedTo } as Policy; + } else { + policiesByTable[`${schemaname}.${tablename}`] = { + [dbPolicy.name]: { ...rest, to: parsedTo, withCheck: parsedWithCheck, using: parsedUsing } as Policy, + }; + } + } + + if (progressCallback) { + progressCallback( + 'policies', + Object.values(policiesByTable).reduce((total, innerRecord) => { + return total + Object.keys(innerRecord).length; + }, 0), + 'done', + ); + } + const sequencesInColumns: string[] = []; const all = allTables @@ -1317,7 +1521,7 @@ WHERE }, ], isUnique: indexIsUnique, - // should not be a part of diff detecs + // should not be a part of diff detects concurrently: false, method: indexMethod, where: indexWhere === null ? undefined : indexWhere, @@ -1339,6 +1543,8 @@ WHERE compositePrimaryKeys: primaryKeys, uniqueConstraints: uniqueConstrains, checkConstraints: checkConstraints, + policies: policiesByTable[`${tableSchema}.${tableName}`] ?? {}, + isRLSEnabled: row.rls_enabled, }; } catch (e) { rej(e); @@ -1601,6 +1807,7 @@ WHERE enums: enumsToReturn, schemas: schemasObject, sequences: sequencesToReturn, + roles: rolesToReturn, views: views, _meta: { schemas: {}, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index bae4c100a..3818d6ac9 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -12,7 +12,7 @@ import { union, ZodTypeAny, } from 'zod'; -import { applyJsonDiff, diffColumns, diffSchemasOrTables } from './jsonDiffer'; +import { applyJsonDiff, diffColumns, diffPolicies, diffSchemasOrTables } from './jsonDiffer'; import { fromJson } from './sqlgenerator'; import { @@ -22,6 +22,7 @@ import { JsonAddColumnStatement, JsonAlterCompositePK, JsonAlterMySqlViewStatement, + JsonAlterPolicyStatement, JsonAlterTableSetSchema, JsonAlterUniqueConstraint, JsonAlterViewStatement, @@ -29,16 +30,22 @@ import { JsonCreateCompositePK, JsonCreateMySqlViewStatement, JsonCreatePgViewStatement, + JsonCreatePolicyStatement, JsonCreateReferenceStatement, JsonCreateSqliteViewStatement, JsonCreateUniqueConstraint, JsonDeleteCheckConstraint, JsonDeleteCompositePK, JsonDeleteUniqueConstraint, + JsonDisableRLSStatement, JsonDropColumnStatement, + JsonDropPolicyStatement, JsonDropViewStatement, + JsonEnableRLSStatement, JsonReferenceStatement, JsonRenameColumnStatement, + JsonRenamePolicyStatement, + JsonRenameRoleStatement, JsonRenameViewStatement, JsonSqliteAddColumnStatement, JsonStatement, @@ -52,11 +59,15 @@ import { prepareAlterCompositePrimaryKeyMySql, prepareAlterCompositePrimaryKeyPg, prepareAlterCompositePrimaryKeySqlite, + prepareAlterPolicyJson, prepareAlterReferencesJson, + prepareAlterRoleJson, prepareAlterSequenceJson, prepareCreateEnumJson, prepareCreateIndexesJson, + prepareCreatePolicyJsons, prepareCreateReferencesJson, + prepareCreateRoleJson, prepareCreateSchemasJson, prepareCreateSequenceJson, prepareDeleteCheckConstraint, @@ -68,7 +79,9 @@ import { prepareDropEnumJson, prepareDropEnumValues, prepareDropIndexesJson, + prepareDropPolicyJsons, prepareDropReferencesJson, + prepareDropRoleJson, prepareDropSequenceJson, prepareDropTableJson, prepareDropViewJson, @@ -90,6 +103,8 @@ import { preparePgCreateViewJson, prepareRenameColumns, prepareRenameEnumJson, + prepareRenamePolicyJsons, + prepareRenameRoleJson, prepareRenameSchemasJson, prepareRenameSequenceJson, prepareRenameTableJson, @@ -102,7 +117,17 @@ import { import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher, ViewSquashed } from './serializer/mysqlSchema'; -import { mergedViewWithOption, PgSchema, PgSchemaSquashed, sequenceSquashed, View } from './serializer/pgSchema'; +import { + mergedViewWithOption, + PgSchema, + PgSchemaSquashed, + PgSquasher, + Policy, + Role, + roleSchema, + sequenceSquashed, + View, +} from './serializer/pgSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher, View as SqliteView } from './serializer/sqliteSchema'; import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; import { copy, prepareMigrationMeta } from './utils'; @@ -229,7 +254,9 @@ const tableScheme = object({ foreignKeys: record(string(), string()), compositePrimaryKeys: record(string(), string()).default({}), uniqueConstraints: record(string(), string()).default({}), + policies: record(string(), string()).default({}), checkConstraints: record(string(), string()).default({}), + isRLSEnabled: boolean().default(false), }).strict(); export const alteredTableScheme = object({ @@ -272,6 +299,15 @@ export const alteredTableScheme = object({ __old: string(), }), ), + addedPolicies: record(string(), string()), + deletedPolicies: record(string(), string()), + alteredPolicies: record( + string(), + object({ + __new: string(), + __old: string(), + }), + ), addedCheckConstraints: record( string(), string(), @@ -337,6 +373,7 @@ export const diffResultScheme = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: changedEnumSchema.array(), alteredSequences: sequenceSquashed.array(), + alteredRoles: roleSchema.array(), alteredViews: alteredPgViewSchema.array(), }).strict(); @@ -387,6 +424,17 @@ export interface ColumnsResolverInput { deleted: T[]; } +export interface RolesResolverInput { + created: T[]; + deleted: T[]; +} + +export interface RolesResolverOutput { + created: T[]; + renamed: { from: T; to: T }[]; + deleted: T[]; +} + export interface ColumnsResolverOutput { tableName: string; schema: string; @@ -457,6 +505,12 @@ const columnChangeFor = ( return column; }; +// resolve roles same as enums +// create new json statements +// sql generators + +// tests everything! + export const applyPgSnapshotsDiff = async ( json1: PgSchemaSquashed, json2: PgSchemaSquashed, @@ -469,6 +523,12 @@ export const applyPgSnapshotsDiff = async ( sequencesResolver: ( input: ResolverInput, ) => Promise>, + policyResolver: ( + input: ColumnsResolverInput, + ) => Promise>, + roleResolver: ( + input: RolesResolverInput, + ) => Promise>, tablesResolver: ( input: ResolverInput
, ) => Promise>, @@ -696,6 +756,60 @@ export const applyPgSnapshotsDiff = async ( }, ); + const rolesDiff = diffSchemasOrTables( + schemasPatchedSnap1.roles, + json2.roles, + ); + + const { + created: createdRoles, + deleted: deletedRoles, + renamed: renamedRoles, + } = await roleResolver({ + created: rolesDiff.added, + deleted: rolesDiff.deleted, + }); + + schemasPatchedSnap1.roles = mapEntries( + schemasPatchedSnap1.roles, + (_, it) => { + const { name } = nameChangeFor(it, renamedRoles); + it.name = name; + return [name, it]; + }, + ); + + const rolesChangeMap = renamedRoles.reduce( + (acc, it) => { + acc[it.from.name] = { + nameFrom: it.from.name, + nameTo: it.to.name, + }; + return acc; + }, + {} as Record< + string, + { + nameFrom: string; + nameTo: string; + } + >, + ); + + schemasPatchedSnap1.roles = mapEntries( + schemasPatchedSnap1.roles, + (roleKey, roleValue) => { + const key = roleKey; + const change = rolesChangeMap[key]; + + if (change) { + roleValue.name = change.nameTo; + } + + return [roleKey, roleValue]; + }, + ); + const tablesDiff = diffSchemasOrTables( schemasPatchedSnap1.tables as Record, json2.tables, @@ -808,7 +922,101 @@ export const applyPgSnapshotsDiff = async ( }, ); - const viewsDiff = diffSchemasOrTables(json1.views, json2.views); + //// Policies + + const policyRes = diffPolicies(tablesPatchedSnap1.tables, json2.tables); + + const policyRenames = [] as { + table: string; + schema: string; + renames: { from: Policy; to: Policy }[]; + }[]; + + const policyCreates = [] as { + table: string; + schema: string; + columns: Policy[]; + }[]; + + const policyDeletes = [] as { + table: string; + schema: string; + columns: Policy[]; + }[]; + + for (let entry of Object.values(policyRes)) { + const { renamed, created, deleted } = await policyResolver({ + tableName: entry.name, + schema: entry.schema, + deleted: entry.policies.deleted.map(PgSquasher.unsquashPolicy), + created: entry.policies.added.map(PgSquasher.unsquashPolicy), + }); + + if (created.length > 0) { + policyCreates.push({ + table: entry.name, + schema: entry.schema, + columns: created, + }); + } + + if (deleted.length > 0) { + policyDeletes.push({ + table: entry.name, + schema: entry.schema, + columns: deleted, + }); + } + + if (renamed.length > 0) { + policyRenames.push({ + table: entry.name, + schema: entry.schema, + renames: renamed, + }); + } + } + + const policyRenamesDict = columnRenames.reduce( + (acc, it) => { + acc[`${it.schema || 'public'}.${it.table}`] = it.renames; + return acc; + }, + {} as Record< + string, + { + from: Named; + to: Named; + }[] + >, + ); + + const policyPatchedSnap1 = copy(tablesPatchedSnap1); + policyPatchedSnap1.tables = mapEntries( + policyPatchedSnap1.tables, + (tableKey, tableValue) => { + const patchedPolicies = mapKeys( + tableValue.policies, + (policyKey, policy) => { + const rens = policyRenamesDict[ + `${tableValue.schema || 'public'}.${tableValue.name}` + ] || []; + + const newName = columnChangeFor(policyKey, rens); + const unsquashedPolicy = PgSquasher.unsquashPolicy(policy); + unsquashedPolicy.name = newName; + policy = PgSquasher.squashPolicy(unsquashedPolicy); + return newName; + }, + ); + + tableValue.policies = patchedPolicies; + return [tableKey, tableValue]; + }, + ); + + //// + const viewsDiff = diffSchemasOrTables(policyPatchedSnap1.views, json2.views); const { created: createdViews, @@ -830,7 +1038,7 @@ export const applyPgSnapshotsDiff = async ( movedViewDic[`${it.schemaFrom}.${it.name}`] = { to: it.schemaTo, from: it.schemaFrom }; }); - const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + const viewsPatchedSnap1 = copy(policyPatchedSnap1); viewsPatchedSnap1.views = mapEntries( viewsPatchedSnap1.views, (viewKey, viewValue) => { @@ -908,13 +1116,15 @@ export const applyPgSnapshotsDiff = async ( const jsonSetTableSchemas: JsonAlterTableSetSchema[] = []; - for (let it of movedTables) { - jsonSetTableSchemas.push({ - type: 'alter_table_set_schema', - tableName: it.name, - schemaFrom: it.schemaFrom || 'public', - schemaTo: it.schemaTo || 'public', - }); + if (movedTables) { + for (let it of movedTables) { + jsonSetTableSchemas.push({ + type: 'alter_table_set_schema', + tableName: it.name, + schemaFrom: it.schemaFrom || 'public', + schemaTo: it.schemaTo || 'public', + }); + } } const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; @@ -1072,7 +1282,131 @@ export const applyPgSnapshotsDiff = async ( }) .flat(); + const jsonCreatePoliciesStatements: JsonCreatePolicyStatement[] = []; + const jsonDropPoliciesStatements: JsonDropPolicyStatement[] = []; + const jsonAlterPoliciesStatements: JsonAlterPolicyStatement[] = []; + const jsonRenamePoliciesStatements: JsonRenamePolicyStatement[] = []; + + const jsonEnableRLSStatements: JsonEnableRLSStatement[] = []; + const jsonDisableRLSStatements: JsonDisableRLSStatement[] = []; + + for (let it of policyRenames) { + jsonRenamePoliciesStatements.push( + ...prepareRenamePolicyJsons(it.table, it.schema, it.renames), + ); + } + + for (const it of policyCreates) { + jsonCreatePoliciesStatements.push( + ...prepareCreatePolicyJsons( + it.table, + it.schema, + it.columns, + ), + ); + } + + for (const it of policyDeletes) { + jsonDropPoliciesStatements.push( + ...prepareDropPolicyJsons( + it.table, + it.schema, + it.columns, + ), + ); + } + alteredTables.forEach((it) => { + // handle policies + Object.keys(it.alteredPolicies).forEach((policyName: string) => { + const newPolicy = PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__new); + const oldPolicy = PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__old); + + if (newPolicy.as !== oldPolicy.as) { + jsonDropPoliciesStatements.push( + ...prepareDropPolicyJsons( + it.name, + it.schema, + [oldPolicy], + ), + ); + + jsonCreatePoliciesStatements.push( + ...prepareCreatePolicyJsons( + it.name, + it.schema, + [newPolicy], + ), + ); + return; + } + + if (newPolicy.for !== oldPolicy.for) { + jsonDropPoliciesStatements.push( + ...prepareDropPolicyJsons( + it.name, + it.schema, + [oldPolicy], + ), + ); + + jsonCreatePoliciesStatements.push( + ...prepareCreatePolicyJsons( + it.name, + it.schema, + [newPolicy], + ), + ); + return; + } + + // alter + jsonAlterPoliciesStatements.push( + prepareAlterPolicyJson( + it.name, + it.schema, + it.alteredPolicies[policyName].__old, + it.alteredPolicies[policyName].__new, + ), + ); + }); + + // Handle enabling and disabling RLS + for (const table of Object.values(json2.tables)) { + const policiesInCurrentState = Object.keys(table.policies); + const tableInPreviousState = + columnsPatchedSnap1.tables[`${table.schema === '' ? 'public' : table.schema}.${table.name}`]; + const policiesInPreviousState = tableInPreviousState ? Object.keys(tableInPreviousState.policies) : []; + + if (policiesInPreviousState.length === 0 && policiesInCurrentState.length > 0 && !table.isRLSEnabled) { + jsonEnableRLSStatements.push({ type: 'enable_rls', tableName: table.name, schema: table.schema }); + } + + if (policiesInPreviousState.length > 0 && policiesInCurrentState.length === 0 && !table.isRLSEnabled) { + jsonDisableRLSStatements.push({ type: 'disable_rls', tableName: table.name, schema: table.schema }); + } + + // handle table.isRLSEnabled + if (table.isRLSEnabled !== tableInPreviousState.isRLSEnabled) { + if (table.isRLSEnabled) { + // was force enabled + jsonEnableRLSStatements.push({ type: 'enable_rls', tableName: table.name, schema: table.schema }); + } else if (!table.isRLSEnabled && policiesInCurrentState.length === 0) { + // was force disabled + jsonDisableRLSStatements.push({ type: 'disable_rls', tableName: table.name, schema: table.schema }); + } + } + } + + for (const table of Object.values(columnsPatchedSnap1.tables)) { + const tableInCurrentState = json2.tables[`${table.schema === '' ? 'public' : table.schema}.${table.name}`]; + + if (tableInCurrentState === undefined && !table.isRLSEnabled) { + jsonDisableRLSStatements.push({ type: 'disable_rls', tableName: table.name, schema: table.schema }); + } + } + + // handle indexes const droppedIndexes = Object.keys(it.alteredIndexes).reduce( (current, item: string) => { current[item] = it.alteredIndexes[item].__old; @@ -1207,6 +1541,26 @@ export const applyPgSnapshotsDiff = async ( //////////// + const createRoles = createdRoles.map((it) => { + return prepareCreateRoleJson(it); + }) ?? []; + + const dropRoles = deletedRoles.map((it) => { + return prepareDropRoleJson(it.name); + }); + + const renameRoles = renamedRoles.map((it) => { + return prepareRenameRoleJson(it.from.name, it.to.name); + }); + + const jsonAlterRoles = typedResult.alteredRoles + .map((it) => { + return prepareAlterRoleJson(it); + }) + .flat() ?? []; + + //////////// + const createSchemas = prepareCreateSchemasJson( createdSchemas.map((it) => it.name), ); @@ -1223,6 +1577,11 @@ export const applyPgSnapshotsDiff = async ( return preparePgCreateTableJson(it, curFull); }); + jsonCreatePoliciesStatements.push(...([] as JsonCreatePolicyStatement[]).concat( + ...(createdTables.map((it) => + prepareCreatePolicyJsons(it.name, it.schema, Object.values(it.policies).map(PgSquasher.unsquashPolicy)) + )), + )); const createViews: JsonCreatePgViewStatement[] = []; const dropViews: JsonDropViewStatement[] = []; const renameViews: JsonRenameViewStatement[] = []; @@ -1385,8 +1744,15 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...renameSequences); jsonStatements.push(...jsonAlterSequences); + jsonStatements.push(...renameRoles); + jsonStatements.push(...dropRoles); + jsonStatements.push(...createRoles); + jsonStatements.push(...jsonAlterRoles); + jsonStatements.push(...createTables); + jsonStatements.push(...jsonEnableRLSStatements); + jsonStatements.push(...jsonDisableRLSStatements); jsonStatements.push(...dropViews); jsonStatements.push(...renameViews); jsonStatements.push(...alterViews); @@ -1425,6 +1791,10 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...jsonAlteredUniqueConstraints); jsonStatements.push(...jsonAlterEnumsWithDroppedValues); + jsonStatements.push(...jsonRenamePoliciesStatements); + jsonStatements.push(...jsonDropPoliciesStatements); + jsonStatements.push(...jsonCreatePoliciesStatements); + jsonStatements.push(...jsonAlterPoliciesStatements); jsonStatements.push(...createViews); jsonStatements.push(...dropEnums); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 586175e28..4b75f4286 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -21,7 +21,9 @@ import { JsonAlterColumnTypeStatement, JsonAlterCompositePK, JsonAlterMySqlViewStatement, + JsonAlterPolicyStatement, JsonAlterReferenceStatement, + JsonAlterRoleStatement, JsonAlterSequenceStatement, JsonAlterTableRemoveFromSchema, JsonAlterTableSetNewSchema, @@ -37,7 +39,9 @@ import { JsonCreateIndexStatement, JsonCreateMySqlViewStatement, JsonCreatePgViewStatement, + JsonCreatePolicyStatement, JsonCreateReferenceStatement, + JsonCreateRoleStatement, JsonCreateSchema, JsonCreateSequenceStatement, JsonCreateSqliteViewStatement, @@ -47,19 +51,25 @@ import { JsonDeleteCompositePK, JsonDeleteReferenceStatement, JsonDeleteUniqueConstraint, + JsonDisableRLSStatement, JsonDropColumnStatement, JsonDropEnumStatement, JsonDropIndexStatement, + JsonDropPolicyStatement, + JsonDropRoleStatement, JsonDropSequenceStatement, JsonDropTableStatement, JsonDropValueFromEnumStatement, JsonDropViewStatement, + JsonEnableRLSStatement, JsonMoveEnumStatement, JsonMoveSequenceStatement, JsonPgCreateIndexStatement, JsonRecreateTableStatement, JsonRenameColumnStatement, JsonRenameEnumStatement, + JsonRenamePolicyStatement, + JsonRenameRoleStatement, JsonRenameSchema, JsonRenameSequenceStatement, JsonRenameTableStatement, @@ -155,13 +165,165 @@ abstract class Convertor { ): string | string[]; } +class PgCreateRoleConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_role' && dialect === 'postgresql'; + } + override convert(statement: JsonCreateRoleStatement): string | string[] { + return `CREATE ROLE "${statement.name}"${ + statement.values.createDb || statement.values.createRole || !statement.values.inherit + ? ` WITH${statement.values.createDb ? ' CREATEDB' : ''}${statement.values.createRole ? ' CREATEROLE' : ''}${ + statement.values.inherit ? '' : ' NOINHERIT' + }` + : '' + };`; + } +} + +class PgDropRoleConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_role' && dialect === 'postgresql'; + } + override convert(statement: JsonDropRoleStatement): string | string[] { + return `DROP ROLE "${statement.name}";`; + } +} + +class PgRenameRoleConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'rename_role' && dialect === 'postgresql'; + } + override convert(statement: JsonRenameRoleStatement): string | string[] { + return `ALTER ROLE "${statement.nameFrom}" RENAME TO "${statement.nameTo}";`; + } +} + +class PgAlterRoleConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_role' && dialect === 'postgresql'; + } + override convert(statement: JsonAlterRoleStatement): string | string[] { + return `ALTER ROLE "${statement.name}"${` WITH${statement.values.createDb ? ' CREATEDB' : ' NOCREATEDB'}${ + statement.values.createRole ? ' CREATEROLE' : ' NOCREATEROLE' + }${statement.values.inherit ? ' INHERIT' : ' NOINHERIT'}`};`; + } +} + +///// + +class PgCreatePolicyConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_policy' && dialect === 'postgresql'; + } + override convert(statement: JsonCreatePolicyStatement): string | string[] { + const policy = statement.data; + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + const usingPart = policy.using ? ` USING (${policy.using})` : ''; + + const withCheckPart = policy.withCheck ? ` WITH CHECK (${policy.withCheck})` : ''; + + const policyToPart = policy.to?.map((v) => + ['current_user', 'current_role', 'session_user', 'public'].includes(v) ? v : `"${v}"` + ).join(', '); + + return `CREATE POLICY "${policy.name}" ON ${tableNameWithSchema} AS ${policy.as?.toUpperCase()} FOR ${policy.for?.toUpperCase()} TO ${policyToPart}${usingPart}${withCheckPart};`; + } +} + +class PgDropPolicyConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_policy' && dialect === 'postgresql'; + } + override convert(statement: JsonDropPolicyStatement): string | string[] { + const policy = statement.data; + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `DROP POLICY "${policy.name}" ON ${tableNameWithSchema} CASCADE;`; + } +} + +class PgRenamePolicyConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'rename_policy' && dialect === 'postgresql'; + } + override convert(statement: JsonRenamePolicyStatement): string | string[] { + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER POLICY "${statement.oldName}" ON ${tableNameWithSchema} RENAME TO "${statement.newName}";`; + } +} + +class PgAlterPolicyConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_policy' && dialect === 'postgresql'; + } + override convert(statement: JsonAlterPolicyStatement): string | string[] { + const newPolicy = PgSquasher.unsquashPolicy(statement.newData); + const oldPolicy = PgSquasher.unsquashPolicy(statement.oldData); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + const usingPart = newPolicy.using + ? ` USING (${newPolicy.using})` + : oldPolicy.using + ? ` USING (${oldPolicy.using})` + : ''; + + const withCheckPart = newPolicy.withCheck + ? ` WITH CHECK (${newPolicy.withCheck})` + : oldPolicy.withCheck + ? ` WITH CHECK (${oldPolicy.withCheck})` + : ''; + + return `ALTER POLICY "${oldPolicy.name}" ON ${tableNameWithSchema} TO ${newPolicy.to}${usingPart}${withCheckPart};`; + } +} + +class PgEnableRlsConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'enable_rls' && dialect === 'postgresql'; + } + override convert(statement: JsonEnableRLSStatement): string { + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} ENABLE ROW LEVEL SECURITY;`; + } +} + +class PgDisableRlsConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'disable_rls' && dialect === 'postgresql'; + } + override convert(statement: JsonDisableRLSStatement): string { + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} DISABLE ROW LEVEL SECURITY;`; + } +} + class PgCreateTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_table' && dialect === 'postgresql'; } convert(st: JsonCreateTableStatement) { - const { tableName, schema, columns, compositePKs, uniqueConstraints, checkConstraints } = st; + const { tableName, schema, columns, compositePKs, uniqueConstraints, checkConstraints, policies, isRLSEnabled } = + st; let statement = ''; const name = schema ? `"${schema}"."${tableName}"` : `"${tableName}"`; @@ -258,7 +420,13 @@ class PgCreateTableConvertor extends Convertor { statement += `\n);`; statement += `\n`; - return statement; + const enableRls = new PgEnableRlsConvertor().convert({ + type: 'enable_rls', + tableName, + schema, + }); + + return [statement, ...(policies && policies.length > 0 || isRLSEnabled ? [enableRls] : [])]; } } @@ -1170,13 +1338,26 @@ class PgDropTableConvertor extends Convertor { } convert(statement: JsonDropTableStatement) { - const { tableName, schema } = statement; + const { tableName, schema, policies } = statement; const tableNameWithSchema = schema ? `"${schema}"."${tableName}"` : `"${tableName}"`; - return `DROP TABLE ${tableNameWithSchema};`; + const dropPolicyConvertor = new PgDropPolicyConvertor(); + const droppedPolicies = policies?.map((p) => { + return dropPolicyConvertor.convert({ + type: 'drop_policy', + tableName, + data: PgSquasher.unsquashPolicy(p), + schema, + }) as string; + }) ?? []; + + return [ + ...droppedPolicies, + `DROP TABLE ${tableNameWithSchema} CASCADE;`, + ]; } } @@ -3017,6 +3198,18 @@ convertors.push(new PgAlterTableAlterColumnDropNotNullConvertor()); convertors.push(new PgAlterTableAlterColumnSetDefaultConvertor()); convertors.push(new PgAlterTableAlterColumnDropDefaultConvertor()); +convertors.push(new PgAlterPolicyConvertor()); +convertors.push(new PgCreatePolicyConvertor()); +convertors.push(new PgDropPolicyConvertor()); +convertors.push(new PgRenamePolicyConvertor()); +convertors.push(new PgEnableRlsConvertor()); +convertors.push(new PgDisableRlsConvertor()); + +convertors.push(new PgDropRoleConvertor()); +convertors.push(new PgAlterRoleConvertor()); +convertors.push(new PgCreateRoleConvertor()); +convertors.push(new PgRenameRoleConvertor()); + /// generated convertors.push(new PgAlterTableAlterColumnSetExpressionConvertor()); convertors.push(new PgAlterTableAlterColumnDropGeneratedConvertor()); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index bd8b15ab9..6762ef27a 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -19,6 +19,8 @@ import { numeric, pgEnum, pgMaterializedView, + pgPolicy, + pgRole, pgSchema, pgTable, pgView, @@ -627,3 +629,239 @@ test('introspect materialized view #2', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('basic policy', async () => { + const client = new PGlite(); + + const schema = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test'), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'basic-policy', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('basic policy with "as"', async () => { + const client = new PGlite(); + + const schema = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'basic-policy-as', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test.todo('basic policy with CURRENT_USER role', async () => { + const client = new PGlite(); + + const schema = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { to: 'current_user' }), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'basic-policy', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('basic policy with all fields except "using" and "with"', async () => { + const client = new PGlite(); + + const schema = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive', for: 'all', to: ['postgres'] }), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'basic-policy-all-fields', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('basic policy with "using" and "with"', async () => { + const client = new PGlite(); + + const schema = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { using: sql`true`, withCheck: sql`true` }), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'basic-policy-using-withcheck', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('multiple policies', async () => { + const client = new PGlite(); + + const schema = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { using: sql`true`, withCheck: sql`true` }), + rlsPolicy: pgPolicy('newRls'), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'multiple-policies', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('multiple policies with roles', async () => { + const client = new PGlite(); + + client.query(`CREATE ROLE manager;`); + + const schema = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { using: sql`true`, withCheck: sql`true` }), + rlsPolicy: pgPolicy('newRls', { to: ['postgres', 'manager'] }), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'multiple-policies-with-roles', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('basic roles', async () => { + const client = new PGlite(); + + const schema = { + usersRole: pgRole('user'), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'basic-roles', + ['public'], + { roles: { include: ['user'] } }, + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('role with properties', async () => { + const client = new PGlite(); + + const schema = { + usersRole: pgRole('user', { inherit: false, createDb: true, createRole: true }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'roles-with-properties', + ['public'], + { roles: { include: ['user'] } }, + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('role with a few properties', async () => { + const client = new PGlite(); + + const schema = { + usersRole: pgRole('user', { inherit: false, createRole: true }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'roles-with-few-properties', + ['public'], + { roles: { include: ['user'] } }, + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('multiple policies with roles from schema', async () => { + const client = new PGlite(); + + const usersRole = pgRole('user_role', { inherit: false, createRole: true }); + + const schema = { + usersRole, + + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { using: sql`true`, withCheck: sql`true` }), + rlsPolicy: pgPolicy('newRls', { to: ['postgres', usersRole] }), + })), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'multiple-policies-with-roles-from-schema', + ['public'], + { roles: { include: ['user_role'] } }, + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/mysql.test.ts b/drizzle-kit/tests/mysql.test.ts index 29f2e869a..183464ec0 100644 --- a/drizzle-kit/tests/mysql.test.ts +++ b/drizzle-kit/tests/mysql.test.ts @@ -201,6 +201,7 @@ test('add table #6', async () => { }); expect(statements[1]).toStrictEqual({ type: 'drop_table', + policies: [], tableName: 'users1', schema: undefined, }); @@ -294,6 +295,7 @@ test('change table schema #1', async () => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ type: 'drop_table', + policies: [], tableName: 'users', schema: undefined, }); diff --git a/drizzle-kit/tests/pg-checks.test.ts b/drizzle-kit/tests/pg-checks.test.ts index 1f5e5e1c5..50a01a6c1 100644 --- a/drizzle-kit/tests/pg-checks.test.ts +++ b/drizzle-kit/tests/pg-checks.test.ts @@ -39,6 +39,8 @@ test('create table with check', async (t) => { checkConstraints: ['some_check_name;"users"."age" > 21'], compositePkName: '', uniqueConstraints: [], + isRLSEnabled: false, + policies: [], } as JsonCreateTableStatement); expect(sqlStatements.length).toBe(1); diff --git a/drizzle-kit/tests/pg-identity.test.ts b/drizzle-kit/tests/pg-identity.test.ts index 7e0854b67..9f6ce8ba7 100644 --- a/drizzle-kit/tests/pg-identity.test.ts +++ b/drizzle-kit/tests/pg-identity.test.ts @@ -45,6 +45,8 @@ test('create table: identity always/by default - no params', async () => { compositePKs: [], compositePkName: '', schema: '', + policies: [], + isRLSEnabled: false, tableName: 'users', type: 'create_table', uniqueConstraints: [], @@ -83,7 +85,9 @@ test('create table: identity always/by default - few params', async () => { ], compositePKs: [], compositePkName: '', + policies: [], schema: '', + isRLSEnabled: false, tableName: 'users', type: 'create_table', uniqueConstraints: [], @@ -126,6 +130,8 @@ test('create table: identity always/by default - all params', async () => { ], compositePKs: [], compositePkName: '', + policies: [], + isRLSEnabled: false, schema: '', tableName: 'users', type: 'create_table', diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index 0648459b4..1f2885f92 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -34,8 +34,10 @@ test('add table #1', async () => { schema: '', columns: [], compositePKs: [], + policies: [], uniqueConstraints: [], checkConstraints: [], + isRLSEnabled: false, compositePkName: '', }); }); @@ -63,6 +65,8 @@ test('add table #2', async () => { }, ], compositePKs: [], + isRLSEnabled: false, + policies: [], uniqueConstraints: [], checkConstraints: [], compositePkName: '', @@ -103,7 +107,9 @@ test('add table #3', async () => { }, ], compositePKs: ['id;users_pk'], + policies: [], uniqueConstraints: [], + isRLSEnabled: false, checkConstraints: [], compositePkName: 'users_pk', }); @@ -124,16 +130,20 @@ test('add table #4', async () => { schema: '', columns: [], compositePKs: [], + policies: [], uniqueConstraints: [], checkConstraints: [], + isRLSEnabled: false, compositePkName: '', }); expect(statements[1]).toStrictEqual({ type: 'create_table', tableName: 'posts', + policies: [], schema: '', columns: [], compositePKs: [], + isRLSEnabled: false, uniqueConstraints: [], checkConstraints: [], compositePkName: '', @@ -160,9 +170,11 @@ test('add table #5', async () => { schema: 'folder', columns: [], compositePKs: [], + policies: [], uniqueConstraints: [], compositePkName: '', checkConstraints: [], + isRLSEnabled: false, }); }); @@ -185,11 +197,14 @@ test('add table #6', async () => { columns: [], compositePKs: [], uniqueConstraints: [], + policies: [], compositePkName: '', checkConstraints: [], + isRLSEnabled: false, }); expect(statements[1]).toStrictEqual({ type: 'drop_table', + policies: [], tableName: 'users1', schema: '', }); @@ -216,8 +231,10 @@ test('add table #7', async () => { schema: '', columns: [], compositePKs: [], + policies: [], uniqueConstraints: [], compositePkName: '', + isRLSEnabled: false, checkConstraints: [], }); expect(statements[1]).toStrictEqual({ @@ -273,7 +290,9 @@ test('multiproject schema add table #1', async () => { }, ], compositePKs: [], + policies: [], compositePkName: '', + isRLSEnabled: false, uniqueConstraints: [], checkConstraints: [], }); @@ -296,6 +315,7 @@ test('multiproject schema drop table #1', async () => { schema: '', tableName: 'prefix_users', type: 'drop_table', + policies: [], }); }); @@ -365,8 +385,10 @@ test('add schema + table #1', async () => { type: 'create_table', tableName: 'users', schema: 'folder', + policies: [], columns: [], compositePKs: [], + isRLSEnabled: false, uniqueConstraints: [], compositePkName: '', checkConstraints: [], @@ -623,6 +645,7 @@ test('drop table + rename schema #1', async () => { type: 'drop_table', tableName: 'users', schema: 'folder2', + policies: [], }); }); diff --git a/drizzle-kit/tests/pg-views.test.ts b/drizzle-kit/tests/pg-views.test.ts index 2874caf5b..002004c47 100644 --- a/drizzle-kit/tests/pg-views.test.ts +++ b/drizzle-kit/tests/pg-views.test.ts @@ -27,8 +27,10 @@ test('create table and view #1', async () => { }], compositePKs: [], uniqueConstraints: [], + isRLSEnabled: false, compositePkName: '', checkConstraints: [], + policies: [], }); expect(statements[1]).toStrictEqual({ type: 'create_view', @@ -73,7 +75,9 @@ test('create table and view #2', async () => { }], compositePKs: [], uniqueConstraints: [], + isRLSEnabled: false, compositePkName: '', + policies: [], checkConstraints: [], }); expect(statements[1]).toStrictEqual({ @@ -130,6 +134,8 @@ test('create table and view #3', async () => { uniqueConstraints: [], compositePkName: '', checkConstraints: [], + isRLSEnabled: false, + policies: [], }); expect(statements[1]).toStrictEqual({ type: 'create_view', @@ -215,6 +221,8 @@ test('create table and view #4', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + isRLSEnabled: false, + policies: [], checkConstraints: [], }); expect(statements[2]).toStrictEqual({ @@ -302,6 +310,8 @@ test('create table and view #6', async () => { type: 'create_table', uniqueConstraints: [], checkConstraints: [], + isRLSEnabled: false, + policies: [], }); expect(statements[1]).toStrictEqual({ definition: 'SELECT * FROM "users"', @@ -370,6 +380,8 @@ test('create table and materialized view #1', async () => { }], compositePKs: [], uniqueConstraints: [], + isRLSEnabled: false, + policies: [], compositePkName: '', checkConstraints: [], }); @@ -417,6 +429,8 @@ test('create table and materialized view #2', async () => { compositePKs: [], uniqueConstraints: [], compositePkName: '', + isRLSEnabled: false, + policies: [], checkConstraints: [], }); expect(statements[1]).toStrictEqual({ @@ -482,7 +496,9 @@ test('create table and materialized view #3', async () => { }], compositePKs: [], uniqueConstraints: [], + isRLSEnabled: false, compositePkName: '', + policies: [], checkConstraints: [], }); expect(statements[1]).toStrictEqual({ @@ -582,6 +598,8 @@ test('create table and materialized view #5', async () => { tableName: 'users', type: 'create_table', uniqueConstraints: [], + isRLSEnabled: false, + policies: [], checkConstraints: [], }); expect(statements[1]).toEqual({ diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 1877f34e1..460809d9e 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -655,6 +655,7 @@ test('drop table with data', async (t) => { expect(statements!.length).toBe(1); expect(statements![0]).toStrictEqual({ + policies: [], schema: undefined, tableName: 'users', type: 'drop_table', diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index fb2ffdc8d..bd4b2840d 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -16,6 +16,8 @@ import { numeric, pgEnum, pgMaterializedView, + pgPolicy, + pgRole, pgSchema, pgSequence, pgTable, @@ -534,8 +536,10 @@ const pgSuite: DialectSuite = { ], compositePKs: [], compositePkName: '', + isRLSEnabled: false, schema: '', tableName: 'users', + policies: [], type: 'create_table', uniqueConstraints: [], checkConstraints: [], @@ -1208,8 +1212,10 @@ test('create table: identity always/by default - no params', async () => { compositePkName: '', schema: '', tableName: 'users', + policies: [], type: 'create_table', uniqueConstraints: [], + isRLSEnabled: false, checkConstraints: [], }, ]); @@ -1267,9 +1273,11 @@ test('create table: identity always/by default - few params', async () => { ], compositePKs: [], compositePkName: '', + policies: [], schema: '', tableName: 'users', type: 'create_table', + isRLSEnabled: false, uniqueConstraints: [], checkConstraints: [], }, @@ -1337,6 +1345,8 @@ test('create table: identity always/by default - all params', async () => { schema: '', tableName: 'users', type: 'create_table', + policies: [], + isRLSEnabled: false, uniqueConstraints: [], checkConstraints: [], }, @@ -2357,6 +2367,7 @@ test('drop mat view with data', async () => { false, ['public'], undefined, + undefined, { after: seedStatements }, ); @@ -2464,6 +2475,7 @@ test('drop view with data', async () => { false, ['public'], undefined, + undefined, { after: seedStatements }, ); @@ -2545,6 +2557,7 @@ test('enums ordering', async () => { false, ['public'], undefined, + undefined, { before: [...createEnum, ...addedValueSql], runApply: false }, ); @@ -2668,3 +2681,1299 @@ test('drop enum values', async () => { `ALTER TABLE "mySchema"."enum_table" ALTER COLUMN "id" SET DATA TYPE "public"."enum_users_customer_and_ship_to_settings_roles" USING "id"::"public"."enum_users_customer_and_ship_to_settings_roles";`, ); }); + +// Policies and Roles push test +test('full policy: no changes', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('add policy', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { type: 'enable_rls', tableName: 'users', schema: '' }, + { + type: 'create_policy', + tableName: 'users', + data: { + name: 'test', + as: 'PERMISSIVE', + for: 'ALL', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR ALL TO public;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('drop policy', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { type: 'disable_rls', tableName: 'users', schema: '' }, + { + schema: '', + tableName: 'users', + type: 'disable_rls', + }, + { + type: 'drop_policy', + tableName: 'users', + data: { + name: 'test', + as: 'PERMISSIVE', + for: 'ALL', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" DISABLE ROW LEVEL SECURITY;', + 'DROP POLICY "test" ON "users" CASCADE;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('add policy without enable rls', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + newrls: pgPolicy('newRls'), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'create_policy', + tableName: 'users', + data: { + name: 'newRls', + as: 'PERMISSIVE', + for: 'ALL', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE POLICY "newRls" ON "users" AS PERMISSIVE FOR ALL TO public;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('drop policy without disable rls', async () => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + oldRls: pgPolicy('oldRls'), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'drop_policy', + tableName: 'users', + data: { + name: 'oldRls', + as: 'PERMISSIVE', + for: 'ALL', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "oldRls" ON "users" CASCADE;', + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +//// + +test('alter policy without recreation: changing roles', async (t) => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive', to: 'current_role' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" TO current_role;', + ]); + expect(statements).toStrictEqual([ + { + newData: 'test--PERMISSIVE--ALL--current_role', + oldData: 'test--PERMISSIVE--ALL--public', + schema: '', + tableName: 'users', + type: 'alter_policy', + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter policy without recreation: changing using', async (t) => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive', using: sql`true` }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([]); + expect(statements).toStrictEqual([]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter policy without recreation: changing with check', async (t) => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive', withCheck: sql`true` }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([]); + expect(statements).toStrictEqual([]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter policy with recreation: changing as', async (t) => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'restrictive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + 'CREATE POLICY "test" ON "users" AS RESTRICTIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + { + data: { + as: 'RESTRICTIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter policy with recreation: changing for', async (t) => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive', for: 'delete' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR DELETE TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + { + data: { + as: 'PERMISSIVE', + for: 'DELETE', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter policy with recreation: changing both "as" and "for"', async (t) => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'restrictive', for: 'insert' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + 'CREATE POLICY "test" ON "users" AS RESTRICTIVE FOR INSERT TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + { + data: { + as: 'RESTRICTIVE', + for: 'INSERT', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter policy with recreation: changing all fields', async (t) => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive', for: 'select', using: sql`true` }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'restrictive', to: 'current_role', withCheck: sql`true` }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + 'CREATE POLICY "test" ON "users" AS RESTRICTIVE FOR ALL TO current_role;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'SELECT', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + { + data: { + as: 'RESTRICTIVE', + for: 'ALL', + name: 'test', + to: ['current_role'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('rename policy', async (t) => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('newName', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + ['public.users.test->public.users.newName'], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" RENAME TO "newName";', + ]); + expect(statements).toStrictEqual([ + { + newName: 'newName', + oldName: 'test', + schema: '', + tableName: 'users', + type: 'rename_policy', + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('rename policy in renamed table', async (t) => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users2', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('newName', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [ + 'public.users->public.users2', + 'public.users2.test->public.users2.newName', + ], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" RENAME TO "users2";', + 'ALTER POLICY "test" ON "users2" RENAME TO "newName";', + ]); + expect(statements).toStrictEqual([ + { + fromSchema: '', + tableNameFrom: 'users', + tableNameTo: 'users2', + toSchema: '', + type: 'rename_table', + }, + { + newName: 'newName', + oldName: 'test', + schema: '', + tableName: 'users2', + type: 'rename_policy', + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('create table with a policy', async (t) => { + const client = new PGlite(); + + const schema1 = {}; + + const schema2 = { + users: pgTable('users2', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "users2" (\n\t"id" integer PRIMARY KEY NOT NULL\n);\n', + 'ALTER TABLE "users2" ENABLE ROW LEVEL SECURITY;', + 'CREATE POLICY "test" ON "users2" AS PERMISSIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + columns: [ + { + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + ], + checkConstraints: [], + compositePKs: [], + isRLSEnabled: false, + compositePkName: '', + policies: [ + 'test--PERMISSIVE--ALL--public', + ], + schema: '', + tableName: 'users2', + type: 'create_table', + uniqueConstraints: [], + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users2', + type: 'create_policy', + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('drop table with a policy', async (t) => { + const client = new PGlite(); + + const schema1 = { + users: pgTable('users2', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = {}; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users2" CASCADE;', + 'DROP TABLE "users2" CASCADE;', + ]); + expect(statements).toStrictEqual([ + { + policies: [ + 'test--PERMISSIVE--ALL--public', + ], + schema: '', + tableName: 'users2', + type: 'drop_table', + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('add policy with multiple "to" roles', async (t) => { + const client = new PGlite(); + + client.query(`CREATE ROLE manager;`); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + + const role = pgRole('manager').existing(); + + const schema2 = { + role, + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { to: ['current_role', role] }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR ALL TO current_role, "manager";', + ]); + expect(statements).toStrictEqual([ + { + schema: '', + tableName: 'users', + type: 'enable_rls', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['current_role', 'manager'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +//// + +test('create role', async (t) => { + const client = new PGlite(); + + const schema1 = {}; + + const schema2 = { + manager: pgRole('manager'), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + { roles: { include: ['manager'] } }, + ); + + expect(sqlStatements).toStrictEqual(['CREATE ROLE "manager";']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'create_role', + values: { + createDb: false, + createRole: false, + inherit: true, + }, + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('create role with properties', async (t) => { + const client = new PGlite(); + + const schema1 = {}; + + const schema2 = { + manager: pgRole('manager', { createDb: true, inherit: false, createRole: true }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + { roles: { include: ['manager'] } }, + ); + + expect(sqlStatements).toStrictEqual(['CREATE ROLE "manager" WITH CREATEDB CREATEROLE NOINHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'create_role', + values: { + createDb: true, + createRole: true, + inherit: false, + }, + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('create role with some properties', async (t) => { + const client = new PGlite(); + + const schema1 = {}; + + const schema2 = { + manager: pgRole('manager', { createDb: true, inherit: false }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + { roles: { include: ['manager'] } }, + ); + + expect(sqlStatements).toStrictEqual(['CREATE ROLE "manager" WITH CREATEDB NOINHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'create_role', + values: { + createDb: true, + createRole: false, + inherit: false, + }, + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('drop role', async (t) => { + const client = new PGlite(); + + const schema1 = { manager: pgRole('manager') }; + + const schema2 = {}; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + { roles: { include: ['manager'] } }, + ); + + expect(sqlStatements).toStrictEqual(['DROP ROLE "manager";']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'drop_role', + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('create and drop role', async (t) => { + const client = new PGlite(); + + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + admin: pgRole('admin'), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + { roles: { include: ['manager', 'admin'] } }, + ); + + expect(sqlStatements).toStrictEqual(['DROP ROLE "manager";', 'CREATE ROLE "admin";']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'drop_role', + }, + { + name: 'admin', + type: 'create_role', + values: { + createDb: false, + createRole: false, + inherit: true, + }, + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('rename role', async (t) => { + const client = new PGlite(); + + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + admin: pgRole('admin'), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + ['manager->admin'], + false, + ['public'], + undefined, + { roles: { include: ['manager', 'admin'] } }, + ); + + expect(sqlStatements).toStrictEqual(['ALTER ROLE "manager" RENAME TO "admin";']); + expect(statements).toStrictEqual([ + { nameFrom: 'manager', nameTo: 'admin', type: 'rename_role' }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter all role field', async (t) => { + const client = new PGlite(); + + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + manager: pgRole('manager', { createDb: true, createRole: true, inherit: false }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + { roles: { include: ['manager'] } }, + ); + + expect(sqlStatements).toStrictEqual(['ALTER ROLE "manager" WITH CREATEDB CREATEROLE NOINHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'alter_role', + values: { + createDb: true, + createRole: true, + inherit: false, + }, + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter createdb in role', async (t) => { + const client = new PGlite(); + + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + manager: pgRole('manager', { createDb: true }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + { roles: { include: ['manager'] } }, + ); + + expect(sqlStatements).toStrictEqual(['ALTER ROLE "manager" WITH CREATEDB NOCREATEROLE INHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'alter_role', + values: { + createDb: true, + createRole: false, + inherit: true, + }, + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter createrole in role', async (t) => { + const client = new PGlite(); + + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + manager: pgRole('manager', { createRole: true }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + { roles: { include: ['manager'] } }, + ); + + expect(sqlStatements).toStrictEqual(['ALTER ROLE "manager" WITH NOCREATEDB CREATEROLE INHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'alter_role', + values: { + createDb: false, + createRole: true, + inherit: true, + }, + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); + +test('alter inherit in role', async (t) => { + const client = new PGlite(); + + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + manager: pgRole('manager', { inherit: false }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + { roles: { include: ['manager'] } }, + ); + + expect(sqlStatements).toStrictEqual(['ALTER ROLE "manager" WITH NOCREATEDB NOCREATEROLE NOINHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'alter_role', + values: { + createDb: false, + createRole: false, + inherit: false, + }, + }, + ]); + + for (const st of sqlStatements) { + await client.query(st); + } +}); diff --git a/drizzle-kit/tests/rls/pg-policy.test.ts b/drizzle-kit/tests/rls/pg-policy.test.ts new file mode 100644 index 000000000..5ca667faa --- /dev/null +++ b/drizzle-kit/tests/rls/pg-policy.test.ts @@ -0,0 +1,801 @@ +import { sql } from 'drizzle-orm'; +import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core'; +import { diffTestSchemas } from 'tests/schemaDiffer'; +import { expect, test } from 'vitest'; + +test('add policy + enable rls', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + schema: '', + tableName: 'users', + type: 'enable_rls', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); + +test('drop policy + disable rls', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" DISABLE ROW LEVEL SECURITY;', + 'DROP POLICY "test" ON "users" CASCADE;', + ]); + expect(statements).toStrictEqual([ + { + schema: '', + tableName: 'users', + type: 'disable_rls', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + ]); +}); + +test('add policy without enable rls', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + newrls: pgPolicy('newRls'), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE POLICY "newRls" ON "users" AS PERMISSIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'newRls', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); + +test('drop policy without disable rls', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + oldRls: pgPolicy('oldRls'), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "oldRls" ON "users" CASCADE;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'oldRls', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + ]); +}); + +test('alter policy without recreation: changing roles', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive', to: 'current_role' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" TO current_role;', + ]); + expect(statements).toStrictEqual([ + { + newData: 'test--PERMISSIVE--ALL--current_role--undefined--undefined', + oldData: 'test--PERMISSIVE--ALL--public--undefined--undefined', + schema: '', + tableName: 'users', + type: 'alter_policy', + }, + ]); +}); + +test('alter policy without recreation: changing using', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive', using: sql`true` }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" TO public USING (true);', + ]); + expect(statements).toStrictEqual([ + { + newData: 'test--PERMISSIVE--ALL--public--true--undefined', + oldData: 'test--PERMISSIVE--ALL--public--undefined--undefined', + schema: '', + tableName: 'users', + type: 'alter_policy', + }, + ]); +}); + +test('alter policy without recreation: changing with check', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive', withCheck: sql`true` }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" TO public WITH CHECK (true);', + ]); + expect(statements).toStrictEqual([ + { + newData: 'test--PERMISSIVE--ALL--public--undefined--true', + oldData: 'test--PERMISSIVE--ALL--public--undefined--undefined', + schema: '', + tableName: 'users', + type: 'alter_policy', + }, + ]); +}); + +/// + +test('alter policy with recreation: changing as', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'restrictive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + 'CREATE POLICY "test" ON "users" AS RESTRICTIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + { + data: { + as: 'RESTRICTIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); + +test('alter policy with recreation: changing for', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive', for: 'delete' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR DELETE TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + { + data: { + as: 'PERMISSIVE', + for: 'DELETE', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); + +test('alter policy with recreation: changing both "as" and "for"', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'restrictive', for: 'insert' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + 'CREATE POLICY "test" ON "users" AS RESTRICTIVE FOR INSERT TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + { + data: { + as: 'RESTRICTIVE', + for: 'INSERT', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); + +test('alter policy with recreation: changing all fields', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive', for: 'select', using: sql`true` }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'restrictive', to: 'current_role', withCheck: sql`true` }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + 'CREATE POLICY "test" ON "users" AS RESTRICTIVE FOR ALL TO current_role WITH CHECK (true);', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'SELECT', + name: 'test', + to: ['public'], + using: 'true', + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + { + data: { + as: 'RESTRICTIVE', + for: 'ALL', + name: 'test', + to: ['current_role'], + using: undefined, + withCheck: 'true', + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); + +test('rename policy', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('newName', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, [ + 'public.users.test->public.users.newName', + ]); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" RENAME TO "newName";', + ]); + expect(statements).toStrictEqual([ + { + newName: 'newName', + oldName: 'test', + schema: '', + tableName: 'users', + type: 'rename_policy', + }, + ]); +}); + +test('rename policy in renamed table', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = { + users: pgTable('users2', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('newName', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, [ + 'public.users->public.users2', + 'public.users2.test->public.users2.newName', + ]); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" RENAME TO "users2";', + 'ALTER POLICY "test" ON "users2" RENAME TO "newName";', + ]); + expect(statements).toStrictEqual([ + { + fromSchema: '', + tableNameFrom: 'users', + tableNameTo: 'users2', + toSchema: '', + type: 'rename_table', + }, + { + newName: 'newName', + oldName: 'test', + schema: '', + tableName: 'users2', + type: 'rename_policy', + }, + ]); +}); + +test('create table with a policy', async (t) => { + const schema1 = {}; + + const schema2 = { + users: pgTable('users2', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "users2" (\n\t"id" integer PRIMARY KEY NOT NULL\n);\n', + 'ALTER TABLE "users2" ENABLE ROW LEVEL SECURITY;', + 'CREATE POLICY "test" ON "users2" AS PERMISSIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + columns: [ + { + name: 'id', + notNull: true, + primaryKey: true, + type: 'integer', + }, + ], + compositePKs: [], + checkConstraints: [], + compositePkName: '', + policies: [ + 'test--PERMISSIVE--ALL--public--undefined--undefined', + ], + schema: '', + tableName: 'users2', + isRLSEnabled: false, + type: 'create_table', + uniqueConstraints: [], + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users2', + type: 'create_policy', + }, + ]); +}); + +test('drop table with a policy', async (t) => { + const schema1 = { + users: pgTable('users2', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { as: 'permissive' }), + })), + }; + + const schema2 = {}; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users2" CASCADE;', + 'DROP TABLE "users2" CASCADE;', + ]); + expect(statements).toStrictEqual([ + { + policies: [ + 'test--PERMISSIVE--ALL--public--undefined--undefined', + ], + schema: '', + tableName: 'users2', + type: 'drop_table', + }, + ]); +}); + +test('add policy with multiple "to" roles', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + + const role = pgRole('manager').existing(); + + const schema2 = { + role, + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { to: ['current_role', role] }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR ALL TO current_role, "manager";', + ]); + expect(statements).toStrictEqual([ + { + schema: '', + tableName: 'users', + type: 'enable_rls', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['current_role', 'manager'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); + +test('create table with rls enabled', async (t) => { + const schema1 = {}; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }).enableRLS(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + `CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer PRIMARY KEY NOT NULL\n); +`, + 'ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;', + ]); + + console.log(statements); +}); + +test('enable rls force', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }).enableRLS(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual(['ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;']); +}); + +test('disable rls force', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }).enableRLS(), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual(['ALTER TABLE "users" DISABLE ROW LEVEL SECURITY;']); +}); + +test('drop policy with enabled rls', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { to: ['current_role', role] }), + })).enableRLS(), + }; + + const role = pgRole('manager').existing(); + + const schema2 = { + role, + users: pgTable('users', { + id: integer('id').primaryKey(), + }).enableRLS(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + ]); +}); + +test('add policy with enabled rls', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }).enableRLS(), + }; + + const role = pgRole('manager').existing(); + + const schema2 = { + role, + users: pgTable('users', { + id: integer('id').primaryKey(), + }, () => ({ + rls: pgPolicy('test', { to: ['current_role', role] }), + })).enableRLS(), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR ALL TO current_role, "manager";', + ]); +}); diff --git a/drizzle-kit/tests/rls/pg-role.test.ts b/drizzle-kit/tests/rls/pg-role.test.ts new file mode 100644 index 000000000..a6b762955 --- /dev/null +++ b/drizzle-kit/tests/rls/pg-role.test.ts @@ -0,0 +1,234 @@ +import { pgRole } from 'drizzle-orm/pg-core'; +import { diffTestSchemas } from 'tests/schemaDiffer'; +import { expect, test } from 'vitest'; + +test('create role', async (t) => { + const schema1 = {}; + + const schema2 = { + manager: pgRole('manager'), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual(['CREATE ROLE "manager";']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'create_role', + values: { + createDb: false, + createRole: false, + inherit: true, + }, + }, + ]); +}); + +test('create role with properties', async (t) => { + const schema1 = {}; + + const schema2 = { + manager: pgRole('manager', { createDb: true, inherit: false, createRole: true }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual(['CREATE ROLE "manager" WITH CREATEDB CREATEROLE NOINHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'create_role', + values: { + createDb: true, + createRole: true, + inherit: false, + }, + }, + ]); +}); + +test('create role with some properties', async (t) => { + const schema1 = {}; + + const schema2 = { + manager: pgRole('manager', { createDb: true, inherit: false }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual(['CREATE ROLE "manager" WITH CREATEDB NOINHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'create_role', + values: { + createDb: true, + createRole: false, + inherit: false, + }, + }, + ]); +}); + +test('drop role', async (t) => { + const schema1 = { manager: pgRole('manager') }; + + const schema2 = {}; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual(['DROP ROLE "manager";']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'drop_role', + }, + ]); +}); + +test('create and drop role', async (t) => { + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + admin: pgRole('admin'), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual(['DROP ROLE "manager";', 'CREATE ROLE "admin";']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'drop_role', + }, + { + name: 'admin', + type: 'create_role', + values: { + createDb: false, + createRole: false, + inherit: true, + }, + }, + ]); +}); + +test('rename role', async (t) => { + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + admin: pgRole('admin'), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, ['manager->admin']); + + expect(sqlStatements).toStrictEqual(['ALTER ROLE "manager" RENAME TO "admin";']); + expect(statements).toStrictEqual([ + { nameFrom: 'manager', nameTo: 'admin', type: 'rename_role' }, + ]); +}); + +test('alter all role field', async (t) => { + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + manager: pgRole('manager', { createDb: true, createRole: true, inherit: false }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual(['ALTER ROLE "manager" WITH CREATEDB CREATEROLE NOINHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'alter_role', + values: { + createDb: true, + createRole: true, + inherit: false, + }, + }, + ]); +}); + +test('alter createdb in role', async (t) => { + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + manager: pgRole('manager', { createDb: true }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual(['ALTER ROLE "manager" WITH CREATEDB NOCREATEROLE INHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'alter_role', + values: { + createDb: true, + createRole: false, + inherit: true, + }, + }, + ]); +}); + +test('alter createrole in role', async (t) => { + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + manager: pgRole('manager', { createRole: true }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual(['ALTER ROLE "manager" WITH NOCREATEDB CREATEROLE INHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'alter_role', + values: { + createDb: false, + createRole: true, + inherit: true, + }, + }, + ]); +}); + +test('alter inherit in role', async (t) => { + const schema1 = { + manager: pgRole('manager'), + }; + + const schema2 = { + manager: pgRole('manager', { inherit: false }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual(['ALTER ROLE "manager" WITH NOCREATEDB NOCREATEROLE NOINHERIT;']); + expect(statements).toStrictEqual([ + { + name: 'manager', + type: 'alter_role', + values: { + createDb: false, + createRole: false, + inherit: false, + }, + }, + ]); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 3001887e1..d8f6efc51 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -1,7 +1,6 @@ import { PGlite } from '@electric-sql/pglite'; import { Client } from '@libsql/client/.'; import { Database } from 'better-sqlite3'; -import { randomUUID } from 'crypto'; import { is } from 'drizzle-orm'; import { MySqlSchema, MySqlTable, MySqlView } from 'drizzle-orm/mysql-core'; import { @@ -12,6 +11,7 @@ import { isPgView, PgEnum, PgMaterializedView, + PgRole, PgSchema, PgSequence, PgTable, @@ -26,6 +26,8 @@ import { enumsResolver, mySqlViewsResolver, Named, + policyResolver, + roleResolver, schemasResolver, sequencesResolver, sqliteViewsResolver, @@ -34,6 +36,7 @@ import { } from 'src/cli/commands/migrate'; import { pgSuggestions } from 'src/cli/commands/pgPushUtils'; import { logSuggestionsAndReturn } from 'src/cli/commands/sqlitePushUtils'; +import { Entities } from 'src/cli/validations/cli'; import { CasingType } from 'src/cli/validations/common'; import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql'; import { schemaToTypeScript } from 'src/introspect-pg'; @@ -43,7 +46,7 @@ import { mysqlSchema, squashMysqlScheme, ViewSquashed } from 'src/serializer/mys import { generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; import { fromDatabase as fromMySqlDatabase } from 'src/serializer/mysqlSerializer'; import { prepareFromPgImports } from 'src/serializer/pgImports'; -import { pgSchema, squashPgScheme, View } from 'src/serializer/pgSchema'; +import { pgSchema, PgSquasher, Policy, Role, squashPgScheme, View } from 'src/serializer/pgSchema'; import { fromDatabase, generatePgSnapshot } from 'src/serializer/pgSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; import { sqliteSchema, squashSqliteScheme, View as SqliteView } from 'src/serializer/sqliteSchema'; @@ -61,13 +64,15 @@ import { ResolverInput, ResolverOutput, ResolverOutputWithMoved, + RolesResolverInput, + RolesResolverOutput, Sequence, Table, } from 'src/snapshotsDiffer'; export type PostgresSchema = Record< string, - PgTable | PgEnum | PgSchema | PgSequence | PgView | PgMaterializedView + PgTable | PgEnum | PgSchema | PgSequence | PgView | PgMaterializedView | PgRole >; export type MysqlSchema = Record | MySqlSchema | MySqlView>; export type SqliteSchema = Record | SQLiteView>; @@ -395,6 +400,128 @@ export const testColumnsResolver = } }; +export const testPolicyResolver = (renames: Set) => +async ( + input: ColumnsResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + tableName: input.tableName, + schema: input.schema, + created: input.created, + renamed: [], + deleted: input.deleted, + }; + } + + let createdPolicies = [...input.created]; + let deletedPolicies = [...input.deleted]; + + const renamed: { from: Policy; to: Policy }[] = []; + + const schema = input.schema || 'public'; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedPolicies.findIndex((it) => { + return `${schema}.${input.tableName}.${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdPolicies.findIndex((it) => { + return `${schema}.${input.tableName}.${it.name}` === to; + }); + + renamed.push({ + from: deletedPolicies[idxFrom], + to: createdPolicies[idxTo], + }); + + delete createdPolicies[idxTo]; + delete deletedPolicies[idxFrom]; + + createdPolicies = createdPolicies.filter(Boolean); + deletedPolicies = deletedPolicies.filter(Boolean); + } + } + + return { + tableName: input.tableName, + schema: input.schema, + created: createdPolicies, + deleted: deletedPolicies, + renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const testRolesResolver = (renames: Set) => +async ( + input: RolesResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + renamed: [], + deleted: input.deleted, + }; + } + + let createdPolicies = [...input.created]; + let deletedPolicies = [...input.deleted]; + + const renamed: { from: Policy; to: Policy }[] = []; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedPolicies.findIndex((it) => { + return `${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdPolicies.findIndex((it) => { + return `${it.name}` === to; + }); + + renamed.push({ + from: deletedPolicies[idxFrom], + to: createdPolicies[idxTo], + }); + + delete createdPolicies[idxTo]; + delete deletedPolicies[idxFrom]; + + createdPolicies = createdPolicies.filter(Boolean); + deletedPolicies = deletedPolicies.filter(Boolean); + } + } + + return { + created: createdPolicies, + deleted: deletedPolicies, + renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; + export const testViewsResolver = (renames: Set) => async (input: ResolverInput): Promise> => { try { @@ -606,6 +733,7 @@ export const diffTestSchemasPush = async ( cli: boolean = false, schemas: string[] = ['public'], casing?: CasingType | undefined, + entities?: Entities, sqlStatementsToRun: { before?: string[]; after?: string[]; runApply?: boolean } = { before: [], after: [], @@ -655,6 +783,7 @@ export const diffTestSchemasPush = async ( }, undefined, schemas, + entities, ); const leftTables = Object.values(right).filter((it) => is(it, PgTable)) as PgTable[]; @@ -665,6 +794,8 @@ export const diffTestSchemasPush = async ( const leftSequences = Object.values(right).filter((it) => isPgSequence(it)) as PgSequence[]; + const leftRoles = Object.values(right).filter((it) => is(it, PgRole)) as PgRole[]; + const leftViews = Object.values(right).filter((it) => isPgView(it)) as PgView[]; const leftMaterializedViews = Object.values(right).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; @@ -674,6 +805,7 @@ export const diffTestSchemasPush = async ( leftEnums, leftSchemas, leftSequences, + leftRoles, leftViews, leftMaterializedViews, casing, @@ -713,6 +845,8 @@ export const diffTestSchemasPush = async ( testSchemasResolver(renames), testEnumsResolver(renames), testSequencesResolver(renames), + testPolicyResolver(renames), + testRolesResolver(renames), testTablesResolver(renames), testColumnsResolver(renames), testViewsResolver(renames), @@ -757,6 +891,8 @@ export const diffTestSchemasPush = async ( schemasResolver, enumsResolver, sequencesResolver, + policyResolver, + roleResolver, tablesResolver, columnsResolver, viewsResolver, @@ -779,6 +915,7 @@ export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | unde views: {}, schemas: {}, sequences: {}, + roles: {}, _meta: { schemas: {}, tables: {}, @@ -794,11 +931,13 @@ export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | unde const sequences = Object.values(sn).filter((it) => isPgSequence(it)) as PgSequence[]; + const roles = Object.values(sn).filter((it) => is(it, PgRole)) as PgRole[]; + const views = Object.values(sn).filter((it) => isPgView(it)) as PgView[]; const materializedViews = Object.values(sn).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; - const serialized1 = generatePgSnapshot(tables, enums, schemas, sequences, views, materializedViews, casing); + const serialized1 = generatePgSnapshot(tables, enums, schemas, sequences, roles, views, materializedViews, casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -821,6 +960,8 @@ export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | unde testSchemasResolver(new Set()), testEnumsResolver(new Set()), testSequencesResolver(new Set()), + testPolicyResolver(new Set()), + testRolesResolver(new Set()), testTablesResolver(new Set()), testColumnsResolver(new Set()), testViewsResolver(new Set()), @@ -853,6 +994,9 @@ export const diffTestSchemas = async ( const rightSequences = Object.values(right).filter((it) => isPgSequence(it)) as PgSequence[]; + const leftRoles = Object.values(left).filter((it) => is(it, PgRole)) as PgRole[]; + + const rightRoles = Object.values(right).filter((it) => is(it, PgRole)) as PgRole[]; const leftViews = Object.values(left).filter((it) => isPgView(it)) as PgView[]; const rightViews = Object.values(right).filter((it) => isPgView(it)) as PgView[]; @@ -866,6 +1010,7 @@ export const diffTestSchemas = async ( leftEnums, leftSchemas, leftSequences, + leftRoles, leftViews, leftMaterializedViews, casing, @@ -875,6 +1020,7 @@ export const diffTestSchemas = async ( rightEnums, rightSchemas, rightSequences, + rightRoles, rightViews, rightMaterializedViews, casing, @@ -914,6 +1060,8 @@ export const diffTestSchemas = async ( testSchemasResolver(renames), testEnumsResolver(renames), testSequencesResolver(renames), + testPolicyResolver(renames), + testRolesResolver(renames), testTablesResolver(renames), testColumnsResolver(renames), testViewsResolver(renames), @@ -928,6 +1076,8 @@ export const diffTestSchemas = async ( schemasResolver, enumsResolver, sequencesResolver, + policyResolver, + roleResolver, tablesResolver, columnsResolver, viewsResolver, @@ -1626,6 +1776,7 @@ export const introspectPgToFile = async ( initSchema: PostgresSchema, testName: string, schemas: string[] = ['public'], + entities?: Entities, casing?: CasingType | undefined, ) => { // put in db @@ -1644,6 +1795,7 @@ export const introspectPgToFile = async ( }, undefined, schemas, + entities, ); const { version: initV, dialect: initD, ...initRest } = introspectedSchema; @@ -1672,6 +1824,7 @@ export const introspectPgToFile = async ( response.enums, response.schemas, response.sequences, + response.roles, response.views, response.matViews, casing, @@ -1696,6 +1849,8 @@ export const introspectPgToFile = async ( testSchemasResolver(new Set()), testEnumsResolver(new Set()), testSequencesResolver(new Set()), + testPolicyResolver(new Set()), + testRolesResolver(new Set()), testTablesResolver(new Set()), testColumnsResolver(new Set()), testViewsResolver(new Set()), diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index 0390ff28e..8d8eae298 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -159,6 +159,7 @@ test('add table #6', async () => { type: 'drop_table', tableName: 'users1', schema: undefined, + policies: [], }); }); diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 8622fea11..b0027dc44 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -45,7 +45,7 @@ "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=3", - "@electric-sql/pglite": ">=0.1.1", + "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.1", diff --git a/drizzle-orm/src/neon/index.ts b/drizzle-orm/src/neon/index.ts new file mode 100644 index 000000000..ee201ff1c --- /dev/null +++ b/drizzle-orm/src/neon/index.ts @@ -0,0 +1 @@ +export * from './rls.ts'; diff --git a/drizzle-orm/src/neon/rls.ts b/drizzle-orm/src/neon/rls.ts new file mode 100644 index 000000000..85f6ba220 --- /dev/null +++ b/drizzle-orm/src/neon/rls.ts @@ -0,0 +1,65 @@ +import { is } from '~/entity.ts'; +import { type AnyPgColumn, pgPolicy, type PgPolicyToOption } from '~/pg-core/index.ts'; +import { PgRole, pgRole } from '~/pg-core/roles.ts'; +import { type SQL, sql } from '~/sql/sql.ts'; + +export const crudPolicy = (options: { + role: PgPolicyToOption; + read?: SQL | boolean; + modify?: SQL | boolean; +}) => { + const read: SQL = options.read === true + ? sql`true` + : options.read === false || options.read === undefined + ? sql`false` + : options.read; + + const modify: SQL = options.modify === true + ? sql`true` + : options.modify === false || options.modify === undefined + ? sql`false` + : options.modify; + + let rolesName = ''; + if (Array.isArray(options.role)) { + rolesName = options.role + .map((it) => { + return is(it, PgRole) ? it.name : (it as string); + }) + .join('-'); + } else { + rolesName = is(options.role, PgRole) + ? options.role.name + : (options.role as string); + } + + return [ + pgPolicy(`crud-${rolesName}-policy-insert`, { + for: 'insert', + to: options.role, + withCheck: modify, + }), + pgPolicy(`crud-${rolesName}-policy-update`, { + for: 'update', + to: options.role, + using: modify, + withCheck: modify, + }), + pgPolicy(`crud-${rolesName}-policy-delete`, { + for: 'delete', + to: options.role, + using: modify, + }), + pgPolicy(`crud-${rolesName}-policy-select`, { + for: 'select', + to: options.role, + using: read, + }), + ]; +}; + +// These are default roles that Neon will set up. +export const authenticatedRole = pgRole('authenticated').existing(); +export const anonymousRole = pgRole('anonymous').existing(); + +export const authUid = (userIdColumn: AnyPgColumn) => sql`(select auth.user_id() = ${userIdColumn})`; diff --git a/drizzle-orm/src/pg-core/index.ts b/drizzle-orm/src/pg-core/index.ts index 084633c4a..ebc436bc1 100644 --- a/drizzle-orm/src/pg-core/index.ts +++ b/drizzle-orm/src/pg-core/index.ts @@ -5,8 +5,10 @@ export * from './db.ts'; export * from './dialect.ts'; export * from './foreign-keys.ts'; export * from './indexes.ts'; +export * from './policies.ts'; export * from './primary-keys.ts'; export * from './query-builders/index.ts'; +export * from './roles.ts'; export * from './schema.ts'; export * from './sequence.ts'; export * from './session.ts'; diff --git a/drizzle-orm/src/pg-core/policies.ts b/drizzle-orm/src/pg-core/policies.ts new file mode 100644 index 000000000..74a3ea85c --- /dev/null +++ b/drizzle-orm/src/pg-core/policies.ts @@ -0,0 +1,47 @@ +import { entityKind } from '~/entity.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { PgRole } from './roles.ts'; + +export type PgPolicyToOption = + | 'public' + | 'current_role' + | 'current_user' + | 'session_user' + | (string & {}) + | PgPolicyToOption[] + | PgRole; + +export interface PgPolicyConfig { + as?: 'permissive' | 'restrictive'; + for?: 'all' | 'select' | 'insert' | 'update' | 'delete'; + to?: PgPolicyToOption; + using?: SQL; + withCheck?: SQL; +} + +export class PgPolicy implements PgPolicyConfig { + static readonly [entityKind]: string = 'PgPolicy'; + + readonly as: PgPolicyConfig['as']; + readonly for: PgPolicyConfig['for']; + readonly to: PgPolicyConfig['to']; + readonly using: PgPolicyConfig['using']; + readonly withCheck: PgPolicyConfig['withCheck']; + + constructor( + readonly name: string, + config?: PgPolicyConfig, + ) { + if (config) { + this.as = config.as; + this.for = config.for; + this.to = config.to; + this.using = config.using; + this.withCheck = config.withCheck; + } + } +} + +export function pgPolicy(name: string, config?: PgPolicyConfig) { + return new PgPolicy(name, config); +} diff --git a/drizzle-orm/src/pg-core/roles.ts b/drizzle-orm/src/pg-core/roles.ts new file mode 100644 index 000000000..a2c77c303 --- /dev/null +++ b/drizzle-orm/src/pg-core/roles.ts @@ -0,0 +1,41 @@ +import { entityKind } from '~/entity.ts'; + +export interface PgRoleConfig { + createDb?: boolean; + createRole?: boolean; + inherit?: boolean; +} + +export class PgRole implements PgRoleConfig { + static readonly [entityKind]: string = 'PgRole'; + + /** @internal */ + _existing?: boolean; + + /** @internal */ + readonly createDb: PgRoleConfig['createDb']; + /** @internal */ + readonly createRole: PgRoleConfig['createRole']; + /** @internal */ + readonly inherit: PgRoleConfig['inherit']; + + constructor( + readonly name: string, + config?: PgRoleConfig, + ) { + if (config) { + this.createDb = config.createDb; + this.createRole = config.createRole; + this.inherit = config.inherit; + } + } + + existing(): this { + this._existing = true; + return this; + } +} + +export function pgRole(name: string, config?: PgRoleConfig) { + return new PgRole(name, config); +} diff --git a/drizzle-orm/src/pg-core/table.ts b/drizzle-orm/src/pg-core/table.ts index 5bf9a9895..c3c34c577 100644 --- a/drizzle-orm/src/pg-core/table.ts +++ b/drizzle-orm/src/pg-core/table.ts @@ -6,22 +6,29 @@ import { getPgColumnBuilders, type PgColumnsBuilders } from './columns/all.ts'; import type { PgColumn, PgColumnBuilder, PgColumnBuilderBase } from './columns/common.ts'; import type { ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; import type { AnyIndexBuilder } from './indexes.ts'; +import type { PgPolicy } from './policies.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; -export type PgTableExtraConfig = Record< - string, +export type PgTableExtraConfigValue = | AnyIndexBuilder | CheckBuilder | ForeignKeyBuilder | PrimaryKeyBuilder | UniqueConstraintBuilder + | PgPolicy; + +export type PgTableExtraConfig = Record< + string, + PgTableExtraConfigValue >; export type TableConfig = TableConfigBase; /** @internal */ export const InlineForeignKeys = Symbol.for('drizzle:PgInlineForeignKeys'); +/** @internal */ +export const EnableRLS = Symbol.for('drizzle:EnableRLS'); export class PgTable extends Table { static override readonly [entityKind]: string = 'PgTable'; @@ -29,11 +36,15 @@ export class PgTable extends Table { /** @internal */ static override readonly Symbol = Object.assign({}, Table.Symbol, { InlineForeignKeys: InlineForeignKeys as typeof InlineForeignKeys, + EnableRLS: EnableRLS as typeof EnableRLS, }); /**@internal */ [InlineForeignKeys]: ForeignKey[] = []; + /** @internal */ + [EnableRLS]: boolean = false; + /** @internal */ override [Table.Symbol.ExtraConfigBuilder]: ((self: Record) => PgTableExtraConfig) | undefined = undefined; @@ -45,6 +56,12 @@ export type PgTableWithColumns = & PgTable & { [Key in keyof T['columns']]: T['columns'][Key]; + } + & { + enableRLS: () => Omit< + PgTableWithColumns, + 'enableRLS' + >; }; /** @internal */ @@ -55,7 +72,9 @@ export function pgTableWithSchema< >( name: TTableName, columns: TColumnsMap | ((columnTypes: PgColumnsBuilders) => TColumnsMap), - extraConfig: ((self: BuildExtraConfigColumns) => PgTableExtraConfig) | undefined, + extraConfig: + | ((self: BuildExtraConfigColumns) => PgTableExtraConfig | PgTableExtraConfigValue[]) + | undefined, schema: TSchemaName, baseName = name, ): PgTableWithColumns<{ @@ -101,17 +120,65 @@ export function pgTableWithSchema< table[PgTable.Symbol.ExtraConfigBuilder] = extraConfig as any; } - return table; + return Object.assign(table, { + enableRLS: () => { + table[PgTable.Symbol.EnableRLS] = true; + return table as PgTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'pg'; + }>; + }, + }); } export interface PgTableFn { + /** + * @deprecated This overload is deprecated. Use the other method overload instead. + */ + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: TColumnsMap, + extraConfig: ( + self: BuildExtraConfigColumns, + ) => PgTableExtraConfig, + ): PgTableWithColumns<{ + name: TTableName; + schema: TSchema; + columns: BuildColumns; + dialect: 'pg'; + }>; + + /** + * @deprecated This overload is deprecated. Use the other method overload instead. + */ + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: PgColumnsBuilders) => TColumnsMap, + extraConfig: (self: BuildExtraConfigColumns) => PgTableExtraConfig, + ): PgTableWithColumns<{ + name: TTableName; + schema: TSchema; + columns: BuildColumns; + dialect: 'pg'; + }>; + < TTableName extends string, TColumnsMap extends Record, >( name: TTableName, columns: TColumnsMap, - extraConfig?: (self: BuildExtraConfigColumns) => PgTableExtraConfig, + extraConfig?: ( + self: BuildExtraConfigColumns, + ) => PgTableExtraConfigValue[], ): PgTableWithColumns<{ name: TTableName; schema: TSchema; @@ -125,7 +192,7 @@ export interface PgTableFn { >( name: TTableName, columns: (columnTypes: PgColumnsBuilders) => TColumnsMap, - extraConfig?: (self: BuildExtraConfigColumns) => PgTableExtraConfig, + extraConfig?: (self: BuildExtraConfigColumns) => PgTableExtraConfigValue[], ): PgTableWithColumns<{ name: TTableName; schema: TSchema; diff --git a/drizzle-orm/src/pg-core/utils.ts b/drizzle-orm/src/pg-core/utils.ts index 90378f249..0191c2439 100644 --- a/drizzle-orm/src/pg-core/utils.ts +++ b/drizzle-orm/src/pg-core/utils.ts @@ -7,6 +7,7 @@ import type { AnyPgColumn } from './columns/index.ts'; import { type ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; import type { Index } from './indexes.ts'; import { IndexBuilder } from './indexes.ts'; +import { PgPolicy } from './policies.ts'; import { type PrimaryKey, PrimaryKeyBuilder } from './primary-keys.ts'; import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; import { PgViewConfig } from './view-common.ts'; @@ -21,12 +22,15 @@ export function getTableConfig(table: TTable) { const uniqueConstraints: UniqueConstraint[] = []; const name = table[Table.Symbol.Name]; const schema = table[Table.Symbol.Schema]; + const policies: PgPolicy[] = []; + const enableRLS: boolean = table[PgTable.Symbol.EnableRLS]; const extraConfigBuilder = table[PgTable.Symbol.ExtraConfigBuilder]; if (extraConfigBuilder !== undefined) { const extraConfig = extraConfigBuilder(table[Table.Symbol.ExtraConfigColumns]); - for (const builder of Object.values(extraConfig)) { + const extraValues = Array.isArray(extraConfig) ? extraConfig.flat(1) as any[] : Object.values(extraConfig); + for (const builder of extraValues) { if (is(builder, IndexBuilder)) { indexes.push(builder.build(table)); } else if (is(builder, CheckBuilder)) { @@ -37,6 +41,8 @@ export function getTableConfig(table: TTable) { primaryKeys.push(builder.build(table)); } else if (is(builder, ForeignKeyBuilder)) { foreignKeys.push(builder.build(table)); + } else if (is(builder, PgPolicy)) { + policies.push(builder); } } } @@ -50,6 +56,8 @@ export function getTableConfig(table: TTable) { uniqueConstraints, name, schema, + policies, + enableRLS, }; } diff --git a/drizzle-orm/src/supabase/index.ts b/drizzle-orm/src/supabase/index.ts new file mode 100644 index 000000000..ee201ff1c --- /dev/null +++ b/drizzle-orm/src/supabase/index.ts @@ -0,0 +1 @@ +export * from './rls.ts'; diff --git a/drizzle-orm/src/supabase/rls.ts b/drizzle-orm/src/supabase/rls.ts new file mode 100644 index 000000000..f6919a980 --- /dev/null +++ b/drizzle-orm/src/supabase/rls.ts @@ -0,0 +1,7 @@ +import { pgRole } from '~/pg-core/roles.ts'; + +// These are default roles that Supabase will set up. +export const anonRole = pgRole('anon').existing(); +export const authenticatedRole = pgRole('authenticated').existing(); +export const serviceRole = pgRole('service_role').existing(); +export const postgresRole = pgRole('postgres_role').existing(); diff --git a/drizzle-orm/src/table.ts b/drizzle-orm/src/table.ts index 0bf08fb3b..6bacfc207 100644 --- a/drizzle-orm/src/table.ts +++ b/drizzle-orm/src/table.ts @@ -109,7 +109,7 @@ export class Table implements SQLWrapper { [IsDrizzleTable] = true; /** @internal */ - [ExtraConfigBuilder]: ((self: any) => Record) | undefined = undefined; + [ExtraConfigBuilder]: ((self: any) => Record | unknown[]) | undefined = undefined; constructor(name: string, schema: string | undefined, baseName: string) { this[TableName] = this[OriginalName] = name; diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index 0ae1d8488..0b139dc3a 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -78,23 +78,23 @@ export const users = pgTable( enumCol: myEnum('enum_col').notNull(), arrayCol: text('array_col').array().notNull(), }, - (users) => ({ - usersAge1Idx: uniqueIndex('usersAge1Idx').on(users.class.asc().nullsFirst(), sql``), - usersAge2Idx: index('usersAge2Idx').on(sql``), - uniqueClass: uniqueIndex('uniqueClass') + (users) => [ + uniqueIndex('usersAge1Idx').on(users.class.asc().nullsFirst(), sql``), + index('usersAge2Idx').on(sql``), + uniqueIndex('uniqueClass') .using('btree', users.class.desc().op('text_ops'), users.subClass.nullsLast()) .where(sql`${users.class} is not null`) .concurrently(), - legalAge: check('legalAge', sql`${users.age1} > 18`), - usersClassFK: foreignKey({ columns: [users.subClass], foreignColumns: [classes.subClass] }) + check('legalAge', sql`${users.age1} > 18`), + foreignKey({ columns: [users.subClass], foreignColumns: [classes.subClass] }) .onUpdate('cascade') .onDelete('cascade'), - usersClassComplexFK: foreignKey({ + foreignKey({ columns: [users.class, users.subClass], foreignColumns: [classes.class, classes.subClass], }), - pk: primaryKey(users.age1, users.class), - }), + primaryKey(users.age1, users.class), + ], ); Expect, typeof users['$inferSelect']>>; @@ -172,9 +172,7 @@ export const citiesCustom = customSchema.table('cities_table', { id: serial('id').primaryKey(), name: text('name').notNull(), population: integer('population').default(0), -}, (cities) => ({ - citiesNameIdx: index().on(cities.id), -})); +}, (cities) => [index().on(cities.id)]); export const newYorkers = pgView('new_yorkers') .with({ diff --git a/integration-tests/package.json b/integration-tests/package.json index 775103111..b7a5cca5b 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -43,7 +43,8 @@ "dependencies": { "@aws-sdk/client-rds-data": "^3.549.0", "@aws-sdk/credential-providers": "^3.549.0", - "@electric-sql/pglite": "^0.2.12", + "@electric-sql/pglite": "0.2.12", + "@libsql/client": "^0.10.0", "@miniflare/d1": "^2.14.4", "@miniflare/shared": "^2.14.4", "@planetscale/database": "^1.16.0", diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 78eecf328..a079db973 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -18,6 +18,7 @@ import { gte, ilike, inArray, + is, lt, max, min, @@ -30,6 +31,7 @@ import { sumDistinct, TransactionRollbackError, } from 'drizzle-orm'; +import { authenticatedRole, crudPolicy } from 'drizzle-orm/neon'; import type { NeonHttpDatabase } from 'drizzle-orm/neon-http'; import type { PgColumn, PgDatabase, PgQueryResultHKT } from 'drizzle-orm/pg-core'; import { @@ -45,6 +47,7 @@ import { getMaterializedViewConfig, getTableConfig, getViewConfig, + index, inet, integer, intersect, @@ -55,8 +58,11 @@ import { macaddr, macaddr8, numeric, + PgDialect, pgEnum, pgMaterializedView, + PgPolicy, + pgPolicy, pgSchema, pgTable, pgTableCreator, @@ -4711,6 +4717,123 @@ export function tests() { }]); }); + test('policy', () => { + { + const policy = pgPolicy('test policy'); + + expect(is(policy, PgPolicy)).toBe(true); + expect(policy.name).toBe('test policy'); + } + + { + const policy = pgPolicy('test policy', { + as: 'permissive', + for: 'all', + to: 'public', + using: sql`1=1`, + withCheck: sql`1=1`, + }); + + expect(is(policy, PgPolicy)).toBe(true); + expect(policy.name).toBe('test policy'); + expect(policy.as).toBe('permissive'); + expect(policy.for).toBe('all'); + expect(policy.to).toBe('public'); + const dialect = new PgDialect(); + expect(is(policy.using, SQL)).toBe(true); + expect(dialect.sqlToQuery(policy.using!).sql).toBe('1=1'); + expect(is(policy.withCheck, SQL)).toBe(true); + expect(dialect.sqlToQuery(policy.withCheck!).sql).toBe('1=1'); + } + + { + const policy = pgPolicy('test policy', { + to: 'custom value', + }); + + expect(policy.to).toBe('custom value'); + } + + { + const p1 = pgPolicy('test policy'); + const p2 = pgPolicy('test policy 2', { + as: 'permissive', + for: 'all', + to: 'public', + using: sql`1=1`, + withCheck: sql`1=1`, + }); + const table = pgTable('table_with_policy', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, () => ({ + p1, + p2, + })); + const config = getTableConfig(table); + expect(config.policies).toHaveLength(2); + expect(config.policies[0]).toBe(p1); + expect(config.policies[1]).toBe(p2); + } + }); + + test('neon: policy', () => { + { + const policy = crudPolicy({ + read: true, + modify: true, + role: authenticatedRole, + }); + + for (const it of Object.values(policy)) { + expect(is(it, PgPolicy)).toBe(true); + expect(it.to).toStrictEqual(authenticatedRole); + it.using ? expect(it.using).toStrictEqual(sql`true`) : ''; + it.withCheck ? expect(it.withCheck).toStrictEqual(sql`true`) : ''; + } + } + + { + const table = pgTable('name', { + id: integer('id'), + }, (t) => [ + index('name').on(t.id), + crudPolicy({ + read: true, + modify: true, + role: authenticatedRole, + }), + primaryKey({ columns: [t.id], name: 'custom' }), + ]); + + const { policies, indexes, primaryKeys } = getTableConfig(table); + + expect(policies.length).toBe(4); + expect(indexes.length).toBe(1); + expect(primaryKeys.length).toBe(1); + + expect(policies[0]?.name === 'crud-custom-policy-modify'); + expect(policies[1]?.name === 'crud-custom-policy-read'); + } + }); + + test('Enable RLS function', () => { + const usersWithRLS = pgTable('users', { + id: integer(), + }).enableRLS(); + + const config1 = getTableConfig(usersWithRLS); + + const usersNoRLS = pgTable('users', { + id: integer(), + }); + + const config2 = getTableConfig(usersNoRLS); + + expect(config1.enableRLS).toBeTruthy(); + expect(config2.enableRLS).toBeFalsy(); + }); + test('$count separate', async (ctx) => { const { db } = ctx.pg; diff --git a/integration-tests/tests/pg/rls/rls.definition.test.ts b/integration-tests/tests/pg/rls/rls.definition.test.ts new file mode 100644 index 000000000..81090633e --- /dev/null +++ b/integration-tests/tests/pg/rls/rls.definition.test.ts @@ -0,0 +1,16 @@ +import { crudPolicy } from 'drizzle-orm/neon'; +import { getTableConfig, integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core'; +import { test } from 'vitest'; + +test.skip('getTableConfig: policies', async () => { + const schema = pgTable('hhh', { + id: integer(), + }, () => [ + pgPolicy('name'), + crudPolicy({ role: pgRole('users') }), + ]); + + const tc = getTableConfig(schema); + + console.log(tc.policies); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 20ff6ca0f..43c397795 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -553,8 +553,11 @@ importers: specifier: ^3.549.0 version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0) '@electric-sql/pglite': - specifier: ^0.2.12 + specifier: 0.2.12 version: 0.2.12 + '@libsql/client': + specifier: ^0.10.0 + version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@miniflare/d1': specifier: ^2.14.4 version: 2.14.4 @@ -652,9 +655,6 @@ importers: '@cloudflare/workers-types': specifier: ^4.20241004.0 version: 4.20241004.0 - '@libsql/client': - specifier: ^0.10.0 - version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': specifier: 0.9.0 version: 0.9.0 From 2a2fd1184dae14c8dab7628ddd65ae9f3d818d36 Mon Sep 17 00:00:00 2001 From: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:37:46 +0300 Subject: [PATCH 262/492] Marked `@libsql/client` peer dependency as optional (#3191) Co-authored-by: Andrii Sherman --- drizzle-orm/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index b0027dc44..02b6084be 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -130,6 +130,9 @@ "@libsql/client": { "optional": true }, + "@libsql/client-wasm": { + "optional": true + }, "@opentelemetry/api": { "optional": true }, From 188a14153a073c2a56af7d821bd6205d00fdb78f Mon Sep 17 00:00:00 2001 From: Steffen <3752127+klotztech@users.noreply.github.com> Date: Fri, 25 Oct 2024 22:05:08 +0200 Subject: [PATCH 263/492] Fix breakpoints option default value --- drizzle-kit/src/cli/commands/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index e58e23435..dbd337a03 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -169,7 +169,7 @@ export const prepareGenerateConfig = async ( name: options.name, custom: options.custom || false, prefix, - breakpoints: breakpoints || true, + breakpoints: breakpoints ?? true, schema: schema, out: out || 'drizzle', bundle: driver === 'expo', From b2b714a0e1588a56765d0f6e459749a77658ca1c Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Sun, 27 Oct 2024 21:22:40 +0200 Subject: [PATCH 264/492] Add link to policy --- drizzle-kit/src/api.ts | 1 + drizzle-kit/src/serializer/index.ts | 4 +- drizzle-kit/src/serializer/pgImports.ts | 14 +- drizzle-kit/src/serializer/pgSerializer.ts | 85 ++++++++ drizzle-kit/tests/rls/pg-policy.test.ts | 233 +++++++++++++++++++++ drizzle-kit/tests/schemaDiffer.ts | 28 ++- drizzle-orm/package.json | 3 +- drizzle-orm/src/pg-core/policies.ts | 9 + drizzle-orm/src/supabase/rls.ts | 28 ++- 9 files changed, 396 insertions(+), 9 deletions(-) diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index d5b53cc9a..6e374c255 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -50,6 +50,7 @@ export const generateDrizzleJson = ( prepared.schemas, prepared.sequences, prepared.roles, + prepared.policies, prepared.views, prepared.matViews, casing, diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index 6347c2182..d76ea424f 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -66,11 +66,11 @@ export const serializePg = async ( const { prepareFromPgImports } = await import('./pgImports'); const { generatePgSnapshot } = await import('./pgSerializer'); - const { tables, enums, schemas, sequences, views, matViews, roles } = await prepareFromPgImports( + const { tables, enums, schemas, sequences, views, matViews, roles, policies } = await prepareFromPgImports( filenames, ); - return generatePgSnapshot(tables, enums, schemas, sequences, roles, views, matViews, casing, schemaFilter); + return generatePgSnapshot(tables, enums, schemas, sequences, roles, policies, views, matViews, casing, schemaFilter); }; export const serializeSQLite = async ( diff --git a/drizzle-kit/src/serializer/pgImports.ts b/drizzle-kit/src/serializer/pgImports.ts index c1ecdb04c..40e54616a 100644 --- a/drizzle-kit/src/serializer/pgImports.ts +++ b/drizzle-kit/src/serializer/pgImports.ts @@ -7,6 +7,7 @@ import { isPgView, PgEnum, PgMaterializedView, + PgPolicy, PgRole, PgSchema, PgSequence, @@ -21,6 +22,7 @@ export const prepareFromExports = (exports: Record) => { const schemas: PgSchema[] = []; const sequences: PgSequence[] = []; const roles: PgRole[] = []; + const policies: PgPolicy[] = []; const views: PgView[] = []; const matViews: PgMaterializedView[] = []; @@ -53,9 +55,13 @@ export const prepareFromExports = (exports: Record) => { if (is(t, PgRole)) { roles.push(t); } + + if (is(t, PgPolicy)) { + policies.push(t); + } }); - return { tables, enums, schemas, sequences, views, matViews, roles }; + return { tables, enums, schemas, sequences, views, matViews, roles, policies }; }; export const prepareFromPgImports = async (imports: string[]) => { @@ -64,7 +70,8 @@ export const prepareFromPgImports = async (imports: string[]) => { const schemas: PgSchema[] = []; const sequences: PgSequence[] = []; const views: PgView[] = []; - let roles: PgRole[] = []; + const roles: PgRole[] = []; + const policies: PgPolicy[] = []; const matViews: PgMaterializedView[] = []; const { unregister } = await safeRegister(); @@ -81,8 +88,9 @@ export const prepareFromPgImports = async (imports: string[]) => { views.push(...prepared.views); matViews.push(...prepared.matViews); roles.push(...prepared.roles); + policies.push(...prepared.policies); } unregister(); - return { tables: Array.from(new Set(tables)), enums, schemas, sequences, views, matViews, roles }; + return { tables: Array.from(new Set(tables)), enums, schemas, sequences, views, matViews, roles, policies }; }; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 98848918a..d8b4682a3 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -12,6 +12,7 @@ import { PgEnum, PgEnumColumn, PgMaterializedView, + PgPolicy, PgRole, PgSchema, PgSequence, @@ -104,6 +105,7 @@ export const generatePgSnapshot = ( schemas: PgSchema[], sequences: PgSequence[], roles: PgRole[], + policies: PgPolicy[], views: PgView[], matViews: PgMaterializedView[], casing: CasingType | undefined, @@ -117,6 +119,7 @@ export const generatePgSnapshot = ( // This object stores unique names for indexes and will be used to detect if you have the same names for indexes // within the same PostgreSQL schema + const indexesInSchema: Record = {}; for (const table of tables) { @@ -496,6 +499,23 @@ export const generatePgSnapshot = ( } } + if (policiesObject[policy.name] !== undefined) { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated policy name across ${ + chalk.underline.blue(tableKey) + } table. Please rename one of the policies with ${ + chalk.underline.blue( + policy.name, + ) + } name`, + ) + }`, + ); + process.exit(1); + } + policiesObject[policy.name] = { name: policy.name, as: policy.as?.toUpperCase() as Policy['as'] ?? 'PERMISSIVE', @@ -559,6 +579,71 @@ export const generatePgSnapshot = ( }; } + for (const policy of policies) { + // @ts-ignore + if (!policy._linkedTable) { + console.log( + `\n${ + withStyle.errorWarning( + `"Policy ${policy.name} was skipped because it was not linked to any table. You should either include the policy in a table or use .link() on the policy to link it to any table you have. For more information, please check:`, + ) + }`, + ); + continue; + } + + // @ts-ignore + const tableConfig = getTableConfig(policy._linkedTable); + + const tableKey = `${tableConfig.schema ?? 'public'}.${tableConfig.name}`; + + const mappedTo = []; + + if (!policy.to) { + mappedTo.push('public'); + } else { + if (policy.to && typeof policy.to === 'string') { + mappedTo.push(policy.to); + } else if (policy.to && is(policy.to, PgRole)) { + mappedTo.push(policy.to.name); + } else if (policy.to && Array.isArray(policy.to)) { + policy.to.forEach((it) => { + if (typeof it === 'string') { + mappedTo.push(it); + } else if (is(it, PgRole)) { + mappedTo.push(it.name); + } + }); + } + } + + if (result[tableKey].policies[policy.name] !== undefined) { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated policy name across ${ + chalk.underline.blue(tableKey) + } table. Please rename one of the policies with ${ + chalk.underline.blue( + policy.name, + ) + } name`, + ) + }`, + ); + process.exit(1); + } + + result[tableKey].policies[policy.name] = { + name: policy.name, + as: policy.as?.toUpperCase() as Policy['as'] ?? 'PERMISSIVE', + for: policy.for?.toUpperCase() as Policy['for'] ?? 'ALL', + to: mappedTo.sort(), + using: is(policy.using, SQL) ? dialect.sqlToQuery(policy.using).sql : undefined, + withCheck: is(policy.withCheck, SQL) ? dialect.sqlToQuery(policy.withCheck).sql : undefined, + }; + } + for (const sequence of sequences) { const name = sequence.seqName!; if (typeof sequencesToReturn[`${sequence.schema ?? 'public'}.${name}`] === 'undefined') { diff --git a/drizzle-kit/tests/rls/pg-policy.test.ts b/drizzle-kit/tests/rls/pg-policy.test.ts index 5ca667faa..42f7c99f2 100644 --- a/drizzle-kit/tests/rls/pg-policy.test.ts +++ b/drizzle-kit/tests/rls/pg-policy.test.ts @@ -799,3 +799,236 @@ test('add policy with enabled rls', async (t) => { 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR ALL TO current_role, "manager";', ]); }); + +test('add policy + link table', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema2 = { + users, + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + schema: '', + tableName: 'users', + type: 'enable_rls', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); + +test('link table', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + rls: pgPolicy('test', { as: 'permissive' }), + }; + + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema2 = { + users, + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + schema: '', + tableName: 'users', + type: 'enable_rls', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); + +test('unlink table', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = { + users, + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const schema2 = { + users, + rls: pgPolicy('test', { as: 'permissive' }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" DISABLE ROW LEVEL SECURITY;', + 'DROP POLICY "test" ON "users" CASCADE;', + ]); + expect(statements).toStrictEqual([ + { + schema: '', + tableName: 'users', + type: 'disable_rls', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + ]); +}); + +test('drop policy with link', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = { + users, + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const schema2 = { + users, + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" DISABLE ROW LEVEL SECURITY;', + 'DROP POLICY "test" ON "users" CASCADE;', + ]); + expect(statements).toStrictEqual([ + { + schema: '', + tableName: 'users', + type: 'disable_rls', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + ]); +}); + +test('add policy in table and with link table', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + const users = pgTable('users', { + id: integer('id').primaryKey(), + }, () => [ + pgPolicy('test1', { to: 'current_user' }), + ]); + + const schema2 = { + users, + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;', + 'CREATE POLICY "test1" ON "users" AS PERMISSIVE FOR ALL TO current_user;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + schema: '', + tableName: 'users', + type: 'enable_rls', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test1', + to: ['current_user'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + to: ['public'], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index d8f6efc51..6453378e9 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -11,6 +11,7 @@ import { isPgView, PgEnum, PgMaterializedView, + PgPolicy, PgRole, PgSchema, PgSequence, @@ -72,7 +73,7 @@ import { export type PostgresSchema = Record< string, - PgTable | PgEnum | PgSchema | PgSequence | PgView | PgMaterializedView | PgRole + PgTable | PgEnum | PgSchema | PgSequence | PgView | PgMaterializedView | PgRole | PgPolicy >; export type MysqlSchema = Record | MySqlSchema | MySqlView>; export type SqliteSchema = Record | SQLiteView>; @@ -796,6 +797,8 @@ export const diffTestSchemasPush = async ( const leftRoles = Object.values(right).filter((it) => is(it, PgRole)) as PgRole[]; + const leftPolicies = Object.values(right).filter((it) => is(it, PgPolicy)) as PgPolicy[]; + const leftViews = Object.values(right).filter((it) => isPgView(it)) as PgView[]; const leftMaterializedViews = Object.values(right).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; @@ -806,6 +809,7 @@ export const diffTestSchemasPush = async ( leftSchemas, leftSequences, leftRoles, + leftPolicies, leftViews, leftMaterializedViews, casing, @@ -935,9 +939,21 @@ export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | unde const views = Object.values(sn).filter((it) => isPgView(it)) as PgView[]; + const policies = Object.values(sn).filter((it) => is(it, PgPolicy)) as PgPolicy[]; + const materializedViews = Object.values(sn).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[]; - const serialized1 = generatePgSnapshot(tables, enums, schemas, sequences, roles, views, materializedViews, casing); + const serialized1 = generatePgSnapshot( + tables, + enums, + schemas, + sequences, + roles, + policies, + views, + materializedViews, + casing, + ); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -997,6 +1013,11 @@ export const diffTestSchemas = async ( const leftRoles = Object.values(left).filter((it) => is(it, PgRole)) as PgRole[]; const rightRoles = Object.values(right).filter((it) => is(it, PgRole)) as PgRole[]; + + const leftPolicies = Object.values(left).filter((it) => is(it, PgPolicy)) as PgPolicy[]; + + const rightPolicies = Object.values(right).filter((it) => is(it, PgPolicy)) as PgPolicy[]; + const leftViews = Object.values(left).filter((it) => isPgView(it)) as PgView[]; const rightViews = Object.values(right).filter((it) => isPgView(it)) as PgView[]; @@ -1011,6 +1032,7 @@ export const diffTestSchemas = async ( leftSchemas, leftSequences, leftRoles, + leftPolicies, leftViews, leftMaterializedViews, casing, @@ -1021,6 +1043,7 @@ export const diffTestSchemas = async ( rightSchemas, rightSequences, rightRoles, + rightPolicies, rightViews, rightMaterializedViews, casing, @@ -1825,6 +1848,7 @@ export const introspectPgToFile = async ( response.schemas, response.sequences, response.roles, + response.policies, response.views, response.matViews, casing, diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 02b6084be..7c9a963d4 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -4,7 +4,8 @@ "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { - "build": "scripts/build.ts", + "p": "prisma generate --schema src/prisma/schema.prisma", + "build": "pnpm p && scripts/build.ts", "b": "pnpm build", "test:types": "cd type-tests && tsc", "test": "vitest run", diff --git a/drizzle-orm/src/pg-core/policies.ts b/drizzle-orm/src/pg-core/policies.ts index 74a3ea85c..9c2f94f28 100644 --- a/drizzle-orm/src/pg-core/policies.ts +++ b/drizzle-orm/src/pg-core/policies.ts @@ -1,6 +1,7 @@ import { entityKind } from '~/entity.ts'; import type { SQL } from '~/sql/sql.ts'; import type { PgRole } from './roles.ts'; +import type { PgTable } from './table.ts'; export type PgPolicyToOption = | 'public' @@ -28,6 +29,9 @@ export class PgPolicy implements PgPolicyConfig { readonly using: PgPolicyConfig['using']; readonly withCheck: PgPolicyConfig['withCheck']; + /** @internal */ + _linkedTable?: PgTable; + constructor( readonly name: string, config?: PgPolicyConfig, @@ -40,6 +44,11 @@ export class PgPolicy implements PgPolicyConfig { this.withCheck = config.withCheck; } } + + link(table: PgTable): this { + this._linkedTable = table; + return this; + } } export function pgPolicy(name: string, config?: PgPolicyConfig) { diff --git a/drizzle-orm/src/supabase/rls.ts b/drizzle-orm/src/supabase/rls.ts index f6919a980..54a326d8a 100644 --- a/drizzle-orm/src/supabase/rls.ts +++ b/drizzle-orm/src/supabase/rls.ts @@ -1,7 +1,33 @@ +import { bigserial, pgSchema, text, uuid } from '~/pg-core/index.ts'; import { pgRole } from '~/pg-core/roles.ts'; +import { sql } from '~/sql/sql.ts'; -// These are default roles that Supabase will set up. export const anonRole = pgRole('anon').existing(); export const authenticatedRole = pgRole('authenticated').existing(); export const serviceRole = pgRole('service_role').existing(); export const postgresRole = pgRole('postgres_role').existing(); +export const supabaseAuthAdminRole = pgRole('supabase_auth_admin').existing(); + +/* ------------------------------ auth schema; ------------------------------ */ +const auth = pgSchema('auth'); + +export const authUsers = auth.table('users', { + id: uuid().primaryKey().notNull(), +}); + +/* ------------------------------ realtime schema; ------------------------------ */ +const realtime = pgSchema('realtime'); + +export const realtimeMessages = realtime.table( + 'messages', + { + id: bigserial({ mode: 'bigint' }).primaryKey(), + topic: text().notNull(), + extension: text({ + enum: ['presence', 'broadcast', 'postgres_changes'], + }).notNull(), + }, +); + +export const authUid = sql`(select ${authUsers.id})`; +export const realtimeTopic = sql`${realtimeMessages.topic}`; From 53e089b74a47702bfba4ec2fc8f6605e70be482e Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 28 Oct 2024 16:36:38 +0200 Subject: [PATCH 265/492] Add link option for policies --- drizzle-kit/src/api.ts | 3 + drizzle-kit/src/cli/commands/introspect.ts | 4 + drizzle-kit/src/cli/commands/migrate.ts | 27 +- drizzle-kit/src/cli/commands/utils.ts | 3 + drizzle-kit/src/cli/schema.ts | 2 + drizzle-kit/src/cli/validations/cli.ts | 7 + drizzle-kit/src/cli/views.ts | 2 +- drizzle-kit/src/jsonDiffer.js | 26 ++ drizzle-kit/src/jsonStatements.ts | 82 +++++- drizzle-kit/src/serializer/pgSchema.ts | 34 ++- drizzle-kit/src/serializer/pgSerializer.ts | 21 +- drizzle-kit/src/snapshotsDiffer.ts | 205 ++++++++++++++- drizzle-kit/src/sqlgenerator.ts | 79 +++++- drizzle-kit/tests/cli-push.test.ts | 3 + drizzle-kit/tests/push/pg.test.ts | 22 +- drizzle-kit/tests/rls/pg-policy.test.ts | 276 ++++++++++++++++++++- drizzle-kit/tests/schemaDiffer.ts | 74 +++++- 17 files changed, 836 insertions(+), 34 deletions(-) diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 6e374c255..4392c7214 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -5,6 +5,7 @@ import { PgDatabase } from 'drizzle-orm/pg-core'; import { columnsResolver, enumsResolver, + indPolicyResolver, mySqlViewsResolver, policyResolver, roleResolver, @@ -83,6 +84,7 @@ export const generateMigration = async ( enumsResolver, sequencesResolver, policyResolver, + indPolicyResolver, roleResolver, tablesResolver, columnsResolver, @@ -129,6 +131,7 @@ export const pushSchema = async ( enumsResolver, sequencesResolver, policyResolver, + indPolicyResolver, roleResolver, tablesResolver, columnsResolver, diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 782116d97..db250d005 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -31,8 +31,10 @@ import { IntrospectProgress } from '../views'; import { columnsResolver, enumsResolver, + indPolicyResolver, mySqlViewsResolver, policyResolver, + roleResolver, schemasResolver, sequencesResolver, sqliteViewsResolver, @@ -117,6 +119,8 @@ export const introspectPostgres = async ( enumsResolver, sequencesResolver, policyResolver, + indPolicyResolver, + roleResolver, tablesResolver, columnsResolver, viewsResolver, diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index b5674e875..8d1e6205f 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -25,6 +25,8 @@ import { ColumnsResolverInput, ColumnsResolverOutput, Enum, + PolicyResolverInput, + PolicyResolverOutput, ResolverInput, ResolverOutput, ResolverOutputWithMoved, @@ -32,6 +34,8 @@ import { RolesResolverOutput, Sequence, Table, + TablePolicyResolverInput, + TablePolicyResolverOutput, } from '../../snapshotsDiffer'; import { assertV1OutFolder, Journal, prepareMigrationFolder } from '../../utils'; import { prepareMigrationMetadata } from '../../utils/words'; @@ -199,8 +203,8 @@ export const roleResolver = async ( }; export const policyResolver = async ( - input: ColumnsResolverInput, -): Promise> => { + input: TablePolicyResolverInput, +): Promise> => { const result = await promptColumnsConflicts( input.tableName, input.created, @@ -215,6 +219,21 @@ export const policyResolver = async ( }; }; +export const indPolicyResolver = async ( + input: PolicyResolverInput, +): Promise> => { + const result = await promptNamedConflict( + input.created, + input.deleted, + 'policy', + ); + return { + created: result.created, + deleted: result.deleted, + renamed: result.renamed, + }; +}; + export const enumsResolver = async ( input: ResolverInput, ): Promise> => { @@ -300,6 +319,7 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => { enumsResolver, sequencesResolver, policyResolver, + indPolicyResolver, roleResolver, tablesResolver, columnsResolver, @@ -348,6 +368,7 @@ export const preparePgPush = async ( enumsResolver, sequencesResolver, policyResolver, + indPolicyResolver, roleResolver, tablesResolver, columnsResolver, @@ -778,7 +799,7 @@ export const promptColumnsConflicts = async ( export const promptNamedConflict = async ( newItems: T[], missingItems: T[], - entity: 'role', + entity: 'role' | 'policy', ): Promise<{ created: T[]; renamed: { from: T; to: T }[]; diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index a4c018aa5..203e38cca 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -229,6 +229,7 @@ export const preparePushConfig = async ( tablesFilter: string[]; schemasFilter: string[]; casing?: CasingType; + entities?: Entities; } > => { const raw = flattenDatabaseCredentials( @@ -300,6 +301,7 @@ export const preparePushConfig = async ( casing: config.casing, tablesFilter, schemasFilter, + entities: config.entities, }; } @@ -508,6 +510,7 @@ export const preparePullConfig = async ( tablesFilter, schemasFilter, prefix: config.migrations?.prefix || 'index', + entities: config.entities, }; } diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 9886d2b61..64ceb5841 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -269,6 +269,7 @@ export const push = command({ schemasFilter, force, casing, + entities, } = config; try { @@ -313,6 +314,7 @@ export const push = command({ credentials, tablesFilter, schemasFilter, + entities, force, casing, ); diff --git a/drizzle-kit/src/cli/validations/cli.ts b/drizzle-kit/src/cli/validations/cli.ts index ef271e299..a2a5ad81f 100644 --- a/drizzle-kit/src/cli/validations/cli.ts +++ b/drizzle-kit/src/cli/validations/cli.ts @@ -26,6 +26,13 @@ export const pushParams = object({ extensionsFilters: literal('postgis').array().optional(), verbose: boolean().optional(), strict: boolean().optional(), + entities: object({ + roles: boolean().or(object({ + provider: string().optional(), + include: string().array().optional(), + exclude: string().array().optional(), + })).optional().default(false), + }).optional(), }).passthrough(); export type PushParams = TypeOf; diff --git a/drizzle-kit/src/cli/views.ts b/drizzle-kit/src/cli/views.ts index ef00ab8c4..3ec04a588 100644 --- a/drizzle-kit/src/cli/views.ts +++ b/drizzle-kit/src/cli/views.ts @@ -166,7 +166,7 @@ export class ResolveSelectNamed extends Prompt< constructor( private readonly base: T, data: (RenamePropmtItem | T)[], - private readonly entityType: 'role', + private readonly entityType: 'role' | 'policy', ) { super(); this.on('attach', (terminal) => terminal.toggleCursor('hide')); diff --git a/drizzle-kit/src/jsonDiffer.js b/drizzle-kit/src/jsonDiffer.js index 78155c8bd..da8284979 100644 --- a/drizzle-kit/src/jsonDiffer.js +++ b/drizzle-kit/src/jsonDiffer.js @@ -103,6 +103,22 @@ export function diffSchemasOrTables(left, right) { return { added, deleted }; } +export function diffIndPolicies(left, right) { + left = JSON.parse(JSON.stringify(left)); + right = JSON.parse(JSON.stringify(right)); + + const result = Object.entries(diff(left, right) ?? {}); + + const added = result + .filter((it) => it[0].endsWith('__added')) + .map((it) => it[1]); + const deleted = result + .filter((it) => it[0].endsWith('__deleted')) + .map((it) => it[1]); + + return { added, deleted }; +} + export function diffColumns(left, right) { left = JSON.parse(JSON.stringify(left)); right = JSON.parse(JSON.stringify(right)); @@ -202,6 +218,7 @@ export function applyJsonDiff(json1, json2) { difference.enums = difference.enums || {}; difference.sequences = difference.sequences || {}; difference.roles = difference.roles || {}; + difference.policies = difference.policies || {}; difference.views = difference.views || {}; // remove added/deleted schemas @@ -290,6 +307,14 @@ export function applyJsonDiff(json1, json2) { .map((it) => { return json2.roles[it[0]]; }); + + const policiesEntries = Object.entries(difference.policies); + const alteredPolicies = policiesEntries + .filter((it) => !(it[0].includes('__added') || it[0].includes('__deleted'))) + .map((it) => { + return json2.policies[it[0]]; + }); + const viewsEntries = Object.entries(difference.views); const alteredViews = viewsEntries.filter((it) => !(it[0].includes('__added') || it[0].includes('__deleted'))).map( @@ -381,6 +406,7 @@ export function applyJsonDiff(json1, json2) { alteredSequences, alteredRoles, alteredViews, + alteredPolicies, }; } diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 0d248422d..9359b1a8d 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -241,6 +241,12 @@ export interface JsonCreatePolicyStatement { schema: string; } +export interface JsonCreateIndPolicyStatement { + type: 'create_ind_policy'; + tableName: string; + data: Policy; +} + export interface JsonDropPolicyStatement { type: 'drop_policy'; tableName: string; @@ -248,6 +254,12 @@ export interface JsonDropPolicyStatement { schema: string; } +export interface JsonDropIndPolicyStatement { + type: 'drop_ind_policy'; + tableName: string; + data: Policy; +} + export interface JsonRenamePolicyStatement { type: 'rename_policy'; tableName: string; @@ -256,6 +268,13 @@ export interface JsonRenamePolicyStatement { schema: string; } +export interface JsonIndRenamePolicyStatement { + type: 'rename_ind_policy'; + tableKey: string; + oldName: string; + newName: string; +} + export interface JsonEnableRLSStatement { type: 'enable_rls'; tableName: string; @@ -276,6 +295,12 @@ export interface JsonAlterPolicyStatement { schema: string; } +export interface JsonAlterIndPolicyStatement { + type: 'alter_ind_policy'; + oldData: Policy; + newData: Policy; +} + export interface JsonCreateIndexStatement { type: 'create_index'; tableName: string; @@ -816,7 +841,11 @@ export type JsonStatement = | JsonCreateSqliteViewStatement | JsonCreateCheckConstraint | JsonDeleteCheckConstraint - | JsonDropValueFromEnumStatement; + | JsonDropValueFromEnumStatement + | JsonIndRenamePolicyStatement + | JsonDropIndPolicyStatement + | JsonCreateIndPolicyStatement + | JsonAlterIndPolicyStatement; export const preparePgCreateTableJson = ( table: Table, @@ -2299,6 +2328,22 @@ export const prepareRenamePolicyJsons = ( }); }; +export const prepareRenameIndPolicyJsons = ( + renames: { + from: Policy; + to: Policy; + }[], +): JsonIndRenamePolicyStatement[] => { + return renames.map((it) => { + return { + type: 'rename_ind_policy', + tableKey: it.from.on!, + oldName: it.from.name, + newName: it.to.name, + }; + }); +}; + export const prepareCreatePolicyJsons = ( tableName: string, schema: string, @@ -2314,6 +2359,18 @@ export const prepareCreatePolicyJsons = ( }); }; +export const prepareCreateIndPolicyJsons = ( + policies: Policy[], +): JsonCreateIndPolicyStatement[] => { + return policies.map((it) => { + return { + type: 'create_ind_policy', + tableName: it.on!, + data: it, + }; + }); +}; + export const prepareDropPolicyJsons = ( tableName: string, schema: string, @@ -2329,6 +2386,18 @@ export const prepareDropPolicyJsons = ( }); }; +export const prepareDropIndPolicyJsons = ( + policies: Policy[], +): JsonDropIndPolicyStatement[] => { + return policies.map((it) => { + return { + type: 'drop_ind_policy', + tableName: it.on!, + data: it, + }; + }); +}; + export const prepareAlterPolicyJson = ( tableName: string, schema: string, @@ -2344,6 +2413,17 @@ export const prepareAlterPolicyJson = ( }; }; +export const prepareAlterIndPolicyJson = ( + oldPolicy: Policy, + newPolicy: Policy, +): JsonAlterIndPolicyStatement => { + return { + type: 'alter_ind_policy', + oldData: oldPolicy, + newData: newPolicy, + }; +}; + export const preparePgCreateIndexesJson = ( tableName: string, schema: string, diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index 52c5a192a..40b02a2d1 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -232,13 +232,19 @@ const uniqueConstraint = object({ nullsNotDistinct: boolean(), }).strict(); -const policy = object({ +export const policy = object({ name: string(), as: enumType(['PERMISSIVE', 'RESTRICTIVE']).optional(), for: enumType(['ALL', 'SELECT', 'INSERT', 'UPDATE', 'DELETE']).optional(), to: string().array().optional(), using: string().optional(), withCheck: string().optional(), + on: string().optional(), +}).strict(); + +export const policySquashed = object({ + name: string(), + values: string(), }).strict(); const viewWithOption = object({ @@ -437,6 +443,7 @@ export const pgSchemaInternal = object({ views: record(string(), view).default({}), sequences: record(string(), sequenceSchema).default({}), roles: record(string(), roleSchema).default({}), + policies: record(string(), policy).default({}), _meta: object({ schemas: record(string(), string()), tables: record(string(), string()), @@ -491,6 +498,7 @@ export const pgSchemaSquashed = object({ views: record(string(), view), sequences: record(string(), sequenceSquashed), roles: record(string(), roleSchema).default({}), + policies: record(string(), policy).default({}), }).strict(); export const pgSchemaV3 = pgSchemaInternalV3.merge(schemaHash); @@ -630,7 +638,9 @@ export const PgSquasher = { };${fk.onDelete ?? ''};${fk.schemaTo || 'public'}`; }, squashPolicy: (policy: Policy) => { - return `${policy.name}--${policy.as}--${policy.for}--${policy.to?.join(',')}--${policy.using}--${policy.withCheck}`; + return `${policy.name}--${policy.as}--${policy.for}--${ + policy.to?.join(',') + }--${policy.using}--${policy.withCheck}--${policy.on}`; }, unsquashPolicy: (policy: string): Policy => { const splitted = policy.split('--'); @@ -641,10 +651,11 @@ export const PgSquasher = { to: splitted[3].split(','), using: splitted[4] !== 'undefined' ? splitted[4] : undefined, withCheck: splitted[5] !== 'undefined' ? splitted[5] : undefined, + on: splitted[6] !== 'undefined' ? splitted[6] : undefined, }; }, squashPolicyPush: (policy: Policy) => { - return `${policy.name}--${policy.as}--${policy.for}--${policy.to?.join(',')}`; + return `${policy.name}--${policy.as}--${policy.for}--${policy.to?.join(',')}--${policy.on}`; }, squashPK: (pk: PrimaryKey) => { return `${pk.columns.join(',')};${pk.name}`; @@ -822,6 +833,20 @@ export const squashPgScheme = ( }), ); + const mappedPolicies = Object.fromEntries( + Object.entries(json.policies).map((it) => { + return [ + it[0], + { + name: it[1].name, + values: action === 'push' + ? PgSquasher.squashPolicyPush(it[1]) + : PgSquasher.squashPolicy(it[1]), + }, + ]; + }), + ); + return { version: '7', dialect: json.dialect, @@ -829,6 +854,7 @@ export const squashPgScheme = ( enums: json.enums, schemas: json.schemas, views: json.views, + policies: mappedPolicies, sequences: mappedSequences, roles: json.roles, }; @@ -842,6 +868,8 @@ export const dryPg = pgSchema.parse({ tables: {}, enums: {}, schemas: {}, + policies: {}, + roles: {}, sequences: {}, _meta: { schemas: {}, diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index d8b4682a3..139b8ae7b 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -116,6 +116,8 @@ export const generatePgSnapshot = ( const resultViews: Record = {}; const sequencesToReturn: Record = {}; const rolesToReturn: Record = {}; + // this policies are a separate objects that were linked to a table outside of it + const policiesToReturn: Record = {}; // This object stores unique names for indexes and will be used to detect if you have the same names for indexes // within the same PostgreSQL schema @@ -617,7 +619,11 @@ export const generatePgSnapshot = ( } } - if (result[tableKey].policies[policy.name] !== undefined) { + // add separate policies object, that will be only responsible for policy creation + // but we would need to track if a policy was enabled for a specific table or not + // enable only if jsonStatements for enable rls was not already there + filter it + + if (result[tableKey]?.policies[policy.name] !== undefined || policiesToReturn[policy.name] !== undefined) { console.log( `\n${ withStyle.errorWarning( @@ -634,7 +640,7 @@ export const generatePgSnapshot = ( process.exit(1); } - result[tableKey].policies[policy.name] = { + const mappedPolicy = { name: policy.name, as: policy.as?.toUpperCase() as Policy['as'] ?? 'PERMISSIVE', for: policy.for?.toUpperCase() as Policy['for'] ?? 'ALL', @@ -642,6 +648,15 @@ export const generatePgSnapshot = ( using: is(policy.using, SQL) ? dialect.sqlToQuery(policy.using).sql : undefined, withCheck: is(policy.withCheck, SQL) ? dialect.sqlToQuery(policy.withCheck).sql : undefined, }; + + if (result[tableKey]) { + result[tableKey].policies[policy.name] = mappedPolicy; + } else { + policiesToReturn[policy.name] = { + ...mappedPolicy, + on: `"${tableConfig.schema ?? 'public'}"."${tableConfig.name}"`, + }; + } } for (const sequence of sequences) { @@ -880,6 +895,7 @@ export const generatePgSnapshot = ( schemas: schemasObject, sequences: sequencesToReturn, roles: rolesToReturn, + policies: policiesToReturn, views: resultViews, _meta: { schemas: {}, @@ -1893,6 +1909,7 @@ WHERE schemas: schemasObject, sequences: sequencesToReturn, roles: rolesToReturn, + policies: {}, views: views, _meta: { schemas: {}, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 3818d6ac9..9bee696d5 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -12,7 +12,7 @@ import { union, ZodTypeAny, } from 'zod'; -import { applyJsonDiff, diffColumns, diffPolicies, diffSchemasOrTables } from './jsonDiffer'; +import { applyJsonDiff, diffColumns, diffIndPolicies, diffPolicies, diffSchemasOrTables } from './jsonDiffer'; import { fromJson } from './sqlgenerator'; import { @@ -21,6 +21,7 @@ import { _prepareSqliteAddColumns, JsonAddColumnStatement, JsonAlterCompositePK, + JsonAlterIndPolicyStatement, JsonAlterMySqlViewStatement, JsonAlterPolicyStatement, JsonAlterTableSetSchema, @@ -28,6 +29,7 @@ import { JsonAlterViewStatement, JsonCreateCheckConstraint, JsonCreateCompositePK, + JsonCreateIndPolicyStatement, JsonCreateMySqlViewStatement, JsonCreatePgViewStatement, JsonCreatePolicyStatement, @@ -39,9 +41,11 @@ import { JsonDeleteUniqueConstraint, JsonDisableRLSStatement, JsonDropColumnStatement, + JsonDropIndPolicyStatement, JsonDropPolicyStatement, JsonDropViewStatement, JsonEnableRLSStatement, + JsonIndRenamePolicyStatement, JsonReferenceStatement, JsonRenameColumnStatement, JsonRenamePolicyStatement, @@ -59,12 +63,14 @@ import { prepareAlterCompositePrimaryKeyMySql, prepareAlterCompositePrimaryKeyPg, prepareAlterCompositePrimaryKeySqlite, + prepareAlterIndPolicyJson, prepareAlterPolicyJson, prepareAlterReferencesJson, prepareAlterRoleJson, prepareAlterSequenceJson, prepareCreateEnumJson, prepareCreateIndexesJson, + prepareCreateIndPolicyJsons, prepareCreatePolicyJsons, prepareCreateReferencesJson, prepareCreateRoleJson, @@ -79,6 +85,7 @@ import { prepareDropEnumJson, prepareDropEnumValues, prepareDropIndexesJson, + prepareDropIndPolicyJsons, prepareDropPolicyJsons, prepareDropReferencesJson, prepareDropRoleJson, @@ -103,6 +110,7 @@ import { preparePgCreateViewJson, prepareRenameColumns, prepareRenameEnumJson, + prepareRenameIndPolicyJsons, prepareRenamePolicyJsons, prepareRenameRoleJson, prepareRenameSchemasJson, @@ -123,6 +131,8 @@ import { PgSchemaSquashed, PgSquasher, Policy, + policy, + policySquashed, Role, roleSchema, sequenceSquashed, @@ -374,6 +384,7 @@ export const diffResultScheme = object({ alteredEnums: changedEnumSchema.array(), alteredSequences: sequenceSquashed.array(), alteredRoles: roleSchema.array(), + alteredPolicies: policySquashed.array(), alteredViews: alteredPgViewSchema.array(), }).strict(); @@ -424,6 +435,32 @@ export interface ColumnsResolverInput { deleted: T[]; } +export interface TablePolicyResolverInput { + tableName: string; + schema: string; + created: T[]; + deleted: T[]; +} + +export interface TablePolicyResolverOutput { + tableName: string; + schema: string; + created: T[]; + renamed: { from: T; to: T }[]; + deleted: T[]; +} + +export interface PolicyResolverInput { + created: T[]; + deleted: T[]; +} + +export interface PolicyResolverOutput { + created: T[]; + renamed: { from: T; to: T }[]; + deleted: T[]; +} + export interface RolesResolverInput { created: T[]; deleted: T[]; @@ -524,8 +561,11 @@ export const applyPgSnapshotsDiff = async ( input: ResolverInput, ) => Promise>, policyResolver: ( - input: ColumnsResolverInput, - ) => Promise>, + input: TablePolicyResolverInput, + ) => Promise>, + indPolicyResolver: ( + input: PolicyResolverInput, + ) => Promise>, roleResolver: ( input: RolesResolverInput, ) => Promise>, @@ -1015,8 +1055,69 @@ export const applyPgSnapshotsDiff = async ( }, ); + //// Individual policies + + const indPolicyRes = diffIndPolicies(policyPatchedSnap1.policies, json2.policies); + + const indPolicyCreates = [] as { + policies: Policy[]; + }[]; + + const indPolicyDeletes = [] as { + policies: Policy[]; + }[]; + + const { renamed: indPolicyRenames, created, deleted } = await indPolicyResolver({ + deleted: indPolicyRes.deleted.map((t) => PgSquasher.unsquashPolicy(t.values)), + created: indPolicyRes.added.map((t) => PgSquasher.unsquashPolicy(t.values)), + }); + + if (created.length > 0) { + indPolicyCreates.push({ + policies: created, + }); + } + + if (deleted.length > 0) { + indPolicyDeletes.push({ + policies: deleted, + }); + } + + const indPolicyRenamesDict = indPolicyRenames.reduce( + (acc, it) => { + acc[it.from.name] = { + nameFrom: it.from.name, + nameTo: it.to.name, + }; + return acc; + }, + {} as Record< + string, + { + nameFrom: string; + nameTo: string; + } + >, + ); + + const indPolicyPatchedSnap1 = copy(policyPatchedSnap1); + indPolicyPatchedSnap1.policies = mapEntries( + indPolicyPatchedSnap1.policies, + (policyKey, policyValue) => { + const key = policyKey; + const change = indPolicyRenamesDict[key]; + + if (change) { + policyValue.name = change.nameTo; + } + + return [policyKey, policyValue]; + }, + ); + //// - const viewsDiff = diffSchemasOrTables(policyPatchedSnap1.views, json2.views); + const viewsDiff = diffSchemasOrTables(indPolicyPatchedSnap1.views, json2.views); const { created: createdViews, @@ -1287,9 +1388,83 @@ export const applyPgSnapshotsDiff = async ( const jsonAlterPoliciesStatements: JsonAlterPolicyStatement[] = []; const jsonRenamePoliciesStatements: JsonRenamePolicyStatement[] = []; + const jsonRenameIndPoliciesStatements: JsonIndRenamePolicyStatement[] = []; + const jsonCreateIndPoliciesStatements: JsonCreateIndPolicyStatement[] = []; + const jsonDropIndPoliciesStatements: JsonDropIndPolicyStatement[] = []; + const jsonAlterIndPoliciesStatements: JsonAlterIndPolicyStatement[] = []; + const jsonEnableRLSStatements: JsonEnableRLSStatement[] = []; const jsonDisableRLSStatements: JsonDisableRLSStatement[] = []; + for (let it of indPolicyRenames) { + jsonRenameIndPoliciesStatements.push( + ...prepareRenameIndPolicyJsons([it]), + ); + } + + for (const it of indPolicyCreates) { + jsonCreateIndPoliciesStatements.push( + ...prepareCreateIndPolicyJsons( + it.policies, + ), + ); + } + + for (const it of indPolicyDeletes) { + jsonDropIndPoliciesStatements.push( + ...prepareDropIndPolicyJsons( + it.policies, + ), + ); + } + + typedResult.alteredPolicies.forEach(({ values }) => { + // return prepareAlterIndPolicyJson(json1.policies[it.name], json2.policies[it.name]); + + const policy = PgSquasher.unsquashPolicy(values); + + const newPolicy = json1.policies[policy.name]; + const oldPolicy = json2.policies[policy.name]; + + if (newPolicy.as !== oldPolicy.as) { + jsonDropIndPoliciesStatements.push( + ...prepareDropIndPolicyJsons( + [oldPolicy], + ), + ); + + jsonCreateIndPoliciesStatements.push( + ...prepareCreateIndPolicyJsons( + [newPolicy], + ), + ); + return; + } + + if (newPolicy.for !== oldPolicy.for) { + jsonDropIndPoliciesStatements.push( + ...prepareDropIndPolicyJsons( + [oldPolicy], + ), + ); + + jsonCreateIndPoliciesStatements.push( + ...prepareCreateIndPolicyJsons( + [newPolicy], + ), + ); + return; + } + + // alter + jsonAlterIndPoliciesStatements.push( + prepareAlterIndPolicyJson( + oldPolicy, + newPolicy, + ), + ); + }); + for (let it of policyRenames) { jsonRenamePoliciesStatements.push( ...prepareRenamePolicyJsons(it.table, it.schema, it.renames), @@ -1378,11 +1553,18 @@ export const applyPgSnapshotsDiff = async ( columnsPatchedSnap1.tables[`${table.schema === '' ? 'public' : table.schema}.${table.name}`]; const policiesInPreviousState = tableInPreviousState ? Object.keys(tableInPreviousState.policies) : []; - if (policiesInPreviousState.length === 0 && policiesInCurrentState.length > 0 && !table.isRLSEnabled) { + // const indPoliciesInCurrentState = Object.keys(table.policies); + // const indPoliciesInPreviousState = Object.keys(columnsPatchedSnap1.policies); + + if ( + (policiesInPreviousState.length === 0 && policiesInCurrentState.length > 0) && !table.isRLSEnabled + ) { jsonEnableRLSStatements.push({ type: 'enable_rls', tableName: table.name, schema: table.schema }); } - if (policiesInPreviousState.length > 0 && policiesInCurrentState.length === 0 && !table.isRLSEnabled) { + if ( + (policiesInPreviousState.length > 0 && policiesInCurrentState.length === 0) && !table.isRLSEnabled + ) { jsonDisableRLSStatements.push({ type: 'disable_rls', tableName: table.name, schema: table.schema }); } @@ -1391,7 +1573,9 @@ export const applyPgSnapshotsDiff = async ( if (table.isRLSEnabled) { // was force enabled jsonEnableRLSStatements.push({ type: 'enable_rls', tableName: table.name, schema: table.schema }); - } else if (!table.isRLSEnabled && policiesInCurrentState.length === 0) { + } else if ( + !table.isRLSEnabled && policiesInCurrentState.length === 0 + ) { // was force disabled jsonDisableRLSStatements.push({ type: 'disable_rls', tableName: table.name, schema: table.schema }); } @@ -1560,7 +1744,6 @@ export const applyPgSnapshotsDiff = async ( .flat() ?? []; //////////// - const createSchemas = prepareCreateSchemasJson( createdSchemas.map((it) => it.name), ); @@ -1795,6 +1978,12 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...jsonDropPoliciesStatements); jsonStatements.push(...jsonCreatePoliciesStatements); jsonStatements.push(...jsonAlterPoliciesStatements); + + jsonStatements.push(...jsonRenameIndPoliciesStatements); + jsonStatements.push(...jsonDropIndPoliciesStatements); + jsonStatements.push(...jsonCreateIndPoliciesStatements); + jsonStatements.push(...jsonAlterIndPoliciesStatements); + jsonStatements.push(...createViews); jsonStatements.push(...dropEnums); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 4b75f4286..da4dcdf56 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -20,6 +20,7 @@ import { JsonAlterColumnSetPrimaryKeyStatement, JsonAlterColumnTypeStatement, JsonAlterCompositePK, + JsonAlterIndPolicyStatement, JsonAlterMySqlViewStatement, JsonAlterPolicyStatement, JsonAlterReferenceStatement, @@ -37,6 +38,7 @@ import { JsonCreateCompositePK, JsonCreateEnumStatement, JsonCreateIndexStatement, + JsonCreateIndPolicyStatement, JsonCreateMySqlViewStatement, JsonCreatePgViewStatement, JsonCreatePolicyStatement, @@ -55,6 +57,7 @@ import { JsonDropColumnStatement, JsonDropEnumStatement, JsonDropIndexStatement, + JsonDropIndPolicyStatement, JsonDropPolicyStatement, JsonDropRoleStatement, JsonDropSequenceStatement, @@ -62,6 +65,7 @@ import { JsonDropValueFromEnumStatement, JsonDropViewStatement, JsonEnableRLSStatement, + JsonIndRenamePolicyStatement, JsonMoveEnumStatement, JsonMoveSequenceStatement, JsonPgCreateIndexStatement, @@ -80,7 +84,7 @@ import { } from './jsonStatements'; import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; -import { PgSquasher } from './serializer/pgSchema'; +import { PgSquasher, policy } from './serializer/pgSchema'; import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; export const pgNativeTypes = new Set([ @@ -290,6 +294,73 @@ class PgAlterPolicyConvertor extends Convertor { } } +//// + +class PgCreateIndPolicyConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_ind_policy' && dialect === 'postgresql'; + } + override convert(statement: JsonCreateIndPolicyStatement): string | string[] { + const policy = statement.data; + + const usingPart = policy.using ? ` USING (${policy.using})` : ''; + + const withCheckPart = policy.withCheck ? ` WITH CHECK (${policy.withCheck})` : ''; + + const policyToPart = policy.to?.map((v) => + ['current_user', 'current_role', 'session_user', 'public'].includes(v) ? v : `"${v}"` + ).join(', '); + + return `CREATE POLICY "${policy.name}" ON ${policy.on} AS ${policy.as?.toUpperCase()} FOR ${policy.for?.toUpperCase()} TO ${policyToPart}${usingPart}${withCheckPart};`; + } +} + +class PgDropIndPolicyConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_ind_policy' && dialect === 'postgresql'; + } + override convert(statement: JsonDropIndPolicyStatement): string | string[] { + const policy = statement.data; + + return `DROP POLICY "${policy.name}" ON ${policy.on} CASCADE;`; + } +} + +class PgRenameIndPolicyConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'rename_ind_policy' && dialect === 'postgresql'; + } + override convert(statement: JsonIndRenamePolicyStatement): string | string[] { + return `ALTER POLICY "${statement.oldName}" ON ${statement.tableKey} RENAME TO "${statement.newName}";`; + } +} + +class PgAlterIndPolicyConvertor extends Convertor { + override can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_ind_policy' && dialect === 'postgresql'; + } + override convert(statement: JsonAlterIndPolicyStatement): string | string[] { + const newPolicy = statement.newData; + const oldPolicy = statement.oldData; + + const usingPart = newPolicy.using + ? ` USING (${newPolicy.using})` + : oldPolicy.using + ? ` USING (${oldPolicy.using})` + : ''; + + const withCheckPart = newPolicy.withCheck + ? ` WITH CHECK (${newPolicy.withCheck})` + : oldPolicy.withCheck + ? ` WITH CHECK (${oldPolicy.withCheck})` + : ''; + + return `ALTER POLICY "${oldPolicy.name}" ON ${oldPolicy.on} TO ${newPolicy.to}${usingPart}${withCheckPart};`; + } +} + +//// + class PgEnableRlsConvertor extends Convertor { override can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'enable_rls' && dialect === 'postgresql'; @@ -3202,6 +3273,12 @@ convertors.push(new PgAlterPolicyConvertor()); convertors.push(new PgCreatePolicyConvertor()); convertors.push(new PgDropPolicyConvertor()); convertors.push(new PgRenamePolicyConvertor()); + +convertors.push(new PgAlterIndPolicyConvertor()); +convertors.push(new PgCreateIndPolicyConvertor()); +convertors.push(new PgDropIndPolicyConvertor()); +convertors.push(new PgRenameIndPolicyConvertor()); + convertors.push(new PgEnableRlsConvertor()); convertors.push(new PgDisableRlsConvertor()); diff --git a/drizzle-kit/tests/cli-push.test.ts b/drizzle-kit/tests/cli-push.test.ts index e6f26eeb5..f5daf2bd0 100644 --- a/drizzle-kit/tests/cli-push.test.ts +++ b/drizzle-kit/tests/cli-push.test.ts @@ -25,6 +25,7 @@ test('push #1', async (t) => { schemaPath: './schema.ts', schemasFilter: ['public'], tablesFilter: [], + entities: undefined, strict: false, verbose: false, casing: undefined, @@ -87,6 +88,7 @@ test('push #4', async (t) => { schemaPath: './schema.ts', schemasFilter: ['public'], tablesFilter: [], + entities: undefined, strict: false, verbose: false, casing: undefined, @@ -110,6 +112,7 @@ test('push #5', async (t) => { schemasFilter: ['public'], tablesFilter: [], strict: false, + entities: undefined, force: false, verbose: false, casing: undefined, diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index bd4b2840d..67743d2ef 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -2756,6 +2756,7 @@ test('add policy', async () => { for: 'ALL', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -2812,6 +2813,7 @@ test('drop policy', async () => { as: 'PERMISSIVE', for: 'ALL', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -2867,6 +2869,7 @@ test('add policy without enable rls', async () => { for: 'ALL', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -2920,6 +2923,7 @@ test('drop policy without disable rls', async () => { for: 'ALL', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -2969,8 +2973,8 @@ test('alter policy without recreation: changing roles', async (t) => { ]); expect(statements).toStrictEqual([ { - newData: 'test--PERMISSIVE--ALL--current_role', - oldData: 'test--PERMISSIVE--ALL--public', + newData: 'test--PERMISSIVE--ALL--current_role--undefined', + oldData: 'test--PERMISSIVE--ALL--public--undefined', schema: '', tableName: 'users', type: 'alter_policy', @@ -3093,6 +3097,7 @@ test('alter policy with recreation: changing as', async (t) => { for: 'ALL', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -3106,6 +3111,7 @@ test('alter policy with recreation: changing as', async (t) => { for: 'ALL', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -3159,6 +3165,7 @@ test('alter policy with recreation: changing for', async (t) => { for: 'ALL', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -3173,6 +3180,7 @@ test('alter policy with recreation: changing for', async (t) => { name: 'test', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -3226,6 +3234,7 @@ test('alter policy with recreation: changing both "as" and "for"', async (t) => name: 'test', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -3239,6 +3248,7 @@ test('alter policy with recreation: changing both "as" and "for"', async (t) => name: 'test', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -3292,6 +3302,7 @@ test('alter policy with recreation: changing all fields', async (t) => { name: 'test', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -3304,6 +3315,7 @@ test('alter policy with recreation: changing all fields', async (t) => { for: 'ALL', name: 'test', to: ['current_role'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -3463,7 +3475,7 @@ test('create table with a policy', async (t) => { isRLSEnabled: false, compositePkName: '', policies: [ - 'test--PERMISSIVE--ALL--public', + 'test--PERMISSIVE--ALL--public--undefined', ], schema: '', tableName: 'users2', @@ -3479,6 +3491,7 @@ test('create table with a policy', async (t) => { 'public', ], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -3521,7 +3534,7 @@ test('drop table with a policy', async (t) => { expect(statements).toStrictEqual([ { policies: [ - 'test--PERMISSIVE--ALL--public', + 'test--PERMISSIVE--ALL--public--undefined', ], schema: '', tableName: 'users2', @@ -3580,6 +3593,7 @@ test('add policy with multiple "to" roles', async (t) => { as: 'PERMISSIVE', for: 'ALL', name: 'test', + on: undefined, to: ['current_role', 'manager'], using: undefined, withCheck: undefined, diff --git a/drizzle-kit/tests/rls/pg-policy.test.ts b/drizzle-kit/tests/rls/pg-policy.test.ts index 42f7c99f2..b93ab3c2f 100644 --- a/drizzle-kit/tests/rls/pg-policy.test.ts +++ b/drizzle-kit/tests/rls/pg-policy.test.ts @@ -1,5 +1,5 @@ import { sql } from 'drizzle-orm'; -import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core'; +import { integer, pgPolicy, pgRole, pgSchema, pgTable } from 'drizzle-orm/pg-core'; import { diffTestSchemas } from 'tests/schemaDiffer'; import { expect, test } from 'vitest'; @@ -36,6 +36,7 @@ test('add policy + enable rls', async (t) => { for: 'ALL', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -79,6 +80,7 @@ test('drop policy + disable rls', async (t) => { for: 'ALL', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -119,6 +121,7 @@ test('add policy without enable rls', async (t) => { for: 'ALL', name: 'newRls', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -160,6 +163,7 @@ test('drop policy without disable rls', async (t) => { name: 'oldRls', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -193,8 +197,8 @@ test('alter policy without recreation: changing roles', async (t) => { ]); expect(statements).toStrictEqual([ { - newData: 'test--PERMISSIVE--ALL--current_role--undefined--undefined', - oldData: 'test--PERMISSIVE--ALL--public--undefined--undefined', + newData: 'test--PERMISSIVE--ALL--current_role--undefined--undefined--undefined', + oldData: 'test--PERMISSIVE--ALL--public--undefined--undefined--undefined', schema: '', tableName: 'users', type: 'alter_policy', @@ -226,8 +230,8 @@ test('alter policy without recreation: changing using', async (t) => { ]); expect(statements).toStrictEqual([ { - newData: 'test--PERMISSIVE--ALL--public--true--undefined', - oldData: 'test--PERMISSIVE--ALL--public--undefined--undefined', + newData: 'test--PERMISSIVE--ALL--public--true--undefined--undefined', + oldData: 'test--PERMISSIVE--ALL--public--undefined--undefined--undefined', schema: '', tableName: 'users', type: 'alter_policy', @@ -259,8 +263,8 @@ test('alter policy without recreation: changing with check', async (t) => { ]); expect(statements).toStrictEqual([ { - newData: 'test--PERMISSIVE--ALL--public--undefined--true', - oldData: 'test--PERMISSIVE--ALL--public--undefined--undefined', + newData: 'test--PERMISSIVE--ALL--public--undefined--true--undefined', + oldData: 'test--PERMISSIVE--ALL--public--undefined--undefined--undefined', schema: '', tableName: 'users', type: 'alter_policy', @@ -301,6 +305,7 @@ test('alter policy with recreation: changing as', async (t) => { name: 'test', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -313,6 +318,7 @@ test('alter policy with recreation: changing as', async (t) => { for: 'ALL', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -353,6 +359,7 @@ test('alter policy with recreation: changing for', async (t) => { for: 'ALL', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -366,6 +373,7 @@ test('alter policy with recreation: changing for', async (t) => { for: 'DELETE', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -407,6 +415,7 @@ test('alter policy with recreation: changing both "as" and "for"', async (t) => name: 'test', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -420,6 +429,7 @@ test('alter policy with recreation: changing both "as" and "for"', async (t) => name: 'test', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -460,6 +470,7 @@ test('alter policy with recreation: changing all fields', async (t) => { name: 'test', to: ['public'], using: 'true', + on: undefined, withCheck: undefined, }, schema: '', @@ -471,6 +482,7 @@ test('alter policy with recreation: changing all fields', async (t) => { as: 'RESTRICTIVE', for: 'ALL', name: 'test', + on: undefined, to: ['current_role'], using: undefined, withCheck: 'true', @@ -593,7 +605,7 @@ test('create table with a policy', async (t) => { checkConstraints: [], compositePkName: '', policies: [ - 'test--PERMISSIVE--ALL--public--undefined--undefined', + 'test--PERMISSIVE--ALL--public--undefined--undefined--undefined', ], schema: '', tableName: 'users2', @@ -609,6 +621,7 @@ test('create table with a policy', async (t) => { to: [ 'public', ], + on: undefined, using: undefined, withCheck: undefined, }, @@ -639,7 +652,7 @@ test('drop table with a policy', async (t) => { expect(statements).toStrictEqual([ { policies: [ - 'test--PERMISSIVE--ALL--public--undefined--undefined', + 'test--PERMISSIVE--ALL--public--undefined--undefined--undefined', ], schema: '', tableName: 'users2', @@ -683,6 +696,7 @@ test('add policy with multiple "to" roles', async (t) => { as: 'PERMISSIVE', for: 'ALL', name: 'test', + on: undefined, to: ['current_role', 'manager'], using: undefined, withCheck: undefined, @@ -834,6 +848,7 @@ test('add policy + link table', async (t) => { for: 'ALL', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -879,6 +894,7 @@ test('link table', async (t) => { for: 'ALL', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -922,6 +938,7 @@ test('unlink table', async (t) => { for: 'ALL', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -964,6 +981,7 @@ test('drop policy with link', async (t) => { for: 'ALL', name: 'test', to: ['public'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -1010,6 +1028,7 @@ test('add policy in table and with link table', async (t) => { for: 'ALL', name: 'test1', to: ['current_user'], + on: undefined, using: undefined, withCheck: undefined, }, @@ -1024,6 +1043,7 @@ test('add policy in table and with link table', async (t) => { name: 'test', to: ['public'], using: undefined, + on: undefined, withCheck: undefined, }, schema: '', @@ -1032,3 +1052,241 @@ test('add policy in table and with link table', async (t) => { }, ]); }); + +test('link non-schema table', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = {}; + + const schema2 = { + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE POLICY "test" ON "public"."users" AS PERMISSIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + on: '"public"."users"', + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + tableName: '"public"."users"', + type: 'create_ind_policy', + }, + ]); +}); + +test('unlink non-schema table', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const schema2 = { + rls: pgPolicy('test', { as: 'permissive' }), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "public"."users" CASCADE;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + on: '"public"."users"', + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + tableName: '"public"."users"', + type: 'drop_ind_policy', + }, + ]); +}); + +test('add policy + link non-schema table', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + + const cities = pgTable('cities', { + id: integer('id').primaryKey(), + }); + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, (t) => [ + pgPolicy('test2'), + ]), + rls: pgPolicy('test', { as: 'permissive' }).link(cities), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;', + 'CREATE POLICY "test2" ON "users" AS PERMISSIVE FOR ALL TO public;', + 'CREATE POLICY "test" ON "public"."cities" AS PERMISSIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + schema: '', + tableName: 'users', + type: 'enable_rls', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test2', + on: undefined, + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + on: '"public"."cities"', + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + tableName: '"public"."cities"', + type: 'create_ind_policy', + }, + ]); +}); + +test('add policy + link non-schema table from auth schema', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }), + }; + + const authSchema = pgSchema('auth'); + + const cities = authSchema.table('cities', { + id: integer('id').primaryKey(), + }); + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, (t) => [ + pgPolicy('test2'), + ]), + rls: pgPolicy('test', { as: 'permissive' }).link(cities), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;', + 'CREATE POLICY "test2" ON "users" AS PERMISSIVE FOR ALL TO public;', + 'CREATE POLICY "test" ON "auth"."cities" AS PERMISSIVE FOR ALL TO public;', + ]); + expect(statements).toStrictEqual([ + { + schema: '', + tableName: 'users', + type: 'enable_rls', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test2', + on: undefined, + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + { + data: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + on: '"auth"."cities"', + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + tableName: '"auth"."cities"', + type: 'create_ind_policy', + }, + ]); +}); + +test('rename policy that is linked', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const schema2 = { + rls: pgPolicy('newName', { as: 'permissive' }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, [ + '"public"."users".test->"public"."users".newName', + ]); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "public"."users" RENAME TO "newName";', + ]); + expect(statements).toStrictEqual([ + { + newName: 'newName', + oldName: 'test', + tableKey: '"public"."users"', + type: 'rename_ind_policy', + }, + ]); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 6453378e9..441318767 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -25,6 +25,7 @@ import { libSqlLogSuggestionsAndReturn } from 'src/cli/commands/libSqlPushUtils' import { columnsResolver, enumsResolver, + indPolicyResolver, mySqlViewsResolver, Named, policyResolver, @@ -62,6 +63,8 @@ import { ColumnsResolverInput, ColumnsResolverOutput, Enum, + PolicyResolverInput, + PolicyResolverOutput, ResolverInput, ResolverOutput, ResolverOutputWithMoved, @@ -69,6 +72,8 @@ import { RolesResolverOutput, Sequence, Table, + TablePolicyResolverInput, + TablePolicyResolverOutput, } from 'src/snapshotsDiffer'; export type PostgresSchema = Record< @@ -403,8 +408,8 @@ export const testColumnsResolver = export const testPolicyResolver = (renames: Set) => async ( - input: ColumnsResolverInput, -): Promise> => { + input: TablePolicyResolverInput, +): Promise> => { try { if ( input.created.length === 0 @@ -465,6 +470,64 @@ async ( } }; +export const testIndPolicyResolver = (renames: Set) => +async ( + input: PolicyResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + renamed: [], + deleted: input.deleted, + }; + } + + let createdPolicies = [...input.created]; + let deletedPolicies = [...input.deleted]; + + const renamed: { from: Policy; to: Policy }[] = []; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedPolicies.findIndex((it) => { + return `${it.on}.${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdPolicies.findIndex((it) => { + return `${it.on}.${it.name}` === to; + }); + + renamed.push({ + from: deletedPolicies[idxFrom], + to: createdPolicies[idxTo], + }); + + delete createdPolicies[idxTo]; + delete deletedPolicies[idxFrom]; + + createdPolicies = createdPolicies.filter(Boolean); + deletedPolicies = deletedPolicies.filter(Boolean); + } + } + + return { + created: createdPolicies, + deleted: deletedPolicies, + renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; + export const testRolesResolver = (renames: Set) => async ( input: RolesResolverInput, @@ -850,6 +913,7 @@ export const diffTestSchemasPush = async ( testEnumsResolver(renames), testSequencesResolver(renames), testPolicyResolver(renames), + testIndPolicyResolver(renames), testRolesResolver(renames), testTablesResolver(renames), testColumnsResolver(renames), @@ -896,6 +960,7 @@ export const diffTestSchemasPush = async ( enumsResolver, sequencesResolver, policyResolver, + indPolicyResolver, roleResolver, tablesResolver, columnsResolver, @@ -919,6 +984,7 @@ export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | unde views: {}, schemas: {}, sequences: {}, + policies: {}, roles: {}, _meta: { schemas: {}, @@ -977,6 +1043,7 @@ export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | unde testEnumsResolver(new Set()), testSequencesResolver(new Set()), testPolicyResolver(new Set()), + testIndPolicyResolver(new Set()), testRolesResolver(new Set()), testTablesResolver(new Set()), testColumnsResolver(new Set()), @@ -1084,6 +1151,7 @@ export const diffTestSchemas = async ( testEnumsResolver(renames), testSequencesResolver(renames), testPolicyResolver(renames), + testIndPolicyResolver(renames), testRolesResolver(renames), testTablesResolver(renames), testColumnsResolver(renames), @@ -1100,6 +1168,7 @@ export const diffTestSchemas = async ( enumsResolver, sequencesResolver, policyResolver, + indPolicyResolver, roleResolver, tablesResolver, columnsResolver, @@ -1874,6 +1943,7 @@ export const introspectPgToFile = async ( testEnumsResolver(new Set()), testSequencesResolver(new Set()), testPolicyResolver(new Set()), + testIndPolicyResolver(new Set()), testRolesResolver(new Set()), testTablesResolver(new Set()), testColumnsResolver(new Set()), From 911d59cfac90ec1a061bb44e06e5d1fa775e38c5 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 28 Oct 2024 17:21:48 +0200 Subject: [PATCH 266/492] Fix to parsing and entities enabled by default --- drizzle-kit/src/cli/commands/pgIntrospect.ts | 2 +- drizzle-kit/src/serializer/pgSerializer.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drizzle-kit/src/cli/commands/pgIntrospect.ts b/drizzle-kit/src/cli/commands/pgIntrospect.ts index 020ed031b..2d3fd75ce 100644 --- a/drizzle-kit/src/cli/commands/pgIntrospect.ts +++ b/drizzle-kit/src/cli/commands/pgIntrospect.ts @@ -11,7 +11,7 @@ export const pgPushIntrospect = async ( db: DB, filters: string[], schemaFilters: string[], - entities: Entities = { roles: true }, + entities: Entities, ) => { const matchers = filters.map((it) => { return new Minimatch(it); diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 139b8ae7b..6b4ee9c11 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -1148,7 +1148,7 @@ WHERE tablename: string; name: string; as: string; - to: string[]; + to: string; for: string; using: string; withCheck: string; @@ -1161,7 +1161,7 @@ WHERE const { tablename, schemaname, to, withCheck, using, ...rest } = dbPolicy; const tableForPolicy = policiesByTable[`${schemaname}.${tablename}`]; - const parsedTo = to; + const parsedTo = to.slice(1, -1).split(','); const parsedWithCheck = withCheck === null ? undefined : withCheck; const parsedUsing = using === null ? undefined : using; From 26ac00ef54e1e07b806981be2f886e91dd09de8e Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 28 Oct 2024 17:52:14 +0200 Subject: [PATCH 267/492] Fix api api --- drizzle-kit/src/api.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 4392c7214..83b7139ad 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -116,6 +116,7 @@ export const pushSchema = async ( db, [], schemaFilters ?? ['public'], + undefined, ); const validatedPrev = pgSchema.parse(prev); From a2bc6f2122876e3101241bb8c17d682d43793591 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 28 Oct 2024 23:07:38 +0200 Subject: [PATCH 268/492] fix ts errors and update fromDatabase in policy roles update supabase functions --- drizzle-kit/.gitignore | 1 + drizzle-kit/package.json | 8 +- drizzle-kit/src/cli/commands/mysqlUp.ts | 1 + drizzle-kit/src/cli/commands/pgUp.ts | 5 +- drizzle-kit/src/cli/commands/sqliteUp.ts | 1 + drizzle-kit/src/cli/connections.ts | 14 +- drizzle-kit/src/serializer/pgSerializer.ts | 2 +- drizzle-kit/tests/testmysql.ts | 27 --- drizzle-kit/tests/testsqlite.ts | 19 -- drizzle-kit/tsconfig.build.json | 4 + drizzle-orm/src/supabase/rls.ts | 4 +- pnpm-lock.yaml | 218 ++++++++++----------- 12 files changed, 128 insertions(+), 176 deletions(-) delete mode 100644 drizzle-kit/tests/testmysql.ts delete mode 100644 drizzle-kit/tests/testsqlite.ts create mode 100644 drizzle-kit/tsconfig.build.json diff --git a/drizzle-kit/.gitignore b/drizzle-kit/.gitignore index 8d2cf5a81..6269daaf5 100644 --- a/drizzle-kit/.gitignore +++ b/drizzle-kit/.gitignore @@ -13,6 +13,7 @@ !package.json !tsconfig.json !tsconfig.cli-types.json +!tsconfig.build.json !pnpm-lock.yaml !.github !build.ts diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 7499a7ec1..7f682003e 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -34,11 +34,11 @@ "api": "tsx ./dev/api.ts", "migrate:old": "drizzle-kit generate:mysql", "cli": "tsx ./src/cli/index.ts", - "test": "TEST_CONFIG_PATH_PREFIX=./tests/cli/ vitest", + "test": "pnpm tsc && TEST_CONFIG_PATH_PREFIX=./tests/cli/ vitest", "build": "rm -rf ./dist && tsx build.ts && cp package.json dist/ && attw --pack dist", "build:dev": "rm -rf ./dist && tsx build.dev.ts && tsc -p tsconfig.cli-types.json && chmod +x ./dist/index.cjs", "pack": "cp package.json README.md dist/ && (cd dist && npm pack --pack-destination ..) && rm -f package.tgz && mv *.tgz package.tgz", - "tsc": "tsc -p tsconfig.build.json", + "tsc": "tsc -p tsconfig.build.json --noEmit", "publish": "npm publish package.tgz" }, "dependencies": { @@ -103,7 +103,7 @@ "superjson": "^2.2.1", "tsup": "^8.0.2", "tsx": "^3.12.1", - "typescript": "^5.4.3", + "typescript": "^5.6.3", "uuid": "^9.0.1", "vite-tsconfig-paths": "^4.3.2", "vitest": "^1.4.0", @@ -138,4 +138,4 @@ "default": "./api.mjs" } } -} +} \ No newline at end of file diff --git a/drizzle-kit/src/cli/commands/mysqlUp.ts b/drizzle-kit/src/cli/commands/mysqlUp.ts index 6c7d2ebe5..8b467090b 100644 --- a/drizzle-kit/src/cli/commands/mysqlUp.ts +++ b/drizzle-kit/src/cli/commands/mysqlUp.ts @@ -82,6 +82,7 @@ export const upMySqlHandlerV4toV5 = (obj: MySqlSchemaV4): MySqlSchemaV5 => { columns: mappedColumns, compositePrimaryKeys: {}, uniqueConstraints: {}, + checkConstraint: {}, }; } diff --git a/drizzle-kit/src/cli/commands/pgUp.ts b/drizzle-kit/src/cli/commands/pgUp.ts index f3faaeb62..52a2fc4a1 100644 --- a/drizzle-kit/src/cli/commands/pgUp.ts +++ b/drizzle-kit/src/cli/commands/pgUp.ts @@ -93,7 +93,7 @@ export const updateUpToV7 = (json: Record): PgSchema => { return [idx[0], { columns: mappedColumns, with: {}, ...rest }]; }), ); - return [it[0], { ...table, indexes: mappedIndexes }]; + return [it[0], { ...table, indexes: mappedIndexes, policies: {}, isRLSEnabled: false, checkConstraints: {} }]; }), ); @@ -103,6 +103,9 @@ export const updateUpToV7 = (json: Record): PgSchema => { dialect: 'postgresql', sequences: {}, tables: tables, + policies: {}, + views: {}, + roles: {}, }; }; diff --git a/drizzle-kit/src/cli/commands/sqliteUp.ts b/drizzle-kit/src/cli/commands/sqliteUp.ts index b76b9e2cd..aaa1fa7b9 100644 --- a/drizzle-kit/src/cli/commands/sqliteUp.ts +++ b/drizzle-kit/src/cli/commands/sqliteUp.ts @@ -47,5 +47,6 @@ const updateUpToV6 = (json: Record): SQLiteSchema => { version: '6', dialect: 'sqlite', tables: tables, + views: {}, }; }; diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 6c4b44634..a857c78b2 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -57,7 +57,7 @@ export const preparePostgresDB = async ( ); const db = drizzle(rdsClient, config); - const migrateFn = async (config: string | MigrationConfig) => { + const migrateFn = async (config: MigrationConfig) => { return migrate(db, config); }; @@ -164,7 +164,7 @@ export const preparePostgresDB = async ( : new pg.default.Pool({ ...credentials, ssl, max: 1 }); const db = drizzle(client); - const migrateFn = async (config: string | MigrationConfig) => { + const migrateFn = async (config: MigrationConfig) => { return migrate(db, config); }; @@ -199,7 +199,7 @@ export const preparePostgresDB = async ( : postgres.default({ ...credentials, max: 1 }); const db = drizzle(client); - const migrateFn = async (config: string | MigrationConfig) => { + const migrateFn = async (config: MigrationConfig) => { return migrate(db, config); }; @@ -247,7 +247,7 @@ export const preparePostgresDB = async ( await client.connect(); const db = drizzle(client); - const migrateFn = async (config: string | MigrationConfig) => { + const migrateFn = async (config: MigrationConfig) => { return migrate(db, config); }; @@ -299,7 +299,7 @@ export const preparePostgresDB = async ( neonConfig.webSocketConstructor = ws; const db = drizzle(client); - const migrateFn = async (config: string | MigrationConfig) => { + const migrateFn = async (config: MigrationConfig) => { return migrate(db, config); }; @@ -400,13 +400,13 @@ export const connectToMySQL = async ( } if (await checkPackage('@planetscale/database')) { - const { connect } = await import('@planetscale/database'); + const { Client } = await import('@planetscale/database'); const { drizzle } = await import('drizzle-orm/planetscale-serverless'); const { migrate } = await import( 'drizzle-orm/planetscale-serverless/migrator' ); - const connection = connect(result); + const connection = new Client(result); const db = drizzle(connection); const migrateFn = async (config: MigrationConfig) => { diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 6b4ee9c11..c2b9fc0a2 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -1161,7 +1161,7 @@ WHERE const { tablename, schemaname, to, withCheck, using, ...rest } = dbPolicy; const tableForPolicy = policiesByTable[`${schemaname}.${tablename}`]; - const parsedTo = to.slice(1, -1).split(','); + const parsedTo = typeof to === 'string' ? to.slice(1, -1).split(',') : to; const parsedWithCheck = withCheck === null ? undefined : withCheck; const parsedUsing = using === null ? undefined : using; diff --git a/drizzle-kit/tests/testmysql.ts b/drizzle-kit/tests/testmysql.ts deleted file mode 100644 index 092f0a9e1..000000000 --- a/drizzle-kit/tests/testmysql.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { index, mysqlTable, text } from 'drizzle-orm/mysql-core'; -import { diffTestSchemasMysql } from './schemaDiffer'; - -const from = { - users: mysqlTable( - 'table', - { - name: text('name'), - }, - (t) => { - return { - idx: index('name_idx').on(t.name), - }; - }, - ), -}; - -const to = { - users: mysqlTable('table', { - name: text('name'), - }), -}; - -const { statements, sqlStatements } = await diffTestSchemasMysql(from, to, []); - -console.log(statements); -console.log(sqlStatements); diff --git a/drizzle-kit/tests/testsqlite.ts b/drizzle-kit/tests/testsqlite.ts deleted file mode 100644 index e68bbc195..000000000 --- a/drizzle-kit/tests/testsqlite.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { diffTestSchemasMysql, diffTestSchemasSqlite } from './schemaDiffer'; - -const from = { - users: sqliteTable('table', { - password: text('password'), - }), -}; - -const to = { - users: sqliteTable('table1', { - password_hash: text('password_hash'), - }), -}; - -const { statements, sqlStatements } = await diffTestSchemasSqlite(from, to, [], true); - -console.log(statements); -console.log(sqlStatements); diff --git a/drizzle-kit/tsconfig.build.json b/drizzle-kit/tsconfig.build.json new file mode 100644 index 000000000..b57ab6b00 --- /dev/null +++ b/drizzle-kit/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["src"] +} diff --git a/drizzle-orm/src/supabase/rls.ts b/drizzle-orm/src/supabase/rls.ts index 54a326d8a..b4b71504b 100644 --- a/drizzle-orm/src/supabase/rls.ts +++ b/drizzle-orm/src/supabase/rls.ts @@ -29,5 +29,5 @@ export const realtimeMessages = realtime.table( }, ); -export const authUid = sql`(select ${authUsers.id})`; -export const realtimeTopic = sql`${realtimeMessages.topic}`; +export const authUid = sql`(select auth.uid())`; +export const realtimeTopic = sql`realtime.topic()`; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 43c397795..60680eaef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -164,10 +164,10 @@ importers: version: 8.5.11 '@typescript-eslint/eslint-plugin': specifier: ^7.2.0 - version: 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + version: 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^7.2.0 - version: 7.16.1(eslint@8.57.0)(typescript@5.4.5) + version: 7.16.1(eslint@8.57.0)(typescript@5.6.3) '@vercel/postgres': specifier: ^0.8.0 version: 0.8.0 @@ -260,19 +260,19 @@ importers: version: 2.2.1 tsup: specifier: ^8.0.2 - version: 8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.4.5)(yaml@2.4.2) + version: 8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.4.2) tsx: specifier: ^3.12.1 version: 3.14.0 typescript: - specifier: ^5.4.3 - version: 5.4.5 + specifier: ^5.6.3 + version: 5.6.3 uuid: specifier: ^9.0.1 version: 9.0.1 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.4.0 version: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) @@ -314,7 +314,7 @@ importers: version: 0.9.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -362,7 +362,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -4428,6 +4428,7 @@ packages: '@xmldom/xmldom@0.7.13': resolution: {integrity: sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==} engines: {node: '>=10.0.0'} + deprecated: this version is no longer supported, please update to at least 0.8.* '@xmldom/xmldom@0.8.10': resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} @@ -9600,11 +9601,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.6.3: resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} @@ -10344,8 +10340,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10431,11 +10427,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/client-sso-oidc@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10474,7 +10470,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.478.0': @@ -10741,11 +10736,11 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0': + '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10784,6 +10779,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/core@3.477.0': @@ -10938,7 +10934,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -11145,7 +11141,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -11346,7 +11342,7 @@ snapshots: '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11355,7 +11351,7 @@ snapshots: '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -13029,7 +13025,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -13047,7 +13043,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13628,10 +13624,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) '@opentelemetry/api@1.8.0': {} @@ -13768,7 +13764,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -13778,7 +13774,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -13805,14 +13801,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -13901,16 +13897,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -13925,7 +13921,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -13939,7 +13935,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -13962,12 +13958,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) optionalDependencies: '@types/react': 18.3.1 @@ -14919,21 +14915,21 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.6.3) '@typescript-eslint/scope-manager': 7.16.1 - '@typescript-eslint/type-utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/type-utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) '@typescript-eslint/visitor-keys': 7.16.1 eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5 + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -14971,16 +14967,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3)': dependencies: '@typescript-eslint/scope-manager': 7.16.1 '@typescript-eslint/types': 7.16.1 - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) '@typescript-eslint/visitor-keys': 7.16.1 debug: 4.3.4 eslint: 8.57.0 optionalDependencies: - typescript: 5.4.5 + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -15029,15 +15025,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@7.16.1(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/type-utils@7.16.1(eslint@8.57.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) - '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) + '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) debug: 4.3.4 eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5 + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -15091,7 +15087,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.16.1(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@7.16.1(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/visitor-keys': 7.16.1 @@ -15100,9 +15096,9 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.4 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5 + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -15149,12 +15145,12 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@7.16.1(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/utils@7.16.1(eslint@8.57.0)(typescript@5.6.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@typescript-eslint/scope-manager': 7.16.1 '@typescript-eslint/types': 7.16.1 - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) eslint: 8.57.0 transitivePeerDependencies: - supports-color @@ -15277,7 +15273,7 @@ snapshots: pathe: 1.1.2 picocolors: 1.0.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) optional: true '@vitest/ui@1.6.0(vitest@2.1.2)': @@ -17338,35 +17334,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) expo-modules-autolinking@1.11.1: dependencies: @@ -17380,24 +17376,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -18879,12 +18875,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -18960,13 +18956,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -18980,7 +18976,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -19006,7 +19002,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -19014,7 +19010,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -19023,7 +19019,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -19911,10 +19907,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + react-devtools-core@5.2.0(bufferutil@4.0.8): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -19927,19 +19923,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -19958,14 +19954,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + react-devtools-core: 5.2.0(bufferutil@4.0.8) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -20949,9 +20945,9 @@ snapshots: dependencies: typescript: 5.6.3 - ts-api-utils@1.3.0(typescript@5.4.5): + ts-api-utils@1.3.0(typescript@5.6.3): dependencies: - typescript: 5.4.5 + typescript: 5.6.3 ts-expose-internals-conditionally@1.0.0-empty.0: {} @@ -20975,10 +20971,6 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - tsconfck@3.0.3(typescript@5.4.5): - optionalDependencies: - typescript: 5.4.5 - tsconfck@3.0.3(typescript@5.6.3): optionalDependencies: typescript: 5.6.3 @@ -21017,7 +21009,7 @@ snapshots: - supports-color - ts-node - tsup@8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.4.5)(yaml@2.4.2): + tsup@8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.4.2): dependencies: bundle-require: 5.0.0(esbuild@0.23.0) cac: 6.7.14 @@ -21036,7 +21028,7 @@ snapshots: tree-kill: 1.2.2 optionalDependencies: postcss: 8.4.39 - typescript: 5.4.5 + typescript: 5.6.3 transitivePeerDependencies: - jiti - supports-color @@ -21208,8 +21200,6 @@ snapshots: typescript@5.3.3: {} - typescript@5.4.5: {} - typescript@5.6.3: {} ua-parser-js@1.0.38: {} @@ -21431,24 +21421,24 @@ snapshots: - supports-color - terser - vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)): + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5) + tsconfck: 3.0.3(typescript@5.6.3) optionalDependencies: - vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)): + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 tsconfck: 3.0.3(typescript@5.6.3) optionalDependencies: - vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - supports-color - typescript @@ -21885,17 +21875,15 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@6.2.2(bufferutil@4.0.8): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@7.5.9(bufferutil@4.0.8): optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From 255f159e94cebfcedb731180d9637a1d5e84334b Mon Sep 17 00:00:00 2001 From: Roman Nabukhotnyi <97584054+RomanNabukhotnyi@users.noreply.github.com> Date: Mon, 28 Oct 2024 23:16:15 +0200 Subject: [PATCH 269/492] [PG | MySQL]: Fix dates in Drizzle Studio (#2866) * fix: Fix incorrect dates * fix: Fix dates * fix: Fix pg * fix: Fix pglite proxy * fix: Fix CORS error * dprint * fix: FIx orm utils * fix: Fix type overriding --- drizzle-kit/src/cli/connections.ts | 147 +++++++++++++++--- drizzle-kit/src/serializer/index.ts | 32 ---- drizzle-kit/src/serializer/mysqlSerializer.ts | 20 ++- drizzle-kit/src/serializer/pgSerializer.ts | 10 +- .../src/serializer/sqliteSerializer.ts | 6 +- drizzle-kit/src/serializer/studio.ts | 5 +- drizzle-kit/src/serializer/utils.ts | 45 ++++++ drizzle-kit/src/utils.ts | 14 -- 8 files changed, 192 insertions(+), 87 deletions(-) create mode 100644 drizzle-kit/src/serializer/utils.ts diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index a857c78b2..105f3d94f 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -104,7 +104,7 @@ export const preparePostgresDB = async ( if (driver === 'pglite') { assertPackages('@electric-sql/pglite'); - const { PGlite } = await import('@electric-sql/pglite'); + const { PGlite, types } = await import('@electric-sql/pglite'); const { drizzle } = await import('drizzle-orm/pglite'); const { migrate } = await import('drizzle-orm/pglite/migrator'); @@ -115,25 +115,26 @@ export const preparePostgresDB = async ( return migrate(drzl, config); }; + const parsers = { + [types.TIMESTAMP]: (value: any) => value, + [types.TIMESTAMPTZ]: (value: any) => value, + [types.INTERVAL]: (value: any) => value, + [types.DATE]: (value: any) => value, + }; + const query = async (sql: string, params: any[] = []) => { - const result = await pglite.query(sql, params); + const result = await pglite.query(sql, params, { + parsers, + }); return result.rows as T[]; }; const proxy = async (params: ProxyParams) => { const preparedParams = preparePGliteParams(params.params); - if ( - params.method === 'values' - || params.method === 'get' - || params.method === 'all' - ) { - const result = await pglite.query(params.sql, preparedParams, { - rowMode: params.mode, - }); - return result.rows; - } - - const result = await pglite.query(params.sql, preparedParams); + const result = await pglite.query(params.sql, preparedParams, { + rowMode: params.mode, + parsers, + }); return result.rows; }; @@ -145,7 +146,7 @@ export const preparePostgresDB = async ( if (await checkPackage('pg')) { console.log(withStyle.info(`Using 'pg' driver for database querying`)); - const pg = await import('pg'); + const { default: pg } = await import('pg'); const { drizzle } = await import('drizzle-orm/node-postgres'); const { migrate } = await import('drizzle-orm/node-postgres/migrator'); @@ -159,9 +160,30 @@ export const preparePostgresDB = async ( : credentials.ssl : {}; + // Override pg default date parsers + const types: { getTypeParser: typeof pg.types.getTypeParser } = { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === pg.types.builtins.TIMESTAMPTZ) { + return (val) => val; + } + if (typeId === pg.types.builtins.TIMESTAMP) { + return (val) => val; + } + if (typeId === pg.types.builtins.DATE) { + return (val) => val; + } + if (typeId === pg.types.builtins.INTERVAL) { + return (val) => val; + } + // @ts-ignore + return pg.types.getTypeParser(typeId, format); + }, + } + const client = 'url' in credentials - ? new pg.default.Pool({ connectionString: credentials.url, max: 1 }) - : new pg.default.Pool({ ...credentials, ssl, max: 1 }); + ? new pg.Pool({ connectionString: credentials.url, max: 1 }) + : new pg.Pool({ ...credentials, ssl, max: 1 }); const db = drizzle(client); const migrateFn = async (config: MigrationConfig) => { @@ -169,7 +191,11 @@ export const preparePostgresDB = async ( }; const query = async (sql: string, params?: any[]) => { - const result = await client.query(sql, params ?? []); + const result = await client.query({ + text: sql, + values: params ?? [], + types, + }); return result.rows; }; @@ -178,6 +204,7 @@ export const preparePostgresDB = async ( text: params.sql, values: params.params, ...(params.mode === 'array' && { rowMode: 'array' }), + types, }); return result.rows; }; @@ -198,6 +225,16 @@ export const preparePostgresDB = async ( ? postgres.default(credentials.url, { max: 1 }) : postgres.default({ ...credentials, max: 1 }); + const transparentParser = (val: any) => val; + + // Override postgres.js default date parsers: https://github.com/porsager/postgres/discussions/761 + for (const type of ['1184', '1082', '1083', '1114']) { + client.options.parsers[type as any] = transparentParser; + client.options.serializers[type as any] = transparentParser; + } + client.options.serializers['114'] = transparentParser; + client.options.serializers['3802'] = transparentParser; + const db = drizzle(client); const migrateFn = async (config: MigrationConfig) => { return migrate(db, config); @@ -227,7 +264,7 @@ export const preparePostgresDB = async ( "'@vercel/postgres' can only connect to remote Neon/Vercel Postgres/Supabase instances through a websocket", ), ); - const { VercelPool } = await import('@vercel/postgres'); + const { VercelPool, types: pgTypes } = await import('@vercel/postgres'); const { drizzle } = await import('drizzle-orm/vercel-postgres'); const { migrate } = await import('drizzle-orm/vercel-postgres/migrator'); const ssl = 'ssl' in credentials @@ -240,6 +277,27 @@ export const preparePostgresDB = async ( : credentials.ssl : {}; + // Override @vercel/postgres default date parsers + const types: { getTypeParser: typeof pgTypes.getTypeParser } = { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === pgTypes.builtins.TIMESTAMPTZ) { + return (val: any) => val; + } + if (typeId === pgTypes.builtins.TIMESTAMP) { + return (val: any) => val; + } + if (typeId === pgTypes.builtins.DATE) { + return (val: any) => val; + } + if (typeId === pgTypes.builtins.INTERVAL) { + return (val: any) => val; + } + // @ts-ignore + return pgTypes.getTypeParser(typeId, format); + }, + } + const client = 'url' in credentials ? new VercelPool({ connectionString: credentials.url }) : new VercelPool({ ...credentials, ssl }); @@ -252,7 +310,11 @@ export const preparePostgresDB = async ( }; const query = async (sql: string, params?: any[]) => { - const result = await client.query(sql, params ?? []); + const result = await client.query({ + text: sql, + values: params ?? [], + types, + }); return result.rows; }; @@ -261,6 +323,7 @@ export const preparePostgresDB = async ( text: params.sql, values: params.params, ...(params.mode === 'array' && { rowMode: 'array' }), + types, }); return result.rows; }; @@ -279,7 +342,7 @@ export const preparePostgresDB = async ( "'@neondatabase/serverless' can only connect to remote Neon/Vercel Postgres/Supabase instances through a websocket", ), ); - const { Pool, neonConfig } = await import('@neondatabase/serverless'); + const { Pool, neonConfig, types: pgTypes } = await import('@neondatabase/serverless'); const { drizzle } = await import('drizzle-orm/neon-serverless'); const { migrate } = await import('drizzle-orm/neon-serverless/migrator'); @@ -293,6 +356,27 @@ export const preparePostgresDB = async ( : credentials.ssl : {}; + // Override @neondatabase/serverless default date parsers + const types: { getTypeParser: typeof pgTypes.getTypeParser } = { + // @ts-ignore + getTypeParser: (typeId, format) => { + if (typeId === pgTypes.builtins.TIMESTAMPTZ) { + return (val: any) => val; + } + if (typeId === pgTypes.builtins.TIMESTAMP) { + return (val: any) => val; + } + if (typeId === pgTypes.builtins.DATE) { + return (val: any) => val; + } + if (typeId === pgTypes.builtins.INTERVAL) { + return (val: any) => val; + } + // @ts-ignore + return pgTypes.getTypeParser(typeId, format); + }, + } + const client = 'url' in credentials ? new Pool({ connectionString: credentials.url, max: 1 }) : new Pool({ ...credentials, max: 1, ssl }); @@ -304,7 +388,11 @@ export const preparePostgresDB = async ( }; const query = async (sql: string, params?: any[]) => { - const result = await client.query(sql, params ?? []); + const result = await client.query({ + text: sql, + values: params ?? [], + types, + }); return result.rows; }; @@ -313,6 +401,7 @@ export const preparePostgresDB = async ( text: params.sql, values: params.params, ...(params.mode === 'array' && { rowMode: 'array' }), + types, }); return result.rows; }; @@ -373,12 +462,23 @@ export const connectToMySQL = async ( return migrate(db, config); }; + const typeCast = (field: any, next: any) => { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }; + await connection.connect(); const query: DB['query'] = async ( sql: string, params?: any[], ): Promise => { - const res = await connection.execute(sql, params); + const res = await connection.execute({ + sql, + values: params, + typeCast, + }); return res[0] as any; }; @@ -387,6 +487,7 @@ export const connectToMySQL = async ( sql: params.sql, values: params.params, rowsAsArray: params.mode === 'array', + typeCast, }); return result[0] as any[]; }; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index d76ea424f..cf2ee625a 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -1,6 +1,4 @@ import chalk from 'chalk'; -import { SQL, Table } from 'drizzle-orm'; -import { CasingCache } from 'drizzle-orm/casing'; import fs from 'fs'; import * as glob from 'glob'; import Path from 'path'; @@ -10,36 +8,6 @@ import type { MySqlSchemaInternal } from './mysqlSchema'; import type { PgSchemaInternal } from './pgSchema'; import type { SQLiteSchemaInternal } from './sqliteSchema'; -export const sqlToStr = (sql: SQL, casing: CasingType | undefined) => { - return sql.toQuery({ - escapeName: () => { - throw new Error("we don't support params for `sql` default values"); - }, - escapeParam: () => { - throw new Error("we don't support params for `sql` default values"); - }, - escapeString: () => { - throw new Error("we don't support params for `sql` default values"); - }, - casing: new CasingCache(casing), - }).sql; -}; - -export const sqlToStrGenerated = (sql: SQL, casing: CasingType | undefined) => { - return sql.toQuery({ - escapeName: () => { - throw new Error("we don't support params for `sql` default values"); - }, - escapeParam: () => { - throw new Error("we don't support params for `sql` default values"); - }, - escapeString: () => { - throw new Error("we don't support params for `sql` default values"); - }, - casing: new CasingCache(casing), - }).sql; -}; - export const serializeMySql = async ( path: string | string[], casing: CasingType | undefined, diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 5ac717525..f7fa7f3f0 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -1,9 +1,15 @@ import chalk from 'chalk'; -import { getTableName, is } from 'drizzle-orm'; -import { SQL } from 'drizzle-orm'; -import { getViewConfig, MySqlColumn, MySqlView } from 'drizzle-orm/mysql-core'; -import { AnyMySqlTable, MySqlDialect, type PrimaryKey as PrimaryKeyORM, uniqueKeyName } from 'drizzle-orm/mysql-core'; -import { getTableConfig } from 'drizzle-orm/mysql-core'; +import { getTableName, is, SQL } from 'drizzle-orm'; +import { + AnyMySqlTable, + getTableConfig, + getViewConfig, + MySqlColumn, + MySqlDialect, + MySqlView, + type PrimaryKey as PrimaryKeyORM, + uniqueKeyName, +} from 'drizzle-orm/mysql-core'; import { RowDataPacket } from 'mysql2/promise'; import { CasingType } from 'src/cli/validations/common'; import { withStyle } from '../cli/validations/outputs'; @@ -20,8 +26,8 @@ import { UniqueConstraint, View, } from '../serializer/mysqlSchema'; -import { type DB, getColumnCasing } from '../utils'; -import { sqlToStr } from '.'; +import type { DB } from '../utils'; +import { getColumnCasing, sqlToStr } from './utils'; export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index c2b9fc0a2..c6f6c0391 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -1,10 +1,9 @@ import chalk from 'chalk'; import { getTableName, is, SQL } from 'drizzle-orm'; -import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; import { AnyPgTable, - ExtraConfigColumn, getMaterializedViewConfig, + getTableConfig, getViewConfig, IndexedColumn, PgColumn, @@ -19,14 +18,13 @@ import { PgView, uniqueKeyName, } from 'drizzle-orm/pg-core'; -import { getTableConfig } from 'drizzle-orm/pg-core'; import { CasingType } from 'src/cli/validations/common'; import { vectorOps } from 'src/extensions/vector'; import { withStyle } from '../cli/validations/outputs'; import type { IntrospectStage, IntrospectStatus } from '../cli/views'; import type { CheckConstraint, - Column as Column, + Column, Enum, ForeignKey, Index, @@ -41,8 +39,8 @@ import type { UniqueConstraint, View, } from '../serializer/pgSchema'; -import { type DB, getColumnCasing, isPgArrayType } from '../utils'; -import { sqlToStr } from '.'; +import { type DB, isPgArrayType } from '../utils'; +import { getColumnCasing, sqlToStr } from './utils'; export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 3977705a6..1ba24b69c 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -1,8 +1,6 @@ import chalk from 'chalk'; import { getTableName, is, SQL } from 'drizzle-orm'; -import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; import { - // AnySQLiteColumnBuilder, AnySQLiteTable, getTableConfig, getViewConfig, @@ -27,8 +25,8 @@ import type { UniqueConstraint, View, } from '../serializer/sqliteSchema'; -import { getColumnCasing, type SQLiteDB } from '../utils'; -import { sqlToStr } from '.'; +import type { SQLiteDB } from '../utils'; +import { getColumnCasing, sqlToStr } from './utils'; export const generateSqliteSnapshot = ( tables: AnySQLiteTable[], diff --git a/drizzle-kit/src/serializer/studio.ts b/drizzle-kit/src/serializer/studio.ts index e83bd21a2..d83a65b08 100644 --- a/drizzle-kit/src/serializer/studio.ts +++ b/drizzle-kit/src/serializer/studio.ts @@ -18,6 +18,7 @@ import { AnyPgTable, getTableConfig as pgTableConfig, PgTable } from 'drizzle-or import { AnySQLiteTable, getTableConfig as sqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; import fs from 'fs'; import { Hono } from 'hono'; +import { compress } from 'hono/compress'; import { cors } from 'hono/cors'; import { createServer } from 'node:https'; import { LibSQLCredentials } from 'src/cli/validations/libsql'; @@ -492,12 +493,14 @@ export const prepareServer = async ( ): Promise => { app = app !== undefined ? app : new Hono(); - app.use(cors()); + app.use(compress()); app.use(async (ctx, next) => { await next(); // * https://wicg.github.io/private-network-access/#headers + // * https://github.com/drizzle-team/drizzle-orm/issues/1857#issuecomment-2395724232 ctx.header('Access-Control-Allow-Private-Network', 'true'); }); + app.use(cors()); app.onError((err, ctx) => { console.error(err); return ctx.json({ diff --git a/drizzle-kit/src/serializer/utils.ts b/drizzle-kit/src/serializer/utils.ts new file mode 100644 index 000000000..bac760403 --- /dev/null +++ b/drizzle-kit/src/serializer/utils.ts @@ -0,0 +1,45 @@ +import { CasingCache, toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; +import { CasingType } from '../cli/validations/common'; +import { SQL } from 'drizzle-orm'; + +export function getColumnCasing( + column: { keyAsName: boolean; name: string | undefined }, + casing: CasingType | undefined, +) { + if (!column.name) return ''; + return !column.keyAsName || casing === undefined + ? column.name + : casing === 'camelCase' + ? toCamelCase(column.name) + : toSnakeCase(column.name); +} + +export const sqlToStr = (sql: SQL, casing: CasingType | undefined) => { + return sql.toQuery({ + escapeName: () => { + throw new Error("we don't support params for `sql` default values"); + }, + escapeParam: () => { + throw new Error("we don't support params for `sql` default values"); + }, + escapeString: () => { + throw new Error("we don't support params for `sql` default values"); + }, + casing: new CasingCache(casing), + }).sql; +}; + +export const sqlToStrGenerated = (sql: SQL, casing: CasingType | undefined) => { + return sql.toQuery({ + escapeName: () => { + throw new Error("we don't support params for `sql` default values"); + }, + escapeParam: () => { + throw new Error("we don't support params for `sql` default values"); + }, + escapeString: () => { + throw new Error("we don't support params for `sql` default values"); + }, + casing: new CasingCache(casing), + }).sql; +}; diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index c13467da3..f26624969 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -1,11 +1,9 @@ import type { RunResult } from 'better-sqlite3'; import chalk from 'chalk'; -import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs'; import { join } from 'path'; import { parse } from 'url'; import type { NamedWithSchema } from './cli/commands/migrate'; -import { CasingType } from './cli/validations/common'; import { info } from './cli/views'; import { assertUnreachable, snapshotVersion } from './global'; import type { Dialect } from './schemaValidator'; @@ -358,15 +356,3 @@ export function findAddedAndRemoved(columnNames1: string[], columnNames2: string return { addedColumns, removedColumns }; } - -export function getColumnCasing( - column: { keyAsName: boolean; name: string | undefined }, - casing: CasingType | undefined, -) { - if (!column.name) return ''; - return !column.keyAsName || casing === undefined - ? column.name - : casing === 'camelCase' - ? toCamelCase(column.name) - : toSnakeCase(column.name); -} From 9f627ed12b5458d4df01ae83aadd242df7d3e63f Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 28 Oct 2024 23:19:21 +0200 Subject: [PATCH 270/492] Fix formatting --- drizzle-kit/package.json | 2 +- drizzle-kit/src/cli/connections.ts | 6 +++--- drizzle-kit/src/serializer/utils.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 7f682003e..3d2890b4b 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -138,4 +138,4 @@ "default": "./api.mjs" } } -} \ No newline at end of file +} diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index 105f3d94f..aab1d0ef7 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -179,7 +179,7 @@ export const preparePostgresDB = async ( // @ts-ignore return pg.types.getTypeParser(typeId, format); }, - } + }; const client = 'url' in credentials ? new pg.Pool({ connectionString: credentials.url, max: 1 }) @@ -296,7 +296,7 @@ export const preparePostgresDB = async ( // @ts-ignore return pgTypes.getTypeParser(typeId, format); }, - } + }; const client = 'url' in credentials ? new VercelPool({ connectionString: credentials.url }) @@ -375,7 +375,7 @@ export const preparePostgresDB = async ( // @ts-ignore return pgTypes.getTypeParser(typeId, format); }, - } + }; const client = 'url' in credentials ? new Pool({ connectionString: credentials.url, max: 1 }) diff --git a/drizzle-kit/src/serializer/utils.ts b/drizzle-kit/src/serializer/utils.ts index bac760403..18d5bb9ad 100644 --- a/drizzle-kit/src/serializer/utils.ts +++ b/drizzle-kit/src/serializer/utils.ts @@ -1,6 +1,6 @@ +import { SQL } from 'drizzle-orm'; import { CasingCache, toCamelCase, toSnakeCase } from 'drizzle-orm/casing'; import { CasingType } from '../cli/validations/common'; -import { SQL } from 'drizzle-orm'; export function getColumnCasing( column: { keyAsName: boolean; name: string | undefined }, From 9a8297919ccf5d8b6490f62788fa3d0e7ec8c65e Mon Sep 17 00:00:00 2001 From: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> Date: Tue, 29 Oct 2024 09:58:11 +0200 Subject: [PATCH 271/492] Updated version of `brocli` for improved error messages (#3208) --- drizzle-kit/package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 3d2890b4b..9f1fef0a7 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -42,7 +42,7 @@ "publish": "npm publish package.tgz" }, "dependencies": { - "@drizzle-team/brocli": "^0.10.1", + "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.19.7", "esbuild-register": "^3.5.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 60680eaef..f69f5727f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -87,8 +87,8 @@ importers: drizzle-kit: dependencies: '@drizzle-team/brocli': - specifier: ^0.10.1 - version: 0.10.1 + specifier: ^0.10.2 + version: 0.10.2 '@esbuild-kit/esm-loader': specifier: ^2.5.5 version: 2.5.5 @@ -1990,8 +1990,8 @@ packages: cpu: [x64] os: [win32] - '@drizzle-team/brocli@0.10.1': - resolution: {integrity: sha512-AHy0vjc+n/4w/8Mif+w86qpppHuF3AyXbcWW+R/W7GNA3F5/p2nuhlkCJaTXSLZheB4l1rtHzOfr9A7NwoR/Zg==} + '@drizzle-team/brocli@0.10.2': + resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} '@drizzle-team/studio@0.0.5': resolution: {integrity: sha512-ps5qF0tMxWRVu+V5gvCRrQNqlY92aTnIKdq27gm9LZMSdaKYZt6AVvSK1dlUMzs6Rt0Jm80b+eWct6xShBKhIw==} @@ -12493,7 +12493,7 @@ snapshots: '@dprint/win32-x64@0.46.3': optional: true - '@drizzle-team/brocli@0.10.1': {} + '@drizzle-team/brocli@0.10.2': {} '@drizzle-team/studio@0.0.5': {} @@ -16486,7 +16486,7 @@ snapshots: drizzle-kit@0.25.0-b1faa33: dependencies: - '@drizzle-team/brocli': 0.10.1 + '@drizzle-team/brocli': 0.10.2 '@esbuild-kit/esm-loader': 2.5.5 esbuild: 0.19.12 esbuild-register: 3.5.0(esbuild@0.19.12) From a1e0ae9b564348460a83cdabf57dfcc7cc3e260c Mon Sep 17 00:00:00 2001 From: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> Date: Tue, 29 Oct 2024 09:58:30 +0200 Subject: [PATCH 272/492] Fixed isConfig not detecting function-type drivers in `.client` (#3178) --- drizzle-orm/src/utils.ts | 2 +- .../tests/utils/is-config.test.ts | 194 ++++++++++++++++++ 2 files changed, 195 insertions(+), 1 deletion(-) diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index 8d563d0da..8e1382c7a 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -302,7 +302,7 @@ export function isConfig(data: any): boolean { if ('client' in data) { const type = typeof data['client']; - if (type !== 'object' && type !== 'undefined') return false; + if (type !== 'object' && type !== 'function' && type !== 'undefined') return false; return true; } diff --git a/integration-tests/tests/utils/is-config.test.ts b/integration-tests/tests/utils/is-config.test.ts index e3d8d95e8..a71a753c2 100644 --- a/integration-tests/tests/utils/is-config.test.ts +++ b/integration-tests/tests/utils/is-config.test.ts @@ -298,3 +298,197 @@ describe('Rejects drivers', (it) => { expect(isConfig(cl)).toEqual(false); }); }); + +describe('Accepts drivers in .client', (it) => { + it('libsql', () => { + const cl = libsql({ + url: ':memory:', + }); + + expect(isConfig({ client: cl })).toEqual(true); + }); + + it('better-sqlite3', () => { + const cl = new betterSqlite3(':memory:'); + + expect(isConfig({ client: cl })).toEqual(true); + }); + + it('pglite', () => { + const cl = new pglite('memory://'); + + expect(isConfig({ client: cl })).toEqual(true); + }); + + it('node-postgres:Pool', () => { + const cl = new pg.Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + + expect(isConfig({ client: cl })).toEqual(true); + }); + + it('node-postgres:Client', async () => { + const cl = new pg.Client({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + + const res = isConfig({ client: cl }); + + await cl.end(); + + expect(res).toEqual(true); + }); + + it('node-postgres:PoolClient', async () => { + const cl = new pg.Pool({ + connectionString: process.env['PG_CONNECTION_STRING'], + }); + + const con = await cl.connect(); + + const res = isConfig({ client: con }); + + con.release(); + + expect(res).toEqual(true); + }); + + it('postgres-js', () => { + const cl = postgres(process.env['PG_CONNECTION_STRING']!); + + expect(isConfig({ client: cl })).toEqual(true); + }); + + it('vercel:sql', () => { + expect(isConfig({ client: vcSql })).toEqual(true); + }); + + // it('vercel:Pool', () => { + // const cl = vcPool({ + // connectionString: process.env['VERCEL_CONNECTION_STRING'], + // }); + + // expect(isConfig({client:cl})).toEqual(true); + // }); + + it('vercel:Client', async () => { + const cl = vcClient({ + connectionString: process.env['NEON_CONNECTION_STRING'], + }); + + const res = isConfig({ client: cl }); + + expect(res).toEqual(true); + }); + + // it('vercel:PoolClient', async () => { + // const cl = vcPool({ + // connectionString: process.env['VERCEL_CONNECTION_STRING'], + // }); + + // const con = await cl.connect(); + + // const res = isConfig({ client: con }); + + // con.release(); + + // expect(res).toEqual(true); + // }); + + it('neon-serverless:Pool', async () => { + const cl = new neonPool({ + connectionString: process.env['NEON_CONNECTION_STRING']!, + }); + + expect(isConfig({ client: cl })).toEqual(true); + }); + + it('neon-serverless:Client', async () => { + const cl = new neonClient({ + connectionString: process.env['NEON_CONNECTION_STRING']!, + }); + + const res = isConfig({ client: cl }); + + await cl.end(); + + expect(res).toEqual(true); + }); + + it('neon-serverless:PoolClient', async () => { + const cl = new neonPool({ + connectionString: process.env['NEON_CONNECTION_STRING']!, + }); + + const con = await cl.connect(); + + const res = isConfig({ client: con }); + + con.release(); + + expect(res).toEqual(true); + }); + + it('neon-http', async () => { + const cl = neon(process.env['NEON_CONNECTION_STRING']!); + + expect(isConfig({ client: cl })).toEqual(true); + }); + + it('planetscale', async () => { + const cl = planetscale({ + url: process.env['PLANETSCALE_CONNECTION_STRING'], + }); + + expect(isConfig({ client: cl })).toEqual(true); + }); + + it('mysql2:Pool', async () => { + const cl = ms2Pool({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + expect(isConfig({ client: cl })).toEqual(true); + }); + + it('mysql2:Connection', async () => { + const cl = ms2Connection({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + expect(isConfig({ client: cl })).toEqual(true); + }); + + it('mysql2/promise:Pool', async () => { + const cl = await ms2pPool({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const res = isConfig({ client: cl }); + + await cl.end(); + + expect(res).toEqual(true); + }); + + it('mysql2/promise:Connection', async () => { + const cl = await ms2pConnection({ + uri: process.env['MYSQL_CONNECTION_STRING'], + }); + + const res = isConfig({ client: cl }); + + await cl.end(); + + expect(res).toEqual(true); + }); + + it('tidb', async () => { + const cl = tidb({ + url: process.env['TIDB_CONNECTION_STRING'], + }); + + expect(isConfig({ client: cl })).toEqual(true); + }); +}); From 9a8395aecfe44f1c8027e868e1134369fcb4de2a Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 29 Oct 2024 16:01:11 +0200 Subject: [PATCH 273/492] Fix altering policies --- drizzle-kit/src/cli/utils.ts | 2 +- drizzle-kit/src/serializer/pgSchema.ts | 2 +- drizzle-kit/src/snapshotsDiffer.ts | 4 +- drizzle-kit/tests/rls/pg-policy.test.ts | 366 ++++++++++++++++++++++++ drizzle-orm/src/version.ts | 2 +- 5 files changed, 371 insertions(+), 5 deletions(-) diff --git a/drizzle-kit/src/cli/utils.ts b/drizzle-kit/src/cli/utils.ts index 4f665ec05..a4c28851e 100644 --- a/drizzle-kit/src/cli/utils.ts +++ b/drizzle-kit/src/cli/utils.ts @@ -74,7 +74,7 @@ export const assertEitherPackage = async ( process.exit(1); }; -const requiredApiVersion = 9; +const requiredApiVersion = 10; export const assertOrmCoreVersion = async () => { try { const { compatibilityVersion } = await import('drizzle-orm/version'); diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index 40b02a2d1..50d712dc4 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -498,7 +498,7 @@ export const pgSchemaSquashed = object({ views: record(string(), view), sequences: record(string(), sequenceSquashed), roles: record(string(), roleSchema).default({}), - policies: record(string(), policy).default({}), + policies: record(string(), policySquashed).default({}), }).strict(); export const pgSchemaV3 = pgSchemaInternalV3.merge(schemaHash); diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 9bee696d5..f50ae5f6c 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -1423,8 +1423,8 @@ export const applyPgSnapshotsDiff = async ( const policy = PgSquasher.unsquashPolicy(values); - const newPolicy = json1.policies[policy.name]; - const oldPolicy = json2.policies[policy.name]; + const newPolicy = PgSquasher.unsquashPolicy(json2.policies[policy.name].values); + const oldPolicy = PgSquasher.unsquashPolicy(json1.policies[policy.name].values); if (newPolicy.as !== oldPolicy.as) { jsonDropIndPoliciesStatements.push( diff --git a/drizzle-kit/tests/rls/pg-policy.test.ts b/drizzle-kit/tests/rls/pg-policy.test.ts index b93ab3c2f..b42385e3e 100644 --- a/drizzle-kit/tests/rls/pg-policy.test.ts +++ b/drizzle-kit/tests/rls/pg-policy.test.ts @@ -1290,3 +1290,369 @@ test('rename policy that is linked', async (t) => { }, ]); }); + +test('alter policy that is linked', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const schema2 = { + rls: pgPolicy('test', { as: 'permissive', to: 'current_role' }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "public"."users" TO current_role;', + ]); + expect(statements).toStrictEqual([ + { + newData: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + on: '"public"."users"', + to: [ + 'current_role', + ], + using: undefined, + withCheck: undefined, + }, + oldData: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + on: '"public"."users"', + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + type: 'alter_ind_policy', + }, + ]); +}); + +test('alter policy that is linked: withCheck', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive', withCheck: sql`true` }).link(users), + }; + + const schema2 = { + rls: pgPolicy('test', { as: 'permissive', withCheck: sql`false` }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "public"."users" TO public WITH CHECK (false);', + ]); + expect(statements).toStrictEqual([ + { + newData: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + on: '"public"."users"', + to: [ + 'public', + ], + using: undefined, + withCheck: 'false', + }, + oldData: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + on: '"public"."users"', + to: [ + 'public', + ], + using: undefined, + withCheck: 'true', + }, + type: 'alter_ind_policy', + }, + ]); +}); + +test('alter policy that is linked: using', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive', using: sql`true` }).link(users), + }; + + const schema2 = { + rls: pgPolicy('test', { as: 'permissive', using: sql`false` }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "public"."users" TO public USING (false);', + ]); + expect(statements).toStrictEqual([ + { + newData: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + on: '"public"."users"', + to: [ + 'public', + ], + using: 'false', + withCheck: undefined, + }, + oldData: { + as: 'PERMISSIVE', + for: 'ALL', + name: 'test', + on: '"public"."users"', + to: [ + 'public', + ], + using: 'true', + withCheck: undefined, + }, + type: 'alter_ind_policy', + }, + ]); +}); + +test('alter policy that is linked: using', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = { + rls: pgPolicy('test', { for: 'insert' }).link(users), + }; + + const schema2 = { + rls: pgPolicy('test', { for: 'delete' }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "public"."users" CASCADE;', + 'CREATE POLICY "test" ON "public"."users" AS PERMISSIVE FOR DELETE TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'INSERT', + name: 'test', + on: '"public"."users"', + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + tableName: '"public"."users"', + type: 'drop_ind_policy', + }, + { + data: { + as: 'PERMISSIVE', + for: 'DELETE', + name: 'test', + on: '"public"."users"', + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + tableName: '"public"."users"', + type: 'create_ind_policy', + }, + ]); +}); + +//// + +test('alter policy in the table', async (t) => { + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, (t) => [ + pgPolicy('test', { as: 'permissive' }), + ]), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, (t) => [ + pgPolicy('test', { as: 'permissive', to: 'current_role' }), + ]), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" TO current_role;', + ]); + expect(statements).toStrictEqual([ + { + newData: 'test--PERMISSIVE--ALL--current_role--undefined--undefined--undefined', + oldData: 'test--PERMISSIVE--ALL--public--undefined--undefined--undefined', + schema: '', + tableName: 'users', + type: 'alter_policy', + }, + ]); +}); + +test('alter policy in the table: withCheck', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, (t) => [ + pgPolicy('test', { as: 'permissive', withCheck: sql`true` }), + ]), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, (t) => [ + pgPolicy('test', { as: 'permissive', withCheck: sql`false` }), + ]), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" TO public WITH CHECK (false);', + ]); + expect(statements).toStrictEqual([ + { + newData: 'test--PERMISSIVE--ALL--public--undefined--false--undefined', + oldData: 'test--PERMISSIVE--ALL--public--undefined--true--undefined', + schema: '', + tableName: 'users', + type: 'alter_policy', + }, + ]); +}); + +test('alter policy in the table: using', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, (t) => [ + pgPolicy('test', { as: 'permissive', using: sql`true` }), + ]), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, (t) => [ + pgPolicy('test', { as: 'permissive', using: sql`false` }), + ]), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" TO public USING (false);', + ]); + expect(statements).toStrictEqual([ + { + newData: 'test--PERMISSIVE--ALL--public--false--undefined--undefined', + oldData: 'test--PERMISSIVE--ALL--public--true--undefined--undefined', + schema: '', + tableName: 'users', + type: 'alter_policy', + }, + ]); +}); + +test('alter policy in the table: using', async (t) => { + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const schema1 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, (t) => [ + pgPolicy('test', { for: 'insert' }), + ]), + }; + + const schema2 = { + users: pgTable('users', { + id: integer('id').primaryKey(), + }, (t) => [ + pgPolicy('test', { for: 'delete' }), + ]), + }; + + const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR DELETE TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'INSERT', + name: 'test', + on: undefined, + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + { + data: { + as: 'PERMISSIVE', + for: 'DELETE', + name: 'test', + on: undefined, + to: [ + 'public', + ], + using: undefined, + withCheck: undefined, + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); diff --git a/drizzle-orm/src/version.ts b/drizzle-orm/src/version.ts index 87f7e2ae9..6f22d27b3 100644 --- a/drizzle-orm/src/version.ts +++ b/drizzle-orm/src/version.ts @@ -1,4 +1,4 @@ // @ts-ignore - imported using Rollup json plugin export { version as npmVersion } from '../package.json'; // In version 7, we changed the PostgreSQL indexes API -export const compatibilityVersion = 9; +export const compatibilityVersion = 10; From 5601a7d4c95a7ad7099474a513b87cd57c5d67c8 Mon Sep 17 00:00:00 2001 From: David Gomes Date: Tue, 29 Oct 2024 17:59:31 +0100 Subject: [PATCH 274/492] fix: allows crudPolicy to skip generating policies, adds TSDoc to crudPolicy function --- CONTRIBUTING.md | 2 +- drizzle-orm/src/neon/rls.ts | 143 ++++++++++++++++++++++-------------- 2 files changed, 89 insertions(+), 56 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5f91755e..3b7f8cbba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -222,7 +222,7 @@ To understand how test should be created and run - please check [Run tests](#-ru 📂 extensions/ - all the extension helpers for databases -📂 serialaizer/ - all the necessary logic to read from the Drizzle ORM schema and convert it to a common JSON format, as well as the logic to introspect all tables, types, and other database elements and convert them to a common JSON format +📂 serializer/ - all the necessary logic to read from the Drizzle ORM schema and convert it to a common JSON format, as well as the logic to introspect all tables, types, and other database elements and convert them to a common JSON format 📄 introspect-pg.ts, introspect-mysql.ts, introspect-sqlite.ts - these files are responsible for mapping JSON snapshots to TypeScript files during introspect commands diff --git a/drizzle-orm/src/neon/rls.ts b/drizzle-orm/src/neon/rls.ts index 85f6ba220..5a81962c0 100644 --- a/drizzle-orm/src/neon/rls.ts +++ b/drizzle-orm/src/neon/rls.ts @@ -1,65 +1,98 @@ -import { is } from '~/entity.ts'; -import { type AnyPgColumn, pgPolicy, type PgPolicyToOption } from '~/pg-core/index.ts'; -import { PgRole, pgRole } from '~/pg-core/roles.ts'; -import { type SQL, sql } from '~/sql/sql.ts'; +import { is } from "~/entity.ts"; +import { + type AnyPgColumn, + pgPolicy, + type PgPolicyToOption, +} from "~/pg-core/index.ts"; +import { PgRole, pgRole } from "~/pg-core/roles.ts"; +import { type SQL, sql } from "~/sql/sql.ts"; +/** + * Generates a set of PostgreSQL row-level security (RLS) policies for CRUD operations based on the provided options. + * + * @param options - An object containing the policy configuration. + * @param options.role - The PostgreSQL role(s) to apply the policy to. Can be a single `PgRole` instance or an array of `PgRole` instances or role names. + * @param options.read - The SQL expression or boolean value that defines the read policy. Set to `true` to allow all reads, `false` to deny all reads, or provide a custom SQL expression. Set to `null` to prevent the policy from being generated. + * @param options.modify - The SQL expression or boolean value that defines the modify (insert, update, delete) policies. Set to `true` to allow all modifications, `false` to deny all modifications, or provide a custom SQL expression. Set to `null` to prevent policies from being generated. + * @returns An array of PostgreSQL policy definitions, one for each CRUD operation. + */ export const crudPolicy = (options: { - role: PgPolicyToOption; - read?: SQL | boolean; - modify?: SQL | boolean; + role: PgPolicyToOption; + read: SQL | boolean | null; + modify: SQL | boolean | null; }) => { - const read: SQL = options.read === true - ? sql`true` - : options.read === false || options.read === undefined - ? sql`false` - : options.read; + if (options.read === undefined) { + throw new Error("crudPolicy requires a read policy"); + } - const modify: SQL = options.modify === true - ? sql`true` - : options.modify === false || options.modify === undefined - ? sql`false` - : options.modify; + if (options.modify === undefined) { + throw new Error("crudPolicy requires a modify policy"); + } - let rolesName = ''; - if (Array.isArray(options.role)) { - rolesName = options.role - .map((it) => { - return is(it, PgRole) ? it.name : (it as string); - }) - .join('-'); - } else { - rolesName = is(options.role, PgRole) - ? options.role.name - : (options.role as string); - } + let read: SQL | undefined; + if (options.read === true) { + read = sql`true`; + } else if (options.read === false) { + read = sql`false`; + } else if (options.read !== null) { + read = options.read; + } - return [ - pgPolicy(`crud-${rolesName}-policy-insert`, { - for: 'insert', - to: options.role, - withCheck: modify, - }), - pgPolicy(`crud-${rolesName}-policy-update`, { - for: 'update', - to: options.role, - using: modify, - withCheck: modify, - }), - pgPolicy(`crud-${rolesName}-policy-delete`, { - for: 'delete', - to: options.role, - using: modify, - }), - pgPolicy(`crud-${rolesName}-policy-select`, { - for: 'select', - to: options.role, - using: read, - }), - ]; + let modify: SQL | undefined; + if (options.modify === true) { + modify = sql`true`; + } else if (options.modify === false) { + modify = sql`false`; + } else if (options.modify !== null) { + modify = options.modify; + } + + let rolesName = ""; + if (Array.isArray(options.role)) { + rolesName = options.role + .map((it) => { + return is(it, PgRole) ? it.name : (it as string); + }) + .join("-"); + } else { + rolesName = is(options.role, PgRole) + ? options.role.name + : (options.role as string); + } + + return [ + read && + pgPolicy(`crud-${rolesName}-policy-select`, { + for: "select", + to: options.role, + using: read, + }), + + modify && + pgPolicy(`crud-${rolesName}-policy-insert`, { + for: "insert", + to: options.role, + withCheck: modify, + }), + modify && + pgPolicy(`crud-${rolesName}-policy-update`, { + for: "update", + to: options.role, + using: modify, + withCheck: modify, + }), + modify && + pgPolicy(`crud-${rolesName}-policy-delete`, { + for: "delete", + to: options.role, + using: modify, + }), + ].filter(Boolean); }; // These are default roles that Neon will set up. -export const authenticatedRole = pgRole('authenticated').existing(); -export const anonymousRole = pgRole('anonymous').existing(); +export const authenticatedRole = pgRole("authenticated").existing(); +export const anonymousRole = pgRole("anonymous").existing(); -export const authUid = (userIdColumn: AnyPgColumn) => sql`(select auth.user_id() = ${userIdColumn})`; +export const authUid = (userIdColumn: AnyPgColumn) => + sql`(select auth.user_id() = ${userIdColumn})`; From e62c333a04930f1072d2d21a7822be735fde0e88 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 29 Oct 2024 22:46:46 +0200 Subject: [PATCH 275/492] Fix lint and tests for crudPolicy --- drizzle-orm/src/neon/rls.ts | 147 +++++++++--------- integration-tests/tests/pg/pg-common.ts | 6 +- .../tests/pg/rls/rls.definition.test.ts | 2 +- 3 files changed, 75 insertions(+), 80 deletions(-) diff --git a/drizzle-orm/src/neon/rls.ts b/drizzle-orm/src/neon/rls.ts index 5a81962c0..16e22f449 100644 --- a/drizzle-orm/src/neon/rls.ts +++ b/drizzle-orm/src/neon/rls.ts @@ -1,11 +1,7 @@ -import { is } from "~/entity.ts"; -import { - type AnyPgColumn, - pgPolicy, - type PgPolicyToOption, -} from "~/pg-core/index.ts"; -import { PgRole, pgRole } from "~/pg-core/roles.ts"; -import { type SQL, sql } from "~/sql/sql.ts"; +import { is } from '~/entity.ts'; +import { type AnyPgColumn, pgPolicy, type PgPolicyToOption } from '~/pg-core/index.ts'; +import { PgRole, pgRole } from '~/pg-core/roles.ts'; +import { type SQL, sql } from '~/sql/sql.ts'; /** * Generates a set of PostgreSQL row-level security (RLS) policies for CRUD operations based on the provided options. @@ -17,82 +13,81 @@ import { type SQL, sql } from "~/sql/sql.ts"; * @returns An array of PostgreSQL policy definitions, one for each CRUD operation. */ export const crudPolicy = (options: { - role: PgPolicyToOption; - read: SQL | boolean | null; - modify: SQL | boolean | null; + role: PgPolicyToOption; + read: SQL | boolean | null; + modify: SQL | boolean | null; }) => { - if (options.read === undefined) { - throw new Error("crudPolicy requires a read policy"); - } + if (options.read === undefined) { + throw new Error('crudPolicy requires a read policy'); + } - if (options.modify === undefined) { - throw new Error("crudPolicy requires a modify policy"); - } + if (options.modify === undefined) { + throw new Error('crudPolicy requires a modify policy'); + } - let read: SQL | undefined; - if (options.read === true) { - read = sql`true`; - } else if (options.read === false) { - read = sql`false`; - } else if (options.read !== null) { - read = options.read; - } + let read: SQL | undefined; + if (options.read === true) { + read = sql`true`; + } else if (options.read === false) { + read = sql`false`; + } else if (options.read !== null) { + read = options.read; + } - let modify: SQL | undefined; - if (options.modify === true) { - modify = sql`true`; - } else if (options.modify === false) { - modify = sql`false`; - } else if (options.modify !== null) { - modify = options.modify; - } + let modify: SQL | undefined; + if (options.modify === true) { + modify = sql`true`; + } else if (options.modify === false) { + modify = sql`false`; + } else if (options.modify !== null) { + modify = options.modify; + } - let rolesName = ""; - if (Array.isArray(options.role)) { - rolesName = options.role - .map((it) => { - return is(it, PgRole) ? it.name : (it as string); - }) - .join("-"); - } else { - rolesName = is(options.role, PgRole) - ? options.role.name - : (options.role as string); - } + let rolesName = ''; + if (Array.isArray(options.role)) { + rolesName = options.role + .map((it) => { + return is(it, PgRole) ? it.name : (it as string); + }) + .join('-'); + } else { + rolesName = is(options.role, PgRole) + ? options.role.name + : (options.role as string); + } - return [ - read && - pgPolicy(`crud-${rolesName}-policy-select`, { - for: "select", - to: options.role, - using: read, - }), + return [ + read + && pgPolicy(`crud-${rolesName}-policy-select`, { + for: 'select', + to: options.role, + using: read, + }), - modify && - pgPolicy(`crud-${rolesName}-policy-insert`, { - for: "insert", - to: options.role, - withCheck: modify, - }), - modify && - pgPolicy(`crud-${rolesName}-policy-update`, { - for: "update", - to: options.role, - using: modify, - withCheck: modify, - }), - modify && - pgPolicy(`crud-${rolesName}-policy-delete`, { - for: "delete", - to: options.role, - using: modify, - }), - ].filter(Boolean); + modify + && pgPolicy(`crud-${rolesName}-policy-insert`, { + for: 'insert', + to: options.role, + withCheck: modify, + }), + modify + && pgPolicy(`crud-${rolesName}-policy-update`, { + for: 'update', + to: options.role, + using: modify, + withCheck: modify, + }), + modify + && pgPolicy(`crud-${rolesName}-policy-delete`, { + for: 'delete', + to: options.role, + using: modify, + }), + ].filter(Boolean); }; // These are default roles that Neon will set up. -export const authenticatedRole = pgRole("authenticated").existing(); -export const anonymousRole = pgRole("anonymous").existing(); +export const authenticatedRole = pgRole('authenticated').existing(); +export const anonymousRole = pgRole('anonymous').existing(); -export const authUid = (userIdColumn: AnyPgColumn) => - sql`(select auth.user_id() = ${userIdColumn})`; +export const authUid = (userIdColumn: AnyPgColumn) => sql`(select auth.user_id() = ${userIdColumn})`; diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index a079db973..3b3e4cb4d 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4787,9 +4787,9 @@ export function tests() { for (const it of Object.values(policy)) { expect(is(it, PgPolicy)).toBe(true); - expect(it.to).toStrictEqual(authenticatedRole); - it.using ? expect(it.using).toStrictEqual(sql`true`) : ''; - it.withCheck ? expect(it.withCheck).toStrictEqual(sql`true`) : ''; + expect(it?.to).toStrictEqual(authenticatedRole); + it?.using ? expect(it.using).toStrictEqual(sql`true`) : ''; + it?.withCheck ? expect(it.withCheck).toStrictEqual(sql`true`) : ''; } } diff --git a/integration-tests/tests/pg/rls/rls.definition.test.ts b/integration-tests/tests/pg/rls/rls.definition.test.ts index 81090633e..2365a2e6d 100644 --- a/integration-tests/tests/pg/rls/rls.definition.test.ts +++ b/integration-tests/tests/pg/rls/rls.definition.test.ts @@ -7,7 +7,7 @@ test.skip('getTableConfig: policies', async () => { id: integer(), }, () => [ pgPolicy('name'), - crudPolicy({ role: pgRole('users') }), + crudPolicy({ role: pgRole('users'), read: true, modify: true }), ]); const tc = getTableConfig(schema); From 64902232bdd4bf94e3d83671de26a2c1c9a2f599 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 29 Oct 2024 22:52:57 +0200 Subject: [PATCH 276/492] Add Supabase RLS createDrizzle function --- drizzle-orm/src/supabase/rls.ts | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drizzle-orm/src/supabase/rls.ts b/drizzle-orm/src/supabase/rls.ts index b4b71504b..486a30fd9 100644 --- a/drizzle-orm/src/supabase/rls.ts +++ b/drizzle-orm/src/supabase/rls.ts @@ -1,3 +1,4 @@ +import type { PgDatabase } from '~/pg-core/index.ts'; import { bigserial, pgSchema, text, uuid } from '~/pg-core/index.ts'; import { pgRole } from '~/pg-core/roles.ts'; import { sql } from '~/sql/sql.ts'; @@ -31,3 +32,55 @@ export const realtimeMessages = realtime.table( export const authUid = sql`(select auth.uid())`; export const realtimeTopic = sql`realtime.topic()`; + +export type SupabaseToken = { + iss?: string; + sub?: string; + aud?: string[] | string; + exp?: number; + nbf?: number; + iat?: number; + jti?: string; + role?: string; +}; + +export function createDrizzle( + token: SupabaseToken, + { admin, client }: { admin: PgDatabase; client: PgDatabase }, +) { + return { + admin, + rls: (async (transaction, ...rest) => { + return await client.transaction(async (tx) => { + // Supabase exposes auth.uid() and auth.jwt() + // https://supabase.com/docs/guides/database/postgres/row-level-security#helper-functions + try { + await tx.execute(sql` + -- auth.jwt() + select set_config('request.jwt.claims', '${ + sql.raw( + JSON.stringify(token), + ) + }', TRUE); + -- auth.uid() + select set_config('request.jwt.claim.sub', '${ + sql.raw( + token.sub ?? '', + ) + }', TRUE); + -- set local role + set local role ${sql.raw(token.role ?? 'anon')}; + `); + return await transaction(tx); + } finally { + await tx.execute(sql` + -- reset + select set_config('request.jwt.claims', NULL, TRUE); + select set_config('request.jwt.claim.sub', NULL, TRUE); + reset role; + `); + } + }, ...rest); + }) as typeof client.transaction, + }; +} From 20c8e02bed2fc009fdc1422bf2bc51a605b744b5 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 30 Oct 2024 00:36:19 +0200 Subject: [PATCH 277/492] Import from db.ts --- drizzle-orm/src/supabase/rls.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/supabase/rls.ts b/drizzle-orm/src/supabase/rls.ts index 486a30fd9..b00a4700f 100644 --- a/drizzle-orm/src/supabase/rls.ts +++ b/drizzle-orm/src/supabase/rls.ts @@ -1,4 +1,4 @@ -import type { PgDatabase } from '~/pg-core/index.ts'; +import type { PgDatabase } from '~/pg-core/db.ts'; import { bigserial, pgSchema, text, uuid } from '~/pg-core/index.ts'; import { pgRole } from '~/pg-core/roles.ts'; import { sql } from '~/sql/sql.ts'; From 098afba2803ca5b89e6096a5de4eea2f26ecb2f6 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 30 Oct 2024 08:38:00 +0200 Subject: [PATCH 278/492] Save exact version for attw --- package.json | 4 ++-- pnpm-lock.yaml | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index b0fda61c8..76174ab44 100755 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "lint": "concurrently -n eslint,dprint \"eslint --ext ts .\" \"dprint check --list-different\"" }, "devDependencies": { - "@arethetypeswrong/cli": "^0.15.3", + "@arethetypeswrong/cli": "0.15.3", "@trivago/prettier-plugin-sort-imports": "^4.2.0", "@typescript-eslint/eslint-plugin": "^6.7.3", "@typescript-eslint/experimental-utils": "^5.62.0", @@ -38,4 +38,4 @@ "typescript": "5.6.3" }, "packageManager": "pnpm@9.7.0" -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f69f5727f..ed86a8353 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,7 +9,7 @@ importers: .: devDependencies: '@arethetypeswrong/cli': - specifier: ^0.15.3 + specifier: 0.15.3 version: 0.15.3 '@trivago/prettier-plugin-sort-imports': specifier: ^4.2.0 @@ -10340,8 +10340,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10427,11 +10427,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0': + '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10470,6 +10470,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.478.0': @@ -10736,11 +10737,11 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/client-sts@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10779,7 +10780,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/core@3.477.0': @@ -10934,7 +10934,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -11141,7 +11141,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -11342,7 +11342,7 @@ snapshots: '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11351,7 +11351,7 @@ snapshots: '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 From 1ee8ed3172fd9ec4add9e71aaa78e257cff82dba Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 30 Oct 2024 08:49:18 +0200 Subject: [PATCH 279/492] re-trigger ci --- drizzle-orm/src/supabase/rls.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/supabase/rls.ts b/drizzle-orm/src/supabase/rls.ts index b00a4700f..6fe3f788c 100644 --- a/drizzle-orm/src/supabase/rls.ts +++ b/drizzle-orm/src/supabase/rls.ts @@ -16,7 +16,7 @@ export const authUsers = auth.table('users', { id: uuid().primaryKey().notNull(), }); -/* ------------------------------ realtime schema; ------------------------------ */ +/* ------------------------------ realtime schema; ------------------------------- */ const realtime = pgSchema('realtime'); export const realtimeMessages = realtime.table( From 4b200a2fd9b21b21691570e807aaefaca43ae348 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 30 Oct 2024 10:06:48 +0200 Subject: [PATCH 280/492] Format json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 76174ab44..29189a91b 100755 --- a/package.json +++ b/package.json @@ -38,4 +38,4 @@ "typescript": "5.6.3" }, "packageManager": "pnpm@9.7.0" -} \ No newline at end of file +} From 5ea5a84f890f24858ec5d3c4490dabcfc719ff47 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 30 Oct 2024 10:56:48 +0200 Subject: [PATCH 281/492] Bump version, remove createDrizzle --- changelogs/drizzle-kit/0.27.0.md | 421 +++++++++++++++++++++++++++++++ changelogs/drizzle-orm/0.36.0.md | 419 ++++++++++++++++++++++++++++++ drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- drizzle-orm/src/supabase/rls.ts | 53 ---- 5 files changed, 842 insertions(+), 55 deletions(-) create mode 100644 changelogs/drizzle-kit/0.27.0.md create mode 100644 changelogs/drizzle-orm/0.36.0.md diff --git a/changelogs/drizzle-kit/0.27.0.md b/changelogs/drizzle-kit/0.27.0.md new file mode 100644 index 000000000..e4f51fdb3 --- /dev/null +++ b/changelogs/drizzle-kit/0.27.0.md @@ -0,0 +1,421 @@ +> This version of `drizzle-jit` requires `drizzle-orm@0.36.0` to enable all new features + +# New Features + +## Row-Level Security (RLS) + +With Drizzle, you can enable Row-Level Security (RLS) for any Postgres table, create policies with various options, and define and manage the roles those policies apply to. + +Drizzle supports a raw representation of Postgres policies and roles that can be used in any way you want. This works with popular Postgres database providers such as `Neon` and `Supabase`. + +In Drizzle, we have specific predefined RLS roles and functions for RLS with both database providers, but you can also define your own logic. + +### Enable RLS + +If you just want to enable RLS on a table without adding policies, you can use `.enableRLS()` + +As mentioned in the PostgreSQL documentation: + +> If no policy exists for the table, a default-deny policy is used, meaning that no rows are visible or can be modified. +Operations that apply to the whole table, such as TRUNCATE and REFERENCES, are not subject to row security. + +```ts +import { integer, pgTable } from 'drizzle-orm/pg-core'; + +export const users = pgTable('users', { + id: integer(), +}).enableRLS(); +``` + +> If you add a policy to a table, RLS will be enabled automatically. So, there’s no need to explicitly enable RLS when adding policies to a table. + +### Roles + +Currently, Drizzle supports defining roles with a few different options, as shown below. Support for more options will be added in a future release. + +```ts +import { pgRole } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin', { createRole: true, createDb: true, inherit: true }); +``` + +If a role already exists in your database, and you don’t want drizzle-kit to ‘see’ it or include it in migrations, you can mark the role as existing. + +```ts +import { pgRole } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin').existing(); +``` + +### Policies + +To fully leverage RLS, you can define policies within a Drizzle table. + +> In PostgreSQL, policies should be linked to an existing table. Since policies are always associated with a specific table, we decided that policy definitions should be defined as a parameter of `pgTable` + +**Example of pgPolicy with all available properties** +```ts +import { sql } from 'drizzle-orm'; +import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin'); + +export const users = pgTable('users', { + id: integer(), +}, (t) => [ + pgPolicy('policy', { + as: 'permissive', + to: admin, + for: 'delete', + using: sql``, + withCheck: sql``, + }), +]); +``` + +**Link Policy to an existing table** + +There are situations where you need to link a policy to an existing table in your database. +The most common use case is with database providers like `Neon` or `Supabase`, where you need to add a policy +to their existing tables. In this case, you can use the `.link()` API + +```ts +import { sql } from "drizzle-orm"; +import { pgPolicy } from "drizzle-orm/pg-core"; +import { authenticatedRole, realtimeMessages } from "drizzle-orm/supabase"; + +export const policy = pgPolicy("authenticated role insert policy", { + for: "insert", + to: authenticatedRole, + using: sql``, +}).link(realtimeMessages); +``` + +### Migrations + +If you are using drizzle-kit to manage your schema and roles, there may be situations where you want to refer to roles that are not defined in your Drizzle schema. In such cases, you may want drizzle-kit to skip managing these roles without having to define each role in your drizzle schema and marking it with `.existing()`. + +In these cases, you can use `entities.roles` in `drizzle.config.ts`. For a complete reference, refer to the the [`drizzle.config.ts`](https://orm.drizzle.team/docs/drizzle-config-file) documentation. + +By default, `drizzle-kit` does not manage roles for you, so you will need to enable this feature in `drizzle.config.ts`. + +```ts {12-14} +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: 'postgresql', + schema: "./drizzle/schema.ts", + dbCredentials: { + url: process.env.DATABASE_URL! + }, + verbose: true, + strict: true, + entities: { + roles: true + } +}); +``` + +In case you need additional configuration options, let's take a look at a few more examples. + +**You have an `admin` role and want to exclude it from the list of manageable roles** + +```ts +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + ... + entities: { + roles: { + exclude: ['admin'] + } + } +}); +``` + +**You have an `admin` role and want to include it in the list of manageable roles** + +```ts +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + ... + entities: { + roles: { + include: ['admin'] + } + } +}); +``` + +**If you are using `Neon` and want to exclude Neon-defined roles, you can use the provider option** + +```ts +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + ... + entities: { + roles: { + provider: 'neon' + } + } +}); +``` + +**If you are using `Supabase` and want to exclude Supabase-defined roles, you can use the provider option** + +```ts +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + ... + entities: { + roles: { + provider: 'supabase' + } + } +}); +``` + +> You may encounter situations where Drizzle is slightly outdated compared to new roles specified by your database provider. +In such cases, you can use the `provider` option and `exclude` additional roles: + +```ts +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + ... + entities: { + roles: { + provider: 'supabase', + exclude: ['new_supabase_role'] + } + } +}); +``` + +### RLS on views + +With Drizzle, you can also specify RLS policies on views. For this, you need to use `security_invoker` in the view's WITH options. Here is a small example: + +```ts {5} +... + +export const roomsUsersProfiles = pgView("rooms_users_profiles") + .with({ + securityInvoker: true, + }) + .as((qb) => + qb + .select({ + ...getTableColumns(roomsUsers), + email: profiles.email, + }) + .from(roomsUsers) + .innerJoin(profiles, eq(roomsUsers.userId, profiles.id)) + ); +``` + +### Using with Neon + +The Neon Team helped us implement their vision of a wrapper on top of our raw policies API. We defined a specific +`/neon` import with the `crudPolicy` function that includes predefined functions and Neon's default roles. + +Here's an example of how to use the `crudPolicy` function: + +```ts +import { crudPolicy } from 'drizzle-orm/neon'; +import { integer, pgRole, pgTable } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin'); + +export const users = pgTable('users', { + id: integer(), +}, (t) => [ + crudPolicy({ role: admin, read: true, modify: false }), +]); +``` + +This policy is equivalent to: + +```ts +import { sql } from 'drizzle-orm'; +import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin'); + +export const users = pgTable('users', { + id: integer(), +}, (t) => [ + pgPolicy(`crud-${admin.name}-policy-insert`, { + for: 'insert', + to: admin, + withCheck: sql`false`, + }), + pgPolicy(`crud-${admin.name}-policy-update`, { + for: 'update', + to: admin, + using: sql`false`, + withCheck: sql`false`, + }), + pgPolicy(`crud-${admin.name}-policy-delete`, { + for: 'delete', + to: admin, + using: sql`false`, + }), + pgPolicy(`crud-${admin.name}-policy-select`, { + for: 'select', + to: admin, + using: sql`true`, + }), +]); +``` + +`Neon` exposes predefined `authenticated` and `anaonymous` roles and related functions. If you are using `Neon` for RLS, you can use these roles, which are marked as existing, and the related functions in your RLS queries. + +```ts +// drizzle-orm/neon +export const authenticatedRole = pgRole('authenticated').existing(); +export const anonymousRole = pgRole('anonymous').existing(); + +export const authUid = (userIdColumn: AnyPgColumn) => sql`(select auth.user_id() = ${userIdColumn})`; +``` + +For example, you can use the `Neon` predefined roles and functions like this: + + +```ts +import { sql } from 'drizzle-orm'; +import { authenticatedRole } from 'drizzle-orm/neon'; +import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin'); + +export const users = pgTable('users', { + id: integer(), +}, (t) => [ + pgPolicy(`policy-insert`, { + for: 'insert', + to: authenticatedRole, + withCheck: sql`false`, + }), +]); +``` + +### Using with Supabase + +We also have a `/supabase` import with a set of predefined roles marked as existing, which you can use in your schema. +This import will be extended in a future release with more functions and helpers to make using RLS and `Supabase` simpler. + +```ts +// drizzle-orm/supabase +export const anonRole = pgRole('anon').existing(); +export const authenticatedRole = pgRole('authenticated').existing(); +export const serviceRole = pgRole('service_role').existing(); +export const postgresRole = pgRole('postgres_role').existing(); +export const supabaseAuthAdminRole = pgRole('supabase_auth_admin').existing(); +``` + +For example, you can use the `Supabase` predefined roles like this: + +```ts +import { sql } from 'drizzle-orm'; +import { serviceRole } from 'drizzle-orm/supabase'; +import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin'); + +export const users = pgTable('users', { + id: integer(), +}, (t) => [ + pgPolicy(`policy-insert`, { + for: 'insert', + to: serviceRole, + withCheck: sql`false`, + }), +]); +``` + +The `/supabase` import also includes predefined tables and functions that you can use in your application + +```ts +// drizzle-orm/supabase + +const auth = pgSchema('auth'); +export const authUsers = auth.table('users', { + id: uuid().primaryKey().notNull(), +}); + +const realtime = pgSchema('realtime'); +export const realtimeMessages = realtime.table( + 'messages', + { + id: bigserial({ mode: 'bigint' }).primaryKey(), + topic: text().notNull(), + extension: text({ + enum: ['presence', 'broadcast', 'postgres_changes'], + }).notNull(), + }, +); + +export const authUid = sql`(select auth.uid())`; +export const realtimeTopic = sql`realtime.topic()`; +``` + +This allows you to use it in your code, and Drizzle Kit will treat them as existing databases, +using them only as information to connect to other entities + +```ts +import { foreignKey, pgPolicy, pgTable, text, uuid } from "drizzle-orm/pg-core"; +import { sql } from "drizzle-orm/sql"; +import { authenticatedRole, authUsers } from "drizzle-orm/supabase"; + +export const profiles = pgTable( + "profiles", + { + id: uuid().primaryKey().notNull(), + email: text().notNull(), + }, + (table) => [ + foreignKey({ + columns: [table.id], + // reference to the auth table from Supabase + foreignColumns: [authUsers.id], + name: "profiles_id_fk", + }).onDelete("cascade"), + pgPolicy("authenticated can view all profiles", { + for: "select", + // using predefined role from Supabase + to: authenticatedRole, + using: sql`true`, + }), + ] +); +``` + +Let's check an example of adding a policy to a table that exists in `Supabase` + +```ts +import { sql } from "drizzle-orm"; +import { pgPolicy } from "drizzle-orm/pg-core"; +import { authenticatedRole, realtimeMessages } from "drizzle-orm/supabase"; + +export const policy = pgPolicy("authenticated role insert policy", { + for: "insert", + to: authenticatedRole, + using: sql``, +}).link(realtimeMessages); +``` + +# Bug fixes + +- [[BUG]: Studio + mysql default mode, wrong format related timezone](https://github.com/drizzle-team/drizzle-orm/issues/2747) +- [[BUG]: Drizzle Studio CORS error](https://github.com/drizzle-team/drizzle-orm/issues/1857) +- [[BUG]: TIMESTAMPS showing up incorrectly on drizzle studio](https://github.com/drizzle-team/drizzle-orm/issues/2549) \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.36.0.md b/changelogs/drizzle-orm/0.36.0.md new file mode 100644 index 000000000..0f01b6e91 --- /dev/null +++ b/changelogs/drizzle-orm/0.36.0.md @@ -0,0 +1,419 @@ +> This version of `drizzle-orm` requires `drizzle-kit@0.27.0` to enable all new features + +# New Features + +## Row-Level Security (RLS) + +With Drizzle, you can enable Row-Level Security (RLS) for any Postgres table, create policies with various options, and define and manage the roles those policies apply to. + +Drizzle supports a raw representation of Postgres policies and roles that can be used in any way you want. This works with popular Postgres database providers such as `Neon` and `Supabase`. + +In Drizzle, we have specific predefined RLS roles and functions for RLS with both database providers, but you can also define your own logic. + +### Enable RLS + +If you just want to enable RLS on a table without adding policies, you can use `.enableRLS()` + +As mentioned in the PostgreSQL documentation: + +> If no policy exists for the table, a default-deny policy is used, meaning that no rows are visible or can be modified. +Operations that apply to the whole table, such as TRUNCATE and REFERENCES, are not subject to row security. + +```ts +import { integer, pgTable } from 'drizzle-orm/pg-core'; + +export const users = pgTable('users', { + id: integer(), +}).enableRLS(); +``` + +> If you add a policy to a table, RLS will be enabled automatically. So, there’s no need to explicitly enable RLS when adding policies to a table. + +### Roles + +Currently, Drizzle supports defining roles with a few different options, as shown below. Support for more options will be added in a future release. + +```ts +import { pgRole } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin', { createRole: true, createDb: true, inherit: true }); +``` + +If a role already exists in your database, and you don’t want drizzle-kit to ‘see’ it or include it in migrations, you can mark the role as existing. + +```ts +import { pgRole } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin').existing(); +``` + +### Policies + +To fully leverage RLS, you can define policies within a Drizzle table. + +> In PostgreSQL, policies should be linked to an existing table. Since policies are always associated with a specific table, we decided that policy definitions should be defined as a parameter of `pgTable` + +**Example of pgPolicy with all available properties** +```ts +import { sql } from 'drizzle-orm'; +import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin'); + +export const users = pgTable('users', { + id: integer(), +}, (t) => [ + pgPolicy('policy', { + as: 'permissive', + to: admin, + for: 'delete', + using: sql``, + withCheck: sql``, + }), +]); +``` + +**Link Policy to an existing table** + +There are situations where you need to link a policy to an existing table in your database. +The most common use case is with database providers like `Neon` or `Supabase`, where you need to add a policy +to their existing tables. In this case, you can use the `.link()` API + +```ts +import { sql } from "drizzle-orm"; +import { pgPolicy } from "drizzle-orm/pg-core"; +import { authenticatedRole, realtimeMessages } from "drizzle-orm/supabase"; + +export const policy = pgPolicy("authenticated role insert policy", { + for: "insert", + to: authenticatedRole, + using: sql``, +}).link(realtimeMessages); +``` + +### Migrations + +If you are using drizzle-kit to manage your schema and roles, there may be situations where you want to refer to roles that are not defined in your Drizzle schema. In such cases, you may want drizzle-kit to skip managing these roles without having to define each role in your drizzle schema and marking it with `.existing()`. + +In these cases, you can use `entities.roles` in `drizzle.config.ts`. For a complete reference, refer to the the [`drizzle.config.ts`](https://orm.drizzle.team/docs/drizzle-config-file) documentation. + +By default, `drizzle-kit` does not manage roles for you, so you will need to enable this feature in `drizzle.config.ts`. + +```ts {12-14} +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + dialect: 'postgresql', + schema: "./drizzle/schema.ts", + dbCredentials: { + url: process.env.DATABASE_URL! + }, + verbose: true, + strict: true, + entities: { + roles: true + } +}); +``` + +In case you need additional configuration options, let's take a look at a few more examples. + +**You have an `admin` role and want to exclude it from the list of manageable roles** + +```ts +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + ... + entities: { + roles: { + exclude: ['admin'] + } + } +}); +``` + +**You have an `admin` role and want to include it in the list of manageable roles** + +```ts +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + ... + entities: { + roles: { + include: ['admin'] + } + } +}); +``` + +**If you are using `Neon` and want to exclude Neon-defined roles, you can use the provider option** + +```ts +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + ... + entities: { + roles: { + provider: 'neon' + } + } +}); +``` + +**If you are using `Supabase` and want to exclude Supabase-defined roles, you can use the provider option** + +```ts +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + ... + entities: { + roles: { + provider: 'supabase' + } + } +}); +``` + +> You may encounter situations where Drizzle is slightly outdated compared to new roles specified by your database provider. +In such cases, you can use the `provider` option and `exclude` additional roles: + +```ts +// drizzle.config.ts +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + ... + entities: { + roles: { + provider: 'supabase', + exclude: ['new_supabase_role'] + } + } +}); +``` + +### RLS on views + +With Drizzle, you can also specify RLS policies on views. For this, you need to use `security_invoker` in the view's WITH options. Here is a small example: + +```ts {5} +... + +export const roomsUsersProfiles = pgView("rooms_users_profiles") + .with({ + securityInvoker: true, + }) + .as((qb) => + qb + .select({ + ...getTableColumns(roomsUsers), + email: profiles.email, + }) + .from(roomsUsers) + .innerJoin(profiles, eq(roomsUsers.userId, profiles.id)) + ); +``` + +### Using with Neon + +The Neon Team helped us implement their vision of a wrapper on top of our raw policies API. We defined a specific +`/neon` import with the `crudPolicy` function that includes predefined functions and Neon's default roles. + +Here's an example of how to use the `crudPolicy` function: + +```ts +import { crudPolicy } from 'drizzle-orm/neon'; +import { integer, pgRole, pgTable } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin'); + +export const users = pgTable('users', { + id: integer(), +}, (t) => [ + crudPolicy({ role: admin, read: true, modify: false }), +]); +``` + +This policy is equivalent to: + +```ts +import { sql } from 'drizzle-orm'; +import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin'); + +export const users = pgTable('users', { + id: integer(), +}, (t) => [ + pgPolicy(`crud-${admin.name}-policy-insert`, { + for: 'insert', + to: admin, + withCheck: sql`false`, + }), + pgPolicy(`crud-${admin.name}-policy-update`, { + for: 'update', + to: admin, + using: sql`false`, + withCheck: sql`false`, + }), + pgPolicy(`crud-${admin.name}-policy-delete`, { + for: 'delete', + to: admin, + using: sql`false`, + }), + pgPolicy(`crud-${admin.name}-policy-select`, { + for: 'select', + to: admin, + using: sql`true`, + }), +]); +``` + +`Neon` exposes predefined `authenticated` and `anaonymous` roles and related functions. If you are using `Neon` for RLS, you can use these roles, which are marked as existing, and the related functions in your RLS queries. + +```ts +// drizzle-orm/neon +export const authenticatedRole = pgRole('authenticated').existing(); +export const anonymousRole = pgRole('anonymous').existing(); + +export const authUid = (userIdColumn: AnyPgColumn) => sql`(select auth.user_id() = ${userIdColumn})`; +``` + +For example, you can use the `Neon` predefined roles and functions like this: + + +```ts +import { sql } from 'drizzle-orm'; +import { authenticatedRole } from 'drizzle-orm/neon'; +import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin'); + +export const users = pgTable('users', { + id: integer(), +}, (t) => [ + pgPolicy(`policy-insert`, { + for: 'insert', + to: authenticatedRole, + withCheck: sql`false`, + }), +]); +``` + +### Using with Supabase + +We also have a `/supabase` import with a set of predefined roles marked as existing, which you can use in your schema. +This import will be extended in a future release with more functions and helpers to make using RLS and `Supabase` simpler. + +```ts +// drizzle-orm/supabase +export const anonRole = pgRole('anon').existing(); +export const authenticatedRole = pgRole('authenticated').existing(); +export const serviceRole = pgRole('service_role').existing(); +export const postgresRole = pgRole('postgres_role').existing(); +export const supabaseAuthAdminRole = pgRole('supabase_auth_admin').existing(); +``` + +For example, you can use the `Supabase` predefined roles like this: + +```ts +import { sql } from 'drizzle-orm'; +import { serviceRole } from 'drizzle-orm/supabase'; +import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core'; + +export const admin = pgRole('admin'); + +export const users = pgTable('users', { + id: integer(), +}, (t) => [ + pgPolicy(`policy-insert`, { + for: 'insert', + to: serviceRole, + withCheck: sql`false`, + }), +]); +``` + +The `/supabase` import also includes predefined tables and functions that you can use in your application + +```ts +// drizzle-orm/supabase + +const auth = pgSchema('auth'); +export const authUsers = auth.table('users', { + id: uuid().primaryKey().notNull(), +}); + +const realtime = pgSchema('realtime'); +export const realtimeMessages = realtime.table( + 'messages', + { + id: bigserial({ mode: 'bigint' }).primaryKey(), + topic: text().notNull(), + extension: text({ + enum: ['presence', 'broadcast', 'postgres_changes'], + }).notNull(), + }, +); + +export const authUid = sql`(select auth.uid())`; +export const realtimeTopic = sql`realtime.topic()`; +``` + +This allows you to use it in your code, and Drizzle Kit will treat them as existing databases, +using them only as information to connect to other entities + +```ts +import { foreignKey, pgPolicy, pgTable, text, uuid } from "drizzle-orm/pg-core"; +import { sql } from "drizzle-orm/sql"; +import { authenticatedRole, authUsers } from "drizzle-orm/supabase"; + +export const profiles = pgTable( + "profiles", + { + id: uuid().primaryKey().notNull(), + email: text().notNull(), + }, + (table) => [ + foreignKey({ + columns: [table.id], + // reference to the auth table from Supabase + foreignColumns: [authUsers.id], + name: "profiles_id_fk", + }).onDelete("cascade"), + pgPolicy("authenticated can view all profiles", { + for: "select", + // using predefined role from Supabase + to: authenticatedRole, + using: sql`true`, + }), + ] +); +``` + +Let's check an example of adding a policy to a table that exists in `Supabase` + +```ts +import { sql } from "drizzle-orm"; +import { pgPolicy } from "drizzle-orm/pg-core"; +import { authenticatedRole, realtimeMessages } from "drizzle-orm/supabase"; + +export const policy = pgPolicy("authenticated role insert policy", { + for: "insert", + to: authenticatedRole, + using: sql``, +}).link(realtimeMessages); +``` + +# Bug fixes + +- [[BUG]: postgres-js driver throws error when using new { client } constructor arguments ](https://github.com/drizzle-team/drizzle-orm/issues/3176) \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 9f1fef0a7..36822a052 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.26.2", + "version": "0.27.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 7c9a963d4..e2b17a1af 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.35.3", + "version": "0.36.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { diff --git a/drizzle-orm/src/supabase/rls.ts b/drizzle-orm/src/supabase/rls.ts index 6fe3f788c..20fea7355 100644 --- a/drizzle-orm/src/supabase/rls.ts +++ b/drizzle-orm/src/supabase/rls.ts @@ -1,4 +1,3 @@ -import type { PgDatabase } from '~/pg-core/db.ts'; import { bigserial, pgSchema, text, uuid } from '~/pg-core/index.ts'; import { pgRole } from '~/pg-core/roles.ts'; import { sql } from '~/sql/sql.ts'; @@ -32,55 +31,3 @@ export const realtimeMessages = realtime.table( export const authUid = sql`(select auth.uid())`; export const realtimeTopic = sql`realtime.topic()`; - -export type SupabaseToken = { - iss?: string; - sub?: string; - aud?: string[] | string; - exp?: number; - nbf?: number; - iat?: number; - jti?: string; - role?: string; -}; - -export function createDrizzle( - token: SupabaseToken, - { admin, client }: { admin: PgDatabase; client: PgDatabase }, -) { - return { - admin, - rls: (async (transaction, ...rest) => { - return await client.transaction(async (tx) => { - // Supabase exposes auth.uid() and auth.jwt() - // https://supabase.com/docs/guides/database/postgres/row-level-security#helper-functions - try { - await tx.execute(sql` - -- auth.jwt() - select set_config('request.jwt.claims', '${ - sql.raw( - JSON.stringify(token), - ) - }', TRUE); - -- auth.uid() - select set_config('request.jwt.claim.sub', '${ - sql.raw( - token.sub ?? '', - ) - }', TRUE); - -- set local role - set local role ${sql.raw(token.role ?? 'anon')}; - `); - return await transaction(tx); - } finally { - await tx.execute(sql` - -- reset - select set_config('request.jwt.claims', NULL, TRUE); - select set_config('request.jwt.claim.sub', NULL, TRUE); - reset role; - `); - } - }, ...rest); - }) as typeof client.transaction, - }; -} From 2f84354f4087d6ea0018e1c335c8a38851e66599 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 30 Oct 2024 11:41:47 +0000 Subject: [PATCH 282/492] skip view tests --- drizzle-kit/tests/singlestore-views.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drizzle-kit/tests/singlestore-views.test.ts b/drizzle-kit/tests/singlestore-views.test.ts index 70add76fc..fedd74645 100644 --- a/drizzle-kit/tests/singlestore-views.test.ts +++ b/drizzle-kit/tests/singlestore-views.test.ts @@ -3,7 +3,7 @@ import { int, singlestoreTable, singlestoreView } from 'drizzle-orm/singlestore- import { expect, test } from 'vitest'; import { diffTestSchemasSingleStore } from './schemaDiffer'; -test('create view #1', async () => { +test.skip('create view #1', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -35,7 +35,7 @@ SQL SECURITY definer VIEW \`some_view\` AS (select \`id\` from \`users\`);`); }); -test('create view #2', async () => { +test.skip('create view #2', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -164,7 +164,7 @@ test('rename view', async () => { expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); }); -test('rename view and alter meta options', async () => { +test.skip('rename view and alter meta options', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -232,7 +232,7 @@ test('rename view with existing flag', async () => { expect(sqlStatements.length).toBe(0); }); -test('add meta to view', async () => { +test.skip('add meta to view', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -289,7 +289,7 @@ test('add meta to view with existing flag', async () => { expect(sqlStatements.length).toBe(0); }); -test('alter meta to view', async () => { +test.skip('alter meta to view', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -348,7 +348,7 @@ test('alter meta to view with existing flag', async () => { expect(sqlStatements.length).toBe(0); }); -test('drop meta from view', async () => { +test.skip('drop meta from view', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -405,7 +405,7 @@ test('drop meta from view existing flag', async () => { expect(sqlStatements.length).toBe(0); }); -test('alter view ".as" value', async () => { +test.skip('alter view ".as" value', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -441,7 +441,7 @@ VIEW \`some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) WITH cascaded CHECK OPTION;`); }); -test('rename and alter view ".as" value', async () => { +test.skip('rename and alter view ".as" value', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -509,7 +509,7 @@ test('set existing', async () => { expect(sqlStatements.length).toBe(0); }); -test('drop existing', async () => { +test.skip('drop existing', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); From 0d06d512a47d9340a6ade3bab494180f5a1fdc00 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 1 Nov 2024 20:26:54 +0200 Subject: [PATCH 283/492] 0.27.1 drizzle-kit release --- changelogs/drizzle-kit/0.27.1.md | 1 + drizzle-kit/package.json | 4 ++-- drizzle-kit/src/snapshotsDiffer.ts | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 changelogs/drizzle-kit/0.27.1.md diff --git a/changelogs/drizzle-kit/0.27.1.md b/changelogs/drizzle-kit/0.27.1.md new file mode 100644 index 000000000..d7a63a723 --- /dev/null +++ b/changelogs/drizzle-kit/0.27.1.md @@ -0,0 +1 @@ +- Fix: [[BUG]: When using RLS policies and Views, the view is the last clause generated](https://github.com/drizzle-team/drizzle-orm/issues/3378) \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 36822a052..16eadda09 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.27.0", + "version": "0.27.1", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", @@ -138,4 +138,4 @@ "default": "./api.mjs" } } -} +} \ No newline at end of file diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index f50ae5f6c..57d8e701d 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -1974,6 +1974,8 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...jsonAlteredUniqueConstraints); jsonStatements.push(...jsonAlterEnumsWithDroppedValues); + jsonStatements.push(...createViews); + jsonStatements.push(...jsonRenamePoliciesStatements); jsonStatements.push(...jsonDropPoliciesStatements); jsonStatements.push(...jsonCreatePoliciesStatements); @@ -1984,8 +1986,6 @@ export const applyPgSnapshotsDiff = async ( jsonStatements.push(...jsonCreateIndPoliciesStatements); jsonStatements.push(...jsonAlterIndPoliciesStatements); - jsonStatements.push(...createViews); - jsonStatements.push(...dropEnums); jsonStatements.push(...dropSequences); jsonStatements.push(...dropSchemas); From 0303acc182d4f5547f57ed7ef1cc74d9f1940640 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 1 Nov 2024 20:32:28 +0200 Subject: [PATCH 284/492] Fix dprint --- drizzle-kit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 16eadda09..bb20a6324 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -138,4 +138,4 @@ "default": "./api.mjs" } } -} \ No newline at end of file +} From afbbba35bc93c61c0c3e7e6a34d93816f0e3b885 Mon Sep 17 00:00:00 2001 From: Nicholas Ly Date: Fri, 1 Nov 2024 15:09:06 -0500 Subject: [PATCH 285/492] fix: added commonly used columns to supabase auth.users table schema --- drizzle-orm/src/supabase/rls.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drizzle-orm/src/supabase/rls.ts b/drizzle-orm/src/supabase/rls.ts index 20fea7355..d5f813ac6 100644 --- a/drizzle-orm/src/supabase/rls.ts +++ b/drizzle-orm/src/supabase/rls.ts @@ -1,4 +1,4 @@ -import { bigserial, pgSchema, text, uuid } from '~/pg-core/index.ts'; +import { bigserial, pgSchema, text, timestamp, uuid, varchar } from '~/pg-core/index.ts'; import { pgRole } from '~/pg-core/roles.ts'; import { sql } from '~/sql/sql.ts'; @@ -13,6 +13,13 @@ const auth = pgSchema('auth'); export const authUsers = auth.table('users', { id: uuid().primaryKey().notNull(), + email: varchar({ length: 255 }), + phone: text().unique(), + emailConfirmedAt: timestamp('email_confirmed_at', { withTimezone: true }), + phoneConfirmedAt: timestamp('phone_confirmed_at', { withTimezone: true }), + lastSignInAt: timestamp('last_sign_in_at', { withTimezone: true }), + createdAt: timestamp('created_at', { withTimezone: true }), + updatedAt: timestamp('updated_at', { withTimezone: true }), }); /* ------------------------------ realtime schema; ------------------------------- */ From 67c68fbd08ffe9331aaacad32d9b3a082b294b7e Mon Sep 17 00:00:00 2001 From: Alex Blokh Date: Sun, 3 Nov 2024 10:13:51 +0200 Subject: [PATCH 286/492] imports checker with OHM grammar --- drizzle-kit/.gitignore | 1 + drizzle-kit/imports-checker/analyze.ts | 65 +++++ drizzle-kit/imports-checker/checker.ts | 254 ++++++++++++++++++ .../imports-checker/grammar/grammar.ohm | 47 ++++ .../grammar/grammar.ohm-bundle.d.ts | 59 ++++ .../grammar/grammar.ohm-bundle.js | 1 + drizzle-kit/imports-checker/index.ts | 49 ++++ drizzle-kit/package.json | 3 + drizzle-kit/tests/bin.test.ts | 56 ++++ pnpm-lock.yaml | 199 +++++--------- 10 files changed, 603 insertions(+), 131 deletions(-) create mode 100644 drizzle-kit/imports-checker/analyze.ts create mode 100644 drizzle-kit/imports-checker/checker.ts create mode 100644 drizzle-kit/imports-checker/grammar/grammar.ohm create mode 100644 drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts create mode 100644 drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js create mode 100644 drizzle-kit/imports-checker/index.ts create mode 100644 drizzle-kit/tests/bin.test.ts diff --git a/drizzle-kit/.gitignore b/drizzle-kit/.gitignore index 8d2cf5a81..2a2caf09c 100644 --- a/drizzle-kit/.gitignore +++ b/drizzle-kit/.gitignore @@ -2,6 +2,7 @@ **/.DS_Store !src +!imports-checker !tests !vitest.config.ts !README.md diff --git a/drizzle-kit/imports-checker/analyze.ts b/drizzle-kit/imports-checker/analyze.ts new file mode 100644 index 000000000..d260e1f7f --- /dev/null +++ b/drizzle-kit/imports-checker/analyze.ts @@ -0,0 +1,65 @@ +import { readFileSync } from 'fs'; +import type { Node } from 'ohm-js'; +import JSImports from './grammar/grammar.ohm-bundle'; + +export type CollectionItem = { + type: 'data' | 'types'; + source: string; +}; + +function recursiveRun(...args: Node[]): boolean { + for (const arg of args) { + if (arg.ctorName === 'Rest' || arg.ctorName === 'comment') continue; + + if (arg.ctorName === 'ImportExpr') { + arg['analyze'](); + + continue; + } + + if (arg.isTerminal()) continue; + + for (const c of arg.children) { + if (!recursiveRun(c)) return false; + } + } + + return true; +} +function init(collection: CollectionItem[]) { + const semantics = JSImports.createSemantics(); + + semantics.addOperation('analyze', { + JSImports(arg0, arg1) { + recursiveRun(arg0, arg1); + }, + + ImportExpr(arg0) { + if (arg0.ctorName === 'ImportExpr_NoFrom') return; + + arg0['analyze'](); + }, + + ImportExpr_From(kImport, importInner, kFrom, importSource) { + const importType = importInner.children[0]?.ctorName === 'ImportInner_Type' ? 'types' : 'data'; + + collection.push({ + source: importSource.children[1]!.sourceString!, + type: importType, + }); + }, + }); + + return semantics; +} + +export function analyze(path: string) { + const file = readFileSync(path).toString(); + const match = JSImports.match(file, 'JSImports'); + + if (match.failed()) throw new Error(`Failed to parse file: ${path}`); + const collection: CollectionItem[] = []; + + init(collection)(match)['analyze'](); + return collection; +} diff --git a/drizzle-kit/imports-checker/checker.ts b/drizzle-kit/imports-checker/checker.ts new file mode 100644 index 000000000..d2c7b0b16 --- /dev/null +++ b/drizzle-kit/imports-checker/checker.ts @@ -0,0 +1,254 @@ +import fs from 'fs'; +import m from 'micromatch'; +import { dirname, join as joinPath, relative, resolve as resolvePath } from 'path'; +import { analyze } from './analyze'; + +type External = { + file: string; + import: string; + type: 'data' | 'types'; +}; + +export type Issue = { + file: string; + imports: IssueImport[]; + accessChains: ChainLink[][]; +}; + +export type IssueImport = { + name: string; + type: 'data' | 'types'; +}; + +export type ChainLink = { + file: string; + import: string; +}; + +type ListMode = 'whitelist' | 'blacklist'; + +class ImportAnalyzer { + private localImportRegex = /^(\.?\.?\/|\.\.?$)/; + private importedFileFormatRegex = /^.*\.(ts|tsx|mts|cts|js|jsx|mjs|cjs|json)$/i; + + private visited: Set = new Set(); + + private externals: External[] = []; + private unresolved: string[] = []; + private unrecognized: string[] = []; + private accessChains: Record = {}; + + constructor( + private basePath: string, + private entry: string, + private listMode: ListMode, + private readonly wantedList: string[], + private localPaths: string[], + private logger?: boolean, + private ignoreTypes?: boolean, + ) { + } + + private isDirectory = (path: string) => { + try { + return fs.lstatSync(path).isDirectory(); + } catch (e) { + return false; + } + }; + + private isFile = (path: string) => { + try { + return fs.lstatSync(path).isFile(); + } catch (e) { + return false; + } + }; + + private localizePath = (path: string) => relative(resolvePath(this.basePath), resolvePath(path)); + + private isCustomLocal = (importTarget: string) => + !!this.localPaths.find((l) => importTarget === l || importTarget.startsWith(l.endsWith('/') ? l : `${l}/`)); + private isLocal = (importTarget: string) => + this.localImportRegex.test(importTarget) || this.isCustomLocal(importTarget); + private isTsFormat = (path: string) => this.importedFileFormatRegex.test(path); + + private resolveCustomLocalPath = (absoluteBase: string, base: string, target: string): string => { + return joinPath(absoluteBase, target); + }; + + private resolveTargetFile = (path: string): string => { + if (this.isFile(path)) return path; + + const formats = ['.ts', '.mts', '.cts', '.tsx', '.js', '.mjs', '.cjs', '.jsx']; + + for (const format of formats) { + const indexPath = joinPath(path, `/index${format}`); + if (this.isFile(indexPath)) return indexPath; + + const formatFilePath = `${path}${format}`; + if (this.isFile(formatFilePath)) return formatFilePath; + } + + return path; + }; + + private resolveTargetPath = (absoluteBase: string, base: string, target: string): string => { + if (this.isCustomLocal(target)) { + return this.resolveTargetFile(this.resolveCustomLocalPath(absoluteBase, base, target)); + } + + const dir = this.isDirectory(base) ? base : dirname(base); + const joined = joinPath(dir, target); + + return this.resolveTargetFile(joined); + }; + + private _analyzeImports = ( + target: string = this.entry, + basePath: string = this.basePath, + accessChain: ChainLink[] = [], + ) => { + if (this.visited.has(target)) return; + + const locals: string[] = []; + + try { + if (this.logger) console.log(`${this.localizePath(target)}`); + + const imports = analyze(target); + + for (const { source: i, type } of imports) { + if (this.isLocal(i)) { + locals.push(i); + + continue; + } + + if (this.ignoreTypes && type === 'types') continue; + + this.externals.push({ + file: this.localizePath(target), + import: i, + type: type, + }); + } + } catch (e) { + throw e + // if (this.logger) console.error(e); + + // this.unresolved.push(this.localizePath(target)); + } finally { + this.visited.add(target); + } + + for (const local of locals) { + const transformedTarget = this.resolveTargetPath(basePath, target, local); + + const localChain = [...accessChain, { + file: this.localizePath(target), + import: local, + }]; + + const localized = this.localizePath(transformedTarget); + + if (this.accessChains[localized]) { + this.accessChains[localized].push(localChain); + } else this.accessChains[localized] = [localChain]; + + if (this.isTsFormat(transformedTarget)) { + this._analyzeImports(transformedTarget, basePath, localChain); + } else { + this.unrecognized.push(localized); + } + } + }; + + public analyzeImports = () => { + this._analyzeImports(); + + const rawIssues = this.listMode === 'whitelist' + ? this.externals.filter((e) => !m([e.import], this.wantedList).length) + : this.externals.filter((e) => m([e.import], this.wantedList).length); + + const issueMap: Record = {}; + for (const { file, import: i, type } of rawIssues) { + if (issueMap[file]) { + issueMap[file].imports.push({ + name: i, + type, + }); + + continue; + } + + issueMap[file] = { + file, + imports: [{ + name: i, + type, + }], + accessChains: this.accessChains[file]!, + }; + } + + return { + issues: Object.values(issueMap), + accessChains: this.accessChains, + unrecognized: this.unrecognized, + unresolved: this.unresolved, + }; + }; +} + +export type CustomLocalPathResolver = (basePath: string, path: string, target: string) => string; + +export type AnalyzeImportsConfig = + & { + basePath: string; + entry: string; + logger?: boolean; + ignoreTypes?: boolean; + localPaths?: string[]; + } + & ({ + blackList: string[]; + } | { + whiteList: string[]; + }); + +type AnyAnalyzeImportsConfig = { + basePath: string; + entry: string; + blackList?: string[]; + whiteList?: string[]; + logger?: boolean; + ignoreTypes?: boolean; + localPaths?: string[]; +}; + +export function analyzeImports(cfg: AnalyzeImportsConfig) { + const { + basePath, + blackList, + whiteList, + entry, + localPaths: localImports, + ignoreTypes, + logger, + } = cfg as AnyAnalyzeImportsConfig; + const mode = whiteList ? 'whitelist' : 'blacklist'; + const wantedList = blackList ?? whiteList!; + + const analyzer = new ImportAnalyzer( + joinPath(basePath), + joinPath(entry), + mode, + wantedList, + localImports ?? [], + logger, + ignoreTypes, + ); + + return analyzer.analyzeImports(); +} diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm b/drizzle-kit/imports-checker/grammar/grammar.ohm new file mode 100644 index 000000000..49bb41e57 --- /dev/null +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm @@ -0,0 +1,47 @@ +JSImports { + JSImports = (Expr semicolon?)* + + Expr = + | comment + | ImportExpr + | Rest + + ImportExpr = + | kImport ImportInner kFrom importSource -- From + | kImport importSource -- NoFrom + + Rest = (~ImportExpr any)+ + + ImportInner = + | ("*" (kAs identifier)?) -- Default + | ("{" NonemptyListOf kComma? "}") -- Extended + | ("type" "{" NonemptyListOf kComma? "}") -- Type + + ImportExtendedSelection = TypeImport | Import + ImportExtendedSelectionTypeless = Import + + Import = identifier (kAs identifier)? + TypeImport = kType Import (kAs identifier)? + + kType = "type" + kImport = "import" + kFrom = "from" + kAs = "as" + kComma = "," + + identifier = letter alnum* + quote = "\"" | "'" | "`" + notQuote = ~quote any + importSource = + | "\"" notQuote+ "\"" + | "'" notQuote+ "'" + | "`" notQuote+ "`" + semicolon = ";" + + lineTerminator = "\n" | "\r" | "\u2028" | "\u2029" + + comment = multiLineComment | singleLineComment + + multiLineComment = "/*" (~"*/" any)* "*/" + singleLineComment = "//" (~lineTerminator any)* +} \ No newline at end of file diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts new file mode 100644 index 000000000..3feb5c64b --- /dev/null +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts @@ -0,0 +1,59 @@ +// AUTOGENERATED FILE +// This file was generated from grammar.ohm by `ohm generateBundles`. + +import { + BaseActionDict, + Grammar, + IterationNode, + Node, + NonterminalNode, + Semantics, + TerminalNode +} from 'ohm-js'; + +export interface JSImportsActionDict extends BaseActionDict { + JSImports?: (this: NonterminalNode, arg0: IterationNode, arg1: IterationNode) => T; + Expr?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExpr_From?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode, arg2: NonterminalNode, arg3: NonterminalNode) => T; + ImportExpr_NoFrom?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode) => T; + ImportExpr?: (this: NonterminalNode, arg0: NonterminalNode) => T; + Rest?: (this: NonterminalNode, arg0: IterationNode) => T; + ImportInner_Default?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: IterationNode) => T; + ImportInner_Extended?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: IterationNode, arg3: TerminalNode) => T; + ImportInner_Type?: (this: NonterminalNode, arg0: TerminalNode, arg1: TerminalNode, arg2: NonterminalNode, arg3: IterationNode, arg4: TerminalNode) => T; + ImportInner?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelection?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelectionTypeless?: (this: NonterminalNode, arg0: NonterminalNode) => T; + Import?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode) => T; + TypeImport?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode, arg2: IterationNode, arg3: IterationNode) => T; + kType?: (this: NonterminalNode, arg0: TerminalNode) => T; + kImport?: (this: NonterminalNode, arg0: TerminalNode) => T; + kFrom?: (this: NonterminalNode, arg0: TerminalNode) => T; + kAs?: (this: NonterminalNode, arg0: TerminalNode) => T; + kComma?: (this: NonterminalNode, arg0: TerminalNode) => T; + identifier?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T; + quote?: (this: NonterminalNode, arg0: TerminalNode) => T; + notQuote?: (this: NonterminalNode, arg0: NonterminalNode) => T; + importSource?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + semicolon?: (this: NonterminalNode, arg0: TerminalNode) => T; + lineTerminator?: (this: NonterminalNode, arg0: TerminalNode) => T; + comment?: (this: NonterminalNode, arg0: NonterminalNode) => T; + multiLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + singleLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode) => T; +} + +export interface JSImportsSemantics extends Semantics { + addOperation(name: string, actionDict: JSImportsActionDict): this; + extendOperation(name: string, actionDict: JSImportsActionDict): this; + addAttribute(name: string, actionDict: JSImportsActionDict): this; + extendAttribute(name: string, actionDict: JSImportsActionDict): this; +} + +export interface JSImportsGrammar extends Grammar { + createSemantics(): JSImportsSemantics; + extendSemantics(superSemantics: JSImportsSemantics): JSImportsSemantics; +} + +declare const grammar: JSImportsGrammar; +export default grammar; + diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js new file mode 100644 index 000000000..76be00861 --- /dev/null +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js @@ -0,0 +1 @@ +import {makeRecipe} from 'ohm-js';const result=makeRecipe(["grammar",{"source":"JSImports {\n JSImports = (Expr semicolon?)*\n\n Expr = \n | comment\n | ImportExpr\n | Rest\n\n ImportExpr =\n | kImport ImportInner kFrom importSource -- From\n | kImport importSource -- NoFrom\n\n Rest = (~ImportExpr any)+\n\n ImportInner = \n | (\"*\" (kAs identifier)?) -- Default\n | (\"{\" NonemptyListOf kComma? \"}\") -- Extended\n | (\"type\" \"{\" NonemptyListOf kComma? \"}\") -- Type\n\n ImportExtendedSelection = TypeImport | Import\n ImportExtendedSelectionTypeless = Import\n\n Import = identifier (kAs identifier)?\n TypeImport = kType Import (kAs identifier)?\n\n kType = \"type\"\n kImport = \"import\"\n kFrom = \"from\"\n kAs = \"as\"\n kComma = \",\"\n\n identifier = letter alnum*\n quote = \"\\\"\" | \"'\" | \"`\"\n notQuote = ~quote any\n importSource =\n | \"\\\"\" notQuote+ \"\\\"\"\n | \"'\" notQuote+ \"'\"\n | \"`\" notQuote+ \"`\"\n semicolon = \";\"\n\n lineTerminator = \"\\n\" | \"\\r\" | \"\\u2028\" | \"\\u2029\"\n \n comment = multiLineComment | singleLineComment\n\n multiLineComment = \"/*\" (~\"*/\" any)* \"*/\"\n singleLineComment = \"//\" (~lineTerminator any)*\n}"},"JSImports",null,"JSImports",{"JSImports":["define",{"sourceInterval":[16,46]},null,[],["star",{"sourceInterval":[28,46]},["seq",{"sourceInterval":[29,44]},["app",{"sourceInterval":[29,33]},"Expr",[]],["opt",{"sourceInterval":[34,44]},["app",{"sourceInterval":[34,43]},"semicolon",[]]]]]],"Expr":["define",{"sourceInterval":[52,101]},null,[],["alt",{"sourceInterval":[64,101]},["app",{"sourceInterval":[66,73]},"comment",[]],["app",{"sourceInterval":[80,90]},"ImportExpr",[]],["app",{"sourceInterval":[97,101]},"Rest",[]]]],"ImportExpr_From":["define",{"sourceInterval":[126,172]},null,[],["seq",{"sourceInterval":[126,164]},["app",{"sourceInterval":[126,133]},"kImport",[]],["app",{"sourceInterval":[134,145]},"ImportInner",[]],["app",{"sourceInterval":[146,151]},"kFrom",[]],["app",{"sourceInterval":[152,164]},"importSource",[]]]],"ImportExpr_NoFrom":["define",{"sourceInterval":[179,209]},null,[],["seq",{"sourceInterval":[179,199]},["app",{"sourceInterval":[179,186]},"kImport",[]],["app",{"sourceInterval":[187,199]},"importSource",[]]]],"ImportExpr":["define",{"sourceInterval":[107,209]},null,[],["alt",{"sourceInterval":[124,209]},["app",{"sourceInterval":[126,164]},"ImportExpr_From",[]],["app",{"sourceInterval":[179,199]},"ImportExpr_NoFrom",[]]]],"Rest":["define",{"sourceInterval":[215,240]},null,[],["plus",{"sourceInterval":[222,240]},["seq",{"sourceInterval":[223,238]},["not",{"sourceInterval":[223,234]},["app",{"sourceInterval":[224,234]},"ImportExpr",[]]],["app",{"sourceInterval":[235,238]},"any",[]]]]],"ImportInner_Default":["define",{"sourceInterval":[267,301]},null,[],["seq",{"sourceInterval":[267,290]},["terminal",{"sourceInterval":[268,271]},"*"],["opt",{"sourceInterval":[272,289]},["seq",{"sourceInterval":[273,287]},["app",{"sourceInterval":[273,276]},"kAs",[]],["app",{"sourceInterval":[277,287]},"identifier",[]]]]]],"ImportInner_Extended":["define",{"sourceInterval":[308,385]},null,[],["seq",{"sourceInterval":[308,373]},["terminal",{"sourceInterval":[309,312]},"{"],["app",{"sourceInterval":[313,360]},"NonemptyListOf",[["app",{"sourceInterval":[328,351]},"ImportExtendedSelection",[]],["app",{"sourceInterval":[353,359]},"kComma",[]]]],["opt",{"sourceInterval":[361,368]},["app",{"sourceInterval":[361,367]},"kComma",[]]],["terminal",{"sourceInterval":[369,372]},"}"]]],"ImportInner_Type":["define",{"sourceInterval":[392,480]},null,[],["seq",{"sourceInterval":[392,472]},["terminal",{"sourceInterval":[393,399]},"type"],["terminal",{"sourceInterval":[400,403]},"{"],["app",{"sourceInterval":[404,459]},"NonemptyListOf",[["app",{"sourceInterval":[419,450]},"ImportExtendedSelectionTypeless",[]],["app",{"sourceInterval":[452,458]},"kComma",[]]]],["opt",{"sourceInterval":[460,467]},["app",{"sourceInterval":[460,466]},"kComma",[]]],["terminal",{"sourceInterval":[468,471]},"}"]]],"ImportInner":["define",{"sourceInterval":[246,480]},null,[],["alt",{"sourceInterval":[265,480]},["app",{"sourceInterval":[267,290]},"ImportInner_Default",[]],["app",{"sourceInterval":[308,373]},"ImportInner_Extended",[]],["app",{"sourceInterval":[392,472]},"ImportInner_Type",[]]]],"ImportExtendedSelection":["define",{"sourceInterval":[486,531]},null,[],["alt",{"sourceInterval":[512,531]},["app",{"sourceInterval":[512,522]},"TypeImport",[]],["app",{"sourceInterval":[525,531]},"Import",[]]]],"ImportExtendedSelectionTypeless":["define",{"sourceInterval":[536,576]},null,[],["app",{"sourceInterval":[570,576]},"Import",[]]],"Import":["define",{"sourceInterval":[582,619]},null,[],["seq",{"sourceInterval":[591,619]},["app",{"sourceInterval":[591,601]},"identifier",[]],["opt",{"sourceInterval":[602,619]},["seq",{"sourceInterval":[603,617]},["app",{"sourceInterval":[603,606]},"kAs",[]],["app",{"sourceInterval":[607,617]},"identifier",[]]]]]],"TypeImport":["define",{"sourceInterval":[624,667]},null,[],["seq",{"sourceInterval":[637,667]},["app",{"sourceInterval":[637,642]},"kType",[]],["app",{"sourceInterval":[643,649]},"Import",[]],["opt",{"sourceInterval":[650,667]},["seq",{"sourceInterval":[651,665]},["app",{"sourceInterval":[651,654]},"kAs",[]],["app",{"sourceInterval":[655,665]},"identifier",[]]]]]],"kType":["define",{"sourceInterval":[673,687]},null,[],["terminal",{"sourceInterval":[681,687]},"type"]],"kImport":["define",{"sourceInterval":[692,710]},null,[],["terminal",{"sourceInterval":[702,710]},"import"]],"kFrom":["define",{"sourceInterval":[715,729]},null,[],["terminal",{"sourceInterval":[723,729]},"from"]],"kAs":["define",{"sourceInterval":[734,744]},null,[],["terminal",{"sourceInterval":[740,744]},"as"]],"kComma":["define",{"sourceInterval":[749,761]},null,[],["terminal",{"sourceInterval":[758,761]},","]],"identifier":["define",{"sourceInterval":[767,793]},null,[],["seq",{"sourceInterval":[780,793]},["app",{"sourceInterval":[780,786]},"letter",[]],["star",{"sourceInterval":[787,793]},["app",{"sourceInterval":[787,792]},"alnum",[]]]]],"quote":["define",{"sourceInterval":[798,822]},null,[],["alt",{"sourceInterval":[806,822]},["terminal",{"sourceInterval":[806,810]},"\""],["terminal",{"sourceInterval":[813,816]},"'"],["terminal",{"sourceInterval":[819,822]},"`"]]],"notQuote":["define",{"sourceInterval":[827,848]},null,[],["seq",{"sourceInterval":[838,848]},["not",{"sourceInterval":[838,844]},["app",{"sourceInterval":[839,844]},"quote",[]]],["app",{"sourceInterval":[845,848]},"any",[]]]],"importSource":["define",{"sourceInterval":[853,941]},null,[],["alt",{"sourceInterval":[872,941]},["seq",{"sourceInterval":[874,893]},["terminal",{"sourceInterval":[874,878]},"\""],["plus",{"sourceInterval":[879,888]},["app",{"sourceInterval":[879,887]},"notQuote",[]]],["terminal",{"sourceInterval":[889,893]},"\""]],["seq",{"sourceInterval":[900,917]},["terminal",{"sourceInterval":[900,903]},"'"],["plus",{"sourceInterval":[904,913]},["app",{"sourceInterval":[904,912]},"notQuote",[]]],["terminal",{"sourceInterval":[914,917]},"'"]],["seq",{"sourceInterval":[924,941]},["terminal",{"sourceInterval":[924,927]},"`"],["plus",{"sourceInterval":[928,937]},["app",{"sourceInterval":[928,936]},"notQuote",[]]],["terminal",{"sourceInterval":[938,941]},"`"]]]],"semicolon":["define",{"sourceInterval":[946,961]},null,[],["terminal",{"sourceInterval":[958,961]},";"]],"lineTerminator":["define",{"sourceInterval":[967,1017]},null,[],["alt",{"sourceInterval":[984,1017]},["terminal",{"sourceInterval":[984,988]},"\n"],["terminal",{"sourceInterval":[991,995]},"\r"],["terminal",{"sourceInterval":[998,1006]},"\u2028"],["terminal",{"sourceInterval":[1009,1017]},"\u2029"]]],"comment":["define",{"sourceInterval":[1027,1073]},null,[],["alt",{"sourceInterval":[1037,1073]},["app",{"sourceInterval":[1037,1053]},"multiLineComment",[]],["app",{"sourceInterval":[1056,1073]},"singleLineComment",[]]]],"multiLineComment":["define",{"sourceInterval":[1079,1120]},null,[],["seq",{"sourceInterval":[1098,1120]},["terminal",{"sourceInterval":[1098,1102]},"/*"],["star",{"sourceInterval":[1103,1115]},["seq",{"sourceInterval":[1104,1113]},["not",{"sourceInterval":[1104,1109]},["terminal",{"sourceInterval":[1105,1109]},"*/"]],["app",{"sourceInterval":[1110,1113]},"any",[]]]],["terminal",{"sourceInterval":[1116,1120]},"*/"]]],"singleLineComment":["define",{"sourceInterval":[1125,1172]},null,[],["seq",{"sourceInterval":[1145,1172]},["terminal",{"sourceInterval":[1145,1149]},"//"],["star",{"sourceInterval":[1150,1172]},["seq",{"sourceInterval":[1151,1170]},["not",{"sourceInterval":[1151,1166]},["app",{"sourceInterval":[1152,1166]},"lineTerminator",[]]],["app",{"sourceInterval":[1167,1170]},"any",[]]]]]]}]);export default result; \ No newline at end of file diff --git a/drizzle-kit/imports-checker/index.ts b/drizzle-kit/imports-checker/index.ts new file mode 100644 index 000000000..3cf61eb8e --- /dev/null +++ b/drizzle-kit/imports-checker/index.ts @@ -0,0 +1,49 @@ +import { analyzeImports, ChainLink } from "./checker"; +import chalk from "chalk"; + +const issues = analyzeImports({ + basePath: "./drizzle-kit", + localPaths: ["src"], + whiteList: [ + "@drizzle-team/brocli", + "json-diff", + "path", + "fs", + "fs/*", + "url", + "zod", + "node:*", + "hono", + "glob", + "hono/*", + "hono/**/*", + "@hono/*", + "crypto", + "hanji", + ], + entry: "./drizzle-kit/src/cli/index.ts", + logger: true, + ignoreTypes: true, +}).issues; + +const chainToString = (chains: ChainLink[]) => { + if (chains.length === 0) throw new Error(); + + let out = chains[0]!.file + "\n"; + let indentation = 0; + for (let chain of chains) { + out += + " ".repeat(indentation) + + "└" + + chain.import + + ` ${chalk.gray(chain.file)}\n`; + indentation += 1; + } + return out; +}; + +console.log() +for (const issue of issues) { + console.log(chalk.red(issue.imports.map(it=>it.name).join("\n"))) + console.log(issue.accessChains.map((it) => chainToString(it)).join("\n")); +} diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 7499a7ec1..9abf79fa7 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -62,6 +62,7 @@ "@types/dockerode": "^3.3.28", "@types/glob": "^8.1.0", "@types/json-diff": "^1.0.3", + "@types/micromatch": "^4.0.9", "@types/minimatch": "^5.1.2", "@types/node": "^18.11.15", "@types/pg": "^8.10.7", @@ -92,9 +93,11 @@ "hanji": "^0.0.5", "hono": "^4.1.5", "json-diff": "1.0.6", + "micromatch": "^4.0.8", "minimatch": "^7.4.3", "mysql2": "3.3.3", "node-fetch": "^3.3.2", + "ohm-js": "^17.1.0", "pg": "^8.11.5", "pluralize": "^8.0.0", "postgres": "^3.4.4", diff --git a/drizzle-kit/tests/bin.test.ts b/drizzle-kit/tests/bin.test.ts new file mode 100644 index 000000000..4c0942448 --- /dev/null +++ b/drizzle-kit/tests/bin.test.ts @@ -0,0 +1,56 @@ +import { analyzeImports, ChainLink } from "../imports-checker/checker"; +import chalk from "chalk"; +import { assert, test } from "vitest"; + + + +test("imports-issues", ()=>{ + const issues = analyzeImports({ + basePath: ".", + localPaths: ["src"], + whiteList: [ + "@drizzle-team/brocli", + "json-diff", + "path", + "fs", + "fs/*", + "url", + "zod", + "node:*", + "hono", + "glob", + "hono/*", + "hono/**/*", + "@hono/*", + "crypto", + "hanji", + ], + entry: "src/cli/index.ts", + logger: true, + ignoreTypes: true, + }).issues; + + const chainToString = (chains: ChainLink[]) => { + if (chains.length === 0) throw new Error(); + + let out = chains[0]!.file + "\n"; + let indentation = 0; + for (let chain of chains) { + out += + " ".repeat(indentation) + + "└" + + chain.import + + ` ${chalk.gray(chain.file)}\n`; + indentation += 1; + } + return out; + }; + + console.log() + for (const issue of issues) { + console.log(chalk.red(issue.imports.map(it=>it.name).join("\n"))) + console.log(issue.accessChains.map((it) => chainToString(it)).join("\n")); + } + + assert.equal(issues.length, 0) +}) \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 20ff6ca0f..8f70c508e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,7 +40,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -73,7 +73,7 @@ importers: version: 0.8.16(typescript@5.6.3) tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3))(typescript@5.6.3) tsx: specifier: ^4.10.5 version: 4.10.5 @@ -141,6 +141,9 @@ importers: '@types/json-diff': specifier: ^1.0.3 version: 1.0.3 + '@types/micromatch': + specifier: ^4.0.9 + version: 4.0.9 '@types/minimatch': specifier: ^5.1.2 version: 5.1.2 @@ -231,6 +234,9 @@ importers: json-diff: specifier: 1.0.6 version: 1.0.6 + micromatch: + specifier: ^4.0.8 + version: 4.0.8 minimatch: specifier: ^7.4.3 version: 7.4.6 @@ -240,6 +246,9 @@ importers: node-fetch: specifier: ^3.3.2 version: 3.3.2 + ohm-js: + specifier: ^17.1.0 + version: 17.1.0 pg: specifier: ^8.11.5 version: 8.11.5 @@ -2001,9 +2010,11 @@ packages: '@esbuild-kit/core-utils@3.1.0': resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-kit/esm-loader@2.5.5': resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-plugins/node-globals-polyfill@0.2.3': resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} @@ -2990,10 +3001,12 @@ packages: '@humanwhocodes/config-array@0.11.11': resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.13': resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} @@ -3006,9 +3019,11 @@ packages: '@humanwhocodes/object-schema@1.2.1': resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.1': resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} @@ -4012,6 +4027,9 @@ packages: '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + '@types/braces@3.0.4': + resolution: {integrity: sha512-0WR3b8eaISjEW7RpZnclONaLFDf7buaowRHdqLp4vLj54AsSAYWfh3DRbfiYJY9XDxMgx1B4sE1Afw2PGpuHOA==} + '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} @@ -4066,6 +4084,9 @@ packages: '@types/jsonfile@6.1.4': resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + '@types/micromatch@4.0.9': + resolution: {integrity: sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg==} + '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} @@ -4555,6 +4576,7 @@ packages: are-we-there-yet@3.0.1: resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -4779,10 +4801,6 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -5970,16 +5988,19 @@ packages: eslint@8.50.0: resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.53.0: resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true esm@3.2.25: @@ -6185,10 +6206,6 @@ packages: file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -6346,6 +6363,7 @@ packages: gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. generate-function@2.3.1: resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} @@ -7165,10 +7183,12 @@ packages: libsql@0.3.19: resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] libsql@0.4.1: resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -7548,14 +7568,14 @@ packages: engines: {node: '>=18'} hasBin: true - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - micromatch@4.0.7: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -7861,6 +7881,7 @@ packages: npmlog@6.0.2: resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. npx-import@1.1.4: resolution: {integrity: sha512-3ShymTWOgqGyNlh5lMJAejLuIv3W1K3fbI5Ewc6YErZU3Sp0PqsNs8UIU1O8z5+KVl/Du5ag56Gza9vdorGEoA==} @@ -7912,6 +7933,10 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + ohm-js@17.1.0: + resolution: {integrity: sha512-xc3B5dgAjTBQGHaH7B58M2Pmv6WvzrJ/3/7LeUzXNg0/sY3jQPdSd/S2SstppaleO77rifR1tyhdfFGNIwxf2Q==} + engines: {node: '>=0.12.1'} + oidc-token-hash@5.0.3: resolution: {integrity: sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==} engines: {node: ^10.13.0 || >=12.0.0} @@ -8681,6 +8706,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@5.0.0: @@ -10249,7 +10275,7 @@ snapshots: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10390,7 +10416,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10650,58 +10676,13 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sts@3.569.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.569.0 '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 '@aws-sdk/middleware-logger': 3.568.0 '@aws-sdk/middleware-recursion-detection': 3.567.0 @@ -10885,23 +10866,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) @@ -10925,7 +10889,7 @@ snapshots: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10969,25 +10933,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 @@ -11014,7 +10959,7 @@ snapshots: '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -11127,17 +11072,9 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': dependencies: - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 @@ -11163,7 +11100,7 @@ snapshots: '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -13243,7 +13180,7 @@ snapshots: find-up: 5.0.0 find-yarn-workspace-root: 2.0.0 js-yaml: 3.14.1 - micromatch: 4.0.7 + micromatch: 4.0.8 npm-package-arg: 7.0.0 ora: 3.4.0 split: 1.0.1 @@ -14735,6 +14672,8 @@ snapshots: '@types/connect': 3.4.38 '@types/node': 20.12.12 + '@types/braces@3.0.4': {} + '@types/connect@3.4.38': dependencies: '@types/node': 20.12.12 @@ -14802,6 +14741,10 @@ snapshots: dependencies: '@types/node': 20.12.12 + '@types/micromatch@4.0.9': + dependencies: + '@types/braces': 3.0.4 + '@types/mime@1.3.5': {} '@types/minimatch@5.1.2': {} @@ -15741,10 +15684,6 @@ snapshots: dependencies: balanced-match: 1.0.2 - braces@3.0.2: - dependencies: - fill-range: 7.0.1 - braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -16497,7 +16436,7 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 '@cloudflare/workers-types': 4.20241004.0 @@ -17460,7 +17399,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.7 fast-glob@3.3.2: dependencies: @@ -17530,10 +17469,6 @@ snapshots: file-uri-to-path@1.0.0: {} - fill-range@7.0.1: - dependencies: - to-regex-range: 5.0.1 - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -17589,7 +17524,7 @@ snapshots: find-yarn-workspace-root@2.0.0: dependencies: - micromatch: 4.0.7 + micromatch: 4.0.8 flat-cache@3.1.0: dependencies: @@ -18303,7 +18238,7 @@ snapshots: '@types/stack-utils': 2.0.3 chalk: 4.1.2 graceful-fs: 4.2.11 - micromatch: 4.0.7 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 @@ -18397,7 +18332,7 @@ snapshots: chalk: 4.1.2 flow-parser: 0.236.0 graceful-fs: 4.2.11 - micromatch: 4.0.7 + micromatch: 4.0.8 neo-async: 2.6.2 node-dir: 0.1.17 recast: 0.21.5 @@ -18907,7 +18842,7 @@ snapshots: graceful-fs: 4.2.11 invariant: 2.2.4 jest-worker: 29.7.0 - micromatch: 4.0.7 + micromatch: 4.0.8 node-abort-controller: 3.1.1 nullthrows: 1.1.1 walker: 1.0.8 @@ -19031,12 +18966,12 @@ snapshots: - supports-color - utf-8-validate - micromatch@4.0.5: + micromatch@4.0.7: dependencies: - braces: 3.0.2 + braces: 3.0.3 picomatch: 2.3.1 - micromatch@4.0.7: + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 @@ -19407,6 +19342,8 @@ snapshots: obuf@1.1.2: {} + ohm-js@17.1.0: {} + oidc-token-hash@5.0.3: {} on-finished@2.3.0: @@ -19719,7 +19656,7 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3)): dependencies: lilconfig: 2.1.0 yaml: 2.3.1 @@ -20994,7 +20931,7 @@ snapshots: tslib@2.6.2: {} - tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3): + tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3))(typescript@5.6.3): dependencies: bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 @@ -21004,7 +20941,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3)) resolve-from: 5.0.0 rollup: 3.27.2 source-map: 0.8.0-beta.0 From cd33310fa317c223b9ef12462e19523e4b8a4686 Mon Sep 17 00:00:00 2001 From: Alex Blokh Date: Sun, 3 Nov 2024 13:32:01 +0200 Subject: [PATCH 287/492] imports checker with OHM grammar + fix of imports issues --- drizzle-kit/imports-checker/analyze.ts | 117 ++-- drizzle-kit/imports-checker/checker.ts | 510 ++++++++++-------- .../imports-checker/grammar/grammar.ohm | 106 +++- .../grammar/grammar.ohm-bundle.d.ts | 70 ++- .../grammar/grammar.ohm-bundle.js | 2 +- drizzle-kit/imports-checker/index.ts | 6 +- drizzle-kit/src/@types/utils.ts | 1 + drizzle-kit/src/cli/schema.ts | 3 +- drizzle-kit/tests/bin.test.ts | 23 +- 9 files changed, 513 insertions(+), 325 deletions(-) diff --git a/drizzle-kit/imports-checker/analyze.ts b/drizzle-kit/imports-checker/analyze.ts index d260e1f7f..20568120c 100644 --- a/drizzle-kit/imports-checker/analyze.ts +++ b/drizzle-kit/imports-checker/analyze.ts @@ -1,65 +1,78 @@ -import { readFileSync } from 'fs'; -import type { Node } from 'ohm-js'; -import JSImports from './grammar/grammar.ohm-bundle'; +import { readFileSync } from "fs"; +import type { Node } from "ohm-js"; +import JSImports from "./grammar/grammar.ohm-bundle"; export type CollectionItem = { - type: 'data' | 'types'; - source: string; + type: "data" | "types"; + source: string; }; function recursiveRun(...args: Node[]): boolean { - for (const arg of args) { - if (arg.ctorName === 'Rest' || arg.ctorName === 'comment') continue; - - if (arg.ctorName === 'ImportExpr') { - arg['analyze'](); - - continue; - } - - if (arg.isTerminal()) continue; - - for (const c of arg.children) { - if (!recursiveRun(c)) return false; - } - } - - return true; + for (const arg of args) { + if ( + arg.ctorName === "Rest" || + arg.ctorName === "comment" || + arg.ctorName === "stringLiteral" + ) + continue; + + if ( + arg.ctorName === "ImportExpr_From" || + arg.ctorName === "ImportExpr_NoFrom" + ) { + arg["analyze"](); + + continue; + } + + if (arg.isTerminal()) continue; + + for (const c of arg.children) { + if (!recursiveRun(c)) return false; + } + } + + return true; } function init(collection: CollectionItem[]) { - const semantics = JSImports.createSemantics(); - - semantics.addOperation('analyze', { - JSImports(arg0, arg1) { - recursiveRun(arg0, arg1); - }, - - ImportExpr(arg0) { - if (arg0.ctorName === 'ImportExpr_NoFrom') return; - - arg0['analyze'](); - }, - - ImportExpr_From(kImport, importInner, kFrom, importSource) { - const importType = importInner.children[0]?.ctorName === 'ImportInner_Type' ? 'types' : 'data'; - - collection.push({ - source: importSource.children[1]!.sourceString!, - type: importType, - }); - }, - }); - - return semantics; + const semantics = JSImports.createSemantics(); + + semantics.addOperation("analyze", { + JSImports(arg0, arg1) { + recursiveRun(arg0, arg1); + }, + + ImportExpr_From(kImport, importInner, kFrom, importSource) { + const ruleName = importInner.children[0]!.ctorName; + const importType = + ruleName === "ImportInner_Type" || ruleName === "ImportInner_Types" + ? "types" + : "data"; + + collection.push({ + source: importSource.children[1]!.sourceString!, + type: importType, + }); + }, + + ImportExpr_NoFrom(kImport, importSource) { + collection.push({ + source: importSource.children[1]!.sourceString!, + type: "data", + }); + }, + }); + + return semantics; } export function analyze(path: string) { - const file = readFileSync(path).toString(); - const match = JSImports.match(file, 'JSImports'); + const file = readFileSync(path).toString(); + const match = JSImports.match(file, "JSImports"); - if (match.failed()) throw new Error(`Failed to parse file: ${path}`); - const collection: CollectionItem[] = []; + if (match.failed()) throw new Error(`Failed to parse file: ${path}`); + const collection: CollectionItem[] = []; - init(collection)(match)['analyze'](); - return collection; + init(collection)(match)["analyze"](); + return collection; } diff --git a/drizzle-kit/imports-checker/checker.ts b/drizzle-kit/imports-checker/checker.ts index d2c7b0b16..70c9bb66b 100644 --- a/drizzle-kit/imports-checker/checker.ts +++ b/drizzle-kit/imports-checker/checker.ts @@ -1,254 +1,302 @@ -import fs from 'fs'; -import m from 'micromatch'; -import { dirname, join as joinPath, relative, resolve as resolvePath } from 'path'; -import { analyze } from './analyze'; +import fs from "fs"; +import m from "micromatch"; +import { + dirname, + join as joinPath, + relative, + resolve as resolvePath, +} from "path"; +import { analyze } from "./analyze"; type External = { - file: string; - import: string; - type: 'data' | 'types'; + file: string; + import: string; + type: "data" | "types"; }; export type Issue = { - file: string; - imports: IssueImport[]; - accessChains: ChainLink[][]; + file: string; + imports: IssueImport[]; + accessChains: ChainLink[][]; }; export type IssueImport = { - name: string; - type: 'data' | 'types'; + name: string; + type: "data" | "types"; }; export type ChainLink = { - file: string; - import: string; + file: string; + import: string; }; -type ListMode = 'whitelist' | 'blacklist'; +type ListMode = "whitelist" | "blacklist"; class ImportAnalyzer { - private localImportRegex = /^(\.?\.?\/|\.\.?$)/; - private importedFileFormatRegex = /^.*\.(ts|tsx|mts|cts|js|jsx|mjs|cjs|json)$/i; - - private visited: Set = new Set(); - - private externals: External[] = []; - private unresolved: string[] = []; - private unrecognized: string[] = []; - private accessChains: Record = {}; - - constructor( - private basePath: string, - private entry: string, - private listMode: ListMode, - private readonly wantedList: string[], - private localPaths: string[], - private logger?: boolean, - private ignoreTypes?: boolean, - ) { - } - - private isDirectory = (path: string) => { - try { - return fs.lstatSync(path).isDirectory(); - } catch (e) { - return false; - } - }; - - private isFile = (path: string) => { - try { - return fs.lstatSync(path).isFile(); - } catch (e) { - return false; - } - }; - - private localizePath = (path: string) => relative(resolvePath(this.basePath), resolvePath(path)); - - private isCustomLocal = (importTarget: string) => - !!this.localPaths.find((l) => importTarget === l || importTarget.startsWith(l.endsWith('/') ? l : `${l}/`)); - private isLocal = (importTarget: string) => - this.localImportRegex.test(importTarget) || this.isCustomLocal(importTarget); - private isTsFormat = (path: string) => this.importedFileFormatRegex.test(path); - - private resolveCustomLocalPath = (absoluteBase: string, base: string, target: string): string => { - return joinPath(absoluteBase, target); - }; - - private resolveTargetFile = (path: string): string => { - if (this.isFile(path)) return path; - - const formats = ['.ts', '.mts', '.cts', '.tsx', '.js', '.mjs', '.cjs', '.jsx']; - - for (const format of formats) { - const indexPath = joinPath(path, `/index${format}`); - if (this.isFile(indexPath)) return indexPath; - - const formatFilePath = `${path}${format}`; - if (this.isFile(formatFilePath)) return formatFilePath; - } - - return path; - }; - - private resolveTargetPath = (absoluteBase: string, base: string, target: string): string => { - if (this.isCustomLocal(target)) { - return this.resolveTargetFile(this.resolveCustomLocalPath(absoluteBase, base, target)); - } - - const dir = this.isDirectory(base) ? base : dirname(base); - const joined = joinPath(dir, target); - - return this.resolveTargetFile(joined); - }; - - private _analyzeImports = ( - target: string = this.entry, - basePath: string = this.basePath, - accessChain: ChainLink[] = [], - ) => { - if (this.visited.has(target)) return; - - const locals: string[] = []; - - try { - if (this.logger) console.log(`${this.localizePath(target)}`); - - const imports = analyze(target); - - for (const { source: i, type } of imports) { - if (this.isLocal(i)) { - locals.push(i); - - continue; - } - - if (this.ignoreTypes && type === 'types') continue; - - this.externals.push({ - file: this.localizePath(target), - import: i, - type: type, - }); - } - } catch (e) { - throw e - // if (this.logger) console.error(e); - - // this.unresolved.push(this.localizePath(target)); - } finally { - this.visited.add(target); - } - - for (const local of locals) { - const transformedTarget = this.resolveTargetPath(basePath, target, local); - - const localChain = [...accessChain, { - file: this.localizePath(target), - import: local, - }]; - - const localized = this.localizePath(transformedTarget); - - if (this.accessChains[localized]) { - this.accessChains[localized].push(localChain); - } else this.accessChains[localized] = [localChain]; - - if (this.isTsFormat(transformedTarget)) { - this._analyzeImports(transformedTarget, basePath, localChain); - } else { - this.unrecognized.push(localized); - } - } - }; - - public analyzeImports = () => { - this._analyzeImports(); - - const rawIssues = this.listMode === 'whitelist' - ? this.externals.filter((e) => !m([e.import], this.wantedList).length) - : this.externals.filter((e) => m([e.import], this.wantedList).length); - - const issueMap: Record = {}; - for (const { file, import: i, type } of rawIssues) { - if (issueMap[file]) { - issueMap[file].imports.push({ - name: i, - type, - }); - - continue; - } - - issueMap[file] = { - file, - imports: [{ - name: i, - type, - }], - accessChains: this.accessChains[file]!, - }; - } - - return { - issues: Object.values(issueMap), - accessChains: this.accessChains, - unrecognized: this.unrecognized, - unresolved: this.unresolved, - }; - }; + private localImportRegex = /^(\.?\.?\/|\.\.?$)/; + private importedFileFormatRegex = + /^.*\.(ts|tsx|mts|cts|js|jsx|mjs|cjs|json)$/i; + + private visited: Set = new Set(); + + private externals: External[] = []; + private accessChains: Record = {}; + + constructor( + private basePath: string, + private entry: string, + private listMode: ListMode, + private readonly wantedList: string[], + private localPaths: string[], + private logger?: boolean, + private ignoreTypes?: boolean + ) {} + + private isDirectory = (path: string) => { + try { + return fs.lstatSync(path).isDirectory(); + } catch (e) { + return false; + } + }; + + private isFile = (path: string) => { + try { + return fs.lstatSync(path).isFile(); + } catch (e) { + return false; + } + }; + + private localizePath = (path: string) => + relative(resolvePath(this.basePath), resolvePath(path)); + + private isCustomLocal = (importTarget: string) => + !!this.localPaths.find( + (l) => + importTarget === l || + importTarget.startsWith(l.endsWith("/") ? l : `${l}/`) + ); + private isLocal = (importTarget: string) => + this.localImportRegex.test(importTarget) || + this.isCustomLocal(importTarget); + private isTsFormat = (path: string) => + this.importedFileFormatRegex.test(path); + + private resolveCustomLocalPath = ( + absoluteBase: string, + base: string, + target: string + ): string => { + return joinPath(absoluteBase, target); + }; + + private resolveTargetFile = (path: string): string => { + if (this.isFile(path)) return path; + + const formats = [ + ".ts", + ".mts", + ".cts", + ".tsx", + ".js", + ".mjs", + ".cjs", + ".jsx", + ]; + + for (const format of formats) { + const indexPath = joinPath(path, `/index${format}`); + if (this.isFile(indexPath)) return indexPath; + + const formatFilePath = `${path}${format}`; + if (this.isFile(formatFilePath)) return formatFilePath; + } + + return path; + }; + + private resolveTargetPath = ( + absoluteBase: string, + base: string, + target: string + ): string => { + if (this.isCustomLocal(target)) { + return this.resolveTargetFile( + this.resolveCustomLocalPath(absoluteBase, base, target) + ); + } + + const dir = this.isDirectory(base) ? base : dirname(base); + const joined = joinPath(dir, target); + + return this.resolveTargetFile(joined); + }; + + private _analyzeImports = ( + target: string = this.entry, + basePath: string = this.basePath, + accessChain: ChainLink[] = [] + ) => { + if (this.visited.has(target)) return; + + const locals: string[] = []; + + try { + if (this.logger) console.log(`${this.localizePath(target)}`); + + const imports = analyze(target); + + for (const { source: i, type } of imports) { + if (this.ignoreTypes && type === "types") continue; + + if (this.isLocal(i)) { + locals.push(i); + + continue; + } + + this.externals.push({ + file: this.localizePath(target), + import: i, + type: type, + }); + } + } catch (e) { + throw e; + } finally { + this.visited.add(target); + } + + for (const local of locals) { + const transformedTarget = this.resolveTargetPath(basePath, target, local); + + const localChain = [ + ...accessChain, + { + file: this.localizePath(target), + import: local, + }, + ]; + + const localized = this.localizePath(transformedTarget); + + if (this.accessChains[localized]) { + this.accessChains[localized].push(localChain); + } else this.accessChains[localized] = [localChain]; + + if (this.isTsFormat(transformedTarget)) { + this._analyzeImports(transformedTarget, basePath, localChain); + } else { + throw new Error(`unrecognized: ${localized}`); + } + } + }; + + public analyzeImports = () => { + const entryLocalized = this.localizePath(this.entry); + if (!this.accessChains[entryLocalized]) + this.accessChains[entryLocalized] = [[]]; + + this._analyzeImports(); + + const rawIssues = + this.listMode === "whitelist" + ? this.externals.filter((e) => !m([e.import], this.wantedList).length) + : this.externals.filter((e) => m([e.import], this.wantedList).length); + + const issueMap: Record = {}; + for (const { file, import: i, type } of rawIssues) { + if (issueMap[file]) { + issueMap[file].imports.push({ + name: i, + type, + }); + + continue; + } + + issueMap[file] = { + file, + imports: [ + { + name: i, + type, + }, + ], + accessChains: this.accessChains[file]!, + }; + } + + return { + issues: Object.entries(issueMap).map(([file, data]) => { + for (const chain of data.accessChains) { + chain.push({ + file, + import: "", + }); + } + + return data; + }), + accessChains: this.accessChains, + }; + }; } -export type CustomLocalPathResolver = (basePath: string, path: string, target: string) => string; - -export type AnalyzeImportsConfig = - & { - basePath: string; - entry: string; - logger?: boolean; - ignoreTypes?: boolean; - localPaths?: string[]; - } - & ({ - blackList: string[]; - } | { - whiteList: string[]; - }); +export type CustomLocalPathResolver = ( + basePath: string, + path: string, + target: string +) => string; + +export type AnalyzeImportsConfig = { + basePath: string; + entry: string; + logger?: boolean; + ignoreTypes?: boolean; + localPaths?: string[]; +} & ( + | { + blackList: string[]; + } + | { + whiteList: string[]; + } +); type AnyAnalyzeImportsConfig = { - basePath: string; - entry: string; - blackList?: string[]; - whiteList?: string[]; - logger?: boolean; - ignoreTypes?: boolean; - localPaths?: string[]; + basePath: string; + entry: string; + blackList?: string[]; + whiteList?: string[]; + logger?: boolean; + ignoreTypes?: boolean; + localPaths?: string[]; }; export function analyzeImports(cfg: AnalyzeImportsConfig) { - const { - basePath, - blackList, - whiteList, - entry, - localPaths: localImports, - ignoreTypes, - logger, - } = cfg as AnyAnalyzeImportsConfig; - const mode = whiteList ? 'whitelist' : 'blacklist'; - const wantedList = blackList ?? whiteList!; - - const analyzer = new ImportAnalyzer( - joinPath(basePath), - joinPath(entry), - mode, - wantedList, - localImports ?? [], - logger, - ignoreTypes, - ); - - return analyzer.analyzeImports(); + const { + basePath, + blackList, + whiteList, + entry, + localPaths: localImports, + ignoreTypes, + logger, + } = cfg as AnyAnalyzeImportsConfig; + const mode = whiteList ? "whitelist" : "blacklist"; + const wantedList = blackList ?? whiteList!; + + const analyzer = new ImportAnalyzer( + joinPath(basePath), + joinPath(entry), + mode, + wantedList, + localImports ?? [], + logger, + ignoreTypes + ); + + return analyzer.analyzeImports(); } diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm b/drizzle-kit/imports-checker/grammar/grammar.ohm index 49bb41e57..de1459942 100644 --- a/drizzle-kit/imports-checker/grammar/grammar.ohm +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm @@ -1,33 +1,33 @@ JSImports { - JSImports = (Expr semicolon?)* + JSImports = (Expr ";"?)* Expr = | comment + | stringLiteral | ImportExpr | Rest ImportExpr = - | kImport ImportInner kFrom importSource -- From - | kImport importSource -- NoFrom + | "import" ImportInner "from" importSource -- From + | "import" importSource -- NoFrom - Rest = (~ImportExpr any)+ + Rest = (~(ImportExpr | comment | stringLiteral) any)+ ImportInner = - | ("*" (kAs identifier)?) -- Default - | ("{" NonemptyListOf kComma? "}") -- Extended - | ("type" "{" NonemptyListOf kComma? "}") -- Type + | ("type" "{" NonemptyListOf ","? "}") -- Type + | ("{" NonemptyListOf ","? "}") -- Types + | ("{" NonemptyListOf ","? "}") -- Extended + | (identifier ("," "type"? "{" NonemptyListOf ","? "}")?) -- Mixed + | ("*" ("as" identifier)?) -- All + | (identifier ("as" identifier)?) -- Default + ImportExtendedSelection = TypeImport | Import + ImportExtendedSelectionTypes = TypeImport ImportExtendedSelectionTypeless = Import - Import = identifier (kAs identifier)? - TypeImport = kType Import (kAs identifier)? - - kType = "type" - kImport = "import" - kFrom = "from" - kAs = "as" - kComma = "," + Import = identifier ("as" identifier)? + TypeImport = "type" Import ("as" identifier)? identifier = letter alnum* quote = "\"" | "'" | "`" @@ -36,12 +36,86 @@ JSImports { | "\"" notQuote+ "\"" | "'" notQuote+ "'" | "`" notQuote+ "`" - semicolon = ";" lineTerminator = "\n" | "\r" | "\u2028" | "\u2029" + lineTerminatorSequence = "\n" | "\r" ~"\n" | "\u2028" | "\u2029" | "\r\n" comment = multiLineComment | singleLineComment multiLineComment = "/*" (~"*/" any)* "*/" singleLineComment = "//" (~lineTerminator any)* + + stringLiteral = + | "\"" doubleStringCharacter* "\"" + | "'" singleStringCharacter* "'" + | "`" templateStringCharacter* "`" + doubleStringCharacter = + | ~("\"" | "\\" | lineTerminator) any -- NonEscaped + | "\\" escapeSequence -- Escaped + | lineContinuation -- LineContinuation + singleStringCharacter = + | ~("'" | "\\" | lineTerminator) any -- NonEscaped + | "\\" escapeSequence -- Escaped + | lineContinuation -- LineContinuation + templateStringCharacter = + | ~ ("`" | "\\") any -- NonEscaped + | "\\" escapeSequence -- Escaped + lineContinuation = "\\" lineTerminatorSequence + escapeSequence = unicodeEscapeSequence | hexEscapeSequence | octalEscapeSequence | characterEscapeSequence + characterEscapeSequence = singleEscapeCharacter | nonEscapeCharacter + singleEscapeCharacter = "'" | "\"" | "\\" | "b" | "f" | "n" | "r" | "t" | "v" + nonEscapeCharacter = ~(escapeCharacter | lineTerminator) any + escapeCharacter = singleEscapeCharacter | decimalDigit | "x" | "u" + octalEscapeSequence = + | zeroToThree octalDigit octalDigit -- Whole + | fourToSeven octalDigit -- EightTimesfourToSeven + | zeroToThree octalDigit ~decimalDigit -- EightTimesZeroToThree + | octalDigit ~decimalDigit -- Octal + hexEscapeSequence = "x" hexDigit hexDigit + unicodeEscapeSequence = "u" hexDigit hexDigit hexDigit hexDigit + + zeroToThree = "0".."3" + fourToSeven = "4".."7" + decimalDigit = "0".."9" + nonZeroDigit = "1".."9" + octalDigit = "0".."7" + + regularExpressionLiteral = "/" regularExpressionBody "/" regularExpressionFlags + regularExpressionBody = regularExpressionFirstChar regularExpressionChar* + regularExpressionFirstChar = + | ~("*" | "\\" | "/" | "[") regularExpressionNonTerminator + | regularExpressionBackslashSequence + | regularExpressionClass + regularExpressionChar = ~("\\" | "/" | "[") regularExpressionNonTerminator + | regularExpressionBackslashSequence + | regularExpressionClass + regularExpressionBackslashSequence = "\\" regularExpressionNonTerminator + regularExpressionNonTerminator = ~(lineTerminator) any + regularExpressionClass = "[" regularExpressionClassChar* "]" + regularExpressionClassChar = + | ~("]" | "\\") regularExpressionNonTerminator + | regularExpressionBackslashSequence + regularExpressionFlags = identifierPart* + + multiLineCommentNoNL = "/*" (~("*/" | lineTerminator) any)* "*/" + + identifierStart = + | letter | "$" | "_" + | "\\" unicodeEscapeSequence -- escaped + identifierPart = + | identifierStart | unicodeCombiningMark + | unicodeDigit | unicodeConnectorPunctuation + | "\u200C" | "\u200D" + letter += unicodeCategoryNl + unicodeCategoryNl + = "\u2160".."\u2182" | "\u3007" | "\u3021".."\u3029" + unicodeDigit (a digit) + = "\u0030".."\u0039" | "\u0660".."\u0669" | "\u06F0".."\u06F9" | "\u0966".."\u096F" | "\u09E6".."\u09EF" | "\u0A66".."\u0A6F" | "\u0AE6".."\u0AEF" | "\u0B66".."\u0B6F" | "\u0BE7".."\u0BEF" | "\u0C66".."\u0C6F" | "\u0CE6".."\u0CEF" | "\u0D66".."\u0D6F" | "\u0E50".."\u0E59" | "\u0ED0".."\u0ED9" | "\u0F20".."\u0F29" | "\uFF10".."\uFF19" + + unicodeCombiningMark (a Unicode combining mark) + = "\u0300".."\u0345" | "\u0360".."\u0361" | "\u0483".."\u0486" | "\u0591".."\u05A1" | "\u05A3".."\u05B9" | "\u05BB".."\u05BD" | "\u05BF".."\u05BF" | "\u05C1".."\u05C2" | "\u05C4".."\u05C4" | "\u064B".."\u0652" | "\u0670".."\u0670" | "\u06D6".."\u06DC" | "\u06DF".."\u06E4" | "\u06E7".."\u06E8" | "\u06EA".."\u06ED" | "\u0901".."\u0902" | "\u093C".."\u093C" | "\u0941".."\u0948" | "\u094D".."\u094D" | "\u0951".."\u0954" | "\u0962".."\u0963" | "\u0981".."\u0981" | "\u09BC".."\u09BC" | "\u09C1".."\u09C4" | "\u09CD".."\u09CD" | "\u09E2".."\u09E3" | "\u0A02".."\u0A02" | "\u0A3C".."\u0A3C" | "\u0A41".."\u0A42" | "\u0A47".."\u0A48" | "\u0A4B".."\u0A4D" | "\u0A70".."\u0A71" | "\u0A81".."\u0A82" | "\u0ABC".."\u0ABC" | "\u0AC1".."\u0AC5" | "\u0AC7".."\u0AC8" | "\u0ACD".."\u0ACD" | "\u0B01".."\u0B01" | "\u0B3C".."\u0B3C" | "\u0B3F".."\u0B3F" | "\u0B41".."\u0B43" | "\u0B4D".."\u0B4D" | "\u0B56".."\u0B56" | "\u0B82".."\u0B82" | "\u0BC0".."\u0BC0" | "\u0BCD".."\u0BCD" | "\u0C3E".."\u0C40" | "\u0C46".."\u0C48" | "\u0C4A".."\u0C4D" | "\u0C55".."\u0C56" | "\u0CBF".."\u0CBF" | "\u0CC6".."\u0CC6" | "\u0CCC".."\u0CCD" | "\u0D41".."\u0D43" | "\u0D4D".."\u0D4D" | "\u0E31".."\u0E31" | "\u0E34".."\u0E3A" | "\u0E47".."\u0E4E" | "\u0EB1".."\u0EB1" | "\u0EB4".."\u0EB9" | "\u0EBB".."\u0EBC" | "\u0EC8".."\u0ECD" | "\u0F18".."\u0F19" | "\u0F35".."\u0F35" | "\u0F37".."\u0F37" | "\u0F39".."\u0F39" | "\u0F71".."\u0F7E" | "\u0F80".."\u0F84" | "\u0F86".."\u0F87" | "\u0F90".."\u0F95" | "\u0F97".."\u0F97" | "\u0F99".."\u0FAD" | "\u0FB1".."\u0FB7" | "\u0FB9".."\u0FB9" | "\u20D0".."\u20DC" | "\u20E1".."\u20E1" | "\u302A".."\u302F" | "\u3099".."\u309A" | "\uFB1E".."\uFB1E" | "\uFE20".."\uFE23" + + unicodeConnectorPunctuation = "\u005F" | "\u203F".."\u2040" | "\u30FB" | "\uFE33".."\uFE34" | "\uFE4D".."\uFE4F" | "\uFF3F" | "\uFF65" + unicodeSpaceSeparator = "\u2000".."\u200B" | "\u3000" + } \ No newline at end of file diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts index 3feb5c64b..ed89916a7 100644 --- a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts @@ -14,32 +14,80 @@ import { export interface JSImportsActionDict extends BaseActionDict { JSImports?: (this: NonterminalNode, arg0: IterationNode, arg1: IterationNode) => T; Expr?: (this: NonterminalNode, arg0: NonterminalNode) => T; - ImportExpr_From?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode, arg2: NonterminalNode, arg3: NonterminalNode) => T; - ImportExpr_NoFrom?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode) => T; + ImportExpr_From?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: TerminalNode, arg3: NonterminalNode) => T; + ImportExpr_NoFrom?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; ImportExpr?: (this: NonterminalNode, arg0: NonterminalNode) => T; Rest?: (this: NonterminalNode, arg0: IterationNode) => T; - ImportInner_Default?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: IterationNode) => T; - ImportInner_Extended?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: IterationNode, arg3: TerminalNode) => T; ImportInner_Type?: (this: NonterminalNode, arg0: TerminalNode, arg1: TerminalNode, arg2: NonterminalNode, arg3: IterationNode, arg4: TerminalNode) => T; + ImportInner_Types?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: IterationNode, arg3: TerminalNode) => T; + ImportInner_Extended?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: IterationNode, arg3: TerminalNode) => T; + ImportInner_Mixed?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode, arg3: IterationNode, arg4: IterationNode, arg5: IterationNode, arg6: IterationNode) => T; + ImportInner_All?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: IterationNode) => T; + ImportInner_Default?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode) => T; ImportInner?: (this: NonterminalNode, arg0: NonterminalNode) => T; ImportExtendedSelection?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelectionTypes?: (this: NonterminalNode, arg0: NonterminalNode) => T; ImportExtendedSelectionTypeless?: (this: NonterminalNode, arg0: NonterminalNode) => T; Import?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode) => T; - TypeImport?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode, arg2: IterationNode, arg3: IterationNode) => T; - kType?: (this: NonterminalNode, arg0: TerminalNode) => T; - kImport?: (this: NonterminalNode, arg0: TerminalNode) => T; - kFrom?: (this: NonterminalNode, arg0: TerminalNode) => T; - kAs?: (this: NonterminalNode, arg0: TerminalNode) => T; - kComma?: (this: NonterminalNode, arg0: TerminalNode) => T; + TypeImport?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: IterationNode, arg3: IterationNode) => T; identifier?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T; quote?: (this: NonterminalNode, arg0: TerminalNode) => T; notQuote?: (this: NonterminalNode, arg0: NonterminalNode) => T; importSource?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; - semicolon?: (this: NonterminalNode, arg0: TerminalNode) => T; lineTerminator?: (this: NonterminalNode, arg0: TerminalNode) => T; + lineTerminatorSequence?: (this: NonterminalNode, arg0: TerminalNode) => T; comment?: (this: NonterminalNode, arg0: NonterminalNode) => T; multiLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; singleLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode) => T; + stringLiteral?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + doubleStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + doubleStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + doubleStringCharacter_LineContinuation?: (this: NonterminalNode, arg0: NonterminalNode) => T; + doubleStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + singleStringCharacter_LineContinuation?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + templateStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + templateStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + templateStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + lineContinuation?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + escapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + characterEscapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleEscapeCharacter?: (this: NonterminalNode, arg0: TerminalNode) => T; + nonEscapeCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + escapeCharacter?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + octalEscapeSequence_Whole?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode, arg2: NonterminalNode) => T; + octalEscapeSequence_EightTimesfourToSeven?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode) => T; + octalEscapeSequence_EightTimesZeroToThree?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode) => T; + octalEscapeSequence_Octal?: (this: NonterminalNode, arg0: NonterminalNode) => T; + octalEscapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + hexEscapeSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: NonterminalNode) => T; + unicodeEscapeSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: NonterminalNode, arg3: NonterminalNode, arg4: NonterminalNode) => T; + zeroToThree?: (this: NonterminalNode, arg0: TerminalNode) => T; + fourToSeven?: (this: NonterminalNode, arg0: TerminalNode) => T; + decimalDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + nonZeroDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + octalDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + regularExpressionLiteral?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: TerminalNode, arg3: NonterminalNode) => T; + regularExpressionBody?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T; + regularExpressionFirstChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionBackslashSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + regularExpressionNonTerminator?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionClass?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + regularExpressionClassChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionFlags?: (this: NonterminalNode, arg0: IterationNode) => T; + multiLineCommentNoNL?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + identifierStart_escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + identifierStart?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + identifierPart?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + letter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + unicodeCategoryNl?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeCombiningMark?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeConnectorPunctuation?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeSpaceSeparator?: (this: NonterminalNode, arg0: TerminalNode) => T; } export interface JSImportsSemantics extends Semantics { diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js index 76be00861..2d473fc8d 100644 --- a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js @@ -1 +1 @@ -import {makeRecipe} from 'ohm-js';const result=makeRecipe(["grammar",{"source":"JSImports {\n JSImports = (Expr semicolon?)*\n\n Expr = \n | comment\n | ImportExpr\n | Rest\n\n ImportExpr =\n | kImport ImportInner kFrom importSource -- From\n | kImport importSource -- NoFrom\n\n Rest = (~ImportExpr any)+\n\n ImportInner = \n | (\"*\" (kAs identifier)?) -- Default\n | (\"{\" NonemptyListOf kComma? \"}\") -- Extended\n | (\"type\" \"{\" NonemptyListOf kComma? \"}\") -- Type\n\n ImportExtendedSelection = TypeImport | Import\n ImportExtendedSelectionTypeless = Import\n\n Import = identifier (kAs identifier)?\n TypeImport = kType Import (kAs identifier)?\n\n kType = \"type\"\n kImport = \"import\"\n kFrom = \"from\"\n kAs = \"as\"\n kComma = \",\"\n\n identifier = letter alnum*\n quote = \"\\\"\" | \"'\" | \"`\"\n notQuote = ~quote any\n importSource =\n | \"\\\"\" notQuote+ \"\\\"\"\n | \"'\" notQuote+ \"'\"\n | \"`\" notQuote+ \"`\"\n semicolon = \";\"\n\n lineTerminator = \"\\n\" | \"\\r\" | \"\\u2028\" | \"\\u2029\"\n \n comment = multiLineComment | singleLineComment\n\n multiLineComment = \"/*\" (~\"*/\" any)* \"*/\"\n singleLineComment = \"//\" (~lineTerminator any)*\n}"},"JSImports",null,"JSImports",{"JSImports":["define",{"sourceInterval":[16,46]},null,[],["star",{"sourceInterval":[28,46]},["seq",{"sourceInterval":[29,44]},["app",{"sourceInterval":[29,33]},"Expr",[]],["opt",{"sourceInterval":[34,44]},["app",{"sourceInterval":[34,43]},"semicolon",[]]]]]],"Expr":["define",{"sourceInterval":[52,101]},null,[],["alt",{"sourceInterval":[64,101]},["app",{"sourceInterval":[66,73]},"comment",[]],["app",{"sourceInterval":[80,90]},"ImportExpr",[]],["app",{"sourceInterval":[97,101]},"Rest",[]]]],"ImportExpr_From":["define",{"sourceInterval":[126,172]},null,[],["seq",{"sourceInterval":[126,164]},["app",{"sourceInterval":[126,133]},"kImport",[]],["app",{"sourceInterval":[134,145]},"ImportInner",[]],["app",{"sourceInterval":[146,151]},"kFrom",[]],["app",{"sourceInterval":[152,164]},"importSource",[]]]],"ImportExpr_NoFrom":["define",{"sourceInterval":[179,209]},null,[],["seq",{"sourceInterval":[179,199]},["app",{"sourceInterval":[179,186]},"kImport",[]],["app",{"sourceInterval":[187,199]},"importSource",[]]]],"ImportExpr":["define",{"sourceInterval":[107,209]},null,[],["alt",{"sourceInterval":[124,209]},["app",{"sourceInterval":[126,164]},"ImportExpr_From",[]],["app",{"sourceInterval":[179,199]},"ImportExpr_NoFrom",[]]]],"Rest":["define",{"sourceInterval":[215,240]},null,[],["plus",{"sourceInterval":[222,240]},["seq",{"sourceInterval":[223,238]},["not",{"sourceInterval":[223,234]},["app",{"sourceInterval":[224,234]},"ImportExpr",[]]],["app",{"sourceInterval":[235,238]},"any",[]]]]],"ImportInner_Default":["define",{"sourceInterval":[267,301]},null,[],["seq",{"sourceInterval":[267,290]},["terminal",{"sourceInterval":[268,271]},"*"],["opt",{"sourceInterval":[272,289]},["seq",{"sourceInterval":[273,287]},["app",{"sourceInterval":[273,276]},"kAs",[]],["app",{"sourceInterval":[277,287]},"identifier",[]]]]]],"ImportInner_Extended":["define",{"sourceInterval":[308,385]},null,[],["seq",{"sourceInterval":[308,373]},["terminal",{"sourceInterval":[309,312]},"{"],["app",{"sourceInterval":[313,360]},"NonemptyListOf",[["app",{"sourceInterval":[328,351]},"ImportExtendedSelection",[]],["app",{"sourceInterval":[353,359]},"kComma",[]]]],["opt",{"sourceInterval":[361,368]},["app",{"sourceInterval":[361,367]},"kComma",[]]],["terminal",{"sourceInterval":[369,372]},"}"]]],"ImportInner_Type":["define",{"sourceInterval":[392,480]},null,[],["seq",{"sourceInterval":[392,472]},["terminal",{"sourceInterval":[393,399]},"type"],["terminal",{"sourceInterval":[400,403]},"{"],["app",{"sourceInterval":[404,459]},"NonemptyListOf",[["app",{"sourceInterval":[419,450]},"ImportExtendedSelectionTypeless",[]],["app",{"sourceInterval":[452,458]},"kComma",[]]]],["opt",{"sourceInterval":[460,467]},["app",{"sourceInterval":[460,466]},"kComma",[]]],["terminal",{"sourceInterval":[468,471]},"}"]]],"ImportInner":["define",{"sourceInterval":[246,480]},null,[],["alt",{"sourceInterval":[265,480]},["app",{"sourceInterval":[267,290]},"ImportInner_Default",[]],["app",{"sourceInterval":[308,373]},"ImportInner_Extended",[]],["app",{"sourceInterval":[392,472]},"ImportInner_Type",[]]]],"ImportExtendedSelection":["define",{"sourceInterval":[486,531]},null,[],["alt",{"sourceInterval":[512,531]},["app",{"sourceInterval":[512,522]},"TypeImport",[]],["app",{"sourceInterval":[525,531]},"Import",[]]]],"ImportExtendedSelectionTypeless":["define",{"sourceInterval":[536,576]},null,[],["app",{"sourceInterval":[570,576]},"Import",[]]],"Import":["define",{"sourceInterval":[582,619]},null,[],["seq",{"sourceInterval":[591,619]},["app",{"sourceInterval":[591,601]},"identifier",[]],["opt",{"sourceInterval":[602,619]},["seq",{"sourceInterval":[603,617]},["app",{"sourceInterval":[603,606]},"kAs",[]],["app",{"sourceInterval":[607,617]},"identifier",[]]]]]],"TypeImport":["define",{"sourceInterval":[624,667]},null,[],["seq",{"sourceInterval":[637,667]},["app",{"sourceInterval":[637,642]},"kType",[]],["app",{"sourceInterval":[643,649]},"Import",[]],["opt",{"sourceInterval":[650,667]},["seq",{"sourceInterval":[651,665]},["app",{"sourceInterval":[651,654]},"kAs",[]],["app",{"sourceInterval":[655,665]},"identifier",[]]]]]],"kType":["define",{"sourceInterval":[673,687]},null,[],["terminal",{"sourceInterval":[681,687]},"type"]],"kImport":["define",{"sourceInterval":[692,710]},null,[],["terminal",{"sourceInterval":[702,710]},"import"]],"kFrom":["define",{"sourceInterval":[715,729]},null,[],["terminal",{"sourceInterval":[723,729]},"from"]],"kAs":["define",{"sourceInterval":[734,744]},null,[],["terminal",{"sourceInterval":[740,744]},"as"]],"kComma":["define",{"sourceInterval":[749,761]},null,[],["terminal",{"sourceInterval":[758,761]},","]],"identifier":["define",{"sourceInterval":[767,793]},null,[],["seq",{"sourceInterval":[780,793]},["app",{"sourceInterval":[780,786]},"letter",[]],["star",{"sourceInterval":[787,793]},["app",{"sourceInterval":[787,792]},"alnum",[]]]]],"quote":["define",{"sourceInterval":[798,822]},null,[],["alt",{"sourceInterval":[806,822]},["terminal",{"sourceInterval":[806,810]},"\""],["terminal",{"sourceInterval":[813,816]},"'"],["terminal",{"sourceInterval":[819,822]},"`"]]],"notQuote":["define",{"sourceInterval":[827,848]},null,[],["seq",{"sourceInterval":[838,848]},["not",{"sourceInterval":[838,844]},["app",{"sourceInterval":[839,844]},"quote",[]]],["app",{"sourceInterval":[845,848]},"any",[]]]],"importSource":["define",{"sourceInterval":[853,941]},null,[],["alt",{"sourceInterval":[872,941]},["seq",{"sourceInterval":[874,893]},["terminal",{"sourceInterval":[874,878]},"\""],["plus",{"sourceInterval":[879,888]},["app",{"sourceInterval":[879,887]},"notQuote",[]]],["terminal",{"sourceInterval":[889,893]},"\""]],["seq",{"sourceInterval":[900,917]},["terminal",{"sourceInterval":[900,903]},"'"],["plus",{"sourceInterval":[904,913]},["app",{"sourceInterval":[904,912]},"notQuote",[]]],["terminal",{"sourceInterval":[914,917]},"'"]],["seq",{"sourceInterval":[924,941]},["terminal",{"sourceInterval":[924,927]},"`"],["plus",{"sourceInterval":[928,937]},["app",{"sourceInterval":[928,936]},"notQuote",[]]],["terminal",{"sourceInterval":[938,941]},"`"]]]],"semicolon":["define",{"sourceInterval":[946,961]},null,[],["terminal",{"sourceInterval":[958,961]},";"]],"lineTerminator":["define",{"sourceInterval":[967,1017]},null,[],["alt",{"sourceInterval":[984,1017]},["terminal",{"sourceInterval":[984,988]},"\n"],["terminal",{"sourceInterval":[991,995]},"\r"],["terminal",{"sourceInterval":[998,1006]},"\u2028"],["terminal",{"sourceInterval":[1009,1017]},"\u2029"]]],"comment":["define",{"sourceInterval":[1027,1073]},null,[],["alt",{"sourceInterval":[1037,1073]},["app",{"sourceInterval":[1037,1053]},"multiLineComment",[]],["app",{"sourceInterval":[1056,1073]},"singleLineComment",[]]]],"multiLineComment":["define",{"sourceInterval":[1079,1120]},null,[],["seq",{"sourceInterval":[1098,1120]},["terminal",{"sourceInterval":[1098,1102]},"/*"],["star",{"sourceInterval":[1103,1115]},["seq",{"sourceInterval":[1104,1113]},["not",{"sourceInterval":[1104,1109]},["terminal",{"sourceInterval":[1105,1109]},"*/"]],["app",{"sourceInterval":[1110,1113]},"any",[]]]],["terminal",{"sourceInterval":[1116,1120]},"*/"]]],"singleLineComment":["define",{"sourceInterval":[1125,1172]},null,[],["seq",{"sourceInterval":[1145,1172]},["terminal",{"sourceInterval":[1145,1149]},"//"],["star",{"sourceInterval":[1150,1172]},["seq",{"sourceInterval":[1151,1170]},["not",{"sourceInterval":[1151,1166]},["app",{"sourceInterval":[1152,1166]},"lineTerminator",[]]],["app",{"sourceInterval":[1167,1170]},"any",[]]]]]]}]);export default result; \ No newline at end of file +import {makeRecipe} from 'ohm-js';const result=makeRecipe(["grammar",{"source":"JSImports {\n JSImports = (Expr \";\"?)*\n\n Expr = \n | comment\n | stringLiteral\n | ImportExpr\n | Rest\n\n ImportExpr =\n | \"import\" ImportInner \"from\" importSource -- From\n | \"import\" importSource -- NoFrom\n\n Rest = (~(ImportExpr | comment | stringLiteral) any)+\n\n ImportInner = \n | (\"type\" \"{\" NonemptyListOf \",\"? \"}\") -- Type\n | (\"{\" NonemptyListOf \",\"? \"}\") -- Types\n | (\"{\" NonemptyListOf \",\"? \"}\") -- Extended\n | (identifier (\",\" \"type\"? \"{\" NonemptyListOf \",\"? \"}\")?) -- Mixed\n | (\"*\" (\"as\" identifier)?) -- All\n | (identifier (\"as\" identifier)?) -- Default\n \n\n ImportExtendedSelection = TypeImport | Import\n ImportExtendedSelectionTypes = TypeImport\n ImportExtendedSelectionTypeless = Import\n\n Import = identifier (\"as\" identifier)?\n TypeImport = \"type\" Import (\"as\" identifier)?\n\n identifier = letter alnum*\n quote = \"\\\"\" | \"'\" | \"`\"\n notQuote = ~quote any\n importSource =\n | \"\\\"\" notQuote+ \"\\\"\"\n | \"'\" notQuote+ \"'\"\n | \"`\" notQuote+ \"`\"\n\n lineTerminator = \"\\n\" | \"\\r\" | \"\\u2028\" | \"\\u2029\"\n lineTerminatorSequence = \"\\n\" | \"\\r\" ~\"\\n\" | \"\\u2028\" | \"\\u2029\" | \"\\r\\n\"\n \n comment = multiLineComment | singleLineComment\n\n multiLineComment = \"/*\" (~\"*/\" any)* \"*/\"\n singleLineComment = \"//\" (~lineTerminator any)*\n\n stringLiteral =\n | \"\\\"\" doubleStringCharacter* \"\\\"\"\n | \"'\" singleStringCharacter* \"'\"\n | \"`\" templateStringCharacter* \"`\"\n doubleStringCharacter =\n | ~(\"\\\"\" | \"\\\\\" | lineTerminator) any -- NonEscaped\n | \"\\\\\" escapeSequence -- Escaped\n | lineContinuation -- LineContinuation\n singleStringCharacter =\n | ~(\"'\" | \"\\\\\" | lineTerminator) any -- NonEscaped\n | \"\\\\\" escapeSequence -- Escaped\n | lineContinuation -- LineContinuation\n templateStringCharacter = \n | ~ (\"`\" | \"\\\\\") any -- NonEscaped\n | \"\\\\\" escapeSequence -- Escaped\n lineContinuation = \"\\\\\" lineTerminatorSequence\n escapeSequence = unicodeEscapeSequence | hexEscapeSequence | octalEscapeSequence | characterEscapeSequence\n characterEscapeSequence = singleEscapeCharacter | nonEscapeCharacter\n singleEscapeCharacter = \"'\" | \"\\\"\" | \"\\\\\" | \"b\" | \"f\" | \"n\" | \"r\" | \"t\" | \"v\"\n nonEscapeCharacter = ~(escapeCharacter | lineTerminator) any\n escapeCharacter = singleEscapeCharacter | decimalDigit | \"x\" | \"u\"\n octalEscapeSequence =\n | zeroToThree octalDigit octalDigit -- Whole\n | fourToSeven octalDigit -- EightTimesfourToSeven\n | zeroToThree octalDigit ~decimalDigit -- EightTimesZeroToThree\n | octalDigit ~decimalDigit -- Octal\n hexEscapeSequence = \"x\" hexDigit hexDigit\n unicodeEscapeSequence = \"u\" hexDigit hexDigit hexDigit hexDigit\n\n zeroToThree = \"0\"..\"3\"\n fourToSeven = \"4\"..\"7\"\n decimalDigit = \"0\"..\"9\"\n nonZeroDigit = \"1\"..\"9\"\n octalDigit = \"0\"..\"7\"\n\n regularExpressionLiteral = \"/\" regularExpressionBody \"/\" regularExpressionFlags\n regularExpressionBody = regularExpressionFirstChar regularExpressionChar*\n regularExpressionFirstChar =\n | ~(\"*\" | \"\\\\\" | \"/\" | \"[\") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n | regularExpressionClass\n regularExpressionChar = ~(\"\\\\\" | \"/\" | \"[\") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n | regularExpressionClass\n regularExpressionBackslashSequence = \"\\\\\" regularExpressionNonTerminator\n regularExpressionNonTerminator = ~(lineTerminator) any\n regularExpressionClass = \"[\" regularExpressionClassChar* \"]\"\n regularExpressionClassChar =\n | ~(\"]\" | \"\\\\\") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n regularExpressionFlags = identifierPart*\n\n multiLineCommentNoNL = \"/*\" (~(\"*/\" | lineTerminator) any)* \"*/\"\n\n identifierStart =\n | letter | \"$\" | \"_\"\n | \"\\\\\" unicodeEscapeSequence -- escaped\n identifierPart =\n | identifierStart | unicodeCombiningMark\n | unicodeDigit | unicodeConnectorPunctuation\n | \"\\u200C\" | \"\\u200D\"\n letter += unicodeCategoryNl\n unicodeCategoryNl\n = \"\\u2160\"..\"\\u2182\" | \"\\u3007\" | \"\\u3021\"..\"\\u3029\"\n unicodeDigit (a digit)\n = \"\\u0030\"..\"\\u0039\" | \"\\u0660\"..\"\\u0669\" | \"\\u06F0\"..\"\\u06F9\" | \"\\u0966\"..\"\\u096F\" | \"\\u09E6\"..\"\\u09EF\" | \"\\u0A66\"..\"\\u0A6F\" | \"\\u0AE6\"..\"\\u0AEF\" | \"\\u0B66\"..\"\\u0B6F\" | \"\\u0BE7\"..\"\\u0BEF\" | \"\\u0C66\"..\"\\u0C6F\" | \"\\u0CE6\"..\"\\u0CEF\" | \"\\u0D66\"..\"\\u0D6F\" | \"\\u0E50\"..\"\\u0E59\" | \"\\u0ED0\"..\"\\u0ED9\" | \"\\u0F20\"..\"\\u0F29\" | \"\\uFF10\"..\"\\uFF19\"\n\n unicodeCombiningMark (a Unicode combining mark)\n = \"\\u0300\"..\"\\u0345\" | \"\\u0360\"..\"\\u0361\" | \"\\u0483\"..\"\\u0486\" | \"\\u0591\"..\"\\u05A1\" | \"\\u05A3\"..\"\\u05B9\" | \"\\u05BB\"..\"\\u05BD\" | \"\\u05BF\"..\"\\u05BF\" | \"\\u05C1\"..\"\\u05C2\" | \"\\u05C4\"..\"\\u05C4\" | \"\\u064B\"..\"\\u0652\" | \"\\u0670\"..\"\\u0670\" | \"\\u06D6\"..\"\\u06DC\" | \"\\u06DF\"..\"\\u06E4\" | \"\\u06E7\"..\"\\u06E8\" | \"\\u06EA\"..\"\\u06ED\" | \"\\u0901\"..\"\\u0902\" | \"\\u093C\"..\"\\u093C\" | \"\\u0941\"..\"\\u0948\" | \"\\u094D\"..\"\\u094D\" | \"\\u0951\"..\"\\u0954\" | \"\\u0962\"..\"\\u0963\" | \"\\u0981\"..\"\\u0981\" | \"\\u09BC\"..\"\\u09BC\" | \"\\u09C1\"..\"\\u09C4\" | \"\\u09CD\"..\"\\u09CD\" | \"\\u09E2\"..\"\\u09E3\" | \"\\u0A02\"..\"\\u0A02\" | \"\\u0A3C\"..\"\\u0A3C\" | \"\\u0A41\"..\"\\u0A42\" | \"\\u0A47\"..\"\\u0A48\" | \"\\u0A4B\"..\"\\u0A4D\" | \"\\u0A70\"..\"\\u0A71\" | \"\\u0A81\"..\"\\u0A82\" | \"\\u0ABC\"..\"\\u0ABC\" | \"\\u0AC1\"..\"\\u0AC5\" | \"\\u0AC7\"..\"\\u0AC8\" | \"\\u0ACD\"..\"\\u0ACD\" | \"\\u0B01\"..\"\\u0B01\" | \"\\u0B3C\"..\"\\u0B3C\" | \"\\u0B3F\"..\"\\u0B3F\" | \"\\u0B41\"..\"\\u0B43\" | \"\\u0B4D\"..\"\\u0B4D\" | \"\\u0B56\"..\"\\u0B56\" | \"\\u0B82\"..\"\\u0B82\" | \"\\u0BC0\"..\"\\u0BC0\" | \"\\u0BCD\"..\"\\u0BCD\" | \"\\u0C3E\"..\"\\u0C40\" | \"\\u0C46\"..\"\\u0C48\" | \"\\u0C4A\"..\"\\u0C4D\" | \"\\u0C55\"..\"\\u0C56\" | \"\\u0CBF\"..\"\\u0CBF\" | \"\\u0CC6\"..\"\\u0CC6\" | \"\\u0CCC\"..\"\\u0CCD\" | \"\\u0D41\"..\"\\u0D43\" | \"\\u0D4D\"..\"\\u0D4D\" | \"\\u0E31\"..\"\\u0E31\" | \"\\u0E34\"..\"\\u0E3A\" | \"\\u0E47\"..\"\\u0E4E\" | \"\\u0EB1\"..\"\\u0EB1\" | \"\\u0EB4\"..\"\\u0EB9\" | \"\\u0EBB\"..\"\\u0EBC\" | \"\\u0EC8\"..\"\\u0ECD\" | \"\\u0F18\"..\"\\u0F19\" | \"\\u0F35\"..\"\\u0F35\" | \"\\u0F37\"..\"\\u0F37\" | \"\\u0F39\"..\"\\u0F39\" | \"\\u0F71\"..\"\\u0F7E\" | \"\\u0F80\"..\"\\u0F84\" | \"\\u0F86\"..\"\\u0F87\" | \"\\u0F90\"..\"\\u0F95\" | \"\\u0F97\"..\"\\u0F97\" | \"\\u0F99\"..\"\\u0FAD\" | \"\\u0FB1\"..\"\\u0FB7\" | \"\\u0FB9\"..\"\\u0FB9\" | \"\\u20D0\"..\"\\u20DC\" | \"\\u20E1\"..\"\\u20E1\" | \"\\u302A\"..\"\\u302F\" | \"\\u3099\"..\"\\u309A\" | \"\\uFB1E\"..\"\\uFB1E\" | \"\\uFE20\"..\"\\uFE23\"\n\n unicodeConnectorPunctuation = \"\\u005F\" | \"\\u203F\"..\"\\u2040\" | \"\\u30FB\" | \"\\uFE33\"..\"\\uFE34\" | \"\\uFE4D\"..\"\\uFE4F\" | \"\\uFF3F\" | \"\\uFF65\"\n unicodeSpaceSeparator = \"\\u2000\"..\"\\u200B\" | \"\\u3000\"\n\n}"},"JSImports",null,"JSImports",{"JSImports":["define",{"sourceInterval":[16,40]},null,[],["star",{"sourceInterval":[28,40]},["seq",{"sourceInterval":[29,38]},["app",{"sourceInterval":[29,33]},"Expr",[]],["opt",{"sourceInterval":[34,38]},["terminal",{"sourceInterval":[34,37]},";"]]]]],"Expr":["define",{"sourceInterval":[46,115]},null,[],["alt",{"sourceInterval":[58,115]},["app",{"sourceInterval":[60,67]},"comment",[]],["app",{"sourceInterval":[74,87]},"stringLiteral",[]],["app",{"sourceInterval":[94,104]},"ImportExpr",[]],["app",{"sourceInterval":[111,115]},"Rest",[]]]],"ImportExpr_From":["define",{"sourceInterval":[140,188]},null,[],["seq",{"sourceInterval":[140,180]},["terminal",{"sourceInterval":[140,148]},"import"],["app",{"sourceInterval":[149,160]},"ImportInner",[]],["terminal",{"sourceInterval":[161,167]},"from"],["app",{"sourceInterval":[168,180]},"importSource",[]]]],"ImportExpr_NoFrom":["define",{"sourceInterval":[195,226]},null,[],["seq",{"sourceInterval":[195,216]},["terminal",{"sourceInterval":[195,203]},"import"],["app",{"sourceInterval":[204,216]},"importSource",[]]]],"ImportExpr":["define",{"sourceInterval":[121,226]},null,[],["alt",{"sourceInterval":[138,226]},["app",{"sourceInterval":[140,180]},"ImportExpr_From",[]],["app",{"sourceInterval":[195,216]},"ImportExpr_NoFrom",[]]]],"Rest":["define",{"sourceInterval":[232,285]},null,[],["plus",{"sourceInterval":[239,285]},["seq",{"sourceInterval":[240,283]},["not",{"sourceInterval":[240,279]},["alt",{"sourceInterval":[242,278]},["app",{"sourceInterval":[242,252]},"ImportExpr",[]],["app",{"sourceInterval":[255,262]},"comment",[]],["app",{"sourceInterval":[265,278]},"stringLiteral",[]]]],["app",{"sourceInterval":[280,283]},"any",[]]]]],"ImportInner_Type":["define",{"sourceInterval":[312,405]},null,[],["seq",{"sourceInterval":[312,386]},["terminal",{"sourceInterval":[313,319]},"type"],["terminal",{"sourceInterval":[320,323]},"{"],["app",{"sourceInterval":[324,376]},"NonemptyListOf",[["app",{"sourceInterval":[339,370]},"ImportExtendedSelectionTypeless",[]],["terminal",{"sourceInterval":[372,375]},","]]],["opt",{"sourceInterval":[377,381]},["terminal",{"sourceInterval":[377,380]},","]],["terminal",{"sourceInterval":[382,385]},"}"]]],"ImportInner_Types":["define",{"sourceInterval":[412,506]},null,[],["seq",{"sourceInterval":[412,476]},["terminal",{"sourceInterval":[413,416]},"{"],["app",{"sourceInterval":[417,466]},"NonemptyListOf",[["app",{"sourceInterval":[432,460]},"ImportExtendedSelectionTypes",[]],["terminal",{"sourceInterval":[462,465]},","]]],["opt",{"sourceInterval":[467,471]},["terminal",{"sourceInterval":[467,470]},","]],["terminal",{"sourceInterval":[472,475]},"}"]]],"ImportInner_Extended":["define",{"sourceInterval":[513,610]},null,[],["seq",{"sourceInterval":[513,572]},["terminal",{"sourceInterval":[514,517]},"{"],["app",{"sourceInterval":[518,562]},"NonemptyListOf",[["app",{"sourceInterval":[533,556]},"ImportExtendedSelection",[]],["terminal",{"sourceInterval":[558,561]},","]]],["opt",{"sourceInterval":[563,567]},["terminal",{"sourceInterval":[563,566]},","]],["terminal",{"sourceInterval":[568,571]},"}"]]],"ImportInner_Mixed":["define",{"sourceInterval":[617,711]},null,[],["seq",{"sourceInterval":[617,702]},["app",{"sourceInterval":[618,628]},"identifier",[]],["opt",{"sourceInterval":[629,701]},["seq",{"sourceInterval":[630,699]},["terminal",{"sourceInterval":[630,633]},","],["opt",{"sourceInterval":[634,641]},["terminal",{"sourceInterval":[634,640]},"type"]],["terminal",{"sourceInterval":[642,645]},"{"],["app",{"sourceInterval":[646,690]},"NonemptyListOf",[["app",{"sourceInterval":[661,684]},"ImportExtendedSelection",[]],["terminal",{"sourceInterval":[686,689]},","]]],["opt",{"sourceInterval":[691,695]},["terminal",{"sourceInterval":[691,694]},","]],["terminal",{"sourceInterval":[696,699]},"}"]]]]],"ImportInner_All":["define",{"sourceInterval":[718,810]},null,[],["seq",{"sourceInterval":[718,742]},["terminal",{"sourceInterval":[719,722]},"*"],["opt",{"sourceInterval":[723,741]},["seq",{"sourceInterval":[724,739]},["terminal",{"sourceInterval":[724,728]},"as"],["app",{"sourceInterval":[729,739]},"identifier",[]]]]]],"ImportInner_Default":["define",{"sourceInterval":[817,913]},null,[],["seq",{"sourceInterval":[817,848]},["app",{"sourceInterval":[818,828]},"identifier",[]],["opt",{"sourceInterval":[829,847]},["seq",{"sourceInterval":[830,845]},["terminal",{"sourceInterval":[830,834]},"as"],["app",{"sourceInterval":[835,845]},"identifier",[]]]]]],"ImportInner":["define",{"sourceInterval":[291,913]},null,[],["alt",{"sourceInterval":[310,913]},["app",{"sourceInterval":[312,386]},"ImportInner_Type",[]],["app",{"sourceInterval":[412,476]},"ImportInner_Types",[]],["app",{"sourceInterval":[513,572]},"ImportInner_Extended",[]],["app",{"sourceInterval":[617,702]},"ImportInner_Mixed",[]],["app",{"sourceInterval":[718,742]},"ImportInner_All",[]],["app",{"sourceInterval":[817,848]},"ImportInner_Default",[]]]],"ImportExtendedSelection":["define",{"sourceInterval":[924,969]},null,[],["alt",{"sourceInterval":[950,969]},["app",{"sourceInterval":[950,960]},"TypeImport",[]],["app",{"sourceInterval":[963,969]},"Import",[]]]],"ImportExtendedSelectionTypes":["define",{"sourceInterval":[974,1015]},null,[],["app",{"sourceInterval":[1005,1015]},"TypeImport",[]]],"ImportExtendedSelectionTypeless":["define",{"sourceInterval":[1020,1060]},null,[],["app",{"sourceInterval":[1054,1060]},"Import",[]]],"Import":["define",{"sourceInterval":[1066,1104]},null,[],["seq",{"sourceInterval":[1075,1104]},["app",{"sourceInterval":[1075,1085]},"identifier",[]],["opt",{"sourceInterval":[1086,1104]},["seq",{"sourceInterval":[1087,1102]},["terminal",{"sourceInterval":[1087,1091]},"as"],["app",{"sourceInterval":[1092,1102]},"identifier",[]]]]]],"TypeImport":["define",{"sourceInterval":[1109,1154]},null,[],["seq",{"sourceInterval":[1122,1154]},["terminal",{"sourceInterval":[1122,1128]},"type"],["app",{"sourceInterval":[1129,1135]},"Import",[]],["opt",{"sourceInterval":[1136,1154]},["seq",{"sourceInterval":[1137,1152]},["terminal",{"sourceInterval":[1137,1141]},"as"],["app",{"sourceInterval":[1142,1152]},"identifier",[]]]]]],"identifier":["define",{"sourceInterval":[1160,1186]},null,[],["seq",{"sourceInterval":[1173,1186]},["app",{"sourceInterval":[1173,1179]},"letter",[]],["star",{"sourceInterval":[1180,1186]},["app",{"sourceInterval":[1180,1185]},"alnum",[]]]]],"quote":["define",{"sourceInterval":[1191,1215]},null,[],["alt",{"sourceInterval":[1199,1215]},["terminal",{"sourceInterval":[1199,1203]},"\""],["terminal",{"sourceInterval":[1206,1209]},"'"],["terminal",{"sourceInterval":[1212,1215]},"`"]]],"notQuote":["define",{"sourceInterval":[1220,1241]},null,[],["seq",{"sourceInterval":[1231,1241]},["not",{"sourceInterval":[1231,1237]},["app",{"sourceInterval":[1232,1237]},"quote",[]]],["app",{"sourceInterval":[1238,1241]},"any",[]]]],"importSource":["define",{"sourceInterval":[1246,1334]},null,[],["alt",{"sourceInterval":[1265,1334]},["seq",{"sourceInterval":[1267,1286]},["terminal",{"sourceInterval":[1267,1271]},"\""],["plus",{"sourceInterval":[1272,1281]},["app",{"sourceInterval":[1272,1280]},"notQuote",[]]],["terminal",{"sourceInterval":[1282,1286]},"\""]],["seq",{"sourceInterval":[1293,1310]},["terminal",{"sourceInterval":[1293,1296]},"'"],["plus",{"sourceInterval":[1297,1306]},["app",{"sourceInterval":[1297,1305]},"notQuote",[]]],["terminal",{"sourceInterval":[1307,1310]},"'"]],["seq",{"sourceInterval":[1317,1334]},["terminal",{"sourceInterval":[1317,1320]},"`"],["plus",{"sourceInterval":[1321,1330]},["app",{"sourceInterval":[1321,1329]},"notQuote",[]]],["terminal",{"sourceInterval":[1331,1334]},"`"]]]],"lineTerminator":["define",{"sourceInterval":[1340,1390]},null,[],["alt",{"sourceInterval":[1357,1390]},["terminal",{"sourceInterval":[1357,1361]},"\n"],["terminal",{"sourceInterval":[1364,1368]},"\r"],["terminal",{"sourceInterval":[1371,1379]},"\u2028"],["terminal",{"sourceInterval":[1382,1390]},"\u2029"]]],"lineTerminatorSequence":["define",{"sourceInterval":[1395,1468]},null,[],["alt",{"sourceInterval":[1420,1468]},["terminal",{"sourceInterval":[1420,1424]},"\n"],["seq",{"sourceInterval":[1427,1437]},["terminal",{"sourceInterval":[1427,1431]},"\r"],["not",{"sourceInterval":[1432,1437]},["terminal",{"sourceInterval":[1433,1437]},"\n"]]],["terminal",{"sourceInterval":[1440,1448]},"\u2028"],["terminal",{"sourceInterval":[1451,1459]},"\u2029"],["terminal",{"sourceInterval":[1462,1468]},"\r\n"]]],"comment":["define",{"sourceInterval":[1478,1524]},null,[],["alt",{"sourceInterval":[1488,1524]},["app",{"sourceInterval":[1488,1504]},"multiLineComment",[]],["app",{"sourceInterval":[1507,1524]},"singleLineComment",[]]]],"multiLineComment":["define",{"sourceInterval":[1530,1571]},null,[],["seq",{"sourceInterval":[1549,1571]},["terminal",{"sourceInterval":[1549,1553]},"/*"],["star",{"sourceInterval":[1554,1566]},["seq",{"sourceInterval":[1555,1564]},["not",{"sourceInterval":[1555,1560]},["terminal",{"sourceInterval":[1556,1560]},"*/"]],["app",{"sourceInterval":[1561,1564]},"any",[]]]],["terminal",{"sourceInterval":[1567,1571]},"*/"]]],"singleLineComment":["define",{"sourceInterval":[1576,1623]},null,[],["seq",{"sourceInterval":[1596,1623]},["terminal",{"sourceInterval":[1596,1600]},"//"],["star",{"sourceInterval":[1601,1623]},["seq",{"sourceInterval":[1602,1621]},["not",{"sourceInterval":[1602,1617]},["app",{"sourceInterval":[1603,1617]},"lineTerminator",[]]],["app",{"sourceInterval":[1618,1621]},"any",[]]]]]],"stringLiteral":["define",{"sourceInterval":[1629,1759]},null,[],["alt",{"sourceInterval":[1649,1759]},["seq",{"sourceInterval":[1651,1683]},["terminal",{"sourceInterval":[1651,1655]},"\""],["star",{"sourceInterval":[1656,1678]},["app",{"sourceInterval":[1656,1677]},"doubleStringCharacter",[]]],["terminal",{"sourceInterval":[1679,1683]},"\""]],["seq",{"sourceInterval":[1690,1720]},["terminal",{"sourceInterval":[1690,1693]},"'"],["star",{"sourceInterval":[1694,1716]},["app",{"sourceInterval":[1694,1715]},"singleStringCharacter",[]]],["terminal",{"sourceInterval":[1717,1720]},"'"]],["seq",{"sourceInterval":[1727,1759]},["terminal",{"sourceInterval":[1727,1730]},"`"],["star",{"sourceInterval":[1731,1755]},["app",{"sourceInterval":[1731,1754]},"templateStringCharacter",[]]],["terminal",{"sourceInterval":[1756,1759]},"`"]]]],"doubleStringCharacter_NonEscaped":["define",{"sourceInterval":[1794,1845]},null,[],["seq",{"sourceInterval":[1794,1829]},["not",{"sourceInterval":[1794,1825]},["alt",{"sourceInterval":[1796,1824]},["terminal",{"sourceInterval":[1796,1800]},"\""],["terminal",{"sourceInterval":[1803,1807]},"\\"],["app",{"sourceInterval":[1810,1824]},"lineTerminator",[]]]],["app",{"sourceInterval":[1826,1829]},"any",[]]]],"doubleStringCharacter_Escaped":["define",{"sourceInterval":[1852,1900]},null,[],["seq",{"sourceInterval":[1852,1871]},["terminal",{"sourceInterval":[1852,1856]},"\\"],["app",{"sourceInterval":[1857,1871]},"escapeSequence",[]]]],"doubleStringCharacter_LineContinuation":["define",{"sourceInterval":[1907,1964]},null,[],["app",{"sourceInterval":[1907,1923]},"lineContinuation",[]]],"doubleStringCharacter":["define",{"sourceInterval":[1764,1964]},null,[],["alt",{"sourceInterval":[1792,1964]},["app",{"sourceInterval":[1794,1829]},"doubleStringCharacter_NonEscaped",[]],["app",{"sourceInterval":[1852,1871]},"doubleStringCharacter_Escaped",[]],["app",{"sourceInterval":[1907,1923]},"doubleStringCharacter_LineContinuation",[]]]],"singleStringCharacter_NonEscaped":["define",{"sourceInterval":[1999,2050]},null,[],["seq",{"sourceInterval":[1999,2033]},["not",{"sourceInterval":[1999,2029]},["alt",{"sourceInterval":[2001,2028]},["terminal",{"sourceInterval":[2001,2004]},"'"],["terminal",{"sourceInterval":[2007,2011]},"\\"],["app",{"sourceInterval":[2014,2028]},"lineTerminator",[]]]],["app",{"sourceInterval":[2030,2033]},"any",[]]]],"singleStringCharacter_Escaped":["define",{"sourceInterval":[2057,2105]},null,[],["seq",{"sourceInterval":[2057,2076]},["terminal",{"sourceInterval":[2057,2061]},"\\"],["app",{"sourceInterval":[2062,2076]},"escapeSequence",[]]]],"singleStringCharacter_LineContinuation":["define",{"sourceInterval":[2112,2169]},null,[],["app",{"sourceInterval":[2112,2128]},"lineContinuation",[]]],"singleStringCharacter":["define",{"sourceInterval":[1969,2169]},null,[],["alt",{"sourceInterval":[1997,2169]},["app",{"sourceInterval":[1999,2033]},"singleStringCharacter_NonEscaped",[]],["app",{"sourceInterval":[2057,2076]},"singleStringCharacter_Escaped",[]],["app",{"sourceInterval":[2112,2128]},"singleStringCharacter_LineContinuation",[]]]],"templateStringCharacter_NonEscaped":["define",{"sourceInterval":[2207,2258]},null,[],["seq",{"sourceInterval":[2207,2225]},["not",{"sourceInterval":[2207,2221]},["alt",{"sourceInterval":[2210,2220]},["terminal",{"sourceInterval":[2210,2213]},"`"],["terminal",{"sourceInterval":[2216,2220]},"\\"]]],["app",{"sourceInterval":[2222,2225]},"any",[]]]],"templateStringCharacter_Escaped":["define",{"sourceInterval":[2265,2318]},null,[],["seq",{"sourceInterval":[2265,2284]},["terminal",{"sourceInterval":[2265,2269]},"\\"],["app",{"sourceInterval":[2270,2284]},"escapeSequence",[]]]],"templateStringCharacter":["define",{"sourceInterval":[2174,2318]},null,[],["alt",{"sourceInterval":[2205,2318]},["app",{"sourceInterval":[2207,2225]},"templateStringCharacter_NonEscaped",[]],["app",{"sourceInterval":[2265,2284]},"templateStringCharacter_Escaped",[]]]],"lineContinuation":["define",{"sourceInterval":[2323,2369]},null,[],["seq",{"sourceInterval":[2342,2369]},["terminal",{"sourceInterval":[2342,2346]},"\\"],["app",{"sourceInterval":[2347,2369]},"lineTerminatorSequence",[]]]],"escapeSequence":["define",{"sourceInterval":[2374,2480]},null,[],["alt",{"sourceInterval":[2391,2480]},["app",{"sourceInterval":[2391,2412]},"unicodeEscapeSequence",[]],["app",{"sourceInterval":[2415,2432]},"hexEscapeSequence",[]],["app",{"sourceInterval":[2435,2454]},"octalEscapeSequence",[]],["app",{"sourceInterval":[2457,2480]},"characterEscapeSequence",[]]]],"characterEscapeSequence":["define",{"sourceInterval":[2485,2553]},null,[],["alt",{"sourceInterval":[2511,2553]},["app",{"sourceInterval":[2511,2532]},"singleEscapeCharacter",[]],["app",{"sourceInterval":[2535,2553]},"nonEscapeCharacter",[]]]],"singleEscapeCharacter":["define",{"sourceInterval":[2558,2635]},null,[],["alt",{"sourceInterval":[2582,2635]},["terminal",{"sourceInterval":[2582,2585]},"'"],["terminal",{"sourceInterval":[2588,2592]},"\""],["terminal",{"sourceInterval":[2595,2599]},"\\"],["terminal",{"sourceInterval":[2602,2605]},"b"],["terminal",{"sourceInterval":[2608,2611]},"f"],["terminal",{"sourceInterval":[2614,2617]},"n"],["terminal",{"sourceInterval":[2620,2623]},"r"],["terminal",{"sourceInterval":[2626,2629]},"t"],["terminal",{"sourceInterval":[2632,2635]},"v"]]],"nonEscapeCharacter":["define",{"sourceInterval":[2640,2700]},null,[],["seq",{"sourceInterval":[2661,2700]},["not",{"sourceInterval":[2661,2696]},["alt",{"sourceInterval":[2663,2695]},["app",{"sourceInterval":[2663,2678]},"escapeCharacter",[]],["app",{"sourceInterval":[2681,2695]},"lineTerminator",[]]]],["app",{"sourceInterval":[2697,2700]},"any",[]]]],"escapeCharacter":["define",{"sourceInterval":[2705,2771]},null,[],["alt",{"sourceInterval":[2723,2771]},["app",{"sourceInterval":[2723,2744]},"singleEscapeCharacter",[]],["app",{"sourceInterval":[2747,2759]},"decimalDigit",[]],["terminal",{"sourceInterval":[2762,2765]},"x"],["terminal",{"sourceInterval":[2768,2771]},"u"]]],"octalEscapeSequence_Whole":["define",{"sourceInterval":[2804,2850]},null,[],["seq",{"sourceInterval":[2804,2837]},["app",{"sourceInterval":[2804,2815]},"zeroToThree",[]],["app",{"sourceInterval":[2816,2826]},"octalDigit",[]],["app",{"sourceInterval":[2827,2837]},"octalDigit",[]]]],"octalEscapeSequence_EightTimesfourToSeven":["define",{"sourceInterval":[2857,2919]},null,[],["seq",{"sourceInterval":[2857,2879]},["app",{"sourceInterval":[2857,2868]},"fourToSeven",[]],["app",{"sourceInterval":[2869,2879]},"octalDigit",[]]]],"octalEscapeSequence_EightTimesZeroToThree":["define",{"sourceInterval":[2926,2988]},null,[],["seq",{"sourceInterval":[2926,2962]},["app",{"sourceInterval":[2926,2937]},"zeroToThree",[]],["app",{"sourceInterval":[2938,2948]},"octalDigit",[]],["not",{"sourceInterval":[2949,2962]},["app",{"sourceInterval":[2950,2962]},"decimalDigit",[]]]]],"octalEscapeSequence_Octal":["define",{"sourceInterval":[2995,3041]},null,[],["seq",{"sourceInterval":[2995,3019]},["app",{"sourceInterval":[2995,3005]},"octalDigit",[]],["not",{"sourceInterval":[3006,3019]},["app",{"sourceInterval":[3007,3019]},"decimalDigit",[]]]]],"octalEscapeSequence":["define",{"sourceInterval":[2776,3041]},null,[],["alt",{"sourceInterval":[2802,3041]},["app",{"sourceInterval":[2804,2837]},"octalEscapeSequence_Whole",[]],["app",{"sourceInterval":[2857,2879]},"octalEscapeSequence_EightTimesfourToSeven",[]],["app",{"sourceInterval":[2926,2962]},"octalEscapeSequence_EightTimesZeroToThree",[]],["app",{"sourceInterval":[2995,3019]},"octalEscapeSequence_Octal",[]]]],"hexEscapeSequence":["define",{"sourceInterval":[3046,3087]},null,[],["seq",{"sourceInterval":[3066,3087]},["terminal",{"sourceInterval":[3066,3069]},"x"],["app",{"sourceInterval":[3070,3078]},"hexDigit",[]],["app",{"sourceInterval":[3079,3087]},"hexDigit",[]]]],"unicodeEscapeSequence":["define",{"sourceInterval":[3092,3155]},null,[],["seq",{"sourceInterval":[3116,3155]},["terminal",{"sourceInterval":[3116,3119]},"u"],["app",{"sourceInterval":[3120,3128]},"hexDigit",[]],["app",{"sourceInterval":[3129,3137]},"hexDigit",[]],["app",{"sourceInterval":[3138,3146]},"hexDigit",[]],["app",{"sourceInterval":[3147,3155]},"hexDigit",[]]]],"zeroToThree":["define",{"sourceInterval":[3161,3183]},null,[],["range",{"sourceInterval":[3175,3183]},"0","3"]],"fourToSeven":["define",{"sourceInterval":[3188,3210]},null,[],["range",{"sourceInterval":[3202,3210]},"4","7"]],"decimalDigit":["define",{"sourceInterval":[3215,3238]},null,[],["range",{"sourceInterval":[3230,3238]},"0","9"]],"nonZeroDigit":["define",{"sourceInterval":[3243,3266]},null,[],["range",{"sourceInterval":[3258,3266]},"1","9"]],"octalDigit":["define",{"sourceInterval":[3271,3292]},null,[],["range",{"sourceInterval":[3284,3292]},"0","7"]],"regularExpressionLiteral":["define",{"sourceInterval":[3298,3377]},null,[],["seq",{"sourceInterval":[3325,3377]},["terminal",{"sourceInterval":[3325,3328]},"/"],["app",{"sourceInterval":[3329,3350]},"regularExpressionBody",[]],["terminal",{"sourceInterval":[3351,3354]},"/"],["app",{"sourceInterval":[3355,3377]},"regularExpressionFlags",[]]]],"regularExpressionBody":["define",{"sourceInterval":[3382,3455]},null,[],["seq",{"sourceInterval":[3406,3455]},["app",{"sourceInterval":[3406,3432]},"regularExpressionFirstChar",[]],["star",{"sourceInterval":[3433,3455]},["app",{"sourceInterval":[3433,3454]},"regularExpressionChar",[]]]]],"regularExpressionFirstChar":["define",{"sourceInterval":[3460,3621]},null,[],["alt",{"sourceInterval":[3493,3621]},["seq",{"sourceInterval":[3495,3551]},["not",{"sourceInterval":[3495,3520]},["alt",{"sourceInterval":[3497,3519]},["terminal",{"sourceInterval":[3497,3500]},"*"],["terminal",{"sourceInterval":[3503,3507]},"\\"],["terminal",{"sourceInterval":[3510,3513]},"/"],["terminal",{"sourceInterval":[3516,3519]},"["]]],["app",{"sourceInterval":[3521,3551]},"regularExpressionNonTerminator",[]]],["app",{"sourceInterval":[3558,3592]},"regularExpressionBackslashSequence",[]],["app",{"sourceInterval":[3599,3621]},"regularExpressionClass",[]]]],"regularExpressionChar":["define",{"sourceInterval":[3626,3770]},null,[],["alt",{"sourceInterval":[3650,3770]},["seq",{"sourceInterval":[3650,3700]},["not",{"sourceInterval":[3650,3669]},["alt",{"sourceInterval":[3652,3668]},["terminal",{"sourceInterval":[3652,3656]},"\\"],["terminal",{"sourceInterval":[3659,3662]},"/"],["terminal",{"sourceInterval":[3665,3668]},"["]]],["app",{"sourceInterval":[3670,3700]},"regularExpressionNonTerminator",[]]],["app",{"sourceInterval":[3707,3741]},"regularExpressionBackslashSequence",[]],["app",{"sourceInterval":[3748,3770]},"regularExpressionClass",[]]]],"regularExpressionBackslashSequence":["define",{"sourceInterval":[3775,3847]},null,[],["seq",{"sourceInterval":[3812,3847]},["terminal",{"sourceInterval":[3812,3816]},"\\"],["app",{"sourceInterval":[3817,3847]},"regularExpressionNonTerminator",[]]]],"regularExpressionNonTerminator":["define",{"sourceInterval":[3852,3906]},null,[],["seq",{"sourceInterval":[3885,3906]},["not",{"sourceInterval":[3885,3902]},["app",{"sourceInterval":[3887,3901]},"lineTerminator",[]]],["app",{"sourceInterval":[3903,3906]},"any",[]]]],"regularExpressionClass":["define",{"sourceInterval":[3911,3971]},null,[],["seq",{"sourceInterval":[3936,3971]},["terminal",{"sourceInterval":[3936,3939]},"["],["star",{"sourceInterval":[3940,3967]},["app",{"sourceInterval":[3940,3966]},"regularExpressionClassChar",[]]],["terminal",{"sourceInterval":[3968,3971]},"]"]]],"regularExpressionClassChar":["define",{"sourceInterval":[3976,4096]},null,[],["alt",{"sourceInterval":[4009,4096]},["seq",{"sourceInterval":[4011,4055]},["not",{"sourceInterval":[4011,4024]},["alt",{"sourceInterval":[4013,4023]},["terminal",{"sourceInterval":[4013,4016]},"]"],["terminal",{"sourceInterval":[4019,4023]},"\\"]]],["app",{"sourceInterval":[4025,4055]},"regularExpressionNonTerminator",[]]],["app",{"sourceInterval":[4062,4096]},"regularExpressionBackslashSequence",[]]]],"regularExpressionFlags":["define",{"sourceInterval":[4101,4141]},null,[],["star",{"sourceInterval":[4126,4141]},["app",{"sourceInterval":[4126,4140]},"identifierPart",[]]]],"multiLineCommentNoNL":["define",{"sourceInterval":[4147,4211]},null,[],["seq",{"sourceInterval":[4170,4211]},["terminal",{"sourceInterval":[4170,4174]},"/*"],["star",{"sourceInterval":[4175,4206]},["seq",{"sourceInterval":[4176,4204]},["not",{"sourceInterval":[4176,4200]},["alt",{"sourceInterval":[4178,4199]},["terminal",{"sourceInterval":[4178,4182]},"*/"],["app",{"sourceInterval":[4185,4199]},"lineTerminator",[]]]],["app",{"sourceInterval":[4201,4204]},"any",[]]]],["terminal",{"sourceInterval":[4207,4211]},"*/"]]],"identifierStart_escaped":["define",{"sourceInterval":[4266,4303]},null,[],["seq",{"sourceInterval":[4266,4292]},["terminal",{"sourceInterval":[4266,4270]},"\\"],["app",{"sourceInterval":[4271,4292]},"unicodeEscapeSequence",[]]]],"identifierStart":["define",{"sourceInterval":[4217,4303]},null,[],["alt",{"sourceInterval":[4239,4303]},["app",{"sourceInterval":[4241,4247]},"letter",[]],["terminal",{"sourceInterval":[4250,4253]},"$"],["terminal",{"sourceInterval":[4256,4259]},"_"],["app",{"sourceInterval":[4266,4292]},"identifierStart_escaped",[]]]],"identifierPart":["define",{"sourceInterval":[4308,4444]},null,[],["alt",{"sourceInterval":[4329,4444]},["app",{"sourceInterval":[4331,4346]},"identifierStart",[]],["app",{"sourceInterval":[4349,4369]},"unicodeCombiningMark",[]],["app",{"sourceInterval":[4376,4388]},"unicodeDigit",[]],["app",{"sourceInterval":[4391,4418]},"unicodeConnectorPunctuation",[]],["terminal",{"sourceInterval":[4425,4433]},"‌"],["terminal",{"sourceInterval":[4436,4444]},"‍"]]],"letter":["extend",{"sourceInterval":[4449,4476]},null,[],["app",{"sourceInterval":[4459,4476]},"unicodeCategoryNl",[]]],"unicodeCategoryNl":["define",{"sourceInterval":[4481,4555]},null,[],["alt",{"sourceInterval":[4505,4555]},["range",{"sourceInterval":[4505,4523]},"Ⅰ","ↂ"],["terminal",{"sourceInterval":[4526,4534]},"〇"],["range",{"sourceInterval":[4537,4555]},"〡","〩"]]],"unicodeDigit":["define",{"sourceInterval":[4560,4922]},"a digit",[],["alt",{"sourceInterval":[4589,4922]},["range",{"sourceInterval":[4589,4607]},"0","9"],["range",{"sourceInterval":[4610,4628]},"٠","٩"],["range",{"sourceInterval":[4631,4649]},"۰","۹"],["range",{"sourceInterval":[4652,4670]},"०","९"],["range",{"sourceInterval":[4673,4691]},"০","৯"],["range",{"sourceInterval":[4694,4712]},"੦","੯"],["range",{"sourceInterval":[4715,4733]},"૦","૯"],["range",{"sourceInterval":[4736,4754]},"୦","୯"],["range",{"sourceInterval":[4757,4775]},"௧","௯"],["range",{"sourceInterval":[4778,4796]},"౦","౯"],["range",{"sourceInterval":[4799,4817]},"೦","೯"],["range",{"sourceInterval":[4820,4838]},"൦","൯"],["range",{"sourceInterval":[4841,4859]},"๐","๙"],["range",{"sourceInterval":[4862,4880]},"໐","໙"],["range",{"sourceInterval":[4883,4901]},"༠","༩"],["range",{"sourceInterval":[4904,4922]},"0","9"]]],"unicodeCombiningMark":["define",{"sourceInterval":[4928,6659]},"a Unicode combining mark",[],["alt",{"sourceInterval":[4982,6659]},["range",{"sourceInterval":[4982,5000]},"̀","ͅ"],["range",{"sourceInterval":[5003,5021]},"͠","͡"],["range",{"sourceInterval":[5024,5042]},"҃","҆"],["range",{"sourceInterval":[5045,5063]},"֑","֡"],["range",{"sourceInterval":[5066,5084]},"֣","ֹ"],["range",{"sourceInterval":[5087,5105]},"ֻ","ֽ"],["range",{"sourceInterval":[5108,5126]},"ֿ","ֿ"],["range",{"sourceInterval":[5129,5147]},"ׁ","ׂ"],["range",{"sourceInterval":[5150,5168]},"ׄ","ׄ"],["range",{"sourceInterval":[5171,5189]},"ً","ْ"],["range",{"sourceInterval":[5192,5210]},"ٰ","ٰ"],["range",{"sourceInterval":[5213,5231]},"ۖ","ۜ"],["range",{"sourceInterval":[5234,5252]},"۟","ۤ"],["range",{"sourceInterval":[5255,5273]},"ۧ","ۨ"],["range",{"sourceInterval":[5276,5294]},"۪","ۭ"],["range",{"sourceInterval":[5297,5315]},"ँ","ं"],["range",{"sourceInterval":[5318,5336]},"़","़"],["range",{"sourceInterval":[5339,5357]},"ु","ै"],["range",{"sourceInterval":[5360,5378]},"्","्"],["range",{"sourceInterval":[5381,5399]},"॑","॔"],["range",{"sourceInterval":[5402,5420]},"ॢ","ॣ"],["range",{"sourceInterval":[5423,5441]},"ঁ","ঁ"],["range",{"sourceInterval":[5444,5462]},"়","়"],["range",{"sourceInterval":[5465,5483]},"ু","ৄ"],["range",{"sourceInterval":[5486,5504]},"্","্"],["range",{"sourceInterval":[5507,5525]},"ৢ","ৣ"],["range",{"sourceInterval":[5528,5546]},"ਂ","ਂ"],["range",{"sourceInterval":[5549,5567]},"਼","਼"],["range",{"sourceInterval":[5570,5588]},"ੁ","ੂ"],["range",{"sourceInterval":[5591,5609]},"ੇ","ੈ"],["range",{"sourceInterval":[5612,5630]},"ੋ","੍"],["range",{"sourceInterval":[5633,5651]},"ੰ","ੱ"],["range",{"sourceInterval":[5654,5672]},"ઁ","ં"],["range",{"sourceInterval":[5675,5693]},"઼","઼"],["range",{"sourceInterval":[5696,5714]},"ુ","ૅ"],["range",{"sourceInterval":[5717,5735]},"ે","ૈ"],["range",{"sourceInterval":[5738,5756]},"્","્"],["range",{"sourceInterval":[5759,5777]},"ଁ","ଁ"],["range",{"sourceInterval":[5780,5798]},"଼","଼"],["range",{"sourceInterval":[5801,5819]},"ି","ି"],["range",{"sourceInterval":[5822,5840]},"ୁ","ୃ"],["range",{"sourceInterval":[5843,5861]},"୍","୍"],["range",{"sourceInterval":[5864,5882]},"ୖ","ୖ"],["range",{"sourceInterval":[5885,5903]},"ஂ","ஂ"],["range",{"sourceInterval":[5906,5924]},"ீ","ீ"],["range",{"sourceInterval":[5927,5945]},"்","்"],["range",{"sourceInterval":[5948,5966]},"ా","ీ"],["range",{"sourceInterval":[5969,5987]},"ె","ై"],["range",{"sourceInterval":[5990,6008]},"ొ","్"],["range",{"sourceInterval":[6011,6029]},"ౕ","ౖ"],["range",{"sourceInterval":[6032,6050]},"ಿ","ಿ"],["range",{"sourceInterval":[6053,6071]},"ೆ","ೆ"],["range",{"sourceInterval":[6074,6092]},"ೌ","್"],["range",{"sourceInterval":[6095,6113]},"ു","ൃ"],["range",{"sourceInterval":[6116,6134]},"്","്"],["range",{"sourceInterval":[6137,6155]},"ั","ั"],["range",{"sourceInterval":[6158,6176]},"ิ","ฺ"],["range",{"sourceInterval":[6179,6197]},"็","๎"],["range",{"sourceInterval":[6200,6218]},"ັ","ັ"],["range",{"sourceInterval":[6221,6239]},"ິ","ູ"],["range",{"sourceInterval":[6242,6260]},"ົ","ຼ"],["range",{"sourceInterval":[6263,6281]},"່","ໍ"],["range",{"sourceInterval":[6284,6302]},"༘","༙"],["range",{"sourceInterval":[6305,6323]},"༵","༵"],["range",{"sourceInterval":[6326,6344]},"༷","༷"],["range",{"sourceInterval":[6347,6365]},"༹","༹"],["range",{"sourceInterval":[6368,6386]},"ཱ","ཾ"],["range",{"sourceInterval":[6389,6407]},"ྀ","྄"],["range",{"sourceInterval":[6410,6428]},"྆","྇"],["range",{"sourceInterval":[6431,6449]},"ྐ","ྕ"],["range",{"sourceInterval":[6452,6470]},"ྗ","ྗ"],["range",{"sourceInterval":[6473,6491]},"ྙ","ྭ"],["range",{"sourceInterval":[6494,6512]},"ྱ","ྷ"],["range",{"sourceInterval":[6515,6533]},"ྐྵ","ྐྵ"],["range",{"sourceInterval":[6536,6554]},"⃐","⃜"],["range",{"sourceInterval":[6557,6575]},"⃡","⃡"],["range",{"sourceInterval":[6578,6596]},"〪","〯"],["range",{"sourceInterval":[6599,6617]},"゙","゚"],["range",{"sourceInterval":[6620,6638]},"ﬞ","ﬞ"],["range",{"sourceInterval":[6641,6659]},"︠","︣"]]],"unicodeConnectorPunctuation":["define",{"sourceInterval":[6665,6799]},null,[],["alt",{"sourceInterval":[6695,6799]},["terminal",{"sourceInterval":[6695,6703]},"_"],["range",{"sourceInterval":[6706,6724]},"‿","⁀"],["terminal",{"sourceInterval":[6727,6735]},"・"],["range",{"sourceInterval":[6738,6756]},"︳","︴"],["range",{"sourceInterval":[6759,6777]},"﹍","﹏"],["terminal",{"sourceInterval":[6780,6788]},"_"],["terminal",{"sourceInterval":[6791,6799]},"・"]]],"unicodeSpaceSeparator":["define",{"sourceInterval":[6804,6857]},null,[],["alt",{"sourceInterval":[6828,6857]},["range",{"sourceInterval":[6828,6846]}," ","​"],["terminal",{"sourceInterval":[6849,6857]}," "]]]}]);export default result; \ No newline at end of file diff --git a/drizzle-kit/imports-checker/index.ts b/drizzle-kit/imports-checker/index.ts index 3cf61eb8e..911d84ff6 100644 --- a/drizzle-kit/imports-checker/index.ts +++ b/drizzle-kit/imports-checker/index.ts @@ -6,7 +6,7 @@ const issues = analyzeImports({ localPaths: ["src"], whiteList: [ "@drizzle-team/brocli", - "json-diff", + "json-diff", "path", "fs", "fs/*", @@ -42,8 +42,8 @@ const chainToString = (chains: ChainLink[]) => { return out; }; -console.log() +console.log(); for (const issue of issues) { - console.log(chalk.red(issue.imports.map(it=>it.name).join("\n"))) + console.log(chalk.red(issue.imports.map((it) => it.name).join("\n"))); console.log(issue.accessChains.map((it) => chainToString(it)).join("\n")); } diff --git a/drizzle-kit/src/@types/utils.ts b/drizzle-kit/src/@types/utils.ts index 04e7e125f..e71d45b89 100644 --- a/drizzle-kit/src/@types/utils.ts +++ b/drizzle-kit/src/@types/utils.ts @@ -13,6 +13,7 @@ declare global { random(): T; } } + import camelcase from 'camelcase'; String.prototype.trimChar = function(char: string) { diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 64ceb5841..84f23f1a2 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -24,7 +24,7 @@ import { mkdirSync } from 'fs'; import { renderWithTask } from 'hanji'; import { dialects } from 'src/schemaValidator'; import { assertUnreachable } from '../global'; -import { drizzleForLibSQL, type Setup } from '../serializer/studio'; +import type { Setup } from '../serializer/studio'; import { certs } from '../utils/certs'; import { grey, MigrateProgress } from './views'; @@ -591,6 +591,7 @@ export const studio = command({ drizzleForMySQL, prepareSQLiteSchema, drizzleForSQLite, + drizzleForLibSQL } = await import('../serializer/studio'); let setup: Setup; diff --git a/drizzle-kit/tests/bin.test.ts b/drizzle-kit/tests/bin.test.ts index 4c0942448..3b338e448 100644 --- a/drizzle-kit/tests/bin.test.ts +++ b/drizzle-kit/tests/bin.test.ts @@ -2,9 +2,7 @@ import { analyzeImports, ChainLink } from "../imports-checker/checker"; import chalk from "chalk"; import { assert, test } from "vitest"; - - -test("imports-issues", ()=>{ +test("imports-issues", () => { const issues = analyzeImports({ basePath: ".", localPaths: ["src"], @@ -24,15 +22,20 @@ test("imports-issues", ()=>{ "@hono/*", "crypto", "hanji", + "chalk", + "dotenv/config", + "camelcase", + "semver", + "env-paths", ], entry: "src/cli/index.ts", logger: true, ignoreTypes: true, }).issues; - + const chainToString = (chains: ChainLink[]) => { if (chains.length === 0) throw new Error(); - + let out = chains[0]!.file + "\n"; let indentation = 0; for (let chain of chains) { @@ -45,12 +48,12 @@ test("imports-issues", ()=>{ } return out; }; - - console.log() + + console.log(); for (const issue of issues) { - console.log(chalk.red(issue.imports.map(it=>it.name).join("\n"))) + console.log(chalk.red(issue.imports.map((it) => it.name).join("\n"))); console.log(issue.accessChains.map((it) => chainToString(it)).join("\n")); } - assert.equal(issues.length, 0) -}) \ No newline at end of file + assert.equal(issues.length, 0); +}); From cfa88ddcf8b998d079a213ca33de5e56986d2969 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Sun, 3 Nov 2024 16:20:00 +0200 Subject: [PATCH 288/492] Formatting fix --- drizzle-kit/imports-checker/analyze.ts | 110 +-- drizzle-kit/imports-checker/checker.ts | 546 +++++++------ .../grammar/grammar.ohm-bundle.d.ts | 241 +++--- .../grammar/grammar.ohm-bundle.js | 754 +++++++++++++++++- drizzle-kit/imports-checker/index.ts | 75 +- drizzle-kit/src/cli/schema.ts | 2 +- drizzle-kit/tests/bin.test.ts | 105 ++- 7 files changed, 1317 insertions(+), 516 deletions(-) diff --git a/drizzle-kit/imports-checker/analyze.ts b/drizzle-kit/imports-checker/analyze.ts index 20568120c..b31686e16 100644 --- a/drizzle-kit/imports-checker/analyze.ts +++ b/drizzle-kit/imports-checker/analyze.ts @@ -1,78 +1,78 @@ -import { readFileSync } from "fs"; -import type { Node } from "ohm-js"; -import JSImports from "./grammar/grammar.ohm-bundle"; +import { readFileSync } from 'fs'; +import type { Node } from 'ohm-js'; +import JSImports from './grammar/grammar.ohm-bundle'; export type CollectionItem = { - type: "data" | "types"; - source: string; + type: 'data' | 'types'; + source: string; }; function recursiveRun(...args: Node[]): boolean { - for (const arg of args) { - if ( - arg.ctorName === "Rest" || - arg.ctorName === "comment" || - arg.ctorName === "stringLiteral" - ) - continue; + for (const arg of args) { + if ( + arg.ctorName === 'Rest' + || arg.ctorName === 'comment' + || arg.ctorName === 'stringLiteral' + ) { + continue; + } - if ( - arg.ctorName === "ImportExpr_From" || - arg.ctorName === "ImportExpr_NoFrom" - ) { - arg["analyze"](); + if ( + arg.ctorName === 'ImportExpr_From' + || arg.ctorName === 'ImportExpr_NoFrom' + ) { + arg['analyze'](); - continue; - } + continue; + } - if (arg.isTerminal()) continue; + if (arg.isTerminal()) continue; - for (const c of arg.children) { - if (!recursiveRun(c)) return false; - } - } + for (const c of arg.children) { + if (!recursiveRun(c)) return false; + } + } - return true; + return true; } function init(collection: CollectionItem[]) { - const semantics = JSImports.createSemantics(); + const semantics = JSImports.createSemantics(); - semantics.addOperation("analyze", { - JSImports(arg0, arg1) { - recursiveRun(arg0, arg1); - }, + semantics.addOperation('analyze', { + JSImports(arg0, arg1) { + recursiveRun(arg0, arg1); + }, - ImportExpr_From(kImport, importInner, kFrom, importSource) { - const ruleName = importInner.children[0]!.ctorName; - const importType = - ruleName === "ImportInner_Type" || ruleName === "ImportInner_Types" - ? "types" - : "data"; + ImportExpr_From(kImport, importInner, kFrom, importSource) { + const ruleName = importInner.children[0]!.ctorName; + const importType = ruleName === 'ImportInner_Type' || ruleName === 'ImportInner_Types' + ? 'types' + : 'data'; - collection.push({ - source: importSource.children[1]!.sourceString!, - type: importType, - }); - }, + collection.push({ + source: importSource.children[1]!.sourceString!, + type: importType, + }); + }, - ImportExpr_NoFrom(kImport, importSource) { - collection.push({ - source: importSource.children[1]!.sourceString!, - type: "data", - }); - }, - }); + ImportExpr_NoFrom(kImport, importSource) { + collection.push({ + source: importSource.children[1]!.sourceString!, + type: 'data', + }); + }, + }); - return semantics; + return semantics; } export function analyze(path: string) { - const file = readFileSync(path).toString(); - const match = JSImports.match(file, "JSImports"); + const file = readFileSync(path).toString(); + const match = JSImports.match(file, 'JSImports'); - if (match.failed()) throw new Error(`Failed to parse file: ${path}`); - const collection: CollectionItem[] = []; + if (match.failed()) throw new Error(`Failed to parse file: ${path}`); + const collection: CollectionItem[] = []; - init(collection)(match)["analyze"](); - return collection; + init(collection)(match)['analyze'](); + return collection; } diff --git a/drizzle-kit/imports-checker/checker.ts b/drizzle-kit/imports-checker/checker.ts index 70c9bb66b..d8fc4b219 100644 --- a/drizzle-kit/imports-checker/checker.ts +++ b/drizzle-kit/imports-checker/checker.ts @@ -1,302 +1,296 @@ -import fs from "fs"; -import m from "micromatch"; -import { - dirname, - join as joinPath, - relative, - resolve as resolvePath, -} from "path"; -import { analyze } from "./analyze"; +import fs from 'fs'; +import m from 'micromatch'; +import { dirname, join as joinPath, relative, resolve as resolvePath } from 'path'; +import { analyze } from './analyze'; type External = { - file: string; - import: string; - type: "data" | "types"; + file: string; + import: string; + type: 'data' | 'types'; }; export type Issue = { - file: string; - imports: IssueImport[]; - accessChains: ChainLink[][]; + file: string; + imports: IssueImport[]; + accessChains: ChainLink[][]; }; export type IssueImport = { - name: string; - type: "data" | "types"; + name: string; + type: 'data' | 'types'; }; export type ChainLink = { - file: string; - import: string; + file: string; + import: string; }; -type ListMode = "whitelist" | "blacklist"; +type ListMode = 'whitelist' | 'blacklist'; class ImportAnalyzer { - private localImportRegex = /^(\.?\.?\/|\.\.?$)/; - private importedFileFormatRegex = - /^.*\.(ts|tsx|mts|cts|js|jsx|mjs|cjs|json)$/i; - - private visited: Set = new Set(); - - private externals: External[] = []; - private accessChains: Record = {}; - - constructor( - private basePath: string, - private entry: string, - private listMode: ListMode, - private readonly wantedList: string[], - private localPaths: string[], - private logger?: boolean, - private ignoreTypes?: boolean - ) {} - - private isDirectory = (path: string) => { - try { - return fs.lstatSync(path).isDirectory(); - } catch (e) { - return false; - } - }; - - private isFile = (path: string) => { - try { - return fs.lstatSync(path).isFile(); - } catch (e) { - return false; - } - }; - - private localizePath = (path: string) => - relative(resolvePath(this.basePath), resolvePath(path)); - - private isCustomLocal = (importTarget: string) => - !!this.localPaths.find( - (l) => - importTarget === l || - importTarget.startsWith(l.endsWith("/") ? l : `${l}/`) - ); - private isLocal = (importTarget: string) => - this.localImportRegex.test(importTarget) || - this.isCustomLocal(importTarget); - private isTsFormat = (path: string) => - this.importedFileFormatRegex.test(path); - - private resolveCustomLocalPath = ( - absoluteBase: string, - base: string, - target: string - ): string => { - return joinPath(absoluteBase, target); - }; - - private resolveTargetFile = (path: string): string => { - if (this.isFile(path)) return path; - - const formats = [ - ".ts", - ".mts", - ".cts", - ".tsx", - ".js", - ".mjs", - ".cjs", - ".jsx", - ]; - - for (const format of formats) { - const indexPath = joinPath(path, `/index${format}`); - if (this.isFile(indexPath)) return indexPath; - - const formatFilePath = `${path}${format}`; - if (this.isFile(formatFilePath)) return formatFilePath; - } - - return path; - }; - - private resolveTargetPath = ( - absoluteBase: string, - base: string, - target: string - ): string => { - if (this.isCustomLocal(target)) { - return this.resolveTargetFile( - this.resolveCustomLocalPath(absoluteBase, base, target) - ); - } - - const dir = this.isDirectory(base) ? base : dirname(base); - const joined = joinPath(dir, target); - - return this.resolveTargetFile(joined); - }; - - private _analyzeImports = ( - target: string = this.entry, - basePath: string = this.basePath, - accessChain: ChainLink[] = [] - ) => { - if (this.visited.has(target)) return; - - const locals: string[] = []; - - try { - if (this.logger) console.log(`${this.localizePath(target)}`); - - const imports = analyze(target); - - for (const { source: i, type } of imports) { - if (this.ignoreTypes && type === "types") continue; - - if (this.isLocal(i)) { - locals.push(i); - - continue; - } - - this.externals.push({ - file: this.localizePath(target), - import: i, - type: type, - }); - } - } catch (e) { - throw e; - } finally { - this.visited.add(target); - } - - for (const local of locals) { - const transformedTarget = this.resolveTargetPath(basePath, target, local); - - const localChain = [ - ...accessChain, - { - file: this.localizePath(target), - import: local, - }, - ]; - - const localized = this.localizePath(transformedTarget); - - if (this.accessChains[localized]) { - this.accessChains[localized].push(localChain); - } else this.accessChains[localized] = [localChain]; - - if (this.isTsFormat(transformedTarget)) { - this._analyzeImports(transformedTarget, basePath, localChain); - } else { - throw new Error(`unrecognized: ${localized}`); - } - } - }; - - public analyzeImports = () => { - const entryLocalized = this.localizePath(this.entry); - if (!this.accessChains[entryLocalized]) - this.accessChains[entryLocalized] = [[]]; - - this._analyzeImports(); - - const rawIssues = - this.listMode === "whitelist" - ? this.externals.filter((e) => !m([e.import], this.wantedList).length) - : this.externals.filter((e) => m([e.import], this.wantedList).length); - - const issueMap: Record = {}; - for (const { file, import: i, type } of rawIssues) { - if (issueMap[file]) { - issueMap[file].imports.push({ - name: i, - type, - }); - - continue; - } - - issueMap[file] = { - file, - imports: [ - { - name: i, - type, - }, - ], - accessChains: this.accessChains[file]!, - }; - } - - return { - issues: Object.entries(issueMap).map(([file, data]) => { - for (const chain of data.accessChains) { - chain.push({ - file, - import: "", - }); - } - - return data; - }), - accessChains: this.accessChains, - }; - }; + private localImportRegex = /^(\.?\.?\/|\.\.?$)/; + private importedFileFormatRegex = /^.*\.(ts|tsx|mts|cts|js|jsx|mjs|cjs|json)$/i; + + private visited: Set = new Set(); + + private externals: External[] = []; + private accessChains: Record = {}; + + constructor( + private basePath: string, + private entry: string, + private listMode: ListMode, + private readonly wantedList: string[], + private localPaths: string[], + private logger?: boolean, + private ignoreTypes?: boolean, + ) {} + + private isDirectory = (path: string) => { + try { + return fs.lstatSync(path).isDirectory(); + } catch (e) { + return false; + } + }; + + private isFile = (path: string) => { + try { + return fs.lstatSync(path).isFile(); + } catch (e) { + return false; + } + }; + + private localizePath = (path: string) => relative(resolvePath(this.basePath), resolvePath(path)); + + private isCustomLocal = (importTarget: string) => + !!this.localPaths.find( + (l) => + importTarget === l + || importTarget.startsWith(l.endsWith('/') ? l : `${l}/`), + ); + private isLocal = (importTarget: string) => + this.localImportRegex.test(importTarget) + || this.isCustomLocal(importTarget); + private isTsFormat = (path: string) => this.importedFileFormatRegex.test(path); + + private resolveCustomLocalPath = ( + absoluteBase: string, + base: string, + target: string, + ): string => { + return joinPath(absoluteBase, target); + }; + + private resolveTargetFile = (path: string): string => { + if (this.isFile(path)) return path; + + const formats = [ + '.ts', + '.mts', + '.cts', + '.tsx', + '.js', + '.mjs', + '.cjs', + '.jsx', + ]; + + for (const format of formats) { + const indexPath = joinPath(path, `/index${format}`); + if (this.isFile(indexPath)) return indexPath; + + const formatFilePath = `${path}${format}`; + if (this.isFile(formatFilePath)) return formatFilePath; + } + + return path; + }; + + private resolveTargetPath = ( + absoluteBase: string, + base: string, + target: string, + ): string => { + if (this.isCustomLocal(target)) { + return this.resolveTargetFile( + this.resolveCustomLocalPath(absoluteBase, base, target), + ); + } + + const dir = this.isDirectory(base) ? base : dirname(base); + const joined = joinPath(dir, target); + + return this.resolveTargetFile(joined); + }; + + private _analyzeImports = ( + target: string = this.entry, + basePath: string = this.basePath, + accessChain: ChainLink[] = [], + ) => { + if (this.visited.has(target)) return; + + const locals: string[] = []; + + try { + if (this.logger) console.log(`${this.localizePath(target)}`); + + const imports = analyze(target); + + for (const { source: i, type } of imports) { + if (this.ignoreTypes && type === 'types') continue; + + if (this.isLocal(i)) { + locals.push(i); + + continue; + } + + this.externals.push({ + file: this.localizePath(target), + import: i, + type: type, + }); + } + } catch (e) { + throw e; + } finally { + this.visited.add(target); + } + + for (const local of locals) { + const transformedTarget = this.resolveTargetPath(basePath, target, local); + + const localChain = [ + ...accessChain, + { + file: this.localizePath(target), + import: local, + }, + ]; + + const localized = this.localizePath(transformedTarget); + + if (this.accessChains[localized]) { + this.accessChains[localized].push(localChain); + } else this.accessChains[localized] = [localChain]; + + if (this.isTsFormat(transformedTarget)) { + this._analyzeImports(transformedTarget, basePath, localChain); + } else { + throw new Error(`unrecognized: ${localized}`); + } + } + }; + + public analyzeImports = () => { + const entryLocalized = this.localizePath(this.entry); + if (!this.accessChains[entryLocalized]) { + this.accessChains[entryLocalized] = [[]]; + } + + this._analyzeImports(); + + const rawIssues = this.listMode === 'whitelist' + ? this.externals.filter((e) => !m([e.import], this.wantedList).length) + : this.externals.filter((e) => m([e.import], this.wantedList).length); + + const issueMap: Record = {}; + for (const { file, import: i, type } of rawIssues) { + if (issueMap[file]) { + issueMap[file].imports.push({ + name: i, + type, + }); + + continue; + } + + issueMap[file] = { + file, + imports: [ + { + name: i, + type, + }, + ], + accessChains: this.accessChains[file]!, + }; + } + + return { + issues: Object.entries(issueMap).map(([file, data]) => { + for (const chain of data.accessChains) { + chain.push({ + file, + import: '', + }); + } + + return data; + }), + accessChains: this.accessChains, + }; + }; } export type CustomLocalPathResolver = ( - basePath: string, - path: string, - target: string + basePath: string, + path: string, + target: string, ) => string; -export type AnalyzeImportsConfig = { - basePath: string; - entry: string; - logger?: boolean; - ignoreTypes?: boolean; - localPaths?: string[]; -} & ( - | { - blackList: string[]; - } - | { - whiteList: string[]; - } -); +export type AnalyzeImportsConfig = + & { + basePath: string; + entry: string; + logger?: boolean; + ignoreTypes?: boolean; + localPaths?: string[]; + } + & ( + | { + blackList: string[]; + } + | { + whiteList: string[]; + } + ); type AnyAnalyzeImportsConfig = { - basePath: string; - entry: string; - blackList?: string[]; - whiteList?: string[]; - logger?: boolean; - ignoreTypes?: boolean; - localPaths?: string[]; + basePath: string; + entry: string; + blackList?: string[]; + whiteList?: string[]; + logger?: boolean; + ignoreTypes?: boolean; + localPaths?: string[]; }; export function analyzeImports(cfg: AnalyzeImportsConfig) { - const { - basePath, - blackList, - whiteList, - entry, - localPaths: localImports, - ignoreTypes, - logger, - } = cfg as AnyAnalyzeImportsConfig; - const mode = whiteList ? "whitelist" : "blacklist"; - const wantedList = blackList ?? whiteList!; - - const analyzer = new ImportAnalyzer( - joinPath(basePath), - joinPath(entry), - mode, - wantedList, - localImports ?? [], - logger, - ignoreTypes - ); - - return analyzer.analyzeImports(); + const { + basePath, + blackList, + whiteList, + entry, + localPaths: localImports, + ignoreTypes, + logger, + } = cfg as AnyAnalyzeImportsConfig; + const mode = whiteList ? 'whitelist' : 'blacklist'; + const wantedList = blackList ?? whiteList!; + + const analyzer = new ImportAnalyzer( + joinPath(basePath), + joinPath(entry), + mode, + wantedList, + localImports ?? [], + logger, + ignoreTypes, + ); + + return analyzer.analyzeImports(); } diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts index ed89916a7..64b5dfb78 100644 --- a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts @@ -1,107 +1,164 @@ // AUTOGENERATED FILE // This file was generated from grammar.ohm by `ohm generateBundles`. -import { - BaseActionDict, - Grammar, - IterationNode, - Node, - NonterminalNode, - Semantics, - TerminalNode -} from 'ohm-js'; +import { BaseActionDict, Grammar, IterationNode, Node, NonterminalNode, Semantics, TerminalNode } from 'ohm-js'; export interface JSImportsActionDict extends BaseActionDict { - JSImports?: (this: NonterminalNode, arg0: IterationNode, arg1: IterationNode) => T; - Expr?: (this: NonterminalNode, arg0: NonterminalNode) => T; - ImportExpr_From?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: TerminalNode, arg3: NonterminalNode) => T; - ImportExpr_NoFrom?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; - ImportExpr?: (this: NonterminalNode, arg0: NonterminalNode) => T; - Rest?: (this: NonterminalNode, arg0: IterationNode) => T; - ImportInner_Type?: (this: NonterminalNode, arg0: TerminalNode, arg1: TerminalNode, arg2: NonterminalNode, arg3: IterationNode, arg4: TerminalNode) => T; - ImportInner_Types?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: IterationNode, arg3: TerminalNode) => T; - ImportInner_Extended?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: IterationNode, arg3: TerminalNode) => T; - ImportInner_Mixed?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode, arg3: IterationNode, arg4: IterationNode, arg5: IterationNode, arg6: IterationNode) => T; - ImportInner_All?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: IterationNode) => T; - ImportInner_Default?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode) => T; - ImportInner?: (this: NonterminalNode, arg0: NonterminalNode) => T; - ImportExtendedSelection?: (this: NonterminalNode, arg0: NonterminalNode) => T; - ImportExtendedSelectionTypes?: (this: NonterminalNode, arg0: NonterminalNode) => T; - ImportExtendedSelectionTypeless?: (this: NonterminalNode, arg0: NonterminalNode) => T; - Import?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode) => T; - TypeImport?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: IterationNode, arg3: IterationNode) => T; - identifier?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T; - quote?: (this: NonterminalNode, arg0: TerminalNode) => T; - notQuote?: (this: NonterminalNode, arg0: NonterminalNode) => T; - importSource?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; - lineTerminator?: (this: NonterminalNode, arg0: TerminalNode) => T; - lineTerminatorSequence?: (this: NonterminalNode, arg0: TerminalNode) => T; - comment?: (this: NonterminalNode, arg0: NonterminalNode) => T; - multiLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; - singleLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode) => T; - stringLiteral?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; - doubleStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; - doubleStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; - doubleStringCharacter_LineContinuation?: (this: NonterminalNode, arg0: NonterminalNode) => T; - doubleStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; - singleStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; - singleStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; - singleStringCharacter_LineContinuation?: (this: NonterminalNode, arg0: NonterminalNode) => T; - singleStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; - templateStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; - templateStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; - templateStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; - lineContinuation?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; - escapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; - characterEscapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; - singleEscapeCharacter?: (this: NonterminalNode, arg0: TerminalNode) => T; - nonEscapeCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; - escapeCharacter?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; - octalEscapeSequence_Whole?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode, arg2: NonterminalNode) => T; - octalEscapeSequence_EightTimesfourToSeven?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode) => T; - octalEscapeSequence_EightTimesZeroToThree?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode) => T; - octalEscapeSequence_Octal?: (this: NonterminalNode, arg0: NonterminalNode) => T; - octalEscapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; - hexEscapeSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: NonterminalNode) => T; - unicodeEscapeSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: NonterminalNode, arg3: NonterminalNode, arg4: NonterminalNode) => T; - zeroToThree?: (this: NonterminalNode, arg0: TerminalNode) => T; - fourToSeven?: (this: NonterminalNode, arg0: TerminalNode) => T; - decimalDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; - nonZeroDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; - octalDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; - regularExpressionLiteral?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: TerminalNode, arg3: NonterminalNode) => T; - regularExpressionBody?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T; - regularExpressionFirstChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; - regularExpressionChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; - regularExpressionBackslashSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; - regularExpressionNonTerminator?: (this: NonterminalNode, arg0: NonterminalNode) => T; - regularExpressionClass?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; - regularExpressionClassChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; - regularExpressionFlags?: (this: NonterminalNode, arg0: IterationNode) => T; - multiLineCommentNoNL?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; - identifierStart_escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; - identifierStart?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; - identifierPart?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; - letter?: (this: NonterminalNode, arg0: NonterminalNode) => T; - unicodeCategoryNl?: (this: NonterminalNode, arg0: TerminalNode) => T; - unicodeDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; - unicodeCombiningMark?: (this: NonterminalNode, arg0: TerminalNode) => T; - unicodeConnectorPunctuation?: (this: NonterminalNode, arg0: TerminalNode) => T; - unicodeSpaceSeparator?: (this: NonterminalNode, arg0: TerminalNode) => T; + JSImports?: (this: NonterminalNode, arg0: IterationNode, arg1: IterationNode) => T; + Expr?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExpr_From?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: TerminalNode, + arg3: NonterminalNode, + ) => T; + ImportExpr_NoFrom?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + ImportExpr?: (this: NonterminalNode, arg0: NonterminalNode) => T; + Rest?: (this: NonterminalNode, arg0: IterationNode) => T; + ImportInner_Type?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: TerminalNode, + arg2: NonterminalNode, + arg3: IterationNode, + arg4: TerminalNode, + ) => T; + ImportInner_Types?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: IterationNode, + arg3: TerminalNode, + ) => T; + ImportInner_Extended?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: IterationNode, + arg3: TerminalNode, + ) => T; + ImportInner_Mixed?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: IterationNode, + arg2: IterationNode, + arg3: IterationNode, + arg4: IterationNode, + arg5: IterationNode, + arg6: IterationNode, + ) => T; + ImportInner_All?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: IterationNode) => T; + ImportInner_Default?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode) => T; + ImportInner?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelection?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelectionTypes?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelectionTypeless?: (this: NonterminalNode, arg0: NonterminalNode) => T; + Import?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode) => T; + TypeImport?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: IterationNode, + arg3: IterationNode, + ) => T; + identifier?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T; + quote?: (this: NonterminalNode, arg0: TerminalNode) => T; + notQuote?: (this: NonterminalNode, arg0: NonterminalNode) => T; + importSource?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + lineTerminator?: (this: NonterminalNode, arg0: TerminalNode) => T; + lineTerminatorSequence?: (this: NonterminalNode, arg0: TerminalNode) => T; + comment?: (this: NonterminalNode, arg0: NonterminalNode) => T; + multiLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + singleLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode) => T; + stringLiteral?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + doubleStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + doubleStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + doubleStringCharacter_LineContinuation?: (this: NonterminalNode, arg0: NonterminalNode) => T; + doubleStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + singleStringCharacter_LineContinuation?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + templateStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + templateStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + templateStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + lineContinuation?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + escapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + characterEscapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleEscapeCharacter?: (this: NonterminalNode, arg0: TerminalNode) => T; + nonEscapeCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + escapeCharacter?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + octalEscapeSequence_Whole?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: NonterminalNode, + arg2: NonterminalNode, + ) => T; + octalEscapeSequence_EightTimesfourToSeven?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: NonterminalNode, + ) => T; + octalEscapeSequence_EightTimesZeroToThree?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: NonterminalNode, + ) => T; + octalEscapeSequence_Octal?: (this: NonterminalNode, arg0: NonterminalNode) => T; + octalEscapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + hexEscapeSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: NonterminalNode) => T; + unicodeEscapeSequence?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: NonterminalNode, + arg3: NonterminalNode, + arg4: NonterminalNode, + ) => T; + zeroToThree?: (this: NonterminalNode, arg0: TerminalNode) => T; + fourToSeven?: (this: NonterminalNode, arg0: TerminalNode) => T; + decimalDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + nonZeroDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + octalDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + regularExpressionLiteral?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: TerminalNode, + arg3: NonterminalNode, + ) => T; + regularExpressionBody?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T; + regularExpressionFirstChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionBackslashSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + regularExpressionNonTerminator?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionClass?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + regularExpressionClassChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionFlags?: (this: NonterminalNode, arg0: IterationNode) => T; + multiLineCommentNoNL?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + identifierStart_escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + identifierStart?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + identifierPart?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + letter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + unicodeCategoryNl?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeCombiningMark?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeConnectorPunctuation?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeSpaceSeparator?: (this: NonterminalNode, arg0: TerminalNode) => T; } export interface JSImportsSemantics extends Semantics { - addOperation(name: string, actionDict: JSImportsActionDict): this; - extendOperation(name: string, actionDict: JSImportsActionDict): this; - addAttribute(name: string, actionDict: JSImportsActionDict): this; - extendAttribute(name: string, actionDict: JSImportsActionDict): this; + addOperation(name: string, actionDict: JSImportsActionDict): this; + extendOperation(name: string, actionDict: JSImportsActionDict): this; + addAttribute(name: string, actionDict: JSImportsActionDict): this; + extendAttribute(name: string, actionDict: JSImportsActionDict): this; } export interface JSImportsGrammar extends Grammar { - createSemantics(): JSImportsSemantics; - extendSemantics(superSemantics: JSImportsSemantics): JSImportsSemantics; + createSemantics(): JSImportsSemantics; + extendSemantics(superSemantics: JSImportsSemantics): JSImportsSemantics; } declare const grammar: JSImportsGrammar; export default grammar; - diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js index 2d473fc8d..9a889d66f 100644 --- a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js @@ -1 +1,753 @@ -import {makeRecipe} from 'ohm-js';const result=makeRecipe(["grammar",{"source":"JSImports {\n JSImports = (Expr \";\"?)*\n\n Expr = \n | comment\n | stringLiteral\n | ImportExpr\n | Rest\n\n ImportExpr =\n | \"import\" ImportInner \"from\" importSource -- From\n | \"import\" importSource -- NoFrom\n\n Rest = (~(ImportExpr | comment | stringLiteral) any)+\n\n ImportInner = \n | (\"type\" \"{\" NonemptyListOf \",\"? \"}\") -- Type\n | (\"{\" NonemptyListOf \",\"? \"}\") -- Types\n | (\"{\" NonemptyListOf \",\"? \"}\") -- Extended\n | (identifier (\",\" \"type\"? \"{\" NonemptyListOf \",\"? \"}\")?) -- Mixed\n | (\"*\" (\"as\" identifier)?) -- All\n | (identifier (\"as\" identifier)?) -- Default\n \n\n ImportExtendedSelection = TypeImport | Import\n ImportExtendedSelectionTypes = TypeImport\n ImportExtendedSelectionTypeless = Import\n\n Import = identifier (\"as\" identifier)?\n TypeImport = \"type\" Import (\"as\" identifier)?\n\n identifier = letter alnum*\n quote = \"\\\"\" | \"'\" | \"`\"\n notQuote = ~quote any\n importSource =\n | \"\\\"\" notQuote+ \"\\\"\"\n | \"'\" notQuote+ \"'\"\n | \"`\" notQuote+ \"`\"\n\n lineTerminator = \"\\n\" | \"\\r\" | \"\\u2028\" | \"\\u2029\"\n lineTerminatorSequence = \"\\n\" | \"\\r\" ~\"\\n\" | \"\\u2028\" | \"\\u2029\" | \"\\r\\n\"\n \n comment = multiLineComment | singleLineComment\n\n multiLineComment = \"/*\" (~\"*/\" any)* \"*/\"\n singleLineComment = \"//\" (~lineTerminator any)*\n\n stringLiteral =\n | \"\\\"\" doubleStringCharacter* \"\\\"\"\n | \"'\" singleStringCharacter* \"'\"\n | \"`\" templateStringCharacter* \"`\"\n doubleStringCharacter =\n | ~(\"\\\"\" | \"\\\\\" | lineTerminator) any -- NonEscaped\n | \"\\\\\" escapeSequence -- Escaped\n | lineContinuation -- LineContinuation\n singleStringCharacter =\n | ~(\"'\" | \"\\\\\" | lineTerminator) any -- NonEscaped\n | \"\\\\\" escapeSequence -- Escaped\n | lineContinuation -- LineContinuation\n templateStringCharacter = \n | ~ (\"`\" | \"\\\\\") any -- NonEscaped\n | \"\\\\\" escapeSequence -- Escaped\n lineContinuation = \"\\\\\" lineTerminatorSequence\n escapeSequence = unicodeEscapeSequence | hexEscapeSequence | octalEscapeSequence | characterEscapeSequence\n characterEscapeSequence = singleEscapeCharacter | nonEscapeCharacter\n singleEscapeCharacter = \"'\" | \"\\\"\" | \"\\\\\" | \"b\" | \"f\" | \"n\" | \"r\" | \"t\" | \"v\"\n nonEscapeCharacter = ~(escapeCharacter | lineTerminator) any\n escapeCharacter = singleEscapeCharacter | decimalDigit | \"x\" | \"u\"\n octalEscapeSequence =\n | zeroToThree octalDigit octalDigit -- Whole\n | fourToSeven octalDigit -- EightTimesfourToSeven\n | zeroToThree octalDigit ~decimalDigit -- EightTimesZeroToThree\n | octalDigit ~decimalDigit -- Octal\n hexEscapeSequence = \"x\" hexDigit hexDigit\n unicodeEscapeSequence = \"u\" hexDigit hexDigit hexDigit hexDigit\n\n zeroToThree = \"0\"..\"3\"\n fourToSeven = \"4\"..\"7\"\n decimalDigit = \"0\"..\"9\"\n nonZeroDigit = \"1\"..\"9\"\n octalDigit = \"0\"..\"7\"\n\n regularExpressionLiteral = \"/\" regularExpressionBody \"/\" regularExpressionFlags\n regularExpressionBody = regularExpressionFirstChar regularExpressionChar*\n regularExpressionFirstChar =\n | ~(\"*\" | \"\\\\\" | \"/\" | \"[\") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n | regularExpressionClass\n regularExpressionChar = ~(\"\\\\\" | \"/\" | \"[\") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n | regularExpressionClass\n regularExpressionBackslashSequence = \"\\\\\" regularExpressionNonTerminator\n regularExpressionNonTerminator = ~(lineTerminator) any\n regularExpressionClass = \"[\" regularExpressionClassChar* \"]\"\n regularExpressionClassChar =\n | ~(\"]\" | \"\\\\\") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n regularExpressionFlags = identifierPart*\n\n multiLineCommentNoNL = \"/*\" (~(\"*/\" | lineTerminator) any)* \"*/\"\n\n identifierStart =\n | letter | \"$\" | \"_\"\n | \"\\\\\" unicodeEscapeSequence -- escaped\n identifierPart =\n | identifierStart | unicodeCombiningMark\n | unicodeDigit | unicodeConnectorPunctuation\n | \"\\u200C\" | \"\\u200D\"\n letter += unicodeCategoryNl\n unicodeCategoryNl\n = \"\\u2160\"..\"\\u2182\" | \"\\u3007\" | \"\\u3021\"..\"\\u3029\"\n unicodeDigit (a digit)\n = \"\\u0030\"..\"\\u0039\" | \"\\u0660\"..\"\\u0669\" | \"\\u06F0\"..\"\\u06F9\" | \"\\u0966\"..\"\\u096F\" | \"\\u09E6\"..\"\\u09EF\" | \"\\u0A66\"..\"\\u0A6F\" | \"\\u0AE6\"..\"\\u0AEF\" | \"\\u0B66\"..\"\\u0B6F\" | \"\\u0BE7\"..\"\\u0BEF\" | \"\\u0C66\"..\"\\u0C6F\" | \"\\u0CE6\"..\"\\u0CEF\" | \"\\u0D66\"..\"\\u0D6F\" | \"\\u0E50\"..\"\\u0E59\" | \"\\u0ED0\"..\"\\u0ED9\" | \"\\u0F20\"..\"\\u0F29\" | \"\\uFF10\"..\"\\uFF19\"\n\n unicodeCombiningMark (a Unicode combining mark)\n = \"\\u0300\"..\"\\u0345\" | \"\\u0360\"..\"\\u0361\" | \"\\u0483\"..\"\\u0486\" | \"\\u0591\"..\"\\u05A1\" | \"\\u05A3\"..\"\\u05B9\" | \"\\u05BB\"..\"\\u05BD\" | \"\\u05BF\"..\"\\u05BF\" | \"\\u05C1\"..\"\\u05C2\" | \"\\u05C4\"..\"\\u05C4\" | \"\\u064B\"..\"\\u0652\" | \"\\u0670\"..\"\\u0670\" | \"\\u06D6\"..\"\\u06DC\" | \"\\u06DF\"..\"\\u06E4\" | \"\\u06E7\"..\"\\u06E8\" | \"\\u06EA\"..\"\\u06ED\" | \"\\u0901\"..\"\\u0902\" | \"\\u093C\"..\"\\u093C\" | \"\\u0941\"..\"\\u0948\" | \"\\u094D\"..\"\\u094D\" | \"\\u0951\"..\"\\u0954\" | \"\\u0962\"..\"\\u0963\" | \"\\u0981\"..\"\\u0981\" | \"\\u09BC\"..\"\\u09BC\" | \"\\u09C1\"..\"\\u09C4\" | \"\\u09CD\"..\"\\u09CD\" | \"\\u09E2\"..\"\\u09E3\" | \"\\u0A02\"..\"\\u0A02\" | \"\\u0A3C\"..\"\\u0A3C\" | \"\\u0A41\"..\"\\u0A42\" | \"\\u0A47\"..\"\\u0A48\" | \"\\u0A4B\"..\"\\u0A4D\" | \"\\u0A70\"..\"\\u0A71\" | \"\\u0A81\"..\"\\u0A82\" | \"\\u0ABC\"..\"\\u0ABC\" | \"\\u0AC1\"..\"\\u0AC5\" | \"\\u0AC7\"..\"\\u0AC8\" | \"\\u0ACD\"..\"\\u0ACD\" | \"\\u0B01\"..\"\\u0B01\" | \"\\u0B3C\"..\"\\u0B3C\" | \"\\u0B3F\"..\"\\u0B3F\" | \"\\u0B41\"..\"\\u0B43\" | \"\\u0B4D\"..\"\\u0B4D\" | \"\\u0B56\"..\"\\u0B56\" | \"\\u0B82\"..\"\\u0B82\" | \"\\u0BC0\"..\"\\u0BC0\" | \"\\u0BCD\"..\"\\u0BCD\" | \"\\u0C3E\"..\"\\u0C40\" | \"\\u0C46\"..\"\\u0C48\" | \"\\u0C4A\"..\"\\u0C4D\" | \"\\u0C55\"..\"\\u0C56\" | \"\\u0CBF\"..\"\\u0CBF\" | \"\\u0CC6\"..\"\\u0CC6\" | \"\\u0CCC\"..\"\\u0CCD\" | \"\\u0D41\"..\"\\u0D43\" | \"\\u0D4D\"..\"\\u0D4D\" | \"\\u0E31\"..\"\\u0E31\" | \"\\u0E34\"..\"\\u0E3A\" | \"\\u0E47\"..\"\\u0E4E\" | \"\\u0EB1\"..\"\\u0EB1\" | \"\\u0EB4\"..\"\\u0EB9\" | \"\\u0EBB\"..\"\\u0EBC\" | \"\\u0EC8\"..\"\\u0ECD\" | \"\\u0F18\"..\"\\u0F19\" | \"\\u0F35\"..\"\\u0F35\" | \"\\u0F37\"..\"\\u0F37\" | \"\\u0F39\"..\"\\u0F39\" | \"\\u0F71\"..\"\\u0F7E\" | \"\\u0F80\"..\"\\u0F84\" | \"\\u0F86\"..\"\\u0F87\" | \"\\u0F90\"..\"\\u0F95\" | \"\\u0F97\"..\"\\u0F97\" | \"\\u0F99\"..\"\\u0FAD\" | \"\\u0FB1\"..\"\\u0FB7\" | \"\\u0FB9\"..\"\\u0FB9\" | \"\\u20D0\"..\"\\u20DC\" | \"\\u20E1\"..\"\\u20E1\" | \"\\u302A\"..\"\\u302F\" | \"\\u3099\"..\"\\u309A\" | \"\\uFB1E\"..\"\\uFB1E\" | \"\\uFE20\"..\"\\uFE23\"\n\n unicodeConnectorPunctuation = \"\\u005F\" | \"\\u203F\"..\"\\u2040\" | \"\\u30FB\" | \"\\uFE33\"..\"\\uFE34\" | \"\\uFE4D\"..\"\\uFE4F\" | \"\\uFF3F\" | \"\\uFF65\"\n unicodeSpaceSeparator = \"\\u2000\"..\"\\u200B\" | \"\\u3000\"\n\n}"},"JSImports",null,"JSImports",{"JSImports":["define",{"sourceInterval":[16,40]},null,[],["star",{"sourceInterval":[28,40]},["seq",{"sourceInterval":[29,38]},["app",{"sourceInterval":[29,33]},"Expr",[]],["opt",{"sourceInterval":[34,38]},["terminal",{"sourceInterval":[34,37]},";"]]]]],"Expr":["define",{"sourceInterval":[46,115]},null,[],["alt",{"sourceInterval":[58,115]},["app",{"sourceInterval":[60,67]},"comment",[]],["app",{"sourceInterval":[74,87]},"stringLiteral",[]],["app",{"sourceInterval":[94,104]},"ImportExpr",[]],["app",{"sourceInterval":[111,115]},"Rest",[]]]],"ImportExpr_From":["define",{"sourceInterval":[140,188]},null,[],["seq",{"sourceInterval":[140,180]},["terminal",{"sourceInterval":[140,148]},"import"],["app",{"sourceInterval":[149,160]},"ImportInner",[]],["terminal",{"sourceInterval":[161,167]},"from"],["app",{"sourceInterval":[168,180]},"importSource",[]]]],"ImportExpr_NoFrom":["define",{"sourceInterval":[195,226]},null,[],["seq",{"sourceInterval":[195,216]},["terminal",{"sourceInterval":[195,203]},"import"],["app",{"sourceInterval":[204,216]},"importSource",[]]]],"ImportExpr":["define",{"sourceInterval":[121,226]},null,[],["alt",{"sourceInterval":[138,226]},["app",{"sourceInterval":[140,180]},"ImportExpr_From",[]],["app",{"sourceInterval":[195,216]},"ImportExpr_NoFrom",[]]]],"Rest":["define",{"sourceInterval":[232,285]},null,[],["plus",{"sourceInterval":[239,285]},["seq",{"sourceInterval":[240,283]},["not",{"sourceInterval":[240,279]},["alt",{"sourceInterval":[242,278]},["app",{"sourceInterval":[242,252]},"ImportExpr",[]],["app",{"sourceInterval":[255,262]},"comment",[]],["app",{"sourceInterval":[265,278]},"stringLiteral",[]]]],["app",{"sourceInterval":[280,283]},"any",[]]]]],"ImportInner_Type":["define",{"sourceInterval":[312,405]},null,[],["seq",{"sourceInterval":[312,386]},["terminal",{"sourceInterval":[313,319]},"type"],["terminal",{"sourceInterval":[320,323]},"{"],["app",{"sourceInterval":[324,376]},"NonemptyListOf",[["app",{"sourceInterval":[339,370]},"ImportExtendedSelectionTypeless",[]],["terminal",{"sourceInterval":[372,375]},","]]],["opt",{"sourceInterval":[377,381]},["terminal",{"sourceInterval":[377,380]},","]],["terminal",{"sourceInterval":[382,385]},"}"]]],"ImportInner_Types":["define",{"sourceInterval":[412,506]},null,[],["seq",{"sourceInterval":[412,476]},["terminal",{"sourceInterval":[413,416]},"{"],["app",{"sourceInterval":[417,466]},"NonemptyListOf",[["app",{"sourceInterval":[432,460]},"ImportExtendedSelectionTypes",[]],["terminal",{"sourceInterval":[462,465]},","]]],["opt",{"sourceInterval":[467,471]},["terminal",{"sourceInterval":[467,470]},","]],["terminal",{"sourceInterval":[472,475]},"}"]]],"ImportInner_Extended":["define",{"sourceInterval":[513,610]},null,[],["seq",{"sourceInterval":[513,572]},["terminal",{"sourceInterval":[514,517]},"{"],["app",{"sourceInterval":[518,562]},"NonemptyListOf",[["app",{"sourceInterval":[533,556]},"ImportExtendedSelection",[]],["terminal",{"sourceInterval":[558,561]},","]]],["opt",{"sourceInterval":[563,567]},["terminal",{"sourceInterval":[563,566]},","]],["terminal",{"sourceInterval":[568,571]},"}"]]],"ImportInner_Mixed":["define",{"sourceInterval":[617,711]},null,[],["seq",{"sourceInterval":[617,702]},["app",{"sourceInterval":[618,628]},"identifier",[]],["opt",{"sourceInterval":[629,701]},["seq",{"sourceInterval":[630,699]},["terminal",{"sourceInterval":[630,633]},","],["opt",{"sourceInterval":[634,641]},["terminal",{"sourceInterval":[634,640]},"type"]],["terminal",{"sourceInterval":[642,645]},"{"],["app",{"sourceInterval":[646,690]},"NonemptyListOf",[["app",{"sourceInterval":[661,684]},"ImportExtendedSelection",[]],["terminal",{"sourceInterval":[686,689]},","]]],["opt",{"sourceInterval":[691,695]},["terminal",{"sourceInterval":[691,694]},","]],["terminal",{"sourceInterval":[696,699]},"}"]]]]],"ImportInner_All":["define",{"sourceInterval":[718,810]},null,[],["seq",{"sourceInterval":[718,742]},["terminal",{"sourceInterval":[719,722]},"*"],["opt",{"sourceInterval":[723,741]},["seq",{"sourceInterval":[724,739]},["terminal",{"sourceInterval":[724,728]},"as"],["app",{"sourceInterval":[729,739]},"identifier",[]]]]]],"ImportInner_Default":["define",{"sourceInterval":[817,913]},null,[],["seq",{"sourceInterval":[817,848]},["app",{"sourceInterval":[818,828]},"identifier",[]],["opt",{"sourceInterval":[829,847]},["seq",{"sourceInterval":[830,845]},["terminal",{"sourceInterval":[830,834]},"as"],["app",{"sourceInterval":[835,845]},"identifier",[]]]]]],"ImportInner":["define",{"sourceInterval":[291,913]},null,[],["alt",{"sourceInterval":[310,913]},["app",{"sourceInterval":[312,386]},"ImportInner_Type",[]],["app",{"sourceInterval":[412,476]},"ImportInner_Types",[]],["app",{"sourceInterval":[513,572]},"ImportInner_Extended",[]],["app",{"sourceInterval":[617,702]},"ImportInner_Mixed",[]],["app",{"sourceInterval":[718,742]},"ImportInner_All",[]],["app",{"sourceInterval":[817,848]},"ImportInner_Default",[]]]],"ImportExtendedSelection":["define",{"sourceInterval":[924,969]},null,[],["alt",{"sourceInterval":[950,969]},["app",{"sourceInterval":[950,960]},"TypeImport",[]],["app",{"sourceInterval":[963,969]},"Import",[]]]],"ImportExtendedSelectionTypes":["define",{"sourceInterval":[974,1015]},null,[],["app",{"sourceInterval":[1005,1015]},"TypeImport",[]]],"ImportExtendedSelectionTypeless":["define",{"sourceInterval":[1020,1060]},null,[],["app",{"sourceInterval":[1054,1060]},"Import",[]]],"Import":["define",{"sourceInterval":[1066,1104]},null,[],["seq",{"sourceInterval":[1075,1104]},["app",{"sourceInterval":[1075,1085]},"identifier",[]],["opt",{"sourceInterval":[1086,1104]},["seq",{"sourceInterval":[1087,1102]},["terminal",{"sourceInterval":[1087,1091]},"as"],["app",{"sourceInterval":[1092,1102]},"identifier",[]]]]]],"TypeImport":["define",{"sourceInterval":[1109,1154]},null,[],["seq",{"sourceInterval":[1122,1154]},["terminal",{"sourceInterval":[1122,1128]},"type"],["app",{"sourceInterval":[1129,1135]},"Import",[]],["opt",{"sourceInterval":[1136,1154]},["seq",{"sourceInterval":[1137,1152]},["terminal",{"sourceInterval":[1137,1141]},"as"],["app",{"sourceInterval":[1142,1152]},"identifier",[]]]]]],"identifier":["define",{"sourceInterval":[1160,1186]},null,[],["seq",{"sourceInterval":[1173,1186]},["app",{"sourceInterval":[1173,1179]},"letter",[]],["star",{"sourceInterval":[1180,1186]},["app",{"sourceInterval":[1180,1185]},"alnum",[]]]]],"quote":["define",{"sourceInterval":[1191,1215]},null,[],["alt",{"sourceInterval":[1199,1215]},["terminal",{"sourceInterval":[1199,1203]},"\""],["terminal",{"sourceInterval":[1206,1209]},"'"],["terminal",{"sourceInterval":[1212,1215]},"`"]]],"notQuote":["define",{"sourceInterval":[1220,1241]},null,[],["seq",{"sourceInterval":[1231,1241]},["not",{"sourceInterval":[1231,1237]},["app",{"sourceInterval":[1232,1237]},"quote",[]]],["app",{"sourceInterval":[1238,1241]},"any",[]]]],"importSource":["define",{"sourceInterval":[1246,1334]},null,[],["alt",{"sourceInterval":[1265,1334]},["seq",{"sourceInterval":[1267,1286]},["terminal",{"sourceInterval":[1267,1271]},"\""],["plus",{"sourceInterval":[1272,1281]},["app",{"sourceInterval":[1272,1280]},"notQuote",[]]],["terminal",{"sourceInterval":[1282,1286]},"\""]],["seq",{"sourceInterval":[1293,1310]},["terminal",{"sourceInterval":[1293,1296]},"'"],["plus",{"sourceInterval":[1297,1306]},["app",{"sourceInterval":[1297,1305]},"notQuote",[]]],["terminal",{"sourceInterval":[1307,1310]},"'"]],["seq",{"sourceInterval":[1317,1334]},["terminal",{"sourceInterval":[1317,1320]},"`"],["plus",{"sourceInterval":[1321,1330]},["app",{"sourceInterval":[1321,1329]},"notQuote",[]]],["terminal",{"sourceInterval":[1331,1334]},"`"]]]],"lineTerminator":["define",{"sourceInterval":[1340,1390]},null,[],["alt",{"sourceInterval":[1357,1390]},["terminal",{"sourceInterval":[1357,1361]},"\n"],["terminal",{"sourceInterval":[1364,1368]},"\r"],["terminal",{"sourceInterval":[1371,1379]},"\u2028"],["terminal",{"sourceInterval":[1382,1390]},"\u2029"]]],"lineTerminatorSequence":["define",{"sourceInterval":[1395,1468]},null,[],["alt",{"sourceInterval":[1420,1468]},["terminal",{"sourceInterval":[1420,1424]},"\n"],["seq",{"sourceInterval":[1427,1437]},["terminal",{"sourceInterval":[1427,1431]},"\r"],["not",{"sourceInterval":[1432,1437]},["terminal",{"sourceInterval":[1433,1437]},"\n"]]],["terminal",{"sourceInterval":[1440,1448]},"\u2028"],["terminal",{"sourceInterval":[1451,1459]},"\u2029"],["terminal",{"sourceInterval":[1462,1468]},"\r\n"]]],"comment":["define",{"sourceInterval":[1478,1524]},null,[],["alt",{"sourceInterval":[1488,1524]},["app",{"sourceInterval":[1488,1504]},"multiLineComment",[]],["app",{"sourceInterval":[1507,1524]},"singleLineComment",[]]]],"multiLineComment":["define",{"sourceInterval":[1530,1571]},null,[],["seq",{"sourceInterval":[1549,1571]},["terminal",{"sourceInterval":[1549,1553]},"/*"],["star",{"sourceInterval":[1554,1566]},["seq",{"sourceInterval":[1555,1564]},["not",{"sourceInterval":[1555,1560]},["terminal",{"sourceInterval":[1556,1560]},"*/"]],["app",{"sourceInterval":[1561,1564]},"any",[]]]],["terminal",{"sourceInterval":[1567,1571]},"*/"]]],"singleLineComment":["define",{"sourceInterval":[1576,1623]},null,[],["seq",{"sourceInterval":[1596,1623]},["terminal",{"sourceInterval":[1596,1600]},"//"],["star",{"sourceInterval":[1601,1623]},["seq",{"sourceInterval":[1602,1621]},["not",{"sourceInterval":[1602,1617]},["app",{"sourceInterval":[1603,1617]},"lineTerminator",[]]],["app",{"sourceInterval":[1618,1621]},"any",[]]]]]],"stringLiteral":["define",{"sourceInterval":[1629,1759]},null,[],["alt",{"sourceInterval":[1649,1759]},["seq",{"sourceInterval":[1651,1683]},["terminal",{"sourceInterval":[1651,1655]},"\""],["star",{"sourceInterval":[1656,1678]},["app",{"sourceInterval":[1656,1677]},"doubleStringCharacter",[]]],["terminal",{"sourceInterval":[1679,1683]},"\""]],["seq",{"sourceInterval":[1690,1720]},["terminal",{"sourceInterval":[1690,1693]},"'"],["star",{"sourceInterval":[1694,1716]},["app",{"sourceInterval":[1694,1715]},"singleStringCharacter",[]]],["terminal",{"sourceInterval":[1717,1720]},"'"]],["seq",{"sourceInterval":[1727,1759]},["terminal",{"sourceInterval":[1727,1730]},"`"],["star",{"sourceInterval":[1731,1755]},["app",{"sourceInterval":[1731,1754]},"templateStringCharacter",[]]],["terminal",{"sourceInterval":[1756,1759]},"`"]]]],"doubleStringCharacter_NonEscaped":["define",{"sourceInterval":[1794,1845]},null,[],["seq",{"sourceInterval":[1794,1829]},["not",{"sourceInterval":[1794,1825]},["alt",{"sourceInterval":[1796,1824]},["terminal",{"sourceInterval":[1796,1800]},"\""],["terminal",{"sourceInterval":[1803,1807]},"\\"],["app",{"sourceInterval":[1810,1824]},"lineTerminator",[]]]],["app",{"sourceInterval":[1826,1829]},"any",[]]]],"doubleStringCharacter_Escaped":["define",{"sourceInterval":[1852,1900]},null,[],["seq",{"sourceInterval":[1852,1871]},["terminal",{"sourceInterval":[1852,1856]},"\\"],["app",{"sourceInterval":[1857,1871]},"escapeSequence",[]]]],"doubleStringCharacter_LineContinuation":["define",{"sourceInterval":[1907,1964]},null,[],["app",{"sourceInterval":[1907,1923]},"lineContinuation",[]]],"doubleStringCharacter":["define",{"sourceInterval":[1764,1964]},null,[],["alt",{"sourceInterval":[1792,1964]},["app",{"sourceInterval":[1794,1829]},"doubleStringCharacter_NonEscaped",[]],["app",{"sourceInterval":[1852,1871]},"doubleStringCharacter_Escaped",[]],["app",{"sourceInterval":[1907,1923]},"doubleStringCharacter_LineContinuation",[]]]],"singleStringCharacter_NonEscaped":["define",{"sourceInterval":[1999,2050]},null,[],["seq",{"sourceInterval":[1999,2033]},["not",{"sourceInterval":[1999,2029]},["alt",{"sourceInterval":[2001,2028]},["terminal",{"sourceInterval":[2001,2004]},"'"],["terminal",{"sourceInterval":[2007,2011]},"\\"],["app",{"sourceInterval":[2014,2028]},"lineTerminator",[]]]],["app",{"sourceInterval":[2030,2033]},"any",[]]]],"singleStringCharacter_Escaped":["define",{"sourceInterval":[2057,2105]},null,[],["seq",{"sourceInterval":[2057,2076]},["terminal",{"sourceInterval":[2057,2061]},"\\"],["app",{"sourceInterval":[2062,2076]},"escapeSequence",[]]]],"singleStringCharacter_LineContinuation":["define",{"sourceInterval":[2112,2169]},null,[],["app",{"sourceInterval":[2112,2128]},"lineContinuation",[]]],"singleStringCharacter":["define",{"sourceInterval":[1969,2169]},null,[],["alt",{"sourceInterval":[1997,2169]},["app",{"sourceInterval":[1999,2033]},"singleStringCharacter_NonEscaped",[]],["app",{"sourceInterval":[2057,2076]},"singleStringCharacter_Escaped",[]],["app",{"sourceInterval":[2112,2128]},"singleStringCharacter_LineContinuation",[]]]],"templateStringCharacter_NonEscaped":["define",{"sourceInterval":[2207,2258]},null,[],["seq",{"sourceInterval":[2207,2225]},["not",{"sourceInterval":[2207,2221]},["alt",{"sourceInterval":[2210,2220]},["terminal",{"sourceInterval":[2210,2213]},"`"],["terminal",{"sourceInterval":[2216,2220]},"\\"]]],["app",{"sourceInterval":[2222,2225]},"any",[]]]],"templateStringCharacter_Escaped":["define",{"sourceInterval":[2265,2318]},null,[],["seq",{"sourceInterval":[2265,2284]},["terminal",{"sourceInterval":[2265,2269]},"\\"],["app",{"sourceInterval":[2270,2284]},"escapeSequence",[]]]],"templateStringCharacter":["define",{"sourceInterval":[2174,2318]},null,[],["alt",{"sourceInterval":[2205,2318]},["app",{"sourceInterval":[2207,2225]},"templateStringCharacter_NonEscaped",[]],["app",{"sourceInterval":[2265,2284]},"templateStringCharacter_Escaped",[]]]],"lineContinuation":["define",{"sourceInterval":[2323,2369]},null,[],["seq",{"sourceInterval":[2342,2369]},["terminal",{"sourceInterval":[2342,2346]},"\\"],["app",{"sourceInterval":[2347,2369]},"lineTerminatorSequence",[]]]],"escapeSequence":["define",{"sourceInterval":[2374,2480]},null,[],["alt",{"sourceInterval":[2391,2480]},["app",{"sourceInterval":[2391,2412]},"unicodeEscapeSequence",[]],["app",{"sourceInterval":[2415,2432]},"hexEscapeSequence",[]],["app",{"sourceInterval":[2435,2454]},"octalEscapeSequence",[]],["app",{"sourceInterval":[2457,2480]},"characterEscapeSequence",[]]]],"characterEscapeSequence":["define",{"sourceInterval":[2485,2553]},null,[],["alt",{"sourceInterval":[2511,2553]},["app",{"sourceInterval":[2511,2532]},"singleEscapeCharacter",[]],["app",{"sourceInterval":[2535,2553]},"nonEscapeCharacter",[]]]],"singleEscapeCharacter":["define",{"sourceInterval":[2558,2635]},null,[],["alt",{"sourceInterval":[2582,2635]},["terminal",{"sourceInterval":[2582,2585]},"'"],["terminal",{"sourceInterval":[2588,2592]},"\""],["terminal",{"sourceInterval":[2595,2599]},"\\"],["terminal",{"sourceInterval":[2602,2605]},"b"],["terminal",{"sourceInterval":[2608,2611]},"f"],["terminal",{"sourceInterval":[2614,2617]},"n"],["terminal",{"sourceInterval":[2620,2623]},"r"],["terminal",{"sourceInterval":[2626,2629]},"t"],["terminal",{"sourceInterval":[2632,2635]},"v"]]],"nonEscapeCharacter":["define",{"sourceInterval":[2640,2700]},null,[],["seq",{"sourceInterval":[2661,2700]},["not",{"sourceInterval":[2661,2696]},["alt",{"sourceInterval":[2663,2695]},["app",{"sourceInterval":[2663,2678]},"escapeCharacter",[]],["app",{"sourceInterval":[2681,2695]},"lineTerminator",[]]]],["app",{"sourceInterval":[2697,2700]},"any",[]]]],"escapeCharacter":["define",{"sourceInterval":[2705,2771]},null,[],["alt",{"sourceInterval":[2723,2771]},["app",{"sourceInterval":[2723,2744]},"singleEscapeCharacter",[]],["app",{"sourceInterval":[2747,2759]},"decimalDigit",[]],["terminal",{"sourceInterval":[2762,2765]},"x"],["terminal",{"sourceInterval":[2768,2771]},"u"]]],"octalEscapeSequence_Whole":["define",{"sourceInterval":[2804,2850]},null,[],["seq",{"sourceInterval":[2804,2837]},["app",{"sourceInterval":[2804,2815]},"zeroToThree",[]],["app",{"sourceInterval":[2816,2826]},"octalDigit",[]],["app",{"sourceInterval":[2827,2837]},"octalDigit",[]]]],"octalEscapeSequence_EightTimesfourToSeven":["define",{"sourceInterval":[2857,2919]},null,[],["seq",{"sourceInterval":[2857,2879]},["app",{"sourceInterval":[2857,2868]},"fourToSeven",[]],["app",{"sourceInterval":[2869,2879]},"octalDigit",[]]]],"octalEscapeSequence_EightTimesZeroToThree":["define",{"sourceInterval":[2926,2988]},null,[],["seq",{"sourceInterval":[2926,2962]},["app",{"sourceInterval":[2926,2937]},"zeroToThree",[]],["app",{"sourceInterval":[2938,2948]},"octalDigit",[]],["not",{"sourceInterval":[2949,2962]},["app",{"sourceInterval":[2950,2962]},"decimalDigit",[]]]]],"octalEscapeSequence_Octal":["define",{"sourceInterval":[2995,3041]},null,[],["seq",{"sourceInterval":[2995,3019]},["app",{"sourceInterval":[2995,3005]},"octalDigit",[]],["not",{"sourceInterval":[3006,3019]},["app",{"sourceInterval":[3007,3019]},"decimalDigit",[]]]]],"octalEscapeSequence":["define",{"sourceInterval":[2776,3041]},null,[],["alt",{"sourceInterval":[2802,3041]},["app",{"sourceInterval":[2804,2837]},"octalEscapeSequence_Whole",[]],["app",{"sourceInterval":[2857,2879]},"octalEscapeSequence_EightTimesfourToSeven",[]],["app",{"sourceInterval":[2926,2962]},"octalEscapeSequence_EightTimesZeroToThree",[]],["app",{"sourceInterval":[2995,3019]},"octalEscapeSequence_Octal",[]]]],"hexEscapeSequence":["define",{"sourceInterval":[3046,3087]},null,[],["seq",{"sourceInterval":[3066,3087]},["terminal",{"sourceInterval":[3066,3069]},"x"],["app",{"sourceInterval":[3070,3078]},"hexDigit",[]],["app",{"sourceInterval":[3079,3087]},"hexDigit",[]]]],"unicodeEscapeSequence":["define",{"sourceInterval":[3092,3155]},null,[],["seq",{"sourceInterval":[3116,3155]},["terminal",{"sourceInterval":[3116,3119]},"u"],["app",{"sourceInterval":[3120,3128]},"hexDigit",[]],["app",{"sourceInterval":[3129,3137]},"hexDigit",[]],["app",{"sourceInterval":[3138,3146]},"hexDigit",[]],["app",{"sourceInterval":[3147,3155]},"hexDigit",[]]]],"zeroToThree":["define",{"sourceInterval":[3161,3183]},null,[],["range",{"sourceInterval":[3175,3183]},"0","3"]],"fourToSeven":["define",{"sourceInterval":[3188,3210]},null,[],["range",{"sourceInterval":[3202,3210]},"4","7"]],"decimalDigit":["define",{"sourceInterval":[3215,3238]},null,[],["range",{"sourceInterval":[3230,3238]},"0","9"]],"nonZeroDigit":["define",{"sourceInterval":[3243,3266]},null,[],["range",{"sourceInterval":[3258,3266]},"1","9"]],"octalDigit":["define",{"sourceInterval":[3271,3292]},null,[],["range",{"sourceInterval":[3284,3292]},"0","7"]],"regularExpressionLiteral":["define",{"sourceInterval":[3298,3377]},null,[],["seq",{"sourceInterval":[3325,3377]},["terminal",{"sourceInterval":[3325,3328]},"/"],["app",{"sourceInterval":[3329,3350]},"regularExpressionBody",[]],["terminal",{"sourceInterval":[3351,3354]},"/"],["app",{"sourceInterval":[3355,3377]},"regularExpressionFlags",[]]]],"regularExpressionBody":["define",{"sourceInterval":[3382,3455]},null,[],["seq",{"sourceInterval":[3406,3455]},["app",{"sourceInterval":[3406,3432]},"regularExpressionFirstChar",[]],["star",{"sourceInterval":[3433,3455]},["app",{"sourceInterval":[3433,3454]},"regularExpressionChar",[]]]]],"regularExpressionFirstChar":["define",{"sourceInterval":[3460,3621]},null,[],["alt",{"sourceInterval":[3493,3621]},["seq",{"sourceInterval":[3495,3551]},["not",{"sourceInterval":[3495,3520]},["alt",{"sourceInterval":[3497,3519]},["terminal",{"sourceInterval":[3497,3500]},"*"],["terminal",{"sourceInterval":[3503,3507]},"\\"],["terminal",{"sourceInterval":[3510,3513]},"/"],["terminal",{"sourceInterval":[3516,3519]},"["]]],["app",{"sourceInterval":[3521,3551]},"regularExpressionNonTerminator",[]]],["app",{"sourceInterval":[3558,3592]},"regularExpressionBackslashSequence",[]],["app",{"sourceInterval":[3599,3621]},"regularExpressionClass",[]]]],"regularExpressionChar":["define",{"sourceInterval":[3626,3770]},null,[],["alt",{"sourceInterval":[3650,3770]},["seq",{"sourceInterval":[3650,3700]},["not",{"sourceInterval":[3650,3669]},["alt",{"sourceInterval":[3652,3668]},["terminal",{"sourceInterval":[3652,3656]},"\\"],["terminal",{"sourceInterval":[3659,3662]},"/"],["terminal",{"sourceInterval":[3665,3668]},"["]]],["app",{"sourceInterval":[3670,3700]},"regularExpressionNonTerminator",[]]],["app",{"sourceInterval":[3707,3741]},"regularExpressionBackslashSequence",[]],["app",{"sourceInterval":[3748,3770]},"regularExpressionClass",[]]]],"regularExpressionBackslashSequence":["define",{"sourceInterval":[3775,3847]},null,[],["seq",{"sourceInterval":[3812,3847]},["terminal",{"sourceInterval":[3812,3816]},"\\"],["app",{"sourceInterval":[3817,3847]},"regularExpressionNonTerminator",[]]]],"regularExpressionNonTerminator":["define",{"sourceInterval":[3852,3906]},null,[],["seq",{"sourceInterval":[3885,3906]},["not",{"sourceInterval":[3885,3902]},["app",{"sourceInterval":[3887,3901]},"lineTerminator",[]]],["app",{"sourceInterval":[3903,3906]},"any",[]]]],"regularExpressionClass":["define",{"sourceInterval":[3911,3971]},null,[],["seq",{"sourceInterval":[3936,3971]},["terminal",{"sourceInterval":[3936,3939]},"["],["star",{"sourceInterval":[3940,3967]},["app",{"sourceInterval":[3940,3966]},"regularExpressionClassChar",[]]],["terminal",{"sourceInterval":[3968,3971]},"]"]]],"regularExpressionClassChar":["define",{"sourceInterval":[3976,4096]},null,[],["alt",{"sourceInterval":[4009,4096]},["seq",{"sourceInterval":[4011,4055]},["not",{"sourceInterval":[4011,4024]},["alt",{"sourceInterval":[4013,4023]},["terminal",{"sourceInterval":[4013,4016]},"]"],["terminal",{"sourceInterval":[4019,4023]},"\\"]]],["app",{"sourceInterval":[4025,4055]},"regularExpressionNonTerminator",[]]],["app",{"sourceInterval":[4062,4096]},"regularExpressionBackslashSequence",[]]]],"regularExpressionFlags":["define",{"sourceInterval":[4101,4141]},null,[],["star",{"sourceInterval":[4126,4141]},["app",{"sourceInterval":[4126,4140]},"identifierPart",[]]]],"multiLineCommentNoNL":["define",{"sourceInterval":[4147,4211]},null,[],["seq",{"sourceInterval":[4170,4211]},["terminal",{"sourceInterval":[4170,4174]},"/*"],["star",{"sourceInterval":[4175,4206]},["seq",{"sourceInterval":[4176,4204]},["not",{"sourceInterval":[4176,4200]},["alt",{"sourceInterval":[4178,4199]},["terminal",{"sourceInterval":[4178,4182]},"*/"],["app",{"sourceInterval":[4185,4199]},"lineTerminator",[]]]],["app",{"sourceInterval":[4201,4204]},"any",[]]]],["terminal",{"sourceInterval":[4207,4211]},"*/"]]],"identifierStart_escaped":["define",{"sourceInterval":[4266,4303]},null,[],["seq",{"sourceInterval":[4266,4292]},["terminal",{"sourceInterval":[4266,4270]},"\\"],["app",{"sourceInterval":[4271,4292]},"unicodeEscapeSequence",[]]]],"identifierStart":["define",{"sourceInterval":[4217,4303]},null,[],["alt",{"sourceInterval":[4239,4303]},["app",{"sourceInterval":[4241,4247]},"letter",[]],["terminal",{"sourceInterval":[4250,4253]},"$"],["terminal",{"sourceInterval":[4256,4259]},"_"],["app",{"sourceInterval":[4266,4292]},"identifierStart_escaped",[]]]],"identifierPart":["define",{"sourceInterval":[4308,4444]},null,[],["alt",{"sourceInterval":[4329,4444]},["app",{"sourceInterval":[4331,4346]},"identifierStart",[]],["app",{"sourceInterval":[4349,4369]},"unicodeCombiningMark",[]],["app",{"sourceInterval":[4376,4388]},"unicodeDigit",[]],["app",{"sourceInterval":[4391,4418]},"unicodeConnectorPunctuation",[]],["terminal",{"sourceInterval":[4425,4433]},"‌"],["terminal",{"sourceInterval":[4436,4444]},"‍"]]],"letter":["extend",{"sourceInterval":[4449,4476]},null,[],["app",{"sourceInterval":[4459,4476]},"unicodeCategoryNl",[]]],"unicodeCategoryNl":["define",{"sourceInterval":[4481,4555]},null,[],["alt",{"sourceInterval":[4505,4555]},["range",{"sourceInterval":[4505,4523]},"Ⅰ","ↂ"],["terminal",{"sourceInterval":[4526,4534]},"〇"],["range",{"sourceInterval":[4537,4555]},"〡","〩"]]],"unicodeDigit":["define",{"sourceInterval":[4560,4922]},"a digit",[],["alt",{"sourceInterval":[4589,4922]},["range",{"sourceInterval":[4589,4607]},"0","9"],["range",{"sourceInterval":[4610,4628]},"٠","٩"],["range",{"sourceInterval":[4631,4649]},"۰","۹"],["range",{"sourceInterval":[4652,4670]},"०","९"],["range",{"sourceInterval":[4673,4691]},"০","৯"],["range",{"sourceInterval":[4694,4712]},"੦","੯"],["range",{"sourceInterval":[4715,4733]},"૦","૯"],["range",{"sourceInterval":[4736,4754]},"୦","୯"],["range",{"sourceInterval":[4757,4775]},"௧","௯"],["range",{"sourceInterval":[4778,4796]},"౦","౯"],["range",{"sourceInterval":[4799,4817]},"೦","೯"],["range",{"sourceInterval":[4820,4838]},"൦","൯"],["range",{"sourceInterval":[4841,4859]},"๐","๙"],["range",{"sourceInterval":[4862,4880]},"໐","໙"],["range",{"sourceInterval":[4883,4901]},"༠","༩"],["range",{"sourceInterval":[4904,4922]},"0","9"]]],"unicodeCombiningMark":["define",{"sourceInterval":[4928,6659]},"a Unicode combining mark",[],["alt",{"sourceInterval":[4982,6659]},["range",{"sourceInterval":[4982,5000]},"̀","ͅ"],["range",{"sourceInterval":[5003,5021]},"͠","͡"],["range",{"sourceInterval":[5024,5042]},"҃","҆"],["range",{"sourceInterval":[5045,5063]},"֑","֡"],["range",{"sourceInterval":[5066,5084]},"֣","ֹ"],["range",{"sourceInterval":[5087,5105]},"ֻ","ֽ"],["range",{"sourceInterval":[5108,5126]},"ֿ","ֿ"],["range",{"sourceInterval":[5129,5147]},"ׁ","ׂ"],["range",{"sourceInterval":[5150,5168]},"ׄ","ׄ"],["range",{"sourceInterval":[5171,5189]},"ً","ْ"],["range",{"sourceInterval":[5192,5210]},"ٰ","ٰ"],["range",{"sourceInterval":[5213,5231]},"ۖ","ۜ"],["range",{"sourceInterval":[5234,5252]},"۟","ۤ"],["range",{"sourceInterval":[5255,5273]},"ۧ","ۨ"],["range",{"sourceInterval":[5276,5294]},"۪","ۭ"],["range",{"sourceInterval":[5297,5315]},"ँ","ं"],["range",{"sourceInterval":[5318,5336]},"़","़"],["range",{"sourceInterval":[5339,5357]},"ु","ै"],["range",{"sourceInterval":[5360,5378]},"्","्"],["range",{"sourceInterval":[5381,5399]},"॑","॔"],["range",{"sourceInterval":[5402,5420]},"ॢ","ॣ"],["range",{"sourceInterval":[5423,5441]},"ঁ","ঁ"],["range",{"sourceInterval":[5444,5462]},"়","়"],["range",{"sourceInterval":[5465,5483]},"ু","ৄ"],["range",{"sourceInterval":[5486,5504]},"্","্"],["range",{"sourceInterval":[5507,5525]},"ৢ","ৣ"],["range",{"sourceInterval":[5528,5546]},"ਂ","ਂ"],["range",{"sourceInterval":[5549,5567]},"਼","਼"],["range",{"sourceInterval":[5570,5588]},"ੁ","ੂ"],["range",{"sourceInterval":[5591,5609]},"ੇ","ੈ"],["range",{"sourceInterval":[5612,5630]},"ੋ","੍"],["range",{"sourceInterval":[5633,5651]},"ੰ","ੱ"],["range",{"sourceInterval":[5654,5672]},"ઁ","ં"],["range",{"sourceInterval":[5675,5693]},"઼","઼"],["range",{"sourceInterval":[5696,5714]},"ુ","ૅ"],["range",{"sourceInterval":[5717,5735]},"ે","ૈ"],["range",{"sourceInterval":[5738,5756]},"્","્"],["range",{"sourceInterval":[5759,5777]},"ଁ","ଁ"],["range",{"sourceInterval":[5780,5798]},"଼","଼"],["range",{"sourceInterval":[5801,5819]},"ି","ି"],["range",{"sourceInterval":[5822,5840]},"ୁ","ୃ"],["range",{"sourceInterval":[5843,5861]},"୍","୍"],["range",{"sourceInterval":[5864,5882]},"ୖ","ୖ"],["range",{"sourceInterval":[5885,5903]},"ஂ","ஂ"],["range",{"sourceInterval":[5906,5924]},"ீ","ீ"],["range",{"sourceInterval":[5927,5945]},"்","்"],["range",{"sourceInterval":[5948,5966]},"ా","ీ"],["range",{"sourceInterval":[5969,5987]},"ె","ై"],["range",{"sourceInterval":[5990,6008]},"ొ","్"],["range",{"sourceInterval":[6011,6029]},"ౕ","ౖ"],["range",{"sourceInterval":[6032,6050]},"ಿ","ಿ"],["range",{"sourceInterval":[6053,6071]},"ೆ","ೆ"],["range",{"sourceInterval":[6074,6092]},"ೌ","್"],["range",{"sourceInterval":[6095,6113]},"ു","ൃ"],["range",{"sourceInterval":[6116,6134]},"്","്"],["range",{"sourceInterval":[6137,6155]},"ั","ั"],["range",{"sourceInterval":[6158,6176]},"ิ","ฺ"],["range",{"sourceInterval":[6179,6197]},"็","๎"],["range",{"sourceInterval":[6200,6218]},"ັ","ັ"],["range",{"sourceInterval":[6221,6239]},"ິ","ູ"],["range",{"sourceInterval":[6242,6260]},"ົ","ຼ"],["range",{"sourceInterval":[6263,6281]},"່","ໍ"],["range",{"sourceInterval":[6284,6302]},"༘","༙"],["range",{"sourceInterval":[6305,6323]},"༵","༵"],["range",{"sourceInterval":[6326,6344]},"༷","༷"],["range",{"sourceInterval":[6347,6365]},"༹","༹"],["range",{"sourceInterval":[6368,6386]},"ཱ","ཾ"],["range",{"sourceInterval":[6389,6407]},"ྀ","྄"],["range",{"sourceInterval":[6410,6428]},"྆","྇"],["range",{"sourceInterval":[6431,6449]},"ྐ","ྕ"],["range",{"sourceInterval":[6452,6470]},"ྗ","ྗ"],["range",{"sourceInterval":[6473,6491]},"ྙ","ྭ"],["range",{"sourceInterval":[6494,6512]},"ྱ","ྷ"],["range",{"sourceInterval":[6515,6533]},"ྐྵ","ྐྵ"],["range",{"sourceInterval":[6536,6554]},"⃐","⃜"],["range",{"sourceInterval":[6557,6575]},"⃡","⃡"],["range",{"sourceInterval":[6578,6596]},"〪","〯"],["range",{"sourceInterval":[6599,6617]},"゙","゚"],["range",{"sourceInterval":[6620,6638]},"ﬞ","ﬞ"],["range",{"sourceInterval":[6641,6659]},"︠","︣"]]],"unicodeConnectorPunctuation":["define",{"sourceInterval":[6665,6799]},null,[],["alt",{"sourceInterval":[6695,6799]},["terminal",{"sourceInterval":[6695,6703]},"_"],["range",{"sourceInterval":[6706,6724]},"‿","⁀"],["terminal",{"sourceInterval":[6727,6735]},"・"],["range",{"sourceInterval":[6738,6756]},"︳","︴"],["range",{"sourceInterval":[6759,6777]},"﹍","﹏"],["terminal",{"sourceInterval":[6780,6788]},"_"],["terminal",{"sourceInterval":[6791,6799]},"・"]]],"unicodeSpaceSeparator":["define",{"sourceInterval":[6804,6857]},null,[],["alt",{"sourceInterval":[6828,6857]},["range",{"sourceInterval":[6828,6846]}," ","​"],["terminal",{"sourceInterval":[6849,6857]}," "]]]}]);export default result; \ No newline at end of file +import { makeRecipe } from 'ohm-js'; +const result = makeRecipe([ + 'grammar', + { + source: + 'JSImports {\n JSImports = (Expr ";"?)*\n\n Expr = \n | comment\n | stringLiteral\n | ImportExpr\n | Rest\n\n ImportExpr =\n | "import" ImportInner "from" importSource -- From\n | "import" importSource -- NoFrom\n\n Rest = (~(ImportExpr | comment | stringLiteral) any)+\n\n ImportInner = \n | ("type" "{" NonemptyListOf ","? "}") -- Type\n | ("{" NonemptyListOf ","? "}") -- Types\n | ("{" NonemptyListOf ","? "}") -- Extended\n | (identifier ("," "type"? "{" NonemptyListOf ","? "}")?) -- Mixed\n | ("*" ("as" identifier)?) -- All\n | (identifier ("as" identifier)?) -- Default\n \n\n ImportExtendedSelection = TypeImport | Import\n ImportExtendedSelectionTypes = TypeImport\n ImportExtendedSelectionTypeless = Import\n\n Import = identifier ("as" identifier)?\n TypeImport = "type" Import ("as" identifier)?\n\n identifier = letter alnum*\n quote = "\\"" | "\'" | "`"\n notQuote = ~quote any\n importSource =\n | "\\"" notQuote+ "\\""\n | "\'" notQuote+ "\'"\n | "`" notQuote+ "`"\n\n lineTerminator = "\\n" | "\\r" | "\\u2028" | "\\u2029"\n lineTerminatorSequence = "\\n" | "\\r" ~"\\n" | "\\u2028" | "\\u2029" | "\\r\\n"\n \n comment = multiLineComment | singleLineComment\n\n multiLineComment = "/*" (~"*/" any)* "*/"\n singleLineComment = "//" (~lineTerminator any)*\n\n stringLiteral =\n | "\\"" doubleStringCharacter* "\\""\n | "\'" singleStringCharacter* "\'"\n | "`" templateStringCharacter* "`"\n doubleStringCharacter =\n | ~("\\"" | "\\\\" | lineTerminator) any -- NonEscaped\n | "\\\\" escapeSequence -- Escaped\n | lineContinuation -- LineContinuation\n singleStringCharacter =\n | ~("\'" | "\\\\" | lineTerminator) any -- NonEscaped\n | "\\\\" escapeSequence -- Escaped\n | lineContinuation -- LineContinuation\n templateStringCharacter = \n | ~ ("`" | "\\\\") any -- NonEscaped\n | "\\\\" escapeSequence -- Escaped\n lineContinuation = "\\\\" lineTerminatorSequence\n escapeSequence = unicodeEscapeSequence | hexEscapeSequence | octalEscapeSequence | characterEscapeSequence\n characterEscapeSequence = singleEscapeCharacter | nonEscapeCharacter\n singleEscapeCharacter = "\'" | "\\"" | "\\\\" | "b" | "f" | "n" | "r" | "t" | "v"\n nonEscapeCharacter = ~(escapeCharacter | lineTerminator) any\n escapeCharacter = singleEscapeCharacter | decimalDigit | "x" | "u"\n octalEscapeSequence =\n | zeroToThree octalDigit octalDigit -- Whole\n | fourToSeven octalDigit -- EightTimesfourToSeven\n | zeroToThree octalDigit ~decimalDigit -- EightTimesZeroToThree\n | octalDigit ~decimalDigit -- Octal\n hexEscapeSequence = "x" hexDigit hexDigit\n unicodeEscapeSequence = "u" hexDigit hexDigit hexDigit hexDigit\n\n zeroToThree = "0".."3"\n fourToSeven = "4".."7"\n decimalDigit = "0".."9"\n nonZeroDigit = "1".."9"\n octalDigit = "0".."7"\n\n regularExpressionLiteral = "/" regularExpressionBody "/" regularExpressionFlags\n regularExpressionBody = regularExpressionFirstChar regularExpressionChar*\n regularExpressionFirstChar =\n | ~("*" | "\\\\" | "/" | "[") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n | regularExpressionClass\n regularExpressionChar = ~("\\\\" | "/" | "[") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n | regularExpressionClass\n regularExpressionBackslashSequence = "\\\\" regularExpressionNonTerminator\n regularExpressionNonTerminator = ~(lineTerminator) any\n regularExpressionClass = "[" regularExpressionClassChar* "]"\n regularExpressionClassChar =\n | ~("]" | "\\\\") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n regularExpressionFlags = identifierPart*\n\n multiLineCommentNoNL = "/*" (~("*/" | lineTerminator) any)* "*/"\n\n identifierStart =\n | letter | "$" | "_"\n | "\\\\" unicodeEscapeSequence -- escaped\n identifierPart =\n | identifierStart | unicodeCombiningMark\n | unicodeDigit | unicodeConnectorPunctuation\n | "\\u200C" | "\\u200D"\n letter += unicodeCategoryNl\n unicodeCategoryNl\n = "\\u2160".."\\u2182" | "\\u3007" | "\\u3021".."\\u3029"\n unicodeDigit (a digit)\n = "\\u0030".."\\u0039" | "\\u0660".."\\u0669" | "\\u06F0".."\\u06F9" | "\\u0966".."\\u096F" | "\\u09E6".."\\u09EF" | "\\u0A66".."\\u0A6F" | "\\u0AE6".."\\u0AEF" | "\\u0B66".."\\u0B6F" | "\\u0BE7".."\\u0BEF" | "\\u0C66".."\\u0C6F" | "\\u0CE6".."\\u0CEF" | "\\u0D66".."\\u0D6F" | "\\u0E50".."\\u0E59" | "\\u0ED0".."\\u0ED9" | "\\u0F20".."\\u0F29" | "\\uFF10".."\\uFF19"\n\n unicodeCombiningMark (a Unicode combining mark)\n = "\\u0300".."\\u0345" | "\\u0360".."\\u0361" | "\\u0483".."\\u0486" | "\\u0591".."\\u05A1" | "\\u05A3".."\\u05B9" | "\\u05BB".."\\u05BD" | "\\u05BF".."\\u05BF" | "\\u05C1".."\\u05C2" | "\\u05C4".."\\u05C4" | "\\u064B".."\\u0652" | "\\u0670".."\\u0670" | "\\u06D6".."\\u06DC" | "\\u06DF".."\\u06E4" | "\\u06E7".."\\u06E8" | "\\u06EA".."\\u06ED" | "\\u0901".."\\u0902" | "\\u093C".."\\u093C" | "\\u0941".."\\u0948" | "\\u094D".."\\u094D" | "\\u0951".."\\u0954" | "\\u0962".."\\u0963" | "\\u0981".."\\u0981" | "\\u09BC".."\\u09BC" | "\\u09C1".."\\u09C4" | "\\u09CD".."\\u09CD" | "\\u09E2".."\\u09E3" | "\\u0A02".."\\u0A02" | "\\u0A3C".."\\u0A3C" | "\\u0A41".."\\u0A42" | "\\u0A47".."\\u0A48" | "\\u0A4B".."\\u0A4D" | "\\u0A70".."\\u0A71" | "\\u0A81".."\\u0A82" | "\\u0ABC".."\\u0ABC" | "\\u0AC1".."\\u0AC5" | "\\u0AC7".."\\u0AC8" | "\\u0ACD".."\\u0ACD" | "\\u0B01".."\\u0B01" | "\\u0B3C".."\\u0B3C" | "\\u0B3F".."\\u0B3F" | "\\u0B41".."\\u0B43" | "\\u0B4D".."\\u0B4D" | "\\u0B56".."\\u0B56" | "\\u0B82".."\\u0B82" | "\\u0BC0".."\\u0BC0" | "\\u0BCD".."\\u0BCD" | "\\u0C3E".."\\u0C40" | "\\u0C46".."\\u0C48" | "\\u0C4A".."\\u0C4D" | "\\u0C55".."\\u0C56" | "\\u0CBF".."\\u0CBF" | "\\u0CC6".."\\u0CC6" | "\\u0CCC".."\\u0CCD" | "\\u0D41".."\\u0D43" | "\\u0D4D".."\\u0D4D" | "\\u0E31".."\\u0E31" | "\\u0E34".."\\u0E3A" | "\\u0E47".."\\u0E4E" | "\\u0EB1".."\\u0EB1" | "\\u0EB4".."\\u0EB9" | "\\u0EBB".."\\u0EBC" | "\\u0EC8".."\\u0ECD" | "\\u0F18".."\\u0F19" | "\\u0F35".."\\u0F35" | "\\u0F37".."\\u0F37" | "\\u0F39".."\\u0F39" | "\\u0F71".."\\u0F7E" | "\\u0F80".."\\u0F84" | "\\u0F86".."\\u0F87" | "\\u0F90".."\\u0F95" | "\\u0F97".."\\u0F97" | "\\u0F99".."\\u0FAD" | "\\u0FB1".."\\u0FB7" | "\\u0FB9".."\\u0FB9" | "\\u20D0".."\\u20DC" | "\\u20E1".."\\u20E1" | "\\u302A".."\\u302F" | "\\u3099".."\\u309A" | "\\uFB1E".."\\uFB1E" | "\\uFE20".."\\uFE23"\n\n unicodeConnectorPunctuation = "\\u005F" | "\\u203F".."\\u2040" | "\\u30FB" | "\\uFE33".."\\uFE34" | "\\uFE4D".."\\uFE4F" | "\\uFF3F" | "\\uFF65"\n unicodeSpaceSeparator = "\\u2000".."\\u200B" | "\\u3000"\n\n}', + }, + 'JSImports', + null, + 'JSImports', + { + JSImports: ['define', { sourceInterval: [16, 40] }, null, [], ['star', { sourceInterval: [28, 40] }, [ + 'seq', + { sourceInterval: [29, 38] }, + ['app', { sourceInterval: [29, 33] }, 'Expr', []], + ['opt', { sourceInterval: [34, 38] }, ['terminal', { sourceInterval: [34, 37] }, ';']], + ]]], + Expr: ['define', { sourceInterval: [46, 115] }, null, [], [ + 'alt', + { sourceInterval: [58, 115] }, + ['app', { sourceInterval: [60, 67] }, 'comment', []], + ['app', { sourceInterval: [74, 87] }, 'stringLiteral', []], + ['app', { sourceInterval: [94, 104] }, 'ImportExpr', []], + ['app', { sourceInterval: [111, 115] }, 'Rest', []], + ]], + ImportExpr_From: ['define', { sourceInterval: [140, 188] }, null, [], [ + 'seq', + { sourceInterval: [140, 180] }, + ['terminal', { sourceInterval: [140, 148] }, 'import'], + ['app', { sourceInterval: [149, 160] }, 'ImportInner', []], + ['terminal', { sourceInterval: [161, 167] }, 'from'], + ['app', { sourceInterval: [168, 180] }, 'importSource', []], + ]], + ImportExpr_NoFrom: ['define', { sourceInterval: [195, 226] }, null, [], ['seq', { sourceInterval: [195, 216] }, [ + 'terminal', + { sourceInterval: [195, 203] }, + 'import', + ], ['app', { sourceInterval: [204, 216] }, 'importSource', []]]], + ImportExpr: ['define', { sourceInterval: [121, 226] }, null, [], ['alt', { sourceInterval: [138, 226] }, [ + 'app', + { sourceInterval: [140, 180] }, + 'ImportExpr_From', + [], + ], ['app', { sourceInterval: [195, 216] }, 'ImportExpr_NoFrom', []]]], + Rest: ['define', { sourceInterval: [232, 285] }, null, [], ['plus', { sourceInterval: [239, 285] }, ['seq', { + sourceInterval: [240, 283], + }, ['not', { sourceInterval: [240, 279] }, [ + 'alt', + { sourceInterval: [242, 278] }, + ['app', { sourceInterval: [242, 252] }, 'ImportExpr', []], + ['app', { sourceInterval: [255, 262] }, 'comment', []], + ['app', { sourceInterval: [265, 278] }, 'stringLiteral', []], + ]], ['app', { sourceInterval: [280, 283] }, 'any', []]]]], + ImportInner_Type: ['define', { sourceInterval: [312, 405] }, null, [], [ + 'seq', + { sourceInterval: [312, 386] }, + ['terminal', { sourceInterval: [313, 319] }, 'type'], + ['terminal', { sourceInterval: [320, 323] }, '{'], + ['app', { sourceInterval: [324, 376] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [339, 370] }, + 'ImportExtendedSelectionTypeless', + [], + ], ['terminal', { sourceInterval: [372, 375] }, ',']]], + ['opt', { sourceInterval: [377, 381] }, ['terminal', { sourceInterval: [377, 380] }, ',']], + ['terminal', { sourceInterval: [382, 385] }, '}'], + ]], + ImportInner_Types: ['define', { sourceInterval: [412, 506] }, null, [], ['seq', { sourceInterval: [412, 476] }, [ + 'terminal', + { sourceInterval: [413, 416] }, + '{', + ], ['app', { sourceInterval: [417, 466] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [432, 460] }, + 'ImportExtendedSelectionTypes', + [], + ], ['terminal', { sourceInterval: [462, 465] }, ',']]], ['opt', { sourceInterval: [467, 471] }, ['terminal', { + sourceInterval: [467, 470], + }, ',']], ['terminal', { sourceInterval: [472, 475] }, '}']]], + ImportInner_Extended: ['define', { sourceInterval: [513, 610] }, null, [], ['seq', { sourceInterval: [513, 572] }, [ + 'terminal', + { sourceInterval: [514, 517] }, + '{', + ], ['app', { sourceInterval: [518, 562] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [533, 556] }, + 'ImportExtendedSelection', + [], + ], ['terminal', { sourceInterval: [558, 561] }, ',']]], ['opt', { sourceInterval: [563, 567] }, ['terminal', { + sourceInterval: [563, 566], + }, ',']], ['terminal', { sourceInterval: [568, 571] }, '}']]], + ImportInner_Mixed: ['define', { sourceInterval: [617, 711] }, null, [], ['seq', { sourceInterval: [617, 702] }, [ + 'app', + { sourceInterval: [618, 628] }, + 'identifier', + [], + ], ['opt', { sourceInterval: [629, 701] }, [ + 'seq', + { sourceInterval: [630, 699] }, + ['terminal', { sourceInterval: [630, 633] }, ','], + ['opt', { sourceInterval: [634, 641] }, ['terminal', { sourceInterval: [634, 640] }, 'type']], + ['terminal', { sourceInterval: [642, 645] }, '{'], + ['app', { sourceInterval: [646, 690] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [661, 684] }, + 'ImportExtendedSelection', + [], + ], ['terminal', { sourceInterval: [686, 689] }, ',']]], + ['opt', { sourceInterval: [691, 695] }, ['terminal', { sourceInterval: [691, 694] }, ',']], + ['terminal', { sourceInterval: [696, 699] }, '}'], + ]]]], + ImportInner_All: ['define', { sourceInterval: [718, 810] }, null, [], ['seq', { sourceInterval: [718, 742] }, [ + 'terminal', + { sourceInterval: [719, 722] }, + '*', + ], ['opt', { sourceInterval: [723, 741] }, ['seq', { sourceInterval: [724, 739] }, ['terminal', { + sourceInterval: [724, 728], + }, 'as'], ['app', { sourceInterval: [729, 739] }, 'identifier', []]]]]], + ImportInner_Default: ['define', { sourceInterval: [817, 913] }, null, [], ['seq', { sourceInterval: [817, 848] }, [ + 'app', + { sourceInterval: [818, 828] }, + 'identifier', + [], + ], ['opt', { sourceInterval: [829, 847] }, ['seq', { sourceInterval: [830, 845] }, ['terminal', { + sourceInterval: [830, 834], + }, 'as'], ['app', { sourceInterval: [835, 845] }, 'identifier', []]]]]], + ImportInner: ['define', { sourceInterval: [291, 913] }, null, [], [ + 'alt', + { sourceInterval: [310, 913] }, + ['app', { sourceInterval: [312, 386] }, 'ImportInner_Type', []], + ['app', { sourceInterval: [412, 476] }, 'ImportInner_Types', []], + ['app', { sourceInterval: [513, 572] }, 'ImportInner_Extended', []], + ['app', { sourceInterval: [617, 702] }, 'ImportInner_Mixed', []], + ['app', { sourceInterval: [718, 742] }, 'ImportInner_All', []], + ['app', { sourceInterval: [817, 848] }, 'ImportInner_Default', []], + ]], + ImportExtendedSelection: ['define', { sourceInterval: [924, 969] }, null, [], [ + 'alt', + { sourceInterval: [950, 969] }, + ['app', { sourceInterval: [950, 960] }, 'TypeImport', []], + ['app', { sourceInterval: [963, 969] }, 'Import', []], + ]], + ImportExtendedSelectionTypes: ['define', { sourceInterval: [974, 1015] }, null, [], [ + 'app', + { sourceInterval: [1005, 1015] }, + 'TypeImport', + [], + ]], + ImportExtendedSelectionTypeless: ['define', { sourceInterval: [1020, 1060] }, null, [], [ + 'app', + { sourceInterval: [1054, 1060] }, + 'Import', + [], + ]], + Import: ['define', { sourceInterval: [1066, 1104] }, null, [], ['seq', { sourceInterval: [1075, 1104] }, [ + 'app', + { sourceInterval: [1075, 1085] }, + 'identifier', + [], + ], ['opt', { sourceInterval: [1086, 1104] }, ['seq', { sourceInterval: [1087, 1102] }, ['terminal', { + sourceInterval: [1087, 1091], + }, 'as'], ['app', { sourceInterval: [1092, 1102] }, 'identifier', []]]]]], + TypeImport: ['define', { sourceInterval: [1109, 1154] }, null, [], [ + 'seq', + { sourceInterval: [1122, 1154] }, + ['terminal', { sourceInterval: [1122, 1128] }, 'type'], + ['app', { sourceInterval: [1129, 1135] }, 'Import', []], + ['opt', { sourceInterval: [1136, 1154] }, ['seq', { sourceInterval: [1137, 1152] }, ['terminal', { + sourceInterval: [1137, 1141], + }, 'as'], ['app', { sourceInterval: [1142, 1152] }, 'identifier', []]]], + ]], + identifier: ['define', { sourceInterval: [1160, 1186] }, null, [], ['seq', { sourceInterval: [1173, 1186] }, [ + 'app', + { sourceInterval: [1173, 1179] }, + 'letter', + [], + ], ['star', { sourceInterval: [1180, 1186] }, ['app', { sourceInterval: [1180, 1185] }, 'alnum', []]]]], + quote: ['define', { sourceInterval: [1191, 1215] }, null, [], [ + 'alt', + { sourceInterval: [1199, 1215] }, + ['terminal', { sourceInterval: [1199, 1203] }, '"'], + ['terminal', { sourceInterval: [1206, 1209] }, "'"], + ['terminal', { sourceInterval: [1212, 1215] }, '`'], + ]], + notQuote: ['define', { sourceInterval: [1220, 1241] }, null, [], ['seq', { sourceInterval: [1231, 1241] }, ['not', { + sourceInterval: [1231, 1237], + }, ['app', { sourceInterval: [1232, 1237] }, 'quote', []]], ['app', { sourceInterval: [1238, 1241] }, 'any', []]]], + importSource: ['define', { sourceInterval: [1246, 1334] }, null, [], [ + 'alt', + { sourceInterval: [1265, 1334] }, + ['seq', { sourceInterval: [1267, 1286] }, ['terminal', { sourceInterval: [1267, 1271] }, '"'], ['plus', { + sourceInterval: [1272, 1281], + }, ['app', { sourceInterval: [1272, 1280] }, 'notQuote', []]], [ + 'terminal', + { sourceInterval: [1282, 1286] }, + '"', + ]], + ['seq', { sourceInterval: [1293, 1310] }, ['terminal', { sourceInterval: [1293, 1296] }, "'"], ['plus', { + sourceInterval: [1297, 1306], + }, ['app', { sourceInterval: [1297, 1305] }, 'notQuote', []]], [ + 'terminal', + { sourceInterval: [1307, 1310] }, + "'", + ]], + ['seq', { sourceInterval: [1317, 1334] }, ['terminal', { sourceInterval: [1317, 1320] }, '`'], ['plus', { + sourceInterval: [1321, 1330], + }, ['app', { sourceInterval: [1321, 1329] }, 'notQuote', []]], [ + 'terminal', + { sourceInterval: [1331, 1334] }, + '`', + ]], + ]], + lineTerminator: ['define', { sourceInterval: [1340, 1390] }, null, [], [ + 'alt', + { sourceInterval: [1357, 1390] }, + ['terminal', { sourceInterval: [1357, 1361] }, '\n'], + ['terminal', { sourceInterval: [1364, 1368] }, '\r'], + ['terminal', { sourceInterval: [1371, 1379] }, '\u2028'], + ['terminal', { sourceInterval: [1382, 1390] }, '\u2029'], + ]], + lineTerminatorSequence: ['define', { sourceInterval: [1395, 1468] }, null, [], [ + 'alt', + { sourceInterval: [1420, 1468] }, + ['terminal', { sourceInterval: [1420, 1424] }, '\n'], + ['seq', { sourceInterval: [1427, 1437] }, ['terminal', { sourceInterval: [1427, 1431] }, '\r'], ['not', { + sourceInterval: [1432, 1437], + }, ['terminal', { sourceInterval: [1433, 1437] }, '\n']]], + ['terminal', { sourceInterval: [1440, 1448] }, '\u2028'], + ['terminal', { sourceInterval: [1451, 1459] }, '\u2029'], + ['terminal', { sourceInterval: [1462, 1468] }, '\r\n'], + ]], + comment: ['define', { sourceInterval: [1478, 1524] }, null, [], ['alt', { sourceInterval: [1488, 1524] }, [ + 'app', + { sourceInterval: [1488, 1504] }, + 'multiLineComment', + [], + ], ['app', { sourceInterval: [1507, 1524] }, 'singleLineComment', []]]], + multiLineComment: ['define', { sourceInterval: [1530, 1571] }, null, [], ['seq', { sourceInterval: [1549, 1571] }, [ + 'terminal', + { sourceInterval: [1549, 1553] }, + '/*', + ], ['star', { sourceInterval: [1554, 1566] }, ['seq', { sourceInterval: [1555, 1564] }, ['not', { + sourceInterval: [1555, 1560], + }, ['terminal', { sourceInterval: [1556, 1560] }, '*/']], ['app', { sourceInterval: [1561, 1564] }, 'any', []]]], [ + 'terminal', + { sourceInterval: [1567, 1571] }, + '*/', + ]]], + singleLineComment: ['define', { sourceInterval: [1576, 1623] }, null, [], [ + 'seq', + { sourceInterval: [1596, 1623] }, + ['terminal', { sourceInterval: [1596, 1600] }, '//'], + ['star', { sourceInterval: [1601, 1623] }, ['seq', { sourceInterval: [1602, 1621] }, ['not', { + sourceInterval: [1602, 1617], + }, ['app', { sourceInterval: [1603, 1617] }, 'lineTerminator', []]], [ + 'app', + { sourceInterval: [1618, 1621] }, + 'any', + [], + ]]], + ]], + stringLiteral: ['define', { sourceInterval: [1629, 1759] }, null, [], ['alt', { sourceInterval: [1649, 1759] }, [ + 'seq', + { sourceInterval: [1651, 1683] }, + ['terminal', { sourceInterval: [1651, 1655] }, '"'], + ['star', { sourceInterval: [1656, 1678] }, [ + 'app', + { sourceInterval: [1656, 1677] }, + 'doubleStringCharacter', + [], + ]], + ['terminal', { sourceInterval: [1679, 1683] }, '"'], + ], ['seq', { sourceInterval: [1690, 1720] }, ['terminal', { sourceInterval: [1690, 1693] }, "'"], ['star', { + sourceInterval: [1694, 1716], + }, ['app', { sourceInterval: [1694, 1715] }, 'singleStringCharacter', []]], ['terminal', { + sourceInterval: [1717, 1720], + }, "'"]], ['seq', { sourceInterval: [1727, 1759] }, ['terminal', { sourceInterval: [1727, 1730] }, '`'], ['star', { + sourceInterval: [1731, 1755], + }, ['app', { sourceInterval: [1731, 1754] }, 'templateStringCharacter', []]], ['terminal', { + sourceInterval: [1756, 1759], + }, '`']]]], + doubleStringCharacter_NonEscaped: ['define', { sourceInterval: [1794, 1845] }, null, [], ['seq', { + sourceInterval: [1794, 1829], + }, ['not', { sourceInterval: [1794, 1825] }, [ + 'alt', + { sourceInterval: [1796, 1824] }, + ['terminal', { sourceInterval: [1796, 1800] }, '"'], + ['terminal', { sourceInterval: [1803, 1807] }, '\\'], + ['app', { sourceInterval: [1810, 1824] }, 'lineTerminator', []], + ]], ['app', { sourceInterval: [1826, 1829] }, 'any', []]]], + doubleStringCharacter_Escaped: ['define', { sourceInterval: [1852, 1900] }, null, [], [ + 'seq', + { sourceInterval: [1852, 1871] }, + ['terminal', { sourceInterval: [1852, 1856] }, '\\'], + ['app', { sourceInterval: [1857, 1871] }, 'escapeSequence', []], + ]], + doubleStringCharacter_LineContinuation: ['define', { sourceInterval: [1907, 1964] }, null, [], [ + 'app', + { sourceInterval: [1907, 1923] }, + 'lineContinuation', + [], + ]], + doubleStringCharacter: ['define', { sourceInterval: [1764, 1964] }, null, [], [ + 'alt', + { sourceInterval: [1792, 1964] }, + ['app', { sourceInterval: [1794, 1829] }, 'doubleStringCharacter_NonEscaped', []], + ['app', { sourceInterval: [1852, 1871] }, 'doubleStringCharacter_Escaped', []], + ['app', { sourceInterval: [1907, 1923] }, 'doubleStringCharacter_LineContinuation', []], + ]], + singleStringCharacter_NonEscaped: ['define', { sourceInterval: [1999, 2050] }, null, [], ['seq', { + sourceInterval: [1999, 2033], + }, ['not', { sourceInterval: [1999, 2029] }, [ + 'alt', + { sourceInterval: [2001, 2028] }, + ['terminal', { sourceInterval: [2001, 2004] }, "'"], + ['terminal', { sourceInterval: [2007, 2011] }, '\\'], + ['app', { sourceInterval: [2014, 2028] }, 'lineTerminator', []], + ]], ['app', { sourceInterval: [2030, 2033] }, 'any', []]]], + singleStringCharacter_Escaped: ['define', { sourceInterval: [2057, 2105] }, null, [], [ + 'seq', + { sourceInterval: [2057, 2076] }, + ['terminal', { sourceInterval: [2057, 2061] }, '\\'], + ['app', { sourceInterval: [2062, 2076] }, 'escapeSequence', []], + ]], + singleStringCharacter_LineContinuation: ['define', { sourceInterval: [2112, 2169] }, null, [], [ + 'app', + { sourceInterval: [2112, 2128] }, + 'lineContinuation', + [], + ]], + singleStringCharacter: ['define', { sourceInterval: [1969, 2169] }, null, [], [ + 'alt', + { sourceInterval: [1997, 2169] }, + ['app', { sourceInterval: [1999, 2033] }, 'singleStringCharacter_NonEscaped', []], + ['app', { sourceInterval: [2057, 2076] }, 'singleStringCharacter_Escaped', []], + ['app', { sourceInterval: [2112, 2128] }, 'singleStringCharacter_LineContinuation', []], + ]], + templateStringCharacter_NonEscaped: ['define', { sourceInterval: [2207, 2258] }, null, [], ['seq', { + sourceInterval: [2207, 2225], + }, ['not', { sourceInterval: [2207, 2221] }, ['alt', { sourceInterval: [2210, 2220] }, ['terminal', { + sourceInterval: [2210, 2213], + }, '`'], ['terminal', { sourceInterval: [2216, 2220] }, '\\']]], [ + 'app', + { sourceInterval: [2222, 2225] }, + 'any', + [], + ]]], + templateStringCharacter_Escaped: ['define', { sourceInterval: [2265, 2318] }, null, [], [ + 'seq', + { sourceInterval: [2265, 2284] }, + ['terminal', { sourceInterval: [2265, 2269] }, '\\'], + ['app', { sourceInterval: [2270, 2284] }, 'escapeSequence', []], + ]], + templateStringCharacter: ['define', { sourceInterval: [2174, 2318] }, null, [], [ + 'alt', + { sourceInterval: [2205, 2318] }, + ['app', { sourceInterval: [2207, 2225] }, 'templateStringCharacter_NonEscaped', []], + ['app', { sourceInterval: [2265, 2284] }, 'templateStringCharacter_Escaped', []], + ]], + lineContinuation: ['define', { sourceInterval: [2323, 2369] }, null, [], ['seq', { sourceInterval: [2342, 2369] }, [ + 'terminal', + { sourceInterval: [2342, 2346] }, + '\\', + ], ['app', { sourceInterval: [2347, 2369] }, 'lineTerminatorSequence', []]]], + escapeSequence: ['define', { sourceInterval: [2374, 2480] }, null, [], [ + 'alt', + { sourceInterval: [2391, 2480] }, + ['app', { sourceInterval: [2391, 2412] }, 'unicodeEscapeSequence', []], + ['app', { sourceInterval: [2415, 2432] }, 'hexEscapeSequence', []], + ['app', { sourceInterval: [2435, 2454] }, 'octalEscapeSequence', []], + ['app', { sourceInterval: [2457, 2480] }, 'characterEscapeSequence', []], + ]], + characterEscapeSequence: ['define', { sourceInterval: [2485, 2553] }, null, [], [ + 'alt', + { sourceInterval: [2511, 2553] }, + ['app', { sourceInterval: [2511, 2532] }, 'singleEscapeCharacter', []], + ['app', { sourceInterval: [2535, 2553] }, 'nonEscapeCharacter', []], + ]], + singleEscapeCharacter: ['define', { sourceInterval: [2558, 2635] }, null, [], [ + 'alt', + { sourceInterval: [2582, 2635] }, + ['terminal', { sourceInterval: [2582, 2585] }, "'"], + ['terminal', { sourceInterval: [2588, 2592] }, '"'], + ['terminal', { sourceInterval: [2595, 2599] }, '\\'], + ['terminal', { sourceInterval: [2602, 2605] }, 'b'], + ['terminal', { sourceInterval: [2608, 2611] }, 'f'], + ['terminal', { sourceInterval: [2614, 2617] }, 'n'], + ['terminal', { sourceInterval: [2620, 2623] }, 'r'], + ['terminal', { sourceInterval: [2626, 2629] }, 't'], + ['terminal', { sourceInterval: [2632, 2635] }, 'v'], + ]], + nonEscapeCharacter: ['define', { sourceInterval: [2640, 2700] }, null, [], [ + 'seq', + { sourceInterval: [2661, 2700] }, + ['not', { sourceInterval: [2661, 2696] }, ['alt', { sourceInterval: [2663, 2695] }, [ + 'app', + { sourceInterval: [2663, 2678] }, + 'escapeCharacter', + [], + ], ['app', { sourceInterval: [2681, 2695] }, 'lineTerminator', []]]], + ['app', { sourceInterval: [2697, 2700] }, 'any', []], + ]], + escapeCharacter: ['define', { sourceInterval: [2705, 2771] }, null, [], [ + 'alt', + { sourceInterval: [2723, 2771] }, + ['app', { sourceInterval: [2723, 2744] }, 'singleEscapeCharacter', []], + ['app', { sourceInterval: [2747, 2759] }, 'decimalDigit', []], + ['terminal', { sourceInterval: [2762, 2765] }, 'x'], + ['terminal', { sourceInterval: [2768, 2771] }, 'u'], + ]], + octalEscapeSequence_Whole: ['define', { sourceInterval: [2804, 2850] }, null, [], [ + 'seq', + { sourceInterval: [2804, 2837] }, + ['app', { sourceInterval: [2804, 2815] }, 'zeroToThree', []], + ['app', { sourceInterval: [2816, 2826] }, 'octalDigit', []], + ['app', { sourceInterval: [2827, 2837] }, 'octalDigit', []], + ]], + octalEscapeSequence_EightTimesfourToSeven: ['define', { sourceInterval: [2857, 2919] }, null, [], [ + 'seq', + { sourceInterval: [2857, 2879] }, + ['app', { sourceInterval: [2857, 2868] }, 'fourToSeven', []], + ['app', { sourceInterval: [2869, 2879] }, 'octalDigit', []], + ]], + octalEscapeSequence_EightTimesZeroToThree: ['define', { sourceInterval: [2926, 2988] }, null, [], [ + 'seq', + { sourceInterval: [2926, 2962] }, + ['app', { sourceInterval: [2926, 2937] }, 'zeroToThree', []], + ['app', { sourceInterval: [2938, 2948] }, 'octalDigit', []], + ['not', { sourceInterval: [2949, 2962] }, ['app', { sourceInterval: [2950, 2962] }, 'decimalDigit', []]], + ]], + octalEscapeSequence_Octal: ['define', { sourceInterval: [2995, 3041] }, null, [], [ + 'seq', + { sourceInterval: [2995, 3019] }, + ['app', { sourceInterval: [2995, 3005] }, 'octalDigit', []], + ['not', { sourceInterval: [3006, 3019] }, ['app', { sourceInterval: [3007, 3019] }, 'decimalDigit', []]], + ]], + octalEscapeSequence: ['define', { sourceInterval: [2776, 3041] }, null, [], [ + 'alt', + { sourceInterval: [2802, 3041] }, + ['app', { sourceInterval: [2804, 2837] }, 'octalEscapeSequence_Whole', []], + ['app', { sourceInterval: [2857, 2879] }, 'octalEscapeSequence_EightTimesfourToSeven', []], + ['app', { sourceInterval: [2926, 2962] }, 'octalEscapeSequence_EightTimesZeroToThree', []], + ['app', { sourceInterval: [2995, 3019] }, 'octalEscapeSequence_Octal', []], + ]], + hexEscapeSequence: ['define', { sourceInterval: [3046, 3087] }, null, [], [ + 'seq', + { sourceInterval: [3066, 3087] }, + ['terminal', { sourceInterval: [3066, 3069] }, 'x'], + ['app', { sourceInterval: [3070, 3078] }, 'hexDigit', []], + ['app', { sourceInterval: [3079, 3087] }, 'hexDigit', []], + ]], + unicodeEscapeSequence: ['define', { sourceInterval: [3092, 3155] }, null, [], [ + 'seq', + { sourceInterval: [3116, 3155] }, + ['terminal', { sourceInterval: [3116, 3119] }, 'u'], + ['app', { sourceInterval: [3120, 3128] }, 'hexDigit', []], + ['app', { sourceInterval: [3129, 3137] }, 'hexDigit', []], + ['app', { sourceInterval: [3138, 3146] }, 'hexDigit', []], + ['app', { sourceInterval: [3147, 3155] }, 'hexDigit', []], + ]], + zeroToThree: ['define', { sourceInterval: [3161, 3183] }, null, [], [ + 'range', + { sourceInterval: [3175, 3183] }, + '0', + '3', + ]], + fourToSeven: ['define', { sourceInterval: [3188, 3210] }, null, [], [ + 'range', + { sourceInterval: [3202, 3210] }, + '4', + '7', + ]], + decimalDigit: ['define', { sourceInterval: [3215, 3238] }, null, [], [ + 'range', + { sourceInterval: [3230, 3238] }, + '0', + '9', + ]], + nonZeroDigit: ['define', { sourceInterval: [3243, 3266] }, null, [], [ + 'range', + { sourceInterval: [3258, 3266] }, + '1', + '9', + ]], + octalDigit: ['define', { sourceInterval: [3271, 3292] }, null, [], [ + 'range', + { sourceInterval: [3284, 3292] }, + '0', + '7', + ]], + regularExpressionLiteral: ['define', { sourceInterval: [3298, 3377] }, null, [], [ + 'seq', + { sourceInterval: [3325, 3377] }, + ['terminal', { sourceInterval: [3325, 3328] }, '/'], + ['app', { sourceInterval: [3329, 3350] }, 'regularExpressionBody', []], + ['terminal', { sourceInterval: [3351, 3354] }, '/'], + ['app', { sourceInterval: [3355, 3377] }, 'regularExpressionFlags', []], + ]], + regularExpressionBody: ['define', { sourceInterval: [3382, 3455] }, null, [], [ + 'seq', + { sourceInterval: [3406, 3455] }, + ['app', { sourceInterval: [3406, 3432] }, 'regularExpressionFirstChar', []], + ['star', { sourceInterval: [3433, 3455] }, [ + 'app', + { sourceInterval: [3433, 3454] }, + 'regularExpressionChar', + [], + ]], + ]], + regularExpressionFirstChar: ['define', { sourceInterval: [3460, 3621] }, null, [], ['alt', { + sourceInterval: [3493, 3621], + }, ['seq', { sourceInterval: [3495, 3551] }, ['not', { sourceInterval: [3495, 3520] }, [ + 'alt', + { sourceInterval: [3497, 3519] }, + ['terminal', { sourceInterval: [3497, 3500] }, '*'], + ['terminal', { sourceInterval: [3503, 3507] }, '\\'], + ['terminal', { sourceInterval: [3510, 3513] }, '/'], + ['terminal', { sourceInterval: [3516, 3519] }, '['], + ]], ['app', { sourceInterval: [3521, 3551] }, 'regularExpressionNonTerminator', []]], [ + 'app', + { sourceInterval: [3558, 3592] }, + 'regularExpressionBackslashSequence', + [], + ], ['app', { sourceInterval: [3599, 3621] }, 'regularExpressionClass', []]]], + regularExpressionChar: ['define', { sourceInterval: [3626, 3770] }, null, [], ['alt', { + sourceInterval: [3650, 3770], + }, ['seq', { sourceInterval: [3650, 3700] }, ['not', { sourceInterval: [3650, 3669] }, [ + 'alt', + { sourceInterval: [3652, 3668] }, + ['terminal', { sourceInterval: [3652, 3656] }, '\\'], + ['terminal', { sourceInterval: [3659, 3662] }, '/'], + ['terminal', { sourceInterval: [3665, 3668] }, '['], + ]], ['app', { sourceInterval: [3670, 3700] }, 'regularExpressionNonTerminator', []]], [ + 'app', + { sourceInterval: [3707, 3741] }, + 'regularExpressionBackslashSequence', + [], + ], ['app', { sourceInterval: [3748, 3770] }, 'regularExpressionClass', []]]], + regularExpressionBackslashSequence: ['define', { sourceInterval: [3775, 3847] }, null, [], [ + 'seq', + { sourceInterval: [3812, 3847] }, + ['terminal', { sourceInterval: [3812, 3816] }, '\\'], + ['app', { sourceInterval: [3817, 3847] }, 'regularExpressionNonTerminator', []], + ]], + regularExpressionNonTerminator: ['define', { sourceInterval: [3852, 3906] }, null, [], [ + 'seq', + { sourceInterval: [3885, 3906] }, + ['not', { sourceInterval: [3885, 3902] }, ['app', { sourceInterval: [3887, 3901] }, 'lineTerminator', []]], + ['app', { sourceInterval: [3903, 3906] }, 'any', []], + ]], + regularExpressionClass: ['define', { sourceInterval: [3911, 3971] }, null, [], [ + 'seq', + { sourceInterval: [3936, 3971] }, + ['terminal', { sourceInterval: [3936, 3939] }, '['], + ['star', { sourceInterval: [3940, 3967] }, [ + 'app', + { sourceInterval: [3940, 3966] }, + 'regularExpressionClassChar', + [], + ]], + ['terminal', { sourceInterval: [3968, 3971] }, ']'], + ]], + regularExpressionClassChar: ['define', { sourceInterval: [3976, 4096] }, null, [], ['alt', { + sourceInterval: [4009, 4096], + }, ['seq', { sourceInterval: [4011, 4055] }, ['not', { sourceInterval: [4011, 4024] }, [ + 'alt', + { sourceInterval: [4013, 4023] }, + ['terminal', { sourceInterval: [4013, 4016] }, ']'], + ['terminal', { sourceInterval: [4019, 4023] }, '\\'], + ]], ['app', { sourceInterval: [4025, 4055] }, 'regularExpressionNonTerminator', []]], [ + 'app', + { sourceInterval: [4062, 4096] }, + 'regularExpressionBackslashSequence', + [], + ]]], + regularExpressionFlags: ['define', { sourceInterval: [4101, 4141] }, null, [], ['star', { + sourceInterval: [4126, 4141], + }, ['app', { sourceInterval: [4126, 4140] }, 'identifierPart', []]]], + multiLineCommentNoNL: ['define', { sourceInterval: [4147, 4211] }, null, [], [ + 'seq', + { sourceInterval: [4170, 4211] }, + ['terminal', { sourceInterval: [4170, 4174] }, '/*'], + ['star', { sourceInterval: [4175, 4206] }, ['seq', { sourceInterval: [4176, 4204] }, ['not', { + sourceInterval: [4176, 4200], + }, ['alt', { sourceInterval: [4178, 4199] }, ['terminal', { sourceInterval: [4178, 4182] }, '*/'], [ + 'app', + { sourceInterval: [4185, 4199] }, + 'lineTerminator', + [], + ]]], ['app', { sourceInterval: [4201, 4204] }, 'any', []]]], + ['terminal', { sourceInterval: [4207, 4211] }, '*/'], + ]], + identifierStart_escaped: ['define', { sourceInterval: [4266, 4303] }, null, [], [ + 'seq', + { sourceInterval: [4266, 4292] }, + ['terminal', { sourceInterval: [4266, 4270] }, '\\'], + ['app', { sourceInterval: [4271, 4292] }, 'unicodeEscapeSequence', []], + ]], + identifierStart: ['define', { sourceInterval: [4217, 4303] }, null, [], [ + 'alt', + { sourceInterval: [4239, 4303] }, + ['app', { sourceInterval: [4241, 4247] }, 'letter', []], + ['terminal', { sourceInterval: [4250, 4253] }, '$'], + ['terminal', { sourceInterval: [4256, 4259] }, '_'], + ['app', { sourceInterval: [4266, 4292] }, 'identifierStart_escaped', []], + ]], + identifierPart: ['define', { sourceInterval: [4308, 4444] }, null, [], [ + 'alt', + { sourceInterval: [4329, 4444] }, + ['app', { sourceInterval: [4331, 4346] }, 'identifierStart', []], + ['app', { sourceInterval: [4349, 4369] }, 'unicodeCombiningMark', []], + ['app', { sourceInterval: [4376, 4388] }, 'unicodeDigit', []], + ['app', { sourceInterval: [4391, 4418] }, 'unicodeConnectorPunctuation', []], + ['terminal', { sourceInterval: [4425, 4433] }, '‌'], + ['terminal', { sourceInterval: [4436, 4444] }, '‍'], + ]], + letter: ['extend', { sourceInterval: [4449, 4476] }, null, [], [ + 'app', + { sourceInterval: [4459, 4476] }, + 'unicodeCategoryNl', + [], + ]], + unicodeCategoryNl: ['define', { sourceInterval: [4481, 4555] }, null, [], [ + 'alt', + { sourceInterval: [4505, 4555] }, + ['range', { sourceInterval: [4505, 4523] }, 'Ⅰ', 'ↂ'], + ['terminal', { sourceInterval: [4526, 4534] }, '〇'], + ['range', { sourceInterval: [4537, 4555] }, '〡', '〩'], + ]], + unicodeDigit: ['define', { sourceInterval: [4560, 4922] }, 'a digit', [], [ + 'alt', + { sourceInterval: [4589, 4922] }, + ['range', { sourceInterval: [4589, 4607] }, '0', '9'], + ['range', { sourceInterval: [4610, 4628] }, '٠', '٩'], + ['range', { sourceInterval: [4631, 4649] }, '۰', '۹'], + ['range', { sourceInterval: [4652, 4670] }, '०', '९'], + ['range', { sourceInterval: [4673, 4691] }, '০', '৯'], + ['range', { sourceInterval: [4694, 4712] }, '੦', '੯'], + ['range', { sourceInterval: [4715, 4733] }, '૦', '૯'], + ['range', { sourceInterval: [4736, 4754] }, '୦', '୯'], + ['range', { sourceInterval: [4757, 4775] }, '௧', '௯'], + ['range', { sourceInterval: [4778, 4796] }, '౦', '౯'], + ['range', { sourceInterval: [4799, 4817] }, '೦', '೯'], + ['range', { sourceInterval: [4820, 4838] }, '൦', '൯'], + ['range', { sourceInterval: [4841, 4859] }, '๐', '๙'], + ['range', { sourceInterval: [4862, 4880] }, '໐', '໙'], + ['range', { sourceInterval: [4883, 4901] }, '༠', '༩'], + ['range', { sourceInterval: [4904, 4922] }, '0', '9'], + ]], + unicodeCombiningMark: ['define', { sourceInterval: [4928, 6659] }, 'a Unicode combining mark', [], [ + 'alt', + { sourceInterval: [4982, 6659] }, + ['range', { sourceInterval: [4982, 5000] }, '̀', 'ͅ'], + ['range', { sourceInterval: [5003, 5021] }, '͠', '͡'], + ['range', { sourceInterval: [5024, 5042] }, '҃', '҆'], + ['range', { sourceInterval: [5045, 5063] }, '֑', '֡'], + ['range', { sourceInterval: [5066, 5084] }, '֣', 'ֹ'], + ['range', { sourceInterval: [5087, 5105] }, 'ֻ', 'ֽ'], + ['range', { sourceInterval: [5108, 5126] }, 'ֿ', 'ֿ'], + ['range', { sourceInterval: [5129, 5147] }, 'ׁ', 'ׂ'], + ['range', { sourceInterval: [5150, 5168] }, 'ׄ', 'ׄ'], + ['range', { sourceInterval: [5171, 5189] }, 'ً', 'ْ'], + ['range', { sourceInterval: [5192, 5210] }, 'ٰ', 'ٰ'], + ['range', { sourceInterval: [5213, 5231] }, 'ۖ', 'ۜ'], + ['range', { sourceInterval: [5234, 5252] }, '۟', 'ۤ'], + ['range', { sourceInterval: [5255, 5273] }, 'ۧ', 'ۨ'], + ['range', { sourceInterval: [5276, 5294] }, '۪', 'ۭ'], + ['range', { sourceInterval: [5297, 5315] }, 'ँ', 'ं'], + ['range', { sourceInterval: [5318, 5336] }, '़', '़'], + ['range', { sourceInterval: [5339, 5357] }, 'ु', 'ै'], + ['range', { sourceInterval: [5360, 5378] }, '्', '्'], + ['range', { sourceInterval: [5381, 5399] }, '॑', '॔'], + ['range', { sourceInterval: [5402, 5420] }, 'ॢ', 'ॣ'], + ['range', { sourceInterval: [5423, 5441] }, 'ঁ', 'ঁ'], + ['range', { sourceInterval: [5444, 5462] }, '়', '়'], + ['range', { sourceInterval: [5465, 5483] }, 'ু', 'ৄ'], + ['range', { sourceInterval: [5486, 5504] }, '্', '্'], + ['range', { sourceInterval: [5507, 5525] }, 'ৢ', 'ৣ'], + ['range', { sourceInterval: [5528, 5546] }, 'ਂ', 'ਂ'], + ['range', { sourceInterval: [5549, 5567] }, '਼', '਼'], + ['range', { sourceInterval: [5570, 5588] }, 'ੁ', 'ੂ'], + ['range', { sourceInterval: [5591, 5609] }, 'ੇ', 'ੈ'], + ['range', { sourceInterval: [5612, 5630] }, 'ੋ', '੍'], + ['range', { sourceInterval: [5633, 5651] }, 'ੰ', 'ੱ'], + ['range', { sourceInterval: [5654, 5672] }, 'ઁ', 'ં'], + ['range', { sourceInterval: [5675, 5693] }, '઼', '઼'], + ['range', { sourceInterval: [5696, 5714] }, 'ુ', 'ૅ'], + ['range', { sourceInterval: [5717, 5735] }, 'ે', 'ૈ'], + ['range', { sourceInterval: [5738, 5756] }, '્', '્'], + ['range', { sourceInterval: [5759, 5777] }, 'ଁ', 'ଁ'], + ['range', { sourceInterval: [5780, 5798] }, '଼', '଼'], + ['range', { sourceInterval: [5801, 5819] }, 'ି', 'ି'], + ['range', { sourceInterval: [5822, 5840] }, 'ୁ', 'ୃ'], + ['range', { sourceInterval: [5843, 5861] }, '୍', '୍'], + ['range', { sourceInterval: [5864, 5882] }, 'ୖ', 'ୖ'], + ['range', { sourceInterval: [5885, 5903] }, 'ஂ', 'ஂ'], + ['range', { sourceInterval: [5906, 5924] }, 'ீ', 'ீ'], + ['range', { sourceInterval: [5927, 5945] }, '்', '்'], + ['range', { sourceInterval: [5948, 5966] }, 'ా', 'ీ'], + ['range', { sourceInterval: [5969, 5987] }, 'ె', 'ై'], + ['range', { sourceInterval: [5990, 6008] }, 'ొ', '్'], + ['range', { sourceInterval: [6011, 6029] }, 'ౕ', 'ౖ'], + ['range', { sourceInterval: [6032, 6050] }, 'ಿ', 'ಿ'], + ['range', { sourceInterval: [6053, 6071] }, 'ೆ', 'ೆ'], + ['range', { sourceInterval: [6074, 6092] }, 'ೌ', '್'], + ['range', { sourceInterval: [6095, 6113] }, 'ു', 'ൃ'], + ['range', { sourceInterval: [6116, 6134] }, '്', '്'], + ['range', { sourceInterval: [6137, 6155] }, 'ั', 'ั'], + ['range', { sourceInterval: [6158, 6176] }, 'ิ', 'ฺ'], + ['range', { sourceInterval: [6179, 6197] }, '็', '๎'], + ['range', { sourceInterval: [6200, 6218] }, 'ັ', 'ັ'], + ['range', { sourceInterval: [6221, 6239] }, 'ິ', 'ູ'], + ['range', { sourceInterval: [6242, 6260] }, 'ົ', 'ຼ'], + ['range', { sourceInterval: [6263, 6281] }, '່', 'ໍ'], + ['range', { sourceInterval: [6284, 6302] }, '༘', '༙'], + ['range', { sourceInterval: [6305, 6323] }, '༵', '༵'], + ['range', { sourceInterval: [6326, 6344] }, '༷', '༷'], + ['range', { sourceInterval: [6347, 6365] }, '༹', '༹'], + ['range', { sourceInterval: [6368, 6386] }, 'ཱ', 'ཾ'], + ['range', { sourceInterval: [6389, 6407] }, 'ྀ', '྄'], + ['range', { sourceInterval: [6410, 6428] }, '྆', '྇'], + ['range', { sourceInterval: [6431, 6449] }, 'ྐ', 'ྕ'], + ['range', { sourceInterval: [6452, 6470] }, 'ྗ', 'ྗ'], + ['range', { sourceInterval: [6473, 6491] }, 'ྙ', 'ྭ'], + ['range', { sourceInterval: [6494, 6512] }, 'ྱ', 'ྷ'], + ['range', { sourceInterval: [6515, 6533] }, 'ྐྵ', 'ྐྵ'], + ['range', { sourceInterval: [6536, 6554] }, '⃐', '⃜'], + ['range', { sourceInterval: [6557, 6575] }, '⃡', '⃡'], + ['range', { sourceInterval: [6578, 6596] }, '〪', '〯'], + ['range', { sourceInterval: [6599, 6617] }, '゙', '゚'], + ['range', { sourceInterval: [6620, 6638] }, 'ﬞ', 'ﬞ'], + ['range', { sourceInterval: [6641, 6659] }, '︠', '︣'], + ]], + unicodeConnectorPunctuation: ['define', { sourceInterval: [6665, 6799] }, null, [], [ + 'alt', + { sourceInterval: [6695, 6799] }, + ['terminal', { sourceInterval: [6695, 6703] }, '_'], + ['range', { sourceInterval: [6706, 6724] }, '‿', '⁀'], + ['terminal', { sourceInterval: [6727, 6735] }, '・'], + ['range', { sourceInterval: [6738, 6756] }, '︳', '︴'], + ['range', { sourceInterval: [6759, 6777] }, '﹍', '﹏'], + ['terminal', { sourceInterval: [6780, 6788] }, '_'], + ['terminal', { sourceInterval: [6791, 6799] }, '・'], + ]], + unicodeSpaceSeparator: ['define', { sourceInterval: [6804, 6857] }, null, [], [ + 'alt', + { sourceInterval: [6828, 6857] }, + ['range', { sourceInterval: [6828, 6846] }, ' ', '​'], + ['terminal', { sourceInterval: [6849, 6857] }, ' '], + ]], + }, +]); +export default result; diff --git a/drizzle-kit/imports-checker/index.ts b/drizzle-kit/imports-checker/index.ts index 911d84ff6..7a4e90838 100644 --- a/drizzle-kit/imports-checker/index.ts +++ b/drizzle-kit/imports-checker/index.ts @@ -1,49 +1,48 @@ -import { analyzeImports, ChainLink } from "./checker"; -import chalk from "chalk"; +import chalk from 'chalk'; +import { analyzeImports, ChainLink } from './checker'; const issues = analyzeImports({ - basePath: "./drizzle-kit", - localPaths: ["src"], - whiteList: [ - "@drizzle-team/brocli", - "json-diff", - "path", - "fs", - "fs/*", - "url", - "zod", - "node:*", - "hono", - "glob", - "hono/*", - "hono/**/*", - "@hono/*", - "crypto", - "hanji", - ], - entry: "./drizzle-kit/src/cli/index.ts", - logger: true, - ignoreTypes: true, + basePath: './drizzle-kit', + localPaths: ['src'], + whiteList: [ + '@drizzle-team/brocli', + 'json-diff', + 'path', + 'fs', + 'fs/*', + 'url', + 'zod', + 'node:*', + 'hono', + 'glob', + 'hono/*', + 'hono/**/*', + '@hono/*', + 'crypto', + 'hanji', + ], + entry: './drizzle-kit/src/cli/index.ts', + logger: true, + ignoreTypes: true, }).issues; const chainToString = (chains: ChainLink[]) => { - if (chains.length === 0) throw new Error(); + if (chains.length === 0) throw new Error(); - let out = chains[0]!.file + "\n"; - let indentation = 0; - for (let chain of chains) { - out += - " ".repeat(indentation) + - "└" + - chain.import + - ` ${chalk.gray(chain.file)}\n`; - indentation += 1; - } - return out; + let out = chains[0]!.file + '\n'; + let indentation = 0; + for (let chain of chains) { + out += ' '.repeat(indentation) + + '└' + + chain.import + + ` ${chalk.gray(chain.file)}\n`; + indentation += 1; + } + return out; }; console.log(); for (const issue of issues) { - console.log(chalk.red(issue.imports.map((it) => it.name).join("\n"))); - console.log(issue.accessChains.map((it) => chainToString(it)).join("\n")); + console.log(chalk.red(issue.imports.map((it) => it.name).join('\n'))); + console.log(issue.accessChains.map((it) => chainToString(it)).join('\n')); } diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 84f23f1a2..b03acde95 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -591,7 +591,7 @@ export const studio = command({ drizzleForMySQL, prepareSQLiteSchema, drizzleForSQLite, - drizzleForLibSQL + drizzleForLibSQL, } = await import('../serializer/studio'); let setup: Setup; diff --git a/drizzle-kit/tests/bin.test.ts b/drizzle-kit/tests/bin.test.ts index 3b338e448..826496676 100644 --- a/drizzle-kit/tests/bin.test.ts +++ b/drizzle-kit/tests/bin.test.ts @@ -1,59 +1,58 @@ -import { analyzeImports, ChainLink } from "../imports-checker/checker"; -import chalk from "chalk"; -import { assert, test } from "vitest"; +import chalk from 'chalk'; +import { assert, test } from 'vitest'; +import { analyzeImports, ChainLink } from '../imports-checker/checker'; -test("imports-issues", () => { - const issues = analyzeImports({ - basePath: ".", - localPaths: ["src"], - whiteList: [ - "@drizzle-team/brocli", - "json-diff", - "path", - "fs", - "fs/*", - "url", - "zod", - "node:*", - "hono", - "glob", - "hono/*", - "hono/**/*", - "@hono/*", - "crypto", - "hanji", - "chalk", - "dotenv/config", - "camelcase", - "semver", - "env-paths", - ], - entry: "src/cli/index.ts", - logger: true, - ignoreTypes: true, - }).issues; +test('imports-issues', () => { + const issues = analyzeImports({ + basePath: '.', + localPaths: ['src'], + whiteList: [ + '@drizzle-team/brocli', + 'json-diff', + 'path', + 'fs', + 'fs/*', + 'url', + 'zod', + 'node:*', + 'hono', + 'glob', + 'hono/*', + 'hono/**/*', + '@hono/*', + 'crypto', + 'hanji', + 'chalk', + 'dotenv/config', + 'camelcase', + 'semver', + 'env-paths', + ], + entry: 'src/cli/index.ts', + logger: true, + ignoreTypes: true, + }).issues; - const chainToString = (chains: ChainLink[]) => { - if (chains.length === 0) throw new Error(); + const chainToString = (chains: ChainLink[]) => { + if (chains.length === 0) throw new Error(); - let out = chains[0]!.file + "\n"; - let indentation = 0; - for (let chain of chains) { - out += - " ".repeat(indentation) + - "└" + - chain.import + - ` ${chalk.gray(chain.file)}\n`; - indentation += 1; - } - return out; - }; + let out = chains[0]!.file + '\n'; + let indentation = 0; + for (let chain of chains) { + out += ' '.repeat(indentation) + + '└' + + chain.import + + ` ${chalk.gray(chain.file)}\n`; + indentation += 1; + } + return out; + }; - console.log(); - for (const issue of issues) { - console.log(chalk.red(issue.imports.map((it) => it.name).join("\n"))); - console.log(issue.accessChains.map((it) => chainToString(it)).join("\n")); - } + console.log(); + for (const issue of issues) { + console.log(chalk.red(issue.imports.map((it) => it.name).join('\n'))); + console.log(issue.accessChains.map((it) => chainToString(it)).join('\n')); + } - assert.equal(issues.length, 0); + assert.equal(issues.length, 0); }); From 19f042a599b449a6b0053fa039a1a9d1fd9ca948 Mon Sep 17 00:00:00 2001 From: L-Mario564 Date: Sun, 3 Nov 2024 08:53:16 -0800 Subject: [PATCH 289/492] [MySQL] Add unsigned floating point types + Fix unsigned integer type bugs in Kit (#3284) * Fix bugs with MySQL introspection tests * Update float data type in MySQL * Better support for float types in MySQL * Handle existing unsigned numerical types in MySQL * Add unsigned to floating point types in MySQL * Handle unsigned floating point types in MySQL * Update decimal data type --------- Co-authored-by: Andrii Sherman --- drizzle-kit/src/introspect-mysql.ts | 71 +++++++++++---- drizzle-kit/src/serializer/mysqlSerializer.ts | 4 +- drizzle-kit/tests/introspect/mysql.test.ts | 90 +++++++++++++++---- drizzle-kit/tests/push/common.ts | 5 +- drizzle-kit/tests/push/mysql.test.ts | 6 ++ drizzle-orm/src/mysql-core/columns/decimal.ts | 20 +++-- drizzle-orm/src/mysql-core/columns/double.ts | 15 ++-- drizzle-orm/src/mysql-core/columns/float.ts | 45 ++++++++-- drizzle-orm/type-tests/mysql/tables.ts | 6 ++ 9 files changed, 206 insertions(+), 56 deletions(-) diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index ea287713f..c15fea937 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -179,6 +179,12 @@ export const schemaToTypeScript = ( patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; patched = patched.startsWith('int(') ? 'int' : patched; patched = patched.startsWith('double(') ? 'double' : patched; + patched = patched.startsWith('float(') ? 'float' : patched; + patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; + patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; + patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; + patched = patched.startsWith('bigint unsigned') ? 'bigint' : patched; return patched; }) .filter((type) => { @@ -207,6 +213,12 @@ export const schemaToTypeScript = ( patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; patched = patched.startsWith('int(') ? 'int' : patched; patched = patched.startsWith('double(') ? 'double' : patched; + patched = patched.startsWith('float(') ? 'float' : patched; + patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; + patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; + patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; + patched = patched.startsWith('bigint unsigned') ? 'bigint' : patched; return patched; }) .filter((type) => { @@ -397,8 +409,9 @@ const column = ( if (lowered.startsWith('int')) { const isUnsigned = lowered.startsWith('int unsigned'); - let out = `${casing(name)}: int(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? '{ unsigned: true }' : '' + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: int(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += typeof defaultValue !== 'undefined' @@ -409,9 +422,10 @@ const column = ( if (lowered.startsWith('tinyint')) { const isUnsigned = lowered.startsWith('tinyint unsigned'); + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); // let out = `${name.camelCase()}: tinyint("${name}")`; - let out: string = `${casing(name)}: tinyint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? ', { unsigned: true }' : '' + let out: string = `${casing(name)}: tinyint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += typeof defaultValue !== 'undefined' @@ -422,8 +436,9 @@ const column = ( if (lowered.startsWith('smallint')) { const isUnsigned = lowered.startsWith('smallint unsigned'); - let out = `${casing(name)}: smallint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? ', { unsigned: true }' : '' + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: smallint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue @@ -434,8 +449,9 @@ const column = ( if (lowered.startsWith('mediumint')) { const isUnsigned = lowered.startsWith('mediumint unsigned'); - let out = `${casing(name)}: mediumint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? ', { unsigned: true }' : '' + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: mediumint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue @@ -466,16 +482,20 @@ const column = ( if (lowered.startsWith('double')) { let params: - | { precision: string | undefined; scale: string | undefined } + | { precision?: string; scale?: string; unsigned?: boolean } | undefined; - if (lowered.length > 6) { + if (lowered.length > (lowered.includes('unsigned') ? 15 : 6)) { const [precision, scale] = lowered - .slice(7, lowered.length - 1) + .slice(7, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) .split(','); params = { precision, scale }; } + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + const timeConfigParams = params ? timeConfig(params) : undefined; let out = params @@ -491,8 +511,23 @@ const column = ( return out; } - if (lowered === 'float') { - let out = `${casing(name)}: float(${dbColumnName({ name, casing: rawCasing })})`; + if (lowered.startsWith('float')) { + let params: + | { precision?: string; scale?: string; unsigned?: boolean } + | undefined; + + if (lowered.length > (lowered.includes('unsigned') ? 14 : 5)) { + const [precision, scale] = lowered + .slice(6, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) + .split(','); + params = { precision, scale }; + } + + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + + let out = `${casing(name)}: float(${dbColumnName({ name, casing: rawCasing })}${params ? timeConfig(params) : ''})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -700,16 +735,20 @@ const column = ( if (lowered.startsWith('decimal')) { let params: - | { precision: string | undefined; scale: string | undefined } + | { precision?: string; scale?: string; unsigned?: boolean } | undefined; - if (lowered.length > 7) { + if (lowered.length > (lowered.includes('unsigned') ? 16 : 7)) { const [precision, scale] = lowered - .slice(8, lowered.length - 1) + .slice(8, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) .split(','); params = { precision, scale }; } + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + const timeConfigParams = params ? timeConfig(params) : undefined; let out = params diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index f7fa7f3f0..25ca1d596 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -651,8 +651,8 @@ export const fromDatabase = async ( } } - if (columnType.startsWith('tinyint')) { - changedType = 'tinyint'; + if (columnType.includes('decimal(10,0)')) { + changedType = columnType.replace('decimal(10,0)', 'decimal'); } let onUpdate: boolean | undefined = undefined; diff --git a/drizzle-kit/tests/introspect/mysql.test.ts b/drizzle-kit/tests/introspect/mysql.test.ts index 024300bea..5ea326793 100644 --- a/drizzle-kit/tests/introspect/mysql.test.ts +++ b/drizzle-kit/tests/introspect/mysql.test.ts @@ -1,12 +1,29 @@ +import 'dotenv/config'; import Docker from 'dockerode'; import { SQL, sql } from 'drizzle-orm'; -import { char, check, int, mysqlTable, mysqlView, serial, text, varchar } from 'drizzle-orm/mysql-core'; +import { + bigint, + char, + check, + decimal, + double, + float, + int, + mediumint, + mysqlTable, + mysqlView, + serial, + smallint, + text, + tinyint, + varchar, +} from 'drizzle-orm/mysql-core'; import * as fs from 'fs'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; import { introspectMySQLToFile } from 'tests/schemaDiffer'; import { v4 as uuid } from 'uuid'; -import { afterAll, beforeAll, expect, test } from 'vitest'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; let client: Connection; let mysqlContainer: Docker.Container; @@ -71,6 +88,12 @@ afterAll(async () => { await mysqlContainer?.stop().catch(console.error); }); +beforeEach(async () => { + await client.query(`drop database if exists \`drizzle\`;`); + await client.query(`create database \`drizzle\`;`); + await client.query(`use \`drizzle\`;`); +}); + if (!fs.existsSync('tests/introspect/mysql')) { fs.mkdirSync('tests/introspect/mysql'); } @@ -95,8 +118,6 @@ test('generated always column: link to another column', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('generated always column virtual: link to another column', async () => { @@ -120,8 +141,6 @@ test('generated always column virtual: link to another column', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('Default value of character type column: char', async () => { @@ -141,8 +160,6 @@ test('Default value of character type column: char', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('Default value of character type column: varchar', async () => { @@ -162,8 +179,6 @@ test('Default value of character type column: varchar', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('introspect checks', async () => { @@ -186,8 +201,6 @@ test('introspect checks', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('view #1', async () => { @@ -210,14 +223,9 @@ test('view #1', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop view some_view;`); - await client.query(`drop table users;`); }); test('view #2', async () => { - // await client.query(`drop view some_view;`); - const users = mysqlTable('some_users', { id: int('id') }); const testView = mysqlView('some_view', { id: int('id') }).algorithm('temptable').sqlSecurity('definer').as( sql`SELECT * FROM ${users}`, @@ -237,6 +245,52 @@ test('view #2', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); +}); + +test('handle float type', async () => { + const schema = { + table: mysqlTable('table', { + col1: float(), + col2: float({ precision: 2 }), + col3: float({ precision: 2, scale: 1 }), + }), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'handle-float-type', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('handle unsigned numerical types', async () => { + const schema = { + table: mysqlTable('table', { + col1: int({ unsigned: true }), + col2: tinyint({ unsigned: true }), + col3: smallint({ unsigned: true }), + col4: mediumint({ unsigned: true }), + col5: bigint({ mode: 'number', unsigned: true }), + col6: float({ unsigned: true }), + col7: float({ precision: 2, scale: 1, unsigned: true }), + col8: double({ unsigned: true }), + col9: double({ precision: 2, scale: 1, unsigned: true }), + col10: decimal({ unsigned: true }), + col11: decimal({ precision: 2, scale: 1, unsigned: true }), + }), + }; - await client.query(`drop table some_users;`); + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'handle-unsigned-numerical-types', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); }); diff --git a/drizzle-kit/tests/push/common.ts b/drizzle-kit/tests/push/common.ts index 0c679ca6f..e5c68625d 100644 --- a/drizzle-kit/tests/push/common.ts +++ b/drizzle-kit/tests/push/common.ts @@ -1,4 +1,4 @@ -import { afterAll, beforeAll, test } from 'vitest'; +import { afterAll, beforeAll, beforeEach, test } from 'vitest'; export interface DialectSuite { allTypes(context?: any): Promise; @@ -22,10 +22,13 @@ export const run = ( suite: DialectSuite, beforeAllFn?: (context: any) => Promise, afterAllFn?: (context: any) => Promise, + beforeEachFn?: (context: any) => Promise, ) => { let context: any = {}; beforeAll(beforeAllFn ? () => beforeAllFn(context) : () => {}); + beforeEach(beforeEachFn ? () => beforeEachFn(context) : () => {}); + test('No diffs for all database types', () => suite.allTypes(context)); test('Adding basic indexes', () => suite.addBasicIndexes(context)); test('Dropping basic index', () => suite.dropIndex(context)); diff --git a/drizzle-kit/tests/push/mysql.test.ts b/drizzle-kit/tests/push/mysql.test.ts index 5cad140be..7b20dc444 100644 --- a/drizzle-kit/tests/push/mysql.test.ts +++ b/drizzle-kit/tests/push/mysql.test.ts @@ -1,3 +1,4 @@ +import 'dotenv/config'; import Docker from 'dockerode'; import { SQL, sql } from 'drizzle-orm'; import { @@ -696,4 +697,9 @@ run( await context.client?.end().catch(console.error); await context.mysqlContainer?.stop().catch(console.error); }, + async (context: any) => { + await context.client?.query(`drop database if exists \`drizzle\`;`); + await context.client?.query(`create database \`drizzle\`;`); + await context.client?.query(`use \`drizzle\`;`); + }, ); diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index 1e5f78679..67cefb531 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -20,10 +20,11 @@ export class MySqlDecimalBuilder< > extends MySqlColumnBuilderWithAutoIncrement { static override readonly [entityKind]: string = 'MySqlDecimalBuilder'; - constructor(name: T['name'], precision?: number, scale?: number) { + constructor(name: T['name'], config: MySqlDecimalConfig | undefined) { super(name, 'string', 'MySqlDecimal'); - this.config.precision = precision; - this.config.scale = scale; + this.config.precision = config?.precision; + this.config.scale = config?.scale; + this.config.unsigned = config?.unsigned; } /** @internal */ @@ -44,21 +45,26 @@ export class MySqlDecimal> readonly precision: number | undefined = this.config.precision; readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; getSQLType(): string { + let type = ''; if (this.precision !== undefined && this.scale !== undefined) { - return `decimal(${this.precision},${this.scale})`; + type += `decimal(${this.precision},${this.scale})`; } else if (this.precision === undefined) { - return 'decimal'; + type += 'decimal'; } else { - return `decimal(${this.precision})`; + type += `decimal(${this.precision})`; } + type = type === 'decimal(10,0)' || type === 'decimal(10)' ? 'decimal' : type; + return this.unsigned ? `${type} unsigned` : type; } } export interface MySqlDecimalConfig { precision?: number; scale?: number; + unsigned?: boolean; } export function decimal(): MySqlDecimalBuilderInitial<''>; @@ -71,5 +77,5 @@ export function decimal( ): MySqlDecimalBuilderInitial; export function decimal(a?: string | MySqlDecimalConfig, b: MySqlDecimalConfig = {}) { const { name, config } = getColumnNameAndConfig(a, b); - return new MySqlDecimalBuilder(name, config.precision, config.scale); + return new MySqlDecimalBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index c9f95fd04..dfe5fca2e 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -24,6 +24,7 @@ export class MySqlDoubleBuilder> { static override readonly [entityKind]: string = 'MySqlDouble'; - precision: number | undefined = this.config.precision; - scale: number | undefined = this.config.scale; + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; getSQLType(): string { + let type = ''; if (this.precision !== undefined && this.scale !== undefined) { - return `double(${this.precision},${this.scale})`; + type += `double(${this.precision},${this.scale})`; } else if (this.precision === undefined) { - return 'double'; + type += 'double'; } else { - return `double(${this.precision})`; + type += `double(${this.precision})`; } + return this.unsigned ? `${type} unsigned` : type; } } export interface MySqlDoubleConfig { precision?: number; scale?: number; + unsigned?: boolean; } export function double(): MySqlDoubleBuilderInitial<''>; diff --git a/drizzle-orm/src/mysql-core/columns/float.ts b/drizzle-orm/src/mysql-core/columns/float.ts index d7c3e586b..12ebd3e74 100644 --- a/drizzle-orm/src/mysql-core/columns/float.ts +++ b/drizzle-orm/src/mysql-core/columns/float.ts @@ -2,6 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ @@ -15,12 +16,15 @@ export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ }>; export class MySqlFloatBuilder> - extends MySqlColumnBuilderWithAutoIncrement + extends MySqlColumnBuilderWithAutoIncrement { static override readonly [entityKind]: string = 'MySqlFloatBuilder'; - constructor(name: T['name']) { + constructor(name: T['name'], config: MySqlFloatConfig | undefined) { super(name, 'number', 'MySqlFloat'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + this.config.unsigned = config?.unsigned; } /** @internal */ @@ -31,16 +35,43 @@ export class MySqlFloatBuilder> extends MySqlColumnWithAutoIncrement { +export class MySqlFloat> + extends MySqlColumnWithAutoIncrement +{ static override readonly [entityKind]: string = 'MySqlFloat'; + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; + getSQLType(): string { - return 'float'; + let type = ''; + if (this.precision !== undefined && this.scale !== undefined) { + type += `float(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + type += 'float'; + } else { + type += `float(${this.precision})`; + } + return this.unsigned ? `${type} unsigned` : type; } } +export interface MySqlFloatConfig { + precision?: number; + scale?: number; + unsigned?: boolean; +} + export function float(): MySqlFloatBuilderInitial<''>; -export function float(name: TName): MySqlFloatBuilderInitial; -export function float(name?: string) { - return new MySqlFloatBuilder(name ?? ''); +export function float( + config?: MySqlFloatConfig, +): MySqlFloatBuilderInitial<''>; +export function float( + name: TName, + config?: MySqlFloatConfig, +): MySqlFloatBuilderInitial; +export function float(a?: string | MySqlFloatConfig, b?: MySqlFloatConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new MySqlFloatBuilder(name, config); } diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index aca5c63d7..adc8e8eb8 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -864,6 +864,9 @@ Expect< enum: mysqlEnum('enum', ['a', 'b', 'c']), enumdef: mysqlEnum('enumdef', ['a', 'b', 'c']).default('a'), float: float('float'), + float2: float('float2', { precision: 10 }), + float3: float('float3', { scale: 2 }), + float4: float('float4', { precision: 10, scale: 2 }), floatdef: float('floatdef').default(0), int: int('int'), int2: int('int2', { unsigned: true }), @@ -961,6 +964,9 @@ Expect< enum: mysqlEnum(['a', 'b', 'c']), enumdef: mysqlEnum(['a', 'b', 'c']).default('a'), float: float(), + float2: float({ precision: 10 }), + float3: float({ scale: 2 }), + float4: float({ precision: 10, scale: 2 }), floatdef: float().default(0), int: int(), int2: int({ unsigned: true }), From 998119e20aa7696dfc792038ac66120396a1ccca Mon Sep 17 00:00:00 2001 From: L-Mario564 Date: Mon, 4 Nov 2024 01:55:35 -0800 Subject: [PATCH 290/492] Batch of bugfixes for ORM (#3181) * (MySQL) Fix placeholder type error in offset and limit * Add prepared statement tests * Add PG test * Fix blob parsing in bun sqlite driver * Lint and format * Fix file * Fix tests * Use const instead of let in tests * Format --------- Co-authored-by: Andrii Sherman --- .../src/mysql-core/query-builders/select.ts | 6 +- drizzle-orm/src/sqlite-core/columns/blob.ts | 8 +-- integration-tests/tests/bun/sqlite.test.ts | 56 +++++++--------- integration-tests/tests/mysql/mysql-common.ts | 67 ++++++++++++++++++- integration-tests/tests/pg/pg-common.ts | 47 +++++++++++++ .../tests/sqlite/sqlite-common.ts | 62 +++++++++++++++++ 6 files changed, 203 insertions(+), 43 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index 95f67827b..63c4b903e 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -17,7 +17,7 @@ import type { } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, Query } from '~/sql/sql.ts'; +import type { ColumnsSelection, Placeholder, Query } from '~/sql/sql.ts'; import { SQL, View } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; @@ -811,7 +811,7 @@ export abstract class MySqlSelectQueryBuilderBase< * await db.select().from(people).limit(10); * ``` */ - limit(limit: number): MySqlSelectWithout { + limit(limit: number | Placeholder): MySqlSelectWithout { if (this.config.setOperators.length > 0) { this.config.setOperators.at(-1)!.limit = limit; } else { @@ -836,7 +836,7 @@ export abstract class MySqlSelectQueryBuilderBase< * await db.select().from(people).offset(10).limit(10); * ``` */ - offset(offset: number): MySqlSelectWithout { + offset(offset: number | Placeholder): MySqlSelectWithout { if (this.config.setOperators.length > 0) { this.config.setOperators.at(-1)!.offset = offset; } else { diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index b7cd90be1..22deb3a84 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -41,8 +41,8 @@ export class SQLiteBigInt> return 'blob'; } - override mapFromDriverValue(value: Buffer): bigint { - return BigInt(value.toString()); + override mapFromDriverValue(value: Buffer | Uint8Array): bigint { + return BigInt(Buffer.isBuffer(value) ? value.toString() : String.fromCodePoint(...value)); } override mapToDriverValue(value: bigint): Buffer { @@ -87,8 +87,8 @@ export class SQLiteBlobJson return 'blob'; } - override mapFromDriverValue(value: Buffer): T['data'] { - return JSON.parse(value.toString()); + override mapFromDriverValue(value: Buffer | Uint8Array): T['data'] { + return JSON.parse(Buffer.isBuffer(value) ? value.toString() : String.fromCodePoint(...value)); } override mapToDriverValue(value: T['data']): Buffer { diff --git a/integration-tests/tests/bun/sqlite.test.ts b/integration-tests/tests/bun/sqlite.test.ts index 0065b1928..c6ce9d4d1 100644 --- a/integration-tests/tests/bun/sqlite.test.ts +++ b/integration-tests/tests/bun/sqlite.test.ts @@ -1,41 +1,34 @@ -/// import { Database } from 'bun:sqlite'; -import { DefaultLogger, sql } from 'drizzle-orm'; +import { beforeAll, beforeEach, expect, test } from 'bun:test'; +import { sql } from 'drizzle-orm'; import type { BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite'; import { drizzle } from 'drizzle-orm/bun-sqlite'; import { blob, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { suite } from 'uvu'; -import * as assert from 'uvu/assert'; const usersTable = sqliteTable('users', { id: integer('id').primaryKey(), name: text('name').notNull(), verified: integer('verified').notNull().default(0), json: blob('json', { mode: 'json' }).$type(), - createdAt: integer('created_at', { mode: 'timestamp' }).notNull().defaultNow(), + bigInt: blob('big_int', { mode: 'bigint' }), + createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull().default(sql`strftime('%s', 'now')`), }); -interface Context { - db: BunSQLiteDatabase; -} +let db: BunSQLiteDatabase; -const test = suite('sqlite-bun'); - -test.before((ctx) => { +beforeAll(async () => { try { const dbPath = process.env['SQLITE_DB_PATH'] ?? ':memory:'; const client = new Database(dbPath); - ctx.db = drizzle(client, { logger: new DefaultLogger() }); + db = drizzle(client); } catch (e) { console.error(e); } }); -test.before.each((ctx) => { +beforeEach(async () => { try { - const { db } = ctx; - db.run(sql`drop table if exists ${usersTable}`); db.run(sql` create table ${usersTable} ( @@ -43,7 +36,8 @@ test.before.each((ctx) => { name text not null, verified integer not null default 0, json blob, - created_at text not null default (strftime('%s', 'now')) + big_int blob, + created_at integer not null default (strftime('%s', 'now')) ) `); } catch (e) { @@ -51,34 +45,30 @@ test.before.each((ctx) => { } }); -test.skip('select large integer', async (ctx) => { +test.skip('select large integer', () => { const a = 1667476703000; - const res = await ctx.db.all<{ a: number }>(sql`select ${sql.raw(String(a))} as a`); + const res = db.all<{ a: number }>(sql`select ${sql.raw(String(a))} as a`); const result = res[0]!; - assert.equal(result.a, a); + expect(result.a).toEqual(a); }); -test('select all fields', (ctx) => { - const { db } = ctx; - +test('select all fields', () => { const now = Date.now(); db.insert(usersTable).values({ name: 'John' }).run(); const result = db.select().from(usersTable).all()[0]!; - assert.ok(result.createdAt instanceof Date, 'createdAt is a Date'); // eslint-disable-line no-instanceof/no-instanceof - assert.ok( - Math.abs(result.createdAt.getTime() - now) < 100, - `${result.createdAt.getTime()} is within 100ms of ${now}`, - ); - assert.equal( - result, - { id: 1, name: 'John', verified: 0, json: null, createdAt: result.createdAt }, - 'result is correct', - ); + expect(result.createdAt).toBeInstanceOf(Date); + expect(Math.abs(result.createdAt.getTime() - now)).toBeLessThan(100); + expect(result).toEqual({ id: 1, name: 'John', verified: 0, json: null, createdAt: result.createdAt, bigInt: null }); }); -test.run(); +test('select bigint', () => { + db.insert(usersTable).values({ name: 'John', bigInt: BigInt(100) }).run(); + const result = db.select({ bigInt: usersTable.bigInt }).from(usersTable).all()[0]!; + + expect(result).toEqual({ bigInt: BigInt(100) }); +}); // test.serial('select partial', (t) => { // const { db } = t.context; diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 45b96f391..5dde42934 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -19,7 +19,6 @@ import { min, Name, notInArray, - placeholder, sql, sum, sumDistinct, @@ -1184,7 +1183,7 @@ export function tests(driver?: string) { const stmt = db.insert(usersTable).values({ verified: true, - name: placeholder('name'), + name: sql.placeholder('name'), }).prepare(); for (let i = 0; i < 10; i++) { @@ -1219,13 +1218,75 @@ export function tests(driver?: string) { id: usersTable.id, name: usersTable.name, }).from(usersTable) - .where(eq(usersTable.id, placeholder('id'))) + .where(eq(usersTable.id, sql.placeholder('id'))) .prepare(); const result = await stmt.execute({ id: 1 }); expect(result).toEqual([{ id: 1, name: 'John' }]); }); + test('prepared statement with placeholder in .limit', async (ctx) => { + const { db } = ctx.mysql; + + await db.insert(usersTable).values({ name: 'John' }); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .limit(sql.placeholder('limit')) + .prepare(); + + const result = await stmt.execute({ id: 1, limit: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + expect(result).toHaveLength(1); + }); + + test('prepared statement with placeholder in .offset', async (ctx) => { + const { db } = ctx.mysql; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .limit(sql.placeholder('limit')) + .offset(sql.placeholder('offset')) + .prepare(); + + const result = await stmt.execute({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + }); + + test('prepared statement built using $dynamic', async (ctx) => { + const { db } = ctx.mysql; + + function withLimitOffset(qb: any) { + return qb.limit(sql.placeholder('limit')).offset(sql.placeholder('offset')); + } + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .$dynamic(); + withLimitOffset(stmt).prepare('stmt_limit'); + + const result = await stmt.execute({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + expect(result).toHaveLength(1); + }); + test('migrator', async (ctx) => { const { db } = ctx.mysql; diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 3b3e4cb4d..c7f4b9be7 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -1260,6 +1260,29 @@ export function tests() { expect(result).toEqual([{ id: 2, name: 'John1' }]); }); + test('prepared statement built using $dynamic', async (ctx) => { + const { db } = ctx.pg; + + function withLimitOffset(qb: any) { + return qb.limit(sql.placeholder('limit')).offset(sql.placeholder('offset')); + } + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .$dynamic(); + withLimitOffset(stmt).prepare('stmt_limit'); + + const result = await stmt.execute({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + expect(result).toHaveLength(1); + }); + // TODO change tests to new structure test('Query check: Insert all defaults in 1 row', async (ctx) => { const { db } = ctx.pg; @@ -5041,5 +5064,29 @@ export function tests() { { count: 3 }, ]); }); + + test('insert multiple rows into table with generated identity column', async (ctx) => { + const { db } = ctx.pg; + + const users = pgTable('users', { + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} ("id" integer generated always as identity primary key, "name" text)`); + + const result = await db.insert(users).values([ + { name: 'John' }, + { name: 'Jane' }, + { name: 'Bob' }, + ]).returning(); + + expect(result).toEqual([ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Bob' }, + ]); + }); }); } diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 83beff74d..a20ce5bbf 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -906,6 +906,68 @@ export function tests() { expect(result).toEqual([{ id: 1, name: 'John' }]); }); + test('prepared statement with placeholder in .limit', async (ctx) => { + const { db } = ctx.sqlite; + + await db.insert(usersTable).values({ name: 'John' }).run(); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .limit(sql.placeholder('limit')) + .prepare(); + + const result = await stmt.all({ id: 1, limit: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + expect(result).toHaveLength(1); + }); + + test('prepared statement with placeholder in .offset', async (ctx) => { + const { db } = ctx.sqlite; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]).run(); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .limit(sql.placeholder('limit')) + .offset(sql.placeholder('offset')) + .prepare(); + + const result = await stmt.all({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + }); + + test('prepared statement built using $dynamic', async (ctx) => { + const { db } = ctx.sqlite; + + function withLimitOffset(qb: any) { + return qb.limit(sql.placeholder('limit')).offset(sql.placeholder('offset')); + } + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]).run(); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .$dynamic(); + withLimitOffset(stmt).prepare('stmt_limit'); + + const result = await stmt.all({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + expect(result).toHaveLength(1); + }); + test('select with group by as field', async (ctx) => { const { db } = ctx.sqlite; From 181d1819cf7d498b83b1465244fdf43bda3b23e7 Mon Sep 17 00:00:00 2001 From: L-Mario564 Date: Mon, 4 Nov 2024 01:56:06 -0800 Subject: [PATCH 291/492] Update Github issue templates (#3157) * Update GH issue templates * Update issue templates --------- Co-authored-by: Andrii Sherman --- .github/ISSUE_TEMPLATE/bug-template.yaml | 44 +++++++++++++------- .github/ISSUE_TEMPLATE/docs-template.yaml | 18 ++++++++ .github/ISSUE_TEMPLATE/feature-template.yaml | 12 ++++-- 3 files changed, 57 insertions(+), 17 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/docs-template.yaml diff --git a/.github/ISSUE_TEMPLATE/bug-template.yaml b/.github/ISSUE_TEMPLATE/bug-template.yaml index 84072af6b..8a0431128 100644 --- a/.github/ISSUE_TEMPLATE/bug-template.yaml +++ b/.github/ISSUE_TEMPLATE/bug-template.yaml @@ -7,36 +7,52 @@ body: - type: markdown attributes: value: | - ## Quick Bug Form - Thank you for taking the time to file a bug report! Please fill out this form as completely as possible. + Thank you for taking the time to file a bug report! Please provide as much information as possible. + + - type: checkbox + attributes: + label: I have verified that the bug I'm about to report hasn't been filed before. + validations: + required: true - type: input attributes: label: What version of `drizzle-orm` are you using? + description: You can check the version by opening the `package.json` file in your project. placeholder: 0.0.0 validations: required: true + - type: input attributes: label: What version of `drizzle-kit` are you using? + description: You can check the version by opening the `package.json` file in your project. placeholder: 0.0.0 - validations: - required: false - - type: textarea - attributes: - label: Describe the Bug - description: Steps to reproduce validations: required: true - - type: textarea + + - type: input attributes: - label: Expected behavior - description: What you expect to happen + label: Other packages + description: If this bug is related to one of the other first-party packages we maintain, please list them here alongside their version. + placeholder: drizzle-zod@0.0.0, drizzle-valibot@0.0.0 validations: required: false + - type: textarea attributes: - label: Environment & setup - description: In which environment does the problem occur? + label: Describe the Bug + description: | + To fill this field, please answer the following: + - What is the undesired behavior? + - What are the steps to reproduce it? + - What is the desired result? + + If the issue is more specific, consider answering the following questions if you think they may be relevant: + - What database engine are you using? Are you using a specific cloud provider? Which one? + - Do you think this bug pertains to a specific database driver? Which one? + - Are you working in a monorepo? + - If this is a bug related to types: What Typescript version are you using? What's the content of your tsconfig.json file? + - If you're using a runtime that isn't Node.js: Which one? What version? Have you verified that this isn't an issue with the runtime itself? validations: - required: false + required: true diff --git a/.github/ISSUE_TEMPLATE/docs-template.yaml b/.github/ISSUE_TEMPLATE/docs-template.yaml new file mode 100644 index 000000000..6c2785a15 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/docs-template.yaml @@ -0,0 +1,18 @@ +name: "Documentation Enhancement" +description: Suggest documentation improvements +title: "[DOCS]:" +labels: ["docs"] + +body: + - type: checkbox + attributes: + label: I have verified this enhancement I'm about to request hasn't been suggested before. + validations: + required: true + + - type: textarea + attributes: + label: Describe the enhancement you want to request + description: What do you want to change or add to the documentation? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/feature-template.yaml b/.github/ISSUE_TEMPLATE/feature-template.yaml index 163b179a9..b2c13d671 100644 --- a/.github/ISSUE_TEMPLATE/feature-template.yaml +++ b/.github/ISSUE_TEMPLATE/feature-template.yaml @@ -1,12 +1,18 @@ name: "Feature Request" -description: Suggest new feature for Drizzle +description: Suggest new feature title: "[FEATURE]:" labels: ["enhancement"] body: + - type: checkbox + attributes: + label: I have verified this feature I'm about to request hasn't been suggested before. + validations: + required: true + - type: textarea attributes: - label: Describe what you want - description: What is the problem? What do you want to change or add? + label: Describe the enhancement you want to request + description: What do you want to change or add? What are the benefits of implementing this? validations: required: true From b762f63843848a82fae97688db01033e092c98d1 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 4 Nov 2024 12:02:11 +0200 Subject: [PATCH 292/492] Fix checkboxes --- .github/ISSUE_TEMPLATE/bug-template.yaml | 13 ++++++++----- .github/ISSUE_TEMPLATE/docs-template.yaml | 10 ++++++---- .github/ISSUE_TEMPLATE/feature-template.yaml | 10 ++++++---- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-template.yaml b/.github/ISSUE_TEMPLATE/bug-template.yaml index 8a0431128..70c7a6807 100644 --- a/.github/ISSUE_TEMPLATE/bug-template.yaml +++ b/.github/ISSUE_TEMPLATE/bug-template.yaml @@ -8,12 +8,14 @@ body: attributes: value: | Thank you for taking the time to file a bug report! Please provide as much information as possible. - - - type: checkbox + + - type: checkboxes + id: verified attributes: - label: I have verified that the bug I'm about to report hasn't been filed before. - validations: - required: true + label: Report hasn't been filed before. + options: + - label: I have verified that the bug I'm about to report hasn't been filed before. + required: true - type: input attributes: @@ -56,3 +58,4 @@ body: - If you're using a runtime that isn't Node.js: Which one? What version? Have you verified that this isn't an issue with the runtime itself? validations: required: true + diff --git a/.github/ISSUE_TEMPLATE/docs-template.yaml b/.github/ISSUE_TEMPLATE/docs-template.yaml index 6c2785a15..26abc9257 100644 --- a/.github/ISSUE_TEMPLATE/docs-template.yaml +++ b/.github/ISSUE_TEMPLATE/docs-template.yaml @@ -4,11 +4,13 @@ title: "[DOCS]:" labels: ["docs"] body: - - type: checkbox + - type: checkboxes + id: verified attributes: - label: I have verified this enhancement I'm about to request hasn't been suggested before. - validations: - required: true + label: Enhancement hasn't been filed before. + options: + - label: I have verified this enhancement I'm about to request hasn't been suggested before. + required: true - type: textarea attributes: diff --git a/.github/ISSUE_TEMPLATE/feature-template.yaml b/.github/ISSUE_TEMPLATE/feature-template.yaml index b2c13d671..dcb10969f 100644 --- a/.github/ISSUE_TEMPLATE/feature-template.yaml +++ b/.github/ISSUE_TEMPLATE/feature-template.yaml @@ -4,11 +4,13 @@ title: "[FEATURE]:" labels: ["enhancement"] body: - - type: checkbox + - type: checkboxes + id: verified attributes: - label: I have verified this feature I'm about to request hasn't been suggested before. - validations: - required: true + label: Feature hasn't been suggested before. + options: + - label: I have verified this feature I'm about to request hasn't been suggested before. + required: true - type: textarea attributes: From 462954fe8e9d83f4c713d0e349ad97f893521c94 Mon Sep 17 00:00:00 2001 From: Andrii Sherman Date: Mon, 4 Nov 2024 12:03:38 +0200 Subject: [PATCH 293/492] main to beta (#3404) * Update Github issue templates (#3157) * Update GH issue templates * Update issue templates --------- Co-authored-by: Andrii Sherman * Fix checkboxes --------- Co-authored-by: L-Mario564 --- .github/ISSUE_TEMPLATE/bug-template.yaml | 47 ++++++++++++++------ .github/ISSUE_TEMPLATE/docs-template.yaml | 20 +++++++++ .github/ISSUE_TEMPLATE/feature-template.yaml | 14 ++++-- 3 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/docs-template.yaml diff --git a/.github/ISSUE_TEMPLATE/bug-template.yaml b/.github/ISSUE_TEMPLATE/bug-template.yaml index 84072af6b..70c7a6807 100644 --- a/.github/ISSUE_TEMPLATE/bug-template.yaml +++ b/.github/ISSUE_TEMPLATE/bug-template.yaml @@ -7,36 +7,55 @@ body: - type: markdown attributes: value: | - ## Quick Bug Form - Thank you for taking the time to file a bug report! Please fill out this form as completely as possible. + Thank you for taking the time to file a bug report! Please provide as much information as possible. + + - type: checkboxes + id: verified + attributes: + label: Report hasn't been filed before. + options: + - label: I have verified that the bug I'm about to report hasn't been filed before. + required: true - type: input attributes: label: What version of `drizzle-orm` are you using? + description: You can check the version by opening the `package.json` file in your project. placeholder: 0.0.0 validations: required: true + - type: input attributes: label: What version of `drizzle-kit` are you using? + description: You can check the version by opening the `package.json` file in your project. placeholder: 0.0.0 - validations: - required: false - - type: textarea - attributes: - label: Describe the Bug - description: Steps to reproduce validations: required: true - - type: textarea + + - type: input attributes: - label: Expected behavior - description: What you expect to happen + label: Other packages + description: If this bug is related to one of the other first-party packages we maintain, please list them here alongside their version. + placeholder: drizzle-zod@0.0.0, drizzle-valibot@0.0.0 validations: required: false + - type: textarea attributes: - label: Environment & setup - description: In which environment does the problem occur? + label: Describe the Bug + description: | + To fill this field, please answer the following: + - What is the undesired behavior? + - What are the steps to reproduce it? + - What is the desired result? + + If the issue is more specific, consider answering the following questions if you think they may be relevant: + - What database engine are you using? Are you using a specific cloud provider? Which one? + - Do you think this bug pertains to a specific database driver? Which one? + - Are you working in a monorepo? + - If this is a bug related to types: What Typescript version are you using? What's the content of your tsconfig.json file? + - If you're using a runtime that isn't Node.js: Which one? What version? Have you verified that this isn't an issue with the runtime itself? validations: - required: false + required: true + diff --git a/.github/ISSUE_TEMPLATE/docs-template.yaml b/.github/ISSUE_TEMPLATE/docs-template.yaml new file mode 100644 index 000000000..26abc9257 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/docs-template.yaml @@ -0,0 +1,20 @@ +name: "Documentation Enhancement" +description: Suggest documentation improvements +title: "[DOCS]:" +labels: ["docs"] + +body: + - type: checkboxes + id: verified + attributes: + label: Enhancement hasn't been filed before. + options: + - label: I have verified this enhancement I'm about to request hasn't been suggested before. + required: true + + - type: textarea + attributes: + label: Describe the enhancement you want to request + description: What do you want to change or add to the documentation? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/feature-template.yaml b/.github/ISSUE_TEMPLATE/feature-template.yaml index 163b179a9..dcb10969f 100644 --- a/.github/ISSUE_TEMPLATE/feature-template.yaml +++ b/.github/ISSUE_TEMPLATE/feature-template.yaml @@ -1,12 +1,20 @@ name: "Feature Request" -description: Suggest new feature for Drizzle +description: Suggest new feature title: "[FEATURE]:" labels: ["enhancement"] body: + - type: checkboxes + id: verified + attributes: + label: Feature hasn't been suggested before. + options: + - label: I have verified this feature I'm about to request hasn't been suggested before. + required: true + - type: textarea attributes: - label: Describe what you want - description: What is the problem? What do you want to change or add? + label: Describe the enhancement you want to request + description: What do you want to change or add? What are the benefits of implementing this? validations: required: true From 4d56096ca66031007b10310d9f4241ea8c440197 Mon Sep 17 00:00:00 2001 From: Dan Ribbens Date: Mon, 4 Nov 2024 07:59:23 -0500 Subject: [PATCH 294/492] feat: add tablesFilter to pushSchema api (#3141) * feat: add tablesFilter to pushSchema api * Format with dprint --------- Co-authored-by: Andrii Sherman --- drizzle-kit/src/api.ts | 9 ++++++++- drizzle-kit/src/cli/commands/utils.ts | 12 ++---------- .../extensions/getTablesFilterByExtensions.ts | 16 ++++++++++++++++ 3 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 drizzle-kit/src/extensions/getTablesFilterByExtensions.ts diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 83b7139ad..b18ed95f4 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -21,7 +21,9 @@ import { updateUpToV6 as upPgV6, updateUpToV7 as upPgV7 } from './cli/commands/p import { sqlitePushIntrospect } from './cli/commands/sqliteIntrospect'; import { logSuggestionsAndReturn } from './cli/commands/sqlitePushUtils'; import type { CasingType } from './cli/validations/common'; +import { getTablesFilterByExtensions } from './extensions/getTablesFilterByExtensions'; import { originUUID } from './global'; +import type { Config } from './index'; import { fillPgSnapshot } from './migrationPreparator'; import { MySqlSchema as MySQLSchemaKit, mysqlSchema, squashMysqlScheme } from './serializer/mysqlSchema'; import { generateMySqlSnapshot } from './serializer/mysqlSerializer'; @@ -100,9 +102,14 @@ export const pushSchema = async ( imports: Record, drizzleInstance: PgDatabase, schemaFilters?: string[], + tablesFilter?: string[], + extensionsFilters?: Config['extensionsFilters'], ) => { const { applyPgSnapshotsDiff } = await import('./snapshotsDiffer'); const { sql } = await import('drizzle-orm'); + const filters = (tablesFilter ?? []).concat( + getTablesFilterByExtensions({ extensionsFilters, dialect: 'postgresql' }), + ); const db: DB = { query: async (query: string, params?: any[]) => { @@ -114,7 +121,7 @@ export const pushSchema = async ( const cur = generateDrizzleJson(imports); const { schema: prev } = await pgPushIntrospect( db, - [], + filters, schemaFilters ?? ['public'], undefined, ); diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 1b22fc545..7386b74d5 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -3,6 +3,7 @@ import { existsSync } from 'fs'; import { render } from 'hanji'; import { join, resolve } from 'path'; import { object, string } from 'zod'; +import { getTablesFilterByExtensions } from '../../extensions/getTablesFilterByExtensions'; import { assertUnreachable } from '../../global'; import { type Dialect, dialect } from '../../schemaValidator'; import { prepareFilenames } from '../../serializer'; @@ -273,16 +274,7 @@ export const preparePushConfig = async ( : schemasFilterConfig : []; - if (config.extensionsFilters) { - if ( - config.extensionsFilters.includes('postgis') - && config.dialect === 'postgresql' - ) { - tablesFilter.push( - ...['!geography_columns', '!geometry_columns', '!spatial_ref_sys'], - ); - } - } + tablesFilter.push(...getTablesFilterByExtensions(config)); if (config.dialect === 'postgresql') { const parsed = postgresCredentials.safeParse(config); diff --git a/drizzle-kit/src/extensions/getTablesFilterByExtensions.ts b/drizzle-kit/src/extensions/getTablesFilterByExtensions.ts new file mode 100644 index 000000000..80321fc6a --- /dev/null +++ b/drizzle-kit/src/extensions/getTablesFilterByExtensions.ts @@ -0,0 +1,16 @@ +import type { Config } from '../index'; + +export const getTablesFilterByExtensions = ({ + extensionsFilters, + dialect, +}: Pick): string[] => { + if (extensionsFilters) { + if ( + extensionsFilters.includes('postgis') + && dialect === 'postgresql' + ) { + return ['!geography_columns', '!geometry_columns', '!spatial_ref_sys']; + } + } + return []; +}; From 456758bfe78fcc2761bb8c115d428ccbc0ccc78d Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 4 Nov 2024 15:39:44 +0200 Subject: [PATCH 295/492] Fix conflicts --- .../src/serializer/singlestoreSerializer.ts | 14 ++++++++++---- drizzle-kit/src/snapshotsDiffer.ts | 4 ++-- drizzle-kit/src/sqlgenerator.ts | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index 922296540..3224306dd 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -16,7 +16,6 @@ import { IntrospectStage, IntrospectStatus } from '../cli/views'; import { SingleStoreColumn } from 'drizzle-orm/singlestore-core/columns'; import { CasingType } from 'src/cli/validations/common'; import type { DB } from '../utils'; -import { sqlToStr } from '.'; import { Column, Index, @@ -27,6 +26,7 @@ import { UniqueConstraint, View, } from './singlestoreSchema'; +import { sqlToStr } from './utils'; const dialect = new SingleStoreDialect(); @@ -716,12 +716,18 @@ export const fromDatabase = async ( const viewName = view['TABLE_NAME']; const definition = view['VIEW_DEFINITION']; - const withCheckOption = view['CHECK_OPTION'] === 'NONE' ? undefined : view['CHECK_OPTION'].toLowerCase(); + const withCheckOption = view['CHECK_OPTION'] === 'NONE' + ? undefined + : view['CHECK_OPTION'].toLowerCase(); const sqlSecurity = view['SECURITY_TYPE'].toLowerCase(); - const [createSqlStatement] = await db.query(`SHOW CREATE VIEW \`${viewName}\`;`); + const [createSqlStatement] = await db.query( + `SHOW CREATE VIEW \`${viewName}\`;`, + ); const algorithmMatch = createSqlStatement['Create View'].match(/ALGORITHM=([^ ]+)/); - const algorithm = algorithmMatch ? algorithmMatch[1].toLowerCase() : undefined; + const algorithm = algorithmMatch + ? algorithmMatch[1].toLowerCase() + : undefined; const columns = result[viewName].columns; delete result[viewName]; diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 71547c6c1..444655909 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -23,8 +23,8 @@ import { JsonAlterCompositePK, JsonAlterIndPolicyStatement, JsonAlterMySqlViewStatement, - JsonAlterSingleStoreViewStatement, JsonAlterPolicyStatement, + JsonAlterSingleStoreViewStatement, JsonAlterTableSetSchema, JsonAlterUniqueConstraint, JsonAlterViewStatement, @@ -133,7 +133,6 @@ import { import { Named, NamedWithSchema } from './cli/commands/migrate'; import { mapEntries, mapKeys, mapValues } from './global'; import { MySqlSchema, MySqlSchemaSquashed, MySqlSquasher, ViewSquashed } from './serializer/mysqlSchema'; -import { SingleStoreSchema, SingleStoreSchemaSquashed, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { mergedViewWithOption, PgSchema, @@ -147,6 +146,7 @@ import { sequenceSquashed, View, } from './serializer/pgSchema'; +import { SingleStoreSchema, SingleStoreSchemaSquashed, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher, View as SqliteView } from './serializer/sqliteSchema'; import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; import { copy, prepareMigrationMeta } from './utils'; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 98de3f405..9d1479653 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -84,8 +84,8 @@ import { } from './jsonStatements'; import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; -import { SingleStoreSquasher } from './serializer/singlestoreSchema'; import { PgSquasher, policy } from './serializer/pgSchema'; +import { SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; export const pgNativeTypes = new Set([ From dab40c877be62715b1411126858991effc377e25 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 4 Nov 2024 17:00:51 +0200 Subject: [PATCH 296/492] No fks? --- drizzle-kit/src/cli/views.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drizzle-kit/src/cli/views.ts b/drizzle-kit/src/cli/views.ts index 3ec04a588..e79d585ee 100644 --- a/drizzle-kit/src/cli/views.ts +++ b/drizzle-kit/src/cli/views.ts @@ -32,10 +32,11 @@ export const schema = (schema: CommonSchema): string => { .map((t) => { const columnsCount = Object.values(t.columns).length; const indexesCount = Object.values(t.indexes).length; - const foreignKeys = Object.values(t.foreignKeys).length; + // should we have fks? + // const foreignKeys = Object.values(t.foreignKeys).length; return `${chalk.bold.blue(t.name)} ${ chalk.gray( - `${columnsCount} columns ${indexesCount} indexes ${foreignKeys} fks`, + `${columnsCount} columns ${indexesCount} indexes`, ) }`; }) From 465a8a27413ff5fbde94ee821e5e6c7892eb6bfb Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 4 Nov 2024 17:39:47 +0200 Subject: [PATCH 297/492] Fix after failed tests --- drizzle-kit/src/cli/commands/introspect.ts | 1 + drizzle-kit/src/cli/commands/push.ts | 27 ++++++++++++++++++---- drizzle-kit/src/cli/commands/utils.ts | 9 ++++++-- drizzle-kit/src/cli/schema.ts | 18 +++++++++++---- drizzle-kit/tests/singlestore.test.ts | 2 ++ 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index d24b71872..149d2048b 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -346,6 +346,7 @@ export const introspectSingleStore = async ( squashSingleStoreScheme(schema), tablesResolver, columnsResolver, + mySqlViewsResolver, drySingleStore, schema, ); diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 2e81a4fd8..b147c2854 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -168,16 +168,21 @@ export const singlestorePush = async ( strict: boolean, verbose: boolean, force: boolean, + casing: CasingType | undefined, ) => { const { connectToSingleStore } = await import('../connections'); const { singlestorePushIntrospect } = await import('./singlestoreIntrospect'); const { db, database } = await connectToSingleStore(credentials); - const { schema } = await singlestorePushIntrospect(db, database, tablesFilter); + const { schema } = await singlestorePushIntrospect( + db, + database, + tablesFilter, + ); const { prepareSingleStorePush } = await import('./migrate'); - const statements = await prepareSingleStorePush(schemaPath, schema); + const statements = await prepareSingleStorePush(schemaPath, schema, casing); const filteredStatements = singleStoreFilterStatements( statements.statements ?? [], @@ -315,11 +320,21 @@ export const pgPush = async ( const { pgPushIntrospect } = await import('./pgIntrospect'); const db = await preparePostgresDB(credentials); - const { schema } = await pgPushIntrospect(db, tablesFilter, schemasFilter, entities); + const { schema } = await pgPushIntrospect( + db, + tablesFilter, + schemasFilter, + entities, + ); const { preparePgPush } = await import('./migrate'); - const statements = await preparePgPush(schemaPath, schema, schemasFilter, casing); + const statements = await preparePgPush( + schemaPath, + schema, + schemasFilter, + casing, + ); try { if (statements.sqlStatements.length === 0) { @@ -390,7 +405,9 @@ export const pgPush = async ( }${ matViewsToRemove.length > 0 ? ` remove ${matViewsToRemove.length} ${ - matViewsToRemove.length > 1 ? 'materialized views' : 'materialize view' + matViewsToRemove.length > 1 + ? 'materialized views' + : 'materialize view' },` : ' ' }` diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index a993c3a80..35a7b5a77 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -516,6 +516,7 @@ export const preparePullConfig = async ( tablesFilter, schemasFilter, prefix: config.migrations?.prefix || 'index', + entities: config.entities, }; } @@ -768,8 +769,12 @@ export const drizzleConfigFromFile = async ( ): Promise => { const prefix = process.env.TEST_CONFIG_PATH_PREFIX || ''; - const defaultTsConfigExists = existsSync(resolve(join(prefix, 'drizzle.config.ts'))); - const defaultJsConfigExists = existsSync(resolve(join(prefix, 'drizzle.config.js'))); + const defaultTsConfigExists = existsSync( + resolve(join(prefix, 'drizzle.config.ts')), + ); + const defaultJsConfigExists = existsSync( + resolve(join(prefix, 'drizzle.config.js')), + ); const defaultJsonConfigExists = existsSync( join(resolve('drizzle.config.json')), ); diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index d61f457e9..e952a8627 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -6,7 +6,7 @@ import { renderWithTask } from 'hanji'; import { dialects } from 'src/schemaValidator'; import '../@types/utils'; import { assertUnreachable } from '../global'; -import { drizzleForLibSQL, type Setup } from '../serializer/studio'; +import { type Setup } from '../serializer/studio'; import { assertV1OutFolder } from '../utils'; import { certs } from '../utils/certs'; import { checkHandler } from './commands/check'; @@ -31,7 +31,9 @@ import { grey, MigrateProgress } from './views'; const optionDialect = string('dialect') .enum(...dialects) - .desc(`Database dialect: 'postgresql', 'mysql', 'sqlite', 'turso' or 'singlestore'`); + .desc( + `Database dialect: 'postgresql', 'mysql', 'sqlite', 'turso' or 'singlestore'`, + ); const optionOut = string().desc("Output folder, 'drizzle' by default"); const optionConfig = string().desc('Path to drizzle config file'); const optionBreakpoints = boolean().desc( @@ -42,7 +44,9 @@ const optionDriver = string() .enum(...drivers) .desc('Database driver'); -const optionCasing = string().enum('camelCase', 'snake_case').desc('Casing for serialization'); +const optionCasing = string() + .enum('camelCase', 'snake_case') + .desc('Casing for serialization'); export const generate = command({ name: 'generate', @@ -364,6 +368,7 @@ export const push = command({ strict, verbose, force, + casing, ); } else { assertUnreachable(dialect); @@ -682,7 +687,12 @@ export const studio = command({ const { schema, relations, files } = schemaPath ? await prepareSingleStoreSchema(schemaPath) : { schema: {}, relations: {}, files: [] }; - setup = await drizzleForSingleStore(credentials, schema, relations, files); + setup = await drizzleForSingleStore( + credentials, + schema, + relations, + files, + ); } else { assertUnreachable(dialect); } diff --git a/drizzle-kit/tests/singlestore.test.ts b/drizzle-kit/tests/singlestore.test.ts index 63abf1755..71b95a8f5 100644 --- a/drizzle-kit/tests/singlestore.test.ts +++ b/drizzle-kit/tests/singlestore.test.ts @@ -191,6 +191,7 @@ test('add table #6', async () => { compositePkName: '', }); expect(statements[1]).toStrictEqual({ + policies: [], type: 'drop_table', tableName: 'users1', schema: undefined, @@ -283,6 +284,7 @@ test('change table schema #1', async () => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ + policies: [], type: 'drop_table', tableName: 'users', schema: undefined, From 68edb2b6cf94775c721af8d594d97ae8dc13a23e Mon Sep 17 00:00:00 2001 From: Andrii Sherman Date: Wed, 6 Nov 2024 15:23:11 +0200 Subject: [PATCH 298/492] Rls fix (#3500) * Fix previous state for RLS * Add unsquash policy push * Make policy unsquash work for push * Fix linked policies that are not in the table for push * Add release notes --- changelogs/drizzle-kit/0.27.2.md | 3 + drizzle-kit/package.json | 4 +- drizzle-kit/src/cli/commands/migrate.ts | 13 +- drizzle-kit/src/cli/commands/pgIntrospect.ts | 5 +- drizzle-kit/src/cli/commands/pgPushUtils.ts | 2 +- drizzle-kit/src/cli/commands/push.ts | 12 +- drizzle-kit/src/serializer/pgSchema.ts | 11 + drizzle-kit/src/serializer/pgSerializer.ts | 19 +- drizzle-kit/src/snapshotsDiffer.ts | 47 +++- drizzle-kit/src/sqlgenerator.ts | 27 +- drizzle-kit/tests/push/pg.test.ts | 245 ++++++++++++++++--- drizzle-kit/tests/schemaDiffer.ts | 28 ++- 12 files changed, 326 insertions(+), 90 deletions(-) create mode 100644 changelogs/drizzle-kit/0.27.2.md diff --git a/changelogs/drizzle-kit/0.27.2.md b/changelogs/drizzle-kit/0.27.2.md new file mode 100644 index 000000000..bafd17222 --- /dev/null +++ b/changelogs/drizzle-kit/0.27.2.md @@ -0,0 +1,3 @@ +- Fix [[BUG]: Undefined properties when using drizzle-kit push](https://github.com/drizzle-team/drizzle-orm/issues/3391) +- Fix TypeError: Cannot read properties of undefined (reading 'isRLSEnabled') +- Fix push bugs, when pushing a schema with linked policy to a table from `drizzle-orm/supabase` diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index bb20a6324..57996969b 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.27.1", + "version": "0.27.2", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", @@ -138,4 +138,4 @@ "default": "./api.mjs" } } -} +} \ No newline at end of file diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 8d1e6205f..0933af194 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -343,18 +343,9 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => { }; export const preparePgPush = async ( - schemaPath: string | string[], - snapshot: PgSchema, - schemaFilter: string[], - casing: CasingType | undefined, + cur: PgSchema, + prev: PgSchema, ) => { - const { prev, cur } = await preparePgDbPushSnapshot( - snapshot, - schemaPath, - casing, - schemaFilter, - ); - const validatedPrev = pgSchema.parse(prev); const validatedCur = pgSchema.parse(cur); diff --git a/drizzle-kit/src/cli/commands/pgIntrospect.ts b/drizzle-kit/src/cli/commands/pgIntrospect.ts index 2d3fd75ce..02867fae9 100644 --- a/drizzle-kit/src/cli/commands/pgIntrospect.ts +++ b/drizzle-kit/src/cli/commands/pgIntrospect.ts @@ -1,7 +1,7 @@ import { renderWithTask } from 'hanji'; import { Minimatch } from 'minimatch'; import { originUUID } from '../../global'; -import type { PgSchema } from '../../serializer/pgSchema'; +import type { PgSchema, PgSchemaInternal } from '../../serializer/pgSchema'; import { fromDatabase } from '../../serializer/pgSerializer'; import type { DB } from '../../utils'; import { Entities } from '../validations/cli'; @@ -12,6 +12,7 @@ export const pgPushIntrospect = async ( filters: string[], schemaFilters: string[], entities: Entities, + tsSchema?: PgSchemaInternal, ) => { const matchers = filters.map((it) => { return new Minimatch(it); @@ -45,7 +46,7 @@ export const pgPushIntrospect = async ( ); const res = await renderWithTask( progress, - fromDatabase(db, filter, schemaFilters, entities), + fromDatabase(db, filter, schemaFilters, entities, undefined, tsSchema), ); const schema = { id: originUUID, prevId: '', ...res } as PgSchema; diff --git a/drizzle-kit/src/cli/commands/pgPushUtils.ts b/drizzle-kit/src/cli/commands/pgPushUtils.ts index b53fec3e7..05322f738 100644 --- a/drizzle-kit/src/cli/commands/pgPushUtils.ts +++ b/drizzle-kit/src/cli/commands/pgPushUtils.ts @@ -250,7 +250,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { } } } - const stmnt = fromJson([statement], 'postgresql'); + const stmnt = fromJson([statement], 'postgresql', 'push'); if (typeof stmnt !== 'undefined') { statementsToExecute.push(...stmnt); } diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 7ef690d81..54dbb4ba0 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -1,5 +1,7 @@ import chalk from 'chalk'; +import { randomUUID } from 'crypto'; import { render } from 'hanji'; +import { serializePg } from 'src/serializer'; import { fromJson } from '../../sqlgenerator'; import { Select } from '../selector-ui'; import { Entities } from '../validations/cli'; @@ -169,11 +171,17 @@ export const pgPush = async ( const { pgPushIntrospect } = await import('./pgIntrospect'); const db = await preparePostgresDB(credentials); - const { schema } = await pgPushIntrospect(db, tablesFilter, schemasFilter, entities); + + const serialized = await serializePg(schemaPath, casing, schemasFilter); + + const { schema } = await pgPushIntrospect(db, tablesFilter, schemasFilter, entities, serialized); const { preparePgPush } = await import('./migrate'); - const statements = await preparePgPush(schemaPath, schema, schemasFilter, casing); + const statements = await preparePgPush( + { id: randomUUID(), prevId: schema.id, ...serialized }, + schema, + ); try { if (statements.sqlStatements.length === 0) { diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index 50d712dc4..f5810bbc8 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -240,6 +240,7 @@ export const policy = object({ using: string().optional(), withCheck: string().optional(), on: string().optional(), + schema: string().optional(), }).strict(); export const policySquashed = object({ @@ -657,6 +658,16 @@ export const PgSquasher = { squashPolicyPush: (policy: Policy) => { return `${policy.name}--${policy.as}--${policy.for}--${policy.to?.join(',')}--${policy.on}`; }, + unsquashPolicyPush: (policy: string): Policy => { + const splitted = policy.split('--'); + return { + name: splitted[0], + as: splitted[1] as Policy['as'], + for: splitted[2] as Policy['for'], + to: splitted[3].split(','), + on: splitted[4] !== 'undefined' ? splitted[4] : undefined, + }; + }, squashPK: (pk: PrimaryKey) => { return `${pk.columns.join(',')};${pk.name}`; }, diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index c6f6c0391..66b8db85f 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -652,6 +652,7 @@ export const generatePgSnapshot = ( } else { policiesToReturn[policy.name] = { ...mappedPolicy, + schema: tableConfig.schema ?? 'public', on: `"${tableConfig.schema ?? 'public'}"."${tableConfig.name}"`, }; } @@ -972,9 +973,11 @@ export const fromDatabase = async ( count: number, status: IntrospectStatus, ) => void, + tsSchema?: PgSchemaInternal, ): Promise => { const result: Record = {}; const views: Record = {}; + const policies: Record = {}; const internals: PgKitInternals = { tables: {} }; const where = schemaFilters.map((t) => `n.nspname = '${t}'`).join(' or '); @@ -1134,7 +1137,9 @@ WHERE } } - const wherePolicies = schemaFilters + const schemasForLinkedPoliciesInSchema = Object.values(tsSchema?.policies ?? {}).map((it) => it.schema!); + + const wherePolicies = [...schemaFilters, ...schemasForLinkedPoliciesInSchema] .map((t) => `schemaname = '${t}'`) .join(' or '); @@ -1171,6 +1176,16 @@ WHERE [dbPolicy.name]: { ...rest, to: parsedTo, withCheck: parsedWithCheck, using: parsedUsing } as Policy, }; } + + if (tsSchema?.policies[dbPolicy.name]) { + policies[dbPolicy.name] = { + ...rest, + to: parsedTo, + withCheck: parsedWithCheck, + using: parsedUsing, + on: tsSchema?.policies[dbPolicy.name].on, + } as Policy; + } } if (progressCallback) { @@ -1907,7 +1922,7 @@ WHERE schemas: schemasObject, sequences: sequencesToReturn, roles: rolesToReturn, - policies: {}, + policies, views: views, _meta: { schemas: {}, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 57d8e701d..dda13b967 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -988,8 +988,10 @@ export const applyPgSnapshotsDiff = async ( const { renamed, created, deleted } = await policyResolver({ tableName: entry.name, schema: entry.schema, - deleted: entry.policies.deleted.map(PgSquasher.unsquashPolicy), - created: entry.policies.added.map(PgSquasher.unsquashPolicy), + deleted: entry.policies.deleted.map( + action === 'push' ? PgSquasher.unsquashPolicyPush : PgSquasher.unsquashPolicy, + ), + created: entry.policies.added.map(action === 'push' ? PgSquasher.unsquashPolicyPush : PgSquasher.unsquashPolicy), }); if (created.length > 0) { @@ -1043,7 +1045,9 @@ export const applyPgSnapshotsDiff = async ( ] || []; const newName = columnChangeFor(policyKey, rens); - const unsquashedPolicy = PgSquasher.unsquashPolicy(policy); + const unsquashedPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(policy) + : PgSquasher.unsquashPolicy(policy); unsquashedPolicy.name = newName; policy = PgSquasher.squashPolicy(unsquashedPolicy); return newName; @@ -1068,8 +1072,12 @@ export const applyPgSnapshotsDiff = async ( }[]; const { renamed: indPolicyRenames, created, deleted } = await indPolicyResolver({ - deleted: indPolicyRes.deleted.map((t) => PgSquasher.unsquashPolicy(t.values)), - created: indPolicyRes.added.map((t) => PgSquasher.unsquashPolicy(t.values)), + deleted: indPolicyRes.deleted.map((t) => + action === 'push' ? PgSquasher.unsquashPolicyPush(t.values) : PgSquasher.unsquashPolicy(t.values) + ), + created: indPolicyRes.added.map((t) => + action === 'push' ? PgSquasher.unsquashPolicyPush(t.values) : PgSquasher.unsquashPolicy(t.values) + ), }); if (created.length > 0) { @@ -1421,10 +1429,14 @@ export const applyPgSnapshotsDiff = async ( typedResult.alteredPolicies.forEach(({ values }) => { // return prepareAlterIndPolicyJson(json1.policies[it.name], json2.policies[it.name]); - const policy = PgSquasher.unsquashPolicy(values); + const policy = action === 'push' ? PgSquasher.unsquashPolicyPush(values) : PgSquasher.unsquashPolicy(values); - const newPolicy = PgSquasher.unsquashPolicy(json2.policies[policy.name].values); - const oldPolicy = PgSquasher.unsquashPolicy(json1.policies[policy.name].values); + const newPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(json2.policies[policy.name].values) + : PgSquasher.unsquashPolicy(json2.policies[policy.name].values); + const oldPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(json2.policies[policy.name].values) + : PgSquasher.unsquashPolicy(json1.policies[policy.name].values); if (newPolicy.as !== oldPolicy.as) { jsonDropIndPoliciesStatements.push( @@ -1494,8 +1506,12 @@ export const applyPgSnapshotsDiff = async ( alteredTables.forEach((it) => { // handle policies Object.keys(it.alteredPolicies).forEach((policyName: string) => { - const newPolicy = PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__new); - const oldPolicy = PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__old); + const newPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(it.alteredPolicies[policyName].__new) + : PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__new); + const oldPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(it.alteredPolicies[policyName].__old) + : PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__old); if (newPolicy.as !== oldPolicy.as) { jsonDropPoliciesStatements.push( @@ -1569,7 +1585,8 @@ export const applyPgSnapshotsDiff = async ( } // handle table.isRLSEnabled - if (table.isRLSEnabled !== tableInPreviousState.isRLSEnabled) { + const wasRlsEnabled = tableInPreviousState ? tableInPreviousState.isRLSEnabled : false; + if (table.isRLSEnabled !== wasRlsEnabled) { if (table.isRLSEnabled) { // was force enabled jsonEnableRLSStatements.push({ type: 'enable_rls', tableName: table.name, schema: table.schema }); @@ -1762,7 +1779,11 @@ export const applyPgSnapshotsDiff = async ( jsonCreatePoliciesStatements.push(...([] as JsonCreatePolicyStatement[]).concat( ...(createdTables.map((it) => - prepareCreatePolicyJsons(it.name, it.schema, Object.values(it.policies).map(PgSquasher.unsquashPolicy)) + prepareCreatePolicyJsons( + it.name, + it.schema, + Object.values(it.policies).map(action === 'push' ? PgSquasher.unsquashPolicyPush : PgSquasher.unsquashPolicy), + ) )), )); const createViews: JsonCreatePgViewStatement[] = []; @@ -2037,7 +2058,7 @@ export const applyPgSnapshotsDiff = async ( return true; }); - const sqlStatements = fromJson(filteredEnumsJsonStatements, 'postgresql'); + const sqlStatements = fromJson(filteredEnumsJsonStatements, 'postgresql', action); const uniqueSqlStatements: string[] = []; sqlStatements.forEach((ss) => { diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index da4dcdf56..bb3335941 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -270,9 +270,13 @@ class PgAlterPolicyConvertor extends Convertor { override can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'alter_policy' && dialect === 'postgresql'; } - override convert(statement: JsonAlterPolicyStatement): string | string[] { - const newPolicy = PgSquasher.unsquashPolicy(statement.newData); - const oldPolicy = PgSquasher.unsquashPolicy(statement.oldData); + override convert(statement: JsonAlterPolicyStatement, _dialect: any, action?: string): string | string[] { + const newPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(statement.newData) + : PgSquasher.unsquashPolicy(statement.newData); + const oldPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(statement.oldData) + : PgSquasher.unsquashPolicy(statement.oldData); const tableNameWithSchema = statement.schema ? `"${statement.schema}"."${statement.tableName}"` @@ -1408,7 +1412,7 @@ class PgDropTableConvertor extends Convertor { return statement.type === 'drop_table' && dialect === 'postgresql'; } - convert(statement: JsonDropTableStatement) { + convert(statement: JsonDropTableStatement, _d: any, action?: string) { const { tableName, schema, policies } = statement; const tableNameWithSchema = schema @@ -1420,7 +1424,9 @@ class PgDropTableConvertor extends Convertor { return dropPolicyConvertor.convert({ type: 'drop_policy', tableName, - data: PgSquasher.unsquashPolicy(p), + data: action === 'push' + ? PgSquasher.unsquashPolicyPush(p) + : PgSquasher.unsquashPolicy(p), schema, }) as string; }) ?? []; @@ -3334,17 +3340,6 @@ convertors.push(new MySqlAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new MySqlAlterTableAddPk()); convertors.push(new MySqlAlterTableAlterCompositePrimaryKeyConvertor()); -export function fromJson( - statements: JsonStatement[], - dialect: Exclude, -): string[]; -export function fromJson( - statements: JsonStatement[], - dialect: 'sqlite' | 'turso', - action?: 'push', - json2?: SQLiteSchemaSquashed, -): string[]; - export function fromJson( statements: JsonStatement[], dialect: Dialect, diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 67743d2ef..51e6fe73a 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -2755,9 +2755,7 @@ test('add policy', async () => { as: 'PERMISSIVE', for: 'ALL', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', }, @@ -2814,8 +2812,6 @@ test('drop policy', async () => { for: 'ALL', to: ['public'], on: undefined, - using: undefined, - withCheck: undefined, }, schema: '', }, @@ -2868,9 +2864,7 @@ test('add policy without enable rls', async () => { as: 'PERMISSIVE', for: 'ALL', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', }, @@ -2922,9 +2916,7 @@ test('drop policy without disable rls', async () => { as: 'PERMISSIVE', for: 'ALL', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', }, @@ -3098,8 +3090,6 @@ test('alter policy with recreation: changing as', async (t) => { name: 'test', to: ['public'], on: undefined, - using: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3112,8 +3102,6 @@ test('alter policy with recreation: changing as', async (t) => { name: 'test', to: ['public'], on: undefined, - using: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3166,8 +3154,6 @@ test('alter policy with recreation: changing for', async (t) => { name: 'test', to: ['public'], on: undefined, - using: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3179,9 +3165,7 @@ test('alter policy with recreation: changing for', async (t) => { for: 'DELETE', name: 'test', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3233,9 +3217,7 @@ test('alter policy with recreation: changing both "as" and "for"', async (t) => for: 'ALL', name: 'test', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3247,9 +3229,7 @@ test('alter policy with recreation: changing both "as" and "for"', async (t) => for: 'INSERT', name: 'test', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3301,9 +3281,7 @@ test('alter policy with recreation: changing all fields', async (t) => { for: 'SELECT', name: 'test', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3316,8 +3294,6 @@ test('alter policy with recreation: changing all fields', async (t) => { name: 'test', to: ['current_role'], on: undefined, - using: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3490,9 +3466,7 @@ test('create table with a policy', async (t) => { to: [ 'public', ], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', tableName: 'users2', @@ -3595,8 +3569,6 @@ test('add policy with multiple "to" roles', async (t) => { name: 'test', on: undefined, to: ['current_role', 'manager'], - using: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3609,6 +3581,223 @@ test('add policy with multiple "to" roles', async (t) => { } }); +test('rename policy that is linked', async (t) => { + const client = new PGlite(); + + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const { sqlStatements: createUsers } = await diffTestSchemas({}, { users }, []); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const schema2 = { + users, + rls: pgPolicy('newName', { as: 'permissive' }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + ['public.users.test->public.users.newName'], + false, + ['public'], + undefined, + undefined, + { before: createUsers }, + ); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" RENAME TO "newName";', + ]); + expect(statements).toStrictEqual([ + { + newName: 'newName', + oldName: 'test', + schema: '', + tableName: 'users', + type: 'rename_policy', + }, + ]); +}); + +test('alter policy that is linked', async (t) => { + const client = new PGlite(); + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const { sqlStatements: createUsers } = await diffTestSchemas({}, { users }, []); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const schema2 = { + users, + rls: pgPolicy('test', { as: 'permissive', to: 'current_role' }).link(users), + }; + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + undefined, + { before: createUsers }, + ); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" TO current_role;', + ]); + expect(statements).toStrictEqual([{ + newData: 'test--PERMISSIVE--ALL--current_role--undefined', + oldData: 'test--PERMISSIVE--ALL--public--undefined', + schema: '', + tableName: 'users', + type: 'alter_policy', + }]); +}); + +test('alter policy that is linked: withCheck', async (t) => { + const client = new PGlite(); + + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const { sqlStatements: createUsers } = await diffTestSchemas({}, { users }, []); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive', withCheck: sql`true` }).link(users), + }; + + const schema2 = { + users, + rls: pgPolicy('test', { as: 'permissive', withCheck: sql`false` }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + undefined, + { before: createUsers }, + ); + + expect(sqlStatements).toStrictEqual([]); + expect(statements).toStrictEqual([]); +}); + +test('alter policy that is linked: using', async (t) => { + const client = new PGlite(); + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const { sqlStatements: createUsers } = await diffTestSchemas({}, { users }, []); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive', using: sql`true` }).link(users), + }; + + const schema2 = { + users, + rls: pgPolicy('test', { as: 'permissive', using: sql`false` }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + undefined, + { before: createUsers }, + ); + + expect(sqlStatements).toStrictEqual([]); + expect(statements).toStrictEqual([]); +}); + +test('alter policy that is linked: using', async (t) => { + const client = new PGlite(); + + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const { sqlStatements: createUsers } = await diffTestSchemas({}, { users }, []); + + const schema1 = { + rls: pgPolicy('test', { for: 'insert' }).link(users), + }; + + const schema2 = { + users, + rls: pgPolicy('test', { for: 'delete' }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + undefined, + { before: createUsers }, + ); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR DELETE TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'INSERT', + name: 'test', + on: undefined, + to: [ + 'public', + ], + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + { + data: { + as: 'PERMISSIVE', + for: 'DELETE', + name: 'test', + on: undefined, + to: [ + 'public', + ], + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); + //// test('create role', async (t) => { diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 441318767..adc7aecbf 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -837,19 +837,6 @@ export const diffTestSchemasPush = async ( ); } - // do introspect into PgSchemaInternal - const introspectedSchema = await fromDatabase( - { - query: async (query: string, values?: any[] | undefined) => { - const res = await client.query(query, values); - return res.rows as any[]; - }, - }, - undefined, - schemas, - entities, - ); - const leftTables = Object.values(right).filter((it) => is(it, PgTable)) as PgTable[]; const leftSchemas = Object.values(right).filter((it) => is(it, PgSchema)) as PgSchema[]; @@ -878,6 +865,21 @@ export const diffTestSchemasPush = async ( casing, ); + // do introspect into PgSchemaInternal + const introspectedSchema = await fromDatabase( + { + query: async (query: string, values?: any[] | undefined) => { + const res = await client.query(query, values); + return res.rows as any[]; + }, + }, + undefined, + schemas, + entities, + undefined, + serialized2, + ); + const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; From 8e98201b2382733bfb37d83b0fa9a2a075cb8dbe Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 6 Nov 2024 15:27:34 +0200 Subject: [PATCH 299/492] Dprint --- drizzle-kit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 57996969b..26163fed2 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -138,4 +138,4 @@ "default": "./api.mjs" } } -} \ No newline at end of file +} From 96d338bbe4c9529047fa8ab537e9bc8a4328032a Mon Sep 17 00:00:00 2001 From: L-Mario564 Date: Wed, 6 Nov 2024 09:45:33 -0800 Subject: [PATCH 300/492] Batch of bugfixes for Kit (#2959) * Escape single quote in enum value * Escape single quotes in string default values * Handle instrospection of strings with single quotes * Add tests * Add tests * Uncomment tests * Fix SQL statement order in MySQL * Add MySQL test * Fix alter composite PK statement missing quotes in PG * Add tests * Handle SQL expressions in timestamp, date and time in PG * Use `.run` instead of `.query` in SQLite queries that don't return anything * Fix parsing of enum array types in PG * Generate more PG index operators * Fix primary key recreate on table rename * Format * Format * Update test * Format * Fix tests * Fix terminal output mistake * Remove duplicate import --------- Co-authored-by: Andrii Sherman --- drizzle-kit/src/cli/commands/push.ts | 8 +- drizzle-kit/src/cli/validations/outputs.ts | 2 +- drizzle-kit/src/introspect-mysql.ts | 13 +- drizzle-kit/src/introspect-pg.ts | 42 +++-- drizzle-kit/src/introspect-sqlite.ts | 4 +- drizzle-kit/src/jsonStatements.ts | 31 +--- drizzle-kit/src/serializer/mysqlSerializer.ts | 24 ++- drizzle-kit/src/serializer/pgSchema.ts | 6 +- drizzle-kit/src/serializer/pgSerializer.ts | 16 +- .../src/serializer/sqliteSerializer.ts | 4 +- drizzle-kit/src/snapshotsDiffer.ts | 18 +- drizzle-kit/src/sqlgenerator.ts | 139 +++++++-------- drizzle-kit/src/utils.ts | 10 ++ drizzle-kit/tests/indexes/pg.test.ts | 4 +- drizzle-kit/tests/introspect/mysql.test.ts | 23 +++ drizzle-kit/tests/introspect/pg.test.ts | 27 +++ drizzle-kit/tests/introspect/sqlite.test.ts | 19 +++ drizzle-kit/tests/mysql.test.ts | 102 +++++++++++ drizzle-kit/tests/pg-columns.test.ts | 28 ++- drizzle-kit/tests/pg-enums.test.ts | 73 +++++++- drizzle-kit/tests/pg-tables.test.ts | 100 +++++++++++ drizzle-kit/tests/push/common.ts | 5 + drizzle-kit/tests/push/mysql.test.ts | 85 +++++++++- drizzle-kit/tests/push/pg.test.ts | 159 ++++++++++++++++++ drizzle-kit/tests/push/sqlite.test.ts | 77 +++++++++ drizzle-kit/tests/sqlite-columns.test.ts | 22 +++ drizzle-kit/tests/sqlite-tables.test.ts | 44 +++++ 27 files changed, 918 insertions(+), 167 deletions(-) diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 54dbb4ba0..4a41a46d4 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -383,15 +383,15 @@ export const sqlitePush = async ( render(`\n[${chalk.blue('i')}] No changes detected`); } else { if (!('driver' in credentials)) { - await db.query('begin'); + await db.run('begin'); try { for (const dStmnt of statementsToExecute) { - await db.query(dStmnt); + await db.run(dStmnt); } - await db.query('commit'); + await db.run('commit'); } catch (e) { console.error(e); - await db.query('rollback'); + await db.run('rollback'); process.exit(1); } } diff --git a/drizzle-kit/src/cli/validations/outputs.ts b/drizzle-kit/src/cli/validations/outputs.ts index 6b92829d5..3ef499651 100644 --- a/drizzle-kit/src/cli/validations/outputs.ts +++ b/drizzle-kit/src/cli/validations/outputs.ts @@ -26,7 +26,7 @@ export const outputs = { ), noDialect: () => withStyle.error( - `Please specify 'dialect' param in config, either of 'pg', 'mysql' or 'sqlite'`, + `Please specify 'dialect' param in config, either of 'postgresql', 'mysql', 'sqlite' or 'turso'`, ), }, common: { diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index c15fea937..ebf30f70d 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -14,6 +14,7 @@ import { UniqueConstraint, } from './serializer/mysqlSchema'; import { indexName } from './serializer/mysqlSerializer'; +import { unescapeSingleQuotes } from './utils'; // time precision to fsp // {mode: "string"} for timestamp by default @@ -679,8 +680,9 @@ const column = ( ) } })`; + const mappedDefaultValue = mapColumnDefault(defaultValue, isExpression); out += defaultValue - ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + ? `.default(${isExpression ? mappedDefaultValue : unescapeSingleQuotes(mappedDefaultValue, true)})` : ''; return out; } @@ -787,10 +789,15 @@ const column = ( } if (lowered.startsWith('enum')) { - const values = lowered.substring('enum'.length + 1, lowered.length - 1); + const values = lowered + .substring('enum'.length + 1, lowered.length - 1) + .split(',') + .map((v) => unescapeSingleQuotes(v, true)) + .join(','); let out = `${casing(name)}: mysqlEnum(${dbColumnName({ name, casing: rawCasing, withMode: true })}[${values}])`; + const mappedDefaultValue = mapColumnDefault(defaultValue, isExpression); out += defaultValue - ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + ? `.default(${isExpression ? mappedDefaultValue : unescapeSingleQuotes(mappedDefaultValue, true)})` : ''; return out; } diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index ed26e8117..9c9383ebe 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -11,7 +11,6 @@ import { import './@types/utils'; import { toCamelCase } from 'drizzle-orm/casing'; import { Casing } from './cli/validations/common'; -import { vectorOps } from './extensions/vector'; import { assertUnreachable } from './global'; import { CheckConstraint, @@ -25,6 +24,7 @@ import { UniqueConstraint, } from './serializer/pgSchema'; import { indexName } from './serializer/pgSerializer'; +import { unescapeSingleQuotes } from './utils'; const pgImportsList = new Set([ 'pgTable', @@ -436,7 +436,7 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => const func = enumSchema ? `${enumSchema}.enum` : 'pgEnum'; const values = Object.values(it.values) - .map((it) => `'${it}'`) + .map((it) => `'${unescapeSingleQuotes(it, false)}'`) .join(', '); return `export const ${withCasing(paramName, casing)} = ${func}("${it.name}", [${values}])\n`; }) @@ -690,7 +690,9 @@ const mapDefault = ( } if (enumTypes.has(`${typeSchema}.${type.replace('[]', '')}`)) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('integer')) { @@ -737,18 +739,20 @@ const mapDefault = ( if (lowered.startsWith('timestamp')) { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue === 'CURRENT_TIMESTAMP' - ? '.default(sql`CURRENT_TIMESTAMP`)' - : defaultValue + : /^'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}(:\d{2})?)?'$/.test(defaultValue) // Matches 'YYYY-MM-DD HH:MI:SS', 'YYYY-MM-DD HH:MI:SS.FFFFFF', 'YYYY-MM-DD HH:MI:SS+TZ', 'YYYY-MM-DD HH:MI:SS.FFFFFF+TZ' and 'YYYY-MM-DD HH:MI:SS+HH:MI' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } if (lowered.startsWith('time')) { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue + : /^'\d{2}:\d{2}(:\d{2})?(\.\d+)?'$/.test(defaultValue) // Matches 'HH:MI', 'HH:MI:SS' and 'HH:MI:SS.FFFFFF' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } @@ -759,15 +763,17 @@ const mapDefault = ( if (lowered === 'date') { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue === 'CURRENT_DATE' - ? `.default(sql\`${defaultValue}\`)` - : defaultValue + : /^'\d{4}-\d{2}-\d{2}'$/.test(defaultValue) // Matches 'YYYY-MM-DD' ? `.default(${defaultValue})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } if (lowered.startsWith('text')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('jsonb')) { @@ -801,7 +807,9 @@ const mapDefault = ( } if (lowered.startsWith('varchar')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('point')) { @@ -821,7 +829,9 @@ const mapDefault = ( } if (lowered.startsWith('char')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } return ''; @@ -1219,7 +1229,11 @@ const createTableIndexes = (tableName: string, idxs: Index[], casing: Casing): s } else { return `table.${withCasing(it.expression, casing)}${it.asc ? '.asc()' : '.desc()'}${ it.nulls === 'first' ? '.nullsFirst()' : '.nullsLast()' - }${it.opclass && vectorOps.includes(it.opclass) ? `.op("${it.opclass}")` : ''}`; + }${ + it.opclass + ? `.op("${it.opclass}")` + : '' + }`; } }) .join(', ') diff --git a/drizzle-kit/src/introspect-sqlite.ts b/drizzle-kit/src/introspect-sqlite.ts index e21f2a5c4..464a32aa3 100644 --- a/drizzle-kit/src/introspect-sqlite.ts +++ b/drizzle-kit/src/introspect-sqlite.ts @@ -272,10 +272,8 @@ const mapColumnDefault = (defaultValue: any) => { if ( typeof defaultValue === 'string' - && defaultValue.startsWith("'") - && defaultValue.endsWith("'") ) { - return defaultValue.substring(1, defaultValue.length - 1); + return defaultValue.substring(1, defaultValue.length - 1).replaceAll('"', '\\"').replaceAll("''", "'"); } return defaultValue; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 9359b1a8d..18b28fac4 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -2704,19 +2704,14 @@ export const prepareAddCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, - // TODO: remove? - json2: PgSchema, ): JsonCreateCompositePK[] => { return Object.values(pks).map((it) => { - const unsquashed = PgSquasher.unsquashPK(it); return { type: 'create_composite_pk', tableName, data: it, schema, - constraintName: json2.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - unsquashed.name - ].name, + constraintName: PgSquasher.unsquashPK(it).name, } as JsonCreateCompositePK; }); }; @@ -2725,8 +2720,6 @@ export const prepareDeleteCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, - // TODO: remove? - json1: PgSchema, ): JsonDeleteCompositePK[] => { return Object.values(pks).map((it) => { return { @@ -2734,9 +2727,7 @@ export const prepareDeleteCompositePrimaryKeyPg = ( tableName, data: it, schema, - constraintName: json1.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it).name - ].name, + constraintName: PgSquasher.unsquashPK(it).name, } as JsonDeleteCompositePK; }); }; @@ -2745,9 +2736,6 @@ export const prepareAlterCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, - // TODO: remove? - json1: PgSchema, - json2: PgSchema, ): JsonAlterCompositePK[] => { return Object.values(pks).map((it) => { return { @@ -2756,12 +2744,8 @@ export const prepareAlterCompositePrimaryKeyPg = ( old: it.__old, new: it.__new, schema, - oldConstraintName: json1.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it.__old).name - ].name, - newConstraintName: json2.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it.__new).name - ].name, + oldConstraintName: PgSquasher.unsquashPK(it.__old).name, + newConstraintName: PgSquasher.unsquashPK(it.__new).name, } as JsonAlterCompositePK; }); }; @@ -2874,7 +2858,7 @@ export const prepareAddCompositePrimaryKeyMySql = ( type: 'create_composite_pk', tableName, data: it, - constraintName: json2.tables[tableName].compositePrimaryKeys[unsquashed.name].name, + constraintName: unsquashed.name, } as JsonCreateCompositePK); } return res; @@ -2887,13 +2871,12 @@ export const prepareDeleteCompositePrimaryKeyMySql = ( json1: MySqlSchema, ): JsonDeleteCompositePK[] => { return Object.values(pks).map((it) => { + const unsquashed = MySqlSquasher.unsquashPK(it); return { type: 'delete_composite_pk', tableName, data: it, - constraintName: json1.tables[tableName].compositePrimaryKeys[ - MySqlSquasher.unsquashPK(it).name - ].name, + constraintName: unsquashed.name, } as JsonDeleteCompositePK; }); }; diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 25ca1d596..aaa1acb82 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -26,13 +26,20 @@ import { UniqueConstraint, View, } from '../serializer/mysqlSchema'; -import type { DB } from '../utils'; +import { type DB, escapeSingleQuotes } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; }; +const handleEnumType = (type: string) => { + let str = type.split('(')[1]; + str = str.substring(0, str.length - 1); + const values = str.split(',').map((v) => `'${escapeSingleQuotes(v.substring(1, v.length - 1))}'`); + return `enum(${values.join(',')})`; +}; + export const generateMySqlSnapshot = ( tables: AnyMySqlTable[], views: MySqlView[], @@ -68,7 +75,8 @@ export const generateMySqlSnapshot = ( columns.forEach((column) => { const name = getColumnCasing(column, casing); const notNull: boolean = column.notNull; - const sqlTypeLowered = column.getSQLType().toLowerCase(); + const sqlType = column.getSQLType(); + const sqlTypeLowered = sqlType.toLowerCase(); const autoIncrement = typeof (column as any).autoIncrement === 'undefined' ? false : (column as any).autoIncrement; @@ -77,7 +85,7 @@ export const generateMySqlSnapshot = ( const columnToSet: Column = { name, - type: column.getSQLType(), + type: sqlType.startsWith('enum') ? handleEnumType(sqlType) : sqlType, primaryKey: false, // If field is autoincrement it's notNull by default // notNull: autoIncrement ? true : notNull, @@ -141,7 +149,7 @@ export const generateMySqlSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { if (typeof column.default === 'string') { - columnToSet.default = `'${column.default}'`; + columnToSet.default = `'${escapeSingleQuotes(column.default)}'`; } else { if (sqlTypeLowered === 'json') { columnToSet.default = `'${JSON.stringify(column.default)}'`; @@ -544,9 +552,9 @@ function clearDefaults(defaultValue: any, collate: string) { .substring(collate.length, defaultValue.length) .replace(/\\/g, ''); if (resultDefault.startsWith("'") && resultDefault.endsWith("'")) { - return `('${resultDefault.substring(1, resultDefault.length - 1)}')`; + return `('${escapeSingleQuotes(resultDefault.substring(1, resultDefault.length - 1))}')`; } else { - return `'${resultDefault}'`; + return `'${escapeSingleQuotes(resultDefault.substring(1, resultDefault.length - 1))}'`; } } else { return `(${resultDefault})`; @@ -665,14 +673,14 @@ export const fromDatabase = async ( } const newColumn: Column = { - default: columnDefault === null + default: columnDefault === null || columnDefault === undefined ? undefined : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) && !['decimal', 'char', 'varchar'].some((type) => columnType.startsWith(type)) ? Number(columnDefault) : isDefaultAnExpression ? clearDefaults(columnDefault, collation) - : `'${columnDefault}'`, + : `'${escapeSingleQuotes(columnDefault)}'`, autoincrement: isAutoincrement, name: columnName, type: changedType, diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index f5810bbc8..d7604d645 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -1,4 +1,3 @@ -import { vectorOps } from 'src/extensions/vector'; import { mapValues, originUUID, snapshotVersion } from '../global'; import { any, array, boolean, enum as enumType, literal, number, object, record, string, TypeOf, union } from 'zod'; @@ -555,10 +554,7 @@ export const PgSquasher = { return `${idx.name};${ idx.columns .map( - (c) => - `${c.expression}--${c.isExpression}--${c.asc}--${c.nulls}--${ - c.opclass && vectorOps.includes(c.opclass) ? c.opclass : '' - }`, + (c) => `${c.expression}--${c.isExpression}--${c.asc}--${c.nulls}--${c.opclass ? c.opclass : ''}`, ) .join(',,') };${idx.isUnique};${idx.concurrently};${idx.method};${idx.where};${JSON.stringify(idx.with)}`; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 66b8db85f..b0faa5ea8 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -39,7 +39,7 @@ import type { UniqueConstraint, View, } from '../serializer/pgSchema'; -import { type DB, isPgArrayType } from '../utils'; +import { type DB, escapeSingleQuotes, isPgArrayType } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const indexName = (tableName: string, columns: string[]) => { @@ -241,7 +241,7 @@ export const generatePgSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { if (typeof column.default === 'string') { - columnToSet.default = `'${column.default}'`; + columnToSet.default = `'${escapeSingleQuotes(column.default)}'`; } else { if (sqlTypeLowered === 'jsonb' || sqlTypeLowered === 'json') { columnToSet.default = `'${JSON.stringify(column.default)}'::${sqlTypeLowered}`; @@ -1937,11 +1937,13 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str const columnName = column.column_name; const isArray = internals?.tables[tableName]?.columns[columnName]?.isArray ?? false; - if (column.column_default === null) { - return undefined; - } - - if (column.data_type === 'serial' || column.data_type === 'smallserial' || column.data_type === 'bigserial') { + if ( + column.column_default === null + || column.column_default === undefined + || column.data_type === 'serial' + || column.data_type === 'smallserial' + || column.data_type === 'bigserial' + ) { return undefined; } diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 1ba24b69c..107a1b292 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -25,7 +25,7 @@ import type { UniqueConstraint, View, } from '../serializer/sqliteSchema'; -import type { SQLiteDB } from '../utils'; +import { escapeSingleQuotes, type SQLiteDB } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const generateSqliteSnapshot = ( @@ -90,7 +90,7 @@ export const generateSqliteSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { columnToSet.default = typeof column.default === 'string' - ? `'${column.default}'` + ? `'${escapeSingleQuotes(column.default)}'` : typeof column.default === 'object' || Array.isArray(column.default) ? `'${JSON.stringify(column.default)}'` diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index dda13b967..060f12bbd 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -131,7 +131,6 @@ import { PgSchemaSquashed, PgSquasher, Policy, - policy, policySquashed, Role, roleSchema, @@ -1243,22 +1242,22 @@ export const applyPgSnapshotsDiff = async ( // This part is needed to make sure that same columns in a table are not triggered for change // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name // We double-check that pk with same set of columns are both in added and deleted diffs - let addedColumns: string[] = []; + let addedColumns: { name: string; columns: string[] } | undefined; for (const addedPkName of Object.keys(it.addedCompositePKs)) { const addedPkColumns = it.addedCompositePKs[addedPkName]; - addedColumns = SQLiteSquasher.unsquashPK(addedPkColumns); + addedColumns = PgSquasher.unsquashPK(addedPkColumns); } - let deletedColumns: string[] = []; + let deletedColumns: { name: string; columns: string[] } | undefined; for (const deletedPkName of Object.keys(it.deletedCompositePKs)) { const deletedPkColumns = it.deletedCompositePKs[deletedPkName]; - deletedColumns = SQLiteSquasher.unsquashPK(deletedPkColumns); + deletedColumns = PgSquasher.unsquashPK(deletedPkColumns); } // Don't need to sort, but need to add tests for it // addedColumns.sort(); // deletedColumns.sort(); - const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); + const doPerformDeleteAndCreate = JSON.stringify(addedColumns ?? {}) !== JSON.stringify(deletedColumns ?? {}); let addedCompositePKs: JsonCreateCompositePK[] = []; let deletedCompositePKs: JsonDeleteCompositePK[] = []; @@ -1268,21 +1267,17 @@ export const applyPgSnapshotsDiff = async ( it.name, it.schema, it.addedCompositePKs, - curFull as PgSchema, ); deletedCompositePKs = prepareDeleteCompositePrimaryKeyPg( it.name, it.schema, it.deletedCompositePKs, - prevFull as PgSchema, ); } alteredCompositePKs = prepareAlterCompositePrimaryKeyPg( it.name, it.schema, it.alteredCompositePKs, - prevFull as PgSchema, - curFull as PgSchema, ); // add logic for unique constraints @@ -2634,12 +2629,11 @@ export const applyMysqlSnapshotsDiff = async ( jsonStatements.push(...jsonDeletedCompositePKs); jsonStatements.push(...jsonTableAlternations); jsonStatements.push(...jsonAddedCompositePKs); + jsonStatements.push(...jsonAddColumnsStatemets); jsonStatements.push(...jsonAddedUniqueConstraints); jsonStatements.push(...jsonDeletedUniqueConstraints); - jsonStatements.push(...jsonAddColumnsStatemets); - jsonStatements.push(...jsonCreateReferencesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForCreatedTables); jsonStatements.push(...jsonCreatedCheckConstraints); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index bb3335941..3c88a86ce 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -86,75 +86,59 @@ import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; import { PgSquasher, policy } from './serializer/pgSchema'; import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; - -export const pgNativeTypes = new Set([ - 'uuid', - 'smallint', - 'integer', - 'bigint', - 'boolean', - 'text', - 'varchar', - 'serial', - 'bigserial', - 'decimal', - 'numeric', - 'real', - 'json', - 'jsonb', - 'time', - 'time with time zone', - 'time without time zone', - 'time', - 'timestamp', - 'timestamp with time zone', - 'timestamp without time zone', - 'date', - 'interval', - 'bigint', - 'bigserial', - 'double precision', - 'interval year', - 'interval month', - 'interval day', - 'interval hour', - 'interval minute', - 'interval second', - 'interval year to month', - 'interval day to hour', - 'interval day to minute', - 'interval day to second', - 'interval hour to minute', - 'interval hour to second', - 'interval minute to second', -]); - -const isPgNativeType = (it: string) => { - if (pgNativeTypes.has(it)) return true; - const toCheck = it.replace(/ /g, ''); - return ( - toCheck.startsWith('varchar(') - || toCheck.startsWith('char(') - || toCheck.startsWith('numeric(') - || toCheck.startsWith('timestamp(') - || toCheck.startsWith('doubleprecision[') - || toCheck.startsWith('intervalyear(') - || toCheck.startsWith('intervalmonth(') - || toCheck.startsWith('intervalday(') - || toCheck.startsWith('intervalhour(') - || toCheck.startsWith('intervalminute(') - || toCheck.startsWith('intervalsecond(') - || toCheck.startsWith('intervalyeartomonth(') - || toCheck.startsWith('intervaldaytohour(') - || toCheck.startsWith('intervaldaytominute(') - || toCheck.startsWith('intervaldaytosecond(') - || toCheck.startsWith('intervalhourtominute(') - || toCheck.startsWith('intervalhourtosecond(') - || toCheck.startsWith('intervalminutetosecond(') - || toCheck.startsWith('vector(') - || toCheck.startsWith('geometry(') - || /^(\w+)(\[\d*])+$/.test(it) - ); +import { escapeSingleQuotes } from './utils'; + +const parseType = (schemaPrefix: string, type: string) => { + const pgNativeTypes = [ + 'uuid', + 'smallint', + 'integer', + 'bigint', + 'boolean', + 'text', + 'varchar', + 'serial', + 'bigserial', + 'decimal', + 'numeric', + 'real', + 'json', + 'jsonb', + 'time', + 'time with time zone', + 'time without time zone', + 'time', + 'timestamp', + 'timestamp with time zone', + 'timestamp without time zone', + 'date', + 'interval', + 'bigint', + 'bigserial', + 'double precision', + 'interval year', + 'interval month', + 'interval day', + 'interval hour', + 'interval minute', + 'interval second', + 'interval year to month', + 'interval day to hour', + 'interval day to minute', + 'interval day to second', + 'interval hour to minute', + 'interval hour to second', + 'interval minute to second', + 'char', + 'vector', + 'geometry', + ]; + const arrayDefinitionRegex = /\[\d*(?:\[\d*\])*\]/g; + const arrayDefinition = (type.match(arrayDefinitionRegex) ?? []).join(''); + const withoutArrayDefinition = type.replace(arrayDefinitionRegex, ''); + return pgNativeTypes.some((it) => type.startsWith(it)) + ? `${withoutArrayDefinition}${arrayDefinition}` + : `${schemaPrefix}"${withoutArrayDefinition}"${arrayDefinition}`; }; abstract class Convertor { @@ -419,9 +403,7 @@ class PgCreateTableConvertor extends Convertor { ? `"${column.typeSchema}".` : ''; - const type = isPgNativeType(column.type) - ? column.type - : `${schemaPrefix}"${column.type}"`; + const type = parseType(schemaPrefix, column.type); const generated = column.generated; const generatedStatement = generated ? ` GENERATED ALWAYS AS (${generated?.as}) STORED` : ''; @@ -1296,7 +1278,7 @@ class CreateTypeEnumConvertor extends Convertor { const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; let valuesStatement = '('; - valuesStatement += values.map((it) => `'${it}'`).join(', '); + valuesStatement += values.map((it) => `'${escapeSingleQuotes(it)}'`).join(', '); valuesStatement += ')'; // TODO do we need this? @@ -1604,9 +1586,7 @@ class PgAlterTableAddColumnConvertor extends Convertor { ? `"${column.typeSchema}".` : ''; - const fixedType = isPgNativeType(column.type) - ? column.type - : `${schemaPrefix}"${column.type}"`; + const fixedType = parseType(schemaPrefix, column.type); const notNullStatement = `${notNull ? ' NOT NULL' : ''}`; @@ -2530,9 +2510,10 @@ class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { ? `"${statement.schema}"."${statement.tableName}"` : `"${statement.tableName}"`; - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT ${statement.oldConstraintName};\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newConstraintName} PRIMARY KEY(${ - newColumns.join(',') - });`; + console.log(statement.oldConstraintName, statement.newConstraintName); + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.oldConstraintName}";\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.newConstraintName}" PRIMARY KEY("${ + newColumns.join('","') + }");`; } } diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index f26624969..685e2efb5 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -4,6 +4,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from import { join } from 'path'; import { parse } from 'url'; import type { NamedWithSchema } from './cli/commands/migrate'; +import { CasingType } from './cli/validations/common'; import { info } from './cli/views'; import { assertUnreachable, snapshotVersion } from './global'; import type { Dialect } from './schemaValidator'; @@ -356,3 +357,12 @@ export function findAddedAndRemoved(columnNames1: string[], columnNames2: string return { addedColumns, removedColumns }; } + +export function escapeSingleQuotes(str: string) { + return str.replace(/'/g, "''"); +} + +export function unescapeSingleQuotes(str: string, ignoreFirstAndLastChar: boolean) { + const regex = ignoreFirstAndLastChar ? /(? { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('instrospect strings with single quotes', async () => { + const schema = { + columns: mysqlTable('columns', { + enum: mysqlEnum('my_enum', ['escape\'s quotes "', 'escape\'s quotes 2 "']).default('escape\'s quotes "'), + text: text('text').default('escape\'s quotes " '), + varchar: varchar('varchar', { length: 255 }).default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'introspect-strings-with-single-quotes', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`drop table columns;`); +}); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index 6762ef27a..1d9f0f18c 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -255,8 +255,12 @@ test('instrospect all column types', async () => { time2: time('time2').defaultNow(), timestamp1: timestamp('timestamp1', { withTimezone: true, precision: 6 }).default(new Date()), timestamp2: timestamp('timestamp2', { withTimezone: true, precision: 6 }).defaultNow(), + timestamp3: timestamp('timestamp3', { withTimezone: true, precision: 6 }).default( + sql`timezone('utc'::text, now())`, + ), date1: date('date1').default('2024-01-01'), date2: date('date2').defaultNow(), + date3: date('date3').default(sql`CURRENT_TIMESTAMP`), uuid1: uuid('uuid1').default('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'), uuid2: uuid('uuid2').defaultRandom(), inet: inet('inet').default('127.0.0.1'), @@ -418,6 +422,29 @@ test('introspect enum with similar name to native type', async () => { expect(sqlStatements.length).toBe(0); }); +test('instrospect strings with single quotes', async () => { + const client = new PGlite(); + + const myEnum = pgEnum('my_enum', ['escape\'s quotes " ']); + const schema = { + enum_: myEnum, + columns: pgTable('columns', { + enum: myEnum('my_enum').default('escape\'s quotes " '), + text: text('text').default('escape\'s quotes " '), + varchar: varchar('varchar').default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-strings-with-single-quotes', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + test('introspect checks', async () => { const client = new PGlite(); diff --git a/drizzle-kit/tests/introspect/sqlite.test.ts b/drizzle-kit/tests/introspect/sqlite.test.ts index 89cdf590e..de13d4e81 100644 --- a/drizzle-kit/tests/introspect/sqlite.test.ts +++ b/drizzle-kit/tests/introspect/sqlite.test.ts @@ -56,6 +56,25 @@ test('generated always column virtual: link to another column', async () => { expect(sqlStatements.length).toBe(0); }); +test('instrospect strings with single quotes', async () => { + const sqlite = new Database(':memory:'); + + const schema = { + columns: sqliteTable('columns', { + text: text('text').default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectSQLiteToFile( + sqlite, + schema, + 'introspect-strings-with-single-quotes', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + test('introspect checks', async () => { const sqlite = new Database(':memory:'); diff --git a/drizzle-kit/tests/mysql.test.ts b/drizzle-kit/tests/mysql.test.ts index 183464ec0..881b05ef7 100644 --- a/drizzle-kit/tests/mysql.test.ts +++ b/drizzle-kit/tests/mysql.test.ts @@ -4,6 +4,7 @@ import { index, int, json, + mysqlEnum, mysqlSchema, mysqlTable, primaryKey, @@ -11,6 +12,7 @@ import { text, unique, uniqueIndex, + varchar, } from 'drizzle-orm/mysql-core'; import { expect, test } from 'vitest'; import { diffTestSchemasMysql } from './schemaDiffer'; @@ -533,6 +535,32 @@ test('drop index', async () => { expect(sqlStatements[0]).toBe('DROP INDEX `name_idx` ON `table`;'); }); +test('drop unique constraint', async () => { + const from = { + users: mysqlTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + uq: unique('name_uq').on(t.name), + }; + }, + ), + }; + + const to = { + users: mysqlTable('table', { + name: text('name'), + }), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe('ALTER TABLE `table` DROP INDEX `name_uq`;'); +}); + test('add table with indexes', async () => { const from = {}; @@ -578,6 +606,80 @@ test('add table with indexes', async () => { ]); }); +test('varchar and text default values escape single quotes', async (t) => { + const schema1 = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const schem2 = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + enum: mysqlEnum('enum', ["escape's quotes", "escape's quotes 2"]).default("escape's quotes"), + text: text('text').default("escape's quotes"), + varchar: varchar('varchar', { length: 255 }).default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemasMysql(schema1, schem2, []); + + expect(sqlStatements.length).toBe(3); + expect(sqlStatements[0]).toStrictEqual( + "ALTER TABLE `table` ADD `enum` enum('escape''s quotes','escape''s quotes 2') DEFAULT 'escape''s quotes';", + ); + expect(sqlStatements[1]).toStrictEqual( + "ALTER TABLE `table` ADD `text` text DEFAULT ('escape''s quotes');", + ); + expect(sqlStatements[2]).toStrictEqual( + "ALTER TABLE `table` ADD `varchar` varchar(255) DEFAULT 'escape''s quotes';", + ); +}); + +test('composite primary key', async () => { + const from = {}; + const to = { + table: mysqlTable('works_to_creators', { + workId: int('work_id').notNull(), + creatorId: int('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `works_to_creators` (\n\t`work_id` int NOT NULL,\n\t`creator_id` int NOT NULL,\n\t`classification` text NOT NULL,\n\tCONSTRAINT `works_to_creators_work_id_creator_id_classification_pk` PRIMARY KEY(`work_id`,`creator_id`,`classification`)\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + }), + }; + const to = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `table` ADD `name` text NOT NULL;', + 'ALTER TABLE `table` ADD CONSTRAINT `uq` UNIQUE(`name`);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; diff --git a/drizzle-kit/tests/pg-columns.test.ts b/drizzle-kit/tests/pg-columns.test.ts index cffeed3ed..ddd744a81 100644 --- a/drizzle-kit/tests/pg-columns.test.ts +++ b/drizzle-kit/tests/pg-columns.test.ts @@ -1,4 +1,4 @@ -import { integer, pgTable, primaryKey, serial, text, uuid } from 'drizzle-orm/pg-core'; +import { integer, pgTable, primaryKey, serial, text, uuid, varchar } from 'drizzle-orm/pg-core'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; @@ -456,3 +456,29 @@ test('add multiple constraints #3', async (t) => { expect(statements.length).toBe(6); }); + +test('varchar and text default values escape single quotes', async (t) => { + const schema1 = { + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const schem2 = { + table: pgTable('table', { + id: serial('id').primaryKey(), + text: text('text').default("escape's quotes"), + varchar: varchar('varchar').default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemas(schema1, schem2, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toStrictEqual( + 'ALTER TABLE "table" ADD COLUMN "text" text DEFAULT \'escape\'\'s quotes\';', + ); + expect(sqlStatements[1]).toStrictEqual( + 'ALTER TABLE "table" ADD COLUMN "varchar" varchar DEFAULT \'escape\'\'s quotes\';', + ); +}); diff --git a/drizzle-kit/tests/pg-enums.test.ts b/drizzle-kit/tests/pg-enums.test.ts index 99a3dca7e..2af691d46 100644 --- a/drizzle-kit/tests/pg-enums.test.ts +++ b/drizzle-kit/tests/pg-enums.test.ts @@ -1,4 +1,4 @@ -import { pgEnum, pgSchema, pgTable } from 'drizzle-orm/pg-core'; +import { integer, pgEnum, pgSchema, pgTable, serial } from 'drizzle-orm/pg-core'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; @@ -506,6 +506,77 @@ test('enums #18', async () => { }); }); +test('enums #19', async () => { + const myEnum = pgEnum('my_enum', ["escape's quotes"]); + + const from = {}; + + const to = { myEnum }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toStrictEqual( + 'CREATE TYPE "public"."my_enum" AS ENUM(\'escape\'\'s quotes\');', + ); +}); + +test('enums #20', async () => { + const myEnum = pgEnum('my_enum', ['one', 'two', 'three']); + + const from = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const to = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + col1: myEnum('col1'), + col2: integer('col2'), + }), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "col1" "my_enum";', + 'ALTER TABLE "table" ADD COLUMN "col2" integer;', + ]); +}); + +test('enums #21', async () => { + const myEnum = pgEnum('my_enum', ['one', 'two', 'three']); + + const from = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const to = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + col1: myEnum('col1').array(), + col2: integer('col2').array(), + }), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "col1" "my_enum"[];', + 'ALTER TABLE "table" ADD COLUMN "col2" integer[];', + ]); +}); + test('drop enum value', async () => { const enum1 = pgEnum('enum', ['value1', 'value2', 'value3']); diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index 1f2885f92..6ea6e472a 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -676,6 +676,106 @@ test('create table with tsvector', async () => { ]); }); +test('composite primary key', async () => { + const from = {}; + const to = { + table: pgTable('works_to_creators', { + workId: integer('work_id').notNull(), + creatorId: integer('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "works_to_creators" (\n\t"work_id" integer NOT NULL,\n\t"creator_id" integer NOT NULL,\n\t"classification" text NOT NULL,\n\tCONSTRAINT "works_to_creators_work_id_creator_id_classification_pk" PRIMARY KEY("work_id","creator_id","classification")\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + const to = { + table: pgTable('table', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "name" text NOT NULL;', + 'ALTER TABLE "table" ADD CONSTRAINT "uq" UNIQUE("name");', + ]); +}); + +test('alter composite primary key', async () => { + const from = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + col3: text('col3').notNull(), + }, (t) => ({ + pk: primaryKey({ + name: 'table_pk', + columns: [t.col1, t.col2], + }), + })), + }; + const to = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + col3: text('col3').notNull(), + }, (t) => ({ + pk: primaryKey({ + name: 'table_pk', + columns: [t.col2, t.col3], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" DROP CONSTRAINT "table_pk";\n--> statement-breakpoint\nALTER TABLE "table" ADD CONSTRAINT "table_pk" PRIMARY KEY("col2","col3");', + ]); +}); + +test('add index with op', async () => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }), + }; + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + nameIdx: index().using('gin', t.name.op('gin_trgm_ops')), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE INDEX IF NOT EXISTS "users_name_index" ON "users" USING gin ("name" gin_trgm_ops);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; diff --git a/drizzle-kit/tests/push/common.ts b/drizzle-kit/tests/push/common.ts index e5c68625d..627070f11 100644 --- a/drizzle-kit/tests/push/common.ts +++ b/drizzle-kit/tests/push/common.ts @@ -15,6 +15,8 @@ export interface DialectSuite { dropGeneratedConstraint(context?: any): Promise; alterGeneratedConstraint(context?: any): Promise; createTableWithGeneratedConstraint(context?: any): Promise; + createCompositePrimaryKey(context?: any): Promise; + renameTableWithCompositePrimaryKey(context?: any): Promise; case1(): Promise; } @@ -48,6 +50,9 @@ export const run = ( // should ignore on push test('Alter generated constraint', () => suite.alterGeneratedConstraint(context)); test('Create table with generated column', () => suite.createTableWithGeneratedConstraint(context)); + test('Rename table with composite primary key', () => suite.renameTableWithCompositePrimaryKey(context)); + + test('Create composite primary key', () => suite.createCompositePrimaryKey(context)); afterAll(afterAllFn ? () => afterAllFn(context) : () => {}); }; diff --git a/drizzle-kit/tests/push/mysql.test.ts b/drizzle-kit/tests/push/mysql.test.ts index 7b20dc444..6c7f5efc2 100644 --- a/drizzle-kit/tests/push/mysql.test.ts +++ b/drizzle-kit/tests/push/mysql.test.ts @@ -15,6 +15,7 @@ import { mediumint, mysqlEnum, mysqlTable, + primaryKey, serial, smallint, text, @@ -29,7 +30,7 @@ import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; import { diffTestSchemasMysql, diffTestSchemasPushMysql } from 'tests/schemaDiffer'; import { v4 as uuid } from 'uuid'; -import { expect } from 'vitest'; +import { expect, test } from 'vitest'; import { DialectSuite, run } from './common'; async function createDockerDB(context: any): Promise { @@ -663,6 +664,88 @@ const mysqlSuite: DialectSuite = { createTableWithGeneratedConstraint: function(context?: any): Promise { return {} as any; }, + createCompositePrimaryKey: async function(context: any): Promise { + const schema1 = {}; + + const schema2 = { + table: mysqlTable('table', { + col1: int('col1').notNull(), + col2: int('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table', + schema: undefined, + internals: { + indexes: {}, + tables: {}, + }, + compositePKs: ['table_col1_col2_pk;col1,col2'], + compositePkName: 'table_col1_col2_pk', + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + { name: 'col2', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + ], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `table` (\n\t`col1` int NOT NULL,\n\t`col2` int NOT NULL,\n\tCONSTRAINT `table_col1_col2_pk` PRIMARY KEY(`col1`,`col2`)\n);\n', + ]); + }, + renameTableWithCompositePrimaryKey: async function(context?: any): Promise { + const productsCategoriesTable = (tableName: string) => { + return mysqlTable(tableName, { + productId: varchar('product_id', { length: 10 }).notNull(), + categoryId: varchar('category_id', { length: 10 }).notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPushMysql( + context.client as Connection, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + 'drizzle', + false, + ); + + expect(sqlStatements).toStrictEqual([ + 'RENAME TABLE `products_categories` TO `products_to_categories`;', + 'ALTER TABLE `products_to_categories` DROP PRIMARY KEY;', + 'ALTER TABLE `products_to_categories` ADD PRIMARY KEY(`product_id`,`category_id`);', + ]); + + await context.client.query(`DROP TABLE \`products_categories\``); + }, }; run( diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 51e6fe73a..44ec786b6 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -22,6 +22,7 @@ import { pgSequence, pgTable, pgView, + primaryKey, real, serial, smallint, @@ -914,6 +915,89 @@ const pgSuite: DialectSuite = { expect(shouldAskForApprove).toBeFalsy(); }, + async createCompositePrimaryKey() { + const client = new PGlite(); + + const schema1 = {}; + + const schema2 = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table', + schema: '', + compositePKs: ['col1,col2;table_col1_col2_pk'], + compositePkName: 'table_col1_col2_pk', + isRLSEnabled: false, + policies: [], + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'integer', primaryKey: false, notNull: true }, + { name: 'col2', type: 'integer', primaryKey: false, notNull: true }, + ], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "table" (\n\t"col1" integer NOT NULL,\n\t"col2" integer NOT NULL,\n\tCONSTRAINT "table_col1_col2_pk" PRIMARY KEY("col1","col2")\n);\n', + ]); + }, + + async renameTableWithCompositePrimaryKey() { + const client = new PGlite(); + + const productsCategoriesTable = (tableName: string) => { + return pgTable(tableName, { + productId: text('product_id').notNull(), + categoryId: text('category_id').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + false, + ['public'], + ); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "products_categories" RENAME TO "products_to_categories";', + 'ALTER TABLE "products_to_categories" DROP CONSTRAINT "products_categories_product_id_category_id_pk";', + 'ALTER TABLE "products_to_categories" ADD CONSTRAINT "products_to_categories_product_id_category_id_pk" PRIMARY KEY("product_id","category_id");', + ]); + }, + // async addVectorIndexes() { // const client = new PGlite(); @@ -2104,6 +2188,81 @@ test('drop check constraint', async () => { ]); }); +test('Column with same name as enum', async () => { + const client = new PGlite(); + const statusEnum = pgEnum('status', ['inactive', 'active', 'banned']); + + const schema1 = { + statusEnum, + table1: pgTable('table1', { + id: serial('id').primaryKey(), + }), + }; + + const schema2 = { + statusEnum, + table1: pgTable('table1', { + id: serial('id').primaryKey(), + status: statusEnum('status').default('inactive'), + }), + table2: pgTable('table2', { + id: serial('id').primaryKey(), + status: statusEnum('status').default('inactive'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table2', + schema: '', + compositePKs: [], + compositePkName: '', + isRLSEnabled: false, + policies: [], + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'id', type: 'serial', primaryKey: true, notNull: true }, + { + name: 'status', + type: 'status', + typeSchema: 'public', + primaryKey: false, + notNull: false, + default: "'inactive'", + }, + ], + }, + { + type: 'alter_table_add_column', + tableName: 'table1', + schema: '', + column: { + name: 'status', + type: 'status', + typeSchema: 'public', + primaryKey: false, + notNull: false, + default: "'inactive'", + }, + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "table2" (\n\t"id" serial PRIMARY KEY NOT NULL,\n\t"status" "status" DEFAULT \'inactive\'\n);\n', + 'ALTER TABLE "table1" ADD COLUMN "status" "status" DEFAULT \'inactive\';', + ]); +}); + test('db has checks. Push with same names', async () => { const client = new PGlite(); diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index 5ac6f996c..dd1d88fe3 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -9,6 +9,7 @@ import { int, integer, numeric, + primaryKey, real, sqliteTable, sqliteView, @@ -1534,3 +1535,79 @@ test('alter view ".as"', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('create composite primary key', async (t) => { + const client = new Database(':memory:'); + + const schema1 = {}; + + const schema2 = { + table: sqliteTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { + statements, + sqlStatements, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([{ + type: 'sqlite_create_table', + tableName: 'table', + compositePKs: [['col1', 'col2']], + uniqueConstraints: [], + referenceData: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'integer', primaryKey: false, notNull: true, autoincrement: false }, + { name: 'col2', type: 'integer', primaryKey: false, notNull: true, autoincrement: false }, + ], + }]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `table` (\n\t`col1` integer NOT NULL,\n\t`col2` integer NOT NULL,\n\tPRIMARY KEY(`col1`, `col2`)\n);\n', + ]); +}); + +test('rename table with composite primary key', async () => { + const client = new Database(':memory:'); + + const productsCategoriesTable = (tableName: string) => { + return sqliteTable(tableName, { + productId: text('product_id').notNull(), + categoryId: text('category_id').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + false, + ); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `products_categories` RENAME TO `products_to_categories`;', + ]); +}); diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index b7b4c7f6b..0cb34c220 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -1025,3 +1025,25 @@ test('recreate table with nested references', async (t) => { expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); + +test('text default values escape single quotes', async (t) => { + const schema1 = { + table: sqliteTable('table', { + id: integer('id').primaryKey(), + }), + }; + + const schem2 = { + table: sqliteTable('table', { + id: integer('id').primaryKey(), + text: text('text').default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(schema1, schem2, []); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toStrictEqual( + "ALTER TABLE `table` ADD `text` text DEFAULT 'escape''s quotes';", + ); +}); diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index 8d8eae298..651c3633c 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -418,6 +418,50 @@ test('add table with indexes', async () => { ]); }); +test('composite primary key', async () => { + const from = {}; + const to = { + table: sqliteTable('works_to_creators', { + workId: int('work_id').notNull(), + creatorId: int('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `works_to_creators` (\n\t`work_id` integer NOT NULL,\n\t`creator_id` integer NOT NULL,\n\t`classification` text NOT NULL,\n\tPRIMARY KEY(`work_id`, `creator_id`, `classification`)\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: sqliteTable('table', { + id: int('id').primaryKey(), + }), + }; + const to = { + table: sqliteTable('table', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `table` ADD `name` text NOT NULL;', + 'CREATE UNIQUE INDEX `uq` ON `table` (`name`);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; From c30d4f0976b480a3649a2165b1a3ce666907ccfa Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 6 Nov 2024 21:12:09 +0200 Subject: [PATCH 301/492] Bump versions --- changelogs/drizzle-kit/0.28.0.md | 28 ++++++++++++++++++++++++++++ changelogs/drizzle-orm/0.36.1.md | 6 ++++++ drizzle-kit/package.json | 4 ++-- drizzle-orm/package.json | 4 ++-- 4 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 changelogs/drizzle-kit/0.28.0.md create mode 100644 changelogs/drizzle-orm/0.36.1.md diff --git a/changelogs/drizzle-kit/0.28.0.md b/changelogs/drizzle-kit/0.28.0.md new file mode 100644 index 000000000..6881c677e --- /dev/null +++ b/changelogs/drizzle-kit/0.28.0.md @@ -0,0 +1,28 @@ +# Improvements + +- Added an OHM static imports checker to identify unexpected imports within a chain of imports in the drizzle-kit repo. For example, it checks if drizzle-orm is imported before drizzle-kit and verifies if the drizzle-orm import is available in your project. +- [Adding more columns to Supabase auth.users table schema](https://github.com/drizzle-team/drizzle-orm/issues/3327) - thanks @nicholasdly + +# Bug Fixes + +- [[BUG]: [drizzle-kit]: Fix breakpoints option cannot be disabled](https://github.com/drizzle-team/drizzle-orm/issues/2828) - thanks @klotztech +- [[BUG]: drizzle-kit introspect: SMALLINT import missing and incorrect DECIMAL UNSIGNED handling](https://github.com/drizzle-team/drizzle-orm/issues/2950) - thanks @L-Mario564 +- [Unsigned tinyints preventing migrations](https://github.com/drizzle-team/drizzle-orm/issues/1571) - thanks @L-Mario564 +- [[BUG]: Can't parse float(8,2) from database (precision and scale and/or unsigned breaks float types)](https://github.com/drizzle-team/drizzle-orm/issues/3285) - thanks @L-Mario564 +- [[BUG]: PgEnum generated migration doesn't escape single quotes](https://github.com/drizzle-team/drizzle-orm/issues/1272) - thanks @L-Mario564 +- [[BUG]: single quote not escaped correctly in migration file](https://github.com/drizzle-team/drizzle-orm/issues/2184) - thanks @L-Mario564 +- [[BUG]: Migrations does not escape single quotes](https://github.com/drizzle-team/drizzle-orm/issues/1765) - thanks @L-Mario564 +- [[BUG]: Issue with quoted default string values](https://github.com/drizzle-team/drizzle-orm/issues/2122) - thanks @L-Mario564 +- [[BUG]: SQl commands in wrong roder](https://github.com/drizzle-team/drizzle-orm/issues/2390) - thanks @L-Mario564 +- [[BUG]: Time with precision in drizzle-orm/pg-core adds double-quotes around type](https://github.com/drizzle-team/drizzle-orm/issues/1804) - thanks @L-Mario564 +- [[BUG]: Postgres push fails due to lack of quotes](https://github.com/drizzle-team/drizzle-orm/issues/2396) - thanks @L-Mario564 +- [[BUG]: TypeError: Cannot read properties of undefined (reading 'compositePrimaryKeys')](https://github.com/drizzle-team/drizzle-orm/issues/2344) - thanks @L-Mario564 +- [[BUG]: drizzle-kit introspect generates CURRENT_TIMESTAMP without sql operator on date column](https://github.com/drizzle-team/drizzle-orm/issues/2899) - thanks @L-Mario564 +- [[BUG]: Drizzle-kit introspect doesn't pull correct defautl statement](https://github.com/drizzle-team/drizzle-orm/issues/2905) - thanks @L-Mario564 +- [[BUG]: Problem on MacBook - This statement does not return data. Use run() instead](https://github.com/drizzle-team/drizzle-orm/issues/2623) - thanks @L-Mario564 +- [[BUG]: Enum column names that are used as arrays are not quoted](https://github.com/drizzle-team/drizzle-orm/issues/2598) - thanks @L-Mario564 +- [[BUG]: drizzle-kit generate ignores index operators](https://github.com/drizzle-team/drizzle-orm/issues/2935) - thanks @L-Mario564 +- [dialect param config error message is wrong](https://github.com/drizzle-team/drizzle-orm/issues/3427) - thanks @L-Mario564 +- [[BUG]: Error setting default enum field values](https://github.com/drizzle-team/drizzle-orm/issues/2299) - thanks @L-Mario564 +- [[BUG]: drizzle-kit does not respect the order of columns configured in primaryKey()](https://github.com/drizzle-team/drizzle-orm/issues/2326) - thanks @L-Mario564 +- [[BUG]: Cannot drop Unique Constraint MySQL](https://github.com/drizzle-team/drizzle-orm/issues/998) - thanks @L-Mario564 diff --git a/changelogs/drizzle-orm/0.36.1.md b/changelogs/drizzle-orm/0.36.1.md new file mode 100644 index 000000000..1c0e96756 --- /dev/null +++ b/changelogs/drizzle-orm/0.36.1.md @@ -0,0 +1,6 @@ +# Bug Fixes + +- [[BUG]: Using sql.placeholder with limit and/or offset for a prepared statement produces TS error](https://github.com/drizzle-team/drizzle-orm/issues/2146) - thanks @L-Mario564 +- [[BUG] If a query I am trying to modify with a dynamic query (....$dynamic()) contains any placeholders, I'm getting an error that says No value for placeholder.... provided](https://github.com/drizzle-team/drizzle-orm/issues/2272) - thanks @L-Mario564 +- [[BUG]: Error thrown when trying to insert an array of new rows using generatedAlwaysAsIdentity() for the id column](https://github.com/drizzle-team/drizzle-orm/issues/2849) - thanks @L-Mario564 +- [[BUG]: Unable to Use BigInt Types with Bun and Drizzle](https://github.com/drizzle-team/drizzle-orm/issues/2603) - thanks @L-Mario564 \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 403b1601c..e45f7dbc5 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.27.2", + "version": "0.28.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", @@ -141,4 +141,4 @@ "default": "./api.mjs" } } -} +} \ No newline at end of file diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index e2b17a1af..598ee9a1e 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.36.0", + "version": "0.36.1", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -203,4 +203,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} +} \ No newline at end of file From 906c87e26d58df2ac8d44ce4d7bad8f1860976da Mon Sep 17 00:00:00 2001 From: Andrii Sherman Date: Wed, 6 Nov 2024 21:20:13 +0200 Subject: [PATCH 302/492] Beta (#3503) * Fix breakpoints option default value * fix: added commonly used columns to supabase auth.users table schema * imports checker with OHM grammar * imports checker with OHM grammar + fix of imports issues * Formatting fix * [MySQL] Add unsigned floating point types + Fix unsigned integer type bugs in Kit (#3284) * Fix bugs with MySQL introspection tests * Update float data type in MySQL * Better support for float types in MySQL * Handle existing unsigned numerical types in MySQL * Add unsigned to floating point types in MySQL * Handle unsigned floating point types in MySQL * Update decimal data type --------- Co-authored-by: Andrii Sherman * Batch of bugfixes for ORM (#3181) * (MySQL) Fix placeholder type error in offset and limit * Add prepared statement tests * Add PG test * Fix blob parsing in bun sqlite driver * Lint and format * Fix file * Fix tests * Use const instead of let in tests * Format --------- Co-authored-by: Andrii Sherman * main to beta (#3404) * Update Github issue templates (#3157) * Update GH issue templates * Update issue templates --------- Co-authored-by: Andrii Sherman * Fix checkboxes --------- Co-authored-by: L-Mario564 * feat: add tablesFilter to pushSchema api (#3141) * feat: add tablesFilter to pushSchema api * Format with dprint --------- Co-authored-by: Andrii Sherman * Batch of bugfixes for Kit (#2959) * Escape single quote in enum value * Escape single quotes in string default values * Handle instrospection of strings with single quotes * Add tests * Add tests * Uncomment tests * Fix SQL statement order in MySQL * Add MySQL test * Fix alter composite PK statement missing quotes in PG * Add tests * Handle SQL expressions in timestamp, date and time in PG * Use `.run` instead of `.query` in SQLite queries that don't return anything * Fix parsing of enum array types in PG * Generate more PG index operators * Fix primary key recreate on table rename * Format * Format * Update test * Format * Fix tests * Fix terminal output mistake * Remove duplicate import --------- Co-authored-by: Andrii Sherman * Bump versions --------- Co-authored-by: Steffen <3752127+klotztech@users.noreply.github.com> Co-authored-by: Nicholas Ly Co-authored-by: Alex Blokh Co-authored-by: Sukairo-02 Co-authored-by: L-Mario564 Co-authored-by: Dan Ribbens --- changelogs/drizzle-kit/0.28.0.md | 28 + changelogs/drizzle-orm/0.36.1.md | 6 + drizzle-kit/.gitignore | 1 + drizzle-kit/imports-checker/analyze.ts | 78 ++ drizzle-kit/imports-checker/checker.ts | 296 +++++++ .../imports-checker/grammar/grammar.ohm | 121 +++ .../grammar/grammar.ohm-bundle.d.ts | 164 ++++ .../grammar/grammar.ohm-bundle.js | 753 ++++++++++++++++++ drizzle-kit/imports-checker/index.ts | 48 ++ drizzle-kit/package.json | 7 +- drizzle-kit/src/@types/utils.ts | 1 + drizzle-kit/src/api.ts | 9 +- drizzle-kit/src/cli/commands/push.ts | 8 +- drizzle-kit/src/cli/commands/utils.ts | 14 +- drizzle-kit/src/cli/schema.ts | 3 +- drizzle-kit/src/cli/validations/outputs.ts | 2 +- .../extensions/getTablesFilterByExtensions.ts | 16 + drizzle-kit/src/introspect-mysql.ts | 84 +- drizzle-kit/src/introspect-pg.ts | 42 +- drizzle-kit/src/introspect-sqlite.ts | 4 +- drizzle-kit/src/jsonStatements.ts | 31 +- drizzle-kit/src/serializer/mysqlSerializer.ts | 28 +- drizzle-kit/src/serializer/pgSchema.ts | 6 +- drizzle-kit/src/serializer/pgSerializer.ts | 16 +- .../src/serializer/sqliteSerializer.ts | 4 +- drizzle-kit/src/snapshotsDiffer.ts | 18 +- drizzle-kit/src/sqlgenerator.ts | 139 ++-- drizzle-kit/src/utils.ts | 10 + drizzle-kit/tests/bin.test.ts | 58 ++ drizzle-kit/tests/indexes/pg.test.ts | 4 +- drizzle-kit/tests/introspect/mysql.test.ts | 113 ++- drizzle-kit/tests/introspect/pg.test.ts | 27 + drizzle-kit/tests/introspect/sqlite.test.ts | 19 + drizzle-kit/tests/mysql.test.ts | 102 +++ drizzle-kit/tests/pg-columns.test.ts | 28 +- drizzle-kit/tests/pg-enums.test.ts | 73 +- drizzle-kit/tests/pg-tables.test.ts | 100 +++ drizzle-kit/tests/push/common.ts | 10 +- drizzle-kit/tests/push/mysql.test.ts | 91 ++- drizzle-kit/tests/push/pg.test.ts | 159 ++++ drizzle-kit/tests/push/sqlite.test.ts | 77 ++ drizzle-kit/tests/sqlite-columns.test.ts | 22 + drizzle-kit/tests/sqlite-tables.test.ts | 44 + drizzle-orm/package.json | 4 +- drizzle-orm/src/mysql-core/columns/decimal.ts | 20 +- drizzle-orm/src/mysql-core/columns/double.ts | 15 +- drizzle-orm/src/mysql-core/columns/float.ts | 45 +- .../src/mysql-core/query-builders/select.ts | 6 +- drizzle-orm/src/sqlite-core/columns/blob.ts | 8 +- drizzle-orm/src/supabase/rls.ts | 9 +- drizzle-orm/type-tests/mysql/tables.ts | 6 + integration-tests/tests/bun/sqlite.test.ts | 56 +- integration-tests/tests/mysql/mysql-common.ts | 67 +- integration-tests/tests/pg/pg-common.ts | 47 ++ .../tests/sqlite/sqlite-common.ts | 62 ++ pnpm-lock.yaml | 199 ++--- 56 files changed, 2993 insertions(+), 415 deletions(-) create mode 100644 changelogs/drizzle-kit/0.28.0.md create mode 100644 changelogs/drizzle-orm/0.36.1.md create mode 100644 drizzle-kit/imports-checker/analyze.ts create mode 100644 drizzle-kit/imports-checker/checker.ts create mode 100644 drizzle-kit/imports-checker/grammar/grammar.ohm create mode 100644 drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts create mode 100644 drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js create mode 100644 drizzle-kit/imports-checker/index.ts create mode 100644 drizzle-kit/src/extensions/getTablesFilterByExtensions.ts create mode 100644 drizzle-kit/tests/bin.test.ts diff --git a/changelogs/drizzle-kit/0.28.0.md b/changelogs/drizzle-kit/0.28.0.md new file mode 100644 index 000000000..6881c677e --- /dev/null +++ b/changelogs/drizzle-kit/0.28.0.md @@ -0,0 +1,28 @@ +# Improvements + +- Added an OHM static imports checker to identify unexpected imports within a chain of imports in the drizzle-kit repo. For example, it checks if drizzle-orm is imported before drizzle-kit and verifies if the drizzle-orm import is available in your project. +- [Adding more columns to Supabase auth.users table schema](https://github.com/drizzle-team/drizzle-orm/issues/3327) - thanks @nicholasdly + +# Bug Fixes + +- [[BUG]: [drizzle-kit]: Fix breakpoints option cannot be disabled](https://github.com/drizzle-team/drizzle-orm/issues/2828) - thanks @klotztech +- [[BUG]: drizzle-kit introspect: SMALLINT import missing and incorrect DECIMAL UNSIGNED handling](https://github.com/drizzle-team/drizzle-orm/issues/2950) - thanks @L-Mario564 +- [Unsigned tinyints preventing migrations](https://github.com/drizzle-team/drizzle-orm/issues/1571) - thanks @L-Mario564 +- [[BUG]: Can't parse float(8,2) from database (precision and scale and/or unsigned breaks float types)](https://github.com/drizzle-team/drizzle-orm/issues/3285) - thanks @L-Mario564 +- [[BUG]: PgEnum generated migration doesn't escape single quotes](https://github.com/drizzle-team/drizzle-orm/issues/1272) - thanks @L-Mario564 +- [[BUG]: single quote not escaped correctly in migration file](https://github.com/drizzle-team/drizzle-orm/issues/2184) - thanks @L-Mario564 +- [[BUG]: Migrations does not escape single quotes](https://github.com/drizzle-team/drizzle-orm/issues/1765) - thanks @L-Mario564 +- [[BUG]: Issue with quoted default string values](https://github.com/drizzle-team/drizzle-orm/issues/2122) - thanks @L-Mario564 +- [[BUG]: SQl commands in wrong roder](https://github.com/drizzle-team/drizzle-orm/issues/2390) - thanks @L-Mario564 +- [[BUG]: Time with precision in drizzle-orm/pg-core adds double-quotes around type](https://github.com/drizzle-team/drizzle-orm/issues/1804) - thanks @L-Mario564 +- [[BUG]: Postgres push fails due to lack of quotes](https://github.com/drizzle-team/drizzle-orm/issues/2396) - thanks @L-Mario564 +- [[BUG]: TypeError: Cannot read properties of undefined (reading 'compositePrimaryKeys')](https://github.com/drizzle-team/drizzle-orm/issues/2344) - thanks @L-Mario564 +- [[BUG]: drizzle-kit introspect generates CURRENT_TIMESTAMP without sql operator on date column](https://github.com/drizzle-team/drizzle-orm/issues/2899) - thanks @L-Mario564 +- [[BUG]: Drizzle-kit introspect doesn't pull correct defautl statement](https://github.com/drizzle-team/drizzle-orm/issues/2905) - thanks @L-Mario564 +- [[BUG]: Problem on MacBook - This statement does not return data. Use run() instead](https://github.com/drizzle-team/drizzle-orm/issues/2623) - thanks @L-Mario564 +- [[BUG]: Enum column names that are used as arrays are not quoted](https://github.com/drizzle-team/drizzle-orm/issues/2598) - thanks @L-Mario564 +- [[BUG]: drizzle-kit generate ignores index operators](https://github.com/drizzle-team/drizzle-orm/issues/2935) - thanks @L-Mario564 +- [dialect param config error message is wrong](https://github.com/drizzle-team/drizzle-orm/issues/3427) - thanks @L-Mario564 +- [[BUG]: Error setting default enum field values](https://github.com/drizzle-team/drizzle-orm/issues/2299) - thanks @L-Mario564 +- [[BUG]: drizzle-kit does not respect the order of columns configured in primaryKey()](https://github.com/drizzle-team/drizzle-orm/issues/2326) - thanks @L-Mario564 +- [[BUG]: Cannot drop Unique Constraint MySQL](https://github.com/drizzle-team/drizzle-orm/issues/998) - thanks @L-Mario564 diff --git a/changelogs/drizzle-orm/0.36.1.md b/changelogs/drizzle-orm/0.36.1.md new file mode 100644 index 000000000..1c0e96756 --- /dev/null +++ b/changelogs/drizzle-orm/0.36.1.md @@ -0,0 +1,6 @@ +# Bug Fixes + +- [[BUG]: Using sql.placeholder with limit and/or offset for a prepared statement produces TS error](https://github.com/drizzle-team/drizzle-orm/issues/2146) - thanks @L-Mario564 +- [[BUG] If a query I am trying to modify with a dynamic query (....$dynamic()) contains any placeholders, I'm getting an error that says No value for placeholder.... provided](https://github.com/drizzle-team/drizzle-orm/issues/2272) - thanks @L-Mario564 +- [[BUG]: Error thrown when trying to insert an array of new rows using generatedAlwaysAsIdentity() for the id column](https://github.com/drizzle-team/drizzle-orm/issues/2849) - thanks @L-Mario564 +- [[BUG]: Unable to Use BigInt Types with Bun and Drizzle](https://github.com/drizzle-team/drizzle-orm/issues/2603) - thanks @L-Mario564 \ No newline at end of file diff --git a/drizzle-kit/.gitignore b/drizzle-kit/.gitignore index 6269daaf5..4916f095a 100644 --- a/drizzle-kit/.gitignore +++ b/drizzle-kit/.gitignore @@ -2,6 +2,7 @@ **/.DS_Store !src +!imports-checker !tests !vitest.config.ts !README.md diff --git a/drizzle-kit/imports-checker/analyze.ts b/drizzle-kit/imports-checker/analyze.ts new file mode 100644 index 000000000..b31686e16 --- /dev/null +++ b/drizzle-kit/imports-checker/analyze.ts @@ -0,0 +1,78 @@ +import { readFileSync } from 'fs'; +import type { Node } from 'ohm-js'; +import JSImports from './grammar/grammar.ohm-bundle'; + +export type CollectionItem = { + type: 'data' | 'types'; + source: string; +}; + +function recursiveRun(...args: Node[]): boolean { + for (const arg of args) { + if ( + arg.ctorName === 'Rest' + || arg.ctorName === 'comment' + || arg.ctorName === 'stringLiteral' + ) { + continue; + } + + if ( + arg.ctorName === 'ImportExpr_From' + || arg.ctorName === 'ImportExpr_NoFrom' + ) { + arg['analyze'](); + + continue; + } + + if (arg.isTerminal()) continue; + + for (const c of arg.children) { + if (!recursiveRun(c)) return false; + } + } + + return true; +} +function init(collection: CollectionItem[]) { + const semantics = JSImports.createSemantics(); + + semantics.addOperation('analyze', { + JSImports(arg0, arg1) { + recursiveRun(arg0, arg1); + }, + + ImportExpr_From(kImport, importInner, kFrom, importSource) { + const ruleName = importInner.children[0]!.ctorName; + const importType = ruleName === 'ImportInner_Type' || ruleName === 'ImportInner_Types' + ? 'types' + : 'data'; + + collection.push({ + source: importSource.children[1]!.sourceString!, + type: importType, + }); + }, + + ImportExpr_NoFrom(kImport, importSource) { + collection.push({ + source: importSource.children[1]!.sourceString!, + type: 'data', + }); + }, + }); + + return semantics; +} + +export function analyze(path: string) { + const file = readFileSync(path).toString(); + const match = JSImports.match(file, 'JSImports'); + + if (match.failed()) throw new Error(`Failed to parse file: ${path}`); + const collection: CollectionItem[] = []; + + init(collection)(match)['analyze'](); + return collection; +} diff --git a/drizzle-kit/imports-checker/checker.ts b/drizzle-kit/imports-checker/checker.ts new file mode 100644 index 000000000..d8fc4b219 --- /dev/null +++ b/drizzle-kit/imports-checker/checker.ts @@ -0,0 +1,296 @@ +import fs from 'fs'; +import m from 'micromatch'; +import { dirname, join as joinPath, relative, resolve as resolvePath } from 'path'; +import { analyze } from './analyze'; + +type External = { + file: string; + import: string; + type: 'data' | 'types'; +}; + +export type Issue = { + file: string; + imports: IssueImport[]; + accessChains: ChainLink[][]; +}; + +export type IssueImport = { + name: string; + type: 'data' | 'types'; +}; + +export type ChainLink = { + file: string; + import: string; +}; + +type ListMode = 'whitelist' | 'blacklist'; + +class ImportAnalyzer { + private localImportRegex = /^(\.?\.?\/|\.\.?$)/; + private importedFileFormatRegex = /^.*\.(ts|tsx|mts|cts|js|jsx|mjs|cjs|json)$/i; + + private visited: Set = new Set(); + + private externals: External[] = []; + private accessChains: Record = {}; + + constructor( + private basePath: string, + private entry: string, + private listMode: ListMode, + private readonly wantedList: string[], + private localPaths: string[], + private logger?: boolean, + private ignoreTypes?: boolean, + ) {} + + private isDirectory = (path: string) => { + try { + return fs.lstatSync(path).isDirectory(); + } catch (e) { + return false; + } + }; + + private isFile = (path: string) => { + try { + return fs.lstatSync(path).isFile(); + } catch (e) { + return false; + } + }; + + private localizePath = (path: string) => relative(resolvePath(this.basePath), resolvePath(path)); + + private isCustomLocal = (importTarget: string) => + !!this.localPaths.find( + (l) => + importTarget === l + || importTarget.startsWith(l.endsWith('/') ? l : `${l}/`), + ); + private isLocal = (importTarget: string) => + this.localImportRegex.test(importTarget) + || this.isCustomLocal(importTarget); + private isTsFormat = (path: string) => this.importedFileFormatRegex.test(path); + + private resolveCustomLocalPath = ( + absoluteBase: string, + base: string, + target: string, + ): string => { + return joinPath(absoluteBase, target); + }; + + private resolveTargetFile = (path: string): string => { + if (this.isFile(path)) return path; + + const formats = [ + '.ts', + '.mts', + '.cts', + '.tsx', + '.js', + '.mjs', + '.cjs', + '.jsx', + ]; + + for (const format of formats) { + const indexPath = joinPath(path, `/index${format}`); + if (this.isFile(indexPath)) return indexPath; + + const formatFilePath = `${path}${format}`; + if (this.isFile(formatFilePath)) return formatFilePath; + } + + return path; + }; + + private resolveTargetPath = ( + absoluteBase: string, + base: string, + target: string, + ): string => { + if (this.isCustomLocal(target)) { + return this.resolveTargetFile( + this.resolveCustomLocalPath(absoluteBase, base, target), + ); + } + + const dir = this.isDirectory(base) ? base : dirname(base); + const joined = joinPath(dir, target); + + return this.resolveTargetFile(joined); + }; + + private _analyzeImports = ( + target: string = this.entry, + basePath: string = this.basePath, + accessChain: ChainLink[] = [], + ) => { + if (this.visited.has(target)) return; + + const locals: string[] = []; + + try { + if (this.logger) console.log(`${this.localizePath(target)}`); + + const imports = analyze(target); + + for (const { source: i, type } of imports) { + if (this.ignoreTypes && type === 'types') continue; + + if (this.isLocal(i)) { + locals.push(i); + + continue; + } + + this.externals.push({ + file: this.localizePath(target), + import: i, + type: type, + }); + } + } catch (e) { + throw e; + } finally { + this.visited.add(target); + } + + for (const local of locals) { + const transformedTarget = this.resolveTargetPath(basePath, target, local); + + const localChain = [ + ...accessChain, + { + file: this.localizePath(target), + import: local, + }, + ]; + + const localized = this.localizePath(transformedTarget); + + if (this.accessChains[localized]) { + this.accessChains[localized].push(localChain); + } else this.accessChains[localized] = [localChain]; + + if (this.isTsFormat(transformedTarget)) { + this._analyzeImports(transformedTarget, basePath, localChain); + } else { + throw new Error(`unrecognized: ${localized}`); + } + } + }; + + public analyzeImports = () => { + const entryLocalized = this.localizePath(this.entry); + if (!this.accessChains[entryLocalized]) { + this.accessChains[entryLocalized] = [[]]; + } + + this._analyzeImports(); + + const rawIssues = this.listMode === 'whitelist' + ? this.externals.filter((e) => !m([e.import], this.wantedList).length) + : this.externals.filter((e) => m([e.import], this.wantedList).length); + + const issueMap: Record = {}; + for (const { file, import: i, type } of rawIssues) { + if (issueMap[file]) { + issueMap[file].imports.push({ + name: i, + type, + }); + + continue; + } + + issueMap[file] = { + file, + imports: [ + { + name: i, + type, + }, + ], + accessChains: this.accessChains[file]!, + }; + } + + return { + issues: Object.entries(issueMap).map(([file, data]) => { + for (const chain of data.accessChains) { + chain.push({ + file, + import: '', + }); + } + + return data; + }), + accessChains: this.accessChains, + }; + }; +} + +export type CustomLocalPathResolver = ( + basePath: string, + path: string, + target: string, +) => string; + +export type AnalyzeImportsConfig = + & { + basePath: string; + entry: string; + logger?: boolean; + ignoreTypes?: boolean; + localPaths?: string[]; + } + & ( + | { + blackList: string[]; + } + | { + whiteList: string[]; + } + ); + +type AnyAnalyzeImportsConfig = { + basePath: string; + entry: string; + blackList?: string[]; + whiteList?: string[]; + logger?: boolean; + ignoreTypes?: boolean; + localPaths?: string[]; +}; + +export function analyzeImports(cfg: AnalyzeImportsConfig) { + const { + basePath, + blackList, + whiteList, + entry, + localPaths: localImports, + ignoreTypes, + logger, + } = cfg as AnyAnalyzeImportsConfig; + const mode = whiteList ? 'whitelist' : 'blacklist'; + const wantedList = blackList ?? whiteList!; + + const analyzer = new ImportAnalyzer( + joinPath(basePath), + joinPath(entry), + mode, + wantedList, + localImports ?? [], + logger, + ignoreTypes, + ); + + return analyzer.analyzeImports(); +} diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm b/drizzle-kit/imports-checker/grammar/grammar.ohm new file mode 100644 index 000000000..de1459942 --- /dev/null +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm @@ -0,0 +1,121 @@ +JSImports { + JSImports = (Expr ";"?)* + + Expr = + | comment + | stringLiteral + | ImportExpr + | Rest + + ImportExpr = + | "import" ImportInner "from" importSource -- From + | "import" importSource -- NoFrom + + Rest = (~(ImportExpr | comment | stringLiteral) any)+ + + ImportInner = + | ("type" "{" NonemptyListOf ","? "}") -- Type + | ("{" NonemptyListOf ","? "}") -- Types + | ("{" NonemptyListOf ","? "}") -- Extended + | (identifier ("," "type"? "{" NonemptyListOf ","? "}")?) -- Mixed + | ("*" ("as" identifier)?) -- All + | (identifier ("as" identifier)?) -- Default + + + ImportExtendedSelection = TypeImport | Import + ImportExtendedSelectionTypes = TypeImport + ImportExtendedSelectionTypeless = Import + + Import = identifier ("as" identifier)? + TypeImport = "type" Import ("as" identifier)? + + identifier = letter alnum* + quote = "\"" | "'" | "`" + notQuote = ~quote any + importSource = + | "\"" notQuote+ "\"" + | "'" notQuote+ "'" + | "`" notQuote+ "`" + + lineTerminator = "\n" | "\r" | "\u2028" | "\u2029" + lineTerminatorSequence = "\n" | "\r" ~"\n" | "\u2028" | "\u2029" | "\r\n" + + comment = multiLineComment | singleLineComment + + multiLineComment = "/*" (~"*/" any)* "*/" + singleLineComment = "//" (~lineTerminator any)* + + stringLiteral = + | "\"" doubleStringCharacter* "\"" + | "'" singleStringCharacter* "'" + | "`" templateStringCharacter* "`" + doubleStringCharacter = + | ~("\"" | "\\" | lineTerminator) any -- NonEscaped + | "\\" escapeSequence -- Escaped + | lineContinuation -- LineContinuation + singleStringCharacter = + | ~("'" | "\\" | lineTerminator) any -- NonEscaped + | "\\" escapeSequence -- Escaped + | lineContinuation -- LineContinuation + templateStringCharacter = + | ~ ("`" | "\\") any -- NonEscaped + | "\\" escapeSequence -- Escaped + lineContinuation = "\\" lineTerminatorSequence + escapeSequence = unicodeEscapeSequence | hexEscapeSequence | octalEscapeSequence | characterEscapeSequence + characterEscapeSequence = singleEscapeCharacter | nonEscapeCharacter + singleEscapeCharacter = "'" | "\"" | "\\" | "b" | "f" | "n" | "r" | "t" | "v" + nonEscapeCharacter = ~(escapeCharacter | lineTerminator) any + escapeCharacter = singleEscapeCharacter | decimalDigit | "x" | "u" + octalEscapeSequence = + | zeroToThree octalDigit octalDigit -- Whole + | fourToSeven octalDigit -- EightTimesfourToSeven + | zeroToThree octalDigit ~decimalDigit -- EightTimesZeroToThree + | octalDigit ~decimalDigit -- Octal + hexEscapeSequence = "x" hexDigit hexDigit + unicodeEscapeSequence = "u" hexDigit hexDigit hexDigit hexDigit + + zeroToThree = "0".."3" + fourToSeven = "4".."7" + decimalDigit = "0".."9" + nonZeroDigit = "1".."9" + octalDigit = "0".."7" + + regularExpressionLiteral = "/" regularExpressionBody "/" regularExpressionFlags + regularExpressionBody = regularExpressionFirstChar regularExpressionChar* + regularExpressionFirstChar = + | ~("*" | "\\" | "/" | "[") regularExpressionNonTerminator + | regularExpressionBackslashSequence + | regularExpressionClass + regularExpressionChar = ~("\\" | "/" | "[") regularExpressionNonTerminator + | regularExpressionBackslashSequence + | regularExpressionClass + regularExpressionBackslashSequence = "\\" regularExpressionNonTerminator + regularExpressionNonTerminator = ~(lineTerminator) any + regularExpressionClass = "[" regularExpressionClassChar* "]" + regularExpressionClassChar = + | ~("]" | "\\") regularExpressionNonTerminator + | regularExpressionBackslashSequence + regularExpressionFlags = identifierPart* + + multiLineCommentNoNL = "/*" (~("*/" | lineTerminator) any)* "*/" + + identifierStart = + | letter | "$" | "_" + | "\\" unicodeEscapeSequence -- escaped + identifierPart = + | identifierStart | unicodeCombiningMark + | unicodeDigit | unicodeConnectorPunctuation + | "\u200C" | "\u200D" + letter += unicodeCategoryNl + unicodeCategoryNl + = "\u2160".."\u2182" | "\u3007" | "\u3021".."\u3029" + unicodeDigit (a digit) + = "\u0030".."\u0039" | "\u0660".."\u0669" | "\u06F0".."\u06F9" | "\u0966".."\u096F" | "\u09E6".."\u09EF" | "\u0A66".."\u0A6F" | "\u0AE6".."\u0AEF" | "\u0B66".."\u0B6F" | "\u0BE7".."\u0BEF" | "\u0C66".."\u0C6F" | "\u0CE6".."\u0CEF" | "\u0D66".."\u0D6F" | "\u0E50".."\u0E59" | "\u0ED0".."\u0ED9" | "\u0F20".."\u0F29" | "\uFF10".."\uFF19" + + unicodeCombiningMark (a Unicode combining mark) + = "\u0300".."\u0345" | "\u0360".."\u0361" | "\u0483".."\u0486" | "\u0591".."\u05A1" | "\u05A3".."\u05B9" | "\u05BB".."\u05BD" | "\u05BF".."\u05BF" | "\u05C1".."\u05C2" | "\u05C4".."\u05C4" | "\u064B".."\u0652" | "\u0670".."\u0670" | "\u06D6".."\u06DC" | "\u06DF".."\u06E4" | "\u06E7".."\u06E8" | "\u06EA".."\u06ED" | "\u0901".."\u0902" | "\u093C".."\u093C" | "\u0941".."\u0948" | "\u094D".."\u094D" | "\u0951".."\u0954" | "\u0962".."\u0963" | "\u0981".."\u0981" | "\u09BC".."\u09BC" | "\u09C1".."\u09C4" | "\u09CD".."\u09CD" | "\u09E2".."\u09E3" | "\u0A02".."\u0A02" | "\u0A3C".."\u0A3C" | "\u0A41".."\u0A42" | "\u0A47".."\u0A48" | "\u0A4B".."\u0A4D" | "\u0A70".."\u0A71" | "\u0A81".."\u0A82" | "\u0ABC".."\u0ABC" | "\u0AC1".."\u0AC5" | "\u0AC7".."\u0AC8" | "\u0ACD".."\u0ACD" | "\u0B01".."\u0B01" | "\u0B3C".."\u0B3C" | "\u0B3F".."\u0B3F" | "\u0B41".."\u0B43" | "\u0B4D".."\u0B4D" | "\u0B56".."\u0B56" | "\u0B82".."\u0B82" | "\u0BC0".."\u0BC0" | "\u0BCD".."\u0BCD" | "\u0C3E".."\u0C40" | "\u0C46".."\u0C48" | "\u0C4A".."\u0C4D" | "\u0C55".."\u0C56" | "\u0CBF".."\u0CBF" | "\u0CC6".."\u0CC6" | "\u0CCC".."\u0CCD" | "\u0D41".."\u0D43" | "\u0D4D".."\u0D4D" | "\u0E31".."\u0E31" | "\u0E34".."\u0E3A" | "\u0E47".."\u0E4E" | "\u0EB1".."\u0EB1" | "\u0EB4".."\u0EB9" | "\u0EBB".."\u0EBC" | "\u0EC8".."\u0ECD" | "\u0F18".."\u0F19" | "\u0F35".."\u0F35" | "\u0F37".."\u0F37" | "\u0F39".."\u0F39" | "\u0F71".."\u0F7E" | "\u0F80".."\u0F84" | "\u0F86".."\u0F87" | "\u0F90".."\u0F95" | "\u0F97".."\u0F97" | "\u0F99".."\u0FAD" | "\u0FB1".."\u0FB7" | "\u0FB9".."\u0FB9" | "\u20D0".."\u20DC" | "\u20E1".."\u20E1" | "\u302A".."\u302F" | "\u3099".."\u309A" | "\uFB1E".."\uFB1E" | "\uFE20".."\uFE23" + + unicodeConnectorPunctuation = "\u005F" | "\u203F".."\u2040" | "\u30FB" | "\uFE33".."\uFE34" | "\uFE4D".."\uFE4F" | "\uFF3F" | "\uFF65" + unicodeSpaceSeparator = "\u2000".."\u200B" | "\u3000" + +} \ No newline at end of file diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts new file mode 100644 index 000000000..64b5dfb78 --- /dev/null +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts @@ -0,0 +1,164 @@ +// AUTOGENERATED FILE +// This file was generated from grammar.ohm by `ohm generateBundles`. + +import { BaseActionDict, Grammar, IterationNode, Node, NonterminalNode, Semantics, TerminalNode } from 'ohm-js'; + +export interface JSImportsActionDict extends BaseActionDict { + JSImports?: (this: NonterminalNode, arg0: IterationNode, arg1: IterationNode) => T; + Expr?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExpr_From?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: TerminalNode, + arg3: NonterminalNode, + ) => T; + ImportExpr_NoFrom?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + ImportExpr?: (this: NonterminalNode, arg0: NonterminalNode) => T; + Rest?: (this: NonterminalNode, arg0: IterationNode) => T; + ImportInner_Type?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: TerminalNode, + arg2: NonterminalNode, + arg3: IterationNode, + arg4: TerminalNode, + ) => T; + ImportInner_Types?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: IterationNode, + arg3: TerminalNode, + ) => T; + ImportInner_Extended?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: IterationNode, + arg3: TerminalNode, + ) => T; + ImportInner_Mixed?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: IterationNode, + arg2: IterationNode, + arg3: IterationNode, + arg4: IterationNode, + arg5: IterationNode, + arg6: IterationNode, + ) => T; + ImportInner_All?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: IterationNode) => T; + ImportInner_Default?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode) => T; + ImportInner?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelection?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelectionTypes?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelectionTypeless?: (this: NonterminalNode, arg0: NonterminalNode) => T; + Import?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode) => T; + TypeImport?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: IterationNode, + arg3: IterationNode, + ) => T; + identifier?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T; + quote?: (this: NonterminalNode, arg0: TerminalNode) => T; + notQuote?: (this: NonterminalNode, arg0: NonterminalNode) => T; + importSource?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + lineTerminator?: (this: NonterminalNode, arg0: TerminalNode) => T; + lineTerminatorSequence?: (this: NonterminalNode, arg0: TerminalNode) => T; + comment?: (this: NonterminalNode, arg0: NonterminalNode) => T; + multiLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + singleLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode) => T; + stringLiteral?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + doubleStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + doubleStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + doubleStringCharacter_LineContinuation?: (this: NonterminalNode, arg0: NonterminalNode) => T; + doubleStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + singleStringCharacter_LineContinuation?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + templateStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + templateStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + templateStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + lineContinuation?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + escapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + characterEscapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleEscapeCharacter?: (this: NonterminalNode, arg0: TerminalNode) => T; + nonEscapeCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + escapeCharacter?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + octalEscapeSequence_Whole?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: NonterminalNode, + arg2: NonterminalNode, + ) => T; + octalEscapeSequence_EightTimesfourToSeven?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: NonterminalNode, + ) => T; + octalEscapeSequence_EightTimesZeroToThree?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: NonterminalNode, + ) => T; + octalEscapeSequence_Octal?: (this: NonterminalNode, arg0: NonterminalNode) => T; + octalEscapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + hexEscapeSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: NonterminalNode) => T; + unicodeEscapeSequence?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: NonterminalNode, + arg3: NonterminalNode, + arg4: NonterminalNode, + ) => T; + zeroToThree?: (this: NonterminalNode, arg0: TerminalNode) => T; + fourToSeven?: (this: NonterminalNode, arg0: TerminalNode) => T; + decimalDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + nonZeroDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + octalDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + regularExpressionLiteral?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: TerminalNode, + arg3: NonterminalNode, + ) => T; + regularExpressionBody?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T; + regularExpressionFirstChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionBackslashSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + regularExpressionNonTerminator?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionClass?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + regularExpressionClassChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionFlags?: (this: NonterminalNode, arg0: IterationNode) => T; + multiLineCommentNoNL?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + identifierStart_escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + identifierStart?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + identifierPart?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + letter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + unicodeCategoryNl?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeCombiningMark?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeConnectorPunctuation?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeSpaceSeparator?: (this: NonterminalNode, arg0: TerminalNode) => T; +} + +export interface JSImportsSemantics extends Semantics { + addOperation(name: string, actionDict: JSImportsActionDict): this; + extendOperation(name: string, actionDict: JSImportsActionDict): this; + addAttribute(name: string, actionDict: JSImportsActionDict): this; + extendAttribute(name: string, actionDict: JSImportsActionDict): this; +} + +export interface JSImportsGrammar extends Grammar { + createSemantics(): JSImportsSemantics; + extendSemantics(superSemantics: JSImportsSemantics): JSImportsSemantics; +} + +declare const grammar: JSImportsGrammar; +export default grammar; diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js new file mode 100644 index 000000000..9a889d66f --- /dev/null +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js @@ -0,0 +1,753 @@ +import { makeRecipe } from 'ohm-js'; +const result = makeRecipe([ + 'grammar', + { + source: + 'JSImports {\n JSImports = (Expr ";"?)*\n\n Expr = \n | comment\n | stringLiteral\n | ImportExpr\n | Rest\n\n ImportExpr =\n | "import" ImportInner "from" importSource -- From\n | "import" importSource -- NoFrom\n\n Rest = (~(ImportExpr | comment | stringLiteral) any)+\n\n ImportInner = \n | ("type" "{" NonemptyListOf ","? "}") -- Type\n | ("{" NonemptyListOf ","? "}") -- Types\n | ("{" NonemptyListOf ","? "}") -- Extended\n | (identifier ("," "type"? "{" NonemptyListOf ","? "}")?) -- Mixed\n | ("*" ("as" identifier)?) -- All\n | (identifier ("as" identifier)?) -- Default\n \n\n ImportExtendedSelection = TypeImport | Import\n ImportExtendedSelectionTypes = TypeImport\n ImportExtendedSelectionTypeless = Import\n\n Import = identifier ("as" identifier)?\n TypeImport = "type" Import ("as" identifier)?\n\n identifier = letter alnum*\n quote = "\\"" | "\'" | "`"\n notQuote = ~quote any\n importSource =\n | "\\"" notQuote+ "\\""\n | "\'" notQuote+ "\'"\n | "`" notQuote+ "`"\n\n lineTerminator = "\\n" | "\\r" | "\\u2028" | "\\u2029"\n lineTerminatorSequence = "\\n" | "\\r" ~"\\n" | "\\u2028" | "\\u2029" | "\\r\\n"\n \n comment = multiLineComment | singleLineComment\n\n multiLineComment = "/*" (~"*/" any)* "*/"\n singleLineComment = "//" (~lineTerminator any)*\n\n stringLiteral =\n | "\\"" doubleStringCharacter* "\\""\n | "\'" singleStringCharacter* "\'"\n | "`" templateStringCharacter* "`"\n doubleStringCharacter =\n | ~("\\"" | "\\\\" | lineTerminator) any -- NonEscaped\n | "\\\\" escapeSequence -- Escaped\n | lineContinuation -- LineContinuation\n singleStringCharacter =\n | ~("\'" | "\\\\" | lineTerminator) any -- NonEscaped\n | "\\\\" escapeSequence -- Escaped\n | lineContinuation -- LineContinuation\n templateStringCharacter = \n | ~ ("`" | "\\\\") any -- NonEscaped\n | "\\\\" escapeSequence -- Escaped\n lineContinuation = "\\\\" lineTerminatorSequence\n escapeSequence = unicodeEscapeSequence | hexEscapeSequence | octalEscapeSequence | characterEscapeSequence\n characterEscapeSequence = singleEscapeCharacter | nonEscapeCharacter\n singleEscapeCharacter = "\'" | "\\"" | "\\\\" | "b" | "f" | "n" | "r" | "t" | "v"\n nonEscapeCharacter = ~(escapeCharacter | lineTerminator) any\n escapeCharacter = singleEscapeCharacter | decimalDigit | "x" | "u"\n octalEscapeSequence =\n | zeroToThree octalDigit octalDigit -- Whole\n | fourToSeven octalDigit -- EightTimesfourToSeven\n | zeroToThree octalDigit ~decimalDigit -- EightTimesZeroToThree\n | octalDigit ~decimalDigit -- Octal\n hexEscapeSequence = "x" hexDigit hexDigit\n unicodeEscapeSequence = "u" hexDigit hexDigit hexDigit hexDigit\n\n zeroToThree = "0".."3"\n fourToSeven = "4".."7"\n decimalDigit = "0".."9"\n nonZeroDigit = "1".."9"\n octalDigit = "0".."7"\n\n regularExpressionLiteral = "/" regularExpressionBody "/" regularExpressionFlags\n regularExpressionBody = regularExpressionFirstChar regularExpressionChar*\n regularExpressionFirstChar =\n | ~("*" | "\\\\" | "/" | "[") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n | regularExpressionClass\n regularExpressionChar = ~("\\\\" | "/" | "[") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n | regularExpressionClass\n regularExpressionBackslashSequence = "\\\\" regularExpressionNonTerminator\n regularExpressionNonTerminator = ~(lineTerminator) any\n regularExpressionClass = "[" regularExpressionClassChar* "]"\n regularExpressionClassChar =\n | ~("]" | "\\\\") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n regularExpressionFlags = identifierPart*\n\n multiLineCommentNoNL = "/*" (~("*/" | lineTerminator) any)* "*/"\n\n identifierStart =\n | letter | "$" | "_"\n | "\\\\" unicodeEscapeSequence -- escaped\n identifierPart =\n | identifierStart | unicodeCombiningMark\n | unicodeDigit | unicodeConnectorPunctuation\n | "\\u200C" | "\\u200D"\n letter += unicodeCategoryNl\n unicodeCategoryNl\n = "\\u2160".."\\u2182" | "\\u3007" | "\\u3021".."\\u3029"\n unicodeDigit (a digit)\n = "\\u0030".."\\u0039" | "\\u0660".."\\u0669" | "\\u06F0".."\\u06F9" | "\\u0966".."\\u096F" | "\\u09E6".."\\u09EF" | "\\u0A66".."\\u0A6F" | "\\u0AE6".."\\u0AEF" | "\\u0B66".."\\u0B6F" | "\\u0BE7".."\\u0BEF" | "\\u0C66".."\\u0C6F" | "\\u0CE6".."\\u0CEF" | "\\u0D66".."\\u0D6F" | "\\u0E50".."\\u0E59" | "\\u0ED0".."\\u0ED9" | "\\u0F20".."\\u0F29" | "\\uFF10".."\\uFF19"\n\n unicodeCombiningMark (a Unicode combining mark)\n = "\\u0300".."\\u0345" | "\\u0360".."\\u0361" | "\\u0483".."\\u0486" | "\\u0591".."\\u05A1" | "\\u05A3".."\\u05B9" | "\\u05BB".."\\u05BD" | "\\u05BF".."\\u05BF" | "\\u05C1".."\\u05C2" | "\\u05C4".."\\u05C4" | "\\u064B".."\\u0652" | "\\u0670".."\\u0670" | "\\u06D6".."\\u06DC" | "\\u06DF".."\\u06E4" | "\\u06E7".."\\u06E8" | "\\u06EA".."\\u06ED" | "\\u0901".."\\u0902" | "\\u093C".."\\u093C" | "\\u0941".."\\u0948" | "\\u094D".."\\u094D" | "\\u0951".."\\u0954" | "\\u0962".."\\u0963" | "\\u0981".."\\u0981" | "\\u09BC".."\\u09BC" | "\\u09C1".."\\u09C4" | "\\u09CD".."\\u09CD" | "\\u09E2".."\\u09E3" | "\\u0A02".."\\u0A02" | "\\u0A3C".."\\u0A3C" | "\\u0A41".."\\u0A42" | "\\u0A47".."\\u0A48" | "\\u0A4B".."\\u0A4D" | "\\u0A70".."\\u0A71" | "\\u0A81".."\\u0A82" | "\\u0ABC".."\\u0ABC" | "\\u0AC1".."\\u0AC5" | "\\u0AC7".."\\u0AC8" | "\\u0ACD".."\\u0ACD" | "\\u0B01".."\\u0B01" | "\\u0B3C".."\\u0B3C" | "\\u0B3F".."\\u0B3F" | "\\u0B41".."\\u0B43" | "\\u0B4D".."\\u0B4D" | "\\u0B56".."\\u0B56" | "\\u0B82".."\\u0B82" | "\\u0BC0".."\\u0BC0" | "\\u0BCD".."\\u0BCD" | "\\u0C3E".."\\u0C40" | "\\u0C46".."\\u0C48" | "\\u0C4A".."\\u0C4D" | "\\u0C55".."\\u0C56" | "\\u0CBF".."\\u0CBF" | "\\u0CC6".."\\u0CC6" | "\\u0CCC".."\\u0CCD" | "\\u0D41".."\\u0D43" | "\\u0D4D".."\\u0D4D" | "\\u0E31".."\\u0E31" | "\\u0E34".."\\u0E3A" | "\\u0E47".."\\u0E4E" | "\\u0EB1".."\\u0EB1" | "\\u0EB4".."\\u0EB9" | "\\u0EBB".."\\u0EBC" | "\\u0EC8".."\\u0ECD" | "\\u0F18".."\\u0F19" | "\\u0F35".."\\u0F35" | "\\u0F37".."\\u0F37" | "\\u0F39".."\\u0F39" | "\\u0F71".."\\u0F7E" | "\\u0F80".."\\u0F84" | "\\u0F86".."\\u0F87" | "\\u0F90".."\\u0F95" | "\\u0F97".."\\u0F97" | "\\u0F99".."\\u0FAD" | "\\u0FB1".."\\u0FB7" | "\\u0FB9".."\\u0FB9" | "\\u20D0".."\\u20DC" | "\\u20E1".."\\u20E1" | "\\u302A".."\\u302F" | "\\u3099".."\\u309A" | "\\uFB1E".."\\uFB1E" | "\\uFE20".."\\uFE23"\n\n unicodeConnectorPunctuation = "\\u005F" | "\\u203F".."\\u2040" | "\\u30FB" | "\\uFE33".."\\uFE34" | "\\uFE4D".."\\uFE4F" | "\\uFF3F" | "\\uFF65"\n unicodeSpaceSeparator = "\\u2000".."\\u200B" | "\\u3000"\n\n}', + }, + 'JSImports', + null, + 'JSImports', + { + JSImports: ['define', { sourceInterval: [16, 40] }, null, [], ['star', { sourceInterval: [28, 40] }, [ + 'seq', + { sourceInterval: [29, 38] }, + ['app', { sourceInterval: [29, 33] }, 'Expr', []], + ['opt', { sourceInterval: [34, 38] }, ['terminal', { sourceInterval: [34, 37] }, ';']], + ]]], + Expr: ['define', { sourceInterval: [46, 115] }, null, [], [ + 'alt', + { sourceInterval: [58, 115] }, + ['app', { sourceInterval: [60, 67] }, 'comment', []], + ['app', { sourceInterval: [74, 87] }, 'stringLiteral', []], + ['app', { sourceInterval: [94, 104] }, 'ImportExpr', []], + ['app', { sourceInterval: [111, 115] }, 'Rest', []], + ]], + ImportExpr_From: ['define', { sourceInterval: [140, 188] }, null, [], [ + 'seq', + { sourceInterval: [140, 180] }, + ['terminal', { sourceInterval: [140, 148] }, 'import'], + ['app', { sourceInterval: [149, 160] }, 'ImportInner', []], + ['terminal', { sourceInterval: [161, 167] }, 'from'], + ['app', { sourceInterval: [168, 180] }, 'importSource', []], + ]], + ImportExpr_NoFrom: ['define', { sourceInterval: [195, 226] }, null, [], ['seq', { sourceInterval: [195, 216] }, [ + 'terminal', + { sourceInterval: [195, 203] }, + 'import', + ], ['app', { sourceInterval: [204, 216] }, 'importSource', []]]], + ImportExpr: ['define', { sourceInterval: [121, 226] }, null, [], ['alt', { sourceInterval: [138, 226] }, [ + 'app', + { sourceInterval: [140, 180] }, + 'ImportExpr_From', + [], + ], ['app', { sourceInterval: [195, 216] }, 'ImportExpr_NoFrom', []]]], + Rest: ['define', { sourceInterval: [232, 285] }, null, [], ['plus', { sourceInterval: [239, 285] }, ['seq', { + sourceInterval: [240, 283], + }, ['not', { sourceInterval: [240, 279] }, [ + 'alt', + { sourceInterval: [242, 278] }, + ['app', { sourceInterval: [242, 252] }, 'ImportExpr', []], + ['app', { sourceInterval: [255, 262] }, 'comment', []], + ['app', { sourceInterval: [265, 278] }, 'stringLiteral', []], + ]], ['app', { sourceInterval: [280, 283] }, 'any', []]]]], + ImportInner_Type: ['define', { sourceInterval: [312, 405] }, null, [], [ + 'seq', + { sourceInterval: [312, 386] }, + ['terminal', { sourceInterval: [313, 319] }, 'type'], + ['terminal', { sourceInterval: [320, 323] }, '{'], + ['app', { sourceInterval: [324, 376] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [339, 370] }, + 'ImportExtendedSelectionTypeless', + [], + ], ['terminal', { sourceInterval: [372, 375] }, ',']]], + ['opt', { sourceInterval: [377, 381] }, ['terminal', { sourceInterval: [377, 380] }, ',']], + ['terminal', { sourceInterval: [382, 385] }, '}'], + ]], + ImportInner_Types: ['define', { sourceInterval: [412, 506] }, null, [], ['seq', { sourceInterval: [412, 476] }, [ + 'terminal', + { sourceInterval: [413, 416] }, + '{', + ], ['app', { sourceInterval: [417, 466] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [432, 460] }, + 'ImportExtendedSelectionTypes', + [], + ], ['terminal', { sourceInterval: [462, 465] }, ',']]], ['opt', { sourceInterval: [467, 471] }, ['terminal', { + sourceInterval: [467, 470], + }, ',']], ['terminal', { sourceInterval: [472, 475] }, '}']]], + ImportInner_Extended: ['define', { sourceInterval: [513, 610] }, null, [], ['seq', { sourceInterval: [513, 572] }, [ + 'terminal', + { sourceInterval: [514, 517] }, + '{', + ], ['app', { sourceInterval: [518, 562] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [533, 556] }, + 'ImportExtendedSelection', + [], + ], ['terminal', { sourceInterval: [558, 561] }, ',']]], ['opt', { sourceInterval: [563, 567] }, ['terminal', { + sourceInterval: [563, 566], + }, ',']], ['terminal', { sourceInterval: [568, 571] }, '}']]], + ImportInner_Mixed: ['define', { sourceInterval: [617, 711] }, null, [], ['seq', { sourceInterval: [617, 702] }, [ + 'app', + { sourceInterval: [618, 628] }, + 'identifier', + [], + ], ['opt', { sourceInterval: [629, 701] }, [ + 'seq', + { sourceInterval: [630, 699] }, + ['terminal', { sourceInterval: [630, 633] }, ','], + ['opt', { sourceInterval: [634, 641] }, ['terminal', { sourceInterval: [634, 640] }, 'type']], + ['terminal', { sourceInterval: [642, 645] }, '{'], + ['app', { sourceInterval: [646, 690] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [661, 684] }, + 'ImportExtendedSelection', + [], + ], ['terminal', { sourceInterval: [686, 689] }, ',']]], + ['opt', { sourceInterval: [691, 695] }, ['terminal', { sourceInterval: [691, 694] }, ',']], + ['terminal', { sourceInterval: [696, 699] }, '}'], + ]]]], + ImportInner_All: ['define', { sourceInterval: [718, 810] }, null, [], ['seq', { sourceInterval: [718, 742] }, [ + 'terminal', + { sourceInterval: [719, 722] }, + '*', + ], ['opt', { sourceInterval: [723, 741] }, ['seq', { sourceInterval: [724, 739] }, ['terminal', { + sourceInterval: [724, 728], + }, 'as'], ['app', { sourceInterval: [729, 739] }, 'identifier', []]]]]], + ImportInner_Default: ['define', { sourceInterval: [817, 913] }, null, [], ['seq', { sourceInterval: [817, 848] }, [ + 'app', + { sourceInterval: [818, 828] }, + 'identifier', + [], + ], ['opt', { sourceInterval: [829, 847] }, ['seq', { sourceInterval: [830, 845] }, ['terminal', { + sourceInterval: [830, 834], + }, 'as'], ['app', { sourceInterval: [835, 845] }, 'identifier', []]]]]], + ImportInner: ['define', { sourceInterval: [291, 913] }, null, [], [ + 'alt', + { sourceInterval: [310, 913] }, + ['app', { sourceInterval: [312, 386] }, 'ImportInner_Type', []], + ['app', { sourceInterval: [412, 476] }, 'ImportInner_Types', []], + ['app', { sourceInterval: [513, 572] }, 'ImportInner_Extended', []], + ['app', { sourceInterval: [617, 702] }, 'ImportInner_Mixed', []], + ['app', { sourceInterval: [718, 742] }, 'ImportInner_All', []], + ['app', { sourceInterval: [817, 848] }, 'ImportInner_Default', []], + ]], + ImportExtendedSelection: ['define', { sourceInterval: [924, 969] }, null, [], [ + 'alt', + { sourceInterval: [950, 969] }, + ['app', { sourceInterval: [950, 960] }, 'TypeImport', []], + ['app', { sourceInterval: [963, 969] }, 'Import', []], + ]], + ImportExtendedSelectionTypes: ['define', { sourceInterval: [974, 1015] }, null, [], [ + 'app', + { sourceInterval: [1005, 1015] }, + 'TypeImport', + [], + ]], + ImportExtendedSelectionTypeless: ['define', { sourceInterval: [1020, 1060] }, null, [], [ + 'app', + { sourceInterval: [1054, 1060] }, + 'Import', + [], + ]], + Import: ['define', { sourceInterval: [1066, 1104] }, null, [], ['seq', { sourceInterval: [1075, 1104] }, [ + 'app', + { sourceInterval: [1075, 1085] }, + 'identifier', + [], + ], ['opt', { sourceInterval: [1086, 1104] }, ['seq', { sourceInterval: [1087, 1102] }, ['terminal', { + sourceInterval: [1087, 1091], + }, 'as'], ['app', { sourceInterval: [1092, 1102] }, 'identifier', []]]]]], + TypeImport: ['define', { sourceInterval: [1109, 1154] }, null, [], [ + 'seq', + { sourceInterval: [1122, 1154] }, + ['terminal', { sourceInterval: [1122, 1128] }, 'type'], + ['app', { sourceInterval: [1129, 1135] }, 'Import', []], + ['opt', { sourceInterval: [1136, 1154] }, ['seq', { sourceInterval: [1137, 1152] }, ['terminal', { + sourceInterval: [1137, 1141], + }, 'as'], ['app', { sourceInterval: [1142, 1152] }, 'identifier', []]]], + ]], + identifier: ['define', { sourceInterval: [1160, 1186] }, null, [], ['seq', { sourceInterval: [1173, 1186] }, [ + 'app', + { sourceInterval: [1173, 1179] }, + 'letter', + [], + ], ['star', { sourceInterval: [1180, 1186] }, ['app', { sourceInterval: [1180, 1185] }, 'alnum', []]]]], + quote: ['define', { sourceInterval: [1191, 1215] }, null, [], [ + 'alt', + { sourceInterval: [1199, 1215] }, + ['terminal', { sourceInterval: [1199, 1203] }, '"'], + ['terminal', { sourceInterval: [1206, 1209] }, "'"], + ['terminal', { sourceInterval: [1212, 1215] }, '`'], + ]], + notQuote: ['define', { sourceInterval: [1220, 1241] }, null, [], ['seq', { sourceInterval: [1231, 1241] }, ['not', { + sourceInterval: [1231, 1237], + }, ['app', { sourceInterval: [1232, 1237] }, 'quote', []]], ['app', { sourceInterval: [1238, 1241] }, 'any', []]]], + importSource: ['define', { sourceInterval: [1246, 1334] }, null, [], [ + 'alt', + { sourceInterval: [1265, 1334] }, + ['seq', { sourceInterval: [1267, 1286] }, ['terminal', { sourceInterval: [1267, 1271] }, '"'], ['plus', { + sourceInterval: [1272, 1281], + }, ['app', { sourceInterval: [1272, 1280] }, 'notQuote', []]], [ + 'terminal', + { sourceInterval: [1282, 1286] }, + '"', + ]], + ['seq', { sourceInterval: [1293, 1310] }, ['terminal', { sourceInterval: [1293, 1296] }, "'"], ['plus', { + sourceInterval: [1297, 1306], + }, ['app', { sourceInterval: [1297, 1305] }, 'notQuote', []]], [ + 'terminal', + { sourceInterval: [1307, 1310] }, + "'", + ]], + ['seq', { sourceInterval: [1317, 1334] }, ['terminal', { sourceInterval: [1317, 1320] }, '`'], ['plus', { + sourceInterval: [1321, 1330], + }, ['app', { sourceInterval: [1321, 1329] }, 'notQuote', []]], [ + 'terminal', + { sourceInterval: [1331, 1334] }, + '`', + ]], + ]], + lineTerminator: ['define', { sourceInterval: [1340, 1390] }, null, [], [ + 'alt', + { sourceInterval: [1357, 1390] }, + ['terminal', { sourceInterval: [1357, 1361] }, '\n'], + ['terminal', { sourceInterval: [1364, 1368] }, '\r'], + ['terminal', { sourceInterval: [1371, 1379] }, '\u2028'], + ['terminal', { sourceInterval: [1382, 1390] }, '\u2029'], + ]], + lineTerminatorSequence: ['define', { sourceInterval: [1395, 1468] }, null, [], [ + 'alt', + { sourceInterval: [1420, 1468] }, + ['terminal', { sourceInterval: [1420, 1424] }, '\n'], + ['seq', { sourceInterval: [1427, 1437] }, ['terminal', { sourceInterval: [1427, 1431] }, '\r'], ['not', { + sourceInterval: [1432, 1437], + }, ['terminal', { sourceInterval: [1433, 1437] }, '\n']]], + ['terminal', { sourceInterval: [1440, 1448] }, '\u2028'], + ['terminal', { sourceInterval: [1451, 1459] }, '\u2029'], + ['terminal', { sourceInterval: [1462, 1468] }, '\r\n'], + ]], + comment: ['define', { sourceInterval: [1478, 1524] }, null, [], ['alt', { sourceInterval: [1488, 1524] }, [ + 'app', + { sourceInterval: [1488, 1504] }, + 'multiLineComment', + [], + ], ['app', { sourceInterval: [1507, 1524] }, 'singleLineComment', []]]], + multiLineComment: ['define', { sourceInterval: [1530, 1571] }, null, [], ['seq', { sourceInterval: [1549, 1571] }, [ + 'terminal', + { sourceInterval: [1549, 1553] }, + '/*', + ], ['star', { sourceInterval: [1554, 1566] }, ['seq', { sourceInterval: [1555, 1564] }, ['not', { + sourceInterval: [1555, 1560], + }, ['terminal', { sourceInterval: [1556, 1560] }, '*/']], ['app', { sourceInterval: [1561, 1564] }, 'any', []]]], [ + 'terminal', + { sourceInterval: [1567, 1571] }, + '*/', + ]]], + singleLineComment: ['define', { sourceInterval: [1576, 1623] }, null, [], [ + 'seq', + { sourceInterval: [1596, 1623] }, + ['terminal', { sourceInterval: [1596, 1600] }, '//'], + ['star', { sourceInterval: [1601, 1623] }, ['seq', { sourceInterval: [1602, 1621] }, ['not', { + sourceInterval: [1602, 1617], + }, ['app', { sourceInterval: [1603, 1617] }, 'lineTerminator', []]], [ + 'app', + { sourceInterval: [1618, 1621] }, + 'any', + [], + ]]], + ]], + stringLiteral: ['define', { sourceInterval: [1629, 1759] }, null, [], ['alt', { sourceInterval: [1649, 1759] }, [ + 'seq', + { sourceInterval: [1651, 1683] }, + ['terminal', { sourceInterval: [1651, 1655] }, '"'], + ['star', { sourceInterval: [1656, 1678] }, [ + 'app', + { sourceInterval: [1656, 1677] }, + 'doubleStringCharacter', + [], + ]], + ['terminal', { sourceInterval: [1679, 1683] }, '"'], + ], ['seq', { sourceInterval: [1690, 1720] }, ['terminal', { sourceInterval: [1690, 1693] }, "'"], ['star', { + sourceInterval: [1694, 1716], + }, ['app', { sourceInterval: [1694, 1715] }, 'singleStringCharacter', []]], ['terminal', { + sourceInterval: [1717, 1720], + }, "'"]], ['seq', { sourceInterval: [1727, 1759] }, ['terminal', { sourceInterval: [1727, 1730] }, '`'], ['star', { + sourceInterval: [1731, 1755], + }, ['app', { sourceInterval: [1731, 1754] }, 'templateStringCharacter', []]], ['terminal', { + sourceInterval: [1756, 1759], + }, '`']]]], + doubleStringCharacter_NonEscaped: ['define', { sourceInterval: [1794, 1845] }, null, [], ['seq', { + sourceInterval: [1794, 1829], + }, ['not', { sourceInterval: [1794, 1825] }, [ + 'alt', + { sourceInterval: [1796, 1824] }, + ['terminal', { sourceInterval: [1796, 1800] }, '"'], + ['terminal', { sourceInterval: [1803, 1807] }, '\\'], + ['app', { sourceInterval: [1810, 1824] }, 'lineTerminator', []], + ]], ['app', { sourceInterval: [1826, 1829] }, 'any', []]]], + doubleStringCharacter_Escaped: ['define', { sourceInterval: [1852, 1900] }, null, [], [ + 'seq', + { sourceInterval: [1852, 1871] }, + ['terminal', { sourceInterval: [1852, 1856] }, '\\'], + ['app', { sourceInterval: [1857, 1871] }, 'escapeSequence', []], + ]], + doubleStringCharacter_LineContinuation: ['define', { sourceInterval: [1907, 1964] }, null, [], [ + 'app', + { sourceInterval: [1907, 1923] }, + 'lineContinuation', + [], + ]], + doubleStringCharacter: ['define', { sourceInterval: [1764, 1964] }, null, [], [ + 'alt', + { sourceInterval: [1792, 1964] }, + ['app', { sourceInterval: [1794, 1829] }, 'doubleStringCharacter_NonEscaped', []], + ['app', { sourceInterval: [1852, 1871] }, 'doubleStringCharacter_Escaped', []], + ['app', { sourceInterval: [1907, 1923] }, 'doubleStringCharacter_LineContinuation', []], + ]], + singleStringCharacter_NonEscaped: ['define', { sourceInterval: [1999, 2050] }, null, [], ['seq', { + sourceInterval: [1999, 2033], + }, ['not', { sourceInterval: [1999, 2029] }, [ + 'alt', + { sourceInterval: [2001, 2028] }, + ['terminal', { sourceInterval: [2001, 2004] }, "'"], + ['terminal', { sourceInterval: [2007, 2011] }, '\\'], + ['app', { sourceInterval: [2014, 2028] }, 'lineTerminator', []], + ]], ['app', { sourceInterval: [2030, 2033] }, 'any', []]]], + singleStringCharacter_Escaped: ['define', { sourceInterval: [2057, 2105] }, null, [], [ + 'seq', + { sourceInterval: [2057, 2076] }, + ['terminal', { sourceInterval: [2057, 2061] }, '\\'], + ['app', { sourceInterval: [2062, 2076] }, 'escapeSequence', []], + ]], + singleStringCharacter_LineContinuation: ['define', { sourceInterval: [2112, 2169] }, null, [], [ + 'app', + { sourceInterval: [2112, 2128] }, + 'lineContinuation', + [], + ]], + singleStringCharacter: ['define', { sourceInterval: [1969, 2169] }, null, [], [ + 'alt', + { sourceInterval: [1997, 2169] }, + ['app', { sourceInterval: [1999, 2033] }, 'singleStringCharacter_NonEscaped', []], + ['app', { sourceInterval: [2057, 2076] }, 'singleStringCharacter_Escaped', []], + ['app', { sourceInterval: [2112, 2128] }, 'singleStringCharacter_LineContinuation', []], + ]], + templateStringCharacter_NonEscaped: ['define', { sourceInterval: [2207, 2258] }, null, [], ['seq', { + sourceInterval: [2207, 2225], + }, ['not', { sourceInterval: [2207, 2221] }, ['alt', { sourceInterval: [2210, 2220] }, ['terminal', { + sourceInterval: [2210, 2213], + }, '`'], ['terminal', { sourceInterval: [2216, 2220] }, '\\']]], [ + 'app', + { sourceInterval: [2222, 2225] }, + 'any', + [], + ]]], + templateStringCharacter_Escaped: ['define', { sourceInterval: [2265, 2318] }, null, [], [ + 'seq', + { sourceInterval: [2265, 2284] }, + ['terminal', { sourceInterval: [2265, 2269] }, '\\'], + ['app', { sourceInterval: [2270, 2284] }, 'escapeSequence', []], + ]], + templateStringCharacter: ['define', { sourceInterval: [2174, 2318] }, null, [], [ + 'alt', + { sourceInterval: [2205, 2318] }, + ['app', { sourceInterval: [2207, 2225] }, 'templateStringCharacter_NonEscaped', []], + ['app', { sourceInterval: [2265, 2284] }, 'templateStringCharacter_Escaped', []], + ]], + lineContinuation: ['define', { sourceInterval: [2323, 2369] }, null, [], ['seq', { sourceInterval: [2342, 2369] }, [ + 'terminal', + { sourceInterval: [2342, 2346] }, + '\\', + ], ['app', { sourceInterval: [2347, 2369] }, 'lineTerminatorSequence', []]]], + escapeSequence: ['define', { sourceInterval: [2374, 2480] }, null, [], [ + 'alt', + { sourceInterval: [2391, 2480] }, + ['app', { sourceInterval: [2391, 2412] }, 'unicodeEscapeSequence', []], + ['app', { sourceInterval: [2415, 2432] }, 'hexEscapeSequence', []], + ['app', { sourceInterval: [2435, 2454] }, 'octalEscapeSequence', []], + ['app', { sourceInterval: [2457, 2480] }, 'characterEscapeSequence', []], + ]], + characterEscapeSequence: ['define', { sourceInterval: [2485, 2553] }, null, [], [ + 'alt', + { sourceInterval: [2511, 2553] }, + ['app', { sourceInterval: [2511, 2532] }, 'singleEscapeCharacter', []], + ['app', { sourceInterval: [2535, 2553] }, 'nonEscapeCharacter', []], + ]], + singleEscapeCharacter: ['define', { sourceInterval: [2558, 2635] }, null, [], [ + 'alt', + { sourceInterval: [2582, 2635] }, + ['terminal', { sourceInterval: [2582, 2585] }, "'"], + ['terminal', { sourceInterval: [2588, 2592] }, '"'], + ['terminal', { sourceInterval: [2595, 2599] }, '\\'], + ['terminal', { sourceInterval: [2602, 2605] }, 'b'], + ['terminal', { sourceInterval: [2608, 2611] }, 'f'], + ['terminal', { sourceInterval: [2614, 2617] }, 'n'], + ['terminal', { sourceInterval: [2620, 2623] }, 'r'], + ['terminal', { sourceInterval: [2626, 2629] }, 't'], + ['terminal', { sourceInterval: [2632, 2635] }, 'v'], + ]], + nonEscapeCharacter: ['define', { sourceInterval: [2640, 2700] }, null, [], [ + 'seq', + { sourceInterval: [2661, 2700] }, + ['not', { sourceInterval: [2661, 2696] }, ['alt', { sourceInterval: [2663, 2695] }, [ + 'app', + { sourceInterval: [2663, 2678] }, + 'escapeCharacter', + [], + ], ['app', { sourceInterval: [2681, 2695] }, 'lineTerminator', []]]], + ['app', { sourceInterval: [2697, 2700] }, 'any', []], + ]], + escapeCharacter: ['define', { sourceInterval: [2705, 2771] }, null, [], [ + 'alt', + { sourceInterval: [2723, 2771] }, + ['app', { sourceInterval: [2723, 2744] }, 'singleEscapeCharacter', []], + ['app', { sourceInterval: [2747, 2759] }, 'decimalDigit', []], + ['terminal', { sourceInterval: [2762, 2765] }, 'x'], + ['terminal', { sourceInterval: [2768, 2771] }, 'u'], + ]], + octalEscapeSequence_Whole: ['define', { sourceInterval: [2804, 2850] }, null, [], [ + 'seq', + { sourceInterval: [2804, 2837] }, + ['app', { sourceInterval: [2804, 2815] }, 'zeroToThree', []], + ['app', { sourceInterval: [2816, 2826] }, 'octalDigit', []], + ['app', { sourceInterval: [2827, 2837] }, 'octalDigit', []], + ]], + octalEscapeSequence_EightTimesfourToSeven: ['define', { sourceInterval: [2857, 2919] }, null, [], [ + 'seq', + { sourceInterval: [2857, 2879] }, + ['app', { sourceInterval: [2857, 2868] }, 'fourToSeven', []], + ['app', { sourceInterval: [2869, 2879] }, 'octalDigit', []], + ]], + octalEscapeSequence_EightTimesZeroToThree: ['define', { sourceInterval: [2926, 2988] }, null, [], [ + 'seq', + { sourceInterval: [2926, 2962] }, + ['app', { sourceInterval: [2926, 2937] }, 'zeroToThree', []], + ['app', { sourceInterval: [2938, 2948] }, 'octalDigit', []], + ['not', { sourceInterval: [2949, 2962] }, ['app', { sourceInterval: [2950, 2962] }, 'decimalDigit', []]], + ]], + octalEscapeSequence_Octal: ['define', { sourceInterval: [2995, 3041] }, null, [], [ + 'seq', + { sourceInterval: [2995, 3019] }, + ['app', { sourceInterval: [2995, 3005] }, 'octalDigit', []], + ['not', { sourceInterval: [3006, 3019] }, ['app', { sourceInterval: [3007, 3019] }, 'decimalDigit', []]], + ]], + octalEscapeSequence: ['define', { sourceInterval: [2776, 3041] }, null, [], [ + 'alt', + { sourceInterval: [2802, 3041] }, + ['app', { sourceInterval: [2804, 2837] }, 'octalEscapeSequence_Whole', []], + ['app', { sourceInterval: [2857, 2879] }, 'octalEscapeSequence_EightTimesfourToSeven', []], + ['app', { sourceInterval: [2926, 2962] }, 'octalEscapeSequence_EightTimesZeroToThree', []], + ['app', { sourceInterval: [2995, 3019] }, 'octalEscapeSequence_Octal', []], + ]], + hexEscapeSequence: ['define', { sourceInterval: [3046, 3087] }, null, [], [ + 'seq', + { sourceInterval: [3066, 3087] }, + ['terminal', { sourceInterval: [3066, 3069] }, 'x'], + ['app', { sourceInterval: [3070, 3078] }, 'hexDigit', []], + ['app', { sourceInterval: [3079, 3087] }, 'hexDigit', []], + ]], + unicodeEscapeSequence: ['define', { sourceInterval: [3092, 3155] }, null, [], [ + 'seq', + { sourceInterval: [3116, 3155] }, + ['terminal', { sourceInterval: [3116, 3119] }, 'u'], + ['app', { sourceInterval: [3120, 3128] }, 'hexDigit', []], + ['app', { sourceInterval: [3129, 3137] }, 'hexDigit', []], + ['app', { sourceInterval: [3138, 3146] }, 'hexDigit', []], + ['app', { sourceInterval: [3147, 3155] }, 'hexDigit', []], + ]], + zeroToThree: ['define', { sourceInterval: [3161, 3183] }, null, [], [ + 'range', + { sourceInterval: [3175, 3183] }, + '0', + '3', + ]], + fourToSeven: ['define', { sourceInterval: [3188, 3210] }, null, [], [ + 'range', + { sourceInterval: [3202, 3210] }, + '4', + '7', + ]], + decimalDigit: ['define', { sourceInterval: [3215, 3238] }, null, [], [ + 'range', + { sourceInterval: [3230, 3238] }, + '0', + '9', + ]], + nonZeroDigit: ['define', { sourceInterval: [3243, 3266] }, null, [], [ + 'range', + { sourceInterval: [3258, 3266] }, + '1', + '9', + ]], + octalDigit: ['define', { sourceInterval: [3271, 3292] }, null, [], [ + 'range', + { sourceInterval: [3284, 3292] }, + '0', + '7', + ]], + regularExpressionLiteral: ['define', { sourceInterval: [3298, 3377] }, null, [], [ + 'seq', + { sourceInterval: [3325, 3377] }, + ['terminal', { sourceInterval: [3325, 3328] }, '/'], + ['app', { sourceInterval: [3329, 3350] }, 'regularExpressionBody', []], + ['terminal', { sourceInterval: [3351, 3354] }, '/'], + ['app', { sourceInterval: [3355, 3377] }, 'regularExpressionFlags', []], + ]], + regularExpressionBody: ['define', { sourceInterval: [3382, 3455] }, null, [], [ + 'seq', + { sourceInterval: [3406, 3455] }, + ['app', { sourceInterval: [3406, 3432] }, 'regularExpressionFirstChar', []], + ['star', { sourceInterval: [3433, 3455] }, [ + 'app', + { sourceInterval: [3433, 3454] }, + 'regularExpressionChar', + [], + ]], + ]], + regularExpressionFirstChar: ['define', { sourceInterval: [3460, 3621] }, null, [], ['alt', { + sourceInterval: [3493, 3621], + }, ['seq', { sourceInterval: [3495, 3551] }, ['not', { sourceInterval: [3495, 3520] }, [ + 'alt', + { sourceInterval: [3497, 3519] }, + ['terminal', { sourceInterval: [3497, 3500] }, '*'], + ['terminal', { sourceInterval: [3503, 3507] }, '\\'], + ['terminal', { sourceInterval: [3510, 3513] }, '/'], + ['terminal', { sourceInterval: [3516, 3519] }, '['], + ]], ['app', { sourceInterval: [3521, 3551] }, 'regularExpressionNonTerminator', []]], [ + 'app', + { sourceInterval: [3558, 3592] }, + 'regularExpressionBackslashSequence', + [], + ], ['app', { sourceInterval: [3599, 3621] }, 'regularExpressionClass', []]]], + regularExpressionChar: ['define', { sourceInterval: [3626, 3770] }, null, [], ['alt', { + sourceInterval: [3650, 3770], + }, ['seq', { sourceInterval: [3650, 3700] }, ['not', { sourceInterval: [3650, 3669] }, [ + 'alt', + { sourceInterval: [3652, 3668] }, + ['terminal', { sourceInterval: [3652, 3656] }, '\\'], + ['terminal', { sourceInterval: [3659, 3662] }, '/'], + ['terminal', { sourceInterval: [3665, 3668] }, '['], + ]], ['app', { sourceInterval: [3670, 3700] }, 'regularExpressionNonTerminator', []]], [ + 'app', + { sourceInterval: [3707, 3741] }, + 'regularExpressionBackslashSequence', + [], + ], ['app', { sourceInterval: [3748, 3770] }, 'regularExpressionClass', []]]], + regularExpressionBackslashSequence: ['define', { sourceInterval: [3775, 3847] }, null, [], [ + 'seq', + { sourceInterval: [3812, 3847] }, + ['terminal', { sourceInterval: [3812, 3816] }, '\\'], + ['app', { sourceInterval: [3817, 3847] }, 'regularExpressionNonTerminator', []], + ]], + regularExpressionNonTerminator: ['define', { sourceInterval: [3852, 3906] }, null, [], [ + 'seq', + { sourceInterval: [3885, 3906] }, + ['not', { sourceInterval: [3885, 3902] }, ['app', { sourceInterval: [3887, 3901] }, 'lineTerminator', []]], + ['app', { sourceInterval: [3903, 3906] }, 'any', []], + ]], + regularExpressionClass: ['define', { sourceInterval: [3911, 3971] }, null, [], [ + 'seq', + { sourceInterval: [3936, 3971] }, + ['terminal', { sourceInterval: [3936, 3939] }, '['], + ['star', { sourceInterval: [3940, 3967] }, [ + 'app', + { sourceInterval: [3940, 3966] }, + 'regularExpressionClassChar', + [], + ]], + ['terminal', { sourceInterval: [3968, 3971] }, ']'], + ]], + regularExpressionClassChar: ['define', { sourceInterval: [3976, 4096] }, null, [], ['alt', { + sourceInterval: [4009, 4096], + }, ['seq', { sourceInterval: [4011, 4055] }, ['not', { sourceInterval: [4011, 4024] }, [ + 'alt', + { sourceInterval: [4013, 4023] }, + ['terminal', { sourceInterval: [4013, 4016] }, ']'], + ['terminal', { sourceInterval: [4019, 4023] }, '\\'], + ]], ['app', { sourceInterval: [4025, 4055] }, 'regularExpressionNonTerminator', []]], [ + 'app', + { sourceInterval: [4062, 4096] }, + 'regularExpressionBackslashSequence', + [], + ]]], + regularExpressionFlags: ['define', { sourceInterval: [4101, 4141] }, null, [], ['star', { + sourceInterval: [4126, 4141], + }, ['app', { sourceInterval: [4126, 4140] }, 'identifierPart', []]]], + multiLineCommentNoNL: ['define', { sourceInterval: [4147, 4211] }, null, [], [ + 'seq', + { sourceInterval: [4170, 4211] }, + ['terminal', { sourceInterval: [4170, 4174] }, '/*'], + ['star', { sourceInterval: [4175, 4206] }, ['seq', { sourceInterval: [4176, 4204] }, ['not', { + sourceInterval: [4176, 4200], + }, ['alt', { sourceInterval: [4178, 4199] }, ['terminal', { sourceInterval: [4178, 4182] }, '*/'], [ + 'app', + { sourceInterval: [4185, 4199] }, + 'lineTerminator', + [], + ]]], ['app', { sourceInterval: [4201, 4204] }, 'any', []]]], + ['terminal', { sourceInterval: [4207, 4211] }, '*/'], + ]], + identifierStart_escaped: ['define', { sourceInterval: [4266, 4303] }, null, [], [ + 'seq', + { sourceInterval: [4266, 4292] }, + ['terminal', { sourceInterval: [4266, 4270] }, '\\'], + ['app', { sourceInterval: [4271, 4292] }, 'unicodeEscapeSequence', []], + ]], + identifierStart: ['define', { sourceInterval: [4217, 4303] }, null, [], [ + 'alt', + { sourceInterval: [4239, 4303] }, + ['app', { sourceInterval: [4241, 4247] }, 'letter', []], + ['terminal', { sourceInterval: [4250, 4253] }, '$'], + ['terminal', { sourceInterval: [4256, 4259] }, '_'], + ['app', { sourceInterval: [4266, 4292] }, 'identifierStart_escaped', []], + ]], + identifierPart: ['define', { sourceInterval: [4308, 4444] }, null, [], [ + 'alt', + { sourceInterval: [4329, 4444] }, + ['app', { sourceInterval: [4331, 4346] }, 'identifierStart', []], + ['app', { sourceInterval: [4349, 4369] }, 'unicodeCombiningMark', []], + ['app', { sourceInterval: [4376, 4388] }, 'unicodeDigit', []], + ['app', { sourceInterval: [4391, 4418] }, 'unicodeConnectorPunctuation', []], + ['terminal', { sourceInterval: [4425, 4433] }, '‌'], + ['terminal', { sourceInterval: [4436, 4444] }, '‍'], + ]], + letter: ['extend', { sourceInterval: [4449, 4476] }, null, [], [ + 'app', + { sourceInterval: [4459, 4476] }, + 'unicodeCategoryNl', + [], + ]], + unicodeCategoryNl: ['define', { sourceInterval: [4481, 4555] }, null, [], [ + 'alt', + { sourceInterval: [4505, 4555] }, + ['range', { sourceInterval: [4505, 4523] }, 'Ⅰ', 'ↂ'], + ['terminal', { sourceInterval: [4526, 4534] }, '〇'], + ['range', { sourceInterval: [4537, 4555] }, '〡', '〩'], + ]], + unicodeDigit: ['define', { sourceInterval: [4560, 4922] }, 'a digit', [], [ + 'alt', + { sourceInterval: [4589, 4922] }, + ['range', { sourceInterval: [4589, 4607] }, '0', '9'], + ['range', { sourceInterval: [4610, 4628] }, '٠', '٩'], + ['range', { sourceInterval: [4631, 4649] }, '۰', '۹'], + ['range', { sourceInterval: [4652, 4670] }, '०', '९'], + ['range', { sourceInterval: [4673, 4691] }, '০', '৯'], + ['range', { sourceInterval: [4694, 4712] }, '੦', '੯'], + ['range', { sourceInterval: [4715, 4733] }, '૦', '૯'], + ['range', { sourceInterval: [4736, 4754] }, '୦', '୯'], + ['range', { sourceInterval: [4757, 4775] }, '௧', '௯'], + ['range', { sourceInterval: [4778, 4796] }, '౦', '౯'], + ['range', { sourceInterval: [4799, 4817] }, '೦', '೯'], + ['range', { sourceInterval: [4820, 4838] }, '൦', '൯'], + ['range', { sourceInterval: [4841, 4859] }, '๐', '๙'], + ['range', { sourceInterval: [4862, 4880] }, '໐', '໙'], + ['range', { sourceInterval: [4883, 4901] }, '༠', '༩'], + ['range', { sourceInterval: [4904, 4922] }, '0', '9'], + ]], + unicodeCombiningMark: ['define', { sourceInterval: [4928, 6659] }, 'a Unicode combining mark', [], [ + 'alt', + { sourceInterval: [4982, 6659] }, + ['range', { sourceInterval: [4982, 5000] }, '̀', 'ͅ'], + ['range', { sourceInterval: [5003, 5021] }, '͠', '͡'], + ['range', { sourceInterval: [5024, 5042] }, '҃', '҆'], + ['range', { sourceInterval: [5045, 5063] }, '֑', '֡'], + ['range', { sourceInterval: [5066, 5084] }, '֣', 'ֹ'], + ['range', { sourceInterval: [5087, 5105] }, 'ֻ', 'ֽ'], + ['range', { sourceInterval: [5108, 5126] }, 'ֿ', 'ֿ'], + ['range', { sourceInterval: [5129, 5147] }, 'ׁ', 'ׂ'], + ['range', { sourceInterval: [5150, 5168] }, 'ׄ', 'ׄ'], + ['range', { sourceInterval: [5171, 5189] }, 'ً', 'ْ'], + ['range', { sourceInterval: [5192, 5210] }, 'ٰ', 'ٰ'], + ['range', { sourceInterval: [5213, 5231] }, 'ۖ', 'ۜ'], + ['range', { sourceInterval: [5234, 5252] }, '۟', 'ۤ'], + ['range', { sourceInterval: [5255, 5273] }, 'ۧ', 'ۨ'], + ['range', { sourceInterval: [5276, 5294] }, '۪', 'ۭ'], + ['range', { sourceInterval: [5297, 5315] }, 'ँ', 'ं'], + ['range', { sourceInterval: [5318, 5336] }, '़', '़'], + ['range', { sourceInterval: [5339, 5357] }, 'ु', 'ै'], + ['range', { sourceInterval: [5360, 5378] }, '्', '्'], + ['range', { sourceInterval: [5381, 5399] }, '॑', '॔'], + ['range', { sourceInterval: [5402, 5420] }, 'ॢ', 'ॣ'], + ['range', { sourceInterval: [5423, 5441] }, 'ঁ', 'ঁ'], + ['range', { sourceInterval: [5444, 5462] }, '়', '়'], + ['range', { sourceInterval: [5465, 5483] }, 'ু', 'ৄ'], + ['range', { sourceInterval: [5486, 5504] }, '্', '্'], + ['range', { sourceInterval: [5507, 5525] }, 'ৢ', 'ৣ'], + ['range', { sourceInterval: [5528, 5546] }, 'ਂ', 'ਂ'], + ['range', { sourceInterval: [5549, 5567] }, '਼', '਼'], + ['range', { sourceInterval: [5570, 5588] }, 'ੁ', 'ੂ'], + ['range', { sourceInterval: [5591, 5609] }, 'ੇ', 'ੈ'], + ['range', { sourceInterval: [5612, 5630] }, 'ੋ', '੍'], + ['range', { sourceInterval: [5633, 5651] }, 'ੰ', 'ੱ'], + ['range', { sourceInterval: [5654, 5672] }, 'ઁ', 'ં'], + ['range', { sourceInterval: [5675, 5693] }, '઼', '઼'], + ['range', { sourceInterval: [5696, 5714] }, 'ુ', 'ૅ'], + ['range', { sourceInterval: [5717, 5735] }, 'ે', 'ૈ'], + ['range', { sourceInterval: [5738, 5756] }, '્', '્'], + ['range', { sourceInterval: [5759, 5777] }, 'ଁ', 'ଁ'], + ['range', { sourceInterval: [5780, 5798] }, '଼', '଼'], + ['range', { sourceInterval: [5801, 5819] }, 'ି', 'ି'], + ['range', { sourceInterval: [5822, 5840] }, 'ୁ', 'ୃ'], + ['range', { sourceInterval: [5843, 5861] }, '୍', '୍'], + ['range', { sourceInterval: [5864, 5882] }, 'ୖ', 'ୖ'], + ['range', { sourceInterval: [5885, 5903] }, 'ஂ', 'ஂ'], + ['range', { sourceInterval: [5906, 5924] }, 'ீ', 'ீ'], + ['range', { sourceInterval: [5927, 5945] }, '்', '்'], + ['range', { sourceInterval: [5948, 5966] }, 'ా', 'ీ'], + ['range', { sourceInterval: [5969, 5987] }, 'ె', 'ై'], + ['range', { sourceInterval: [5990, 6008] }, 'ొ', '్'], + ['range', { sourceInterval: [6011, 6029] }, 'ౕ', 'ౖ'], + ['range', { sourceInterval: [6032, 6050] }, 'ಿ', 'ಿ'], + ['range', { sourceInterval: [6053, 6071] }, 'ೆ', 'ೆ'], + ['range', { sourceInterval: [6074, 6092] }, 'ೌ', '್'], + ['range', { sourceInterval: [6095, 6113] }, 'ു', 'ൃ'], + ['range', { sourceInterval: [6116, 6134] }, '്', '്'], + ['range', { sourceInterval: [6137, 6155] }, 'ั', 'ั'], + ['range', { sourceInterval: [6158, 6176] }, 'ิ', 'ฺ'], + ['range', { sourceInterval: [6179, 6197] }, '็', '๎'], + ['range', { sourceInterval: [6200, 6218] }, 'ັ', 'ັ'], + ['range', { sourceInterval: [6221, 6239] }, 'ິ', 'ູ'], + ['range', { sourceInterval: [6242, 6260] }, 'ົ', 'ຼ'], + ['range', { sourceInterval: [6263, 6281] }, '່', 'ໍ'], + ['range', { sourceInterval: [6284, 6302] }, '༘', '༙'], + ['range', { sourceInterval: [6305, 6323] }, '༵', '༵'], + ['range', { sourceInterval: [6326, 6344] }, '༷', '༷'], + ['range', { sourceInterval: [6347, 6365] }, '༹', '༹'], + ['range', { sourceInterval: [6368, 6386] }, 'ཱ', 'ཾ'], + ['range', { sourceInterval: [6389, 6407] }, 'ྀ', '྄'], + ['range', { sourceInterval: [6410, 6428] }, '྆', '྇'], + ['range', { sourceInterval: [6431, 6449] }, 'ྐ', 'ྕ'], + ['range', { sourceInterval: [6452, 6470] }, 'ྗ', 'ྗ'], + ['range', { sourceInterval: [6473, 6491] }, 'ྙ', 'ྭ'], + ['range', { sourceInterval: [6494, 6512] }, 'ྱ', 'ྷ'], + ['range', { sourceInterval: [6515, 6533] }, 'ྐྵ', 'ྐྵ'], + ['range', { sourceInterval: [6536, 6554] }, '⃐', '⃜'], + ['range', { sourceInterval: [6557, 6575] }, '⃡', '⃡'], + ['range', { sourceInterval: [6578, 6596] }, '〪', '〯'], + ['range', { sourceInterval: [6599, 6617] }, '゙', '゚'], + ['range', { sourceInterval: [6620, 6638] }, 'ﬞ', 'ﬞ'], + ['range', { sourceInterval: [6641, 6659] }, '︠', '︣'], + ]], + unicodeConnectorPunctuation: ['define', { sourceInterval: [6665, 6799] }, null, [], [ + 'alt', + { sourceInterval: [6695, 6799] }, + ['terminal', { sourceInterval: [6695, 6703] }, '_'], + ['range', { sourceInterval: [6706, 6724] }, '‿', '⁀'], + ['terminal', { sourceInterval: [6727, 6735] }, '・'], + ['range', { sourceInterval: [6738, 6756] }, '︳', '︴'], + ['range', { sourceInterval: [6759, 6777] }, '﹍', '﹏'], + ['terminal', { sourceInterval: [6780, 6788] }, '_'], + ['terminal', { sourceInterval: [6791, 6799] }, '・'], + ]], + unicodeSpaceSeparator: ['define', { sourceInterval: [6804, 6857] }, null, [], [ + 'alt', + { sourceInterval: [6828, 6857] }, + ['range', { sourceInterval: [6828, 6846] }, ' ', '​'], + ['terminal', { sourceInterval: [6849, 6857] }, ' '], + ]], + }, +]); +export default result; diff --git a/drizzle-kit/imports-checker/index.ts b/drizzle-kit/imports-checker/index.ts new file mode 100644 index 000000000..7a4e90838 --- /dev/null +++ b/drizzle-kit/imports-checker/index.ts @@ -0,0 +1,48 @@ +import chalk from 'chalk'; +import { analyzeImports, ChainLink } from './checker'; + +const issues = analyzeImports({ + basePath: './drizzle-kit', + localPaths: ['src'], + whiteList: [ + '@drizzle-team/brocli', + 'json-diff', + 'path', + 'fs', + 'fs/*', + 'url', + 'zod', + 'node:*', + 'hono', + 'glob', + 'hono/*', + 'hono/**/*', + '@hono/*', + 'crypto', + 'hanji', + ], + entry: './drizzle-kit/src/cli/index.ts', + logger: true, + ignoreTypes: true, +}).issues; + +const chainToString = (chains: ChainLink[]) => { + if (chains.length === 0) throw new Error(); + + let out = chains[0]!.file + '\n'; + let indentation = 0; + for (let chain of chains) { + out += ' '.repeat(indentation) + + '└' + + chain.import + + ` ${chalk.gray(chain.file)}\n`; + indentation += 1; + } + return out; +}; + +console.log(); +for (const issue of issues) { + console.log(chalk.red(issue.imports.map((it) => it.name).join('\n'))); + console.log(issue.accessChains.map((it) => chainToString(it)).join('\n')); +} diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 26163fed2..e45f7dbc5 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.27.2", + "version": "0.28.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", @@ -62,6 +62,7 @@ "@types/dockerode": "^3.3.28", "@types/glob": "^8.1.0", "@types/json-diff": "^1.0.3", + "@types/micromatch": "^4.0.9", "@types/minimatch": "^5.1.2", "@types/node": "^18.11.15", "@types/pg": "^8.10.7", @@ -92,9 +93,11 @@ "hanji": "^0.0.5", "hono": "^4.1.5", "json-diff": "1.0.6", + "micromatch": "^4.0.8", "minimatch": "^7.4.3", "mysql2": "3.3.3", "node-fetch": "^3.3.2", + "ohm-js": "^17.1.0", "pg": "^8.11.5", "pluralize": "^8.0.0", "postgres": "^3.4.4", @@ -138,4 +141,4 @@ "default": "./api.mjs" } } -} +} \ No newline at end of file diff --git a/drizzle-kit/src/@types/utils.ts b/drizzle-kit/src/@types/utils.ts index 04e7e125f..e71d45b89 100644 --- a/drizzle-kit/src/@types/utils.ts +++ b/drizzle-kit/src/@types/utils.ts @@ -13,6 +13,7 @@ declare global { random(): T; } } + import camelcase from 'camelcase'; String.prototype.trimChar = function(char: string) { diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 83b7139ad..b18ed95f4 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -21,7 +21,9 @@ import { updateUpToV6 as upPgV6, updateUpToV7 as upPgV7 } from './cli/commands/p import { sqlitePushIntrospect } from './cli/commands/sqliteIntrospect'; import { logSuggestionsAndReturn } from './cli/commands/sqlitePushUtils'; import type { CasingType } from './cli/validations/common'; +import { getTablesFilterByExtensions } from './extensions/getTablesFilterByExtensions'; import { originUUID } from './global'; +import type { Config } from './index'; import { fillPgSnapshot } from './migrationPreparator'; import { MySqlSchema as MySQLSchemaKit, mysqlSchema, squashMysqlScheme } from './serializer/mysqlSchema'; import { generateMySqlSnapshot } from './serializer/mysqlSerializer'; @@ -100,9 +102,14 @@ export const pushSchema = async ( imports: Record, drizzleInstance: PgDatabase, schemaFilters?: string[], + tablesFilter?: string[], + extensionsFilters?: Config['extensionsFilters'], ) => { const { applyPgSnapshotsDiff } = await import('./snapshotsDiffer'); const { sql } = await import('drizzle-orm'); + const filters = (tablesFilter ?? []).concat( + getTablesFilterByExtensions({ extensionsFilters, dialect: 'postgresql' }), + ); const db: DB = { query: async (query: string, params?: any[]) => { @@ -114,7 +121,7 @@ export const pushSchema = async ( const cur = generateDrizzleJson(imports); const { schema: prev } = await pgPushIntrospect( db, - [], + filters, schemaFilters ?? ['public'], undefined, ); diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 54dbb4ba0..4a41a46d4 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -383,15 +383,15 @@ export const sqlitePush = async ( render(`\n[${chalk.blue('i')}] No changes detected`); } else { if (!('driver' in credentials)) { - await db.query('begin'); + await db.run('begin'); try { for (const dStmnt of statementsToExecute) { - await db.query(dStmnt); + await db.run(dStmnt); } - await db.query('commit'); + await db.run('commit'); } catch (e) { console.error(e); - await db.query('rollback'); + await db.run('rollback'); process.exit(1); } } diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 203e38cca..7386b74d5 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -3,6 +3,7 @@ import { existsSync } from 'fs'; import { render } from 'hanji'; import { join, resolve } from 'path'; import { object, string } from 'zod'; +import { getTablesFilterByExtensions } from '../../extensions/getTablesFilterByExtensions'; import { assertUnreachable } from '../../global'; import { type Dialect, dialect } from '../../schemaValidator'; import { prepareFilenames } from '../../serializer'; @@ -169,7 +170,7 @@ export const prepareGenerateConfig = async ( name: options.name, custom: options.custom || false, prefix, - breakpoints: breakpoints || true, + breakpoints: breakpoints ?? true, schema: schema, out: out || 'drizzle', bundle: driver === 'expo', @@ -273,16 +274,7 @@ export const preparePushConfig = async ( : schemasFilterConfig : []; - if (config.extensionsFilters) { - if ( - config.extensionsFilters.includes('postgis') - && config.dialect === 'postgresql' - ) { - tablesFilter.push( - ...['!geography_columns', '!geometry_columns', '!spatial_ref_sys'], - ); - } - } + tablesFilter.push(...getTablesFilterByExtensions(config)); if (config.dialect === 'postgresql') { const parsed = postgresCredentials.safeParse(config); diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 64ceb5841..b03acde95 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -24,7 +24,7 @@ import { mkdirSync } from 'fs'; import { renderWithTask } from 'hanji'; import { dialects } from 'src/schemaValidator'; import { assertUnreachable } from '../global'; -import { drizzleForLibSQL, type Setup } from '../serializer/studio'; +import type { Setup } from '../serializer/studio'; import { certs } from '../utils/certs'; import { grey, MigrateProgress } from './views'; @@ -591,6 +591,7 @@ export const studio = command({ drizzleForMySQL, prepareSQLiteSchema, drizzleForSQLite, + drizzleForLibSQL, } = await import('../serializer/studio'); let setup: Setup; diff --git a/drizzle-kit/src/cli/validations/outputs.ts b/drizzle-kit/src/cli/validations/outputs.ts index 6b92829d5..3ef499651 100644 --- a/drizzle-kit/src/cli/validations/outputs.ts +++ b/drizzle-kit/src/cli/validations/outputs.ts @@ -26,7 +26,7 @@ export const outputs = { ), noDialect: () => withStyle.error( - `Please specify 'dialect' param in config, either of 'pg', 'mysql' or 'sqlite'`, + `Please specify 'dialect' param in config, either of 'postgresql', 'mysql', 'sqlite' or 'turso'`, ), }, common: { diff --git a/drizzle-kit/src/extensions/getTablesFilterByExtensions.ts b/drizzle-kit/src/extensions/getTablesFilterByExtensions.ts new file mode 100644 index 000000000..80321fc6a --- /dev/null +++ b/drizzle-kit/src/extensions/getTablesFilterByExtensions.ts @@ -0,0 +1,16 @@ +import type { Config } from '../index'; + +export const getTablesFilterByExtensions = ({ + extensionsFilters, + dialect, +}: Pick): string[] => { + if (extensionsFilters) { + if ( + extensionsFilters.includes('postgis') + && dialect === 'postgresql' + ) { + return ['!geography_columns', '!geometry_columns', '!spatial_ref_sys']; + } + } + return []; +}; diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index ea287713f..ebf30f70d 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -14,6 +14,7 @@ import { UniqueConstraint, } from './serializer/mysqlSchema'; import { indexName } from './serializer/mysqlSerializer'; +import { unescapeSingleQuotes } from './utils'; // time precision to fsp // {mode: "string"} for timestamp by default @@ -179,6 +180,12 @@ export const schemaToTypeScript = ( patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; patched = patched.startsWith('int(') ? 'int' : patched; patched = patched.startsWith('double(') ? 'double' : patched; + patched = patched.startsWith('float(') ? 'float' : patched; + patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; + patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; + patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; + patched = patched.startsWith('bigint unsigned') ? 'bigint' : patched; return patched; }) .filter((type) => { @@ -207,6 +214,12 @@ export const schemaToTypeScript = ( patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; patched = patched.startsWith('int(') ? 'int' : patched; patched = patched.startsWith('double(') ? 'double' : patched; + patched = patched.startsWith('float(') ? 'float' : patched; + patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; + patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; + patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; + patched = patched.startsWith('bigint unsigned') ? 'bigint' : patched; return patched; }) .filter((type) => { @@ -397,8 +410,9 @@ const column = ( if (lowered.startsWith('int')) { const isUnsigned = lowered.startsWith('int unsigned'); - let out = `${casing(name)}: int(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? '{ unsigned: true }' : '' + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: int(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += typeof defaultValue !== 'undefined' @@ -409,9 +423,10 @@ const column = ( if (lowered.startsWith('tinyint')) { const isUnsigned = lowered.startsWith('tinyint unsigned'); + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); // let out = `${name.camelCase()}: tinyint("${name}")`; - let out: string = `${casing(name)}: tinyint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? ', { unsigned: true }' : '' + let out: string = `${casing(name)}: tinyint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += typeof defaultValue !== 'undefined' @@ -422,8 +437,9 @@ const column = ( if (lowered.startsWith('smallint')) { const isUnsigned = lowered.startsWith('smallint unsigned'); - let out = `${casing(name)}: smallint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? ', { unsigned: true }' : '' + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: smallint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue @@ -434,8 +450,9 @@ const column = ( if (lowered.startsWith('mediumint')) { const isUnsigned = lowered.startsWith('mediumint unsigned'); - let out = `${casing(name)}: mediumint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? ', { unsigned: true }' : '' + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: mediumint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue @@ -466,16 +483,20 @@ const column = ( if (lowered.startsWith('double')) { let params: - | { precision: string | undefined; scale: string | undefined } + | { precision?: string; scale?: string; unsigned?: boolean } | undefined; - if (lowered.length > 6) { + if (lowered.length > (lowered.includes('unsigned') ? 15 : 6)) { const [precision, scale] = lowered - .slice(7, lowered.length - 1) + .slice(7, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) .split(','); params = { precision, scale }; } + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + const timeConfigParams = params ? timeConfig(params) : undefined; let out = params @@ -491,8 +512,23 @@ const column = ( return out; } - if (lowered === 'float') { - let out = `${casing(name)}: float(${dbColumnName({ name, casing: rawCasing })})`; + if (lowered.startsWith('float')) { + let params: + | { precision?: string; scale?: string; unsigned?: boolean } + | undefined; + + if (lowered.length > (lowered.includes('unsigned') ? 14 : 5)) { + const [precision, scale] = lowered + .slice(6, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) + .split(','); + params = { precision, scale }; + } + + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + + let out = `${casing(name)}: float(${dbColumnName({ name, casing: rawCasing })}${params ? timeConfig(params) : ''})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -644,8 +680,9 @@ const column = ( ) } })`; + const mappedDefaultValue = mapColumnDefault(defaultValue, isExpression); out += defaultValue - ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + ? `.default(${isExpression ? mappedDefaultValue : unescapeSingleQuotes(mappedDefaultValue, true)})` : ''; return out; } @@ -700,16 +737,20 @@ const column = ( if (lowered.startsWith('decimal')) { let params: - | { precision: string | undefined; scale: string | undefined } + | { precision?: string; scale?: string; unsigned?: boolean } | undefined; - if (lowered.length > 7) { + if (lowered.length > (lowered.includes('unsigned') ? 16 : 7)) { const [precision, scale] = lowered - .slice(8, lowered.length - 1) + .slice(8, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) .split(','); params = { precision, scale }; } + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + const timeConfigParams = params ? timeConfig(params) : undefined; let out = params @@ -748,10 +789,15 @@ const column = ( } if (lowered.startsWith('enum')) { - const values = lowered.substring('enum'.length + 1, lowered.length - 1); + const values = lowered + .substring('enum'.length + 1, lowered.length - 1) + .split(',') + .map((v) => unescapeSingleQuotes(v, true)) + .join(','); let out = `${casing(name)}: mysqlEnum(${dbColumnName({ name, casing: rawCasing, withMode: true })}[${values}])`; + const mappedDefaultValue = mapColumnDefault(defaultValue, isExpression); out += defaultValue - ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + ? `.default(${isExpression ? mappedDefaultValue : unescapeSingleQuotes(mappedDefaultValue, true)})` : ''; return out; } diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index ed26e8117..9c9383ebe 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -11,7 +11,6 @@ import { import './@types/utils'; import { toCamelCase } from 'drizzle-orm/casing'; import { Casing } from './cli/validations/common'; -import { vectorOps } from './extensions/vector'; import { assertUnreachable } from './global'; import { CheckConstraint, @@ -25,6 +24,7 @@ import { UniqueConstraint, } from './serializer/pgSchema'; import { indexName } from './serializer/pgSerializer'; +import { unescapeSingleQuotes } from './utils'; const pgImportsList = new Set([ 'pgTable', @@ -436,7 +436,7 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => const func = enumSchema ? `${enumSchema}.enum` : 'pgEnum'; const values = Object.values(it.values) - .map((it) => `'${it}'`) + .map((it) => `'${unescapeSingleQuotes(it, false)}'`) .join(', '); return `export const ${withCasing(paramName, casing)} = ${func}("${it.name}", [${values}])\n`; }) @@ -690,7 +690,9 @@ const mapDefault = ( } if (enumTypes.has(`${typeSchema}.${type.replace('[]', '')}`)) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('integer')) { @@ -737,18 +739,20 @@ const mapDefault = ( if (lowered.startsWith('timestamp')) { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue === 'CURRENT_TIMESTAMP' - ? '.default(sql`CURRENT_TIMESTAMP`)' - : defaultValue + : /^'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}(:\d{2})?)?'$/.test(defaultValue) // Matches 'YYYY-MM-DD HH:MI:SS', 'YYYY-MM-DD HH:MI:SS.FFFFFF', 'YYYY-MM-DD HH:MI:SS+TZ', 'YYYY-MM-DD HH:MI:SS.FFFFFF+TZ' and 'YYYY-MM-DD HH:MI:SS+HH:MI' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } if (lowered.startsWith('time')) { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue + : /^'\d{2}:\d{2}(:\d{2})?(\.\d+)?'$/.test(defaultValue) // Matches 'HH:MI', 'HH:MI:SS' and 'HH:MI:SS.FFFFFF' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } @@ -759,15 +763,17 @@ const mapDefault = ( if (lowered === 'date') { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue === 'CURRENT_DATE' - ? `.default(sql\`${defaultValue}\`)` - : defaultValue + : /^'\d{4}-\d{2}-\d{2}'$/.test(defaultValue) // Matches 'YYYY-MM-DD' ? `.default(${defaultValue})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } if (lowered.startsWith('text')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('jsonb')) { @@ -801,7 +807,9 @@ const mapDefault = ( } if (lowered.startsWith('varchar')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('point')) { @@ -821,7 +829,9 @@ const mapDefault = ( } if (lowered.startsWith('char')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } return ''; @@ -1219,7 +1229,11 @@ const createTableIndexes = (tableName: string, idxs: Index[], casing: Casing): s } else { return `table.${withCasing(it.expression, casing)}${it.asc ? '.asc()' : '.desc()'}${ it.nulls === 'first' ? '.nullsFirst()' : '.nullsLast()' - }${it.opclass && vectorOps.includes(it.opclass) ? `.op("${it.opclass}")` : ''}`; + }${ + it.opclass + ? `.op("${it.opclass}")` + : '' + }`; } }) .join(', ') diff --git a/drizzle-kit/src/introspect-sqlite.ts b/drizzle-kit/src/introspect-sqlite.ts index e21f2a5c4..464a32aa3 100644 --- a/drizzle-kit/src/introspect-sqlite.ts +++ b/drizzle-kit/src/introspect-sqlite.ts @@ -272,10 +272,8 @@ const mapColumnDefault = (defaultValue: any) => { if ( typeof defaultValue === 'string' - && defaultValue.startsWith("'") - && defaultValue.endsWith("'") ) { - return defaultValue.substring(1, defaultValue.length - 1); + return defaultValue.substring(1, defaultValue.length - 1).replaceAll('"', '\\"').replaceAll("''", "'"); } return defaultValue; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 9359b1a8d..18b28fac4 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -2704,19 +2704,14 @@ export const prepareAddCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, - // TODO: remove? - json2: PgSchema, ): JsonCreateCompositePK[] => { return Object.values(pks).map((it) => { - const unsquashed = PgSquasher.unsquashPK(it); return { type: 'create_composite_pk', tableName, data: it, schema, - constraintName: json2.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - unsquashed.name - ].name, + constraintName: PgSquasher.unsquashPK(it).name, } as JsonCreateCompositePK; }); }; @@ -2725,8 +2720,6 @@ export const prepareDeleteCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, - // TODO: remove? - json1: PgSchema, ): JsonDeleteCompositePK[] => { return Object.values(pks).map((it) => { return { @@ -2734,9 +2727,7 @@ export const prepareDeleteCompositePrimaryKeyPg = ( tableName, data: it, schema, - constraintName: json1.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it).name - ].name, + constraintName: PgSquasher.unsquashPK(it).name, } as JsonDeleteCompositePK; }); }; @@ -2745,9 +2736,6 @@ export const prepareAlterCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, - // TODO: remove? - json1: PgSchema, - json2: PgSchema, ): JsonAlterCompositePK[] => { return Object.values(pks).map((it) => { return { @@ -2756,12 +2744,8 @@ export const prepareAlterCompositePrimaryKeyPg = ( old: it.__old, new: it.__new, schema, - oldConstraintName: json1.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it.__old).name - ].name, - newConstraintName: json2.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it.__new).name - ].name, + oldConstraintName: PgSquasher.unsquashPK(it.__old).name, + newConstraintName: PgSquasher.unsquashPK(it.__new).name, } as JsonAlterCompositePK; }); }; @@ -2874,7 +2858,7 @@ export const prepareAddCompositePrimaryKeyMySql = ( type: 'create_composite_pk', tableName, data: it, - constraintName: json2.tables[tableName].compositePrimaryKeys[unsquashed.name].name, + constraintName: unsquashed.name, } as JsonCreateCompositePK); } return res; @@ -2887,13 +2871,12 @@ export const prepareDeleteCompositePrimaryKeyMySql = ( json1: MySqlSchema, ): JsonDeleteCompositePK[] => { return Object.values(pks).map((it) => { + const unsquashed = MySqlSquasher.unsquashPK(it); return { type: 'delete_composite_pk', tableName, data: it, - constraintName: json1.tables[tableName].compositePrimaryKeys[ - MySqlSquasher.unsquashPK(it).name - ].name, + constraintName: unsquashed.name, } as JsonDeleteCompositePK; }); }; diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index f7fa7f3f0..aaa1acb82 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -26,13 +26,20 @@ import { UniqueConstraint, View, } from '../serializer/mysqlSchema'; -import type { DB } from '../utils'; +import { type DB, escapeSingleQuotes } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; }; +const handleEnumType = (type: string) => { + let str = type.split('(')[1]; + str = str.substring(0, str.length - 1); + const values = str.split(',').map((v) => `'${escapeSingleQuotes(v.substring(1, v.length - 1))}'`); + return `enum(${values.join(',')})`; +}; + export const generateMySqlSnapshot = ( tables: AnyMySqlTable[], views: MySqlView[], @@ -68,7 +75,8 @@ export const generateMySqlSnapshot = ( columns.forEach((column) => { const name = getColumnCasing(column, casing); const notNull: boolean = column.notNull; - const sqlTypeLowered = column.getSQLType().toLowerCase(); + const sqlType = column.getSQLType(); + const sqlTypeLowered = sqlType.toLowerCase(); const autoIncrement = typeof (column as any).autoIncrement === 'undefined' ? false : (column as any).autoIncrement; @@ -77,7 +85,7 @@ export const generateMySqlSnapshot = ( const columnToSet: Column = { name, - type: column.getSQLType(), + type: sqlType.startsWith('enum') ? handleEnumType(sqlType) : sqlType, primaryKey: false, // If field is autoincrement it's notNull by default // notNull: autoIncrement ? true : notNull, @@ -141,7 +149,7 @@ export const generateMySqlSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { if (typeof column.default === 'string') { - columnToSet.default = `'${column.default}'`; + columnToSet.default = `'${escapeSingleQuotes(column.default)}'`; } else { if (sqlTypeLowered === 'json') { columnToSet.default = `'${JSON.stringify(column.default)}'`; @@ -544,9 +552,9 @@ function clearDefaults(defaultValue: any, collate: string) { .substring(collate.length, defaultValue.length) .replace(/\\/g, ''); if (resultDefault.startsWith("'") && resultDefault.endsWith("'")) { - return `('${resultDefault.substring(1, resultDefault.length - 1)}')`; + return `('${escapeSingleQuotes(resultDefault.substring(1, resultDefault.length - 1))}')`; } else { - return `'${resultDefault}'`; + return `'${escapeSingleQuotes(resultDefault.substring(1, resultDefault.length - 1))}'`; } } else { return `(${resultDefault})`; @@ -651,8 +659,8 @@ export const fromDatabase = async ( } } - if (columnType.startsWith('tinyint')) { - changedType = 'tinyint'; + if (columnType.includes('decimal(10,0)')) { + changedType = columnType.replace('decimal(10,0)', 'decimal'); } let onUpdate: boolean | undefined = undefined; @@ -665,14 +673,14 @@ export const fromDatabase = async ( } const newColumn: Column = { - default: columnDefault === null + default: columnDefault === null || columnDefault === undefined ? undefined : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) && !['decimal', 'char', 'varchar'].some((type) => columnType.startsWith(type)) ? Number(columnDefault) : isDefaultAnExpression ? clearDefaults(columnDefault, collation) - : `'${columnDefault}'`, + : `'${escapeSingleQuotes(columnDefault)}'`, autoincrement: isAutoincrement, name: columnName, type: changedType, diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index f5810bbc8..d7604d645 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -1,4 +1,3 @@ -import { vectorOps } from 'src/extensions/vector'; import { mapValues, originUUID, snapshotVersion } from '../global'; import { any, array, boolean, enum as enumType, literal, number, object, record, string, TypeOf, union } from 'zod'; @@ -555,10 +554,7 @@ export const PgSquasher = { return `${idx.name};${ idx.columns .map( - (c) => - `${c.expression}--${c.isExpression}--${c.asc}--${c.nulls}--${ - c.opclass && vectorOps.includes(c.opclass) ? c.opclass : '' - }`, + (c) => `${c.expression}--${c.isExpression}--${c.asc}--${c.nulls}--${c.opclass ? c.opclass : ''}`, ) .join(',,') };${idx.isUnique};${idx.concurrently};${idx.method};${idx.where};${JSON.stringify(idx.with)}`; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 66b8db85f..b0faa5ea8 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -39,7 +39,7 @@ import type { UniqueConstraint, View, } from '../serializer/pgSchema'; -import { type DB, isPgArrayType } from '../utils'; +import { type DB, escapeSingleQuotes, isPgArrayType } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const indexName = (tableName: string, columns: string[]) => { @@ -241,7 +241,7 @@ export const generatePgSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { if (typeof column.default === 'string') { - columnToSet.default = `'${column.default}'`; + columnToSet.default = `'${escapeSingleQuotes(column.default)}'`; } else { if (sqlTypeLowered === 'jsonb' || sqlTypeLowered === 'json') { columnToSet.default = `'${JSON.stringify(column.default)}'::${sqlTypeLowered}`; @@ -1937,11 +1937,13 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str const columnName = column.column_name; const isArray = internals?.tables[tableName]?.columns[columnName]?.isArray ?? false; - if (column.column_default === null) { - return undefined; - } - - if (column.data_type === 'serial' || column.data_type === 'smallserial' || column.data_type === 'bigserial') { + if ( + column.column_default === null + || column.column_default === undefined + || column.data_type === 'serial' + || column.data_type === 'smallserial' + || column.data_type === 'bigserial' + ) { return undefined; } diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 1ba24b69c..107a1b292 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -25,7 +25,7 @@ import type { UniqueConstraint, View, } from '../serializer/sqliteSchema'; -import type { SQLiteDB } from '../utils'; +import { escapeSingleQuotes, type SQLiteDB } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const generateSqliteSnapshot = ( @@ -90,7 +90,7 @@ export const generateSqliteSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { columnToSet.default = typeof column.default === 'string' - ? `'${column.default}'` + ? `'${escapeSingleQuotes(column.default)}'` : typeof column.default === 'object' || Array.isArray(column.default) ? `'${JSON.stringify(column.default)}'` diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index dda13b967..060f12bbd 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -131,7 +131,6 @@ import { PgSchemaSquashed, PgSquasher, Policy, - policy, policySquashed, Role, roleSchema, @@ -1243,22 +1242,22 @@ export const applyPgSnapshotsDiff = async ( // This part is needed to make sure that same columns in a table are not triggered for change // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name // We double-check that pk with same set of columns are both in added and deleted diffs - let addedColumns: string[] = []; + let addedColumns: { name: string; columns: string[] } | undefined; for (const addedPkName of Object.keys(it.addedCompositePKs)) { const addedPkColumns = it.addedCompositePKs[addedPkName]; - addedColumns = SQLiteSquasher.unsquashPK(addedPkColumns); + addedColumns = PgSquasher.unsquashPK(addedPkColumns); } - let deletedColumns: string[] = []; + let deletedColumns: { name: string; columns: string[] } | undefined; for (const deletedPkName of Object.keys(it.deletedCompositePKs)) { const deletedPkColumns = it.deletedCompositePKs[deletedPkName]; - deletedColumns = SQLiteSquasher.unsquashPK(deletedPkColumns); + deletedColumns = PgSquasher.unsquashPK(deletedPkColumns); } // Don't need to sort, but need to add tests for it // addedColumns.sort(); // deletedColumns.sort(); - const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); + const doPerformDeleteAndCreate = JSON.stringify(addedColumns ?? {}) !== JSON.stringify(deletedColumns ?? {}); let addedCompositePKs: JsonCreateCompositePK[] = []; let deletedCompositePKs: JsonDeleteCompositePK[] = []; @@ -1268,21 +1267,17 @@ export const applyPgSnapshotsDiff = async ( it.name, it.schema, it.addedCompositePKs, - curFull as PgSchema, ); deletedCompositePKs = prepareDeleteCompositePrimaryKeyPg( it.name, it.schema, it.deletedCompositePKs, - prevFull as PgSchema, ); } alteredCompositePKs = prepareAlterCompositePrimaryKeyPg( it.name, it.schema, it.alteredCompositePKs, - prevFull as PgSchema, - curFull as PgSchema, ); // add logic for unique constraints @@ -2634,12 +2629,11 @@ export const applyMysqlSnapshotsDiff = async ( jsonStatements.push(...jsonDeletedCompositePKs); jsonStatements.push(...jsonTableAlternations); jsonStatements.push(...jsonAddedCompositePKs); + jsonStatements.push(...jsonAddColumnsStatemets); jsonStatements.push(...jsonAddedUniqueConstraints); jsonStatements.push(...jsonDeletedUniqueConstraints); - jsonStatements.push(...jsonAddColumnsStatemets); - jsonStatements.push(...jsonCreateReferencesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForCreatedTables); jsonStatements.push(...jsonCreatedCheckConstraints); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index bb3335941..3c88a86ce 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -86,75 +86,59 @@ import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; import { PgSquasher, policy } from './serializer/pgSchema'; import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; - -export const pgNativeTypes = new Set([ - 'uuid', - 'smallint', - 'integer', - 'bigint', - 'boolean', - 'text', - 'varchar', - 'serial', - 'bigserial', - 'decimal', - 'numeric', - 'real', - 'json', - 'jsonb', - 'time', - 'time with time zone', - 'time without time zone', - 'time', - 'timestamp', - 'timestamp with time zone', - 'timestamp without time zone', - 'date', - 'interval', - 'bigint', - 'bigserial', - 'double precision', - 'interval year', - 'interval month', - 'interval day', - 'interval hour', - 'interval minute', - 'interval second', - 'interval year to month', - 'interval day to hour', - 'interval day to minute', - 'interval day to second', - 'interval hour to minute', - 'interval hour to second', - 'interval minute to second', -]); - -const isPgNativeType = (it: string) => { - if (pgNativeTypes.has(it)) return true; - const toCheck = it.replace(/ /g, ''); - return ( - toCheck.startsWith('varchar(') - || toCheck.startsWith('char(') - || toCheck.startsWith('numeric(') - || toCheck.startsWith('timestamp(') - || toCheck.startsWith('doubleprecision[') - || toCheck.startsWith('intervalyear(') - || toCheck.startsWith('intervalmonth(') - || toCheck.startsWith('intervalday(') - || toCheck.startsWith('intervalhour(') - || toCheck.startsWith('intervalminute(') - || toCheck.startsWith('intervalsecond(') - || toCheck.startsWith('intervalyeartomonth(') - || toCheck.startsWith('intervaldaytohour(') - || toCheck.startsWith('intervaldaytominute(') - || toCheck.startsWith('intervaldaytosecond(') - || toCheck.startsWith('intervalhourtominute(') - || toCheck.startsWith('intervalhourtosecond(') - || toCheck.startsWith('intervalminutetosecond(') - || toCheck.startsWith('vector(') - || toCheck.startsWith('geometry(') - || /^(\w+)(\[\d*])+$/.test(it) - ); +import { escapeSingleQuotes } from './utils'; + +const parseType = (schemaPrefix: string, type: string) => { + const pgNativeTypes = [ + 'uuid', + 'smallint', + 'integer', + 'bigint', + 'boolean', + 'text', + 'varchar', + 'serial', + 'bigserial', + 'decimal', + 'numeric', + 'real', + 'json', + 'jsonb', + 'time', + 'time with time zone', + 'time without time zone', + 'time', + 'timestamp', + 'timestamp with time zone', + 'timestamp without time zone', + 'date', + 'interval', + 'bigint', + 'bigserial', + 'double precision', + 'interval year', + 'interval month', + 'interval day', + 'interval hour', + 'interval minute', + 'interval second', + 'interval year to month', + 'interval day to hour', + 'interval day to minute', + 'interval day to second', + 'interval hour to minute', + 'interval hour to second', + 'interval minute to second', + 'char', + 'vector', + 'geometry', + ]; + const arrayDefinitionRegex = /\[\d*(?:\[\d*\])*\]/g; + const arrayDefinition = (type.match(arrayDefinitionRegex) ?? []).join(''); + const withoutArrayDefinition = type.replace(arrayDefinitionRegex, ''); + return pgNativeTypes.some((it) => type.startsWith(it)) + ? `${withoutArrayDefinition}${arrayDefinition}` + : `${schemaPrefix}"${withoutArrayDefinition}"${arrayDefinition}`; }; abstract class Convertor { @@ -419,9 +403,7 @@ class PgCreateTableConvertor extends Convertor { ? `"${column.typeSchema}".` : ''; - const type = isPgNativeType(column.type) - ? column.type - : `${schemaPrefix}"${column.type}"`; + const type = parseType(schemaPrefix, column.type); const generated = column.generated; const generatedStatement = generated ? ` GENERATED ALWAYS AS (${generated?.as}) STORED` : ''; @@ -1296,7 +1278,7 @@ class CreateTypeEnumConvertor extends Convertor { const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; let valuesStatement = '('; - valuesStatement += values.map((it) => `'${it}'`).join(', '); + valuesStatement += values.map((it) => `'${escapeSingleQuotes(it)}'`).join(', '); valuesStatement += ')'; // TODO do we need this? @@ -1604,9 +1586,7 @@ class PgAlterTableAddColumnConvertor extends Convertor { ? `"${column.typeSchema}".` : ''; - const fixedType = isPgNativeType(column.type) - ? column.type - : `${schemaPrefix}"${column.type}"`; + const fixedType = parseType(schemaPrefix, column.type); const notNullStatement = `${notNull ? ' NOT NULL' : ''}`; @@ -2530,9 +2510,10 @@ class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { ? `"${statement.schema}"."${statement.tableName}"` : `"${statement.tableName}"`; - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT ${statement.oldConstraintName};\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newConstraintName} PRIMARY KEY(${ - newColumns.join(',') - });`; + console.log(statement.oldConstraintName, statement.newConstraintName); + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.oldConstraintName}";\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.newConstraintName}" PRIMARY KEY("${ + newColumns.join('","') + }");`; } } diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index f26624969..685e2efb5 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -4,6 +4,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from import { join } from 'path'; import { parse } from 'url'; import type { NamedWithSchema } from './cli/commands/migrate'; +import { CasingType } from './cli/validations/common'; import { info } from './cli/views'; import { assertUnreachable, snapshotVersion } from './global'; import type { Dialect } from './schemaValidator'; @@ -356,3 +357,12 @@ export function findAddedAndRemoved(columnNames1: string[], columnNames2: string return { addedColumns, removedColumns }; } + +export function escapeSingleQuotes(str: string) { + return str.replace(/'/g, "''"); +} + +export function unescapeSingleQuotes(str: string, ignoreFirstAndLastChar: boolean) { + const regex = ignoreFirstAndLastChar ? /(? { + const issues = analyzeImports({ + basePath: '.', + localPaths: ['src'], + whiteList: [ + '@drizzle-team/brocli', + 'json-diff', + 'path', + 'fs', + 'fs/*', + 'url', + 'zod', + 'node:*', + 'hono', + 'glob', + 'hono/*', + 'hono/**/*', + '@hono/*', + 'crypto', + 'hanji', + 'chalk', + 'dotenv/config', + 'camelcase', + 'semver', + 'env-paths', + ], + entry: 'src/cli/index.ts', + logger: true, + ignoreTypes: true, + }).issues; + + const chainToString = (chains: ChainLink[]) => { + if (chains.length === 0) throw new Error(); + + let out = chains[0]!.file + '\n'; + let indentation = 0; + for (let chain of chains) { + out += ' '.repeat(indentation) + + '└' + + chain.import + + ` ${chalk.gray(chain.file)}\n`; + indentation += 1; + } + return out; + }; + + console.log(); + for (const issue of issues) { + console.log(chalk.red(issue.imports.map((it) => it.name).join('\n'))); + console.log(issue.accessChains.map((it) => chainToString(it)).join('\n')); + } + + assert.equal(issues.length, 0); +}); diff --git a/drizzle-kit/tests/indexes/pg.test.ts b/drizzle-kit/tests/indexes/pg.test.ts index 9958a2356..b9ff36020 100644 --- a/drizzle-kit/tests/indexes/pg.test.ts +++ b/drizzle-kit/tests/indexes/pg.test.ts @@ -125,12 +125,12 @@ const pgSuite: DialectSuite = { expect(sqlStatements).toStrictEqual([ 'DROP INDEX IF EXISTS "indx";', 'DROP INDEX IF EXISTS "indx1";', - // 'DROP INDEX IF EXISTS "indx2";', + 'DROP INDEX IF EXISTS "indx2";', 'DROP INDEX IF EXISTS "indx3";', 'CREATE INDEX IF NOT EXISTS "indx4" ON "users" USING btree (lower(id)) WHERE true;', 'CREATE INDEX IF NOT EXISTS "indx" ON "users" USING btree ("name" DESC NULLS LAST);', 'CREATE INDEX IF NOT EXISTS "indx1" ON "users" USING btree ("name" DESC NULLS LAST) WHERE false;', - // 'CREATE INDEX IF NOT EXISTS "indx2" ON "users" USING btree ("name" test) WHERE true;', + 'CREATE INDEX IF NOT EXISTS "indx2" ON "users" USING btree ("name" test) WHERE true;', 'CREATE INDEX IF NOT EXISTS "indx3" ON "users" USING btree (lower("id")) WHERE true;', ]); }, diff --git a/drizzle-kit/tests/introspect/mysql.test.ts b/drizzle-kit/tests/introspect/mysql.test.ts index 024300bea..2db33416b 100644 --- a/drizzle-kit/tests/introspect/mysql.test.ts +++ b/drizzle-kit/tests/introspect/mysql.test.ts @@ -1,12 +1,30 @@ +import 'dotenv/config'; import Docker from 'dockerode'; import { SQL, sql } from 'drizzle-orm'; -import { char, check, int, mysqlTable, mysqlView, serial, text, varchar } from 'drizzle-orm/mysql-core'; +import { + bigint, + char, + check, + decimal, + double, + float, + int, + mediumint, + mysqlEnum, + mysqlTable, + mysqlView, + serial, + smallint, + text, + tinyint, + varchar, +} from 'drizzle-orm/mysql-core'; import * as fs from 'fs'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; import { introspectMySQLToFile } from 'tests/schemaDiffer'; import { v4 as uuid } from 'uuid'; -import { afterAll, beforeAll, expect, test } from 'vitest'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; let client: Connection; let mysqlContainer: Docker.Container; @@ -71,6 +89,12 @@ afterAll(async () => { await mysqlContainer?.stop().catch(console.error); }); +beforeEach(async () => { + await client.query(`drop database if exists \`drizzle\`;`); + await client.query(`create database \`drizzle\`;`); + await client.query(`use \`drizzle\`;`); +}); + if (!fs.existsSync('tests/introspect/mysql')) { fs.mkdirSync('tests/introspect/mysql'); } @@ -95,8 +119,6 @@ test('generated always column: link to another column', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('generated always column virtual: link to another column', async () => { @@ -120,8 +142,6 @@ test('generated always column virtual: link to another column', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('Default value of character type column: char', async () => { @@ -141,8 +161,6 @@ test('Default value of character type column: char', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('Default value of character type column: varchar', async () => { @@ -162,8 +180,6 @@ test('Default value of character type column: varchar', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('introspect checks', async () => { @@ -186,8 +202,6 @@ test('introspect checks', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('view #1', async () => { @@ -210,14 +224,9 @@ test('view #1', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop view some_view;`); - await client.query(`drop table users;`); }); test('view #2', async () => { - // await client.query(`drop view some_view;`); - const users = mysqlTable('some_users', { id: int('id') }); const testView = mysqlView('some_view', { id: int('id') }).algorithm('temptable').sqlSecurity('definer').as( sql`SELECT * FROM ${users}`, @@ -237,6 +246,74 @@ test('view #2', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); +}); + +test('handle float type', async () => { + const schema = { + table: mysqlTable('table', { + col1: float(), + col2: float({ precision: 2 }), + col3: float({ precision: 2, scale: 1 }), + }), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'handle-float-type', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('handle unsigned numerical types', async () => { + const schema = { + table: mysqlTable('table', { + col1: int({ unsigned: true }), + col2: tinyint({ unsigned: true }), + col3: smallint({ unsigned: true }), + col4: mediumint({ unsigned: true }), + col5: bigint({ mode: 'number', unsigned: true }), + col6: float({ unsigned: true }), + col7: float({ precision: 2, scale: 1, unsigned: true }), + col8: double({ unsigned: true }), + col9: double({ precision: 2, scale: 1, unsigned: true }), + col10: decimal({ unsigned: true }), + col11: decimal({ precision: 2, scale: 1, unsigned: true }), + }), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'handle-unsigned-numerical-types', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('instrospect strings with single quotes', async () => { + const schema = { + columns: mysqlTable('columns', { + enum: mysqlEnum('my_enum', ['escape\'s quotes "', 'escape\'s quotes 2 "']).default('escape\'s quotes "'), + text: text('text').default('escape\'s quotes " '), + varchar: varchar('varchar', { length: 255 }).default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'introspect-strings-with-single-quotes', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); - await client.query(`drop table some_users;`); + await client.query(`drop table columns;`); }); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index 6762ef27a..1d9f0f18c 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -255,8 +255,12 @@ test('instrospect all column types', async () => { time2: time('time2').defaultNow(), timestamp1: timestamp('timestamp1', { withTimezone: true, precision: 6 }).default(new Date()), timestamp2: timestamp('timestamp2', { withTimezone: true, precision: 6 }).defaultNow(), + timestamp3: timestamp('timestamp3', { withTimezone: true, precision: 6 }).default( + sql`timezone('utc'::text, now())`, + ), date1: date('date1').default('2024-01-01'), date2: date('date2').defaultNow(), + date3: date('date3').default(sql`CURRENT_TIMESTAMP`), uuid1: uuid('uuid1').default('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'), uuid2: uuid('uuid2').defaultRandom(), inet: inet('inet').default('127.0.0.1'), @@ -418,6 +422,29 @@ test('introspect enum with similar name to native type', async () => { expect(sqlStatements.length).toBe(0); }); +test('instrospect strings with single quotes', async () => { + const client = new PGlite(); + + const myEnum = pgEnum('my_enum', ['escape\'s quotes " ']); + const schema = { + enum_: myEnum, + columns: pgTable('columns', { + enum: myEnum('my_enum').default('escape\'s quotes " '), + text: text('text').default('escape\'s quotes " '), + varchar: varchar('varchar').default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-strings-with-single-quotes', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + test('introspect checks', async () => { const client = new PGlite(); diff --git a/drizzle-kit/tests/introspect/sqlite.test.ts b/drizzle-kit/tests/introspect/sqlite.test.ts index 89cdf590e..de13d4e81 100644 --- a/drizzle-kit/tests/introspect/sqlite.test.ts +++ b/drizzle-kit/tests/introspect/sqlite.test.ts @@ -56,6 +56,25 @@ test('generated always column virtual: link to another column', async () => { expect(sqlStatements.length).toBe(0); }); +test('instrospect strings with single quotes', async () => { + const sqlite = new Database(':memory:'); + + const schema = { + columns: sqliteTable('columns', { + text: text('text').default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectSQLiteToFile( + sqlite, + schema, + 'introspect-strings-with-single-quotes', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + test('introspect checks', async () => { const sqlite = new Database(':memory:'); diff --git a/drizzle-kit/tests/mysql.test.ts b/drizzle-kit/tests/mysql.test.ts index 183464ec0..881b05ef7 100644 --- a/drizzle-kit/tests/mysql.test.ts +++ b/drizzle-kit/tests/mysql.test.ts @@ -4,6 +4,7 @@ import { index, int, json, + mysqlEnum, mysqlSchema, mysqlTable, primaryKey, @@ -11,6 +12,7 @@ import { text, unique, uniqueIndex, + varchar, } from 'drizzle-orm/mysql-core'; import { expect, test } from 'vitest'; import { diffTestSchemasMysql } from './schemaDiffer'; @@ -533,6 +535,32 @@ test('drop index', async () => { expect(sqlStatements[0]).toBe('DROP INDEX `name_idx` ON `table`;'); }); +test('drop unique constraint', async () => { + const from = { + users: mysqlTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + uq: unique('name_uq').on(t.name), + }; + }, + ), + }; + + const to = { + users: mysqlTable('table', { + name: text('name'), + }), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe('ALTER TABLE `table` DROP INDEX `name_uq`;'); +}); + test('add table with indexes', async () => { const from = {}; @@ -578,6 +606,80 @@ test('add table with indexes', async () => { ]); }); +test('varchar and text default values escape single quotes', async (t) => { + const schema1 = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const schem2 = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + enum: mysqlEnum('enum', ["escape's quotes", "escape's quotes 2"]).default("escape's quotes"), + text: text('text').default("escape's quotes"), + varchar: varchar('varchar', { length: 255 }).default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemasMysql(schema1, schem2, []); + + expect(sqlStatements.length).toBe(3); + expect(sqlStatements[0]).toStrictEqual( + "ALTER TABLE `table` ADD `enum` enum('escape''s quotes','escape''s quotes 2') DEFAULT 'escape''s quotes';", + ); + expect(sqlStatements[1]).toStrictEqual( + "ALTER TABLE `table` ADD `text` text DEFAULT ('escape''s quotes');", + ); + expect(sqlStatements[2]).toStrictEqual( + "ALTER TABLE `table` ADD `varchar` varchar(255) DEFAULT 'escape''s quotes';", + ); +}); + +test('composite primary key', async () => { + const from = {}; + const to = { + table: mysqlTable('works_to_creators', { + workId: int('work_id').notNull(), + creatorId: int('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `works_to_creators` (\n\t`work_id` int NOT NULL,\n\t`creator_id` int NOT NULL,\n\t`classification` text NOT NULL,\n\tCONSTRAINT `works_to_creators_work_id_creator_id_classification_pk` PRIMARY KEY(`work_id`,`creator_id`,`classification`)\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + }), + }; + const to = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `table` ADD `name` text NOT NULL;', + 'ALTER TABLE `table` ADD CONSTRAINT `uq` UNIQUE(`name`);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; diff --git a/drizzle-kit/tests/pg-columns.test.ts b/drizzle-kit/tests/pg-columns.test.ts index cffeed3ed..ddd744a81 100644 --- a/drizzle-kit/tests/pg-columns.test.ts +++ b/drizzle-kit/tests/pg-columns.test.ts @@ -1,4 +1,4 @@ -import { integer, pgTable, primaryKey, serial, text, uuid } from 'drizzle-orm/pg-core'; +import { integer, pgTable, primaryKey, serial, text, uuid, varchar } from 'drizzle-orm/pg-core'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; @@ -456,3 +456,29 @@ test('add multiple constraints #3', async (t) => { expect(statements.length).toBe(6); }); + +test('varchar and text default values escape single quotes', async (t) => { + const schema1 = { + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const schem2 = { + table: pgTable('table', { + id: serial('id').primaryKey(), + text: text('text').default("escape's quotes"), + varchar: varchar('varchar').default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemas(schema1, schem2, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toStrictEqual( + 'ALTER TABLE "table" ADD COLUMN "text" text DEFAULT \'escape\'\'s quotes\';', + ); + expect(sqlStatements[1]).toStrictEqual( + 'ALTER TABLE "table" ADD COLUMN "varchar" varchar DEFAULT \'escape\'\'s quotes\';', + ); +}); diff --git a/drizzle-kit/tests/pg-enums.test.ts b/drizzle-kit/tests/pg-enums.test.ts index 99a3dca7e..2af691d46 100644 --- a/drizzle-kit/tests/pg-enums.test.ts +++ b/drizzle-kit/tests/pg-enums.test.ts @@ -1,4 +1,4 @@ -import { pgEnum, pgSchema, pgTable } from 'drizzle-orm/pg-core'; +import { integer, pgEnum, pgSchema, pgTable, serial } from 'drizzle-orm/pg-core'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; @@ -506,6 +506,77 @@ test('enums #18', async () => { }); }); +test('enums #19', async () => { + const myEnum = pgEnum('my_enum', ["escape's quotes"]); + + const from = {}; + + const to = { myEnum }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toStrictEqual( + 'CREATE TYPE "public"."my_enum" AS ENUM(\'escape\'\'s quotes\');', + ); +}); + +test('enums #20', async () => { + const myEnum = pgEnum('my_enum', ['one', 'two', 'three']); + + const from = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const to = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + col1: myEnum('col1'), + col2: integer('col2'), + }), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "col1" "my_enum";', + 'ALTER TABLE "table" ADD COLUMN "col2" integer;', + ]); +}); + +test('enums #21', async () => { + const myEnum = pgEnum('my_enum', ['one', 'two', 'three']); + + const from = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const to = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + col1: myEnum('col1').array(), + col2: integer('col2').array(), + }), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "col1" "my_enum"[];', + 'ALTER TABLE "table" ADD COLUMN "col2" integer[];', + ]); +}); + test('drop enum value', async () => { const enum1 = pgEnum('enum', ['value1', 'value2', 'value3']); diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index 1f2885f92..6ea6e472a 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -676,6 +676,106 @@ test('create table with tsvector', async () => { ]); }); +test('composite primary key', async () => { + const from = {}; + const to = { + table: pgTable('works_to_creators', { + workId: integer('work_id').notNull(), + creatorId: integer('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "works_to_creators" (\n\t"work_id" integer NOT NULL,\n\t"creator_id" integer NOT NULL,\n\t"classification" text NOT NULL,\n\tCONSTRAINT "works_to_creators_work_id_creator_id_classification_pk" PRIMARY KEY("work_id","creator_id","classification")\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + const to = { + table: pgTable('table', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "name" text NOT NULL;', + 'ALTER TABLE "table" ADD CONSTRAINT "uq" UNIQUE("name");', + ]); +}); + +test('alter composite primary key', async () => { + const from = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + col3: text('col3').notNull(), + }, (t) => ({ + pk: primaryKey({ + name: 'table_pk', + columns: [t.col1, t.col2], + }), + })), + }; + const to = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + col3: text('col3').notNull(), + }, (t) => ({ + pk: primaryKey({ + name: 'table_pk', + columns: [t.col2, t.col3], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" DROP CONSTRAINT "table_pk";\n--> statement-breakpoint\nALTER TABLE "table" ADD CONSTRAINT "table_pk" PRIMARY KEY("col2","col3");', + ]); +}); + +test('add index with op', async () => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }), + }; + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + nameIdx: index().using('gin', t.name.op('gin_trgm_ops')), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE INDEX IF NOT EXISTS "users_name_index" ON "users" USING gin ("name" gin_trgm_ops);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; diff --git a/drizzle-kit/tests/push/common.ts b/drizzle-kit/tests/push/common.ts index 0c679ca6f..627070f11 100644 --- a/drizzle-kit/tests/push/common.ts +++ b/drizzle-kit/tests/push/common.ts @@ -1,4 +1,4 @@ -import { afterAll, beforeAll, test } from 'vitest'; +import { afterAll, beforeAll, beforeEach, test } from 'vitest'; export interface DialectSuite { allTypes(context?: any): Promise; @@ -15,6 +15,8 @@ export interface DialectSuite { dropGeneratedConstraint(context?: any): Promise; alterGeneratedConstraint(context?: any): Promise; createTableWithGeneratedConstraint(context?: any): Promise; + createCompositePrimaryKey(context?: any): Promise; + renameTableWithCompositePrimaryKey(context?: any): Promise; case1(): Promise; } @@ -22,10 +24,13 @@ export const run = ( suite: DialectSuite, beforeAllFn?: (context: any) => Promise, afterAllFn?: (context: any) => Promise, + beforeEachFn?: (context: any) => Promise, ) => { let context: any = {}; beforeAll(beforeAllFn ? () => beforeAllFn(context) : () => {}); + beforeEach(beforeEachFn ? () => beforeEachFn(context) : () => {}); + test('No diffs for all database types', () => suite.allTypes(context)); test('Adding basic indexes', () => suite.addBasicIndexes(context)); test('Dropping basic index', () => suite.dropIndex(context)); @@ -45,6 +50,9 @@ export const run = ( // should ignore on push test('Alter generated constraint', () => suite.alterGeneratedConstraint(context)); test('Create table with generated column', () => suite.createTableWithGeneratedConstraint(context)); + test('Rename table with composite primary key', () => suite.renameTableWithCompositePrimaryKey(context)); + + test('Create composite primary key', () => suite.createCompositePrimaryKey(context)); afterAll(afterAllFn ? () => afterAllFn(context) : () => {}); }; diff --git a/drizzle-kit/tests/push/mysql.test.ts b/drizzle-kit/tests/push/mysql.test.ts index 5cad140be..6c7f5efc2 100644 --- a/drizzle-kit/tests/push/mysql.test.ts +++ b/drizzle-kit/tests/push/mysql.test.ts @@ -1,3 +1,4 @@ +import 'dotenv/config'; import Docker from 'dockerode'; import { SQL, sql } from 'drizzle-orm'; import { @@ -14,6 +15,7 @@ import { mediumint, mysqlEnum, mysqlTable, + primaryKey, serial, smallint, text, @@ -28,7 +30,7 @@ import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; import { diffTestSchemasMysql, diffTestSchemasPushMysql } from 'tests/schemaDiffer'; import { v4 as uuid } from 'uuid'; -import { expect } from 'vitest'; +import { expect, test } from 'vitest'; import { DialectSuite, run } from './common'; async function createDockerDB(context: any): Promise { @@ -662,6 +664,88 @@ const mysqlSuite: DialectSuite = { createTableWithGeneratedConstraint: function(context?: any): Promise { return {} as any; }, + createCompositePrimaryKey: async function(context: any): Promise { + const schema1 = {}; + + const schema2 = { + table: mysqlTable('table', { + col1: int('col1').notNull(), + col2: int('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table', + schema: undefined, + internals: { + indexes: {}, + tables: {}, + }, + compositePKs: ['table_col1_col2_pk;col1,col2'], + compositePkName: 'table_col1_col2_pk', + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + { name: 'col2', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + ], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `table` (\n\t`col1` int NOT NULL,\n\t`col2` int NOT NULL,\n\tCONSTRAINT `table_col1_col2_pk` PRIMARY KEY(`col1`,`col2`)\n);\n', + ]); + }, + renameTableWithCompositePrimaryKey: async function(context?: any): Promise { + const productsCategoriesTable = (tableName: string) => { + return mysqlTable(tableName, { + productId: varchar('product_id', { length: 10 }).notNull(), + categoryId: varchar('category_id', { length: 10 }).notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPushMysql( + context.client as Connection, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + 'drizzle', + false, + ); + + expect(sqlStatements).toStrictEqual([ + 'RENAME TABLE `products_categories` TO `products_to_categories`;', + 'ALTER TABLE `products_to_categories` DROP PRIMARY KEY;', + 'ALTER TABLE `products_to_categories` ADD PRIMARY KEY(`product_id`,`category_id`);', + ]); + + await context.client.query(`DROP TABLE \`products_categories\``); + }, }; run( @@ -696,4 +780,9 @@ run( await context.client?.end().catch(console.error); await context.mysqlContainer?.stop().catch(console.error); }, + async (context: any) => { + await context.client?.query(`drop database if exists \`drizzle\`;`); + await context.client?.query(`create database \`drizzle\`;`); + await context.client?.query(`use \`drizzle\`;`); + }, ); diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 51e6fe73a..44ec786b6 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -22,6 +22,7 @@ import { pgSequence, pgTable, pgView, + primaryKey, real, serial, smallint, @@ -914,6 +915,89 @@ const pgSuite: DialectSuite = { expect(shouldAskForApprove).toBeFalsy(); }, + async createCompositePrimaryKey() { + const client = new PGlite(); + + const schema1 = {}; + + const schema2 = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table', + schema: '', + compositePKs: ['col1,col2;table_col1_col2_pk'], + compositePkName: 'table_col1_col2_pk', + isRLSEnabled: false, + policies: [], + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'integer', primaryKey: false, notNull: true }, + { name: 'col2', type: 'integer', primaryKey: false, notNull: true }, + ], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "table" (\n\t"col1" integer NOT NULL,\n\t"col2" integer NOT NULL,\n\tCONSTRAINT "table_col1_col2_pk" PRIMARY KEY("col1","col2")\n);\n', + ]); + }, + + async renameTableWithCompositePrimaryKey() { + const client = new PGlite(); + + const productsCategoriesTable = (tableName: string) => { + return pgTable(tableName, { + productId: text('product_id').notNull(), + categoryId: text('category_id').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + false, + ['public'], + ); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "products_categories" RENAME TO "products_to_categories";', + 'ALTER TABLE "products_to_categories" DROP CONSTRAINT "products_categories_product_id_category_id_pk";', + 'ALTER TABLE "products_to_categories" ADD CONSTRAINT "products_to_categories_product_id_category_id_pk" PRIMARY KEY("product_id","category_id");', + ]); + }, + // async addVectorIndexes() { // const client = new PGlite(); @@ -2104,6 +2188,81 @@ test('drop check constraint', async () => { ]); }); +test('Column with same name as enum', async () => { + const client = new PGlite(); + const statusEnum = pgEnum('status', ['inactive', 'active', 'banned']); + + const schema1 = { + statusEnum, + table1: pgTable('table1', { + id: serial('id').primaryKey(), + }), + }; + + const schema2 = { + statusEnum, + table1: pgTable('table1', { + id: serial('id').primaryKey(), + status: statusEnum('status').default('inactive'), + }), + table2: pgTable('table2', { + id: serial('id').primaryKey(), + status: statusEnum('status').default('inactive'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table2', + schema: '', + compositePKs: [], + compositePkName: '', + isRLSEnabled: false, + policies: [], + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'id', type: 'serial', primaryKey: true, notNull: true }, + { + name: 'status', + type: 'status', + typeSchema: 'public', + primaryKey: false, + notNull: false, + default: "'inactive'", + }, + ], + }, + { + type: 'alter_table_add_column', + tableName: 'table1', + schema: '', + column: { + name: 'status', + type: 'status', + typeSchema: 'public', + primaryKey: false, + notNull: false, + default: "'inactive'", + }, + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "table2" (\n\t"id" serial PRIMARY KEY NOT NULL,\n\t"status" "status" DEFAULT \'inactive\'\n);\n', + 'ALTER TABLE "table1" ADD COLUMN "status" "status" DEFAULT \'inactive\';', + ]); +}); + test('db has checks. Push with same names', async () => { const client = new PGlite(); diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index 5ac6f996c..dd1d88fe3 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -9,6 +9,7 @@ import { int, integer, numeric, + primaryKey, real, sqliteTable, sqliteView, @@ -1534,3 +1535,79 @@ test('alter view ".as"', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('create composite primary key', async (t) => { + const client = new Database(':memory:'); + + const schema1 = {}; + + const schema2 = { + table: sqliteTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { + statements, + sqlStatements, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([{ + type: 'sqlite_create_table', + tableName: 'table', + compositePKs: [['col1', 'col2']], + uniqueConstraints: [], + referenceData: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'integer', primaryKey: false, notNull: true, autoincrement: false }, + { name: 'col2', type: 'integer', primaryKey: false, notNull: true, autoincrement: false }, + ], + }]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `table` (\n\t`col1` integer NOT NULL,\n\t`col2` integer NOT NULL,\n\tPRIMARY KEY(`col1`, `col2`)\n);\n', + ]); +}); + +test('rename table with composite primary key', async () => { + const client = new Database(':memory:'); + + const productsCategoriesTable = (tableName: string) => { + return sqliteTable(tableName, { + productId: text('product_id').notNull(), + categoryId: text('category_id').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + false, + ); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `products_categories` RENAME TO `products_to_categories`;', + ]); +}); diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index b7b4c7f6b..0cb34c220 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -1025,3 +1025,25 @@ test('recreate table with nested references', async (t) => { expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); + +test('text default values escape single quotes', async (t) => { + const schema1 = { + table: sqliteTable('table', { + id: integer('id').primaryKey(), + }), + }; + + const schem2 = { + table: sqliteTable('table', { + id: integer('id').primaryKey(), + text: text('text').default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(schema1, schem2, []); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toStrictEqual( + "ALTER TABLE `table` ADD `text` text DEFAULT 'escape''s quotes';", + ); +}); diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index 8d8eae298..651c3633c 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -418,6 +418,50 @@ test('add table with indexes', async () => { ]); }); +test('composite primary key', async () => { + const from = {}; + const to = { + table: sqliteTable('works_to_creators', { + workId: int('work_id').notNull(), + creatorId: int('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `works_to_creators` (\n\t`work_id` integer NOT NULL,\n\t`creator_id` integer NOT NULL,\n\t`classification` text NOT NULL,\n\tPRIMARY KEY(`work_id`, `creator_id`, `classification`)\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: sqliteTable('table', { + id: int('id').primaryKey(), + }), + }; + const to = { + table: sqliteTable('table', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `table` ADD `name` text NOT NULL;', + 'CREATE UNIQUE INDEX `uq` ON `table` (`name`);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index e2b17a1af..598ee9a1e 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.36.0", + "version": "0.36.1", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -203,4 +203,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} +} \ No newline at end of file diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index 1e5f78679..67cefb531 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -20,10 +20,11 @@ export class MySqlDecimalBuilder< > extends MySqlColumnBuilderWithAutoIncrement { static override readonly [entityKind]: string = 'MySqlDecimalBuilder'; - constructor(name: T['name'], precision?: number, scale?: number) { + constructor(name: T['name'], config: MySqlDecimalConfig | undefined) { super(name, 'string', 'MySqlDecimal'); - this.config.precision = precision; - this.config.scale = scale; + this.config.precision = config?.precision; + this.config.scale = config?.scale; + this.config.unsigned = config?.unsigned; } /** @internal */ @@ -44,21 +45,26 @@ export class MySqlDecimal> readonly precision: number | undefined = this.config.precision; readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; getSQLType(): string { + let type = ''; if (this.precision !== undefined && this.scale !== undefined) { - return `decimal(${this.precision},${this.scale})`; + type += `decimal(${this.precision},${this.scale})`; } else if (this.precision === undefined) { - return 'decimal'; + type += 'decimal'; } else { - return `decimal(${this.precision})`; + type += `decimal(${this.precision})`; } + type = type === 'decimal(10,0)' || type === 'decimal(10)' ? 'decimal' : type; + return this.unsigned ? `${type} unsigned` : type; } } export interface MySqlDecimalConfig { precision?: number; scale?: number; + unsigned?: boolean; } export function decimal(): MySqlDecimalBuilderInitial<''>; @@ -71,5 +77,5 @@ export function decimal( ): MySqlDecimalBuilderInitial; export function decimal(a?: string | MySqlDecimalConfig, b: MySqlDecimalConfig = {}) { const { name, config } = getColumnNameAndConfig(a, b); - return new MySqlDecimalBuilder(name, config.precision, config.scale); + return new MySqlDecimalBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index c9f95fd04..dfe5fca2e 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -24,6 +24,7 @@ export class MySqlDoubleBuilder> { static override readonly [entityKind]: string = 'MySqlDouble'; - precision: number | undefined = this.config.precision; - scale: number | undefined = this.config.scale; + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; getSQLType(): string { + let type = ''; if (this.precision !== undefined && this.scale !== undefined) { - return `double(${this.precision},${this.scale})`; + type += `double(${this.precision},${this.scale})`; } else if (this.precision === undefined) { - return 'double'; + type += 'double'; } else { - return `double(${this.precision})`; + type += `double(${this.precision})`; } + return this.unsigned ? `${type} unsigned` : type; } } export interface MySqlDoubleConfig { precision?: number; scale?: number; + unsigned?: boolean; } export function double(): MySqlDoubleBuilderInitial<''>; diff --git a/drizzle-orm/src/mysql-core/columns/float.ts b/drizzle-orm/src/mysql-core/columns/float.ts index d7c3e586b..12ebd3e74 100644 --- a/drizzle-orm/src/mysql-core/columns/float.ts +++ b/drizzle-orm/src/mysql-core/columns/float.ts @@ -2,6 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ @@ -15,12 +16,15 @@ export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ }>; export class MySqlFloatBuilder> - extends MySqlColumnBuilderWithAutoIncrement + extends MySqlColumnBuilderWithAutoIncrement { static override readonly [entityKind]: string = 'MySqlFloatBuilder'; - constructor(name: T['name']) { + constructor(name: T['name'], config: MySqlFloatConfig | undefined) { super(name, 'number', 'MySqlFloat'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + this.config.unsigned = config?.unsigned; } /** @internal */ @@ -31,16 +35,43 @@ export class MySqlFloatBuilder> extends MySqlColumnWithAutoIncrement { +export class MySqlFloat> + extends MySqlColumnWithAutoIncrement +{ static override readonly [entityKind]: string = 'MySqlFloat'; + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; + getSQLType(): string { - return 'float'; + let type = ''; + if (this.precision !== undefined && this.scale !== undefined) { + type += `float(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + type += 'float'; + } else { + type += `float(${this.precision})`; + } + return this.unsigned ? `${type} unsigned` : type; } } +export interface MySqlFloatConfig { + precision?: number; + scale?: number; + unsigned?: boolean; +} + export function float(): MySqlFloatBuilderInitial<''>; -export function float(name: TName): MySqlFloatBuilderInitial; -export function float(name?: string) { - return new MySqlFloatBuilder(name ?? ''); +export function float( + config?: MySqlFloatConfig, +): MySqlFloatBuilderInitial<''>; +export function float( + name: TName, + config?: MySqlFloatConfig, +): MySqlFloatBuilderInitial; +export function float(a?: string | MySqlFloatConfig, b?: MySqlFloatConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new MySqlFloatBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index 95f67827b..63c4b903e 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -17,7 +17,7 @@ import type { } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, Query } from '~/sql/sql.ts'; +import type { ColumnsSelection, Placeholder, Query } from '~/sql/sql.ts'; import { SQL, View } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; @@ -811,7 +811,7 @@ export abstract class MySqlSelectQueryBuilderBase< * await db.select().from(people).limit(10); * ``` */ - limit(limit: number): MySqlSelectWithout { + limit(limit: number | Placeholder): MySqlSelectWithout { if (this.config.setOperators.length > 0) { this.config.setOperators.at(-1)!.limit = limit; } else { @@ -836,7 +836,7 @@ export abstract class MySqlSelectQueryBuilderBase< * await db.select().from(people).offset(10).limit(10); * ``` */ - offset(offset: number): MySqlSelectWithout { + offset(offset: number | Placeholder): MySqlSelectWithout { if (this.config.setOperators.length > 0) { this.config.setOperators.at(-1)!.offset = offset; } else { diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index b7cd90be1..22deb3a84 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -41,8 +41,8 @@ export class SQLiteBigInt> return 'blob'; } - override mapFromDriverValue(value: Buffer): bigint { - return BigInt(value.toString()); + override mapFromDriverValue(value: Buffer | Uint8Array): bigint { + return BigInt(Buffer.isBuffer(value) ? value.toString() : String.fromCodePoint(...value)); } override mapToDriverValue(value: bigint): Buffer { @@ -87,8 +87,8 @@ export class SQLiteBlobJson return 'blob'; } - override mapFromDriverValue(value: Buffer): T['data'] { - return JSON.parse(value.toString()); + override mapFromDriverValue(value: Buffer | Uint8Array): T['data'] { + return JSON.parse(Buffer.isBuffer(value) ? value.toString() : String.fromCodePoint(...value)); } override mapToDriverValue(value: T['data']): Buffer { diff --git a/drizzle-orm/src/supabase/rls.ts b/drizzle-orm/src/supabase/rls.ts index 20fea7355..d5f813ac6 100644 --- a/drizzle-orm/src/supabase/rls.ts +++ b/drizzle-orm/src/supabase/rls.ts @@ -1,4 +1,4 @@ -import { bigserial, pgSchema, text, uuid } from '~/pg-core/index.ts'; +import { bigserial, pgSchema, text, timestamp, uuid, varchar } from '~/pg-core/index.ts'; import { pgRole } from '~/pg-core/roles.ts'; import { sql } from '~/sql/sql.ts'; @@ -13,6 +13,13 @@ const auth = pgSchema('auth'); export const authUsers = auth.table('users', { id: uuid().primaryKey().notNull(), + email: varchar({ length: 255 }), + phone: text().unique(), + emailConfirmedAt: timestamp('email_confirmed_at', { withTimezone: true }), + phoneConfirmedAt: timestamp('phone_confirmed_at', { withTimezone: true }), + lastSignInAt: timestamp('last_sign_in_at', { withTimezone: true }), + createdAt: timestamp('created_at', { withTimezone: true }), + updatedAt: timestamp('updated_at', { withTimezone: true }), }); /* ------------------------------ realtime schema; ------------------------------- */ diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index aca5c63d7..adc8e8eb8 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -864,6 +864,9 @@ Expect< enum: mysqlEnum('enum', ['a', 'b', 'c']), enumdef: mysqlEnum('enumdef', ['a', 'b', 'c']).default('a'), float: float('float'), + float2: float('float2', { precision: 10 }), + float3: float('float3', { scale: 2 }), + float4: float('float4', { precision: 10, scale: 2 }), floatdef: float('floatdef').default(0), int: int('int'), int2: int('int2', { unsigned: true }), @@ -961,6 +964,9 @@ Expect< enum: mysqlEnum(['a', 'b', 'c']), enumdef: mysqlEnum(['a', 'b', 'c']).default('a'), float: float(), + float2: float({ precision: 10 }), + float3: float({ scale: 2 }), + float4: float({ precision: 10, scale: 2 }), floatdef: float().default(0), int: int(), int2: int({ unsigned: true }), diff --git a/integration-tests/tests/bun/sqlite.test.ts b/integration-tests/tests/bun/sqlite.test.ts index 0065b1928..c6ce9d4d1 100644 --- a/integration-tests/tests/bun/sqlite.test.ts +++ b/integration-tests/tests/bun/sqlite.test.ts @@ -1,41 +1,34 @@ -/// import { Database } from 'bun:sqlite'; -import { DefaultLogger, sql } from 'drizzle-orm'; +import { beforeAll, beforeEach, expect, test } from 'bun:test'; +import { sql } from 'drizzle-orm'; import type { BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite'; import { drizzle } from 'drizzle-orm/bun-sqlite'; import { blob, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { suite } from 'uvu'; -import * as assert from 'uvu/assert'; const usersTable = sqliteTable('users', { id: integer('id').primaryKey(), name: text('name').notNull(), verified: integer('verified').notNull().default(0), json: blob('json', { mode: 'json' }).$type(), - createdAt: integer('created_at', { mode: 'timestamp' }).notNull().defaultNow(), + bigInt: blob('big_int', { mode: 'bigint' }), + createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull().default(sql`strftime('%s', 'now')`), }); -interface Context { - db: BunSQLiteDatabase; -} +let db: BunSQLiteDatabase; -const test = suite('sqlite-bun'); - -test.before((ctx) => { +beforeAll(async () => { try { const dbPath = process.env['SQLITE_DB_PATH'] ?? ':memory:'; const client = new Database(dbPath); - ctx.db = drizzle(client, { logger: new DefaultLogger() }); + db = drizzle(client); } catch (e) { console.error(e); } }); -test.before.each((ctx) => { +beforeEach(async () => { try { - const { db } = ctx; - db.run(sql`drop table if exists ${usersTable}`); db.run(sql` create table ${usersTable} ( @@ -43,7 +36,8 @@ test.before.each((ctx) => { name text not null, verified integer not null default 0, json blob, - created_at text not null default (strftime('%s', 'now')) + big_int blob, + created_at integer not null default (strftime('%s', 'now')) ) `); } catch (e) { @@ -51,34 +45,30 @@ test.before.each((ctx) => { } }); -test.skip('select large integer', async (ctx) => { +test.skip('select large integer', () => { const a = 1667476703000; - const res = await ctx.db.all<{ a: number }>(sql`select ${sql.raw(String(a))} as a`); + const res = db.all<{ a: number }>(sql`select ${sql.raw(String(a))} as a`); const result = res[0]!; - assert.equal(result.a, a); + expect(result.a).toEqual(a); }); -test('select all fields', (ctx) => { - const { db } = ctx; - +test('select all fields', () => { const now = Date.now(); db.insert(usersTable).values({ name: 'John' }).run(); const result = db.select().from(usersTable).all()[0]!; - assert.ok(result.createdAt instanceof Date, 'createdAt is a Date'); // eslint-disable-line no-instanceof/no-instanceof - assert.ok( - Math.abs(result.createdAt.getTime() - now) < 100, - `${result.createdAt.getTime()} is within 100ms of ${now}`, - ); - assert.equal( - result, - { id: 1, name: 'John', verified: 0, json: null, createdAt: result.createdAt }, - 'result is correct', - ); + expect(result.createdAt).toBeInstanceOf(Date); + expect(Math.abs(result.createdAt.getTime() - now)).toBeLessThan(100); + expect(result).toEqual({ id: 1, name: 'John', verified: 0, json: null, createdAt: result.createdAt, bigInt: null }); }); -test.run(); +test('select bigint', () => { + db.insert(usersTable).values({ name: 'John', bigInt: BigInt(100) }).run(); + const result = db.select({ bigInt: usersTable.bigInt }).from(usersTable).all()[0]!; + + expect(result).toEqual({ bigInt: BigInt(100) }); +}); // test.serial('select partial', (t) => { // const { db } = t.context; diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 45b96f391..5dde42934 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -19,7 +19,6 @@ import { min, Name, notInArray, - placeholder, sql, sum, sumDistinct, @@ -1184,7 +1183,7 @@ export function tests(driver?: string) { const stmt = db.insert(usersTable).values({ verified: true, - name: placeholder('name'), + name: sql.placeholder('name'), }).prepare(); for (let i = 0; i < 10; i++) { @@ -1219,13 +1218,75 @@ export function tests(driver?: string) { id: usersTable.id, name: usersTable.name, }).from(usersTable) - .where(eq(usersTable.id, placeholder('id'))) + .where(eq(usersTable.id, sql.placeholder('id'))) .prepare(); const result = await stmt.execute({ id: 1 }); expect(result).toEqual([{ id: 1, name: 'John' }]); }); + test('prepared statement with placeholder in .limit', async (ctx) => { + const { db } = ctx.mysql; + + await db.insert(usersTable).values({ name: 'John' }); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .limit(sql.placeholder('limit')) + .prepare(); + + const result = await stmt.execute({ id: 1, limit: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + expect(result).toHaveLength(1); + }); + + test('prepared statement with placeholder in .offset', async (ctx) => { + const { db } = ctx.mysql; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .limit(sql.placeholder('limit')) + .offset(sql.placeholder('offset')) + .prepare(); + + const result = await stmt.execute({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + }); + + test('prepared statement built using $dynamic', async (ctx) => { + const { db } = ctx.mysql; + + function withLimitOffset(qb: any) { + return qb.limit(sql.placeholder('limit')).offset(sql.placeholder('offset')); + } + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .$dynamic(); + withLimitOffset(stmt).prepare('stmt_limit'); + + const result = await stmt.execute({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + expect(result).toHaveLength(1); + }); + test('migrator', async (ctx) => { const { db } = ctx.mysql; diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 3b3e4cb4d..c7f4b9be7 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -1260,6 +1260,29 @@ export function tests() { expect(result).toEqual([{ id: 2, name: 'John1' }]); }); + test('prepared statement built using $dynamic', async (ctx) => { + const { db } = ctx.pg; + + function withLimitOffset(qb: any) { + return qb.limit(sql.placeholder('limit')).offset(sql.placeholder('offset')); + } + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .$dynamic(); + withLimitOffset(stmt).prepare('stmt_limit'); + + const result = await stmt.execute({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + expect(result).toHaveLength(1); + }); + // TODO change tests to new structure test('Query check: Insert all defaults in 1 row', async (ctx) => { const { db } = ctx.pg; @@ -5041,5 +5064,29 @@ export function tests() { { count: 3 }, ]); }); + + test('insert multiple rows into table with generated identity column', async (ctx) => { + const { db } = ctx.pg; + + const users = pgTable('users', { + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} ("id" integer generated always as identity primary key, "name" text)`); + + const result = await db.insert(users).values([ + { name: 'John' }, + { name: 'Jane' }, + { name: 'Bob' }, + ]).returning(); + + expect(result).toEqual([ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Bob' }, + ]); + }); }); } diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 83beff74d..a20ce5bbf 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -906,6 +906,68 @@ export function tests() { expect(result).toEqual([{ id: 1, name: 'John' }]); }); + test('prepared statement with placeholder in .limit', async (ctx) => { + const { db } = ctx.sqlite; + + await db.insert(usersTable).values({ name: 'John' }).run(); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .limit(sql.placeholder('limit')) + .prepare(); + + const result = await stmt.all({ id: 1, limit: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + expect(result).toHaveLength(1); + }); + + test('prepared statement with placeholder in .offset', async (ctx) => { + const { db } = ctx.sqlite; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]).run(); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .limit(sql.placeholder('limit')) + .offset(sql.placeholder('offset')) + .prepare(); + + const result = await stmt.all({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + }); + + test('prepared statement built using $dynamic', async (ctx) => { + const { db } = ctx.sqlite; + + function withLimitOffset(qb: any) { + return qb.limit(sql.placeholder('limit')).offset(sql.placeholder('offset')); + } + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]).run(); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .$dynamic(); + withLimitOffset(stmt).prepare('stmt_limit'); + + const result = await stmt.all({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + expect(result).toHaveLength(1); + }); + test('select with group by as field', async (ctx) => { const { db } = ctx.sqlite; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed86a8353..468f12ca6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,7 +40,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -73,7 +73,7 @@ importers: version: 0.8.16(typescript@5.6.3) tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3))(typescript@5.6.3) tsx: specifier: ^4.10.5 version: 4.10.5 @@ -141,6 +141,9 @@ importers: '@types/json-diff': specifier: ^1.0.3 version: 1.0.3 + '@types/micromatch': + specifier: ^4.0.9 + version: 4.0.9 '@types/minimatch': specifier: ^5.1.2 version: 5.1.2 @@ -231,6 +234,9 @@ importers: json-diff: specifier: 1.0.6 version: 1.0.6 + micromatch: + specifier: ^4.0.8 + version: 4.0.8 minimatch: specifier: ^7.4.3 version: 7.4.6 @@ -240,6 +246,9 @@ importers: node-fetch: specifier: ^3.3.2 version: 3.3.2 + ohm-js: + specifier: ^17.1.0 + version: 17.1.0 pg: specifier: ^8.11.5 version: 8.11.5 @@ -2001,9 +2010,11 @@ packages: '@esbuild-kit/core-utils@3.1.0': resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-kit/esm-loader@2.5.5': resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-plugins/node-globals-polyfill@0.2.3': resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} @@ -2990,10 +3001,12 @@ packages: '@humanwhocodes/config-array@0.11.11': resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.13': resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} @@ -3006,9 +3019,11 @@ packages: '@humanwhocodes/object-schema@1.2.1': resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.1': resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} @@ -4012,6 +4027,9 @@ packages: '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + '@types/braces@3.0.4': + resolution: {integrity: sha512-0WR3b8eaISjEW7RpZnclONaLFDf7buaowRHdqLp4vLj54AsSAYWfh3DRbfiYJY9XDxMgx1B4sE1Afw2PGpuHOA==} + '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} @@ -4066,6 +4084,9 @@ packages: '@types/jsonfile@6.1.4': resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + '@types/micromatch@4.0.9': + resolution: {integrity: sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg==} + '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} @@ -4556,6 +4577,7 @@ packages: are-we-there-yet@3.0.1: resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -4780,10 +4802,6 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -5971,16 +5989,19 @@ packages: eslint@8.50.0: resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.53.0: resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true esm@3.2.25: @@ -6186,10 +6207,6 @@ packages: file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -6347,6 +6364,7 @@ packages: gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. generate-function@2.3.1: resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} @@ -7166,10 +7184,12 @@ packages: libsql@0.3.19: resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] libsql@0.4.1: resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -7549,14 +7569,14 @@ packages: engines: {node: '>=18'} hasBin: true - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - micromatch@4.0.7: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -7862,6 +7882,7 @@ packages: npmlog@6.0.2: resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. npx-import@1.1.4: resolution: {integrity: sha512-3ShymTWOgqGyNlh5lMJAejLuIv3W1K3fbI5Ewc6YErZU3Sp0PqsNs8UIU1O8z5+KVl/Du5ag56Gza9vdorGEoA==} @@ -7913,6 +7934,10 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + ohm-js@17.1.0: + resolution: {integrity: sha512-xc3B5dgAjTBQGHaH7B58M2Pmv6WvzrJ/3/7LeUzXNg0/sY3jQPdSd/S2SstppaleO77rifR1tyhdfFGNIwxf2Q==} + engines: {node: '>=0.12.1'} + oidc-token-hash@5.0.3: resolution: {integrity: sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==} engines: {node: ^10.13.0 || >=12.0.0} @@ -8682,6 +8707,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@5.0.0: @@ -10245,7 +10271,7 @@ snapshots: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10386,7 +10412,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10646,58 +10672,13 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sts@3.569.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.569.0 '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 '@aws-sdk/middleware-logger': 3.568.0 '@aws-sdk/middleware-recursion-detection': 3.567.0 @@ -10881,23 +10862,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) @@ -10921,7 +10885,7 @@ snapshots: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10965,25 +10929,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 @@ -11010,7 +10955,7 @@ snapshots: '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -11123,17 +11068,9 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': dependencies: - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 @@ -11159,7 +11096,7 @@ snapshots: '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -13239,7 +13176,7 @@ snapshots: find-up: 5.0.0 find-yarn-workspace-root: 2.0.0 js-yaml: 3.14.1 - micromatch: 4.0.7 + micromatch: 4.0.8 npm-package-arg: 7.0.0 ora: 3.4.0 split: 1.0.1 @@ -14731,6 +14668,8 @@ snapshots: '@types/connect': 3.4.38 '@types/node': 20.12.12 + '@types/braces@3.0.4': {} + '@types/connect@3.4.38': dependencies: '@types/node': 20.12.12 @@ -14798,6 +14737,10 @@ snapshots: dependencies: '@types/node': 20.12.12 + '@types/micromatch@4.0.9': + dependencies: + '@types/braces': 3.0.4 + '@types/mime@1.3.5': {} '@types/minimatch@5.1.2': {} @@ -15737,10 +15680,6 @@ snapshots: dependencies: balanced-match: 1.0.2 - braces@3.0.2: - dependencies: - fill-range: 7.0.1 - braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -16493,7 +16432,7 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 '@cloudflare/workers-types': 4.20241004.0 @@ -17456,7 +17395,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.7 fast-glob@3.3.2: dependencies: @@ -17526,10 +17465,6 @@ snapshots: file-uri-to-path@1.0.0: {} - fill-range@7.0.1: - dependencies: - to-regex-range: 5.0.1 - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -17585,7 +17520,7 @@ snapshots: find-yarn-workspace-root@2.0.0: dependencies: - micromatch: 4.0.7 + micromatch: 4.0.8 flat-cache@3.1.0: dependencies: @@ -18299,7 +18234,7 @@ snapshots: '@types/stack-utils': 2.0.3 chalk: 4.1.2 graceful-fs: 4.2.11 - micromatch: 4.0.7 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 @@ -18393,7 +18328,7 @@ snapshots: chalk: 4.1.2 flow-parser: 0.236.0 graceful-fs: 4.2.11 - micromatch: 4.0.7 + micromatch: 4.0.8 neo-async: 2.6.2 node-dir: 0.1.17 recast: 0.21.5 @@ -18903,7 +18838,7 @@ snapshots: graceful-fs: 4.2.11 invariant: 2.2.4 jest-worker: 29.7.0 - micromatch: 4.0.7 + micromatch: 4.0.8 node-abort-controller: 3.1.1 nullthrows: 1.1.1 walker: 1.0.8 @@ -19027,12 +18962,12 @@ snapshots: - supports-color - utf-8-validate - micromatch@4.0.5: + micromatch@4.0.7: dependencies: - braces: 3.0.2 + braces: 3.0.3 picomatch: 2.3.1 - micromatch@4.0.7: + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 @@ -19403,6 +19338,8 @@ snapshots: obuf@1.1.2: {} + ohm-js@17.1.0: {} + oidc-token-hash@5.0.3: {} on-finished@2.3.0: @@ -19715,7 +19652,7 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3)): dependencies: lilconfig: 2.1.0 yaml: 2.3.1 @@ -20986,7 +20923,7 @@ snapshots: tslib@2.6.2: {} - tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3): + tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3))(typescript@5.6.3): dependencies: bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 @@ -20996,7 +20933,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3)) resolve-from: 5.0.0 rollup: 3.27.2 source-map: 0.8.0-beta.0 From 83daf2d5cf023112de878bc2249ee2c41a2a5b1b Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 6 Nov 2024 21:27:32 +0200 Subject: [PATCH 303/492] Dprint --- drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index e45f7dbc5..1c911f23f 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -141,4 +141,4 @@ "default": "./api.mjs" } } -} \ No newline at end of file +} diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 598ee9a1e..b2b204ead 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -203,4 +203,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} \ No newline at end of file +} From 6b8676e32102864847c00be0402b720227b2d8dc Mon Sep 17 00:00:00 2001 From: apeng-singlestore <127370261+apeng-singlestore@users.noreply.github.com> Date: Wed, 6 Nov 2024 13:32:32 -0800 Subject: [PATCH 304/492] Add drizzleIntegration query header Added query header for future logging of integration usage --- drizzle-orm/src/singlestore/session.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/singlestore/session.ts b/drizzle-orm/src/singlestore/session.ts index e03171262..dea4c1d7f 100644 --- a/drizzle-orm/src/singlestore/session.ts +++ b/drizzle-orm/src/singlestore/session.ts @@ -63,8 +63,9 @@ export class SingleStoreDriverPreparedQuery Date: Thu, 7 Nov 2024 12:39:32 +0200 Subject: [PATCH 305/492] Add a few test changes Using database for tests and remove datetime and json from singlestore allTypes test on push --- .../tests/push/singlestore-push.test.ts | 65 +-- drizzle-kit/tests/push/singlestore.test.ts | 386 ++---------------- drizzle-kit/vitest.config.ts | 13 +- 3 files changed, 80 insertions(+), 384 deletions(-) diff --git a/drizzle-kit/tests/push/singlestore-push.test.ts b/drizzle-kit/tests/push/singlestore-push.test.ts index 5db899fc0..79eeebbb5 100644 --- a/drizzle-kit/tests/push/singlestore-push.test.ts +++ b/drizzle-kit/tests/push/singlestore-push.test.ts @@ -18,7 +18,7 @@ async function createDockerDB(): Promise { const pullStream = await docker.pull(image); await new Promise((resolve, reject) => - docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) ); singlestoreContainer = await docker.createContainer({ @@ -40,7 +40,7 @@ async function createDockerDB(): Promise { } beforeAll(async () => { - const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(); + const connectionString = process.env.MYSQL_CONNECTION_STRING ?? (await createDockerDB()); const sleep = 1000; let timeLeft = 20000; @@ -64,6 +64,9 @@ beforeAll(async () => { await singlestoreContainer?.stop().catch(console.error); throw lastError; } + + await client.query('CREATE DATABASE drizzle;'); + await client.query('USE drizzle;'); }); afterAll(async () => { @@ -103,7 +106,7 @@ test('add check constraint to table', async () => { type: 'create_check_constraint', tableName: 'test', schema: '', - data: 'some_check1;\`test\`.\`values\` < 100', + data: 'some_check1;`test`.`values` < 100', }, { data: "some_check2;'test' < 100", @@ -113,7 +116,7 @@ test('add check constraint to table', async () => { }, ]); expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE \`test\` ADD CONSTRAINT \`some_check1\` CHECK (\`test\`.\`values\` < 100);', + 'ALTER TABLE `test` ADD CONSTRAINT `some_check1` CHECK (`test`.`values` < 100);', `ALTER TABLE \`test\` ADD CONSTRAINT \`some_check2\` CHECK ('test' < 100);`, ]); @@ -158,7 +161,7 @@ test('drop check constraint to table', async () => { }, ]); expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE \`test\` DROP CONSTRAINT \`some_check1\`;', + 'ALTER TABLE `test` DROP CONSTRAINT `some_check1`;', `ALTER TABLE \`test\` DROP CONSTRAINT \`some_check2\`;`, ]); @@ -218,7 +221,7 @@ test('create view', async () => { expect(statements).toStrictEqual([ { - definition: 'select \`id\` from \`test\`', + definition: 'select `id` from `test`', name: 'view', type: 'singlestore_create_view', replace: false, @@ -265,9 +268,7 @@ test('drop view', async () => { type: 'drop_view', }, ]); - expect(sqlStatements).toStrictEqual([ - 'DROP VIEW \`view\`;', - ]); + expect(sqlStatements).toStrictEqual(['DROP VIEW `view`;']); await client.query(`DROP TABLE \`test\`;`); await client.query(`DROP VIEW \`view\`;`); }); @@ -279,7 +280,12 @@ test('alter view ".as"', async () => { const schema1 = { test: table, - view: singlestoreView('view').as((qb) => qb.select().from(table).where(sql`${table.id} = 1`)), + view: singlestoreView('view').as((qb) => + qb + .select() + .from(table) + .where(sql`${table.id} = 1`) + ), }; const schema2 = { @@ -310,26 +316,37 @@ test('alter meta options with distinct in definition', async () => { const schema1 = { test: table, - view: singlestoreView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('merge').as(( - qb, - ) => qb.selectDistinct().from(table).where(sql`${table.id} = 1`)), + view: singlestoreView('view') + .withCheckOption('cascaded') + .sqlSecurity('definer') + .algorithm('merge') + .as((qb) => + qb + .selectDistinct() + .from(table) + .where(sql`${table.id} = 1`) + ), }; const schema2 = { test: table, - view: singlestoreView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('undefined').as((qb) => - qb.selectDistinct().from(table) - ), + view: singlestoreView('view') + .withCheckOption('cascaded') + .sqlSecurity('definer') + .algorithm('undefined') + .as((qb) => qb.selectDistinct().from(table)), }; - await expect(diffTestSchemasPushSingleStore( - client, - schema1, - schema2, - [], - 'drizzle', - false, - )).rejects.toThrowError(); + await expect( + diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ), + ).rejects.toThrowError(); await client.query(`DROP TABLE \`test\`;`); }); diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 182c89b66..798d018f6 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -38,7 +38,7 @@ async function createDockerDB(context: any): Promise { const pullStream = await docker.pull(image); await new Promise((resolve, reject) => - docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) ); context.singlestoreContainer = await docker.createContainer({ @@ -83,15 +83,15 @@ const singlestoreSuite: DialectSuite = { 'h', ), }), - allDateTimes: singlestoreTable('all_date_times', { - simple: datetime('simple', { mode: 'string', fsp: 1 }), - columnNotNull: datetime('column_not_null', { - mode: 'string', - }).notNull(), - columnDefault: datetime('column_default', { mode: 'string' }).default( - '2023-03-01 14:05:29', - ), - }), + // allDateTimes: singlestoreTable("all_date_times", { + // simple: datetime("simple", { mode: "string", fsp: 1 }), + // columnNotNull: datetime("column_not_null", { + // mode: "string", + // }).notNull(), + // columnDefault: datetime("column_default", { mode: "string" }).default( + // "2023-03-01 14:05:29" + // ), + // }), allDates: singlestoreTable('all_dates', { simple: date('simple', { mode: 'string' }), column_not_null: date('column_not_null', { mode: 'string' }).notNull(), @@ -150,17 +150,17 @@ const singlestoreSuite: DialectSuite = { columnDefaultSql: int('column_default_sql').default(101), }), - allJsons: singlestoreTable('all_jsons', { - columnDefaultObject: json('column_default_object') - .default({ hello: 'world world' }) - .notNull(), - columnDefaultArray: json('column_default_array').default({ - hello: { 'world world': ['foo', 'bar'] }, - foo: 'bar', - fe: 23, - }), - column: json('column'), - }), + // allJsons: singlestoreTable("all_jsons", { + // columnDefaultObject: json("column_default_object") + // .default({ hello: "world world" }) + // .notNull(), + // columnDefaultArray: json("column_default_array").default({ + // hello: { "world world": ["foo", "bar"] }, + // foo: "bar", + // fe: 23, + // }), + // column: json("column"), + // }), allMInts: singlestoreTable('all_m_ints', { simple: mediumint('simple'), @@ -318,346 +318,16 @@ const singlestoreSuite: DialectSuite = { return {} as any; }, addGeneratedColumn: async function(context: any): Promise { - const schema1 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - }), - }; - const schema2 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - context.client as Connection, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([ - { - column: { - autoincrement: false, - generated: { - as: "`users`.`name` || 'hello'", - type: 'stored', - }, - name: 'gen_name', - notNull: false, - primaryKey: false, - type: 'text', - }, - schema: '', - tableName: 'users', - type: 'alter_table_add_column', - }, - { - column: { - autoincrement: false, - generated: { - as: "`users`.`name` || 'hello'", - type: 'virtual', - }, - name: 'gen_name1', - notNull: false, - primaryKey: false, - type: 'text', - }, - schema: '', - tableName: 'users', - type: 'alter_table_add_column', - }, - ]); - expect(sqlStatements).toStrictEqual([ - "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", - "ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", - ]); - - for (const st of sqlStatements) { - await context.client.query(st); - } - - const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( - schema2, - {}, - [], - false, - ); - - for (const st of dropStatements) { - await context.client.query(st); - } + return {} as any; }, addGeneratedToColumn: async function(context: any): Promise { - const schema1 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name'), - generatedName1: text('gen_name1'), - }), - }; - const schema2 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - context.client as Connection, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([ - { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: { - as: "`users`.`name` || 'hello'", - type: 'stored', - }, - columnName: 'gen_name', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_set_generated', - }, - { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: { - as: "`users`.`name` || 'hello'", - type: 'virtual', - }, - columnName: 'gen_name1', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_set_generated', - }, - ]); - expect(sqlStatements).toStrictEqual([ - "ALTER TABLE `users` MODIFY COLUMN `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", - 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', - "ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", - ]); - - for (const st of sqlStatements) { - await context.client.query(st); - } - - const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( - schema2, - {}, - [], - false, - ); - - for (const st of dropStatements) { - await context.client.query(st); - } + return {} as any; }, dropGeneratedConstraint: async function(context: any): Promise { - const schema1 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - { mode: 'virtual' }, - ), - }), - }; - const schema2 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name'), - generatedName1: text('gen_name1'), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - context.client as Connection, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([ - { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: undefined, - columnName: 'gen_name', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - oldColumn: { - autoincrement: false, - default: undefined, - generated: { - as: '`name`', - type: 'stored', - }, - name: 'gen_name', - notNull: false, - onUpdate: undefined, - primaryKey: false, - type: 'text', - }, - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_generated', - }, - { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: undefined, - columnName: 'gen_name1', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - oldColumn: { - autoincrement: false, - default: undefined, - generated: { - as: '`name`', - type: 'virtual', - }, - name: 'gen_name1', - notNull: false, - onUpdate: undefined, - primaryKey: false, - type: 'text', - }, - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_generated', - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', - 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', - 'ALTER TABLE `users` ADD `gen_name1` text;', - ]); - - for (const st of sqlStatements) { - await context.client.query(st); - } - - const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( - schema2, - {}, - [], - false, - ); - - for (const st of dropStatements) { - await context.client.query(st); - } + return {} as any; }, alterGeneratedConstraint: async function(context: any): Promise { - const schema1 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - { mode: 'virtual' }, - ), - }), - }; - const schema2 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - context.client as Connection, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([]); - expect(sqlStatements).toStrictEqual([]); - - const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( - schema2, - {}, - [], - false, - ); - - for (const st of dropStatements) { - await context.client.query(st); - } + return {} as any; }, createTableWithGeneratedConstraint: function(context?: any): Promise { return {} as any; @@ -667,7 +337,8 @@ const singlestoreSuite: DialectSuite = { run( singlestoreSuite, async (context: any) => { - const connectionString = process.env.SINGLESTORE_CONNECTION_STRING ?? await createDockerDB(context); + const connectionString = process.env.SINGLESTORE_CONNECTION_STRING + ?? (await createDockerDB(context)); const sleep = 1000; let timeLeft = 20000; @@ -691,6 +362,9 @@ run( await context.singlestoreContainer?.stop().catch(console.error); throw lastError; } + + await context.client.query('CREATE DATABASE drizzle;'); + await context.client.query('USE drizzle;'); }, async (context: any) => { await context.client?.end().catch(console.error); diff --git a/drizzle-kit/vitest.config.ts b/drizzle-kit/vitest.config.ts index 8f22123dd..d8ee4a881 100644 --- a/drizzle-kit/vitest.config.ts +++ b/drizzle-kit/vitest.config.ts @@ -4,12 +4,17 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { include: [ - 'tests/**/*.test.ts', + // 'tests/**/*.test.ts', + // Need to test it first before pushing changes + 'tests/singlestore-schemas.test.ts', + 'tests/singlestore-views.test.ts', + 'tests/push/singlestore-push.test.ts', + 'tests/push/singlestore.test.ts', ], - exclude: [ - 'tests/**/singlestore-generated.test.ts', - ], + // This one was excluded because we need to modify an API for SingleStore-generated columns. + // It’s in the backlog. + exclude: ['tests/**/singlestore-generated.test.ts'], typecheck: { tsconfig: 'tsconfig.json', From f5393afb44130cfcd476e44646b3389b719348c6 Mon Sep 17 00:00:00 2001 From: Armand SALLE Date: Thu, 7 Nov 2024 15:06:18 +0100 Subject: [PATCH 306/492] fix: typo (#3172) Co-authored-by: Andrii Sherman --- drizzle-kit/src/cli/commands/migrate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 0933af194..92770e99d 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -1078,7 +1078,7 @@ export const writeResult = ({ if (type === 'custom') { console.log('Prepared empty file for your custom SQL migration!'); - sql = '-- Custom SQL migration file, put you code below! --'; + sql = '-- Custom SQL migration file, put your code below! --'; } journal.entries.push({ From e25e2c2c53322bf55f466a02c9f90a5ae2ce4a3d Mon Sep 17 00:00:00 2001 From: Christopher Masto Date: Thu, 7 Nov 2024 09:06:47 -0500 Subject: [PATCH 307/492] Fix typo (#3030) Trivial: "You ... is ready" -> "Your ... is ready" Co-authored-by: Andrii Sherman --- drizzle-kit/src/cli/commands/introspect.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index db250d005..2629d000e 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -153,14 +153,14 @@ export const introspectPostgres = async ( chalk.green( '✓', ) - }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + }] Your schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, ); render( `[${ chalk.green( '✓', ) - }] You relations file is ready ➜ ${ + }] Your relations file is ready ➜ ${ chalk.bold.underline.blue( relationsFile, ) @@ -264,14 +264,14 @@ export const introspectMysql = async ( chalk.green( '✓', ) - }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + }] Your schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, ); render( `[${ chalk.green( '✓', ) - }] You relations file is ready ➜ ${ + }] Your relations file is ready ➜ ${ chalk.bold.underline.blue( relationsFile, ) @@ -488,14 +488,14 @@ export const introspectLibSQL = async ( chalk.green( '✓', ) - }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + }] Your schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, ); render( `[${ chalk.green( '✓', ) - }] You relations file is ready ➜ ${ + }] Your relations file is ready ➜ ${ chalk.bold.underline.blue( relationsFile, ) From 908e6f45b460ebff7e96f9b53ae193db7881a552 Mon Sep 17 00:00:00 2001 From: Daniel Harvey Date: Thu, 7 Nov 2024 22:07:30 +0800 Subject: [PATCH 308/492] [MySQL] Correct $returningId() implementation to correctly store selected fields (#2975) * Add test to reproduce $returningId() column order issue Currently, $returningId() only works when the primary key is in the first column (of the Drizzle table definition not the underlying MySQL table). This new test checks for this behaviour by using $returningId() when the primary key is in the second column. See https://github.com/drizzle-team/drizzle-orm/issues/2971 Signed-off-by: Daniel Harvey * Fix $returningId() to correctly set selected fields The local variable `returning` computes the selected fields in $returningId() but throws this away. Change to correctly store config in the insert query builder. Fixed https://github.com/drizzle-team/drizzle-orm/issues/2971 Signed-off-by: Daniel Harvey --------- Signed-off-by: Daniel Harvey Co-authored-by: Andrii Sherman --- .../src/mysql-core/query-builders/insert.ts | 6 +++--- integration-tests/tests/mysql/mysql-common.ts | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/insert.ts b/drizzle-orm/src/mysql-core/query-builders/insert.ts index fe9f7d7ba..5a9afaa8a 100644 --- a/drizzle-orm/src/mysql-core/query-builders/insert.ts +++ b/drizzle-orm/src/mysql-core/query-builders/insert.ts @@ -16,8 +16,8 @@ import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; import { Param, SQL, sql } from '~/sql/sql.ts'; import type { InferModelFromColumns } from '~/table.ts'; import { Table } from '~/table.ts'; -import { mapUpdateSet, orderSelectedFields } from '~/utils.ts'; -import type { AnyMySqlColumn, MySqlColumn } from '../columns/common.ts'; +import { mapUpdateSet } from '~/utils.ts'; +import type { AnyMySqlColumn } from '../columns/common.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; import type { MySqlUpdateSetSource } from './update.ts'; @@ -252,7 +252,7 @@ export class MySqlInsertBase< returning.push({ field: value, path: [key] }); } } - this.config.returning = orderSelectedFields(this.config.table[Table.Symbol.Columns]); + this.config.returning = returning; return this as any; } diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 5dde42934..e2d74dc50 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3506,6 +3506,23 @@ export function tests(driver?: string) { expect(result).toStrictEqual([{ id: 1 }]); }); + test('insert $returningId: serial as id, not first column', async (ctx) => { + const { db } = ctx.mysql; + + const usersTableDefNotFirstColumn = mysqlTable('users2', { + name: text('name').notNull(), + id: serial('id').primaryKey(), + }); + + const result = await db.insert(usersTableDefNotFirstColumn).values({ name: 'John' }).$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + id: number; + }[]>(); + + expect(result).toStrictEqual([{ id: 1 }]); + }); + test('insert $returningId: serial as id, batch insert', async (ctx) => { const { db } = ctx.mysql; From b2f96069c05be78c5871520b72785e608a27e8e8 Mon Sep 17 00:00:00 2001 From: wackbyte Date: Thu, 7 Nov 2024 09:14:20 -0500 Subject: [PATCH 309/492] revise and proofread project documentation (#2960) Co-authored-by: Andrii Sherman --- CONTRIBUTING.md | 306 ++++++++++++-------------- README.md | 16 +- docs/custom-types.lite.md | 3 +- docs/custom-types.md | 27 +-- docs/joins.md | 13 +- drizzle-kit/README.md | 14 +- drizzle-orm/src/sqlite-core/README.md | 18 +- examples/mysql-proxy/README.md | 6 +- examples/neon-cloudflare/readme.md | 2 +- examples/pg-proxy/README.md | 6 +- examples/sqlite-proxy/README.md | 6 +- 11 files changed, 196 insertions(+), 221 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3b7f8cbba..38b9f4642 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,169 +2,137 @@ Welcome! We're glad you're interested in Drizzle ORM and want to help us make it better. -Drizzle ORM is owned by [Drizzle Team](https://drizzle.team) and maintained by community members, mainly by our core contributors [@AndriiSherman](https://github.com/AndriiSherman) [@AlexBlokh](https://github.com/AlexBlokh) [@dankochetov](https://github.com/dankochetov). Everything that is going to be merged should be approved by all core contributors members +Drizzle ORM is owned by [Drizzle Team](https://drizzle.team) and maintained by community members, mainly by our core contributors ([@AndriiSherman](https://github.com/AndriiSherman), [@AlexBlokh](https://github.com/AlexBlokh), [@dankochetov](https://github.com/dankochetov)). Everything that is going to be merged should be approved by all core contributors members. --- -There are many ways you can contribute to the Drizzle ORM project +There are many ways you can contribute to the Drizzle ORM project: -- [Submitting bug reports](#bugreport) -- [Submitting feature request](#featurerequest) +- [Submitting bug reports](#bug-report) +- [Submitting feature request](#feature-request) - [Providing feedback](#feedback) -- [Contribution guidelines](#contributing) +- [Contribution guidelines](#contribution-guidelines) -## Submitting bug report +## Submitting bug report ---- - -To submit a bug or issue, please use our [issue form](https://github.com/drizzle-team/drizzle-orm/issues/new/choose) and choose Bug Report +To report a bug or issue, please use our [issue form](https://github.com/drizzle-team/drizzle-orm/issues/new/choose) and choose Bug Report. -## Submitting feature request +## Submitting feature request ---- - -To submit a bug or issue, please use our [issue form](https://github.com/drizzle-team/drizzle-orm/issues/new/choose) and choose Feature Request +To request a feature, please use our [issue form](https://github.com/drizzle-team/drizzle-orm/issues/new/choose) and choose Feature Request. ## Providing feedback ---- +There are several ways you can provide feedback: -There are several ways how you can provide a feedback +- You can join our [Discord server](https://discord.gg/yfjTbVXMW4) and provide feedback there. +- You can add new ticket in [Discussions](https://github.com/drizzle-team/drizzle-orm/discussions). +- Mention our [Twitter account](https://twitter.com/DrizzleOrm). -- You can join our [Discord](https://discord.gg/yfjTbVXMW4) channel and provide feedback there -- You can add new ticket in [Discussions](https://github.com/drizzle-team/drizzle-orm/discussions) -- Mention our [Twitter account](https://twitter.com/DrizzleOrm) +## Contribution guidelines -## Contribution guidelines - ---- - -- [Pre-Contribution setup](#pre-contribution) - - [Installing node](#-installing-node) - - [Install pnpm](#-install-pnpm) - - [Install docker](#-install-docker) - - [Clone project](#-clone-project) - - [Repository Structure](#repo-structure) - - [Build project](#-build-project) +- [Pre-contribution setup](#pre-contribution) + - [Installing Node](#installing-node) + - [Installing pnpm](#installing-pnpm) + - [Installing Docker](#installing-docker) + - [Cloning the repository](#cloning-the-repository) + - [Repository structure](#repository-structure) + - [Building the project](#building-the-project) +- [Commit message guidelines](#commit-message-guidelines) - [Contributing to `drizzle-orm`](#contributing-orm) - [Project structure](#project-structure-orm) - - [Run tests](#run-tests-orm) - - [Commits and PRs](#commits-and-prs-orm) - - [Commit guideline](#commit-guideline-orm) - - [PR guideline](#pr-guideline-orm) + - [Running tests](#running-tests-orm) + - [PR guidelines](#pr-guidelines-orm) - [Contributing to `drizzle-kit`](#contributing-kit) - [Project structure](#project-structure-kit) - - [Run tests](#run-tests-kit) - - [Commits and PRs](#commits-and-prs-kit) - - [Commit guideline](#commit-guideline-kit) - - [PR guideline](#-pr-guideline) - -## Pre-Contribution setup + - [Running tests](#running-tests-kit) + - [PR guidelines](#pr-guidelines-kit) -### Installing node +## Pre-contribution setup ---- +### Installing Node ```bash # https://github.com/nvm-sh/nvm#install--update-script -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash nvm install 18.13.0 nvm use 18.13.0 ``` -### Install pnpm - ---- +### Installing pnpm ```bash # https://pnpm.io/installation npm install -g pnpm ``` -### Install docker - ---- +### Installing Docker ```bash # https://docs.docker.com/get-docker/ -Use docker guide to install docker on your OS +# Use Docker's guide to install Docker for your OS. ``` -## Local project setup - -### Clone project - ---- +### Cloning the repository ```bash git clone https://github.com/drizzle-team/drizzle-orm.git cd drizzle-orm ``` -### Repository Structure - -``` -📂 drizzle-orm/ - orm core package with all main logic for each dialect - -📂 drizzle-kit/ - kit core package with all main logic and tests for each dialect +### Repository structure -📂 drizzle-typebox/ - all the code related to drizzle+typebox extension +- 📂 `drizzle-orm/` -📂 drizzle-valibot/ - all the code related to drizzle+valibot extension + orm core package with all main logic for each dialect -📂 drizzle-zod/ - all the code related to drizzle+zod extension +- 📂 `drizzle-kit/` -📂 eslint-plugin-drizzle/ - all the code related to drizzle eslint plugin + kit core package with all main logic and tests for each dialect -📂 changelogs/ - all changelogs for drizzle-orm, drizzle-kit, drizzle-typebox, drizzle-zod, drizzle-valibot modules +- 📂 `drizzle-typebox/` -📂 examples/ - package with Drizzle ORM usage examples + all the code related to drizzle+typebox extension -📂 integration-tests/ - package with all type of tests for each supported database -``` +- 📂 `drizzle-valibot/` -### Build project + all the code related to drizzle+valibot extension ---- +- 📂 `drizzle-zod/` -- `"pnpm i && pnpm build"` -> if you run this script from root folder - it will build whole monorepo. Running this script from specific package folder will only build current package + all the code related to drizzle+zod extension -## Contributing to `drizzle-orm` - -### Project structure - -``` -Project structure +- 📂 `eslint-plugin-drizzle/` -📂 pg-core, mysql-core, sqlite-core - core packages for each dialect with all the main logic for relation and query builder + all the code related to drizzle eslint plugin -📂 sql/ - package containing all expressions and SQL template implementation +- 📂 `changelogs/` -All other folders are for specific drivers that Drizzle ORM supports. -``` + all changelogs for drizzle-orm, drizzle-kit, drizzle-typebox, drizzle-zod, drizzle-valibot modules -### Run tests +- 📂 `examples/` ---- -All tests for Drizzle ORM are integration tests, that are simulating real database and different queries and responses from database. Each file in `integration-tests` has a list of different scenarios for different dialect+driver. Each file is creating a docker instance with needed database and running test cases there. Right after all tests were run - docker container with database will be deleted + package with Drizzle ORM usage examples -If you have added additional logic to core package - make sure that all tests were executed without any errors +- 📂 `integration-tests/` -> If you have added data types or feature for query building, you need to create additional test cases with this data type/syntax changes, syntax addition + package with all type of tests for each supported database -- `"cd integration-tests && pnpm test"` -> will run all tests in integration test folder +### Building the project -## Commits and PRs +Run the following script from the root folder to build the whole monorepo. Running it from a specific package folder will only build that package. -### Commit guideline +```bash +pnpm install && pnpm build +``` ---- +## Commit message guidelines We have specific rules on how commit messages should be structured. -It's important to make sure your commit messages are clear, concise, and informative to make it easier for others to understand the changes you are making +It's important to make sure your commit messages are clear, concise, and informative to make it easier for others to understand the changes you are making. -Commit message pattern +All commit messages should follow the pattern below: ``` @@ -172,7 +140,7 @@ Commit message pattern ``` -Example +Example: ``` Add groupBy error message @@ -181,117 +149,131 @@ In specific case, groupBy was responding with unreadable error ... ``` -> **Warning**: -> All commits should be signed, before submitting PR. Please check detailed info on [how to sign commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) +> [!WARNING] +> All commits should be signed before submitting a PR. Please check the documentation on [how to sign commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification). -### PR guideline +## Contributing to `drizzle-orm` ---- +### Project structure -1. PR should be created with specific name pattern +- 📂 `pg-core/`, `mysql-core/`, `sqlite-core/` + + core packages for each dialect with all the main logic for relation and query builder -``` -[Dialect name]: -``` +- 📂 `sql/` -Example + package containing all expressions and SQL template implementation -``` -[Pg] Add PostGIS extension support +- All other folders are for each specific driver that Drizzle ORM supports. + +### Running tests + +All tests for Drizzle ORM are integration tests that simulate real databases with different queries and responses from each database. Each file in `integration-tests` has a list of different scenarios for different dialects and drivers. Each file creates a Docker container with the needed database and runs the test cases there. After every test is run, the Docker container will be deleted. + +If you have added additional logic to a core package, make sure that all tests completed without any failures. + +> [!NOTE] +> If you have added data types or a feature for query building, you need to create additional test cases using the new API to ensure it works properly. + +If you are in the root of the repository, run all integration tests with the following script: + +```bash +cd integration-tests && pnpm test ``` -2. PR should contain detailed description with everything, that was changed +### PR guidelines -3. Each PR should contain - - Tests on feature, that was created; - - Tests on bugs, that was fixed; +1. PR titles should follow the pattern below: -To understand how test should be created and run - please check [Run tests](#-run-tests) section + ``` + []: + ``` + Example: + + ``` + [Pg] Add PostGIS extension support + ``` + +2. PRs should contain a detailed description of everything that was changed. + +3. Commit messages should follow the [message style guidelines](#commit-message-guidelines). + +4. PRs should implement: + - Tests for features that were added. + - Tests for bugs that were fixed. + +> [!NOTE] +> To understand how tests should be created and run, please check the [Running tests](#running-tests-orm) section. ## Contributing to `drizzle-kit` ### Project structure -``` -📂 cli/ - | - | -> 📄 schema.ts - all the commands defined using brocli - | - | -> 📂 commands - all the business logic for drizzle-kit commands - -📂 extensions/ - all the extension helpers for databases +- 📂 `cli/` + - 📄 `schema.ts` -📂 serializer/ - all the necessary logic to read from the Drizzle ORM schema and convert it to a common JSON format, as well as the logic to introspect all tables, types, and other database elements and convert them to a common JSON format + all the commands defined using brocli -📄 introspect-pg.ts, introspect-mysql.ts, introspect-sqlite.ts - these files are responsible for mapping JSON snapshots to TypeScript files during introspect commands + - 📂 `commands/` -📄 snapshotsDiffer.ts - this file handles the mapping from JSON snapshot format to JSON statement objects. + all the business logic for drizzle-kit commands -📄 jsonStatements.ts - this file defines JSON statement types, interfaces, and helper functions. +- 📂 `extensions/` -📄 sqlgenerator.ts - this file converts JSON statements to SQL strings. -``` + all the extension helpers for databases -### Run tests +- 📂 `serializer/` ---- -All tests for Drizzle Kit are integration tests, that are simulating real database and different queries and responses from database. Each file in `drizzle-kit/tests` has a list of different scenarios for different commands. Each MySQL file is creating a docker instance with needed database and running test cases there. Right after all tests were run - docker container with database will be deleted. For PostgreSQL we are using PgLite and for SQLite we are using SQLite files. + all the necessary logic to read from the Drizzle ORM schema and convert it to a common JSON format, as well as the logic to introspect all tables, types, and other database elements and convert them to a common JSON format -If you are in the root of repo: +- 📄 `introspect-pg.ts`, `introspect-mysql.ts`, `introspect-sqlite.ts` -- `"cd drizzle-kit && pnpm test"` -> will run all tests + these files are responsible for mapping JSON snapshots to TypeScript files during introspect commands -## Commits and PRs +- 📄 `snapshotsDiffer.ts` -### Commit guideline + this file handles the mapping from JSON snapshot format to JSON statement objects. ---- +- 📄 `jsonStatements.ts` -We have specific rules on how commit messages should be structured. + this file defines JSON statement types, interfaces, and helper functions. -It's important to make sure your commit messages are clear, concise, and informative to make it easier for others to understand the changes you are making +- 📄 `sqlgenerator.ts` -Commit message pattern + this file converts JSON statements to SQL strings. -``` - - - -``` +### Running tests -Example +All tests for Drizzle Kit are integration tests that simulate real databases with different queries and responses from each database. Each file in `drizzle-kit/tests` has a list of different scenarios for different commands. Each file creates a Docker container with the needed database and runs the test cases there. After every test is run, the Docker container will be deleted. We test MySQL, PostgreSQL (using PGlite), and SQLite. -``` -Add groupBy error message +If you are in the root of the repository, run all Drizzle Kit tests with the following script: -In specific case, groupBy was responding with unreadable error -... +```bash +cd drizzle-kit && pnpm test ``` -> **Warning**: -> All commits should be signed, before submitting PR. Please check detailed info on [how to sign commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) +### PR guidelines -### PR guideline +1. PR titles should follow the pattern below: ---- + ``` + [-kit]: + ``` -1. PR should be created with specific name pattern + Example: -``` -[-kit]: -``` - -Example + ``` + [Pg-kit] Add PostGIS extension support + ``` -``` -[Pg-kit] Add PostGIS extension support -``` +2. PRs should contain a detailed description of everything that was changed. -2. PR should contain detailed description with everything, that was changed +3. Commit messages should follow the [message style guidelines](#commit-message-guidelines). -3. Each PR should contain - - Tests on feature, that was created; - - Tests on bugs, that was fixed; +4. PRs should implement: + - Tests for features that were added. + - Tests for bugs that were fixed. -To understand how test should be created and run - please check [Run tests](#run-tests) section +> [!NOTE] +> To understand how tests should be created and run, please check the [Running tests](#running-tests-kit) section. diff --git a/README.md b/README.md index ac509ab0d..4342d8afe 100644 --- a/README.md +++ b/README.md @@ -17,24 +17,24 @@ ### What's Drizzle? Drizzle is a modern TypeScript ORM developers [wanna use in their next project](https://stateofdb.com/tools/drizzle). -It is [lightweight](https://bundlephobia.com/package/drizzle-orm) at only ~7.4kb minified+gzipped, it's tree shakeable with exactly 0 dependencies. +It is [lightweight](https://bundlephobia.com/package/drizzle-orm) at only ~7.4kb minified+gzipped, and it's tree shakeable with exactly 0 dependencies. -**Drizzle supports every PostgreSQL, MySQL and SQLite databases**, including serverless ones like [Turso](https://orm.drizzle.team/docs/get-started-sqlite#turso), [Neon](https://orm.drizzle.team/docs/get-started-postgresql#neon), [Xata](xata.io), [PlanetScale](https://orm.drizzle.team/docs/get-started-mysql#planetscale), [Cloudflare D1](https://orm.drizzle.team/docs/get-started-sqlite#cloudflare-d1), [FlyIO LiteFS](https://fly.io/docs/litefs/), [Vercel Postgres](https://orm.drizzle.team/docs/get-started-postgresql#vercel-postgres), [Supabase](https://orm.drizzle.team/docs/get-started-postgresql#supabase) and [AWS Data API](https://orm.drizzle.team/docs/get-started-postgresql#aws-data-api). No bells and whistles, no rust binaries, no serverless adapters, everything just works out of the box. +**Drizzle supports every PostgreSQL, MySQL and SQLite database**, including serverless ones like [Turso](https://orm.drizzle.team/docs/get-started-sqlite#turso), [Neon](https://orm.drizzle.team/docs/get-started-postgresql#neon), [Xata](xata.io), [PlanetScale](https://orm.drizzle.team/docs/get-started-mysql#planetscale), [Cloudflare D1](https://orm.drizzle.team/docs/get-started-sqlite#cloudflare-d1), [FlyIO LiteFS](https://fly.io/docs/litefs/), [Vercel Postgres](https://orm.drizzle.team/docs/get-started-postgresql#vercel-postgres), [Supabase](https://orm.drizzle.team/docs/get-started-postgresql#supabase) and [AWS Data API](https://orm.drizzle.team/docs/get-started-postgresql#aws-data-api). No bells and whistles, no Rust binaries, no serverless adapters, everything just works out of the box. -**Drizzle is serverless-ready by design**, it works in every major JavaScript runtime like NodeJS, Bun, Deno, Cloudflare Workers, Supabase functions, any Edge runtime and even in Browsers. -With Drizzle you can be [**fast out of the box**](https://orm.drizzle.team/benchmarks), save time and costs while never introducing any data proxies into your infrastructure. +**Drizzle is serverless-ready by design**. It works in every major JavaScript runtime like NodeJS, Bun, Deno, Cloudflare Workers, Supabase functions, any Edge runtime, and even in browsers. +With Drizzle you can be [**fast out of the box**](https://orm.drizzle.team/benchmarks) and save time and costs while never introducing any data proxies into your infrastructure. -While you can use Drizzle as a JavaScript library, it shines in the TypeScript. It lets you [**declare SQL schema**](https://orm.drizzle.team/docs/sql-schema-declaration) and build both [**relational**](https://orm.drizzle.team/docs/rqb) and [**SQL-like queries**](https://orm.drizzle.team/docs/select), while keeping the balance between type-safety and extensibility for toolmakers to build on top. +While you can use Drizzle as a JavaScript library, it shines with TypeScript. It lets you [**declare SQL schemas**](https://orm.drizzle.team/docs/sql-schema-declaration) and build both [**relational**](https://orm.drizzle.team/docs/rqb) and [**SQL-like queries**](https://orm.drizzle.team/docs/select), while keeping the balance between type-safety and extensibility for toolmakers to build on top. ### Ecosystem While Drizzle ORM remains a thin typed layer on top of SQL, we made a set of tools for people to have best possible developer experience. -Drizzle comes with a powerful [**Drizzle Kit**](https://orm.drizzle.team/kit-docs/overview) CLI companion for you to have hasstle-free migrations. It can generate SQL migration files for you or apply schema changes directly to the database. +Drizzle comes with a powerful [**Drizzle Kit**](https://orm.drizzle.team/kit-docs/overview) CLI companion for you to have hassle-free migrations. It can generate SQL migration files for you or apply schema changes directly to the database. -And we have a [**Drizzle Studio**](https://orm.drizzle.team/drizzle-studio/overview) for you to effortlessly browse and manipulate data in your database of choice. +We also have [**Drizzle Studio**](https://orm.drizzle.team/drizzle-studio/overview) for you to effortlessly browse and manipulate data in your database of choice. ### Documentation -Check out the full documentation on [the website](https://orm.drizzle.team/docs/overview) +Check out the full documentation on [the website](https://orm.drizzle.team/docs/overview). ### Our sponsors ❤️

diff --git a/docs/custom-types.lite.md b/docs/custom-types.lite.md index 627aba1a4..af1371461 100644 --- a/docs/custom-types.lite.md +++ b/docs/custom-types.lite.md @@ -1,6 +1,7 @@ # Common way of defining custom types -> **Info**: For more advanced documentation about defining custom data types in PostgreSQL and MySQL please check [custom-types.md](https://github.com/drizzle-team/drizzle-orm/blob/main/docs/custom-types.md) +> [!NOTE] +> For more advanced documentation about defining custom data types in PostgreSQL and MySQL, please check [`custom-types.md`](custom-types.md). ## Examples diff --git a/docs/custom-types.md b/docs/custom-types.md index 1dffe6ce0..2a9f1a1da 100644 --- a/docs/custom-types.md +++ b/docs/custom-types.md @@ -1,7 +1,6 @@ # How to define custom types Drizzle ORM has a big set of predefined column types for different SQL databases. But still there are additional types that are not supported by Drizzle ORM (yet). That could be native pg types or extension types -
Here are some instructions on how to create and use your own types with Drizzle ORM @@ -13,14 +12,11 @@ Each type creation should use 2 classes: - `ColumnBuilder` - class, that is responsible for generating whole set of needed fields for column creation - `Column` - class, that is representing Columns itself, that is used in query generation, migration mapping, etc. -
-
+ Each module has it's own class, representing `ColumnBuilder` or `Column`: - For `pg` -> `PgColumnBuilder` and `PgColumn` - For `mysql` -> `MySqlColumnBuilder` and `MySqlColumn` - For `sqlite` -> `SQLiteColumnBuilder` and `SQLiteColumn` -
-
### Builder class explanation - (postgresql text data type example) @@ -44,7 +40,7 @@ export class PgTextBuilder } ``` -> **Warning** +> [!WARNING] > `$pgColumnBuilderBrand` should be changed and be equal to class name for new data type builder ### Column class explanation - (postgresql text data type example) @@ -104,11 +100,8 @@ export class PgText } ``` -> **Warning** +> [!WARNING] > `$pgColumnBrand` should be changed and be equal to class name for new data type ---- - -
### Full text data type for PostgreSQL example @@ -162,19 +155,13 @@ export function text( ## Custom data type example ---- - -> **Note** +> [!NOTE] > We will check example on pg module, but current pattern applies to all dialects, that are currently supported by Drizzle ORM -
- ### Setting up CITEXT datatype ---- -> **Note** - This type is available only with extensions and used for example, just to show how you could setup any data type you want. Extension support will come soon -
+> [!NOTE] +> This type is available only with extensions and used for example, just to show how you could setup any data type you want. Extension support will come soon ### CITEXT data type example @@ -224,4 +211,4 @@ You could add your created custom data types to Drizzle ORM, so everyone can use Each data type should be placed in separate file in `columns` folder and PR open with tag `new-data-type:pg` | `new-data-type:sqlite` | `new-data-type:mysql` -For more Contribution information - please check [CONTRIBUTING.md](https://github.com/drizzle-team/drizzle-orm/blob/main/CONTRIBUTING.md) +For more Contribution information - please check [CONTRIBUTING.md](../CONTRIBUTING.md) diff --git a/docs/joins.md b/docs/joins.md index e0579e3e2..2b5829aa9 100644 --- a/docs/joins.md +++ b/docs/joins.md @@ -1,7 +1,7 @@ # Drizzle ORM - Joins As with other parts of Drizzle ORM, the joins syntax is a balance between the SQL-likeness and type safety. -Here's an example of how a common `1-to-many` relationship can be modelled. +Here's an example of how a common "one-to-many" relationship can be modelled. ```typescript const users = pgTable('users', { @@ -96,7 +96,7 @@ In that case, the ORM will use dark TypeScript magic (as if it wasn't already) a This is much more convenient! Now, you can just do a single check for `row.user !== null`, and all the user fields will become available. -


+--- Note that you can group any fields in a nested object however you like, but the single check optimization will only be applied to a certain nested object if all its fields belong to the same table. So, for example, you can group the city fields, too: @@ -131,7 +131,7 @@ And the result type will look like this: } ``` -
+--- If you just need all the fields from all the tables you're selecting and joining, you can simply omit the argument of the `.select()` method altogether: @@ -139,7 +139,8 @@ If you just need all the fields from all the tables you're selecting and joining const rows = await db.select().from(cities).leftJoin(users, eq(users.cityId, cities.id)); ``` -> **Note**: in this case, the Drizzle table/column names will be used as the keys in the result object. +> [!NOTE] +> In this case, the Drizzle table/column names will be used as the keys in the result object. ```typescript { @@ -156,7 +157,7 @@ const rows = await db.select().from(cities).leftJoin(users, eq(users.cityId, cit }[] ``` -
+--- There are cases where you'd want to select all the fields from one table, but pick fields from others. In that case, instead of listing all the table fields, you can just pass a table: @@ -181,7 +182,7 @@ There are cases where you'd want to select all the fields from one table, but pi } ``` -
+--- But what happens if you group columns from multiple tables in the same nested object? Nothing, really - they will still be all individually nullable, just grouped under the same object (as you might expect!): diff --git a/drizzle-kit/README.md b/drizzle-kit/README.md index d2a4191b7..bd69a4d3d 100644 --- a/drizzle-kit/README.md +++ b/drizzle-kit/README.md @@ -1,21 +1,21 @@ ## Drizzle Kit -DrizzleKit - is a CLI migrator tool for DrizzleORM. It is probably one and only tool that lets you completely automatically generate SQL migrations and covers ~95% of the common cases like deletions and renames by prompting user input. +Drizzle Kit is a CLI migrator tool for Drizzle ORM. It is probably the one and only tool that lets you completely automatically generate SQL migrations and covers ~95% of the common cases like deletions and renames by prompting user input. - is a mirror repository for issues. ## Documentation -Check the full documenation on [the website](https://orm.drizzle.team/kit-docs/overview) +Check the full documentation on [the website](https://orm.drizzle.team/kit-docs/overview). ### How it works -`drizzle-kit` will traverse `schema folder` or `schema file`, generate schema snapshot and compare it to the previous version, if there's one. - Based on the difference it will generate all needed SQL migrations and if there are any `automatically unresolvable` cases like `renames` it will prompt user for input. +Drizzle Kit traverses a schema module and generates a snapshot to compare with the previous version, if there is one. +Based on the difference, it will generate all needed SQL migrations. If there are any cases that can't be resolved automatically, such as renames, it will prompt the user for input. -For schema file: +For example, for this schema module: ```typescript -// ./src/db/schema.ts +// src/db/schema.ts import { integer, pgTable, serial, text, varchar } from "drizzle-orm/pg-core"; @@ -63,7 +63,7 @@ CREATE INDEX IF NOT EXISTS users_full_name_index ON users (full_name); npm install -D drizzle-kit ``` -Running with CLI options +Running with CLI options: ```jsonc // package.json diff --git a/drizzle-orm/src/sqlite-core/README.md b/drizzle-orm/src/sqlite-core/README.md index 6d4ebd8b6..ae5fbe660 100644 --- a/drizzle-orm/src/sqlite-core/README.md +++ b/drizzle-orm/src/sqlite-core/README.md @@ -8,7 +8,7 @@
-DrizzleORM is a [tiny](https://twitter.com/_alexblokh/status/1594735880417472512), [blazingly fast](#️-performance-and-prepared-statements) TypeScript ORM library with a [drizzle-kit](#-migrations) CLI companion for automatic SQL migrations generation. +Drizzle ORM is a [tiny](https://twitter.com/_alexblokh/status/1594735880417472512), [blazingly fast](#️-performance-and-prepared-statements) TypeScript ORM library with a [drizzle-kit](#-migrations) CLI companion for automatic SQL migrations generation. Here you can find extensive docs for SQLite module. | Driver | Support | | @@ -365,7 +365,8 @@ const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42))); const result = db.with(sq).select().from(sq).all(); ``` -> **Note**: Keep in mind that if you need to select raw `sql` in a WITH subquery and reference that field in other queries, you must add an alias to it: +> [!NOTE] +> Keep in mind that if you need to select raw `sql` in a WITH subquery and reference that field in other queries, you must add an alias to it: ```typescript const sq = db.$with('sq').as(db.select({ name: sql`upper(${users.name})`.as('name') }).from(users)); @@ -582,7 +583,8 @@ db ### Joins -> **Note**: for in-depth partial select joins documentation, refer to [this page](/docs/joins.md). +> [!NOTE] +> For in-depth partial select joins documentation, refer to [this page](/docs/joins.md). ### Many-to-one @@ -721,7 +723,8 @@ const { sql, params } = query.toSQL(); ## Views (WIP) -> **Warning**: views are currently only implemented on the ORM side. That means you can query the views that already exist in the database, but they won't be added to drizzle-kit migrations or `db push` yet. +> [!WARNING] +> views are currently only implemented on the ORM side. That means you can query the views that already exist in the database, but they won't be added to drizzle-kit migrations or `db push` yet. ### Creating a view @@ -731,7 +734,8 @@ import { sqliteView } from 'drizzle-orm/sqlite-core'; const newYorkers = sqliteView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); ``` -> **Warning**: All the parameters inside the query will be inlined, instead of replaced by `$1`, `$2`, etc. +> [!WARNING] +> All the parameters inside the query will be inlined, instead of replaced by `$1`, `$2`, etc. You can also use the [`queryBuilder` instance](#query-builder) directly instead of passing a callback, if you already have it imported. @@ -794,8 +798,8 @@ q.all({ name: '%an%' }) // SELECT * FROM customers WHERE name ilike '%an%' ### Automatic SQL migrations generation with drizzle-kit -[Drizzle Kit](https://www.npmjs.com/package/drizzle-kit) is a CLI migrator tool for Drizzle ORM. It is probably one and only tool that lets you completely automatically generate SQL migrations and covers ~95% of the common cases like deletions and renames by prompting user input. -Check out the [docs for Drizzle Kit](https://github.com/drizzle-team/drizzle-kit-mirror) +[Drizzle Kit](https://www.npmjs.com/package/drizzle-kit) is a CLI migrator tool for Drizzle ORM. It is probably the one and only tool that lets you completely automatically generate SQL migrations and covers ~95% of the common cases like deletions and renames by prompting user input. +Check out the [docs for Drizzle Kit](https://github.com/drizzle-team/drizzle-kit-mirror). For schema file: diff --git a/examples/mysql-proxy/README.md b/examples/mysql-proxy/README.md index 8bbdf3f7b..fadc843d3 100644 --- a/examples/mysql-proxy/README.md +++ b/examples/mysql-proxy/README.md @@ -30,7 +30,7 @@ This project has simple example of defining http proxy server, that will proxy a
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle always waits for `{rows: string[][] | object[]}` so if any error was on http call(or any other call) - be sure, that you return at least empty array back > > For `all` method you should return `{rows: string[][]}` @@ -72,7 +72,7 @@ In current MySQL Proxy version - drizzle don't handle transactions for migration
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle just finds migrations, that need to be executed on this iteration and if finds some -> provide `queries` array to callback
@@ -97,7 +97,7 @@ await migrate(db, async (queries) => { --- -> **Note**: +> [!WARNING] > It's just a suggestion on how proxy server could be set up and a simple example of params handling on `query` and `migration` calls ```typescript diff --git a/examples/neon-cloudflare/readme.md b/examples/neon-cloudflare/readme.md index 0585ccecc..f69581b21 100644 --- a/examples/neon-cloudflare/readme.md +++ b/examples/neon-cloudflare/readme.md @@ -1,4 +1,4 @@ -### Example project for [DrizzleORM](https://driz.li/orm) + [Cloudflare Worker](https://workers.cloudflare.com) + [Neon Serverless](https://github.com/neondatabase/serverless) +### Example project for [Drizzle ORM](https://driz.li/orm) + [Cloudflare Worker](https://workers.cloudflare.com) + [Neon Serverless](https://github.com/neondatabase/serverless) --- diff --git a/examples/pg-proxy/README.md b/examples/pg-proxy/README.md index d9ff24fb1..b47fcd5e3 100644 --- a/examples/pg-proxy/README.md +++ b/examples/pg-proxy/README.md @@ -30,7 +30,7 @@ This project has simple example of defining http proxy server, that will proxy a
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle always waits for `{rows: string[][] | object[]}` so if any error was on http call(or any other call) - be sure, that you return at least empty array back > > For `all` method you should return `{rows: string[][]}` @@ -72,7 +72,7 @@ In current Postgres Proxy version - drizzle don't handle transactions for migrat
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle just finds migrations, that need to be executed on this iteration and if finds some -> provide `queries` array to callback
@@ -97,7 +97,7 @@ await migrate(db, async (queries) => { --- -> **Note**: +> [!NOTE] > It's just a suggestion on how proxy server could be set up and a simple example of params handling on `query` and `migration` calls ```typescript diff --git a/examples/sqlite-proxy/README.md b/examples/sqlite-proxy/README.md index b187e35fb..d25cd7d8b 100644 --- a/examples/sqlite-proxy/README.md +++ b/examples/sqlite-proxy/README.md @@ -30,7 +30,7 @@ This project has simple example of defining http proxy server, that will proxy a
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle always waits for `{rows: string[][]}` so if any error was on http call(or any other call) - be sure, that you return at least empty array back > > For `get` method you should return `{rows: string[]}` @@ -71,7 +71,7 @@ In current SQLite Proxy version - drizzle don't handle transactions for migratio
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle just finds migrations, that need to be executed on this iteration and if finds some -> provide `queries` array to callback
@@ -96,7 +96,7 @@ await migrate(db, async (queries) => { --- -> **Note**: +> [!NOTE] > It's just a suggestion on how proxy server could be set up and a simple example of params handling on `query` and `migration` calls ```typescript From d2fb0748d96f1016659c390db55b2103c089b7b6 Mon Sep 17 00:00:00 2001 From: Pedro Rodrigues <44656907+Rodriguespn@users.noreply.github.com> Date: Wed, 2 Oct 2024 01:23:29 +0100 Subject: [PATCH 310/492] [SingleStore] Add SingleStore connector (#32) --- drizzle-kit/src/api.ts | 110 + drizzle-kit/src/cli/commands/introspect.ts | 102 +- drizzle-kit/src/cli/commands/migrate.ts | 148 + drizzle-kit/src/cli/commands/push.ts | 155 +- .../src/cli/commands/singlestoreIntrospect.ts | 53 + .../src/cli/commands/singlestorePushUtils.ts | 352 + drizzle-kit/src/cli/commands/singlestoreUp.ts | 1 + drizzle-kit/src/cli/commands/utils.ts | 87 +- drizzle-kit/src/cli/connections.ts | 80 + drizzle-kit/src/cli/schema.ts | 68 +- drizzle-kit/src/cli/validations/outputs.ts | 11 +- .../src/cli/validations/singlestore.ts | 61 + drizzle-kit/src/index.ts | 23 +- drizzle-kit/src/introspect-singlestore.ts | 780 ++ drizzle-kit/src/jsonStatements.ts | 463 +- drizzle-kit/src/migrationPreparator.ts | 45 +- drizzle-kit/src/schemaValidator.ts | 6 +- drizzle-kit/src/serializer/index.ts | 16 + .../src/serializer/singlestoreImports.ts | 38 + .../src/serializer/singlestoreSchema.ts | 203 + .../src/serializer/singlestoreSerializer.ts | 606 ++ drizzle-kit/src/serializer/studio.ts | 84 +- drizzle-kit/src/snapshotsDiffer.ts | 433 +- drizzle-kit/src/sqlgenerator.ts | 803 ++- drizzle-kit/src/utils.ts | 3 + .../tests/push/singlestore-push.test.ts | 335 + drizzle-kit/tests/push/singlestore.test.ts | 699 ++ drizzle-kit/tests/schemaDiffer.ts | 375 +- .../tests/singlestore-generated.test.ts | 1290 ++++ drizzle-kit/tests/singlestore-schemas.test.ts | 155 + drizzle-kit/tests/singlestore-views.test.ts | 553 ++ drizzle-kit/tests/singlestore.test.ts | 578 ++ drizzle-kit/tests/testsinglestore.ts | 29 + drizzle-kit/tests/validations.test.ts | 169 + drizzle-kit/tests/wrap-param.test.ts | 3 + drizzle-orm/src/column-builder.ts | 9 +- drizzle-orm/src/singlestore-core/alias.ts | 11 + drizzle-orm/src/singlestore-core/checks.ts | 32 + .../src/singlestore-core/columns/all.ts | 55 + .../src/singlestore-core/columns/bigint.ts | 120 + .../src/singlestore-core/columns/binary.ts | 70 + .../src/singlestore-core/columns/boolean.ts | 58 + .../src/singlestore-core/columns/char.ts | 75 + .../src/singlestore-core/columns/common.ts | 116 + .../src/singlestore-core/columns/custom.ts | 235 + .../singlestore-core/columns/date.common.ts | 41 + .../src/singlestore-core/columns/date.ts | 123 + .../src/singlestore-core/columns/datetime.ts | 143 + .../src/singlestore-core/columns/decimal.ts | 75 + .../src/singlestore-core/columns/double.ts | 75 + .../src/singlestore-core/columns/enum.ts | 70 + .../src/singlestore-core/columns/float.ts | 51 + .../src/singlestore-core/columns/index.ts | 25 + .../src/singlestore-core/columns/int.ts | 71 + .../src/singlestore-core/columns/json.ts | 53 + .../src/singlestore-core/columns/mediumint.ts | 68 + .../src/singlestore-core/columns/real.ts | 81 + .../src/singlestore-core/columns/serial.ts | 76 + .../src/singlestore-core/columns/smallint.ts | 68 + .../src/singlestore-core/columns/text.ts | 116 + .../src/singlestore-core/columns/time.ts | 73 + .../src/singlestore-core/columns/timestamp.ts | 127 + .../src/singlestore-core/columns/tinyint.ts | 68 + .../src/singlestore-core/columns/varbinary.ts | 66 + .../src/singlestore-core/columns/varchar.ts | 75 + .../src/singlestore-core/columns/year.ts | 51 + drizzle-orm/src/singlestore-core/db.ts | 566 ++ drizzle-orm/src/singlestore-core/dialect.ts | 866 +++ .../src/singlestore-core/expressions.ts | 25 + drizzle-orm/src/singlestore-core/index.ts | 16 + drizzle-orm/src/singlestore-core/indexes.ts | 191 + .../src/singlestore-core/primary-keys.ts | 63 + .../singlestore-core/query-builders/attach.ts | 198 + .../singlestore-core/query-builders/branch.ts | 186 + .../singlestore-core/query-builders/count.ts | 79 + .../query-builders/createMilestone.ts | 136 + .../singlestore-core/query-builders/delete.ts | 207 + .../singlestore-core/query-builders/detach.ts | 172 + .../query-builders/dropMilestone.ts | 136 + .../singlestore-core/query-builders/index.ts | 12 + .../singlestore-core/query-builders/insert.ts | 305 + .../query-builders/optimizeTable.ts | 158 + .../query-builders/query-builder.ts | 114 + .../singlestore-core/query-builders/query.ts | 141 + .../singlestore-core/query-builders/select.ts | 1084 +++ .../query-builders/select.types.ts | 457 ++ .../singlestore-core/query-builders/update.ts | 251 + drizzle-orm/src/singlestore-core/schema.ts | 41 + drizzle-orm/src/singlestore-core/session.ts | 159 + .../sql/expressions/conditions.ts | 22 + .../singlestore-core/sql/expressions/index.ts | 1 + drizzle-orm/src/singlestore-core/sql/index.ts | 1 + drizzle-orm/src/singlestore-core/subquery.ts | 17 + drizzle-orm/src/singlestore-core/table.ts | 142 + .../src/singlestore-core/unique-constraint.ts | 64 + drizzle-orm/src/singlestore-core/utils.ts | 56 + drizzle-orm/src/singlestore-core/view-base.ts | 15 + .../src/singlestore-core/view-common.ts | 1 + drizzle-orm/src/singlestore-core/view.ts | 208 + drizzle-orm/src/singlestore-proxy/driver.ts | 54 + drizzle-orm/src/singlestore-proxy/index.ts | 2 + drizzle-orm/src/singlestore-proxy/migrator.ts | 52 + drizzle-orm/src/singlestore-proxy/session.ts | 178 + drizzle-orm/src/singlestore/driver.ts | 92 + drizzle-orm/src/singlestore/index.ts | 2 + drizzle-orm/src/singlestore/migrator.ts | 11 + drizzle-orm/src/singlestore/session.ts | 339 + .../type-tests/singlestore/1000columns.ts | 904 +++ drizzle-orm/type-tests/singlestore/db.ts | 12 + drizzle-orm/type-tests/singlestore/delete.ts | 61 + .../singlestore/generated-columns.ts | 158 + drizzle-orm/type-tests/singlestore/insert.ts | 135 + drizzle-orm/type-tests/singlestore/select.ts | 606 ++ .../type-tests/singlestore/set-operators.ts | 223 + .../type-tests/singlestore/subquery.ts | 97 + drizzle-orm/type-tests/singlestore/tables.ts | 751 ++ drizzle-orm/type-tests/singlestore/update.ts | 26 + drizzle-orm/type-tests/singlestore/with.ts | 80 + integration-tests/.env.example | 1 + .../singlestore/0000_nostalgic_carnage.sql | 20 + .../singlestore/meta/0000_snapshot.json | 132 + .../drizzle2/singlestore/meta/_journal.json | 13 + .../tests/relational/singlestore.schema.ts | 106 + .../tests/relational/singlestore.test.ts | 6402 +++++++++++++++++ .../tests/replicas/singlestore.test.ts | 805 +++ .../tests/singlestore/singlestore-common.ts | 3432 +++++++++ .../singlestore/singlestore-custom.test.ts | 827 +++ .../singlestore/singlestore-prefixed.test.ts | 1572 ++++ .../singlestore/singlestore-proxy.test.ts | 140 + .../tests/singlestore/singlestore.test.ts | 51 + integration-tests/vitest.config.ts | 4 + package.json | 3 +- pnpm-lock.yaml | 2 +- 133 files changed, 34585 insertions(+), 92 deletions(-) create mode 100644 drizzle-kit/src/cli/commands/singlestoreIntrospect.ts create mode 100644 drizzle-kit/src/cli/commands/singlestorePushUtils.ts create mode 100644 drizzle-kit/src/cli/commands/singlestoreUp.ts create mode 100644 drizzle-kit/src/cli/validations/singlestore.ts create mode 100644 drizzle-kit/src/introspect-singlestore.ts create mode 100644 drizzle-kit/src/serializer/singlestoreImports.ts create mode 100644 drizzle-kit/src/serializer/singlestoreSchema.ts create mode 100644 drizzle-kit/src/serializer/singlestoreSerializer.ts create mode 100644 drizzle-kit/tests/push/singlestore-push.test.ts create mode 100644 drizzle-kit/tests/push/singlestore.test.ts create mode 100644 drizzle-kit/tests/singlestore-generated.test.ts create mode 100644 drizzle-kit/tests/singlestore-schemas.test.ts create mode 100644 drizzle-kit/tests/singlestore-views.test.ts create mode 100644 drizzle-kit/tests/singlestore.test.ts create mode 100644 drizzle-kit/tests/testsinglestore.ts create mode 100644 drizzle-orm/src/singlestore-core/alias.ts create mode 100644 drizzle-orm/src/singlestore-core/checks.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/all.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/bigint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/binary.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/boolean.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/char.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/common.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/custom.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/date.common.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/date.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/datetime.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/decimal.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/double.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/enum.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/float.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/index.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/int.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/json.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/mediumint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/real.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/serial.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/smallint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/text.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/time.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/timestamp.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/tinyint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/varbinary.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/varchar.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/year.ts create mode 100644 drizzle-orm/src/singlestore-core/db.ts create mode 100644 drizzle-orm/src/singlestore-core/dialect.ts create mode 100644 drizzle-orm/src/singlestore-core/expressions.ts create mode 100644 drizzle-orm/src/singlestore-core/index.ts create mode 100644 drizzle-orm/src/singlestore-core/indexes.ts create mode 100644 drizzle-orm/src/singlestore-core/primary-keys.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/attach.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/branch.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/count.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/delete.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/detach.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/index.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/insert.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/query-builder.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/query.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/select.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/select.types.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/update.ts create mode 100644 drizzle-orm/src/singlestore-core/schema.ts create mode 100644 drizzle-orm/src/singlestore-core/session.ts create mode 100644 drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts create mode 100644 drizzle-orm/src/singlestore-core/sql/expressions/index.ts create mode 100644 drizzle-orm/src/singlestore-core/sql/index.ts create mode 100644 drizzle-orm/src/singlestore-core/subquery.ts create mode 100644 drizzle-orm/src/singlestore-core/table.ts create mode 100644 drizzle-orm/src/singlestore-core/unique-constraint.ts create mode 100644 drizzle-orm/src/singlestore-core/utils.ts create mode 100644 drizzle-orm/src/singlestore-core/view-base.ts create mode 100644 drizzle-orm/src/singlestore-core/view-common.ts create mode 100644 drizzle-orm/src/singlestore-core/view.ts create mode 100644 drizzle-orm/src/singlestore-proxy/driver.ts create mode 100644 drizzle-orm/src/singlestore-proxy/index.ts create mode 100644 drizzle-orm/src/singlestore-proxy/migrator.ts create mode 100644 drizzle-orm/src/singlestore-proxy/session.ts create mode 100644 drizzle-orm/src/singlestore/driver.ts create mode 100644 drizzle-orm/src/singlestore/index.ts create mode 100644 drizzle-orm/src/singlestore/migrator.ts create mode 100644 drizzle-orm/src/singlestore/session.ts create mode 100644 drizzle-orm/type-tests/singlestore/1000columns.ts create mode 100644 drizzle-orm/type-tests/singlestore/db.ts create mode 100644 drizzle-orm/type-tests/singlestore/delete.ts create mode 100644 drizzle-orm/type-tests/singlestore/generated-columns.ts create mode 100644 drizzle-orm/type-tests/singlestore/insert.ts create mode 100644 drizzle-orm/type-tests/singlestore/select.ts create mode 100644 drizzle-orm/type-tests/singlestore/set-operators.ts create mode 100644 drizzle-orm/type-tests/singlestore/subquery.ts create mode 100644 drizzle-orm/type-tests/singlestore/tables.ts create mode 100644 drizzle-orm/type-tests/singlestore/update.ts create mode 100644 drizzle-orm/type-tests/singlestore/with.ts create mode 100644 integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql create mode 100644 integration-tests/drizzle2/singlestore/meta/0000_snapshot.json create mode 100644 integration-tests/drizzle2/singlestore/meta/_journal.json create mode 100644 integration-tests/tests/relational/singlestore.schema.ts create mode 100644 integration-tests/tests/relational/singlestore.test.ts create mode 100644 integration-tests/tests/replicas/singlestore.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore-common.ts create mode 100644 integration-tests/tests/singlestore/singlestore-custom.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore-prefixed.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore-proxy.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore.test.ts diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index b18ed95f4..9f66b2fb7 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'; import { LibSQLDatabase } from 'drizzle-orm/libsql'; import type { MySql2Database } from 'drizzle-orm/mysql2'; import { PgDatabase } from 'drizzle-orm/pg-core'; +import { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; import { columnsResolver, enumsResolver, @@ -30,12 +31,19 @@ import { generateMySqlSnapshot } from './serializer/mysqlSerializer'; import { prepareFromExports } from './serializer/pgImports'; import { PgSchema as PgSchemaKit, pgSchema, squashPgScheme } from './serializer/pgSchema'; import { generatePgSnapshot } from './serializer/pgSerializer'; +import { + SingleStoreSchema as SingleStoreSchemaKit, + singlestoreSchema, + squashSingleStoreScheme, +} from './serializer/singlestoreSchema'; +import { generateSingleStoreSnapshot } from './serializer/singlestoreSerializer'; import { SQLiteSchema as SQLiteSchemaKit, sqliteSchema, squashSqliteScheme } from './serializer/sqliteSchema'; import { generateSqliteSnapshot } from './serializer/sqliteSerializer'; import type { DB, SQLiteDB } from './utils'; export type DrizzleSnapshotJSON = PgSchemaKit; export type DrizzleSQLiteSnapshotJSON = SQLiteSchemaKit; export type DrizzleMySQLSnapshotJSON = MySQLSchemaKit; +export type DrizzleSingleStoreSnapshotJSON = SingleStoreSchemaKit; export const generateDrizzleJson = ( imports: Record, @@ -374,6 +382,108 @@ export const pushMySQLSchema = async ( }; }; +// SingleStore + +export const generateSingleStoreDrizzleJson = async ( + imports: Record, + prevId?: string, +): Promise => { + const { prepareFromExports } = await import('./serializer/singlestoreImports'); + + const prepared = prepareFromExports(imports); + + const id = randomUUID(); + + const snapshot = generateSingleStoreSnapshot(prepared.tables); + + return { + ...snapshot, + id, + prevId: prevId ?? originUUID, + }; +}; + +export const generateSingleStoreMigration = async ( + prev: DrizzleSingleStoreSnapshotJSON, + cur: DrizzleSingleStoreSnapshotJSON, +) => { + const { applySingleStoreSnapshotsDiff } = await import('./snapshotsDiffer'); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + ); + + return sqlStatements; +}; + +export const pushSingleStoreSchema = async ( + imports: Record, + drizzleInstance: SingleStoreDriverDatabase, + databaseName: string, +) => { + const { applySingleStoreSnapshotsDiff } = await import('./snapshotsDiffer'); + const { logSuggestionsAndReturn } = await import( + './cli/commands/singlestorePushUtils' + ); + const { singlestorePushIntrospect } = await import( + './cli/commands/singlestoreIntrospect' + ); + const { sql } = await import('drizzle-orm'); + + const db: DB = { + query: async (query: string, params?: any[]) => { + const res = await drizzleInstance.execute(sql.raw(query)); + return res[0] as unknown as any[]; + }, + }; + const cur = await generateSingleStoreDrizzleJson(imports); + const { schema: prev } = await singlestorePushIntrospect(db, databaseName, []); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { statements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + ); + + const { shouldAskForApprove, statementsToExecute, infoToPrint } = await logSuggestionsAndReturn( + db, + statements, + validatedCur, + ); + + return { + hasDataLoss: shouldAskForApprove, + warnings: infoToPrint, + statementsToExecute, + apply: async () => { + for (const dStmnt of statementsToExecute) { + await db.query(dStmnt); + } + }, + }; +}; + export const upPgSnapshot = (snapshot: Record) => { if (snapshot.version === '5') { return upPgV7(upPgV6(snapshot)); diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index db250d005..d24b71872 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -4,20 +4,24 @@ import { render, renderWithTask } from 'hanji'; import { Minimatch } from 'minimatch'; import { join } from 'path'; import { plural, singular } from 'pluralize'; +import { drySingleStore, SingleStoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; import { assertUnreachable, originUUID } from '../../global'; import { schemaToTypeScript as mysqlSchemaToTypeScript } from '../../introspect-mysql'; import { paramNameFor, schemaToTypeScript as postgresSchemaToTypeScript } from '../../introspect-pg'; +import { schemaToTypeScript as singlestoreSchemaToTypeScript } from '../../introspect-singlestore'; import { schemaToTypeScript as sqliteSchemaToTypeScript } from '../../introspect-sqlite'; import { dryMySql, MySqlSchema, squashMysqlScheme } from '../../serializer/mysqlSchema'; import { fromDatabase as fromMysqlDatabase } from '../../serializer/mysqlSerializer'; import { dryPg, type PgSchema, squashPgScheme } from '../../serializer/pgSchema'; import { fromDatabase as fromPostgresDatabase } from '../../serializer/pgSerializer'; +import { fromDatabase as fromSingleStoreDatabase } from '../../serializer/singlestoreSerializer'; import { drySQLite, type SQLiteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase } from '../../serializer/sqliteSerializer'; import { applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, } from '../../snapshotsDiffer'; import { prepareOutFolder } from '../../utils'; @@ -26,6 +30,7 @@ import type { Casing, Prefix } from '../validations/common'; import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; import type { PostgresCredentials } from '../validations/postgres'; +import { SingleStoreCredentials } from '../validations/singlestore'; import type { SqliteCredentials } from '../validations/sqlite'; import { IntrospectProgress } from '../views'; import { @@ -218,7 +223,6 @@ export const introspectMysql = async ( const schema = { id: originUUID, prevId: '', ...res } as MySqlSchema; const ts = mysqlSchemaToTypeScript(schema, casing); const relationsTs = relationsToTypeScript(schema, casing); - const { internal, ...schemaWithoutInternals } = schema; const schemaFile = join(out, 'schema.ts'); writeFileSync(schemaFile, ts.file); @@ -280,6 +284,102 @@ export const introspectMysql = async ( process.exit(0); }; +export const introspectSingleStore = async ( + casing: Casing, + out: string, + breakpoints: boolean, + credentials: SingleStoreCredentials, + tablesFilter: string[], + prefix: Prefix, +) => { + const { connectToSingleStore } = await import('../connections'); + const { db, database } = await connectToSingleStore(credentials); + + const matchers = tablesFilter.map((it) => { + return new Minimatch(it); + }); + + const filter = (tableName: string) => { + if (matchers.length === 0) return true; + + let flags: boolean[] = []; + + for (let matcher of matchers) { + if (matcher.negate) { + if (!matcher.match(tableName)) { + flags.push(false); + } + } + + if (matcher.match(tableName)) { + flags.push(true); + } + } + + if (flags.length > 0) { + return flags.every(Boolean); + } + return false; + }; + + const progress = new IntrospectProgress(); + const res = await renderWithTask( + progress, + fromSingleStoreDatabase(db, database, filter, (stage, count, status) => { + progress.update(stage, count, status); + }), + ); + + const schema = { id: originUUID, prevId: '', ...res } as SingleStoreSchema; + const ts = singlestoreSchemaToTypeScript(schema, casing); + const { internal, ...schemaWithoutInternals } = schema; + + const schemaFile = join(out, 'schema.ts'); + writeFileSync(schemaFile, ts.file); + console.log(); + + const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + + if (snapshots.length === 0) { + const { sqlStatements, _meta } = await applySingleStoreSnapshotsDiff( + squashSingleStoreScheme(drySingleStore), + squashSingleStoreScheme(schema), + tablesResolver, + columnsResolver, + drySingleStore, + schema, + ); + + writeResult({ + cur: schema, + sqlStatements, + journal, + _meta, + outFolder: out, + breakpoints, + type: 'introspect', + prefixMode: prefix, + }); + } else { + render( + `[${ + chalk.blue( + 'i', + ) + }] No SQL generated, you already have migrations in project`, + ); + } + + render( + `[${ + chalk.green( + '✓', + ) + }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + ); + process.exit(0); +}; + export const introspectSqlite = async ( casing: Casing, out: string, diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 0933af194..bce7ff010 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -4,6 +4,8 @@ import { prepareMySqlMigrationSnapshot, preparePgDbPushSnapshot, preparePgMigrationSnapshot, + prepareSingleStoreDbPushSnapshot, + prepareSingleStoreMigrationSnapshot, prepareSQLiteDbPushSnapshot, prepareSqliteMigrationSnapshot, } from '../../migrationPreparator'; @@ -11,6 +13,7 @@ import { import chalk from 'chalk'; import { render } from 'hanji'; import path, { join } from 'path'; +import { SingleStoreSchema, singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme, ViewSquashed } from '../../serializer/mysqlSchema'; @@ -20,6 +23,7 @@ import { applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, Column, ColumnsResolverInput, @@ -521,6 +525,150 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { } }; +// Not needed for now +function singleStoreSchemaSuggestions( + curSchema: TypeOf, + prevSchema: TypeOf, +) { + const suggestions: string[] = []; + const usedSuggestions: string[] = []; + const suggestionTypes = { + // TODO: Check if SingleStore has serial type + serial: withStyle.errorWarning( + `We deprecated the use of 'serial' for SingleStore starting from version 0.20.0. In SingleStore, 'serial' is simply an alias for 'bigint unsigned not null auto_increment unique,' which creates all constraints and indexes for you. This may make the process less explicit for both users and drizzle-kit push commands`, + ), + }; + + for (const table of Object.values(curSchema.tables)) { + for (const column of Object.values(table.columns)) { + if (column.type === 'serial') { + if (!usedSuggestions.includes('serial')) { + suggestions.push(suggestionTypes['serial']); + } + + const uniqueForSerial = Object.values( + prevSchema.tables[table.name].uniqueConstraints, + ).find((it) => it.columns[0] === column.name); + + suggestions.push( + `\n` + + withStyle.suggestion( + `We are suggesting to change ${ + chalk.blue( + column.name, + ) + } column in ${ + chalk.blueBright( + table.name, + ) + } table from serial to bigint unsigned\n\n${ + chalk.blueBright( + `bigint("${column.name}", { mode: "number", unsigned: true }).notNull().autoincrement().unique(${ + uniqueForSerial?.name ? `"${uniqueForSerial?.name}"` : '' + })`, + ) + }`, + ), + ); + } + } + } + + return suggestions; +} + +// Intersect with prepareAnMigrate +export const prepareSingleStorePush = async ( + schemaPath: string | string[], + snapshot: SingleStoreSchema, +) => { + try { + const { prev, cur } = await prepareSingleStoreDbPushSnapshot( + snapshot, + schemaPath, + ); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + 'push', + ); + + return { sqlStatements, statements, validatedCur, validatedPrev }; + } catch (e) { + console.error(e); + process.exit(1); + } +}; + +export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { + const outFolder = config.out; + const schemaPath = config.schema; + + try { + // TODO: remove + assertV1OutFolder(outFolder); + + const { snapshots, journal } = prepareMigrationFolder(outFolder, 'singlestore'); + const { prev, cur, custom } = await prepareSingleStoreMigrationSnapshot( + snapshots, + schemaPath, + ); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + if (config.custom) { + writeResult({ + cur: custom, + sqlStatements: [], + journal, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + type: 'custom', + prefixMode: config.prefix, + }); + return; + } + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements, statements, _meta } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + validatedPrev, + validatedCur, + ); + + writeResult({ + cur, + sqlStatements, + journal, + _meta, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + prefixMode: config.prefix, + }); + } catch (e) { + console.error(e); + } +}; + export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 4a41a46d4..e19e95455 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -10,10 +10,18 @@ import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; import { withStyle } from '../validations/outputs'; import type { PostgresCredentials } from '../validations/postgres'; +import { SingleStoreCredentials } from '../validations/singlestore'; import type { SqliteCredentials } from '../validations/sqlite'; import { libSqlLogSuggestionsAndReturn } from './libSqlPushUtils'; -import { filterStatements, logSuggestionsAndReturn } from './mysqlPushUtils'; +import { + filterStatements as mySqlFilterStatements, + logSuggestionsAndReturn as mySqlLogSuggestionsAndReturn, +} from './mysqlPushUtils'; import { pgSuggestions } from './pgPushUtils'; +import { + filterStatements as singleStoreFilterStatements, + logSuggestionsAndReturn as singleStoreLogSuggestionsAndReturn, +} from './singlestorePushUtils'; import { logSuggestionsAndReturn as sqliteSuggestions } from './sqlitePushUtils'; export const mysqlPush = async ( @@ -35,7 +43,7 @@ export const mysqlPush = async ( const statements = await prepareMySQLPush(schemaPath, schema, casing); - const filteredStatements = filterStatements( + const filteredStatements = mySqlFilterStatements( statements.statements ?? [], statements.validatedCur, statements.validatedPrev, @@ -52,8 +60,7 @@ export const mysqlPush = async ( tablesToRemove, tablesToTruncate, infoToPrint, - schemasToRemove, - } = await logSuggestionsAndReturn( + } = await mySqlLogSuggestionsAndReturn( db, filteredStatements, statements.validatedCur, @@ -156,6 +163,145 @@ export const mysqlPush = async ( } }; +export const singlestorePush = async ( + schemaPath: string | string[], + credentials: SingleStoreCredentials, + tablesFilter: string[], + strict: boolean, + verbose: boolean, + force: boolean, +) => { + const { connectToSingleStore } = await import('../connections'); + const { singlestorePushIntrospect } = await import('./singlestoreIntrospect'); + + const { db, database } = await connectToSingleStore(credentials); + + const { schema } = await singlestorePushIntrospect(db, database, tablesFilter); + const { prepareSingleStorePush } = await import('./migrate'); + + const statements = await prepareSingleStorePush(schemaPath, schema); + + const filteredStatements = singleStoreFilterStatements( + statements.statements ?? [], + statements.validatedCur, + statements.validatedPrev, + ); + + try { + if (filteredStatements.length === 0) { + render(`[${chalk.blue('i')}] No changes detected`); + } else { + const { + shouldAskForApprove, + statementsToExecute, + columnsToRemove, + tablesToRemove, + tablesToTruncate, + infoToPrint, + schemasToRemove, + } = await singleStoreLogSuggestionsAndReturn( + db, + filteredStatements, + statements.validatedCur, + ); + + const filteredSqlStatements = fromJson(filteredStatements, 'singlestore'); + + const uniqueSqlStatementsToExecute: string[] = []; + statementsToExecute.forEach((ss) => { + if (!uniqueSqlStatementsToExecute.includes(ss)) { + uniqueSqlStatementsToExecute.push(ss); + } + }); + const uniqueFilteredSqlStatements: string[] = []; + filteredSqlStatements.forEach((ss) => { + if (!uniqueFilteredSqlStatements.includes(ss)) { + uniqueFilteredSqlStatements.push(ss); + } + }); + + if (verbose) { + console.log(); + console.log( + withStyle.warning('You are about to execute current statements:'), + ); + console.log(); + console.log( + [...uniqueSqlStatementsToExecute, ...uniqueFilteredSqlStatements] + .map((s) => chalk.blue(s)) + .join('\n'), + ); + console.log(); + } + + if (!force && strict) { + if (!shouldAskForApprove) { + const { status, data } = await render( + new Select(['No, abort', `Yes, I want to execute all statements`]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + } + + if (!force && shouldAskForApprove) { + console.log(withStyle.warning('Found data-loss statements:')); + console.log(infoToPrint.join('\n')); + console.log(); + console.log( + chalk.red.bold( + 'THIS ACTION WILL CAUSE DATA LOSS AND CANNOT BE REVERTED\n', + ), + ); + + console.log(chalk.white('Do you still want to push changes?')); + + const { status, data } = await render( + new Select([ + 'No, abort', + `Yes, I want to${ + tablesToRemove.length > 0 + ? ` remove ${tablesToRemove.length} ${tablesToRemove.length > 1 ? 'tables' : 'table'},` + : ' ' + }${ + columnsToRemove.length > 0 + ? ` remove ${columnsToRemove.length} ${columnsToRemove.length > 1 ? 'columns' : 'column'},` + : ' ' + }${ + tablesToTruncate.length > 0 + ? ` truncate ${tablesToTruncate.length} ${tablesToTruncate.length > 1 ? 'tables' : 'table'}` + : '' + }` + .replace(/(^,)|(,$)/g, '') + .replace(/ +(?= )/g, ''), + ]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + + for (const dStmnt of uniqueSqlStatementsToExecute) { + await db.query(dStmnt); + } + + for (const statement of uniqueFilteredSqlStatements) { + await db.query(statement); + } + if (filteredStatements.length > 0) { + render(`[${chalk.green('✓')}] Changes applied`); + } else { + render(`[${chalk.blue('i')}] No changes detected`); + } + } + } catch (e) { + console.log(e); + } +}; + export const pgPush = async ( schemaPath: string | string[], verbose: boolean, @@ -309,7 +455,6 @@ export const sqlitePush = async ( tablesToRemove, tablesToTruncate, infoToPrint, - schemasToRemove, } = await sqliteSuggestions( db, statements.statements, diff --git a/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts b/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts new file mode 100644 index 000000000..27d8c59c5 --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts @@ -0,0 +1,53 @@ +import { renderWithTask } from 'hanji'; +import { Minimatch } from 'minimatch'; +import { originUUID } from '../../global'; +import type { SingleStoreSchema } from '../../serializer/singlestoreSchema'; +import { fromDatabase } from '../../serializer/singlestoreSerializer'; +import type { DB } from '../../utils'; +import { ProgressView } from '../views'; + +export const singlestorePushIntrospect = async ( + db: DB, + databaseName: string, + filters: string[], +) => { + const matchers = filters.map((it) => { + return new Minimatch(it); + }); + + const filter = (tableName: string) => { + if (matchers.length === 0) return true; + + let flags: boolean[] = []; + + for (let matcher of matchers) { + if (matcher.negate) { + if (!matcher.match(tableName)) { + flags.push(false); + } + } + + if (matcher.match(tableName)) { + flags.push(true); + } + } + + if (flags.length > 0) { + return flags.every(Boolean); + } + return false; + }; + + const progress = new ProgressView( + 'Pulling schema from database...', + 'Pulling schema from database...', + ); + const res = await renderWithTask( + progress, + fromDatabase(db, databaseName, filter), + ); + + const schema = { id: originUUID, prevId: '', ...res } as SingleStoreSchema; + const { internal, ...schemaWithoutInternals } = schema; + return { schema: schemaWithoutInternals }; +}; diff --git a/drizzle-kit/src/cli/commands/singlestorePushUtils.ts b/drizzle-kit/src/cli/commands/singlestorePushUtils.ts new file mode 100644 index 000000000..80fad9b2d --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestorePushUtils.ts @@ -0,0 +1,352 @@ +import chalk from 'chalk'; +import { render } from 'hanji'; +import { TypeOf } from 'zod'; +import { JsonAlterColumnTypeStatement, JsonStatement } from '../../jsonStatements'; +import { singlestoreSchema, SingleStoreSquasher } from '../../serializer/singlestoreSchema'; +import type { DB } from '../../utils'; +import { Select } from '../selector-ui'; +import { withStyle } from '../validations/outputs'; + +export const filterStatements = ( + statements: JsonStatement[], + currentSchema: TypeOf, + prevSchema: TypeOf, +) => { + return statements.filter((statement) => { + if (statement.type === 'alter_table_alter_column_set_type') { + // Don't need to handle it on migrations step and introspection + // but for both it should be skipped + if ( + statement.oldDataType.startsWith('tinyint') + && statement.newDataType.startsWith('boolean') + ) { + return false; + } + + if ( + statement.oldDataType.startsWith('bigint unsigned') + && statement.newDataType.startsWith('serial') + ) { + return false; + } + + if ( + statement.oldDataType.startsWith('serial') + && statement.newDataType.startsWith('bigint unsigned') + ) { + return false; + } + } else if (statement.type === 'alter_table_alter_column_set_default') { + if ( + statement.newDefaultValue === false + && statement.oldDefaultValue === 0 + && statement.newDataType === 'boolean' + ) { + return false; + } + if ( + statement.newDefaultValue === true + && statement.oldDefaultValue === 1 + && statement.newDataType === 'boolean' + ) { + return false; + } + } else if (statement.type === 'delete_unique_constraint') { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); + // only if constraint was removed from a serial column, than treat it as removed + // const serialStatement = statements.find( + // (it) => it.type === "alter_table_alter_column_set_type" + // ) as JsonAlterColumnTypeStatement; + // if ( + // serialStatement?.oldDataType.startsWith("bigint unsigned") && + // serialStatement?.newDataType.startsWith("serial") && + // serialStatement.columnName === + // SingleStoreSquasher.unsquashUnique(statement.data).columns[0] + // ) { + // return false; + // } + // Check if uniqueindex was only on this column, that is serial + + // if now serial and was not serial and was unique index + if ( + unsquashed.columns.length === 1 + && currentSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .type === 'serial' + && prevSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .type === 'serial' + && currentSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .name === unsquashed.columns[0] + ) { + return false; + } + } else if (statement.type === 'alter_table_alter_column_drop_notnull') { + // only if constraint was removed from a serial column, than treat it as removed + const serialStatement = statements.find( + (it) => it.type === 'alter_table_alter_column_set_type', + ) as JsonAlterColumnTypeStatement; + if ( + serialStatement?.oldDataType.startsWith('bigint unsigned') + && serialStatement?.newDataType.startsWith('serial') + && serialStatement.columnName === statement.columnName + && serialStatement.tableName === statement.tableName + ) { + return false; + } + if (statement.newDataType === 'serial' && !statement.columnNotNull) { + return false; + } + if (statement.columnAutoIncrement) { + return false; + } + } + + return true; + }); +}; + +export const logSuggestionsAndReturn = async ( + db: DB, + statements: JsonStatement[], + json2: TypeOf, +) => { + let shouldAskForApprove = false; + const statementsToExecute: string[] = []; + const infoToPrint: string[] = []; + + const tablesToRemove: string[] = []; + const columnsToRemove: string[] = []; + const schemasToRemove: string[] = []; + const tablesToTruncate: string[] = []; + + for (const statement of statements) { + if (statement.type === 'drop_table') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.tableName, + ) + } table with ${count} items`, + ); + tablesToRemove.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_drop_column') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.columnName, + ) + } column in ${statement.tableName} table with ${count} items`, + ); + columnsToRemove.push(`${statement.tableName}_${statement.columnName}`); + shouldAskForApprove = true; + } + } else if (statement.type === 'drop_schema') { + const res = await db.query( + `select count(*) as count from information_schema.tables where table_schema = \`${statement.name}\`;`, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.name, + ) + } schema with ${count} tables`, + ); + schemasToRemove.push(statement.name); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_alter_column_set_type') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to change ${ + chalk.underline( + statement.columnName, + ) + } column type from ${ + chalk.underline( + statement.oldDataType, + ) + } to ${chalk.underline(statement.newDataType)} with ${count} items`, + ); + statementsToExecute.push(`truncate table ${statement.tableName};`); + tablesToTruncate.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_alter_column_drop_default') { + if (statement.columnNotNull) { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to remove default value from ${ + chalk.underline( + statement.columnName, + ) + } not-null column with ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + // shouldAskForApprove = true; + } else if (statement.type === 'alter_table_alter_column_set_notnull') { + if (typeof statement.columnDefault === 'undefined') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to set not-null constraint to ${ + chalk.underline( + statement.columnName, + ) + } column without default, which contains ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + } else if (statement.type === 'alter_table_alter_column_drop_pk') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + // if drop pk and json2 has autoincrement in table -> exit process with error + if ( + Object.values(json2.tables[statement.tableName].columns).filter( + (column) => column.autoincrement, + ).length > 0 + ) { + console.log( + `${ + withStyle.errorWarning( + `You have removed the primary key from a ${statement.tableName} table without removing the auto-increment property from this table. As the database error states: 'there can be only one auto column, and it must be defined as a key. Make sure to remove autoincrement from ${statement.tableName} table`, + ) + }`, + ); + process.exit(1); + } + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to change ${ + chalk.underline( + statement.tableName, + ) + } primary key. This statements may fail and you table may left without primary key`, + ); + + tablesToTruncate.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'delete_composite_pk') { + // if drop pk and json2 has autoincrement in table -> exit process with error + if ( + Object.values(json2.tables[statement.tableName].columns).filter( + (column) => column.autoincrement, + ).length > 0 + ) { + console.log( + `${ + withStyle.errorWarning( + `You have removed the primary key from a ${statement.tableName} table without removing the auto-increment property from this table. As the database error states: 'there can be only one auto column, and it must be defined as a key. Make sure to remove autoincrement from ${statement.tableName} table`, + ) + }`, + ); + process.exit(1); + } + } else if (statement.type === 'alter_table_add_column') { + if ( + statement.column.notNull + && typeof statement.column.default === 'undefined' + ) { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + statement.column.name, + ) + } column without default value, which contains ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + } else if (statement.type === 'create_unique_constraint') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + const unsquashedUnique = SingleStoreSquasher.unsquashUnique(statement.data); + console.log( + `· You're about to add ${ + chalk.underline( + unsquashedUnique.name, + ) + } unique constraint to the table, which contains ${count} items. If this statement fails, you will receive an error from the database. Do you want to truncate ${ + chalk.underline( + statement.tableName, + ) + } table?\n`, + ); + const { status, data } = await render( + new Select([ + 'No, add the constraint without truncating the table', + `Yes, truncate the table`, + ]), + ); + if (data?.index === 1) { + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + shouldAskForApprove = true; + } + } + } + } + + return { + statementsToExecute, + shouldAskForApprove, + infoToPrint, + columnsToRemove: [...new Set(columnsToRemove)], + schemasToRemove: [...new Set(schemasToRemove)], + tablesToTruncate: [...new Set(tablesToTruncate)], + tablesToRemove: [...new Set(tablesToRemove)], + }; +}; diff --git a/drizzle-kit/src/cli/commands/singlestoreUp.ts b/drizzle-kit/src/cli/commands/singlestoreUp.ts new file mode 100644 index 000000000..dc5004ed0 --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestoreUp.ts @@ -0,0 +1 @@ +export const upSinglestoreHandler = (out: string) => {}; diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 7386b74d5..a993c3a80 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -31,13 +31,18 @@ import { postgresCredentials, printConfigConnectionIssues as printIssuesPg, } from '../validations/postgres'; +import { + printConfigConnectionIssues as printIssuesSingleStore, + SingleStoreCredentials, + singlestoreCredentials, +} from '../validations/singlestore'; import { printConfigConnectionIssues as printIssuesSqlite, SqliteCredentials, sqliteCredentials, } from '../validations/sqlite'; import { studioCliParams, studioConfig } from '../validations/studio'; -import { error, grey } from '../views'; +import { error } from '../views'; // NextJs default config is target: es5, which esbuild-register can't consume const assertES5 = async (unregister: () => void) => { @@ -222,6 +227,10 @@ export const preparePushConfig = async ( dialect: 'turso'; credentials: LibSQLCredentials; } + | { + dialect: 'singlestore'; + credentials: SingleStoreCredentials; + } ) & { schemaPath: string | string[]; verbose: boolean; @@ -316,6 +325,25 @@ export const preparePushConfig = async ( }; } + if (config.dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(config); + if (!parsed.success) { + printIssuesSingleStore(config); + process.exit(1); + } + + return { + dialect: 'singlestore', + schemaPath: config.schema, + strict: config.strict ?? false, + verbose: config.verbose ?? false, + force: (options.force as boolean) ?? false, + credentials: parsed.data, + tablesFilter, + schemasFilter, + }; + } + if (config.dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(config); if (!parsed.success) { @@ -378,6 +406,10 @@ export const preparePullConfig = async ( dialect: 'turso'; credentials: LibSQLCredentials; } + | { + dialect: 'singlestore'; + credentials: SingleStoreCredentials; + } ) & { out: string; breakpoints: boolean; @@ -468,6 +500,25 @@ export const preparePullConfig = async ( }; } + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(config); + if (!parsed.success) { + printIssuesSingleStore(config); + process.exit(1); + } + + return { + dialect: 'singlestore', + out: config.out, + breakpoints: config.breakpoints, + casing: config.casing, + credentials: parsed.data, + tablesFilter, + schemasFilter, + prefix: config.migrations?.prefix || 'index', + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(config); if (!parsed.success) { @@ -559,6 +610,23 @@ export const prepareStudioConfig = async (options: Record) => { credentials, }; } + + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesSingleStore(flattened as Record); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + schema, + host, + port, + credentials, + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(flattened); if (!parsed.success) { @@ -644,6 +712,23 @@ export const prepareMigrateConfig = async (configPath: string | undefined) => { table, }; } + + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesSingleStore(flattened as Record); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + out, + credentials, + schema, + table, + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(flattened); if (!parsed.success) { diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index aab1d0ef7..f2cf4817c 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -19,6 +19,7 @@ import { LibSQLCredentials } from './validations/libsql'; import type { MysqlCredentials } from './validations/mysql'; import { withStyle } from './validations/outputs'; import type { PostgresCredentials } from './validations/postgres'; +import { SingleStoreCredentials } from './validations/singlestore'; import type { SqliteCredentials } from './validations/sqlite'; export const preparePostgresDB = async ( @@ -415,6 +416,85 @@ export const preparePostgresDB = async ( process.exit(1); }; +const parseSingleStoreCredentials = (credentials: SingleStoreCredentials) => { + if ('url' in credentials) { + const url = credentials.url; + + const connectionUrl = new URL(url); + const pathname = connectionUrl.pathname; + + const database = pathname.split('/')[pathname.split('/').length - 1]; + if (!database) { + console.error( + 'You should specify a database name in connection string (singlestore://USER:PASSWORD@HOST:PORT/DATABASE)', + ); + process.exit(1); + } + return { database, url }; + } else { + return { + database: credentials.database, + credentials, + }; + } +}; + +export const connectToSingleStore = async ( + it: SingleStoreCredentials, +): Promise<{ + db: DB; + proxy: Proxy; + database: string; + migrate: (config: MigrationConfig) => Promise; +}> => { + const result = parseSingleStoreCredentials(it); + + if (await checkPackage('mysql2')) { + const { createConnection } = await import('mysql2/promise'); + const { drizzle } = await import('drizzle-orm/singlestore'); + const { migrate } = await import('drizzle-orm/singlestore/migrator'); + + const connection = result.url + ? await createConnection(result.url) + : await createConnection(result.credentials!); // needed for some reason! + + const db = drizzle(connection); + const migrateFn = async (config: MigrationConfig) => { + return migrate(db, config); + }; + + await connection.connect(); + const query: DB['query'] = async ( + sql: string, + params?: any[], + ): Promise => { + const res = await connection.execute(sql, params); + return res[0] as any; + }; + + const proxy: Proxy = async (params: ProxyParams) => { + const result = await connection.query({ + sql: params.sql, + values: params.params, + rowsAsArray: params.mode === 'array', + }); + return result[0] as any[]; + }; + + return { + db: { query }, + proxy, + database: result.database, + migrate: migrateFn, + }; + } + + console.error( + "To connect to SingleStore database - please install 'singlestore' driver", + ); + process.exit(1); +}; + const parseMysqlCredentials = (credentials: MysqlCredentials) => { if ('url' in credentials) { const url = credentials.url; diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index b03acde95..72d5a282b 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -1,11 +1,19 @@ +import { boolean, command, number, string } from '@drizzle-team/brocli'; import chalk from 'chalk'; -import { checkHandler } from './commands/check'; -import { assertOrmCoreVersion, assertPackages, assertStudioNodeVersion, ormVersionGt } from './utils'; +import 'dotenv/config'; +import { mkdirSync } from 'fs'; +import { renderWithTask } from 'hanji'; +import { dialects } from 'src/schemaValidator'; import '../@types/utils'; +import { assertUnreachable } from '../global'; +import { type Setup } from '../serializer/studio'; import { assertV1OutFolder } from '../utils'; +import { certs } from '../utils/certs'; +import { checkHandler } from './commands/check'; import { dropMigration } from './commands/drop'; import { upMysqlHandler } from './commands/mysqlUp'; import { upPgHandler } from './commands/pgUp'; +import { upSinglestoreHandler } from './commands/singlestoreUp'; import { upSqliteHandler } from './commands/sqliteUp'; import { prepareCheckParams, @@ -16,21 +24,14 @@ import { preparePushConfig, prepareStudioConfig, } from './commands/utils'; +import { assertOrmCoreVersion, assertPackages, assertStudioNodeVersion, ormVersionGt } from './utils'; import { assertCollisions, drivers, prefixes } from './validations/common'; import { withStyle } from './validations/outputs'; -import 'dotenv/config'; -import { boolean, command, number, string } from '@drizzle-team/brocli'; -import { mkdirSync } from 'fs'; -import { renderWithTask } from 'hanji'; -import { dialects } from 'src/schemaValidator'; -import { assertUnreachable } from '../global'; -import type { Setup } from '../serializer/studio'; -import { certs } from '../utils/certs'; import { grey, MigrateProgress } from './views'; const optionDialect = string('dialect') .enum(...dialects) - .desc(`Database dialect: 'postgresql', 'mysql', 'sqlite' or 'turso'`); + .desc(`Database dialect: 'postgresql', 'mysql', 'sqlite', 'turso' or 'singlestore'`); const optionOut = string().desc("Output folder, 'drizzle' by default"); const optionConfig = string().desc('Path to drizzle config file'); const optionBreakpoints = boolean().desc( @@ -81,6 +82,7 @@ export const generate = command({ prepareAndMigrateMysql, prepareAndMigrateSqlite, prepareAndMigrateLibSQL, + prepareAndMigrateSingleStore, } = await import('./commands/migrate'); const dialect = opts.dialect; @@ -92,6 +94,8 @@ export const generate = command({ await prepareAndMigrateSqlite(opts); } else if (dialect === 'turso') { await prepareAndMigrateLibSQL(opts); + } else if (dialect === 'singlestore') { + await prepareAndMigrateSqlite(opts); } else { assertUnreachable(dialect); } @@ -154,6 +158,17 @@ export const migrate = command({ migrationsSchema: schema, }), ); + } else if (dialect === 'singlestore') { + const { connectToSingleStore } = await import('./connections'); + const { migrate } = await connectToSingleStore(credentials); + await renderWithTask( + new MigrateProgress(), + migrate({ + migrationsFolder: out, + migrationsTable: table, + migrationsSchema: schema, + }), + ); } else if (dialect === 'sqlite') { const { connectToSQLite } = await import('./connections'); const { migrate } = await connectToSQLite(credentials); @@ -340,6 +355,16 @@ export const push = command({ force, casing, ); + } else if (dialect === 'singlestore') { + const { singlestorePush } = await import('./commands/push'); + await singlestorePush( + schemaPath, + credentials, + tablesFilter, + strict, + verbose, + force, + ); } else { assertUnreachable(dialect); } @@ -398,6 +423,10 @@ export const up = command({ if (dialect === 'sqlite' || dialect === 'turso') { upSqliteHandler(out); } + + if (dialect === 'singlestore') { + upSinglestoreHandler(out); + } }, }); @@ -531,6 +560,16 @@ export const pull = command({ tablesFilter, prefix, ); + } else if (dialect === 'singlestore') { + const { introspectSingleStore } = await import('./commands/introspect'); + await introspectSingleStore( + casing, + out, + breakpoints, + credentials, + tablesFilter, + prefix, + ); } else { assertUnreachable(dialect); } @@ -592,6 +631,8 @@ export const studio = command({ prepareSQLiteSchema, drizzleForSQLite, drizzleForLibSQL, + prepareSingleStoreSchema, + drizzleForSingleStore, } = await import('../serializer/studio'); let setup: Setup; @@ -637,6 +678,11 @@ export const studio = command({ ? await prepareSQLiteSchema(schemaPath) : { schema: {}, relations: {}, files: [] }; setup = await drizzleForLibSQL(credentials, schema, relations, files); + } else if (dialect === 'singlestore') { + const { schema, relations, files } = schemaPath + ? await prepareSingleStoreSchema(schemaPath) + : { schema: {}, relations: {}, files: [] }; + setup = await drizzleForSingleStore(credentials, schema, relations, files); } else { assertUnreachable(dialect); } diff --git a/drizzle-kit/src/cli/validations/outputs.ts b/drizzle-kit/src/cli/validations/outputs.ts index 3ef499651..bb283468c 100644 --- a/drizzle-kit/src/cli/validations/outputs.ts +++ b/drizzle-kit/src/cli/validations/outputs.ts @@ -26,7 +26,7 @@ export const outputs = { ), noDialect: () => withStyle.error( - `Please specify 'dialect' param in config, either of 'postgresql', 'mysql', 'sqlite' or 'turso'`, + `Please specify 'dialect' param in config, either of 'postgresql', 'mysql', 'sqlite', 'singlestore' or 'turso'`, ), }, common: { @@ -79,4 +79,13 @@ export const outputs = { introspect: {}, push: {}, }, + singlestore: { + connection: { + driver: () => withStyle.error(`Only "mysql2" is available options for "--driver"`), + required: () => + withStyle.error( + `Either "url" or "host", "database" are required for database connection`, + ), + }, + }, }; diff --git a/drizzle-kit/src/cli/validations/singlestore.ts b/drizzle-kit/src/cli/validations/singlestore.ts new file mode 100644 index 000000000..ebe0cc5f0 --- /dev/null +++ b/drizzle-kit/src/cli/validations/singlestore.ts @@ -0,0 +1,61 @@ +import { boolean, coerce, object, string, TypeOf, union } from 'zod'; +import { error } from '../views'; +import { wrapParam } from './common'; +import { outputs } from './outputs'; + +export const singlestoreCredentials = union([ + object({ + host: string().min(1), + port: coerce.number().min(1).optional(), + user: string().min(1).optional(), + password: string().min(1).optional(), + database: string().min(1), + ssl: union([ + string(), + object({ + pfx: string().optional(), + key: string().optional(), + passphrase: string().optional(), + cert: string().optional(), + ca: union([string(), string().array()]).optional(), + crl: union([string(), string().array()]).optional(), + ciphers: string().optional(), + rejectUnauthorized: boolean().optional(), + }), + ]).optional(), + }), + object({ + url: string().min(1), + }), +]); + +export type SingleStoreCredentials = TypeOf; + +export const printCliConnectionIssues = (options: any) => { + const { uri, host, database } = options || {}; + + if (!uri && (!host || !database)) { + console.log(outputs.singlestore.connection.required()); + } +}; + +export const printConfigConnectionIssues = ( + options: Record, +) => { + if ('url' in options) { + let text = `Please provide required params for SingleStore driver:\n`; + console.log(error(text)); + console.log(wrapParam('url', options.url, false, 'url')); + process.exit(1); + } + + let text = `Please provide required params for SingleStore driver:\n`; + console.log(error(text)); + console.log(wrapParam('host', options.host)); + console.log(wrapParam('port', options.port, true)); + console.log(wrapParam('user', options.user, true)); + console.log(wrapParam('password', options.password, true, 'secret')); + console.log(wrapParam('database', options.database)); + console.log(wrapParam('ssl', options.ssl, true)); + process.exit(1); +}; diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 4a57e59e3..b59581dd0 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -23,7 +23,7 @@ type Verify = U; * **Config** usage: * * `dialect` - mandatory and is responsible for explicitly providing a databse dialect you are using for all the commands - * *Possible values*: `postgresql`, `mysql`, `sqlite` + * *Possible values*: `postgresql`, `mysql`, `sqlite`, `singlestore * * See https://orm.drizzle.team/kit-docs/config-reference#dialect * @@ -64,7 +64,7 @@ type Verify = U; * * `breakpoints` - param lets you enable/disable SQL statement breakpoints in generated migrations. * It’s optional and true by default, it’s necessary to properly apply migrations on databases, - * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite) and + * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite, SingleStore) and * Drizzle ORM has to apply them sequentially one by one. * * See https://orm.drizzle.team/kit-docs/config-reference#breakpoints @@ -210,6 +210,21 @@ export type Config = driver: Verify; } | {} + | { + dialect: Verify; + dbCredentials: + | { + host: string; + port?: number; + user?: string; + password?: string; + database: string; + ssl?: string | SslOptions; + } + | { + url: string; + }; + } ); /** @@ -219,7 +234,7 @@ export type Config = * **Config** usage: * * `dialect` - mandatory and is responsible for explicitly providing a databse dialect you are using for all the commands - * *Possible values*: `postgresql`, `mysql`, `sqlite` + * *Possible values*: `postgresql`, `mysql`, `sqlite`, `singlestore` * * See https://orm.drizzle.team/kit-docs/config-reference#dialect * @@ -260,7 +275,7 @@ export type Config = * * `breakpoints` - param lets you enable/disable SQL statement breakpoints in generated migrations. * It’s optional and true by default, it’s necessary to properly apply migrations on databases, - * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite) and + * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite, SingleStore) and * Drizzle ORM has to apply them sequentially one by one. * * See https://orm.drizzle.team/kit-docs/config-reference#breakpoints diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts new file mode 100644 index 000000000..8aa6e3dd7 --- /dev/null +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -0,0 +1,780 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +import './@types/utils'; +import type { Casing } from './cli/validations/common'; +import { Column, Index, PrimaryKey, SingleStoreSchemaInternal, UniqueConstraint } from './serializer/singlestoreSchema'; +import { indexName } from './serializer/singlestoreSerializer'; + +// time precision to fsp +// {mode: "string"} for timestamp by default + +const singlestoreImportsList = new Set([ + 'singlestoreTable', + 'singlestoreEnum', + 'bigint', + 'binary', + 'boolean', + 'char', + 'date', + 'datetime', + 'decimal', + 'double', + 'float', + 'int', + 'json', + // TODO: add new type BSON + // TODO: add new type Blob + // TODO: add new type UUID + // TODO: add new type GUID + // TODO: add new type Vector + // TODO: add new type GeoPoint + 'mediumint', + 'real', + 'serial', + 'smallint', + 'text', + 'tinytext', + 'mediumtext', + 'longtext', + 'time', + 'timestamp', + 'tinyint', + 'varbinary', + 'varchar', + 'year', + 'enum', +]); + +const objToStatement = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `"${it}": "${json[it]}"`).join(', '); + statement += ' }'; + return statement; +}; + +const objToStatement2 = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: "${json[it]}"`).join(', '); // no "" for keys + statement += ' }'; + return statement; +}; + +const timeConfig = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: ${json[it]}`).join(', '); + statement += ' }'; + return statement; +}; + +const binaryConfig = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: ${json[it]}`).join(', '); + statement += ' }'; + return statement; +}; + +const importsPatch = { + 'double precision': 'doublePrecision', + 'timestamp without time zone': 'timestamp', +} as Record; + +const relations = new Set(); + +const prepareCasing = (casing?: Casing) => (value: string) => { + if (typeof casing === 'undefined') { + return value; + } + if (casing === 'camel') { + return value.camelCase(); + } + + return value; +}; + +export const schemaToTypeScript = ( + schema: SingleStoreSchemaInternal, + casing: Casing, +) => { + const withCasing = prepareCasing(casing); + + const imports = Object.values(schema.tables).reduce( + (res, it) => { + const idxImports = Object.values(it.indexes).map((idx) => idx.isUnique ? 'uniqueIndex' : 'index'); + const pkImports = Object.values(it.compositePrimaryKeys).map( + (it) => 'primaryKey', + ); + const uniqueImports = Object.values(it.uniqueConstraints).map( + (it) => 'unique', + ); + + res.singlestore.push(...idxImports); + res.singlestore.push(...pkImports); + res.singlestore.push(...uniqueImports); + + const columnImports = Object.values(it.columns) + .map((col) => { + let patched = importsPatch[col.type] ?? col.type; + patched = patched.startsWith('varchar(') ? 'varchar' : patched; + patched = patched.startsWith('char(') ? 'char' : patched; + patched = patched.startsWith('binary(') ? 'binary' : patched; + patched = patched.startsWith('decimal(') ? 'decimal' : patched; + patched = patched.startsWith('smallint(') ? 'smallint' : patched; + patched = patched.startsWith('enum(') ? 'singlestoreEnum' : patched; + patched = patched.startsWith('datetime(') ? 'datetime' : patched; + patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; + patched = patched.startsWith('int(') ? 'int' : patched; + return patched; + }) + .filter((type) => { + return singlestoreImportsList.has(type); + }); + + res.singlestore.push(...columnImports); + return res; + }, + { singlestore: [] as string[] }, + ); + + const tableStatements = Object.values(schema.tables).map((table) => { + const func = 'singlestoreTable'; + let statement = ''; + if (imports.singlestore.includes(withCasing(table.name))) { + statement = `// Table name is in conflict with ${ + withCasing( + table.name, + ) + } import.\n// Please change to any other name, that is not in imports list\n`; + } + statement += `export const ${withCasing(table.name)} = ${func}("${table.name}", {\n`; + statement += createTableColumns( + Object.values(table.columns), + withCasing, + table.name, + schema, + ); + statement += '}'; + + if ( + Object.keys(table.indexes).length > 0 + || Object.keys(table.compositePrimaryKeys).length > 0 + || Object.keys(table.uniqueConstraints).length > 0 + ) { + statement += ',\n'; + statement += '(table) => {\n'; + statement += '\treturn {\n'; + statement += createTableIndexes( + table.name, + Object.values(table.indexes), + withCasing, + ); + statement += createTablePKs( + Object.values(table.compositePrimaryKeys), + withCasing, + ); + statement += createTableUniques( + Object.values(table.uniqueConstraints), + withCasing, + ); + statement += '\t}\n'; + statement += '}'; + } + + statement += ');'; + return statement; + }); + + const uniqueSingleStoreImports = [ + 'singlestoreTable', + 'singlestoreSchema', + 'AnySingleStoreColumn', + ...new Set(imports.singlestore), + ]; + const importsTs = `import { ${ + uniqueSingleStoreImports.join( + ', ', + ) + } } from "drizzle-orm/singlestore-core"\nimport { sql } from "drizzle-orm"\n\n`; + + let decalrations = ''; + decalrations += tableStatements.join('\n\n'); + + const file = importsTs + decalrations; + + const schemaEntry = ` + { + ${ + Object.values(schema.tables) + .map((it) => withCasing(it.name)) + .join(',') + } + } + `; + + return { + file, // backward compatible, print to file + imports: importsTs, + decalrations, + schemaEntry, + }; +}; + +const mapColumnDefault = (defaultValue: any, isExpression?: boolean) => { + if (isExpression) { + return `sql\`${defaultValue}\``; + } + + return defaultValue; +}; + +const mapColumnDefaultForJson = (defaultValue: any) => { + if ( + typeof defaultValue === 'string' + && defaultValue.startsWith("('") + && defaultValue.endsWith("')") + ) { + return defaultValue.substring(2, defaultValue.length - 2); + } + + return defaultValue; +}; + +const column = ( + type: string, + name: string, + casing: (value: string) => string, + defaultValue?: any, + autoincrement?: boolean, + onUpdate?: boolean, + isExpression?: boolean, +) => { + let lowered = type; + if (!type.startsWith('enum(')) { + lowered = type.toLowerCase(); + } + + if (lowered === 'serial') { + return `${casing(name)}: serial("${name}")`; + } + + if (lowered.startsWith('int')) { + const isUnsigned = lowered.startsWith('int unsigned'); + let out = `${casing(name)}: int("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('tinyint')) { + const isUnsigned = lowered.startsWith('tinyint unsigned'); + // let out = `${name.camelCase()}: tinyint("${name}")`; + let out: string = `${casing(name)}: tinyint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('smallint')) { + const isUnsigned = lowered.startsWith('smallint unsigned'); + let out = `${casing(name)}: smallint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('mediumint')) { + const isUnsigned = lowered.startsWith('mediumint unsigned'); + let out = `${casing(name)}: mediumint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('bigint')) { + const isUnsigned = lowered.startsWith('bigint unsigned'); + let out = `${casing(name)}: bigint("${name}", { mode: "number"${isUnsigned ? ', unsigned: true' : ''} })`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'boolean') { + let out = `${casing(name)}: boolean("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('double')) { + let params: + | { precision: string | undefined; scale: string | undefined } + | undefined; + + if (lowered.length > 6) { + const [precision, scale] = lowered + .slice(7, lowered.length - 1) + .split(','); + params = { precision, scale }; + } + + let out = params + ? `${casing(name)}: double("${name}", ${timeConfig(params)})` + : `${casing(name)}: double("${name}")`; + + // let out = `${name.camelCase()}: double("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'float') { + let out = `${casing(name)}: float("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'real') { + let out = `${casing(name)}: real("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('timestamp')) { + const keyLength = 'timestamp'.length + 1; + let fsp = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + fsp = fsp ? fsp : null; + + const params = timeConfig({ fsp, mode: "'string'" }); + + let out = params + ? `${casing(name)}: timestamp("${name}", ${params})` + : `${casing(name)}: timestamp("${name}")`; + + // TODO: check if SingleStore has defaultNow() or now() + defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + + // TODO: check if SingleStore has onUpdateNow() + let onUpdateNow = onUpdate ? '.onUpdateNow()' : ''; + out += onUpdateNow; + + return out; + } + + if (lowered.startsWith('time')) { + const keyLength = 'time'.length + 1; + let fsp = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + fsp = fsp ? fsp : null; + + const params = timeConfig({ fsp }); + + let out = params + ? `${casing(name)}: time("${name}", ${params})` + : `${casing(name)}: time("${name}")`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered === 'date') { + let out = `// you can use { mode: 'date' }, if you want to have Date as type for this column\n\t${ + casing( + name, + ) + }: date("${name}", { mode: 'string' })`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has text can't have default value + if (lowered === 'text') { + let out = `${casing(name)}: text("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has tinytext can't have default value + if (lowered === 'tinytext') { + let out = `${casing(name)}: tinytext("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has mediumtext can't have default value + if (lowered === 'mediumtext') { + let out = `${casing(name)}: mediumtext("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql text can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has longtext can't have default value + if (lowered === 'longtext') { + let out = `${casing(name)}: longtext("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'year') { + let out = `${casing(name)}: year("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in mysql json can't have default value. Will leave it in case smth ;) + // TODO: check if SingleStore has json can't have default value + if (lowered === 'json') { + let out = `${casing(name)}: json("${name}")`; + + out += defaultValue + ? `.default(${mapColumnDefaultForJson(defaultValue)})` + : ''; + + return out; + } + + // TODO: add new type BSON + + // TODO: add new type Blob + + // TODO: add new type UUID + + // TODO: add new type GUID + + // TODO: add new type Vector + + // TODO: add new type GeoPoint + + if (lowered.startsWith('varchar')) { + let out: string = `${ + casing( + name, + ) + }: varchar("${name}", { length: ${ + lowered.substring( + 'varchar'.length + 1, + lowered.length - 1, + ) + } })`; + + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('char')) { + let out: string = `${ + casing( + name, + ) + }: char("${name}", { length: ${ + lowered.substring( + 'char'.length + 1, + lowered.length - 1, + ) + } })`; + + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('datetime')) { + let out = `// you can use { mode: 'date' }, if you want to have Date as type for this column\n\t`; + + const fsp = lowered.startsWith('datetime(') + ? lowered.substring('datetime'.length + 1, lowered.length - 1) + : undefined; + + out = fsp + ? `${ + casing( + name, + ) + }: datetime("${name}", { mode: 'string', fsp: ${ + lowered.substring( + 'datetime'.length + 1, + lowered.length - 1, + ) + } })` + : `${casing(name)}: datetime("${name}", { mode: 'string'})`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('decimal')) { + let params: + | { precision: string | undefined; scale: string | undefined } + | undefined; + + if (lowered.length > 7) { + const [precision, scale] = lowered + .slice(8, lowered.length - 1) + .split(','); + params = { precision, scale }; + } + + let out = params + ? `${casing(name)}: decimal("${name}", ${timeConfig(params)})` + : `${casing(name)}: decimal("${name}")`; + + defaultValue = typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('binary')) { + const keyLength = 'binary'.length + 1; + let length = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + length = length ? length : null; + + const params = binaryConfig({ length }); + + let out = params + ? `${casing(name)}: binary("${name}", ${params})` + : `${casing(name)}: binary("${name}")`; + + defaultValue = defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('enum')) { + const values = lowered.substring('enum'.length + 1, lowered.length - 1); + let out = `${casing(name)}: singlestoreEnum("${name}", [${values}])`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('varbinary')) { + const keyLength = 'varbinary'.length + 1; + let length = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + length = length ? length : null; + + const params = binaryConfig({ length }); + + let out = params + ? `${casing(name)}: varbinary("${name}", ${params})` + : `${casing(name)}: varbinary("${name}")`; + + defaultValue = defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + console.log('uknown', type); + return `// Warning: Can't parse ${type} from database\n\t// ${type}Type: ${type}("${name}")`; +}; + +const createTableColumns = ( + columns: Column[], + casing: (val: string) => string, + tableName: string, + schema: SingleStoreSchemaInternal, +): string => { + let statement = ''; + + columns.forEach((it) => { + statement += '\t'; + statement += column( + it.type, + it.name, + casing, + it.default, + it.autoincrement, + it.onUpdate, + schema.internal?.tables![tableName]?.columns[it.name] + ?.isDefaultAnExpression ?? false, + ); + statement += it.primaryKey ? '.primaryKey()' : ''; + statement += it.notNull ? '.notNull()' : ''; + + statement += it.generated + ? `.generatedAlwaysAs(sql\`${ + it.generated.as.replace( + /`/g, + '\\`', + ) + }\`, { mode: "${it.generated.type}" })` + : ''; + + statement += ',\n'; + }); + + return statement; +}; + +const createTableIndexes = ( + tableName: string, + idxs: Index[], + casing: (value: string) => string, +): string => { + let statement = ''; + + idxs.forEach((it) => { + let idxKey = it.name.startsWith(tableName) && it.name !== tableName + ? it.name.slice(tableName.length + 1) + : it.name; + idxKey = idxKey.endsWith('_index') + ? idxKey.slice(0, -'_index'.length) + '_idx' + : idxKey; + + idxKey = casing(idxKey); + + const indexGeneratedName = indexName(tableName, it.columns); + const escapedIndexName = indexGeneratedName === it.name ? '' : `"${it.name}"`; + + statement += `\t\t${idxKey}: `; + statement += it.isUnique ? 'uniqueIndex(' : 'index('; + statement += `${escapedIndexName})`; + statement += `.on(${ + it.columns + .map((it) => `table.${casing(it)}`) + .join(', ') + }),`; + statement += `\n`; + }); + + return statement; +}; + +const createTableUniques = ( + unqs: UniqueConstraint[], + casing: (value: string) => string, +): string => { + let statement = ''; + + unqs.forEach((it) => { + const idxKey = casing(it.name); + + statement += `\t\t${idxKey}: `; + statement += 'unique('; + statement += `"${it.name}")`; + statement += `.on(${ + it.columns + .map((it) => `table.${casing(it)}`) + .join(', ') + }),`; + statement += `\n`; + }); + + return statement; +}; + +const createTablePKs = ( + pks: PrimaryKey[], + casing: (value: string) => string, +): string => { + let statement = ''; + + pks.forEach((it) => { + let idxKey = casing(it.name); + + statement += `\t\t${idxKey}: `; + statement += 'primaryKey({ columns: ['; + statement += `${ + it.columns + .map((c) => { + return `table.${casing(c)}`; + }) + .join(', ') + }]${it.name ? `, name: "${it.name}"` : ''}}`; + statement += '),'; + statement += `\n`; + }); + + return statement; +}; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 18b28fac4..8257265cb 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -8,11 +8,12 @@ import { MatViewWithOption, PgSchema, PgSquasher, + View as PgView, Policy, Role, - View as PgView, ViewWithOption, } from './serializer/pgSchema'; +import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, @@ -50,8 +51,8 @@ export interface JsonCreateTableStatement { uniqueConstraints?: string[]; policies?: string[]; checkConstraints?: string[]; - internals?: MySqlKitInternals; isRLSEnabled?: boolean; + internals?: MySqlKitInternals | SingleStoreKitInternals; } export interface JsonRecreateTableStatement { @@ -306,7 +307,7 @@ export interface JsonCreateIndexStatement { tableName: string; data: string; schema: string; - internal?: MySqlKitInternals | SQLiteKitInternals; + internal?: MySqlKitInternals | SQLiteKitInternals | SingleStoreKitInternals; } export interface JsonPgCreateIndexStatement { @@ -906,6 +907,34 @@ export const prepareMySqlCreateTableJson = ( }; }; +export const prepareSingleStoreCreateTableJson = ( + table: Table, + // TODO: remove? + json2: SingleStoreSchema, + // we need it to know if some of the indexes(and in future other parts) are expressions or columns + // didn't change singlestoreserialaizer, because it will break snapshots and diffs and it's hard to detect + // if previously it was an expression or column + internals: SingleStoreKitInternals, +): JsonCreateTableStatement => { + const { name, schema, columns, compositePrimaryKeys, uniqueConstraints } = table; + + return { + type: 'create_table', + tableName: name, + schema, + columns: Object.values(columns), + compositePKs: Object.values(compositePrimaryKeys), + compositePkName: Object.values(compositePrimaryKeys).length > 0 + ? json2.tables[name].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(Object.values(compositePrimaryKeys)[0]) + .name + ].name + : '', + uniqueConstraints: Object.values(uniqueConstraints), + internals, + }; +}; + export const prepareSQLiteCreateTable = ( table: Table, action?: 'push' | undefined, @@ -1207,7 +1236,7 @@ export const prepareDeleteSchemasJson = ( export const prepareRenameColumns = ( tableName: string, - // TODO: split for pg and mysql+sqlite without schema + // TODO: split for pg and mysql+sqlite and singlestore without schema schema: string, pairs: { from: Column; to: Column }[], ): JsonRenameColumnStatement[] => { @@ -1637,6 +1666,363 @@ export const prepareAlterColumnsMysql = ( return [...dropPkStatements, ...setPkStatements, ...statements]; }; +export const prepareAlterColumnsSingleStore = ( + tableName: string, + schema: string, + columns: AlteredColumn[], + // TODO: remove? + json1: CommonSquashedSchema, + json2: CommonSquashedSchema, + action?: 'push' | undefined, +): JsonAlterColumnStatement[] => { + let statements: JsonAlterColumnStatement[] = []; + let dropPkStatements: JsonAlterColumnDropPrimaryKeyStatement[] = []; + let setPkStatements: JsonAlterColumnSetPrimaryKeyStatement[] = []; + + for (const column of columns) { + const columnName = typeof column.name !== 'string' ? column.name.new : column.name; + + const table = json2.tables[tableName]; + const snapshotColumn = table.columns[columnName]; + + const columnType = snapshotColumn.type; + const columnDefault = snapshotColumn.default; + const columnOnUpdate = 'onUpdate' in snapshotColumn ? snapshotColumn.onUpdate : undefined; + const columnNotNull = table.columns[columnName].notNull; + + const columnAutoIncrement = 'autoincrement' in snapshotColumn + ? snapshotColumn.autoincrement ?? false + : false; + + const columnPk = table.columns[columnName].primaryKey; + + if (column.autoincrement?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'changed') { + const type = column.autoincrement.new + ? 'alter_table_alter_column_set_autoincrement' + : 'alter_table_alter_column_drop_autoincrement'; + + statements.push({ + type, + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + } + + for (const column of columns) { + const columnName = typeof column.name !== 'string' ? column.name.new : column.name; + + // I used any, because those fields are available only for mysql and singlestore dialect + // For other dialects it will become undefined, that is fine for json statements + const columnType = json2.tables[tableName].columns[columnName].type; + const columnDefault = json2.tables[tableName].columns[columnName].default; + const columnGenerated = json2.tables[tableName].columns[columnName].generated; + const columnOnUpdate = (json2.tables[tableName].columns[columnName] as any) + .onUpdate; + const columnNotNull = json2.tables[tableName].columns[columnName].notNull; + const columnAutoIncrement = ( + json2.tables[tableName].columns[columnName] as any + ).autoincrement; + const columnPk = (json2.tables[tableName].columns[columnName] as any) + .primaryKey; + + const compositePk = json2.tables[tableName].compositePrimaryKeys[ + `${tableName}_${columnName}` + ]; + + if (typeof column.name !== 'string') { + statements.push({ + type: 'alter_table_rename_column', + tableName, + oldColumnName: column.name.old, + newColumnName: column.name.new, + schema, + }); + } + + if (column.type?.type === 'changed') { + statements.push({ + type: 'alter_table_alter_column_set_type', + tableName, + columnName, + newDataType: column.type.new, + oldDataType: column.type.old, + schema, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if ( + column.primaryKey?.type === 'deleted' + || (column.primaryKey?.type === 'changed' + && !column.primaryKey.new + && typeof compositePk === 'undefined') + ) { + dropPkStatements.push({ + //// + type: 'alter_table_alter_column_drop_pk', + tableName, + columnName, + schema, + }); + } + + if (column.default?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_default', + tableName, + columnName, + newDefaultValue: column.default.value, + schema, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.default?.type === 'changed') { + statements.push({ + type: 'alter_table_alter_column_set_default', + tableName, + columnName, + newDefaultValue: column.default.new, + oldDefaultValue: column.default.old, + schema, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.default?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_default', + tableName, + columnName, + schema, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.notNull?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_notnull', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.notNull?.type === 'changed') { + const type = column.notNull.new + ? 'alter_table_alter_column_set_notnull' + : 'alter_table_alter_column_drop_notnull'; + statements.push({ + type: type, + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.notNull?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_notnull', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.generated?.type === 'added') { + if (columnGenerated?.type === 'virtual') { + // TODO: Change warning message according to SingleStore docs + warning( + `You are trying to add virtual generated constraint to ${ + chalk.blue( + columnName, + ) + } column. As MySQL docs mention: "Nongenerated columns can be altered to stored but not virtual generated columns". We will drop an existing column and add it with a virtual generated statement. This means that the data previously stored in this column will be wiped, and new data will be generated on each read for this column\n`, + ); + } + statements.push({ + type: 'alter_table_alter_column_set_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if (column.generated?.type === 'changed' && action !== 'push') { + statements.push({ + type: 'alter_table_alter_column_alter_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if (column.generated?.type === 'deleted') { + if (columnGenerated?.type === 'virtual') { + // TODO: Change warning message according to SingleStore docs + warning( + `You are trying to remove virtual generated constraint from ${ + chalk.blue( + columnName, + ) + } column. As MySQL docs mention: "Stored but not virtual generated columns can be altered to nongenerated columns. The stored generated values become the values of the nongenerated column". We will drop an existing column and add it without a virtual generated statement. This means that this column will have no data after migration\n`, + ); + } + statements.push({ + type: 'alter_table_alter_column_drop_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + oldColumn: json1.tables[tableName].columns[columnName], + }); + } + + if ( + column.primaryKey?.type === 'added' + || (column.primaryKey?.type === 'changed' && column.primaryKey.new) + ) { + const wasAutoincrement = statements.filter( + (it) => it.type === 'alter_table_alter_column_set_autoincrement', + ); + if (wasAutoincrement.length === 0) { + setPkStatements.push({ + type: 'alter_table_alter_column_set_pk', + tableName, + schema, + columnName, + }); + } + } + + if (column.onUpdate?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_on_update', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.onUpdate?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_on_update', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + } + + return [...dropPkStatements, ...setPkStatements, ...statements]; +}; + export const preparePgAlterColumns = ( _tableName: string, schema: string, @@ -3070,3 +3456,72 @@ export const prepareMySqlAlterView = ( ): JsonAlterMySqlViewStatement => { return { type: 'alter_mysql_view', ...view }; }; + +export const prepareAddCompositePrimaryKeySingleStore = ( + tableName: string, + pks: Record, + // TODO: remove? + json1: SingleStoreSchema, + json2: SingleStoreSchema, +): JsonCreateCompositePK[] => { + const res: JsonCreateCompositePK[] = []; + for (const it of Object.values(pks)) { + const unsquashed = SingleStoreSquasher.unsquashPK(it); + + if ( + unsquashed.columns.length === 1 + && json1.tables[tableName]?.columns[unsquashed.columns[0]]?.primaryKey + ) { + continue; + } + + res.push({ + type: 'create_composite_pk', + tableName, + data: it, + constraintName: json2.tables[tableName].compositePrimaryKeys[unsquashed.name].name, + } as JsonCreateCompositePK); + } + return res; +}; + +export const prepareDeleteCompositePrimaryKeySingleStore = ( + tableName: string, + pks: Record, + // TODO: remove? + json1: SingleStoreSchema, +): JsonDeleteCompositePK[] => { + return Object.values(pks).map((it) => { + return { + type: 'delete_composite_pk', + tableName, + data: it, + constraintName: json1.tables[tableName].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(it).name + ].name, + } as JsonDeleteCompositePK; + }); +}; + +export const prepareAlterCompositePrimaryKeySingleStore = ( + tableName: string, + pks: Record, + // TODO: remove? + json1: SingleStoreSchema, + json2: SingleStoreSchema, +): JsonAlterCompositePK[] => { + return Object.values(pks).map((it) => { + return { + type: 'alter_composite_pk', + tableName, + old: it.__old, + new: it.__new, + oldConstraintName: json1.tables[tableName].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(it.__old).name + ].name, + newConstraintName: json2.tables[tableName].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(it.__new).name + ].name, + } as JsonAlterCompositePK; + }); +}; diff --git a/drizzle-kit/src/migrationPreparator.ts b/drizzle-kit/src/migrationPreparator.ts index d61f804ca..262f4dcba 100644 --- a/drizzle-kit/src/migrationPreparator.ts +++ b/drizzle-kit/src/migrationPreparator.ts @@ -1,9 +1,10 @@ import { randomUUID } from 'crypto'; import fs from 'fs'; import { CasingType } from './cli/validations/common'; -import { serializeMySql, serializePg, serializeSQLite } from './serializer'; +import { serializeMySql, serializePg, serializeSingleStore, serializeSQLite } from './serializer'; import { dryMySql, MySqlSchema, mysqlSchema } from './serializer/mysqlSchema'; import { dryPg, PgSchema, pgSchema, PgSchemaInternal } from './serializer/pgSchema'; +import { drySingleStore, SingleStoreSchema, singlestoreSchema } from './serializer/singlestoreSchema'; import { drySQLite, SQLiteSchema, sqliteSchema } from './serializer/sqliteSchema'; export const prepareMySqlDbPushSnapshot = async ( @@ -22,6 +23,21 @@ export const prepareMySqlDbPushSnapshot = async ( return { prev, cur: result }; }; +export const prepareSingleStoreDbPushSnapshot = async ( + prev: SingleStoreSchema, + schemaPath: string | string[], +): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema }> => { + const serialized = await serializeSingleStore(schemaPath); + + const id = randomUUID(); + const idPrev = prev.id; + + const { version, dialect, ...rest } = serialized; + const result: SingleStoreSchema = { version, dialect, id, prevId: idPrev, ...rest }; + + return { prev, cur: result }; +}; + export const prepareSQLiteDbPushSnapshot = async ( prev: SQLiteSchema, schemaPath: string | string[], @@ -89,6 +105,33 @@ export const prepareMySqlMigrationSnapshot = async ( return { prev: prevSnapshot, cur: result, custom }; }; +export const prepareSingleStoreMigrationSnapshot = async ( + migrationFolders: string[], + schemaPath: string | string[], +): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema; custom: SingleStoreSchema }> => { + const prevSnapshot = singlestoreSchema.parse( + preparePrevSnapshot(migrationFolders, drySingleStore), + ); + const serialized = await serializeSingleStore(schemaPath); + + const id = randomUUID(); + const idPrev = prevSnapshot.id; + + const { version, dialect, ...rest } = serialized; + const result: SingleStoreSchema = { version, dialect, id, prevId: idPrev, ...rest }; + + const { id: _ignoredId, prevId: _ignoredPrevId, ...prevRest } = prevSnapshot; + + // that's for custom migrations, when we need new IDs, but old snapshot + const custom: SingleStoreSchema = { + id, + prevId: idPrev, + ...prevRest, + }; + + return { prev: prevSnapshot, cur: result, custom }; +}; + export const prepareSqliteMigrationSnapshot = async ( snapshots: string[], schemaPath: string | string[], diff --git a/drizzle-kit/src/schemaValidator.ts b/drizzle-kit/src/schemaValidator.ts index 6ad29a544..e91b5ab11 100644 --- a/drizzle-kit/src/schemaValidator.ts +++ b/drizzle-kit/src/schemaValidator.ts @@ -1,9 +1,10 @@ import { enum as enumType, TypeOf, union } from 'zod'; import { mysqlSchema, mysqlSchemaSquashed } from './serializer/mysqlSchema'; import { pgSchema, pgSchemaSquashed } from './serializer/pgSchema'; +import { singlestoreSchema, singlestoreSchemaSquashed } from './serializer/singlestoreSchema'; import { sqliteSchema, SQLiteSchemaSquashed } from './serializer/sqliteSchema'; -export const dialects = ['postgresql', 'mysql', 'sqlite', 'turso'] as const; +export const dialects = ['postgresql', 'mysql', 'sqlite', 'turso', 'singlestore'] as const; export const dialect = enumType(dialects); export type Dialect = (typeof dialects)[number]; @@ -13,9 +14,10 @@ const commonSquashedSchema = union([ pgSchemaSquashed, mysqlSchemaSquashed, SQLiteSchemaSquashed, + singlestoreSchemaSquashed, ]); -const commonSchema = union([pgSchema, mysqlSchema, sqliteSchema]); +const commonSchema = union([pgSchema, mysqlSchema, sqliteSchema, singlestoreSchema]); export type CommonSquashedSchema = TypeOf; export type CommonSchema = TypeOf; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index cf2ee625a..e82fda92d 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -6,6 +6,7 @@ import { CasingType } from 'src/cli/validations/common'; import { error } from '../cli/views'; import type { MySqlSchemaInternal } from './mysqlSchema'; import type { PgSchemaInternal } from './pgSchema'; +import { SingleStoreSchemaInternal } from './singlestoreSchema'; import type { SQLiteSchemaInternal } from './sqliteSchema'; export const serializeMySql = async ( @@ -53,6 +54,21 @@ export const serializeSQLite = async ( return generateSqliteSnapshot(tables, views, casing); }; +export const serializeSingleStore = async ( + path: string | string[], +): Promise => { + const filenames = prepareFilenames(path); + + console.log(chalk.gray(`Reading schema files:\n${filenames.join('\n')}\n`)); + + const { prepareFromSingleStoreImports } = await import('./singlestoreImports'); + const { generateSingleStoreSnapshot } = await import('./singlestoreSerializer'); + + const { tables } = await prepareFromSingleStoreImports(filenames); + + return generateSingleStoreSnapshot(tables); +}; + export const prepareFilenames = (path: string | string[]) => { if (typeof path === 'string') { path = [path]; diff --git a/drizzle-kit/src/serializer/singlestoreImports.ts b/drizzle-kit/src/serializer/singlestoreImports.ts new file mode 100644 index 000000000..fe9cf04ff --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreImports.ts @@ -0,0 +1,38 @@ +import { is } from 'drizzle-orm'; +import { AnySingleStoreTable, SingleStoreTable, SingleStoreView } from 'drizzle-orm/singlestore-core'; +import { safeRegister } from '../cli/commands/utils'; + +export const prepareFromExports = (exports: Record) => { + const tables: AnySingleStoreTable[] = []; + const views: SingleStoreView[] = []; + + const i0values = Object.values(exports); + i0values.forEach((t) => { + if (is(t, SingleStoreTable)) { + tables.push(t); + } + + if (is(t, SingleStoreView)) { + views.push(t); + } + }); + + return { tables, views }; +}; + +export const prepareFromSingleStoreImports = async (imports: string[]) => { + const tables: AnySingleStoreTable[] = []; + const views: SingleStoreView[] = []; + + const { unregister } = await safeRegister(); + for (let i = 0; i < imports.length; i++) { + const it = imports[i]; + const i0: Record = require(`${it}`); + const prepared = prepareFromExports(i0); + + tables.push(...prepared.tables); + views.push(...prepared.views); + } + unregister(); + return { tables: Array.from(new Set(tables)), views }; +}; diff --git a/drizzle-kit/src/serializer/singlestoreSchema.ts b/drizzle-kit/src/serializer/singlestoreSchema.ts new file mode 100644 index 000000000..a0bbae1bf --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreSchema.ts @@ -0,0 +1,203 @@ +import { any, boolean, enum as enumType, literal, object, record, string, TypeOf, union } from 'zod'; +import { mapValues, originUUID, snapshotVersion } from '../global'; + +// ------- V3 -------- +const index = object({ + name: string(), + columns: string().array(), + isUnique: boolean(), + using: enumType(['btree', 'hash']).optional(), + algorithm: enumType(['default', 'inplace', 'copy']).optional(), + lock: enumType(['default', 'none', 'shared', 'exclusive']).optional(), +}).strict(); + +const column = object({ + name: string(), + type: string(), + primaryKey: boolean(), + notNull: boolean(), + autoincrement: boolean().optional(), + default: any().optional(), + onUpdate: any().optional(), + generated: object({ + type: enumType(['stored', 'virtual']), + as: string(), + }).optional(), +}).strict(); + +const compositePK = object({ + name: string(), + columns: string().array(), +}).strict(); + +const uniqueConstraint = object({ + name: string(), + columns: string().array(), +}).strict(); + +const table = object({ + name: string(), + columns: record(string(), column), + indexes: record(string(), index), + compositePrimaryKeys: record(string(), compositePK), + uniqueConstraints: record(string(), uniqueConstraint).default({}), +}).strict(); + +export const kitInternals = object({ + tables: record( + string(), + object({ + columns: record( + string(), + object({ isDefaultAnExpression: boolean().optional() }).optional(), + ), + }).optional(), + ).optional(), + indexes: record( + string(), + object({ + columns: record( + string(), + object({ isExpression: boolean().optional() }).optional(), + ), + }).optional(), + ).optional(), +}).optional(); + +// use main dialect +const dialect = literal('singlestore'); + +const schemaHash = object({ + id: string(), + prevId: string(), +}); + +export const schemaInternal = object({ + version: literal('1'), + dialect: dialect, + tables: record(string(), table), + _meta: object({ + tables: record(string(), string()), + columns: record(string(), string()), + }), + internal: kitInternals, +}).strict(); + +export const schema = schemaInternal.merge(schemaHash); + +const tableSquashed = object({ + name: string(), + columns: record(string(), column), + indexes: record(string(), string()), + compositePrimaryKeys: record(string(), string()), + uniqueConstraints: record(string(), string()).default({}), +}).strict(); + +export const schemaSquashed = object({ + version: literal('1'), + dialect: dialect, + tables: record(string(), tableSquashed), +}).strict(); + +export type Dialect = TypeOf; +export type Column = TypeOf; +export type Table = TypeOf; +export type SingleStoreSchema = TypeOf; +export type SingleStoreSchemaInternal = TypeOf; +export type SingleStoreKitInternals = TypeOf; +export type SingleStoreSchemaSquashed = TypeOf; +export type Index = TypeOf; +export type PrimaryKey = TypeOf; +export type UniqueConstraint = TypeOf; + +export const SingleStoreSquasher = { + squashIdx: (idx: Index) => { + index.parse(idx); + return `${idx.name};${idx.columns.join(',')};${idx.isUnique};${idx.using ?? ''};${idx.algorithm ?? ''};${ + idx.lock ?? '' + }`; + }, + unsquashIdx: (input: string): Index => { + const [name, columnsString, isUnique, using, algorithm, lock] = input.split(';'); + const destructed = { + name, + columns: columnsString.split(','), + isUnique: isUnique === 'true', + using: using ? using : undefined, + algorithm: algorithm ? algorithm : undefined, + lock: lock ? lock : undefined, + }; + return index.parse(destructed); + }, + squashPK: (pk: PrimaryKey) => { + return `${pk.name};${pk.columns.join(',')}`; + }, + unsquashPK: (pk: string): PrimaryKey => { + const splitted = pk.split(';'); + return { name: splitted[0], columns: splitted[1].split(',') }; + }, + squashUnique: (unq: UniqueConstraint) => { + return `${unq.name};${unq.columns.join(',')}`; + }, + unsquashUnique: (unq: string): UniqueConstraint => { + const [name, columns] = unq.split(';'); + return { name, columns: columns.split(',') }; + }, +}; + +export const squashSingleStoreScheme = (json: SingleStoreSchema): SingleStoreSchemaSquashed => { + const mappedTables = Object.fromEntries( + Object.entries(json.tables).map((it) => { + const squashedIndexes = mapValues(it[1].indexes, (index) => { + return SingleStoreSquasher.squashIdx(index); + }); + + const squashedPKs = mapValues(it[1].compositePrimaryKeys, (pk) => { + return SingleStoreSquasher.squashPK(pk); + }); + + const squashedUniqueConstraints = mapValues( + it[1].uniqueConstraints, + (unq) => { + return SingleStoreSquasher.squashUnique(unq); + }, + ); + + return [ + it[0], + { + name: it[1].name, + columns: it[1].columns, + indexes: squashedIndexes, + compositePrimaryKeys: squashedPKs, + uniqueConstraints: squashedUniqueConstraints, + }, + ]; + }), + ); + return { + version: '1', + dialect: json.dialect, + tables: mappedTables, + }; +}; + +export const singlestoreSchema = schema; +export const singlestoreSchemaSquashed = schemaSquashed; + +// no prev version +export const backwardCompatibleSingleStoreSchema = union([singlestoreSchema, schema]); + +export const drySingleStore = singlestoreSchema.parse({ + version: '1', + dialect: 'singlestore', + id: originUUID, + prevId: '', + tables: {}, + schemas: {}, + _meta: { + schemas: {}, + tables: {}, + columns: {}, + }, +}); diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts new file mode 100644 index 000000000..d96004c8f --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -0,0 +1,606 @@ +import chalk from 'chalk'; +import { is, SQL } from 'drizzle-orm'; +import { + AnySingleStoreTable, + getTableConfig, + type PrimaryKey as PrimaryKeyORM, + SingleStoreDialect, + SingleStoreView, + uniqueKeyName, +} from 'drizzle-orm/singlestore-core'; +import { RowDataPacket } from 'mysql2/promise'; +import { withStyle } from '../cli/validations/outputs'; +import { IntrospectStage, IntrospectStatus } from '../cli/views'; + +import type { DB } from '../utils'; +import { sqlToStr } from '.'; +import { + Column, + Index, + PrimaryKey, + SingleStoreKitInternals, + SingleStoreSchemaInternal, + Table, + UniqueConstraint, +} from './singlestoreSchema'; +import { CasingType } from 'src/cli/validations/common'; + +const dialect = new SingleStoreDialect(); + +export const indexName = (tableName: string, columns: string[]) => { + return `${tableName}_${columns.join('_')}_index`; +}; + +export const generateSingleStoreSnapshot = ( + tables: AnySingleStoreTable[], + views: SingleStoreView[], + casing: CasingType | undefined, +): SingleStoreSchemaInternal => { + const result: Record = {}; + const internal: SingleStoreKitInternals = { tables: {}, indexes: {} }; + for (const table of tables) { + const { + name: tableName, + columns, + indexes, + schema, + primaryKeys, + uniqueConstraints, + } = getTableConfig(table); + const columnsObject: Record = {}; + const indexesObject: Record = {}; + const primaryKeysObject: Record = {}; + const uniqueConstraintObject: Record = {}; + + columns.forEach((column) => { + const notNull: boolean = column.notNull; + const sqlTypeLowered = column.getSQLType().toLowerCase(); + const autoIncrement = typeof (column as any).autoIncrement === 'undefined' + ? false + : (column as any).autoIncrement; + + const generated = column.generated; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + primaryKey: false, + // If field is autoincrement it's notNull by default + // notNull: autoIncrement ? true : notNull, + notNull, + autoincrement: autoIncrement, + onUpdate: (column as any).hasOnUpdateNow, + generated: generated + ? { + as: is(generated.as, SQL) + ? dialect.sqlToQuery(generated.as as SQL).sql + : typeof generated.as === 'function' + ? dialect.sqlToQuery(generated.as() as SQL).sql + : (generated.as as any), + type: generated.mode ?? 'stored', + } + : undefined, + }; + + if (column.primary) { + primaryKeysObject[`${tableName}_${column.name}`] = { + name: `${tableName}_${column.name}`, + columns: [column.name], + }; + } + + if (column.isUnique) { + const existingUnique = uniqueConstraintObject[column.uniqueName!]; + if (typeof existingUnique !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. + The unique constraint ${ + chalk.underline.blue( + column.uniqueName, + ) + } on the ${ + chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`) + }`, + ); + process.exit(1); + } + uniqueConstraintObject[column.uniqueName!] = { + name: column.uniqueName!, + columns: [columnToSet.name], + }; + } + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default, casing); + } else { + if (typeof column.default === 'string') { + columnToSet.default = `'${column.default}'`; + } else { + if (sqlTypeLowered === 'json') { + columnToSet.default = `'${JSON.stringify(column.default)}'`; + } else if (column.default instanceof Date) { + if (sqlTypeLowered === 'date') { + columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; + } else if ( + sqlTypeLowered.startsWith('datetime') + || sqlTypeLowered.startsWith('timestamp') + ) { + columnToSet.default = `'${ + column.default + .toISOString() + .replace('T', ' ') + .slice(0, 23) + }'`; + } + } else { + columnToSet.default = column.default; + } + } + if (['blob', 'text', 'json'].includes(column.getSQLType())) { + columnToSet.default = `(${columnToSet.default})`; + } + } + } + columnsObject[column.name] = columnToSet; + }); + + primaryKeys.map((pk: PrimaryKeyORM) => { + const columnNames = pk.columns.map((c: any) => c.name); + primaryKeysObject[pk.getName()] = { + name: pk.getName(), + columns: columnNames, + }; + + // all composite pk's should be treated as notNull + for (const column of pk.columns) { + columnsObject[column.name].notNull = true; + } + }); + + uniqueConstraints?.map((unq) => { + const columnNames = unq.columns.map((c) => c.name); + + const name = unq.name ?? uniqueKeyName(table, columnNames); + + const existingUnique = uniqueConstraintObject[name]; + if (typeof existingUnique !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. \nThe unique constraint ${ + chalk.underline.blue( + name, + ) + } on the ${ + chalk.underline.blue( + columnNames.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`, + ) + }`, + ); + process.exit(1); + } + + uniqueConstraintObject[name] = { + name: unq.name!, + columns: columnNames, + }; + }); + + indexes.forEach((value) => { + const columns = value.config.columns; + const name = value.config.name; + + let indexColumns = columns.map((it) => { + if (is(it, SQL)) { + const sql = dialect.sqlToQuery(it, 'indexes').sql; + if (typeof internal!.indexes![name] === 'undefined') { + internal!.indexes![name] = { + columns: { + [sql]: { + isExpression: true, + }, + }, + }; + } else { + if (typeof internal!.indexes![name]?.columns[sql] === 'undefined') { + internal!.indexes![name]!.columns[sql] = { + isExpression: true, + }; + } else { + internal!.indexes![name]!.columns[sql]!.isExpression = true; + } + } + return sql; + } else { + return `${it.name}`; + } + }); + + if (value.config.unique) { + if (typeof uniqueConstraintObject[name] !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. \nThe unique index ${ + chalk.underline.blue( + name, + ) + } on the ${ + chalk.underline.blue( + indexColumns.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + uniqueConstraintObject[name].columns.join(','), + ) + } columns\n`, + ) + }`, + ); + process.exit(1); + } + } + + indexesObject[name] = { + name, + columns: indexColumns, + isUnique: value.config.unique ?? false, + using: value.config.using, + algorithm: value.config.algorythm, + lock: value.config.lock, + }; + }); + + // only handle tables without schemas + if (!schema) { + result[tableName] = { + name: tableName, + columns: columnsObject, + indexes: indexesObject, + compositePrimaryKeys: primaryKeysObject, + uniqueConstraints: uniqueConstraintObject, + }; + } + } + + return { + version: '1', + dialect: 'singlestore', + tables: result, + _meta: { + tables: {}, + columns: {}, + }, + internal, + }; +}; + +function clearDefaults(defaultValue: any, collate: string) { + if (typeof collate === 'undefined' || collate === null) { + collate = `utf8mb4`; + } + + let resultDefault = defaultValue; + collate = `_${collate}`; + if (defaultValue.startsWith(collate)) { + resultDefault = resultDefault + .substring(collate.length, defaultValue.length) + .replace(/\\/g, ''); + if (resultDefault.startsWith("'") && resultDefault.endsWith("'")) { + return `('${resultDefault.substring(1, resultDefault.length - 1)}')`; + } else { + return `'${resultDefault}'`; + } + } else { + return `(${resultDefault})`; + } +} + +export const fromDatabase = async ( + db: DB, + inputSchema: string, + tablesFilter: (table: string) => boolean = (table) => true, + progressCallback?: ( + stage: IntrospectStage, + count: number, + status: IntrospectStatus, + ) => void, +): Promise => { + const result: Record = {}; + const internals: SingleStoreKitInternals = { tables: {}, indexes: {} }; + + const columns = await db.query(`select * from information_schema.columns + where table_schema = '${inputSchema}' and table_name != '__drizzle_migrations' + order by table_name, ordinal_position;`); + + const response = columns as RowDataPacket[]; + + const schemas: string[] = []; + + let columnsCount = 0; + let tablesCount = new Set(); + let indexesCount = 0; + let foreignKeysCount = 0; + + const idxs = await db.query( + `select * from INFORMATION_SCHEMA.STATISTICS + WHERE INFORMATION_SCHEMA.STATISTICS.TABLE_SCHEMA = '${inputSchema}' and INFORMATION_SCHEMA.STATISTICS.INDEX_NAME != 'PRIMARY';`, + ); + + const idxRows = idxs as RowDataPacket[]; + + for (const column of response) { + if (!tablesFilter(column['TABLE_NAME'] as string)) continue; + + columnsCount += 1; + if (progressCallback) { + progressCallback('columns', columnsCount, 'fetching'); + } + const schema: string = column['TABLE_SCHEMA']; + const tableName = column['TABLE_NAME']; + + tablesCount.add(`${schema}.${tableName}`); + if (progressCallback) { + progressCallback('columns', tablesCount.size, 'fetching'); + } + const columnName: string = column['COLUMN_NAME']; + const isNullable = column['IS_NULLABLE'] === 'YES'; // 'YES', 'NO' + const dataType = column['DATA_TYPE']; // varchar + const columnType = column['COLUMN_TYPE']; // varchar(256) + const isPrimary = column['COLUMN_KEY'] === 'PRI'; // 'PRI', '' + const columnDefault: string = column['COLUMN_DEFAULT']; + const collation: string = column['CHARACTER_SET_NAME']; + const geenratedExpression: string = column['GENERATION_EXPRESSION']; + + let columnExtra = column['EXTRA']; + let isAutoincrement = false; // 'auto_increment', '' + let isDefaultAnExpression = false; // 'auto_increment', '' + + if (typeof column['EXTRA'] !== 'undefined') { + columnExtra = column['EXTRA']; + isAutoincrement = column['EXTRA'] === 'auto_increment'; // 'auto_increment', '' + isDefaultAnExpression = column['EXTRA'].includes('DEFAULT_GENERATED'); // 'auto_increment', '' + } + + // if (isPrimary) { + // if (typeof tableToPk[tableName] === "undefined") { + // tableToPk[tableName] = [columnName]; + // } else { + // tableToPk[tableName].push(columnName); + // } + // } + + if (schema !== inputSchema) { + schemas.push(schema); + } + + const table = result[tableName]; + + // let changedType = columnType.replace("bigint unsigned", "serial") + let changedType = columnType; + + if (columnType === 'bigint unsigned' && !isNullable && isAutoincrement) { + // check unique here + const uniqueIdx = idxRows.filter( + (it) => + it['COLUMN_NAME'] === columnName + && it['TABLE_NAME'] === tableName + && it['NON_UNIQUE'] === 0, + ); + if (uniqueIdx && uniqueIdx.length === 1) { + changedType = columnType.replace('bigint unsigned', 'serial'); + } + } + + if (columnType.startsWith('tinyint')) { + changedType = 'tinyint'; + } + + let onUpdate: boolean | undefined = undefined; + if ( + columnType.startsWith('timestamp') + && typeof columnExtra !== 'undefined' + && columnExtra.includes('on update CURRENT_TIMESTAMP') + ) { + onUpdate = true; + } + + const newColumn: Column = { + default: columnDefault === null + ? undefined + : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) + && !columnType.startsWith('decimal') + ? Number(columnDefault) + : isDefaultAnExpression + ? clearDefaults(columnDefault, collation) + : `'${columnDefault}'`, + autoincrement: isAutoincrement, + name: columnName, + type: changedType, + primaryKey: false, + notNull: !isNullable, + onUpdate, + generated: geenratedExpression + ? { + as: geenratedExpression, + type: columnExtra === 'VIRTUAL GENERATED' ? 'virtual' : 'stored', + } + : undefined, + }; + + // Set default to internal object + if (isDefaultAnExpression) { + if (typeof internals!.tables![tableName] === 'undefined') { + internals!.tables![tableName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, + }, + }; + } else { + if ( + typeof internals!.tables![tableName]!.columns[columnName] + === 'undefined' + ) { + internals!.tables![tableName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![tableName]!.columns[ + columnName + ]!.isDefaultAnExpression = true; + } + } + } + + if (!table) { + result[tableName] = { + name: tableName, + columns: { + [columnName]: newColumn, + }, + compositePrimaryKeys: {}, + indexes: {}, + uniqueConstraints: {}, + }; + } else { + result[tableName]!.columns[columnName] = newColumn; + } + } + + const tablePks = await db.query( + `SELECT table_name, column_name, ordinal_position + FROM information_schema.table_constraints t + LEFT JOIN information_schema.key_column_usage k + USING(constraint_name,table_schema,table_name) + WHERE t.constraint_type='PRIMARY KEY' + and table_name != '__drizzle_migrations' + AND t.table_schema = '${inputSchema}' + ORDER BY ordinal_position`, + ); + + const tableToPk: { [tname: string]: string[] } = {}; + + const tableToPkRows = tablePks as RowDataPacket[]; + for (const tableToPkRow of tableToPkRows) { + const tableName: string = tableToPkRow['TABLE_NAME']; + const columnName: string = tableToPkRow['COLUMN_NAME']; + const position: string = tableToPkRow['ordinal_position']; + + if (typeof result[tableName] === 'undefined') { + continue; + } + + if (typeof tableToPk[tableName] === 'undefined') { + tableToPk[tableName] = [columnName]; + } else { + tableToPk[tableName].push(columnName); + } + } + + for (const [key, value] of Object.entries(tableToPk)) { + // if (value.length > 1) { + result[key].compositePrimaryKeys = { + [`${key}_${value.join('_')}`]: { + name: `${key}_${value.join('_')}`, + columns: value, + }, + }; + // } else if (value.length === 1) { + // result[key].columns[value[0]].primaryKey = true; + // } else { + // } + } + if (progressCallback) { + progressCallback('columns', columnsCount, 'done'); + progressCallback('tables', tablesCount.size, 'done'); + } + + for (const idxRow of idxRows) { + const tableSchema = idxRow['TABLE_SCHEMA']; + const tableName = idxRow['TABLE_NAME']; + const constraintName = idxRow['INDEX_NAME']; + const columnName: string = idxRow['COLUMN_NAME']; + const isUnique = idxRow['NON_UNIQUE'] === 0; + + const tableInResult = result[tableName]; + if (typeof tableInResult === 'undefined') continue; + + // if (tableInResult.columns[columnName].type === "serial") continue; + + indexesCount += 1; + if (progressCallback) { + progressCallback('indexes', indexesCount, 'fetching'); + } + + if (isUnique) { + if ( + typeof tableInResult.uniqueConstraints[constraintName] !== 'undefined' + ) { + tableInResult.uniqueConstraints[constraintName]!.columns.push( + columnName, + ); + } else { + tableInResult.uniqueConstraints[constraintName] = { + name: constraintName, + columns: [columnName], + }; + } + } else { + if (typeof tableInResult.indexes[constraintName] !== 'undefined') { + tableInResult.indexes[constraintName]!.columns.push(columnName); + } else { + tableInResult.indexes[constraintName] = { + name: constraintName, + columns: [columnName], + isUnique: isUnique, + }; + } + } + } + + if (progressCallback) { + progressCallback('indexes', indexesCount, 'done'); + // progressCallback("enums", 0, "fetching"); + progressCallback('enums', 0, 'done'); + } + + return { + version: '1', + dialect: 'singlestore', + tables: result, + _meta: { + tables: {}, + columns: {}, + }, + internal: internals, + }; +}; diff --git a/drizzle-kit/src/serializer/studio.ts b/drizzle-kit/src/serializer/studio.ts index d83a65b08..bbd811627 100644 --- a/drizzle-kit/src/serializer/studio.ts +++ b/drizzle-kit/src/serializer/studio.ts @@ -15,6 +15,11 @@ import { } from 'drizzle-orm'; import { AnyMySqlTable, getTableConfig as mysqlTableConfig, MySqlTable } from 'drizzle-orm/mysql-core'; import { AnyPgTable, getTableConfig as pgTableConfig, PgTable } from 'drizzle-orm/pg-core'; +import { + AnySingleStoreTable, + getTableConfig as singlestoreTableConfig, + SingleStoreTable, +} from 'drizzle-orm/singlestore-core'; import { AnySQLiteTable, getTableConfig as sqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; import fs from 'fs'; import { Hono } from 'hono'; @@ -28,6 +33,7 @@ import { z } from 'zod'; import { safeRegister } from '../cli/commands/utils'; import type { MysqlCredentials } from '../cli/validations/mysql'; import type { PostgresCredentials } from '../cli/validations/postgres'; +import type { SingleStoreCredentials } from '../cli/validations/singlestore'; import type { SqliteCredentials } from '../cli/validations/sqlite'; import { prepareFilenames } from '.'; @@ -45,7 +51,7 @@ type SchemaFile = { export type Setup = { dbHash: string; - dialect: 'postgresql' | 'mysql' | 'sqlite'; + dialect: 'postgresql' | 'mysql' | 'sqlite' | 'singlestore'; driver?: 'aws-data-api' | 'd1-http' | 'turso' | 'pglite'; proxy: (params: ProxyParams) => Promise; customDefaults: CustomDefault[]; @@ -172,6 +178,43 @@ export const prepareSQLiteSchema = async (path: string | string[]) => { return { schema: sqliteSchema, relations, files }; }; +export const prepareSingleStoreSchema = async (path: string | string[]) => { + const imports = prepareFilenames(path); + const singlestoreSchema: Record> = { + public: {}, + }; + const relations: Record = {}; + + // files content as string + const files = imports.map((it, index) => ({ + // get the file name from the path + name: it.split('/').pop() || `schema${index}.ts`, + content: fs.readFileSync(it, 'utf-8'), + })); + + const { unregister } = await safeRegister(); + for (let i = 0; i < imports.length; i++) { + const it = imports[i]; + + const i0: Record = require(`${it}`); + const i0values = Object.entries(i0); + + i0values.forEach(([k, t]) => { + if (is(t, SingleStoreTable)) { + const schema = singlestoreTableConfig(t).schema || 'public'; + singlestoreSchema[schema][k] = t; + } + + if (is(t, Relations)) { + relations[k] = t; + } + }); + } + unregister(); + + return { schema: singlestoreSchema, relations, files }; +}; + const getCustomDefaults = >( schema: Record>, ): CustomDefault[] => { @@ -187,8 +230,10 @@ const getCustomDefaults = >( tableConfig = pgTableConfig(table); } else if (is(table, MySqlTable)) { tableConfig = mysqlTableConfig(table); - } else { + } else if (is(table, SQLiteTable)) { tableConfig = sqliteTableConfig(table); + } else { + tableConfig = singlestoreTableConfig(table); } tableConfig.columns.map((column) => { @@ -346,6 +391,39 @@ export const drizzleForLibSQL = async ( }; }; +export const drizzleForSingleStore = async ( + credentials: SingleStoreCredentials, + singlestoreSchema: Record>, + relations: Record, + schemaFiles?: SchemaFile[], +): Promise => { + const { connectToSingleStore } = await import('../cli/connections'); + const { proxy } = await connectToSingleStore(credentials); + + const customDefaults = getCustomDefaults(singlestoreSchema); + + let dbUrl: string; + + if ('url' in credentials) { + dbUrl = credentials.url; + } else { + dbUrl = + `singlestore://${credentials.user}:${credentials.password}@${credentials.host}:${credentials.port}/${credentials.database}`; + } + + const dbHash = createHash('sha256').update(dbUrl).digest('hex'); + + return { + dbHash, + dialect: 'singlestore', + proxy, + customDefaults, + schema: singlestoreSchema, + relations, + schemaFiles, + }; +}; + export const extractRelations = (tablesConfig: { tables: TablesRelationalConfig; tableNamesMap: Record; @@ -371,6 +449,8 @@ export const extractRelations = (tablesConfig: { refSchema = mysqlTableConfig(refTable).schema; } else if (is(refTable, SQLiteTable)) { refSchema = undefined; + } else if (is(refTable, SingleStoreTable)) { + refSchema = singlestoreTableConfig(refTable).schema; } else { throw new Error('unsupported dialect'); } diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 060f12bbd..a9d45596b 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -49,19 +49,21 @@ import { JsonReferenceStatement, JsonRenameColumnStatement, JsonRenamePolicyStatement, - JsonRenameRoleStatement, JsonRenameViewStatement, JsonSqliteAddColumnStatement, JsonStatement, prepareAddCheckConstraint, prepareAddCompositePrimaryKeyMySql, prepareAddCompositePrimaryKeyPg, + prepareAddCompositePrimaryKeySingleStore, prepareAddCompositePrimaryKeySqlite, prepareAddUniqueConstraintPg as prepareAddUniqueConstraint, prepareAddValuesToEnumJson, prepareAlterColumnsMysql, + prepareAlterColumnsSingleStore, prepareAlterCompositePrimaryKeyMySql, prepareAlterCompositePrimaryKeyPg, + prepareAlterCompositePrimaryKeySingleStore, prepareAlterCompositePrimaryKeySqlite, prepareAlterIndPolicyJson, prepareAlterPolicyJson, @@ -79,8 +81,8 @@ import { prepareDeleteCheckConstraint, prepareDeleteCompositePrimaryKeyMySql, prepareDeleteCompositePrimaryKeyPg, + prepareDeleteCompositePrimaryKeySingleStore, prepareDeleteCompositePrimaryKeySqlite, - prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDeleteUniqueConstraintPg as prepareDeleteUniqueConstraint, prepareDropEnumJson, prepareDropEnumValues, @@ -89,6 +91,7 @@ import { prepareDropPolicyJsons, prepareDropReferencesJson, prepareDropRoleJson, + prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDropSequenceJson, prepareDropTableJson, prepareDropViewJson, @@ -117,9 +120,10 @@ import { prepareRenameSequenceJson, prepareRenameTableJson, prepareRenameViewJson, + prepareSingleStoreCreateTableJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, - prepareSqliteCreateViewJson, + prepareSqliteCreateViewJson } from './jsonStatements'; import { Named, NamedWithSchema } from './cli/commands/migrate'; @@ -137,6 +141,7 @@ import { sequenceSquashed, View, } from './serializer/pgSchema'; +import { SingleStoreSchema, SingleStoreSchemaSquashed, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher, View as SqliteView } from './serializer/sqliteSchema'; import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; import { copy, prepareMigrationMeta } from './utils'; @@ -393,6 +398,11 @@ export const diffResultSchemeMysql = object({ alteredViews: alteredMySqlViewSchema.array(), }); +export const diffResultSchemeSingleStore = object({ + alteredTablesWithColumns: alteredTableScheme.array(), + alteredEnums: never().array(), +}); + export const diffResultSchemeSQLite = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: never().array(), @@ -407,6 +417,7 @@ export type Table = TypeOf; export type AlteredTable = TypeOf; export type DiffResult = TypeOf; export type DiffResultMysql = TypeOf; +export type DiffResultSingleStore = TypeOf; export type DiffResultSQLite = TypeOf; export interface ResolverInput { @@ -2673,6 +2684,422 @@ export const applyMysqlSnapshotsDiff = async ( }; }; +export const applySingleStoreSnapshotsDiff = async ( + json1: SingleStoreSchemaSquashed, + json2: SingleStoreSchemaSquashed, + tablesResolver: ( + input: ResolverInput
, + ) => Promise>, + columnsResolver: ( + input: ColumnsResolverInput, + ) => Promise>, + viewsResolver: ( + input: ResolverInput, + ) => Promise>, + prevFull: SingleStoreSchema, + curFull: SingleStoreSchema, + action?: 'push' | undefined, +): Promise<{ + statements: JsonStatement[]; + sqlStatements: string[]; + _meta: + | { + schemas: {}; + tables: {}; + columns: {}; + } + | undefined; +}> => { + // squash indexes and fks + + // squash uniqueIndexes and uniqueConstraint into constraints object + // it should be done for singlestore only because it has no diffs for it + for (const tableName in json1.tables) { + const table = json1.tables[tableName]; + for (const indexName in table.indexes) { + const index = SingleStoreSquasher.unsquashIdx(table.indexes[indexName]); + if (index.isUnique) { + table.uniqueConstraints[indexName] = SingleStoreSquasher.squashUnique({ + name: index.name, + columns: index.columns, + }); + delete json1.tables[tableName].indexes[index.name]; + } + } + } + + for (const tableName in json2.tables) { + const table = json2.tables[tableName]; + for (const indexName in table.indexes) { + const index = SingleStoreSquasher.unsquashIdx(table.indexes[indexName]); + if (index.isUnique) { + table.uniqueConstraints[indexName] = SingleStoreSquasher.squashUnique({ + name: index.name, + columns: index.columns, + }); + delete json2.tables[tableName].indexes[index.name]; + } + } + } + + const tablesDiff = diffSchemasOrTables(json1.tables, json2.tables); + + const { + created: createdTables, + deleted: deletedTables, + renamed: renamedTables, // renamed or moved + } = await tablesResolver({ + created: tablesDiff.added, + deleted: tablesDiff.deleted, + }); + + const tablesPatchedSnap1 = copy(json1); + tablesPatchedSnap1.tables = mapEntries(tablesPatchedSnap1.tables, (_, it) => { + const { name } = nameChangeFor(it, renamedTables); + it.name = name; + return [name, it]; + }); + + const res = diffColumns(tablesPatchedSnap1.tables, json2.tables); + const columnRenames = [] as { + table: string; + renames: { from: Column; to: Column }[]; + }[]; + + const columnCreates = [] as { + table: string; + columns: Column[]; + }[]; + + const columnDeletes = [] as { + table: string; + columns: Column[]; + }[]; + + for (let entry of Object.values(res)) { + const { renamed, created, deleted } = await columnsResolver({ + tableName: entry.name, + schema: entry.schema, + deleted: entry.columns.deleted, + created: entry.columns.added, + }); + + if (created.length > 0) { + columnCreates.push({ + table: entry.name, + columns: created, + }); + } + + if (deleted.length > 0) { + columnDeletes.push({ + table: entry.name, + columns: deleted, + }); + } + + if (renamed.length > 0) { + columnRenames.push({ + table: entry.name, + renames: renamed, + }); + } + } + + const columnRenamesDict = columnRenames.reduce( + (acc, it) => { + acc[it.table] = it.renames; + return acc; + }, + {} as Record< + string, + { + from: Named; + to: Named; + }[] + >, + ); + + const columnsPatchedSnap1 = copy(tablesPatchedSnap1); + columnsPatchedSnap1.tables = mapEntries( + columnsPatchedSnap1.tables, + (tableKey, tableValue) => { + const patchedColumns = mapKeys( + tableValue.columns, + (columnKey, column) => { + const rens = columnRenamesDict[tableValue.name] || []; + const newName = columnChangeFor(columnKey, rens); + column.name = newName; + return newName; + }, + ); + + tableValue.columns = patchedColumns; + return [tableKey, tableValue]; + }, + ); + + const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + + const typedResult: DiffResultSingleStore = diffResultSchemeSingleStore.parse(diffResult); + + const jsonStatements: JsonStatement[] = []; + + const jsonCreateIndexesForCreatedTables = createdTables + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.indexes, + curFull.internal, + ); + }) + .flat(); + + const jsonDropTables = deletedTables.map((it) => { + return prepareDropTableJson(it); + }); + + const jsonRenameTables = renamedTables.map((it) => { + return prepareRenameTableJson(it.from, it.to); + }); + + const alteredTables = typedResult.alteredTablesWithColumns; + + const jsonAddedCompositePKs: JsonCreateCompositePK[] = []; + const jsonDeletedCompositePKs: JsonDeleteCompositePK[] = []; + const jsonAlteredCompositePKs: JsonAlterCompositePK[] = []; + + const jsonAddedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames + .map((it) => prepareRenameColumns(it.table, '', it.renames)) + .flat(); + + const jsonAddColumnsStatemets: JsonAddColumnStatement[] = columnCreates + .map((it) => _prepareAddColumns(it.table, '', it.columns)) + .flat(); + + const jsonDropColumnsStatemets: JsonDropColumnStatement[] = columnDeletes + .map((it) => _prepareDropColumns(it.table, '', it.columns)) + .flat(); + + alteredTables.forEach((it) => { + // This part is needed to make sure that same columns in a table are not triggered for change + // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name + // We double-check that pk with same set of columns are both in added and deleted diffs + let addedColumns: string[] = []; + for (const addedPkName of Object.keys(it.addedCompositePKs)) { + const addedPkColumns = it.addedCompositePKs[addedPkName]; + addedColumns = SingleStoreSquasher.unsquashPK(addedPkColumns).columns; + } + + let deletedColumns: string[] = []; + for (const deletedPkName of Object.keys(it.deletedCompositePKs)) { + const deletedPkColumns = it.deletedCompositePKs[deletedPkName]; + deletedColumns = SingleStoreSquasher.unsquashPK(deletedPkColumns).columns; + } + + // Don't need to sort, but need to add tests for it + // addedColumns.sort(); + // deletedColumns.sort(); + const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); + + let addedCompositePKs: JsonCreateCompositePK[] = []; + let deletedCompositePKs: JsonDeleteCompositePK[] = []; + let alteredCompositePKs: JsonAlterCompositePK[] = []; + + addedCompositePKs = prepareAddCompositePrimaryKeySingleStore( + it.name, + it.addedCompositePKs, + prevFull, + curFull, + ); + deletedCompositePKs = prepareDeleteCompositePrimaryKeySingleStore( + it.name, + it.deletedCompositePKs, + prevFull, + ); + // } + alteredCompositePKs = prepareAlterCompositePrimaryKeySingleStore( + it.name, + it.alteredCompositePKs, + prevFull, + curFull, + ); + + // add logic for unique constraints + let addedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + addedUniqueConstraints = prepareAddUniqueConstraint( + it.name, + it.schema, + it.addedUniqueConstraints, + ); + deletedUniqueConstraints = prepareDeleteUniqueConstraint( + it.name, + it.schema, + it.deletedUniqueConstraints, + ); + if (it.alteredUniqueConstraints) { + const added: Record = {}; + const deleted: Record = {}; + for (const k of Object.keys(it.alteredUniqueConstraints)) { + added[k] = it.alteredUniqueConstraints[k].__new; + deleted[k] = it.alteredUniqueConstraints[k].__old; + } + addedUniqueConstraints.push( + ...prepareAddUniqueConstraint(it.name, it.schema, added), + ); + deletedUniqueConstraints.push( + ...prepareDeleteUniqueConstraint(it.name, it.schema, deleted), + ); + } + + jsonAddedCompositePKs.push(...addedCompositePKs); + jsonDeletedCompositePKs.push(...deletedCompositePKs); + jsonAlteredCompositePKs.push(...alteredCompositePKs); + + jsonAddedUniqueConstraints.push(...addedUniqueConstraints); + jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); + jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + }); + + const rColumns = jsonRenameColumnsStatements.map((it) => { + const tableName = it.tableName; + const schema = it.schema; + return { + from: { schema, table: tableName, column: it.oldColumnName }, + to: { schema, table: tableName, column: it.newColumnName }, + }; + }); + + const jsonTableAlternations = alteredTables + .map((it) => { + return prepareAlterColumnsSingleStore( + it.name, + it.schema, + it.altered, + json1, + json2, + action, + ); + }) + .flat(); + + const jsonCreateIndexesForAllAlteredTables = alteredTables + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.addedIndexes || {}, + curFull.internal, + ); + }) + .flat(); + + const jsonDropIndexesForAllAlteredTables = alteredTables + .map((it) => { + return prepareDropIndexesJson( + it.name, + it.schema, + it.deletedIndexes || {}, + ); + }) + .flat(); + + alteredTables.forEach((it) => { + const droppedIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__old; + return current; + }, + {} as Record, + ); + const createdIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__new; + return current; + }, + {} as Record, + ); + + jsonCreateIndexesForAllAlteredTables.push( + ...prepareCreateIndexesJson(it.name, it.schema, createdIndexes || {}), + ); + jsonDropIndexesForAllAlteredTables.push( + ...prepareDropIndexesJson(it.name, it.schema, droppedIndexes || {}), + ); + }); + + const jsonSingleStoreCreateTables = createdTables.map((it) => { + return prepareSingleStoreCreateTableJson( + it, + curFull as SingleStoreSchema, + curFull.internal, + ); + }); + jsonStatements.push(...jsonSingleStoreCreateTables); + + jsonStatements.push(...jsonDropTables); + jsonStatements.push(...jsonRenameTables); + jsonStatements.push(...jsonRenameColumnsStatements); + + jsonStatements.push(...jsonDeletedUniqueConstraints); + + // Will need to drop indexes before changing any columns in table + // Then should go column alternations and then index creation + jsonStatements.push(...jsonDropIndexesForAllAlteredTables); + + jsonStatements.push(...jsonDeletedCompositePKs); + jsonStatements.push(...jsonTableAlternations); + jsonStatements.push(...jsonAddedCompositePKs); + + jsonStatements.push(...jsonAddedUniqueConstraints); + jsonStatements.push(...jsonDeletedUniqueConstraints); + + jsonStatements.push(...jsonAddColumnsStatemets); + + jsonStatements.push(...jsonCreateIndexesForCreatedTables); + + jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); + + jsonStatements.push(...jsonDropColumnsStatemets); + + // jsonStatements.push(...jsonDeletedCompositePKs); + // jsonStatements.push(...jsonAddedCompositePKs); + jsonStatements.push(...jsonAlteredCompositePKs); + + jsonStatements.push(...jsonAddedUniqueConstraints); + + jsonStatements.push(...jsonAlteredUniqueConstraints); + + const sqlStatements = fromJson(jsonStatements, 'singlestore'); + + const uniqueSqlStatements: string[] = []; + sqlStatements.forEach((ss) => { + if (!uniqueSqlStatements.includes(ss)) { + uniqueSqlStatements.push(ss); + } + }); + + const rTables = renamedTables.map((it) => { + return { from: it.from, to: it.to }; + }); + + const _meta = prepareMigrationMeta([], rTables, rColumns); + + return { + statements: jsonStatements, + sqlStatements: uniqueSqlStatements, + _meta, + }; +}; + export const applySqliteSnapshotsDiff = async ( json1: SQLiteSchemaSquashed, json2: SQLiteSchemaSquashed, diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 3c88a86ce..60ec3fc9c 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -84,7 +84,8 @@ import { } from './jsonStatements'; import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; -import { PgSquasher, policy } from './serializer/pgSchema'; +import { PgSquasher } from './serializer/pgSchema'; +import { SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; import { escapeSingleQuotes } from './utils'; @@ -572,6 +573,81 @@ class MySqlCreateTableConvertor extends Convertor { return statement; } } +class SingleStoreCreateTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_table' && dialect === 'singlestore'; + } + + convert(st: JsonCreateTableStatement) { + const { + tableName, + columns, + schema, + compositePKs, + uniqueConstraints, + internals, + } = st; + + let statement = ''; + statement += `CREATE TABLE \`${tableName}\` (\n`; + for (let i = 0; i < columns.length; i++) { + const column = columns[i]; + + const primaryKeyStatement = column.primaryKey ? ' PRIMARY KEY' : ''; + const notNullStatement = column.notNull ? ' NOT NULL' : ''; + const defaultStatement = column.default !== undefined ? ` DEFAULT ${column.default}` : ''; + + const onUpdateStatement = column.onUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + + const autoincrementStatement = column.autoincrement + ? ' AUTO_INCREMENT' + : ''; + + const generatedStatement = column.generated + ? ` GENERATED ALWAYS AS (${column.generated?.as}) ${column.generated?.type.toUpperCase()}` + : ''; + + statement += '\t' + + `\`${column.name}\` ${column.type}${autoincrementStatement}${primaryKeyStatement}${notNullStatement}${defaultStatement}${onUpdateStatement}${generatedStatement}`; + statement += i === columns.length - 1 ? '' : ',\n'; + } + + if (typeof compositePKs !== 'undefined' && compositePKs.length > 0) { + statement += ',\n'; + const compositePK = SingleStoreSquasher.unsquashPK(compositePKs[0]); + statement += `\tCONSTRAINT \`${st.compositePkName}\` PRIMARY KEY(\`${compositePK.columns.join(`\`,\``)}\`)`; + } + + if ( + typeof uniqueConstraints !== 'undefined' + && uniqueConstraints.length > 0 + ) { + for (const uniqueConstraint of uniqueConstraints) { + statement += ',\n'; + const unsquashedUnique = SingleStoreSquasher.unsquashUnique(uniqueConstraint); + + const uniqueString = unsquashedUnique.columns + .map((it) => { + return internals?.indexes + ? internals?.indexes[unsquashedUnique.name]?.columns[it] + ?.isExpression + ? it + : `\`${it}\`` + : `\`${it}\``; + }) + .join(','); + + statement += `\tCONSTRAINT \`${unsquashedUnique.name}\` UNIQUE(${uniqueString})`; + } + } + + statement += `\n);`; + statement += `\n`; + return statement; + } +} export class SQLiteCreateTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { @@ -1165,6 +1241,29 @@ class MySqlAlterTableAddCheckConstraintConvertor extends Convertor { } } +class SingleStoreAlterTableAddUniqueConstraintConvertor extends Convertor { + can(statement: JsonCreateUniqueConstraint, dialect: Dialect): boolean { + return statement.type === 'create_unique_constraint' && dialect === 'singlestore'; + } + convert(statement: JsonCreateUniqueConstraint): string { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); + + return `ALTER TABLE \`${statement.tableName}\` ADD CONSTRAINT \`${unsquashed.name}\` UNIQUE(\`${ + unsquashed.columns.join('`,`') + }\`);`; + } +} +class SingleStoreAlterTableDropUniqueConstraintConvertor extends Convertor { + can(statement: JsonDeleteUniqueConstraint, dialect: Dialect): boolean { + return statement.type === 'delete_unique_constraint' && dialect === 'singlestore'; + } + convert(statement: JsonDeleteUniqueConstraint): string { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); + + return `ALTER TABLE \`${statement.tableName}\` DROP INDEX \`${unsquashed.name}\`;`; + } +} + class MySqlAlterTableDeleteCheckConstraintConvertor extends Convertor { can(statement: JsonDeleteCheckConstraint, dialect: Dialect): boolean { return ( @@ -1431,6 +1530,17 @@ class MySQLDropTableConvertor extends Convertor { } } +class SingleStoreDropTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_table' && dialect === 'singlestore'; + } + + convert(statement: JsonDropTableStatement) { + const { tableName } = statement; + return `DROP TABLE \`${tableName}\`;`; + } +} + export class SQLiteDropTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'drop_table' && (dialect === 'sqlite' || dialect === 'turso'); @@ -1479,6 +1589,17 @@ class MySqlRenameTableConvertor extends Convertor { } } +class SingleStoreRenameTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'rename_table' && dialect === 'singlestore'; + } + + convert(statement: JsonRenameTableStatement) { + const { tableNameFrom, tableNameTo } = statement; + return `RENAME TABLE \`${tableNameFrom}\` TO \`${tableNameTo}\`;`; + } +} + class PgAlterTableRenameColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1510,6 +1631,19 @@ class MySqlAlterTableRenameColumnConvertor extends Convertor { } } +class SingleStoreAlterTableRenameColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + statement.type === 'alter_table_rename_column' && dialect === 'singlestore' + ); + } + + convert(statement: JsonRenameColumnStatement) { + const { tableName, oldColumnName, newColumnName } = statement; + return `ALTER TABLE \`${tableName}\` RENAME COLUMN \`${oldColumnName}\` TO \`${newColumnName}\`;`; + } +} + class SQLiteAlterTableRenameColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1552,6 +1686,17 @@ class MySqlAlterTableDropColumnConvertor extends Convertor { } } +class SingleStoreAlterTableDropColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_table_drop_column' && dialect === 'singlestore'; + } + + convert(statement: JsonDropColumnStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` DROP COLUMN \`${columnName}\`;`; + } +} + class SQLiteAlterTableDropColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'alter_table_drop_column' && (dialect === 'sqlite' || dialect === 'turso'); @@ -1659,6 +1804,37 @@ class MySqlAlterTableAddColumnConvertor extends Convertor { } } +class SingleStoreAlterTableAddColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_table_add_column' && dialect === 'singlestore'; + } + + convert(statement: JsonAddColumnStatement) { + const { tableName, column } = statement; + const { + name, + type, + notNull, + primaryKey, + autoincrement, + onUpdate, + generated, + } = column; + + const defaultStatement = `${column.default !== undefined ? ` DEFAULT ${column.default}` : ''}`; + const notNullStatement = `${notNull ? ' NOT NULL' : ''}`; + const primaryKeyStatement = `${primaryKey ? ' PRIMARY KEY' : ''}`; + const autoincrementStatement = `${autoincrement ? ' AUTO_INCREMENT' : ''}`; + const onUpdateStatement = `${onUpdate ? ' ON UPDATE CURRENT_TIMESTAMP' : ''}`; + + const generatedStatement = generated + ? ` GENERATED ALWAYS AS (${generated?.as}) ${generated?.type.toUpperCase()}` + : ''; + + return `ALTER TABLE \`${tableName}\` ADD \`${name}\` ${type}${primaryKeyStatement}${autoincrementStatement}${defaultStatement}${notNullStatement}${onUpdateStatement}${generatedStatement};`; + } +} + export class SQLiteAlterTableAddColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2462,76 +2638,430 @@ class MySqlModifyColumn extends Convertor { } } -class PgAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { +class SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_composite_pk' && dialect === 'postgresql'; + return ( + statement.type === 'alter_table_alter_column_alter_generated' + && dialect === 'singlestore' + ); } - convert(statement: JsonCreateCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.data); + convert(statement: JsonAlterColumnAlterGeneratedStatement) { + const { + tableName, + columnName, + schema, + columnNotNull: notNull, + columnDefault, + columnOnUpdate, + columnAutoIncrement, + columnPk, + columnGenerated, + } = statement; - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; + const tableNameWithSchema = schema + ? `\`${schema}\`.\`${tableName}\`` + : `\`${tableName}\``; - return `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.constraintName}" PRIMARY KEY("${ - columns.join('","') - }");`; + const addColumnStatement = new SingleStoreAlterTableAddColumnConvertor().convert({ + schema, + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull, + default: columnDefault, + onUpdate: columnOnUpdate, + autoincrement: columnAutoIncrement, + primaryKey: columnPk, + generated: columnGenerated, + }, + type: 'alter_table_add_column', + }); + + return [ + `ALTER TABLE ${tableNameWithSchema} drop column \`${columnName}\`;`, + addColumnStatement, + ]; } } -class PgAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + +class SingleStoreAlterTableAlterColumnSetDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'delete_composite_pk' && dialect === 'postgresql'; + return ( + statement.type === 'alter_table_alter_column_set_default' + && dialect === 'singlestore' + ); } - convert(statement: JsonDeleteCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.data); - - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; - - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.constraintName}";`; + convert(statement: JsonAlterColumnSetDefaultStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` ALTER COLUMN \`${columnName}\` SET DEFAULT ${statement.newDefaultValue};`; } } -class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { +class SingleStoreAlterTableAlterColumnDropDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_composite_pk' && dialect === 'postgresql'; - } - - convert(statement: JsonAlterCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.old); - const { name: newName, columns: newColumns } = PgSquasher.unsquashPK( - statement.new, + return ( + statement.type === 'alter_table_alter_column_drop_default' + && dialect === 'singlestore' ); + } - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; - - console.log(statement.oldConstraintName, statement.newConstraintName); - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.oldConstraintName}";\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.newConstraintName}" PRIMARY KEY("${ - newColumns.join('","') - }");`; + convert(statement: JsonAlterColumnDropDefaultStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` ALTER COLUMN \`${columnName}\` DROP DEFAULT;`; } } -class MySqlAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_composite_pk' && dialect === 'mysql'; +class SingleStoreAlterTableAddPk extends Convertor { + can(statement: JsonStatement, dialect: string): boolean { + return ( + statement.type === 'alter_table_alter_column_set_pk' + && dialect === 'singlestore' + ); } - - convert(statement: JsonCreateCompositePK) { - const { name, columns } = MySqlSquasher.unsquashPK(statement.data); - return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY(\`${columns.join('`,`')}\`);`; + convert(statement: JsonAlterColumnSetPrimaryKeyStatement): string { + return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY (\`${statement.columnName}\`);`; } } -class MySqlAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'delete_composite_pk' && dialect === 'mysql'; - } +class SingleStoreAlterTableDropPk extends Convertor { + can(statement: JsonStatement, dialect: string): boolean { + return ( + statement.type === 'alter_table_alter_column_drop_pk' + && dialect === 'singlestore' + ); + } + convert(statement: JsonAlterColumnDropPrimaryKeyStatement): string { + return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY`; + } +} + +type SingleStoreModifyColumnStatement = + | JsonAlterColumnDropNotNullStatement + | JsonAlterColumnSetNotNullStatement + | JsonAlterColumnTypeStatement + | JsonAlterColumnDropOnUpdateStatement + | JsonAlterColumnSetOnUpdateStatement + | JsonAlterColumnDropAutoincrementStatement + | JsonAlterColumnSetAutoincrementStatement + | JsonAlterColumnSetDefaultStatement + | JsonAlterColumnDropDefaultStatement + | JsonAlterColumnSetGeneratedStatement + | JsonAlterColumnDropGeneratedStatement; + +class SingleStoreModifyColumn extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + (statement.type === 'alter_table_alter_column_set_type' + || statement.type === 'alter_table_alter_column_set_notnull' + || statement.type === 'alter_table_alter_column_drop_notnull' + || statement.type === 'alter_table_alter_column_drop_on_update' + || statement.type === 'alter_table_alter_column_set_on_update' + || statement.type === 'alter_table_alter_column_set_autoincrement' + || statement.type === 'alter_table_alter_column_drop_autoincrement' + || statement.type === 'alter_table_alter_column_set_default' + || statement.type === 'alter_table_alter_column_drop_default' + || statement.type === 'alter_table_alter_column_set_generated' + || statement.type === 'alter_table_alter_column_drop_generated') + && dialect === 'singlestore' + ); + } + + convert(statement: SingleStoreModifyColumnStatement) { + const { tableName, columnName } = statement; + let columnType = ``; + let columnDefault: any = ''; + let columnNotNull = ''; + let columnOnUpdate = ''; + let columnAutoincrement = ''; + let primaryKey = statement.columnPk ? ' PRIMARY KEY' : ''; + let columnGenerated = ''; + + if (statement.type === 'alter_table_alter_column_drop_notnull') { + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_notnull') { + columnNotNull = ` NOT NULL`; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_drop_on_update') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnOnUpdate = ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_on_update') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = ` ON UPDATE CURRENT_TIMESTAMP`; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if ( + statement.type === 'alter_table_alter_column_set_autoincrement' + ) { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = ' AUTO_INCREMENT'; + } else if ( + statement.type === 'alter_table_alter_column_drop_autoincrement' + ) { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = ''; + } else if (statement.type === 'alter_table_alter_column_set_default') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = ` DEFAULT ${statement.newDefaultValue}`; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_drop_default') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_generated') { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + + if (statement.columnGenerated?.type === 'virtual') { + return [ + new SingleStoreAlterTableDropColumnConvertor().convert({ + type: 'alter_table_drop_column', + tableName: statement.tableName, + columnName: statement.columnName, + schema: statement.schema, + }), + new SingleStoreAlterTableAddColumnConvertor().convert({ + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull: statement.columnNotNull, + default: statement.columnDefault, + onUpdate: statement.columnOnUpdate, + autoincrement: statement.columnAutoIncrement, + primaryKey: statement.columnPk, + generated: statement.columnGenerated, + }, + schema: statement.schema, + type: 'alter_table_add_column', + }), + ]; + } else { + columnGenerated = statement.columnGenerated + ? ` GENERATED ALWAYS AS (${statement.columnGenerated?.as}) ${statement.columnGenerated?.type.toUpperCase()}` + : ''; + } + } else if (statement.type === 'alter_table_alter_column_drop_generated') { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + + if (statement.oldColumn?.generated?.type === 'virtual') { + return [ + new SingleStoreAlterTableDropColumnConvertor().convert({ + type: 'alter_table_drop_column', + tableName: statement.tableName, + columnName: statement.columnName, + schema: statement.schema, + }), + new SingleStoreAlterTableAddColumnConvertor().convert({ + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull: statement.columnNotNull, + default: statement.columnDefault, + onUpdate: statement.columnOnUpdate, + autoincrement: statement.columnAutoIncrement, + primaryKey: statement.columnPk, + generated: statement.columnGenerated, + }, + schema: statement.schema, + type: 'alter_table_add_column', + }), + ]; + } + } else { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + columnGenerated = statement.columnGenerated + ? ` GENERATED ALWAYS AS (${statement.columnGenerated?.as}) ${statement.columnGenerated?.type.toUpperCase()}` + : ''; + } + + // Seems like getting value from simple json2 shanpshot makes dates be dates + columnDefault = columnDefault instanceof Date + ? columnDefault.toISOString() + : columnDefault; + + return `ALTER TABLE \`${tableName}\` MODIFY COLUMN \`${columnName}\`${columnType}${columnAutoincrement}${columnNotNull}${columnDefault}${columnOnUpdate}${columnGenerated};`; + } +} +class SqliteAlterTableAlterColumnDropDefaultConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + statement.type === 'alter_table_alter_column_drop_default' + && dialect === 'sqlite' + ); + } + + convert(statement: JsonAlterColumnDropDefaultStatement) { + return ( + '/*\n SQLite does not support "Drop default from column" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' + ); + } +} + +class PgAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonCreateCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.data); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.constraintName}" PRIMARY KEY("${ + columns.join('","') + }");`; + } +} +class PgAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonDeleteCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.data); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.constraintName}";`; + } +} + +class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonAlterCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.old); + const { name: newName, columns: newColumns } = PgSquasher.unsquashPK( + statement.new, + ); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + console.log(statement.oldConstraintName, statement.newConstraintName); + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.oldConstraintName}";\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.newConstraintName}" PRIMARY KEY("${ + newColumns.join('","') + }");`; + } +} + +class MySqlAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'mysql'; + } + + convert(statement: JsonCreateCompositePK) { + const { name, columns } = MySqlSquasher.unsquashPK(statement.data); + return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY(\`${columns.join('`,`')}\`);`; + } +} + +class MySqlAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'mysql'; + } convert(statement: JsonDeleteCompositePK) { const { name, columns } = MySqlSquasher.unsquashPK(statement.data); @@ -2553,6 +3083,125 @@ class MySqlAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { } } +class SingleStoreAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'singlestore'; + } + + convert(statement: JsonCreateCompositePK) { + const { name, columns } = SingleStoreSquasher.unsquashPK(statement.data); + return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY(\`${columns.join('`,`')}\`);`; + } +} + +class SingleStoreAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'singlestore'; + } + + convert(statement: JsonDeleteCompositePK) { + const { name, columns } = SingleStoreSquasher.unsquashPK(statement.data); + return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY;`; + } +} + +class SingleStoreAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_composite_pk' && dialect === 'singlestore'; + } + + convert(statement: JsonAlterCompositePK) { + const { name, columns } = SingleStoreSquasher.unsquashPK(statement.old); + const { name: newName, columns: newColumns } = SingleStoreSquasher.unsquashPK( + statement.new, + ); + return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY, ADD PRIMARY KEY(\`${newColumns.join('`,`')}\`);`; + } +} + +class SqliteAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'sqlite'; + } + + convert(statement: JsonCreateCompositePK) { + let msg = '/*\n'; + msg += `You're trying to add PRIMARY KEY(${statement.data}) to '${statement.tableName}' table\n`; + msg += 'SQLite does not support adding primary key to an already created table\n'; + msg += 'You can do it in 3 steps with drizzle orm:\n'; + msg += ' - create new mirror table with needed pk, rename current table to old_table, generate SQL\n'; + msg += ' - migrate old data from one table to another\n'; + msg += ' - delete old_table in schema, generate sql\n\n'; + msg += 'or create manual migration like below:\n\n'; + msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; + msg += 'CREATE TABLE table_name (\n'; + msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; + msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; + msg += '\t...\n'; + msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; + msg += ' );\n'; + msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; + msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; + msg += '*/\n'; + return msg; + } +} +class SqliteAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'sqlite'; + } + + convert(statement: JsonDeleteCompositePK) { + let msg = '/*\n'; + msg += `You're trying to delete PRIMARY KEY(${statement.data}) from '${statement.tableName}' table\n`; + msg += 'SQLite does not supportprimary key deletion from existing table\n'; + msg += 'You can do it in 3 steps with drizzle orm:\n'; + msg += ' - create new mirror table table without pk, rename current table to old_table, generate SQL\n'; + msg += ' - migrate old data from one table to another\n'; + msg += ' - delete old_table in schema, generate sql\n\n'; + msg += 'or create manual migration like below:\n\n'; + msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; + msg += 'CREATE TABLE table_name (\n'; + msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; + msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; + msg += '\t...\n'; + msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; + msg += ' );\n'; + msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; + msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; + msg += '*/\n'; + return msg; + } +} + +class SqliteAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_composite_pk' && dialect === 'sqlite'; + } + + convert(statement: JsonAlterCompositePK) { + let msg = '/*\n'; + msg += 'SQLite does not support altering primary key\n'; + msg += 'You can do it in 3 steps with drizzle orm:\n'; + msg += ' - create new mirror table with needed pk, rename current table to old_table, generate SQL\n'; + msg += ' - migrate old data from one table to another\n'; + msg += ' - delete old_table in schema, generate sql\n\n'; + msg += 'or create manual migration like below:\n\n'; + msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; + msg += 'CREATE TABLE table_name (\n'; + msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; + msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; + msg += '\t...\n'; + msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; + msg += ' );\n'; + msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; + msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; + msg += '*/\n'; + + return msg; + } +} + class PgAlterTableAlterColumnSetPrimaryKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2895,6 +3544,32 @@ class CreateMySqlIndexConvertor extends Convertor { } } +class CreateSingleStoreIndexConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_index' && dialect === 'singlestore'; + } + + convert(statement: JsonCreateIndexStatement): string { + // should be changed + const { name, columns, isUnique } = SingleStoreSquasher.unsquashIdx( + statement.data, + ); + const indexPart = isUnique ? 'UNIQUE INDEX' : 'INDEX'; + + const uniqueString = columns + .map((it) => { + return statement.internal?.indexes + ? statement.internal?.indexes[name]?.columns[it]?.isExpression + ? it + : `\`${it}\`` + : `\`${it}\``; + }) + .join(','); + + return `CREATE ${indexPart} \`${name}\` ON \`${statement.tableName}\` (${uniqueString});`; + } +} + export class CreateSqliteIndexConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_index' && (dialect === 'sqlite' || dialect === 'turso'); @@ -3039,6 +3714,17 @@ class MySqlDropIndexConvertor extends Convertor { } } +class SingleStoreDropIndexConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_index' && dialect === 'singlestore'; + } + + convert(statement: JsonDropIndexStatement): string { + const { name } = SingleStoreSquasher.unsquashIdx(statement.data); + return `DROP INDEX \`${name}\` ON \`${statement.tableName}\`;`; + } +} + class SQLiteRecreateTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -3174,6 +3860,7 @@ class LibSQLRecreateTableConvertor extends Convertor { const convertors: Convertor[] = []; convertors.push(new PgCreateTableConvertor()); convertors.push(new MySqlCreateTableConvertor()); +convertors.push(new SingleStoreCreateTableConvertor()); convertors.push(new SQLiteCreateTableConvertor()); convertors.push(new SQLiteRecreateTableConvertor()); convertors.push(new LibSQLRecreateTableConvertor()); @@ -3210,22 +3897,27 @@ convertors.push(new AlterPgSequenceConvertor()); convertors.push(new PgDropTableConvertor()); convertors.push(new MySQLDropTableConvertor()); +convertors.push(new SingleStoreDropTableConvertor()); convertors.push(new SQLiteDropTableConvertor()); convertors.push(new PgRenameTableConvertor()); convertors.push(new MySqlRenameTableConvertor()); +convertors.push(new SingleStoreRenameTableConvertor()); convertors.push(new SqliteRenameTableConvertor()); convertors.push(new PgAlterTableRenameColumnConvertor()); convertors.push(new MySqlAlterTableRenameColumnConvertor()); +convertors.push(new SingleStoreAlterTableRenameColumnConvertor()); convertors.push(new SQLiteAlterTableRenameColumnConvertor()); convertors.push(new PgAlterTableDropColumnConvertor()); convertors.push(new MySqlAlterTableDropColumnConvertor()); +convertors.push(new SingleStoreAlterTableDropColumnConvertor()); convertors.push(new SQLiteAlterTableDropColumnConvertor()); convertors.push(new PgAlterTableAddColumnConvertor()); convertors.push(new MySqlAlterTableAddColumnConvertor()); +convertors.push(new SingleStoreAlterTableAddColumnConvertor()); convertors.push(new SQLiteAlterTableAddColumnConvertor()); convertors.push(new PgAlterTableAlterColumnSetTypeConvertor()); @@ -3241,13 +3933,18 @@ convertors.push(new MySqlAlterTableDeleteCheckConstraintConvertor()); convertors.push(new MySQLAlterTableAddUniqueConstraintConvertor()); convertors.push(new MySQLAlterTableDropUniqueConstraintConvertor()); +convertors.push(new SingleStoreAlterTableAddUniqueConstraintConvertor()); +convertors.push(new SingleStoreAlterTableDropUniqueConstraintConvertor()); + convertors.push(new CreatePgIndexConvertor()); convertors.push(new CreateMySqlIndexConvertor()); +convertors.push(new CreateSingleStoreIndexConvertor()); convertors.push(new CreateSqliteIndexConvertor()); convertors.push(new PgDropIndexConvertor()); convertors.push(new SqliteDropIndexConvertor()); convertors.push(new MySqlDropIndexConvertor()); +convertors.push(new SingleStoreDropIndexConvertor()); convertors.push(new PgAlterTableAlterColumnSetPrimaryKeyConvertor()); convertors.push(new PgAlterTableAlterColumnDropPrimaryKeyConvertor()); @@ -3281,6 +3978,8 @@ convertors.push(new PgAlterTableAlterColumnAlterrGeneratedConvertor()); convertors.push(new MySqlAlterTableAlterColumnAlterrGeneratedConvertor()); +convertors.push(new SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor()); + convertors.push(new SqliteAlterTableAlterColumnDropGeneratedConvertor()); convertors.push(new SqliteAlterTableAlterColumnAlterGeneratedConvertor()); convertors.push(new SqliteAlterTableAlterColumnSetExpressionConvertor()); @@ -3290,6 +3989,8 @@ convertors.push(new LibSQLModifyColumn()); // convertors.push(new MySqlAlterTableAlterColumnSetDefaultConvertor()); // convertors.push(new MySqlAlterTableAlterColumnDropDefaultConvertor()); +convertors.push(new SingleStoreModifyColumn()); + convertors.push(new PgCreateForeignKeyConvertor()); convertors.push(new MySqlCreateForeignKeyConvertor()); @@ -3321,6 +4022,12 @@ convertors.push(new MySqlAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new MySqlAlterTableAddPk()); convertors.push(new MySqlAlterTableAlterCompositePrimaryKeyConvertor()); +convertors.push(new SingleStoreAlterTableDeleteCompositePrimaryKeyConvertor()); +convertors.push(new SingleStoreAlterTableDropPk()); +convertors.push(new SingleStoreAlterTableCreateCompositePrimaryKeyConvertor()); +convertors.push(new SingleStoreAlterTableAddPk()); +convertors.push(new SingleStoreAlterTableAlterCompositePrimaryKeyConvertor()); + export function fromJson( statements: JsonStatement[], dialect: Dialect, diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 685e2efb5..2638ca4ef 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -10,6 +10,7 @@ import { assertUnreachable, snapshotVersion } from './global'; import type { Dialect } from './schemaValidator'; import { backwardCompatibleMysqlSchema } from './serializer/mysqlSchema'; import { backwardCompatiblePgSchema } from './serializer/pgSchema'; +import { backwardCompatibleSingleStoreSchema } from './serializer/singlestoreSchema'; import { backwardCompatibleSqliteSchema } from './serializer/sqliteSchema'; import type { ProxyParams } from './serializer/studio'; @@ -123,6 +124,8 @@ const validatorForDialect = (dialect: Dialect) => { return { validator: backwardCompatibleSqliteSchema, version: 6 }; case 'mysql': return { validator: backwardCompatibleMysqlSchema, version: 5 }; + case 'singlestore': + return { validator: backwardCompatibleSingleStoreSchema, version: 1 }; } }; diff --git a/drizzle-kit/tests/push/singlestore-push.test.ts b/drizzle-kit/tests/push/singlestore-push.test.ts new file mode 100644 index 000000000..5db899fc0 --- /dev/null +++ b/drizzle-kit/tests/push/singlestore-push.test.ts @@ -0,0 +1,335 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import { int, singlestoreTable, singlestoreView } from 'drizzle-orm/singlestore-core'; +import fs from 'fs'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { diffTestSchemasPushSingleStore } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, expect, test } from 'vitest'; + +let client: Connection; +let singlestoreContainer: Docker.Container; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + ); + + singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return `singlestore://root:singlestore@localhost:${port}/`; +} + +beforeAll(async () => { + const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); + throw lastError; + } +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); +}); + +if (!fs.existsSync('tests/push/singlestore')) { + fs.mkdirSync('tests/push/singlestore'); +} + +test('add check constraint to table', async () => { + const schema1 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + const schema2 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'create_check_constraint', + tableName: 'test', + schema: '', + data: 'some_check1;\`test\`.\`values\` < 100', + }, + { + data: "some_check2;'test' < 100", + schema: '', + tableName: 'test', + type: 'create_check_constraint', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE \`test\` ADD CONSTRAINT \`some_check1\` CHECK (\`test\`.\`values\` < 100);', + `ALTER TABLE \`test\` ADD CONSTRAINT \`some_check2\` CHECK ('test' < 100);`, + ]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('drop check constraint to table', async () => { + const schema1 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + const schema2 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'delete_check_constraint', + tableName: 'test', + schema: '', + constraintName: 'some_check1', + }, + { + constraintName: 'some_check2', + schema: '', + tableName: 'test', + type: 'delete_check_constraint', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE \`test\` DROP CONSTRAINT \`some_check1\`;', + `ALTER TABLE \`test\` DROP CONSTRAINT \`some_check2\`;`, + ]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('db has checks. Push with same names', async () => { + const schema1 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values').default(1), + }), + }; + const schema2 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values').default(1), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('create view', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + }; + + const schema2 = { + test: table, + view: singlestoreView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + definition: 'select \`id\` from \`test\`', + name: 'view', + type: 'singlestore_create_view', + replace: false, + sqlSecurity: 'definer', + withCheckOption: undefined, + algorithm: 'undefined', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `CREATE ALGORITHM = undefined +SQL SECURITY definer +VIEW \`view\` AS (select \`id\` from \`test\`);`, + ]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +test('drop view', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: singlestoreView('view').as((qb) => qb.select().from(table)), + }; + + const schema2 = { + test: table, + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + name: 'view', + type: 'drop_view', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'DROP VIEW \`view\`;', + ]); + await client.query(`DROP TABLE \`test\`;`); + await client.query(`DROP VIEW \`view\`;`); +}); + +test('alter view ".as"', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: singlestoreView('view').as((qb) => qb.select().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: singlestoreView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`DROP TABLE \`test\`;`); + await client.query(`DROP VIEW \`view\`;`); +}); + +test('alter meta options with distinct in definition', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: singlestoreView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('merge').as(( + qb, + ) => qb.selectDistinct().from(table).where(sql`${table.id} = 1`)), + }; + + const schema2 = { + test: table, + view: singlestoreView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('undefined').as((qb) => + qb.selectDistinct().from(table) + ), + }; + + await expect(diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + )).rejects.toThrowError(); + + await client.query(`DROP TABLE \`test\`;`); +}); diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts new file mode 100644 index 000000000..7f3ea755d --- /dev/null +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -0,0 +1,699 @@ +import Docker from 'dockerode'; +import { SQL, sql } from 'drizzle-orm'; +import { + bigint, + binary, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + singlestoreEnum, + singlestoreTable, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, +} from 'drizzle-orm/singlestore-core'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { diffTestSchemasSingleStore, diffTestSchemasPushSingleStore } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { expect } from 'vitest'; +import { DialectSuite, run } from './common'; + +async function createDockerDB(context: any): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + ); + + context.singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await context.singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return `singlestore://root:singlestore@localhost:${port}/`; +} + +const singlestoreSuite: DialectSuite = { + allTypes: async function(context: any): Promise { + const schema1 = { + allBigInts: singlestoreTable('all_big_ints', { + simple: bigint('simple', { mode: 'number' }), + columnNotNull: bigint('column_not_null', { mode: 'number' }).notNull(), + columnDefault: bigint('column_default', { mode: 'number' }).default(12), + columnDefaultSql: bigint('column_default_sql', { + mode: 'number', + }).default(12), + }), + allBools: singlestoreTable('all_bools', { + simple: tinyint('simple'), + columnNotNull: tinyint('column_not_null').notNull(), + columnDefault: tinyint('column_default').default(1), + }), + allChars: singlestoreTable('all_chars', { + simple: char('simple', { length: 1 }), + columnNotNull: char('column_not_null', { length: 45 }).notNull(), + // columnDefault: char("column_default", { length: 1 }).default("h"), + columnDefaultSql: char('column_default_sql', { length: 1 }).default( + 'h', + ), + }), + allDateTimes: singlestoreTable('all_date_times', { + simple: datetime('simple', { mode: 'string', fsp: 1 }), + columnNotNull: datetime('column_not_null', { + mode: 'string', + }).notNull(), + columnDefault: datetime('column_default', { mode: 'string' }).default( + '2023-03-01 14:05:29', + ), + }), + allDates: singlestoreTable('all_dates', { + simple: date('simple', { mode: 'string' }), + column_not_null: date('column_not_null', { mode: 'string' }).notNull(), + column_default: date('column_default', { mode: 'string' }).default( + '2023-03-01', + ), + }), + allDecimals: singlestoreTable('all_decimals', { + simple: decimal('simple', { precision: 1, scale: 0 }), + columnNotNull: decimal('column_not_null', { + precision: 45, + scale: 3, + }).notNull(), + columnDefault: decimal('column_default', { + precision: 10, + scale: 0, + }).default('100'), + columnDefaultSql: decimal('column_default_sql', { + precision: 10, + scale: 0, + }).default('101'), + }), + + allDoubles: singlestoreTable('all_doubles', { + simple: double('simple'), + columnNotNull: double('column_not_null').notNull(), + columnDefault: double('column_default').default(100), + columnDefaultSql: double('column_default_sql').default(101), + }), + + allEnums: singlestoreTable('all_enums', { + simple: singlestoreEnum('simple', ['hi', 'hello']), + }), + + allEnums1: singlestoreTable('all_enums1', { + simple: singlestoreEnum('simple', ['hi', 'hello']).default('hi'), + }), + + allFloats: singlestoreTable('all_floats', { + columnNotNull: float('column_not_null').notNull(), + columnDefault: float('column_default').default(100), + columnDefaultSql: float('column_default_sql').default(101), + }), + + allInts: singlestoreTable('all_ints', { + simple: int('simple'), + columnNotNull: int('column_not_null').notNull(), + columnDefault: int('column_default').default(100), + columnDefaultSql: int('column_default_sql').default(101), + }), + + allIntsRef: singlestoreTable('all_ints_ref', { + simple: int('simple'), + columnNotNull: int('column_not_null').notNull(), + columnDefault: int('column_default').default(100), + columnDefaultSql: int('column_default_sql').default(101), + }), + + allJsons: singlestoreTable('all_jsons', { + columnDefaultObject: json('column_default_object') + .default({ hello: 'world world' }) + .notNull(), + columnDefaultArray: json('column_default_array').default({ + hello: { 'world world': ['foo', 'bar'] }, + foo: 'bar', + fe: 23, + }), + column: json('column'), + }), + + allMInts: singlestoreTable('all_m_ints', { + simple: mediumint('simple'), + columnNotNull: mediumint('column_not_null').notNull(), + columnDefault: mediumint('column_default').default(100), + columnDefaultSql: mediumint('column_default_sql').default(101), + }), + + allReals: singlestoreTable('all_reals', { + simple: double('simple', { precision: 5, scale: 2 }), + columnNotNull: double('column_not_null').notNull(), + columnDefault: double('column_default').default(100), + columnDefaultSql: double('column_default_sql').default(101), + }), + + allSInts: singlestoreTable('all_s_ints', { + simple: smallint('simple'), + columnNotNull: smallint('column_not_null').notNull(), + columnDefault: smallint('column_default').default(100), + columnDefaultSql: smallint('column_default_sql').default(101), + }), + + allSmallSerials: singlestoreTable('all_small_serials', { + columnAll: serial('column_all').primaryKey().notNull(), + }), + + allTInts: singlestoreTable('all_t_ints', { + simple: tinyint('simple'), + columnNotNull: tinyint('column_not_null').notNull(), + columnDefault: tinyint('column_default').default(10), + columnDefaultSql: tinyint('column_default_sql').default(11), + }), + + allTexts: singlestoreTable('all_texts', { + simple: text('simple'), + columnNotNull: text('column_not_null').notNull(), + columnDefault: text('column_default').default('hello'), + columnDefaultSql: text('column_default_sql').default('hello'), + }), + + allTimes: singlestoreTable('all_times', { + simple: time('simple', { fsp: 1 }), + columnNotNull: time('column_not_null').notNull(), + columnDefault: time('column_default').default('22:12:12'), + }), + + allTimestamps: singlestoreTable('all_timestamps', { + columnDateNow: timestamp('column_date_now', { + fsp: 1, + mode: 'string', + }).default(sql`(now())`), + columnAll: timestamp('column_all', { mode: 'string' }) + .default('2023-03-01 14:05:29') + .notNull(), + column: timestamp('column', { mode: 'string' }).default( + '2023-02-28 16:18:31', + ), + }), + + allVarChars: singlestoreTable('all_var_chars', { + simple: varchar('simple', { length: 100 }), + columnNotNull: varchar('column_not_null', { length: 45 }).notNull(), + columnDefault: varchar('column_default', { length: 100 }).default( + 'hello', + ), + columnDefaultSql: varchar('column_default_sql', { + length: 100, + }).default('hello'), + }), + + allVarbinaries: singlestoreTable('all_varbinaries', { + simple: varbinary('simple', { length: 100 }), + columnNotNull: varbinary('column_not_null', { length: 100 }).notNull(), + columnDefault: varbinary('column_default', { length: 12 }).default( + sql`(uuid_to_bin(uuid()))`, + ), + }), + + allYears: singlestoreTable('all_years', { + simple: year('simple'), + columnNotNull: year('column_not_null').notNull(), + columnDefault: year('column_default').default(2022), + }), + + binafry: singlestoreTable('binary', { + simple: binary('simple', { length: 1 }), + columnNotNull: binary('column_not_null', { length: 1 }).notNull(), + columnDefault: binary('column_default', { length: 12 }).default( + sql`(uuid_to_bin(uuid()))`, + ), + }), + }; + + const { statements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema1, + [], + 'drizzle', + false, + ); + expect(statements.length).toBe(2); + expect(statements).toEqual([ + { + type: 'delete_unique_constraint', + tableName: 'all_small_serials', + data: 'column_all;column_all', + schema: '', + }, + { + type: 'delete_unique_constraint', + tableName: 'all_small_serials', + data: 'column_all;column_all', + schema: '', + }, + ]); + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema1, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + addBasicIndexes: function(context?: any): Promise { + return {} as any; + }, + changeIndexFields: function(context?: any): Promise { + return {} as any; + }, + dropIndex: function(context?: any): Promise { + return {} as any; + }, + indexesToBeNotTriggered: function(context?: any): Promise { + return {} as any; + }, + indexesTestCase1: function(context?: any): Promise { + return {} as any; + }, + async case1() { + // TODO: implement if needed + expect(true).toBe(true); + }, + addNotNull: function(context?: any): Promise { + return {} as any; + }, + addNotNullWithDataNoRollback: function(context?: any): Promise { + return {} as any; + }, + addBasicSequences: function(context?: any): Promise { + return {} as any; + }, + addGeneratedColumn: async function(context: any): Promise { + const schema1 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const schema2 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'stored' }, + ), + generatedName1: text('gen_name1').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'virtual' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + column: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + { + column: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + name: 'gen_name1', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + "ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); + + for (const st of sqlStatements) { + await context.client.query(st); + } + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema2, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + addGeneratedToColumn: async function(context: any): Promise { + const schema1 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name'), + generatedName1: text('gen_name1'), + }), + }; + const schema2 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'stored' }, + ), + generatedName1: text('gen_name1').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'virtual' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name1', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', + "ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); + + for (const st of sqlStatements) { + await context.client.query(st); + } + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema2, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + dropGeneratedConstraint: async function(context: any): Promise { + const schema1 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name}`, + { mode: 'stored' }, + ), + generatedName1: text('gen_name1').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name}`, + { mode: 'virtual' }, + ), + }), + }; + const schema2 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name'), + generatedName1: text('gen_name1'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + oldColumn: { + autoincrement: false, + default: undefined, + generated: { + as: '`name`', + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name1', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + oldColumn: { + autoincrement: false, + default: undefined, + generated: { + as: '`name`', + type: 'virtual', + }, + name: 'gen_name1', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', + 'ALTER TABLE `users` ADD `gen_name1` text;', + ]); + + for (const st of sqlStatements) { + await context.client.query(st); + } + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema2, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + alterGeneratedConstraint: async function(context: any): Promise { + const schema1 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name}`, + { mode: 'stored' }, + ), + generatedName1: text('gen_name1').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name}`, + { mode: 'virtual' }, + ), + }), + }; + const schema2 = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'stored' }, + ), + generatedName1: text('gen_name1').generatedAlwaysAs( + (): SQL => sql`${schema2.users.name} || 'hello'`, + { mode: 'virtual' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema2, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + createTableWithGeneratedConstraint: function(context?: any): Promise { + return {} as any; + }, +}; + +run( + singlestoreSuite, + async (context: any) => { + const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(context); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + context.client = await createConnection(connectionString); + await context.client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await context.client?.end().catch(console.error); + await context.singlestoreContainer?.stop().catch(console.error); + throw lastError; + } + }, + async (context: any) => { + await context.client?.end().catch(console.error); + await context.singlestoreContainer?.stop().catch(console.error); + }, +); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index adc7aecbf..cb1fe0cec 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -18,6 +18,7 @@ import { PgTable, PgView, } from 'drizzle-orm/pg-core'; +import { SingleStoreSchema, SingleStoreTable, SingleStoreView } from 'drizzle-orm/singlestore-core'; import { SQLiteTable, SQLiteView } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; @@ -42,22 +43,28 @@ import { Entities } from 'src/cli/validations/cli'; import { CasingType } from 'src/cli/validations/common'; import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql'; import { schemaToTypeScript } from 'src/introspect-pg'; +import { schemaToTypeScript as schemaToTypeScriptSingleStore } from 'src/introspect-singlestore'; import { schemaToTypeScript as schemaToTypeScriptSQLite } from 'src/introspect-sqlite'; import { prepareFromMySqlImports } from 'src/serializer/mysqlImports'; import { mysqlSchema, squashMysqlScheme, ViewSquashed } from 'src/serializer/mysqlSchema'; -import { generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; -import { fromDatabase as fromMySqlDatabase } from 'src/serializer/mysqlSerializer'; +import { fromDatabase as fromMySqlDatabase, generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; import { prepareFromPgImports } from 'src/serializer/pgImports'; import { pgSchema, PgSquasher, Policy, Role, squashPgScheme, View } from 'src/serializer/pgSchema'; import { fromDatabase, generatePgSnapshot } from 'src/serializer/pgSerializer'; +import { prepareFromSingleStoreImports } from 'src/serializer/singlestoreImports'; +import { singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; +import { + fromDatabase as fromSingleStoreDatabase, + generateSingleStoreSnapshot, +} from 'src/serializer/singlestoreSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; import { sqliteSchema, squashSqliteScheme, View as SqliteView } from 'src/serializer/sqliteSchema'; -import { fromDatabase as fromSqliteDatabase } from 'src/serializer/sqliteSerializer'; -import { generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; +import { fromDatabase as fromSqliteDatabase, generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; import { applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, Column, ColumnsResolverInput, @@ -82,6 +89,7 @@ export type PostgresSchema = Record< >; export type MysqlSchema = Record | MySqlSchema | MySqlView>; export type SqliteSchema = Record | SQLiteView>; +export type SinglestoreSchema = Record | SingleStoreSchema | SingleStoreView>; export const testSchemasResolver = (renames: Set) => async (input: ResolverInput): Promise> => { @@ -727,6 +735,77 @@ export const testViewsResolverMySql = } }; +export const testViewsResolverSingleStore = + (renames: Set) => + async (input: ResolverInput): Promise> => { + try { + if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } + + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; + + const result: { + created: ViewSquashed[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: ViewSquashed; to: ViewSquashed }[]; + deleted: ViewSquashed[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; + }); + + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, + }); + } + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } + } + + result.created = createdViews; + result.deleted = deletedViews; + + return result; + } catch (e) { + console.error(e); + throw e; + } + }; + export const testViewsResolverSqlite = (renames: Set) => async (input: ResolverInput): Promise> => { try { @@ -1386,6 +1465,209 @@ export const diffTestSchemasMysql = async ( return { sqlStatements, statements }; }; +export const diffTestSchemasSingleStore = async ( + left: SinglestoreSchema, + right: SinglestoreSchema, + renamesArr: string[], + cli: boolean = false, + casing?: CasingType | undefined, +) => { + const leftTables = Object.values(left).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const leftViews = Object.values(left).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + + const rightTables = Object.values(right).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const rightViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + + const serialized1 = generateSingleStoreSnapshot(leftTables, leftViews, casing); + const serialized2 = generateSingleStoreSnapshot(rightTables, rightViews, casing); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashSingleStoreScheme(sch1); + const sn2 = squashSingleStoreScheme(sch2); + + const validatedPrev = singlestoreSchema.parse(sch1); + const validatedCur = singlestoreSchema.parse(sch2); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + sn1, + sn2, + testTablesResolver(renames), + testColumnsResolver(renames), + testViewsResolverMySql(renames), + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; + } + + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + mySqlViewsResolver, + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; +}; + +export const diffTestSchemasPushSinglestore = async ( + client: Connection, + left: SingleStoreSchema, + right: SingleStoreSchema, + renamesArr: string[], + schema: string, + cli: boolean = false, + casing?: CasingType | undefined, +) => { + const { sqlStatements } = await applySingleStoreDiffs(left, casing); + for (const st of sqlStatements) { + await client.query(st); + } + // do introspect into PgSchemaInternal + const introspectedSchema = await fromSingleStoreDatabase( + { + query: async (sql: string, params?: any[]) => { + const res = await client.execute(sql, params); + return res[0] as any; + }, + }, + schema, + ); + + const leftTables = Object.values(right).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const leftViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + + const serialized2 = generateSingleStoreSnapshot(leftTables, leftViews, casing); + + const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashSingleStoreScheme(sch1); + const sn2 = squashSingleStoreScheme(sch2); + + const validatedPrev = singlestoreSchema.parse(sch1); + const validatedCur = singlestoreSchema.parse(sch2); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + sn1, + sn2, + testTablesResolver(renames), + testColumnsResolver(renames), + testViewsResolverSingleStore(renames), + validatedPrev, + validatedCur, + 'push', + ); + return { sqlStatements, statements }; + } else { + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + mySqlViewsResolver, + validatedPrev, + validatedCur, + 'push', + ); + return { sqlStatements, statements }; + } +}; + +export const applySingleStoreDiffs = async (sn: SingleStoreSchema, casing: CasingType | undefined) => { + const dryRun = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + tables: {}, + enums: {}, + schemas: {}, + _meta: { + schemas: {}, + tables: {}, + columns: {}, + }, + } as const; + + const tables = Object.values(sn).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const views = Object.values(sn).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + + const serialized1 = generateSingleStoreSnapshot(tables, views, casing); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + + const sch1 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sn1 = squashSingleStoreScheme(sch1); + + const validatedPrev = singlestoreSchema.parse(dryRun); + const validatedCur = singlestoreSchema.parse(sch1); + + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + dryRun, + sn1, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + testViewsResolverSingleStore(new Set()), + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; +}; + export const diffTestSchemasPushSqlite = async ( client: Database, left: SqliteSchema, @@ -2038,6 +2320,91 @@ export const introspectMySQLToFile = async ( }; }; +export const introspectSingleStoreToFile = async ( + client: Connection, + initSchema: SingleStoreSchema, + testName: string, + schema: string, + casing?: CasingType | undefined, +) => { + // put in db + const { sqlStatements } = await applySingleStoreDiffs(initSchema, casing); + for (const st of sqlStatements) { + await client.query(st); + } + + // introspect to schema + const introspectedSchema = await fromSingleStoreDatabase( + { + query: async (sql: string, params?: any[] | undefined) => { + const res = await client.execute(sql, params); + return res[0] as any; + }, + }, + schema, + ); + + const file = schemaToTypeScriptSingleStore(introspectedSchema, 'camel'); + + fs.writeFileSync(`tests/introspect/singlestore/${testName}.ts`, file.file); + + const response = await prepareFromSingleStoreImports([ + `tests/introspect/singlestore/${testName}.ts`, + ]); + + const afterFileImports = generateSingleStoreSnapshot(response.tables, response.views, casing); + + const { version: v2, dialect: d2, ...rest2 } = afterFileImports; + + const sch2 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn2AfterIm = squashSingleStoreScheme(sch2); + const validatedCurAfterImport = singlestoreSchema.parse(sch2); + + const leftTables = Object.values(initSchema).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const initSnapshot = generateSingleStoreSnapshot(leftTables, response.views, casing); + + const { version: initV, dialect: initD, ...initRest } = initSnapshot; + + const initSch = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashSingleStoreScheme(initSch); + const validatedCur = singlestoreSchema.parse(initSch); + + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applySingleStoreSnapshotsDiff( + sn2AfterIm, + initSn, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + testViewsResolverSingleStore(new Set()), + validatedCurAfterImport, + validatedCur, + ); + + fs.rmSync(`tests/introspect/singlestore/${testName}.ts`); + + return { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + }; +}; + export const introspectSQLiteToFile = async ( client: Database, initSchema: SqliteSchema, diff --git a/drizzle-kit/tests/singlestore-generated.test.ts b/drizzle-kit/tests/singlestore-generated.test.ts new file mode 100644 index 000000000..8944f3b21 --- /dev/null +++ b/drizzle-kit/tests/singlestore-generated.test.ts @@ -0,0 +1,1290 @@ +import { SQL, sql } from 'drizzle-orm'; +import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +test('generated as callback: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as callback: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs((): SQL => sql`${from.users.name} || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as callback: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs((): SQL => sql`${from.users.name} || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as callback: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name} || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as callback: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name} || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as callback: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as callback: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as callback: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +// --- + +test('generated as sql: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as sql: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(sql`\`users\`.\`name\` || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as sql: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(sql`\`users\`.\`name\` || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as sql: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as sql: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as sql: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as sql: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as sql: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +// --- + +test('generated as string: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as string: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(`\`users\`.\`name\` || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as string: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(`\`users\`.\`name\` || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as string: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as string: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as string: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``, { + mode: 'virtual', + }), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as string: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as string: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); diff --git a/drizzle-kit/tests/singlestore-schemas.test.ts b/drizzle-kit/tests/singlestore-schemas.test.ts new file mode 100644 index 000000000..db9fe0480 --- /dev/null +++ b/drizzle-kit/tests/singlestore-schemas.test.ts @@ -0,0 +1,155 @@ +import { singlestoreSchema, singlestoreTable } from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +// We don't manage databases(schemas) in MySQL with Drizzle Kit +test('add schema #1', async () => { + const to = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(0); +}); + +test('add schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('delete schema #1', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, {}, []); + + expect(statements.length).toBe(0); +}); + +test('delete schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('rename schema #1', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + const to = { + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev->dev2']); + + expect(statements.length).toBe(0); +}); + +test('rename schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + devSchema1: singlestoreSchema('dev1'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #1', async () => { + const dev = singlestoreSchema('dev'); + const from = {}; + const to = { + dev, + users: dev.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #2', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev }; + const to = { + dev, + users: dev.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #3', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev }; + const to = { + dev, + usersInDev: dev.table('users', {}), + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePkName: '', + compositePKs: [], + }); +}); + +test('remove table from schema #1', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev, users: dev.table('users', {}) }; + const to = { + dev, + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('remove table from schema #2', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev, users: dev.table('users', {}) }; + const to = {}; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/singlestore-views.test.ts b/drizzle-kit/tests/singlestore-views.test.ts new file mode 100644 index 000000000..70add76fc --- /dev/null +++ b/drizzle-kit/tests/singlestore-views.test.ts @@ -0,0 +1,553 @@ +import { sql } from 'drizzle-orm'; +import { int, singlestoreTable, singlestoreView } from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +test('create view #1', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: singlestoreView('some_view').as((qb) => qb.select().from(users)), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'singlestore_create_view', + name: 'some_view', + algorithm: 'undefined', + replace: false, + definition: 'select `id` from `users`', + withCheckOption: undefined, + sqlSecurity: 'definer', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE ALGORITHM = undefined +SQL SECURITY definer +VIEW \`some_view\` AS (select \`id\` from \`users\`);`); +}); + +test('create view #2', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'singlestore_create_view', + name: 'some_view', + algorithm: 'merge', + replace: false, + definition: 'SELECT * FROM \`users\`', + withCheckOption: 'cascaded', + sqlSecurity: 'definer', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS (SELECT * FROM \`users\`) +WITH cascaded CHECK OPTION;`); +}); + +test('create view with existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop view', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_view', + name: 'some_view', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`DROP VIEW \`some_view\`;`); +}); + +test('drop view with existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('rename view', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + }); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); +}); + +test('rename view and alter meta options', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'rename_view', + nameFrom: 'some_view', + nameTo: 'new_some_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'undefined', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'new_some_view', + sqlSecurity: 'definer', + type: 'alter_singlestore_view', + withCheckOption: 'cascaded', + }); + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`ALTER ALGORITHM = undefined +SQL SECURITY definer +VIEW \`new_some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('rename view with existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('add meta to view', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'merge', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_singlestore_view', + withCheckOption: 'cascaded', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('add meta to view with existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).existing(), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter meta to view', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'merge', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_singlestore_view', + withCheckOption: 'cascaded', + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = merge +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\` +WITH cascaded CHECK OPTION;`); +}); + +test('alter meta to view with existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop meta from view', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).as(sql`SELECT * FROM ${users}`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'undefined', + columns: {}, + definition: 'SELECT * FROM `users`', + isExisting: false, + name: 'some_view', + sqlSecurity: 'definer', + type: 'alter_singlestore_view', + withCheckOption: undefined, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = undefined +SQL SECURITY definer +VIEW \`some_view\` AS SELECT * FROM \`users\`;`); +}); + +test('drop meta from view existing flag', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + + view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('alter view ".as" value', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'some_view', + sqlSecurity: 'invoker', + type: 'singlestore_create_view', + withCheckOption: 'cascaded', + replace: true, + }); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe(`CREATE OR REPLACE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); + +test('rename and alter view ".as" value', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + nameFrom: 'some_view', + nameTo: 'new_some_view', + type: 'rename_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'new_some_view', + sqlSecurity: 'invoker', + type: 'singlestore_create_view', + withCheckOption: 'cascaded', + replace: true, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`CREATE OR REPLACE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`new_some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); + +test('set existing', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('drop existing', async () => { + const users = singlestoreTable('users', { + id: int('id').primaryKey().notNull(), + }); + + const from = { + users: users, + view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').existing(), + }; + const to = { + users: users, + view: singlestoreView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') + .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ + 'public.some_view->public.new_some_view', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + name: 'new_some_view', + type: 'drop_view', + }); + expect(statements[1]).toStrictEqual({ + algorithm: 'temptable', + definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', + name: 'new_some_view', + sqlSecurity: 'invoker', + type: 'singlestore_create_view', + withCheckOption: 'cascaded', + replace: false, + }); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toBe(`DROP VIEW \`new_some_view\`;`); + expect(sqlStatements[1]).toBe(`CREATE ALGORITHM = temptable +SQL SECURITY invoker +VIEW \`new_some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) +WITH cascaded CHECK OPTION;`); +}); diff --git a/drizzle-kit/tests/singlestore.test.ts b/drizzle-kit/tests/singlestore.test.ts new file mode 100644 index 000000000..63abf1755 --- /dev/null +++ b/drizzle-kit/tests/singlestore.test.ts @@ -0,0 +1,578 @@ +import { sql } from 'drizzle-orm'; +import { + index, + json, + primaryKey, + serial, + singlestoreSchema, + singlestoreTable, + text, + uniqueIndex, +} from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +test('add table #1', async () => { + const to = { + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + uniqueConstraints: [], + compositePkName: '', + }); +}); + +test('add table #2', async () => { + const to = { + users: singlestoreTable('users', { + id: serial('id').primaryKey(), + }), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [ + { + name: 'id', + notNull: true, + primaryKey: false, + type: 'serial', + autoincrement: true, + }, + ], + compositePKs: ['users_id;id'], + compositePkName: 'users_id', + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('add table #3', async () => { + const to = { + users: singlestoreTable( + 'users', + { + id: serial('id'), + }, + (t) => { + return { + pk: primaryKey({ + name: 'users_pk', + columns: [t.id], + }), + }; + }, + ), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [ + { + name: 'id', + notNull: true, + primaryKey: false, + type: 'serial', + autoincrement: true, + }, + ], + compositePKs: ['users_pk;id'], + uniqueConstraints: [], + compositePkName: 'users_pk', + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('add table #4', async () => { + const to = { + users: singlestoreTable('users', {}), + posts: singlestoreTable('posts', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_table', + tableName: 'posts', + schema: undefined, + columns: [], + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + uniqueConstraints: [], + compositePkName: '', + }); +}); + +test('add table #5', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + }; + + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('add table #6', async () => { + const from = { + users1: singlestoreTable('users1', {}), + }; + + const to = { + users2: singlestoreTable('users2', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users2', + schema: undefined, + columns: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'drop_table', + tableName: 'users1', + schema: undefined, + }); +}); + +test('add table #7', async () => { + const from = { + users1: singlestoreTable('users1', {}), + }; + + const to = { + users: singlestoreTable('users', {}), + users2: singlestoreTable('users2', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'public.users1->public.users2', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + compositePKs: [], + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'rename_table', + tableNameFrom: 'users1', + tableNameTo: 'users2', + fromSchema: undefined, + toSchema: undefined, + }); +}); + +test('add schema + table #1', async () => { + const schema = singlestoreSchema('folder'); + + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(0); +}); + +test('change schema with tables #1', async () => { + const schema = singlestoreSchema('folder'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema, + users: schema.table('users', {}), + }; + const to = { + schema2, + users: schema2.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder->folder2', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #1', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + users: singlestoreTable('users', {}), + }; + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'public.users->folder.users', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'drop_table', + tableName: 'users', + schema: undefined, + }); +}); + +test('change table schema #2', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + users: schema.table('users', {}), + }; + const to = { + schema, + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder.users->public.users', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + uniqueConstraints: [], + compositePkName: '', + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('change table schema #3', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + schema2, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, + users: schema2.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #4', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, // add schema + users: schema2.table('users', {}), // move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #5', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, // remove schema + users: schema1.table('users', {}), + }; + const to = { + schema2, // add schema + users: schema2.table('users', {}), // move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #5', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + schema2, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, + users: schema2.table('users2', {}), // rename and move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users2', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #6', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + users: schema1.table('users', {}), + }; + const to = { + schema2, // rename schema + users: schema2.table('users2', {}), // rename table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1->folder2', + 'folder2.users->folder2.users2', + ]); + + expect(statements.length).toBe(0); +}); + +test('add table #10', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({}), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT ('{}')\n);\n", + ); +}); + +test('add table #11', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default([]), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT ('[]')\n);\n", + ); +}); + +test('add table #12', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default([1, 2, 3]), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT ('[1,2,3]')\n);\n", + ); +}); + +test('add table #13', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({ key: 'value' }), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + 'CREATE TABLE `table` (\n\t`json` json DEFAULT (\'{"key":"value"}\')\n);\n', + ); +}); + +test('add table #14', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({ + key: 'value', + arr: [1, 2, 3], + }), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + 'CREATE TABLE `table` (\n\t`json` json DEFAULT (\'{"key":"value","arr":[1,2,3]}\')\n);\n', + ); +}); + +// TODO: add bson type tests + +// TODO: add blob type tests + +// TODO: add uuid type tests + +// TODO: add guid type tests + +// TODO: add vector type tests + +// TODO: add geopoint type tests + +test('drop index', async () => { + const from = { + users: singlestoreTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + idx: index('name_idx').on(t.name), + }; + }, + ), + }; + + const to = { + users: singlestoreTable('table', { + name: text('name'), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe('DROP INDEX `name_idx` ON `table`;'); +}); + +test('add table with indexes', async () => { + const from = {}; + + const to = { + users: singlestoreTable( + 'users', + { + id: serial('id').primaryKey(), + name: text('name'), + email: text('email'), + }, + (t) => ({ + uniqueExpr: uniqueIndex('uniqueExpr').on(sql`(lower(${t.email}))`), + indexExpr: index('indexExpr').on(sql`(lower(${t.email}))`), + indexExprMultiple: index('indexExprMultiple').on( + sql`(lower(${t.email}))`, + sql`(lower(${t.email}))`, + ), + + uniqueCol: uniqueIndex('uniqueCol').on(t.email), + indexCol: index('indexCol').on(t.email), + indexColMultiple: index('indexColMultiple').on(t.email, t.email), + + indexColExpr: index('indexColExpr').on( + sql`(lower(${t.email}))`, + t.email, + ), + }), + ), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements).toStrictEqual([ + `CREATE TABLE \`users\` (\n\t\`id\` serial AUTO_INCREMENT NOT NULL,\n\t\`name\` text,\n\t\`email\` text,\n\tCONSTRAINT \`users_id\` PRIMARY KEY(\`id\`),\n\tCONSTRAINT \`uniqueExpr\` UNIQUE((lower(\`email\`))),\n\tCONSTRAINT \`uniqueCol\` UNIQUE(\`email\`) +); +`, + 'CREATE INDEX `indexExpr` ON `users` ((lower(`email`)));', + 'CREATE INDEX `indexExprMultiple` ON `users` ((lower(`email`)),(lower(`email`)));', + 'CREATE INDEX `indexCol` ON `users` (`email`);', + 'CREATE INDEX `indexColMultiple` ON `users` (`email`,`email`);', + 'CREATE INDEX `indexColExpr` ON `users` ((lower(`email`)),`email`);', + ]); +}); diff --git a/drizzle-kit/tests/testsinglestore.ts b/drizzle-kit/tests/testsinglestore.ts new file mode 100644 index 000000000..1dc97d9c3 --- /dev/null +++ b/drizzle-kit/tests/testsinglestore.ts @@ -0,0 +1,29 @@ +import { index, singlestoreTable, text } from 'drizzle-orm/singlestore-core'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +const from = { + users: singlestoreTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + idx: index('name_idx').on(t.name), + }; + }, + ), +}; + +const to = { + users: singlestoreTable('table', { + name: text('name'), + }), +}; + +diffTestSchemasSingleStore(from, to, []).then((res) => { + const { statements, sqlStatements } = res; + + console.log(statements); + console.log(sqlStatements); +}); diff --git a/drizzle-kit/tests/validations.test.ts b/drizzle-kit/tests/validations.test.ts index 82731ee25..8a64603bb 100644 --- a/drizzle-kit/tests/validations.test.ts +++ b/drizzle-kit/tests/validations.test.ts @@ -1,5 +1,6 @@ import { mysqlCredentials } from 'src/cli/validations/mysql'; import { postgresCredentials } from 'src/cli/validations/postgres'; +import { singlestoreCredentials } from 'src/cli/validations/singlestore'; import { sqliteCredentials } from 'src/cli/validations/sqlite'; import { expect, test } from 'vitest'; @@ -698,3 +699,171 @@ test('mysql #17', () => { }); }).toThrowError(); }); + +test('singlestore #1', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: 'database', + host: 'host', + }), + ).toStrictEqual({ + database: 'database', + host: 'host', + }); +}); + +test('singlestore #2', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: 'database', + host: 'host', + }), + ).toStrictEqual({ + database: 'database', + host: 'host', + }); +}); + +test('singlestore #3', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + port: 1234, + user: 'user', + password: 'password', + database: 'database', + ssl: 'require', + }), + ).toStrictEqual({ + host: 'host', + port: 1234, + user: 'user', + password: 'password', + database: 'database', + ssl: 'require', + }); +}); + +test('singlestore #4', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + database: 'database', + ssl: 'allow', + }), + ).toStrictEqual({ + host: 'host', + database: 'database', + ssl: 'allow', + }); +}); + +test('singlestore #5', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + database: 'database', + ssl: { + ca: 'ca', + cert: 'cert', + }, + }), + ).toStrictEqual({ + host: 'host', + database: 'database', + ssl: { + ca: 'ca', + cert: 'cert', + }, + }); +}); + +test('singlestore #6', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + }); + }).toThrowError(); +}); + +test('singlestore #7', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + url: undefined, + }); + }).toThrowError(); +}); + +test('singlestore #8', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + url: '', + }); + }).toThrowError(); +}); + +test('singlestore #9', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: '', + database: '', + }); + }).toThrowError(); +}); + +test('singlestore #10', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: '', + }); + }).toThrowError(); +}); + +test('singlestore #11', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: '', + }); + }).toThrowError(); +}); + +test('singlestore #12', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: ' ', + host: '', + }); + }).toThrowError(); +}); + +test('singlestore #13', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: '', + host: ' ', + }); + }).toThrowError(); +}); + +test('singlestore #14', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: ' ', + host: ' ', + port: '', + }); + }).toThrowError(); +}); diff --git a/drizzle-kit/tests/wrap-param.test.ts b/drizzle-kit/tests/wrap-param.test.ts index 542998bda..a27d27d45 100644 --- a/drizzle-kit/tests/wrap-param.test.ts +++ b/drizzle-kit/tests/wrap-param.test.ts @@ -7,6 +7,9 @@ test('wrapParam', () => { expect(wrapParam('url', 'mysql://user:password@localhost:3306/database', false, 'url')).toBe( ` [${chalk.green('✓')}] url: 'mysql://user:****@localhost:3306/database'`, ); + expect(wrapParam('url', 'singlestore://user:password@localhost:3306/database', false, 'url')).toBe( + ` [${chalk.green('✓')}] url: 'singlestore://user:****@localhost:3306/database'`, + ); expect(wrapParam('url', 'postgresql://user:password@localhost:5432/database', false, 'url')).toBe( ` [${chalk.green('✓')}] url: 'postgresql://user:****@localhost:5432/database'`, ); diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index fb7da9ef6..13d9d363f 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -2,6 +2,7 @@ import { entityKind } from '~/entity.ts'; import type { Column } from './column.ts'; import type { MySqlColumn } from './mysql-core/index.ts'; import type { ExtraConfigColumn, PgColumn, PgSequenceOptions } from './pg-core/index.ts'; +import type { SingleStoreColumn } from './singlestore-core/index.ts'; import type { SQL } from './sql/sql.ts'; import type { SQLiteColumn } from './sqlite-core/index.ts'; import type { Assume, Simplify } from './utils.ts'; @@ -17,7 +18,7 @@ export type ColumnDataType = | 'custom' | 'buffer'; -export type Dialect = 'pg' | 'mysql' | 'sqlite' | 'common'; +export type Dialect = 'pg' | 'mysql' | 'sqlite' | 'singlestore' | 'common'; export type GeneratedStorageMode = 'virtual' | 'stored'; @@ -307,7 +308,8 @@ export type BuildColumn< TTableName extends string, TBuilder extends ColumnBuilderBase, TDialect extends Dialect, -> = TDialect extends 'pg' ? PgColumn> +> = TDialect extends 'singlestore' ? SingleStoreColumn> + : TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : TDialect extends 'common' ? Column> @@ -349,7 +351,8 @@ export type BuildExtraConfigColumns< & {}; export type ChangeColumnTableName = - TDialect extends 'pg' ? PgColumn> + TDialect extends 'singlestore' ? SingleStoreColumn> + : TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : never; diff --git a/drizzle-orm/src/singlestore-core/alias.ts b/drizzle-orm/src/singlestore-core/alias.ts new file mode 100644 index 000000000..08e7ecc67 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/alias.ts @@ -0,0 +1,11 @@ +import { TableAliasProxyHandler } from '~/alias.ts'; +import type { BuildAliasTable } from './query-builders/select.types.ts'; +import type { SingleStoreTable } from './table.ts'; +import type { SingleStoreViewBase } from './view-base.ts'; + +export function alias( + table: TTable, + alias: TAlias, +): BuildAliasTable { + return new Proxy(table, new TableAliasProxyHandler(alias, false)) as any; +} diff --git a/drizzle-orm/src/singlestore-core/checks.ts b/drizzle-orm/src/singlestore-core/checks.ts new file mode 100644 index 000000000..29fdb7680 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/checks.ts @@ -0,0 +1,32 @@ +import { entityKind } from '~/entity.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { SingleStoreTable } from './table.ts'; + +export class CheckBuilder { + static readonly [entityKind]: string = 'SingleStoreCheckBuilder'; + + protected brand!: 'SingleStoreConstraintBuilder'; + + constructor(public name: string, public value: SQL) {} + + /** @internal */ + build(table: SingleStoreTable): Check { + return new Check(table, this); + } +} + +export class Check { + static readonly [entityKind]: string = 'SingleStoreCheck'; + + readonly name: string; + readonly value: SQL; + + constructor(public table: SingleStoreTable, builder: CheckBuilder) { + this.name = builder.name; + this.value = builder.value; + } +} + +export function check(name: string, value: SQL): CheckBuilder { + return new CheckBuilder(name, value); +} diff --git a/drizzle-orm/src/singlestore-core/columns/all.ts b/drizzle-orm/src/singlestore-core/columns/all.ts new file mode 100644 index 000000000..66d289e3f --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/all.ts @@ -0,0 +1,55 @@ +import { bigint } from './bigint.ts'; +import { binary } from './binary.ts'; +import { boolean } from './boolean.ts'; +import { char } from './char.ts'; +import { customType } from './custom.ts'; +import { date } from './date.ts'; +import { datetime } from './datetime.ts'; +import { decimal } from './decimal.ts'; +import { double } from './double.ts'; +import { singlestoreEnum } from './enum.ts'; +import { float } from './float.ts'; +import { int } from './int.ts'; +import { json } from './json.ts'; +import { mediumint } from './mediumint.ts'; +import { real } from './real.ts'; +import { serial } from './serial.ts'; +import { smallint } from './smallint.ts'; +import { text } from './text.ts'; +import { time } from './time.ts'; +import { timestamp } from './timestamp.ts'; +import { tinyint } from './tinyint.ts'; +import { varbinary } from './varbinary.ts'; +import { varchar } from './varchar.ts'; +import { year } from './year.ts'; + +export function getSingleStoreColumnBuilders() { + return { + bigint, + binary, + boolean, + char, + customType, + date, + datetime, + decimal, + double, + singlestoreEnum, + float, + int, + json, + mediumint, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, + }; +} + +export type SingleStoreColumnBuilders = ReturnType; diff --git a/drizzle-orm/src/singlestore-core/columns/bigint.ts b/drizzle-orm/src/singlestore-core/columns/bigint.ts new file mode 100644 index 000000000..1e6b64c49 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/bigint.ts @@ -0,0 +1,120 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreBigInt53BuilderInitial = SingleStoreBigInt53Builder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreBigInt53'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBigInt53Builder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt53Builder'; + + constructor(name: T['name'], unsigned: boolean = false) { + super(name, 'number', 'SingleStoreBigInt53'); + this.config.unsigned = unsigned; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBigInt53> { + return new SingleStoreBigInt53>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBigInt53> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt53'; + + getSQLType(): string { + return `bigint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'number') { + return value; + } + return Number(value); + } +} + +export type SingleStoreBigInt64BuilderInitial = SingleStoreBigInt64Builder<{ + name: TName; + dataType: 'bigint'; + columnType: 'SingleStoreBigInt64'; + data: bigint; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBigInt64Builder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt64Builder'; + + constructor(name: T['name'], unsigned: boolean = false) { + super(name, 'bigint', 'SingleStoreBigInt64'); + this.config.unsigned = unsigned; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBigInt64> { + return new SingleStoreBigInt64>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBigInt64> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt64'; + + getSQLType(): string { + return `bigint${this.config.unsigned ? ' unsigned' : ''}`; + } + + // eslint-disable-next-line unicorn/prefer-native-coercion-functions + override mapFromDriverValue(value: string): bigint { + return BigInt(value); + } +} + +export interface SingleStoreBigIntConfig { + mode: T; + unsigned?: boolean; +} + +export function bigint( + config: SingleStoreBigIntConfig, +): TMode extends 'number' ? SingleStoreBigInt53BuilderInitial<''> : SingleStoreBigInt64BuilderInitial<''>; +export function bigint( + name: TName, + config: SingleStoreBigIntConfig, +): TMode extends 'number' ? SingleStoreBigInt53BuilderInitial : SingleStoreBigInt64BuilderInitial; +export function bigint(a?: string | SingleStoreBigIntConfig, b?: SingleStoreBigIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config.mode === 'number') { + return new SingleStoreBigInt53Builder(name, config.unsigned); + } + return new SingleStoreBigInt64Builder(name, config.unsigned); +} diff --git a/drizzle-orm/src/singlestore-core/columns/binary.ts b/drizzle-orm/src/singlestore-core/columns/binary.ts new file mode 100644 index 000000000..153456447 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/binary.ts @@ -0,0 +1,70 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreBinaryBuilderInitial = SingleStoreBinaryBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreBinary'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBinaryBuilder> + extends SingleStoreColumnBuilder< + T, + SingleStoreBinaryConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreBinaryBuilder'; + + constructor(name: T['name'], length: number | undefined) { + super(name, 'string', 'SingleStoreBinary'); + this.config.length = length; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBinary> { + return new SingleStoreBinary>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBinary> extends SingleStoreColumn< + T, + SingleStoreBinaryConfig +> { + static override readonly [entityKind]: string = 'SingleStoreBinary'; + + length: number | undefined = this.config.length; + + getSQLType(): string { + return this.length === undefined ? `binary` : `binary(${this.length})`; + } +} + +export interface SingleStoreBinaryConfig { + length?: number; +} + +export function binary(): SingleStoreBinaryBuilderInitial<''>; +export function binary( + config?: SingleStoreBinaryConfig, +): SingleStoreBinaryBuilderInitial<''>; +export function binary( + name: TName, + config?: SingleStoreBinaryConfig, +): SingleStoreBinaryBuilderInitial; +export function binary(a?: string | SingleStoreBinaryConfig, b: SingleStoreBinaryConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreBinaryBuilder(name, config.length); +} diff --git a/drizzle-orm/src/singlestore-core/columns/boolean.ts b/drizzle-orm/src/singlestore-core/columns/boolean.ts new file mode 100644 index 000000000..bf48ff1da --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/boolean.ts @@ -0,0 +1,58 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreBooleanBuilderInitial = SingleStoreBooleanBuilder<{ + name: TName; + dataType: 'boolean'; + columnType: 'SingleStoreBoolean'; + data: boolean; + driverParam: number | boolean; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBooleanBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreBooleanBuilder'; + + constructor(name: T['name']) { + super(name, 'boolean', 'SingleStoreBoolean'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBoolean> { + return new SingleStoreBoolean>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBoolean> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreBoolean'; + + getSQLType(): string { + return 'boolean'; + } + + override mapFromDriverValue(value: number | boolean): boolean { + if (typeof value === 'boolean') { + return value; + } + return value === 1; + } +} + +export function boolean(): SingleStoreBooleanBuilderInitial<''>; +export function boolean(name: TName): SingleStoreBooleanBuilderInitial; +export function boolean(name?: string) { + return new SingleStoreBooleanBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/char.ts b/drizzle-orm/src/singlestore-core/columns/char.ts new file mode 100644 index 000000000..512460f92 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/char.ts @@ -0,0 +1,75 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreCharBuilderInitial = + SingleStoreCharBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; + }>; + +export class SingleStoreCharBuilder> + extends SingleStoreColumnBuilder< + T, + SingleStoreCharConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreCharBuilder'; + + constructor(name: T['name'], config: SingleStoreCharConfig) { + super(name, 'string', 'SingleStoreChar'); + this.config.length = config.length; + this.config.enum = config.enum; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreChar & { enumValues: T['enumValues'] }> { + return new SingleStoreChar & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreChar> + extends SingleStoreColumn> +{ + static override readonly [entityKind]: string = 'SingleStoreChar'; + + readonly length: number | undefined = this.config.length; + override readonly enumValues = this.config.enum; + + getSQLType(): string { + return this.length === undefined ? `char` : `char(${this.length})`; + } +} + +export interface SingleStoreCharConfig< + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, +> { + length?: number; + enum?: TEnum; +} + +export function char(): SingleStoreCharBuilderInitial<'', [string, ...string[]]>; +export function char>( + config?: SingleStoreCharConfig>, +): SingleStoreCharBuilderInitial<'', Writable>; +export function char>( + name: TName, + config?: SingleStoreCharConfig>, +): SingleStoreCharBuilderInitial>; +export function char(a?: string | SingleStoreCharConfig, b: SingleStoreCharConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreCharBuilder(name, config as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts new file mode 100644 index 000000000..63a6dbf29 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -0,0 +1,116 @@ +import { ColumnBuilder } from '~/column-builder.ts'; +import type { + ColumnBuilderBase, + ColumnBuilderBaseConfig, + ColumnBuilderExtraConfig, + ColumnBuilderRuntimeConfig, + ColumnDataType, + HasDefault, + HasGenerated, + IsAutoincrement, + MakeColumnConfig, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { Column } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable, SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { Update } from '~/utils.ts'; +import { uniqueKeyName } from '../unique-constraint.ts'; + +export interface SingleStoreColumnBuilderBase< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, + TTypeConfig extends object = object, +> extends ColumnBuilderBase {} + +export interface SingleStoreGeneratedColumnConfig { + mode?: 'virtual' | 'stored'; +} + +export abstract class SingleStoreColumnBuilder< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig & { + data: any; + }, + TRuntimeConfig extends object = object, + TTypeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends ColumnBuilder + implements SingleStoreColumnBuilderBase +{ + static override readonly [entityKind]: string = 'SingleStoreColumnBuilder'; + + unique(name?: string): this { + this.config.isUnique = true; + this.config.uniqueName = name; + return this; + } + + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SingleStoreGeneratedColumnConfig): HasGenerated { + this.config.generated = { + as, + type: 'always', + mode: config?.mode ?? 'virtual', + }; + return this as any; + } + + /** @internal */ + abstract build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreColumn>; +} + +// To understand how to use `SingleStoreColumn` and `AnySingleStoreColumn`, see `Column` and `AnyColumn` documentation. +export abstract class SingleStoreColumn< + T extends ColumnBaseConfig = ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends Column { + static override readonly [entityKind]: string = 'SingleStoreColumn'; + + constructor( + override readonly table: SingleStoreTable, + config: ColumnBuilderRuntimeConfig, + ) { + if (!config.uniqueName) { + config.uniqueName = uniqueKeyName(table, [config.name]); + } + super(table, config); + } +} + +export type AnySingleStoreColumn> = {}> = + SingleStoreColumn< + Required, TPartial>> + >; + +export interface SingleStoreColumnWithAutoIncrementConfig { + autoIncrement: boolean; +} + +export abstract class SingleStoreColumnBuilderWithAutoIncrement< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, + TRuntimeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends SingleStoreColumnBuilder { + static override readonly [entityKind]: string = 'SingleStoreColumnBuilderWithAutoIncrement'; + + constructor(name: NonNullable, dataType: T['dataType'], columnType: T['columnType']) { + super(name, dataType, columnType); + this.config.autoIncrement = false; + } + + autoincrement(): IsAutoincrement> { + this.config.autoIncrement = true; + this.config.hasDefault = true; + return this as IsAutoincrement>; + } +} + +export abstract class SingleStoreColumnWithAutoIncrement< + T extends ColumnBaseConfig = ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreColumnWithAutoIncrement'; + + readonly autoIncrement: boolean = this.config.autoIncrement; +} diff --git a/drizzle-orm/src/singlestore-core/columns/custom.ts b/drizzle-orm/src/singlestore-core/columns/custom.ts new file mode 100644 index 000000000..964e077d7 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/custom.ts @@ -0,0 +1,235 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/sql.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type ConvertCustomConfig> = + & { + name: TName; + dataType: 'custom'; + columnType: 'SingleStoreCustomColumn'; + data: T['data']; + driverParam: T['driverData']; + enumValues: undefined; + generated: undefined; + } + & (T['notNull'] extends true ? { notNull: true } : {}) + & (T['default'] extends true ? { hasDefault: true } : {}); + +export interface SingleStoreCustomColumnInnerConfig { + customTypeValues: CustomTypeValues; +} + +export class SingleStoreCustomColumnBuilder> + extends SingleStoreColumnBuilder< + T, + { + fieldConfig: CustomTypeValues['config']; + customTypeParams: CustomTypeParams; + }, + { + singlestoreColumnBuilderBrand: 'SingleStoreCustomColumnBuilderBrand'; + } + > +{ + static override readonly [entityKind]: string = 'SingleStoreCustomColumnBuilder'; + + constructor( + name: T['name'], + fieldConfig: CustomTypeValues['config'], + customTypeParams: CustomTypeParams, + ) { + super(name, 'custom', 'SingleStoreCustomColumn'); + this.config.fieldConfig = fieldConfig; + this.config.customTypeParams = customTypeParams; + } + + /** @internal */ + build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreCustomColumn> { + return new SingleStoreCustomColumn>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreCustomColumn> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreCustomColumn'; + + private sqlName: string; + private mapTo?: (value: T['data']) => T['driverParam']; + private mapFrom?: (value: T['driverParam']) => T['data']; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreCustomColumnBuilder['config'], + ) { + super(table, config); + this.sqlName = config.customTypeParams.dataType(config.fieldConfig); + this.mapTo = config.customTypeParams.toDriver; + this.mapFrom = config.customTypeParams.fromDriver; + } + + getSQLType(): string { + return this.sqlName; + } + + override mapFromDriverValue(value: T['driverParam']): T['data'] { + return typeof this.mapFrom === 'function' ? this.mapFrom(value) : value as T['data']; + } + + override mapToDriverValue(value: T['data']): T['driverParam'] { + return typeof this.mapTo === 'function' ? this.mapTo(value) : value as T['data']; + } +} + +export type CustomTypeValues = { + /** + * Required type for custom column, that will infer proper type model + * + * Examples: + * + * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar` + * + * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer` + */ + data: unknown; + + /** + * Type helper, that represents what type database driver is accepting for specific database data type + */ + driverData?: unknown; + + /** + * What config type should be used for {@link CustomTypeParams} `dataType` generation + */ + config?: Record; + + /** + * Whether the config argument should be required or not + * @default false + */ + configRequired?: boolean; + + /** + * If your custom data type should be notNull by default you can use `notNull: true` + * + * @example + * const customSerial = customType<{ data: number, notNull: true, default: true }>({ + * dataType() { + * return 'serial'; + * }, + * }); + */ + notNull?: boolean; + + /** + * If your custom data type has default you can use `default: true` + * + * @example + * const customSerial = customType<{ data: number, notNull: true, default: true }>({ + * dataType() { + * return 'serial'; + * }, + * }); + */ + default?: boolean; +}; + +export interface CustomTypeParams { + /** + * Database data type string representation, that is used for migrations + * @example + * ``` + * `jsonb`, `text` + * ``` + * + * If database data type needs additional params you can use them from `config` param + * @example + * ``` + * `varchar(256)`, `numeric(2,3)` + * ``` + * + * To make `config` be of specific type please use config generic in {@link CustomTypeValues} + * + * @example + * Usage example + * ``` + * dataType() { + * return 'boolean'; + * }, + * ``` + * Or + * ``` + * dataType(config) { + * return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`; + * } + * ``` + */ + dataType: (config: T['config'] | (Equal extends true ? never : undefined)) => string; + + /** + * Optional mapping function, between user input and driver + * @example + * For example, when using jsonb we need to map JS/TS object to string before writing to database + * ``` + * toDriver(value: TData): string { + * return JSON.stringify(value); + * } + * ``` + */ + toDriver?: (value: T['data']) => T['driverData'] | SQL; + + /** + * Optional mapping function, that is responsible for data mapping from database to JS/TS code + * @example + * For example, when using timestamp we need to map string Date representation to JS Date + * ``` + * fromDriver(value: string): Date { + * return new Date(value); + * }, + * ``` + */ + fromDriver?: (value: T['driverData']) => T['data']; +} + +/** + * Custom singlestore database data type generator + */ +export function customType( + customTypeParams: CustomTypeParams, +): Equal extends true ? { + & T['config']>( + fieldConfig: TConfig, + ): SingleStoreCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig: T['config'], + ): SingleStoreCustomColumnBuilder>; + } + : { + (): SingleStoreCustomColumnBuilder>; + & T['config']>( + fieldConfig?: TConfig, + ): SingleStoreCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig?: T['config'], + ): SingleStoreCustomColumnBuilder>; + } +{ + return ( + a?: TName | T['config'], + b?: T['config'], + ): SingleStoreCustomColumnBuilder> => { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreCustomColumnBuilder(name as ConvertCustomConfig['name'], config, customTypeParams); + }; +} diff --git a/drizzle-orm/src/singlestore-core/columns/date.common.ts b/drizzle-orm/src/singlestore-core/columns/date.common.ts new file mode 100644 index 000000000..8afac71d0 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/date.common.ts @@ -0,0 +1,41 @@ +import type { + ColumnBuilderBaseConfig, + ColumnBuilderExtraConfig, + ColumnDataType, + HasDefault, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import { sql } from '~/sql/sql.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export interface SingleStoreDateColumnBaseConfig { + hasOnUpdateNow: boolean; +} + +export abstract class SingleStoreDateColumnBaseBuilder< + T extends ColumnBuilderBaseConfig, + TRuntimeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends SingleStoreColumnBuilder { + static override readonly [entityKind]: string = 'SingleStoreDateColumnBuilder'; + + defaultNow() { + return this.default(sql`(now())`); + } + + onUpdateNow(): HasDefault { + this.config.hasOnUpdateNow = true; + this.config.hasDefault = true; + return this as HasDefault; + } +} + +export abstract class SingleStoreDateBaseColumn< + T extends ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreDateColumn'; + + readonly hasOnUpdateNow: boolean = this.config.hasOnUpdateNow; +} diff --git a/drizzle-orm/src/singlestore-core/columns/date.ts b/drizzle-orm/src/singlestore-core/columns/date.ts new file mode 100644 index 000000000..70da74f3a --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/date.ts @@ -0,0 +1,123 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreDateBuilderInitial = SingleStoreDateBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'SingleStoreDate'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreDateBuilder'; + + constructor(name: T['name']) { + super(name, 'date', 'SingleStoreDate'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDate> { + return new SingleStoreDate>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDate> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreDate'; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return `date`; + } + + override mapFromDriverValue(value: string): Date { + return new Date(value); + } +} + +export type SingleStoreDateStringBuilderInitial = SingleStoreDateStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreDateString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateStringBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreDateStringBuilder'; + + constructor(name: T['name']) { + super(name, 'string', 'SingleStoreDateString'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateString> { + return new SingleStoreDateString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDateString> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreDateString'; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateStringBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return `date`; + } +} + +export interface SingleStoreDateConfig { + mode?: TMode; +} + +export function date(): SingleStoreDateBuilderInitial<''>; +export function date( + config?: SingleStoreDateConfig, +): Equal extends true ? SingleStoreDateStringBuilderInitial<''> : SingleStoreDateBuilderInitial<''>; +export function date( + name: TName, + config?: SingleStoreDateConfig, +): Equal extends true ? SingleStoreDateStringBuilderInitial + : SingleStoreDateBuilderInitial; +export function date(a?: string | SingleStoreDateConfig, b?: SingleStoreDateConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config?.mode === 'string') { + return new SingleStoreDateStringBuilder(name); + } + return new SingleStoreDateBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts new file mode 100644 index 000000000..aaaa11708 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -0,0 +1,143 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreDateTimeBuilderInitial = SingleStoreDateTimeBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'SingleStoreDateTime'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateTimeBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreDateTimeBuilder'; + + constructor(name: T['name'], config: SingleStoreDatetimeConfig | undefined) { + super(name, 'date', 'SingleStoreDateTime'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateTime> { + return new SingleStoreDateTime>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDateTime> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreDateTime'; + + readonly fsp: number | undefined; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateTimeBuilder['config'], + ) { + super(table, config); + this.fsp = config.fsp; + } + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `datetime${precision}`; + } + + override mapToDriverValue(value: Date): unknown { + return value.toISOString().replace('T', ' ').replace('Z', ''); + } + + override mapFromDriverValue(value: string): Date { + return new Date(value.replace(' ', 'T') + 'Z'); + } +} + +export type SingleStoreDateTimeStringBuilderInitial = SingleStoreDateTimeStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreDateTimeString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateTimeStringBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreDateTimeStringBuilder'; + + constructor(name: T['name'], config: SingleStoreDatetimeConfig | undefined) { + super(name, 'string', 'SingleStoreDateTimeString'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateTimeString> { + return new SingleStoreDateTimeString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDateTimeString> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreDateTimeString'; + + readonly fsp: number | undefined; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateTimeStringBuilder['config'], + ) { + super(table, config); + this.fsp = config.fsp; + } + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `datetime${precision}`; + } +} + +export type DatetimeFsp = 0 | 1 | 2 | 3 | 4 | 5 | 6; + +export interface SingleStoreDatetimeConfig { + mode?: TMode; + fsp?: DatetimeFsp; +} + +export function datetime(): SingleStoreDateTimeBuilderInitial<''>; +export function datetime( + config?: SingleStoreDatetimeConfig, +): Equal extends true ? SingleStoreDateTimeStringBuilderInitial<''> + : SingleStoreDateTimeBuilderInitial<''>; +export function datetime( + name: TName, + config?: SingleStoreDatetimeConfig, +): Equal extends true ? SingleStoreDateTimeStringBuilderInitial + : SingleStoreDateTimeBuilderInitial; +export function datetime(a?: string | SingleStoreDatetimeConfig, b?: SingleStoreDatetimeConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config?.mode === 'string') { + return new SingleStoreDateTimeStringBuilder(name, config); + } + return new SingleStoreDateTimeBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts new file mode 100644 index 000000000..112ca86ee --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -0,0 +1,75 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreDecimalBuilderInitial = SingleStoreDecimalBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreDecimal'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDecimalBuilder< + T extends ColumnBuilderBaseConfig<'string', 'SingleStoreDecimal'>, +> extends SingleStoreColumnBuilderWithAutoIncrement { + static override readonly [entityKind]: string = 'SingleStoreDecimalBuilder'; + + constructor(name: T['name'], precision?: number, scale?: number) { + super(name, 'string', 'SingleStoreDecimal'); + this.config.precision = precision; + this.config.scale = scale; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDecimal> { + return new SingleStoreDecimal>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDecimal> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreDecimal'; + + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + + getSQLType(): string { + if (this.precision !== undefined && this.scale !== undefined) { + return `decimal(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + return 'decimal'; + } else { + return `decimal(${this.precision})`; + } + } +} + +export interface SingleStoreDecimalConfig { + precision?: number; + scale?: number; +} + +export function decimal(): SingleStoreDecimalBuilderInitial<''>; +export function decimal( + config: SingleStoreDecimalConfig, +): SingleStoreDecimalBuilderInitial<''>; +export function decimal( + name: TName, + config?: SingleStoreDecimalConfig, +): SingleStoreDecimalBuilderInitial; +export function decimal(a?: string | SingleStoreDecimalConfig, b: SingleStoreDecimalConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreDecimalBuilder(name, config.precision, config.scale); +} diff --git a/drizzle-orm/src/singlestore-core/columns/double.ts b/drizzle-orm/src/singlestore-core/columns/double.ts new file mode 100644 index 000000000..6335b5937 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/double.ts @@ -0,0 +1,75 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreDoubleBuilderInitial = SingleStoreDoubleBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreDouble'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDoubleBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreDoubleBuilder'; + + constructor(name: T['name'], config: SingleStoreDoubleConfig | undefined) { + super(name, 'number', 'SingleStoreDouble'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDouble> { + return new SingleStoreDouble>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDouble> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreDouble'; + + precision: number | undefined = this.config.precision; + scale: number | undefined = this.config.scale; + + getSQLType(): string { + if (this.precision !== undefined && this.scale !== undefined) { + return `double(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + return 'double'; + } else { + return `double(${this.precision})`; + } + } +} + +export interface SingleStoreDoubleConfig { + precision?: number; + scale?: number; +} + +export function double(): SingleStoreDoubleBuilderInitial<''>; +export function double( + config?: SingleStoreDoubleConfig, +): SingleStoreDoubleBuilderInitial<''>; +export function double( + name: TName, + config?: SingleStoreDoubleConfig, +): SingleStoreDoubleBuilderInitial; +export function double(a?: string | SingleStoreDoubleConfig, b?: SingleStoreDoubleConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreDoubleBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/enum.ts b/drizzle-orm/src/singlestore-core/columns/enum.ts new file mode 100644 index 000000000..00b61393e --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/enum.ts @@ -0,0 +1,70 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreEnumColumnBuilderInitial = + SingleStoreEnumColumnBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreEnumColumn'; + data: TEnum[number]; + driverParam: string; + enumValues: TEnum; + generated: undefined; + }>; + +export class SingleStoreEnumColumnBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreEnumColumnBuilder'; + + constructor(name: T['name'], values: T['enumValues']) { + super(name, 'string', 'SingleStoreEnumColumn'); + this.config.enumValues = values; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreEnumColumn & { enumValues: T['enumValues'] }> { + return new SingleStoreEnumColumn & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreEnumColumn> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreEnumColumn'; + + override readonly enumValues = this.config.enumValues; + + getSQLType(): string { + return `enum(${this.enumValues!.map((value) => `'${value}'`).join(',')})`; + } +} + +export function singlestoreEnum>( + values: T | Writable, +): SingleStoreEnumColumnBuilderInitial<'', Writable>; +export function singlestoreEnum>( + name: TName, + values: T | Writable, +): SingleStoreEnumColumnBuilderInitial>; +export function singlestoreEnum( + a?: string | readonly [string, ...string[]] | [string, ...string[]], + b?: readonly [string, ...string[]] | [string, ...string[]], +): any { + const { name, config: values } = getColumnNameAndConfig(a, b); + + if (values.length === 0) { + throw new Error(`You have an empty array for "${name}" enum values`); + } + + return new SingleStoreEnumColumnBuilder(name, values as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts new file mode 100644 index 000000000..07a685170 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -0,0 +1,51 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreFloatBuilderInitial = SingleStoreFloatBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreFloat'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreFloatBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreFloatBuilder'; + + constructor(name: T['name']) { + super(name, 'number', 'SingleStoreFloat'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreFloat> { + return new SingleStoreFloat>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreFloat> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreFloat'; + + getSQLType(): string { + return 'float'; + } +} + +export function float(): SingleStoreFloatBuilderInitial<''>; +export function float(name: TName): SingleStoreFloatBuilderInitial; +export function float(name?: string) { + return new SingleStoreFloatBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/index.ts b/drizzle-orm/src/singlestore-core/columns/index.ts new file mode 100644 index 000000000..b51f0fac4 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/index.ts @@ -0,0 +1,25 @@ +export * from './bigint.ts'; +export * from './binary.ts'; +export * from './boolean.ts'; +export * from './char.ts'; +export * from './common.ts'; +export * from './custom.ts'; +export * from './date.ts'; +export * from './datetime.ts'; +export * from './decimal.ts'; +export * from './double.ts'; +export * from './enum.ts'; +export * from './float.ts'; +export * from './int.ts'; +export * from './json.ts'; +export * from './mediumint.ts'; +export * from './real.ts'; +export * from './serial.ts'; +export * from './smallint.ts'; +export * from './text.ts'; +export * from './time.ts'; +export * from './timestamp.ts'; +export * from './tinyint.ts'; +export * from './varbinary.ts'; +export * from './varchar.ts'; +export * from './year.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/int.ts b/drizzle-orm/src/singlestore-core/columns/int.ts new file mode 100644 index 000000000..b6a661f66 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/int.ts @@ -0,0 +1,71 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreIntBuilderInitial = SingleStoreIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreInt> { + return new SingleStoreInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreInt'; + + getSQLType(): string { + return `int${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export interface SingleStoreIntConfig { + unsigned?: boolean; +} + +export function int(): SingleStoreIntBuilderInitial<''>; +export function int( + config?: SingleStoreIntConfig, +): SingleStoreIntBuilderInitial<''>; +export function int( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreIntBuilderInitial; +export function int(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/json.ts b/drizzle-orm/src/singlestore-core/columns/json.ts new file mode 100644 index 000000000..97ff759d1 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/json.ts @@ -0,0 +1,53 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreJsonBuilderInitial = SingleStoreJsonBuilder<{ + name: TName; + dataType: 'json'; + columnType: 'SingleStoreJson'; + data: unknown; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreJsonBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreJsonBuilder'; + + constructor(name: T['name']) { + super(name, 'json', 'SingleStoreJson'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreJson> { + return new SingleStoreJson>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreJson> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreJson'; + + getSQLType(): string { + return 'json'; + } + + override mapToDriverValue(value: T['data']): string { + return JSON.stringify(value); + } +} + +export function json(): SingleStoreJsonBuilderInitial<''>; +export function json(name: TName): SingleStoreJsonBuilderInitial; +export function json(name?: string) { + return new SingleStoreJsonBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/mediumint.ts b/drizzle-orm/src/singlestore-core/columns/mediumint.ts new file mode 100644 index 000000000..4a5fa80f9 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/mediumint.ts @@ -0,0 +1,68 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; + +export type SingleStoreMediumIntBuilderInitial = SingleStoreMediumIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreMediumInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreMediumIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreMediumIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreMediumInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreMediumInt> { + return new SingleStoreMediumInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreMediumInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreMediumInt'; + + getSQLType(): string { + return `mediumint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function mediumint(): SingleStoreMediumIntBuilderInitial<''>; +export function mediumint( + config?: SingleStoreIntConfig, +): SingleStoreMediumIntBuilderInitial<''>; +export function mediumint( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreMediumIntBuilderInitial; +export function mediumint(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreMediumIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/real.ts b/drizzle-orm/src/singlestore-core/columns/real.ts new file mode 100644 index 000000000..53d15345c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/real.ts @@ -0,0 +1,81 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreRealBuilderInitial = SingleStoreRealBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreReal'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreRealBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement< + T, + SingleStoreRealConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreRealBuilder'; + + constructor(name: T['name'], config: SingleStoreRealConfig | undefined) { + super(name, 'number', 'SingleStoreReal'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreReal> { + return new SingleStoreReal>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreReal> + extends SingleStoreColumnWithAutoIncrement< + T, + SingleStoreRealConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreReal'; + + precision: number | undefined = this.config.precision; + scale: number | undefined = this.config.scale; + + getSQLType(): string { + if (this.precision !== undefined && this.scale !== undefined) { + return `real(${this.precision}, ${this.scale})`; + } else if (this.precision === undefined) { + return 'real'; + } else { + return `real(${this.precision})`; + } + } +} + +export interface SingleStoreRealConfig { + precision?: number; + scale?: number; +} + +export function real(): SingleStoreRealBuilderInitial<''>; +export function real( + config?: SingleStoreRealConfig, +): SingleStoreRealBuilderInitial<''>; +export function real( + name: TName, + config?: SingleStoreRealConfig, +): SingleStoreRealBuilderInitial; +export function real(a?: string | SingleStoreRealConfig, b: SingleStoreRealConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreRealBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/serial.ts b/drizzle-orm/src/singlestore-core/columns/serial.ts new file mode 100644 index 000000000..df415d47e --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/serial.ts @@ -0,0 +1,76 @@ +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + HasDefault, + IsAutoincrement, + IsPrimaryKey, + MakeColumnConfig, + NotNull, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreSerialBuilderInitial = IsAutoincrement< + IsPrimaryKey< + NotNull< + HasDefault< + SingleStoreSerialBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + enumValues: undefined; + generated: undefined; + }> + > + > + > +>; + +export class SingleStoreSerialBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreSerialBuilder'; + + constructor(name: T['name']) { + super(name, 'number', 'SingleStoreSerial'); + this.config.hasDefault = true; + this.config.autoIncrement = true; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreSerial> { + return new SingleStoreSerial>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreSerial< + T extends ColumnBaseConfig<'number', 'SingleStoreSerial'>, +> extends SingleStoreColumnWithAutoIncrement { + static override readonly [entityKind]: string = 'SingleStoreSerial'; + + getSQLType(): string { + return 'serial'; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function serial(): SingleStoreSerialBuilderInitial<''>; +export function serial(name: TName): SingleStoreSerialBuilderInitial; +export function serial(name?: string) { + return new SingleStoreSerialBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/smallint.ts b/drizzle-orm/src/singlestore-core/columns/smallint.ts new file mode 100644 index 000000000..3f504b68c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/smallint.ts @@ -0,0 +1,68 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; + +export type SingleStoreSmallIntBuilderInitial = SingleStoreSmallIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreSmallInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreSmallIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreSmallIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreSmallInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreSmallInt> { + return new SingleStoreSmallInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreSmallInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreSmallInt'; + + getSQLType(): string { + return `smallint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function smallint(): SingleStoreSmallIntBuilderInitial<''>; +export function smallint( + config?: SingleStoreIntConfig, +): SingleStoreSmallIntBuilderInitial<''>; +export function smallint( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreSmallIntBuilderInitial; +export function smallint(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreSmallIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/text.ts b/drizzle-orm/src/singlestore-core/columns/text.ts new file mode 100644 index 000000000..425da550f --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/text.ts @@ -0,0 +1,116 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreTextColumnType = 'tinytext' | 'text' | 'mediumtext' | 'longtext'; + +export type SingleStoreTextBuilderInitial = + SingleStoreTextBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreText'; + data: TEnum[number]; + driverParam: string; + enumValues: TEnum; + generated: undefined; + }>; + +export class SingleStoreTextBuilder> + extends SingleStoreColumnBuilder< + T, + { textType: SingleStoreTextColumnType; enumValues: T['enumValues'] } + > +{ + static override readonly [entityKind]: string = 'SingleStoreTextBuilder'; + + constructor(name: T['name'], textType: SingleStoreTextColumnType, config: SingleStoreTextConfig) { + super(name, 'string', 'SingleStoreText'); + this.config.textType = textType; + this.config.enumValues = config.enum; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreText> { + return new SingleStoreText>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreText> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreText'; + + private textType: SingleStoreTextColumnType = this.config.textType; + + override readonly enumValues = this.config.enumValues; + + getSQLType(): string { + return this.textType; + } +} + +export interface SingleStoreTextConfig< + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, +> { + enum?: TEnum; +} + +export function text(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function text>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function text>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function text(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'text', config as any); +} + +export function tinytext(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function tinytext>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function tinytext>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function tinytext(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'tinytext', config as any); +} + +export function mediumtext(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function mediumtext>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function mediumtext>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function mediumtext(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'mediumtext', config as any); +} + +export function longtext(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function longtext>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function longtext>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function longtext(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'longtext', config as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/time.ts b/drizzle-orm/src/singlestore-core/columns/time.ts new file mode 100644 index 000000000..be43041a7 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/time.ts @@ -0,0 +1,73 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreTimeBuilderInitial = SingleStoreTimeBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreTime'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTimeBuilder> + extends SingleStoreColumnBuilder< + T, + TimeConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreTimeBuilder'; + + constructor( + name: T['name'], + config: TimeConfig | undefined, + ) { + super(name, 'string', 'SingleStoreTime'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTime> { + return new SingleStoreTime>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreTime< + T extends ColumnBaseConfig<'string', 'SingleStoreTime'>, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreTime'; + + readonly fsp: number | undefined = this.config.fsp; + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `time${precision}`; + } +} + +export type TimeConfig = { + fsp?: 0 | 1 | 2 | 3 | 4 | 5 | 6; +}; + +export function time(): SingleStoreTimeBuilderInitial<''>; +export function time( + config?: TimeConfig, +): SingleStoreTimeBuilderInitial<''>; +export function time( + name: TName, + config?: TimeConfig, +): SingleStoreTimeBuilderInitial; +export function time(a?: string | TimeConfig, b?: TimeConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTimeBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts new file mode 100644 index 000000000..747fb44bf --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -0,0 +1,127 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreDateBaseColumn, SingleStoreDateColumnBaseBuilder } from './date.common.ts'; + +export type SingleStoreTimestampBuilderInitial = SingleStoreTimestampBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'SingleStoreTimestamp'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTimestampBuilder> + extends SingleStoreDateColumnBaseBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreTimestampBuilder'; + + constructor(name: T['name'], config: SingleStoreTimestampConfig | undefined) { + super(name, 'date', 'SingleStoreTimestamp'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTimestamp> { + return new SingleStoreTimestamp>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreTimestamp> + extends SingleStoreDateBaseColumn +{ + static override readonly [entityKind]: string = 'SingleStoreTimestamp'; + + readonly fsp: number | undefined = this.config.fsp; + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `timestamp${precision}`; + } + + override mapFromDriverValue(value: string): Date { + return new Date(value + '+0000'); + } + + override mapToDriverValue(value: Date): string { + return value.toISOString().slice(0, -1).replace('T', ' '); + } +} + +export type SingleStoreTimestampStringBuilderInitial = SingleStoreTimestampStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreTimestampString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTimestampStringBuilder< + T extends ColumnBuilderBaseConfig<'string', 'SingleStoreTimestampString'>, +> extends SingleStoreDateColumnBaseBuilder { + static override readonly [entityKind]: string = 'SingleStoreTimestampStringBuilder'; + + constructor(name: T['name'], config: SingleStoreTimestampConfig | undefined) { + super(name, 'string', 'SingleStoreTimestampString'); + this.config.fsp = config?.fsp; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTimestampString> { + return new SingleStoreTimestampString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreTimestampString> + extends SingleStoreDateBaseColumn +{ + static override readonly [entityKind]: string = 'SingleStoreTimestampString'; + + readonly fsp: number | undefined = this.config.fsp; + + getSQLType(): string { + const precision = this.fsp === undefined ? '' : `(${this.fsp})`; + return `timestamp${precision}`; + } +} + +export type TimestampFsp = 0 | 1 | 2 | 3 | 4 | 5 | 6; + +export interface SingleStoreTimestampConfig { + mode?: TMode; + fsp?: TimestampFsp; +} + +export function timestamp(): SingleStoreTimestampBuilderInitial<''>; +export function timestamp( + config?: SingleStoreTimestampConfig, +): Equal extends true ? SingleStoreTimestampStringBuilderInitial<''> + : SingleStoreTimestampBuilderInitial<''>; +export function timestamp( + name: TName, + config?: SingleStoreTimestampConfig, +): Equal extends true ? SingleStoreTimestampStringBuilderInitial + : SingleStoreTimestampBuilderInitial; +export function timestamp(a?: string | SingleStoreTimestampConfig, b: SingleStoreTimestampConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config?.mode === 'string') { + return new SingleStoreTimestampStringBuilder(name, config); + } + return new SingleStoreTimestampBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/tinyint.ts b/drizzle-orm/src/singlestore-core/columns/tinyint.ts new file mode 100644 index 000000000..090619a6d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/tinyint.ts @@ -0,0 +1,68 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; + +export type SingleStoreTinyIntBuilderInitial = SingleStoreTinyIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreTinyInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTinyIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreTinyIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreTinyInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTinyInt> { + return new SingleStoreTinyInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreTinyInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreTinyInt'; + + getSQLType(): string { + return `tinyint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function tinyint(): SingleStoreTinyIntBuilderInitial<''>; +export function tinyint( + config?: SingleStoreIntConfig, +): SingleStoreTinyIntBuilderInitial<''>; +export function tinyint( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreTinyIntBuilderInitial; +export function tinyint(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTinyIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/varbinary.ts b/drizzle-orm/src/singlestore-core/columns/varbinary.ts new file mode 100644 index 000000000..c55aa8071 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/varbinary.ts @@ -0,0 +1,66 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreVarBinaryBuilderInitial = SingleStoreVarBinaryBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreVarBinary'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreVarBinaryBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreVarBinaryBuilder'; + + /** @internal */ + constructor(name: T['name'], config: SingleStoreVarbinaryOptions) { + super(name, 'string', 'SingleStoreVarBinary'); + this.config.length = config?.length; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreVarBinary> { + return new SingleStoreVarBinary>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreVarBinary< + T extends ColumnBaseConfig<'string', 'SingleStoreVarBinary'>, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreVarBinary'; + + length: number | undefined = this.config.length; + + getSQLType(): string { + return this.length === undefined ? `varbinary` : `varbinary(${this.length})`; + } +} + +export interface SingleStoreVarbinaryOptions { + length: number; +} + +export function varbinary( + config: SingleStoreVarbinaryOptions, +): SingleStoreVarBinaryBuilderInitial<''>; +export function varbinary( + name: TName, + config: SingleStoreVarbinaryOptions, +): SingleStoreVarBinaryBuilderInitial; +export function varbinary(a?: string | SingleStoreVarbinaryOptions, b?: SingleStoreVarbinaryOptions) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreVarBinaryBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/varchar.ts b/drizzle-orm/src/singlestore-core/columns/varchar.ts new file mode 100644 index 000000000..2c39491d7 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/varchar.ts @@ -0,0 +1,75 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreVarCharBuilderInitial = + SingleStoreVarCharBuilder< + { + name: TName; + dataType: 'string'; + columnType: 'SingleStoreVarChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; + } + >; + +export class SingleStoreVarCharBuilder> + extends SingleStoreColumnBuilder> +{ + static override readonly [entityKind]: string = 'SingleStoreVarCharBuilder'; + + /** @internal */ + constructor(name: T['name'], config: SingleStoreVarCharConfig) { + super(name, 'string', 'SingleStoreVarChar'); + this.config.length = config.length; + this.config.enum = config.enum; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreVarChar & { enumValues: T['enumValues'] }> { + return new SingleStoreVarChar & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreVarChar> + extends SingleStoreColumn> +{ + static override readonly [entityKind]: string = 'SingleStoreVarChar'; + + readonly length: number | undefined = this.config.length; + + override readonly enumValues = this.config.enum; + + getSQLType(): string { + return this.length === undefined ? `varchar` : `varchar(${this.length})`; + } +} + +export interface SingleStoreVarCharConfig< + TEnum extends string[] | readonly string[] | undefined = string[] | readonly string[] | undefined, +> { + length: number; + enum?: TEnum; +} + +export function varchar>( + config: SingleStoreVarCharConfig>, +): SingleStoreVarCharBuilderInitial<'', Writable>; +export function varchar>( + name: TName, + config: SingleStoreVarCharConfig>, +): SingleStoreVarCharBuilderInitial>; +export function varchar(a?: string | SingleStoreVarCharConfig, b?: SingleStoreVarCharConfig): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreVarCharBuilder(name, config as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/year.ts b/drizzle-orm/src/singlestore-core/columns/year.ts new file mode 100644 index 000000000..37f3d55a3 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/year.ts @@ -0,0 +1,51 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreYearBuilderInitial = SingleStoreYearBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreYear'; + data: number; + driverParam: number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreYearBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreYearBuilder'; + + constructor(name: T['name']) { + super(name, 'number', 'SingleStoreYear'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreYear> { + return new SingleStoreYear>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreYear< + T extends ColumnBaseConfig<'number', 'SingleStoreYear'>, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreYear'; + + getSQLType(): string { + return `year`; + } +} + +export function year(): SingleStoreYearBuilderInitial<''>; +export function year(name: TName): SingleStoreYearBuilderInitial; +export function year(name?: string) { + return new SingleStoreYearBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts new file mode 100644 index 000000000..63cf97da4 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -0,0 +1,566 @@ +import type { ResultSetHeader } from 'mysql2/promise'; +import { entityKind } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import { WithSubquery } from '~/subquery.ts'; +import type { DrizzleTypeError } from '~/utils.ts'; +import type { SingleStoreDialect } from './dialect.ts'; +import { SingleStoreAttachBase } from './query-builders/attach.ts'; +import { SingleStoreBranchBase } from './query-builders/branch.ts'; +import { SingleStoreCreateMilestoneBase } from './query-builders/createMilestone.ts'; +import { SingleStoreDetachBase } from './query-builders/detach.ts'; +import { SingleStoreDropMilestoneBase } from './query-builders/dropMilestone.ts'; +import { + QueryBuilder, + SingleStoreDeleteBase, + SingleStoreInsertBuilder, + SingleStoreSelectBuilder, + SingleStoreUpdateBuilder, +} from './query-builders/index.ts'; +import type { OptimizeTableArgument } from './query-builders/optimizeTable.ts'; +import { SingleStoreOptimizeTableBase } from './query-builders/optimizeTable.ts'; +import { RelationalQueryBuilder } from './query-builders/query.ts'; +import type { SelectedFields } from './query-builders/select.types.ts'; +import type { + PreparedQueryHKTBase, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, + SingleStoreTransaction, + SingleStoreTransactionConfig, +} from './session.ts'; +import type { WithSubqueryWithSelection } from './subquery.ts'; +import type { SingleStoreTable } from './table.ts'; + +export class SingleStoreDatabase< + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record = {}, + TSchema extends TablesRelationalConfig = ExtractTablesWithRelations, +> { + static readonly [entityKind]: string = 'SingleStoreDatabase'; + + declare readonly _: { + readonly schema: TSchema | undefined; + readonly fullSchema: TFullSchema; + readonly tableNamesMap: Record; + }; + + query: TFullSchema extends Record + ? DrizzleTypeError<'Seems like the schema generic is missing - did you forget to add it to your DB type?'> + : { + [K in keyof TSchema]: RelationalQueryBuilder; + }; + + constructor( + /** @internal */ + readonly dialect: SingleStoreDialect, + /** @internal */ + readonly session: SingleStoreSession, + schema: RelationalSchemaConfig | undefined, + ) { + this._ = schema + ? { + schema: schema.schema, + fullSchema: schema.fullSchema as TFullSchema, + tableNamesMap: schema.tableNamesMap, + } + : { + schema: undefined, + fullSchema: {} as TFullSchema, + tableNamesMap: {}, + }; + this.query = {} as typeof this['query']; + if (this._.schema) { + for (const [tableName, columns] of Object.entries(this._.schema)) { + (this.query as SingleStoreDatabase>['query'])[tableName] = + new RelationalQueryBuilder( + schema!.fullSchema, + this._.schema, + this._.tableNamesMap, + schema!.fullSchema[tableName] as SingleStoreTable, + columns, + dialect, + session, + ); + } + } + } + + /** + * Creates a subquery that defines a temporary named result set as a CTE. + * + * It is useful for breaking down complex queries into simpler parts and for reusing the result set in subsequent parts of the query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#with-clause} + * + * @param alias The alias for the subquery. + * + * Failure to provide an alias will result in a DrizzleTypeError, preventing the subquery from being referenced in other queries. + * + * @example + * + * ```ts + * // Create a subquery with alias 'sq' and use it in the select query + * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42))); + * + * const result = await db.with(sq).select().from(sq); + * ``` + * + * To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query, you need to add aliases to them: + * + * ```ts + * // Select an arbitrary SQL value as a field in a CTE and reference it in the main query + * const sq = db.$with('sq').as(db.select({ + * name: sql`upper(${users.name})`.as('name'), + * }) + * .from(users)); + * + * const result = await db.with(sq).select({ name: sq.name }).from(sq); + * ``` + */ + $with(alias: TAlias) { + return { + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): WithSubqueryWithSelection { + if (typeof qb === 'function') { + qb = qb(new QueryBuilder()); + } + + return new Proxy( + new WithSubquery(qb.getSQL(), qb.getSelectedFields() as SelectedFields, alias, true), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as WithSubqueryWithSelection; + }, + }; + } + + /** + * Incorporates a previously defined CTE (using `$with`) into the main query. + * + * This method allows the main query to reference a temporary named result set. + * + * See docs: {@link https://orm.drizzle.team/docs/select#with-clause} + * + * @param queries The CTEs to incorporate into the main query. + * + * @example + * + * ```ts + * // Define a subquery 'sq' as a CTE using $with + * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42))); + * + * // Incorporate the CTE 'sq' into the main query and select from it + * const result = await db.with(sq).select().from(sq); + * ``` + */ + with(...queries: WithSubquery[]) { + const self = this; + + /** + * Creates a select query. + * + * Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select} + * + * @param fields The selection object. + * + * @example + * + * ```ts + * // Select all columns and all rows from the 'cars' table + * const allCars: Car[] = await db.select().from(cars); + * + * // Select specific columns and all rows from the 'cars' table + * const carsIdsAndBrands: { id: number; brand: string }[] = await db.select({ + * id: cars.id, + * brand: cars.brand + * }) + * .from(cars); + * ``` + * + * Like in SQL, you can use arbitrary expressions as selection fields, not just table columns: + * + * ```ts + * // Select specific columns along with expression and all rows from the 'cars' table + * const carsIdsAndLowerNames: { id: number; lowerBrand: string }[] = await db.select({ + * id: cars.id, + * lowerBrand: sql`lower(${cars.brand})`, + * }) + * .from(cars); + * ``` + */ + function select(): SingleStoreSelectBuilder; + function select( + fields: TSelection, + ): SingleStoreSelectBuilder; + function select(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: self.session, + dialect: self.dialect, + withList: queries, + }); + } + + /** + * Adds `distinct` expression to the select query. + * + * Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select#distinct} + * + * @param fields The selection object. + * + * @example + * ```ts + * // Select all unique rows from the 'cars' table + * await db.selectDistinct() + * .from(cars) + * .orderBy(cars.id, cars.brand, cars.color); + * + * // Select all unique brands from the 'cars' table + * await db.selectDistinct({ brand: cars.brand }) + * .from(cars) + * .orderBy(cars.brand); + * ``` + */ + function selectDistinct(): SingleStoreSelectBuilder; + function selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + function selectDistinct( + fields?: SelectedFields, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: self.session, + dialect: self.dialect, + withList: queries, + distinct: true, + }); + } + + /** + * Creates an update query. + * + * Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated. + * + * Use `.set()` method to specify which values to update. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param table The table to update. + * + * @example + * + * ```ts + * // Update all rows in the 'cars' table + * await db.update(cars).set({ color: 'red' }); + * + * // Update rows with filters and conditions + * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW')); + * ``` + */ + function update( + table: TTable, + ): SingleStoreUpdateBuilder { + return new SingleStoreUpdateBuilder(table, self.session, self.dialect, queries); + } + + /** + * Creates a delete query. + * + * Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param table The table to delete from. + * + * @example + * + * ```ts + * // Delete all rows in the 'cars' table + * await db.delete(cars); + * + * // Delete rows with filters and conditions + * await db.delete(cars).where(eq(cars.color, 'green')); + * ``` + */ + function delete_( + table: TTable, + ): SingleStoreDeleteBase { + return new SingleStoreDeleteBase(table, self.session, self.dialect, queries); + } + + return { select, selectDistinct, update, delete: delete_ }; + } + + /** + * Creates a select query. + * + * Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select} + * + * @param fields The selection object. + * + * @example + * + * ```ts + * // Select all columns and all rows from the 'cars' table + * const allCars: Car[] = await db.select().from(cars); + * + * // Select specific columns and all rows from the 'cars' table + * const carsIdsAndBrands: { id: number; brand: string }[] = await db.select({ + * id: cars.id, + * brand: cars.brand + * }) + * .from(cars); + * ``` + * + * Like in SQL, you can use arbitrary expressions as selection fields, not just table columns: + * + * ```ts + * // Select specific columns along with expression and all rows from the 'cars' table + * const carsIdsAndLowerNames: { id: number; lowerBrand: string }[] = await db.select({ + * id: cars.id, + * lowerBrand: sql`lower(${cars.brand})`, + * }) + * .from(cars); + * ``` + */ + select(): SingleStoreSelectBuilder; + select( + fields: TSelection, + ): SingleStoreSelectBuilder; + select(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ fields: fields ?? undefined, session: this.session, dialect: this.dialect }); + } + + /** + * Adds `distinct` expression to the select query. + * + * Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select#distinct} + * + * @param fields The selection object. + * + * @example + * ```ts + * // Select all unique rows from the 'cars' table + * await db.selectDistinct() + * .from(cars) + * .orderBy(cars.id, cars.brand, cars.color); + * + * // Select all unique brands from the 'cars' table + * await db.selectDistinct({ brand: cars.brand }) + * .from(cars) + * .orderBy(cars.brand); + * ``` + */ + selectDistinct(): SingleStoreSelectBuilder; + selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + selectDistinct(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: this.session, + dialect: this.dialect, + distinct: true, + }); + } + + /** + * Creates an update query. + * + * Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated. + * + * Use `.set()` method to specify which values to update. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param table The table to update. + * + * @example + * + * ```ts + * // Update all rows in the 'cars' table + * await db.update(cars).set({ color: 'red' }); + * + * // Update rows with filters and conditions + * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW')); + * ``` + */ + update( + table: TTable, + ): SingleStoreUpdateBuilder { + return new SingleStoreUpdateBuilder(table, this.session, this.dialect); + } + + /** + * Creates an insert query. + * + * Calling this method will create new rows in a table. Use `.values()` method to specify which values to insert. + * + * See docs: {@link https://orm.drizzle.team/docs/insert} + * + * @param table The table to insert into. + * + * @example + * + * ```ts + * // Insert one row + * await db.insert(cars).values({ brand: 'BMW' }); + * + * // Insert multiple rows + * await db.insert(cars).values([{ brand: 'BMW' }, { brand: 'Porsche' }]); + * ``` + */ + insert( + table: TTable, + ): SingleStoreInsertBuilder { + return new SingleStoreInsertBuilder(table, this.session, this.dialect); + } + + /** + * Creates a delete query. + * + * Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param table The table to delete from. + * + * @example + * + * ```ts + * // Delete all rows in the 'cars' table + * await db.delete(cars); + * + * // Delete rows with filters and conditions + * await db.delete(cars).where(eq(cars.color, 'green')); + * ``` + */ + delete( + table: TTable, + ): SingleStoreDeleteBase { + return new SingleStoreDeleteBase(table, this.session, this.dialect); + } + + execute( + query: SQLWrapper, + ): Promise> { + return this.session.execute(query.getSQL()); + } + + transaction( + transaction: ( + tx: SingleStoreTransaction, + config?: SingleStoreTransactionConfig, + ) => Promise, + config?: SingleStoreTransactionConfig, + ): Promise { + return this.session.transaction(transaction, config); + } + + detach( + database: TDatabase, + ): SingleStoreDetachBase { + return new SingleStoreDetachBase(database, this.session, this.dialect); + } + + attach( + database: TDatabase, + ): SingleStoreAttachBase { + return new SingleStoreAttachBase(database, this.session, this.dialect); + } + + branch( + database: TDatabase, + branchName: string, + ): SingleStoreBranchBase { + return new SingleStoreBranchBase(database, branchName, this.session, this.dialect); + } + + createMilestone( + milestone: TMilestone, + ): SingleStoreCreateMilestoneBase { + return new SingleStoreCreateMilestoneBase(milestone, this.session, this.dialect); + } + + dropMilestone( + milestone: TMilestone, + ): SingleStoreDropMilestoneBase { + return new SingleStoreDropMilestoneBase(milestone, this.session, this.dialect); + } + + optimizeTable< + TTable extends SingleStoreTable, + TArg extends OptimizeTableArgument, + >( + table: TTable, + arg: TArg | undefined = undefined, + ): SingleStoreOptimizeTableBase { + return new SingleStoreOptimizeTableBase(table, arg, this.session, this.dialect); + } +} + +export type SingleStoreWithReplicas = Q & { $primary: Q }; + +export const withReplicas = < + HKT extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, + Q extends SingleStoreDatabase< + HKT, + TPreparedQueryHKT, + TFullSchema, + TSchema extends Record ? ExtractTablesWithRelations : TSchema + >, +>( + primary: Q, + replicas: [Q, ...Q[]], + getReplica: (replicas: Q[]) => Q = () => replicas[Math.floor(Math.random() * replicas.length)]!, +): SingleStoreWithReplicas => { + const select: Q['select'] = (...args: []) => getReplica(replicas).select(...args); + const selectDistinct: Q['selectDistinct'] = (...args: []) => getReplica(replicas).selectDistinct(...args); + const $with: Q['with'] = (...args: []) => getReplica(replicas).with(...args); + + const update: Q['update'] = (...args: [any]) => primary.update(...args); + const insert: Q['insert'] = (...args: [any]) => primary.insert(...args); + const $delete: Q['delete'] = (...args: [any]) => primary.delete(...args); + const execute: Q['execute'] = (...args: [any]) => primary.execute(...args); + const transaction: Q['transaction'] = (...args: [any, any]) => primary.transaction(...args); + + return { + ...primary, + update, + insert, + delete: $delete, + execute, + transaction, + $primary: primary, + select, + selectDistinct, + with: $with, + get query() { + return getReplica(replicas).query; + }, + }; +}; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts new file mode 100644 index 000000000..9e942cba8 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -0,0 +1,866 @@ +import { aliasedTable, aliasedTableColumn, mapColumnsInAliasedSQLToAlias, mapColumnsInSQLToAlias } from '~/alias.ts'; +import { CasingCache } from '~/casing.ts'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import { DrizzleError } from '~/errors.ts'; +import { and, eq } from '~/expressions.ts'; +import type { MigrationConfig, MigrationMeta } from '~/migrator.ts'; +import { + type BuildRelationalQueryResult, + type DBQueryConfig, + getOperators, + getOrderByOperators, + Many, + normalizeRelation, + One, + type Relation, + type TableRelationalConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import { Param, SQL, sql, View } from '~/sql/sql.ts'; +import type { Name, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; +import { Subquery } from '~/subquery.ts'; +import { getTableName, getTableUniqueName, Table } from '~/table.ts'; +import { orderSelectedFields } from '~/utils.ts'; +import type { Casing, UpdateSet } from '~/utils.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import { SingleStoreColumn } from './columns/common.ts'; +import type { SingleStoreAttachConfig } from './query-builders/attach.ts'; +import type { SingleStoreBranchConfig } from './query-builders/branch.ts'; +import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; +import type { SingleStoreDeleteConfig } from './query-builders/delete.ts'; +import type { SingleStoreDetachConfig } from './query-builders/detach.ts'; +import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; +import type { SingleStoreInsertConfig } from './query-builders/insert.ts'; +import type { SingleStoreOptimizeTableConfig } from './query-builders/optimizeTable.ts'; +import type { + SelectedFieldsOrdered, + SingleStoreSelectConfig, + SingleStoreSelectJoinConfig, +} from './query-builders/select.types.ts'; +import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; +import type { SingleStoreSession } from './session.ts'; +import { SingleStoreTable } from './table.ts'; +import { SingleStoreViewBase } from './view-base.ts'; + +export interface SingleStoreDialectConfig { + casing?: Casing; +} + +export class SingleStoreDialect { + static readonly [entityKind]: string = 'SingleStoreDialect'; + + /** @internal */ + readonly casing: CasingCache; + + constructor(config?: SingleStoreDialectConfig) { + this.casing = new CasingCache(config?.casing); + } + + async migrate( + migrations: MigrationMeta[], + session: SingleStoreSession, + config: Omit, + ): Promise { + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; + const migrationTableCreate = sql` + create table if not exists ${sql.identifier(migrationsTable)} ( + id serial primary key, + hash text not null, + created_at bigint + ) + `; + await session.execute(migrationTableCreate); + + const dbMigrations = await session.all<{ id: number; hash: string; created_at: string }>( + sql`select id, hash, created_at from ${sql.identifier(migrationsTable)} order by created_at desc limit 1`, + ); + + const lastDbMigration = dbMigrations[0]; + + await session.transaction(async (tx) => { + for (const migration of migrations) { + if ( + !lastDbMigration + || Number(lastDbMigration.created_at) < migration.folderMillis + ) { + for (const stmt of migration.sql) { + await tx.execute(sql.raw(stmt)); + } + await tx.execute( + sql`insert into ${ + sql.identifier(migrationsTable) + } (\`hash\`, \`created_at\`) values(${migration.hash}, ${migration.folderMillis})`, + ); + } + } + }); + } + + escapeName(name: string): string { + return `\`${name}\``; + } + + escapeParam(_num: number): string { + return `?`; + } + + escapeString(str: string): string { + return `'${str.replace(/'/g, "''")}'`; + } + + private buildWithCTE(queries: Subquery[] | undefined): SQL | undefined { + if (!queries?.length) return undefined; + + const withSqlChunks = [sql`with `]; + for (const [i, w] of queries.entries()) { + withSqlChunks.push(sql`${sql.identifier(w._.alias)} as (${w._.sql})`); + if (i < queries.length - 1) { + withSqlChunks.push(sql`, `); + } + } + withSqlChunks.push(sql` `); + return sql.join(withSqlChunks); + } + + buildDeleteQuery({ table, where, returning, withList }: SingleStoreDeleteConfig): SQL { + const withSql = this.buildWithCTE(withList); + + const returningSql = returning + ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` + : undefined; + + const whereSql = where ? sql` where ${where}` : undefined; + + return sql`${withSql}delete from ${table}${whereSql}${returningSql}`; + } + + buildDetachQuery({ database, milestone, workspace }: SingleStoreDetachConfig): SQL { + const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; + + const workspaceSql = workspace ? sql` from workspace ${workspace}` : undefined; + + return sql`detach database ${database}${milestoneSql}${workspaceSql}`; + } + + buildAttachQuery( + { database, milestone, time, databaseAlias, readOnly, ...rest }: SingleStoreAttachConfig | SingleStoreBranchConfig, + ): SQL { + const asSql = databaseAlias ? sql` as ${sql.identifier(databaseAlias)}` : undefined; + const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; + const timeSql = time ? sql` at time ${time}` : undefined; + const readOnlySql = readOnly ? sql` read only` : undefined; + const fromWorkspaceGroupSql = 'fromWorkspaceGroup' in rest + ? sql` from workspace group ${rest.fromWorkspaceGroup}` + : undefined; + + return sql`attach database ${ + sql.raw(database) + }${fromWorkspaceGroupSql}${readOnlySql}${asSql}${milestoneSql}${timeSql}`; + } + + buildCreateMilestoneQuery({ database, milestone }: SingleStoreCreateMilestoneConfig): SQL { + const forSql = database ? sql` for ${sql.identifier(database)}` : undefined; + + return sql`create milestone ${milestone}${forSql}`; + } + + buildDropMilestoneQuery({ database, milestone }: SingleStoreDropMilestoneConfig): SQL { + const forSql = database ? sql` for ${sql.identifier(database)}` : undefined; + + return sql`drop milestone ${milestone}${forSql}`; + } + + buildOptimizeTable({ table, arg, selection }: SingleStoreOptimizeTableConfig): SQL { + const argSql = arg ? sql` ${sql.raw(arg)}` : undefined; + + let warmBlobCacheForColumnSql = undefined; + if (selection) { + const selectionField = selection.length > 0 + ? selection.map((column) => { + return { path: [], field: column }; + }) + : [{ path: [], field: sql.raw('*') }]; + warmBlobCacheForColumnSql = sql` warm blob cache for column ${ + this.buildSelection(selectionField, { isSingleTable: true }) + }`; + } + + return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; + } + + buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { + const tableColumns = table[Table.Symbol.Columns]; + + const columnNames = Object.keys(tableColumns).filter((colName) => + set[colName] !== undefined || tableColumns[colName]?.onUpdateFn !== undefined + ); + + const setSize = columnNames.length; + return sql.join(columnNames.flatMap((colName, i) => { + const col = tableColumns[colName]!; + + const value = set[colName] ?? sql.param(col.onUpdateFn!(), col); + const res = sql`${sql.identifier(col.name)} = ${value}`; + + if (i < setSize - 1) { + return [res, sql.raw(', ')]; + } + return [res]; + })); + } + + buildUpdateQuery({ table, set, where, returning, withList }: SingleStoreUpdateConfig): SQL { + const withSql = this.buildWithCTE(withList); + + const setSql = this.buildUpdateSet(table, set); + + const returningSql = returning + ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` + : undefined; + + const whereSql = where ? sql` where ${where}` : undefined; + + return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}`; + } + + /** + * Builds selection SQL with provided fields/expressions + * + * Examples: + * + * `select from` + * + * `insert ... returning ` + * + * If `isSingleTable` is true, then columns won't be prefixed with table name + */ + private buildSelection( + fields: SelectedFieldsOrdered, + { isSingleTable = false }: { isSingleTable?: boolean } = {}, + ): SQL { + const columnsLen = fields.length; + + const chunks = fields + .flatMap(({ field }, i) => { + const chunk: SQLChunk[] = []; + + if (is(field, SQL.Aliased) && field.isSelectionField) { + chunk.push(sql.identifier(field.fieldAlias)); + } else if (is(field, SQL.Aliased) || is(field, SQL)) { + const query = is(field, SQL.Aliased) ? field.sql : field; + + if (isSingleTable) { + chunk.push( + new SQL( + query.queryChunks.map((c) => { + if (is(c, SingleStoreColumn)) { + return sql.identifier(c.name); + } + return c; + }), + ), + ); + } else { + chunk.push(query); + } + + if (is(field, SQL.Aliased)) { + chunk.push(sql` as ${sql.identifier(field.fieldAlias)}`); + } + } else if (is(field, Column)) { + if (isSingleTable) { + chunk.push(sql.identifier(field.name)); + } else { + chunk.push(field); + } + } + + if (i < columnsLen - 1) { + chunk.push(sql`, `); + } + + return chunk; + }); + + return sql.join(chunks); + } + + buildSelectQuery( + { + withList, + fields, + fieldsFlat, + where, + having, + table, + joins, + orderBy, + groupBy, + limit, + offset, + lockingClause, + distinct, + setOperators, + }: SingleStoreSelectConfig, + ): SQL { + const fieldsList = fieldsFlat ?? orderSelectedFields(fields); + for (const f of fieldsList) { + if ( + is(f.field, Column) + && getTableName(f.field.table) + !== (is(table, Subquery) + ? table._.alias + : is(table, SingleStoreViewBase) + ? table[ViewBaseConfig].name + : is(table, SQL) + ? undefined + : getTableName(table)) + && !((table) => + joins?.some(({ alias }) => + alias === (table[Table.Symbol.IsAlias] ? getTableName(table) : table[Table.Symbol.BaseName]) + ))(f.field.table) + ) { + const tableName = getTableName(f.field.table); + throw new Error( + `Your "${ + f.path.join('->') + }" field references a column "${tableName}"."${f.field.name}", but the table "${tableName}" is not part of the query! Did you forget to join it?`, + ); + } + } + + const isSingleTable = !joins || joins.length === 0; + + const withSql = this.buildWithCTE(withList); + + const distinctSql = distinct ? sql` distinct` : undefined; + + const selection = this.buildSelection(fieldsList, { isSingleTable }); + + const tableSql = (() => { + if (is(table, Table) && table[Table.Symbol.OriginalName] !== table[Table.Symbol.Name]) { + return sql`${sql.identifier(table[Table.Symbol.OriginalName])} ${sql.identifier(table[Table.Symbol.Name])}`; + } + + return table; + })(); + + const joinsArray: SQL[] = []; + + if (joins) { + for (const [index, joinMeta] of joins.entries()) { + if (index === 0) { + joinsArray.push(sql` `); + } + const table = joinMeta.table; + const lateralSql = joinMeta.lateral ? sql` lateral` : undefined; + + if (is(table, SingleStoreTable)) { + const tableName = table[SingleStoreTable.Symbol.Name]; + const tableSchema = table[SingleStoreTable.Symbol.Schema]; + const origTableName = table[SingleStoreTable.Symbol.OriginalName]; + const alias = tableName === origTableName ? undefined : joinMeta.alias; + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ + tableSchema ? sql`${sql.identifier(tableSchema)}.` : undefined + }${sql.identifier(origTableName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + ); + } else if (is(table, View)) { + const viewName = table[ViewBaseConfig].name; + const viewSchema = table[ViewBaseConfig].schema; + const origViewName = table[ViewBaseConfig].originalName; + const alias = viewName === origViewName ? undefined : joinMeta.alias; + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ + viewSchema ? sql`${sql.identifier(viewSchema)}.` : undefined + }${sql.identifier(origViewName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + ); + } else { + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${table} on ${joinMeta.on}`, + ); + } + if (index < joins.length - 1) { + joinsArray.push(sql` `); + } + } + } + + const joinsSql = sql.join(joinsArray); + + const whereSql = where ? sql` where ${where}` : undefined; + + const havingSql = having ? sql` having ${having}` : undefined; + + let orderBySql; + if (orderBy && orderBy.length > 0) { + orderBySql = sql` order by ${sql.join(orderBy, sql`, `)}`; + } + + let groupBySql; + if (groupBy && groupBy.length > 0) { + groupBySql = sql` group by ${sql.join(groupBy, sql`, `)}`; + } + + const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined; + + const offsetSql = offset ? sql` offset ${offset}` : undefined; + + let lockingClausesSql; + if (lockingClause) { + const { config, strength } = lockingClause; + lockingClausesSql = sql` for ${sql.raw(strength)}`; + if (config.noWait) { + lockingClausesSql.append(sql` no wait`); + } else if (config.skipLocked) { + lockingClausesSql.append(sql` skip locked`); + } + } + + const finalQuery = + sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`; + + if (setOperators.length > 0) { + return this.buildSetOperations(finalQuery, setOperators); + } + + return finalQuery; + } + + buildSetOperations(leftSelect: SQL, setOperators: SingleStoreSelectConfig['setOperators']): SQL { + const [setOperator, ...rest] = setOperators; + + if (!setOperator) { + throw new Error('Cannot pass undefined values to any set operator'); + } + + if (rest.length === 0) { + return this.buildSetOperationQuery({ leftSelect, setOperator }); + } + + // Some recursive magic here + return this.buildSetOperations( + this.buildSetOperationQuery({ leftSelect, setOperator }), + rest, + ); + } + + buildSetOperationQuery({ + leftSelect, + setOperator: { type, isAll, rightSelect, limit, orderBy, offset }, + }: { leftSelect: SQL; setOperator: SingleStoreSelectConfig['setOperators'][number] }): SQL { + const leftChunk = sql`(${leftSelect.getSQL()}) `; + const rightChunk = sql`(${rightSelect.getSQL()})`; + + let orderBySql; + if (orderBy && orderBy.length > 0) { + const orderByValues: (SQL | Name)[] = []; + + // The next bit is necessary because the sql operator replaces ${table.column} with `table`.`column` + // which is invalid SingleStore syntax, Table from one of the SELECTs cannot be used in global ORDER clause + for (const orderByUnit of orderBy) { + if (is(orderByUnit, SingleStoreColumn)) { + orderByValues.push(sql.identifier(orderByUnit.name)); + } else if (is(orderByUnit, SQL)) { + for (let i = 0; i < orderByUnit.queryChunks.length; i++) { + const chunk = orderByUnit.queryChunks[i]; + + if (is(chunk, SingleStoreColumn)) { + orderByUnit.queryChunks[i] = sql.identifier(chunk.name); + } + } + + orderByValues.push(sql`${orderByUnit}`); + } else { + orderByValues.push(sql`${orderByUnit}`); + } + } + + orderBySql = sql` order by ${sql.join(orderByValues, sql`, `)} `; + } + + const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined; + + const operatorChunk = sql.raw(`${type} ${isAll ? 'all ' : ''}`); + + const offsetSql = offset ? sql` offset ${offset}` : undefined; + + return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; + } + + buildInsertQuery( + { table, values, ignore, onConflict }: SingleStoreInsertConfig, + ): { sql: SQL; generatedIds: Record[] } { + // const isSingleValue = values.length === 1; + const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = []; + const columns: Record = table[Table.Symbol.Columns]; + const colEntries: [string, SingleStoreColumn][] = Object.entries(columns).filter(([_, col]) => + !col.shouldDisableInsert() + ); + + const insertOrder = colEntries.map(([, column]) => sql.identifier(column.name)); + const generatedIdsResponse: Record[] = []; + + for (const [valueIndex, value] of values.entries()) { + const generatedIds: Record = {}; + + const valueList: (SQLChunk | SQL)[] = []; + for (const [fieldName, col] of colEntries) { + const colValue = value[fieldName]; + if (colValue === undefined || (is(colValue, Param) && colValue.value === undefined)) { + // eslint-disable-next-line unicorn/no-negated-condition + if (col.defaultFn !== undefined) { + const defaultFnResult = col.defaultFn(); + generatedIds[fieldName] = defaultFnResult; + const defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col); + valueList.push(defaultValue); + // eslint-disable-next-line unicorn/no-negated-condition + } else if (!col.default && col.onUpdateFn !== undefined) { + const onUpdateFnResult = col.onUpdateFn(); + const newValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col); + valueList.push(newValue); + } else { + valueList.push(sql`default`); + } + } else { + if (col.defaultFn && is(colValue, Param)) { + generatedIds[fieldName] = colValue.value; + } + valueList.push(colValue); + } + } + + generatedIdsResponse.push(generatedIds); + valuesSqlList.push(valueList); + if (valueIndex < values.length - 1) { + valuesSqlList.push(sql`, `); + } + } + + const valuesSql = sql.join(valuesSqlList); + + const ignoreSql = ignore ? sql` ignore` : undefined; + + const onConflictSql = onConflict ? sql` on duplicate key ${onConflict}` : undefined; + + return { + sql: sql`insert${ignoreSql} into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}`, + generatedIds: generatedIdsResponse, + }; + } + + sqlToQuery(sql: SQL, invokeSource?: 'indexes' | undefined): QueryWithTypings { + return sql.toQuery({ + casing: this.casing, + escapeName: this.escapeName, + escapeParam: this.escapeParam, + escapeString: this.escapeString, + invokeSource, + }); + } + + buildRelationalQuery({ + fullSchema, + schema, + tableNamesMap, + table, + tableConfig, + queryConfig: config, + tableAlias, + nestedQueryRelation, + joinOn, + }: { + fullSchema: Record; + schema: TablesRelationalConfig; + tableNamesMap: Record; + table: SingleStoreTable; + tableConfig: TableRelationalConfig; + queryConfig: true | DBQueryConfig<'many', true>; + tableAlias: string; + nestedQueryRelation?: Relation; + joinOn?: SQL; + }): BuildRelationalQueryResult { + let selection: BuildRelationalQueryResult['selection'] = []; + let limit, offset, orderBy: SingleStoreSelectConfig['orderBy'], where; + const joins: SingleStoreSelectJoinConfig[] = []; + + if (config === true) { + const selectionEntries = Object.entries(tableConfig.columns); + selection = selectionEntries.map(( + [key, value], + ) => ({ + dbKey: value.name, + tsKey: key, + field: aliasedTableColumn(value as SingleStoreColumn, tableAlias), + relationTableTsKey: undefined, + isJson: false, + selection: [], + })); + } else { + const aliasedColumns = Object.fromEntries( + Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value, tableAlias)]), + ); + + if (config.where) { + const whereSql = typeof config.where === 'function' + ? config.where(aliasedColumns, getOperators()) + : config.where; + where = whereSql && mapColumnsInSQLToAlias(whereSql, tableAlias); + } + + const fieldsSelection: { tsKey: string; value: SingleStoreColumn | SQL.Aliased }[] = []; + let selectedColumns: string[] = []; + + // Figure out which columns to select + if (config.columns) { + let isIncludeMode = false; + + for (const [field, value] of Object.entries(config.columns)) { + if (value === undefined) { + continue; + } + + if (field in tableConfig.columns) { + if (!isIncludeMode && value === true) { + isIncludeMode = true; + } + selectedColumns.push(field); + } + } + + if (selectedColumns.length > 0) { + selectedColumns = isIncludeMode + ? selectedColumns.filter((c) => config.columns?.[c] === true) + : Object.keys(tableConfig.columns).filter((key) => !selectedColumns.includes(key)); + } + } else { + // Select all columns if selection is not specified + selectedColumns = Object.keys(tableConfig.columns); + } + + for (const field of selectedColumns) { + const column = tableConfig.columns[field]! as SingleStoreColumn; + fieldsSelection.push({ tsKey: field, value: column }); + } + + let selectedRelations: { + tsKey: string; + queryConfig: true | DBQueryConfig<'many', false>; + relation: Relation; + }[] = []; + + // Figure out which relations to select + if (config.with) { + selectedRelations = Object.entries(config.with) + .filter((entry): entry is [typeof entry[0], NonNullable] => !!entry[1]) + .map(([tsKey, queryConfig]) => ({ tsKey, queryConfig, relation: tableConfig.relations[tsKey]! })); + } + + let extras; + + // Figure out which extras to select + if (config.extras) { + extras = typeof config.extras === 'function' + ? config.extras(aliasedColumns, { sql }) + : config.extras; + for (const [tsKey, value] of Object.entries(extras)) { + fieldsSelection.push({ + tsKey, + value: mapColumnsInAliasedSQLToAlias(value, tableAlias), + }); + } + } + + // Transform `fieldsSelection` into `selection` + // `fieldsSelection` shouldn't be used after this point + for (const { tsKey, value } of fieldsSelection) { + selection.push({ + dbKey: is(value, SQL.Aliased) ? value.fieldAlias : tableConfig.columns[tsKey]!.name, + tsKey, + field: is(value, Column) ? aliasedTableColumn(value, tableAlias) : value, + relationTableTsKey: undefined, + isJson: false, + selection: [], + }); + } + + let orderByOrig = typeof config.orderBy === 'function' + ? config.orderBy(aliasedColumns, getOrderByOperators()) + : config.orderBy ?? []; + if (!Array.isArray(orderByOrig)) { + orderByOrig = [orderByOrig]; + } + orderBy = orderByOrig.map((orderByValue) => { + if (is(orderByValue, Column)) { + return aliasedTableColumn(orderByValue, tableAlias) as SingleStoreColumn; + } + return mapColumnsInSQLToAlias(orderByValue, tableAlias); + }); + + limit = config.limit; + offset = config.offset; + + // Process all relations + for ( + const { + tsKey: selectedRelationTsKey, + queryConfig: selectedRelationConfigValue, + relation, + } of selectedRelations + ) { + const normalizedRelation = normalizeRelation(schema, tableNamesMap, relation); + const relationTableName = getTableUniqueName(relation.referencedTable); + const relationTableTsName = tableNamesMap[relationTableName]!; + const relationTableAlias = `${tableAlias}_${selectedRelationTsKey}`; + const joinOn = and( + ...normalizedRelation.fields.map((field, i) => + eq( + aliasedTableColumn(normalizedRelation.references[i]!, relationTableAlias), + aliasedTableColumn(field, tableAlias), + ) + ), + ); + const builtRelation = this.buildRelationalQuery({ + fullSchema, + schema, + tableNamesMap, + table: fullSchema[relationTableTsName] as SingleStoreTable, + tableConfig: schema[relationTableTsName]!, + queryConfig: is(relation, One) + ? (selectedRelationConfigValue === true + ? { limit: 1 } + : { ...selectedRelationConfigValue, limit: 1 }) + : selectedRelationConfigValue, + tableAlias: relationTableAlias, + joinOn, + nestedQueryRelation: relation, + }); + const field = sql`coalesce(${sql.identifier(relationTableAlias)}.${sql.identifier('data')}, "[]")`.as( + selectedRelationTsKey, + ); + joins.push({ + on: sql`true`, + table: new Subquery(builtRelation.sql as SQL, {}, relationTableAlias), + alias: relationTableAlias, + joinType: 'left', + lateral: true, + }); + selection.push({ + dbKey: selectedRelationTsKey, + tsKey: selectedRelationTsKey, + field, + relationTableTsKey: relationTableTsName, + isJson: true, + selection: builtRelation.selection, + }); + } + } + + if (selection.length === 0) { + throw new DrizzleError({ message: `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}")` }); + } + + let result; + + where = and(joinOn, where); + + if (nestedQueryRelation) { + let field = sql`JSON_BUILD_OBJECT(${ + sql.join( + selection.map(({ field, tsKey, isJson }, index) => + isJson + ? sql`${index}, ${sql.identifier(`${tableAlias}_${tsKey}`)}.${sql.identifier('data')}` + : is(field, SQL.Aliased) + ? sql`${index}, ${field.sql}` + : sql`${index}, ${field}` + ), + sql`, `, + ) + })`; + if (is(nestedQueryRelation, Many)) { + field = sql`json_agg(${field})`; + } + const nestedSelection = [{ + dbKey: 'data', + tsKey: 'data', + field: field.as('data'), + isJson: true, + relationTableTsKey: tableConfig.tsName, + selection, + }]; + + const needsSubquery = limit !== undefined || offset !== undefined || (orderBy?.length ?? 0) > 0; + + if (needsSubquery) { + result = this.buildSelectQuery({ + table: aliasedTable(table, tableAlias), + fields: {}, + fieldsFlat: [ + { + path: [], + field: sql.raw('*'), + }, + ...(((orderBy?.length ?? 0) > 0) + ? [{ + path: [], + field: sql`row_number() over (order by ${sql.join(orderBy!, sql`, `)})`, + }] + : []), + ], + where, + limit, + offset, + setOperators: [], + }); + + where = undefined; + limit = undefined; + offset = undefined; + orderBy = undefined; + } else { + result = aliasedTable(table, tableAlias); + } + + result = this.buildSelectQuery({ + table: is(result, SingleStoreTable) ? result : new Subquery(result, {}, tableAlias), + fields: {}, + fieldsFlat: nestedSelection.map(({ field }) => ({ + path: [], + field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field, + })), + joins, + where, + limit, + offset, + orderBy, + setOperators: [], + }); + } else { + result = this.buildSelectQuery({ + table: aliasedTable(table, tableAlias), + fields: {}, + fieldsFlat: selection.map(({ field }) => ({ + path: [], + field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field, + })), + joins, + where, + limit, + offset, + orderBy, + setOperators: [], + }); + } + + return { + tableTsKey: tableConfig.tsName, + sql: result, + selection, + }; + } +} diff --git a/drizzle-orm/src/singlestore-core/expressions.ts b/drizzle-orm/src/singlestore-core/expressions.ts new file mode 100644 index 000000000..6d4284d18 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/expressions.ts @@ -0,0 +1,25 @@ +import { bindIfParam } from '~/expressions.ts'; +import type { Placeholder, SQL, SQLChunk, SQLWrapper } from '~/sql/sql.ts'; +import { sql } from '~/sql/sql.ts'; +import type { SingleStoreColumn } from './columns/index.ts'; + +export * from '~/expressions.ts'; + +export function concat(column: SingleStoreColumn | SQL.Aliased, value: string | Placeholder | SQLWrapper): SQL { + return sql`${column} || ${bindIfParam(value, column)}`; +} + +export function substring( + column: SingleStoreColumn | SQL.Aliased, + { from, for: _for }: { from?: number | Placeholder | SQLWrapper; for?: number | Placeholder | SQLWrapper }, +): SQL { + const chunks: SQLChunk[] = [sql`substring(`, column]; + if (from !== undefined) { + chunks.push(sql` from `, bindIfParam(from, column)); + } + if (_for !== undefined) { + chunks.push(sql` for `, bindIfParam(_for, column)); + } + chunks.push(sql`)`); + return sql.join(chunks); +} diff --git a/drizzle-orm/src/singlestore-core/index.ts b/drizzle-orm/src/singlestore-core/index.ts new file mode 100644 index 000000000..4da014404 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/index.ts @@ -0,0 +1,16 @@ +export * from './alias.ts'; +export * from './columns/index.ts'; +export * from './db.ts'; +export * from './dialect.ts'; +export * from './indexes.ts'; +export * from './primary-keys.ts'; +export * from './query-builders/index.ts'; +export * from './schema.ts'; +export * from './session.ts'; +export * from './sql/index.ts'; +export * from './subquery.ts'; +export * from './table.ts'; +export * from './unique-constraint.ts'; +export * from './utils.ts'; +export * from './view-common.ts'; +export * from './view.ts'; diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts new file mode 100644 index 000000000..172f524f5 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -0,0 +1,191 @@ +import { entityKind } from '~/entity.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; +import type { SingleStoreTable } from './table.ts'; + +interface IndexConfig { + name: string; + + columns: IndexColumn[]; + + /** + * If true, the index will be created as `create unique index` instead of `create index`. + */ + unique?: boolean; + + /** + * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. + */ + using?: 'btree' | 'hash'; + + /** + * If set, the index will be created as `create index ... algorythm { 'default' | 'inplace' | 'copy' }`. + */ + algorythm?: 'default' | 'inplace' | 'copy'; + + /** + * If set, adds locks to the index creation. + */ + lock?: 'default' | 'none' | 'shared' | 'exclusive'; +} + +export type IndexColumn = SingleStoreColumn | SQL; + +export class IndexBuilderOn { + static readonly [entityKind]: string = 'SingleStoreIndexBuilderOn'; + + constructor(private name: string, private unique: boolean) {} + + on(...columns: [IndexColumn, ...IndexColumn[]]): IndexBuilder { + return new IndexBuilder(this.name, columns, this.unique); + } +} + +export interface AnyIndexBuilder { + build(table: SingleStoreTable): Index; +} + +export interface AnyFullTextIndexBuilder { + build(table: SingleStoreTable): FullTextIndex; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface IndexBuilder extends AnyIndexBuilder {} + +export class IndexBuilder implements AnyIndexBuilder { + static readonly [entityKind]: string = 'SingleStoreIndexBuilder'; + + /** @internal */ + config: IndexConfig; + + constructor(name: string, columns: IndexColumn[], unique: boolean) { + this.config = { + name, + columns, + unique, + }; + } + + using(using: IndexConfig['using']): this { + this.config.using = using; + return this; + } + + algorythm(algorythm: IndexConfig['algorythm']): this { + this.config.algorythm = algorythm; + return this; + } + + lock(lock: IndexConfig['lock']): this { + this.config.lock = lock; + return this; + } + + /** @internal */ + build(table: SingleStoreTable): Index { + return new Index(this.config, table); + } +} + +export class Index { + static readonly [entityKind]: string = 'SingleStoreIndex'; + + readonly config: IndexConfig & { table: SingleStoreTable }; + + constructor(config: IndexConfig, table: SingleStoreTable) { + this.config = { ...config, table }; + } +} + +export type GetColumnsTableName = TColumns extends + AnySingleStoreColumn<{ tableName: infer TTableName extends string }> | AnySingleStoreColumn< + { tableName: infer TTableName extends string } + >[] ? TTableName + : never; + +export function index(name: string): IndexBuilderOn { + return new IndexBuilderOn(name, false); +} + +export function uniqueIndex(name: string): IndexBuilderOn { + return new IndexBuilderOn(name, true); +} + +interface FullTextIndexConfig { + version?: number; +} + +interface FullTextIndexFullConfig extends FullTextIndexConfig { + columns: IndexColumn[]; + + name: string; +} + +export class FullTextIndexBuilderOn { + static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilderOn'; + + constructor(private name: string, private config: FullTextIndexConfig) {} + + on(...columns: [IndexColumn, ...IndexColumn[]]): FullTextIndexBuilder { + return new FullTextIndexBuilder({ + name: this.name, + columns: columns, + ...this.config, + }); + } +} + +export interface FullTextIndexBuilder extends AnyFullTextIndexBuilder {} + +export class FullTextIndexBuilder implements AnyFullTextIndexBuilder { + static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilder'; + + /** @internal */ + config: FullTextIndexFullConfig; + + constructor(config: FullTextIndexFullConfig) { + this.config = config; + } + + /** @internal */ + build(table: SingleStoreTable): FullTextIndex { + return new FullTextIndex(this.config, table); + } +} + +export class FullTextIndex { + static readonly [entityKind]: string = 'SingleStoreFullTextIndex'; + + readonly config: FullTextIndexConfig & { table: SingleStoreTable }; + + constructor(config: FullTextIndexConfig, table: SingleStoreTable) { + this.config = { ...config, table }; + } +} + +export function fulltext(name: string, config: FullTextIndexConfig): FullTextIndexBuilderOn { + return new FullTextIndexBuilderOn(name, config); +} + +export type SortKeyColumn = SingleStoreColumn | SQL; + +export class SortKeyBuilder { + static readonly [entityKind]: string = 'SingleStoreSortKeyBuilder'; + + constructor(private columns: SortKeyColumn[]) {} + + /** @internal */ + build(table: SingleStoreTable): SortKey { + return new SortKey(this.columns, table); + } +} + +export class SortKey { + static readonly [entityKind]: string = 'SingleStoreSortKey'; + + constructor(public columns: SortKeyColumn[], public table: SingleStoreTable) {} +} + +export function sortKey(...columns: SortKeyColumn[]): SortKeyBuilder { + return new SortKeyBuilder(columns); +} diff --git a/drizzle-orm/src/singlestore-core/primary-keys.ts b/drizzle-orm/src/singlestore-core/primary-keys.ts new file mode 100644 index 000000000..47dc0a19c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/primary-keys.ts @@ -0,0 +1,63 @@ +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; +import { SingleStoreTable } from './table.ts'; + +export function primaryKey< + TTableName extends string, + TColumn extends AnySingleStoreColumn<{ tableName: TTableName }>, + TColumns extends AnySingleStoreColumn<{ tableName: TTableName }>[], +>(config: { name?: string; columns: [TColumn, ...TColumns] }): PrimaryKeyBuilder; +/** + * @deprecated: Please use primaryKey({ columns: [] }) instead of this function + * @param columns + */ +export function primaryKey< + TTableName extends string, + TColumns extends AnySingleStoreColumn<{ tableName: TTableName }>[], +>(...columns: TColumns): PrimaryKeyBuilder; +export function primaryKey(...config: any) { + if (config[0].columns) { + return new PrimaryKeyBuilder(config[0].columns, config[0].name); + } + return new PrimaryKeyBuilder(config); +} + +export class PrimaryKeyBuilder { + static readonly [entityKind]: string = 'SingleStorePrimaryKeyBuilder'; + + /** @internal */ + columns: SingleStoreColumn[]; + + /** @internal */ + name?: string; + + constructor( + columns: SingleStoreColumn[], + name?: string, + ) { + this.columns = columns; + this.name = name; + } + + /** @internal */ + build(table: SingleStoreTable): PrimaryKey { + return new PrimaryKey(table, this.columns, this.name); + } +} + +export class PrimaryKey { + static readonly [entityKind]: string = 'SingleStorePrimaryKey'; + + readonly columns: SingleStoreColumn[]; + readonly name?: string; + + constructor(readonly table: SingleStoreTable, columns: SingleStoreColumn[], name?: string) { + this.columns = columns; + this.name = name; + } + + getName(): string { + return this.name + ?? `${this.table[SingleStoreTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/attach.ts b/drizzle-orm/src/singlestore-core/query-builders/attach.ts new file mode 100644 index 000000000..ca894ced1 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/attach.ts @@ -0,0 +1,198 @@ +import { entityKind } from '~/entity.ts'; +import { DrizzleError } from '~/errors.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreAttachWithout< + T extends AnySingleStoreAttachBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreAttachBase< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreAttach< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreAttachBase; + +export interface SingleStoreAttachConfig { + milestone?: string | undefined; + time?: Date | undefined; + database: string; + databaseAlias?: string | undefined; + readOnly?: boolean | undefined; +} + +export type SingleStoreAttachPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreAttachDynamic = SingleStoreAttach< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreAttachBase = SingleStoreAttachBase; + +export interface SingleStoreAttachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly database: TDatabase; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreAttachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreAttach'; + + private config: SingleStoreAttachConfig; + + constructor( + private database: TDatabase, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { database }; + } + + as(dabataseAlias: string): SingleStoreAttachWithout { + if (this.config.readOnly) { + throw new DrizzleError({ message: 'Cannot set both databaseAlias and readOnly' }); + } + this.config.databaseAlias = dabataseAlias; + return this as any; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Attach all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Attach all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Attach all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + // TODO(singlestore): docs + atMilestone(milestone: string): SingleStoreAttachWithout { + if (this.config.time) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } + this.config.milestone = milestone; + return this as any; + } + + // TODO(singlestore): docs + atTime(time: Date): SingleStoreAttachWithout { + if (this.config.milestone) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } + this.config.time = time; + return this as any; + } + + // TODO(singlestore): docs + readOnly(): SingleStoreAttachWithout { + if (this.config.databaseAlias) { + throw new DrizzleError({ message: 'Cannot set both databaseAlias and readOnly' }); + } + this.config.readOnly = true; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildAttachQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreAttachPrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreAttachPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreAttachDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/branch.ts b/drizzle-orm/src/singlestore-core/query-builders/branch.ts new file mode 100644 index 000000000..21e2fe0ac --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/branch.ts @@ -0,0 +1,186 @@ +import { entityKind } from '~/entity.ts'; +import { DrizzleError } from '~/errors.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { SingleStoreAttachConfig } from './attach.ts'; + +export type SingleStoreBranchWithout< + T extends AnySingleStoreBranchBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreBranchBase< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreBranch< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreBranchBase; + +export interface SingleStoreBranchConfig extends SingleStoreAttachConfig { + databaseAlias: string; + fromWorkspaceGroup?: string | undefined; +} + +export type SingleStoreBranchPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreBranchDynamic = SingleStoreBranch< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreBranchBase = SingleStoreBranchBase; + +export interface SingleStoreBranchBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly database: TDatabase; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreBranchBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreBranch'; + + private config: SingleStoreBranchConfig; + + constructor( + private database: TDatabase, + private branchName: string, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { database, databaseAlias: branchName }; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Attach all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Attach all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Attach all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + // TODO(singlestore): docs + atMilestone(milestone: string): SingleStoreBranchWithout { + if (this.config.time) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } + this.config.milestone = milestone; + return this as any; + } + + // TODO(singlestore): docs + atTime(time: Date): SingleStoreBranchWithout { + if (this.config.milestone) { + throw new DrizzleError({ message: 'Cannot set both time and milestone' }); + } + this.config.time = time; + return this as any; + } + + // TODO(singlestore): docs + fromWorkspaceGroup(groupID: string): SingleStoreBranchWithout { + this.config.fromWorkspaceGroup = groupID; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildAttachQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreBranchPrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreBranchPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreBranchDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/count.ts b/drizzle-orm/src/singlestore-core/query-builders/count.ts new file mode 100644 index 000000000..931e76a6f --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/count.ts @@ -0,0 +1,79 @@ +import { entityKind } from '~/entity.ts'; +import { SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; +import type { SingleStoreSession } from '../session.ts'; +import type { SingleStoreTable } from '../table.ts'; +import type { SingleStoreViewBase } from '../view-base.ts'; + +export class SingleStoreCountBuilder< + TSession extends SingleStoreSession, +> extends SQL implements Promise, SQLWrapper { + private sql: SQL; + + static override readonly [entityKind] = 'SingleStoreCountBuilder'; + [Symbol.toStringTag] = 'SingleStoreCountBuilder'; + + private session: TSession; + + private static buildEmbeddedCount( + source: SingleStoreTable | SingleStoreViewBase | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; + } + + private static buildCount( + source: SingleStoreTable | SingleStoreViewBase | SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`select count(*) as count from ${source}${sql.raw(' where ').if(filters)}${filters}`; + } + + constructor( + readonly params: { + source: SingleStoreTable | SingleStoreViewBase | SQL | SQLWrapper; + filters?: SQL; + session: TSession; + }, + ) { + super(SingleStoreCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); + + this.mapWith(Number); + + this.session = params.session; + + this.sql = SingleStoreCountBuilder.buildCount( + params.source, + params.filters, + ); + } + + then( + onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, + ): Promise { + return Promise.resolve(this.session.count(this.sql)) + .then( + onfulfilled, + onrejected, + ); + } + + catch( + onRejected?: ((reason: any) => never | PromiseLike) | null | undefined, + ): Promise { + return this.then(undefined, onRejected); + } + + finally(onFinally?: (() => void) | null | undefined): Promise { + return this.then( + (value) => { + onFinally?.(); + return value; + }, + (reason) => { + onFinally?.(); + throw reason; + }, + ); + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts b/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts new file mode 100644 index 000000000..0444d6bf8 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts @@ -0,0 +1,136 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreCreateMilestoneWithout< + T extends AnySingleStoreCreateMilestoneBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreCreateMilestoneBase< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreCreateMilestone< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreCreateMilestoneBase; + +export interface SingleStoreCreateMilestoneConfig { + milestone: string; + database?: string | undefined; +} + +export type SingleStoreCreateMilestonePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreCreateMilestoneDynamic = SingleStoreCreateMilestone< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreCreateMilestoneBase = SingleStoreCreateMilestoneBase; + +export interface SingleStoreCreateMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly milestone: TMilestone; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreCreateMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreCreateMilestone'; + + private config: SingleStoreCreateMilestoneConfig; + + constructor( + private milestone: TMilestone, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { milestone }; + } + + // TODO(singlestore): docs + for(database: string): SingleStoreCreateMilestoneWithout { + this.config.database = database; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildCreateMilestoneQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreCreateMilestonePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreCreateMilestonePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreCreateMilestoneDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/delete.ts b/drizzle-orm/src/singlestore-core/query-builders/delete.ts new file mode 100644 index 000000000..1f41d29ba --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/delete.ts @@ -0,0 +1,207 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; +import type { ValueOrArray } from '~/utils.ts'; +import type { SingleStoreColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; + +export type SingleStoreDeleteWithout< + T extends AnySingleStoreDeleteBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreDeleteBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreDelete< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreDeleteBase; + +export interface SingleStoreDeleteConfig { + where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + table: SingleStoreTable; + returning?: SelectedFieldsOrdered; + withList?: Subquery[]; +} + +export type SingleStoreDeletePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreDeleteDynamic = SingleStoreDelete< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreDeleteBase = SingleStoreDeleteBase; + +export interface SingleStoreDeleteBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreDeleteBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreDelete'; + + private config: SingleStoreDeleteConfig; + + constructor( + private table: TTable, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + withList?: Subquery[], + ) { + super(); + this.config = { table, withList }; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Delete all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Delete all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Delete all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where(where: SQL | undefined): SingleStoreDeleteWithout { + this.config.where = where; + return this as any; + } + + orderBy( + builder: (deleteTable: TTable) => ValueOrArray, + ): SingleStoreDeleteWithout; + orderBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreDeleteWithout; + orderBy( + ...columns: + | [(deleteTable: TTable) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreDeleteWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): SingleStoreDeleteWithout { + this.config.limit = limit; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildDeleteQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreDeletePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + this.config.returning, + ) as SingleStoreDeletePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreDeleteDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/detach.ts b/drizzle-orm/src/singlestore-core/query-builders/detach.ts new file mode 100644 index 000000000..2b74873e2 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/detach.ts @@ -0,0 +1,172 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreDetachWithout< + T extends AnySingleStoreDetachBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreDetachBase< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreDetach< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreDetachBase; + +export interface SingleStoreDetachConfig { + milestone?: string | undefined; + database: string; + workspace?: string | undefined; +} + +export type SingleStoreDetachPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreDetachDynamic = SingleStoreDetach< + T['_']['database'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreDetachBase = SingleStoreDetachBase; + +export interface SingleStoreDetachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly database: TDatabase; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreDetachBase< + TDatabase extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreDetach'; + + private config: SingleStoreDetachConfig; + + constructor( + private database: TDatabase, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { database }; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Detach all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Detach all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Detach all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + // TODO(singlestore): docs + atMilestone(milestone: string): SingleStoreDetachWithout { + this.config.milestone = milestone; + return this as any; + } + + // TODO(singlestore): docs + fromWorkspace(workspace: string): SingleStoreDetachWithout { + this.config.workspace = workspace; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildDetachQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreDetachPrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreDetachPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreDetachDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts b/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts new file mode 100644 index 000000000..66047c991 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts @@ -0,0 +1,136 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; + +export type SingleStoreDropMilestoneWithout< + T extends AnySingleStoreDropMilestoneBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreDropMilestoneBase< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreDropMilestone< + TDatabase extends string = string, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreDropMilestoneBase; + +export interface SingleStoreDropMilestoneConfig { + milestone: string; + database?: string | undefined; +} + +export type SingleStoreDropMilestonePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreDropMilestoneDynamic = SingleStoreDropMilestone< + T['_']['milestone'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreDropMilestoneBase = SingleStoreDropMilestoneBase; + +export interface SingleStoreDropMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly milestone: TMilestone; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreDropMilestoneBase< + TMilestone extends string, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreDropMilestone'; + + private config: SingleStoreDropMilestoneConfig; + + constructor( + private milestone: TMilestone, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { milestone }; + } + + // TODO(singlestore): docs + for(database: string): SingleStoreDropMilestoneWithout { + this.config.database = database; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildDropMilestoneQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreDropMilestonePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreDropMilestonePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreDropMilestoneDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/index.ts b/drizzle-orm/src/singlestore-core/query-builders/index.ts new file mode 100644 index 000000000..95de476cd --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/index.ts @@ -0,0 +1,12 @@ +export * from './attach.ts'; +export * from './branch.ts'; +export * from './count.ts'; +export * from './createMilestone.ts'; +export * from './delete.ts'; +export * from './detach.ts'; +export * from './insert.ts'; +export * from './optimizeTable.ts'; +export * from './query-builder.ts'; +export * from './select.ts'; +export * from './select.types.ts'; +export * from './update.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/insert.ts b/drizzle-orm/src/singlestore-core/query-builders/insert.ts new file mode 100644 index 000000000..78a19c784 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/insert.ts @@ -0,0 +1,305 @@ +import { entityKind, is } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { RunnableQuery } from '~/runnable-query.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; +import { Param, SQL, sql } from '~/sql/sql.ts'; +import type { InferModelFromColumns } from '~/table.ts'; +import { Table } from '~/table.ts'; +import { mapUpdateSet, orderSelectedFields } from '~/utils.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; +import type { SingleStoreUpdateSetSource } from './update.ts'; + +export interface SingleStoreInsertConfig { + table: TTable; + values: Record[]; + ignore: boolean; + onConflict?: SQL; + returning?: SelectedFieldsOrdered; +} + +export type AnySingleStoreInsertConfig = SingleStoreInsertConfig; + +export type SingleStoreInsertValue = + & { + [Key in keyof TTable['$inferInsert']]: TTable['$inferInsert'][Key] | SQL | Placeholder; + } + & {}; + +export class SingleStoreInsertBuilder< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> { + static readonly [entityKind]: string = 'SingleStoreInsertBuilder'; + + private shouldIgnore = false; + + constructor( + private table: TTable, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) {} + + ignore(): this { + this.shouldIgnore = true; + return this; + } + + values(value: SingleStoreInsertValue): SingleStoreInsertBase; + values(values: SingleStoreInsertValue[]): SingleStoreInsertBase; + values( + values: SingleStoreInsertValue | SingleStoreInsertValue[], + ): SingleStoreInsertBase { + values = Array.isArray(values) ? values : [values]; + if (values.length === 0) { + throw new Error('values() must be called with at least one value'); + } + const mappedValues = values.map((entry) => { + const result: Record = {}; + const cols = this.table[Table.Symbol.Columns]; + for (const colKey of Object.keys(entry)) { + const colValue = entry[colKey as keyof typeof entry]; + result[colKey] = is(colValue, SQL) ? colValue : new Param(colValue, cols[colKey]); + } + return result; + }); + + return new SingleStoreInsertBase(this.table, mappedValues, this.shouldIgnore, this.session, this.dialect); + } +} + +export type SingleStoreInsertWithout< + T extends AnySingleStoreInsert, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + T['_']['returning'], + TDynamic, + T['_']['excludedMethods'] | '$returning' + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreInsertDynamic = SingleStoreInsert< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + T['_']['returning'] +>; + +export type SingleStoreInsertPrepare< + T extends AnySingleStoreInsert, + TReturning extends Record | undefined = undefined, +> = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[]; + iterator: never; + }, + true +>; + +export type SingleStoreInsertOnDuplicateKeyUpdateConfig = { + set: SingleStoreUpdateSetSource; +}; + +export type SingleStoreInsert< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TReturning extends Record | undefined = Record | undefined, +> = SingleStoreInsertBase; + +export type SingleStoreInsertReturning< + T extends AnySingleStoreInsert, + TDynamic extends boolean, +> = SingleStoreInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + InferModelFromColumns>, + TDynamic, + T['_']['excludedMethods'] | '$returning' +>; + +export type AnySingleStoreInsert = SingleStoreInsertBase; + +export interface SingleStoreInsertBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TReturning extends Record | undefined = undefined, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends + QueryPromise : TReturning[]>, + RunnableQuery< + TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[], + 'singlestore' + >, + SQLWrapper +{ + readonly _: { + readonly dialect: 'singlestore'; + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly returning: TReturning; + readonly result: TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[]; + }; +} + +export type PrimaryKeyKeys> = { + [K in keyof T]: T[K]['_']['isPrimaryKey'] extends true ? T[K]['_']['isAutoincrement'] extends true ? K + : T[K]['_']['hasRuntimeDefault'] extends true ? T[K]['_']['isPrimaryKey'] extends true ? K : never + : never + : T[K]['_']['hasRuntimeDefault'] extends true ? T[K]['_']['isPrimaryKey'] extends true ? K : never + : never; +}[keyof T]; + +export type GetPrimarySerialOrDefaultKeys> = { + [K in PrimaryKeyKeys]: T[K]; +}; + +export class SingleStoreInsertBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TReturning extends Record | undefined = undefined, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise : TReturning[]> + implements + RunnableQuery< + TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[], + 'singlestore' + >, + SQLWrapper +{ + static override readonly [entityKind]: string = 'SingleStoreInsert'; + + declare protected $table: TTable; + + private config: SingleStoreInsertConfig; + + constructor( + table: TTable, + values: SingleStoreInsertConfig['values'], + ignore: boolean, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { table, values, ignore }; + } + + /** + * Adds an `on duplicate key update` clause to the query. + * + * Calling this method will update update the row if any unique index conflicts. SingleStore will automatically determine the conflict target based on the primary key and unique indexes. + * + * See docs: {@link https://orm.drizzle.team/docs/insert#on-duplicate-key-update} + * + * @param config The `set` clause + * + * @example + * ```ts + * await db.insert(cars) + * .values({ id: 1, brand: 'BMW'}) + * .onDuplicateKeyUpdate({ set: { brand: 'Porsche' }}); + * ``` + * + * While SingleStore does not directly support doing nothing on conflict, you can perform a no-op by setting any column's value to itself and achieve the same effect: + * + * ```ts + * import { sql } from 'drizzle-orm'; + * + * await db.insert(cars) + * .values({ id: 1, brand: 'BMW' }) + * .onDuplicateKeyUpdate({ set: { id: sql`id` } }); + * ``` + */ + onDuplicateKeyUpdate( + config: SingleStoreInsertOnDuplicateKeyUpdateConfig, + ): SingleStoreInsertWithout { + const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set)); + this.config.onConflict = sql`update ${setSql}`; + return this as any; + } + + $returningId(): SingleStoreInsertWithout< + SingleStoreInsertReturning, + TDynamic, + '$returningId' + > { + const returning: SelectedFieldsOrdered = []; + for (const [key, value] of Object.entries(this.config.table[Table.Symbol.Columns])) { + if (value.primary) { + returning.push({ field: value, path: [key] }); + } + } + this.config.returning = orderSelectedFields(this.config.table[Table.Symbol.Columns]); + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildInsertQuery(this.config).sql; + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreInsertPrepare { + const { sql, generatedIds } = this.dialect.buildInsertQuery(this.config); + return this.session.prepareQuery( + this.dialect.sqlToQuery(sql), + undefined, + undefined, + generatedIds, + this.config.returning, + ) as SingleStoreInsertPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreInsertDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts new file mode 100644 index 000000000..3e174c869 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts @@ -0,0 +1,158 @@ +import { entityKind } from '~/entity.ts'; +import type { ColumnBaseConfig, ColumnDataType } from '~/index.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { SingleStoreColumn } from '../columns/common.ts'; +import type { SingleStoreTable } from '../table.ts'; + +export type OptimizeTableArgument = + | 'FULL' + | 'FLUSH' + | 'FIX_ALTER' + | 'INDEX'; + +export type SingleStoreOptimizeTableWithout< + T extends AnySingleStoreOptimizeTableBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreOptimizeTableBase< + T['_']['table'], + T['_']['arg'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreOptimizeTable< + TTable extends SingleStoreTable = SingleStoreTable, + TArg extends OptimizeTableArgument = OptimizeTableArgument, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreOptimizeTableBase; + +export interface SingleStoreOptimizeTableConfig { + table: SingleStoreTable; + arg?: OptimizeTableArgument | undefined; + selection?: SingleStoreColumn, object>[] | undefined; +} + +export type SingleStoreOptimizeTablePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreOptimizeTableDynamic = SingleStoreOptimizeTable< + T['_']['table'], + T['_']['arg'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreOptimizeTableBase = SingleStoreOptimizeTableBase; + +export interface SingleStoreOptimizeTableBase< + TTable extends SingleStoreTable, + TArg extends OptimizeTableArgument, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly table: TTable; + readonly arg: TArg | undefined; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreOptimizeTableBase< + TTable extends SingleStoreTable, + TArg extends OptimizeTableArgument, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreOptimizeTable'; + + private config: SingleStoreOptimizeTableConfig; + + constructor( + private table: TTable, + private arg: TArg | undefined, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { table, arg }; + } + + // TODO(singlestore): docs + warmBlobCacheForColumn( + ...selection: SingleStoreColumn, object>[] + ): SingleStoreOptimizeTableWithout { + if (this.config.arg) { + throw new Error('Cannot call warmBlobCacheForColumn with an argument'); + } + this.config.selection = selection; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildOptimizeTable(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreOptimizeTablePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + undefined, + ) as SingleStoreOptimizeTablePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreOptimizeTableDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts b/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts new file mode 100644 index 000000000..29d6c2290 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts @@ -0,0 +1,114 @@ +import { entityKind, is } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreDialectConfig } from '~/singlestore-core/dialect.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { WithSubqueryWithSelection } from '~/singlestore-core/subquery.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import { WithSubquery } from '~/subquery.ts'; +import { SingleStoreSelectBuilder } from './select.ts'; +import type { SelectedFields } from './select.types.ts'; + +export class QueryBuilder { + static readonly [entityKind]: string = 'SingleStoreQueryBuilder'; + + private dialect: SingleStoreDialect | undefined; + private dialectConfig: SingleStoreDialectConfig | undefined; + + constructor(dialect?: SingleStoreDialect | SingleStoreDialectConfig) { + this.dialect = is(dialect, SingleStoreDialect) ? dialect : undefined; + this.dialectConfig = is(dialect, SingleStoreDialect) ? undefined : dialect; + } + + $with(alias: TAlias) { + const queryBuilder = this; + + return { + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): WithSubqueryWithSelection { + if (typeof qb === 'function') { + qb = qb(queryBuilder); + } + + return new Proxy( + new WithSubquery(qb.getSQL(), qb.getSelectedFields() as SelectedFields, alias, true), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as WithSubqueryWithSelection; + }, + }; + } + + with(...queries: WithSubquery[]) { + const self = this; + + function select(): SingleStoreSelectBuilder; + function select( + fields: TSelection, + ): SingleStoreSelectBuilder; + function select( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: self.getDialect(), + withList: queries, + }); + } + + function selectDistinct(): SingleStoreSelectBuilder; + function selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + function selectDistinct( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: self.getDialect(), + withList: queries, + distinct: true, + }); + } + + return { select, selectDistinct }; + } + + select(): SingleStoreSelectBuilder; + select(fields: TSelection): SingleStoreSelectBuilder; + select( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: this.getDialect(), + }); + } + + selectDistinct(): SingleStoreSelectBuilder; + selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + selectDistinct( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: this.getDialect(), + distinct: true, + }); + } + + // Lazy load dialect to avoid circular dependency + private getDialect() { + if (!this.dialect) { + this.dialect = new SingleStoreDialect(this.dialectConfig); + } + + return this.dialect; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/query.ts b/drizzle-orm/src/singlestore-core/query-builders/query.ts new file mode 100644 index 000000000..c15f7ad59 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/query.ts @@ -0,0 +1,141 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { + type BuildQueryResult, + type BuildRelationalQueryResult, + type DBQueryConfig, + mapRelationalRow, + type TableRelationalConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import type { Query, QueryWithTypings, SQL } from '~/sql/sql.ts'; +import type { KnownKeysOnly } from '~/utils.ts'; +import type { SingleStoreDialect } from '../dialect.ts'; +import type { + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreSession, +} from '../session.ts'; +import type { SingleStoreTable } from '../table.ts'; + +export class RelationalQueryBuilder< + TPreparedQueryHKT extends PreparedQueryHKTBase, + TSchema extends TablesRelationalConfig, + TFields extends TableRelationalConfig, +> { + static readonly [entityKind]: string = 'SingleStoreRelationalQueryBuilder'; + + constructor( + private fullSchema: Record, + private schema: TSchema, + private tableNamesMap: Record, + private table: SingleStoreTable, + private tableConfig: TableRelationalConfig, + private dialect: SingleStoreDialect, + private session: SingleStoreSession, + ) {} + + findMany>( + config?: KnownKeysOnly>, + ): SingleStoreRelationalQuery[]> { + return new SingleStoreRelationalQuery( + this.fullSchema, + this.schema, + this.tableNamesMap, + this.table, + this.tableConfig, + this.dialect, + this.session, + config ? (config as DBQueryConfig<'many', true>) : {}, + 'many', + ); + } + + findFirst, 'limit'>>( + config?: KnownKeysOnly, 'limit'>>, + ): SingleStoreRelationalQuery | undefined> { + return new SingleStoreRelationalQuery( + this.fullSchema, + this.schema, + this.tableNamesMap, + this.table, + this.tableConfig, + this.dialect, + this.session, + config ? { ...(config as DBQueryConfig<'many', true> | undefined), limit: 1 } : { limit: 1 }, + 'first', + ); + } +} + +export class SingleStoreRelationalQuery< + TPreparedQueryHKT extends PreparedQueryHKTBase, + TResult, +> extends QueryPromise { + static override readonly [entityKind]: string = 'SingleStoreRelationalQuery'; + + declare protected $brand: 'SingleStoreRelationalQuery'; + + constructor( + private fullSchema: Record, + private schema: TablesRelationalConfig, + private tableNamesMap: Record, + private table: SingleStoreTable, + private tableConfig: TableRelationalConfig, + private dialect: SingleStoreDialect, + private session: SingleStoreSession, + private config: DBQueryConfig<'many', true> | true, + private queryMode: 'many' | 'first', + ) { + super(); + } + + prepare() { + const { query, builtQuery } = this._toSQL(); + return this.session.prepareQuery( + builtQuery, + undefined, + (rawRows) => { + const rows = rawRows.map((row) => mapRelationalRow(this.schema, this.tableConfig, row, query.selection)); + if (this.queryMode === 'first') { + return rows[0] as TResult; + } + return rows as TResult; + }, + ) as PreparedQueryKind; + } + + private _getQuery() { + return this.dialect.buildRelationalQuery({ + fullSchema: this.fullSchema, + schema: this.schema, + tableNamesMap: this.tableNamesMap, + table: this.table, + tableConfig: this.tableConfig, + queryConfig: this.config, + tableAlias: this.tableConfig.tsName, + }); + } + + private _toSQL(): { query: BuildRelationalQueryResult; builtQuery: QueryWithTypings } { + const query = this._getQuery(); + + const builtQuery = this.dialect.sqlToQuery(query.sql as SQL); + + return { builtQuery, query }; + } + + /** @internal */ + getSQL(): SQL { + return this._getQuery().sql as SQL; + } + + toSQL(): Query { + return this._toSQL().builtQuery; + } + + override execute(): Promise { + return this.prepare().execute(); + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.ts b/drizzle-orm/src/singlestore-core/query-builders/select.ts new file mode 100644 index 000000000..0fcefaf85 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/select.ts @@ -0,0 +1,1084 @@ +import { entityKind, is } from '~/entity.ts'; +import { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { + BuildSubquerySelection, + GetSelectTableName, + GetSelectTableSelection, + JoinNullability, + JoinType, + SelectMode, + SelectResult, + SetOperator, +} from '~/query-builders/select.types.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreColumn } from '~/singlestore-core/columns/index.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + PreparedQueryHKTBase, + SingleStorePreparedQueryConfig, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SubqueryWithSelection } from '~/singlestore-core/subquery.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { ColumnsSelection, Query } from '~/sql/sql.ts'; +import { SQL, View } from '~/sql/sql.ts'; +import { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; +import { + applyMixins, + getTableColumns, + getTableLikeName, + haveSameKeys, + orderSelectedFields, + type ValueOrArray, +} from '~/utils.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import { SingleStoreViewBase } from '../view-base.ts'; +import type { + AnySingleStoreSelect, + CreateSingleStoreSelectFromBuilderMode, + GetSingleStoreSetOperators, + LockConfig, + LockStrength, + SelectedFields, + SetOperatorRightSelect, + SingleStoreCreateSetOperatorFn, + SingleStoreJoinFn, + SingleStoreSelectConfig, + SingleStoreSelectDynamic, + SingleStoreSelectHKT, + SingleStoreSelectHKTBase, + SingleStoreSelectPrepare, + SingleStoreSelectWithout, + SingleStoreSetOperatorExcludedMethods, + SingleStoreSetOperatorWithResult, +} from './select.types.ts'; + +export class SingleStoreSelectBuilder< + TSelection extends SelectedFields | undefined, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TBuilderMode extends 'db' | 'qb' = 'db', +> { + static readonly [entityKind]: string = 'SingleStoreSelectBuilder'; + + private fields: TSelection; + private session: SingleStoreSession | undefined; + private dialect: SingleStoreDialect; + private withList: Subquery[] = []; + private distinct: boolean | undefined; + + constructor( + config: { + fields: TSelection; + session: SingleStoreSession | undefined; + dialect: SingleStoreDialect; + withList?: Subquery[]; + distinct?: boolean; + }, + ) { + this.fields = config.fields; + this.session = config.session; + this.dialect = config.dialect; + if (config.withList) { + this.withList = config.withList; + } + this.distinct = config.distinct; + } + + from( + source: TFrom, + ): CreateSingleStoreSelectFromBuilderMode< + TBuilderMode, + GetSelectTableName, + TSelection extends undefined ? GetSelectTableSelection : TSelection, + TSelection extends undefined ? 'single' : 'partial', + TPreparedQueryHKT + > { + const isPartialSelect = !!this.fields; + + let fields: SelectedFields; + if (this.fields) { + fields = this.fields; + } else if (is(source, Subquery)) { + // This is required to use the proxy handler to get the correct field values from the subquery + fields = Object.fromEntries( + Object.keys(source._.selectedFields).map(( + key, + ) => [key, source[key as unknown as keyof typeof source] as unknown as SelectedFields[string]]), + ); + } else if (is(source, SingleStoreViewBase)) { + fields = source[ViewBaseConfig].selectedFields as SelectedFields; + } else if (is(source, SQL)) { + fields = {}; + } else { + fields = getTableColumns(source); + } + + return new SingleStoreSelectBase( + { + table: source, + fields, + isPartialSelect, + session: this.session, + dialect: this.dialect, + withList: this.withList, + distinct: this.distinct, + }, + ) as any; + } +} + +export abstract class SingleStoreSelectQueryBuilderBase< + THKT extends SingleStoreSelectHKTBase, + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends TypedQueryBuilder { + static override readonly [entityKind]: string = 'SingleStoreSelectQueryBuilder'; + + override readonly _: { + readonly hkt: THKT; + readonly tableName: TTableName; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; + }; + + protected config: SingleStoreSelectConfig; + protected joinsNotNullableMap: Record; + private tableName: string | undefined; + private isPartialSelect: boolean; + /** @internal */ + readonly session: SingleStoreSession | undefined; + protected dialect: SingleStoreDialect; + + constructor( + { table, fields, isPartialSelect, session, dialect, withList, distinct }: { + table: SingleStoreSelectConfig['table']; + fields: SingleStoreSelectConfig['fields']; + isPartialSelect: boolean; + session: SingleStoreSession | undefined; + dialect: SingleStoreDialect; + withList: Subquery[]; + distinct: boolean | undefined; + }, + ) { + super(); + this.config = { + withList, + table, + fields: { ...fields }, + distinct, + setOperators: [], + }; + this.isPartialSelect = isPartialSelect; + this.session = session; + this.dialect = dialect; + this._ = { + selectedFields: fields as TSelectedFields, + } as this['_']; + this.tableName = getTableLikeName(table); + this.joinsNotNullableMap = typeof this.tableName === 'string' ? { [this.tableName]: true } : {}; + } + + private createJoin( + joinType: TJoinType, + ): SingleStoreJoinFn { + return ( + table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL, + on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, + ) => { + const baseTableName = this.tableName; + const tableName = getTableLikeName(table); + + if (typeof tableName === 'string' && this.config.joins?.some((join) => join.alias === tableName)) { + throw new Error(`Alias "${tableName}" is already used in this query`); + } + + if (!this.isPartialSelect) { + // If this is the first join and this is not a partial select and we're not selecting from raw SQL, "move" the fields from the main table to the nested object + if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === 'string') { + this.config.fields = { + [baseTableName]: this.config.fields, + }; + } + if (typeof tableName === 'string' && !is(table, SQL)) { + const selection = is(table, Subquery) + ? table._.selectedFields + : is(table, View) + ? table[ViewBaseConfig].selectedFields + : table[Table.Symbol.Columns]; + this.config.fields[tableName] = selection; + } + } + + if (typeof on === 'function') { + on = on( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + + if (!this.config.joins) { + this.config.joins = []; + } + + this.config.joins.push({ on, table, joinType, alias: tableName }); + + if (typeof tableName === 'string') { + switch (joinType) { + case 'left': { + this.joinsNotNullableMap[tableName] = false; + break; + } + case 'right': { + this.joinsNotNullableMap = Object.fromEntries( + Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]), + ); + this.joinsNotNullableMap[tableName] = true; + break; + } + case 'inner': { + this.joinsNotNullableMap[tableName] = true; + break; + } + case 'full': { + this.joinsNotNullableMap = Object.fromEntries( + Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]), + ); + this.joinsNotNullableMap[tableName] = false; + break; + } + } + } + + return this as any; + }; + } + + /** + * Executes a `left join` operation by adding another table to the current query. + * + * Calling this method associates each row of the table with the corresponding row from the joined table, if a match is found. If no matching row exists, it sets all columns of the joined table to null. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#left-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User; pets: Pet | null }[] = await db.select() + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + leftJoin = this.createJoin('left'); + + /** + * Executes a `right join` operation by adding another table to the current query. + * + * Calling this method associates each row of the joined table with the corresponding row from the main table, if a match is found. If no matching row exists, it sets all columns of the main table to null. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#right-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User | null; pets: Pet }[] = await db.select() + * .from(users) + * .rightJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number | null; petId: number }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .rightJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + rightJoin = this.createJoin('right'); + + /** + * Executes an `inner join` operation, creating a new table by combining rows from two tables that have matching values. + * + * Calling this method retrieves rows that have corresponding entries in both joined tables. Rows without matching entries in either table are excluded, resulting in a table that includes only matching pairs. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#inner-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User; pets: Pet }[] = await db.select() + * .from(users) + * .innerJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number; petId: number }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .innerJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + innerJoin = this.createJoin('inner'); + + /** + * Executes a `full join` operation by combining rows from two tables into a new table. + * + * Calling this method retrieves all rows from both main and joined tables, merging rows with matching values and filling in `null` for non-matching columns. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#full-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User | null; pets: Pet | null }[] = await db.select() + * .from(users) + * .fullJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number | null; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .fullJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + fullJoin = this.createJoin('full'); + + private createSetOperator( + type: SetOperator, + isAll: boolean, + ): >( + rightSelection: + | ((setOperators: GetSingleStoreSetOperators) => SetOperatorRightSelect) + | SetOperatorRightSelect, + ) => SingleStoreSelectWithout< + this, + TDynamic, + SingleStoreSetOperatorExcludedMethods, + true + > { + return (rightSelection) => { + const rightSelect = (typeof rightSelection === 'function' + ? rightSelection(getSingleStoreSetOperators()) + : rightSelection) as TypedQueryBuilder< + any, + TResult + >; + + if (!haveSameKeys(this.getSelectedFields(), rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + + this.config.setOperators.push({ type, isAll, rightSelect }); + return this as any; + }; + } + + /** + * Adds `union` set operator to the query. + * + * Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union} + * + * @example + * + * ```ts + * // Select all unique names from customers and users tables + * await db.select({ name: users.name }) + * .from(users) + * .union( + * db.select({ name: customers.name }).from(customers) + * ); + * // or + * import { union } from 'drizzle-orm/singlestore-core' + * + * await union( + * db.select({ name: users.name }).from(users), + * db.select({ name: customers.name }).from(customers) + * ); + * ``` + */ + union = this.createSetOperator('union', false); + + /** + * Adds `union all` set operator to the query. + * + * Calling this method will combine the result-set of the `select` statements and keep all duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union-all} + * + * @example + * + * ```ts + * // Select all transaction ids from both online and in-store sales + * await db.select({ transaction: onlineSales.transactionId }) + * .from(onlineSales) + * .unionAll( + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * // or + * import { unionAll } from 'drizzle-orm/singlestore-core' + * + * await unionAll( + * db.select({ transaction: onlineSales.transactionId }).from(onlineSales), + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * ``` + */ + unionAll = this.createSetOperator('union', true); + + /** + * Adds `intersect` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets and eliminate duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect} + * + * @example + * + * ```ts + * // Select course names that are offered in both departments A and B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .intersect( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * import { intersect } from 'drizzle-orm/singlestore-core' + * + * await intersect( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ + intersect = this.createSetOperator('intersect', false); + + /** + * Adds `except` set operator to the query. + * + * Calling this method will retrieve all unique rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except} + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .except( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * import { except } from 'drizzle-orm/singlestore-core' + * + * await except( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ + except = this.createSetOperator('except', false); + + /** + * Adds `minus` set operator to the query. + * + * This is an alias of `except` supported by SingleStore. + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .minus( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * import { minus } from 'drizzle-orm/singlestore-core' + * + * await minus( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ + minus = this.createSetOperator('except', false); + + /** @internal */ + addSetOperators(setOperators: SingleStoreSelectConfig['setOperators']): SingleStoreSelectWithout< + this, + TDynamic, + SingleStoreSetOperatorExcludedMethods, + true + > { + this.config.setOperators.push(...setOperators); + return this as any; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will select only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/select#filtering} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be selected. + * + * ```ts + * // Select all cars with green color + * await db.select().from(cars).where(eq(cars.color, 'green')); + * // or + * await db.select().from(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Select all BMW cars with a green color + * await db.select().from(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Select all cars with the green or blue color + * await db.select().from(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where( + where: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): SingleStoreSelectWithout { + if (typeof where === 'function') { + where = where( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + this.config.where = where; + return this as any; + } + + /** + * Adds a `having` clause to the query. + * + * Calling this method will select only those rows that fulfill a specified condition. It is typically used with aggregate functions to filter the aggregated data based on a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/select#aggregations} + * + * @param having the `having` clause. + * + * @example + * + * ```ts + * // Select all brands with more than one car + * await db.select({ + * brand: cars.brand, + * count: sql`cast(count(${cars.id}) as int)`, + * }) + * .from(cars) + * .groupBy(cars.brand) + * .having(({ count }) => gt(count, 1)); + * ``` + */ + having( + having: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): SingleStoreSelectWithout { + if (typeof having === 'function') { + having = having( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + this.config.having = having; + return this as any; + } + + /** + * Adds a `group by` clause to the query. + * + * Calling this method will group rows that have the same values into summary rows, often used for aggregation purposes. + * + * See docs: {@link https://orm.drizzle.team/docs/select#aggregations} + * + * @example + * + * ```ts + * // Group and count people by their last names + * await db.select({ + * lastName: people.lastName, + * count: sql`cast(count(*) as int)` + * }) + * .from(people) + * .groupBy(people.lastName); + * ``` + */ + groupBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): SingleStoreSelectWithout; + groupBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreSelectWithout; + groupBy( + ...columns: + | [(aliases: this['_']['selection']) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreSelectWithout { + if (typeof columns[0] === 'function') { + const groupBy = columns[0]( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as TSelection, + ); + this.config.groupBy = Array.isArray(groupBy) ? groupBy : [groupBy]; + } else { + this.config.groupBy = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + } + return this as any; + } + + /** + * Adds an `order by` clause to the query. + * + * Calling this method will sort the result-set in ascending or descending order. By default, the sort order is ascending. + * + * See docs: {@link https://orm.drizzle.team/docs/select#order-by} + * + * @example + * + * ``` + * // Select cars ordered by year + * await db.select().from(cars).orderBy(cars.year); + * ``` + * + * You can specify whether results are in ascending or descending order with the `asc()` and `desc()` operators. + * + * ```ts + * // Select cars ordered by year in descending order + * await db.select().from(cars).orderBy(desc(cars.year)); + * + * // Select cars ordered by year and price + * await db.select().from(cars).orderBy(asc(cars.year), desc(cars.price)); + * ``` + */ + orderBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): SingleStoreSelectWithout; + orderBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreSelectWithout; + orderBy( + ...columns: + | [(aliases: this['_']['selection']) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreSelectWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as TSelection, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } + } else { + const orderByArray = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } + } + return this as any; + } + + /** + * Adds a `limit` clause to the query. + * + * Calling this method will set the maximum number of rows that will be returned by this query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset} + * + * @param limit the `limit` clause. + * + * @example + * + * ```ts + * // Get the first 10 people from this query. + * await db.select().from(people).limit(10); + * ``` + */ + limit(limit: number): SingleStoreSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.limit = limit; + } else { + this.config.limit = limit; + } + return this as any; + } + + /** + * Adds an `offset` clause to the query. + * + * Calling this method will skip a number of rows when returning results from this query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset} + * + * @param offset the `offset` clause. + * + * @example + * + * ```ts + * // Get the 10th-20th people from this query. + * await db.select().from(people).offset(10).limit(10); + * ``` + */ + offset(offset: number): SingleStoreSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.offset = offset; + } else { + this.config.offset = offset; + } + return this as any; + } + + /** + * Adds a `for` clause to the query. + * + * Calling this method will specify a lock strength for this query that controls how strictly it acquires exclusive access to the rows being queried. + * + * @param strength the lock strength. + * @param config the lock configuration. + */ + for(strength: LockStrength, config: LockConfig = {}): SingleStoreSelectWithout { + this.config.lockingClause = { strength, config }; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildSelectQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + as( + alias: TAlias, + ): SubqueryWithSelection { + return new Proxy( + new Subquery(this.getSQL(), this.config.fields, alias), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as SubqueryWithSelection; + } + + /** @internal */ + override getSelectedFields(): this['_']['selectedFields'] { + return new Proxy( + this.config.fields, + new SelectionProxyHandler({ alias: this.tableName, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as this['_']['selectedFields']; + } + + $dynamic(): SingleStoreSelectDynamic { + return this as any; + } +} + +export interface SingleStoreSelectBase< + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends + SingleStoreSelectQueryBuilderBase< + SingleStoreSelectHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + QueryPromise +{} + +export class SingleStoreSelectBase< + TTableName extends string | undefined, + TSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, +> extends SingleStoreSelectQueryBuilderBase< + SingleStoreSelectHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields +> { + static override readonly [entityKind]: string = 'SingleStoreSelect'; + + prepare(): SingleStoreSelectPrepare { + if (!this.session) { + throw new Error('Cannot execute a query on a query builder. Please use a database instance instead.'); + } + const fieldsList = orderSelectedFields(this.config.fields); + const query = this.session.prepareQuery< + SingleStorePreparedQueryConfig & { execute: SelectResult[] }, + TPreparedQueryHKT + >(this.dialect.sqlToQuery(this.getSQL()), fieldsList); + query.joinsNotNullableMap = this.joinsNotNullableMap; + return query as SingleStoreSelectPrepare; + } + + execute = ((placeholderValues) => { + return this.prepare().execute(placeholderValues); + }) as ReturnType['execute']; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); +} + +applyMixins(SingleStoreSelectBase, [QueryPromise]); + +function createSetOperator(type: SetOperator, isAll: boolean): SingleStoreCreateSetOperatorFn { + return (leftSelect, rightSelect, ...restSelects) => { + const setOperators = [rightSelect, ...restSelects].map((select) => ({ + type, + isAll, + rightSelect: select as AnySingleStoreSelect, + })); + + for (const setOperator of setOperators) { + if (!haveSameKeys((leftSelect as any).getSelectedFields(), setOperator.rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + } + + return (leftSelect as AnySingleStoreSelect).addSetOperators(setOperators) as any; + }; +} + +const getSingleStoreSetOperators = () => ({ + union, + unionAll, + intersect, + except, + minus, +}); + +/** + * Adds `union` set operator to the query. + * + * Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union} + * + * @example + * + * ```ts + * // Select all unique names from customers and users tables + * import { union } from 'drizzle-orm/singlestore-core' + * + * await union( + * db.select({ name: users.name }).from(users), + * db.select({ name: customers.name }).from(customers) + * ); + * // or + * await db.select({ name: users.name }) + * .from(users) + * .union( + * db.select({ name: customers.name }).from(customers) + * ); + * ``` + */ +export const union = createSetOperator('union', false); + +/** + * Adds `union all` set operator to the query. + * + * Calling this method will combine the result-set of the `select` statements and keep all duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union-all} + * + * @example + * + * ```ts + * // Select all transaction ids from both online and in-store sales + * import { unionAll } from 'drizzle-orm/singlestore-core' + * + * await unionAll( + * db.select({ transaction: onlineSales.transactionId }).from(onlineSales), + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * // or + * await db.select({ transaction: onlineSales.transactionId }) + * .from(onlineSales) + * .unionAll( + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * ``` + */ +export const unionAll = createSetOperator('union', true); + +/** + * Adds `intersect` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets and eliminate duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect} + * + * @example + * + * ```ts + * // Select course names that are offered in both departments A and B + * import { intersect } from 'drizzle-orm/singlestore-core' + * + * await intersect( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .intersect( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ +export const intersect = createSetOperator('intersect', false); + +/** + * Adds `except` set operator to the query. + * + * Calling this method will retrieve all unique rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except} + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * import { except } from 'drizzle-orm/singlestore-core' + * + * await except( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .except( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ +export const except = createSetOperator('except', false); + +/** + * Adds `minus` set operator to the query. + * + * This is an alias of `except` supported by SingleStore. + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * import { minus } from 'drizzle-orm/singlestore-core' + * + * await minus( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .minus( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ +export const minus = createSetOperator('except', true); diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts new file mode 100644 index 000000000..6db1cc357 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts @@ -0,0 +1,457 @@ +import type { + SelectedFields as SelectedFieldsBase, + SelectedFieldsFlat as SelectedFieldsFlatBase, + SelectedFieldsOrdered as SelectedFieldsOrderedBase, +} from '~/operations.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { + AppendToNullabilityMap, + AppendToResult, + BuildSubquerySelection, + GetSelectTableName, + JoinNullability, + JoinType, + MapColumnsToTableAlias, + SelectMode, + SelectResult, + SetOperator, +} from '~/query-builders/select.types.ts'; +import type { SingleStoreColumn } from '~/singlestore-core/columns/index.ts'; +import type { SingleStoreTable, SingleStoreTableWithColumns } from '~/singlestore-core/table.ts'; +import type { ColumnsSelection, Placeholder, SQL, View } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import type { Table, UpdateTableConfig } from '~/table.ts'; +import type { Assume, ValidateShape } from '~/utils.ts'; +import type { PreparedQueryHKTBase, PreparedQueryKind, SingleStorePreparedQueryConfig } from '../session.ts'; +import type { SingleStoreViewBase } from '../view-base.ts'; +import type { SingleStoreViewWithSelection } from '../view.ts'; +import type { SingleStoreSelectBase, SingleStoreSelectQueryBuilderBase } from './select.ts'; + +export interface SingleStoreSelectJoinConfig { + on: SQL | undefined; + table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL; + alias: string | undefined; + joinType: JoinType; + lateral?: boolean; +} + +export type BuildAliasTable = TTable extends Table + ? SingleStoreTableWithColumns< + UpdateTableConfig; + }> + > + : TTable extends View ? SingleStoreViewWithSelection< + TAlias, + TTable['_']['existing'], + MapColumnsToTableAlias + > + : never; + +export interface SingleStoreSelectConfig { + withList?: Subquery[]; + fields: Record; + fieldsFlat?: SelectedFieldsOrdered; + where?: SQL; + having?: SQL; + table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL; + limit?: number | Placeholder; + offset?: number | Placeholder; + joins?: SingleStoreSelectJoinConfig[]; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + groupBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + lockingClause?: { + strength: LockStrength; + config: LockConfig; + }; + distinct?: boolean; + setOperators: { + rightSelect: TypedQueryBuilder; + type: SetOperator; + isAll: boolean; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + limit?: number | Placeholder; + offset?: number | Placeholder; + }[]; +} + +export type SingleStoreJoin< + T extends AnySingleStoreSelectQueryBuilder, + TDynamic extends boolean, + TJoinType extends JoinType, + TJoinedTable extends SingleStoreTable | Subquery | SingleStoreViewBase | SQL, + TJoinedName extends GetSelectTableName = GetSelectTableName, +> = T extends any ? SingleStoreSelectWithout< + SingleStoreSelectKind< + T['_']['hkt'], + T['_']['tableName'], + AppendToResult< + T['_']['tableName'], + T['_']['selection'], + TJoinedName, + TJoinedTable extends SingleStoreTable ? TJoinedTable['_']['columns'] + : TJoinedTable extends Subquery ? Assume + : never, + T['_']['selectMode'] + >, + T['_']['selectMode'] extends 'partial' ? T['_']['selectMode'] : 'multiple', + T['_']['preparedQueryHKT'], + AppendToNullabilityMap, + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + T['_']['excludedMethods'] + > + : never; + +export type SingleStoreJoinFn< + T extends AnySingleStoreSelectQueryBuilder, + TDynamic extends boolean, + TJoinType extends JoinType, +> = < + TJoinedTable extends SingleStoreTable | Subquery | SingleStoreViewBase | SQL, + TJoinedName extends GetSelectTableName = GetSelectTableName, +>( + table: TJoinedTable, + on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, +) => SingleStoreJoin; + +export type SelectedFieldsFlat = SelectedFieldsFlatBase; + +export type SelectedFields = SelectedFieldsBase; + +export type SelectedFieldsOrdered = SelectedFieldsOrderedBase; + +export type LockStrength = 'update' | 'share'; + +export type LockConfig = { + noWait: true; + skipLocked?: undefined; +} | { + noWait?: undefined; + skipLocked: true; +} | { + noWait?: undefined; + skipLocked?: undefined; +}; + +export interface SingleStoreSelectHKTBase { + tableName: string | undefined; + selection: unknown; + selectMode: SelectMode; + preparedQueryHKT: unknown; + nullabilityMap: unknown; + dynamic: boolean; + excludedMethods: string; + result: unknown; + selectedFields: unknown; + _type: unknown; +} + +export type SingleStoreSelectKind< + T extends SingleStoreSelectHKTBase, + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record, + TDynamic extends boolean, + TExcludedMethods extends string, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, +> = (T & { + tableName: TTableName; + selection: TSelection; + selectMode: TSelectMode; + preparedQueryHKT: TPreparedQueryHKT; + nullabilityMap: TNullabilityMap; + dynamic: TDynamic; + excludedMethods: TExcludedMethods; + result: TResult; + selectedFields: TSelectedFields; +})['_type']; + +export interface SingleStoreSelectQueryBuilderHKT extends SingleStoreSelectHKTBase { + _type: SingleStoreSelectQueryBuilderBase< + SingleStoreSelectQueryBuilderHKT, + this['tableName'], + Assume, + this['selectMode'], + Assume, + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume + >; +} + +export interface SingleStoreSelectHKT extends SingleStoreSelectHKTBase { + _type: SingleStoreSelectBase< + this['tableName'], + Assume, + this['selectMode'], + Assume, + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume + >; +} + +export type SingleStoreSetOperatorExcludedMethods = + | 'where' + | 'having' + | 'groupBy' + | 'session' + | 'leftJoin' + | 'rightJoin' + | 'innerJoin' + | 'fullJoin' + | 'for'; + +export type SingleStoreSelectWithout< + T extends AnySingleStoreSelectQueryBuilder, + TDynamic extends boolean, + K extends keyof T & string, + TResetExcluded extends boolean = false, +> = TDynamic extends true ? T : Omit< + SingleStoreSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['preparedQueryHKT'], + T['_']['nullabilityMap'], + TDynamic, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K, + T['_']['result'], + T['_']['selectedFields'] + >, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K +>; + +export type SingleStoreSelectPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: T['_']['result']; + iterator: T['_']['result'][number]; + }, + true +>; + +export type SingleStoreSelectDynamic = SingleStoreSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['preparedQueryHKT'], + T['_']['nullabilityMap'], + true, + never, + T['_']['result'], + T['_']['selectedFields'] +>; + +export type CreateSingleStoreSelectFromBuilderMode< + TBuilderMode extends 'db' | 'qb', + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> = TBuilderMode extends 'db' ? SingleStoreSelectBase + : SingleStoreSelectQueryBuilderBase< + SingleStoreSelectQueryBuilderHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT + >; + +export type SingleStoreSelectQueryBuilder< + THKT extends SingleStoreSelectHKTBase = SingleStoreSelectQueryBuilderHKT, + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = ColumnsSelection, + TSelectMode extends SelectMode = SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = Record, + TResult extends any[] = unknown[], + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> = SingleStoreSelectQueryBuilderBase< + THKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + true, + never, + TResult, + TSelectedFields +>; + +export type AnySingleStoreSelectQueryBuilder = SingleStoreSelectQueryBuilderBase< + any, + any, + any, + any, + any, + any, + any, + any, + any +>; + +export type AnySingleStoreSetOperatorInterface = SingleStoreSetOperatorInterface< + any, + any, + any, + any, + any, + any, + any, + any, + any +>; + +export interface SingleStoreSetOperatorInterface< + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> { + _: { + readonly hkt: SingleStoreSelectHKT; + readonly tableName: TTableName; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; + }; +} + +export type SingleStoreSetOperatorWithResult = SingleStoreSetOperatorInterface< + any, + any, + any, + any, + any, + any, + any, + TResult, + any +>; + +export type SingleStoreSelect< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TNullabilityMap extends Record = Record, +> = SingleStoreSelectBase; + +export type AnySingleStoreSelect = SingleStoreSelectBase; + +export type SingleStoreSetOperator< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = Record, +> = SingleStoreSelectBase< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + true, + SingleStoreSetOperatorExcludedMethods +>; + +export type SetOperatorRightSelect< + TValue extends SingleStoreSetOperatorWithResult, + TResult extends any[], +> = TValue extends SingleStoreSetOperatorInterface + ? ValidateShape< + TValueResult[number], + TResult[number], + TypedQueryBuilder + > + : TValue; + +export type SetOperatorRestSelect< + TValue extends readonly SingleStoreSetOperatorWithResult[], + TResult extends any[], +> = TValue extends [infer First, ...infer Rest] + ? First extends SingleStoreSetOperatorInterface + ? Rest extends AnySingleStoreSetOperatorInterface[] ? [ + ValidateShape>, + ...SetOperatorRestSelect, + ] + : ValidateShape[]> + : never + : TValue; + +export type SingleStoreCreateSetOperatorFn = < + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TValue extends SingleStoreSetOperatorWithResult, + TRest extends SingleStoreSetOperatorWithResult[], + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +>( + leftSelect: SingleStoreSetOperatorInterface< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + rightSelect: SetOperatorRightSelect, + ...restSelects: SetOperatorRestSelect +) => SingleStoreSelectWithout< + SingleStoreSelectBase< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + false, + SingleStoreSetOperatorExcludedMethods, + true +>; + +export type GetSingleStoreSetOperators = { + union: SingleStoreCreateSetOperatorFn; + intersect: SingleStoreCreateSetOperatorFn; + except: SingleStoreCreateSetOperatorFn; + unionAll: SingleStoreCreateSetOperatorFn; + minus: SingleStoreCreateSetOperatorFn; +}; diff --git a/drizzle-orm/src/singlestore-core/query-builders/update.ts b/drizzle-orm/src/singlestore-core/query-builders/update.ts new file mode 100644 index 000000000..40ca97662 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/update.ts @@ -0,0 +1,251 @@ +import type { GetColumnData } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; +import { mapUpdateSet, type UpdateSet, type ValueOrArray } from '~/utils.ts'; +import type { SingleStoreColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; + +export interface SingleStoreUpdateConfig { + where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + set: UpdateSet; + table: SingleStoreTable; + returning?: SelectedFieldsOrdered; + withList?: Subquery[]; +} + +export type SingleStoreUpdateSetSource = + & { + [Key in keyof TTable['$inferInsert']]?: + | GetColumnData + | SQL; + } + & {}; + +export class SingleStoreUpdateBuilder< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> { + static readonly [entityKind]: string = 'SingleStoreUpdateBuilder'; + + declare readonly _: { + readonly table: TTable; + }; + + constructor( + private table: TTable, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + private withList?: Subquery[], + ) {} + + set(values: SingleStoreUpdateSetSource): SingleStoreUpdateBase { + return new SingleStoreUpdateBase( + this.table, + mapUpdateSet(this.table, values), + this.session, + this.dialect, + this.withList, + ); + } +} + +export type SingleStoreUpdateWithout< + T extends AnySingleStoreUpdateBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T : Omit< + SingleStoreUpdateBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K +>; + +export type SingleStoreUpdatePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +export type SingleStoreUpdateDynamic = SingleStoreUpdate< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +export type SingleStoreUpdate< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreUpdateBase; + +export type AnySingleStoreUpdateBase = SingleStoreUpdateBase; + +export interface SingleStoreUpdateBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise>, SQLWrapper { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreUpdateBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreUpdate'; + + private config: SingleStoreUpdateConfig; + + constructor( + table: TTable, + set: UpdateSet, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + withList?: Subquery[], + ) { + super(); + this.config = { set, table, withList }; + } + + /** + * Adds a 'where' clause to the query. + * + * Calling this method will update only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param where the 'where' clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be updated. + * + * ```ts + * // Update all cars with green color + * db.update(cars).set({ color: 'red' }) + * .where(eq(cars.color, 'green')); + * // or + * db.update(cars).set({ color: 'red' }) + * .where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Update all BMW cars with a green color + * db.update(cars).set({ color: 'red' }) + * .where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Update all cars with the green or blue color + * db.update(cars).set({ color: 'red' }) + * .where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where(where: SQL | undefined): SingleStoreUpdateWithout { + this.config.where = where; + return this as any; + } + + orderBy( + builder: (updateTable: TTable) => ValueOrArray, + ): SingleStoreUpdateWithout; + orderBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreUpdateWithout; + orderBy( + ...columns: + | [(updateTable: TTable) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreUpdateWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): SingleStoreUpdateWithout { + this.config.limit = limit; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildUpdateQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreUpdatePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + this.config.returning, + ) as SingleStoreUpdatePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreUpdateDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts new file mode 100644 index 000000000..82da44a49 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -0,0 +1,41 @@ +import { entityKind, is } from '~/entity.ts'; +import { type SingleStoreTableFn, singlestoreTableWithSchema } from './table.ts'; +import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; + +export class SingleStoreSchema { + static readonly [entityKind]: string = 'SingleStoreSchema'; + + constructor( + public readonly schemaName: TName, + ) {} + + table: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, this.schemaName); + }; + + view = ((name, columns) => { + return singlestoreViewWithSchema(name, columns, this.schemaName); + }) as typeof singlestoreView; +} + +/** @deprecated - use `instanceof SingleStoreSchema` */ +export function isSingleStoreSchema(obj: unknown): obj is SingleStoreSchema { + return is(obj, SingleStoreSchema); +} + +/** + * Create a SingleStore schema. + * https://dev.mysql.com/doc/refman/8.0/en/create-database.html + * TODO(singlestore) + * + * @param name singlestore use schema name + * @returns SingleStore schema + */ +export function singlestoreDatabase(name: TName) { + return new SingleStoreSchema(name); +} + +/** + * @see singlestoreDatabase + */ +export const singlestoreSchema = singlestoreDatabase; diff --git a/drizzle-orm/src/singlestore-core/session.ts b/drizzle-orm/src/singlestore-core/session.ts new file mode 100644 index 000000000..1b7f076d6 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/session.ts @@ -0,0 +1,159 @@ +import { entityKind } from '~/entity.ts'; +import { TransactionRollbackError } from '~/errors.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { type Query, type SQL, sql } from '~/sql/sql.ts'; +import type { Assume, Equal } from '~/utils.ts'; +import { SingleStoreDatabase } from './db.ts'; +import type { SingleStoreDialect } from './dialect.ts'; +import type { SelectedFieldsOrdered } from './query-builders/select.types.ts'; + +export type Mode = 'default' | 'planetscale'; + +export interface SingleStoreQueryResultHKT { + readonly $brand: 'SingleStoreQueryResultHKT'; + readonly row: unknown; + readonly type: unknown; +} + +export interface AnySingleStoreQueryResultHKT extends SingleStoreQueryResultHKT { + readonly type: any; +} + +export type SingleStoreQueryResultKind = (TKind & { + readonly row: TRow; +})['type']; + +export interface SingleStorePreparedQueryConfig { + execute: unknown; + iterator: unknown; +} + +export interface SingleStorePreparedQueryHKT { + readonly $brand: 'SingleStorePreparedQueryHKT'; + readonly config: unknown; + readonly type: unknown; +} + +export type PreparedQueryKind< + TKind extends SingleStorePreparedQueryHKT, + TConfig extends SingleStorePreparedQueryConfig, + TAssume extends boolean = false, +> = Equal extends true + ? Assume<(TKind & { readonly config: TConfig })['type'], SingleStorePreparedQuery> + : (TKind & { readonly config: TConfig })['type']; + +export abstract class SingleStorePreparedQuery { + static readonly [entityKind]: string = 'SingleStorePreparedQuery'; + + /** @internal */ + joinsNotNullableMap?: Record; + + abstract execute(placeholderValues?: Record): Promise; + + abstract iterator(placeholderValues?: Record): AsyncGenerator; +} + +export interface SingleStoreTransactionConfig { + withConsistentSnapshot?: boolean; + accessMode?: 'read only' | 'read write'; + isolationLevel: 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable'; +} + +export abstract class SingleStoreSession< + TQueryResult extends SingleStoreQueryResultHKT = SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TFullSchema extends Record = Record, + TSchema extends TablesRelationalConfig = Record, +> { + static readonly [entityKind]: string = 'SingleStoreSession'; + + constructor(protected dialect: SingleStoreDialect) {} + + abstract prepareQuery< + T extends SingleStorePreparedQueryConfig, + TPreparedQueryHKT extends SingleStorePreparedQueryHKT, + >( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind; + + execute(query: SQL): Promise { + return this.prepareQuery( + this.dialect.sqlToQuery(query), + undefined, + ).execute(); + } + + abstract all(query: SQL): Promise; + + async count(sql: SQL): Promise { + const res = await this.execute<[[{ count: string }]]>(sql); + + return Number( + res[0][0]['count'], + ); + } + + abstract transaction( + transaction: (tx: SingleStoreTransaction) => Promise, + config?: SingleStoreTransactionConfig, + ): Promise; + + protected getSetTransactionSQL(config: SingleStoreTransactionConfig): SQL | undefined { + const parts: string[] = []; + + if (config.isolationLevel) { + parts.push(`isolation level ${config.isolationLevel}`); + } + + return parts.length ? sql`set transaction ${sql.raw(parts.join(' '))}` : undefined; + } + + protected getStartTransactionSQL(config: SingleStoreTransactionConfig): SQL | undefined { + const parts: string[] = []; + + if (config.withConsistentSnapshot) { + parts.push('with consistent snapshot'); + } + + if (config.accessMode) { + parts.push(config.accessMode); + } + + return parts.length ? sql`start transaction ${sql.raw(parts.join(' '))}` : undefined; + } +} + +export abstract class SingleStoreTransaction< + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record = Record, + TSchema extends TablesRelationalConfig = Record, +> extends SingleStoreDatabase { + static override readonly [entityKind]: string = 'SingleStoreTransaction'; + + constructor( + dialect: SingleStoreDialect, + session: SingleStoreSession, + protected schema: RelationalSchemaConfig | undefined, + protected readonly nestedIndex: number, + ) { + super(dialect, session, schema); + } + + rollback(): never { + throw new TransactionRollbackError(); + } + + /** Nested transactions (aka savepoints) only work with InnoDB engine. */ + abstract override transaction( + transaction: (tx: SingleStoreTransaction) => Promise, + ): Promise; +} + +export interface PreparedQueryHKTBase extends SingleStorePreparedQueryHKT { + type: SingleStorePreparedQuery>; +} diff --git a/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts new file mode 100644 index 000000000..95cffabdd --- /dev/null +++ b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts @@ -0,0 +1,22 @@ +import { bindIfParam } from '~/sql/expressions/conditions.ts'; +import { type SQL, sql } from '~/sql/sql.ts'; +import type { Table } from '~/table'; + +/** + * Test that two values match. + * + * ## Examples + * + * ```ts + * // Select cars made by Ford + * db.select().from(cars) + * .where(match(cars.make, 'Ford')) + * ``` + * + * @see isNull for a way to test equality to NULL. + */ +export function match< + TTable extends Table, +>(left: TTable, right: unknown): SQL { + return sql`MATCH (TABLE ${left}) AGAINST (${bindIfParam(right, left)})`; +} diff --git a/drizzle-orm/src/singlestore-core/sql/expressions/index.ts b/drizzle-orm/src/singlestore-core/sql/expressions/index.ts new file mode 100644 index 000000000..81cb13770 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/sql/expressions/index.ts @@ -0,0 +1 @@ +export * from './conditions.ts'; diff --git a/drizzle-orm/src/singlestore-core/sql/index.ts b/drizzle-orm/src/singlestore-core/sql/index.ts new file mode 100644 index 000000000..16ca76679 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/sql/index.ts @@ -0,0 +1 @@ +export * from './expressions/index.ts'; diff --git a/drizzle-orm/src/singlestore-core/subquery.ts b/drizzle-orm/src/singlestore-core/subquery.ts new file mode 100644 index 000000000..a4605c56d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/subquery.ts @@ -0,0 +1,17 @@ +import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import type { Subquery, WithSubquery } from '~/subquery.ts'; + +export type SubqueryWithSelection< + TSelection extends ColumnsSelection, + TAlias extends string, +> = + & Subquery> + & AddAliasToSelection; + +export type WithSubqueryWithSelection< + TSelection extends ColumnsSelection, + TAlias extends string, +> = + & WithSubquery> + & AddAliasToSelection; diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts new file mode 100644 index 000000000..db24a8587 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -0,0 +1,142 @@ +import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts'; +import { entityKind } from '~/entity.ts'; +import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; +import type { CheckBuilder } from './checks.ts'; +import { getSingleStoreColumnBuilders, type SingleStoreColumnBuilders } from './columns/all.ts'; +import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; +import type { AnyIndexBuilder } from './indexes.ts'; +import type { PrimaryKeyBuilder } from './primary-keys.ts'; +import type { UniqueConstraintBuilder } from './unique-constraint.ts'; + +export type SingleStoreTableExtraConfig = Record< + string, + | AnyIndexBuilder + | CheckBuilder + | PrimaryKeyBuilder + | UniqueConstraintBuilder +>; + +export type TableConfig = TableConfigBase; + +/** @internal */ +export const InlineForeignKeys = Symbol.for('drizzle:SingleStoreInlineForeignKeys'); + +export class SingleStoreTable extends Table { + static override readonly [entityKind]: string = 'SingleStoreTable'; + + declare protected $columns: T['columns']; + + /** @internal */ + static override readonly Symbol = Object.assign({}, Table.Symbol, {}); + + /** @internal */ + override [Table.Symbol.Columns]!: NonNullable; + + /** @internal */ + override [Table.Symbol.ExtraConfigBuilder]: + | ((self: Record) => SingleStoreTableExtraConfig) + | undefined = undefined; +} + +export type AnySingleStoreTable = {}> = SingleStoreTable< + UpdateTableConfig +>; + +export type SingleStoreTableWithColumns = + & SingleStoreTable + & { + [Key in keyof T['columns']]: T['columns'][Key]; + }; + +export function singlestoreTableWithSchema< + TTableName extends string, + TSchemaName extends string | undefined, + TColumnsMap extends Record, +>( + name: TTableName, + columns: TColumnsMap | ((columnTypes: SingleStoreColumnBuilders) => TColumnsMap), + extraConfig: + | ((self: BuildColumns) => SingleStoreTableExtraConfig) + | undefined, + schema: TSchemaName, + baseName = name, +): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; +}> { + const rawTable = new SingleStoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); + + const parsedColumns: TColumnsMap = typeof columns === 'function' ? columns(getSingleStoreColumnBuilders()) : columns; + + const builtColumns = Object.fromEntries( + Object.entries(parsedColumns).map(([name, colBuilderBase]) => { + const colBuilder = colBuilderBase as SingleStoreColumnBuilder; + const column = colBuilder.build(rawTable); + return [name, column]; + }), + ) as unknown as BuildColumns; + + const table = Object.assign(rawTable, builtColumns); + + table[Table.Symbol.Columns] = builtColumns; + table[Table.Symbol.ExtraConfigColumns] = builtColumns as unknown as BuildExtraConfigColumns< + TTableName, + TColumnsMap, + 'singlestore' + >; + + if (extraConfig) { + table[SingleStoreTable.Symbol.ExtraConfigBuilder] = extraConfig as unknown as ( + self: Record, + ) => SingleStoreTableExtraConfig; + } + + return table; +} + +export interface SingleStoreTableFn { + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: TColumnsMap, + extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfig, + ): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: SingleStoreColumnBuilders) => TColumnsMap, + extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfig, + ): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>; +} + +export const singlestoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, undefined, name); +}; + +export function singlestoreTableCreator(customizeTableName: (name: string) => string): SingleStoreTableFn { + return (name, columns, extraConfig) => { + return singlestoreTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); + }; +} diff --git a/drizzle-orm/src/singlestore-core/unique-constraint.ts b/drizzle-orm/src/singlestore-core/unique-constraint.ts new file mode 100644 index 000000000..faa4f3216 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/unique-constraint.ts @@ -0,0 +1,64 @@ +import { entityKind } from '~/entity.ts'; +import type { SingleStoreColumn } from './columns/index.ts'; +import { SingleStoreTable } from './table.ts'; + +export function unique(name?: string): UniqueOnConstraintBuilder { + return new UniqueOnConstraintBuilder(name); +} + +export function uniqueKeyName(table: SingleStoreTable, columns: string[]) { + return `${table[SingleStoreTable.Symbol.Name]}_${columns.join('_')}_unique`; +} + +export class UniqueConstraintBuilder { + static readonly [entityKind]: string = 'SingleStoreUniqueConstraintBuilder'; + + /** @internal */ + columns: SingleStoreColumn[]; + + constructor( + columns: SingleStoreColumn[], + private name?: string, + ) { + this.columns = columns; + } + + /** @internal */ + build(table: SingleStoreTable): UniqueConstraint { + return new UniqueConstraint(table, this.columns, this.name); + } +} + +export class UniqueOnConstraintBuilder { + static readonly [entityKind]: string = 'SingleStoreUniqueOnConstraintBuilder'; + + /** @internal */ + name?: string; + + constructor( + name?: string, + ) { + this.name = name; + } + + on(...columns: [SingleStoreColumn, ...SingleStoreColumn[]]) { + return new UniqueConstraintBuilder(columns, this.name); + } +} + +export class UniqueConstraint { + static readonly [entityKind]: string = 'SingleStoreUniqueConstraint'; + + readonly columns: SingleStoreColumn[]; + readonly name?: string; + readonly nullsNotDistinct: boolean = false; + + constructor(readonly table: SingleStoreTable, columns: SingleStoreColumn[], name?: string) { + this.columns = columns; + this.name = name ?? uniqueKeyName(this.table, this.columns.map((column) => column.name)); + } + + getName() { + return this.name; + } +} diff --git a/drizzle-orm/src/singlestore-core/utils.ts b/drizzle-orm/src/singlestore-core/utils.ts new file mode 100644 index 000000000..e6412161d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/utils.ts @@ -0,0 +1,56 @@ +import { is } from '~/entity.ts'; +import { Table } from '~/table.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import type { Index } from './indexes.ts'; +import { IndexBuilder } from './indexes.ts'; +import type { PrimaryKey } from './primary-keys.ts'; +import { PrimaryKeyBuilder } from './primary-keys.ts'; +import { SingleStoreTable } from './table.ts'; +import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; +import { SingleStoreViewConfig } from './view-common.ts'; +import type { SingleStoreView } from './view.ts'; + +export function getTableConfig(table: SingleStoreTable) { + const columns = Object.values(table[SingleStoreTable.Symbol.Columns]); + const indexes: Index[] = []; + const primaryKeys: PrimaryKey[] = []; + const uniqueConstraints: UniqueConstraint[] = []; + const name = table[Table.Symbol.Name]; + const schema = table[Table.Symbol.Schema]; + const baseName = table[Table.Symbol.BaseName]; + + const extraConfigBuilder = table[SingleStoreTable.Symbol.ExtraConfigBuilder]; + + if (extraConfigBuilder !== undefined) { + const extraConfig = extraConfigBuilder(table[SingleStoreTable.Symbol.Columns]); + for (const builder of Object.values(extraConfig)) { + if (is(builder, IndexBuilder)) { + indexes.push(builder.build(table)); + } else if (is(builder, UniqueConstraintBuilder)) { + uniqueConstraints.push(builder.build(table)); + } else if (is(builder, PrimaryKeyBuilder)) { + primaryKeys.push(builder.build(table)); + } + } + } + + return { + columns, + indexes, + primaryKeys, + uniqueConstraints, + name, + schema, + baseName, + }; +} + +export function getViewConfig< + TName extends string = string, + TExisting extends boolean = boolean, +>(view: SingleStoreView) { + return { + ...view[ViewBaseConfig], + ...view[SingleStoreViewConfig], + }; +} diff --git a/drizzle-orm/src/singlestore-core/view-base.ts b/drizzle-orm/src/singlestore-core/view-base.ts new file mode 100644 index 000000000..1ad8d62d5 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view-base.ts @@ -0,0 +1,15 @@ +import { entityKind } from '~/entity.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import { View } from '~/sql/sql.ts'; + +export abstract class SingleStoreViewBase< + TName extends string = string, + TExisting extends boolean = boolean, + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> extends View { + static override readonly [entityKind]: string = 'SingleStoreViewBase'; + + declare readonly _: View['_'] & { + readonly viewBrand: 'SingleStoreViewBase'; + }; +} diff --git a/drizzle-orm/src/singlestore-core/view-common.ts b/drizzle-orm/src/singlestore-core/view-common.ts new file mode 100644 index 000000000..d29c3d5ad --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view-common.ts @@ -0,0 +1 @@ +export const SingleStoreViewConfig = Symbol.for('drizzle:SingleStoreViewConfig'); diff --git a/drizzle-orm/src/singlestore-core/view.ts b/drizzle-orm/src/singlestore-core/view.ts new file mode 100644 index 000000000..ce0fe4dd3 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view.ts @@ -0,0 +1,208 @@ +import type { BuildColumns } from '~/column-builder.ts'; +import { entityKind } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { ColumnsSelection, SQL } from '~/sql/sql.ts'; +import { getTableColumns } from '~/utils.ts'; +import type { SingleStoreColumn, SingleStoreColumnBuilderBase } from './columns/index.ts'; +import { QueryBuilder } from './query-builders/query-builder.ts'; +import type { SelectedFields } from './query-builders/select.types.ts'; +import { singlestoreTable } from './table.ts'; +import { SingleStoreViewBase } from './view-base.ts'; +import { SingleStoreViewConfig } from './view-common.ts'; + +export interface ViewBuilderConfig { + algorithm?: 'undefined' | 'merge' | 'temptable'; + definer?: string; + sqlSecurity?: 'definer' | 'invoker'; + withCheckOption?: 'cascaded' | 'local'; +} + +export class ViewBuilderCore { + static readonly [entityKind]: string = 'SingleStoreViewBuilder'; + + declare readonly _: { + readonly name: TConfig['name']; + readonly columns: TConfig['columns']; + }; + + constructor( + protected name: TConfig['name'], + protected schema: string | undefined, + ) {} + + protected config: ViewBuilderConfig = {}; + + algorithm( + algorithm: Exclude, + ): this { + this.config.algorithm = algorithm; + return this; + } + + definer( + definer: Exclude, + ): this { + this.config.definer = definer; + return this; + } + + sqlSecurity( + sqlSecurity: Exclude, + ): this { + this.config.sqlSecurity = sqlSecurity; + return this; + } + + withCheckOption( + withCheckOption?: Exclude, + ): this { + this.config.withCheckOption = withCheckOption ?? 'cascaded'; + return this; + } +} + +export class ViewBuilder extends ViewBuilderCore<{ name: TName }> { + static override readonly [entityKind]: string = 'SingleStoreViewBuilder'; + + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): SingleStoreViewWithSelection> { + if (typeof qb === 'function') { + qb = qb(new QueryBuilder()); + } + const selectionProxy = new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }); + const aliasedSelection = new Proxy(qb.getSelectedFields(), selectionProxy); + return new Proxy( + new SingleStoreView({ + singlestoreConfig: this.config, + config: { + name: this.name, + schema: this.schema, + selectedFields: aliasedSelection, + query: qb.getSQL().inlineParams(), + }, + }), + selectionProxy as any, + ) as SingleStoreViewWithSelection>; + } +} + +export class ManualViewBuilder< + TName extends string = string, + TColumns extends Record = Record, +> extends ViewBuilderCore<{ name: TName; columns: TColumns }> { + static override readonly [entityKind]: string = 'SingleStoreManualViewBuilder'; + + private columns: Record; + + constructor( + name: TName, + columns: TColumns, + schema: string | undefined, + ) { + super(name, schema); + this.columns = getTableColumns(singlestoreTable(name, columns)) as BuildColumns; + } + + existing(): SingleStoreViewWithSelection> { + return new Proxy( + new SingleStoreView({ + singlestoreConfig: undefined, + config: { + name: this.name, + schema: this.schema, + selectedFields: this.columns, + query: undefined, + }, + }), + new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }), + ) as SingleStoreViewWithSelection>; + } + + as(query: SQL): SingleStoreViewWithSelection> { + return new Proxy( + new SingleStoreView({ + singlestoreConfig: this.config, + config: { + name: this.name, + schema: this.schema, + selectedFields: this.columns, + query: query.inlineParams(), + }, + }), + new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }), + ) as SingleStoreViewWithSelection>; + } +} + +export class SingleStoreView< + TName extends string = string, + TExisting extends boolean = boolean, + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> extends SingleStoreViewBase { + static override readonly [entityKind]: string = 'SingleStoreView'; + + declare protected $SingleStoreViewBrand: 'SingleStoreView'; + + [SingleStoreViewConfig]: ViewBuilderConfig | undefined; + + constructor({ singlestoreConfig, config }: { + singlestoreConfig: ViewBuilderConfig | undefined; + config: { + name: TName; + schema: string | undefined; + selectedFields: SelectedFields; + query: SQL | undefined; + }; + }) { + super(config); + this[SingleStoreViewConfig] = singlestoreConfig; + } +} + +export type SingleStoreViewWithSelection< + TName extends string, + TExisting extends boolean, + TSelectedFields extends ColumnsSelection, +> = SingleStoreView & TSelectedFields; + +/** @internal */ +export function singlestoreViewWithSchema( + name: string, + selection: Record | undefined, + schema: string | undefined, +): ViewBuilder | ManualViewBuilder { + if (selection) { + return new ManualViewBuilder(name, selection, schema); + } + return new ViewBuilder(name, schema); +} + +export function singlestoreView(name: TName): ViewBuilder; +export function singlestoreView>( + name: TName, + columns: TColumns, +): ManualViewBuilder; +export function singlestoreView( + name: string, + selection?: Record, +): ViewBuilder | ManualViewBuilder { + return singlestoreViewWithSchema(name, selection, undefined); +} diff --git a/drizzle-orm/src/singlestore-proxy/driver.ts b/drizzle-orm/src/singlestore-proxy/driver.ts new file mode 100644 index 000000000..f54180c66 --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/driver.ts @@ -0,0 +1,54 @@ +import { DefaultLogger } from '~/logger.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type RelationalSchemaConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { DrizzleConfig } from '~/utils.ts'; +import { + type SingleStoreRemotePreparedQueryHKT, + type SingleStoreRemoteQueryResultHKT, + SingleStoreRemoteSession, +} from './session.ts'; + +export type SingleStoreRemoteDatabase< + TSchema extends Record = Record, +> = SingleStoreDatabase; + +export type RemoteCallback = ( + sql: string, + params: any[], + method: 'all' | 'execute', +) => Promise<{ rows: any[]; insertId?: number; affectedRows?: number }>; + +export function drizzle = Record>( + callback: RemoteCallback, + config: DrizzleConfig = {}, +): SingleStoreRemoteDatabase { + const dialect = new SingleStoreDialect(); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const session = new SingleStoreRemoteSession(callback, dialect, schema, { logger }); + return new SingleStoreDatabase(dialect, session, schema) as SingleStoreRemoteDatabase; +} diff --git a/drizzle-orm/src/singlestore-proxy/index.ts b/drizzle-orm/src/singlestore-proxy/index.ts new file mode 100644 index 000000000..b1b6a52e7 --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/singlestore-proxy/migrator.ts b/drizzle-orm/src/singlestore-proxy/migrator.ts new file mode 100644 index 000000000..2ed0172fb --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/migrator.ts @@ -0,0 +1,52 @@ +import type { MigrationConfig } from '~/migrator.ts'; +import { readMigrationFiles } from '~/migrator.ts'; +import { sql } from '~/sql/sql.ts'; +import type { SingleStoreRemoteDatabase } from './driver.ts'; + +export type ProxyMigrator = (migrationQueries: string[]) => Promise; + +export async function migrate>( + db: SingleStoreRemoteDatabase, + callback: ProxyMigrator, + config: MigrationConfig, +) { + const migrations = readMigrationFiles(config); + + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; + const migrationTableCreate = sql` + create table if not exists ${sql.identifier(migrationsTable)} ( + id serial primary key, + hash text not null, + created_at bigint + ) + `; + await db.execute(migrationTableCreate); + + const dbMigrations = await db.select({ + id: sql.raw('id'), + hash: sql.raw('hash'), + created_at: sql.raw('created_at'), + }).from(sql.identifier(migrationsTable).getSQL()).orderBy( + sql.raw('created_at desc'), + ).limit(1); + + const lastDbMigration = dbMigrations[0]; + + const queriesToRun: string[] = []; + + for (const migration of migrations) { + if ( + !lastDbMigration + || Number(lastDbMigration.created_at) < migration.folderMillis + ) { + queriesToRun.push( + ...migration.sql, + `insert into ${ + sql.identifier(migrationsTable).value + } (\`hash\`, \`created_at\`) values('${migration.hash}', '${migration.folderMillis}')`, + ); + } + } + + await callback(queriesToRun); +} diff --git a/drizzle-orm/src/singlestore-proxy/session.ts b/drizzle-orm/src/singlestore-proxy/session.ts new file mode 100644 index 000000000..f7b404860 --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/session.ts @@ -0,0 +1,178 @@ +import type { FieldPacket, ResultSetHeader } from 'mysql2/promise'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import { SingleStoreTransaction } from '~/singlestore-core/index.ts'; +import type { SelectedFieldsOrdered } from '~/singlestore-core/query-builders/select.types.ts'; +import type { + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStorePreparedQueryHKT, + SingleStoreQueryResultHKT, + SingleStoreTransactionConfig, +} from '~/singlestore-core/session.ts'; +import { SingleStorePreparedQuery as PreparedQueryBase, SingleStoreSession } from '~/singlestore-core/session.ts'; +import { fillPlaceholders } from '~/sql/sql.ts'; +import type { Query, SQL } from '~/sql/sql.ts'; +import { type Assume, mapResultRow } from '~/utils.ts'; +import type { RemoteCallback } from './driver.ts'; + +export type SingleStoreRawQueryResult = [ResultSetHeader, FieldPacket[]]; + +export interface SingleStoreRemoteSessionOptions { + logger?: Logger; +} + +export class SingleStoreRemoteSession< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreSession { + static override readonly [entityKind]: string = 'SingleStoreRemoteSession'; + + private logger: Logger; + + constructor( + private client: RemoteCallback, + dialect: SingleStoreDialect, + private schema: RelationalSchemaConfig | undefined, + options: SingleStoreRemoteSessionOptions, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + } + + prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind { + return new PreparedQuery( + this.client, + query.sql, + query.params, + this.logger, + fields, + customResultMapper, + generatedIds, + returningIds, + ) as PreparedQueryKind; + } + + override all(query: SQL): Promise { + const querySql = this.dialect.sqlToQuery(query); + this.logger.logQuery(querySql.sql, querySql.params); + return this.client(querySql.sql, querySql.params, 'all').then(({ rows }) => rows) as Promise; + } + + override async transaction( + _transaction: (tx: SingleStoreProxyTransaction) => Promise, + _config?: SingleStoreTransactionConfig, + ): Promise { + throw new Error('Transactions are not supported by the SingleStore Proxy driver'); + } +} + +export class SingleStoreProxyTransaction< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreTransaction< + SingleStoreRemoteQueryResultHKT, + SingleStoreRemotePreparedQueryHKT, + TFullSchema, + TSchema +> { + static override readonly [entityKind]: string = 'SingleStoreProxyTransaction'; + + override async transaction( + _transaction: (tx: SingleStoreProxyTransaction) => Promise, + ): Promise { + throw new Error('Transactions are not supported by the SingleStore Proxy driver'); + } +} + +export class PreparedQuery extends PreparedQueryBase { + static override readonly [entityKind]: string = 'SingleStoreProxyPreparedQuery'; + + constructor( + private client: RemoteCallback, + private queryString: string, + private params: unknown[], + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + private customResultMapper?: (rows: unknown[][]) => T['execute'], + // Keys that were used in $default and the value that was generated for them + private generatedIds?: Record[], + // Keys that should be returned, it has the column with all properries + key from object + private returningIds?: SelectedFieldsOrdered, + ) { + super(); + } + + async execute(placeholderValues: Record | undefined = {}): Promise { + const params = fillPlaceholders(this.params, placeholderValues); + + const { fields, client, queryString, logger, joinsNotNullableMap, customResultMapper, returningIds, generatedIds } = + this; + + logger.logQuery(queryString, params); + + if (!fields && !customResultMapper) { + const { rows: data } = await client(queryString, params, 'execute'); + + const insertId = data[0].insertId as number; + const affectedRows = data[0].affectedRows; + + if (returningIds) { + const returningResponse = []; + let j = 0; + for (let i = insertId; i < insertId + affectedRows; i++) { + for (const column of returningIds) { + const key = returningIds[0]!.path[0]!; + if (is(column.field, Column)) { + // @ts-ignore + if (column.field.primary && column.field.autoIncrement) { + returningResponse.push({ [key]: i }); + } + if (column.field.defaultFn && generatedIds) { + // generatedIds[rowIdx][key] + returningResponse.push({ [key]: generatedIds[j]![key] }); + } + } + } + j++; + } + + return returningResponse; + } + + return data; + } + + const { rows } = await client(queryString, params, 'all'); + + if (customResultMapper) { + return customResultMapper(rows); + } + + return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + } + + override iterator( + _placeholderValues: Record = {}, + ): AsyncGenerator { + throw new Error('Streaming is not supported by the SingleStore Proxy driver'); + } +} + +export interface SingleStoreRemoteQueryResultHKT extends SingleStoreQueryResultHKT { + type: SingleStoreRawQueryResult; +} + +export interface SingleStoreRemotePreparedQueryHKT extends SingleStorePreparedQueryHKT { + type: PreparedQuery>; +} diff --git a/drizzle-orm/src/singlestore/driver.ts b/drizzle-orm/src/singlestore/driver.ts new file mode 100644 index 000000000..ffc5c2795 --- /dev/null +++ b/drizzle-orm/src/singlestore/driver.ts @@ -0,0 +1,92 @@ +import type { Connection as CallbackConnection, Pool as CallbackPool } from 'mysql2'; +import { entityKind } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { DefaultLogger } from '~/logger.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type RelationalSchemaConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { DrizzleConfig } from '~/utils.ts'; +import type { + Mode, + SingleStoreDriverClient, + SingleStoreDriverPreparedQueryHKT, + SingleStoreDriverQueryResultHKT, +} from './session.ts'; +import { SingleStoreDriverSession } from './session.ts'; + +export interface SingleStoreDriverOptions { + logger?: Logger; +} + +export class SingleStoreDriver { + static readonly [entityKind]: string = 'SingleStoreDriver'; + + constructor( + private client: SingleStoreDriverClient, + private dialect: SingleStoreDialect, + private options: SingleStoreDriverOptions = {}, + ) { + } + + createSession( + schema: RelationalSchemaConfig | undefined, + ): SingleStoreDriverSession, TablesRelationalConfig> { + return new SingleStoreDriverSession(this.client, this.dialect, schema, { logger: this.options.logger }); + } +} + +export { SingleStoreDatabase } from '~/singlestore-core/db.ts'; + +export type SingleStoreDriverDatabase< + TSchema extends Record = Record, +> = SingleStoreDatabase; + +export type SingleStoreDriverDrizzleConfig = Record> = + & Omit, 'schema'> + & ({ schema: TSchema; mode: Mode } | { schema?: undefined; mode?: Mode }); + +export function drizzle = Record>( + client: SingleStoreDriverClient | CallbackConnection | CallbackPool, + config: DrizzleConfig = {}, +): SingleStoreDriverDatabase { + const dialect = new SingleStoreDialect(); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + if (isCallbackClient(client)) { + client = client.promise(); + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const driver = new SingleStoreDriver(client as SingleStoreDriverClient, dialect, { logger }); + const session = driver.createSession(schema); + return new SingleStoreDatabase(dialect, session, schema) as SingleStoreDriverDatabase; +} + +interface CallbackClient { + promise(): SingleStoreDriverClient; +} + +function isCallbackClient(client: any): client is CallbackClient { + return typeof client.promise === 'function'; +} diff --git a/drizzle-orm/src/singlestore/index.ts b/drizzle-orm/src/singlestore/index.ts new file mode 100644 index 000000000..b1b6a52e7 --- /dev/null +++ b/drizzle-orm/src/singlestore/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/singlestore/migrator.ts b/drizzle-orm/src/singlestore/migrator.ts new file mode 100644 index 000000000..6f342c0c5 --- /dev/null +++ b/drizzle-orm/src/singlestore/migrator.ts @@ -0,0 +1,11 @@ +import type { MigrationConfig } from '~/migrator.ts'; +import { readMigrationFiles } from '~/migrator.ts'; +import type { SingleStoreDriverDatabase } from './driver.ts'; + +export async function migrate>( + db: SingleStoreDriverDatabase, + config: MigrationConfig, +) { + const migrations = readMigrationFiles(config); + await db.dialect.migrate(migrations, db.session, config); +} diff --git a/drizzle-orm/src/singlestore/session.ts b/drizzle-orm/src/singlestore/session.ts new file mode 100644 index 000000000..e03171262 --- /dev/null +++ b/drizzle-orm/src/singlestore/session.ts @@ -0,0 +1,339 @@ +import type { Connection as CallbackConnection } from 'mysql2'; +import type { + Connection, + FieldPacket, + OkPacket, + Pool, + PoolConnection, + QueryOptions, + ResultSetHeader, + RowDataPacket, +} from 'mysql2/promise'; +import { once } from 'node:events'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { SelectedFieldsOrdered } from '~/singlestore-core/query-builders/select.types.ts'; +import { + type PreparedQueryKind, + SingleStorePreparedQuery, + type SingleStorePreparedQueryConfig, + type SingleStorePreparedQueryHKT, + type SingleStoreQueryResultHKT, + SingleStoreSession, + SingleStoreTransaction, + type SingleStoreTransactionConfig, +} from '~/singlestore-core/session.ts'; +import { fillPlaceholders, sql } from '~/sql/sql.ts'; +import type { Query, SQL } from '~/sql/sql.ts'; +import { type Assume, mapResultRow } from '~/utils.ts'; + +// must keep this type here for compatibility with DrizzleConfig +export type Mode = 'default'; + +export type SingleStoreDriverClient = Pool | Connection; + +export type SingleStoreRawQueryResult = [ResultSetHeader, FieldPacket[]]; +export type SingleStoreQueryResultType = RowDataPacket[][] | RowDataPacket[] | OkPacket | OkPacket[] | ResultSetHeader; +export type SingleStoreQueryResult< + T = any, +> = [T extends ResultSetHeader ? T : T[], FieldPacket[]]; + +export class SingleStoreDriverPreparedQuery + extends SingleStorePreparedQuery +{ + static override readonly [entityKind]: string = 'SingleStoreDriverPreparedQuery'; + + private rawQuery: QueryOptions; + private query: QueryOptions; + + constructor( + private client: SingleStoreDriverClient, + queryString: string, + private params: unknown[], + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + private customResultMapper?: (rows: unknown[][]) => T['execute'], + // Keys that were used in $default and the value that was generated for them + private generatedIds?: Record[], + // Keys that should be returned, it has the column with all properries + key from object + private returningIds?: SelectedFieldsOrdered, + ) { + super(); + this.rawQuery = { + sql: queryString, + // rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }; + this.query = { + sql: queryString, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }; + } + + async execute(placeholderValues: Record = {}): Promise { + const params = fillPlaceholders(this.params, placeholderValues); + + this.logger.logQuery(this.rawQuery.sql, params); + + const { fields, client, rawQuery, query, joinsNotNullableMap, customResultMapper, returningIds, generatedIds } = + this; + if (!fields && !customResultMapper) { + const res = await client.query(rawQuery, params); + const insertId = res[0].insertId; + const affectedRows = res[0].affectedRows; + // for each row, I need to check keys from + if (returningIds) { + const returningResponse = []; + let j = 0; + for (let i = insertId; i < insertId + affectedRows; i++) { + for (const column of returningIds) { + const key = returningIds[0]!.path[0]!; + if (is(column.field, Column)) { + // @ts-ignore + if (column.field.primary && column.field.autoIncrement) { + returningResponse.push({ [key]: i }); + } + if (column.field.defaultFn && generatedIds) { + // generatedIds[rowIdx][key] + returningResponse.push({ [key]: generatedIds[j]![key] }); + } + } + } + j++; + } + + return returningResponse; + } + return res; + } + + const result = await client.query(query, params); + const rows = result[0]; + + if (customResultMapper) { + return customResultMapper(rows); + } + + return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + } + + async *iterator( + placeholderValues: Record = {}, + ): AsyncGenerator { + const params = fillPlaceholders(this.params, placeholderValues); + const conn = ((isPool(this.client) ? await this.client.getConnection() : this.client) as {} as { + connection: CallbackConnection; + }).connection; + + const { fields, query, rawQuery, joinsNotNullableMap, client, customResultMapper } = this; + const hasRowsMapper = Boolean(fields || customResultMapper); + const driverQuery = hasRowsMapper ? conn.query(query, params) : conn.query(rawQuery, params); + + const stream = driverQuery.stream(); + + function dataListener() { + stream.pause(); + } + + stream.on('data', dataListener); + + try { + const onEnd = once(stream, 'end'); + const onError = once(stream, 'error'); + + while (true) { + stream.resume(); + const row = await Promise.race([onEnd, onError, new Promise((resolve) => stream.once('data', resolve))]); + if (row === undefined || (Array.isArray(row) && row.length === 0)) { + break; + } else if (row instanceof Error) { // eslint-disable-line no-instanceof/no-instanceof + throw row; + } else { + if (hasRowsMapper) { + if (customResultMapper) { + const mappedRow = customResultMapper([row as unknown[]]); + yield (Array.isArray(mappedRow) ? mappedRow[0] : mappedRow); + } else { + yield mapResultRow(fields!, row as unknown[], joinsNotNullableMap); + } + } else { + yield row as T['execute']; + } + } + } + } finally { + stream.off('data', dataListener); + if (isPool(client)) { + conn.end(); + } + } + } +} + +export interface SingleStoreDriverSessionOptions { + logger?: Logger; +} + +export class SingleStoreDriverSession< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreSession { + static override readonly [entityKind]: string = 'SingleStoreDriverSession'; + + private logger: Logger; + + constructor( + private client: SingleStoreDriverClient, + dialect: SingleStoreDialect, + private schema: RelationalSchemaConfig | undefined, + private options: SingleStoreDriverSessionOptions, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + } + + prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind { + // Add returningId fields + // Each driver gets them from response from database + return new SingleStoreDriverPreparedQuery( + this.client, + query.sql, + query.params, + this.logger, + fields, + customResultMapper, + generatedIds, + returningIds, + ) as PreparedQueryKind; + } + + /** + * @internal + * What is its purpose? + */ + async query(query: string, params: unknown[]): Promise { + this.logger.logQuery(query, params); + const result = await this.client.query({ + sql: query, + values: params, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + return result; + } + + override all(query: SQL): Promise { + const querySql = this.dialect.sqlToQuery(query); + this.logger.logQuery(querySql.sql, querySql.params); + return this.client.execute(querySql.sql, querySql.params).then((result) => result[0]) as Promise; + } + + override async transaction( + transaction: (tx: SingleStoreDriverTransaction) => Promise, + config?: SingleStoreTransactionConfig, + ): Promise { + const session = isPool(this.client) + ? new SingleStoreDriverSession( + await this.client.getConnection(), + this.dialect, + this.schema, + this.options, + ) + : this; + const tx = new SingleStoreDriverTransaction( + this.dialect, + session as SingleStoreSession, + this.schema, + 0, + ); + if (config) { + const startTransactionSql = this.getStartTransactionSQL(config); + await (startTransactionSql ? tx.execute(startTransactionSql) : tx.execute(sql`begin`)); + } else { + await tx.execute(sql`begin`); + } + try { + const result = await transaction(tx); + await tx.execute(sql`commit`); + return result; + } catch (err) { + await tx.execute(sql`rollback`); + throw err; + } finally { + if (isPool(this.client)) { + (session.client as PoolConnection).release(); + } + } + } +} + +export class SingleStoreDriverTransaction< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreTransaction< + SingleStoreDriverQueryResultHKT, + SingleStoreDriverPreparedQueryHKT, + TFullSchema, + TSchema +> { + static override readonly [entityKind]: string = 'SingleStoreDriverTransaction'; + + override async transaction( + transaction: (tx: SingleStoreDriverTransaction) => Promise, + ): Promise { + const savepointName = `sp${this.nestedIndex + 1}`; + const tx = new SingleStoreDriverTransaction( + this.dialect, + this.session, + this.schema, + this.nestedIndex + 1, + ); + await tx.execute(sql.raw(`savepoint ${savepointName}`)); + try { + const result = await transaction(tx); + await tx.execute(sql.raw(`release savepoint ${savepointName}`)); + return result; + } catch (err) { + await tx.execute(sql.raw(`rollback to savepoint ${savepointName}`)); + throw err; + } + } +} + +function isPool(client: SingleStoreDriverClient): client is Pool { + return 'getConnection' in client; +} + +export interface SingleStoreDriverQueryResultHKT extends SingleStoreQueryResultHKT { + type: SingleStoreRawQueryResult; +} + +export interface SingleStoreDriverPreparedQueryHKT extends SingleStorePreparedQueryHKT { + type: SingleStoreDriverPreparedQuery>; +} diff --git a/drizzle-orm/type-tests/singlestore/1000columns.ts b/drizzle-orm/type-tests/singlestore/1000columns.ts new file mode 100644 index 000000000..f84640858 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/1000columns.ts @@ -0,0 +1,904 @@ +import { bigint, double, singlestoreTable, varchar } from '~/singlestore-core/index.ts'; + +singlestoreTable('test', { + col0: double('col1').primaryKey().autoincrement().default(0), + col1: double('col1').primaryKey().autoincrement().default(0), + col2: double('col1').primaryKey().autoincrement().default(0), + col3: double('col1').primaryKey().autoincrement().default(0), + col4: double('col1').primaryKey().autoincrement().default(0), + col5: double('col1').primaryKey().autoincrement().default(0), + col6: double('col1').primaryKey().autoincrement().default(0), + col8: double('col1').primaryKey().autoincrement().default(0), + col9: double('col1').primaryKey().autoincrement().default(0), + col10: double('col1').primaryKey().autoincrement().default(0), + col11: double('col1').primaryKey().autoincrement().default(0), + col12: double('col1').primaryKey().autoincrement().default(0), + col13: double('col1').primaryKey().autoincrement().default(0), + col14: double('col1').primaryKey().autoincrement().default(0), + col15: double('col1').primaryKey().autoincrement().default(0), + col16: double('col1').primaryKey().autoincrement().default(0), + col18: double('col1').primaryKey().autoincrement().default(0), + col19: double('col1').primaryKey().autoincrement().default(0), + col20: double('col1').primaryKey().autoincrement().default(0), + col21: double('col1').primaryKey().autoincrement().default(0), + col22: double('col1').primaryKey().autoincrement().default(0), + col23: double('col1').primaryKey().autoincrement().default(0), + col24: double('col1').primaryKey().autoincrement().default(0), + col25: double('col1').primaryKey().autoincrement().default(0), + col26: double('col1').primaryKey().autoincrement().default(0), + col28: double('col1').primaryKey().autoincrement().default(0), + col29: double('col1').primaryKey().autoincrement().default(0), + col30: double('col1').primaryKey().autoincrement().default(0), + col31: double('col1').primaryKey().autoincrement().default(0), + col32: double('col1').primaryKey().autoincrement().default(0), + col33: double('col1').primaryKey().autoincrement().default(0), + col34: double('col1').primaryKey().autoincrement().default(0), + col35: double('col1').primaryKey().autoincrement().default(0), + col36: double('col1').primaryKey().autoincrement().default(0), + col38: double('col1').primaryKey().autoincrement().default(0), + col39: double('col1').primaryKey().autoincrement().default(0), + col40: double('col1').primaryKey().autoincrement().default(0), + col41: double('col1').primaryKey().autoincrement().default(0), + col42: double('col1').primaryKey().autoincrement().default(0), + col43: double('col1').primaryKey().autoincrement().default(0), + col44: double('col1').primaryKey().autoincrement().default(0), + col45: double('col1').primaryKey().autoincrement().default(0), + col46: double('col1').primaryKey().autoincrement().default(0), + col48: double('col1').primaryKey().autoincrement().default(0), + col49: double('col1').primaryKey().autoincrement().default(0), + col50: double('col1').primaryKey().autoincrement().default(0), + col51: double('col1').primaryKey().autoincrement().default(0), + col52: double('col1').primaryKey().autoincrement().default(0), + col53: double('col1').primaryKey().autoincrement().default(0), + col54: double('col1').primaryKey().autoincrement().default(0), + col55: double('col1').primaryKey().autoincrement().default(0), + col56: double('col1').primaryKey().autoincrement().default(0), + col58: double('col1').primaryKey().autoincrement().default(0), + col59: double('col1').primaryKey().autoincrement().default(0), + col60: double('col1').primaryKey().autoincrement().default(0), + col61: double('col1').primaryKey().autoincrement().default(0), + col62: double('col1').primaryKey().autoincrement().default(0), + col63: double('col1').primaryKey().autoincrement().default(0), + col64: double('col1').primaryKey().autoincrement().default(0), + col65: double('col1').primaryKey().autoincrement().default(0), + col66: double('col1').primaryKey().autoincrement().default(0), + col68: double('col1').primaryKey().autoincrement().default(0), + col69: double('col1').primaryKey().autoincrement().default(0), + col70: double('col1').primaryKey().autoincrement().default(0), + col71: double('col1').primaryKey().autoincrement().default(0), + col72: double('col1').primaryKey().autoincrement().default(0), + col73: double('col1').primaryKey().autoincrement().default(0), + col74: double('col1').primaryKey().autoincrement().default(0), + col75: double('col1').primaryKey().autoincrement().default(0), + col76: double('col1').primaryKey().autoincrement().default(0), + col78: double('col1').primaryKey().autoincrement().default(0), + col79: double('col1').primaryKey().autoincrement().default(0), + col80: double('col1').primaryKey().autoincrement().default(0), + col81: double('col1').primaryKey().autoincrement().default(0), + col82: double('col1').primaryKey().autoincrement().default(0), + col83: double('col1').primaryKey().autoincrement().default(0), + col84: double('col1').primaryKey().autoincrement().default(0), + col85: double('col1').primaryKey().autoincrement().default(0), + col86: double('col1').primaryKey().autoincrement().default(0), + col88: double('col1').primaryKey().autoincrement().default(0), + col89: double('col1').primaryKey().autoincrement().default(0), + col90: double('col1').primaryKey().autoincrement().default(0), + col91: double('col1').primaryKey().autoincrement().default(0), + col92: double('col1').primaryKey().autoincrement().default(0), + col93: double('col1').primaryKey().autoincrement().default(0), + col94: double('col1').primaryKey().autoincrement().default(0), + col95: double('col1').primaryKey().autoincrement().default(0), + col96: double('col1').primaryKey().autoincrement().default(0), + col98: double('col1').primaryKey().autoincrement().default(0), + col99: double('col1').primaryKey().autoincrement().default(0), + col100: double('col1').primaryKey().autoincrement().default(0), + col101: double('col1').primaryKey().autoincrement().default(0), + col102: double('col1').primaryKey().autoincrement().default(0), + col103: double('col1').primaryKey().autoincrement().default(0), + col104: double('col1').primaryKey().autoincrement().default(0), + col105: double('col1').primaryKey().autoincrement().default(0), + col106: double('col1').primaryKey().autoincrement().default(0), + col108: double('col1').primaryKey().autoincrement().default(0), + col109: double('col1').primaryKey().autoincrement().default(0), + col110: double('col11').primaryKey().autoincrement().default(0), + col111: double('col11').primaryKey().autoincrement().default(0), + col112: double('col11').primaryKey().autoincrement().default(0), + col113: double('col11').primaryKey().autoincrement().default(0), + col114: double('col11').primaryKey().autoincrement().default(0), + col115: double('col11').primaryKey().autoincrement().default(0), + col116: double('col11').primaryKey().autoincrement().default(0), + col118: double('col11').primaryKey().autoincrement().default(0), + col119: double('col11').primaryKey().autoincrement().default(0), + col120: double('col11').primaryKey().autoincrement().default(0), + col121: double('col11').primaryKey().autoincrement().default(0), + col122: double('col11').primaryKey().autoincrement().default(0), + col123: double('col11').primaryKey().autoincrement().default(0), + col124: double('col11').primaryKey().autoincrement().default(0), + col125: double('col11').primaryKey().autoincrement().default(0), + col126: double('col11').primaryKey().autoincrement().default(0), + col128: double('col11').primaryKey().autoincrement().default(0), + col129: double('col11').primaryKey().autoincrement().default(0), + col130: double('col11').primaryKey().autoincrement().default(0), + col131: double('col11').primaryKey().autoincrement().default(0), + col132: double('col11').primaryKey().autoincrement().default(0), + col133: double('col11').primaryKey().autoincrement().default(0), + col134: double('col11').primaryKey().autoincrement().default(0), + col135: double('col11').primaryKey().autoincrement().default(0), + col136: double('col11').primaryKey().autoincrement().default(0), + col138: double('col11').primaryKey().autoincrement().default(0), + col139: double('col11').primaryKey().autoincrement().default(0), + col140: double('col11').primaryKey().autoincrement().default(0), + col141: double('col11').primaryKey().autoincrement().default(0), + col142: double('col11').primaryKey().autoincrement().default(0), + col143: double('col11').primaryKey().autoincrement().default(0), + col144: double('col11').primaryKey().autoincrement().default(0), + col145: double('col11').primaryKey().autoincrement().default(0), + col146: double('col11').primaryKey().autoincrement().default(0), + col148: double('col11').primaryKey().autoincrement().default(0), + col149: double('col11').primaryKey().autoincrement().default(0), + col150: double('col11').primaryKey().autoincrement().default(0), + col151: double('col11').primaryKey().autoincrement().default(0), + col152: double('col11').primaryKey().autoincrement().default(0), + col153: double('col11').primaryKey().autoincrement().default(0), + col154: double('col11').primaryKey().autoincrement().default(0), + col155: double('col11').primaryKey().autoincrement().default(0), + col156: double('col11').primaryKey().autoincrement().default(0), + col158: double('col11').primaryKey().autoincrement().default(0), + col159: double('col11').primaryKey().autoincrement().default(0), + col160: double('col11').primaryKey().autoincrement().default(0), + col161: double('col11').primaryKey().autoincrement().default(0), + col162: double('col11').primaryKey().autoincrement().default(0), + col163: double('col11').primaryKey().autoincrement().default(0), + col164: double('col11').primaryKey().autoincrement().default(0), + col165: double('col11').primaryKey().autoincrement().default(0), + col166: double('col11').primaryKey().autoincrement().default(0), + col168: double('col11').primaryKey().autoincrement().default(0), + col169: double('col11').primaryKey().autoincrement().default(0), + col170: double('col11').primaryKey().autoincrement().default(0), + col171: double('col11').primaryKey().autoincrement().default(0), + col172: double('col11').primaryKey().autoincrement().default(0), + col173: double('col11').primaryKey().autoincrement().default(0), + col174: double('col11').primaryKey().autoincrement().default(0), + col175: double('col11').primaryKey().autoincrement().default(0), + col176: double('col11').primaryKey().autoincrement().default(0), + col178: double('col11').primaryKey().autoincrement().default(0), + col179: double('col11').primaryKey().autoincrement().default(0), + col180: double('col11').primaryKey().autoincrement().default(0), + col181: double('col11').primaryKey().autoincrement().default(0), + col182: double('col11').primaryKey().autoincrement().default(0), + col183: double('col11').primaryKey().autoincrement().default(0), + col184: double('col11').primaryKey().autoincrement().default(0), + col185: double('col11').primaryKey().autoincrement().default(0), + col186: double('col11').primaryKey().autoincrement().default(0), + col188: double('col11').primaryKey().autoincrement().default(0), + col189: double('col11').primaryKey().autoincrement().default(0), + col190: double('col11').primaryKey().autoincrement().default(0), + col191: double('col11').primaryKey().autoincrement().default(0), + col192: double('col11').primaryKey().autoincrement().default(0), + col193: double('col11').primaryKey().autoincrement().default(0), + col194: double('col11').primaryKey().autoincrement().default(0), + col195: double('col11').primaryKey().autoincrement().default(0), + col196: double('col11').primaryKey().autoincrement().default(0), + col198: double('col11').primaryKey().autoincrement().default(0), + col199: double('col11').primaryKey().autoincrement().default(0), + col200: double('col2').primaryKey().autoincrement().default(0), + col201: double('col2').primaryKey().autoincrement().default(0), + col202: double('col2').primaryKey().autoincrement().default(0), + col203: double('col2').primaryKey().autoincrement().default(0), + col204: double('col2').primaryKey().autoincrement().default(0), + col205: double('col2').primaryKey().autoincrement().default(0), + col206: double('col2').primaryKey().autoincrement().default(0), + col208: double('col2').primaryKey().autoincrement().default(0), + col209: double('col2').primaryKey().autoincrement().default(0), + col210: double('col21').primaryKey().autoincrement().default(0), + col211: double('col21').primaryKey().autoincrement().default(0), + col212: double('col21').primaryKey().autoincrement().default(0), + col213: double('col21').primaryKey().autoincrement().default(0), + col214: double('col21').primaryKey().autoincrement().default(0), + col215: double('col21').primaryKey().autoincrement().default(0), + col216: double('col21').primaryKey().autoincrement().default(0), + col218: double('col21').primaryKey().autoincrement().default(0), + col219: double('col21').primaryKey().autoincrement().default(0), + col220: double('col21').primaryKey().autoincrement().default(0), + col221: double('col21').primaryKey().autoincrement().default(0), + col222: double('col21').primaryKey().autoincrement().default(0), + col223: double('col21').primaryKey().autoincrement().default(0), + col224: double('col21').primaryKey().autoincrement().default(0), + col225: double('col21').primaryKey().autoincrement().default(0), + col226: double('col21').primaryKey().autoincrement().default(0), + col228: double('col21').primaryKey().autoincrement().default(0), + col229: double('col21').primaryKey().autoincrement().default(0), + col230: double('col21').primaryKey().autoincrement().default(0), + col231: double('col21').primaryKey().autoincrement().default(0), + col232: double('col21').primaryKey().autoincrement().default(0), + col233: double('col21').primaryKey().autoincrement().default(0), + col234: double('col21').primaryKey().autoincrement().default(0), + col235: double('col21').primaryKey().autoincrement().default(0), + col236: double('col21').primaryKey().autoincrement().default(0), + col238: double('col21').primaryKey().autoincrement().default(0), + col239: double('col21').primaryKey().autoincrement().default(0), + col240: double('col21').primaryKey().autoincrement().default(0), + col241: double('col21').primaryKey().autoincrement().default(0), + col242: double('col21').primaryKey().autoincrement().default(0), + col243: double('col21').primaryKey().autoincrement().default(0), + col244: double('col21').primaryKey().autoincrement().default(0), + col245: double('col21').primaryKey().autoincrement().default(0), + col246: double('col21').primaryKey().autoincrement().default(0), + col248: double('col21').primaryKey().autoincrement().default(0), + col249: double('col21').primaryKey().autoincrement().default(0), + col250: double('col21').primaryKey().autoincrement().default(0), + col251: double('col21').primaryKey().autoincrement().default(0), + col252: double('col21').primaryKey().autoincrement().default(0), + col253: double('col21').primaryKey().autoincrement().default(0), + col254: double('col21').primaryKey().autoincrement().default(0), + col255: double('col21').primaryKey().autoincrement().default(0), + col256: double('col21').primaryKey().autoincrement().default(0), + col258: double('col21').primaryKey().autoincrement().default(0), + col259: double('col21').primaryKey().autoincrement().default(0), + col260: double('col21').primaryKey().autoincrement().default(0), + col261: double('col21').primaryKey().autoincrement().default(0), + col262: double('col21').primaryKey().autoincrement().default(0), + col263: double('col21').primaryKey().autoincrement().default(0), + col264: double('col21').primaryKey().autoincrement().default(0), + col265: double('col21').primaryKey().autoincrement().default(0), + col266: double('col21').primaryKey().autoincrement().default(0), + col268: double('col21').primaryKey().autoincrement().default(0), + col269: double('col21').primaryKey().autoincrement().default(0), + col270: double('col21').primaryKey().autoincrement().default(0), + col271: double('col21').primaryKey().autoincrement().default(0), + col272: double('col21').primaryKey().autoincrement().default(0), + col273: double('col21').primaryKey().autoincrement().default(0), + col274: double('col21').primaryKey().autoincrement().default(0), + col275: double('col21').primaryKey().autoincrement().default(0), + col276: double('col21').primaryKey().autoincrement().default(0), + col278: double('col21').primaryKey().autoincrement().default(0), + col279: double('col21').primaryKey().autoincrement().default(0), + col280: double('col21').primaryKey().autoincrement().default(0), + col281: double('col21').primaryKey().autoincrement().default(0), + col282: double('col21').primaryKey().autoincrement().default(0), + col283: double('col21').primaryKey().autoincrement().default(0), + col284: double('col21').primaryKey().autoincrement().default(0), + col285: double('col21').primaryKey().autoincrement().default(0), + col286: double('col21').primaryKey().autoincrement().default(0), + col288: double('col21').primaryKey().autoincrement().default(0), + col289: double('col21').primaryKey().autoincrement().default(0), + col290: double('col21').primaryKey().autoincrement().default(0), + col291: double('col21').primaryKey().autoincrement().default(0), + col292: double('col21').primaryKey().autoincrement().default(0), + col293: double('col21').primaryKey().autoincrement().default(0), + col294: double('col21').primaryKey().autoincrement().default(0), + col295: double('col21').primaryKey().autoincrement().default(0), + col296: double('col21').primaryKey().autoincrement().default(0), + col298: double('col21').primaryKey().autoincrement().default(0), + col299: double('col21').primaryKey().autoincrement().default(0), + col300: double('col3').primaryKey().autoincrement().default(0), + col301: double('col3').primaryKey().autoincrement().default(0), + col302: double('col3').primaryKey().autoincrement().default(0), + col303: double('col3').primaryKey().autoincrement().default(0), + col304: double('col3').primaryKey().autoincrement().default(0), + col305: double('col3').primaryKey().autoincrement().default(0), + col306: double('col3').primaryKey().autoincrement().default(0), + col308: double('col3').primaryKey().autoincrement().default(0), + col309: double('col3').primaryKey().autoincrement().default(0), + col310: double('col31').primaryKey().autoincrement().default(0), + col311: double('col31').primaryKey().autoincrement().default(0), + col312: double('col31').primaryKey().autoincrement().default(0), + col313: double('col31').primaryKey().autoincrement().default(0), + col314: double('col31').primaryKey().autoincrement().default(0), + col315: double('col31').primaryKey().autoincrement().default(0), + col316: double('col31').primaryKey().autoincrement().default(0), + col318: double('col31').primaryKey().autoincrement().default(0), + col319: double('col31').primaryKey().autoincrement().default(0), + col320: double('col31').primaryKey().autoincrement().default(0), + col321: double('col31').primaryKey().autoincrement().default(0), + col322: double('col31').primaryKey().autoincrement().default(0), + col323: double('col31').primaryKey().autoincrement().default(0), + col324: double('col31').primaryKey().autoincrement().default(0), + col325: double('col31').primaryKey().autoincrement().default(0), + col326: double('col31').primaryKey().autoincrement().default(0), + col328: double('col31').primaryKey().autoincrement().default(0), + col329: double('col31').primaryKey().autoincrement().default(0), + col330: double('col31').primaryKey().autoincrement().default(0), + col331: double('col31').primaryKey().autoincrement().default(0), + col332: double('col31').primaryKey().autoincrement().default(0), + col333: double('col31').primaryKey().autoincrement().default(0), + col334: double('col31').primaryKey().autoincrement().default(0), + col335: double('col31').primaryKey().autoincrement().default(0), + col336: double('col31').primaryKey().autoincrement().default(0), + col338: double('col31').primaryKey().autoincrement().default(0), + col339: double('col31').primaryKey().autoincrement().default(0), + col340: double('col31').primaryKey().autoincrement().default(0), + col341: double('col31').primaryKey().autoincrement().default(0), + col342: double('col31').primaryKey().autoincrement().default(0), + col343: double('col31').primaryKey().autoincrement().default(0), + col344: double('col31').primaryKey().autoincrement().default(0), + col345: double('col31').primaryKey().autoincrement().default(0), + col346: double('col31').primaryKey().autoincrement().default(0), + col348: double('col31').primaryKey().autoincrement().default(0), + col349: double('col31').primaryKey().autoincrement().default(0), + col350: double('col31').primaryKey().autoincrement().default(0), + col351: double('col31').primaryKey().autoincrement().default(0), + col352: double('col31').primaryKey().autoincrement().default(0), + col353: double('col31').primaryKey().autoincrement().default(0), + col354: double('col31').primaryKey().autoincrement().default(0), + col355: double('col31').primaryKey().autoincrement().default(0), + col356: double('col31').primaryKey().autoincrement().default(0), + col358: double('col31').primaryKey().autoincrement().default(0), + col359: double('col31').primaryKey().autoincrement().default(0), + col360: double('col31').primaryKey().autoincrement().default(0), + col361: double('col31').primaryKey().autoincrement().default(0), + col362: double('col31').primaryKey().autoincrement().default(0), + col363: double('col31').primaryKey().autoincrement().default(0), + col364: double('col31').primaryKey().autoincrement().default(0), + col365: double('col31').primaryKey().autoincrement().default(0), + col366: double('col31').primaryKey().autoincrement().default(0), + col368: double('col31').primaryKey().autoincrement().default(0), + col369: double('col31').primaryKey().autoincrement().default(0), + col370: double('col31').primaryKey().autoincrement().default(0), + col371: double('col31').primaryKey().autoincrement().default(0), + col372: double('col31').primaryKey().autoincrement().default(0), + col373: double('col31').primaryKey().autoincrement().default(0), + col374: double('col31').primaryKey().autoincrement().default(0), + col375: double('col31').primaryKey().autoincrement().default(0), + col376: double('col31').primaryKey().autoincrement().default(0), + col378: double('col31').primaryKey().autoincrement().default(0), + col379: double('col31').primaryKey().autoincrement().default(0), + col380: double('col31').primaryKey().autoincrement().default(0), + col381: double('col31').primaryKey().autoincrement().default(0), + col382: double('col31').primaryKey().autoincrement().default(0), + col383: double('col31').primaryKey().autoincrement().default(0), + col384: double('col31').primaryKey().autoincrement().default(0), + col385: double('col31').primaryKey().autoincrement().default(0), + col386: double('col31').primaryKey().autoincrement().default(0), + col388: double('col31').primaryKey().autoincrement().default(0), + col389: double('col31').primaryKey().autoincrement().default(0), + col390: double('col31').primaryKey().autoincrement().default(0), + col391: double('col31').primaryKey().autoincrement().default(0), + col392: double('col31').primaryKey().autoincrement().default(0), + col393: double('col31').primaryKey().autoincrement().default(0), + col394: double('col31').primaryKey().autoincrement().default(0), + col395: double('col31').primaryKey().autoincrement().default(0), + col396: double('col31').primaryKey().autoincrement().default(0), + col398: double('col31').primaryKey().autoincrement().default(0), + col399: double('col31').primaryKey().autoincrement().default(0), + col400: double('col4').primaryKey().autoincrement().default(0), + col401: double('col4').primaryKey().autoincrement().default(0), + col402: double('col4').primaryKey().autoincrement().default(0), + col403: double('col4').primaryKey().autoincrement().default(0), + col404: double('col4').primaryKey().autoincrement().default(0), + col405: double('col4').primaryKey().autoincrement().default(0), + col406: double('col4').primaryKey().autoincrement().default(0), + col408: double('col4').primaryKey().autoincrement().default(0), + col409: double('col4').primaryKey().autoincrement().default(0), + col410: double('col41').primaryKey().autoincrement().default(0), + col411: double('col41').primaryKey().autoincrement().default(0), + col412: double('col41').primaryKey().autoincrement().default(0), + col413: double('col41').primaryKey().autoincrement().default(0), + col414: double('col41').primaryKey().autoincrement().default(0), + col415: double('col41').primaryKey().autoincrement().default(0), + col416: double('col41').primaryKey().autoincrement().default(0), + col418: double('col41').primaryKey().autoincrement().default(0), + col419: double('col41').primaryKey().autoincrement().default(0), + col420: double('col41').primaryKey().autoincrement().default(0), + col421: double('col41').primaryKey().autoincrement().default(0), + col422: double('col41').primaryKey().autoincrement().default(0), + col423: double('col41').primaryKey().autoincrement().default(0), + col424: double('col41').primaryKey().autoincrement().default(0), + col425: double('col41').primaryKey().autoincrement().default(0), + col426: double('col41').primaryKey().autoincrement().default(0), + col428: double('col41').primaryKey().autoincrement().default(0), + col429: double('col41').primaryKey().autoincrement().default(0), + col430: double('col41').primaryKey().autoincrement().default(0), + col431: double('col41').primaryKey().autoincrement().default(0), + col432: double('col41').primaryKey().autoincrement().default(0), + col433: double('col41').primaryKey().autoincrement().default(0), + col434: double('col41').primaryKey().autoincrement().default(0), + col435: double('col41').primaryKey().autoincrement().default(0), + col436: double('col41').primaryKey().autoincrement().default(0), + col438: double('col41').primaryKey().autoincrement().default(0), + col439: double('col41').primaryKey().autoincrement().default(0), + col440: double('col41').primaryKey().autoincrement().default(0), + col441: double('col41').primaryKey().autoincrement().default(0), + col442: double('col41').primaryKey().autoincrement().default(0), + col443: double('col41').primaryKey().autoincrement().default(0), + col444: double('col41').primaryKey().autoincrement().default(0), + col445: double('col41').primaryKey().autoincrement().default(0), + col446: double('col41').primaryKey().autoincrement().default(0), + col448: double('col41').primaryKey().autoincrement().default(0), + col449: double('col41').primaryKey().autoincrement().default(0), + col450: double('col41').primaryKey().autoincrement().default(0), + col451: double('col41').primaryKey().autoincrement().default(0), + col452: double('col41').primaryKey().autoincrement().default(0), + col453: double('col41').primaryKey().autoincrement().default(0), + col454: double('col41').primaryKey().autoincrement().default(0), + col455: double('col41').primaryKey().autoincrement().default(0), + col456: double('col41').primaryKey().autoincrement().default(0), + col458: double('col41').primaryKey().autoincrement().default(0), + col459: double('col41').primaryKey().autoincrement().default(0), + col460: double('col41').primaryKey().autoincrement().default(0), + col461: double('col41').primaryKey().autoincrement().default(0), + col462: double('col41').primaryKey().autoincrement().default(0), + col463: double('col41').primaryKey().autoincrement().default(0), + col464: double('col41').primaryKey().autoincrement().default(0), + col465: double('col41').primaryKey().autoincrement().default(0), + col466: double('col41').primaryKey().autoincrement().default(0), + col468: double('col41').primaryKey().autoincrement().default(0), + col469: double('col41').primaryKey().autoincrement().default(0), + col470: double('col41').primaryKey().autoincrement().default(0), + col471: double('col41').primaryKey().autoincrement().default(0), + col472: double('col41').primaryKey().autoincrement().default(0), + col473: double('col41').primaryKey().autoincrement().default(0), + col474: double('col41').primaryKey().autoincrement().default(0), + col475: double('col41').primaryKey().autoincrement().default(0), + col476: double('col41').primaryKey().autoincrement().default(0), + col478: double('col41').primaryKey().autoincrement().default(0), + col479: double('col41').primaryKey().autoincrement().default(0), + col480: double('col41').primaryKey().autoincrement().default(0), + col481: double('col41').primaryKey().autoincrement().default(0), + col482: double('col41').primaryKey().autoincrement().default(0), + col483: double('col41').primaryKey().autoincrement().default(0), + col484: double('col41').primaryKey().autoincrement().default(0), + col485: double('col41').primaryKey().autoincrement().default(0), + col486: double('col41').primaryKey().autoincrement().default(0), + col488: double('col41').primaryKey().autoincrement().default(0), + col489: double('col41').primaryKey().autoincrement().default(0), + col490: double('col41').primaryKey().autoincrement().default(0), + col491: double('col41').primaryKey().autoincrement().default(0), + col492: double('col41').primaryKey().autoincrement().default(0), + col493: double('col41').primaryKey().autoincrement().default(0), + col494: double('col41').primaryKey().autoincrement().default(0), + col495: double('col41').primaryKey().autoincrement().default(0), + col496: double('col41').primaryKey().autoincrement().default(0), + col498: double('col41').primaryKey().autoincrement().default(0), + col499: double('col41').primaryKey().autoincrement().default(0), + col500: double('col5').primaryKey().autoincrement().default(0), + col501: double('col5').primaryKey().autoincrement().default(0), + col502: double('col5').primaryKey().autoincrement().default(0), + col503: double('col5').primaryKey().autoincrement().default(0), + col504: double('col5').primaryKey().autoincrement().default(0), + col505: double('col5').primaryKey().autoincrement().default(0), + col506: double('col5').primaryKey().autoincrement().default(0), + col508: double('col5').primaryKey().autoincrement().default(0), + col509: double('col5').primaryKey().autoincrement().default(0), + col510: double('col51').primaryKey().autoincrement().default(0), + col511: double('col51').primaryKey().autoincrement().default(0), + col512: double('col51').primaryKey().autoincrement().default(0), + col513: double('col51').primaryKey().autoincrement().default(0), + col514: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col515: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col516: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col518: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col519: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col520: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col521: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col522: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col523: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col524: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col525: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col526: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col528: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col529: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col530: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col531: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col532: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col533: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col534: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col535: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col536: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col538: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col539: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col540: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col541: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col542: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col543: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col544: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col545: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col546: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col548: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col549: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col550: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col551: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col552: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col553: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col554: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col555: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col556: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col558: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col559: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col560: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col561: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col562: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col563: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col564: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col565: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col566: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col568: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col569: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col570: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col571: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col572: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col573: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col574: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col575: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col576: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col578: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col579: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col580: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col581: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col582: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col583: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col584: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col585: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col586: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col588: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col589: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col590: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col591: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col592: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col593: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col594: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col595: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col596: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col598: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col599: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col600: bigint('col6', { mode: 'number' }).primaryKey().autoincrement().default(0), + col601: double('col6').primaryKey().autoincrement().default(0), + col602: double('col6').primaryKey().autoincrement().default(0), + col603: double('col6').primaryKey().autoincrement().default(0), + col604: double('col6').primaryKey().autoincrement().default(0), + col605: double('col6').primaryKey().autoincrement().default(0), + col606: double('col6').primaryKey().autoincrement().default(0), + col608: double('col6').primaryKey().autoincrement().default(0), + col609: double('col6').primaryKey().autoincrement().default(0), + col610: double('col61').primaryKey().autoincrement().default(0), + col611: double('col61').primaryKey().autoincrement().default(0), + col612: double('col61').primaryKey().autoincrement().default(0), + col613: double('col61').primaryKey().autoincrement().default(0), + col614: double('col61').primaryKey().autoincrement().default(0), + col615: double('col61').primaryKey().autoincrement().default(0), + col616: double('col61').primaryKey().autoincrement().default(0), + col618: double('col61').primaryKey().autoincrement().default(0), + col619: double('col61').primaryKey().autoincrement().default(0), + col620: double('col61').primaryKey().autoincrement().default(0), + col621: double('col61').primaryKey().autoincrement().default(0), + col622: double('col61').primaryKey().autoincrement().default(0), + col623: double('col61').primaryKey().autoincrement().default(0), + col624: double('col61').primaryKey().autoincrement().default(0), + col625: double('col61').primaryKey().autoincrement().default(0), + col626: double('col61').primaryKey().autoincrement().default(0), + col628: double('col61').primaryKey().autoincrement().default(0), + col629: double('col61').primaryKey().autoincrement().default(0), + col630: double('col61').primaryKey().autoincrement().default(0), + col631: double('col61').primaryKey().autoincrement().default(0), + col632: double('col61').primaryKey().autoincrement().default(0), + col633: double('col61').primaryKey().autoincrement().default(0), + col634: double('col61').primaryKey().autoincrement().default(0), + col635: double('col61').primaryKey().autoincrement().default(0), + col636: double('col61').primaryKey().autoincrement().default(0), + col638: double('col61').primaryKey().autoincrement().default(0), + col639: double('col61').primaryKey().autoincrement().default(0), + col640: double('col61').primaryKey().autoincrement().default(0), + col641: double('col61').primaryKey().autoincrement().default(0), + col642: double('col61').primaryKey().autoincrement().default(0), + col643: double('col61').primaryKey().autoincrement().default(0), + col644: double('col61').primaryKey().autoincrement().default(0), + col645: double('col61').primaryKey().autoincrement().default(0), + col646: double('col61').primaryKey().autoincrement().default(0), + col648: double('col61').primaryKey().autoincrement().default(0), + col649: double('col61').primaryKey().autoincrement().default(0), + col650: double('col61').primaryKey().autoincrement().default(0), + col651: double('col61').primaryKey().autoincrement().default(0), + col652: double('col61').primaryKey().autoincrement().default(0), + col653: double('col61').primaryKey().autoincrement().default(0), + col654: double('col61').primaryKey().autoincrement().default(0), + col655: double('col61').primaryKey().autoincrement().default(0), + col656: double('col61').primaryKey().autoincrement().default(0), + col658: double('col61').primaryKey().autoincrement().default(0), + col659: double('col61').primaryKey().autoincrement().default(0), + col660: double('col61').primaryKey().autoincrement().default(0), + col661: double('col61').primaryKey().autoincrement().default(0), + col662: double('col61').primaryKey().autoincrement().default(0), + col663: double('col61').primaryKey().autoincrement().default(0), + col664: double('col61').primaryKey().autoincrement().default(0), + col665: double('col61').primaryKey().autoincrement().default(0), + col666: double('col61').primaryKey().autoincrement().default(0), + col668: double('col61').primaryKey().autoincrement().default(0), + col669: double('col61').primaryKey().autoincrement().default(0), + col670: double('col61').primaryKey().autoincrement().default(0), + col671: double('col61').primaryKey().autoincrement().default(0), + col672: double('col61').primaryKey().autoincrement().default(0), + col673: double('col61').primaryKey().autoincrement().default(0), + col674: double('col61').primaryKey().autoincrement().default(0), + col675: double('col61').primaryKey().autoincrement().default(0), + col676: double('col61').primaryKey().autoincrement().default(0), + col678: double('col61').primaryKey().autoincrement().default(0), + col679: double('col61').primaryKey().autoincrement().default(0), + col680: double('col61').primaryKey().autoincrement().default(0), + col681: double('col61').primaryKey().autoincrement().default(0), + col682: double('col61').primaryKey().autoincrement().default(0), + col683: double('col61').primaryKey().autoincrement().default(0), + col684: double('col61').primaryKey().autoincrement().default(0), + col685: double('col61').primaryKey().autoincrement().default(0), + col686: double('col61').primaryKey().autoincrement().default(0), + col688: double('col61').primaryKey().autoincrement().default(0), + col689: double('col61').primaryKey().autoincrement().default(0), + col690: double('col61').primaryKey().autoincrement().default(0), + col691: double('col61').primaryKey().autoincrement().default(0), + col692: double('col61').primaryKey().autoincrement().default(0), + col693: double('col61').primaryKey().autoincrement().default(0), + col694: double('col61').primaryKey().autoincrement().default(0), + col695: double('col61').primaryKey().autoincrement().default(0), + col696: double('col61').primaryKey().autoincrement().default(0), + col698: double('col61').primaryKey().autoincrement().default(0), + col699: double('col61').primaryKey().autoincrement().default(0), + col700: double('col7').primaryKey().autoincrement().default(0), + col701: double('col7').primaryKey().autoincrement().default(0), + col702: double('col7').primaryKey().autoincrement().default(0), + col703: double('col7').primaryKey().autoincrement().default(0), + col704: double('col7').primaryKey().autoincrement().default(0), + col705: double('col7').primaryKey().autoincrement().default(0), + col706: double('col7').primaryKey().autoincrement().default(0), + col708: double('col7').primaryKey().autoincrement().default(0), + col709: double('col7').primaryKey().autoincrement().default(0), + col710: double('col71').primaryKey().autoincrement().default(0), + col711: double('col71').primaryKey().autoincrement().default(0), + col712: double('col71').primaryKey().autoincrement().default(0), + col713: double('col71').primaryKey().autoincrement().default(0), + col714: double('col71').primaryKey().autoincrement().default(0), + col715: double('col71').primaryKey().autoincrement().default(0), + col716: double('col71').primaryKey().autoincrement().default(0), + col718: double('col71').primaryKey().autoincrement().default(0), + col719: double('col71').primaryKey().autoincrement().default(0), + col720: double('col71').primaryKey().autoincrement().default(0), + col721: double('col71').primaryKey().autoincrement().default(0), + col722: double('col71').primaryKey().autoincrement().default(0), + col723: double('col71').primaryKey().autoincrement().default(0), + col724: double('col71').primaryKey().autoincrement().default(0), + col725: double('col71').primaryKey().autoincrement().default(0), + col726: double('col71').primaryKey().autoincrement().default(0), + col728: double('col71').primaryKey().autoincrement().default(0), + col729: double('col71').primaryKey().autoincrement().default(0), + col730: double('col71').primaryKey().autoincrement().default(0), + col731: double('col71').primaryKey().autoincrement().default(0), + col732: double('col71').primaryKey().autoincrement().default(0), + col733: double('col71').primaryKey().autoincrement().default(0), + col734: double('col71').primaryKey().autoincrement().default(0), + col735: double('col71').primaryKey().autoincrement().default(0), + col736: double('col71').primaryKey().autoincrement().default(0), + col738: double('col71').primaryKey().autoincrement().default(0), + col739: double('col71').primaryKey().autoincrement().default(0), + col740: double('col71').primaryKey().autoincrement().default(0), + col741: double('col71').primaryKey().autoincrement().default(0), + col742: double('col71').primaryKey().autoincrement().default(0), + col743: double('col71').primaryKey().autoincrement().default(0), + col744: double('col71').primaryKey().autoincrement().default(0), + col745: double('col71').primaryKey().autoincrement().default(0), + col746: double('col71').primaryKey().autoincrement().default(0), + col748: double('col71').primaryKey().autoincrement().default(0), + col749: double('col71').primaryKey().autoincrement().default(0), + col750: double('col71').primaryKey().autoincrement().default(0), + col751: double('col71').primaryKey().autoincrement().default(0), + col752: double('col71').primaryKey().autoincrement().default(0), + col753: double('col71').primaryKey().autoincrement().default(0), + col754: double('col71').primaryKey().autoincrement().default(0), + col755: double('col71').primaryKey().autoincrement().default(0), + col756: double('col71').primaryKey().autoincrement().default(0), + col758: double('col71').primaryKey().autoincrement().default(0), + col759: double('col71').primaryKey().autoincrement().default(0), + col760: double('col71').primaryKey().autoincrement().default(0), + col761: double('col71').primaryKey().autoincrement().default(0), + col762: double('col71').primaryKey().autoincrement().default(0), + col763: double('col71').primaryKey().autoincrement().default(0), + col764: double('col71').primaryKey().autoincrement().default(0), + col765: double('col71').primaryKey().autoincrement().default(0), + col766: double('col71').primaryKey().autoincrement().default(0), + col768: double('col71').primaryKey().autoincrement().default(0), + col769: double('col71').primaryKey().autoincrement().default(0), + col770: double('col71').primaryKey().autoincrement().default(0), + col771: double('col71').primaryKey().autoincrement().default(0), + col772: double('col71').primaryKey().autoincrement().default(0), + col773: double('col71').primaryKey().autoincrement().default(0), + col774: double('col71').primaryKey().autoincrement().default(0), + col775: double('col71').primaryKey().autoincrement().default(0), + col776: double('col71').primaryKey().autoincrement().default(0), + col778: double('col71').primaryKey().autoincrement().default(0), + col779: double('col71').primaryKey().autoincrement().default(0), + col780: double('col71').primaryKey().autoincrement().default(0), + col781: double('col71').primaryKey().autoincrement().default(0), + col782: double('col71').primaryKey().autoincrement().default(0), + col783: double('col71').primaryKey().autoincrement().default(0), + col784: double('col71').primaryKey().autoincrement().default(0), + col785: double('col71').primaryKey().autoincrement().default(0), + col786: double('col71').primaryKey().autoincrement().default(0), + col788: double('col71').primaryKey().autoincrement().default(0), + col789: double('col71').primaryKey().autoincrement().default(0), + col790: double('col71').primaryKey().autoincrement().default(0), + col791: double('col71').primaryKey().autoincrement().default(0), + col792: double('col71').primaryKey().autoincrement().default(0), + col793: double('col71').primaryKey().autoincrement().default(0), + col794: double('col71').primaryKey().autoincrement().default(0), + col795: double('col71').primaryKey().autoincrement().default(0), + col796: double('col71').primaryKey().autoincrement().default(0), + col798: double('col71').primaryKey().autoincrement().default(0), + col799: double('col71').primaryKey().autoincrement().default(0), + col800: double('col8').primaryKey().autoincrement().default(0), + col801: double('col8').primaryKey().autoincrement().default(0), + col802: double('col8').primaryKey().autoincrement().default(0), + col803: double('col8').primaryKey().autoincrement().default(0), + col804: double('col8').primaryKey().autoincrement().default(0), + col805: double('col8').primaryKey().autoincrement().default(0), + col806: double('col8').primaryKey().autoincrement().default(0), + col808: double('col8').primaryKey().autoincrement().default(0), + col809: double('col8').primaryKey().autoincrement().default(0), + col810: double('col81').primaryKey().autoincrement().default(0), + col811: double('col81').primaryKey().autoincrement().default(0), + col812: double('col81').primaryKey().autoincrement().default(0), + col813: double('col81').primaryKey().autoincrement().default(0), + col814: double('col81').primaryKey().autoincrement().default(0), + col815: double('col81').primaryKey().autoincrement().default(0), + col816: double('col81').primaryKey().autoincrement().default(0), + col818: double('col81').primaryKey().autoincrement().default(0), + col819: double('col81').primaryKey().autoincrement().default(0), + col820: double('col81').primaryKey().autoincrement().default(0), + col821: double('col81').primaryKey().autoincrement().default(0), + col822: double('col81').primaryKey().autoincrement().default(0), + col823: double('col81').primaryKey().autoincrement().default(0), + col824: double('col81').primaryKey().autoincrement().default(0), + col825: double('col81').primaryKey().autoincrement().default(0), + col826: double('col81').primaryKey().autoincrement().default(0), + col828: double('col81').primaryKey().autoincrement().default(0), + col829: double('col81').primaryKey().autoincrement().default(0), + col830: double('col81').primaryKey().autoincrement().default(0), + col831: double('col81').primaryKey().autoincrement().default(0), + col832: double('col81').primaryKey().autoincrement().default(0), + col833: double('col81').primaryKey().autoincrement().default(0), + col834: double('col81').primaryKey().autoincrement().default(0), + col835: double('col81').primaryKey().autoincrement().default(0), + col836: double('col81').primaryKey().autoincrement().default(0), + col838: double('col81').primaryKey().autoincrement().default(0), + col839: double('col81').primaryKey().autoincrement().default(0), + col840: double('col81').primaryKey().autoincrement().default(0), + col841: double('col81').primaryKey().autoincrement().default(0), + col842: double('col81').primaryKey().autoincrement().default(0), + col843: double('col81').primaryKey().autoincrement().default(0), + col844: double('col81').primaryKey().autoincrement().default(0), + col845: double('col81').primaryKey().autoincrement().default(0), + col846: double('col81').primaryKey().autoincrement().default(0), + col848: double('col81').primaryKey().autoincrement().default(0), + col849: double('col81').primaryKey().autoincrement().default(0), + col850: double('col81').primaryKey().autoincrement().default(0), + col851: double('col81').primaryKey().autoincrement().default(0), + col852: double('col81').primaryKey().autoincrement().default(0), + col853: double('col81').primaryKey().autoincrement().default(0), + col854: double('col81').primaryKey().autoincrement().default(0), + col855: double('col81').primaryKey().autoincrement().default(0), + col856: double('col81').primaryKey().autoincrement().default(0), + col858: double('col81').primaryKey().autoincrement().default(0), + col859: double('col81').primaryKey().autoincrement().default(0), + col860: double('col81').primaryKey().autoincrement().default(0), + col861: double('col81').primaryKey().autoincrement().default(0), + col862: double('col81').primaryKey().autoincrement().default(0), + col863: double('col81').primaryKey().autoincrement().default(0), + col864: double('col81').primaryKey().autoincrement().default(0), + col865: double('col81').primaryKey().autoincrement().default(0), + col866: double('col81').primaryKey().autoincrement().default(0), + col868: double('col81').primaryKey().autoincrement().default(0), + col869: double('col81').primaryKey().autoincrement().default(0), + col870: double('col81').primaryKey().autoincrement().default(0), + col871: double('col81').primaryKey().autoincrement().default(0), + col872: double('col81').primaryKey().autoincrement().default(0), + col873: double('col81').primaryKey().autoincrement().default(0), + col874: double('col81').primaryKey().autoincrement().default(0), + col875: double('col81').primaryKey().autoincrement().default(0), + col876: double('col81').primaryKey().autoincrement().default(0), + col878: double('col81').primaryKey().autoincrement().default(0), + col879: double('col81').primaryKey().autoincrement().default(0), + col880: double('col81').primaryKey().autoincrement().default(0), + col881: double('col81').primaryKey().autoincrement().default(0), + col882: double('col81').primaryKey().autoincrement().default(0), + col883: double('col81').primaryKey().autoincrement().default(0), + col884: double('col81').primaryKey().autoincrement().default(0), + col885: double('col81').primaryKey().autoincrement().default(0), + col886: double('col81').primaryKey().autoincrement().default(0), + col888: double('col81').primaryKey().autoincrement().default(0), + col889: double('col81').primaryKey().autoincrement().default(0), + col890: double('col81').primaryKey().autoincrement().default(0), + col891: double('col81').primaryKey().autoincrement().default(0), + col892: double('col81').primaryKey().autoincrement().default(0), + col893: double('col81').primaryKey().autoincrement().default(0), + col894: double('col81').primaryKey().autoincrement().default(0), + col895: double('col81').primaryKey().autoincrement().default(0), + col896: double('col81').primaryKey().autoincrement().default(0), + col898: double('col81').primaryKey().autoincrement().default(0), + col899: double('col81').primaryKey().autoincrement().default(0), + col900: double('col9').primaryKey().autoincrement().default(0), + col901: double('col9').primaryKey().autoincrement().default(0), + col902: double('col9').primaryKey().autoincrement().default(0), + col903: double('col9').primaryKey().autoincrement().default(0), + col904: double('col9').primaryKey().autoincrement().default(0), + col905: double('col9').primaryKey().autoincrement().default(0), + col906: double('col9').primaryKey().autoincrement().default(0), + col908: double('col9').primaryKey().autoincrement().default(0), + col909: double('col9').primaryKey().autoincrement().default(0), + col910: double('col91').primaryKey().autoincrement().default(0), + col911: double('col91').primaryKey().autoincrement().default(0), + col912: double('col91').primaryKey().autoincrement().default(0), + col913: double('col91').primaryKey().autoincrement().default(0), + col914: double('col91').primaryKey().autoincrement().default(0), + col915: double('col91').primaryKey().autoincrement().default(0), + col916: double('col91').primaryKey().autoincrement().default(0), + col918: double('col91').primaryKey().autoincrement().default(0), + col919: double('col91').primaryKey().autoincrement().default(0), + col920: double('col91').primaryKey().autoincrement().default(0), + col921: double('col91').primaryKey().autoincrement().default(0), + col922: double('col91').primaryKey().autoincrement().default(0), + col923: double('col91').primaryKey().autoincrement().default(0), + col924: double('col91').primaryKey().autoincrement().default(0), + col925: double('col91').primaryKey().autoincrement().default(0), + col926: double('col91').primaryKey().autoincrement().default(0), + col928: double('col91').primaryKey().autoincrement().default(0), + col929: double('col91').primaryKey().autoincrement().default(0), + col930: double('col91').primaryKey().autoincrement().default(0), + col931: double('col91').primaryKey().autoincrement().default(0), + col932: double('col91').primaryKey().autoincrement().default(0), + col933: double('col91').primaryKey().autoincrement().default(0), + col934: double('col91').primaryKey().autoincrement().default(0), + col935: double('col91').primaryKey().autoincrement().default(0), + col936: double('col91').primaryKey().autoincrement().default(0), + col938: double('col91').primaryKey().autoincrement().default(0), + col939: double('col91').primaryKey().autoincrement().default(0), + col940: double('col91').primaryKey().autoincrement().default(0), + col941: double('col91').primaryKey().autoincrement().default(0), + col942: double('col91').primaryKey().autoincrement().default(0), + col943: double('col91').primaryKey().autoincrement().default(0), + col944: varchar('col91', { length: 200 }).primaryKey().default('0'), + col945: varchar('col91', { length: 200 }).primaryKey().default('0'), + col946: varchar('col91', { length: 200 }).primaryKey().default('0'), + col948: varchar('col91', { length: 200 }).primaryKey().default('0'), + col949: varchar('col91', { length: 200 }).primaryKey().default('0'), + col950: varchar('col91', { length: 200 }).primaryKey().default('0'), + col951: varchar('col91', { length: 200 }).primaryKey().default('0'), + col952: varchar('col91', { length: 200 }).primaryKey().default('0'), + col953: varchar('col91', { length: 200 }).primaryKey().default('0'), + col954: varchar('col91', { length: 200 }).primaryKey().default('0'), + col955: varchar('col91', { length: 200 }).primaryKey().default('0'), + col956: varchar('col91', { length: 200 }).primaryKey().default('0'), + col958: varchar('col91', { length: 200 }).primaryKey().default('0'), + col959: varchar('col91', { length: 200 }).primaryKey().default('0'), + col960: varchar('col91', { length: 200 }).primaryKey().default('0'), + col961: varchar('col91', { length: 200 }).primaryKey().default('0'), + col962: varchar('col91', { length: 200 }).primaryKey().default('0'), + col963: varchar('col91', { length: 200 }).primaryKey().default('0'), + col964: varchar('col91', { length: 200 }).primaryKey().default('0'), + col965: varchar('col91', { length: 200 }).primaryKey().default('0'), + col966: varchar('col91', { length: 200 }).primaryKey().default('0'), + col968: varchar('col91', { length: 200 }).primaryKey().default('0'), + col969: varchar('col91', { length: 200 }).primaryKey().default('0'), + col970: varchar('col91', { length: 200 }).primaryKey().default('0'), + col971: varchar('col91', { length: 200 }).primaryKey().default('0'), + col972: varchar('col91', { length: 200 }).primaryKey().default('0'), + col973: varchar('col91', { length: 200 }).primaryKey().default('0'), + col974: varchar('col91', { length: 200 }).primaryKey().default('0'), + col975: varchar('col91', { length: 200 }).primaryKey().default('0'), + col976: varchar('col91', { length: 200 }).primaryKey().default('0'), + col978: varchar('col91', { length: 200 }).primaryKey().default('0'), + col979: varchar('col91', { length: 200 }).primaryKey().default('0'), + col980: varchar('col91', { length: 200 }).primaryKey().default('0'), + col981: varchar('col91', { length: 200 }).primaryKey().default('0'), + col982: varchar('col91', { length: 200 }).primaryKey().default('0'), + col983: varchar('col91', { length: 200 }).primaryKey().default('0'), + col984: varchar('col91', { length: 200 }).primaryKey().default('0'), + col985: varchar('col91', { length: 200 }).primaryKey().default('0'), + col986: varchar('col91', { length: 200 }).primaryKey().default('0'), + col988: varchar('col91', { length: 200 }).primaryKey().default('0'), + col989: varchar('col91', { length: 200 }).primaryKey().default('0'), + col990: varchar('col91', { length: 200 }).primaryKey().default('0'), + col991: varchar('col91', { length: 200 }).primaryKey().default('0'), + col992: varchar('col91', { length: 200 }).primaryKey().default('0'), + col993: varchar('col91', { length: 200 }).primaryKey().default('0'), + col994: varchar('col91', { length: 200 }).primaryKey().default('0'), + col995: varchar('col91', { length: 200 }).primaryKey().default('0'), + col996: varchar('col91', { length: 200 }).primaryKey().default('0'), + col998: varchar('col91', { length: 200 }).primaryKey().default('0'), + col999: varchar('col91', { length: 200 }).primaryKey().default('0'), +}); diff --git a/drizzle-orm/type-tests/singlestore/db.ts b/drizzle-orm/type-tests/singlestore/db.ts new file mode 100644 index 000000000..f9bc6ff5f --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/db.ts @@ -0,0 +1,12 @@ +import { createPool } from 'mysql2/promise'; +import { drizzle } from '~/singlestore/index.ts'; + +const pool = createPool({}); + +export const db = drizzle(pool); + +{ + drizzle(pool); + drizzle(pool, {}); + drizzle(pool, { schema: {} }); +} diff --git a/drizzle-orm/type-tests/singlestore/delete.ts b/drizzle-orm/type-tests/singlestore/delete.ts new file mode 100644 index 000000000..0fce8882e --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/delete.ts @@ -0,0 +1,61 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { eq } from '~/expressions.ts'; +import type { SingleStoreDelete } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +const deleteAll = await db.delete(users); +Expect>; + +const deleteAllStmt = db.delete(users).prepare(); +const deleteAllPrepared = await deleteAllStmt.execute(); +Expect>; + +const deleteWhere = await db.delete(users).where(eq(users.id, 1)); +Expect>; + +const deleteWhereStmt = db.delete(users).where(eq(users.id, 1)).prepare(); +const deleteWherePrepared = await deleteWhereStmt.execute(); +Expect>; + +const deleteReturningAll = await db.delete(users); +Expect>; + +const deleteReturningAllStmt = db.delete(users).prepare(); +const deleteReturningAllPrepared = await deleteReturningAllStmt.execute(); +Expect>; + +const deleteReturningPartial = await db.delete(users); +Expect>; + +const deleteReturningPartialStmt = db.delete(users).prepare(); +const deleteReturningPartialPrepared = await deleteReturningPartialStmt.execute(); +Expect>; + +{ + function dynamic(qb: T) { + return qb.where(sql``); + } + + const qbBase = db.delete(users).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .delete(users) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); + + db + .delete(users) + .$dynamic() + .where(sql``) + .where(sql``); +} diff --git a/drizzle-orm/type-tests/singlestore/generated-columns.ts b/drizzle-orm/type-tests/singlestore/generated-columns.ts new file mode 100644 index 000000000..e5b17a9b1 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/generated-columns.ts @@ -0,0 +1,158 @@ +import { type Equal, Expect } from 'type-tests/utils'; +import { type InferInsertModel, type InferSelectModel, sql } from '~/index'; +import { drizzle } from '~/singlestore'; +import { serial, singlestoreTable, text, varchar } from '~/singlestore-core'; +import { db } from './db'; + +const users = singlestoreTable( + 'users', + { + id: serial('id').primaryKey(), + firstName: varchar('first_name', { length: 255 }), + lastName: varchar('last_name', { length: 255 }), + email: text('email').notNull(), + fullName: text('full_name').generatedAlwaysAs(sql`concat_ws(first_name, ' ', last_name)`), + upperName: text('upper_name').generatedAlwaysAs( + sql` case when first_name is null then null else upper(first_name) end `, + ).$type(), // There is no way for drizzle to detect nullability in these cases. This is how the user can work around it + }, +); +{ + type User = typeof users.$inferSelect; + type NewUser = typeof users.$inferInsert; + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }, + User + > + >(); + + Expect< + Equal< + { + email: string; + id?: number | undefined; + firstName?: string | null | undefined; + lastName?: string | null | undefined; + }, + NewUser + > + >(); +} + +{ + type User = InferSelectModel; + type NewUser = InferInsertModel; + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }, + User + > + >(); + + Expect< + Equal< + { + email: string; + id?: number | undefined; + firstName?: string | null | undefined; + lastName?: string | null | undefined; + }, + NewUser + > + >(); +} + +{ + const dbUsers = await db.select().from(users); + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }[], + typeof dbUsers + > + >(); +} + +{ + const db = drizzle({} as any, { schema: { users } }); + + const dbUser = await db.query.users.findFirst(); + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + } | undefined, + typeof dbUser + > + >(); +} + +{ + const db = drizzle({} as any, { schema: { users } }); + + const dbUser = await db.query.users.findMany(); + + Expect< + Equal< + { + id: number; + firstName: string | null; + lastName: string | null; + email: string; + fullName: string | null; + upperName: string | null; + }[], + typeof dbUser + > + >(); +} + +{ + // @ts-expect-error - Can't use the fullName because it's a generated column + await db.insert(users).values({ + firstName: 'test', + lastName: 'test', + email: 'test', + fullName: 'test', + }); +} + +{ + await db.update(users).set({ + firstName: 'test', + lastName: 'test', + email: 'test', + // @ts-expect-error - Can't use the fullName because it's a generated column + fullName: 'test', + }); +} diff --git a/drizzle-orm/type-tests/singlestore/insert.ts b/drizzle-orm/type-tests/singlestore/insert.ts new file mode 100644 index 000000000..738bf669d --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/insert.ts @@ -0,0 +1,135 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { int, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import type { SingleStoreInsert } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +const singlestoreInsertReturning = await db.insert(users).values({ + // ^? + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).$returningId(); + +Expect>; + +const insert = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertPrepared = await insertStmt.execute(); +Expect>; + +const insertSql = await db.insert(users).values({ + homeCity: sql`123`, + class: 'A', + age1: 1, + enumCol: sql`foobar`, +}); +Expect>; + +const insertSqlStmt = db.insert(users).values({ + homeCity: sql`123`, + class: 'A', + age1: 1, + enumCol: sql`foobar`, +}).prepare(); +const insertSqlPrepared = await insertSqlStmt.execute(); +Expect>; + +const insertReturning = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertReturningStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertReturningPrepared = await insertReturningStmt.execute(); +Expect>; + +const insertReturningPartial = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertReturningPartialStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertReturningPartialPrepared = await insertReturningPartialStmt.execute(); +Expect>; + +const insertReturningSql = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: sql`2 + 2`, + enumCol: 'a', +}); +Expect>; + +const insertReturningSqlStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: sql`2 + 2`, + enumCol: 'a', +}).prepare(); +const insertReturningSqlPrepared = await insertReturningSqlStmt.execute(); +Expect>; + +{ + const users = singlestoreTable('users', { + id: int('id').autoincrement().primaryKey(), + name: text('name').notNull(), + age: int('age'), + occupation: text('occupation'), + }); + + await db.insert(users).values({ name: 'John Wick', age: 58, occupation: 'housekeeper' }); +} + +{ + function dynamic(qb: T) { + return qb.onDuplicateKeyUpdate({ set: {} }); + } + + const qbBase = db.insert(users).values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0 }).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + + Expect>; +} + +{ + db + .insert(users) + .values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0 }) + .onDuplicateKeyUpdate({ set: {} }) + // @ts-expect-error method was already called + .onDuplicateKeyUpdate({ set: {} }); +} diff --git a/drizzle-orm/type-tests/singlestore/select.ts b/drizzle-orm/type-tests/singlestore/select.ts new file mode 100644 index 000000000..10a7551a7 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/select.ts @@ -0,0 +1,606 @@ +import { + and, + between, + eq, + exists, + gt, + gte, + ilike, + inArray, + isNotNull, + isNull, + like, + lt, + lte, + ne, + not, + notBetween, + notExists, + notIlike, + notInArray, + notLike, + or, +} from '~/expressions.ts'; +import { alias } from '~/singlestore-core/alias.ts'; +import { param, sql } from '~/sql/sql.ts'; + +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { QueryBuilder, type SingleStoreSelect, type SingleStoreSelectQueryBuilder } from '~/singlestore-core/index.ts'; +import { db } from './db.ts'; +import { cities, classes, newYorkers, users } from './tables.ts'; + +const city = alias(cities, 'city'); +const city1 = alias(cities, 'city1'); + +const join = await db + .select({ + users, + cities, + city, + city1: { + id: city1.id, + }, + }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)) + .rightJoin(city, eq(city.id, users.id)) + .rightJoin(city1, eq(city1.id, users.id)); + +Expect< + Equal< + { + users: { + id: number; + text: string | null; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + } | null; + cities: { + id: number; + name: string; + population: number | null; + } | null; + city: { + id: number; + name: string; + population: number | null; + } | null; + city1: { + id: number; + }; + }[], + typeof join + > +>; + +const join2 = await db + .select({ + userId: users.id, + cityId: cities.id, + }) + .from(users) + .fullJoin(cities, eq(users.id, cities.id)); + +Expect< + Equal< + { + userId: number | null; + cityId: number | null; + }[], + typeof join2 + > +>; + +const join3 = await db + .select({ + userId: users.id, + cityId: cities.id, + classId: classes.id, + }) + .from(users) + .fullJoin(cities, eq(users.id, cities.id)) + .rightJoin(classes, eq(users.id, classes.id)); + +Expect< + Equal< + { + userId: number | null; + cityId: number | null; + classId: number; + }[], + typeof join3 + > +>; + +db + .select() + .from(users) + .where(exists(db.select().from(cities).where(eq(users.homeCity, cities.id)))); + +function mapFunkyFuncResult(valueFromDriver: unknown) { + return { + foo: (valueFromDriver as Record)['foo'], + }; +} + +const age = 1; + +const allOperators = await db + .select({ + col2: sql`5 - ${users.id} + 1`, // unknown + col3: sql`${users.id} + 1`, // number + col33: sql`${users.id} + 1`.mapWith(users.id), // number + col34: sql`${users.id} + 1`.mapWith(mapFunkyFuncResult), // number + col4: sql`one_or_another(${users.id}, ${users.class})`, // string | number + col5: sql`true`, // unknown + col6: sql`true`, // boolean + col7: sql`random()`, // number + col8: sql`some_funky_func(${users.id})`.mapWith(mapFunkyFuncResult), // { foo: string } + col9: sql`greatest(${users.createdAt}, ${param(new Date(), users.createdAt)})`, // unknown + col10: sql`date_or_false(${users.createdAt}, ${param(new Date(), users.createdAt)})`, // Date | boolean + col11: sql`${users.age1} + ${age}`, // unknown + col12: sql`${users.age1} + ${param(age, users.age1)}`, // unknown + col13: sql`lower(${users.class})`, // unknown + col14: sql`length(${users.class})`, // number + count: sql`count(*)::int`, // number + }) + .from(users) + .where(and( + eq(users.id, 1), + ne(users.id, 1), + or(eq(users.id, 1), ne(users.id, 1)), + not(eq(users.id, 1)), + gt(users.id, 1), + gte(users.id, 1), + lt(users.id, 1), + lte(users.id, 1), + inArray(users.id, [1, 2, 3]), + inArray(users.id, db.select({ id: users.id }).from(users)), + inArray(users.id, sql`select id from ${users}`), + notInArray(users.id, [1, 2, 3]), + notInArray(users.id, db.select({ id: users.id }).from(users)), + notInArray(users.id, sql`select id from ${users}`), + isNull(users.subClass), + isNotNull(users.id), + exists(db.select({ id: users.id }).from(users)), + exists(sql`select id from ${users}`), + notExists(db.select({ id: users.id }).from(users)), + notExists(sql`select id from ${users}`), + between(users.id, 1, 2), + notBetween(users.id, 1, 2), + like(users.id, '%1%'), + notLike(users.id, '%1%'), + ilike(users.id, '%1%'), + notIlike(users.id, '%1%'), + )); + +Expect< + Equal<{ + col2: unknown; + col3: number; + col33: number; + col34: { foo: any }; + col4: string | number; + col5: unknown; + col6: boolean; + col7: number; + col8: { + foo: any; + }; + col9: unknown; + col10: boolean | Date; + col11: unknown; + col12: unknown; + col13: unknown; + col14: number; + count: number; + }[], typeof allOperators> +>; + +const textSelect = await db + .select({ + t: users.text, + }) + .from(users); + +Expect>; + +const homeCity = alias(cities, 'homeCity'); +const c = alias(classes, 'c'); +const otherClass = alias(classes, 'otherClass'); +const anotherClass = alias(classes, 'anotherClass'); +const friend = alias(users, 'friend'); +const currentCity = alias(cities, 'currentCity'); +const subscriber = alias(users, 'subscriber'); +const closestCity = alias(cities, 'closestCity'); + +const megaJoin = await db + .select({ + user: { + id: users.id, + maxAge: sql`max(${users.age1})`, + }, + city: { + id: cities.id, + }, + homeCity, + c, + otherClass, + anotherClass, + friend, + currentCity, + subscriber, + closestCity, + }) + .from(users) + .innerJoin(cities, sql`${users.id} = ${cities.id}`) + .innerJoin(homeCity, sql`${users.homeCity} = ${homeCity.id}`) + .innerJoin(c, eq(c.id, users.class)) + .innerJoin(otherClass, sql`${c.id} = ${otherClass.id}`) + .innerJoin(anotherClass, sql`${users.class} = ${anotherClass.id}`) + .innerJoin(friend, sql`${users.id} = ${friend.id}`) + .innerJoin(currentCity, sql`${homeCity.id} = ${currentCity.id}`) + .innerJoin(subscriber, sql`${users.class} = ${subscriber.id}`) + .innerJoin(closestCity, sql`${users.currentCity} = ${closestCity.id}`) + .where(and(sql`${users.age1} > 0`, eq(cities.id, 1))) + .limit(1) + .offset(1); + +Expect< + Equal< + { + user: { + id: number; + maxAge: unknown; + }; + city: { + id: number; + }; + homeCity: { + id: number; + name: string; + population: number | null; + }; + c: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + otherClass: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + anotherClass: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + friend: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + currentCity: { + id: number; + name: string; + population: number | null; + }; + subscriber: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + closestCity: { + id: number; + name: string; + population: number | null; + }; + }[], + typeof megaJoin + > +>; + +const friends = alias(users, 'friends'); + +const join4 = await db + .select({ + user: { + id: users.id, + }, + city: { + id: cities.id, + }, + class: classes, + friend: friends, + }) + .from(users) + .innerJoin(cities, sql`${users.id} = ${cities.id}`) + .innerJoin(classes, sql`${cities.id} = ${classes.id}`) + .innerJoin(friends, sql`${friends.id} = ${users.id}`) + .where(sql`${users.age1} > 0`); + +Expect< + Equal<{ + user: { + id: number; + }; + city: { + id: number; + }; + class: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + friend: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + }[], typeof join4> +>; + +{ + const authenticated = false as boolean; + + const result = await db + .select({ + id: users.id, + ...(authenticated ? { city: users.homeCity } : {}), + }) + .from(users); + + Expect< + Equal< + { + id: number; + city?: number; + }[], + typeof result + > + >; +} + +await db.select().from(users).for('update'); +await db.select().from(users).for('share', { skipLocked: true }); +await db.select().from(users).for('update', { noWait: true }); +await db + .select() + .from(users) + // @ts-expect-error - can't use both skipLocked and noWait + .for('share', { noWait: true, skipLocked: true }); + +{ + const result = await db.select().from(newYorkers); + Expect< + Equal< + { + userId: number; + cityId: number | null; + }[], + typeof result + > + >; +} + +{ + const result = await db.select({ userId: newYorkers.userId }).from(newYorkers); + Expect< + Equal< + { + userId: number; + }[], + typeof result + > + >; +} + +{ + const query = db.select().from(users).prepare().iterator(); + for await (const row of query) { + Expect>(); + } +} + +{ + db + .select() + .from(users) + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + .limit(10) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const qb = db.select().from(users).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +{ + // TODO: add to docs + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const query = new QueryBuilder().select().from(users).$dynamic(); + dynamic(query); +} + +{ + // TODO: add to docs + function paginated(qb: T, page: number) { + return qb.limit(10).offset((page - 1) * 10); + } + + const qb = db.select().from(users).$dynamic(); + const result = await paginated(qb, 1); + + Expect>; +} + +{ + db + .select() + .from(users) + .where(sql``) + .limit(10) + // @ts-expect-error method was already called + .where(sql``); + + db + .select() + .from(users) + .having(sql``) + .limit(10) + // @ts-expect-error method was already called + .having(sql``); + + db + .select() + .from(users) + .groupBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .groupBy(sql``); + + db + .select() + .from(users) + .orderBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .orderBy(sql``); + + db + .select() + .from(users) + .limit(10) + .where(sql``) + // @ts-expect-error method was already called + .limit(10); + + db + .select() + .from(users) + .offset(10) + .limit(10) + // @ts-expect-error method was already called + .offset(10); + + db + .select() + .from(users) + .for('update') + .limit(10) + // @ts-expect-error method was already called + .for('update'); +} diff --git a/drizzle-orm/type-tests/singlestore/set-operators.ts b/drizzle-orm/type-tests/singlestore/set-operators.ts new file mode 100644 index 000000000..aa4f21b9c --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/set-operators.ts @@ -0,0 +1,223 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import { eq } from '~/expressions.ts'; +import { except, intersect, type SingleStoreSetOperator, union, unionAll } from '~/singlestore-core/index.ts'; +import { sql } from '~/sql/index.ts'; +import { db } from './db.ts'; +import { cities, classes, newYorkers, users } from './tables.ts'; + +const unionTest = await db + .select({ id: users.id }) + .from(users) + .union( + db + .select({ id: users.id }) + .from(users), + ); + +Expect>; + +const unionAllTest = await db + .select({ id: users.id, age: users.age1 }) + .from(users) + .unionAll( + db.select({ id: users.id, age: users.age1 }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)), + ); + +Expect>; + +const intersectTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .intersect(({ intersect }) => + intersect( + db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users), + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ) + ); + +Expect>; + +const exceptTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .except( + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ); + +Expect>; + +const union2Test = await union(db.select().from(cities), db.select().from(cities), db.select().from(cities)); + +Expect>; + +const unionAll2Test = await unionAll( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select().from(cities), +); + +Expect>; + +const intersect2Test = await intersect( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), +); + +Expect>; + +const except2Test = await except( + db.select({ + userId: newYorkers.userId, + }) + .from(newYorkers), + db.select({ + userId: newYorkers.userId, + }).from(newYorkers), +); + +Expect>; + +const unionfull = await union(db.select().from(users), db.select().from(users)).orderBy(sql``).limit(1).offset(2); + +Expect< + Equal<{ + id: number; + text: string | null; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }[], typeof unionfull> +>; + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +union(db.select().from(users), db.select().from(users)) + .offset(1) + // @ts-expect-error - method was already called + .offset(2); + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +{ + function dynamic(qb: T) { + return qb.orderBy(sql``).limit(1).offset(2); + } + + const qb = union(db.select().from(users), db.select().from(users)).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + .intersect(({ intersect }) => intersect(db.select().from(users), db.select().from(users))); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select().from(classes).union(db.select({ id: classes.id }).from(classes)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes).where(sql``)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes)); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + db.select({ id: cities.id, name: cities.name }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select().from(cities), +); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities), + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``).limit(3).$dynamic(), + db.select({ id: cities.id, name: cities.name }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: newYorkers.userId }).from(newYorkers), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities).where(sql``), + db.select({ id: sql`${cities.id}` }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities).where(sql``), +); diff --git a/drizzle-orm/type-tests/singlestore/subquery.ts b/drizzle-orm/type-tests/singlestore/subquery.ts new file mode 100644 index 000000000..e8ee4e80b --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/subquery.ts @@ -0,0 +1,97 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, eq } from '~/expressions.ts'; +import { alias, int, serial, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import { sql } from '~/sql/sql.ts'; +import type { DrizzleTypeError, Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = singlestoreTable('names', { + id: serial('id').primaryKey(), + name: text('name'), + authorId: int('author_id'), +}); + +const n1 = db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: sql`count(1)::int`.as('count1'), + }) + .from(names) + .groupBy(names.id, names.name, names.authorId) + .as('n1'); + +const n2 = db + .select({ + id: names.id, + authorId: names.authorId, + totalCount: sql`count(1)::int`.as('totalCount'), + }) + .from(names) + .groupBy(names.id, names.authorId) + .as('n2'); + +const result = await db + .select({ + name: n1.name, + authorId: n1.authorId, + count1: n1.count1, + totalCount: n2.totalCount, + }) + .from(n1) + .innerJoin(n2, and(eq(n2.id, n1.id), eq(n2.authorId, n1.authorId))); + +Expect< + Equal< + { + name: string | null; + authorId: number | null; + count1: number; + totalCount: number; + }[], + typeof result + > +>; + +const names2 = alias(names, 'names2'); + +const sq1 = db + .select({ + id: names.id, + name: names.name, + id2: names2.id, + }) + .from(names) + .leftJoin(names2, eq(names.name, names2.name)) + .as('sq1'); + +const res = await db.select().from(sq1); + +Expect< + Equal< + { + id: number; + name: string | null; + id2: number | null; + }[], + typeof res + > +>; + +{ + const sq = db.select({ count: sql`count(1)::int` }).from(names).as('sq'); + Expect ? true : false>; +} + +const sqUnion = db.select().from(names).union(db.select().from(names2)).as('sqUnion'); + +const resUnion = await db.select().from(sqUnion); + +Expect< + Equal<{ + id: number; + name: string | null; + authorId: number | null; + }[], typeof resUnion> +>; diff --git a/drizzle-orm/type-tests/singlestore/tables.ts b/drizzle-orm/type-tests/singlestore/tables.ts new file mode 100644 index 000000000..18ed96a30 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/tables.ts @@ -0,0 +1,751 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import { eq, gt } from '~/expressions.ts'; +import type { BuildColumn, InferSelectModel, Simplify } from '~/index.ts'; +import { + bigint, + char, + customType, + date, + datetime, + decimal, + index, + int, + json, + longtext, + mediumtext, + primaryKey, + serial, + type SingleStoreColumn, + singlestoreEnum, + singlestoreSchema, + singlestoreTable, + text, + timestamp, + tinytext, + unique, + uniqueIndex, + varchar, +} from '~/singlestore-core/index.ts'; + +import { singlestoreView, type SingleStoreViewWithSelection } from '~/singlestore-core/view.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; + +export const users = singlestoreTable( + 'users_table', + { + id: serial('id').primaryKey(), + homeCity: int('home_city') + .notNull(), + currentCity: int('current_city'), + serialNullable: serial('serial1'), + serialNotNull: serial('serial2').notNull(), + class: text('class', { enum: ['A', 'C'] }).notNull(), + subClass: text('sub_class', { enum: ['B', 'D'] }), + text: text('text'), + age1: int('age1').notNull(), + createdAt: timestamp('created_at', { mode: 'date' }).notNull().defaultNow(), + enumCol: singlestoreEnum('enum_col', ['a', 'b', 'c']).notNull(), + }, + (users) => ({ + usersAge1Idx: uniqueIndex('usersAge1Idx').on(users.class), + usersAge2Idx: index('usersAge2Idx').on(users.class), + uniqueClass: uniqueIndex('uniqueClass') + .on(users.class, users.subClass) + .lock('default') + .algorythm('copy') + .using(`btree`), + pk: primaryKey(users.age1, users.class), + }), +); + +export const cities = singlestoreTable('cities_table', { + id: serial('id').primaryKey(), + name: text('name_db').notNull(), + population: int('population').default(0), +}, (cities) => ({ + citiesNameIdx: index('citiesNameIdx').on(cities.id), +})); + +Expect< + Equal< + { + id: SingleStoreColumn<{ + name: 'id'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + isPrimaryKey: true; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isAutoincrement: true; + hasRuntimeDefault: false; + }, object>; + name: SingleStoreColumn<{ + name: 'name_db'; + tableName: 'cities_table'; + dataType: 'string'; + columnType: 'SingleStoreText'; + data: string; + driverParam: string; + notNull: true; + hasDefault: false; + isPrimaryKey: false; + enumValues: [string, ...string[]]; + baseColumn: never; + generated: undefined; + isAutoincrement: false; + hasRuntimeDefault: false; + }, object>; + population: SingleStoreColumn<{ + name: 'population'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + notNull: false; + hasDefault: true; + isPrimaryKey: false; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isAutoincrement: false; + hasRuntimeDefault: false; + }, object>; + }, + typeof cities._.columns + > +>; + +Expect< + Equal<{ + id: number; + name_db: string; + population: number | null; + }, InferSelectModel> +>; + +Expect< + Equal<{ + id?: number; + name: string; + population?: number | null; + }, typeof cities.$inferInsert> +>; + +export const customSchema = singlestoreSchema('custom_schema'); + +export const citiesCustom = customSchema.table('cities_table', { + id: serial('id').primaryKey(), + name: text('name_db').notNull(), + population: int('population').default(0), +}, (cities) => ({ + citiesNameIdx: index('citiesNameIdx').on(cities.id), +})); + +Expect>; + +export const classes = singlestoreTable('classes_table', { + id: serial('id').primaryKey(), + class: text('class', { enum: ['A', 'C'] }), + subClass: text('sub_class', { enum: ['B', 'D'] }).notNull(), +}); + +/* export const classes2 = singlestoreTable('classes_table', { + id: serial().primaryKey(), + class: text({ enum: ['A', 'C'] }).$dbName('class_db'), + subClass: text({ enum: ['B', 'D'] }).notNull(), +}); */ + +export const newYorkers = singlestoreView('new_yorkers') + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + +Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: false; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > +>; + +{ + const newYorkers = customSchema.view('new_yorkers') + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: false; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = singlestoreView('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }) + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as( + sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ + eq(cities.id, users.homeCity) + } where ${gt(users.age1, 18)}`, + ); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = customSchema.view('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }) + .algorithm('merge') + .definer('root@localhost') + .sqlSecurity('definer') + .as( + sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ + eq(cities.id, users.homeCity) + } where ${gt(users.age1, 18)}`, + ); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = singlestoreView('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }).existing(); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', true, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = customSchema.view('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }).existing(); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', true, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const customText = customType<{ data: string }>({ + dataType() { + return 'text'; + }, + }); + + const t = customText('name').notNull(); + Expect< + Equal< + { + brand: 'Column'; + name: 'name'; + tableName: 'table'; + dataType: 'custom'; + columnType: 'SingleStoreCustomColumn'; + data: string; + driverParam: unknown; + notNull: true; + hasDefault: false; + enumValues: undefined; + baseColumn: never; + dialect: 'singlestore'; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }, + Simplify['_']> + > + >; +} + +{ + singlestoreTable('test', { + bigint: bigint('bigint', { mode: 'bigint' }), + number: bigint('number', { mode: 'number' }), + date: date('date').default(new Date()), + date2: date('date2', { mode: 'date' }).default(new Date()), + date3: date('date3', { mode: 'string' }).default('2020-01-01'), + date4: date('date4', { mode: undefined }).default(new Date()), + datetime: datetime('datetime').default(new Date()), + datetime2: datetime('datetime2', { mode: 'date' }).default(new Date()), + datetime3: datetime('datetime3', { mode: 'string' }).default('2020-01-01'), + datetime4: datetime('datetime4', { mode: undefined }).default(new Date()), + timestamp: timestamp('timestamp').default(new Date()), + timestamp2: timestamp('timestamp2', { mode: 'date' }).default(new Date()), + timestamp3: timestamp('timestamp3', { mode: 'string' }).default('2020-01-01'), + timestamp4: timestamp('timestamp4', { mode: undefined }).default(new Date()), + }); +} + +{ + singlestoreTable('test', { + col1: decimal('col1').default('1'), + }); +} + +{ + const test = singlestoreTable('test', { + test1: singlestoreEnum('test', ['a', 'b', 'c'] as const).notNull(), + test2: singlestoreEnum('test', ['a', 'b', 'c']).notNull(), + test3: varchar('test', { length: 255, enum: ['a', 'b', 'c'] as const }).notNull(), + test4: varchar('test', { length: 255, enum: ['a', 'b', 'c'] }).notNull(), + test5: text('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test6: text('test', { enum: ['a', 'b', 'c'] }).notNull(), + test7: tinytext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test8: tinytext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test9: mediumtext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test10: mediumtext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test11: longtext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test12: longtext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test13: char('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test14: char('test', { enum: ['a', 'b', 'c'] }).notNull(), + test15: text('test').notNull(), + }); + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; +} + +{ // All types with generated columns + const test = singlestoreTable('test', { + test1: singlestoreEnum('test', ['a', 'b', 'c'] as const).generatedAlwaysAs(sql``), + test2: singlestoreEnum('test', ['a', 'b', 'c']).generatedAlwaysAs(sql``), + test3: varchar('test', { length: 255, enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test4: varchar('test', { length: 255, enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test5: text('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test6: text('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test7: tinytext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test8: tinytext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test9: mediumtext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test10: mediumtext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test11: longtext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test12: longtext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test13: char('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test14: char('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test15: text('test').generatedAlwaysAs(sql``), + }); + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; +} + +{ + const getUsersTable = (schemaName: TSchema) => { + return singlestoreSchema(schemaName).table('users', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }); + }; + + const users1 = getUsersTable('id1'); + Expect>; + + const users2 = getUsersTable('id2'); + Expect>; +} + +{ + const internalStaff = singlestoreTable('internal_staff', { + userId: int('user_id').notNull(), + }); + + const customUser = singlestoreTable('custom_user', { + id: int('id').notNull(), + }); + + const ticket = singlestoreTable('ticket', { + staffId: int('staff_id').notNull(), + }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin( + customUser, + eq(internalStaff.userId, customUser.id), + ).as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + Expect< + Equal<{ + internal_staff: { + internal_staff: { + userId: number; + }; + custom_user: { + id: number | null; + }; + } | null; + ticket: { + staffId: number; + }; + }[], typeof mainQuery> + >; +} + +{ + const newYorkers = singlestoreView('new_yorkers') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + + await db.select().from(newYorkers).leftJoin(newYorkers, eq(newYorkers.userId, newYorkers.userId)); +} + +{ + const test = singlestoreTable('test', { + id: text('id').$defaultFn(() => crypto.randomUUID()).primaryKey(), + }); + + Expect< + Equal<{ + id?: string; + }, typeof test.$inferInsert> + >; +} + +{ + singlestoreTable('test', { + id: int('id').$default(() => 1), + id2: int('id').$defaultFn(() => 1), + // @ts-expect-error - should be number + id3: int('id').$default(() => '1'), + // @ts-expect-error - should be number + id4: int('id').$defaultFn(() => '1'), + }); +} +{ + const emailLog = singlestoreTable( + 'email_log', + { + id: int('id', { unsigned: true }).autoincrement().notNull(), + clientId: int('id_client', { unsigned: true }), + receiverEmail: varchar('receiver_email', { length: 255 }).notNull(), + messageId: varchar('message_id', { length: 255 }), + contextId: int('context_id', { unsigned: true }), + contextType: singlestoreEnum('context_type', ['test']).$type<['test']>(), + action: varchar('action', { length: 80 }).$type<['test']>(), + events: json('events').$type<{ t: 'test' }[]>(), + createdAt: timestamp('created_at', { mode: 'string' }).defaultNow().notNull(), + updatedAt: timestamp('updated_at', { mode: 'string' }).defaultNow().onUpdateNow(), + }, + (table) => { + return { + emailLogId: primaryKey({ columns: [table.id], name: 'email_log_id' }), + emailLogMessageIdUnique: unique('email_log_message_id_unique').on(table.messageId), + }; + }, + ); + + Expect< + Equal<{ + receiverEmail: string; + id?: number | undefined; + createdAt?: string | undefined; + clientId?: number | null | undefined; + messageId?: string | null | undefined; + contextId?: number | null | undefined; + contextType?: ['test'] | null | undefined; + action?: ['test'] | null | undefined; + events?: + | { + t: 'test'; + }[] + | null + | undefined; + updatedAt?: string | null | undefined; + }, typeof emailLog.$inferInsert> + >; +} diff --git a/drizzle-orm/type-tests/singlestore/update.ts b/drizzle-orm/type-tests/singlestore/update.ts new file mode 100644 index 000000000..3f10ae2e4 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/update.ts @@ -0,0 +1,26 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import type { SingleStoreUpdate } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/session.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +{ + function dynamic(qb: T) { + return qb.where(sql``); + } + + const qbBase = db.update(users).set({}).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .update(users) + .set({}) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); +} diff --git a/drizzle-orm/type-tests/singlestore/with.ts b/drizzle-orm/type-tests/singlestore/with.ts new file mode 100644 index 000000000..77309e32a --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/with.ts @@ -0,0 +1,80 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { gt, inArray } from '~/expressions.ts'; +import { int, serial, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; + +const orders = singlestoreTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull(), + amount: int('amount').notNull(), + quantity: int('quantity').notNull(), + generated: text('generatedText').generatedAlwaysAs(sql``), +}); + +{ + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: orders.region, + totalSales: orders.amount, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`sum(${orders.quantity})`, + productSales: sql`sum(${orders.amount})`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))); + + Expect< + Equal<{ + region: string; + product: string; + productUnits: number; + productSales: number; + }[], typeof result> + >; + + const allOrdersWith = db.$with('all_orders_with').as(db.select().from(orders)); + const allFromWith = await db.with(allOrdersWith).select().from(allOrdersWith); + + Expect< + Equal<{ + id: number; + region: string; + product: string; + amount: number; + quantity: number; + generated: string | null; + }[], typeof allFromWith> + >; +} diff --git a/integration-tests/.env.example b/integration-tests/.env.example index ceff7d132..cad737330 100644 --- a/integration-tests/.env.example +++ b/integration-tests/.env.example @@ -1,5 +1,6 @@ PG_CONNECTION_STRING="postgres://postgres:postgres@localhost:55432/postgres" MYSQL_CONNECTION_STRING="mysql://root:mysql@127.0.0.1:33306/drizzle" +SINGLESTORE_CONNECTION_STRING="singlestore://root:singlestore@localhost:3306/drizzle" PLANETSCALE_CONNECTION_STRING= TIDB_CONNECTION_STRING= NEON_CONNECTION_STRING= diff --git a/integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql b/integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql new file mode 100644 index 000000000..50efe47da --- /dev/null +++ b/integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql @@ -0,0 +1,20 @@ +CREATE TABLE `cities_migration` ( + `id` int, + `fullname_name` text, + `state` text +); +--> statement-breakpoint +CREATE TABLE `users_migration` ( + `id` int PRIMARY KEY NOT NULL, + `full_name` text, + `phone` int, + `invited_by` int, + `city_id` int, + `date` timestamp DEFAULT now() +); +--> statement-breakpoint +CREATE TABLE `users12` ( + `id` serial AUTO_INCREMENT PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `email` text NOT NULL +); diff --git a/integration-tests/drizzle2/singlestore/meta/0000_snapshot.json b/integration-tests/drizzle2/singlestore/meta/0000_snapshot.json new file mode 100644 index 000000000..63d5ad187 --- /dev/null +++ b/integration-tests/drizzle2/singlestore/meta/0000_snapshot.json @@ -0,0 +1,132 @@ +{ + "version": "1", + "dialect": "singlestore", + "id": "8e8c8378-0496-40f6-88e3-98aab8282b1f", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "cities_migration": { + "name": "cities_migration", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fullname_name": { + "name": "fullname_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {} + }, + "users_migration": { + "name": "users_migration", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "full_name": { + "name": "full_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "invited_by": { + "name": "invited_by", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "city_id": { + "name": "city_id", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "date": { + "name": "date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {} + }, + "users12": { + "name": "users12", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "my_unique_index": { + "name": "my_unique_index", + "columns": [ + "name" + ], + "isUnique": true, + "using": "btree" + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {} + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} diff --git a/integration-tests/drizzle2/singlestore/meta/_journal.json b/integration-tests/drizzle2/singlestore/meta/_journal.json new file mode 100644 index 000000000..49e74f169 --- /dev/null +++ b/integration-tests/drizzle2/singlestore/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "dialect": "singlestore", + "entries": [ + { + "idx": 0, + "version": "1", + "when": 1680270921944, + "tag": "0000_nostalgic_carnage", + "breakpoints": true + } + ] +} diff --git a/integration-tests/tests/relational/singlestore.schema.ts b/integration-tests/tests/relational/singlestore.schema.ts new file mode 100644 index 000000000..ca3386ba0 --- /dev/null +++ b/integration-tests/tests/relational/singlestore.schema.ts @@ -0,0 +1,106 @@ +import { bigint, boolean, primaryKey, serial, singlestoreTable, text, timestamp } from 'drizzle-orm/singlestore-core'; + +import { relations } from 'drizzle-orm'; + +export const usersTable = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + invitedBy: bigint('invited_by', { mode: 'number' }), +}); +export const usersConfig = relations(usersTable, ({ one, many }) => ({ + invitee: one(usersTable, { + fields: [usersTable.invitedBy], + references: [usersTable.id], + }), + usersToGroups: many(usersToGroupsTable), + posts: many(postsTable), + comments: many(commentsTable), +})); + +export const groupsTable = singlestoreTable('groups', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + description: text('description'), +}); +export const groupsConfig = relations(groupsTable, ({ many }) => ({ + usersToGroups: many(usersToGroupsTable), +})); + +export const usersToGroupsTable = singlestoreTable( + 'users_to_groups', + { + id: serial('id').primaryKey(), + userId: bigint('user_id', { mode: 'number' }).notNull(), + groupId: bigint('group_id', { mode: 'number' }).notNull(), + }, + (t) => ({ + pk: primaryKey(t.userId, t.groupId), + }), +); +export const usersToGroupsConfig = relations(usersToGroupsTable, ({ one }) => ({ + group: one(groupsTable, { + fields: [usersToGroupsTable.groupId], + references: [groupsTable.id], + }), + user: one(usersTable, { + fields: [usersToGroupsTable.userId], + references: [usersTable.id], + }), +})); + +export const postsTable = singlestoreTable('posts', { + id: serial('id').primaryKey(), + content: text('content').notNull(), + ownerId: bigint('owner_id', { mode: 'number' }), + createdAt: timestamp('created_at') + .notNull() + .defaultNow(), +}); +export const postsConfig = relations(postsTable, ({ one, many }) => ({ + author: one(usersTable, { + fields: [postsTable.ownerId], + references: [usersTable.id], + }), + comments: many(commentsTable), +})); + +export const commentsTable = singlestoreTable('comments', { + id: serial('id').primaryKey(), + content: text('content').notNull(), + creator: bigint('creator', { mode: 'number' }), + postId: bigint('post_id', { mode: 'number' }), + createdAt: timestamp('created_at') + .notNull() + .defaultNow(), +}); +export const commentsConfig = relations(commentsTable, ({ one, many }) => ({ + post: one(postsTable, { + fields: [commentsTable.postId], + references: [postsTable.id], + }), + author: one(usersTable, { + fields: [commentsTable.creator], + references: [usersTable.id], + }), + likes: many(commentLikesTable), +})); + +export const commentLikesTable = singlestoreTable('comment_likes', { + id: serial('id').primaryKey(), + creator: bigint('creator', { mode: 'number' }), + commentId: bigint('comment_id', { mode: 'number' }), + createdAt: timestamp('created_at') + .notNull() + .defaultNow(), +}); +export const commentLikesConfig = relations(commentLikesTable, ({ one }) => ({ + comment: one(commentsTable, { + fields: [commentLikesTable.commentId], + references: [commentsTable.id], + }), + author: one(usersTable, { + fields: [commentLikesTable.creator], + references: [usersTable.id], + }), +})); diff --git a/integration-tests/tests/relational/singlestore.test.ts b/integration-tests/tests/relational/singlestore.test.ts new file mode 100644 index 000000000..50aa2e8f4 --- /dev/null +++ b/integration-tests/tests/relational/singlestore.test.ts @@ -0,0 +1,6402 @@ +import retry from 'async-retry'; +import Docker from 'dockerode'; +import 'dotenv/config'; +import { desc, DrizzleError, eq, gt, gte, or, placeholder, sql, TransactionRollbackError } from 'drizzle-orm'; +import { drizzle, type SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +import getPort from 'get-port'; +import * as mysql from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, beforeEach, expect, expectTypeOf, test } from 'vitest'; +import * as schema from './singlestore.schema.ts'; + +const { usersTable, postsTable, commentsTable, usersToGroupsTable, groupsTable } = schema; + +const ENABLE_LOGGING = false; + +/* + Test cases: + - querying nested relation without PK with additional fields +*/ + +declare module 'vitest' { + export interface TestContext { + docker: Docker; + singlestoreContainer: Docker.Container; + singlestoreDb: SingleStoreDriverDatabase; + singlestoreClient: mysql.Connection; + } +} + +let globalDocker: Docker; +let singlestoreContainer: Docker.Container; +let db: SingleStoreDriverDatabase; +let client: mysql.Connection; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + ); + + singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return `singlestore://root:singlestore@localhost:${port}/`; +} + +beforeAll(async () => { + const connectionString = process.env['SINGLESTORE_CONNECTION_STRING'] ?? (await createDockerDB()); + client = await retry(async () => { + client = await mysql.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + db = drizzle(client, { schema, logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); +}); + +beforeEach(async (ctx) => { + ctx.singlestoreDb = db; + ctx.singlestoreClient = client; + ctx.docker = globalDocker; + ctx.singlestoreContainer = singlestoreContainer; + + await ctx.singlestoreDb.execute(sql`drop table if exists \`users\``); + await ctx.singlestoreDb.execute(sql`drop table if exists \`groups\``); + await ctx.singlestoreDb.execute(sql`drop table if exists \`users_to_groups\``); + await ctx.singlestoreDb.execute(sql`drop table if exists \`posts\``); + await ctx.singlestoreDb.execute(sql`drop table if exists \`comments\``); + await ctx.singlestoreDb.execute(sql`drop table if exists \`comment_likes\``); + + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`users\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`name\` text NOT NULL, + \`verified\` boolean DEFAULT false NOT NULL, + \`invited_by\` bigint + ); + `, + ); + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`groups\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`name\` text NOT NULL, + \`description\` text + ); + `, + ); + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`users_to_groups\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`user_id\` bigint, + \`group_id\` bigint + ); + `, + ); + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`posts\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`content\` text NOT NULL, + \`owner_id\` bigint, + \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL + ); + `, + ); + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`comments\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`content\` text NOT NULL, + \`creator\` bigint, + \`post_id\` bigint, + \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL + ); + `, + ); + await ctx.singlestoreDb.execute( + sql` + CREATE TABLE \`comment_likes\` ( + \`id\` serial PRIMARY KEY NOT NULL, + \`creator\` bigint, + \`comment_id\` bigint, + \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL + ); + `, + ); +}); + +/* + [Find Many] One relation users+posts +*/ + +test('[Find Many] Get users with posts', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + with: { + posts: true, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithPosts.length).eq(3); + expect(usersWithPosts[0]?.posts.length).eq(1); + expect(usersWithPosts[1]?.posts.length).eq(1); + expect(usersWithPosts[2]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[2]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ id: 3, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find Many] Get users with posts + limit posts', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + with: { + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithPosts.length).eq(3); + expect(usersWithPosts[0]?.posts.length).eq(1); + expect(usersWithPosts[1]?.posts.length).eq(1); + expect(usersWithPosts[2]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[2]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find Many] Get users with posts + limit posts and users', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + limit: 2, + with: { + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithPosts.length).eq(2); + expect(usersWithPosts[0]?.posts.length).eq(1); + expect(usersWithPosts[1]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts + custom fields', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + with: { + posts: true, + }, + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lowerName: string; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + usersWithPosts[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithPosts.length).toEqual(3); + expect(usersWithPosts[0]?.posts.length).toEqual(3); + expect(usersWithPosts[1]?.posts.length).toEqual(2); + expect(usersWithPosts[2]?.posts.length).toEqual(2); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + lowerName: 'dan', + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }, { + id: 2, + ownerId: 1, + content: 'Post1.2', + createdAt: usersWithPosts[0]?.posts[1]?.createdAt, + }, { id: 3, ownerId: 1, content: 'Post1.3', createdAt: usersWithPosts[0]?.posts[2]?.createdAt }], + }); + expect(usersWithPosts[1]).toEqual({ + id: 2, + name: 'Andrew', + lowerName: 'andrew', + verified: false, + invitedBy: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }, { + id: 5, + ownerId: 2, + content: 'Post2.1', + createdAt: usersWithPosts[1]?.posts[1]?.createdAt, + }], + }); + expect(usersWithPosts[2]).toEqual({ + id: 3, + name: 'Alex', + lowerName: 'alex', + verified: false, + invitedBy: null, + posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }, { + id: 7, + ownerId: 3, + content: 'Post3.1', + createdAt: usersWithPosts[2]?.posts[1]?.createdAt, + }], + }); +}); + +test.skip('[Find Many] Get users with posts + custom fields + limits', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + limit: 1, + with: { + posts: { + limit: 1, + }, + }, + extras: (usersTable, { sql }) => ({ + lowerName: sql`lower(${usersTable.name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lowerName: string; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).toEqual(1); + expect(usersWithPosts[0]?.posts.length).toEqual(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + lowerName: 'dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find Many] Get users with posts + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: '1' }, + { ownerId: 1, content: '2' }, + { ownerId: 1, content: '3' }, + { ownerId: 2, content: '4' }, + { ownerId: 2, content: '5' }, + { ownerId: 3, content: '6' }, + { ownerId: 3, content: '7' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + with: { + posts: { + orderBy: (postsTable, { desc }) => [desc(postsTable.content)], + }, + }, + orderBy: (usersTable, { desc }) => [desc(usersTable.id)], + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(3); + expect(usersWithPosts[0]?.posts.length).eq(2); + expect(usersWithPosts[1]?.posts.length).eq(2); + expect(usersWithPosts[2]?.posts.length).eq(3); + + expect(usersWithPosts[2]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 3, ownerId: 1, content: '3', createdAt: usersWithPosts[2]?.posts[2]?.createdAt }, { + id: 2, + ownerId: 1, + content: '2', + createdAt: usersWithPosts[2]?.posts[1]?.createdAt, + }, { id: 1, ownerId: 1, content: '1', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ + id: 5, + ownerId: 2, + content: '5', + createdAt: usersWithPosts[1]?.posts[1]?.createdAt, + }, { id: 4, ownerId: 2, content: '4', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts[0]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ + id: 7, + ownerId: 3, + content: '7', + createdAt: usersWithPosts[0]?.posts[1]?.createdAt, + }, { id: 6, ownerId: 3, content: '6', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + where: (({ id }, { eq }) => eq(id, 1)), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts + where + partial', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: { + id: true, + name: true, + }, + with: { + posts: { + columns: { + id: true, + content: true, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + posts: { + id: number; + content: string; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + posts: [{ id: 1, content: 'Post1' }], + }); +}); + +test('[Find Many] Get users with posts + where + partial. Did not select posts id, but used it in where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: { + id: true, + name: true, + }, + with: { + posts: { + columns: { + id: true, + content: true, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + posts: { + id: number; + content: string; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + posts: [{ id: 1, content: 'Post1' }], + }); +}); + +test('[Find Many] Get users with posts + where + partial(true + false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: { + id: true, + name: false, + }, + with: { + posts: { + columns: { + id: true, + content: false, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + posts: { + id: number; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + posts: [{ id: 1 }], + }); +}); + +test('[Find Many] Get users with posts + where + partial(false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: { + name: false, + }, + with: { + posts: { + columns: { + content: false, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts in transaction', async (t) => { + const { singlestoreDb: db } = t; + + let usersWithPosts: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[] = []; + + await db.transaction(async (tx) => { + await tx.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await tx.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + usersWithPosts = await tx.query.usersTable.findMany({ + where: (({ id }, { eq }) => eq(id, 1)), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + }); + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts in rollbacked transaction', async (t) => { + const { singlestoreDb: db } = t; + + let usersWithPosts: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[] = []; + + await expect(db.transaction(async (tx) => { + await tx.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await tx.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + tx.rollback(); + + usersWithPosts = await tx.query.usersTable.findMany({ + where: (({ id }, { eq }) => eq(id, 1)), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + }); + })).rejects.toThrowError(new TransactionRollbackError()); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(0); +}); + +// select only custom +test('[Find Many] Get only custom fields', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { id: 1, ownerId: 1, content: 'Post1' }, + { id: 2, ownerId: 1, content: 'Post1.2' }, + { id: 3, ownerId: 1, content: 'Post1.3' }, + { id: 4, ownerId: 2, content: 'Post2' }, + { id: 5, ownerId: 2, content: 'Post2.1' }, + { id: 6, ownerId: 3, content: 'Post3' }, + { id: 7, ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: {}, + with: { + posts: { + columns: {}, + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + lowerName: string; + posts: { + lowerName: string; + }[]; + }[]>(); + + // General Assertions + expect(usersWithPosts).toHaveLength(3); + + // Helper function to find user by lowerName + const findUser = (lowerName: string) => usersWithPosts.find((user) => user.lowerName === lowerName); + + // Assertions for each user + const dan = findUser('dan'); + const andrew = findUser('andrew'); + const alex = findUser('alex'); + + expect(dan).toBeDefined(); + expect(andrew).toBeDefined(); + expect(alex).toBeDefined(); + + // Verify the number of posts for each user + expect(dan?.posts).toHaveLength(3); + expect(andrew?.posts).toHaveLength(2); + expect(alex?.posts).toHaveLength(2); + + // Define expected posts for each user + const expectedDanPosts = ['post1', 'post1.2', 'post1.3']; + const expectedAndrewPosts = ['post2', 'post2.1']; + const expectedAlexPosts = ['post3', 'post3.1']; + + // Helper function to extract lowerNames from posts + const getPostLowerNames = (posts: { lowerName: string }[]) => posts.map((post) => post.lowerName); + + // Assertions for Dan's posts + expect(getPostLowerNames(dan!.posts)).toEqual(expect.arrayContaining(expectedDanPosts)); + expect(getPostLowerNames(dan!.posts)).toHaveLength(expectedDanPosts.length); + + // Assertions for Andrew's posts + expect(getPostLowerNames(andrew!.posts)).toEqual(expect.arrayContaining(expectedAndrewPosts)); + expect(getPostLowerNames(andrew!.posts)).toHaveLength(expectedAndrewPosts.length); + + // Assertions for Alex's posts + expect(getPostLowerNames(alex!.posts)).toEqual(expect.arrayContaining(expectedAlexPosts)); + expect(getPostLowerNames(alex!.posts)).toHaveLength(expectedAlexPosts.length); +}); + +// select only custom with where clause (Order Agnostic) +test('[Find Many] Get only custom fields + where', async (t) => { + const { singlestoreDb: db } = t; + + // Insert Users + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + // Insert Posts + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + // Query Users with Posts where users.id = 1 and posts.id >= 2 + const usersWithPosts = await db.query.usersTable.findMany({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + lowerName: string; + posts: { + lowerName: string; + }[]; + }[]>(); + + // General Assertions + expect(usersWithPosts).toHaveLength(1); + + // Since we expect only one user, we can extract it directly + const danWithPosts = usersWithPosts[0]; + + // Assert that the user exists and has the correct lowerName + expect(danWithPosts).toBeDefined(); + expect(danWithPosts?.lowerName).toBe('dan'); + + // Assert that the user has the expected number of posts + expect(danWithPosts?.posts).toHaveLength(2); + + // Define the expected posts + const expectedPosts = ['post1.2', 'post1.3']; + + // Extract the lowerName of each post + const actualPostLowerNames = danWithPosts?.posts.map((post) => post.lowerName); + + // Assert that all expected posts are present, regardless of order + for (const expectedPost of expectedPosts) { + expect(actualPostLowerNames).toContain(expectedPost); + } + + // Additionally, ensure no unexpected posts are present + expect(actualPostLowerNames).toHaveLength(expectedPosts.length); +}); + +test.skip('[Find Many] Get only custom fields + where + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + limit: 1, + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + lowerName: string; + posts: { + lowerName: string; + }[]; + }[]>(); + + expect(usersWithPosts.length).toEqual(1); + expect(usersWithPosts[0]?.posts.length).toEqual(1); + + expect(usersWithPosts).toContainEqual({ + lowerName: 'dan', + posts: [{ lowerName: 'post1.2' }], + }); +}); + +test.skip('[Find Many] Get only custom fields + where + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findMany({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + orderBy: [desc(postsTable.id)], + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + lowerName: string; + posts: { + lowerName: string; + }[]; + }[]>(); + + expect(usersWithPosts.length).toEqual(1); + expect(usersWithPosts[0]?.posts.length).toEqual(2); + + expect(usersWithPosts).toContainEqual({ + lowerName: 'dan', + posts: [{ lowerName: 'post1.3' }, { lowerName: 'post1.2' }], + }); +}); + +// select only custom find one (Order Agnostic) +test('[Find One] Get only custom fields (Order Agnostic)', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + // Query to find the first user without any specific order + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: {}, + with: { + posts: { + columns: {}, + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + lowerName: string; + posts: { + lowerName: string; + }[]; + } | undefined + >(); + + // General Assertions + expect(usersWithPosts).toBeDefined(); + + // Since findFirst without orderBy can return any user, we'll verify the returned user and their posts + if (usersWithPosts) { + // Define expected users and their corresponding posts + const expectedUsers: { [key: string]: string[] } = { + dan: ['post1', 'post1.2', 'post1.3'], + andrew: ['post2', 'post2.1'], + alex: ['post3', 'post3.1'], + }; + + // Verify that the returned user is one of the expected users + expect(Object.keys(expectedUsers)).toContain(usersWithPosts.lowerName); + + // Get the expected posts for the returned user + const expectedPosts = expectedUsers[usersWithPosts.lowerName] as string[]; + + // Verify the number of posts + expect(usersWithPosts.posts).toHaveLength(expectedPosts.length); + + // Extract the lowerName of each post + const actualPostLowerNames = usersWithPosts.posts.map((post) => post.lowerName); + + // Assert that all expected posts are present, regardless of order + for (const expectedPost of expectedPosts) { + expect(actualPostLowerNames).toContain(expectedPost.toLowerCase()); + } + } +}); + +// select only custom find one with where clause (Order Agnostic) +test('[Find One] Get only custom fields + where (Order Agnostic)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + // Query to find the first user with id = 1 and posts with id >= 2 + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + lowerName: string; + posts: { + lowerName: string; + }[]; + } | undefined + >(); + + // General Assertions + expect(usersWithPosts).toBeDefined(); + + if (usersWithPosts) { + // Assert that the returned user has the expected lowerName + expect(usersWithPosts.lowerName).toBe('dan'); + + // Assert that the user has exactly two posts + expect(usersWithPosts.posts).toHaveLength(2); + + // Define the expected posts + const expectedPosts = ['post1.2', 'post1.3']; + + // Extract the lowerName of each post + const actualPostLowerNames = usersWithPosts.posts.map((post) => post.lowerName); + + // Assert that all expected posts are present, regardless of order + for (const expectedPost of expectedPosts) { + expect(actualPostLowerNames).toContain(expectedPost.toLowerCase()); + } + + // Additionally, ensure no unexpected posts are present + expect(actualPostLowerNames).toHaveLength(expectedPosts.length); + } +}); + +test.skip('[Find One] Get only custom fields + where + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + limit: 1, + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + lowerName: string; + posts: { + lowerName: string; + }[]; + } | undefined + >(); + + expect(usersWithPosts?.posts.length).toEqual(1); + + expect(usersWithPosts).toEqual({ + lowerName: 'dan', + posts: [{ lowerName: 'post1.2' }], + }); +}); + +test.skip('[Find One] Get only custom fields + where + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: {}, + with: { + posts: { + columns: {}, + where: gte(postsTable.id, 2), + orderBy: [desc(postsTable.id)], + extras: ({ content }) => ({ + lowerName: sql`lower(${content})`.as('content_lower'), + }), + }, + }, + where: eq(usersTable.id, 1), + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + lowerName: string; + posts: { + lowerName: string; + }[]; + } | undefined + >(); + + expect(usersWithPosts?.posts.length).toEqual(2); + + expect(usersWithPosts).toEqual({ + lowerName: 'dan', + posts: [{ lowerName: 'post1.3' }, { lowerName: 'post1.2' }], + }); +}); + +// columns {} +test('[Find Many] Get select {}', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await expect( + async () => + await db.query.usersTable.findMany({ + columns: {}, + }), + ).rejects.toThrow(DrizzleError); +}); + +// columns {} +test('[Find One] Get select {}', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await expect(async () => + await db.query.usersTable.findFirst({ + columns: {}, + }) + ).rejects.toThrow(DrizzleError); +}); + +// deep select {} +test('[Find Many] Get deep select {}', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + await expect(async () => + await db.query.usersTable.findMany({ + columns: {}, + with: { + posts: { + columns: {}, + }, + }, + }) + ).rejects.toThrow(DrizzleError); +}); + +// deep select {} +test('[Find One] Get deep select {}', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + await expect(async () => + await db.query.usersTable.findFirst({ + columns: {}, + with: { + posts: { + columns: {}, + }, + }, + }) + ).rejects.toThrow(DrizzleError); +}); + +/* + Prepared statements for users+posts +*/ +test.skip('[Find Many] Get users with posts + prepared limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const prepared = db.query.usersTable.findMany({ + with: { + posts: { + limit: placeholder('limit'), + }, + }, + }).prepare(); + + const usersWithPosts = await prepared.execute({ limit: 1 }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(3); + expect(usersWithPosts[0]?.posts.length).eq(1); + expect(usersWithPosts[1]?.posts.length).eq(1); + expect(usersWithPosts[2]?.posts.length).eq(1); + + expect(usersWithPosts).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find Many] Get users with posts + prepared limit + offset', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const prepared = db.query.usersTable.findMany({ + limit: placeholder('uLimit'), + offset: placeholder('uOffset'), + with: { + posts: { + limit: placeholder('pLimit'), + }, + }, + }).prepare(); + + const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1 }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(2); + expect(usersWithPosts[0]?.posts.length).eq(1); + expect(usersWithPosts[1]?.posts.length).eq(1); + + expect(usersWithPosts).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); + expect(usersWithPosts).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], + }); +}); + +test('[Find Many] Get users with posts + prepared where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const prepared = db.query.usersTable.findMany({ + where: (({ id }, { eq }) => eq(id, placeholder('id'))), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + }).prepare(); + + const usersWithPosts = await prepared.execute({ id: 1 }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find Many] Get users with posts + prepared + limit + offset + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const prepared = db.query.usersTable.findMany({ + limit: placeholder('uLimit'), + offset: placeholder('uOffset'), + where: (({ id }, { eq, or }) => or(eq(id, placeholder('id')), eq(id, 3))), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, placeholder('pid'))), + limit: placeholder('pLimit'), + }, + }, + }).prepare(); + + const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 }); + + expectTypeOf(usersWithPosts).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + }[]>(); + + expect(usersWithPosts.length).eq(1); + expect(usersWithPosts[0]?.posts.length).eq(1); + + expect(usersWithPosts).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], + }); +}); + +/* + [Find One] One relation users+posts +*/ + +test('[Find One] Get users with posts', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: true, + }, + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + // General Assertions + expect(usersWithPosts).toBeDefined(); + + if (usersWithPosts) { + const { id, name, posts } = usersWithPosts; + + // Verify that the user is one of the inserted users + const validUsers: { [key: number]: string } = { + 1: 'dan', + 2: 'andrew', + 3: 'alex', + }; + expect(validUsers[id]).toBe(name.toLowerCase()); + + // Assert that the user has exactly one post + expect(posts).toHaveLength(1); + + const post = posts[0]; + + // Verify that the post belongs to the user + expect(post?.ownerId).toBe(id); + + // Verify that the post content matches the user + const expectedPostContent = `Post${id}`; + expect(post?.content.toLowerCase()).toBe(expectedPostContent.toLowerCase()); + + // Optionally, verify the presence of `createdAt` + expect(post?.createdAt).toBeInstanceOf(Date); + } +}); + +test.skip('[Find One] Get users with posts + limit posts', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find One] Get users with posts no results found', async (t) => { + const { singlestoreDb: db } = t; + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts).toBeUndefined(); +}); + +test.skip('[Find One] Get users with posts + limit posts and users', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +test('[Find One] Get users with posts + custom fields', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: true, + }, + extras: ({ name }) => ({ + lowerName: sql`lower(${name})`.as('name_lower'), + }), + }); + + // Type Assertion + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lowerName: string; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + // General Assertions + expect(usersWithPosts).toBeDefined(); + + if (usersWithPosts) { + const { id, lowerName, posts } = usersWithPosts; + + // Define valid users and their expected lower names + const validUsers: { [key: number]: string } = { + 1: 'dan', + 2: 'andrew', + 3: 'alex', + }; + + // Verify that the returned user's lowerName matches the expected value + expect(validUsers[id]).toBe(lowerName); + + // Define the expected posts based on the user ID + const expectedPostsByUser: Record = { + 1: ['post1', 'post1.2', 'post1.3'], + 2: ['post2', 'post2.1'], + 3: ['post3', 'post3.1'], + }; + + // Get the expected posts for the returned user + const expectedPosts = expectedPostsByUser[id] || []; + + // Extract the lowerName of each post + const actualPostContents = posts.map((post) => post.content.toLowerCase()); + + // Assert that all expected posts are present, regardless of order + for (const expectedPost of expectedPosts) { + expect(actualPostContents).toContain(expectedPost.toLowerCase()); + } + + // Optionally, ensure that no unexpected posts are present + expect(actualPostContents).toHaveLength(expectedPosts.length); + } +}); + +test.skip('[Find One] Get users with posts + custom fields + limits', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.2' }, + { ownerId: 1, content: 'Post1.3' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: { + limit: 1, + }, + }, + extras: (usersTable, { sql }) => ({ + lowerName: sql`lower(${usersTable.name})`.as('name_lower'), + }), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lowerName: string; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).toEqual(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + lowerName: 'dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +test.skip('[Find One] Get users with posts + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: '1' }, + { ownerId: 1, content: '2' }, + { ownerId: 1, content: '3' }, + { ownerId: 2, content: '4' }, + { ownerId: 2, content: '5' }, + { ownerId: 3, content: '6' }, + { ownerId: 3, content: '7' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + with: { + posts: { + orderBy: (postsTable, { desc }) => [desc(postsTable.content)], + }, + }, + orderBy: (usersTable, { desc }) => [desc(usersTable.id)], + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(2); + + expect(usersWithPosts).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + posts: [{ + id: 7, + ownerId: 3, + content: '7', + createdAt: usersWithPosts?.posts[1]?.createdAt, + }, { id: 6, ownerId: 3, content: '6', createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +test('[Find One] Get users with posts + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + where: (({ id }, { eq }) => eq(id, 1)), + with: { + posts: { + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +test('[Find One] Get users with posts + where + partial', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: { + id: true, + name: true, + }, + with: { + posts: { + columns: { + id: true, + content: true, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + posts: { + id: number; + content: string; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + posts: [{ id: 1, content: 'Post1' }], + }); +}); + +test('[Find One] Get users with posts + where + partial. Did not select posts id, but used it in where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: { + id: true, + name: true, + }, + with: { + posts: { + columns: { + id: true, + content: true, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + name: string; + posts: { + id: number; + content: string; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + name: 'Dan', + posts: [{ id: 1, content: 'Post1' }], + }); +}); + +test('[Find One] Get users with posts + where + partial(true + false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: { + id: true, + name: false, + }, + with: { + posts: { + columns: { + id: true, + content: false, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + posts: { + id: number; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + posts: [{ id: 1 }], + }); +}); + +test('[Find One] Get users with posts + where + partial(false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const usersWithPosts = await db.query.usersTable.findFirst({ + columns: { + name: false, + }, + with: { + posts: { + columns: { + content: false, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }, + }, + where: (({ id }, { eq }) => eq(id, 1)), + }); + + expectTypeOf(usersWithPosts).toEqualTypeOf< + { + id: number; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + ownerId: number | null; + createdAt: Date; + }[]; + } | undefined + >(); + + expect(usersWithPosts!.posts.length).eq(1); + + expect(usersWithPosts).toEqual({ + id: 1, + verified: false, + invitedBy: null, + posts: [{ id: 1, ownerId: 1, createdAt: usersWithPosts?.posts[0]?.createdAt }], + }); +}); + +/* + One relation users+users. Self referencing +*/ + +test.skip('Get user with invitee', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + with: { + invitee: true, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithInvitee.length).eq(4); + expect(usersWithInvitee[0]?.invitee).toBeNull(); + expect(usersWithInvitee[1]?.invitee).toBeNull(); + expect(usersWithInvitee[2]?.invitee).not.toBeNull(); + expect(usersWithInvitee[3]?.invitee).not.toBeNull(); + + expect(usersWithInvitee[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[2]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + }); + expect(usersWithInvitee[3]).toEqual({ + id: 4, + name: 'John', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user + limit with invitee', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew', invitedBy: 1 }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + with: { + invitee: true, + }, + limit: 2, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user with invitee and custom fields', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), + with: { + invitee: { + extras: (invitee, { sql }) => ({ lower: sql`lower(${invitee.name})`.as('lower_name') }), + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + } | null; + }[] + >(); + + usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithInvitee.length).eq(4); + expect(usersWithInvitee[0]?.invitee).toBeNull(); + expect(usersWithInvitee[1]?.invitee).toBeNull(); + expect(usersWithInvitee[2]?.invitee).not.toBeNull(); + expect(usersWithInvitee[3]?.invitee).not.toBeNull(); + + expect(usersWithInvitee[0]).toEqual({ + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[1]).toEqual({ + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[2]).toEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, + }); + expect(usersWithInvitee[3]).toEqual({ + id: 4, + name: 'John', + lower: 'john', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', lower: 'andrew', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user with invitee and custom fields + limits', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), + limit: 3, + with: { + invitee: { + extras: (invitee, { sql }) => ({ lower: sql`lower(${invitee.name})`.as('lower_name') }), + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + } | null; + }[] + >(); + + usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(usersWithInvitee.length).eq(3); + expect(usersWithInvitee[0]?.invitee).toBeNull(); + expect(usersWithInvitee[1]?.invitee).toBeNull(); + expect(usersWithInvitee[2]?.invitee).not.toBeNull(); + + expect(usersWithInvitee[0]).toEqual({ + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[1]).toEqual({ + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[2]).toEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user with invitee + order by', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + orderBy: (users, { desc }) => [desc(users.id)], + with: { + invitee: true, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(4); + expect(usersWithInvitee[3]?.invitee).toBeNull(); + expect(usersWithInvitee[2]?.invitee).toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + + expect(usersWithInvitee[3]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[2]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + }); + expect(usersWithInvitee[1]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + }); + expect(usersWithInvitee[0]).toEqual({ + id: 4, + name: 'John', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user with invitee + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + with: { + invitee: true, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + }); + expect(usersWithInvitee).toContainEqual({ + id: 4, + name: 'John', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + }); +}); + +test.skip('Get user with invitee + where + partial', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + columns: { + id: true, + name: true, + }, + with: { + invitee: { + columns: { + id: true, + name: true, + }, + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + invitee: { + id: number; + name: string; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee).toContainEqual({ + id: 3, + name: 'Alex', + invitee: { id: 1, name: 'Dan' }, + }); + expect(usersWithInvitee).toContainEqual({ + id: 4, + name: 'John', + invitee: { id: 2, name: 'Andrew' }, + }); +}); + +test.skip('Get user with invitee + where + partial. Did not select users id, but used it in where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + columns: { + name: true, + }, + with: { + invitee: { + columns: { + id: true, + name: true, + }, + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + name: string; + invitee: { + id: number; + name: string; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee).toContainEqual({ + name: 'Alex', + invitee: { id: 1, name: 'Dan' }, + }); + expect(usersWithInvitee).toContainEqual({ + name: 'John', + invitee: { id: 2, name: 'Andrew' }, + }); +}); + +test.skip('Get user with invitee + where + partial(true+false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + columns: { + id: true, + name: true, + verified: false, + }, + with: { + invitee: { + columns: { + id: true, + name: true, + verified: false, + }, + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + invitee: { + id: number; + name: string; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee).toContainEqual({ + id: 3, + name: 'Alex', + invitee: { id: 1, name: 'Dan' }, + }); + expect(usersWithInvitee).toContainEqual({ + id: 4, + name: 'John', + invitee: { id: 2, name: 'Andrew' }, + }); +}); + +test.skip('Get user with invitee + where + partial(false)', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + const usersWithInvitee = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + columns: { + verified: false, + }, + with: { + invitee: { + columns: { + name: false, + }, + }, + }, + }); + + expectTypeOf(usersWithInvitee).toEqualTypeOf< + { + id: number; + name: string; + invitedBy: number | null; + invitee: { + id: number; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(usersWithInvitee.length).eq(2); + expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + + expect(usersWithInvitee).toContainEqual({ + id: 3, + name: 'Alex', + invitedBy: 1, + invitee: { id: 1, verified: false, invitedBy: null }, + }); + expect(usersWithInvitee).toContainEqual({ + id: 4, + name: 'John', + invitedBy: 2, + invitee: { id: 2, verified: false, invitedBy: null }, + }); +}); + +/* + Two first-level relations users+users and users+posts +*/ + +test.skip('Get user with invitee and posts', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const response = await db.query.usersTable.findMany({ + with: { + invitee: true, + posts: true, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(4); + + expect(response[0]?.invitee).toBeNull(); + expect(response[1]?.invitee).toBeNull(); + expect(response[2]?.invitee).not.toBeNull(); + expect(response[3]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: response[0]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: response[1]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [{ id: 3, ownerId: 3, content: 'Post3', createdAt: response[2]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 4, + name: 'John', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + posts: [], + }); +}); + +test.skip('Get user with invitee and posts + limit posts and users', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const response = await db.query.usersTable.findMany({ + limit: 3, + with: { + invitee: true, + posts: { + limit: 1, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(3); + + expect(response[0]?.invitee).toBeNull(); + expect(response[1]?.invitee).toBeNull(); + expect(response[2]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: response[0]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 3, ownerId: 2, content: 'Post2', createdAt: response[1]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [{ id: 5, ownerId: 3, content: 'Post3', createdAt: response[2]?.posts[0]?.createdAt }], + }); +}); + +test.skip('Get user with invitee and posts + limits + custom fields in each', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const response = await db.query.usersTable.findMany({ + limit: 3, + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), + with: { + invitee: { + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_invitee_name') }), + }, + posts: { + limit: 1, + extras: (posts, { sql }) => ({ lower: sql`lower(${posts.content})`.as('lower_content') }), + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + lower: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(3); + + expect(response[0]?.invitee).toBeNull(); + expect(response[1]?.invitee).toBeNull(); + expect(response[2]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', lower: 'post1', createdAt: response[0]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 3, ownerId: 2, content: 'Post2', lower: 'post2', createdAt: response[1]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, + posts: [{ id: 5, ownerId: 3, content: 'Post3', lower: 'post3', createdAt: response[2]?.posts[0]?.createdAt }], + }); +}); + +test.skip('Get user with invitee and posts + custom fields in each', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const response = await db.query.usersTable.findMany({ + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), + with: { + invitee: { + extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), + }, + posts: { + extras: (posts, { sql }) => ({ lower: sql`lower(${posts.content})`.as('lower_name') }), + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + lower: string; + invitedBy: number | null; + posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + lower: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + response[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + response[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + response[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(4); + + expect(response[0]?.invitee).toBeNull(); + expect(response[1]?.invitee).toBeNull(); + expect(response[2]?.invitee).not.toBeNull(); + expect(response[3]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(2); + expect(response[1]?.posts.length).eq(2); + expect(response[2]?.posts.length).eq(2); + expect(response[3]?.posts.length).eq(0); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 1, ownerId: 1, content: 'Post1', lower: 'post1', createdAt: response[0]?.posts[0]?.createdAt }, { + id: 2, + ownerId: 1, + content: 'Post1.1', + lower: 'post1.1', + createdAt: response[0]?.posts[1]?.createdAt, + }], + }); + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 3, ownerId: 2, content: 'Post2', lower: 'post2', createdAt: response[1]?.posts[0]?.createdAt }, { + id: 4, + ownerId: 2, + content: 'Post2.1', + lower: 'post2.1', + createdAt: response[1]?.posts[1]?.createdAt, + }], + }); + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, + posts: [{ id: 5, ownerId: 3, content: 'Post3', lower: 'post3', createdAt: response[2]?.posts[0]?.createdAt }, { + id: 6, + ownerId: 3, + content: 'Post3.1', + lower: 'post3.1', + createdAt: response[2]?.posts[1]?.createdAt, + }], + }); + expect(response).toContainEqual({ + id: 4, + name: 'John', + lower: 'john', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', lower: 'andrew', verified: false, invitedBy: null }, + posts: [], + }); +}); + +test.skip('Get user with invitee and posts + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const response = await db.query.usersTable.findMany({ + orderBy: (users, { desc }) => [desc(users.id)], + with: { + invitee: true, + posts: { + orderBy: (posts, { desc }) => [desc(posts.id)], + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(response.length).eq(4); + + expect(response[3]?.invitee).toBeNull(); + expect(response[2]?.invitee).toBeNull(); + expect(response[1]?.invitee).not.toBeNull(); + expect(response[0]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(0); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(2); + expect(response[3]?.posts.length).eq(2); + + expect(response[3]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 2, ownerId: 1, content: 'Post1.1', createdAt: response[3]?.posts[0]?.createdAt }, { + id: 1, + ownerId: 1, + content: 'Post1', + createdAt: response[3]?.posts[1]?.createdAt, + }], + }); + expect(response[2]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 4, ownerId: 2, content: 'Post2.1', createdAt: response[2]?.posts[0]?.createdAt }, { + id: 3, + ownerId: 2, + content: 'Post2', + createdAt: response[2]?.posts[1]?.createdAt, + }], + }); + expect(response[1]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [{ + id: 5, + ownerId: 3, + content: 'Post3', + createdAt: response[3]?.posts[1]?.createdAt, + }], + }); + expect(response[0]).toEqual({ + id: 4, + name: 'John', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + posts: [], + }); +}); + +test.skip('Get user with invitee and posts + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const response = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 2), eq(users.id, 3))), + with: { + invitee: true, + posts: { + where: (posts, { eq }) => (eq(posts.ownerId, 2)), + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(2); + + expect(response[0]?.invitee).toBeNull(); + expect(response[1]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(0); + + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + invitee: null, + posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: response[0]?.posts[0]?.createdAt }], + }); + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [], + }); +}); + +test.skip('Get user with invitee and posts + limit posts and users + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + { ownerId: 3, content: 'Post3.1' }, + ]); + + const response = await db.query.usersTable.findMany({ + where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), + limit: 1, + with: { + invitee: true, + posts: { + where: (posts, { eq }) => (eq(posts.ownerId, 3)), + limit: 1, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(response.length).eq(1); + + expect(response[0]?.invitee).not.toBeNull(); + expect(response[0]?.posts.length).eq(1); + + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [{ id: 5, ownerId: 3, content: 'Post3', createdAt: response[0]?.posts[0]?.createdAt }], + }); +}); + +test.skip('Get user with invitee and posts + orderBy + where + custom', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const response = await db.query.usersTable.findMany({ + orderBy: [desc(usersTable.id)], + where: or(eq(usersTable.id, 3), eq(usersTable.id, 4)), + extras: { + lower: sql`lower(${usersTable.name})`.as('lower_name'), + }, + with: { + invitee: true, + posts: { + where: eq(postsTable.ownerId, 3), + orderBy: [desc(postsTable.id)], + extras: { + lower: sql`lower(${postsTable.content})`.as('lower_name'), + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lower: string; + posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; + invitee: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[] + >(); + + expect(response.length).eq(2); + + expect(response[1]?.invitee).not.toBeNull(); + expect(response[0]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(0); + expect(response[1]?.posts.length).eq(1); + + expect(response[1]).toEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: 1, + invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, + posts: [{ + id: 5, + ownerId: 3, + content: 'Post3', + lower: 'post3', + createdAt: response[1]?.posts[0]?.createdAt, + }], + }); + expect(response[0]).toEqual({ + id: 4, + name: 'John', + lower: 'john', + verified: false, + invitedBy: 2, + invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, + posts: [], + }); +}); + +test.skip('Get user with invitee and posts + orderBy + where + partial + custom', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex', invitedBy: 1 }, + { id: 4, name: 'John', invitedBy: 2 }, + ]); + + await db.insert(postsTable).values([ + { ownerId: 1, content: 'Post1' }, + { ownerId: 1, content: 'Post1.1' }, + { ownerId: 2, content: 'Post2' }, + { ownerId: 2, content: 'Post2.1' }, + { ownerId: 3, content: 'Post3' }, + ]); + + const response = await db.query.usersTable.findMany({ + orderBy: [desc(usersTable.id)], + where: or(eq(usersTable.id, 3), eq(usersTable.id, 4)), + extras: { + lower: sql`lower(${usersTable.name})`.as('lower_name'), + }, + columns: { + id: true, + name: true, + }, + with: { + invitee: { + columns: { + id: true, + name: true, + }, + extras: { + lower: sql`lower(${usersTable.name})`.as('lower_name'), + }, + }, + posts: { + columns: { + id: true, + content: true, + }, + where: eq(postsTable.ownerId, 3), + orderBy: [desc(postsTable.id)], + extras: { + lower: sql`lower(${postsTable.content})`.as('lower_name'), + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + lower: string; + posts: { id: number; lower: string; content: string }[]; + invitee: { + id: number; + name: string; + lower: string; + } | null; + }[] + >(); + + expect(response.length).eq(2); + + expect(response[1]?.invitee).not.toBeNull(); + expect(response[0]?.invitee).not.toBeNull(); + + expect(response[0]?.posts.length).eq(0); + expect(response[1]?.posts.length).eq(1); + + expect(response[1]).toEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + invitee: { id: 1, name: 'Dan', lower: 'dan' }, + posts: [{ + id: 5, + content: 'Post3', + lower: 'post3', + }], + }); + expect(response[0]).toEqual({ + id: 4, + name: 'John', + lower: 'john', + invitee: { id: 2, name: 'Andrew', lower: 'andrew' }, + posts: [], + }); +}); + +/* + One two-level relation users+posts+comments +*/ + +test.skip('Get user with posts and posts with comments', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { id: 1, ownerId: 1, content: 'Post1' }, + { id: 2, ownerId: 2, content: 'Post2' }, + { id: 3, ownerId: 3, content: 'Post3' }, + ]); + + await db.insert(commentsTable).values([ + { postId: 1, content: 'Comment1', creator: 2 }, + { postId: 2, content: 'Comment2', creator: 2 }, + { postId: 3, content: 'Comment3', creator: 3 }, + ]); + + const response = await db.query.usersTable.findMany({ + with: { + posts: { + with: { + comments: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + comments: { + id: number; + content: string; + createdAt: Date; + creator: number | null; + postId: number | null; + }[]; + }[]; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(3); + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(1); + + expect(response[0]?.posts[0]?.comments.length).eq(1); + expect(response[1]?.posts[0]?.comments.length).eq(1); + expect(response[2]?.posts[0]?.comments.length).eq(1); + + expect(response[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ + id: 1, + ownerId: 1, + content: 'Post1', + createdAt: response[0]?.posts[0]?.createdAt, + comments: [ + { + id: 1, + content: 'Comment1', + creator: 2, + postId: 1, + createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, + }, + ], + }], + }); + expect(response[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ + id: 2, + ownerId: 2, + content: 'Post2', + createdAt: response[1]?.posts[0]?.createdAt, + comments: [ + { + id: 2, + content: 'Comment2', + creator: 2, + postId: 2, + createdAt: response[1]?.posts[0]?.comments[0]?.createdAt, + }, + ], + }], + }); + // expect(response[2]).toEqual({ + // id: 3, + // name: 'Alex', + // verified: false, + // invitedBy: null, + // posts: [{ + // id: 3, + // ownerId: 3, + // content: 'Post3', + // createdAt: response[2]?.posts[0]?.createdAt, + // comments: [ + // { + // id: , + // content: 'Comment3', + // creator: 3, + // postId: 3, + // createdAt: response[2]?.posts[0]?.comments[0]?.createdAt, + // }, + // ], + // }], + // }); +}); + +// Get user with limit posts and limit comments + +// Get user with custom field + post + comment with custom field + +// Get user with limit + posts orderBy + comment orderBy + +// Get user with where + posts where + comment where + +// Get user with where + posts partial where + comment where + +// Get user with where + posts partial where + comment partial(false) where + +// Get user with where partial(false) + posts partial where partial(false) + comment partial(false+true) where + +// Get user with where + posts partial where + comment where. Didn't select field from where in posts + +// Get user with where + posts partial where + comment where. Didn't select field from where for all + +// Get with limit+offset in each + +/* + One two-level + One first-level relation users+posts+comments and users+users +*/ + +/* + One three-level relation users+posts+comments+comment_owner +*/ + +test.skip('Get user with posts and posts with comments and comments with owner', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { id: 1, ownerId: 1, content: 'Post1' }, + { id: 2, ownerId: 2, content: 'Post2' }, + { id: 3, ownerId: 3, content: 'Post3' }, + ]); + + await db.insert(commentsTable).values([ + { postId: 1, content: 'Comment1', creator: 2 }, + { postId: 2, content: 'Comment2', creator: 2 }, + { postId: 3, content: 'Comment3', creator: 3 }, + ]); + + const response = await db.query.usersTable.findMany({ + with: { + posts: { + with: { + comments: { + with: { + author: true, + }, + }, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + comments: { + id: number; + content: string; + createdAt: Date; + creator: number | null; + postId: number | null; + author: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[]; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).eq(3); + expect(response[0]?.posts.length).eq(1); + expect(response[1]?.posts.length).eq(1); + expect(response[2]?.posts.length).eq(1); + + expect(response[0]?.posts[0]?.comments.length).eq(1); + expect(response[1]?.posts[0]?.comments.length).eq(1); + expect(response[2]?.posts[0]?.comments.length).eq(1); + + expect(response[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ + id: 1, + ownerId: 1, + content: 'Post1', + createdAt: response[0]?.posts[0]?.createdAt, + comments: [ + { + id: 1, + content: 'Comment1', + creator: 2, + author: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + postId: 1, + createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, + }, + ], + }], + }); + expect(response[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + posts: [{ + id: 2, + ownerId: 2, + content: 'Post2', + createdAt: response[1]?.posts[0]?.createdAt, + comments: [ + { + id: 2, + content: 'Comment2', + creator: 2, + author: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + postId: 2, + createdAt: response[1]?.posts[0]?.comments[0]?.createdAt, + }, + ], + }], + }); +}); + +test.skip('Get user with posts and posts with comments and comments with owner where exists', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(postsTable).values([ + { id: 1, ownerId: 1, content: 'Post1' }, + { id: 2, ownerId: 2, content: 'Post2' }, + { id: 3, ownerId: 3, content: 'Post3' }, + ]); + + await db.insert(commentsTable).values([ + { postId: 1, content: 'Comment1', creator: 2 }, + { postId: 2, content: 'Comment2', creator: 2 }, + { postId: 3, content: 'Comment3', creator: 3 }, + ]); + + const response = await db.query.usersTable.findMany({ + with: { + posts: { + with: { + comments: { + with: { + author: true, + }, + }, + }, + }, + }, + where: (table, { exists, eq }) => exists(db.select({ one: sql`1` }).from(usersTable).where(eq(sql`1`, table.id))), + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + posts: { + id: number; + content: string; + ownerId: number | null; + createdAt: Date; + comments: { + id: number; + content: string; + createdAt: Date; + creator: number | null; + postId: number | null; + author: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + } | null; + }[]; + }[]; + }[]>(); + + expect(response.length).eq(1); + expect(response[0]?.posts.length).eq(1); + + expect(response[0]?.posts[0]?.comments.length).eq(1); + + expect(response[0]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + posts: [{ + id: 1, + ownerId: 1, + content: 'Post1', + createdAt: response[0]?.posts[0]?.createdAt, + comments: [ + { + id: 1, + content: 'Comment1', + creator: 2, + author: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + postId: 1, + createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, + }, + ], + }], + }); +}); + +/* + One three-level relation + 1 first-level relatioon + 1. users+posts+comments+comment_owner + 2. users+users +*/ + +/* + One four-level relation users+posts+comments+coment_likes +*/ + +/* + [Find Many] Many-to-many cases + + Users+users_to_groups+groups +*/ + +test.skip('[Find Many] Get users with groups', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + with: { + usersToGroups: { + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + expect(response[2]?.usersToGroups.length).toEqual(2); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + description: null, + }, + }, { + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get groups with users', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + with: { + usersToGroups: { + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(2); + expect(response[2]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }, { + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 3, + name: 'Group3', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get users with groups + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + limit: 2, + with: { + usersToGroups: { + limit: 1, + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get groups with users + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + limit: 2, + with: { + usersToGroups: { + limit: 1, + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get users with groups + limit + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + limit: 1, + where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.groupId, 1), + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(1); + + expect(response[0]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get groups with users + limit + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + limit: 1, + where: gt(groupsTable.id, 1), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.userId, 2), + limit: 1, + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(1); + + expect(response[0]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get users with groups + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.groupId, 2), + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(0); + expect(response[1]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get groups with users + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + where: gt(groupsTable.id, 1), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.userId, 2), + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[]>(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(0); + + expect(response).toContainEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 3, + name: 'Group3', + description: null, + usersToGroups: [], + }); +}); + +test.skip('[Find Many] Get users with groups + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + orderBy: (users, { desc }) => [desc(users.id)], + with: { + usersToGroups: { + orderBy: [desc(usersToGroupsTable.groupId)], + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(2); + expect(response[1]?.usersToGroups.length).toEqual(1); + expect(response[2]?.usersToGroups.length).toEqual(1); + + expect(response[2]).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); + + expect(response[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); + + expect(response[0]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + description: null, + }, + }, { + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get groups with users + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + orderBy: [desc(groupsTable.id)], + with: { + usersToGroups: { + orderBy: (utg, { desc }) => [desc(utg.userId)], + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[]>(); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(2); + expect(response[2]?.usersToGroups.length).toEqual(1); + + expect(response[2]).toEqual({ + id: 1, + name: 'Group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response[1]).toEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }, { + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response[0]).toEqual({ + id: 3, + name: 'Group3', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find Many] Get users with groups + orderBy + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + orderBy: (users, { desc }) => [desc(users.id)], + limit: 2, + with: { + usersToGroups: { + limit: 1, + orderBy: [desc(usersToGroupsTable.groupId)], + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf<{ + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + }[]>(); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + + expect(response[1]).toEqual({ + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); + + expect(response[0]).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + description: null, + }, + }], + }); +}); + +/* + [Find One] Many-to-many cases + + Users+users_to_groups+groups +*/ + +test.skip('[Find One] Get users with groups', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + with: { + usersToGroups: { + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); +}); + +test.skip('[Find One] Get groups with users', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findFirst({ + with: { + usersToGroups: { + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 1, + name: 'Group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find One] Get users with groups + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + with: { + usersToGroups: { + limit: 1, + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); +}); + +test.skip('[Find One] Get groups with users + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findFirst({ + with: { + usersToGroups: { + limit: 1, + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 1, + name: 'Group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find One] Get users with groups + limit + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.groupId, 1), + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + description: null, + }, + }], + }); +}); + +test.skip('[Find One] Get groups with users + limit + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findFirst({ + where: gt(groupsTable.id, 1), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.userId, 2), + limit: 1, + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find One] Get users with groups + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 2, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.groupId, 2), + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(0); + + expect(response).toEqual({ + id: 1, + name: 'Dan', + verified: false, + invitedBy: null, + usersToGroups: [], + }); +}); + +test.skip('[Find One] Get groups with users + where', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findFirst({ + where: gt(groupsTable.id, 1), + with: { + usersToGroups: { + where: eq(usersToGroupsTable.userId, 2), + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find One] Get users with groups + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + orderBy: (users, { desc }) => [desc(users.id)], + with: { + usersToGroups: { + orderBy: [desc(usersToGroupsTable.groupId)], + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(2); + + expect(response).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + description: null, + }, + }, { + group: { + id: 2, + name: 'Group2', + description: null, + }, + }], + }); +}); + +test.skip('[Find One] Get groups with users + orderBy', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findFirst({ + orderBy: [desc(groupsTable.id)], + with: { + usersToGroups: { + orderBy: (utg, { desc }) => [desc(utg.userId)], + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 3, + name: 'Group3', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('[Find One] Get users with groups + orderBy + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findFirst({ + orderBy: (users, { desc }) => [desc(users.id)], + with: { + usersToGroups: { + limit: 1, + orderBy: [desc(usersToGroupsTable.groupId)], + columns: {}, + with: { + group: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + }; + }[]; + } | undefined + >(); + + expect(response?.usersToGroups.length).toEqual(1); + + expect(response).toEqual({ + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + description: null, + }, + }], + }); +}); + +test.skip('Get groups with users + orderBy + limit', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + orderBy: [desc(groupsTable.id)], + limit: 2, + with: { + usersToGroups: { + limit: 1, + orderBy: (utg, { desc }) => [desc(utg.userId)], + columns: {}, + with: { + user: true, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + }; + }[]; + }[] + >(); + + expect(response.length).toEqual(2); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + + expect(response[1]).toEqual({ + id: 2, + name: 'Group2', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response[0]).toEqual({ + id: 3, + name: 'Group3', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test.skip('Get users with groups + custom', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.usersTable.findMany({ + extras: { + lower: sql`lower(${usersTable.name})`.as('lower_name'), + }, + with: { + usersToGroups: { + columns: {}, + with: { + group: { + extras: { + lower: sql`lower(${groupsTable.name})`.as('lower_name'), + }, + }, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lower: string; + usersToGroups: { + group: { + id: number; + name: string; + description: string | null; + lower: string; + }; + }[]; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(1); + expect(response[2]?.usersToGroups.length).toEqual(2); + + expect(response).toContainEqual({ + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 1, + name: 'Group1', + lower: 'group1', + description: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 2, + name: 'Group2', + lower: 'group2', + description: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: null, + usersToGroups: [{ + group: { + id: 3, + name: 'Group3', + lower: 'group3', + description: null, + }, + }, { + group: { + id: 2, + name: 'Group2', + lower: 'group2', + description: null, + }, + }], + }); +}); + +test.skip('Get groups with users + custom', async (t) => { + const { singlestoreDb: db } = t; + + await db.insert(usersTable).values([ + { id: 1, name: 'Dan' }, + { id: 2, name: 'Andrew' }, + { id: 3, name: 'Alex' }, + ]); + + await db.insert(groupsTable).values([ + { id: 1, name: 'Group1' }, + { id: 2, name: 'Group2' }, + { id: 3, name: 'Group3' }, + ]); + + await db.insert(usersToGroupsTable).values([ + { userId: 1, groupId: 1 }, + { userId: 2, groupId: 2 }, + { userId: 3, groupId: 3 }, + { userId: 3, groupId: 2 }, + ]); + + const response = await db.query.groupsTable.findMany({ + extras: (table, { sql }) => ({ + lower: sql`lower(${table.name})`.as('lower_name'), + }), + with: { + usersToGroups: { + columns: {}, + with: { + user: { + extras: (table, { sql }) => ({ + lower: sql`lower(${table.name})`.as('lower_name'), + }), + }, + }, + }, + }, + }); + + expectTypeOf(response).toEqualTypeOf< + { + id: number; + name: string; + description: string | null; + lower: string; + usersToGroups: { + user: { + id: number; + name: string; + verified: boolean; + invitedBy: number | null; + lower: string; + }; + }[]; + }[] + >(); + + response.sort((a, b) => (a.id > b.id) ? 1 : -1); + + expect(response.length).toEqual(3); + + expect(response[0]?.usersToGroups.length).toEqual(1); + expect(response[1]?.usersToGroups.length).toEqual(2); + expect(response[2]?.usersToGroups.length).toEqual(1); + + expect(response).toContainEqual({ + id: 1, + name: 'Group1', + lower: 'group1', + description: null, + usersToGroups: [{ + user: { + id: 1, + name: 'Dan', + lower: 'dan', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 2, + name: 'Group2', + lower: 'group2', + description: null, + usersToGroups: [{ + user: { + id: 2, + name: 'Andrew', + lower: 'andrew', + verified: false, + invitedBy: null, + }, + }, { + user: { + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: null, + }, + }], + }); + + expect(response).toContainEqual({ + id: 3, + name: 'Group3', + lower: 'group3', + description: null, + usersToGroups: [{ + user: { + id: 3, + name: 'Alex', + lower: 'alex', + verified: false, + invitedBy: null, + }, + }], + }); +}); + +test('.toSQL()', () => { + const query = db.query.usersTable.findFirst().toSQL(); + + expect(query).toHaveProperty('sql', expect.any(String)); + expect(query).toHaveProperty('params', expect.any(Array)); +}); + +// + custom + where + orderby + +// + custom + where + orderby + limit + +// + partial + +// + partial(false) + +// + partial + orderBy + where (all not selected) + +/* + One four-level relation users+posts+comments+coment_likes + + users+users_to_groups+groups +*/ + +/* + Really hard case + 1. users+posts+comments+coment_likes + 2. users+users_to_groups+groups + 3. users+users +*/ diff --git a/integration-tests/tests/replicas/singlestore.test.ts b/integration-tests/tests/replicas/singlestore.test.ts new file mode 100644 index 000000000..76d84c972 --- /dev/null +++ b/integration-tests/tests/replicas/singlestore.test.ts @@ -0,0 +1,805 @@ +import { sql } from 'drizzle-orm'; +import { drizzle } from 'drizzle-orm/singlestore'; +import { boolean, serial, singlestoreTable, text, withReplicas } from 'drizzle-orm/singlestore-core'; +import { describe, expect, it, vi } from 'vitest'; + +const usersTable = singlestoreTable('users', { + id: serial('id' as string).primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), +}); + +const users = singlestoreTable('users', { + id: serial('id' as string).primaryKey(), +}); + +describe('[select] read replicas singlestore', () => { + it('primary select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + const query = db.$primary.select().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(query.toSQL().sql).toEqual('select `id` from `users`'); + + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + const query1 = db.select({ count: sql`count(*)`.as('count') }).from(users).limit(1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(query1.toSQL().sql).toEqual('select count(*) as `count` from `users` limit ?'); + + const query2 = db.select().from(users); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); + + it('single read replica select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + const query1 = db.select().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select `id` from `users`'); + + const query2 = db.select().from(users); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); + + it('single read replica select + primary select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + const query1 = db.select({ id: users.id }).from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select `id` from `users`'); + + const query2 = db.$primary.select().from(users); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); + + it('always first read select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + const query1 = db.select().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('select `id` from `users`'); + + const query2 = db.select().from(users); + + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); +}); + +describe('[selectDistinct] read replicas singlestore', () => { + it('primary selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + const query = db.$primary.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('random replica selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.selectDistinct().from(users); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('single read replica selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.selectDistinct().from(users); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('single read replica selectDistinct + primary selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.$primary.selectDistinct().from(users); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('always first read selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.selectDistinct().from(users); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); +}); + +describe('[with] read replicas singlestore', () => { + it('primary with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + const obj1 = {} as any; + const obj2 = {} as any; + const obj3 = {} as any; + const obj4 = {} as any; + + db.$primary.with(obj1, obj2, obj3, obj4); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(obj1, obj2, obj3, obj4); + }); + + it('random replica with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica with + primary with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.with(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + const obj1 = {} as any; + const obj2 = {} as any; + const obj3 = {} as any; + + db.with(obj1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledWith(obj1); + + db.with(obj2, obj3); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledWith(obj2, obj3); + }); +}); + +describe('[update] replicas singlestore', () => { + it('primary update', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'update'); + const spyRead1 = vi.spyOn(read1, 'update'); + const spyRead2 = vi.spyOn(read2, 'update'); + + const query1 = db.update(users).set({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('update `users` set `id` = ?'); + + const query2 = db.update(users).set({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query2.toSQL().sql).toEqual('update `users` set `id` = ?'); + + const query3 = db.$primary.update(users).set({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query3.toSQL().sql).toEqual('update `users` set `id` = ?'); + }); +}); + +describe('[delete] replicas singlestore', () => { + it('primary delete', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'delete'); + const spyRead1 = vi.spyOn(read1, 'delete'); + const spyRead2 = vi.spyOn(read2, 'delete'); + + const query1 = db.delete(users); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(users); + expect(query1.toSQL().sql).toEqual('delete from `users`'); + + const query2 = db.delete(users); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenNthCalledWith(2, users); + expect(query2.toSQL().sql).toEqual('delete from `users`'); + + db.$primary.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[insert] replicas singlestore', () => { + it('primary insert', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'insert'); + const spyRead1 = vi.spyOn(read1, 'insert'); + const spyRead2 = vi.spyOn(read2, 'insert'); + + const query = db.insert(users).values({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(users); + expect(query.toSQL().sql).toEqual('insert into `users` (`id`) values (?)'); + + db.insert(users); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenNthCalledWith(2, users); + + db.$primary.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[execute] replicas singlestore', () => { + it('primary execute', async () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'execute'); + const spyRead1 = vi.spyOn(read1, 'execute'); + const spyRead2 = vi.spyOn(read2, 'execute'); + + expect(db.execute(sql``)).rejects.toThrow(); + + // try { + // db.execute(sql``); + // } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.execute(sql``)).rejects.toThrow(); + // try { + // db.execute(sql``); + // } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.execute(sql``)).rejects.toThrow(); + // try { + // db.execute(sql``); + // } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[transaction] replicas singlestore', () => { + it('primary transaction', async () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'transaction'); + const spyRead1 = vi.spyOn(read1, 'transaction'); + const spyRead2 = vi.spyOn(read2, 'transaction'); + const txFn1 = async (tx: any) => { + tx.select().from({} as any); + }; + + expect(db.transaction(txFn1)).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(txFn1); + + const txFn2 = async (tx: any) => { + tx.select().from({} as any); + }; + + expect(db.transaction(txFn2)).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenNthCalledWith(2, txFn2); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[findFirst] read replicas singlestore', () => { + it('primary findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + const obj = {} as any; + + db.$primary.query.usersTable.findFirst(obj); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(obj); + }); + + it('random replica findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + const par1 = {} as any; + + db.query.usersTable.findFirst(par1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledWith(par1); + + const query = db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + expect(query.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable` limit ?'); + }); + + it('single read replica findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica findFirst + primary findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.query.usersTable.findFirst(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[findMany] read replicas singlestore', () => { + it('primary findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + const obj = {} as any; + + const query = db.$primary.query.usersTable.findMany(obj); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(obj); + expect(query.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + }); + + it('random replica findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + const obj1 = {} as any; + const obj2 = {} as any; + + const query1 = db.query.usersTable.findMany(obj1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + expect(spyRead1).toHaveBeenCalledWith(obj1); + + const query2 = db.query.usersTable.findMany(obj2); + + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + expect(spyRead2).toHaveBeenCalledWith(obj2); + }); + + it('single read replica findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const obj1 = {} as any; + const obj2 = {} as any; + + const query1 = db.query.usersTable.findMany(obj1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledWith(obj1); + expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + + const query2 = db.query.usersTable.findMany(obj2); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenNthCalledWith(2, obj2); + expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + }); + + it('single read replica findMany + primary findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const obj1 = {} as any; + const obj2 = {} as any; + + const query1 = db.query.usersTable.findMany(obj1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledWith(obj1); + expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + + const query2 = db.$primary.query.usersTable.findMany(obj2); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyPrimary).toHaveBeenNthCalledWith(1, obj2); + expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + }); + + it('always first read findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + const obj1 = {} as any; + const obj2 = {} as any; + + const query1 = db.query.usersTable.findMany(obj1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledWith(obj1); + expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + + const query2 = db.query.usersTable.findMany(obj2); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenNthCalledWith(2, obj2); + expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + }); +}); diff --git a/integration-tests/tests/singlestore/singlestore-common.ts b/integration-tests/tests/singlestore/singlestore-common.ts new file mode 100644 index 000000000..037c27202 --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-common.ts @@ -0,0 +1,3432 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import 'dotenv/config'; +import Docker from 'dockerode'; +import { + and, + asc, + avg, + avgDistinct, + count, + countDistinct, + eq, + exists, + getTableColumns, + gt, + gte, + inArray, + lt, + max, + min, + Name, + notInArray, + placeholder, + sql, + sum, + sumDistinct, + TransactionRollbackError, +} from 'drizzle-orm'; +import type { SingleStoreDatabase } from 'drizzle-orm/singlestore-core'; +import { + alias, + bigint, + boolean, + date, + datetime, + decimal, + except, + getTableConfig, + getViewConfig, + int, + intersect, + json, + mediumint, + primaryKey, + serial, + singlestoreEnum, + singlestoreSchema, + singlestoreTable, + singlestoreTableCreator, + singlestoreView, + smallint, + text, + time, + timestamp, + tinyint, + union, + unionAll, + unique, + uniqueIndex, + uniqueKeyName, + varchar, + year, +} from 'drizzle-orm/singlestore-core'; +import { migrate } from 'drizzle-orm/singlestore/migrator'; +import getPort from 'get-port'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeEach, describe, expect, expectTypeOf, test } from 'vitest'; +import { Expect, toLocalDate } from '~/utils.ts'; +import type { Equal } from '~/utils.ts'; + +type TestSingleStoreDB = SingleStoreDatabase; + +declare module 'vitest' { + interface TestContext { + singlestore: { + db: TestSingleStoreDB; + }; + } +} + +const ENABLE_LOGGING = false; + +const usersTable = singlestoreTable('userstest', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: json('jsonb').$type(), + createdAt: timestamp('created_at', { fsp: 6 }).notNull().defaultNow(), +}); + +const users2Table = singlestoreTable('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id'), +}); + +const citiesTable = singlestoreTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +const usersOnUpdate = singlestoreTable('users_on_update', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + updateCounter: int('update_counter').default(sql`1`).$onUpdateFn(() => sql`update_counter + 1`), + updatedAt: datetime('updated_at', { mode: 'date', fsp: 6 }).$onUpdateFn(() => new Date()), + alwaysNull: text('always_null').$type().$onUpdateFn(() => null), // need to add $type because $onUpdate add a default value +}); + +const datesTable = singlestoreTable('datestable', { + date: date('date'), + dateAsString: date('date_as_string', { mode: 'string' }), + time: time('time', { fsp: 1 }), + datetime: datetime('datetime', { fsp: 6 }), + datetimeAsString: datetime('datetime_as_string', { fsp: 6, mode: 'string' }), + timestamp: timestamp('timestamp', { fsp: 6 }), + timestampAsString: timestamp('timestamp_as_string', { fsp: 6, mode: 'string' }), + year: year('year'), +}); + +const coursesTable = singlestoreTable('courses', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + categoryId: int('category_id'), +}); + +const courseCategoriesTable = singlestoreTable('course_categories', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +const orders = singlestoreTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull().$default(() => 'random_string'), + amount: int('amount').notNull(), + quantity: int('quantity').notNull(), +}); + +const usersMigratorTable = singlestoreTable('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}, (table) => { + return { + name: uniqueIndex('').on(table.name).using('btree'), + }; +}); + +// To test aggregate functions +const aggregateTable = singlestoreTable('aggregate_table', { + id: serial('id').notNull(), + name: text('name').notNull(), + a: int('a'), + b: int('b'), + c: int('c'), + nullOnly: int('null_only'), +}); + +// To test another schema and multischema +const mySchema = singlestoreSchema(`mySchema`); + +const usersMySchemaTable = mySchema.table('userstest', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: json('jsonb').$type(), + createdAt: timestamp('created_at', { fsp: 6 }).notNull().defaultNow(), +}); + +const users2MySchemaTable = mySchema.table('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id'), +}); + +const citiesMySchemaTable = mySchema.table('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +let singlestoreContainer: Docker.Container; +export async function createDockerDB(): Promise<{ connectionString: string; container: Docker.Container }> { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + ); + + singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return { + connectionString: `singlestore://root:singlestore@localhost:${port}/`, + container: singlestoreContainer, + }; +} + +// Tests are slow so we keep track of the test number +let testRunNumber = 0; + +export function tests(driver?: string) { + describe('common', () => { + afterAll(async () => { + await singlestoreContainer?.stop().catch(console.error); + }); + + beforeEach(async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`drop table if exists userstest`); + await db.execute(sql`drop table if exists users2`); + await db.execute(sql`drop table if exists cities`); + + await db.execute(sql`drop schema if exists \`mySchema\``); + await db.execute(sql`create schema if not exists \`mySchema\``); + + await db.execute( + sql` + create table userstest ( + id serial primary key, + name text not null, + verified boolean not null default false, + jsonb json, + created_at timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table users2 ( + id serial primary key, + name text not null, + city_id int + ) + `, + ); + + await db.execute( + sql` + create table cities ( + id serial primary key, + name text not null + ) + `, + ); + + // mySchema + await db.execute( + sql` + create table \`mySchema\`.\`userstest\` ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table \`mySchema\`.\`cities\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.execute( + sql` + create table \`mySchema\`.\`users2\` ( + \`id\` serial primary key, + \`name\` text not null, + \`city_id\` int + ) + `, + ); + + testRunNumber += 1; + console.log(`Test number: ${testRunNumber}`); + }); + + async function setupReturningFunctionsTest(db: SingleStoreDatabase) { + await db.execute(sql`drop table if exists \`users_default_fn\``); + await db.execute( + sql` + create table \`users_default_fn\` ( + \`id\` varchar(256) primary key, + \`name\` text not null + ); + `, + ); + } + + async function setupSetOperationTest(db: TestSingleStoreDB) { + await db.execute(sql`drop table if exists \`users2\``); + await db.execute(sql`drop table if exists \`cities\``); + await db.execute( + sql` + create table \`users2\` ( + \`id\` serial primary key, + \`name\` text not null, + \`city_id\` int + ) + `, + ); + + await db.execute( + sql` + create table \`cities\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.insert(citiesTable).values([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 3 }, + { id: 4, name: 'Peter', cityId: 3 }, + { id: 5, name: 'Ben', cityId: 2 }, + { id: 6, name: 'Jill', cityId: 1 }, + { id: 7, name: 'Mary', cityId: 2 }, + { id: 8, name: 'Sally', cityId: 1 }, + ]); + } + + async function setupAggregateFunctionsTest(db: TestSingleStoreDB) { + await db.execute(sql`drop table if exists \`aggregate_table\``); + await db.execute( + sql` + create table \`aggregate_table\` ( + \`id\` integer primary key auto_increment not null, + \`name\` text not null, + \`a\` integer, + \`b\` integer, + \`c\` integer, + \`null_only\` integer + ); + `, + ); + await db.insert(aggregateTable).values([ + { id: 1, name: 'value 1', a: 5, b: 10, c: 20 }, + { id: 2, name: 'value 1', a: 5, b: 20, c: 30 }, + { id: 3, name: 'value 2', a: 10, b: 50, c: 60 }, + { id: 4, name: 'value 3', a: 20, b: 20, c: null }, + { id: 5, name: 'value 4', a: null, b: 90, c: 120 }, + { id: 6, name: 'value 5', a: 80, b: 10, c: null }, + { id: 7, name: 'value 6', a: null, b: null, c: 150 }, + ]); + } + + test('table config: unsigned ints', async () => { + const unsignedInts = singlestoreTable('cities1', { + bigint: bigint('bigint', { mode: 'number', unsigned: true }), + int: int('int', { unsigned: true }), + smallint: smallint('smallint', { unsigned: true }), + mediumint: mediumint('mediumint', { unsigned: true }), + tinyint: tinyint('tinyint', { unsigned: true }), + }); + + const tableConfig = getTableConfig(unsignedInts); + + const bigintColumn = tableConfig.columns.find((c) => c.name === 'bigint')!; + const intColumn = tableConfig.columns.find((c) => c.name === 'int')!; + const smallintColumn = tableConfig.columns.find((c) => c.name === 'smallint')!; + const mediumintColumn = tableConfig.columns.find((c) => c.name === 'mediumint')!; + const tinyintColumn = tableConfig.columns.find((c) => c.name === 'tinyint')!; + + expect(bigintColumn.getSQLType()).toBe('bigint unsigned'); + expect(intColumn.getSQLType()).toBe('int unsigned'); + expect(smallintColumn.getSQLType()).toBe('smallint unsigned'); + expect(mediumintColumn.getSQLType()).toBe('mediumint unsigned'); + expect(tinyintColumn.getSQLType()).toBe('tinyint unsigned'); + }); + + test('table config: signed ints', async () => { + const unsignedInts = singlestoreTable('cities1', { + bigint: bigint('bigint', { mode: 'number' }), + int: int('int'), + smallint: smallint('smallint'), + mediumint: mediumint('mediumint'), + tinyint: tinyint('tinyint'), + }); + + const tableConfig = getTableConfig(unsignedInts); + + const bigintColumn = tableConfig.columns.find((c) => c.name === 'bigint')!; + const intColumn = tableConfig.columns.find((c) => c.name === 'int')!; + const smallintColumn = tableConfig.columns.find((c) => c.name === 'smallint')!; + const mediumintColumn = tableConfig.columns.find((c) => c.name === 'mediumint')!; + const tinyintColumn = tableConfig.columns.find((c) => c.name === 'tinyint')!; + + expect(bigintColumn.getSQLType()).toBe('bigint'); + expect(intColumn.getSQLType()).toBe('int'); + expect(smallintColumn.getSQLType()).toBe('smallint'); + expect(mediumintColumn.getSQLType()).toBe('mediumint'); + expect(tinyintColumn.getSQLType()).toBe('tinyint'); + }); + + test('table config: primary keys name', async () => { + const table = singlestoreTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: primaryKey({ columns: [t.id, t.name], name: 'custom_pk' }), + })); + + const tableConfig = getTableConfig(table); + + expect(tableConfig.primaryKeys).toHaveLength(1); + expect(tableConfig.primaryKeys[0]!.getName()).toBe('custom_pk'); + }); + + test('table configs: unique third param', async () => { + const cities1Table = singlestoreTable('cities1', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: unique('custom_name').on(t.name, t.state), + f1: unique('custom_name1').on(t.name, t.state), + })); + + const tableConfig = getTableConfig(cities1Table); + + expect(tableConfig.uniqueConstraints).toHaveLength(2); + + expect(tableConfig.uniqueConstraints[0]?.name).toBe('custom_name'); + expect(tableConfig.uniqueConstraints[0]?.columns.map((t) => t.name)).toEqual(['name', 'state']); + + expect(tableConfig.uniqueConstraints[1]?.name).toBe('custom_name1'); + expect(tableConfig.uniqueConstraints[1]?.columns.map((t) => t.name)).toEqual(['name', 'state']); + }); + + test('table configs: unique in column', async () => { + const cities1Table = singlestoreTable('cities1', { + id: serial('id').primaryKey(), + name: text('name').notNull().unique(), + state: text('state').unique('custom'), + field: text('field').unique('custom_field'), + }); + + const tableConfig = getTableConfig(cities1Table); + + const columnName = tableConfig.columns.find((it) => it.name === 'name'); + expect(columnName?.uniqueName).toBe(uniqueKeyName(cities1Table, [columnName!.name])); + expect(columnName?.isUnique).toBeTruthy(); + + const columnState = tableConfig.columns.find((it) => it.name === 'state'); + expect(columnState?.uniqueName).toBe('custom'); + expect(columnState?.isUnique).toBeTruthy(); + + const columnField = tableConfig.columns.find((it) => it.name === 'field'); + expect(columnField?.uniqueName).toBe('custom_field'); + expect(columnField?.isUnique).toBeTruthy(); + }); + + test('select all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('select sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('select typed sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('select with empty array in inArray', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + const result = await db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(inArray(usersTable.id, [])) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([]); + }); + + test('select with empty array in notInArray', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + const result = await db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(notInArray(usersTable.id, [])) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'JOHN' }, { name: 'JANE' }, { name: 'JANE' }]); + }); + + test('select distinct', async (ctx) => { + const { db } = ctx.singlestore; + + const usersDistinctTable = singlestoreTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${usersDistinctTable}`); + await db.execute(sql`create table ${usersDistinctTable} (id int, name text)`); + + await db.insert(usersDistinctTable).values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]); + const users = await db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ); + + await db.execute(sql`drop table ${usersDistinctTable}`); + + expect(users).toEqual([{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); + }); + + test('insert returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + const [result, _] = await db.insert(usersTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); + }); + + test('delete returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); + }); + + test('update returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + expect(users[0].changedRows).toBe(1); + }); + + test('update with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select().from(usersTable).where(eq(usersTable.id, 1)); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 2000); + expect(users).toEqual([{ id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); + }); + + test('update with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); + }); + + test('delete with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); + }); + + test('delete with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); + }); + + test('insert + select', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); + }); + + test('json insert', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); + }); + + test('insert with overridden default values', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('insert many', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); + }); + + test('insert many with returning', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + + expect(result[0].affectedRows).toBe(4); + }); + + test('select with group by as field', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.name) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); + }); + + test('select with exists', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const user = alias(usersTable, 'user'); + const result = await db.select({ name: usersTable.name }).from(usersTable).where( + exists( + db.select({ one: sql`1` }).from(user).where(and(eq(usersTable.name, 'John'), eq(user.id, usersTable.id))), + ), + ) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }]); + }); + + test('select with group by as sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); + }); + + test('$default function', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`orders\``); + await db.execute( + sql` + create table \`orders\` ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values({ id: 1, region: 'Ukraine', amount: 1, quantity: 1 }); + const selectedOrder = await db.select().from(orders); + + expect(selectedOrder).toEqual([{ + id: 1, + amount: 1, + quantity: 1, + region: 'Ukraine', + product: 'random_string', + }]); + }); + + test('$default with empty array', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`s_orders\``); + await db.execute( + sql` + create table \`s_orders\` ( + \`id\` serial primary key, + \`region\` text default 'Ukraine', + \`product\` text not null + ) + `, + ); + + const users = singlestoreTable('s_orders', { + id: serial('id').primaryKey(), + region: text('region').default('Ukraine'), + product: text('product').$defaultFn(() => 'random_string'), + }); + + await db.insert(users).values({ id: 1 }); + const selectedOrder = await db.select().from(users); + + expect(selectedOrder).toEqual([{ + id: 1, + region: 'Ukraine', + product: 'random_string', + }]); + }); + + test('select with group by as sql + column', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + }); + + test('select with group by as column + sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + }); + + test('select with group by complex query', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + expect(result).toEqual([{ name: 'Jane' }]); + }); + + test('build query', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: `select \`id\`, \`name\` from \`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + params: [], + }); + }); + + test('Query check: Insert all defaults in 1 row', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + const query = db + .insert(users) + .values({}) + .toSQL(); + + expect(query).toEqual({ + sql: 'insert into `users` (`id`, `name`, `state`) values (default, default, default)', + params: [], + }); + }); + + test('Query check: Insert all defaults in multiple rows', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state').default('UA'), + }); + + const query = db + .insert(users) + .values([{}, {}]) + .toSQL(); + + expect(query).toEqual({ + sql: + 'insert into `users` (`id`, `name`, `state`) values (default, default, default), (default, default, default)', + params: [], + }); + }); + + test('Insert all defaults in 1 row', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('empty_insert_single', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial primary key, name text default 'Dan', state text)`, + ); + + await db.insert(users).values({ id: 1 }); + + const res = await db.select().from(users); + + expect(res).toEqual([{ id: 1, name: 'Dan', state: null }]); + }); + + test('Insert all defaults in multiple rows', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('empty_insert_multiple', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial primary key, name text default 'Dan', state text)`, + ); + + await db.insert(users).values([{ id: 1 }, { id: 2 }]); + + const res = await db.select().from(users).orderBy(asc(users.id)); + + expect(res).toEqual([{ id: 1, name: 'Dan', state: null }, { id: 2, name: 'Dan', state: null }]); + }); + + test('build query insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.insert(usersTable) + .values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }) + .onDuplicateKeyUpdate({ set: { id: 1, name: 'John1' } }) + .toSQL(); + + expect(query).toEqual({ + sql: + 'insert into `userstest` (`id`, `name`, `verified`, `jsonb`, `created_at`) values (?, ?, default, ?, default) on duplicate key update `id` = ?, `name` = ?', + params: [1, 'John', '["foo","bar"]', 1, 'John1'], + }); + }); + + test('insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John1' }]); + }); + + test('insert conflict', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await expect((async () => { + db.insert(usersTable).values({ id: 1, name: 'John1' }); + })()).resolves.not.toThrowError(); + }); + + test('insert conflict with ignore', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .ignore() + .values({ id: 1, name: 'John1' }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John' }]); + }); + + test('insert sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`${'John'}` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('partial join with alias', async (ctx) => { + const { db } = ctx.singlestore; + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }).from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }]); + }); + + test('full join with alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select().from(users) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(users.id, 10)) + .orderBy(asc(users.id)); + + expect(result).toEqual([{ + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); + }); + + test('select from alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(user) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(user.id, 10)) + .orderBy(asc(user.id)); + + expect(result).toEqual([{ + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); + }); + + test('insert with spaces', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); + }); + + test('prepared statement', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const statement = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .prepare(); + const result = await statement.execute(); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('insert: placeholders on columns with encoder', async (ctx) => { + const { db } = ctx.singlestore; + + const date = new Date('2024-08-07T15:30:00Z'); + + const statement = db.insert(usersTable).values({ + id: 1, + name: 'John', + createdAt: sql.placeholder('createdAt'), + }).prepare(); + + await statement.execute({ createdAt: date }); + + const result = await db + .select({ + id: usersTable.id, + createdAt: usersTable.createdAt, + }) + .from(usersTable); + + expect(result).toEqual([ + { id: 1, createdAt: date }, + ]); + }); + + test('prepared statement reuse', async (ctx) => { + const { db } = ctx.singlestore; + + const stmt = db.insert(usersTable).values({ + verified: true, + id: placeholder('id'), + name: placeholder('name'), + }).prepare(); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ id: i + 1, name: `John ${i}` }); + } + + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); + }); + + test('prepared statement with placeholder in .where', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .where(eq(usersTable.id, placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('migrator', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists cities_migration`); + await db.execute(sql`drop table if exists users_migration`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists __drizzle_migrations`); + + await migrate(db, { migrationsFolder: './drizzle2/singlestore' }); + + await db.insert(usersMigratorTable).values({ id: 1, name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table cities_migration`); + await db.execute(sql`drop table users_migration`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table __drizzle_migrations`); + }); + + test('insert via db.execute + select via db.execute', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute( + sql`insert into ${usersTable} (${new Name(usersTable.id.name)},${new Name( + usersTable.name.name, + )}) values (1,${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>(sql`select id, name from ${usersTable}`); + expect(result[0]).toEqual([{ id: 1, name: 'John' }]); + }); + + test('insert via db.execute w/ query builder', async (ctx) => { + const { db } = ctx.singlestore; + + const inserted = await db.execute( + db.insert(usersTable).values({ id: 1, name: 'John' }), + ); + expect(inserted[0].affectedRows).toBe(1); + }); + + test('insert + select all possible dates', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute( + sql` + create table \`datestable\` ( + \`date\` date, + \`date_as_string\` date, + \`time\` time, + \`datetime\` datetime, + \`datetime_as_string\` datetime, + \`timestamp\` timestamp(6), + \`timestamp_as_string\` timestamp(6), + \`year\` year + ) + `, + ); + + const date = new Date('2022-11-11'); + const dateWithMilliseconds = new Date('2022-11-11 12:12:12.123'); + + await db.insert(datesTable).values({ + date: date, + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: date, + year: 22, + datetimeAsString: '2022-11-11 12:12:12', + timestamp: dateWithMilliseconds, + timestampAsString: '2022-11-11 12:12:12.123', + }); + + const res = await db.select().from(datesTable); + + expect(res[0]?.date).toBeInstanceOf(Date); + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(typeof res[0]?.dateAsString).toBe('string'); + expect(typeof res[0]?.datetimeAsString).toBe('string'); + + expect(res).toEqual([{ + date: toLocalDate(new Date('2022-11-11')), + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: new Date('2022-11-11'), + year: 2022, + datetimeAsString: '2022-11-11 12:12:12', + timestamp: new Date('2022-11-11 12:12:12.123'), + timestampAsString: '2022-11-11 12:12:12.123000', + }]); + + await db.execute(sql`drop table if exists \`datestable\``); + }); + + const tableWithEnums = singlestoreTable('enums_test_case', { + id: serial('id').primaryKey(), + enum1: singlestoreEnum('enum1', ['a', 'b', 'c']).notNull(), + enum2: singlestoreEnum('enum2', ['a', 'b', 'c']).default('a'), + enum3: singlestoreEnum('enum3', ['a', 'b', 'c']).notNull().default('b'), + }); + + test('SingleStore enum test case #1', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`enums_test_case\``); + + await db.execute(sql` + create table \`enums_test_case\` ( + \`id\` serial primary key, + \`enum1\` ENUM('a', 'b', 'c') not null, + \`enum2\` ENUM('a', 'b', 'c') default 'a', + \`enum3\` ENUM('a', 'b', 'c') not null default 'b' + ) + `); + + await db.insert(tableWithEnums).values([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum3: 'c' }, + { id: 3, enum1: 'a' }, + ]); + + const res = await db.select().from(tableWithEnums).orderBy(asc(tableWithEnums.id)); + + await db.execute(sql`drop table \`enums_test_case\``); + + expect(res).toEqual([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum2: 'a', enum3: 'c' }, + { id: 3, enum1: 'a', enum2: 'a', enum3: 'b' }, + ]); + }); + + test('left join (flat object fields)', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + userId: users2Table.id, + userName: users2Table.name, + cityId: citiesTable.id, + cityName: citiesTable.name, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(users2Table.id); + + expect(res).toEqual([ + { userId: 1, userName: 'John', cityId: 1, cityName: 'Paris' }, + { userId: 2, userName: 'Jane', cityId: null, cityName: null }, + ]); + }); + + test('left join (grouped fields)', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + id: users2Table.id, + user: { + name: users2Table.name, + nameUpper: sql`upper(${users2Table.name})`, + }, + city: { + id: citiesTable.id, + name: citiesTable.name, + nameUpper: sql`upper(${citiesTable.name})`, + }, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + id: 1, + user: { name: 'John', nameUpper: 'JOHN' }, + city: { id: 1, name: 'Paris', nameUpper: 'PARIS' }, + }, + { + id: 2, + user: { name: 'Jane', nameUpper: 'JANE' }, + city: null, + }, + ]); + }); + + test('left join (all fields)', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select().from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + users2: { + id: 1, + name: 'John', + cityId: 1, + }, + cities: { + id: 1, + name: 'Paris', + }, + }, + { + users2: { + id: 2, + name: 'Jane', + cityId: null, + }, + cities: null, + }, + ]); + }); + + test('join subquery', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`courses\``); + await db.execute(sql`drop table if exists \`course_categories\``); + + await db.execute( + sql` + create table \`course_categories\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.execute( + sql` + create table \`courses\` ( + \`id\` serial primary key, + \`name\` text not null, + \`category_id\` int + ) + `, + ); + + await db.insert(courseCategoriesTable).values([ + { id: 1, name: 'Category 1' }, + { id: 2, name: 'Category 2' }, + { id: 3, name: 'Category 3' }, + { id: 4, name: 'Category 4' }, + ]); + + await db.insert(coursesTable).values([ + { id: 1, name: 'Development', categoryId: 2 }, + { id: 2, name: 'IT & Software', categoryId: 3 }, + { id: 3, name: 'Marketing', categoryId: 4 }, + { id: 4, name: 'Design', categoryId: 1 }, + ]); + + const sq2 = db + .select({ + categoryId: courseCategoriesTable.id, + category: courseCategoriesTable.name, + total: sql`count(${courseCategoriesTable.id})`, + }) + .from(courseCategoriesTable) + .groupBy(courseCategoriesTable.id, courseCategoriesTable.name) + .as('sq2'); + + const res = await db + .select({ + courseName: coursesTable.name, + categoryId: sq2.categoryId, + }) + .from(coursesTable) + .leftJoin(sq2, eq(coursesTable.categoryId, sq2.categoryId)) + .orderBy(coursesTable.name); + + expect(res).toEqual([ + { courseName: 'Design', categoryId: 1 }, + { courseName: 'Development', categoryId: 2 }, + { courseName: 'IT & Software', categoryId: 3 }, + { courseName: 'Marketing', categoryId: 4 }, + ]); + + await db.execute(sql`drop table if exists \`courses\``); + await db.execute(sql`drop table if exists \`course_categories\``); + }); + + test('with ... select', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`orders\``); + await db.execute( + sql` + create table \`orders\` ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: regionalSales.region, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`cast(sum(${orders.quantity}) as unsigned)`, + productSales: sql`cast(sum(${orders.amount}) as unsigned)`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))) + .groupBy(orders.region, orders.product) + .orderBy(orders.region, orders.product); + + expect(result).toEqual([ + { + region: 'Europe', + product: 'A', + productUnits: 3, + productSales: 30, + }, + { + region: 'Europe', + product: 'B', + productUnits: 5, + productSales: 50, + }, + { + region: 'US', + product: 'A', + productUnits: 7, + productSales: 70, + }, + { + region: 'US', + product: 'B', + productUnits: 9, + productSales: 90, + }, + ]); + }); + + test('with ... update', async (ctx) => { + const { db } = ctx.singlestore; + + const products = singlestoreTable('products', { + id: serial('id').primaryKey(), + price: decimal('price', { + precision: 15, + scale: 2, + }).notNull(), + cheap: boolean('cheap').notNull().default(false), + }); + + await db.execute(sql`drop table if exists ${products}`); + await db.execute(sql` + create table ${products} ( + id serial primary key, + price decimal(15, 2) not null, + cheap boolean not null default false + ) + `); + + await db.insert(products).values([ + { id: 1, price: '10.99' }, + { id: 2, price: '25.85' }, + { id: 3, price: '32.99' }, + { id: 4, price: '2.50' }, + { id: 5, price: '4.59' }, + ]); + + const averagePrice = db + .$with('average_price') + .as( + db + .select({ + value: sql`avg(${products.price})`.as('value'), + }) + .from(products), + ); + + await db + .with(averagePrice) + .update(products) + .set({ + cheap: true, + }) + .where(lt(products.price, sql`(select * from ${averagePrice})`)); + + const result = await db + .select({ + id: products.id, + }) + .from(products) + .where(eq(products.cheap, true)) + .orderBy(asc(products.id)); + + expect(result).toEqual([ + { id: 1 }, + { id: 4 }, + { id: 5 }, + ]); + }); + + test('with ... delete', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`orders\``); + await db.execute( + sql` + create table \`orders\` ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values([ + { id: 1, region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { id: 2, region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { id: 3, region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { id: 4, region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { id: 5, region: 'US', product: 'A', amount: 30, quantity: 3 }, + { id: 6, region: 'US', product: 'A', amount: 40, quantity: 4 }, + { id: 7, region: 'US', product: 'B', amount: 40, quantity: 4 }, + { id: 8, region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const averageAmount = db + .$with('average_amount') + .as( + db + .select({ + value: sql`avg(${orders.amount})`.as('value'), + }) + .from(orders), + ); + + await db + .with(averageAmount) + .delete(orders) + .where(gt(orders.amount, sql`(select * from ${averageAmount})`)); + + const result = await db + .select({ + id: orders.id, + }) + .from(orders) + .orderBy(asc(orders.id)); + + expect(result).toEqual([ + { id: 1 }, + { id: 2 }, + { id: 3 }, + { id: 4 }, + { id: 5 }, + ]); + }); + + test('select from subquery sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(users2Table).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]); + + const sq = db + .select({ name: sql`concat(${users2Table.name}, " modified")`.as('name') }) + .from(users2Table) + .orderBy(asc(users2Table.id)) + .as('sq'); + + const res = await db.select({ name: sq.name }).from(sq); + + expect(res).toEqual([{ name: 'John modified' }, { name: 'Jane modified' }]); + }); + + test('select a field without joining its table', (ctx) => { + const { db } = ctx.singlestore; + + expect(() => db.select({ name: users2Table.name }).from(usersTable).prepare()).toThrowError(); + }); + + test('select all fields from subquery without alias', (ctx) => { + const { db } = ctx.singlestore; + + const sq = db.$with('sq').as(db.select({ name: sql`upper(${users2Table.name})` }).from(users2Table)); + + expect(() => db.select().from(sq).prepare()).toThrowError(); + }); + + test('select count()', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }]); + + const res = await db.select({ count: sql`count(*)` }).from(usersTable); + + expect(res).toEqual([{ count: 2 }]); + }); + + test('select for ...', (ctx) => { + const { db } = ctx.singlestore; + + { + const query = db.select().from(users2Table).for('update').toSQL(); + expect(query.sql).toMatch(/ for update$/); + } + { + const query = db.select().from(users2Table).for('share', { skipLocked: true }).toSQL(); + expect(query.sql).toMatch(/ for share skip locked$/); + } + { + const query = db.select().from(users2Table).for('update', { noWait: true }).toSQL(); + expect(query.sql).toMatch(/ for update no wait$/); + } + }); + + test('having', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable).values([{ id: 1, name: 'London' }, { id: 2, name: 'Paris' }, { + id: 3, + name: 'New York', + }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane', cityId: 1 }, { + id: 3, + name: 'Jack', + cityId: 2, + }]); + + const result = await db + .select({ + id: citiesTable.id, + name: sql`upper(${citiesTable.name})`.as('upper_name'), + usersCount: sql`count(${users2Table.id})`.as('users_count'), + }) + .from(citiesTable) + .leftJoin(users2Table, eq(users2Table.cityId, citiesTable.id)) + .where(({ name }) => sql`length(${name}) >= 3`) + .groupBy(citiesTable.id) + .having(({ usersCount }) => sql`${usersCount} > 0`) + .orderBy(({ name }) => name); + + expect(result).toEqual([ + { + id: 1, + name: 'LONDON', + usersCount: 2, + }, + { + id: 2, + name: 'PARIS', + usersCount: 1, + }, + ]); + }); + + test('view', async (ctx) => { + const { db } = ctx.singlestore; + + const newYorkers1 = singlestoreView('new_yorkers') + .as((qb) => qb.select().from(users2Table).where(eq(users2Table.cityId, 1))); + + const newYorkers2 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).as(sql`select * from ${users2Table} where ${eq(users2Table.cityId, 1)}`); + + const newYorkers3 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).existing(); + + await db.execute(sql`create view new_yorkers as ${getViewConfig(newYorkers1).query}`); + + await db.insert(citiesTable).values([{ id: 1, name: 'New York' }, { id: 2, name: 'Paris' }]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2).orderBy(asc(newYorkers2.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3).orderBy(asc(newYorkers3.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop view ${newYorkers1}`); + }); + + test('select from raw sql', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.select({ + id: sql`id`, + name: sql`name`, + }).from(sql`(select 1 as id, 'John' as name) as users`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John' }, + ]); + }); + + test('select from raw sql with joins', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db + .select({ + id: sql`users.id`, + name: sql`users.name`, + userCity: sql`users.city`, + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, sql`cities.id = users.id`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John', userCity: 'New York', cityName: 'Paris' }, + ]); + }); + + test('join on aliased sql from select', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db + .select({ + userId: sql`users.id`.as('userId'), + name: sql`users.name`, + userCity: sql`users.city`, + cityId: sql`cities.id`.as('cityId'), + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, (cols) => eq(cols.cityId, cols.userId)); + + Expect< + Equal<{ userId: number; name: string; userCity: string; cityId: number; cityName: string }[], typeof result> + >; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); + }); + + test('join on aliased sql from with clause', async (ctx) => { + const { db } = ctx.singlestore; + + const users = db.$with('users').as( + db.select({ + id: sql`id`.as('userId'), + name: sql`name`.as('userName'), + city: sql`city`.as('city'), + }).from( + sql`(select 1 as id, 'John' as name, 'New York' as city) as users`, + ), + ); + + const cities = db.$with('cities').as( + db.select({ + id: sql`id`.as('cityId'), + name: sql`name`.as('cityName'), + }).from( + sql`(select 1 as id, 'Paris' as name) as cities`, + ), + ); + + const result = await db + .with(users, cities) + .select({ + userId: users.id, + name: users.name, + userCity: users.city, + cityId: cities.id, + cityName: cities.name, + }) + .from(users) + .leftJoin(cities, (cols) => eq(cols.cityId, cols.userId)); + + Expect< + Equal<{ userId: number; name: string; userCity: string; cityId: number; cityName: string }[], typeof result> + >; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); + }); + + test('prefixed table', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `myprefix_${name}`); + + const users = singlestoreTable('test_prefixed_table_with_unique_name', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table myprefix_test_prefixed_table_with_unique_name (id int not null primary key, name text not null)`, + ); + + await db.insert(users).values({ id: 1, name: 'John' }); + + const result = await db.select().from(users); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + + await db.execute(sql`drop table ${users}`); + }); + + test('orderBy with aliased column', (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ + test: sql`something`.as('test'), + }).from(users2Table).orderBy((fields) => fields.test).toSQL(); + + expect(query.sql).toBe('select something as `test` from `users2` order by `test`'); + }); + + test('timestamp timezone', async (ctx) => { + const { db } = ctx.singlestore; + + const date = new Date(Date.parse('2020-01-01T12:34:56+07:00')); + + await db.insert(usersTable).values({ id: 1, name: 'With default times' }); + await db.insert(usersTable).values({ + id: 2, + name: 'Without default times', + createdAt: date, + }); + const users = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + + // check that the timestamps are set correctly for default times + expect(Math.abs(users[0]!.createdAt.getTime() - Date.now())).toBeLessThan(2000); + + // check that the timestamps are set correctly for non default times + expect(Math.abs(users[1]!.createdAt.getTime() - date.getTime())).toBeLessThan(2000); + }); + + test('transaction', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_transactions', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + const products = singlestoreTable('products_transactions', { + id: serial('id').primaryKey(), + price: int('price').notNull(), + stock: int('stock').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop table if exists ${products}`); + + await db.execute(sql`create table users_transactions (id serial not null primary key, balance int not null)`); + await db.execute( + sql`create table products_transactions (id serial not null primary key, price int not null, stock int not null)`, + ); + + const [{ insertId: userId }] = await db.insert(users).values({ id: 1, balance: 100 }); + const user = await db.select().from(users).where(eq(users.id, userId)).then((rows) => rows[0]!); + const [{ insertId: productId }] = await db.insert(products).values({ id: 1, price: 10, stock: 10 }); + const product = await db.select().from(products).where(eq(products.id, productId)).then((rows) => rows[0]!); + + await db.transaction(async (tx) => { + await tx.update(users).set({ balance: user.balance - product.price }).where(eq(users.id, user.id)); + await tx.update(products).set({ stock: product.stock - 1 }).where(eq(products.id, product.id)); + }); + + const result = await db.select().from(users); + + expect(result).toEqual([{ id: 1, balance: 90 }]); + + await db.execute(sql`drop table ${users}`); + await db.execute(sql`drop table ${products}`); + }); + + test('transaction rollback', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_transactions_rollback', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table users_transactions_rollback (id serial not null primary key, balance int not null)`, + ); + + await expect((async () => { + await db.transaction(async (tx) => { + await tx.insert(users).values({ balance: 100 }); + tx.rollback(); + }); + })()).rejects.toThrowError(TransactionRollbackError); + + const result = await db.select().from(users); + + expect(result).toEqual([]); + + await db.execute(sql`drop table ${users}`); + }); + + test('join subquery with join', async (ctx) => { + const { db } = ctx.singlestore; + + const internalStaff = singlestoreTable('internal_staff', { + userId: int('user_id').notNull(), + }); + + const customUser = singlestoreTable('custom_user', { + id: int('id').notNull(), + }); + + const ticket = singlestoreTable('ticket', { + staffId: int('staff_id').notNull(), + }); + + await db.execute(sql`drop table if exists ${internalStaff}`); + await db.execute(sql`drop table if exists ${customUser}`); + await db.execute(sql`drop table if exists ${ticket}`); + + await db.execute(sql`create table internal_staff (user_id integer not null)`); + await db.execute(sql`create table custom_user (id integer not null)`); + await db.execute(sql`create table ticket (staff_id integer not null)`); + + await db.insert(internalStaff).values({ userId: 1 }); + await db.insert(customUser).values({ id: 1 }); + await db.insert(ticket).values({ staffId: 1 }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin(customUser, eq(internalStaff.userId, customUser.id)) + .as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + expect(mainQuery).toEqual([{ + ticket: { staffId: 1 }, + internal_staff: { + internal_staff: { userId: 1 }, + custom_user: { id: 1 }, + }, + }]); + + await db.execute(sql`drop table ${internalStaff}`); + await db.execute(sql`drop table ${customUser}`); + await db.execute(sql`drop table ${ticket}`); + }); + + test('subquery with view', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_subquery_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.$with('sq').as(db.select().from(newYorkers)); + const result = await db.with(sq).select().from(sq).orderBy(asc(sq.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 1 }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); + }); + + test('join view as subquery', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_join_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.select().from(newYorkers).as('new_yorkers_sq'); + + const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id)).orderBy(asc(users.id)); + + expect(result).toEqual([ + { + users_join_view: { id: 1, name: 'John', cityId: 1 }, + new_yorkers_sq: { id: 1, name: 'John', cityId: 1 }, + }, + { + users_join_view: { id: 2, name: 'Jane', cityId: 2 }, + new_yorkers_sq: null, + }, + { + users_join_view: { id: 3, name: 'Jack', cityId: 1 }, + new_yorkers_sq: { id: 3, name: 'Jack', cityId: 1 }, + }, + { + users_join_view: { id: 4, name: 'Jill', cityId: 2 }, + new_yorkers_sq: null, + }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); + }); + + test('select iterator', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const iter = db.select().from(users) + .orderBy(asc(users.id)) + .iterator(); + + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + test('select iterator w/ prepared statement', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const prepared = db.select().from(users) + .orderBy(asc(users.id)) + .prepare(); + const iter = prepared.iterator(); + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + test('insert undefined', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.insert(users).values({ name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); + }); + + test('update undefined', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.update(users).set({ name: undefined }); + })()).rejects.toThrowError(); + + await expect((async () => { + await db.update(users).set({ id: 1, name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); + }); + + test('utc config for datetime', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute( + sql` + create table \`datestable\` ( + \`datetime_utc\` datetime(6), + \`datetime\` datetime(6) + ) + `, + ); + const datesTable = singlestoreTable('datestable', { + datetimeUTC: datetime('datetime_utc', { fsp: 6, mode: 'date' }), + datetime: datetime('datetime', { fsp: 6 }), + }); + + const dateObj = new Date('2022-11-11'); + const dateUtc = new Date('2022-11-11T12:12:12.122Z'); + + await db.insert(datesTable).values({ + datetimeUTC: dateUtc, + datetime: dateObj, + }); + + const res = await db.select().from(datesTable); + + const [rawSelect] = await db.execute(sql`select \`datetime_utc\` from \`datestable\``); + const selectedRow = (rawSelect as unknown as [{ datetime_utc: string }])[0]; + + expect(selectedRow.datetime_utc).toBe('2022-11-11 12:12:12.122000'); + expect(new Date(selectedRow.datetime_utc.replace(' ', 'T') + 'Z')).toEqual(dateUtc); + + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(res[0]?.datetimeUTC).toBeInstanceOf(Date); + + expect(res).toEqual([{ + datetimeUTC: dateUtc, + datetime: new Date('2022-11-11'), + }]); + + await db.execute(sql`drop table if exists \`datestable\``); + }); + + // TODO (https://memsql.atlassian.net/browse/MCDB-63261) allow chaining limit and orderby in subquery + test('set operations (union) from query builder with subquery', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + const citiesQuery = db + .select({ + id: citiesTable.id, + name: citiesTable.name, + orderCol: sql`0`.as('orderCol'), + }) + .from(citiesTable); + + const usersQuery = db + .select({ + id: users2Table.id, + name: users2Table.name, + orderCol: sql`1`.as('orderCol'), + }) + .from(users2Table); + + const unionQuery = db + .select({ + id: sql`id`, + name: sql`name`, + }) + .from( + citiesQuery.union(usersQuery).as('combined'), + ) + .orderBy(sql`orderCol`, sql`id`) + .limit(8); + + const result = await unionQuery; + + expect(result).toHaveLength(8); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Jack' }, + { id: 4, name: 'Peter' }, + { id: 5, name: 'Ben' }, + ]); + + // union should throw if selected fields are not in the same order + await expect((async () => { + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).union( + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (union) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const result = await union( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + { id: 1, name: 'John' }, + ]); + + await expect((async () => { + union( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (union all) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).orderBy(asc(sql`id`)).limit(2).unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).orderBy(asc(sql`id`)).limit(2), + ).as('sq'); + + const result = await db.select().from(sq).orderBy(asc(sql`id`)).limit(3); + + expect(result).toHaveLength(3); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + ]); + + await expect((async () => { + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).limit(2).unionAll( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).limit(2), + ).orderBy(asc(sql`id`)); + })()).rejects.toThrowError(); + }); + + test('set operations (union all) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).as('sq'); + + const result = await db.select().from(sq).limit(1); + + expect(result).toHaveLength(1); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + ]); + + await expect((async () => { + unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(1); + })()).rejects.toThrowError(); + }); + + test('set operations (intersect) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ) + .as('sq'); + + const result = await db.select().from(sq).orderBy(asc(sql`id`)); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await expect((async () => { + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (intersect) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = await intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).as('sq'); + + const result = await db.select().from(sq).limit(1); + + expect(result).toHaveLength(0); + + expect(result).toEqual([]); + + await expect((async () => { + intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(1); + })()).rejects.toThrowError(); + }); + + test('set operations (except) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const result = await db + .select() + .from(citiesTable).except( + db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + + expect(result).toHaveLength(1); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + ]); + }); + + test('set operations (except) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = await except( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable), + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).as('sq'); + + const result = await db.select().from(sq).limit(3); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await expect((async () => { + except( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable), + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(3); + })()).rejects.toThrowError(); + }); + + test('set operations (mixed) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq1 = unionAll( + db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + db.select().from(citiesTable).where(eq(citiesTable.id, 2)), + ).as('sq1'); + + const sq2 = await db.select().from(sq1).orderBy(asc(sql`id`)).as('sq2'); + + const sq3 = await db.select().from(sq2).limit(1).offset(1).as('sq3'); + + const result = await db + .select() + .from(citiesTable) + .except( + db + .select() + .from(sq3), + ); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 3, name: 'Tampa' }, + { id: 1, name: 'New York' }, + ]); + + await expect((async () => { + db + .select() + .from(citiesTable).except( + ({ unionAll }) => + unionAll( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + db.select().from(citiesTable).where(eq(citiesTable.id, 2)), + ), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (mixed all) as function with subquery', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq1 = except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 7)), + ).as('sq1'); + + const sq2 = await db.select().from(sq1).orderBy(asc(sql`id`)).as('sq2'); + + const sq3 = await db.select().from(sq2).limit(1).as('sq3'); + + const result = await union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db.select().from(sq3), + db + .select().from(citiesTable).where(gt(citiesTable.id, 1)), + ); + + expect(result).toHaveLength(4); + + // multiple results possible as a result of the filters >= 5 and ==7 because singlestore doesn't guarantee order + // dynamically validate results + const hasValidEntry = (entry: { id: number; name: string }) => { + if (entry.id === 1) return entry.name === 'John'; + if (entry.id > 1 && entry.id < 5) return entry.name === 'Tampa' || entry.name === 'London'; + if (entry.id >= 5 && entry.id !== 7) return true; // Accept any entry with id >= 5 and not 7 + return false; + }; + + for (const entry of result) { + expect(hasValidEntry(entry)).toBe(true); + } + + await expect((async () => { + union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 7)), + ).limit(1), + db + .select().from(citiesTable).where(gt(citiesTable.id, 1)), + ); + })()).rejects.toThrowError(); + }); + + test('aggregate function: count', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: count() }).from(table); + const result2 = await db.select({ value: count(table.a) }).from(table); + const result3 = await db.select({ value: countDistinct(table.name) }).from(table); + + expect(result1[0]?.value).toBe(7); + expect(result2[0]?.value).toBe(5); + expect(result3[0]?.value).toBe(6); + }); + + test('aggregate function: avg', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: avg(table.b) }).from(table); + const result2 = await db.select({ value: avg(table.nullOnly) }).from(table); + const result3 = await db.select({ value: avgDistinct(table.b) }).from(table); + + expect(result1[0]?.value).toBe('33.3333'); + expect(result2[0]?.value).toBe(null); + expect(result3[0]?.value).toBe('42.5000'); + }); + + test('aggregate function: sum', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: sum(table.b) }).from(table); + const result2 = await db.select({ value: sum(table.nullOnly) }).from(table); + const result3 = await db.select({ value: sumDistinct(table.b) }).from(table); + + expect(result1[0]?.value).toBe('200'); + expect(result2[0]?.value).toBe(null); + expect(result3[0]?.value).toBe('170'); + }); + + test('aggregate function: max', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: max(table.b) }).from(table); + const result2 = await db.select({ value: max(table.nullOnly) }).from(table); + + expect(result1[0]?.value).toBe(90); + expect(result2[0]?.value).toBe(null); + }); + + test('aggregate function: min', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: min(table.b) }).from(table); + const result2 = await db.select({ value: min(table.nullOnly) }).from(table); + + expect(result1[0]?.value).toBe(10); + expect(result2[0]?.value).toBe(null); + }); + + test('test $onUpdateFn and $onUpdate works as $default', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists ${usersOnUpdate}`); + + await db.execute( + sql` + create table ${usersOnUpdate} ( + id serial not null primary key, + name text not null, + update_counter integer default 1 not null, + updated_at datetime(6), + always_null text + ) + `, + ); + + await db.insert(usersOnUpdate).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Jack' }, + { id: 4, name: 'Jill' }, + ]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + + const justDates = await db.select({ updatedAt }).from(usersOnUpdate); + + const response = await db.select({ ...rest }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + expect(response).toEqual([ + { name: 'John', id: 1, updateCounter: 1, alwaysNull: null }, + { name: 'Jane', id: 2, updateCounter: 1, alwaysNull: null }, + { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, + { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, + ]); + const msDelay = 750; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); + } + }); + + test('test $onUpdateFn and $onUpdate works updating', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists ${usersOnUpdate}`); + + await db.execute( + sql` + create table ${usersOnUpdate} ( + id serial not null primary key, + name text not null, + update_counter integer default 1 not null, + updated_at datetime(6), + always_null text + ) + `, + ); + + await db.insert(usersOnUpdate).values([ + { id: 1, name: 'John', alwaysNull: 'this will will be null after updating' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Jack' }, + { id: 4, name: 'Jill' }, + ]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + const initial = await db.select({ id: usersOnUpdate.id, updatedAt: usersOnUpdate.updatedAt }).from(usersOnUpdate); + + await db.update(usersOnUpdate).set({ name: 'Angel' }).where(eq(usersOnUpdate.id, 1)); + + const justDates = await db.select({ id: usersOnUpdate.id, updatedAt: usersOnUpdate.updatedAt }).from( + usersOnUpdate, + ); + + const response = await db.select().from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + expect(response).toEqual([ + { id: 1, name: 'Angel', updateCounter: 2, updatedAt: expect.any(Date), alwaysNull: null }, + { id: 2, name: 'Jane', updateCounter: 1, updatedAt: expect.any(Date), alwaysNull: null }, + { id: 3, name: 'Jack', updateCounter: 1, updatedAt: expect.any(Date), alwaysNull: null }, + { id: 4, name: 'Jill', updateCounter: 1, updatedAt: expect.any(Date), alwaysNull: null }, + ]); + + const initialRecord = initial.find((record) => record.id === 1); + const updatedRecord = justDates.find((record) => record.id === 1); + + expect(initialRecord?.updatedAt?.valueOf()).not.toBe(updatedRecord?.updatedAt?.valueOf()); + + const msDelay = 1000; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); + } + }); + + // mySchema tests + test('mySchema :: select all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersMySchemaTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('mySchema :: select sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersMySchemaTable.name})`, + }).from(usersMySchemaTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('mySchema :: select typed sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersMySchemaTable.name})`, + }).from(usersMySchemaTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('mySchema :: select distinct', async (ctx) => { + const { db } = ctx.singlestore; + + const usersDistinctTable = singlestoreTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${usersDistinctTable}`); + await db.execute(sql`create table ${usersDistinctTable} (id int, name text)`); + + await db.insert(usersDistinctTable).values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]); + const users = await db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ); + + await db.execute(sql`drop table ${usersDistinctTable}`); + + expect(users).toEqual([{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); + }); + + test('mySchema :: insert returning sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + const [result, _] = await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); + }); + + test('mySchema :: delete returning sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const users = await db.delete(usersMySchemaTable).where(eq(usersMySchemaTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); + }); + + test('mySchema :: update with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersMySchemaTable).set({ name: 'Jane' }).where( + eq(usersMySchemaTable.name, 'John'), + ); + + const users = await db.select({ id: usersMySchemaTable.id, name: usersMySchemaTable.name }).from( + usersMySchemaTable, + ) + .where( + eq(usersMySchemaTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); + }); + + test('mySchema :: delete with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersMySchemaTable).where(eq(usersMySchemaTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); + }); + + test('mySchema :: insert + select', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersMySchemaTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersMySchemaTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersMySchemaTable).orderBy(asc(usersMySchemaTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); + }); + + test('mySchema :: insert with overridden default values', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersMySchemaTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('mySchema :: insert many', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersMySchemaTable.id, + name: usersMySchemaTable.name, + jsonb: usersMySchemaTable.jsonb, + verified: usersMySchemaTable.verified, + }).from(usersMySchemaTable) + .orderBy(asc(usersMySchemaTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); + }); + + test('mySchema :: select with group by as field', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { + id: 3, + name: 'Jane', + }]); + + const result = await db.select({ name: usersMySchemaTable.name }).from(usersMySchemaTable) + .groupBy(usersMySchemaTable.name) + .orderBy(asc(usersMySchemaTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); + }); + + test('mySchema :: select with group by as column + sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { + id: 3, + name: 'Jane', + }]); + + const result = await db.select({ name: usersMySchemaTable.name }).from(usersMySchemaTable) + .groupBy(usersMySchemaTable.id, sql`${usersMySchemaTable.name}`) + .orderBy(asc(usersMySchemaTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + }); + + test('mySchema :: build query', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ id: usersMySchemaTable.id, name: usersMySchemaTable.name }).from(usersMySchemaTable) + .groupBy(usersMySchemaTable.id, usersMySchemaTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: + `select \`id\`, \`name\` from \`mySchema\`.\`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + params: [], + }); + }); + + test('mySchema :: insert with spaces', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersMySchemaTable.id, name: usersMySchemaTable.name }).from( + usersMySchemaTable, + ); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); + }); + + test('mySchema :: prepared statement with placeholder in .where', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersMySchemaTable.id, + name: usersMySchemaTable.name, + }).from(usersMySchemaTable) + .where(eq(usersMySchemaTable.id, sql.placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('mySchema :: select from tables with same name from different schema using alias', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.execute(sql`drop table if exists \`userstest\``); + await db.execute( + sql` + create table \`userstest\` ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.insert(usersMySchemaTable).values({ id: 10, name: 'Ivan' }); + await db.insert(usersTable).values({ id: 11, name: 'Hans' }); + + const customerAlias = alias(usersTable, 'customer'); + + const result = await db + .select().from(usersMySchemaTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersMySchemaTable.id, 10)); + + expect(result).toEqual([{ + userstest: { + id: 10, + name: 'Ivan', + verified: false, + jsonb: null, + createdAt: result[0]!.userstest.createdAt, + }, + customer: { + id: 11, + name: 'Hans', + verified: false, + jsonb: null, + createdAt: result[0]!.customer!.createdAt, + }, + }]); + }); + + test('insert $returningId: serial as id', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values({ id: 1, name: 'John' }).$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + id: number; + }[]>(); + + expect(result).toStrictEqual([{ id: 1 }]); + }); + + test('insert $returningId: serial as id, batch insert', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'John1' }]) + .$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + id: number; + }[]>(); + + // singlestore auto increments when batch inserting, so the ids increment by one + expect(result).toStrictEqual([{ id: 2 }, { id: 3 }]); + }); + + test('insert $returningId: $default as primary key', async (ctx) => { + const { db } = ctx.singlestore; + + const uniqueKeys = ['ao865jf3mcmkfkk8o5ri495z', 'dyqs529eom0iczo2efxzbcut']; + let iterator = 0; + + const usersTableDefFn = singlestoreTable('users_default_fn', { + customId: varchar('id', { length: 256 }).primaryKey().$defaultFn(() => { + const value = uniqueKeys[iterator]!; + iterator++; + return value; + }), + name: text('name').notNull(), + }); + + await setupReturningFunctionsTest(db); + + const result = await db.insert(usersTableDefFn).values([{ name: 'John' }, { name: 'John1' }]) + // ^? + .$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + customId: string; + }[]>(); + + expect(result).toStrictEqual([{ customId: 'ao865jf3mcmkfkk8o5ri495z' }, { + customId: 'dyqs529eom0iczo2efxzbcut', + }]); + }); + + test('insert $returningId: $default as primary key with value', async (ctx) => { + const { db } = ctx.singlestore; + + const uniqueKeys = ['ao865jf3mcmkfkk8o5ri495z', 'dyqs529eom0iczo2efxzbcut']; + let iterator = 0; + + const usersTableDefFn = singlestoreTable('users_default_fn', { + customId: varchar('id', { length: 256 }).primaryKey().$defaultFn(() => { + const value = uniqueKeys[iterator]!; + iterator++; + return value; + }), + name: text('name').notNull(), + }); + + await setupReturningFunctionsTest(db); + + const result = await db.insert(usersTableDefFn).values([{ name: 'John', customId: 'test' }, { name: 'John1' }]) + // ^? + .$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + customId: string; + }[]>(); + + expect(result).toStrictEqual([{ customId: 'test' }, { customId: 'ao865jf3mcmkfkk8o5ri495z' }]); + }); + + test('mySchema :: view', async (ctx) => { + const { db } = ctx.singlestore; + + const newYorkers1 = mySchema.view('new_yorkers') + .as((qb) => qb.select().from(users2MySchemaTable).where(eq(users2MySchemaTable.cityId, 1))); + + const newYorkers2 = mySchema.view('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).as(sql`select * from ${users2MySchemaTable} where ${eq(users2MySchemaTable.cityId, 1)}`); + + const newYorkers3 = mySchema.view('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).existing(); + + await db.execute(sql`create view ${newYorkers1} as ${getViewConfig(newYorkers1).query}`); + + await db.insert(citiesMySchemaTable).values([{ id: 1, name: 'New York' }, { id: 2, name: 'Paris' }]); + + await db.insert(users2MySchemaTable).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2).orderBy(asc(newYorkers2.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3).orderBy(asc(newYorkers3.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop view ${newYorkers1}`); + }); + + test('limit 0', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .select() + .from(usersTable) + .limit(0); + + expect(users).toEqual([]); + }); + + test('limit -1', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .select() + .from(usersTable) + .limit(-1); + + expect(users.length).toBeGreaterThan(0); + }); + }); +} diff --git a/integration-tests/tests/singlestore/singlestore-custom.test.ts b/integration-tests/tests/singlestore/singlestore-custom.test.ts new file mode 100644 index 000000000..b05cd756b --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-custom.test.ts @@ -0,0 +1,827 @@ +import retry from 'async-retry'; +import type Docker from 'dockerode'; +import { asc, eq, Name, placeholder, sql } from 'drizzle-orm'; +import type { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +import { drizzle } from 'drizzle-orm/singlestore'; +import { + alias, + binary, + customType, + date, + datetime, + serial, + singlestoreEnum, + singlestoreTable, + singlestoreTableCreator, + text, + time, + varchar, + year, +} from 'drizzle-orm/singlestore-core'; +import { migrate } from 'drizzle-orm/singlestore/migrator'; +import * as mysql2 from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { toLocalDate } from '~/utils'; +import { createDockerDB } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +let db: SingleStoreDriverDatabase; +let client: mysql2.Connection; +let container: Docker.Container | undefined; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr, container: contrainerObj } = await createDockerDB(); + connectionString = conStr; + container = contrainerObj; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); + await container?.stop().catch(console.error); +}); + +beforeEach((ctx) => { + ctx.singlestore = { + db, + }; +}); + +const customSerial = customType<{ data: number; notNull: true; default: true }>({ + dataType() { + return 'serial'; + }, +}); + +const customText = customType<{ data: string }>({ + dataType() { + return 'text'; + }, +}); + +const customBoolean = customType<{ data: boolean }>({ + dataType() { + return 'boolean'; + }, + fromDriver(value) { + if (typeof value === 'boolean') { + return value; + } + return value === 1; + }, +}); + +const customJson = (name: string) => + customType<{ data: TData; driverData: string }>({ + dataType() { + return 'json'; + }, + toDriver(value: TData): string { + return JSON.stringify(value); + }, + })(name); + +const customTimestamp = customType< + { data: Date; driverData: string; config: { fsp: number } } +>({ + dataType(config) { + const precision = config?.fsp === undefined ? '' : ` (${config.fsp})`; + return `timestamp${precision}`; + }, + fromDriver(value: string): Date { + return new Date(value); + }, +}); + +const customBinary = customType<{ data: string; driverData: Buffer; config: { length: number } }>({ + dataType(config) { + return config?.length === undefined + ? `binary` + : `binary(${config.length})`; + }, + + toDriver(value) { + return sql`UNHEX(${value})`; + }, + + fromDriver(value) { + return value.toString('hex'); + }, +}); + +const usersTable = singlestoreTable('userstest', { + id: customSerial('id').primaryKey(), + name: customText('name').notNull(), + verified: customBoolean('verified').notNull().default(false), + jsonb: customJson('jsonb'), + createdAt: customTimestamp('created_at', { fsp: 6 }).notNull().default(sql`now()`), +}); + +const datesTable = singlestoreTable('datestable', { + date: date('date'), + dateAsString: date('date_as_string', { mode: 'string' }), + time: time('time', { fsp: 1 }), + datetime: datetime('datetime', { fsp: 6 }), + datetimeAsString: datetime('datetime_as_string', { fsp: 6, mode: 'string' }), + year: year('year'), +}); + +export const testTable = singlestoreTable('test_table', { + id: customBinary('id', { length: 16 }).primaryKey(), + sqlId: binary('sql_id', { length: 16 }), + rawId: varchar('raw_id', { length: 64 }), +}); + +const usersMigratorTable = singlestoreTable('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}); + +beforeEach(async () => { + await db.execute(sql`drop table if exists \`userstest\``); + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute(sql`drop table if exists \`test_table\``); + // await ctx.db.execute(sql`create schema public`); + await db.execute( + sql` + create table \`userstest\` ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table \`datestable\` ( + \`date\` date, + \`date_as_string\` date, + \`time\` time, + \`datetime\` datetime, + \`datetime_as_string\` datetime, + \`year\` year + ) + `, + ); + + await db.execute( + sql` + create table \`test_table\` ( + \`id\` binary(16) primary key, + \`sql_id\` binary(16), + \`raw_id\` varchar(64) + ) + `, + ); +}); + +test('select all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('select sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('select typed sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('insert returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + const [result, _] = await db.insert(usersTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); +}); + +test('delete returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); +}); + +test('update returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + expect(users[0].changedRows).toBe(1); +}); + +test('update with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select().from(usersTable).where(eq(usersTable.id, 1)); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 2000); + expect(users).toEqual([{ id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); +}); + +test('update with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); +}); + +test('delete with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('delete with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('insert + select', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); +}); + +test('json insert', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); +}); + +test('insert with overridden default values', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('insert many', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }).from(usersTable).orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); +}); + +test('insert many with returning', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + + expect(result[0].affectedRows).toBe(4); +}); + +test('select with group by as field', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.name).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql + column', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by as column + sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by complex query', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + expect(result).toEqual([{ name: 'Jane' }]); +}); + +test('build query', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: `select \`id\`, \`name\` from \`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + params: [], + }); +}); + +test('build query insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }) + .toSQL(); + + expect(query).toEqual({ + sql: + 'insert into `userstest` (`id`, `name`, `verified`, `jsonb`, `created_at`) values (default, ?, default, ?, default) on duplicate key update `name` = ?', + params: ['John', '["foo","bar"]', 'John1'], + }); +}); + +test('insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John1' }]); +}); + +test('insert conflict', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await expect((async () => { + db.insert(usersTable).values({ id: 1, name: 'John1' }); + })()).resolves.not.toThrowError(); +}); + +test('insert conflict with ignore', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .ignore() + .values({ id: 1, name: 'John1' }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`${'John'}` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('partial join with alias', async (ctx) => { + const { db } = ctx.singlestore; + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }).from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }]); +}); + +test('full join with alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select().from(users) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(users.id, 10)) + .orderBy(asc(users.id)); + + expect(result).toEqual([{ + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('select from alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(user) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(user.id, 10)) + .orderBy(asc(user.id)); + + expect(result).toEqual([{ + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('insert with spaces', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); +}); + +test('prepared statement', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const statement = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .prepare(); + const result = await statement.execute(); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('prepared statement reuse', async (ctx) => { + const { db } = ctx.singlestore; + + const stmt = db.insert(usersTable).values({ + id: placeholder('id'), + verified: true, + name: placeholder('name'), + }).prepare(); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ id: i + 1, name: `John ${i}` }); + } + + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }).from(usersTable).orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); +}); + +test('prepared statement with placeholder in .where', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .where(eq(usersTable.id, placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('migrator', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists cities_migration`); + await db.execute(sql`drop table if exists users_migration`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists __drizzle_migrations`); + + await migrate(db, { migrationsFolder: './drizzle2/singlestore' }); + + await db.insert(usersMigratorTable).values({ id: 1, name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table cities_migration`); + await db.execute(sql`drop table users_migration`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table __drizzle_migrations`); +}); + +test('insert via db.execute + select via db.execute', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute( + sql`insert into ${usersTable} (${new Name(usersTable.id.name)}, ${new Name( + usersTable.name.name, + )}) values (1,${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>(sql`select id, name from ${usersTable}`); + expect(result[0]).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert via db.execute w/ query builder', async (ctx) => { + const { db } = ctx.singlestore; + + const inserted = await db.execute( + db.insert(usersTable).values({ name: 'John' }), + ); + expect(inserted[0].affectedRows).toBe(1); +}); + +test('insert + select all possible dates', async (ctx) => { + const { db } = ctx.singlestore; + + const date = new Date('2022-11-11'); + + await db.insert(datesTable).values({ + date: date, + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: date, + year: 22, + datetimeAsString: '2022-11-11 12:12:12', + }); + + const res = await db.select().from(datesTable); + + expect(res[0]?.date).toBeInstanceOf(Date); + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(res[0]?.dateAsString).toBeTypeOf('string'); + expect(res[0]?.datetimeAsString).toBeTypeOf('string'); + + expect(res).toEqual([{ + date: toLocalDate(new Date('2022-11-11')), + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: new Date('2022-11-11'), + year: 2022, + datetimeAsString: '2022-11-11 12:12:12', + }]); +}); + +const tableWithEnums = singlestoreTable('enums_test_case', { + id: serial('id').primaryKey(), + enum1: singlestoreEnum('enum1', ['a', 'b', 'c']).notNull(), + enum2: singlestoreEnum('enum2', ['a', 'b', 'c']).default('a'), + enum3: singlestoreEnum('enum3', ['a', 'b', 'c']).notNull().default('b'), +}); + +test('SingleStore enum test case #1', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`enums_test_case\``); + + await db.execute(sql` + create table \`enums_test_case\` ( + \`id\` serial primary key, + \`enum1\` ENUM('a', 'b', 'c') not null, + \`enum2\` ENUM('a', 'b', 'c') default 'a', + \`enum3\` ENUM('a', 'b', 'c') not null default 'b' + ) + `); + + await db.insert(tableWithEnums).values([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum3: 'c' }, + { id: 3, enum1: 'a' }, + ]); + + const res = await db.select().from(tableWithEnums).orderBy(asc(tableWithEnums.id)); + + await db.execute(sql`drop table \`enums_test_case\``); + + expect(res).toEqual([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum2: 'a', enum3: 'c' }, + { id: 3, enum1: 'a', enum2: 'a', enum3: 'b' }, + ]); +}); + +test('custom binary', async (ctx) => { + const { db } = ctx.singlestore; + + const id = uuid().replace(/-/g, ''); + await db.insert(testTable).values({ + id, + sqlId: sql`UNHEX(${id})`, + rawId: id, + }); + + const res = await db.select().from(testTable); + + expect(res).toEqual([{ + id, + sqlId: Buffer.from(id, 'hex'), + rawId: id, + }]); +}); diff --git a/integration-tests/tests/singlestore/singlestore-prefixed.test.ts b/integration-tests/tests/singlestore/singlestore-prefixed.test.ts new file mode 100644 index 000000000..224ad433d --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-prefixed.test.ts @@ -0,0 +1,1572 @@ +import retry from 'async-retry'; +import type Docker from 'dockerode'; +import type { Equal } from 'drizzle-orm'; +import { asc, eq, getTableName, gt, inArray, Name, sql, TransactionRollbackError } from 'drizzle-orm'; +import type { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +import { drizzle } from 'drizzle-orm/singlestore'; +import { + alias, + boolean, + date, + datetime, + getViewConfig, + int, + json, + serial, + singlestoreEnum, + singlestoreTable as singlestoreTableRaw, + singlestoreTableCreator, + singlestoreView, + text, + time, + timestamp, + uniqueIndex, + year, +} from 'drizzle-orm/singlestore-core'; +import { migrate } from 'drizzle-orm/singlestore/migrator'; +import * as mysql2 from 'mysql2/promise'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { Expect, toLocalDate } from '~/utils'; +import { createDockerDB } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +let db: SingleStoreDriverDatabase; +let client: mysql2.Connection; +let container: Docker.Container | undefined; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr, container: contrainerObj } = await createDockerDB(); + connectionString = conStr; + container = contrainerObj; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); + await container?.stop().catch(console.error); +}); + +const tablePrefix = 'drizzle_tests_'; + +const singlestoreTable = singlestoreTableCreator((name) => `${tablePrefix}${name}`); +const usersTable = singlestoreTable('userstest', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: json('jsonb').$type(), + createdAt: timestamp('created_at', { fsp: 6 }).notNull().defaultNow(), +}); + +const users2Table = singlestoreTable('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id'), +}); + +const citiesTable = singlestoreTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +beforeEach(async () => { + await db.execute(sql`drop table if exists ${usersTable}`); + await db.execute(sql`drop table if exists ${users2Table}`); + await db.execute(sql`drop table if exists ${citiesTable}`); + + await db.execute( + sql` + create table ${usersTable} ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table ${users2Table} ( + \`id\` serial primary key, + \`name\` text not null, + \`city_id\` int + ) + `, + ); + + await db.execute( + sql` + create table ${citiesTable} ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); +}); + +test('select all fields', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('select sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('select typed sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('select distinct', async () => { + const usersDistinctTable = singlestoreTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${usersDistinctTable}`); + await db.execute(sql`create table ${usersDistinctTable} (id int, name text)`); + + await db.insert(usersDistinctTable).values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]); + const users = await db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ); + + await db.execute(sql`drop table ${usersDistinctTable}`); + + expect(users).toEqual([{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); +}); + +test('insert returning sql', async () => { + const [result, _] = await db.insert(usersTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); +}); + +test('delete returning sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); +}); + +test('update returning sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + expect(users[0].changedRows).toBe(1); +}); + +test('update with returning all fields', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select().from(usersTable).where(eq(usersTable.id, 1)); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 2000); + expect(users).toEqual([{ id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); +}); + +test('update with returning partial', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); +}); + +test('delete with returning all fields', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('delete with returning partial', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('insert + select', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); +}); + +test('json insert', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); +}); + +test('insert with overridden default values', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('insert many', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); +}); + +test('insert many with returning', async () => { + const result = await db.insert(usersTable).values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + + expect(result[0].affectedRows).toBe(4); +}); + +test('select with group by as field', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.name) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql + column', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by as column + sql', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by complex query', async () => { + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + expect(result).toEqual([{ name: 'Jane' }]); +}); + +test('build query', async () => { + const query = db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: `select \`id\`, \`name\` from \`${getTableName(usersTable)}\` group by \`${ + getTableName(usersTable) + }\`.\`id\`, \`${getTableName(usersTable)}\`.\`name\``, + params: [], + }); +}); + +test('build query insert with onDuplicate', async () => { + const query = db.insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }) + .toSQL(); + + expect(query).toEqual({ + sql: `insert into \`${ + getTableName(usersTable) + }\` (\`id\`, \`name\`, \`verified\`, \`jsonb\`, \`created_at\`) values (default, ?, default, ?, default) on duplicate key update \`name\` = ?`, + params: ['John', '["foo","bar"]', 'John1'], + }); +}); + +test('insert with onDuplicate', async () => { + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John1' }]); +}); + +test('insert conflict', async () => { + await db.insert(usersTable) + .values({ name: 'John' }); + + await expect((async () => { + db.insert(usersTable).values({ id: 1, name: 'John1' }); + })()).resolves.not.toThrowError(); +}); + +test('insert conflict with ignore', async () => { + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .ignore() + .values({ id: 1, name: 'John1' }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert sql', async () => { + await db.insert(usersTable).values({ id: 1, name: sql`${'John'}` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('partial join with alias', async () => { + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }).from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }]); +}); + +test('full join with alias', async () => { + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select().from(users) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(users.id, 10)) + .orderBy(asc(users.id)); + + expect(result).toEqual([{ + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('select from alias', async () => { + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(user) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(user.id, 10)) + .orderBy(asc(user.id)); + + expect(result).toEqual([{ + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('insert with spaces', async () => { + await db.insert(usersTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); +}); + +test('prepared statement', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const statement = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .prepare(); + const result = await statement.execute(); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('prepared statement reuse', async () => { + const stmt = db.insert(usersTable).values({ + verified: true, + id: sql.placeholder('id'), + name: sql.placeholder('name'), + }).prepare(); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ id: i + 1, name: `John ${i}` }); + } + + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); +}); + +test('prepared statement with placeholder in .where', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('migrator', async () => { + const usersMigratorTable = singlestoreTableRaw('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), + }, (table) => { + return { + name: uniqueIndex('').on(table.name).using('btree'), + }; + }); + + await db.execute(sql.raw(`drop table if exists cities_migration`)); + await db.execute(sql.raw(`drop table if exists users_migration`)); + await db.execute(sql.raw(`drop table if exists users12`)); + await db.execute(sql.raw(`drop table if exists __drizzle_migrations`)); + + await migrate(db, { migrationsFolder: './drizzle2/singlestore' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql.raw(`drop table cities_migration`)); + await db.execute(sql.raw(`drop table users_migration`)); + await db.execute(sql.raw(`drop table users12`)); + await db.execute(sql.raw(`drop table __drizzle_migrations`)); +}); + +test('insert via db.execute + select via db.execute', async () => { + await db.execute( + sql`insert into ${usersTable} (${new Name(usersTable.id.name)}, ${new Name( + usersTable.name.name, + )}) values (1, ${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>(sql`select id, name from ${usersTable}`); + expect(result[0]).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert via db.execute w/ query builder', async () => { + const inserted = await db.execute( + db.insert(usersTable).values({ name: 'John' }), + ); + expect(inserted[0].affectedRows).toBe(1); +}); + +test('insert + select all possible dates', async () => { + const datesTable = singlestoreTable('datestable', { + date: date('date'), + dateAsString: date('date_as_string', { mode: 'string' }), + time: time('time', { fsp: 1 }), + datetime: datetime('datetime', { fsp: 6 }), + datetimeAsString: datetime('datetime_as_string', { fsp: 6, mode: 'string' }), + year: year('year'), + }); + + await db.execute(sql`drop table if exists ${datesTable}`); + await db.execute( + sql` + create table ${datesTable} ( + \`date\` date, + \`date_as_string\` date, + \`time\` time, + \`datetime\` datetime, + \`datetime_as_string\` datetime, + \`year\` year + ) + `, + ); + + const d = new Date('2022-11-11'); + + await db.insert(datesTable).values({ + date: d, + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: d, + year: 22, + datetimeAsString: '2022-11-11 12:12:12', + }); + + const res = await db.select().from(datesTable); + + expect(res[0]?.date).toBeInstanceOf(Date); + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(typeof res[0]?.dateAsString).toBe('string'); + expect(typeof res[0]?.datetimeAsString).toBe('string'); + + expect(res).toEqual([{ + date: toLocalDate(new Date('2022-11-11')), + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: new Date('2022-11-11'), + year: 2022, + datetimeAsString: '2022-11-11 12:12:12', + }]); + + await db.execute(sql`drop table ${datesTable}`); +}); + +test('SingleStore enum test case #1', async () => { + const tableWithEnums = singlestoreTable('enums_test_case', { + id: serial('id').primaryKey(), + enum1: singlestoreEnum('enum1', ['a', 'b', 'c']).notNull(), + enum2: singlestoreEnum('enum2', ['a', 'b', 'c']).default('a'), + enum3: singlestoreEnum('enum3', ['a', 'b', 'c']).notNull().default('b'), + }); + + await db.execute(sql`drop table if exists ${tableWithEnums}`); + + await db.execute(sql` + create table ${tableWithEnums} ( + \`id\` serial primary key, + \`enum1\` ENUM('a', 'b', 'c') not null, + \`enum2\` ENUM('a', 'b', 'c') default 'a', + \`enum3\` ENUM('a', 'b', 'c') not null default 'b' + ) + `); + + await db.insert(tableWithEnums).values([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum3: 'c' }, + { id: 3, enum1: 'a' }, + ]); + + const res = await db.select().from(tableWithEnums).orderBy(asc(tableWithEnums.id)); + + await db.execute(sql`drop table ${tableWithEnums}`); + + expect(res).toEqual([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum2: 'a', enum3: 'c' }, + { id: 3, enum1: 'a', enum2: 'a', enum3: 'b' }, + ]); +}); + +test('left join (flat object fields)', async () => { + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + userId: users2Table.id, + userName: users2Table.name, + cityId: citiesTable.id, + cityName: citiesTable.name, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { userId: 1, userName: 'John', cityId: 1, cityName: 'Paris' }, + { userId: 2, userName: 'Jane', cityId: null, cityName: null }, + ]); +}); + +test('left join (grouped fields)', async () => { + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + id: users2Table.id, + user: { + name: users2Table.name, + nameUpper: sql`upper(${users2Table.name})`, + }, + city: { + id: citiesTable.id, + name: citiesTable.name, + nameUpper: sql`upper(${citiesTable.name})`, + }, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + id: 1, + user: { name: 'John', nameUpper: 'JOHN' }, + city: { id: 1, name: 'Paris', nameUpper: 'PARIS' }, + }, + { + id: 2, + user: { name: 'Jane', nameUpper: 'JANE' }, + city: null, + }, + ]); +}); + +test('left join (all fields)', async () => { + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select().from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + users2: { + id: 1, + name: 'John', + cityId: 1, + }, + cities: { + id: 1, + name: 'Paris', + }, + }, + { + users2: { + id: 2, + name: 'Jane', + cityId: null, + }, + cities: null, + }, + ]); +}); + +test('join subquery', async () => { + const coursesTable = singlestoreTable('courses', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + categoryId: int('category_id'), + }); + + const courseCategoriesTable = singlestoreTable('course_categories', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${coursesTable}`); + await db.execute(sql`drop table if exists ${courseCategoriesTable}`); + + await db.execute( + sql` + create table ${courseCategoriesTable} ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.execute( + sql` + create table ${coursesTable} ( + \`id\` serial primary key, + \`name\` text not null, + \`category_id\` int + ) + `, + ); + + await db.insert(courseCategoriesTable).values([ + { id: 1, name: 'Category 1' }, + { id: 2, name: 'Category 2' }, + { id: 3, name: 'Category 3' }, + { id: 4, name: 'Category 4' }, + ]); + + await db.insert(coursesTable).values([ + { id: 1, name: 'Development', categoryId: 2 }, + { id: 2, name: 'IT & Software', categoryId: 3 }, + { id: 3, name: 'Marketing', categoryId: 4 }, + { id: 4, name: 'Design', categoryId: 1 }, + ]); + + const sq2 = db + .select({ + categoryId: courseCategoriesTable.id, + category: courseCategoriesTable.name, + total: sql`count(${courseCategoriesTable.id})`, + }) + .from(courseCategoriesTable) + .groupBy(courseCategoriesTable.id, courseCategoriesTable.name) + .orderBy(courseCategoriesTable.id) + .as('sq2'); + + const res = await db + .select({ + courseName: coursesTable.name, + categoryId: sq2.categoryId, + }) + .from(coursesTable) + .leftJoin(sq2, eq(coursesTable.categoryId, sq2.categoryId)) + .orderBy(coursesTable.name); + + await db.execute(sql`drop table ${coursesTable}`); + await db.execute(sql`drop table ${courseCategoriesTable}`); + + expect(res).toEqual([ + { courseName: 'Design', categoryId: 1 }, + { courseName: 'Development', categoryId: 2 }, + { courseName: 'IT & Software', categoryId: 3 }, + { courseName: 'Marketing', categoryId: 4 }, + ]); +}); + +test('with ... select', async () => { + const orders = singlestoreTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull(), + amount: int('amount').notNull(), + quantity: int('quantity').notNull(), + }); + + await db.execute(sql`drop table if exists ${orders}`); + await db.execute( + sql` + create table ${orders} ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: regionalSales.region, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`cast(sum(${orders.quantity}) as unsigned)`, + productSales: sql`cast(sum(${orders.amount}) as unsigned)`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))) + .groupBy(orders.region, orders.product) + .orderBy(orders.region, orders.product); + + await db.execute(sql`drop table ${orders}`); + + expect(result).toEqual([ + { + region: 'Europe', + product: 'A', + productUnits: 3, + productSales: 30, + }, + { + region: 'Europe', + product: 'B', + productUnits: 5, + productSales: 50, + }, + { + region: 'US', + product: 'A', + productUnits: 7, + productSales: 70, + }, + { + region: 'US', + product: 'B', + productUnits: 9, + productSales: 90, + }, + ]); +}); + +test('select from subquery sql', async () => { + await db.insert(users2Table).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]); + + const sq = db + .select({ name: sql`concat(${users2Table.name}, " modified")`.as('name') }) + .from(users2Table) + .orderBy(asc(users2Table.id)) + .as('sq'); + + const res = await db.select({ name: sq.name }).from(sq); + + expect(res).toEqual([{ name: 'John modified' }, { name: 'Jane modified' }]); +}); + +test('select a field without joining its table', () => { + expect(() => db.select({ name: users2Table.name }).from(usersTable).prepare()).toThrowError(); +}); + +test('select all fields from subquery without alias', () => { + const sq = db.$with('sq').as(db.select({ name: sql`upper(${users2Table.name})` }).from(users2Table)); + + expect(() => db.select().from(sq).prepare()).toThrowError(); +}); + +test('select count()', async () => { + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }]); + + const res = await db.select({ count: sql`count(*)` }).from(usersTable); + + expect(res).toEqual([{ count: 2 }]); +}); + +test('select for ...', () => { + { + const query = db.select().from(users2Table).for('update').toSQL(); + expect(query.sql).toMatch(/ for update$/); + } + { + const query = db.select().from(users2Table).for('share', { skipLocked: true }).toSQL(); + expect(query.sql).toMatch(/ for share skip locked$/); + } + { + const query = db.select().from(users2Table).for('update', { noWait: true }).toSQL(); + expect(query.sql).toMatch(/ for update no wait$/); + } +}); + +test('having', async () => { + await db.insert(citiesTable).values([{ id: 1, name: 'London' }, { id: 2, name: 'Paris' }, { + id: 3, + name: 'New York', + }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane', cityId: 1 }, { + id: 3, + name: 'Jack', + cityId: 2, + }]); + + const result = await db + .select({ + id: citiesTable.id, + name: sql`upper(${citiesTable.name})`.as('upper_name'), + usersCount: sql`count(${users2Table.id})`.as('users_count'), + }) + .from(citiesTable) + .leftJoin(users2Table, eq(users2Table.cityId, citiesTable.id)) + .where(({ name }) => sql`length(${name}) >= 3`) + .groupBy(citiesTable.id) + .having(({ usersCount }) => sql`${usersCount} > 0`) + .orderBy(({ name }) => name); + + expect(result).toEqual([ + { + id: 1, + name: 'LONDON', + usersCount: 2, + }, + { + id: 2, + name: 'PARIS', + usersCount: 1, + }, + ]); +}); + +test('view', async () => { + const newYorkers1 = singlestoreView('new_yorkers') + .as((qb) => qb.select().from(users2Table).where(eq(users2Table.cityId, 1))); + + const newYorkers2 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).as(sql`select * from ${users2Table} where ${eq(users2Table.cityId, 1)}`); + + const newYorkers3 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).existing(); + + await db.execute(sql`create view new_yorkers as ${getViewConfig(newYorkers1).query}`); + + await db.insert(citiesTable).values([{ name: 'New York' }, { name: 'Paris' }]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2).orderBy(asc(newYorkers2.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3).orderBy(asc(newYorkers3.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop view ${newYorkers1}`); +}); + +test('select from raw sql', async () => { + const result = await db.select({ + id: sql`id`, + name: sql`name`, + }).from(sql`(select 1 as id, 'John' as name) as users`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John' }, + ]); +}); + +test('select from raw sql with joins', async () => { + const result = await db + .select({ + id: sql`users.id`, + name: sql`users.name`, + userCity: sql`users.city`, + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, sql`cities.id = users.id`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John', userCity: 'New York', cityName: 'Paris' }, + ]); +}); + +test('join on aliased sql from select', async () => { + const result = await db + .select({ + userId: sql`users.id`.as('userId'), + name: sql`users.name`, + userCity: sql`users.city`, + cityId: sql`cities.id`.as('cityId'), + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, (cols) => eq(cols.cityId, cols.userId)); + + Expect>; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); +}); + +test('join on aliased sql from with clause', async () => { + const users = db.$with('users').as( + db.select({ + id: sql`id`.as('userId'), + name: sql`name`.as('userName'), + city: sql`city`.as('city'), + }).from( + sql`(select 1 as id, 'John' as name, 'New York' as city) as users`, + ), + ); + + const cities = db.$with('cities').as( + db.select({ + id: sql`id`.as('cityId'), + name: sql`name`.as('cityName'), + }).from( + sql`(select 1 as id, 'Paris' as name) as cities`, + ), + ); + + const result = await db + .with(users, cities) + .select({ + userId: users.id, + name: users.name, + userCity: users.city, + cityId: cities.id, + cityName: cities.name, + }) + .from(users) + .leftJoin(cities, (cols) => eq(cols.cityId, cols.userId)); + + Expect>; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); +}); + +test('prefixed table', async () => { + const singlestoreTable = singlestoreTableCreator((name) => `myprefix_${name}`); + + const users = singlestoreTable('test_prefixed_table_with_unique_name', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table myprefix_test_prefixed_table_with_unique_name (id int not null primary key, name text not null)`, + ); + + await db.insert(users).values({ id: 1, name: 'John' }); + + const result = await db.select().from(users); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('orderBy with aliased column', () => { + const query = db.select({ + test: sql`something`.as('test'), + }).from(users2Table).orderBy((fields) => fields.test).toSQL(); + + expect(query.sql).toBe(`select something as \`test\` from \`${getTableName(users2Table)}\` order by \`test\``); +}); + +test('timestamp timezone', async () => { + const date = new Date(Date.parse('2020-01-01T12:34:56+07:00')); + + await db.insert(usersTable).values({ id: 1, name: 'With default times' }); + await db.insert(usersTable).values({ + id: 2, + name: 'Without default times', + createdAt: date, + }); + const users = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + + // check that the timestamps are set correctly for default times + expect(Math.abs(users[0]!.createdAt.getTime() - Date.now())).toBeLessThan(2000); + + // check that the timestamps are set correctly for non default times + expect(Math.abs(users[1]!.createdAt.getTime() - date.getTime())).toBeLessThan(2000); +}); + +test('transaction', async () => { + const users = singlestoreTable('users_transactions', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + const products = singlestoreTable('products_transactions', { + id: serial('id').primaryKey(), + price: int('price').notNull(), + stock: int('stock').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop table if exists ${products}`); + + await db.execute(sql`create table ${users} (id serial not null primary key, balance int not null)`); + await db.execute( + sql`create table ${products} (id serial not null primary key, price int not null, stock int not null)`, + ); + + const [{ insertId: userId }] = await db.insert(users).values({ id: 1, balance: 100 }); + const user = await db.select().from(users).where(eq(users.id, userId)).then((rows) => rows[0]!); + const [{ insertId: productId }] = await db.insert(products).values({ id: 1, price: 10, stock: 10 }); + const product = await db.select().from(products).where(eq(products.id, productId)).then((rows) => rows[0]!); + + await db.transaction(async (tx) => { + await tx.update(users).set({ balance: user.balance - product.price }).where(eq(users.id, user.id)); + await tx.update(products).set({ stock: product.stock - 1 }).where(eq(products.id, product.id)); + }); + + const result = await db.select().from(users); + + await db.execute(sql`drop table ${users}`); + await db.execute(sql`drop table ${products}`); + + expect(result).toEqual([{ id: 1, balance: 90 }]); +}); + +test('transaction rollback', async () => { + const users = singlestoreTable('users_transactions_rollback', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, balance int not null)`, + ); + + await expect((async () => { + await db.transaction(async (tx) => { + await tx.insert(users).values({ balance: 100 }); + tx.rollback(); + }); + })()).rejects.toThrowError(TransactionRollbackError); + + const result = await db.select().from(users); + + await db.execute(sql`drop table ${users}`); + + expect(result).toEqual([]); +}); + +test('join subquery with join', async () => { + const internalStaff = singlestoreTable('internal_staff', { + userId: int('user_id').notNull(), + }); + + const customUser = singlestoreTable('custom_user', { + id: int('id').notNull(), + }); + + const ticket = singlestoreTable('ticket', { + staffId: int('staff_id').notNull(), + }); + + await db.execute(sql`drop table if exists ${internalStaff}`); + await db.execute(sql`drop table if exists ${customUser}`); + await db.execute(sql`drop table if exists ${ticket}`); + + await db.execute(sql`create table ${internalStaff} (user_id integer not null)`); + await db.execute(sql`create table ${customUser} (id integer not null)`); + await db.execute(sql`create table ${ticket} (staff_id integer not null)`); + + await db.insert(internalStaff).values({ userId: 1 }); + await db.insert(customUser).values({ id: 1 }); + await db.insert(ticket).values({ staffId: 1 }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin(customUser, eq(internalStaff.userId, customUser.id)) + .as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + await db.execute(sql`drop table ${internalStaff}`); + await db.execute(sql`drop table ${customUser}`); + await db.execute(sql`drop table ${ticket}`); + + expect(mainQuery).toEqual([{ + ticket: { staffId: 1 }, + internal_staff: { + internal_staff: { userId: 1 }, + custom_user: { id: 1 }, + }, + }]); +}); + +test('subquery with view', async () => { + const users = singlestoreTable('users_subquery_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.$with('sq').as(db.select().from(newYorkers)); + const result = await db.with(sq).select().from(sq).orderBy(asc(sq.id)); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); + + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 1 }, + ]); +}); + +test('join view as subquery', async () => { + const users = singlestoreTable('users_join_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.select().from(newYorkers).as('new_yorkers_sq'); + + const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id)).orderBy(asc(users.id)); + + expect(result).toEqual([ + { + users_join_view: { id: 1, name: 'John', cityId: 1 }, + new_yorkers_sq: { id: 1, name: 'John', cityId: 1 }, + }, + { + users_join_view: { id: 2, name: 'Jane', cityId: 2 }, + new_yorkers_sq: null, + }, + { + users_join_view: { id: 3, name: 'Jack', cityId: 1 }, + new_yorkers_sq: { id: 3, name: 'Jack', cityId: 1 }, + }, + { + users_join_view: { id: 4, name: 'Jill', cityId: 2 }, + new_yorkers_sq: null, + }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); +}); + +test('select iterator', async () => { + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const iter = db.select().from(users) + .orderBy(asc(users.id)) + .iterator(); + + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); +}); + +test('select iterator w/ prepared statement', async () => { + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const prepared = db.select().from(users) + .orderBy(asc(users.id)) + .prepare(); + const iter = prepared.iterator(); + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); +}); + +test('insert undefined', async () => { + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.insert(users).values({ name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); +}); + +test('update undefined', async () => { + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.update(users).set({ name: undefined }); + })()).rejects.toThrowError(); + + await expect((async () => { + await db.update(users).set({ id: 1, name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); +}); diff --git a/integration-tests/tests/singlestore/singlestore-proxy.test.ts b/integration-tests/tests/singlestore/singlestore-proxy.test.ts new file mode 100644 index 000000000..51dc48a4a --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-proxy.test.ts @@ -0,0 +1,140 @@ +import retry from 'async-retry'; +import type { SingleStoreRemoteDatabase } from 'drizzle-orm/singlestore-proxy'; +import { drizzle as proxyDrizzle } from 'drizzle-orm/singlestore-proxy'; +import * as mysql2 from 'mysql2/promise'; +import { afterAll, beforeAll, beforeEach } from 'vitest'; +import { skipTests } from '~/common'; +import { createDockerDB, tests } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +// eslint-disable-next-line drizzle-internal/require-entity-kind +class ServerSimulator { + constructor(private db: mysql2.Connection) {} + + async query(sql: string, params: any[], method: 'all' | 'execute') { + if (method === 'all') { + try { + const result = await this.db.query({ + sql, + values: params, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + + return { data: result[0] as any }; + } catch (e: any) { + return { error: e }; + } + } else if (method === 'execute') { + try { + const result = await this.db.query({ + sql, + values: params, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + + return { data: result as any }; + } catch (e: any) { + return { error: e }; + } + } else { + return { error: 'Unknown method value' }; + } + } + + async migrations(queries: string[]) { + await this.db.query('START TRANSACTION'); + try { + for (const query of queries) { + await this.db.query(query); + } + await this.db.query('COMMIT'); + } catch (e) { + await this.db.query('ROLLBACK'); + throw e; + } + + return {}; + } +} + +let db: SingleStoreRemoteDatabase; +let client: mysql2.Connection; +let serverSimulator: ServerSimulator; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr } = await createDockerDB(); + connectionString = conStr; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + + serverSimulator = new ServerSimulator(client); + db = proxyDrizzle(async (sql, params, method) => { + try { + const response = await serverSimulator.query(sql, params, method); + + if (response.error !== undefined) { + throw response.error; + } + + return { rows: response.data }; + } catch (e: any) { + console.error('Error from singlestore proxy server:', e.message); + throw e; + } + }, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); +}); + +beforeEach((ctx) => { + ctx.singlestore = { + db, + }; +}); + +skipTests([ + 'select iterator w/ prepared statement', + 'select iterator', + 'nested transaction rollback', + 'nested transaction', + 'transaction rollback', + 'transaction', + 'transaction with options (set isolationLevel)', + 'migrator', +]); + +tests(); diff --git a/integration-tests/tests/singlestore/singlestore.test.ts b/integration-tests/tests/singlestore/singlestore.test.ts new file mode 100644 index 000000000..bfb1ee5b7 --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore.test.ts @@ -0,0 +1,51 @@ +import retry from 'async-retry'; +import { drizzle } from 'drizzle-orm/singlestore'; +import type { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +import * as mysql2 from 'mysql2/promise'; +import { afterAll, beforeAll, beforeEach } from 'vitest'; +import { createDockerDB, tests } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +let db: SingleStoreDriverDatabase; +let client: mysql2.Connection; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr } = await createDockerDB(); + connectionString = conStr; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); +}); + +beforeEach((ctx) => { + ctx.singlestore = { + db, + }; +}); + +tests(); diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 84ea9b1c8..3ec77a7ba 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -15,9 +15,13 @@ export default defineConfig({ 'tests/extensions/vectors/**/*', 'tests/version.test.ts', 'tests/pg/node-postgres.test.ts', +<<<<<<< HEAD 'tests/utils/is-config.test.ts', 'js-tests/driver-init/commonjs/*.test.cjs', 'js-tests/driver-init/module/*.test.mjs', +======= + 'tests/singlestore/**/*.test.ts', +>>>>>>> 78db5cf6 ([SingleStore] Add SingleStore connector (#32)) ], exclude: [ ...(process.env.SKIP_EXTERNAL_DB_TESTS diff --git a/package.json b/package.json index 29189a91b..7fcf31c19 100755 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "test": "turbo run test --color", "t": "pnpm test", "test:types": "turbo run test:types --color", - "lint": "concurrently -n eslint,dprint \"eslint --ext ts .\" \"dprint check --list-different\"" + "lint": "concurrently -n eslint,dprint \"eslint --ext ts .\" \"dprint check --list-different\"", + "lint:fix": "concurrently -n eslint,dprint \"eslint --ext ts --fix .\" \"dprint fmt\"" }, "devDependencies": { "@arethetypeswrong/cli": "0.15.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 468f12ca6..d8c3242a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21944,4 +21944,4 @@ snapshots: ps-tree: 1.2.0 webpod: 0.0.2 which: 3.0.1 - yaml: 2.4.2 + yaml: 2.4.2 \ No newline at end of file From 6e91991dbf53d138a3abd02763e1880ea78c3d8d Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 23 Oct 2024 18:05:19 +0100 Subject: [PATCH 311/492] rebase singlestore connector with last commit: https://github.com/drizzle-team/drizzle-orm/commit/526996bd2ea20d5b1a0d65e743b47e23329d441c --- drizzle-kit/package.json | 1 + drizzle-kit/src/api.ts | 9 +- drizzle-kit/src/cli/commands/migrate.ts | 37 ++++- drizzle-kit/src/jsonStatements.ts | 37 ++++- drizzle-kit/src/migrationPreparator.ts | 6 +- drizzle-kit/src/serializer/index.ts | 5 +- .../src/serializer/singlestoreSchema.ts | 54 ++++++ .../src/serializer/singlestoreSerializer.ts | 155 +++++++++++++++++- drizzle-kit/src/snapshotsDiffer.ts | 154 ++++++++++++++++- drizzle-kit/tests/push/singlestore.test.ts | 8 +- drizzle-kit/tests/schemaDiffer.ts | 11 +- drizzle-kit/vitest.config.ts | 4 + drizzle-orm/package.json | 1 + drizzle-orm/src/column-builder.ts | 8 +- .../src/singlestore-core/columns/common.ts | 2 +- .../singlestore-core/query-builders/index.ts | 1 - drizzle-orm/src/singlestore-core/table.ts | 6 +- .../src/singlestore-core/unique-constraint.ts | 5 +- integration-tests/vitest.config.ts | 5 +- pnpm-lock.yaml | 2 +- 20 files changed, 466 insertions(+), 45 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 1c911f23f..3de4487c4 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -7,6 +7,7 @@ "orm", "pg", "mysql", + "singlestore", "postgresql", "postgres", "sqlite", diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 9f66b2fb7..5d0ef60e3 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -12,6 +12,7 @@ import { roleResolver, schemasResolver, sequencesResolver, + singleStoreViewsResolver, sqliteViewsResolver, tablesResolver, viewsResolver, @@ -387,6 +388,7 @@ export const pushMySQLSchema = async ( export const generateSingleStoreDrizzleJson = async ( imports: Record, prevId?: string, + casing?: CasingType, ): Promise => { const { prepareFromExports } = await import('./serializer/singlestoreImports'); @@ -394,7 +396,7 @@ export const generateSingleStoreDrizzleJson = async ( const id = randomUUID(); - const snapshot = generateSingleStoreSnapshot(prepared.tables); + const snapshot = generateSingleStoreSnapshot(prepared.tables, prepared.views, casing); return { ...snapshot, @@ -420,8 +422,10 @@ export const generateSingleStoreMigration = async ( squashedCur, tablesResolver, columnsResolver, + singleStoreViewsResolver, validatedPrev, validatedCur, + 'push', ); return sqlStatements; @@ -442,7 +446,7 @@ export const pushSingleStoreSchema = async ( const { sql } = await import('drizzle-orm'); const db: DB = { - query: async (query: string, params?: any[]) => { + query: async (query: string) => { const res = await drizzleInstance.execute(sql.raw(query)); return res[0] as unknown as any[]; }, @@ -461,6 +465,7 @@ export const pushSingleStoreSchema = async ( squashedCur, tablesResolver, columnsResolver, + singleStoreViewsResolver, validatedPrev, validatedCur, 'push', diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index bce7ff010..00c472e9e 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -13,7 +13,12 @@ import { import chalk from 'chalk'; import { render } from 'hanji'; import path, { join } from 'path'; -import { SingleStoreSchema, singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; +import { + SingleStoreSchema, + singlestoreSchema, + squashSingleStoreScheme, + ViewSquashed as SingleStoreViewSquashed, +} from 'src/serializer/singlestoreSchema'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme, ViewSquashed } from '../../serializer/mysqlSchema'; @@ -147,6 +152,28 @@ export const mySqlViewsResolver = async ( } }; +export const singleStoreViewsResolver = async ( + input: ResolverInput, +): Promise> => { + try { + const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict( + input.created, + input.deleted, + 'view', + ); + + return { + created: created, + deleted: deleted, + moved: moved, + renamed: renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; + export const sqliteViewsResolver = async ( input: ResolverInput, ): Promise> => { @@ -581,11 +608,13 @@ function singleStoreSchemaSuggestions( export const prepareSingleStorePush = async ( schemaPath: string | string[], snapshot: SingleStoreSchema, + casing: CasingType | undefined, ) => { try { const { prev, cur } = await prepareSingleStoreDbPushSnapshot( snapshot, schemaPath, + casing, ); const validatedPrev = singlestoreSchema.parse(prev); @@ -599,6 +628,7 @@ export const prepareSingleStorePush = async ( squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, 'push', @@ -614,6 +644,7 @@ export const prepareSingleStorePush = async ( export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; + const casing = config.casing; try { // TODO: remove @@ -623,6 +654,7 @@ export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { const { prev, cur, custom } = await prepareSingleStoreMigrationSnapshot( snapshots, schemaPath, + casing, ); const validatedPrev = singlestoreSchema.parse(prev); @@ -645,11 +677,12 @@ export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { const squashedPrev = squashSingleStoreScheme(validatedPrev); const squashedCur = squashSingleStoreScheme(validatedCur); - const { sqlStatements, statements, _meta } = await applySingleStoreSnapshotsDiff( + const { sqlStatements, _meta } = await applySingleStoreSnapshotsDiff( squashedPrev, squashedCur, tablesResolver, columnsResolver, + mySqlViewsResolver, validatedPrev, validatedCur, ); diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 8257265cb..a3ec288bc 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -13,7 +13,7 @@ import { Role, ViewWithOption, } from './serializer/pgSchema'; -import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; +import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher, View as SingleStoreView } from './serializer/singlestoreSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, @@ -674,6 +674,11 @@ export type JsonCreateMySqlViewStatement = { replace: boolean; } & Omit; +export type JsonCreateSingleStoreViewStatement = { + type: 'singlestore_create_view'; + replace: boolean; +} & Omit; + export type JsonCreateSqliteViewStatement = { type: 'sqlite_create_view'; } & Omit; @@ -757,6 +762,10 @@ export type JsonAlterMySqlViewStatement = { type: 'alter_mysql_view'; } & Omit; +export type JsonAlterSingleStoreViewStatement = { + type: 'alter_singlestore_view'; +} & Omit; + export type JsonAlterViewStatement = | JsonAlterViewAlterSchemaStatement | JsonAlterViewAddWithOptionStatement @@ -839,6 +848,8 @@ export type JsonStatement = | JsonAlterViewStatement | JsonCreateMySqlViewStatement | JsonAlterMySqlViewStatement + | JsonCreateSingleStoreViewStatement + | JsonAlterSingleStoreViewStatement | JsonCreateSqliteViewStatement | JsonCreateCheckConstraint | JsonDeleteCheckConstraint @@ -3331,6 +3342,24 @@ export const prepareMySqlCreateViewJson = ( }; }; +export const prepareSingleStoreCreateViewJson = ( + name: string, + definition: string, + meta: string, + replace: boolean = false, +): JsonCreateSingleStoreViewStatement => { + const { algorithm, sqlSecurity, withCheckOption } = SingleStoreSquasher.unsquashView(meta); + return { + type: 'singlestore_create_view', + name: name, + definition: definition, + algorithm, + sqlSecurity, + withCheckOption, + replace, + }; +}; + export const prepareSqliteCreateViewJson = ( name: string, definition: string, @@ -3457,6 +3486,12 @@ export const prepareMySqlAlterView = ( return { type: 'alter_mysql_view', ...view }; }; +export const prepareSingleStoreAlterView = ( + view: Omit, +): JsonAlterSingleStoreViewStatement => { + return { type: 'alter_singlestore_view', ...view }; +}; + export const prepareAddCompositePrimaryKeySingleStore = ( tableName: string, pks: Record, diff --git a/drizzle-kit/src/migrationPreparator.ts b/drizzle-kit/src/migrationPreparator.ts index 262f4dcba..4e67e8174 100644 --- a/drizzle-kit/src/migrationPreparator.ts +++ b/drizzle-kit/src/migrationPreparator.ts @@ -26,8 +26,9 @@ export const prepareMySqlDbPushSnapshot = async ( export const prepareSingleStoreDbPushSnapshot = async ( prev: SingleStoreSchema, schemaPath: string | string[], + casing: CasingType | undefined, ): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema }> => { - const serialized = await serializeSingleStore(schemaPath); + const serialized = await serializeSingleStore(schemaPath, casing); const id = randomUUID(); const idPrev = prev.id; @@ -108,11 +109,12 @@ export const prepareMySqlMigrationSnapshot = async ( export const prepareSingleStoreMigrationSnapshot = async ( migrationFolders: string[], schemaPath: string | string[], + casing: CasingType | undefined, ): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema; custom: SingleStoreSchema }> => { const prevSnapshot = singlestoreSchema.parse( preparePrevSnapshot(migrationFolders, drySingleStore), ); - const serialized = await serializeSingleStore(schemaPath); + const serialized = await serializeSingleStore(schemaPath, casing); const id = randomUUID(); const idPrev = prevSnapshot.id; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index e82fda92d..d8934de00 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -56,6 +56,7 @@ export const serializeSQLite = async ( export const serializeSingleStore = async ( path: string | string[], + casing: CasingType | undefined, ): Promise => { const filenames = prepareFilenames(path); @@ -64,9 +65,9 @@ export const serializeSingleStore = async ( const { prepareFromSingleStoreImports } = await import('./singlestoreImports'); const { generateSingleStoreSnapshot } = await import('./singlestoreSerializer'); - const { tables } = await prepareFromSingleStoreImports(filenames); + const { tables, views } = await prepareFromSingleStoreImports(filenames); - return generateSingleStoreSnapshot(tables); + return generateSingleStoreSnapshot(tables, views, casing); }; export const prepareFilenames = (path: string | string[]) => { diff --git a/drizzle-kit/src/serializer/singlestoreSchema.ts b/drizzle-kit/src/serializer/singlestoreSchema.ts index a0bbae1bf..501ccfe40 100644 --- a/drizzle-kit/src/serializer/singlestoreSchema.ts +++ b/drizzle-kit/src/serializer/singlestoreSchema.ts @@ -43,6 +43,20 @@ const table = object({ uniqueConstraints: record(string(), uniqueConstraint).default({}), }).strict(); +const viewMeta = object({ + algorithm: enumType(['undefined', 'merge', 'temptable']), + sqlSecurity: enumType(['definer', 'invoker']), + withCheckOption: enumType(['local', 'cascaded']).optional(), +}).strict(); + +export const view = object({ + name: string(), + columns: record(string(), column), + definition: string().optional(), + isExisting: boolean(), +}).strict().merge(viewMeta); +type SquasherViewMeta = Omit, 'definer'>; + export const kitInternals = object({ tables: record( string(), @@ -76,6 +90,7 @@ export const schemaInternal = object({ version: literal('1'), dialect: dialect, tables: record(string(), table), + views: record(string(), view).default({}), _meta: object({ tables: record(string(), string()), columns: record(string(), string()), @@ -93,10 +108,17 @@ const tableSquashed = object({ uniqueConstraints: record(string(), string()).default({}), }).strict(); +const viewSquashed = view.omit({ + algorithm: true, + sqlSecurity: true, + withCheckOption: true, +}).extend({ meta: string() }); + export const schemaSquashed = object({ version: literal('1'), dialect: dialect, tables: record(string(), tableSquashed), + views: record(string(), viewSquashed), }).strict(); export type Dialect = TypeOf; @@ -109,6 +131,8 @@ export type SingleStoreSchemaSquashed = TypeOf; export type Index = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; +export type View = TypeOf; +export type ViewSquashed = TypeOf; export const SingleStoreSquasher = { squashIdx: (idx: Index) => { @@ -143,6 +167,19 @@ export const SingleStoreSquasher = { const [name, columns] = unq.split(';'); return { name, columns: columns.split(',') }; }, + squashView: (view: View): string => { + return `${view.algorithm};${view.sqlSecurity};${view.withCheckOption}`; + }, + unsquashView: (meta: string): SquasherViewMeta => { + const [algorithm, sqlSecurity, withCheckOption] = meta.split(';'); + const toReturn = { + algorithm: algorithm, + sqlSecurity: sqlSecurity, + withCheckOption: withCheckOption !== 'undefined' ? withCheckOption : undefined, + }; + + return viewMeta.parse(toReturn); + }, }; export const squashSingleStoreScheme = (json: SingleStoreSchema): SingleStoreSchemaSquashed => { @@ -175,10 +212,26 @@ export const squashSingleStoreScheme = (json: SingleStoreSchema): SingleStoreSch ]; }), ); + + const mappedViews = Object.fromEntries( + Object.entries(json.views).map(([key, value]) => { + const meta = SingleStoreSquasher.squashView(value); + + return [key, { + name: value.name, + isExisting: value.isExisting, + columns: value.columns, + definition: value.definition, + meta, + }]; + }), + ); + return { version: '1', dialect: json.dialect, tables: mappedTables, + views: mappedViews, }; }; @@ -195,6 +248,7 @@ export const drySingleStore = singlestoreSchema.parse({ prevId: '', tables: {}, schemas: {}, + views: {}, _meta: { schemas: {}, tables: {}, diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index d96004c8f..922296540 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -3,6 +3,7 @@ import { is, SQL } from 'drizzle-orm'; import { AnySingleStoreTable, getTableConfig, + getViewConfig, type PrimaryKey as PrimaryKeyORM, SingleStoreDialect, SingleStoreView, @@ -12,6 +13,8 @@ import { RowDataPacket } from 'mysql2/promise'; import { withStyle } from '../cli/validations/outputs'; import { IntrospectStage, IntrospectStatus } from '../cli/views'; +import { SingleStoreColumn } from 'drizzle-orm/singlestore-core/columns'; +import { CasingType } from 'src/cli/validations/common'; import type { DB } from '../utils'; import { sqlToStr } from '.'; import { @@ -22,8 +25,8 @@ import { SingleStoreSchemaInternal, Table, UniqueConstraint, + View, } from './singlestoreSchema'; -import { CasingType } from 'src/cli/validations/common'; const dialect = new SingleStoreDialect(); @@ -36,7 +39,9 @@ export const generateSingleStoreSnapshot = ( views: SingleStoreView[], casing: CasingType | undefined, ): SingleStoreSchemaInternal => { + const dialect = new SingleStoreDialect({ casing }); const result: Record = {}; + const resultViews: Record = {}; const internal: SingleStoreKitInternals = { tables: {}, indexes: {} }; for (const table of tables) { const { @@ -290,10 +295,120 @@ export const generateSingleStoreSnapshot = ( } } + for (const view of views) { + const { + isExisting, + name, + query, + schema, + selectedFields, + algorithm, + sqlSecurity, + withCheckOption, + } = getViewConfig(view); + + const columnsObject: Record = {}; + + const existingView = resultViews[name]; + if (typeof existingView !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated view name across ${ + chalk.underline.blue( + schema ?? 'public', + ) + } schema. Please rename your view`, + ) + }`, + ); + process.exit(1); + } + for (const key in selectedFields) { + if (is(selectedFields[key], SingleStoreColumn)) { + const column = selectedFields[key]; + + const notNull: boolean = column.notNull; + const sqlTypeLowered = column.getSQLType().toLowerCase(); + const autoIncrement = typeof (column as any).autoIncrement === 'undefined' + ? false + : (column as any).autoIncrement; + + const generated = column.generated; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + primaryKey: false, + // If field is autoincrement it's notNull by default + // notNull: autoIncrement ? true : notNull, + notNull, + autoincrement: autoIncrement, + onUpdate: (column as any).hasOnUpdateNow, + generated: generated + ? { + as: is(generated.as, SQL) + ? dialect.sqlToQuery(generated.as as SQL).sql + : typeof generated.as === 'function' + ? dialect.sqlToQuery(generated.as() as SQL).sql + : (generated.as as any), + type: generated.mode ?? 'stored', + } + : undefined, + }; + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default, casing); + } else { + if (typeof column.default === 'string') { + columnToSet.default = `'${column.default}'`; + } else { + if (sqlTypeLowered === 'json') { + columnToSet.default = `'${JSON.stringify(column.default)}'`; + } else if (column.default instanceof Date) { + if (sqlTypeLowered === 'date') { + columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; + } else if ( + sqlTypeLowered.startsWith('datetime') + || sqlTypeLowered.startsWith('timestamp') + ) { + columnToSet.default = `'${ + column.default + .toISOString() + .replace('T', ' ') + .slice(0, 23) + }'`; + } + } else { + columnToSet.default = column.default; + } + } + if (['blob', 'text', 'json'].includes(column.getSQLType())) { + columnToSet.default = `(${columnToSet.default})`; + } + } + } + columnsObject[column.name] = columnToSet; + } + } + + resultViews[name] = { + columns: columnsObject, + name, + isExisting, + definition: isExisting ? undefined : dialect.sqlToQuery(query!).sql, + withCheckOption, + algorithm: algorithm ?? 'undefined', // set default values + sqlSecurity: sqlSecurity ?? 'definer', // set default values + }; + } + return { version: '1', dialect: 'singlestore', tables: result, + views: resultViews, _meta: { tables: {}, columns: {}, @@ -347,7 +462,7 @@ export const fromDatabase = async ( let columnsCount = 0; let tablesCount = new Set(); let indexesCount = 0; - let foreignKeysCount = 0; + let viewsCount = 0; const idxs = await db.query( `select * from INFORMATION_SCHEMA.STATISTICS @@ -587,6 +702,41 @@ export const fromDatabase = async ( } } + const views = await db.query( + `select * from INFORMATION_SCHEMA.VIEWS WHERE table_schema = '${inputSchema}';`, + ); + + const resultViews: Record = {}; + + viewsCount = views.length; + if (progressCallback) { + progressCallback('views', viewsCount, 'fetching'); + } + for await (const view of views) { + const viewName = view['TABLE_NAME']; + const definition = view['VIEW_DEFINITION']; + + const withCheckOption = view['CHECK_OPTION'] === 'NONE' ? undefined : view['CHECK_OPTION'].toLowerCase(); + const sqlSecurity = view['SECURITY_TYPE'].toLowerCase(); + + const [createSqlStatement] = await db.query(`SHOW CREATE VIEW \`${viewName}\`;`); + const algorithmMatch = createSqlStatement['Create View'].match(/ALGORITHM=([^ ]+)/); + const algorithm = algorithmMatch ? algorithmMatch[1].toLowerCase() : undefined; + + const columns = result[viewName].columns; + delete result[viewName]; + + resultViews[viewName] = { + columns: columns, + isExisting: false, + name: viewName, + algorithm, + definition, + sqlSecurity, + withCheckOption, + }; + } + if (progressCallback) { progressCallback('indexes', indexesCount, 'done'); // progressCallback("enums", 0, "fetching"); @@ -597,6 +747,7 @@ export const fromDatabase = async ( version: '1', dialect: 'singlestore', tables: result, + views: resultViews, _meta: { tables: {}, columns: {}, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index a9d45596b..e4857031e 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -24,6 +24,7 @@ import { JsonAlterIndPolicyStatement, JsonAlterMySqlViewStatement, JsonAlterPolicyStatement, + JsonAlterSingleStoreViewStatement, JsonAlterTableSetSchema, JsonAlterUniqueConstraint, JsonAlterViewStatement, @@ -34,6 +35,7 @@ import { JsonCreatePgViewStatement, JsonCreatePolicyStatement, JsonCreateReferenceStatement, + JsonCreateSingleStoreViewStatement, JsonCreateSqliteViewStatement, JsonCreateUniqueConstraint, JsonDeleteCheckConstraint, @@ -60,7 +62,6 @@ import { prepareAddUniqueConstraintPg as prepareAddUniqueConstraint, prepareAddValuesToEnumJson, prepareAlterColumnsMysql, - prepareAlterColumnsSingleStore, prepareAlterCompositePrimaryKeyMySql, prepareAlterCompositePrimaryKeyPg, prepareAlterCompositePrimaryKeySingleStore, @@ -120,7 +121,9 @@ import { prepareRenameSequenceJson, prepareRenameTableJson, prepareRenameViewJson, + prepareSingleStoreAlterView, prepareSingleStoreCreateTableJson, + prepareSingleStoreCreateViewJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, prepareSqliteCreateViewJson @@ -2713,7 +2716,11 @@ export const applySingleStoreSnapshotsDiff = async ( // squash indexes and fks // squash uniqueIndexes and uniqueConstraint into constraints object - // it should be done for singlestore only because it has no diffs for it + // it should be done for mysql only because it has no diffs for it + + // TODO: @AndriiSherman + // Add an upgrade to v6 and move all snaphosts to this strcutre + // After that we can generate mysql in 1 object directly(same as sqlite) for (const tableName in json1.tables) { const table = json1.tables[tableName]; for (const indexName in table.indexes) { @@ -2839,9 +2846,40 @@ export const applySingleStoreSnapshotsDiff = async ( }, ); - const diffResult = applyJsonDiff(columnsPatchedSnap1, json2); + const viewsDiff = diffSchemasOrTables(json1.views, json2.views); - const typedResult: DiffResultSingleStore = diffResultSchemeSingleStore.parse(diffResult); + const { + created: createdViews, + deleted: deletedViews, + renamed: renamedViews, // renamed or moved + } = await viewsResolver({ + created: viewsDiff.added, + deleted: viewsDiff.deleted, + }); + + const renamesViewDic: Record = {}; + renamedViews.forEach((it) => { + renamesViewDic[it.from.name] = { to: it.to.name, from: it.from.name }; + }); + + const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + viewsPatchedSnap1.views = mapEntries( + viewsPatchedSnap1.views, + (viewKey, viewValue) => { + const rename = renamesViewDic[viewValue.name]; + + if (rename) { + viewValue.name = rename.to; + viewKey = rename.to; + } + + return [viewKey, viewValue]; + }, + ); + + const diffResult = applyJsonDiff(viewsPatchedSnap1, json2); + + const typedResult: DiffResultMysql = diffResultSchemeMysql.parse(diffResult); const jsonStatements: JsonStatement[] = []; @@ -2874,6 +2912,9 @@ export const applySingleStoreSnapshotsDiff = async ( const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + const jsonCreatedCheckConstraints: JsonCreateCheckConstraint[] = []; + const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames .map((it) => prepareRenameColumns(it.table, '', it.renames)) .flat(); @@ -2935,6 +2976,9 @@ export const applySingleStoreSnapshotsDiff = async ( let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + let createdCheckConstraints: JsonCreateCheckConstraint[] = []; + let deletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + addedUniqueConstraints = prepareAddUniqueConstraint( it.name, it.schema, @@ -2960,6 +3004,26 @@ export const applySingleStoreSnapshotsDiff = async ( ); } + createdCheckConstraints = prepareAddCheckConstraint(it.name, it.schema, it.addedCheckConstraints); + deletedCheckConstraints = prepareDeleteCheckConstraint( + it.name, + it.schema, + it.deletedCheckConstraints, + ); + + // skip for push + if (it.alteredCheckConstraints && action !== 'push') { + const added: Record = {}; + const deleted: Record = {}; + + for (const k of Object.keys(it.alteredCheckConstraints)) { + added[k] = it.alteredCheckConstraints[k].__new; + deleted[k] = it.alteredCheckConstraints[k].__old; + } + createdCheckConstraints.push(...prepareAddCheckConstraint(it.name, it.schema, added)); + deletedCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); + } + jsonAddedCompositePKs.push(...addedCompositePKs); jsonDeletedCompositePKs.push(...deletedCompositePKs); jsonAlteredCompositePKs.push(...alteredCompositePKs); @@ -2967,6 +3031,9 @@ export const applySingleStoreSnapshotsDiff = async ( jsonAddedUniqueConstraints.push(...addedUniqueConstraints); jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + + jsonCreatedCheckConstraints.push(...createdCheckConstraints); + jsonDeletedCheckConstraints.push(...deletedCheckConstraints); }); const rColumns = jsonRenameColumnsStatements.map((it) => { @@ -2980,7 +3047,7 @@ export const applySingleStoreSnapshotsDiff = async ( const jsonTableAlternations = alteredTables .map((it) => { - return prepareAlterColumnsSingleStore( + return prepareAlterColumnsMysql( it.name, it.schema, it.altered, @@ -3043,13 +3110,85 @@ export const applySingleStoreSnapshotsDiff = async ( curFull.internal, ); }); + + const createViews: JsonCreateSingleStoreViewStatement[] = []; + const dropViews: JsonDropViewStatement[] = []; + const renameViews: JsonRenameViewStatement[] = []; + const alterViews: JsonAlterSingleStoreViewStatement[] = []; + + createViews.push( + ...createdViews.filter((it) => !it.isExisting).map((it) => { + return prepareSingleStoreCreateViewJson( + it.name, + it.definition!, + it.meta, + ); + }), + ); + + dropViews.push( + ...deletedViews.filter((it) => !it.isExisting).map((it) => { + return prepareDropViewJson(it.name); + }), + ); + + renameViews.push( + ...renamedViews.filter((it) => !it.to.isExisting && !json1.views[it.from.name].isExisting).map((it) => { + return prepareRenameViewJson(it.to.name, it.from.name); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[it.name].isExisting); + + for (const alteredView of alteredViews) { + const { definition, meta } = json2.views[alteredView.name]; + + if (alteredView.alteredExisting) { + dropViews.push(prepareDropViewJson(alteredView.name)); + + createViews.push( + prepareSingleStoreCreateViewJson( + alteredView.name, + definition!, + meta, + ), + ); + + continue; + } + + if (alteredView.alteredDefinition && action !== 'push') { + createViews.push( + prepareSingleStoreCreateViewJson( + alteredView.name, + definition!, + meta, + true, + ), + ); + continue; + } + + if (alteredView.alteredMeta) { + const view = curFull['views'][alteredView.name]; + alterViews.push( + prepareSingleStoreAlterView(view), + ); + } + } + jsonStatements.push(...jsonSingleStoreCreateTables); jsonStatements.push(...jsonDropTables); jsonStatements.push(...jsonRenameTables); jsonStatements.push(...jsonRenameColumnsStatements); + jsonStatements.push(...dropViews); + jsonStatements.push(...renameViews); + jsonStatements.push(...alterViews); + jsonStatements.push(...jsonDeletedUniqueConstraints); + jsonStatements.push(...jsonDeletedCheckConstraints); // Will need to drop indexes before changing any columns in table // Then should go column alternations and then index creation @@ -3065,6 +3204,7 @@ export const applySingleStoreSnapshotsDiff = async ( jsonStatements.push(...jsonAddColumnsStatemets); jsonStatements.push(...jsonCreateIndexesForCreatedTables); + jsonStatements.push(...jsonCreatedCheckConstraints); jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); @@ -3074,11 +3214,11 @@ export const applySingleStoreSnapshotsDiff = async ( // jsonStatements.push(...jsonAddedCompositePKs); jsonStatements.push(...jsonAlteredCompositePKs); - jsonStatements.push(...jsonAddedUniqueConstraints); + jsonStatements.push(...createViews); jsonStatements.push(...jsonAlteredUniqueConstraints); - const sqlStatements = fromJson(jsonStatements, 'singlestore'); + const sqlStatements = fromJson(jsonStatements, 'mysql'); const uniqueSqlStatements: string[] = []; sqlStatements.forEach((ss) => { diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 7f3ea755d..182c89b66 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -12,9 +12,9 @@ import { int, json, mediumint, + serial, singlestoreEnum, singlestoreTable, - serial, smallint, text, time, @@ -26,7 +26,7 @@ import { } from 'drizzle-orm/singlestore-core'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; -import { diffTestSchemasSingleStore, diffTestSchemasPushSingleStore } from 'tests/schemaDiffer'; +import { diffTestSchemasPushSingleStore, diffTestSchemasSingleStore } from 'tests/schemaDiffer'; import { v4 as uuid } from 'uuid'; import { expect } from 'vitest'; import { DialectSuite, run } from './common'; @@ -667,7 +667,7 @@ const singlestoreSuite: DialectSuite = { run( singlestoreSuite, async (context: any) => { - const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(context); + const connectionString = process.env.SINGLESTORE_CONNECTION_STRING ?? await createDockerDB(context); const sleep = 1000; let timeLeft = 20000; @@ -686,7 +686,7 @@ run( } } while (timeLeft > 0); if (!connected) { - console.error('Cannot connect to MySQL'); + console.error('Cannot connect to SingleStore'); await context.client?.end().catch(console.error); await context.singlestoreContainer?.stop().catch(console.error); throw lastError; diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index cb1fe0cec..5d4cdbdcf 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -1535,10 +1535,10 @@ export const diffTestSchemasSingleStore = async ( return { sqlStatements, statements }; }; -export const diffTestSchemasPushSinglestore = async ( +export const diffTestSchemasPushSingleStore = async ( client: Connection, - left: SingleStoreSchema, - right: SingleStoreSchema, + left: SinglestoreSchema, + right: SinglestoreSchema, renamesArr: string[], schema: string, cli: boolean = false, @@ -1619,13 +1619,14 @@ export const diffTestSchemasPushSinglestore = async ( } }; -export const applySingleStoreDiffs = async (sn: SingleStoreSchema, casing: CasingType | undefined) => { +export const applySingleStoreDiffs = async (sn: SinglestoreSchema, casing: CasingType | undefined) => { const dryRun = { version: '1', dialect: 'singlestore', id: '0', prevId: '0', tables: {}, + views: {}, enums: {}, schemas: {}, _meta: { @@ -2322,7 +2323,7 @@ export const introspectMySQLToFile = async ( export const introspectSingleStoreToFile = async ( client: Connection, - initSchema: SingleStoreSchema, + initSchema: SinglestoreSchema, testName: string, schema: string, casing?: CasingType | undefined, diff --git a/drizzle-kit/vitest.config.ts b/drizzle-kit/vitest.config.ts index 602e96ede..8f22123dd 100644 --- a/drizzle-kit/vitest.config.ts +++ b/drizzle-kit/vitest.config.ts @@ -7,6 +7,10 @@ export default defineConfig({ 'tests/**/*.test.ts', ], + exclude: [ + 'tests/**/singlestore-generated.test.ts', + ], + typecheck: { tsconfig: 'tsconfig.json', }, diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index b2b204ead..6c20ac27f 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -29,6 +29,7 @@ "orm", "pg", "mysql", + "singlestore", "postgresql", "postgres", "sqlite", diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index 13d9d363f..5236d2e05 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -308,9 +308,9 @@ export type BuildColumn< TTableName extends string, TBuilder extends ColumnBuilderBase, TDialect extends Dialect, -> = TDialect extends 'singlestore' ? SingleStoreColumn> - : TDialect extends 'pg' ? PgColumn> +> = TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> + : TDialect extends 'singlestore' ? SingleStoreColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : TDialect extends 'common' ? Column> : never; @@ -351,8 +351,8 @@ export type BuildExtraConfigColumns< & {}; export type ChangeColumnTableName = - TDialect extends 'singlestore' ? SingleStoreColumn> - : TDialect extends 'pg' ? PgColumn> + TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> + : TDialect extends 'singlestore' ? SingleStoreColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : never; diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts index 63a6dbf29..6ccd64f1e 100644 --- a/drizzle-orm/src/singlestore-core/columns/common.ts +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -1,4 +1,3 @@ -import { ColumnBuilder } from '~/column-builder.ts'; import type { ColumnBuilderBase, ColumnBuilderBaseConfig, @@ -10,6 +9,7 @@ import type { IsAutoincrement, MakeColumnConfig, } from '~/column-builder.ts'; +import { ColumnBuilder } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { Column } from '~/column.ts'; import { entityKind } from '~/entity.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/index.ts b/drizzle-orm/src/singlestore-core/query-builders/index.ts index 95de476cd..5963612e0 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/index.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/index.ts @@ -1,6 +1,5 @@ export * from './attach.ts'; export * from './branch.ts'; -export * from './count.ts'; export * from './createMilestone.ts'; export * from './delete.ts'; export * from './detach.ts'; diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index db24a8587..4cc8973ee 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -1,7 +1,6 @@ import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; -import type { CheckBuilder } from './checks.ts'; import { getSingleStoreColumnBuilders, type SingleStoreColumnBuilders } from './columns/all.ts'; import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; import type { AnyIndexBuilder } from './indexes.ts'; @@ -11,16 +10,12 @@ import type { UniqueConstraintBuilder } from './unique-constraint.ts'; export type SingleStoreTableExtraConfig = Record< string, | AnyIndexBuilder - | CheckBuilder | PrimaryKeyBuilder | UniqueConstraintBuilder >; export type TableConfig = TableConfigBase; -/** @internal */ -export const InlineForeignKeys = Symbol.for('drizzle:SingleStoreInlineForeignKeys'); - export class SingleStoreTable extends Table { static override readonly [entityKind]: string = 'SingleStoreTable'; @@ -78,6 +73,7 @@ export function singlestoreTableWithSchema< const builtColumns = Object.fromEntries( Object.entries(parsedColumns).map(([name, colBuilderBase]) => { const colBuilder = colBuilderBase as SingleStoreColumnBuilder; + colBuilder.setName(name); const column = colBuilder.build(rawTable); return [name, column]; }), diff --git a/drizzle-orm/src/singlestore-core/unique-constraint.ts b/drizzle-orm/src/singlestore-core/unique-constraint.ts index faa4f3216..511e466dc 100644 --- a/drizzle-orm/src/singlestore-core/unique-constraint.ts +++ b/drizzle-orm/src/singlestore-core/unique-constraint.ts @@ -1,13 +1,14 @@ import { entityKind } from '~/entity.ts'; +import { TableName } from '~/table.utils.ts'; import type { SingleStoreColumn } from './columns/index.ts'; -import { SingleStoreTable } from './table.ts'; +import type { SingleStoreTable } from './table.ts'; export function unique(name?: string): UniqueOnConstraintBuilder { return new UniqueOnConstraintBuilder(name); } export function uniqueKeyName(table: SingleStoreTable, columns: string[]) { - return `${table[SingleStoreTable.Symbol.Name]}_${columns.join('_')}_unique`; + return `${table[TableName]}_${columns.join('_')}_unique`; } export class UniqueConstraintBuilder { diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 3ec77a7ba..f90a4f125 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -9,19 +9,16 @@ export default defineConfig({ 'tests/relational/**/*.test.ts', 'tests/pg/**/*.test.ts', 'tests/mysql/**/*.test.ts', + 'tests/singlestore/**/*.test.ts', 'tests/sqlite/**/*.test.ts', 'tests/replicas/**/*', 'tests/imports/**/*', 'tests/extensions/vectors/**/*', 'tests/version.test.ts', 'tests/pg/node-postgres.test.ts', -<<<<<<< HEAD 'tests/utils/is-config.test.ts', 'js-tests/driver-init/commonjs/*.test.cjs', 'js-tests/driver-init/module/*.test.mjs', -======= - 'tests/singlestore/**/*.test.ts', ->>>>>>> 78db5cf6 ([SingleStore] Add SingleStore connector (#32)) ], exclude: [ ...(process.env.SKIP_EXTERNAL_DB_TESTS diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d8c3242a8..468f12ca6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21944,4 +21944,4 @@ snapshots: ps-tree: 1.2.0 webpod: 0.0.2 which: 3.0.1 - yaml: 2.4.2 \ No newline at end of file + yaml: 2.4.2 From f5c662b6fdc194d65fae8181ab99a4e4224a1650 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 30 Oct 2024 11:41:47 +0000 Subject: [PATCH 312/492] skip view tests --- drizzle-kit/tests/singlestore-views.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drizzle-kit/tests/singlestore-views.test.ts b/drizzle-kit/tests/singlestore-views.test.ts index 70add76fc..fedd74645 100644 --- a/drizzle-kit/tests/singlestore-views.test.ts +++ b/drizzle-kit/tests/singlestore-views.test.ts @@ -3,7 +3,7 @@ import { int, singlestoreTable, singlestoreView } from 'drizzle-orm/singlestore- import { expect, test } from 'vitest'; import { diffTestSchemasSingleStore } from './schemaDiffer'; -test('create view #1', async () => { +test.skip('create view #1', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -35,7 +35,7 @@ SQL SECURITY definer VIEW \`some_view\` AS (select \`id\` from \`users\`);`); }); -test('create view #2', async () => { +test.skip('create view #2', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -164,7 +164,7 @@ test('rename view', async () => { expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); }); -test('rename view and alter meta options', async () => { +test.skip('rename view and alter meta options', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -232,7 +232,7 @@ test('rename view with existing flag', async () => { expect(sqlStatements.length).toBe(0); }); -test('add meta to view', async () => { +test.skip('add meta to view', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -289,7 +289,7 @@ test('add meta to view with existing flag', async () => { expect(sqlStatements.length).toBe(0); }); -test('alter meta to view', async () => { +test.skip('alter meta to view', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -348,7 +348,7 @@ test('alter meta to view with existing flag', async () => { expect(sqlStatements.length).toBe(0); }); -test('drop meta from view', async () => { +test.skip('drop meta from view', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -405,7 +405,7 @@ test('drop meta from view existing flag', async () => { expect(sqlStatements.length).toBe(0); }); -test('alter view ".as" value', async () => { +test.skip('alter view ".as" value', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -441,7 +441,7 @@ VIEW \`some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) WITH cascaded CHECK OPTION;`); }); -test('rename and alter view ".as" value', async () => { +test.skip('rename and alter view ".as" value', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -509,7 +509,7 @@ test('set existing', async () => { expect(sqlStatements.length).toBe(0); }); -test('drop existing', async () => { +test.skip('drop existing', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); From 67d0548290e074358f062966b7be8e7ad221efb9 Mon Sep 17 00:00:00 2001 From: Alex Blokh Date: Sun, 3 Nov 2024 10:13:51 +0200 Subject: [PATCH 313/492] imports checker with OHM grammar --- drizzle-kit/imports-checker/grammar/grammar.ohm | 2 +- drizzle-kit/src/jsonStatements.ts | 9 +++++++-- drizzle-kit/src/serializer/singlestoreSerializer.ts | 2 +- drizzle-kit/src/snapshotsDiffer.ts | 4 ++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm b/drizzle-kit/imports-checker/grammar/grammar.ohm index de1459942..8d9b5e718 100644 --- a/drizzle-kit/imports-checker/grammar/grammar.ohm +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm @@ -118,4 +118,4 @@ JSImports { unicodeConnectorPunctuation = "\u005F" | "\u203F".."\u2040" | "\u30FB" | "\uFE33".."\uFE34" | "\uFE4D".."\uFE4F" | "\uFF3F" | "\uFF65" unicodeSpaceSeparator = "\u2000".."\u200B" | "\u3000" -} \ No newline at end of file +} diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index a3ec288bc..8cd792fe9 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -8,12 +8,17 @@ import { MatViewWithOption, PgSchema, PgSquasher, - View as PgView, Policy, Role, + View as PgView, ViewWithOption, } from './serializer/pgSchema'; -import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher, View as SingleStoreView } from './serializer/singlestoreSchema'; +import { + SingleStoreKitInternals, + SingleStoreSchema, + SingleStoreSquasher, + View as SingleStoreView, +} from './serializer/singlestoreSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index 922296540..b0445e439 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -16,7 +16,6 @@ import { IntrospectStage, IntrospectStatus } from '../cli/views'; import { SingleStoreColumn } from 'drizzle-orm/singlestore-core/columns'; import { CasingType } from 'src/cli/validations/common'; import type { DB } from '../utils'; -import { sqlToStr } from '.'; import { Column, Index, @@ -27,6 +26,7 @@ import { UniqueConstraint, View, } from './singlestoreSchema'; +import { sqlToStr } from './utils'; const dialect = new SingleStoreDialect(); diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index e4857031e..44bd0a713 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -84,6 +84,7 @@ import { prepareDeleteCompositePrimaryKeyPg, prepareDeleteCompositePrimaryKeySingleStore, prepareDeleteCompositePrimaryKeySqlite, + prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDeleteUniqueConstraintPg as prepareDeleteUniqueConstraint, prepareDropEnumJson, prepareDropEnumValues, @@ -92,7 +93,6 @@ import { prepareDropPolicyJsons, prepareDropReferencesJson, prepareDropRoleJson, - prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDropSequenceJson, prepareDropTableJson, prepareDropViewJson, @@ -126,7 +126,7 @@ import { prepareSingleStoreCreateViewJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, - prepareSqliteCreateViewJson + prepareSqliteCreateViewJson, } from './jsonStatements'; import { Named, NamedWithSchema } from './cli/commands/migrate'; From beddb8595d47c621ef64ee9c9a16c712a80b1fa1 Mon Sep 17 00:00:00 2001 From: Alex Blokh Date: Sun, 3 Nov 2024 13:32:01 +0200 Subject: [PATCH 314/492] imports checker with OHM grammar + fix of imports issues --- drizzle-kit/imports-checker/grammar/grammar.ohm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm b/drizzle-kit/imports-checker/grammar/grammar.ohm index 8d9b5e718..4b7ba55e4 100644 --- a/drizzle-kit/imports-checker/grammar/grammar.ohm +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm @@ -118,4 +118,8 @@ JSImports { unicodeConnectorPunctuation = "\u005F" | "\u203F".."\u2040" | "\u30FB" | "\uFE33".."\uFE34" | "\uFE4D".."\uFE4F" | "\uFF3F" | "\uFF65" unicodeSpaceSeparator = "\u2000".."\u200B" | "\u3000" +<<<<<<< HEAD } +======= +} +>>>>>>> cd33310f (imports checker with OHM grammar + fix of imports issues) From a9ad0ae1f84911449ffcd51962dee1f9b6079a3e Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 4 Nov 2024 15:39:44 +0200 Subject: [PATCH 315/492] Fix conflicts --- drizzle-kit/src/serializer/singlestoreSerializer.ts | 12 +++++++++--- drizzle-kit/src/sqlgenerator.ts | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index b0445e439..3224306dd 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -716,12 +716,18 @@ export const fromDatabase = async ( const viewName = view['TABLE_NAME']; const definition = view['VIEW_DEFINITION']; - const withCheckOption = view['CHECK_OPTION'] === 'NONE' ? undefined : view['CHECK_OPTION'].toLowerCase(); + const withCheckOption = view['CHECK_OPTION'] === 'NONE' + ? undefined + : view['CHECK_OPTION'].toLowerCase(); const sqlSecurity = view['SECURITY_TYPE'].toLowerCase(); - const [createSqlStatement] = await db.query(`SHOW CREATE VIEW \`${viewName}\`;`); + const [createSqlStatement] = await db.query( + `SHOW CREATE VIEW \`${viewName}\`;`, + ); const algorithmMatch = createSqlStatement['Create View'].match(/ALGORITHM=([^ ]+)/); - const algorithm = algorithmMatch ? algorithmMatch[1].toLowerCase() : undefined; + const algorithm = algorithmMatch + ? algorithmMatch[1].toLowerCase() + : undefined; const columns = result[viewName].columns; delete result[viewName]; diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 60ec3fc9c..e74e1e50a 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -84,7 +84,7 @@ import { } from './jsonStatements'; import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; -import { PgSquasher } from './serializer/pgSchema'; +import { PgSquasher, policy } from './serializer/pgSchema'; import { SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; import { escapeSingleQuotes } from './utils'; From 0414ecf5c5cc04546555a1df7a4273d4460415ee Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 4 Nov 2024 17:00:51 +0200 Subject: [PATCH 316/492] No fks? --- drizzle-kit/src/cli/views.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drizzle-kit/src/cli/views.ts b/drizzle-kit/src/cli/views.ts index 3ec04a588..e79d585ee 100644 --- a/drizzle-kit/src/cli/views.ts +++ b/drizzle-kit/src/cli/views.ts @@ -32,10 +32,11 @@ export const schema = (schema: CommonSchema): string => { .map((t) => { const columnsCount = Object.values(t.columns).length; const indexesCount = Object.values(t.indexes).length; - const foreignKeys = Object.values(t.foreignKeys).length; + // should we have fks? + // const foreignKeys = Object.values(t.foreignKeys).length; return `${chalk.bold.blue(t.name)} ${ chalk.gray( - `${columnsCount} columns ${indexesCount} indexes ${foreignKeys} fks`, + `${columnsCount} columns ${indexesCount} indexes`, ) }`; }) From 329638c175c1e66a2005c0231d552381b324e0db Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 4 Nov 2024 17:39:47 +0200 Subject: [PATCH 317/492] Fix after failed tests --- drizzle-kit/src/cli/commands/introspect.ts | 1 + drizzle-kit/src/cli/commands/push.ts | 13 ++++++++++--- drizzle-kit/src/cli/commands/utils.ts | 9 +++++++-- drizzle-kit/src/cli/schema.ts | 16 +++++++++++++--- drizzle-kit/tests/singlestore.test.ts | 2 ++ 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index d24b71872..149d2048b 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -346,6 +346,7 @@ export const introspectSingleStore = async ( squashSingleStoreScheme(schema), tablesResolver, columnsResolver, + mySqlViewsResolver, drySingleStore, schema, ); diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index e19e95455..d2d9c5e37 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -170,16 +170,21 @@ export const singlestorePush = async ( strict: boolean, verbose: boolean, force: boolean, + casing: CasingType | undefined, ) => { const { connectToSingleStore } = await import('../connections'); const { singlestorePushIntrospect } = await import('./singlestoreIntrospect'); const { db, database } = await connectToSingleStore(credentials); - const { schema } = await singlestorePushIntrospect(db, database, tablesFilter); + const { schema } = await singlestorePushIntrospect( + db, + database, + tablesFilter, + ); const { prepareSingleStorePush } = await import('./migrate'); - const statements = await prepareSingleStorePush(schemaPath, schema); + const statements = await prepareSingleStorePush(schemaPath, schema, casing); const filteredStatements = singleStoreFilterStatements( statements.statements ?? [], @@ -398,7 +403,9 @@ export const pgPush = async ( }${ matViewsToRemove.length > 0 ? ` remove ${matViewsToRemove.length} ${ - matViewsToRemove.length > 1 ? 'materialized views' : 'materialize view' + matViewsToRemove.length > 1 + ? 'materialized views' + : 'materialize view' },` : ' ' }` diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index a993c3a80..35a7b5a77 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -516,6 +516,7 @@ export const preparePullConfig = async ( tablesFilter, schemasFilter, prefix: config.migrations?.prefix || 'index', + entities: config.entities, }; } @@ -768,8 +769,12 @@ export const drizzleConfigFromFile = async ( ): Promise => { const prefix = process.env.TEST_CONFIG_PATH_PREFIX || ''; - const defaultTsConfigExists = existsSync(resolve(join(prefix, 'drizzle.config.ts'))); - const defaultJsConfigExists = existsSync(resolve(join(prefix, 'drizzle.config.js'))); + const defaultTsConfigExists = existsSync( + resolve(join(prefix, 'drizzle.config.ts')), + ); + const defaultJsConfigExists = existsSync( + resolve(join(prefix, 'drizzle.config.js')), + ); const defaultJsonConfigExists = existsSync( join(resolve('drizzle.config.json')), ); diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 72d5a282b..f10bcf748 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -31,7 +31,9 @@ import { grey, MigrateProgress } from './views'; const optionDialect = string('dialect') .enum(...dialects) - .desc(`Database dialect: 'postgresql', 'mysql', 'sqlite', 'turso' or 'singlestore'`); + .desc( + `Database dialect: 'postgresql', 'mysql', 'sqlite', 'turso' or 'singlestore'`, + ); const optionOut = string().desc("Output folder, 'drizzle' by default"); const optionConfig = string().desc('Path to drizzle config file'); const optionBreakpoints = boolean().desc( @@ -42,7 +44,9 @@ const optionDriver = string() .enum(...drivers) .desc('Database driver'); -const optionCasing = string().enum('camelCase', 'snake_case').desc('Casing for serialization'); +const optionCasing = string() + .enum('camelCase', 'snake_case') + .desc('Casing for serialization'); export const generate = command({ name: 'generate', @@ -364,6 +368,7 @@ export const push = command({ strict, verbose, force, + casing, ); } else { assertUnreachable(dialect); @@ -682,7 +687,12 @@ export const studio = command({ const { schema, relations, files } = schemaPath ? await prepareSingleStoreSchema(schemaPath) : { schema: {}, relations: {}, files: [] }; - setup = await drizzleForSingleStore(credentials, schema, relations, files); + setup = await drizzleForSingleStore( + credentials, + schema, + relations, + files, + ); } else { assertUnreachable(dialect); } diff --git a/drizzle-kit/tests/singlestore.test.ts b/drizzle-kit/tests/singlestore.test.ts index 63abf1755..71b95a8f5 100644 --- a/drizzle-kit/tests/singlestore.test.ts +++ b/drizzle-kit/tests/singlestore.test.ts @@ -191,6 +191,7 @@ test('add table #6', async () => { compositePkName: '', }); expect(statements[1]).toStrictEqual({ + policies: [], type: 'drop_table', tableName: 'users1', schema: undefined, @@ -283,6 +284,7 @@ test('change table schema #1', async () => { expect(statements.length).toBe(1); expect(statements[0]).toStrictEqual({ + policies: [], type: 'drop_table', tableName: 'users', schema: undefined, From 6c2e568b6075a814f9874db337bb7bbda22f1eab Mon Sep 17 00:00:00 2001 From: apeng-singlestore <127370261+apeng-singlestore@users.noreply.github.com> Date: Wed, 6 Nov 2024 13:32:32 -0800 Subject: [PATCH 318/492] Add drizzleIntegration query header Added query header for future logging of integration usage --- drizzle-orm/src/singlestore/session.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/src/singlestore/session.ts b/drizzle-orm/src/singlestore/session.ts index e03171262..dea4c1d7f 100644 --- a/drizzle-orm/src/singlestore/session.ts +++ b/drizzle-orm/src/singlestore/session.ts @@ -63,8 +63,9 @@ export class SingleStoreDriverPreparedQuery Date: Thu, 7 Nov 2024 12:39:32 +0200 Subject: [PATCH 319/492] Add a few test changes Using database for tests and remove datetime and json from singlestore allTypes test on push --- .../tests/push/singlestore-push.test.ts | 65 +-- drizzle-kit/tests/push/singlestore.test.ts | 386 ++---------------- drizzle-kit/vitest.config.ts | 13 +- 3 files changed, 80 insertions(+), 384 deletions(-) diff --git a/drizzle-kit/tests/push/singlestore-push.test.ts b/drizzle-kit/tests/push/singlestore-push.test.ts index 5db899fc0..79eeebbb5 100644 --- a/drizzle-kit/tests/push/singlestore-push.test.ts +++ b/drizzle-kit/tests/push/singlestore-push.test.ts @@ -18,7 +18,7 @@ async function createDockerDB(): Promise { const pullStream = await docker.pull(image); await new Promise((resolve, reject) => - docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) ); singlestoreContainer = await docker.createContainer({ @@ -40,7 +40,7 @@ async function createDockerDB(): Promise { } beforeAll(async () => { - const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(); + const connectionString = process.env.MYSQL_CONNECTION_STRING ?? (await createDockerDB()); const sleep = 1000; let timeLeft = 20000; @@ -64,6 +64,9 @@ beforeAll(async () => { await singlestoreContainer?.stop().catch(console.error); throw lastError; } + + await client.query('CREATE DATABASE drizzle;'); + await client.query('USE drizzle;'); }); afterAll(async () => { @@ -103,7 +106,7 @@ test('add check constraint to table', async () => { type: 'create_check_constraint', tableName: 'test', schema: '', - data: 'some_check1;\`test\`.\`values\` < 100', + data: 'some_check1;`test`.`values` < 100', }, { data: "some_check2;'test' < 100", @@ -113,7 +116,7 @@ test('add check constraint to table', async () => { }, ]); expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE \`test\` ADD CONSTRAINT \`some_check1\` CHECK (\`test\`.\`values\` < 100);', + 'ALTER TABLE `test` ADD CONSTRAINT `some_check1` CHECK (`test`.`values` < 100);', `ALTER TABLE \`test\` ADD CONSTRAINT \`some_check2\` CHECK ('test' < 100);`, ]); @@ -158,7 +161,7 @@ test('drop check constraint to table', async () => { }, ]); expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE \`test\` DROP CONSTRAINT \`some_check1\`;', + 'ALTER TABLE `test` DROP CONSTRAINT `some_check1`;', `ALTER TABLE \`test\` DROP CONSTRAINT \`some_check2\`;`, ]); @@ -218,7 +221,7 @@ test('create view', async () => { expect(statements).toStrictEqual([ { - definition: 'select \`id\` from \`test\`', + definition: 'select `id` from `test`', name: 'view', type: 'singlestore_create_view', replace: false, @@ -265,9 +268,7 @@ test('drop view', async () => { type: 'drop_view', }, ]); - expect(sqlStatements).toStrictEqual([ - 'DROP VIEW \`view\`;', - ]); + expect(sqlStatements).toStrictEqual(['DROP VIEW `view`;']); await client.query(`DROP TABLE \`test\`;`); await client.query(`DROP VIEW \`view\`;`); }); @@ -279,7 +280,12 @@ test('alter view ".as"', async () => { const schema1 = { test: table, - view: singlestoreView('view').as((qb) => qb.select().from(table).where(sql`${table.id} = 1`)), + view: singlestoreView('view').as((qb) => + qb + .select() + .from(table) + .where(sql`${table.id} = 1`) + ), }; const schema2 = { @@ -310,26 +316,37 @@ test('alter meta options with distinct in definition', async () => { const schema1 = { test: table, - view: singlestoreView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('merge').as(( - qb, - ) => qb.selectDistinct().from(table).where(sql`${table.id} = 1`)), + view: singlestoreView('view') + .withCheckOption('cascaded') + .sqlSecurity('definer') + .algorithm('merge') + .as((qb) => + qb + .selectDistinct() + .from(table) + .where(sql`${table.id} = 1`) + ), }; const schema2 = { test: table, - view: singlestoreView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('undefined').as((qb) => - qb.selectDistinct().from(table) - ), + view: singlestoreView('view') + .withCheckOption('cascaded') + .sqlSecurity('definer') + .algorithm('undefined') + .as((qb) => qb.selectDistinct().from(table)), }; - await expect(diffTestSchemasPushSingleStore( - client, - schema1, - schema2, - [], - 'drizzle', - false, - )).rejects.toThrowError(); + await expect( + diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ), + ).rejects.toThrowError(); await client.query(`DROP TABLE \`test\`;`); }); diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 182c89b66..798d018f6 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -38,7 +38,7 @@ async function createDockerDB(context: any): Promise { const pullStream = await docker.pull(image); await new Promise((resolve, reject) => - docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) ); context.singlestoreContainer = await docker.createContainer({ @@ -83,15 +83,15 @@ const singlestoreSuite: DialectSuite = { 'h', ), }), - allDateTimes: singlestoreTable('all_date_times', { - simple: datetime('simple', { mode: 'string', fsp: 1 }), - columnNotNull: datetime('column_not_null', { - mode: 'string', - }).notNull(), - columnDefault: datetime('column_default', { mode: 'string' }).default( - '2023-03-01 14:05:29', - ), - }), + // allDateTimes: singlestoreTable("all_date_times", { + // simple: datetime("simple", { mode: "string", fsp: 1 }), + // columnNotNull: datetime("column_not_null", { + // mode: "string", + // }).notNull(), + // columnDefault: datetime("column_default", { mode: "string" }).default( + // "2023-03-01 14:05:29" + // ), + // }), allDates: singlestoreTable('all_dates', { simple: date('simple', { mode: 'string' }), column_not_null: date('column_not_null', { mode: 'string' }).notNull(), @@ -150,17 +150,17 @@ const singlestoreSuite: DialectSuite = { columnDefaultSql: int('column_default_sql').default(101), }), - allJsons: singlestoreTable('all_jsons', { - columnDefaultObject: json('column_default_object') - .default({ hello: 'world world' }) - .notNull(), - columnDefaultArray: json('column_default_array').default({ - hello: { 'world world': ['foo', 'bar'] }, - foo: 'bar', - fe: 23, - }), - column: json('column'), - }), + // allJsons: singlestoreTable("all_jsons", { + // columnDefaultObject: json("column_default_object") + // .default({ hello: "world world" }) + // .notNull(), + // columnDefaultArray: json("column_default_array").default({ + // hello: { "world world": ["foo", "bar"] }, + // foo: "bar", + // fe: 23, + // }), + // column: json("column"), + // }), allMInts: singlestoreTable('all_m_ints', { simple: mediumint('simple'), @@ -318,346 +318,16 @@ const singlestoreSuite: DialectSuite = { return {} as any; }, addGeneratedColumn: async function(context: any): Promise { - const schema1 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - }), - }; - const schema2 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - context.client as Connection, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([ - { - column: { - autoincrement: false, - generated: { - as: "`users`.`name` || 'hello'", - type: 'stored', - }, - name: 'gen_name', - notNull: false, - primaryKey: false, - type: 'text', - }, - schema: '', - tableName: 'users', - type: 'alter_table_add_column', - }, - { - column: { - autoincrement: false, - generated: { - as: "`users`.`name` || 'hello'", - type: 'virtual', - }, - name: 'gen_name1', - notNull: false, - primaryKey: false, - type: 'text', - }, - schema: '', - tableName: 'users', - type: 'alter_table_add_column', - }, - ]); - expect(sqlStatements).toStrictEqual([ - "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", - "ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", - ]); - - for (const st of sqlStatements) { - await context.client.query(st); - } - - const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( - schema2, - {}, - [], - false, - ); - - for (const st of dropStatements) { - await context.client.query(st); - } + return {} as any; }, addGeneratedToColumn: async function(context: any): Promise { - const schema1 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name'), - generatedName1: text('gen_name1'), - }), - }; - const schema2 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - context.client as Connection, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([ - { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: { - as: "`users`.`name` || 'hello'", - type: 'stored', - }, - columnName: 'gen_name', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_set_generated', - }, - { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: { - as: "`users`.`name` || 'hello'", - type: 'virtual', - }, - columnName: 'gen_name1', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_set_generated', - }, - ]); - expect(sqlStatements).toStrictEqual([ - "ALTER TABLE `users` MODIFY COLUMN `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", - 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', - "ALTER TABLE `users` ADD `gen_name1` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", - ]); - - for (const st of sqlStatements) { - await context.client.query(st); - } - - const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( - schema2, - {}, - [], - false, - ); - - for (const st of dropStatements) { - await context.client.query(st); - } + return {} as any; }, dropGeneratedConstraint: async function(context: any): Promise { - const schema1 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - { mode: 'virtual' }, - ), - }), - }; - const schema2 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name'), - generatedName1: text('gen_name1'), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - context.client as Connection, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([ - { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: undefined, - columnName: 'gen_name', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - oldColumn: { - autoincrement: false, - default: undefined, - generated: { - as: '`name`', - type: 'stored', - }, - name: 'gen_name', - notNull: false, - onUpdate: undefined, - primaryKey: false, - type: 'text', - }, - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_generated', - }, - { - columnAutoIncrement: false, - columnDefault: undefined, - columnGenerated: undefined, - columnName: 'gen_name1', - columnNotNull: false, - columnOnUpdate: undefined, - columnPk: false, - newDataType: 'text', - oldColumn: { - autoincrement: false, - default: undefined, - generated: { - as: '`name`', - type: 'virtual', - }, - name: 'gen_name1', - notNull: false, - onUpdate: undefined, - primaryKey: false, - type: 'text', - }, - schema: '', - tableName: 'users', - type: 'alter_table_alter_column_drop_generated', - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', - 'ALTER TABLE `users` DROP COLUMN `gen_name1`;', - 'ALTER TABLE `users` ADD `gen_name1` text;', - ]); - - for (const st of sqlStatements) { - await context.client.query(st); - } - - const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( - schema2, - {}, - [], - false, - ); - - for (const st of dropStatements) { - await context.client.query(st); - } + return {} as any; }, alterGeneratedConstraint: async function(context: any): Promise { - const schema1 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name}`, - { mode: 'virtual' }, - ), - }), - }; - const schema2 = { - users: singlestoreTable('users', { - id: int('id'), - id2: int('id2'), - name: text('name'), - generatedName: text('gen_name').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'stored' }, - ), - generatedName1: text('gen_name1').generatedAlwaysAs( - (): SQL => sql`${schema2.users.name} || 'hello'`, - { mode: 'virtual' }, - ), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - context.client as Connection, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([]); - expect(sqlStatements).toStrictEqual([]); - - const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( - schema2, - {}, - [], - false, - ); - - for (const st of dropStatements) { - await context.client.query(st); - } + return {} as any; }, createTableWithGeneratedConstraint: function(context?: any): Promise { return {} as any; @@ -667,7 +337,8 @@ const singlestoreSuite: DialectSuite = { run( singlestoreSuite, async (context: any) => { - const connectionString = process.env.SINGLESTORE_CONNECTION_STRING ?? await createDockerDB(context); + const connectionString = process.env.SINGLESTORE_CONNECTION_STRING + ?? (await createDockerDB(context)); const sleep = 1000; let timeLeft = 20000; @@ -691,6 +362,9 @@ run( await context.singlestoreContainer?.stop().catch(console.error); throw lastError; } + + await context.client.query('CREATE DATABASE drizzle;'); + await context.client.query('USE drizzle;'); }, async (context: any) => { await context.client?.end().catch(console.error); diff --git a/drizzle-kit/vitest.config.ts b/drizzle-kit/vitest.config.ts index 8f22123dd..d8ee4a881 100644 --- a/drizzle-kit/vitest.config.ts +++ b/drizzle-kit/vitest.config.ts @@ -4,12 +4,17 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { include: [ - 'tests/**/*.test.ts', + // 'tests/**/*.test.ts', + // Need to test it first before pushing changes + 'tests/singlestore-schemas.test.ts', + 'tests/singlestore-views.test.ts', + 'tests/push/singlestore-push.test.ts', + 'tests/push/singlestore.test.ts', ], - exclude: [ - 'tests/**/singlestore-generated.test.ts', - ], + // This one was excluded because we need to modify an API for SingleStore-generated columns. + // It’s in the backlog. + exclude: ['tests/**/singlestore-generated.test.ts'], typecheck: { tsconfig: 'tsconfig.json', From e9db7f1d5d482408b2ed532ecea5badd6bdc1672 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Thu, 7 Nov 2024 19:44:26 +0000 Subject: [PATCH 320/492] fix some singlestore drizzle kit tests --- .../imports-checker/grammar/grammar.ohm | 4 - drizzle-kit/src/introspect-singlestore.ts | 2 +- drizzle-kit/src/jsonStatements.ts | 2 + .../src/serializer/singlestoreSerializer.ts | 3 - drizzle-kit/src/snapshotsDiffer.ts | 2 +- drizzle-kit/src/sqlgenerator.ts | 2 + .../tests/push/singlestore-push.test.ts | 130 ++---------------- drizzle-kit/tests/push/singlestore.test.ts | 30 ++-- drizzle-kit/tests/schemaDiffer.ts | 3 +- .../singlestore-core/columns/date.common.ts | 2 +- 10 files changed, 29 insertions(+), 151 deletions(-) diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm b/drizzle-kit/imports-checker/grammar/grammar.ohm index 4b7ba55e4..8d9b5e718 100644 --- a/drizzle-kit/imports-checker/grammar/grammar.ohm +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm @@ -118,8 +118,4 @@ JSImports { unicodeConnectorPunctuation = "\u005F" | "\u203F".."\u2040" | "\u30FB" | "\uFE33".."\uFE34" | "\uFE4D".."\uFE4F" | "\uFF3F" | "\uFF65" unicodeSpaceSeparator = "\u2000".."\u200B" | "\u3000" -<<<<<<< HEAD } -======= -} ->>>>>>> cd33310f (imports checker with OHM grammar + fix of imports issues) diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts index 8aa6e3dd7..3643241ad 100644 --- a/drizzle-kit/src/introspect-singlestore.ts +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -387,7 +387,7 @@ const column = ( : `${casing(name)}: timestamp("${name}")`; // TODO: check if SingleStore has defaultNow() or now() - defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' + defaultValue = defaultValue === 'now()' || defaultValue === 'CURRENT_TIMESTAMP()' ? '.defaultNow()' : defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 8cd792fe9..418083b8a 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -934,6 +934,8 @@ export const prepareSingleStoreCreateTableJson = ( ): JsonCreateTableStatement => { const { name, schema, columns, compositePrimaryKeys, uniqueConstraints } = table; + console.log('prepareSingleStoreCreateTableJson', columns); + return { type: 'create_table', tableName: name, diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index 3224306dd..472bb7351 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -154,9 +154,6 @@ export const generateSingleStoreSnapshot = ( columnToSet.default = column.default; } } - if (['blob', 'text', 'json'].includes(column.getSQLType())) { - columnToSet.default = `(${columnToSet.default})`; - } } } columnsObject[column.name] = columnToSet; diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 44bd0a713..a93379aa1 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -3218,7 +3218,7 @@ export const applySingleStoreSnapshotsDiff = async ( jsonStatements.push(...jsonAlteredUniqueConstraints); - const sqlStatements = fromJson(jsonStatements, 'mysql'); + const sqlStatements = fromJson(jsonStatements, 'singlestore'); const uniqueSqlStatements: string[] = []; sqlStatements.forEach((ss) => { diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index e74e1e50a..1bfa12ad5 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -588,10 +588,12 @@ class SingleStoreCreateTableConvertor extends Convertor { internals, } = st; + let statement = ''; statement += `CREATE TABLE \`${tableName}\` (\n`; for (let i = 0; i < columns.length; i++) { const column = columns[i]; + console.log('SingleStoreCreateTableConvertor', column.default); const primaryKeyStatement = column.primaryKey ? ' PRIMARY KEY' : ''; const notNullStatement = column.notNull ? ' NOT NULL' : ''; diff --git a/drizzle-kit/tests/push/singlestore-push.test.ts b/drizzle-kit/tests/push/singlestore-push.test.ts index 79eeebbb5..5098a92a1 100644 --- a/drizzle-kit/tests/push/singlestore-push.test.ts +++ b/drizzle-kit/tests/push/singlestore-push.test.ts @@ -78,125 +78,8 @@ if (!fs.existsSync('tests/push/singlestore')) { fs.mkdirSync('tests/push/singlestore'); } -test('add check constraint to table', async () => { - const schema1 = { - test: singlestoreTable('test', { - id: int('id').primaryKey(), - values: int('values'), - }), - }; - const schema2 = { - test: singlestoreTable('test', { - id: int('id').primaryKey(), - values: int('values'), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - client, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([ - { - type: 'create_check_constraint', - tableName: 'test', - schema: '', - data: 'some_check1;`test`.`values` < 100', - }, - { - data: "some_check2;'test' < 100", - schema: '', - tableName: 'test', - type: 'create_check_constraint', - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `test` ADD CONSTRAINT `some_check1` CHECK (`test`.`values` < 100);', - `ALTER TABLE \`test\` ADD CONSTRAINT \`some_check2\` CHECK ('test' < 100);`, - ]); - - await client.query(`DROP TABLE \`test\`;`); -}); - -test('drop check constraint to table', async () => { - const schema1 = { - test: singlestoreTable('test', { - id: int('id').primaryKey(), - values: int('values'), - }), - }; - const schema2 = { - test: singlestoreTable('test', { - id: int('id').primaryKey(), - values: int('values'), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - client, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([ - { - type: 'delete_check_constraint', - tableName: 'test', - schema: '', - constraintName: 'some_check1', - }, - { - constraintName: 'some_check2', - schema: '', - tableName: 'test', - type: 'delete_check_constraint', - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `test` DROP CONSTRAINT `some_check1`;', - `ALTER TABLE \`test\` DROP CONSTRAINT \`some_check2\`;`, - ]); - - await client.query(`DROP TABLE \`test\`;`); -}); - -test('db has checks. Push with same names', async () => { - const schema1 = { - test: singlestoreTable('test', { - id: int('id').primaryKey(), - values: int('values').default(1), - }), - }; - const schema2 = { - test: singlestoreTable('test', { - id: int('id').primaryKey(), - values: int('values').default(1), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - client, - schema1, - schema2, - [], - 'drizzle', - ); - - expect(statements).toStrictEqual([]); - expect(sqlStatements).toStrictEqual([]); - - await client.query(`DROP TABLE \`test\`;`); -}); - -test('create view', async () => { +// SingleStore views in a work in progress state +test.skip('create view', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); @@ -239,7 +122,8 @@ VIEW \`view\` AS (select \`id\` from \`test\`);`, await client.query(`DROP TABLE \`test\`;`); }); -test('drop view', async () => { +// SingleStore views in a work in progress state +test.skip('drop view', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); @@ -273,7 +157,8 @@ test('drop view', async () => { await client.query(`DROP VIEW \`view\`;`); }); -test('alter view ".as"', async () => { +// SingleStore views in a work in progress state +test.skip('alter view ".as"', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); @@ -309,7 +194,8 @@ test('alter view ".as"', async () => { await client.query(`DROP VIEW \`view\`;`); }); -test('alter meta options with distinct in definition', async () => { +// SingleStore views in a work in progress state +test.skip('alter meta options with distinct in definition', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 798d018f6..39d228060 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -1,18 +1,15 @@ import Docker from 'dockerode'; -import { SQL, sql } from 'drizzle-orm'; +import { sql } from 'drizzle-orm'; import { bigint, binary, char, date, - datetime, decimal, double, float, int, - json, mediumint, - serial, singlestoreEnum, singlestoreTable, smallint, @@ -22,7 +19,7 @@ import { tinyint, varbinary, varchar, - year, + year } from 'drizzle-orm/singlestore-core'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; @@ -183,10 +180,6 @@ const singlestoreSuite: DialectSuite = { columnDefaultSql: smallint('column_default_sql').default(101), }), - allSmallSerials: singlestoreTable('all_small_serials', { - columnAll: serial('column_all').primaryKey().notNull(), - }), - allTInts: singlestoreTable('all_t_ints', { simple: tinyint('simple'), columnNotNull: tinyint('column_not_null').notNull(), @@ -202,16 +195,16 @@ const singlestoreSuite: DialectSuite = { }), allTimes: singlestoreTable('all_times', { - simple: time('simple', { fsp: 1 }), + simple: time('simple', { fsp: 0 }), columnNotNull: time('column_not_null').notNull(), columnDefault: time('column_default').default('22:12:12'), }), allTimestamps: singlestoreTable('all_timestamps', { columnDateNow: timestamp('column_date_now', { - fsp: 1, + fsp: 0, mode: 'string', - }).default(sql`(now())`), + }).default(sql`now()`), columnAll: timestamp('column_all', { mode: 'string' }) .default('2023-03-01 14:05:29') .notNull(), @@ -234,9 +227,6 @@ const singlestoreSuite: DialectSuite = { allVarbinaries: singlestoreTable('all_varbinaries', { simple: varbinary('simple', { length: 100 }), columnNotNull: varbinary('column_not_null', { length: 100 }).notNull(), - columnDefault: varbinary('column_default', { length: 12 }).default( - sql`(uuid_to_bin(uuid()))`, - ), }), allYears: singlestoreTable('all_years', { @@ -248,9 +238,6 @@ const singlestoreSuite: DialectSuite = { binafry: singlestoreTable('binary', { simple: binary('simple', { length: 1 }), columnNotNull: binary('column_not_null', { length: 1 }).notNull(), - columnDefault: binary('column_default', { length: 12 }).default( - sql`(uuid_to_bin(uuid()))`, - ), }), }; @@ -262,6 +249,7 @@ const singlestoreSuite: DialectSuite = { 'drizzle', false, ); + console.log(statements); expect(statements.length).toBe(2); expect(statements).toEqual([ { @@ -332,6 +320,12 @@ const singlestoreSuite: DialectSuite = { createTableWithGeneratedConstraint: function(context?: any): Promise { return {} as any; }, + createCompositePrimaryKey: function(context?: any): Promise { + return {} as any; + }, + renameTableWithCompositePrimaryKey: function(context?: any): Promise { + return {} as any; + } }; run( diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 5d4cdbdcf..aa9a2a848 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -33,6 +33,7 @@ import { roleResolver, schemasResolver, sequencesResolver, + singleStoreViewsResolver, sqliteViewsResolver, tablesResolver, viewsResolver, @@ -1610,7 +1611,7 @@ export const diffTestSchemasPushSingleStore = async ( sn2, tablesResolver, columnsResolver, - mySqlViewsResolver, + singleStoreViewsResolver, validatedPrev, validatedCur, 'push', diff --git a/drizzle-orm/src/singlestore-core/columns/date.common.ts b/drizzle-orm/src/singlestore-core/columns/date.common.ts index 8afac71d0..39b2507eb 100644 --- a/drizzle-orm/src/singlestore-core/columns/date.common.ts +++ b/drizzle-orm/src/singlestore-core/columns/date.common.ts @@ -21,7 +21,7 @@ export abstract class SingleStoreDateColumnBaseBuilder< static override readonly [entityKind]: string = 'SingleStoreDateColumnBuilder'; defaultNow() { - return this.default(sql`(now())`); + return this.default(sql`now()`); } onUpdateNow(): HasDefault { From 4f163ccd6a4e77683a6beefbf69d56f6fce9a0d6 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Fri, 8 Nov 2024 16:05:40 +0200 Subject: [PATCH 321/492] fix drizzle-seed --- drizzle-seed/package.json | 2 +- drizzle-seed/src/services/SeedService.ts | 6 ++++- integration-tests/package.json | 3 +-- package.json | 1 + pnpm-lock.yaml | 28 +++++++----------------- pnpm-workspace.yaml | 2 +- 6 files changed, 17 insertions(+), 25 deletions(-) diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index 86edaf97b..8f3aa11d4 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -41,7 +41,7 @@ }, "devDependencies": { "@arethetypeswrong/cli": "^0.16.1", - "@electric-sql/pglite": "^0.1.5", + "@electric-sql/pglite": "^0.2.12", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.6", "@types/better-sqlite3": "^7.6.11", diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index fd78b647a..b8f8bbd73 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -3,6 +3,7 @@ import type { MySqlTable } from 'drizzle-orm/mysql-core'; import { MySqlDatabase } from 'drizzle-orm/mysql-core'; import type { PgTable } from 'drizzle-orm/pg-core'; import { PgDatabase } from 'drizzle-orm/pg-core'; +import { PgliteSession } from 'drizzle-orm/pglite'; import type { SQLiteTable } from 'drizzle-orm/sqlite-core'; import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core'; import type { @@ -44,6 +45,7 @@ class SeedService { static readonly [entityKind]: string = 'SeedService'; private defaultCountForTable = 10; + private postgresPgLiteMaxParametersNumber = 32740; private postgresMaxParametersNumber = 65535; // there is no max parameters number in mysql, so you can increase mysqlMaxParametersNumber if it's needed. private mysqlMaxParametersNumber = 100000; @@ -1094,7 +1096,9 @@ class SeedService { // console.timeEnd("initiate generators"); let maxParametersNumber: number; if (is(db, PgDatabase)) { - maxParametersNumber = this.postgresMaxParametersNumber; + maxParametersNumber = is(db._.session, PgliteSession) + ? this.postgresPgLiteMaxParametersNumber + : this.postgresMaxParametersNumber; } else if (is(db, MySqlDatabase)) { maxParametersNumber = this.mysqlMaxParametersNumber; } else { diff --git a/integration-tests/package.json b/integration-tests/package.json index 51d29197c..776deb153 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -17,7 +17,7 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20241004.0", "@libsql/client": "^0.10.0", - "@neondatabase/serverless": "0.9.0", + "@neondatabase/serverless": "^0.9.0", "@originjs/vite-plugin-commonjs": "^1.0.3", "@paralleldrive/cuid2": "^2.2.2", "@types/async-retry": "^1.4.8", @@ -61,7 +61,6 @@ "drizzle-typebox": "workspace:../drizzle-typebox/dist", "drizzle-valibot": "workspace:../drizzle-valibot/dist", "drizzle-zod": "workspace:../drizzle-zod/dist", - "drizzle-seed": "workspace:../drizzle-seed/dist", "express": "^4.18.2", "get-port": "^7.0.0", "mysql2": "^3.3.3", diff --git a/package.json b/package.json index 29189a91b..721931ac8 100755 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "drizzle-kit": "^0.19.13", "drizzle-orm": "workspace:./drizzle-orm/dist", "drizzle-orm-old": "npm:drizzle-orm@^0.27.2", + "drizzle-seed": "workspace:./drizzle-seed/dist", "eslint": "^8.50.0", "eslint-plugin-drizzle-internal": "link:eslint/eslint-plugin-drizzle-internal", "eslint-plugin-import": "^2.28.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 09ae4508e..79ec83a3d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ importers: drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.687.0)(@cloudflare/workers-types@4.20241106.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.5)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.10)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.1.34)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.3.3)(pg@8.13.1)(postgres@3.4.5)(sql.js@1.12.0)(sqlite3@5.1.7) + drizzle-seed: + specifier: workspace:./drizzle-seed/dist + version: link:drizzle-seed/dist eslint: specifier: ^8.50.0 version: 8.57.1 @@ -428,8 +431,8 @@ importers: specifier: ^0.16.1 version: 0.16.4 '@electric-sql/pglite': - specifier: ^0.1.5 - version: 0.1.5 + specifier: ^0.2.12 + version: 0.2.12 '@rollup/plugin-terser': specifier: ^0.4.4 version: 0.4.4(rollup@4.24.4) @@ -688,9 +691,6 @@ importers: drizzle-prisma-generator: specifier: ^0.1.2 version: 0.1.7 - drizzle-seed: - specifier: workspace:../drizzle-seed/dist - version: link:../drizzle-seed/dist drizzle-typebox: specifier: workspace:../drizzle-typebox/dist version: link:../drizzle-typebox/dist @@ -750,8 +750,8 @@ importers: specifier: ^4.20241004.0 version: 4.20241106.0 '@neondatabase/serverless': - specifier: 0.9.0 - version: 0.9.0 + specifier: ^0.9.0 + version: 0.9.5 '@originjs/vite-plugin-commonjs': specifier: ^1.0.3 version: 1.0.3 @@ -1850,9 +1850,6 @@ packages: '@drizzle-team/studio@0.0.5': resolution: {integrity: sha512-ps5qF0tMxWRVu+V5gvCRrQNqlY92aTnIKdq27gm9LZMSdaKYZt6AVvSK1dlUMzs6Rt0Jm80b+eWct6xShBKhIw==} - '@electric-sql/pglite@0.1.5': - resolution: {integrity: sha512-eymv4ONNvoPZQTvOQIi5dbpR+J5HzEv0qQH9o/y3gvNheJV/P/NFcrbsfJZYTsDKoq7DKrTiFNexsRkJKy8x9Q==} - '@electric-sql/pglite@0.2.12': resolution: {integrity: sha512-J/X42ujcoFEbOkgRyoNqZB5qcqrnJRWVlwpH3fKYoJkTz49N91uAK/rDSSG/85WRas9nC9mdV4FnMTxnQWE/rw==} @@ -2990,9 +2987,6 @@ packages: '@neondatabase/serverless@0.7.2': resolution: {integrity: sha512-wU3WA2uTyNO7wjPs3Mg0G01jztAxUxzd9/mskMmtPwPTjf7JKWi9AW5/puOGXLxmZ9PVgRFeBVRVYq5nBPhsCg==} - '@neondatabase/serverless@0.9.0': - resolution: {integrity: sha512-mmJnUAzlzvxNSZuuhI6kgJjH+JgFdBMYUWxihtq/nj0Tjt+Y5UU3W+SvRFoucnd5NObYkuLYQzk+zV5DGFKGJg==} - '@neondatabase/serverless@0.9.5': resolution: {integrity: sha512-siFas6gItqv6wD/pZnvdu34wEqgG3nSE6zWZdq5j2DEsa+VvX8i/5HXJOo06qrw5axPXn+lGCxeR+NLaSPIXug==} @@ -10928,8 +10922,6 @@ snapshots: '@drizzle-team/studio@0.0.5': {} - '@electric-sql/pglite@0.1.5': {} - '@electric-sql/pglite@0.2.12': {} '@esbuild-kit/core-utils@3.3.2': @@ -11920,10 +11912,6 @@ snapshots: dependencies: '@types/pg': 8.6.6 - '@neondatabase/serverless@0.9.0': - dependencies: - '@types/pg': 8.6.6 - '@neondatabase/serverless@0.9.5': dependencies: '@types/pg': 8.11.6 @@ -12838,7 +12826,7 @@ snapshots: '@types/pg@8.6.6': dependencies: - '@types/node': 20.17.6 + '@types/node': 18.19.64 pg-protocol: 1.7.0 pg-types: 2.2.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 72d3f184a..0a4ddf3b4 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,6 +4,6 @@ packages: - drizzle-zod - drizzle-typebox - drizzle-valibot + - drizzle-seed - integration-tests - eslint-plugin-drizzle - - drizzle-seed From 7be73dff4b9c190b821bd644a7fa08a1e1f53405 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Mon, 11 Nov 2024 16:18:05 +0000 Subject: [PATCH 322/492] update SingleStore decimal column type --- .../src/singlestore-core/columns/decimal.ts | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts index 112ca86ee..980b8a5e9 100644 --- a/drizzle-orm/src/singlestore-core/columns/decimal.ts +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -20,10 +20,11 @@ export class SingleStoreDecimalBuilder< > extends SingleStoreColumnBuilderWithAutoIncrement { static override readonly [entityKind]: string = 'SingleStoreDecimalBuilder'; - constructor(name: T['name'], precision?: number, scale?: number) { + constructor(name: T['name'], config: SingleStoreDecimalConfig | undefined) { super(name, 'string', 'SingleStoreDecimal'); - this.config.precision = precision; - this.config.scale = scale; + this.config.precision = config?.precision; + this.config.scale = config?.scale; + this.config.unsigned = config?.unsigned; } /** @internal */ @@ -44,21 +45,26 @@ export class SingleStoreDecimal; @@ -71,5 +77,5 @@ export function decimal( ): SingleStoreDecimalBuilderInitial; export function decimal(a?: string | SingleStoreDecimalConfig, b: SingleStoreDecimalConfig = {}) { const { name, config } = getColumnNameAndConfig(a, b); - return new SingleStoreDecimalBuilder(name, config.precision, config.scale); + return new SingleStoreDecimalBuilder(name, config); } From 198fbc2128359f32ba88147f9374c7f06ed978ae Mon Sep 17 00:00:00 2001 From: prodrigues Date: Mon, 11 Nov 2024 16:22:11 +0000 Subject: [PATCH 323/492] remove unnecessary logs --- drizzle-kit/tests/push/singlestore.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 39d228060..41a984b08 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -249,7 +249,7 @@ const singlestoreSuite: DialectSuite = { 'drizzle', false, ); - console.log(statements); + expect(statements.length).toBe(2); expect(statements).toEqual([ { From 40e0037e8974296c9d157a5623a3867006c95969 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 11 Nov 2024 18:31:26 +0200 Subject: [PATCH 324/492] Fixed type parsing --- .../src/serializer/singlestoreSerializer.ts | 27 +- .../tests/push/singlestore-push.test.ts | 14 +- drizzle-kit/tests/push/singlestore.test.ts | 41 +- drizzle-kit/tests/schemaDiffer.ts | 1083 ++++++++++------- 4 files changed, 650 insertions(+), 515 deletions(-) diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index 3224306dd..5b6f005c6 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -154,9 +154,9 @@ export const generateSingleStoreSnapshot = ( columnToSet.default = column.default; } } - if (['blob', 'text', 'json'].includes(column.getSQLType())) { - columnToSet.default = `(${columnToSet.default})`; - } + // if (['blob', 'text', 'json'].includes(column.getSQLType())) { + // columnToSet.default = `(${columnToSet.default})`; + // } } } columnsObject[column.name] = columnToSet; @@ -489,6 +489,7 @@ export const fromDatabase = async ( const isNullable = column['IS_NULLABLE'] === 'YES'; // 'YES', 'NO' const dataType = column['DATA_TYPE']; // varchar const columnType = column['COLUMN_TYPE']; // varchar(256) + // const columnType = column["DATA_TYPE"]; const isPrimary = column['COLUMN_KEY'] === 'PRI'; // 'PRI', '' const columnDefault: string = column['COLUMN_DEFAULT']; const collation: string = column['CHARACTER_SET_NAME']; @@ -534,10 +535,24 @@ export const fromDatabase = async ( } } - if (columnType.startsWith('tinyint')) { - changedType = 'tinyint'; + if ( + columnType.startsWith('bigint(') + || columnType.startsWith('tinyint(') + || columnType.startsWith('date(') + || columnType.startsWith('int(') + || columnType.startsWith('mediumint(') + || columnType.startsWith('smallint(') + || columnType.startsWith('text(') + || columnType.startsWith('time(') + || columnType.startsWith('year(') + ) { + changedType = columnType.replace(/\(\s*[^)]*\)$/, ''); } + // if (columnType.includes("decimal(10,0)")) { + // changedType = columnType.replace("decimal(10,0)", "decimal"); + // } + let onUpdate: boolean | undefined = undefined; if ( columnType.startsWith('timestamp') @@ -551,7 +566,7 @@ export const fromDatabase = async ( default: columnDefault === null ? undefined : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) - && !columnType.startsWith('decimal') + && !['decimal', 'char', 'varchar'].some((type) => columnType.startsWith(type)) ? Number(columnDefault) : isDefaultAnExpression ? clearDefaults(columnDefault, collation) diff --git a/drizzle-kit/tests/push/singlestore-push.test.ts b/drizzle-kit/tests/push/singlestore-push.test.ts index 79eeebbb5..bd6f9d342 100644 --- a/drizzle-kit/tests/push/singlestore-push.test.ts +++ b/drizzle-kit/tests/push/singlestore-push.test.ts @@ -78,7 +78,7 @@ if (!fs.existsSync('tests/push/singlestore')) { fs.mkdirSync('tests/push/singlestore'); } -test('add check constraint to table', async () => { +test.skip('add check constraint to table', async () => { const schema1 = { test: singlestoreTable('test', { id: int('id').primaryKey(), @@ -123,7 +123,7 @@ test('add check constraint to table', async () => { await client.query(`DROP TABLE \`test\`;`); }); -test('drop check constraint to table', async () => { +test.skip('drop check constraint to table', async () => { const schema1 = { test: singlestoreTable('test', { id: int('id').primaryKey(), @@ -168,7 +168,7 @@ test('drop check constraint to table', async () => { await client.query(`DROP TABLE \`test\`;`); }); -test('db has checks. Push with same names', async () => { +test.skip('db has checks. Push with same names', async () => { const schema1 = { test: singlestoreTable('test', { id: int('id').primaryKey(), @@ -196,7 +196,7 @@ test('db has checks. Push with same names', async () => { await client.query(`DROP TABLE \`test\`;`); }); -test('create view', async () => { +test.skip('create view', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); @@ -239,7 +239,7 @@ VIEW \`view\` AS (select \`id\` from \`test\`);`, await client.query(`DROP TABLE \`test\`;`); }); -test('drop view', async () => { +test.skip('drop view', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); @@ -273,7 +273,7 @@ test('drop view', async () => { await client.query(`DROP VIEW \`view\`;`); }); -test('alter view ".as"', async () => { +test.skip('alter view ".as"', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); @@ -309,7 +309,7 @@ test('alter view ".as"', async () => { await client.query(`DROP VIEW \`view\`;`); }); -test('alter meta options with distinct in definition', async () => { +test.skip('alter meta options with distinct in definition', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 798d018f6..a6d4e2ada 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -183,9 +183,9 @@ const singlestoreSuite: DialectSuite = { columnDefaultSql: smallint('column_default_sql').default(101), }), - allSmallSerials: singlestoreTable('all_small_serials', { - columnAll: serial('column_all').primaryKey().notNull(), - }), + // allSmallSerials: singlestoreTable("all_small_serials", { + // columnAll: serial("column_all").notNull(), + // }), allTInts: singlestoreTable('all_t_ints', { simple: tinyint('simple'), @@ -202,16 +202,16 @@ const singlestoreSuite: DialectSuite = { }), allTimes: singlestoreTable('all_times', { - simple: time('simple', { fsp: 1 }), + // simple: time("simple", { fsp: 1 }), columnNotNull: time('column_not_null').notNull(), columnDefault: time('column_default').default('22:12:12'), }), allTimestamps: singlestoreTable('all_timestamps', { - columnDateNow: timestamp('column_date_now', { - fsp: 1, - mode: 'string', - }).default(sql`(now())`), + // columnDateNow: timestamp("column_date_now", { + // fsp: 1, + // mode: "string", + // }).default(sql`(now())`), columnAll: timestamp('column_all', { mode: 'string' }) .default('2023-03-01 14:05:29') .notNull(), @@ -234,9 +234,7 @@ const singlestoreSuite: DialectSuite = { allVarbinaries: singlestoreTable('all_varbinaries', { simple: varbinary('simple', { length: 100 }), columnNotNull: varbinary('column_not_null', { length: 100 }).notNull(), - columnDefault: varbinary('column_default', { length: 12 }).default( - sql`(uuid_to_bin(uuid()))`, - ), + columnDefault: varbinary('column_default', { length: 12 }), }), allYears: singlestoreTable('all_years', { @@ -248,9 +246,7 @@ const singlestoreSuite: DialectSuite = { binafry: singlestoreTable('binary', { simple: binary('simple', { length: 1 }), columnNotNull: binary('column_not_null', { length: 1 }).notNull(), - columnDefault: binary('column_default', { length: 12 }).default( - sql`(uuid_to_bin(uuid()))`, - ), + columnDefault: binary('column_default', { length: 12 }), }), }; @@ -262,21 +258,8 @@ const singlestoreSuite: DialectSuite = { 'drizzle', false, ); - expect(statements.length).toBe(2); - expect(statements).toEqual([ - { - type: 'delete_unique_constraint', - tableName: 'all_small_serials', - data: 'column_all;column_all', - schema: '', - }, - { - type: 'delete_unique_constraint', - tableName: 'all_small_serials', - data: 'column_all;column_all', - schema: '', - }, - ]); + expect(statements.length).toBe(0); + expect(statements).toEqual([]); const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( schema1, diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index bd6a850f3..b9f66a079 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -85,16 +85,33 @@ import { export type PostgresSchema = Record< string, - PgTable | PgEnum | PgSchema | PgSequence | PgView | PgMaterializedView | PgRole | PgPolicy + | PgTable + | PgEnum + | PgSchema + | PgSequence + | PgView + | PgMaterializedView + | PgRole + | PgPolicy +>; +export type MysqlSchema = Record< + string, + MySqlTable | MySqlSchema | MySqlView >; -export type MysqlSchema = Record | MySqlSchema | MySqlView>; export type SqliteSchema = Record | SQLiteView>; -export type SinglestoreSchema = Record | SingleStoreSchema | SingleStoreView>; +export type SinglestoreSchema = Record< + string, + SingleStoreTable | SingleStoreSchema | SingleStoreView +>; export const testSchemasResolver = (renames: Set) => async (input: ResolverInput): Promise> => { try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { return { created: input.created, renamed: [], @@ -146,273 +163,297 @@ export const testSchemasResolver = } }; -export const testSequencesResolver = - (renames: Set) => async (input: ResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } +export const testSequencesResolver = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - let createdSequences = [...input.created]; - let deletedSequences = [...input.deleted]; + let createdSequences = [...input.created]; + let deletedSequences = [...input.deleted]; - const result: { - created: Sequence[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Sequence; to: Sequence }[]; - deleted: Sequence[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + const result: { + created: Sequence[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Sequence; to: Sequence }[]; + deleted: Sequence[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - for (let rename of renames) { - const [from, to] = rename.split('->'); + for (let rename of renames) { + const [from, to] = rename.split('->'); - const idxFrom = deletedSequences.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; + const idxFrom = deletedSequences.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdSequences.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdSequences.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const tableFrom = deletedSequences[idxFrom]; + const tableTo = createdSequences[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, }); + } - const tableFrom = deletedSequences[idxFrom]; - const tableTo = createdSequences[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, - }); - } - - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedSequences[idxFrom], - to: createdSequences[idxTo], - }); - } - - delete createdSequences[idxTo]; - delete deletedSequences[idxFrom]; - - createdSequences = createdSequences.filter(Boolean); - deletedSequences = deletedSequences.filter(Boolean); + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedSequences[idxFrom], + to: createdSequences[idxTo], + }); } + + delete createdSequences[idxTo]; + delete deletedSequences[idxFrom]; + + createdSequences = createdSequences.filter(Boolean); + deletedSequences = deletedSequences.filter(Boolean); } + } - result.created = createdSequences; - result.deleted = deletedSequences; + result.created = createdSequences; + result.deleted = deletedSequences; - return result; - } catch (e) { - console.error(e); - throw e; + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const testEnumsResolver = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; } - }; -export const testEnumsResolver = - (renames: Set) => async (input: ResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } + let createdEnums = [...input.created]; + let deletedEnums = [...input.deleted]; - let createdEnums = [...input.created]; - let deletedEnums = [...input.deleted]; + const result: { + created: Enum[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Enum; to: Enum }[]; + deleted: Enum[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const result: { - created: Enum[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Enum; to: Enum }[]; - deleted: Enum[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + for (let rename of renames) { + const [from, to] = rename.split('->'); - for (let rename of renames) { - const [from, to] = rename.split('->'); + const idxFrom = deletedEnums.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); - const idxFrom = deletedEnums.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; + if (idxFrom >= 0) { + const idxTo = createdEnums.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdEnums.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const tableFrom = deletedEnums[idxFrom]; + const tableTo = createdEnums[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, }); + } - const tableFrom = deletedEnums[idxFrom]; - const tableTo = createdEnums[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, - }); - } - - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedEnums[idxFrom], - to: createdEnums[idxTo], - }); - } - - delete createdEnums[idxTo]; - delete deletedEnums[idxFrom]; - - createdEnums = createdEnums.filter(Boolean); - deletedEnums = deletedEnums.filter(Boolean); + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedEnums[idxFrom], + to: createdEnums[idxTo], + }); } + + delete createdEnums[idxTo]; + delete deletedEnums[idxFrom]; + + createdEnums = createdEnums.filter(Boolean); + deletedEnums = deletedEnums.filter(Boolean); } + } - result.created = createdEnums; - result.deleted = deletedEnums; + result.created = createdEnums; + result.deleted = deletedEnums; - return result; - } catch (e) { - console.error(e); - throw e; + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const testTablesResolver = (renames: Set) => +async ( + input: ResolverInput
, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; } - }; -export const testTablesResolver = - (renames: Set) => async (input: ResolverInput
): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } + let createdTables = [...input.created]; + let deletedTables = [...input.deleted]; - let createdTables = [...input.created]; - let deletedTables = [...input.deleted]; + const result: { + created: Table[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Table; to: Table }[]; + deleted: Table[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const result: { - created: Table[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Table; to: Table }[]; - deleted: Table[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + for (let rename of renames) { + const [from, to] = rename.split('->'); - for (let rename of renames) { - const [from, to] = rename.split('->'); + const idxFrom = deletedTables.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); - const idxFrom = deletedTables.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; + if (idxFrom >= 0) { + const idxTo = createdTables.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdTables.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const tableFrom = deletedTables[idxFrom]; + const tableTo = createdTables[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, }); + } - const tableFrom = deletedTables[idxFrom]; - const tableTo = createdTables[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, - }); - } - - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedTables[idxFrom], - to: createdTables[idxTo], - }); - } - - delete createdTables[idxTo]; - delete deletedTables[idxFrom]; - - createdTables = createdTables.filter(Boolean); - deletedTables = deletedTables.filter(Boolean); + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedTables[idxFrom], + to: createdTables[idxTo], + }); } + + delete createdTables[idxTo]; + delete deletedTables[idxFrom]; + + createdTables = createdTables.filter(Boolean); + deletedTables = deletedTables.filter(Boolean); } + } - result.created = createdTables; - result.deleted = deletedTables; + result.created = createdTables; + result.deleted = deletedTables; - return result; - } catch (e) { - console.error(e); - throw e; + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const testColumnsResolver = (renames: Set) => +async ( + input: ColumnsResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + tableName: input.tableName, + schema: input.schema, + created: input.created, + renamed: [], + deleted: input.deleted, + }; } - }; -export const testColumnsResolver = - (renames: Set) => async (input: ColumnsResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - tableName: input.tableName, - schema: input.schema, - created: input.created, - renamed: [], - deleted: input.deleted, - }; - } + let createdColumns = [...input.created]; + let deletedColumns = [...input.deleted]; - let createdColumns = [...input.created]; - let deletedColumns = [...input.deleted]; + const renamed: { from: Column; to: Column }[] = []; - const renamed: { from: Column; to: Column }[] = []; + const schema = input.schema || 'public'; - const schema = input.schema || 'public'; + for (let rename of renames) { + const [from, to] = rename.split('->'); - for (let rename of renames) { - const [from, to] = rename.split('->'); + const idxFrom = deletedColumns.findIndex((it) => { + return `${schema}.${input.tableName}.${it.name}` === from; + }); - const idxFrom = deletedColumns.findIndex((it) => { - return `${schema}.${input.tableName}.${it.name}` === from; + if (idxFrom >= 0) { + const idxTo = createdColumns.findIndex((it) => { + return `${schema}.${input.tableName}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdColumns.findIndex((it) => { - return `${schema}.${input.tableName}.${it.name}` === to; - }); - - renamed.push({ - from: deletedColumns[idxFrom], - to: createdColumns[idxTo], - }); + renamed.push({ + from: deletedColumns[idxFrom], + to: createdColumns[idxTo], + }); - delete createdColumns[idxTo]; - delete deletedColumns[idxFrom]; + delete createdColumns[idxTo]; + delete deletedColumns[idxFrom]; - createdColumns = createdColumns.filter(Boolean); - deletedColumns = deletedColumns.filter(Boolean); - } + createdColumns = createdColumns.filter(Boolean); + deletedColumns = deletedColumns.filter(Boolean); } - - return { - tableName: input.tableName, - schema: input.schema, - created: createdColumns, - deleted: deletedColumns, - renamed, - }; - } catch (e) { - console.error(e); - throw e; } - }; + + return { + tableName: input.tableName, + schema: input.schema, + created: createdColumns, + deleted: deletedColumns, + renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; export const testPolicyResolver = (renames: Set) => async ( @@ -594,279 +635,301 @@ async ( } }; -export const testViewsResolver = - (renames: Set) => async (input: ResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } +export const testViewsResolver = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - let createdViews = [...input.created]; - let deletedViews = [...input.deleted]; + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; - const result: { - created: View[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: View; to: View }[]; - deleted: View[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + const result: { + created: View[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: View; to: View }[]; + deleted: View[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - for (let rename of renames) { - const [from, to] = rename.split('->'); + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); - const idxFrom = deletedViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, }); + } - const viewFrom = deletedViews[idxFrom]; - const viewTo = createdViews[idxFrom]; - - if (viewFrom.schema !== viewTo.schema) { - result.moved.push({ - name: viewFrom.name, - schemaFrom: viewFrom.schema, - schemaTo: viewTo.schema, - }); - } - - if (viewFrom.name !== viewTo.name) { - result.renamed.push({ - from: deletedViews[idxFrom], - to: createdViews[idxTo], - }); - } - - delete createdViews[idxTo]; - delete deletedViews[idxFrom]; - - createdViews = createdViews.filter(Boolean); - deletedViews = deletedViews.filter(Boolean); + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); } + } - result.created = createdViews; - result.deleted = deletedViews; + result.created = createdViews; + result.deleted = deletedViews; - return result; - } catch (e) { - console.error(e); - throw e; + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const testViewsResolverMySql = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; } - }; -export const testViewsResolverMySql = - (renames: Set) => - async (input: ResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; - let createdViews = [...input.created]; - let deletedViews = [...input.deleted]; + const result: { + created: ViewSquashed[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: ViewSquashed; to: ViewSquashed }[]; + deleted: ViewSquashed[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const result: { - created: ViewSquashed[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: ViewSquashed; to: ViewSquashed }[]; - deleted: ViewSquashed[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + for (let rename of renames) { + const [from, to] = rename.split('->'); - for (let rename of renames) { - const [from, to] = rename.split('->'); + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); - const idxFrom = deletedViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, }); + } - const viewFrom = deletedViews[idxFrom]; - const viewTo = createdViews[idxFrom]; - - if (viewFrom.schema !== viewTo.schema) { - result.moved.push({ - name: viewFrom.name, - schemaFrom: viewFrom.schema, - schemaTo: viewTo.schema, - }); - } - - if (viewFrom.name !== viewTo.name) { - result.renamed.push({ - from: deletedViews[idxFrom], - to: createdViews[idxTo], - }); - } - - delete createdViews[idxTo]; - delete deletedViews[idxFrom]; - - createdViews = createdViews.filter(Boolean); - deletedViews = deletedViews.filter(Boolean); + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); } + } - result.created = createdViews; - result.deleted = deletedViews; + result.created = createdViews; + result.deleted = deletedViews; - return result; - } catch (e) { - console.error(e); - throw e; + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const testViewsResolverSingleStore = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; } - }; -export const testViewsResolverSingleStore = - (renames: Set) => - async (input: ResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; - let createdViews = [...input.created]; - let deletedViews = [...input.deleted]; + const result: { + created: ViewSquashed[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: ViewSquashed; to: ViewSquashed }[]; + deleted: ViewSquashed[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const result: { - created: ViewSquashed[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: ViewSquashed; to: ViewSquashed }[]; - deleted: ViewSquashed[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + for (let rename of renames) { + const [from, to] = rename.split('->'); - for (let rename of renames) { - const [from, to] = rename.split('->'); + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); - const idxFrom = deletedViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, }); + } - const viewFrom = deletedViews[idxFrom]; - const viewTo = createdViews[idxFrom]; - - if (viewFrom.schema !== viewTo.schema) { - result.moved.push({ - name: viewFrom.name, - schemaFrom: viewFrom.schema, - schemaTo: viewTo.schema, - }); - } - - if (viewFrom.name !== viewTo.name) { - result.renamed.push({ - from: deletedViews[idxFrom], - to: createdViews[idxTo], - }); - } - - delete createdViews[idxTo]; - delete deletedViews[idxFrom]; - - createdViews = createdViews.filter(Boolean); - deletedViews = deletedViews.filter(Boolean); + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); } - } - result.created = createdViews; - result.deleted = deletedViews; + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; - return result; - } catch (e) { - console.error(e); - throw e; + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } } - }; -export const testViewsResolverSqlite = - (renames: Set) => async (input: ResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } + result.created = createdViews; + result.deleted = deletedViews; - let createdViews = [...input.created]; - let deletedViews = [...input.deleted]; + return result; + } catch (e) { + console.error(e); + throw e; + } +}; - const result: { - created: SqliteView[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: SqliteView; to: SqliteView }[]; - deleted: SqliteView[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; +export const testViewsResolverSqlite = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - for (let rename of renames) { - const [from, to] = rename.split('->'); + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; - const idxFrom = deletedViews.findIndex((it) => { - return it.name === from; - }); + const result: { + created: SqliteView[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: SqliteView; to: SqliteView }[]; + deleted: SqliteView[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - if (idxFrom >= 0) { - const idxTo = createdViews.findIndex((it) => { - return it.name === to; - }); + for (let rename of renames) { + const [from, to] = rename.split('->'); - const viewFrom = deletedViews[idxFrom]; - const viewTo = createdViews[idxFrom]; + const idxFrom = deletedViews.findIndex((it) => { + return it.name === from; + }); - if (viewFrom.name !== viewTo.name) { - result.renamed.push({ - from: deletedViews[idxFrom], - to: createdViews[idxTo], - }); - } + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return it.name === to; + }); - delete createdViews[idxTo]; - delete deletedViews[idxFrom]; + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; - createdViews = createdViews.filter(Boolean); - deletedViews = deletedViews.filter(Boolean); + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); } - } - result.created = createdViews; - result.deleted = deletedViews; + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; - return result; - } catch (e) { - console.error(e); - throw e; + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } } - }; + + result.created = createdViews; + result.deleted = deletedViews; + + return result; + } catch (e) { + console.error(e); + throw e; + } +}; export const diffTestSchemasPush = async ( client: PGlite, @@ -877,13 +940,19 @@ export const diffTestSchemasPush = async ( schemas: string[] = ['public'], casing?: CasingType | undefined, entities?: Entities, - sqlStatementsToRun: { before?: string[]; after?: string[]; runApply?: boolean } = { + sqlStatementsToRun: { + before?: string[]; + after?: string[]; + runApply?: boolean; + } = { before: [], after: [], runApply: true, }, ) => { - const shouldRunApply = sqlStatementsToRun.runApply === undefined ? true : sqlStatementsToRun.runApply; + const shouldRunApply = sqlStatementsToRun.runApply === undefined + ? true + : sqlStatementsToRun.runApply; for (const st of sqlStatementsToRun.before ?? []) { await client.query(st); @@ -1052,7 +1121,10 @@ export const diffTestSchemasPush = async ( } }; -export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | undefined) => { +export const applyPgDiffs = async ( + sn: PostgresSchema, + casing: CasingType | undefined, +) => { const dryRun = { version: '7', dialect: 'postgresql', @@ -1343,7 +1415,10 @@ export const diffTestSchemasPushMysql = async ( } }; -export const applyMySqlDiffs = async (sn: MysqlSchema, casing: CasingType | undefined) => { +export const applyMySqlDiffs = async ( + sn: MysqlSchema, + casing: CasingType | undefined, +) => { const dryRun = { version: '5', dialect: 'mysql', @@ -1478,8 +1553,16 @@ export const diffTestSchemasSingleStore = async ( const rightViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; - const serialized1 = generateSingleStoreSnapshot(leftTables, leftViews, casing); - const serialized2 = generateSingleStoreSnapshot(rightTables, rightViews, casing); + const serialized1 = generateSingleStoreSnapshot( + leftTables, + leftViews, + casing, + ); + const serialized2 = generateSingleStoreSnapshot( + rightTables, + rightViews, + casing, + ); const { version: v1, dialect: d1, ...rest1 } = serialized1; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1544,6 +1627,7 @@ export const diffTestSchemasPushSingleStore = async ( ) => { const { sqlStatements } = await applySingleStoreDiffs(left, casing); for (const st of sqlStatements) { + console.log('st', st); await client.query(st); } // do introspect into PgSchemaInternal @@ -1561,7 +1645,11 @@ export const diffTestSchemasPushSingleStore = async ( const leftViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; - const serialized2 = generateSingleStoreSnapshot(leftTables, leftViews, casing); + const serialized2 = generateSingleStoreSnapshot( + leftTables, + leftViews, + casing, + ); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -1617,7 +1705,10 @@ export const diffTestSchemasPushSingleStore = async ( } }; -export const applySingleStoreDiffs = async (sn: SinglestoreSchema, casing: CasingType | undefined) => { +export const applySingleStoreDiffs = async ( + sn: SinglestoreSchema, + casing: CasingType | undefined, +) => { const dryRun = { version: '1', dialect: 'singlestore', @@ -1863,22 +1954,28 @@ export async function diffTestSchemasPushLibSQL( 'push', ); - const { statementsToExecute, columnsToRemove, infoToPrint, shouldAskForApprove, tablesToRemove, tablesToTruncate } = - await libSqlLogSuggestionsAndReturn( - { - query: async (sql: string, params?: any[]) => { - const res = await client.execute({ sql, args: params || [] }); - return res.rows as T[]; - }, - run: async (query: string) => { - await client.execute(query); - }, + const { + statementsToExecute, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await libSqlLogSuggestionsAndReturn( + { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); }, - statements, - sn1, - sn2, - _meta!, - ); + }, + statements, + sn1, + sn2, + _meta!, + ); return { sqlStatements: statementsToExecute, @@ -2192,7 +2289,9 @@ export const introspectPgToFile = async ( fs.writeFileSync(`tests/introspect/postgres/${testName}.ts`, file.file); // generate snapshot from ts file - const response = await prepareFromPgImports([`tests/introspect/postgres/${testName}.ts`]); + const response = await prepareFromPgImports([ + `tests/introspect/postgres/${testName}.ts`, + ]); const afterFileImports = generatePgSnapshot( response.tables, @@ -2219,7 +2318,10 @@ export const introspectPgToFile = async ( const sn2AfterIm = squashPgScheme(sch2); const validatedCurAfterImport = pgSchema.parse(sch2); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyPgSnapshotsDiff( + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applyPgSnapshotsDiff( initSn, sn2AfterIm, testSchemasResolver(new Set()), @@ -2284,9 +2386,15 @@ export const introspectMySQLToFile = async ( fs.writeFileSync(`tests/introspect/mysql/${testName}.ts`, file.file); - const response = await prepareFromMySqlImports([`tests/introspect/mysql/${testName}.ts`]); + const response = await prepareFromMySqlImports([ + `tests/introspect/mysql/${testName}.ts`, + ]); - const afterFileImports = generateMySqlSnapshot(response.tables, response.views, casing); + const afterFileImports = generateMySqlSnapshot( + response.tables, + response.views, + casing, + ); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -2301,7 +2409,10 @@ export const introspectMySQLToFile = async ( const sn2AfterIm = squashMysqlScheme(sch2); const validatedCurAfterImport = mysqlSchema.parse(sch2); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyMysqlSnapshotsDiff( + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applyMysqlSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), @@ -2351,7 +2462,11 @@ export const introspectSingleStoreToFile = async ( `tests/introspect/singlestore/${testName}.ts`, ]); - const afterFileImports = generateSingleStoreSnapshot(response.tables, response.views, casing); + const afterFileImports = generateSingleStoreSnapshot( + response.tables, + response.views, + casing, + ); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -2368,7 +2483,11 @@ export const introspectSingleStoreToFile = async ( const leftTables = Object.values(initSchema).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; - const initSnapshot = generateSingleStoreSnapshot(leftTables, response.views, casing); + const initSnapshot = generateSingleStoreSnapshot( + leftTables, + response.views, + casing, + ); const { version: initV, dialect: initD, ...initRest } = initSnapshot; @@ -2447,9 +2566,15 @@ export const introspectSQLiteToFile = async ( fs.writeFileSync(`tests/introspect/sqlite/${testName}.ts`, file.file); - const response = await prepareFromSqliteImports([`tests/introspect/sqlite/${testName}.ts`]); + const response = await prepareFromSqliteImports([ + `tests/introspect/sqlite/${testName}.ts`, + ]); - const afterFileImports = generateSqliteSnapshot(response.tables, response.views, casing); + const afterFileImports = generateSqliteSnapshot( + response.tables, + response.views, + casing, + ); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -2464,7 +2589,10 @@ export const introspectSQLiteToFile = async ( const sn2AfterIm = squashSqliteScheme(sch2); const validatedCurAfterImport = sqliteSchema.parse(sch2); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applySqliteSnapshotsDiff( + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applySqliteSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), @@ -2525,9 +2653,15 @@ export const introspectLibSQLToFile = async ( fs.writeFileSync(`tests/introspect/libsql/${testName}.ts`, file.file); - const response = await prepareFromSqliteImports([`tests/introspect/libsql/${testName}.ts`]); + const response = await prepareFromSqliteImports([ + `tests/introspect/libsql/${testName}.ts`, + ]); - const afterFileImports = generateSqliteSnapshot(response.tables, response.views, casing); + const afterFileImports = generateSqliteSnapshot( + response.tables, + response.views, + casing, + ); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -2542,7 +2676,10 @@ export const introspectLibSQLToFile = async ( const sn2AfterIm = squashSqliteScheme(sch2); const validatedCurAfterImport = sqliteSchema.parse(sch2); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyLibSQLSnapshotsDiff( + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applyLibSQLSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), From 28d29f7518aeaf90399cbd54145473a52494d2d0 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 11 Nov 2024 18:50:28 +0200 Subject: [PATCH 325/492] Fix decimal SingleStore --- drizzle-kit/src/serializer/singlestoreSerializer.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index 5b6f005c6..f0e91d892 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -549,9 +549,9 @@ export const fromDatabase = async ( changedType = columnType.replace(/\(\s*[^)]*\)$/, ''); } - // if (columnType.includes("decimal(10,0)")) { - // changedType = columnType.replace("decimal(10,0)", "decimal"); - // } + if (columnType.includes('decimal(10,0)')) { + changedType = columnType.replace('decimal(10,0)', 'decimal'); + } let onUpdate: boolean | undefined = undefined; if ( From 997f94b944127ea67f5ec3e31ca20220e0ef0b9a Mon Sep 17 00:00:00 2001 From: prodrigues Date: Mon, 11 Nov 2024 17:17:56 +0000 Subject: [PATCH 326/492] update SingleStore decimal column type --- drizzle-kit/src/introspect-singlestore.ts | 270 +++++++++++----- .../tests/introspect/singlestore.test.ts | 296 ++++++++++++++++++ drizzle-kit/tests/push/singlestore.test.ts | 6 +- 3 files changed, 497 insertions(+), 75 deletions(-) create mode 100644 drizzle-kit/tests/introspect/singlestore.test.ts diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts index 8aa6e3dd7..588268488 100644 --- a/drizzle-kit/src/introspect-singlestore.ts +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -1,7 +1,16 @@ /* eslint-disable @typescript-eslint/no-unsafe-argument */ +import { toCamelCase } from 'drizzle-orm/casing'; import './@types/utils'; import type { Casing } from './cli/validations/common'; -import { Column, Index, PrimaryKey, SingleStoreSchemaInternal, UniqueConstraint } from './serializer/singlestoreSchema'; +import { assertUnreachable } from './global'; +import { + Column, + Index, + SingleStoreSchema, + SingleStoreSchemaInternal, + PrimaryKey, + UniqueConstraint, +} from './serializer/singlestoreSchema'; import { indexName } from './serializer/singlestoreSerializer'; // time precision to fsp @@ -97,17 +106,33 @@ const importsPatch = { 'timestamp without time zone': 'timestamp', } as Record; -const relations = new Set(); +const escapeColumnKey = (value: string) => { + if (/^(?![a-zA-Z_$][a-zA-Z0-9_$]*$).+$/.test(value)) { + return `"${value}"`; + } + return value; +}; const prepareCasing = (casing?: Casing) => (value: string) => { - if (typeof casing === 'undefined') { - return value; + if (casing === 'preserve') { + return escapeColumnKey(value); } if (casing === 'camel') { - return value.camelCase(); + return escapeColumnKey(value.camelCase()); } - return value; + assertUnreachable(casing); +}; + +const dbColumnName = ({ name, casing, withMode = false }: { name: string; casing: Casing; withMode?: boolean }) => { + if (casing === 'preserve') { + return ''; + } + if (casing === 'camel') { + return toCamelCase(name) === name ? '' : withMode ? `"${name}", ` : `"${name}"`; + } + + assertUnreachable(casing); }; export const schemaToTypeScript = ( @@ -142,6 +167,13 @@ export const schemaToTypeScript = ( patched = patched.startsWith('datetime(') ? 'datetime' : patched; patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; patched = patched.startsWith('int(') ? 'int' : patched; + patched = patched.startsWith('double(') ? 'double' : patched; + patched = patched.startsWith('float(') ? 'float' : patched; + patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; + patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; + patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; + patched = patched.startsWith('bigint unsigned') ? 'bigint' : patched; return patched; }) .filter((type) => { @@ -154,6 +186,37 @@ export const schemaToTypeScript = ( { singlestore: [] as string[] }, ); + Object.values(schema.views).forEach((it) => { + imports.singlestore.push('singlestoreView'); + + const columnImports = Object.values(it.columns) + .map((col) => { + let patched = importsPatch[col.type] ?? col.type; + patched = patched.startsWith('varchar(') ? 'varchar' : patched; + patched = patched.startsWith('char(') ? 'char' : patched; + patched = patched.startsWith('binary(') ? 'binary' : patched; + patched = patched.startsWith('decimal(') ? 'decimal' : patched; + patched = patched.startsWith('smallint(') ? 'smallint' : patched; + patched = patched.startsWith('enum(') ? 'singlestoreEnum' : patched; + patched = patched.startsWith('datetime(') ? 'datetime' : patched; + patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; + patched = patched.startsWith('int(') ? 'int' : patched; + patched = patched.startsWith('double(') ? 'double' : patched; + patched = patched.startsWith('float(') ? 'float' : patched; + patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; + patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; + patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; + patched = patched.startsWith('bigint unsigned') ? 'bigint' : patched; + return patched; + }) + .filter((type) => { + return singlestoreImportsList.has(type); + }); + + imports.singlestore.push(...columnImports); + }); + const tableStatements = Object.values(schema.tables).map((table) => { const func = 'singlestoreTable'; let statement = ''; @@ -168,6 +231,7 @@ export const schemaToTypeScript = ( statement += createTableColumns( Object.values(table.columns), withCasing, + casing, table.name, schema, ); @@ -202,6 +266,36 @@ export const schemaToTypeScript = ( return statement; }); + const viewsStatements = Object.values(schema.views).map((view) => { + const { columns, name, algorithm, definition, sqlSecurity, withCheckOption } = view; + const func = 'singlestoreView'; + let statement = ''; + + if (imports.singlestore.includes(withCasing(name))) { + statement = `// Table name is in conflict with ${ + withCasing( + view.name, + ) + } import.\n// Please change to any other name, that is not in imports list\n`; + } + statement += `export const ${withCasing(name)} = ${func}("${name}", {\n`; + statement += createTableColumns( + Object.values(columns), + withCasing, + casing, + name, + schema, + ); + statement += '})'; + + statement += algorithm ? `.algorithm("${algorithm}")` : ''; + statement += sqlSecurity ? `.sqlSecurity("${sqlSecurity}")` : ''; + statement += withCheckOption ? `.withCheckOption("${withCheckOption}")` : ''; + statement += `.as(sql\`${definition?.replaceAll('`', '\\`')}\`);`; + + return statement; + }); + const uniqueSingleStoreImports = [ 'singlestoreTable', 'singlestoreSchema', @@ -216,6 +310,8 @@ export const schemaToTypeScript = ( let decalrations = ''; decalrations += tableStatements.join('\n\n'); + decalrations += '\n'; + decalrations += viewsStatements.join('\n\n'); const file = importsTs + decalrations; @@ -261,6 +357,7 @@ const column = ( type: string, name: string, casing: (value: string) => string, + rawCasing: Casing, defaultValue?: any, autoincrement?: boolean, onUpdate?: boolean, @@ -272,12 +369,15 @@ const column = ( } if (lowered === 'serial') { - return `${casing(name)}: serial("${name}")`; + return `${casing(name)}: serial(${dbColumnName({ name, casing: rawCasing })})`; } if (lowered.startsWith('int')) { const isUnsigned = lowered.startsWith('int unsigned'); - let out = `${casing(name)}: int("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: int(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' + })`; out += autoincrement ? `.autoincrement()` : ''; out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -287,8 +387,11 @@ const column = ( if (lowered.startsWith('tinyint')) { const isUnsigned = lowered.startsWith('tinyint unsigned'); + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); // let out = `${name.camelCase()}: tinyint("${name}")`; - let out: string = `${casing(name)}: tinyint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + let out: string = `${casing(name)}: tinyint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' + })`; out += autoincrement ? `.autoincrement()` : ''; out += typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -298,7 +401,10 @@ const column = ( if (lowered.startsWith('smallint')) { const isUnsigned = lowered.startsWith('smallint unsigned'); - let out = `${casing(name)}: smallint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: smallint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' + })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -308,7 +414,10 @@ const column = ( if (lowered.startsWith('mediumint')) { const isUnsigned = lowered.startsWith('mediumint unsigned'); - let out = `${casing(name)}: mediumint("${name}"${isUnsigned ? ', { unsigned: true }' : ''})`; + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: mediumint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' + })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -318,7 +427,9 @@ const column = ( if (lowered.startsWith('bigint')) { const isUnsigned = lowered.startsWith('bigint unsigned'); - let out = `${casing(name)}: bigint("${name}", { mode: "number"${isUnsigned ? ', unsigned: true' : ''} })`; + let out = `${casing(name)}: bigint(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: "number"${ + isUnsigned ? ', unsigned: true' : '' + } })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -327,7 +438,7 @@ const column = ( } if (lowered === 'boolean') { - let out = `${casing(name)}: boolean("${name}")`; + let out = `${casing(name)}: boolean(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -336,19 +447,27 @@ const column = ( if (lowered.startsWith('double')) { let params: - | { precision: string | undefined; scale: string | undefined } + | { precision?: string; scale?: string; unsigned?: boolean } | undefined; - if (lowered.length > 6) { + if (lowered.length > (lowered.includes('unsigned') ? 15 : 6)) { const [precision, scale] = lowered - .slice(7, lowered.length - 1) + .slice(7, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) .split(','); params = { precision, scale }; } + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + + const timeConfigParams = params ? timeConfig(params) : undefined; + let out = params - ? `${casing(name)}: double("${name}", ${timeConfig(params)})` - : `${casing(name)}: double("${name}")`; + ? `${casing(name)}: double(${ + dbColumnName({ name, casing: rawCasing, withMode: timeConfigParams !== undefined }) + }${timeConfig(params)})` + : `${casing(name)}: double(${dbColumnName({ name, casing: rawCasing })})`; // let out = `${name.camelCase()}: double("${name}")`; out += defaultValue @@ -357,8 +476,23 @@ const column = ( return out; } - if (lowered === 'float') { - let out = `${casing(name)}: float("${name}")`; + if (lowered.startsWith('float')) { + let params: + | { precision?: string; scale?: string; unsigned?: boolean } + | undefined; + + if (lowered.length > (lowered.includes('unsigned') ? 14 : 5)) { + const [precision, scale] = lowered + .slice(6, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) + .split(','); + params = { precision, scale }; + } + + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + + let out = `${casing(name)}: float(${dbColumnName({ name, casing: rawCasing })}${params ? timeConfig(params) : ''})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -366,7 +500,7 @@ const column = ( } if (lowered === 'real') { - let out = `${casing(name)}: real("${name}")`; + let out = `${casing(name)}: real(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -383,10 +517,12 @@ const column = ( const params = timeConfig({ fsp, mode: "'string'" }); let out = params - ? `${casing(name)}: timestamp("${name}", ${params})` - : `${casing(name)}: timestamp("${name}")`; + ? `${casing(name)}: timestamp(${ + dbColumnName({ name, casing: rawCasing, withMode: params !== undefined }) + }${params})` + : `${casing(name)}: timestamp(${dbColumnName({ name, casing: rawCasing })})`; - // TODO: check if SingleStore has defaultNow() or now() + // singlestore has only CURRENT_TIMESTAMP, as I found from docs. But will leave now() for just a case defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' ? '.defaultNow()' : defaultValue @@ -395,7 +531,6 @@ const column = ( out += defaultValue; - // TODO: check if SingleStore has onUpdateNow() let onUpdateNow = onUpdate ? '.onUpdateNow()' : ''; out += onUpdateNow; @@ -412,8 +547,8 @@ const column = ( const params = timeConfig({ fsp }); let out = params - ? `${casing(name)}: time("${name}", ${params})` - : `${casing(name)}: time("${name}")`; + ? `${casing(name)}: time(${dbColumnName({ name, casing: rawCasing, withMode: params !== undefined })}${params})` + : `${casing(name)}: time(${dbColumnName({ name, casing: rawCasing })})`; defaultValue = defaultValue === 'now()' ? '.defaultNow()' @@ -430,7 +565,7 @@ const column = ( casing( name, ) - }: date("${name}", { mode: 'string' })`; + }: date(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: 'string' })`; defaultValue = defaultValue === 'now()' ? '.defaultNow()' @@ -442,40 +577,36 @@ const column = ( return out; } - // in mysql text can't have default value. Will leave it in case smth ;) - // TODO: check if SingleStore has text can't have default value + // in singlestore text can't have default value. Will leave it in case smth ;) if (lowered === 'text') { - let out = `${casing(name)}: text("${name}")`; + let out = `${casing(name)}: text(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } - // in mysql text can't have default value. Will leave it in case smth ;) - // TODO: check if SingleStore has tinytext can't have default value + // in singlestore text can't have default value. Will leave it in case smth ;) if (lowered === 'tinytext') { - let out = `${casing(name)}: tinytext("${name}")`; + let out = `${casing(name)}: tinytext(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } - // in mysql text can't have default value. Will leave it in case smth ;) - // TODO: check if SingleStore has mediumtext can't have default value + // in singlestore text can't have default value. Will leave it in case smth ;) if (lowered === 'mediumtext') { - let out = `${casing(name)}: mediumtext("${name}")`; + let out = `${casing(name)}: mediumtext(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } - // in mysql text can't have default value. Will leave it in case smth ;) - // TODO: check if SingleStore has longtext can't have default value + // in singlestore text can't have default value. Will leave it in case smth ;) if (lowered === 'longtext') { - let out = `${casing(name)}: longtext("${name}")`; + let out = `${casing(name)}: longtext(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -483,17 +614,16 @@ const column = ( } if (lowered === 'year') { - let out = `${casing(name)}: year("${name}")`; + let out = `${casing(name)}: year(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; } - // in mysql json can't have default value. Will leave it in case smth ;) - // TODO: check if SingleStore has json can't have default value + // in singlestore json can't have default value. Will leave it in case smth ;) if (lowered === 'json') { - let out = `${casing(name)}: json("${name}")`; + let out = `${casing(name)}: json(${dbColumnName({ name, casing: rawCasing })})`; out += defaultValue ? `.default(${mapColumnDefaultForJson(defaultValue)})` @@ -502,24 +632,12 @@ const column = ( return out; } - // TODO: add new type BSON - - // TODO: add new type Blob - - // TODO: add new type UUID - - // TODO: add new type GUID - - // TODO: add new type Vector - - // TODO: add new type GeoPoint - if (lowered.startsWith('varchar')) { let out: string = `${ casing( name, ) - }: varchar("${name}", { length: ${ + }: varchar(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ length: ${ lowered.substring( 'varchar'.length + 1, lowered.length - 1, @@ -537,7 +655,7 @@ const column = ( casing( name, ) - }: char("${name}", { length: ${ + }: char(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ length: ${ lowered.substring( 'char'.length + 1, lowered.length - 1, @@ -562,13 +680,13 @@ const column = ( casing( name, ) - }: datetime("${name}", { mode: 'string', fsp: ${ + }: datetime(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: 'string', fsp: ${ lowered.substring( 'datetime'.length + 1, lowered.length - 1, ) } })` - : `${casing(name)}: datetime("${name}", { mode: 'string'})`; + : `${casing(name)}: datetime(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: 'string'})`; defaultValue = defaultValue === 'now()' ? '.defaultNow()' @@ -582,19 +700,27 @@ const column = ( if (lowered.startsWith('decimal')) { let params: - | { precision: string | undefined; scale: string | undefined } + | { precision?: string; scale?: string; unsigned?: boolean } | undefined; - if (lowered.length > 7) { + if (lowered.length > (lowered.includes('unsigned') ? 16 : 7)) { const [precision, scale] = lowered - .slice(8, lowered.length - 1) + .slice(8, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) .split(','); params = { precision, scale }; } + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + + const timeConfigParams = params ? timeConfig(params) : undefined; + let out = params - ? `${casing(name)}: decimal("${name}", ${timeConfig(params)})` - : `${casing(name)}: decimal("${name}")`; + ? `${casing(name)}: decimal(${ + dbColumnName({ name, casing: rawCasing, withMode: timeConfigParams !== undefined }) + }${timeConfigParams})` + : `${casing(name)}: decimal(${dbColumnName({ name, casing: rawCasing })})`; defaultValue = typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -614,8 +740,8 @@ const column = ( const params = binaryConfig({ length }); let out = params - ? `${casing(name)}: binary("${name}", ${params})` - : `${casing(name)}: binary("${name}")`; + ? `${casing(name)}: binary(${dbColumnName({ name, casing: rawCasing, withMode: params !== undefined })}${params})` + : `${casing(name)}: binary(${dbColumnName({ name, casing: rawCasing })})`; defaultValue = defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -627,7 +753,7 @@ const column = ( if (lowered.startsWith('enum')) { const values = lowered.substring('enum'.length + 1, lowered.length - 1); - let out = `${casing(name)}: singlestoreEnum("${name}", [${values}])`; + let out = `${casing(name)}: singlestoreEnum(${dbColumnName({ name, casing: rawCasing, withMode: true })}[${values}])`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -644,8 +770,10 @@ const column = ( const params = binaryConfig({ length }); let out = params - ? `${casing(name)}: varbinary("${name}", ${params})` - : `${casing(name)}: varbinary("${name}")`; + ? `${casing(name)}: varbinary(${ + dbColumnName({ name, casing: rawCasing, withMode: params !== undefined }) + }${params})` + : `${casing(name)}: varbinary(${dbColumnName({ name, casing: rawCasing })})`; defaultValue = defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -662,6 +790,7 @@ const column = ( const createTableColumns = ( columns: Column[], casing: (val: string) => string, + rawCasing: Casing, tableName: string, schema: SingleStoreSchemaInternal, ): string => { @@ -673,6 +802,7 @@ const createTableColumns = ( it.type, it.name, casing, + rawCasing, it.default, it.autoincrement, it.onUpdate, diff --git a/drizzle-kit/tests/introspect/singlestore.test.ts b/drizzle-kit/tests/introspect/singlestore.test.ts new file mode 100644 index 000000000..914887a04 --- /dev/null +++ b/drizzle-kit/tests/introspect/singlestore.test.ts @@ -0,0 +1,296 @@ +import 'dotenv/config'; +import Docker from 'dockerode'; +import { SQL, sql } from 'drizzle-orm'; +import { + bigint, + char, + check, + decimal, + double, + float, + int, + mediumint, + singlestoreTable, + singlestoreView, + serial, + smallint, + text, + tinyint, + varchar, +} from 'drizzle-orm/singlestore-core'; +import * as fs from 'fs'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { introspectSingleStoreToFile } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; + +let client: Connection; +let singlestoreContainer: Docker.Container; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return `singlestore://root:singlestore@localhost:${port}/`; +} + +beforeAll(async () => { + const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to SingleStore'); + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); + throw lastError; + } +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); +}); + +beforeEach(async () => { + await client.query(`drop database if exists \`drizzle\`;`); + await client.query(`create database \`drizzle\`;`); + await client.query(`use \`drizzle\`;`); +}); + +if (!fs.existsSync('tests/introspect/singlestore')) { + fs.mkdirSync('tests/introspect/singlestore'); +} + +test('generated always column: link to another column', async () => { + const schema = { + users: singlestoreTable('users', { + id: int('id'), + email: text('email'), + generatedEmail: text('generatedEmail').generatedAlwaysAs( + (): SQL => sql`\`email\``, + ), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'generated-link-column', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('generated always column virtual: link to another column', async () => { + const schema = { + users: singlestoreTable('users', { + id: int('id'), + email: text('email'), + generatedEmail: text('generatedEmail').generatedAlwaysAs( + (): SQL => sql`\`email\``, + { mode: 'virtual' }, + ), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'generated-link-column-virtual', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('Default value of character type column: char', async () => { + const schema = { + users: singlestoreTable('users', { + id: int('id'), + sortKey: char('sortKey', { length: 255 }).default('0'), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'default-value-char-column', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('Default value of character type column: varchar', async () => { + const schema = { + users: singlestoreTable('users', { + id: int('id'), + sortKey: varchar('sortKey', { length: 255 }).default('0'), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'default-value-varchar-column', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('introspect checks', async () => { + const schema = { + users: singlestoreTable('users', { + id: serial('id'), + name: varchar('name', { length: 255 }), + age: int('age'), + }, (table) => ({ + someCheck: check('some_check', sql`${table.age} > 21`), + })), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'introspect-checks', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('view #1', async () => { + const users = singlestoreTable('users', { id: int('id') }); + const testView = singlestoreView('some_view', { id: int('id') }).as( + sql`select \`drizzle\`.\`users\`.\`id\` AS \`id\` from \`drizzle\`.\`users\``, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'view-1', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('view #2', async () => { + const users = singlestoreTable('some_users', { id: int('id') }); + const testView = singlestoreView('some_view', { id: int('id') }).algorithm('temptable').sqlSecurity('definer').as( + sql`SELECT * FROM ${users}`, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'view-2', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('handle float type', async () => { + const schema = { + table: singlestoreTable('table', { + col1: float(), + col2: float({ precision: 2 }), + col3: float({ precision: 2, scale: 1 }), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'handle-float-type', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('handle unsigned numerical types', async () => { + const schema = { + table: singlestoreTable('table', { + col1: int({ unsigned: true }), + col2: tinyint({ unsigned: true }), + col3: smallint({ unsigned: true }), + col4: mediumint({ unsigned: true }), + col5: bigint({ mode: 'number', unsigned: true }), + col6: float({ unsigned: true }), + col7: float({ precision: 2, scale: 1, unsigned: true }), + col8: double({ unsigned: true }), + col9: double({ precision: 2, scale: 1, unsigned: true }), + col10: decimal({ unsigned: true }), + col11: decimal({ precision: 2, scale: 1, unsigned: true }), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'handle-unsigned-numerical-types', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 592e89e33..b557d45cd 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -1,18 +1,14 @@ import Docker from "dockerode"; -import { SQL, sql } from "drizzle-orm"; import { bigint, binary, char, date, - datetime, decimal, double, float, int, - json, mediumint, - serial, singlestoreEnum, singlestoreTable, smallint, @@ -22,7 +18,7 @@ import { tinyint, varbinary, varchar, - year, + year } from "drizzle-orm/singlestore-core"; import getPort from "get-port"; import { Connection, createConnection } from "mysql2/promise"; From 643d83e29bbd91b570dc33ee3954b7c2124478a0 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Mon, 11 Nov 2024 17:26:02 +0000 Subject: [PATCH 327/492] update SingleStore float column type --- drizzle-kit/tests/push/singlestore.test.ts | 1 + .../src/singlestore-core/columns/float.ts | 48 ++- drizzle-orm/type-tests/singlestore/tables.ts | 279 +++++++++++++++++- 3 files changed, 306 insertions(+), 22 deletions(-) diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index b557d45cd..580144194 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -259,6 +259,7 @@ const singlestoreSuite: DialectSuite = { "drizzle", false ); + expect(statements.length).toBe(0); expect(statements).toEqual([]); diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts index 07a685170..82cccc5b8 100644 --- a/drizzle-orm/src/singlestore-core/columns/float.ts +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -2,6 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreFloatBuilderInitial = SingleStoreFloatBuilder<{ @@ -15,37 +16,62 @@ export type SingleStoreFloatBuilderInitial = SingleStoreFl }>; export class SingleStoreFloatBuilder> - extends SingleStoreColumnBuilderWithAutoIncrement + extends SingleStoreColumnBuilderWithAutoIncrement { static override readonly [entityKind]: string = 'SingleStoreFloatBuilder'; - constructor(name: T['name']) { + constructor(name: T['name'], config: SingleStoreFloatConfig | undefined) { super(name, 'number', 'SingleStoreFloat'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + this.config.unsigned = config?.unsigned; } /** @internal */ override build( table: AnySingleStoreTable<{ name: TTableName }>, ): SingleStoreFloat> { - return new SingleStoreFloat>( - table, - this.config as ColumnBuilderRuntimeConfig, - ); + return new SingleStoreFloat>(table, this.config as ColumnBuilderRuntimeConfig); } } export class SingleStoreFloat> - extends SingleStoreColumnWithAutoIncrement + extends SingleStoreColumnWithAutoIncrement { static override readonly [entityKind]: string = 'SingleStoreFloat'; + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; + getSQLType(): string { - return 'float'; + let type = ''; + if (this.precision !== undefined && this.scale !== undefined) { + type += `float(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + type += 'float'; + } else { + type += `float(${this.precision})`; + } + return this.unsigned ? `${type} unsigned` : type; } } +export interface SingleStoreFloatConfig { + precision?: number; + scale?: number; + unsigned?: boolean; +} + export function float(): SingleStoreFloatBuilderInitial<''>; -export function float(name: TName): SingleStoreFloatBuilderInitial; -export function float(name?: string) { - return new SingleStoreFloatBuilder(name ?? ''); +export function float( + config?: SingleStoreFloatConfig, +): SingleStoreFloatBuilderInitial<''>; +export function float( + name: TName, + config?: SingleStoreFloatConfig, +): SingleStoreFloatBuilderInitial; +export function float(a?: string | SingleStoreFloatConfig, b?: SingleStoreFloatConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreFloatBuilder(name, config); } diff --git a/drizzle-orm/type-tests/singlestore/tables.ts b/drizzle-orm/type-tests/singlestore/tables.ts index 18ed96a30..7bac4ac50 100644 --- a/drizzle-orm/type-tests/singlestore/tables.ts +++ b/drizzle-orm/type-tests/singlestore/tables.ts @@ -1,34 +1,46 @@ import { type Equal, Expect } from 'type-tests/utils.ts'; +import type { BuildColumn } from '~/column-builder.ts'; import { eq, gt } from '~/expressions.ts'; -import type { BuildColumn, InferSelectModel, Simplify } from '~/index.ts'; import { bigint, + binary, + boolean, char, customType, date, datetime, decimal, + double, + float, index, int, json, longtext, + mediumint, mediumtext, - primaryKey, - serial, type SingleStoreColumn, singlestoreEnum, - singlestoreSchema, singlestoreTable, + primaryKey, + real, + serial, + smallint, text, + time, timestamp, + tinyint, tinytext, unique, uniqueIndex, + varbinary, varchar, + year, } from '~/singlestore-core/index.ts'; - +import { singlestoreSchema } from '~/singlestore-core/schema.ts'; import { singlestoreView, type SingleStoreViewWithSelection } from '~/singlestore-core/view.ts'; import { sql } from '~/sql/sql.ts'; +import type { InferSelectModel } from '~/table.ts'; +import type { Simplify } from '~/utils.ts'; import { db } from './db.ts'; export const users = singlestoreTable( @@ -151,11 +163,11 @@ export const citiesCustom = customSchema.table('cities_table', { Expect>; -export const classes = singlestoreTable('classes_table', { +export const classes = singlestoreTable('classes_table', ({ serial, text }) => ({ id: serial('id').primaryKey(), class: text('class', { enum: ['A', 'C'] }), subClass: text('sub_class', { enum: ['B', 'D'] }).notNull(), -}); +})); /* export const classes2 = singlestoreTable('classes_table', { id: serial().primaryKey(), @@ -165,7 +177,6 @@ export const classes = singlestoreTable('classes_table', { export const newYorkers = singlestoreView('new_yorkers') .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as((qb) => { const sq = qb @@ -222,7 +233,6 @@ Expect< { const newYorkers = customSchema.view('new_yorkers') .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as((qb) => { const sq = qb @@ -283,7 +293,6 @@ Expect< cityId: int('city_id'), }) .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as( sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ @@ -338,7 +347,6 @@ Expect< cityId: int('city_id'), }) .algorithm('merge') - .definer('root@localhost') .sqlSecurity('definer') .as( sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ @@ -749,3 +757,252 @@ Expect< }, typeof emailLog.$inferInsert> >; } + +{ + const customRequiredConfig = customType<{ + data: string; + driverData: string; + config: { length: number }; + configRequired: true; + }>({ + dataType(config) { + Expect>; + return `varchar(${config.length})`; + }, + + toDriver(value) { + Expect>(); + return value; + }, + + fromDriver(value) { + Expect>(); + return value; + }, + }); + + customRequiredConfig('t', { length: 10 }); + customRequiredConfig({ length: 10 }); + // @ts-expect-error - config is required + customRequiredConfig('t'); + // @ts-expect-error - config is required + customRequiredConfig(); +} + +{ + const customOptionalConfig = customType<{ + data: string; + driverData: string; + config: { length: number }; + }>({ + dataType(config) { + Expect>; + return config ? `varchar(${config.length})` : `text`; + }, + + toDriver(value) { + Expect>(); + return value; + }, + + fromDriver(value) { + Expect>(); + return value; + }, + }); + + customOptionalConfig('t', { length: 10 }); + customOptionalConfig('t'); + customOptionalConfig({ length: 10 }); + customOptionalConfig(); +} + +{ + singlestoreTable('all_columns', { + bigint: bigint('bigint', { mode: 'number' }), + bigint2: bigint('bigint', { mode: 'number', unsigned: true }), + bigintdef: bigint('bigintdef', { mode: 'number' }).default(0), + binary: binary('binary'), + binary1: binary('binary1', { length: 1 }), + binarydef: binary('binarydef').default(''), + boolean: boolean('boolean'), + booleandef: boolean('booleandef').default(false), + char: char('char'), + char2: char('char2', { length: 1 }), + char3: char('char3', { enum: ['a', 'b', 'c'] }), + char4: char('char4', { length: 1, enum: ['a', 'b', 'c'] }), + chardef: char('chardef').default(''), + date: date('date'), + date2: date('date2', { mode: 'string' }), + datedef: date('datedef').default(new Date()), + datetime: datetime('datetime'), + datetime2: datetime('datetime2', { mode: 'string' }), + datetime3: datetime('datetime3', { mode: 'string', fsp: 3 }), + datetimedef: datetime('datetimedef').default(new Date()), + decimal: decimal('decimal'), + decimal2: decimal('decimal2', { precision: 10 }), + decimal3: decimal('decimal3', { scale: 2 }), + decimal4: decimal('decimal4', { precision: 10, scale: 2 }), + decimaldef: decimal('decimaldef').default('0'), + double: double('double'), + double2: double('double2', { precision: 10 }), + double3: double('double3', { scale: 2 }), + double4: double('double4', { precision: 10, scale: 2 }), + doubledef: double('doubledef').default(0), + enum: singlestoreEnum('enum', ['a', 'b', 'c']), + enumdef: singlestoreEnum('enumdef', ['a', 'b', 'c']).default('a'), + float: float('float'), + float2: float('float2', { precision: 10 }), + float3: float('float3', { scale: 2 }), + float4: float('float4', { precision: 10, scale: 2 }), + floatdef: float('floatdef').default(0), + int: int('int'), + int2: int('int2', { unsigned: true }), + intdef: int('intdef').default(0), + json: json('json'), + jsondef: json('jsondef').default({}), + mediumint: mediumint('mediumint'), + mediumint2: mediumint('mediumint2', { unsigned: true }), + mediumintdef: mediumint('mediumintdef').default(0), + real: real('real'), + real2: real('real2', { precision: 10 }), + real3: real('real3', { scale: 2 }), + real4: real('real4', { precision: 10, scale: 2 }), + realdef: real('realdef').default(0), + serial: serial('serial'), + serialdef: serial('serialdef').default(0), + smallint: smallint('smallint'), + smallint2: smallint('smallint2', { unsigned: true }), + smallintdef: smallint('smallintdef').default(0), + text: text('text'), + text2: text('text2', { enum: ['a', 'b', 'c'] }), + textdef: text('textdef').default(''), + tinytext: tinytext('tinytext'), + tinytext2: tinytext('tinytext2', { enum: ['a', 'b', 'c'] }), + tinytextdef: tinytext('tinytextdef').default(''), + mediumtext: mediumtext('mediumtext'), + mediumtext2: mediumtext('mediumtext2', { enum: ['a', 'b', 'c'] }), + mediumtextdef: mediumtext('mediumtextdef').default(''), + longtext: longtext('longtext'), + longtext2: longtext('longtext2', { enum: ['a', 'b', 'c'] }), + longtextdef: longtext('longtextdef').default(''), + time: time('time'), + time2: time('time2', { fsp: 1 }), + timedef: time('timedef').default('00:00:00'), + timestamp: timestamp('timestamp'), + timestamp2: timestamp('timestamp2', { mode: 'string' }), + timestamp3: timestamp('timestamp3', { mode: 'string', fsp: 1 }), + timestamp4: timestamp('timestamp4', { fsp: 1 }), + timestampdef: timestamp('timestampdef').default(new Date()), + tinyint: tinyint('tinyint'), + tinyint2: tinyint('tinyint2', { unsigned: true }), + tinyintdef: tinyint('tinyintdef').default(0), + varbinary: varbinary('varbinary', { length: 1 }), + varbinarydef: varbinary('varbinarydef', { length: 1 }).default(''), + varchar: varchar('varchar', { length: 1 }), + varchar2: varchar('varchar2', { length: 1, enum: ['a', 'b', 'c'] }), + varchardef: varchar('varchardef', { length: 1 }).default(''), + year: year('year'), + yeardef: year('yeardef').default(0), + }); +} + +{ + const keysAsColumnNames = singlestoreTable('test', { + id: int(), + name: text(), + }); + + Expect>; + Expect>; +} + +{ + singlestoreTable('all_columns_without_name', { + bigint: bigint({ mode: 'number' }), + bigint2: bigint({ mode: 'number', unsigned: true }), + bigintdef: bigint({ mode: 'number' }).default(0), + binary: binary(), + binrary1: binary({ length: 1 }), + binarydef: binary().default(''), + boolean: boolean(), + booleandef: boolean().default(false), + char: char(), + char2: char({ length: 1 }), + char3: char({ enum: ['a', 'b', 'c'] }), + char4: char({ length: 1, enum: ['a', 'b', 'c'] }), + chardef: char().default(''), + date: date(), + date2: date({ mode: 'string' }), + datedef: date('datedef').default(new Date()), + datetime: datetime(), + datetime2: datetime({ mode: 'string' }), + datetime3: datetime({ mode: 'string', fsp: 3 }), + datetimedef: datetime('datetimedef').default(new Date()), + decimal: decimal(), + decimal2: decimal({ precision: 10 }), + decimal3: decimal({ scale: 2 }), + decimal4: decimal({ precision: 10, scale: 2 }), + decimaldef: decimal('decimaldef').default('0'), + double: double(), + double2: double({ precision: 10 }), + double3: double({ scale: 2 }), + double4: double({ precision: 10, scale: 2 }), + doubledef: double().default(0), + enum: singlestoreEnum(['a', 'b', 'c']), + enumdef: singlestoreEnum(['a', 'b', 'c']).default('a'), + float: float(), + float2: float({ precision: 10 }), + float3: float({ scale: 2 }), + float4: float({ precision: 10, scale: 2 }), + floatdef: float().default(0), + int: int(), + int2: int({ unsigned: true }), + intdef: int().default(0), + json: json(), + jsondef: json().default({}), + mediumint: mediumint(), + mediumint2: mediumint({ unsigned: true }), + mediumintdef: mediumint().default(0), + real: real(), + real2: real({ precision: 10 }), + real3: real({ scale: 2 }), + real4: real({ precision: 10, scale: 2 }), + realdef: real().default(0), + serial: serial(), + serialdef: serial().default(0), + smallint: smallint(), + smallint2: smallint({ unsigned: true }), + smallintdef: smallint().default(0), + text: text(), + text2: text({ enum: ['a', 'b', 'c'] }), + textdef: text().default(''), + tinytext: tinytext(), + tinytext2: tinytext({ enum: ['a', 'b', 'c'] }), + tinytextdef: tinytext().default(''), + mediumtext: mediumtext(), + mediumtext2: mediumtext({ enum: ['a', 'b', 'c'] }), + mediumtextdef: mediumtext().default(''), + longtext: longtext(), + longtext2: longtext({ enum: ['a', 'b', 'c'] }), + longtextdef: longtext().default(''), + time: time(), + time2: time({ fsp: 1 }), + timedef: time().default('00:00:00'), + timestamp: timestamp(), + timestamp2: timestamp({ mode: 'string' }), + timestamp3: timestamp({ mode: 'string', fsp: 1 }), + timestamp4: timestamp({ fsp: 1 }), + timestampdef: timestamp().default(new Date()), + tinyint: tinyint(), + tinyint2: tinyint({ unsigned: true }), + tinyintdef: tinyint().default(0), + varbinary: varbinary({ length: 1 }), + varbinarydef: varbinary({ length: 1 }).default(''), + varchar: varchar({ length: 1 }), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }), + varchardef: varchar({ length: 1 }).default(''), + year: year(), + yeardef: year().default(0), + }); +} From df04b80ad1d2c73aca8eea7fbb6c2a8438313f46 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Tue, 12 Nov 2024 02:20:55 +0000 Subject: [PATCH 328/492] singlestore drizzle-kit test pass --- drizzle-kit/src/introspect-singlestore.ts | 24 +- .../src/serializer/singlestoreSerializer.ts | 11 +- drizzle-kit/src/snapshotsDiffer.ts | 2 +- .../tests/introspect/singlestore.test.ts | 34 +- drizzle-kit/tests/push/singlestore.test.ts | 694 +++++++++--------- drizzle-kit/tests/schemaDiffer.ts | 8 +- drizzle-kit/tests/singlestore-views.test.ts | 6 +- drizzle-kit/tests/singlestore.test.ts | 10 +- drizzle-kit/vitest.config.ts | 2 +- .../singlestore-core/columns/date.common.ts | 2 +- .../src/singlestore-core/columns/datetime.ts | 6 +- .../src/singlestore-core/columns/double.ts | 15 +- .../src/singlestore-core/columns/float.ts | 7 +- .../src/singlestore-core/columns/timestamp.ts | 15 +- drizzle-orm/type-tests/singlestore/tables.ts | 6 +- package.json | 4 +- 16 files changed, 426 insertions(+), 420 deletions(-) diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts index 588268488..6272152a8 100644 --- a/drizzle-kit/src/introspect-singlestore.ts +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -6,9 +6,9 @@ import { assertUnreachable } from './global'; import { Column, Index, + PrimaryKey, SingleStoreSchema, SingleStoreSchemaInternal, - PrimaryKey, UniqueConstraint, } from './serializer/singlestoreSchema'; import { indexName } from './serializer/singlestoreSerializer'; @@ -170,6 +170,9 @@ export const schemaToTypeScript = ( patched = patched.startsWith('double(') ? 'double' : patched; patched = patched.startsWith('float(') ? 'float' : patched; patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint(') ? 'tinyint' : patched; + patched = patched.startsWith('mediumint(') ? 'mediumint' : patched; + patched = patched.startsWith('bigint(') ? 'bigint' : patched; patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; @@ -204,6 +207,9 @@ export const schemaToTypeScript = ( patched = patched.startsWith('double(') ? 'double' : patched; patched = patched.startsWith('float(') ? 'float' : patched; patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint(') ? 'tinyint' : patched; + patched = patched.startsWith('mediumint(') ? 'mediumint' : patched; + patched = patched.startsWith('bigint(') ? 'bigint' : patched; patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; @@ -373,7 +379,7 @@ const column = ( } if (lowered.startsWith('int')) { - const isUnsigned = lowered.startsWith('int unsigned'); + const isUnsigned = lowered.includes('unsigned'); const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); let out = `${casing(name)}: int(${columnName}${ isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' @@ -386,7 +392,7 @@ const column = ( } if (lowered.startsWith('tinyint')) { - const isUnsigned = lowered.startsWith('tinyint unsigned'); + const isUnsigned = lowered.includes('unsigned'); const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); // let out = `${name.camelCase()}: tinyint("${name}")`; let out: string = `${casing(name)}: tinyint(${columnName}${ @@ -400,7 +406,7 @@ const column = ( } if (lowered.startsWith('smallint')) { - const isUnsigned = lowered.startsWith('smallint unsigned'); + const isUnsigned = lowered.includes('unsigned'); const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); let out = `${casing(name)}: smallint(${columnName}${ isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' @@ -413,7 +419,7 @@ const column = ( } if (lowered.startsWith('mediumint')) { - const isUnsigned = lowered.startsWith('mediumint unsigned'); + const isUnsigned = lowered.includes('unsigned'); const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); let out = `${casing(name)}: mediumint(${columnName}${ isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' @@ -426,7 +432,7 @@ const column = ( } if (lowered.startsWith('bigint')) { - const isUnsigned = lowered.startsWith('bigint unsigned'); + const isUnsigned = lowered.includes('unsigned'); let out = `${casing(name)}: bigint(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: "number"${ isUnsigned ? ', unsigned: true' : '' } })`; @@ -523,7 +529,7 @@ const column = ( : `${casing(name)}: timestamp(${dbColumnName({ name, casing: rawCasing })})`; // singlestore has only CURRENT_TIMESTAMP, as I found from docs. But will leave now() for just a case - defaultValue = defaultValue === 'now()' || defaultValue === '(CURRENT_TIMESTAMP)' + defaultValue = defaultValue === 'now()' || defaultValue === 'CURRENT_TIMESTAMP' ? '.defaultNow()' : defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` @@ -753,7 +759,9 @@ const column = ( if (lowered.startsWith('enum')) { const values = lowered.substring('enum'.length + 1, lowered.length - 1); - let out = `${casing(name)}: singlestoreEnum(${dbColumnName({ name, casing: rawCasing, withMode: true })}[${values}])`; + let out = `${casing(name)}: singlestoreEnum(${ + dbColumnName({ name, casing: rawCasing, withMode: true }) + }[${values}])`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index f0e91d892..7fa6354cc 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -384,9 +384,6 @@ export const generateSingleStoreSnapshot = ( columnToSet.default = column.default; } } - if (['blob', 'text', 'json'].includes(column.getSQLType())) { - columnToSet.default = `(${columnToSet.default})`; - } } } columnsObject[column.name] = columnToSet; @@ -491,7 +488,7 @@ export const fromDatabase = async ( const columnType = column['COLUMN_TYPE']; // varchar(256) // const columnType = column["DATA_TYPE"]; const isPrimary = column['COLUMN_KEY'] === 'PRI'; // 'PRI', '' - const columnDefault: string = column['COLUMN_DEFAULT']; + let columnDefault: string | null = column['COLUMN_DEFAULT']; const collation: string = column['CHARACTER_SET_NAME']; const geenratedExpression: string = column['GENERATION_EXPRESSION']; @@ -553,6 +550,10 @@ export const fromDatabase = async ( changedType = columnType.replace('decimal(10,0)', 'decimal'); } + if (columnDefault?.endsWith('.')) { + columnDefault = columnDefault.slice(0, -1); + } + let onUpdate: boolean | undefined = undefined; if ( columnType.startsWith('timestamp') @@ -570,6 +571,8 @@ export const fromDatabase = async ( ? Number(columnDefault) : isDefaultAnExpression ? clearDefaults(columnDefault, collation) + : columnDefault.startsWith('CURRENT_TIMESTAMP') + ? 'CURRENT_TIMESTAMP' : `'${columnDefault}'`, autoincrement: isAutoincrement, name: columnName, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 444655909..48520dc68 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -3204,7 +3204,7 @@ export const applySingleStoreSnapshotsDiff = async ( jsonStatements.push(...jsonAlteredUniqueConstraints); - const sqlStatements = fromJson(jsonStatements, 'mysql'); + const sqlStatements = fromJson(jsonStatements, 'singlestore'); const uniqueSqlStatements: string[] = []; sqlStatements.forEach((ss) => { diff --git a/drizzle-kit/tests/introspect/singlestore.test.ts b/drizzle-kit/tests/introspect/singlestore.test.ts index 914887a04..ed1db094b 100644 --- a/drizzle-kit/tests/introspect/singlestore.test.ts +++ b/drizzle-kit/tests/introspect/singlestore.test.ts @@ -1,10 +1,9 @@ -import 'dotenv/config'; import Docker from 'dockerode'; +import 'dotenv/config'; import { SQL, sql } from 'drizzle-orm'; import { bigint, char, - check, decimal, double, float, @@ -12,11 +11,10 @@ import { mediumint, singlestoreTable, singlestoreView, - serial, smallint, text, tinyint, - varchar, + varchar } from 'drizzle-orm/singlestore-core'; import * as fs from 'fs'; import getPort from 'get-port'; @@ -57,7 +55,7 @@ async function createDockerDB(): Promise { } beforeAll(async () => { - const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB(); + const connectionString = process.env.SINGLESTORE_CONNECTION_STRING ?? await createDockerDB(); const sleep = 1000; let timeLeft = 20000; @@ -98,7 +96,7 @@ if (!fs.existsSync('tests/introspect/singlestore')) { fs.mkdirSync('tests/introspect/singlestore'); } -test('generated always column: link to another column', async () => { +test.skip('generated always column: link to another column', async () => { const schema = { users: singlestoreTable('users', { id: int('id'), @@ -120,7 +118,7 @@ test('generated always column: link to another column', async () => { expect(sqlStatements.length).toBe(0); }); -test('generated always column virtual: link to another column', async () => { +test.skip('generated always column virtual: link to another column', async () => { const schema = { users: singlestoreTable('users', { id: int('id'), @@ -181,28 +179,6 @@ test('Default value of character type column: varchar', async () => { expect(sqlStatements.length).toBe(0); }); -test('introspect checks', async () => { - const schema = { - users: singlestoreTable('users', { - id: serial('id'), - name: varchar('name', { length: 255 }), - age: int('age'), - }, (table) => ({ - someCheck: check('some_check', sql`${table.age} > 21`), - })), - }; - - const { statements, sqlStatements } = await introspectSingleStoreToFile( - client, - schema, - 'introspect-checks', - 'drizzle', - ); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); - test('view #1', async () => { const users = singlestoreTable('users', { id: int('id') }); const testView = singlestoreView('some_view', { id: int('id') }).as( diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 580144194..13ef08cfa 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -1,359 +1,355 @@ -import Docker from "dockerode"; +import Docker from 'dockerode'; import { - bigint, - binary, - char, - date, - decimal, - double, - float, - int, - mediumint, - singlestoreEnum, - singlestoreTable, - smallint, - text, - time, - timestamp, - tinyint, - varbinary, - varchar, - year -} from "drizzle-orm/singlestore-core"; -import getPort from "get-port"; -import { Connection, createConnection } from "mysql2/promise"; -import { - diffTestSchemasPushSingleStore, - diffTestSchemasSingleStore, -} from "tests/schemaDiffer"; -import { v4 as uuid } from "uuid"; -import { expect } from "vitest"; -import { DialectSuite, run } from "./common"; + bigint, + binary, + char, + date, + datetime, + decimal, + double, + float, + int, + mediumint, + singlestoreEnum, + singlestoreTable, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, +} from 'drizzle-orm/singlestore-core'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { diffTestSchemasPushSingleStore, diffTestSchemasSingleStore } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { expect } from 'vitest'; +import { DialectSuite, run } from './common'; +import { sql } from 'drizzle-orm'; async function createDockerDB(context: any): Promise { - const docker = new Docker(); - const port = await getPort({ port: 3306 }); - const image = "ghcr.io/singlestore-labs/singlestoredb-dev:latest"; - - const pullStream = await docker.pull(image); - await new Promise((resolve, reject) => - docker.modem.followProgress(pullStream, (err) => - err ? reject(err) : resolve(err) - ) - ); - - context.singlestoreContainer = await docker.createContainer({ - Image: image, - Env: ["ROOT_PASSWORD=singlestore"], - name: `drizzle-integration-tests-${uuid()}`, - HostConfig: { - AutoRemove: true, - PortBindings: { - "3306/tcp": [{ HostPort: `${port}` }], - }, - }, - }); - - await context.singlestoreContainer.start(); - await new Promise((resolve) => setTimeout(resolve, 4000)); - - return `singlestore://root:singlestore@localhost:${port}/`; + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + context.singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await context.singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return `singlestore://root:singlestore@localhost:${port}/`; } const singlestoreSuite: DialectSuite = { - allTypes: async function (context: any): Promise { - const schema1 = { - allBigInts: singlestoreTable("all_big_ints", { - simple: bigint("simple", { mode: "number" }), - columnNotNull: bigint("column_not_null", { mode: "number" }).notNull(), - columnDefault: bigint("column_default", { mode: "number" }).default(12), - columnDefaultSql: bigint("column_default_sql", { - mode: "number", - }).default(12), - }), - allBools: singlestoreTable("all_bools", { - simple: tinyint("simple"), - columnNotNull: tinyint("column_not_null").notNull(), - columnDefault: tinyint("column_default").default(1), - }), - allChars: singlestoreTable("all_chars", { - simple: char("simple", { length: 1 }), - columnNotNull: char("column_not_null", { length: 45 }).notNull(), - // columnDefault: char("column_default", { length: 1 }).default("h"), - columnDefaultSql: char("column_default_sql", { length: 1 }).default( - "h" - ), - }), - // allDateTimes: singlestoreTable("all_date_times", { - // simple: datetime("simple", { mode: "string", fsp: 1 }), - // columnNotNull: datetime("column_not_null", { - // mode: "string", - // }).notNull(), - // columnDefault: datetime("column_default", { mode: "string" }).default( - // "2023-03-01 14:05:29" - // ), - // }), - allDates: singlestoreTable("all_dates", { - simple: date("simple", { mode: "string" }), - column_not_null: date("column_not_null", { mode: "string" }).notNull(), - column_default: date("column_default", { mode: "string" }).default( - "2023-03-01" - ), - }), - allDecimals: singlestoreTable("all_decimals", { - simple: decimal("simple", { precision: 1, scale: 0 }), - columnNotNull: decimal("column_not_null", { - precision: 45, - scale: 3, - }).notNull(), - columnDefault: decimal("column_default", { - precision: 10, - scale: 0, - }).default("100"), - columnDefaultSql: decimal("column_default_sql", { - precision: 10, - scale: 0, - }).default("101"), - }), - - allDoubles: singlestoreTable("all_doubles", { - simple: double("simple"), - columnNotNull: double("column_not_null").notNull(), - columnDefault: double("column_default").default(100), - columnDefaultSql: double("column_default_sql").default(101), - }), - - allEnums: singlestoreTable("all_enums", { - simple: singlestoreEnum("simple", ["hi", "hello"]), - }), - - allEnums1: singlestoreTable("all_enums1", { - simple: singlestoreEnum("simple", ["hi", "hello"]).default("hi"), - }), - - allFloats: singlestoreTable("all_floats", { - columnNotNull: float("column_not_null").notNull(), - columnDefault: float("column_default").default(100), - columnDefaultSql: float("column_default_sql").default(101), - }), - - allInts: singlestoreTable("all_ints", { - simple: int("simple"), - columnNotNull: int("column_not_null").notNull(), - columnDefault: int("column_default").default(100), - columnDefaultSql: int("column_default_sql").default(101), - }), - - allIntsRef: singlestoreTable("all_ints_ref", { - simple: int("simple"), - columnNotNull: int("column_not_null").notNull(), - columnDefault: int("column_default").default(100), - columnDefaultSql: int("column_default_sql").default(101), - }), - - // allJsons: singlestoreTable("all_jsons", { - // columnDefaultObject: json("column_default_object") - // .default({ hello: "world world" }) - // .notNull(), - // columnDefaultArray: json("column_default_array").default({ - // hello: { "world world": ["foo", "bar"] }, - // foo: "bar", - // fe: 23, - // }), - // column: json("column"), - // }), - - allMInts: singlestoreTable("all_m_ints", { - simple: mediumint("simple"), - columnNotNull: mediumint("column_not_null").notNull(), - columnDefault: mediumint("column_default").default(100), - columnDefaultSql: mediumint("column_default_sql").default(101), - }), - - allReals: singlestoreTable("all_reals", { - simple: double("simple", { precision: 5, scale: 2 }), - columnNotNull: double("column_not_null").notNull(), - columnDefault: double("column_default").default(100), - columnDefaultSql: double("column_default_sql").default(101), - }), - - allSInts: singlestoreTable("all_s_ints", { - simple: smallint("simple"), - columnNotNull: smallint("column_not_null").notNull(), - columnDefault: smallint("column_default").default(100), - columnDefaultSql: smallint("column_default_sql").default(101), - }), - - // allSmallSerials: singlestoreTable("all_small_serials", { - // columnAll: serial("column_all").notNull(), - // }), - - allTInts: singlestoreTable("all_t_ints", { - simple: tinyint("simple"), - columnNotNull: tinyint("column_not_null").notNull(), - columnDefault: tinyint("column_default").default(10), - columnDefaultSql: tinyint("column_default_sql").default(11), - }), - - allTexts: singlestoreTable("all_texts", { - simple: text("simple"), - columnNotNull: text("column_not_null").notNull(), - columnDefault: text("column_default").default("hello"), - columnDefaultSql: text("column_default_sql").default("hello"), - }), - - allTimes: singlestoreTable("all_times", { - // simple: time("simple", { fsp: 1 }), - columnNotNull: time("column_not_null").notNull(), - columnDefault: time("column_default").default("22:12:12"), - }), - - allTimestamps: singlestoreTable("all_timestamps", { - // columnDateNow: timestamp("column_date_now", { - // fsp: 1, - // mode: "string", - // }).default(sql`(now())`), - columnAll: timestamp("column_all", { mode: "string" }) - .default("2023-03-01 14:05:29") - .notNull(), - column: timestamp("column", { mode: "string" }).default( - "2023-02-28 16:18:31" - ), - }), - - allVarChars: singlestoreTable("all_var_chars", { - simple: varchar("simple", { length: 100 }), - columnNotNull: varchar("column_not_null", { length: 45 }).notNull(), - columnDefault: varchar("column_default", { length: 100 }).default( - "hello" - ), - columnDefaultSql: varchar("column_default_sql", { - length: 100, - }).default("hello"), - }), - - allVarbinaries: singlestoreTable("all_varbinaries", { - simple: varbinary("simple", { length: 100 }), - columnNotNull: varbinary("column_not_null", { length: 100 }).notNull(), - columnDefault: varbinary("column_default", { length: 12 }), - }), - - allYears: singlestoreTable("all_years", { - simple: year("simple"), - columnNotNull: year("column_not_null").notNull(), - columnDefault: year("column_default").default(2022), - }), - - binafry: singlestoreTable("binary", { - simple: binary("simple", { length: 1 }), - columnNotNull: binary("column_not_null", { length: 1 }).notNull(), - columnDefault: binary("column_default", { length: 12 }), - }), - }; - - const { statements } = await diffTestSchemasPushSingleStore( - context.client as Connection, - schema1, - schema1, - [], - "drizzle", - false - ); - - expect(statements.length).toBe(0); - expect(statements).toEqual([]); - - const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( - schema1, - {}, - [], - false - ); - - for (const st of dropStatements) { - await context.client.query(st); - } - }, - addBasicIndexes: function (context?: any): Promise { - return {} as any; - }, - changeIndexFields: function (context?: any): Promise { - return {} as any; - }, - dropIndex: function (context?: any): Promise { - return {} as any; - }, - indexesToBeNotTriggered: function (context?: any): Promise { - return {} as any; - }, - indexesTestCase1: function (context?: any): Promise { - return {} as any; - }, - async case1() { - // TODO: implement if needed - expect(true).toBe(true); - }, - addNotNull: function (context?: any): Promise { - return {} as any; - }, - addNotNullWithDataNoRollback: function (context?: any): Promise { - return {} as any; - }, - addBasicSequences: function (context?: any): Promise { - return {} as any; - }, - addGeneratedColumn: async function (context: any): Promise { - return {} as any; - }, - addGeneratedToColumn: async function (context: any): Promise { - return {} as any; - }, - dropGeneratedConstraint: async function (context: any): Promise { - return {} as any; - }, - alterGeneratedConstraint: async function (context: any): Promise { - return {} as any; - }, - createTableWithGeneratedConstraint: function (context?: any): Promise { - return {} as any; - }, + allTypes: async function(context: any): Promise { + const schema1 = { + allBigInts: singlestoreTable('all_big_ints', { + simple: bigint('simple', { mode: 'number' }), + columnNotNull: bigint('column_not_null', { mode: 'number' }).notNull(), + columnDefault: bigint('column_default', { mode: 'number' }).default(12), + columnDefaultSql: bigint('column_default_sql', { + mode: 'number', + }).default(12), + }), + allBools: singlestoreTable('all_bools', { + simple: tinyint('simple'), + columnNotNull: tinyint('column_not_null').notNull(), + columnDefault: tinyint('column_default').default(1), + }), + allChars: singlestoreTable('all_chars', { + simple: char('simple', { length: 1 }), + columnNotNull: char('column_not_null', { length: 45 }).notNull(), + // columnDefault: char("column_default", { length: 1 }).default("h"), + columnDefaultSql: char('column_default_sql', { length: 1 }).default( + 'h', + ), + }), + allDateTimes: singlestoreTable('all_date_times', { + simple: datetime('simple', { mode: 'string', fsp: 0 }), + columnNotNull: datetime('column_not_null', { + mode: 'string', + }).notNull(), + columnDefault: datetime('column_default', { mode: 'string' }).default( + '2023-03-01 14:05:29', + ), + }), + allDates: singlestoreTable('all_dates', { + simple: date('simple', { mode: 'string' }), + column_not_null: date('column_not_null', { mode: 'string' }).notNull(), + column_default: date('column_default', { mode: 'string' }).default( + '2023-03-01', + ), + }), + allDecimals: singlestoreTable('all_decimals', { + simple: decimal('simple', { precision: 1, scale: 0 }), + columnNotNull: decimal('column_not_null', { + precision: 45, + scale: 3, + }).notNull(), + columnDefault: decimal('column_default', { + precision: 10, + scale: 0, + }).default('100'), + columnDefaultSql: decimal('column_default_sql', { + precision: 10, + scale: 0, + }).default('101'), + }), + + allDoubles: singlestoreTable('all_doubles', { + simple: double('simple'), + columnNotNull: double('column_not_null').notNull(), + columnDefault: double('column_default').default(100), + columnDefaultSql: double('column_default_sql').default(101), + }), + + allEnums: singlestoreTable('all_enums', { + simple: singlestoreEnum('simple', ['hi', 'hello']), + }), + + allEnums1: singlestoreTable('all_enums1', { + simple: singlestoreEnum('simple', ['hi', 'hello']).default('hi'), + }), + + allFloats: singlestoreTable('all_floats', { + columnNotNull: float('column_not_null').notNull(), + columnDefault: float('column_default').default(100), + columnDefaultSql: float('column_default_sql').default(101), + }), + + allInts: singlestoreTable('all_ints', { + simple: int('simple'), + columnNotNull: int('column_not_null').notNull(), + columnDefault: int('column_default').default(100), + columnDefaultSql: int('column_default_sql').default(101), + }), + + allIntsRef: singlestoreTable('all_ints_ref', { + simple: int('simple'), + columnNotNull: int('column_not_null').notNull(), + columnDefault: int('column_default').default(100), + columnDefaultSql: int('column_default_sql').default(101), + }), + + // allJsons: singlestoreTable("all_jsons", { + // columnDefaultObject: json("column_default_object") + // .default({ hello: "world world" }) + // .notNull(), + // columnDefaultArray: json("column_default_array").default({ + // hello: { "world world": ["foo", "bar"] }, + // foo: "bar", + // fe: 23, + // }), + // column: json("column"), + // }), + + allMInts: singlestoreTable('all_m_ints', { + simple: mediumint('simple'), + columnNotNull: mediumint('column_not_null').notNull(), + columnDefault: mediumint('column_default').default(100), + columnDefaultSql: mediumint('column_default_sql').default(101), + }), + + allReals: singlestoreTable('all_reals', { + simple: double('simple', { precision: 5, scale: 2 }), + columnNotNull: double('column_not_null').notNull(), + columnDefault: double('column_default').default(100), + columnDefaultSql: double('column_default_sql').default(101), + }), + + allSInts: singlestoreTable('all_s_ints', { + simple: smallint('simple'), + columnNotNull: smallint('column_not_null').notNull(), + columnDefault: smallint('column_default').default(100), + columnDefaultSql: smallint('column_default_sql').default(101), + }), + + // allSmallSerials: singlestoreTable("all_small_serials", { + // columnAll: serial("column_all").notNull(), + // }), + + allTInts: singlestoreTable('all_t_ints', { + simple: tinyint('simple'), + columnNotNull: tinyint('column_not_null').notNull(), + columnDefault: tinyint('column_default').default(10), + columnDefaultSql: tinyint('column_default_sql').default(11), + }), + + allTexts: singlestoreTable('all_texts', { + simple: text('simple'), + columnNotNull: text('column_not_null').notNull(), + columnDefault: text('column_default').default('hello'), + columnDefaultSql: text('column_default_sql').default('hello'), + }), + + allTimes: singlestoreTable('all_times', { + // simple: time("simple", { fsp: 1 }), + columnNotNull: time('column_not_null').notNull(), + columnDefault: time('column_default').default('22:12:12'), + }), + + allTimestamps: singlestoreTable('all_timestamps', { + columnDateNow: timestamp("column_date_now", { + fsp: 0, + mode: "string", + }).default(sql`CURRENT_TIMESTAMP`), + columnAll: timestamp('column_all', { mode: 'string' }) + .default('2023-03-01 14:05:29') + .notNull(), + column: timestamp('column', { mode: 'string' }).default( + '2023-02-28 16:18:31', + ), + }), + + allVarChars: singlestoreTable('all_var_chars', { + simple: varchar('simple', { length: 100 }), + columnNotNull: varchar('column_not_null', { length: 45 }).notNull(), + columnDefault: varchar('column_default', { length: 100 }).default( + 'hello', + ), + columnDefaultSql: varchar('column_default_sql', { + length: 100, + }).default('hello'), + }), + + allVarbinaries: singlestoreTable('all_varbinaries', { + simple: varbinary('simple', { length: 100 }), + columnNotNull: varbinary('column_not_null', { length: 100 }).notNull(), + columnDefault: varbinary('column_default', { length: 12 }), + }), + + allYears: singlestoreTable('all_years', { + simple: year('simple'), + columnNotNull: year('column_not_null').notNull(), + columnDefault: year('column_default').default(2022), + }), + + binafry: singlestoreTable('binary', { + simple: binary('simple', { length: 1 }), + columnNotNull: binary('column_not_null', { length: 1 }).notNull(), + columnDefault: binary('column_default', { length: 12 }), + }), + }; + + const { statements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema1, + [], + 'drizzle', + false, + ); + + expect(statements.length).toBe(0); + expect(statements).toEqual([]); + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema1, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + addBasicIndexes: function(context?: any): Promise { + return {} as any; + }, + changeIndexFields: function(context?: any): Promise { + return {} as any; + }, + dropIndex: function(context?: any): Promise { + return {} as any; + }, + indexesToBeNotTriggered: function(context?: any): Promise { + return {} as any; + }, + indexesTestCase1: function(context?: any): Promise { + return {} as any; + }, + async case1() { + // TODO: implement if needed + expect(true).toBe(true); + }, + addNotNull: function(context?: any): Promise { + return {} as any; + }, + addNotNullWithDataNoRollback: function(context?: any): Promise { + return {} as any; + }, + addBasicSequences: function(context?: any): Promise { + return {} as any; + }, + addGeneratedColumn: async function(context: any): Promise { + return {} as any; + }, + addGeneratedToColumn: async function(context: any): Promise { + return {} as any; + }, + dropGeneratedConstraint: async function(context: any): Promise { + return {} as any; + }, + alterGeneratedConstraint: async function(context: any): Promise { + return {} as any; + }, + createTableWithGeneratedConstraint: function(context?: any): Promise { + return {} as any; + }, }; run( - singlestoreSuite, - async (context: any) => { - const connectionString = - process.env.SINGLESTORE_CONNECTION_STRING ?? - (await createDockerDB(context)); - - const sleep = 1000; - let timeLeft = 20000; - let connected = false; - let lastError: unknown | undefined; - do { - try { - context.client = await createConnection(connectionString); - await context.client.connect(); - connected = true; - break; - } catch (e) { - lastError = e; - await new Promise((resolve) => setTimeout(resolve, sleep)); - timeLeft -= sleep; - } - } while (timeLeft > 0); - if (!connected) { - console.error("Cannot connect to SingleStore"); - await context.client?.end().catch(console.error); - await context.singlestoreContainer?.stop().catch(console.error); - throw lastError; - } - - await context.client.query("CREATE DATABASE drizzle;"); - await context.client.query("USE drizzle;"); - }, - async (context: any) => { - await context.client?.end().catch(console.error); - await context.singlestoreContainer?.stop().catch(console.error); - } + singlestoreSuite, + async (context: any) => { + const connectionString = process.env.SINGLESTORE_CONNECTION_STRING + ?? (await createDockerDB(context)); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + context.client = await createConnection(connectionString); + await context.client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to SingleStore'); + await context.client?.end().catch(console.error); + await context.singlestoreContainer?.stop().catch(console.error); + throw lastError; + } + + await context.client.query('CREATE DATABASE drizzle;'); + await context.client.query('USE drizzle;'); + }, + async (context: any) => { + await context.client?.end().catch(console.error); + await context.singlestoreContainer?.stop().catch(console.error); + }, ); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index b9f66a079..62109c60a 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -33,6 +33,7 @@ import { roleResolver, schemasResolver, sequencesResolver, + singleStoreViewsResolver, sqliteViewsResolver, tablesResolver, viewsResolver, @@ -49,7 +50,7 @@ import { prepareFromMySqlImports } from 'src/serializer/mysqlImports'; import { mysqlSchema, squashMysqlScheme, ViewSquashed } from 'src/serializer/mysqlSchema'; import { fromDatabase as fromMySqlDatabase, generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; import { prepareFromPgImports } from 'src/serializer/pgImports'; -import { pgSchema, PgSquasher, Policy, Role, squashPgScheme, View } from 'src/serializer/pgSchema'; +import { pgSchema, Policy, Role, squashPgScheme, View } from 'src/serializer/pgSchema'; import { fromDatabase, generatePgSnapshot } from 'src/serializer/pgSerializer'; import { prepareFromSingleStoreImports } from 'src/serializer/singlestoreImports'; import { singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; @@ -58,7 +59,7 @@ import { generateSingleStoreSnapshot, } from 'src/serializer/singlestoreSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; -import { sqliteSchema, squashSqliteScheme, View as SqliteView } from 'src/serializer/sqliteSchema'; +import { sqliteSchema, View as SqliteView, squashSqliteScheme } from 'src/serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase, generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; import { applyLibSQLSnapshotsDiff, @@ -1627,7 +1628,6 @@ export const diffTestSchemasPushSingleStore = async ( ) => { const { sqlStatements } = await applySingleStoreDiffs(left, casing); for (const st of sqlStatements) { - console.log('st', st); await client.query(st); } // do introspect into PgSchemaInternal @@ -1696,7 +1696,7 @@ export const diffTestSchemasPushSingleStore = async ( sn2, tablesResolver, columnsResolver, - mySqlViewsResolver, + singleStoreViewsResolver, validatedPrev, validatedCur, 'push', diff --git a/drizzle-kit/tests/singlestore-views.test.ts b/drizzle-kit/tests/singlestore-views.test.ts index fedd74645..93b726276 100644 --- a/drizzle-kit/tests/singlestore-views.test.ts +++ b/drizzle-kit/tests/singlestore-views.test.ts @@ -88,7 +88,8 @@ test('create view with existing flag', async () => { expect(sqlStatements.length).toBe(0); }); -test('drop view', async () => { +// Views are not currently supported by this driver +test.skip('drop view', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); @@ -134,7 +135,8 @@ test('drop view with existing flag', async () => { expect(sqlStatements.length).toBe(0); }); -test('rename view', async () => { +// Views are not currently supported by this driver +test.skip('rename view', async () => { const users = singlestoreTable('users', { id: int('id').primaryKey().notNull(), }); diff --git a/drizzle-kit/tests/singlestore.test.ts b/drizzle-kit/tests/singlestore.test.ts index 71b95a8f5..3bdccab81 100644 --- a/drizzle-kit/tests/singlestore.test.ts +++ b/drizzle-kit/tests/singlestore.test.ts @@ -433,7 +433,7 @@ test('add table #10', async () => { const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); expect(sqlStatements.length).toBe(1); expect(sqlStatements[0]).toBe( - "CREATE TABLE `table` (\n\t`json` json DEFAULT ('{}')\n);\n", + "CREATE TABLE `table` (\n\t`json` json DEFAULT '{}'\n);\n", ); }); @@ -447,7 +447,7 @@ test('add table #11', async () => { const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); expect(sqlStatements.length).toBe(1); expect(sqlStatements[0]).toBe( - "CREATE TABLE `table` (\n\t`json` json DEFAULT ('[]')\n);\n", + "CREATE TABLE `table` (\n\t`json` json DEFAULT '[]'\n);\n", ); }); @@ -461,7 +461,7 @@ test('add table #12', async () => { const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); expect(sqlStatements.length).toBe(1); expect(sqlStatements[0]).toBe( - "CREATE TABLE `table` (\n\t`json` json DEFAULT ('[1,2,3]')\n);\n", + "CREATE TABLE `table` (\n\t`json` json DEFAULT '[1,2,3]'\n);\n", ); }); @@ -475,7 +475,7 @@ test('add table #13', async () => { const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); expect(sqlStatements.length).toBe(1); expect(sqlStatements[0]).toBe( - 'CREATE TABLE `table` (\n\t`json` json DEFAULT (\'{"key":"value"}\')\n);\n', + 'CREATE TABLE `table` (\n\t`json` json DEFAULT \'{"key":"value"}\'\n);\n', ); }); @@ -492,7 +492,7 @@ test('add table #14', async () => { const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); expect(sqlStatements.length).toBe(1); expect(sqlStatements[0]).toBe( - 'CREATE TABLE `table` (\n\t`json` json DEFAULT (\'{"key":"value","arr":[1,2,3]}\')\n);\n', + 'CREATE TABLE `table` (\n\t`json` json DEFAULT \'{"key":"value","arr":[1,2,3]}\'\n);\n', ); }); diff --git a/drizzle-kit/vitest.config.ts b/drizzle-kit/vitest.config.ts index d8ee4a881..8667511aa 100644 --- a/drizzle-kit/vitest.config.ts +++ b/drizzle-kit/vitest.config.ts @@ -4,7 +4,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { include: [ - // 'tests/**/*.test.ts', + 'tests/**/*.test.ts', // Need to test it first before pushing changes 'tests/singlestore-schemas.test.ts', 'tests/singlestore-views.test.ts', diff --git a/drizzle-orm/src/singlestore-core/columns/date.common.ts b/drizzle-orm/src/singlestore-core/columns/date.common.ts index 8afac71d0..39b2507eb 100644 --- a/drizzle-orm/src/singlestore-core/columns/date.common.ts +++ b/drizzle-orm/src/singlestore-core/columns/date.common.ts @@ -21,7 +21,7 @@ export abstract class SingleStoreDateColumnBaseBuilder< static override readonly [entityKind]: string = 'SingleStoreDateColumnBuilder'; defaultNow() { - return this.default(sql`(now())`); + return this.default(sql`now()`); } onUpdateNow(): HasDefault { diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts index aaaa11708..a1aa8eba9 100644 --- a/drizzle-orm/src/singlestore-core/columns/datetime.ts +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -52,7 +52,8 @@ export class SingleStoreDateTime; diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts index 82cccc5b8..9cfed6131 100644 --- a/drizzle-orm/src/singlestore-core/columns/float.ts +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -31,7 +31,10 @@ export class SingleStoreFloatBuilder( table: AnySingleStoreTable<{ name: TTableName }>, ): SingleStoreFloat> { - return new SingleStoreFloat>(table, this.config as ColumnBuilderRuntimeConfig); + return new SingleStoreFloat>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } @@ -51,7 +54,7 @@ export class SingleStoreFloat = SingleStoreTimestampBuilder<{ name: TName; @@ -34,6 +35,10 @@ export class SingleStoreTimestampBuilder, ); } + + override defaultNow() { + return this.default(sql`CURRENT_TIMESTAMP`); + } } export class SingleStoreTimestamp> @@ -44,7 +49,8 @@ export class SingleStoreTimestamp, ); } + + override defaultNow() { + return this.default(sql`CURRENT_TIMESTAMP`); + } } export class SingleStoreTimestampString> @@ -96,7 +106,8 @@ export class SingleStoreTimestampString Date: Tue, 12 Nov 2024 02:25:16 +0000 Subject: [PATCH 329/492] nit: missing files from main --- changelogs/drizzle-kit/0.27.2.md | 3 +++ changelogs/drizzle-kit/0.28.0.md | 28 ++++++++++++++++++++++++++++ changelogs/drizzle-orm/0.36.1.md | 6 ++++++ drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 changelogs/drizzle-kit/0.27.2.md create mode 100644 changelogs/drizzle-kit/0.28.0.md create mode 100644 changelogs/drizzle-orm/0.36.1.md diff --git a/changelogs/drizzle-kit/0.27.2.md b/changelogs/drizzle-kit/0.27.2.md new file mode 100644 index 000000000..b003379b9 --- /dev/null +++ b/changelogs/drizzle-kit/0.27.2.md @@ -0,0 +1,3 @@ +Fix [BUG]: Undefined properties when using drizzle-kit push +Fix TypeError: Cannot read properties of undefined (reading 'isRLSEnabled') +Fix push bugs, when pushing a schema with linked policy to a table from drizzle-orm/supabase diff --git a/changelogs/drizzle-kit/0.28.0.md b/changelogs/drizzle-kit/0.28.0.md new file mode 100644 index 000000000..6881c677e --- /dev/null +++ b/changelogs/drizzle-kit/0.28.0.md @@ -0,0 +1,28 @@ +# Improvements + +- Added an OHM static imports checker to identify unexpected imports within a chain of imports in the drizzle-kit repo. For example, it checks if drizzle-orm is imported before drizzle-kit and verifies if the drizzle-orm import is available in your project. +- [Adding more columns to Supabase auth.users table schema](https://github.com/drizzle-team/drizzle-orm/issues/3327) - thanks @nicholasdly + +# Bug Fixes + +- [[BUG]: [drizzle-kit]: Fix breakpoints option cannot be disabled](https://github.com/drizzle-team/drizzle-orm/issues/2828) - thanks @klotztech +- [[BUG]: drizzle-kit introspect: SMALLINT import missing and incorrect DECIMAL UNSIGNED handling](https://github.com/drizzle-team/drizzle-orm/issues/2950) - thanks @L-Mario564 +- [Unsigned tinyints preventing migrations](https://github.com/drizzle-team/drizzle-orm/issues/1571) - thanks @L-Mario564 +- [[BUG]: Can't parse float(8,2) from database (precision and scale and/or unsigned breaks float types)](https://github.com/drizzle-team/drizzle-orm/issues/3285) - thanks @L-Mario564 +- [[BUG]: PgEnum generated migration doesn't escape single quotes](https://github.com/drizzle-team/drizzle-orm/issues/1272) - thanks @L-Mario564 +- [[BUG]: single quote not escaped correctly in migration file](https://github.com/drizzle-team/drizzle-orm/issues/2184) - thanks @L-Mario564 +- [[BUG]: Migrations does not escape single quotes](https://github.com/drizzle-team/drizzle-orm/issues/1765) - thanks @L-Mario564 +- [[BUG]: Issue with quoted default string values](https://github.com/drizzle-team/drizzle-orm/issues/2122) - thanks @L-Mario564 +- [[BUG]: SQl commands in wrong roder](https://github.com/drizzle-team/drizzle-orm/issues/2390) - thanks @L-Mario564 +- [[BUG]: Time with precision in drizzle-orm/pg-core adds double-quotes around type](https://github.com/drizzle-team/drizzle-orm/issues/1804) - thanks @L-Mario564 +- [[BUG]: Postgres push fails due to lack of quotes](https://github.com/drizzle-team/drizzle-orm/issues/2396) - thanks @L-Mario564 +- [[BUG]: TypeError: Cannot read properties of undefined (reading 'compositePrimaryKeys')](https://github.com/drizzle-team/drizzle-orm/issues/2344) - thanks @L-Mario564 +- [[BUG]: drizzle-kit introspect generates CURRENT_TIMESTAMP without sql operator on date column](https://github.com/drizzle-team/drizzle-orm/issues/2899) - thanks @L-Mario564 +- [[BUG]: Drizzle-kit introspect doesn't pull correct defautl statement](https://github.com/drizzle-team/drizzle-orm/issues/2905) - thanks @L-Mario564 +- [[BUG]: Problem on MacBook - This statement does not return data. Use run() instead](https://github.com/drizzle-team/drizzle-orm/issues/2623) - thanks @L-Mario564 +- [[BUG]: Enum column names that are used as arrays are not quoted](https://github.com/drizzle-team/drizzle-orm/issues/2598) - thanks @L-Mario564 +- [[BUG]: drizzle-kit generate ignores index operators](https://github.com/drizzle-team/drizzle-orm/issues/2935) - thanks @L-Mario564 +- [dialect param config error message is wrong](https://github.com/drizzle-team/drizzle-orm/issues/3427) - thanks @L-Mario564 +- [[BUG]: Error setting default enum field values](https://github.com/drizzle-team/drizzle-orm/issues/2299) - thanks @L-Mario564 +- [[BUG]: drizzle-kit does not respect the order of columns configured in primaryKey()](https://github.com/drizzle-team/drizzle-orm/issues/2326) - thanks @L-Mario564 +- [[BUG]: Cannot drop Unique Constraint MySQL](https://github.com/drizzle-team/drizzle-orm/issues/998) - thanks @L-Mario564 diff --git a/changelogs/drizzle-orm/0.36.1.md b/changelogs/drizzle-orm/0.36.1.md new file mode 100644 index 000000000..74d256a13 --- /dev/null +++ b/changelogs/drizzle-orm/0.36.1.md @@ -0,0 +1,6 @@ +# Bug Fixes + +- [[BUG]: Using sql.placeholder with limit and/or offset for a prepared statement produces TS error](https://github.com/drizzle-team/drizzle-orm/issues/2146) - thanks @L-Mario564 +- [[BUG] If a query I am trying to modify with a dynamic query (....$dynamic()) contains any placeholders, I'm getting an error that says No value for placeholder.... provided](https://github.com/drizzle-team/drizzle-orm/issues/2272) - thanks @L-Mario564 +- [[BUG]: Error thrown when trying to insert an array of new rows using generatedAlwaysAsIdentity() for the id column](https://github.com/drizzle-team/drizzle-orm/issues/2849) - thanks @L-Mario564 +- [[BUG]: Unable to Use BigInt Types with Bun and Drizzle](https://github.com/drizzle-team/drizzle-orm/issues/2603) - thanks @L-Mario564 diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 86ce0c095..3de4487c4 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.27.1", + "version": "0.28.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 1244e9e56..6c20ac27f 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.36.0", + "version": "0.36.1", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { From dbb0d04533b39bce1b98660bdd38486a7152fdc6 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Tue, 12 Nov 2024 14:59:09 +0200 Subject: [PATCH 330/492] + --- drizzle-orm/src/column-builder.ts | 8 ++++-- drizzle-orm/src/column.ts | 1 + drizzle-orm/src/operations.ts | 11 +++++++- drizzle-orm/src/pg-core/columns/common.ts | 1 + drizzle-orm/src/pg-core/columns/int.common.ts | 6 ++--- drizzle-orm/src/pg-core/dialect.ts | 8 +++--- .../src/pg-core/query-builders/insert.ts | 27 ++++++++++++------- drizzle-orm/src/table.ts | 7 ++--- 8 files changed, 48 insertions(+), 21 deletions(-) diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index fb7da9ef6..dcc2b4734 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -43,6 +43,7 @@ export interface ColumnBuilderBaseConfig | undefined; + identity: 'always' | 'byDefault' | undefined; } export type MakeColumnConfig< @@ -65,6 +66,7 @@ export type MakeColumnConfig< baseColumn: T extends { baseBuilder: infer U extends ColumnBuilderBase } ? BuildColumn : never; generated: T['generated'] extends object ? T['generated'] : undefined; + identity: T['identity']; } & {}; export type ColumnBuilderTypeConfig< @@ -83,6 +85,7 @@ export type ColumnBuilderTypeConfig< hasDefault: T extends { hasDefault: infer U } ? U : boolean; enumValues: T['enumValues']; generated: GeneratedColumnConfig | undefined; + identity: T['identity']; } & TTypeConfig >; @@ -152,16 +155,17 @@ export type HasGenerated = T & { _: { notNull: true; hasDefault: true; - generated: { as: any; type: TType }; + identity: TType; }; }; +// always -> user pass overriding and export interface ColumnBuilderBase< T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, diff --git a/drizzle-orm/src/column.ts b/drizzle-orm/src/column.ts index 79ba17f12..9865d2849 100644 --- a/drizzle-orm/src/column.ts +++ b/drizzle-orm/src/column.ts @@ -38,6 +38,7 @@ export type ColumnTypeConfig, enumValues: T['enumValues']; baseColumn: T extends { baseColumn: infer U } ? U : unknown; generated: GeneratedColumnConfig | undefined; + identity: T["identity"]; } & TTypeConfig; export type ColumnRuntimeConfig = ColumnBuilderRuntimeConfig< diff --git a/drizzle-orm/src/operations.ts b/drizzle-orm/src/operations.ts index 6fb5cbd2e..d827843fc 100644 --- a/drizzle-orm/src/operations.ts +++ b/drizzle-orm/src/operations.ts @@ -16,11 +16,20 @@ export type NotGenerated = T extends AnyC export type OptionalKeyOnly< TKey extends string, T extends Column, + OverrideT extends boolean | undefined = false > = TKey extends RequiredKeyOnly ? never : TKey extends NotGenerated ? TKey - : T['_']['generated'] extends object ? T['_']['generated']['type'] extends 'byDefault' ? TKey : never + : T['_']['generated'] extends object ? T['_']['generated']['type'] extends 'byDefault' ? TKey + : + ( + T['_']['identity'] extends 'always'? + OverrideT extends true? TKey: never + : never + ) : never; +// byDefault -> accept +// always -> accept only if overide and always // TODO: SQL -> SQLWrapper export type SelectedFieldsFlat = Record< string, diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index c2fbe8cb9..d0d9f0502 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -57,6 +57,7 @@ export abstract class PgColumnBuilder< driverParam: T['driverParam'][] | string; enumValues: T['enumValues']; generated: GeneratedColumnConfig; + identity: T['identity']; } & (T extends { notNull: true } ? { notNull: true } : {}) & (T extends { hasDefault: true } ? { hasDefault: true } : {}), diff --git a/drizzle-orm/src/pg-core/columns/int.common.ts b/drizzle-orm/src/pg-core/columns/int.common.ts index c473b8d04..b12ed68f5 100644 --- a/drizzle-orm/src/pg-core/columns/int.common.ts +++ b/drizzle-orm/src/pg-core/columns/int.common.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnDataType, GeneratedIdentityConfig, - IsIdentityByDefault, + IsIdentity, } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; import type { PgSequenceOptions } from '../sequence.ts'; @@ -18,7 +18,7 @@ export abstract class PgIntColumnBaseBuilder< generatedAlwaysAsIdentity( sequence?: PgSequenceOptions & { name?: string }, - ): IsIdentityByDefault { + ): IsIdentity { if (sequence) { const { name, ...options } = sequence; this.config.generatedIdentity = { @@ -40,7 +40,7 @@ export abstract class PgIntColumnBaseBuilder< generatedByDefaultAsIdentity( sequence?: PgSequenceOptions & { name?: string }, - ): IsIdentityByDefault { + ): IsIdentity { if (sequence) { const { name, ...options } = sequence; this.config.generatedIdentity = { diff --git a/drizzle-orm/src/pg-core/dialect.ts b/drizzle-orm/src/pg-core/dialect.ts index bc3d4cf52..ef0b24191 100644 --- a/drizzle-orm/src/pg-core/dialect.ts +++ b/drizzle-orm/src/pg-core/dialect.ts @@ -468,7 +468,7 @@ export class PgDialect { return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; } - buildInsertQuery({ table, values, onConflict, returning, withList }: PgInsertConfig): SQL { + buildInsertQuery({ table, values, onConflict, returning, withList, overridingSystemValue_ }: PgInsertConfig): SQL { const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = []; const columns: Record = table[Table.Symbol.Columns]; @@ -517,7 +517,9 @@ export class PgDialect { const onConflictSql = onConflict ? sql` on conflict ${onConflict}` : undefined; - return sql`${withSql}insert into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}${returningSql}`; + const overridingSql = overridingSystemValue_ === true? sql`overriding system value `: undefined; + + return sql`${withSql}insert into ${table} ${insertOrder} ${overridingSql}values ${valuesSql}${onConflictSql}${returningSql}`; } buildRefreshMaterializedViewQuery( @@ -1127,7 +1129,7 @@ export class PgDialect { })); } else { const aliasedColumns = Object.fromEntries( - Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value, tableAlias)]), + Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value as PgColumn, tableAlias)]), ); if (config.where) { diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index 9f494ab50..e413a754a 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -8,13 +8,14 @@ import type { PgSession, PreparedQueryConfig, } from '~/pg-core/session.ts'; -import type { PgTable } from '~/pg-core/table.ts'; +import type { PgTable, TableConfig } from '~/pg-core/table.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; import { Param, SQL, sql } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; +import type { InferInsertModel} from '~/table.ts'; import { Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; import { mapUpdateSet, orderSelectedFields } from '~/utils.ts'; @@ -28,15 +29,16 @@ export interface PgInsertConfig { withList?: Subquery[]; onConflict?: SQL; returning?: SelectedFieldsOrdered; + overridingSystemValue_?: boolean; } -export type PgInsertValue = +export type PgInsertValue, OverrideT extends boolean = false> = & { - [Key in keyof TTable['$inferInsert']]: TTable['$inferInsert'][Key] | SQL | Placeholder; + [Key in keyof InferInsertModel]: InferInsertModel[Key] | SQL | Placeholder; } & {}; -export class PgInsertBuilder { +export class PgInsertBuilder { static readonly [entityKind]: string = 'PgInsertBuilder'; constructor( @@ -44,11 +46,17 @@ export class PgInsertBuilder): PgInsertBase; - values(values: PgInsertValue[]): PgInsertBase; - values(values: PgInsertValue | PgInsertValue[]): PgInsertBase { + overridingSystemValue(): Omit, 'overridingSystemValue'>{ + this.overridingSystemValue_ = true; + return this; + } + + values(value: PgInsertValue): PgInsertBase; + values(values: PgInsertValue[]): PgInsertBase; + values(values: PgInsertValue | PgInsertValue[]): PgInsertBase { values = Array.isArray(values) ? values : [values]; if (values.length === 0) { throw new Error('values() must be called with at least one value'); @@ -63,7 +71,7 @@ export class PgInsertBuilder, TInferMode extends 'select' | 'insert' = 'select', - TConfig extends { dbColumnNames: boolean } = { dbColumnNames: false }, + TConfig extends { dbColumnNames: boolean, override?: boolean } = { dbColumnNames: false, override: false }, > = Simplify< TInferMode extends 'insert' ? & { @@ -171,7 +171,8 @@ export type InferModelFromColumns< [ Key in keyof TColumns & string as OptionalKeyOnly< MapColumnName, - TColumns[Key] + TColumns[Key], + TConfig['override'] > ]?: GetColumnData; } @@ -201,5 +202,5 @@ export type InferSelectModel< export type InferInsertModel< TTable extends Table, - TConfig extends { dbColumnNames: boolean } = { dbColumnNames: false }, + TConfig extends { dbColumnNames: boolean, override?: boolean } = { dbColumnNames: false, override: false } > = InferModelFromColumns; From 87b2c2c011ea0620c4a811494c9fbd8b29227dd3 Mon Sep 17 00:00:00 2001 From: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:09:03 +0200 Subject: [PATCH 331/492] Fixed lack of schema name on columns in sql (#3531) * Beta (#3503) * Fix breakpoints option default value * fix: added commonly used columns to supabase auth.users table schema * imports checker with OHM grammar * imports checker with OHM grammar + fix of imports issues * Formatting fix * [MySQL] Add unsigned floating point types + Fix unsigned integer type bugs in Kit (#3284) * Fix bugs with MySQL introspection tests * Update float data type in MySQL * Better support for float types in MySQL * Handle existing unsigned numerical types in MySQL * Add unsigned to floating point types in MySQL * Handle unsigned floating point types in MySQL * Update decimal data type --------- Co-authored-by: Andrii Sherman * Batch of bugfixes for ORM (#3181) * (MySQL) Fix placeholder type error in offset and limit * Add prepared statement tests * Add PG test * Fix blob parsing in bun sqlite driver * Lint and format * Fix file * Fix tests * Use const instead of let in tests * Format --------- Co-authored-by: Andrii Sherman * main to beta (#3404) * Update Github issue templates (#3157) * Update GH issue templates * Update issue templates --------- Co-authored-by: Andrii Sherman * Fix checkboxes --------- Co-authored-by: L-Mario564 * feat: add tablesFilter to pushSchema api (#3141) * feat: add tablesFilter to pushSchema api * Format with dprint --------- Co-authored-by: Andrii Sherman * Batch of bugfixes for Kit (#2959) * Escape single quote in enum value * Escape single quotes in string default values * Handle instrospection of strings with single quotes * Add tests * Add tests * Uncomment tests * Fix SQL statement order in MySQL * Add MySQL test * Fix alter composite PK statement missing quotes in PG * Add tests * Handle SQL expressions in timestamp, date and time in PG * Use `.run` instead of `.query` in SQLite queries that don't return anything * Fix parsing of enum array types in PG * Generate more PG index operators * Fix primary key recreate on table rename * Format * Format * Update test * Format * Fix tests * Fix terminal output mistake * Remove duplicate import --------- Co-authored-by: Andrii Sherman * Bump versions --------- Co-authored-by: Steffen <3752127+klotztech@users.noreply.github.com> Co-authored-by: Nicholas Ly Co-authored-by: Alex Blokh Co-authored-by: Sukairo-02 Co-authored-by: L-Mario564 Co-authored-by: Dan Ribbens * Dprint * Fixed `sql` omitting schema names when processing columns, fixed related test cases * Fixed dprint formatting issues * Fixed lack of schema name on integration tests column references * Removed `\!` --------- Co-authored-by: Andrii Sherman Co-authored-by: Steffen <3752127+klotztech@users.noreply.github.com> Co-authored-by: Nicholas Ly Co-authored-by: Alex Blokh Co-authored-by: L-Mario564 Co-authored-by: Dan Ribbens --- drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- drizzle-orm/src/sql/sql.ts | 12 ++++++++++-- drizzle-orm/tests/casing/mysql-to-camel.test.ts | 2 +- drizzle-orm/tests/casing/mysql-to-snake.test.ts | 2 +- drizzle-orm/tests/casing/pg-to-camel.test.ts | 2 +- drizzle-orm/tests/casing/pg-to-snake.test.ts | 2 +- integration-tests/tests/mysql/mysql-common.ts | 2 +- integration-tests/tests/pg/pg-common.ts | 2 +- 9 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index e45f7dbc5..1c911f23f 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -141,4 +141,4 @@ "default": "./api.mjs" } } -} \ No newline at end of file +} diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 598ee9a1e..b2b204ead 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -203,4 +203,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} \ No newline at end of file +} diff --git a/drizzle-orm/src/sql/sql.ts b/drizzle-orm/src/sql/sql.ts index 19185f1bf..234370a85 100644 --- a/drizzle-orm/src/sql/sql.ts +++ b/drizzle-orm/src/sql/sql.ts @@ -7,7 +7,7 @@ import { tracer } from '~/tracing.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { AnyColumn } from '../column.ts'; import { Column } from '../column.ts'; -import { Table } from '../table.ts'; +import { IsAlias, Table } from '../table.ts'; /** * This class is used to indicate a primitive param value that is used in `sql` tag. @@ -192,7 +192,15 @@ export class SQL implements SQLWrapper { if (_config.invokeSource === 'indexes') { return { sql: escapeName(columnName), params: [] }; } - return { sql: escapeName(chunk.table[Table.Symbol.Name]) + '.' + escapeName(columnName), params: [] }; + + const schemaName = chunk.table[Table.Symbol.Schema]; + return { + sql: chunk.table[IsAlias] || schemaName === undefined + ? escapeName(chunk.table[Table.Symbol.Name]) + '.' + escapeName(columnName) + : escapeName(schemaName) + '.' + escapeName(chunk.table[Table.Symbol.Name]) + '.' + + escapeName(columnName), + params: [], + }; } if (is(chunk, View)) { diff --git a/drizzle-orm/tests/casing/mysql-to-camel.test.ts b/drizzle-orm/tests/casing/mysql-to-camel.test.ts index 651365485..aa8aa04ee 100644 --- a/drizzle-orm/tests/casing/mysql-to-camel.test.ts +++ b/drizzle-orm/tests/casing/mysql-to-camel.test.ts @@ -66,7 +66,7 @@ describe('mysql to snake case', () => { expect(query.toSQL()).toEqual({ sql: - "select `users`.`firstName` || ' ' || `users`.`lastName` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`userId` order by `users`.`firstName` asc", + "select `users`.`firstName` || ' ' || `users`.`lastName` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `test`.`developers`.`userId` order by `users`.`firstName` asc", params: [], }); expect(db.dialect.casing.cache).toEqual(cache); diff --git a/drizzle-orm/tests/casing/mysql-to-snake.test.ts b/drizzle-orm/tests/casing/mysql-to-snake.test.ts index 8ce65e2f9..60496af22 100644 --- a/drizzle-orm/tests/casing/mysql-to-snake.test.ts +++ b/drizzle-orm/tests/casing/mysql-to-snake.test.ts @@ -66,7 +66,7 @@ describe('mysql to snake case', () => { expect(query.toSQL()).toEqual({ sql: - "select `users`.`first_name` || ' ' || `users`.`last_name` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`user_id` order by `users`.`first_name` asc", + "select `users`.`first_name` || ' ' || `users`.`last_name` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `test`.`developers`.`user_id` order by `users`.`first_name` asc", params: [], }); expect(db.dialect.casing.cache).toEqual(cache); diff --git a/drizzle-orm/tests/casing/pg-to-camel.test.ts b/drizzle-orm/tests/casing/pg-to-camel.test.ts index 8d4420403..e325745da 100644 --- a/drizzle-orm/tests/casing/pg-to-camel.test.ts +++ b/drizzle-orm/tests/casing/pg-to-camel.test.ts @@ -62,7 +62,7 @@ describe('postgres to camel case', () => { expect(query.toSQL()).toEqual({ sql: - 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."userId" order by "users"."firstName" asc', + 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "test"."developers"."userId" order by "users"."firstName" asc', params: [], }); expect(db.dialect.casing.cache).toEqual(cache); diff --git a/drizzle-orm/tests/casing/pg-to-snake.test.ts b/drizzle-orm/tests/casing/pg-to-snake.test.ts index 0384e70ca..0c2aeaa27 100644 --- a/drizzle-orm/tests/casing/pg-to-snake.test.ts +++ b/drizzle-orm/tests/casing/pg-to-snake.test.ts @@ -62,7 +62,7 @@ describe('postgres to snake case', () => { expect(query.toSQL()).toEqual({ sql: - 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."user_id" order by "users"."first_name" asc', + 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "test"."developers"."user_id" order by "users"."first_name" asc', params: [], }); expect(db.dialect.casing.cache).toEqual(cache); diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index e2d74dc50..e2695d767 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3416,7 +3416,7 @@ export function tests(driver?: string) { expect(query).toEqual({ sql: - `select \`id\`, \`name\` from \`mySchema\`.\`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + `select \`id\`, \`name\` from \`mySchema\`.\`userstest\` group by \`mySchema\`.\`userstest\`.\`id\`, \`mySchema\`.\`userstest\`.\`name\``, params: [], }); }); diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index c7f4b9be7..dd2971c3c 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4278,7 +4278,7 @@ export function tests() { .toSQL(); expect(query).toEqual({ - sql: 'select "id", "name" from "mySchema"."users" group by "users"."id", "users"."name"', + sql: 'select "id", "name" from "mySchema"."users" group by "mySchema"."users"."id", "mySchema"."users"."name"', params: [], }); }); From ae2f4b4bb7da2da3557368224338cf826f3b954c Mon Sep 17 00:00:00 2001 From: Michael Lohr Date: Tue, 12 Nov 2024 15:15:48 +0100 Subject: [PATCH 332/492] Update driver.ts (#3424) Co-authored-by: Andrii Sherman --- drizzle-orm/src/neon-http/driver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index 4ef1dc36a..cfa0c7861 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -16,7 +16,7 @@ export interface NeonDriverOptions { } export class NeonHttpDriver { - static readonly [entityKind]: string = 'NeonDriver'; + static readonly [entityKind]: string = 'NeonHttpDriver'; constructor( private client: NeonHttpClient, From 2796c1db848a6d68bd5cead123d8f691dc163d1c Mon Sep 17 00:00:00 2001 From: Mickael Lecoq Date: Tue, 12 Nov 2024 15:37:25 +0100 Subject: [PATCH 333/492] fix: wrong dialect set in mysql/sqlite introspect (#2865) Co-authored-by: Andrii Sherman From 571a67d1e679807c16920033b5dffc6dc4af5c45 Mon Sep 17 00:00:00 2001 From: Asher Chan Date: Tue, 12 Nov 2024 22:37:50 +0800 Subject: [PATCH 334/492] Extra `update` in comment (#2864) Removed and extra `update` text in the comment description using onDuplicateKeyUpdate --- drizzle-orm/src/mysql-core/query-builders/insert.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/insert.ts b/drizzle-orm/src/mysql-core/query-builders/insert.ts index 5a9afaa8a..f3b4eec21 100644 --- a/drizzle-orm/src/mysql-core/query-builders/insert.ts +++ b/drizzle-orm/src/mysql-core/query-builders/insert.ts @@ -210,7 +210,7 @@ export class MySqlInsertBase< /** * Adds an `on duplicate key update` clause to the query. * - * Calling this method will update update the row if any unique index conflicts. MySQL will automatically determine the conflict target based on the primary key and unique indexes. + * Calling this method will update the row if any unique index conflicts. MySQL will automatically determine the conflict target based on the primary key and unique indexes. * * See docs: {@link https://orm.drizzle.team/docs/insert#on-duplicate-key-update} * From 2cb427f03769b2c19d8bfc43204a22079d8bd7d5 Mon Sep 17 00:00:00 2001 From: Alexis Reymann <16920060+Yoctoboy@users.noreply.github.com> Date: Tue, 12 Nov 2024 15:38:28 +0100 Subject: [PATCH 335/492] chore: export PgIntegerBuilderInitial type as are all other pg-core columns (#2846) Co-authored-by: Alexis Reymann Co-authored-by: Andrii Sherman --- drizzle-orm/src/pg-core/columns/integer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/pg-core/columns/integer.ts b/drizzle-orm/src/pg-core/columns/integer.ts index bb70f9b41..6c88126d2 100644 --- a/drizzle-orm/src/pg-core/columns/integer.ts +++ b/drizzle-orm/src/pg-core/columns/integer.ts @@ -5,7 +5,7 @@ import type { AnyPgTable } from '../table.ts'; import { PgColumn } from './common.ts'; import { PgIntColumnBaseBuilder } from './int.common.ts'; -type PgIntegerBuilderInitial = PgIntegerBuilder<{ +export type PgIntegerBuilderInitial = PgIntegerBuilder<{ name: TName; dataType: 'number'; columnType: 'PgInteger'; From 96ca2b585e06df1ebaf1a1a649afeee36ca050ff Mon Sep 17 00:00:00 2001 From: L-Mario564 Date: Tue, 12 Nov 2024 06:39:37 -0800 Subject: [PATCH 336/492] Support more types in text comparing sql expressions (#2805) Co-authored-by: Andrii Sherman --- drizzle-orm/src/sql/expressions/conditions.ts | 8 ++++---- drizzle-orm/type-tests/mysql/with.ts | 5 ++++- drizzle-orm/type-tests/pg/with.ts | 5 ++++- drizzle-orm/type-tests/sqlite/with.ts | 5 ++++- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drizzle-orm/src/sql/expressions/conditions.ts b/drizzle-orm/src/sql/expressions/conditions.ts index ba0e21fbc..7ad1355dd 100644 --- a/drizzle-orm/src/sql/expressions/conditions.ts +++ b/drizzle-orm/src/sql/expressions/conditions.ts @@ -526,7 +526,7 @@ export function notBetween( * * @see ilike for a case-insensitive version of this condition */ -export function like(column: Column, value: string | SQLWrapper): SQL { +export function like(column: Column | SQL.Aliased | SQL, value: string | SQLWrapper): SQL { return sql`${column} like ${value}`; } @@ -548,7 +548,7 @@ export function like(column: Column, value: string | SQLWrapper): SQL { * @see like for the inverse condition * @see notIlike for a case-insensitive version of this condition */ -export function notLike(column: Column, value: string | SQLWrapper): SQL { +export function notLike(column: Column | SQL.Aliased | SQL, value: string | SQLWrapper): SQL { return sql`${column} not like ${value}`; } @@ -571,7 +571,7 @@ export function notLike(column: Column, value: string | SQLWrapper): SQL { * * @see like for a case-sensitive version of this condition */ -export function ilike(column: Column, value: string | SQLWrapper): SQL { +export function ilike(column: Column | SQL.Aliased | SQL, value: string | SQLWrapper): SQL { return sql`${column} ilike ${value}`; } @@ -593,7 +593,7 @@ export function ilike(column: Column, value: string | SQLWrapper): SQL { * @see ilike for the inverse condition * @see notLike for a case-sensitive version of this condition */ -export function notIlike(column: Column, value: string | SQLWrapper): SQL { +export function notIlike(column: Column | SQL.Aliased | SQL, value: string | SQLWrapper): SQL { return sql`${column} not ilike ${value}`; } diff --git a/drizzle-orm/type-tests/mysql/with.ts b/drizzle-orm/type-tests/mysql/with.ts index b4e528191..e6f240489 100644 --- a/drizzle-orm/type-tests/mysql/with.ts +++ b/drizzle-orm/type-tests/mysql/with.ts @@ -1,6 +1,6 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; -import { gt, inArray } from '~/expressions.ts'; +import { gt, inArray, like } from '~/expressions.ts'; import { int, mysqlTable, serial, text } from '~/mysql-core/index.ts'; import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; @@ -77,4 +77,7 @@ const orders = mysqlTable('orders', { generated: string | null; }[], typeof allFromWith> >; + + const regionalSalesWith = db.$with('regional_sales_with').as(db.select().from(regionalSales)); + db.with(regionalSalesWith).select().from(regionalSalesWith).where(like(regionalSalesWith.totalSales, 'abc')); } diff --git a/drizzle-orm/type-tests/pg/with.ts b/drizzle-orm/type-tests/pg/with.ts index d5fcc96ed..288e3b6d0 100644 --- a/drizzle-orm/type-tests/pg/with.ts +++ b/drizzle-orm/type-tests/pg/with.ts @@ -1,6 +1,6 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; -import { gt, inArray } from '~/expressions.ts'; +import { gt, inArray, like } from '~/expressions.ts'; import { integer, pgTable, serial, text } from '~/pg-core/index.ts'; import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; @@ -77,4 +77,7 @@ const orders = pgTable('orders', { generated: string | null; }[], typeof allFromWith> >; + + const regionalSalesWith = db.$with('regional_sales_with').as(db.select().from(regionalSales)); + db.with(regionalSalesWith).select().from(regionalSalesWith).where(like(regionalSalesWith.totalSales, 'abc')); } diff --git a/drizzle-orm/type-tests/sqlite/with.ts b/drizzle-orm/type-tests/sqlite/with.ts index 8b5963eb6..b26e4e7d7 100644 --- a/drizzle-orm/type-tests/sqlite/with.ts +++ b/drizzle-orm/type-tests/sqlite/with.ts @@ -1,6 +1,6 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; -import { gt, inArray } from '~/expressions.ts'; +import { gt, inArray, like } from '~/expressions.ts'; import { sql } from '~/sql/sql.ts'; import { integer, sqliteTable, text } from '~/sqlite-core/index.ts'; import { db } from './db.ts'; @@ -78,4 +78,7 @@ const orders = sqliteTable('orders', { generated: string | null; }[], typeof allFromWith> >; + + const regionalSalesWith = db.$with('regional_sales_with').as(db.select().from(regionalSales)); + db.with(regionalSalesWith).select().from(regionalSalesWith).where(like(regionalSalesWith.totalSales, 'abc')); } From 9859e8e4e2359d25b3ee088af1801d866c0f5e71 Mon Sep 17 00:00:00 2001 From: Max Leiter Date: Tue, 12 Nov 2024 06:39:45 -0800 Subject: [PATCH 337/492] drizzle-kit/commands/migrate: fix "you code" typo (#2801) "put you code below" should be "put your code below" From a08a9edca53d834cfe9ddbd5803a4f69a7cf9ec0 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Tue, 12 Nov 2024 17:54:01 +0200 Subject: [PATCH 338/492] attempt to fix identity columns types --- drizzle-orm/src/column-builder.ts | 3 +- drizzle-orm/src/mysql-core/columns/bigint.ts | 2 + drizzle-orm/src/mysql-core/columns/binary.ts | 1 + drizzle-orm/src/mysql-core/columns/boolean.ts | 1 + drizzle-orm/src/mysql-core/columns/char.ts | 1 + drizzle-orm/src/mysql-core/columns/custom.ts | 1 + drizzle-orm/src/mysql-core/columns/date.ts | 2 + .../src/mysql-core/columns/datetime.ts | 2 + drizzle-orm/src/mysql-core/columns/decimal.ts | 1 + drizzle-orm/src/mysql-core/columns/double.ts | 1 + drizzle-orm/src/mysql-core/columns/enum.ts | 1 + drizzle-orm/src/mysql-core/columns/float.ts | 1 + drizzle-orm/src/mysql-core/columns/int.ts | 1 + drizzle-orm/src/mysql-core/columns/json.ts | 1 + .../src/mysql-core/columns/mediumint.ts | 1 + drizzle-orm/src/mysql-core/columns/real.ts | 1 + drizzle-orm/src/mysql-core/columns/serial.ts | 1 + .../src/mysql-core/columns/smallint.ts | 1 + drizzle-orm/src/mysql-core/columns/text.ts | 1 + drizzle-orm/src/mysql-core/columns/time.ts | 1 + .../src/mysql-core/columns/timestamp.ts | 2 + drizzle-orm/src/mysql-core/columns/tinyint.ts | 1 + .../src/mysql-core/columns/varbinary.ts | 1 + drizzle-orm/src/mysql-core/columns/varchar.ts | 1 + drizzle-orm/src/mysql-core/columns/year.ts | 1 + drizzle-orm/src/operations.ts | 35 +++++++++++++-- drizzle-orm/src/pg-core/columns/bigint.ts | 2 + drizzle-orm/src/pg-core/columns/bigserial.ts | 2 + drizzle-orm/src/pg-core/columns/boolean.ts | 1 + drizzle-orm/src/pg-core/columns/char.ts | 1 + drizzle-orm/src/pg-core/columns/cidr.ts | 1 + drizzle-orm/src/pg-core/columns/custom.ts | 1 + drizzle-orm/src/pg-core/columns/date.ts | 2 + .../src/pg-core/columns/double-precision.ts | 1 + drizzle-orm/src/pg-core/columns/enum.ts | 1 + drizzle-orm/src/pg-core/columns/inet.ts | 1 + drizzle-orm/src/pg-core/columns/int.common.ts | 18 ++++++++ drizzle-orm/src/pg-core/columns/integer.ts | 4 +- drizzle-orm/src/pg-core/columns/interval.ts | 1 + drizzle-orm/src/pg-core/columns/json.ts | 1 + drizzle-orm/src/pg-core/columns/jsonb.ts | 1 + drizzle-orm/src/pg-core/columns/line.ts | 2 + drizzle-orm/src/pg-core/columns/macaddr.ts | 1 + drizzle-orm/src/pg-core/columns/macaddr8.ts | 1 + drizzle-orm/src/pg-core/columns/numeric.ts | 1 + drizzle-orm/src/pg-core/columns/point.ts | 2 + .../columns/postgis_extension/geometry.ts | 2 + drizzle-orm/src/pg-core/columns/real.ts | 1 + drizzle-orm/src/pg-core/columns/serial.ts | 1 + drizzle-orm/src/pg-core/columns/smallint.ts | 1 + .../src/pg-core/columns/smallserial.ts | 1 + drizzle-orm/src/pg-core/columns/text.ts | 1 + drizzle-orm/src/pg-core/columns/time.ts | 1 + drizzle-orm/src/pg-core/columns/timestamp.ts | 2 + drizzle-orm/src/pg-core/columns/uuid.ts | 1 + drizzle-orm/src/pg-core/columns/varchar.ts | 1 + .../pg-core/columns/vector_extension/bit.ts | 1 + .../columns/vector_extension/halfvec.ts | 1 + .../columns/vector_extension/sparsevec.ts | 1 + .../columns/vector_extension/vector.ts | 1 + .../src/pg-core/query-builders/insert.ts | 2 +- drizzle-orm/src/sqlite-core/columns/blob.ts | 3 ++ drizzle-orm/src/sqlite-core/columns/custom.ts | 1 + .../src/sqlite-core/columns/integer.ts | 3 ++ .../src/sqlite-core/columns/numeric.ts | 1 + drizzle-orm/src/sqlite-core/columns/real.ts | 1 + drizzle-orm/src/sqlite-core/columns/text.ts | 2 + drizzle-orm/src/table.ts | 43 +++++++++++-------- drizzle-orm/type-tests/pg/array.ts | 1 + drizzle-orm/type-tests/pg/insert.ts | 8 +++- drizzle-orm/type-tests/pg/tables.ts | 36 ++++++++++++++++ 71 files changed, 203 insertions(+), 25 deletions(-) diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index dcc2b4734..d87460336 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -162,7 +162,8 @@ export type IsIdentity< _: { notNull: true; hasDefault: true; - identity: TType; + generated: { as: any; type: TType }; + identity: TType ; }; }; // always -> user pass overriding and diff --git a/drizzle-orm/src/mysql-core/columns/bigint.ts b/drizzle-orm/src/mysql-core/columns/bigint.ts index 7411c07ce..2dc7cb4bc 100644 --- a/drizzle-orm/src/mysql-core/columns/bigint.ts +++ b/drizzle-orm/src/mysql-core/columns/bigint.ts @@ -13,6 +13,7 @@ export type MySqlBigInt53BuilderInitial = MySqlBigInt53Bui driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlBigInt53Builder> @@ -61,6 +62,7 @@ export type MySqlBigInt64BuilderInitial = MySqlBigInt64Bui driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlBigInt64Builder> diff --git a/drizzle-orm/src/mysql-core/columns/binary.ts b/drizzle-orm/src/mysql-core/columns/binary.ts index 7031b565c..a9df0b5f1 100644 --- a/drizzle-orm/src/mysql-core/columns/binary.ts +++ b/drizzle-orm/src/mysql-core/columns/binary.ts @@ -13,6 +13,7 @@ export type MySqlBinaryBuilderInitial = MySqlBinaryBuilder driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlBinaryBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/boolean.ts b/drizzle-orm/src/mysql-core/columns/boolean.ts index 9e786b6f9..01129244e 100644 --- a/drizzle-orm/src/mysql-core/columns/boolean.ts +++ b/drizzle-orm/src/mysql-core/columns/boolean.ts @@ -12,6 +12,7 @@ export type MySqlBooleanBuilderInitial = MySqlBooleanBuild driverParam: number | boolean; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlBooleanBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/char.ts b/drizzle-orm/src/mysql-core/columns/char.ts index efcb7e65a..02eb9a8a7 100644 --- a/drizzle-orm/src/mysql-core/columns/char.ts +++ b/drizzle-orm/src/mysql-core/columns/char.ts @@ -13,6 +13,7 @@ export type MySqlCharBuilderInitial; export class MySqlCharBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/custom.ts b/drizzle-orm/src/mysql-core/columns/custom.ts index 711b27813..2dcde8d96 100644 --- a/drizzle-orm/src/mysql-core/columns/custom.ts +++ b/drizzle-orm/src/mysql-core/columns/custom.ts @@ -15,6 +15,7 @@ export type ConvertCustomConfig = MySqlDateBuilder<{ driverParam: string | number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlDateBuilder> extends MySqlColumnBuilder { @@ -57,6 +58,7 @@ export type MySqlDateStringBuilderInitial = MySqlDateStrin driverParam: string | number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlDateStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/datetime.ts b/drizzle-orm/src/mysql-core/columns/datetime.ts index 61b062e8f..ae0ad90ed 100644 --- a/drizzle-orm/src/mysql-core/columns/datetime.ts +++ b/drizzle-orm/src/mysql-core/columns/datetime.ts @@ -13,6 +13,7 @@ export type MySqlDateTimeBuilderInitial = MySqlDateTimeBui driverParam: string | number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlDateTimeBuilder> @@ -71,6 +72,7 @@ export type MySqlDateTimeStringBuilderInitial = MySqlDateT driverParam: string | number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlDateTimeStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index 67cefb531..b3a689471 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -13,6 +13,7 @@ export type MySqlDecimalBuilderInitial = MySqlDecimalBuild driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlDecimalBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index dfe5fca2e..fbd0d3b37 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -13,6 +13,7 @@ export type MySqlDoubleBuilderInitial = MySqlDoubleBuilder driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlDoubleBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/enum.ts b/drizzle-orm/src/mysql-core/columns/enum.ts index 6a586ca7c..7d3b2f2be 100644 --- a/drizzle-orm/src/mysql-core/columns/enum.ts +++ b/drizzle-orm/src/mysql-core/columns/enum.ts @@ -14,6 +14,7 @@ export type MySqlEnumColumnBuilderInitial; export class MySqlEnumColumnBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/float.ts b/drizzle-orm/src/mysql-core/columns/float.ts index 12ebd3e74..62537d638 100644 --- a/drizzle-orm/src/mysql-core/columns/float.ts +++ b/drizzle-orm/src/mysql-core/columns/float.ts @@ -13,6 +13,7 @@ export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlFloatBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/int.ts b/drizzle-orm/src/mysql-core/columns/int.ts index aca0ea61e..7860a5c96 100644 --- a/drizzle-orm/src/mysql-core/columns/int.ts +++ b/drizzle-orm/src/mysql-core/columns/int.ts @@ -13,6 +13,7 @@ export type MySqlIntBuilderInitial = MySqlIntBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/json.ts b/drizzle-orm/src/mysql-core/columns/json.ts index ecb73ed82..66d2899d0 100644 --- a/drizzle-orm/src/mysql-core/columns/json.ts +++ b/drizzle-orm/src/mysql-core/columns/json.ts @@ -12,6 +12,7 @@ export type MySqlJsonBuilderInitial = MySqlJsonBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlJsonBuilder> extends MySqlColumnBuilder { diff --git a/drizzle-orm/src/mysql-core/columns/mediumint.ts b/drizzle-orm/src/mysql-core/columns/mediumint.ts index 764969d31..a8c9c0498 100644 --- a/drizzle-orm/src/mysql-core/columns/mediumint.ts +++ b/drizzle-orm/src/mysql-core/columns/mediumint.ts @@ -14,6 +14,7 @@ export type MySqlMediumIntBuilderInitial = MySqlMediumIntB driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlMediumIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/real.ts b/drizzle-orm/src/mysql-core/columns/real.ts index 8b9eca794..e7b157537 100644 --- a/drizzle-orm/src/mysql-core/columns/real.ts +++ b/drizzle-orm/src/mysql-core/columns/real.ts @@ -13,6 +13,7 @@ export type MySqlRealBuilderInitial = MySqlRealBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlRealBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/serial.ts b/drizzle-orm/src/mysql-core/columns/serial.ts index 88485d6b2..27fa1e610 100644 --- a/drizzle-orm/src/mysql-core/columns/serial.ts +++ b/drizzle-orm/src/mysql-core/columns/serial.ts @@ -24,6 +24,7 @@ export type MySqlSerialBuilderInitial = IsAutoincrement< driverParam: number; enumValues: undefined; generated: undefined; + identity: undefined; }> > > diff --git a/drizzle-orm/src/mysql-core/columns/smallint.ts b/drizzle-orm/src/mysql-core/columns/smallint.ts index 482ff89ea..ebf1def13 100644 --- a/drizzle-orm/src/mysql-core/columns/smallint.ts +++ b/drizzle-orm/src/mysql-core/columns/smallint.ts @@ -14,6 +14,7 @@ export type MySqlSmallIntBuilderInitial = MySqlSmallIntBui driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlSmallIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/text.ts b/drizzle-orm/src/mysql-core/columns/text.ts index 18434a532..f7d8a3eab 100644 --- a/drizzle-orm/src/mysql-core/columns/text.ts +++ b/drizzle-orm/src/mysql-core/columns/text.ts @@ -15,6 +15,7 @@ export type MySqlTextBuilderInitial; export class MySqlTextBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/time.ts b/drizzle-orm/src/mysql-core/columns/time.ts index 408453947..672f3eda3 100644 --- a/drizzle-orm/src/mysql-core/columns/time.ts +++ b/drizzle-orm/src/mysql-core/columns/time.ts @@ -13,6 +13,7 @@ export type MySqlTimeBuilderInitial = MySqlTimeBuilder<{ driverParam: string | number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlTimeBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/timestamp.ts b/drizzle-orm/src/mysql-core/columns/timestamp.ts index 892f8e603..86ccf59a9 100644 --- a/drizzle-orm/src/mysql-core/columns/timestamp.ts +++ b/drizzle-orm/src/mysql-core/columns/timestamp.ts @@ -13,6 +13,7 @@ export type MySqlTimestampBuilderInitial = MySqlTimestampB driverParam: string | number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlTimestampBuilder> @@ -65,6 +66,7 @@ export type MySqlTimestampStringBuilderInitial = MySqlTime driverParam: string | number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlTimestampStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/tinyint.ts b/drizzle-orm/src/mysql-core/columns/tinyint.ts index ee4ccdaa7..a221fdab5 100644 --- a/drizzle-orm/src/mysql-core/columns/tinyint.ts +++ b/drizzle-orm/src/mysql-core/columns/tinyint.ts @@ -14,6 +14,7 @@ export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuild driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlTinyIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/varbinary.ts b/drizzle-orm/src/mysql-core/columns/varbinary.ts index bc0dde635..bf8e32ce1 100644 --- a/drizzle-orm/src/mysql-core/columns/varbinary.ts +++ b/drizzle-orm/src/mysql-core/columns/varbinary.ts @@ -13,6 +13,7 @@ export type MySqlVarBinaryBuilderInitial = MySqlVarBinaryB driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlVarBinaryBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/varchar.ts b/drizzle-orm/src/mysql-core/columns/varchar.ts index 32cfda7e9..2905d91ef 100644 --- a/drizzle-orm/src/mysql-core/columns/varchar.ts +++ b/drizzle-orm/src/mysql-core/columns/varchar.ts @@ -14,6 +14,7 @@ export type MySqlVarCharBuilderInitial; diff --git a/drizzle-orm/src/mysql-core/columns/year.ts b/drizzle-orm/src/mysql-core/columns/year.ts index 8a7a44410..8bcd923f5 100644 --- a/drizzle-orm/src/mysql-core/columns/year.ts +++ b/drizzle-orm/src/mysql-core/columns/year.ts @@ -12,6 +12,7 @@ export type MySqlYearBuilderInitial = MySqlYearBuilder<{ driverParam: number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class MySqlYearBuilder> extends MySqlColumnBuilder { diff --git a/drizzle-orm/src/operations.ts b/drizzle-orm/src/operations.ts index d827843fc..b7f488f8c 100644 --- a/drizzle-orm/src/operations.ts +++ b/drizzle-orm/src/operations.ts @@ -13,20 +13,47 @@ export type NotGenerated = T extends AnyC }> ? TKey : never; +// export type OptionalKeyOnly< +// TKey extends string, +// T extends Column, +// // OverrideT extends boolean | undefined = false +// > = TKey extends RequiredKeyOnly ? never +// : TKey extends NotGenerated ? TKey +// : T['_']['generated'] extends object ? T['_']['generated']['type'] extends 'byDefault' ? TKey +// : never +// // ( +// // T['_']['identity'] extends 'always'? +// // OverrideT extends true? TKey: never +// // : never +// // ) +// : never; + export type OptionalKeyOnly< TKey extends string, T extends Column, OverrideT extends boolean | undefined = false > = TKey extends RequiredKeyOnly ? never - : TKey extends NotGenerated ? TKey - : T['_']['generated'] extends object ? T['_']['generated']['type'] extends 'byDefault' ? TKey + : TKey extends NotGenerated ? ( + T['_'] + // T['_']['identity'] extends 'always'? + // OverrideT extends true? TKey: never + // : TKey + ): + never; + +export type IdentityColumns< + TKey extends string, + T extends Column, + OverrideT extends boolean | undefined = false +> = TKey extends RequiredKeyOnly ? never + : TKey extends OptionalKeyOnly? never + : T['_']['identity'] extends 'byDefault' ? TKey : ( T['_']['identity'] extends 'always'? OverrideT extends true? TKey: never : never - ) - : never; + ); // byDefault -> accept // always -> accept only if overide and always diff --git a/drizzle-orm/src/pg-core/columns/bigint.ts b/drizzle-orm/src/pg-core/columns/bigint.ts index 23e1e7f15..6f23f5796 100644 --- a/drizzle-orm/src/pg-core/columns/bigint.ts +++ b/drizzle-orm/src/pg-core/columns/bigint.ts @@ -15,6 +15,7 @@ export type PgBigInt53BuilderInitial = PgBigInt53Builder<{ driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgBigInt53Builder> @@ -57,6 +58,7 @@ export type PgBigInt64BuilderInitial = PgBigInt64Builder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgBigInt64Builder> diff --git a/drizzle-orm/src/pg-core/columns/bigserial.ts b/drizzle-orm/src/pg-core/columns/bigserial.ts index ed4224354..41872f622 100644 --- a/drizzle-orm/src/pg-core/columns/bigserial.ts +++ b/drizzle-orm/src/pg-core/columns/bigserial.ts @@ -21,6 +21,7 @@ export type PgBigSerial53BuilderInitial = NotNull< driverParam: number; enumValues: undefined; generated: undefined; + identity: undefined; }> > >; @@ -72,6 +73,7 @@ export type PgBigSerial64BuilderInitial = NotNull< driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }> > >; diff --git a/drizzle-orm/src/pg-core/columns/boolean.ts b/drizzle-orm/src/pg-core/columns/boolean.ts index cd30895c7..d28e57baf 100644 --- a/drizzle-orm/src/pg-core/columns/boolean.ts +++ b/drizzle-orm/src/pg-core/columns/boolean.ts @@ -12,6 +12,7 @@ export type PgBooleanBuilderInitial = PgBooleanBuilder<{ driverParam: boolean; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgBooleanBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/char.ts b/drizzle-orm/src/pg-core/columns/char.ts index 6629f08cc..dbd30dbc7 100644 --- a/drizzle-orm/src/pg-core/columns/char.ts +++ b/drizzle-orm/src/pg-core/columns/char.ts @@ -13,6 +13,7 @@ export type PgCharBuilderInitial; export class PgCharBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/cidr.ts b/drizzle-orm/src/pg-core/columns/cidr.ts index 6caa3dc25..acace9268 100644 --- a/drizzle-orm/src/pg-core/columns/cidr.ts +++ b/drizzle-orm/src/pg-core/columns/cidr.ts @@ -12,6 +12,7 @@ export type PgCidrBuilderInitial = PgCidrBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgCidrBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/custom.ts b/drizzle-orm/src/pg-core/columns/custom.ts index b59169ed6..313575d41 100644 --- a/drizzle-orm/src/pg-core/columns/custom.ts +++ b/drizzle-orm/src/pg-core/columns/custom.ts @@ -15,6 +15,7 @@ export type ConvertCustomConfig = PgDateBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgDateBuilder> extends PgDateColumnBaseBuilder { @@ -55,6 +56,7 @@ export type PgDateStringBuilderInitial = PgDateStringBuild driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgDateStringBuilder> diff --git a/drizzle-orm/src/pg-core/columns/double-precision.ts b/drizzle-orm/src/pg-core/columns/double-precision.ts index 77245ea45..3d157e54a 100644 --- a/drizzle-orm/src/pg-core/columns/double-precision.ts +++ b/drizzle-orm/src/pg-core/columns/double-precision.ts @@ -12,6 +12,7 @@ export type PgDoublePrecisionBuilderInitial = PgDoublePrec driverParam: string | number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgDoublePrecisionBuilder> diff --git a/drizzle-orm/src/pg-core/columns/enum.ts b/drizzle-orm/src/pg-core/columns/enum.ts index 7712ca606..1e0c67ef2 100644 --- a/drizzle-orm/src/pg-core/columns/enum.ts +++ b/drizzle-orm/src/pg-core/columns/enum.ts @@ -14,6 +14,7 @@ export type PgEnumColumnBuilderInitial; const isPgEnumSym = Symbol.for('drizzle:isPgEnum'); diff --git a/drizzle-orm/src/pg-core/columns/inet.ts b/drizzle-orm/src/pg-core/columns/inet.ts index 6b6210fcf..b2e353188 100644 --- a/drizzle-orm/src/pg-core/columns/inet.ts +++ b/drizzle-orm/src/pg-core/columns/inet.ts @@ -12,6 +12,7 @@ export type PgInetBuilderInitial = PgInetBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgInetBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/int.common.ts b/drizzle-orm/src/pg-core/columns/int.common.ts index b12ed68f5..8c388fb2e 100644 --- a/drizzle-orm/src/pg-core/columns/int.common.ts +++ b/drizzle-orm/src/pg-core/columns/int.common.ts @@ -7,6 +7,24 @@ import type { import { entityKind } from '~/entity.ts'; import type { PgSequenceOptions } from '../sequence.ts'; import { PgColumnBuilder } from './common.ts'; +import type { PgIntegerBuilderInitial } from './integer.ts'; +// import type { Simplify } from '~/index.ts'; + + +// type a = Simplify, "always">>; +type a = IsIdentity, "always">; + +type a1 = {'_': { + identity: undefined +}} + +type a2 = a1 & {'_': { + identity: 'always' +}} + +let b: a2; +b._ + export abstract class PgIntColumnBaseBuilder< T extends ColumnBuilderBaseConfig, diff --git a/drizzle-orm/src/pg-core/columns/integer.ts b/drizzle-orm/src/pg-core/columns/integer.ts index bb70f9b41..98822bee6 100644 --- a/drizzle-orm/src/pg-core/columns/integer.ts +++ b/drizzle-orm/src/pg-core/columns/integer.ts @@ -5,7 +5,8 @@ import type { AnyPgTable } from '../table.ts'; import { PgColumn } from './common.ts'; import { PgIntColumnBaseBuilder } from './int.common.ts'; -type PgIntegerBuilderInitial = PgIntegerBuilder<{ +// no need export +export type PgIntegerBuilderInitial = PgIntegerBuilder<{ name: TName; dataType: 'number'; columnType: 'PgInteger'; @@ -13,6 +14,7 @@ type PgIntegerBuilderInitial = PgIntegerBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgIntegerBuilder> diff --git a/drizzle-orm/src/pg-core/columns/interval.ts b/drizzle-orm/src/pg-core/columns/interval.ts index 4d3ed4588..fa0af41fb 100644 --- a/drizzle-orm/src/pg-core/columns/interval.ts +++ b/drizzle-orm/src/pg-core/columns/interval.ts @@ -14,6 +14,7 @@ export type PgIntervalBuilderInitial = PgIntervalBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgIntervalBuilder> diff --git a/drizzle-orm/src/pg-core/columns/json.ts b/drizzle-orm/src/pg-core/columns/json.ts index 3c440c7d2..76f576ee6 100644 --- a/drizzle-orm/src/pg-core/columns/json.ts +++ b/drizzle-orm/src/pg-core/columns/json.ts @@ -12,6 +12,7 @@ export type PgJsonBuilderInitial = PgJsonBuilder<{ driverParam: unknown; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgJsonBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/jsonb.ts b/drizzle-orm/src/pg-core/columns/jsonb.ts index 3407730db..189771975 100644 --- a/drizzle-orm/src/pg-core/columns/jsonb.ts +++ b/drizzle-orm/src/pg-core/columns/jsonb.ts @@ -12,6 +12,7 @@ export type PgJsonbBuilderInitial = PgJsonbBuilder<{ driverParam: unknown; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgJsonbBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/line.ts b/drizzle-orm/src/pg-core/columns/line.ts index 014140797..3b4d790f5 100644 --- a/drizzle-orm/src/pg-core/columns/line.ts +++ b/drizzle-orm/src/pg-core/columns/line.ts @@ -14,6 +14,7 @@ export type PgLineBuilderInitial = PgLineBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgLineBuilder> extends PgColumnBuilder { @@ -59,6 +60,7 @@ export type PgLineABCBuilderInitial = PgLineABCBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgLineABCBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/macaddr.ts b/drizzle-orm/src/pg-core/columns/macaddr.ts index bfc4511f4..c16bb43cd 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr.ts @@ -12,6 +12,7 @@ export type PgMacaddrBuilderInitial = PgMacaddrBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgMacaddrBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/macaddr8.ts b/drizzle-orm/src/pg-core/columns/macaddr8.ts index 6c4218de0..2445958c4 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr8.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr8.ts @@ -12,6 +12,7 @@ export type PgMacaddr8BuilderInitial = PgMacaddr8Builder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgMacaddr8Builder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/numeric.ts b/drizzle-orm/src/pg-core/columns/numeric.ts index efeb4ab97..1857fa37d 100644 --- a/drizzle-orm/src/pg-core/columns/numeric.ts +++ b/drizzle-orm/src/pg-core/columns/numeric.ts @@ -13,6 +13,7 @@ export type PgNumericBuilderInitial = PgNumericBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgNumericBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/point.ts b/drizzle-orm/src/pg-core/columns/point.ts index 827579ad8..6344bf707 100644 --- a/drizzle-orm/src/pg-core/columns/point.ts +++ b/drizzle-orm/src/pg-core/columns/point.ts @@ -14,6 +14,7 @@ export type PgPointTupleBuilderInitial = PgPointTupleBuild driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgPointTupleBuilder> @@ -64,6 +65,7 @@ export type PgPointObjectBuilderInitial = PgPointObjectBui driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgPointObjectBuilder> diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts index 853c3dff9..455088ec9 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts @@ -15,6 +15,7 @@ export type PgGeometryBuilderInitial = PgGeometryBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgGeometryBuilder> extends PgColumnBuilder { @@ -59,6 +60,7 @@ export type PgGeometryObjectBuilderInitial = PgGeometryObj driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgGeometryObjectBuilder> diff --git a/drizzle-orm/src/pg-core/columns/real.ts b/drizzle-orm/src/pg-core/columns/real.ts index 0e3de4b2e..c8d499fb4 100644 --- a/drizzle-orm/src/pg-core/columns/real.ts +++ b/drizzle-orm/src/pg-core/columns/real.ts @@ -12,6 +12,7 @@ export type PgRealBuilderInitial = PgRealBuilder<{ driverParam: string | number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgRealBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/serial.ts b/drizzle-orm/src/pg-core/columns/serial.ts index 6a0196c38..85b4da797 100644 --- a/drizzle-orm/src/pg-core/columns/serial.ts +++ b/drizzle-orm/src/pg-core/columns/serial.ts @@ -20,6 +20,7 @@ export type PgSerialBuilderInitial = NotNull< driverParam: number; enumValues: undefined; generated: undefined; + identity: undefined; }> > >; diff --git a/drizzle-orm/src/pg-core/columns/smallint.ts b/drizzle-orm/src/pg-core/columns/smallint.ts index 1cdfe141f..d84fa0e55 100644 --- a/drizzle-orm/src/pg-core/columns/smallint.ts +++ b/drizzle-orm/src/pg-core/columns/smallint.ts @@ -13,6 +13,7 @@ export type PgSmallIntBuilderInitial = PgSmallIntBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgSmallIntBuilder> diff --git a/drizzle-orm/src/pg-core/columns/smallserial.ts b/drizzle-orm/src/pg-core/columns/smallserial.ts index 456dc47f7..7ab8408f3 100644 --- a/drizzle-orm/src/pg-core/columns/smallserial.ts +++ b/drizzle-orm/src/pg-core/columns/smallserial.ts @@ -20,6 +20,7 @@ export type PgSmallSerialBuilderInitial = NotNull< driverParam: number; enumValues: undefined; generated: undefined; + identity: undefined; }> > >; diff --git a/drizzle-orm/src/pg-core/columns/text.ts b/drizzle-orm/src/pg-core/columns/text.ts index 6845f0e74..c43888449 100644 --- a/drizzle-orm/src/pg-core/columns/text.ts +++ b/drizzle-orm/src/pg-core/columns/text.ts @@ -13,6 +13,7 @@ type PgTextBuilderInitial; export class PgTextBuilder< diff --git a/drizzle-orm/src/pg-core/columns/time.ts b/drizzle-orm/src/pg-core/columns/time.ts index 9b3ff51e0..8ccafd333 100644 --- a/drizzle-orm/src/pg-core/columns/time.ts +++ b/drizzle-orm/src/pg-core/columns/time.ts @@ -15,6 +15,7 @@ export type PgTimeBuilderInitial = PgTimeBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgTimeBuilder> extends PgDateColumnBaseBuilder< diff --git a/drizzle-orm/src/pg-core/columns/timestamp.ts b/drizzle-orm/src/pg-core/columns/timestamp.ts index 6879106e0..27372df7a 100644 --- a/drizzle-orm/src/pg-core/columns/timestamp.ts +++ b/drizzle-orm/src/pg-core/columns/timestamp.ts @@ -14,6 +14,7 @@ export type PgTimestampBuilderInitial = PgTimestampBuilder driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgTimestampBuilder> @@ -76,6 +77,7 @@ export type PgTimestampStringBuilderInitial = PgTimestampS driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgTimestampStringBuilder> diff --git a/drizzle-orm/src/pg-core/columns/uuid.ts b/drizzle-orm/src/pg-core/columns/uuid.ts index d0e5a6830..bff7f0d7e 100644 --- a/drizzle-orm/src/pg-core/columns/uuid.ts +++ b/drizzle-orm/src/pg-core/columns/uuid.ts @@ -13,6 +13,7 @@ export type PgUUIDBuilderInitial = PgUUIDBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgUUIDBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/varchar.ts b/drizzle-orm/src/pg-core/columns/varchar.ts index 78ee0db96..d9234137b 100644 --- a/drizzle-orm/src/pg-core/columns/varchar.ts +++ b/drizzle-orm/src/pg-core/columns/varchar.ts @@ -13,6 +13,7 @@ export type PgVarcharBuilderInitial; export class PgVarcharBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts index 81eea6b2f..35cc8ccd2 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts @@ -13,6 +13,7 @@ export type PgBinaryVectorBuilderInitial = PgBinaryVectorB driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgBinaryVectorBuilder> diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts index e12d0d22f..65f040c00 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts @@ -13,6 +13,7 @@ export type PgHalfVectorBuilderInitial = PgHalfVectorBuild driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgHalfVectorBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts index 3881b338f..7ff85dd85 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts @@ -13,6 +13,7 @@ export type PgSparseVectorBuilderInitial = PgSparseVectorB driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgSparseVectorBuilder> diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts index eaac075dc..bb63af5ab 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts @@ -13,6 +13,7 @@ export type PgVectorBuilderInitial = PgVectorBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class PgVectorBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index e413a754a..725239cb6 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -51,7 +51,7 @@ export class PgInsertBuilder, 'overridingSystemValue'>{ this.overridingSystemValue_ = true; - return this; + return this as any; } values(value: PgInsertValue): PgInsertBase; diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index 22deb3a84..b0ebd83d0 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -15,6 +15,7 @@ export type SQLiteBigIntBuilderInitial = SQLiteBigIntBuild driverParam: Buffer; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class SQLiteBigIntBuilder> @@ -58,6 +59,7 @@ export type SQLiteBlobJsonBuilderInitial = SQLiteBlobJsonB driverParam: Buffer; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class SQLiteBlobJsonBuilder> @@ -104,6 +106,7 @@ export type SQLiteBlobBufferBuilderInitial = SQLiteBlobBuf driverParam: Buffer; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class SQLiteBlobBufferBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/custom.ts b/drizzle-orm/src/sqlite-core/columns/custom.ts index 6ece801c5..8c0012e28 100644 --- a/drizzle-orm/src/sqlite-core/columns/custom.ts +++ b/drizzle-orm/src/sqlite-core/columns/custom.ts @@ -15,6 +15,7 @@ export type ConvertCustomConfig = SQLiteIntegerBui driverParam: number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class SQLiteIntegerBuilder> @@ -104,6 +105,7 @@ export type SQLiteTimestampBuilderInitial = SQLiteTimestam driverParam: number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class SQLiteTimestampBuilder> @@ -166,6 +168,7 @@ export type SQLiteBooleanBuilderInitial = SQLiteBooleanBui driverParam: number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class SQLiteBooleanBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/numeric.ts b/drizzle-orm/src/sqlite-core/columns/numeric.ts index 93dfc4c3d..13c67f080 100644 --- a/drizzle-orm/src/sqlite-core/columns/numeric.ts +++ b/drizzle-orm/src/sqlite-core/columns/numeric.ts @@ -12,6 +12,7 @@ export type SQLiteNumericBuilderInitial = SQLiteNumericBui driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class SQLiteNumericBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/real.ts b/drizzle-orm/src/sqlite-core/columns/real.ts index cd7cf5d01..208e26045 100644 --- a/drizzle-orm/src/sqlite-core/columns/real.ts +++ b/drizzle-orm/src/sqlite-core/columns/real.ts @@ -12,6 +12,7 @@ export type SQLiteRealBuilderInitial = SQLiteRealBuilder<{ driverParam: number; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class SQLiteRealBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/text.ts b/drizzle-orm/src/sqlite-core/columns/text.ts index 84c71fb20..66db76607 100644 --- a/drizzle-orm/src/sqlite-core/columns/text.ts +++ b/drizzle-orm/src/sqlite-core/columns/text.ts @@ -13,6 +13,7 @@ export type SQLiteTextBuilderInitial; export class SQLiteTextBuilder> extends SQLiteColumnBuilder< @@ -64,6 +65,7 @@ export type SQLiteTextJsonBuilderInitial = SQLiteTextJsonB driverParam: string; enumValues: undefined; generated: undefined; + identity: undefined; }>; export class SQLiteTextJsonBuilder> diff --git a/drizzle-orm/src/table.ts b/drizzle-orm/src/table.ts index 8a3ea30b3..98a904d86 100644 --- a/drizzle-orm/src/table.ts +++ b/drizzle-orm/src/table.ts @@ -159,23 +159,32 @@ export type InferModelFromColumns< TConfig extends { dbColumnNames: boolean, override?: boolean } = { dbColumnNames: false, override: false }, > = Simplify< TInferMode extends 'insert' ? - & { - [ - Key in keyof TColumns & string as RequiredKeyOnly< - MapColumnName, - TColumns[Key] - > - ]: GetColumnData; - } - & { - [ - Key in keyof TColumns & string as OptionalKeyOnly< - MapColumnName, - TColumns[Key], - TConfig['override'] - > - ]?: GetColumnData; - } + & { + [ + Key in keyof TColumns & string as RequiredKeyOnly< + MapColumnName, + TColumns[Key] + > + ]: GetColumnData; + } + & { + [ + Key in keyof TColumns & string as OptionalKeyOnly< + MapColumnName, + TColumns[Key], + TConfig['override'] + > + ]?: GetColumnData; + } + // & { + // [ + // Key in keyof TColumns & string as IdentityColumns< + // MapColumnName, + // TColumns[Key], + // TConfig['override'] + // > + // ]?: GetColumnData; + // } : { [ Key in keyof TColumns & string as MapColumnName< diff --git a/drizzle-orm/type-tests/pg/array.ts b/drizzle-orm/type-tests/pg/array.ts index 3961e92d0..586acb1c7 100644 --- a/drizzle-orm/type-tests/pg/array.ts +++ b/drizzle-orm/type-tests/pg/array.ts @@ -21,6 +21,7 @@ import { integer, pgTable } from '~/pg-core/index.ts'; enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; diff --git a/drizzle-orm/type-tests/pg/insert.ts b/drizzle-orm/type-tests/pg/insert.ts index 6a5179804..c11ea8740 100644 --- a/drizzle-orm/type-tests/pg/insert.ts +++ b/drizzle-orm/type-tests/pg/insert.ts @@ -4,7 +4,7 @@ import { Expect } from 'type-tests/utils.ts'; import type { PgInsert } from '~/pg-core/query-builders/insert.ts'; import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; -import { users } from './tables.ts'; +import { users, identityColumnsTable } from './tables.ts'; const insert = await db .insert(users) @@ -204,3 +204,9 @@ Expect< // @ts-expect-error method was already called .returning(); } + +db.insert(identityColumnsTable).overridingSystemValue().values([ + { alwaysAsIdentity: 3, name: "aa"}, + // { byDefaultAsIdentity: 5, name: "ff"}, + // { alwaysAsIdentity: 4, byDefaultAsIdentity: 6, name: "sd"}, +]); \ No newline at end of file diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index 0b139dc3a..ef2c9edf4 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -59,6 +59,14 @@ import { db } from './db.ts'; export const myEnum = pgEnum('my_enum', ['a', 'b', 'c']); +export const identityColumnsTable = pgTable('identity_columns_table', { + // generatedCol: integer('g').generatedAlwaysAs(1), + alwaysAsIdentity: integer("always_as_identity").generatedByDefaultAsIdentity(), + // byDefaultAsIdentity: integer('by_default_as_identity').generatedByDefaultAsIdentity(), + // name: text('name') +}); + +identityColumnsTable.$inferInsert export const users = pgTable( 'users_table', { @@ -207,6 +215,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -223,6 +232,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -266,6 +276,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -282,6 +293,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -323,6 +335,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -339,6 +352,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -380,6 +394,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -396,6 +411,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -427,6 +443,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -443,6 +460,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -474,6 +492,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -490,6 +509,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -536,6 +556,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -552,6 +573,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -598,6 +620,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -614,6 +637,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -658,6 +682,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -674,6 +699,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -718,6 +744,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -734,6 +761,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -765,6 +793,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -781,6 +810,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -812,6 +842,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -828,6 +859,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -943,6 +975,7 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -959,6 +992,7 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); notNull: true; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -975,6 +1009,7 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); notNull: true; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -991,6 +1026,7 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; From 746e091f2421cfb94fd23409d044369945dc804b Mon Sep 17 00:00:00 2001 From: prodrigues Date: Tue, 12 Nov 2024 22:28:17 +0000 Subject: [PATCH 339/492] fix changelog files --- changelogs/drizzle-kit/0.27.2.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/changelogs/drizzle-kit/0.27.2.md b/changelogs/drizzle-kit/0.27.2.md index b003379b9..bafd17222 100644 --- a/changelogs/drizzle-kit/0.27.2.md +++ b/changelogs/drizzle-kit/0.27.2.md @@ -1,3 +1,3 @@ -Fix [BUG]: Undefined properties when using drizzle-kit push -Fix TypeError: Cannot read properties of undefined (reading 'isRLSEnabled') -Fix push bugs, when pushing a schema with linked policy to a table from drizzle-orm/supabase +- Fix [[BUG]: Undefined properties when using drizzle-kit push](https://github.com/drizzle-team/drizzle-orm/issues/3391) +- Fix TypeError: Cannot read properties of undefined (reading 'isRLSEnabled') +- Fix push bugs, when pushing a schema with linked policy to a table from `drizzle-orm/supabase` From 9a68340a2edc0cf56c963006cdbf88aa5afc27c4 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Tue, 12 Nov 2024 22:53:14 +0000 Subject: [PATCH 340/492] fix drizzle-kit non singlestore files --- drizzle-kit/src/cli/commands/pgIntrospect.ts | 5 +- drizzle-kit/src/cli/commands/pgPushUtils.ts | 2 +- drizzle-kit/src/introspect-mysql.ts | 13 +- drizzle-kit/src/introspect-pg.ts | 42 +- drizzle-kit/src/introspect-sqlite.ts | 4 +- drizzle-kit/src/serializer/mysqlSerializer.ts | 24 +- drizzle-kit/src/serializer/pgSchema.ts | 17 +- drizzle-kit/src/serializer/pgSerializer.ts | 35 +- .../src/serializer/sqliteSerializer.ts | 4 +- drizzle-kit/src/sqlgenerator.ts | 11 - drizzle-kit/src/utils.ts | 11 + drizzle-kit/tests/indexes/pg.test.ts | 4 +- drizzle-kit/tests/introspect/mysql.test.ts | 23 + drizzle-kit/tests/introspect/pg.test.ts | 27 ++ drizzle-kit/tests/introspect/sqlite.test.ts | 19 + drizzle-kit/tests/mysql.test.ts | 102 +++++ drizzle-kit/tests/pg-columns.test.ts | 28 +- drizzle-kit/tests/pg-enums.test.ts | 73 +++- drizzle-kit/tests/pg-tables.test.ts | 100 +++++ drizzle-kit/tests/push/common.ts | 5 + drizzle-kit/tests/push/mysql.test.ts | 85 +++- drizzle-kit/tests/push/pg.test.ts | 404 ++++++++++++++++-- drizzle-kit/tests/sqlite-columns.test.ts | 22 + drizzle-kit/tests/sqlite-tables.test.ts | 44 ++ 24 files changed, 1013 insertions(+), 91 deletions(-) diff --git a/drizzle-kit/src/cli/commands/pgIntrospect.ts b/drizzle-kit/src/cli/commands/pgIntrospect.ts index 2d3fd75ce..02867fae9 100644 --- a/drizzle-kit/src/cli/commands/pgIntrospect.ts +++ b/drizzle-kit/src/cli/commands/pgIntrospect.ts @@ -1,7 +1,7 @@ import { renderWithTask } from 'hanji'; import { Minimatch } from 'minimatch'; import { originUUID } from '../../global'; -import type { PgSchema } from '../../serializer/pgSchema'; +import type { PgSchema, PgSchemaInternal } from '../../serializer/pgSchema'; import { fromDatabase } from '../../serializer/pgSerializer'; import type { DB } from '../../utils'; import { Entities } from '../validations/cli'; @@ -12,6 +12,7 @@ export const pgPushIntrospect = async ( filters: string[], schemaFilters: string[], entities: Entities, + tsSchema?: PgSchemaInternal, ) => { const matchers = filters.map((it) => { return new Minimatch(it); @@ -45,7 +46,7 @@ export const pgPushIntrospect = async ( ); const res = await renderWithTask( progress, - fromDatabase(db, filter, schemaFilters, entities), + fromDatabase(db, filter, schemaFilters, entities, undefined, tsSchema), ); const schema = { id: originUUID, prevId: '', ...res } as PgSchema; diff --git a/drizzle-kit/src/cli/commands/pgPushUtils.ts b/drizzle-kit/src/cli/commands/pgPushUtils.ts index b53fec3e7..05322f738 100644 --- a/drizzle-kit/src/cli/commands/pgPushUtils.ts +++ b/drizzle-kit/src/cli/commands/pgPushUtils.ts @@ -250,7 +250,7 @@ export const pgSuggestions = async (db: DB, statements: JsonStatement[]) => { } } } - const stmnt = fromJson([statement], 'postgresql'); + const stmnt = fromJson([statement], 'postgresql', 'push'); if (typeof stmnt !== 'undefined') { statementsToExecute.push(...stmnt); } diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index c15fea937..ebf30f70d 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -14,6 +14,7 @@ import { UniqueConstraint, } from './serializer/mysqlSchema'; import { indexName } from './serializer/mysqlSerializer'; +import { unescapeSingleQuotes } from './utils'; // time precision to fsp // {mode: "string"} for timestamp by default @@ -679,8 +680,9 @@ const column = ( ) } })`; + const mappedDefaultValue = mapColumnDefault(defaultValue, isExpression); out += defaultValue - ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + ? `.default(${isExpression ? mappedDefaultValue : unescapeSingleQuotes(mappedDefaultValue, true)})` : ''; return out; } @@ -787,10 +789,15 @@ const column = ( } if (lowered.startsWith('enum')) { - const values = lowered.substring('enum'.length + 1, lowered.length - 1); + const values = lowered + .substring('enum'.length + 1, lowered.length - 1) + .split(',') + .map((v) => unescapeSingleQuotes(v, true)) + .join(','); let out = `${casing(name)}: mysqlEnum(${dbColumnName({ name, casing: rawCasing, withMode: true })}[${values}])`; + const mappedDefaultValue = mapColumnDefault(defaultValue, isExpression); out += defaultValue - ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + ? `.default(${isExpression ? mappedDefaultValue : unescapeSingleQuotes(mappedDefaultValue, true)})` : ''; return out; } diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index ed26e8117..9c9383ebe 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -11,7 +11,6 @@ import { import './@types/utils'; import { toCamelCase } from 'drizzle-orm/casing'; import { Casing } from './cli/validations/common'; -import { vectorOps } from './extensions/vector'; import { assertUnreachable } from './global'; import { CheckConstraint, @@ -25,6 +24,7 @@ import { UniqueConstraint, } from './serializer/pgSchema'; import { indexName } from './serializer/pgSerializer'; +import { unescapeSingleQuotes } from './utils'; const pgImportsList = new Set([ 'pgTable', @@ -436,7 +436,7 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => const func = enumSchema ? `${enumSchema}.enum` : 'pgEnum'; const values = Object.values(it.values) - .map((it) => `'${it}'`) + .map((it) => `'${unescapeSingleQuotes(it, false)}'`) .join(', '); return `export const ${withCasing(paramName, casing)} = ${func}("${it.name}", [${values}])\n`; }) @@ -690,7 +690,9 @@ const mapDefault = ( } if (enumTypes.has(`${typeSchema}.${type.replace('[]', '')}`)) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('integer')) { @@ -737,18 +739,20 @@ const mapDefault = ( if (lowered.startsWith('timestamp')) { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue === 'CURRENT_TIMESTAMP' - ? '.default(sql`CURRENT_TIMESTAMP`)' - : defaultValue + : /^'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}(:\d{2})?)?'$/.test(defaultValue) // Matches 'YYYY-MM-DD HH:MI:SS', 'YYYY-MM-DD HH:MI:SS.FFFFFF', 'YYYY-MM-DD HH:MI:SS+TZ', 'YYYY-MM-DD HH:MI:SS.FFFFFF+TZ' and 'YYYY-MM-DD HH:MI:SS+HH:MI' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } if (lowered.startsWith('time')) { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue + : /^'\d{2}:\d{2}(:\d{2})?(\.\d+)?'$/.test(defaultValue) // Matches 'HH:MI', 'HH:MI:SS' and 'HH:MI:SS.FFFFFF' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } @@ -759,15 +763,17 @@ const mapDefault = ( if (lowered === 'date') { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue === 'CURRENT_DATE' - ? `.default(sql\`${defaultValue}\`)` - : defaultValue + : /^'\d{4}-\d{2}-\d{2}'$/.test(defaultValue) // Matches 'YYYY-MM-DD' ? `.default(${defaultValue})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } if (lowered.startsWith('text')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('jsonb')) { @@ -801,7 +807,9 @@ const mapDefault = ( } if (lowered.startsWith('varchar')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('point')) { @@ -821,7 +829,9 @@ const mapDefault = ( } if (lowered.startsWith('char')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } return ''; @@ -1219,7 +1229,11 @@ const createTableIndexes = (tableName: string, idxs: Index[], casing: Casing): s } else { return `table.${withCasing(it.expression, casing)}${it.asc ? '.asc()' : '.desc()'}${ it.nulls === 'first' ? '.nullsFirst()' : '.nullsLast()' - }${it.opclass && vectorOps.includes(it.opclass) ? `.op("${it.opclass}")` : ''}`; + }${ + it.opclass + ? `.op("${it.opclass}")` + : '' + }`; } }) .join(', ') diff --git a/drizzle-kit/src/introspect-sqlite.ts b/drizzle-kit/src/introspect-sqlite.ts index e21f2a5c4..464a32aa3 100644 --- a/drizzle-kit/src/introspect-sqlite.ts +++ b/drizzle-kit/src/introspect-sqlite.ts @@ -272,10 +272,8 @@ const mapColumnDefault = (defaultValue: any) => { if ( typeof defaultValue === 'string' - && defaultValue.startsWith("'") - && defaultValue.endsWith("'") ) { - return defaultValue.substring(1, defaultValue.length - 1); + return defaultValue.substring(1, defaultValue.length - 1).replaceAll('"', '\\"').replaceAll("''", "'"); } return defaultValue; diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index 25ca1d596..aaa1acb82 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -26,13 +26,20 @@ import { UniqueConstraint, View, } from '../serializer/mysqlSchema'; -import type { DB } from '../utils'; +import { type DB, escapeSingleQuotes } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; }; +const handleEnumType = (type: string) => { + let str = type.split('(')[1]; + str = str.substring(0, str.length - 1); + const values = str.split(',').map((v) => `'${escapeSingleQuotes(v.substring(1, v.length - 1))}'`); + return `enum(${values.join(',')})`; +}; + export const generateMySqlSnapshot = ( tables: AnyMySqlTable[], views: MySqlView[], @@ -68,7 +75,8 @@ export const generateMySqlSnapshot = ( columns.forEach((column) => { const name = getColumnCasing(column, casing); const notNull: boolean = column.notNull; - const sqlTypeLowered = column.getSQLType().toLowerCase(); + const sqlType = column.getSQLType(); + const sqlTypeLowered = sqlType.toLowerCase(); const autoIncrement = typeof (column as any).autoIncrement === 'undefined' ? false : (column as any).autoIncrement; @@ -77,7 +85,7 @@ export const generateMySqlSnapshot = ( const columnToSet: Column = { name, - type: column.getSQLType(), + type: sqlType.startsWith('enum') ? handleEnumType(sqlType) : sqlType, primaryKey: false, // If field is autoincrement it's notNull by default // notNull: autoIncrement ? true : notNull, @@ -141,7 +149,7 @@ export const generateMySqlSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { if (typeof column.default === 'string') { - columnToSet.default = `'${column.default}'`; + columnToSet.default = `'${escapeSingleQuotes(column.default)}'`; } else { if (sqlTypeLowered === 'json') { columnToSet.default = `'${JSON.stringify(column.default)}'`; @@ -544,9 +552,9 @@ function clearDefaults(defaultValue: any, collate: string) { .substring(collate.length, defaultValue.length) .replace(/\\/g, ''); if (resultDefault.startsWith("'") && resultDefault.endsWith("'")) { - return `('${resultDefault.substring(1, resultDefault.length - 1)}')`; + return `('${escapeSingleQuotes(resultDefault.substring(1, resultDefault.length - 1))}')`; } else { - return `'${resultDefault}'`; + return `'${escapeSingleQuotes(resultDefault.substring(1, resultDefault.length - 1))}'`; } } else { return `(${resultDefault})`; @@ -665,14 +673,14 @@ export const fromDatabase = async ( } const newColumn: Column = { - default: columnDefault === null + default: columnDefault === null || columnDefault === undefined ? undefined : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) && !['decimal', 'char', 'varchar'].some((type) => columnType.startsWith(type)) ? Number(columnDefault) : isDefaultAnExpression ? clearDefaults(columnDefault, collation) - : `'${columnDefault}'`, + : `'${escapeSingleQuotes(columnDefault)}'`, autoincrement: isAutoincrement, name: columnName, type: changedType, diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index 50d712dc4..d7604d645 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -1,4 +1,3 @@ -import { vectorOps } from 'src/extensions/vector'; import { mapValues, originUUID, snapshotVersion } from '../global'; import { any, array, boolean, enum as enumType, literal, number, object, record, string, TypeOf, union } from 'zod'; @@ -240,6 +239,7 @@ export const policy = object({ using: string().optional(), withCheck: string().optional(), on: string().optional(), + schema: string().optional(), }).strict(); export const policySquashed = object({ @@ -554,10 +554,7 @@ export const PgSquasher = { return `${idx.name};${ idx.columns .map( - (c) => - `${c.expression}--${c.isExpression}--${c.asc}--${c.nulls}--${ - c.opclass && vectorOps.includes(c.opclass) ? c.opclass : '' - }`, + (c) => `${c.expression}--${c.isExpression}--${c.asc}--${c.nulls}--${c.opclass ? c.opclass : ''}`, ) .join(',,') };${idx.isUnique};${idx.concurrently};${idx.method};${idx.where};${JSON.stringify(idx.with)}`; @@ -657,6 +654,16 @@ export const PgSquasher = { squashPolicyPush: (policy: Policy) => { return `${policy.name}--${policy.as}--${policy.for}--${policy.to?.join(',')}--${policy.on}`; }, + unsquashPolicyPush: (policy: string): Policy => { + const splitted = policy.split('--'); + return { + name: splitted[0], + as: splitted[1] as Policy['as'], + for: splitted[2] as Policy['for'], + to: splitted[3].split(','), + on: splitted[4] !== 'undefined' ? splitted[4] : undefined, + }; + }, squashPK: (pk: PrimaryKey) => { return `${pk.columns.join(',')};${pk.name}`; }, diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index c6f6c0391..b0faa5ea8 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -39,7 +39,7 @@ import type { UniqueConstraint, View, } from '../serializer/pgSchema'; -import { type DB, isPgArrayType } from '../utils'; +import { type DB, escapeSingleQuotes, isPgArrayType } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const indexName = (tableName: string, columns: string[]) => { @@ -241,7 +241,7 @@ export const generatePgSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { if (typeof column.default === 'string') { - columnToSet.default = `'${column.default}'`; + columnToSet.default = `'${escapeSingleQuotes(column.default)}'`; } else { if (sqlTypeLowered === 'jsonb' || sqlTypeLowered === 'json') { columnToSet.default = `'${JSON.stringify(column.default)}'::${sqlTypeLowered}`; @@ -652,6 +652,7 @@ export const generatePgSnapshot = ( } else { policiesToReturn[policy.name] = { ...mappedPolicy, + schema: tableConfig.schema ?? 'public', on: `"${tableConfig.schema ?? 'public'}"."${tableConfig.name}"`, }; } @@ -972,9 +973,11 @@ export const fromDatabase = async ( count: number, status: IntrospectStatus, ) => void, + tsSchema?: PgSchemaInternal, ): Promise => { const result: Record = {}; const views: Record = {}; + const policies: Record = {}; const internals: PgKitInternals = { tables: {} }; const where = schemaFilters.map((t) => `n.nspname = '${t}'`).join(' or '); @@ -1134,7 +1137,9 @@ WHERE } } - const wherePolicies = schemaFilters + const schemasForLinkedPoliciesInSchema = Object.values(tsSchema?.policies ?? {}).map((it) => it.schema!); + + const wherePolicies = [...schemaFilters, ...schemasForLinkedPoliciesInSchema] .map((t) => `schemaname = '${t}'`) .join(' or '); @@ -1171,6 +1176,16 @@ WHERE [dbPolicy.name]: { ...rest, to: parsedTo, withCheck: parsedWithCheck, using: parsedUsing } as Policy, }; } + + if (tsSchema?.policies[dbPolicy.name]) { + policies[dbPolicy.name] = { + ...rest, + to: parsedTo, + withCheck: parsedWithCheck, + using: parsedUsing, + on: tsSchema?.policies[dbPolicy.name].on, + } as Policy; + } } if (progressCallback) { @@ -1907,7 +1922,7 @@ WHERE schemas: schemasObject, sequences: sequencesToReturn, roles: rolesToReturn, - policies: {}, + policies, views: views, _meta: { schemas: {}, @@ -1922,11 +1937,13 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str const columnName = column.column_name; const isArray = internals?.tables[tableName]?.columns[columnName]?.isArray ?? false; - if (column.column_default === null) { - return undefined; - } - - if (column.data_type === 'serial' || column.data_type === 'smallserial' || column.data_type === 'bigserial') { + if ( + column.column_default === null + || column.column_default === undefined + || column.data_type === 'serial' + || column.data_type === 'smallserial' + || column.data_type === 'bigserial' + ) { return undefined; } diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 1ba24b69c..107a1b292 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -25,7 +25,7 @@ import type { UniqueConstraint, View, } from '../serializer/sqliteSchema'; -import type { SQLiteDB } from '../utils'; +import { escapeSingleQuotes, type SQLiteDB } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const generateSqliteSnapshot = ( @@ -90,7 +90,7 @@ export const generateSqliteSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { columnToSet.default = typeof column.default === 'string' - ? `'${column.default}'` + ? `'${escapeSingleQuotes(column.default)}'` : typeof column.default === 'object' || Array.isArray(column.default) ? `'${JSON.stringify(column.default)}'` diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 9d1479653..81f04f10e 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -4041,17 +4041,6 @@ convertors.push(new SingleStoreAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new SingleStoreAlterTableAddPk()); convertors.push(new SingleStoreAlterTableAlterCompositePrimaryKeyConvertor()); -export function fromJson( - statements: JsonStatement[], - dialect: Exclude, -): string[]; -export function fromJson( - statements: JsonStatement[], - dialect: 'sqlite' | 'turso', - action?: 'push', - json2?: SQLiteSchemaSquashed, -): string[]; - export function fromJson( statements: JsonStatement[], dialect: Dialect, diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 71454550e..559153c38 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -1,9 +1,11 @@ + import type { RunResult } from 'better-sqlite3'; import chalk from 'chalk'; import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs'; import { join } from 'path'; import { parse } from 'url'; import type { NamedWithSchema } from './cli/commands/migrate'; +import { CasingType } from './cli/validations/common'; import { info } from './cli/views'; import { assertUnreachable, snapshotVersion } from './global'; import type { Dialect } from './schemaValidator'; @@ -359,3 +361,12 @@ export function findAddedAndRemoved(columnNames1: string[], columnNames2: string return { addedColumns, removedColumns }; } + +export function escapeSingleQuotes(str: string) { + return str.replace(/'/g, "''"); +} + +export function unescapeSingleQuotes(str: string, ignoreFirstAndLastChar: boolean) { + const regex = ignoreFirstAndLastChar ? /(? { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('instrospect strings with single quotes', async () => { + const schema = { + columns: mysqlTable('columns', { + enum: mysqlEnum('my_enum', ['escape\'s quotes "', 'escape\'s quotes 2 "']).default('escape\'s quotes "'), + text: text('text').default('escape\'s quotes " '), + varchar: varchar('varchar', { length: 255 }).default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'introspect-strings-with-single-quotes', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`drop table columns;`); +}); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index 6762ef27a..1d9f0f18c 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -255,8 +255,12 @@ test('instrospect all column types', async () => { time2: time('time2').defaultNow(), timestamp1: timestamp('timestamp1', { withTimezone: true, precision: 6 }).default(new Date()), timestamp2: timestamp('timestamp2', { withTimezone: true, precision: 6 }).defaultNow(), + timestamp3: timestamp('timestamp3', { withTimezone: true, precision: 6 }).default( + sql`timezone('utc'::text, now())`, + ), date1: date('date1').default('2024-01-01'), date2: date('date2').defaultNow(), + date3: date('date3').default(sql`CURRENT_TIMESTAMP`), uuid1: uuid('uuid1').default('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'), uuid2: uuid('uuid2').defaultRandom(), inet: inet('inet').default('127.0.0.1'), @@ -418,6 +422,29 @@ test('introspect enum with similar name to native type', async () => { expect(sqlStatements.length).toBe(0); }); +test('instrospect strings with single quotes', async () => { + const client = new PGlite(); + + const myEnum = pgEnum('my_enum', ['escape\'s quotes " ']); + const schema = { + enum_: myEnum, + columns: pgTable('columns', { + enum: myEnum('my_enum').default('escape\'s quotes " '), + text: text('text').default('escape\'s quotes " '), + varchar: varchar('varchar').default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-strings-with-single-quotes', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + test('introspect checks', async () => { const client = new PGlite(); diff --git a/drizzle-kit/tests/introspect/sqlite.test.ts b/drizzle-kit/tests/introspect/sqlite.test.ts index 89cdf590e..de13d4e81 100644 --- a/drizzle-kit/tests/introspect/sqlite.test.ts +++ b/drizzle-kit/tests/introspect/sqlite.test.ts @@ -56,6 +56,25 @@ test('generated always column virtual: link to another column', async () => { expect(sqlStatements.length).toBe(0); }); +test('instrospect strings with single quotes', async () => { + const sqlite = new Database(':memory:'); + + const schema = { + columns: sqliteTable('columns', { + text: text('text').default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectSQLiteToFile( + sqlite, + schema, + 'introspect-strings-with-single-quotes', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + test('introspect checks', async () => { const sqlite = new Database(':memory:'); diff --git a/drizzle-kit/tests/mysql.test.ts b/drizzle-kit/tests/mysql.test.ts index 183464ec0..881b05ef7 100644 --- a/drizzle-kit/tests/mysql.test.ts +++ b/drizzle-kit/tests/mysql.test.ts @@ -4,6 +4,7 @@ import { index, int, json, + mysqlEnum, mysqlSchema, mysqlTable, primaryKey, @@ -11,6 +12,7 @@ import { text, unique, uniqueIndex, + varchar, } from 'drizzle-orm/mysql-core'; import { expect, test } from 'vitest'; import { diffTestSchemasMysql } from './schemaDiffer'; @@ -533,6 +535,32 @@ test('drop index', async () => { expect(sqlStatements[0]).toBe('DROP INDEX `name_idx` ON `table`;'); }); +test('drop unique constraint', async () => { + const from = { + users: mysqlTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + uq: unique('name_uq').on(t.name), + }; + }, + ), + }; + + const to = { + users: mysqlTable('table', { + name: text('name'), + }), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe('ALTER TABLE `table` DROP INDEX `name_uq`;'); +}); + test('add table with indexes', async () => { const from = {}; @@ -578,6 +606,80 @@ test('add table with indexes', async () => { ]); }); +test('varchar and text default values escape single quotes', async (t) => { + const schema1 = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const schem2 = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + enum: mysqlEnum('enum', ["escape's quotes", "escape's quotes 2"]).default("escape's quotes"), + text: text('text').default("escape's quotes"), + varchar: varchar('varchar', { length: 255 }).default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemasMysql(schema1, schem2, []); + + expect(sqlStatements.length).toBe(3); + expect(sqlStatements[0]).toStrictEqual( + "ALTER TABLE `table` ADD `enum` enum('escape''s quotes','escape''s quotes 2') DEFAULT 'escape''s quotes';", + ); + expect(sqlStatements[1]).toStrictEqual( + "ALTER TABLE `table` ADD `text` text DEFAULT ('escape''s quotes');", + ); + expect(sqlStatements[2]).toStrictEqual( + "ALTER TABLE `table` ADD `varchar` varchar(255) DEFAULT 'escape''s quotes';", + ); +}); + +test('composite primary key', async () => { + const from = {}; + const to = { + table: mysqlTable('works_to_creators', { + workId: int('work_id').notNull(), + creatorId: int('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `works_to_creators` (\n\t`work_id` int NOT NULL,\n\t`creator_id` int NOT NULL,\n\t`classification` text NOT NULL,\n\tCONSTRAINT `works_to_creators_work_id_creator_id_classification_pk` PRIMARY KEY(`work_id`,`creator_id`,`classification`)\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + }), + }; + const to = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `table` ADD `name` text NOT NULL;', + 'ALTER TABLE `table` ADD CONSTRAINT `uq` UNIQUE(`name`);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; diff --git a/drizzle-kit/tests/pg-columns.test.ts b/drizzle-kit/tests/pg-columns.test.ts index cffeed3ed..ddd744a81 100644 --- a/drizzle-kit/tests/pg-columns.test.ts +++ b/drizzle-kit/tests/pg-columns.test.ts @@ -1,4 +1,4 @@ -import { integer, pgTable, primaryKey, serial, text, uuid } from 'drizzle-orm/pg-core'; +import { integer, pgTable, primaryKey, serial, text, uuid, varchar } from 'drizzle-orm/pg-core'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; @@ -456,3 +456,29 @@ test('add multiple constraints #3', async (t) => { expect(statements.length).toBe(6); }); + +test('varchar and text default values escape single quotes', async (t) => { + const schema1 = { + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const schem2 = { + table: pgTable('table', { + id: serial('id').primaryKey(), + text: text('text').default("escape's quotes"), + varchar: varchar('varchar').default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemas(schema1, schem2, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toStrictEqual( + 'ALTER TABLE "table" ADD COLUMN "text" text DEFAULT \'escape\'\'s quotes\';', + ); + expect(sqlStatements[1]).toStrictEqual( + 'ALTER TABLE "table" ADD COLUMN "varchar" varchar DEFAULT \'escape\'\'s quotes\';', + ); +}); diff --git a/drizzle-kit/tests/pg-enums.test.ts b/drizzle-kit/tests/pg-enums.test.ts index 99a3dca7e..2af691d46 100644 --- a/drizzle-kit/tests/pg-enums.test.ts +++ b/drizzle-kit/tests/pg-enums.test.ts @@ -1,4 +1,4 @@ -import { pgEnum, pgSchema, pgTable } from 'drizzle-orm/pg-core'; +import { integer, pgEnum, pgSchema, pgTable, serial } from 'drizzle-orm/pg-core'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; @@ -506,6 +506,77 @@ test('enums #18', async () => { }); }); +test('enums #19', async () => { + const myEnum = pgEnum('my_enum', ["escape's quotes"]); + + const from = {}; + + const to = { myEnum }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toStrictEqual( + 'CREATE TYPE "public"."my_enum" AS ENUM(\'escape\'\'s quotes\');', + ); +}); + +test('enums #20', async () => { + const myEnum = pgEnum('my_enum', ['one', 'two', 'three']); + + const from = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const to = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + col1: myEnum('col1'), + col2: integer('col2'), + }), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "col1" "my_enum";', + 'ALTER TABLE "table" ADD COLUMN "col2" integer;', + ]); +}); + +test('enums #21', async () => { + const myEnum = pgEnum('my_enum', ['one', 'two', 'three']); + + const from = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const to = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + col1: myEnum('col1').array(), + col2: integer('col2').array(), + }), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "col1" "my_enum"[];', + 'ALTER TABLE "table" ADD COLUMN "col2" integer[];', + ]); +}); + test('drop enum value', async () => { const enum1 = pgEnum('enum', ['value1', 'value2', 'value3']); diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index 1f2885f92..6ea6e472a 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -676,6 +676,106 @@ test('create table with tsvector', async () => { ]); }); +test('composite primary key', async () => { + const from = {}; + const to = { + table: pgTable('works_to_creators', { + workId: integer('work_id').notNull(), + creatorId: integer('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "works_to_creators" (\n\t"work_id" integer NOT NULL,\n\t"creator_id" integer NOT NULL,\n\t"classification" text NOT NULL,\n\tCONSTRAINT "works_to_creators_work_id_creator_id_classification_pk" PRIMARY KEY("work_id","creator_id","classification")\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + const to = { + table: pgTable('table', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "name" text NOT NULL;', + 'ALTER TABLE "table" ADD CONSTRAINT "uq" UNIQUE("name");', + ]); +}); + +test('alter composite primary key', async () => { + const from = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + col3: text('col3').notNull(), + }, (t) => ({ + pk: primaryKey({ + name: 'table_pk', + columns: [t.col1, t.col2], + }), + })), + }; + const to = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + col3: text('col3').notNull(), + }, (t) => ({ + pk: primaryKey({ + name: 'table_pk', + columns: [t.col2, t.col3], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" DROP CONSTRAINT "table_pk";\n--> statement-breakpoint\nALTER TABLE "table" ADD CONSTRAINT "table_pk" PRIMARY KEY("col2","col3");', + ]); +}); + +test('add index with op', async () => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }), + }; + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + nameIdx: index().using('gin', t.name.op('gin_trgm_ops')), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE INDEX IF NOT EXISTS "users_name_index" ON "users" USING gin ("name" gin_trgm_ops);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; diff --git a/drizzle-kit/tests/push/common.ts b/drizzle-kit/tests/push/common.ts index e5c68625d..627070f11 100644 --- a/drizzle-kit/tests/push/common.ts +++ b/drizzle-kit/tests/push/common.ts @@ -15,6 +15,8 @@ export interface DialectSuite { dropGeneratedConstraint(context?: any): Promise; alterGeneratedConstraint(context?: any): Promise; createTableWithGeneratedConstraint(context?: any): Promise; + createCompositePrimaryKey(context?: any): Promise; + renameTableWithCompositePrimaryKey(context?: any): Promise; case1(): Promise; } @@ -48,6 +50,9 @@ export const run = ( // should ignore on push test('Alter generated constraint', () => suite.alterGeneratedConstraint(context)); test('Create table with generated column', () => suite.createTableWithGeneratedConstraint(context)); + test('Rename table with composite primary key', () => suite.renameTableWithCompositePrimaryKey(context)); + + test('Create composite primary key', () => suite.createCompositePrimaryKey(context)); afterAll(afterAllFn ? () => afterAllFn(context) : () => {}); }; diff --git a/drizzle-kit/tests/push/mysql.test.ts b/drizzle-kit/tests/push/mysql.test.ts index 7b20dc444..6c7f5efc2 100644 --- a/drizzle-kit/tests/push/mysql.test.ts +++ b/drizzle-kit/tests/push/mysql.test.ts @@ -15,6 +15,7 @@ import { mediumint, mysqlEnum, mysqlTable, + primaryKey, serial, smallint, text, @@ -29,7 +30,7 @@ import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; import { diffTestSchemasMysql, diffTestSchemasPushMysql } from 'tests/schemaDiffer'; import { v4 as uuid } from 'uuid'; -import { expect } from 'vitest'; +import { expect, test } from 'vitest'; import { DialectSuite, run } from './common'; async function createDockerDB(context: any): Promise { @@ -663,6 +664,88 @@ const mysqlSuite: DialectSuite = { createTableWithGeneratedConstraint: function(context?: any): Promise { return {} as any; }, + createCompositePrimaryKey: async function(context: any): Promise { + const schema1 = {}; + + const schema2 = { + table: mysqlTable('table', { + col1: int('col1').notNull(), + col2: int('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table', + schema: undefined, + internals: { + indexes: {}, + tables: {}, + }, + compositePKs: ['table_col1_col2_pk;col1,col2'], + compositePkName: 'table_col1_col2_pk', + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + { name: 'col2', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + ], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `table` (\n\t`col1` int NOT NULL,\n\t`col2` int NOT NULL,\n\tCONSTRAINT `table_col1_col2_pk` PRIMARY KEY(`col1`,`col2`)\n);\n', + ]); + }, + renameTableWithCompositePrimaryKey: async function(context?: any): Promise { + const productsCategoriesTable = (tableName: string) => { + return mysqlTable(tableName, { + productId: varchar('product_id', { length: 10 }).notNull(), + categoryId: varchar('category_id', { length: 10 }).notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPushMysql( + context.client as Connection, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + 'drizzle', + false, + ); + + expect(sqlStatements).toStrictEqual([ + 'RENAME TABLE `products_categories` TO `products_to_categories`;', + 'ALTER TABLE `products_to_categories` DROP PRIMARY KEY;', + 'ALTER TABLE `products_to_categories` ADD PRIMARY KEY(`product_id`,`category_id`);', + ]); + + await context.client.query(`DROP TABLE \`products_categories\``); + }, }; run( diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 67743d2ef..44ec786b6 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -22,6 +22,7 @@ import { pgSequence, pgTable, pgView, + primaryKey, real, serial, smallint, @@ -914,6 +915,89 @@ const pgSuite: DialectSuite = { expect(shouldAskForApprove).toBeFalsy(); }, + async createCompositePrimaryKey() { + const client = new PGlite(); + + const schema1 = {}; + + const schema2 = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table', + schema: '', + compositePKs: ['col1,col2;table_col1_col2_pk'], + compositePkName: 'table_col1_col2_pk', + isRLSEnabled: false, + policies: [], + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'integer', primaryKey: false, notNull: true }, + { name: 'col2', type: 'integer', primaryKey: false, notNull: true }, + ], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "table" (\n\t"col1" integer NOT NULL,\n\t"col2" integer NOT NULL,\n\tCONSTRAINT "table_col1_col2_pk" PRIMARY KEY("col1","col2")\n);\n', + ]); + }, + + async renameTableWithCompositePrimaryKey() { + const client = new PGlite(); + + const productsCategoriesTable = (tableName: string) => { + return pgTable(tableName, { + productId: text('product_id').notNull(), + categoryId: text('category_id').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + false, + ['public'], + ); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "products_categories" RENAME TO "products_to_categories";', + 'ALTER TABLE "products_to_categories" DROP CONSTRAINT "products_categories_product_id_category_id_pk";', + 'ALTER TABLE "products_to_categories" ADD CONSTRAINT "products_to_categories_product_id_category_id_pk" PRIMARY KEY("product_id","category_id");', + ]); + }, + // async addVectorIndexes() { // const client = new PGlite(); @@ -2104,6 +2188,81 @@ test('drop check constraint', async () => { ]); }); +test('Column with same name as enum', async () => { + const client = new PGlite(); + const statusEnum = pgEnum('status', ['inactive', 'active', 'banned']); + + const schema1 = { + statusEnum, + table1: pgTable('table1', { + id: serial('id').primaryKey(), + }), + }; + + const schema2 = { + statusEnum, + table1: pgTable('table1', { + id: serial('id').primaryKey(), + status: statusEnum('status').default('inactive'), + }), + table2: pgTable('table2', { + id: serial('id').primaryKey(), + status: statusEnum('status').default('inactive'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table2', + schema: '', + compositePKs: [], + compositePkName: '', + isRLSEnabled: false, + policies: [], + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'id', type: 'serial', primaryKey: true, notNull: true }, + { + name: 'status', + type: 'status', + typeSchema: 'public', + primaryKey: false, + notNull: false, + default: "'inactive'", + }, + ], + }, + { + type: 'alter_table_add_column', + tableName: 'table1', + schema: '', + column: { + name: 'status', + type: 'status', + typeSchema: 'public', + primaryKey: false, + notNull: false, + default: "'inactive'", + }, + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "table2" (\n\t"id" serial PRIMARY KEY NOT NULL,\n\t"status" "status" DEFAULT \'inactive\'\n);\n', + 'ALTER TABLE "table1" ADD COLUMN "status" "status" DEFAULT \'inactive\';', + ]); +}); + test('db has checks. Push with same names', async () => { const client = new PGlite(); @@ -2755,9 +2914,7 @@ test('add policy', async () => { as: 'PERMISSIVE', for: 'ALL', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', }, @@ -2814,8 +2971,6 @@ test('drop policy', async () => { for: 'ALL', to: ['public'], on: undefined, - using: undefined, - withCheck: undefined, }, schema: '', }, @@ -2868,9 +3023,7 @@ test('add policy without enable rls', async () => { as: 'PERMISSIVE', for: 'ALL', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', }, @@ -2922,9 +3075,7 @@ test('drop policy without disable rls', async () => { as: 'PERMISSIVE', for: 'ALL', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', }, @@ -3098,8 +3249,6 @@ test('alter policy with recreation: changing as', async (t) => { name: 'test', to: ['public'], on: undefined, - using: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3112,8 +3261,6 @@ test('alter policy with recreation: changing as', async (t) => { name: 'test', to: ['public'], on: undefined, - using: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3166,8 +3313,6 @@ test('alter policy with recreation: changing for', async (t) => { name: 'test', to: ['public'], on: undefined, - using: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3179,9 +3324,7 @@ test('alter policy with recreation: changing for', async (t) => { for: 'DELETE', name: 'test', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3233,9 +3376,7 @@ test('alter policy with recreation: changing both "as" and "for"', async (t) => for: 'ALL', name: 'test', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3247,9 +3388,7 @@ test('alter policy with recreation: changing both "as" and "for"', async (t) => for: 'INSERT', name: 'test', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3301,9 +3440,7 @@ test('alter policy with recreation: changing all fields', async (t) => { for: 'SELECT', name: 'test', to: ['public'], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3316,8 +3453,6 @@ test('alter policy with recreation: changing all fields', async (t) => { name: 'test', to: ['current_role'], on: undefined, - using: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3490,9 +3625,7 @@ test('create table with a policy', async (t) => { to: [ 'public', ], - using: undefined, on: undefined, - withCheck: undefined, }, schema: '', tableName: 'users2', @@ -3595,8 +3728,6 @@ test('add policy with multiple "to" roles', async (t) => { name: 'test', on: undefined, to: ['current_role', 'manager'], - using: undefined, - withCheck: undefined, }, schema: '', tableName: 'users', @@ -3609,6 +3740,223 @@ test('add policy with multiple "to" roles', async (t) => { } }); +test('rename policy that is linked', async (t) => { + const client = new PGlite(); + + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const { sqlStatements: createUsers } = await diffTestSchemas({}, { users }, []); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const schema2 = { + users, + rls: pgPolicy('newName', { as: 'permissive' }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + ['public.users.test->public.users.newName'], + false, + ['public'], + undefined, + undefined, + { before: createUsers }, + ); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" RENAME TO "newName";', + ]); + expect(statements).toStrictEqual([ + { + newName: 'newName', + oldName: 'test', + schema: '', + tableName: 'users', + type: 'rename_policy', + }, + ]); +}); + +test('alter policy that is linked', async (t) => { + const client = new PGlite(); + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const { sqlStatements: createUsers } = await diffTestSchemas({}, { users }, []); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive' }).link(users), + }; + + const schema2 = { + users, + rls: pgPolicy('test', { as: 'permissive', to: 'current_role' }).link(users), + }; + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + undefined, + { before: createUsers }, + ); + + expect(sqlStatements).toStrictEqual([ + 'ALTER POLICY "test" ON "users" TO current_role;', + ]); + expect(statements).toStrictEqual([{ + newData: 'test--PERMISSIVE--ALL--current_role--undefined', + oldData: 'test--PERMISSIVE--ALL--public--undefined', + schema: '', + tableName: 'users', + type: 'alter_policy', + }]); +}); + +test('alter policy that is linked: withCheck', async (t) => { + const client = new PGlite(); + + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const { sqlStatements: createUsers } = await diffTestSchemas({}, { users }, []); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive', withCheck: sql`true` }).link(users), + }; + + const schema2 = { + users, + rls: pgPolicy('test', { as: 'permissive', withCheck: sql`false` }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + undefined, + { before: createUsers }, + ); + + expect(sqlStatements).toStrictEqual([]); + expect(statements).toStrictEqual([]); +}); + +test('alter policy that is linked: using', async (t) => { + const client = new PGlite(); + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const { sqlStatements: createUsers } = await diffTestSchemas({}, { users }, []); + + const schema1 = { + rls: pgPolicy('test', { as: 'permissive', using: sql`true` }).link(users), + }; + + const schema2 = { + users, + rls: pgPolicy('test', { as: 'permissive', using: sql`false` }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + undefined, + { before: createUsers }, + ); + + expect(sqlStatements).toStrictEqual([]); + expect(statements).toStrictEqual([]); +}); + +test('alter policy that is linked: using', async (t) => { + const client = new PGlite(); + + const users = pgTable('users', { + id: integer('id').primaryKey(), + }); + + const { sqlStatements: createUsers } = await diffTestSchemas({}, { users }, []); + + const schema1 = { + rls: pgPolicy('test', { for: 'insert' }).link(users), + }; + + const schema2 = { + users, + rls: pgPolicy('test', { for: 'delete' }).link(users), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + undefined, + undefined, + { before: createUsers }, + ); + + expect(sqlStatements).toStrictEqual([ + 'DROP POLICY "test" ON "users" CASCADE;', + 'CREATE POLICY "test" ON "users" AS PERMISSIVE FOR DELETE TO public;', + ]); + expect(statements).toStrictEqual([ + { + data: { + as: 'PERMISSIVE', + for: 'INSERT', + name: 'test', + on: undefined, + to: [ + 'public', + ], + }, + schema: '', + tableName: 'users', + type: 'drop_policy', + }, + { + data: { + as: 'PERMISSIVE', + for: 'DELETE', + name: 'test', + on: undefined, + to: [ + 'public', + ], + }, + schema: '', + tableName: 'users', + type: 'create_policy', + }, + ]); +}); + //// test('create role', async (t) => { diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index b7b4c7f6b..0cb34c220 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -1025,3 +1025,25 @@ test('recreate table with nested references', async (t) => { expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); + +test('text default values escape single quotes', async (t) => { + const schema1 = { + table: sqliteTable('table', { + id: integer('id').primaryKey(), + }), + }; + + const schem2 = { + table: sqliteTable('table', { + id: integer('id').primaryKey(), + text: text('text').default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(schema1, schem2, []); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toStrictEqual( + "ALTER TABLE `table` ADD `text` text DEFAULT 'escape''s quotes';", + ); +}); diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index 8d8eae298..651c3633c 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -418,6 +418,50 @@ test('add table with indexes', async () => { ]); }); +test('composite primary key', async () => { + const from = {}; + const to = { + table: sqliteTable('works_to_creators', { + workId: int('work_id').notNull(), + creatorId: int('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `works_to_creators` (\n\t`work_id` integer NOT NULL,\n\t`creator_id` integer NOT NULL,\n\t`classification` text NOT NULL,\n\tPRIMARY KEY(`work_id`, `creator_id`, `classification`)\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: sqliteTable('table', { + id: int('id').primaryKey(), + }), + }; + const to = { + table: sqliteTable('table', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `table` ADD `name` text NOT NULL;', + 'CREATE UNIQUE INDEX `uq` ON `table` (`name`);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; From dc3d78c43ab7b64fb8ce07650c17086d9f6896eb Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 13 Nov 2024 00:22:54 +0000 Subject: [PATCH 341/492] remain fix of non singlestore files and common files --- drizzle-kit/src/cli/commands/introspect.ts | 1 + drizzle-kit/src/cli/commands/migrate.ts | 13 +- drizzle-kit/src/cli/commands/push.ts | 28 ++-- drizzle-kit/src/cli/commands/utils.ts | 10 +- drizzle-kit/src/cli/schema.ts | 4 +- drizzle-kit/src/cli/validations/outputs.ts | 2 +- drizzle-kit/src/cli/views.ts | 11 +- drizzle-kit/src/jsonStatements.ts | 22 +-- drizzle-kit/src/snapshotsDiffer.ts | 60 ++++--- drizzle-kit/src/sqlgenerator.ts | 147 ++++++++---------- drizzle-kit/src/utils.ts | 1 - .../tests/introspect/singlestore.test.ts | 2 +- drizzle-kit/tests/push/singlestore.test.ts | 10 +- drizzle-kit/tests/push/sqlite.test.ts | 77 +++++++++ drizzle-kit/tests/schemaDiffer.ts | 2 +- .../src/singlestore-core/columns/timestamp.ts | 2 +- 16 files changed, 226 insertions(+), 166 deletions(-) diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 149d2048b..7f13b99ff 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -223,6 +223,7 @@ export const introspectMysql = async ( const schema = { id: originUUID, prevId: '', ...res } as MySqlSchema; const ts = mysqlSchemaToTypeScript(schema, casing); const relationsTs = relationsToTypeScript(schema, casing); + const { internal, ...schemaWithoutInternals } = schema; const schemaFile = join(out, 'schema.ts'); writeFileSync(schemaFile, ts.file); diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 21a7bb440..00c472e9e 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -374,18 +374,9 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => { }; export const preparePgPush = async ( - schemaPath: string | string[], - snapshot: PgSchema, - schemaFilter: string[], - casing: CasingType | undefined, + cur: PgSchema, + prev: PgSchema, ) => { - const { prev, cur } = await preparePgDbPushSnapshot( - snapshot, - schemaPath, - casing, - schemaFilter, - ); - const validatedPrev = pgSchema.parse(prev); const validatedCur = pgSchema.parse(cur); diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index b147c2854..0c82fe026 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -1,5 +1,7 @@ import chalk from 'chalk'; +import { randomUUID } from 'crypto'; import { render } from 'hanji'; +import { serializePg } from 'src/serializer'; import { fromJson } from '../../sqlgenerator'; import { Select } from '../selector-ui'; import { Entities } from '../validations/cli'; @@ -320,20 +322,15 @@ export const pgPush = async ( const { pgPushIntrospect } = await import('./pgIntrospect'); const db = await preparePostgresDB(credentials); - const { schema } = await pgPushIntrospect( - db, - tablesFilter, - schemasFilter, - entities, - ); + const serialized = await serializePg(schemaPath, casing, schemasFilter); + + const { schema } = await pgPushIntrospect(db, tablesFilter, schemasFilter, entities, serialized); const { preparePgPush } = await import('./migrate'); const statements = await preparePgPush( - schemaPath, + { id: randomUUID(), prevId: schema.id, ...serialized }, schema, - schemasFilter, - casing, ); try { @@ -405,9 +402,7 @@ export const pgPush = async ( }${ matViewsToRemove.length > 0 ? ` remove ${matViewsToRemove.length} ${ - matViewsToRemove.length > 1 - ? 'materialized views' - : 'materialize view' + matViewsToRemove.length > 1 ? 'materialized views' : 'materialize view' },` : ' ' }` @@ -464,6 +459,7 @@ export const sqlitePush = async ( tablesToRemove, tablesToTruncate, infoToPrint, + schemasToRemove, } = await sqliteSuggestions( db, statements.statements, @@ -537,15 +533,15 @@ export const sqlitePush = async ( render(`\n[${chalk.blue('i')}] No changes detected`); } else { if (!('driver' in credentials)) { - await db.query('begin'); + await db.run('begin'); try { for (const dStmnt of statementsToExecute) { - await db.query(dStmnt); + await db.run(dStmnt); } - await db.query('commit'); + await db.run('commit'); } catch (e) { console.error(e); - await db.query('rollback'); + await db.run('rollback'); process.exit(1); } } diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 35a7b5a77..88476c56e 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -42,7 +42,7 @@ import { sqliteCredentials, } from '../validations/sqlite'; import { studioCliParams, studioConfig } from '../validations/studio'; -import { error } from '../views'; +import { error, grey } from '../views'; // NextJs default config is target: es5, which esbuild-register can't consume const assertES5 = async (unregister: () => void) => { @@ -769,12 +769,8 @@ export const drizzleConfigFromFile = async ( ): Promise => { const prefix = process.env.TEST_CONFIG_PATH_PREFIX || ''; - const defaultTsConfigExists = existsSync( - resolve(join(prefix, 'drizzle.config.ts')), - ); - const defaultJsConfigExists = existsSync( - resolve(join(prefix, 'drizzle.config.js')), - ); + const defaultTsConfigExists = existsSync(resolve(join(prefix, 'drizzle.config.ts'))); + const defaultJsConfigExists = existsSync(resolve(join(prefix, 'drizzle.config.js'))); const defaultJsonConfigExists = existsSync( join(resolve('drizzle.config.json')), ); diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index e952a8627..12153ee74 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -44,9 +44,7 @@ const optionDriver = string() .enum(...drivers) .desc('Database driver'); -const optionCasing = string() - .enum('camelCase', 'snake_case') - .desc('Casing for serialization'); +const optionCasing = string().enum('camelCase', 'snake_case').desc('Casing for serialization'); export const generate = command({ name: 'generate', diff --git a/drizzle-kit/src/cli/validations/outputs.ts b/drizzle-kit/src/cli/validations/outputs.ts index ad0423b97..6e9d520dd 100644 --- a/drizzle-kit/src/cli/validations/outputs.ts +++ b/drizzle-kit/src/cli/validations/outputs.ts @@ -26,7 +26,7 @@ export const outputs = { ), noDialect: () => withStyle.error( - `Please specify 'dialect' param in config, either of 'pg', 'mysql', 'sqlite' or singlestore`, + `Please specify 'dialect' param in config, either of 'postgresql', 'mysql', 'sqlite', turso or singlestore`, ), }, common: { diff --git a/drizzle-kit/src/cli/views.ts b/drizzle-kit/src/cli/views.ts index e79d585ee..9106d31cd 100644 --- a/drizzle-kit/src/cli/views.ts +++ b/drizzle-kit/src/cli/views.ts @@ -32,11 +32,16 @@ export const schema = (schema: CommonSchema): string => { .map((t) => { const columnsCount = Object.values(t.columns).length; const indexesCount = Object.values(t.indexes).length; - // should we have fks? - // const foreignKeys = Object.values(t.foreignKeys).length; + let foreignKeys: number = 0; + // Singlestore doesn't have foreign keys + if (schema.dialect !== 'singlestore') { + // @ts-expect-error + foreignKeys = Object.values(t.foreignKeys).length; + } + return `${chalk.bold.blue(t.name)} ${ chalk.gray( - `${columnsCount} columns ${indexesCount} indexes`, + `${columnsCount} columns ${indexesCount} indexes ${foreignKeys} fks`, ) }`; }) diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 81bbc2610..4fd9726d6 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -3116,9 +3116,7 @@ export const prepareAddCompositePrimaryKeyPg = ( tableName, data: it, schema, - constraintName: json2.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - unsquashed.name - ].name, + constraintName: PgSquasher.unsquashPK(it).name, } as JsonCreateCompositePK; }); }; @@ -3136,9 +3134,7 @@ export const prepareDeleteCompositePrimaryKeyPg = ( tableName, data: it, schema, - constraintName: json1.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it).name - ].name, + constraintName: PgSquasher.unsquashPK(it).name, } as JsonDeleteCompositePK; }); }; @@ -3158,12 +3154,8 @@ export const prepareAlterCompositePrimaryKeyPg = ( old: it.__old, new: it.__new, schema, - oldConstraintName: json1.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it.__old).name - ].name, - newConstraintName: json2.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it.__new).name - ].name, + oldConstraintName: PgSquasher.unsquashPK(it.__old).name, + newConstraintName: PgSquasher.unsquashPK(it.__new).name, } as JsonAlterCompositePK; }); }; @@ -3276,7 +3268,7 @@ export const prepareAddCompositePrimaryKeyMySql = ( type: 'create_composite_pk', tableName, data: it, - constraintName: json2.tables[tableName].compositePrimaryKeys[unsquashed.name].name, + constraintName: unsquashed.name, } as JsonCreateCompositePK); } return res; @@ -3289,13 +3281,11 @@ export const prepareDeleteCompositePrimaryKeyMySql = ( json1: MySqlSchema, ): JsonDeleteCompositePK[] => { return Object.values(pks).map((it) => { + const unsquashed = MySqlSquasher.unsquashPK(it); return { type: 'delete_composite_pk', tableName, data: it, - constraintName: json1.tables[tableName].compositePrimaryKeys[ - MySqlSquasher.unsquashPK(it).name - ].name, } as JsonDeleteCompositePK; }); }; diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 48520dc68..5e5d8fb19 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -1003,8 +1003,10 @@ export const applyPgSnapshotsDiff = async ( const { renamed, created, deleted } = await policyResolver({ tableName: entry.name, schema: entry.schema, - deleted: entry.policies.deleted.map(PgSquasher.unsquashPolicy), - created: entry.policies.added.map(PgSquasher.unsquashPolicy), + deleted: entry.policies.deleted.map( + action === 'push' ? PgSquasher.unsquashPolicyPush : PgSquasher.unsquashPolicy, + ), + created: entry.policies.added.map(action === 'push' ? PgSquasher.unsquashPolicyPush : PgSquasher.unsquashPolicy), }); if (created.length > 0) { @@ -1058,7 +1060,9 @@ export const applyPgSnapshotsDiff = async ( ] || []; const newName = columnChangeFor(policyKey, rens); - const unsquashedPolicy = PgSquasher.unsquashPolicy(policy); + const unsquashedPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(policy) + : PgSquasher.unsquashPolicy(policy); unsquashedPolicy.name = newName; policy = PgSquasher.squashPolicy(unsquashedPolicy); return newName; @@ -1083,8 +1087,12 @@ export const applyPgSnapshotsDiff = async ( }[]; const { renamed: indPolicyRenames, created, deleted } = await indPolicyResolver({ - deleted: indPolicyRes.deleted.map((t) => PgSquasher.unsquashPolicy(t.values)), - created: indPolicyRes.added.map((t) => PgSquasher.unsquashPolicy(t.values)), + deleted: indPolicyRes.deleted.map((t) => + action === 'push' ? PgSquasher.unsquashPolicyPush(t.values) : PgSquasher.unsquashPolicy(t.values) + ), + created: indPolicyRes.added.map((t) => + action === 'push' ? PgSquasher.unsquashPolicyPush(t.values) : PgSquasher.unsquashPolicy(t.values) + ), }); if (created.length > 0) { @@ -1250,22 +1258,22 @@ export const applyPgSnapshotsDiff = async ( // This part is needed to make sure that same columns in a table are not triggered for change // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name // We double-check that pk with same set of columns are both in added and deleted diffs - let addedColumns: string[] = []; + let addedColumns: { name: string; columns: string[] } | undefined; for (const addedPkName of Object.keys(it.addedCompositePKs)) { const addedPkColumns = it.addedCompositePKs[addedPkName]; - addedColumns = SQLiteSquasher.unsquashPK(addedPkColumns); + addedColumns = PgSquasher.unsquashPK(addedPkColumns); } - let deletedColumns: string[] = []; + let deletedColumns: { name: string; columns: string[] } | undefined; for (const deletedPkName of Object.keys(it.deletedCompositePKs)) { const deletedPkColumns = it.deletedCompositePKs[deletedPkName]; - deletedColumns = SQLiteSquasher.unsquashPK(deletedPkColumns); + deletedColumns = PgSquasher.unsquashPK(deletedPkColumns); } // Don't need to sort, but need to add tests for it // addedColumns.sort(); // deletedColumns.sort(); - const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); + const doPerformDeleteAndCreate = JSON.stringify(addedColumns ?? {}) !== JSON.stringify(deletedColumns ?? {}); let addedCompositePKs: JsonCreateCompositePK[] = []; let deletedCompositePKs: JsonDeleteCompositePK[] = []; @@ -1436,10 +1444,14 @@ export const applyPgSnapshotsDiff = async ( typedResult.alteredPolicies.forEach(({ values }) => { // return prepareAlterIndPolicyJson(json1.policies[it.name], json2.policies[it.name]); - const policy = PgSquasher.unsquashPolicy(values); + const policy = action === 'push' ? PgSquasher.unsquashPolicyPush(values) : PgSquasher.unsquashPolicy(values); - const newPolicy = PgSquasher.unsquashPolicy(json2.policies[policy.name].values); - const oldPolicy = PgSquasher.unsquashPolicy(json1.policies[policy.name].values); + const newPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(json2.policies[policy.name].values) + : PgSquasher.unsquashPolicy(json2.policies[policy.name].values); + const oldPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(json2.policies[policy.name].values) + : PgSquasher.unsquashPolicy(json1.policies[policy.name].values); if (newPolicy.as !== oldPolicy.as) { jsonDropIndPoliciesStatements.push( @@ -1509,8 +1521,12 @@ export const applyPgSnapshotsDiff = async ( alteredTables.forEach((it) => { // handle policies Object.keys(it.alteredPolicies).forEach((policyName: string) => { - const newPolicy = PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__new); - const oldPolicy = PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__old); + const newPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(it.alteredPolicies[policyName].__new) + : PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__new); + const oldPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(it.alteredPolicies[policyName].__old) + : PgSquasher.unsquashPolicy(it.alteredPolicies[policyName].__old); if (newPolicy.as !== oldPolicy.as) { jsonDropPoliciesStatements.push( @@ -1584,7 +1600,8 @@ export const applyPgSnapshotsDiff = async ( } // handle table.isRLSEnabled - if (table.isRLSEnabled !== tableInPreviousState.isRLSEnabled) { + const wasRlsEnabled = tableInPreviousState ? tableInPreviousState.isRLSEnabled : false; + if (table.isRLSEnabled !== wasRlsEnabled) { if (table.isRLSEnabled) { // was force enabled jsonEnableRLSStatements.push({ type: 'enable_rls', tableName: table.name, schema: table.schema }); @@ -1777,7 +1794,11 @@ export const applyPgSnapshotsDiff = async ( jsonCreatePoliciesStatements.push(...([] as JsonCreatePolicyStatement[]).concat( ...(createdTables.map((it) => - prepareCreatePolicyJsons(it.name, it.schema, Object.values(it.policies).map(PgSquasher.unsquashPolicy)) + prepareCreatePolicyJsons( + it.name, + it.schema, + Object.values(it.policies).map(action === 'push' ? PgSquasher.unsquashPolicyPush : PgSquasher.unsquashPolicy), + ) )), )); const createViews: JsonCreatePgViewStatement[] = []; @@ -2052,7 +2073,7 @@ export const applyPgSnapshotsDiff = async ( return true; }); - const sqlStatements = fromJson(filteredEnumsJsonStatements, 'postgresql'); + const sqlStatements = fromJson(filteredEnumsJsonStatements, 'postgresql', action); const uniqueSqlStatements: string[] = []; sqlStatements.forEach((ss) => { @@ -2628,12 +2649,11 @@ export const applyMysqlSnapshotsDiff = async ( jsonStatements.push(...jsonDeletedCompositePKs); jsonStatements.push(...jsonTableAlternations); jsonStatements.push(...jsonAddedCompositePKs); + jsonStatements.push(...jsonAddColumnsStatemets); jsonStatements.push(...jsonAddedUniqueConstraints); jsonStatements.push(...jsonDeletedUniqueConstraints); - jsonStatements.push(...jsonAddColumnsStatemets); - jsonStatements.push(...jsonCreateReferencesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForCreatedTables); jsonStatements.push(...jsonCreatedCheckConstraints); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 81f04f10e..1dd72a338 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -88,74 +88,59 @@ import { PgSquasher, policy } from './serializer/pgSchema'; import { SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; -export const pgNativeTypes = new Set([ - 'uuid', - 'smallint', - 'integer', - 'bigint', - 'boolean', - 'text', - 'varchar', - 'serial', - 'bigserial', - 'decimal', - 'numeric', - 'real', - 'json', - 'jsonb', - 'time', - 'time with time zone', - 'time without time zone', - 'time', - 'timestamp', - 'timestamp with time zone', - 'timestamp without time zone', - 'date', - 'interval', - 'bigint', - 'bigserial', - 'double precision', - 'interval year', - 'interval month', - 'interval day', - 'interval hour', - 'interval minute', - 'interval second', - 'interval year to month', - 'interval day to hour', - 'interval day to minute', - 'interval day to second', - 'interval hour to minute', - 'interval hour to second', - 'interval minute to second', -]); - -const isPgNativeType = (it: string) => { - if (pgNativeTypes.has(it)) return true; - const toCheck = it.replace(/ /g, ''); - return ( - toCheck.startsWith('varchar(') - || toCheck.startsWith('char(') - || toCheck.startsWith('numeric(') - || toCheck.startsWith('timestamp(') - || toCheck.startsWith('doubleprecision[') - || toCheck.startsWith('intervalyear(') - || toCheck.startsWith('intervalmonth(') - || toCheck.startsWith('intervalday(') - || toCheck.startsWith('intervalhour(') - || toCheck.startsWith('intervalminute(') - || toCheck.startsWith('intervalsecond(') - || toCheck.startsWith('intervalyeartomonth(') - || toCheck.startsWith('intervaldaytohour(') - || toCheck.startsWith('intervaldaytominute(') - || toCheck.startsWith('intervaldaytosecond(') - || toCheck.startsWith('intervalhourtominute(') - || toCheck.startsWith('intervalhourtosecond(') - || toCheck.startsWith('intervalminutetosecond(') - || toCheck.startsWith('vector(') - || toCheck.startsWith('geometry(') - || /^(\w+)(\[\d*])+$/.test(it) - ); +import { escapeSingleQuotes } from './utils'; + +const parseType = (schemaPrefix: string, type: string) => { + const pgNativeTypes = [ + 'uuid', + 'smallint', + 'integer', + 'bigint', + 'boolean', + 'text', + 'varchar', + 'serial', + 'bigserial', + 'decimal', + 'numeric', + 'real', + 'json', + 'jsonb', + 'time', + 'time with time zone', + 'time without time zone', + 'time', + 'timestamp', + 'timestamp with time zone', + 'timestamp without time zone', + 'date', + 'interval', + 'bigint', + 'bigserial', + 'double precision', + 'interval year', + 'interval month', + 'interval day', + 'interval hour', + 'interval minute', + 'interval second', + 'interval year to month', + 'interval day to hour', + 'interval day to minute', + 'interval day to second', + 'interval hour to minute', + 'interval hour to second', + 'interval minute to second', + 'char', + 'vector', + 'geometry', + ]; + const arrayDefinitionRegex = /\[\d*(?:\[\d*\])*\]/g; + const arrayDefinition = (type.match(arrayDefinitionRegex) ?? []).join(''); + const withoutArrayDefinition = type.replace(arrayDefinitionRegex, ''); + return pgNativeTypes.some((it) => type.startsWith(it)) + ? `${withoutArrayDefinition}${arrayDefinition}` + : `${schemaPrefix}"${withoutArrayDefinition}"${arrayDefinition}`; }; abstract class Convertor { @@ -271,9 +256,13 @@ class PgAlterPolicyConvertor extends Convertor { override can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'alter_policy' && dialect === 'postgresql'; } - override convert(statement: JsonAlterPolicyStatement): string | string[] { - const newPolicy = PgSquasher.unsquashPolicy(statement.newData); - const oldPolicy = PgSquasher.unsquashPolicy(statement.oldData); + override convert(statement: JsonAlterPolicyStatement, _dialect: any, action?: string): string | string[] { + const newPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(statement.newData) + : PgSquasher.unsquashPolicy(statement.newData); + const oldPolicy = action === 'push' + ? PgSquasher.unsquashPolicyPush(statement.oldData) + : PgSquasher.unsquashPolicy(statement.oldData); const tableNameWithSchema = statement.schema ? `"${statement.schema}"."${statement.tableName}"` @@ -416,9 +405,7 @@ class PgCreateTableConvertor extends Convertor { ? `"${column.typeSchema}".` : ''; - const type = isPgNativeType(column.type) - ? column.type - : `${schemaPrefix}"${column.type}"`; + const type = parseType(schemaPrefix, column.type); const generated = column.generated; const generatedStatement = generated ? ` GENERATED ALWAYS AS (${generated?.as}) STORED` : ''; @@ -1391,7 +1378,7 @@ class CreateTypeEnumConvertor extends Convertor { const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; let valuesStatement = '('; - valuesStatement += values.map((it) => `'${it}'`).join(', '); + valuesStatement += values.map((it) => `'${escapeSingleQuotes(it)}'`).join(', '); valuesStatement += ')'; // TODO do we need this? @@ -1507,7 +1494,7 @@ class PgDropTableConvertor extends Convertor { return statement.type === 'drop_table' && dialect === 'postgresql'; } - convert(statement: JsonDropTableStatement) { + convert(statement: JsonDropTableStatement, _d: any, action?: string) { const { tableName, schema, policies } = statement; const tableNameWithSchema = schema @@ -1519,7 +1506,9 @@ class PgDropTableConvertor extends Convertor { return dropPolicyConvertor.convert({ type: 'drop_policy', tableName, - data: PgSquasher.unsquashPolicy(p), + data: action === 'push' + ? PgSquasher.unsquashPolicyPush(p) + : PgSquasher.unsquashPolicy(p), schema, }) as string; }) ?? []; @@ -1743,9 +1732,7 @@ class PgAlterTableAddColumnConvertor extends Convertor { ? `"${column.typeSchema}".` : ''; - const fixedType = isPgNativeType(column.type) - ? column.type - : `${schemaPrefix}"${column.type}"`; + const fixedType = parseType(schemaPrefix, column.type); const notNullStatement = `${notNull ? ' NOT NULL' : ''}`; diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 559153c38..2638ca4ef 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -1,4 +1,3 @@ - import type { RunResult } from 'better-sqlite3'; import chalk from 'chalk'; import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs'; diff --git a/drizzle-kit/tests/introspect/singlestore.test.ts b/drizzle-kit/tests/introspect/singlestore.test.ts index ed1db094b..9a7e3af5a 100644 --- a/drizzle-kit/tests/introspect/singlestore.test.ts +++ b/drizzle-kit/tests/introspect/singlestore.test.ts @@ -14,7 +14,7 @@ import { smallint, text, tinyint, - varchar + varchar, } from 'drizzle-orm/singlestore-core'; import * as fs from 'fs'; import getPort from 'get-port'; diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 13ef08cfa..82a901b16 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -1,4 +1,5 @@ import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; import { bigint, binary, @@ -27,7 +28,6 @@ import { diffTestSchemasPushSingleStore, diffTestSchemasSingleStore } from 'test import { v4 as uuid } from 'uuid'; import { expect } from 'vitest'; import { DialectSuite, run } from './common'; -import { sql } from 'drizzle-orm'; async function createDockerDB(context: any): Promise { const docker = new Docker(); @@ -206,10 +206,10 @@ const singlestoreSuite: DialectSuite = { }), allTimestamps: singlestoreTable('all_timestamps', { - columnDateNow: timestamp("column_date_now", { - fsp: 0, - mode: "string", - }).default(sql`CURRENT_TIMESTAMP`), + columnDateNow: timestamp('column_date_now', { + fsp: 0, + mode: 'string', + }).default(sql`CURRENT_TIMESTAMP`), columnAll: timestamp('column_all', { mode: 'string' }) .default('2023-03-01 14:05:29') .notNull(), diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index 5ac6f996c..dd1d88fe3 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -9,6 +9,7 @@ import { int, integer, numeric, + primaryKey, real, sqliteTable, sqliteView, @@ -1534,3 +1535,79 @@ test('alter view ".as"', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('create composite primary key', async (t) => { + const client = new Database(':memory:'); + + const schema1 = {}; + + const schema2 = { + table: sqliteTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { + statements, + sqlStatements, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([{ + type: 'sqlite_create_table', + tableName: 'table', + compositePKs: [['col1', 'col2']], + uniqueConstraints: [], + referenceData: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'integer', primaryKey: false, notNull: true, autoincrement: false }, + { name: 'col2', type: 'integer', primaryKey: false, notNull: true, autoincrement: false }, + ], + }]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `table` (\n\t`col1` integer NOT NULL,\n\t`col2` integer NOT NULL,\n\tPRIMARY KEY(`col1`, `col2`)\n);\n', + ]); +}); + +test('rename table with composite primary key', async () => { + const client = new Database(':memory:'); + + const productsCategoriesTable = (tableName: string) => { + return sqliteTable(tableName, { + productId: text('product_id').notNull(), + categoryId: text('category_id').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + false, + ); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `products_categories` RENAME TO `products_to_categories`;', + ]); +}); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index 62109c60a..a383ab717 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -59,7 +59,7 @@ import { generateSingleStoreSnapshot, } from 'src/serializer/singlestoreSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; -import { sqliteSchema, View as SqliteView, squashSqliteScheme } from 'src/serializer/sqliteSchema'; +import { sqliteSchema, squashSqliteScheme, View as SqliteView } from 'src/serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase, generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; import { applyLibSQLSnapshotsDiff, diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts index 3dbe1f9da..f269dad0f 100644 --- a/drizzle-orm/src/singlestore-core/columns/timestamp.ts +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -2,9 +2,9 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { sql } from '~/sql/sql.ts'; import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreDateBaseColumn, SingleStoreDateColumnBaseBuilder } from './date.common.ts'; -import { sql } from '~/sql/sql.ts'; export type SingleStoreTimestampBuilderInitial = SingleStoreTimestampBuilder<{ name: TName; From 28cd0e1902a231ada253741ef374a63ae29dc077 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 13 Nov 2024 02:37:07 +0000 Subject: [PATCH 342/492] update drizzle-orm --- drizzle-orm/src/singlestore-core/alias.ts | 3 +- drizzle-orm/src/singlestore-core/checks.ts | 32 ----- drizzle-orm/src/singlestore-core/db.ts | 68 +++------- drizzle-orm/src/singlestore-core/dialect.ts | 125 +++++------------- drizzle-orm/src/singlestore-core/index.ts | 5 +- drizzle-orm/src/singlestore-core/indexes.ts | 30 +++-- .../singlestore-core/query-builders/index.ts | 8 +- .../singlestore-core/query-builders/insert.ts | 4 +- .../singlestore-core/query-builders/query.ts | 5 + .../singlestore-core/query-builders/select.ts | 16 +-- .../query-builders/select.types.ts | 10 +- drizzle-orm/src/singlestore-core/schema.ts | 9 +- drizzle-orm/src/singlestore-core/session.ts | 7 +- .../sql/expressions/conditions.ts | 22 --- .../singlestore-core/sql/expressions/index.ts | 1 - drizzle-orm/src/singlestore-core/sql/index.ts | 1 - drizzle-orm/src/singlestore-core/utils.ts | 9 +- 17 files changed, 106 insertions(+), 249 deletions(-) delete mode 100644 drizzle-orm/src/singlestore-core/checks.ts delete mode 100644 drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts delete mode 100644 drizzle-orm/src/singlestore-core/sql/expressions/index.ts delete mode 100644 drizzle-orm/src/singlestore-core/sql/index.ts diff --git a/drizzle-orm/src/singlestore-core/alias.ts b/drizzle-orm/src/singlestore-core/alias.ts index 08e7ecc67..6c08bdff3 100644 --- a/drizzle-orm/src/singlestore-core/alias.ts +++ b/drizzle-orm/src/singlestore-core/alias.ts @@ -1,9 +1,8 @@ import { TableAliasProxyHandler } from '~/alias.ts'; import type { BuildAliasTable } from './query-builders/select.types.ts'; import type { SingleStoreTable } from './table.ts'; -import type { SingleStoreViewBase } from './view-base.ts'; -export function alias( +export function alias( // | SingleStoreViewBase table: TTable, alias: TAlias, ): BuildAliasTable { diff --git a/drizzle-orm/src/singlestore-core/checks.ts b/drizzle-orm/src/singlestore-core/checks.ts deleted file mode 100644 index 29fdb7680..000000000 --- a/drizzle-orm/src/singlestore-core/checks.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { entityKind } from '~/entity.ts'; -import type { SQL } from '~/sql/sql.ts'; -import type { SingleStoreTable } from './table.ts'; - -export class CheckBuilder { - static readonly [entityKind]: string = 'SingleStoreCheckBuilder'; - - protected brand!: 'SingleStoreConstraintBuilder'; - - constructor(public name: string, public value: SQL) {} - - /** @internal */ - build(table: SingleStoreTable): Check { - return new Check(table, this); - } -} - -export class Check { - static readonly [entityKind]: string = 'SingleStoreCheck'; - - readonly name: string; - readonly value: SQL; - - constructor(public table: SingleStoreTable, builder: CheckBuilder) { - this.name = builder.name; - this.value = builder.value; - } -} - -export function check(name: string, value: SQL): CheckBuilder { - return new CheckBuilder(name, value); -} diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 63cf97da4..2f4814544 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -3,15 +3,11 @@ import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import { type ColumnsSelection, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; import type { DrizzleTypeError } from '~/utils.ts'; import type { SingleStoreDialect } from './dialect.ts'; -import { SingleStoreAttachBase } from './query-builders/attach.ts'; -import { SingleStoreBranchBase } from './query-builders/branch.ts'; -import { SingleStoreCreateMilestoneBase } from './query-builders/createMilestone.ts'; -import { SingleStoreDetachBase } from './query-builders/detach.ts'; -import { SingleStoreDropMilestoneBase } from './query-builders/dropMilestone.ts'; +import { SingleStoreCountBuilder } from './query-builders/count.ts'; import { QueryBuilder, SingleStoreDeleteBase, @@ -19,11 +15,10 @@ import { SingleStoreSelectBuilder, SingleStoreUpdateBuilder, } from './query-builders/index.ts'; -import type { OptimizeTableArgument } from './query-builders/optimizeTable.ts'; -import { SingleStoreOptimizeTableBase } from './query-builders/optimizeTable.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import type { + Mode, PreparedQueryHKTBase, SingleStoreQueryResultHKT, SingleStoreQueryResultKind, @@ -60,6 +55,7 @@ export class SingleStoreDatabase< /** @internal */ readonly session: SingleStoreSession, schema: RelationalSchemaConfig | undefined, + protected readonly mode: Mode, ) { this._ = schema ? { @@ -84,6 +80,7 @@ export class SingleStoreDatabase< columns, dialect, session, + this.mode, ); } } @@ -122,12 +119,13 @@ export class SingleStoreDatabase< * ``` */ $with(alias: TAlias) { + const self = this; return { as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), ): WithSubqueryWithSelection { if (typeof qb === 'function') { - qb = qb(new QueryBuilder()); + qb = qb(new QueryBuilder(self.dialect)); } return new Proxy( @@ -138,6 +136,13 @@ export class SingleStoreDatabase< }; } + $count( + source: SingleStoreTable | SQL | SQLWrapper, // SingleStoreViewBase | + filters?: SQL, + ) { + return new SingleStoreCountBuilder({ source, filters, session: this.session }); + } + /** * Incorporates a previously defined CTE (using `$with`) into the main query. * @@ -463,9 +468,9 @@ export class SingleStoreDatabase< } execute( - query: SQLWrapper, + query: SQLWrapper | string, ): Promise> { - return this.session.execute(query.getSQL()); + return this.session.execute(typeof query === 'string' ? sql.raw(query) : query.getSQL()); } transaction( @@ -477,47 +482,6 @@ export class SingleStoreDatabase< ): Promise { return this.session.transaction(transaction, config); } - - detach( - database: TDatabase, - ): SingleStoreDetachBase { - return new SingleStoreDetachBase(database, this.session, this.dialect); - } - - attach( - database: TDatabase, - ): SingleStoreAttachBase { - return new SingleStoreAttachBase(database, this.session, this.dialect); - } - - branch( - database: TDatabase, - branchName: string, - ): SingleStoreBranchBase { - return new SingleStoreBranchBase(database, branchName, this.session, this.dialect); - } - - createMilestone( - milestone: TMilestone, - ): SingleStoreCreateMilestoneBase { - return new SingleStoreCreateMilestoneBase(milestone, this.session, this.dialect); - } - - dropMilestone( - milestone: TMilestone, - ): SingleStoreDropMilestoneBase { - return new SingleStoreDropMilestoneBase(milestone, this.session, this.dialect); - } - - optimizeTable< - TTable extends SingleStoreTable, - TArg extends OptimizeTableArgument, - >( - table: TTable, - arg: TArg | undefined = undefined, - ): SingleStoreOptimizeTableBase { - return new SingleStoreOptimizeTableBase(table, arg, this.session, this.dialect); - } } export type SingleStoreWithReplicas = Q & { $primary: Q }; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 9e942cba8..951a5cac7 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -17,22 +17,15 @@ import { type TableRelationalConfig, type TablesRelationalConfig, } from '~/relations.ts'; +import type { Name, Placeholder, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; import { Param, SQL, sql, View } from '~/sql/sql.ts'; -import type { Name, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { getTableName, getTableUniqueName, Table } from '~/table.ts'; -import { orderSelectedFields } from '~/utils.ts'; -import type { Casing, UpdateSet } from '~/utils.ts'; +import { type Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import { SingleStoreColumn } from './columns/common.ts'; -import type { SingleStoreAttachConfig } from './query-builders/attach.ts'; -import type { SingleStoreBranchConfig } from './query-builders/branch.ts'; -import type { SingleStoreCreateMilestoneConfig } from './query-builders/createMilestone.ts'; import type { SingleStoreDeleteConfig } from './query-builders/delete.ts'; -import type { SingleStoreDetachConfig } from './query-builders/detach.ts'; -import type { SingleStoreDropMilestoneConfig } from './query-builders/dropMilestone.ts'; import type { SingleStoreInsertConfig } from './query-builders/insert.ts'; -import type { SingleStoreOptimizeTableConfig } from './query-builders/optimizeTable.ts'; import type { SelectedFieldsOrdered, SingleStoreSelectConfig, @@ -123,7 +116,7 @@ export class SingleStoreDialect { return sql.join(withSqlChunks); } - buildDeleteQuery({ table, where, returning, withList }: SingleStoreDeleteConfig): SQL { + buildDeleteQuery({ table, where, returning, withList, limit, orderBy }: SingleStoreDeleteConfig): SQL { const withSql = this.buildWithCTE(withList); const returningSql = returning @@ -132,61 +125,11 @@ export class SingleStoreDialect { const whereSql = where ? sql` where ${where}` : undefined; - return sql`${withSql}delete from ${table}${whereSql}${returningSql}`; - } - - buildDetachQuery({ database, milestone, workspace }: SingleStoreDetachConfig): SQL { - const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; - - const workspaceSql = workspace ? sql` from workspace ${workspace}` : undefined; - - return sql`detach database ${database}${milestoneSql}${workspaceSql}`; - } + const orderBySql = this.buildOrderBy(orderBy); - buildAttachQuery( - { database, milestone, time, databaseAlias, readOnly, ...rest }: SingleStoreAttachConfig | SingleStoreBranchConfig, - ): SQL { - const asSql = databaseAlias ? sql` as ${sql.identifier(databaseAlias)}` : undefined; - const milestoneSql = milestone ? sql` at milestone ${milestone}` : undefined; - const timeSql = time ? sql` at time ${time}` : undefined; - const readOnlySql = readOnly ? sql` read only` : undefined; - const fromWorkspaceGroupSql = 'fromWorkspaceGroup' in rest - ? sql` from workspace group ${rest.fromWorkspaceGroup}` - : undefined; - - return sql`attach database ${ - sql.raw(database) - }${fromWorkspaceGroupSql}${readOnlySql}${asSql}${milestoneSql}${timeSql}`; - } - - buildCreateMilestoneQuery({ database, milestone }: SingleStoreCreateMilestoneConfig): SQL { - const forSql = database ? sql` for ${sql.identifier(database)}` : undefined; - - return sql`create milestone ${milestone}${forSql}`; - } - - buildDropMilestoneQuery({ database, milestone }: SingleStoreDropMilestoneConfig): SQL { - const forSql = database ? sql` for ${sql.identifier(database)}` : undefined; - - return sql`drop milestone ${milestone}${forSql}`; - } - - buildOptimizeTable({ table, arg, selection }: SingleStoreOptimizeTableConfig): SQL { - const argSql = arg ? sql` ${sql.raw(arg)}` : undefined; - - let warmBlobCacheForColumnSql = undefined; - if (selection) { - const selectionField = selection.length > 0 - ? selection.map((column) => { - return { path: [], field: column }; - }) - : [{ path: [], field: sql.raw('*') }]; - warmBlobCacheForColumnSql = sql` warm blob cache for column ${ - this.buildSelection(selectionField, { isSingleTable: true }) - }`; - } + const limitSql = this.buildLimit(limit); - return sql`optimize table ${table}${argSql}${warmBlobCacheForColumnSql}`; + return sql`${withSql}delete from ${table}${whereSql}${orderBySql}${limitSql}${returningSql}`; } buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { @@ -201,7 +144,7 @@ export class SingleStoreDialect { const col = tableColumns[colName]!; const value = set[colName] ?? sql.param(col.onUpdateFn!(), col); - const res = sql`${sql.identifier(col.name)} = ${value}`; + const res = sql`${sql.identifier(this.casing.getColumnCasing(col))} = ${value}`; if (i < setSize - 1) { return [res, sql.raw(', ')]; @@ -210,7 +153,7 @@ export class SingleStoreDialect { })); } - buildUpdateQuery({ table, set, where, returning, withList }: SingleStoreUpdateConfig): SQL { + buildUpdateQuery({ table, set, where, returning, withList, limit, orderBy }: SingleStoreUpdateConfig): SQL { const withSql = this.buildWithCTE(withList); const setSql = this.buildUpdateSet(table, set); @@ -221,7 +164,11 @@ export class SingleStoreDialect { const whereSql = where ? sql` where ${where}` : undefined; - return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}`; + const orderBySql = this.buildOrderBy(orderBy); + + const limitSql = this.buildLimit(limit); + + return sql`${withSql}update ${table} set ${setSql}${whereSql}${orderBySql}${limitSql}${returningSql}`; } /** @@ -255,7 +202,7 @@ export class SingleStoreDialect { new SQL( query.queryChunks.map((c) => { if (is(c, SingleStoreColumn)) { - return sql.identifier(c.name); + return sql.identifier(this.casing.getColumnCasing(c)); } return c; }), @@ -270,7 +217,7 @@ export class SingleStoreDialect { } } else if (is(field, Column)) { if (isSingleTable) { - chunk.push(sql.identifier(field.name)); + chunk.push(sql.identifier(this.casing.getColumnCasing(field))); } else { chunk.push(field); } @@ -286,6 +233,16 @@ export class SingleStoreDialect { return sql.join(chunks); } + private buildLimit(limit: number | Placeholder | undefined): SQL | undefined { + return typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined; + } + + private buildOrderBy(orderBy: (SingleStoreColumn | SQL | SQL.Aliased)[] | undefined): SQL | undefined { + return orderBy && orderBy.length > 0 ? sql` order by ${sql.join(orderBy, sql`, `)}` : undefined; + } + buildSelectQuery( { withList, @@ -393,19 +350,11 @@ export class SingleStoreDialect { const havingSql = having ? sql` having ${having}` : undefined; - let orderBySql; - if (orderBy && orderBy.length > 0) { - orderBySql = sql` order by ${sql.join(orderBy, sql`, `)}`; - } + const orderBySql = this.buildOrderBy(orderBy); - let groupBySql; - if (groupBy && groupBy.length > 0) { - groupBySql = sql` group by ${sql.join(groupBy, sql`, `)}`; - } + const groupBySql = groupBy && groupBy.length > 0 ? sql` group by ${sql.join(groupBy, sql`, `)}` : undefined; - const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) - ? sql` limit ${limit}` - : undefined; + const limitSql = this.buildLimit(limit); const offsetSql = offset ? sql` offset ${offset}` : undefined; @@ -463,13 +412,13 @@ export class SingleStoreDialect { // which is invalid SingleStore syntax, Table from one of the SELECTs cannot be used in global ORDER clause for (const orderByUnit of orderBy) { if (is(orderByUnit, SingleStoreColumn)) { - orderByValues.push(sql.identifier(orderByUnit.name)); + orderByValues.push(sql.identifier(this.casing.getColumnCasing(orderByUnit))); } else if (is(orderByUnit, SQL)) { for (let i = 0; i < orderByUnit.queryChunks.length; i++) { const chunk = orderByUnit.queryChunks[i]; if (is(chunk, SingleStoreColumn)) { - orderByUnit.queryChunks[i] = sql.identifier(chunk.name); + orderByUnit.queryChunks[i] = sql.identifier(this.casing.getColumnCasing(chunk)); } } @@ -503,7 +452,7 @@ export class SingleStoreDialect { !col.shouldDisableInsert() ); - const insertOrder = colEntries.map(([, column]) => sql.identifier(column.name)); + const insertOrder = colEntries.map(([, column]) => sql.identifier(this.casing.getColumnCasing(column))); const generatedIdsResponse: Record[] = []; for (const [valueIndex, value] of values.entries()) { @@ -740,9 +689,7 @@ export class SingleStoreDialect { joinOn, nestedQueryRelation: relation, }); - const field = sql`coalesce(${sql.identifier(relationTableAlias)}.${sql.identifier('data')}, "[]")`.as( - selectedRelationTsKey, - ); + const field = sql`${sql.identifier(relationTableAlias)}.${sql.identifier('data')}`.as(selectedRelationTsKey); joins.push({ on: sql`true`, table: new Subquery(builtRelation.sql as SQL, {}, relationTableAlias), @@ -772,12 +719,12 @@ export class SingleStoreDialect { if (nestedQueryRelation) { let field = sql`JSON_BUILD_OBJECT(${ sql.join( - selection.map(({ field, tsKey, isJson }, index) => + selection.map(({ field, tsKey, isJson }) => isJson - ? sql`${index}, ${sql.identifier(`${tableAlias}_${tsKey}`)}.${sql.identifier('data')}` + ? sql`${sql.identifier(`${tableAlias}_${tsKey}`)}.${sql.identifier('data')}` : is(field, SQL.Aliased) - ? sql`${index}, ${field.sql}` - : sql`${index}, ${field}` + ? field.sql + : field ), sql`, `, ) diff --git a/drizzle-orm/src/singlestore-core/index.ts b/drizzle-orm/src/singlestore-core/index.ts index 4da014404..4e7d4268e 100644 --- a/drizzle-orm/src/singlestore-core/index.ts +++ b/drizzle-orm/src/singlestore-core/index.ts @@ -7,10 +7,9 @@ export * from './primary-keys.ts'; export * from './query-builders/index.ts'; export * from './schema.ts'; export * from './session.ts'; -export * from './sql/index.ts'; export * from './subquery.ts'; export * from './table.ts'; export * from './unique-constraint.ts'; export * from './utils.ts'; -export * from './view-common.ts'; -export * from './view.ts'; +/* export * from './view-common.ts'; +export * from './view.ts'; */ diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts index 172f524f5..3120cab1b 100644 --- a/drizzle-orm/src/singlestore-core/indexes.ts +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -45,10 +45,6 @@ export interface AnyIndexBuilder { build(table: SingleStoreTable): Index; } -export interface AnyFullTextIndexBuilder { - build(table: SingleStoreTable): FullTextIndex; -} - // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface IndexBuilder extends AnyIndexBuilder {} @@ -111,6 +107,10 @@ export function uniqueIndex(name: string): IndexBuilderOn { return new IndexBuilderOn(name, true); } +/* export interface AnyFullTextIndexBuilder { + build(table: SingleStoreTable): FullTextIndex; +} */ +/* interface FullTextIndexConfig { version?: number; } @@ -133,22 +133,23 @@ export class FullTextIndexBuilderOn { ...this.config, }); } -} +} */ +/* export interface FullTextIndexBuilder extends AnyFullTextIndexBuilder {} export class FullTextIndexBuilder implements AnyFullTextIndexBuilder { - static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilder'; + static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilder'; */ - /** @internal */ - config: FullTextIndexFullConfig; +/** @internal */ +/* config: FullTextIndexFullConfig; constructor(config: FullTextIndexFullConfig) { this.config = config; - } + } */ - /** @internal */ - build(table: SingleStoreTable): FullTextIndex { +/** @internal */ +/* build(table: SingleStoreTable): FullTextIndex { return new FullTextIndex(this.config, table); } } @@ -172,10 +173,10 @@ export type SortKeyColumn = SingleStoreColumn | SQL; export class SortKeyBuilder { static readonly [entityKind]: string = 'SingleStoreSortKeyBuilder'; - constructor(private columns: SortKeyColumn[]) {} + constructor(private columns: SortKeyColumn[]) {} */ - /** @internal */ - build(table: SingleStoreTable): SortKey { +/** @internal */ +/* build(table: SingleStoreTable): SortKey { return new SortKey(this.columns, table); } } @@ -189,3 +190,4 @@ export class SortKey { export function sortKey(...columns: SortKeyColumn[]): SortKeyBuilder { return new SortKeyBuilder(columns); } + */ diff --git a/drizzle-orm/src/singlestore-core/query-builders/index.ts b/drizzle-orm/src/singlestore-core/query-builders/index.ts index 5963612e0..704cb4afa 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/index.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/index.ts @@ -1,10 +1,10 @@ -export * from './attach.ts'; +/* export * from './attach.ts'; export * from './branch.ts'; -export * from './createMilestone.ts'; +export * from './createMilestone.ts'; */ export * from './delete.ts'; -export * from './detach.ts'; +/* export * from './detach.ts'; */ export * from './insert.ts'; -export * from './optimizeTable.ts'; +/* export * from './optimizeTable.ts'; */ export * from './query-builder.ts'; export * from './select.ts'; export * from './select.types.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/insert.ts b/drizzle-orm/src/singlestore-core/query-builders/insert.ts index 78a19c784..84a72fdab 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/insert.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/insert.ts @@ -219,7 +219,7 @@ export class SingleStoreInsertBase< /** * Adds an `on duplicate key update` clause to the query. * - * Calling this method will update update the row if any unique index conflicts. SingleStore will automatically determine the conflict target based on the primary key and unique indexes. + * Calling this method will update update the row if any unique index conflicts. MySQL will automatically determine the conflict target based on the primary key and unique indexes. * * See docs: {@link https://orm.drizzle.team/docs/insert#on-duplicate-key-update} * @@ -232,7 +232,7 @@ export class SingleStoreInsertBase< * .onDuplicateKeyUpdate({ set: { brand: 'Porsche' }}); * ``` * - * While SingleStore does not directly support doing nothing on conflict, you can perform a no-op by setting any column's value to itself and achieve the same effect: + * While MySQL does not directly support doing nothing on conflict, you can perform a no-op by setting any column's value to itself and achieve the same effect: * * ```ts * import { sql } from 'drizzle-orm'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/query.ts b/drizzle-orm/src/singlestore-core/query-builders/query.ts index c15f7ad59..b42fb4f39 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/query.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/query.ts @@ -12,6 +12,7 @@ import type { Query, QueryWithTypings, SQL } from '~/sql/sql.ts'; import type { KnownKeysOnly } from '~/utils.ts'; import type { SingleStoreDialect } from '../dialect.ts'; import type { + Mode, PreparedQueryHKTBase, PreparedQueryKind, SingleStorePreparedQueryConfig, @@ -34,6 +35,7 @@ export class RelationalQueryBuilder< private tableConfig: TableRelationalConfig, private dialect: SingleStoreDialect, private session: SingleStoreSession, + private mode: Mode, ) {} findMany>( @@ -49,6 +51,7 @@ export class RelationalQueryBuilder< this.session, config ? (config as DBQueryConfig<'many', true>) : {}, 'many', + this.mode, ); } @@ -65,6 +68,7 @@ export class RelationalQueryBuilder< this.session, config ? { ...(config as DBQueryConfig<'many', true> | undefined), limit: 1 } : { limit: 1 }, 'first', + this.mode, ); } } @@ -87,6 +91,7 @@ export class SingleStoreRelationalQuery< private session: SingleStoreSession, private config: DBQueryConfig<'many', true> | true, private queryMode: 'many' | 'first', + private mode?: Mode, ) { super(); } diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.ts b/drizzle-orm/src/singlestore-core/query-builders/select.ts index 0fcefaf85..36a3893a2 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.ts @@ -22,7 +22,7 @@ import type { import type { SubqueryWithSelection } from '~/singlestore-core/subquery.ts'; import type { SingleStoreTable } from '~/singlestore-core/table.ts'; import type { ColumnsSelection, Query } from '~/sql/sql.ts'; -import { SQL, View } from '~/sql/sql.ts'; +import { SQL } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; import { @@ -33,8 +33,6 @@ import { orderSelectedFields, type ValueOrArray, } from '~/utils.ts'; -import { ViewBaseConfig } from '~/view-common.ts'; -import { SingleStoreViewBase } from '../view-base.ts'; import type { AnySingleStoreSelect, CreateSingleStoreSelectFromBuilderMode, @@ -86,7 +84,7 @@ export class SingleStoreSelectBuilder< this.distinct = config.distinct; } - from( + from( // | SingleStoreViewBase source: TFrom, ): CreateSingleStoreSelectFromBuilderMode< TBuilderMode, @@ -107,8 +105,8 @@ export class SingleStoreSelectBuilder< key, ) => [key, source[key as unknown as keyof typeof source] as unknown as SelectedFields[string]]), ); - } else if (is(source, SingleStoreViewBase)) { - fields = source[ViewBaseConfig].selectedFields as SelectedFields; + /* } else if (is(source, SingleStoreViewBase)) { + fields = source[ViewBaseConfig].selectedFields as SelectedFields; */ } else if (is(source, SQL)) { fields = {}; } else { @@ -198,7 +196,7 @@ export abstract class SingleStoreSelectQueryBuilderBase< joinType: TJoinType, ): SingleStoreJoinFn { return ( - table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL, + table: SingleStoreTable | Subquery | SQL, // | SingleStoreViewBase on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, ) => { const baseTableName = this.tableName; @@ -218,8 +216,8 @@ export abstract class SingleStoreSelectQueryBuilderBase< if (typeof tableName === 'string' && !is(table, SQL)) { const selection = is(table, Subquery) ? table._.selectedFields - : is(table, View) - ? table[ViewBaseConfig].selectedFields + /* : is(table, View) + ? table[ViewBaseConfig].selectedFields */ : table[Table.Symbol.Columns]; this.config.fields[tableName] = selection; } diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts index 6db1cc357..e36a0f154 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts @@ -23,13 +23,13 @@ import type { Subquery } from '~/subquery.ts'; import type { Table, UpdateTableConfig } from '~/table.ts'; import type { Assume, ValidateShape } from '~/utils.ts'; import type { PreparedQueryHKTBase, PreparedQueryKind, SingleStorePreparedQueryConfig } from '../session.ts'; -import type { SingleStoreViewBase } from '../view-base.ts'; +/* import type { SingleStoreViewBase } from '../view-base.ts'; */ import type { SingleStoreViewWithSelection } from '../view.ts'; import type { SingleStoreSelectBase, SingleStoreSelectQueryBuilderBase } from './select.ts'; export interface SingleStoreSelectJoinConfig { on: SQL | undefined; - table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL; + table: SingleStoreTable | Subquery | SQL; // SingleStoreViewBase | alias: string | undefined; joinType: JoinType; lateral?: boolean; @@ -55,7 +55,7 @@ export interface SingleStoreSelectConfig { fieldsFlat?: SelectedFieldsOrdered; where?: SQL; having?: SQL; - table: SingleStoreTable | Subquery | SingleStoreViewBase | SQL; + table: SingleStoreTable | Subquery | SQL; // | SingleStoreViewBase limit?: number | Placeholder; offset?: number | Placeholder; joins?: SingleStoreSelectJoinConfig[]; @@ -80,7 +80,7 @@ export type SingleStoreJoin< T extends AnySingleStoreSelectQueryBuilder, TDynamic extends boolean, TJoinType extends JoinType, - TJoinedTable extends SingleStoreTable | Subquery | SingleStoreViewBase | SQL, + TJoinedTable extends SingleStoreTable | Subquery | SQL, // | SingleStoreViewBase TJoinedName extends GetSelectTableName = GetSelectTableName, > = T extends any ? SingleStoreSelectWithout< SingleStoreSelectKind< @@ -111,7 +111,7 @@ export type SingleStoreJoinFn< TDynamic extends boolean, TJoinType extends JoinType, > = < - TJoinedTable extends SingleStoreTable | Subquery | SingleStoreViewBase | SQL, + TJoinedTable extends SingleStoreTable | Subquery | SQL, // | SingleStoreViewBase TJoinedName extends GetSelectTableName = GetSelectTableName, >( table: TJoinedTable, diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts index 82da44a49..ea7a53924 100644 --- a/drizzle-orm/src/singlestore-core/schema.ts +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -1,6 +1,6 @@ import { entityKind, is } from '~/entity.ts'; import { type SingleStoreTableFn, singlestoreTableWithSchema } from './table.ts'; -import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; +/* import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; */ export class SingleStoreSchema { static readonly [entityKind]: string = 'SingleStoreSchema'; @@ -12,10 +12,10 @@ export class SingleStoreSchema { table: SingleStoreTableFn = (name, columns, extraConfig) => { return singlestoreTableWithSchema(name, columns, extraConfig, this.schemaName); }; - + /* view = ((name, columns) => { return singlestoreViewWithSchema(name, columns, this.schemaName); - }) as typeof singlestoreView; + }) as typeof singlestoreView; */ } /** @deprecated - use `instanceof SingleStoreSchema` */ @@ -25,8 +25,7 @@ export function isSingleStoreSchema(obj: unknown): obj is SingleStoreSchema { /** * Create a SingleStore schema. - * https://dev.mysql.com/doc/refman/8.0/en/create-database.html - * TODO(singlestore) + * https://docs.singlestore.com/cloud/create-a-database/ * * @param name singlestore use schema name * @returns SingleStore schema diff --git a/drizzle-orm/src/singlestore-core/session.ts b/drizzle-orm/src/singlestore-core/session.ts index 1b7f076d6..78d477a27 100644 --- a/drizzle-orm/src/singlestore-core/session.ts +++ b/drizzle-orm/src/singlestore-core/session.ts @@ -7,7 +7,7 @@ import { SingleStoreDatabase } from './db.ts'; import type { SingleStoreDialect } from './dialect.ts'; import type { SelectedFieldsOrdered } from './query-builders/select.types.ts'; -export type Mode = 'default' | 'planetscale'; +export type Mode = 'default'; export interface SingleStoreQueryResultHKT { readonly $brand: 'SingleStoreQueryResultHKT'; @@ -56,7 +56,7 @@ export abstract class SingleStorePreparedQuery | undefined, protected readonly nestedIndex: number, + mode: Mode, ) { - super(dialect, session, schema); + super(dialect, session, schema, mode); } rollback(): never { diff --git a/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts b/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts deleted file mode 100644 index 95cffabdd..000000000 --- a/drizzle-orm/src/singlestore-core/sql/expressions/conditions.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { bindIfParam } from '~/sql/expressions/conditions.ts'; -import { type SQL, sql } from '~/sql/sql.ts'; -import type { Table } from '~/table'; - -/** - * Test that two values match. - * - * ## Examples - * - * ```ts - * // Select cars made by Ford - * db.select().from(cars) - * .where(match(cars.make, 'Ford')) - * ``` - * - * @see isNull for a way to test equality to NULL. - */ -export function match< - TTable extends Table, ->(left: TTable, right: unknown): SQL { - return sql`MATCH (TABLE ${left}) AGAINST (${bindIfParam(right, left)})`; -} diff --git a/drizzle-orm/src/singlestore-core/sql/expressions/index.ts b/drizzle-orm/src/singlestore-core/sql/expressions/index.ts deleted file mode 100644 index 81cb13770..000000000 --- a/drizzle-orm/src/singlestore-core/sql/expressions/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './conditions.ts'; diff --git a/drizzle-orm/src/singlestore-core/sql/index.ts b/drizzle-orm/src/singlestore-core/sql/index.ts deleted file mode 100644 index 16ca76679..000000000 --- a/drizzle-orm/src/singlestore-core/sql/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './expressions/index.ts'; diff --git a/drizzle-orm/src/singlestore-core/utils.ts b/drizzle-orm/src/singlestore-core/utils.ts index e6412161d..634b4e261 100644 --- a/drizzle-orm/src/singlestore-core/utils.ts +++ b/drizzle-orm/src/singlestore-core/utils.ts @@ -1,14 +1,13 @@ import { is } from '~/entity.ts'; import { Table } from '~/table.ts'; -import { ViewBaseConfig } from '~/view-common.ts'; import type { Index } from './indexes.ts'; import { IndexBuilder } from './indexes.ts'; import type { PrimaryKey } from './primary-keys.ts'; import { PrimaryKeyBuilder } from './primary-keys.ts'; import { SingleStoreTable } from './table.ts'; import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; -import { SingleStoreViewConfig } from './view-common.ts'; -import type { SingleStoreView } from './view.ts'; +/* import { SingleStoreViewConfig } from './view-common.ts'; +import type { SingleStoreView } from './view.ts'; */ export function getTableConfig(table: SingleStoreTable) { const columns = Object.values(table[SingleStoreTable.Symbol.Columns]); @@ -45,7 +44,7 @@ export function getTableConfig(table: SingleStoreTable) { }; } -export function getViewConfig< +/* export function getViewConfig< TName extends string = string, TExisting extends boolean = boolean, >(view: SingleStoreView) { @@ -53,4 +52,4 @@ export function getViewConfig< ...view[ViewBaseConfig], ...view[SingleStoreViewConfig], }; -} +} */ From 9e591e60b112f1af302433f9672d59ae873f4a79 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 13 Nov 2024 02:37:22 +0000 Subject: [PATCH 343/492] update singlestore-driver --- drizzle-orm/src/singlestore/driver.ts | 136 ++++++++++++++++++++----- drizzle-orm/src/singlestore/session.ts | 35 +++---- 2 files changed, 126 insertions(+), 45 deletions(-) diff --git a/drizzle-orm/src/singlestore/driver.ts b/drizzle-orm/src/singlestore/driver.ts index ffc5c2795..9d5ee2575 100644 --- a/drizzle-orm/src/singlestore/driver.ts +++ b/drizzle-orm/src/singlestore/driver.ts @@ -1,30 +1,28 @@ -import type { Connection as CallbackConnection, Pool as CallbackPool } from 'mysql2'; +import { type Connection as CallbackConnection, createPool, type Pool as CallbackPool, type PoolOptions } from 'mysql2'; +import type { Connection, Pool } from 'mysql2/promise'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; +import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { Mode } from '~/singlestore-core/session.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; -import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; -import type { DrizzleConfig } from '~/utils.ts'; -import type { - Mode, - SingleStoreDriverClient, - SingleStoreDriverPreparedQueryHKT, - SingleStoreDriverQueryResultHKT, -} from './session.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { DrizzleError } from '../errors.ts'; +import type { SingleStoreDriverClient, SingleStoreDriverPreparedQueryHKT, SingleStoreDriverQueryResultHKT } from './session.ts'; import { SingleStoreDriverSession } from './session.ts'; export interface SingleStoreDriverOptions { logger?: Logger; } -export class SingleStoreDriver { - static readonly [entityKind]: string = 'SingleStoreDriver'; +export class SingleStoreDriverDriver { + static readonly [entityKind]: string = 'SingleStoreDriverDriver'; constructor( private client: SingleStoreDriverClient, @@ -35,38 +33,52 @@ export class SingleStoreDriver { createSession( schema: RelationalSchemaConfig | undefined, + mode: Mode, ): SingleStoreDriverSession, TablesRelationalConfig> { - return new SingleStoreDriverSession(this.client, this.dialect, schema, { logger: this.options.logger }); + return new SingleStoreDriverSession(this.client, this.dialect, schema, { logger: this.options.logger, mode }); } } export { SingleStoreDatabase } from '~/singlestore-core/db.ts'; -export type SingleStoreDriverDatabase< +export class SingleStoreDriverDatabase< TSchema extends Record = Record, -> = SingleStoreDatabase; +> extends SingleStoreDatabase { + static override readonly [entityKind]: string = 'SingleStoreDriverDatabase'; +} export type SingleStoreDriverDrizzleConfig = Record> = & Omit, 'schema'> & ({ schema: TSchema; mode: Mode } | { schema?: undefined; mode?: Mode }); -export function drizzle = Record>( - client: SingleStoreDriverClient | CallbackConnection | CallbackPool, - config: DrizzleConfig = {}, -): SingleStoreDriverDatabase { - const dialect = new SingleStoreDialect(); +function construct< + TSchema extends Record = Record, + TClient extends Pool | Connection | CallbackPool | CallbackConnection = CallbackPool, +>( + client: TClient, + config: SingleStoreDriverDrizzleConfig = {}, +): SingleStoreDriverDatabase & { + $client: TClient; +} { + const dialect = new SingleStoreDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); } else if (config.logger !== false) { logger = config.logger; } - if (isCallbackClient(client)) { - client = client.promise(); - } + + const clientForInstance = isCallbackClient(client) ? client.promise() : client; let schema: RelationalSchemaConfig | undefined; if (config.schema) { + if (config.mode === undefined) { + throw new DrizzleError({ + message: + 'You need to specify "mode": "planetscale" or "default" when providing a schema. Read more: https://orm.drizzle.team/docs/rqb#modes', + }); + } + const tablesConfig = extractTablesRelationalConfig( config.schema, createTableRelationsHelpers, @@ -78,9 +90,14 @@ export function drizzle = Record; + const mode = config.mode ?? 'default'; + + const driver = new SingleStoreDriverDriver(clientForInstance as SingleStoreDriverClient, dialect, { logger }); + const session = driver.createSession(schema, mode); + const db = new SingleStoreDriverDatabase(dialect, session, schema as any, mode) as SingleStoreDriverDatabase; + ( db).$client = client; + + return db as any; } interface CallbackClient { @@ -90,3 +107,70 @@ interface CallbackClient { function isCallbackClient(client: any): client is CallbackClient { return typeof client.promise === 'function'; } + +export type AnySingleStoreDriverConnection = Pool | Connection | CallbackPool | CallbackConnection; + +export function drizzle< + TSchema extends Record = Record, + TClient extends AnySingleStoreDriverConnection = CallbackPool, +>( + ...params: IfNotImported< + CallbackPool, + [ImportTypeError<'singlestore'>], + [ + TClient | string, + ] | [ + TClient | string, + SingleStoreDriverDrizzleConfig, + ] | [ + ( + & SingleStoreDriverDrizzleConfig + & ({ + connection: string | PoolOptions; + } | { + client: TClient; + }) + ), + ] + > +): SingleStoreDriverDatabase & { + $client: TClient; +} { + if (typeof params[0] === 'string') { + const connectionString = params[0]!; + const instance = createPool({ + uri: connectionString, + }); + + return construct(instance, params[1]) as any; + } + + if (isConfig(params[0])) { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: PoolOptions | string; client?: TClient } + & SingleStoreDriverDrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' + ? createPool({ + uri: connection, + }) + : createPool(connection!); + const db = construct(instance, drizzleConfig); + + return db as any; + } + + return construct(params[0] as TClient, params[1] as SingleStoreDriverDrizzleConfig | undefined) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: SingleStoreDriverDrizzleConfig, + ): SingleStoreDriverDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/singlestore/session.ts b/drizzle-orm/src/singlestore/session.ts index dea4c1d7f..c05e7f5ba 100644 --- a/drizzle-orm/src/singlestore/session.ts +++ b/drizzle-orm/src/singlestore/session.ts @@ -18,6 +18,7 @@ import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; import type { SelectedFieldsOrdered } from '~/singlestore-core/query-builders/select.types.ts'; import { + type Mode, type PreparedQueryKind, SingleStorePreparedQuery, type SingleStorePreparedQueryConfig, @@ -27,13 +28,10 @@ import { SingleStoreTransaction, type SingleStoreTransactionConfig, } from '~/singlestore-core/session.ts'; -import { fillPlaceholders, sql } from '~/sql/sql.ts'; import type { Query, SQL } from '~/sql/sql.ts'; +import { fillPlaceholders, sql } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; -// must keep this type here for compatibility with DrizzleConfig -export type Mode = 'default'; - export type SingleStoreDriverClient = Pool | Connection; export type SingleStoreRawQueryResult = [ResultSetHeader, FieldPacket[]]; @@ -42,9 +40,7 @@ export type SingleStoreQueryResult< T = any, > = [T extends ResultSetHeader ? T : T[], FieldPacket[]]; -export class SingleStoreDriverPreparedQuery - extends SingleStorePreparedQuery -{ +export class SingleStoreDriverPreparedQuery extends SingleStorePreparedQuery { static override readonly [entityKind]: string = 'SingleStoreDriverPreparedQuery'; private rawQuery: QueryOptions; @@ -63,9 +59,8 @@ export class SingleStoreDriverPreparedQuery( @@ -272,8 +270,13 @@ export class SingleStoreDriverSession< session as SingleStoreSession, this.schema, 0, + this.mode, ); if (config) { + const setTransactionConfigSql = this.getSetTransactionSQL(config); + if (setTransactionConfigSql) { + await tx.execute(setTransactionConfigSql); + } const startTransactionSql = this.getStartTransactionSQL(config); await (startTransactionSql ? tx.execute(startTransactionSql) : tx.execute(sql`begin`)); } else { @@ -297,23 +300,17 @@ export class SingleStoreDriverSession< export class SingleStoreDriverTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, -> extends SingleStoreTransaction< - SingleStoreDriverQueryResultHKT, - SingleStoreDriverPreparedQueryHKT, - TFullSchema, - TSchema -> { +> extends SingleStoreTransaction { static override readonly [entityKind]: string = 'SingleStoreDriverTransaction'; - override async transaction( - transaction: (tx: SingleStoreDriverTransaction) => Promise, - ): Promise { + override async transaction(transaction: (tx: SingleStoreDriverTransaction) => Promise): Promise { const savepointName = `sp${this.nestedIndex + 1}`; const tx = new SingleStoreDriverTransaction( this.dialect, this.session, this.schema, this.nestedIndex + 1, + this.mode, ); await tx.execute(sql.raw(`savepoint ${savepointName}`)); try { From c9f780c12b2720de4814b002bb4fa7e19447c7a0 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 13 Nov 2024 02:40:14 +0000 Subject: [PATCH 344/492] update singlestore-proxy --- drizzle-orm/src/singlestore-proxy/driver.ts | 13 +++++++++---- drizzle-orm/src/singlestore-proxy/session.ts | 2 +- drizzle-orm/src/singlestore/driver.ts | 12 ++++++++---- drizzle-orm/src/singlestore/session.ts | 15 ++++++++++++--- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/drizzle-orm/src/singlestore-proxy/driver.ts b/drizzle-orm/src/singlestore-proxy/driver.ts index f54180c66..6752dedb7 100644 --- a/drizzle-orm/src/singlestore-proxy/driver.ts +++ b/drizzle-orm/src/singlestore-proxy/driver.ts @@ -1,3 +1,4 @@ +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { createTableRelationsHelpers, @@ -14,9 +15,11 @@ import { SingleStoreRemoteSession, } from './session.ts'; -export type SingleStoreRemoteDatabase< +export class SingleStoreRemoteDatabase< TSchema extends Record = Record, -> = SingleStoreDatabase; +> extends SingleStoreDatabase { + static override readonly [entityKind]: string = 'SingleStoreRemoteDatabase'; +} export type RemoteCallback = ( sql: string, @@ -28,7 +31,7 @@ export function drizzle = Record = {}, ): SingleStoreRemoteDatabase { - const dialect = new SingleStoreDialect(); + const dialect = new SingleStoreDialect({ casing: config.casing }); let logger; if (config.logger === true) { logger = new DefaultLogger(); @@ -50,5 +53,7 @@ export function drizzle = Record; + return new SingleStoreRemoteDatabase(dialect, session, schema as any, 'default') as SingleStoreRemoteDatabase< + TSchema + >; } diff --git a/drizzle-orm/src/singlestore-proxy/session.ts b/drizzle-orm/src/singlestore-proxy/session.ts index f7b404860..42cc8ecde 100644 --- a/drizzle-orm/src/singlestore-proxy/session.ts +++ b/drizzle-orm/src/singlestore-proxy/session.ts @@ -15,8 +15,8 @@ import type { SingleStoreTransactionConfig, } from '~/singlestore-core/session.ts'; import { SingleStorePreparedQuery as PreparedQueryBase, SingleStoreSession } from '~/singlestore-core/session.ts'; -import { fillPlaceholders } from '~/sql/sql.ts'; import type { Query, SQL } from '~/sql/sql.ts'; +import { fillPlaceholders } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; import type { RemoteCallback } from './driver.ts'; diff --git a/drizzle-orm/src/singlestore/driver.ts b/drizzle-orm/src/singlestore/driver.ts index 9d5ee2575..b413a5ebc 100644 --- a/drizzle-orm/src/singlestore/driver.ts +++ b/drizzle-orm/src/singlestore/driver.ts @@ -3,18 +3,22 @@ import type { Connection, Pool } from 'mysql2/promise'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; -import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; -import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; -import type { Mode } from '~/singlestore-core/session.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; +import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { Mode } from '~/singlestore-core/session.ts'; import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; import { DrizzleError } from '../errors.ts'; -import type { SingleStoreDriverClient, SingleStoreDriverPreparedQueryHKT, SingleStoreDriverQueryResultHKT } from './session.ts'; +import type { + SingleStoreDriverClient, + SingleStoreDriverPreparedQueryHKT, + SingleStoreDriverQueryResultHKT, +} from './session.ts'; import { SingleStoreDriverSession } from './session.ts'; export interface SingleStoreDriverOptions { diff --git a/drizzle-orm/src/singlestore/session.ts b/drizzle-orm/src/singlestore/session.ts index c05e7f5ba..f5868cb70 100644 --- a/drizzle-orm/src/singlestore/session.ts +++ b/drizzle-orm/src/singlestore/session.ts @@ -40,7 +40,9 @@ export type SingleStoreQueryResult< T = any, > = [T extends ResultSetHeader ? T : T[], FieldPacket[]]; -export class SingleStoreDriverPreparedQuery extends SingleStorePreparedQuery { +export class SingleStoreDriverPreparedQuery + extends SingleStorePreparedQuery +{ static override readonly [entityKind]: string = 'SingleStoreDriverPreparedQuery'; private rawQuery: QueryOptions; @@ -300,10 +302,17 @@ export class SingleStoreDriverSession< export class SingleStoreDriverTransaction< TFullSchema extends Record, TSchema extends TablesRelationalConfig, -> extends SingleStoreTransaction { +> extends SingleStoreTransaction< + SingleStoreDriverQueryResultHKT, + SingleStoreDriverPreparedQueryHKT, + TFullSchema, + TSchema +> { static override readonly [entityKind]: string = 'SingleStoreDriverTransaction'; - override async transaction(transaction: (tx: SingleStoreDriverTransaction) => Promise): Promise { + override async transaction( + transaction: (tx: SingleStoreDriverTransaction) => Promise, + ): Promise { const savepointName = `sp${this.nestedIndex + 1}`; const tx = new SingleStoreDriverTransaction( this.dialect, From d167aa8ca42ade725ba81349c65fd57aee38063e Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 13 Nov 2024 03:33:31 +0000 Subject: [PATCH 345/492] cleaning singlestore drizzle-orm and passing tests --- .../src/singlestore-core/columns/bigint.ts | 11 +- .../src/singlestore-core/columns/binary.ts | 7 +- .../src/singlestore-core/columns/boolean.ts | 7 +- .../src/singlestore-core/columns/char.ts | 7 +- .../src/singlestore-core/columns/common.ts | 7 +- .../src/singlestore-core/columns/custom.ts | 6 +- .../src/singlestore-core/columns/date.ts | 11 +- .../src/singlestore-core/columns/datetime.ts | 11 +- .../src/singlestore-core/columns/decimal.ts | 7 +- .../src/singlestore-core/columns/double.ts | 7 +- .../src/singlestore-core/columns/enum.ts | 7 +- .../src/singlestore-core/columns/float.ts | 7 +- .../src/singlestore-core/columns/int.ts | 7 +- .../src/singlestore-core/columns/json.ts | 7 +- .../src/singlestore-core/columns/mediumint.ts | 7 +- .../src/singlestore-core/columns/real.ts | 7 +- .../src/singlestore-core/columns/serial.ts | 7 + .../src/singlestore-core/columns/smallint.ts | 7 +- .../src/singlestore-core/columns/text.ts | 7 +- .../src/singlestore-core/columns/time.ts | 7 +- .../src/singlestore-core/columns/timestamp.ts | 11 +- .../src/singlestore-core/columns/tinyint.ts | 7 +- .../src/singlestore-core/columns/varbinary.ts | 7 +- .../src/singlestore-core/columns/varchar.ts | 7 +- .../src/singlestore-core/columns/year.ts | 7 +- .../singlestore-core/query-builders/attach.ts | 198 ------------------ .../singlestore-core/query-builders/branch.ts | 186 ---------------- .../query-builders/createMilestone.ts | 136 ------------ .../singlestore-core/query-builders/detach.ts | 172 --------------- .../query-builders/dropMilestone.ts | 136 ------------ .../query-builders/optimizeTable.ts | 158 -------------- drizzle-orm/type-tests/singlestore/count.ts | 61 ++++++ drizzle-orm/type-tests/singlestore/db.ts | 4 +- drizzle-orm/type-tests/singlestore/delete.ts | 4 + .../singlestore/generated-columns.ts | 158 -------------- drizzle-orm/type-tests/singlestore/select.ts | 7 +- .../type-tests/singlestore/set-operators.ts | 22 +- drizzle-orm/type-tests/singlestore/tables.ts | 19 +- drizzle-orm/type-tests/singlestore/update.ts | 4 + drizzle-orm/type-tests/singlestore/with.ts | 4 +- 40 files changed, 268 insertions(+), 1191 deletions(-) delete mode 100644 drizzle-orm/src/singlestore-core/query-builders/attach.ts delete mode 100644 drizzle-orm/src/singlestore-core/query-builders/branch.ts delete mode 100644 drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts delete mode 100644 drizzle-orm/src/singlestore-core/query-builders/detach.ts delete mode 100644 drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts delete mode 100644 drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts create mode 100644 drizzle-orm/type-tests/singlestore/count.ts delete mode 100644 drizzle-orm/type-tests/singlestore/generated-columns.ts diff --git a/drizzle-orm/src/singlestore-core/columns/bigint.ts b/drizzle-orm/src/singlestore-core/columns/bigint.ts index 1e6b64c49..b0e0c0ea2 100644 --- a/drizzle-orm/src/singlestore-core/columns/bigint.ts +++ b/drizzle-orm/src/singlestore-core/columns/bigint.ts @@ -1,9 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreBigInt53BuilderInitial = SingleStoreBigInt53Builder<{ name: TName; @@ -18,6 +19,10 @@ export type SingleStoreBigInt53BuilderInitial = SingleStor export class SingleStoreBigInt53Builder> extends SingleStoreColumnBuilderWithAutoIncrement { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreBigInt53Builder'; constructor(name: T['name'], unsigned: boolean = false) { @@ -66,6 +71,10 @@ export type SingleStoreBigInt64BuilderInitial = SingleStor export class SingleStoreBigInt64Builder> extends SingleStoreColumnBuilderWithAutoIncrement { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreBigInt64Builder'; constructor(name: T['name'], unsigned: boolean = false) { diff --git a/drizzle-orm/src/singlestore-core/columns/binary.ts b/drizzle-orm/src/singlestore-core/columns/binary.ts index 153456447..45cdf7743 100644 --- a/drizzle-orm/src/singlestore-core/columns/binary.ts +++ b/drizzle-orm/src/singlestore-core/columns/binary.ts @@ -1,9 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreBinaryBuilderInitial = SingleStoreBinaryBuilder<{ name: TName; @@ -21,6 +22,10 @@ export class SingleStoreBinaryBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreBinaryBuilder'; constructor(name: T['name'], length: number | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/boolean.ts b/drizzle-orm/src/singlestore-core/columns/boolean.ts index bf48ff1da..f6df9c3fa 100644 --- a/drizzle-orm/src/singlestore-core/columns/boolean.ts +++ b/drizzle-orm/src/singlestore-core/columns/boolean.ts @@ -1,8 +1,9 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreBooleanBuilderInitial = SingleStoreBooleanBuilder<{ name: TName; @@ -17,6 +18,10 @@ export type SingleStoreBooleanBuilderInitial = SingleStore export class SingleStoreBooleanBuilder> extends SingleStoreColumnBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreBooleanBuilder'; constructor(name: T['name']) { diff --git a/drizzle-orm/src/singlestore-core/columns/char.ts b/drizzle-orm/src/singlestore-core/columns/char.ts index 512460f92..8bcb36fa6 100644 --- a/drizzle-orm/src/singlestore-core/columns/char.ts +++ b/drizzle-orm/src/singlestore-core/columns/char.ts @@ -1,9 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreCharBuilderInitial = SingleStoreCharBuilder<{ @@ -22,6 +23,10 @@ export class SingleStoreCharBuilder > { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreCharBuilder'; constructor(name: T['name'], config: SingleStoreCharConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts index 6ccd64f1e..2c4d6528a 100644 --- a/drizzle-orm/src/singlestore-core/columns/common.ts +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -5,7 +5,6 @@ import type { ColumnBuilderRuntimeConfig, ColumnDataType, HasDefault, - HasGenerated, IsAutoincrement, MakeColumnConfig, } from '~/column-builder.ts'; @@ -14,7 +13,6 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { Column } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable, SingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/sql.ts'; import type { Update } from '~/utils.ts'; import { uniqueKeyName } from '../unique-constraint.ts'; @@ -45,14 +43,15 @@ export abstract class SingleStoreColumnBuilder< return this; } - generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SingleStoreGeneratedColumnConfig): HasGenerated { + // TODO: Implement generated columns for SingleStore (https://docs.singlestore.com/cloud/create-a-database/using-persistent-computed-columns/) + /* generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SingleStoreGeneratedColumnConfig): HasGenerated { this.config.generated = { as, type: 'always', mode: config?.mode ?? 'virtual', }; return this as any; - } + } */ /** @internal */ abstract build( diff --git a/drizzle-orm/src/singlestore-core/columns/custom.ts b/drizzle-orm/src/singlestore-core/columns/custom.ts index 964e077d7..3a50bc328 100644 --- a/drizzle-orm/src/singlestore-core/columns/custom.ts +++ b/drizzle-orm/src/singlestore-core/columns/custom.ts @@ -1,4 +1,4 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; @@ -35,6 +35,10 @@ export class SingleStoreCustomColumnBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreCustomColumnBuilder'; constructor( diff --git a/drizzle-orm/src/singlestore-core/columns/date.ts b/drizzle-orm/src/singlestore-core/columns/date.ts index 70da74f3a..1940757aa 100644 --- a/drizzle-orm/src/singlestore-core/columns/date.ts +++ b/drizzle-orm/src/singlestore-core/columns/date.ts @@ -1,9 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreDateBuilderInitial = SingleStoreDateBuilder<{ name: TName; @@ -18,6 +19,10 @@ export type SingleStoreDateBuilderInitial = SingleStoreDat export class SingleStoreDateBuilder> extends SingleStoreColumnBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreDateBuilder'; constructor(name: T['name']) { @@ -67,6 +72,10 @@ export type SingleStoreDateStringBuilderInitial = SingleSt export class SingleStoreDateStringBuilder> extends SingleStoreColumnBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreDateStringBuilder'; constructor(name: T['name']) { diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts index a1aa8eba9..9cc359438 100644 --- a/drizzle-orm/src/singlestore-core/columns/datetime.ts +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -1,9 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreDateTimeBuilderInitial = SingleStoreDateTimeBuilder<{ name: TName; @@ -18,6 +19,10 @@ export type SingleStoreDateTimeBuilderInitial = SingleStor export class SingleStoreDateTimeBuilder> extends SingleStoreColumnBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreDateTimeBuilder'; constructor(name: T['name'], config: SingleStoreDatetimeConfig | undefined) { @@ -79,6 +84,10 @@ export type SingleStoreDateTimeStringBuilderInitial = Sing export class SingleStoreDateTimeStringBuilder> extends SingleStoreColumnBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreDateTimeStringBuilder'; constructor(name: T['name'], config: SingleStoreDatetimeConfig | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts index 980b8a5e9..2f452d1bd 100644 --- a/drizzle-orm/src/singlestore-core/columns/decimal.ts +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -1,9 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreDecimalBuilderInitial = SingleStoreDecimalBuilder<{ name: TName; @@ -18,6 +19,10 @@ export type SingleStoreDecimalBuilderInitial = SingleStore export class SingleStoreDecimalBuilder< T extends ColumnBuilderBaseConfig<'string', 'SingleStoreDecimal'>, > extends SingleStoreColumnBuilderWithAutoIncrement { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreDecimalBuilder'; constructor(name: T['name'], config: SingleStoreDecimalConfig | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/double.ts b/drizzle-orm/src/singlestore-core/columns/double.ts index 103731eab..919f5c893 100644 --- a/drizzle-orm/src/singlestore-core/columns/double.ts +++ b/drizzle-orm/src/singlestore-core/columns/double.ts @@ -1,9 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreDoubleBuilderInitial = SingleStoreDoubleBuilder<{ name: TName; @@ -18,6 +19,10 @@ export type SingleStoreDoubleBuilderInitial = SingleStoreD export class SingleStoreDoubleBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: T['data'] | SQL | (() => SQL), config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreDoubleBuilder'; constructor(name: T['name'], config: SingleStoreDoubleConfig | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/enum.ts b/drizzle-orm/src/singlestore-core/columns/enum.ts index 00b61393e..e8d62ede0 100644 --- a/drizzle-orm/src/singlestore-core/columns/enum.ts +++ b/drizzle-orm/src/singlestore-core/columns/enum.ts @@ -1,7 +1,8 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -19,6 +20,10 @@ export type SingleStoreEnumColumnBuilderInitial> extends SingleStoreColumnBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreEnumColumnBuilder'; constructor(name: T['name'], values: T['enumValues']) { diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts index 9cfed6131..08931505c 100644 --- a/drizzle-orm/src/singlestore-core/columns/float.ts +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -1,9 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreFloatBuilderInitial = SingleStoreFloatBuilder<{ name: TName; @@ -18,6 +19,10 @@ export type SingleStoreFloatBuilderInitial = SingleStoreFl export class SingleStoreFloatBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreFloatBuilder'; constructor(name: T['name'], config: SingleStoreFloatConfig | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/int.ts b/drizzle-orm/src/singlestore-core/columns/int.ts index b6a661f66..994148045 100644 --- a/drizzle-orm/src/singlestore-core/columns/int.ts +++ b/drizzle-orm/src/singlestore-core/columns/int.ts @@ -1,9 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreIntBuilderInitial = SingleStoreIntBuilder<{ name: TName; @@ -18,6 +19,10 @@ export type SingleStoreIntBuilderInitial = SingleStoreIntB export class SingleStoreIntBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreIntBuilder'; constructor(name: T['name'], config?: SingleStoreIntConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/json.ts b/drizzle-orm/src/singlestore-core/columns/json.ts index 97ff759d1..db00df33b 100644 --- a/drizzle-orm/src/singlestore-core/columns/json.ts +++ b/drizzle-orm/src/singlestore-core/columns/json.ts @@ -1,8 +1,9 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreJsonBuilderInitial = SingleStoreJsonBuilder<{ name: TName; @@ -17,6 +18,10 @@ export type SingleStoreJsonBuilderInitial = SingleStoreJso export class SingleStoreJsonBuilder> extends SingleStoreColumnBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: T['data'] | SQL | (() => SQL), config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreJsonBuilder'; constructor(name: T['name']) { diff --git a/drizzle-orm/src/singlestore-core/columns/mediumint.ts b/drizzle-orm/src/singlestore-core/columns/mediumint.ts index 4a5fa80f9..78aa23984 100644 --- a/drizzle-orm/src/singlestore-core/columns/mediumint.ts +++ b/drizzle-orm/src/singlestore-core/columns/mediumint.ts @@ -1,10 +1,11 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreMediumIntBuilderInitial = SingleStoreMediumIntBuilder<{ name: TName; @@ -19,6 +20,10 @@ export type SingleStoreMediumIntBuilderInitial = SingleSto export class SingleStoreMediumIntBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreMediumIntBuilder'; constructor(name: T['name'], config?: SingleStoreIntConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/real.ts b/drizzle-orm/src/singlestore-core/columns/real.ts index 53d15345c..fb099b483 100644 --- a/drizzle-orm/src/singlestore-core/columns/real.ts +++ b/drizzle-orm/src/singlestore-core/columns/real.ts @@ -1,9 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreRealBuilderInitial = SingleStoreRealBuilder<{ name: TName; @@ -21,6 +22,10 @@ export class SingleStoreRealBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreRealBuilder'; constructor(name: T['name'], config: SingleStoreRealConfig | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/serial.ts b/drizzle-orm/src/singlestore-core/columns/serial.ts index df415d47e..1bbf4cbbc 100644 --- a/drizzle-orm/src/singlestore-core/columns/serial.ts +++ b/drizzle-orm/src/singlestore-core/columns/serial.ts @@ -1,7 +1,9 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, HasDefault, + HasGenerated, IsAutoincrement, IsPrimaryKey, MakeColumnConfig, @@ -11,6 +13,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreSerialBuilderInitial = IsAutoincrement< IsPrimaryKey< @@ -33,6 +36,10 @@ export type SingleStoreSerialBuilderInitial = IsAutoincrem export class SingleStoreSerialBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreSerialBuilder'; constructor(name: T['name']) { diff --git a/drizzle-orm/src/singlestore-core/columns/smallint.ts b/drizzle-orm/src/singlestore-core/columns/smallint.ts index 3f504b68c..17177bc52 100644 --- a/drizzle-orm/src/singlestore-core/columns/smallint.ts +++ b/drizzle-orm/src/singlestore-core/columns/smallint.ts @@ -1,7 +1,8 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; @@ -19,6 +20,10 @@ export type SingleStoreSmallIntBuilderInitial = SingleStor export class SingleStoreSmallIntBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreSmallIntBuilder'; constructor(name: T['name'], config?: SingleStoreIntConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/text.ts b/drizzle-orm/src/singlestore-core/columns/text.ts index 425da550f..ede9f2f94 100644 --- a/drizzle-orm/src/singlestore-core/columns/text.ts +++ b/drizzle-orm/src/singlestore-core/columns/text.ts @@ -1,7 +1,8 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -24,6 +25,10 @@ export class SingleStoreTextBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreTextBuilder'; constructor(name: T['name'], textType: SingleStoreTextColumnType, config: SingleStoreTextConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/time.ts b/drizzle-orm/src/singlestore-core/columns/time.ts index be43041a7..27bcfe342 100644 --- a/drizzle-orm/src/singlestore-core/columns/time.ts +++ b/drizzle-orm/src/singlestore-core/columns/time.ts @@ -1,9 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import type { SQL } from '~/sql/index.ts'; export type SingleStoreTimeBuilderInitial = SingleStoreTimeBuilder<{ name: TName; @@ -21,6 +22,10 @@ export class SingleStoreTimeBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreTimeBuilder'; constructor( diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts index f269dad0f..ddd3dc695 100644 --- a/drizzle-orm/src/singlestore-core/columns/timestamp.ts +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -1,7 +1,8 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/sql.ts'; import { sql } from '~/sql/sql.ts'; import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreDateBaseColumn, SingleStoreDateColumnBaseBuilder } from './date.common.ts'; @@ -19,6 +20,10 @@ export type SingleStoreTimestampBuilderInitial = SingleSto export class SingleStoreTimestampBuilder> extends SingleStoreDateColumnBaseBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreTimestampBuilder'; constructor(name: T['name'], config: SingleStoreTimestampConfig | undefined) { @@ -76,6 +81,10 @@ export type SingleStoreTimestampStringBuilderInitial = Sin export class SingleStoreTimestampStringBuilder< T extends ColumnBuilderBaseConfig<'string', 'SingleStoreTimestampString'>, > extends SingleStoreDateColumnBaseBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreTimestampStringBuilder'; constructor(name: T['name'], config: SingleStoreTimestampConfig | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/tinyint.ts b/drizzle-orm/src/singlestore-core/columns/tinyint.ts index 090619a6d..ff822ea2f 100644 --- a/drizzle-orm/src/singlestore-core/columns/tinyint.ts +++ b/drizzle-orm/src/singlestore-core/columns/tinyint.ts @@ -1,7 +1,8 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; @@ -19,6 +20,10 @@ export type SingleStoreTinyIntBuilderInitial = SingleStore export class SingleStoreTinyIntBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreTinyIntBuilder'; constructor(name: T['name'], config?: SingleStoreIntConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/varbinary.ts b/drizzle-orm/src/singlestore-core/columns/varbinary.ts index c55aa8071..81188e15c 100644 --- a/drizzle-orm/src/singlestore-core/columns/varbinary.ts +++ b/drizzle-orm/src/singlestore-core/columns/varbinary.ts @@ -1,7 +1,8 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -18,6 +19,10 @@ export type SingleStoreVarBinaryBuilderInitial = SingleSto export class SingleStoreVarBinaryBuilder> extends SingleStoreColumnBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreVarBinaryBuilder'; /** @internal */ diff --git a/drizzle-orm/src/singlestore-core/columns/varchar.ts b/drizzle-orm/src/singlestore-core/columns/varchar.ts index 2c39491d7..a2282639e 100644 --- a/drizzle-orm/src/singlestore-core/columns/varchar.ts +++ b/drizzle-orm/src/singlestore-core/columns/varchar.ts @@ -1,7 +1,8 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -21,6 +22,10 @@ export type SingleStoreVarCharBuilderInitial> extends SingleStoreColumnBuilder> { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreVarCharBuilder'; /** @internal */ diff --git a/drizzle-orm/src/singlestore-core/columns/year.ts b/drizzle-orm/src/singlestore-core/columns/year.ts index 37f3d55a3..c9ddf24e8 100644 --- a/drizzle-orm/src/singlestore-core/columns/year.ts +++ b/drizzle-orm/src/singlestore-core/columns/year.ts @@ -1,7 +1,8 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreYearBuilderInitial = SingleStoreYearBuilder<{ @@ -17,6 +18,10 @@ export type SingleStoreYearBuilderInitial = SingleStoreYea export class SingleStoreYearBuilder> extends SingleStoreColumnBuilder { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + throw new Error('Method not implemented.'); + } static override readonly [entityKind]: string = 'SingleStoreYearBuilder'; constructor(name: T['name']) { diff --git a/drizzle-orm/src/singlestore-core/query-builders/attach.ts b/drizzle-orm/src/singlestore-core/query-builders/attach.ts deleted file mode 100644 index ca894ced1..000000000 --- a/drizzle-orm/src/singlestore-core/query-builders/attach.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { entityKind } from '~/entity.ts'; -import { DrizzleError } from '~/errors.ts'; -import { QueryPromise } from '~/query-promise.ts'; -import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; -import type { - AnySingleStoreQueryResultHKT, - PreparedQueryHKTBase, - PreparedQueryKind, - SingleStorePreparedQueryConfig, - SingleStoreQueryResultHKT, - SingleStoreQueryResultKind, - SingleStoreSession, -} from '~/singlestore-core/session.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; - -export type SingleStoreAttachWithout< - T extends AnySingleStoreAttachBase, - TDynamic extends boolean, - K extends keyof T & string, -> = TDynamic extends true ? T - : Omit< - SingleStoreAttachBase< - T['_']['database'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'], - TDynamic, - T['_']['excludedMethods'] | K - >, - T['_']['excludedMethods'] | K - >; - -export type SingleStoreAttach< - TDatabase extends string = string, - TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, -> = SingleStoreAttachBase; - -export interface SingleStoreAttachConfig { - milestone?: string | undefined; - time?: Date | undefined; - database: string; - databaseAlias?: string | undefined; - readOnly?: boolean | undefined; -} - -export type SingleStoreAttachPrepare = PreparedQueryKind< - T['_']['preparedQueryHKT'], - SingleStorePreparedQueryConfig & { - execute: SingleStoreQueryResultKind; - iterator: never; - }, - true ->; - -type SingleStoreAttachDynamic = SingleStoreAttach< - T['_']['database'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'] ->; - -type AnySingleStoreAttachBase = SingleStoreAttachBase; - -export interface SingleStoreAttachBase< - TDatabase extends string, - TQueryResult extends SingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - TExcludedMethods extends string = never, -> extends QueryPromise> { - readonly _: { - readonly database: TDatabase; - readonly queryResult: TQueryResult; - readonly preparedQueryHKT: TPreparedQueryHKT; - readonly dynamic: TDynamic; - readonly excludedMethods: TExcludedMethods; - }; -} - -export class SingleStoreAttachBase< - TDatabase extends string, - TQueryResult extends SingleStoreQueryResultHKT, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TExcludedMethods extends string = never, -> extends QueryPromise> implements SQLWrapper { - static override readonly [entityKind]: string = 'SingleStoreAttach'; - - private config: SingleStoreAttachConfig; - - constructor( - private database: TDatabase, - private session: SingleStoreSession, - private dialect: SingleStoreDialect, - ) { - super(); - this.config = { database }; - } - - as(dabataseAlias: string): SingleStoreAttachWithout { - if (this.config.readOnly) { - throw new DrizzleError({ message: 'Cannot set both databaseAlias and readOnly' }); - } - this.config.databaseAlias = dabataseAlias; - return this as any; - } - - /** - * Adds a `where` clause to the query. - * - * Calling this method will delete only those rows that fulfill a specified condition. - * - * See docs: {@link https://orm.drizzle.team/docs/delete} - * - * @param where the `where` clause. - * - * @example - * You can use conditional operators and `sql function` to filter the rows to be deleted. - * - * ```ts - * // Attach all cars with green color - * db.delete(cars).where(eq(cars.color, 'green')); - * // or - * db.delete(cars).where(sql`${cars.color} = 'green'`) - * ``` - * - * You can logically combine conditional operators with `and()` and `or()` operators: - * - * ```ts - * // Attach all BMW cars with a green color - * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); - * - * // Attach all cars with the green or blue color - * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); - * ``` - */ - // TODO(singlestore): docs - atMilestone(milestone: string): SingleStoreAttachWithout { - if (this.config.time) { - throw new DrizzleError({ message: 'Cannot set both time and milestone' }); - } - this.config.milestone = milestone; - return this as any; - } - - // TODO(singlestore): docs - atTime(time: Date): SingleStoreAttachWithout { - if (this.config.milestone) { - throw new DrizzleError({ message: 'Cannot set both time and milestone' }); - } - this.config.time = time; - return this as any; - } - - // TODO(singlestore): docs - readOnly(): SingleStoreAttachWithout { - if (this.config.databaseAlias) { - throw new DrizzleError({ message: 'Cannot set both databaseAlias and readOnly' }); - } - this.config.readOnly = true; - return this as any; - } - - /** @internal */ - getSQL(): SQL { - return this.dialect.buildAttachQuery(this.config); - } - - toSQL(): Query { - const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); - return rest; - } - - prepare(): SingleStoreAttachPrepare { - return this.session.prepareQuery( - this.dialect.sqlToQuery(this.getSQL()), - undefined, - ) as SingleStoreAttachPrepare; - } - - override execute: ReturnType['execute'] = (placeholderValues) => { - return this.prepare().execute(placeholderValues); - }; - - private createIterator = (): ReturnType['iterator'] => { - const self = this; - return async function*(placeholderValues) { - yield* self.prepare().iterator(placeholderValues); - }; - }; - - iterator = this.createIterator(); - - $dynamic(): SingleStoreAttachDynamic { - return this as any; - } -} diff --git a/drizzle-orm/src/singlestore-core/query-builders/branch.ts b/drizzle-orm/src/singlestore-core/query-builders/branch.ts deleted file mode 100644 index 21e2fe0ac..000000000 --- a/drizzle-orm/src/singlestore-core/query-builders/branch.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { entityKind } from '~/entity.ts'; -import { DrizzleError } from '~/errors.ts'; -import { QueryPromise } from '~/query-promise.ts'; -import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; -import type { - AnySingleStoreQueryResultHKT, - PreparedQueryHKTBase, - PreparedQueryKind, - SingleStorePreparedQueryConfig, - SingleStoreQueryResultHKT, - SingleStoreQueryResultKind, - SingleStoreSession, -} from '~/singlestore-core/session.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; -import type { SingleStoreAttachConfig } from './attach.ts'; - -export type SingleStoreBranchWithout< - T extends AnySingleStoreBranchBase, - TDynamic extends boolean, - K extends keyof T & string, -> = TDynamic extends true ? T - : Omit< - SingleStoreBranchBase< - T['_']['database'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'], - TDynamic, - T['_']['excludedMethods'] | K - >, - T['_']['excludedMethods'] | K - >; - -export type SingleStoreBranch< - TDatabase extends string = string, - TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, -> = SingleStoreBranchBase; - -export interface SingleStoreBranchConfig extends SingleStoreAttachConfig { - databaseAlias: string; - fromWorkspaceGroup?: string | undefined; -} - -export type SingleStoreBranchPrepare = PreparedQueryKind< - T['_']['preparedQueryHKT'], - SingleStorePreparedQueryConfig & { - execute: SingleStoreQueryResultKind; - iterator: never; - }, - true ->; - -type SingleStoreBranchDynamic = SingleStoreBranch< - T['_']['database'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'] ->; - -type AnySingleStoreBranchBase = SingleStoreBranchBase; - -export interface SingleStoreBranchBase< - TDatabase extends string, - TQueryResult extends SingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - TExcludedMethods extends string = never, -> extends QueryPromise> { - readonly _: { - readonly database: TDatabase; - readonly queryResult: TQueryResult; - readonly preparedQueryHKT: TPreparedQueryHKT; - readonly dynamic: TDynamic; - readonly excludedMethods: TExcludedMethods; - }; -} - -export class SingleStoreBranchBase< - TDatabase extends string, - TQueryResult extends SingleStoreQueryResultHKT, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TExcludedMethods extends string = never, -> extends QueryPromise> implements SQLWrapper { - static override readonly [entityKind]: string = 'SingleStoreBranch'; - - private config: SingleStoreBranchConfig; - - constructor( - private database: TDatabase, - private branchName: string, - private session: SingleStoreSession, - private dialect: SingleStoreDialect, - ) { - super(); - this.config = { database, databaseAlias: branchName }; - } - - /** - * Adds a `where` clause to the query. - * - * Calling this method will delete only those rows that fulfill a specified condition. - * - * See docs: {@link https://orm.drizzle.team/docs/delete} - * - * @param where the `where` clause. - * - * @example - * You can use conditional operators and `sql function` to filter the rows to be deleted. - * - * ```ts - * // Attach all cars with green color - * db.delete(cars).where(eq(cars.color, 'green')); - * // or - * db.delete(cars).where(sql`${cars.color} = 'green'`) - * ``` - * - * You can logically combine conditional operators with `and()` and `or()` operators: - * - * ```ts - * // Attach all BMW cars with a green color - * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); - * - * // Attach all cars with the green or blue color - * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); - * ``` - */ - // TODO(singlestore): docs - atMilestone(milestone: string): SingleStoreBranchWithout { - if (this.config.time) { - throw new DrizzleError({ message: 'Cannot set both time and milestone' }); - } - this.config.milestone = milestone; - return this as any; - } - - // TODO(singlestore): docs - atTime(time: Date): SingleStoreBranchWithout { - if (this.config.milestone) { - throw new DrizzleError({ message: 'Cannot set both time and milestone' }); - } - this.config.time = time; - return this as any; - } - - // TODO(singlestore): docs - fromWorkspaceGroup(groupID: string): SingleStoreBranchWithout { - this.config.fromWorkspaceGroup = groupID; - return this as any; - } - - /** @internal */ - getSQL(): SQL { - return this.dialect.buildAttachQuery(this.config); - } - - toSQL(): Query { - const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); - return rest; - } - - prepare(): SingleStoreBranchPrepare { - return this.session.prepareQuery( - this.dialect.sqlToQuery(this.getSQL()), - undefined, - ) as SingleStoreBranchPrepare; - } - - override execute: ReturnType['execute'] = (placeholderValues) => { - return this.prepare().execute(placeholderValues); - }; - - private createIterator = (): ReturnType['iterator'] => { - const self = this; - return async function*(placeholderValues) { - yield* self.prepare().iterator(placeholderValues); - }; - }; - - iterator = this.createIterator(); - - $dynamic(): SingleStoreBranchDynamic { - return this as any; - } -} diff --git a/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts b/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts deleted file mode 100644 index 0444d6bf8..000000000 --- a/drizzle-orm/src/singlestore-core/query-builders/createMilestone.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { entityKind } from '~/entity.ts'; -import { QueryPromise } from '~/query-promise.ts'; -import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; -import type { - AnySingleStoreQueryResultHKT, - PreparedQueryHKTBase, - PreparedQueryKind, - SingleStorePreparedQueryConfig, - SingleStoreQueryResultHKT, - SingleStoreQueryResultKind, - SingleStoreSession, -} from '~/singlestore-core/session.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; - -export type SingleStoreCreateMilestoneWithout< - T extends AnySingleStoreCreateMilestoneBase, - TDynamic extends boolean, - K extends keyof T & string, -> = TDynamic extends true ? T - : Omit< - SingleStoreCreateMilestoneBase< - T['_']['milestone'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'], - TDynamic, - T['_']['excludedMethods'] | K - >, - T['_']['excludedMethods'] | K - >; - -export type SingleStoreCreateMilestone< - TDatabase extends string = string, - TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, -> = SingleStoreCreateMilestoneBase; - -export interface SingleStoreCreateMilestoneConfig { - milestone: string; - database?: string | undefined; -} - -export type SingleStoreCreateMilestonePrepare = PreparedQueryKind< - T['_']['preparedQueryHKT'], - SingleStorePreparedQueryConfig & { - execute: SingleStoreQueryResultKind; - iterator: never; - }, - true ->; - -type SingleStoreCreateMilestoneDynamic = SingleStoreCreateMilestone< - T['_']['milestone'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'] ->; - -type AnySingleStoreCreateMilestoneBase = SingleStoreCreateMilestoneBase; - -export interface SingleStoreCreateMilestoneBase< - TMilestone extends string, - TQueryResult extends SingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - TExcludedMethods extends string = never, -> extends QueryPromise> { - readonly _: { - readonly milestone: TMilestone; - readonly queryResult: TQueryResult; - readonly preparedQueryHKT: TPreparedQueryHKT; - readonly dynamic: TDynamic; - readonly excludedMethods: TExcludedMethods; - }; -} - -export class SingleStoreCreateMilestoneBase< - TMilestone extends string, - TQueryResult extends SingleStoreQueryResultHKT, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TExcludedMethods extends string = never, -> extends QueryPromise> implements SQLWrapper { - static override readonly [entityKind]: string = 'SingleStoreCreateMilestone'; - - private config: SingleStoreCreateMilestoneConfig; - - constructor( - private milestone: TMilestone, - private session: SingleStoreSession, - private dialect: SingleStoreDialect, - ) { - super(); - this.config = { milestone }; - } - - // TODO(singlestore): docs - for(database: string): SingleStoreCreateMilestoneWithout { - this.config.database = database; - return this as any; - } - - /** @internal */ - getSQL(): SQL { - return this.dialect.buildCreateMilestoneQuery(this.config); - } - - toSQL(): Query { - const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); - return rest; - } - - prepare(): SingleStoreCreateMilestonePrepare { - return this.session.prepareQuery( - this.dialect.sqlToQuery(this.getSQL()), - undefined, - ) as SingleStoreCreateMilestonePrepare; - } - - override execute: ReturnType['execute'] = (placeholderValues) => { - return this.prepare().execute(placeholderValues); - }; - - private createIterator = (): ReturnType['iterator'] => { - const self = this; - return async function*(placeholderValues) { - yield* self.prepare().iterator(placeholderValues); - }; - }; - - iterator = this.createIterator(); - - $dynamic(): SingleStoreCreateMilestoneDynamic { - return this as any; - } -} diff --git a/drizzle-orm/src/singlestore-core/query-builders/detach.ts b/drizzle-orm/src/singlestore-core/query-builders/detach.ts deleted file mode 100644 index 2b74873e2..000000000 --- a/drizzle-orm/src/singlestore-core/query-builders/detach.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { entityKind } from '~/entity.ts'; -import { QueryPromise } from '~/query-promise.ts'; -import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; -import type { - AnySingleStoreQueryResultHKT, - PreparedQueryHKTBase, - PreparedQueryKind, - SingleStorePreparedQueryConfig, - SingleStoreQueryResultHKT, - SingleStoreQueryResultKind, - SingleStoreSession, -} from '~/singlestore-core/session.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; - -export type SingleStoreDetachWithout< - T extends AnySingleStoreDetachBase, - TDynamic extends boolean, - K extends keyof T & string, -> = TDynamic extends true ? T - : Omit< - SingleStoreDetachBase< - T['_']['database'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'], - TDynamic, - T['_']['excludedMethods'] | K - >, - T['_']['excludedMethods'] | K - >; - -export type SingleStoreDetach< - TDatabase extends string = string, - TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, -> = SingleStoreDetachBase; - -export interface SingleStoreDetachConfig { - milestone?: string | undefined; - database: string; - workspace?: string | undefined; -} - -export type SingleStoreDetachPrepare = PreparedQueryKind< - T['_']['preparedQueryHKT'], - SingleStorePreparedQueryConfig & { - execute: SingleStoreQueryResultKind; - iterator: never; - }, - true ->; - -type SingleStoreDetachDynamic = SingleStoreDetach< - T['_']['database'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'] ->; - -type AnySingleStoreDetachBase = SingleStoreDetachBase; - -export interface SingleStoreDetachBase< - TDatabase extends string, - TQueryResult extends SingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - TExcludedMethods extends string = never, -> extends QueryPromise> { - readonly _: { - readonly database: TDatabase; - readonly queryResult: TQueryResult; - readonly preparedQueryHKT: TPreparedQueryHKT; - readonly dynamic: TDynamic; - readonly excludedMethods: TExcludedMethods; - }; -} - -export class SingleStoreDetachBase< - TDatabase extends string, - TQueryResult extends SingleStoreQueryResultHKT, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TExcludedMethods extends string = never, -> extends QueryPromise> implements SQLWrapper { - static override readonly [entityKind]: string = 'SingleStoreDetach'; - - private config: SingleStoreDetachConfig; - - constructor( - private database: TDatabase, - private session: SingleStoreSession, - private dialect: SingleStoreDialect, - ) { - super(); - this.config = { database }; - } - - /** - * Adds a `where` clause to the query. - * - * Calling this method will delete only those rows that fulfill a specified condition. - * - * See docs: {@link https://orm.drizzle.team/docs/delete} - * - * @param where the `where` clause. - * - * @example - * You can use conditional operators and `sql function` to filter the rows to be deleted. - * - * ```ts - * // Detach all cars with green color - * db.delete(cars).where(eq(cars.color, 'green')); - * // or - * db.delete(cars).where(sql`${cars.color} = 'green'`) - * ``` - * - * You can logically combine conditional operators with `and()` and `or()` operators: - * - * ```ts - * // Detach all BMW cars with a green color - * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); - * - * // Detach all cars with the green or blue color - * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); - * ``` - */ - // TODO(singlestore): docs - atMilestone(milestone: string): SingleStoreDetachWithout { - this.config.milestone = milestone; - return this as any; - } - - // TODO(singlestore): docs - fromWorkspace(workspace: string): SingleStoreDetachWithout { - this.config.workspace = workspace; - return this as any; - } - - /** @internal */ - getSQL(): SQL { - return this.dialect.buildDetachQuery(this.config); - } - - toSQL(): Query { - const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); - return rest; - } - - prepare(): SingleStoreDetachPrepare { - return this.session.prepareQuery( - this.dialect.sqlToQuery(this.getSQL()), - undefined, - ) as SingleStoreDetachPrepare; - } - - override execute: ReturnType['execute'] = (placeholderValues) => { - return this.prepare().execute(placeholderValues); - }; - - private createIterator = (): ReturnType['iterator'] => { - const self = this; - return async function*(placeholderValues) { - yield* self.prepare().iterator(placeholderValues); - }; - }; - - iterator = this.createIterator(); - - $dynamic(): SingleStoreDetachDynamic { - return this as any; - } -} diff --git a/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts b/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts deleted file mode 100644 index 66047c991..000000000 --- a/drizzle-orm/src/singlestore-core/query-builders/dropMilestone.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { entityKind } from '~/entity.ts'; -import { QueryPromise } from '~/query-promise.ts'; -import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; -import type { - AnySingleStoreQueryResultHKT, - PreparedQueryHKTBase, - PreparedQueryKind, - SingleStorePreparedQueryConfig, - SingleStoreQueryResultHKT, - SingleStoreQueryResultKind, - SingleStoreSession, -} from '~/singlestore-core/session.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; - -export type SingleStoreDropMilestoneWithout< - T extends AnySingleStoreDropMilestoneBase, - TDynamic extends boolean, - K extends keyof T & string, -> = TDynamic extends true ? T - : Omit< - SingleStoreDropMilestoneBase< - T['_']['milestone'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'], - TDynamic, - T['_']['excludedMethods'] | K - >, - T['_']['excludedMethods'] | K - >; - -export type SingleStoreDropMilestone< - TDatabase extends string = string, - TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, -> = SingleStoreDropMilestoneBase; - -export interface SingleStoreDropMilestoneConfig { - milestone: string; - database?: string | undefined; -} - -export type SingleStoreDropMilestonePrepare = PreparedQueryKind< - T['_']['preparedQueryHKT'], - SingleStorePreparedQueryConfig & { - execute: SingleStoreQueryResultKind; - iterator: never; - }, - true ->; - -type SingleStoreDropMilestoneDynamic = SingleStoreDropMilestone< - T['_']['milestone'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'] ->; - -type AnySingleStoreDropMilestoneBase = SingleStoreDropMilestoneBase; - -export interface SingleStoreDropMilestoneBase< - TMilestone extends string, - TQueryResult extends SingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - TExcludedMethods extends string = never, -> extends QueryPromise> { - readonly _: { - readonly milestone: TMilestone; - readonly queryResult: TQueryResult; - readonly preparedQueryHKT: TPreparedQueryHKT; - readonly dynamic: TDynamic; - readonly excludedMethods: TExcludedMethods; - }; -} - -export class SingleStoreDropMilestoneBase< - TMilestone extends string, - TQueryResult extends SingleStoreQueryResultHKT, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TExcludedMethods extends string = never, -> extends QueryPromise> implements SQLWrapper { - static override readonly [entityKind]: string = 'SingleStoreDropMilestone'; - - private config: SingleStoreDropMilestoneConfig; - - constructor( - private milestone: TMilestone, - private session: SingleStoreSession, - private dialect: SingleStoreDialect, - ) { - super(); - this.config = { milestone }; - } - - // TODO(singlestore): docs - for(database: string): SingleStoreDropMilestoneWithout { - this.config.database = database; - return this as any; - } - - /** @internal */ - getSQL(): SQL { - return this.dialect.buildDropMilestoneQuery(this.config); - } - - toSQL(): Query { - const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); - return rest; - } - - prepare(): SingleStoreDropMilestonePrepare { - return this.session.prepareQuery( - this.dialect.sqlToQuery(this.getSQL()), - undefined, - ) as SingleStoreDropMilestonePrepare; - } - - override execute: ReturnType['execute'] = (placeholderValues) => { - return this.prepare().execute(placeholderValues); - }; - - private createIterator = (): ReturnType['iterator'] => { - const self = this; - return async function*(placeholderValues) { - yield* self.prepare().iterator(placeholderValues); - }; - }; - - iterator = this.createIterator(); - - $dynamic(): SingleStoreDropMilestoneDynamic { - return this as any; - } -} diff --git a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts b/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts deleted file mode 100644 index 3e174c869..000000000 --- a/drizzle-orm/src/singlestore-core/query-builders/optimizeTable.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { entityKind } from '~/entity.ts'; -import type { ColumnBaseConfig, ColumnDataType } from '~/index.ts'; -import { QueryPromise } from '~/query-promise.ts'; -import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; -import type { - AnySingleStoreQueryResultHKT, - PreparedQueryHKTBase, - PreparedQueryKind, - SingleStorePreparedQueryConfig, - SingleStoreQueryResultHKT, - SingleStoreQueryResultKind, - SingleStoreSession, -} from '~/singlestore-core/session.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; -import type { SingleStoreColumn } from '../columns/common.ts'; -import type { SingleStoreTable } from '../table.ts'; - -export type OptimizeTableArgument = - | 'FULL' - | 'FLUSH' - | 'FIX_ALTER' - | 'INDEX'; - -export type SingleStoreOptimizeTableWithout< - T extends AnySingleStoreOptimizeTableBase, - TDynamic extends boolean, - K extends keyof T & string, -> = TDynamic extends true ? T - : Omit< - SingleStoreOptimizeTableBase< - T['_']['table'], - T['_']['arg'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'], - TDynamic, - T['_']['excludedMethods'] | K - >, - T['_']['excludedMethods'] | K - >; - -export type SingleStoreOptimizeTable< - TTable extends SingleStoreTable = SingleStoreTable, - TArg extends OptimizeTableArgument = OptimizeTableArgument, - TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, -> = SingleStoreOptimizeTableBase; - -export interface SingleStoreOptimizeTableConfig { - table: SingleStoreTable; - arg?: OptimizeTableArgument | undefined; - selection?: SingleStoreColumn, object>[] | undefined; -} - -export type SingleStoreOptimizeTablePrepare = PreparedQueryKind< - T['_']['preparedQueryHKT'], - SingleStorePreparedQueryConfig & { - execute: SingleStoreQueryResultKind; - iterator: never; - }, - true ->; - -type SingleStoreOptimizeTableDynamic = SingleStoreOptimizeTable< - T['_']['table'], - T['_']['arg'], - T['_']['queryResult'], - T['_']['preparedQueryHKT'] ->; - -type AnySingleStoreOptimizeTableBase = SingleStoreOptimizeTableBase; - -export interface SingleStoreOptimizeTableBase< - TTable extends SingleStoreTable, - TArg extends OptimizeTableArgument, - TQueryResult extends SingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - TExcludedMethods extends string = never, -> extends QueryPromise> { - readonly _: { - readonly table: TTable; - readonly arg: TArg | undefined; - readonly queryResult: TQueryResult; - readonly preparedQueryHKT: TPreparedQueryHKT; - readonly dynamic: TDynamic; - readonly excludedMethods: TExcludedMethods; - }; -} - -export class SingleStoreOptimizeTableBase< - TTable extends SingleStoreTable, - TArg extends OptimizeTableArgument, - TQueryResult extends SingleStoreQueryResultHKT, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TPreparedQueryHKT extends PreparedQueryHKTBase, - TDynamic extends boolean = false, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TExcludedMethods extends string = never, -> extends QueryPromise> implements SQLWrapper { - static override readonly [entityKind]: string = 'SingleStoreOptimizeTable'; - - private config: SingleStoreOptimizeTableConfig; - - constructor( - private table: TTable, - private arg: TArg | undefined, - private session: SingleStoreSession, - private dialect: SingleStoreDialect, - ) { - super(); - this.config = { table, arg }; - } - - // TODO(singlestore): docs - warmBlobCacheForColumn( - ...selection: SingleStoreColumn, object>[] - ): SingleStoreOptimizeTableWithout { - if (this.config.arg) { - throw new Error('Cannot call warmBlobCacheForColumn with an argument'); - } - this.config.selection = selection; - return this as any; - } - - /** @internal */ - getSQL(): SQL { - return this.dialect.buildOptimizeTable(this.config); - } - - toSQL(): Query { - const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); - return rest; - } - - prepare(): SingleStoreOptimizeTablePrepare { - return this.session.prepareQuery( - this.dialect.sqlToQuery(this.getSQL()), - undefined, - ) as SingleStoreOptimizeTablePrepare; - } - - override execute: ReturnType['execute'] = (placeholderValues) => { - return this.prepare().execute(placeholderValues); - }; - - private createIterator = (): ReturnType['iterator'] => { - const self = this; - return async function*(placeholderValues) { - yield* self.prepare().iterator(placeholderValues); - }; - }; - - iterator = this.createIterator(); - - $dynamic(): SingleStoreOptimizeTableDynamic { - return this as any; - } -} diff --git a/drizzle-orm/type-tests/singlestore/count.ts b/drizzle-orm/type-tests/singlestore/count.ts new file mode 100644 index 000000000..50abc8c3a --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/count.ts @@ -0,0 +1,61 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, gt, ne } from '~/expressions.ts'; +import { int, serial, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import type { Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = singlestoreTable('names', { + id: serial('id').primaryKey(), + name: text('name'), + authorId: int('author_id'), +}); + +const separate = await db.$count(names); + +const separateFilters = await db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))); + +const embedded = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names).as('count1'), + }) + .from(names); + +const embeddedFilters = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))).as('count1'), + }) + .from(names); + +Expect>; + +Expect>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embedded + > +>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embeddedFilters + > +>; diff --git a/drizzle-orm/type-tests/singlestore/db.ts b/drizzle-orm/type-tests/singlestore/db.ts index f9bc6ff5f..bde149b08 100644 --- a/drizzle-orm/type-tests/singlestore/db.ts +++ b/drizzle-orm/type-tests/singlestore/db.ts @@ -7,6 +7,8 @@ export const db = drizzle(pool); { drizzle(pool); - drizzle(pool, {}); + // @ts-expect-error - missing mode drizzle(pool, { schema: {} }); + drizzle(pool, { schema: {}, mode: 'default' }); + drizzle(pool, { mode: 'default' }); } diff --git a/drizzle-orm/type-tests/singlestore/delete.ts b/drizzle-orm/type-tests/singlestore/delete.ts index 0fce8882e..db58ac2ec 100644 --- a/drizzle-orm/type-tests/singlestore/delete.ts +++ b/drizzle-orm/type-tests/singlestore/delete.ts @@ -59,3 +59,7 @@ Expect>; .where(sql``) .where(sql``); } + +{ + db.delete(users).where(sql``).limit(1).orderBy(sql``); +} diff --git a/drizzle-orm/type-tests/singlestore/generated-columns.ts b/drizzle-orm/type-tests/singlestore/generated-columns.ts deleted file mode 100644 index e5b17a9b1..000000000 --- a/drizzle-orm/type-tests/singlestore/generated-columns.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { type Equal, Expect } from 'type-tests/utils'; -import { type InferInsertModel, type InferSelectModel, sql } from '~/index'; -import { drizzle } from '~/singlestore'; -import { serial, singlestoreTable, text, varchar } from '~/singlestore-core'; -import { db } from './db'; - -const users = singlestoreTable( - 'users', - { - id: serial('id').primaryKey(), - firstName: varchar('first_name', { length: 255 }), - lastName: varchar('last_name', { length: 255 }), - email: text('email').notNull(), - fullName: text('full_name').generatedAlwaysAs(sql`concat_ws(first_name, ' ', last_name)`), - upperName: text('upper_name').generatedAlwaysAs( - sql` case when first_name is null then null else upper(first_name) end `, - ).$type(), // There is no way for drizzle to detect nullability in these cases. This is how the user can work around it - }, -); -{ - type User = typeof users.$inferSelect; - type NewUser = typeof users.$inferInsert; - - Expect< - Equal< - { - id: number; - firstName: string | null; - lastName: string | null; - email: string; - fullName: string | null; - upperName: string | null; - }, - User - > - >(); - - Expect< - Equal< - { - email: string; - id?: number | undefined; - firstName?: string | null | undefined; - lastName?: string | null | undefined; - }, - NewUser - > - >(); -} - -{ - type User = InferSelectModel; - type NewUser = InferInsertModel; - - Expect< - Equal< - { - id: number; - firstName: string | null; - lastName: string | null; - email: string; - fullName: string | null; - upperName: string | null; - }, - User - > - >(); - - Expect< - Equal< - { - email: string; - id?: number | undefined; - firstName?: string | null | undefined; - lastName?: string | null | undefined; - }, - NewUser - > - >(); -} - -{ - const dbUsers = await db.select().from(users); - - Expect< - Equal< - { - id: number; - firstName: string | null; - lastName: string | null; - email: string; - fullName: string | null; - upperName: string | null; - }[], - typeof dbUsers - > - >(); -} - -{ - const db = drizzle({} as any, { schema: { users } }); - - const dbUser = await db.query.users.findFirst(); - - Expect< - Equal< - { - id: number; - firstName: string | null; - lastName: string | null; - email: string; - fullName: string | null; - upperName: string | null; - } | undefined, - typeof dbUser - > - >(); -} - -{ - const db = drizzle({} as any, { schema: { users } }); - - const dbUser = await db.query.users.findMany(); - - Expect< - Equal< - { - id: number; - firstName: string | null; - lastName: string | null; - email: string; - fullName: string | null; - upperName: string | null; - }[], - typeof dbUser - > - >(); -} - -{ - // @ts-expect-error - Can't use the fullName because it's a generated column - await db.insert(users).values({ - firstName: 'test', - lastName: 'test', - email: 'test', - fullName: 'test', - }); -} - -{ - await db.update(users).set({ - firstName: 'test', - lastName: 'test', - email: 'test', - // @ts-expect-error - Can't use the fullName because it's a generated column - fullName: 'test', - }); -} diff --git a/drizzle-orm/type-tests/singlestore/select.ts b/drizzle-orm/type-tests/singlestore/select.ts index 10a7551a7..f7a5094ea 100644 --- a/drizzle-orm/type-tests/singlestore/select.ts +++ b/drizzle-orm/type-tests/singlestore/select.ts @@ -28,7 +28,7 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { QueryBuilder, type SingleStoreSelect, type SingleStoreSelectQueryBuilder } from '~/singlestore-core/index.ts'; import { db } from './db.ts'; -import { cities, classes, newYorkers, users } from './tables.ts'; +import { cities, classes, users } from './tables.ts'; const city = alias(cities, 'city'); const city1 = alias(cities, 'city1'); @@ -397,7 +397,8 @@ Expect< await db.select().from(users).for('update'); await db.select().from(users).for('share', { skipLocked: true }); await db.select().from(users).for('update', { noWait: true }); -await db +// TODO Implement views for SingleStore (https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-view/) +/* await db .select() .from(users) // @ts-expect-error - can't use both skipLocked and noWait @@ -426,7 +427,7 @@ await db typeof result > >; -} +} */ { const query = db.select().from(users).prepare().iterator(); diff --git a/drizzle-orm/type-tests/singlestore/set-operators.ts b/drizzle-orm/type-tests/singlestore/set-operators.ts index aa4f21b9c..1db4bb7f1 100644 --- a/drizzle-orm/type-tests/singlestore/set-operators.ts +++ b/drizzle-orm/type-tests/singlestore/set-operators.ts @@ -1,9 +1,9 @@ import { type Equal, Expect } from 'type-tests/utils.ts'; import { eq } from '~/expressions.ts'; -import { except, intersect, type SingleStoreSetOperator, union, unionAll } from '~/singlestore-core/index.ts'; +import { intersect, type SingleStoreSetOperator, union, unionAll } from '~/singlestore-core/index.ts'; import { sql } from '~/sql/index.ts'; import { db } from './db.ts'; -import { cities, classes, newYorkers, users } from './tables.ts'; +import { cities, classes, users } from './tables.ts'; const unionTest = await db .select({ id: users.id }) @@ -54,6 +54,17 @@ const exceptTest = await db Expect>; +const minusTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .minus( + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ); + +Expect>; + const union2Test = await union(db.select().from(cities), db.select().from(cities), db.select().from(cities)); Expect>; @@ -89,7 +100,8 @@ const intersect2Test = await intersect( Expect>; -const except2Test = await except( +// TODO Implement views for SingleStore (https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-view/) +/* const except2Test = await except( db.select({ userId: newYorkers.userId, }) @@ -99,7 +111,7 @@ const except2Test = await except( }).from(newYorkers), ); -Expect>; +Expect>; */ const unionfull = await union(db.select().from(users), db.select().from(users)).orderBy(sql``).limit(1).offset(2); @@ -206,7 +218,7 @@ union( // @ts-expect-error db.select({ id: cities.id, name: cities.name }).from(cities), db.select({ id: cities.id }).from(cities), - db.select({ id: newYorkers.userId }).from(newYorkers), + /* db.select({ id: newYorkers.userId }).from(newYorkers), */ db.select({ id: cities.id }).from(cities), ); diff --git a/drizzle-orm/type-tests/singlestore/tables.ts b/drizzle-orm/type-tests/singlestore/tables.ts index da9b4f7cf..5d63cf410 100644 --- a/drizzle-orm/type-tests/singlestore/tables.ts +++ b/drizzle-orm/type-tests/singlestore/tables.ts @@ -1,6 +1,6 @@ import { type Equal, Expect } from 'type-tests/utils.ts'; import type { BuildColumn } from '~/column-builder.ts'; -import { eq, gt } from '~/expressions.ts'; +import { eq } from '~/expressions.ts'; import { bigint, binary, @@ -37,8 +37,7 @@ import { year, } from '~/singlestore-core/index.ts'; import { singlestoreSchema } from '~/singlestore-core/schema.ts'; -import { singlestoreView, type SingleStoreViewWithSelection } from '~/singlestore-core/view.ts'; -import { sql } from '~/sql/sql.ts'; +/* import { singlestoreView, type SingleStoreViewWithSelection } from '~/singlestore-core/view.ts'; */ import type { InferSelectModel } from '~/table.ts'; import type { Simplify } from '~/utils.ts'; import { db } from './db.ts'; @@ -169,13 +168,14 @@ export const classes = singlestoreTable('classes_table', ({ serial, text }) => ( subClass: text('sub_class', { enum: ['B', 'D'] }).notNull(), })); +// TODO Implement views for SingleStore (https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-view/) /* export const classes2 = singlestoreTable('classes_table', { id: serial().primaryKey(), class: text({ enum: ['A', 'C'] }).$dbName('class_db'), subClass: text({ enum: ['B', 'D'] }).notNull(), }); */ -export const newYorkers = singlestoreView('new_yorkers') +/* export const newYorkers = singlestoreView('new_yorkers') .algorithm('merge') .sqlSecurity('definer') .as((qb) => { @@ -487,7 +487,7 @@ Expect< typeof newYorkers > >; -} +} */ { const customText = customType<{ data: string }>({ @@ -582,7 +582,7 @@ Expect< Expect>; } -{ // All types with generated columns +/* { // All types with generated columns const test = singlestoreTable('test', { test1: singlestoreEnum('test', ['a', 'b', 'c'] as const).generatedAlwaysAs(sql``), test2: singlestoreEnum('test', ['a', 'b', 'c']).generatedAlwaysAs(sql``), @@ -615,7 +615,7 @@ Expect< Expect>; Expect>; Expect>; -} +} */ { const getUsersTable = (schemaName: TSchema) => { @@ -675,7 +675,8 @@ Expect< >; } -{ +// TODO Implement views for SingleStore (https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-view/) +/* { const newYorkers = singlestoreView('new_yorkers') .as((qb) => { const sq = qb @@ -690,7 +691,7 @@ Expect< }); await db.select().from(newYorkers).leftJoin(newYorkers, eq(newYorkers.userId, newYorkers.userId)); -} +} */ { const test = singlestoreTable('test', { diff --git a/drizzle-orm/type-tests/singlestore/update.ts b/drizzle-orm/type-tests/singlestore/update.ts index 3f10ae2e4..4fb5497cf 100644 --- a/drizzle-orm/type-tests/singlestore/update.ts +++ b/drizzle-orm/type-tests/singlestore/update.ts @@ -24,3 +24,7 @@ import { users } from './tables.ts'; // @ts-expect-error method was already called .where(sql``); } + +{ + db.update(users).set({}).where(sql``).limit(1).orderBy(sql``); +} diff --git a/drizzle-orm/type-tests/singlestore/with.ts b/drizzle-orm/type-tests/singlestore/with.ts index 77309e32a..4233fbbf1 100644 --- a/drizzle-orm/type-tests/singlestore/with.ts +++ b/drizzle-orm/type-tests/singlestore/with.ts @@ -11,7 +11,7 @@ const orders = singlestoreTable('orders', { product: text('product').notNull(), amount: int('amount').notNull(), quantity: int('quantity').notNull(), - generated: text('generatedText').generatedAlwaysAs(sql``), + /* generated: text('generatedText').generatedAlwaysAs(sql``), */ }); { @@ -74,7 +74,7 @@ const orders = singlestoreTable('orders', { product: string; amount: number; quantity: number; - generated: string | null; + /* generated: string | null; */ }[], typeof allFromWith> >; } From 894638fdd5555ca7c261ecbe40faa8ae3d103768 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 13 Nov 2024 11:01:31 +0200 Subject: [PATCH 346/492] Fixes --- drizzle-orm/src/column-builder.ts | 11 ++--- drizzle-orm/src/mysql-core/columns/serial.ts | 1 - drizzle-orm/src/operations.ts | 28 +++++------ drizzle-orm/src/pg-core/columns/int.common.ts | 29 ++---------- drizzle-orm/src/pg-core/columns/integer.ts | 1 - drizzle-orm/src/pg-core/columns/serial.ts | 1 - drizzle-orm/src/table.ts | 47 ++++++++----------- drizzle-orm/type-tests/pg/insert.ts | 9 ++-- drizzle-orm/type-tests/pg/tables.ts | 14 +++--- 9 files changed, 52 insertions(+), 89 deletions(-) diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index d87460336..f24e63fbf 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -43,7 +43,6 @@ export interface ColumnBuilderBaseConfig | undefined; - identity: 'always' | 'byDefault' | undefined; } export type MakeColumnConfig< @@ -66,7 +65,7 @@ export type MakeColumnConfig< baseColumn: T extends { baseBuilder: infer U extends ColumnBuilderBase } ? BuildColumn : never; generated: T['generated'] extends object ? T['generated'] : undefined; - identity: T['identity']; + identity: T extends { identity: 'always' } ? 'always' : T extends { identity: 'byDefault' } ? 'byDefault' : undefined; } & {}; export type ColumnBuilderTypeConfig< @@ -85,7 +84,7 @@ export type ColumnBuilderTypeConfig< hasDefault: T extends { hasDefault: infer U } ? U : boolean; enumValues: T['enumValues']; generated: GeneratedColumnConfig | undefined; - identity: T['identity']; + identity: T extends { identity: infer U } ? U : unknown; } & TTypeConfig >; @@ -106,6 +105,7 @@ export type ColumnBuilderRuntimeConfig | undefined; generatedIdentity: GeneratedIdentityConfig | undefined; + identity: 'always' | 'byDefault' | undefined; } & TRuntimeConfig; export interface ColumnBuilderExtraConfig { @@ -162,12 +162,9 @@ export type IsIdentity< _: { notNull: true; hasDefault: true; - generated: { as: any; type: TType }; - identity: TType ; + identity: TType; }; }; -// always -> user pass overriding and - export interface ColumnBuilderBase< T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, TTypeConfig extends object = object, diff --git a/drizzle-orm/src/mysql-core/columns/serial.ts b/drizzle-orm/src/mysql-core/columns/serial.ts index 27fa1e610..88485d6b2 100644 --- a/drizzle-orm/src/mysql-core/columns/serial.ts +++ b/drizzle-orm/src/mysql-core/columns/serial.ts @@ -24,7 +24,6 @@ export type MySqlSerialBuilderInitial = IsAutoincrement< driverParam: number; enumValues: undefined; generated: undefined; - identity: undefined; }> > > diff --git a/drizzle-orm/src/operations.ts b/drizzle-orm/src/operations.ts index b7f488f8c..cfb28e6d3 100644 --- a/drizzle-orm/src/operations.ts +++ b/drizzle-orm/src/operations.ts @@ -19,7 +19,7 @@ export type NotGenerated = T extends AnyC // // OverrideT extends boolean | undefined = false // > = TKey extends RequiredKeyOnly ? never // : TKey extends NotGenerated ? TKey -// : T['_']['generated'] extends object ? T['_']['generated']['type'] extends 'byDefault' ? TKey +// : T['_']['generated'] extends object ? T['_']['generated']['type'] extends 'byDefault' ? TKey // : never // // ( // // T['_']['identity'] extends 'always'? @@ -31,28 +31,24 @@ export type NotGenerated = T extends AnyC export type OptionalKeyOnly< TKey extends string, T extends Column, - OverrideT extends boolean | undefined = false + OverrideT extends boolean | undefined = false, > = TKey extends RequiredKeyOnly ? never : TKey extends NotGenerated ? ( - T['_'] - // T['_']['identity'] extends 'always'? - // OverrideT extends true? TKey: never - // : TKey - ): - never; + T['_']['identity'] extends 'always' ? OverrideT extends true ? TKey : never + : TKey + ) + : never; export type IdentityColumns< TKey extends string, T extends Column, - OverrideT extends boolean | undefined = false + OverrideT extends boolean | undefined = false, > = TKey extends RequiredKeyOnly ? never - : TKey extends OptionalKeyOnly? never - : T['_']['identity'] extends 'byDefault' ? TKey - : - ( - T['_']['identity'] extends 'always'? - OverrideT extends true? TKey: never - : never + : TKey extends OptionalKeyOnly ? never + : T['_']['identity'] extends 'byDefault' ? TKey + : ( + T['_']['identity'] extends 'always' ? OverrideT extends true ? TKey : never + : never ); // byDefault -> accept diff --git a/drizzle-orm/src/pg-core/columns/int.common.ts b/drizzle-orm/src/pg-core/columns/int.common.ts index 8c388fb2e..32d5d12cd 100644 --- a/drizzle-orm/src/pg-core/columns/int.common.ts +++ b/drizzle-orm/src/pg-core/columns/int.common.ts @@ -1,30 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnDataType, - GeneratedIdentityConfig, - IsIdentity, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnDataType, GeneratedIdentityConfig, IsIdentity } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; import type { PgSequenceOptions } from '../sequence.ts'; import { PgColumnBuilder } from './common.ts'; -import type { PgIntegerBuilderInitial } from './integer.ts'; -// import type { Simplify } from '~/index.ts'; - - -// type a = Simplify, "always">>; -type a = IsIdentity, "always">; - -type a1 = {'_': { - identity: undefined -}} - -type a2 = a1 & {'_': { - identity: 'always' -}} - -let b: a2; -b._ - export abstract class PgIntColumnBaseBuilder< T extends ColumnBuilderBaseConfig, @@ -53,7 +30,7 @@ export abstract class PgIntColumnBaseBuilder< this.config.hasDefault = true; this.config.notNull = true; - return this as any; + return this as IsIdentity; } generatedByDefaultAsIdentity( @@ -75,6 +52,6 @@ export abstract class PgIntColumnBaseBuilder< this.config.hasDefault = true; this.config.notNull = true; - return this as any; + return this as IsIdentity; } } diff --git a/drizzle-orm/src/pg-core/columns/integer.ts b/drizzle-orm/src/pg-core/columns/integer.ts index 98822bee6..49b5924da 100644 --- a/drizzle-orm/src/pg-core/columns/integer.ts +++ b/drizzle-orm/src/pg-core/columns/integer.ts @@ -14,7 +14,6 @@ export type PgIntegerBuilderInitial = PgIntegerBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgIntegerBuilder> diff --git a/drizzle-orm/src/pg-core/columns/serial.ts b/drizzle-orm/src/pg-core/columns/serial.ts index 85b4da797..6a0196c38 100644 --- a/drizzle-orm/src/pg-core/columns/serial.ts +++ b/drizzle-orm/src/pg-core/columns/serial.ts @@ -20,7 +20,6 @@ export type PgSerialBuilderInitial = NotNull< driverParam: number; enumValues: undefined; generated: undefined; - identity: undefined; }> > >; diff --git a/drizzle-orm/src/table.ts b/drizzle-orm/src/table.ts index 98a904d86..c843fd519 100644 --- a/drizzle-orm/src/table.ts +++ b/drizzle-orm/src/table.ts @@ -156,35 +156,26 @@ export type MapColumnName, TInferMode extends 'select' | 'insert' = 'select', - TConfig extends { dbColumnNames: boolean, override?: boolean } = { dbColumnNames: false, override: false }, + TConfig extends { dbColumnNames: boolean; override?: boolean } = { dbColumnNames: false; override: false }, > = Simplify< TInferMode extends 'insert' ? - & { - [ - Key in keyof TColumns & string as RequiredKeyOnly< - MapColumnName, - TColumns[Key] - > - ]: GetColumnData; - } - & { - [ - Key in keyof TColumns & string as OptionalKeyOnly< - MapColumnName, - TColumns[Key], - TConfig['override'] - > - ]?: GetColumnData; - } - // & { - // [ - // Key in keyof TColumns & string as IdentityColumns< - // MapColumnName, - // TColumns[Key], - // TConfig['override'] - // > - // ]?: GetColumnData; - // } + & { + [ + Key in keyof TColumns & string as RequiredKeyOnly< + MapColumnName, + TColumns[Key] + > + ]: GetColumnData; + } + & { + [ + Key in keyof TColumns & string as OptionalKeyOnly< + MapColumnName, + TColumns[Key], + TConfig['override'] + > + ]?: GetColumnData; + } : { [ Key in keyof TColumns & string as MapColumnName< @@ -211,5 +202,5 @@ export type InferSelectModel< export type InferInsertModel< TTable extends Table, - TConfig extends { dbColumnNames: boolean, override?: boolean } = { dbColumnNames: false, override: false } + TConfig extends { dbColumnNames: boolean; override?: boolean } = { dbColumnNames: false; override: false }, > = InferModelFromColumns; diff --git a/drizzle-orm/type-tests/pg/insert.ts b/drizzle-orm/type-tests/pg/insert.ts index c11ea8740..c1ae7c685 100644 --- a/drizzle-orm/type-tests/pg/insert.ts +++ b/drizzle-orm/type-tests/pg/insert.ts @@ -2,9 +2,10 @@ import type { QueryResult } from 'pg'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import type { PgInsert } from '~/pg-core/query-builders/insert.ts'; +import { PgInsertValue } from '~/pg-core/query-builders/insert.ts'; import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; -import { users, identityColumnsTable } from './tables.ts'; +import { identityColumnsTable, users } from './tables.ts'; const insert = await db .insert(users) @@ -205,8 +206,10 @@ Expect< .returning(); } +type hh = PgInsertValue; + db.insert(identityColumnsTable).overridingSystemValue().values([ - { alwaysAsIdentity: 3, name: "aa"}, + { alwaysAsIdentity: 1 }, // { byDefaultAsIdentity: 5, name: "ff"}, // { alwaysAsIdentity: 4, byDefaultAsIdentity: 6, name: "sd"}, -]); \ No newline at end of file +]); diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index ef2c9edf4..15642a190 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -54,19 +54,23 @@ import { type PgViewWithSelection, } from '~/pg-core/view.ts'; import { sql } from '~/sql/sql.ts'; -import type { InferInsertModel, InferSelectModel } from '~/table.ts'; +import { InferInsertModel } from '~/table.ts'; +import type { InferSelectModel, Table } from '~/table.ts'; import { db } from './db.ts'; export const myEnum = pgEnum('my_enum', ['a', 'b', 'c']); export const identityColumnsTable = pgTable('identity_columns_table', { // generatedCol: integer('g').generatedAlwaysAs(1), - alwaysAsIdentity: integer("always_as_identity").generatedByDefaultAsIdentity(), + alwaysAsIdentity: integer('always_as_identity').generatedAlwaysAsIdentity(), // byDefaultAsIdentity: integer('by_default_as_identity').generatedByDefaultAsIdentity(), // name: text('name') }); -identityColumnsTable.$inferInsert +type g = InferInsertModel; + +type h = typeof identityColumnsTable.$inferInsert; + export const users = pgTable( 'users_table', { @@ -122,9 +126,7 @@ export const smallSerialTest = pgTable('cities_table', { id: smallserial('id').primaryKey(), name: text('name').notNull(), population: integer('population').default(0), -}, (cities) => ({ - citiesNameIdx: index().on(cities.id), -})); +}); Expect< Equal<{ From 30196162d70e8ed3b70f435204a3aafe4038869d Mon Sep 17 00:00:00 2001 From: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> Date: Wed, 13 Nov 2024 16:45:39 +0200 Subject: [PATCH 347/492] Fixed `.generated` behaviour with non-strict `tsconfig` (fixes #2654) (#3542) --- drizzle-orm/src/column-builder.ts | 12 ++++++++---- drizzle-orm/src/mysql-core/columns/bigint.ts | 2 -- drizzle-orm/src/mysql-core/columns/binary.ts | 1 - drizzle-orm/src/mysql-core/columns/boolean.ts | 1 - drizzle-orm/src/mysql-core/columns/char.ts | 1 - drizzle-orm/src/mysql-core/columns/common.ts | 4 +++- drizzle-orm/src/mysql-core/columns/custom.ts | 1 - drizzle-orm/src/mysql-core/columns/date.ts | 2 -- drizzle-orm/src/mysql-core/columns/datetime.ts | 2 -- drizzle-orm/src/mysql-core/columns/decimal.ts | 1 - drizzle-orm/src/mysql-core/columns/double.ts | 1 - drizzle-orm/src/mysql-core/columns/enum.ts | 1 - drizzle-orm/src/mysql-core/columns/float.ts | 1 - drizzle-orm/src/mysql-core/columns/int.ts | 1 - drizzle-orm/src/mysql-core/columns/json.ts | 1 - drizzle-orm/src/mysql-core/columns/mediumint.ts | 1 - drizzle-orm/src/mysql-core/columns/real.ts | 1 - drizzle-orm/src/mysql-core/columns/serial.ts | 1 - drizzle-orm/src/mysql-core/columns/smallint.ts | 1 - drizzle-orm/src/mysql-core/columns/text.ts | 1 - drizzle-orm/src/mysql-core/columns/time.ts | 1 - drizzle-orm/src/mysql-core/columns/timestamp.ts | 2 -- drizzle-orm/src/mysql-core/columns/tinyint.ts | 1 - drizzle-orm/src/mysql-core/columns/varbinary.ts | 1 - drizzle-orm/src/mysql-core/columns/varchar.ts | 1 - drizzle-orm/src/mysql-core/columns/year.ts | 1 - drizzle-orm/src/operations.ts | 14 +++++++------- drizzle-orm/src/pg-core/columns/bigint.ts | 2 -- drizzle-orm/src/pg-core/columns/bigserial.ts | 2 -- drizzle-orm/src/pg-core/columns/boolean.ts | 1 - drizzle-orm/src/pg-core/columns/char.ts | 1 - drizzle-orm/src/pg-core/columns/cidr.ts | 1 - drizzle-orm/src/pg-core/columns/common.ts | 8 ++++++-- drizzle-orm/src/pg-core/columns/custom.ts | 1 - drizzle-orm/src/pg-core/columns/date.ts | 2 -- .../src/pg-core/columns/double-precision.ts | 1 - drizzle-orm/src/pg-core/columns/enum.ts | 1 - drizzle-orm/src/pg-core/columns/inet.ts | 1 - drizzle-orm/src/pg-core/columns/integer.ts | 1 - drizzle-orm/src/pg-core/columns/interval.ts | 1 - drizzle-orm/src/pg-core/columns/json.ts | 1 - drizzle-orm/src/pg-core/columns/jsonb.ts | 1 - drizzle-orm/src/pg-core/columns/line.ts | 2 -- drizzle-orm/src/pg-core/columns/macaddr.ts | 1 - drizzle-orm/src/pg-core/columns/macaddr8.ts | 1 - drizzle-orm/src/pg-core/columns/numeric.ts | 1 - drizzle-orm/src/pg-core/columns/point.ts | 2 -- .../pg-core/columns/postgis_extension/geometry.ts | 2 -- drizzle-orm/src/pg-core/columns/real.ts | 1 - drizzle-orm/src/pg-core/columns/serial.ts | 1 - drizzle-orm/src/pg-core/columns/smallint.ts | 1 - drizzle-orm/src/pg-core/columns/smallserial.ts | 1 - drizzle-orm/src/pg-core/columns/text.ts | 1 - drizzle-orm/src/pg-core/columns/time.ts | 1 - drizzle-orm/src/pg-core/columns/timestamp.ts | 2 -- drizzle-orm/src/pg-core/columns/uuid.ts | 1 - drizzle-orm/src/pg-core/columns/varchar.ts | 1 - .../src/pg-core/columns/vector_extension/bit.ts | 1 - .../pg-core/columns/vector_extension/halfvec.ts | 1 - .../pg-core/columns/vector_extension/sparsevec.ts | 1 - .../src/pg-core/columns/vector_extension/vector.ts | 1 - drizzle-orm/src/sqlite-core/columns/blob.ts | 3 --- drizzle-orm/src/sqlite-core/columns/common.ts | 4 +++- drizzle-orm/src/sqlite-core/columns/custom.ts | 1 - drizzle-orm/src/sqlite-core/columns/integer.ts | 3 --- drizzle-orm/src/sqlite-core/columns/numeric.ts | 1 - drizzle-orm/src/sqlite-core/columns/real.ts | 1 - drizzle-orm/src/sqlite-core/columns/text.ts | 1 - drizzle-orm/type-tests/mysql/generated-columns.ts | 1 + drizzle-orm/type-tests/sqlite/generated-columns.ts | 4 +++- 70 files changed, 31 insertions(+), 94 deletions(-) diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index fb7da9ef6..e53e5ca0d 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -42,7 +42,6 @@ export interface ColumnBuilderBaseConfig | undefined; } export type MakeColumnConfig< @@ -64,7 +63,10 @@ export type MakeColumnConfig< enumValues: T['enumValues']; baseColumn: T extends { baseBuilder: infer U extends ColumnBuilderBase } ? BuildColumn : never; - generated: T['generated'] extends object ? T['generated'] : undefined; + generated: T extends { generated: infer G } ? unknown extends G ? undefined + : G extends undefined ? undefined + : G + : undefined; } & {}; export type ColumnBuilderTypeConfig< @@ -82,7 +84,7 @@ export type ColumnBuilderTypeConfig< notNull: T extends { notNull: infer U } ? U : boolean; hasDefault: T extends { hasDefault: infer U } ? U : boolean; enumValues: T['enumValues']; - generated: GeneratedColumnConfig | undefined; + generated: T extends { generated: infer G } ? G extends undefined ? unknown : G : unknown; } & TTypeConfig >; @@ -294,7 +296,9 @@ export abstract class ColumnBuilder< abstract generatedAlwaysAs( as: SQL | T['data'] | (() => SQL), config?: Partial>, - ): HasGenerated; + ): HasGenerated; /** @internal Sets the name of the column to the key within the table definition if a name was not given. */ setName(name: string) { diff --git a/drizzle-orm/src/mysql-core/columns/bigint.ts b/drizzle-orm/src/mysql-core/columns/bigint.ts index 7411c07ce..0973a1346 100644 --- a/drizzle-orm/src/mysql-core/columns/bigint.ts +++ b/drizzle-orm/src/mysql-core/columns/bigint.ts @@ -12,7 +12,6 @@ export type MySqlBigInt53BuilderInitial = MySqlBigInt53Bui data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlBigInt53Builder> @@ -60,7 +59,6 @@ export type MySqlBigInt64BuilderInitial = MySqlBigInt64Bui data: bigint; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class MySqlBigInt64Builder> diff --git a/drizzle-orm/src/mysql-core/columns/binary.ts b/drizzle-orm/src/mysql-core/columns/binary.ts index 7031b565c..e67006653 100644 --- a/drizzle-orm/src/mysql-core/columns/binary.ts +++ b/drizzle-orm/src/mysql-core/columns/binary.ts @@ -12,7 +12,6 @@ export type MySqlBinaryBuilderInitial = MySqlBinaryBuilder data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class MySqlBinaryBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/boolean.ts b/drizzle-orm/src/mysql-core/columns/boolean.ts index 9e786b6f9..2057496b6 100644 --- a/drizzle-orm/src/mysql-core/columns/boolean.ts +++ b/drizzle-orm/src/mysql-core/columns/boolean.ts @@ -11,7 +11,6 @@ export type MySqlBooleanBuilderInitial = MySqlBooleanBuild data: boolean; driverParam: number | boolean; enumValues: undefined; - generated: undefined; }>; export class MySqlBooleanBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/char.ts b/drizzle-orm/src/mysql-core/columns/char.ts index efcb7e65a..88492288e 100644 --- a/drizzle-orm/src/mysql-core/columns/char.ts +++ b/drizzle-orm/src/mysql-core/columns/char.ts @@ -12,7 +12,6 @@ export type MySqlCharBuilderInitial; export class MySqlCharBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/common.ts b/drizzle-orm/src/mysql-core/columns/common.ts index 9babc31da..2f1073e53 100644 --- a/drizzle-orm/src/mysql-core/columns/common.ts +++ b/drizzle-orm/src/mysql-core/columns/common.ts @@ -62,7 +62,9 @@ export abstract class MySqlColumnBuilder< return this; } - generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: MySqlGeneratedColumnConfig): HasGenerated { + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: MySqlGeneratedColumnConfig): HasGenerated { this.config.generated = { as, type: 'always', diff --git a/drizzle-orm/src/mysql-core/columns/custom.ts b/drizzle-orm/src/mysql-core/columns/custom.ts index 711b27813..50585bece 100644 --- a/drizzle-orm/src/mysql-core/columns/custom.ts +++ b/drizzle-orm/src/mysql-core/columns/custom.ts @@ -14,7 +14,6 @@ export type ConvertCustomConfig = MySqlDateBuilder<{ data: Date; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlDateBuilder> extends MySqlColumnBuilder { @@ -56,7 +55,6 @@ export type MySqlDateStringBuilderInitial = MySqlDateStrin data: string; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlDateStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/datetime.ts b/drizzle-orm/src/mysql-core/columns/datetime.ts index 61b062e8f..ea5b917b9 100644 --- a/drizzle-orm/src/mysql-core/columns/datetime.ts +++ b/drizzle-orm/src/mysql-core/columns/datetime.ts @@ -12,7 +12,6 @@ export type MySqlDateTimeBuilderInitial = MySqlDateTimeBui data: Date; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlDateTimeBuilder> @@ -70,7 +69,6 @@ export type MySqlDateTimeStringBuilderInitial = MySqlDateT data: string; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlDateTimeStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index 67cefb531..76b0ba8a1 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -12,7 +12,6 @@ export type MySqlDecimalBuilderInitial = MySqlDecimalBuild data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class MySqlDecimalBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index dfe5fca2e..bc23fc74c 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -12,7 +12,6 @@ export type MySqlDoubleBuilderInitial = MySqlDoubleBuilder data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlDoubleBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/enum.ts b/drizzle-orm/src/mysql-core/columns/enum.ts index 6a586ca7c..384e07d17 100644 --- a/drizzle-orm/src/mysql-core/columns/enum.ts +++ b/drizzle-orm/src/mysql-core/columns/enum.ts @@ -13,7 +13,6 @@ export type MySqlEnumColumnBuilderInitial; export class MySqlEnumColumnBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/float.ts b/drizzle-orm/src/mysql-core/columns/float.ts index 12ebd3e74..e368740a0 100644 --- a/drizzle-orm/src/mysql-core/columns/float.ts +++ b/drizzle-orm/src/mysql-core/columns/float.ts @@ -12,7 +12,6 @@ export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlFloatBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/int.ts b/drizzle-orm/src/mysql-core/columns/int.ts index aca0ea61e..79b93bdf7 100644 --- a/drizzle-orm/src/mysql-core/columns/int.ts +++ b/drizzle-orm/src/mysql-core/columns/int.ts @@ -12,7 +12,6 @@ export type MySqlIntBuilderInitial = MySqlIntBuilder<{ data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/json.ts b/drizzle-orm/src/mysql-core/columns/json.ts index ecb73ed82..12d11bd4a 100644 --- a/drizzle-orm/src/mysql-core/columns/json.ts +++ b/drizzle-orm/src/mysql-core/columns/json.ts @@ -11,7 +11,6 @@ export type MySqlJsonBuilderInitial = MySqlJsonBuilder<{ data: unknown; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class MySqlJsonBuilder> extends MySqlColumnBuilder { diff --git a/drizzle-orm/src/mysql-core/columns/mediumint.ts b/drizzle-orm/src/mysql-core/columns/mediumint.ts index 764969d31..7ba5cc944 100644 --- a/drizzle-orm/src/mysql-core/columns/mediumint.ts +++ b/drizzle-orm/src/mysql-core/columns/mediumint.ts @@ -13,7 +13,6 @@ export type MySqlMediumIntBuilderInitial = MySqlMediumIntB data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlMediumIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/real.ts b/drizzle-orm/src/mysql-core/columns/real.ts index 8b9eca794..c6b447310 100644 --- a/drizzle-orm/src/mysql-core/columns/real.ts +++ b/drizzle-orm/src/mysql-core/columns/real.ts @@ -12,7 +12,6 @@ export type MySqlRealBuilderInitial = MySqlRealBuilder<{ data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlRealBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/serial.ts b/drizzle-orm/src/mysql-core/columns/serial.ts index 88485d6b2..90fd7a2e5 100644 --- a/drizzle-orm/src/mysql-core/columns/serial.ts +++ b/drizzle-orm/src/mysql-core/columns/serial.ts @@ -23,7 +23,6 @@ export type MySqlSerialBuilderInitial = IsAutoincrement< data: number; driverParam: number; enumValues: undefined; - generated: undefined; }> > > diff --git a/drizzle-orm/src/mysql-core/columns/smallint.ts b/drizzle-orm/src/mysql-core/columns/smallint.ts index 482ff89ea..87083f0fa 100644 --- a/drizzle-orm/src/mysql-core/columns/smallint.ts +++ b/drizzle-orm/src/mysql-core/columns/smallint.ts @@ -13,7 +13,6 @@ export type MySqlSmallIntBuilderInitial = MySqlSmallIntBui data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlSmallIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/text.ts b/drizzle-orm/src/mysql-core/columns/text.ts index 18434a532..0604ef141 100644 --- a/drizzle-orm/src/mysql-core/columns/text.ts +++ b/drizzle-orm/src/mysql-core/columns/text.ts @@ -14,7 +14,6 @@ export type MySqlTextBuilderInitial; export class MySqlTextBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/time.ts b/drizzle-orm/src/mysql-core/columns/time.ts index 408453947..7ca5426ec 100644 --- a/drizzle-orm/src/mysql-core/columns/time.ts +++ b/drizzle-orm/src/mysql-core/columns/time.ts @@ -12,7 +12,6 @@ export type MySqlTimeBuilderInitial = MySqlTimeBuilder<{ data: string; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlTimeBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/timestamp.ts b/drizzle-orm/src/mysql-core/columns/timestamp.ts index 892f8e603..2ccc2925f 100644 --- a/drizzle-orm/src/mysql-core/columns/timestamp.ts +++ b/drizzle-orm/src/mysql-core/columns/timestamp.ts @@ -12,7 +12,6 @@ export type MySqlTimestampBuilderInitial = MySqlTimestampB data: Date; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlTimestampBuilder> @@ -64,7 +63,6 @@ export type MySqlTimestampStringBuilderInitial = MySqlTime data: string; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlTimestampStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/tinyint.ts b/drizzle-orm/src/mysql-core/columns/tinyint.ts index ee4ccdaa7..890f169bd 100644 --- a/drizzle-orm/src/mysql-core/columns/tinyint.ts +++ b/drizzle-orm/src/mysql-core/columns/tinyint.ts @@ -13,7 +13,6 @@ export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuild data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlTinyIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/varbinary.ts b/drizzle-orm/src/mysql-core/columns/varbinary.ts index bc0dde635..837de8dcb 100644 --- a/drizzle-orm/src/mysql-core/columns/varbinary.ts +++ b/drizzle-orm/src/mysql-core/columns/varbinary.ts @@ -12,7 +12,6 @@ export type MySqlVarBinaryBuilderInitial = MySqlVarBinaryB data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class MySqlVarBinaryBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/varchar.ts b/drizzle-orm/src/mysql-core/columns/varchar.ts index 32cfda7e9..6a335fef7 100644 --- a/drizzle-orm/src/mysql-core/columns/varchar.ts +++ b/drizzle-orm/src/mysql-core/columns/varchar.ts @@ -13,7 +13,6 @@ export type MySqlVarCharBuilderInitial; diff --git a/drizzle-orm/src/mysql-core/columns/year.ts b/drizzle-orm/src/mysql-core/columns/year.ts index 8a7a44410..4e4ae4faf 100644 --- a/drizzle-orm/src/mysql-core/columns/year.ts +++ b/drizzle-orm/src/mysql-core/columns/year.ts @@ -11,7 +11,6 @@ export type MySqlYearBuilderInitial = MySqlYearBuilder<{ data: number; driverParam: number; enumValues: undefined; - generated: undefined; }>; export class MySqlYearBuilder> extends MySqlColumnBuilder { diff --git a/drizzle-orm/src/operations.ts b/drizzle-orm/src/operations.ts index 6fb5cbd2e..573e05957 100644 --- a/drizzle-orm/src/operations.ts +++ b/drizzle-orm/src/operations.ts @@ -1,4 +1,5 @@ import type { AnyColumn, Column } from './column.ts'; +import type { GeneratedColumnConfig } from './index.ts'; import type { SQL } from './sql/sql.ts'; import type { Table } from './table.ts'; @@ -8,17 +9,16 @@ export type RequiredKeyOnly = T extends A }> ? TKey : never; -export type NotGenerated = T extends AnyColumn<{ - generated: undefined; -}> ? TKey - : never; - export type OptionalKeyOnly< TKey extends string, T extends Column, > = TKey extends RequiredKeyOnly ? never - : TKey extends NotGenerated ? TKey - : T['_']['generated'] extends object ? T['_']['generated']['type'] extends 'byDefault' ? TKey : never + : T extends { + _: { + generated: infer G; + }; + } ? G extends GeneratedColumnConfig ? G['type'] extends 'always' ? never : TKey + : TKey : never; // TODO: SQL -> SQLWrapper diff --git a/drizzle-orm/src/pg-core/columns/bigint.ts b/drizzle-orm/src/pg-core/columns/bigint.ts index 23e1e7f15..17ac0798b 100644 --- a/drizzle-orm/src/pg-core/columns/bigint.ts +++ b/drizzle-orm/src/pg-core/columns/bigint.ts @@ -14,7 +14,6 @@ export type PgBigInt53BuilderInitial = PgBigInt53Builder<{ data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class PgBigInt53Builder> @@ -56,7 +55,6 @@ export type PgBigInt64BuilderInitial = PgBigInt64Builder<{ data: bigint; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgBigInt64Builder> diff --git a/drizzle-orm/src/pg-core/columns/bigserial.ts b/drizzle-orm/src/pg-core/columns/bigserial.ts index ed4224354..0aa7e7a7f 100644 --- a/drizzle-orm/src/pg-core/columns/bigserial.ts +++ b/drizzle-orm/src/pg-core/columns/bigserial.ts @@ -20,7 +20,6 @@ export type PgBigSerial53BuilderInitial = NotNull< data: number; driverParam: number; enumValues: undefined; - generated: undefined; }> > >; @@ -71,7 +70,6 @@ export type PgBigSerial64BuilderInitial = NotNull< data: bigint; driverParam: string; enumValues: undefined; - generated: undefined; }> > >; diff --git a/drizzle-orm/src/pg-core/columns/boolean.ts b/drizzle-orm/src/pg-core/columns/boolean.ts index cd30895c7..e2d514864 100644 --- a/drizzle-orm/src/pg-core/columns/boolean.ts +++ b/drizzle-orm/src/pg-core/columns/boolean.ts @@ -11,7 +11,6 @@ export type PgBooleanBuilderInitial = PgBooleanBuilder<{ data: boolean; driverParam: boolean; enumValues: undefined; - generated: undefined; }>; export class PgBooleanBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/char.ts b/drizzle-orm/src/pg-core/columns/char.ts index 6629f08cc..2cc304221 100644 --- a/drizzle-orm/src/pg-core/columns/char.ts +++ b/drizzle-orm/src/pg-core/columns/char.ts @@ -12,7 +12,6 @@ export type PgCharBuilderInitial; export class PgCharBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/cidr.ts b/drizzle-orm/src/pg-core/columns/cidr.ts index 6caa3dc25..ab97536ee 100644 --- a/drizzle-orm/src/pg-core/columns/cidr.ts +++ b/drizzle-orm/src/pg-core/columns/cidr.ts @@ -11,7 +11,6 @@ export type PgCidrBuilderInitial = PgCidrBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgCidrBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index c2fbe8cb9..de2267cf3 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -83,13 +83,17 @@ export abstract class PgColumnBuilder< return this; } - generatedAlwaysAs(as: SQL | T['data'] | (() => SQL)): HasGenerated { + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL)): HasGenerated { this.config.generated = { as, type: 'always', mode: 'stored', }; - return this as any; + return this as HasGenerated; } /** @internal */ diff --git a/drizzle-orm/src/pg-core/columns/custom.ts b/drizzle-orm/src/pg-core/columns/custom.ts index b59169ed6..f4f622ff6 100644 --- a/drizzle-orm/src/pg-core/columns/custom.ts +++ b/drizzle-orm/src/pg-core/columns/custom.ts @@ -14,7 +14,6 @@ export type ConvertCustomConfig = PgDateBuilder<{ data: Date; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgDateBuilder> extends PgDateColumnBaseBuilder { @@ -54,7 +53,6 @@ export type PgDateStringBuilderInitial = PgDateStringBuild data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgDateStringBuilder> diff --git a/drizzle-orm/src/pg-core/columns/double-precision.ts b/drizzle-orm/src/pg-core/columns/double-precision.ts index 77245ea45..942085bc1 100644 --- a/drizzle-orm/src/pg-core/columns/double-precision.ts +++ b/drizzle-orm/src/pg-core/columns/double-precision.ts @@ -11,7 +11,6 @@ export type PgDoublePrecisionBuilderInitial = PgDoublePrec data: number; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class PgDoublePrecisionBuilder> diff --git a/drizzle-orm/src/pg-core/columns/enum.ts b/drizzle-orm/src/pg-core/columns/enum.ts index 7712ca606..db7905b39 100644 --- a/drizzle-orm/src/pg-core/columns/enum.ts +++ b/drizzle-orm/src/pg-core/columns/enum.ts @@ -13,7 +13,6 @@ export type PgEnumColumnBuilderInitial; const isPgEnumSym = Symbol.for('drizzle:isPgEnum'); diff --git a/drizzle-orm/src/pg-core/columns/inet.ts b/drizzle-orm/src/pg-core/columns/inet.ts index 6b6210fcf..741bbdf86 100644 --- a/drizzle-orm/src/pg-core/columns/inet.ts +++ b/drizzle-orm/src/pg-core/columns/inet.ts @@ -11,7 +11,6 @@ export type PgInetBuilderInitial = PgInetBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgInetBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/integer.ts b/drizzle-orm/src/pg-core/columns/integer.ts index 6c88126d2..9be92bb34 100644 --- a/drizzle-orm/src/pg-core/columns/integer.ts +++ b/drizzle-orm/src/pg-core/columns/integer.ts @@ -12,7 +12,6 @@ export type PgIntegerBuilderInitial = PgIntegerBuilder<{ data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class PgIntegerBuilder> diff --git a/drizzle-orm/src/pg-core/columns/interval.ts b/drizzle-orm/src/pg-core/columns/interval.ts index 4d3ed4588..8f81e9867 100644 --- a/drizzle-orm/src/pg-core/columns/interval.ts +++ b/drizzle-orm/src/pg-core/columns/interval.ts @@ -13,7 +13,6 @@ export type PgIntervalBuilderInitial = PgIntervalBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgIntervalBuilder> diff --git a/drizzle-orm/src/pg-core/columns/json.ts b/drizzle-orm/src/pg-core/columns/json.ts index 3c440c7d2..deed256b9 100644 --- a/drizzle-orm/src/pg-core/columns/json.ts +++ b/drizzle-orm/src/pg-core/columns/json.ts @@ -11,7 +11,6 @@ export type PgJsonBuilderInitial = PgJsonBuilder<{ data: unknown; driverParam: unknown; enumValues: undefined; - generated: undefined; }>; export class PgJsonBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/jsonb.ts b/drizzle-orm/src/pg-core/columns/jsonb.ts index 3407730db..14af7c9e9 100644 --- a/drizzle-orm/src/pg-core/columns/jsonb.ts +++ b/drizzle-orm/src/pg-core/columns/jsonb.ts @@ -11,7 +11,6 @@ export type PgJsonbBuilderInitial = PgJsonbBuilder<{ data: unknown; driverParam: unknown; enumValues: undefined; - generated: undefined; }>; export class PgJsonbBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/line.ts b/drizzle-orm/src/pg-core/columns/line.ts index 014140797..9378d1aa1 100644 --- a/drizzle-orm/src/pg-core/columns/line.ts +++ b/drizzle-orm/src/pg-core/columns/line.ts @@ -13,7 +13,6 @@ export type PgLineBuilderInitial = PgLineBuilder<{ data: [number, number, number]; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class PgLineBuilder> extends PgColumnBuilder { @@ -58,7 +57,6 @@ export type PgLineABCBuilderInitial = PgLineABCBuilder<{ data: { a: number; b: number; c: number }; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgLineABCBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/macaddr.ts b/drizzle-orm/src/pg-core/columns/macaddr.ts index bfc4511f4..bcd8b02bc 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr.ts @@ -11,7 +11,6 @@ export type PgMacaddrBuilderInitial = PgMacaddrBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgMacaddrBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/macaddr8.ts b/drizzle-orm/src/pg-core/columns/macaddr8.ts index 6c4218de0..e9e3e4bef 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr8.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr8.ts @@ -11,7 +11,6 @@ export type PgMacaddr8BuilderInitial = PgMacaddr8Builder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgMacaddr8Builder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/numeric.ts b/drizzle-orm/src/pg-core/columns/numeric.ts index efeb4ab97..fc58d9859 100644 --- a/drizzle-orm/src/pg-core/columns/numeric.ts +++ b/drizzle-orm/src/pg-core/columns/numeric.ts @@ -12,7 +12,6 @@ export type PgNumericBuilderInitial = PgNumericBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgNumericBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/point.ts b/drizzle-orm/src/pg-core/columns/point.ts index 827579ad8..c204aedea 100644 --- a/drizzle-orm/src/pg-core/columns/point.ts +++ b/drizzle-orm/src/pg-core/columns/point.ts @@ -13,7 +13,6 @@ export type PgPointTupleBuilderInitial = PgPointTupleBuild data: [number, number]; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class PgPointTupleBuilder> @@ -63,7 +62,6 @@ export type PgPointObjectBuilderInitial = PgPointObjectBui data: { x: number; y: number }; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgPointObjectBuilder> diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts index 853c3dff9..93632d31c 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts @@ -14,7 +14,6 @@ export type PgGeometryBuilderInitial = PgGeometryBuilder<{ data: [number, number]; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgGeometryBuilder> extends PgColumnBuilder { @@ -58,7 +57,6 @@ export type PgGeometryObjectBuilderInitial = PgGeometryObj data: { x: number; y: number }; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgGeometryObjectBuilder> diff --git a/drizzle-orm/src/pg-core/columns/real.ts b/drizzle-orm/src/pg-core/columns/real.ts index 0e3de4b2e..b3c339c9b 100644 --- a/drizzle-orm/src/pg-core/columns/real.ts +++ b/drizzle-orm/src/pg-core/columns/real.ts @@ -11,7 +11,6 @@ export type PgRealBuilderInitial = PgRealBuilder<{ data: number; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class PgRealBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/serial.ts b/drizzle-orm/src/pg-core/columns/serial.ts index 6a0196c38..261ef2af9 100644 --- a/drizzle-orm/src/pg-core/columns/serial.ts +++ b/drizzle-orm/src/pg-core/columns/serial.ts @@ -19,7 +19,6 @@ export type PgSerialBuilderInitial = NotNull< data: number; driverParam: number; enumValues: undefined; - generated: undefined; }> > >; diff --git a/drizzle-orm/src/pg-core/columns/smallint.ts b/drizzle-orm/src/pg-core/columns/smallint.ts index 1cdfe141f..e662904b5 100644 --- a/drizzle-orm/src/pg-core/columns/smallint.ts +++ b/drizzle-orm/src/pg-core/columns/smallint.ts @@ -12,7 +12,6 @@ export type PgSmallIntBuilderInitial = PgSmallIntBuilder<{ data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class PgSmallIntBuilder> diff --git a/drizzle-orm/src/pg-core/columns/smallserial.ts b/drizzle-orm/src/pg-core/columns/smallserial.ts index 456dc47f7..c92fc8350 100644 --- a/drizzle-orm/src/pg-core/columns/smallserial.ts +++ b/drizzle-orm/src/pg-core/columns/smallserial.ts @@ -19,7 +19,6 @@ export type PgSmallSerialBuilderInitial = NotNull< data: number; driverParam: number; enumValues: undefined; - generated: undefined; }> > >; diff --git a/drizzle-orm/src/pg-core/columns/text.ts b/drizzle-orm/src/pg-core/columns/text.ts index 6845f0e74..980f0ec2f 100644 --- a/drizzle-orm/src/pg-core/columns/text.ts +++ b/drizzle-orm/src/pg-core/columns/text.ts @@ -12,7 +12,6 @@ type PgTextBuilderInitial; export class PgTextBuilder< diff --git a/drizzle-orm/src/pg-core/columns/time.ts b/drizzle-orm/src/pg-core/columns/time.ts index 9b3ff51e0..b9b52fd79 100644 --- a/drizzle-orm/src/pg-core/columns/time.ts +++ b/drizzle-orm/src/pg-core/columns/time.ts @@ -14,7 +14,6 @@ export type PgTimeBuilderInitial = PgTimeBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgTimeBuilder> extends PgDateColumnBaseBuilder< diff --git a/drizzle-orm/src/pg-core/columns/timestamp.ts b/drizzle-orm/src/pg-core/columns/timestamp.ts index 6879106e0..f5a5cb0a6 100644 --- a/drizzle-orm/src/pg-core/columns/timestamp.ts +++ b/drizzle-orm/src/pg-core/columns/timestamp.ts @@ -13,7 +13,6 @@ export type PgTimestampBuilderInitial = PgTimestampBuilder data: Date; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgTimestampBuilder> @@ -75,7 +74,6 @@ export type PgTimestampStringBuilderInitial = PgTimestampS data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgTimestampStringBuilder> diff --git a/drizzle-orm/src/pg-core/columns/uuid.ts b/drizzle-orm/src/pg-core/columns/uuid.ts index d0e5a6830..c8455d372 100644 --- a/drizzle-orm/src/pg-core/columns/uuid.ts +++ b/drizzle-orm/src/pg-core/columns/uuid.ts @@ -12,7 +12,6 @@ export type PgUUIDBuilderInitial = PgUUIDBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgUUIDBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/varchar.ts b/drizzle-orm/src/pg-core/columns/varchar.ts index 78ee0db96..192262bef 100644 --- a/drizzle-orm/src/pg-core/columns/varchar.ts +++ b/drizzle-orm/src/pg-core/columns/varchar.ts @@ -12,7 +12,6 @@ export type PgVarcharBuilderInitial; export class PgVarcharBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts index 81eea6b2f..f1d692821 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts @@ -12,7 +12,6 @@ export type PgBinaryVectorBuilderInitial = PgBinaryVectorB data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgBinaryVectorBuilder> diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts index e12d0d22f..1c89e7b60 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts @@ -12,7 +12,6 @@ export type PgHalfVectorBuilderInitial = PgHalfVectorBuild data: number[]; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgHalfVectorBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts index 3881b338f..4817fa51f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts @@ -12,7 +12,6 @@ export type PgSparseVectorBuilderInitial = PgSparseVectorB data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgSparseVectorBuilder> diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts index eaac075dc..84fb54964 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts @@ -12,7 +12,6 @@ export type PgVectorBuilderInitial = PgVectorBuilder<{ data: number[]; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgVectorBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index 22deb3a84..d9f3fc7c6 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -14,7 +14,6 @@ export type SQLiteBigIntBuilderInitial = SQLiteBigIntBuild data: bigint; driverParam: Buffer; enumValues: undefined; - generated: undefined; }>; export class SQLiteBigIntBuilder> @@ -57,7 +56,6 @@ export type SQLiteBlobJsonBuilderInitial = SQLiteBlobJsonB data: unknown; driverParam: Buffer; enumValues: undefined; - generated: undefined; }>; export class SQLiteBlobJsonBuilder> @@ -103,7 +101,6 @@ export type SQLiteBlobBufferBuilderInitial = SQLiteBlobBuf data: Buffer; driverParam: Buffer; enumValues: undefined; - generated: undefined; }>; export class SQLiteBlobBufferBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/common.ts b/drizzle-orm/src/sqlite-core/columns/common.ts index 0fd985537..953e5692d 100644 --- a/drizzle-orm/src/sqlite-core/columns/common.ts +++ b/drizzle-orm/src/sqlite-core/columns/common.ts @@ -63,7 +63,9 @@ export abstract class SQLiteColumnBuilder< return this; } - generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SQLiteGeneratedColumnConfig): HasGenerated { + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SQLiteGeneratedColumnConfig): HasGenerated { this.config.generated = { as, type: 'always', diff --git a/drizzle-orm/src/sqlite-core/columns/custom.ts b/drizzle-orm/src/sqlite-core/columns/custom.ts index 6ece801c5..b23d6442f 100644 --- a/drizzle-orm/src/sqlite-core/columns/custom.ts +++ b/drizzle-orm/src/sqlite-core/columns/custom.ts @@ -14,7 +14,6 @@ export type ConvertCustomConfig = SQLiteIntegerBui data: number; driverParam: number; enumValues: undefined; - generated: undefined; }>; export class SQLiteIntegerBuilder> @@ -103,7 +102,6 @@ export type SQLiteTimestampBuilderInitial = SQLiteTimestam data: Date; driverParam: number; enumValues: undefined; - generated: undefined; }>; export class SQLiteTimestampBuilder> @@ -165,7 +163,6 @@ export type SQLiteBooleanBuilderInitial = SQLiteBooleanBui data: boolean; driverParam: number; enumValues: undefined; - generated: undefined; }>; export class SQLiteBooleanBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/numeric.ts b/drizzle-orm/src/sqlite-core/columns/numeric.ts index 93dfc4c3d..9505367a2 100644 --- a/drizzle-orm/src/sqlite-core/columns/numeric.ts +++ b/drizzle-orm/src/sqlite-core/columns/numeric.ts @@ -11,7 +11,6 @@ export type SQLiteNumericBuilderInitial = SQLiteNumericBui data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class SQLiteNumericBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/real.ts b/drizzle-orm/src/sqlite-core/columns/real.ts index cd7cf5d01..8821eb275 100644 --- a/drizzle-orm/src/sqlite-core/columns/real.ts +++ b/drizzle-orm/src/sqlite-core/columns/real.ts @@ -11,7 +11,6 @@ export type SQLiteRealBuilderInitial = SQLiteRealBuilder<{ data: number; driverParam: number; enumValues: undefined; - generated: undefined; }>; export class SQLiteRealBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/text.ts b/drizzle-orm/src/sqlite-core/columns/text.ts index 84c71fb20..241eb860d 100644 --- a/drizzle-orm/src/sqlite-core/columns/text.ts +++ b/drizzle-orm/src/sqlite-core/columns/text.ts @@ -12,7 +12,6 @@ export type SQLiteTextBuilderInitial; export class SQLiteTextBuilder> extends SQLiteColumnBuilder< diff --git a/drizzle-orm/type-tests/mysql/generated-columns.ts b/drizzle-orm/type-tests/mysql/generated-columns.ts index d045fe1b3..56b9d4412 100644 --- a/drizzle-orm/type-tests/mysql/generated-columns.ts +++ b/drizzle-orm/type-tests/mysql/generated-columns.ts @@ -17,6 +17,7 @@ const users = mysqlTable( ).$type(), // There is no way for drizzle to detect nullability in these cases. This is how the user can work around it }, ); + { type User = typeof users.$inferSelect; type NewUser = typeof users.$inferInsert; diff --git a/drizzle-orm/type-tests/sqlite/generated-columns.ts b/drizzle-orm/type-tests/sqlite/generated-columns.ts index 57ffea989..f1474baed 100644 --- a/drizzle-orm/type-tests/sqlite/generated-columns.ts +++ b/drizzle-orm/type-tests/sqlite/generated-columns.ts @@ -11,12 +11,14 @@ const users = sqliteTable( firstName: text('first_name', { length: 255 }), lastName: text('last_name', { length: 255 }), email: text('email').notNull(), - fullName: text('full_name').generatedAlwaysAs(sql`concat_ws(first_name, ' ', last_name)`), + fullName: text('full_name') + .generatedAlwaysAs(sql`concat_ws(first_name, ' ', last_name)`), upperName: text('upper_name').generatedAlwaysAs( sql` case when first_name is null then null else upper(first_name) end `, ).$type(), // There is no way for drizzle to detect nullability in these cases. This is how the user can work around it }, ); + { type User = typeof users.$inferSelect; type NewUser = typeof users.$inferInsert; From dfbb42281ffaf95fa27c259879e5cafb85a14a3b Mon Sep 17 00:00:00 2001 From: Subramanya Chakravarthy Date: Wed, 13 Nov 2024 20:17:17 +0530 Subject: [PATCH 348/492] Fix Drizzle ORM for expo-sqlite (#3197) * Fix Drizzle ORM for expo-sqlite closes #3195 * bump expo-sqlite version to 14.0.0 in package.json and pnpm-lock.yaml --------- Co-authored-by: Andrii Sherman --- drizzle-orm/package.json | 4 ++-- drizzle-orm/src/expo-sqlite/driver.ts | 2 +- drizzle-orm/src/expo-sqlite/query.ts | 2 +- drizzle-orm/src/expo-sqlite/session.ts | 2 +- pnpm-lock.yaml | 10 +++++----- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index b2b204ead..154a93922 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -63,7 +63,7 @@ "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", - "expo-sqlite": ">=13.2.0", + "expo-sqlite": ">=14.0.0", "knex": "*", "kysely": "*", "mysql2": ">=2", @@ -186,7 +186,7 @@ "better-sqlite3": "^8.4.0", "bun-types": "^0.6.6", "cpy": "^10.1.0", - "expo-sqlite": "^13.2.0", + "expo-sqlite": "^14.0.0", "knex": "^2.4.2", "kysely": "^0.25.0", "mysql2": "^3.3.3", diff --git a/drizzle-orm/src/expo-sqlite/driver.ts b/drizzle-orm/src/expo-sqlite/driver.ts index 6d9ebe375..fce53eed2 100644 --- a/drizzle-orm/src/expo-sqlite/driver.ts +++ b/drizzle-orm/src/expo-sqlite/driver.ts @@ -1,4 +1,4 @@ -import type { SQLiteDatabase, SQLiteRunResult } from 'expo-sqlite/next'; +import type { SQLiteDatabase, SQLiteRunResult } from 'expo-sqlite'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { diff --git a/drizzle-orm/src/expo-sqlite/query.ts b/drizzle-orm/src/expo-sqlite/query.ts index 8d9c5e4d9..a38fc3046 100644 --- a/drizzle-orm/src/expo-sqlite/query.ts +++ b/drizzle-orm/src/expo-sqlite/query.ts @@ -1,4 +1,4 @@ -import { addDatabaseChangeListener } from 'expo-sqlite/next'; +import { addDatabaseChangeListener } from 'expo-sqlite'; import { useEffect, useState } from 'react'; import { is } from '~/entity.ts'; import { SQL } from '~/sql/sql.ts'; diff --git a/drizzle-orm/src/expo-sqlite/session.ts b/drizzle-orm/src/expo-sqlite/session.ts index 9fcc4b93c..cb880ac6e 100644 --- a/drizzle-orm/src/expo-sqlite/session.ts +++ b/drizzle-orm/src/expo-sqlite/session.ts @@ -1,4 +1,4 @@ -import type { SQLiteDatabase, SQLiteRunResult, SQLiteStatement } from 'expo-sqlite/next'; +import type { SQLiteDatabase, SQLiteRunResult, SQLiteStatement } from 'expo-sqlite'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { NoopLogger } from '~/logger.ts'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 468f12ca6..3eefe9fd5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -370,8 +370,8 @@ importers: specifier: ^10.1.0 version: 10.1.0 expo-sqlite: - specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + specifier: ^14.0.0 + version: 14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -6127,8 +6127,8 @@ packages: expo-modules-core@1.12.11: resolution: {integrity: sha512-CF5G6hZo/6uIUz6tj4dNRlvE5L4lakYukXPqz5ZHQ+6fLk1NQVZbRdpHjMkxO/QSBQcKUzG/ngeytpoJus7poQ==} - expo-sqlite@13.4.0: - resolution: {integrity: sha512-5f7d2EDM+pgerM33KndtX4gWw2nuVaXY68nnqx7PhkiYeyEmeNfZ29bIFtpBzNb/L5l0/DTtRxuSqftxbknFtw==} + expo-sqlite@14.0.6: + resolution: {integrity: sha512-T3YNx7LT7lM4UQRgi8ml+cj0Wf3Ep09+B4CVaWtUCjdyYJIZjsHDT65hypKG+r6btTLLEd11hjlrstNQhzt5gQ==} peerDependencies: expo: '*' @@ -17315,7 +17315,7 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-sqlite@14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/websql': 1.0.1 expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) From 1dc75c02f35691c0a07d12448c46430651576061 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Wed, 13 Nov 2024 16:53:13 +0200 Subject: [PATCH 349/492] added method overridingSystemValue to PgInsertBuilder --- .gitignore | 1 + drizzle-orm/src/column.ts | 2 +- drizzle-orm/src/mysql-core/columns/bigint.ts | 2 - drizzle-orm/src/mysql-core/columns/binary.ts | 1 - drizzle-orm/src/mysql-core/columns/boolean.ts | 1 - drizzle-orm/src/mysql-core/columns/char.ts | 1 - drizzle-orm/src/mysql-core/columns/custom.ts | 1 - drizzle-orm/src/mysql-core/columns/date.ts | 2 - .../src/mysql-core/columns/datetime.ts | 2 - drizzle-orm/src/mysql-core/columns/decimal.ts | 1 - drizzle-orm/src/mysql-core/columns/double.ts | 1 - drizzle-orm/src/mysql-core/columns/enum.ts | 1 - drizzle-orm/src/mysql-core/columns/float.ts | 1 - drizzle-orm/src/mysql-core/columns/int.ts | 1 - drizzle-orm/src/mysql-core/columns/json.ts | 1 - .../src/mysql-core/columns/mediumint.ts | 1 - drizzle-orm/src/mysql-core/columns/real.ts | 1 - .../src/mysql-core/columns/smallint.ts | 1 - drizzle-orm/src/mysql-core/columns/text.ts | 1 - drizzle-orm/src/mysql-core/columns/time.ts | 1 - .../src/mysql-core/columns/timestamp.ts | 2 - drizzle-orm/src/mysql-core/columns/tinyint.ts | 1 - .../src/mysql-core/columns/varbinary.ts | 1 - drizzle-orm/src/mysql-core/columns/varchar.ts | 1 - drizzle-orm/src/mysql-core/columns/year.ts | 1 - drizzle-orm/src/operations.ts | 17 ------ drizzle-orm/src/pg-core/columns/bigint.ts | 2 - drizzle-orm/src/pg-core/columns/bigserial.ts | 2 - drizzle-orm/src/pg-core/columns/boolean.ts | 1 - drizzle-orm/src/pg-core/columns/char.ts | 1 - drizzle-orm/src/pg-core/columns/cidr.ts | 1 - drizzle-orm/src/pg-core/columns/common.ts | 1 - drizzle-orm/src/pg-core/columns/custom.ts | 1 - drizzle-orm/src/pg-core/columns/date.ts | 1 - .../src/pg-core/columns/double-precision.ts | 1 - drizzle-orm/src/pg-core/columns/enum.ts | 1 - drizzle-orm/src/pg-core/columns/inet.ts | 1 - drizzle-orm/src/pg-core/columns/integer.ts | 3 +- drizzle-orm/src/pg-core/columns/interval.ts | 1 - drizzle-orm/src/pg-core/columns/json.ts | 1 - drizzle-orm/src/pg-core/columns/jsonb.ts | 1 - drizzle-orm/src/pg-core/columns/line.ts | 2 - drizzle-orm/src/pg-core/columns/macaddr.ts | 1 - drizzle-orm/src/pg-core/columns/macaddr8.ts | 1 - drizzle-orm/src/pg-core/columns/numeric.ts | 1 - drizzle-orm/src/pg-core/columns/point.ts | 2 - .../columns/postgis_extension/geometry.ts | 2 - drizzle-orm/src/pg-core/columns/real.ts | 1 - drizzle-orm/src/pg-core/columns/smallint.ts | 1 - .../src/pg-core/columns/smallserial.ts | 1 - drizzle-orm/src/pg-core/columns/text.ts | 1 - drizzle-orm/src/pg-core/columns/time.ts | 1 - drizzle-orm/src/pg-core/columns/timestamp.ts | 1 - drizzle-orm/src/pg-core/columns/uuid.ts | 1 - drizzle-orm/src/pg-core/columns/varchar.ts | 1 - .../pg-core/columns/vector_extension/bit.ts | 1 - .../columns/vector_extension/halfvec.ts | 1 - .../columns/vector_extension/sparsevec.ts | 1 - .../columns/vector_extension/vector.ts | 1 - drizzle-orm/src/pg-core/dialect.ts | 6 ++- .../src/pg-core/query-builders/insert.ts | 28 +++++++--- drizzle-orm/src/sqlite-core/columns/blob.ts | 3 -- drizzle-orm/src/sqlite-core/columns/custom.ts | 1 - .../src/sqlite-core/columns/integer.ts | 3 -- .../src/sqlite-core/columns/numeric.ts | 1 - drizzle-orm/src/sqlite-core/columns/real.ts | 1 - drizzle-orm/src/sqlite-core/columns/text.ts | 2 - drizzle-orm/type-tests/mysql/tables.ts | 16 ++++++ drizzle-orm/type-tests/pg/insert.ts | 27 +++++++--- drizzle-orm/type-tests/pg/tables.ts | 29 ++++++++--- drizzle-orm/type-tests/sqlite/tables.ts | 6 +++ integration-tests/tests/pg/pg-common.ts | 52 ++++++++++++++++--- 72 files changed, 137 insertions(+), 125 deletions(-) diff --git a/.gitignore b/.gitignore index 45788cac5..3d7b1e447 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ dist-dts rollup.config-*.mjs *.log .DS_Store +drizzle-seed/src/test.ts \ No newline at end of file diff --git a/drizzle-orm/src/column.ts b/drizzle-orm/src/column.ts index 9865d2849..1396e3a61 100644 --- a/drizzle-orm/src/column.ts +++ b/drizzle-orm/src/column.ts @@ -38,7 +38,7 @@ export type ColumnTypeConfig, enumValues: T['enumValues']; baseColumn: T extends { baseColumn: infer U } ? U : unknown; generated: GeneratedColumnConfig | undefined; - identity: T["identity"]; + identity: undefined | 'always' | 'byDefault'; } & TTypeConfig; export type ColumnRuntimeConfig = ColumnBuilderRuntimeConfig< diff --git a/drizzle-orm/src/mysql-core/columns/bigint.ts b/drizzle-orm/src/mysql-core/columns/bigint.ts index 2dc7cb4bc..7411c07ce 100644 --- a/drizzle-orm/src/mysql-core/columns/bigint.ts +++ b/drizzle-orm/src/mysql-core/columns/bigint.ts @@ -13,7 +13,6 @@ export type MySqlBigInt53BuilderInitial = MySqlBigInt53Bui driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlBigInt53Builder> @@ -62,7 +61,6 @@ export type MySqlBigInt64BuilderInitial = MySqlBigInt64Bui driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlBigInt64Builder> diff --git a/drizzle-orm/src/mysql-core/columns/binary.ts b/drizzle-orm/src/mysql-core/columns/binary.ts index a9df0b5f1..7031b565c 100644 --- a/drizzle-orm/src/mysql-core/columns/binary.ts +++ b/drizzle-orm/src/mysql-core/columns/binary.ts @@ -13,7 +13,6 @@ export type MySqlBinaryBuilderInitial = MySqlBinaryBuilder driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlBinaryBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/boolean.ts b/drizzle-orm/src/mysql-core/columns/boolean.ts index 01129244e..9e786b6f9 100644 --- a/drizzle-orm/src/mysql-core/columns/boolean.ts +++ b/drizzle-orm/src/mysql-core/columns/boolean.ts @@ -12,7 +12,6 @@ export type MySqlBooleanBuilderInitial = MySqlBooleanBuild driverParam: number | boolean; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlBooleanBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/char.ts b/drizzle-orm/src/mysql-core/columns/char.ts index 02eb9a8a7..efcb7e65a 100644 --- a/drizzle-orm/src/mysql-core/columns/char.ts +++ b/drizzle-orm/src/mysql-core/columns/char.ts @@ -13,7 +13,6 @@ export type MySqlCharBuilderInitial; export class MySqlCharBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/custom.ts b/drizzle-orm/src/mysql-core/columns/custom.ts index 2dcde8d96..711b27813 100644 --- a/drizzle-orm/src/mysql-core/columns/custom.ts +++ b/drizzle-orm/src/mysql-core/columns/custom.ts @@ -15,7 +15,6 @@ export type ConvertCustomConfig = MySqlDateBuilder<{ driverParam: string | number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlDateBuilder> extends MySqlColumnBuilder { @@ -58,7 +57,6 @@ export type MySqlDateStringBuilderInitial = MySqlDateStrin driverParam: string | number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlDateStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/datetime.ts b/drizzle-orm/src/mysql-core/columns/datetime.ts index ae0ad90ed..61b062e8f 100644 --- a/drizzle-orm/src/mysql-core/columns/datetime.ts +++ b/drizzle-orm/src/mysql-core/columns/datetime.ts @@ -13,7 +13,6 @@ export type MySqlDateTimeBuilderInitial = MySqlDateTimeBui driverParam: string | number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlDateTimeBuilder> @@ -72,7 +71,6 @@ export type MySqlDateTimeStringBuilderInitial = MySqlDateT driverParam: string | number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlDateTimeStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index b3a689471..67cefb531 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -13,7 +13,6 @@ export type MySqlDecimalBuilderInitial = MySqlDecimalBuild driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlDecimalBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index fbd0d3b37..dfe5fca2e 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -13,7 +13,6 @@ export type MySqlDoubleBuilderInitial = MySqlDoubleBuilder driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlDoubleBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/enum.ts b/drizzle-orm/src/mysql-core/columns/enum.ts index 7d3b2f2be..6a586ca7c 100644 --- a/drizzle-orm/src/mysql-core/columns/enum.ts +++ b/drizzle-orm/src/mysql-core/columns/enum.ts @@ -14,7 +14,6 @@ export type MySqlEnumColumnBuilderInitial; export class MySqlEnumColumnBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/float.ts b/drizzle-orm/src/mysql-core/columns/float.ts index 62537d638..12ebd3e74 100644 --- a/drizzle-orm/src/mysql-core/columns/float.ts +++ b/drizzle-orm/src/mysql-core/columns/float.ts @@ -13,7 +13,6 @@ export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlFloatBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/int.ts b/drizzle-orm/src/mysql-core/columns/int.ts index 7860a5c96..aca0ea61e 100644 --- a/drizzle-orm/src/mysql-core/columns/int.ts +++ b/drizzle-orm/src/mysql-core/columns/int.ts @@ -13,7 +13,6 @@ export type MySqlIntBuilderInitial = MySqlIntBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/json.ts b/drizzle-orm/src/mysql-core/columns/json.ts index 66d2899d0..ecb73ed82 100644 --- a/drizzle-orm/src/mysql-core/columns/json.ts +++ b/drizzle-orm/src/mysql-core/columns/json.ts @@ -12,7 +12,6 @@ export type MySqlJsonBuilderInitial = MySqlJsonBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlJsonBuilder> extends MySqlColumnBuilder { diff --git a/drizzle-orm/src/mysql-core/columns/mediumint.ts b/drizzle-orm/src/mysql-core/columns/mediumint.ts index a8c9c0498..764969d31 100644 --- a/drizzle-orm/src/mysql-core/columns/mediumint.ts +++ b/drizzle-orm/src/mysql-core/columns/mediumint.ts @@ -14,7 +14,6 @@ export type MySqlMediumIntBuilderInitial = MySqlMediumIntB driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlMediumIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/real.ts b/drizzle-orm/src/mysql-core/columns/real.ts index e7b157537..8b9eca794 100644 --- a/drizzle-orm/src/mysql-core/columns/real.ts +++ b/drizzle-orm/src/mysql-core/columns/real.ts @@ -13,7 +13,6 @@ export type MySqlRealBuilderInitial = MySqlRealBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlRealBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/smallint.ts b/drizzle-orm/src/mysql-core/columns/smallint.ts index ebf1def13..482ff89ea 100644 --- a/drizzle-orm/src/mysql-core/columns/smallint.ts +++ b/drizzle-orm/src/mysql-core/columns/smallint.ts @@ -14,7 +14,6 @@ export type MySqlSmallIntBuilderInitial = MySqlSmallIntBui driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlSmallIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/text.ts b/drizzle-orm/src/mysql-core/columns/text.ts index f7d8a3eab..18434a532 100644 --- a/drizzle-orm/src/mysql-core/columns/text.ts +++ b/drizzle-orm/src/mysql-core/columns/text.ts @@ -15,7 +15,6 @@ export type MySqlTextBuilderInitial; export class MySqlTextBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/time.ts b/drizzle-orm/src/mysql-core/columns/time.ts index 672f3eda3..408453947 100644 --- a/drizzle-orm/src/mysql-core/columns/time.ts +++ b/drizzle-orm/src/mysql-core/columns/time.ts @@ -13,7 +13,6 @@ export type MySqlTimeBuilderInitial = MySqlTimeBuilder<{ driverParam: string | number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlTimeBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/timestamp.ts b/drizzle-orm/src/mysql-core/columns/timestamp.ts index 86ccf59a9..892f8e603 100644 --- a/drizzle-orm/src/mysql-core/columns/timestamp.ts +++ b/drizzle-orm/src/mysql-core/columns/timestamp.ts @@ -13,7 +13,6 @@ export type MySqlTimestampBuilderInitial = MySqlTimestampB driverParam: string | number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlTimestampBuilder> @@ -66,7 +65,6 @@ export type MySqlTimestampStringBuilderInitial = MySqlTime driverParam: string | number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlTimestampStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/tinyint.ts b/drizzle-orm/src/mysql-core/columns/tinyint.ts index a221fdab5..ee4ccdaa7 100644 --- a/drizzle-orm/src/mysql-core/columns/tinyint.ts +++ b/drizzle-orm/src/mysql-core/columns/tinyint.ts @@ -14,7 +14,6 @@ export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuild driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlTinyIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/varbinary.ts b/drizzle-orm/src/mysql-core/columns/varbinary.ts index bf8e32ce1..bc0dde635 100644 --- a/drizzle-orm/src/mysql-core/columns/varbinary.ts +++ b/drizzle-orm/src/mysql-core/columns/varbinary.ts @@ -13,7 +13,6 @@ export type MySqlVarBinaryBuilderInitial = MySqlVarBinaryB driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlVarBinaryBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/varchar.ts b/drizzle-orm/src/mysql-core/columns/varchar.ts index 2905d91ef..32cfda7e9 100644 --- a/drizzle-orm/src/mysql-core/columns/varchar.ts +++ b/drizzle-orm/src/mysql-core/columns/varchar.ts @@ -14,7 +14,6 @@ export type MySqlVarCharBuilderInitial; diff --git a/drizzle-orm/src/mysql-core/columns/year.ts b/drizzle-orm/src/mysql-core/columns/year.ts index 8bcd923f5..8a7a44410 100644 --- a/drizzle-orm/src/mysql-core/columns/year.ts +++ b/drizzle-orm/src/mysql-core/columns/year.ts @@ -12,7 +12,6 @@ export type MySqlYearBuilderInitial = MySqlYearBuilder<{ driverParam: number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class MySqlYearBuilder> extends MySqlColumnBuilder { diff --git a/drizzle-orm/src/operations.ts b/drizzle-orm/src/operations.ts index cfb28e6d3..f36274dc3 100644 --- a/drizzle-orm/src/operations.ts +++ b/drizzle-orm/src/operations.ts @@ -13,21 +13,6 @@ export type NotGenerated = T extends AnyC }> ? TKey : never; -// export type OptionalKeyOnly< -// TKey extends string, -// T extends Column, -// // OverrideT extends boolean | undefined = false -// > = TKey extends RequiredKeyOnly ? never -// : TKey extends NotGenerated ? TKey -// : T['_']['generated'] extends object ? T['_']['generated']['type'] extends 'byDefault' ? TKey -// : never -// // ( -// // T['_']['identity'] extends 'always'? -// // OverrideT extends true? TKey: never -// // : never -// // ) -// : never; - export type OptionalKeyOnly< TKey extends string, T extends Column, @@ -51,8 +36,6 @@ export type IdentityColumns< : never ); -// byDefault -> accept -// always -> accept only if overide and always // TODO: SQL -> SQLWrapper export type SelectedFieldsFlat = Record< string, diff --git a/drizzle-orm/src/pg-core/columns/bigint.ts b/drizzle-orm/src/pg-core/columns/bigint.ts index 6f23f5796..23e1e7f15 100644 --- a/drizzle-orm/src/pg-core/columns/bigint.ts +++ b/drizzle-orm/src/pg-core/columns/bigint.ts @@ -15,7 +15,6 @@ export type PgBigInt53BuilderInitial = PgBigInt53Builder<{ driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgBigInt53Builder> @@ -58,7 +57,6 @@ export type PgBigInt64BuilderInitial = PgBigInt64Builder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgBigInt64Builder> diff --git a/drizzle-orm/src/pg-core/columns/bigserial.ts b/drizzle-orm/src/pg-core/columns/bigserial.ts index 41872f622..ed4224354 100644 --- a/drizzle-orm/src/pg-core/columns/bigserial.ts +++ b/drizzle-orm/src/pg-core/columns/bigserial.ts @@ -21,7 +21,6 @@ export type PgBigSerial53BuilderInitial = NotNull< driverParam: number; enumValues: undefined; generated: undefined; - identity: undefined; }> > >; @@ -73,7 +72,6 @@ export type PgBigSerial64BuilderInitial = NotNull< driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }> > >; diff --git a/drizzle-orm/src/pg-core/columns/boolean.ts b/drizzle-orm/src/pg-core/columns/boolean.ts index d28e57baf..cd30895c7 100644 --- a/drizzle-orm/src/pg-core/columns/boolean.ts +++ b/drizzle-orm/src/pg-core/columns/boolean.ts @@ -12,7 +12,6 @@ export type PgBooleanBuilderInitial = PgBooleanBuilder<{ driverParam: boolean; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgBooleanBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/char.ts b/drizzle-orm/src/pg-core/columns/char.ts index dbd30dbc7..6629f08cc 100644 --- a/drizzle-orm/src/pg-core/columns/char.ts +++ b/drizzle-orm/src/pg-core/columns/char.ts @@ -13,7 +13,6 @@ export type PgCharBuilderInitial; export class PgCharBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/cidr.ts b/drizzle-orm/src/pg-core/columns/cidr.ts index acace9268..6caa3dc25 100644 --- a/drizzle-orm/src/pg-core/columns/cidr.ts +++ b/drizzle-orm/src/pg-core/columns/cidr.ts @@ -12,7 +12,6 @@ export type PgCidrBuilderInitial = PgCidrBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgCidrBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index d0d9f0502..c2fbe8cb9 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -57,7 +57,6 @@ export abstract class PgColumnBuilder< driverParam: T['driverParam'][] | string; enumValues: T['enumValues']; generated: GeneratedColumnConfig; - identity: T['identity']; } & (T extends { notNull: true } ? { notNull: true } : {}) & (T extends { hasDefault: true } ? { hasDefault: true } : {}), diff --git a/drizzle-orm/src/pg-core/columns/custom.ts b/drizzle-orm/src/pg-core/columns/custom.ts index 313575d41..b59169ed6 100644 --- a/drizzle-orm/src/pg-core/columns/custom.ts +++ b/drizzle-orm/src/pg-core/columns/custom.ts @@ -15,7 +15,6 @@ export type ConvertCustomConfig = PgDateBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgDateBuilder> extends PgDateColumnBaseBuilder { diff --git a/drizzle-orm/src/pg-core/columns/double-precision.ts b/drizzle-orm/src/pg-core/columns/double-precision.ts index 3d157e54a..77245ea45 100644 --- a/drizzle-orm/src/pg-core/columns/double-precision.ts +++ b/drizzle-orm/src/pg-core/columns/double-precision.ts @@ -12,7 +12,6 @@ export type PgDoublePrecisionBuilderInitial = PgDoublePrec driverParam: string | number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgDoublePrecisionBuilder> diff --git a/drizzle-orm/src/pg-core/columns/enum.ts b/drizzle-orm/src/pg-core/columns/enum.ts index 1e0c67ef2..7712ca606 100644 --- a/drizzle-orm/src/pg-core/columns/enum.ts +++ b/drizzle-orm/src/pg-core/columns/enum.ts @@ -14,7 +14,6 @@ export type PgEnumColumnBuilderInitial; const isPgEnumSym = Symbol.for('drizzle:isPgEnum'); diff --git a/drizzle-orm/src/pg-core/columns/inet.ts b/drizzle-orm/src/pg-core/columns/inet.ts index b2e353188..6b6210fcf 100644 --- a/drizzle-orm/src/pg-core/columns/inet.ts +++ b/drizzle-orm/src/pg-core/columns/inet.ts @@ -12,7 +12,6 @@ export type PgInetBuilderInitial = PgInetBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgInetBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/integer.ts b/drizzle-orm/src/pg-core/columns/integer.ts index 49b5924da..bb70f9b41 100644 --- a/drizzle-orm/src/pg-core/columns/integer.ts +++ b/drizzle-orm/src/pg-core/columns/integer.ts @@ -5,8 +5,7 @@ import type { AnyPgTable } from '../table.ts'; import { PgColumn } from './common.ts'; import { PgIntColumnBaseBuilder } from './int.common.ts'; -// no need export -export type PgIntegerBuilderInitial = PgIntegerBuilder<{ +type PgIntegerBuilderInitial = PgIntegerBuilder<{ name: TName; dataType: 'number'; columnType: 'PgInteger'; diff --git a/drizzle-orm/src/pg-core/columns/interval.ts b/drizzle-orm/src/pg-core/columns/interval.ts index fa0af41fb..4d3ed4588 100644 --- a/drizzle-orm/src/pg-core/columns/interval.ts +++ b/drizzle-orm/src/pg-core/columns/interval.ts @@ -14,7 +14,6 @@ export type PgIntervalBuilderInitial = PgIntervalBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgIntervalBuilder> diff --git a/drizzle-orm/src/pg-core/columns/json.ts b/drizzle-orm/src/pg-core/columns/json.ts index 76f576ee6..3c440c7d2 100644 --- a/drizzle-orm/src/pg-core/columns/json.ts +++ b/drizzle-orm/src/pg-core/columns/json.ts @@ -12,7 +12,6 @@ export type PgJsonBuilderInitial = PgJsonBuilder<{ driverParam: unknown; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgJsonBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/jsonb.ts b/drizzle-orm/src/pg-core/columns/jsonb.ts index 189771975..3407730db 100644 --- a/drizzle-orm/src/pg-core/columns/jsonb.ts +++ b/drizzle-orm/src/pg-core/columns/jsonb.ts @@ -12,7 +12,6 @@ export type PgJsonbBuilderInitial = PgJsonbBuilder<{ driverParam: unknown; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgJsonbBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/line.ts b/drizzle-orm/src/pg-core/columns/line.ts index 3b4d790f5..014140797 100644 --- a/drizzle-orm/src/pg-core/columns/line.ts +++ b/drizzle-orm/src/pg-core/columns/line.ts @@ -14,7 +14,6 @@ export type PgLineBuilderInitial = PgLineBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgLineBuilder> extends PgColumnBuilder { @@ -60,7 +59,6 @@ export type PgLineABCBuilderInitial = PgLineABCBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgLineABCBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/macaddr.ts b/drizzle-orm/src/pg-core/columns/macaddr.ts index c16bb43cd..bfc4511f4 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr.ts @@ -12,7 +12,6 @@ export type PgMacaddrBuilderInitial = PgMacaddrBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgMacaddrBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/macaddr8.ts b/drizzle-orm/src/pg-core/columns/macaddr8.ts index 2445958c4..6c4218de0 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr8.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr8.ts @@ -12,7 +12,6 @@ export type PgMacaddr8BuilderInitial = PgMacaddr8Builder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgMacaddr8Builder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/numeric.ts b/drizzle-orm/src/pg-core/columns/numeric.ts index 1857fa37d..efeb4ab97 100644 --- a/drizzle-orm/src/pg-core/columns/numeric.ts +++ b/drizzle-orm/src/pg-core/columns/numeric.ts @@ -13,7 +13,6 @@ export type PgNumericBuilderInitial = PgNumericBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgNumericBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/point.ts b/drizzle-orm/src/pg-core/columns/point.ts index 6344bf707..827579ad8 100644 --- a/drizzle-orm/src/pg-core/columns/point.ts +++ b/drizzle-orm/src/pg-core/columns/point.ts @@ -14,7 +14,6 @@ export type PgPointTupleBuilderInitial = PgPointTupleBuild driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgPointTupleBuilder> @@ -65,7 +64,6 @@ export type PgPointObjectBuilderInitial = PgPointObjectBui driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgPointObjectBuilder> diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts index 455088ec9..853c3dff9 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts @@ -15,7 +15,6 @@ export type PgGeometryBuilderInitial = PgGeometryBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgGeometryBuilder> extends PgColumnBuilder { @@ -60,7 +59,6 @@ export type PgGeometryObjectBuilderInitial = PgGeometryObj driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgGeometryObjectBuilder> diff --git a/drizzle-orm/src/pg-core/columns/real.ts b/drizzle-orm/src/pg-core/columns/real.ts index c8d499fb4..0e3de4b2e 100644 --- a/drizzle-orm/src/pg-core/columns/real.ts +++ b/drizzle-orm/src/pg-core/columns/real.ts @@ -12,7 +12,6 @@ export type PgRealBuilderInitial = PgRealBuilder<{ driverParam: string | number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgRealBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/smallint.ts b/drizzle-orm/src/pg-core/columns/smallint.ts index d84fa0e55..1cdfe141f 100644 --- a/drizzle-orm/src/pg-core/columns/smallint.ts +++ b/drizzle-orm/src/pg-core/columns/smallint.ts @@ -13,7 +13,6 @@ export type PgSmallIntBuilderInitial = PgSmallIntBuilder<{ driverParam: number | string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgSmallIntBuilder> diff --git a/drizzle-orm/src/pg-core/columns/smallserial.ts b/drizzle-orm/src/pg-core/columns/smallserial.ts index 7ab8408f3..456dc47f7 100644 --- a/drizzle-orm/src/pg-core/columns/smallserial.ts +++ b/drizzle-orm/src/pg-core/columns/smallserial.ts @@ -20,7 +20,6 @@ export type PgSmallSerialBuilderInitial = NotNull< driverParam: number; enumValues: undefined; generated: undefined; - identity: undefined; }> > >; diff --git a/drizzle-orm/src/pg-core/columns/text.ts b/drizzle-orm/src/pg-core/columns/text.ts index c43888449..6845f0e74 100644 --- a/drizzle-orm/src/pg-core/columns/text.ts +++ b/drizzle-orm/src/pg-core/columns/text.ts @@ -13,7 +13,6 @@ type PgTextBuilderInitial; export class PgTextBuilder< diff --git a/drizzle-orm/src/pg-core/columns/time.ts b/drizzle-orm/src/pg-core/columns/time.ts index 8ccafd333..9b3ff51e0 100644 --- a/drizzle-orm/src/pg-core/columns/time.ts +++ b/drizzle-orm/src/pg-core/columns/time.ts @@ -15,7 +15,6 @@ export type PgTimeBuilderInitial = PgTimeBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgTimeBuilder> extends PgDateColumnBaseBuilder< diff --git a/drizzle-orm/src/pg-core/columns/timestamp.ts b/drizzle-orm/src/pg-core/columns/timestamp.ts index 27372df7a..f12fa6304 100644 --- a/drizzle-orm/src/pg-core/columns/timestamp.ts +++ b/drizzle-orm/src/pg-core/columns/timestamp.ts @@ -14,7 +14,6 @@ export type PgTimestampBuilderInitial = PgTimestampBuilder driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgTimestampBuilder> diff --git a/drizzle-orm/src/pg-core/columns/uuid.ts b/drizzle-orm/src/pg-core/columns/uuid.ts index bff7f0d7e..d0e5a6830 100644 --- a/drizzle-orm/src/pg-core/columns/uuid.ts +++ b/drizzle-orm/src/pg-core/columns/uuid.ts @@ -13,7 +13,6 @@ export type PgUUIDBuilderInitial = PgUUIDBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgUUIDBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/varchar.ts b/drizzle-orm/src/pg-core/columns/varchar.ts index d9234137b..78ee0db96 100644 --- a/drizzle-orm/src/pg-core/columns/varchar.ts +++ b/drizzle-orm/src/pg-core/columns/varchar.ts @@ -13,7 +13,6 @@ export type PgVarcharBuilderInitial; export class PgVarcharBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts index 35cc8ccd2..81eea6b2f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts @@ -13,7 +13,6 @@ export type PgBinaryVectorBuilderInitial = PgBinaryVectorB driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgBinaryVectorBuilder> diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts index 65f040c00..e12d0d22f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts @@ -13,7 +13,6 @@ export type PgHalfVectorBuilderInitial = PgHalfVectorBuild driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgHalfVectorBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts index 7ff85dd85..3881b338f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts @@ -13,7 +13,6 @@ export type PgSparseVectorBuilderInitial = PgSparseVectorB driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgSparseVectorBuilder> diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts index bb63af5ab..eaac075dc 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts @@ -13,7 +13,6 @@ export type PgVectorBuilderInitial = PgVectorBuilder<{ driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class PgVectorBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/dialect.ts b/drizzle-orm/src/pg-core/dialect.ts index ef0b24191..4fd3075a2 100644 --- a/drizzle-orm/src/pg-core/dialect.ts +++ b/drizzle-orm/src/pg-core/dialect.ts @@ -517,7 +517,7 @@ export class PgDialect { const onConflictSql = onConflict ? sql` on conflict ${onConflict}` : undefined; - const overridingSql = overridingSystemValue_ === true? sql`overriding system value `: undefined; + const overridingSql = overridingSystemValue_ === true ? sql`overriding system value ` : undefined; return sql`${withSql}insert into ${table} ${insertOrder} ${overridingSql}values ${valuesSql}${onConflictSql}${returningSql}`; } @@ -1129,7 +1129,9 @@ export class PgDialect { })); } else { const aliasedColumns = Object.fromEntries( - Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value as PgColumn, tableAlias)]), + Object.entries(tableConfig.columns).map(( + [key, value], + ) => [key, aliasedTableColumn(value, tableAlias)]), ); if (config.where) { diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index 725239cb6..9411719c5 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -15,7 +15,7 @@ import type { RunnableQuery } from '~/runnable-query.ts'; import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; import { Param, SQL, sql } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; -import type { InferInsertModel} from '~/table.ts'; +import type { InferInsertModel } from '~/table.ts'; import { Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; import { mapUpdateSet, orderSelectedFields } from '~/utils.ts'; @@ -34,11 +34,18 @@ export interface PgInsertConfig { export type PgInsertValue, OverrideT extends boolean = false> = & { - [Key in keyof InferInsertModel]: InferInsertModel[Key] | SQL | Placeholder; + [Key in keyof InferInsertModel]: + | InferInsertModel[Key] + | SQL + | Placeholder; } & {}; -export class PgInsertBuilder { +export class PgInsertBuilder< + TTable extends PgTable, + TQueryResult extends PgQueryResultHKT, + OverrideT extends boolean = false, +> { static readonly [entityKind]: string = 'PgInsertBuilder'; constructor( @@ -49,14 +56,16 @@ export class PgInsertBuilder, 'overridingSystemValue'>{ + overridingSystemValue(): Omit, 'overridingSystemValue'> { this.overridingSystemValue_ = true; return this as any; } values(value: PgInsertValue): PgInsertBase; values(values: PgInsertValue[]): PgInsertBase; - values(values: PgInsertValue | PgInsertValue[]): PgInsertBase { + values( + values: PgInsertValue | PgInsertValue[], + ): PgInsertBase { values = Array.isArray(values) ? values : [values]; if (values.length === 0) { throw new Error('values() must be called with at least one value'); @@ -71,7 +80,14 @@ export class PgInsertBuilder = SQLiteBigIntBuild driverParam: Buffer; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class SQLiteBigIntBuilder> @@ -59,7 +58,6 @@ export type SQLiteBlobJsonBuilderInitial = SQLiteBlobJsonB driverParam: Buffer; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class SQLiteBlobJsonBuilder> @@ -106,7 +104,6 @@ export type SQLiteBlobBufferBuilderInitial = SQLiteBlobBuf driverParam: Buffer; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class SQLiteBlobBufferBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/custom.ts b/drizzle-orm/src/sqlite-core/columns/custom.ts index 8c0012e28..6ece801c5 100644 --- a/drizzle-orm/src/sqlite-core/columns/custom.ts +++ b/drizzle-orm/src/sqlite-core/columns/custom.ts @@ -15,7 +15,6 @@ export type ConvertCustomConfig = SQLiteIntegerBui driverParam: number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class SQLiteIntegerBuilder> @@ -105,7 +104,6 @@ export type SQLiteTimestampBuilderInitial = SQLiteTimestam driverParam: number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class SQLiteTimestampBuilder> @@ -168,7 +166,6 @@ export type SQLiteBooleanBuilderInitial = SQLiteBooleanBui driverParam: number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class SQLiteBooleanBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/numeric.ts b/drizzle-orm/src/sqlite-core/columns/numeric.ts index 13c67f080..93dfc4c3d 100644 --- a/drizzle-orm/src/sqlite-core/columns/numeric.ts +++ b/drizzle-orm/src/sqlite-core/columns/numeric.ts @@ -12,7 +12,6 @@ export type SQLiteNumericBuilderInitial = SQLiteNumericBui driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class SQLiteNumericBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/real.ts b/drizzle-orm/src/sqlite-core/columns/real.ts index 208e26045..cd7cf5d01 100644 --- a/drizzle-orm/src/sqlite-core/columns/real.ts +++ b/drizzle-orm/src/sqlite-core/columns/real.ts @@ -12,7 +12,6 @@ export type SQLiteRealBuilderInitial = SQLiteRealBuilder<{ driverParam: number; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class SQLiteRealBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/text.ts b/drizzle-orm/src/sqlite-core/columns/text.ts index 66db76607..84c71fb20 100644 --- a/drizzle-orm/src/sqlite-core/columns/text.ts +++ b/drizzle-orm/src/sqlite-core/columns/text.ts @@ -13,7 +13,6 @@ export type SQLiteTextBuilderInitial; export class SQLiteTextBuilder> extends SQLiteColumnBuilder< @@ -65,7 +64,6 @@ export type SQLiteTextJsonBuilderInitial = SQLiteTextJsonB driverParam: string; enumValues: undefined; generated: undefined; - identity: undefined; }>; export class SQLiteTextJsonBuilder> diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index adc8e8eb8..473976d1a 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -104,6 +104,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: true; hasRuntimeDefault: false; }, object>; @@ -120,6 +121,7 @@ Expect< enumValues: [string, ...string[]]; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; }, object>; @@ -136,6 +138,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; }, object>; @@ -214,6 +217,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: true; hasRuntimeDefault: false; @@ -230,6 +234,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: true; hasRuntimeDefault: false; @@ -270,6 +275,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: true; hasRuntimeDefault: false; @@ -286,6 +292,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: true; hasRuntimeDefault: false; @@ -324,6 +331,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -340,6 +348,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -378,6 +387,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -394,6 +404,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -425,6 +436,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -441,6 +453,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -472,6 +485,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -488,6 +502,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -522,6 +537,7 @@ Expect< baseColumn: never; dialect: 'mysql'; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; diff --git a/drizzle-orm/type-tests/pg/insert.ts b/drizzle-orm/type-tests/pg/insert.ts index c1ae7c685..fec20924b 100644 --- a/drizzle-orm/type-tests/pg/insert.ts +++ b/drizzle-orm/type-tests/pg/insert.ts @@ -2,7 +2,6 @@ import type { QueryResult } from 'pg'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import type { PgInsert } from '~/pg-core/query-builders/insert.ts'; -import { PgInsertValue } from '~/pg-core/query-builders/insert.ts'; import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; import { identityColumnsTable, users } from './tables.ts'; @@ -206,10 +205,22 @@ Expect< .returning(); } -type hh = PgInsertValue; - -db.insert(identityColumnsTable).overridingSystemValue().values([ - { alwaysAsIdentity: 1 }, - // { byDefaultAsIdentity: 5, name: "ff"}, - // { alwaysAsIdentity: 4, byDefaultAsIdentity: 6, name: "sd"}, -]); +{ + db.insert(identityColumnsTable).values([ + { byDefaultAsIdentity: 4, name: 'fdf' }, + ]); + + // @ts-expect-error + db.insert(identityColumnsTable).values([ + { alwaysAsIdentity: 2 }, + ]); + + db.insert(identityColumnsTable).overridingSystemValue().values([ + { alwaysAsIdentity: 2 }, + ]); + + // @ts-expect-error + db.insert(identityColumnsTable).values([ + { generatedCol: 2 }, + ]); +} diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index 15642a190..2b07a9fcd 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -54,22 +54,35 @@ import { type PgViewWithSelection, } from '~/pg-core/view.ts'; import { sql } from '~/sql/sql.ts'; -import { InferInsertModel } from '~/table.ts'; -import type { InferSelectModel, Table } from '~/table.ts'; +import type { InferInsertModel, InferSelectModel } from '~/table.ts'; +import type { Simplify } from '~/utils.ts'; import { db } from './db.ts'; export const myEnum = pgEnum('my_enum', ['a', 'b', 'c']); export const identityColumnsTable = pgTable('identity_columns_table', { - // generatedCol: integer('g').generatedAlwaysAs(1), + generatedCol: integer('generated_col').generatedAlwaysAs(1), alwaysAsIdentity: integer('always_as_identity').generatedAlwaysAsIdentity(), - // byDefaultAsIdentity: integer('by_default_as_identity').generatedByDefaultAsIdentity(), - // name: text('name') + byDefaultAsIdentity: integer('by_default_as_identity').generatedByDefaultAsIdentity(), + name: text('name'), }); -type g = InferInsertModel; - -type h = typeof identityColumnsTable.$inferInsert; +Expect, typeof identityColumnsTable['$inferSelect']>>; +Expect, typeof identityColumnsTable['_']['inferSelect']>>; +Expect, typeof identityColumnsTable['$inferInsert']>>; +Expect, typeof identityColumnsTable['_']['inferInsert']>>; +Expect< + Equal< + InferInsertModel, + Simplify + > +>; +Expect< + Equal< + InferInsertModel, + Simplify + > +>; export const users = pgTable( 'users_table', diff --git a/drizzle-orm/type-tests/sqlite/tables.ts b/drizzle-orm/type-tests/sqlite/tables.ts index 02a6e840a..358b6fea6 100644 --- a/drizzle-orm/type-tests/sqlite/tables.ts +++ b/drizzle-orm/type-tests/sqlite/tables.ts @@ -171,6 +171,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: true; @@ -187,6 +188,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: true; @@ -222,6 +224,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: false; @@ -238,6 +241,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: false; @@ -269,6 +273,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: false; @@ -285,6 +290,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: false; diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index c7f4b9be7..3c03db678 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -5069,23 +5069,63 @@ export function tests() { const { db } = ctx.pg; const users = pgTable('users', { - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), + id: integer('id').generatedAlwaysAsIdentity(), + id1: integer('id1').generatedByDefaultAsIdentity(), name: text('name').notNull(), }); + // not passing identity columns await db.execute(sql`drop table if exists ${users}`); - await db.execute(sql`create table ${users} ("id" integer generated always as identity primary key, "name" text)`); + await db.execute( + sql`create table ${users} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, + ); - const result = await db.insert(users).values([ + let result = await db.insert(users).values([ { name: 'John' }, { name: 'Jane' }, { name: 'Bob' }, ]).returning(); expect(result).toEqual([ - { id: 1, name: 'John' }, - { id: 2, name: 'Jane' }, - { id: 3, name: 'Bob' }, + { id: 1, id1: 1, name: 'John' }, + { id: 2, id1: 2, name: 'Jane' }, + { id: 3, id1: 3, name: 'Bob' }, + ]); + + // passing generated by default as identity column + await db.execute(sql`drop table if exists ${users}`); + await db.execute( + sql`create table ${users} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, + ); + + result = await db.insert(users).values([ + { name: 'John', id1: 3 }, + { name: 'Jane', id1: 5 }, + { name: 'Bob', id1: 5 }, + ]).returning(); + + expect(result).toEqual([ + { id: 1, id1: 3, name: 'John' }, + { id: 2, id1: 5, name: 'Jane' }, + { id: 3, id1: 5, name: 'Bob' }, + ]); + + // passing all identity columns + await db.execute(sql`drop table if exists ${users}`); + await db.execute( + sql`create table ${users} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, + ); + + result = await db.insert(users).overridingSystemValue().values([ + { name: 'John', id: 2, id1: 3 }, + { name: 'Jane', id: 4, id1: 5 }, + { name: 'Bob', id: 4, id1: 5 }, + ]).returning(); + + expect(result).toEqual([ + { id: 2, id1: 3, name: 'John' }, + { id: 4, id1: 5, name: 'Jane' }, + { id: 4, id1: 5, name: 'Bob' }, ]); }); }); From 0d204bf4d018591719833d71bf9167909b4cc721 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Wed, 13 Nov 2024 23:36:49 +0000 Subject: [PATCH 350/492] remove views and generated columns from drizzle-kit --- drizzle-kit/src/api.ts | 7 +- drizzle-kit/src/cli/commands/introspect.ts | 2 +- drizzle-kit/src/cli/commands/migrate.ts | 15 +- drizzle-kit/src/introspect-singlestore.ts | 10 +- drizzle-kit/src/jsonStatements.ts | 96 +-- drizzle-kit/src/serializer/index.ts | 4 +- .../src/serializer/singlestoreImports.ts | 16 +- .../src/serializer/singlestoreSchema.ts | 28 +- .../src/serializer/singlestoreSerializer.ts | 44 +- drizzle-kit/src/snapshotsDiffer.ts | 73 +-- drizzle-kit/src/sqlgenerator.ts | 39 -- .../tests/introspect/singlestore.test.ts | 20 +- .../tests/push/singlestore-push.test.ts | 112 +--- drizzle-kit/tests/push/singlestore.test.ts | 81 +++ drizzle-kit/tests/schemaDiffer.ts | 37 +- drizzle-kit/tests/singlestore-views.test.ts | 555 ------------------ .../src/singlestore-core/columns/bigint.ts | 20 +- .../src/singlestore-core/columns/binary.ts | 15 +- .../src/singlestore-core/columns/boolean.ts | 15 +- .../src/singlestore-core/columns/char.ts | 15 +- .../src/singlestore-core/columns/custom.ts | 13 +- .../src/singlestore-core/columns/date.ts | 20 +- .../src/singlestore-core/columns/datetime.ts | 20 +- .../src/singlestore-core/columns/decimal.ts | 15 +- .../src/singlestore-core/columns/double.ts | 15 +- .../src/singlestore-core/columns/enum.ts | 13 +- .../src/singlestore-core/columns/float.ts | 15 +- .../src/singlestore-core/columns/int.ts | 15 +- .../src/singlestore-core/columns/json.ts | 15 +- .../src/singlestore-core/columns/mediumint.ts | 15 +- .../src/singlestore-core/columns/real.ts | 15 +- .../src/singlestore-core/columns/serial.ts | 7 +- .../src/singlestore-core/columns/smallint.ts | 13 +- .../src/singlestore-core/columns/text.ts | 13 +- .../src/singlestore-core/columns/time.ts | 15 +- .../src/singlestore-core/columns/timestamp.ts | 18 +- .../src/singlestore-core/columns/tinyint.ts | 13 +- .../src/singlestore-core/columns/varbinary.ts | 13 +- .../src/singlestore-core/columns/varchar.ts | 13 +- .../src/singlestore-core/columns/year.ts | 13 +- drizzle-orm/src/singlestore-core/dialect.ts | 6 +- .../singlestore-core/query-builders/count.ts | 8 +- .../query-builders/select.types.ts | 6 +- 43 files changed, 499 insertions(+), 1014 deletions(-) delete mode 100644 drizzle-kit/tests/singlestore-views.test.ts diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 5d0ef60e3..18107bd34 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -12,7 +12,6 @@ import { roleResolver, schemasResolver, sequencesResolver, - singleStoreViewsResolver, sqliteViewsResolver, tablesResolver, viewsResolver, @@ -396,7 +395,7 @@ export const generateSingleStoreDrizzleJson = async ( const id = randomUUID(); - const snapshot = generateSingleStoreSnapshot(prepared.tables, prepared.views, casing); + const snapshot = generateSingleStoreSnapshot(prepared.tables, /* prepared.views, */ casing); return { ...snapshot, @@ -422,7 +421,7 @@ export const generateSingleStoreMigration = async ( squashedCur, tablesResolver, columnsResolver, - singleStoreViewsResolver, + /* singleStoreViewsResolver, */ validatedPrev, validatedCur, 'push', @@ -465,7 +464,7 @@ export const pushSingleStoreSchema = async ( squashedCur, tablesResolver, columnsResolver, - singleStoreViewsResolver, + /* singleStoreViewsResolver, */ validatedPrev, validatedCur, 'push', diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 7f13b99ff..c8b14ba5e 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -347,7 +347,7 @@ export const introspectSingleStore = async ( squashSingleStoreScheme(schema), tablesResolver, columnsResolver, - mySqlViewsResolver, + /* singleStoreViewsResolver, */ drySingleStore, schema, ); diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 00c472e9e..ef2b7fef8 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -13,12 +13,7 @@ import { import chalk from 'chalk'; import { render } from 'hanji'; import path, { join } from 'path'; -import { - SingleStoreSchema, - singlestoreSchema, - squashSingleStoreScheme, - ViewSquashed as SingleStoreViewSquashed, -} from 'src/serializer/singlestoreSchema'; +import { SingleStoreSchema, singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme, ViewSquashed } from '../../serializer/mysqlSchema'; @@ -152,7 +147,7 @@ export const mySqlViewsResolver = async ( } }; -export const singleStoreViewsResolver = async ( +/* export const singleStoreViewsResolver = async ( input: ResolverInput, ): Promise> => { try { @@ -172,7 +167,7 @@ export const singleStoreViewsResolver = async ( console.error(e); throw e; } -}; +}; */ export const sqliteViewsResolver = async ( input: ResolverInput, @@ -628,7 +623,7 @@ export const prepareSingleStorePush = async ( squashedCur, tablesResolver, columnsResolver, - mySqlViewsResolver, + /* singleStoreViewsResolver, */ validatedPrev, validatedCur, 'push', @@ -682,7 +677,7 @@ export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { squashedCur, tablesResolver, columnsResolver, - mySqlViewsResolver, + /* singleStoreViewsResolver, */ validatedPrev, validatedCur, ); diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts index 6272152a8..8f93cdfda 100644 --- a/drizzle-kit/src/introspect-singlestore.ts +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -189,7 +189,7 @@ export const schemaToTypeScript = ( { singlestore: [] as string[] }, ); - Object.values(schema.views).forEach((it) => { + /* Object.values(schema.views).forEach((it) => { imports.singlestore.push('singlestoreView'); const columnImports = Object.values(it.columns) @@ -221,7 +221,7 @@ export const schemaToTypeScript = ( }); imports.singlestore.push(...columnImports); - }); + }); */ const tableStatements = Object.values(schema.tables).map((table) => { const func = 'singlestoreTable'; @@ -272,7 +272,7 @@ export const schemaToTypeScript = ( return statement; }); - const viewsStatements = Object.values(schema.views).map((view) => { + /* const viewsStatements = Object.values(schema.views).map((view) => { const { columns, name, algorithm, definition, sqlSecurity, withCheckOption } = view; const func = 'singlestoreView'; let statement = ''; @@ -300,7 +300,7 @@ export const schemaToTypeScript = ( statement += `.as(sql\`${definition?.replaceAll('`', '\\`')}\`);`; return statement; - }); + }); */ const uniqueSingleStoreImports = [ 'singlestoreTable', @@ -317,7 +317,7 @@ export const schemaToTypeScript = ( let decalrations = ''; decalrations += tableStatements.join('\n\n'); decalrations += '\n'; - decalrations += viewsStatements.join('\n\n'); + /* decalrations += viewsStatements.join('\n\n'); */ const file = importsTs + decalrations; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 4fd9726d6..f64020f5a 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -13,12 +13,7 @@ import { View as PgView, ViewWithOption, } from './serializer/pgSchema'; -import { - SingleStoreKitInternals, - SingleStoreSchema, - SingleStoreSquasher, - View as SingleStoreView, -} from './serializer/singlestoreSchema'; +import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, @@ -679,10 +674,10 @@ export type JsonCreateMySqlViewStatement = { replace: boolean; } & Omit; -export type JsonCreateSingleStoreViewStatement = { +/* export type JsonCreateSingleStoreViewStatement = { type: 'singlestore_create_view'; replace: boolean; -} & Omit; +} & Omit; */ export type JsonCreateSqliteViewStatement = { type: 'sqlite_create_view'; @@ -767,9 +762,9 @@ export type JsonAlterMySqlViewStatement = { type: 'alter_mysql_view'; } & Omit; -export type JsonAlterSingleStoreViewStatement = { +/* export type JsonAlterSingleStoreViewStatement = { type: 'alter_singlestore_view'; -} & Omit; +} & Omit; */ export type JsonAlterViewStatement = | JsonAlterViewAlterSchemaStatement @@ -853,8 +848,8 @@ export type JsonStatement = | JsonAlterViewStatement | JsonCreateMySqlViewStatement | JsonAlterMySqlViewStatement - | JsonCreateSingleStoreViewStatement - | JsonAlterSingleStoreViewStatement + /* | JsonCreateSingleStoreViewStatement + | JsonAlterSingleStoreViewStatement */ | JsonCreateSqliteViewStatement | JsonCreateCheckConstraint | JsonDeleteCheckConstraint @@ -3354,7 +3349,7 @@ export const prepareMySqlCreateViewJson = ( }; }; -export const prepareSingleStoreCreateViewJson = ( +/* export const prepareSingleStoreCreateViewJson = ( name: string, definition: string, meta: string, @@ -3370,7 +3365,7 @@ export const prepareSingleStoreCreateViewJson = ( withCheckOption, replace, }; -}; +}; */ export const prepareSqliteCreateViewJson = ( name: string, @@ -3498,77 +3493,8 @@ export const prepareMySqlAlterView = ( return { type: 'alter_mysql_view', ...view }; }; -export const prepareSingleStoreAlterView = ( +/* export const prepareSingleStoreAlterView = ( view: Omit, ): JsonAlterSingleStoreViewStatement => { return { type: 'alter_singlestore_view', ...view }; -}; - -export const prepareAddCompositePrimaryKeySingleStore = ( - tableName: string, - pks: Record, - // TODO: remove? - json1: SingleStoreSchema, - json2: SingleStoreSchema, -): JsonCreateCompositePK[] => { - const res: JsonCreateCompositePK[] = []; - for (const it of Object.values(pks)) { - const unsquashed = SingleStoreSquasher.unsquashPK(it); - - if ( - unsquashed.columns.length === 1 - && json1.tables[tableName]?.columns[unsquashed.columns[0]]?.primaryKey - ) { - continue; - } - - res.push({ - type: 'create_composite_pk', - tableName, - data: it, - constraintName: json2.tables[tableName].compositePrimaryKeys[unsquashed.name].name, - } as JsonCreateCompositePK); - } - return res; -}; - -export const prepareDeleteCompositePrimaryKeySingleStore = ( - tableName: string, - pks: Record, - // TODO: remove? - json1: SingleStoreSchema, -): JsonDeleteCompositePK[] => { - return Object.values(pks).map((it) => { - return { - type: 'delete_composite_pk', - tableName, - data: it, - constraintName: json1.tables[tableName].compositePrimaryKeys[ - SingleStoreSquasher.unsquashPK(it).name - ].name, - } as JsonDeleteCompositePK; - }); -}; - -export const prepareAlterCompositePrimaryKeySingleStore = ( - tableName: string, - pks: Record, - // TODO: remove? - json1: SingleStoreSchema, - json2: SingleStoreSchema, -): JsonAlterCompositePK[] => { - return Object.values(pks).map((it) => { - return { - type: 'alter_composite_pk', - tableName, - old: it.__old, - new: it.__new, - oldConstraintName: json1.tables[tableName].compositePrimaryKeys[ - SingleStoreSquasher.unsquashPK(it.__old).name - ].name, - newConstraintName: json2.tables[tableName].compositePrimaryKeys[ - SingleStoreSquasher.unsquashPK(it.__new).name - ].name, - } as JsonAlterCompositePK; - }); -}; +}; */ diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index d8934de00..d24afbab0 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -65,9 +65,9 @@ export const serializeSingleStore = async ( const { prepareFromSingleStoreImports } = await import('./singlestoreImports'); const { generateSingleStoreSnapshot } = await import('./singlestoreSerializer'); - const { tables, views } = await prepareFromSingleStoreImports(filenames); + const { tables /* views */ } = await prepareFromSingleStoreImports(filenames); - return generateSingleStoreSnapshot(tables, views, casing); + return generateSingleStoreSnapshot(tables, /* views, */ casing); }; export const prepareFilenames = (path: string | string[]) => { diff --git a/drizzle-kit/src/serializer/singlestoreImports.ts b/drizzle-kit/src/serializer/singlestoreImports.ts index fe9cf04ff..23c2d66a9 100644 --- a/drizzle-kit/src/serializer/singlestoreImports.ts +++ b/drizzle-kit/src/serializer/singlestoreImports.ts @@ -1,10 +1,10 @@ import { is } from 'drizzle-orm'; -import { AnySingleStoreTable, SingleStoreTable, SingleStoreView } from 'drizzle-orm/singlestore-core'; +import { AnySingleStoreTable, SingleStoreTable } from 'drizzle-orm/singlestore-core'; import { safeRegister } from '../cli/commands/utils'; export const prepareFromExports = (exports: Record) => { const tables: AnySingleStoreTable[] = []; - const views: SingleStoreView[] = []; + /* const views: SingleStoreView[] = []; */ const i0values = Object.values(exports); i0values.forEach((t) => { @@ -12,17 +12,17 @@ export const prepareFromExports = (exports: Record) => { tables.push(t); } - if (is(t, SingleStoreView)) { + /* if (is(t, SingleStoreView)) { views.push(t); - } + } */ }); - return { tables, views }; + return { tables /* views */ }; }; export const prepareFromSingleStoreImports = async (imports: string[]) => { const tables: AnySingleStoreTable[] = []; - const views: SingleStoreView[] = []; + /* const views: SingleStoreView[] = []; */ const { unregister } = await safeRegister(); for (let i = 0; i < imports.length; i++) { @@ -31,8 +31,8 @@ export const prepareFromSingleStoreImports = async (imports: string[]) => { const prepared = prepareFromExports(i0); tables.push(...prepared.tables); - views.push(...prepared.views); + /* views.push(...prepared.views); */ } unregister(); - return { tables: Array.from(new Set(tables)), views }; + return { tables: Array.from(new Set(tables)) /* , views */ }; }; diff --git a/drizzle-kit/src/serializer/singlestoreSchema.ts b/drizzle-kit/src/serializer/singlestoreSchema.ts index 501ccfe40..9ff45ef5a 100644 --- a/drizzle-kit/src/serializer/singlestoreSchema.ts +++ b/drizzle-kit/src/serializer/singlestoreSchema.ts @@ -49,13 +49,13 @@ const viewMeta = object({ withCheckOption: enumType(['local', 'cascaded']).optional(), }).strict(); -export const view = object({ +/* export const view = object({ name: string(), columns: record(string(), column), definition: string().optional(), isExisting: boolean(), }).strict().merge(viewMeta); -type SquasherViewMeta = Omit, 'definer'>; +type SquasherViewMeta = Omit, 'definer'>; */ export const kitInternals = object({ tables: record( @@ -90,7 +90,7 @@ export const schemaInternal = object({ version: literal('1'), dialect: dialect, tables: record(string(), table), - views: record(string(), view).default({}), + /* views: record(string(), view).default({}), */ _meta: object({ tables: record(string(), string()), columns: record(string(), string()), @@ -108,17 +108,17 @@ const tableSquashed = object({ uniqueConstraints: record(string(), string()).default({}), }).strict(); -const viewSquashed = view.omit({ +/* const viewSquashed = view.omit({ algorithm: true, sqlSecurity: true, withCheckOption: true, -}).extend({ meta: string() }); +}).extend({ meta: string() }); */ export const schemaSquashed = object({ version: literal('1'), dialect: dialect, tables: record(string(), tableSquashed), - views: record(string(), viewSquashed), + /* views: record(string(), viewSquashed), */ }).strict(); export type Dialect = TypeOf; @@ -131,8 +131,8 @@ export type SingleStoreSchemaSquashed = TypeOf; export type Index = TypeOf; export type PrimaryKey = TypeOf; export type UniqueConstraint = TypeOf; -export type View = TypeOf; -export type ViewSquashed = TypeOf; +/* export type View = TypeOf; */ +/* export type ViewSquashed = TypeOf; */ export const SingleStoreSquasher = { squashIdx: (idx: Index) => { @@ -167,7 +167,7 @@ export const SingleStoreSquasher = { const [name, columns] = unq.split(';'); return { name, columns: columns.split(',') }; }, - squashView: (view: View): string => { + /* squashView: (view: View): string => { return `${view.algorithm};${view.sqlSecurity};${view.withCheckOption}`; }, unsquashView: (meta: string): SquasherViewMeta => { @@ -179,7 +179,7 @@ export const SingleStoreSquasher = { }; return viewMeta.parse(toReturn); - }, + }, */ }; export const squashSingleStoreScheme = (json: SingleStoreSchema): SingleStoreSchemaSquashed => { @@ -213,7 +213,7 @@ export const squashSingleStoreScheme = (json: SingleStoreSchema): SingleStoreSch }), ); - const mappedViews = Object.fromEntries( + /* const mappedViews = Object.fromEntries( Object.entries(json.views).map(([key, value]) => { const meta = SingleStoreSquasher.squashView(value); @@ -225,13 +225,13 @@ export const squashSingleStoreScheme = (json: SingleStoreSchema): SingleStoreSch meta, }]; }), - ); + ); */ return { version: '1', dialect: json.dialect, tables: mappedTables, - views: mappedViews, + /* views: mappedViews, */ }; }; @@ -248,7 +248,7 @@ export const drySingleStore = singlestoreSchema.parse({ prevId: '', tables: {}, schemas: {}, - views: {}, + /* views: {}, */ _meta: { schemas: {}, tables: {}, diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index 7fa6354cc..e8c89f1d1 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -3,17 +3,14 @@ import { is, SQL } from 'drizzle-orm'; import { AnySingleStoreTable, getTableConfig, - getViewConfig, type PrimaryKey as PrimaryKeyORM, SingleStoreDialect, - SingleStoreView, uniqueKeyName, } from 'drizzle-orm/singlestore-core'; import { RowDataPacket } from 'mysql2/promise'; import { withStyle } from '../cli/validations/outputs'; import { IntrospectStage, IntrospectStatus } from '../cli/views'; -import { SingleStoreColumn } from 'drizzle-orm/singlestore-core/columns'; import { CasingType } from 'src/cli/validations/common'; import type { DB } from '../utils'; import { @@ -24,7 +21,6 @@ import { SingleStoreSchemaInternal, Table, UniqueConstraint, - View, } from './singlestoreSchema'; import { sqlToStr } from './utils'; @@ -36,12 +32,12 @@ export const indexName = (tableName: string, columns: string[]) => { export const generateSingleStoreSnapshot = ( tables: AnySingleStoreTable[], - views: SingleStoreView[], + /* views: SingleStoreView[], */ casing: CasingType | undefined, ): SingleStoreSchemaInternal => { const dialect = new SingleStoreDialect({ casing }); const result: Record = {}; - const resultViews: Record = {}; + /* const resultViews: Record = {}; */ const internal: SingleStoreKitInternals = { tables: {}, indexes: {} }; for (const table of tables) { const { @@ -295,7 +291,7 @@ export const generateSingleStoreSnapshot = ( } } - for (const view of views) { + /* for (const view of views) { const { isExisting, name, @@ -399,13 +395,13 @@ export const generateSingleStoreSnapshot = ( algorithm: algorithm ?? 'undefined', // set default values sqlSecurity: sqlSecurity ?? 'definer', // set default values }; - } + } */ return { version: '1', dialect: 'singlestore', tables: result, - views: resultViews, + /* views: resultViews, */ _meta: { tables: {}, columns: {}, @@ -459,7 +455,7 @@ export const fromDatabase = async ( let columnsCount = 0; let tablesCount = new Set(); let indexesCount = 0; - let viewsCount = 0; + /* let viewsCount = 0; */ const idxs = await db.query( `select * from INFORMATION_SCHEMA.STATISTICS @@ -634,7 +630,7 @@ export const fromDatabase = async ( FROM information_schema.table_constraints t LEFT JOIN information_schema.key_column_usage k USING(constraint_name,table_schema,table_name) - WHERE t.constraint_type='PRIMARY KEY' + WHERE t.constraint_type='UNIQUE' and table_name != '__drizzle_migrations' AND t.table_schema = '${inputSchema}' ORDER BY ordinal_position`, @@ -644,8 +640,8 @@ export const fromDatabase = async ( const tableToPkRows = tablePks as RowDataPacket[]; for (const tableToPkRow of tableToPkRows) { - const tableName: string = tableToPkRow['TABLE_NAME']; - const columnName: string = tableToPkRow['COLUMN_NAME']; + const tableName: string = tableToPkRow['table_name']; + const columnName: string = tableToPkRow['column_name']; const position: string = tableToPkRow['ordinal_position']; if (typeof result[tableName] === 'undefined') { @@ -707,26 +703,16 @@ export const fromDatabase = async ( columns: [columnName], }; } - } else { - if (typeof tableInResult.indexes[constraintName] !== 'undefined') { - tableInResult.indexes[constraintName]!.columns.push(columnName); - } else { - tableInResult.indexes[constraintName] = { - name: constraintName, - columns: [columnName], - isUnique: isUnique, - }; - } } } - const views = await db.query( + /* const views = await db.query( `select * from INFORMATION_SCHEMA.VIEWS WHERE table_schema = '${inputSchema}';`, - ); + ); */ - const resultViews: Record = {}; + /* const resultViews: Record = {}; */ - viewsCount = views.length; + /* viewsCount = views.length; if (progressCallback) { progressCallback('views', viewsCount, 'fetching'); } @@ -759,7 +745,7 @@ export const fromDatabase = async ( sqlSecurity, withCheckOption, }; - } + } */ if (progressCallback) { progressCallback('indexes', indexesCount, 'done'); @@ -771,7 +757,7 @@ export const fromDatabase = async ( version: '1', dialect: 'singlestore', tables: result, - views: resultViews, + /* views: resultViews, */ _meta: { tables: {}, columns: {}, diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 5e5d8fb19..2db4ad02c 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -24,7 +24,6 @@ import { JsonAlterIndPolicyStatement, JsonAlterMySqlViewStatement, JsonAlterPolicyStatement, - JsonAlterSingleStoreViewStatement, JsonAlterTableSetSchema, JsonAlterUniqueConstraint, JsonAlterViewStatement, @@ -35,7 +34,6 @@ import { JsonCreatePgViewStatement, JsonCreatePolicyStatement, JsonCreateReferenceStatement, - JsonCreateSingleStoreViewStatement, JsonCreateSqliteViewStatement, JsonCreateUniqueConstraint, JsonDeleteCheckConstraint, @@ -58,14 +56,12 @@ import { prepareAddCheckConstraint, prepareAddCompositePrimaryKeyMySql, prepareAddCompositePrimaryKeyPg, - prepareAddCompositePrimaryKeySingleStore, prepareAddCompositePrimaryKeySqlite, prepareAddUniqueConstraintPg as prepareAddUniqueConstraint, prepareAddValuesToEnumJson, prepareAlterColumnsMysql, prepareAlterCompositePrimaryKeyMySql, prepareAlterCompositePrimaryKeyPg, - prepareAlterCompositePrimaryKeySingleStore, prepareAlterCompositePrimaryKeySqlite, prepareAlterIndPolicyJson, prepareAlterPolicyJson, @@ -83,7 +79,6 @@ import { prepareDeleteCheckConstraint, prepareDeleteCompositePrimaryKeyMySql, prepareDeleteCompositePrimaryKeyPg, - prepareDeleteCompositePrimaryKeySingleStore, prepareDeleteCompositePrimaryKeySqlite, prepareDeleteSchemasJson as prepareDropSchemasJson, prepareDeleteUniqueConstraintPg as prepareDeleteUniqueConstraint, @@ -122,9 +117,7 @@ import { prepareRenameSequenceJson, prepareRenameTableJson, prepareRenameViewJson, - prepareSingleStoreAlterView, prepareSingleStoreCreateTableJson, - prepareSingleStoreCreateViewJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, prepareSqliteCreateViewJson, @@ -2702,9 +2695,9 @@ export const applySingleStoreSnapshotsDiff = async ( columnsResolver: ( input: ColumnsResolverInput, ) => Promise>, - viewsResolver: ( + /* viewsResolver: ( input: ResolverInput, - ) => Promise>, + ) => Promise>, */ prevFull: SingleStoreSchema, curFull: SingleStoreSchema, action?: 'push' | undefined, @@ -2722,11 +2715,11 @@ export const applySingleStoreSnapshotsDiff = async ( // squash indexes and fks // squash uniqueIndexes and uniqueConstraint into constraints object - // it should be done for mysql only because it has no diffs for it + // it should be done for singlestore only because it has no diffs for it // TODO: @AndriiSherman // Add an upgrade to v6 and move all snaphosts to this strcutre - // After that we can generate mysql in 1 object directly(same as sqlite) + // After that we can generate singlestore in 1 object directly(same as sqlite) for (const tableName in json1.tables) { const table = json1.tables[tableName]; for (const indexName in table.indexes) { @@ -2852,7 +2845,7 @@ export const applySingleStoreSnapshotsDiff = async ( }, ); - const viewsDiff = diffSchemasOrTables(json1.views, json2.views); + /* const viewsDiff = diffSchemasOrTables(json1.views, json2.views); const { created: createdViews, @@ -2883,9 +2876,10 @@ export const applySingleStoreSnapshotsDiff = async ( }, ); - const diffResult = applyJsonDiff(viewsPatchedSnap1, json2); + */ + const diffResult = applyJsonDiff(tablesPatchedSnap1, json2); // replace tablesPatchedSnap1 with viewsPatchedSnap1 - const typedResult: DiffResultMysql = diffResultSchemeMysql.parse(diffResult); + const typedResult: DiffResultSingleStore = diffResultSchemeSingleStore.parse(diffResult); const jsonStatements: JsonStatement[] = []; @@ -2911,16 +2905,11 @@ export const applySingleStoreSnapshotsDiff = async ( const alteredTables = typedResult.alteredTablesWithColumns; const jsonAddedCompositePKs: JsonCreateCompositePK[] = []; - const jsonDeletedCompositePKs: JsonDeleteCompositePK[] = []; - const jsonAlteredCompositePKs: JsonAlterCompositePK[] = []; const jsonAddedUniqueConstraints: JsonCreateUniqueConstraint[] = []; const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; - const jsonCreatedCheckConstraints: JsonCreateCheckConstraint[] = []; - const jsonDeletedCheckConstraints: JsonDeleteCheckConstraint[] = []; - const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames .map((it) => prepareRenameColumns(it.table, '', it.renames)) .flat(); @@ -2954,29 +2943,6 @@ export const applySingleStoreSnapshotsDiff = async ( // deletedColumns.sort(); const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); - let addedCompositePKs: JsonCreateCompositePK[] = []; - let deletedCompositePKs: JsonDeleteCompositePK[] = []; - let alteredCompositePKs: JsonAlterCompositePK[] = []; - - addedCompositePKs = prepareAddCompositePrimaryKeySingleStore( - it.name, - it.addedCompositePKs, - prevFull, - curFull, - ); - deletedCompositePKs = prepareDeleteCompositePrimaryKeySingleStore( - it.name, - it.deletedCompositePKs, - prevFull, - ); - // } - alteredCompositePKs = prepareAlterCompositePrimaryKeySingleStore( - it.name, - it.alteredCompositePKs, - prevFull, - curFull, - ); - // add logic for unique constraints let addedUniqueConstraints: JsonCreateUniqueConstraint[] = []; let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; @@ -3030,16 +2996,9 @@ export const applySingleStoreSnapshotsDiff = async ( deletedCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); } - jsonAddedCompositePKs.push(...addedCompositePKs); - jsonDeletedCompositePKs.push(...deletedCompositePKs); - jsonAlteredCompositePKs.push(...alteredCompositePKs); - jsonAddedUniqueConstraints.push(...addedUniqueConstraints); jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); - - jsonCreatedCheckConstraints.push(...createdCheckConstraints); - jsonDeletedCheckConstraints.push(...deletedCheckConstraints); }); const rColumns = jsonRenameColumnsStatements.map((it) => { @@ -3117,7 +3076,7 @@ export const applySingleStoreSnapshotsDiff = async ( ); }); - const createViews: JsonCreateSingleStoreViewStatement[] = []; + /* const createViews: JsonCreateSingleStoreViewStatement[] = []; const dropViews: JsonDropViewStatement[] = []; const renameViews: JsonRenameViewStatement[] = []; const alterViews: JsonAlterSingleStoreViewStatement[] = []; @@ -3181,7 +3140,7 @@ export const applySingleStoreSnapshotsDiff = async ( prepareSingleStoreAlterView(view), ); } - } + } */ jsonStatements.push(...jsonSingleStoreCreateTables); @@ -3189,18 +3148,17 @@ export const applySingleStoreSnapshotsDiff = async ( jsonStatements.push(...jsonRenameTables); jsonStatements.push(...jsonRenameColumnsStatements); + /*jsonStatements.push(...createViews); jsonStatements.push(...dropViews); jsonStatements.push(...renameViews); jsonStatements.push(...alterViews); - + */ jsonStatements.push(...jsonDeletedUniqueConstraints); - jsonStatements.push(...jsonDeletedCheckConstraints); // Will need to drop indexes before changing any columns in table // Then should go column alternations and then index creation jsonStatements.push(...jsonDropIndexesForAllAlteredTables); - jsonStatements.push(...jsonDeletedCompositePKs); jsonStatements.push(...jsonTableAlternations); jsonStatements.push(...jsonAddedCompositePKs); @@ -3210,17 +3168,12 @@ export const applySingleStoreSnapshotsDiff = async ( jsonStatements.push(...jsonAddColumnsStatemets); jsonStatements.push(...jsonCreateIndexesForCreatedTables); - jsonStatements.push(...jsonCreatedCheckConstraints); jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); jsonStatements.push(...jsonDropColumnsStatemets); - // jsonStatements.push(...jsonDeletedCompositePKs); - // jsonStatements.push(...jsonAddedCompositePKs); - jsonStatements.push(...jsonAlteredCompositePKs); - - jsonStatements.push(...createViews); + jsonStatements.push(...jsonAddedCompositePKs); jsonStatements.push(...jsonAlteredUniqueConstraints); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 1dd72a338..bf43fde1b 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -3083,42 +3083,6 @@ class MySqlAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { } } -class SingleStoreAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_composite_pk' && dialect === 'singlestore'; - } - - convert(statement: JsonCreateCompositePK) { - const { name, columns } = SingleStoreSquasher.unsquashPK(statement.data); - return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY(\`${columns.join('`,`')}\`);`; - } -} - -class SingleStoreAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'delete_composite_pk' && dialect === 'singlestore'; - } - - convert(statement: JsonDeleteCompositePK) { - const { name, columns } = SingleStoreSquasher.unsquashPK(statement.data); - return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY;`; - } -} - -class SingleStoreAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_composite_pk' && dialect === 'singlestore'; - } - - convert(statement: JsonAlterCompositePK) { - const { name, columns } = SingleStoreSquasher.unsquashPK(statement.old); - const { name: newName, columns: newColumns } = SingleStoreSquasher.unsquashPK( - statement.new, - ); - return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY, ADD PRIMARY KEY(\`${newColumns.join('`,`')}\`);`; - } -} - class SqliteAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_composite_pk' && dialect === 'sqlite'; @@ -4022,11 +3986,8 @@ convertors.push(new MySqlAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new MySqlAlterTableAddPk()); convertors.push(new MySqlAlterTableAlterCompositePrimaryKeyConvertor()); -convertors.push(new SingleStoreAlterTableDeleteCompositePrimaryKeyConvertor()); convertors.push(new SingleStoreAlterTableDropPk()); -convertors.push(new SingleStoreAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new SingleStoreAlterTableAddPk()); -convertors.push(new SingleStoreAlterTableAlterCompositePrimaryKeyConvertor()); export function fromJson( statements: JsonStatement[], diff --git a/drizzle-kit/tests/introspect/singlestore.test.ts b/drizzle-kit/tests/introspect/singlestore.test.ts index 9a7e3af5a..245f818ba 100644 --- a/drizzle-kit/tests/introspect/singlestore.test.ts +++ b/drizzle-kit/tests/introspect/singlestore.test.ts @@ -96,7 +96,8 @@ if (!fs.existsSync('tests/introspect/singlestore')) { fs.mkdirSync('tests/introspect/singlestore'); } -test.skip('generated always column: link to another column', async () => { +// TODO: Unskip this test when generated column is implemented +/* test.skip('generated always column: link to another column', async () => { const schema = { users: singlestoreTable('users', { id: int('id'), @@ -116,9 +117,10 @@ test.skip('generated always column: link to another column', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); -}); +}); */ -test.skip('generated always column virtual: link to another column', async () => { +// TODO: Unskip this test when generated column is implemented +/* test.skip('generated always column virtual: link to another column', async () => { const schema = { users: singlestoreTable('users', { id: int('id'), @@ -139,7 +141,7 @@ test.skip('generated always column virtual: link to another column', async () => expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); -}); +}); */ test('Default value of character type column: char', async () => { const schema = { @@ -179,7 +181,8 @@ test('Default value of character type column: varchar', async () => { expect(sqlStatements.length).toBe(0); }); -test('view #1', async () => { +// TODO: Unskip this test when views are implemented +/* test('view #1', async () => { const users = singlestoreTable('users', { id: int('id') }); const testView = singlestoreView('some_view', { id: int('id') }).as( sql`select \`drizzle\`.\`users\`.\`id\` AS \`id\` from \`drizzle\`.\`users\``, @@ -199,9 +202,10 @@ test('view #1', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); -}); +}); */ -test('view #2', async () => { +// TODO: Unskip this test when views are implemented +/* test('view #2', async () => { const users = singlestoreTable('some_users', { id: int('id') }); const testView = singlestoreView('some_view', { id: int('id') }).algorithm('temptable').sqlSecurity('definer').as( sql`SELECT * FROM ${users}`, @@ -221,7 +225,7 @@ test('view #2', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); -}); +}); */ test('handle float type', async () => { const schema = { diff --git a/drizzle-kit/tests/push/singlestore-push.test.ts b/drizzle-kit/tests/push/singlestore-push.test.ts index bd6f9d342..49e0cc270 100644 --- a/drizzle-kit/tests/push/singlestore-push.test.ts +++ b/drizzle-kit/tests/push/singlestore-push.test.ts @@ -78,97 +78,7 @@ if (!fs.existsSync('tests/push/singlestore')) { fs.mkdirSync('tests/push/singlestore'); } -test.skip('add check constraint to table', async () => { - const schema1 = { - test: singlestoreTable('test', { - id: int('id').primaryKey(), - values: int('values'), - }), - }; - const schema2 = { - test: singlestoreTable('test', { - id: int('id').primaryKey(), - values: int('values'), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - client, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([ - { - type: 'create_check_constraint', - tableName: 'test', - schema: '', - data: 'some_check1;`test`.`values` < 100', - }, - { - data: "some_check2;'test' < 100", - schema: '', - tableName: 'test', - type: 'create_check_constraint', - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `test` ADD CONSTRAINT `some_check1` CHECK (`test`.`values` < 100);', - `ALTER TABLE \`test\` ADD CONSTRAINT \`some_check2\` CHECK ('test' < 100);`, - ]); - - await client.query(`DROP TABLE \`test\`;`); -}); - -test.skip('drop check constraint to table', async () => { - const schema1 = { - test: singlestoreTable('test', { - id: int('id').primaryKey(), - values: int('values'), - }), - }; - const schema2 = { - test: singlestoreTable('test', { - id: int('id').primaryKey(), - values: int('values'), - }), - }; - - const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( - client, - schema1, - schema2, - [], - 'drizzle', - false, - ); - - expect(statements).toStrictEqual([ - { - type: 'delete_check_constraint', - tableName: 'test', - schema: '', - constraintName: 'some_check1', - }, - { - constraintName: 'some_check2', - schema: '', - tableName: 'test', - type: 'delete_check_constraint', - }, - ]); - expect(sqlStatements).toStrictEqual([ - 'ALTER TABLE `test` DROP CONSTRAINT `some_check1`;', - `ALTER TABLE \`test\` DROP CONSTRAINT \`some_check2\`;`, - ]); - - await client.query(`DROP TABLE \`test\`;`); -}); - -test.skip('db has checks. Push with same names', async () => { +test('db has checks. Push with same names', async () => { const schema1 = { test: singlestoreTable('test', { id: int('id').primaryKey(), @@ -196,7 +106,8 @@ test.skip('db has checks. Push with same names', async () => { await client.query(`DROP TABLE \`test\`;`); }); -test.skip('create view', async () => { +// TODO: Unskip this test when views are implemented +/* test.skip.skip('create view', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); @@ -237,9 +148,10 @@ VIEW \`view\` AS (select \`id\` from \`test\`);`, ]); await client.query(`DROP TABLE \`test\`;`); -}); +}); */ -test.skip('drop view', async () => { +// TODO: Unskip this test when views are implemented +/* test.skip('drop view', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); @@ -271,9 +183,10 @@ test.skip('drop view', async () => { expect(sqlStatements).toStrictEqual(['DROP VIEW `view`;']); await client.query(`DROP TABLE \`test\`;`); await client.query(`DROP VIEW \`view\`;`); -}); +}); */ -test.skip('alter view ".as"', async () => { +// TODO: Unskip this test when views are implemented +/* test.skip('alter view ".as"', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); @@ -307,9 +220,10 @@ test.skip('alter view ".as"', async () => { await client.query(`DROP TABLE \`test\`;`); await client.query(`DROP VIEW \`view\`;`); -}); +}); */ -test.skip('alter meta options with distinct in definition', async () => { +// TODO: Unskip this test when views are implemented +/* test.skip('alter meta options with distinct in definition', async () => { const table = singlestoreTable('test', { id: int('id').primaryKey(), }); @@ -349,4 +263,4 @@ test.skip('alter meta options with distinct in definition', async () => { ).rejects.toThrowError(); await client.query(`DROP TABLE \`test\`;`); -}); +}); */ diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 82a901b16..824f78576 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -11,6 +11,7 @@ import { float, int, mediumint, + primaryKey, singlestoreEnum, singlestoreTable, smallint, @@ -314,6 +315,86 @@ const singlestoreSuite: DialectSuite = { createTableWithGeneratedConstraint: function(context?: any): Promise { return {} as any; }, + createCompositePrimaryKey: async function(context: any): Promise { + const schema1 = {}; + + const schema2 = { + table: singlestoreTable('table', { + col1: int('col1').notNull(), + col2: int('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table', + schema: undefined, + internals: { + indexes: {}, + tables: {}, + }, + compositePKs: ['table_col1_col2_pk;col1,col2'], + compositePkName: 'table_col1_col2_pk', + uniqueConstraints: [], + columns: [ + { name: 'col1', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + { name: 'col2', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + ], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `table` (\n\t`col1` int NOT NULL,\n\t`col2` int NOT NULL,\n\tCONSTRAINT `table_col1_col2_pk` PRIMARY KEY(`col1`,`col2`)\n);\n', + ]); + }, + renameTableWithCompositePrimaryKey: async function(context?: any): Promise { + const productsCategoriesTable = (tableName: string) => { + return singlestoreTable(tableName, { + productId: varchar('product_id', { length: 10 }).notNull(), + categoryId: varchar('category_id', { length: 10 }).notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + 'drizzle', + false, + ); + + // It's not possible to create/alter/drop primary keys in SingleStore + expect(sqlStatements).toStrictEqual([ + 'RENAME TABLE `products_categories` TO `products_to_categories`;', + ]); + + await context.client.query(`DROP TABLE \`products_categories\``); + }, }; run( diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index a383ab717..9c7f212aa 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -18,7 +18,7 @@ import { PgTable, PgView, } from 'drizzle-orm/pg-core'; -import { SingleStoreSchema, SingleStoreTable, SingleStoreView } from 'drizzle-orm/singlestore-core'; +import { SingleStoreSchema, SingleStoreTable } from 'drizzle-orm/singlestore-core'; import { SQLiteTable, SQLiteView } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; @@ -33,7 +33,6 @@ import { roleResolver, schemasResolver, sequencesResolver, - singleStoreViewsResolver, sqliteViewsResolver, tablesResolver, viewsResolver, @@ -102,7 +101,7 @@ export type MysqlSchema = Record< export type SqliteSchema = Record | SQLiteView>; export type SinglestoreSchema = Record< string, - SingleStoreTable | SingleStoreSchema | SingleStoreView + SingleStoreTable | SingleStoreSchema /* | SingleStoreView */ >; export const testSchemasResolver = @@ -1548,20 +1547,20 @@ export const diffTestSchemasSingleStore = async ( ) => { const leftTables = Object.values(left).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; - const leftViews = Object.values(left).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + /* const leftViews = Object.values(left).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */ const rightTables = Object.values(right).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; - const rightViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + /* const rightViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */ const serialized1 = generateSingleStoreSnapshot( leftTables, - leftViews, + /* leftViews, */ casing, ); const serialized2 = generateSingleStoreSnapshot( rightTables, - rightViews, + /* rightViews, */ casing, ); @@ -1598,7 +1597,7 @@ export const diffTestSchemasSingleStore = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), - testViewsResolverMySql(renames), + /* testViewsResolverSingleStore(renames), */ validatedPrev, validatedCur, ); @@ -1610,7 +1609,7 @@ export const diffTestSchemasSingleStore = async ( sn2, tablesResolver, columnsResolver, - mySqlViewsResolver, + /* singleStoreViewsResolver, */ validatedPrev, validatedCur, ); @@ -1643,11 +1642,11 @@ export const diffTestSchemasPushSingleStore = async ( const leftTables = Object.values(right).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; - const leftViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + /* const leftViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */ const serialized2 = generateSingleStoreSnapshot( leftTables, - leftViews, + /* leftViews, */ casing, ); @@ -1684,7 +1683,7 @@ export const diffTestSchemasPushSingleStore = async ( sn2, testTablesResolver(renames), testColumnsResolver(renames), - testViewsResolverSingleStore(renames), + /* testViewsResolverSingleStore(renames), */ validatedPrev, validatedCur, 'push', @@ -1696,7 +1695,7 @@ export const diffTestSchemasPushSingleStore = async ( sn2, tablesResolver, columnsResolver, - singleStoreViewsResolver, + /* singleStoreViewsResolver, */ validatedPrev, validatedCur, 'push', @@ -1727,9 +1726,9 @@ export const applySingleStoreDiffs = async ( const tables = Object.values(sn).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; - const views = Object.values(sn).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; + /* const views = Object.values(sn).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */ - const serialized1 = generateSingleStoreSnapshot(tables, views, casing); + const serialized1 = generateSingleStoreSnapshot(tables, /* views, */ casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; @@ -1751,7 +1750,7 @@ export const applySingleStoreDiffs = async ( sn1, testTablesResolver(new Set()), testColumnsResolver(new Set()), - testViewsResolverSingleStore(new Set()), + /* testViewsResolverSingleStore(new Set()), */ validatedPrev, validatedCur, ); @@ -2464,7 +2463,7 @@ export const introspectSingleStoreToFile = async ( const afterFileImports = generateSingleStoreSnapshot( response.tables, - response.views, + /* response.views, */ casing, ); @@ -2485,7 +2484,7 @@ export const introspectSingleStoreToFile = async ( const initSnapshot = generateSingleStoreSnapshot( leftTables, - response.views, + /* response.views, */ casing, ); @@ -2510,7 +2509,7 @@ export const introspectSingleStoreToFile = async ( initSn, testTablesResolver(new Set()), testColumnsResolver(new Set()), - testViewsResolverSingleStore(new Set()), + /* testViewsResolverSingleStore(new Set()), */ validatedCurAfterImport, validatedCur, ); diff --git a/drizzle-kit/tests/singlestore-views.test.ts b/drizzle-kit/tests/singlestore-views.test.ts deleted file mode 100644 index 93b726276..000000000 --- a/drizzle-kit/tests/singlestore-views.test.ts +++ /dev/null @@ -1,555 +0,0 @@ -import { sql } from 'drizzle-orm'; -import { int, singlestoreTable, singlestoreView } from 'drizzle-orm/singlestore-core'; -import { expect, test } from 'vitest'; -import { diffTestSchemasSingleStore } from './schemaDiffer'; - -test.skip('create view #1', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - }; - const to = { - users: users, - view: singlestoreView('some_view').as((qb) => qb.select().from(users)), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'singlestore_create_view', - name: 'some_view', - algorithm: 'undefined', - replace: false, - definition: 'select `id` from `users`', - withCheckOption: undefined, - sqlSecurity: 'definer', - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`CREATE ALGORITHM = undefined -SQL SECURITY definer -VIEW \`some_view\` AS (select \`id\` from \`users\`);`); -}); - -test.skip('create view #2', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - }; - const to = { - users: users, - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'singlestore_create_view', - name: 'some_view', - algorithm: 'merge', - replace: false, - definition: 'SELECT * FROM \`users\`', - withCheckOption: 'cascaded', - sqlSecurity: 'definer', - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`CREATE ALGORITHM = merge -SQL SECURITY definer -VIEW \`some_view\` AS (SELECT * FROM \`users\`) -WITH cascaded CHECK OPTION;`); -}); - -test('create view with existing flag', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - }; - const to = { - users: users, - view: singlestoreView('some_view', {}).existing(), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); - -// Views are not currently supported by this driver -test.skip('drop view', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - const to = { - users: users, - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'drop_view', - name: 'some_view', - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`DROP VIEW \`some_view\`;`); -}); - -test('drop view with existing flag', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').existing(), - }; - const to = { - users: users, - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); - -// Views are not currently supported by this driver -test.skip('rename view', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - const to = { - users: users, - view: singlestoreView('new_some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ - 'public.some_view->public.new_some_view', - ]); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - type: 'rename_view', - nameFrom: 'some_view', - nameTo: 'new_some_view', - }); - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); -}); - -test.skip('rename view and alter meta options', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - const to = { - users: users, - view: singlestoreView('new_some_view', {}).sqlSecurity('definer') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ - 'public.some_view->public.new_some_view', - ]); - - expect(statements.length).toBe(2); - expect(statements[0]).toStrictEqual({ - type: 'rename_view', - nameFrom: 'some_view', - nameTo: 'new_some_view', - }); - expect(statements[1]).toStrictEqual({ - algorithm: 'undefined', - columns: {}, - definition: 'SELECT * FROM `users`', - isExisting: false, - name: 'new_some_view', - sqlSecurity: 'definer', - type: 'alter_singlestore_view', - withCheckOption: 'cascaded', - }); - expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); - expect(sqlStatements[1]).toBe(`ALTER ALGORITHM = undefined -SQL SECURITY definer -VIEW \`new_some_view\` AS SELECT * FROM \`users\` -WITH cascaded CHECK OPTION;`); -}); - -test('rename view with existing flag', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').existing(), - }; - const to = { - users: users, - view: singlestoreView('new_some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').existing(), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ - 'public.some_view->public.new_some_view', - ]); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); - -test.skip('add meta to view', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).as(sql`SELECT * FROM ${users}`), - }; - const to = { - users: users, - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - algorithm: 'merge', - columns: {}, - definition: 'SELECT * FROM `users`', - isExisting: false, - name: 'some_view', - sqlSecurity: 'definer', - type: 'alter_singlestore_view', - withCheckOption: 'cascaded', - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = merge -SQL SECURITY definer -VIEW \`some_view\` AS SELECT * FROM \`users\` -WITH cascaded CHECK OPTION;`); -}); - -test('add meta to view with existing flag', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).existing(), - }; - const to = { - users: users, - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').existing(), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); - -test.skip('alter meta to view', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - const to = { - users: users, - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - algorithm: 'merge', - columns: {}, - definition: 'SELECT * FROM `users`', - isExisting: false, - name: 'some_view', - sqlSecurity: 'definer', - type: 'alter_singlestore_view', - withCheckOption: 'cascaded', - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = merge -SQL SECURITY definer -VIEW \`some_view\` AS SELECT * FROM \`users\` -WITH cascaded CHECK OPTION;`); -}); - -test('alter meta to view with existing flag', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') - .withCheckOption('cascaded').existing(), - }; - const to = { - users: users, - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').existing(), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); - -test.skip('drop meta from view', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - const to = { - users: users, - view: singlestoreView('some_view', {}).as(sql`SELECT * FROM ${users}`), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - algorithm: 'undefined', - columns: {}, - definition: 'SELECT * FROM `users`', - isExisting: false, - name: 'some_view', - sqlSecurity: 'definer', - type: 'alter_singlestore_view', - withCheckOption: undefined, - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`ALTER ALGORITHM = undefined -SQL SECURITY definer -VIEW \`some_view\` AS SELECT * FROM \`users\`;`); -}); - -test('drop meta from view existing flag', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - - view: singlestoreView('some_view', {}).algorithm('merge').sqlSecurity('definer') - .withCheckOption('cascaded').existing(), - }; - const to = { - users: users, - view: singlestoreView('some_view', {}).existing(), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); - -test.skip('alter view ".as" value', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - const to = { - users: users, - view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, []); - - expect(statements.length).toBe(1); - expect(statements[0]).toStrictEqual({ - algorithm: 'temptable', - definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', - name: 'some_view', - sqlSecurity: 'invoker', - type: 'singlestore_create_view', - withCheckOption: 'cascaded', - replace: true, - }); - - expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`CREATE OR REPLACE ALGORITHM = temptable -SQL SECURITY invoker -VIEW \`some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) -WITH cascaded CHECK OPTION;`); -}); - -test.skip('rename and alter view ".as" value', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - const to = { - users: users, - view: singlestoreView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ - 'public.some_view->public.new_some_view', - ]); - - expect(statements.length).toBe(2); - expect(statements[0]).toStrictEqual({ - nameFrom: 'some_view', - nameTo: 'new_some_view', - type: 'rename_view', - }); - expect(statements[1]).toStrictEqual({ - algorithm: 'temptable', - definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', - name: 'new_some_view', - sqlSecurity: 'invoker', - type: 'singlestore_create_view', - withCheckOption: 'cascaded', - replace: true, - }); - - expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`RENAME TABLE \`some_view\` TO \`new_some_view\`;`); - expect(sqlStatements[1]).toBe(`CREATE OR REPLACE ALGORITHM = temptable -SQL SECURITY invoker -VIEW \`new_some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) -WITH cascaded CHECK OPTION;`); -}); - -test('set existing', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users}`), - }; - const to = { - users: users, - view: singlestoreView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') - .withCheckOption('cascaded').existing(), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ - 'public.some_view->public.new_some_view', - ]); - - expect(statements.length).toBe(0); - expect(sqlStatements.length).toBe(0); -}); - -test.skip('drop existing', async () => { - const users = singlestoreTable('users', { - id: int('id').primaryKey().notNull(), - }); - - const from = { - users: users, - view: singlestoreView('some_view', {}).algorithm('temptable').sqlSecurity('invoker') - .withCheckOption('cascaded').existing(), - }; - const to = { - users: users, - view: singlestoreView('new_some_view', {}).algorithm('temptable').sqlSecurity('invoker') - .withCheckOption('cascaded').as(sql`SELECT * FROM ${users} WHERE ${users.id} = 1`), - }; - - const { statements, sqlStatements } = await diffTestSchemasSingleStore(from, to, [ - 'public.some_view->public.new_some_view', - ]); - - expect(statements.length).toBe(2); - expect(statements[0]).toStrictEqual({ - name: 'new_some_view', - type: 'drop_view', - }); - expect(statements[1]).toStrictEqual({ - algorithm: 'temptable', - definition: 'SELECT * FROM `users` WHERE `users`.`id` = 1', - name: 'new_some_view', - sqlSecurity: 'invoker', - type: 'singlestore_create_view', - withCheckOption: 'cascaded', - replace: false, - }); - - expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`DROP VIEW \`new_some_view\`;`); - expect(sqlStatements[1]).toBe(`CREATE ALGORITHM = temptable -SQL SECURITY invoker -VIEW \`new_some_view\` AS (SELECT * FROM \`users\` WHERE \`users\`.\`id\` = 1) -WITH cascaded CHECK OPTION;`); -}); diff --git a/drizzle-orm/src/singlestore-core/columns/bigint.ts b/drizzle-orm/src/singlestore-core/columns/bigint.ts index b0e0c0ea2..c29c531fa 100644 --- a/drizzle-orm/src/singlestore-core/columns/bigint.ts +++ b/drizzle-orm/src/singlestore-core/columns/bigint.ts @@ -1,10 +1,16 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreBigInt53BuilderInitial = SingleStoreBigInt53Builder<{ name: TName; @@ -20,7 +26,10 @@ export class SingleStoreBigInt53Builder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreBigInt53Builder'; @@ -72,7 +81,10 @@ export class SingleStoreBigInt64Builder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreBigInt64Builder'; diff --git a/drizzle-orm/src/singlestore-core/columns/binary.ts b/drizzle-orm/src/singlestore-core/columns/binary.ts index 45cdf7743..4d5f65fc0 100644 --- a/drizzle-orm/src/singlestore-core/columns/binary.ts +++ b/drizzle-orm/src/singlestore-core/columns/binary.ts @@ -1,10 +1,16 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreBinaryBuilderInitial = SingleStoreBinaryBuilder<{ name: TName; @@ -23,7 +29,10 @@ export class SingleStoreBinaryBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreBinaryBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/boolean.ts b/drizzle-orm/src/singlestore-core/columns/boolean.ts index f6df9c3fa..b02d3741f 100644 --- a/drizzle-orm/src/singlestore-core/columns/boolean.ts +++ b/drizzle-orm/src/singlestore-core/columns/boolean.ts @@ -1,9 +1,15 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; import type { SQL } from '~/sql/index.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreBooleanBuilderInitial = SingleStoreBooleanBuilder<{ name: TName; @@ -19,7 +25,10 @@ export class SingleStoreBooleanBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreBooleanBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/char.ts b/drizzle-orm/src/singlestore-core/columns/char.ts index 8bcb36fa6..3a5603e00 100644 --- a/drizzle-orm/src/singlestore-core/columns/char.ts +++ b/drizzle-orm/src/singlestore-core/columns/char.ts @@ -1,10 +1,16 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreCharBuilderInitial = SingleStoreCharBuilder<{ @@ -24,7 +30,10 @@ export class SingleStoreCharBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreCharBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/custom.ts b/drizzle-orm/src/singlestore-core/columns/custom.ts index 3a50bc328..dec4574ed 100644 --- a/drizzle-orm/src/singlestore-core/columns/custom.ts +++ b/drizzle-orm/src/singlestore-core/columns/custom.ts @@ -1,4 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; @@ -36,7 +42,10 @@ export class SingleStoreCustomColumnBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreCustomColumnBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/date.ts b/drizzle-orm/src/singlestore-core/columns/date.ts index 1940757aa..62d31d761 100644 --- a/drizzle-orm/src/singlestore-core/columns/date.ts +++ b/drizzle-orm/src/singlestore-core/columns/date.ts @@ -1,10 +1,16 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreDateBuilderInitial = SingleStoreDateBuilder<{ name: TName; @@ -20,7 +26,10 @@ export class SingleStoreDateBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreDateBuilder'; @@ -73,7 +82,10 @@ export class SingleStoreDateStringBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreDateStringBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts index 9cc359438..bacffa1c3 100644 --- a/drizzle-orm/src/singlestore-core/columns/datetime.ts +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -1,10 +1,16 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreDateTimeBuilderInitial = SingleStoreDateTimeBuilder<{ name: TName; @@ -20,7 +26,10 @@ export class SingleStoreDateTimeBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreDateTimeBuilder'; @@ -85,7 +94,10 @@ export class SingleStoreDateTimeStringBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreDateTimeStringBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts index 2f452d1bd..7c10dc83f 100644 --- a/drizzle-orm/src/singlestore-core/columns/decimal.ts +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -1,10 +1,16 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreDecimalBuilderInitial = SingleStoreDecimalBuilder<{ name: TName; @@ -20,7 +26,10 @@ export class SingleStoreDecimalBuilder< T extends ColumnBuilderBaseConfig<'string', 'SingleStoreDecimal'>, > extends SingleStoreColumnBuilderWithAutoIncrement { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreDecimalBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/double.ts b/drizzle-orm/src/singlestore-core/columns/double.ts index 919f5c893..bf19d49c0 100644 --- a/drizzle-orm/src/singlestore-core/columns/double.ts +++ b/drizzle-orm/src/singlestore-core/columns/double.ts @@ -1,10 +1,16 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreDoubleBuilderInitial = SingleStoreDoubleBuilder<{ name: TName; @@ -20,7 +26,10 @@ export class SingleStoreDoubleBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: T['data'] | SQL | (() => SQL), config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: T['data'] | SQL | (() => SQL), + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreDoubleBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/enum.ts b/drizzle-orm/src/singlestore-core/columns/enum.ts index e8d62ede0..98f3d78e3 100644 --- a/drizzle-orm/src/singlestore-core/columns/enum.ts +++ b/drizzle-orm/src/singlestore-core/columns/enum.ts @@ -1,4 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; @@ -21,7 +27,10 @@ export class SingleStoreEnumColumnBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreEnumColumnBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts index 08931505c..6d6075ca6 100644 --- a/drizzle-orm/src/singlestore-core/columns/float.ts +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -1,10 +1,16 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreFloatBuilderInitial = SingleStoreFloatBuilder<{ name: TName; @@ -20,7 +26,10 @@ export class SingleStoreFloatBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreFloatBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/int.ts b/drizzle-orm/src/singlestore-core/columns/int.ts index 994148045..5a7ab2167 100644 --- a/drizzle-orm/src/singlestore-core/columns/int.ts +++ b/drizzle-orm/src/singlestore-core/columns/int.ts @@ -1,10 +1,16 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreIntBuilderInitial = SingleStoreIntBuilder<{ name: TName; @@ -20,7 +26,10 @@ export class SingleStoreIntBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreIntBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/json.ts b/drizzle-orm/src/singlestore-core/columns/json.ts index db00df33b..cdacbac82 100644 --- a/drizzle-orm/src/singlestore-core/columns/json.ts +++ b/drizzle-orm/src/singlestore-core/columns/json.ts @@ -1,9 +1,15 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; import type { SQL } from '~/sql/index.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreJsonBuilderInitial = SingleStoreJsonBuilder<{ name: TName; @@ -19,7 +25,10 @@ export class SingleStoreJsonBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: T['data'] | SQL | (() => SQL), config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: T['data'] | SQL | (() => SQL), + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreJsonBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/mediumint.ts b/drizzle-orm/src/singlestore-core/columns/mediumint.ts index 78aa23984..7231e58ff 100644 --- a/drizzle-orm/src/singlestore-core/columns/mediumint.ts +++ b/drizzle-orm/src/singlestore-core/columns/mediumint.ts @@ -1,11 +1,17 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreMediumIntBuilderInitial = SingleStoreMediumIntBuilder<{ name: TName; @@ -21,7 +27,10 @@ export class SingleStoreMediumIntBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreMediumIntBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/real.ts b/drizzle-orm/src/singlestore-core/columns/real.ts index fb099b483..4ba09c200 100644 --- a/drizzle-orm/src/singlestore-core/columns/real.ts +++ b/drizzle-orm/src/singlestore-core/columns/real.ts @@ -1,10 +1,16 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreRealBuilderInitial = SingleStoreRealBuilder<{ name: TName; @@ -23,7 +29,10 @@ export class SingleStoreRealBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreRealBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/serial.ts b/drizzle-orm/src/singlestore-core/columns/serial.ts index 1bbf4cbbc..4b7a618e0 100644 --- a/drizzle-orm/src/singlestore-core/columns/serial.ts +++ b/drizzle-orm/src/singlestore-core/columns/serial.ts @@ -12,8 +12,8 @@ import type { import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SQL } from '~/sql/index.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreSerialBuilderInitial = IsAutoincrement< IsPrimaryKey< @@ -37,7 +37,10 @@ export class SingleStoreSerialBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreSerialBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/smallint.ts b/drizzle-orm/src/singlestore-core/columns/smallint.ts index 17177bc52..4011662e0 100644 --- a/drizzle-orm/src/singlestore-core/columns/smallint.ts +++ b/drizzle-orm/src/singlestore-core/columns/smallint.ts @@ -1,4 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; @@ -21,7 +27,10 @@ export class SingleStoreSmallIntBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreSmallIntBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/text.ts b/drizzle-orm/src/singlestore-core/columns/text.ts index ede9f2f94..d69728375 100644 --- a/drizzle-orm/src/singlestore-core/columns/text.ts +++ b/drizzle-orm/src/singlestore-core/columns/text.ts @@ -1,4 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; @@ -26,7 +32,10 @@ export class SingleStoreTextBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreTextBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/time.ts b/drizzle-orm/src/singlestore-core/columns/time.ts index 27bcfe342..405700177 100644 --- a/drizzle-orm/src/singlestore-core/columns/time.ts +++ b/drizzle-orm/src/singlestore-core/columns/time.ts @@ -1,10 +1,16 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -import type { SQL } from '~/sql/index.ts'; export type SingleStoreTimeBuilderInitial = SingleStoreTimeBuilder<{ name: TName; @@ -23,7 +29,10 @@ export class SingleStoreTimeBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreTimeBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts index ddd3dc695..17d76fb0f 100644 --- a/drizzle-orm/src/singlestore-core/columns/timestamp.ts +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -1,4 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; @@ -21,7 +27,10 @@ export class SingleStoreTimestampBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreTimestampBuilder'; @@ -82,7 +91,10 @@ export class SingleStoreTimestampStringBuilder< T extends ColumnBuilderBaseConfig<'string', 'SingleStoreTimestampString'>, > extends SingleStoreDateColumnBaseBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreTimestampStringBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/tinyint.ts b/drizzle-orm/src/singlestore-core/columns/tinyint.ts index ff822ea2f..a25b89a6d 100644 --- a/drizzle-orm/src/singlestore-core/columns/tinyint.ts +++ b/drizzle-orm/src/singlestore-core/columns/tinyint.ts @@ -1,4 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; @@ -21,7 +27,10 @@ export class SingleStoreTinyIntBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreTinyIntBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/varbinary.ts b/drizzle-orm/src/singlestore-core/columns/varbinary.ts index 81188e15c..0b0323784 100644 --- a/drizzle-orm/src/singlestore-core/columns/varbinary.ts +++ b/drizzle-orm/src/singlestore-core/columns/varbinary.ts @@ -1,4 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; @@ -20,7 +26,10 @@ export class SingleStoreVarBinaryBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreVarBinaryBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/varchar.ts b/drizzle-orm/src/singlestore-core/columns/varchar.ts index a2282639e..82f232c29 100644 --- a/drizzle-orm/src/singlestore-core/columns/varchar.ts +++ b/drizzle-orm/src/singlestore-core/columns/varchar.ts @@ -1,4 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; @@ -23,7 +29,10 @@ export class SingleStoreVarCharBuilder> { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreVarCharBuilder'; diff --git a/drizzle-orm/src/singlestore-core/columns/year.ts b/drizzle-orm/src/singlestore-core/columns/year.ts index c9ddf24e8..a6ab07e30 100644 --- a/drizzle-orm/src/singlestore-core/columns/year.ts +++ b/drizzle-orm/src/singlestore-core/columns/year.ts @@ -1,4 +1,10 @@ -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, GeneratedColumnConfig, HasGenerated, MakeColumnConfig } from '~/column-builder.ts'; +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; @@ -19,7 +25,10 @@ export class SingleStoreYearBuilder { // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: Partial>): HasGenerated { + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreYearBuilder'; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 951a5cac7..4ac14d88c 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -34,7 +34,7 @@ import type { import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; import type { SingleStoreSession } from './session.ts'; import { SingleStoreTable } from './table.ts'; -import { SingleStoreViewBase } from './view-base.ts'; +/* import { SingleStoreViewBase } from './view-base.ts'; */ export interface SingleStoreDialectConfig { casing?: Casing; @@ -268,8 +268,8 @@ export class SingleStoreDialect { && getTableName(f.field.table) !== (is(table, Subquery) ? table._.alias - : is(table, SingleStoreViewBase) - ? table[ViewBaseConfig].name + /* : is(table, SingleStoreViewBase) + ? table[ViewBaseConfig].name */ : is(table, SQL) ? undefined : getTableName(table)) diff --git a/drizzle-orm/src/singlestore-core/query-builders/count.ts b/drizzle-orm/src/singlestore-core/query-builders/count.ts index 931e76a6f..aba5b2f3f 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/count.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/count.ts @@ -2,7 +2,7 @@ import { entityKind } from '~/entity.ts'; import { SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import type { SingleStoreSession } from '../session.ts'; import type { SingleStoreTable } from '../table.ts'; -import type { SingleStoreViewBase } from '../view-base.ts'; +/* import type { SingleStoreViewBase } from '../view-base.ts'; */ export class SingleStoreCountBuilder< TSession extends SingleStoreSession, @@ -15,14 +15,14 @@ export class SingleStoreCountBuilder< private session: TSession; private static buildEmbeddedCount( - source: SingleStoreTable | SingleStoreViewBase | SQL | SQLWrapper, + source: SingleStoreTable | /* SingleStoreViewBase | */ SQL | SQLWrapper, filters?: SQL, ): SQL { return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; } private static buildCount( - source: SingleStoreTable | SingleStoreViewBase | SQL | SQLWrapper, + source: SingleStoreTable | /* SingleStoreViewBase | */ SQL | SQLWrapper, filters?: SQL, ): SQL { return sql`select count(*) as count from ${source}${sql.raw(' where ').if(filters)}${filters}`; @@ -30,7 +30,7 @@ export class SingleStoreCountBuilder< constructor( readonly params: { - source: SingleStoreTable | SingleStoreViewBase | SQL | SQLWrapper; + source: SingleStoreTable | /* SingleStoreViewBase | */ SQL | SQLWrapper; filters?: SQL; session: TSession; }, diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts index e36a0f154..75bc8d783 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts @@ -24,7 +24,7 @@ import type { Table, UpdateTableConfig } from '~/table.ts'; import type { Assume, ValidateShape } from '~/utils.ts'; import type { PreparedQueryHKTBase, PreparedQueryKind, SingleStorePreparedQueryConfig } from '../session.ts'; /* import type { SingleStoreViewBase } from '../view-base.ts'; */ -import type { SingleStoreViewWithSelection } from '../view.ts'; +/* import type { SingleStoreViewWithSelection } from '../view.ts'; */ import type { SingleStoreSelectBase, SingleStoreSelectQueryBuilderBase } from './select.ts'; export interface SingleStoreSelectJoinConfig { @@ -42,11 +42,11 @@ export type BuildAliasTable; }> > - : TTable extends View ? SingleStoreViewWithSelection< + /* : TTable extends View ? SingleStoreViewWithSelection< TAlias, TTable['_']['existing'], MapColumnsToTableAlias - > + > */ : never; export interface SingleStoreSelectConfig { From 2816180ee72bd2de865be27401b9af6d14fa8934 Mon Sep 17 00:00:00 2001 From: prodrigues Date: Thu, 14 Nov 2024 01:31:25 +0000 Subject: [PATCH 351/492] remove mode from drizzle-orm --- drizzle-orm/src/singlestore-core/db.ts | 3 --- .../singlestore-core/query-builders/query.ts | 5 ----- drizzle-orm/src/singlestore-core/session.ts | 5 +---- drizzle-orm/src/singlestore-proxy/driver.ts | 2 +- drizzle-orm/src/singlestore/driver.ts | 20 ++++--------------- drizzle-orm/src/singlestore/session.ts | 6 ------ drizzle-orm/type-tests/singlestore/db.ts | 5 ++--- 7 files changed, 8 insertions(+), 38 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 2f4814544..6e8f18f44 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -18,7 +18,6 @@ import { import { RelationalQueryBuilder } from './query-builders/query.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import type { - Mode, PreparedQueryHKTBase, SingleStoreQueryResultHKT, SingleStoreQueryResultKind, @@ -55,7 +54,6 @@ export class SingleStoreDatabase< /** @internal */ readonly session: SingleStoreSession, schema: RelationalSchemaConfig | undefined, - protected readonly mode: Mode, ) { this._ = schema ? { @@ -80,7 +78,6 @@ export class SingleStoreDatabase< columns, dialect, session, - this.mode, ); } } diff --git a/drizzle-orm/src/singlestore-core/query-builders/query.ts b/drizzle-orm/src/singlestore-core/query-builders/query.ts index b42fb4f39..c15f7ad59 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/query.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/query.ts @@ -12,7 +12,6 @@ import type { Query, QueryWithTypings, SQL } from '~/sql/sql.ts'; import type { KnownKeysOnly } from '~/utils.ts'; import type { SingleStoreDialect } from '../dialect.ts'; import type { - Mode, PreparedQueryHKTBase, PreparedQueryKind, SingleStorePreparedQueryConfig, @@ -35,7 +34,6 @@ export class RelationalQueryBuilder< private tableConfig: TableRelationalConfig, private dialect: SingleStoreDialect, private session: SingleStoreSession, - private mode: Mode, ) {} findMany>( @@ -51,7 +49,6 @@ export class RelationalQueryBuilder< this.session, config ? (config as DBQueryConfig<'many', true>) : {}, 'many', - this.mode, ); } @@ -68,7 +65,6 @@ export class RelationalQueryBuilder< this.session, config ? { ...(config as DBQueryConfig<'many', true> | undefined), limit: 1 } : { limit: 1 }, 'first', - this.mode, ); } } @@ -91,7 +87,6 @@ export class SingleStoreRelationalQuery< private session: SingleStoreSession, private config: DBQueryConfig<'many', true> | true, private queryMode: 'many' | 'first', - private mode?: Mode, ) { super(); } diff --git a/drizzle-orm/src/singlestore-core/session.ts b/drizzle-orm/src/singlestore-core/session.ts index 78d477a27..bc31f3d97 100644 --- a/drizzle-orm/src/singlestore-core/session.ts +++ b/drizzle-orm/src/singlestore-core/session.ts @@ -7,8 +7,6 @@ import { SingleStoreDatabase } from './db.ts'; import type { SingleStoreDialect } from './dialect.ts'; import type { SelectedFieldsOrdered } from './query-builders/select.types.ts'; -export type Mode = 'default'; - export interface SingleStoreQueryResultHKT { readonly $brand: 'SingleStoreQueryResultHKT'; readonly row: unknown; @@ -140,9 +138,8 @@ export abstract class SingleStoreTransaction< session: SingleStoreSession, protected schema: RelationalSchemaConfig | undefined, protected readonly nestedIndex: number, - mode: Mode, ) { - super(dialect, session, schema, mode); + super(dialect, session, schema); } rollback(): never { diff --git a/drizzle-orm/src/singlestore-proxy/driver.ts b/drizzle-orm/src/singlestore-proxy/driver.ts index 6752dedb7..ea24ae2d8 100644 --- a/drizzle-orm/src/singlestore-proxy/driver.ts +++ b/drizzle-orm/src/singlestore-proxy/driver.ts @@ -53,7 +53,7 @@ export function drizzle = Record; } diff --git a/drizzle-orm/src/singlestore/driver.ts b/drizzle-orm/src/singlestore/driver.ts index b413a5ebc..ba294f6dc 100644 --- a/drizzle-orm/src/singlestore/driver.ts +++ b/drizzle-orm/src/singlestore/driver.ts @@ -11,9 +11,7 @@ import { } from '~/relations.ts'; import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; -import type { Mode } from '~/singlestore-core/session.ts'; import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; -import { DrizzleError } from '../errors.ts'; import type { SingleStoreDriverClient, SingleStoreDriverPreparedQueryHKT, @@ -37,9 +35,8 @@ export class SingleStoreDriverDriver { createSession( schema: RelationalSchemaConfig | undefined, - mode: Mode, ): SingleStoreDriverSession, TablesRelationalConfig> { - return new SingleStoreDriverSession(this.client, this.dialect, schema, { logger: this.options.logger, mode }); + return new SingleStoreDriverSession(this.client, this.dialect, schema, { logger: this.options.logger }); } } @@ -53,7 +50,7 @@ export class SingleStoreDriverDatabase< export type SingleStoreDriverDrizzleConfig = Record> = & Omit, 'schema'> - & ({ schema: TSchema; mode: Mode } | { schema?: undefined; mode?: Mode }); + & ({ schema: TSchema } | { schema?: undefined }); function construct< TSchema extends Record = Record, @@ -76,13 +73,6 @@ function construct< let schema: RelationalSchemaConfig | undefined; if (config.schema) { - if (config.mode === undefined) { - throw new DrizzleError({ - message: - 'You need to specify "mode": "planetscale" or "default" when providing a schema. Read more: https://orm.drizzle.team/docs/rqb#modes', - }); - } - const tablesConfig = extractTablesRelationalConfig( config.schema, createTableRelationsHelpers, @@ -94,11 +84,9 @@ function construct< }; } - const mode = config.mode ?? 'default'; - const driver = new SingleStoreDriverDriver(clientForInstance as SingleStoreDriverClient, dialect, { logger }); - const session = driver.createSession(schema, mode); - const db = new SingleStoreDriverDatabase(dialect, session, schema as any, mode) as SingleStoreDriverDatabase; + const session = driver.createSession(schema); + const db = new SingleStoreDriverDatabase(dialect, session, schema as any) as SingleStoreDriverDatabase; ( db).$client = client; return db as any; diff --git a/drizzle-orm/src/singlestore/session.ts b/drizzle-orm/src/singlestore/session.ts index f5868cb70..fd70a1d52 100644 --- a/drizzle-orm/src/singlestore/session.ts +++ b/drizzle-orm/src/singlestore/session.ts @@ -18,7 +18,6 @@ import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; import type { SelectedFieldsOrdered } from '~/singlestore-core/query-builders/select.types.ts'; import { - type Mode, type PreparedQueryKind, SingleStorePreparedQuery, type SingleStorePreparedQueryConfig, @@ -185,7 +184,6 @@ export class SingleStoreDriverPreparedQuery( @@ -272,7 +268,6 @@ export class SingleStoreDriverSession< session as SingleStoreSession, this.schema, 0, - this.mode, ); if (config) { const setTransactionConfigSql = this.getSetTransactionSQL(config); @@ -319,7 +314,6 @@ export class SingleStoreDriverTransaction< this.session, this.schema, this.nestedIndex + 1, - this.mode, ); await tx.execute(sql.raw(`savepoint ${savepointName}`)); try { diff --git a/drizzle-orm/type-tests/singlestore/db.ts b/drizzle-orm/type-tests/singlestore/db.ts index bde149b08..b314e504d 100644 --- a/drizzle-orm/type-tests/singlestore/db.ts +++ b/drizzle-orm/type-tests/singlestore/db.ts @@ -7,8 +7,7 @@ export const db = drizzle(pool); { drizzle(pool); - // @ts-expect-error - missing mode drizzle(pool, { schema: {} }); - drizzle(pool, { schema: {}, mode: 'default' }); - drizzle(pool, { mode: 'default' }); + drizzle(pool, { schema: {} }); + drizzle(pool, {}); } From 0969a7687730075182342ce2647cb267f611092e Mon Sep 17 00:00:00 2001 From: prodrigues Date: Thu, 14 Nov 2024 01:31:37 +0000 Subject: [PATCH 352/492] fix replica integration tests --- .../tests/replicas/singlestore.test.ts | 160 +++++++++--------- .../tests/singlestore/singlestore-common.ts | 23 +-- .../singlestore/singlestore-prefixed.test.ts | 18 +- 3 files changed, 103 insertions(+), 98 deletions(-) diff --git a/integration-tests/tests/replicas/singlestore.test.ts b/integration-tests/tests/replicas/singlestore.test.ts index 76d84c972..56a589224 100644 --- a/integration-tests/tests/replicas/singlestore.test.ts +++ b/integration-tests/tests/replicas/singlestore.test.ts @@ -15,9 +15,9 @@ const users = singlestoreTable('users', { describe('[select] read replicas singlestore', () => { it('primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -35,9 +35,9 @@ describe('[select] read replicas singlestore', () => { }); it('random replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -64,8 +64,8 @@ describe('[select] read replicas singlestore', () => { }); it('single read replica select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -84,8 +84,8 @@ describe('[select] read replicas singlestore', () => { }); it('single read replica select + primary select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -105,9 +105,9 @@ describe('[select] read replicas singlestore', () => { }); it('always first read select', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -134,9 +134,9 @@ describe('[select] read replicas singlestore', () => { describe('[selectDistinct] read replicas singlestore', () => { it('primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -153,9 +153,9 @@ describe('[selectDistinct] read replicas singlestore', () => { }); it('random replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -181,8 +181,8 @@ describe('[selectDistinct] read replicas singlestore', () => { }); it('single read replica selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -201,8 +201,8 @@ describe('[selectDistinct] read replicas singlestore', () => { }); it('single read replica selectDistinct + primary selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -222,9 +222,9 @@ describe('[selectDistinct] read replicas singlestore', () => { }); it('always first read selectDistinct', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -250,9 +250,9 @@ describe('[selectDistinct] read replicas singlestore', () => { describe('[with] read replicas singlestore', () => { it('primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -273,9 +273,9 @@ describe('[with] read replicas singlestore', () => { }); it('random replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -299,8 +299,8 @@ describe('[with] read replicas singlestore', () => { }); it('single read replica with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -317,8 +317,8 @@ describe('[with] read replicas singlestore', () => { }); it('single read replica with + primary with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); const db = withReplicas(primaryDb, [read1]); @@ -336,9 +336,9 @@ describe('[with] read replicas singlestore', () => { }); it('always first read with', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -367,9 +367,9 @@ describe('[with] read replicas singlestore', () => { describe('[update] replicas singlestore', () => { it('primary update', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -402,9 +402,9 @@ describe('[update] replicas singlestore', () => { describe('[delete] replicas singlestore', () => { it('primary delete', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -438,9 +438,9 @@ describe('[delete] replicas singlestore', () => { describe('[insert] replicas singlestore', () => { it('primary insert', () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -473,9 +473,9 @@ describe('[insert] replicas singlestore', () => { describe('[execute] replicas singlestore', () => { it('primary execute', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -515,9 +515,9 @@ describe('[execute] replicas singlestore', () => { describe('[transaction] replicas singlestore', () => { it('primary transaction', async () => { - const primaryDb = drizzle({} as any); - const read1 = drizzle({} as any); - const read2 = drizzle({} as any); + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); const db = withReplicas(primaryDb, [read1, read2]); @@ -558,9 +558,9 @@ describe('[transaction] replicas singlestore', () => { describe('[findFirst] read replicas singlestore', () => { it('primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -578,9 +578,9 @@ describe('[findFirst] read replicas singlestore', () => { }); it('random replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -607,8 +607,8 @@ describe('[findFirst] read replicas singlestore', () => { }); it('single read replica findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -625,8 +625,8 @@ describe('[findFirst] read replicas singlestore', () => { }); it('single read replica findFirst + primary findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -644,9 +644,9 @@ describe('[findFirst] read replicas singlestore', () => { }); it('always first read findFirst', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; @@ -670,9 +670,9 @@ describe('[findFirst] read replicas singlestore', () => { describe('[findMany] read replicas singlestore', () => { it('primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2]); @@ -691,9 +691,9 @@ describe('[findMany] read replicas singlestore', () => { }); it('random replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); @@ -724,8 +724,8 @@ describe('[findMany] read replicas singlestore', () => { }); it('single read replica findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -748,8 +748,8 @@ describe('[findMany] read replicas singlestore', () => { }); it('single read replica findMany + primary findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1]); @@ -774,9 +774,9 @@ describe('[findMany] read replicas singlestore', () => { }); it('always first read findMany', () => { - const primaryDb = drizzle({} as any, { schema: { usersTable } }); - const read1 = drizzle({} as any, { schema: { usersTable } }); - const read2 = drizzle({} as any, { schema: { usersTable } }); + const primaryDb = drizzle.mock({ schema: { usersTable } }); + const read1 = drizzle.mock({ schema: { usersTable } }); + const read2 = drizzle.mock({ schema: { usersTable } }); const db = withReplicas(primaryDb, [read1, read2], (replicas) => { return replicas[0]!; diff --git a/integration-tests/tests/singlestore/singlestore-common.ts b/integration-tests/tests/singlestore/singlestore-common.ts index 037c27202..620715bc9 100644 --- a/integration-tests/tests/singlestore/singlestore-common.ts +++ b/integration-tests/tests/singlestore/singlestore-common.ts @@ -35,7 +35,6 @@ import { decimal, except, getTableConfig, - getViewConfig, int, intersect, json, @@ -46,7 +45,7 @@ import { singlestoreSchema, singlestoreTable, singlestoreTableCreator, - singlestoreView, + /* singlestoreView, */ smallint, text, time, @@ -1832,7 +1831,8 @@ export function tests(driver?: string) { ]); }); - test('view', async (ctx) => { + // TODO: Unskip when views are supported + /* test.skip('view', async (ctx) => { const { db } = ctx.singlestore; const newYorkers1 = singlestoreView('new_yorkers') @@ -1893,7 +1893,7 @@ export function tests(driver?: string) { } await db.execute(sql`drop view ${newYorkers1}`); - }); + }); */ test('select from raw sql', async (ctx) => { const { db } = ctx.singlestore; @@ -2169,7 +2169,8 @@ export function tests(driver?: string) { await db.execute(sql`drop table ${ticket}`); }); - test('subquery with view', async (ctx) => { + // TODO: Unskip when views are supported + /* test.skip('subquery with view', async (ctx) => { const { db } = ctx.singlestore; const users = singlestoreTable('users_subquery_view', { @@ -2205,9 +2206,10 @@ export function tests(driver?: string) { await db.execute(sql`drop view ${newYorkers}`); await db.execute(sql`drop table ${users}`); - }); + }); */ - test('join view as subquery', async (ctx) => { + // TODO: Unskip when views are supported + /* test.skip('join view as subquery', async (ctx) => { const { db } = ctx.singlestore; const users = singlestoreTable('users_join_view', { @@ -2258,7 +2260,7 @@ export function tests(driver?: string) { await db.execute(sql`drop view ${newYorkers}`); await db.execute(sql`drop table ${users}`); - }); + }); */ test('select iterator', async (ctx) => { const { db } = ctx.singlestore; @@ -3342,7 +3344,8 @@ export function tests(driver?: string) { expect(result).toStrictEqual([{ customId: 'test' }, { customId: 'ao865jf3mcmkfkk8o5ri495z' }]); }); - test('mySchema :: view', async (ctx) => { + // TODO: Unkip this test when views are supported + /* test.skip('mySchema :: view', async (ctx) => { const { db } = ctx.singlestore; const newYorkers1 = mySchema.view('new_yorkers') @@ -3403,7 +3406,7 @@ export function tests(driver?: string) { } await db.execute(sql`drop view ${newYorkers1}`); - }); + }); */ test('limit 0', async (ctx) => { const { db } = ctx.singlestore; diff --git a/integration-tests/tests/singlestore/singlestore-prefixed.test.ts b/integration-tests/tests/singlestore/singlestore-prefixed.test.ts index 224ad433d..af7912216 100644 --- a/integration-tests/tests/singlestore/singlestore-prefixed.test.ts +++ b/integration-tests/tests/singlestore/singlestore-prefixed.test.ts @@ -9,14 +9,13 @@ import { boolean, date, datetime, - getViewConfig, int, json, serial, singlestoreEnum, singlestoreTable as singlestoreTableRaw, singlestoreTableCreator, - singlestoreView, + /* singlestoreView, */ text, time, timestamp, @@ -1085,7 +1084,8 @@ test('having', async () => { ]); }); -test('view', async () => { +// TODO: Unskip when views are supported +/* test.skip('view', async () => { const newYorkers1 = singlestoreView('new_yorkers') .as((qb) => qb.select().from(users2Table).where(eq(users2Table.cityId, 1))); @@ -1144,7 +1144,7 @@ test('view', async () => { } await db.execute(sql`drop view ${newYorkers1}`); -}); +}); */ test('select from raw sql', async () => { const result = await db.select({ @@ -1396,7 +1396,8 @@ test('join subquery with join', async () => { }]); }); -test('subquery with view', async () => { +// TODO: Unskip when views are supported +/* test.skip('subquery with view', async () => { const users = singlestoreTable('users_subquery_view', { id: serial('id').primaryKey(), name: text('name').notNull(), @@ -1430,9 +1431,10 @@ test('subquery with view', async () => { { id: 1, name: 'John', cityId: 1 }, { id: 3, name: 'Jack', cityId: 1 }, ]); -}); +}); */ -test('join view as subquery', async () => { +// TODO: Unskip when views are supported +/* test.skip('join view as subquery', async () => { const users = singlestoreTable('users_join_view', { id: serial('id').primaryKey(), name: text('name').notNull(), @@ -1481,7 +1483,7 @@ test('join view as subquery', async () => { await db.execute(sql`drop view ${newYorkers}`); await db.execute(sql`drop table ${users}`); -}); +}); */ test('select iterator', async () => { const users = singlestoreTable('users_iterator', { From b2e95af325c5f588cbe3349c106533d5ff395b7b Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 14 Nov 2024 11:06:00 +0200 Subject: [PATCH 353/492] Upgrade turbo to v2 --- package.json | 3 +- pnpm-lock.yaml | 175 ++++++++++++++++++++++++++++++++++++------------- turbo.json | 162 ++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 280 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index 29189a91b..d52a568a6 100755 --- a/package.json +++ b/package.json @@ -1,4 +1,5 @@ { + "name": "drizzle-root", "private": true, "scripts": { "build:orm": "turbo run build --filter drizzle-orm --color", @@ -34,7 +35,7 @@ "resolve-tspaths": "^0.8.16", "tsup": "^7.2.0", "tsx": "^4.10.5", - "turbo": "^1.10.14", + "turbo": "^2.2.3", "typescript": "5.6.3" }, "packageManager": "pnpm@9.7.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3eefe9fd5..759aad057 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,7 +40,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -73,13 +73,13 @@ importers: version: 0.8.16(typescript@5.6.3) tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3))(typescript@5.6.3) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3) tsx: specifier: ^4.10.5 version: 4.10.5 turbo: - specifier: ^1.10.14 - version: 1.10.14 + specifier: ^2.2.3 + version: 2.2.3 typescript: specifier: 5.6.3 version: 5.6.3 @@ -7184,12 +7184,10 @@ packages: libsql@0.3.19: resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] libsql@0.4.1: resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -9491,38 +9489,38 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - turbo-darwin-64@1.10.14: - resolution: {integrity: sha512-I8RtFk1b9UILAExPdG/XRgGQz95nmXPE7OiGb6ytjtNIR5/UZBS/xVX/7HYpCdmfriKdVwBKhalCoV4oDvAGEg==} + turbo-darwin-64@2.2.3: + resolution: {integrity: sha512-Rcm10CuMKQGcdIBS3R/9PMeuYnv6beYIHqfZFeKWVYEWH69sauj4INs83zKMTUiZJ3/hWGZ4jet9AOwhsssLyg==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@1.10.14: - resolution: {integrity: sha512-KAdUWryJi/XX7OD0alOuOa0aJ5TLyd4DNIYkHPHYcM6/d7YAovYvxRNwmx9iv6Vx6IkzTnLeTiUB8zy69QkG9Q==} + turbo-darwin-arm64@2.2.3: + resolution: {integrity: sha512-+EIMHkuLFqUdJYsA3roj66t9+9IciCajgj+DVek+QezEdOJKcRxlvDOS2BUaeN8kEzVSsNiAGnoysFWYw4K0HA==} cpu: [arm64] os: [darwin] - turbo-linux-64@1.10.14: - resolution: {integrity: sha512-BOBzoREC2u4Vgpap/WDxM6wETVqVMRcM8OZw4hWzqCj2bqbQ6L0wxs1LCLWVrghQf93JBQtIGAdFFLyCSBXjWQ==} + turbo-linux-64@2.2.3: + resolution: {integrity: sha512-UBhJCYnqtaeOBQLmLo8BAisWbc9v9daL9G8upLR+XGj6vuN/Nz6qUAhverN4Pyej1g4Nt1BhROnj6GLOPYyqxQ==} cpu: [x64] os: [linux] - turbo-linux-arm64@1.10.14: - resolution: {integrity: sha512-D8T6XxoTdN5D4V5qE2VZG+/lbZX/89BkAEHzXcsSUTRjrwfMepT3d2z8aT6hxv4yu8EDdooZq/2Bn/vjMI32xw==} + turbo-linux-arm64@2.2.3: + resolution: {integrity: sha512-hJYT9dN06XCQ3jBka/EWvvAETnHRs3xuO/rb5bESmDfG+d9yQjeTMlhRXKrr4eyIMt6cLDt1LBfyi+6CQ+VAwQ==} cpu: [arm64] os: [linux] - turbo-windows-64@1.10.14: - resolution: {integrity: sha512-zKNS3c1w4i6432N0cexZ20r/aIhV62g69opUn82FLVs/zk3Ie0GVkSB6h0rqIvMalCp7enIR87LkPSDGz9K4UA==} + turbo-windows-64@2.2.3: + resolution: {integrity: sha512-NPrjacrZypMBF31b4HE4ROg4P3nhMBPHKS5WTpMwf7wydZ8uvdEHpESVNMOtqhlp857zbnKYgP+yJF30H3N2dQ==} cpu: [x64] os: [win32] - turbo-windows-arm64@1.10.14: - resolution: {integrity: sha512-rkBwrTPTxNSOUF7of8eVvvM+BkfkhA2OvpHM94if8tVsU+khrjglilp8MTVPHlyS9byfemPAmFN90oRIPB05BA==} + turbo-windows-arm64@2.2.3: + resolution: {integrity: sha512-fnNrYBCqn6zgKPKLHu4sOkihBI/+0oYFr075duRxqUZ+1aLWTAGfHZLgjVeLh3zR37CVzuerGIPWAEkNhkWEIw==} cpu: [arm64] os: [win32] - turbo@1.10.14: - resolution: {integrity: sha512-hr9wDNYcsee+vLkCDIm8qTtwhJ6+UAMJc3nIY6+PNgUTtXcQgHxCq8BGoL7gbABvNWv76CNbK5qL4Lp9G3ZYRA==} + turbo@2.2.3: + resolution: {integrity: sha512-5lDvSqIxCYJ/BAd6rQGK/AzFRhBkbu4JHVMLmGh/hCb7U3CqSnr5Tjwfy9vc+/5wG2DJ6wttgAaA7MoCgvBKZQ==} hasBin: true tweetnacl@0.14.5: @@ -10271,7 +10269,7 @@ snapshots: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/client-sts': 3.569.0 '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10412,7 +10410,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/client-sts': 3.569.0 '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10672,7 +10670,7 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)': + '@aws-sdk/client-sts@3.569.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 @@ -10714,6 +10712,51 @@ snapshots: '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.569.0 + '@aws-sdk/core': 3.567.0 + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/middleware-host-header': 3.567.0 + '@aws-sdk/middleware-logger': 3.568.0 + '@aws-sdk/middleware-recursion-detection': 3.567.0 + '@aws-sdk/middleware-user-agent': 3.567.0 + '@aws-sdk/region-config-resolver': 3.567.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@aws-sdk/util-user-agent-browser': 3.567.0 + '@aws-sdk/util-user-agent-node': 3.568.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.6.2 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -10862,6 +10905,23 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + dependencies: + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-env': 3.568.0 + '@aws-sdk/credential-provider-process': 3.568.0 + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/types': 3.567.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) @@ -10885,7 +10945,7 @@ snapshots: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10929,6 +10989,25 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + dependencies: + '@aws-sdk/credential-provider-env': 3.568.0 + '@aws-sdk/credential-provider-http': 3.568.0 + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-process': 3.568.0 + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/types': 3.567.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 @@ -10955,7 +11034,7 @@ snapshots: '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -11068,7 +11147,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': + '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/types': 3.567.0 @@ -11076,6 +11155,14 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 + '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': + dependencies: + '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.6.2 + '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/client-sts': 3.583.0 @@ -11096,7 +11183,7 @@ snapshots: '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -16432,7 +16519,7 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 '@cloudflare/workers-types': 4.20241004.0 @@ -19652,7 +19739,7 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3)): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)): dependencies: lilconfig: 2.1.0 yaml: 2.3.1 @@ -20923,7 +21010,7 @@ snapshots: tslib@2.6.2: {} - tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3))(typescript@5.6.3): + tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3): dependencies: bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 @@ -20933,7 +21020,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3)) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)) resolve-from: 5.0.0 rollup: 3.27.2 source-map: 0.8.0-beta.0 @@ -21003,32 +21090,32 @@ snapshots: dependencies: safe-buffer: 5.2.1 - turbo-darwin-64@1.10.14: + turbo-darwin-64@2.2.3: optional: true - turbo-darwin-arm64@1.10.14: + turbo-darwin-arm64@2.2.3: optional: true - turbo-linux-64@1.10.14: + turbo-linux-64@2.2.3: optional: true - turbo-linux-arm64@1.10.14: + turbo-linux-arm64@2.2.3: optional: true - turbo-windows-64@1.10.14: + turbo-windows-64@2.2.3: optional: true - turbo-windows-arm64@1.10.14: + turbo-windows-arm64@2.2.3: optional: true - turbo@1.10.14: + turbo@2.2.3: optionalDependencies: - turbo-darwin-64: 1.10.14 - turbo-darwin-arm64: 1.10.14 - turbo-linux-64: 1.10.14 - turbo-linux-arm64: 1.10.14 - turbo-windows-64: 1.10.14 - turbo-windows-arm64: 1.10.14 + turbo-darwin-64: 2.2.3 + turbo-darwin-arm64: 2.2.3 + turbo-linux-64: 2.2.3 + turbo-linux-arm64: 2.2.3 + turbo-windows-64: 2.2.3 + turbo-windows-arm64: 2.2.3 tweetnacl@0.14.5: {} diff --git a/turbo.json b/turbo.json index 3d07b1e88..dcc88efbc 100644 --- a/turbo.json +++ b/turbo.json @@ -1,12 +1,22 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "//#lint": { - "inputs": ["**/*.ts", "!**/node_modules", "!**/dist", "!**/dist-dts"], - "outputMode": "new-only" + "dependsOn": [ + "^test:types" + ], + "inputs": [ + "**/*.ts", + "!**/node_modules", + "!**/dist", + "!**/dist-dts" + ], + "outputLogs": "new-only" }, "test:types": { - "dependsOn": ["^test:types", "^build"], + "dependsOn": [ + "^test:types" + ], "inputs": [ "src/**/*.ts", "tests/**/*.ts", @@ -14,10 +24,31 @@ "tests/tsconfig.json", "../tsconfig.json" ], - "outputMode": "new-only" + "outputLogs": "new-only" + }, + "drizzle-orm#build": { + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" }, - "build": { - "dependsOn": ["^build"], + "drizzle-kit#build": { + "dependsOn": [ + "drizzle-orm#build" + ], "inputs": [ "src/**/*.ts", "package.json", @@ -30,23 +61,124 @@ "scripts/fix-imports.ts", "../tsconfig.json" ], - "outputs": ["dist/**", "dist-dts/**"], - "outputMode": "new-only" + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, + "drizzle-zod#build": { + "dependsOn": [ + "drizzle-orm#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, + "drizzle-typebox#build": { + "dependsOn": [ + "drizzle-orm#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, + "drizzle-valibot#build": { + "dependsOn": [ + "drizzle-orm#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, + "integration-tests#build": { + "dependsOn": [ + "drizzle-orm#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" }, "pack": { - "dependsOn": ["build", "test:types"], - "inputs": ["dist/**"], - "outputs": ["package.tgz"], - "outputMode": "new-only" + "dependsOn": [ + "build", + "test:types" + ], + "inputs": [ + "dist/**" + ], + "outputs": [ + "package.tgz" + ], + "outputLogs": "new-only" }, "test": { - "dependsOn": ["build", "test:types"], + "dependsOn": [ + "build", + "test:types" + ], "inputs": [ "tests/**/*.test.ts", "tests/**/*.test.cjs", "tests/**/*.test.mjs" ], - "outputMode": "new-only" + "outputLogs": "new-only" } } } From 08b813cfb9faacdd5631028114dc8d5c2908b5fa Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 14 Nov 2024 11:13:00 +0200 Subject: [PATCH 354/492] Wait for drizzle-orm to be ready --- turbo.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/turbo.json b/turbo.json index dcc88efbc..78003426a 100644 --- a/turbo.json +++ b/turbo.json @@ -3,7 +3,8 @@ "tasks": { "//#lint": { "dependsOn": [ - "^test:types" + "^test:types", + "drizzle-orm#build" ], "inputs": [ "**/*.ts", @@ -15,7 +16,8 @@ }, "test:types": { "dependsOn": [ - "^test:types" + "^test:types", + "drizzle-orm#build" ], "inputs": [ "src/**/*.ts", @@ -181,4 +183,4 @@ "outputLogs": "new-only" } } -} +} \ No newline at end of file From 548cb8b2ab881a0cced272a5b70b1cbb87901582 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 14 Nov 2024 11:17:07 +0200 Subject: [PATCH 355/492] Format turbo json --- turbo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo.json b/turbo.json index 78003426a..c4d020226 100644 --- a/turbo.json +++ b/turbo.json @@ -183,4 +183,4 @@ "outputLogs": "new-only" } } -} \ No newline at end of file +} From a24b87124e502af8e9edd16a641781db44c219d9 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 14 Nov 2024 11:25:34 +0200 Subject: [PATCH 356/492] Fix turbo for eslint plugin --- turbo.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/turbo.json b/turbo.json index c4d020226..e978069b2 100644 --- a/turbo.json +++ b/turbo.json @@ -135,6 +135,28 @@ ], "outputLogs": "new-only" }, + "eslint-plugin-drizzle#build": { + "dependsOn": [ + "drizzle-orm#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, "integration-tests#build": { "dependsOn": [ "drizzle-orm#build" From c31614aa093c2a50af9a1f6c9509b05d470f2924 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 14 Nov 2024 12:13:27 +0200 Subject: [PATCH 357/492] Add release notes --- changelogs/drizzle-kit/0.28.1.md | 4 ++++ changelogs/drizzle-orm/0.36.2.md | 15 +++++++++++++++ drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 changelogs/drizzle-kit/0.28.1.md create mode 100644 changelogs/drizzle-orm/0.36.2.md diff --git a/changelogs/drizzle-kit/0.28.1.md b/changelogs/drizzle-kit/0.28.1.md new file mode 100644 index 000000000..194b4bd57 --- /dev/null +++ b/changelogs/drizzle-kit/0.28.1.md @@ -0,0 +1,4 @@ +# Bug fixes + +- Fixed typos in repository: thanks @armandsalle, @masto, @wackbyte, @Asher-JH, @MaxLeiter +- [fix: wrong dialect set in mysql/sqlite introspect](https://github.com/drizzle-team/drizzle-orm/pull/2865) \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.36.2.md b/changelogs/drizzle-orm/0.36.2.md new file mode 100644 index 000000000..3790e0944 --- /dev/null +++ b/changelogs/drizzle-orm/0.36.2.md @@ -0,0 +1,15 @@ +# New Features + +- [Support more types in like, notLike, ilike and notIlike expressions](https://github.com/drizzle-team/drizzle-orm/pull/2805) + + +# Bug and typo fixes + +- Fixed typos in repository: thanks @armandsalle, @masto, @wackbyte, @Asher-JH, @MaxLeiter + +- [Fixed .generated behavior with non-strict tsconfig](https://github.com/drizzle-team/drizzle-orm/pull/3542) +- [Fix Drizzle ORM for expo-sqlite](https://github.com/drizzle-team/drizzle-orm/pull/3197) +- [Fixed lack of schema name on columns in sql](https://github.com/drizzle-team/drizzle-orm/pull/3531) +- [fix: Adjust neon http driver entity kind](https://github.com/drizzle-team/drizzle-orm/pull/3424) +- [Export PgIntegerBuilderInitial type](https://github.com/drizzle-team/drizzle-orm/pull/2846) +- [[MySQL] Correct $returningId() implementation to correctly store selected fields](https://github.com/drizzle-team/drizzle-orm/pull/2975) \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 1c911f23f..0b3b2562b 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.28.0", + "version": "0.28.1", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 154a93922..41852bfa7 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.36.1", + "version": "0.36.2", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { From 2677718bf98835b8ec313d0f3bf2b921e795e7c1 Mon Sep 17 00:00:00 2001 From: Andrii Sherman Date: Thu, 14 Nov 2024 12:15:48 +0200 Subject: [PATCH 358/492] Beta (#3543) * Fix breakpoints option default value * fix: added commonly used columns to supabase auth.users table schema * imports checker with OHM grammar * imports checker with OHM grammar + fix of imports issues * Formatting fix * [MySQL] Add unsigned floating point types + Fix unsigned integer type bugs in Kit (#3284) * Fix bugs with MySQL introspection tests * Update float data type in MySQL * Better support for float types in MySQL * Handle existing unsigned numerical types in MySQL * Add unsigned to floating point types in MySQL * Handle unsigned floating point types in MySQL * Update decimal data type --------- Co-authored-by: Andrii Sherman * Batch of bugfixes for ORM (#3181) * (MySQL) Fix placeholder type error in offset and limit * Add prepared statement tests * Add PG test * Fix blob parsing in bun sqlite driver * Lint and format * Fix file * Fix tests * Use const instead of let in tests * Format --------- Co-authored-by: Andrii Sherman * main to beta (#3404) * Update Github issue templates (#3157) * Update GH issue templates * Update issue templates --------- Co-authored-by: Andrii Sherman * Fix checkboxes --------- Co-authored-by: L-Mario564 * feat: add tablesFilter to pushSchema api (#3141) * feat: add tablesFilter to pushSchema api * Format with dprint --------- Co-authored-by: Andrii Sherman * Batch of bugfixes for Kit (#2959) * Escape single quote in enum value * Escape single quotes in string default values * Handle instrospection of strings with single quotes * Add tests * Add tests * Uncomment tests * Fix SQL statement order in MySQL * Add MySQL test * Fix alter composite PK statement missing quotes in PG * Add tests * Handle SQL expressions in timestamp, date and time in PG * Use `.run` instead of `.query` in SQLite queries that don't return anything * Fix parsing of enum array types in PG * Generate more PG index operators * Fix primary key recreate on table rename * Format * Format * Update test * Format * Fix tests * Fix terminal output mistake * Remove duplicate import --------- Co-authored-by: Andrii Sherman * Bump versions * fix: typo (#3172) Co-authored-by: Andrii Sherman * Fix typo (#3030) Trivial: "You ... is ready" -> "Your ... is ready" Co-authored-by: Andrii Sherman * [MySQL] Correct $returningId() implementation to correctly store selected fields (#2975) * Add test to reproduce $returningId() column order issue Currently, $returningId() only works when the primary key is in the first column (of the Drizzle table definition not the underlying MySQL table). This new test checks for this behaviour by using $returningId() when the primary key is in the second column. See https://github.com/drizzle-team/drizzle-orm/issues/2971 Signed-off-by: Daniel Harvey * Fix $returningId() to correctly set selected fields The local variable `returning` computes the selected fields in $returningId() but throws this away. Change to correctly store config in the insert query builder. Fixed https://github.com/drizzle-team/drizzle-orm/issues/2971 Signed-off-by: Daniel Harvey --------- Signed-off-by: Daniel Harvey Co-authored-by: Andrii Sherman * revise and proofread project documentation (#2960) Co-authored-by: Andrii Sherman * Fixed lack of schema name on columns in sql (#3531) * Beta (#3503) * Fix breakpoints option default value * fix: added commonly used columns to supabase auth.users table schema * imports checker with OHM grammar * imports checker with OHM grammar + fix of imports issues * Formatting fix * [MySQL] Add unsigned floating point types + Fix unsigned integer type bugs in Kit (#3284) * Fix bugs with MySQL introspection tests * Update float data type in MySQL * Better support for float types in MySQL * Handle existing unsigned numerical types in MySQL * Add unsigned to floating point types in MySQL * Handle unsigned floating point types in MySQL * Update decimal data type --------- Co-authored-by: Andrii Sherman * Batch of bugfixes for ORM (#3181) * (MySQL) Fix placeholder type error in offset and limit * Add prepared statement tests * Add PG test * Fix blob parsing in bun sqlite driver * Lint and format * Fix file * Fix tests * Use const instead of let in tests * Format --------- Co-authored-by: Andrii Sherman * main to beta (#3404) * Update Github issue templates (#3157) * Update GH issue templates * Update issue templates --------- Co-authored-by: Andrii Sherman * Fix checkboxes --------- Co-authored-by: L-Mario564 * feat: add tablesFilter to pushSchema api (#3141) * feat: add tablesFilter to pushSchema api * Format with dprint --------- Co-authored-by: Andrii Sherman * Batch of bugfixes for Kit (#2959) * Escape single quote in enum value * Escape single quotes in string default values * Handle instrospection of strings with single quotes * Add tests * Add tests * Uncomment tests * Fix SQL statement order in MySQL * Add MySQL test * Fix alter composite PK statement missing quotes in PG * Add tests * Handle SQL expressions in timestamp, date and time in PG * Use `.run` instead of `.query` in SQLite queries that don't return anything * Fix parsing of enum array types in PG * Generate more PG index operators * Fix primary key recreate on table rename * Format * Format * Update test * Format * Fix tests * Fix terminal output mistake * Remove duplicate import --------- Co-authored-by: Andrii Sherman * Bump versions --------- Co-authored-by: Steffen <3752127+klotztech@users.noreply.github.com> Co-authored-by: Nicholas Ly Co-authored-by: Alex Blokh Co-authored-by: Sukairo-02 Co-authored-by: L-Mario564 Co-authored-by: Dan Ribbens * Dprint * Fixed `sql` omitting schema names when processing columns, fixed related test cases * Fixed dprint formatting issues * Fixed lack of schema name on integration tests column references * Removed `\!` --------- Co-authored-by: Andrii Sherman Co-authored-by: Steffen <3752127+klotztech@users.noreply.github.com> Co-authored-by: Nicholas Ly Co-authored-by: Alex Blokh Co-authored-by: L-Mario564 Co-authored-by: Dan Ribbens * Update driver.ts (#3424) Co-authored-by: Andrii Sherman * fix: wrong dialect set in mysql/sqlite introspect (#2865) Co-authored-by: Andrii Sherman * Extra `update` in comment (#2864) Removed and extra `update` text in the comment description using onDuplicateKeyUpdate * chore: export PgIntegerBuilderInitial type as are all other pg-core columns (#2846) Co-authored-by: Alexis Reymann Co-authored-by: Andrii Sherman * Support more types in text comparing sql expressions (#2805) Co-authored-by: Andrii Sherman * drizzle-kit/commands/migrate: fix "you code" typo (#2801) "put you code below" should be "put your code below" * Fixed `.generated` behaviour with non-strict `tsconfig` (fixes #2654) (#3542) * Fix Drizzle ORM for expo-sqlite (#3197) * Fix Drizzle ORM for expo-sqlite closes #3195 * bump expo-sqlite version to 14.0.0 in package.json and pnpm-lock.yaml --------- Co-authored-by: Andrii Sherman * Upgrade turbo to v2 * Wait for drizzle-orm to be ready * Format turbo json * Fix turbo for eslint plugin * Add release notes --------- Signed-off-by: Daniel Harvey Co-authored-by: Steffen <3752127+klotztech@users.noreply.github.com> Co-authored-by: Nicholas Ly Co-authored-by: Alex Blokh Co-authored-by: Sukairo-02 Co-authored-by: L-Mario564 Co-authored-by: Dan Ribbens Co-authored-by: Armand SALLE Co-authored-by: Christopher Masto Co-authored-by: Daniel Harvey Co-authored-by: wackbyte Co-authored-by: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> Co-authored-by: Michael Lohr Co-authored-by: Mickael Lecoq Co-authored-by: Asher Chan Co-authored-by: Alexis Reymann <16920060+Yoctoboy@users.noreply.github.com> Co-authored-by: Alexis Reymann Co-authored-by: Max Leiter Co-authored-by: Subramanya Chakravarthy --- CONTRIBUTING.md | 306 +++++++++--------- README.md | 16 +- changelogs/drizzle-kit/0.28.1.md | 4 + changelogs/drizzle-orm/0.36.2.md | 15 + docs/custom-types.lite.md | 3 +- docs/custom-types.md | 27 +- docs/joins.md | 13 +- drizzle-kit/README.md | 14 +- drizzle-kit/package.json | 2 +- drizzle-kit/src/cli/commands/introspect.ts | 12 +- drizzle-kit/src/cli/commands/migrate.ts | 2 +- drizzle-orm/package.json | 6 +- drizzle-orm/src/column-builder.ts | 12 +- drizzle-orm/src/expo-sqlite/driver.ts | 2 +- drizzle-orm/src/expo-sqlite/query.ts | 2 +- drizzle-orm/src/expo-sqlite/session.ts | 2 +- drizzle-orm/src/mysql-core/columns/bigint.ts | 2 - drizzle-orm/src/mysql-core/columns/binary.ts | 1 - drizzle-orm/src/mysql-core/columns/boolean.ts | 1 - drizzle-orm/src/mysql-core/columns/char.ts | 1 - drizzle-orm/src/mysql-core/columns/common.ts | 4 +- drizzle-orm/src/mysql-core/columns/custom.ts | 1 - drizzle-orm/src/mysql-core/columns/date.ts | 2 - .../src/mysql-core/columns/datetime.ts | 2 - drizzle-orm/src/mysql-core/columns/decimal.ts | 1 - drizzle-orm/src/mysql-core/columns/double.ts | 1 - drizzle-orm/src/mysql-core/columns/enum.ts | 1 - drizzle-orm/src/mysql-core/columns/float.ts | 1 - drizzle-orm/src/mysql-core/columns/int.ts | 1 - drizzle-orm/src/mysql-core/columns/json.ts | 1 - .../src/mysql-core/columns/mediumint.ts | 1 - drizzle-orm/src/mysql-core/columns/real.ts | 1 - drizzle-orm/src/mysql-core/columns/serial.ts | 1 - .../src/mysql-core/columns/smallint.ts | 1 - drizzle-orm/src/mysql-core/columns/text.ts | 1 - drizzle-orm/src/mysql-core/columns/time.ts | 1 - .../src/mysql-core/columns/timestamp.ts | 2 - drizzle-orm/src/mysql-core/columns/tinyint.ts | 1 - .../src/mysql-core/columns/varbinary.ts | 1 - drizzle-orm/src/mysql-core/columns/varchar.ts | 1 - drizzle-orm/src/mysql-core/columns/year.ts | 1 - .../src/mysql-core/query-builders/insert.ts | 8 +- drizzle-orm/src/neon-http/driver.ts | 2 +- drizzle-orm/src/operations.ts | 14 +- drizzle-orm/src/pg-core/columns/bigint.ts | 2 - drizzle-orm/src/pg-core/columns/bigserial.ts | 2 - drizzle-orm/src/pg-core/columns/boolean.ts | 1 - drizzle-orm/src/pg-core/columns/char.ts | 1 - drizzle-orm/src/pg-core/columns/cidr.ts | 1 - drizzle-orm/src/pg-core/columns/common.ts | 8 +- drizzle-orm/src/pg-core/columns/custom.ts | 1 - drizzle-orm/src/pg-core/columns/date.ts | 2 - .../src/pg-core/columns/double-precision.ts | 1 - drizzle-orm/src/pg-core/columns/enum.ts | 1 - drizzle-orm/src/pg-core/columns/inet.ts | 1 - drizzle-orm/src/pg-core/columns/integer.ts | 3 +- drizzle-orm/src/pg-core/columns/interval.ts | 1 - drizzle-orm/src/pg-core/columns/json.ts | 1 - drizzle-orm/src/pg-core/columns/jsonb.ts | 1 - drizzle-orm/src/pg-core/columns/line.ts | 2 - drizzle-orm/src/pg-core/columns/macaddr.ts | 1 - drizzle-orm/src/pg-core/columns/macaddr8.ts | 1 - drizzle-orm/src/pg-core/columns/numeric.ts | 1 - drizzle-orm/src/pg-core/columns/point.ts | 2 - .../columns/postgis_extension/geometry.ts | 2 - drizzle-orm/src/pg-core/columns/real.ts | 1 - drizzle-orm/src/pg-core/columns/serial.ts | 1 - drizzle-orm/src/pg-core/columns/smallint.ts | 1 - .../src/pg-core/columns/smallserial.ts | 1 - drizzle-orm/src/pg-core/columns/text.ts | 1 - drizzle-orm/src/pg-core/columns/time.ts | 1 - drizzle-orm/src/pg-core/columns/timestamp.ts | 2 - drizzle-orm/src/pg-core/columns/uuid.ts | 1 - drizzle-orm/src/pg-core/columns/varchar.ts | 1 - .../pg-core/columns/vector_extension/bit.ts | 1 - .../columns/vector_extension/halfvec.ts | 1 - .../columns/vector_extension/sparsevec.ts | 1 - .../columns/vector_extension/vector.ts | 1 - drizzle-orm/src/sql/expressions/conditions.ts | 8 +- drizzle-orm/src/sql/sql.ts | 12 +- drizzle-orm/src/sqlite-core/README.md | 18 +- drizzle-orm/src/sqlite-core/columns/blob.ts | 3 - drizzle-orm/src/sqlite-core/columns/common.ts | 4 +- drizzle-orm/src/sqlite-core/columns/custom.ts | 1 - .../src/sqlite-core/columns/integer.ts | 3 - .../src/sqlite-core/columns/numeric.ts | 1 - drizzle-orm/src/sqlite-core/columns/real.ts | 1 - drizzle-orm/src/sqlite-core/columns/text.ts | 1 - .../tests/casing/mysql-to-camel.test.ts | 2 +- .../tests/casing/mysql-to-snake.test.ts | 2 +- drizzle-orm/tests/casing/pg-to-camel.test.ts | 2 +- drizzle-orm/tests/casing/pg-to-snake.test.ts | 2 +- .../type-tests/mysql/generated-columns.ts | 1 + drizzle-orm/type-tests/mysql/with.ts | 5 +- drizzle-orm/type-tests/pg/with.ts | 5 +- .../type-tests/sqlite/generated-columns.ts | 4 +- drizzle-orm/type-tests/sqlite/with.ts | 5 +- examples/mysql-proxy/README.md | 6 +- examples/neon-cloudflare/readme.md | 2 +- examples/pg-proxy/README.md | 6 +- examples/sqlite-proxy/README.md | 6 +- integration-tests/tests/mysql/mysql-common.ts | 19 +- integration-tests/tests/pg/pg-common.ts | 2 +- package.json | 3 +- pnpm-lock.yaml | 185 ++++++++--- turbo.json | 186 ++++++++++- 106 files changed, 624 insertions(+), 415 deletions(-) create mode 100644 changelogs/drizzle-kit/0.28.1.md create mode 100644 changelogs/drizzle-orm/0.36.2.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3b7f8cbba..38b9f4642 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,169 +2,137 @@ Welcome! We're glad you're interested in Drizzle ORM and want to help us make it better. -Drizzle ORM is owned by [Drizzle Team](https://drizzle.team) and maintained by community members, mainly by our core contributors [@AndriiSherman](https://github.com/AndriiSherman) [@AlexBlokh](https://github.com/AlexBlokh) [@dankochetov](https://github.com/dankochetov). Everything that is going to be merged should be approved by all core contributors members +Drizzle ORM is owned by [Drizzle Team](https://drizzle.team) and maintained by community members, mainly by our core contributors ([@AndriiSherman](https://github.com/AndriiSherman), [@AlexBlokh](https://github.com/AlexBlokh), [@dankochetov](https://github.com/dankochetov)). Everything that is going to be merged should be approved by all core contributors members. --- -There are many ways you can contribute to the Drizzle ORM project +There are many ways you can contribute to the Drizzle ORM project: -- [Submitting bug reports](#bugreport) -- [Submitting feature request](#featurerequest) +- [Submitting bug reports](#bug-report) +- [Submitting feature request](#feature-request) - [Providing feedback](#feedback) -- [Contribution guidelines](#contributing) +- [Contribution guidelines](#contribution-guidelines) -## Submitting bug report +## Submitting bug report ---- - -To submit a bug or issue, please use our [issue form](https://github.com/drizzle-team/drizzle-orm/issues/new/choose) and choose Bug Report +To report a bug or issue, please use our [issue form](https://github.com/drizzle-team/drizzle-orm/issues/new/choose) and choose Bug Report. -## Submitting feature request +## Submitting feature request ---- - -To submit a bug or issue, please use our [issue form](https://github.com/drizzle-team/drizzle-orm/issues/new/choose) and choose Feature Request +To request a feature, please use our [issue form](https://github.com/drizzle-team/drizzle-orm/issues/new/choose) and choose Feature Request. ## Providing feedback ---- +There are several ways you can provide feedback: -There are several ways how you can provide a feedback +- You can join our [Discord server](https://discord.gg/yfjTbVXMW4) and provide feedback there. +- You can add new ticket in [Discussions](https://github.com/drizzle-team/drizzle-orm/discussions). +- Mention our [Twitter account](https://twitter.com/DrizzleOrm). -- You can join our [Discord](https://discord.gg/yfjTbVXMW4) channel and provide feedback there -- You can add new ticket in [Discussions](https://github.com/drizzle-team/drizzle-orm/discussions) -- Mention our [Twitter account](https://twitter.com/DrizzleOrm) +## Contribution guidelines -## Contribution guidelines - ---- - -- [Pre-Contribution setup](#pre-contribution) - - [Installing node](#-installing-node) - - [Install pnpm](#-install-pnpm) - - [Install docker](#-install-docker) - - [Clone project](#-clone-project) - - [Repository Structure](#repo-structure) - - [Build project](#-build-project) +- [Pre-contribution setup](#pre-contribution) + - [Installing Node](#installing-node) + - [Installing pnpm](#installing-pnpm) + - [Installing Docker](#installing-docker) + - [Cloning the repository](#cloning-the-repository) + - [Repository structure](#repository-structure) + - [Building the project](#building-the-project) +- [Commit message guidelines](#commit-message-guidelines) - [Contributing to `drizzle-orm`](#contributing-orm) - [Project structure](#project-structure-orm) - - [Run tests](#run-tests-orm) - - [Commits and PRs](#commits-and-prs-orm) - - [Commit guideline](#commit-guideline-orm) - - [PR guideline](#pr-guideline-orm) + - [Running tests](#running-tests-orm) + - [PR guidelines](#pr-guidelines-orm) - [Contributing to `drizzle-kit`](#contributing-kit) - [Project structure](#project-structure-kit) - - [Run tests](#run-tests-kit) - - [Commits and PRs](#commits-and-prs-kit) - - [Commit guideline](#commit-guideline-kit) - - [PR guideline](#-pr-guideline) - -## Pre-Contribution setup + - [Running tests](#running-tests-kit) + - [PR guidelines](#pr-guidelines-kit) -### Installing node +## Pre-contribution setup ---- +### Installing Node ```bash # https://github.com/nvm-sh/nvm#install--update-script -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash nvm install 18.13.0 nvm use 18.13.0 ``` -### Install pnpm - ---- +### Installing pnpm ```bash # https://pnpm.io/installation npm install -g pnpm ``` -### Install docker - ---- +### Installing Docker ```bash # https://docs.docker.com/get-docker/ -Use docker guide to install docker on your OS +# Use Docker's guide to install Docker for your OS. ``` -## Local project setup - -### Clone project - ---- +### Cloning the repository ```bash git clone https://github.com/drizzle-team/drizzle-orm.git cd drizzle-orm ``` -### Repository Structure - -``` -📂 drizzle-orm/ - orm core package with all main logic for each dialect - -📂 drizzle-kit/ - kit core package with all main logic and tests for each dialect +### Repository structure -📂 drizzle-typebox/ - all the code related to drizzle+typebox extension +- 📂 `drizzle-orm/` -📂 drizzle-valibot/ - all the code related to drizzle+valibot extension + orm core package with all main logic for each dialect -📂 drizzle-zod/ - all the code related to drizzle+zod extension +- 📂 `drizzle-kit/` -📂 eslint-plugin-drizzle/ - all the code related to drizzle eslint plugin + kit core package with all main logic and tests for each dialect -📂 changelogs/ - all changelogs for drizzle-orm, drizzle-kit, drizzle-typebox, drizzle-zod, drizzle-valibot modules +- 📂 `drizzle-typebox/` -📂 examples/ - package with Drizzle ORM usage examples + all the code related to drizzle+typebox extension -📂 integration-tests/ - package with all type of tests for each supported database -``` +- 📂 `drizzle-valibot/` -### Build project + all the code related to drizzle+valibot extension ---- +- 📂 `drizzle-zod/` -- `"pnpm i && pnpm build"` -> if you run this script from root folder - it will build whole monorepo. Running this script from specific package folder will only build current package + all the code related to drizzle+zod extension -## Contributing to `drizzle-orm` - -### Project structure - -``` -Project structure +- 📂 `eslint-plugin-drizzle/` -📂 pg-core, mysql-core, sqlite-core - core packages for each dialect with all the main logic for relation and query builder + all the code related to drizzle eslint plugin -📂 sql/ - package containing all expressions and SQL template implementation +- 📂 `changelogs/` -All other folders are for specific drivers that Drizzle ORM supports. -``` + all changelogs for drizzle-orm, drizzle-kit, drizzle-typebox, drizzle-zod, drizzle-valibot modules -### Run tests +- 📂 `examples/` ---- -All tests for Drizzle ORM are integration tests, that are simulating real database and different queries and responses from database. Each file in `integration-tests` has a list of different scenarios for different dialect+driver. Each file is creating a docker instance with needed database and running test cases there. Right after all tests were run - docker container with database will be deleted + package with Drizzle ORM usage examples -If you have added additional logic to core package - make sure that all tests were executed without any errors +- 📂 `integration-tests/` -> If you have added data types or feature for query building, you need to create additional test cases with this data type/syntax changes, syntax addition + package with all type of tests for each supported database -- `"cd integration-tests && pnpm test"` -> will run all tests in integration test folder +### Building the project -## Commits and PRs +Run the following script from the root folder to build the whole monorepo. Running it from a specific package folder will only build that package. -### Commit guideline +```bash +pnpm install && pnpm build +``` ---- +## Commit message guidelines We have specific rules on how commit messages should be structured. -It's important to make sure your commit messages are clear, concise, and informative to make it easier for others to understand the changes you are making +It's important to make sure your commit messages are clear, concise, and informative to make it easier for others to understand the changes you are making. -Commit message pattern +All commit messages should follow the pattern below: ``` @@ -172,7 +140,7 @@ Commit message pattern ``` -Example +Example: ``` Add groupBy error message @@ -181,117 +149,131 @@ In specific case, groupBy was responding with unreadable error ... ``` -> **Warning**: -> All commits should be signed, before submitting PR. Please check detailed info on [how to sign commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) +> [!WARNING] +> All commits should be signed before submitting a PR. Please check the documentation on [how to sign commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification). -### PR guideline +## Contributing to `drizzle-orm` ---- +### Project structure -1. PR should be created with specific name pattern +- 📂 `pg-core/`, `mysql-core/`, `sqlite-core/` + + core packages for each dialect with all the main logic for relation and query builder -``` -[Dialect name]: -``` +- 📂 `sql/` -Example + package containing all expressions and SQL template implementation -``` -[Pg] Add PostGIS extension support +- All other folders are for each specific driver that Drizzle ORM supports. + +### Running tests + +All tests for Drizzle ORM are integration tests that simulate real databases with different queries and responses from each database. Each file in `integration-tests` has a list of different scenarios for different dialects and drivers. Each file creates a Docker container with the needed database and runs the test cases there. After every test is run, the Docker container will be deleted. + +If you have added additional logic to a core package, make sure that all tests completed without any failures. + +> [!NOTE] +> If you have added data types or a feature for query building, you need to create additional test cases using the new API to ensure it works properly. + +If you are in the root of the repository, run all integration tests with the following script: + +```bash +cd integration-tests && pnpm test ``` -2. PR should contain detailed description with everything, that was changed +### PR guidelines -3. Each PR should contain - - Tests on feature, that was created; - - Tests on bugs, that was fixed; +1. PR titles should follow the pattern below: -To understand how test should be created and run - please check [Run tests](#-run-tests) section + ``` + []: + ``` + Example: + + ``` + [Pg] Add PostGIS extension support + ``` + +2. PRs should contain a detailed description of everything that was changed. + +3. Commit messages should follow the [message style guidelines](#commit-message-guidelines). + +4. PRs should implement: + - Tests for features that were added. + - Tests for bugs that were fixed. + +> [!NOTE] +> To understand how tests should be created and run, please check the [Running tests](#running-tests-orm) section. ## Contributing to `drizzle-kit` ### Project structure -``` -📂 cli/ - | - | -> 📄 schema.ts - all the commands defined using brocli - | - | -> 📂 commands - all the business logic for drizzle-kit commands - -📂 extensions/ - all the extension helpers for databases +- 📂 `cli/` + - 📄 `schema.ts` -📂 serializer/ - all the necessary logic to read from the Drizzle ORM schema and convert it to a common JSON format, as well as the logic to introspect all tables, types, and other database elements and convert them to a common JSON format + all the commands defined using brocli -📄 introspect-pg.ts, introspect-mysql.ts, introspect-sqlite.ts - these files are responsible for mapping JSON snapshots to TypeScript files during introspect commands + - 📂 `commands/` -📄 snapshotsDiffer.ts - this file handles the mapping from JSON snapshot format to JSON statement objects. + all the business logic for drizzle-kit commands -📄 jsonStatements.ts - this file defines JSON statement types, interfaces, and helper functions. +- 📂 `extensions/` -📄 sqlgenerator.ts - this file converts JSON statements to SQL strings. -``` + all the extension helpers for databases -### Run tests +- 📂 `serializer/` ---- -All tests for Drizzle Kit are integration tests, that are simulating real database and different queries and responses from database. Each file in `drizzle-kit/tests` has a list of different scenarios for different commands. Each MySQL file is creating a docker instance with needed database and running test cases there. Right after all tests were run - docker container with database will be deleted. For PostgreSQL we are using PgLite and for SQLite we are using SQLite files. + all the necessary logic to read from the Drizzle ORM schema and convert it to a common JSON format, as well as the logic to introspect all tables, types, and other database elements and convert them to a common JSON format -If you are in the root of repo: +- 📄 `introspect-pg.ts`, `introspect-mysql.ts`, `introspect-sqlite.ts` -- `"cd drizzle-kit && pnpm test"` -> will run all tests + these files are responsible for mapping JSON snapshots to TypeScript files during introspect commands -## Commits and PRs +- 📄 `snapshotsDiffer.ts` -### Commit guideline + this file handles the mapping from JSON snapshot format to JSON statement objects. ---- +- 📄 `jsonStatements.ts` -We have specific rules on how commit messages should be structured. + this file defines JSON statement types, interfaces, and helper functions. -It's important to make sure your commit messages are clear, concise, and informative to make it easier for others to understand the changes you are making +- 📄 `sqlgenerator.ts` -Commit message pattern + this file converts JSON statements to SQL strings. -``` - - - -``` +### Running tests -Example +All tests for Drizzle Kit are integration tests that simulate real databases with different queries and responses from each database. Each file in `drizzle-kit/tests` has a list of different scenarios for different commands. Each file creates a Docker container with the needed database and runs the test cases there. After every test is run, the Docker container will be deleted. We test MySQL, PostgreSQL (using PGlite), and SQLite. -``` -Add groupBy error message +If you are in the root of the repository, run all Drizzle Kit tests with the following script: -In specific case, groupBy was responding with unreadable error -... +```bash +cd drizzle-kit && pnpm test ``` -> **Warning**: -> All commits should be signed, before submitting PR. Please check detailed info on [how to sign commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) +### PR guidelines -### PR guideline +1. PR titles should follow the pattern below: ---- + ``` + [-kit]: + ``` -1. PR should be created with specific name pattern + Example: -``` -[-kit]: -``` - -Example + ``` + [Pg-kit] Add PostGIS extension support + ``` -``` -[Pg-kit] Add PostGIS extension support -``` +2. PRs should contain a detailed description of everything that was changed. -2. PR should contain detailed description with everything, that was changed +3. Commit messages should follow the [message style guidelines](#commit-message-guidelines). -3. Each PR should contain - - Tests on feature, that was created; - - Tests on bugs, that was fixed; +4. PRs should implement: + - Tests for features that were added. + - Tests for bugs that were fixed. -To understand how test should be created and run - please check [Run tests](#run-tests) section +> [!NOTE] +> To understand how tests should be created and run, please check the [Running tests](#running-tests-kit) section. diff --git a/README.md b/README.md index ac509ab0d..4342d8afe 100644 --- a/README.md +++ b/README.md @@ -17,24 +17,24 @@ ### What's Drizzle? Drizzle is a modern TypeScript ORM developers [wanna use in their next project](https://stateofdb.com/tools/drizzle). -It is [lightweight](https://bundlephobia.com/package/drizzle-orm) at only ~7.4kb minified+gzipped, it's tree shakeable with exactly 0 dependencies. +It is [lightweight](https://bundlephobia.com/package/drizzle-orm) at only ~7.4kb minified+gzipped, and it's tree shakeable with exactly 0 dependencies. -**Drizzle supports every PostgreSQL, MySQL and SQLite databases**, including serverless ones like [Turso](https://orm.drizzle.team/docs/get-started-sqlite#turso), [Neon](https://orm.drizzle.team/docs/get-started-postgresql#neon), [Xata](xata.io), [PlanetScale](https://orm.drizzle.team/docs/get-started-mysql#planetscale), [Cloudflare D1](https://orm.drizzle.team/docs/get-started-sqlite#cloudflare-d1), [FlyIO LiteFS](https://fly.io/docs/litefs/), [Vercel Postgres](https://orm.drizzle.team/docs/get-started-postgresql#vercel-postgres), [Supabase](https://orm.drizzle.team/docs/get-started-postgresql#supabase) and [AWS Data API](https://orm.drizzle.team/docs/get-started-postgresql#aws-data-api). No bells and whistles, no rust binaries, no serverless adapters, everything just works out of the box. +**Drizzle supports every PostgreSQL, MySQL and SQLite database**, including serverless ones like [Turso](https://orm.drizzle.team/docs/get-started-sqlite#turso), [Neon](https://orm.drizzle.team/docs/get-started-postgresql#neon), [Xata](xata.io), [PlanetScale](https://orm.drizzle.team/docs/get-started-mysql#planetscale), [Cloudflare D1](https://orm.drizzle.team/docs/get-started-sqlite#cloudflare-d1), [FlyIO LiteFS](https://fly.io/docs/litefs/), [Vercel Postgres](https://orm.drizzle.team/docs/get-started-postgresql#vercel-postgres), [Supabase](https://orm.drizzle.team/docs/get-started-postgresql#supabase) and [AWS Data API](https://orm.drizzle.team/docs/get-started-postgresql#aws-data-api). No bells and whistles, no Rust binaries, no serverless adapters, everything just works out of the box. -**Drizzle is serverless-ready by design**, it works in every major JavaScript runtime like NodeJS, Bun, Deno, Cloudflare Workers, Supabase functions, any Edge runtime and even in Browsers. -With Drizzle you can be [**fast out of the box**](https://orm.drizzle.team/benchmarks), save time and costs while never introducing any data proxies into your infrastructure. +**Drizzle is serverless-ready by design**. It works in every major JavaScript runtime like NodeJS, Bun, Deno, Cloudflare Workers, Supabase functions, any Edge runtime, and even in browsers. +With Drizzle you can be [**fast out of the box**](https://orm.drizzle.team/benchmarks) and save time and costs while never introducing any data proxies into your infrastructure. -While you can use Drizzle as a JavaScript library, it shines in the TypeScript. It lets you [**declare SQL schema**](https://orm.drizzle.team/docs/sql-schema-declaration) and build both [**relational**](https://orm.drizzle.team/docs/rqb) and [**SQL-like queries**](https://orm.drizzle.team/docs/select), while keeping the balance between type-safety and extensibility for toolmakers to build on top. +While you can use Drizzle as a JavaScript library, it shines with TypeScript. It lets you [**declare SQL schemas**](https://orm.drizzle.team/docs/sql-schema-declaration) and build both [**relational**](https://orm.drizzle.team/docs/rqb) and [**SQL-like queries**](https://orm.drizzle.team/docs/select), while keeping the balance between type-safety and extensibility for toolmakers to build on top. ### Ecosystem While Drizzle ORM remains a thin typed layer on top of SQL, we made a set of tools for people to have best possible developer experience. -Drizzle comes with a powerful [**Drizzle Kit**](https://orm.drizzle.team/kit-docs/overview) CLI companion for you to have hasstle-free migrations. It can generate SQL migration files for you or apply schema changes directly to the database. +Drizzle comes with a powerful [**Drizzle Kit**](https://orm.drizzle.team/kit-docs/overview) CLI companion for you to have hassle-free migrations. It can generate SQL migration files for you or apply schema changes directly to the database. -And we have a [**Drizzle Studio**](https://orm.drizzle.team/drizzle-studio/overview) for you to effortlessly browse and manipulate data in your database of choice. +We also have [**Drizzle Studio**](https://orm.drizzle.team/drizzle-studio/overview) for you to effortlessly browse and manipulate data in your database of choice. ### Documentation -Check out the full documentation on [the website](https://orm.drizzle.team/docs/overview) +Check out the full documentation on [the website](https://orm.drizzle.team/docs/overview). ### Our sponsors ❤️

diff --git a/changelogs/drizzle-kit/0.28.1.md b/changelogs/drizzle-kit/0.28.1.md new file mode 100644 index 000000000..194b4bd57 --- /dev/null +++ b/changelogs/drizzle-kit/0.28.1.md @@ -0,0 +1,4 @@ +# Bug fixes + +- Fixed typos in repository: thanks @armandsalle, @masto, @wackbyte, @Asher-JH, @MaxLeiter +- [fix: wrong dialect set in mysql/sqlite introspect](https://github.com/drizzle-team/drizzle-orm/pull/2865) \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.36.2.md b/changelogs/drizzle-orm/0.36.2.md new file mode 100644 index 000000000..3790e0944 --- /dev/null +++ b/changelogs/drizzle-orm/0.36.2.md @@ -0,0 +1,15 @@ +# New Features + +- [Support more types in like, notLike, ilike and notIlike expressions](https://github.com/drizzle-team/drizzle-orm/pull/2805) + + +# Bug and typo fixes + +- Fixed typos in repository: thanks @armandsalle, @masto, @wackbyte, @Asher-JH, @MaxLeiter + +- [Fixed .generated behavior with non-strict tsconfig](https://github.com/drizzle-team/drizzle-orm/pull/3542) +- [Fix Drizzle ORM for expo-sqlite](https://github.com/drizzle-team/drizzle-orm/pull/3197) +- [Fixed lack of schema name on columns in sql](https://github.com/drizzle-team/drizzle-orm/pull/3531) +- [fix: Adjust neon http driver entity kind](https://github.com/drizzle-team/drizzle-orm/pull/3424) +- [Export PgIntegerBuilderInitial type](https://github.com/drizzle-team/drizzle-orm/pull/2846) +- [[MySQL] Correct $returningId() implementation to correctly store selected fields](https://github.com/drizzle-team/drizzle-orm/pull/2975) \ No newline at end of file diff --git a/docs/custom-types.lite.md b/docs/custom-types.lite.md index 627aba1a4..af1371461 100644 --- a/docs/custom-types.lite.md +++ b/docs/custom-types.lite.md @@ -1,6 +1,7 @@ # Common way of defining custom types -> **Info**: For more advanced documentation about defining custom data types in PostgreSQL and MySQL please check [custom-types.md](https://github.com/drizzle-team/drizzle-orm/blob/main/docs/custom-types.md) +> [!NOTE] +> For more advanced documentation about defining custom data types in PostgreSQL and MySQL, please check [`custom-types.md`](custom-types.md). ## Examples diff --git a/docs/custom-types.md b/docs/custom-types.md index 1dffe6ce0..2a9f1a1da 100644 --- a/docs/custom-types.md +++ b/docs/custom-types.md @@ -1,7 +1,6 @@ # How to define custom types Drizzle ORM has a big set of predefined column types for different SQL databases. But still there are additional types that are not supported by Drizzle ORM (yet). That could be native pg types or extension types -
Here are some instructions on how to create and use your own types with Drizzle ORM @@ -13,14 +12,11 @@ Each type creation should use 2 classes: - `ColumnBuilder` - class, that is responsible for generating whole set of needed fields for column creation - `Column` - class, that is representing Columns itself, that is used in query generation, migration mapping, etc. -
-
+ Each module has it's own class, representing `ColumnBuilder` or `Column`: - For `pg` -> `PgColumnBuilder` and `PgColumn` - For `mysql` -> `MySqlColumnBuilder` and `MySqlColumn` - For `sqlite` -> `SQLiteColumnBuilder` and `SQLiteColumn` -
-
### Builder class explanation - (postgresql text data type example) @@ -44,7 +40,7 @@ export class PgTextBuilder } ``` -> **Warning** +> [!WARNING] > `$pgColumnBuilderBrand` should be changed and be equal to class name for new data type builder ### Column class explanation - (postgresql text data type example) @@ -104,11 +100,8 @@ export class PgText } ``` -> **Warning** +> [!WARNING] > `$pgColumnBrand` should be changed and be equal to class name for new data type ---- - -
### Full text data type for PostgreSQL example @@ -162,19 +155,13 @@ export function text( ## Custom data type example ---- - -> **Note** +> [!NOTE] > We will check example on pg module, but current pattern applies to all dialects, that are currently supported by Drizzle ORM -
- ### Setting up CITEXT datatype ---- -> **Note** - This type is available only with extensions and used for example, just to show how you could setup any data type you want. Extension support will come soon -
+> [!NOTE] +> This type is available only with extensions and used for example, just to show how you could setup any data type you want. Extension support will come soon ### CITEXT data type example @@ -224,4 +211,4 @@ You could add your created custom data types to Drizzle ORM, so everyone can use Each data type should be placed in separate file in `columns` folder and PR open with tag `new-data-type:pg` | `new-data-type:sqlite` | `new-data-type:mysql` -For more Contribution information - please check [CONTRIBUTING.md](https://github.com/drizzle-team/drizzle-orm/blob/main/CONTRIBUTING.md) +For more Contribution information - please check [CONTRIBUTING.md](../CONTRIBUTING.md) diff --git a/docs/joins.md b/docs/joins.md index e0579e3e2..2b5829aa9 100644 --- a/docs/joins.md +++ b/docs/joins.md @@ -1,7 +1,7 @@ # Drizzle ORM - Joins As with other parts of Drizzle ORM, the joins syntax is a balance between the SQL-likeness and type safety. -Here's an example of how a common `1-to-many` relationship can be modelled. +Here's an example of how a common "one-to-many" relationship can be modelled. ```typescript const users = pgTable('users', { @@ -96,7 +96,7 @@ In that case, the ORM will use dark TypeScript magic (as if it wasn't already) a This is much more convenient! Now, you can just do a single check for `row.user !== null`, and all the user fields will become available. -


+--- Note that you can group any fields in a nested object however you like, but the single check optimization will only be applied to a certain nested object if all its fields belong to the same table. So, for example, you can group the city fields, too: @@ -131,7 +131,7 @@ And the result type will look like this: } ``` -
+--- If you just need all the fields from all the tables you're selecting and joining, you can simply omit the argument of the `.select()` method altogether: @@ -139,7 +139,8 @@ If you just need all the fields from all the tables you're selecting and joining const rows = await db.select().from(cities).leftJoin(users, eq(users.cityId, cities.id)); ``` -> **Note**: in this case, the Drizzle table/column names will be used as the keys in the result object. +> [!NOTE] +> In this case, the Drizzle table/column names will be used as the keys in the result object. ```typescript { @@ -156,7 +157,7 @@ const rows = await db.select().from(cities).leftJoin(users, eq(users.cityId, cit }[] ``` -
+--- There are cases where you'd want to select all the fields from one table, but pick fields from others. In that case, instead of listing all the table fields, you can just pass a table: @@ -181,7 +182,7 @@ There are cases where you'd want to select all the fields from one table, but pi } ``` -
+--- But what happens if you group columns from multiple tables in the same nested object? Nothing, really - they will still be all individually nullable, just grouped under the same object (as you might expect!): diff --git a/drizzle-kit/README.md b/drizzle-kit/README.md index d2a4191b7..bd69a4d3d 100644 --- a/drizzle-kit/README.md +++ b/drizzle-kit/README.md @@ -1,21 +1,21 @@ ## Drizzle Kit -DrizzleKit - is a CLI migrator tool for DrizzleORM. It is probably one and only tool that lets you completely automatically generate SQL migrations and covers ~95% of the common cases like deletions and renames by prompting user input. +Drizzle Kit is a CLI migrator tool for Drizzle ORM. It is probably the one and only tool that lets you completely automatically generate SQL migrations and covers ~95% of the common cases like deletions and renames by prompting user input. - is a mirror repository for issues. ## Documentation -Check the full documenation on [the website](https://orm.drizzle.team/kit-docs/overview) +Check the full documentation on [the website](https://orm.drizzle.team/kit-docs/overview). ### How it works -`drizzle-kit` will traverse `schema folder` or `schema file`, generate schema snapshot and compare it to the previous version, if there's one. - Based on the difference it will generate all needed SQL migrations and if there are any `automatically unresolvable` cases like `renames` it will prompt user for input. +Drizzle Kit traverses a schema module and generates a snapshot to compare with the previous version, if there is one. +Based on the difference, it will generate all needed SQL migrations. If there are any cases that can't be resolved automatically, such as renames, it will prompt the user for input. -For schema file: +For example, for this schema module: ```typescript -// ./src/db/schema.ts +// src/db/schema.ts import { integer, pgTable, serial, text, varchar } from "drizzle-orm/pg-core"; @@ -63,7 +63,7 @@ CREATE INDEX IF NOT EXISTS users_full_name_index ON users (full_name); npm install -D drizzle-kit ``` -Running with CLI options +Running with CLI options: ```jsonc // package.json diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 1c911f23f..0b3b2562b 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.28.0", + "version": "0.28.1", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index db250d005..2629d000e 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -153,14 +153,14 @@ export const introspectPostgres = async ( chalk.green( '✓', ) - }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + }] Your schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, ); render( `[${ chalk.green( '✓', ) - }] You relations file is ready ➜ ${ + }] Your relations file is ready ➜ ${ chalk.bold.underline.blue( relationsFile, ) @@ -264,14 +264,14 @@ export const introspectMysql = async ( chalk.green( '✓', ) - }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + }] Your schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, ); render( `[${ chalk.green( '✓', ) - }] You relations file is ready ➜ ${ + }] Your relations file is ready ➜ ${ chalk.bold.underline.blue( relationsFile, ) @@ -488,14 +488,14 @@ export const introspectLibSQL = async ( chalk.green( '✓', ) - }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + }] Your schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, ); render( `[${ chalk.green( '✓', ) - }] You relations file is ready ➜ ${ + }] Your relations file is ready ➜ ${ chalk.bold.underline.blue( relationsFile, ) diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 0933af194..92770e99d 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -1078,7 +1078,7 @@ export const writeResult = ({ if (type === 'custom') { console.log('Prepared empty file for your custom SQL migration!'); - sql = '-- Custom SQL migration file, put you code below! --'; + sql = '-- Custom SQL migration file, put your code below! --'; } journal.entries.push({ diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index b2b204ead..41852bfa7 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.36.1", + "version": "0.36.2", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -63,7 +63,7 @@ "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", - "expo-sqlite": ">=13.2.0", + "expo-sqlite": ">=14.0.0", "knex": "*", "kysely": "*", "mysql2": ">=2", @@ -186,7 +186,7 @@ "better-sqlite3": "^8.4.0", "bun-types": "^0.6.6", "cpy": "^10.1.0", - "expo-sqlite": "^13.2.0", + "expo-sqlite": "^14.0.0", "knex": "^2.4.2", "kysely": "^0.25.0", "mysql2": "^3.3.3", diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index fb7da9ef6..e53e5ca0d 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -42,7 +42,6 @@ export interface ColumnBuilderBaseConfig | undefined; } export type MakeColumnConfig< @@ -64,7 +63,10 @@ export type MakeColumnConfig< enumValues: T['enumValues']; baseColumn: T extends { baseBuilder: infer U extends ColumnBuilderBase } ? BuildColumn : never; - generated: T['generated'] extends object ? T['generated'] : undefined; + generated: T extends { generated: infer G } ? unknown extends G ? undefined + : G extends undefined ? undefined + : G + : undefined; } & {}; export type ColumnBuilderTypeConfig< @@ -82,7 +84,7 @@ export type ColumnBuilderTypeConfig< notNull: T extends { notNull: infer U } ? U : boolean; hasDefault: T extends { hasDefault: infer U } ? U : boolean; enumValues: T['enumValues']; - generated: GeneratedColumnConfig | undefined; + generated: T extends { generated: infer G } ? G extends undefined ? unknown : G : unknown; } & TTypeConfig >; @@ -294,7 +296,9 @@ export abstract class ColumnBuilder< abstract generatedAlwaysAs( as: SQL | T['data'] | (() => SQL), config?: Partial>, - ): HasGenerated; + ): HasGenerated; /** @internal Sets the name of the column to the key within the table definition if a name was not given. */ setName(name: string) { diff --git a/drizzle-orm/src/expo-sqlite/driver.ts b/drizzle-orm/src/expo-sqlite/driver.ts index 6d9ebe375..fce53eed2 100644 --- a/drizzle-orm/src/expo-sqlite/driver.ts +++ b/drizzle-orm/src/expo-sqlite/driver.ts @@ -1,4 +1,4 @@ -import type { SQLiteDatabase, SQLiteRunResult } from 'expo-sqlite/next'; +import type { SQLiteDatabase, SQLiteRunResult } from 'expo-sqlite'; import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { diff --git a/drizzle-orm/src/expo-sqlite/query.ts b/drizzle-orm/src/expo-sqlite/query.ts index 8d9c5e4d9..a38fc3046 100644 --- a/drizzle-orm/src/expo-sqlite/query.ts +++ b/drizzle-orm/src/expo-sqlite/query.ts @@ -1,4 +1,4 @@ -import { addDatabaseChangeListener } from 'expo-sqlite/next'; +import { addDatabaseChangeListener } from 'expo-sqlite'; import { useEffect, useState } from 'react'; import { is } from '~/entity.ts'; import { SQL } from '~/sql/sql.ts'; diff --git a/drizzle-orm/src/expo-sqlite/session.ts b/drizzle-orm/src/expo-sqlite/session.ts index 9fcc4b93c..cb880ac6e 100644 --- a/drizzle-orm/src/expo-sqlite/session.ts +++ b/drizzle-orm/src/expo-sqlite/session.ts @@ -1,4 +1,4 @@ -import type { SQLiteDatabase, SQLiteRunResult, SQLiteStatement } from 'expo-sqlite/next'; +import type { SQLiteDatabase, SQLiteRunResult, SQLiteStatement } from 'expo-sqlite'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { NoopLogger } from '~/logger.ts'; diff --git a/drizzle-orm/src/mysql-core/columns/bigint.ts b/drizzle-orm/src/mysql-core/columns/bigint.ts index 7411c07ce..0973a1346 100644 --- a/drizzle-orm/src/mysql-core/columns/bigint.ts +++ b/drizzle-orm/src/mysql-core/columns/bigint.ts @@ -12,7 +12,6 @@ export type MySqlBigInt53BuilderInitial = MySqlBigInt53Bui data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlBigInt53Builder> @@ -60,7 +59,6 @@ export type MySqlBigInt64BuilderInitial = MySqlBigInt64Bui data: bigint; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class MySqlBigInt64Builder> diff --git a/drizzle-orm/src/mysql-core/columns/binary.ts b/drizzle-orm/src/mysql-core/columns/binary.ts index 7031b565c..e67006653 100644 --- a/drizzle-orm/src/mysql-core/columns/binary.ts +++ b/drizzle-orm/src/mysql-core/columns/binary.ts @@ -12,7 +12,6 @@ export type MySqlBinaryBuilderInitial = MySqlBinaryBuilder data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class MySqlBinaryBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/boolean.ts b/drizzle-orm/src/mysql-core/columns/boolean.ts index 9e786b6f9..2057496b6 100644 --- a/drizzle-orm/src/mysql-core/columns/boolean.ts +++ b/drizzle-orm/src/mysql-core/columns/boolean.ts @@ -11,7 +11,6 @@ export type MySqlBooleanBuilderInitial = MySqlBooleanBuild data: boolean; driverParam: number | boolean; enumValues: undefined; - generated: undefined; }>; export class MySqlBooleanBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/char.ts b/drizzle-orm/src/mysql-core/columns/char.ts index efcb7e65a..88492288e 100644 --- a/drizzle-orm/src/mysql-core/columns/char.ts +++ b/drizzle-orm/src/mysql-core/columns/char.ts @@ -12,7 +12,6 @@ export type MySqlCharBuilderInitial; export class MySqlCharBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/common.ts b/drizzle-orm/src/mysql-core/columns/common.ts index 9babc31da..2f1073e53 100644 --- a/drizzle-orm/src/mysql-core/columns/common.ts +++ b/drizzle-orm/src/mysql-core/columns/common.ts @@ -62,7 +62,9 @@ export abstract class MySqlColumnBuilder< return this; } - generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: MySqlGeneratedColumnConfig): HasGenerated { + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: MySqlGeneratedColumnConfig): HasGenerated { this.config.generated = { as, type: 'always', diff --git a/drizzle-orm/src/mysql-core/columns/custom.ts b/drizzle-orm/src/mysql-core/columns/custom.ts index 711b27813..50585bece 100644 --- a/drizzle-orm/src/mysql-core/columns/custom.ts +++ b/drizzle-orm/src/mysql-core/columns/custom.ts @@ -14,7 +14,6 @@ export type ConvertCustomConfig = MySqlDateBuilder<{ data: Date; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlDateBuilder> extends MySqlColumnBuilder { @@ -56,7 +55,6 @@ export type MySqlDateStringBuilderInitial = MySqlDateStrin data: string; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlDateStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/datetime.ts b/drizzle-orm/src/mysql-core/columns/datetime.ts index 61b062e8f..ea5b917b9 100644 --- a/drizzle-orm/src/mysql-core/columns/datetime.ts +++ b/drizzle-orm/src/mysql-core/columns/datetime.ts @@ -12,7 +12,6 @@ export type MySqlDateTimeBuilderInitial = MySqlDateTimeBui data: Date; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlDateTimeBuilder> @@ -70,7 +69,6 @@ export type MySqlDateTimeStringBuilderInitial = MySqlDateT data: string; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlDateTimeStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index 67cefb531..76b0ba8a1 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -12,7 +12,6 @@ export type MySqlDecimalBuilderInitial = MySqlDecimalBuild data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class MySqlDecimalBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index dfe5fca2e..bc23fc74c 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -12,7 +12,6 @@ export type MySqlDoubleBuilderInitial = MySqlDoubleBuilder data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlDoubleBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/enum.ts b/drizzle-orm/src/mysql-core/columns/enum.ts index 6a586ca7c..384e07d17 100644 --- a/drizzle-orm/src/mysql-core/columns/enum.ts +++ b/drizzle-orm/src/mysql-core/columns/enum.ts @@ -13,7 +13,6 @@ export type MySqlEnumColumnBuilderInitial; export class MySqlEnumColumnBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/float.ts b/drizzle-orm/src/mysql-core/columns/float.ts index 12ebd3e74..e368740a0 100644 --- a/drizzle-orm/src/mysql-core/columns/float.ts +++ b/drizzle-orm/src/mysql-core/columns/float.ts @@ -12,7 +12,6 @@ export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlFloatBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/int.ts b/drizzle-orm/src/mysql-core/columns/int.ts index aca0ea61e..79b93bdf7 100644 --- a/drizzle-orm/src/mysql-core/columns/int.ts +++ b/drizzle-orm/src/mysql-core/columns/int.ts @@ -12,7 +12,6 @@ export type MySqlIntBuilderInitial = MySqlIntBuilder<{ data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/json.ts b/drizzle-orm/src/mysql-core/columns/json.ts index ecb73ed82..12d11bd4a 100644 --- a/drizzle-orm/src/mysql-core/columns/json.ts +++ b/drizzle-orm/src/mysql-core/columns/json.ts @@ -11,7 +11,6 @@ export type MySqlJsonBuilderInitial = MySqlJsonBuilder<{ data: unknown; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class MySqlJsonBuilder> extends MySqlColumnBuilder { diff --git a/drizzle-orm/src/mysql-core/columns/mediumint.ts b/drizzle-orm/src/mysql-core/columns/mediumint.ts index 764969d31..7ba5cc944 100644 --- a/drizzle-orm/src/mysql-core/columns/mediumint.ts +++ b/drizzle-orm/src/mysql-core/columns/mediumint.ts @@ -13,7 +13,6 @@ export type MySqlMediumIntBuilderInitial = MySqlMediumIntB data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlMediumIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/real.ts b/drizzle-orm/src/mysql-core/columns/real.ts index 8b9eca794..c6b447310 100644 --- a/drizzle-orm/src/mysql-core/columns/real.ts +++ b/drizzle-orm/src/mysql-core/columns/real.ts @@ -12,7 +12,6 @@ export type MySqlRealBuilderInitial = MySqlRealBuilder<{ data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlRealBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/serial.ts b/drizzle-orm/src/mysql-core/columns/serial.ts index 88485d6b2..90fd7a2e5 100644 --- a/drizzle-orm/src/mysql-core/columns/serial.ts +++ b/drizzle-orm/src/mysql-core/columns/serial.ts @@ -23,7 +23,6 @@ export type MySqlSerialBuilderInitial = IsAutoincrement< data: number; driverParam: number; enumValues: undefined; - generated: undefined; }> > > diff --git a/drizzle-orm/src/mysql-core/columns/smallint.ts b/drizzle-orm/src/mysql-core/columns/smallint.ts index 482ff89ea..87083f0fa 100644 --- a/drizzle-orm/src/mysql-core/columns/smallint.ts +++ b/drizzle-orm/src/mysql-core/columns/smallint.ts @@ -13,7 +13,6 @@ export type MySqlSmallIntBuilderInitial = MySqlSmallIntBui data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlSmallIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/text.ts b/drizzle-orm/src/mysql-core/columns/text.ts index 18434a532..0604ef141 100644 --- a/drizzle-orm/src/mysql-core/columns/text.ts +++ b/drizzle-orm/src/mysql-core/columns/text.ts @@ -14,7 +14,6 @@ export type MySqlTextBuilderInitial; export class MySqlTextBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/time.ts b/drizzle-orm/src/mysql-core/columns/time.ts index 408453947..7ca5426ec 100644 --- a/drizzle-orm/src/mysql-core/columns/time.ts +++ b/drizzle-orm/src/mysql-core/columns/time.ts @@ -12,7 +12,6 @@ export type MySqlTimeBuilderInitial = MySqlTimeBuilder<{ data: string; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlTimeBuilder> extends MySqlColumnBuilder< diff --git a/drizzle-orm/src/mysql-core/columns/timestamp.ts b/drizzle-orm/src/mysql-core/columns/timestamp.ts index 892f8e603..2ccc2925f 100644 --- a/drizzle-orm/src/mysql-core/columns/timestamp.ts +++ b/drizzle-orm/src/mysql-core/columns/timestamp.ts @@ -12,7 +12,6 @@ export type MySqlTimestampBuilderInitial = MySqlTimestampB data: Date; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlTimestampBuilder> @@ -64,7 +63,6 @@ export type MySqlTimestampStringBuilderInitial = MySqlTime data: string; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class MySqlTimestampStringBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/tinyint.ts b/drizzle-orm/src/mysql-core/columns/tinyint.ts index ee4ccdaa7..890f169bd 100644 --- a/drizzle-orm/src/mysql-core/columns/tinyint.ts +++ b/drizzle-orm/src/mysql-core/columns/tinyint.ts @@ -13,7 +13,6 @@ export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuild data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class MySqlTinyIntBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/varbinary.ts b/drizzle-orm/src/mysql-core/columns/varbinary.ts index bc0dde635..837de8dcb 100644 --- a/drizzle-orm/src/mysql-core/columns/varbinary.ts +++ b/drizzle-orm/src/mysql-core/columns/varbinary.ts @@ -12,7 +12,6 @@ export type MySqlVarBinaryBuilderInitial = MySqlVarBinaryB data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class MySqlVarBinaryBuilder> diff --git a/drizzle-orm/src/mysql-core/columns/varchar.ts b/drizzle-orm/src/mysql-core/columns/varchar.ts index 32cfda7e9..6a335fef7 100644 --- a/drizzle-orm/src/mysql-core/columns/varchar.ts +++ b/drizzle-orm/src/mysql-core/columns/varchar.ts @@ -13,7 +13,6 @@ export type MySqlVarCharBuilderInitial; diff --git a/drizzle-orm/src/mysql-core/columns/year.ts b/drizzle-orm/src/mysql-core/columns/year.ts index 8a7a44410..4e4ae4faf 100644 --- a/drizzle-orm/src/mysql-core/columns/year.ts +++ b/drizzle-orm/src/mysql-core/columns/year.ts @@ -11,7 +11,6 @@ export type MySqlYearBuilderInitial = MySqlYearBuilder<{ data: number; driverParam: number; enumValues: undefined; - generated: undefined; }>; export class MySqlYearBuilder> extends MySqlColumnBuilder { diff --git a/drizzle-orm/src/mysql-core/query-builders/insert.ts b/drizzle-orm/src/mysql-core/query-builders/insert.ts index fe9f7d7ba..f3b4eec21 100644 --- a/drizzle-orm/src/mysql-core/query-builders/insert.ts +++ b/drizzle-orm/src/mysql-core/query-builders/insert.ts @@ -16,8 +16,8 @@ import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; import { Param, SQL, sql } from '~/sql/sql.ts'; import type { InferModelFromColumns } from '~/table.ts'; import { Table } from '~/table.ts'; -import { mapUpdateSet, orderSelectedFields } from '~/utils.ts'; -import type { AnyMySqlColumn, MySqlColumn } from '../columns/common.ts'; +import { mapUpdateSet } from '~/utils.ts'; +import type { AnyMySqlColumn } from '../columns/common.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; import type { MySqlUpdateSetSource } from './update.ts'; @@ -210,7 +210,7 @@ export class MySqlInsertBase< /** * Adds an `on duplicate key update` clause to the query. * - * Calling this method will update update the row if any unique index conflicts. MySQL will automatically determine the conflict target based on the primary key and unique indexes. + * Calling this method will update the row if any unique index conflicts. MySQL will automatically determine the conflict target based on the primary key and unique indexes. * * See docs: {@link https://orm.drizzle.team/docs/insert#on-duplicate-key-update} * @@ -252,7 +252,7 @@ export class MySqlInsertBase< returning.push({ field: value, path: [key] }); } } - this.config.returning = orderSelectedFields(this.config.table[Table.Symbol.Columns]); + this.config.returning = returning; return this as any; } diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index 4ef1dc36a..cfa0c7861 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -16,7 +16,7 @@ export interface NeonDriverOptions { } export class NeonHttpDriver { - static readonly [entityKind]: string = 'NeonDriver'; + static readonly [entityKind]: string = 'NeonHttpDriver'; constructor( private client: NeonHttpClient, diff --git a/drizzle-orm/src/operations.ts b/drizzle-orm/src/operations.ts index 6fb5cbd2e..573e05957 100644 --- a/drizzle-orm/src/operations.ts +++ b/drizzle-orm/src/operations.ts @@ -1,4 +1,5 @@ import type { AnyColumn, Column } from './column.ts'; +import type { GeneratedColumnConfig } from './index.ts'; import type { SQL } from './sql/sql.ts'; import type { Table } from './table.ts'; @@ -8,17 +9,16 @@ export type RequiredKeyOnly = T extends A }> ? TKey : never; -export type NotGenerated = T extends AnyColumn<{ - generated: undefined; -}> ? TKey - : never; - export type OptionalKeyOnly< TKey extends string, T extends Column, > = TKey extends RequiredKeyOnly ? never - : TKey extends NotGenerated ? TKey - : T['_']['generated'] extends object ? T['_']['generated']['type'] extends 'byDefault' ? TKey : never + : T extends { + _: { + generated: infer G; + }; + } ? G extends GeneratedColumnConfig ? G['type'] extends 'always' ? never : TKey + : TKey : never; // TODO: SQL -> SQLWrapper diff --git a/drizzle-orm/src/pg-core/columns/bigint.ts b/drizzle-orm/src/pg-core/columns/bigint.ts index 23e1e7f15..17ac0798b 100644 --- a/drizzle-orm/src/pg-core/columns/bigint.ts +++ b/drizzle-orm/src/pg-core/columns/bigint.ts @@ -14,7 +14,6 @@ export type PgBigInt53BuilderInitial = PgBigInt53Builder<{ data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class PgBigInt53Builder> @@ -56,7 +55,6 @@ export type PgBigInt64BuilderInitial = PgBigInt64Builder<{ data: bigint; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgBigInt64Builder> diff --git a/drizzle-orm/src/pg-core/columns/bigserial.ts b/drizzle-orm/src/pg-core/columns/bigserial.ts index ed4224354..0aa7e7a7f 100644 --- a/drizzle-orm/src/pg-core/columns/bigserial.ts +++ b/drizzle-orm/src/pg-core/columns/bigserial.ts @@ -20,7 +20,6 @@ export type PgBigSerial53BuilderInitial = NotNull< data: number; driverParam: number; enumValues: undefined; - generated: undefined; }> > >; @@ -71,7 +70,6 @@ export type PgBigSerial64BuilderInitial = NotNull< data: bigint; driverParam: string; enumValues: undefined; - generated: undefined; }> > >; diff --git a/drizzle-orm/src/pg-core/columns/boolean.ts b/drizzle-orm/src/pg-core/columns/boolean.ts index cd30895c7..e2d514864 100644 --- a/drizzle-orm/src/pg-core/columns/boolean.ts +++ b/drizzle-orm/src/pg-core/columns/boolean.ts @@ -11,7 +11,6 @@ export type PgBooleanBuilderInitial = PgBooleanBuilder<{ data: boolean; driverParam: boolean; enumValues: undefined; - generated: undefined; }>; export class PgBooleanBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/char.ts b/drizzle-orm/src/pg-core/columns/char.ts index 6629f08cc..2cc304221 100644 --- a/drizzle-orm/src/pg-core/columns/char.ts +++ b/drizzle-orm/src/pg-core/columns/char.ts @@ -12,7 +12,6 @@ export type PgCharBuilderInitial; export class PgCharBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/cidr.ts b/drizzle-orm/src/pg-core/columns/cidr.ts index 6caa3dc25..ab97536ee 100644 --- a/drizzle-orm/src/pg-core/columns/cidr.ts +++ b/drizzle-orm/src/pg-core/columns/cidr.ts @@ -11,7 +11,6 @@ export type PgCidrBuilderInitial = PgCidrBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgCidrBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index c2fbe8cb9..de2267cf3 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -83,13 +83,17 @@ export abstract class PgColumnBuilder< return this; } - generatedAlwaysAs(as: SQL | T['data'] | (() => SQL)): HasGenerated { + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL)): HasGenerated { this.config.generated = { as, type: 'always', mode: 'stored', }; - return this as any; + return this as HasGenerated; } /** @internal */ diff --git a/drizzle-orm/src/pg-core/columns/custom.ts b/drizzle-orm/src/pg-core/columns/custom.ts index b59169ed6..f4f622ff6 100644 --- a/drizzle-orm/src/pg-core/columns/custom.ts +++ b/drizzle-orm/src/pg-core/columns/custom.ts @@ -14,7 +14,6 @@ export type ConvertCustomConfig = PgDateBuilder<{ data: Date; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgDateBuilder> extends PgDateColumnBaseBuilder { @@ -54,7 +53,6 @@ export type PgDateStringBuilderInitial = PgDateStringBuild data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgDateStringBuilder> diff --git a/drizzle-orm/src/pg-core/columns/double-precision.ts b/drizzle-orm/src/pg-core/columns/double-precision.ts index 77245ea45..942085bc1 100644 --- a/drizzle-orm/src/pg-core/columns/double-precision.ts +++ b/drizzle-orm/src/pg-core/columns/double-precision.ts @@ -11,7 +11,6 @@ export type PgDoublePrecisionBuilderInitial = PgDoublePrec data: number; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class PgDoublePrecisionBuilder> diff --git a/drizzle-orm/src/pg-core/columns/enum.ts b/drizzle-orm/src/pg-core/columns/enum.ts index 7712ca606..db7905b39 100644 --- a/drizzle-orm/src/pg-core/columns/enum.ts +++ b/drizzle-orm/src/pg-core/columns/enum.ts @@ -13,7 +13,6 @@ export type PgEnumColumnBuilderInitial; const isPgEnumSym = Symbol.for('drizzle:isPgEnum'); diff --git a/drizzle-orm/src/pg-core/columns/inet.ts b/drizzle-orm/src/pg-core/columns/inet.ts index 6b6210fcf..741bbdf86 100644 --- a/drizzle-orm/src/pg-core/columns/inet.ts +++ b/drizzle-orm/src/pg-core/columns/inet.ts @@ -11,7 +11,6 @@ export type PgInetBuilderInitial = PgInetBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgInetBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/integer.ts b/drizzle-orm/src/pg-core/columns/integer.ts index bb70f9b41..9be92bb34 100644 --- a/drizzle-orm/src/pg-core/columns/integer.ts +++ b/drizzle-orm/src/pg-core/columns/integer.ts @@ -5,14 +5,13 @@ import type { AnyPgTable } from '../table.ts'; import { PgColumn } from './common.ts'; import { PgIntColumnBaseBuilder } from './int.common.ts'; -type PgIntegerBuilderInitial = PgIntegerBuilder<{ +export type PgIntegerBuilderInitial = PgIntegerBuilder<{ name: TName; dataType: 'number'; columnType: 'PgInteger'; data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class PgIntegerBuilder> diff --git a/drizzle-orm/src/pg-core/columns/interval.ts b/drizzle-orm/src/pg-core/columns/interval.ts index 4d3ed4588..8f81e9867 100644 --- a/drizzle-orm/src/pg-core/columns/interval.ts +++ b/drizzle-orm/src/pg-core/columns/interval.ts @@ -13,7 +13,6 @@ export type PgIntervalBuilderInitial = PgIntervalBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgIntervalBuilder> diff --git a/drizzle-orm/src/pg-core/columns/json.ts b/drizzle-orm/src/pg-core/columns/json.ts index 3c440c7d2..deed256b9 100644 --- a/drizzle-orm/src/pg-core/columns/json.ts +++ b/drizzle-orm/src/pg-core/columns/json.ts @@ -11,7 +11,6 @@ export type PgJsonBuilderInitial = PgJsonBuilder<{ data: unknown; driverParam: unknown; enumValues: undefined; - generated: undefined; }>; export class PgJsonBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/jsonb.ts b/drizzle-orm/src/pg-core/columns/jsonb.ts index 3407730db..14af7c9e9 100644 --- a/drizzle-orm/src/pg-core/columns/jsonb.ts +++ b/drizzle-orm/src/pg-core/columns/jsonb.ts @@ -11,7 +11,6 @@ export type PgJsonbBuilderInitial = PgJsonbBuilder<{ data: unknown; driverParam: unknown; enumValues: undefined; - generated: undefined; }>; export class PgJsonbBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/line.ts b/drizzle-orm/src/pg-core/columns/line.ts index 014140797..9378d1aa1 100644 --- a/drizzle-orm/src/pg-core/columns/line.ts +++ b/drizzle-orm/src/pg-core/columns/line.ts @@ -13,7 +13,6 @@ export type PgLineBuilderInitial = PgLineBuilder<{ data: [number, number, number]; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class PgLineBuilder> extends PgColumnBuilder { @@ -58,7 +57,6 @@ export type PgLineABCBuilderInitial = PgLineABCBuilder<{ data: { a: number; b: number; c: number }; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgLineABCBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/macaddr.ts b/drizzle-orm/src/pg-core/columns/macaddr.ts index bfc4511f4..bcd8b02bc 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr.ts @@ -11,7 +11,6 @@ export type PgMacaddrBuilderInitial = PgMacaddrBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgMacaddrBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/macaddr8.ts b/drizzle-orm/src/pg-core/columns/macaddr8.ts index 6c4218de0..e9e3e4bef 100644 --- a/drizzle-orm/src/pg-core/columns/macaddr8.ts +++ b/drizzle-orm/src/pg-core/columns/macaddr8.ts @@ -11,7 +11,6 @@ export type PgMacaddr8BuilderInitial = PgMacaddr8Builder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgMacaddr8Builder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/numeric.ts b/drizzle-orm/src/pg-core/columns/numeric.ts index efeb4ab97..fc58d9859 100644 --- a/drizzle-orm/src/pg-core/columns/numeric.ts +++ b/drizzle-orm/src/pg-core/columns/numeric.ts @@ -12,7 +12,6 @@ export type PgNumericBuilderInitial = PgNumericBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgNumericBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/point.ts b/drizzle-orm/src/pg-core/columns/point.ts index 827579ad8..c204aedea 100644 --- a/drizzle-orm/src/pg-core/columns/point.ts +++ b/drizzle-orm/src/pg-core/columns/point.ts @@ -13,7 +13,6 @@ export type PgPointTupleBuilderInitial = PgPointTupleBuild data: [number, number]; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class PgPointTupleBuilder> @@ -63,7 +62,6 @@ export type PgPointObjectBuilderInitial = PgPointObjectBui data: { x: number; y: number }; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgPointObjectBuilder> diff --git a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts index 853c3dff9..93632d31c 100644 --- a/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts +++ b/drizzle-orm/src/pg-core/columns/postgis_extension/geometry.ts @@ -14,7 +14,6 @@ export type PgGeometryBuilderInitial = PgGeometryBuilder<{ data: [number, number]; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgGeometryBuilder> extends PgColumnBuilder { @@ -58,7 +57,6 @@ export type PgGeometryObjectBuilderInitial = PgGeometryObj data: { x: number; y: number }; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgGeometryObjectBuilder> diff --git a/drizzle-orm/src/pg-core/columns/real.ts b/drizzle-orm/src/pg-core/columns/real.ts index 0e3de4b2e..b3c339c9b 100644 --- a/drizzle-orm/src/pg-core/columns/real.ts +++ b/drizzle-orm/src/pg-core/columns/real.ts @@ -11,7 +11,6 @@ export type PgRealBuilderInitial = PgRealBuilder<{ data: number; driverParam: string | number; enumValues: undefined; - generated: undefined; }>; export class PgRealBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/serial.ts b/drizzle-orm/src/pg-core/columns/serial.ts index 6a0196c38..261ef2af9 100644 --- a/drizzle-orm/src/pg-core/columns/serial.ts +++ b/drizzle-orm/src/pg-core/columns/serial.ts @@ -19,7 +19,6 @@ export type PgSerialBuilderInitial = NotNull< data: number; driverParam: number; enumValues: undefined; - generated: undefined; }> > >; diff --git a/drizzle-orm/src/pg-core/columns/smallint.ts b/drizzle-orm/src/pg-core/columns/smallint.ts index 1cdfe141f..e662904b5 100644 --- a/drizzle-orm/src/pg-core/columns/smallint.ts +++ b/drizzle-orm/src/pg-core/columns/smallint.ts @@ -12,7 +12,6 @@ export type PgSmallIntBuilderInitial = PgSmallIntBuilder<{ data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class PgSmallIntBuilder> diff --git a/drizzle-orm/src/pg-core/columns/smallserial.ts b/drizzle-orm/src/pg-core/columns/smallserial.ts index 456dc47f7..c92fc8350 100644 --- a/drizzle-orm/src/pg-core/columns/smallserial.ts +++ b/drizzle-orm/src/pg-core/columns/smallserial.ts @@ -19,7 +19,6 @@ export type PgSmallSerialBuilderInitial = NotNull< data: number; driverParam: number; enumValues: undefined; - generated: undefined; }> > >; diff --git a/drizzle-orm/src/pg-core/columns/text.ts b/drizzle-orm/src/pg-core/columns/text.ts index 6845f0e74..980f0ec2f 100644 --- a/drizzle-orm/src/pg-core/columns/text.ts +++ b/drizzle-orm/src/pg-core/columns/text.ts @@ -12,7 +12,6 @@ type PgTextBuilderInitial; export class PgTextBuilder< diff --git a/drizzle-orm/src/pg-core/columns/time.ts b/drizzle-orm/src/pg-core/columns/time.ts index 9b3ff51e0..b9b52fd79 100644 --- a/drizzle-orm/src/pg-core/columns/time.ts +++ b/drizzle-orm/src/pg-core/columns/time.ts @@ -14,7 +14,6 @@ export type PgTimeBuilderInitial = PgTimeBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgTimeBuilder> extends PgDateColumnBaseBuilder< diff --git a/drizzle-orm/src/pg-core/columns/timestamp.ts b/drizzle-orm/src/pg-core/columns/timestamp.ts index 6879106e0..f5a5cb0a6 100644 --- a/drizzle-orm/src/pg-core/columns/timestamp.ts +++ b/drizzle-orm/src/pg-core/columns/timestamp.ts @@ -13,7 +13,6 @@ export type PgTimestampBuilderInitial = PgTimestampBuilder data: Date; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgTimestampBuilder> @@ -75,7 +74,6 @@ export type PgTimestampStringBuilderInitial = PgTimestampS data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgTimestampStringBuilder> diff --git a/drizzle-orm/src/pg-core/columns/uuid.ts b/drizzle-orm/src/pg-core/columns/uuid.ts index d0e5a6830..c8455d372 100644 --- a/drizzle-orm/src/pg-core/columns/uuid.ts +++ b/drizzle-orm/src/pg-core/columns/uuid.ts @@ -12,7 +12,6 @@ export type PgUUIDBuilderInitial = PgUUIDBuilder<{ data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgUUIDBuilder> extends PgColumnBuilder { diff --git a/drizzle-orm/src/pg-core/columns/varchar.ts b/drizzle-orm/src/pg-core/columns/varchar.ts index 78ee0db96..192262bef 100644 --- a/drizzle-orm/src/pg-core/columns/varchar.ts +++ b/drizzle-orm/src/pg-core/columns/varchar.ts @@ -12,7 +12,6 @@ export type PgVarcharBuilderInitial; export class PgVarcharBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts index 81eea6b2f..f1d692821 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts @@ -12,7 +12,6 @@ export type PgBinaryVectorBuilderInitial = PgBinaryVectorB data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgBinaryVectorBuilder> diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts index e12d0d22f..1c89e7b60 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts @@ -12,7 +12,6 @@ export type PgHalfVectorBuilderInitial = PgHalfVectorBuild data: number[]; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgHalfVectorBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts index 3881b338f..4817fa51f 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/sparsevec.ts @@ -12,7 +12,6 @@ export type PgSparseVectorBuilderInitial = PgSparseVectorB data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgSparseVectorBuilder> diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts index eaac075dc..84fb54964 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts @@ -12,7 +12,6 @@ export type PgVectorBuilderInitial = PgVectorBuilder<{ data: number[]; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class PgVectorBuilder> extends PgColumnBuilder< diff --git a/drizzle-orm/src/sql/expressions/conditions.ts b/drizzle-orm/src/sql/expressions/conditions.ts index ba0e21fbc..7ad1355dd 100644 --- a/drizzle-orm/src/sql/expressions/conditions.ts +++ b/drizzle-orm/src/sql/expressions/conditions.ts @@ -526,7 +526,7 @@ export function notBetween( * * @see ilike for a case-insensitive version of this condition */ -export function like(column: Column, value: string | SQLWrapper): SQL { +export function like(column: Column | SQL.Aliased | SQL, value: string | SQLWrapper): SQL { return sql`${column} like ${value}`; } @@ -548,7 +548,7 @@ export function like(column: Column, value: string | SQLWrapper): SQL { * @see like for the inverse condition * @see notIlike for a case-insensitive version of this condition */ -export function notLike(column: Column, value: string | SQLWrapper): SQL { +export function notLike(column: Column | SQL.Aliased | SQL, value: string | SQLWrapper): SQL { return sql`${column} not like ${value}`; } @@ -571,7 +571,7 @@ export function notLike(column: Column, value: string | SQLWrapper): SQL { * * @see like for a case-sensitive version of this condition */ -export function ilike(column: Column, value: string | SQLWrapper): SQL { +export function ilike(column: Column | SQL.Aliased | SQL, value: string | SQLWrapper): SQL { return sql`${column} ilike ${value}`; } @@ -593,7 +593,7 @@ export function ilike(column: Column, value: string | SQLWrapper): SQL { * @see ilike for the inverse condition * @see notLike for a case-sensitive version of this condition */ -export function notIlike(column: Column, value: string | SQLWrapper): SQL { +export function notIlike(column: Column | SQL.Aliased | SQL, value: string | SQLWrapper): SQL { return sql`${column} not ilike ${value}`; } diff --git a/drizzle-orm/src/sql/sql.ts b/drizzle-orm/src/sql/sql.ts index 19185f1bf..234370a85 100644 --- a/drizzle-orm/src/sql/sql.ts +++ b/drizzle-orm/src/sql/sql.ts @@ -7,7 +7,7 @@ import { tracer } from '~/tracing.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { AnyColumn } from '../column.ts'; import { Column } from '../column.ts'; -import { Table } from '../table.ts'; +import { IsAlias, Table } from '../table.ts'; /** * This class is used to indicate a primitive param value that is used in `sql` tag. @@ -192,7 +192,15 @@ export class SQL implements SQLWrapper { if (_config.invokeSource === 'indexes') { return { sql: escapeName(columnName), params: [] }; } - return { sql: escapeName(chunk.table[Table.Symbol.Name]) + '.' + escapeName(columnName), params: [] }; + + const schemaName = chunk.table[Table.Symbol.Schema]; + return { + sql: chunk.table[IsAlias] || schemaName === undefined + ? escapeName(chunk.table[Table.Symbol.Name]) + '.' + escapeName(columnName) + : escapeName(schemaName) + '.' + escapeName(chunk.table[Table.Symbol.Name]) + '.' + + escapeName(columnName), + params: [], + }; } if (is(chunk, View)) { diff --git a/drizzle-orm/src/sqlite-core/README.md b/drizzle-orm/src/sqlite-core/README.md index 6d4ebd8b6..ae5fbe660 100644 --- a/drizzle-orm/src/sqlite-core/README.md +++ b/drizzle-orm/src/sqlite-core/README.md @@ -8,7 +8,7 @@
-DrizzleORM is a [tiny](https://twitter.com/_alexblokh/status/1594735880417472512), [blazingly fast](#️-performance-and-prepared-statements) TypeScript ORM library with a [drizzle-kit](#-migrations) CLI companion for automatic SQL migrations generation. +Drizzle ORM is a [tiny](https://twitter.com/_alexblokh/status/1594735880417472512), [blazingly fast](#️-performance-and-prepared-statements) TypeScript ORM library with a [drizzle-kit](#-migrations) CLI companion for automatic SQL migrations generation. Here you can find extensive docs for SQLite module. | Driver | Support | | @@ -365,7 +365,8 @@ const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42))); const result = db.with(sq).select().from(sq).all(); ``` -> **Note**: Keep in mind that if you need to select raw `sql` in a WITH subquery and reference that field in other queries, you must add an alias to it: +> [!NOTE] +> Keep in mind that if you need to select raw `sql` in a WITH subquery and reference that field in other queries, you must add an alias to it: ```typescript const sq = db.$with('sq').as(db.select({ name: sql`upper(${users.name})`.as('name') }).from(users)); @@ -582,7 +583,8 @@ db ### Joins -> **Note**: for in-depth partial select joins documentation, refer to [this page](/docs/joins.md). +> [!NOTE] +> For in-depth partial select joins documentation, refer to [this page](/docs/joins.md). ### Many-to-one @@ -721,7 +723,8 @@ const { sql, params } = query.toSQL(); ## Views (WIP) -> **Warning**: views are currently only implemented on the ORM side. That means you can query the views that already exist in the database, but they won't be added to drizzle-kit migrations or `db push` yet. +> [!WARNING] +> views are currently only implemented on the ORM side. That means you can query the views that already exist in the database, but they won't be added to drizzle-kit migrations or `db push` yet. ### Creating a view @@ -731,7 +734,8 @@ import { sqliteView } from 'drizzle-orm/sqlite-core'; const newYorkers = sqliteView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); ``` -> **Warning**: All the parameters inside the query will be inlined, instead of replaced by `$1`, `$2`, etc. +> [!WARNING] +> All the parameters inside the query will be inlined, instead of replaced by `$1`, `$2`, etc. You can also use the [`queryBuilder` instance](#query-builder) directly instead of passing a callback, if you already have it imported. @@ -794,8 +798,8 @@ q.all({ name: '%an%' }) // SELECT * FROM customers WHERE name ilike '%an%' ### Automatic SQL migrations generation with drizzle-kit -[Drizzle Kit](https://www.npmjs.com/package/drizzle-kit) is a CLI migrator tool for Drizzle ORM. It is probably one and only tool that lets you completely automatically generate SQL migrations and covers ~95% of the common cases like deletions and renames by prompting user input. -Check out the [docs for Drizzle Kit](https://github.com/drizzle-team/drizzle-kit-mirror) +[Drizzle Kit](https://www.npmjs.com/package/drizzle-kit) is a CLI migrator tool for Drizzle ORM. It is probably the one and only tool that lets you completely automatically generate SQL migrations and covers ~95% of the common cases like deletions and renames by prompting user input. +Check out the [docs for Drizzle Kit](https://github.com/drizzle-team/drizzle-kit-mirror). For schema file: diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index 22deb3a84..d9f3fc7c6 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -14,7 +14,6 @@ export type SQLiteBigIntBuilderInitial = SQLiteBigIntBuild data: bigint; driverParam: Buffer; enumValues: undefined; - generated: undefined; }>; export class SQLiteBigIntBuilder> @@ -57,7 +56,6 @@ export type SQLiteBlobJsonBuilderInitial = SQLiteBlobJsonB data: unknown; driverParam: Buffer; enumValues: undefined; - generated: undefined; }>; export class SQLiteBlobJsonBuilder> @@ -103,7 +101,6 @@ export type SQLiteBlobBufferBuilderInitial = SQLiteBlobBuf data: Buffer; driverParam: Buffer; enumValues: undefined; - generated: undefined; }>; export class SQLiteBlobBufferBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/common.ts b/drizzle-orm/src/sqlite-core/columns/common.ts index 0fd985537..953e5692d 100644 --- a/drizzle-orm/src/sqlite-core/columns/common.ts +++ b/drizzle-orm/src/sqlite-core/columns/common.ts @@ -63,7 +63,9 @@ export abstract class SQLiteColumnBuilder< return this; } - generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SQLiteGeneratedColumnConfig): HasGenerated { + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SQLiteGeneratedColumnConfig): HasGenerated { this.config.generated = { as, type: 'always', diff --git a/drizzle-orm/src/sqlite-core/columns/custom.ts b/drizzle-orm/src/sqlite-core/columns/custom.ts index 6ece801c5..b23d6442f 100644 --- a/drizzle-orm/src/sqlite-core/columns/custom.ts +++ b/drizzle-orm/src/sqlite-core/columns/custom.ts @@ -14,7 +14,6 @@ export type ConvertCustomConfig = SQLiteIntegerBui data: number; driverParam: number; enumValues: undefined; - generated: undefined; }>; export class SQLiteIntegerBuilder> @@ -103,7 +102,6 @@ export type SQLiteTimestampBuilderInitial = SQLiteTimestam data: Date; driverParam: number; enumValues: undefined; - generated: undefined; }>; export class SQLiteTimestampBuilder> @@ -165,7 +163,6 @@ export type SQLiteBooleanBuilderInitial = SQLiteBooleanBui data: boolean; driverParam: number; enumValues: undefined; - generated: undefined; }>; export class SQLiteBooleanBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/numeric.ts b/drizzle-orm/src/sqlite-core/columns/numeric.ts index 93dfc4c3d..9505367a2 100644 --- a/drizzle-orm/src/sqlite-core/columns/numeric.ts +++ b/drizzle-orm/src/sqlite-core/columns/numeric.ts @@ -11,7 +11,6 @@ export type SQLiteNumericBuilderInitial = SQLiteNumericBui data: string; driverParam: string; enumValues: undefined; - generated: undefined; }>; export class SQLiteNumericBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/real.ts b/drizzle-orm/src/sqlite-core/columns/real.ts index cd7cf5d01..8821eb275 100644 --- a/drizzle-orm/src/sqlite-core/columns/real.ts +++ b/drizzle-orm/src/sqlite-core/columns/real.ts @@ -11,7 +11,6 @@ export type SQLiteRealBuilderInitial = SQLiteRealBuilder<{ data: number; driverParam: number; enumValues: undefined; - generated: undefined; }>; export class SQLiteRealBuilder> diff --git a/drizzle-orm/src/sqlite-core/columns/text.ts b/drizzle-orm/src/sqlite-core/columns/text.ts index 84c71fb20..241eb860d 100644 --- a/drizzle-orm/src/sqlite-core/columns/text.ts +++ b/drizzle-orm/src/sqlite-core/columns/text.ts @@ -12,7 +12,6 @@ export type SQLiteTextBuilderInitial; export class SQLiteTextBuilder> extends SQLiteColumnBuilder< diff --git a/drizzle-orm/tests/casing/mysql-to-camel.test.ts b/drizzle-orm/tests/casing/mysql-to-camel.test.ts index 651365485..aa8aa04ee 100644 --- a/drizzle-orm/tests/casing/mysql-to-camel.test.ts +++ b/drizzle-orm/tests/casing/mysql-to-camel.test.ts @@ -66,7 +66,7 @@ describe('mysql to snake case', () => { expect(query.toSQL()).toEqual({ sql: - "select `users`.`firstName` || ' ' || `users`.`lastName` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`userId` order by `users`.`firstName` asc", + "select `users`.`firstName` || ' ' || `users`.`lastName` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `test`.`developers`.`userId` order by `users`.`firstName` asc", params: [], }); expect(db.dialect.casing.cache).toEqual(cache); diff --git a/drizzle-orm/tests/casing/mysql-to-snake.test.ts b/drizzle-orm/tests/casing/mysql-to-snake.test.ts index 8ce65e2f9..60496af22 100644 --- a/drizzle-orm/tests/casing/mysql-to-snake.test.ts +++ b/drizzle-orm/tests/casing/mysql-to-snake.test.ts @@ -66,7 +66,7 @@ describe('mysql to snake case', () => { expect(query.toSQL()).toEqual({ sql: - "select `users`.`first_name` || ' ' || `users`.`last_name` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `developers`.`user_id` order by `users`.`first_name` asc", + "select `users`.`first_name` || ' ' || `users`.`last_name` as `name`, `users`.`AGE` from `users` left join `test`.`developers` on `users`.`id` = `test`.`developers`.`user_id` order by `users`.`first_name` asc", params: [], }); expect(db.dialect.casing.cache).toEqual(cache); diff --git a/drizzle-orm/tests/casing/pg-to-camel.test.ts b/drizzle-orm/tests/casing/pg-to-camel.test.ts index 8d4420403..e325745da 100644 --- a/drizzle-orm/tests/casing/pg-to-camel.test.ts +++ b/drizzle-orm/tests/casing/pg-to-camel.test.ts @@ -62,7 +62,7 @@ describe('postgres to camel case', () => { expect(query.toSQL()).toEqual({ sql: - 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."userId" order by "users"."firstName" asc', + 'select "users"."firstName" || \' \' || "users"."lastName" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "test"."developers"."userId" order by "users"."firstName" asc', params: [], }); expect(db.dialect.casing.cache).toEqual(cache); diff --git a/drizzle-orm/tests/casing/pg-to-snake.test.ts b/drizzle-orm/tests/casing/pg-to-snake.test.ts index 0384e70ca..0c2aeaa27 100644 --- a/drizzle-orm/tests/casing/pg-to-snake.test.ts +++ b/drizzle-orm/tests/casing/pg-to-snake.test.ts @@ -62,7 +62,7 @@ describe('postgres to snake case', () => { expect(query.toSQL()).toEqual({ sql: - 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "developers"."user_id" order by "users"."first_name" asc', + 'select "users"."first_name" || \' \' || "users"."last_name" as "name", "users"."AGE" from "users" left join "test"."developers" on "users"."id" = "test"."developers"."user_id" order by "users"."first_name" asc', params: [], }); expect(db.dialect.casing.cache).toEqual(cache); diff --git a/drizzle-orm/type-tests/mysql/generated-columns.ts b/drizzle-orm/type-tests/mysql/generated-columns.ts index d045fe1b3..56b9d4412 100644 --- a/drizzle-orm/type-tests/mysql/generated-columns.ts +++ b/drizzle-orm/type-tests/mysql/generated-columns.ts @@ -17,6 +17,7 @@ const users = mysqlTable( ).$type(), // There is no way for drizzle to detect nullability in these cases. This is how the user can work around it }, ); + { type User = typeof users.$inferSelect; type NewUser = typeof users.$inferInsert; diff --git a/drizzle-orm/type-tests/mysql/with.ts b/drizzle-orm/type-tests/mysql/with.ts index b4e528191..e6f240489 100644 --- a/drizzle-orm/type-tests/mysql/with.ts +++ b/drizzle-orm/type-tests/mysql/with.ts @@ -1,6 +1,6 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; -import { gt, inArray } from '~/expressions.ts'; +import { gt, inArray, like } from '~/expressions.ts'; import { int, mysqlTable, serial, text } from '~/mysql-core/index.ts'; import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; @@ -77,4 +77,7 @@ const orders = mysqlTable('orders', { generated: string | null; }[], typeof allFromWith> >; + + const regionalSalesWith = db.$with('regional_sales_with').as(db.select().from(regionalSales)); + db.with(regionalSalesWith).select().from(regionalSalesWith).where(like(regionalSalesWith.totalSales, 'abc')); } diff --git a/drizzle-orm/type-tests/pg/with.ts b/drizzle-orm/type-tests/pg/with.ts index d5fcc96ed..288e3b6d0 100644 --- a/drizzle-orm/type-tests/pg/with.ts +++ b/drizzle-orm/type-tests/pg/with.ts @@ -1,6 +1,6 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; -import { gt, inArray } from '~/expressions.ts'; +import { gt, inArray, like } from '~/expressions.ts'; import { integer, pgTable, serial, text } from '~/pg-core/index.ts'; import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; @@ -77,4 +77,7 @@ const orders = pgTable('orders', { generated: string | null; }[], typeof allFromWith> >; + + const regionalSalesWith = db.$with('regional_sales_with').as(db.select().from(regionalSales)); + db.with(regionalSalesWith).select().from(regionalSalesWith).where(like(regionalSalesWith.totalSales, 'abc')); } diff --git a/drizzle-orm/type-tests/sqlite/generated-columns.ts b/drizzle-orm/type-tests/sqlite/generated-columns.ts index 57ffea989..f1474baed 100644 --- a/drizzle-orm/type-tests/sqlite/generated-columns.ts +++ b/drizzle-orm/type-tests/sqlite/generated-columns.ts @@ -11,12 +11,14 @@ const users = sqliteTable( firstName: text('first_name', { length: 255 }), lastName: text('last_name', { length: 255 }), email: text('email').notNull(), - fullName: text('full_name').generatedAlwaysAs(sql`concat_ws(first_name, ' ', last_name)`), + fullName: text('full_name') + .generatedAlwaysAs(sql`concat_ws(first_name, ' ', last_name)`), upperName: text('upper_name').generatedAlwaysAs( sql` case when first_name is null then null else upper(first_name) end `, ).$type(), // There is no way for drizzle to detect nullability in these cases. This is how the user can work around it }, ); + { type User = typeof users.$inferSelect; type NewUser = typeof users.$inferInsert; diff --git a/drizzle-orm/type-tests/sqlite/with.ts b/drizzle-orm/type-tests/sqlite/with.ts index 8b5963eb6..b26e4e7d7 100644 --- a/drizzle-orm/type-tests/sqlite/with.ts +++ b/drizzle-orm/type-tests/sqlite/with.ts @@ -1,6 +1,6 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; -import { gt, inArray } from '~/expressions.ts'; +import { gt, inArray, like } from '~/expressions.ts'; import { sql } from '~/sql/sql.ts'; import { integer, sqliteTable, text } from '~/sqlite-core/index.ts'; import { db } from './db.ts'; @@ -78,4 +78,7 @@ const orders = sqliteTable('orders', { generated: string | null; }[], typeof allFromWith> >; + + const regionalSalesWith = db.$with('regional_sales_with').as(db.select().from(regionalSales)); + db.with(regionalSalesWith).select().from(regionalSalesWith).where(like(regionalSalesWith.totalSales, 'abc')); } diff --git a/examples/mysql-proxy/README.md b/examples/mysql-proxy/README.md index 8bbdf3f7b..fadc843d3 100644 --- a/examples/mysql-proxy/README.md +++ b/examples/mysql-proxy/README.md @@ -30,7 +30,7 @@ This project has simple example of defining http proxy server, that will proxy a
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle always waits for `{rows: string[][] | object[]}` so if any error was on http call(or any other call) - be sure, that you return at least empty array back > > For `all` method you should return `{rows: string[][]}` @@ -72,7 +72,7 @@ In current MySQL Proxy version - drizzle don't handle transactions for migration
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle just finds migrations, that need to be executed on this iteration and if finds some -> provide `queries` array to callback
@@ -97,7 +97,7 @@ await migrate(db, async (queries) => { --- -> **Note**: +> [!WARNING] > It's just a suggestion on how proxy server could be set up and a simple example of params handling on `query` and `migration` calls ```typescript diff --git a/examples/neon-cloudflare/readme.md b/examples/neon-cloudflare/readme.md index 0585ccecc..f69581b21 100644 --- a/examples/neon-cloudflare/readme.md +++ b/examples/neon-cloudflare/readme.md @@ -1,4 +1,4 @@ -### Example project for [DrizzleORM](https://driz.li/orm) + [Cloudflare Worker](https://workers.cloudflare.com) + [Neon Serverless](https://github.com/neondatabase/serverless) +### Example project for [Drizzle ORM](https://driz.li/orm) + [Cloudflare Worker](https://workers.cloudflare.com) + [Neon Serverless](https://github.com/neondatabase/serverless) --- diff --git a/examples/pg-proxy/README.md b/examples/pg-proxy/README.md index d9ff24fb1..b47fcd5e3 100644 --- a/examples/pg-proxy/README.md +++ b/examples/pg-proxy/README.md @@ -30,7 +30,7 @@ This project has simple example of defining http proxy server, that will proxy a
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle always waits for `{rows: string[][] | object[]}` so if any error was on http call(or any other call) - be sure, that you return at least empty array back > > For `all` method you should return `{rows: string[][]}` @@ -72,7 +72,7 @@ In current Postgres Proxy version - drizzle don't handle transactions for migrat
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle just finds migrations, that need to be executed on this iteration and if finds some -> provide `queries` array to callback
@@ -97,7 +97,7 @@ await migrate(db, async (queries) => { --- -> **Note**: +> [!NOTE] > It's just a suggestion on how proxy server could be set up and a simple example of params handling on `query` and `migration` calls ```typescript diff --git a/examples/sqlite-proxy/README.md b/examples/sqlite-proxy/README.md index b187e35fb..d25cd7d8b 100644 --- a/examples/sqlite-proxy/README.md +++ b/examples/sqlite-proxy/README.md @@ -30,7 +30,7 @@ This project has simple example of defining http proxy server, that will proxy a
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle always waits for `{rows: string[][]}` so if any error was on http call(or any other call) - be sure, that you return at least empty array back > > For `get` method you should return `{rows: string[]}` @@ -71,7 +71,7 @@ In current SQLite Proxy version - drizzle don't handle transactions for migratio
-> **Warning**: +> [!WARNING] > You will be responsible for proper error handling in this part. Drizzle just finds migrations, that need to be executed on this iteration and if finds some -> provide `queries` array to callback
@@ -96,7 +96,7 @@ await migrate(db, async (queries) => { --- -> **Note**: +> [!NOTE] > It's just a suggestion on how proxy server could be set up and a simple example of params handling on `query` and `migration` calls ```typescript diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 5dde42934..e2695d767 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3416,7 +3416,7 @@ export function tests(driver?: string) { expect(query).toEqual({ sql: - `select \`id\`, \`name\` from \`mySchema\`.\`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + `select \`id\`, \`name\` from \`mySchema\`.\`userstest\` group by \`mySchema\`.\`userstest\`.\`id\`, \`mySchema\`.\`userstest\`.\`name\``, params: [], }); }); @@ -3506,6 +3506,23 @@ export function tests(driver?: string) { expect(result).toStrictEqual([{ id: 1 }]); }); + test('insert $returningId: serial as id, not first column', async (ctx) => { + const { db } = ctx.mysql; + + const usersTableDefNotFirstColumn = mysqlTable('users2', { + name: text('name').notNull(), + id: serial('id').primaryKey(), + }); + + const result = await db.insert(usersTableDefNotFirstColumn).values({ name: 'John' }).$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + id: number; + }[]>(); + + expect(result).toStrictEqual([{ id: 1 }]); + }); + test('insert $returningId: serial as id, batch insert', async (ctx) => { const { db } = ctx.mysql; diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index c7f4b9be7..dd2971c3c 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4278,7 +4278,7 @@ export function tests() { .toSQL(); expect(query).toEqual({ - sql: 'select "id", "name" from "mySchema"."users" group by "users"."id", "users"."name"', + sql: 'select "id", "name" from "mySchema"."users" group by "mySchema"."users"."id", "mySchema"."users"."name"', params: [], }); }); diff --git a/package.json b/package.json index 29189a91b..d52a568a6 100755 --- a/package.json +++ b/package.json @@ -1,4 +1,5 @@ { + "name": "drizzle-root", "private": true, "scripts": { "build:orm": "turbo run build --filter drizzle-orm --color", @@ -34,7 +35,7 @@ "resolve-tspaths": "^0.8.16", "tsup": "^7.2.0", "tsx": "^4.10.5", - "turbo": "^1.10.14", + "turbo": "^2.2.3", "typescript": "5.6.3" }, "packageManager": "pnpm@9.7.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 468f12ca6..759aad057 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,7 +40,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -73,13 +73,13 @@ importers: version: 0.8.16(typescript@5.6.3) tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3))(typescript@5.6.3) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3) tsx: specifier: ^4.10.5 version: 4.10.5 turbo: - specifier: ^1.10.14 - version: 1.10.14 + specifier: ^2.2.3 + version: 2.2.3 typescript: specifier: 5.6.3 version: 5.6.3 @@ -370,8 +370,8 @@ importers: specifier: ^10.1.0 version: 10.1.0 expo-sqlite: - specifier: ^13.2.0 - version: 13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + specifier: ^14.0.0 + version: 14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -6127,8 +6127,8 @@ packages: expo-modules-core@1.12.11: resolution: {integrity: sha512-CF5G6hZo/6uIUz6tj4dNRlvE5L4lakYukXPqz5ZHQ+6fLk1NQVZbRdpHjMkxO/QSBQcKUzG/ngeytpoJus7poQ==} - expo-sqlite@13.4.0: - resolution: {integrity: sha512-5f7d2EDM+pgerM33KndtX4gWw2nuVaXY68nnqx7PhkiYeyEmeNfZ29bIFtpBzNb/L5l0/DTtRxuSqftxbknFtw==} + expo-sqlite@14.0.6: + resolution: {integrity: sha512-T3YNx7LT7lM4UQRgi8ml+cj0Wf3Ep09+B4CVaWtUCjdyYJIZjsHDT65hypKG+r6btTLLEd11hjlrstNQhzt5gQ==} peerDependencies: expo: '*' @@ -7184,12 +7184,10 @@ packages: libsql@0.3.19: resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] libsql@0.4.1: resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -9491,38 +9489,38 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - turbo-darwin-64@1.10.14: - resolution: {integrity: sha512-I8RtFk1b9UILAExPdG/XRgGQz95nmXPE7OiGb6ytjtNIR5/UZBS/xVX/7HYpCdmfriKdVwBKhalCoV4oDvAGEg==} + turbo-darwin-64@2.2.3: + resolution: {integrity: sha512-Rcm10CuMKQGcdIBS3R/9PMeuYnv6beYIHqfZFeKWVYEWH69sauj4INs83zKMTUiZJ3/hWGZ4jet9AOwhsssLyg==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@1.10.14: - resolution: {integrity: sha512-KAdUWryJi/XX7OD0alOuOa0aJ5TLyd4DNIYkHPHYcM6/d7YAovYvxRNwmx9iv6Vx6IkzTnLeTiUB8zy69QkG9Q==} + turbo-darwin-arm64@2.2.3: + resolution: {integrity: sha512-+EIMHkuLFqUdJYsA3roj66t9+9IciCajgj+DVek+QezEdOJKcRxlvDOS2BUaeN8kEzVSsNiAGnoysFWYw4K0HA==} cpu: [arm64] os: [darwin] - turbo-linux-64@1.10.14: - resolution: {integrity: sha512-BOBzoREC2u4Vgpap/WDxM6wETVqVMRcM8OZw4hWzqCj2bqbQ6L0wxs1LCLWVrghQf93JBQtIGAdFFLyCSBXjWQ==} + turbo-linux-64@2.2.3: + resolution: {integrity: sha512-UBhJCYnqtaeOBQLmLo8BAisWbc9v9daL9G8upLR+XGj6vuN/Nz6qUAhverN4Pyej1g4Nt1BhROnj6GLOPYyqxQ==} cpu: [x64] os: [linux] - turbo-linux-arm64@1.10.14: - resolution: {integrity: sha512-D8T6XxoTdN5D4V5qE2VZG+/lbZX/89BkAEHzXcsSUTRjrwfMepT3d2z8aT6hxv4yu8EDdooZq/2Bn/vjMI32xw==} + turbo-linux-arm64@2.2.3: + resolution: {integrity: sha512-hJYT9dN06XCQ3jBka/EWvvAETnHRs3xuO/rb5bESmDfG+d9yQjeTMlhRXKrr4eyIMt6cLDt1LBfyi+6CQ+VAwQ==} cpu: [arm64] os: [linux] - turbo-windows-64@1.10.14: - resolution: {integrity: sha512-zKNS3c1w4i6432N0cexZ20r/aIhV62g69opUn82FLVs/zk3Ie0GVkSB6h0rqIvMalCp7enIR87LkPSDGz9K4UA==} + turbo-windows-64@2.2.3: + resolution: {integrity: sha512-NPrjacrZypMBF31b4HE4ROg4P3nhMBPHKS5WTpMwf7wydZ8uvdEHpESVNMOtqhlp857zbnKYgP+yJF30H3N2dQ==} cpu: [x64] os: [win32] - turbo-windows-arm64@1.10.14: - resolution: {integrity: sha512-rkBwrTPTxNSOUF7of8eVvvM+BkfkhA2OvpHM94if8tVsU+khrjglilp8MTVPHlyS9byfemPAmFN90oRIPB05BA==} + turbo-windows-arm64@2.2.3: + resolution: {integrity: sha512-fnNrYBCqn6zgKPKLHu4sOkihBI/+0oYFr075duRxqUZ+1aLWTAGfHZLgjVeLh3zR37CVzuerGIPWAEkNhkWEIw==} cpu: [arm64] os: [win32] - turbo@1.10.14: - resolution: {integrity: sha512-hr9wDNYcsee+vLkCDIm8qTtwhJ6+UAMJc3nIY6+PNgUTtXcQgHxCq8BGoL7gbABvNWv76CNbK5qL4Lp9G3ZYRA==} + turbo@2.2.3: + resolution: {integrity: sha512-5lDvSqIxCYJ/BAd6rQGK/AzFRhBkbu4JHVMLmGh/hCb7U3CqSnr5Tjwfy9vc+/5wG2DJ6wttgAaA7MoCgvBKZQ==} hasBin: true tweetnacl@0.14.5: @@ -10271,7 +10269,7 @@ snapshots: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/client-sts': 3.569.0 '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10412,7 +10410,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/client-sts': 3.569.0 '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10672,7 +10670,7 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)': + '@aws-sdk/client-sts@3.569.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 @@ -10714,6 +10712,51 @@ snapshots: '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.569.0 + '@aws-sdk/core': 3.567.0 + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/middleware-host-header': 3.567.0 + '@aws-sdk/middleware-logger': 3.568.0 + '@aws-sdk/middleware-recursion-detection': 3.567.0 + '@aws-sdk/middleware-user-agent': 3.567.0 + '@aws-sdk/region-config-resolver': 3.567.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@aws-sdk/util-user-agent-browser': 3.567.0 + '@aws-sdk/util-user-agent-node': 3.568.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.6.2 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -10862,6 +10905,23 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + dependencies: + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-env': 3.568.0 + '@aws-sdk/credential-provider-process': 3.568.0 + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/types': 3.567.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) @@ -10885,7 +10945,7 @@ snapshots: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10929,6 +10989,25 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + dependencies: + '@aws-sdk/credential-provider-env': 3.568.0 + '@aws-sdk/credential-provider-http': 3.568.0 + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-process': 3.568.0 + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/types': 3.567.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 @@ -10955,7 +11034,7 @@ snapshots: '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -11068,7 +11147,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': + '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/types': 3.567.0 @@ -11076,6 +11155,14 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 + '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': + dependencies: + '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.6.2 + '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-sdk/client-sts': 3.583.0 @@ -11096,7 +11183,7 @@ snapshots: '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -16432,7 +16519,7 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 '@cloudflare/workers-types': 4.20241004.0 @@ -17315,7 +17402,7 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@13.4.0(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-sqlite@14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/websql': 1.0.1 expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) @@ -19652,7 +19739,7 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3)): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)): dependencies: lilconfig: 2.1.0 yaml: 2.3.1 @@ -20923,7 +21010,7 @@ snapshots: tslib@2.6.2: {} - tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3))(typescript@5.6.3): + tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3): dependencies: bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 @@ -20933,7 +21020,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3)) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)) resolve-from: 5.0.0 rollup: 3.27.2 source-map: 0.8.0-beta.0 @@ -21003,32 +21090,32 @@ snapshots: dependencies: safe-buffer: 5.2.1 - turbo-darwin-64@1.10.14: + turbo-darwin-64@2.2.3: optional: true - turbo-darwin-arm64@1.10.14: + turbo-darwin-arm64@2.2.3: optional: true - turbo-linux-64@1.10.14: + turbo-linux-64@2.2.3: optional: true - turbo-linux-arm64@1.10.14: + turbo-linux-arm64@2.2.3: optional: true - turbo-windows-64@1.10.14: + turbo-windows-64@2.2.3: optional: true - turbo-windows-arm64@1.10.14: + turbo-windows-arm64@2.2.3: optional: true - turbo@1.10.14: + turbo@2.2.3: optionalDependencies: - turbo-darwin-64: 1.10.14 - turbo-darwin-arm64: 1.10.14 - turbo-linux-64: 1.10.14 - turbo-linux-arm64: 1.10.14 - turbo-windows-64: 1.10.14 - turbo-windows-arm64: 1.10.14 + turbo-darwin-64: 2.2.3 + turbo-darwin-arm64: 2.2.3 + turbo-linux-64: 2.2.3 + turbo-linux-arm64: 2.2.3 + turbo-windows-64: 2.2.3 + turbo-windows-arm64: 2.2.3 tweetnacl@0.14.5: {} diff --git a/turbo.json b/turbo.json index 3d07b1e88..e978069b2 100644 --- a/turbo.json +++ b/turbo.json @@ -1,12 +1,24 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "//#lint": { - "inputs": ["**/*.ts", "!**/node_modules", "!**/dist", "!**/dist-dts"], - "outputMode": "new-only" + "dependsOn": [ + "^test:types", + "drizzle-orm#build" + ], + "inputs": [ + "**/*.ts", + "!**/node_modules", + "!**/dist", + "!**/dist-dts" + ], + "outputLogs": "new-only" }, "test:types": { - "dependsOn": ["^test:types", "^build"], + "dependsOn": [ + "^test:types", + "drizzle-orm#build" + ], "inputs": [ "src/**/*.ts", "tests/**/*.ts", @@ -14,10 +26,119 @@ "tests/tsconfig.json", "../tsconfig.json" ], - "outputMode": "new-only" + "outputLogs": "new-only" + }, + "drizzle-orm#build": { + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, + "drizzle-kit#build": { + "dependsOn": [ + "drizzle-orm#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, + "drizzle-zod#build": { + "dependsOn": [ + "drizzle-orm#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, + "drizzle-typebox#build": { + "dependsOn": [ + "drizzle-orm#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, + "drizzle-valibot#build": { + "dependsOn": [ + "drizzle-orm#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" }, - "build": { - "dependsOn": ["^build"], + "eslint-plugin-drizzle#build": { + "dependsOn": [ + "drizzle-orm#build" + ], "inputs": [ "src/**/*.ts", "package.json", @@ -30,23 +151,58 @@ "scripts/fix-imports.ts", "../tsconfig.json" ], - "outputs": ["dist/**", "dist-dts/**"], - "outputMode": "new-only" + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, + "integration-tests#build": { + "dependsOn": [ + "drizzle-orm#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" }, "pack": { - "dependsOn": ["build", "test:types"], - "inputs": ["dist/**"], - "outputs": ["package.tgz"], - "outputMode": "new-only" + "dependsOn": [ + "build", + "test:types" + ], + "inputs": [ + "dist/**" + ], + "outputs": [ + "package.tgz" + ], + "outputLogs": "new-only" }, "test": { - "dependsOn": ["build", "test:types"], + "dependsOn": [ + "build", + "test:types" + ], "inputs": [ "tests/**/*.test.ts", "tests/**/*.test.cjs", "tests/**/*.test.mjs" ], - "outputMode": "new-only" + "outputLogs": "new-only" } } } From 89628d8679b3995b73bb79e488530c0f2fce3637 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Thu, 14 Nov 2024 16:25:22 +0200 Subject: [PATCH 359/492] fixes --- drizzle-orm/src/column-builder.ts | 1 - drizzle-orm/src/operations.ts | 15 +------------ drizzle-orm/src/pg-core/columns/common.ts | 2 -- drizzle-seed/src/index.ts | 1 + drizzle-seed/src/services/SeedService.ts | 15 ++++++++++--- drizzle-seed/src/tests/pg/pg.test.ts | 18 ++++++++++++++++ drizzle-seed/src/tests/pg/pgSchema.ts | 6 ++++++ drizzle-seed/src/types/seedService.ts | 1 + drizzle-seed/src/types/tables.ts | 1 + integration-tests/package.json | 1 + integration-tests/tests/pg/pg-common.ts | 20 ++++++++--------- integration-tests/tests/seeder/pg.test.ts | 8 +++++++ integration-tests/tests/seeder/pgSchema.ts | 6 ++++++ package.json | 1 - pnpm-lock.yaml | 6 +++--- turbo.json | 25 +++++++++++++++++++++- 16 files changed, 92 insertions(+), 35 deletions(-) diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index 4e825187e..f621343d9 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -107,7 +107,6 @@ export type ColumnBuilderRuntimeConfig | undefined; generatedIdentity: GeneratedIdentityConfig | undefined; - identity: 'always' | 'byDefault' | undefined; } & TRuntimeConfig; export interface ColumnBuilderExtraConfig { diff --git a/drizzle-orm/src/operations.ts b/drizzle-orm/src/operations.ts index d8afe4078..5f7704fd6 100644 --- a/drizzle-orm/src/operations.ts +++ b/drizzle-orm/src/operations.ts @@ -8,7 +8,6 @@ export type RequiredKeyOnly = T extends A }> ? TKey : never; - export type OptionalKeyOnly< TKey extends string, T extends Column, @@ -17,25 +16,13 @@ export type OptionalKeyOnly< : T extends { _: { generated: undefined; - } + }; } ? ( T['_']['identity'] extends 'always' ? OverrideT extends true ? TKey : never : TKey ) : never; -export type IdentityColumns< - TKey extends string, - T extends Column, - OverrideT extends boolean | undefined = false, -> = TKey extends RequiredKeyOnly ? never - : TKey extends OptionalKeyOnly ? never - : T['_']['identity'] extends 'byDefault' ? TKey - : ( - T['_']['identity'] extends 'always' ? OverrideT extends true ? TKey : never - : never - ); - // TODO: SQL -> SQLWrapper export type SelectedFieldsFlat = Record< string, diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index de2267cf3..d9384b344 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -4,7 +4,6 @@ import type { ColumnBuilderExtraConfig, ColumnBuilderRuntimeConfig, ColumnDataType, - GeneratedColumnConfig, HasGenerated, MakeColumnConfig, } from '~/column-builder.ts'; @@ -56,7 +55,6 @@ export abstract class PgColumnBuilder< data: T['data'][]; driverParam: T['driverParam'][] | string; enumValues: T['enumValues']; - generated: GeneratedColumnConfig; } & (T extends { notNull: true } ? { notNull: true } : {}) & (T extends { hasDefault: true } ? { hasDefault: true } : {}), diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index e3a22c427..545b9295d 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -635,6 +635,7 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { enumValues: column.enumValues, isUnique: column.isUnique, notNull: column.notNull, + generatedIdentityType: column.generatedIdentity?.type, })), primaryKeys: tableConfig.columns .filter((column) => column.primary) diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index b8f8bbd73..c023e7d5f 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -181,6 +181,7 @@ class SeedService { columnName: col.name, isUnique: col.isUnique, notNull: col.notNull, + generatedIdentityType: col.generatedIdentityType, generator: undefined, }; @@ -1055,10 +1056,12 @@ class SeedService { // console.time("initiate generators"); let columnsNumber = 0; + let override = false; // console.log("before init") for (const columnName of Object.keys(tableGenerators)) { columnsNumber += 1; columnGenerator = tableGenerators[columnName]!; + override = tableGenerators[columnName]?.generatedIdentityType === 'always' ? true : override; // columnsGenerators[columnName] = columnGenerator.generator!.execute({ // count, @@ -1153,6 +1156,7 @@ class SeedService { [key: string]: PgTable | MySqlTable | SQLiteTable; }, tableName: tableName as string, + override, }); generatedValues = []; } else { @@ -1171,6 +1175,7 @@ class SeedService { [key: string]: PgTable | MySqlTable | SQLiteTable; }, tableName: tableName as string, + override, }); } } @@ -1191,6 +1196,7 @@ class SeedService { db, schema, tableName, + override, }: { generatedValues: { [columnName: string]: number | string | boolean | undefined; @@ -1203,13 +1209,16 @@ class SeedService { [key: string]: PgTable | MySqlTable | SQLiteTable; }; tableName: string; + override: boolean; }) => { // console.log(tableName, generatedValues); if (is(db, PgDatabase)) { // console.log("table to insert data:", tableName, ";columns in table:", Object.keys(generatedValues[0]!).length, ";rows to insert:", generatedValues, ";overall parameters:", generatedValues.length * Object.keys(generatedValues[0]!).length); - await db - .insert((schema as { [key: string]: PgTable })[tableName]!) - .values(generatedValues); + const query = db.insert((schema as { [key: string]: PgTable })[tableName]!); + if (override === true) { + return await query.overridingSystemValue().values(generatedValues); + } + await query.values(generatedValues); } else if (is(db, MySqlDatabase)) { // console.log("table to insert data:", tableName, ";columns in table:", Object.keys(generatedValues[0]).length, ";rows to insert:", generatedValues, ";overall parameters:", generatedValues.length * Object.keys(generatedValues[0]).length); await db diff --git a/drizzle-seed/src/tests/pg/pg.test.ts b/drizzle-seed/src/tests/pg/pg.test.ts index 9aadf28c2..bd9ec7504 100644 --- a/drizzle-seed/src/tests/pg/pg.test.ts +++ b/drizzle-seed/src/tests/pg/pg.test.ts @@ -180,6 +180,16 @@ beforeAll(async () => { END $$; `, ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."identity_columns_table" ( + "id" integer generated always as identity, + "id1" integer generated by default as identity, + "name" text + ); + `, + ); }); afterEach(async () => { @@ -343,3 +353,11 @@ test("sequential using of 'with'", async () => { expect(products.length).toBe(11); expect(suppliers.length).toBe(11); }); + +test('seeding with identity columns', async () => { + await seed(db, { identityColumnsTable: schema.identityColumnsTable }); + + const result = await db.select().from(schema.identityColumnsTable); + + expect(result.length).toBe(10); +}); diff --git a/drizzle-seed/src/tests/pg/pgSchema.ts b/drizzle-seed/src/tests/pg/pgSchema.ts index fdf42f89b..2c1c95045 100644 --- a/drizzle-seed/src/tests/pg/pgSchema.ts +++ b/drizzle-seed/src/tests/pg/pgSchema.ts @@ -128,3 +128,9 @@ export const details = schema.table('order_detail', { .notNull() .references(() => products.id, { onDelete: 'cascade' }), }); + +export const identityColumnsTable = schema.table('identity_columns_table', { + id: integer().generatedAlwaysAsIdentity(), + id1: integer().generatedByDefaultAsIdentity(), + name: text(), +}); diff --git a/drizzle-seed/src/types/seedService.ts b/drizzle-seed/src/types/seedService.ts index 3244a0a12..2490d5e26 100644 --- a/drizzle-seed/src/types/seedService.ts +++ b/drizzle-seed/src/types/seedService.ts @@ -16,6 +16,7 @@ export type GeneratePossibleGeneratorsColumnType = { generator: AbstractGenerator | undefined; isUnique: boolean; notNull: boolean; + generatedIdentityType?: 'always' | 'byDefault' | undefined; }; export type GeneratePossibleGeneratorsTableType = Prettify<{ diff --git a/drizzle-seed/src/types/tables.ts b/drizzle-seed/src/types/tables.ts index 206d94be5..637e96c48 100644 --- a/drizzle-seed/src/types/tables.ts +++ b/drizzle-seed/src/types/tables.ts @@ -9,6 +9,7 @@ export type Column = { enumValues?: string[]; isUnique: boolean; notNull: boolean; + generatedIdentityType?: 'always' | 'byDefault' | undefined; }; export type Table = { diff --git a/integration-tests/package.json b/integration-tests/package.json index 776deb153..389001d8b 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -61,6 +61,7 @@ "drizzle-typebox": "workspace:../drizzle-typebox/dist", "drizzle-valibot": "workspace:../drizzle-valibot/dist", "drizzle-zod": "workspace:../drizzle-zod/dist", + "drizzle-seed": "workspace:../drizzle-seed/dist", "express": "^4.18.2", "get-port": "^7.0.0", "mysql2": "^3.3.3", diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 7ea1a586d..06622aae7 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -5068,19 +5068,19 @@ export function tests() { test('insert multiple rows into table with generated identity column', async (ctx) => { const { db } = ctx.pg; - const users = pgTable('users', { + const identityColumnsTable = pgTable('identity_columns_table', { id: integer('id').generatedAlwaysAsIdentity(), id1: integer('id1').generatedByDefaultAsIdentity(), name: text('name').notNull(), }); // not passing identity columns - await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop table if exists ${identityColumnsTable}`); await db.execute( - sql`create table ${users} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, + sql`create table ${identityColumnsTable} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, ); - let result = await db.insert(users).values([ + let result = await db.insert(identityColumnsTable).values([ { name: 'John' }, { name: 'Jane' }, { name: 'Bob' }, @@ -5093,12 +5093,12 @@ export function tests() { ]); // passing generated by default as identity column - await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop table if exists ${identityColumnsTable}`); await db.execute( - sql`create table ${users} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, + sql`create table ${identityColumnsTable} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, ); - result = await db.insert(users).values([ + result = await db.insert(identityColumnsTable).values([ { name: 'John', id1: 3 }, { name: 'Jane', id1: 5 }, { name: 'Bob', id1: 5 }, @@ -5111,12 +5111,12 @@ export function tests() { ]); // passing all identity columns - await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop table if exists ${identityColumnsTable}`); await db.execute( - sql`create table ${users} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, + sql`create table ${identityColumnsTable} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, ); - result = await db.insert(users).overridingSystemValue().values([ + result = await db.insert(identityColumnsTable).overridingSystemValue().values([ { name: 'John', id: 2, id1: 3 }, { name: 'Jane', id: 4, id1: 5 }, { name: 'Bob', id: 4, id1: 5 }, diff --git a/integration-tests/tests/seeder/pg.test.ts b/integration-tests/tests/seeder/pg.test.ts index d9cbca2e5..f0bce90df 100644 --- a/integration-tests/tests/seeder/pg.test.ts +++ b/integration-tests/tests/seeder/pg.test.ts @@ -785,6 +785,14 @@ test("sequential using of 'with'", async () => { expect(suppliers.length).toBe(11); }); +test('seeding with identity columns', async () => { + await seed(db, { identityColumnsTable: schema.identityColumnsTable }); + + const result = await db.select().from(schema.identityColumnsTable); + + expect(result.length).toBe(10); +}); + // All data types test ------------------------------- test('basic seed test for all postgres data types', async () => { await seed(db, { allDataTypes: schema.allDataTypes }, { count: 10000 }); diff --git a/integration-tests/tests/seeder/pgSchema.ts b/integration-tests/tests/seeder/pgSchema.ts index ffb2e9783..ef5c4943a 100644 --- a/integration-tests/tests/seeder/pgSchema.ts +++ b/integration-tests/tests/seeder/pgSchema.ts @@ -349,3 +349,9 @@ export const weightedRandomTable = schema.table('weighted_random_table', { export const weightedRandomWithUniqueGensTable = schema.table('weighted_random_with_unique_gens_table', { weightedRandomWithUniqueGens: varchar('weighted_random_with_unique_gens', { length: 256 }).unique(), }); + +export const identityColumnsTable = schema.table('identity_columns_table', { + id: integer('id').generatedAlwaysAsIdentity(), + id1: integer('id1'), + name: text('name'), +}); diff --git a/package.json b/package.json index f2290d7ad..d52a568a6 100755 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ "drizzle-kit": "^0.19.13", "drizzle-orm": "workspace:./drizzle-orm/dist", "drizzle-orm-old": "npm:drizzle-orm@^0.27.2", - "drizzle-seed": "workspace:./drizzle-seed/dist", "eslint": "^8.50.0", "eslint-plugin-drizzle-internal": "link:eslint/eslint-plugin-drizzle-internal", "eslint-plugin-import": "^2.28.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f71483e1..f13c32c4b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,9 +41,6 @@ importers: drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.687.0)(@cloudflare/workers-types@4.20241106.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.5)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.10)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.1.34)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.3.3)(pg@8.13.1)(postgres@3.4.5)(sql.js@1.12.0)(sqlite3@5.1.7) - drizzle-seed: - specifier: workspace:./drizzle-seed/dist - version: link:drizzle-seed/dist eslint: specifier: ^8.50.0 version: 8.57.1 @@ -691,6 +688,9 @@ importers: drizzle-prisma-generator: specifier: ^0.1.2 version: 0.1.7 + drizzle-seed: + specifier: workspace:../drizzle-seed/dist + version: link:../drizzle-seed/dist drizzle-typebox: specifier: workspace:../drizzle-typebox/dist version: link:../drizzle-typebox/dist diff --git a/turbo.json b/turbo.json index e978069b2..bd576fb44 100644 --- a/turbo.json +++ b/turbo.json @@ -157,7 +157,7 @@ ], "outputLogs": "new-only" }, - "integration-tests#build": { + "drizzle-seed#build": { "dependsOn": [ "drizzle-orm#build" ], @@ -179,6 +179,29 @@ ], "outputLogs": "new-only" }, + "integration-tests#build": { + "dependsOn": [ + "drizzle-orm#build", + "drizzle-seed#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, "pack": { "dependsOn": [ "build", From 143653cef0dcf9da4a46e6bb9a0d30223e098d6d Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 14 Nov 2024 16:30:32 +0200 Subject: [PATCH 360/492] Fix test:types --- turbo.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/turbo.json b/turbo.json index bd576fb44..6af34fa47 100644 --- a/turbo.json +++ b/turbo.json @@ -17,7 +17,8 @@ "test:types": { "dependsOn": [ "^test:types", - "drizzle-orm#build" + "drizzle-orm#build", + "drizzle-seed#build" ], "inputs": [ "src/**/*.ts", From d7e3535a9083f31dd1fd0028adfcc2b12f48d954 Mon Sep 17 00:00:00 2001 From: L-Mario564 Date: Thu, 14 Nov 2024 07:42:56 -0800 Subject: [PATCH 361/492] Support `update ... from` (Pg | SQLite) (#2963) * Implement `update ... from` in PG * Add `update ... from` in SQLite * Lint and format * Fix type error * Fix SQLite type errors * Lint and format * Push merge changes --- drizzle-orm/src/pg-core/dialect.ts | 134 ++++---- .../src/pg-core/query-builders/select.ts | 4 +- .../pg-core/query-builders/select.types.ts | 6 +- .../src/pg-core/query-builders/update.ts | 304 +++++++++++++++++- drizzle-orm/src/sqlite-core/dialect.ts | 96 +++--- .../src/sqlite-core/query-builders/select.ts | 4 +- .../query-builders/select.types.ts | 6 +- .../src/sqlite-core/query-builders/update.ts | 131 +++++++- drizzle-orm/src/utils.ts | 4 +- drizzle-orm/type-tests/pg/update.ts | 192 ++++++++++- drizzle-orm/type-tests/sqlite/update.ts | 60 +++- integration-tests/tests/pg/pg-common.ts | 169 ++++++++++ .../tests/sqlite/sqlite-common.ts | 179 +++++++++++ 13 files changed, 1152 insertions(+), 137 deletions(-) diff --git a/drizzle-orm/src/pg-core/dialect.ts b/drizzle-orm/src/pg-core/dialect.ts index bc3d4cf52..173cb88b2 100644 --- a/drizzle-orm/src/pg-core/dialect.ts +++ b/drizzle-orm/src/pg-core/dialect.ts @@ -169,18 +169,30 @@ export class PgDialect { })); } - buildUpdateQuery({ table, set, where, returning, withList }: PgUpdateConfig): SQL { + buildUpdateQuery({ table, set, where, returning, withList, from, joins }: PgUpdateConfig): SQL { const withSql = this.buildWithCTE(withList); + const tableName = table[PgTable.Symbol.Name]; + const tableSchema = table[PgTable.Symbol.Schema]; + const origTableName = table[PgTable.Symbol.OriginalName]; + const alias = tableName === origTableName ? undefined : tableName; + const tableSql = sql`${tableSchema ? sql`${sql.identifier(tableSchema)}.` : undefined}${ + sql.identifier(origTableName) + }${alias && sql` ${sql.identifier(alias)}`}`; + const setSql = this.buildUpdateSet(table, set); + const fromSql = from && sql.join([sql.raw(' from '), this.buildFromTable(from)]); + + const joinsSql = this.buildJoins(joins); + const returningSql = returning - ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` + ? sql` returning ${this.buildSelection(returning, { isSingleTable: !from })}` : undefined; const whereSql = where ? sql` where ${where}` : undefined; - return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}`; + return sql`${withSql}update ${tableSql} set ${setSql}${fromSql}${joinsSql}${whereSql}${returningSql}`; } /** @@ -245,6 +257,67 @@ export class PgDialect { return sql.join(chunks); } + private buildJoins(joins: PgSelectJoinConfig[] | undefined): SQL | undefined { + if (!joins || joins.length === 0) { + return undefined; + } + + const joinsArray: SQL[] = []; + + for (const [index, joinMeta] of joins.entries()) { + if (index === 0) { + joinsArray.push(sql` `); + } + const table = joinMeta.table; + const lateralSql = joinMeta.lateral ? sql` lateral` : undefined; + + if (is(table, PgTable)) { + const tableName = table[PgTable.Symbol.Name]; + const tableSchema = table[PgTable.Symbol.Schema]; + const origTableName = table[PgTable.Symbol.OriginalName]; + const alias = tableName === origTableName ? undefined : joinMeta.alias; + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ + tableSchema ? sql`${sql.identifier(tableSchema)}.` : undefined + }${sql.identifier(origTableName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + ); + } else if (is(table, View)) { + const viewName = table[ViewBaseConfig].name; + const viewSchema = table[ViewBaseConfig].schema; + const origViewName = table[ViewBaseConfig].originalName; + const alias = viewName === origViewName ? undefined : joinMeta.alias; + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ + viewSchema ? sql`${sql.identifier(viewSchema)}.` : undefined + }${sql.identifier(origViewName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + ); + } else { + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${table} on ${joinMeta.on}`, + ); + } + if (index < joins.length - 1) { + joinsArray.push(sql` `); + } + } + + return sql.join(joinsArray); + } + + private buildFromTable( + table: SQL | Subquery | PgViewBase | PgTable | undefined, + ): SQL | Subquery | PgViewBase | PgTable | undefined { + if (is(table, Table) && table[Table.Symbol.OriginalName] !== table[Table.Symbol.Name]) { + let fullName = sql`${sql.identifier(table[Table.Symbol.OriginalName])}`; + if (table[Table.Symbol.Schema]) { + fullName = sql`${sql.identifier(table[Table.Symbol.Schema]!)}.${fullName}`; + } + return sql`${fullName} ${sql.identifier(table[Table.Symbol.Name])}`; + } + + return table; + } + buildSelectQuery( { withList, @@ -300,60 +373,9 @@ export class PgDialect { const selection = this.buildSelection(fieldsList, { isSingleTable }); - const tableSql = (() => { - if (is(table, Table) && table[Table.Symbol.OriginalName] !== table[Table.Symbol.Name]) { - let fullName = sql`${sql.identifier(table[Table.Symbol.OriginalName])}`; - if (table[Table.Symbol.Schema]) { - fullName = sql`${sql.identifier(table[Table.Symbol.Schema]!)}.${fullName}`; - } - return sql`${fullName} ${sql.identifier(table[Table.Symbol.Name])}`; - } - - return table; - })(); - - const joinsArray: SQL[] = []; - - if (joins) { - for (const [index, joinMeta] of joins.entries()) { - if (index === 0) { - joinsArray.push(sql` `); - } - const table = joinMeta.table; - const lateralSql = joinMeta.lateral ? sql` lateral` : undefined; - - if (is(table, PgTable)) { - const tableName = table[PgTable.Symbol.Name]; - const tableSchema = table[PgTable.Symbol.Schema]; - const origTableName = table[PgTable.Symbol.OriginalName]; - const alias = tableName === origTableName ? undefined : joinMeta.alias; - joinsArray.push( - sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ - tableSchema ? sql`${sql.identifier(tableSchema)}.` : undefined - }${sql.identifier(origTableName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, - ); - } else if (is(table, View)) { - const viewName = table[ViewBaseConfig].name; - const viewSchema = table[ViewBaseConfig].schema; - const origViewName = table[ViewBaseConfig].originalName; - const alias = viewName === origViewName ? undefined : joinMeta.alias; - joinsArray.push( - sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ - viewSchema ? sql`${sql.identifier(viewSchema)}.` : undefined - }${sql.identifier(origViewName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, - ); - } else { - joinsArray.push( - sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${table} on ${joinMeta.on}`, - ); - } - if (index < joins.length - 1) { - joinsArray.push(sql` `); - } - } - } + const tableSql = this.buildFromTable(table); - const joinsSql = sql.join(joinsArray); + const joinsSql = this.buildJoins(joins); const whereSql = where ? sql` where ${where}` : undefined; diff --git a/drizzle-orm/src/pg-core/query-builders/select.ts b/drizzle-orm/src/pg-core/query-builders/select.ts index 6e9a961c0..0fbc85fa6 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.ts @@ -34,11 +34,11 @@ import type { LockConfig, LockStrength, PgCreateSetOperatorFn, - PgJoinFn, PgSelectConfig, PgSelectDynamic, PgSelectHKT, PgSelectHKTBase, + PgSelectJoinFn, PgSelectPrepare, PgSelectWithout, PgSetOperatorExcludedMethods, @@ -194,7 +194,7 @@ export abstract class PgSelectQueryBuilderBase< private createJoin( joinType: TJoinType, - ): PgJoinFn { + ): PgSelectJoinFn { return ( table: PgTable | Subquery | PgViewBase | SQL, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, diff --git a/drizzle-orm/src/pg-core/query-builders/select.types.ts b/drizzle-orm/src/pg-core/query-builders/select.types.ts index 005a2d924..9c5a538aa 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.types.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.types.ts @@ -79,7 +79,7 @@ export interface PgSelectConfig { }[]; } -export type PgJoin< +export type PgSelectJoin< T extends AnyPgSelectQueryBuilder, TDynamic extends boolean, TJoinType extends JoinType, @@ -108,7 +108,7 @@ export type PgJoin< > : never; -export type PgJoinFn< +export type PgSelectJoinFn< T extends AnyPgSelectQueryBuilder, TDynamic extends boolean, TJoinType extends JoinType, @@ -118,7 +118,7 @@ export type PgJoinFn< >( table: TJoinedTable, on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, -) => PgJoin; +) => PgSelectJoin; export type SelectedFieldsFlat = SelectedFieldsFlatBase; diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index 2c63dacc0..12e076d97 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -1,5 +1,5 @@ import type { GetColumnData } from '~/column.ts'; -import { entityKind } from '~/entity.ts'; +import { entityKind, is } from '~/entity.ts'; import type { PgDialect } from '~/pg-core/dialect.ts'; import type { PgPreparedQuery, @@ -8,21 +8,35 @@ import type { PgSession, PreparedQueryConfig, } from '~/pg-core/session.ts'; -import type { PgTable } from '~/pg-core/table.ts'; -import type { SelectResultFields } from '~/query-builders/select.types.ts'; +import { PgTable } from '~/pg-core/table.ts'; +import type { + AppendToNullabilityMap, + AppendToResult, + GetSelectTableName, + GetSelectTableSelection, + JoinNullability, + JoinType, + SelectMode, + SelectResult, +} from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; -import type { Subquery } from '~/subquery.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import { type ColumnsSelection, type Query, SQL, type SQLWrapper } from '~/sql/sql.ts'; +import { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; -import { mapUpdateSet, orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { type Assume, getTableLikeName, mapUpdateSet, orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; import type { PgColumn } from '../columns/common.ts'; -import type { SelectedFields, SelectedFieldsOrdered } from './select.types.ts'; +import type { PgViewBase } from '../view-base.ts'; +import type { PgSelectJoinConfig, SelectedFields, SelectedFieldsOrdered } from './select.types.ts'; export interface PgUpdateConfig { where?: SQL | undefined; set: UpdateSet; table: PgTable; + from?: PgTable | Subquery | PgViewBase | SQL; + joins: PgSelectJoinConfig[]; returning?: SelectedFieldsOrdered; withList?: Subquery[]; } @@ -31,7 +45,8 @@ export type PgUpdateSetSource = & { [Key in keyof TTable['$inferInsert']]?: | GetColumnData - | SQL; + | SQL + | PgColumn; } & {}; @@ -49,7 +64,9 @@ export class PgUpdateBuilder): PgUpdateBase { + set( + values: PgUpdateSetSource, + ): PgUpdateWithout, false, 'leftJoin' | 'rightJoin' | 'innerJoin' | 'fullJoin'> { return new PgUpdateBase( this.table, mapUpdateSet(this.table, values), @@ -68,18 +85,123 @@ export type PgUpdateWithout< PgUpdateBase< T['_']['table'], T['_']['queryResult'], + T['_']['from'], T['_']['returning'], + T['_']['nullabilityMap'], + T['_']['joins'], TDynamic, T['_']['excludedMethods'] | K >, T['_']['excludedMethods'] | K >; +export type PgUpdateWithJoins< + T extends AnyPgUpdate, + TDynamic extends boolean, + TFrom extends PgTable | Subquery | PgViewBase | SQL, +> = TDynamic extends true ? T : Omit< + PgUpdateBase< + T['_']['table'], + T['_']['queryResult'], + TFrom, + T['_']['returning'], + AppendToNullabilityMap, 'inner'>, + [...T['_']['joins'], { + name: GetSelectTableName; + joinType: 'inner'; + table: TFrom; + }], + TDynamic, + Exclude + >, + Exclude +>; + +export type PgUpdateJoinFn< + T extends AnyPgUpdate, + TDynamic extends boolean, + TJoinType extends JoinType, +> = < + TJoinedTable extends PgTable | Subquery | PgViewBase | SQL, +>( + table: TJoinedTable, + on: + | ( + ( + updateTable: T['_']['table']['_']['columns'], + from: T['_']['from'] extends PgTable ? T['_']['from']['_']['columns'] + : T['_']['from'] extends Subquery | PgViewBase ? T['_']['from']['_']['selectedFields'] + : never, + ) => SQL | undefined + ) + | SQL + | undefined, +) => PgUpdateJoin; + +export type PgUpdateJoin< + T extends AnyPgUpdate, + TDynamic extends boolean, + TJoinType extends JoinType, + TJoinedTable extends PgTable | Subquery | PgViewBase | SQL, +> = TDynamic extends true ? T : PgUpdateBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['from'], + T['_']['returning'], + AppendToNullabilityMap, TJoinType>, + [...T['_']['joins'], { + name: GetSelectTableName; + joinType: TJoinType; + table: TJoinedTable; + }], + TDynamic, + T['_']['excludedMethods'] +>; + +type Join = { + name: string | undefined; + joinType: JoinType; + table: PgTable | Subquery | PgViewBase | SQL; +}; + +type AccumulateToResult< + T extends AnyPgUpdate, + TSelectMode extends SelectMode, + TJoins extends Join[], + TSelectedFields extends ColumnsSelection, +> = TJoins extends [infer TJoin extends Join, ...infer TRest extends Join[]] ? AccumulateToResult< + T, + TSelectMode extends 'partial' ? TSelectMode : 'multiple', + TRest, + AppendToResult< + T['_']['table']['_']['name'], + TSelectedFields, + TJoin['name'], + TJoin['table'] extends Table ? TJoin['table']['_']['columns'] + : TJoin['table'] extends Subquery ? Assume + : never, + TSelectMode extends 'partial' ? TSelectMode : 'multiple' + > + > + : TSelectedFields; + export type PgUpdateReturningAll = PgUpdateWithout< PgUpdateBase< T['_']['table'], T['_']['queryResult'], - T['_']['table']['$inferSelect'], + T['_']['from'], + SelectResult< + AccumulateToResult< + T, + 'single', + T['_']['joins'], + GetSelectTableSelection + >, + 'partial', + T['_']['nullabilityMap'] + >, + T['_']['nullabilityMap'], + T['_']['joins'], TDynamic, T['_']['excludedMethods'] >, @@ -95,7 +217,19 @@ export type PgUpdateReturning< PgUpdateBase< T['_']['table'], T['_']['queryResult'], - SelectResultFields, + T['_']['from'], + SelectResult< + AccumulateToResult< + T, + 'partial', + T['_']['joins'], + TSelectedFields + >, + 'partial', + T['_']['nullabilityMap'] + >, + T['_']['nullabilityMap'], + T['_']['joins'], TDynamic, T['_']['excludedMethods'] >, @@ -113,21 +247,29 @@ export type PgUpdatePrepare = PgPreparedQuery< export type PgUpdateDynamic = PgUpdate< T['_']['table'], T['_']['queryResult'], - T['_']['returning'] + T['_']['from'], + T['_']['returning'], + T['_']['nullabilityMap'] >; export type PgUpdate< TTable extends PgTable = PgTable, TQueryResult extends PgQueryResultHKT = PgQueryResultHKT, + TFrom extends PgTable | Subquery | PgViewBase | SQL | undefined = undefined, TReturning extends Record | undefined = Record | undefined, -> = PgUpdateBase; + TNullabilityMap extends Record = Record, + TJoins extends Join[] = [], +> = PgUpdateBase; -type AnyPgUpdate = PgUpdateBase; +export type AnyPgUpdate = PgUpdateBase; export interface PgUpdateBase< TTable extends PgTable, TQueryResult extends PgQueryResultHKT, + TFrom extends PgTable | Subquery | PgViewBase | SQL | undefined = undefined, TReturning extends Record | undefined = undefined, + TNullabilityMap extends Record = Record, + TJoins extends Join[] = [], TDynamic extends boolean = false, TExcludedMethods extends string = never, > extends @@ -138,7 +280,10 @@ export interface PgUpdateBase< readonly _: { readonly dialect: 'pg'; readonly table: TTable; + readonly joins: TJoins; + readonly nullabilityMap: TNullabilityMap; readonly queryResult: TQueryResult; + readonly from: TFrom; readonly returning: TReturning; readonly dynamic: TDynamic; readonly excludedMethods: TExcludedMethods; @@ -149,8 +294,13 @@ export interface PgUpdateBase< export class PgUpdateBase< TTable extends PgTable, TQueryResult extends PgQueryResultHKT, + TFrom extends PgTable | Subquery | PgViewBase | SQL | undefined = undefined, TReturning extends Record | undefined = undefined, // eslint-disable-next-line @typescript-eslint/no-unused-vars + TNullabilityMap extends Record = Record, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TJoins extends Join[] = [], + // eslint-disable-next-line @typescript-eslint/no-unused-vars TDynamic extends boolean = false, // eslint-disable-next-line @typescript-eslint/no-unused-vars TExcludedMethods extends string = never, @@ -162,6 +312,8 @@ export class PgUpdateBase< static override readonly [entityKind]: string = 'PgUpdate'; private config: PgUpdateConfig; + private tableName: string | undefined; + private joinsNotNullableMap: Record; constructor( table: TTable, @@ -171,9 +323,101 @@ export class PgUpdateBase< withList?: Subquery[], ) { super(); - this.config = { set, table, withList }; + this.config = { set, table, withList, joins: [] }; + this.tableName = getTableLikeName(table); + this.joinsNotNullableMap = typeof this.tableName === 'string' ? { [this.tableName]: true } : {}; + } + + from( + source: TFrom, + ): PgUpdateWithJoins { + const tableName = getTableLikeName(source); + if (typeof tableName === 'string') { + this.joinsNotNullableMap[tableName] = true; + } + this.config.from = source; + return this as any; + } + + private getTableLikeFields(table: PgTable | Subquery | PgViewBase): Record { + if (is(table, PgTable)) { + return table[Table.Symbol.Columns]; + } else if (is(table, Subquery)) { + return table._.selectedFields; + } + return table[ViewBaseConfig].selectedFields; + } + + private createJoin( + joinType: TJoinType, + ): PgUpdateJoinFn { + return (( + table: PgTable | Subquery | PgViewBase | SQL, + on: ((updateTable: TTable, from: TFrom) => SQL | undefined) | SQL | undefined, + ) => { + const tableName = getTableLikeName(table); + + if (typeof tableName === 'string' && this.config.joins.some((join) => join.alias === tableName)) { + throw new Error(`Alias "${tableName}" is already used in this query`); + } + + if (typeof on === 'function') { + const from = this.config.from && !is(this.config.from, SQL) + ? this.getTableLikeFields(this.config.from) + : undefined; + on = on( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as any, + from && new Proxy( + from, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as any, + ); + } + + this.config.joins.push({ on, table, joinType, alias: tableName }); + + if (typeof tableName === 'string') { + switch (joinType) { + case 'left': { + this.joinsNotNullableMap[tableName] = false; + break; + } + case 'right': { + this.joinsNotNullableMap = Object.fromEntries( + Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]), + ); + this.joinsNotNullableMap[tableName] = true; + break; + } + case 'inner': { + this.joinsNotNullableMap[tableName] = true; + break; + } + case 'full': { + this.joinsNotNullableMap = Object.fromEntries( + Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]), + ); + this.joinsNotNullableMap[tableName] = false; + break; + } + } + } + + return this as any; + }) as any; } + leftJoin = this.createJoin('left'); + + rightJoin = this.createJoin('right'); + + innerJoin = this.createJoin('inner'); + + fullJoin = this.createJoin('full'); + /** * Adds a 'where' clause to the query. * @@ -239,8 +483,30 @@ export class PgUpdateBase< fields: TSelectedFields, ): PgUpdateReturning; returning( - fields: SelectedFields = this.config.table[Table.Symbol.Columns], + fields?: SelectedFields, ): PgUpdateWithout { + if (!fields) { + fields = Object.assign({}, this.config.table[Table.Symbol.Columns]); + + if (this.config.from) { + const tableName = getTableLikeName(this.config.from); + + if (typeof tableName === 'string' && this.config.from && !is(this.config.from, SQL)) { + const fromFields = this.getTableLikeFields(this.config.from); + fields[tableName] = fromFields as any; + } + + for (const join of this.config.joins) { + const tableName = getTableLikeName(join.table); + + if (typeof tableName === 'string' && !is(join.table, SQL)) { + const fromFields = this.getTableLikeFields(join.table); + fields[tableName] = fromFields as any; + } + } + } + } + this.config.returning = orderSelectedFields(fields); return this as any; } @@ -257,7 +523,11 @@ export class PgUpdateBase< /** @internal */ _prepare(name?: string): PgUpdatePrepare { - return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name, true); + const query = this.session.prepareQuery< + PreparedQueryConfig & { execute: TReturning[] } + >(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name, true); + query.joinsNotNullableMap = this.joinsNotNullableMap; + return query; } prepare(name: string): PgUpdatePrepare { diff --git a/drizzle-orm/src/sqlite-core/dialect.ts b/drizzle-orm/src/sqlite-core/dialect.ts index 8995148c1..20e530d26 100644 --- a/drizzle-orm/src/sqlite-core/dialect.ts +++ b/drizzle-orm/src/sqlite-core/dialect.ts @@ -112,11 +112,15 @@ export abstract class SQLiteDialect { })); } - buildUpdateQuery({ table, set, where, returning, withList, limit, orderBy }: SQLiteUpdateConfig): SQL { + buildUpdateQuery({ table, set, where, returning, withList, joins, from, limit, orderBy }: SQLiteUpdateConfig): SQL { const withSql = this.buildWithCTE(withList); const setSql = this.buildUpdateSet(table, set); + const fromSql = from && sql.join([sql.raw(' from '), this.buildFromTable(from)]); + + const joinsSql = this.buildJoins(joins); + const returningSql = returning ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` : undefined; @@ -127,7 +131,7 @@ export abstract class SQLiteDialect { const limitSql = this.buildLimit(limit); - return sql`${withSql}update ${table} set ${setSql}${whereSql}${returningSql}${orderBySql}${limitSql}`; + return sql`${withSql}update ${table} set ${setSql}${fromSql}${joinsSql}${whereSql}${returningSql}${orderBySql}${limitSql}`; } /** @@ -193,6 +197,44 @@ export abstract class SQLiteDialect { return sql.join(chunks); } + private buildJoins(joins: SQLiteSelectJoinConfig[] | undefined): SQL | undefined { + if (!joins || joins.length === 0) { + return undefined; + } + + const joinsArray: SQL[] = []; + + if (joins) { + for (const [index, joinMeta] of joins.entries()) { + if (index === 0) { + joinsArray.push(sql` `); + } + const table = joinMeta.table; + + if (is(table, SQLiteTable)) { + const tableName = table[SQLiteTable.Symbol.Name]; + const tableSchema = table[SQLiteTable.Symbol.Schema]; + const origTableName = table[SQLiteTable.Symbol.OriginalName]; + const alias = tableName === origTableName ? undefined : joinMeta.alias; + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join ${tableSchema ? sql`${sql.identifier(tableSchema)}.` : undefined}${ + sql.identifier(origTableName) + }${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + ); + } else { + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join ${table} on ${joinMeta.on}`, + ); + } + if (index < joins.length - 1) { + joinsArray.push(sql` `); + } + } + } + + return sql.join(joinsArray); + } + private buildLimit(limit: number | Placeholder | undefined): SQL | undefined { return typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) ? sql` limit ${limit}` @@ -215,6 +257,16 @@ export abstract class SQLiteDialect { return orderByList.length > 0 ? sql` order by ${sql.join(orderByList)}` : undefined; } + private buildFromTable( + table: SQL | Subquery | SQLiteViewBase | SQLiteTable | undefined, + ): SQL | Subquery | SQLiteViewBase | SQLiteTable | undefined { + if (is(table, Table) && table[Table.Symbol.OriginalName] !== table[Table.Symbol.Name]) { + return sql`${sql.identifier(table[Table.Symbol.OriginalName])} ${sql.identifier(table[Table.Symbol.Name])}`; + } + + return table; + } + buildSelectQuery( { withList, @@ -266,45 +318,9 @@ export abstract class SQLiteDialect { const selection = this.buildSelection(fieldsList, { isSingleTable }); - const tableSql = (() => { - if (is(table, Table) && table[Table.Symbol.OriginalName] !== table[Table.Symbol.Name]) { - return sql`${sql.identifier(table[Table.Symbol.OriginalName])} ${sql.identifier(table[Table.Symbol.Name])}`; - } - - return table; - })(); - - const joinsArray: SQL[] = []; - - if (joins) { - for (const [index, joinMeta] of joins.entries()) { - if (index === 0) { - joinsArray.push(sql` `); - } - const table = joinMeta.table; - - if (is(table, SQLiteTable)) { - const tableName = table[SQLiteTable.Symbol.Name]; - const tableSchema = table[SQLiteTable.Symbol.Schema]; - const origTableName = table[SQLiteTable.Symbol.OriginalName]; - const alias = tableName === origTableName ? undefined : joinMeta.alias; - joinsArray.push( - sql`${sql.raw(joinMeta.joinType)} join ${tableSchema ? sql`${sql.identifier(tableSchema)}.` : undefined}${ - sql.identifier(origTableName) - }${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, - ); - } else { - joinsArray.push( - sql`${sql.raw(joinMeta.joinType)} join ${table} on ${joinMeta.on}`, - ); - } - if (index < joins.length - 1) { - joinsArray.push(sql` `); - } - } - } + const tableSql = this.buildFromTable(table); - const joinsSql = sql.join(joinsArray); + const joinsSql = this.buildJoins(joins); const whereSql = where ? sql` where ${where}` : undefined; diff --git a/drizzle-orm/src/sqlite-core/query-builders/select.ts b/drizzle-orm/src/sqlite-core/query-builders/select.ts index d9fce748a..443bf8480 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/select.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/select.ts @@ -39,12 +39,12 @@ import type { SelectedFields, SetOperatorRightSelect, SQLiteCreateSetOperatorFn, - SQLiteJoinFn, SQLiteSelectConfig, SQLiteSelectDynamic, SQLiteSelectExecute, SQLiteSelectHKT, SQLiteSelectHKTBase, + SQLiteSelectJoinFn, SQLiteSelectPrepare, SQLiteSelectWithout, SQLiteSetOperatorExcludedMethods, @@ -193,7 +193,7 @@ export abstract class SQLiteSelectQueryBuilderBase< private createJoin( joinType: TJoinType, - ): SQLiteJoinFn { + ): SQLiteSelectJoinFn { return ( table: SQLiteTable | Subquery | SQLiteViewBase | SQL, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, diff --git a/drizzle-orm/src/sqlite-core/query-builders/select.types.ts b/drizzle-orm/src/sqlite-core/query-builders/select.types.ts index 48c7054fa..e76a09f3e 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/select.types.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/select.types.ts @@ -72,7 +72,7 @@ export interface SQLiteSelectConfig { }[]; } -export type SQLiteJoin< +export type SQLiteSelectJoin< T extends AnySQLiteSelectQueryBuilder, TDynamic extends boolean, TJoinType extends JoinType, @@ -103,7 +103,7 @@ export type SQLiteJoin< > : never; -export type SQLiteJoinFn< +export type SQLiteSelectJoinFn< T extends AnySQLiteSelectQueryBuilder, TDynamic extends boolean, TJoinType extends JoinType, @@ -113,7 +113,7 @@ export type SQLiteJoinFn< >( table: TJoinedTable, on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, -) => SQLiteJoin; +) => SQLiteSelectJoin; export type SelectedFieldsFlat = SelectFieldsFlatBase; diff --git a/drizzle-orm/src/sqlite-core/query-builders/update.ts b/drizzle-orm/src/sqlite-core/query-builders/update.ts index f49337107..cc5e4ee30 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/update.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/update.ts @@ -1,6 +1,6 @@ import type { GetColumnData } from '~/column.ts'; -import { entityKind } from '~/entity.ts'; -import type { SelectResultFields } from '~/query-builders/select.types.ts'; +import { entityKind, is } from '~/entity.ts'; +import type { JoinType, SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; @@ -8,17 +8,20 @@ import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteDialect } from '~/sqlite-core/dialect.ts'; import type { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; -import type { Subquery } from '~/subquery.ts'; +import { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; import { type DrizzleTypeError, + getTableLikeName, mapUpdateSet, orderSelectedFields, type UpdateSet, type ValueOrArray, } from '~/utils.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; import type { SQLiteColumn } from '../columns/common.ts'; -import type { SelectedFields, SelectedFieldsOrdered } from './select.types.ts'; +import { SQLiteViewBase } from '../view-base.ts'; +import type { SelectedFields, SelectedFieldsOrdered, SQLiteSelectJoinConfig } from './select.types.ts'; export interface SQLiteUpdateConfig { where?: SQL | undefined; @@ -26,6 +29,8 @@ export interface SQLiteUpdateConfig { orderBy?: (SQLiteColumn | SQL | SQL.Aliased)[]; set: UpdateSet; table: SQLiteTable; + from?: SQLiteTable | Subquery | SQLiteViewBase | SQL; + joins: SQLiteSelectJoinConfig[]; returning?: SelectedFieldsOrdered; withList?: Subquery[]; } @@ -34,7 +39,8 @@ export type SQLiteUpdateSetSource = & { [Key in keyof TTable['$inferInsert']]?: | GetColumnData - | SQL; + | SQL + | SQLiteColumn; } & {}; @@ -56,14 +62,20 @@ export class SQLiteUpdateBuilder< private withList?: Subquery[], ) {} - set(values: SQLiteUpdateSetSource): SQLiteUpdateBase { + set( + values: SQLiteUpdateSetSource, + ): SQLiteUpdateWithout< + SQLiteUpdateBase, + false, + 'leftJoin' | 'rightJoin' | 'innerJoin' | 'fullJoin' + > { return new SQLiteUpdateBase( this.table, mapUpdateSet(this.table, values), this.session, this.dialect, this.withList, - ); + ) as any; } } @@ -76,6 +88,7 @@ export type SQLiteUpdateWithout< T['_']['table'], T['_']['resultType'], T['_']['runResult'], + T['_']['from'], T['_']['returning'], TDynamic, T['_']['excludedMethods'] | K @@ -83,11 +96,29 @@ export type SQLiteUpdateWithout< T['_']['excludedMethods'] | K >; +export type SQLiteUpdateWithJoins< + T extends AnySQLiteUpdate, + TDynamic extends boolean, + TFrom extends SQLiteTable | Subquery | SQLiteViewBase | SQL, +> = TDynamic extends true ? T : Omit< + SQLiteUpdateBase< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + TFrom, + T['_']['returning'], + TDynamic, + Exclude + >, + Exclude +>; + export type SQLiteUpdateReturningAll = SQLiteUpdateWithout< SQLiteUpdateBase< T['_']['table'], T['_']['resultType'], T['_']['runResult'], + T['_']['from'], T['_']['table']['$inferSelect'], TDynamic, T['_']['excludedMethods'] @@ -105,6 +136,7 @@ export type SQLiteUpdateReturning< T['_']['table'], T['_']['resultType'], T['_']['runResult'], + T['_']['from'], SelectResultFields, TDynamic, T['_']['excludedMethods'] @@ -130,6 +162,25 @@ export type SQLiteUpdatePrepare = SQLitePreparedQuery } >; +export type SQLiteUpdateJoinFn< + T extends AnySQLiteUpdate, +> = < + TJoinedTable extends SQLiteTable | Subquery | SQLiteViewBase | SQL, +>( + table: TJoinedTable, + on: + | ( + ( + updateTable: T['_']['table']['_']['columns'], + from: T['_']['from'] extends SQLiteTable ? T['_']['from']['_']['columns'] + : T['_']['from'] extends Subquery | SQLiteViewBase ? T['_']['from']['_']['selectedFields'] + : never, + ) => SQL | undefined + ) + | SQL + | undefined, +) => T; + export type SQLiteUpdateDynamic = SQLiteUpdate< T['_']['table'], T['_']['resultType'], @@ -141,15 +192,17 @@ export type SQLiteUpdate< TTable extends SQLiteTable = SQLiteTable, TResultType extends 'sync' | 'async' = 'sync' | 'async', TRunResult = any, + TFrom extends SQLiteTable | Subquery | SQLiteViewBase | SQL | undefined = undefined, TReturning extends Record | undefined = Record | undefined, -> = SQLiteUpdateBase; +> = SQLiteUpdateBase; -export type AnySQLiteUpdate = SQLiteUpdateBase; +export type AnySQLiteUpdate = SQLiteUpdateBase; export interface SQLiteUpdateBase< TTable extends SQLiteTable = SQLiteTable, TResultType extends 'sync' | 'async' = 'sync' | 'async', TRunResult = unknown, + TFrom extends SQLiteTable | Subquery | SQLiteViewBase | SQL | undefined = undefined, TReturning = undefined, TDynamic extends boolean = false, TExcludedMethods extends string = never, @@ -159,6 +212,7 @@ export interface SQLiteUpdateBase< readonly table: TTable; readonly resultType: TResultType; readonly runResult: TRunResult; + readonly from: TFrom; readonly returning: TReturning; readonly dynamic: TDynamic; readonly excludedMethods: TExcludedMethods; @@ -171,6 +225,7 @@ export class SQLiteUpdateBase< // eslint-disable-next-line @typescript-eslint/no-unused-vars TResultType extends 'sync' | 'async' = 'sync' | 'async', TRunResult = unknown, + TFrom extends SQLiteTable | Subquery | SQLiteViewBase | SQL | undefined = undefined, TReturning = undefined, // eslint-disable-next-line @typescript-eslint/no-unused-vars TDynamic extends boolean = false, @@ -192,9 +247,65 @@ export class SQLiteUpdateBase< withList?: Subquery[], ) { super(); - this.config = { set, table, withList }; + this.config = { set, table, withList, joins: [] }; + } + + from( + source: TFrom, + ): SQLiteUpdateWithJoins { + this.config.from = source; + return this as any; } + private createJoin( + joinType: TJoinType, + ): SQLiteUpdateJoinFn { + return (( + table: SQLiteTable | Subquery | SQLiteViewBase | SQL, + on: ((updateTable: TTable, from: TFrom) => SQL | undefined) | SQL | undefined, + ) => { + const tableName = getTableLikeName(table); + + if (typeof tableName === 'string' && this.config.joins.some((join) => join.alias === tableName)) { + throw new Error(`Alias "${tableName}" is already used in this query`); + } + + if (typeof on === 'function') { + const from = this.config.from + ? is(table, SQLiteTable) + ? table[Table.Symbol.Columns] + : is(table, Subquery) + ? table._.selectedFields + : is(table, SQLiteViewBase) + ? table[ViewBaseConfig].selectedFields + : undefined + : undefined; + on = on( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as any, + from && new Proxy( + from, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as any, + ); + } + + this.config.joins.push({ on, table, joinType, alias: tableName }); + + return this as any; + }) as any; + } + + leftJoin = this.createJoin('left'); + + rightJoin = this.createJoin('right'); + + innerJoin = this.createJoin('inner'); + + fullJoin = this.createJoin('full'); + /** * Adds a 'where' clause to the query. * diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index 8e1382c7a..bd8fea848 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -114,7 +114,7 @@ export function mapUpdateSet(table: Table, values: Record): Upd .filter(([, value]) => value !== undefined) .map(([key, value]) => { // eslint-disable-next-line unicorn/prefer-ternary - if (is(value, SQL)) { + if (is(value, SQL) || is(value, Column)) { return [key, value]; } else { return [key, new Param(value, table[Table.Symbol.Columns][key])]; @@ -128,7 +128,7 @@ export function mapUpdateSet(table: Table, values: Record): Upd return Object.fromEntries(entries); } -export type UpdateSet = Record; +export type UpdateSet = Record; export type OneOrMany = T | T[]; diff --git a/drizzle-orm/type-tests/pg/update.ts b/drizzle-orm/type-tests/pg/update.ts index a667825e0..a53f70b03 100644 --- a/drizzle-orm/type-tests/pg/update.ts +++ b/drizzle-orm/type-tests/pg/update.ts @@ -4,8 +4,9 @@ import { Expect } from 'type-tests/utils.ts'; import { eq } from '~/expressions.ts'; import type { PgUpdate } from '~/pg-core/index.ts'; import { sql } from '~/sql/sql.ts'; +import type { Simplify } from '~/utils.ts'; import { db } from './db.ts'; -import { users } from './tables.ts'; +import { cities, salEmp, users } from './tables.ts'; const update = await db.update(users) .set({ @@ -86,3 +87,192 @@ Expect>; // @ts-expect-error method was already called .where(sql``); } + +{ + db + .update(users) + .set({}) + .from(sql``) + .leftJoin(sql``, (table, from) => { + Expect>; + Expect>; + return sql``; + }); + + db + .update(users) + .set({}) + .from(cities) + .leftJoin(sql``, (table, from) => { + Expect>; + Expect>; + return sql``; + }); + + const citiesSq = db.$with('cities_sq').as(db.select({ id: cities.id }).from(cities)); + + db + .with(citiesSq) + .update(users) + .set({}) + .from(citiesSq) + .leftJoin(sql``, (table, from) => { + Expect>; + Expect>; + return sql``; + }); + + db + .with(citiesSq) + .update(users) + .set({ + homeCity: citiesSq.id, + }) + .from(citiesSq); +} + +{ + const result = await db.update(users).set({}).from(cities).returning(); + Expect< + Equal[], typeof result> + >; +} + +{ + const result1 = await db.update(users).set({}).from(cities).leftJoin(salEmp, sql``).returning(); + Expect< + Equal[], typeof result1> + >; + + const result2 = await db.update(users).set({}).from(cities).rightJoin(salEmp, sql``).returning(); + Expect< + Equal[], typeof result2> + >; + + const result3 = await db.update(users).set({}).from(cities).innerJoin(salEmp, sql``).returning(); + Expect< + Equal[], typeof result3> + >; + + const result4 = await db.update(users).set({}).from(cities).fullJoin(salEmp, sql``).returning(); + Expect< + Equal[], typeof result4> + >; +} + +{ + const result = await db.update(users).set({}).from(cities).returning({ + id: users.id, + cities: cities, + cityName: cities.name, + }); + Expect< + Equal[], typeof result> + >; +} + +{ + const result1 = await db.update(users).set({}).from(cities).leftJoin(salEmp, sql``).returning({ + id: users.id, + cities: cities, + cityName: cities.name, + salEmp: salEmp, + salEmpName: salEmp.name, + }); + Expect< + Equal[], typeof result1> + >; + + const result2 = await db.update(users).set({}).from(cities).rightJoin(salEmp, sql``).returning({ + id: users.id, + cities: cities, + cityName: cities.name, + salEmp: salEmp, + salEmpName: salEmp.name, + }); + Expect< + Equal[], typeof result2> + >; + + const result3 = await db.update(users).set({}).from(cities).innerJoin(salEmp, sql``).returning({ + id: users.id, + cities: cities, + cityName: cities.name, + salEmp: salEmp, + salEmpName: salEmp.name, + }); + Expect< + Equal[], typeof result3> + >; + + const result4 = await db.update(users).set({}).from(cities).fullJoin(salEmp, sql``).returning({ + id: users.id, + cities: cities, + cityName: cities.name, + salEmp: salEmp, + salEmpName: salEmp.name, + }); + Expect< + Equal[], typeof result4> + >; +} + +{ + await db + .update(users) + .set({}) + // @ts-expect-error can't use joins before from + .fullJoin(salEmp, sql``); +} diff --git a/drizzle-orm/type-tests/sqlite/update.ts b/drizzle-orm/type-tests/sqlite/update.ts index cea386b98..a6a1b47b3 100644 --- a/drizzle-orm/type-tests/sqlite/update.ts +++ b/drizzle-orm/type-tests/sqlite/update.ts @@ -6,7 +6,7 @@ import { sql } from '~/sql/sql.ts'; import type { SQLiteUpdate } from '~/sqlite-core/query-builders/update.ts'; import type { DrizzleTypeError } from '~/utils.ts'; import { bunDb, db } from './db.ts'; -import { users } from './tables.ts'; +import { cities, users } from './tables.ts'; const updateRun = db.update(users) .set({ @@ -135,5 +135,63 @@ Expect>; } { + db + .update(users) + .set({}) + .from(sql``) + .leftJoin(sql``, (table, from) => { + Expect>; + Expect>; + return sql``; + }); + + db + .update(users) + .set({}) + .from(cities) + .leftJoin(sql``, (table, from) => { + Expect>; + Expect>; + return sql``; + }); + + const citiesSq = db.$with('cities_sq').as(db.select({ id: cities.id }).from(cities)); + + db + .with(citiesSq) + .update(users) + .set({}) + .from(citiesSq) + .leftJoin(sql``, (table, from) => { + Expect>; + Expect>; + return sql``; + }); + + db + .with(citiesSq) + .update(users) + .set({ + homeCity: citiesSq.id, + }) + .from(citiesSq); +} + +{ + const result = await db.update(users).set({}).from(cities).returning(); + Expect< + Equal + >; +} + +{ + const result = await db.update(users).set({}).from(cities).returning({ + id: users.id, + }); + Expect< + Equal<{ + id: number; + }[], typeof result> + >; db.update(users).set({}).where(sql``).limit(1).orderBy(sql``); } diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index dd2971c3c..17495afac 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4740,6 +4740,175 @@ export function tests() { }]); }); + test('update ... from', async (ctx) => { + const { db } = ctx.pg; + + await db.insert(cities2Table).values([ + { name: 'New York City' }, + { name: 'Seattle' }, + ]); + await db.insert(users2Table).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + ]); + + const result = await db + .update(users2Table) + .set({ + cityId: cities2Table.id, + }) + .from(cities2Table) + .where(and(eq(cities2Table.name, 'Seattle'), eq(users2Table.name, 'John'))) + .returning(); + + expect(result).toStrictEqual([{ + id: 1, + name: 'John', + cityId: 2, + cities: { + id: 2, + name: 'Seattle', + }, + }]); + }); + + test('update ... from with alias', async (ctx) => { + const { db } = ctx.pg; + + await db.insert(cities2Table).values([ + { name: 'New York City' }, + { name: 'Seattle' }, + ]); + await db.insert(users2Table).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + ]); + + const users = alias(users2Table, 'u'); + const cities = alias(cities2Table, 'c'); + const result = await db + .update(users) + .set({ + cityId: cities.id, + }) + .from(cities) + .where(and(eq(cities.name, 'Seattle'), eq(users.name, 'John'))) + .returning(); + + expect(result).toStrictEqual([{ + id: 1, + name: 'John', + cityId: 2, + c: { + id: 2, + name: 'Seattle', + }, + }]); + }); + + test('update ... from with join', async (ctx) => { + const { db } = ctx.pg; + + const states = pgTable('states', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + const cities = pgTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + stateId: integer('state_id').references(() => states.id), + }); + const users = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull().references(() => cities.id), + }); + + await db.execute(sql`drop table if exists "states" cascade`); + await db.execute(sql`drop table if exists "cities" cascade`); + await db.execute(sql`drop table if exists "users" cascade`); + await db.execute(sql` + create table "states" ( + "id" serial primary key, + "name" text not null + ) + `); + await db.execute(sql` + create table "cities" ( + "id" serial primary key, + "name" text not null, + "state_id" integer references "states"("id") + ) + `); + await db.execute(sql` + create table "users" ( + "id" serial primary key, + "name" text not null, + "city_id" integer not null references "cities"("id") + ) + `); + + await db.insert(states).values([ + { name: 'New York' }, + { name: 'Washington' }, + ]); + await db.insert(cities).values([ + { name: 'New York City', stateId: 1 }, + { name: 'Seattle', stateId: 2 }, + { name: 'London' }, + ]); + await db.insert(users).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + { name: 'Jack', cityId: 3 }, + ]); + + const result1 = await db + .update(users) + .set({ + cityId: cities.id, + }) + .from(cities) + .leftJoin(states, eq(cities.stateId, states.id)) + .where(and(eq(cities.name, 'Seattle'), eq(users.name, 'John'))) + .returning(); + const result2 = await db + .update(users) + .set({ + cityId: cities.id, + }) + .from(cities) + .leftJoin(states, eq(cities.stateId, states.id)) + .where(and(eq(cities.name, 'London'), eq(users.name, 'Jack'))) + .returning(); + + expect(result1).toStrictEqual([{ + id: 1, + name: 'John', + cityId: 2, + cities: { + id: 2, + name: 'Seattle', + stateId: 2, + }, + states: { + id: 2, + name: 'Washington', + }, + }]); + expect(result2).toStrictEqual([{ + id: 3, + name: 'Jack', + cityId: 3, + cities: { + id: 3, + name: 'London', + stateId: null, + }, + states: null, + }]); + }); + test('policy', () => { { const policy = pgPolicy('test policy'); diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index a20ce5bbf..5cfcb45bd 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -3065,6 +3065,185 @@ export function tests() { expect(users.length).toBeGreaterThan(0); }); + test('update ... from', async (ctx) => { + const { db } = ctx.sqlite; + + await db.run(sql`drop table if exists \`cities\``); + await db.run(sql`drop table if exists \`users2\``); + await db.run(sql` + create table \`cities\` ( + \`id\` integer primary key autoincrement, + \`name\` text not null + ) + `); + await db.run(sql` + create table \`users2\` ( + \`id\` integer primary key autoincrement, + \`name\` text not null, + \`city_id\` integer references \`cities\`(\`id\`) + ) + `); + + await db.insert(citiesTable).values([ + { name: 'New York City' }, + { name: 'Seattle' }, + ]); + await db.insert(users2Table).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + ]); + + const result = await db + .update(users2Table) + .set({ + cityId: citiesTable.id, + }) + .from(citiesTable) + .where(and(eq(citiesTable.name, 'Seattle'), eq(users2Table.name, 'John'))) + .returning(); + + expect(result).toStrictEqual([{ + id: 1, + name: 'John', + cityId: 2, + }]); + }); + + test('update ... from with alias', async (ctx) => { + const { db } = ctx.sqlite; + + await db.run(sql`drop table if exists \`users2\``); + await db.run(sql`drop table if exists \`cities\``); + await db.run(sql` + create table \`cities\` ( + \`id\` integer primary key autoincrement, + \`name\` text not null + ) + `); + await db.run(sql` + create table \`users2\` ( + \`id\` integer primary key autoincrement, + \`name\` text not null, + \`city_id\` integer references \`cities\`(\`id\`) + ) + `); + + await db.insert(citiesTable).values([ + { name: 'New York City' }, + { name: 'Seattle' }, + ]); + await db.insert(users2Table).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + ]); + + const cities = alias(citiesTable, 'c'); + const result = await db + .update(users2Table) + .set({ + cityId: cities.id, + }) + .from(cities) + .where(and(eq(cities.name, 'Seattle'), eq(users2Table.name, 'John'))) + .returning(); + + expect(result).toStrictEqual([{ + id: 1, + name: 'John', + cityId: 2, + }]); + + await db.run(sql`drop table if exists \`users2\``); + }); + + test('update ... from with join', async (ctx) => { + const { db } = ctx.sqlite; + + const states = sqliteTable('states', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }); + const cities = sqliteTable('cities', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + stateId: integer('state_id').references(() => states.id), + }); + const users = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + cityId: integer('city_id').notNull().references(() => cities.id), + }); + + await db.run(sql`drop table if exists \`states\``); + await db.run(sql`drop table if exists \`cities\``); + await db.run(sql`drop table if exists \`users\``); + await db.run(sql` + create table \`states\` ( + \`id\` integer primary key autoincrement, + \`name\` text not null + ) + `); + await db.run(sql` + create table \`cities\` ( + \`id\` integer primary key autoincrement, + \`name\` text not null, + \`state_id\` integer references \`states\`(\`id\`) + ) + `); + await db.run(sql` + create table \`users\` ( + \`id\` integer primary key autoincrement, + \`name\` text not null, + \`city_id\` integer not null references \`cities\`(\`id\`) + ) + `); + + await db.insert(states).values([ + { name: 'New York' }, + { name: 'Washington' }, + ]); + await db.insert(cities).values([ + { name: 'New York City', stateId: 1 }, + { name: 'Seattle', stateId: 2 }, + { name: 'London' }, + ]); + await db.insert(users).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + { name: 'Jack', cityId: 3 }, + ]); + + const result1 = await db + .update(users) + .set({ + cityId: cities.id, + }) + .from(cities) + .leftJoin(states, eq(cities.stateId, states.id)) + .where(and(eq(cities.name, 'Seattle'), eq(users.name, 'John'))) + .returning(); + const result2 = await db + .update(users) + .set({ + cityId: cities.id, + }) + .from(cities) + .leftJoin(states, eq(cities.stateId, states.id)) + .where(and(eq(cities.name, 'London'), eq(users.name, 'Jack'))) + .returning(); + + expect(result1).toStrictEqual([{ + id: 1, + name: 'John', + cityId: 2, + }]); + expect(result2).toStrictEqual([{ + id: 3, + name: 'Jack', + cityId: 3, + }]); + }); + test('Object keys as column names', async (ctx) => { const { db } = ctx.sqlite; From cadba2449cae62f0b070c16653c1558cebfb4e47 Mon Sep 17 00:00:00 2001 From: L-Mario564 Date: Fri, 15 Nov 2024 02:46:26 -0800 Subject: [PATCH 362/492] Feat: Support `insert into ... select` syntax (#2783) * Implement insert into select for PG dialect * Add additional PG test * Implement insert into select in MySql dialect * Implement insert into select in SQLite dialect * Format * Set cascade delete on test table foreign keys --- drizzle-orm/src/aws-data-api/pg/driver.ts | 23 ++-- drizzle-orm/src/mysql-core/dialect.ts | 80 +++++++----- .../src/mysql-core/query-builders/insert.ts | 42 +++++- drizzle-orm/src/pg-core/dialect.ts | 60 +++++---- .../src/pg-core/query-builders/insert.ts | 42 +++++- drizzle-orm/src/sqlite-core/dialect.ts | 74 +++++++---- .../src/sqlite-core/query-builders/insert.ts | 44 ++++++- drizzle-orm/type-tests/mysql/insert.ts | 74 ++++++++++- drizzle-orm/type-tests/pg/insert.ts | 73 +++++++++++ drizzle-orm/type-tests/sqlite/insert.ts | 73 +++++++++++ integration-tests/tests/mysql/mysql-common.ts | 122 ++++++++++++++++++ integration-tests/tests/pg/pg-common.ts | 121 +++++++++++++++++ .../tests/sqlite/sqlite-common.ts | 118 +++++++++++++++++ .../tests/sqlite/sqlite-proxy.test.ts | 2 +- 14 files changed, 841 insertions(+), 107 deletions(-) diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index 1d59bea62..d1d68e7ac 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -54,22 +54,25 @@ export class AwsPgDialect extends PgDialect { } override buildInsertQuery( - { table, values, onConflict, returning }: PgInsertConfig>, + { table, values, onConflict, returning, select, withList }: PgInsertConfig>, ): SQL { const columns: Record = table[Table.Symbol.Columns]; - for (const value of values) { - for (const fieldName of Object.keys(columns)) { - const colValue = value[fieldName]; - if ( - is(colValue, Param) && colValue.value !== undefined && is(colValue.encoder, PgArray) - && Array.isArray(colValue.value) - ) { - value[fieldName] = sql`cast(${colValue} as ${sql.raw(colValue.encoder.getSQLType())})`; + + if (!select) { + for (const value of (values as Record[])) { + for (const fieldName of Object.keys(columns)) { + const colValue = value[fieldName]; + if ( + is(colValue, Param) && colValue.value !== undefined && is(colValue.encoder, PgArray) + && Array.isArray(colValue.value) + ) { + value[fieldName] = sql`cast(${colValue} as ${sql.raw(colValue.encoder.getSQLType())})`; + } } } } - return super.buildInsertQuery({ table, values, onConflict, returning }); + return super.buildInsertQuery({ table, values, onConflict, returning, withList }); } override buildUpdateSet(table: PgTable, set: UpdateSet): SQL { diff --git a/drizzle-orm/src/mysql-core/dialect.ts b/drizzle-orm/src/mysql-core/dialect.ts index af4f11905..e01888636 100644 --- a/drizzle-orm/src/mysql-core/dialect.ts +++ b/drizzle-orm/src/mysql-core/dialect.ts @@ -26,7 +26,12 @@ import { ViewBaseConfig } from '~/view-common.ts'; import { MySqlColumn } from './columns/common.ts'; import type { MySqlDeleteConfig } from './query-builders/delete.ts'; import type { MySqlInsertConfig } from './query-builders/insert.ts'; -import type { MySqlSelectConfig, MySqlSelectJoinConfig, SelectedFieldsOrdered } from './query-builders/select.types.ts'; +import type { + AnyMySqlSelectQueryBuilder, + MySqlSelectConfig, + MySqlSelectJoinConfig, + SelectedFieldsOrdered, +} from './query-builders/select.types.ts'; import type { MySqlUpdateConfig } from './query-builders/update.ts'; import type { MySqlSession } from './session.ts'; import { MySqlTable } from './table.ts'; @@ -439,7 +444,7 @@ export class MySqlDialect { } buildInsertQuery( - { table, values, ignore, onConflict }: MySqlInsertConfig, + { table, values: valuesOrSelect, ignore, onConflict, select }: MySqlInsertConfig, ): { sql: SQL; generatedIds: Record[] } { // const isSingleValue = values.length === 1; const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = []; @@ -451,39 +456,52 @@ export class MySqlDialect { const insertOrder = colEntries.map(([, column]) => sql.identifier(this.casing.getColumnCasing(column))); const generatedIdsResponse: Record[] = []; - for (const [valueIndex, value] of values.entries()) { - const generatedIds: Record = {}; - - const valueList: (SQLChunk | SQL)[] = []; - for (const [fieldName, col] of colEntries) { - const colValue = value[fieldName]; - if (colValue === undefined || (is(colValue, Param) && colValue.value === undefined)) { - // eslint-disable-next-line unicorn/no-negated-condition - if (col.defaultFn !== undefined) { - const defaultFnResult = col.defaultFn(); - generatedIds[fieldName] = defaultFnResult; - const defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col); - valueList.push(defaultValue); + if (select) { + const select = valuesOrSelect as AnyMySqlSelectQueryBuilder | SQL; + + if (is(select, SQL)) { + valuesSqlList.push(select); + } else { + valuesSqlList.push(select.getSQL()); + } + } else { + const values = valuesOrSelect as Record[]; + valuesSqlList.push(sql.raw('values ')); + + for (const [valueIndex, value] of values.entries()) { + const generatedIds: Record = {}; + + const valueList: (SQLChunk | SQL)[] = []; + for (const [fieldName, col] of colEntries) { + const colValue = value[fieldName]; + if (colValue === undefined || (is(colValue, Param) && colValue.value === undefined)) { // eslint-disable-next-line unicorn/no-negated-condition - } else if (!col.default && col.onUpdateFn !== undefined) { - const onUpdateFnResult = col.onUpdateFn(); - const newValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col); - valueList.push(newValue); + if (col.defaultFn !== undefined) { + const defaultFnResult = col.defaultFn(); + generatedIds[fieldName] = defaultFnResult; + const defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col); + valueList.push(defaultValue); + // eslint-disable-next-line unicorn/no-negated-condition + } else if (!col.default && col.onUpdateFn !== undefined) { + const onUpdateFnResult = col.onUpdateFn(); + const newValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col); + valueList.push(newValue); + } else { + valueList.push(sql`default`); + } } else { - valueList.push(sql`default`); - } - } else { - if (col.defaultFn && is(colValue, Param)) { - generatedIds[fieldName] = colValue.value; + if (col.defaultFn && is(colValue, Param)) { + generatedIds[fieldName] = colValue.value; + } + valueList.push(colValue); } - valueList.push(colValue); } - } - generatedIdsResponse.push(generatedIds); - valuesSqlList.push(valueList); - if (valueIndex < values.length - 1) { - valuesSqlList.push(sql`, `); + generatedIdsResponse.push(generatedIds); + valuesSqlList.push(valueList); + if (valueIndex < values.length - 1) { + valuesSqlList.push(sql`, `); + } } } @@ -494,7 +512,7 @@ export class MySqlDialect { const onConflictSql = onConflict ? sql` on duplicate key ${onConflict}` : undefined; return { - sql: sql`insert${ignoreSql} into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}`, + sql: sql`insert${ignoreSql} into ${table} ${insertOrder} ${valuesSql}${onConflictSql}`, generatedIds: generatedIdsResponse, }; } diff --git a/drizzle-orm/src/mysql-core/query-builders/insert.ts b/drizzle-orm/src/mysql-core/query-builders/insert.ts index f3b4eec21..f943d0322 100644 --- a/drizzle-orm/src/mysql-core/query-builders/insert.ts +++ b/drizzle-orm/src/mysql-core/query-builders/insert.ts @@ -10,23 +10,26 @@ import type { PreparedQueryKind, } from '~/mysql-core/session.ts'; import type { MySqlTable } from '~/mysql-core/table.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; import { Param, SQL, sql } from '~/sql/sql.ts'; import type { InferModelFromColumns } from '~/table.ts'; -import { Table } from '~/table.ts'; -import { mapUpdateSet } from '~/utils.ts'; +import { Columns, Table } from '~/table.ts'; +import { haveSameKeys, mapUpdateSet } from '~/utils.ts'; import type { AnyMySqlColumn } from '../columns/common.ts'; +import { QueryBuilder } from './query-builder.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; import type { MySqlUpdateSetSource } from './update.ts'; export interface MySqlInsertConfig { table: TTable; - values: Record[]; + values: Record[] | MySqlInsertSelectQueryBuilder | SQL; ignore: boolean; onConflict?: SQL; returning?: SelectedFieldsOrdered; + select?: boolean; } export type AnyMySqlInsertConfig = MySqlInsertConfig; @@ -37,6 +40,10 @@ export type MySqlInsertValue = } & {}; +export type MySqlInsertSelectQueryBuilder = TypedQueryBuilder< + { [K in keyof TTable['$inferInsert']]: AnyMySqlColumn | SQL | SQL.Aliased | TTable['$inferInsert'][K] } +>; + export class MySqlInsertBuilder< TTable extends MySqlTable, TQueryResult extends MySqlQueryResultHKT, @@ -78,6 +85,32 @@ export class MySqlInsertBuilder< return new MySqlInsertBase(this.table, mappedValues, this.shouldIgnore, this.session, this.dialect); } + + select( + selectQuery: (qb: QueryBuilder) => MySqlInsertSelectQueryBuilder, + ): MySqlInsertBase; + select(selectQuery: (qb: QueryBuilder) => SQL): MySqlInsertBase; + select(selectQuery: SQL): MySqlInsertBase; + select(selectQuery: MySqlInsertSelectQueryBuilder): MySqlInsertBase; + select( + selectQuery: + | SQL + | MySqlInsertSelectQueryBuilder + | ((qb: QueryBuilder) => MySqlInsertSelectQueryBuilder | SQL), + ): MySqlInsertBase { + const select = typeof selectQuery === 'function' ? selectQuery(new QueryBuilder()) : selectQuery; + + if ( + !is(select, SQL) + && !haveSameKeys(this.table[Columns], select._.selectedFields) + ) { + throw new Error( + 'Insert select error: selected fields are not the same or are in a different order compared to the table definition', + ); + } + + return new MySqlInsertBase(this.table, select, this.shouldIgnore, this.session, this.dialect, true); + } } export type MySqlInsertWithout = @@ -202,9 +235,10 @@ export class MySqlInsertBase< ignore: boolean, private session: MySqlSession, private dialect: MySqlDialect, + select?: boolean, ) { super(); - this.config = { table, values, ignore }; + this.config = { table, values: values as any, select, ignore }; } /** diff --git a/drizzle-orm/src/pg-core/dialect.ts b/drizzle-orm/src/pg-core/dialect.ts index 173cb88b2..318ea3098 100644 --- a/drizzle-orm/src/pg-core/dialect.ts +++ b/drizzle-orm/src/pg-core/dialect.ts @@ -17,6 +17,7 @@ import { PgUUID, } from '~/pg-core/columns/index.ts'; import type { + AnyPgSelectQueryBuilder, PgDeleteConfig, PgInsertConfig, PgSelectJoinConfig, @@ -490,7 +491,7 @@ export class PgDialect { return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; } - buildInsertQuery({ table, values, onConflict, returning, withList }: PgInsertConfig): SQL { + buildInsertQuery({ table, values: valuesOrSelect, onConflict, returning, withList, select }: PgInsertConfig): SQL { const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = []; const columns: Record = table[Table.Symbol.Columns]; @@ -500,32 +501,45 @@ export class PgDialect { ([, column]) => sql.identifier(this.casing.getColumnCasing(column)), ); - for (const [valueIndex, value] of values.entries()) { - const valueList: (SQLChunk | SQL)[] = []; - for (const [fieldName, col] of colEntries) { - const colValue = value[fieldName]; - if (colValue === undefined || (is(colValue, Param) && colValue.value === undefined)) { - // eslint-disable-next-line unicorn/no-negated-condition - if (col.defaultFn !== undefined) { - const defaultFnResult = col.defaultFn(); - const defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col); - valueList.push(defaultValue); + if (select) { + const select = valuesOrSelect as AnyPgSelectQueryBuilder | SQL; + + if (is(select, SQL)) { + valuesSqlList.push(select); + } else { + valuesSqlList.push(select.getSQL()); + } + } else { + const values = valuesOrSelect as Record[]; + valuesSqlList.push(sql.raw('values ')); + + for (const [valueIndex, value] of values.entries()) { + const valueList: (SQLChunk | SQL)[] = []; + for (const [fieldName, col] of colEntries) { + const colValue = value[fieldName]; + if (colValue === undefined || (is(colValue, Param) && colValue.value === undefined)) { // eslint-disable-next-line unicorn/no-negated-condition - } else if (!col.default && col.onUpdateFn !== undefined) { - const onUpdateFnResult = col.onUpdateFn(); - const newValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col); - valueList.push(newValue); + if (col.defaultFn !== undefined) { + const defaultFnResult = col.defaultFn(); + const defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col); + valueList.push(defaultValue); + // eslint-disable-next-line unicorn/no-negated-condition + } else if (!col.default && col.onUpdateFn !== undefined) { + const onUpdateFnResult = col.onUpdateFn(); + const newValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col); + valueList.push(newValue); + } else { + valueList.push(sql`default`); + } } else { - valueList.push(sql`default`); + valueList.push(colValue); } - } else { - valueList.push(colValue); } - } - valuesSqlList.push(valueList); - if (valueIndex < values.length - 1) { - valuesSqlList.push(sql`, `); + valuesSqlList.push(valueList); + if (valueIndex < values.length - 1) { + valuesSqlList.push(sql`, `); + } } } @@ -539,7 +553,7 @@ export class PgDialect { const onConflictSql = onConflict ? sql` on conflict ${onConflict}` : undefined; - return sql`${withSql}insert into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}${returningSql}`; + return sql`${withSql}insert into ${table} ${insertOrder} ${valuesSql}${onConflictSql}${returningSql}`; } buildRefreshMaterializedViewQuery( diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index 9f494ab50..e44d3fbbb 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -9,25 +9,28 @@ import type { PreparedQueryConfig, } from '~/pg-core/session.ts'; import type { PgTable } from '~/pg-core/table.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; import { Param, SQL, sql } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; -import { Table } from '~/table.ts'; +import { Columns, Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; -import { mapUpdateSet, orderSelectedFields } from '~/utils.ts'; -import type { PgColumn } from '../columns/common.ts'; +import { haveSameKeys, mapUpdateSet, orderSelectedFields } from '~/utils.ts'; +import type { AnyPgColumn, PgColumn } from '../columns/common.ts'; +import { QueryBuilder } from './query-builder.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; import type { PgUpdateSetSource } from './update.ts'; export interface PgInsertConfig { table: TTable; - values: Record[]; + values: Record[] | PgInsertSelectQueryBuilder | SQL; withList?: Subquery[]; onConflict?: SQL; returning?: SelectedFieldsOrdered; + select?: boolean; } export type PgInsertValue = @@ -36,6 +39,10 @@ export type PgInsertValue = } & {}; +export type PgInsertSelectQueryBuilder = TypedQueryBuilder< + { [K in keyof TTable['$inferInsert']]: AnyPgColumn | SQL | SQL.Aliased | TTable['$inferInsert'][K] } +>; + export class PgInsertBuilder { static readonly [entityKind]: string = 'PgInsertBuilder'; @@ -65,6 +72,30 @@ export class PgInsertBuilder PgInsertSelectQueryBuilder): PgInsertBase; + select(selectQuery: (qb: QueryBuilder) => SQL): PgInsertBase; + select(selectQuery: SQL): PgInsertBase; + select(selectQuery: PgInsertSelectQueryBuilder): PgInsertBase; + select( + selectQuery: + | SQL + | PgInsertSelectQueryBuilder + | ((qb: QueryBuilder) => PgInsertSelectQueryBuilder | SQL), + ): PgInsertBase { + const select = typeof selectQuery === 'function' ? selectQuery(new QueryBuilder()) : selectQuery; + + if ( + !is(select, SQL) + && !haveSameKeys(this.table[Columns], select._.selectedFields) + ) { + throw new Error( + 'Insert select error: selected fields are not the same or are in a different order compared to the table definition', + ); + } + + return new PgInsertBase(this.table, select, this.session, this.dialect, this.withList, true); + } } export type PgInsertWithout = @@ -176,9 +207,10 @@ export class PgInsertBase< private session: PgSession, private dialect: PgDialect, withList?: Subquery[], + select?: boolean, ) { super(); - this.config = { table, values, withList }; + this.config = { table, values: values as any, withList, select }; } /** diff --git a/drizzle-orm/src/sqlite-core/dialect.ts b/drizzle-orm/src/sqlite-core/dialect.ts index 20e530d26..8db4ee56b 100644 --- a/drizzle-orm/src/sqlite-core/dialect.ts +++ b/drizzle-orm/src/sqlite-core/dialect.ts @@ -21,7 +21,12 @@ import type { Name, Placeholder } from '~/sql/index.ts'; import { and, eq } from '~/sql/index.ts'; import { Param, type QueryWithTypings, SQL, sql, type SQLChunk } from '~/sql/sql.ts'; import { SQLiteColumn } from '~/sqlite-core/columns/index.ts'; -import type { SQLiteDeleteConfig, SQLiteInsertConfig, SQLiteUpdateConfig } from '~/sqlite-core/query-builders/index.ts'; +import type { + AnySQLiteSelectQueryBuilder, + SQLiteDeleteConfig, + SQLiteInsertConfig, + SQLiteUpdateConfig, +} from '~/sqlite-core/query-builders/index.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; import { Subquery } from '~/subquery.ts'; import { getTableName, getTableUniqueName, Table } from '~/table.ts'; @@ -419,7 +424,9 @@ export abstract class SQLiteDialect { return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; } - buildInsertQuery({ table, values, onConflict, returning, withList }: SQLiteInsertConfig): SQL { + buildInsertQuery( + { table, values: valuesOrSelect, onConflict, returning, withList, select }: SQLiteInsertConfig, + ): SQL { // const isSingleValue = values.length === 1; const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = []; const columns: Record = table[Table.Symbol.Columns]; @@ -429,33 +436,46 @@ export abstract class SQLiteDialect { ); const insertOrder = colEntries.map(([, column]) => sql.identifier(this.casing.getColumnCasing(column))); - for (const [valueIndex, value] of values.entries()) { - const valueList: (SQLChunk | SQL)[] = []; - for (const [fieldName, col] of colEntries) { - const colValue = value[fieldName]; - if (colValue === undefined || (is(colValue, Param) && colValue.value === undefined)) { - let defaultValue; - if (col.default !== null && col.default !== undefined) { - defaultValue = is(col.default, SQL) ? col.default : sql.param(col.default, col); - // eslint-disable-next-line unicorn/no-negated-condition - } else if (col.defaultFn !== undefined) { - const defaultFnResult = col.defaultFn(); - defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col); - // eslint-disable-next-line unicorn/no-negated-condition - } else if (!col.default && col.onUpdateFn !== undefined) { - const onUpdateFnResult = col.onUpdateFn(); - defaultValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col); + if (select) { + const select = valuesOrSelect as AnySQLiteSelectQueryBuilder | SQL; + + if (is(select, SQL)) { + valuesSqlList.push(select); + } else { + valuesSqlList.push(select.getSQL()); + } + } else { + const values = valuesOrSelect as Record[]; + valuesSqlList.push(sql.raw('values ')); + + for (const [valueIndex, value] of values.entries()) { + const valueList: (SQLChunk | SQL)[] = []; + for (const [fieldName, col] of colEntries) { + const colValue = value[fieldName]; + if (colValue === undefined || (is(colValue, Param) && colValue.value === undefined)) { + let defaultValue; + if (col.default !== null && col.default !== undefined) { + defaultValue = is(col.default, SQL) ? col.default : sql.param(col.default, col); + // eslint-disable-next-line unicorn/no-negated-condition + } else if (col.defaultFn !== undefined) { + const defaultFnResult = col.defaultFn(); + defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col); + // eslint-disable-next-line unicorn/no-negated-condition + } else if (!col.default && col.onUpdateFn !== undefined) { + const onUpdateFnResult = col.onUpdateFn(); + defaultValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col); + } else { + defaultValue = sql`null`; + } + valueList.push(defaultValue); } else { - defaultValue = sql`null`; + valueList.push(colValue); } - valueList.push(defaultValue); - } else { - valueList.push(colValue); } - } - valuesSqlList.push(valueList); - if (valueIndex < values.length - 1) { - valuesSqlList.push(sql`, `); + valuesSqlList.push(valueList); + if (valueIndex < values.length - 1) { + valuesSqlList.push(sql`, `); + } } } @@ -473,7 +493,7 @@ export abstract class SQLiteDialect { // return sql`insert into ${table} default values ${onConflictSql}${returningSql}`; // } - return sql`${withSql}insert into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}${returningSql}`; + return sql`${withSql}insert into ${table} ${insertOrder} ${valuesSql}${onConflictSql}${returningSql}`; } sqlToQuery(sql: SQL, invokeSource?: 'indexes' | undefined): QueryWithTypings { diff --git a/drizzle-orm/src/sqlite-core/query-builders/insert.ts b/drizzle-orm/src/sqlite-core/query-builders/insert.ts index 4f20666c4..2c26df8df 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/insert.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/insert.ts @@ -1,4 +1,5 @@ import { entityKind, is } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; @@ -9,18 +10,20 @@ import type { IndexColumn } from '~/sqlite-core/indexes.ts'; import type { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; import type { Subquery } from '~/subquery.ts'; -import { Table } from '~/table.ts'; -import { type DrizzleTypeError, mapUpdateSet, orderSelectedFields, type Simplify } from '~/utils.ts'; -import type { SQLiteColumn } from '../columns/common.ts'; +import { Columns, Table } from '~/table.ts'; +import { type DrizzleTypeError, haveSameKeys, mapUpdateSet, orderSelectedFields, type Simplify } from '~/utils.ts'; +import type { AnySQLiteColumn, SQLiteColumn } from '../columns/common.ts'; +import { QueryBuilder } from './query-builder.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; import type { SQLiteUpdateSetSource } from './update.ts'; export interface SQLiteInsertConfig { table: TTable; - values: Record[]; + values: Record[] | SQLiteInsertSelectQueryBuilder | SQL; withList?: Subquery[]; onConflict?: SQL; returning?: SelectedFieldsOrdered; + select?: boolean; } export type SQLiteInsertValue = Simplify< @@ -29,6 +32,10 @@ export type SQLiteInsertValue = Simplify< } >; +export type SQLiteInsertSelectQueryBuilder = TypedQueryBuilder< + { [K in keyof TTable['$inferInsert']]: AnySQLiteColumn | SQL | SQL.Aliased | TTable['$inferInsert'][K] } +>; + export class SQLiteInsertBuilder< TTable extends SQLiteTable, TResultType extends 'sync' | 'async', @@ -70,6 +77,32 @@ export class SQLiteInsertBuilder< return new SQLiteInsertBase(this.table, mappedValues, this.session, this.dialect, this.withList); } + + select( + selectQuery: (qb: QueryBuilder) => SQLiteInsertSelectQueryBuilder, + ): SQLiteInsertBase; + select(selectQuery: (qb: QueryBuilder) => SQL): SQLiteInsertBase; + select(selectQuery: SQL): SQLiteInsertBase; + select(selectQuery: SQLiteInsertSelectQueryBuilder): SQLiteInsertBase; + select( + selectQuery: + | SQL + | SQLiteInsertSelectQueryBuilder + | ((qb: QueryBuilder) => SQLiteInsertSelectQueryBuilder | SQL), + ): SQLiteInsertBase { + const select = typeof selectQuery === 'function' ? selectQuery(new QueryBuilder()) : selectQuery; + + if ( + !is(select, SQL) + && !haveSameKeys(this.table[Columns], select._.selectedFields) + ) { + throw new Error( + 'Insert select error: selected fields are not the same or are in a different order compared to the table definition', + ); + } + + return new SQLiteInsertBase(this.table, select, this.session, this.dialect, this.withList, true); + } } export type SQLiteInsertWithout = @@ -210,9 +243,10 @@ export class SQLiteInsertBase< private session: SQLiteSession, private dialect: SQLiteDialect, withList?: Subquery[], + select?: boolean, ) { super(); - this.config = { table, values, withList }; + this.config = { table, values: values as any, withList, select }; } /** diff --git a/drizzle-orm/type-tests/mysql/insert.ts b/drizzle-orm/type-tests/mysql/insert.ts index b354410bd..34fcbf9ae 100644 --- a/drizzle-orm/type-tests/mysql/insert.ts +++ b/drizzle-orm/type-tests/mysql/insert.ts @@ -1,6 +1,6 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; -import { int, mysqlTable, text } from '~/mysql-core/index.ts'; +import { boolean, int, mysqlTable, QueryBuilder, serial, text } from '~/mysql-core/index.ts'; import type { MySqlInsert } from '~/mysql-core/index.ts'; import type { MySqlRawQueryResult } from '~/mysql2/index.ts'; import { sql } from '~/sql/sql.ts'; @@ -133,3 +133,75 @@ Expect>; // @ts-expect-error method was already called .onDuplicateKeyUpdate({ set: {} }); } + +{ + const users1 = mysqlTable('users1', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + admin: boolean('admin').notNull().default(false), + }); + const users2 = mysqlTable('users2', { + id: serial('id').primaryKey(), + firstName: text('first_name').notNull(), + lastName: text('last_name').notNull(), + admin: boolean('admin').notNull().default(false), + phoneNumber: text('phone_number'), + }); + + const qb = new QueryBuilder(); + + db.insert(users1).select(sql`select * from users1`); + db.insert(users1).select(() => sql`select * from users1`); + + db + .insert(users1) + .select( + qb.select({ + name: users2.firstName, + admin: users2.admin, + }).from(users2), + ); + + db + .insert(users1) + .select( + qb.select({ + name: users2.firstName, + admin: users2.admin, + }).from(users2).where(sql``), + ); + + db + .insert(users2) + .select( + qb.select({ + firstName: users2.firstName, + lastName: users2.lastName, + admin: users2.admin, + }).from(users2), + ); + + db + .insert(users1) + .select( + qb.select({ + name: sql`${users2.firstName} || ' ' || ${users2.lastName}`.as('name'), + admin: users2.admin, + }).from(users2), + ); + + db + .insert(users1) + .select( + // @ts-expect-error name is undefined + qb.select({ admin: users1.admin }).from(users1), + ); + + db.insert(users1).select(db.select().from(users1)); + db.insert(users1).select(() => db.select().from(users1)); + db.insert(users1).select((qb) => qb.select().from(users1)); + // @ts-expect-error tables have different keys + db.insert(users1).select(db.select().from(users2)); + // @ts-expect-error tables have different keys + db.insert(users1).select(() => db.select().from(users2)); +} diff --git a/drizzle-orm/type-tests/pg/insert.ts b/drizzle-orm/type-tests/pg/insert.ts index 6a5179804..78d2c3197 100644 --- a/drizzle-orm/type-tests/pg/insert.ts +++ b/drizzle-orm/type-tests/pg/insert.ts @@ -1,6 +1,7 @@ import type { QueryResult } from 'pg'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; +import { boolean, pgTable, QueryBuilder, serial, text } from '~/pg-core/index.ts'; import type { PgInsert } from '~/pg-core/query-builders/insert.ts'; import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; @@ -204,3 +205,75 @@ Expect< // @ts-expect-error method was already called .returning(); } + +{ + const users1 = pgTable('users1', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + admin: boolean('admin').notNull().default(false), + }); + const users2 = pgTable('users2', { + id: serial('id').primaryKey(), + firstName: text('first_name').notNull(), + lastName: text('last_name').notNull(), + admin: boolean('admin').notNull().default(false), + phoneNumber: text('phone_number'), + }); + + const qb = new QueryBuilder(); + + db.insert(users1).select(sql`select * from users1`); + db.insert(users1).select(() => sql`select * from users1`); + + db + .insert(users1) + .select( + qb.select({ + name: users2.firstName, + admin: users2.admin, + }).from(users2), + ); + + db + .insert(users1) + .select( + qb.select({ + name: users2.firstName, + admin: users2.admin, + }).from(users2).where(sql``), + ); + + db + .insert(users2) + .select( + qb.select({ + firstName: users2.firstName, + lastName: users2.lastName, + admin: users2.admin, + }).from(users2), + ); + + db + .insert(users1) + .select( + qb.select({ + name: sql`${users2.firstName} || ' ' || ${users2.lastName}`.as('name'), + admin: users2.admin, + }).from(users2), + ); + + db + .insert(users1) + .select( + // @ts-expect-error name is undefined + qb.select({ admin: users1.admin }).from(users1), + ); + + db.insert(users1).select(db.select().from(users1)); + db.insert(users1).select(() => db.select().from(users1)); + db.insert(users1).select((qb) => qb.select().from(users1)); + // @ts-expect-error tables have different keys + db.insert(users1).select(db.select().from(users2)); + // @ts-expect-error tables have different keys + db.insert(users1).select(() => db.select().from(users2)); +} diff --git a/drizzle-orm/type-tests/sqlite/insert.ts b/drizzle-orm/type-tests/sqlite/insert.ts index c4566ae8f..e7d9cb77d 100644 --- a/drizzle-orm/type-tests/sqlite/insert.ts +++ b/drizzle-orm/type-tests/sqlite/insert.ts @@ -3,6 +3,7 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { and, eq } from '~/expressions.ts'; import { sql } from '~/sql/sql.ts'; +import { integer, QueryBuilder, sqliteTable, text } from '~/sqlite-core/index.ts'; import type { SQLiteInsert } from '~/sqlite-core/query-builders/insert.ts'; import type { DrizzleTypeError } from '~/utils.ts'; import { bunDb, db } from './db.ts'; @@ -205,3 +206,75 @@ stmt.run({ id: 1, limit: 10, offset: 20 }); // @ts-expect-error method was already called .returning(); } + +{ + const users1 = sqliteTable('users1', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + admin: integer('admin', { mode: 'boolean' }).notNull().default(false), + }); + const users2 = sqliteTable('users2', { + id: integer('id').primaryKey(), + firstName: text('first_name').notNull(), + lastName: text('last_name').notNull(), + admin: integer('admin', { mode: 'boolean' }).notNull().default(false), + phoneNumber: text('phone_number'), + }); + + const qb = new QueryBuilder(); + + db.insert(users1).select(sql`select * from users1`); + db.insert(users1).select(() => sql`select * from users1`); + + db + .insert(users1) + .select( + qb.select({ + name: users2.firstName, + admin: users2.admin, + }).from(users2), + ); + + db + .insert(users1) + .select( + qb.select({ + name: users2.firstName, + admin: users2.admin, + }).from(users2).where(sql``), + ); + + db + .insert(users2) + .select( + qb.select({ + firstName: users2.firstName, + lastName: users2.lastName, + admin: users2.admin, + }).from(users2), + ); + + db + .insert(users1) + .select( + qb.select({ + name: sql`${users2.firstName} || ' ' || ${users2.lastName}`.as('name'), + admin: users2.admin, + }).from(users2), + ); + + db + .insert(users1) + .select( + // @ts-expect-error name is undefined + qb.select({ admin: users1.admin }).from(users1), + ); + + db.insert(users1).select(db.select().from(users1)); + db.insert(users1).select(() => db.select().from(users1)); + db.insert(users1).select((qb) => qb.select().from(users1)); + // @ts-expect-error tables have different keys + db.insert(users1).select(db.select().from(users2)); + // @ts-expect-error tables have different keys + db.insert(users1).select(() => db.select().from(users2)); +} diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index e2695d767..a2a0baeb0 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -3978,4 +3978,126 @@ export function tests(driver?: string) { await db.execute(sql`drop table users`); }); }); + + test('insert into ... select', async (ctx) => { + const { db } = ctx.mysql; + + const notifications = mysqlTable('notifications', { + id: serial('id').primaryKey(), + sentAt: timestamp('sent_at').notNull().defaultNow(), + message: text('message').notNull(), + }); + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + const userNotications = mysqlTable('user_notifications', { + userId: int('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }), + notificationId: int('notification_id').notNull().references(() => notifications.id, { onDelete: 'cascade' }), + }, (t) => ({ + pk: primaryKey({ columns: [t.userId, t.notificationId] }), + })); + + await db.execute(sql`drop table if exists ${notifications}`); + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop table if exists ${userNotications}`); + await db.execute(sql` + create table ${notifications} ( + \`id\` serial primary key, + \`sent_at\` timestamp not null default now(), + \`message\` text not null + ) + `); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` text not null + ) + `); + await db.execute(sql` + create table ${userNotications} ( + \`user_id\` int references users(id) on delete cascade, + \`notification_id\` int references notifications(id) on delete cascade, + primary key (user_id, notification_id) + ) + `); + + await db + .insert(notifications) + .values({ message: 'You are one of the 3 lucky winners!' }); + const newNotification = await db + .select({ id: notifications.id }) + .from(notifications) + .then((result) => result[0]); + + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + await db + .insert(userNotications) + .select( + db + .select({ + userId: users.id, + notificationId: sql`(${newNotification!.id})`.as('notification_id'), + }) + .from(users) + .where(inArray(users.name, ['Alice', 'Charlie', 'Eve'])) + .orderBy(asc(users.id)), + ); + const sentNotifications = await db.select().from(userNotications); + + expect(sentNotifications).toStrictEqual([ + { userId: 1, notificationId: newNotification!.id }, + { userId: 3, notificationId: newNotification!.id }, + { userId: 5, notificationId: newNotification!.id }, + ]); + }); + + test('insert into ... select with keys in different order', async (ctx) => { + const { db } = ctx.mysql; + + const users1 = mysqlTable('users1', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + const users2 = mysqlTable('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users1}`); + await db.execute(sql`drop table if exists ${users2}`); + await db.execute(sql` + create table ${users1} ( + \`id\` serial primary key, + \`name\` text not null + ) + `); + await db.execute(sql` + create table ${users2} ( + \`id\` serial primary key, + \`name\` text not null + ) + `); + + expect( + () => + db + .insert(users1) + .select( + db + .select({ + name: users2.name, + id: users2.id, + }) + .from(users2), + ), + ).toThrowError(); + }); } diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 17495afac..49d9c3025 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -4909,6 +4909,127 @@ export function tests() { }]); }); + test('insert into ... select', async (ctx) => { + const { db } = ctx.pg; + + const notifications = pgTable('notifications', { + id: serial('id').primaryKey(), + sentAt: timestamp('sent_at').notNull().defaultNow(), + message: text('message').notNull(), + }); + const users = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + const userNotications = pgTable('user_notifications', { + userId: integer('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }), + notificationId: integer('notification_id').notNull().references(() => notifications.id, { + onDelete: 'cascade', + }), + }, (t) => ({ + pk: primaryKey({ columns: [t.userId, t.notificationId] }), + })); + + await db.execute(sql`drop table if exists notifications`); + await db.execute(sql`drop table if exists users`); + await db.execute(sql`drop table if exists user_notifications`); + await db.execute(sql` + create table notifications ( + id serial primary key, + sent_at timestamp not null default now(), + message text not null + ) + `); + await db.execute(sql` + create table users ( + id serial primary key, + name text not null + ) + `); + await db.execute(sql` + create table user_notifications ( + user_id int references users(id) on delete cascade, + notification_id int references notifications(id) on delete cascade, + primary key (user_id, notification_id) + ) + `); + + const newNotification = await db + .insert(notifications) + .values({ message: 'You are one of the 3 lucky winners!' }) + .returning({ id: notifications.id }) + .then((result) => result[0]); + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + const sentNotifications = await db + .insert(userNotications) + .select( + db + .select({ + userId: users.id, + notificationId: sql`${newNotification!.id}`.as('notification_id'), + }) + .from(users) + .where(inArray(users.name, ['Alice', 'Charlie', 'Eve'])) + .orderBy(asc(users.id)), + ) + .returning(); + + expect(sentNotifications).toStrictEqual([ + { userId: 1, notificationId: newNotification!.id }, + { userId: 3, notificationId: newNotification!.id }, + { userId: 5, notificationId: newNotification!.id }, + ]); + }); + + test('insert into ... select with keys in different order', async (ctx) => { + const { db } = ctx.pg; + + const users1 = pgTable('users1', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + const users2 = pgTable('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists users1`); + await db.execute(sql`drop table if exists users2`); + await db.execute(sql` + create table users1 ( + id serial primary key, + name text not null + ) + `); + await db.execute(sql` + create table users2 ( + id serial primary key, + name text not null + ) + `); + + expect( + () => + db + .insert(users1) + .select( + db + .select({ + name: users2.name, + id: users2.id, + }) + .from(users2), + ), + ).toThrowError(); + }); + test('policy', () => { { const policy = pgPolicy('test policy'); diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 5cfcb45bd..f53e85758 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -3244,6 +3244,124 @@ export function tests() { }]); }); + test('insert into ... select', async (ctx) => { + const { db } = ctx.sqlite; + + const notifications = sqliteTable('notifications', { + id: integer('id').primaryKey({ autoIncrement: true }), + sentAt: integer('sent_at', { mode: 'timestamp' }).notNull().default(sql`current_timestamp`), + message: text('message').notNull(), + }); + const users = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }); + const userNotications = sqliteTable('user_notifications', { + userId: integer('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }), + notificationId: integer('notification_id').notNull().references(() => notifications.id, { onDelete: 'cascade' }), + }, (t) => ({ + pk: primaryKey({ columns: [t.userId, t.notificationId] }), + })); + + await db.run(sql`drop table if exists notifications`); + await db.run(sql`drop table if exists users`); + await db.run(sql`drop table if exists user_notifications`); + await db.run(sql` + create table notifications ( + id integer primary key autoincrement, + sent_at integer not null default (current_timestamp), + message text not null + ) + `); + await db.run(sql` + create table users ( + id integer primary key autoincrement, + name text not null + ) + `); + await db.run(sql` + create table user_notifications ( + user_id integer references users(id) on delete cascade, + notification_id integer references notifications(id) on delete cascade, + primary key (user_id, notification_id) + ) + `); + + const newNotification = await db + .insert(notifications) + .values({ message: 'You are one of the 3 lucky winners!' }) + .returning({ id: notifications.id }) + .then((result) => result[0]); + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + const sentNotifications = await db + .insert(userNotications) + .select( + db + .select({ + userId: users.id, + notificationId: sql`${newNotification!.id}`.as('notification_id'), + }) + .from(users) + .where(inArray(users.name, ['Alice', 'Charlie', 'Eve'])) + .orderBy(asc(users.id)), + ) + .returning(); + + expect(sentNotifications).toStrictEqual([ + { userId: 1, notificationId: newNotification!.id }, + { userId: 3, notificationId: newNotification!.id }, + { userId: 5, notificationId: newNotification!.id }, + ]); + }); + + test('insert into ... select with keys in different order', async (ctx) => { + const { db } = ctx.sqlite; + + const users1 = sqliteTable('users1', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }); + const users2 = sqliteTable('users2', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + }); + + await db.run(sql`drop table if exists users1`); + await db.run(sql`drop table if exists users2`); + await db.run(sql` + create table users1 ( + id integer primary key autoincrement, + name text not null + ) + `); + await db.run(sql` + create table users2 ( + id integer primary key autoincrement, + name text not null + ) + `); + + await expect(async () => { + db + .insert(users1) + .select( + db + .select({ + name: users2.name, + id: users2.id, + }) + .from(users2), + ); + }).rejects.toThrowError(); + }); + test('Object keys as column names', async (ctx) => { const { db } = ctx.sqlite; diff --git a/integration-tests/tests/sqlite/sqlite-proxy.test.ts b/integration-tests/tests/sqlite/sqlite-proxy.test.ts index 9066b2bec..2aec14be5 100644 --- a/integration-tests/tests/sqlite/sqlite-proxy.test.ts +++ b/integration-tests/tests/sqlite/sqlite-proxy.test.ts @@ -72,7 +72,7 @@ beforeAll(async () => { return { rows: rows.data }; } catch (e: any) { - console.error('Error from sqlite proxy server:', e.response.data); + console.error('Error from sqlite proxy server:', e.response?.data ?? e.message); throw e; } }); From 44b6c8a630544470de5e049ddf91267f6857ff99 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 15 Nov 2024 13:51:17 +0200 Subject: [PATCH 363/492] Fix tests for libsql and sqlite --- .../tests/sqlite/sqlite-common.ts | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index f53e85758..1c62181dd 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -153,6 +153,9 @@ export function tests() { await db.run(sql`drop table if exists ${orders}`); await db.run(sql`drop table if exists ${bigIntExample}`); await db.run(sql`drop table if exists ${pkExampleTable}`); + await db.run(sql`drop table if exists user_notifications_insert_into`); + await db.run(sql`drop table if exists users_insert_into`); + await db.run(sql`drop table if exists notifications_insert_into`); await db.run(sql` create table ${usersTable} ( @@ -3247,42 +3250,42 @@ export function tests() { test('insert into ... select', async (ctx) => { const { db } = ctx.sqlite; - const notifications = sqliteTable('notifications', { + const notifications = sqliteTable('notifications_insert_into', { id: integer('id').primaryKey({ autoIncrement: true }), sentAt: integer('sent_at', { mode: 'timestamp' }).notNull().default(sql`current_timestamp`), message: text('message').notNull(), }); - const users = sqliteTable('users', { + const users = sqliteTable('users_insert_into', { id: integer('id').primaryKey({ autoIncrement: true }), name: text('name').notNull(), }); - const userNotications = sqliteTable('user_notifications', { + const userNotications = sqliteTable('user_notifications_insert_into', { userId: integer('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }), notificationId: integer('notification_id').notNull().references(() => notifications.id, { onDelete: 'cascade' }), }, (t) => ({ pk: primaryKey({ columns: [t.userId, t.notificationId] }), })); - await db.run(sql`drop table if exists notifications`); - await db.run(sql`drop table if exists users`); - await db.run(sql`drop table if exists user_notifications`); + await db.run(sql`drop table if exists notifications_insert_into`); + await db.run(sql`drop table if exists users_insert_into`); + await db.run(sql`drop table if exists user_notifications_insert_into`); await db.run(sql` - create table notifications ( + create table notifications_insert_into ( id integer primary key autoincrement, sent_at integer not null default (current_timestamp), message text not null ) `); await db.run(sql` - create table users ( + create table users_insert_into ( id integer primary key autoincrement, name text not null ) `); await db.run(sql` - create table user_notifications ( - user_id integer references users(id) on delete cascade, - notification_id integer references notifications(id) on delete cascade, + create table user_notifications_insert_into ( + user_id integer references users_insert_into(id) on delete cascade, + notification_id integer references notifications_insert_into(id) on delete cascade, primary key (user_id, notification_id) ) `); From dae82190075cee1967370786936d4d97e3465106 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 15 Nov 2024 15:51:46 +0200 Subject: [PATCH 364/492] Bump version and add release notes --- changelogs/drizzle-orm/0.36.3.md | 154 +++++++++++++++++++++++++++++++ drizzle-orm/package.json | 4 +- 2 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 changelogs/drizzle-orm/0.36.3.md diff --git a/changelogs/drizzle-orm/0.36.3.md b/changelogs/drizzle-orm/0.36.3.md new file mode 100644 index 000000000..4602f348e --- /dev/null +++ b/changelogs/drizzle-orm/0.36.3.md @@ -0,0 +1,154 @@ +# New Features + +## Support for `UPDATE ... FROM` in PostgreSQL and SQLite + +As the SQLite documentation mentions: + +> [!NOTE] +> The UPDATE-FROM idea is an extension to SQL that allows an UPDATE statement to be driven by other tables in the database. +The "target" table is the specific table that is being updated. With UPDATE-FROM you can join the target table +against other tables in the database in order to help compute which rows need updating and what +the new values should be on those rows + +Similarly, the PostgreSQL documentation states: + +> [!NOTE] +> A table expression allowing columns from other tables to appear in the WHERE condition and update expressions + +Drizzle also supports this feature starting from this version + +For example, current query: + +```ts +await db + .update(users) + .set({ cityId: cities.id }) + .from(cities) + .where(and(eq(cities.name, 'Seattle'), eq(users.name, 'John'))) +``` + +Will generate this sql + +```sql +update "users" set "city_id" = "cities"."id" +from "cities" +where ("cities"."name" = $1 and "users"."name" = $2) + +-- params: [ 'Seattle', 'John' ] +``` + +You can also alias tables that are joined (in PG, you can also alias the updating table too). + +```ts +const c = alias(cities, 'c'); +await db + .update(users) + .set({ cityId: c.id }) + .from(c); +``` + +Will generate this sql + +```sql +update "users" set "city_id" = "c"."id" +from "cities" "c" +``` + +In PostgreSQL, you can also return columns from the joined tables. + +```ts +const updatedUsers = await db + .update(users) + .set({ cityId: cities.id }) + .from(cities) + .returning({ id: users.id, cityName: cities.name }); +``` + +Will generate this sql + +```sql +update "users" set "city_id" = "cities"."id" +from "cities" +returning "users"."id", "cities"."name" +``` + +## Support for `INSERT INTO ... SELECT` in all dialects + +As the SQLite documentation mentions: + +> [!NOTE] +> The second form of the INSERT statement contains a SELECT statement instead of a VALUES clause. +A new entry is inserted into the table for each row of data returned by executing the SELECT statement. +If a column-list is specified, the number of columns in the result of the SELECT must be the same as +the number of items in the column-list. Otherwise, if no column-list is specified, the number of +columns in the result of the SELECT must be the same as the number of columns in the table. +Any SELECT statement, including compound SELECTs and SELECT statements with ORDER BY and/or LIMIT clauses, +may be used in an INSERT statement of this form. + +> [!CAUTION] +> To avoid a parsing ambiguity, the SELECT statement should always contain a WHERE clause, even if that clause is simply "WHERE true", if the upsert-clause is present. Without the WHERE clause, the parser does not know if the token "ON" is part of a join constraint on the SELECT, or the beginning of the upsert-clause. + +As the PostgreSQL documentation mentions: +> [!NOTE] +> A query (SELECT statement) that supplies the rows to be inserted + +And as the MySQL documentation mentions: + +> [!NOTE] +> With INSERT ... SELECT, you can quickly insert many rows into a table from the result of a SELECT statement, which can select from one or many tables + +Drizzle supports the current syntax for all dialects, and all of them share the same syntax. Let's review some common scenarios and API usage. +There are several ways to use select inside insert statements, allowing you to choose your preferred approach: + +- You can pass a query builder inside the select function. +- You can use a query builder inside a callback. +- You can pass an SQL template tag with any custom select query you want to use + +**Query Builder** + +```ts +const insertedEmployees = await db + .insert(employees) + .select( + db.select({ name: users.name }).from(users).where(eq(users.role, 'employee')) + ) + .returning({ + id: employees.id, + name: employees.name + }); +``` + +```ts +const qb = new QueryBuilder(); +await db.insert(employees).select( + qb.select({ name: users.name }).from(users).where(eq(users.role, 'employee')) +); +``` + +**Callback** + +```ts +await db.insert(employees).select( + () => db.select({ name: users.name }).from(users).where(eq(users.role, 'employee')) +); +``` + +```ts +await db.insert(employees).select( + (qb) => qb.select({ name: users.name }).from(users).where(eq(users.role, 'employee')) +); +``` + +**SQL template tag** + +```ts +await db.insert(employees).select( + sql`select "users"."name" as "name" from "users" where "users"."role" = 'employee'` +); +``` + +```ts +await db.insert(employees).select( + () => sql`select "users"."name" as "name" from "users" where "users"."role" = 'employee'` +); +``` diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 41852bfa7..e43462fb0 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.36.2", + "version": "0.36.3", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -203,4 +203,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} +} \ No newline at end of file From 30e5347c5b363e4ae5e30be78ac0bf64feaf98d4 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 15 Nov 2024 16:00:51 +0200 Subject: [PATCH 365/492] dprint!!! --- drizzle-orm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index e43462fb0..fedd4073c 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -203,4 +203,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} \ No newline at end of file +} From 3a2d559078d68d4ffa7cd9b7d3c738516fd9776c Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Fri, 15 Nov 2024 18:47:19 +0200 Subject: [PATCH 366/492] added error for with in refinements --- drizzle-seed/src/services/SeedService.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index c023e7d5f..4ec70118b 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -66,7 +66,8 @@ class SeedService { // console.log("relations:", relations); // sorting table in order which they will be filled up (tables with foreign keys case) // relations = relations.filter(rel => rel.type === "one"); - const orderedTablesNames = this.getOrderedTablesList(relations); + const tablesInOutRelations = this.getTablesInOutRelations(relations); + const orderedTablesNames = this.getOrderedTablesList(tablesInOutRelations); tables = tables.sort((tabel1, tabel2) => { const tabel1Order = orderedTablesNames.indexOf( tabel1.name, @@ -120,6 +121,15 @@ class SeedService { refinements[table.name]!.with as {}, ) ) { + if (!tablesInOutRelations[table.name]?.dependantTableNames.has(fkTableName)) { + const reason = tablesInOutRelations[table.name]?.selfRelation === true + ? `"${table.name}" table has self reference` + : `"${fkTableName}" table doesn't have reference to "${table.name}" table`; + throw new Error( + `${reason}. you can't specify "${fkTableName}" as parameter in ${table.name}.with object.`, + ); + } + idx = tablesPossibleGenerators.findIndex( (table) => table.tableName === fkTableName, ); @@ -246,9 +256,9 @@ class SeedService { return tablesPossibleGenerators; }; - getOrderedTablesList = (relations: Relation[]): string[] => { + getOrderedTablesList = (tablesInOutRelations: ReturnType): string[] => { // console.time("getOrderedTablesList"); - const tablesInOutRelations = this.getTablesInOutRelations(relations); + // const tablesInOutRelations = this.getTablesInOutRelations(relations); const leafTablesNames = Object.entries(tablesInOutRelations) .filter( @@ -280,11 +290,9 @@ class SeedService { continue; } - tablesInOutRelations[parent]!.requiredTableNames = new Set( - [...tablesInOutRelations[parent]!.requiredTableNames.values()].filter( - (tableName) => !orderedTablesNames.includes(tableName), - ), - ); + for (const orderedTableName of orderedTablesNames) { + tablesInOutRelations[parent]!.requiredTableNames.delete(orderedTableName); + } if (tablesInOutRelations[parent]!.requiredTableNames.size === 0) { orderedTablesNames.push(parent); From de52746d34f20f6c6fb71bdce777562970e89417 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 18 Nov 2024 17:48:34 +0200 Subject: [PATCH 367/492] changed some files formatting --- drizzle-orm/package.json | 2 +- drizzle-orm/src/pg-core/dialect.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index e43462fb0..fedd4073c 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -203,4 +203,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} \ No newline at end of file +} diff --git a/drizzle-orm/src/pg-core/dialect.ts b/drizzle-orm/src/pg-core/dialect.ts index 785d993a9..cce3394e5 100644 --- a/drizzle-orm/src/pg-core/dialect.ts +++ b/drizzle-orm/src/pg-core/dialect.ts @@ -491,7 +491,9 @@ export class PgDialect { return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; } - buildInsertQuery({ table, values: valuesOrSelect, onConflict, returning, withList, select, overridingSystemValue_ }: PgInsertConfig): SQL { + buildInsertQuery( + { table, values: valuesOrSelect, onConflict, returning, withList, select, overridingSystemValue_ }: PgInsertConfig, + ): SQL { const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = []; const columns: Record = table[Table.Symbol.Columns]; From 13baf35e967ebd2da32242d19e53837b288f1277 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Wed, 20 Nov 2024 17:52:17 +0200 Subject: [PATCH 368/492] fixes --- .gitignore | 3 +- drizzle-orm/src/pg-core/dialect.ts | 2 +- .../src/pg-core/query-builders/insert.ts | 1 + drizzle-seed/README.md | 10 +- drizzle-seed/src/datasets/cityNames.ts | 85409 ++++++++-------- drizzle-seed/src/datasets/countries.ts | 2 - drizzle-seed/src/datasets/phonesInfo.ts | 24 - .../src/services/GeneratorsWrappers.ts | 102 +- .../pg/generatorsTest/generators.test.ts | 10 +- 9 files changed, 42706 insertions(+), 42857 deletions(-) diff --git a/.gitignore b/.gitignore index 3d7b1e447..570a706f8 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ dist-dts rollup.config-*.mjs *.log .DS_Store -drizzle-seed/src/test.ts \ No newline at end of file +drizzle-seed/src/test.ts +drizzle-seed/src/schemaTest.ts \ No newline at end of file diff --git a/drizzle-orm/src/pg-core/dialect.ts b/drizzle-orm/src/pg-core/dialect.ts index cce3394e5..52bd10ed5 100644 --- a/drizzle-orm/src/pg-core/dialect.ts +++ b/drizzle-orm/src/pg-core/dialect.ts @@ -557,7 +557,7 @@ export class PgDialect { const overridingSql = overridingSystemValue_ === true ? sql`overriding system value ` : undefined; - return sql`${withSql}insert into ${table} ${insertOrder} ${overridingSql}values ${valuesSql}${onConflictSql}${returningSql}`; + return sql`${withSql}insert into ${table} ${insertOrder} ${overridingSql}${valuesSql}${onConflictSql}${returningSql}`; } buildRefreshMaterializedViewQuery( diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index 60b557b76..b1a39fa05 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -93,6 +93,7 @@ export class PgInsertBuilder< this.session, this.dialect, this.withList, + false, this.overridingSystemValue_, ); } diff --git a/drizzle-seed/README.md b/drizzle-seed/README.md index 8b659e882..8476e03b5 100644 --- a/drizzle-seed/README.md +++ b/drizzle-seed/README.md @@ -584,7 +584,7 @@ generates integers with given range. await seed(db, schema, { count: 1000 }).refine((funcs) => ({ products: { columns: { - unitsInStock: funcs.number({ + unitsInStock: funcs.int({ minValue: 0, maxValue: 100, isUnique: false, @@ -682,7 +682,9 @@ await seed(db, schema, { count: 1000 }).refine((funcs) => ({ #### **year** -generates years. ("2024") +generates years. + +example of generated value: "2024" ```ts await seed(db, schema, { count: 1000 }).refine((funcs) => ({ @@ -742,7 +744,7 @@ await seed(db, schema, { count: 1000 }).refine((funcs) => ({ generates time intervals. -interval example: "1 years 12 days 5 minutes" +example of generated value: "1 years 12 days 5 minutes" `isUnique` - property that controls if generated values gonna be unique or not. @@ -921,7 +923,7 @@ generates city's names. await seed(db, schema, { count: 1000 }).refine((funcs) => ({ users: { columns: { - city: funcs.cityName({ isUnique: false }), + city: funcs.city({ isUnique: false }), }, }, })); diff --git a/drizzle-seed/src/datasets/cityNames.ts b/drizzle-seed/src/datasets/cityNames.ts index bcec411bb..e358a0b31 100644 --- a/drizzle-seed/src/datasets/cityNames.ts +++ b/drizzle-seed/src/datasets/cityNames.ts @@ -1,42986 +1,42855 @@ export default [ - 'Tokyo', - 'Jakarta', - 'Delhi', - 'Guangzhou', - 'Mumbai', - 'Manila', - 'Shanghai', - 'Sao Paulo', - 'Seoul', - 'Mexico City', - 'Cairo', - 'New York', - 'Dhaka', - 'Beijing', - 'Kolkata', - 'Bangkok', - 'Shenzhen', - 'Buenos Aires', - 'Lagos', - 'Istanbul', - 'Karachi', - 'Bangalore', - 'Ho Chi Minh City', - 'Osaka', - 'Chengdu', - 'Tehran', - 'Kinshasa', - 'Rio de Janeiro', - 'Chennai', - "Xi'an", - 'Lahore', - 'Chongqing', - 'Los Angeles', - 'Baoding', - 'London', - 'Paris', - 'Linyi', - 'Dongguan', - 'Hyderabad', - 'Tianjin', - 'Lima', - 'Wuhan', - 'Nanyang', - 'Hangzhou', - 'Foshan', - 'Nagoya', - 'Tongshan', - 'Luanda', - 'Zhoukou', - 'Ganzhou', - 'Kuala Lumpur', - 'Heze', - 'Quanzhou', - 'Johannesburg', - 'Chicago', - 'Nanjing', - 'Jining', - 'Hanoi', - 'Pune', - 'Fuyang', - 'Ahmedabad', - 'Bogota', - 'Shenyang', - 'Dar es Salaam', - 'Khartoum', - 'Shangqiu', - 'Hong Kong', - 'Cangzhou', - 'Riyadh', - 'Santiago', - 'Xingtai', - 'Zhumadian', - 'Chattogram', - 'Surabaya', - 'Zhanjiang', - 'Bijie', - 'Yancheng', - 'Hengyang', - 'Zunyi', - 'Shaoyang', - 'Surat', - 'Shangrao', - 'Xinyang', - 'Madrid', - 'Baghdad', - 'Maoming', - 'Jieyang', - 'Miami', - 'Singapore', - 'Houston', - 'Liaocheng', - 'Huanggang', - 'Dalian', - 'Dallas', - 'Qingdao', - 'Yulin', + 'Humpata', + 'Qunghirot', + 'Erdek', + 'Asenovgrad', + 'Payyoli', + 'Pidhorodne', + 'Clawson', + 'Kala Diara', + 'Kadan', + 'Tumut', + 'Bayat', + 'Gangoli', + 'Nuqui', + 'Lochau', + 'Albignasego', + 'Narayanganj', + 'Novo Lino', + 'Regeneracao', + 'Belvedere Marittimo', + 'Santana de Parnaiba', + 'Miyako', + 'Aniche', + 'Andrijevica', + 'Buggenhout', + 'Kurikka', + 'Milanowek', + 'Liaquatpur', + 'Khamaria', + 'Jora Khurd', + 'Petal', + 'Pak Tin Pa', + 'Xiantangcun', + 'Bovingdon', + 'Lianmuqin Kancun', + 'Sainte-Maxime', + 'Campinorte', + 'Vammanal', + 'Yabelo', + 'Wani', + 'Kaita', + 'Monkey Bay', + 'Ianapera', + 'Mariestad', + 'Bukomansimbi', + 'Kavaje', + 'Amahai', + 'Luis Alves', + 'Altmunster', + 'Spring Lake', + 'Niemasson', 'Douala', - 'Qujing', - 'Nangandao', - 'Philadelphia', - 'Pudong', - 'Toronto', - 'Zhengzhou', - 'Dezhou', - 'Nanchong', - 'Jinan', - 'Giza', - 'Nairobi', - 'Guadalajara', - 'Ankara', - "Tai'an", - 'Langfang', - 'Dazhou', - 'Monterrey', - 'Belo Horizonte', - 'Suzhou', - 'Yongzhou', - 'Changde', - 'Xiangyang', - 'Rangoon', - 'Atlanta', - 'Washington', - 'Zhaotong', - 'Zhangzhou', - 'Melbourne', - 'Yichun', - 'Bozhou', - 'Suqian', - 'Abidjan', - "Ji'an", - 'Guilin', - 'Pingdingshan', - 'Berlin', - 'Alexandria', - 'Mianyang', - 'Sydney', - 'Huanglongsi', - 'Barcelona', - 'Yuncheng', - 'Cape Town', - 'Changsha', - 'Jeddah', - 'Weinan', - 'Chenzhou', - 'Jiangmen', - 'Jiujiang', - 'Xinpu', - 'Yibin', - 'Huaihua', - 'Yangzhou', - 'Taizhou', - 'Kunming', - 'Yiyang', - 'Changchun', - "Lu'an", - 'Jiangguanchi', - 'Meizhou', - 'Urumqi', - 'Boston', - 'Izmir', - 'Guigang', - 'Shantou', - 'Kabul', - 'Xiaoganzhan', - 'Bamako', - 'Luzhou', - 'Hefei', - 'Hengshui', - 'Fortaleza', - 'Anqing', - 'Liuzhou', - 'Zhangjiakou', - 'Zhaoqing', - 'Shijiazhuang', - 'Ningbo', - 'Qiqihar', - 'Phoenix', - 'Fuzhou', - 'Chifeng', - 'Xiaoxita', - 'Amman', - 'Chuzhou', - 'Linfen', - 'Qingyuan', - 'Xianyang', - 'Loudi', - 'Binzhou', - 'Zhuzhou', - 'Taiyuan', - 'Nanning', - 'Harbin', - 'Abuja', - 'Yokohama', - 'Suihua', - 'Zaozhuang', - 'Detroit', - 'Xiamen', - 'Neijiang', - 'Montreal', - 'Baicheng', - 'Wuhu', - 'Yulinshi', - 'Medan', - 'Wenzhou', - 'Changzhou', - 'Puyang', - 'Jiaozuo', - 'Nanchang', - 'Seattle', - 'Ibadan', - 'Casablanca', - 'Kumasi', - 'Deyang', - 'Busan', - 'Hohhot', - 'Hechi', - 'Algiers', - 'Tangshan', - 'Shiyan', - 'Lucknow', - 'Mashhad', - 'San Francisco', - 'Boankra', - 'Dubai', - 'Anshan', - 'Baojishi', - 'Qinzhou', - 'Guiyang', - 'Bengbu', - 'Bazhou', - 'Suining', - 'Wuxi', - 'Kotla Qasim Khan', - 'Hanzhong', - 'Putian', - 'Zhenjiang', - "Guang'an", - 'Faisalabad', - 'Changzhi', - 'Tongren', - 'Leshan', - 'Santa Cruz de la Sierra', - 'Qinhuangdao', - 'Jaipur', - 'Xinzhou', - 'Lanzhou', - 'Wuzhou', - 'Athens', - 'San Diego', - 'Addis Ababa', - 'Taichung', - 'Huainan', - 'Guatemala City', - 'Kuwait City', - 'Budapest', - 'Qincheng', - 'Rizhao', - 'Quezon City', - 'Sanaa', - 'Tashkent', - 'Kyiv', - 'Meishan', - 'Incheon', - 'Birmingham', - 'Ningde', - 'Zhongshan', - 'Weihai', - 'Bursa', - 'Minneapolis', - 'Mbuji-Mayi', - 'Haikou', - 'Tongliao', - 'Chaoyang', - 'La Paz', - 'Pyongyang', - 'Tampa', - 'Shaoguan', - 'Heyuan', - 'Brasilia', - 'Omdurman', - 'Malang', - 'Stuttgart', - 'Daqing', - 'Rome', - 'Brooklyn', - 'Kaohsiung', - 'Xiangtan', - 'Longyan', - 'Baotou', - 'Handan', - 'Jinzhou', - 'Kanpur', - 'Denver', - 'Nanping', - 'Gazipura', - 'Shanwei', - 'Chaozhou', - 'Guayaquil', - 'Weifang', - "Huai'an", - 'Zibo', - 'Ankang', - 'Mogadishu', - 'Munich', - 'Gulou', - 'Taipei', - 'Bekasi', - 'Damascus', - 'Sanming', - 'Yangjiang', - 'Jiamusi', - 'Luohe', - 'Medellin', - 'Dingxi', - 'Shaoxing', - 'Yantai', - 'Huizhou', - 'Lishui', - 'Xuanzhou', - 'Khowrhesht', - 'Mirzapur', - 'Zigong', - 'Hamburg', - 'Guangyuan', - 'Cali', - 'Huangshi', - 'Xining', - 'Lusaka', - 'Ouagadougou', - 'Yaounde', - 'Zhuhai', - 'Huludao', - 'Baoshan', - 'Mecca', - 'Vancouver', - 'Lianshan', - 'Beirut', - 'Salvador', - 'Bucharest', - 'Longba', - 'Nagpur', - 'Queens', - 'Jilin', - 'Tieling', - 'Accra', - 'Yunfu', - 'Bekasi Kota', - 'Daegu', - 'Ghaziabad', - 'Luoyang', - 'Brisbane', - 'Anshun', - 'Riverside', - 'Yingkou', - 'Colombo', - 'Yanjiang', - 'Baku', - 'Antananarivo', - 'Mudanjiang', - 'Fukuoka', - "Yan'an", - 'Jincheng', - 'Nantong', - 'Lincang', - 'Yuxi', - 'Las Vegas', - 'Caracas', - 'Tangerang', - 'Laibin', - 'Konya', - 'Supaul', - 'Vienna', - 'Esfahan', - 'Baltimore', - 'Shengli', - 'Dandong', - 'Qinbaling', - 'Gaoping', - 'Awka', - "Ma'anshan", - 'Harare', - 'Perth', - 'St. Louis', - 'Phnom Penh', - 'Depok', - 'Stockholm', - 'Puning', - 'Huaibei', - 'Kowloon', - 'Cordoba', - 'Haiphong', - 'Zamboanga City', - 'Chongzuo', - 'Rawalpindi', - 'Portland', - 'Kano', - 'Yushan', - 'Havana', - 'Hezhou', - 'Pingliang', - 'Vadodara', - 'Manaus', - 'Qingyang', - 'San Antonio', - 'Rajkot', - 'Shangzhou', - 'Vishakhapatnam', - 'Sanmenxia', - 'Gujranwala', - 'Aleppo', - 'Tijuana', - 'Bamenda', - 'Minsk', - 'Indore', - 'Karaj', - 'Kananga', - 'Peshawar', - 'Sapporo', - 'Sacramento', - 'Tilburg', - 'Pingxiang', - 'Ecatepec', - 'Almaty', - 'Austin', - 'Yinchuan', - 'Santos', - 'Blantyre', - 'Thane', - 'Orlando', - 'Tainan', - 'Xiping', - 'Multan', - 'Santa Cruz', - 'Port Harcourt', - 'Jixi', - 'Fushun', - 'Warsaw', - 'Beihai', - 'Fuxin', - 'Wuwei', - 'Siping', - 'San Juan', - 'Mersin', - 'Bhopal', - 'Mosul', - 'Lubumbashi', - 'Davao', - 'Curitiba', - 'San Jose', - 'Shuyangzha', - 'Adana', - 'Quito', - 'Pittsburgh', - 'Brazzaville', - 'Hyderabad City', - 'Diyarbakir', - 'Indianapolis', - 'Pimpri-Chinchwad', - 'Masqat', - 'Montevideo', - 'Shuozhou', - 'Manhattan', - 'Cincinnati', - 'Kansas City', - 'Patna', - 'Tegucigalpa', - 'Kampala', - 'Cleveland', - 'Sanzhou', - 'Changshu', - 'Heihe', - 'Conakry', - 'Ximeicun', - 'Caloocan City', - 'Masvingo', - 'Zhongli', - 'Bilaspur', - 'Semarang', - 'Jingdezhen', - 'Ludhiana', - 'Liaoyang', - 'Chengtangcun', - 'Rajshahi', - 'Balandougou', - 'Jiangyin', - 'Valencia', - 'Agra', - 'Leon de los Aldama', - 'Puebla', - 'Columbus', - 'Yopougon', - 'Hebi', - 'Shiraz', - 'Madurai', - 'Huzhou', - 'Tabriz', - 'Jamshedpur', - 'Maracaibo', - 'Sofia', - 'Prayagraj', - 'Palembang', - 'Kawasaki', - 'Kobe', - 'Jiaxing', - 'Kigali', - 'Zhangjiajie', - 'Baiyin', - 'Guiping', - 'Lianjiang', - 'Jianguang', - 'Yucheng', - 'Xushan', - 'Panama City', - 'Nneyi-Umuleri', - 'Leizhou', - 'Gwangju', - 'Katako-Kombe', - 'Recife', - 'Nasik', - 'Onitsha', - 'Abu Dhabi', - 'Zapopan', - 'Daejeon', - 'Bronx', - 'Huazhou', - 'Jinhua', - 'Kyoto', - 'Amsterdam', - 'Pizhou', - 'Kismaayo', - 'Yangshe', - 'Virginia Beach', - 'Dakar', - 'Goiania', - 'Charlotte', - "Rui'an", - 'Muscat', - 'Kharkiv', - 'Wenling', - 'Gaozhou', - 'Faridabad', - 'Medina', - 'Khulna', - 'Ulaanbaatar', - 'Fuqing', + 'Naranjos', + 'Madhubani', + 'Atotonilco el Alto', + 'Palmar de Varela', + 'Hanerik', + 'Wadhraf', + 'Terre Neuve', + 'Libungan', + 'Mattigiri', + 'Prieto Diaz', + 'Barjora', + 'Kagamino', + 'Pakokku', + 'Bol', + 'Prienai', + 'Tan Phong', + 'Kali', + 'Rauenberg', + 'Chios', + 'Jerico', + "Qal'acha", + 'Biwong', + 'Albi', + 'Plantation', + 'Nargund', + 'Yamakita', + 'Ghota Fatehgarh', + 'Vredenburg', + 'Sherman', + 'Penal', + 'Varkaus', + 'Zhongwei', + 'Miri', + 'Guarapuava', + 'Bolszewo', + 'Park Forest Village', + 'Cianjur', + 'Kempsey', + 'Guaraci', + 'Odorheiu Secuiesc', + 'Alytus', + 'Mulanje', + 'Evinayong', + 'Bukkapatnam', + 'Berd', + 'Kisaran', + 'Bitung', + 'Selcuk', + 'Xikeng', + 'Cantanhede', + 'Pasuquin', + 'Steinheim am der Murr', + 'Mahem', + 'Gloria', + 'Benbrook', + 'Beforona', + 'Borken', + 'Ouled Rahmoun', + 'Pedras de Maria da Cruz', + 'Al Fuhays', + 'Titiribi', + 'Kien Luong', + 'Shediac', + 'Villasanta', + 'Guelph', + 'Duzkoy', + 'Narkher', + 'Tateyama', + 'Penzance', + 'Pasay City', + 'San Lucas Sacatepequez', + 'Skardu', + 'Maharajapuram', + 'Al `Asharah', + 'Tanant', + 'Kawaguchi', + 'Madhuban Bediban', + 'Bridge City', + 'Greenbelt', + 'Iara', + 'Baton Rouge', + 'Yopal', + 'Moribila', + 'Ciudad-Rodrigo', + 'Madira', + 'Bobonong', + 'Fort Hood', + 'Amboasary', + 'Sostanj', + 'Fnidq', + 'Vikasnagar', + 'Yangping', + 'Arraias', + 'Goslar', + 'Shuixi', + 'Lagoa da Canoa', + 'Baiersbronn', + 'Forest', + 'Sedavi', + 'Kosonsoy', + 'Trelleborg', + 'Bucheya', + 'Kidricevo', + 'Gokulgarh', + 'Coswig', + 'Marechal Taumaturgo', + 'Sidi Akkacha', + 'Kouarfa', + 'Finspang', + 'Timberlane', + 'Colotenango', + 'Puerto Ayora', + 'Goytapa', + 'Tarlapalli', + 'Acandi', + 'General Luna', + 'Calamba', + 'Miqiao', + 'Linxia Chengguanzhen', + 'Nizamabad', + 'Doria Sonapur', + 'Chongoroi', + 'Oskaloosa', + 'Prevalje', + 'Lubang', + 'Ladispoli', + 'Coite do Noia', + 'Sarjapur', + 'Panuco', + 'Jendouba', + 'Nayakanhatti', + "'Ain Mouilah", + 'Chapeco', + 'Stanton', + 'Balve', + 'Libante', + 'Etah', + 'Yarim', + 'Litchfield Beach', + 'Tsingoni', + 'Kendall Park', + 'Karkala', + 'Vlaardingen', + 'Torrente', + 'Periyanegamam', + 'Senhor do Bonfim', + 'Fleet', + 'Geita', + 'Chettipalaiyam', + 'New Washington', + 'Vlore', + 'San Juan Ermita', + 'Lagonglong', + 'Shwebo', + 'Hattiesburg', + 'Mering', + 'Basibasy', + 'Sarahs', + 'Nadendla', + 'Palaiyam', + 'Porto de Pedras', + 'Porto Novo', + 'Westampton', + 'Oriximina', + 'Al Jaghbub', + 'Hajjah', + 'Cutler Bay', + 'Toyokawa', + 'Tehuipango', + 'Catabola', + 'Ivanic-Grad', + 'Caudete', + 'Del Rio', + 'Clarence-Rockland', + 'Morrisville', + 'Divisopolis', + 'Chigasaki', + 'West Auckland', + 'Suzu', + 'Blythe', + 'Khunti', + 'Putussibau', + 'Ourikela', + 'Ambano', + 'Calpe', + 'Ambohitralanana', + 'Longjin', + 'Sao Filipe', + 'San Jose de Gracia', + 'Bura', + 'Ziarat', + 'Termoli', + 'Vohindava', + 'Xinbu', + 'Biliaivka', + 'Sahneh', + 'Rutherglen', + 'Naolinco de Victoria', + 'Windlesham', + 'Manchester', + 'Orinda', + 'South Yarmouth', + 'Tabaco', 'Kayseri', - 'Tel Aviv-Yafo', - 'Wuzhong', - 'Pingdu', - 'Sangereng', - 'Yangquan', - 'Samsun', - 'Yutan', - 'Copenhagen', - 'Helsinki', - 'Prague', - 'Milan', - 'Auckland', - 'Chizhou', - 'Makassar', - 'Liangshi', - 'Porto Alegre', - 'Huangshan', - 'Barranquilla', - 'Al Basrah', - 'Benxi', - 'Saitama', - 'Guarulhos', - 'Juarez', - 'Mandalay', - 'Xintai', - 'Wusong', - 'Calgary', - 'Meerut', - 'Yushu', - 'Belem', - 'Kuaidamao', - 'Baishan', - 'Adelaide', - 'Haicheng', - 'Milwaukee', - 'Providence', - 'Jacksonville', - 'Yicheng', - 'Cacuaco', - 'Porto', - 'Rosario', - 'Canagatan', - 'Soweto', - 'Bagam', - 'Jabalpur', - 'Rucheng', - 'Huaiyin', - 'Dublin', - 'Dayan', - 'Balikesir', - 'Comayaguela', - 'Laiwu', - 'Sharjah', - 'Jingling', - 'Kalyan', - 'Yongcheng', - 'Sumedang', - 'Can Tho', - 'Brussels', - 'Suwon', - 'Yiwu', - 'Beidao', - 'Vasai-Virar', - 'Xiangshui', - 'Dadukou', - 'Campinas', - 'Lingcheng', - 'Shuangyashan', - 'Mombasa', - 'Najafgarh', - 'Xinyu', - 'Qom', - 'Hargeysa', - 'Baidoa', - 'Zhangye', - 'Varanasi', - 'Hiroshima', - 'Chiang Mai', - 'Belgrade', - 'Maiduguri', + 'Ibiapina', + 'Murcia', + 'Swieqi', + 'Valencia', + 'Chirala', + 'Eloxochitlan', + 'Dembeni', + 'Fardis', + 'Misaki', + 'Nagar', + 'Miyajima', + 'Brikama', + 'Umurlu', + 'Brierley Hill', + 'Khodabandeh', + 'Ozgon', + 'Reze', + 'Tinajeros', + 'Novomyrhorod', + 'Fully', + 'Biak', + 'Colider', + 'Kashiwara', + 'Sjenica', + 'Hednesford', + 'Madukkarai', + 'Villaflores', + 'Chiautla de Tapia', + 'Taormina', + 'Huwei', + 'Seiyo', + 'Washim', + 'Benton', + 'Venturina', + 'Kakalur', + 'Andamooka', + 'Anghad', + 'West Hempfield', + 'Turnhout', + 'Markkleeberg', + 'Poko', + 'Wealdstone', + 'Ban Na Pa', + 'Cerklje na Gorenjskem', + 'Bombon', + 'Arimalam', + 'Jangy-Kyshtak', + 'Isny im Allgau', + 'Braga', + 'Kawadgaon', + 'Bonate di Sopra', + 'Tonneins', + 'Munagala', + 'Chinna Mushidivada', + 'Talagutong', + 'Neihuzhai', + 'Agua de Dios', + 'Herceg Novi', + "Nerk'in Getashen", + 'Botucatu', + 'Arroio do Meio', + 'Villafranca del Panades', + 'Madikeri', + 'Serik', + 'San Sebastian Huehuetenango', + 'Kyzyl-Adyr', + 'Somarasampettai', + 'Surmene', + 'Turbana', + 'Chilas', + 'Marinette', + 'The Hammocks', + 'McPherson', + 'General MacArthur', + 'Strasbourg', + 'Tibana', + 'Polatli', + 'Sur', + 'Lye', + 'West Carson', + 'Uludere', + 'Moroni', + 'Mata de Sao Joao', + 'Pachmir', + 'Saskatoon', + 'Nina Rodrigues', + 'Chinnakkavundanur', + 'Norton Shores', + 'Abu', + 'Santo Angelo', + 'Pianezza', + 'Wythenshawe', + 'Mabeskraal', + 'Fort Drum', + 'Gobindpur', + 'Kostopil', + 'Calca', + 'Nonkon', + 'Kolno', + 'Tati', + 'Glastonbury', + 'Itakura', + 'Payyanadam', + 'Puerto Caimito', + 'Thionville', + 'Wezep', + 'Llandudno', + 'Antequera', + 'Camp Perrin', + 'Sao Luis do Paraitinga', + 'Kabatas', + 'Volta Redonda', + 'Beni Mered', + 'Kaffrine', + 'Reutlingen', + 'Fort Morgan', + 'Naucalpan de Juarez', + 'Ebo', + 'Dargaz', + 'Vina del Mar', + 'Ilam', + 'Kyzyl-Suu', + 'Perinton', + 'Nenmini', + 'La Mirada', + 'Sumbe', + 'Jicin', + 'Indian Trail', + 'Nova Bassano', 'Batam Centre', - 'Rongcheng', - 'Mbandaka', - 'Doha', - 'Ahvaz', - 'Shymkent', - 'Tripoli', - 'Srinagar', - 'Nashville', - 'Liaoyuan', - 'Aurangabad', - 'Cilacap', - 'Salt Lake City', - 'Pikine', - 'Guankou', - 'Bandar Lampung', - 'Raleigh', - 'Lianyuan', - 'Dhanbad', - 'Nay Pyi Taw', - 'Aba', - 'Kaiyuan', - 'Zhuji', - 'Yingtan', - 'Edmonton', - 'Leiyang', - 'Ulsan', - 'Benin City', - 'Bujumbura', - 'Guyuan', - 'Xiantao', - 'Maputo', - 'Bukavu', - 'Amritsar', - 'Shagamu', - 'Yingchuan', - 'Aligarh', - 'Santo Domingo', - 'Bogor', - 'Bishkek', - 'Tbilisi', + 'Tocache Nuevo', + 'Tambaram', + 'Kikugawa', + 'Sari', + 'Borca', + 'Beja', + 'Feltre', + 'Godo', + 'Oshawa', + 'German Flatts', + 'Schaffhausen', + 'Albino', + 'Wejherowo', + 'Plav', + 'Beccar', + 'Pitsea', + 'Lauro de Freitas', + 'Gogrial', + 'Ferros', + 'Tipp City', + 'Waynesboro', + 'Khost', + 'Golungo Alto', + 'Tamesis', + 'Almondbury', + 'Bernardo de Irigoyen', + 'Vairampatti', + 'Neiafu', + 'Everswinkel', + 'Garden Acres', + 'Yufu', + 'Coxim', + 'Dilra', 'Guwahati', - 'Fes', - 'Mwanza', - 'Bien Hoa', - 'Mexicali', - 'Sevilla', - 'Ikare', - 'Dongtai', + 'Tan Phu', + "Khairpur Mir's", + 'Poza Rica de Hidalgo', + 'Trancoso', + 'Koytendag', + 'At Tafilah', + 'Ranohira', + 'Legionowo', + 'Romitan Shahri', + 'The Villages', + 'Carroll', + 'Mogi Mirim', + 'Mo i Rana', + 'San Miguel Duenas', + 'Dardoq', + 'Abaetetuba', + 'New Milford', + 'Palda', + 'Tsinjomitondraka', + 'Pisz', + 'Otaru', + 'Caldas Novas', + 'Pampanito', + 'Panuco de Coronado', + 'Lanyi', + 'Mayoyao', + 'Tlagasana', + 'Chetouane', + 'Grand-Popo', + 'Nagaoki', + 'Chong Nonsi', + 'Emmiganur', + 'Looc', + 'Vila Muriqui', + 'Frattamaggiore', + 'Ormoz', + 'Goynucek', + 'Arles', + 'Laungowal', + 'Jalhay', + 'Wan Tau Tong', + 'Villa Angela', + 'Mariyammanahalli', + 'Pivka', + 'Firmat', + 'Patsanda', + 'Colle Salvetti', + 'Gyula', + 'Valparai', + 'Issaquah', + 'Jeronimo Monteiro', + 'Bugasong', + 'Broxbourne', + 'Tsundupalle', + 'Jacupiranga', + 'San Juan Ixcoy', + 'Ambatomirahavavy', + 'Lanco', + 'Monsenhor Gil', + 'Sabaa Aiyoun', + 'Narnaul', + 'Carutapera', + 'Altay', + 'Ambodiampana', + 'Kouvola', + 'Harahan', + 'Paoskoto', + 'Vargem Grande Paulista', + 'Schwarzenbruck', + 'Bellheim', + 'Oak Ridge', + 'Chimaltenango', + 'Issaba', + 'Tiri', + 'Taroudannt', + 'Nonahi', + 'Ranquitte', + 'Tala Yfassene', + 'Meybod', + 'Muchamiel', + 'Antohobe', + 'Axochiapan', + 'Malakanagiri', + 'Whitchurch', + 'Lake in the Hills', + 'San Mateo del Mar', + 'Curuzu Cuatia', + 'Schweizer-Reineke', + 'Babusnica', + 'Montgomeryville', + 'Gundugolanu', + 'Abi al Khasib', + 'Pillanallur', + 'Soulei', + 'Ayas', + 'Azuqueca de Henares', + 'Chodov', + 'Mingjiujie', + 'Patar', + 'Porto Murtinho', + 'Jafra', + 'El Progreso', + 'Rulin', + 'Penetanguishene', + 'Ban Khek Noi', + 'Tubao', + 'Calw', + 'Gaundra', + 'Nasik', + 'Gaolingcun', + 'Kalol', + 'Meadowbrook', + 'Kidapawan', + 'Rudsar', + 'Maddaloni', + 'Kabul', + 'Karlskoga', + 'Yazd', + 'Podalakur', + 'Asakura', + 'Teranikallu', + 'Keokuk', + 'Uyuni', + 'Yorosso', + 'Pfaffikon', + 'Arniquet', + 'Kyzyl-Kyshtak', + 'Kambur', + 'Mburucuya', + 'Mingacevir', + 'Zvolen', + 'Cabaceiras do Paraguacu', + 'Tamworth', + 'Guantanamo', + 'Darregueira', + 'Ezequiel Montes', + 'Fomboni', + 'Quintanar de la Orden', + 'Siachoque', + 'Kericho', + 'Mineral de Angangueo', + 'Peka', + 'Fenglin', + 'Quetzaltenango', + 'Sevanagala', + 'Port Pirie', + 'Tengyue', + 'Novoyavorovskoye', + 'Forli', + 'Suchitoto', + 'Hosdurga', + 'Arcoverde', + 'Vale de Cambra', + 'San Pablo Atlazalpan', + 'Hockenheim', + 'Dandu Mailaram', + 'Tadjmout', + 'Port of Spain', + 'Nanaimo', + 'Colonia del Sol', + 'Primeiro de Maio', + 'Valletta', + 'Horishni Plavni', + 'Kingswood', + 'Furstenwalde', + 'Grosse Pointe Farms', + 'Bang Kruai', + 'Haiger', + 'Chansolme', + 'Xiaoganzhan', + 'Mulaikkaraippatti', + 'Nandazhang', + 'Hambuhren', + 'Medellin', + 'Canapolis', + 'Corozal', + 'Bignona', + 'Nova Vodolaha', + 'Shedbal', + 'Maojiatang', + 'Greentree', + 'Mahayag', + 'Rajendranagar', + 'Guararema', + 'Pirane', + 'Tall Dhahab', + 'Sipoo', + 'Aiquile', + 'Kish', + 'Taltal', + 'Kushmanchi', + 'Santa Genoveva de Docordo', + 'Tapiales', + 'Yunak', + 'Floirac', + 'Parbata', + 'Zhangzhengqiao', + 'Zossen', + 'Caselle Torinese', + 'Zaliohouan', + 'Waldkirchen', + 'Sao Jose da Coroa Grande', + 'Pasinler', + 'Gaspe', + 'Soubakaniedougou', + 'Nabire', + 'Sieyik', + 'Sao Jose de Piranhas', + 'Gioia del Colle', + 'Villanueva de Arosa', + 'Marihatag', + 'Daugavpils', + 'Saint Helens', + 'Jiannan', + 'Gross Kreutz', + 'Ganapathivattam', + 'Santiago de Cuba', + 'Katanning', + 'Marotolana', 'Dingzhou', - 'Xibeijie', - 'Tamale', - 'Yuyao', - 'Hanchuan', - 'Gongzhuling', - "N'Djamena", - 'Ubungo', - 'Cologne', - 'Zhufeng', - 'Ezhou', - 'Astana', - 'Nezahualcoyotl', - 'Nouakchott', - 'Haora', - 'Tongjin', - 'Xiashi', - 'Yerevan', - 'Ranchi', - 'Richmond', - 'Ciudad Nezahualcoyotl', - 'Gwalior', - 'Ottawa', - 'Zhongwei', - 'Oslo', - 'Goyang', - 'Sendai', - 'Mizhou', - 'Xishan', - 'Barquisimeto', - 'Hegang', - 'Chandigarh', - 'Managua', - 'Haldwani', - 'Vijayawada', - 'Fangchenggang', - 'Jiancheng', - 'Cazenga', - 'Kisangani', - 'Shouguang', - 'Memphis', - 'Sao Luis', - 'Jodhpur', - 'Matola', - 'Ogbomoso', - 'Sanya', - 'Rangapukur', - 'Ashgabat', - 'Wutong', - 'Linhai', - 'Denizli', - 'Niamey', - 'Shubra al Khaymah', - 'Wafangdian', - 'Zhongxiang', - 'Monrovia', - 'San Cristobal', - 'Islamabad', - 'Xinyi', - 'Thu Duc', - 'Morelia', - 'Odesa', - 'Raipur', - 'Changwon', - 'Arequipa', - 'Zaoyang', - 'Xingyi', - 'Shuizhai', - 'Kota', - 'Quetta', - 'Quang Ha', - 'Domaa-Ahenkro', - 'Bareilly', - 'Oklahoma City', - 'Bordeaux', - 'Xingcheng', + 'Spoleto', + 'San Agustin Chahal', + 'Calheta de Sao Miguel', + 'Aragua de Barcelona', + 'Vammala', + 'Sao Goncalo do Amarante', + 'Shahba', + 'Cornedo Vicentino', + 'Kew Green', + 'Kuzuculu', + 'Tobati', + 'Currais Novos', + 'Mounds View', + 'Wetzlar', + 'Nesoddtangen', + 'Bosilovo', + 'Marolambo', + 'Horodyshche', + 'Aleksandrow Kujawski', + 'Sao Jose do Cedro', + 'Dhabauli', + 'Macka', + 'Oelsnitz', + 'Kiambu', + 'Mugutkhan Hubli', + 'Jalkaura', + "Bo'ao", + 'Emmiganuru', + 'Manglur', + 'Shenmu', + 'Kerch', + 'Paluan', + 'Jaguaribe', + 'Palmeira dos Indios', + 'Zorgo', + 'Chagne', + 'Ugrinovci', + 'Feuchtwangen', + 'Mitake', + 'Pacora', + "Rui'an", + 'West Hanover', + 'Buca', + 'Sam Son', + 'Matsuyama', + 'Gouka', + 'Tuchin', + 'Tonantins', + 'Narangba', + 'Inami', + 'Wolf Trap', + 'Kumharsan', + 'Gundi', + 'Rubiera', + 'Balia', + 'Estarreja', + 'Golkoy', + 'Nordestina', + 'Dattapulia', + 'Wapienica', + 'Unao', + 'Vasterhaninge', + 'Wenxian Chengguanzhen', + 'Hanover Park', + 'Urrugne', + 'San Antonio Ilotenango', + 'San Vicente dels Horts', + "Sao Miguel d'Oeste", + 'Caerfyrddin', + 'Sidi Rahhal', + 'Olongapo', + 'Jasol', + 'Castelnuovo Rangone', + 'Don Benito', + 'Thung Song', + 'Zhanibek', + 'Male', + 'Anpachi', + 'Buford', + 'Kwekwe', + 'Urmston', + 'Fernan-Nunez', + 'Rio das Ostras', + 'Zhmerynka', + 'Shahrud', + 'Las Lomitas', + 'Curuca', + 'Ar Ramadi', + 'Jamundi', + 'Skalica', 'Taixing', - 'Xinhualu', - 'Lilongwe', - 'Port-au-Prince', - 'Yingcheng', - 'Al Mijlad', - 'Luocheng', - 'Pekanbaru', - 'Natal', - 'Chiba', - 'Kirkuk', - 'Hartford', - 'Huilong', - 'Wuchuan', - 'Dnipro', - 'Narayanganj', - 'Gqeberha', - 'Malaga', - 'Marrakech', - 'Cebu City', - 'Louisville', - 'Asmara', - 'Coimbatore', - 'Maceio', - 'Nada', - 'Taishan', - 'Teresina', - 'Solapur', - 'Freetown', - 'Santo Domingo Este', - 'Vientiane', - 'Tangier', - 'Anqiu', - 'Kermanshah', - 'Feicheng', - 'Kibanseke Premiere', - 'Seberang Jaya', - 'Buffalo', - 'Hubli', - 'El Alto', - 'Cankaya', - 'Hwasu-dong', - 'Setagaya', - 'Kecioren', - 'Jerusalem', - 'Khartoum North', - 'Mushin', - 'Trujillo', - 'Kitakyushu', - 'Aguascalientes', - 'New Orleans', - 'Fort Worth', - 'Taihe', - 'Riga', - "Xin'an", - 'Taihecun', - 'Kashgar', - 'Songnam', - 'Trichinopoly', - 'Cartagena', - 'Qingzhou', - 'Naples', - 'Santiago del Estero', - 'Naucalpan de Juarez', - 'Daye', - 'Hengzhou', - 'Padang', - 'Bridgeport', - 'Owerri', - 'Zhuanghe', - 'Bobo-Dioulasso', - 'Ad Dammam', - 'Quzhou', - 'Donetsk', - 'Ashmun', - 'Bunia', - 'Jiaozhou', - 'Campo Grande', - 'Wuchang', - 'Sao Goncalo', - 'Bucaramanga', - 'Merida', - 'Yangchun', - 'Osmangazi', - 'Esenyurt', - 'Moradabad', - 'Bangui', - 'Abeokuta', - 'Cancun', - 'Antipolo', - 'Dengtalu', - 'Taguig City', - 'Tabuk', - 'Zhoushan', - 'Tucson', - 'As Sulaymaniyah', - 'Chihuahua', - 'Klang', - 'Tiruppur', - 'Gurgaon', - 'Ar Ramadi', - "Hai'an", - 'Laiyang', - 'Barinas', - 'Jalandhar', - 'Marseille', - 'Kaifeng Chengguanzhen', - 'Eskisehir', - 'Gaomi', - 'Lhasa', - 'Ipoh', - 'El Paso', - 'Saltillo', - 'Dushanbe', - 'Ikeja', - 'El Dorado', - 'Cochabamba', - 'Portsmouth', - 'Southampton', - 'Hermosillo', - 'Leping', - 'Cheongju', - 'Shache', - 'Sale', - 'Hailun', - 'Macheng', - 'Akure', - 'Ilorin', - 'Erbil', - 'Kathmandu', - 'Iguacu', - 'Zijinglu', - 'Turin', - 'Yuci', - 'Dehui', - 'Pietermaritzburg', - 'Durban', - 'Bhubaneshwar', - 'Denpasar', - 'Tongchuan', - 'Joao Pessoa', - 'Samarinda', - 'Chengxiang', - 'Rongjiawan', - 'Weichanglu', - 'Sakai', - 'Renqiu', - 'Omaha', - 'Xindi', - "Wu'an", - 'Qingping', - 'Gaoyou', - 'Sao Bernardo do Campo', - 'Hejian', - 'Puxi', - 'Bhayandar', - 'Androtsy', - 'Culiacan', - 'Cucuta', - 'Danyang', - 'Dongyang', - 'Krakow', - 'Pasig City', - 'Thessaloniki', - 'Queretaro', - 'Palermo', - 'Xigaze', - 'Qamdo', - 'McAllen', - 'Libreville', - 'Seyhan', - 'San Pedro Sula', - 'Niigata', - 'Hempstead', - 'Leeds', - 'Hamamatsu', - 'Pointe-Noire', - 'Xiangxiang', - 'Chaohucun', - 'Bucheon', - 'Lubango', - 'Homs', - 'Bilbao', - 'Zouping', - 'Frankfurt', - 'San Luis Potosi', - 'Dali', - 'Khujand', - 'Korla', - 'Albuquerque', - 'Hamhung', - 'Erzurum', - 'Zagreb', - 'Al `Ayn', - 'Songzi', - 'Patiala', - 'Laixi', - 'Zhongba', - 'Bahawalpur', - 'Qingnian', - 'Kaduna', - 'Winnipeg', - 'Trabzon', - 'Guangshui', - 'Baardheere', - 'Shishgarh', - 'Nerima', - 'Sizhan', - 'Ciudad Guayana', - 'Lichuan', - 'Licheng', - 'Santo Andre', - 'Ota-ku', - 'Gaalkacyo', - 'Thiruvananthapuram', - 'Osasco', - 'Nampula', - 'Pretoria', - 'Kyaukse', - 'Chengguan', - 'Nehe', - 'Cabinda', - 'Kumamoto', - 'Kerman', - 'Zunhua', - 'Orumiyeh', - 'Wugang', - 'Bagcilar', - 'Quebec City', - 'Shuangqiao', - 'Umraniye', - 'Yanggok', - 'Tshikapa', - 'Tulsa', - 'Osogbo', - 'Comodoro Rivadavia', - 'Nottingham', - 'Hamilton', - 'Langzhong', - 'Cagayan de Oro', - "Qian'an", - 'Fresno', - 'An Najaf', - 'Cencheng', - 'Sorocaba', - 'Guli', - 'Sagamihara', - 'Pishbar', - 'Okayama', - 'Anlu', - 'Concepcion', - 'Mississauga', - 'Songyang', - 'Lviv', - 'Shihezi', - 'Vilnius', - 'Marka', - 'Enugu', - 'Valenzuela', - 'Yatou', - 'Uberlandia', - 'Xichang', - 'Zaporizhzhia', - 'Bhiwandi', - 'George Town', - 'Bristol', - 'Charleston', - 'Saharanpur', - 'Dashiqiao', - 'Yenimahalle', - 'Warangal', - 'Nampo', - 'Dasmarinas', - 'Jaboatao', - 'Chisinau', - 'Shiliguri', - 'Boosaaso', - 'Port Moresby', - 'Latakia', - 'Rochester', - 'Ribeirao Preto', - 'Edogawa', - 'Sao Jose dos Campos', - 'General Santos', - 'Hamah', - 'Qianxi', - 'Bauchi', - 'Pendik', - 'Salem', - 'Shishi', - 'Sinnuris', - 'Cocody', - 'Miluo Chengguanzhen', - 'Lokoja', - 'Guadalupe', - 'Gaizhou', - "Karbala'", - 'Borvayeh-ye Al Bu `Aziz', - 'City of Paranaque', - 'Leling', - 'Mamak', - 'Jianshe', - 'Shizuoka', - 'Jingcheng', - 'Agege', - 'Mar del Plata', - 'Zaragoza', - 'Adachi', - 'Xinmin', - 'Rasht', - 'Shanhu', - 'Zhongshu', - 'Cotonou', - 'Tasikmalaya', - 'Kochi', - 'Soledad', - 'Dhulia', - 'Acapulco de Juarez', - 'Gorakhpur', - 'Bahar', - 'Kumul', - 'Wroclaw', - 'Murcia', - 'Pinghu', - 'Lodz', - 'Guntur', - 'Bhangar', - 'Dayton', - "Ch'ongjin", - 'Qionghu', - 'Zhaodong', - 'Puyang Chengguanzhen', - 'Bulawayo', - 'Huambo', - 'Aracaju', - 'Bacoor', - 'Wenchang', - 'Rotterdam', - 'Tlaquepaque', - 'Villavicencio', - 'Shulan', - 'Banjarmasin', - 'Narela', - 'Catia La Mar', - 'Al Hufuf', - 'Jalingo', - 'Sargodha', - 'Karaikandi', - 'Bouake', - 'Lingbao Chengguanzhen', - 'Brampton', - 'Abomey-Calavi', - 'Durango', - 'Cape Coral', - 'Tondo', - 'Dayrut', - 'Tlalnepantla', - 'Ansan', - 'Hue', - 'Sanhe', - 'San Jose del Monte', - "Ch'onan", - 'Cuiaba', - 'Jieshou', - 'Erer Sata', - 'Selcuklu', - 'Suohe', - 'Guixi', - 'Honcho', - 'Wuxue', - 'Jaboatao dos Guararapes', - 'Yildirim', - 'Bhavnagar', - 'Jinghong', - 'Tengyue', - 'Mission Viejo', - 'Ruiming', - 'Qufu', - 'Sha Tin', - 'Petaling Jaya', - 'Colorado Springs', - 'Noida', - 'Xinshi', - 'Baton Rouge', - 'Manama', - 'Las Palmas', - 'Chak Forty-one', - "Jin'e", - 'Benghazi', - 'Chuxiong', - 'Makati City', - 'Dusseldorf', - 'Allentown', - 'Xinxing', - 'Tukh', - 'Glasgow', - 'Namangan', - "Bazal'tove", - 'Al Qatif', - 'Bhilai', - 'Mangalore', - 'Kaihua', - 'Meilan', - 'Ogden', - 'Turpan', - 'Jos', - 'Al Mansurah', - 'Contagem', - 'Jambi', - 'Halwan', - 'Provo', - 'Tan An', - 'Port-Bouet', - 'Pontianak', - 'Meihekou', - 'Jurong', - 'Bihta', - 'Yuhuan', - 'Joinvile', - 'Feira de Santana', - 'Leipzig', - 'Xinji', - 'Knoxville', - 'Ta`izz', - 'Etimesgut', - 'Changping', - 'Tallinn', - 'Chimalhuacan', - 'Kandahar', - 'Serang', - 'Zhangshu', - 'Grand Rapids', - 'Yukarikaraman', - 'Gothenburg', - 'Kuantan', - 'Gold Coast', - 'Kawaguchi', - 'Las Pinas City', - 'Cuttack', - 'San Miguel de Tucuman', - 'Ar Rayyan', - 'Salimpur', - 'Malanje', - 'Columbia', - 'Kryvyi Rih', - 'Djibouti', - 'Zhuozhou', - 'Tianchang', - 'Tunis', - 'Bacolod', - 'Garoua', - 'Bafoussam', - 'Haifa', - 'Raurkela', - 'Tumkur', - 'Balikpapan', - 'Somolu', - 'Al Hillah', - 'Melikgazi', - 'Kagoshima', - 'Sihui', - 'Dortmund', - 'Irapuato', - 'Al Mahallah al Kubra', - 'Sialkot City', - 'Albany', - 'Pereira', - 'Gaza', - 'Uvira', - 'Reynosa', - 'Zahedan', - 'Cimahi', - 'Mbale', - 'Wenlan', - 'Shangzhi', - 'Essen', - 'Itabashi', - 'Shah Alam', - 'Botou', - 'Suginami-ku', - 'Tenkasi', - 'Kingston', - 'Al Mafraq', - "At Ta'if", - 'Port Sudan', - 'Tuxtla', - 'Dehra Dun', - 'Xiulin', - "Fu'an", - 'Mymensingh', - 'Hachioji', - 'Iloilo', - 'Puente Alto', - 'Rabat', - 'Sincan', - 'Bakersfield', - 'Kottayam', - 'Luofeng', - 'Shibin al Qanatir', - 'Nakuru', - 'Lingyuan', - 'Tonala', - 'Bremen', - 'Abu Hummus', - 'Irbid', - 'Macau', + 'Huron', + 'Basse-Goulaine', + 'Arteche', + 'Roxbury', + 'Nawnghkio', + 'Terryville', + 'Eastlake', + 'Guarabira', + 'Zionsville', + 'Yala', + 'Os', + 'Tuquerres', + 'Zlatograd', + 'Harnai', + 'Cherukara', + 'Numancia', + 'Negotino', + 'Sparta', + 'Buzen', + 'Karuvelampatti', + 'Monte San Pietro', + 'Rosario do Catete', + 'Thamaga', + 'Johnstown', + 'Manaira', + 'Zabrat', + 'Tebourba', + 'Cornelius', + 'Al Mu`addamiyah', + 'Epinal', + 'Haria', 'Surrey', - 'Ciudad Bolivar', - 'Durgapur', - 'Shenzhou', - 'New Haven', - 'Kuiju', - 'Zhenzhou', - 'Asansol', - 'Bokaro Steel City', - 'Dresden', - 'Bello', - 'Kolhapur', - 'Wencheng', - 'Lanxi', - 'Dangyang', - 'Nava Raipur', - 'Genoa', - 'Herat', - 'Londrina', - 'Cuautitlan Izcalli', - 'Uyo', - 'Hamadan', - 'Luanzhou', - 'Chiclayo', - 'Surakarta', - 'Ajmer', - 'Kimhae', - 'Nanded', - 'Wuhai', - 'Palma', - 'Rustenburg', - 'Amravati', - 'Des Moines', - 'Lisbon', - 'Yanji', - 'Huanghua', - 'Al Hudaydah', - 'Anyang', - 'The Hague', - 'Andijon', - 'Manchester', - 'Nellore', - 'Poznan', - 'Samarkand', - 'Wancheng', - 'Hannover', - 'Sungai Petani', - 'Valledupar', - 'Fengcheng', - 'Muntinlupa City', - 'Ghulja', - 'Ixtapaluca', - 'Fuding', - 'Heroica Matamoros', - 'Akron', - 'Mbeya', - 'An Nasiriyah', - 'Ibague', - 'Juiz de Fora', - 'City of Calamba', - 'El Geneina', - "Chang'an", - 'Florianopolis', - 'Nilufer', - 'Antwerp', - 'Kassala', - 'Aksu', - 'Salta', - 'Dispur', - 'Palm Bay', - 'Gulbarga', - 'Nansana', - 'Mingguang', - 'Concord', - 'Beira', - 'Yazd', - 'Ardabil', - 'Touba', - 'Bikaner', - 'Gaobeidian', - 'Ndola', - 'Himeji', - 'Ailan Mubage', - 'Bandar `Abbas', - 'Skopje', - 'Santa Teresa del Tuy', - 'Port Said', - 'Koto-ku', - 'Ciudad Apodaca', - 'Monteria', - 'Nuremberg', - 'Kitchener', - 'Nagercoil', - 'Agartala', - 'Soacha', - 'Buca', - 'Lyon', - 'Maipu', - 'Arak', - 'Serra', - 'Tultitlan de Mariano Escobedo', - 'Meknes', - 'Bac Ninh', - 'Anda', - 'Longzhou', - 'Al Fayyum', - 'Utsunomiya', - 'Sheffield', - 'Mixco', - 'Suez', - 'Heshan', - 'Loni', - 'Jiaji', - 'Santa Marta', - 'Ujjain', - 'Beining', - 'Abu Tisht', - 'Maturin', - 'Liverpool', - 'Macapa', - 'Benguela', - 'Al Fashn', - 'Al `Amarah', - 'Carrefour', - 'Campos', - 'Cadaado', - 'Encheng', - 'Bhilwara', - 'Biba', - 'Wichita', - 'Leicester', - 'Newcastle', - 'Hai Duong', - 'Aden', - 'Jhansi', - 'Matsuyama', - 'Ulhasnagar', - 'Nagqu', - 'Kitwe', - 'Vellore', - 'Toulouse', - 'Pohang', - 'Mesa', - 'Duisburg', - 'Jammu', - 'Ile-Ife', - "Homyel'", - 'Mazatlan', - 'Meicheng', - 'El Fasher', - 'Farah', - 'Belas', - 'Talatona', - 'Nenjiang', - 'Sukkur', - 'Hsinchu', - 'Harrisburg', - 'Hongjiang', - 'Qaraghandy', - 'Lapu-Lapu City', - 'Matsudo', - 'Johor Bahru', - 'Purnea', - 'Imus', - 'Niteroi', - 'Beipiao', - 'Dengtacun', - 'Zhijiang', - 'Suoluntun', - 'Staten Island', - 'Chengjiao', - 'Lembok', - 'Likasi', - 'Oujda-Angad', - 'Duyun', - 'Toledo', - 'Pindi Bhattian', - 'Nyala', - 'Bissau', - 'Ichikawa', - 'Kota Bharu', - 'Yuanping', - 'Higashi-osaka', - 'Larkana', - '`Ajman', - 'Vinh', - 'Ciudad Lopez Mateos', - 'Yueqing', - 'Belgaum', - 'Caerdydd', - 'Edinburgh', - 'Brookhaven', - 'Nishinomiya-hama', - 'Karamay', - 'Worcester', - 'Kawachicho', - 'Shahe', - 'Gdansk', - 'Sevastopol', - 'Garoowe', - 'Villa Nueva', - 'Dunhua', - 'Lianran', - 'Akhmim', - 'Sanliurfa', - "Az Zarqa'", - 'Malegaon', - 'Sao Jose do Rio Preto', - 'Valletta', - 'Kolwezi', - 'Jamnagar', - 'Sylhet', - 'Ananindeua', - 'East London', - 'Berbera', - 'Jiannan', - 'Chiniot', - 'Asuncion', - 'Oita', - 'Nangong', - 'Bardoli', - 'Eldoret', - 'Bratislava', - 'Kurashiki', - 'Al Jubayl', - 'Worthing', - 'Gaya', - 'Shekhupura', - 'Piura', - 'Vila Velha', - 'Ar Rusayfah', - 'Jiaojiangcun', - 'Laohekou', - 'Mykolaiv', - 'Beian', - 'Fujin', - 'Kucukcekmece', - 'Mazar-e Sharif', - 'Xiaoyi', - 'Qingzhen', - 'Ba`qubah', - 'Katlehong', - 'Jiangshan', - 'Buraydah', - 'Surab', - 'Kupang', - 'Ambattur', - 'Nakhon Ratchasima', - 'Tan Uyen', - 'Constantine', - 'Longjiang', - 'Caxias do Sul', - 'Angeles City', - 'Kuqa', - 'Kanazawa', - 'Long Beach', - 'Port St. Lucie', - 'Manado Light', - 'Kartal', - 'Cranbourne', - 'Jalgaon', - 'Porto Velho', - 'Chhatarpur', - 'Fukuyama', - 'Little Rock', - 'Juba', - 'Lanus', - 'Amagasaki', - 'Kikwit', - 'Pyeongtaek', - 'Reno', - 'Kurnool', - 'Spokane', - 'Marikina City', - "Jian'ou", - 'Huadian', - 'Melaka', - 'Manado', - 'Manizales', - 'Bornova', - 'Minzhu', - 'Demiryol', - 'Erkoklu', - 'Kota Kinabalu', - 'Katsushika-ku', - 'Madison', - 'Santiago de Cuba', - 'Udaipur', - 'Mogi das Cruzes', - 'General Trias', - 'Sirajganj', - 'Boise', - 'Bonita Springs', - 'Mariupol', - 'Eslamshahr', - 'Piraeus', - 'Tanbei', - 'Zurich', - 'Pingquan', - 'Ado-Ekiti', - 'Baisha', - 'Batman', - 'Yongji', - 'Esenler', - 'Rodriguez', - 'Ensenada', - 'Danjiangkou', - 'Chauddagram', - 'Kahramanmaras', - 'San Nicolas de los Garza', - 'Taoyuan District', - 'Ndjili', - 'Mathura', - 'Pasay City', - "Ning'an", - 'Halifax', - 'Fujisawa', - 'Denton', - 'Laval', - 'Jinchang', - 'Oakland', - 'Springfield', - 'Guangming', - 'Augusta', - 'Kagithane', - "Sunch'on", - 'Sangli', - 'Avcilar', - 'Jeju', - 'Zhuangyuan', - 'Davangere', - 'Machida', - 'Sanghar', - 'Al Maraghah', - 'Bandung', - 'Kissimmee', - 'Calicut', - 'Kenitra', - 'Windhoek', - 'Huili Chengguanzhen', - 'Sidi Bouzid', - 'Baramati', - 'Tanta', - 'Ismailia', - 'Cusco', - 'Veracruz', - 'Sokoto', - 'Winston-Salem', - 'Kashiwa', - 'Al Bajur', - 'Xunyang', - 'Malatya', - "Yan'an Beilu", - 'Mothihari', - 'Aomori', - 'Akola', - 'Mandaluyong City', - 'Aves', - 'Sihung', - 'Burco', - 'Xalapa', - 'Buenaventura', - 'Piracicaba', - 'Yogyakarta', - 'Toyota', - 'Daloa', - 'Agadir', - 'Elazig', - 'Uijeongbu', - 'Hpa-An', - 'Rahimyar Khan', + 'Tarapoto', + 'Morecambe', + 'Maribojoc', + 'Savda', + 'Calbiga', + 'Ayodhyapattanam', + 'Dulmen', + 'Porteirinha', + 'Armstrong', + 'Darton', + 'Poco Redondo', + 'Yoboki', + 'Maevka', + 'Pihra', + 'Nong Khae', + 'Mascoutah', + 'Ukrainka', + 'Ivrea', + 'Vadavalam', + 'Huaraz', + 'Gjakove', + 'Penablanca', + 'Lishuping', + 'Kiso', + 'Guaranda', + 'Palliman', + 'Rawtenstall', + 'Atchampeta', + 'Tarazona de Aragon', + 'Vincent', + 'Longtang', + 'Muragacha', + 'Gwadar', + 'Aguilas', + 'Karttigappalli', + 'Rahway', + 'Churi', + 'Leini', + 'Ragan Sur', + 'Hongliuwan', + 'Bayang', + 'Plattsburgh', + 'Anagni', + 'Gidan Ider', + 'Ait Bouchta', + 'Sidi Abdelkader', + 'Salaverry', + "Ma'erkang", + 'Niena', + 'Santamaguluru', + 'Buxtehude', 'Ugep', - 'Hailin', - 'Mishan', - 'Sarajevo', - 'Seremban', - 'Zhengjiatun', - 'Lecheng', - 'Campina Grande', - 'Xicheng', - 'Pencheng', - 'Kowloon City', - 'Tirana', - 'Kushtia', - 'El Obeid', - 'Maua', - "Da'an", - 'Luhansk', - 'Xingren', - 'Takamatsu', - 'Arusha', - 'Fenyang', - 'Ajdabiya', - 'Callao', - 'Awsim', - 'Shinagawa-ku', - 'Paju', - 'Santa Rosa', - 'Bettiah', + 'Zelezniki', + 'Emmendingen', + 'Monforte de Lemos', + 'Tourza', + 'Rivalta di Torino', + 'Orange Cove', + 'Bijbiara', + 'Jardim do Serido', + 'Kajaani', + 'Barros Cassal', + 'Shengang', + 'Candido de Abreu', + 'Ashdod', + 'Bhit Bhagwanpur', + 'Sajoszentpeter', + 'Ambolotarakely', + 'Viota', + 'Muskegon', + 'Hanau', + 'Madhupur', + 'Popesti-Leordeni', + 'Coyhaique', + 'Hojai', + 'Nehe', + 'Maddagiri', + 'Bodrum', + 'Mountain View', + 'Tash-Komur', + 'Cili', + 'Kristianstad', + 'Pehuajo', + 'Jam', + 'Frederickson', + 'Aywaille', + 'Heule', + 'Kasungu', + 'Koge', + 'Mukdahan', + 'Dialakoroba', + 'Les Sorinieres', + 'Al Kiswah', + 'Dongxiaozhai', + 'Mirandela', + 'Mochizuki', + 'Hanumantanpatti', + 'Bregenz', + 'Kongjiazhuangcun', + 'Xianxi', + 'Kovin', + 'Konan', + 'La Serena', + 'Menomonie', + 'Zemmouri', + 'Nakagusuku', + 'Gharbara', + 'Oro-Medonte', + 'Qiloane', + 'Larantuka', + 'Nonoai', + 'Silvarpatti', + 'Kharagbani', + 'Nghia Lo', + 'Kissimmee', + 'Higuey', + 'Susques', + 'Pyalakurti', + 'Sleaford', + 'Barranco de Loba', + 'Rattihalli', + 'Standish', + 'Holyoke', + 'Nettadahalli', + 'Torrejon de la Calzada', + 'Nidzica', + 'Sovata', + 'Ilha Solteira', + 'Rampur Khajuriya', + 'Pappinissheri', + 'Sint Willebrord', + 'Benito Soliven', + "Sek'ot'a", 'Jhang City', - 'Altindag', - 'Tala', - 'Stockton', - 'Talkha', - 'Boa Vista', - 'Banjul', - 'Jayapura', - 'Toyama', - 'Sanandaj', - 'Khon Kaen', - 'Fangting', - 'Linghai', - 'Shorapur', - 'Koumassi', - 'Betim', - 'Tinnevelly', - 'Pasto', - 'Syracuse', - 'Bellary', - 'Bhagalpur', - 'Kisumu', - 'Zhangjiakou Shi Xuanhua Qu', - 'Maringa', - 'Kocasinan', - 'Mataram', - 'Shashemene', - 'Zaria', - 'Kumi', - 'Wanyuan', - 'Binan', - 'Chattanooga', - 'Jiexiu', - 'Baglar', - 'Padiala', - 'Da Lat', - 'Sham Shui Po', - 'Santa Fe', - 'Delhi Cantonment', - 'Cumana', - 'Barura', - 'Yuregir', - 'Nagasaki', - 'Mardan', - 'Hat Yai', - 'Qazvin', - 'Etawa', - 'Lancaster', - 'Sonipat', - 'Jundiai', - 'Greenville', - 'Toyonaka', - 'Bogra', - 'Oskemen', - 'Gifu', - 'Maungdaw', - 'Jiangjiafan', - 'Durham', - 'Dera Ghazi Khan', - 'Anapolis', - 'Pensacola', - 'Miyazaki', - 'Quilon', - 'Mulangodi', - 'Munro Turuttu', - 'Hirakata', - 'Sandakan', - 'Szczecin', - 'Brno', - 'Hejin', - 'Fayetteville', - 'Betsiboka', - 'Thies', - 'Arlington', - "Al Jahra'", - 'Kaunas', - 'Thanh Hoa', - 'Diadema', - 'Lobito', - 'Saurimo', - 'Yola', - 'Zhugang', - 'Tangail', - 'Nha Trang', - 'Khayelitsha', - 'Ad Diwaniyah', - 'Nnewi', - 'Hancheng', - 'San-Pedro', - 'Gujrat', - 'Yokosuka', - 'Tieli', - 'Asyut', - 'Gwoza', - 'Sampaloc', - 'Saki', - 'Bologna', - 'Aqtobe', - 'Cilegon', - 'Uvinza', - 'Aurora', - 'Carapicuiba', - 'Hafr al Batin', - 'Zanjan', - 'Petrolina', - 'Bairia', - 'Oyo', - 'Taytay', - 'Kisenzi', - 'Bhatpara', - 'Kukatpalli', - 'Manisa', - 'Sirur', - 'Tarlac City', - 'Okazaki', - 'Lianzhou', - 'Ceel Baraf', - 'Yidu', - 'Lingxi', - 'Ilesa', - 'Kakinada', - 'Savar', - 'Nuevo Laredo', - 'Bawshar', - 'Christchurch', - 'Gusau', - 'Zetang', - 'Palu', - 'Canberra', - 'Minamisuita', - 'Tetouan', - 'Malabon', - 'Neiva', - 'Novi Sad', - 'Huancayo', - 'Celaya', - 'Ichinomiya', - 'Caruaru', - 'Sintra', - 'Hatay', - 'Iquitos', - 'Panihati', - 'Cainta', - 'Helixi', - 'Mamou', - 'Manukau City', - 'Itaquaquecetuba', - 'Cantonment', - 'Rohtak', - 'Gaziantep', - 'Maler Kotla', - 'Bhawana', - 'Khorramabad', - 'Lipa City', - 'Butuan', - 'Dikirnis', - 'Stoke-on-Trent', - 'Takasaki', - 'Malakwal', - 'Toyohashi', - 'Chitungwiza', - 'Gebze', - 'Cibinong', - 'Lengshuijiang', - 'Panshi', - 'Az Zubayr', - 'Oxnard', - 'Vinnytsia', - 'Indio', - 'Bharatpur', - 'Petare', - 'Nagano', - 'Huichang', - 'Keelung', - 'Bauru', - 'La Florida', - 'Nicolas Romero', - 'Jinshan', - 'Baguio City', - 'Scranton', - 'Bochum', - 'Sivas', - 'Kolga', - 'Korba', - 'Qardho', - 'Rio Branco', - 'Tecamac', - 'Alanya', - 'Mandaue City', - 'Victorville', - 'Kocaeli', - 'Warri', - 'Victoria', - 'Wonsan', - 'Iligan', - 'Anguo', - "K'ebri Dehar", - 'Coventry', - 'Kayapinar', - 'Trenton', - 'Cuenca', - 'Blumenau', - 'Nanqiao', - 'Florence', - 'Buurhakaba', - 'Bengkulu', - 'Malmo', - 'Wudalianchi', - 'Shuanghe', - 'Petion-Ville', - 'Utrecht', - 'Sikar', - 'Umuahia', - 'Vitsyebsk', - 'Palmira', - 'Wuppertal', - 'Hrodna', - "Ash Shuhada'", - 'Karur', - 'Ponta Grossa', - 'Sasaram', - 'Taraz', - 'Cubal', - 'Luena', - 'Karnal', - "Yong'an", - 'Konak', - 'Minatitlan', - 'Linxia Chengguanzhen', - 'Brahmapur', - 'Chanda', - 'Caucaia', - 'Cuito', - 'Cabuyao', - 'Hongzhai', - 'Gedaref', - 'San Fernando', - 'Kawagoe', - 'Modesto', - 'Pokhara', - 'Villahermosa', - 'Van', - 'Mahilyow', - 'Wakayama', - 'Osh', - 'Kita-ku', - 'Gimpo', - 'Corrientes', - 'Franca', - 'Thari Mir Wah', - 'Nara', - 'Yakeshi', - 'Nam Dinh', - 'Sinuiju', - 'Oruro', - 'Cabimas', - 'Batangas', - 'Ibb', - 'Ahmadnagar', - 'Sarai Alamgir', - 'Semey', - 'Holguin', - 'Tungi', - 'Yingmen', - 'Sawran', - 'Olinda', - 'Praia Grande', - 'Dasarhalli', - 'Huntsville', - 'Shinjuku', - 'Alicante', - 'Cariacica', - 'Varna', - 'Honolulu', - 'Antofagasta', - 'Ambon', - 'Nice', - 'Cascavel', - 'Pamukkale', - 'Canoas', - 'Takatsuki', - 'Antonio Enes', - 'Greensboro', - 'Anaheim', - 'Plovdiv', - 'Central Coast', - 'Karsiyaka', - 'Shahjanpur', - 'Gwagwalada', - 'Alamadi', - 'Avadi', - "Tanch'on", - 'Khanapur', - 'Wad Medani', - 'Kusti', - 'Belfast', - 'Hosur', - 'Cuddapah', - 'Nakano', - 'Otsu', - 'Maseru', - 'Makiivka', + 'Vadakkanandal', + 'Kolo', + 'Montecorvino Rovella', + 'Mancio Lima', + 'Kashkar-Kyshtak', + 'Mohania', + 'Kochgawan', + 'Honiara', + 'Brejoes', + 'Krasnyy Yar', + 'Otrokovice', + 'Saidpur', + 'Nainijor', + 'Jhanjharpur', + 'Yarm', + 'Caransebes', + 'Santa Teresa del Tuy', + 'Banate', + 'Altadena', + 'Sihu', + 'Velten', + 'San Pablo', + 'Chbar Mon', + 'Baraderes', + 'Baraon', + 'Telsang', + 'Saint Budeaux', + 'Candelaria', + 'Silva Jardim', + 'Udburu', + 'Mastic', + 'Itapora', + 'Iklin', + 'Vlasotince', + 'Svay Pak', + 'Havelock North', + 'Kalipatnam', + 'Mozarlandia', + 'Kamarhati', + 'Strehaia', + 'Joshimath', + 'Bridgnorth', + 'Batticaloa', + 'Pallisa', + 'Coronel Dorrego', + 'Chelmek', + 'Hinthada', + 'Nola', + 'Little Rock', + 'New Braunfels', + 'Havre', + 'Lavezares', + 'Lamphun', + 'Karajgi', + 'Maheshram', + 'Rangasamudram', + 'Cuango', + 'Tonse East', + 'Morlanwelz-Mariemont', + 'Otavalo', + 'Nerkunram', + 'Jaque', + 'Okha', + 'Bhamo', + 'Gadabay', + 'Timbauba', + 'Andapafito', + 'Punta Umbria', + 'Vanj', + 'Kun Puhal', + 'Timmendorfer Strand', + 'Pau dos Ferros', + 'Matsuzaka', + 'Columbus', + 'Putina', + 'Kotdwara', + 'Tagana-an', + 'Ajdovscina', + 'Siegen', + 'Sangin', + 'Bihpuriagaon', + 'Biswanath Chariali', + 'Chiva', + 'Paszto', + 'Ban Wang Daeng', + 'Karlsfeld', + 'El Alamo', + 'Lelystad', + 'Chand Chaur', + 'Nioaque', + 'Yargatti', + 'Hilzingen', + 'Ayvacik', + 'Suceava', + 'Padova', + 'Carneys Point', + 'Winkfield', + 'Absecon', + 'Guntakal Junction', + 'Bhadwar', + 'Iwaka', + 'San Pedro de Lloc', + 'Key Largo', + 'Monterotondo', + 'Al Hillah', + 'Zaouia Ait Ishak', + 'Floriana', + 'Ubajara', + 'Ouled Fayet', + 'Novo Cruzeiro', + 'Selwyn', + 'Phitsanulok', + 'Amarzgane', + 'Punakha', + 'Liperi', + 'Biblis', 'Pavlodar', - 'Chon Buri', - 'Naga City', - 'Sariyer', - 'Brest', - 'Meram', - 'Gomez Palacio', - 'Paulista', - 'Rajahmundry', - 'Koshigaya', - 'Vung Tau', - 'Jeonju', - 'Alwar', - 'Tokorozawa', - 'Sumqayit', - 'Vitoria da Conquista', - 'Simferopol', - 'Buon Ma Thuot', - 'Serekunda', - 'Islip', - 'Cuernavaca', - 'Markham', - 'Bielefeld', - 'Uberaba', - 'Jitpur', - 'Bydgoszcz', - 'Tangdong', - 'Chinju', - 'Corpus Christi', - 'Fort Wayne', - 'Reading', - 'Randburg', - 'Matadi', - 'Bonn', - 'Iwaki', - 'Oshawa', - 'Shah Latif Town', - 'Sambalpur', - 'Fort Collins', - 'Jackson', - 'Yingzhong', - 'Santo Domingo de los Colorados', - 'Uruapan', - 'Lublin', - 'Tampere', - 'Muzaffarpur', - 'Vina del Mar', - 'Tepic', - 'Khipro', - 'Hangu', - 'Asan', - 'Chak Jhumra', - 'Myrtle Beach', - 'Soledad de Graciano Sanchez', 'Salalah', - 'Santarem', - 'Yanbu', - 'Maebashi', - 'Dumai', - 'Beylikduzu', - 'Ganca', - 'Asahikawa', - 'Kendari', - 'Wonju', - 'Birkat as Sab`', - 'Lafia', - 'Dahuk', - 'Finglas', - 'Kamarhati', - 'Thai Nguyen', - 'Bamiantong', - 'Nicosia', - 'Sao Vicente', - 'Ribeirao das Neves', - 'Guediawaye', - 'Ciudad Obregon', - 'Sao Jose dos Pinhais', - 'Campiernagar', - 'Phatthaya', - 'Debrecen', - 'Mirpur Mathelo', - 'Sultanbeyli', - 'Bijapur', - 'Cabanatuan City', - 'Tharad', - 'Antioch', - 'Si Racha', - 'Salamanca', - 'Ratnagiri', - 'Ulanhot', - 'Koriyama', - 'Yunzhong', - 'Roodepoort', - 'Pucallpa', - 'San Pedro', - 'Pelotas', - 'Rampur', - 'Kuching', - 'Cotabato', - 'Cimanggis', - 'Gonaives', - 'Nazret', - 'Kikuyu', - 'Kluang', - 'Mekele', - 'Binxian', - 'Nantes', - 'Vaughan', - 'Vitoria', - 'Shimoga', - 'Lansing', - 'Uige', - 'Hotan', - 'Camaguey', - 'Taourirt', - 'San Salvador de Jujuy', - 'Kashipur', - 'Thu Dau Mot', - 'Al Kut', - 'Lexington', - 'Sukabumi', - 'Munster', - 'Menongue', - 'Mobile', - 'Gode', - 'Okene', - 'Junagadh', - 'Guasavito', - 'Nukus', - "Kaech'on", - 'Tehuacan', - 'Coatzacoalcos', - 'Muhanga', - 'Youngstown', - 'Zalantun', - 'Katsina', - 'Puerto Plata', - 'Henderson', - 'Gwangmyeongni', - 'Geita', - 'Taubate', - 'An Nhon', - 'Fontibon', - 'Hapur', - 'Kot Radha Kishan', - 'Barueri', - 'San Salvador', - 'Savannah', - 'Naha', - 'Bari', - 'Xiaoli', - 'Trichur', - 'Mannheim', - 'Bor', - 'Ca Mau', - 'Saint-Denis', - 'San Miguelito', - 'Muar', - 'Kasur', - 'Usme', - 'Barddhaman', - 'Poughkeepsie', - 'Kingston upon Hull', - 'Binangonan', - 'Temara', - 'Attiecoube', - 'Jiayuguan', - 'Pasir Gudang', - 'Gorgan', - 'Tanza', - 'Panvel', - 'Santa Ana', - 'Guaruja', - 'Nizamabad', - 'Quy Nhon', - "Ha'il", - 'Datang', - 'Longquan', - 'Mitchells Plain', - 'Yokkaichi', - 'Chalco', - 'Shahriar', - 'Shahr-e Qods', - 'Ciudad del Este', - 'Ann Arbor', - 'St. Paul', - 'Karlsruhe', - 'Safi', - 'Ciudad Benito Juarez', - 'Karawang', - 'Sariwon', - 'Suzano', - 'Newark', - 'Nghi Son', - 'Parbhani', - 'Puerto Princesa', - 'Hisar', - 'Windsor', - 'Kasugai', - 'Ciudad Santa Catarina', - 'Puerto La Cruz', - 'Fatehpur', - 'Ciudad Victoria', - 'Playa del Carmen', - 'Yesilyurt', - 'Yonghetun', - 'Irvine', - 'Kashan', - 'Minna', - 'Sumbawanga', - 'Akita', - 'Kurume', - 'Az Zaqaziq', - 'Palmas', - 'Montpellier', - 'Vila Nova de Gaia', - 'Bahia Blanca', - 'Al Waqf', - 'San Bernardo', - 'San Juan del Rio', - 'Armenia', - 'Augsburg', - 'Qianzhou', - 'Popayan', - 'Al Qunfudhah', - 'Yakou', - 'Oulgaret', - 'Awasa', - 'Ingraj Bazar', - 'Oaxaca', - 'Binjai', - 'Barr Elias', - 'Khairpur Tamewah', - 'Sucre', - 'Al `Ajami', - 'Al Matariyah', - 'Bada Barabil', - 'Ash Shamiyah', - 'Oyster Bay', - 'Ar Raqqah', - 'Chakwal', - 'Oakashicho', - 'Afyonkarahisar', - 'Dod Ballapur', - 'Camacari', - 'Ciudad General Escobedo', - 'Catania', - 'Jember', - 'Al Mubarraz', - 'Pekalongan', - 'Los Mochis', - 'Toshima', - 'Pachuca', - 'Yangsan', - 'Valladolid', - 'Tampico', - 'Bihar', - 'Espoo', - 'Malabo', - 'Pilar', - 'Valparaiso', - 'Cirebon', - 'Tagum', - 'Darbhanga', - 'Comilla', - 'Battalgazi', - 'Sorong', - 'Shubrakhit', - 'Floridablanca', - 'Silang', - 'Eloy Alfaro', - 'Pondokaren', - 'Sikandarabad', - 'Kafr Saqr', - 'Vila Teixeira da Silva', - 'Panipat', - 'Rangpur', - 'Bialystok', - 'Canton', - 'Asheville', - 'Flint', - 'Vigo', - 'Coacalco', - 'Aizawl', - 'Bali', - 'Bradford', - 'Mabalacat', - 'Dexing', - 'Winter Haven', - 'Graz', - 'Palni', - 'Resistencia', - 'Chimbote', - 'Strasbourg', - 'Bergen', - 'Gatineau', - 'Surajgarha', - 'Tegal', - 'Anchorage', - 'Batna', - 'Aarhus', - 'Morioka', - 'Lincoln', - 'Hulin', - "Hong'an", - 'Karimnagar', - 'Santa Maria', - 'Dewas', - 'Gungoren', - 'Magway', - 'Farg`ona', - 'Hugli', - 'Chunchura', - 'Setif', - 'Sonpur', - 'Meguro', - 'Machala', - 'San Lorenzo', - 'Jersey City', - 'Ichalkaranji', - 'Punto Fijo', - 'Varzea Grande', - 'Tirupati', - 'Pathein', - 'Chernihiv', - 'Sincelejo', - 'Cluj-Napoca', - 'Sekondi', - 'Tacna', - 'Tin Shui Wai', - 'Juazeiro do Norte', - 'Al Qurnah', - 'Korhogo', - 'Bhatinda', - 'Katowice', - 'Jalna', - 'Foz do Iguacu', - 'Bolton', - 'San Pablo', - 'Huixquilucan', - 'Plano', - 'Qillin', - 'Croix-des-Bouquets', - 'San Juan Sacatepequez', - 'Ljubljana', - 'Fukushima', - 'Bago', - 'Delmas', - 'Fuquan', - 'Ibaraki', - 'Shreveport', - 'Ostrava', - 'Poltava', - 'Wiesbaden', - 'Satna', - 'Sannai', - 'Huozhou', - 'Temuco', - 'Ica', - 'Tongchuanshi', - 'Chuncheon', - 'Sakarya', - 'Inegol', - 'Kaura Namoda', - 'Davenport', - 'Malard', - 'Lubbock', - 'Lakeland', - 'Bukhara', - 'Sumbe', - 'Mingaora', - 'Corlu', - 'Kherson', - 'Lucena', - 'Petropolis', - 'Mamuju', - 'Mau', - 'Long Xuyen', - 'Gyeongsan', - 'Barasat', - 'South Bend', - 'Pematangsiantar', - 'Maastricht', - 'Viet Tri', - 'Sunderland', - 'Gagnoa', - 'Xingsha', - 'Dire Dawa', - 'Lashkar Gah', - 'Itagui', - 'Juliaca', - 'Chula Vista', - 'Posadas', - 'Farrukhabad', - 'Chandler', - 'Kunsan', - 'Yeosu', - 'Qarshi', - 'Saugor', - 'Khmelnytskyi', - 'Nassau', - 'Ratlam', - 'Crato', - 'Shaowu', - 'Pasarkemis', - 'Cotia', - 'Taboao da Serra', - 'San Mateo', - 'Tsu', - 'Rockford', - 'Imperatriz', - 'Los Alcarrizos', - 'Soubre', - 'Szekesfehervar', - 'Majene', - 'Sumida', - 'Chopda', - 'Gabela', - 'Dayr az Zawr', - 'Iasi', - 'Sarta', - 'Eugene', - 'Iksan', - 'My Tho', - 'Nguru', - 'Arnavutkoy', - 'Derby', - 'Mito', - "Kunp'o", - 'Gombe', - 'Bijiao', - 'Cherkasy', - 'Bayat', - 'Handwara', - 'Kunduz', - 'Drug', - 'Wilmington', - 'Monchengladbach', - 'Gijon', - 'Brahmanbaria', - 'Santa Clarita', - 'Thai Binh', - 'Ichihara', - 'Tarija', - 'Shibin al Kawm', - 'Plymouth', - 'Aswan', - 'Bimo', - 'Gilbert', - 'Maradi', - 'Xiangkhoang', - 'Anantapur', - 'Adiyaman', - 'Kutahya', - 'Maraba', - 'Saskatoon', - 'Sumare', - 'Killeen', - 'Nagaoka', - 'Djelfa', - 'Sumy', - 'Khwazakhela', - 'Chernivtsi', - 'Suncheon', - 'Kibaha', - 'Sfax', - 'Gent', - 'Gravatai', - 'Antsirabe', - 'Feni', - 'Imphal', - 'Taunggyi', - 'Nogales', - 'Ed Daein', - 'Dezful', - 'Mossoro', - 'Round Lake Beach', - 'Potosi', - 'Osmaniye', - 'Itajai', - 'North Las Vegas', - 'Taluqan', - 'Constanta', - 'Luque', - 'Yao', - 'Jalalabad', - 'Nawabshah', - 'Talisay', - 'Gelsenkirchen', + 'Tysvaer', + 'Yapqan', + 'Vetapalem', + 'Baisari', + 'Boryeong', + 'Dhanauli', + 'Atenco', + 'Little Chute', + 'Mimasaka', + 'Champapur', + 'Itamonte', + 'Marple', + 'El Callao', + 'Whanganui', + 'Korschenbroich', + 'Zhuqi', + 'Asfarvarin', + 'Kodayattur', + 'Yozyovon', + 'Thompson', + 'Wingles', + 'Karliova', + 'Radyvyliv', + 'Mollendo', 'Jagdalpur', - 'Tchibota', - 'Kafr ad Dawwar', - 'Quilmes', - 'Wollongong', - 'Zhytomyr', - 'Volta Redonda', - 'Fukui', - 'Arrah', - 'Malolos', - 'Heroica Nogales', - 'Bariadi', - 'Hong', - 'Oume', - 'Fuchu', - 'Minato', - 'Boksburg', - 'Olongapo', - 'Quang Ngai', - 'Al Hamzah', - 'Kennewick', - 'Qo`qon', - 'Kotri', - 'St. Petersburg', - 'Misratah', - 'Aydin', - 'Singa', - 'Manta', - 'Tallahassee', - 'Kakogawacho-honmachi', - 'Isparta', - 'Siverek', - 'Ndulo', - 'Antalya', - 'Huayin', - 'Hiratsuka', - 'Raniyah', - 'Annaba', - 'Governador Valadares', - 'Ondo', - 'Etawah', - 'Siddhirganj', - 'Horlivka', - 'Indaiatuba', - 'Bloemfontein', - 'Ap Da Loi', - 'Turkmenabat', - 'Malkajgiri', - 'Vitoria-Gasteiz', - 'Germiston', - 'Nonthaburi', - 'Verona', - 'Tuzla', - 'Westminster', - 'Laredo', - 'Kuala Terengganu', - 'San Pedro Carcha', - 'Mocamedes', - 'Irving', - 'Turmero', - 'Tokushima', - 'Sao Carlos', - 'Longueuil', - 'Marilao', - 'Tuni', - 'Ash Shatrah', - 'Sab` al Bur', - 'Fort-de-France', - 'Mawlamyine', - 'Peoria', - 'Godome', - 'Rapar', - 'Samastipur', - 'Aksaray', - 'Shinozaki', - 'Parnamirim', - 'Kiziltepe', - 'Jhenida', - 'Turku', - 'Aachen', - 'Begusarai', - 'Kediri', - 'Kanggye', - 'Chiayi', - 'Cekme', - 'Hakodate', - 'Tacloban', - 'Junagarh', - 'Braunschweig', - 'Iskenderun', - 'Pecs', - 'Soka', - 'Nedumana', - 'Higuey', - 'Los Teques', - 'Montgomery', - 'Jinshi', - 'Wolverhampton', - 'Pointe-a-Pitre', - 'Al Fallujah', - 'Timisoara', - 'Bata', - 'Rach Gia', - 'Companiganj', - 'Venice', - 'Babol', - 'Sao Jose', - "Al Bayda'", - 'Natogyi', - 'Kurmuk', - 'Ras el-Barr', - 'Kalar', - 'Bojnurd', - 'Turkistan', - 'New Delhi', - 'Las Condes', - 'Goma', - 'Rishon LeZiyyon', - 'Campeche', - 'Manzhouli', - 'Tiruvottiyur', - 'Palangkaraya', - 'Chesapeake', - 'Burnaby', - 'Ramnagar', - 'Limeira', - 'Carmen', - 'Gandhidham', - 'Banikoara', - 'Chemnitz', - 'Salumbar', - 'Kyongju', - 'Glendale', - 'Sibu', - "Qa'em Shahr", - 'Parana', - 'Buyukcekmece', - 'Kiel', - 'Sahiwal', - 'A Coruna', - 'Navotas', - 'Santa Clara', - 'Mehrabpur', - 'Yamagata', - 'York', - 'Khomeyni Shahr', - 'Beykoz', - 'Tsukuba-kenkyugakuen-toshi', - 'Macae', - 'Gyor', - 'Al `Ashir min Ramadan', - 'Mahajanga', - 'Mount Lavinia', - 'Northampton', - 'Krishnarajpur', - 'Hafizabad', - 'Nelamangala', - 'Beichengqu', - 'Abertawe', - 'Rivne', - 'Gdynia', - 'Nashua', - 'Barnsley', - 'Taiping', - 'Rondonopolis', - 'Sao Jose de Ribamar', - 'Puducherry', - 'Merlo', - 'Portoviejo', - 'Damanhur', - 'Garland', - 'Kabinda', - 'Jessore', - 'Kesbewa', - 'Fuji', - 'Eindhoven', - 'Sabzevar', - 'Dourados', - 'Bahir Dar', - 'Yoshiicho-shimobaru', - 'Myitkyina', - 'Ramgundam', - 'Palanpur', - 'Tuy Hoa', - 'Sasebo', - 'Sapele', - 'Biratnagar', - 'Pandharpur', - 'Qyzylorda', - 'St. Catharines', - 'Chigasaki', - 'Araraquara', - 'Kahama', - 'Halle', - 'Americana', - 'Zhangping', - 'Man', - 'Sete Lagoas', - 'Banchpar', - 'Haeju', - 'Soyapango', - 'Masaurhi Buzurg', - 'Baruta', - 'Duzce', - 'Marilia', - 'Katihar', - 'Scottsdale', - 'Tarapoto', - 'Atushi', - 'Abi al Khasib', - 'Jacarei', - 'Anju', - 'Bunkyo-ku', - 'Byatarayanpur', - 'Ahor', - 'Diaobingshancun', - 'Magdeburg', - 'Yato', - 'Matsumoto', - 'Szeged', - 'Chimoio', - 'Kasulu', + 'Nandgaon', + 'Toyono', + 'Gryfino', + 'Ventspils', + 'Sibiti', + 'Shishi', + 'Lulhaul', + 'Bhalpatti', + 'Norman', + 'Halesowen', + 'Al Midhnab', + 'Viroflay', + 'Nether Providence', + 'Anglet', + 'Seven Corners', + 'Kurort Steinbach-Hallenberg', + 'Eden Prairie', + 'Firestone', + 'Shanywathit', + 'North Wantagh', + 'Grenzach-Wyhlen', + 'Chiari', + 'Keningau', + 'Miranda do Corvo', + 'Tenambakkam', + 'Tilburg', + 'Budipuram', + 'Nallamada', + 'San Giovanni la Punta', + 'Middle', + 'Nanzhai', + 'Castelfiorentino', + 'Mont-Royal', + 'Khasbalanda', + 'Zirara', + 'Carluke', + 'Kawatana', + 'Idangansalai', + 'Mandi', + 'Sabanitas', + 'Balangir', + 'Phillipsburg', + 'Poniatowa', + 'Jizzax', + 'Corumbaiba', + 'Sampues', + 'Muynoq', + 'Valga', + 'Daharia', + 'Mundakkal', + 'Qarqin', + 'Gandu', + 'Los Vilos', + 'Arkonam', + 'Kananya', + 'South Middleton', + 'Devsar', + 'Kamin-Kashyrskyi', + 'Hauterive', + 'Raitar', + 'Swords', 'Elche', - 'Tarsus', - 'Ivano-Frankivsk', - 'Chofugaoka', - 'Gonzalez Catan', - 'Nyiregyhaza', - 'Wuyishan', - 'Shenmu', - 'Tuticorin', - 'As Sib', - 'Ganganagar', - 'Brasov', - 'Lafayette', - 'Amol', - 'Stavanger', - 'Sandnes', - 'Monclova', - 'Chishui', - 'Djougou', - 'Norfolk', - 'Mirpur Khas', - 'Lille', - "P'yongsong-si", - "P'yong-dong", - 'Centurion', - 'North Hempstead', - 'Tinkhang', - 'Rewa', - 'Pakdasht', - 'Kajang', - 'Petah Tiqwa', - 'Abha', - 'Freiburg im Breisgau', - 'Al Minya', - 'Iseyin', - 'Central District', - 'Gaborone', - 'Juazeiro', - 'Zinder', - 'Bole', - 'Ganda', - 'Uluberiya', - 'Bulandshahr', - 'Banda Aceh', - 'Najafabad', - 'Shibuya-ku', - 'Bayamo', - 'Limassol', - 'Borujerd', - 'Garcia', - 'Arapiraca', - 'Miri', - 'Maracanau', - 'Oral', - 'Craiova', - 'Formosa', - 'Appleton', - 'Chauhanpatti', - 'Bo', - 'Mambere', - 'Damboa', - 'Groningen', - 'Ipswich', - 'Teluk Intan', - 'Cannanore', - 'Raichur', - 'Okara', - 'Saga', - 'Saidpur', - "Lin'an", - 'Machilipatnam', - 'Beni', - 'Nazipur', - 'Purwokerto', - 'Biyala', - 'Madan', - 'Rancagua', - 'Phu Yen', - 'Neuquen', - 'Divinopolis', - 'Qarchak', - 'Ormoc', - 'Fresnillo', - 'Granada', - 'Son Tay', - 'Singkawang', - 'Zegoua', - 'Kulai', - 'Barishal', - 'Pali', - 'Songadh', - 'Gadda Madiral', - 'Ordu', - 'Kosice', - 'Kasukabe', - 'Mirialguda', - 'Aguadilla', - 'Envigado', - 'Haridwar', - 'Rock Hill', - 'Fremont', - 'Vizianagaram', - 'Coban', - 'Khenifra', - 'Guantanamo', - 'Krefeld', - 'Sabya', - 'Fargo', - 'Raisinghnagar', - 'Usak', - 'Pathardi', - 'Mage', - 'Gulfport', - 'Neya', - 'Mel Palaiyam', - 'Novo Hamburgo', - 'Ipatinga', - 'Saqultah', - 'Choloma', - 'Kropyvnytskyi', - 'Khatima', - 'Dasoguz', - 'Khanewal', - 'Petlad', - 'Kamianske', - 'Bremerton', - 'Ageoshimo', - 'Changhua', - 'Regina', - 'Badalona', - 'Dianbu', - 'Rio Verde', - 'Meycauayan', - 'Presidente Prudente', - 'Green Bay', - 'Varamin', - 'Padangsidempuan', - 'Uacu Cungo', - 'Enterprise', - 'Hunchun', - 'Tarrasa', - 'Ternopil', - 'Kimberley', - 'Nadiad', - 'Toamasina', - 'Rennes', - 'Mutare', - 'Cikupa', - 'Ratodero', - 'Chuadanga', - 'Carlos Manuel de Cespedes', - "Nong'an", - 'Ota', - 'Itaborai', - 'Puerto Vallarta', - 'Capiata', - 'Viamao', - 'Takarazuka', - 'Chapeco', - 'Banfield', - 'Toluca', - 'Atsugicho', - 'Paramaribo', - "Cox's Bazar", - 'Bandar-e Bushehr', - 'Itapevi', + 'Shakhtinsk', + 'Meadow Woods', + 'Kadiapattanam', + 'Sherrelwood', + 'Altamura', + 'Bloomingdale', + 'Hesperia', + 'Marathon', + 'Sogndal', + 'Timberlake', + 'Upper Gwynedd', + 'Saint-Andre-de-Cubzac', + 'Chelmsford', + 'Udaipur Bithwar', + 'Provins', + 'Prievidza', + 'Loiyo', + 'Dabou', + 'Kastav', + 'Vellarivalli', + 'Orchards', + 'Summerfield', + 'Ilidza', + 'Badiadka', + 'Ypsilanti', + 'Warsaw', + 'Randers', + 'Aqtobe', + 'Rosendael', + 'New Paltz', + 'Port Neches', + 'Cranford', + 'Hadamar', + 'Bergenfield', + 'Orland Park', + 'Ba Chuc', + 'Fomento', + 'Tegueste', + 'Omagh', + 'Maria Pinto', + 'Ban Suan', + 'Cuernavaca', + 'Leominster', + 'Eidsvold', + 'Sohtha', + 'Todi', + 'Choszczno', + 'Yamato', + 'Lengquancun', + 'Sultanpur Mazra', + 'Boumalne', + 'Manises', + 'Xiaoli', + 'Zolochiv', + 'Pyapon', + 'Lake Ronkonkoma', + 'Hasselt', + 'El Minie', + 'Ambinanindovoka', + 'Trittau', + 'Mulavur', + 'Loyish Shaharchasi', + 'Bembereke', + 'Antratsyt', + 'Sayalkudi', + 'Chorrocho', + 'Ipiau', + 'Pembroke Pines', + 'Palghar', + 'Frodsham', + 'Sullana', + 'Sunamganj', + 'Finike', + 'Qiryat Mozqin', + 'Correia Pinto', + 'Macheng', + 'Ban Du', + 'Agde', + 'Santa Quiteria', + 'Voyenno-Antonovka', + 'Kapellen', + 'An Chau', + 'Valera', + 'Glen Parva', + 'Mahikeng', + 'Gland', + 'Northallerton', + 'Su-ngai Kolok', + 'Ash Shaykhan', + 'Roztoky', + 'Kokomo', + 'Duren', + 'Iver', + 'Campanha', + 'Befody', + 'Vaisampakkal', + 'Ucar', + 'Janesville', + 'Aksehir', + 'Buur Gaabo', + 'Ouled Fares', + 'Eseka', + 'Cossimbazar', + 'Abingdon', + 'Andrychow', + 'Calimesa', + 'Manati', + 'Hannoversch Munden', + 'Nalakadoddi', + 'Xiaoba', + 'Suo-Oshima', + 'Beaver Dam', + 'Oulad Ouchchih', + 'Analavory', + 'Lopez Jaena', + 'Midland', + 'Zhongbu', + 'Tarrytown', + 'Brighton', + 'Vannes', + 'Rajgir', + 'Kuppam', + 'Kottakota', + 'Onesti', + 'Massa', + 'Sebastian', + 'Benahavis', + 'Gigmoto', 'Probolinggo', - 'Hialeah', - 'Tanjore', - "Ji'an Shi", - 'Hachinohe', - 'Ijebu-Ode', - 'Barra do Dande', - 'Mezitli', - 'Sandton', - 'Beji', - 'Cork', - 'Dili', - 'Owo', - 'Swindon', - 'Myeik', - 'Cabo Frio', - 'Kichha', - 'Katri', - 'Saricam', - 'Gueckedou', - 'Neyshabur', - 'Sousse', - 'Tabora', - 'Soc Trang', - 'Dagarua', - 'Deltona', - 'Tchaourou', - 'Rufisque', - 'San Bernardino', - 'Duekoue', - 'Gainesville', - 'Sambhal', - 'San Felipe', - 'Saveh', - 'Mainz', - 'Santa Luzia', - 'Chi Linh', - 'La Vega', - 'Singrauliya', - 'El Jadid', - 'Kremenchuk', - 'Ashdod', - 'Prizren', - 'Spring Valley', - 'Thatta', - 'Yenisehir', - 'Al Khubar', - 'Osisioma', - 'Tacoma', - 'Tulua', - 'Zanzibar', - 'Kafue', - 'Konibodom', - 'Petrel', - 'Messina', - 'Pangkalpinang', - 'Roanoke', - 'Bitung', - 'Santo Tomas', - 'San Miguel', - 'Sabadell', - 'Lubeck', - 'Naihati', - 'Arakawa', - 'Galati', - 'Babylon', - 'Laayoune', - 'Butembo', - 'Oviedo', - 'Tapachula', - 'Porbandar', - 'Sao Leopoldo', - 'Apapa', - 'Netanya', - 'Qostanay', - 'Alor Setar', - 'Wayaobu', - 'Zielona Gora', - 'Batu', - 'Gujiao', - 'Jose C. Paz', - 'Yamunanagar', - 'Banjarbaru', - 'Ayacucho', - 'Wellington', - 'Penalolen', - 'Dongxing', - 'Lutsk', - 'La Ceiba', - 'Ar Ruseris', - 'Hortolandia', - 'Pallavaram', - 'Marg`ilon', - 'Jiutepec', - 'Brownsville', - 'Golmud', - 'San Rafael', - 'Sidi Aissa', - 'Khargone', - 'As Samawah', - 'Matrah', - 'Comalcalco', - 'Cua', - 'Almere', - 'Vantaa', - 'Mokpo', - 'La Victoria', - 'Warnes', - 'Cascais', - 'Cigli', - 'Marcory', - 'Chilas', - 'Sikasso', - 'Osan', - 'Oakville', - 'Secunderabad', + 'Valkenswaard', + 'Momostenango', + 'Det Udom', + 'Myrza-Ake', + 'Bou Saada', + 'Maur Kalan', + 'Cholargos', + 'Senglea', + 'Baranzate', + 'Point Fortin', + 'Wutiancun', + 'South Whittier', + 'Tiran', + 'Fitchburg', + 'Eyvan', + 'Burbaliq', + 'Heanor', + 'Rancharia', + 'Karumattampatti', + 'Piagapo', + 'Rishivandiyam', + 'Amposta', + 'Tultepec', + 'Cabaret', + 'Cloquet', + 'Plouzane', + 'Wilnecote', + 'Presidente Epitacio', + 'Mossaka', + 'Piano di Sorrento', + 'Colomiers', + 'Kaithal', + 'Cotoca', + 'Kofele', + 'Nangong', + 'Yhu', + 'Chepo', + 'Kyoto', + 'Sorocaba', + 'Phagwara', + 'Ludenscheid', + 'Guotang', + 'Vayakkalattu', + 'Mianeh', + 'Closepet', + 'Kronshagen', + 'Unye', + 'Vale de Cavalos', + 'Zitorada', + 'Ramnicu Valcea', + 'Samastipur', + 'West Hempstead', + 'Saunshi', + 'Atamyrat', + 'Morfelden-Walldorf', + 'Okahandja', + 'Shaoyu', + 'Mirpur Mathelo', + 'Odendaalsrus', + 'Jisrayn', + 'Elankur', + 'Facatativa', + 'Leshan', + 'Halle', + 'Paharpur', + 'Dialafara', + 'Villeneuve-Loubet', + 'Regidor', + 'Pukkulam', + 'Torre Boldone', + 'Tirukkalikkunram', + 'Xihuangcun', + 'Artemida', + 'Lorrach', + 'Governador Valadares', + 'Virton', + 'Xochiatipan de Castillo', + 'Ehingen an der Donau', + 'Carlosama', + 'Zarzal', + 'Terni', + 'Tomaszow Mazowiecki', + 'Villa Union', + 'North Lakes', + 'Lospalos', + 'Wuhan', + 'La Puebla del Rio', + 'Caraga', + 'Drolshagen', + 'Mahad', + 'Charleville', + 'Dhorimanna', + 'Hakodate', + 'Soumagne', + 'Magra', + 'Chulumani', + 'Alloa', + 'Montegranaro', + 'Singhara Buzurg', + 'Errahalli', + 'Sakleshpur', + 'Serris', + 'Zell am See', + 'Danbury', + 'Yoshioka', + 'Eruh', + 'Kinshasa', + 'Mellieha', + 'Ibadan', + 'Filottrano', + 'Dongjiangshui', + 'Mariehamn', + 'Mbalmayo', + 'Cobija', + 'Cairo', + 'Jatara', + 'Famalicao', + 'Bayonet Point', + 'Trang Bang', + 'Fandriana', + 'Copceac', + 'Nhamunda', + 'Sriperumbudur', + 'Kitamoto', + 'Le Grand-Quevilly', + 'Higuera de Zaragoza', 'Sa Dec', - 'Turbat', - 'El Tigre', - 'Bhuj', - 'Sodo', - 'Isesaki', - 'Jerez de la Frontera', - 'College Station', - 'Norwich', - 'Czestochowa', - 'Monghyr', - 'Luton', - 'Chapra', - 'Sidi Bel Abbes', - 'Zhubei', - 'Tumaco', - 'Trondheim', - 'Mallawi', - 'Kure', - 'Kuje', - 'Bhadravati', - 'Taito', - '`Aqrah', - 'Cao Lanh', - 'Xigujing', - 'Irakleio', - 'Criciuma', - 'Panchkula', - 'Mirpur Bhtoro', - 'Burhanpur', - 'Olympia', - 'Oberhausen', - 'Burgas', - 'Sobral', - 'Clarksville', - 'Trece Martires City', - 'Gangneung', - 'Pagadian', - 'Quilicura', - 'Kiratot', - 'Linz', - 'Arroyo Naranjo', - 'Bukit Mertajam', - 'Dongning', - 'Rostock', - 'Kapra', - 'Yonkers', - 'Burutu', - 'Mostoles', - 'Moreno Valley', - 'Thousand Oaks', - 'Legazpi City', - 'Fontana', - 'Panabo', - 'Puerto Cabello', - "Ich'on", - 'Beersheba', - 'Bila Tserkva', - 'Santo Agostinho', - 'Oulu', - 'Luziania', - 'Ciputat', - 'Guarenas', - 'Mohammedia', - 'Babruysk', - 'Taisheng', - 'Sunyani', - 'Lubuklinggau', - 'Ashaiman', - 'Ambala', - 'Zamora', - 'Chungju', - 'Kasangati', - 'Kharagpur', + 'Plougastel-Daoulas', + 'IJsselstein', + 'Rivoli', + 'Neu Bleckede', + 'Am-Timan', + 'Jobabo', + 'Lerik', + 'Chaiyo', + 'Bergen op Zoom', + 'Niederzier', + 'Sesimbra', + 'Jagta', + 'Levis', + "Stara L'ubovna", + 'Horbury', + 'Bialy Kamien', + 'Alamo', + 'Palaio Faliro', + 'Roselle Park', + 'Rudewa', + 'Kotma', + 'Cojedes', + 'Guangming', + 'Shanwei', + 'Vanimo', + 'Alesd', + 'Sidmouth', + 'Hamah', + 'Alejandro Korn', + 'Emsworth', + 'Shenjiabang', + 'Calatayud', + 'Furano', + 'Moca', + 'Viraghattam', 'Farshut', - 'Monywa', - 'Nishitokyo', - 'Robertsonpet', - 'Dindigul', - 'Milton Keynes', - 'Marawi City', - 'Morogoro', - 'Raniwara Kalan', - 'Solihull', - 'Parakou', - 'Damietta', - 'Shimla', - 'Padova', - 'Banjar', - 'Cidade de Nacala', - 'Passo Fundo', - 'Dinajpur', - 'Hospet', - 'Islington', - 'Talca', - 'Hickory', - 'Amarillo', - 'Ifakara', - 'Pamplona', - 'Northcote', - 'Maldah', - 'San Carlos City', - 'Jiutai', - 'Phan Thiet', - 'Puqi', - 'Khan Yunis', - 'Ongole', - 'Brahmanpara', - 'Biskra', - 'Bingerville', - 'Betigeri', - 'Sioux Falls', - 'Mpanda', - 'Ternate', - 'Kassel', - 'Sakaka', - 'Sejong', - 'Quetzaltenango', - 'Coquimbo', - 'Tekirdag', - 'Luzhang', - 'Kodumur', - 'Kukawa', - 'Geneva', - 'Huntington', - 'Ellore', - 'Evansville', - 'Kinh Mon', - 'Birjand', - 'Barrancabermeja', - 'La Guaira', - 'Loja', - 'Mandi Burewala', - 'Lauro de Freitas', - 'Mazabuka', - 'Deoghar', - 'Tanjungpinang', - 'Phu Tu Son', - 'Chhindwara', - 'Iringa', - 'Lingampalli', - 'Waterbury', - 'Mokameh', - 'Luxor', - 'Arica', - 'Las Tunas', - 'Qal`at Bishah', - 'Frisco', - 'Ha Tinh', - 'Richmond Hill', - 'Timayy al Imdid', - 'Al Khums', - 'Charleroi', - 'Lorain', - 'Matsue', - 'Tarakan', - 'Loures', - 'Pingzhen', - 'Radom', - 'Petropavl', - 'Rio Claro', - 'Maroua', - 'Cajamarca', - 'Qina', - "Mai'Adua", - 'Hebron', - 'Puri', - 'Sidfa', - 'Soio', - 'Menemen', - 'Kalamazoo', - 'Haldia', - 'Jacobabad', - 'Khandwa', - 'Aberdeen', - 'Huacho', - 'Almeria', - 'Yachiyo', - 'Nandyal', - 'Pulimaddi', - 'Georgetown', - 'Morena', - 'Galveston', - 'Nasim Shahr', - 'Cosenza', - 'Guacara', - 'Kabankalan', - 'Nagareyama', - 'Aracatuba', - 'Vinh Long', - 'Lang Son', - 'Az Zawiyah', - 'Isanlu', - 'Rio Cuarto', - 'Lochau', - 'Karjat', - 'At Taji', - 'Spartanburg', - 'Lahad Datu', - 'Drabar', - 'Madiun', - 'Santa Tecla', - 'Santa Barbara', - 'Pristina', - 'Uripa', - 'Khowy', - 'Gbadolite', - 'Huangyan', - 'Laqtah', - 'Amroha', - 'Lunga-Lunga', - 'Trieste', - 'Sunrise Manor', - 'Torun', - 'Martapura', - 'Rani', - 'Kankan', - 'Chakradharpur', - 'Helong', - 'Segamat', - 'Bhiwani', - 'Bhind', - 'Huntington Beach', - 'Hobart', - 'Tocuyito', - 'Baure', - 'Higashi-Hiroshima', - 'Marica', - 'Grand Prairie', - 'Ciudad Madero', - 'Itami', - 'Zakhu', - 'Kodaira', - 'Rajin', - 'Alcala de Henares', - 'Parma', - 'Overland Park', - 'Huanuco', - 'Kusong', - 'Brescia', - 'Zipaquira', - 'Khammam', - 'Kouribga', - 'McKinney', - 'Madhyamgram', - 'Sinop', - 'Kajo Kaji', - 'Viransehir', - 'Ghandinagar', - 'Rzeszow', - 'Prato', - 'Waco', - 'Acarigua', - 'Myawadi', - 'Mwene-Ditu', - 'Karakopru', - 'Parachinar', - 'Koronadal', - 'La Serena', - 'Maharagama', - 'San Pedro de Macoris', - 'Liege', - 'Hagerstown', - 'Suzuka', - 'Baharampur', - 'Tchitato', - 'Malema', - "N'Zerekore", - 'Mbarara', - 'Morbi', - 'Cuautla', - 'Anseong', - 'Guanajuato', - 'Tebessa', - 'Kamirenjaku', - 'Holon', - 'Pingtung', - 'Peterborough', - 'Tanauan', - 'Nampa', - 'Suhaj', - 'Pandhurna', - 'Bene Beraq', - 'Sosnowiec', - 'Bukan', - 'Mus', - 'Kumagaya', - 'La Plata', - 'Bani Suwayf', - 'Lae', - 'Quelimane', - 'Hyesan', - 'Beni Mellal', - 'Jalapa', - 'Guanare', - 'Kaesong', - 'Nossa Senhora do Socorro', - 'Castanhal', - 'Croydon', - "Arba Minch'", - 'Rio Grande', - 'Gorontalo', - 'Florencia', - 'Fianarantsoa', - 'Tsing Yi Town', - 'Yamaguchi', - 'Iwo', - 'Rae Bareli', - 'Godoy Cruz', - 'Ciudad del Carmen', - 'Daman', - 'Valera', - 'Ouargla', - 'Cedar Rapids', - 'Manzanillo', - 'Malaybalay', - 'Isidro Casanova', - 'Chibia', - 'Leganes', - 'Hino', - 'Orai', - 'Shahr-e Kord', - 'Jhelum', - 'Mahbubnagar', - 'Pabna', - 'Cap-Haitien', - 'Nova Friburgo', - 'Saddiqabad', - 'Ngaoundere', - 'Hagen', - 'Chongju', - 'Paradise', - 'Poza Rica de Hidalgo', - 'Murtazabad', - 'Rajendranagar', - 'Las Heras', - 'Odawara', - 'Abu Ghurayb', - 'Anjomachi', - 'Araure', - 'Donostia', - 'Fuenlabrada', - 'Pinar del Rio', - 'Kenema', - 'Digos', - 'El Progreso', - 'Al Hasakah', - 'San Francisco de Macoris', - 'Taranto', - 'Prabumulih', - 'Kishiwada', - 'Iquique', - 'Dese', - 'Gharyan', - 'Kecskemet', - 'Numazu', - 'Ratanpur', - 'Bournemouth', - 'Bhusaval', - 'Tottori', - 'Alvorada', - 'Joetsu', - 'Chaedok', - 'Guatire', - 'Chilpancingo', - 'Kofu', - 'Ucu Seles', - 'Calbayog City', - 'Kirikkale', - 'Burlington', - 'Kielce', - 'Ocala', - 'Itabuna', - 'Kairouan', - 'Klerksdorp', - 'Pasuruan', - 'Bahraigh', - 'Ed Damazin', - 'Suva', - 'Basildon', - 'Getafe', - 'Cachoeiro de Itapemirim', - 'Potsdam', - "St. John's", - 'Erie', - 'Umreth', - 'Dunhuang', - 'Semnan', - 'Narsingdi', - 'Newport News', - 'Temirtau', - 'Banja Luka', - 'Ittikara', - 'Yei', - 'Mahesana', - 'Frederick', - 'Kuchlagh', - 'Murfreesboro', - 'Ferraz de Vasconcelos', - 'Bolu', - '`Unayzah', - 'Pak Kret', - 'Seixal', - 'Al Qamishli', - 'Padalarang', - 'Modena', - 'Breda', - 'Toyokawa', - 'Vinh Chau', - 'Siguiri', - 'Cuango', - 'Raiganj', - 'Fernando de la Mora', - 'Trang Bang', - 'Aqtau', - "Santa Barbara d'Oeste", - 'Batala', - 'Nis', - 'Oradea', - 'Tumpat', - 'Malumfashi', - 'Isiro', - 'Pinrang', - 'Fort Lauderdale', - 'Jaragua do Sul', - 'Sirsa', - 'Morsi', - 'Donghua', - 'Odense', - 'Noumea', - 'Dinapore', - 'Sorsogon', - 'Guarapuava', - 'Tambaram', - 'Bethelsdorp', - 'Saarbrucken', - 'Karaikkudi', - 'Shrirampur', - 'Braga', - 'Epe', - 'Kelowna', - 'Plzen', - 'Fardis', - 'Himatnagar', - 'Kindia', - 'Tachikawa', - 'Tempe', - 'Thanhlyin', - 'Turbo', - 'La Rioja', - 'Guna', - 'Hamm', - 'Nawada', - 'Cuauhtemoc', - 'Ploiesti', - 'Inisa', - 'Berazategui', - 'Ikot Ekpene', - 'Funtua', - 'Obuase', - 'Toulon', - 'Jaunpur', - 'Mbanza Kongo', - 'Edirne', - 'Longjing', - 'Geelong', - 'Lhokseumawe', - 'Mahad', - 'Madanapalle', - 'Danbury', - 'Palopo', - 'Petarukan', - 'Guri', - 'Singosari', - 'Quang Yen', + 'Nachod', + 'Patzun', + 'Southborough', + 'Hopetown', + 'Regina', + 'Estavayer-le-Lac', + 'Castellammare di Stabia', + 'Marabut', + 'Wegrow', + 'Moncton', + 'Pochuta', + 'Yumbe', + 'Raynes Park', + 'Kaiserslautern', + 'Ixtahuacan', + 'Montemor-o-Novo', + 'Palanisettipatti', + 'Baaqline', + 'Pen-y-Bont ar Ogwr', + 'Altinekin', + 'Villaba', + 'Cudahy', + 'Pazhanji', + 'Icononzo', + 'Yaozhuangcun', + 'Sanson', + 'Mol', + 'Lejiangxiang', + 'Prien am Chiemsee', + 'Heerde', + 'Nabatiye', + 'Dobre Miasto', + 'Franklin', + 'Ban Khi Lek', + 'Calumpang', + 'Levelland', + 'San Jose de Bocay', + 'Xichang', + 'Uravakonda', + 'Madinat Zayid', + 'Udayagiri', + "Jeppe's Reef", + "Nek'emte", + 'Fajardo', + 'Ratodero', + 'South Elgin', + 'Gogogogo', + 'Awjilah', + 'Kantharalak', + 'La Trinidad', + 'Nakanoto', + 'Paamiut', + 'Augustdorf', + 'Ferizli', + 'Belauncha', + 'Elurupadu', + 'Abuna', + 'Kuantan', + 'Casimiro de Abreu', + 'Battle Creek', + 'Ohara', + 'Knottingley', + 'Varzedo', + 'Ouled Slama Tahta', + 'Sorrento', + 'Lalmatie', + 'Hemavati', + 'Lewisboro', + 'Gary', + 'Hartbeespoort', + 'Piriyapatna', + 'Fulacunda', + 'Coatzacoalcos', + 'Puliyara', + 'Busca', + 'Jamkhed', + 'Targu Lapus', + "Ra's al Ma`arrah", + 'Nakhtarana', + 'Monte Plata', + 'Gravenhurst', + 'Jingcheng', + 'Starnberg', + 'Sa al Hajar', + 'Whitehouse', + 'Batatais', + 'Ciempozuelos', + 'Bingmei', + 'Divinopolis', + 'Como', + 'Sirgora', + 'Ban Bang Yai', + 'Tejucuoca', + 'Soavina Antanety', + 'Grapevine', + 'Waseca', + 'Sindelfingen', + 'Ulhasnagar', + 'Tulcan', + 'Ararica', + 'Camoapa', + 'Zoubiria', + 'Dour', + 'Terku Narippaiyur', + 'Llagostera', + 'Qo`rg`ontepa', + 'San Rafael La Independencia', + 'Sandino', + 'Dasoguz', + 'Bankra', + 'Mauguio', + 'Viagrande', + 'Bay Village', + 'Galivedu', + 'Oulad Fares', + 'Patapatnam', + 'Swinoujscie', + 'Dharmkot', + 'Recklinghausen', + 'General Viamonte', + 'Cyangugu', + 'Monteux', + 'Ozalp', + 'Quintero', + 'Baocheng', + 'Marhaura', + 'La Solana', + 'Simpang Renggam', + 'Bad Durkheim', + 'Sao Bento do Sapucai', + 'Mitzic', + 'Etajima', + 'Volos', + 'Hailey', + 'Weinsberg', + 'Dahi', + 'Braselton', + 'Miro Khan', + 'Qujingpu', + 'Ince-in-Makerfield', + 'Spanish Springs', + 'Montanhas', + 'Presevo', + 'San Carlos Centro', + 'Nandnawan', + 'Nowy Sacz', + 'View Royal', + 'West Rembo', + 'Paragould', + 'Tortoli', + 'Guapiacu', + 'Gijon', + 'Ilesa', 'Tongjiang', - 'Longjin', - 'Santander de Quilichao', - 'Wadlakonda', - 'Bhachau', - 'Shivpuri', - 'Caluquembe', - "Hosa'ina", - 'Tanjungbalai', - 'Budhanilkantha', - 'Uji', - 'Mongu', - 'Divo', - 'Calabar', - 'Reims', - 'Dosquebradas', - 'Roxas City', - 'Masan', - 'Purwakarta', - 'Satara', - 'El Khroub', - 'Tiaret', - 'Cuautitlan', - 'Spring Hill', - 'Njeru', - 'Torbali', - 'Ilheus', - 'Al `Arish', - 'Langsa', - 'Gastonia', - 'Phillaur', - 'Quevedo', - 'Tebingtinggi', - 'Kandi', - 'Nijmegen', - 'Unnao', - 'Dundo', - 'Meiktila', - 'Salinas', - 'Sitapur', - 'La Pintana', - 'Ambato', - 'Almada', - 'Riobamba', - 'Kalamboli', - 'Ciudad Valles', - 'Fredericksburg', - 'Maidstone', - 'San Luis Rio Colorado', - 'Letpandan', - 'Al Juwayyidah', - 'Cianjur', - 'Ontario', - 'Ar Rahmaniyah', - 'Waraseoni', - 'Castellon de la Plana', - 'Leon', - 'Mauli', - 'Harnaut', - 'Bejaia', - 'Elk Grove', - 'Biu', - 'Arafat', - 'Rantau Prapat', - 'Catumbela', - 'Shibirghan', - 'El Bosque', - 'Santa Maria Texmelucan', - 'Matosinhos', - 'Navadwip', - 'Salatiga', - 'Maragheh', - 'Kotdwara', - 'Amadora', - 'Durres', - 'Chicoloapan', - 'Khapalu', - 'Bodrum', - 'Yangmei', - 'Pilibhit', - 'Sirjan', - 'Narashino', - 'Cary', - 'Curug', - 'Rancho Cucamonga', - 'Kangqiao', - 'Timon', - 'Burgos', - 'Dagupan City', - 'Ludwigshafen', - 'Bac Giang', - 'Alleppey', - 'Ada', - 'Habaswein', - 'Gliwice', - 'Piedras Negras', - 'Linjiang', - 'Carupano', - 'Bida', - 'Sakura', - 'Townsville', - 'Oceanside', - 'Cuddalore', - 'Patra', - 'Basel', - 'Tlemcen', - 'Lubao', - 'Mexico', - 'Gondal', - 'Shahin Shahr', - 'Deo', - 'Albacete', - 'Fenglu', - 'Keningau', - 'Akhisar', - 'Podgorica', - 'Sherbrooke', - 'Kamakurayama', - 'Ha Long', - 'Oldenburg', - 'Silchar', - 'Chirala', - 'Gadag', - 'Santander', - 'Saint-Etienne', - 'Mang La', - 'Hitachi', - 'Jabalya', - 'Polomolok', - 'Ongata Rongai', - 'Sacaba', - 'General Mariano Alvarez', - 'Mulheim', - 'Lagos de Moreno', - 'Tiruvannamalai', - 'Kindu', - 'Kaolack', - 'Bidar', - 'Baranavichy', - 'Bade', - 'Talhar', - 'Izumo', - 'Rafah', - 'Bir el Djir', - 'Ait Melloul', - 'Oeiras', - 'Alcorcon', - 'Cazanga', - 'Garden Grove', - 'Kempton Park', - 'Al Kufah', - 'Araguaina', - 'Metro', - 'Nawsari', - 'Surigao', - 'Ercis', - 'Reggio di Calabria', - 'Makurdi', - 'Bao Loc', - 'Kohat', - "Petite Riviere de l'Artibonite", - 'Hemet', - 'Pembroke Pines', - 'Ibirite', - 'Hinthada', - 'Nqutu', - 'Escuintla', - 'Fusagasuga', - 'Malayer', - 'Olsztyn', - 'Tomakomai', - 'Aplahoue', - 'Valsad', - 'Thingangyun', - 'As Suwayq', - 'Metouia', - 'San Luis', - 'Barra Mansa', - 'Cape Coast', - 'Magwe', - 'Urayasu', - 'Puerto Montt', - 'Reggio Emilia', - 'Vallejo', - 'Al Marj', - 'Sahab', - 'Medinipur', - 'Sosan', - 'Talas', - 'Minbya', - 'Chuo-ku', - 'Santa Rita', - 'Batumi', - 'Bielsko-Biala', - 'Chetumal', - 'Nishio', - 'Medford', - 'Damoh', - 'Kalale', - 'Kroonstad', - 'Toliara', - 'Bayamon', - 'Calabozo', - 'Baliuag', - 'Haripur', - 'Mahabad', - 'Neyveli', - 'Bordj Bou Arreridj', - 'Mauldin', - 'Karaman', - 'Moratuwa', - 'Francisco Morato', - "Huich'on", - 'Ilford', - 'Kasama', - 'Gondomar', - 'Malanville', - 'Baramula', - 'Porto Seguro', - 'Jamalpur', - 'Riohacha', - 'Catape', - 'Hirosaki', - 'Villa Canales', - 'Malkapur', - 'Katha', - 'Oyama', - 'Basuo', - 'Jind', - 'Angra dos Reis', - 'Phan Rang-Thap Cham', - 'Osnabruck', - 'Itapecerica da Serra', - 'Mogok', - 'Fethiye', - 'Itu', - 'Al Qurayyat', - 'Jutiapa', - 'Palmdale', - 'Chandannagar', - 'Muskegon', - 'Cerkezkoy', - 'Linhares', - 'Tiantoujiao', - 'Sampit', - 'Uppsala', - 'Villanueva', - 'Adoni', - 'Alasandigutta', - 'Tuguegarao', - 'Siirt', - 'Kuytun', - 'Leesburg', - 'Offa', - 'Ipiales', - 'Le Havre', - 'Sudbury', - 'Ratnapura', - 'Niiza', - 'Takaoka', - 'Leverkusen', - 'Kushiro', - 'Iwata', - 'Obihiro', - 'Sao Caetano do Sul', - 'Sawangan', - 'Bechar', - "K'ebri Beyah", - 'Korfez', - 'Singida', - 'Warrington', - 'Udipi', - 'Saqqez', - 'Fyzabad', - 'Kokshetau', - 'Ebo', - 'Manavgat', - 'Fukang', - 'Idlib', - 'Sawai Madhopur', - 'Lajes', - 'Tenali', - 'Cienfuegos', - 'High Point', - 'Bocoio', - 'Abengourou', - 'Tuscaloosa', - 'Conjeeveram', - 'Hadano', - 'Chillan', - 'Abu Hulayfah', - 'Madhubani', - 'Arnhem', - 'Quibala', - 'Proddatur', - 'Baubau', - 'San Martin Texmelucan de Labastida', - 'Tunja', - 'Teresopolis', - 'San Marcos', - 'Pocos de Caldas', - 'Sultanpur Mazra', - 'Visalia', - 'Wapi', - 'Blida', - 'Sidon', - 'Wau', - 'Tokat', - 'Garissa', - 'Pocheon', - 'Skikda', - 'Muridke', - 'Muzaffargarh', - 'Kebili', - 'Turgutlu', - 'Jizzax', - 'Ungaran', - 'Kyaunggon', - 'Huddersfield', - 'Ube', - 'Bandar-e Mahshahr', - 'Nazilli', - 'Simao', - 'Anaco', - 'Marysville', - 'Golcuk', - 'Haarlem', - 'Boma', - 'Tuxtepec', - 'Sullana', - 'San Andres Tuxtla', - 'Heidelberg', - 'Darmstadt', - 'Parnaiba', - 'Mukono', - 'Hala', - 'Godhra', - 'Rafsanjan', - 'Sariaya', - 'Multai', - 'Perugia', - 'Nador', - 'Tema', - 'Zemun', - 'Ndalatando', - 'Salihli', - 'Daule', - 'Rajapalaiyam', - 'Zhanlicun', - 'Pangzawl', - 'Bontang', - 'Jinggang', - 'Ash Shihaniyah', - 'Papantla de Olarte', - 'San Miguel del Padron', - 'Tulancingo', - 'Tacheng', - 'Tan Phu', - 'Naic', - 'Liancheng', - 'General Roca', - 'Zaranj', - 'Al Ghardaqah', - 'Kidapawan', - 'Chittoor', - 'Braganca Paulista', - 'Solingen', - 'Merced', - 'Pindamonhangaba', - 'Hayward', - 'Split', - 'Ziarat', - 'Giron', - 'Miyakonojo', - 'Dong Hoi', - 'Tra Vinh', - 'Khanpur', - 'Ferkessedougou', - 'Southend', - 'Ciudad Acuna', - 'Jose Maria Ezeiza', - 'Khost', - 'Koudougou', - 'Saint-Marc', - 'Ninh Binh', - 'Bingol', - 'Dhamar', - 'Sivakasi', - 'Huaycan', - 'San Nicolas de los Arroyos', - 'Osorno', - 'Milagro', - 'Ceyhan', - 'Moga', - 'Ede', - 'Ekibastuz', - 'Barreiras', - 'Enschede', - 'Newport', - 'Chirchiq', - 'Dijon', - 'Jijiga', - 'Patos de Minas', - 'Budaun', - 'Ramat Gan', - 'Uttarpara', - 'Catamarca', - 'La Laguna', - 'Daltonganj', - 'Quipungo', - 'Jequie', - 'Benoni', - 'Macuspana', - 'Zhengding', - 'Aral', - 'Cadiz', - 'Matsuzaka', - 'Klaipeda', - 'Ogaki', - 'Corona', - 'Zabrze', - 'Bharuch', - 'Ilagan', - 'Abaetetuba', - 'Guimaraes', - 'Ibarra', - 'Paterson', - 'Gojra', - 'Banha', - 'Mahlaing', - 'Calama', - "'s-Hertogenbosch", - 'Grenoble', - 'Amersfoort', - 'Erzincan', - 'Regensburg', - 'George', - 'Herne', - 'Bima', - 'Mandi Bahauddin', - 'Chau Doc', - 'Angers', - 'Itapetininga', - 'Xiaping', - 'Caxias', - 'Villeurbanne', - 'Nablus', - 'Nan Zhuang', - 'Zaanstad', - 'Guaymas', - 'Enfield', - 'Kamina', - 'Molo', - 'Macon', - 'Saharsa', - 'Chaoshan', - 'Ketou', - 'Rio das Ostras', - 'Adzope', - 'Portmore', - 'Binghamton', - 'Qalyub', - 'Danao', - 'Marbella', - 'Ghorahi', - 'Lakewood', - 'Bac Lieu', - 'Capas', - 'Cam Pha', - 'Al Miqdadiyah', - 'Vidisha', - 'Pathankot', - 'Nowgong', - 'Ravenna', - 'Ar Ramtha', - 'Borazjan', - 'Tigaraksa', - 'Kisi', - 'Esmeraldas', - 'Horad Barysaw', - 'Souk Ahras', - 'Daiwanishi', - 'Chlef', - 'Pandi', - 'Camarajibe', - 'Odessa', - 'El Eulma', - 'Salzburg', - 'Thanesar', - 'Danzao', - 'Camacupa', - 'Kishangarh', - 'Uiwang', - 'Hanam', - 'Paderborn', - 'Zango', - 'Braila', - 'Barrie', - 'Sunnyvale', - 'Saint-Louis', - 'Edremit', - 'Rudarpur', - 'Kitenkela', - 'Tindwara', - 'Bandirma', - 'Nalgonda', - 'Jinghai', - 'Hitachi-Naka', - 'Lucapa', - 'Neuss', - 'Noda', - 'Santana de Parnaiba', - 'Ambikapur', - 'Madinat as Sadis min Uktubar', - 'Dibrugarh', - 'Singaraja', - 'Moanda', - 'Seogwipo', - 'Palo Negro', - 'New Bedford', - 'Veraval', - 'Mogi Guacu', - 'Hoeryong', - 'Abbotsford', - 'Kirsehir', - 'Tochigi', - 'Betul Bazar', - 'Andong', - 'Balurghat', - 'Bytom', - 'Jorhat', - 'Poblacion', - 'Ixtlahuaca', - 'Kariya', - 'Nevsehir', - 'Krishnanagar', - 'Dutse', - 'Ueda', - 'Livorno', - 'Tete', - 'Vinh Yen', - 'Barakpur', - 'Hollywood', - 'Sinpo', - 'Pouso Alegre', - 'Ciudad Choluteca', - 'Hoa Thanh', - 'Alagoinhas', - 'Mudon', - 'Amatitlan', - 'Gulu', - 'Gwangyang', - 'South Lyon', - 'Imabari', - 'Kawashiri', - 'Oxford', - 'Bordj el Kiffan', - 'Go Cong', - 'Erdemli', - 'Gonbad-e Kavus', - 'Al Manaqil', - 'Shantipur', - 'Dila', - 'Hindupur', - 'Araucaria', - 'Matanzas', - 'Beawar', - 'Long Khanh', - 'Bhalswa Jahangirpur', - 'As Suwayhirah as Sahil', - 'Tauranga', - 'Erode', - 'Escondido', - 'Lake Charles', - 'Dahuaishu', - 'Minglanilla', - 'Chichicastenango', - 'Duc Pho', - 'Copiapo', - 'Tafeng', - 'Mahmutlu', - 'Buyuk Cakirman', - 'Bugdayli', - 'Eminabad', - 'Kragujevac', - 'Pasadena', - 'Bellevue', - 'Logrono', - 'Delicias', - 'Talcahuano', - 'Piedecuesta', - 'Higashimurayama', - 'Ipokia', - 'Jaranwala', - 'Nangloi Jat', - 'Joliet', - 'Kukichuo', - 'Badajoz', - 'Champaign', - 'Fengyicun', - 'Shahrud', - 'Mzuzu', - 'Valle de Santiago', - 'Dong Xoai', - 'Valdivia', - 'Golbasi', - 'Naogaon', - 'Kashikishi', - 'El Minie', - 'Borj Hammoud', - 'Auchi', - 'Chauk Azam', - 'Yilan', - 'Sievierodonetsk', - 'Urganch', - 'Ocumare del Tuy', - 'Willemstad', - 'Bavaro', - 'Soro', - 'Penjamo', - 'Mariveles', - 'Pomona', - 'Saumlaki', - 'Villa de Alvarez', - 'Levis', - 'Fairfield', - 'Asaba', - 'Kerch', - 'Concordia', - 'Mesquite', - 'Lashio', - 'Elkhart', - 'Bohicon', - 'Harrow', - 'Rimini', - 'Port Louis', - 'Agri', - 'Naperville', - 'Maimanah', - 'Musashino', - 'Kastamonu', - 'St. George', - 'Sagay', - 'Roseville', - '`Ajlun', - 'Marvdasht', - 'Melitopol', - 'Potchefstroom', - 'Coquitlam', - "Nek'emte", - 'Xianshuigu', - 'Nuzvid', - 'Abbottabad', - 'Larisa', - 'Ramapo', - 'Coro', - 'Sayama', - 'Taza', - 'Jean-Rabel', - 'Al `Aqabah', - 'Dundee', - 'Sitarganj', - 'Dongguazhen', - 'Topeka', - 'Al Hawiyah', - 'Cagliari', - 'Nimes', - 'Luleburgaz', - 'Consolacion', - 'Maridi', - 'Quilpue', - 'Rafael Castillo', - 'Zhangaozen', - 'Nchelenge', - 'Szombathely', - 'Kutaisi', - 'Komaki', - 'Kiambu', - 'Siem Reap', - 'Hajipur', - 'Pesqueria', - 'Mati', - 'Aix-en-Provence', - 'Malakal', - 'Chingola', - 'Milas', - 'La Lisa', - 'Kafr ash Shaykh', - 'Tipitapa', - 'Clermont-Ferrand', - 'Hung Yen', - 'Tama', - 'Dongsheng', - 'Habra', - 'Yonago', - 'Kramatorsk', - 'Pageralam', - 'Kalemie', - 'Colima', - 'Dawei', - 'Maquela do Zombo', - 'Wamba', - 'Warner Robins', - 'Cairns', - 'Xinjing', - 'Cam Ranh', - 'Bir', - 'Florencio Varela', - 'Keren', - 'Dar`a', - 'West Bromwich', - 'Derince', - 'Gandajika', - 'Colina', - 'Dadu', - 'Pleiku', - 'Amreli', - 'Taungdwingyi', - 'Narnaul', - 'Jyvaskyla', - 'Chitaldrug', - 'Calapan', - 'Franco da Rocha', - 'Mostaganem', - 'Paco do Lumiar', - 'Etah', - 'Bani', - 'Surprise', - 'Gloucester', - 'Quchan', - 'Vila Junqueiro', - 'Torrance', - 'Eregli', - 'Foggia', - 'Iruma', - 'Abohar', - 'Thanatpin', - 'Miskolc', - 'Bhandaria', - 'Teixeira de Freitas', - 'Villa de Cura', - 'Facatativa', - 'Arad', - 'Fujita', - 'Le Mans', - 'Kisaran', - "Khairpur Mir's", - 'Bukoba', - 'Kaithal', - 'Arayat', - 'Poole', - 'Comayagua', - 'Yima', - 'Moshi', - 'Saguenay', - 'Urdaneta', - 'Boca del Rio', - 'Odivelas', - 'Xintang', - 'Barranca', - 'Balasore', - 'Guelph', - 'Zhaxi', - 'Mehtar Lam', - 'Al Mukalla', - 'Dar Naim', - 'Cinere', - 'Pinetown', - 'Asaka', - 'Ramu', - 'Mallapalli', - 'Kakamigahara', - 'Aalborg', - 'Koiridih', - 'Ciego de Avila', - 'Bandundu', - 'Disuq', - 'Calabayan', - 'Coimbra', - 'Ghazni', - 'Zhaoxiang', - 'Ruse', - 'Touggourt', - 'Shillong', - 'Houma', - 'Cizre', - 'Malasiqui', - 'Lleida', - 'Sannar', - 'Rewari', - 'Paghman', - 'Birkenhead', - 'Jinjiang', - 'Tinipuka', - 'Cartago', - 'Ashikaga', - 'Stara Zagora', - 'Telford', - 'Huelva', - 'Garanhuns', - 'Hazaribagh', - 'Moundou', - 'Trindade', - 'Nizip', - 'Nawabganj', - 'Toda', - 'Fullerton', - 'Lichinga', - 'Settat', - 'Bafra', - 'Bhimavaram', - 'Negombo', - 'Olathe', - 'Okinawa', - 'Namacunde', - 'Boca Chica', - 'Altay', - 'Bahawalnagar', - 'Misato', - 'Olmaliq', - 'Moriguchi', - 'Preston', - 'Thornton', - 'Mandsaur', - 'Jahrom', - 'Bondoukou', - 'Lausanne', - 'Bocaue', - 'Khuzdar', - 'Tepatitlan de Morelos', - 'Pemba', - 'Elbistan', - 'Bilbays', - 'Pitesti', - 'Gweru', - 'Tan Chau', - 'Numan', - 'Kamalshahr', - 'Rize', - 'Subang', - 'Villupuram', - 'Ingolstadt', - 'Las Maravillas', - 'Greeley', - 'Tabaco', - 'Fukayacho', - 'Beaumont', - 'Nsele', - 'Las Cruces', - 'Porac', - 'Mejicanos', - 'Krugersdorp', - 'Middlesbrough', - 'Shizhaobi', - 'Paranagua', - "Samarra'", - 'Iguala de la Independencia', - 'Ozamiz City', - 'Harchandpur', - 'Yaritagua', - 'Midland', - 'Kumbakonam', - 'Metairie', - 'Torbat-e Heydariyeh', - 'Xiangcheng', - 'Batu Pahat', - 'Nahiyat Ghammas', - 'Peristeri', - 'Darwin', - 'Reykjavik', - 'Atbara', - 'Kanasin', - 'Gia Rai', - 'Payatas', - 'Debre Birhan', - 'La Romana', - 'Aul', - 'Masaya', - 'Malambo', - 'Momostenango', - 'Pakpattan', - 'Botucatu', - 'Jicheon', - 'Tanay', - 'Blackpool', - 'Carolina', - 'Trois-Rivieres', - 'Balneario de Camboriu', - 'Balkanabat', - 'Dos Hermanas', - 'Apeldoorn', - 'Pantanal', - 'West Valley City', - 'Ishizaki', - 'Carsamba', - 'Kuwana', - 'Orange', - 'Warren', - 'Gemena', - 'Sancti Spiritus', - 'Whitby', - 'Cambridge', - 'Kolar', - 'Grand Junction', - 'Medea', - 'Teluknaga', - 'Tarragona', - 'Koga', - 'Dipolog', - 'Dabou', - 'Tsuchiura', - 'Tyler', - 'Jacmel', - 'Chicacole', - 'Montero', - 'Koutiala', - 'Shunan', - 'Candelaria', - 'Silivri', - 'Mthatha', - 'Gaziemir', - 'Brusque', - 'Tours', - 'Igdir', - 'Gunungsitoli', - 'Negage', - 'Teofilo Otoni', - 'La Trinidad', - 'Bankura', - 'Mandya', - 'Palhoca', - 'Norrkoping', - 'Jolo', - 'Kusatsu', - 'Cunduacan', - 'Dehri', - 'Hampton', - 'Sinfra', - 'Myebon', - 'Atibaia', - 'Quillacollo', - 'Medina Estates', - 'Stockport', - 'Kanata', - 'Rangkasbitung', - 'Porto Amboim', - 'Mino', - 'Durgauti', - 'Curico', - 'Vila Franca de Xira', - 'Igboho', - 'Gingoog', - 'Phu Ly', - 'Marivan', - 'Huehuetenango', - 'Barrechid', - 'San Justo', - 'Shizuishan', - 'Mainpuri', - 'Nasugbu', - 'Bloomington', - 'Quimbele', - 'Varginha', - 'Port-Gentil', - 'Carcar', - 'Qabr as Sitt', - "Chech'on", - 'Campo Largo', - 'San Jose del Cabo', - 'Cachoeirinha', - 'Termiz', - 'Zinacantepec', - 'Batang', - 'Bacau', - 'Norzagaray', - 'Yaizu', - 'Talaivasal', - 'Kisarazu', - 'Agcabadi', - 'Birganj', - 'Disa', - 'Tobruk', - 'Elizabeth', - 'Ebina', - 'Gitega', - 'Rionegro', - 'Stamford', - 'Nkongsamba', - 'Yuma', - 'Raigarh', - 'Yalova', - 'Maia', - 'Ituzaingo', - 'Tay Ninh', - 'Kigoma', - 'Kent', - 'Miramar', - 'Andimeshk', - 'Tizi Ouzou', - 'Agboville', - 'Siwan', - 'Maldonado', - 'Ipetumodu', - 'Shahreza', - 'Zabol', - 'Inazawa', - 'Caraguatatuba', - 'Pyay', - 'Silopi', - 'Djakotome', - 'El Oued', - 'Moron', - 'Bern', - "Coeur d'Alene", - 'Ashqelon', - 'Minoo', - 'Mabacun', - 'Laghouat', - 'Salto', - 'Sibiu', - 'Brighton', - 'Zafarwal', - 'Londuimbali', - 'Cameta', - 'Vitoria de Santo Antao', - 'Dumaguete City', - 'Navoiy', - 'Marianao', - 'Luuq', - 'Ba Don', - 'Gubeng', - 'Daraga', - 'Veszprem', - 'Famalicao', - "Debre Mark'os", - 'Tiraspol', - 'Coral Springs', - 'Ruda Slaska', - 'Rybnik', - 'Idfu', - 'Tokha', - 'Sterling Heights', - 'Kalol', - 'San Andres', - 'Marituba', - 'Amiens', - 'Yunxian Chengguanzhen', - 'Ferfer', - 'Renca', - 'Segou', - 'Jau', - 'Tando Allahyar', - 'Thandwe', - 'Hagonoy', - 'Hassan', - 'Batu Gajah', - 'Matagalpa', - 'Lalitpur', - 'Conchali', - 'Santa Cruz do Sul', - 'Long Binh', - 'Pitalito', - 'Bibemi', - 'Naga', - 'Porto-Novo', - 'Yuba City', - 'Khorramshahr', - 'Tarime', - 'Male', - 'Parla', - 'Milton', - "M'Sila", - 'Sripur', - 'Kipushi', - 'Gondia', - 'Zhangmu Touwei', - 'Schaarbeek', - 'Luxembourg', - 'Rehovot', - 'San Carlos', - 'Sao Mateus', - 'Dalupura', - 'Mogaung', - 'Odemis', - 'Centro Habana', - 'Zagnanado', - 'Isahaya', - 'Yakima', - 'Adonara', - 'Talavera', - 'Rustavi', - 'Carrollton', - 'Aware', - 'Naryai ka Puri', - 'Blitar', - 'Racine', - 'Karabuk', - 'Palwal', - 'Ome', - 'Chicomba', - 'Johnson City', - 'Annecy', - 'Papeete', - 'Cubatao', - 'Conselheiro Lafaiete', - 'Ji-Parana', - 'Al Khmissat', - 'Billings', - 'Jijel', - 'Furth', - 'Buea', - 'Apopa', - 'Itapipoca', - 'Spanish Town', - 'Lam Tin', - 'Palghat', - 'Atyrau', - 'Araras', - 'Maijdi', - 'Kusadasi', - 'Vlore', - 'Quibdo', - 'Marand', - 'Bassila', - 'Thaton', - 'Zama', - 'Chittandikavundanur', - 'Iowa City', - 'Nanqiaotou', - 'Shuangcheng', - 'Surat Thani', - 'Narita', - 'Lao Cai', - 'Trinidad', - 'Innsbruck', - 'Kozan', - 'Angono', - 'Silay', - 'Anand', - 'Jiroft', - 'City of Isabela', - 'Nantou', - 'Los Guayos', - 'Inezgane', - 'Arcahaie', - 'Botad', - 'Abiko', - 'Tabarre', - 'Udon Thani', - 'Baiyashi', - 'Mojokerto', - 'Dover', - 'Onomichi', - 'Lucheng', - 'Apucarana', - 'Jamundi', - 'Ergani', - 'Relizane', - 'Polokwane', - 'Aaley', - 'Cili', - 'Battambang', - 'Taldyqorghan', - 'Huejutla de Reyes', - 'Bongaigaon', - 'Bellingham', - 'Mukerian', - 'Zwolle', - 'Girardot', - 'Vespasiano', - 'Limoges', - 'Ponnagyun', - 'Sukrah', - 'Araruama', - 'Cayirova', - 'Hanumangarh', - 'Jetpur', - 'Arcot', - 'Kokubunji', - 'Amherst', - 'Kanchrapara', - 'Parepare', - 'Cienaga', - 'Sabara', - 'Chinguar', - 'Ferrara', - 'Antsiranana', - 'Tottenham', - 'Mansa', - 'Jamaame', - 'Petapa', - 'Mataro', - 'Cholula de Rivadabia', - 'Idanre', - 'Bamban', - 'Harar', - 'Sarhari', - 'Guadalajara de Buga', - 'Dortyol', - 'Ulm', - 'Braganca', - 'Mubi', - 'Guagua', - 'Lynchburg', - 'Songnim', - 'Bat Yam', - 'Osaki', - 'Vasteras', - 'Puno', - 'Hoshangabad', - 'Tariba', - 'Saida', - 'Heilbronn', - 'Chas', - 'Apatzingan de la Constitucion', - 'Tuaran', - 'Rudnyy', - 'Khanna', - 'Ahmadpur East', - 'Wazirabad', - 'Avrankou', - 'Vihari', - 'Guasdualito', - 'Mosquera', - 'Garut', - 'Votorantim', - 'Buon Ho', - 'Abaji', - 'Salmas', - 'Pforzheim', - 'Wurzburg', - 'Jazan', - 'Norman', - 'Santa Lucia Cotzumalguapa', - 'Guimba', - 'Simi Valley', - 'Latina', - 'Zhaozhou', - 'Dessalines', - 'San Ignacio', - 'Ciudad Sandino', - 'Allada', - 'Iwakuni', - 'Nagda', - 'Bam', - 'Opole', - 'Kayes', - 'Koforidua', - 'Seto', - 'Omiyacho', - 'Misserete', - 'Koganei', - 'Salerno', - 'Torrejon de Ardoz', - 'Nahiyat Khan Bani Sa`d', - 'Angren', - 'Pakokku', - 'Leiria', - 'Sertaozinho', - 'Hardoi', - 'Nemby', - 'Kamez', - 'Unye', - 'Fuyuan', - 'Duitama', - 'Gurabo al Medio', - 'Ajax', - 'Barcarena Nova', - 'Catabola', - 'Ksar El Kebir', - 'Orebro', - 'My Drarga', - 'Fort Smith', - 'Suhum', - 'Jandira', - 'Abilene', - 'Valinhos', - 'Altamira', - 'Guntakal', - 'Mary', - 'Iizuka', - 'Pithampur', - 'Karatepe', - 'Wolfsburg', - 'Rosetta', - 'Arecibo', - 'Giresun', - 'Kombolcha', - 'Payakumbuh', - 'Patan', - 'Bonao', - 'Barbacena', - 'Zoetermeer', - 'Basirhat', - 'Resende', - 'Nzega', - 'Villa Alemana', - 'Gashua', - 'Polatli', - 'Lewisville', - 'Larache', - 'Kristiansand', - 'Az Zulfi', - 'Jilib', - 'Cerro', - 'Halisahar', - 'Magelang', - 'Jagadhri', - 'Tychy', - 'Juticalpa', - 'Jizhou', - 'Leuwiliang', - 'Koidu', - 'Guarapari', - 'Pinsk', - 'Sunam', - 'Ouahigouya', - 'Rishra', - 'Grand-Bassam', - 'Jharsugra', - 'Leeuwarden', - 'Pearland', - 'Ben Tre', - 'Lehigh Acres', - 'Glazoue', - 'Panevezys', - 'Chinautla', - 'New Mirpur', - 'Serik', - 'Chia', - 'Kenosha', - 'Noksan', - 'Bajos de Haina', - 'Magalang', - 'Exeter', - 'Bimbo', - 'Leiden', - 'Kadirli', - 'Fugu', - 'Savannakhet', - 'Khrustalnyi', - 'Magangue', - 'Kirishima', - 'Cai Lay', - 'Maicao', - 'Pobe', - 'Giugliano in Campania', - 'Algeciras', - 'Paleng', - 'Akcaabat', - 'Djidja', - 'Duma', - 'Longtian', - 'Seaside', - 'Punta Arenas', - 'Itaituba', - 'Tres Lagoas', - 'Nandgaon', - 'Orizaba', - 'Bento Goncalves', - 'Honmachi', - 'Baraki', - 'Arvada', - 'Alwal', - 'Gapan', - 'Kaya', - 'Ed Damer', - "Munch'on", - 'Gexianzhuang', - 'Kilifi', - 'Zacatecas', - 'Romford', - 'Dimapur', - 'Patnos', - 'Pati', - 'Kahta', - 'Yuanlin', - 'Bayawan', - 'Machiques', - 'Hoima', - 'San Pedro Garza Garcia', - 'Bayan Lepas', - 'Ciudad Hidalgo', - 'Behbahan', - 'Itatiba', - 'Cagua', - 'Barretos', - 'Ise', - 'Puerto Cortes', - 'Maina', - 'Indramayu', - 'Tam Ky', - 'Uruma', - 'Sarangapuram', - 'Mufulira', - 'Waldorf', - 'Independence', - 'Ciudad Ojeda', - 'Bhadrakh', - 'Gyumri', - 'Dharmavaram', - 'Colchester', - 'Monza', - 'Sivaganga', - 'Chinandega', - 'Hoi An', - 'Logan', - 'Faridpur', - 'Springs', - 'Dorud', - 'Kashiwara', - 'Kuopio', - 'Ondjiva', - 'Alberton', - 'Temperley', - 'Harlingen', - 'Waterloo', - 'Dordrecht', - 'Kamalia', - 'Berkeley', - 'Tsuruoka', - 'Lianhe', - 'Ar Rass', - 'Hoa Binh', - 'Dogubayazit', - 'Port-de-Paix', - 'Upington', - 'Wuling', - 'Samandag', - 'Chon Thanh', - 'Puruliya', - 'Mit Ghamr', - 'Kirikhan', - 'Sassari', - 'Ghazipur', - "Ch'ungmu", - 'Apartado', - 'Tumen', - 'Thanh Pho Uong Bi', - 'Jima', - 'Genhe', - 'Navojoa', - 'Porlamar', - 'Anderlecht', - 'Metz', - 'Winterveld', - 'Renala Khurd', - 'Chilapa de Alvarez', - 'Coatepeque', - 'Bagaha', - 'Gudiyattam', - 'Mahuva', - 'Catchiungo', - 'Fier', - 'Clovis', - 'Kotamobagu', - 'Gurdaspur', - 'Ky Anh', - 'Kot Addu', - 'Round Rock', - 'Barcelos', - 'Pueblo', - 'Ramos Mejia', - 'High Wycombe', - 'Gemlik', - 'Temple', - 'Soke', - 'Khurda', - 'Delgado', - 'Kandy', - 'Ban Bang Pu Mai', - 'Gateshead', - 'Guelma', - 'Unwana', - 'Ar Rustaq', - 'Baraka', - 'Ghardaia', - 'Nokha', - 'Jandrapeta', - 'Hengken', - 'Dong Hoa', - 'Gorzow Wielkopolski', - 'Terrebonne', - 'Lalo', - 'Pelabuhanratu', - 'Yelahanka', - 'Meridian', - 'Malindi', - 'Almirante Tamandare', - 'Ebetsu', - 'Boulogne-Billancourt', - 'Moncton', - 'Yuksekova', - 'Palma Soriano', - 'An', - 'Jiangna', - 'Perpignan', - 'Pleven', - 'Fulgazi', - 'Bergamo', - 'Shuixi', - 'Sanxi', - 'Nazarabad', - 'Candaba', - 'Parow', - 'Tizayuca', - 'Mohammad Shahr', - 'Silifke', - 'Port Dickson', - 'Besancon', - 'Debre Tabor', - 'Arapongas', - 'Guaratingueta', - 'Slough', - 'Aw Dheegle', - 'Tuz Khurmatu', - 'Birigui', - 'Totonicapan', - 'Gottingen', - 'Huaraz', - 'Daitocho', - 'Darjeeling', - 'Piraquara', - 'Bet Shemesh', - 'Bismil', - 'Vihiga', - 'Pescara', - 'Sopur', - 'Nowshera', - 'Duluth', - 'Bandar-e Anzali', - 'Bruges', - 'Yongqing', - 'Calumpit', - 'Bwana Mkubwa', - 'Butwal', - 'Senador Canedo', - 'The Woodlands', - 'Chikmagalur', - 'Matamoros', - 'Kadoma', - 'Guelmim', - 'Yangliuqing', - 'Xuqiaocun', - 'Soasio', - 'Kampong Cham', - 'Dinalupihan', - 'Malita', - 'Nigde', - 'Gudivada', - 'Bama', - 'Lahti', - 'Bottrop', - 'Quyang', - 'Ilobu', - 'Ligao', - 'Boulder', - 'Richardson', - 'Trento', - 'Nouadhibou', - 'Blackburn', - 'Phagwara', - 'Bage', - 'Aizuwakamatsu', - 'Lodhran', - 'Tahoua', - 'Matsubara', - 'Araguari', - 'Gogounou', - 'Agadez', - 'Pudukkottai', - 'Saanich', - 'Nobeoka', - 'Charallave', - 'Uribia', - 'West Palm Beach', - 'Luanshya', - 'Banyuwangi', - 'Reutlingen', - 'Handa', - 'Kabwe', - 'La Asuncion', - 'Salman Bak', - 'Catacamas', - 'Tangjin', - 'Midsayap', - 'Port Arthur', - 'Heroica Guaymas', - 'Munuf', - 'East Los Angeles', - 'Uruguaiana', - 'Banfora', - 'Harshin', - 'Adilabad', - 'Redding', - 'Apalit', - 'Yulu', - 'Umuarama', - 'Alcobendas', - 'Cassongue', - 'Clearwater', - 'Faqus', - 'Dabrowa Gornicza', - 'Monroe', - 'Kapakli', - 'Baripada', - 'Soreang', - 'Konosu', - 'Samal', - 'Datu Odin Sinsuat', - 'Utica', - 'Manpo', - 'Tatui', - 'St. Cloud', - 'Mandeville', - 'Chimaltenango', - 'Orleans', - 'La Granja', - 'Erlangen', - 'Yavatmal', - 'Titagarh', - 'Ikoma', - 'Lira', - 'Barnala', - 'Cheltenham', - 'Forli', - 'Chittaurgarh', - 'West Jordan', - 'Xai-Xai', - 'Gabes', - 'Tecoman', - 'Boke', - 'Coronel', - 'Narasaraopet', - 'Siracusa', - 'Himamaylan', - 'Ocana', - 'Ballarat', - 'Adigrat', - 'Dharan', - 'Smithtown', - 'Fatsa', - 'Temixco', - 'Bongao', - 'Ain Beida', - 'Karatsu', - 'Nagahama', - 'Targu-Mures', - 'Sogamoso', - 'San Tung Chung Hang', - 'Beppu', - 'Adjaouere', - "Ra's al Khaymah", - 'Valle de La Pascua', - 'Urasoe', - 'Sao Goncalo do Amarante', - 'Sri Jayewardenepura Kotte', - 'Catanduva', - 'Varzea Paulista', - 'North Charleston', - 'San Ildefonso', - 'Linkoping', - 'Tarogong', - 'Nasushiobara', - 'Nusaybin', - 'Pedro Juan Caballero', - 'Ribeirao Pires', - 'Sandvika', - 'Bremerhaven', - 'Uzhhorod', - 'Saginaw', - 'Koencho', - 'Kovilpatti', - 'Ar Rumaythah', - 'Kasese', - 'Bijnor', - 'Chelmsford', - 'Los Banos', - 'Puerto Madryn', - 'Koblenz', - 'El Pueblito', - 'Kailua', - 'Sliven', - 'Elblag', - 'Igarassu', - 'Guanabacoa', - 'Aihua', - 'Mendoza', - 'Al Mudaybi', - 'Swabi', - 'Ciudad Guzman', - 'Tlapacoyan', - "Bu'aale", - 'Turbaco', - 'Niihama', - 'Brandon', - 'Amasya', - 'Ponce', - 'Rawajaya', - 'Rawasari', - 'Sano', - 'Dam Dam', - 'Las Delicias', - 'Carlsbad', - 'Lowell', - 'Qiaotou', - 'Hatsukaichi', - 'Bijeljina', - 'Maghnia', - 'Plock', - 'Shacheng', - "Sach'on", - 'Thimphu', - 'Ariana', - 'Iriga City', - 'Boras', - 'Simoes Filho', - 'Plaridel', - 'Catalao', - 'Jaramana', - 'Kaikkudi', - 'Codo', - 'Yoju', - 'Broken Arrow', - 'Ambovombe', - 'Sakete', - 'Elgin', - 'Alphen aan den Rijn', - 'Lugazi', - 'Machakos', - 'Rouen', - 'Bintulu', - 'Petrzalka', - 'Materi', - 'Kakegawa', - 'Kuningan', - 'Helsingborg', - 'Quilengues', - 'Tawau', - 'Poa', - 'Sakiet ed Daier', - 'Iranshahr', - 'Ifanhim', - 'Euriapolis', - 'Ndali', - 'Gresham', - 'Pul-e Khumri', - 'Fujimino', - 'Comitan', - 'League City', - 'Mungo', - 'Guiguinto', - 'Midyat', - 'Itabira', - "Sa-ch'on", - 'Bukittinggi', - 'Satkhira', - 'Manolo Fortich', - 'Sloviansk', - 'Akcakale', - 'Hikone', - 'Mangaldan', - 'Hofu', - 'Mostar', - 'Tokai', - 'Downey', - 'Sokode', - 'Libmanan', - 'Hosan', - 'San Carlos de Bariloche', - 'Paulo Afonso', - 'Tecpan Guatemala', - 'Kazo', - 'Jonkoping', - 'Bergisch Gladbach', - 'Tayabas', - 'Remscheid', - 'Carora', - 'Lomas de Zamora', - 'Balangir', - 'Shegaon', - 'Macul', - 'Oshu', - 'Nkayi', - 'Higashiomi', - 'Otaru', - 'Ciudad de la Costa', - 'Badin', - 'Kisii', - 'Santa Lucia', - 'Goth Tando Sumro', - 'Shkoder', - 'Kaposvar', - 'Mahasamund', - 'Trier', - 'Rajpura', - 'Hezuo', - 'La Libertad', - 'Pochuta', - 'Dassa-Zoume', - 'Akishima', - 'Bagalkot', - 'Osmanabad', - 'Esteli', - 'Paarl', - 'Kouande', - 'Kalianpur', - 'Shujalpur', - 'Sahibganj', - 'Passos', - 'Subic', - 'Murrieta', - 'Jaen', - 'Fujimi', - 'Leominster', - 'Longview', - 'Baybay', - 'Ichinoseki', - 'Pompano Beach', - 'Colatina', - 'Bou Saada', - 'Bend', - 'Alkmaar', - 'Recklinghausen', - 'Mawanella', - 'Daet', - 'Nova Lima', - 'Araxa', - 'Laoag', - 'Miami Gardens', - 'Chilon', - 'Chiquimula', - 'Sabara Bangou', - 'Costa Mesa', - 'Baleraja', - 'Montreuil', - 'Villa Mercedes', - 'Sioux City', - 'Ghotki', - 'Jawhar', - 'Santamesa', - 'Kasempa', - 'Champdani', - 'Sao Lourenco da Mata', - 'Harad', - 'Jena', - 'Gafsa', - 'Ariquemes', - 'Kasuga', - 'Nsukka', - 'Kintampo', - 'Nandurbar', - 'Purwa Utar', - 'Kaiyun', - 'Namur', - 'Khushab', - 'Everett', - 'Puerto Barrios', - 'Fasa', - 'Gilroy', - 'Kiffa', - 'Al Ahad al Masarihah', - 'As Salamiyah', - 'Sorriso', - 'Franceville', - 'San Antonio Enchisi', - 'Quibor', - 'Socopo', - 'Ahuachapan', - 'Manzini', - 'Masindi', - 'Muktsar', - 'Martinez de la Torre', - 'San Buenaventura', - 'Changbang', - 'Empangeni', - 'Ferozepore', - 'Baneh', - 'Itele', - 'Rochdale', - 'Jeonghae', - 'Shirayamamachi', - 'Temecula', - 'Tubarao', - 'Sugar Land', - 'Omuta', - 'Chico', - 'Msaken', - 'Tinaquillo', - 'Bridgetown', - 'Wythenshawe', - 'Mancheral', - 'Qal`at Sukkar', - 'Pisco', - 'Retalhuleu', - 'Bernal', - 'Sutton Coldfield', - 'Vicenza', - 'Doncaster', - 'Winterthur', - 'Rotherham', - 'Dera Ismail Khan', - 'Esteban Echeverria', - 'Quezon', - 'Aguachica', - 'Naujan', - 'Glan', - 'Bayugan', - 'Eau Claire', - 'Brovary', - 'Gualeguaychu', - 'Delft', - 'Walthamstow', - 'Drammen', - 'Medenine', - 'Nkpor', - 'Kamagaya', - 'Tacurong', - 'Malacatan', - 'Taoyang', - 'Beja', - 'Yongju', - 'Labo', - 'Sandacho', - 'Berkane', - 'Sam Son', - 'White Rock', - 'Marugame', - 'Tangjia', - 'Sehore', - 'Soma', - 'Handeni', - 'Balombo', - 'Taitung', - 'Bangaon', - 'Thunder Bay', - 'Pulilan', - 'Maxixe', - 'Kasserine', - 'Bagu Na Mohra', - 'Matruh', - 'Baia Mare', - 'Shihuajie', - 'Tondabayashicho', - 'Ba Ria', - 'El Monte', - 'Witbank', - 'Khopoli', - 'Ferizaj', - 'Xishancun', - 'Mascara', - 'Khenchela', - 'Taungoo', - 'Mong Cai', - 'Idaho Falls', - 'Melipilla', - 'Komatsu', - 'Yasuj', - 'Khardah', - 'Cawayan', - 'Reus', - 'Mopti', - 'Delta', - 'Dearborn', - 'Toowoomba', - 'Mungeli', - 'Alto Hospicio', - 'Habikino', - 'Maramag', - 'Yevpatoriia', - 'Caen', - 'Nantang', - 'West Covina', - 'Tadpatri', - 'Birnin Kebbi', - 'Acharnes', - 'Yilong', - 'Sarh', - 'Sparks', - 'Mudanya', - 'An Nuhud', - 'Zilina', - 'Itumbiara', - 'Rijeka', - 'Douliu', - 'South Fulton', - 'Baia Farta', - 'Mazhang', - 'Castelar', - 'Villa Krause', - 'Balsas', - 'Lingayen', - 'Centennial', - 'Labe', - 'Gharbara', - 'Chaman', - 'Sultanpur', - 'Joyabaj', - 'Umm Qasr', - 'Kogon Shahri', - 'Kawit', - 'Kotmale', - 'Mineshita', - 'Shikohabad', - 'Morales', - 'Liberec', - 'Santana', - 'Shinyanga', - 'Basingstoke', - 'Jalpaiguri', - 'Manokwari', - 'Shamli', - 'Argenteuil', - 'Sandy Springs', - 'Wa', - 'Cambe', - 'Bhilai Karanja', - 'Chongshan', - 'Ilebo', - 'La Gi', - 'Ejido', - 'Emmen', - 'Edison', - 'Bante', - 'Lujan', - 'Bagong Silangan', - 'Yopal', - 'Erdenet', - 'Inglewood', - 'Suriapet', - 'Kalmunai', - 'Tajimi', - 'Chabahar', - 'Tenggarong', - 'Hillsboro', - 'Crawley', - 'Acailandia', - 'Roquetas de Mar', - 'As Safirah', - 'Wardha', - 'La Banda', - 'Catbalogan', - 'Htison', - 'Ranibennur', - 'Burbank', - 'Terni', - 'Mulhouse', - 'Nakhon Si Thammarat', - 'Berdiansk', - 'Toufen', - 'Kulob', - 'Kemalpasa', - 'Ad Dakhla', - 'Tiaong', - 'Tarnow', - 'Carmona', - 'Dagenham', - 'El Limon', - 'Barnoi', - 'Bolzano', - 'Raba', - 'Mingacevir', - 'Sitamarhi', - 'Lokossa', - 'Nanaimo', - 'Son La', - 'Sao Pedro da Aldeia', - 'Contramaestre', - 'Binh Hoa', - 'Atebubu', - 'Koszalin', - 'Idku', - 'Lo Barnechea', - 'Davie', - 'Kishanganj', - 'Song Cau', - 'Temoaya', - 'Kiryu', - 'Jatai', - 'El Cajon', - 'Erechim', - 'Tikrit', - 'Hindaun', - 'Azare', - 'Semari', - 'Jurupa Valley', - 'Lerma', - 'Tarim', - 'Nova Serrana', - 'Japeri', - 'Paragominas', - 'Gangawati', - 'Binh Long', - 'Malungun', - 'Allen', - 'Sabac', - 'Charsadda', - 'Alchevsk', - 'Robat Karim', - 'Auburn', - 'Renton', - 'Nautanwa', - 'Mazyr', - 'Xiva', - 'Moers', - 'Ash Shaykh `Uthman', - 'Lagarto', - 'Kongolo', - 'Mityana', - 'Bulan', - 'Yozgat', - 'Texcoco', - 'Nikopol', - 'Alasehir', - 'Holland', - 'Sultan Kudarat', - 'Maranguape', - 'Ndjamba', - 'Makrana', - 'Al Faw', - 'Planaltina', - 'Sheopur', - 'Kandhkot', - 'Pergamino', - 'Tagbilaran City', - 'Los Minas', - 'Parral', - 'Lavras', - 'Coronel Fabriciano', - 'Brockton', - 'Wloclawek', - 'Brantford', - 'Tenancingo', - 'Presidente Franco', - 'Tuyen Quang', - 'Olanchito', - 'Salzgitter', - 'Masbate', - 'Godollo', - 'Ballia', - 'Walbrzych', - 'Barika', - 'Rio Rancho', - 'Girona', - 'Suruc', - 'Siauliai', - 'Nancy', - 'Ourense', - 'Aquin', - 'Techiman', - 'Chorzow', - 'Tam Diep', - 'Balanga', - 'Gillingham', - 'Kanoya', - 'Ikeda', - 'Muriae', - 'Tadepallegudem', - 'Natitingou', - 'Chatham', - 'Ourinhos', - 'Sindangan', - 'Chicoutimi', - 'Bansbaria', - 'Tula de Allende', - 'Lida', - 'Toride', - 'Salford', - 'Rialto', - 'Ilopango', - 'Masaka', - 'Spokane Valley', - 'Saijo', - 'Charlottesville', - 'Kilinochchi', - 'Bacabal', - 'Menifee', - 'Orsha', - 'Daly City', - 'Uitenhage', - 'Biak', - 'Wigan', - 'Roncaglia', - 'Itacoatiara', - 'Musoma', - 'Breves', - 'Buzau', - 'Mubende', - 'Francistown', - 'Lower Hutt', - 'Woodbridge', - 'Tanga', - 'Uba', - 'Hounslow', - 'Bumba', - 'Bundi', - 'Bergama', - 'Chikushino', - 'Patos', - 'Itanhaem', - 'Aracruz', - 'Inzai', - 'Iguatu', - 'Camboriu', - 'Miryang', - 'Tanjungpandan', - 'Santo Antonio de Jesus', - 'Bendigo', - 'Bouskoura', - 'Paniqui', - 'Amaravati', - 'Parang', - 'Negapatam', - 'Sangju', - 'Buxar', - 'Wembley', - 'Caieiras', - 'Telde', - 'Kurichchi', - 'Hinche', - 'Hoyacho', - 'Guihulngan', - 'Saint Helens', - 'Gursu', - 'Jirja', - 'Kheda', - 'Siegen', - 'Tezpur', - 'Wichita Falls', - 'Riverview', - 'Piacenza', - 'Messaad', - 'Sundarnagar', - 'Houzhuang', - 'Gutersloh', - 'Mayari', - 'Seoni', - 'Ngong', - 'Ban Mangkon', - 'Mustafakemalpasa', - 'Kashmar', - 'Bahrain', - 'Jounie', - 'Ituiutaba', - 'Mositai', - 'Matehuala', - 'Rishikesh', - 'Simanggang', - 'Yishi', - 'Isehara', - 'Shibuya', - 'Sabratah', - 'Lahan', - 'Aflou', - 'Al Fqih Ben Calah', - 'Fugangcun', - 'Al Jumayl', - 'Dhangadhi', - 'Tavsanli', - 'Norwalk', - 'Shushtar', - 'Tota', - 'Tando Muhammad Khan', - 'Hildesheim', - 'Kapurthala', - 'Boryeong', - 'Al Hajar al Aswad', - 'Olomouc', - 'Zonguldak', - "Lee's Summit", - 'Dhamtari', - 'Raneswar', - 'Chishtian', - 'Longmont', - '`Ibri', - 'Vacaville', - 'Onojo', - 'Brajarajnagar', - 'Eastbourne', - 'Sujangarh', - 'Highlands Ranch', - 'Ciudad Rio Bravo', - 'Bhadreswar', - 'Pavlohrad', - 'Clarington', - 'Hengnan', - 'Assis', - 'Klagenfurt', - 'Chilakalurupet', - 'San Luis de la Paz', - 'Hanau', - 'Hikkaduwa', - 'Sungai Penuh', - 'Kingsport', - 'Chaguanas', - 'Jingping', - 'Novara', - 'Kousseri', - 'Ain Oussera', - 'Deventer', - 'San Vicente de Baracaldo', - 'Kaiserslautern', - 'KwaDukuza', - 'San Tan Valley', - 'Nga Bay', - 'Hong Ngu', - 'Jeypore', - 'Zomba', - 'Daoukro', - 'Itaperuna', - 'Oran', - 'Mporokoso', - 'Quincy', - 'Edinburg', - 'Karanja', - 'Aboisso', - 'Salavan', - 'Xirdalan', - 'Saint-Jerome', - 'Red Deer', - 'Sakado', - 'Bim Son', - 'Kefar Sava', - 'Chanwari', - 'Xinhua', - 'Sungailiat', - 'Sittwe', - 'Concepcion del Uruguay', - 'Leer', - 'Cavite City', - 'Playas de Rosarito', - 'Lynn', - 'Ahar', - 'Yen Bai', - 'Weifen', - 'Sur', - 'Port Blair', - 'Nahiyat al Iskandariyah', - 'Kalyani', - 'Masjed Soleyman', - 'Calasiao', - 'Datia', - 'Kamianets-Podilskyi', - 'Itaugua', - 'Torbat-e Jam', - 'Diourbel', - 'Madhavaram', - 'Kawachinagano', - 'Libertad', - 'Shahrisabz', - 'Gangtok', - 'Vaciamadrid', - 'Bocono', - 'San Felipe del Progreso', - 'Chust', - 'Lamitan', - 'Talipao', - 'San Angelo', - 'Sabanalarga', - 'Pyinmana', - 'Zahle', - 'Bamyan', - 'Mbanza-Ngungu', - 'Banzhuangcun', - "Ra's Gharib", - 'Gwelej', - 'Babile', - 'Dzolokpuita', - 'Suramala', - 'Navalyal', - 'Barod', - 'Vasco Da Gama', - 'Khambhaliya', - 'Abbigeri', - 'Kundli', - 'Ad Dujayl', - 'Mumias', - 'Luckeesarai', - 'Songea', - 'Pouytenga', - 'Solola', - 'Mabai', - 'Debre Zeyit', - 'Dunedin', - 'Hesperia', - 'Nabire', - 'Sundsvall', - 'Kadaiyanallur', - 'Sayaxche', - 'Ciamis', - 'Putatan', - 'Xiongzhou', - 'Urgut Shahri', - 'Fengning', - 'Bowling Green', - 'Shahdadpur', - 'Federal Way', - 'Talara', - 'Menglang', - 'Kani', - 'Cottbus', - 'Tinsukia', - 'Santa Cruz del Quiche', - 'Hualien', - 'Carmel', - 'Bismarck', - 'Campo Mourao', - 'Alaminos', - 'Xiegang', - 'Tellicherry', - 'Jinotega', - 'Itarsi', - 'Izumisano', - 'Thika', - 'Bislig', - 'Abhar', - 'Viseu', - 'Malate', - 'Ginowan', - 'Wakefield', - 'Sakata', - 'Khamis Mushayt', - 'Pili', - 'Pickering', - 'Hasilpur', - 'Trincomalee', - 'Riberalta', - 'Fishers', - 'Kohima', - 'Sisophon', - 'Tourcoing', - 'Vereeniging', - 'Mianeh', - 'Paoy Paet', - 'Weldiya', - 'Nyeri', - 'Roubaix', - 'Burzaco', - 'Espejo', - 'Kontagora', - 'Senahu', - 'Khambhat', - 'Santiago de Compostela', - 'Ixmiquilpan', - 'Caldas Novas', - 'Schwerin', - 'Salihorsk', - 'Reyhanli', - 'Itoshima', - 'Zarate', - 'Oton', - 'Manacapuru', - 'Sopron', - 'Koytendag', - 'Abreu e Lima', - 'Lorca', - 'Chipata', - 'Lethbridge', - 'Vista', - 'Chikusei', - 'Ancona', - 'Saku', - 'Silvassa', - 'Santa Cruz do Capibaribe', - 'Babahoyo', - 'Lugo', - "M'lang", - 'Leme', - 'Las Rozas de Madrid', - 'Boca Raton', - 'Moortebeek', - 'Chitose', - 'Balti', - 'Smederevo', - 'Trelew', - 'Kamloops', - 'Montego Bay', - 'Catarman', - 'Valenca', - 'Saint-Jean-sur-Richelieu', - 'Marmaris', - 'Udine', - 'Janakpur', - 'Nanxicun', - 'St. Augustine', - 'Paulinia', - 'Kambar', - 'Al Jammaliyah', - 'Itauna', - 'Ipojuca', - 'Quilenda', - 'Gambela', - 'Kallithea', - 'Deoni Buzurg', - 'Rades', - 'Mariano Roque Alonso', - 'Hammamet', - 'Asagicinik', - 'Beaverton', - 'Goodyear', - 'San Cugat del Valles', - 'Tartu', - 'Tsuyama', - 'Isulan', - 'Kalluru', - 'Konan', - 'Lajeado', - 'Adjarra', - 'Dongducheon', - 'Attock Khurd', - 'Nanterre', - 'Fanyang', - 'Yacuiba', - 'Vi Thanh', - 'Pernik', - 'Andria', - 'Para de Minas', - 'Orem', - 'Modi`in Makkabbim Re`ut', - 'Munakata', - 'Maribor', - 'Harnai', - 'Didim', - 'Colon', - 'Gavle', - 'Tumbes', - 'Es Senia', - 'Bodinayakkanur', - 'Quvasoy', - 'Paletwa', - 'Caotun', - 'Tamazunchale', - 'Arauca', - 'Tela', - 'Paraiso', - 'Do Gonbadan', - 'Sumber', - 'Kazerun', - 'Francisco Beltrao', - 'Sangolqui', - 'Iida', - 'Votuporanga', - 'Tiddim', - 'Buin', - 'Bab Ezzouar', - 'Oldham', - 'Zhudong', - 'Sunrise', - 'Omura', - 'Half Way Tree', - 'Peje', - 'Wujiaqu', - 'Harihar', - 'Ceske Budejovice', - 'Tomohon', - 'Parintins', - 'Navapolatsk', - 'Osijek', - 'Greece', - 'Corumba', - 'Arezzo', - 'Caceres', - 'Vitry-sur-Seine', - 'Doudian', - 'Lysychansk', - 'Escalante', - 'Itabaiana', - 'Charikar', - 'Arden-Arcade', - 'Harran', - 'Lawrence', - 'Muzaffarabad', - 'Bachhraon', - 'Toms River', - 'Hammersmith', - 'Amalner', - 'Balayan', - 'Sardarshahr', - 'Kalisz', - 'Witten', - 'Longkeng', - 'Vanderbijlpark', - 'Vilhena', - 'Rio Gallegos', - 'Weiyuan', - 'Caseros', - 'Cesena', - 'Tataouine', - 'Dhulian', - 'Hadera', - 'Arifwala', - 'Sandy', - 'Sao Cristovao', - 'Rayleigh', - 'Paramagudi', - 'Zerakpur', - 'Slidell', - 'Tandwa', - 'Shire', - 'Kamisu', - 'Cubuk', - 'Burdur', - 'Aliaga', - 'Pesaro', - 'Erbaa', - 'Tiruchengodu', - 'Huong Thuy', - 'Mons', - 'Pedagadi', - 'Oued Zem', - 'Boli', - 'Nagina', - 'Bogo', - "Saint-Michel de l'Atalaye", - 'Chakdaha', - 'Shimada', - 'Closepet', - 'Jiantang', - 'Dovzhansk', - 'Birecik', - 'Emmiganur', - 'Yalamakuru', - 'Balamban', - 'Siguatepeque', - 'Labuan', - 'Naxcivan', - 'Rawanduz', - 'Yumbo', - 'Vaniyambadi', - 'Al Jizah', - 'Buckeye', - 'Rubio', - 'Tiruttani', - 'Mianwali', - 'Dongping', - 'Meizichong', - 'Nahiyat al Karmah', - 'Moca', - 'Rincon de Romos', - 'Ocotlan', - 'Sibolga', - 'Esslingen', - 'Cerete', - 'Hemel Hempstead', - 'Livonia', - 'San Ramon', - 'San Martin Jilotepeque', - 'Williamsburg', - 'Bouna', - 'Legnica', - 'Kangan', - 'Suffolk', - 'Los Patios', - 'Compton', - 'Lecce', - 'Bath', - 'Behshahr', - 'Lopez', - 'Lingwala', - 'La Crosse', - 'Bhadohi', - 'Kanuma', - 'Gjakove', - 'Edmond', - 'San Joaquin', - 'Gerona', - 'Carson', - 'Allinagaram', - 'Bayan Hot', - 'Niagara Falls', - 'Villa Luzuriaga', - 'Marmagao', - 'Pingyuanjie', - 'Greenburgh', - 'Shibata', - 'Ludwigsburg', - 'Giessen', - 'Ashiya', - 'Yishui', - 'Yi Xian', - 'Tracy', - 'Paracatu', - 'Herzliyya', - 'Monkayo', - 'Ponta Pora', - 'Hayes', - 'Rio Largo', - 'Azumino', - 'Prescott Valley', - 'Dhar', - 'Qormi', - 'San Jose del Rincon Centro', - 'Middletown', - 'Valongo', - 'Alvand', - 'Lingtang', - 'Dong Ha', - 'Menderes', - 'Chiantla', - 'Simeulu', - 'Zifta', - 'Cape Breton', - 'Al Fujayrah', - 'Sanjo', - 'Fall River', - 'Gera', - 'Mairipora', - 'Lawang', - 'San German', - 'Hradec Kralove', - 'Daanbantayan', - 'Monastir', - 'Wangjia', - 'Yashio', - 'Jinbi', - 'Aksehir', - 'Yotsukaido', - 'Duren', - 'Chilliwack', - 'Santa Cruz Xoxocotlan', - 'Lemery', - 'Indanan', - 'Ramnicu Valcea', - 'Fenggang', - 'Tual', - 'Plantation', - 'Galle', - 'Mayaguez', - 'Itajuba', - 'Kwekwe', - 'Darlington', - 'New Braunfels', - 'Sidi Slimane', - 'Creteil', - 'La Marsa', - 'Ubatuba', - 'Ciudad General Belgrano', - 'Rafaela', - 'Wukari', - 'Guaiba', - 'Barra do Pirai', - 'Palimbang', - 'Nisshin', - 'Hanamaki Onsen', - 'Tubingen', - 'Boundiali', - 'La Reina', - 'Roswell', - 'Wimbledon', - 'San Sebastian de los Reyes', - 'Tatvan', - 'Kadugli', - 'Akot', - 'Tamanrasset', - 'Helmond', - 'Inagi', - 'Mtwara', - 'Rongwo', - 'Sablayan', - 'Azua', - 'Naju', - 'Mogi Mirim', - 'Flensburg', - 'Iserlohn', - 'Sao Joao da Boa Vista', - 'Oss', - 'Conroe', - 'Barletta', - 'Bedford', - 'South Gate', - 'Errachidia', - 'Tatakan', - 'Sepatan', - 'Kitakami', - 'Serra Talhada', - 'Contai', - 'Obu', - 'Teziutlan', - 'Santa Monica', - 'Pardubice', - 'Coatepec', - 'La Spezia', - 'Sao Roque', - 'Kirkland', - 'Hoover', - 'Kot Kapura', - 'Usti nad Labem', - 'Netrakona', - 'Hove', - 'Cruzeiro do Sul', - 'Satsumasendai', - 'Shabqadar', - 'Pato Branco', - "O'Fallon", - 'Higashi-Matsuyama', - 'Tultepec', - 'Kakamega', - 'Raub', - 'Turayf', - 'Southport', - 'Mijas', - 'Ouidah', - 'Goalundo Ghat', - 'Sinende', - 'Linquan', - 'Phu Tho', - 'Maracay', - 'Caycuma', - 'Niono', - 'Grahamstown', - 'Myingyan', - 'Alafaya', - 'Brossard', - 'Satu Mare', - 'Piranshahr', - 'Samalut', - 'Karwar', - 'Mizan Teferi', - 'Arzew', - 'Salaman', - 'Mandvi', - 'San Francisco Solano', - 'Tucurui', - 'Kalamaria', - 'Jauharabad', - 'Kendu Bay', - 'Hilversum', - 'Rayachoti', - 'Avare', - 'Paloncha', - 'Manhuacu', - 'Cacapava', - 'Xiancun', - 'Palm Coast', - 'Alessandria', - 'Ambohimangakely', - 'Hastings', - 'Agua Prieta', - 'Lawton', - 'Chino', - 'Lachhmangarh Sikar', - 'Maple Ridge', - 'Miaoli', - 'Mount Pleasant', - 'Tonacatepeque', - 'Grudziadz', - 'Guercif', - 'Solwezi', - 'Cisauk', - 'Caimbambo', - 'Oudtshoorn', - 'Bauan', - 'Pantukan', - 'Pongotan', - 'Ramagiri Udayagiri', - 'Cambambe', - 'Gwadar', - 'Mengdingjie', - 'Manteca', - 'Funza', - 'Zhezqazghan', - 'Canakkale', - 'Katiola', - 'Biga', - 'Eslamabad-e Gharb', - 'Chililabombwe', - 'Vanadzor', - 'Fundacion', - 'Ponnani', - 'Sahagun', - 'Arsuz', - 'Jamtara', - 'Joplin', - 'Pinamalayan', - 'Avignon', - 'Orpington', - 'Valjevo', - 'Julu', - 'Pazardzhik', - 'Vezirkopru', - 'Mandurah', - 'Watford', - 'Poitiers', - 'Sao Joao del Rei', - 'Yoshiwara', - 'Puerto Padre', - 'Caucasia', - 'Germantown', - 'Penaflor', - 'Imizucho', - 'Nasatta', - 'Abomey', - 'Pollachi', - 'Gjilan', - 'Hendek', - 'Gujar Khan', - 'Jalalpur Jattan', - 'Wajir', - 'Victorias', - 'Marudi', - 'Kavali', - 'Aubervilliers', - 'Botosani', - 'Darnah', - 'Mong Tun', - 'Richard-Toll', - 'Afmadow', - 'Barwaaqo', - 'Ma`arrat an Nu`man', - 'Luau', - 'Necochea', - 'Al Badrashayn', - 'Leogane', - 'El Ejido', - 'Mihara', - 'Compostela', - 'Presidencia Roque Saenz Pena', - 'Bayt Lahya', - 'Patrocinio', - 'El Puerto de Santa Maria', - 'Itapeva', - 'San Leandro', - 'Olavarria', - 'Dobrich', - 'Stevenage', - 'San Jose Pinula', - 'Sankeshwar', - 'Koka', - 'Glyfada', - 'Serdar', - 'Saquarema', - 'Cantaura', - 'Los Cerrillos', - 'Conda', - 'Cheektowaga', - 'Tartus', - "Town 'n' Country", - 'Clifton', - 'Waukegan', - 'Kadiri', - 'Tonghae', - 'Zhunan', - 'Ipil', - 'Prijedor', - 'Oulad Teima', - 'Nikaia', - 'Mestre', - 'Caracase', - 'Surallah', - 'Ciudad de Atlixco', - 'Pistoia', - 'Akyazi', - 'Torrevieja', - 'Pamekasan', - 'Segbana', - 'Maladzyechna', - 'Lere', - 'Avondale', - 'Maumere', - 'Phusro', - 'Polangui', - 'Banga', - 'Humpata', - 'Kalibo', - 'Atascocita', - 'Kuhdasht', - 'Jalal-Abad', - 'Kairana', - 'Jaworzno', - 'Saundatti', - 'Shwebo', - 'Hinigaran', - 'Calabanga', - 'As Salt', - 'Passi', - 'Colombes', - 'Aalst', - 'Lucca', - 'Missoula', - 'Hemei', - 'Pisa', - 'Wangqing', - 'Viana do Castelo', - 'Danli', - 'Chiclana de la Frontera', - 'Fort Myers', - 'Montelibano', - 'Ben Guerir', - 'Toviklin', - 'Chosica', - 'Paingkyon', - 'Villa Maria', - 'Rasipuram', - 'Najibabad', - 'Podujeve', - 'Barra do Corda', - 'Bayramaly', - 'Kimje', - 'Bhakkar', - 'Berisso', - 'Bertoua', - 'Newton', - 'La Grita', - 'Solana', - "Ain M'Lila", - 'Nirmal', - 'Nirala', - 'Ootacamund', - 'Echague', - 'Aroroy', - 'Mobara', - 'Ben Arous', - 'Prosperidad', - 'Alabel', - 'Ban Laem Chabang', - 'Grimsby', - 'Villingen-Schwenningen', - 'Jangipur', - 'Jaffna', - 'Janzur', - 'Leshou', - 'Muncie', - 'Sangrur', - 'Damaturu', - 'Qiantangcun', - 'Hartlepool', - 'Al Wakrah', - 'Sassandra', - 'Newmarket', - 'Jilotepec', - 'Makilala', - 'Wislane', - 'Maiquetia', - 'Mettupalaiyam', - 'Wakiso', - 'Bromley', - 'Jumri Tilaiya', - 'Rapid City', - 'Guanambi', - 'Jaguey Grande', - 'Baggao', - 'San Juan de los Morros', - 'Aruppukkottai', - 'Faridkot', - 'Calauan', - 'Ceylanpinar', - 'Ama', - 'Slupsk', - 'Madgaon', - 'Baras', - 'Gitarama', - 'Ende', - 'Koidu-Bulma', - 'Palangotu Adwar', - 'Sakiet ez Zit', - 'Western Bicutan', - 'Chester', - 'Consolacion del Sur', - 'Cipolletti', - 'Kpalime', - 'Changting', - 'Maasin', - 'San Fabian', - 'Satrovka', - 'Ratingen', - 'Midrand', - 'Denan', - 'Santa Catarina Pinula', - 'Calaca', - 'Caratinga', - 'Jamui', - 'Middelburg', - 'Camiling', - 'Nahuala', - 'Limpio', - 'Shuangshuicun', - 'Torrente', - 'Chongoroi', - 'Chimbas', - 'Bhola', - "Bi'r al `Abd", - 'Lorena', - 'Dipalpur', - 'Zwickau', - 'Troy', - 'Fulham', - 'Hounde', - 'Livermore', - 'Citrus Heights', - 'Ad Diwem', - 'Norton', - 'Wulan', - 'Hawthorne', - 'Heyunkeng', - 'Mardin', - 'Kumarapalaiyam', - 'Heerlen', - 'Mechelen', - 'Cacoal', - 'Takasagocho-takasemachi', - 'Binmaley', - 'Lunen', - 'Tangxing', - 'Campana', - 'Paredes', - 'Fukuroi', - 'Widekum', - 'Winchester', - 'Taohuajiang', - 'Longonjo', - 'Dunkerque', - 'Les Cayes', - 'Hansi', - 'Salinas Victoria', - 'Kattagan', - 'Tiflet', - 'Springdale', - 'Cardenas', - 'Shahdol', - 'Yoro', - 'Hamakita', - 'Unai', - 'Clarkstown', - 'Nuneaton', - 'Anakapalle', - 'Gravata', - 'Nabua', - 'Tucupita', - 'Tuncheng', - 'Whittier', - 'Deerfield Beach', - 'Nimbahera', - 'Nakhon Sawan', - 'Yaofeng', - 'Nachchandupatti', - 'Hassi Bahbah', - 'Loznica', - 'Kalpitiya', - 'Karanganyar', - 'Navegantes', - 'Yabelo', - 'Santa Rosa Jauregui', - 'Dingcheng', - 'Guasave', - 'Gotenba', - 'Odienne', - 'Ciudad de Melilla', - 'Bangkalan', - 'Bantayan', - 'Decatur', - 'Batticaloa', - 'Seoni Malwa', - 'Ibshaway', - 'Settsu', - 'Silvan', - 'Sarni', - 'Aulnay-sous-Bois', - 'Repentigny', - 'Khowrasgan', - 'Kitanagoya', - 'Vineland', - 'Shaoshanzhan', - 'Potiskum', - 'Sharurah', - 'Kameoka', - 'Keffi', - 'Qaracuxur', - 'Iga', - 'Chiguayante', - 'Cabiao', - 'Konstanz', - 'Kouvola', - 'Volos', - 'Guinobatan', - 'Kharian', - 'Mission', - 'Basoda', - 'Longhua', - 'Taishan Houcun', - 'San Pedro Sacatepequez', - 'Ducheng', - 'Adwa', - 'Sekimachi', - 'Maratturai', - 'Fuengirola', - 'Redencao', - 'Karakol', - 'Lake Forest', - 'El Bayadh', - 'Mukacheve', - 'Fusui', - 'Xuddur', - 'Karad', - 'Pariaman', - 'Chinnachauku', - 'Batarasa', - 'Lugang', - 'Junin', - 'Shumen', - 'Colonie', - 'Warder', - 'Caldas', - 'Velez-Malaga', - 'Pori', - 'Mitrovice', - 'Jinhe', - 'Garulia', - 'Tagaytay', - 'Apaseo el Grande', - 'General Rodriguez', - 'Chiquinquira', - 'Krishnagiri', - 'Arona', - 'Upper Darby', - 'Dapitan', - 'Takayama', - 'Grand Bourg', - 'Newport Beach', - 'Harda Khas', - 'Gurupi', - 'Maga', - 'Araripina', - 'Monte Chingolo', - 'Jastrzebie-Zdroj', - 'Puerto Maldonado', - 'Mhow', - 'Derry', - 'Santa Ines', - 'Ealing', - 'Walvisbaai', - "Bahla'", - 'Taxila', - 'Hovsan', - 'Luvungi', - 'Korgas', - 'Atakpame', - 'Woolwich', - 'Longchuan', - 'Brooklyn Park', - 'Karacabey', - 'Baabda', - 'Larnaca', - 'Presov', - 'Bryan', - 'Sayhat', - 'Westland', - 'Ilion', - 'Ciudad Mante', - 'Konotop', - 'Pandacan', - 'Chirundu', - 'Tuxpam de Rodriguez Cano', - 'Ijui', - 'Napa', - 'Mohammadia', - 'Catanzaro', - 'Sumenep', - 'Tshilenge', - 'Worms', - 'Pinheiro', - 'Treviso', - 'Madaba', - 'Khemis Miliana', - 'Yokotemachi', - 'Dhoraji', - 'Rafha', - 'Honiara', - 'Ushiku', - 'Tire', - 'Virappanchathiram', - 'Baytown', - 'Komae', - 'Santana do Livramento', - 'New Kru Town', - 'Carpina', - 'Kaizuka', - 'Nabunturan', - 'Marl', - 'Suceava', - 'Bais', - 'Villa Altagracia', - 'Science City of Munoz', - 'Athurugiriya', - 'Higashiyamato', - 'Ayase', - 'Bilwi', - 'Cicero', - 'Chigorodo', - 'Quixada', - 'Concepcion Tutuapa', - 'Wako', - 'Al Hindiyah', - 'Luancheng', - 'Darayya', - 'Sambava', - 'Kitakoriyamacho', - 'Hetauda', - 'Ath Thawrah', - 'Laharpur', - 'Diphu', - 'Bolinao', - 'Aruja', - 'El Milia', - 'Channapatna', - 'San Baudilio de Llobregat', - 'Chita', - 'Anderson', - 'Kesan', - 'Ermelo', - 'Acayucan', - 'Lucas do Rio Verde', - 'Dolisie', - 'Bhawanipatna', - 'Pilkhua', - 'Samadiala', - 'Ho', - 'Haskovo', - 'Franklin', - 'Matao', - 'Barahona', - 'Tiruppattur', - 'Hamma Bouziane', - 'Versailles', - 'Moriyama', - 'Farmington Hills', - 'Nizwa', - 'Buena Park', - 'Foumban', - 'Talavera de la Reina', - 'Lafey', - 'Galway', - 'Aylesbury', - 'Atambua', - 'Nazareth', - 'Phuc Yen', - 'Resita', - 'La Piedad', - 'Gokulgarh', - 'Sao Bento do Sul', - 'Serrinha', - 'Maco', - 'Lqoliaa', - 'Pine Hills', - 'Ashford', - 'Sirsilla', - 'Como', - 'State College', - 'Boukoumbe', - 'Habiganj', - 'Lakshmipur', - 'Picos', - 'Siaton', - 'Redwood City', - 'Minden', - 'Kampong Trach', - 'Moju', - 'Ciudad de Ceuta', - 'Lelystad', - 'La Lima', - 'Wutiancun', - 'Mingxing', - 'Mazatenango', - 'Mabinay', - 'Busto Arsizio', - 'Nantingcun', - 'David', - 'Al Hayy', - 'Louga', - 'Ufeyn', - 'Wadala Sandhuan', - 'Warwick', - 'Bayeux', - 'Stockton-on-Tees', - 'Nakatsu', - 'Brindisi', - 'Cranston', - 'Shirvan', - 'Tanjay', - 'Chingleput', - 'Jacobina', - 'Mian Channun', - 'Manfalut', - 'Rivadavia', - 'Cruzeiro', - 'Chelghoum el Aid', - 'Bhalwal', - 'Largo', - 'Calatrava', - 'Pontevedra', - 'Wuyi', - 'Chulucanas', - 'El Estor', - 'Velbert', - 'Cukai', - 'Miami Beach', - 'Sabaneta', - 'Oleksandriia', - 'Owariasahi', - 'Shikokuchuo', - 'Alhambra', - 'Deurne', - 'Omihachiman', - 'Johns Creek', - 'Puerto Iguazu', - 'Nueva Concepcion', - 'Macaiba', - 'Uman', - 'Saint Albans', - 'Mountain View', - 'Quixeramobim', - 'Bekobod', - 'Tacana', - 'Harlow', - 'Burnley', - 'Salisbury', - 'Jepara', - 'Redditch', - 'Saunda', - 'Morgantown', - 'Kongjiazhuangcun', - 'Norderstedt', - 'Ashoknagar', - 'Silver Spring', - 'Ubay', - 'Bhaktapur', - 'Banco Filipino International Village', - 'Layton', - 'Bilecik', - 'Yildiz', - 'Gurgenpinari', - 'Uzungoz', - 'Lucerne', - 'Siasi', - 'Watampone', - 'Katoya', - 'An Khe', - 'Paranavai', - 'Muroran', - 'Timoteo', - 'Apizaco', - 'Hukou', - 'Sao Sebastiao', - 'Courbevoic', - 'Purmerend', - 'Dar el Beida', - 'Imam Qasim', - 'Kentau', - 'Remedios de Escalada', - 'Xicotepec de Juarez', - 'Fiumicino', - 'Afsin', - 'Shuibian', - 'Kadi', - 'Valdemoro', - 'Chapadinha', - 'Xiedian', - 'Matalam', - 'Kimitsu', - 'Grosseto', - 'Buhi', - 'Athi River', - 'Nowy Sacz', - 'San Jose de las Lajas', - 'Pacatuba', - 'Lambunao', - 'Bulacan', - 'Mannargudi', - 'Port of Spain', - 'Orhangazi', - 'Hengkou', - 'Ita', - 'Folsom', - 'Kapalong', - 'Salina Cruz', - 'Panzos', - 'Tecate', - 'Balrampur', - 'Baalbek', - 'Hengelo', - 'Kashiwazaki', - 'Tallaght', - 'Khamanon Kalan', - 'La Louviere', - 'Launceston', - 'Madera', - 'Dera Allahyar', - 'Gonder', - 'Campo Limpo', - 'Gaoliying Ercun', - 'New Rochelle', - 'Ahenkro', - 'Yonezawa', - 'Orihuela', - 'Shiji', - 'Gobernador Galvez', - 'Malapatan', - 'Balcova', - 'Barili', - 'Wujindian', - 'Meybod', - 'Yanggao', - 'Bargarh', - 'Curvelo', - 'San Cristobal Verapaz', - 'Comitancillo', - 'Seropedica', - 'Terre Haute', - 'Bulanik', - "Sama'il", - 'Dahegam', - 'Torre del Greco', - 'Randfontein', - 'Batley', - 'Somerville', - 'Adigala', - 'Calandala', - 'Panjgur', - 'Butterworth', - 'Antehiroka', - 'Oum el Bouaghi', - 'Cabadbaran', - 'Beziers', - 'Tagoloan', - 'Kamareddipet', - 'Zuwarah', - 'Bafut', - 'Takestan', - 'Arni', - 'Echizen', - 'Maravatio de Ocampo', - 'Livingston', - 'Aquiraz', - 'Kumbo', - 'Bolpur', - 'Peruvancha', - 'Sint-Niklaas', - 'Flagstaff', - 'Taroudannt', - 'Namsan', - 'Gumla', - 'Simdega', - 'San Andres Cholula', - 'Qunghirot', - 'Cachoeira do Sul', - 'Boynton Beach', - 'Gamagori', - 'Manmad', - 'Goiana', - 'Rubi', - 'Nabatiye', - 'Masallatah', - 'Andahuaylas', - 'Kathri', - 'Jamshoro', - 'Khewra', - 'Zarzis', - 'Puerto Ayacucho', - 'San Carlos del Zulia', - 'Koktokay', - 'Piro', - 'Tall `Afar', - 'Homestead', - 'Scunthorpe', - 'Polatsk', - 'Mit Salsil', - 'Bamberg', - 'Turhal', - 'Ben Gardane', - 'Sefrou', - 'Kirklareli', - 'Patzcuaro', - 'Drobeta-Turnu Severin', - 'Sokcho', - 'Paco', - 'Kottagudem', - 'Idah', - 'Marsala', - 'Anniston', - 'Piatra Neamt', - 'Ciudad Lerdo', - 'Tissamaharama', - 'Akiruno', - 'Texarkana', - 'Patikul', - 'Ezpeleta', - 'Bani Mazar', - 'Mahdia', - 'Vila do Conde', - 'Krasnyi Luch', - 'Cianorte', - 'Tustin', - 'Belo Jardim', - 'Neumunster', - 'Xai', - 'Viana', - 'Eseka', - 'Dosemealti', - 'Robles', - 'San Martin', - 'Torres Vedras', - 'Langarud', - 'Pharr', - 'Senhor do Bonfim', - 'Afgooye', - 'Dudley', - 'San Isidro', - 'Port Huron', - 'Iwamizawa', - 'Yenakiieve', - 'Mangatarem', - 'Ban Talat Rangsit', - 'Sorgun', - 'Cacador', - 'Turlock', - 'Owendo', - 'Schiedam', - 'Yalta', - 'Ban Nong Prue', - 'Drummondville', - 'Natori-shi', - 'Kawartha Lakes', - 'Lisala', - 'Evosmos', - 'Juventino Rosas', - 'Ciudad Lazaro Cardenas', - 'Dobni Para', - 'Hanno', - 'Rancho Cordova', - 'Gokak', - 'Ceara-Mirim', - 'The Villages', - 'Tikamgarh', - 'Ikom', - 'Milpitas', - 'Bumahen', - 'Ubon Ratchathani', - 'Baharestan', - 'Araria', - 'Cuamba', - 'Huaral', - 'Madinat as Sadat', - 'Perere', - 'Alfenas', - 'Sougueur', - 'Nakatsugawa', - 'New Westminster', - 'Tiko', - 'Sesto San Giovanni', - 'Perris', - 'Bistrita', - 'Manresa', - 'Daugavpils', - 'Upland', - 'Subulussalam', - 'Tambacounda', - 'Dome', - 'Nakhon Pathom', - 'Toboali', - 'Tierralta', - 'Maizuru', - 'Bury', - 'Alton', - 'Eastleigh', - 'Elbasan', - 'Pagbilao', - 'Villa Celina', - "Ra's al Khafji", - 'Pleasanton', - 'Aligudarz', - 'Zaandam', - 'Mooka', - 'Arlit', - 'Skarzysko-Kamienna', - 'Dabakala', - 'Curepipe', - 'Dongchuan', - 'Hengbei', - 'Kuvango', - 'Brixton', - 'La Rochelle', - 'Taher', - 'Gyoda', - 'Sahuayo de Morelos', - 'Aveiro', - 'Bauang', - 'Dinga', - 'Iperu', - 'Varese', - 'Kendall', - 'Arkonam', - 'Delmenhorst', - 'Jonesboro', - 'Bandar Emam', - 'Bellflower', - 'Tres Rios', - 'Kashiba', - 'Barreiro', - 'Battle Creek', - 'Denov', - 'Pototan', - 'Qorveh', - 'Queluz', - 'Limay', - 'Manbij', - 'Pingyi', - 'Southall', - 'Huolu', - 'San Pedro Pinula', - 'Chino Hills', - 'Pehonko', - 'Viersen', - 'Cheyenne', - 'Argao', - 'Rueil-Malmaison', - 'Al Khankah', - 'Tanashicho', - 'Chitembo', - 'Chitemo', - 'Ilioupoli', - 'Macabebe', - 'Lebanon', - 'Carmichael', - 'South Jordan', - 'Kuacjok', - 'Gandia', - 'Faranah', - 'Mandiraja Kulon', - 'Baracoa', - 'Kizugawa', - 'Godawari', - 'Balqash', - 'Essaouira', - 'Tanuku', - 'Narra', - 'Koch Bihar', - 'Chengbin', - 'Pakxe', - 'Honjo', - 'Toyomamachi-teraike', - 'Fray Bartolome de Las Casas', - 'Rheine', - 'Hoofddorp', - 'Davis', - 'Marburg', - 'Villa Victoria', - 'Elizabethtown', - 'Linkou', - 'Birkhadem', - 'Kuniyamuttur', - 'Kortrijk', - 'Kambam', - 'Bir el Ater', - 'Champigny-sur-Marne', - 'Brikama', - 'Ukunda', - 'Huebampo', - 'Hasselt', - 'Bebedouro', - 'Nitra', - 'Phuket', - 'Lipjan', - 'Bodhan', - 'Schaumburg', - 'Alameda', - 'Zhongcheng', - 'Santa Catalina', - 'Grand-Lahou', - 'Stellenbosch', - 'Hermosa', - 'Fnidq', - 'Mengla', - 'Katano', - 'Hammond', - 'Tsubame', - 'Tirkakara', - 'Quatre Bornes', - 'Jelenia Gora', - 'Puli', - 'Caxito', - 'Pasco', - 'Latacunga', - 'Bracknell', - 'Ban Tha Khlong', - 'Cozumel', - 'Paisley', - 'Pattoki', - 'Harunabad', - 'Roosendaal', - 'As Suwayrah', - 'Bustos', - 'Evanston', - 'Kabacan', - 'Fukuchiyama', - 'Shush', - 'Lehi', - 'Chalandri', - 'Keratsini', - 'Umingan', - 'Pau', - 'Tecamachalco', - 'Guildford', - 'Zhlobin', - 'Talakag', - 'Nikko', - 'Nabari', - 'Balagtas', - 'Toyooka', - 'Balkh', - 'Estepona', - 'North Port', - 'Bongabong', - 'Nagua', - 'Berberati', - 'Santo Angelo', - 'Ebolowa', - 'Mao', - 'Luneburg', - 'Baj Baj', - 'Veliko Tarnovo', - 'Arlington Heights', - 'Surt', - 'Shostka', - 'El Viejo', - 'Usta Muhammad', - 'Camarillo', - 'Pyapon', - 'Wyoming', - 'Dorsten', - 'Prince George', - 'Mafra', - "E'erguna", - 'Nipani', - 'Vinhedo', - 'Tacambaro de Codallos', - 'Ait Ali', - 'Flower Mound', - 'Aira', - 'Caledon', - 'Bethlehem', - 'Cotui', - 'Alcala de Guadaira', - 'Tiangua', - 'Daxincun', - 'Dschang', - 'Idil', - 'Virac', - 'Hattiesburg', - 'Loveland', - 'Abeche', - 'Fazilka', - 'Khemis el Khechna', - 'Funing', - 'Armant', - 'Al Musayyib', - 'Shinkai', - 'Ibiuna', - 'Paysandu', - 'Pittsburg', - 'Kafr az Zayyat', - 'Crateus', - 'Ninh Hoa', - 'Siedlce', - 'Sasolburg', - 'Melton', - 'Cedar Park', - 'Palencia', - 'Pozzuoli', - 'Shajapur', - 'So-Awa', - 'Troisdorf', - 'Tuban', - 'Palmerston North', - 'Padre Hurtado', - 'Palo', - 'Keshod', - 'Infanta', - 'East Ham', - 'Daisen', - 'Nahavand', - 'Bender', - 'Wenatchee', - 'Weston-super-Mare', - 'Montepuez', - 'Esteio', - 'Southfield', - 'Kahror Pakka', - 'Lins', - 'Wilhelmshaven', - 'Fancheng', - 'Molina de Segura', - 'San Ramon de la Nueva Oran', - 'Chintamani', - 'Ryugasaki', - 'Manaoag', - 'Rochester Hills', - 'Banska Bystrica', - 'Merouana', - 'Yanam', - 'Tailai', - 'Toba Tek Singh', - 'Villa Elisa', - 'Valdosta', - 'Houmt Souk', - 'Rulin', - 'Chateauguay', - 'Gladbeck', - 'Catacaos', - 'Kengtung', - 'Ovalle', - 'Solok', - 'Sankt Gallen', - 'Espinal', - 'Benalmadena', - 'Surendranagar', - 'Stakhanov', - 'Sentani', - 'Malappuram', - 'Kargilik', - 'Merignac', - 'Cadereyta Jimenez', - 'Laiyuan', - 'Xaignabouli', - 'Lod', - 'Sidi Qacem', - 'Maghaghah', - 'Arta', - 'Sapiranga', - 'Owensboro', - 'Umea', - 'Arjona', - 'Apple Valley', - 'Jocotan', - 'Ain Temouchent', - 'Woodbury', - 'Garhi', - 'Cataguases', - 'Aviles', - 'Joensuu', - 'Jablah', - 'Ramla', - 'Tres Coracoes', - 'Landshut', - 'Saint-Maur-des-Fosses', - 'Tindivanam', - 'Carlisle', - 'Srivilliputtur', - 'Kiyose', - 'Xinglong', - 'Bhadarwah', - 'Ranaghat', - 'Cheria', - 'South Shields', - 'Kai', - 'Bonab', - 'Villa Carlos Paz', - 'Ciudad Real', - 'Ardakan', - 'Cua Lo', - 'Acacias', - 'Frontera', - 'Itapira', - 'Tissemsilt', - 'Pawtucket', - 'Lagoa Santa', - 'Dhrangadhra', - 'Kunitachi', - 'Dayr al Balah', - 'Pinamungahan', - 'Antibes', - 'East Kilbride', - 'Teyateyaneng', - 'Aracati', - 'Detmold', - 'Newcastle under Lyme', - 'Mawatagama', - 'Burton upon Trent', - 'Libon', - 'Belleville', - 'Telemaco Borba', - 'St. Joseph', - 'Gangammapeta', - 'Puqiancun', - 'Iju', - 'Wisil', - 'Al Muharraq', - 'Khejroli', - 'Tirumangalam', - 'Pardiguda', - 'Warabi', - 'Bugallon', - 'Tocumen', - 'Cherry Hill', - 'Panggezhuang', - 'Jaora', - 'Doral', - 'Gonen', - 'Fouchana', - 'Amakusa', - 'Tura', - 'Ambajogai', - 'Juchitan de Zaragoza', - 'Dabra', - 'Ubud', - 'Sasagawa', - 'Darhan', - 'Pozorrubio', - 'Toffo', - 'Tiznit', - 'Esperanza', - 'Tanguieta', - 'Tosu', - 'Moulay Abdallah', - 'Cotorro', - 'Drohobych', - 'Dalaguete', - 'Piracununga', - 'Ouro Preto', - 'Cinisello Balsamo', - 'Missouri City', - 'Dayong', - 'Bayreuth', - 'Itahari', - 'Peda-Houeyogbe', - 'Katori', - 'Kandori', - 'Shancheng', - 'Bozuyuk', - 'San Antonio de Los Altos', - 'Assab', - 'Gbawe', - 'Skelleftea', - 'Balingasag', - 'Saratoga Springs', - 'Arnsberg', - 'Wandiwash', - 'Ouake', - 'Ramhormoz', - 'Pocatello', - 'Bongouanou', - 'San Juan Opico', - 'Miki', - 'Oshkosh', - 'Uspantan', - 'Silao', - 'Brick', - 'New Britain', - 'Cinar', - 'Zlin', - 'Izumiotsu', - 'Caninde', - 'Mankono', - 'Le Kram', - 'Aprilia', - 'Okegawa', - 'Meshgin Shahr', - "Al Qa'im", - 'Airdrie', - 'Blagoevgrad', - 'Castle Rock', - 'Chalchuapa', - 'Gudur', - 'Casoria', - 'Pedro Brand', - 'Gravesend', - 'Ra`ananna', - 'Brookes Point', - 'Tatebayashi', - 'Lauderhill', - 'Kyotanabe', - 'Kahan', - 'Tatsunocho-tominaga', - 'Majalengka', - 'Broomfield', - 'Sarnia', - 'Dale City', - 'Vlaardingen', - 'Tamworth', - 'Samundri', - 'Dumangas', - 'Alicia', - 'Di An', - 'Yurihonjo', - 'Ain Oulmene', - 'Cunhinga', - 'Ajaccio', - 'Haveri', - 'Castrop-Rauxel', - 'Turkoglu', - 'Beysehir', - 'Bolingbrook', - 'Redmond', - 'Caguas', - 'El Kef', - 'Gouda', - 'Mansfield', - 'Tefe', - 'Tarn Taran', - 'Nandi Hills', - 'Hoorn', - 'Mangalagiri', - 'Joao Monlevade', - 'Brandenburg', - 'Linares', - 'Ellicott City', - 'Vriddhachalam', - 'Harrogate', - 'Copacabana', - 'Cao Bang', - 'Targu Jiu', - 'Sheboygan', - 'Xindian', - 'Kallakkurichchi', - 'Irece', - 'El Hamma', - 'Kumluca', - 'Paterna', - 'Bandar-e Genaveh', - 'Tupi', - 'Lala', - 'Kasipalaiyam', - 'Glens Falls', - 'Asti', - 'Inuyama', - 'Pancevo', - 'Jose Abad Santos', - 'Bagan Si Api-api', - 'Daytona Beach', - 'Reconquista', - 'Quillota', - 'Cannes', - 'Crewe', - 'Lodi', - 'Redlands', - 'Tan-Tan', - 'Fada Ngourma', - 'Otawara', - 'Pacajus', - 'Shakargarh', - 'Harrisonburg', - 'Ragusa', - 'Ciudadela', - 'Bula', - 'Pattukkottai', - 'Almelo', - 'Gobindgarh', - 'Nabeul', - 'Edea', - 'Brakpan', - 'Nea Smyrni', - 'Usulutan', - 'Shibukawa', - 'Lujan de Cuyo', - 'Moa', - 'Berdychiv', - 'Dothan', - 'Baghlan', - 'Chaigoubu', - 'Santa Rosa de Cabal', - 'Santa Isabel do Para', - 'Turkmenbasy', - 'Naqadeh', - 'Catalca', - 'San Vicente del Caguan', - 'Jinja', - 'Russas', - 'La Dorada', - 'Mackay', - 'Padre Las Casas', - 'Kostiantynivka', - 'Khomeyn', - 'Joyo', - 'Tocoa', - 'Mount Vernon', - 'Jingzhou', - 'Caserta', - 'Paine', - 'Catanauan', - 'Spijkenisse', - 'Sodertalje', - 'Centreville', - 'Huong Tra', - 'Amparo', - 'Yafran', - 'Lappeenranta', - 'Carles', - 'Sanwal', - 'Rio do Sul', - 'Yukuhashi', - 'Sremska Mitrovica', - 'Gaspar', - 'Myslowice', - 'Majadahonda', - 'Zhuolu', - 'San Dionisio', - 'Weligama', - 'Nepalganj', - 'Siruguppa', - 'Tangalla', - 'Bacacay', - 'Hekinan', - 'Sipalay', - 'Aschaffenburg', - 'Dazaifu', - 'Samborondon', - 'Longkoucun', - 'Alegrete', - 'Keshan', - 'Candeias', - 'Altoona', - 'Sangareddi', - 'Benidorm', - 'Zogbodome', - 'Marousi', - 'Wood Buffalo', - 'Dambulla', - 'Goya', - 'Oroquieta', - 'Virudunagar', - 'Abancay', - 'Penafiel', - 'Palin', - 'Turbana', - 'Yoshikawa', - 'Santo Antonio do Descoberto', - 'El Banco', - 'Warora', - 'Casa Nova', - 'Tibati', - 'Saint-Nazaire', - 'Sault Ste. Marie', - 'Camalig', - 'Najran', - 'Belo Tsiribihina', - 'Myaydo', - 'Al Lith', - 'Bella Vista', - 'Bailongqiaocun', - 'Chaklasi', - 'Nilanga', - 'Long My', - 'Borongan', - 'Wenping', - 'Gumaca', - 'Stara Pazova', - 'Bocholt', - 'Ararangua', - 'Esbjerg', - 'Merzifon', - 'Goianira', - 'Chiryu', - 'Cacak', - 'Quilandi', - 'Carpi', - 'Ludenscheid', - "Mun'gyong", - 'Ishioka', - 'Jabuticabal', - 'Calauag', - 'Castro', - 'Cajamar', - 'Framingham', - 'Camden', - 'Sao Sebastiao do Paraiso', - 'Bouafle', - 'Patzun', - 'Kabarore', - 'Sambrial', - 'Pila', - 'Dondo', - 'Shrewsbury', - 'Manikganj', - 'Baldwin Park', - 'Florida', - 'Rocklin', - 'Porterville', - 'Agios Dimitrios', - 'Calarca', - 'Tarin Kot', - 'Bakixanov', - 'Kawm Umbu', - 'Mandla', - 'Tamarac', - 'Palmeira dos Indios', - 'Ostend', - 'Saymayl', - 'Indaial', - 'La Estrella', - 'Sonsonate', - 'Pililla', - 'Santo Tirso', - 'Gosport', - 'Bartin', - "Dias d'Avila", - 'Lomas del Mirador', - 'Nanfengcun', - 'Salama', - 'Biankouma', - 'Lisburn', - 'Rayadrug', - 'Mamoudzou', - 'Glen Burnie', - 'Halmstad', - 'Le Bardo', - 'Binalbagan', - 'Shahrixon', - 'Bilara', - 'Villa Tunari', - 'Huanchaco', - 'Campo Formoso', - 'Goa', - 'Drancy', - 'Rayagada', - 'Blacksburg', - 'Talibon', - 'Las Piedras', - 'Ganthier', - 'Jinsha', - 'Parappanangadi', - 'Konongo', - 'Wausau', - 'Sumter', - 'Gela', - 'Placetas', - 'Janesville', - 'Melong', - 'Fernandopolis', - 'Musashimurayama', - 'Brunswick', - 'Morong', - 'San Francisco del Rincon', - 'Gibara', - 'Ratangarh', - 'Tandur', - 'Bakhmut', - 'Terme', - 'Markapur', - 'Bunbury', - 'Sihanoukville', - 'Mauban', - 'Tejupilco', - 'Alabang', - 'Goianesia', - 'Warzat', - 'Montecristi', - 'Ayvalik', - 'Nadi', - 'Zografos', - 'An Nu`maniyah', - 'Izalco', - 'Malaut', - 'Lowestoft', - 'Waukesha', - 'Samraong', - 'Kopargo', - 'Phitsanulok', - 'Kodungallur', - 'Corozal', - 'Neyyattinkara', - 'Kumanovo', - 'Fairbanks', - 'Ejura', - 'Zinjibar', - 'Sesvete', - 'Erd', - 'Zadar', - 'Fatehabad', - 'Bapatla', - 'Kalamasseri', - 'Tumauini', - 'Izmail', - 'Ostrow Wielkopolski', - 'Lakeville', - 'St. Charles', - 'Sirvan', - 'Al Qurayya', - 'Gardez', - 'Cremona', - 'Pavia', - 'Rugby', - 'Badvel', - 'Loule', - 'Redondo Beach', - 'Yinying', - 'Chiang Rai', - 'Karasu', - 'Shujaabad', - 'Stafford', - 'Valparai', - 'Yambol', - 'Djemmal', - 'Chingford', - 'Cabudare', - 'Sankaranayinar Kovil', - 'Xangongo', - 'Uxbridge', - 'Zenica', - 'Bundaberg', - 'Suratgarh', - 'Tamana', - 'Kaukhali', - 'Sig', - 'Bayonne', - 'Coari', - 'Grand Forks', - 'Baiquan', - 'Mindelo', - "Togoch'ale", - 'Noblesville', - 'Torremolinos', - "Bur Fu'ad", - 'Capanema', - 'Noisy-le-Grand', - 'Yawata-shimizui', - 'Orani', - 'Dandeli', - 'Santa Maria La Pila', - 'Minxiong', - 'Huwei', - 'Bopa', - 'Brumado', - 'Havirov', - 'Hujra Shah Muqim', - 'Sa`dah', - 'Ban Houayxay', - 'Nandura Buzurg', - 'Dimbokro', - 'Rizal', - 'Tinambac', - 'Pazarcik', - 'Guaynabo', - 'Celle', - 'Sagunto', - 'El Paso de Robles', - 'Kabirwala', - 'Thaba Nchu', - 'North Richland Hills', - 'Maple Grove', - 'Eniwa', - 'Guzhou', - 'Gaura', - 'Mineiros', - "Pan'an", - 'Tsurugashima', - 'Grajau', - 'Cahama', - 'Waingapu', - 'Kempten', - 'Passaic', - 'Blaine', - 'Lubin', - 'Luodong', - 'Thakhek', - 'Castries', - 'Nansang', - 'Al `Amirat', - 'Talamba', - 'Badhan', - 'Dien Bien Phu', - 'Phu Quoc', - 'Longtangwan', - 'Zhanggu', - '`Izbat al Burj', - 'Bijaynagar', - 'Satyamangalam', - 'Madhipura', - 'Kodoli', - 'Az Zubaydiyah', - 'Lake Elsinore', - 'Raha Tiga', - 'Raha', - 'Nikki', - 'Fulda', - 'Avaniyapuram', - 'Rogers', - 'Entebbe', - 'Imerintsiatosika', - 'Eskilstuna', - 'Aigaleo', - 'Rohri', - 'Sagaing', - 'Casas Adobes', - 'Qingquan', - 'Saint John', - 'Farroupilha', - 'Moquegua', - 'Yueshanwan', - 'Altamura', - 'Sherman', - 'Vushtrri', - 'Encarnacion', - 'Konin', - 'Novomoskovsk', - 'Kwamhlanga', - 'Ratnanagar', - 'Villa del Rosario', - 'Amstelveen', - 'Garzon', - 'San Miguel de Allende', - 'Walnut Creek', - 'Sanlucar de Barrameda', - 'San Juan de los Lagos', - 'Los Reyes de Salgado', - 'Basavakalyan', - 'Kiyosu', - 'Conway', - 'Ziguinchor', - 'Minami-Alps', - 'Uwajima', - 'Roxas', - 'Rioverde', - 'Ritto', - 'Eastvale', - 'Saint-Louis du Nord', - 'Inowroclaw', - 'Somasso', - "L'Aquila", - 'Tournai', - 'Bawku', - "Samch'ok", - 'Rhondda', - 'Union City', - 'Biguacu', - 'Michigan City', - 'Thohoyandou', - 'Poptun', - 'Soja', - 'Tripunittura', - 'Toyoake', - 'Al Qusiyah', - 'Alenquer', - 'Aqsu', - 'Chisec', - 'Kirdasah', - 'Poinciana', - 'Nowrangapur', - 'Welland', - 'Kars', - 'Bitola', - 'Planeta Rica', - 'Don Carlos', - 'Bafia', - 'Tulare', - 'Anan', - 'Limonade', - 'Limbe', - 'Shangchuankou', - 'Barra do Garcas', - 'Ongjang', - 'Cuimba', - 'Torbeck', - 'Fedosiia', - 'Gary', - 'Ad Darb', - 'Imola', - 'Necocli', - 'Mansehra', - 'Renk', - 'Mila', - 'Mocuba', - 'Dharmasagaram', - 'Granby', - 'Gaithersburg', - 'San Pascual', - 'Peruibe', - 'Kireka', - 'Kamsar', - 'Ko Samui', - 'Moriya', - 'Tanabe', - 'Mococa', - 'Piotrkow Trybunalski', - 'Varisshiyakuni', - 'Huishi', - 'Yitiaoshan', - 'Bagumbayan', - 'Liuhe', - 'Palghar', - 'La Chorrera', - 'Buenavista', - 'Lippstadt', - 'East Orange', - 'San Jose del Guaviare', - 'Queenstown', - 'Yunnanyi', - 'Aparri', - 'Assen', - 'Ixtaczoquitlan', - 'Aalen', - 'Wesley Chapel', - 'Ponta Delgada', - 'Purisima de Bustos', - 'Arcoverde', - 'Jacona de Plancarte', - 'Pakribarawan', - 'Al Ahmadi', - 'Suwalki', - "Say'un", - 'West Des Moines', - 'Yuriria', - 'Mineral de la Reforma', - 'Indang', - 'Sabae', - 'Alamada', - 'Isna', - 'Venancio Aires', - 'Pozarevac', - 'Kayankulam', - 'Velsen-Zuid', - 'Dalton', - 'Dubuque', - 'Jarabacoa', - 'Paradip Garh', - "Quartu Sant'Elena", - 'Issy-les-Moulineaux', - 'Valle Hermoso', - 'Bouira', - 'San Leonardo', - 'Ilkal', - 'Zapotlanejo', - 'Doboj', - 'Victor Larco Herrera', - 'Igbanke', - 'Nihtaur', - 'Schenectady', - 'Mamungan', - 'Cabo San Lucas', - 'Kladno', - 'Castelldefels', - 'Ankeny', - 'Sanza Pombo', - 'Tangub', - 'Anjangaon', - 'Maricopa', - 'Bardibas', - 'Cergy', - 'Puerto San Jose', - 'Ash Shihr', - 'Oriximina', - 'Adrar', - 'Eagan', - 'Matara', - 'Lodja', - 'St. Albert', - 'Otukpo', - 'Swedru', - 'Nghia Lo', - 'Tynemouth', - 'Sipocot', - 'Tuburan', - 'Villanueva y Geltru', - 'Hanford', - 'Miagao', - 'Xa Muteba', - 'Cuyapo', - 'Mbake', - 'Yorba Linda', - 'Weston', - 'Watsonville', - 'Hameenlinna', - 'Levallois-Perret', - 'Fort McMurray', - 'Lindong', - 'Renukut', - 'Nabha', - 'Ixtlahuacan de los Membrillos', - 'Putrajaya', - 'Al Buraymi', - 'San Pedro Ayampuc', - 'La Barca', - 'Yanghe', - 'Palo Alto', - 'Castillejos', - 'Antalaha', - 'Odate', - 'Siuri', - 'Boditi', - 'Januaria', - 'South Hill', - 'Chengjiao Chengguanzhen', - 'Conceicao do Coite', - 'Formiga', - 'Ksar el Boukhari', - 'Kamuli', - 'Rajsamand', - 'Longshan', - 'Bishnupur', - 'Cannock', - 'Dinslaken', - 'Pesqueira', - 'Colmar', - 'Tepotzotlan', - 'Bayombong', - "Sant'Eufemia Lamezia", - 'Apac', - 'Shashijie', - 'Pongnam', - 'Islahiye', - 'Shawnee', - 'Modasa', - 'Banepa', - 'Youssoufia', - 'Vaasa', - 'Santa Catarina Otzolotepec', - 'Heroica Caborca', - 'Molepolole', - 'Walsall', - 'Manaure', - 'Kovel', - 'Abnub', - 'Zigon', - 'Gauravaram', - 'Bergen op Zoom', - 'Aregua', - 'Ayolas', - 'Herford', - 'Sausar', - 'Yuquan', - 'Taman Senai', - 'Omidiyeh', - 'Huajing', - 'Dhenkanal', - 'Zihuatanejo', - 'Chicacao', - 'Fuefuki', - 'Urun-Islampur', - 'Rolandia', - 'Calais', - 'Stargard Szczecinski', - 'Gopalganj', - 'Itapema', - 'Ankazoabokely', - 'Capelle aan den IJssel', - 'Tome-Acu', - 'Great Falls', - 'Cuilco', - 'Tolanaro', - 'Lala Musa', - 'Russelsheim', - 'Haverhill', - 'Asela', - 'Sousa', - 'Seguela', - 'Shiojiri', - 'Kerpen', - 'Palatine', - 'Corvallis', - 'Bay', - 'Tabatinga', - 'Wanggezhuang', - 'Lushar', - 'Rockville', - 'Nea Ionia', - 'Zrenjanin', - 'Szolnok', - 'Old Bridge', - 'Dolores Hidalgo Cuna de la Independencia Nacional', - 'Liepaja', - "Sa'ada", - 'Skokie', - 'Pikit', - 'Dharapuram', - 'Guruvayur', - 'Kashima', - 'Cedeno', - 'Jagoniguda', - 'Mirpeta', - 'Nizhyn', - 'Lupon', - 'Phalodi', - 'Embu-Guacu', - 'Targoviste', - 'Nueva Guinea', - 'Acilia', - 'Veenendaal', - 'Kati', - 'Guines', - 'Beypore', - 'Casper', - 'El Seibo', - 'Grays', - 'Bongabon', - 'Kissidougou', - 'Cosmopolis', - 'Janauba', - 'Aksum', - 'Cumra', - 'Janiuay', - 'Calimera', - 'Godalming', - 'Pessac', - 'San Mateo Atenco', - 'Botolan', - 'Siddipet', - 'Bulancak', - 'Ilidza', - 'Ames', - 'Rosales', - 'Hihya', - 'Hit', - 'Kraljevo', - 'Bolgatanga', - 'Chiyoda-ku', - 'Viladecans', - 'Karlskrona', - 'Karimama', - 'La Carlota', - 'Focsani', - 'Delray Beach', - 'Nalut', - 'Katwijk', - 'Sammamish', - 'Walton upon Thames', - 'Ramos Arizpe', - 'Aflao', - 'Karakax', - 'Novi Pazar', - 'Cabedelo', - 'Koratla', - 'Saiki', - 'Damba', - 'Yachimata', - 'Zacapa', - 'Cuscatancingo', - 'Guangping', - 'Venissieux', - 'Urla', - 'Lynwood', - 'Hasanpur', - 'Opol', - 'Dundalk', - 'Bethesda', - 'Hashima', - 'Vaxjo', - 'Huquan', - 'Zanhuang', - 'Morristown', - 'Reghaia', - 'Kampung Tengah', - 'Bengkalis', - 'Virginia', - 'Juana Diaz', - 'Sahaswan', - 'Ocoyoacac', - 'Arambagh', - 'Kazanlak', - 'Piduguralla', - 'Massa', - 'Cazin', - 'Lencois Paulista', - 'Tsuruga', - 'Ilo', - 'Obera', - 'Genk', - 'Goz-Beida', - 'Chibok', - 'Ban Suan', - 'Oas', - 'Kankakee', - 'Dangbo', - 'Moita', - 'Agoo', - 'Fajardo', - 'Torreon', - 'El Carmen de Bolivar', - 'Madirovalo', - 'Taman Johor Jaya', - 'Puliyankudi', - 'Neuwied', - 'Lantapan', - 'Asenovgrad', - 'Viterbo', - 'Anamur', - 'Lahat', - 'Itapetinga', - 'Alpharetta', - 'Wilde', - 'Tatabanya', - 'Novi', - 'Martinez', - 'Kavala', - 'Karlstad', - 'Coron', - 'Zacatecoluca', - 'Finchley', - 'Thornton Heath', - 'Sangamner', - 'Chegutu', - 'Kenner', - 'Kiamba', - 'Fukutsu', - 'Wamena', - 'San Remigio', - 'Gohna', - 'Pulivendla', - 'Bay City', - 'Sakrand', - 'Santo Tome', - 'Smila', - 'Ina', - 'Collado-Villalba', - 'Surubim', - 'Menzel Temime', - 'Lutayan', - 'Tulcea', - 'Arima', - 'Weimar', - 'Angat', - 'Qiryat Gat', - 'Kirtipur', - 'Istaravshan', - 'Rio Negro', - 'South San Francisco', - 'Barreirinhas', - 'Qarqan', - 'Bom Jesus da Lapa', - 'Apex', - 'Parkersburg', - 'Xarardheere', - 'San Francisco El Alto', - 'El Prat de Llobregat', - 'San Antonio Suchitepequez', - 'Kanhangad', - 'Xiantangcun', - 'Al Minshah', - 'Los Amates', - 'Xieqiaocun', - 'Jaisalmer', - 'Sao Tome', - 'Singaparna', - 'Malden', - 'Kurabur', - 'Ain Defla', - 'Gniezno', - 'Piripiri', - 'Castro Valley', - 'Narok', - 'Rechytsa', - 'Sao Felix do Xingu', - 'Aran Bidgol', - 'Baqershahr', - 'Giddarbaha', - 'Taby', - 'Purulha', - 'Develi', - 'Villa Curuguaty', - 'Tamluk', - 'Hadjout', - 'Jamjamal', - 'Sinnar', - 'Vaijapur', - 'Jocotitlan', - 'Solano', - 'Pruszkow', - 'Bozeman', - 'Birnin Konni', - 'Tigbauan', - 'Ouricuri', - 'Torquay', - 'Jagraon', - 'Alipur Duar', - 'Pateros', - 'Dhuri', - 'Xibang', - 'Halabjah', - 'Kitamoto', - 'Guider', - 'Dormagen', - 'Villach', - 'Estancia', - 'Itaberaba', - 'Rath', - 'Villasis', - 'Zeist', - 'Mecheria', - 'Brentwood', - 'Farnborough', - 'Jiquilpan de Juarez', - 'Popondetta', - 'Saidu Sharif', - 'Bazar-e Yakawlang', - 'Patuakhali', - 'Sindelfingen', - 'Matamey', - 'Embu', - 'Caripito', - 'Sumbawa Besar', - 'Bucak', - 'Keitumkawn', - 'Autlan de Navarro', - 'Busia', - 'Ioannina', - 'La Ceja', - 'Kolonnawa', - 'Coyula', - 'Chiquimulilla', - 'Don Torcuato', - 'Nagcarlan', - 'Palaio Faliro', - 'Ladysmith', - 'Tomigusuku', - 'Clichy', - 'Igarape-Miri', - 'Bordj Menaiel', - 'Gwacheon', - 'Sabinas', - 'Acarau', - 'Ostrowiec Swietokrzyski', - 'Soloma', - 'Plauen', - "As Suwayda'", - 'Chipindo', - 'Waltham', - 'Faizabad', - 'Sangzishi', - 'Seydisehir', - 'Oued Rhiou', - 'Kensington', - 'Siemianowice Slaskie', - 'Meulaboh', - 'Marinilla', - 'Gerli', - 'Santo Domingo Tehuantepec', - 'Binga', - 'Fredericton', - 'Grevenbroich', - 'Lechang', - 'Faro', - 'Pirane', - 'Narapalli', - 'Fujioka', - 'Tulkarm', - 'Pflugerville', - 'Isabela', - 'Hilongos', - 'Arrecife', - 'Palitana', - 'Roeselare', - 'Valence', - 'Rivera', - 'Rahat', - 'Itamaraju', - 'North Little Rock', - 'Al Qurayn', - 'Dharmapuri', - 'Apaseo el Alto', - 'Sokhumi', - 'Idappadi', - 'Hiriyur', - 'Porto Nacional', - 'Paignton', - 'Potenza', - 'Rosenheim', - 'Chunian', - 'Malvar', - 'Santiago Tianguistenco', - 'Martil', - 'Waterlooville', - 'Sirsi', - 'Sibulan', - 'Povoa de Varzim', - 'Ash Shaykh Zuwayd', - 'Chervonohrad', - 'Saravia', - 'Seraing', - 'Glogow', - 'Atimonan', - 'Laguna Niguel', - 'Ambarawa', - 'Misantla', - 'Kodad', - 'San Clemente', - 'Alba Iulia', - 'Sangmelima', - 'Cienaga de Oro', - 'Bertioga', - 'Vacaria', - 'Qinggang', - 'Ghardimaou', - 'Seinajoki', - 'Tadepalle', - 'Grande Prairie', - 'Welkom', - 'Qal`ah-ye Now', - 'Yanagawa', - 'Niksar', - 'Pomezia', - 'Siuna', - 'Burnsville', - 'Teresa', - 'Randers', - 'Armur', - 'Simav', - 'Ivry-sur-Seine', - 'Horad Zhodzina', - 'Guiseley', - 'Neubrandenburg', - 'Sodegaura', - 'Tiquisate', - 'Tuao', - 'Bankra', - 'Nawalgarh', - 'Spring', - 'Tupa', - 'Port Charlotte', - 'Camocim', - 'Ferrol', - 'Bognor Regis', - 'Tohana', - 'Nieuwegein', - 'Most', - 'Penedo', - 'Inhambane', - 'Songkhla', - 'Sibalom', - 'Trnava', - 'Kangbao', - 'La Linea de la Concepcion', - 'Khagaul', - 'Tenri', - 'Dalja', - 'Ponferrada', - 'Magong', - 'Zarand', - 'Odendaalsrus', - 'Guamuchil', - 'Chakpi Karong', - 'Sundapalaiyam', - 'Fraijanes', - 'Bourges', - 'Jatani', - 'Chokwe', - 'Kurihara', - 'Zvornik', - 'Nawa', - 'Chincha Alta', - 'Jose Panganiban', - 'Chik Ballapur', - 'Guiglo', - 'Quimper', - 'Athni', - 'Eden Prairie', - 'Dedougou', - 'Fredrikstad', - 'Paphos', - 'Capao da Canoa', - 'Hornchurch', - 'Assi Bou Nif', - 'Maidenhead', - 'Greenwood', - 'Yangqingcun', - 'Benevides', - 'Lower Merion', - 'At Tall', - 'Midoun', - 'Millcreek', - 'Yattir', - 'Asahi', - 'Slatina', - 'Bhairahawa', - 'Badr Hunayn', - 'Khulays', - 'Korydallos', - 'Pokrovsk', - 'Rundu', - 'Tajumulco', - 'Akurana', - 'Mitcham', - 'Medicine Hat', - 'Pervomaisk', - 'Feltham', - 'Ito', - 'Dhuburi', - 'Fujiidera', - 'Mirassol', - 'Vittoria', - 'Prilep', - 'Stourbridge', - 'Coon Rapids', - 'Rowlett', - 'Mercedes', - 'Galgamuwa', - 'Ban Lam Sam Kaeo', - 'Abu Qurqas', - 'Kitale', - 'Cajazeiras', - 'Ouled Djellal', - 'Antony', - 'Banda del Rio Sali', - 'Anuradhapura', - 'Svyetlahorsk', - 'Tartagal', - 'Lugano', - 'Gadwal', - 'Tetovo', - 'Horsens', - 'Rockhampton', - 'Qurayyat', - 'Florence-Graham', - 'Teoloyucan', - 'Sidi Barani', - 'Granollers', - 'Nankana Sahib', - 'Visnagar', - 'Puerto Asis', - 'Nago', - 'Commerce City', - 'Vaslui', - 'Pamuru', - 'Caldiran', - 'Kasongo', - 'Kaga', - 'Batatais', - 'Bossier City', - 'Miyoshi', - 'Pabianice', - 'Halton Hills', - 'Beledweyne', - 'Dewsbury', - 'Taylor', - 'Friedrichshafen', - 'Sheikhpura', - 'Narlidere', - 'Marina di Carrara', - 'Irun', - 'Mahdasht', - 'La Habra', - 'Yurimaguas', - 'Campo Bom', - 'Balboa Heights', - 'Washim', - 'Calinog', - 'Mut', - 'Port Orange', - 'Palmela', - 'Moncada', - 'Balad', - 'Itupeva', - 'Gampaha', - 'Woking', - 'Troyes', - 'Nanpara', - 'Tan Phuoc Khanh', - 'Castellammare di Stabia', - 'La Seyne-sur-Mer', - 'Bansalan', - 'Champasak', - 'Lingshou', - 'Qoryooley', - 'Gusang', - 'Brookline', - 'Moore', - 'Koro', - 'Council Bluffs', - 'Tandag', - 'Boadilla del Monte', - 'Ico', - 'Carmen de Viboral', - 'Kapatagan', - 'Bensalem', - 'Anse a Galets', - 'Sittingbourne', - 'Leander', - 'Acton', - 'Dearborn Heights', - 'Herten', - 'Nagakute', - 'Kilis', - 'Mobarakeh', - 'Portel', - 'Ain Harrouda', - 'Rovaniemi', - 'Wenxicun', - 'Bergheim', - 'Berekum', - 'Ranipet', - 'Ambilobe', - 'Wundanyi', - 'Reston', - 'Kolding', - 'Schwabisch Gmund', - 'Kesamudram', - 'Villa Dominico', - 'Ras Tanura', - 'Puerto Penasco', - 'Bainet', - 'Riosucio', - 'Shangtangcun', - 'Boryspil', - 'Carazinho', - 'Kolda', - 'Nagari', - 'Cristalina', - 'Napier', - 'Sherkot', - 'Tighenif', - 'Camaqua', - 'Panchari Bazar', - 'Bannu', - 'Cyuve', - 'Boituva', - 'Raghogarh', - 'Chidambaram', - 'Twickenham', - 'Agia Paraskevi', - 'Analavory', - 'Figueira da Foz', - 'Narwana', - 'Vigevano', - 'North Bergen', - 'Trikala', - 'Cabaret', - 'Montebello', - 'Okha', - 'Zaraza', - 'Nova Odessa', - 'Meshkin Dasht', - 'Viedma', - 'Sihushan', - 'Bhabhua', - 'Koshizuka', - 'Manicaragua', - 'Rouiba', - 'Tendo', - 'Borj el Qoble', - 'Pontiac', - 'Arua', - 'Nanjangud', - 'Camotan', - 'Mongagua', - 'Encinitas', - 'Tagajo', - 'Yongbei', - 'Menzel Bourguiba', - 'Montauban', - 'Rayong', - 'Cambanugoy', - 'Satbayev', - 'Zengqiao', - 'Siddhapur', - 'Plato', - 'Mitoyo', - 'Derik', - 'Zory', - 'Sao Miguel dos Campos', - 'Leszno', - 'Runcorn', - 'Nakhyaungcharipara', - 'Queen Creek', - 'Nkawkaw', - 'Camabatela', - 'Hita', - 'Saraburi', - 'Morada Nova', - 'Naj` Hammadi', - 'Jhargram', - 'Afragola', - 'Santo Amaro', - 'Yangiyul', - 'Bezerros', - 'Sungo', - 'Penapolis', - 'Kapchagay', - 'Shiroi', - 'Offenburg', - 'Xiluodu', - 'Cortazar', - 'Praia', - 'Kolea', - 'San Juan Chamelco', - 'San Antonio del Tachira', - 'Karonga', - 'Wrecsam', - 'Sayyid Sadiq', - 'Valle de Bravo', - 'Hendersonville', - 'Palm Harbor', - 'Hato Mayor', - 'Extremoz', - 'Pico Rivera', - 'Cayenne', - 'May Pen', - 'Vyronas', - 'Asker', - 'Ostuncalco', - 'Ilobasco', - 'Itogon', - 'Port Coquitlam', - 'Korosten', - 'Baao', - 'La Democracia', - 'Uzunkopru', - 'Hasuda', - 'Widnes', - 'Taal', - 'Djibo', - 'Euclides da Cunha', - 'Ramanathapuram', - 'Kozluk', - 'Candon', - 'Sawahlunto', - 'Gia Nghia', - 'Marietta', - 'Hatogaya-honcho', - 'Tunasan', - 'Garbsen', - 'Wesel', - 'Vejle', - 'Tarnowskie Gory', - 'Trikonavattam', - 'Santa Catarina Ixtahuacan', - 'Sanford', - 'Kolomyia', - 'Yala', - 'Salgueiro', - 'Halvad', - 'Mateare', - 'Wels', - 'Barbalha', - 'Woodland', - 'Taua', - 'Margate', - 'Abuyog', - 'Caldwell', - 'Coyhaique', - 'Maues', - 'Huntersville', - 'Bocaranga', - 'Ar Rastan', - 'Caico', - 'Udamalpet', - 'Cabatuan', - 'Mirabel', - 'Ellesmere Port', - 'Santa Rosa de Copan', - 'Barberena', - 'Velika Gorica', - 'Hashimoto', - 'Idiofa', - 'Olbia', - 'Neu-Ulm', - 'Nordre Fale', - 'Ogoshi', - 'Bangor', - 'Iranduba', - 'Neka', - 'Tulunan', - 'Hurth', - 'Adjohon', - 'Wanparti', - 'Jupiter', - 'Tafo', - 'Aisai', - 'Tsushima', - 'Itoman', - 'Soroti', - 'Unna', - 'La Mesa', - 'Nambuangongo', - 'Los Polvorines', - 'Richland', - 'Jinoba-an', - 'Lomza', - 'Tamba', - 'Chamrajnagar', - 'Fort Portal', - 'Pantin', - 'Burhaniye', - 'Meihuacun', - 'Yamatotakada', - 'Bethal', - 'Orion', - 'Artemisa', - 'Sarandi', - 'Kresek', - 'El Wak', - 'Villamaria', - 'Shihe', - 'Puerto Limon', - 'Calulo', - 'Galapa', - 'Cubulco', - 'Mbabane', - 'Oyem', - 'Kyustendil', - 'Huatusco', - 'Castilla', - 'Laoang', - 'Oda', - 'Ibitinga', - 'Kukarmunda', - 'Kokawa', - 'Trang', - 'Viareggio', - 'Revere', - 'Yongyang', - 'Meriden', - 'Tigaon', - 'Matanao', - 'Atotonilco el Alto', - 'Taunton', - 'Dumraon', - 'Piscataway', - 'Itapecuru Mirim', - 'Elk', - 'Monterey Park', - 'Gardena', - 'Slutsk', - 'Vratsa', - 'Euless', - 'Cruz das Almas', - 'Altinozu', - 'Panruti', - 'Lalmanirhat', - 'Ambanja', - 'Ciudad Arce', - 'Velampalaiyam', - 'Laeken', - 'Gubat', - 'Wallasey', - 'Yisuhe', - 'Irvington', - 'Belladere', - 'Mizusawa', - 'Clay', - 'Tirukkoyilur', - 'San Mateo Ixtatan', - 'Parkent', - 'Paracale', - 'Yame', - 'Qoorlugud', - 'Razampeta', - 'Nedumangad', - 'Berrouaghia', - 'Zamosc', - 'Pasaje', - 'San Mariano', - 'Nioro', - 'Abyek', - 'Samut Sakhon', - 'Mbalmayo', - 'Des Plaines', - 'Jinxing', - 'Malay', - 'Souq Sebt Oulad Nemma', - 'Towada', - 'Pirojpur', - 'Manhica', - 'Horqueta', - 'Floriano', - 'Sao Borja', - 'Monte Alegre', - 'Saravan', - 'Tyre', - 'Faruka', - 'Buqda Caqable', - 'Oodweyne', - 'Guigue', - 'Hurlingham', - 'Kribi', - 'Suifenhe', - 'Consuelito', - 'Baba Hassen', - 'Meskiana', - 'Afula', - 'Nahariyya', - 'Gunupur', - 'Mehnajpur', - 'Bayji', - 'Banane', - 'Kakuma', - 'Kratie', - 'Barneveld', - 'Obando', - 'Civril', - 'Babolsar', - 'Union', - 'Thatri', - 'Rubizhne', - 'Registro', - 'Chandralapadu', - 'Legnano', - 'Loughborough', - 'San Vicente del Raspeig', - 'Ponnuru', - 'West Allis', - 'Carrara', - 'Ain Touta', - 'Arankhola', - 'Sigaboy', - 'Kathua', - 'Chambery', - 'Ilog', - 'North Miami', - 'Ozalp', - 'The Hammocks', - 'Escada', - 'Aranjuez', - 'Blainville', - 'North Lakhimpur', - 'Fano', - 'Andradina', - 'Langenfeld', - 'Skhirate', - 'Dongcun', - 'Euskirchen', - 'Ragay', - 'Khartsyzk', - 'Cupertino', - 'Uzice', - 'Lakhdaria', - 'Taylorsville', - 'Vinukonda', - 'Alexandroupoli', - 'Suhareke', - 'Huehuetoca', - 'Vicosa do Ceara', - 'Gohadi', - 'Kananya', - 'Greifswald', - 'Khagaria', - 'Hardenberg', - 'Matera', - 'Petaluma', - 'Bougouni', - 'Karamursel', - 'Huajiang', - 'Sanyo-Onoda', - 'Aguacatan', - 'Sennan', - 'Guerra', - 'Date', - 'Pachora', - 'Ouezzane', - 'Maimbung', - 'Lianzhuangcun', - 'Coroata', - 'Limoeiro do Norte', - 'Chelm', - 'Tiptur', - 'Kokomo', - 'Gopichettipalaiyam', - 'Givatayim', - 'Santee', - 'Alcoy', - 'Itanagar', - 'Esfarayen', - 'Xo`jayli Shahri', - 'Hakkari', - 'Wangzhuang', - 'Stonecrest', - 'White Plains', - 'Montenegro', - 'Yara', - 'Shimotsuke', - 'Druzhkivka', - 'Shirakawa', - 'Tomaszow Mazowiecki', - 'Los Andes', - 'Ouinhri', - 'Hua Hin', - 'Stralsund', - 'As Saff', - 'Galatsi', - 'Kesennuma', - 'Garin', - 'Ruhengeri', - 'Joso', - 'Niort', - 'Alfonso', - 'Zhoujiajing', - 'Gaibandha', - 'Uniao dos Palmares', - 'Hyuga', - 'Dhone', - 'Irosin', - 'Neuilly-sur-Seine', - 'Serres', - 'Irati', - 'Gannan', - 'Trollhattan', - 'Rajgarh', - 'Katerini', - 'San Simon', - 'Chalkida', - 'Mansalay', - 'Damghan', - 'Chichibu', - 'Umm al Qaywayn', - 'Antigua Guatemala', - 'Panna', - 'Palm Beach Gardens', - 'Barking', - 'Chivacoa', - 'Goppingen', - 'Constanza', - 'Saint-Louis du Sud', - 'Yevlax', - 'Mossel Bay', - 'El Palomar', - 'Tahara', - 'Upi', - 'Metapan', - 'Jiguani', - 'Petroupoli', - 'Huauchinango', - "Kattaqo'rg'on Shahri", - 'Anzio', - 'Motril', - 'Nirgua', - 'Chapel Hill', - 'Santa Maria Chiquimula', - 'Cruz Alta', - 'Cerro de Pasco', - 'Xikeng', - 'Lac-Brome', - 'Andoharanofotsy', - 'Gattaran', - 'Carvajal', - 'Parobe', - 'Sidi ech Chahmi', - 'Zahirabad', - 'Scheveningen', - 'Wani', - 'Binnaguri', - 'Ban Rangsit', - 'Canlaon', - 'Kalamata', - 'Beccar', - 'Manouba', - 'Upleta', - 'El Salvador', - 'Narasapur', - 'Xanthi', - 'Chikuma', - 'Hoboken', - 'Krusevac', - 'Pedro Leopoldo', - 'Parker', - 'Jaguariuna', - 'Blue Springs', - 'Calatagan', - 'Baganga', - 'Faenza', - 'Jovellanos', - 'Shoreline', - 'Dosso', - 'Baguineda', - 'Koja', - 'St. Clair Shores', - 'Kasungu', - 'Sonabedha', - 'Pasrur', - 'Wuyang', - 'Raharpur', - 'Edgware', - 'Xinfeng', - 'Alta Floresta', - 'Kas', - 'Mpondwe', - 'Tenkodogo', - 'Horizon West', - 'Osakasayama', - 'Frutal', - 'Piparia', - 'Caltanissetta', - 'Gllogovc', - 'Una', - 'Balancan', - 'Ibaan', - 'Kelibia', - 'Sardhana', - 'Sao Gabriel', - 'Hastinapur', - 'Crotone', - "Ma'erkang", - 'Tianningcun', - 'Liannong', - 'Liantangcun', - 'Sarcelles', - 'Benevento', - 'Qaskeleng', - 'Trairi', - 'Przemysl', - 'Heerhugowaard', - 'Littlehampton', - 'Sandila', - 'Orland Park', - 'Pebane', - 'Zengcun', - 'Acerra', - 'Ogori', - 'Limerick', - 'Punta Alta', - 'Palompon', - 'Abington', - 'Tiruvalur', - 'Sucun', - 'Murakami', - 'Nanjian', - 'Capenda Camulemba', - 'Ishikari', - 'Antsalova', - 'Lambayeque', - 'Doetinchem', - 'Le Blanc-Mesnil', - 'Pursat', - 'Carson City', - 'Rass el Djebel', - 'Mouscron', - 'Frankfurt (Oder)', - 'Sillod', - 'Ruislip', - 'Mielec', - 'Calarasi', - 'Savona', - 'Naval', - 'Barotac Nuevo', - 'Temascalcingo', - 'Samana', - 'Chivilcoy', - 'Halesowen', - 'Kitahiroshima', - 'Midwest City', - 'Mulbagal', - 'North Vancouver', - 'Rouissat', - 'Bakwa-Kalonji', - 'Dapaong', - 'Maisons-Alfort', - 'Felgueiras', - 'Streatham', - 'Royal Oak', - 'Timargara', - 'Ambahikily', - 'Chibuto', - 'Masantol', - 'Tczew', - 'Pradera', - 'Chornomorsk', - 'Santa Isabel', - 'Kawthoung', - 'Hunsur', - 'Panskura', - 'Nanjakkad', - 'Bowie', - "Kan'onjicho", - 'New Corella', - 'Zempoala', - 'Hameln', - 'Kolondieba', - 'Allanmyo', - 'Cogan', - 'Oued Lill', - 'Nausori', - 'Glew', - 'Lorient', - 'Rampur Hat', - 'Dumanjog', - 'Asingan', - 'Sidi Yahya Zaer', - 'Suileng', - 'Marano di Napoli', - 'Orito', - 'Xiezhou', - 'Royal Tunbridge Wells', - 'Zivinice', - 'Villejuif', - 'Avila', - 'El Attaf', - 'Hervey Bay', - 'Kettering', - 'Khandala', - 'Lonavale', - 'St. Peters', - 'Kosai', - 'General Pico', - 'Oak Lawn', - 'Mogoditshane', - 'Grand-Popo', - 'Stalowa Wola', - 'Gengzhuangqiaocun', - 'Towson', - 'Jerez de Garcia Salinas', - 'Yanguancun', - 'New Plymouth', - 'Camajuani', - 'Taquara', - 'Bilimora', - 'Kothapet', - 'Coconut Creek', - 'Maduraivayal', - 'Togane', - 'Sira', - 'Monte Plata', - 'Lucan', - 'Diriamba', - 'Milagros', - 'Choshi', - 'Palasa', - 'Tokoname', - 'Ejmiatsin', - 'Lenexa', - 'Wiwili', - 'Guarabira', - 'Bartlett', - 'Humaita', - 'Santiago Tuxtla', - 'Cosquin', - 'Chintalapalli', - 'Meerbusch', - 'Lohardaga', - 'Buluan', - 'Cuvelai', - 'Ponte Nova', - 'Richards Bay', - 'Acara', - 'South Whittier', - 'Foumbot', - 'Antsinanantsena', - 'Huaniu', - 'Qianwu', - 'Nacaome', - 'Bebington', - 'Molfetta', - 'Tieshansi', - 'Eldorado', - 'Mali', - 'Roermond', - 'Weymouth', - 'Coruripe', - 'Lake Havasu City', - 'Macherla', - 'Boac', - 'Gumushane', - 'Bimgal', - 'Nova Esperanca', - 'Icara', - 'Kandukur', - 'Tres Arroyos', - 'Saint-Hyacinthe', - 'Keonjhargarh', - 'Villa Hayes', - 'Aldershot', - 'Bilhorod-Dnistrovskyi', - 'Cupang', - 'Alangalang', - 'Samannud', - 'Belize City', - 'Bulungu', - 'Uson', - 'Boufarik', - "Ping'an", - 'Kollegal', - 'Cosamaloapan', - 'Sarapiqui', - 'Moknine', - 'Bel Air South', - 'Unjha', - 'Benslimane', - 'Uki', - 'Nonoichi', - 'Moramanga', - 'Frejus', - 'Borujen', - 'Devrek', - 'Maun', - 'Fountainebleau', - 'Wylie', - 'Mafeteng', - 'Bail-Hongal', - 'Jasaan', - 'Dehdasht', - 'Semara', - 'Alvarado', - 'Baden-Baden', - 'Lunglei', - 'Minokamo', - 'Ipele', - 'Bura', - 'Zushi', - 'Talagante', - 'Ribnita', - 'Nasirabad', - 'Cerignola', - 'Rodos', - 'Cuemba', - 'Tezonapa', - 'Ushuaia', - 'Ban Bang Kaeo', - 'Cachoeiras de Macacu', - 'Machang', - 'Huaixiangcun', - 'Kedzierzyn-Kozle', - 'Puerto Boyaca', - 'Azzaba', - 'Mora', - 'Xam Nua', - 'Limbang', - 'Dina', - 'Gudalur', - 'Ipira', - 'Caacupe', - 'Miragoane', - 'Samalkot', - 'Karimganj', - 'Acambay', - 'Pinagkaisahan', - 'Bobbili', - 'Irpin', - 'Bebandem', - 'Chinhoyi', - 'Highland', - 'Fussa', - 'Fountain Valley', - 'Bowmanville', - 'Duzici', - 'Kalna', - 'Sattenapalle', - 'Tulcan', - 'Al Hoceima', - 'Lagonoy', - 'Basey', - 'Beauvais', - 'Kudamatsu', - "Pau d'Alho", - 'Hod HaSharon', - 'Pirapora', - 'Barabai', - 'Mugla', - 'Vrindavan', - 'Chini', - 'Acambaro', - 'Diglipur', - 'Khash', - 'Beni Enzar', - 'Den Helder', - 'Forest', - 'Macclesfield', - 'Pangantocan', - 'Gorlitz', - 'Wellingborough', - 'Taybad', - 'Berwyn', - 'Ar Riqqah', - 'Lingen', - 'Ramon', - 'Ixtahuacan', - 'Limoeiro', - 'Porto Feliz', - 'Naugaon Sadat', - 'Colomba', - 'Sendhwa', - 'Athieme', - 'El Cerrito', - 'Bartolome Maso', - 'Stolberg', - 'Moyobamba', - 'Bianyang', - 'Tiwi', - 'Severn', - 'Talegaon Dabhade', - 'Rafael Calzada', - 'Wote', - 'Hassa', - 'Rolim de Moura', - 'Mocoa', - 'Boudouaou', - 'Narbonne', - 'Villarrica', - 'Binalonan', - 'Longxing', - 'Sankt Augustin', - 'Sucat', - 'National City', - 'Placer', - 'Pacos de Ferreira', - 'Rosh Ha`Ayin', - 'Korkuteli', - 'Lian', - 'Narammala', - 'Libungan', - 'Amarante', - 'Magsaysay', - 'Lacey', - 'Bihac', - 'Pelengana', - 'Esquipulas', - 'Kut-e `Abdollah', - 'Poonamallee', - 'Sarikei', - "M'diq", - 'Gangarampur', - 'Rahovec', - 'Oosterhout', - 'Hohoe', - 'Mount Prospect', - 'Arcadia', - 'Dongola', - 'Mota', - 'Mukocho', - 'Khlong Luang', - 'Tilakpur', - 'Moncalieri', - 'Castelo Branco', - 'Mizuho', - 'Diffun', - 'Cuizhuangzi', - 'Waiblingen', - 'Tiruvallur', - 'Mandapeta', - 'San Andres Villa Seca', - 'Tirur', - 'Mendi', - 'Takizawa', - 'Kimilili', - 'Eschweiler', - 'Bonga', - 'Pithoragarh', - 'Kengri', - 'Huaquillas', - 'Myaungmya', - 'Intibuca', - 'Bluefields', - 'Oke-Mesi', - 'Langtang', - 'Ropar', - 'Parsippany-Troy Hills', - 'Abu Za`bal', - 'Chiapa de Corzo', - 'Lower Bicutan', - 'General Tinio', - 'Takaishi', - 'Acul du Nord', - 'Ajodhya', - 'DeSoto', - 'Smyrna', - 'Bungoma', - 'Longmen', - 'Khan Shaykhun', - 'Changling', - 'Belampalli', - 'Kharar', - 'Viramgam', - 'Zarrin Shahr', - 'Sidi Bennour', - 'Hilden', - 'Bradenton', - 'Braintree', - 'Bambang', - 'Biswan', - 'Tsevie', - 'Rengo', - 'Gulariya', - 'Cuneo', - 'Umm Ruwaba', - 'Kannamangalam', - 'Royal Leamington Spa', - 'Azul', - 'Atchampeta', - 'Oulad Yaich', - 'New Brunswick', - 'Nogata', - 'Asadabad', - 'Tursunzoda', - 'Paombong', - 'Bedzin', - 'Zile', - 'Nawucun', - 'Siliancun', - 'Hashtgerd', - 'Nueva Loja', - 'Meaux', - 'Portimao', - 'Hoogeveen', - 'Nyenga', - 'Guliston', - 'Iba', - 'Mulanay', - 'Kuala Kapuas', - 'Tinley Park', - 'Finote Selam', - 'Ha Giang', - 'Trapani', - 'Urbiztondo', - 'Saravena', - 'Nuevo Casas Grandes', - 'Buthidaung', - 'Raxaul', - 'Pulheim', - 'Kidderminster', - 'Shendi', - 'Sankt Polten', - 'Opava', - 'Agrigento', - 'Chystiakove', - 'San Agustin Acasaguastlan', - 'Sarasota', - 'Barwani', - 'PortoAlexandre', - 'Barrow in Furness', - 'Batac', - 'Videira', - 'Qiryat Ata', - 'Hacienda Heights', - 'Chicopee', - 'Nansan', - 'Tonekabon', - 'Zalaegerszeg', - 'Biala Podlaska', - 'Xinqing', - 'Monte Mor', - 'Tatalon', - 'Ovar', - 'Sacapulas', - 'Asturias', - 'Toki', - 'Erumaippatti', - 'Khorramdarreh', - 'Langenhagen', - 'Thermi', - 'Yamasa', - 'Taliwang', - 'West Haven', - 'Winneba', - 'Harpanahalli', - 'Buta', - 'Midalt', - 'Herriman', - 'Umm el Fahm', - 'Meyerton', - 'Periya Semur', - 'Moreno', - 'Tres Pontas', - 'Wangguanzhuang Sicun', - 'Nordhorn', - 'Madhupur', - 'Foligno', - 'Perth Amboy', - 'Rijswijk', - 'Porirua', - 'Pombal', - 'Chalil', - 'Pinto', - 'Verviers', - 'Colmenar Viejo', - 'Challakere', - 'Casa Grande', - 'Wuhuang', - 'Tigard', - 'Biel/Bienne', - 'Kronjo', - 'Puthiyangadi', - 'Lazarevac', - 'Namakkal', - 'Vranje', - 'Ibipora', - 'Hyeres', - 'Stryi', - 'Mangrol', - 'Shijonawate', - 'Bekescsaba', - 'Novohrad-Volynskyi', - 'Manapla', - 'Chonthrhu', - 'Bhimunipatnam', - 'Zgierz', - 'Olimpia', - 'Eqbaliyeh', - 'Rangewala', - 'Bobigny', - 'Apopka', - 'Ucuma', - 'Lampang', - 'Falakata', - 'Uniao da Vitoria', - 'Canoinhas', - 'Agbangnizoun', - 'Bilis Qooqaani', - 'Elenga', - 'Polur', - 'Bhongir', - 'Tasgaon', - 'Bad Homburg', - 'Narutocho-mitsuishi', - 'Dompu', - 'Songjiangcun', - 'Catu', - 'Sirnak', - 'La Roche-sur-Yon', - 'Granadilla de Abona', - 'Trani', - 'Oxchuc', - 'Tequisquiapan', - 'Corby', - 'Nandod', - 'Tivoli', - 'Southaven', - 'Imaricho-ko', - 'Acipayam', - 'Luquembo', - 'Canterbury', - 'Zhushan', - 'Pithapuram', - 'Queensburgh', - 'Jelgava', - 'Minamiuonuma', - 'Bad Salzuflen', - 'Khurai', - 'Swidnica', - 'Ojok-tong', - 'Tacuarembo', - 'Punganuru', - 'Trencin', - 'Hidaka', - 'Piedade', - 'Barranqueras', - 'Chaiwu', - 'Sarpsborg', - 'Belen de Escobar', - 'Schweinfurt', - 'Phuthaditjhaba', - 'Saruhanli', - 'Carigara', - 'Sara', - 'Hattingen', - 'Chone', - 'Mikkeli', - 'Chota', - 'Gabrovo', - 'Annaka', - 'Ghatal', - 'Terneuzen', - 'Palmares', - 'Santa Elena', - 'Giurgiu', - 'Sagar', - 'Huntington Park', - 'Mundka', - 'Diamond Bar', - 'Masinloc', - 'Bentonville', - 'Clamart', - 'Buderim', - 'Ortaca', - 'Douar Ain Chkef', - 'Kampen', - 'Antanifotsy', - 'Nihonmatsu', - 'Kouri', - 'Yucaipa', - 'Capitao Poco', - 'Mbulungu', - 'Tapas', - 'Vannes', - 'Pallini', - 'Caojia', - 'Dikwella South', - 'Medianeira', - 'Plainfield', - 'Javanrud', - 'Azrou', - 'Shidong', - 'Shidongcun', - 'Sakurai', - 'Islampur', - 'Umm Qurun', - 'Ruma', - 'Belchatow', - 'Morsott', - 'Sidhi', - 'Rahuri', - 'Chelles', - 'Sado', - 'Hanyu', - 'Zarafshon Shahri', - 'San Manuel', - 'Kizilpinar', - 'Paracin', - 'Aspen Hill', - 'Rocky Mount', - 'Cornillon', - 'Valle del Guamuez', - 'Ankadinondry-Sakay', - 'Rotorua', - 'Peabody', - 'Don Bosco', - 'Frydek-Mistek', - 'Wetzlar', - 'Hashtpar', - 'Kasaragod', - 'Komotini', - 'West Sacramento', - 'Frenda', - 'Bir Ali Ben Khalifa', - 'Wayne', - 'Huesca', - 'Ixhuatlan de Madero', - 'Cajica', - 'Louang Namtha', - 'Puttur', - 'Mariano Acosta', - 'Jalor', - 'Tarma', - 'San Jacinto', - 'Cheddra', - 'Kunnamkulam', - 'Kentwood', - 'Palmaner', - 'Xihu', - 'Jalakati', - 'Deolali', - 'Lozova', - 'Prachuap Khiri Khan', - 'Ribeira do Pombal', - 'Juanjui', - 'Tagkawayan', - 'Ghoriyan', - 'Jihong', - 'Kennedy Town', - 'Titay', - 'Puerto Libertador', - 'Minalabac', - 'Neustadt', - 'Umred', - 'Sabbashahr', - 'Bandar-e Torkaman', - 'Hamura', - 'Chenab Nagar', - 'Sohna', - 'Colton', - 'Chilibre', - 'Cholet', - 'Vigan', - 'Manicore', - 'San Bartolome', - 'Chania', - 'An Nimas', - 'Passau', - 'Manfredonia', - 'Cabagan', - 'Bacaadweyn', - 'Narva', - 'Bijar', - 'Iganga', - 'Impasugong', - 'Parvatipuram', - 'Oak Park', - 'Mansala', - 'Ullal', - 'Magpet', - 'Juigalpa', - 'Kitaotao', - 'Louangphabang', - 'Dholka', - 'Ottappalam', - 'Westchester', - 'Sao Francisco do Sul', - 'Zongo', - 'A Yun Pa', - 'Cangola', - 'Funato', - 'Gazipasa', - 'Upata', - 'Wheaton', - 'Hadali', - 'Manjeri', - 'Alcobaca', - 'Kongoussi', - 'Evry', - 'Al Majaridah', - 'Ashta', - 'Sakon Nakhon', - 'Gisenyi', - 'Lower Paxton', - 'Cambundi Catembo', - 'Evora', - 'Encarnacion de Diaz', - 'Ilindu Kothi', - 'Bisceglie', - 'Aloha', - 'Kaliyaganj', - 'Jaggayyapeta', - 'Minnetonka', - 'Brits', - 'Morondava', - 'Modica', - 'Marechal Candido Rondon', - 'Ilgin', - 'Epinay-sur-Seine', - 'Travnik', - 'Extrema', - 'Howell', - 'Hongshandian', - 'Ajuy', - 'Pasacao', - 'Marco de Canavezes', - 'Popesti-Leordeni', - 'Goalpara', - 'Sibonga', - 'Dilovasi', - 'Pryluky', - 'Mutsu', - 'Kleve', - 'Liberia', - 'Yaguajay', - 'Shahpur', - 'Guiuan', - 'Tutoia', - 'Pinellas Park', - 'Ahlen', - 'Granja', - 'Tokamachi', - 'Keighley', - 'Kannapolis', - 'Gorkha', - 'Itabirito', - 'Montesilvano', - 'Tame', - 'Inhumas', - 'Paramount', - 'Dongshan', - 'Amalapuram', - 'Tokmok', - 'Acu', - 'Dangila', - 'Bakhtiyarpur', - 'Legionowo', - 'Arsikere', - 'San Vicente', - 'La Gomera', - 'Saint-Ouen', - 'Qingan', - 'Kabale', - 'Bitonto', - 'Barbosa', - 'Patancheruvu', - 'Capivari', - 'Pinotepa', - 'Barobo', - 'Rondon do Para', - 'Vikarabad', - 'Molave', - 'Baruipur', - 'Beberibe', - 'Deva', - 'Hereford', - 'Dandarah', - 'Dunfermline', - 'Lucban', - 'Texas City', - 'Sagua la Grande', - 'Itapage', - 'Novato', - 'Targovishte', - 'Edina', - 'Naka', - 'Mahmutlar', - 'Elda', - 'Piekary Slaskie', - 'Safranbolu', - 'At Tawahi', - 'Salo', - 'San Estanislao', - 'Izumi', - 'Manglaur', - 'Beloeil', - 'Saint-Quentin', - 'Phra Nakhon Si Ayutthaya', - 'Simojovel de Allende', - 'Kadiolo', - 'Bagheria', - 'Hyosha', - 'Normal', - 'Tilhar', - 'Bondy', - 'Xincheng', - 'Sao Miguel do Guama', - 'Xinguara', - 'Sultanganj', - 'Congonhas', - 'Tiruvalla', - 'Kandira', - 'Mandi Dabwali', - 'Maha Sarakham', - 'Tamiami', - '`Aliabad-e Katul', - 'Clorinda', - 'Grand Island', - 'Siena', - 'Methuen Town', - 'Frechen', - 'Gallarate', - 'Hrazdan', - 'Timbauba', - 'San Remo', - 'Elyria', - 'Lorica', - 'Usa', - 'Harrismith', - 'Sao Francisco', - 'Malkara', - 'Ksar Chellala', - 'Pigcawayan', - 'Ouenza', - 'Jette', - 'Lagoa da Prata', - 'Karak', - 'Madinat Hamad', - 'Woerden', - 'Venkatagiri', - 'Hamtic', - 'Kelaa Kebira', - 'Paracambi', - 'Corbeil-Essonnes', - 'Wolfenbuttel', - 'Bozova', - 'Kobryn', - 'North Bay', - 'Kendale Lakes', - 'Porto Ferreira', - 'Quezaltepeque', - 'San Jose Villa de Allende', - 'Bloomfield', - 'Tramandai', - 'Kahnuj', - 'Yaozhuangcun', - 'Minami-Soma', - 'Zhangjiazhuang', - 'Zhangjiazhuangcun', - 'Sihor', - 'Tizimin', - 'Imbituba', - 'Roskilde', - 'Cagnes-sur-Mer', - 'Nerkunram', - 'Jihlava', - 'Baskale', - 'Marana', - 'Guernica', - 'Bad Kreuznach', - 'Neibu', - 'Velletri', - 'Cihanbeyli', - 'President Roxas', - 'Burauen', - 'Tlacotepec', - 'An Nabk', - 'Panjakent', - 'Qabqa', - 'Bamei', - 'Thongwa', - 'Pacora', - 'Baduria', - 'Dauis', - 'El Rama', - 'Claveria', - 'Barlad', - 'Sironj', - 'Ban Om Noi', - 'San Miguel Ixtahuacan', - 'West New York', - 'Padangpanjang', - 'Ibbenburen', - 'Tonsberg', - 'Altrincham', - 'Coronel Oviedo', - 'Jangaon', - 'Miyakojima', - 'Charlottetown', - 'Marechal Deodoro', - 'Ibajay', - 'Daudnagar', - 'Paraiso do Tocantins', - 'Jiyyammavalasa', - 'Zalau', - 'Acajutla', - 'Antratsyt', - 'Mandamari', - 'Lakhminia', - 'Sison', - 'Ain Sefra', - 'Twin Falls', - 'Marondera', - 'Akbou', - 'Campo Belo', - 'Santo Estevao', - 'Delmiro Gouveia', - 'Taquaritinga', - 'Tekkekoy', - 'Enerhodar', - 'Obidos', - 'Cangandala', - 'Lautoka', - 'Pula', - 'Taxco de Alarcon', - 'Sao Jose do Rio Pardo', - 'Koraput', - 'Mudhol', - 'Avellino', - 'Pola de Siero', - 'Naguilian', - 'Horishni Plavni', - 'Florissant', - 'Alesund', - 'Uriangato', - 'Bato', - 'El Tumbador', - 'Vaulx-en-Velin', - 'Bhajani', - 'Phaltan', - 'Shiraoka', - 'Buique', - 'Glendora', - 'Acatzingo', - 'Diu', - 'Lengquancun', - 'Portici', - 'Ampanihy', - 'Todupulai', - 'Bitlis', - 'Albu Kamal', - 'Chajul', - 'Pontes e Lacerda', - 'Thomazeau', - 'Tangkak', - 'Caetite', - 'Yendi', - 'Gummersbach', - 'Ambohibary', - 'Ad Dabbah', - 'Tejen', - 'Dungu', - 'Takeo', - 'Shiogama', - 'Huamantla', - 'Ibiza', - 'San Onofre', - 'Khattan', - 'Cathedral City', - 'Vaisampakkal', - 'Kumarankari', - 'Al Kharj', - 'Ntoum', - 'Piaseczno', - 'Eilat', - 'Muban Saeng Bua Thong', - 'Santa Eulalia', - 'Mengmeng', - 'Aliso Viejo', - 'Vernon', - 'Liaquatpur', - 'Rumia', - 'San Gil', - 'Wangjiazhai', - 'El Bagre', - 'Tomiya', - 'Alytus', - 'Padre Garcia', - 'Villareal', - 'Vila Real', - 'Arwal', - 'Sevran', - 'Choma', - 'Kardzhali', - 'Melo', - 'Mollet', - 'Fontenay-sous-Bois', - 'M.A. Rasulzada', - 'Palenque', - 'Covilha', - 'Placentia', - 'Sao Gabriel da Cachoeira', - 'Crosby', - 'Sherpur', - 'Burla', - 'Hoffman Estates', - 'Gadarwara', - 'Caleta Olivia', - 'Baranoa', - 'Caldas da Rainha', - 'Caramoan', - 'Gradiska', - 'Pordenone', - 'Utrera', - 'Belle-Anse', - 'Isfara', - 'Guapimirim', - 'Tamboril', - 'Qalqilyah', - 'Kalpi', - 'Aguadulce', - 'Girardota', - 'Civitavecchia', - 'Baiao', - 'Santa Ignacia', - 'Shahr-e Babak', - 'Xanxere', - 'Mulongo', - 'Huazangsi', - 'Tijucas', - 'Irinjalakuda', - 'Menggala', - 'Kokstad', - 'Tachilek', - 'Zeralda', - 'Teramo', - 'Tirupparangunram', - 'Maubin', - 'Tulsipur', - 'Incirliova', - 'Bando', - 'Zangareddigudem', - 'Burien', - 'Barri', - 'Baham', - 'Abdul Hakim', - 'Ravensburg', - 'Ras el Oued', - 'Sombor', - 'Bantacan', - 'Boblingen', - 'Dunwoody', - 'Ensenada Berisso', - 'Susangerd', - 'Mangochi', - 'Willenhall', - 'Peine', - 'Cerca la Source', - 'El Kelaa des Srarhna', - 'Bootle', - 'Stratford', - 'Speyer', - 'Torrelavega', - 'Morrinhos', - 'Nenton', - 'Koumantou', - 'Boukadir', - 'Folkestone', - "'Ain Merane", - 'Tadmur', - 'Rastatt', - 'Samut Prakan', - 'Kalawana', - 'Sape', - 'Lankaran', - 'Rincon de la Victoria', - 'Kyzyl-Kyya', - 'Palm Desert', - 'Puerto Francisco de Orellana', - 'Cutervo', - 'Peranampattu', - 'Guarne', - 'Tamalous', - 'Raciborz', - 'Rongat', - 'Walin', - 'Dartford', - 'Dabhoi', - 'Montijo', - 'Sartrouville', - 'Herning', - 'Bargny', - 'Bhavani', - 'Puthuppariyaram', - 'Mascouche', - 'Collierville', - 'Sidlaghatta', - 'Jurmala', - 'Korce', - 'Levittown', - 'Leopoldina', - 'Martin', - 'Tsukubamirai', - 'Barra', - 'Brejo Santo', - 'Marpalli', - 'Bowringpet', - 'Knysna', - 'Sar-e Pul', - 'Ocampo', - 'San Narciso', - 'Hodal', - 'Fatwa', - 'Rosemead', - 'Rosso', - 'Kot Mumin', - 'Shimencun', - 'Segovia', - 'Kalba', - 'Iormughanlo', - 'Country Club', - 'Tucuru', - 'Massy', - 'Enid', - 'Horsham', - 'Cumbernauld', - 'Pardwal', - 'Djamaa', - 'Cuyahoga Falls', - 'Guaxupe', - 'Tobias Barreto', - 'Esher', - 'Metpalli', - 'Kalamansig', - 'Mishawaka', - 'Andover', - 'Juruti', - 'Babila', - 'Silkeborg', - 'Repalle', - 'Huaiyang', - 'Skenderaj', - 'Mabini', - 'Kyotango', - 'Miyako', - 'Pontal', - 'Campos do Jordao', - 'Teplice', - 'Summerville', - 'Vigia', - 'Nicoya', - 'Bani Walid', - 'Cermik', - 'Turtkul', - 'Geyve', - 'Kuchaiburi', - 'Vyara', - 'Whangarei', - 'Zabid', - 'Sibsagar', - 'Irondequoit', - 'Mahmudabad', - 'Elmshorn', - 'Grapevine', - 'Goshogawara', - 'Jarash', - 'Zumpango', - 'Marigot', - 'Covina', - 'Rio Tinto', - 'Ranchuelo', - 'Quirinopolis', - 'Beruniy', - 'Bikramganj', - 'Agrinio', - 'Goksun', - 'Mweka', - 'Chinchina', - 'Estancia Velha', - 'Sunamganj', - 'Milford city', - 'Neath', - 'Chinnamanur', - 'Draper', - 'Fafe', - 'Cataingan', - 'Kotka', - 'El Jem', - 'Skien', - 'Haskah Menah', - 'Jaru', - 'Metema', - 'Sakaidecho', - 'Catalina Foothills', - 'Arao', - 'Anaiyur', - 'Kosamba', - 'La Calera', - 'Clacton-on-Sea', - "Cava de' Tirreni", - 'Emden', - 'Northwich', - 'Jaspur', - 'Nichinan', - 'Acireale', - 'Susono', - 'Delano', - 'Gloria', - 'El Nido', - 'Mahmud-e Raqi', - 'Forbesganj', - 'Tebourba', - 'Hunedoara', - 'Navirai', - 'Bas Limbe', - 'Tuyserkan', - 'Laksar', - 'Youfangcun', - 'Cabreuva', - 'El Talar de Pacheco', - 'Bar Bigha', - 'Tundla', - 'Arles', - 'Boa Viagem', - 'Bangued', - 'Aringay', - 'Haverford', - 'Tanjombato', - 'Ampitatafika', - 'Plaisance', - 'Wao', - 'Myrnohrad', - 'Chbar Mon', - 'Ma`an', - 'Amulung', - 'Vargem Grande Paulista', - 'Cojutepeque', - 'Chinu', - 'Baghpat', - 'Floresti', - 'Penablanca', - 'Rho', - 'Donsol', - 'Beveren', - 'Rowley Regis', - 'Artur Nogueira', - 'Bhawanipur Rajdham', - 'Houten', - 'Yuki', - 'Goslar', - 'Ghulakandoz', - 'Gombong', - 'Nes Ziyyona', - 'Nakagawa', - 'Palpala', - 'Hamada', - 'Karvina', - 'Adeje', - 'Gopalpur', - 'Willich', - 'Cardona', - 'Qinhe', - 'Bang Bua Thong', - 'Scarborough', - 'Ercolano', - 'Sour el Ghozlane', - 'Deressia', - 'Itarare', - 'Bhadrachalam', - 'Francisco I. Madero', - 'Sfantu-Gheorghe', - 'Tubod', - 'Biaora', - 'Sojat', - 'Yerba Buena', - 'Wolossebougou', - 'Yasu', - 'Hassan Abdal', - 'Murray', - 'Mazara del Vallo', - 'Leith', - 'Heidenheim', - 'Mooresville', - 'Eger', - 'Weert', - 'Sakubva', - 'Qabb Elias', - 'El Ghaziye', - 'Aarsal', - 'Ikot Okoro', - 'Sechura', - 'Chak Thirty-six North Branch', - 'Rukan', - 'Buni', - 'Chak Sixty-one Gugera Branch', - 'Al Wajh', - 'Abu Hamad', - 'Godinlabe', - 'Ceel Dheere', - 'Tukuyu', - 'Kyaliwajjala', - 'Aqchah', - 'Krems an der Donau', - 'Bandar Seri Begawan', - 'Kahemba', - 'Gutao', - 'Xiayang', - 'Dongxishan', - 'Xiazhai', - 'Jieshangya', - 'Saoula', - "'Ain el Turk", - 'Semera', - 'Bogoso', - 'Tammampatti', - 'Sujanpur', - 'Shiv', - 'Bhattu Kolan', - 'Downers Grove', - 'Louveira', - 'Florin', - 'Al Kharjah', - 'Sihora', - 'Chatra', - 'Rovigo', - 'Parasia', - 'Satte', - 'Chake Chake', - 'Cypress', - 'Chahar Dangeh', - 'Simraungadh', - 'Porvoo', - 'Ejeda', - 'Muktagacha', - 'Janin', - 'Shankou', - "Al Ma`alla'", - 'Bigadic', - 'Erftstadt', - 'Lorrach', - 'Stouffville', - 'Hilsa', - 'Poprad', - 'Cuxhaven', - 'Tepeapulco', - 'Neyriz', - 'Pananaw', - 'Xankandi', - 'Boaco', - 'Nohar', - 'Gediz', - 'Gronau', - 'Ain El Aouda', - 'Ostersund', - 'Ostroleka', - 'Cerquilho Velho', - 'Hannan', - 'El Meghaier', - 'Novovolynsk', - 'Jeffersonville', - 'Karapinar', - 'Bhainsa', - 'North Bethesda', - 'Cine', - 'Itupiranga', - 'Selibe Phikwe', - 'Perintalmanna', - 'Padrauna', - 'Bignay', - 'Albi', - 'Gualan', - 'Azusa', - 'Yeovil', - 'Coral Gables', - 'Ridder', - 'Wagga Wagga', - 'Cangucu', - 'Nanao', - 'Zyryanovsk', - 'Perambalur', - 'Chesterfield', - 'Noshiromachi', - 'Coelho Neto', - 'Shawinigan', - 'Aversa', - 'Kandangan', - 'Pirot', - 'Cimitarra', - 'Sosua', - 'McLean', - 'San Juan del Cesar', - 'Huancavelica', - 'Saint-Herblain', - 'Kizhake Chalakudi', - 'Mojo', - 'Leonberg', - 'Dumarao', - 'Sesimbra', - 'Mpigi', - 'Sulleru', - 'St. Louis Park', - 'Arakli', - 'East Honolulu', - 'Rheda-Wiedenbruck', - 'Gao', - 'Shakhtarsk', - 'Bad Oeynhausen', - 'Peddapuram', - 'Payyoli', - 'Tomisato', - 'Maria la Baja', - 'East Brunswick', - 'Santa Lucia del Camino', - 'Kameyama', - 'Monte Alto', - 'Majalgaon', - 'Noveleta', - 'Catemaco', - 'Sao Bento do Una', - 'Villaguay', - 'Singen', - 'Battipaglia', - 'Gennevilliers', - 'Ozgon', - 'Pen-y-Bont ar Ogwr', - 'Nowshahr', - 'Prudentopolis', - 'Suzaka', - 'Prattipadu', - 'Scandicci', - 'Kiblawan', - 'Karlovac', - 'Ksar Hellal', - 'Arifiye', - 'Mulukuku', - 'Freising', - 'Sebeta', - 'Wandan', - 'San Severo', - 'Mbouda', - 'Goba', - 'Kapadvanj', - 'Mailiao', - 'Edenvale', - 'Odiongan', - 'Euclid', - 'Bergkamen', - 'Asakura', - 'Higashiura', - 'Joliette', - 'Zargar', - 'Agustin Codazzi', - 'Tuodian', - 'Tennala', - 'Fangcun', - 'Cintalapa de Figueroa', - 'Midori', - 'Ceres', - 'Samaniego', - 'Straubing', - 'Qalat', - 'Kaedi', - 'University', - 'Notse', - 'Biloxi', - 'Tunuyan', - 'Lulea', - 'Slonim', - 'Saray', - 'Suresnes', - 'Luwero', - 'Guozhen', - 'Hikari', - 'Kefamenanu', - 'Malabang', - 'Sungurlu', - 'Yamaga', - 'El Dorado Hills', - 'Nahuizalco', - 'Pio Duran', - 'Naugachhia', - 'Ardea', - 'Frankenthal', - 'Karlovy Vary', - 'Vinzons', - 'Port-Vila', - 'Bornheim', - 'Oamishirasato', - 'Misterbianco', - 'Cerritos', - 'Nizampur', - 'Farajok', - 'Song Doc', - 'Jaggisettigudem', - 'Dulag', - 'Rye', - 'Changyon', - 'Suwa', - 'Burleson', - 'Libona', - 'Eltham', - 'Fouka', - 'Portage', - 'Rimouski', - 'Al Mayadin', - 'Barnstable', - 'Courtenay', - 'Alcala', - 'Upplands Vasby', - '`Akko', - 'Kangar', - 'Panay', - 'Dumingag', - 'Nomimachi', - 'Jimenez', - 'Couva', - 'Hampstead', - 'Godda', - 'Telerghma', - 'Takeocho-takeo', - 'Empoli', - "Tajura'", - 'Badurpalle', - 'Santo Domingo Suchitepequez', - 'Saint-Priest', - 'Vertientes', - 'Waalwijk', - 'Shimotsucho-kominami', - 'Ain Fakroun', - 'Cacongo', - 'Vincennes', - 'Chikugo', - 'Jales', - 'Nikaweratiya', - 'Bastia', - 'Ocotal', - 'Sanare', - 'El`ad', - 'Sesto Fiorentino', - 'Tunglangan', - 'Tucano', - 'Poway', - 'Lal-lo', - 'Cedar Hill', - 'Harderwijk', - 'Verrettes', - 'Boucan Carre', - 'Dongzhang', - 'Takahama', - 'Mladenovac', - 'Koduvalli', - 'Garmsar', - 'Guntakal Junction', - 'Gooty', - 'Mantova', - 'Brejo da Madre de Deus', - 'Roman', - 'Stillwater', - 'Barendrecht', - 'Colcapirhua', - 'Amora', - 'Caraballeda', - 'Zajecar', - 'Bantval', - 'Barotac Viejo', - 'Angol', - 'Soest', - 'Leiktho', - 'Batajnica', - 'Titusville', - 'Namtu', - 'Yenangyaung', - 'Martigues', - 'Sao Joaquim da Barra', - 'Omitama', - 'Masagua', - 'Orangetown', - 'Cwmbran', - 'Inabanga', - 'Suzukawa', - 'Nyaungu', - 'Sutton in Ashfield', - 'Siocon', - 'Kilvisharam', - 'Begoro', - 'Liujiaxia', - 'Khairabad', - "'Ain Azel", - 'Kyle', - 'Jasdan', - 'Etterbeek', - 'Upperu', - 'Kawkareik', - 'Pedreira', - 'Chieti', - 'Mangalapadi', - 'Wakema', - 'Dollard-des-Ormeaux', - 'West Orange', - 'Babaeski', - 'Kozlu', - 'Minalin', - 'Welwyn Garden City', - 'Damavand', - 'Erlin', - 'Waterford', - 'Stade', - 'Collegno', - 'Beni Yakhlef', - 'Kalima', - 'San Pedro Mixtepec', - 'Alsdorf', - 'Alajuela', - 'Grasse', - 'IJmuiden', - 'Upper Buchanan', - 'Tuba', - 'Levakant', - 'Asuncion Mita', - 'Vite', - 'Kara-Balta', - 'Nong Khai', - 'Beypazari', - 'Jiashizhuangcun', - 'Westfield', - 'Mahayag', - 'Ishigaki', - 'Berastagi', - 'Chhagalnaiya', - 'Titao', - 'Little Elm', - 'Morden', - 'Can', - 'Duyen Hai', - 'Homnabad', - 'Joshimath', - 'Sanmu', - 'Qulicun', - 'Dachau', - 'Smethwick', - 'Hagere Hiywet', - 'Shuishang', - 'Playas', - 'Gumia', - 'Alta Gracia', - 'Finike', - 'Kirkcaldy', - 'Faya', - 'Bokaro', - 'North Highlands', - 'Ami', - 'Dornbirn', - 'Bacolor', - 'Balimbing', - 'Tuckahoe', - 'Wake Forest', - 'Scafati', - 'Minot', - 'Araci', - 'Nettuno', - 'Colonia del Sol', - 'Bocaiuva', - 'Aquidauana', - 'Kanye', - 'Hennef', - 'Tunduru', - 'Liutuancun', - 'Santangpai', - 'Nangal Township', - 'Ena', - 'Monopoli', - 'Yongping', - 'Cuetzalan', - 'Ash Shaykh Badr', - 'Kasuya', - 'Iwakura', - 'Okhtyrka', - 'Basoko', - 'Sadaseopet', - 'New Washington', - 'Hoskote', - 'Barras', - 'Clondalkin', - 'Carepa', - 'Bhamo', - 'Wauwatosa', - 'Bothell', - 'Birendranagar', - 'Glenview', - 'Vila Verde', - 'Tibigan', - 'Figueras', - 'Dyero', - 'Chong Nonsi', - 'Rockwall', - 'Baguanos', - 'Golpayegan', - 'Jalandhar Cantonment', - 'Cornwall', - 'La Reja', - 'Horsholm', - 'Pativilca', - 'Jiquilisco', - 'Monte Santo', - 'Luwuk', - 'Wilson', - 'Victoriaville', - 'Oranienburg', - 'Bhatkal', - 'Higashine', - 'Guroymak', - 'Agueda', - 'Ad Darwa', - "Al Madrah Sama'il", - 'Tremembe', - 'Dungarpur', - 'Mamburao', - 'Diamantina', - 'Rancho Santa Margarita', - 'Chandrawada', - 'Kamidani', - 'Zawiercie', - 'Monte Carmelo', - 'Ocosingo', - 'Vale de Cavalos', - 'Montrouge', - 'Amahai', - 'Ambatondrazaka', - 'Pabellon de Arteaga', - 'La Mirada', - 'Georgina', - 'Sao Benedito', - 'Tonami', - 'Antelope', - 'Hilo', - 'Invercargill', - 'Longchamps', - 'Gracias', - 'Landau', - 'Ono', - 'Yumbe', - 'Chetouane', - 'Al Aaroui', - 'Gava', - 'Hitachi-ota', - 'Dumka', - '`Amuda', - 'Yecun', - 'Kokkola', - 'Catriel', - 'Helsingor', - 'Chioggia', - 'Sogod', - 'Pampan', - 'Vich', - 'Mairena del Aljarafe', - 'Lamia', - 'San Luis Obispo', - 'Puerto Lempira', - 'Bunawan', - 'Rengam', - 'Gaocheng', - 'Okaya', - 'Buena Vista Tomatlan', - 'Azna', - 'Egg Harbor', - 'Changanacheri', - 'Dalaman', - 'Poso', - 'Dulmen', - 'Campi Bisenzio', - 'Umarkhed', - 'Serowe', - 'Liuhu', - 'Indija', - 'Zutphen', - 'Atarra', - 'Altos', - 'Osorio', - 'Chaparral', - 'Malinao', - 'Nanto', - 'Lousada', - 'Villa Constitucion', - 'Chenalho', - 'Penco', - 'Voluntari', - 'Vryheid', - 'Sanski Most', - 'Barnet', - 'Wejherowo', - 'Jobabo', - 'General Martin Miguel de Guemes', - 'Sumisip', - 'Qasbat Tadla', - 'Aubagne', - 'Kifisia', - 'Saint-Malo', - 'Azhikkod', - 'Azhikkal', - 'Rio de Mouro', - 'Loum', - 'Mentor', - 'Talghar', - 'Ocoee', - 'Evreux', - 'Sao Jose de Mipibu', - 'San Andres de Sotavento', - 'Mataquescuintla', - 'Gosen', - 'Snizhne', - 'Cunen', - 'Oued Sly', - 'Ayapel', - 'Vikramasingapuram', - 'Perinton', - 'Waspan', - 'Melle', - 'Jiaganj', - 'Manapparai', - 'Kasumbalesa', - 'As Sa`diyah', - 'Rowland Heights', - 'Zhongtanying', - 'Evesham', - 'Kikugawa', - 'Douz', - 'Decin', - 'La Courneuve', - 'Fort Pierce', - 'Albuera', - 'Rivoli', - 'Yabrud', - 'Urrao', - 'Sidrolandia', - 'Capao Bonito', - 'Cumanayagua', - 'Paderno Dugnano', - 'Ayungon', - 'Brea', - 'Cantel', - 'Sowme`eh Sara', - 'Mattanur', - 'Campobasso', - 'Zarzal', - 'Oro Valley', - 'Chaidari', - 'Dracena', - 'Hagaribommanahalli', - 'Ha Tien', - 'Pallipalaiyam', - 'Calimaya', - 'Corato', - 'East Providence', - 'Saranambana', - 'Dahutang', - 'Al Balyana', - 'Banisilan', - 'Haeryong', - 'Casalnuovo di Napoli', - 'Liulin', - 'Viti', - 'Jitaicun', - 'Cuilapa', - 'San Benedetto del Tronto', - 'Nandikotkur', - 'Herzogenrath', - 'Chomutov', - 'Tomioka', - 'Esplugas de Llobregat', - 'Selu', - 'Stretford', - 'Matay', - 'Mela Gudalur', - 'Martina Franca', - 'Boujad', - 'Campo Maior', - 'Borgne', - 'Kabasalan', - 'Neunkirchen', - 'Pocoes', - 'Lecco', - 'Banbury', - 'Beckenham', - 'Noboribetsu', - 'Blois', - 'Pearl City', - 'Joao Pinheiro', - 'Lorenskog', - 'Nanzhuangzhen', - 'Greenford', - 'Lohja', - 'Isabel', - 'Ayr', - 'Teotihuacan', - 'San Jacinto de Buena Fe', - 'Santa Ana Chiautempan', - 'Al Qusayr', - 'Araioses', - 'Wokingham', - 'Hyvinkaa', - 'Rovenky', - 'Salina', - 'Lukavac', - 'Jesus Menendez', - 'Sanuki', - 'La Jagua de Ibirico', - 'South Brunswick', - 'Taebaek', - 'Stepnogorsk', - 'Guaramirim', - 'Cologno Monzese', - 'Woodstock', - 'Punalur', - 'Kampli', - 'Bizerte', - 'Yashan', - 'Ramat HaSharon', - 'La Caleta', - 'Kuilsrivier', - 'Norala', - 'Nellikkuppam', - 'Daxiang', - 'Ridderkerk', - 'Hioki', - 'Dongnanyanfa', - 'Padra', - 'Fujiyoshida', - 'Schwerte', - 'Hof', - 'Muara Teweh', - 'Yalvac', - 'Wangtan', - 'Libertador General San Martin', - 'Puerto Villarroel', - 'Suluova', - 'Brive-la-Gaillarde', - 'Bruchsal', - 'Langford Station', - 'Beavercreek', - 'Obra', - 'Faratsiho', - 'Hajjah', - 'Nakai', - 'Quinte West', - 'Montevista', - 'Schagen', - 'Lucaya', - 'Aland', - 'Dori', - 'Tuy', - 'Winter Garden', - 'Punal', - 'Hadithah', - 'Potomac', - 'Lower Tungawan', - 'Swietochlowice', - 'Vuyyuru', - 'Cordon', - 'Kadinamkulam', - 'Corroios', - 'Manvi', - 'Jendouba', - 'Farmington', - 'San Francisco de los Romo', - 'Jeomchon', - 'Henrietta', - 'Santa Cruz do Rio Pardo', - 'Nelson', - 'Skierniewice', - 'Kita', - 'Rodgau', - 'Albstadt', - 'Rio Tercero', - 'Pakenham', - 'Alcira', - 'Sardasht', - 'La Independencia', - 'Quva', - 'Charleville-Mezieres', - 'Sao Bento', - 'Manacor', - 'Lissone', - 'Attleboro', - 'Starogard Gdanski', - 'Nilambur', - 'Shimenzhai', - 'Kilmarnock', - 'Marino', - 'Meudon', - 'Cuihua', - 'Bhalki', - 'Halle-Neustadt', - 'Pagalungan', - 'Bindura', - 'Ban Plai Bua Phatthana', - 'Starachowice', - 'Vidin', - 'Kurayoshi', - 'Farim', - 'Cobija', - 'Zhongzhai', - 'Douera', - 'Anandpur', - 'Capannori', - 'Koure', - 'Takashima', - 'Nichelino', - 'Narvacan', - 'Arandelovac', - 'Santana do Ipanema', - 'Carcassonne', - 'Izunokuni', - 'Shimeo', - 'Lawas', - 'Chitre', - 'Tingo Maria', - 'Filderstadt', - 'Labutta', - 'Puerto Tejada', - 'Strongsville', - 'Zhob', - 'Seabra', - 'Tlalmanalco', - 'Choisy-le-Roi', - 'Uniao', - 'Manono', - 'Casimiro de Abreu', - 'Eagle Mountain', - 'Noisy-le-Sec', - 'Borca', - 'Sumpango', - 'Kasaoka', - 'Bridgewater', - 'Jammalamadugu', - 'Acaxochitlan', - 'Beringen', - 'Garhwa', - 'Santurce-Antiguo', - 'San Feliu de Llobregat', - 'Prescott', - 'Sikandra Rao', - 'Cavaillon', - 'Eusebio', - 'Nova Venecia', - 'Bothaville', - 'Bunde', - 'Livry-Gargan', - 'Tomboco', - 'Nawashahr', - 'Trenque Lauquen', - 'Gotha', - 'Ranavav', - 'Mairinque', - 'Bihat', - 'Gahini', - 'Mindat', - 'Bajil', - 'Huilongcun', - 'Camp Perrin', - 'Amboasary', - 'Isiolo', - 'Harasta', - 'Ban Bang Mae Nang', - 'Kikuchi', - 'Dingle', - 'Jaguaquara', - 'Markala', - 'Coonoor', - 'Wodzislaw Slaski', - 'Thoubal', - 'Tamagawa', - 'Paraguacu Paulista', - 'Freeport City', - 'Olive Branch', - 'Ourem', - 'Haymana', - 'Lupao', - 'Donggang', - 'Hokota', - 'Lumba-a-Bayabao', - 'Fastiv', - 'Joal-Fadiout', - 'Koupela', - 'Campo Novo do Parecis', - 'Chepen', - 'Fellbach', - 'Arendal', - 'Stavroupoli', - 'Dharmaragar', - 'Juina', - 'Parys', - 'Goose Creek', - 'Memmingen', - 'Tallbisah', - 'Sicklerville', - 'Chajari', - 'Igarape', - 'Pakaur', - 'Settimo Torinese', - 'Shima', - 'Cheshunt', - 'Jablonec nad Nisou', - 'Shertallai', - 'Havant', - 'Aribinda', - 'Hexiwu', - 'Dodoma', - 'Phan Ri Cua', - 'Kaufbeuren', - 'Nawai', - 'Lubny', - 'Altamonte Springs', - 'Badrashni', - 'Haltom City', - 'Ouled Moussa', - 'Borgerhout', - 'Gollalagunta', - 'Hackensack', - 'Dongsu', - 'Tantangan', - 'Dialakorodji', - 'St. Thomas', - 'Maluso', - 'Muradiye', - 'La Goulette', - 'Changchong', - 'Yambio', - 'Santa Maria Huatulco', - 'Farrukhnagar', - 'Dendermonde', - 'Puttalam', - 'Hokuto', - 'Shangpa', - 'Rosny-sous-Bois', - 'Elmhurst', - 'Mislata', - 'Ogimachi', - 'Porangatu', - 'Jones', - 'Chattamangalam', - 'Denia', - 'Remedios', - 'Tangdukou', - 'Tindouf', - 'El Valle del Espiritu Santo', - 'Qianjiang Shequ', - 'Urbandale', - 'Kitakata', - 'Caiguantun', - 'Nueva Gerona', - 'Baiji', - 'Ascoli Piceno', - 'Kirkby', - 'Mauriti', - 'Rio Cauto', - 'Guacharachi', - 'Talagutong', - 'Kumta', - 'Busaar', - 'Littleton', - 'Cuautepec de Hinojosa', - 'Ortega', - 'Sangarebougou', - 'Veldhoven', - 'Canela', - 'Voi', - 'Warud', - 'Ashburn', - 'Lalian', - 'Bafq', - 'Surcin', - 'Labrea', - 'Kerkrade', - 'Birak', - 'Carnot', - 'Ganapathivattam', - 'East Lansing', - 'Olhao', - 'San Pelayo', - 'Fuxing', - 'West Seneca', - 'Mbulu', - 'Palayan City', - 'Jipijapa', - 'Gobardanga', - 'Barra Velha', - 'Bountiful', - 'Erith', - 'San Antonio Abad', - 'Ciudad de Huajuapam de Leon', - 'Keller', - 'Svitlovodsk', - 'Karmiel', - 'Vallenar', - 'Morgan Hill', - 'Gaoua', - 'Rieti', - 'Saint-Eustache', - 'Weinheim', - 'Pulawy', - 'Neustadt am Rubenberge', - 'Hinckley', - 'Tayug', - 'Misseni', - 'Rada`', - 'Talence', - 'Kelo', - 'Jaragua', - 'Webster', - 'Chimteppa', - 'Gracanica', - 'Sierra Vista', - 'Cornelio Procopio', - 'Vercelli', - 'Ashton', - 'Drachten', - 'Araquari', - 'Medemblik', - 'Paterno', - 'Inongo', - 'Bani `Ubayd', - 'Presidente Dutra', - 'Belfort', - 'Garango', - 'Hassi Messaoud', - 'Sayreville', - 'Basud', - 'Surbiton', - 'Numata', - 'Puertollano', - 'Marau', - 'Massigui', - 'Montemorelos', - 'Castleford', - 'Chalungalpadam', - 'Aguilar', - 'Bingmei', - 'Nova Kakhovka', - 'Inuma', - 'Krosno', - 'Arantangi', - 'Nayudupet', - 'Maracaju', - 'Caete', - 'Alfortville', - 'Haugesund', - 'Bac Kan', - 'Sundargarh', - 'Abqaiq', - 'Chalon-sur-Saone', - 'Odenton', - 'Prievidza', - 'Bilacari', - 'Heusden', - 'Slavonski Brod', - 'Shchuchinsk', - 'Lapa', - 'Cleveland Heights', - 'Pakxan', - 'Batroun', - 'Shahhat', - 'Kutum', - 'Nimule', - 'Jedeida', - 'Baba I', - 'Mlada Boleslav', - 'Rabinal', - 'Mahalingpur', - 'Bhayala', - 'Nalegaon', - 'Muddebihal', - 'Kedgaon', - 'Sachin', - 'Alamuru', - 'Qarabulaq', - 'Dig', - 'Hekou', - 'Tank', - 'Naestved', - 'Barnagar', - 'Brianka', - 'Marhanets', - 'Tres Valles', - 'Angadanan', - 'Timbo', - 'Acopiara', - 'Maria Aurora', - 'Gallatin', - 'Astaneh-ye Ashrafiyeh', - 'Yatagan', - 'Palm Springs', - 'Mount Laurel', - 'Seregno', - 'Pederneiras', - 'Catford', - 'Tarnobrzeg', - 'Port Loko', - 'Borlange', - 'Razgrad', - 'Charkhi Dadri', - 'Azarshahr', - 'Buguias', - 'Sagua de Tanamo', - 'Shangshan', - 'Shazhou', - 'Dois Vizinhos', - 'Guledagudda', - 'Al `Aziziyah', - 'Tateyama', - 'Bolivar', - 'Riverton', - 'West Lafayette', - 'Parigi', - 'Rameswaram', - 'Santiago Atitlan', - 'Meoqui', - 'Port Macquarie', - 'Lehrte', - 'Colotenango', - 'Nasipit', - '`Ayn al `Arab', - 'Barru', - 'Mochudi', - 'Merksem', - 'Falkensee', - 'Bruhl', - 'Santana do Paraiso', - 'Manjuyod', - 'Sao Lourenco', - 'Balcarce', - 'Jidd Hafs', - 'Pemangkat', - 'Zwijndrecht', - 'Chichigalpa', - 'Liuquancun', - 'Xique-Xique', - 'Cutler Bay', - 'Cascina', - 'Itaberai', - 'Worksop', - 'Salon-de-Provence', - 'San Pedro Perulapan', - 'Melur', - 'Terracina', - 'Lake Ridge', - 'Whitney', - 'Dhupgari', - 'Kafr al Battikh', - 'Sapanca', - 'Sete', - 'Pahrump', - 'Flores', - 'Yaopu', - 'Tangjiacun', - 'Soliman', - 'Katipunan', - 'Zamalka', - 'Bharella', - 'Kharan', - 'Zouerate', - 'Pyu', - 'Dowlaiswaram', - 'North Lauderdale', - 'Portugalete', - 'Dolores', - 'Conceicao do Araguaia', - 'Xiluo', - 'Jacaltenango', - 'Kitgum', - 'Sainthia', - 'Gogrial', - 'Mamanguape', - 'Grabouw', - 'Upper Bicutan', - 'Wentzville', - 'Istres', - 'Augusto Correa', - 'Tori-Bossito', - 'Alcamo', - 'Guisa', - 'Jangamguda', - 'Arboletes', - 'Cayambe', - 'Mawlaik', - 'Mantes-la-Jolie', - 'Piendamo', - 'Garca', - 'Fond du Lac', - 'Seferhisar', - 'Otwock', - 'Gori', - 'Nsawam', - 'Culasi', - 'Jalacingo', - 'Petatlan', - 'Shekhupur', - 'Masuda', - 'Tsiroanomandidy', - 'Wiener Neustadt', - 'Rohnert Park', - 'Ellenabad', - 'Banaybanay', - 'Mankato', - 'Moorhead', - 'Radomsko', - 'Morley', - 'Karvarakundu', - 'Sao Sebastiao do Passe', - 'Rapur', - 'Abu al Matamir', - 'Siyana', - 'Abovyan', - 'Angul', - 'Bacnotan', - 'Rajaldesar', - 'Robe', - 'Elmadag', - 'Tongoma', - 'Yaoquan', - 'Santo Antonio da Platina', - 'Sandefjord', - 'Bulalacao', - 'Dalli Rajhara', - 'Houbu', - 'Svishtov', - 'Nandigama', - 'Vlissingen', - 'Beigangwa', - 'San Juan y Martinez', - 'Eqlid', - 'Kolobrzeg', - 'Iwanuma', - 'Kaimana', - "Sao Miguel d'Oeste", - 'Pagsanjan', - 'Changtoushang', - 'The Colony', - 'Jisr ash Shughur', - 'Nanjo', - 'Deinze', - 'General Mamerto Natividad', - 'Cayeli', - 'Barwah', - 'Chauk', - 'Alapli', - 'Pinneberg', - 'Labangan', - 'Bom Conselho', - 'Drama', - 'Sonqor', - 'Medak', - 'Kaarst', - 'Talipparamba', - 'Huatan', - 'Manakara', - 'Iznik', - 'Jora', - 'Pattani', - 'Burke', - 'Loon', - 'Saint-Brieuc', - 'Ananipalle', - 'Erkelenz', - 'Majurwa', - 'Freeport', - 'Cateel', - 'Miliana', - 'Tiberias', - 'Maitum', - 'Regla', - 'El Centro', - 'Dikili', - 'Germencik', - 'Al `Ayyat', - 'Rio Grande da Serra', - 'Las Matas de Farfan', - 'Raisen', - 'Albufeira', - 'Harsin', - 'Turnhout', - 'Shakopee', - 'Central Signal Village', - 'Wilkes-Barre', - 'Mandaon', - 'West Vancouver', - 'Hagi', - 'Daijiazhuang', - 'Togo', - 'Tlajomulco de Zuniga', - 'Roghun', - 'Zevenaar', - 'Lompoc', - 'Hicksville', - 'Talatamaty', - 'Noordwijk', - 'Janakammapeta', - 'Oakland Park', - 'Lombard', - 'Otofuke', - 'Debica', - 'San Vicente de Tagua Tagua', - 'Guinayangan', - 'Al Midhnab', - 'Nocera Inferiore', - 'Murshidabad', - 'Senigallia', - 'Vilvoorde', - 'Boyabat', - 'Korogwe', - 'Ahmadpur', - 'Tinajdad', - 'Limache', - 'Seohara', - 'Yuchengcun', - 'Mucaba', - 'Coatbridge', - 'Tarbes', - 'New Tecumseth', - 'Casale', - 'Labason', - 'Yuanli', - 'Bakamune', - 'Goshikicho-aihara-minamidani', - 'Livramento de Nossa Senhora', - 'Comendador', - 'Ales', - 'Wankaner', - 'Loreto', - 'Wismar', - 'Chalons-en-Champagne', - 'Zongolica', - 'Etten-Leur', - 'Erkrath', - 'Addanki', - 'Hinatuan', - 'Wallsend', - 'Merthyr Tudful', - 'Yirga `Alem', - 'Nidadavole', - 'Ciudad Constitucion', - 'Beni Saf', - 'Xinjun', - 'Baler', - 'Bellinzona', - 'Varazdin', - 'Anekal', - 'Azadshahr', - 'Jaro', - 'Bietigheim-Bissingen', - 'Sugito', - 'Salto de Pirapora', - 'Himi', - 'Lubuk Sikaping', - 'Shyorongi', - 'Zabki', - 'Badian', - 'Thun', - 'Murzuq', - 'Kottangara', - 'Pittsfield', - 'Venray', - 'Kalilangan', - 'North Brunswick', - 'Takab', - 'Cameron Highlands', - 'Bushenyi', - 'Mastaga', - 'Bagneux', - 'Porsa', - 'Bodupal', - 'Krasnodon', - 'Tanghin-Dassouri', - 'Alhaurin de la Torre', - 'Puteaux', - 'Ramachandrapuram', - 'Greenacres', - 'Chembra', - 'Gifhorn', - 'Jinku', - 'Shinshiro', - 'Nijkerk', - 'Roseller Lim', - 'Villeta', - 'Caluire-et-Cuire', - 'Kumatori', - 'Uruara', - 'Cove', - 'Guambog', - 'Prostejov', - "'Ain Arnat", - 'Zhexiang', - 'Presidente Epitacio', - 'Shoranur', - 'Ksar', - 'Rheden', - 'Oakley', - 'Panambi', - 'Kiraz', - 'Jerada', - 'Cimerak', - 'Of', - 'Ponte de Lima', - 'Cesme', - 'Borken', - 'Bahia Honda', - 'Linden', - 'Heinsberg', - 'Tarauaca', - 'Campbell', - 'Moises Padilla', - 'Paoskoto', - 'Al Kiswah', - 'Danville', - 'Pedro Celestino Negrete', - 'Toboso', - 'Kikuyo', - 'Kilosa', - 'Frosinone', - 'Bolvadin', - 'Anse Rouge', - 'Puerto del Rosario', - 'Actopan', - 'De Bilt', - 'Nilothi', - 'Dounan', - 'Trelleborg', - 'Yutiancun', - 'Isla', - 'Jambusar', - 'Xihuachi', - 'Sawakin', - 'Innisfil', - 'Turda', - 'Kozani', - 'Shinas', - 'Hueyapan de Ocampo', - 'El Cua', - 'General Pacheco', - 'Kottoppadam', - 'Douar Bni Malek', - 'El Asintal', - 'Villa de Zaachila', - 'Zhongbu', - 'Lota', - 'Andes', - 'North Miami Beach', - 'Vaudreuil-Dorion', - 'Clermont', - 'Silistra', - 'Vargem Grande', - 'San Sebastian Huehuetenango', - 'Aleksinac', - 'Konarak', - 'Paso de los Libres', - 'Ocozocoautla de Espinosa', - 'Mahallat', - 'Kula', - 'Khawr Fakkan', - 'San Bruno', - 'Ambasamudram', - 'Veroia', - 'Laurel', - 'Yeola', - 'Nagaizumi', - 'Channelview', - 'Vahdat', - 'Shanshan', - 'South Upi', - 'Trujillo Alto', - 'Kapan', - 'Nagykanizsa', - 'Aguazul', - 'Darcheh', - 'Berchem', - 'Dock Sur', - 'Vergina', - 'San al Hajar al Qibliyah', - 'Sonaguera', - 'Baniyas', - 'Zhangliangcun', - 'Chicaman', - 'Cumaribo', - 'Maissade', - 'Khutubi', - 'Ormond Beach', - 'Rantepao', - 'Kayalpattanam', - 'Kobayashi', - 'Inabe', - 'Dun Dealgan', - 'Vargem Grande do Sul', - 'Sidcup', - 'Macenta', - 'Et Taiyiba', - 'Bakau', - 'Nettetal', - 'Taketoyo', - 'Huber Heights', - 'Rudauli', - 'Tesanj', - 'Dunakeszi', - 'Makinohara', - 'Kamen', - 'Alcantarilla', - 'Bron', - 'Yatomi', - 'Barhiya', - 'Woonsocket', - 'Kattivakkam', - 'Kingston upon Thames', - 'Jesus Maria', - 'Gualeguay', - 'Hillsborough', - 'Garbahaarrey', - 'Saoner', - 'Reze', - 'Yepocapa', - 'Valenciennes', - 'Abucay', - 'Periyakulam', - 'Cuchi', - 'Lai Chau', - 'Middleton', - 'Aurich', - 'Chateauroux', - 'Jatibonico', - 'Heist-op-den-Berg', - 'Santo Antonio', - 'San Cristobal Totonicapan', - 'Nandongcun', - 'Nandazhang', - 'Buffalo Grove', - 'Badulla', - 'Akdagmadeni', - 'Char Fasson', - 'Zhangcun', - 'Bairagnia', - 'Sevanagala', - 'Pirthipur', - 'Bradford West Gwillimbury', - 'Tepalcatepec', - 'Villaba', - 'Shimabara', - 'Mahbubabad', - 'Garges-les-Gonesse', - 'Fleet', - 'Kalaiya', - 'Longtoushan Jiezi', - 'Puerto Colombia', - "King's Lynn", - 'Salaberry-de-Valleyfield', - 'Chefchaouene', - 'Laguna', - 'La Mata', - 'West Babylon', - 'Ban Pet', - 'Nueva Valencia', - 'Al Badari', - 'Limbdi', - 'Catonsville', - 'Barreiros', - 'Atenco', - 'Mrirt', - 'Itarema', - 'Altadena', - 'Bukama', - 'Naranjo', - 'Ciechanow', - 'Edmonds', - 'Lokeren', - 'Gravina in Puglia', - 'Linton Hall', - 'Thol', - 'Spanish Fork', - 'Hammam Sousse', - 'Newnan', - 'Sarikamis', - 'Taniyama-chuo', - 'Musina', - 'Orlandia', - 'Meru', - 'Laatzen', - 'Castres', - 'Proper Bansud', - 'Quinhamel', - 'Vineyard', - 'Evere', - 'Mengdong', - 'Cabo Bojador', - 'Kafr al Kurdi', - 'Barpeta', - 'Jefferson City', - 'Webuye', - 'Miranda', - 'Kharik', - 'Sidi Mohamed Lahmar', - 'Mondoro', - 'El Affroun', - 'Sukheke Mandi', - 'Manassas', - 'Tecoanapa', - 'Biella', - 'Zharkent', - 'Puyallup', - 'San Francisco Menendez', - 'Fianga', - 'Arras', - 'Sibenik', - 'Awaji', - 'Salar', - 'Nyunzu', - 'Hwange', - 'Simao Dias', - 'Shuilou', - 'Vera Cruz', - 'Machali', - 'Mata de Sao Joao', - 'Panitan', - 'Jose de Freitas', - 'Thomassique', - 'Jajpur', - 'Sokoura', - 'Tamu', - 'Uruacu', - 'Alluru', - 'Schertz', - 'Guarda', - 'Amberg', - 'Maroantsetra', - 'Balabac', - 'El Charco', - 'Loufan', - 'Kadalur', - 'Coppell', - 'Itapa-Ekiti', - 'Mariel', - 'North Fort Myers', - 'San Giorgio a Cremano', - 'Jambughoda', - 'Dupnitsa', - 'Bairuo', - 'La Orotava', - 'Moline', - 'Seevetal', - 'Karsiyang', - 'Dilbeek', - 'Tucuran', - 'Singhanakhon', - 'Sanarate', - 'Carranglan', - 'San Rafael del Sur', - 'Beverly', - 'Eisenach', - 'Si Sa Ket', - 'Xidiancun', - 'Bassano del Grappa', - 'Bang Kruai', - 'Bhatpalli', - 'Alghero', - 'Balykchy', - 'Melun', - 'Kotabumi', - 'Sao Mateus do Sul', - 'Than', - 'Acatlan de Perez Figueroa', - 'Laungowal', - 'Akaiwa', - 'Shenjiatun', - 'Annandale', - 'Yaguate', - "Qa'en", - 'Ben Zakkay', - 'Rouyn-Noranda', - 'Tome', - 'Iten', - 'Xonobod', - 'Pallisa', - 'Homburg', - 'Kasai', - 'Llanera', - 'Futtsu', - 'Coachella', - 'Coronel Suarez', - 'Alerce', - 'Polanco', - 'Dreieich', - 'Maniwa', - 'Kutno', - 'Hoddesdon', - 'Myanaung', - 'Marki', - 'Akbarpur', - 'President Quirino', - 'Woodlawn', - 'Viborg', - 'Palladam', - 'Uozu', - 'Ansbach', - 'Hilvan', - 'Liloy', - 'Fareham', - 'Meadow Woods', - 'Karmegh', - 'Aritao', - 'Smederevska Palanka', - 'Sarakhs', - 'Coram', - 'Qapshaghay', - 'Jocotepec', - 'Thionville', - 'Amontada', - 'Nysa', - 'Morarano Chrome', - 'Peachtree Corners', - 'Liantang', - 'Angelholm', - 'Anakaputtur', - 'Diyadin', - 'Cortlandt', - 'Dildarnagar', - 'Jinotepe', - 'Pardes Hanna Karkur', - 'Hollister', - 'Villa Bisono', - 'Sbiba', - 'Bensheim', - 'Pratapgarh', - 'Bokhtar', - 'Coyuca de Catalan', - 'Puerto Real', - 'Paraiba do Sul', - 'Guaratuba', - 'Quesada', - 'Imperia', - 'Soran', - 'Sarab', - 'Guaraciaba do Norte', - 'Zhovti Vody', - 'Siegburg', - 'Tineghir', - 'Madridejos', - 'Mampong', - 'San Jose de Bocay', - 'Miercurea-Ciuc', - 'Holly Springs', - 'Wangyuanqiao', - 'Nathdwara', - 'Dronten', - 'Pachkhal', - 'Tinpiple', - 'Santa Rosa del Sur', - 'Stip', - 'Myedu', - 'Songhuajiangcun', - 'Qiryat Mozqin', - 'Lingquan', - 'Muttayyapuram', - 'Vawkavysk', - 'Greenock', - 'Matnog', - 'Sao Lourenco do Sul', - 'Naikankudi', - 'Puerto Galera', - 'Zhujiacun', - 'Yangcunzai', - 'Yagoua', - 'Nuevo San Carlos', - 'Hodmezovasarhely', - 'Tactic', - 'Delaware', - 'Ho Nai', - 'Santa Maria Atzompa', - 'Tiel', - 'Oizumi', - 'Kirchheim unter Teck', - 'Tororo', - 'Minamishimabara', - 'Amadeo', - 'Qiryat Ono', - 'Schwabisch Hall', - 'Kibawe', - 'Ban Wat Lak Hok', - 'Larantuka', - 'Barauli', - 'Dunaujvaros', - 'Beverwijk', - 'Macaubas', - 'Kalmar', - 'Marialva', - 'Coburg', - 'Yinggen', - 'Tadjenanet', - 'El Aioun', - 'Urmston', - 'Coyotepec', - 'Miura', - 'Rancho Palos Verdes', - 'Diamond Harbour', - 'Waxahachie', - 'Jardinopolis', - 'Civitanova Marche', - 'Tadif', - 'Koniz', - 'Uden', - 'Surampatti', - 'Velasco Ibarra', - 'Kasibu', - 'Paicandu', - 'Beitbridge', - 'Dacun', - 'Narayanpet', - 'Torres', - 'El Consejo', - 'Boucherville', - 'Fenoarivo Atsinanana', - 'Saidpur Dabra', - 'Shadegan', - 'Danderesso', - 'Bodo', - 'Alimos', - 'Campechuela', - 'Otavalo', - 'Tavas', - 'Varash', - 'Oued Fodda', - 'Billerica', - 'Tolosa', - 'Kampong Chhnang', - 'Wunstorf', - 'Hempfield', - 'Boumerdes', - 'Pueblo Nuevo', - 'Gonzaga', - 'Litian Gezhuang', - 'Blanes', - 'Bayt al Faqih', - 'Mableton', - 'Jaltipan de Morelos', - 'Prerov', - 'Fitchburg', - 'Kenge', - 'Daram', - 'Ambohitrimanjaka', - 'Yuzawa', - 'Oqtosh Shahri', - 'Shefar`am', - 'Le Cannet', - 'Berubari', - 'Ayagoz', - 'Bullhead City', - 'Su-ngai Kolok', - 'Rajgir', - 'Socorro', - 'Santa Cruz de Los Taques', - 'Shetou', - 'Sipe Sipe', - 'San Pedro Necta', - 'Dubrovnik', - 'Santa Helena', - 'Lloret de Mar', - 'Indi', - 'Amuntai', - 'Rajaori', - 'Slobozia', - 'Lindi', - 'Aguas Belas', - 'Patulul', - 'Yarumal', - 'Copan', - 'Tagudin', - 'San Dona di Piave', - 'Nalhati', - 'Ruteng', - 'Ventanas', - 'Sanand', - 'Puntarenas', - 'Bourg-en-Bresse', - 'Puerto Gaitan', - 'Barra dos Coqueiros', - 'Poti', - 'Shimotsuma', - 'Konigswinter', - 'Zugdidi', - 'Kodinar', - 'Sagauli', - 'Golaghat', - 'Pileru', - 'Sutton', - 'Marlboro', - 'Sinanpasa', - 'Llavallol', - 'Desio', - 'Nola', - 'Eberswalde', - 'Memari', - 'Bani Suhayla', - 'Tabogon', - 'Teaneck', - 'Svay Rieng', - 'Grove City', - 'Arcos', - 'Lusambo', - 'Mondragon', - 'Yakacik', - 'Maplewood', - 'Kendraparha', - 'Villa Angela', - 'Nurtingen', - 'Caerphilly', - 'Marion', - 'Nebbi', - 'Marlborough', - 'Tortuguitas', - 'San', - 'Naini Tal', - 'Erzin', - 'Maulavi Bazar', - 'Bambari', - 'Germering', - 'Kitaibaraki', - 'Sena Madureira', - 'Tuchin', - 'Narathiwat', - 'Brookfield', - 'Obita', - 'Nordhausen', - 'Tezoyuca', - 'Ramganj Mandi', - 'El Tocuyo', - 'Santo Antonio de Padua', - 'Nurdagi', - 'Currais Novos', - 'Mahalapye', - 'Meiganga', - 'Arauquita', - 'Huckelhoven', - 'Tabarka', - 'Caloundra', - 'Alcalde Diaz', - 'Bridgwater', - 'Leigh', - 'Jayamkondacholapuram', - 'Cherupulassheri', - 'Mikolow', - 'Guacimo', - 'Hatfield', - 'Wijchen', - 'Panchimalco', - 'Mersa', - 'Niquero', - 'Chaves', - 'Fredericia', - 'Rozzano', - 'French Valley', - 'Santa Eulalia del Rio', - 'Schwabach', - 'Schweizer-Reineke', - 'Maayon', - 'Lasam', - 'Mangaratiba', - 'Bacong', - 'Constitucion', - 'Shelton', - 'Tuquerres', - 'Nossa Senhora da Gloria', - 'Trikarpur North', - 'Shutayil', - 'Agar', - 'San Jose de Urquico', - 'Tanxia', - 'Zakynthos', - 'Antequera', - 'Claypole', - 'Pine Bluff', - 'Peddapalli', - 'Igualada', - 'Kearny', - 'Villa Alsina', - 'Anglet', - 'Geel', - 'Bilasipara', - 'Timmins', - 'Halfeti', - 'Guaduas', - 'Toritama', - 'Matiguas', - 'Palia Kalan', - 'Jose Marmol', - 'Halol', - 'Ganta', - 'Kallar', - 'Hallandale Beach', - 'Mambajao', - 'Huizen', - 'Angouleme', - 'Ardesen', - 'Sevilla de Niefang', - 'Rivas', - 'Ambositra', - 'Newbury', - 'Merano', - 'Bujanovac', - 'Komoro', - 'Ishaka', - 'Sumoto', - 'Tagbina', - 'Amami', - 'Pozi', - 'Arraijan', - 'Tampakan', - 'Unzen', - 'Ciudad Dario', - 'Bazar-Korgon', - 'Ciudad Vieja', - 'Upper Hutt', - 'Gatunda', - 'Sarande', - 'Dongyangshi', - 'Shengaocun', - 'Dongluocun', - 'Chambas', - 'Welling', - 'Woburn', - 'Beigang', - 'Hongfengcun', - 'Wujie', - 'Monterotondo', - 'Patti', - 'Esperantina', - 'Marikina Heights', - 'Paranaiba', - 'Drogheda', - 'Bagua Grande', - 'Nanbei', - 'Dowlatabad', - 'Maddela', - 'Lijiaxiang', - 'Reynoldsburg', - 'Yingzhou Linchang', - 'Covington', - 'Salinopolis', - 'Azemmour', - 'Famagusta', - 'Buxtehude', - 'Ciudad Piar', - 'Dhamdaha', - 'Boulogne-sur-Mer', - 'Muana', - 'Velika Plana', - 'Delijan', - 'Jalalpur Bhattian', - 'Friendswood', - 'Talukkara', - 'Meftah', - 'Penn Hills', - 'Betun', - 'Apostoles', - 'Weslaco', - 'Malilipot', - 'Patzicia', - "Land O' Lakes", - 'Essex', - 'Talcher', - 'Soe', - 'Wattrelos', - 'Cuito Cuanavale', - 'Promissao', - 'Anyuan', - 'Qadian', - 'Fourou', - 'Mobo', - 'Pamban', - 'Abadan', - 'Buchholz in der Nordheide', - 'Neumarkt', - 'Ahlat', - 'Saint-Germain-en-Laye', - 'Kitob', - 'Temsia', - 'Vallehermoso', - 'Swords', - 'Vavveru', - 'Elmali', - 'Gonabad', - 'Sidi Moussa', - 'Baichigan', - 'Lobo', - 'Sassuolo', - 'Kingswood', - 'Pie de Pato', - 'Buddh Gaya', - 'Shanhe', - 'Kato', - 'Kirkkonummi', - 'Khowrmuj', - 'Annapolis', - 'Villafranca del Panades', - 'Arys', - 'Ipiau', - 'Dunstable', - 'DeKalb', - 'Vasto', - 'Mambusao', - 'Maragondon', - 'Cedar Falls', - 'Pirmasens', - 'Itabaianinha', - 'Qeshm', - 'Tomar', - 'Sukuta', - 'Kadur', - 'Sint-Truiden', - 'Mundakkal', - 'Sherghati', - 'Nanuque', - 'Veles', - 'Bury Saint Edmunds', - 'Zoumi', - 'Avezzano', - 'Artigas', - 'Ladispoli', - 'Barra de Sao Francisco', - 'Dayr Mawas', - 'Manalapan', - 'Santa Rita do Sapucai', - 'Nabas', - 'Akyurt', - 'Evren', - 'Yangtangxu', - 'Yatangcun', - 'Njombe', - 'Douar Laouamra', - 'Samkir', - 'Porto de Moz', - 'Lemgo', - 'Pilani', - 'Remanso', - 'Siay', - 'Bayindir', - 'Santa Maria da Boa Vista', - 'Metlili Chaamba', - 'Bayburt', - 'Olgiy', - 'Bosconia', - 'Janjgir', - 'Romblon', - 'Andradas', - 'Katsuren-haebaru', - 'Lordegan', - "Villenave-d'Ornon", - 'Gap', - 'Macerata', - 'Cumbal', - 'Guariba', - 'Freiberg', - 'Erramvaripalem', - 'Corigliano Calabro', - 'Minsk Mazowiecki', - 'Crystal Lake', - 'Halberstadt', - 'Lake Oswego', - 'Severna Park', - 'Pilate', - 'Krishnarajasagara', - 'Leinfelden-Echterdingen', - 'Lakeshore', - 'Ramsgate', - 'Findlay', - 'Marakkara', - 'Huaura', - 'Aracataca', - 'Channarayapatna', - 'Montelimar', - 'Leyte', - 'Compiegne', - 'New Berlin', - 'Palampur', - 'Agano', - 'Hofheim', - 'Reguiba', - 'Almenara', - 'Jhabua', - 'Stains', - 'Vellakkovil', - 'Culver City', - 'Bouar', - 'Beyneu', - 'Curuca', - 'Balaoan', - 'La Union', - 'Rubengera', - 'Sabalgarh', - 'Sensuntepeque', - 'Molina', - 'Komono', - 'Kualaserba', - 'Indian Trail', - 'Romny', - 'Magburaka', - 'Hellevoetsluis', - 'Payabon', - 'Colinas', - 'Ampana', - 'Murtajapur', - 'Peringalam', - 'Autazes', - 'Ozu', - 'Duncanville', - 'Valley Stream', - 'Yajalon', - 'Karditsa', - 'Lohne', - 'Pinamar', - 'Tosya', - 'Ahaus', - 'Afogados da Ingazeira', - 'Majibacoa', - 'Hidirbey', - 'Fonds Verrettes', - 'Clinton', - 'Camargo', - 'Merta', - 'Uttarkashi', - 'Boa Esperanca', - 'Swinoujscie', - 'Schorndorf', - 'Kabuga', - 'Leramatang', - 'Itoigawa', - 'Secunda', - 'El Golea', - 'Havza', - 'Volklingen', - 'Maihar', - 'Begamganj', - 'Gagny', - 'Pedra Branca', - 'Jambe', - 'Santa Quiteria', - 'Tiruchendur', - 'Mokolo', - 'Sejenane', - 'La Rinconada', - 'Myrhorod', - 'The Acreage', - 'Colomiers', - 'Malalag', - 'Balud', - 'Podilsk', - 'Torre Annunziata', - 'Dohazari', - 'Taysan', - 'Taicheng', - 'Gourcy', - 'Kilakkarai', - 'Kalimpong', - 'Cihuatlan', - 'Gramado', - 'Romeoville', - 'Oroqen Zizhiqi', - 'Dingras', - 'Heroica Ciudad de Tlaxiaco', - 'Phulwaria', - 'Sisak', - 'Luebo', - 'Jarvenpaa', - 'Chiredzi', - 'Soria', - 'Longtang', - 'Raxruha', - 'Kakrala', - 'Bragadiru', - 'Zagora', - 'Menghan', - 'Hurst', - 'Altagracia de Orituco', - 'Kunigal', - 'Mailapur', - 'Varkkallai', - 'Soavinandriana', - 'Curitibanos', - 'Montana', - 'Mayyanad', - 'Panaji', - 'Poissy', - 'Sieradz', - 'Inverness', - 'Armacao dos Buzios', - 'Oraiokastro', - 'Zacualpa', - 'Post Falls', - 'Ihnasya al Madinah', - 'Jbail', - 'Matsoandakana', - 'Bukit Gambir', - 'Bandhi', - 'Safdarabad', - 'Choa Saidan Shah', - 'Ranipur', - 'Lidkoping', - 'Kambia', - 'Uchqurghon Shahri', - 'Madinat `Isa', - 'Bamessing', - 'Alashankou', - 'Strood', - "L'Asile", - 'Chikodi', - 'Sindgi', - 'Wadegaon', - 'Sardulgarh', - 'Samalkha', - 'Junnar', - 'Salaiya', - 'Tazah Khurmatu', - 'Nicastro', - 'Hutchinson', - 'Kasumigaura', - 'Lishaocun', - 'Herstal', - 'Szigetszentmiklos', - 'Fushe Kosove', - 'Visoko', - 'Kyaukme', - 'Zimapan', - 'Yian', - 'Santa Cruz del Sur', - 'Jayrud', - 'Saraqib', - 'Vyshneve', - 'Xacmaz', - 'Qiryat Bialik', - 'Brcko', - 'Zhongbai', - 'Chelsea', - 'Santiago Nonualco', - 'Barcellona-Pozzo di Gotto', - 'Ngozi', - 'Acevedo', - 'Waipahu', - 'Lynnwood', - 'Yecapixtla', - 'Sagae', - 'Winslow', - 'Kish', - 'Koumra', - 'Zvolen', - 'Ramdurg', - 'Panglao', - "Braine-l'Alleud", - 'Tago', - 'Matias Romero', - 'Baco', - 'Pinhal', - 'Maintal', - 'Kopavogur', - 'Rauma', - 'Rovereto', - 'Lincoln Park', - 'Huamachuco', - 'Ostfildern', - 'Oshnaviyeh', - 'Villamontes', - 'Sebdou', - 'Amudalavalasa', - 'Fort Lee', - "'Ain el Melh", - 'Santo Nino', - 'Cape Girardeau', - 'Atmakur', - 'Yomitan', - 'Kirkagac', - 'Palauig', - 'Montclair', - 'Hobbs', - 'Toukountouna', - 'San Nicolas', - 'Carini', - 'Benenitra', - 'Aizawa', - 'Massawa', - 'Tivaouane', - 'Maarssen', - 'Draguignan', - 'Shirone', - 'Surin', - 'Alimodian', - 'Albano Laziale', - 'Kurobeshin', - 'Cantu', - 'Veruela', - "Pomigliano d'Arco", - 'Caraga', - 'Burjasot', - 'Tianzhong', - 'Ettlingen', - 'Buldon', - 'Masaki', - 'Temascal', - 'Oshakati', - 'Talacogon', - 'Srebrenik', - 'Tabas', - 'Kovvur', - 'Libano', - 'Fonseca', - 'Carol Stream', - 'Plant City', - 'Xisa', - 'Douai', - 'Todos Santos Cuchumatan', - 'Wageningen', - 'Nakama', - 'Ninove', - 'Yomra', - 'Capelinha', - 'Aventura', - 'Despatch', - 'Basudebpur', - 'Charbagh', - 'Parnu', - 'Tafi Viejo', - 'Vendrell', - 'Samaxi', - 'Huanghuajie', - 'La Troncal', - 'Isfisor', - 'Villa del Carbon', - 'Skovde', - 'Manay', - 'Chachoengsao', - 'Villa de San Diego de Ubate', - 'Jordan', - 'Freital', - 'Djidian Kenieba', - 'Salcedo', - 'Ihosy', - 'Streamwood', - 'Jiaozishan', - 'Tucuma', - 'Fondi', - 'Kalingalan Caluang', - 'Duba', - 'Ecija', - 'Mount Juliet', - 'Fariman', - 'Sao Goncalo dos Campos', - 'Nova Vicosa', - 'Virreyes', - 'Media', - 'Ossining', - 'La Tebaida', - 'Itapolis', - 'Lilio', - 'Pachrukha', - 'Brant', - 'Siniloan', - 'Dogansehir', - 'San Jose de Ocoa', - 'San Giuliano Milanese', - 'Marratxi', - 'Asamankese', - 'Kalu Khan', - 'Lalganj', - 'Qiryat Yam', - 'Plasencia', - 'Presidente Venceslau', - 'Whanganui', - 'Xonqa', - 'Issaquah', - 'Sanjiang', - 'Parkland', - 'Guajara-Mirim', - 'Olintepeque', - 'Khachrod', - 'Zyrardow', - 'Badepalli', - 'Sijua', - 'Park Ridge', - 'Bagnolet', - 'Kaffrine', - 'Clarin', - 'Marcq-en-Baroeul', - 'Spruce Grove', - 'Placilla de Penuelas', - 'Seram', - 'Gradacac', - 'Vadasinor', - 'Abrantes', - 'Amambai', - 'Naranjal', - 'Damulog', - 'Jacarezinho', - 'Puerto Berrio', - 'Cocorote', - 'Cesano Maderno', - 'Sadiola', - 'Cacuso', - 'Tangpingcun', - 'Marovoay', - 'Istog', - 'Neu Isenburg', - 'Nueva Santa Rosa', - 'Niederkassel', - 'Jogbani', - 'Galkot', - 'Chojnice', - 'Cottage Grove', - 'Guaira', - 'Takikawa', - 'Bell Gardens', - 'Oliveira', - 'Matinhos', - 'Rio Negrinho', - 'Taraza', - 'Solan', - 'Hailakandi', - 'Al Qa`idah', - 'Magra', - 'Apan', - 'Tamba-Sasayama', - 'Erattukulakkada', - 'Koycegiz', - 'Yuzhnoukrainsk', - 'Langen', - 'Ospino', - 'Ayirapuram', - 'San Gabriel', - 'Playa Vicente', - 'Heemskerk', - 'Kampot', - 'Axochiapan', - 'Androka', - 'Guemar', - 'Baikonur', - 'Visconde do Rio Branco', - 'Cacocum', - 'Masamba', - 'Marcos Paz', - 'Mibu', - 'Bayanan', - 'Security-Widefield', - 'Iesi', - 'Manggar', - 'Mettmann', - 'Grants Pass', - 'Ilmenau', - 'Cakung', - 'Keizer', - 'Idangansalai', - 'Ciftlikkoy', - 'Ait Ourir', - 'Stendal', - 'Agoncillo', - 'Chittaranjan', - 'Sual', - 'Penfield', - 'Moatize', - 'Roy', - 'Nueva Rosita', - 'Susurluk', - 'Pirna', - 'Huanren', - 'Naron', - 'Partapnagar', - 'Sidi Bibi', - 'Weissenfels', - 'Lluchmayor', - 'Revelganj', - 'Torre-Pacheco', - 'Marinha Grande', - 'Sebekoro', - 'Camana', - 'Mitsuke', - 'Kaseda-shirakame', - 'Amla', - 'Toumodi', - 'Ambatomainty', - 'Al Malikiyah', - 'Trofa', - 'Ramallah', - 'Bettendorf', - 'Cleethorpes', - 'Nuevitas', - 'Betamcherla', - 'Ciudad Melchor Muzquiz', - 'Ancud', - 'Sidi Khaled', - 'Gornji Milanovac', - 'Varzea Alegre', - 'Nongzhangjie', - 'Tromso', - 'Pala Oua', - 'San Fernando de Henares', - 'Sciacca', - 'La Chaux-de-Fonds', - 'Gabaldon', - 'Nabaruh', - 'Goes', - 'Mafamude', - 'Sao Fidelis', - 'Sao Raimundo Nonato', - 'Dibaya-Lubwe', - 'Nallur', - 'Galeana', - 'Konigs Wusterhausen', - 'Yangfang', - 'Brumadinho', - 'Staoueli', - 'Penumur', - 'Westerville', - 'Caluya', - 'Walajapet', - 'Huangyoutang', - 'Garalo', - 'Changchunpu', - 'Juan Rodriguez Clara', - 'San Raimundo', - 'Tuvagudi', - 'Empalme', - 'Draa el Mizan', - 'Cabugao', - 'Higashimatsushima', - 'Xiwanzi', - 'Royal Palm Beach', - 'Dwarka', - 'Haverstraw', - 'Birmitrapur', - 'Apache Junction', - 'Pehowa', - 'Inashiki', - 'Taskopru', - 'Saryaghash', - 'Akcakoca', - 'Tshela', - 'Hitachiomiya', - 'Sao Mateus do Maranhao', - 'Navarre', - 'Ngororero', - 'Ain Tedeles', - 'Wheeling', - 'Ohrid', - 'Lake Stevens', - 'Skelmersdale', - 'Santa Helena de Goias', - 'Nurpur', - 'Rexburg', - 'Ermezinde', - 'Omagari', - 'Dubbo', - 'Nykoping', - 'Mehidpur', - 'Tipton', - 'Lambarene', - 'Campina Grande do Sul', - 'Ban Bang Khu Lat', - 'Eccles', - 'Gujo', - 'Fasano', - 'Urbana', - 'Aborlan', - 'Penalva', - 'Los Palacios', - 'Yoshinogawa', - 'Villepinte', - 'Ouro Branco', - 'Rosenberg', - 'Tinnanur', - 'Dzhankoi', - 'Barbacoas', - 'Cajibio', - 'Los Palacios y Villafranca', - 'Pinner', - 'Monreale', - 'Taibao', - 'Great Yarmouth', - 'Paracuru', - 'Yako', - 'Real', - 'Sakuragawa', - 'Kwai Chung', - 'Vetapalem', - 'Jamindan', - 'Kamp-Lintfort', - 'Margosatubig', - 'Tonbridge', - 'Zacatelco', - 'West Fargo', - 'Paravurkambolam', - 'Tuusula', - 'Povazska Bystrica', - 'Ilkeston', - 'Voghera', - 'Armavir', - 'Metlaoui', - 'San Jose de Las Matas', - 'Abrego', - 'La Presa', - 'Dabola', - 'Kampung Baharu Nilai', - 'Menomonee Falls', - 'Vengat', - 'Santa Maria da Vitoria', - 'Arucas', - 'Vestavia Hills', - 'Calexico', - 'Wurselen', - 'Ciampino', - 'Valrico', - 'Aketi', - 'Koge', - 'Schio', - 'Leyland', - 'Ibusuki', - 'Champerico', - 'Leribe', - 'Papenburg', - 'La Vergne', - 'Ban Na Pa', - 'Sungandiancun', - 'Vangaindrano', - 'Strangnas', - 'Achaguas', - 'Khalkhal', - 'Aziylal', - 'Glenrothes', - 'Alingsas', - 'Santa Clara del Cobre', - 'Barda', - 'Kline', - 'Rajula', - 'Atlantic City', - 'Caibarien', - 'Nishiwaki', - 'Sarikishty', - 'Al Ghizlaniyah', - 'San Felipe Orizatlan', - 'Ingeniero Pablo Nogues', - 'Emir Abdelkader', - "Saint-Martin-d'Heres", - 'Coto Brus', - 'Mahadeopur', - 'Chartres', - 'Szczecinek', - 'Minas', - 'Saronno', - 'Olutanga', - 'Lanyi', - 'Genc', - 'Buug', - 'Chorley', - 'Chacabuco', - 'Peachtree City', - 'Phenix City', - 'Sibate', - 'Melmadai', - 'Buchireddipalem', - 'Shijiazhuangnan', - 'Hammam-Lif', - 'Qiaotouyi', - 'Daraw', - 'DeLand', - 'Herne Bay', - 'Vredenburg', - 'Kaka', - 'Fribourg', - 'Miyoshidai', - 'Nindiri', - 'Bougara', - 'Misawa', - 'Atamyrat', - 'Waregem', - 'Ripollet', - 'Xiaguanying', - 'Marcianise', - 'Steyr', - 'Patnongon', - 'Mechanicsville', - 'Itaitinga', - 'Novo Horizonte', - 'Wilrijk', - 'Nigel', - 'Bayan', - 'Sarkisla', - 'Chuangjian', - 'Khairtal', - 'Mmabatho', - 'Iturama', - 'Azzano', - 'Stanton', - 'Maule', - 'Laur', - 'Taki', - 'Am-Timan', - 'Siyang', - 'Maibara', - 'Antsohihy', - 'Xiushui', - 'Ibara', - 'Barrancas', - 'Matale', - 'Brasschaat', - 'Bat Khela', - 'Citta di Castello', - 'Dicle', - 'Menglie', - 'Pitangueiras', - 'Holyoke', - 'Greven', - 'Winter Springs', - 'Americo Brasiliense', - 'Bishops Stortford', - 'Xico', - 'Mechelen-aan-de-Maas', - 'Wesseling', - 'Borbon', - 'Joue-les-Tours', - 'Naushahro Firoz', - 'Porur', - 'Pallipram', - 'Tayasan', - 'Zacualtipan', - 'Kehl', - 'Fereydun Kenar', - 'Karuvambram', - 'Matozinhos', - 'Choybalsan', - 'Bautzen', - 'Owasso', - 'Prattville', - 'Cananea', - 'East Point', - 'Campbell River', - 'Navgilem', - 'Vavuniya', - 'Quba', - 'Entre Rios', - 'Shankarpur Khawas', - 'Shengang', - 'Veghel', - 'Sabang', - 'Clifton Park', - 'Savelugu', - 'Thakraha', - 'Mapandan', - 'Prokuplje', - 'Mantingan', - 'Pacifica', - 'Bangar', - 'Dubrajpur', - 'Hot Springs', - 'Shambhunath', - 'Gudarah', - 'Aristobulo del Valle', - 'Zhongdong Shequ', - 'Rudsar', - 'Abu Qir', - 'Gurais', - 'San Pedro Jocopilas', - 'Bagabag', - 'Dengtangcun', - 'Sidi Yahia El Gharb', - 'Sama', - 'Tlapa de Comonfort', - 'Mucuri', - 'Olot', - 'Yamen', - 'Adelanto', - 'Backnang', - 'Princeton', - 'San Juan Cancuc', - 'Qaratog', - 'Northglenn', - 'Goribidnur', - 'Kenieran', - 'Ali Sabieh', - 'Tupelo', - 'Hajin', - 'Biougra', - 'La Quinta', - 'Urena', - 'Sampues', - 'San Adrian de Besos', - 'Annemasse', - 'Raalte', - 'Rusape', - 'Shakhtinsk', - 'Pedro II', - 'Bitterfeld', - 'Dhanera', - 'Guayacanes', - 'Obala', - 'Andkhoy', - 'Swidnik', - 'Giyon', - 'Luuk', - 'Celje', - 'Gampola', - 'Ameca', - 'Namlea', - 'Elmont', - 'Tlalixcoyan', - 'Cerveteri', - 'Dibulla', - 'Mission Bend', - 'Tumba', - 'Gaspar Hernandez', - 'Pen', - 'Bangkinang', - 'Mateus Leme', - 'Guira de Melena', - 'La Puente', - 'Santaluz', - 'Carpentersville', - 'Koboko', - 'Al Qaryatayn', - 'Emirdag', - 'Santa Pola', - 'Pentecoste', - 'Oleiros', - 'Cheyyar', - 'Pathanamthitta', - 'Mahanoro', - 'Kastel Stari', - 'Teijlingen', - 'Nove Zamky', - 'Tudela', - 'Ohangaron', - 'Patia', - 'Sillanwali', - 'San Antonio de Padua', - 'Charaut', - 'San Sebastian de Mariquita', - 'Kwidzyn', - 'Arnold', - 'Afua', - 'Marantao', - 'Long Eaton', - 'Prince Albert', - 'Guzelbahce', - 'Calpulalpan', - 'Karuhatan', - 'Manali', - 'Sun City', - 'Mixquiahuala de Juarez', - 'Mamun', - 'Haedo', - 'Coondapoor', - 'Hanumannagar', - 'Mombaca', - 'Gomoh', - 'Sao Francisco do Conde', - 'Matina', - 'San Marcelino', - 'Aklera', - 'Umi', - 'Apia', - 'Hilton Head Island', - 'Jacunda', - 'Melchor Ocampo', - 'Yoloten', - 'Mizunami', - 'Falavarjan', - 'Rawatbhata', - 'Satana', - 'Custodia', - 'Basavana Bagevadi', - 'Massape', - 'Galloway', - 'Vasylkiv', - 'Furstenfeldbruck', - 'Villagarcia de Arosa', - 'Basista', - 'Sanchahe', - 'Les Abricots', - 'Riviera Beach', - 'Venlo', - 'Tiete', - 'Coalville', - 'Huzurabad', - 'Yanqi', - 'Kolongo-Bozo', - 'Benjamin Constant', - 'Attingal', - 'Hatta', - 'Malbork', - 'Foothill Farms', - 'Bom Jardim', - 'Jeremoabo', - 'Taounate', - 'Warendorf', - 'Stirling', - "Su'ao", - 'Rio Brilhante', - 'Malavalli', - 'South Valley', - 'Salto del Guaira', - 'Lampa', - 'New Albany', - 'Sirinhaem', - 'Lewiston', - 'Boleslawiec', - 'Rio Branco do Sul', - 'Kranj', - 'Bamendjou', - 'Villaflores', - 'Dubno', - 'Mira', - 'Paraty', - 'Neuilly-sur-Marne', - 'Kahrizak', - 'Gabu', - 'Greenfield', - 'Franconville', - 'Bletchley', - 'Tuxpan', - 'Perote', - 'Atalaia', - 'Phonsavan', - 'El Bordo', - 'Allahabad', - 'Pokrov', - 'Baocheng', - 'Turiacu', - 'Ma`arratmisrin', - 'Itaqui', - 'Teboulba', - 'Don Benito', - 'Tambulig', - 'Bonito', - 'Leighton Buzzard', - 'Paracho de Verduzco', - 'Souma', - 'Tuttlingen', - 'Evans', - 'Pleasant Grove', - 'Oras', - 'Lovech', - 'Donji Kakanj', - 'Amargosa', - 'Cansancao', - 'Porteirinha', - 'Santa Rosa de Osos', - 'Samobor', - 'Sarangpur', - 'Sandur', - 'Kanigiri', - 'Kerou', - 'Oregon City', - 'Magallanes', - 'Gorinchem', - 'Ambatofinandrahana', - 'Trou du Nord', - 'Agudos', - 'Mabuhay', - 'Selcuk', - 'Jaito', - 'Savigny-sur-Orge', - 'Phulbani', - 'Progreso', - 'Bayur', - 'Tozeur', - 'Conchagua', - 'Grimbergen', - 'Becej', - 'Villa Gonzalez', - 'Eboli', - 'Mullaittivu', - 'Blyth', - 'Fengguangcun', - 'Beckum', - 'Besni', - 'Sitangkai', - 'Luna', - 'Ataq', - 'Bartlesville', - 'Al Hashimiyah', - 'Sanankoroba', - 'Lahar', - 'Falun', - 'Dajiecun', - 'Sao Manuel', - 'Pilibangan', - 'Tibu', - 'Mariano Escobedo', - 'Goygol', - 'Port Talbot', - 'Rock Island', - 'Landgraaf', - 'Ceska Lipa', - 'Lydenburg', - 'Gajendragarh', - 'Jale', - 'Yamoussoukro', - 'Paravur Tekkumbhagam', - 'Bouznika', - 'Jelilyuzi', - 'Mankayan', - 'Molndal', - 'Andilamena', - 'Katsuragi', - 'Melgar', - 'Kaman', - 'Hanover Park', - 'Vettur', - 'Comapa', - 'Salvatierra', - 'Rukungiri', - 'Leavenworth', - 'Mangai', - 'Moerdijk', - 'Chunar', - 'Wangsicun', - 'Tunzi', - 'Laindon', - 'Ratia', - 'Kadiyam', - 'Ciudad Manuel Doblado', - 'Minami-Boso', - 'Formia', - 'Silves', - 'Bantay', - 'Bahadurganj', - 'Imbatug', - 'Masyaf', - 'Obburdon', - 'Qulsary', - 'Adjumani', - 'Qo`ng`irot Shahri', - 'Binaqadi', - 'Languyan', - 'Boryslav', - 'Amarante do Maranhao', - 'Sittard', - 'Long Lama', - 'Kalutara', - 'Redcar', - 'Jagdispur', - 'Siribala', - 'Chorkuh', - 'Prijepolje', - 'Porsgrunn', - 'Cloppenburg', - 'Sitalkuchi', - 'Tokar', - 'Kalinkavichy', - 'Llanelli', - 'Pujali', - 'Kalihati', - 'Kampene', - 'Coesfeld', - 'Thonon-les-Bains', - 'Mol', - 'Holstebro', - 'Lagkadas', - 'Greer', - 'Suhl', - 'Bentota', - 'Mandoto', - 'Manazary', - 'Beeston', - 'Dargot', - 'Dachepalle', - 'Granadero Baigorria', - 'Tucker', - 'La Ciotat', - 'Pennsauken', - 'Baishi Airikecun', - 'Santiago Sacatepequez', - 'Dom Pedrito', - 'Stara Gora', - 'Nakodar', - 'Bucha', - 'Richmond West', - 'Nanshuicun', - 'Tabligbo', - 'Shaxi', - 'Oswiecim', - 'Lunavada', - 'Ban Doi Suthep', - 'Aourir', - 'Suhut', - 'Port-Margot', - 'Monatele', - 'Muskogee', - 'Campos Novos', - 'Guilderland', - 'Moalboal', - 'Dalkola', - 'Bindki', - 'Kankuria', - 'Chaiyaphum', - 'Netishyn', - 'Chimboy Shahri', - 'Basilisa', - 'San Enrique', - 'Segrate', - 'Vavur', - 'Pingxiangcheng', - 'Small Heath', - 'Grugliasco', - 'Penticton', - 'Dagua', - 'Claremont', - 'Manucan', - 'Siyabuswa', - 'Musiri', - 'Anosiala', - 'Aguilas', - 'Kearns', - 'East Meadow', - 'Pathri', - 'Faraskur', - 'Echirolles', - 'San Miguel Chicaj', - 'Nowa Sol', - 'Zuojiawu', - 'Pylaia', - 'Sagnay', - 'Kesavapuram', - 'Maddaloni', - 'Mahe', - 'Missao Velha', - 'Wildomar', - 'Caimito', - 'Erding', - 'Richfield', - 'Marijampole', - 'Ipueiras', - 'Agogo', - 'Elixku', - 'Qaladizay', - 'Uster', - 'Salima', - 'Camberley', - 'Kanie', - 'La Macarena', - 'Sayula', - 'Chatillon', - 'Tuensang', - 'Mulavana', - 'Kona', - 'Manoli', - 'Dargaz', - 'Koneurgench', - 'Lakshmeshwar', - 'Taxisco', - 'Vastervik', - 'Houghton le Spring', - 'Zira', - 'Wangtuan', - 'Tsubata', - 'Karamadai', - 'Torres Novas', - 'Mandaguari', - 'Esik', - 'Yasugicho', - 'Or Yehuda', - 'Enrile', - 'Michalovce', - 'Kambove', - 'Yovon', - 'Xinpo', - 'Anserma', - 'Robertsganj', - 'Esquel', - 'Beni Khiar', - 'Estero', - 'Ikongo', - 'Thana Bhawan', - 'Pande', - 'Risalpur Cantonment', - 'Sitakund', - 'Sorel-Tracy', - 'Lierre', - 'Ulan Hua', - 'Beloit', - 'Kulp', - 'Hojai', - 'Jose Bonifacio', - 'Matan', - 'Rosario do Sul', - 'Lajedo', - 'Belalcazar', - 'Esch-sur-Alzette', - 'Whitley Bay', - 'Las Navas', - 'Demirci', - 'Kannan', - 'Makan', - 'Kidangazhi', - 'Sinsheim', - 'Rossano', - "Mek'i", - 'Cantanhede', - 'Natick', - 'Schaffhausen', - 'Jaral del Progreso', - 'Sao Joao da Barra', - 'Ebebiyin', - '`Afrin', - 'Tunduma', - 'Dabutou', - 'Nemmara', - 'Chippenham', - 'Punarakh', - 'Barra do Choca', - 'Oakton', - 'Patamundai', - 'Bulicun', - 'Benapol', - 'Songo', - 'Horasan', - 'Central Islip', - 'Binde', - 'Sile', - 'Haomen', - 'Neiba', - 'Kodaikanal', - 'Dashtobod', - 'Mamfe', - 'Chelora', - 'Upper Arlington', - 'Knurow', - 'Berat', - 'Cambrils', - 'Nueve de Julio', - 'Zhetisay', - 'Ichchapuram', - 'West Bridgford', - 'Kaniama', - 'Bossangoa', - 'Guapiles', - 'Lecherias', - 'Sonson', - 'Arawa', - 'Mazidagi', - 'Zinzana', - 'Tocancipa', - 'Copperas Cove', - 'Rende', - 'Purna', - 'Liwonde', - 'Estahban', - 'Byumba', - "Anse d'Hainault", - 'Holubivske', - 'Simbahan', - 'Porta Westfalica', - 'Banaz', - 'Monaco', - 'Namakgale', - 'Maur', - 'Emsdetten', - 'Cegled', - 'Ratchaburi', - 'Sandanski', - 'Yahyali', - 'Fuchucho', - 'Borehamwood', - 'Barra Bonita', - 'Tomatlan', - 'Bjelovar', - 'Tooele', - 'Danihe', - 'Wolomin', - 'Tomelloso', - 'Jaroslaw', - 'San Juan Cotzal', - 'Mpessoba', - 'Kajaani', - 'Winsen', - 'Dinas', - 'Nargund', - 'Cabanglasan', - 'Oak Creek', - 'Cumberland', - 'Santiago Juxtlahuaca', - 'Kurtalan', - 'Spoleto', - 'Aketao', - 'Parappur', - 'Coatepec Harinas', - 'Yandian', - 'Melito di Napoli', - 'Teruel', - 'Kotma', - 'Prey Veng', - 'Tuntum', - 'San Miguel Acatan', - 'Beiya', - 'Siayan', - 'Muhlhausen', - 'Yorktown', - 'Modugno', - 'Capalonga', - 'Randallstown', - 'Athis-Mons', - 'Isla de Maipo', - 'Yejituo', - 'Merrillville', - 'Palapye', - 'Canaman', - 'Bollate', - 'Six-Fours-les-Plages', - 'Cuyotenango', - 'Goycay', - 'San Bernardo del Viento', - 'Gasan', - 'Voerde', - 'Mieres', - 'Onteniente', - 'Taastrup', - 'Ouled Beni Messous', - 'La Vallee de Jacmel', - 'Aparecida', - 'Madingou', - 'Dagami', - 'Kalaleh', - 'Nyaungdon', - 'Temple City', - 'Zacatepec', - 'Cisterna di Latina', - 'Boende', - 'Ban Mueang Na Tai', - 'Rapu-Rapu', - 'Carrollwood', - 'Nellaya', - 'Barira', - 'Petit-Trou de Nippes', - 'Pingshang', - 'Ewing', - 'Pestel', - 'Sareh Mowndeh', - 'Balarampuram', - 'Amancio', - 'Mingjian', - 'Kishmat Dhanbari', - 'Dinhata', - 'Dighwara', - 'Komatsushimacho', - 'Garhakota', - 'Meppen', - 'Guaimaro', - 'Lunsar', - 'Creil', - 'Hilliard', - 'Girau do Ponciano', - 'Chatelet', - 'Al Jabayish', - 'Frankston', - 'Apodi', - 'Gutalac', - 'Castricum', - 'Kamenice', - 'Berriozabal', - 'Sunbury', - 'El Plan', - 'East Kelowna', - 'Kanada', - 'Moorpark', - 'Maspalomas', - 'Piui', - 'Pioltello', - 'Limburg', - 'Sibuco', - 'Hillerod', - 'Tamamura', - 'Matanog', - 'Masasi', - 'Vempalle', - 'Wai', - 'Viru', - 'Bombardopolis', - 'Malpura', - 'Saparua', - 'Pihani', - 'Guayaramerin', - 'Bel-Air', - 'Zary', - 'Shirdi', - 'Ingelheim', - 'San Carlos Sija', - 'Vohipeno', - 'Ampasina-Maningory', - 'Mugumu', - 'Bugiri', - 'Farafenni', - 'Nim ka Thana', - 'Taloda', - 'Egypt Lake-Leto', - 'Ramsar', - 'Naduvattam', - 'Chekkal', - 'Krong Kep', - 'Farmers Branch', - 'Tlokweng', - 'Arroyomolinos', - 'Pandan', - 'Sarigol', - 'Seika', - 'Saint-Raphael', - 'Uto', - 'Tarikere', - 'Oued Athmenia', - 'Anloga', - 'Hellendoorn', - 'Rumonge', - 'Conflans-Sainte-Honorine', - 'Az Zahiriyah', - 'San Lorenzo de Guayubin', - 'Yangshuwa', - 'Lauderdale Lakes', - 'Villefranche-sur-Saone', - 'Mokokchung', - 'Chillum', - 'Majhaul', - 'Kakhovka', - 'Malmesbury', - 'Daiyue', - 'Hyde', - 'Dinangorou', - 'Partur', - 'Chieri', - 'Gorukle', - 'Meyzieu', - 'Santa Cruz Verapaz', - 'Hendon', - 'Caivano', - 'Dumbea', - 'Jalarpet', - 'Dar Chabanne', - 'Maragogipe', - 'Tirkadavur', - 'Olesnica', - 'Orangevale', - 'Falkirk', - 'Huzurnagar', - 'Sun Prairie', - 'Sainte-Genevieve-des-Bois', - 'Ampelokipoi', - 'Munro', - 'Jagna', - 'Agualva', - 'Pantnagar', - 'Cedar City', - 'Zaio', - 'Igarape-Acu', - 'Kattipparutti', - 'Taozhou', - 'Tambolaka', - 'Fermo', - 'Andujar', - 'Varberg', - 'La Porte', - 'Smarhon', - 'Commack', - 'Caltagirone', - 'Azogues', - 'Crailsheim', - 'Prestea', - 'Riverhead', - 'Bad Vilbel', - 'Kalakkadu', - 'Vavatenina', - 'Burriana', - 'Tam Hiep', - 'Alianca', - 'Nawan Shahr', - 'Pak Chong', - 'Leamington', - 'Guane', - 'Haguenau', - 'Kumo', - 'Camiri', - 'Norristown', - 'Calumet City', - 'South Miami Heights', - 'Vrsac', - 'Zefat', - 'Numancia', - 'Addison', - 'Ipora', - 'Macomia', - 'Collo', - 'Usuki', - 'Shiggaon', - 'Mahna', - 'Sosa', - 'Inver Grove Heights', - 'Graaff-Reinet', - 'Hole Narsipur', - 'Santiago de Tolu', - 'Camara de Lobos', - 'Miyajima', - 'Gurpinar', - 'Guacari', - 'El Mirage', - 'Goiatuba', - 'Chitapur', - 'Miranda de Ebro', - 'Port Shepstone', - 'Awa', - 'Al `Aqiq', - 'Aguelmous', - 'Setouchi', - 'Zhentang', - 'Walkden', - 'Chortoq', - 'Medchal', - 'Midvale', - 'Kendall West', - 'Casiguran', - 'Kenton', - 'Cha-am', - 'San Andres Itzapa', - 'Hoogvliet', - 'Narsampet', - 'Shangzhuangcun', - 'Isumi', - 'Uravakonda', - 'Savanur', - 'Yerkoy', - 'Bariri', - 'Niamina', - 'Freehold', - 'Pishin', - 'Sanok', - 'Sykies', - 'Rafiganj', - 'Aravankara', - 'Mahabo', - 'Pambujan', - 'Vitrolles', - 'Yangambi', - 'Sirohi', - 'Belluno', - 'Gahanna', - 'Lokbatan', - 'Savonlinna', - 'Olney', - 'Rifu', - 'Miahuatlan de Porfirio Diaz', - 'Guama Abajo', - 'Torrington', - 'Sahneh', - 'Udhampur', - 'Gigante', - 'Sungaiselam', - 'Kaneohe', - 'Villeneuve-Saint-Georges', - 'Coevorden', - 'North Ridgeville', - 'Umarga', - 'Ringsaker', - 'Hamirpur', - 'La Concordia', - 'Simiganj', - 'Cartagena del Chaira', - 'Woodley', - 'Cutral-Co', - 'Yayladagi', - 'Midlothian', - 'Tenes', - 'Accrington', - 'Pola', - 'Ofunato', - 'Lugoj', - 'Boca do Acre', - 'Tamuin', - 'Tallkalakh', - 'Sandino', - 'Savalou', - 'Spisska Nova Ves', - 'Ulliyil', - 'Fuquay-Varina', - 'Feijo', - 'Tomobe', - 'Lage', - 'Santuario', - 'Pinerolo', - 'Casalecchio di Reno', - 'Boyarka', - 'Dayr Hafir', - 'Kundian', - 'Zorgo', - 'Bou Noura', - 'Angra do Heroismo', - 'Aine Draham', - 'Pampatar', - 'Buhriz', - 'Bautista', - 'Ratnapur', - 'Baohezhuangcun', - 'Hamidiye', - 'Guskhara', - 'Samokov', - 'Morohongo', - 'Unnan', - 'Yongjing', - 'Rio Real', - 'Akcadag', - 'West Hollywood', - 'Pilao Arcado', - 'Dama', - 'Urgup', - 'La Palma', - 'Westmont', - 'Fruit Cove', - 'Timbuktu', - 'Kilimli', - 'Benton', - 'Saint-Benoit', - 'Conceicao de Jacuipe', - 'Villa Adelina', - 'Barra do Bugres', - 'Tahuna', - 'Yasynuvata', - 'Villa Ballester', - 'Juban', - 'Bedesa', - 'Kerava', - 'Morfelden-Walldorf', - 'Ciudad de Allende', - 'Cieza', - 'El Hajeb', - 'Chakapara', - 'Quimbaya', - 'Wildwood', - 'Surandai', - 'Goch', - 'Aizumi', - 'Diabali', - 'Bridlington', - 'Czechowice-Dziedzice', - 'Tangancicuaro de Arista', - 'Pansol', - 'Douglasville', - 'Chandanais', - 'Voznesensk', - 'Gandara', - 'San Javier', - 'Evergem', - 'Jieshang', - 'Azuqueca de Henares', - 'Allacapan', - 'Yecla', - 'Cento', - 'Zvishavane', - 'Roi Et', - 'Usilampatti', - 'Baturite', - 'Sankt Ingbert', - 'Kamata', - 'Bria', - 'Tilingzhai', - 'Springville', - 'Bou Salem', - 'Datteln', - 'Zaventem', - 'Praya', - 'Watertown Town', - 'Abra de Ilog', - 'Izki', - 'Bom Jesus do Itabapoana', - 'Perunad', - 'Deggendorf', - 'Billingham', - 'Aktuluk', - 'Hammam Bou Hadjar', - 'Barsinghausen', - 'Soteapan', - 'Mahasolo', - 'Sulop', - 'Giddalur', - 'Mananara Avaratra', - 'Lingig', - 'Jaguariaiva', - 'Pappinissheri', - 'Fair Oaks', - 'Tazhakara', - 'Manhattan Beach', - 'Ikalamavony', - 'Pandaul', - 'Adamantina', - 'Bibhutpur', - 'Qazax', - 'Steinfurt', - 'Rawatsar', - 'San Juan Capistrano', - 'Puerto Lopez', - 'Effia-Kuma', - 'Pulppatta', - 'Cassino', - 'Chrzanow', - 'Lebowakgomo', - 'Al Hisn', - 'Kherrata', - 'Confresa', - 'Saint-Chamond', - 'Balasan', - 'Vinces', - 'Umarkot', - 'Casilda', - 'Yellandu', - 'Suong', - "Ouro Preto d'Oeste", - 'Phatthalung', - 'Ieper', - 'Chur', - 'Tebesbest', - 'Guimbal', - 'San Luis de Since', - 'San Pedro de Ycuamandiyu', - 'Union de Reyes', - 'Munai', - 'Charqueadas', - 'Palotina', - 'Marancheri', - 'Kotah-ye `Ashro', - 'Maidan Shahr', - 'Wokha', - 'Prado', - 'Mannar', - 'Awbari', - 'Firavahana', - 'Fotadrevo', - "Ibra'", - 'Chakdarra', - 'Negotin', - 'Dulay` Rashid', - "Shaqra'", - 'Salkhad', - 'Tall Salhab', - 'Bagamoyo', - 'Magu', - 'Caucagua', - 'Guanta', - 'Maojiatang', - 'Cangxi', - 'Dikhil', - 'Winsford', - 'Bapaura', - 'Chiplun', - 'Harra', - 'Mel Nariyappanur', - 'Dulhanganj', - 'Al Hamdaniyah', - 'Shu', - 'Brugherio', - 'Owings Mills', - 'Pimenta Bueno', - 'Talanga', - 'Dimitrovgrad', - 'Oranjestad', - 'Maglaj', - 'Ngaoundal', - 'Mlimba', - 'Francavilla Fontana', - 'Padre Bernardo', - 'Cookeville', - 'Niquelandia', - 'Shenjiabang', - 'Camoapa', - 'Ez Zahra', - 'Kaizu', - 'Chipinge', - 'Payao', - 'Northbrook', - 'Karumattampatti', - 'At Turrah', - 'Fair Lawn', - 'Tenosique', - 'Foca', - 'Balingen', - 'Ypane', - 'Tarkwa', - 'Kahoku', - 'Tambe', - 'Ilhabela', - 'Esme', - 'Jiaoxi', - 'Lingsugur', - 'Dietzenbach', - 'Shiyali', - 'Iyo', - 'Campoalegre', - 'Nyamata', - 'Khodabandeh', - 'Tamura', - 'Slavuta', - 'Ekpe', - 'Posse', - 'Ikot Abasi', - 'Santa Cruz del Norte', - 'Juara', - 'Madukkarai', - 'Piskent', - 'Chatenay-Malabry', - 'Seiyo', - 'Palaiseau', - 'Jagodina', - 'Ouled Fares', - 'Ville Bonheur', - 'Mendez-Nunez', - 'Alandatte', - 'Ewell', - 'Vadigenhalli', - 'Aguai', - 'University City', - 'Cernusco sul Naviglio', - 'Sao Jose do Belmonte', - 'Kempen', - 'Hirakud', - 'Munnarkod', - 'Mannarakkat', - 'Galapagar', - 'Arsin', - 'Villajoyosa', - 'Dragash', - 'Naryn', - 'Allagadda', - 'Oswego', - 'Yarim', - 'Oildale', - 'Santa Fe do Sul', - 'Sansanne-Mango', - 'Limbiate', - 'Hammam Dalaa', - 'Khajamahalpur', - 'Uddevalla', - 'Auxerre', - 'Graham', - 'Vernier', - 'Morecambe', - 'Mason', - 'Roanne', - 'Sao Luis Gonzaga', - 'Montgomery Village', - 'Castelo', - 'Seelze', - 'Wermelskirchen', - 'Yhu', - 'Zhitiqara', - 'Hinesville', - 'Safidon', - 'Shangcaiyuan', - 'Corum', - 'Golden Glades', - 'Del Rio', - 'Kolattupuzha', - 'Saarlouis', - 'Zhujiezhen', - 'Trebic', - 'Bagre', - 'Ayutuxtepeque', - 'Sion', - 'Goshen', - 'Gladstone', - 'Simpang Renggam', - 'University Place', - 'Randolph', - 'Osimo', - 'Azazga', - 'Dhamnod', - 'Farafangana', - 'Bugasong', - 'Tienen', - 'Naranjito', - 'Rio Pardo', - 'Manamadurai', - 'Slagelse', - 'Abashiri', - 'Tortosa', - 'Butte', - 'East Gwillimbury', - 'Sarpol-e Zahab', - 'Marutharod', - 'Andapa', - 'Anse-a-Veau', - 'Medgidia', - 'Misungwi', - 'Sidi Lakhdar', - 'Dabouziya', - 'Mugnano di Napoli', - 'Falls', - 'Phokeng', - 'Duenas', - 'Tynaarlo', - 'Espiye', - 'Grantham', - 'Zhangziying', - 'Huntington Station', - 'Qasr al Qarabulli', - 'Abulug', - 'Inca', - 'Swadlincote', - 'San Juan Despi', - 'Mildura', - 'Banda', - 'Yeonil', - 'Bugojno', - 'Cativa', - 'Bonifacio', - 'Paithan', - 'Kalaa Srira', - 'Dapoli', - 'Wedel', - 'Canete', - 'Zweibrucken', - 'Viernheim', - 'Kulittalai', - 'Gisborne', - 'Pasni', - 'Bayog', - 'Baft', - 'Mogpog', - 'Skhira', - 'Ahrensburg', - 'Pleasant Hill', - 'Cote-Saint-Luc', - 'Ankola', - 'Ain Taya', - 'Lebork', - 'Manitowoc', - 'Barugo', - 'Sadda', - 'Akouda', - 'Fairborn', - 'Brzeg', - 'Ballesteros', - 'Ocuilan de Arteaga', - 'Shangzhen', - 'Bodoco', - 'Curuzu Cuatia', - 'Gerash', - 'Formigine', - 'Aloguinsan', - 'San Dimas', - 'Smolyan', - 'Nishihara', - 'Schoten', - 'Mazarron', - 'Stow', - 'Motosu', - 'Banes', - 'Madakalavaripalli', - 'Canicatti', - 'Hatibanda', - 'Bela Vista de Goias', - 'Sambir', - 'Zaidpur', - 'Sochaczew', - 'Kalasin', - 'Fort Liberte', - 'Exmouth', - 'McMinnville', - 'Ye', - 'Mnasra', - 'Goto', - 'North Shields', - 'Centenario', - 'Kuji', - 'College Park', - 'Merauke', - "Itaporanga d'Ajuda", - 'Paxtaobod', - 'Riccione Marina', - 'Navodari', - 'Meppel', - 'Toretsk', - 'Santa Ana Nextlalpan', - 'Biwong', - 'Corsico', - 'Cherchell', - 'Durazno', - 'Kiryas Joel', - 'Yihezhuang', - 'Houlong', - 'Sao Joaquim de Bicas', - 'Lakewood Ranch', - 'Kita Chauhattar', - 'Pueblo West', - 'Betafo', - 'Garibaldi', - 'Merseburg', - 'Heunghae', - 'Phra Phutthabat', - 'Same', - 'Tandubas', - 'Degana', - 'La Blanca', - 'Trinec', - 'Wavre', - 'Bathurst', - 'Tabor', - 'Swakopmund', - 'Isingiro', - 'Merritt Island', - 'Geldern', - 'Quilevo', - 'Aracuai', - 'Conegliano', - 'Nandaime', - 'Licata', - 'Sao Pedro', - 'Shinjo', - 'Almeirim', - 'Kalaruch', - 'Pinukpuk', - 'Buchanan', - 'Nova Cruz', - 'Lautaro', - 'Fuso', - 'Aiyappan Kovil', - 'Sao Desiderio', - 'Hitchin', - 'Vedaranniyam', - 'Pomerode', - 'Zhangzhengqiao', - 'Esposende', - 'Lixingcun', - 'Timberwood Park', - 'New Panamao', - 'Simunul', - 'La Huacana', - 'Sibutu', - 'Sahuarita', - 'Nazerabad', - 'Baraidih', - 'Dakota Ridge', - 'Colinas do Tocantins', - 'Atami', - 'Mosonmagyarovar', - 'General Nakar', - 'Isfana', - 'Prairieville', - 'Le Perreux-Sur-Marne', - 'Pangururan', - 'Ubeda', - 'Badiadka', - 'Shahin Dezh', - 'Sereflikochisar', - 'Karoi', - 'Toumoukro', - 'Eastchester', - 'Toon', - 'Sid', - 'Korschenbroich', - 'Curaca', - 'Orangeville', - 'Cariari', - 'Abiy Adi', - 'Tiruvur', - 'Agioi Anargyroi', - 'Lufkin', - 'Talayan', - 'Tepeji del Rio de Ocampo', - 'Tobelo', - 'Znojmo', - 'Villena', - 'Kokrajhar', - 'Risod', - 'Dimona', - 'Caldono', - 'Kornwestheim', - 'Schiltigheim', - 'Laoac East', - 'Takhemaret', - 'Almora', - 'Bogazliyan', - 'Brejo', - 'San Agustin', - 'Shiso', - 'Spalding', - 'Balarampur', - 'Uonuma', - 'Cravinhos', - 'Gyapekurom', - 'Guindulman', - 'Fungurume', - 'Pingtang', - 'Pikesville', - 'Diakon', - 'Argyroupoli', - 'Radebeul', - 'Leduc', - 'Rainham', - 'Eastpointe', - 'Beaufort West', - 'Cinarcik', - 'Honaz', - 'Portao', - 'Titlagarh', - 'Cantilan', - 'Waris Aliganj', - 'Gbarnga', - 'Deer Park', - 'Cooper City', - 'Podgorze', - 'Lommel', - 'Pagani', - 'Vac', - 'Sint-Pieters-Leeuw', - 'Palapag', - 'Sao Domingos do Maranhao', - 'Westlake', - 'Woodridge', - 'Zeghanghane', - 'Hemer', - 'Jalajala', - 'Jamkhed', - 'Spanaway', - 'San Juan Nepomuceno', - 'Minamishiro', - 'Majagual', - 'Biberach', - 'Divandarreh', - 'Onesti', - 'Quinchia', - 'Gibraltar', - 'Ankazomiriotra', - 'Maromandia', - 'Mahasoabe', - 'Lushoto', - 'Zhegaozhen', - 'Tamra', - 'Letchworth', - 'American Fork', - 'Kallidaikurichi', - 'Shariff Aguak', - 'Menen', - 'San Quintin', - 'Les Mureaux', - 'Vassouras', - 'Angri', - 'Peyziwat', - 'Milaor', - 'Kignan', - 'Cieszyn', - 'Sibagat', - 'Acatlan de Osorio', - 'Stuhr', - 'Lochem', - 'Almendralejo', - 'Kakata', - 'North Providence', - 'Lanciano', - 'Annigeri', - 'Uelzen', - 'San Jose Poaquil', - 'Uttaradit', - 'San Juan Evangelista', - 'Bassin Bleu', - 'Pulgaon', - 'Sindirgi', - 'City of Orange', - 'Starokostiantyniv', - 'Oued el Alleug', - 'Impfondo', - 'Zhuqi', - 'Curralinho', - 'Initao', - 'Mulavur', - 'Adrano', - 'Lupi Viejo', - 'Reo', - 'Navan', - 'Guying', - 'Timbio', - 'Gadsden', - 'Zhaitangcun', - 'Toda Bhim', - 'Byadgi', - 'Itiuba', - 'Lianga', - 'Tabango', - 'Desamparados', - 'Sneek', - 'Palmeira', - 'Imzouren', - 'Sao Luis de Montes Belos', - 'Selmane', - 'Baclaran', - 'Chaodongcun', - 'Nuoro', - 'Beni Tamou', - 'Oeiras do Para', - 'Bozdogan', - 'Dao', - 'Walla Walla', - 'New City', - 'Bell Ville', - 'Golungo Alto', - 'Jaslo', - 'San Martin Sacatepequez', - 'Strumica', - 'Harima', - 'Waikabubak', - 'IJsselstein', - 'Parras de la Fuente', - 'Tobias Fornier', - 'Buxin', - 'Lichfield', - 'San Antonio de los Banos', - 'Rio Verde Arriba', - 'Kearney', - 'Inhambupe', - 'Kadungapuram', - 'Somoto', - 'Xinzhancun', - 'Crema', - 'Leawood', - 'Beni Slimane', - 'Baldwin', - 'Ghazaouet', - 'Braco do Norte', - 'Vechta', - 'Puerto Rico', - 'Narsipatnam', - 'Zhmerynka', - 'Mount Lebanon', - 'Catmon', - 'Varzea da Palma', - 'Tekes', - 'Mankoeng', - 'Zacatlan', - 'Kadingilan', - 'Crown Point', - 'El Ksar', - 'Ojiya', - 'Jaguaribe', - 'Chilecito', - 'Kovin', - 'Capoocan', - 'Kaippakancheri', - 'Azezo', - 'Karaagac', - 'Leo', - 'Trappes', - 'Midsalip', - 'Fallbrook', - 'Grodzisk Mazowiecki', - 'Vemalwada', - 'Xiaotangzhuang', - 'Antiguo Cuscatlan', - 'Landi Kotal', - 'Roldanillo', - 'Somma Vesuviana', - 'Palmerston', - 'Tlanchinol', - 'Kasba', - 'Datu Paglas', - 'Kohtla-Jarve', - 'Mella', - 'Moose Jaw', - 'Batobato', - 'Upper Merion', - 'Penha', - 'Villa Riva', - 'San Antero', - 'Barhadashi', - 'Oulad Zemam', - 'San Roque', - 'Lianmuqin Kancun', - 'Englewood', - 'East Lake', - 'Aranda de Duero', - 'Macuro', - 'Koryo', - 'Chascomus', - '`Ajab Shir', - 'Binche', - 'Morro do Chapeu', - 'Batouri', - 'Koh Kong', - 'Atiquizaya', - 'Rheinfelden (Baden)', - 'Masiu', - 'Sapa Sapa', - 'Cotes de Fer', - 'Elmina', - 'Sicuani', - 'Daganbhuiya', - 'Iriba', - 'Qadsayya', - 'Maassluis', - 'Pitanga', - 'Goldsboro', - 'Ano Liosia', - 'Aleshtar', - 'Bagh', - 'Chavakkad', - 'Ixtapan de la Sal', - 'Belen', - 'Aweil', - 'Port Moody', - 'Cabarroguis', - 'Acornhoek', - 'Ayorou', - 'Columbio', - 'Manganam', - 'Saint Helier', - 'Chumphon', - 'Arteijo', - 'Sidi Okba', - 'Come', - 'Ribeirao', - 'Gorizia', - 'Ken Caryl', - 'Leticia', - 'Niangoloko', - 'Bacarra', - 'Schwedt (Oder)', - 'Warminster', - 'Manlius', - 'Corinto', - 'Chempalli', - 'Pointe-Claire', - 'Wickford', - 'Batan', - 'Fraiburgo', - 'Hlukhiv', - 'Neuchatel', - 'Cishan', - 'Nogent-sur-Marne', - 'West Little River', - 'Olkusz', - 'Dhekiajuli', - 'Coxim', - 'Badr', - 'Houilles', - 'Chimbarongo', - 'Bad Nauheim', - 'Mangalam', - 'Poco Redondo', - 'Cukurcayir', - 'Sabanagrande', - 'Monteiro', - 'Vettam', - 'Paidha', - 'Angamali', - 'Orodara', - 'Darsi', - 'Siripur', - 'Alabaster', - 'My Hoa', - 'Orillia', - 'Kacanik', - 'Shobara', - 'Ban Pak Phun', - 'Butajira', - 'Geraardsbergen', - 'Paso de Ovejas', - 'Kong', - 'Riachao do Jacuipe', - 'Namhkam', - 'Asakuchi', - 'Madikeri', - 'Bell', - 'Banate', - 'Aldaya', - 'Tulum', - 'Kondapalle', - 'Landskrona', - 'Ipero', - 'Kennesaw', - 'South Riding', - 'Loughton', - 'Bafang', - 'Montlucon', - 'Glossop', - 'Vintar', - 'Dursunbey', - "An'gang", - 'Shirakawa-tsuda', - 'Shiroishi', - 'Ronda', - 'Puyo', - 'Batcha', - 'Menlo Park', - 'Nokia', - 'Taishi', - 'Al Mindak', - 'Amparafaravola', - 'Bamaur', - 'Ziniare', - 'Dupax Del Norte', - 'Estreito', - 'Churi', - 'Kidamangalam', - 'Mohnyin', - 'Joao Camara', - 'Beidou', - 'Kolin', - 'Shanawan', - 'Buenaventura Lakes', - 'Gojo', - 'Bethel Park', - 'Nowy Targ', - 'Hisua', - 'Olawa', - 'Didouche Mourad', - 'Romainville', - 'Muconda', - 'Petersburg', - 'Radnor', - 'Cottonwood Heights', - 'Persembe', - 'Mazeikiai', - 'Zamania', - 'Barguna', - 'Capim Grosso', - 'Kampong Speu', - 'Kavundappadi', - 'Pivijay', - 'Castro-Urdiales', - 'Bragado', - 'Foster City', - "Alamat'a", - 'Ross', - 'Geiro', - 'Guarambare', - 'Kyrenia', - 'Kartarpur', - 'Obukhiv', - 'Borne', - 'Andirin', - 'Huyton', - 'Uniondale', - 'Khvaf', - 'Lower Makefield', - 'Statesboro', - 'Katiena', - 'Pandami', - 'Eirunepe', - 'Puerto Cumarebo', - 'Cranberry', - 'Julich', - 'Gillette', - 'Totana', - 'Chuhuiv', - 'Shamsabad', - 'Baja', - 'Dipaculao', - 'Palmeira das Missoes', - 'Abingdon', - 'Shikarpur', - 'Panuco', - 'Kusapin', - 'Minamikyushu', - 'Umaria', - 'Brooklyn Center', - 'Trowbridge', - 'Ben Ahmed', - 'Mukdahan', - 'Bugembe', - 'Kaarina', - 'Knokke-Heist', - 'Aosta', - 'Los Gatos', - 'Glendale Heights', - 'Tekkebhagam', - 'El Arrouch', - 'Chanderi', - 'Calape', - 'Bungoono', - 'Temascalapa', - 'Mushie', - 'Kamaishi', - 'Victoria Falls', - 'Timimoun', - 'Borba', - 'Kareli', - 'Castelfranco Emilia', - 'Tutin', - 'Ban Ang Sila', - 'Kingman', - 'Taiobeiras', - '`Ain el Hadjel', - 'Didy', - 'Kadinhani', - 'Wakabadai', - 'Harker Heights', - 'Touros', - 'Puebloviejo', - 'Las Mercedes', - 'Dana Point', - 'Lubon', - 'Jishi', - 'Shingu', - 'Hangal', - 'Sarikaya', - 'Marignane', - 'Xinbu', - 'Livingstone', - 'Ambodimanga II', - 'Vohitromby', - 'Zumbo', - 'Forbe Oroya', - 'Lome', - 'Gumdag', - 'Gyzylgaya', - 'Osvaldo Cruz', - 'Luxitun', - 'Villafranca di Verona', - 'Hinda', - 'Turkauliya', - 'Boxtel', - 'Hampden', - 'Forchheim', - 'Porto Uniao', - 'Taguasco', - 'Sao Paulo de Olivenca', - 'Sopot', - 'Shalingzicun', - 'Asse', - 'Elesvaram', - 'Bembe', - 'Dellys', - 'Ornskoldsvik', - 'Ventspils', - 'Itamarandiba', - 'Djenne', - 'Rencun', - 'Dara', - 'Dehloran', - 'Musikot-Khalanga', - 'Carapegua', - 'Biritiba-Mirim', - 'Castelfranco Veneto', - 'Saint-Georges', - 'Dumalinao', - 'Yamanashi', - 'Massango', - 'Aravan', - 'Romans-sur-Isere', - 'Baragua', - 'Saintard', - 'Fatehpur Sikri', - 'Escuque', - 'Fort Erie', - 'Moninnpebougou', - 'Patratu', - 'Sanchor', - 'Pantelimon', - 'Aksay', - 'Lampertheim', - 'Oued Zenati', - 'Kifri', - 'Clarence', - 'Tawsalun', - 'Nijar', - 'Lohagaon', - 'So', - 'Niksic', - 'Araban', - 'Watari', - 'Sanana', - 'Nevers', - 'Kollo', - 'Carache', - 'Kakira', - 'Tunceli', - 'Gostivar', - 'Urbano Santos', - 'Sertania', - 'Arumuganeri', - 'Igrejinha', - 'Tecuci', - 'Baraawe', - 'Teutonia', - 'Ticul', - 'Sighetu Marmatiei', - 'Buco Zau', - 'Parambil', - 'Tit Mellil', - 'Shaliuhe', - 'Bela Cruz', - 'Rubino', - 'Delbruck', - 'Ubajara', - 'Bocas de Satinga', - 'Sayram', - 'Xinyuan', - 'Chand Chaur', - 'Achim', - "Val-d'Or", - 'Mankada', - 'Yuzhne', - 'Puerto Escondido', - 'Balzar', - 'Pribram', - 'Baroueli', - 'Ylojarvi', - 'Kallur', - 'Sayula de Aleman', - 'LaSalle', - 'Ivaipora', - 'Rodas', - 'Geraldton', - 'Sherwood', - 'Kaysville', - 'Ansongo', - 'Vadavalli', - 'Jaguarari', - 'Yufu', - 'Debagram', - 'Falmouth', - 'Silvia', - 'Cota', - 'Arbaoua', - 'Nanjikkottai', - 'Sao Joao Batista', - 'Xiaodian', - 'Vilakkudi', - 'Zhanjia', - 'Ilawa', - 'Oguzeli', - 'Itaiba', - 'Herrenberg', - 'City Bell', - 'Furstenwalde', - 'Jamikunta', - 'Putla Villa de Guerrero', - 'Taranagar', - 'Goleta', - 'Cibolo', - 'El Dificil', - 'Belhi', - 'Frederico Westphalen', - 'Lens', - 'San Lazzaro di Savena', - 'Ain el Bya', - 'Osawa', - 'Mayantoc', - 'Arris', - 'Krasnik', - 'Motherwell', - 'Mashiki', - 'Matalom', - 'Diplahan', - 'Businga', - 'Inza', - 'Erraguntla', - 'Balindong', - 'Payshamba Shahri', - 'Sarkoy', - 'Esplanada', - 'Shimanto', - 'Ain Bessem', - 'Mateur', - 'Saint-Medard-en-Jalles', - 'Chemancheri', - 'Badoc', - 'Helena', - 'Hani', - 'I-n-Salah', - 'Salt', - 'Cacapava do Sul', - 'Lobougoula', - 'Minamisatsuma', - 'Elk Grove Village', - 'Manwat', - 'Agen', - 'Shiyeli', - 'Baiyan', - 'Garfield', - 'Yinchengpu', - 'Rethymno', - 'Nueva Italia de Ruiz', - 'Ourilandia do Norte', - 'Sotouboua', - 'Fucheng', - 'Correntina', - 'Staryy Beyneu', - 'Ferry Pass', - 'Virei', - 'Chemmaruthi', - 'Savage', - 'Turaiyur', - 'Nouna', - 'Abbiategrasso', - 'Omaezaki', - 'Lower Macungie', - 'Dioungani', - 'Vrilissia', - 'Bussum', - 'Beverly Hills', - 'Nedroma', - 'Plottier', - 'Desert Hot Springs', - 'Ketti', - 'Kameda-honcho', - 'Pierrefitte-sur-Seine', - 'Dumfries', - 'Oisterwijk', - 'Pires do Rio', - 'Chamtha', - 'Clearfield', - 'Dartmouth', - 'Brighouse', - 'Massantola', - 'Kiranomena', - 'Ingenio', - 'Yankou', - 'Redcliff', - 'Guararapes', - 'Kavlinge', - 'Pattanapuram', - 'Ire', - 'Geesthacht', - 'Lumbang', - 'La Virginia', - 'Sasthankotta', - 'Narsinghgarh', - 'San Pedro de Uraba', - 'Kalyandrug', - 'Wigston Magna', - 'Bilzen', - 'Oharu', - 'Namerikawa', - 'Chancay', - "Sant'Antimo", - 'Nagarote', - 'El Abiodh Sidi Cheikh', - 'Madinat al Habbaniyah', - 'Tattamangalam', - 'Sibiti', - 'Cachoeira Paulista', - 'Dracut', - 'Naumburg', - 'Curanilahue', - 'Venaria Reale', - 'Komarno', - 'Epinal', - 'Messamena', - 'Concon', - 'Chiche', - 'Penaranda', - 'Niena', - 'Wheat Ridge', - 'Bernburg', - 'Zarqan', - 'Zaojiao', - 'Itzehoe', - 'Jimalalud', - 'Bambadinca', - 'Boro', - 'Guanhaes', - 'North Olmsted', - 'Tafas', - 'Termoli', - 'Kangasala', - 'Jacqueville', - 'Laranjeiras do Sul', - 'Yokaichiba', - 'Sebaco', - 'Paraipaba', - 'Safita', - 'Mallig', - 'Kindi', - 'Casale Monferrato', - 'Buloqboshi', - 'Cochrane', - 'Igbaras', - 'Piombino', - 'Georgsmarienhutte', - 'Kristianstad', - 'Estrela', - 'Didcot', - 'Nagato', - 'Bramsche', - 'Massillon', - 'Gandu', - 'Ibate', - 'Xangda', - 'Catubig', - 'Matoes', - 'Maragogi', - 'Homa Bay', - 'Yorii', - 'Papendrecht', - 'Weatherford', - 'Alubijid', - 'Koungou', - 'Catende', - 'Rokhaty', - 'Sint-Amandsberg', - 'Eramala', - 'Miguel Alves', - 'Buguey', - 'Nacogdoches', - 'Kangayam', - 'Utraula', - 'Salug', - 'Shilou', - 'Douar Oulad Hssine', - 'Pojuca', - 'Pervari', - 'Ptolemaida', - 'Maputsoe', - 'Termas de Rio Hondo', - 'Caramoran', - 'Ribeira Grande', - 'Huixtla', - 'Juneau', - 'Campo Alegre', - 'Odacho-oda', - 'Rumbek', - 'Waiyuanshan', - 'Zapala', - 'Aguilares', - 'Ouro Fino', - 'Kukshi', - 'Mangur', - 'Mutki', - 'Quitilipi', - 'Sami', - 'Kovur', - 'Antsohimbondrona', - 'Radhanpur', - 'Pekin', - 'Tamparan', - 'Dhahran', - 'Ciudad Sabinas Hidalgo', - 'Radolfzell am Bodensee', - 'Sao Miguel Arcanjo', - 'Earley', - 'Canyon Lake', - 'Rahachow', - 'Munnar', - 'Chachapoyas', - 'Brasilia de Minas', - 'Wernigerode', - 'Malangas', - 'Bauko', - 'Akividu', - 'Bizen', - 'Bezons', - 'San Donato Milanese', - 'Aiken', - 'Sakaiminato', - 'Tirebolu', - 'Marrero', - 'Bandarawela', - 'Andriba', - 'Bekoratsaka', - 'Vohilava', - 'Itampolo', - 'Ambano', - 'Ghuenke', - 'Yaguaron', - 'Cabaiguan', - 'Makhdumpur', - 'Milot', - 'Aalsmeer', - 'North Cowichan', - 'Wrzesnia', - 'Youwangjie', - 'Kanzakimachi-kanzaki', - 'Arzano', - 'Levice', - 'Pullman', - 'Franklin Square', - 'Puraini', - 'Mascalucia', - 'Massafra', - 'Tholikuzhi', - 'Needham', - 'Deptford', - 'Cheb', - 'Sitges', - 'La Concepcion', - 'Mangalia', - 'Sergio Osmena Sr', - 'Nisia Floresta', - 'Landecy', - 'Ganderkesee', - 'San Carlos Alzatate', - 'Neropolis', - 'Long Branch', - 'Bexleyheath', - 'South Kingstown', - 'Quintero', - 'Bougaa', - 'Santo Antonio do Taua', - 'Araguatins', - 'Xaxim', - 'Palamel', - 'Purattur', - 'Polillo', - 'Yenice', - 'Nilka', - 'Santa Maria Capua Vetere', - 'Erdek', - 'Canuelas', - 'Cacolo', - 'Avellaneda', - 'Paso del Macho', - 'Bayaguana', - 'Centereach', - 'Turicato', - 'Maryville', - 'Aix-les-Bains', - 'Kampong Thom', - 'Jyvaskylan Maalaiskunta', - 'Alengad', - 'Paipa', - 'Dzierzoniow', - 'Oudenaarde', - 'Buu Long', - 'Bahharet Oulad Ayyad', - 'Palmeiras de Goias', - 'Guachaves', - 'Maur Kalan', - 'Cleburne', - 'El Oro de Hidalgo', - 'Domingos Martins', - 'Willingboro', - 'Exu', - 'Camaiore', - 'Atwater', - 'Sidi Ali', - 'Oer-Erkenschwick', - 'Remchi', - 'Pampanito', - 'Namegata', - 'Jhanjharpur', - 'Sao Gotardo', - 'Ortakoy', - 'Alamnagar', - 'Newburgh', - 'San Lucas Toliman', - 'Plettenberg Bay', - 'Masi-Manimba', - 'Tongxiao', - 'Stadskanaal', - 'Bagasra', - 'Gurupa', - 'San Pedro de Ribas', - 'Hassi Khelifa', - 'Gallipoli', - 'Kottaikuppam', - 'North Huntingdon', - 'Ferrenafe', - 'Montigny-le-Bretonneux', - 'Salamina', - 'Pantabangan', - 'Tubao', - 'Velliyod', - 'Komagane', - 'Bocana de Paiwas', - 'Singia', - 'General Jose de San Martin', - 'Descalvado', - 'Yildizeli', - 'Tekkekara Kizhakku', - "'Ain Abid", - 'La Mana', - 'Tredyffrin', - 'Farrokh Shahr', - 'Sadabad', - 'Amatenango de la Frontera', - 'Al `Aydabi', - 'Laramie', - 'Donggou', - 'La Uruca', - 'Maebara', - 'Kochugaon', - 'Staffanstorp', - 'Bostanici', - 'Tuljapur', - 'Kavar', - 'Santa Catarina Mita', - 'Sitionuevo', - 'El Palmar', - 'Oldenzaal', - 'Jaguaruana', - 'Dania Beach', - 'Lalgola', - 'Rushden', - 'Baraderes', - 'Sigma', - 'Amecameca de Juarez', - 'Zhaoyu', - 'Garner', - 'Jasim', - 'West Bend', - 'Bagrami', - 'Itapicuru', - 'Kumba', - 'Masur', - 'Vught', - 'Jiming', - 'Naugatuck', - 'Shimizucho', - 'Barros Blancos', - 'Nautan Dube', - 'Rumuruti', - 'Calubian', - 'Capela', - 'Siquirres', - 'Nueva Imperial', - 'Balyqshy', - 'Morro Agudo', - 'Zentsujicho', - 'Kiryandongo', - 'Tecozautla', - 'Ecclesfield', - 'Kuroishi', - 'Jalpatagua', - 'Jerez', - 'Chum Phae', - 'Favara', - 'Media Luna', - 'Chorbog', - 'Masatepe', - 'Mundelein', - 'Pruszcz Gdanski', - 'Zepce', - 'Lloydminster', - 'Nanyuki', - 'Manises', - 'Wisbech', - 'Fangyuan', - 'Darwen', - 'Holladay', - 'Lidingo', - 'Shenwan', - 'Cururupu', - 'Katagami', - 'Pehuajo', - 'Lawndale', - 'Cueto', - 'Al Khawr', - 'Thazhamel', - 'Hayama', - 'Lake Magdalene', - 'Rahatgarh', - 'Ayabe', - 'Oak Ridge', - 'I`zaz', - 'Mae Sot', - 'Milford Mill', - 'Ivrindi', - 'Puerto Wilches', - 'Prosper', - 'Kurivikod', - 'Buzovna', - 'Encrucijada', - 'Prestwich', - 'Mechraa Bel Ksiri', - 'Bunyan', - 'Charthawal', - 'Knjazevac', - 'Epsom', - 'Dialoube', - 'Colombia', - 'Qara', - 'Samdhin', - 'Dej', - 'Sejiyon', - 'Kostopil', - 'Mandaguacu', - 'Bangassou', - 'Airmadidi', - 'Parambu', - 'Save', - 'Chambly', - 'Kalisizo', - 'Nagdha Simla', - 'Jam', - 'Trebinje', - 'Forquilhinha', - 'Nauagarhi', - 'Cambrai', - 'Deori Khas', - 'Neuruppin', - 'Renkum', - 'Carballo', - 'Nieuw-Vennep', - 'Pindare-Mirim', - 'Cay', - 'Wevelgem', - 'Areka', - 'Norak', - 'Kunnatnad', - 'Neira', - 'Kolachel', - 'Cornelius', - 'Sanha', - 'Shentang', - "L'Hay-les-Roses", - 'Halden', - 'Yawatahama-shi', - 'Vellanad', - 'Ilhavo', - 'Draa Ben Khedda', - 'Buyan', - 'Navalcarnero', - 'Courcelles', - 'Plaisir', - 'Myoko', - 'New Bern', - 'Colider', - 'Bolobo', - 'Qutur', - 'Sri Madhopur', - 'Bagac', - 'Opelika', - 'Humenne', - 'Ithaca', - 'Hoyerswerda', - 'Villaricca', - 'Dasol', - 'Nicholasville', - 'Point Pedro', - 'Guamo', - 'Maralal', - 'Lumding', - 'Candido Mota', - 'Norwood', - 'Waddinxveen', - 'Dimataling', - 'Mamaroneck', - 'Wenxian Chengguanzhen', - 'Odorheiu Secuiesc', - 'Klela', - 'Diemen', - 'Hitoyoshi', - 'Monjas', - 'Rio das Pedras', - 'Gongguan', - 'Pontoise', - 'Redan', - 'Tanmen', - 'Sherpur Khurd', - 'Aracoiaba da Serra', - 'Ibanda', - 'Altenburg', - 'Netivot', - 'Imisli', - 'Magsingal', - 'Yahsihan', - 'Bel Air North', - 'Rio Bravo', - 'Zaqatala', - 'Eyvan', - 'Mahallat Damanah', - 'Mograne', - 'Shimotoba', - 'Yby Yau', - 'Port Chester', - 'Burgdorf', - 'Ennery', - 'Chatellerault', - 'Aguada de Pasajeros', - 'Ivisan', - 'Bandeirantes', - 'Vadakakarai', - 'Tiquipaya', - 'Boghni', - 'Oiso', - 'Petrovac na Mlavi', - 'Hendrik-Ido-Ambacht', - 'Inkhil', - 'Siliana', - 'Parnarama', - 'Rillieux-la-Pape', - 'Naspur', - 'Carangola', - 'La Verne', - 'Unchagao', - 'Esperanca', - 'Barrinha', - 'Changuinola', - 'Salgotarjan', - 'Valkenswaard', - 'Rosmalen', - 'Kosonsoy', - 'Pocone', - 'Itaperucu', - 'Bittou', - 'Alba', - 'Bramhapuri', - 'Pontypridd', - 'Duanshan', - 'Shepparton', - 'Kreuztal', - 'Lobos', - 'Rutherglen', - 'Sakaraha', - 'LaGrange', - 'Dar Ould Zidouh', - 'Laguna Hills', - 'Varto', - 'Paracelis', - 'Saint Neots', - 'Siraway', - 'Khanah Sur', - 'Rusera', - 'Middle River', - 'Rheinberg', - 'Asilah', - 'Ciudad del Plata', - 'Podili', - 'Yaita', - 'Tongeren', - 'Gata', - 'Ambatomiady', - 'Beidaying', - 'Orcutt', - 'Shrigonda', - 'Los Altos', - 'Fomento', - 'Ngudu', - 'Kalliyassheri', - 'West Falls Church', - 'Rosa Zarate', - 'North Royalton', - 'Tequila', - 'Espinosa', - 'Yingyangcun', - 'Lushnje', - 'Bembereke', - 'Tancitaro', - 'Chitral', - 'Danghara', - 'Khorugh', - 'Sakhnin', - 'Gevelsberg', - 'Thiais', - 'Sabana Grande de Boya', - 'Montebelluna', - 'Centre Wellington', - 'Vibo Valentia', - 'Sasaguri', - 'Bedworth', - 'Tewksbury', - 'Huangxicun', - 'Tangua', - 'San Juan Ixcoy', - 'Nantan', - 'Barreirinha', - 'Sterling', - 'Cambita Garabitos', - 'Manaratsandry', - 'Vienne', - 'Vigneux-sur-Seine', - 'Malaikkal', - 'Pompeu', - 'Werl', - 'Viry-Chatillon', - 'Petrosani', - 'Hopkinsville', - 'Tairan Camp', - 'Tummapala', - 'Mushabani', - 'Chantal', - 'Espinho', - 'Karera', - 'Konseguela', - 'Malakanagiri', - 'Rodolfo Sanchez Taboada', - 'Sao Jose do Egito', - 'Vohitrandriana', - 'Andranovory', - 'Wobulenzi', - 'Dashao', - 'Alamogordo', - 'Burlingame', - 'Iguape', - 'Diffa', - 'Itapemirim', - 'Arraial do Cabo', - 'Santa Vitoria do Palmar', - 'Bethany', - 'Gimbi', - 'Babati', - 'Lucera', - 'Yaese', - 'Lakeside', - 'Dolo Odo', - 'Irituia', - 'Arcos de la Frontera', - 'Mocimboa da Praia', - 'Tawaramoto', - 'Ballwin', - 'Tarakeswar', - 'Minas de Matahambre', - 'Wanghong Yidui', - 'Badami', - 'Husainabad', - 'Saint-Laurent-du-Var', - 'Ridley', - 'Chagne', - 'Dedza', - 'Alcazar de San Juan', - 'SeaTac', - 'Chichester', - 'Sacele', - 'Mlawa', - 'Sabirabad', - 'Deal', - 'Jeremie', - 'West Warwick', - 'Itatiaia', - 'Cicero Dantas', - 'Canavieiras', - 'West Odessa', - 'Pichanal', - 'Flores da Cunha', - 'Okagaki', - 'North Chicago', - 'Coria del Rio', - 'Kaminokawa', - 'Bairi Chak', - 'Champoton', - 'Pontefract', - 'Dreux', - 'Voorhees', - 'Sao Luis do Quitunde', - 'Leh', - 'Pattanakkad', - 'Ozd', - 'Culleredo', - 'San Antonio Ilotenango', - 'Sholinghur', - 'Dharampur', - 'Juanacatlan', - 'Bicester', - 'Manavadar', - 'Puerto de la Cruz', - 'Palaiya Ayakkudi', - 'North Andover', - 'Careiro da Varzea', - 'Lohmar', - 'Vinkovci', - 'Kalgoorlie', - 'Cholargos', - 'Capulhuac', - 'Saraykoy', - 'Zionsville', - 'Beverley', - 'Al Husayniyah', - 'Chinnalapatti', - 'Walsrode', - 'Pattittara', - 'Arlon', - 'Friedberg', - 'Korinthos', - 'Lohagara', - 'Begles', - 'Taunusstein', - 'Vitoria do Mearim', - 'Ungheni', - 'Nalchiti', - 'Ganassi', - 'Lavras da Mangabeira', - 'Qo`rg`ontepa', - 'Jonuta', - 'Careiro', - 'Escuinapa', - 'Nardo', - 'Santa Paula', - 'Rio Blanco', - 'Southlake', - 'Barao de Cocais', - 'Saratoga', - 'Weil am Rhein', - 'Carpentras', - 'Mahemdavad', - 'Alegre', - 'Pascani', - 'Andingcun', - 'Tsuruno', - 'Guaranda', - 'Gadarpur', - 'Ban Sai Ma Tai', - 'Pisek', - 'Ulliyeri', - 'Ferizli', - 'Tekkali', - 'Chak Five Hundred Seventy-five', - 'Udaypur Gadhi', - 'Einbeck', - 'San Sebastian', - 'Novoyavorovskoye', - 'Pedana', - 'Mattathur', - 'Alem Paraiba', - 'Agblangandan', - 'Juatuba', - 'Aglipay', - 'Northport', - 'Riacho de Santana', - 'Sekiyado', - 'Dois Irmaos', - 'Tekeli', - 'Pandua', - 'Nova Russas', - 'Babura', - 'Goussainville', - 'Treviglio', - 'Ciudad Melchor de Mencos', - 'Czeladz', - 'Tepetlaoxtoc', - 'Cruz del Eje', - 'Bannur', - 'Mont-de-Marsan', - 'Partinico', - 'Moche', - 'Campo Alegre de Lourdes', - 'Balatan', - 'Villiers-sur-Marne', - 'Presidente Figueiredo', - 'Gobernador Virasora', - 'Lahij', - 'Catole do Rocha', - 'Chuo', - 'Osterholz-Scharmbeck', - 'Gamu', - 'Toribio', - 'Chengam', - 'Tabuleiro do Norte', - 'Bad Hersfeld', - 'Ennepetal', - 'San Giuliano Terme', - 'Nazare da Mata', - 'Juquitiba', - 'Luis Correia', - 'Yunoshima', - 'Niles', - 'Burgess Hill', - 'Eagle', - 'Calafell', - 'Gurnee', - 'Santana do Acarau', - 'Police', - 'Mataas Na Kahoy', - 'Miami Lakes', - 'Jarinu', - 'Carapo', - 'Kaele', - 'Sao Jose da Tapera', - 'Keles', - 'Capim', - 'Taozhuangcun', - 'Diema', - 'Cachan', - 'Banamba', - 'Uzynaghash', - 'Grottaglie', - 'Talakkad', - 'Devarshola', - 'Birtouta', - 'Ain Kercha', - 'Buey Arriba', - 'Hafnarfjordhur', - 'Sarno', - 'Illescas', - 'Bay Shore', - 'Wallkill', - 'Leusden', - 'Xingang', - 'Zug', - 'Haan', - 'Sokuluk', - 'Osmancik', - 'Olopa', - 'Suzak', - 'Founougo', - 'Liptovsky Mikulas', - 'Hayrabolu', - 'Anilao', - 'Gariadhar', - 'Parkville', - 'Ouatagouna', - 'Aungban', - 'Savigny-le-Temple', - 'Westville', - 'Farsan', - 'Sankaramangalam', - 'Nagawaram', - 'Thung Song', - 'Krabi', - 'Giannitsa', - 'Stratford-upon-Avon', - 'Masho Khel', - 'Hellin', - 'Mainaguri', - "G'ijduvon Shahri", - 'Pamukova', - 'Pittsford', - 'Pau dos Ferros', - 'Gubbio', - 'North Tonawanda', - 'Torrijos', - 'Karuvakulam', - 'Mukumbura', - 'Neuburg', - 'Lawrenceville', - 'Yanai', - 'Afonso Claudio', - 'Motema', - 'Ar Ruhaybah', - 'New Smyrna Beach', - 'Besiri', - 'Tchindjendje', - 'Ash Shinan', - 'Uran', - 'Maguing', - 'Bandar-e Lengeh', - 'Mandera', - 'Tskhinvali', - 'Magdalena de Kino', - 'Camamu', - 'Pontal do Parana', - 'Quillabamba', - 'Bala Koh', - 'Carlos Barbosa', - 'Myszkow', - 'Menton', - 'Kailahun', - 'Valdepenas', - 'Karjan', - 'Okotoks', - 'Motomiya', - 'Banlung', - 'Muvattupula', - 'Austintown', - 'Salyan', - 'Manawar', - 'Avola', - 'Schonebeck', - 'Samrong', - 'Amaga', - 'Oristano', - 'Eldersburg', - 'Kuttanallur', - 'Dhari', - 'Newark upon Trent', - 'Nanyo', - 'Temascaltepec de Gonzalez', - 'Zywiec', - 'Villemomble', - 'Alma', - 'Rehli', - 'Hirakawacho', - 'Huatabampo', - 'Fengrenxu', - 'Graneros', - 'Abu Suwayr', - 'Shahpura', - 'Sallimedu', - 'Seguin', - 'Kessel-Lo', - 'Pothuhera', - 'Kurunegala', - "Al 'Attawia", - 'Telimele', - 'Segala Mba', - 'Northolt', - 'San Salvador El Seco', - 'Chimichagua', - 'To`raqo`rg`on', - 'Koni', - 'Liberty', - 'Cabrobo', - 'Malakoff', - 'Wishaw', - 'Bai Chay', - 'Chimakurti', - 'Andernach', - 'Ometepec', - 'Benguema', - 'San Gregorio de Nigua', - 'Bardejov', - 'Jima Abajo', - 'Majidpur', - 'Drexel Heights', - 'Aspropyrgos', - 'Gaggenau', - 'Jinka', - 'Pantao-Ragat', - 'Zhedao', - 'Las Nieves', - 'Harpenden', - 'Falou', - 'Huanta', - 'Salou', - 'Chabet el Ameur', - 'Taramangalam', - 'Anse-a-Foleur', - 'Best', - "Wik'ro", - 'Highland Park', - 'Lewe', - 'Uithoorn', - 'Anjad', - 'Qaratau', - 'Milford', - 'Berriane', - 'Daheba', - 'Whitstable', - 'Tsuru', - 'Crevillente', - 'Calintaan', - 'Ndora', - 'Djendel', - 'Gorna Oryahovitsa', - 'Kaipram', - 'Kibiti', - 'Bankass', - 'Claudio', - 'Yverdon-les-Bains', - 'Periyanayakkanpalaiyam', - 'Ypacarai', - 'Lievin', - 'Egra', - 'Inami', - 'Joacaba', - 'Anse a Pitre', - 'Floresta', - 'Ostuni', - 'Piagapo', - 'Tasova', - 'Kanniparamba', - 'San Giuseppe Vesuviano', - 'Candijay', - 'Marogong', - 'Mussoorie', - 'Pulupandan', - 'Planadas', - 'Mucari', - 'Gukeng', - 'Sakti', - 'Dumalag', - 'Rury', - 'Elur', - 'Balete', - 'Postmasburg', - 'Rahimpur', - 'Minudasht', - 'Rosignano Marittimo', - 'Oltu', - 'Bretten', - 'Muratli', - 'Kondarangi Kiranur', - 'Iguig', - 'Wuyuan', - 'Szekszard', - 'Monte Patria', - 'Nethirimangalam', - 'Margram', - 'Merzig', - 'Sainte-Julie', - 'Milazzo', - 'Nanchital de Lazaro Cardenas del Rio', - 'Villa Regina', - 'Sakhipur', - 'Zemoura', - 'Degeh Bur', - 'Meschede', - 'Kericho', - 'Granger', - 'Cahul', - 'Dauin', - 'Comiso', - 'Congleton', - 'Kulat', - 'Mahugaon', - 'Monterey', - 'Arda', - 'Balungao', - 'Qahderijan', - 'Chmistar', - 'El Fanar', - 'Bent Jbail', - 'Zgharta', - 'Andranomanelatra', - 'Tsitondroina', - 'Ambinanitelo', - 'Ambalavao', - 'Majuro', - 'Bourem Guindou', - 'Du Yar', - 'Kuah', - 'Dulmial', - 'Malak Abad', - 'Maleme Hodar', - 'Sali', - 'Uar Esgudud', - 'Ikoto', - 'Kafr Nubl', - 'Anew', - 'Mpwapwa', - 'Kayunga', - 'Pop', - 'Kanyobagonga', - 'Gongyefu', - 'Liaojiayuan', - 'Les Palmes', - 'Mundahal Khurd', - 'Hasanparti', - 'Ranpur', - 'Patri', - 'Salaya', - 'Edassheri', - 'Mundi', - 'Padappakara', - 'Sagwara', - 'Tirwa', - 'Kaluvaya', - 'Masabdisa', - 'Magadi', - 'Baghmari', - 'Sarpavaram', - 'Dhandhuka', - '`Aynkawah', - "Jalawla'", - 'Mutsamudu', - 'Saundhonwali', - 'Salay', - 'Parakadavu', - 'Eshtehard', - 'Dala', - 'Soledade', - 'Sombrio', - 'Koratgi', - 'Schwandorf', - 'Askoy', - 'Kamisato', - 'Winter Park', - 'Anchieta', - 'East Niles', - 'Chamblee', - 'Navapur', - 'Kaminoyama', - 'Zgorzelec', - 'Birur', - 'Aarschot', - 'Kotturu', - 'Vero Beach South', - 'San Andres del Rabanedo', - 'Holbaek', - 'Garopaba', - 'Saint-Constant', - 'Radcliffe', - 'Southgate', - 'Agno', - 'Verbania', - 'Gerakas', - 'Dalin', - 'Pind Dadan Khan', - 'Manduria', - 'La Garenne-Colombes', - 'Marhaura', - 'Banning', - 'Ragan Sur', - 'Mohyliv-Podilskyi', - 'Imbituva', - 'Galesburg', - 'Subotica', - 'Rietberg', - 'Carshalton', - 'Vyshhorod', - 'Vestal', - 'Triprangottur', - 'General Alvear', - 'Dandenong', - 'Mahon', - 'Plympton', - 'Panakkudi', - 'Serra Negra', - 'Metamorfosi', - 'Algonquin', - 'Conguaco', - 'Pinhao', - 'Mandali', - 'Mabole', - 'Campo Magro', - 'Padada', - 'Balabagan', - 'Wellesley', - 'Tacuba', - 'El Idrissia', - 'Villa Dolores', - 'Al Madad', - "Be'er Ya`aqov", - 'San Andres Xecul', - 'Xiaba', - 'Quiapo', - 'El Kseur', - 'Waslala', - 'Ozhur', - 'Kabalo', - 'Alacuas', - 'Ris-Orangis', - 'Motala', - 'Nutley', - 'Kodayattur', - 'Petite Riviere de Nippes', - 'Nanga Eboko', - 'Oosterend', - 'Shibancun', - 'Dzyarzhynsk', - 'Shetang', - 'Tiruvegapra', - 'Fleming Island', - 'Thuan Tien', - 'Krishnarajpet', - 'Kinik', - 'Bad Zwischenahn', - 'Hakha', - 'Bontoc', - 'Talwara', - 'Kaita', - 'Hengchun', - 'Antsampandrano', - 'East Windsor', - 'Puente-Genil', - 'Madavur', - 'Hengshuicun', - 'Ranai', - 'Dahana', - 'Ramnicu Sarat', - 'Puthupalli', - 'Raytown', - 'Bulwell', - 'Mount Hagen', - 'Bois-Colombes', - 'Mananasy-Tsitakondaza', - 'Charneca', - 'Ancon', - 'Nattam', - 'Atascadero', - 'Morrisville', - 'Benito Soliven', - 'Bazeh Kalagh', - 'Chahchaheh', - 'Bozmargi', - 'Kalateh-ye Mir Ab', - 'Santiago do Cacem', - 'Perico', - 'Rendsburg', - 'Reghin', - 'Sardrud', - 'Phu My', - 'Clichy-sous-Bois', - 'Atbasar', - 'Mbanga', - "Yong'ancun", - 'Tabio', - 'Decines-Charpieu', - 'Devarkonda', - 'Fridley', - 'Heesch', - 'Igarapava', - 'Saint-Cloud', - 'East Fishkill', - 'Tena', - 'Summerlin South', - 'Karahrud', - 'Makato', - 'Savanette', - 'Bayramic', - 'Kloof', - 'Nu`ayjah', - 'Orchard Park', - 'Kitaakita', - 'Parsuram', - 'Paragould', - 'Sursand', - 'Vinaroz', - 'Buriti', - 'Hosdurga', - 'Uychi', - 'Manjo', - 'Nepanagar', - 'Werve', - 'Pasuquin', - 'Newtownards', - 'Rota', - 'Hazleton', - 'Vlasotince', - 'Alushta', - 'Canguaretama', - 'Stung Treng', - 'Piraju', - 'Yingshouyingzi', - 'Rahway', - 'Pedras de Fogo', - 'Warrnambool', - 'Trutnov', - 'Toksun', - 'Bonou', - 'Synelnykove', - 'West Rembo', - 'Chatou', - 'Waltrop', - 'Oelde', - 'Monfalcone', - 'Lathrop', - 'Petrich', - 'Cruz', - 'Villa Donato Guerra', - 'Bregenz', - 'Jamai', - 'Pati do Alferes', - 'Alquizar', - 'Matthews', - 'Chikuzen', - 'Kalpatta', - 'Agdas', - 'Idar', - 'Veliyangod', - 'Villa Gesell', - 'Kendal', - 'San Agustin Chahal', - 'Dayr Abu Sa`id', - 'Mangdongshan', - 'Kollengode', - 'Gotse Delchev', - 'South Ubian', - 'Rarott', - 'Point Fortin', - 'Mashan', - 'Bourgoin-Jallieu', - 'Hajduboszormeny', - 'Tokmak', - 'Schererville', - 'Xalatlaco', - 'Lakheri', - 'Inagawa', - 'Zamboanguita', - 'Limoeiro do Ajuru', - 'Burton', - 'Pedro Betancourt', - 'Eastern Goleta Valley', - 'Antsahalava', - 'Gustrow', - 'Chiknayakanhalli', - 'Landsberg', - 'Maranga', - 'Johnston', - 'Purificacion', - 'Vandoeuvre-les-Nancy', - 'Cambui', - 'Sumilao', - 'Behror', - 'Olocuilta', - 'Temse', - 'Unterschleissheim', - 'Bra', - 'East Palo Alto', - 'Vallentuna', - 'Central', - 'Perigueux', - "Nan'ao", - 'Sevenoaks', - 'Demnat', - "N'Gaous", - 'Dongyuya', - 'Sint-Michielsgestel', - 'Duanzhuang', - 'Hutto', - 'Fountain', - 'Minad', - 'Garfield Heights', - 'Ja`ar', - 'Augustow', - 'Lalla Mimouna', - 'Kumalarang', - 'Flandes', - 'Escarcega', - 'Melrose', - 'Northfleet', - 'Arari', - 'Manticao', - 'Sankaridrug', - 'Yangshuling', - 'Fritissa', - 'Nejapa', - 'Brecht', - 'Dembi Dolo', - 'Zaltbommel', - 'Charenton-le-Pont', - 'West Windsor', - 'Northeim', - 'Tournefeuille', - 'McCandless', - 'Pirakkad', - 'Juchitepec', - 'Garchitorena', - 'Ibrahimpatnam', - 'Mudbidri', - 'Bujaru', - 'Pueblo Nuevo Vinas', - 'Vadakku Valliyur', - 'Uthal', - 'Krimpen aan den IJssel', - 'Tizi Gheniff', - 'Perafita', - 'Guyancourt', - 'Cramlington', - 'Funchal', - 'Kyegegwa', - 'Golden Gate', - 'Figuil', - "Espigao D'Oeste", - 'Budaors', - 'Pontedera', - 'Lavezares', - 'Bagong Pag-Asa', - 'Lamerd', - 'Brownsburg', - "L'Arbaa Nait Irathen", - 'Bluffton', - 'Marar', - 'Santiago de Baney', - 'Baglung', - 'Crofton', - 'Kavaje', - 'Carney', - 'Suisun City', - 'Didieni', - 'Prainha', - 'Povoa de Santa Iria', - 'Pilachikare', - "Ra's al `Ayn", - 'Gloria do Goita', - 'Casma', - 'Pattikonda', - 'Nalakadoddi', - 'Castelvetrano', - 'Madang', - 'Asipovichy', - 'Aralam', - 'Pignon', - 'Glenville', - 'Tonisvorst', - 'Shikharpur', - 'Mioveni', - 'Catarroja', - 'Guotang', - 'Pitou', - 'Kirkwood', - 'Ski', - 'Vaihingen an der Enz', - 'Swarzedz', - 'Benhao', - 'Sun City Center', - 'Arfoud', - 'Shuangtian', - 'Magna', - 'Namaacha', - 'Chalatenango', - 'Khunti', - 'Licab', - 'Riihimaki', - 'Shibushi', - 'Oakleaf Plantation', - 'Oslob', - 'Rasra', - 'Gates', - 'Garaimari', - 'Perry Hall', - 'Quivican', - 'Paratinga', - 'Cachoeira', - 'Winnenden', - 'East Lake-Orient Park', - 'Bromsgrove', - 'Koshu', - 'Fandriana', - 'Drexel Hill', - 'Le Plessis-Robinson', - 'Saalfeld', - 'Capitan Bermudez', - 'Maddagiri', - 'Orchards', - 'Fundao', - 'Tomi', - 'Cottica', - 'Dougabougou', - 'Canada de Gomez', - 'Beldanga', - 'Esmeralda', - "Bulung'ur Shahri", - 'Poas', - 'Redondela', - 'Zapotiltic', - 'Santa Cruz Cabralia', - 'Poona-Piagapo', - 'La Source', - 'Arniquet', - 'Kamphaeng Phet', - 'Aipe', - 'Irara', - 'Draveil', - "Oktyabr'sk", - 'Ath', - 'Blankenfelde', - 'Shaker Heights', - 'Horki', - 'Nieuwkoop', - 'Anadia', - 'Hinunangan', - 'Raghopur', - 'Yehud', - 'Queensbury', - 'Yomou', - 'McDonough', - 'Buhl', - 'Ulundi', - 'Pallijkarani', - 'Mahendragarh', - 'Nakrekal', - 'Takanezawa', - 'Sao Miguel do Iguacu', - 'Megara', - 'Culemborg', - 'Sopo', - 'Monitos', - 'Primero de Enero', - 'Ozumba', - 'Sankrail', - 'Springe', - 'Kelkheim (Taunus)', - 'Viacha', - 'Xiaobazi', - 'Desenzano del Garda', - 'Colgong', - 'Agde', - 'Rapallo', - 'Chili', - 'Suran', - 'Hisor', - 'Budaka', - 'Sherobod', - 'Cambuslang', - 'La Oliva', - 'Palpa', - 'Madinat Zayid', - 'Casselberry', - 'Mehlville', - 'Sonamukhi', - 'Kalappatti', - 'Baixo Guandu', - 'Zhongwangzhuang', - 'Sexmoan', - 'Riesa', - 'Teapa', - 'Marigliano', - 'Maubeuge', - 'Whitehall', - 'Boxmeer', - 'Pont-y-pwl', - 'Kitui', - 'Paripiranga', - 'Vattalkundu', - 'Chortkiv', - 'Catandica', - 'Stoughton', - 'Shiqiao', - 'Uttamapalaiyam', - 'Lugus', - 'Mirandopolis', - 'Sendjas', - 'Deodrug', - 'Johi', - 'Somotillo', - 'Tocache Nuevo', - 'Vallikunnam', - 'Kudat', - 'Togitsu', - 'Winterswijk', - 'Matouying', - 'Benavente', - 'Reforma', - 'Hendijan', - 'Ouled Haddaj', - 'Carmo do Paranaiba', - 'Meissen', - 'Pirri', - 'Ipubi', - 'Vandiyur', - 'Ponmana', - 'Dapa', - 'Ursulo Galvan', - 'Abasolo', - 'Senhora da Hora', - "Ahmer el 'Ain", - 'Ofaqim', - 'Sortobe', - 'Timizart', - 'Campina', - 'Humansdorp', - 'Ermont', - 'Pervomaiskyi', - 'Ystad', - 'Cervia', - 'Tameslouht', - 'Cruces', - 'Placheri', - 'Germi', - 'Sotteville-les-Rouen', - 'Langley', - 'Ammi Moussa', - 'Lake in the Hills', - 'Laplace', - 'Kailaras', - 'Hawtat Sudayr', - 'Hajira', - 'Limoeiro de Anadia', - 'Bochnia', - 'Tondela', - 'Russellville', - 'Hakmana', - 'Ampatuan', - 'Humberto de Campos', - 'Sibanicu', - 'Siroki Brijeg', - 'Hanawa', - 'Pucon', - 'Haines City', - 'Fabriano', - 'Siquijor', - 'Ban Phai', - 'Tabuelan', - 'Kuttuparamba', - 'Ariyalur', - 'Dalfsen', - 'Nahan', - 'Bielawa', - 'Tres Marias', - 'Coromandel', - 'Tazmalt', - 'Rosrath', - 'Karippira', - 'Ladwa', - 'Arrentela', - 'Gidri', - 'Easton', - 'Ponot', - 'Munsan', - 'Ruskin', - 'Mount Olive', - 'Mondlo', - 'Carinhanha', - 'Balakliia', - "Welk'it'e", - 'Santa Cruz das Palmeiras', - 'Pokhram', - 'Stockbridge', - 'Emmendingen', - 'Baleno', - 'Mathba', - 'Thabazimbi', - 'Bou Arfa', - 'Izegem', - 'Rehoboth', - 'Kudligi', - 'Virapandi', - 'Villiers-le-Bel', - 'Srem', - 'Duzhuang', - 'Ibaiti', - 'Las Rosas', - 'Caetes', - 'Caicedonia', - 'Takahashi', - 'Babatngon', - 'Hirado', - 'Tiruvambadi', - 'San Lucas Sacatepequez', - 'Narsimlapet', - 'Curridabat', - 'Kamalapuram', - 'Saikaicho-kobago', - 'Garupa', - 'Lepe', - 'Roseaux', - 'Yoshida', - 'Bugarama', - 'Kiskunfelegyhaza', - 'Asago', - 'Tarawa', - 'Pingdeng', - 'Bom Jesus', - 'Jeffersontown', - 'Ponmala', - 'Papa', - 'Landhaura', - 'Metu', - 'Fresnes', - 'Acatenango', - 'Manati', - 'Hanwell', - 'Premia de Mar', - 'Stanford le Hope', - 'Zighout Youcef', - 'Umrat', - 'Martorell', - 'Misilmeri', - 'West Springfield', - 'Pilon', - 'Kozhinjampara', - 'Novyi Rozdil', - 'Zhonghechang', - 'Kikinda', - 'Carauari', - 'Nongstoin', - 'Raikot', - "Sidi Smai'il", - 'Bixby', - 'Schwelm', - 'Harrison', - 'Tanglou', - 'Tantoucun', - 'Maki', - 'Chahe', - 'Hoxter', - 'Andoharanomaitso', - 'Muritiba', - 'Soissons', - 'Krotoszyn', - 'Ballymena', - 'Tibiao', - 'Karakocan', - 'Paraparaumu', - 'Pakwach', - 'Katima Mulilo', - 'Yerres', - 'Leonding', - 'Ferdows', - 'Bang Phongphang', - 'Murliganj', - 'Nauhata', - 'Souk et Tnine Jorf el Mellah', - 'Benicarlo', - 'Esztergom', - 'Jamestown', - 'Navolato', - 'Old Harbour', - 'Dona Remedios Trinidad', - 'Geislingen an der Steige', - 'Taungup', - 'Nowy Dwor Mazowiecki', - 'Esparza', - 'Mehdya', - 'Pitoa', - 'Oyabe', - 'Pattambi', - 'Sarny', - 'Mondragone', - 'Gevas', - 'Saito', - 'Kombissiri', - 'Fenoarivobe', - 'Pawayan', - 'Manga', - 'Ciudad Sahagun', - 'Neduvannur', - 'Edayikunnam', - 'Agawam', - 'Ihsaniye', - 'Jujutla', - 'Xizhou', - 'Tracuateua', - 'Laoaoba', - 'Mampikony', - 'Yangiyer', - 'Akkattettar', - 'Iuna', - 'Rancharia', - 'Simri Bakhriarpur', - 'Sottaiyampalaiyam', - 'Shangluhu', - 'Koprivnica', - 'Zhongtai', - 'Statesville', - 'Moribabougou', - 'Manampizha', - 'Munnalam', - 'Jaciara', - 'Mechernich', - 'Saugus', - 'Frome', - 'Blackrock', - 'Sabra', - 'Mouzaia', - 'El Copey', - 'Plaine du Nord', - 'Baradero', - 'Brodnica', - 'Reinbek', - 'Rudehen', - 'Basay', - 'Isnos', - 'Hattersheim', - 'Azangaro', - 'Verden', - 'Bamba', - 'Nivelles', - 'Madison Heights', - 'Amaliada', - 'Harir', - 'Monroeville', - 'Saint-Etienne-du-Rouvray', - 'Bagha Purana', - 'Losal', - 'Dubasari', - 'Ambatolampy', - 'Bin-Houye', - 'Longavi', - 'Rajpur', - 'Heerenveen', - 'Pardi', - 'Cajati', - 'Szentendre', - 'Matsubushi', - 'Samut Songkhram', - 'Izu', - 'Mendefera', - 'Frattamaggiore', - 'San Lorenzo de Esmeraldas', - 'Sue', - 'Pavugada', - 'Ilave', - 'Condega', - 'Nenmem', - 'Elanjivaliseri', - 'Venezuela', - 'Puerto Leguizamo', - 'Zhailuo', - 'Frankfort', - 'Piracuruca', - 'Wood Green', - 'Oulad Hammou', - 'Conceicao da Barra', - 'Selargius', - 'Mpika', - 'Coyaima', - 'Siraha', - 'Douar Oulad Aj-jabri', - 'Tha Yang', - 'Goio-Ere', - 'Kumru', - 'Castel Volturno', - 'Ouled Ben Abd el Kader', - 'Bonito Oriental', - 'South Laurel', - 'Forest Hills', - 'Ludwigsfelde', - 'Baishaling', - 'Bushey', - 'Saint Bernard', - 'Almus', - 'Cartama', - 'Harur', - 'Raseborg', - 'Ar Rutbah', - 'Short Pump', - 'Byaroza', - 'Jaramijo', - 'Allen Park', - 'Ogawa', - 'Yalda', - 'Banswada', - 'Mitu', - 'Conceicao das Alagoas', - 'Datu Piang', - 'Qianxucun', - 'Toli', - 'Ciro Redondo', - 'Ramanayyapeta', - 'Maharajpur', - 'Voula', - 'New Iberia', - 'Kamatero', - 'Dieppe', - 'Pongoz', - 'Nkhotakota', - 'Aioi', - 'Ban Bang Khu Wat', - 'Guararema', - 'Prata', - 'Passira', - 'General San Martin', - 'Baunatal', - 'Mannanchori', - 'Clarksburg', - 'Princes Town', - 'Toucheng', - 'Kpandu', - 'Kocani', - 'Arivonimamo', - 'Brahmana Periya Agraharam', - 'Henstedt-Ulzburg', - 'Puvali', - 'Tarana', - 'Kizhakkott', - 'Puttankulam', - 'Magog', - 'Boisbriand', - 'Taiwa', - 'Saho', - 'Mollendo', - 'Higashikagawa', - 'Srungavarapukota', - 'Glen Ellyn', - 'Karanjia', - 'Oltinko`l', - 'Ain Taoujdat', - 'Temerin', - 'Truskavets', - 'Monsey', - 'Supe', - 'Bermejo', - 'Saint-Sebastien-sur-Loire', - 'Ruy Barbosa', - 'Huanghuajing', - 'Guamal', - 'Bakhor', - 'Tablat', - 'Libacao', - 'Herentals', - 'Rio Pardo de Minas', - 'Kolambugan', - 'Adrogue', - 'Safaja', - 'Shakiso', - 'Juangriego', - 'Geilenkirchen', - 'Maravilha', - 'Qiman al `Arus', - 'Vicar', - 'Lagdo', - 'Aneho', - 'Ans', - 'Kosk', - 'Gizycko', - 'Bardaskan', - 'Altinova', - 'Kevelaer', - 'Konigsbrunn', - 'Cuitzeo del Porvenir', - 'Temescal Valley', - 'Edappalli', - 'Bergenfield', - 'Caucete', - 'Antur', - 'Eonyang', - 'Diangoute Kamara', - 'Cocal', - 'Sirsaganj', - 'Walnut', - 'Santo Antonio do Ica', - 'Vakfikebir', - 'Poggibonsi', - 'Kotagiri', - 'Zacoalco de Torres', - 'Metepec', - 'Bejucal', - 'Grimma', - 'Heywood', - 'Amircan', - 'Whitehorse', - 'Wappinger', - 'Heshancun', - 'Reda', - 'Kromeriz', - 'Ljubuski', - 'Ayun', - 'Babar', - 'Carmagnola', - 'Ouesso', - 'Agui', - 'Dobropillia', - 'Arqalyq', - 'Ciftlik', - 'Lier', - 'Chatan', - 'Eagle Pass', - 'Itabela', - 'Guma', - 'Camas', - 'Dar Bel Hamri', - 'Warin Chamrap', - 'Nalayh', - 'Villaviciosa de Odon', - 'Nirasaki', - 'Khrestivka', - 'Gaotan', - 'Saldanha', - 'Obama', - 'Carrickfergus', - 'Tetela de Ocampo', - 'Sonderborg', - 'Chennamangalam', - 'Glen Cove', - 'Pinyahan', - 'Alotenango', - 'Arnstadt', - 'Cabrican', - 'Capljina', - 'Bearsden', - 'Bhambia Bhai', - 'La Paz Centro', - 'Cabangan', - 'Ridgecrest', - 'Sangola', - 'Sheohar', - 'San Vicente dels Horts', - 'Neptune', - 'Massama', - 'Tsinjoarivo', - 'Conchal', - 'Golo-Djigbe', - 'Sesena', - 'Kakiri', - 'Maryland Heights', - 'Hazar', - 'Kuli', - 'Nallihan', - 'Gyula', - 'Xochistlahuaca', - 'Nakhal', - 'Mima', - 'Qujingpu', - 'Sueca', - 'San Vicente de Chucuri', - 'Casa Branca', - 'Po', - 'Khulm', - 'Guaimaca', - 'Wegberg', - 'Dajabon', - 'Djugu', - 'Kalwakurti', - 'East Hampton', - 'Reddish', - 'Converse', - 'Rhennouch', - 'Devanhalli', - 'Gingee', - 'Leichlingen', - 'Villazon', - 'Khust', - 'Akersberga', - 'Oakdale', - 'Vallauris', - 'Kefar Yona', - 'Bayang', - 'Nunspeet', - 'Navahrudak', - 'Mainit', - 'Vanves', - 'Mchinji', - 'Anajas', - 'Lomme', - 'Twentynine Palms', - 'Douentza', - 'Tainai', - 'Dubendorf', - 'Geldrop', - 'Qornet Chahouane', - 'Sahavato', - 'Imito', - 'Sandrandahy', - 'Ambohijanahary', - 'Masanwa', - 'Bo`ka', - 'Qianshanhong Nongchang', - 'Jiaoxiling', - 'Saila', - 'Limeil-Brevannes', - 'Karakurisshi', - 'Billericay', - 'Cuartero', - 'Langedijk', - 'Isser', - 'Almazora', - 'Lubok Antu', - 'Montfermeil', - 'San Felipe Jalapa de Diaz', - 'Pacho', - 'Belpasso', - 'Zeitz', - 'Yangyuhe', - 'Orlova', - 'Shaler', - 'San Andres Sajcabaja', - 'Kasangulu', - 'Kushtagi', - 'Gragnano', - 'Shalqar', - 'San Martin de los Andes', - 'Kanavaikuli', - 'Punceres', - 'Aron', - 'Lake Jackson', - 'Dhabauli', - 'Labasa', - 'Goriar', - 'Hamar', - 'Canosa di Puglia', - 'Vilangudi', - 'Noe', - 'Douglas', - 'Aloran', - 'Garden City', - 'Nochistlan de Mejia', - 'Bitam', - 'Ennis', - 'Malmal', - 'Iguaba Grande', - 'Sfizef', - 'Newry', - 'Danvers', - 'Mocimboa', - 'Dahmani', - 'Lukow', - 'Bouka', - 'Ash Shajarah', - 'El Sauce', - 'Reina Mercedes Viejo', - 'Reina Mercedes', - 'Bordj el Bahri', - 'Ambohitompoina', - 'Larreynaga', - 'Majayjay', - 'Caridad', - 'Gulnar', - 'Maple Valley', - 'Gyongyos', - 'Hiji', - 'Harelbeke', - 'Cecina', - 'Dingalan', - 'Melgaco', - 'Talusan', - 'Orvault', - 'Mytilini', - 'Chichaoua', - 'Zanandore', - 'Ampasimanolotra', - 'Mahaplag', - 'Quiroga', - 'Daphne', - 'Villa Luvianos', - 'Sirakorola', - 'Chalhuanca', - 'Umargam', - 'Guacui', - 'Kakuda', - 'Zolotonosha', - 'Hamtramck', - 'Barughutu', - 'Griesheim', - 'Uchturpan', - 'Muchun', - 'Sestao', - 'Sachse', - 'Traipu', - 'Wasi', - 'Mizumaki', - 'Darlaston', - 'Belmont', - 'Nibria', - 'Magdalena', - 'Motozintla', - 'Vleuten', - 'Rockledge', - 'Mattul', - 'Tualatin', - 'Wilmette', - 'Vadnagar', - 'Aci Catena', - 'Tlalpujahua de Rayon', - 'Williston', - 'Chato', - 'Ramsey', - 'Vinales', - 'Soledad de Doblado', - 'Bongor', - 'Bernards', - 'Ivanjica', - 'Tenares', - 'Ashington', - 'Chaska', - 'Mongo', - 'Fuman', - 'Ramotswa', - 'Charkhari', - 'Paivalike', - 'Williamsport', - 'Pirapozinho', - 'Immokalee', - 'Moncao', - 'Qibray', - 'Itapissuma', - 'Ouda-yamaguchi', - 'Khategaon', - 'As Sarw', - 'Gabasumdo', - 'Havran', - 'Hidrolandia', - 'Sundern', - 'Lapuyan', - 'Ocean', - 'Batken', - 'Tahla', - 'Palmar de Varela', - 'Lebrija', - 'Joao Alfredo', - 'Itacare', - 'Tudiyalur', - 'Parabiago', - 'Mogliano Veneto', - 'Dodge City', - 'San Giovanni in Persiceto', - 'Axim', - 'North Kingstown', - 'Koewarasan', - 'Borsa', - 'San Miniato', - 'Shuiding', - 'Bellaa', - 'Wajimazakimachi', - 'Teltow', - 'Spinea', - 'Santa Rosa de Lima', - 'Alatri', - 'San Pedro del Pinatar', - 'Poruvakara', - 'Porto Belo', - 'Troyan', - 'Le Chesnay', - 'Tabira', - 'Aparecida do Taboado', - 'Amarpur', - 'Brunssum', - 'Argelia', - 'Ban Chang', - 'Kitsuki', - 'New Windsor', - 'Atlautla', - 'Tuku', - 'Malargue', - 'Lagoa Vermelha', - 'Phuntsholing', - 'Tanguturu', - 'Huntley', - 'Niuchangqiao', - 'Zongdi', - 'Mukher', - 'San Juan Guichicovi', - 'Di Linh', - 'Parsa', - 'Hikawa', - 'Leon Postigo', - 'Longtan', - 'Pachor', - 'Padiyanallur', - 'Yahaba', - 'Bhimbar', - 'Theniet el Had', - 'Quijingue', - 'Shatiancun', - 'Shilan', - 'Sucy-en-Brie', - 'Mont-Dore', - 'Maracas', - 'Baesweiler', - 'Lagoa Seca', - 'Tysons', - 'Veendam', - 'Reisterstown', - 'Pilar do Sul', - 'Contla', - 'Prior Lake', - 'Assisi', - 'Soignies', - 'Ambodibonara', - 'New London', - 'Cabrero', - 'Svendborg', - 'Ouled Fayet', - 'Waddan', - 'Swatara', - 'Laojiezi', - 'Hulst', - 'Campulung', - 'Taougrite', - 'Andenne', - 'Ouled Slama Tahta', - 'Narat', - 'Wengtiancun', - 'Wangtang', - 'Karlskoga', - 'Atharan Hazari', - 'Jauja', - 'Mulchen', - 'Homewood', - 'Mazenod', - 'Conner', - 'Pombos', - 'Fortuna Foothills', - 'Wetter (Ruhr)', - 'Kantai', - 'Kobuleti', - 'Heemstede', - 'Novo Oriente', - 'Rardhu', - 'Citong', - 'Rayamangalam', - 'Haciqabul', - 'Ninomiya', - 'Patjirwa', - 'Teno', - 'Jarrow', - 'Niimi', - 'Abarkuh', - 'Millville', - 'Witney', - 'Takahagi', - 'Apaxco de Ocampo', - 'Pitogo', - 'Daulatkhan', - 'Marshalltown', - 'Marolambo', - 'Suluru', - 'Sitakili', - 'Timaru', - 'Nuwara Eliya', - 'Ipsala', - 'Triunfo', - 'Sint-Joost-ten-Node', - 'Tazoult-Lambese', - 'Fiche', - 'McHenry', - 'Nasriganj', - 'Supia', - 'Bourem', - 'Oiapoque', - 'Bandipura', - 'Lemon Grove', - 'Tongyangdao', - 'Duayaw-Nkwanta', - 'Pirai', - 'Konnur', - 'Ukiha', - 'Aguas Santas', - 'Schloss Holte-Stukenbrock', - 'Fetesti', - 'Purral', - 'Los Reyes de Juarez', - 'Toqsu', - 'Villa El Carmen', - 'Arar', - 'Vandikarai', - 'Algemesi', - 'Mandirituba', - 'Malekan', - 'Surmene', - 'Crestview', - "Mu'tah", - 'Mililani Town', - 'Cyangugu', - 'Jardim', - 'Wangen im Allgau', - 'Heilbron', - 'Ruzomberok', - 'Guastatoya', - 'Overath', - 'Caracal', - 'Sebikhotane', - 'Butzbach', - 'Oppegard', - 'Shotley Bridge', - 'Sadri', - 'Ayyagarpet', - 'Ibipetuba', - 'Nalbari', - 'Itai', - 'Penukonda', - 'Leiderdorp', - 'Itako', - 'Chicago Heights', - 'Ciudad Tecun Uman', - 'Kedu', - 'Balussheri', - 'Chillan Viejo', - "K'olito", - 'Panauti', - 'Paouignan', - 'Korgan', - 'Strausberg', - 'Jalpan', - 'Varandarapilli', - 'Green', - 'King', - 'Blerick', - 'Ikaruga', - 'Parksville', - 'Aytos', - 'Drimmelen', - 'Alvin', - 'Shtime', - 'Palanas', - 'Bihpur', - 'Balch Springs', - 'Castanos', - 'Macalelon', - 'Neenah', - 'Cueramaro', - 'Pallippurattuseri', - 'Chiavari', - 'Navrongo', - 'Zarraga', - 'Almunecar', - 'Savur', - "Piest'any", - 'Gurlan', - 'Xovos', - 'Ilchester', - 'Santo Antonio do Monte', - 'Porto Calvo', - 'Bhander', - 'Behara', - 'Corrente', - 'Ramon Magsaysay', - 'Ehingen an der Donau', - 'Santo Amaro da Imperatriz', - 'Mason City', - 'Sipacapa', - 'Haliyal', - 'Bady Bassitt', - 'Citrus Park', - 'Zalingei', - 'Grigny', - 'Pearl', - 'Choba', - 'Novi Ligure', - 'Akitakata', - 'Hamminkeln', - 'Alvares Machado', - 'New Lenox', - 'Tepehuacan de Guerrero', - 'Debiapur', - 'Hayang', - 'Kahului', - 'Moron de la Frontera', - 'Holbrook', - 'Longton', - 'Bourzanga', - 'Calimete', - 'Ezhipram', - 'Castelli', - 'Oak Forest', - 'Mocajuba', - 'Ewa Gentry', - 'West Islip', - 'Kimbe', - 'Sihecun', - 'Boralday', - 'Merrimack', - 'Kobylka', - 'El Abadia', - 'Taraka', - 'Paiporta', - 'Les Anglais', - 'Tauramena', - 'Kernersville', - 'Kupiansk', - 'Conception Bay South', - 'West Linn', - 'Melton Mowbray', - "Bo'ao", - 'Nguti', - 'Buri Ram', - 'San Juan de Uraba', - 'Dargecit', - 'Keswick', - 'Leimen', - 'Hohen Neuendorf', - 'Lindenhurst', - 'Jonava', - 'Pijnacker', - 'Thomasville', - 'Digboi', - 'Picarras', - 'Dame-Marie', - 'Cakovec', - 'Parimpudi', - 'Lambersart', - 'Aalten', - 'San Agustin Tlaxiaca', - 'Illkirch-Graffenstaden', - 'Asheboro', - 'Rappang', - 'Novi Grad', - 'Sikonge', - 'Nemuro', - "Jeffrey's Bay", - 'Awara', - 'Bretigny-sur-Orge', - 'Haiyang', - 'Rheinbach', - 'Lishanpu', - 'Pershotravensk', - 'Mirano', - 'Ambohijanaka', - "Pereyaslav-Khmel'nyts'kyy", - 'Afzalpur', - 'Fort Saskatchewan', - 'Tall Rif`at', - 'Long Thanh', - 'Liugoucun', - 'Batgram', - 'Quakers Hill', - 'Ichikikushikino', - 'Villagran', - 'Muchamiel', - 'Vittorio Veneto', - 'Lochearn', - 'Zomin Shaharchasi', - 'El Alia', - 'Minacu', - 'Irimbiliyam', - 'Agios Nikolaos', - 'Pedernales', - 'Kuzhittura', - 'Nova Olinda do Norte', - 'Nayoro', - 'Ksebia', - 'Klosterneuburg', - 'Toguere-Koumbe', - 'Harbiye', - 'Badiangan', - 'Pasinler', - 'Libenge', - 'Guanxi', - 'Nazare', - 'Wiesloch', - 'Benicia', - 'Raver', - 'Loutete', - 'Imamoglu', - 'Springettsbury', - 'Marsta', - 'Sens', - 'Leisure City', - 'Plum', - 'Santa Eugenia', - 'Nizao', - 'Thetford', - 'Amatepec', - 'Catamayo', - 'Granite City', - 'Taverny', - 'Malebennur', - 'Madhura', - 'Wooster', - 'Amangal', - 'Bagepalli', - 'Ticuantepe', - 'Alexania', - 'Pueblo Bello', - 'Chiriguana', - 'Marcos Juarez', - 'Payakaraopeta', - 'Vohipaho', - 'Tsaravary', - 'Miandrarivo', - 'Mandabe', - 'Andranomavo', - 'Antsiatsiaka', - 'Alakamisy Itenina', - 'Arandu', - 'Jaglot', - 'Haqqulobod', - 'Aragua de Barcelona', - 'Arrecifes', - 'Barbacha', - 'Paracuellos de Jarama', - 'Catio', - 'Estarreja', - 'Kriens', - 'Rapperswil-Jona', - 'Oullins', - 'Ourika Wawrmas', - 'Ambinanisakana', - 'Soanierana Ivongo', - 'Anajatuba', - 'Aldridge', - 'Basi', - 'Aripuana', - 'Kapellen', - 'Kadappuram', - 'San Sebastian de Yali', - 'Ar Rudayyif', - 'Novo Cruzeiro', - 'Nava', - 'Ternivka', - 'Uyuni', - 'Seaford', - 'Lemoore', - 'Bouguirat', - 'Potrerillos', - 'Wassenaar', - 'Zuitou', - 'Heppenheim', - 'Fidenza', - 'Sao Bernardo', - 'Pfaffenhofen', - 'Werkendam', - 'Tupanatinga', - 'Albania', - 'Farnworth', - 'Moon', - 'Ureshinomachi-shimojuku', - 'Dietikon', - 'Safashahr', - 'Nainijor', - 'Tambo', - 'Lowicz', - 'Pemberton', - 'Celendin', - 'Nelliyalam', - "Qa'emiyeh", - 'Khmilnyk', - 'Margherita', - 'Maner', - 'Pinarbasi', - 'San Andres de la Barca', - 'Kulasekharapuram', - 'Atitalaquia', - 'Kaluderica', - 'San Antonio del Monte', - 'Wahga', - 'Lobatse', - 'Acapetahua', - 'Bridgeton', - 'Barauna', - 'Al Qitena', - 'Albignasego', - 'Pappakurichchi', - 'Pamidi', - 'Idigny', - 'Miracema', - 'Kadambanad', - 'Alhaurin el Grande', - 'Lukula', - 'Kararan', - 'Sarayonu', - 'Bakhchysarai', - 'San Luis Jilotepeque', - 'Kizilcahamam', - 'Areraj', - 'Paducah', - 'Madattukkulam', - 'Kalikavu', - 'Feidh el Botma', - 'Gursarai', - 'Punch', - 'Scicli', - 'Chios', - 'Shoreview', - 'Nsanje', - 'Xima', - 'Bozyazi', - 'Clayton', - 'Caninde de Sao Francisco', - 'Majagua', - 'Vadippatti', - 'Bankapur', - 'Shencottah', - 'Villeparisis', - 'Alitagtag', - 'Temple Terrace', - 'Santa Margarita', - 'Rambouillet', - 'Ives Estates', - 'Labrador', - 'Vilyeyka', - 'Wesselsbron', - 'Cangas', - 'Ban Phonla Krang', - 'Khanabad', - 'Bamessi', - 'Magilampupuram', - 'Fortul', - 'Tuvur', - 'Srinivaspur', - 'Garbagnate Milanese', - 'Trikkunnapuzha', - 'Paracuaro', - "Mirassol d'Oeste", - 'Jumilla', - 'Lisen', - 'Cenon', - 'Solanea', - 'Tamayo', - 'Santa Maria de Jesus', - 'Sannois', - '`Abasan al Kabirah', - "Qarah Zia' od Din", - 'Thatha', - 'West Melbourne', - 'Betera', - 'Tlaxcoapan', - 'Mahina', - 'Gadhada', - 'Bidur', - 'Vernon Hills', - 'Tamorot', - 'Meppayyur', - 'Magarao', - 'Malitbog', - 'Goianinha', - 'Cormeilles-en-Parisis', - 'Upper Dublin', - 'Hennigsdorf', - 'Hukumati Baghran', - 'Soron', - 'Santa Maria Ixhuatan', - 'Megrine', - 'Alattur', - 'Miacatlan', - 'Saguiaran', - 'Bhuban', - 'Los Cordobas', - 'Circasia', - 'Kiruna', - 'Ronse', - 'Wanlaweyn', - 'Sapian', - 'Qaha', - 'Mamidalapadu', - 'Lamego', - 'Pirenopolis', - 'Miyanaga', - 'Piracaia', - 'Shelek', - 'Shangxiao', - 'Pitangui', - 'Quarrata', - 'Heiligenhaus', - 'Turrialba', - 'Nediyanad', - 'Ipu', - 'Ambodiangezoka', - 'Itamaraca', - 'Al Qutayfah', - 'Birine', - 'Bad Neuenahr-Ahrweiler', - 'Nannamukku', - 'Paiania', - 'Talaja', - 'Bien Unido', - 'Samayac', - 'Highbury', - 'Kuppadi', - 'Mizque', - 'Bugho', - 'Dalsingh Sarai', - 'South Portland', - 'Kirovsk', - 'Horn Lake', - 'Las Flores', - 'Frias', - 'Ajka', - 'Chettipalaiyam', - 'Manjacaze', - 'Betong', - 'Sun City West', - 'Sibi', - 'Buldan', - 'Manihari', - 'Cuajinicuilapa', - 'Macka', - 'Edwardsville', - 'Lauri', - 'Plainview', - 'Propria', - 'Moulay Bousselham', - 'Dar Chioukh', - 'Baytunya', - 'Aschersleben', - 'Jaguarao', - 'Chuanliaocun', - 'Newton Mearns', - 'Pantar', - 'Wieliczka', - 'Ibimirim', - 'San Benito Abad', - 'Sidi Akkacha', - 'Voinjama', - 'Ghataro Chaturbhuj', - 'Okuta', - 'South Pasadena', - 'Ratau', - 'Iheddadene', - 'Paramus', - 'Susquehanna', - 'Macrohon', - 'Lauaan', - 'Miguel Pereira', - 'Porto da Folha', - "Sofiyivs'ka Borshchahivka", - 'Bussy-Saint-Georges', - 'Jarocin', - 'Gioia del Colle', - 'Superior', - 'Iesolo', - 'Tarui', - 'La Teste-de-Buch', - 'Shahganj', - 'Molins de Rey', - 'Sanger', - 'San Alberto', - 'Lanquin', - 'Manasa', - 'Agia Varvara', - 'Dasuya', - 'Perumbalam', - 'Nyamti', - 'Cabot', - 'Zeboudja', - 'Mint Hill', - 'Mantena', - 'Sainte-Therese', - 'Etampes', - 'Deogarh', - 'Ituporanga', - 'Kantabanji', - 'Nacimiento', - 'Aleksandrovac', - 'Eureka', - 'Dois Corregos', - 'Hennaya', - 'Bubong', - 'Ahmadabad', - 'Giarre', - 'Qingshan', - 'Brawley', - 'Clarence-Rockland', - 'Uchinada', - 'Shirley', - 'Charata', - 'Neckarsulm', - 'Karumandi Chellipalaiyam', - 'Elmira', - 'Sebes', - 'Al Karnak', - 'Capao do Leao', - 'Xincun', - 'Timbiras', - 'Upper Macungie', - 'Cheadle Hulme', - 'Madalum', - 'Marapanim', - 'Achern', - 'Kayapa', - 'Langdu', - 'Blagnac', - 'Apam', - 'Quilali', - 'Agua Preta', - 'Gordes', - 'Kaisariani', - 'Wete', - 'Wall', - 'Perez', - 'Lido di Iesolo', - 'Makubetsu', - 'Apollo Beach', - 'Maski', - 'Tamarakulam', - 'Nakhon Phanom', - 'Caboolture', - 'Santa Josefa', - 'Panchla', - 'Tortona', - 'Tecolutla', - 'Peniche', - 'Mandi', - 'Mavelikara', - 'Selibaby', - 'Lauf', - 'Mauganj', - 'Gross-Gerau', - 'Newton Aycliffe', - 'Beohari', - 'Madruga', - 'Nadbai', - 'Dinokana', - 'Zemmouri', - 'La Prairie', - 'Gorlice', - 'Miramas', - 'Del Gallego', - 'Blenheim', - 'Owatonna', - 'Estoril', - 'Bina', - 'Muhlacker', - 'Dinanagar', - 'Cajuru', - 'Jinju', - 'Virakeralam', - 'Ouled Mimoun', - 'Rangia', - 'Balboa', - 'East Grinstead', - 'Elakadu', - 'Ashton in Makerfield', - 'Rezekne', - 'Zottegem', - 'Bombo', - 'Dongen', - 'Gundlupet', - 'Lagindingan', - 'East Chicago', - 'Jaltenco', - 'Vicencia', - 'Reoti', - 'Panchanandapur', - 'Pandag', - 'Batavia', - 'Incesu', - 'Yuanyangzhen', - 'Poldokhtar', - 'Wyszkow', - 'Tougan', - 'Sapouy', - 'Ilha Solteira', - 'Vogosca', - 'Bagh-e Malek', - 'Pensilvania', - 'Lichtenburg', - 'Ondokuzmayis', - 'Duptiair', - 'Eloi Mendes', - 'Cheranallur', - 'Parit Buntar', - 'Bergerac', - 'Tehuipango', - 'Weiterstadt', - 'Navabad', - 'Caririacu', - 'Clydebank', - 'Ulaangom', - 'Ubaidullahganj', - 'Werota', - 'Siquinala', - 'Wasco', - 'Walpole', - 'South Salt Lake', - 'Ibotirama', - 'Bingen am Rhein', - 'Nordenham', - 'Cotoca', - 'Koelwar', - 'Khadbari', - 'Batalha', - 'Nuevo Arraijan', - 'Aru', - 'Bozkir', - 'East Hempfield', - 'Baden', - 'Az Zabadani', - 'Fagaras', - 'Narasannapeta', - 'Rasiari', - 'Sabaa Aiyoun', - 'Beramanja', - 'Saint-Bruno-de-Montarville', - 'Kaboila', - 'Wright', - 'Yapacani', - 'As Sanamayn', - 'Ora', - 'Teustepe', - 'Pooler', - 'Laranjal Paulista', - 'Semirom', - 'Zhaicun', - 'Bayanhongor', - 'Carbonia', - 'Mirganj', - 'Mel Bhuvanagiri', - 'Paz de Ariporo', - 'Bourdoud', - 'Lamut', - 'Kudlu', - 'San Giovanni Rotondo', - 'Zirndorf', - 'Poro', - 'Colonia del Sacramento', - 'Buesaco', - 'Lainate', - 'Ganjing', - 'Tekkalakote', - 'Chivasso', - 'Rancho Grande', - 'Willebroek', - 'Kalfou', - 'Woodburn', - 'Muniz', - 'Ksour Essaf', - 'Gedera', - 'Talikota', - 'Saumur', - 'Kiskunhalas', - 'Wilmslow', - 'Ait Faska', - 'Sograha', - 'Canas', - 'Et Tira', - 'Iradan', - 'Vadakkanandal', - 'Buddayyakota', - 'Kottakota', - 'Guruzala', - 'Lunel', - 'Marimba', - 'Liushuquan', - 'Ketrzyn', - 'Rosario de la Frontera', - 'Flemalle-Haute', - 'Puerto Varas', - 'Budhlada', - 'Montemor-o-Velho', - "Sant'Anastasia", - 'Tavira', - 'Sanchez-Mira', - 'Suphan Buri', - 'Lice', - 'Selm', - 'Manito', - 'Jirwa', - 'Mankachar', - 'Iskandar', - 'Baykan', - 'Forest Grove', - 'Beuningen', - 'Mortsel', - 'Imperial Beach', - 'Mesagne', - 'Dum Duma', - 'Suar', - 'Guduru', - 'Ringas', - 'Kaous', - 'Oum Hadjer', - 'Cifuentes', - 'Perevalsk', - 'Ouled Rahmoun', - 'Dongfeng', - 'Bijbiara', - 'Pacasmayo', - 'Cankiri', - 'Wum', - 'Santiago Papasquiaro', - 'Lockport', - 'Baruni', - 'Vadakku Viravanallur', - 'Montichiari', - 'Gourma Rharous', - 'Huaquechula', - 'Itapuranga', - 'Terlizzi', - 'Kuyucak', - 'Tono', - 'Anosipatrana', - 'Campos Gerais', - 'Terrytown', - 'Misserghin', - 'Camanducaia', - 'Mzimba', - 'Sierra Bullones', - 'Tianyingcun', - 'Elangunnapuzha', - 'Phulera', - 'Requinoa', - 'Erice', - 'Terdal', - 'Tholen', - 'Konobougou', - 'Winona', - 'Elancourt', - 'Dengjiazhuang', - 'Halemba', - 'Tralee', - 'Northdale', - 'Kathu', - 'Key West', - 'Chellalat el Adhaouara', - 'Dancagan', - 'Mahates', - 'Thetford Mines', - 'Odemira', - 'Tianwei', - 'Alagoa Grande', - 'La Maquina', - 'Bad Honnef am Rhein', - 'El Hadjar', - 'Casillas', - 'Keystone', - 'Jaszbereny', - 'Mahitsy', - 'Emmeloord', - 'Dardoq', - 'Gamboma', - 'Burntwood', - 'Chuimatan', - 'Ridgewood', - 'Hercules', - 'Henin-Beaumont', - 'San Juan Atitan', - 'Renigunta', - 'Bangzha', - 'Lubbecke', - 'Barra da Estiva', - 'Hovd', - 'Skardu', - 'Bajina Basta', - 'Fort Mill', - 'Cave Spring', - 'Idhna', - 'Sandi', - 'Vertou', - 'Bresso', - 'Ambatomborona', - 'Malaimbandy', - 'Mahambo', - 'Ambatofotsy', - 'Tsarazaza', - 'Poytug`', - 'Brasileia', - 'Majiadiancun', - 'Harsewinkel', - 'Sinait', - 'Lakshmicharipara', - 'Gahmar', - 'Gaoya', - 'De Witt', - 'Rosemount', - 'Rich', - 'Dehgolan', - 'Wilsonville', - 'Upper Moreland', - 'Mangaldai', - 'Gonglang', - 'Fairland', - 'Londonderry', - 'Bom Jesus dos Perdoes', - 'Montreux', - 'Dharmapuram', - 'Puerto Piritu', - 'Istmina', - 'Queimadas', - 'Curtea de Arges', - 'Le Grand-Quevilly', - 'Tekman', - 'Binidayan', - 'Bobon', - 'Gonesse', - 'Golkoy', - 'Palm City', - 'Giussano', - 'Otake', - 'Giyani', - 'Chintalapudi', - 'Pando', - 'Big Spring', - 'Gressier', - 'Mathibestad', - 'Columbine', - 'Sao Joaquim', - 'Fleetwood', - 'Boscoreale', - 'Bournville', - 'Masrakh', - 'Elk River', - 'San Sebastian Coatan', - 'Putignano', - 'Gembloux', - 'Mannachchanellur', - 'Maevatanana', - 'Santa Perpetua de Moguda', - 'Krishnapuram', - 'Dano', - 'Jaynagar-Majilpur', - 'Cesenatico', - 'Grandview', - 'Azacualpa', - 'Hjorring', - 'Tubize', - 'La Garde', - 'Grevena', - 'Haoping', - 'Lucenec', - 'Mimoso do Sul', - 'El Jicaro', - 'Formosa do Rio Preto', - 'Gilarchat', - 'Demre', - 'Teniente Primero Manuel Irala Fernandez', - 'Chevella', - 'Bessemer', - 'El Quetzal', - 'Kibeho', - 'Noicattaro', - 'Galatina', - 'Dhrol', - 'Omachi', - 'Vimercate', - 'Colleyville', - 'Vesala', - 'Jharka', - 'Marmara Ereglisi', - 'Unterhaching', - 'Boureit', - 'Jenks', - 'Fonte Boa', - 'Chanhassen', - 'Ciempozuelos', - 'Santa Isabel do Rio Negro', - 'Perunkalattu', - 'Ban Pa Sak', - 'Kotal', - 'Port Alfred', - 'Amnat Charoen', - 'Alacam', - 'Calpe', - 'Gokarn', - 'Ciudad Altamirano', - 'Triggiano', - 'Calilabad', - 'Lindau', - 'Dondon', - 'Canarana I', - 'Artvin', - 'Yuanchang', - 'Suitland', - 'Inkster', - 'Vitez', - 'Nagai', - 'Gradignan', - 'Assemini', - 'Schleswig', - 'Andasibe', - 'San Vicente de Canete', - 'Polasara', - 'Shenley Brook End', - 'Fort Washington', - 'Karkala', - 'Lanaken', - 'Kulmbach', - 'Korkut', - 'Aurillac', - 'Vignola', - 'Vayakkalattu', - 'Maracana', - 'Consett', - 'Raman', - 'Marco', - 'Kadamalaikkundu', - 'Koko', - 'Alboraya', - 'Ladkhed', - 'Nechi', - 'Kunisakimachi-tsurugawa', - 'Le Ray', - 'Vichy', - 'Maintirano', - 'Mungaoli', - 'Chhota Udepur', - 'Tubay', - 'Rockville Centre', - 'Santo Cristo', - 'Marshfield', - 'Pura', - 'Helmstedt', - 'Karavaram', - 'Conversano', - 'Koba', - 'Arapoti', - 'Wagrowiec', - 'Bishunpur Sundar', - 'Seondha', - 'Natividad', - 'Novelda', - 'Paveh', - 'Zakopane', - 'Cherukolattur', - 'Biarritz', - 'Talisayan', - 'Chinna Salem', - 'Firmat', - 'Brevnov', - 'Vorkadi', - 'Halfmoon', - 'Koper', - 'Coffs Harbour', - 'San Antonio del Sur', - 'Horb am Neckar', - 'Ginan', - 'Tecax', - 'Villanueva de la Serena', - 'Bema', - 'Haskoy', - 'Yinajia', - 'Felipe Carrillo Puerto', - 'Lapao', - 'Arida', - 'Lourinha', - 'Tabina', - 'Nea Filadelfeia', - 'Mpophomeni', - 'Bandar-e Deylam', - 'Palm River-Clair Mel', - 'Ban Piang Luang', - 'Rinteln', - 'Klodzko', - 'New Milton', - 'Tarangnan', - 'Santeramo in Colle', - 'Lower Providence', - 'Nanpingcun', - 'Jardin America', - 'Zhutailing', - 'Mogtedo', - 'Haisyn', - 'Carahue', - 'Champs-Sur-Marne', - 'Coulsdon', - 'Nova Prata', - 'Diebougou', - 'Safipur', - 'Nagod', - 'Scandiano', - 'Huejotzingo', - 'Ellwangen', - 'Netapur Tanda', - 'Pereira Barreto', - 'Fenoarivo', - 'Malanguan', - 'Lamzoudia', - 'Fort Beaufort', - 'Santa Lucia La Reforma', - 'Tosa', - 'Batabano', - 'Friedrichsdorf', - 'Ligang', - 'Toin', - 'Pace', - 'Sagara', - 'Imatra', - 'Siqba', - 'Kanchanaburi', - 'Oulad Said', - 'Voorschoten', - 'Doba', - 'Haql', - 'Yolombo', - 'Foughala', - 'Sao Sebastiao da Boa Vista', - 'Altavas', - 'West Chicago', - 'Phulpur', - 'Nanminda', - 'Kesla', - 'Geretsried', - 'Francavilla al Mare', - 'Trussville', - 'Alegria', - 'Busuanga', - 'Tumwater', - 'Igaci', - 'Utena', - 'Kako', - 'Farnham', - 'Valdagno', - 'Migdal Ha`Emeq', - "Porto Sant'Elpidio", - 'Inaja', - 'Sliedrecht', - 'Velenje', - 'El Tarf', - 'Genet', - 'Mount Gambier', - 'Tarkeshwar', - 'Sirumugai', - 'Missour', - 'Chainpura', - 'Sankt Wendel', - 'Armentieres', - 'Staunton', - 'Sarkikaraagac', - 'Bilston', - 'Montbeliard', - 'Nagar', - 'Haiwei', - 'Pszczyna', - 'Sao Joao Nepomuceno', - 'Bandiagara', - 'Kami', - 'Raghunathpur', - 'Oliva', - 'Vijapur', - 'Jericoacoara', - 'Alencon', - 'Idstein', - 'Aracoiaba', - 'Abay', - 'Stevens Point', - 'Okemos', - 'Ipameri', - 'Onda', - 'Niramaruthur', - 'Cliffside Park', - 'Poranki', - 'Shahedshahr', - 'Karayazi', - 'Oltiariq', - 'Witham', - 'Licey al Medio', - 'Rockaway', - 'Tipo-Tipo', - 'Tougue', - 'Vaterstetten', - 'Falconara Marittima', - 'Verl', - 'Salor', - 'Mar de Ajo', - 'Saintes', - 'Ayuquitan', - 'Rottweil', - 'Enna', - 'Brilon', - 'Lopez Jaena', - 'Manyoni', - 'Nettappakkam', - 'Roseto degli Abruzzi', - 'Al `Awwamiyah', - 'Borcka', - 'Xenia', - 'Kocaali', - 'Ciying', - 'Mimasaka', - 'Fujikawaguchiko', - 'Oldbury', - 'Menaceur', - 'Treinta y Tres', - 'Wetteren', - 'Bungku', - 'Backa Palanka', - 'Fort Hood', - 'Sobradinho', - 'Astorga', - 'Mimata', - 'Mannadipattu', - 'Kalispell', - 'Salaga', - 'Oroshaza', - 'South Bradenton', - 'Mahwah', - 'Tupaciguara', - 'Veenoord', - 'Thatcham', - 'Mercer Island', - 'Vistahermosa', - 'Bilgoraj', - 'Agaro', - 'Bathnaha', - 'Bishop Auckland', - 'Kouhu', - 'Silver Springs Shores', - 'Yany Kapu', - 'Unisan', - 'San Pedro Masahuat', - 'Sao Jose do Norte', - 'West Whittier-Los Nietos', - 'Sangerhausen', - 'Moschato', - 'Pauri', - 'Tumbao', - 'Anage', - 'Tres Passos', - 'Brunoy', - 'Rocha', - 'Limonar', - 'Kiranur', - 'Omigawa', - 'Ain Aicha', - 'Nyanza', - 'Szentes', - 'Caloto', - 'Longbridge', - 'Leandro N. Alem', - 'Bloxwich', - 'Peekskill', - 'Nagtipunan', - 'Rouached', - 'Craibas', - 'Vsetin', - 'Chengannur', - 'Perama', - 'Belvidere', - 'Zawyat ech Cheikh', - 'Ohringen', - 'Miyaki', - 'Lamu', - 'Hudson', - 'Demba', - 'Jilikul', - 'Showt', - 'Newberg', - 'Coracao de Jesus', - 'Turek', - 'Luzilandia', - 'Tomares', - 'Holt', - 'Eaubonne', - 'De Pere', - 'Zhongcun', - 'Villeneuve-la-Garenne', - 'Diego Martin', - 'Cherbourg', - 'Roth', - 'Arriaga', - 'Nonahi', - 'Legnago', - 'Upminster', - 'Louis Trichardt', - 'Ottumwa', - 'Thal', - 'Yanyan', - 'Tarpon Springs', - 'Lennestadt', - 'Galt', - 'Vierzon', - 'Hazelwood', - 'Ibirapitanga', - 'San Giovanni Lupatoto', - 'Karunagapalli', - 'Busselton', - 'Norco', - 'Rakovski', - 'Pinal de Amoles', - 'Timurni', - 'Vynohradiv', - 'Jevargi', - 'Wiehl', - 'Requena', - 'Salzkotten', - 'Harbel', - 'Ulongue', - 'Obertshausen', - 'Mill Creek East', - 'Farkhor', - "Giv`at Shemu'el", - 'Lengir', - 'Oupeye', - 'Kovancilar', - 'Susehri', - 'Ula', - 'Arzignano', - 'Caledonia', - 'Belen de Umbria', - 'San Juan de Alicante', - 'Denizciler', - 'Babra', - 'Forney', - 'Camillus', - 'Budai', - 'Sebastian', - 'Tanabi', - 'Kirkby in Ashfield', - 'Kingsville', - 'Seriate', - 'Merkanam', - 'Ludinghausen', - 'Wadi', - 'Mariano Comense', - 'Choconta', - 'Weingarten', - 'Bouknadel', - 'Kawlin', - 'Albergaria-a-Velha', - 'Elkridge', - 'Acatlan', - "Topol'cany", - 'Reedley', - 'Candido Sales', - 'Delitzsch', - 'Chardonnieres', - 'Talugtug', - 'Camalaniugan', - 'Fengruncun', - 'Chiromo', - 'Barstow', - 'Ganshoren', - 'Almonte', - 'Ilaiyankudi', - 'Mudgal', - 'Atlatlahucan', - 'Pfungstadt', - 'Bacoli', - 'Miahuatlan', - 'Tipasa', - 'Mananjary', - 'Petershagen', - 'Wumayingcun', - 'Sandona', - 'Sastamala', - 'Avon Lake', - 'Apiai', - 'Workington', - 'Guene', - 'Allendale', - 'Urucui', - 'Maaseik', - 'Brodosqui', - 'Somoniyon', - 'Saranga', - 'Taquari', - 'Adra', - 'Saydnaya', - 'Uttaramerur', - 'Kingswinford', - 'Kola', - 'Villarrobledo', - 'Latehar', - 'Gole', - 'Chekfa', - 'Sarrat', - 'Erlun', - 'Piranhas', - 'Paonta Sahib', - 'Tirora', - 'Norden', - 'University Park', - 'Fish Hawk', - 'Melrose Park', - 'Banhatti', - 'Walker', - 'Espelkamp', - 'Malyn', - 'El Calafate', - 'Jutai', - 'Overijse', - 'Aridagawa', - 'Barberton', - 'Raahe', - 'Monreal', - 'El Ghiate', - 'Fatime', - 'Vasudevanallur', - 'Carteret', - 'Alamo', - 'Debila', - 'Bagno a Ripoli', - 'Moses Lake', - 'Bardsir', - 'Dedham', - 'Rhyl', - 'Gulam', - 'Kasrawad', - 'Ditzingen', - 'Wewak', - 'Panagar', - 'Aimores', - 'Campos Sales', - 'Otuzco', - 'Pallappatti', - 'North Tustin', - 'Santa Maria Tonameca', - 'Sahibpur Kamal', - 'Sohwal', - 'Rania', - 'Edgewood', - 'Dickinson', - 'Atuntaqui', - 'Torrelodones', - 'Mombin Crochu', - 'Saiha', - 'Novi Travnik', - 'Namrup', - 'Corsicana', - 'Ashkhaneh', - 'Malangawa', - 'Mequon', - 'Kadavur', - 'Baliqchi', - 'Pagudpud', - 'Iglesias', - 'Sahjanwa', - 'Rajakheri', - 'Kongsberg', - 'Vicuna', - 'Bure', - 'Ninohe', - 'Ibiapina', - 'Yapqan', - 'Jafarabad', - 'Safsaf', - 'Correggio', - 'Soccorro', - 'Muskego', - 'Beersel', - 'Duiven', - 'Oegstgeest', - 'Sumperk', - 'Shrirangapattana', - 'El Karimia', - 'Muret', - 'Armilla', - 'Bombinhas', - 'Romulus', - 'Steenbergen', - 'Seal Beach', - 'Husi', - 'Waukee', - 'Lanling', - 'Nabinagar', - 'Sohagpur', - 'Charentsavan', - 'Camaligan', - 'Wolfsberg', - 'Whitehaven', - 'Slavutych', - 'Datca', - 'Barwa Sagar', - 'Droitwich', - 'Pangil', - 'Daventry', - 'Quirino', - 'Coin', - "Saint-Ouen-l'Aumone", - 'Bousse', - 'Sao Joao dos Patos', - 'Barki Ballia', - 'Nepomuceno', - 'Simria', - 'Yarmouth', - 'Olpe', - 'Trikodi', - 'Valls', - 'Hukeri', - 'Naubatpur', - 'Ramshir', - 'Maywood', - 'Pathiyanikunnu', - 'Sonzacate', - 'Attili', - 'Paoay', - 'Hindley', - 'Khed Brahma', - 'Vangviang', - 'Ehden', - 'Ampahana', - 'Fidirana', - 'Mahatalaky', - 'Ankazomborona', - 'Antsirabe Avaratra', - 'Catembe', - 'Nijverdal', - 'Santiago de Chuco', - 'Caballococha', - 'Dainyor', - 'Pinhal Novo', - 'Baxdo', - 'Tall Shihab', - 'Zaouiet Sousse', - 'Kamonkoli', - 'Kibuku', - 'Sho`rchi', - 'Araira', - 'Higuerote', - 'Drodro', - 'Dbarwa', - 'Moyale', - 'Portishead', - 'Pitsea', - 'Tegalbuleud', - 'Ayirurpara', - 'Parner', - 'Lalru', - 'Singhana', - 'Kalamner', - 'Sojitra', - 'Madha', - 'Chanasma', - 'Vodurivandlagudem', - 'Khiria Jhansi', - 'Ladol', - 'Kali', - 'Data', - 'Malanvadi', - 'As Saqlawiyah', - 'Shaqlawah', - 'Ash Shunah ash Shamaliyah', - 'Simaria', - 'Nossa Senhora das Dores', - 'Calahorra', - "Mohale's Hoek", - 'Bethune', - 'Sultepec', - 'Ponta de Pedras', - 'Norton Shores', - 'Kabanga', - 'Sidhauli', - 'Westhoughton', - 'Tsaratanana', - 'Tapa', - 'Paduvari', - 'Mardakan', - 'Sandusky', - 'Gajwel', - 'Baindur', - 'Plettenberg', - 'Visby', - 'La Esperanza', - 'Sugar Hill', - 'Paete', - 'Rio Preto da Eva', - 'Bad Oldesloe', - 'Yuzhang', - 'Niscemi', - 'Traralgon', - 'Cuijk', - 'Portalegre', - 'Marneuli', - 'Ixchiguan', - 'Dalupo', - 'Pinillos', - 'Termini Imerese', - 'Mundargi', - 'Tres de Maio', - 'Koumia', - 'Nainpur', - 'Hunucma', - 'Elefsina', - 'Morton Grove', - 'Dimasalang', - 'Montalban', - 'Dugda', - 'Broadstairs', - 'Nogi', - 'Pezinok', - 'Sand', - 'Ixhuatlancillo', - 'Ushtobe', - 'Westchase', - 'Castelnau-le-Lez', - 'Flores Costa Cuca', - 'Minowa', - 'Quisqueya', - 'Westerlo', - 'Sora', - 'Piracanjuba', - 'Loma Linda', - 'Pedro Carbo', - 'Martinopolis', - 'Quispamsis', - 'Schmallenberg', - 'Sahasoa', - 'Meckenheim', - 'Omurtag', - 'Stein', - 'Iki', - 'Denison', - 'Villa Tapia', - 'Kobo', - 'Wasaga Beach', - 'Wujiaying', - 'Karukurti', - 'Watertown', - 'Kalavad', - 'Wyandotte', - 'Edavanakad', - 'Ishii', - 'Jabonga', - 'Perrysburg', - 'Solsona', - 'Fort Dodge', - 'Adis Zemen', - 'Rangapara', - 'Kuna', - 'Maduru', - 'Cherukara', - 'Valambur', - 'Anivorano Avaratra', - 'Liangwu', - 'Sprockhovel', - 'Kerkyra', - 'Ghoti Budrukh', - 'Santa Rita do Passa Quatro', - 'Sirmatpur', - 'Hamme', - 'Gemerek', - 'Turuttikkara', - 'Carolina Forest', - 'Avon', - 'Aso', - 'Ciudad Barrios', - 'Uherske Hradiste', - 'Collingwood', - 'Syke', - 'Basopatti', - 'Piat', - 'Madaoua', - 'General Luna', - 'Riverbank', - 'Thundersley', - 'Kuttampuzha', - 'West Milford', - 'Swiecie', - 'Icatu', - 'Zittau', - 'Khalari', - 'Baarn', - 'Corralillo', - 'Ouaoula', - 'Voorst', - 'Suchitoto', - "Sao Lourenco d'Oeste", - 'Gorleston-on-Sea', - 'Shivganj', - "Bailey's Crossroads", - 'Ardmore', - 'Salanso', - 'Tugaya', - 'Douar Olad. Salem', - 'Guarai', - 'Fontenay-aux-Roses', - 'Zanesville', - 'Pepa', - 'Pweto', - 'Dodola', - 'San Benito', - 'Beifan', - 'Galdacano', - 'San Francisco Zapotitlan', - 'Penistone', - 'Kalayaan', - 'Jamay', - 'Rudolstadt', - 'Tres Isletas', - 'Ban Khamen', - 'Meiningen', - 'Bintuni', - 'Thornaby on Tees', - 'Frederickson', - 'Scotch Plains', - 'Cambre', - 'Kulachi', - 'Patian', - 'Taquaritinga do Norte', - 'Owando', - 'Cloverleaf', - 'Bazarak', - 'Junqueiro', - 'Lutz', - 'Hertford', - 'Zumpango del Rio', - 'Brasil Novo', - 'Delfzijl', - 'Bystrc', - 'Dinuba', - 'Castro Alves', - 'Joao Lisboa', - 'Ma`bar', - 'Zhenbeibu', - 'Gouna', - 'Podaturpeta', - "G'allaorol Shahri", - 'Mairwa', - 'North Potomac', - 'Oga', - 'Saltpond', - 'Kakonko', - 'Baroy', - 'Bainbridge Island', - 'Tamilisan', - 'Raska', - 'Hinis', - 'Jacare', - 'Panapur', - 'Kajiado', - 'Naruto', - 'Patnagarh', - 'Monte Cristi', - 'Stutterheim', - 'Narasingapuram', - 'Shitan', - 'Uaua', - 'Chandili', - 'Miguel Calmon', - 'Kaga Bandoro', - 'Pasighat', - 'Dix Hills', - 'Naduvannur', - 'Eidsvoll', - 'Larvik', - 'Warstein', - 'Greenbelt', - 'Leoben', - 'Burdeos', - 'Newton in Makerfield', - 'Las Cabras', - 'Palakodu', - 'Oleshky', - 'Boquim', - 'Shamgarh', - 'Merelbeke', - 'Bielsk Podlaski', - 'Al Qubbah', - 'Bayonet Point', - 'El Milagro', - 'Ban Bang Phun', - 'Santa Maria do Para', - 'Zwevegem', - 'Ridgeland', - 'Rawson', - 'Navalgund', - 'San Borja', - 'Iacu', - 'Donggangli', - 'Waldshut-Tiengen', - 'Khashuri', - 'Madougou', - 'Pata Kalidindi', - 'Rathenow', - 'Coral Terrace', - 'Etajima', - 'Fatoma', - 'Ramdiri', - 'Oulad Tayeb', - 'Telagh', - 'Auburn Hills', - 'Darende', - 'Condado', - 'Carrascal', - 'Gorantla', - 'Irugur', - 'Selma', - 'Biharamulo', - 'Reserva', - 'Calamar', - 'Ain Kechera', - 'Ronnenberg', - 'Zion', - 'Sept-Iles', - 'Panglong', - 'Carlos A. Carrillo', - 'Bad Mergentheim', - 'Paita', - 'Takhli', - 'Isernhagen-Sud', - 'El Retorno', - 'Tuzluca', - 'Karatas', - 'Tapejara', - 'Libourne', - 'Breclav', - 'Mponela', - 'Guabiruba', - 'Stjordal', - 'Kottapeta', - 'Wierden', - 'Cheruvaranam', - 'Ravansar', - 'Sirkhandi Bhitha', - 'Westford', - 'Markkleeberg', - 'Dungra Chhota', - 'Ain Dfali', - 'Liria', - 'Watsa', - 'Chebba', - 'Cordeiropolis', - 'Amatan', - 'Centerville', - 'Homer Glen', - 'Aklvidu', - 'Zdolbuniv', - 'Qualiano', - 'Hulbuk', - 'Bereket', - 'Haren', - 'Andhra Tharhi', - 'Nij Khari', - 'Dongxiaozhai', - 'Tirumuruganpundi', - 'Parambatt Kavu', - 'Ocara', - 'Waldkraiburg', - 'Pindwara', - 'Ap Khanh Hoa', - 'Dhamnagar', - 'Mahdishahr', - 'Kaynarca', - 'Orly', - 'Hanerik', - 'Khajuraho', - 'Traun', - 'Leland', - 'San Agustin Loxicha', - 'Purwa', - 'Juayua', - 'Baar', - 'Socastee', - 'Gyal', - 'Sahaspur', - 'Cartaxo', - 'Oak Harbor', - 'Sahawar', - 'Nasukarasuyama', - 'Herndon', - 'Wetzikon', - 'Igaracu do Tiete', - 'Attendorn', - 'Zungeru', - 'Olesa de Montserrat', - 'Vinnamala', - 'Bundu', - 'Tamahu', - 'Felixstowe', - 'Ponca City', - 'Qabatiyah', - 'Channagiri', - "'Ain Boucif", - 'Vilankulo', - 'Zhuangwei', - 'Gaz', - 'Garcia Hernandez', - 'Yokadouma', - 'Landover', - 'Sao Sebastiao do Cai', - 'Tres Coroas', - 'North Augusta', - 'Zagan', - 'King of Prussia', - 'Faribault', - 'Mola di Bari', - 'Armiansk', - 'North Laurel', - 'Erandio', - 'Pedra Azul', - 'Oirase', - 'Bay Point', - 'Ramain', - 'Fray Bentos', - 'Minas Novas', - 'Ashwaraopeta', - 'Herzogenaurach', - 'Tirutturaippundi', - 'Abim', - 'Varel', - 'Garhara', - 'Panmana', - 'Itambe', - 'Siofok', - 'Rugeley', - 'Ngorkou', - 'Happy Valley', - 'Le Kremlin-Bicetre', - 'Kings Norton', - 'Tbeng Meanchey', - 'Eysines', - 'Les Irois', - 'Kazincbarcika', - 'Buzen', - 'Port St. John', - 'Benbrook', - 'Putten', - 'Valente', - 'Preah Vihear', - 'Kenndie', - 'Hirriyat Raznah', - 'Pyrgos', - 'Duncan', - 'Birkirkara', - 'Hennenman', - 'Puerto Guzman', - 'Nagarpara', - 'Ambohimasina', - 'West Memphis', - 'Taquarituba', - 'Ruvo di Puglia', - 'Nova Xavantina', - 'Paruthur', - 'Porto de Mos', - 'Le Bouscat', - 'Grombalia', - 'Sagbayan', - 'Kerrville', - 'Horquetas', - 'Canhotinho', - 'Martos', - 'Las Margaritas', - 'Ballenger Creek', - 'Singarayakonda', - 'Ladera Ranch', - 'Tadjmout', - 'Pallapatti', - 'Iringal', - 'Gose', - 'White Bear Lake', - 'Portogruaro', - 'Sarykemer', - 'Ipixuna', - 'Bijawar', - 'Qazi Ahmad', - 'Cedros', - 'Velur', - 'Echemmaia Est', - 'Bedburg', - 'Alfreton', - 'Oud-Beijerland', - 'Freudenstadt', - 'Qianwangcun', - 'Koloriang', - 'Pinheiral', - 'Curacavi', - 'Daksinkali', - 'Barnegat', - 'Ajim', - 'Collinsville', - 'Stassfurt', - 'Radauti', - 'Raisio', - 'Oulad Barhil', - 'Kien Luong', - 'Saint-Laurent-du-Maroni', - 'Saky', - 'Baheri', - 'Almansa', - 'Maharajgani', - 'Volksrust', - 'Zhuchangba', - 'Elmwood Park', - 'Satuba', - 'Nueva Paz', - 'Starkville', - 'South Plainfield', - 'Borre', - 'Carlow', - 'Katrineholm', - 'Wekiwa Springs', - 'Ayanavelikulangara Tekku', - 'Middleborough', - 'Palmetto Bay', - 'Senador Pompeu', - 'Noto', - 'Umga', - 'Zhangshanying', - 'Sao Geraldo do Araguaia', - 'Gazojak', - 'Saint-Nicolas', - 'Lukaya', - 'Tocopilla', - 'Somerset', - 'Mahaiza', - 'Fairfax', - "Douar 'Ayn Dfali", - 'El Salto', - 'Belton', - 'El Factor', - 'Mayang Imphal', - 'uMhlanga Rocks', - 'Lebedyn', - 'Carutapera', - 'Mekla', - 'Nova Soure', - 'Ganzhu', - 'Vettakkaranpudur', - 'North Lynnwood', - 'Qiaomaichuan', - 'Haaksbergen', - 'Freha', - 'Chester-le-Street', - 'Sroda Wielkopolska', - 'Pelham', - 'Jan Kempdorp', - 'El Congo', - 'Calw', - 'Los Barrios', - 'Cabrera', - 'Guatuba', - 'Gotvand', - 'Ubach-Palenberg', - 'Farnley', - 'Ambalamanasy II', - 'Great Sankey', - 'Kariba', - 'Debaltseve', - 'Rodez', - 'Canarana', - 'Calliaqua', - 'Ponneri', - 'Soure', - 'Donmatias', - 'Buwenge', - 'Uchquduq Shahri', - 'Boulsa', - 'Gelemso', - 'Aioun', - 'Feriana', - 'Yukon', - 'Marin', - 'Naravarikuppam', - 'Halikner', - 'Kauswagan', - 'Ortigueira', - 'Quatro Barras', - 'Lagonglong', - 'Fossano', - 'Maksi', - 'Mogalturru', - 'Machachi', - 'Novo Mesto', - 'Magenta', - 'Skawina', - 'Helleland', - 'Forquilha', - 'Golborne', - 'Caibiran', - 'Walcz', - 'Lop Buri', - 'Les Pavillons-sous-Bois', - 'Ukkayapalle', - 'Kosigi', - 'Jaruco', - 'Angatuba', - 'Oguchi', - 'Yoqne`am `Illit', - 'Sehnde', - 'Velingrad', - 'Macia', - 'Liushui', - 'Heiloo', - 'Meyrin', - 'Hingham', - 'Baharly', - 'Rioblanco', - 'Itapora', - 'Bir Jdid', - 'Zapresic', - 'Simpsonville', - 'Marsella', - 'Isa', - 'Setti Fatma', - 'Korostyshiv', - 'Salvaterra', - 'Eisenhuttenstadt', - 'Mairena del Alcor', - 'Loha', - 'Tiruvattar', - 'Emporia', - 'Anjozorobe', - 'Marple', - 'Vrbas', - 'Sundararaopeta', - 'Alwaye', - 'Fishkill', - 'Paraopeba', - 'Anastacio', - 'Upper Providence', - 'Tayyibat al Imam', - 'Wandlitz', - 'Plymstock', - 'Bloomingdale', - 'Espera Feliz', - 'Jaisinghpur', - 'As Sulayyil', - 'Ryde', - 'Qiloane', - 'Areia Branca', - 'Cogua', - 'Monte Siao', - 'Lagoa Grande', - 'Mirandola', - 'Deyr', - 'Montevarchi', - 'Vicente Lopez', - 'Santa Maria Colotepec', - 'Ormskirk', - 'Wadsworth', - 'Goias', - 'Sangrampur', - 'Skoura', - 'Rolling Meadows', - 'Solon', - 'Boo', - 'Mandan', - 'Senboku', - 'Arttuvattala', - 'Mina', - 'Tangcun', - 'Rita', - 'Siswa', - 'Suleswaranpatti', - 'Tegina', - 'Guapi', - 'Bellview', - 'Buritis', - 'Sanando', - 'Jasmine Estates', - 'Saint-Lin--Laurentides', - 'Kourou', - 'Independencia', - 'Pontinha', - 'Koscian', - 'Atar', - 'Veranopolis', - 'Laon', - 'Yadiki', - 'Papillion', - 'Tehri', - 'Soamanandrariny', - 'Ambatotsipihina', - 'Jequitinhonha', - 'Bcharre', - 'Ambohimandroso', - 'Lopary', - 'Antonibe', - 'Antanimieva', - 'Miarinarivo', - 'Tsiatosika', - 'Itigi', - 'Butaleja', - 'Chinobod', - 'Jalolquduq', - 'Sheghnan', - 'Tchibanga', - 'Maheshwar', - 'Payipira', - 'Caazapa', - 'Quellon', - 'Zolochiv', - 'Sikandarpur', - 'Cachoeira do Arari', - 'Cavinti', - 'Pennadam', - 'Huilongping', - 'Barnstaple', - 'Laranjeiras', - 'Plainsboro', - 'General Emilio Aguinaldo', - 'Rickmansworth', - 'Kamiamakusa', - 'Icod de los Vinos', - 'Dabaga', - 'Kyonpyaw', - 'Embarcacion', - 'Laguna Salada', - 'Sao Goncalo do Sapucai', - 'Littleover', - 'Santa Quiteria do Maranhao', - 'Wil', - 'La Valette-du-Var', - 'Goirle', - 'Neduvattur', - 'Ambohimahamasina', - 'Urucurituba', - 'Itaporanga', - 'Juchen', - 'Arbroath', - 'Tsawwassen', - 'Bulusan', - 'Sao Joao da Ponte', - 'Belo Oriente', - 'Sighisoara', - 'Mapoteng', - 'Solin', - 'Wijk bij Duurstede', - 'Puyappalli', - 'Jucas', - 'El Zulia', - 'Douar Bou Tlelis', - 'Ibi', - 'Koulikoro', - 'Manlio Fabio Altamirano', - 'Umbauba', - 'Iraucuba', - 'Usia', - 'Sendamangalam', - 'Hatonuevo', - 'Sao Joao do Paraiso', - 'Buritizeiro', - 'Pompei', - 'Alfter', - 'Zwedru', - 'Porto Franco', - 'Falticeni', - 'Tacaratu', - 'Paxtakor Shahri', - 'Brotas', - 'Mejorada del Campo', - 'Tantoyuca', - 'Tecoluca', - 'Gungu', - 'Hadzici', - 'Matabhanga', - 'Mulgund', - 'Cibitoke', - 'Caversham', - 'Vanersborg', - 'Seveso', - 'Tata', - 'Noqui', - 'Macaparana', - 'Iraquara', - 'Peringuzha', - 'Karian', - 'Strathroy-Caradoc', - 'Subaykhan', - 'Buon Trap', - 'Koilkuntla', - 'Matriz de Camarajibe', - 'Dunleary', - 'Ourikela', - 'Westerstede', - 'Lihe', - 'Herohalli', - 'Mirandela', - 'Oadby', - 'Hopa', - 'Rosemont', - 'Jurh', - 'Caras', - 'Az Zuwaydah', - 'Ksar el Hirane', - 'South Elgin', - 'Webster Groves', - 'Cranford', - 'Chanthaburi', - 'Mulakumud', - 'Limbach-Oberfrohna', - 'Cruzeiro do Oeste', - 'Honda', - 'Annur', - 'Makhmur', - 'San Miguel Ocotenco', - 'Ciudad Serdan', - 'Diest', - 'Atotonilco el Grande', - 'Pao de Acucar', - 'Willoughby', - 'Kasongo-Lunda', - 'Altea', - 'Popovo', - 'Encruzilhada do Sul', - 'Squamish', - 'Douar Ouled Ayad', - 'Novo Aripuana', - 'Thorold', - 'Firuzoba', - 'Kalawit', - 'Carandai', - 'Kuju', - 'Frontignan', - 'Hungund', - 'Kumar Khad', - 'Catigbian', - 'Hodonin', - 'Zawyat an Nwacer', - 'Montgeron', - 'Sulya', - 'Bithar', - 'Farragut', - 'Thiene', - 'Grootfontein', - 'Selydove', - 'El Maknassi', - 'Fada', - 'Gaojiayingcun', - 'Ituango', - 'Dakor', - 'Vallabh Vidyanagar', - 'Stepanavan', - 'El Tejar', - 'Agrestina', - 'Tirumala', - 'Hoh Ereg', - 'Velingara', - 'Dole', - 'Ishiki', - 'Baliguian', - 'Akwatia', - 'Basankusu', - 'Manari', - 'Dobeln', - 'Verukulambu', - 'De Aar', - 'Oldebroek', - 'Kidsgrove', - 'Cullera', - 'Candoni', - 'Santa Apolonia', - 'Limbuhan', - 'Hachimantai', - 'Starnberg', - 'Elukone', - 'East Retford', - 'Lalgudi', - 'Fountain Hills', - 'Avanigadda', - 'Vizela', - 'Birpur', - 'Nocera Superiore', - 'Husum', - 'Huntingdon', - 'Mummidivaram', - 'Stalybridge', - 'Oji', - 'Fria', - 'Pout', - 'Alice Springs', - 'San Giovanni la Punta', - 'Koscierzyna', - 'Waverly', - 'Lebu', - 'Ayancik', - 'Norresundby', - 'Puduva', - 'Dasungezhuang', - 'Devikolam', - 'Karavalur', - 'Khenichet-sur Ouerrha', - 'Rishton', - 'Korbach', - 'Tangalan', - 'Salqin', - 'Chinoz', - 'Stanmore', - 'Nesher', - 'Shama', - 'Sezze', - 'Ayt Mohamed', - 'Southold', - 'Miantso', - 'Maldegem', - 'Droylsden', - 'San Juan Cotzocon', - 'Gelnhausen', - 'Silappadi', - 'Patterson', - 'Tirukkalikkunram', - 'Anupshahr', - 'Shelbyville', - 'Cazones de Herrera', - 'Sanaur', - 'Santo Antonio do Sudoeste', - 'Muscatine', - 'Dalyoni Bolo', - 'Champlin', - 'Orleaes', - 'Conil de la Frontera', - 'Lubliniec', - 'Alangulam', - 'Yellapur', - 'Roseburg', - 'Perry Barr', - 'Conde', - 'Pirai do Sul', - 'Raritan', - 'Dunaharaszti', - 'Ahualulco de Mercado', - 'Bang Sao Thong', - 'Chandrakona', - 'Bafilo', - 'Tecali', - 'Taupo', - 'Beni Amrane', - 'Berhoum', - 'Gosforth', - 'Mannamturuttu', - 'Satun', - 'Santa Gertrudes', - 'Kenmore', - 'Yesagyo', - 'Gueznaia', - 'Mountain House', - 'Askale', - 'Tapiales', - 'Ogawara', - 'Kulgam', - 'Jacksonville Beach', - 'Truro', - 'Kyeintali', - 'Kebila', - 'Oostkamp', - 'Newton Abbot', - 'Lustenau', - 'Perungudi', - 'Dakovo', - 'San Martin Totolan', - 'Cerro Azul', - 'Amstetten', - 'San Ignacio de Velasco', - 'Monsefu', - 'Tamandare', - 'Toda Rai Singh', - 'Peravur', - 'Bauta', - 'Castiglione delle Stiviere', - 'Heverlee', - 'Gollapudi', - 'Dhing', - 'Ma`alot Tarshiha', - 'Codajas', - 'Luninyets', - 'Belsand', - 'Gerede', - 'Bambui', - 'Salzwedel', - 'Bishopbriggs', - 'Kaltenkirchen', - 'Sao Miguel', - 'Khelil', - 'Nyuzen', - 'Xiaojiangcun', - 'Jaleshwar', - 'Yangi Marg`ilon', - 'Hannoversch Munden', - 'Brookings', - 'Dumaran', - 'Honavar', - 'General Panfilo Natera', - 'Amherstburg', - 'Nixa', - 'Funes', - 'Canalete', - 'Ban Phru', - 'Cupira', - 'At Tafilah', - 'Watauga', - 'Marshall', - 'Sonneberg', - 'Loon op Zand', - 'Kaniv', - 'Mujui dos Campos', - 'Muang Sing', - 'Quarai', - 'Arukutti', - 'Suonan', - 'Nayanakulam', - 'Lisle', - 'Ringsted', - 'Pakil', - 'Port Laoise', - 'Jocotenango', - 'Cuyo', - 'Padre Burgos', - 'Gardner', - 'Cesky Tesin', - 'Griffin', - 'Mosbach', - 'Matinha', - 'Dillenburg', - 'Oued el Djemaa', - 'Koili Simra', - 'Yugawara', - 'Carmo do Cajuru', - 'Bloemendaal', - 'Chanaur', - 'Gauripur', - 'Francisco Sa', - 'Oulad Hassoune', - 'Hajduszoboszlo', - 'Kharupatia', - 'Maple Heights', - 'Maharlika Village', - 'Monte Caseros', - 'Krychaw', - 'Les Lilas', - 'Kyenjojo', - 'Bonoufla', - 'Dank', - 'Tapaktuan', - 'Muggio', - 'Sanga', - 'Brody', - 'Sinj', - 'Beni Rached', - 'Madangir', - 'Kedainiai', - 'Minamikarasuyama', - 'Chrudim', - 'Copiague', - "L'Assomption", - 'Rampura', - 'Gjirokaster', - 'Nasu', - 'Bni Frassen', - 'Elburg', - 'Pilar de la Horadada', - 'Kilindoni', - 'Badnawar', - 'Raul Soares', - 'Pissila', - 'Maychew', - 'Sattahip', - 'Kailashahar', - 'Vega Baja', - 'Pesochin', - 'Srvanampatti', - 'Santa Rosa de Viterbo', - 'Teguise', - 'Veinticinco de Mayo', - 'Senftenberg', - 'Havlickuv Brod', - 'Van Buren', - 'Burhar', - 'Galikesh', - 'Ban Thoet Thai', - 'Svilajnac', - 'Kafr Shukr', - 'Makouda', - 'Meda', - 'Sluis', - 'Teorama', - 'Ponda', - 'Albenga', - 'Akkus', - 'Giulianova', - 'Vanimel', - 'Gamay', - 'Bultfontein', - 'Netphen', - 'Canico', - 'Rock Springs', - 'Barbasa', - 'Beni Khalled', - 'Quang Tri', - 'Pottstown', - 'Dighwa', - 'Sakleshpur', - 'Montecchio Maggiore', - 'Pitea', - 'Takehara', - 'Sandwa', - 'Caglayancerit', - 'Pindoretama', - 'Leutkirch im Allgau', - 'Tazhava', - 'Madappalli', - 'Sokolo', - 'Maigo', - 'Westerly', - 'Piravanthur', - 'Saint-Ghislain', - 'Mandawa', - 'Antanimasaka', - 'Coronel Vivida', - 'Cide', - 'Cadca', - 'Dongshi', - 'Berehove', - 'Zemst', - 'Doctor Mora', - 'Warburg', - 'Collipulli', - 'Ambohimiadana', - 'Horgen', - 'Minja', - 'Sai Mai', - 'Dalmine', - 'Pelitli', - 'Capinzal', - 'Quedlinburg', - 'Ron', - 'Calbiga', - 'North Platte', - 'Bazhajiemicun', - 'Phongsali', - 'Moskva', - 'Tecumseh', - 'Tugatog', - 'Tobati', - 'Ardahan', - 'Lormont', - 'Bordj Ghdir', - 'Niskayuna', - 'Anatuya', - 'Goumori', - 'Aldeias Altas', - 'La Cruz de Rio Grande', - 'Poxoreo', - 'Carambei', - 'San Rafael Abajo', - 'Whitefield', - 'Kedavur', - 'Piastow', - 'Alhama de Murcia', - 'Rathfarnham', - 'Monteros', - 'Gersthofen', - 'Teodoro Sampaio', - 'Mulampilli', - 'Camp Springs', - 'Telica', - 'Abaete', - 'Linda', - 'Cajidiocan', - 'Tekari', - 'Martha Lake', - 'La Higuerita', - 'La Huerta', - 'Maibog', - 'Alliston', - 'Ulukisla', - 'Piritu', - 'Cockeysville', - 'Ozuluama de Mascarenas', - 'Santo Antonio de Posse', - 'Motul', - 'Mine', - 'Phetchaburi', - 'Xunjiansi', - 'Vaikam', - 'Mantua', - 'Cottage Lake', - 'Raymore', - 'Selim', - 'Kun Puhal', - 'Pickerington', - 'Calamba', - 'Loanda', - 'Nuku`alofa', - 'Samrala', - 'Mizdah', - 'Culion', - 'Kedia', - 'Sheyban', - 'Nakashunbetsu', - 'Cambara', - 'Fergus', - 'Kelishad va Sudarjan', - 'Patakakani', - 'Amarapura', - 'Sevan', - 'Manambur', - 'Touboro', - 'Wertheim', - 'Wareham', - 'Tranquebar', - 'Kazhukambalam', - 'Capoterra', - 'Bassar', - 'Rastede', - '`Ali Shahr', - 'Nova Petropolis', - 'Vilaseca de Solcina', - 'Vukovar', - 'Ponmundam', - 'Kannamangalam Tekku', - 'Union Hill-Novelty Hill', - 'Eastmont', - 'Karben', - 'Tototlan', - 'Pajapita', - 'Kouoro', - 'Tukrah', - 'Ashland', - 'Conceicao do Mato Dentro', - 'Bad Soden am Taunus', - 'Vreden', - 'Apatin', - 'Minamata', - 'Puenteareas', - 'Zarautz', - 'Sonepur', - 'Ribas do Rio Pardo', - 'Ban Bang Rin', - 'Abreus', - 'Bialogard', - 'Ravulapalem', - 'New Brighton', - 'Edgewater', - 'Planalto', - 'Easley', - 'Shuilin', - 'Bananeiras', - 'Douar Imoukkane', - 'Puerto Concordia', - 'Soledad Atzompa', - 'Neihuzhai', - 'Trotwood', - 'Litomerice', - 'Sao Mamede de Infesta', - 'Manage', - 'Mahthi', - 'Tamiahua', - 'Caba', - 'West Goshen', - 'Ottaviano', - 'Yasica Arriba', - 'Rafael Delgado', - 'Liberty Triangle', - 'Los Arabos', - 'Sansanding', - 'Singhara Buzurg', - 'Fanzeres', - 'Chantilly', - 'Calabasas', - 'Vuliyattara', - 'Cartersville', - 'Sonari', - 'Engandiyur', - 'Eustis', - 'Roxbury', - 'Tupiza', - "Qiryat Mal'akhi", - 'Hombori', - 'Uberlingen', - 'Oxkutzkab', - 'Morris', - 'Yunak', - 'Rochefort', - 'Sederot', - 'Mujiayu', - 'Khirkiyan', - 'Rucphen', - 'Siwah', - 'Maisons-Laffitte', - 'Vilachcheri', - 'Qiryat Shemona', - 'Tnine Lgharbia', - 'Apolda', - 'Vigonza', - 'Bear', - 'Saint-Dizier', - 'Pallikondai', - 'Yakinca', - 'Roissy-en-Brie', - 'Orbassano', - 'Catano', - 'Asafabad', - 'Coueron', - 'Weilheim', - 'Dom Pedro', - 'Nagykoros', - 'Lunbei', - 'Warragul', - 'Achi', - 'Koussane', - 'Velugodu', - 'Penwortham', - 'Youwarou', - 'Devonport', - 'Hopewell', - 'Dunajska Streda', - 'Auch', - 'Thiotte', - 'Buyende', - 'Upper Allen', - 'Bad Kissingen', - 'Koiri Bigha', - 'Fernley', - 'Mangidy', - 'Copertino', - 'Bataguacu', - 'Anjarkandi', - 'Oliveira do Bairro', - 'San Andres de Giles', - 'Nova Milanese', - 'Lanester', - 'Shiling', - 'Tembagapura', - 'Lysander', - 'Tubungan', - 'Curumani', - 'Kulattuppalaiyam', - 'Ladner', - 'Novy Jicin', - 'Glassboro', - 'Bad Salzungen', - 'Loos', - 'Khaira Tola', - 'Ban Bang Krang', - 'Taylors', - 'Harborne', - 'Ka-Bungeni', - 'Carletonville', - 'Majdel Aanjar', - 'Ambohitrarivo', - 'Mahela', - 'Farahalana', - 'Analamisampy', - 'Ambohitoaka', - 'Miantsoarivo', - 'Ankaramy', - 'Marovato', - 'Ankilizato', - 'Andalatanosy', - 'Kungsbacka', - 'Gyegu', - 'Zhaoling', - 'Rawtenstall', - 'Dindori', - 'Candiac', - 'Despotovac', - 'Wichian Buri', - 'Stoneham', - 'Panelas', - 'Wallenhorst', - 'Niamtougou', - 'Manlin', - 'Nagold', - 'Ivoti', - 'Mobetsu', - 'Lisse', - 'Radcliff', - 'Lengerich', - 'Vandiperiyar', - 'Lagoa', - 'Yaguachi Nuevo', - 'Tighedouine', - 'Malinalco', - 'Labuleng', - 'Essa', - 'Brent', - 'Latauna', - 'Sandviken', - 'Manuel B. Gonnet', - 'Minbu', - 'Encantado', - 'Frederikshavn', - 'Searcy', - 'Nikaho', - 'Moguer', - 'Dabeiba', - 'Crystal', - 'Las Brenas', - 'Scherpenheuvel', - 'Nocatee', - 'Kamabougou', - 'Manghit', - 'Christiansburg', - 'Friesoythe', - 'Kitzingen', - 'Muttupet', - 'Mekhe', - 'Hollola', - 'Abu', - 'Laguna Beach', - 'Molodohvardiisk', - 'Znamianka', - 'Nijlen', - 'Huaibaijie', - 'Loves Park', - 'Blue Island', - 'Swinton', - 'Peters', - 'Manosque', - 'Famailla', - 'Prairie Village', - 'Bathgate', - 'Itaocara', - 'Biancavilla', - 'Pul-e `Alam', - 'Kilkis', - 'Dafni', - 'Market Harborough', - 'Nyakrom', - 'Wulongpu', - 'Edewecht', - 'Dialakoroba', - 'Dokuchaievsk', - 'Keene', - 'Zdunska Wola', - 'Bhiraha', - 'Shurugwi', - 'Kotido', - 'Vadakarai Kil Pidagai', - 'Ayos', - 'Colorado', - 'Senden', - 'Dorohoi', - 'Fontaine', - 'Trebisov', - 'Losser', - 'Vellalur', - 'Pointe a Raquettes', - 'Ogre', - 'Garoua Boulai', - 'Zeewolde', - 'Ramos', - 'Kalat', - 'Luruaco', - 'Marcinelle', - 'Mahadebnagar', - 'Ekeren', - 'Neusass', - 'Pietrasanta', - 'Viga', - 'Baile Atha Luain', - 'Bhadas', - 'Genzano di Roma', - 'Vale de Cambra', - 'Laupheim', - 'Aracariguama', - 'Nazca', - 'Waltham Abbey', - 'Malacatancito', - 'Patacamaya', - 'Oteiza', - 'Olivet', - 'Azove', - 'Vagos', - 'Hadyach', - 'Ventimiglia', - 'Blangmangat', - 'Krnov', - 'Arcos de Valdevez', - 'Roselle', - 'Villanueva de la Canada', - 'Dammarie-le-Lys', - 'Gainsborough', - 'Machesney Park', - 'Guanajay', - 'Nayagaon', - 'Tadmait', - 'Chitarpur', - 'Naolinco de Victoria', - 'Ecoporanga', - 'Selvazzano Dentro', - 'Qatana', - 'Xinsi', - 'Ahwa', - 'Erdington', - 'Katy', - 'Millbrae', - 'Nogoya', - 'Ondangwa', - 'Pawni', - 'Torre del Mar', - 'Ataco', - 'Bressanone', - 'Gaoshu', - 'Hialeah Gardens', - 'Kagadi', - 'Balen', - 'Tadotsu', - 'Siqueira Campos', - 'Yanshanbu', - 'Barbate de Franco', - 'Camilo Ponce Enriquez', - 'Cherial', - 'Zunheboto', - 'Tomarza', - 'Pulimathu', - 'Corcoran', - 'Beek en Donk', - 'Fangliao', - 'Beshariq', - 'Haywards Heath', - 'Nahiyat al Kifl', - 'Kapfenberg', - 'Brambleton', - 'Pedra', - 'Frascati', - 'Cinco Saltos', - 'Pecan Grove', - 'Aybasti', - 'Achhnera', - 'Lumbatan', - 'Bormujos', - 'Gormi', - 'Sun Valley', - 'Butig', - 'Kungalv', - 'San Jose Ojetenam', - 'Amoucha', - 'Pariyapuram', - 'Kavallemmavu', - 'Kodarma', - 'Kaler', - 'Onondaga', - 'Baravat', - 'Saint-Lambert', - 'Kumano', - 'Herdecke', - 'Linstead', - 'Kanchika', - 'Nasrullahganj', - 'Villa Park', - 'Vernag', - 'San Feliu de Guixols', - 'San Miguel de Papasquiaro', - 'Ivato', - 'Quartier Militaire', - 'Ojinaga', - 'Gobo', - 'Vayanur', - 'Melissia', - 'Ashtown', - 'Keta', - 'Seva', - 'Junction City', - 'Boura', - 'Kulkent', - 'Chunakara Vadakku', - 'Curchorem', - 'Ayagawa', - 'Ravar', - 'Arroyito', - 'Kerur', - 'Garmdarreh', - 'Alnif', - 'Idak', - 'Rosita', - 'Asaita', - 'Byala Slatina', - 'Madira', - 'Volendam', - 'Sidi Lmokhtar', - 'Amalfi', - 'Kittanapalli', - 'Muradpur', - 'Hazel Dell', - 'Velizy-Villacoublay', - 'Ambriz', - 'Feira Grande', - 'Nakur', - 'Bulle', - 'Anthem', - 'The Crossings', - 'Candler-McAfee', - 'Kluczbork', - 'Kapolei', - 'Allison Park', - 'Jarqo`rg`on', - 'Litvinov', - 'North Plainfield', - 'Goldasht', - 'Inhapim', - 'Burg', - 'Dalan', - 'Shaomi', - 'Candelaria de La Frontera', - 'Patharia', - 'Beixingzhuang', - 'Andoany', - 'Mallasamudram', - 'Tequixquiac', - 'Tassin-la-Demi-Lune', - 'Lucala', - 'Moirang', - 'Dip', - 'Oytal', - 'Laguna de Duero', - 'Kitajima', - 'Mullingar', - 'Khaw Zar Chaung Wa', - 'Moncagua', - 'Llaillay', - 'Cudahy', - 'Nanyangcun', - 'East San Gabriel', - 'Lefkada', - 'Bagula', - 'Wednesfield', - 'Prieto Diaz', - 'Stadthagen', - 'Pullappalli', - 'Okahandja', - 'Royken', - 'Zedelgem', - 'Olindina', - 'Areia', - 'Besikduzu', - 'Valasske Mezirici', - 'Chincholi', - 'Fucecchio', - 'Manimala', - 'Morombe', - 'Oltenita', - 'Manzanares', - 'Baraki Barak', - 'Budingen', - 'Sevres', - 'Andorra la Vella', - 'Tocantinopolis', - 'Santa Fe de Antioquia', - 'Timmapur', - 'Fairhope', - 'Montigny-les-Cormeilles', - 'Lajas', - 'Savanna-la-Mar', - 'Hirpardangal', - 'Manki', - 'Abbeville', - 'Fleurus', - 'Farsley', - 'Parabcan', - 'Bouzeghaia', - 'Bonney Lake', - 'Warrenton', - 'Yahualica de Gonzalez Gallo', - 'Valmiera', - 'Furukawa', - 'Dawmat al Jandal', - 'Sardinata', - 'Strakonice', - 'Camacan', - 'Cholavandan', - 'Senador Jose Porfirio', - 'Oshwe', - 'Boriziny', - 'Los Llanos', - 'El Amria', - 'Talayolaparambu', - 'Uenohara', - 'Isperih', - 'Haar', - 'Summit', - 'Souk Tlet El Gharb', - 'Belabo', - 'Raman Mandi', - 'East Peoria', - 'Pokhuria', - 'Letterkenny', - 'Sinjar', - 'Florida Ridge', - 'Tlacolula de Matamoros', - 'Mentana', - 'Vengattur', - 'Kenilworth', - 'Horizon City', - 'Lempaala', - 'Potters Bar', - 'Kafr Batna', - 'Medjez el Bab', - 'Melila', - 'Metzingen', - 'Bobleshwar', - 'Meiwa', - 'Huautla', - 'Katangi', - 'Golhisar', - 'Sarangani', - 'Sabana de Torres', - 'Jogipet', - 'Melchor Romero', - 'Hulikal', - 'Deuil-la-Barre', - 'Mutata', - 'Nadvirna', - 'Corinth', - 'Bafata', - 'Ouani', - 'Kafr Sa`d', - 'Vilcun', - 'Zabrat', - 'Klatovy', - 'Coracao de Maria', - 'Challans', - 'Coralville', - 'San Antonio La Paz', - 'Willowbrook', - 'San Pablo Jocopilas', - 'Lazi', - 'La Madeleine', - 'Ivatsevichy', - 'Nkowakowa', - 'Chavassheri', - 'Foleshill', - 'Mount Pearl Park', - 'Piddig', - 'Yuli', - 'Chatayamangalam', - 'San Juan de Aznalfarache', - 'Emiliano Zapata', - 'Mouila', - 'Kondazhi', - 'Karnobat', - 'Cacule', - 'Baclayon', - 'Ladyzhyn', - 'Buriti Bravo', - 'Puente Nacional', - 'Gan Yavne', - 'Pullanpallikonam', - 'Naawan', - 'Torcy', - 'Esparraguera', - 'Mihama', - 'Biddeford', - 'Aymangala', - 'Moyo', - 'Albertville', - 'Pirajui', - 'Donaueschingen', - 'Naciria', - 'Ottobrunn', - 'Rancho San Diego', - 'Finnkolo', - 'Sarea Khas', - 'Junnardev', - 'Goulburn', - 'Sibut', - 'Formby', - 'Fenyuan', - 'Sipilou', - 'Maying', - 'Kasamatsucho', - 'Jebba', - 'Betsizaraina', - 'Pudsey', - 'Rixensart', - 'Kiboga', - 'Zhengtun', - 'Zurbatiyah', - 'Gujan-Mestras', - 'Macas', - 'Bermo', - 'Quissama', - 'Barreira', - 'Freire', - 'Szczytno', - 'Taishituncun', - 'Sevlievo', - 'Gonghe', - 'Hartbeespoort', - 'Kato Polemidia', - 'Mechta Ouled Oulha', - 'Lindsay', - 'Ibatiba', - 'Perundurai', - 'Montville', - 'Arouca', - 'Central Falls', - 'Rumphi', - 'Ivrea', - 'Bad Rappenau', - 'Saint-Lazare', - "Arbi'a Tighadwiyn", - 'Diriomo', - 'Gif-sur-Yvette', - "Sek'ot'a", - 'Sabuncu', - 'Cedro', - 'Waynesboro', - 'Loei', - 'Gurmatkal', - 'Carouge', - 'Lyndhurst', - 'Gilan-e Gharb', - 'Kadiria', - 'Sambhar', - 'El Tortuguero', - 'Guerou', - 'Taulaha', - 'Natagaima', - 'Bhawanigarh', - 'Ceccano', - 'Acworth', - 'Owen Sound', - 'Lyman', - 'Frauenfeld', - 'Chinameca', - 'Daxin', - 'DeBary', - 'Panniyannur', - 'El Doncello', - 'Prantij', - 'Gornji Vakuf', - 'Guia de Isora', - 'Bundibugyo', - 'Qorako`l Shahri', - 'Lochristi', - 'Piuma', - 'Phichit', - 'Montilla', - 'March', - 'Rosiori de Vede', - 'Pozega', - 'Brockville', - 'Tiverton', - 'Braine-le-Comte', - 'Laja', - 'Cayo Mambi', - 'Sanso', - 'Digor', - 'Pale', - 'Ruston', - 'Brushy Creek', - 'Bartoszyce', - 'Valenca do Piaui', - 'Monte Aprazivel', - 'Cisnadie', - 'Had Sahary', - 'Oyonnax', - 'Zhucaoying', - 'Maracena', - 'Shoeburyness', - 'Versmold', - 'Chankou', - 'Yokoshibahikari', - 'Lordelo do Ouro', - 'Palaw', - 'Ugong', - 'Palmer', - 'Tiruttangal', - 'Senekane', - 'Hillside', - 'Telsiai', - 'Edegem', - 'Aljaraque', - 'Montereau-faut-Yonne', - 'Mountain Brook', - 'Nagla', - 'Ankireddikuntapalem', - 'Bhatpuri', - 'Chausa', - 'Marina', - 'Singampunari', - 'Itsukaichi', - 'El Hermel', - 'Karacoban', - 'Athiringal', - 'Tervuren', - 'El Colegio', - 'Kihei', - 'Silvania', - 'Souahlia', - 'Alangayam', - 'Bahce', - 'Litherland', - 'Takahata', - 'Koziatyn', - 'Kheiredine', - 'Combs-la-Ville', - 'West Carson', - 'Bignona', - 'Picasent', - 'Huangzhai', - 'Yeadon', - 'Silver Firs', - 'Ibia', - 'Yahualica', - 'Kundgol', - 'Sao Filipe', - 'Sokolov', - 'Herouville-Saint-Clair', - 'Eppingen', - 'Ingabu', - 'Metekora', - 'Radevormwald', - 'Murayama', - 'Sharunah', - 'Swiebodzice', - "Saint John's", - 'Dasnapur', - 'Poggiomarino', - 'Acomb', - 'Abu Sir Bana', - 'Khorabar', - 'Bahia de Caraquez', - 'Ortona', - 'Topola', - 'Tiruverumbur', - 'Ilsede', - 'Zirapur', - 'Sunny Isles Beach', - 'Samtredia', - 'Tirat Karmel', - 'West Deptford', - 'Hillegom', - 'Rioja', - 'Guazacapan', - 'Soroca', - 'Repelon', - 'Medeiros Neto', - 'Adalhat', - 'Yavuzeli', - 'Chalmette', - "'s-Gravenzande", - 'Surdulica', - 'Sandomierz', - 'McNair', - 'Kondalampatti', - 'Phularwan', - 'Pattiyurgramam', - 'Las Torres de Cotillas', - 'Haderslev', - 'Gubbi', - 'Shabestar', - 'Granite Bay', - 'Gumushacikoy', - 'Kilkenny', - 'Bakhri', - 'Maribojoc', - 'Yabu', - 'Nova Zagora', - 'Sulmona', - 'Guabo', - 'Qarazhal', - 'Goleniow', - 'Mbaiki', - 'Jiangdi', - 'Chestermere', - 'Les Pennes-Mirabeau', - 'Salvaterra de Magos', - 'Batad', - 'Vellithiruthi', - 'Paraguari', - 'Takelsa', - 'Ghriss', - 'Sarapaka', - 'Aleksandrow Lodzki', - "Sant'Arcangelo di Romagna", - 'Ensley', - 'Vayalar', - 'Katkol', - 'Bhanvad', - 'Golden Valley', - 'West Rancho Dominguez', - 'Ban Pa Tueng', - 'World Golf Village', - 'Pirmed', - 'Waldkirch', - 'Reigate', - 'Lower', - 'Phetchabun', - 'Pingtan', - 'Bourkika', - 'Ramona', - 'Fantino', - 'Bellavista', - 'Sahil', - 'Tabursuq', - 'Talwandi Sabo', - 'Heide', - 'Livadeia', - 'Salemata', - 'Krolevets', - 'Qapqal', - 'Cunha', - 'Namayumba', - 'Caojiachuan', - 'Doutou', - 'La Cruz', - 'Palmital', - 'Hallim', - 'Smithfield', - 'Argos', - 'Peravurani', - 'Huejucar', - 'Pailitas', - 'Penarth', - 'Howli', - 'Ocatlan', - 'Muelle de los Bueyes', - 'Husnabad', - 'Hoogezand', - 'Vilnohirsk', - 'Taixi', - 'Timbiqui', - 'Horley', - 'Newquay', - 'Camborne', - 'West Puente Valley', - 'Kalchini', - 'Estcourt', - 'Eschborn', - 'Karlsfeld', - 'Yorosso', - 'Qift', - 'Palestrina', - 'Schwetzingen', - 'Imbert', - 'Parsagarhi', - 'Hamidiyeh', - 'Gardelegen', - 'Adampur', - 'Chhanera', - 'Itaiopolis', - 'Madamba', - 'Lorton', - 'Rimavska Sobota', - 'Polygyros', - 'Kalyves Polygyrou', - 'Northwood', - 'Aswapuram', - 'Khandela', - 'Karaisali', - 'Tiquisio', - 'Dongta', - 'Mondovi', - 'East Ridge', - 'Carbondale', - 'Ruwa', - 'Jizhuang', - 'Sapulpa', - 'Banbishancun', - 'Woensdrecht', - 'Jawad', - 'Naregal', - 'Dubnica nad Vahom', - 'Elsdorf', - 'Corail', - 'Dioumanzana', - 'Anini-y', - 'Taveta', - 'Comacchio', - 'Meixedo', - 'Ostrow Mazowiecka', - 'Tola', - 'Greystones', - 'Uliastay', - 'Paese', - 'Priego de Cordoba', - 'Chillicothe', - 'Epernay', - 'Jugial', - 'Ghat', - 'Manakambahiny', - 'Ambodimotso Atsimo', - 'Ampasimanjeva', - 'Iarintsena', - 'Andranovorivato', - 'Bemanonga', - 'Vohimasina', - 'Andilanatoby', - 'Alakamisy-Ambohimaha', - 'Ambalaroka', - 'Jafaro', - 'Ankiabe-Salohy', - 'Antsakabary', - 'Uch Sharif', - 'Lebane', - 'Huskvarna', - 'Kigumba', - 'Haci Zeynalabdin', - 'Aoshang', - 'Atherton', - 'Clevedon', - 'Bukkarayasamudram', - 'Machagai', - 'Unchahra', - 'God', - 'Zundert', - 'Dras', - 'Gavimane', - 'Taminango', - 'Bilthoven', - 'Al Bahah', - 'Pitrufquen', - 'Nema', - 'Pinhalzinho', - 'Khosrowshahr', - 'Ampanotokana', - 'Iracemapolis', - 'San Rafael del Yuma', - 'Djinet', - 'Robbah', - 'Arroio do Meio', - 'Kuppam', - 'Koekelberg', - 'Vertentes', - 'Koksijde', - 'Dudelange', - 'Villa de Leyva', - 'Darien', - 'Serro', - 'Valinda', - 'Glauchau', - 'Chakia', - 'Pocharam', - 'Diamantino', - 'Mundamala', - 'New Hartford', - 'Ramantali', - 'Harim', - 'Ap Phu My', - 'Robertson', - 'Tornio', - 'Nakagusuku', - 'Samba Cango', - 'Mazagao', - 'Chambersburg', - 'Sandbach', - 'Chalchihuitan', - 'Axapusco', - 'Itubera', - 'Nerja', - 'Mako', - 'Gotsucho', - 'St. Andrews', - 'Aichach', - 'Al Fuhays', - 'Krathum Baen', - 'Pascagoula', - 'Pak Tin Pa', - 'Bungotakada', - 'Membakut', - 'Sao Miguel do Araguaia', - 'Sayada', - 'Kachhari', - 'Darreh Shahr', - 'Beguedo', - 'Sao Francisco de Paula', - 'Lom', - 'Muzambinho', - 'Vanthli', - 'Kueneng', - 'Povoa de Lanhoso', - 'Pio XII', - 'Caranavi', - 'Alfafar', - 'Frameries', - 'North Salt Lake', - 'Almoradi', - 'Shinhidaka', - 'Montmorency', - 'Maghalleen', - 'Karlovo', - 'New Castle', - 'Sonthofen', - 'Sainte-Foy-les-Lyon', - 'Montigny-les-Metz', - 'Renfrew', - 'Komlo', - 'Florsheim', - 'Gigaquit', - 'Binnish', - 'Tongzhou', - 'Kafr Qasim', - 'Port Hueneme', - 'Rajauli', - 'Massapequa', - 'Mata Grande', - 'Lihuzhuang', - 'Mbandjok', - 'Otsuki', - 'Kocarli', - 'Los Palmitos', - 'Muhlenberg', - 'Machico', - 'Kepsut', - 'Mangalvedha', - 'Yoshioka', - 'Santa Teresa', - 'Danwan', - 'Puttige', - 'Belper', - 'Soyagaon', - 'Columbia Heights', - 'Hayesville', - 'Horad Smalyavichy', - 'Kizhakkemanad', - 'Ginosa', - 'Sheldon', - 'Mehnatobod', - 'De Meern', - 'Ginebra', - 'Azambuja', - 'Ouardenine', - "Ma'muniyeh", - 'Pallippuram', - 'Amtali', - 'Orobo', - 'Soltau', - 'Pueblo Juarez', - 'Amposta', - 'Muzhakkunnu', - 'Parsippany', - 'Klamath Falls', - 'Kreuzlingen', - 'Plonsk', - 'Looc', - 'Manor', - 'Palmas de Monte Alto', - 'Poco Verde', - 'Siilinjarvi', - 'Santa Lucia Utatlan', - 'Yate', - 'Morinda', - 'Polkowice', - 'Charo', - 'Ad Dabyah', - 'Ad Dali`', - 'Le Petit-Quevilly', - 'Jaynagar', - 'Puruk Cahu', - 'Tuneri', - 'Had Oulad Issa', - 'Ambatomanoina', - 'Hassi Maameche', - 'Langley Park', - 'Silverdale', - 'Sidi Amrane', - 'Surpur', - 'Bhanpura', - 'Gulsehir', - 'Geertruidenberg', - 'El Callao', - 'Chatra Gobraura', - 'Kayanza', - 'Sedalia', - 'Maniche', - 'Mailavaram', - 'Selden', - 'Seia', - 'South Euclid', - 'Zara', - 'Otopeni', - 'Notteroy', - 'Penonome', - 'Oberwingert', - 'Shendurjana', - 'Cagwait', - 'Sarai Ranjan', - 'Chapa de Mota', - 'Puerto Triunfo', - 'Eislingen', - 'Hockenheim', - 'Banapur', - 'Zoersel', - 'Guipos', - 'Bad Harzburg', - 'Chimore', - 'Anamalais', - 'Shanywathit', - 'Sori', - 'Kurikka', - 'Kalleribhagam', - 'Massarosa', - 'Vamanapuram', - 'Miguelopolis', - 'Comalapa', - 'Zabre', - 'Mezdra', - 'Yaojiazhuangcun', - 'Yaojiafen', - "Erval d'Oeste", - 'Idukki', - 'Tixtla de Guerrero', - 'Vendram', - 'Moulares', - 'Wadenswil', - 'Bankoumana', - 'Caransebes', - 'Pachino', - 'Sao Joao da Madeira', - 'Alhandra', - 'Millau', - 'Shelby', - 'Guapiacu', - 'Port Alberni', - 'Kozakai-cho', - 'Pampierstad', - 'Tidili Masfiywat', - 'Chagallu', - 'Sombrerete', - 'Springwater', - 'Eyl', - 'Saint-Jean-de-Braye', - 'Biggleswade', - 'Yucca Valley', - 'Chaumont', - 'Millburn', - 'Assare', - 'Muhldorf', - 'Paramirim', - 'Kavak', - 'Qadirganj', - 'Duarte', - 'Geseke', - 'Bad Krozingen', - 'Kadiapattanam', - 'Can-Avid', - 'Del City', - 'Pampur', - 'Al Karak', - 'Sirat', - 'Ocotlan de Morelos', - 'Tigbao', - 'San Luis Talpa', - 'Gallup', - 'Kangal', - 'Koprivnice', - 'American Canyon', - 'Senda', - 'Zantiebougou', - 'Ibicarai', - 'Lindlar', - 'Bailleston', - 'Gros Islet', - 'Nangavaram', - 'Kobilo', - 'Gokcebey', - 'Nefta', - 'Himora', - 'Papanasam', - 'Lohuti', - 'Jaipur Chuhar', - 'Anuppur', - 'Kanke', - 'Sarzana', - 'Lentini', - 'Ayamonte', - 'Raja Pakar', - 'Tiruvankod', - 'Okuchi-shinohara', - 'Riachao das Neves', - 'Kumla', - 'Howick', - 'Iisalmi', - 'Tlaltenango de Sanchez Roman', - 'Sao Miguel do Guapore', - 'Mercato San Severino', - 'Herent', - 'Orzesze', - 'Villeneuve-sur-Lot', - 'Pushkar', - 'Zarnesti', - 'Mashiko', - 'New Hope', - 'Novopokrovka', - 'Sidi Ifni', - 'Fukagawa', - 'Sainte-Suzanne', - 'Scugog', - 'Bela Vista', - 'Jiuru', - 'Nueva Granada', - 'Nerupperichchal', - 'Lakato', - 'Amarpatan', - 'Savigliano', - 'Xinzhai', - 'Paraguacu', - 'Vicente Noble', - 'Tamgrout', - 'Isla-Cristina', - 'Alliance', - 'G`azalkent', - 'Ashtarak', - 'Cuilapan de Guerrero', - 'Chapala', - 'Senaki', - 'Seynod', - "M'Chedallah", - 'Laziska Gorne', - 'Rosario de Lerma', - 'Alcala la Real', - 'Unity', - 'Bougado', - "Qal'acha", - 'Spremberg', - 'Ibiruba', - 'Marti', - 'Xanten', - 'MacArthur', - 'Salcaja', - 'Chilca', - 'Mandapam', - 'Pergine Valsugana', - 'Selouane', - 'Tukwila', - 'Elverum', - 'Seligenstadt', - 'Pakala', - 'Mandelieu-la-Napoule', - 'Rancheria Payau', - 'Santa Teresita', - 'Arcueil', - 'Kalpakathukonam', - 'Stadtallendorf', - 'Fulshear', - 'Rocky River', - 'Beni Douala', - "Colle di Val d'Elsa", - 'Pancas', - 'Galeras', - 'Mililani Mauka', - 'Cabucgayan', - 'Naranammalpuram', - 'Kontela', - 'Guimar', - 'Corciano', - 'Stowmarket', - 'Acatic', - 'Naqadah', - 'Thebes', - 'Payson', - 'Nong Bua Lamphu', - 'Lino Lakes', - 'Wexford', - 'Sermadevi', - 'Ladario', - 'Zerbst', - 'Dean Funes', - 'Cardito', - 'San Martin de las Piramides', - 'Caombo', - 'Goroka', - 'Villagarzon', - 'Eckernforde', - 'Ano Syros', - 'Chebli', - 'Bastos', - 'Aarau', - 'Alnavar', - 'Whyalla', - 'Celina', - 'Parelhas', - 'Hazebrouck', - 'Boquira', - 'North Guwahati', - 'Muthutala', - 'Tanki Leendert', - "Alta Floresta D'Oeste", - 'Holiday', - 'Jawor', - 'Nang Rong', - 'Allauch', - 'Artemida', - 'Gunzburg', - 'Harvey', - 'Chesham', - 'Puerto Natales', - 'Rees', - 'Trezzano sul Naviglio', - 'Takaba', - 'Aspe', - 'Kodikuthi', - 'Secaucus', - 'Mons-en-Baroeul', - 'Ambohitromby', - 'Hojambaz', - 'Gokdepe', - 'Fort St. John', - 'Madakasira', - 'Juli', - 'Kotli', - 'El Paujil', - 'Llorente', - 'Ozark', - 'Sihu', - 'Loncoche', - 'Beni Mered', - 'Ganapavaram', - 'Laventille', - 'Paramonga', - 'Senador Guiomard', - 'Qalansuwa', - 'East Patchogue', - 'Riehen', - "Tong'anyi", - 'Paravai', - 'Pendurti', - 'Rio Rico', - 'Osterode', - 'Bariarpur', - 'Amizmiz', - 'Waghausel', - 'Bogande', - 'Nhamunda', - 'Volnovakha', - 'Partizanske', - 'Thenia', - 'Fleury-les-Aubrais', - 'Saint-Michel-sur-Orge', - 'Jekabpils', - 'Chandlers Ford', - 'Tambau', - 'Andippatti', - 'Egil', - 'Maruturu', - 'Icapui', - 'Zossen', - 'Panagyurishte', - 'Shahbazpur', - 'Wilmot', - 'Hoogstraten', - 'Noamundi', - 'Merefa', - 'Sao Joao do Piaui', - 'Urucuca', - 'Ghanzi', - 'Puchheim', - 'Four Square Mile', - 'San Bonifacio', - 'Kutna Hora', - 'Taurage', - 'Lioua', - 'Neuilly-Plaisance', - 'Pefki', - 'Srivaikuntam', - 'Jandaia do Sul', - 'Alejandro Korn', - 'Bayi', - 'Kant', - 'Swiedbodzin', - 'Cumaral', - 'Grajewo', - 'Pamarru', - 'Shirhatti', - 'Naas', - 'Annecy-le-Vieux', - 'Inopacan', - 'Khowai', - 'Mohiuddinnagar', - 'Perdoes', - 'Afourar', - 'Los Vilos', - 'Nogent-sur-Oise', - 'Singur', - 'Kirkintilloch', - 'Gummudipundi', - 'Nedre Eiker', - 'Allende', - 'Masis', - 'Mantes-la-Ville', - 'Teteven', - 'Almaguer', - 'Palma di Montechiaro', - 'Pleasant Prairie', - 'Seymour', - 'Igreja Nova', - 'Senago', - 'Fortin de las Flores', - 'Acheres', - 'Bilohorodka', - 'Mukilteo', - 'Ambinanindrano', - 'Fukuyoshi', - 'Westborough', - 'Iguai', - 'Stange', - 'Bornem', - 'Silva Jardim', - 'Vecses', - 'Hafshejan', - 'Galugah', - 'Zambrow', - 'Tiruppuvanam', - 'Mountlake Terrace', - "Mi'eso", - 'Metahara', - 'Mundgod', - 'Dax', - 'South Lake Tahoe', - 'Hammanskraal', - 'Darton', - 'Kasumpti', - 'Padmanabhapuram', - 'Doaba', - 'Pambadi', - 'Lindenwold', - 'Vicksburg', - 'Moorestown', - 'San Antonio de Areco', - 'Somers', - 'Ulus', - 'Antilla', - 'Terrier Rouge', - 'Oum Drou', - 'Mragowo', - 'Sriperumbudur', - 'Sukhodilsk', - 'Youganning', - 'Yegainnyin', - 'Alcudia', - 'Mit Nama', - 'Winter Gardens', - 'Sondershausen', - 'Kelkit', - 'Tubbergen', - 'Armidale', - 'Sao Joao', - 'Aralik', - 'Aiud', - 'Nirmali', - 'Narippatta', - 'Wang Nam Yen', - 'Makulubita', - 'Artashat', - 'Akonolinga', - 'Casal di Principe', - 'Kaduturutti', - 'Huy', - 'Kaikalur', - 'Cacem', - 'Chagalamarri', - 'Krus na Ligas', - 'South Holland', - 'Sulphur', - 'Sevilimedu', - 'Royton', - 'Dolton', - 'Clemmons', - 'Mansourah', - 'Perry', - 'Kitcharao', - 'Carthage', - 'Gauting', - 'Mabitac', - 'Belovodskoe', - 'Yorkville', - 'Pajara', - 'Wielun', - 'Linamon', - 'Mossaka', - 'Nowa Ruda', - 'Agropoli', - 'Vialonga', - 'Almasi', - 'Dronfield', - 'Oshoba', - 'Iruttarakonam', - 'Rolante', - 'Traunstein', - 'Namagiripettai', - 'Sulejowek', - 'West Pensacola', - 'Tapalpa', - 'Asni', - 'Koduvilarpatti', - 'Carrboro', - 'Ntcheu', - 'Sanxing', - 'Suwanee', - 'Aguadas', - 'Manuel Tames', - 'Lealman', - 'Bhairi', - 'Ossett', - 'Montecristo', - 'Urk', - 'Narkher', - 'Degollado', - 'Tadikombu', - 'Fierenana', - 'Dupax del Sur', - 'Sao Sepe', - 'Pillaiyarkuppam', - 'Bobonong', - 'Kosgi', - 'Zonhoven', - 'Concepcion Huista', - 'Jiangjiadong', - 'Kontich', - 'Parasi', - 'Matsuura', - 'Rose Hill', - 'Obock', - 'Tabount', - 'Varennes', - 'Lucelia', - 'Chorwad', - 'Ratu', - 'Saint-Mande', - 'Milwaukie', - 'Caapora', - 'Rio Maior', - 'Valle Nacional', - "Qia'erbagecun", - 'Nagamangala', - 'Borgomanero', - 'Boca da Mata', - 'Rupauli', - "Sal'a", - 'Vryburg', - 'Floridia', - 'Hyde Park', - 'Shazand', - 'Belonia', - 'Gardanne', - 'Lathi', - 'Manlleu', - 'Varadero', - 'Tiburon', - 'Penzance', - 'Sarari', - 'Tinja', - 'Guasipati', - 'Khromtau', - 'Varkaus', - 'Wildeshausen', - 'Hallein', - 'Allschwil', - 'Morasar', - 'Maracacume', - 'Hancha', - 'Sapone', - 'Irakleia', - 'Kanmaki', - 'Bayou Cane', - 'Loyola Heights', - 'Kannanendal', - 'Quirima', - 'Saurh', - 'Cortona', - 'Kagizman', - 'Forbach', - 'Villeneuve-le-Roi', - 'Aguinaldo', - 'Cartaya', - 'Skegness', - 'Carlos Casares', - 'Schramberg', - 'Raksaha', - 'Adigaratti', - 'Enkoping', - 'Shark', - 'Suaza', - 'Kokofata', - 'Adet', - 'San Juan de Rio Coco', - 'Princesa Isabel', - 'Foley', - 'Wipperfurth', - 'Irukanni', - 'Hays', - 'Martellago', - 'Tullahoma', - 'Amodei', - 'Banki', - 'Conceicao de Macabu', - 'Molde', - 'Chocaman', - 'Traunreut', - 'Altepexi', - 'Wulfrath', - 'Germersheim', - 'Tehata', - 'Gorgonzola', - 'El Pinar', - 'San Isidro de Lules', - 'Oued el Aneb', - 'Itapaci', - 'Sadao', - 'Tizi-n-Bechar', - 'Sao Marcos', - 'Seria', - 'Chopinzinho', - 'Xoxocotla', - 'Furano', - 'Harstad', - 'North Bellmore', - 'Paiganapalli', - 'Sondrio', - 'Orhei', - 'Injibara', - 'North Ogden', - "Imi n'Oulaoun", - 'Xinnongcun', - 'Palmeiras', - 'Behat', - 'Caxambu', - 'Paulistana', - 'San Juan de Vilasar', - 'Makakilo', - 'Saint Austell', - 'Laje', - 'Chinchali', - 'Villapinzon', - 'Palafrugell', - 'Jangy-Nookat', - 'Ukmerge', - 'Saka', - "Saint Paul's Bay", - 'Joaquin V. Gonzalez', - 'South Whitehall', - 'Itambacuri', - 'Park Forest', - 'Nubl', - 'Oro-Medonte', - 'Jozefow', - 'Praia da Vitoria', - 'Mirador', - 'Caterham', - 'Porto Torres', - 'Wade Hampton', - 'Sao Jeronimo', - 'Gross-Umstadt', - 'Phalia', - 'Zulpich', - 'Patpara', - 'Ariano Irpino', - 'Stephenville', - 'Klaukkala', - 'San Jose de Jachal', - 'Az Zuwaytinah', - 'Timmarasanayakkanur', - 'Woodlesford', - 'Nordlingen', - 'San Victor Abajo', - 'Fatehgarh Churian', - 'Manjhi', - 'Tanhacu', - 'Samba', - 'Willmar', - 'Stratton Saint Margaret', - 'Alto-Cuilo', - 'Cuilo', - 'Daddi', - 'Mangghystau', - 'Merrick', - 'Cranendonck', - 'Sremcica', - 'Nurota', - 'Morafeno', - 'Sitampiky', - 'Ambalavato', - 'Tongobory', - 'Tsarasaotra', - 'Ambohipandrano', - 'Andolofotsy', - 'Soanindrariny', - 'Ankililoaka', - 'Tsiamalao', - 'Fiadanana', - 'Antanambao', - 'Sahamadio', - 'Miorimivalana', - 'Ambohimanambola', - 'Ampasimatera', - 'Karianga', - 'Matanga', - 'La Colonia Tovar', - 'Fengjia', - 'Dabaozi', - 'Sancoale', - 'Kudal', - 'Anah', - 'Mandza', - 'Sidi Lahssen', - 'Tufanganj', - 'Torqabeh', - 'Fredonia', - 'San Antonio Sacatepequez', - 'Vadakkum', - 'Walia', - 'Laranjeira', - 'Cassilandia', - 'Sokal', - 'Capela do Alto', - 'Agan', - 'Itapecerica', - "Welench'iti", - 'Daboh', - 'Nizampatam', - 'El Reten', - 'Suzzara', - 'Osmaneli', - 'Zele', - 'Fot', - 'Santa Vitoria', - 'Baiheqiao', - 'Thuan An', - "Saint-Cyr-l'Ecole", - 'Bugalagrande', - 'Ankaraobato', - 'Hualqui', - 'Upper St. Clair', - 'Caracarai', - 'Carmo do Rio Claro', - 'Mont-Royal', - 'Pacatu', - 'Coreau', - 'Hirekerur', - 'Quela', - 'Purranque', - 'Mineola', - 'San Cataldo', - 'Vladicin Han', - 'East Moline', - 'East Pennsboro', - 'Green Valley', - 'Ondorhaan', - 'Chaudfontaine', - 'Cuncolim', - 'Piedra Blanca', - 'Torrox', - 'Damua', - 'Punturin', - 'Saint-Genis-Laval', - 'Renens', - 'Nambiyur', - 'Cho Phuoc Hai', - 'Alagoa Nova', - 'Concepcion Chiquirichapa', - 'Urussanga', - 'Fort Walton Beach', - 'Argenta', - 'Five Corners', - 'San Guillermo', - 'Vili', - 'Leskovac', - 'Aisho', - 'Guara', - 'Jericho', - 'Bni Rzine', - 'Little Egg Harbor', - 'Mossingen', - 'Esperalvillo', - 'Vakkam', - 'Lucani', - 'Pudupattanam', - 'Kamamaung', - 'Snellville', - 'Herborn', - 'Voiron', - 'Eeklo', - 'Monte Santo de Minas', - 'Pico Truncado', - 'Battle Ground', - 'Texistepec', - 'Liubotyn', - 'Balugan', - 'Brummen', - 'Ludlow', - 'Murphy', - 'Koath', - 'Quixere', - 'Ambohimanga', - 'Normanton', - 'Mulanje', - 'Sint-Katelijne-Waver', - 'Palavur', - 'Murree', - 'Zaliohouan', - 'Kyaukpyu', - 'Saint-Gratien', - 'Sotomayor', - 'Sanchez', - 'Bordj Bounaama', - 'Bambalang', - 'Mudakkal', - 'Kara-Suu', - 'Aurad', - 'Luisiana', - 'Showa', - 'El Gara', - 'Oliveira do Hospital', - 'Sidi Abdelkader', - 'Birkerod', - 'Beni Haoua', - 'Hyattsville', - 'Amdjarass', - 'Wallington', - 'Hindang', - 'Pogradec', - 'Moniquira', - 'Ovejas', - 'Vinany', - 'Wettingen', - 'Cercado Abajo', - 'Letlhakane', - 'Musselburgh', - 'Harohalli', - 'Luckenwalde', - "Debark'", - 'Imi-n-Tanout', - 'Paldorak', - 'Wasquehal', - 'Lajinha', - 'Junqueiropolis', - 'Halluin', - 'Jindrichuv Hradec', - 'Bruchkobel', - 'Conselheiro Pena', - 'Castrovillari', - 'West St. Paul', - 'Murrysville', - 'Buckingham', - 'Karmana', - 'Sao Jose da Laje', - 'Miches', - 'Meinerzhagen', - 'Bhainsdehi', - 'Sonagazi', - 'Bourg-la-Reine', - 'Beroun', - 'Stadtlohn', - 'Devirammanahalli', - 'Mariani', - 'Grayslake', - 'Malaba', - 'Chelak', - 'Ararat', - 'Conceicao da Feira', - 'Valkeakoski', - 'Banting', - 'Schortens', - 'Mill Creek', - 'Ambondro', - 'Alta', - 'Derinkuyu', - 'Ibicoara', - 'Morsang-sur-Orge', - 'Peringanad', - 'Cordeiro', - 'Veresegyhaz', - 'Coolbaugh', - 'Croix', - 'Jicome', - 'Carcagente', - 'Wittmund', - 'Sestu', - 'Bronkhorstspruit', - 'Leek', - 'Samaca', - 'Algete', - 'Horstel', - 'Gavarr', - 'Coudekerque-Branche', - 'Barhampur', - 'Bulnes', - 'Colfontaine', - 'Ul', - 'Oliveira de Azemeis', - 'Palkonda', - 'Puduppalli Kunnam', - 'Yermal', - 'Luacano', - 'Sivasli', - 'Illapel', - 'Valljkkod', - 'Ino', - 'Bryant', - 'Banganapalle', - 'Kuknur', - 'Sivrihisar', - 'Narwar', - 'Bandar-e Gaz', - 'Mathukumnel', - 'Leigh-on-Sea', - 'Castel San Pietro Terme', - 'Sonbarsa', - 'Tittagudi', - 'Anagni', - 'Puzol', - 'Le Creusot', - 'Monsummano', - 'Zhangatas', - 'Hanahan', - 'Iriona', - 'Hexiang', - 'Gannavaram', - 'St. John', - 'Kiseljak', - 'Achampet', - 'Mohammadabad', - 'Boscombe', - 'Palestina de los Altos', - 'Beruri', - 'Arnaud', - 'Oliveira dos Brejinhos', - 'Hanmayingcun', - 'Goodlands', - 'Lebedinovka', - 'Elvas', - 'Parma Heights', - 'Enger', - 'Menaka', - "Vranov nad Topl'ou", - 'Werdau', - 'Llandudno', - 'Guaratinga', - 'Nidderau', - 'Kolaras', - 'Mae Sai', - 'Campestre', - 'Monte Azul', - 'Ati', - "Olho d'Agua das Flores", - 'Chithara', - 'Ozoir-la-Ferriere', - 'Dolyna', - 'Montecatini Terme', - 'Sao Joao de Pirabas', - 'Palma del Rio', - 'Baroda', - 'San Julian', - 'Lennox', - 'Baie-Comeau', - 'Mantsala', - 'Soye', - 'Bussolengo', - 'Pozanti', - 'Failsworth', - 'Recanati', - 'Cornaredo', - 'South Milwaukee', - 'Kremenets', - 'Kirkstall', - 'Marquette', - 'Wuustwezel', - 'Steinhagen', - 'Dzialdowo', - 'Profesor Salvador Mazza', - 'Bozoum', - 'Waxhaw', - 'Lomita', - 'Schwanewede', - 'Ismayilli', - 'Lagoa do Itaenga', - 'Sidi Chiker', - 'Muttatodi', - 'Givors', - 'Rosamond', - 'Fougeres', - 'As', - 'Banaue', - 'Los Llanos de Aridane', - 'Melena del Sur', - 'Bohumin', - 'Piazza Armerina', - 'Denain', - 'Vinjamur', - 'Kladovo', - 'Riacho das Almas', - 'El Hammadia', - 'Parramos', - 'Miandrivazo', - 'Lubalo', - 'Bagou', - 'Bad Waldsee', - 'Sidi Rahal', - 'Mitry-Mory', - 'Yanagawamachi-saiwaicho', - 'Sour', - 'Sarreguemines', - 'Arroyo Seco', - 'Longjumeau', - 'Chachahuantla', - 'Pahuatlan de Valle', - 'Bockum', - 'Isernia', - 'Kleppe', - 'Schifferstadt', - 'Hardi', - 'Manhumirim', - 'Na Klang', - 'Hurricane', - 'Dingolfing', - 'Concarneau', - 'Crowborough', - 'Adrian', - 'Tarnaveni', - 'Tan Phong', - 'Al Qays', - 'Botevgrad', - 'Celbridge', - 'Ghafurov', - 'Popasna', - 'Yakkabog`', - 'Sunbat', - 'Tepexi de Rodriguez', - 'Patuvilayi', - 'South St. Paul', - 'Somanya', - 'Nan', - 'Goris', - 'Manbengtang', - 'Campia Turzii', - 'Neufahrn bei Freising', - 'Jatara', - 'Kawambwa', - 'Gjovik', - 'Caravelas', - 'Nanuet', - 'Savda', - 'Kapay', - 'Wachtberg', - 'Mead Valley', - 'Nuenen', - 'Lillehammer', - 'Kekem', - 'Baza', - 'Chapulhuacan', - 'Buftea', - 'Rosolini', - 'Toktogul', - 'Palo del Colle', - 'Romano di Lombardia', - 'Hashtrud', - 'Mbala', - 'Qagan Us', - 'Foya Tangia', - 'Sa al Hajar', - 'Arhavi', - 'Pleasantville', - 'Dumbarton', - 'Lugait', - '`Adra', - 'Chintalapalle', - 'Hlohovec', - 'Modling', - 'Libertyville', - 'Jefferson', - 'Forest Lake', - 'Honnali', - 'La Resolana', - 'Frondenberg', - 'Zestaponi', - 'Shoreham-by-Sea', - 'Cha Grande', - 'Namioka', - 'Vakon', - 'Sunchales', - 'Gandujie', - 'Bati', - 'Colleferro', - 'Codlea', - 'Mazinde', - 'Laboulaye', - 'Guadalupe Nuevo', - 'Sultanhisar', - 'Carmen de Patagones', - 'Quemado de Guines', - 'Aomar', - 'Maniyamturuttu', - 'Torhout', - 'Bothell West', - 'Bladel', - 'Lami', - 'Sonkach', - 'Hernani', - 'Hythe', - 'Vadamadurai', - 'Madipakkam', - 'Chennimalai', - 'Bala', - "Zd'ar nad Sazavou", - 'Cobourg', - 'Ohara', - 'Mustang', - 'Northfield', - 'Atoyac de Alvarez', - 'Station des Essais M.V.A.', - 'Eruh', - 'Elko', - 'Coswig', - 'Colonia General Felipe Angeles', - 'Cauto Cristo', - 'Carquefou', - 'Trecate', - 'Ijevan', - 'Nishigo', - 'Bibai', - 'Banolas', - 'Baskil', - 'Horten', - 'Muhammadabad', - 'Pendembu', - 'Tielt', - 'Shimogamo', - 'Cranbrook', - 'Nellimarla', - 'Lubartow', - 'Grottaferrata', - 'Binondo', - 'Seydi', - 'Sapang Dalaga', - 'Nahorkatiya', - 'Khvansar', - 'Sceaux', - 'Stevenson Ranch', - 'Hatvan', - 'Peritoro', - 'Saint-Pol-sur-Mer', - 'Lower Southampton', - 'Posusje', - 'Becerril', - 'La Celle-Saint-Cloud', - 'Hailsham', - 'Bhojpur Kadim', - 'Uetze', - 'Kurshab', - 'Recani', - 'Dulken', - 'Nadikude', - 'Timana', - 'Mindouli', - 'Sant Just Desvern', - 'Golden', - 'Omagh', - 'Kizhattur', - 'Ain Cheggag', - 'Kawayan', - 'Otsego', - 'Bourne', - 'Costas de Cao', - 'Caparica', - 'Taslicay', - 'Muong Lay', - 'Saco', - 'Paraisopolis', - 'Puerto Quito', - 'Maghull', - 'Piqua', - 'Keevallur', - "'Ain el Bell", - 'Fara', - 'Sidi Jaber', - 'Imperial', - 'Susaki', - 'Mealhada', - 'Cinfaes', - 'Jarajus', - 'Vyskov', - 'Pak Phanang', - 'Huercal-Overa', - 'Itatira', - 'Baud', - 'Aigio', - 'Chepo', - 'Sandwich', - 'Koipadi', - 'Yasothon', - 'Lambari', - 'Joinville-le-Pont', - 'Kuala Pembuang', - 'Bouguenais', - 'Jaboticatubas', - 'Dereli', - 'Pariyaram', - 'Reggane', - "'Ain el Hammam", - 'Iztapa', - 'Hauppauge', - 'Follonica', - 'Greiz', - 'Montrose', - 'West Hempstead', - 'North Liberty', - 'Zaghouan', - 'Hassloch', - 'Old Jamestown', - 'Painesville', - 'Sandhurst', - 'Chokkampatti', - 'Beforona', - 'Kolo', - 'Longbangcun', - 'La Canada Flintridge', - 'Naraura', - 'Jaguaruna', - 'Barki Saria', - 'Ramnagar Farsahi', - 'Samboan', - 'Porto Real', - 'Reichenbach/Vogtland', - 'Alatsinainy-Bakaro', - 'Kuttampala', - 'Feltre', - 'San Pablo Tacachico', - 'Kanaya', - 'Yangping', - 'Tewkesbury', - 'Cormano', - 'Rothwell', - 'Karaiyampudur', - 'Froyland', - 'Hoyland', - 'Marblehead', - 'Sidney', - 'Kihihi', - 'Blankenberge', - 'Sartalillo', - 'Altamont', - 'Lannion', - 'Cugnaux', - 'Harpalpur', - 'Bratunac', - 'Neustrelitz', - 'Middle', - 'Yellowknife', - 'Makhtal', - 'Westbrook', - 'Mundra', - 'Tala Yfassene', - 'Huanuni', - 'North Amityville', - 'Kashkar-Kyshtak', - 'Dan Gorayo', - 'Grande-Synthe', - 'La Chapelle-sur-Erdre', - 'Trentola', - 'Santa Maria Chilchotla', - 'Chevilly-Larue', - 'Dharmkot', - 'Nesoddtangen', - 'Farashband', - 'Fangasso', - 'Farum', - 'Baihar', - 'Salmon Creek', - 'Rawicz', - 'Katakos', - 'Senta', - 'Khowrzuq', - 'Las Vigas de Ramirez', - 'Chandragiri', - 'Lynbrook', - 'Gryfino', - 'Selendi', - 'Bellshill', - 'Tobe', - 'East Northport', - 'Duderstadt', - 'San Martin De Porres', - 'Sao Felipe', - 'Marion Oaks', - 'Oroville', - 'Lalin', - 'Salgado', - 'Inirida', - 'Candido Mendes', - 'Shisui', - 'Chorozinho', - 'Nyon', - 'Teculutan', - 'Simiti', - 'Tenjo', - 'Minturno', - 'Whitpain', - 'Gopavaram', - 'Cilimli', - 'Lingolsheim', - 'Devrukh', - 'Kokopo', - 'East Hemet', - 'Pulicat', - 'Rumoi', - 'Wodonga', - 'Luperon', - 'Parkal', - 'Ely', - 'Ervalia', - 'Rovira', - 'Bad Schwartau', - 'Vico Equense', - 'Sbeitla', - 'Chodavaram', - 'Hazlet', - 'Husainpur', - "Mar''ina Horka", - 'Mosta', - 'South Burlington', - 'Blieskastel', - 'Jdour', - 'Aguas Zarcas', - 'Touna', - 'Raipura', - 'Abano Terme', - 'Palisades Park', - 'Ochtrup', - 'Samthar', - 'Asosa', - 'Belur', - 'Xionglin', - 'Telgte', - 'Pinan', - 'Edakkunnam', - 'Le Plessis-Trevise', - 'Khilchipur', - 'Lichtenfels', - 'Gyomro', - 'Kortenberg', - 'Ban Tha Pha', - 'Yaraka', - 'Lower Allen', - 'Gostyn', - 'Sessa Aurunca', - 'Le Mee-sur-Seine', - 'Chandpur', - 'Entroncamento', - 'Ypsilanti', - 'Rhenen', - 'Pennagaram', - 'Melnik', - 'Tondi', - 'Stebnyk', - 'Xo`jaobod', - 'Agsu', - 'Agstafa', - 'Mayluu-Suu', - 'Rivalta di Torino', - 'Pontassieve', - 'Pompeia', - 'Boromo', - "Cournon-d'Auvergne", - 'Uruburetama', - 'South Frontenac', - 'Douar Lamrabih', - 'Puerto Viejo', - 'Reitz', - 'Guacima', - 'Voyenno-Antonovka', - 'Skive', - 'Ripley', - 'Cruz Grande', - 'Ban Klang', - 'Blansko', - 'Taibet', - 'Polonne', - 'Seaham', - 'Talayazham', - 'Monte Alegre de Minas', - 'Abou el Hassan', - 'Peterlee', - 'Pargi', - 'Schopfheim', - 'Otegen Batyr', - 'Motatan', - 'Shafter', - 'Diondiori', - 'Sivagiri', - 'Nelkattumseval', - 'Akora', - 'Frontino', - 'Erragondapalem', - 'Aurad Shahjahani', - 'Ayaviri', - 'Pantanaw', - 'Sesheke', - 'Bhitarwar', - 'Regente Feijo', - 'Kheralu', - 'Cahors', - 'Midway', - 'Rosas', - 'Mattigiri', - 'Alblasserdam', - 'Alampalaiyam', - 'Dorchester', - 'Teonthar', - 'Arbutus', - 'Giengen an der Brenz', - 'Karukachal', - 'Aquidaba', - 'Kurten', - 'Del Carmen', - 'Toprakkale', - 'Mayfield Heights', - 'Farakka', - 'Turmalina', - 'Pujehun', - 'Belmonte', - 'Holzminden', - 'Bela', - 'Leinefelde', - 'Villa Verde', - 'Vettikkavala', - 'Riviere-du-Loup', - 'Huanimaro', - 'Senec', - 'Halewood', - 'Comrat', - 'Archena', - "Pallazzolo sull'Oglio", - 'Barkly West', - 'Nykobing Falster', - 'Culpeper', - 'Galvez', - 'Nkoteng', - 'Celorico de Basto', - 'Bilasuvar', - 'Luban', - 'Kulpahar', - 'Montalto Uffugo', - 'Buckhall', - 'Satsuma', - 'Oberkirch', - 'La Crescenta-Montrose', - 'Medina del Campo', - 'Villa Hidalgo', - 'Agoura Hills', - 'Kwinana', - 'Denderleeuw', - 'Piata', - 'Yabayo', - 'Siran', - 'Lonar', - 'Virarajendrapet', - 'Barroso', - 'Mithi', - 'Porto Real do Colegio', - 'Skanderborg', - 'Killingworth', - 'Depalpur', - 'Sidhapa', - 'Naranjos', - 'Esanboy', - 'Dhorimanna', - 'El Ancer', - 'Cabra', - 'Mahaditra', - 'Temacine', - 'Horwich', - 'Mont-Saint-Aignan', - 'Llallagua', - 'Schmalkalden', - 'Bani Murr', - 'Brezno', - 'Schroeder', - 'Rosedale', - 'Ban Wat Sala Daeng', - 'Casa de Oro-Mount Helix', - 'Nguekhokh', - 'Mesra', - 'Durbat', - 'Pita', - 'Kartikapalli', - 'Guding', - 'Diguapo', - 'Buxton', - 'Ferentino', - 'Lohur', - 'Meadowbrook', - 'Bulach', - 'Teopisca', - 'Kannod', - 'Kafr Laha', - 'Makoua', - 'Castillo de Teayo', - 'Mutuipe', - 'Sao Joaquim do Monte', - 'Tettnang', - 'Bhopatpur', - 'Yumbel', - 'Tolu Viejo', - 'Atescatempa', - 'Port Colborne', - 'Beaune', - 'Bubanza', - 'Hakui', - 'La Esmeralda', - 'Takanabe', - 'Rolla', - 'Atarfe', - 'Cittadella', - 'Howard', - 'Sidi Merouane', - 'Kissa', - 'Oderzo', - 'Jiangjiehe', - 'Dumbravita', - 'Krasnohrad', - 'Pertuis', - 'Etzatlan', - 'Calceta', - 'Presidente Getulio', - 'Kandakkadava', - 'Rio Formoso', - 'Goraya', - 'Port Angeles', - 'Tupancireta', - 'Forest Park', - 'Piove di Sacco', - 'El Ksiba', - 'Bispham', - 'Indwe', - 'Kfar Kidde', - 'El Bazouriye', - 'Ampasimena', - 'Mandrosohasina', - 'Ambalakirajy', - 'Rantabe', - 'Mandiavato', - 'Ambatosoratra', - 'Tsararafa', - 'Analapatsy', - 'Tsarabaria', - 'Soavina Antanety', - 'Bekatra Maromiandra', - 'Haka', - 'Arvayheer', - 'Kuala Lipis', - 'Opuwo', - 'Bulolo', - 'Gahi Mammar', - 'Alfena', - 'Kebemer', - 'Mikumi', - 'Muheza', - 'Sultonobod', - 'Sangin', - 'Sitrah', - 'Zemio', - 'Bamukumbit', - 'Bamumkumbit', - 'Sanjianxiang', - 'Minster', - 'Shri Mahavirji', - 'Tadas', - 'Asarganj', - 'Rankhandi', - 'Bhaluhar', - 'Mandi Bamora', - 'Bareja', - 'Sikka', - 'Munak', - 'Pirbahora', - 'Hudli', - 'Bazidpur Madhaul', - 'Suroth', - 'Sujnipur', - 'Marjampad', - 'Sohana', - 'Chimthana', - 'Mangapet', - 'Ankalgi', - 'Kothanuru', - 'Tuminkatti', - 'Naranda', - 'Sonaimukh', - 'Baragoi', - 'Ciudad Miguel Aleman', - "'Ain Mabed", - 'Comanesti', - 'Garhshankar', - 'Donauworth', - 'Vasiana', - 'Chaville', - 'Salsomaggiore Terme', - 'Dillingen', - 'Evaz', - 'Emet', - 'Antrim', - "Trostyanets'", - 'Chirilagua', - 'Sanrh Majhgawan', - 'Palashi', - 'Sidi Taibi', - 'Kumil', - "'Ali Ben Sliman", - 'Shonai', - 'Shirahama', - 'Vazante', - 'Shiruru', - 'Valderrama', - 'Valiyakumaramangalam', - 'Kadakola', - 'Vianen', - "L'Isle-sur-la-Sorgue", - 'Matheu', - 'Tibagi', - 'Itsoseng', - 'Alpinopolis', - 'Bafoulabe', - 'Altagracia', - 'Korntal-Munchingen', - 'Benicasim', - 'Kampong Thum', - 'Petrinja', - 'Ampefy', - 'Waldbrol', - 'Bhasawar', - 'Coruche', - 'Plaisance-du-Touch', - 'Ban Tha Kham', - 'Carira', - 'Chilly-Mazarin', - 'Acquaviva delle Fonti', - 'Butare', - 'Tarhzirt', - 'Nachod', - 'Irlam', - 'Mapai', - 'Mulundo', - 'Venmani', - 'Ait Tamlil', - 'Koskapur', - 'Doany', - 'San Martin de la Vega', - 'Had Zraqtane', - 'Sand Springs', - 'La Mornaghia', - 'Hiddenhausen', - 'Chatia', - 'Andal', - 'Siahkal', - 'Merrifield', - 'Affton', - 'Ulcinj', - 'Dhanaula', - 'Palliman', - 'Aanekoski', - 'Burnie', - 'Merad', - 'Bichena', - 'Yuancun', - 'Novate Milanese', - 'Senapparetti', - 'Pukhrayan', - 'Plattsburgh', - 'Saint-Augustin-de-Desmaures', - 'Bressuire', - 'Ban Tha Ton', - 'Sakae', - 'Nottuln', - 'El Arenal', - 'Zawiyat Razin', - 'Oregon', - 'Hunters Creek', - 'Akureyri', - 'Biddulph', - 'Saynshand', - 'Vevey', - 'Vila Rica', - 'Nejo', - 'Mokena', - 'Crest Hill', - 'Namegawa', - 'Maple Shade', - 'Loudima Poste', - 'Kisai', - 'El Paraiso', - 'Gil', - 'Guire', - 'Andira', - 'Kuysinjaq', - 'Brandsen', - 'Peshtera', - 'Hamina', - 'Miamisburg', - 'Senica', - 'Dagohoy', - 'Karlapalem', - 'Gherla', - 'Castilho', - 'Canelones', - 'El Castillo de La Concepcion', - 'Opfikon', - 'Sacile', - 'Ibirama', - 'Calella', - 'Orasje', - 'Quepos', - 'Bara Malehra', - 'Likak', - 'Boussu', - 'Umrapur', - 'El Mansouria', - 'Gerlingen', - 'Zimatlan de Alvarez', - 'Kavieng', - 'Tepetlixpa', - 'Cartavio', - 'Humanes de Madrid', - 'Moosburg', - 'Campamento', - 'Kuusankoski', - 'Jagatpur', - 'Cantagalo', - 'Rechaiga', - 'Gebre Guracha', - 'Stroud', - 'Peto', - 'Masterton', - 'Sint-Andries', - 'Rio Verde de Mato Grosso', - 'Ellamanda', - 'Khizrpur', - 'Kolavallur', - 'Makurazaki', - 'Spennymoor', - 'Broadview Heights', - 'Pradopolis', - 'Jambai', - 'Atlapexco', - 'Lincolnia', - 'Garforth', - 'Dokolo', - 'Lisieux', - 'Sleaford', - 'Anghad', - 'Mannur', - 'Kochas', - 'Kamakhyanagar', - 'Torgau', - 'Ban Na San', - 'Hirokawa', - 'Remigio', - 'Universal City', - 'Sainte-Marthe-sur-le-Lac', - 'Stoke Gifford', - 'Wilnsdorf', - 'Kannankurichchi', - 'Itaparica', - 'Rubiataba', - 'Nosy Varika', - 'Cekerek', - 'Araripe', - 'Holden', - 'Poperinge', - 'Time', - 'Mosopa', - 'Smorumnedre', - 'Sparta', - 'Oulad Embarek', - 'Vulcan', - 'Malabuyoc', - 'Cheung Chau', - 'Brandys nad Labem-Stara Boleslav', - 'Zhaodianzi', - 'Palm Valley', - 'Kattanam', - 'Puerto Armuelles', - 'Ghatkesar', - 'Lackawanna', - 'Selby', - 'Bishunpur', - 'Ennigerloh', - 'Ryuyo', - 'Oulad Fraj', - 'Xingangli', - 'Simonesia', - 'Lake Zurich', - 'Prudnik', - 'Poshkent', - 'Tres Barras', - 'Pattamadai', - 'Calvillo', - 'Os', - 'Wittlich', - 'Opoczno', - 'Itatinga', - 'Assebroek', - 'Thimiri', - 'Beldaur', - 'Marsberg', - 'Cherakhera', - 'Mengdan', - 'Sarstedt', - 'Yonabaru', - 'Issaba', - 'Kanekallu', - 'Evergreen Park', - 'Crisopolis', - 'Moinesti', - 'Yosano', - 'Claremore', - 'Viadana', - 'Nittedal', - 'Pecinci', - 'West Whiteland', - 'Cuite', - 'Hongshui', - 'Grobenzell', - 'Saavedra', - 'Castelo do Piaui', - 'Pichidegua', - 'Rio Segundo', - 'Payimattam', - 'Mayen', - 'Schenefeld', - 'Jnane Bouih', - 'Alga', - 'Oschersleben', - 'Beltsville', - 'Kinston', - 'Buckeburg', - 'Babanusah', - 'Lehara', - 'South El Monte', - 'Suarez', - 'Colotlan', - 'San Salvo', - 'Taketa', - 'Jimaguayu', - 'Dicholi', - 'Harmanli', - 'Mokeri', - 'Busra ash Sham', - 'Silla', - 'Katpadi', - 'Kanniyakumari', - 'Calatayud', - 'Mougins', - 'Namburu', - 'Oros', - 'Whitemarsh', - 'Sinacaban', - 'Mahmudabad Nemuneh', - 'Hajnowka', - 'Guantiankan', - 'Udalguri', - 'Korsholm', - 'Pastores', - 'Budipuram', - 'Westmount', - 'Andaingo Gara', - 'Chiconcuac', - 'Pichor', - 'Buriti dos Lopes', - 'Komarom', - 'Bruz', - 'Duragan', - 'Yuanhucun', - 'Grafton', - 'Chipiona', - 'Karuizawa', - 'Kondur', - 'Nove Mesto nad Vahom', - 'Luenoufla', - 'Dayr Abu Hinnis', - 'Davyhulme', - 'Villabate', - 'Ahfir', - 'Nilakkottai', - 'Urumita', - 'Hanumana', - 'Rawah', - 'Jussara', - 'Varpalota', - 'Haiger', - 'Bir Kasdali', - 'Ampere', - 'Atasu', - 'Otjiwarongo', - 'Yahotyn', - 'Bad Aibling', - 'Arvin', - 'Ramjibanpur', - 'Lerdo de Tejada', - 'Okhmalynka', - 'Punta Gorda', - 'Bad Pyrmont', - 'Mayahaura', - 'El Coco', - 'Ilijas', - 'Veroli', - 'Niiyama', - 'Brigham City', - 'Bondo', - 'Kutina', - 'San Juan Zitlaltepec', - 'Petrila', - 'Diinsoor', - 'Sadpur', - 'Tapaua', - 'Ischia', - 'Russell', - 'Turnu Magurele', - 'Holtsville', - 'Xapuri', - 'Lieto', - 'Rhede', - 'Buritirama', - 'Lastra a Signa', - 'Hidalgotitlan', - 'Visaginas', - 'Venadillo', - 'Schilde', - 'Engelskirchen', - 'Liuliang', - 'Les Coteaux', - 'Bourg-les-Valence', - 'Bequimao', - 'Jajarm', - 'Punjai Puliyampatti', - 'Caraubas', - 'Erlanger', - 'Burnham-on-Sea', - 'Baranain', - 'Heinola', - 'Caoayan', - 'Abbots Langley', - 'Suchiapa', - 'Amorebieta', - 'Aysha', - 'Atchoupa', - 'Wenden', - 'Doujing', - 'Mirfield', - 'Acigol', - 'Ansermanuevo', - 'Ballyfermot', - 'Vallam', - 'Morwa', - 'Mogiyon', - 'Tole Bi', - 'Hermosa Beach', - 'Carai', - 'Thamaga', - 'Huseni', - 'Pathrajolhania', - 'Tirthahalli', - 'Guapo', - 'Jhalida', - 'Artik', - 'Mihona', - 'Marahra', - 'Liuguang', - 'Herceg Novi', - 'Crespo', - 'Bagaces', - 'Rajaudha', - 'Eersel', - 'Eupen', - 'Ipanema', - 'Pauini', - 'Hoxut', - 'Ibigawa', - 'Goole', - 'Bedele', - 'Parsahi Sirsia', - 'Arese', - 'Fukude', - 'Yusufeli', - 'Alaca', - 'Kalayapuram', - 'Amta', - 'Telavi', - 'Mahinawan', - 'Tibba', - 'East Massapequa', - 'Akanavaritota', - 'Asasa', - 'West Mifflin', - 'Castellana Grotte', - 'Garsfontein', - 'Ait Bousarane', - 'Ait Bouziyane', - 'Sao Vicente Ferrer', - 'Sjobo', - 'Sangasso', - 'Hushihacun', - 'Los Alamos', - 'El Arahal', - 'Teminabuan', - 'Oulad Salmane', - 'Callosa de Segura', - 'San Juan de Dios', - 'Hoveyzeh', - 'Deneysville', - 'Nilgiri', - 'Rhar el Melah', - 'Capinota', - 'Orinda', - 'Albolote', - 'Cugir', - 'Eschwege', - 'Borna', - 'Molln', - 'Mullheim', - 'Jagalur', - 'Krishnapur', - 'Orvieto', - 'Sondiha', - 'Gogogogo', - 'Qorasuv', - 'Polonuevo', - 'Setlagode', - 'Ramchandrapur', - 'Teghra English', - 'Angleton', - 'Narsapur', - 'Cervantes', - 'Marihatag', - 'Kempston', - 'Hechingen', - 'Kemi', - 'Ronchin', - 'Sabaudia', - 'Madisonville', - 'Kos', - 'Salmon Arm', - 'Cardonal', - 'Adel', - 'Tublay', - 'Someren', - 'Santiago Texacuangos', - 'Ban Thap Kwang', - 'Bartow', - 'Gaeta', - 'Lynn Haven', - 'Kemise', - 'Liversedge', - 'Siruma', - 'Nova Granada', - 'Karttigappalli', - 'Vence', - 'Dorou', - 'Samalapuram', - 'Salangaippalaiyam', - 'Abrisham', - 'Xihuangcun', - 'Weil der Stadt', - 'Sulzbach-Rosenberg', - 'Zachary', - 'Los Bajos', - 'Frutillar Alto', - 'Sipoo', - 'Sweetwater', - 'Yandrapalle', - 'Dalanzadgad', - 'Pahsara', - 'Kantharalak', - 'Pariquera-Acu', - 'Bad Driburg', - 'Cabildo', - 'Alto Araguaia', - 'Arbaoun', - 'Annaberg-Buchholz', - 'Sartell', - 'Barro', - 'Torokszentmiklos', - 'Kalghatgi', - 'Shikrapur', - 'Charef', - 'Saint-Lo', - 'Manjathala', - 'Casarano', - 'Prunedale', - 'Middelkerke', - 'Heishanzuicun', - 'Seabrook', - 'Abhayapuri', - 'Kakdwip', - 'Boone', - 'Giovinazzo', - 'Canto do Buriti', - 'Burghausen', - 'Tajerouine', - 'Kloten', - 'Kitatajima', - 'Godo', - 'Saint-Fons', - 'Pastrana', - 'Juquia', - 'Rifadpur', - 'Mukaiengaru', - 'Sare-Yamou', - 'Buruanga', - 'Paranapanema', - 'Heishuikeng', - 'Arbatache', - 'Balta', - 'Prichard', - 'Nauen', - 'Kuttyadi', - 'Great Linford', - 'Dudu', - 'Jamsa', - 'Napindan', - 'Ban Bueng', - 'Ban Patong', - 'Mahajeran-e Kamar', - 'Oruvadalkotta', - 'Moulins', - 'Jose Cardel', - 'Tadian', - 'Wassenberg', - 'Allanridge', - 'Pugo', - 'Tangbian', - 'Wolfratshausen', - 'Sorada', - 'Weesp', - 'Bierun', - 'Cajola', - 'Corner Brook', - 'Dashtigulho', - 'Pultusk', - 'Presidente Medici', - 'Bholsar', - 'Ban Fang Tuen', - 'Peruru', - 'Tevaram', - 'Saint-Die-des-Vosges', - 'Kamiichi', - 'Warrensburg', - 'Faversham', - 'New Glasgow', - 'Moana', - 'Palera', - 'Panniperumthalai', - 'Mancio Lima', - 'San Antonio Huista', - 'Assamannur', - 'Pohadi', - 'Tash-Komur', - 'Pottanikad', - 'Heusenstamm', - 'Dukinfield', - 'Jirkov', - 'Monte Azul Paulista', - 'Virovitica', - 'Dorval', - 'Qandala', - 'Selestat', - 'Marechal Taumaturgo', - 'Espiritu', - 'Kapangan', - 'Sirvar', - 'Casamassima', - 'Sukumo', - 'Twinsburg', - 'Ganyesa', - 'Sudley', - 'Dolynska', - 'Seminole', - 'Douar Ait Sidi Daoud', - 'Bouanri', - 'Bhojpur Jadid', - 'Cutlerville', - 'Iiyama', - 'Wanluan', - 'Rovato', - 'Beaconsfield', - 'Tsumeb', - 'Pitimbu', - 'Sint-Gillis-Waas', - 'Mapastepec', - 'Marchena', - 'Peterhead', - 'Indargarh', - 'Haldensleben', - 'Hermiston', - 'Maitland', - 'Alzey', - 'El Viso del Alcor', - 'Kudra', - 'Ferndale', - "Cassano d'Adda", - 'Tillaberi', - 'Balintawak', - 'Babai', - 'Cabusao', - 'Sherrelwood', - 'Henichesk', - 'Valle Vista', - 'Tonantins', - 'Realeza', - 'Aguas Formosas', - 'Gilching', - 'Dracevo', - 'Sogut', - 'Quartier Morin', - 'Kamwenge', - 'Sirnia', - 'Groveland', - 'Holalkere', - 'Diadi', - 'Al Brouj', - 'Ballitoville', - 'Roosevelt', - 'Garot', - 'Kassama', - 'Ghosai', - 'Magitang', - 'Suhbaatar', - 'Pescia', - 'Gazi', - 'Vigna di Valle', - 'Atok', - 'Springboro', - 'Amboanana', - 'Khonj', - 'Eruvatti', - 'Cheticheri', - 'Kabudarahang', - 'Tingloy', - 'Malgrat de Mar', - 'Brie-Comte-Robert', - 'Bandar-e Kong', - 'Ecclesall', - 'Abomsa', - 'Jakobstad', - 'Zola Predosa', - 'Texcaltitlan', - 'Puerto Morelos', - 'Jiabong', - 'Lumphat', - 'Ystrad Mynach', - 'Andrychow', - 'Rangra', - 'Kale', - 'Jamiltepec', - 'Devgadh Bariya', - 'Attapu', - 'Aradippou', - 'Sligo', - 'Lebbeke', - 'Rurrenabaque', - 'La Corredoria', - 'Binka', - 'Khamaria', - 'Gomishan', - 'Ermita', - 'Schkeuditz', - 'Venceslau Bras', - 'Ranst', - 'Zerong', - 'Bad Tolz', - 'Dumra', - 'Pokaran', - 'Sibila', - 'Vera', - 'Oued el Abtal', - 'Sirpur', - 'Maumelle', - 'West Manchester', - 'Badger', - 'Maghar', - 'Tinton Falls', - 'La Crau', - 'Gioia Tauro', - 'Krasnogorskiy', - 'Schonefeld', - 'Ghogardiha', - 'Deerfield', - 'Jaicos', - 'Sidi Redouane', - 'Naantali', - 'Meise', - 'Koropi', - 'Chiari', - 'Horseheads', - 'Ambatomirahavavy', - 'Blankenburg', - 'Seesen', - 'Izra', - 'Gulagac', - 'Raita', - 'Pauktaw', - 'Vila Real de Santo Antonio', - 'Sommerda', - 'Tiruvadi', - 'Cocos', - 'Cedar Mill', - 'Papanduva', - 'Guaranesia', - 'Senguio', - 'Pitt Meadows', - 'Biswanath Chariali', - 'Gerze', - 'Reinach', - 'Ad Dir`iyah', - 'Schwalmtal', - 'Fukusaki', - 'Diamante', - 'Siralkoppa', - 'Schneverdingen', - 'Pidhorodne', - 'Billinghurst', - 'Kodumba', - 'Diepenbeek', - 'Passagem Franca', - 'Iramala', - 'Pljevlja', - 'Ampanety', - 'Trzebinia', - 'Zaouia Ait Ishak', - 'Eitorf', - 'Ainan', - 'Vargem Alta', - 'Contenda', - 'La Ligua', - 'Shemonaikha', - 'Knightdale', - 'Kufstein', - 'Imouzzer Kandar', - 'Chennirkara', - 'Mavinpalli', - 'Ban Mon Pin', - 'Ashkezar', - 'Shimokizukuri', - 'Central Point', - 'San Teodoro', - 'Martin Coronado', - 'Morauna', - 'Shahgarh', - 'Sorgues', - 'Cerqueira Cesar', - 'Cacahoatan', - 'Uwchlan', - 'Montemurlo', - 'Gobabis', - 'White Oak', - 'Bierun Stary', - 'Bella Union', - 'Harpur', - 'Lumberton', - 'Liberal', - 'Stord', - 'Lebach', - 'Taka', - 'Frimley', - 'Chautapal', - 'Lumbayanague', - 'Anguillara Sabazia', - 'Haslett', - 'Paillaco', - 'Molesey', - 'Tavares', - 'Niagara-on-the-Lake', - 'Saugerties', - 'Mumbwa', - 'Prestatyn', - 'Butia', - 'Pindobacu', - 'Villefontaine', - 'Cheran', - 'Tazishan', - 'Menzel Abderhaman', - 'Aizumisato', - 'Douar Toulal', - 'Cirencester', - 'Karlshamn', - 'Ban Bueng Phra', - 'Calne', - 'Perumkulam', - 'Mahisi', - 'Cocoa', - 'Simri', - 'Nalua', - 'Dixon', - 'Ixtlahuacan del Rio', - 'Scituate', - 'Sao Jose de Piranhas', - "Sant'Antonio Abate", - 'Pruzhany', - 'Bouansa', - 'Cunco', - 'Malanday', - 'Chinna Ganjam', - 'Murugampalaiyam', - 'La Eliana', - 'Sabanitas', - 'Gentilly', - 'Hindoria', - 'Tanbaichicho', - 'Zatec', - 'Monkseaton', - 'Preveza', - 'Puranpur', - 'Svay Pak', - 'Sylvania', - 'Itaosy', - 'Lejiangxiang', - 'Cimarron Hills', - 'Guaymango', - 'Dharmsala', - 'Bukungu', - 'Taquarana', - 'Winthrop', - 'Royan', - 'Tirmitine', - 'Telpaneca', - 'Rahata', - 'Point Pleasant', - 'Cardedeu', - 'Sarauli', - 'Wervik', - 'Monor', - 'Morlanwelz-Mariemont', - 'Cotija de la Paz', - 'North Valley Stream', - 'West Chester', - 'Caowotan', - 'Ferguson', - 'Dadeldhura', - 'Santa Ana Jilotzingo', - 'Sahline', - 'Spoltore', - 'Manjha', - 'Fond des Blancs', - 'Fate', - 'El Bolson', - 'Akune', - 'Agua Branca', - 'Gautier', - 'Quaregnon', - 'Pfullingen', - 'Lagoa de Itaenga', - 'Ellensburg', - 'Befandriana Atsimo', - 'Anjahabe', - 'Ambalanirana', - 'Ambatomena', - 'Mitsinjo', - 'Belamoty', - 'Vohimasy', - 'Ampataka', - 'Ifanirea', - 'Tanambe', - 'Ambodinonoka', - 'Miarinavaratra', - 'Ambatosia', - 'Mahazoarivo', - 'Manantenina', - 'Bezaha', - 'Ranomena', - 'Nootdorp', - 'Bajo Boquete', - 'Shovot', - 'Durpalli', - 'Vitre', - 'Cafelandia', - 'Vista Hermosa de Negrete', - 'Kouloum', - 'Haukipudas', - 'Druten', - 'Chapada dos Guimaraes', - 'Heredia', - 'Kosatarosh', - 'Barao do Grajau', - 'Narapala', - 'Sukhasan', - 'Scorze', - 'Radeberg', - 'Laukaa', - 'Kaveripatnam', - 'Onex', - 'Ait Ben Daoudi', - 'Caconde', - 'Boiro', - 'Koliakkod', - 'Weirton', - 'La Nucia', - 'Sarso', - 'Burscheid', - 'Acqui Terme', - 'Varidhanam', - 'Ban Na Yang', - 'Colwood', - 'Konstantynow Lodzki', - 'Chichiriviche', - 'Southbourne', - 'El Rosal', - 'Saint Peter Port', - 'Carei', - 'Sarsawa', - 'Krommenie', - 'Utebo', - 'Makronia', - 'Ansonia', - 'San Ignacio Cerro Gordo', - 'Chilkuru', - 'Krizevci', - 'Fox Crossing', - 'Pitseng', - 'Atacames', - 'Pinole', - 'Kolbermoor', - 'El Malah', - 'Tak Bai', - 'Guru Har Sahai', - 'Motomachi', - 'Beni Zouli', - 'Aikaranad', - 'Neviges', - 'Casalgrande', - 'Malacky', - 'Lakhnadon', - 'Ayvacik', - 'Middlesex Centre', - 'Desavilakku', - 'Monserrato', - 'Bad Berleburg', - 'Eiheiji', - 'Nakasi', - 'Elamattur', - 'Zuidhorn', - 'Pirkkala', - 'Ab Pakhsh', - 'Prenzlau', - 'Ismailpur', - 'Kotekara', - 'Ranbirsinghpura', - 'Tado', - 'Lagoa Formosa', - 'Franklin Farm', - 'Sironko', - 'Beshkent Shahri', - 'Shirin', - 'Fakfak', - 'Mo i Rana', - 'Matteson', - 'Utazu', - 'Horsforth', - 'Somandepalle', - 'Nayagarh', - 'Bad Reichenhall', - 'Gatada', - 'Gardhabaer', - 'Madalag', - 'Amares', - 'Nanjanad', - 'San Carlos Park', - 'Guarei', - 'Ezhamkulam', - 'Sugaon', - 'Kasterlee', - 'Naousa', - 'Formoso do Araguaia', - 'Jaggampeta', - 'Pozzallo', - 'Hun', - 'Lagawe', - 'Korsimoro', - 'Ap Khanh Hung', - 'Signa', - 'Malazgirt', - 'Ajacuba', - 'Massaguet', - 'Kalmthout', - 'Lake Shore', - 'Coronado', - 'Groesbeek', - 'Hemmingen', - 'Kabbur', - 'Varapatti', - 'Arita', - 'Alsip', - 'San Sebastian de Buenavista', - 'Arac', - 'Duero', - 'Conceicao', - 'Mont-Saint-Hilaire', - 'Naaldwijk', - 'Traiskirchen', - 'Cinco Ranch', - 'Weissenburg', - 'Larne', - 'Malimono', - 'Horizontina', - 'North Myrtle Beach', - 'Anzoategui', - 'Fihaonana', - 'Guachucal', - 'Kara-Kol', - 'Oirschot', - 'Varzelandia', - 'Santa Fe Springs', - 'Zahana', - 'Dukli', - "Ben 'Aknoun", - 'Ronkonkoma', - 'Chelmno', - 'Nakhl-e Taqi', - 'Onalaska', - 'Acri', - 'Tradate', - 'Lakeway', - 'Cusano Milanino', - 'Bradfordville', - 'Qitai', - 'Dzuunharaa', - 'Alzenau in Unterfranken', - 'Las Terrenas', - 'Edam', - 'Nunungan', - 'Khetia', - 'Somerset East', - 'Sao Jose da Coroa Grande', - 'Republic', - 'Camarate', - 'Berkovitsa', - 'Odzak', - 'Carlos Spegazzini', - 'Brownwood', - 'Bad Durkheim', - 'Sebaste', - 'Ascencion de Guarayos', - 'Lancing', - 'Sabalpur', - 'Marktoberdorf', - 'Velez', - 'Purushottampur', - 'Sheridan', - 'Syosset', - 'Kalabahi', - 'Udumanthala', - 'Huehuetla', - 'Pastos Bons', - 'Shimomura', - 'Abdurahmoni Jomi', - 'Dusti', - 'Hazorasp', - 'Diallassagou', - 'Ware', - 'Starobilsk', - 'East St. Louis', - 'Owego', - 'Bremervorde', - 'Arilje', - 'Ibirataia', - 'Tocaima', - 'Lukovit', - 'Oulmes', - 'Taft', - 'Jwaneng', - 'Wisconsin Rapids', - 'Terra Santa', - 'Itajuipe', - 'Sompeta', - 'Ban Bo Haeo', - 'Heerde', - 'Antotohazo', - 'Pastavy', - 'Chowchilla', - 'Camrose', - 'Kabala', - 'Kralupy nad Vltavou', - 'Zlotow', - 'Maranchi', - 'Presidente Olegario', + 'Belakvadi', + 'Santa Sylvina', + 'Adelfia', + 'Mandya', + 'Bay City', + 'Rosny-sous-Bois', + 'Angono', + 'Uzhhorod', + 'Ap Phu Hai', + 'Bembe', + 'Palma di Montechiaro', + 'Shanhe', + 'Oued el Djemaa', + 'Atturkuppam', + 'Adwa', + 'Zabbar', + 'Bhagalpur', + 'West Valley City', + 'Ruislip', + 'Talatamaty', + 'Ban Wang Krachae', + 'Iskapalem', + 'Kashmar', + 'Bouchagroun', + 'Timissa', + 'Xizi', + 'Elmwood Park', + 'Santa Ana Huista', + 'Hickory Hills', + 'Rayong', + 'Zambrow', + 'Diamantina', + 'Carmen de Areco', + 'Kodigenahalli', + 'Jamikunta', + 'Soyaux', + 'Juraqan', + 'Burgess Hill', + 'Piskent', + 'Wloclawek', + 'Meerssen', + 'Cruz Alta', + 'Huitzilan', + 'Melo', + 'Takelsa', + 'Xiaoyi', + 'Jhabua', + 'Jagna', + 'Sondiha', + 'Sopiste', + 'Koungou', + 'Yeldurti', + 'Dois Irmaos', + 'Jaru', + 'Kulasekharapuram', + 'Shinshiro', + 'Qaanaaq', + 'Cangucu', + 'Rosas', + 'Westtown', + 'Kaka', + 'Gobardanga', + 'Fangyuan', + 'Kallupatti', + 'Raiganj', + 'Chitapur', + 'Benevides', + 'Miercurea-Ciuc', + 'Massapequa', + 'Kallakkudi', + 'Dinuba', + 'Ouagadougou', + 'Hanford', + 'Mfou', + 'Mandalapalle', + 'Alvand', + 'Fort Campbell North', + 'Kueneng', + 'Bunnik', + 'Radnor', + 'Ikoto', + 'Blankenburg', + 'Santa Marinella', + 'Snizhne', + 'Zerakpur', + 'Caetite', + 'Boechout', + 'Gulbarga', + 'Southern Pines', + 'Nanakuli', + 'Miarinarivo', + 'Lakshmeshwar', + 'Gaocheng', + 'Laheji', + 'Bagumbayan', + 'Goshen', + 'Neopolis', + 'Baohe', + 'Diss', + 'Hangu', + 'Muyinga', + 'Apahida', + 'Miagao', + 'Videm pri Ptuju', + 'Kuysinjaq', + 'Kalfou', + 'Danilovgrad', + 'Ambalatany', + 'Katkol', + 'Forio', + 'Chaohucun', + 'Manki', + 'Capulhuac', + 'White Rock', + 'Ban Pa Tueng', + 'Marahom', + 'Constanta', + 'Ntoum', + 'Los Minas', + 'Nabaruh', + 'Mahuver', + 'Crosia', + 'Bilenke', + 'Miranda de Ebro', + 'Oshakati', + 'Kochugaon', + 'Paralimni', + 'Ramon Santana', + 'Villa Bisono', + 'Ichikai', + 'Nefasit', + 'Sangmelima', + 'Jasmine Estates', + 'Marion Oaks', + 'Ahmedabad', + 'Bello', + 'Koporo-Kenie-na', + 'Attard', + 'Kamargani', + 'Greenwood Village', + 'Dubacherla', + 'Ad Dabyah', + 'Katosi', + 'Nhandeara', + 'Thap Than', + 'Andranambolava', + 'Totutla', + 'Gambettola', + 'Hatoyama', + 'Shanyincun', + 'Pinjranwan', + 'Yadiki', + 'Ceelbuur', + 'Petrovec', + 'Tighenif', + 'Berwick-Upon-Tweed', + 'Pakhtaobod', + 'Sentilj', + 'Barahra', + 'Pingdeng', + 'Zunil', + 'Darwen', + 'Trang', + 'Napier', + 'Oroshaza', + 'Sao Tiago', + 'Sipe Sipe', + 'Gera', + 'Sadhoa', + 'Sungo', + 'Papagaios', + 'Yahaba', + 'Tassera', + 'Cuyotenango', + 'Doumanaba', + 'Tortuguitas', + 'La Prairie', + 'Enfida', + 'Nafpaktos', + 'Chhapra', + 'Hoenheim', + 'Bondoufle', + 'La Virginia', + 'Guneysu', + 'Champaign', + 'Kampala', + 'Sundararaopeta', + 'Uppidamangalam', + 'Ikkadu', + 'Valjevo', + 'Xidiancun', + 'Bangkinang', + 'Ermenek', + 'Bayaguana', + 'Bitburg', + 'North Smithfield', + 'Lagunas', + 'Chuquicamata', + 'Kannamangalam', + 'Taunggyi', + 'Bibipet', + 'Fangcun', + 'Baikatpur', + 'Sultanpur', + 'Rio de Mouro', + 'Dongcun', + 'Yali', + 'Gora Kalwaria', + 'Ottawa', + 'Achankovil', + 'Przemysl', + 'Ambohinamboarina', + 'Sangalbahita', + 'Ban Pet', + 'Segaon', + 'Watertown', + 'Baghmaria', + 'Meissen', + 'Chebli', + 'Santo Antonio do Descoberto', + 'Santa Rosa de Rio Primero', + 'Gold Canyon', + 'Marburg', + 'Bhadas', + 'Arcos', + 'Kediri', + 'Kasaoka', + 'Teisendorf', + 'Tadikombu', + 'Enger', + 'Hajan', + 'Fenggeling', + 'Guroymak', + 'Kolanpak', + 'Magam', + 'Marsberg', + 'Panagar', + 'Nove Mesto nad Vahom', + 'Koluszki', + 'Tan-Tan', + 'Dehdasht', + 'Karimganj', + 'Tekman', + 'Dudelange', + 'Remscheid', + 'Xiaolongtan', + 'Srisailain', + 'Pike Road', 'Villaquilambre', - 'Donihue', - 'Karia Ba Mohamed', - 'Villa Rica', - 'Ayyampettai', - 'Durant', - 'Birnagar', - 'Bergeijk', - 'Retiro', - 'Rutherford', - 'Hopkins', - 'San Juan Ermita', - 'Nanthankulam', - 'Bonneuil-sur-Marne', - 'Kurumbapalaiyam', - 'Hopkinton', - 'Koporo-Kenie-na', - 'Kiliia', - 'Bayshore Gardens', - 'Ngathainggyaung', - 'Palestine', - 'Harihans', - 'Altonia', - 'Wallingford Center', - 'Melmuri', - 'Riom', - 'Los Lagos', - 'San Rafael La Independencia', - 'Adliswil', - 'Schlieren', - 'Sendamaram', - 'Paglat', - 'Rufino', - 'Lansdale', - 'Gunri', + 'Neustadt', + 'Anserma', + 'Prerov', + 'Mandleshwar', + 'Entrerrios', + 'Andranopasy', + 'Ambohibe', + 'Eagle Mountain', + 'Kadimetla', + 'Obala', + 'Nichinan', + 'Kouloum', + 'Karumba', + 'Sagamihara', + 'Multi', + 'Imabari', + 'Vizela', + 'Chiquimula', + 'Okkerneutboom', + 'Faribault', + 'Seyhan', + 'Vinces', + 'Vijayapuri North', + 'Santa Clara del Cobre', + 'Yorkville', + 'Purisima de Bustos', + 'Belhi', + 'Balarampur', + 'Buluan', + 'Jefferson Valley-Yorktown', + 'Buchs', + 'Agua Boa', + 'Karayazi', + 'Raipur Buzurg', + 'Sisa', + 'Adigala', + 'Demba', + 'Tangerhutte', + 'Sidi Moussa Ben Ali', + 'Alpharetta', + 'Shangping', + 'Sabha', + 'Iguatemi', + 'Ragampet', + 'Andranovao', + 'Chitaga', + 'Olalapadi', + 'Chenalho', + 'Kent', 'Gorele', - 'Alfeld', - 'Phoenixville', - 'Ozorkow', - 'Country Walk', - 'South San Jose Hills', - 'Tlalnelhuayocan', - 'Kljuc', - 'Hem', - 'Snina', - 'Altus', - 'Dhariwal', - 'Aroeiras', - 'Djidian', - 'Vadakkangara', - 'Choghadak', - 'Peduasi', - 'Aburi', - "Qo'shko'pir", - 'Abong Mbang', - 'Lupeni', - 'Tyele', - 'Tsivory', - 'Balilihan', - 'Cerkes', - 'Qaryat al Qi`an', - 'Valle', - "Nefas Mewch'a", - 'Perunturuttu', - 'Anderanboukan', - 'Majdanpek', - 'Ceglie Messapico', - 'Zapote', - 'Creve Coeur', - 'Martinsburg', - 'Round Lake', - 'Kinzau-Vuete', - 'Doura', - 'Blooming Grove', - 'Togba', - 'Afranio', - 'Bensenville', - 'Sao Raimundo das Mangabeiras', - 'Mansa Konko', - 'Trinity', - 'Sonhauli', - 'Lakhna', - 'Almel', - 'Rishivandiyam', - 'Lelydorp', - 'Meerssen', - 'Jasidih', - 'Broughty Ferry', - 'Samma', - 'Seagoville', - 'Siyazan', - 'Maimon', - 'Soalkuchi', - 'Molakalumuru', - 'Centerton', - 'Santa Catarina Juquila', - 'Selwyn', - 'Elumalai', - 'St. Michael', - 'Laualagaon', - 'Carnaiba', - 'Kangazha', - 'Telwa', - 'Adria', - 'Castaic', - 'Aldama', - 'Futog', - 'Szamotuly', - 'Basatpur', - 'Mukkanur', - 'Enkhuizen', - 'Bonanza', - 'Bergneustadt', - 'Kilmangalam', - 'Manikkal', - 'Le Puy-en-Velay', - 'Lede', - 'Mossendjo', - 'Ribeirao Branco', - 'Chakur', - 'Manakayi', - 'Ubaira', - 'Urucara', - 'Sanharo', - 'Tarifa', - 'Ballincollig', - 'Londerzeel', - 'Seara', - 'Knik-Fairview', - 'Uetersen', - 'Medjedel', - 'Carlos Chagas', - 'Volketswil', - 'Tillsonburg', - 'Eastwood', - 'Fairwood', - 'Engenheiro Coelho', - 'Maurepas', - 'Bellwood', - 'East Dereham', - 'Onga', - 'Mullach Ide', - 'Stannington', - 'Reriutaba', - 'Ajnala', - 'Leposaviq', - 'Saylac', - 'Toshloq', - 'Miyatoko', - 'Timoktene', - 'Los Alcazares', - 'Renningen', - 'Kalugumalai', - 'Jbabra', - 'Antombana', - 'Felanitx', - 'Five Forks', - 'Ploemeur', - 'Preakness', - 'Majhua', - 'Valavanur', - 'Al Jawf', - 'Anna', - 'Jalakandapuram', - 'San Mauro Torinese', - 'Colonia', - 'Skara', - 'Windham', - 'Shika', - 'Rhynern', - 'Tamri', - 'Mohana', - 'Liuma', - 'Clive', - 'Liancourt', - 'Narangba', - 'Meylan', - 'Kasongan', - 'Elizabeth City', - 'Nederland', - 'Bougtob', - 'Tomaszow Lubelski', - 'Crimmitschau', - 'Paluan', - 'San Sebastian Salitrillo', - 'Miracema do Tocantins', - 'Ban Mae Hia Nai', - 'Erumakkuzhi', - 'Zhosaly', - 'Kingsland', - 'Pizarro', - 'Tarrafal', - 'Bhadaur', - 'Shenandoah', - 'Ebbw Vale', - 'Garuva', - 'Boom', - 'Mingjiujie', - 'Leteri', - 'Wheatfield', - 'Morros', - 'Zakiyah', - 'Miracatu', - 'Lessines', - 'Matipo', - 'Kumbhraj', - 'Mennzel Bou Zelfa', - 'Mellacheruvu', - 'Berea', - 'Shaogang', - 'Glinde', - 'Ban Mae Kha Tai', - 'Sebt Gzoula', - 'Orhaneli', - 'Hochheim am Main', - 'Kothia', - 'Morro da Fumaca', - 'Kulu', - 'Arcata', - 'Baena', - 'Stabroek', - 'Guadix', - 'Parole', - 'Sokolow Podlaski', - 'Ba', - 'Rohar', - 'Melville', - 'Oxon Hill', - 'Asuncion Nochixtlan', - 'Thalwil', - 'Lodhwe', - 'Tsetserleg', - 'Tessenderlo', - 'Guanzhai', - 'Santa Cruz Zenzontepec', - 'Bilar', - 'Iselin', - 'Brook Park', - 'Harnosand', - 'Galhinna', - 'Huercal de Almeria', - 'St. Marys', - 'Tadikonda', - 'Madre de Deus', - 'Anicuns', - 'Tatsuno', - 'Palaiyampatti', - 'Hassleholm', - 'Buikwe', - 'Appley Bridge', - 'Goffstown', - 'Rawmarsh', - 'Ghedi', - 'Kivsharivka', - 'Potirendaba', - 'Bitkine', - 'Rhaude', - 'Vlotho', - 'Karcag', - 'Kalynivka', - 'Chubek', - 'San Lorenzo de El Escorial', - 'Busovaca', - 'Schwalmstadt', - 'Staines-upon-Thames', - 'Unquillo', - 'Zagarolo', - 'Pinas', - 'San Celoni', - 'Sirvel', - 'Fushe-Kruje', - 'Kherameh', - 'Ajaigarh', - 'Foxborough', - 'Tinoc', - 'Giszowiec', - 'Boerne', - 'Vellmar', - 'Tirmalgiri', - 'Qasr-e Shirin', - 'Sharon', - 'Bedlington', - 'Sacavem', - 'Hoppegarten', - 'Eragny', - 'Alcantara', - 'La Marque', - 'Catak', - 'Castel Maggiore', - 'Kotancheri', - 'Kunitomi', - 'Pio IX', - 'Kannapuram', - 'Osku', - 'Hessisch Oldendorf', - 'Lagoa da Canoa', - 'Od', - 'Kariyapatti', - 'Mill Hill', - 'Matelandia', - 'Cognac', - 'Ngolonianasso', - 'Shimokodanaka', - 'Narlica', - 'Coalcoman de Vazquez Pallares', - 'Haaltert', - 'Kassaro', - 'Jucuapa', - 'Achocalla', - 'Bakhmach', - 'Bonen', - 'Hellemmes-Lille', - 'Chouafa', - 'Zhangshicun', - 'Choi Hung', - 'Arroyo Grande', - 'Astrea', - 'Albert Lea', - 'Cullman', - 'Baliangao', - 'Lahnstein', - 'Dumjor', - 'Ponedera', - 'Johnstown', - 'Orestiada', - 'Juvisy-sur-Orge', - 'New River', - 'Mukkudal', - 'Vechelde', - 'Montrouis', - 'Pomaz', - 'Castelfidardo', - 'Kreminna', - 'Svatove', - 'San Vicente Pacaya', - 'Ocean Springs', - 'Fatick', - 'Kronberg', - 'Devadanappatti', - 'Basse Santa Su', - 'Unhel', - 'Winder', - 'Hardinxveld-Giessendam', - 'Amvrosiivka', - 'Foum el Anser', - 'Belo Campo', - 'Tallmadge', - 'San Blas Atempa', - 'Tilothu', - 'Niar', - 'Konz', - 'Nordestina', - 'Fairmont', - 'Korsun-Shevchenkivskyi', - 'Quitandinha', - 'Kumarapuram', - 'Santa Marinella', - 'Srikhanda', - 'North Babylon', - 'Inhapi', - 'Crowley', - 'North Bay Shore', - 'Aragarcas', - 'Harij', - 'Tinajeros', - 'Longjia', - 'Rio Maria', - 'Bhawanipur', - 'Itapororoca', - 'Sanpaicun', - 'Bracciano', - 'East Goshen', - 'Straseni', - 'Walcourt', - 'Greene', - 'Cesario Lange', - 'Sigmaringen', - 'Franklin Park', - 'Clonmel', - 'Qatlupur', - 'Illertissen', - 'Mumford', - 'Assa', - 'Filomeno Mata', - 'Chennevieres-sur-Marne', - 'Agarpur', - 'Baependi', - 'Santiago Ixcuintla', - 'Sao Benedito do Rio Preto', - 'El Transito', - 'Olten', + 'Fiumicino', + 'Carrboro', + 'Sihanoukville', + 'Cepin', + 'Mawlaik', + 'Melmuri', + 'Mapai', + 'Ciudad Lopez Mateos', + 'Santaluz', + 'Leninskoe', + 'Esbiaat', + 'Shterpce', + 'Sidi Abdelkarim', + 'Meoqui', + 'Wajimazakimachi', + 'Sulya', + 'Kangersuatsiaq', + 'Telpur', + 'Osmanabad', + 'Diourbel', + 'Waycross', + 'Hohenmolsen', + 'Mukhtarpur Salkani', + 'Campo Grande', + 'Willebroek', + 'Bamaur', + 'Vico Equense', + 'Andipalaiyam', + 'Peraia', + 'Ashtown', + 'Biro', + 'Weddington', + 'Arboletes', + 'Tauramena', + 'Bayserke', + 'Toretsk', + 'Ha Tinh', + 'Redondela', + 'Patcham', + 'Hilden', + 'New Corella', + 'San Francisco del Rincon', + 'Tlacolulan', + 'Letlhakane', + 'Rubanda', + 'Bohechio', + 'Boujediane', + 'Hacienda Heights', + 'Alderwood Manor', + 'Hendrik-Ido-Ambacht', + 'Dhangadhi', + 'Chanute', + 'Paraippatti', + 'Senftenberg', + 'Remich', + 'Nimbahera', + 'Kadrabad', + 'Taperoa', + 'Dharan', + 'Bidar', + 'Jiaozuo', + 'Waterford', + 'Nanao', + 'Verona', + 'Bawali', + 'Vellakkovil', + 'Lakkavaram', + 'Lyss', + 'Punnavalli', + 'Martil', + 'Melut', + 'Newburgh', + 'Qaskeleng', + 'Crevillente', + 'Assemini', + 'Kilankundal', + 'Rades', + 'Beidao', + 'Leiden', + 'Phu Ly', + 'Antehiroka', + 'Ouolodo', + 'Vaddepalli', + 'Andalusia', + 'Marechal Candido Rondon', + 'Malaut', + 'Port Shepstone', + 'Julich', + 'Spitak', + 'Si Wilai', + 'Oblesevo', + 'Nantes', + 'Totana', + 'Godhavn', + 'Augusto Correa', + 'Mirchpur', + 'Yzeure', + 'Pelabuhanratu', + 'Werneuchen', + 'Dospat', + 'Ikkarai Boluvampatti', + 'Sareh Mowndeh', + 'Ramiriqui', + 'Sorriso', + 'Wasi', + 'Indi', + 'Talavera de la Reina', + 'Lichuan', + 'Cachoeiro de Itapemirim', + 'Kariba', + 'Narita', + 'Dazhou', + 'Marmeleiro', + 'Wollongong', + 'Alwaye', + 'Fazilka', + 'Tynemouth', + 'Aramari', + 'Bantay', + 'Helmond', + 'Talegaon Dabhade', + 'Dowbaran', + 'Babak', + 'Country Walk', + 'Irara', + 'Simoes', + 'Surakarta', + 'Carapegua', + 'Lal Khatanga', + 'Nowshera', + 'Sao Leopoldo', + 'Pinrang', + 'Bouchegouf', + 'Kipili', + 'Yuzhne', + 'Narasimharajapura', + 'Halls', + 'Paco', + 'Tarija', + 'Vergina', + 'Sheridan', + 'Bastrop', + 'Cota', + 'Jinghong', + 'Aylestone', + 'Tlalixcoyan', + 'Tiszakecske', + 'Blackwells Mills', + 'Serarou', + 'Kherameh', + 'Kampung Baharu Nilai', + 'Gomboussougou', + 'Mulheim-Karlich', + 'Oshnaviyeh', + 'Ocnita', + 'Thornton Heath', + 'Enfield', + 'Castricum', + 'Rio dos Cedros', + 'West Chester', + 'Beanana', + 'Wiener Neudorf', + 'Takkolam', + 'Santo Antonio de Posse', + 'Les Abricots', + 'Higashi-Matsuyama', + 'Burutu', + 'Yingtan', + 'Valkeala', + 'Council Bluffs', + 'North Decatur', + 'Gaozhou', + 'Ghabrah', + 'Barun', + 'Mugla', + 'Olgiy', + 'Pramatam', + 'Ituacu', + 'Hihya', + 'Faridkot', + 'Zarand', + 'Escada', + 'Ambaguio', + 'Sao Joao Nepomuceno', + 'Bardoli', + 'Murakami', + 'Leinefelde', + 'Zawyat an Nwacer', + 'Banjul', + 'Genthin', + 'Susono', + 'Buin', + 'Vryheid', + 'El Tocuyo', + 'Pompton Lakes', + 'Ibipitanga', + 'Magwe', + 'Ocuilan de Arteaga', + 'Solleftea', + 'Areal', + 'Casal di Principe', + 'Hyvinkaa', + 'Kukdeshwar', + 'Ludlow', + 'Klamath Falls', + 'Husnabad', + 'Belwara', + 'Tonisvorst', + 'Shekhupur', + 'Yokaichiba', + 'Amlash', + 'Usumatlan', + 'Mascota', + 'Hemau', + 'Bhawana', + 'Dongshi', + 'Siriari', + 'Gulf Hills', + 'Khromtau', + 'Jalal-Abad', + 'Ayvalik', + 'Baza', + 'Knowsley', + 'Gibsonville', + 'Tondangi', + 'Uzunkopru', + 'Pedda Penki', + 'New Rochelle', + 'Limache', + 'Nasiyanur', + 'Pansemal', + 'Ottendorf-Okrilla', + 'Karukurti', + 'Xiangjiaba', + 'Varennes', + 'Del Gallego', + 'Riviera Beach', + 'Chicacole', + 'Marignane', + 'Nova Vas', + 'Dammaj', + 'Kayunga', + 'Wallaceburg', + 'Bangkalan', + 'Kandi', + 'Corman Park No. 344', + 'Lavinia', + 'Estelle', + 'Parthenay', + 'Datiana', + 'Tamzoura', + 'Banapur', + 'Campia Turzii', + 'Pylaia', + 'Las Heras', + 'Diamantino', + 'Dachepalle', + 'Vegarai', + 'Campbell', + 'Sao Cristovao', + 'Nossa Senhora do Socorro', + 'Ocotal', + 'Del Carmen', + 'Mangalvedha', + 'Bamba', + 'Yaojia', 'Ecully', - 'Noci', - 'Chhoti Sadri', - 'Krasyliv', - 'Newburyport', - 'Campo de la Cruz', - 'Stekene', - 'San Rafael Pie de la Cuesta', - 'Cagdianao', - 'Worth am Rhein', - 'Louviers', - 'Saladas', - 'Ammapettai', - 'Almondbury', - 'Redland', - 'Nari Bhadaun', - 'Maryland City', - 'Cortes', - 'Apastepeque', - 'Sendarappatti', - 'Capoeiras', - 'Mineros', - 'Lake Ronkonkoma', - 'Mirante do Paranapanema', - 'Daryabad', - 'Lamrasla', - 'Xintian', - 'Picui', - 'Novopavlovka', - 'Cran-Gevrier', - 'Pembroke', - 'Memuro-minami', - 'Sandare', - 'Shaoyu', - 'Nuuk', - 'Skydra', - 'Calverton', - 'Karuppur', - 'Tha Bo', - 'Taio', - 'Melzo', - 'San Jose Tenango', - 'Lora del Rio', - 'Carrieres-sous-Poissy', - 'Talata-Volonondry', - 'Riachao do Dantas', - 'Pully', - 'Pontalina', - 'Morretes', - 'Gerd Faramarz Shahediyeh', - 'Abrandabad-e Shahediyeh', - 'Kitagata', - 'Nossombougou', - 'Nehbandan', - 'Mangualde', - 'Belem de Sao Francisco', - 'Lenoir', - "Do'stlik Shahri", - 'Hadleigh', - 'Sint-Genesius-Rode', - 'Ommen', - 'Volochysk', - 'Puttlingen', - 'Bingley', - 'Rutigliano', - 'Taung', - 'Szigethalom', - 'Sakoueba', - 'Navraftor', - 'Senkaya', - 'Panama City Beach', - 'Pinecrest', - 'Parchim', - 'Palos Hills', - 'Fomboni', - 'Kadan', - 'Paraibano', - 'Kristiansund', - 'Mannara', - 'Rosendael', - 'Phelan', - 'Ait Bouchta', - 'Bni Bouayach', - 'Tarrega', - 'Kasba Maker', - 'Paraibuna', - 'Yupiltepeque', - 'Siloe', - 'Bideford', - 'Luz', - 'Ban Mai', - 'Monte Cristo', - 'Regensdorf', - 'Yoichi', - 'Mulanur', - 'Shuangluan', - 'South Orange Village', - 'Bagnols-sur-Ceze', - 'Moissy-Cramayel', - 'Staveley', - 'Asakapalle', - 'Mathurapur', - 'Pisz', - 'Shaw', - 'Savastepe', - 'Narayankher', - 'Monforte de Lemos', - 'Sivandipuram', - 'Santa Iria da Azoia', - 'Carrigaline', - 'Comodoro', - 'Kanp', - 'Ikniwn', - 'Calera de Tango', - 'Leczna', - 'Centralia', - 'Fulwood', - 'Ocean Acres', - 'Eski-Nookat', - 'Kingstowne', - 'Kottukal', - 'Julio de Castilhos', - 'Budrio', - 'Galaat el Andeless', - 'Mahiari', - 'Bad Segeberg', - 'Kurakhove', - 'Baixa Grande', - 'El Astillero', - 'Pieksamaki', - 'Bronte', - 'Pijijiapan', - 'Zielonka', - 'Taqah', - 'Bani Hasan ash Shuruq', - 'Nazare Paulista', - 'Farias Brito', - 'Bettioua', - 'Taku', - 'Gameleira', - 'Sipacate', - 'Stillorgan', - 'Tirunageswaram', - 'Sahna', - 'Filadelfia', - 'Sikhio', - 'Blindio', - 'Serrita', - 'Dagana', - 'Amaraji', - 'Kudatini', - 'Budhni', - 'Kishi', - 'Shaying', - 'Konskie', - 'Santiago de Maria', - "Bet She'an", - 'North Massapequa', - 'Kiangara', - 'Ranquitte', - 'Griffith', - 'Palamos', - 'San Sebastian Tutla', - 'Udaipura', - 'Sarvestan', - 'Taufkirchen', - '`Anbarabad', - 'Rikuzen-Takata', - 'Solonopole', - 'Dapi', - 'Oconomowoc', - 'Quibaxi', - 'Aldo Bonzi', - 'Steubenville', - 'South Fayette', - 'Gossau', - 'Sycamore', - 'Vredendal', - 'Logansport', - 'Bhadrapur', - 'Tummalapenta', - 'Redhill', - 'Laives', - 'Asane', - 'Kottapalle', - 'Corbetta', - 'Petawawa', - 'Colonial Heights', - 'Xochiatipan de Castillo', - 'Zinvie', - 'Qishe', - 'Guayama', - 'El Achir', - 'Heckmondwike', - 'Bouarouss', - 'Lavasan', - 'Inga', - 'Piatykhatky', - 'Citluk', - 'Keskin', - 'Heusweiler', - 'Minamishibetsucho', - 'Dobrush', - 'Pinabacdao', - 'Yoshimi', - 'Schofield Barracks', - 'Palanga', - 'Andalucia', - 'Tominian', - 'Gangwuzhen', - 'Svilengrad', - 'Beerse', - 'Sangre Grande', - 'Canby', - 'Dumri', - 'Jora Khurd', - 'Bourbonnais', - 'Menasha', - 'Lomianki', - 'Ouankoro', - 'Louny', - 'Cirie', - 'Pottanur', - 'Feyzabad', - "Terra Roxa d'Oeste", - 'Ambiula', - 'Raisari', - 'Coronda', - 'Poulton le Fylde', - 'Convencion', - 'Polohy', - 'Gandarbal', - 'Faches-Thumesnil', - 'Manikpur', - 'McAlester', - 'Caldas de Montbuy', - 'Paharpur', - 'Shorewood', - 'Campos Belos', - 'Mure', - 'White Settlement', - 'Binh Minh', - 'Varjota', - 'Fort Carson', - 'Maoussa', - 'Hybla Valley', - 'Pavullo nel Frignano', - 'San Vito dei Normanni', + 'Tadjourah', + 'Flanders', + 'Nordhragota', + 'Stutterheim', + 'Sher', + 'Seferhisar', + 'Lieshout', + 'Brignoles', + 'Alcoa', + 'Senta', + 'Isola della Scala', + 'Ekchari', + 'Formello', + 'Rio Bananal', + 'Uppalapadu', + 'Apatzingan de la Constitucion', + 'Yuancun', + 'Mandi Burewala', + 'Baraka', + 'Ban Bang Khu Lat', + 'Tradate', + 'Fangliao', + 'Santa Ana de Yacuma', + 'Castel San Giovanni', + 'Aachen', + 'Ginan', + 'Riviere-du-Loup', + 'Blain', + 'Alawandi', + 'Xo`jayli Shahri', + 'Samut Prakan', + 'Ban Wang Nok Aen', + 'Triprangottur', + 'Tumbes', + 'Vandam', + 'Bistan', + 'Punnaikkayal', + 'St. Francis', + 'Garforth', + 'Sultanbeyli', + 'Jalpaiguri', + 'Nelas', + 'Embrun', + 'Karia Ba Mohamed', + 'Guasavito', + 'Chiroqchi', + 'Leander', + 'Adrano', + 'Boudjima', + 'Ostroh', + 'Kodriva', + 'Meriden', + 'Nova Laranjeiras', + 'Barnoldswick', + 'Urbiztondo', + 'Marapanim', + 'Jiangshan', + 'Jamshoro', + 'Aki', + 'Lackawanna', + 'Kafr Nubl', + 'Siroda', + 'Whittier', + 'Junqueiro', + 'Karavaram', + 'Jaguariaiva', + 'Fort Stewart', + 'Alvarado', + 'Vicopisano', + 'Raseiniai', + 'Zolotonosha', + 'Arbutus', + 'Parsahi Sirsia', + 'Alcora', + 'Canutama', + 'Edmonton', + 'Kalaa Srira', + 'Shirayamamachi', + 'Orito', + 'Mahadebnagar', + 'Wallaroo', + 'Ciampino', + 'Sirumugai', + 'Zhangshicun', + 'Fanambana', + 'Los Guayos', + 'Santa Gertrudes', + 'Godome', + 'Formby', + 'Paramankurichi', + 'Caratinga', + 'Dayalpur Sapha', + 'Mahuakheraganj', + 'Pine Hill', + 'Zhosaly', + 'Kousseri', + 'Jabalpur', + 'Bad Lauchstadt', + 'Julu', + 'Cortazar', + 'Drexel Heights', + 'Bolzano', + 'Plano', 'Grossenhain', - 'Borgo San Lorenzo', - 'Kikube', - 'Berkhampstead', - 'Cofradia', - 'Belterra', - 'Dolny Kubin', - 'Southeast', - 'Tora', - 'Chapelle', - 'Antonina', - 'General Juan Madariaga', - 'Madalena', - 'Heguri', - 'Calenzano', - 'Barikot', - 'Ghouazi', - 'Agua Azul do Norte', - 'Kopa', - 'East Riverdale', - 'Arajpur', - 'Wandsworth', - 'Mayorga', - 'Bobingen', - 'Kety', - 'Ricaurte', - 'Manyas', - 'Pedra Preta', - 'Sao Tiago de Custoias', - 'Oroszlany', - 'Fuente-Alamo de Murcia', - 'Luganville', - 'Ismaning', - 'Tottiyam', - 'Scarsdale', - 'Bidestan', - 'Kotta Kalidindi', - 'Sidi Allal Tazi', - 'Tlacoachistlahuaca', - 'Libjo', - 'Myslenice', - 'Badkulla', - 'Spanish Lake', - 'Middelharnis', - 'Annakunnu', - 'Vilavur', - 'Buadiposo-Buntong', - 'Nigran', - 'Chodziez', - 'Taperoa', - 'Timri', - 'Whitestown', - 'Carmelo', - 'Abangaritos', - 'Frankenberg', - 'Bryn Mawr-Skyway', - 'Keszthely', - 'Targu Neamt', - 'Cristinapolis', - 'Porto Novo', - 'Schwechat', - 'Destelbergen', - 'Gidi', - 'Valenza', - 'Piossasco', - 'Zuhres', - 'Matigou', - 'Koratagere', - 'Lakshmaneswaram', - 'Tordera', - 'Ulao', - 'Banbalah', - 'Buchen in Odenwald', - 'Tillmans Corner', - 'Fecamp', - 'Itabera', - 'Jasien', - 'Dumont', - 'Campina Verde', - 'Toyono', - 'Marcos', - 'Marsciano', - 'Rwamagana', - 'Nipomo', - 'Soisy-sous-Montmorency', - 'Biro', - 'Ashtabula', - 'Sakri', - 'Terrell', - 'Dbaiye', - 'Antsampanimahazo', - 'Antanambe', - 'Manampatrana', - 'Alakamisy', - 'Maroteza', - 'Bemahatazana-Belobaka', - 'Vohilengo', - 'Amboahangibe', - 'Mahazoma', - 'Ambongo', - 'Alatsinainy Ialamarina', - 'Analaiva', - 'Maroaloka', - 'Belobaka', - 'Ankofa', - 'Matsakabanja', - 'Ambovombe Afovoany', - 'Tsianisiha', - 'Beantake', - 'Behenjy', - 'Tranoroa', - 'Qal`ah-ye Zal', - 'General Deheza', - 'Al Hamalah', - 'Ad Diraz', - 'Doruma', - 'Yoboki', - 'Mickleover', - 'Gondar', - 'Tankara', - 'Ghogaon', - 'Mahraurh', - 'Tall Qasab', - 'Athar', - 'Gorham', - 'Kamienna Gora', - 'Batie', - 'Kolonodale', - 'Serra Preta', - 'Bombon', - 'Tyagadurgam', - "Aci Sant'Antonio", - 'Cameron Park', - 'Wantagh', - 'Stony Plain', - 'Oak Bay', - 'Hijuelas', - 'San Cristobal Cucho', - 'Ariccia', - 'Mount Washington', - 'Sevierville', - 'Kosvik', - 'Lagoa do Carro', - 'Cuquio', - 'Hranice', - 'Halstenbek', - 'Sukhsena', - 'Rampur Tilak', - 'Rajmahal', - 'Terenure', - 'Konakli', - 'Dizicheh', - 'Antenor Navarro', - 'Melegnano', - 'North Grenville', - 'Sapeacu', - 'Santo Anastacio', - 'Kegalle', - 'Chaita', - 'Souba', - 'Payyannur', - 'Cohoes', - 'Ptuj', - 'Towamencin', - 'Jadcherla', - 'Torit', - 'Bodegraven', - 'Ranzan', + 'Ventaquemada', + 'Bechem', + 'Masaki', + 'Denpasar', + 'Gaggiano', + 'Roxas', + 'Wickede', + 'Gomoh', + 'Arklow', + 'Fossano', + 'Stralsund', + 'Kresek', + 'Pohrebyshche', + 'Siruvalur', + 'Karpi', + 'Adra', + 'Rafiganj', + 'Oftringen', + 'Ilirska Bistrica', + 'Anazzou', + 'Jonnagiri', + 'Norcross', + 'Sidi Bennour', + 'Berkine', + 'Ueckermunde', + 'Walsall', + 'Dingle', + 'Raxaul', + 'Chard', + 'Cataingan', + 'Ervadi', + 'Santiago', + 'Dallgow-Doberitz', + 'Poperinge', + 'Shankarpur', + 'Felton', + 'Nesebar', + 'Junction City', + 'Socorro', + 'Horb am Neckar', + 'Slavonski Brod', + 'Samaniego', + 'Bolingbrook', + 'Sombrerete', + 'Pastrana', + 'Bertoua', + 'Zungeru', + 'Ataleia', + 'Ath Thawrah', + 'Palisades Park', + 'Biatorbagy', + 'Perches', + 'Ashqelon', + 'Janjanbureh', + 'Stendal', + 'Quixabeira', + 'San Giovanni Valdarno', + 'Madepalli', + 'Bubanza', + 'Fatehpur Shahbaz', + 'Vigonza', + 'Pallikapuzha', + 'Stepney', + 'Sibiu', + 'Bodagudipadu', + 'Isidro Casanova', + 'Chatia', + 'Angor', + 'Ouro Verde', + 'Markala', + 'Sapkyo', + 'Amarapuuram', + 'Kannadiparamba', 'Koula', - 'Bucay', - 'Ben Daoud', - 'Erumapalaiyam', - 'Barvala', - 'Blythe', - 'Mukondapalli', - 'Doylestown', - 'Flora', - 'Loyalist', - 'Stilfontein', - 'Yeddumailaram', - 'Falkoping', - 'Bischheim', - 'Miyauchi', - 'Madeley', - 'Jiadong', - 'Agliana', - 'Kuchinda', - 'Quipapa', - 'Tres de Mayo', - 'Manthani', - 'Burke Centre', - 'Texistepeque', - 'Ammon', - 'Gitagum', - 'Palmi', - "Olho d'Agua das Cunhas", - 'Coltauco', - 'Kapsabet', - 'Shirosato', - 'Alice', - 'Union de San Antonio', - 'Roulia', - 'Deux-Montagnes', - 'Ituacu', - 'Narni', - 'Pelaya', - 'Pornic', - 'Mabehiri', - 'Chateauneuf-les-Martigues', - 'Khokha', - 'Natchitoches', - 'Franconia', - 'Wadowice', - 'Glenvar Heights', - 'Manambaro', - 'Saatli', - 'Nyborg', - 'Kostrzyn nad Odra', - 'Mebane', - 'Nao-Me-Toque', - 'Garches', - 'Nguigmi', - 'Fatima', - 'Tiffin', - 'Zapotlan del Rey', - 'Sint-Oedenrode', - 'Murambi', - 'Silvani', - 'Pudunagaram', - 'Anoka', - 'Puquio', - 'Bafanji', - 'Sanghera', - 'Veldurti', - 'Cal', - 'Mount Eliza', - 'Yuanquan', - 'Munguia', - 'Guapiara', + 'Laksar', + 'Uonuma', + 'Mainpuri', + 'Liberia', + 'Zarah Sharan', + 'Alcaniz', + 'Lakhaura', + 'Bansbari', + 'Kurikuppi', + 'Muan', + 'Sandrandahy', + 'Corail', + 'Sardrud', + 'Ambositra', + 'Zhengtun', + 'Ijebu-Ode', + 'Athol', + 'Menderes', + 'Shirbadgi', + 'Oaxaca', + 'Nogales', + 'Tekkattur', + 'Mobile', + 'Pazaryeri', + 'Hirakud', + 'Oyama', + 'Anrochte', + 'Mashiko', + 'Vobkent Shahri', + 'Neumunster', + 'Lingbao Chengguanzhen', + 'Elbistan', + 'Hakka', + 'Safranbolu', + 'Goulds', + 'Kadriye', + 'Komae', + 'Mahdia', + 'Peer', + 'Mbulungu', + 'Prince George', + 'Bir Ben Laabed', + 'Manukau City', + 'Isfana', + 'Buxton', + 'Hassfurt', + 'Paro', + 'Andimeshk', + 'Mockmuhl', + 'Leonora', + 'Healdsburg', + 'Pyrgos', + 'Dardilly', + 'Richardson', + 'Espiritu', + 'Dipolog', + 'Oyodo', + 'Concord', + 'Rye Brook', + 'Komoro', + 'Liedekerke', + 'Nishon Tumani', + 'Wyke', + 'Padangsidempuan', + 'Milton', + 'Princes Town', + 'Bandar-e Deylam', + 'Perry Hall', + "Ahmer el 'Ain", + 'Kampong Cham', + 'Vijayawada', + 'Kendal', + 'Sabinas', + 'Sihanamaro', + 'Kanye', + 'George Town', + 'Piquete', + 'Mullach Ide', + 'Fukushima', + 'Hohen Neuendorf', + 'Antsahabe', + 'Navoiy', + 'Riehen', + 'Castel Bolognese', + 'Virovitica', + 'Solihull', + 'Galaat el Andeless', + 'Endwell', + 'Langeloop', + 'Tuban', + 'Quaregnon', + 'Mastchoh', + 'La Chapelle-sur-Erdre', + 'Tapes', + 'Bac Ninh', + 'Tustin', + 'Leava', + 'Nagai', + 'Huatusco', + 'Kyjov', + 'Duque Bacelar', + 'Tanbei', + 'Copiague', + 'Langenzenn', + 'Iaciara', + 'Bimbo', + 'Guri', + 'Lake Ridge', + 'Star Dojran', + 'Nivala', + 'Damme', + 'Ambohitompoina', + 'Slovenj Gradec', + 'Najibabad', + 'Ziguinchor', + 'Chatenay-Malabry', + 'Mulanay', + 'Nakasi', + 'Guadalajara', + 'Bad Hersfeld', + 'Raciborz', + 'Sesto San Giovanni', + 'Walker', + 'Nonnweiler', + 'Dujiashigou', + 'Akune', + 'Malabang', + 'Konarka', + 'Chaves', + 'Yueqing', + 'Goias', + 'Isbergues', + 'Esenler', + 'Jovellanos', + 'Hajin', + 'Forest Acres', + 'Duchcov', + 'Keza', + 'Summit View', + 'Sokotindji', + 'Chitvel', + 'Tunis', + 'Sarkoy', + 'Nerang', + 'Berlaar', + 'Lukovica', + 'Bilthoven', + 'Muddebihal', + 'Thi Tran Mau A', + 'Fano', + 'Samtse', + 'Litian Gezhuang', + 'Dundalk', + 'Silistra', + 'Jangamguda', + 'Borna', + 'Bassar', + 'Gerstungen', + 'Talevad', + 'Worksop', + 'Sidlaghatta', + 'Chapulhuacan', + 'Guasdualito', + 'Garhi', + 'Cugir', + 'Epitacio Huerta', + 'Sankhavaram', + 'Sabotsy', + 'Nausori', + 'Purnea', + 'Ponnamaravati', + 'Sarkikaraagac', + 'Bourem', + 'Quepos', + 'South San Jose Hills', + 'Changchunpu', + 'Wissen', + 'Nova Canaa', + 'Whitburn', + 'Wysokie Mazowieckie', + 'Soacha', + 'Nagathan', + 'Daly City', + 'Antanimasaka', + 'Pura', + 'Petersfield', + 'Overlea', + 'Patjirwa', + 'Weldiya', + 'Iringa', + 'Guaruja', + 'Sitges', + 'Paola', + 'West End', + 'Nasice', + 'Mullanwala', + 'Nanjangud', + 'Jozefoslaw', + 'Zalau', + 'Petorca', + 'Zandhoven', + 'Xiashi', + 'Jaspur', + 'Pasuruan', + 'Bergen', + 'Gangneung', + 'Stargard Szczecinski', + 'President Roxas', + 'El Achir', + 'Beltangadi', + 'Iida', + 'Ardooie', + 'Swallownest', + 'Bairi Chak', + 'Zhijiang', + 'Shiyan', + 'Huzurabad', + 'Kampene', + 'Norden', + 'Chumpak', + 'Kokrajhar', + 'Arbelaez', + 'Mendig', + 'Independent Hill', + 'Etimesgut', + 'White Settlement', + 'Pottanur', + 'Shisui', + 'Mukkudal', + 'Mellila', + 'Pinagkaisahan', + 'Alcorta', + 'Dhantola', + 'San Carlos de Bariloche', + 'New Kingman-Butler', + 'Lawang', + 'Taki', + 'Khanpur', + 'Pirallahi', + 'Amatlan de los Reyes', + 'Kottapuram', + 'Mount Magnet', + 'Hunedoara', + 'Urayasu', + 'Provadia', + 'Siddarampuram', + 'Warfield', + 'Lemery', + 'Lidkoping', + 'Kalikiri', + 'Cravinhos', + 'Mukkanur', + 'Lakeland Highlands', + 'Pilani', + 'Al Mayadin', + 'Port Charlotte', + 'Jinshan', + 'Zeydabad', + 'Cantonment', + 'Nakhon Thai', + 'Dingras', + 'Kirippatti', + 'Haverford', + 'Rufisque', + 'Alagarai', + 'Bang Ban', + 'Querencia do Norte', + 'Puebloviejo', + 'Helena Valley Southeast', + 'Mezitli', + 'Pryor Creek', + 'Hem', + 'Antadinga', + 'Costa de Caparica', + 'Ghardimaou', + 'Shuinancun', + 'Shelek', + 'Saldanha', + 'Maues', + 'Apaseo el Grande', + 'Gendou', + 'Conceicao da Aparecida', + 'Burtonsville', + 'Eagle Pass', + 'Babhangawan', + 'Halle-Neustadt', + "Bahla'", + 'Matelandia', + 'Muddanuru', + 'Coroaci', + 'Morro Agudo', + 'Lipjan', + 'Mizusawa', + 'Cangola', + 'Montanha', + 'Rethymno', + 'Westwood Lakes', + 'Valpovo', + 'Cayambe', + 'Itapicuru', + 'Bourdoud', + 'Polasara', + 'Beltinci', + 'Armentieres', + 'Nuriston', + 'Hattian Bala', + 'Torre del Campo', + 'Hormigueros', + 'Tan An', + 'Sao Jose dos Campos', + 'Belem de Maria', + 'Ksar Lmajaz', + 'Ossining', + 'Tikota', + 'Matsumoto', + 'Reina Mercedes Viejo', + 'New Plymouth', + 'Ocean Pointe', + 'Zogbodome', + 'Ahlaf', + 'Southfield', + 'Nijverdal', + 'Mumias', + 'Vac', + 'Hevie', + 'Malumfashi', + 'Merignac', + 'Agua Prieta', + 'Parabcan', + 'Kako', + 'Chestermere', + 'Nijar', + 'Esanboy', + 'Loango', + 'Boulder City', + 'Pedda Mupparam', + 'Bender', + 'Snellville', + 'Aibongo', + 'Geraardsbergen', + 'Skillounta', + 'Zalingei', + 'Argyroupoli', 'Steiner Ranch', - 'Gibsonton', - 'Carmopolis de Minas', - 'Gaoniang', - 'Santa Cruz Naranjo', - 'Vilattikulam', - 'El Bordj', - 'Ramsbottom', - 'Tolentino', - 'Patar', - 'Segue', - 'Vordingborg', - 'Sa Kaeo', - 'Pimentel', - 'Chortiatis', - 'Marturu', - 'Pachmir', - 'Marwa', - 'San Kamphaeng', - 'Cenovi', - 'Manilva', - 'Szazhalombatta', - 'Loay', - 'Forst (Lausitz)', - 'Colne', - 'Sangenjo', - 'Carvin', - 'Vissannapeta', + 'Meghraj', + 'Midrand', + 'Akola', + 'Sacacoyo', + 'Osogbo', + 'Kaukhali', + 'Cotui', + 'Nzalat Laadam', + 'Bunji', + 'East Meadow', + 'Yangasso', + 'Saint-Cyprien', + 'Banda Aceh', + 'Shipley', + 'Nelamangala', + 'Sidi Redouane', + 'Mahomet', + 'El Abadia', + 'Kanagicho', + 'Port Elgin', + 'Parkway', + 'Kashiwazaki', + 'Belabo', + 'Rajauli', + 'Vlist', + 'Lucheng', + 'Chania', + 'Garching bei Munchen', + 'Taurianova', + 'Kahhale', + 'Novellara', + 'Cerejeiras', + 'Maintal', + 'Old Orchard Beach', + 'Lecco', + 'Oirase', + 'Kailahun', + 'Tres Valles', + 'Sao Jose de Ribamar', + 'Pala', + 'Galikesh', + 'Phularwan', + 'Santo Tomas de los Platanos', + 'Sher Chakla', + 'Rumia', + 'Almasi', + 'Hasanpur Juned', + 'Acambaro', + 'Market Warsop', + 'Diankabou', + 'Yelahanka', + 'Florissant', + 'Daegu', + 'Neckarsulm', + 'Suan', + 'Abadan', + 'Piritu', + 'Tulancingo', + 'Al Malikiyah', + 'Hazel Grove', + 'Zhanlicun', + 'Shoreline', + 'Sutihar', + 'Kopa', + 'Conshohocken', + 'Cuilco', + 'Budaun', + 'Makhar', + 'Kondrukota', + 'South Huron', + 'Jambukuttaippatti', + 'Plabennec', + 'Benoni', + 'Maddikera', + 'Vredendal', 'Aci Castello', - 'Ambohitralanana', - 'Bekalta', - 'Shirali', - 'Montanha', - 'Pontarlier', - 'Porto Grande', - 'Edessa', - 'Sing Buri', - 'Sidi Kada', - 'Pataskala', - 'Marabut', - 'Savignano sul Rubicone', - 'Itapiuna', - 'Kristinehamn', - 'Harper', - 'San Bartolo Tutotepec', - 'Ribera', - 'Pelahiivka', - 'Timbedgha', - 'Policoro', - 'Parede', - 'Goshaingaon', - 'Aguas de Lindoia', - 'Bredene', - 'Werdohl', - 'Paks', - 'Bhikhi', - 'Arcore', - 'Villa Corona', - 'Mengjiacun', - 'Sao Luis Gonzaga do Maranhao', - 'Carate Brianza', - 'Blaj', - 'Freilassing', - 'Mazapil', - 'Itanhem', - 'Oberasbach', - 'Pariharpur', - 'Muttenz', - 'Steinbach', - 'Salgar', - 'Seyah Cheshmeh', - 'Gazantarak', - "Fontaine-l'Eveque", - 'Feilding', - 'Dhansaria', - 'Herenfa', - 'Bagahi', - 'Hendaye', - 'Vennandur', - 'Jovellar', - 'Salaspils', - 'Delran', - 'Jucurutu', - 'Shichigahama', - 'Godfrey', - 'Aminpur', - 'San Rafael del Norte', - 'Portchester', - 'Idylwood', - 'Mankara', - 'Mooirivier', - 'Arakkapadi', - 'Cordenons', - 'Khasab', - 'Monthey', - 'Dhamaun', - 'Freudenberg', - 'North Canton', - 'Varvarin', - 'Lancut', - 'Prachin Buri', - "Fanipal'", - 'Tall `Aran', - 'Vise', - 'Somma Lombardo', - 'Ash Shaykhan', - 'Agua Blanca', - 'Lake Butler', - 'Klaeng', - 'Weilerswist', - 'Willimantic', - 'Cairu', - 'Auerbach', - 'Or `Aqiva', - 'Luneville', - 'Schrobenhausen', - 'Mahis', - 'Cahokia Heights', - 'Ostermundigen', - 'Arco', - 'North Aurora', - 'Floirac', - 'McKeesport', - 'Eslov', - 'Dergaon', - 'Douar Oulad Mbarek', - 'Kuttalam', - 'Chitipa', - 'Koping', - 'Toba', - 'Saint-Colomban', - 'Dianopolis', - 'Dniprorudne', - 'Reni', - 'Kodiyeri', - 'Nikshahr', - 'Laukaha', - 'Sapucaia', - 'Erjie', - 'Bad Munder am Deister', - 'Estancia Pozo Colorado', - 'Susner', - 'Bekes', - 'Herzele', - 'Rockland', - 'Cesson-Sevigne', - 'Ban Mae Ngon Khilek', - 'Pirapemas', - 'Domodossola', - 'Hlybokaye', - 'Live Oak', - 'Broken Hill', - 'Dialafara', - 'Zaltan', - 'Ngora', - 'Major Isidoro', - 'Kharhial', - 'Miramichi', - 'Kiangan', - 'Vettavalam', - 'Vrede', - 'Miaojiaping', - 'Kalyanpur Bamaiya', - 'Kreuzau', - 'Florina', - 'Diepholz', - 'Maripad', - 'Palanan', - 'Harwich', - 'East Lampeter', - 'Dourbali', - 'Panorama', - 'Bechem', - 'Dugo Selo', - 'Mairi', - 'Avion', - 'Hope Mills', - 'Levin', - 'Torredembarra', - 'South Ockendon', - 'Moreton', - 'Pulla', - 'Southbridge', - 'Tufanbeyli', - 'Beni Fouda', - 'Whittlesey', - 'Anacortes', + 'Solotvyno', + 'Tarhzout', + 'Webb City', + 'Shagamu', + 'Svendborg', + 'Manokwari', + 'Lalian', + 'Kings Mountain', + 'Sambhar', + 'Kovacica', + 'Sumperk', + 'Barra Bonita', + 'Cedeno', + 'El Paraiso', + 'Zeghanghane', + 'Parihara', + 'Chosica', + 'Allur', + 'Al Qatif', + 'Wadlakonda', + 'Itoshima', + 'Huckelhoven', + 'Lempaala', + 'Fleming Island', + 'Sewai', + 'Mahesh Khunt', + 'Cranbourne', + 'Bahia Honda', + 'Sanderstead', + 'Munagapaka', + 'Kamata', + 'Arakere', + 'Nasirabad', + 'Tennala', + 'Sumbal', + 'Mandaluyong City', + 'Sunne', + 'Skierniewice', + 'Dilarpur', + 'Qujing', + 'Minneapolis', + 'Abalessa', + 'Roosevelt', + 'Balatonfured', + 'Mel Palaiyam', + 'Maitum', + 'Umm el Fahm', + 'Nanpala', + 'Isahara', + 'Qantir', + 'Boucherville', + 'Port Townsend', + 'Sassuolo', + 'Lipno', + 'Vahdat', + 'Orastie', + 'Oakland', + 'Reus', + 'Arpacay', + 'Andenne', + 'Kafr Takharim', + 'Wakasa', + 'Rutigliano', + 'Marianao', + 'Norderstedt', + 'Orobo', + 'Helsinki', + 'Bria', + 'Wehr', + 'Melsungen', + 'Saint-Basile-le-Grand', + 'Keisen', + 'Khorramshahr', + 'Brighouse', + 'Mount Dora', + 'Bogor', + 'Ayni', + 'Karoi', + 'Kujri', + 'Codo', + 'Police', + 'Ascension', + 'Chaguaramas', + 'Montauban', + 'Kukichuo', + 'Ruti', + 'Abbottabad', + 'Zgornje Jezersko', + 'Bushkill', + 'Ilobu', + 'Allison Park', + 'Abreu e Lima', + 'Magdalena', + 'Natividade do Carangola', + 'Chiclayo', + 'Hard', + 'Singrauliya', + 'Thanh Phu', + 'Kraljevo', + 'Grossos', + 'Algonquin', + 'Nowgong', + 'San Pietro in Casale', + 'Si Racha', + 'Anjoma-Ramartina', + 'Somain', + 'Ronkonkoma', + 'Draper', + 'Gudikallu', + 'Anandnagar', + 'Bouknadel', + 'Torri di Quartesolo', + 'Kaluvaya', + 'Benato-Toby', + 'Bormujos', + 'Xinzhou', + 'Qingyuan', + 'Tiruppattur', + 'Rotherham', + 'Alawalpur', + 'West Perrine', + 'Sahab', + 'Brejo do Cruz', + 'Uchiko', + 'Lichfield', + 'Schwaz', + 'Prevost', + 'Srimushnam', + 'Isalo', + 'Malinagar', + 'Tucson Estates', + 'Santiago do Cacem', + 'Neuenhaus', + 'Sa`dah', + 'Diebougou', + 'Karmah an Nuzul', + 'Muradpur', + 'Hov', 'Duffel', - 'Brignoles', - 'Minquan', - 'Biliran', - 'El Omaria', + 'Ankeny', + 'Selim', + 'San Juan Bautista', + 'La Lisa', + 'Upper Arlington', + 'Chagallu', + 'West Wickham', + 'Godhra', + 'Bilaspur', + 'Bijeraghogarh', + 'Misterbianco', + 'Immingham', + 'Lawndale', + 'Ham Lake', + 'Bytow', + 'Lahnstein', + 'Illertissen', + 'Carpi', + 'Uch Sharif', + 'Pariconia', + 'Teixeira de Freitas', + 'Newstead', + 'Chegga', + 'Potsdam', + 'Korinthos', + 'Palmital', + 'Undavalli', + 'Onteniente', + 'Ayutuxtepeque', + 'Parbhani', + 'Ban Noen Kum Nueng', + 'Sucha Beskidzka', + 'Pieve di Soligo', + 'Sioux City', + 'Bni Darkoul', + 'Mae O', + 'Nova Sintra', + 'Piratininga', + 'Massantola', + 'Alice Springs', + 'Tidili Masfiywat', + 'Mahaly', + 'Baglar', + 'Heartland', + 'Kuyucak', + 'Pili', + 'Katri', + 'Saladas', + 'Samarinda', + 'Okhtyrka', + 'Sulagiri', + 'Pluzine', + 'Di Linh', + 'Kabacan', + 'Koprubasi', + 'Bayanauyl', + 'Murray Bridge', + 'Sunchales', + 'Holzminden', + 'Solon', + 'Orosi', + 'Ofaqim', + 'Vadakkangara', + 'Tooele', + '`Adra', + 'Nagercoil', + 'Berriche', + 'Hyuga', + 'Santos Reyes Nopala', + 'Sezana', + 'Halifax', + 'Ambodisakoana', + 'Booneville', + 'Kirkenes', + 'Mahmutlar', + 'Bad Mergentheim', + 'Tnine Lgharbia', + 'Tanamarina-Sakay', + 'Escaudain', + 'Paterno', + 'Lepe', + 'Marui', + 'Lalitpur', + 'Las Veredas', + 'Pocos de Caldas', + 'Guasave', + 'Canterbury', + 'Rakhwari', + 'Benbutucun', + 'Harrisburg', + 'Casalgrande', + 'Mercaderes', + 'Celorico de Basto', + 'Goiania', + 'Thiruvananthapuram', + 'Padrauna', + 'Navarro', + 'Minturno', + 'Sarari', + 'Carugate', + 'Math Lohiyar', + 'Vairichettipalaiyam', + 'Leo', + 'Saposoa', + 'Vasa', + 'Heggadadevankote', + 'Po', + 'Rock Springs', + 'Kantilo', + 'Jedeida', + 'Pignon', + 'Izunokuni', + 'Shiyeli', + 'Mandiavato', + 'San Jose del Monte', + 'Ouenou', + 'Bouabout', + 'Kangaba', + 'Ulm', + 'Gwalior', + 'Recke', + 'Puruk Cahu', + 'Leonia', + 'Zapala', + 'Ban Na San', + 'Morant Bay', + 'Teonthar', + 'Douar Bou Tlelis', + 'Gondia', + 'Pulur', + 'Andonabe', + 'Santo Antonio do Jacinto', + 'Poldokhtar', + 'Setubal', + 'Mogalturru', + 'Tlahuelilpan', + 'Strood', + 'Pirapetinga', + 'Hamina', + 'Pompeia', + 'Pistoia', + 'Varre-Sai', + 'Tonosho', + 'Cisneros', 'Bad Sackingen', - 'Jaguaripe', - 'Vandalur', - 'Brenham', - 'Yumurtalik', - 'Pinehurst', - 'Tohoue', - 'Pianoro', - 'Tunapuna', - 'Nidda', - 'Monzon', - 'Fern Down', - 'Balaguer', - 'Tabara Arriba', - 'Fornaka', - 'Pirapora do Bom Jesus', - 'Kappiyara', - 'Fanandrana', - 'Mount Holly', - 'Bexbach', - 'Arsanjan', - 'Camano', - 'Valluvandad', - 'Vettikattiri', - 'Stowbtsy', - 'Gretna', - 'Sao Miguel do Tapuio', - 'Abare', - 'Dingjiagouxiang', - 'Damme', - 'Stuart', - 'Terenos', - 'El Carmen de Chucuri', - 'Cerrillos', - 'Otrokovice', - 'Carire', - 'Pupri', - 'Manullahpatti', - 'Siloam Springs', - 'Woodmere', - 'Saint-Maximin-la-Sainte-Baume', - 'Stegen', - 'Oborniki', - 'Ban Mae Ka Hua Thung', - 'Daimiel', - 'Asarcik', - 'Pinili', - 'La Primavera', - 'Eastlake', - 'Gostynin', - 'Lobogo', - 'Naklo nad Notecia', - 'Karacasu', - 'Yayas de Viajama', - 'Colbun', - 'Benito Juarez', - 'Sao Francisco de Assis', - 'Vittal', - 'Ambolomadinika', - 'Sokolka', - 'San Jorge', - 'Iskilip', - 'Sam Phran', - 'Totoro', - 'Omallur', - 'Veliko Gradiste', - 'Ubaitaba', - 'Zhongguyue', - 'Restrepo', - 'Barrhead', - 'Capua', - 'Chedaopo', - 'Savsat', - 'Tijucas do Sul', - 'Storrs', - 'Bel Air', - 'Lousa', - 'New Philadelphia', - 'Pirayu', - 'Siderno Marina', - 'Bakouma', - 'Abejorral', - 'Amacuzac', - 'San Alejo', - 'Herve', - 'Boqueirao', - 'Sigus', - 'Arauco', - 'Yondo', - 'Neder-Over-Heembeek', - 'Bad Wildungen', + 'Yinggen', + 'Barwa Sagar', + 'Ayorou', + 'Chandhaus', + 'Mehsari', + 'Bobrovytsia', + 'McKinney', + 'Gernsbach', + 'Huejutla de Reyes', + 'Cintalapa de Figueroa', + 'Terra Alta', + 'Isemi-Ile', + 'Nishiwaki', + 'Siruma', + 'Leinfelden-Echterdingen', + 'Bernissart', + 'Dharampur', + 'Golden', + 'Beek', + 'Noordwijk', + 'Elixku', + "Piest'any", + 'Kilvisharam', + 'Andria', + 'Nanjakkad', + 'Sankaridrug', + 'Ondorhaan', + 'Campo Novo do Parecis', + 'Castellon de la Plana', + 'Houthulst', + 'Choi Hung', + 'Zabrze', + 'Madaya', + 'Alfafar', + 'Nili', + 'Robertsonpet', + 'Yedapalli', + 'Cidade de Nacala', + 'Mathibestad', + 'Oued Tlelat', + 'Cuetzalan', + 'Juli', + 'Xixinzhuangzhen', + 'Hanwell', + 'Pomezia', + 'Lucani', + 'Fastiv', + 'Bela Palanka', + 'Kumarkhali', + 'Golubac', + 'Svencionys', + 'Sesena', + 'Savigny-sur-Orge', + 'Cal', + 'Brown Deer', + 'Thessaloniki', + 'Jiroft', + 'Taoyang', + 'Beziers', + 'Pathraha', + 'Minalabac', + 'Genova', + 'Sarea Khas', + 'Mahabe', + 'Bela Vista', + 'Zawyat Ahancal', + 'Speyer', + 'Cicekdagi', + 'Ouled Brahim', + 'Yinying', + 'Aguas Vermelhas', + 'Lille', + 'Dillingen', + 'Silang', + 'Monsey', + 'Kalakada', + 'Comarapa', + 'Tit Mellil', + 'Sergio Osmena Sr', + 'Tabapua', + 'Nata', + 'Redlands', + 'Jaggisettigudem', + 'Loma de Cabrera', + 'Kasongo', + 'Kincardine', + 'Aukstieji Paneriai', + 'Sabana Grande', + 'Barwadih', + 'Eragny', + 'Mochudi', + 'New Ulm', + 'La Chorrera', + 'Teresa', + 'Pingtan', + 'Caete', + 'Wieruszow', + 'Torrelavega', + 'Waltham Cross', + 'Yaupi', + 'Becancour', + 'Sao Fidelis', + 'Koch', + 'San Martin de Valdeiglesias', + 'Akron', + 'Cruzeiro do Sul', + 'Halabjah', + 'Channapatna', + 'Aliquippa', + 'Tilehurst', + 'Sabaoani', + 'Berck-sur-Mer', + 'Marquetalia', + 'Shepparton', + 'Stalybridge', + 'Banos', + 'Rengam', + 'Andradina', + 'Andicun', + 'Changde', + 'Vacaville', + 'Sattegalam', + 'Dadukou', + 'Machida', + 'Quisqueya', + 'Solcava', + 'Annecy', + 'Golakpur', + 'Altenburg', + 'Vahdattiyeh', + 'Damoh', + 'Mojo', + 'Vercelli', + 'Simijaca', + 'Chainpur', + 'Esopus', + 'Dimasalang', + 'Grand Rapids', + 'Bowdon', + 'Socastee', + 'Sibila', + 'Miches', + 'Kalkuni', + 'Kananga', + 'Ain Legdah', + 'Songo', + 'Huandacareo', + 'Panazol', + 'Iacu', + 'Kelandis', + 'Miragoane', + 'Pote', + 'Shimabara', + 'Mariluz', + 'Anyuan', + 'Guisborough', + 'Hashtgerd', + 'La Esperanza', + 'Gitarama', + 'San Miguel de Tucuman', + 'Hialeah', + 'Lake Wales', + 'Orihuela', + 'Lakhzazra', + 'Marivan', + 'Whitehorse', + 'Arawa', + 'Ono', + 'Sidi Bou Ali', + 'Papa', + 'Guankou', + 'Marghita', + 'Takarazuka', + 'Sao Joao do Manhuacu', + "G'ijduvon Shahri", + 'Puerto Heath', + 'San Juanito de Escobedo', + 'Mattenhof', + 'Amriswil', + 'Semara', + 'Lokeren', + 'Nevers', + 'Ken Caryl', + 'Hungen', + 'Kehl', + 'Tysmenytsia', + 'Khaur', + 'Hawsh al Bahdaliyah', + 'Palasa', + 'Vaduz', + 'Munnuru', + 'Oranjestad', + 'Tallkalakh', + 'Elwood', + 'Tocaima', + 'Ostringen', + 'Fontoura Xavier', 'Palau', - 'Para', - 'Marcon', - 'Laatatra', - 'Srbac', - 'Manganj', - 'Putte', - 'Santos Reyes Nopala', - 'Inkollu', - 'Eldama Ravine', - 'Aja', - 'Maesteg', - 'Saint Andrews', - 'Chakkuvarakal', - 'Ziar nad Hronom', - 'Muhradah', - 'Quanzhang', - 'Peruvanthanam', - 'Rayappanpatti', - 'Zephyrhills', - 'Cortland', - 'Ait Majdane', - 'Trossingen', - 'Cerca Carvajal', - 'Boissy-Saint-Leger', - 'Alcochete', - 'Roznava', - 'Sagrada Familia', - 'Piritiba', - 'Tak', - 'Ban Thum', - 'Sirari', - 'Kambla', - 'Kisoro', - 'Bistaria', - 'Arroio Grande', - 'Khutaha', - 'Lemont', - 'Clemson', - 'Gomec', - 'Palaiyam', - 'Mawkanin', - 'Son en Breugel', - 'Penn', - 'Le Pontet', - 'Cameli', - 'Glencoe', - 'Punnayur', - 'Morarano-Gara', - 'Waalre', - 'Lattes', - 'Aliyabad', - 'Takoma Park', - 'Koriapatti', - 'Swellendam', - 'Al `Asharah', - 'Etacheri', - 'Sona', - 'Mitake', - 'Kempele', - 'Vayalpad', - 'Oak Grove', - 'Shangjing', - 'Shanglingcun', - 'Harinakunda', - 'Duijiang', - 'Kirksville', - 'Esquimalt', - 'Polignano a Mare', - 'Rio Bananal', - 'Bonnyrigg', - 'Turuvekere', - 'Shirva', - 'Norcross', - 'Mistrato', - 'Dabas', - 'Attimarappatti', - 'Garching bei Munchen', - 'Guidan Roumdji', - 'Boljoon', - 'Yesilhisar', - 'Villorba', - 'Matagob', - 'Manin', - 'Gunjur', - 'Krasnystaw', - 'Quedgeley', - 'Malacacheta', - 'Ivanovka', - 'Strzelce Opolskie', - 'Rocca di Papa', - 'St. Matthews', - 'Sulaco', - 'Ebino', - 'Elankur', - 'Moloacan', - 'Tenango de Doria', - 'Piratini', - 'Mendes', - 'Baxt', - 'San Antonio de Ibarra', - 'Eksambe', - 'Goodlettsville', - 'Buguda', - 'Kudavasal', - 'Sahel', - 'Ilam', - 'Stockach', - 'Scott', - 'Coalinga', - 'Numbrecht', - 'Biyahmu', - 'Karukh', - 'Augustinopolis', - 'Zhoujia', - 'Bhucho Mandi', - 'Ambatolahy', - 'Villa Sarmiento', - 'Croata', - 'Pajapan', - 'Budva', - 'Kushk', - 'Urucuia', - 'Shin-Kamigoto', - 'South Ogden', - 'El Reno', - 'Fairview', - 'Tepatlaxco', - 'Dharampuri', - 'Umirim', - 'Corbelia', - 'Vallieres', - 'Anantavur', - 'Saluzzo', - 'Pocinhos', - 'South Venice', - 'Phayao', - 'Cafarnaum', - 'Talitay', - 'Vladimirci', - 'Cruz do Espirito Santo', - 'Bluffdale', - 'West Columbia', - 'Guanagazapa', - 'Gautampura', - 'Morganton', - 'Karkamb', - 'Falea', - 'Marche-en-Famenne', - 'Kiyama', - 'Dar Chaifat', - 'Veternik', - 'Chamalieres', - 'Sibutao', - 'Puurs', - 'Los Lunas', - 'Laguna Woods', - 'Bon Air', - 'Tasquillo', - 'Rojales', - 'Woodhouse', - 'Albino', - 'Royston', - 'Pecanha', - 'Abdullahnagar', - 'Rio Pomba', - 'Tabernes de Valldigna', - 'Nedugula', - 'Lakhnaur', - 'Rozdilna', - 'Puerto Aysen', - 'Brielle', - 'Nova Era', - 'Nisang', - 'Lubang', - 'Montemor-o-Novo', - 'Sinzig', - 'Reota', - 'Forio', - 'Bramhall', - 'Mehran', - 'Derhachi', - 'Seoni Chhapara', - 'Totutla', - 'Remagen', - 'Pescantina', - 'Anosiarivo', - 'Santa Lucia Milpas Altas', - 'Nahazari', - 'Cham', - 'Kolokonde', - 'Camocim de Sao Felix', - 'Zaslawye', - 'Loboc', - 'Osuna', - 'Bahon', - 'Olivehurst', - 'Conyers', - 'Viradouro', - 'Calayan', - 'Awlouz', - 'Babenhausen', - 'Karahia', - 'Isola Capo Rizzuto', - 'Ummannur', - 'Namminikara', - 'Jhagarua', - 'Beinasco', - 'Fraserpet', - 'Borda da Mata', - 'Douetire', - 'Yutz', - 'Odaipatti', - 'Miedzyrzecz', - 'Bolhrad', - 'Jomboy Shahri', - 'Bry-sur-Marne', - 'Martahalli', - 'Wahiawa', - 'Bhagabanpur', - 'Kawa', - 'Curti', - 'Ziracuaretiro', - 'Pyskowice', - 'Sao Domingos do Prata', - 'Abelardo Luz', - 'Wilton', - 'Cat', - 'Banni', - 'Plunge', - 'Mareth', - 'Balma', - 'Central Saanich', - 'Solrod Strand', - 'Villanueva del Pardillo', - 'Mula', - 'Louth', - 'Nea Erythraia', - 'Kurugodu', - 'Santa Maria di Sala', - 'Streetsboro', - 'Woodcrest', - 'Wangaratta', - 'Gunjapalle', - 'Kelsterbach', - 'Ban Song', - 'Arpacay', - 'Paoua', - 'Holmdel', - 'Lalibela', - 'Mujikharf', - 'Barhan', - 'Sanwer', - 'Gescher', - "Milla'ab", - 'Oued el Kheir', - 'Betio', - 'Viljandi', - 'Glassmanor', - 'Ketama', - 'Bad Langensalza', - 'Sestri Levante', - 'Sainte-Catherine', - 'Lumbreras', - 'Kembhavi', - 'Ibrahimpatan', - 'Skadovsk', - 'Hednesford', - 'Kadogawa', - 'Tonj', - 'Kamudi', - 'Valenzano', - 'Gothini', - 'Yerrapalem', - 'Sedeh Lanjan', - 'Padre Paraiso', - 'Galaz', - 'Mori', - 'Pecel', - 'Riva del Garda', - 'New Amsterdam', - 'Guardamar del Segura', - 'Mau Dhaneshpur', - 'Betroka', - 'Mudukulattur', - 'Matam', - 'Manno', - 'Tagana-an', - 'Dijiasuoxiang', - 'Ain Zaouia', - 'Uryzhar', - 'Muniz Freire', - 'El Kouif', - 'Miharu', - 'Suesca', - 'Pital', - 'Betulia', - 'Schwarzenbek', - 'Villiers', - 'Mohacs', - 'Jenison', - 'As Suqaylibiyah', - 'Chadchan', - 'Mecayapan', - 'Otacilio Costa', - 'Fort Thomas', - 'Schwalbach', - 'Sierpc', - 'Tiogollo', - 'Maranello', - 'Charipara', - 'Almolonga', - 'Namayingo', - 'Dombovar', - 'Kanrangana', - 'Mundo Novo', - 'Ban Pong', - 'Holzwickede', - 'Saram', - 'Poyo', - 'Chorhat', - 'Krupanj', - 'Barbastro', - 'Thorne', - 'Fortim', - 'Port Hope', - 'Keota', - 'Jawkatia', - 'West Lampeter', - 'Horn-Bad Meinberg', - 'Porciuncula', - 'Pont-a-Celles', - 'Kouka', - 'Santo Antonio do Amparo', - 'Talwandi Bhai', - 'Brand', - 'Bad Munstereifel', - 'Bethpage', - 'Houghton Regis', - 'Garwolin', - 'Pollensa', - 'Amesbury', - 'Zebala', - 'Osny', - 'Baie de Henne', - 'Kukraun', - 'Norrtalje', - 'Mulki', - 'Arinos', - 'Senges', - 'Sanary-sur-Mer', - 'Kulasegaram', - 'Moroni', - 'Shongzhy', - 'Hernando', - 'Staphorst', - 'Dehti', - 'Elliniko', - 'Maigh Nuad', - 'Oskarshamn', - 'Tecolotlan', - 'Rattaphum', - 'Rancho Mirage', - 'San Juan Nonualco', - 'Stanford', - 'Capistrano', - 'G`uzor', - 'Illizi', - 'Venturosa', - 'Heanor', - 'Friern Barnet', - 'Mariakerke', - 'Baturbari', - 'North Druid Hills', - 'Mettuppalaiyam', - 'Gunzenhausen', - 'Marmande', - 'Oerlinghausen', - 'Nadugadda', + 'Eastleigh', + 'Ferry Pass', + 'Renigunta', + 'Gig Harbor', + 'Guma', + 'Angadikkal Tekkekara', + 'Pathri', + 'Neya', + 'Santa Ana Maya', + 'Campobello di Mazara', + 'Zhongshu', + 'Lorton', + 'Wankaner', + 'Claremont', + 'Casca', + 'Izumi', + 'Lodhwe', + 'Sidi Boushab', + 'Karcag', + 'Siyabuswa', + 'Simeria', + 'Nemby', + 'Tema', + 'Komatsushimacho', + 'Canhotinho', + 'Ubstadt-Weiher', + 'Mill Hill', + 'Stange', + 'Rincon', + 'Leteri', + 'Cavite City', + 'Msaken', + 'Maputsoe', + 'Martorell', + 'Villiers-le-Bel', + 'San Esteban', + 'Fruita', + 'Sagunto', + 'Monkayo', + 'Maurepas', + 'Jianguang', + 'Zetel', + 'Dordrecht', + 'Kangbao', + 'Linkou', + 'Virginia', + 'Freital', + 'Tut', + 'Tashi', + 'Lang Son', + 'Falun', + 'Tentena', + 'Cristino Castro', + 'Langwedel', + 'Joaima', + 'Maraiyur', + 'Mata Grande', + 'Estanzuela', + 'Rosemere', + 'Kloof', + 'Or `Aqiva', + 'Cerro Grande', + 'Villa Berthet', + 'Buena Park', + 'Balkanabat', + 'Yaguate', + 'Katagon', + 'Cantaura', + 'Stung Treng', + 'Shambu', + 'Froha', + 'Anzio', + 'Trichur', + 'Bhatranha', + 'Sideropolis', + 'Herbrechtingen', + 'Gent', + 'Burhaniye', + 'Odienne', + 'Hendon', + 'Rustenburg', + 'Ninohe', + 'Godollo', + 'Muelle de los Bueyes', + 'Astorga', + 'Nowy Dwor Mazowiecki', + 'Pilibangan', + 'Rapu-Rapu', + 'Ingham', + 'Sable-sur-Sarthe', + 'Andre Fernandes', + 'Khomeyni Shahr', + 'Languyan', + 'Schwyz', + 'Terranuova Bracciolini', + 'Sangan', + 'Nirpur', + 'Palmeira', + 'Aziylal', + "Vel'ky Krtis", + 'Babhnoul', + 'Ait Yaazem', + 'Usti nad Orlici', + 'Bonham', + 'Achampet', + 'San Baudilio de Llobregat', + 'Tres Arroyos', + 'Suva', + 'Hameln', + 'Oued Taria', + 'Tamalameque', + 'Aguinaldo', + 'Kitajima', + 'Bilhorod-Dnistrovskyi', + 'Glocester', + 'Nuevo Ideal', + 'Rialma', + 'Tukums', + 'Calhoun', + 'Ambalavero', + 'Idappadi', + 'Benevento', + 'Lormont', + 'Anndevarapeta', + 'Upton', + 'Zamalka', + 'Sasaram', + 'Bucksburn', + 'Segamat', + 'Zywiec', + 'Ribnitz-Damgarten', + 'Marly', + 'Mogwase', + 'Senaki', + 'Arroio Grande', + 'Grobbendonk', + 'Clarendon Hills', + 'Vyshneve', + 'Lomas del Mirador', + 'Royal Palm Beach', + 'Koloriang', + 'Niort', + 'Tazhakara', + 'Papanasam', + 'Arroio do Tigre', + 'Los Bajos', + 'Ostuncalco', + 'Jastrzebie-Zdroj', + 'Bejucal', + 'St. Clements', + 'Itanhem', + 'Bayamo', + 'Vejle', + 'Kishanpur Ratwara', + 'Chok Chai', + 'Oberhausen-Rheinhausen', + 'Karawang', + 'Lengir', + 'Katori', + 'Karapinar', + 'Talcahuano', + 'Ciudad de Huajuapam de Leon', + 'Hindupur', + 'Keller', + 'Fagaras', + 'Wodonga', + 'Tanakkangulam', + 'Pereira', + 'Clonmel', + 'Eunice', + 'Eberswalde', + 'Tottiyam', + 'Iquira', + 'Ergani', + 'Santa Clara', + 'Jaitpur', + 'Anzin', + 'Toumodi', + 'Sitio do Mato', + 'Drabar', + 'Srikhanda', + 'Ban Mae Hia Nai', + 'Shimubi', + 'Ozd', + 'Mucur', + 'Burdeos', + 'Hawthorne', + 'El Aouana', + 'Kirkuk', + 'Mekele', + 'Barguna', + 'Brzeg Dolny', + 'Santa Maria Tonameca', + 'San Luis', + 'Les Ponts-de-Ce', + 'Helong', + 'Marneuli', + 'Anjiamangirana I', + 'Punjai Kalamangalam', + 'Phan Thiet', + 'Beni Mellal', + 'Jose Panganiban', + 'Boxley', + 'Tamalpais-Homestead Valley', + 'Raisari', + 'Calanasan', + 'Kazanlak', + 'Buved', + 'Amarpatan', + 'Quang Tri', + 'Premia de Mar', + 'Nandimandalam', + 'Leeuwarden', + 'Difficult Run', + 'Bergamo', + 'Kuwana', + 'Paignton', + 'Puduparambubhagam', + 'Tranqueras', + 'Haren', + 'Wertingen', + 'Castelar', + 'Glenrothes', + 'Bilimora', + 'Funes', + 'Longview', + 'Afdem', + 'Soyalo', + 'Nasatta', + 'Takkali', + 'Downpatrick', + 'Khotyn', + 'Sidi Brahim', + 'Halewood', + 'Lawton', + 'Surampatti', + 'Arroio dos Ratos', + 'Ain Zohra', + 'Barking', + 'Sucre', + 'Amboanjo', + 'Lubalo', + 'Chachapoyas', + 'Villa Yapacani', + 'Vettakkaranpudur', + 'Montemarciano', + 'Aracatu', + 'Avigliano', + 'Roanne', + 'Nadur', + 'Weinan', + 'Heyuan', + 'Tabontabon', + 'Peterborough', + 'Dieli', + 'El Ach', + 'Ezanville', + 'Gore', + 'Bougoula', + 'Porlamar', + 'Sedona', + 'Saint-Louis', + 'Cebazat', + 'Nueva Guinea', + 'Sao Francisco de Assis', + 'Achi', + 'Mummidivaram', + 'Antsirabe', + 'Samalapuram', + 'Chandler', + 'Shuanghe', + 'Santana do Paraiso', + 'Ampondra', + 'Delavan', + 'Cacoal', + 'Abangaritos', + 'South Londonderry', + 'Triesenberg', + 'Amantea', + 'Bou Arkoub', + 'Tamponala', + 'Sogamoso', + 'Verdun', + 'Mali Zvornik', + 'La Democracia', + 'El Prat de Llobregat', + 'Borgloon', + 'Morwa', + 'Jarville-la-Malgrange', + 'Evans', + 'Peto', + 'Forde', + 'Grants', + 'Maglie', + 'Altagracia de Orituco', + 'Budaors', + 'El Affroun', + 'Azhikkod', + 'Hiramandalam', + 'Botad', + 'Rye', + 'Broadstairs', + 'Tilmi', + 'Harleysville', + 'Moncao', + 'Usti nad Labem', + 'Maracha', + 'Gaojiayingcun', + 'Castelnuovo di Verona', + 'Versmold', + 'Luzilandia', + 'Vernier', + 'Southold', + 'Nkhata Bay', + 'Chavkandak', + 'Paniqui', + 'South Milwaukee', + 'Mauranwan', + 'Sidi Ladjel', + 'Mozirje', + 'Mthatha', + 'Novotroitske', + 'Aracinovo', + 'Fulin', + 'Tatalon', + 'Carpentersville', + 'Vaijapur', + 'Zhongcheng', + 'Glendale', + 'Saugeen Shores', + 'Saint-Paul-les-Dax', + 'Kobeliaky', + 'Pai Bigha', + 'Bay St. Louis', + 'Bluffdale', + 'Zagora', + 'Careiro', + 'Karahrud', + 'Mudakkal', + 'Amuru', + 'Ismailia', + 'Chodavaram', + 'Kiyose', + 'Cerritos', + 'Ambondrona', + 'Penn Hills', + 'Le Taillan-Medoc', + 'Girua', + 'Rio Linda', + 'Poas', + 'Lucas do Rio Verde', + 'Pratapgarh', + 'Daddi', + 'Lifford', + 'Vandikarai', + 'Westhoughton', + 'Rajepur', + 'Monreal', + 'Loviisa', + 'Juanacatlan', + 'Hankey', + 'Amboise', + 'Bozkir', + 'Ha Tien', + 'Kucukcekmece', + 'Posse', + 'Buerarema', + 'Leixlip', + 'Huanren', 'Bawgalegyi', - 'Les Clayes-sous-Bois', - 'Heilbad Heiligenstadt', - 'Kangaba', - 'Ejutla de Crespo', - 'Jaguaretama', - 'Cipo', - 'Pavumba', - 'Abadiania', - 'Resplendor', - 'Littau', - 'Souaflia', - 'Minakami', - 'Belmopan', - 'Buford', - 'Bendorf', - 'Monselice', - 'Castelfiorentino', - 'Cukurca', - 'Bakeshiyingcun', - 'Martigny', - 'Belakoba', - 'Pisaflores', - 'Bareggio', - 'Bailen', - 'Terzigno', - 'Avenel', - 'Durlesti', - 'Carnaubal', - 'Itacarambi', - 'Kretinga', - 'Port-a-Piment', - 'Marktredwitz', - "L'Isle-d'Abeau", - 'Raiyam', - 'Piera', - 'Chouafaa', - 'Shahritus', - 'Carmo', + 'Manage', + 'Dumanjog', + 'Mulifanua', + 'Traun', + 'Pantelho', + 'Gundur', + 'Mirialguda', + 'Russelsheim', + 'Quixelo', + 'Chipata', + 'Macaubas', + 'Fujino', + 'Craig', + 'Iskapalli', + 'Solhan', + 'Costessey', + 'La Vega', + 'Espejo', + 'Perevalsk', + 'Middle Island', + 'Zavora', + 'Lorain', + 'Leninskiy', + 'Rossdorf', + 'Pembroke', + 'Weirton', + 'Villa Gonzalez', + 'Multan', + 'Patamundai', + 'Wicklow', + 'Florence', + 'Tibati', + 'Steti', + 'Ugento', + 'Messstetten', + 'Pestel', + 'Sujangarh', + 'Camanducaia', + 'Acarau', + 'Balagam', + 'Sungal', + 'Linyi', + 'Tukuyu', + 'Faetano', + 'Batgram', + 'Saundatti', + 'Roux', + 'Hermosa Beach', + 'Mavelikara', + 'Canapi', + 'Lovendegem', + 'Busogo', + 'Villeneuve-les-Avignon', + 'Phokeng', + "Sant'Arpino", + 'Ambasamudram', + 'Gobernador Virasora', + 'Langley Park', + 'Mungo', + 'Carrick on Shannon', + 'Warangal', + 'Haan', + 'Markt Indersdorf', + 'Ngororero', + 'Pavannur', + 'Boekel', + 'Sotteville-les-Rouen', + 'Sarai Alamgir', + 'Kutiyana', + 'Great Cornard', + 'Oiapoque', + 'Diondiori', + 'Xiangshui', + 'Benesov', + 'Borja', + 'Traunstein', + 'Cardito', + 'Evreux', + 'Camponogara', + 'Kladovo', + 'Oncativo', + 'Nazret', + 'Cachoeiras de Macacu', + 'Bayport', + 'Mandaguari', + 'Katha', + 'Scarborough', + 'Hotan', + 'Dinangorou', + 'Kilimli', + 'Killamarsh', + 'Bifoun', + 'Gorom-Gorom', + 'Reddish', + 'Wildomar', + 'Tlalmanalco', + 'Grafenhainichen', + "Sama'il", + 'Touwu', + 'Castillos', + 'Sipacapa', + 'Dionisio Cerqueira', + 'Maqsuda', + 'Iranduba', + 'Bharweli', + 'Irakleio', + 'Shima', + 'Zandvoort', + 'Edremit', + 'Vitomirice', + 'Laoaoba', + 'Kocakoy', + 'Barnet', + 'Majitha', + 'Minnehaha', + 'Holbaek', + 'Panchgram', + 'San Michele al Tagliamento', + 'San Agustin de Guadalix', + 'Fanjakana', + 'Piat', + 'Marjampad', + 'River Falls', + 'Gualan', + 'Capannori', + 'Takashima', + 'Siripur', + 'Antakotako', + "Qa'en", + 'Agadir Melloul', + 'West Jordan', + 'Dipalpur', + 'Ar Rudayyif', + 'New Hyde Park', + 'Rasdhoo', + 'Amakusa', + 'Jember', + 'North Richland Hills', + 'Andrainjato', + "Bo'ness", + 'Curridabat', + 'Wangaratta', + 'Mirante', + 'Pulppatta', + 'Prestwick', + 'El Tarra', + 'Ambodimanga II', + 'Beausoleil', + 'Raisio', + 'Puttur', + 'Diriamba', + 'Davyhulme', + 'Murukondapadu', + 'North Union', + 'Guayaramerin', + 'Mingguang', + 'Milaor', + 'Dongluocun', + 'Ghuenke', + 'Market Harborough', + 'Sainte-Savine', + 'Makaha', + 'Security-Widefield', + 'Donabate', + 'Wigan', + 'Tasquillo', + 'Villasagar', + 'Buikwe', + "Ouro Preto d'Oeste", + 'Roldanillo', + "Ait I'yach", + 'Camliyayla', + 'Cinderford', + 'Maraial', + 'Santo Stefano di Magra', + 'Anaiyur', + 'Kushk', + 'Amontada', + 'Marituba', + 'Cambe', + 'Horjul', + 'Seguela', + 'Wagin', + 'Schwandorf', + 'Lawaan', + 'Kadirli', + 'Vaughan', + 'East Retford', + 'Hinatuan', + 'Shoranur', + 'Rayen', + 'Bistrica ob Sotli', + 'Acharnes', + 'Rajsamand', + 'Aipe', + 'Faxinal', + 'Ollioules', + 'Ismaning', + 'Smartno', + 'Lamhadi', + 'Lecce', + 'Bredbury', + 'Adjarra', + 'Lichana', + 'La Troncal', + 'Sao Caetano do Sul', + 'Koppal', + 'Hansa', + 'Sirinhaem', + 'Weissenfels', + 'Aloha', + 'Tailai', + 'Jucuaran', + 'Summerstrand', + 'Amnat Charoen', + 'Kornwestheim', + 'Sorum', + 'Iarpur', + 'Minquan', + 'Srivaikuntam', + 'Almunecar', + 'Ban Don Thong', + 'Targu Jiu', + 'Tamparan', + 'Oyabe', + 'Stadtlohn', + 'Hazorasp', + 'Torredembarra', + 'Kalavad', + 'Ochakiv', + 'Williamsburg', + 'North Greenbush', + 'Victor Larco Herrera', + 'Karasu', + 'Sabnima', + 'Iramala', + 'Hoa Binh', + 'Naregal', + 'Concordia Sagittaria', + 'Portishead', + 'Zhaltyr', + 'Liberty Triangle', + 'Chegurumomadi', + 'Vila Junqueiro', + 'Bitlis', + "Tajura'", + 'Ambodivoara', + 'Highbury', + 'Nizza Monferrato', + 'Kesariya', + 'Walur', + 'Turbat', + 'Kars', + 'Colorado Springs', + 'Lashkar Gah', + 'Lavaur', + 'Nova Petropolis', + 'Goalpara', + 'Padra', + 'Fallbrook', + 'Imotski', + 'Domnesti', + 'Ilami', + 'Edewecht', + 'Playas de Rosarito', + 'Palo Negro', + 'Ban Song', + 'Batna', + 'Galt', + 'Ambatolava', + 'Le Cannet', + 'Urumita', + 'Ankily', + 'Missouri City', + 'Partap Tanr', + 'Margarita', + 'Vandiperiyar', + 'Kaminokawa', + 'Goldach', + 'Viamao', + 'Nainpur', + 'Ya`bad', + 'Palhano', + 'Chhatapur', + 'Commune Sidi Youssef Ben Ahmed', + 'Jucati', + 'Con Dao', + "Al Bayda'", + 'Badhoevedorp', + 'San Rafael Oriente', + 'Ndulo', + 'Az Zulfi', + 'Ban San Pong', + 'Antioch', + 'Stoke-on-Trent', + 'Sahuli', + 'Asagi Ayibli', + 'Palukudoddi', + 'Chorfa', + 'Campos Novos', + 'Borim', + 'Hueytown', + 'Anuppur', + 'Port Lincoln', + 'Sertanopolis', + 'Cradock', + 'Winsford', + 'Bakhchysarai', + 'Spreitenbach', + 'Arese', + 'Buug', + 'Paruchuru', + 'Lower Swatara', + 'Vinica', + 'Pottsville', + 'Moncalieri', + 'Lamzoudia', + 'Crestwood', + 'Damongo', + 'Greece', + 'Utinga', + 'Niamtougou', + 'Kallayi', + 'Trogir', + 'Osmaneli', + 'Friendly', + 'Kanchanpur', + 'Hawera', + 'Carupano', + 'Nador', + 'Grand-Couronne', + 'Ogbomoso', + 'Sahagun', + 'Bridgwater', + 'Xicotepec de Juarez', + 'Durham', + 'Jerez de los Caballeros', + 'North Hykeham', + 'Stannington', + 'Ibanda', + 'Batac', + 'Logten', + 'Hoorn', + 'Roussillon', + 'Minzhu', + 'Blindio', + 'Mainz', + 'Catarman', + 'Lumberton', + 'Payabon', + 'Sangeorz-Bai', + "Pau d'Alho", + 'Honggu', + 'Sauk Rapids', + 'Ortaklar', + 'Thousand Oaks', + 'Kocani', + 'Kudangulam', + 'Chicoloapan', + 'De Meern', + 'Qiblai', + 'Montevista', + 'San Felipe Orizatlan', + 'Lakatoro', + 'Badia Polesine', + 'Bad Kissingen', + 'Bom Jesus do Itabapoana', + 'Erenler', + 'Katwijk', + 'Sao Francisco do Sul', + 'Lila', + 'Na Sceiri', + 'Perumbakkam', + 'Leling', + 'Gladstone', + 'Al `Aqabah', + 'Waregem', + 'Mulgund', + 'Ambolomadinika', + 'Osorno', + 'Gorgab', + 'Udaipur', + 'Khomam', + 'Sindalakkundu', + 'Toukountouna', + 'Chebba', + 'Pettampalaiyam', + 'Baile Atha Luain', + 'Nurobod Shahri', + 'Kropyvnytskyi', + 'Guarapari', + 'Caidat Sidi Boubker El Haj', + 'Ala-Buka', + 'Turin', + 'Bucharest', + 'Gingoog', + 'Youngsville', + 'Angwali', + 'Orikhiv', + 'Hofn', + 'Varzea da Palma', + 'Lower Makefield', + 'Chillicothe', + 'Seabrook', + 'Phetchaburi', + 'Fujisawa', + 'Matara', + 'Kepno', + 'Alden', + 'Omigawa', + 'Bayombong', + 'Toride', + 'Mirabela', + 'Tullukuttinayakkanur', + 'Ugong', + 'Zhangye', + 'Mangha', + 'Krsko', + 'Comrat', + 'Sudbury', + 'Almaty', + 'Sonamukhi', + 'Terrabona', + 'Windsor', + 'Coralville', + 'Capela', + 'Qufu', + 'Stallings', + 'Kingaroy', + 'Downham Market', + 'Calapan', + 'Aizuwakamatsu', + 'Kaintragarh', + 'Inhuma', + 'Pangururan', + 'Scotchtown', + 'La Marque', + 'Iwata', + 'Zrece', + 'Waldheim', + 'Ajmer', + 'Pamekasan', + 'Mafune', + 'Weiyuan', + 'Gunzburg', + 'Drohobych', + 'Damal', + 'Sigtuna', + 'Campulung', + 'Patancheruvu', + 'Gavardo', + 'Acushnet', + 'Poiana Mare', + 'Tarsus', + 'Betanzos', + 'Chau Doc', + 'Cacequi', + 'Lalsaraia', + 'Aweitancun', + 'Gia Rai', + 'Corat', + 'Arcos de la Frontera', 'Akassato', - 'Lerida', - 'Banabuiu', - 'Anori', - 'Digne-les-Bains', - 'Badantola', + "Samch'ok", + 'Lake Tapps', + 'Aine Draham', + 'Vertou', + 'Neenah', + 'Tanhacu', + 'Shimla', + 'Keal', + 'Rani', + 'Kadaiyanallur', + 'Sefwi Wiawso', + 'Shankarpur Khawas', + 'Veliyangod', + 'Senador Guiomard', + 'Danzao', + 'Ndele', + 'Pornic', + 'Nowy Tomysl', + 'Scenic Oaks', + 'Ursulo Galvan', + 'Freudenberg', 'Araruna', - 'Glen Parva', - 'Mont-Organise', - 'Dormentes', - 'Flowing Wells', - 'Sudipen', - 'Batufah', - 'Forssa', - 'Cherakara', - 'Calhoun', - 'North Decatur', - 'Lyepyel', - 'Trstenik', - 'Bad Worishofen', - 'Cacimba de Dentro', - 'Jouy-le-Moutier', - 'Padugupadu', - 'Neerpelt', - 'Al Harah', - 'Nederweert', - 'Shek Tong Tsui', - 'Villa Isabela', - 'Hinsdale', - 'Zandvoort', - 'Guoxing', - 'Castilleja de la Cuesta', - 'Sume', - 'Conceicao do Almeida', - 'Iati', - 'Traiguen', - 'Cluses', - 'Cottingham', - 'Calnali', - 'Bellaire', - 'Pinewood', - 'Massaranduba', - 'Peka', - 'Pocao de Pedras', - 'Tizi Rached', - 'Sinnai', - 'Itirapina', - 'Kayaralam', - 'Tanque Novo', - 'Malta', - 'Swansea', - 'Konstancin-Jeziorna', - 'Cassia', - 'Tejucuoca', - 'Tlahuelilpan', - 'Joaquim Gomes', - 'Mayuge', - 'Bom Sucesso', - 'Sake', - 'Settiyarpatti', - 'Monsenhor Tabosa', - 'Majitha', - 'Sawankhalok', + 'Popayan', + 'Centereach', + 'Kamaishi', + 'Sainte-Marthe-sur-le-Lac', + 'Imilchil', + 'Zimapan', + 'Meschede', + 'Puthuppariyaram', + 'Paso de los Libres', + 'Longbenton', + 'Kampong Speu', + 'Novy Jicin', + 'Jinggang', + 'Asahi', + 'Khokri Kalan', + 'Kaveripatnam', + 'Lviv', + 'Bowling Green', + 'Braganca', + 'Panjgirain Kalan', + 'Emeryville', + 'Ruhango', + 'Tarim', + 'Castiglione del Lago', + 'Kyiv', + 'Mineral Wells', + 'Burnsville', + 'Franeker', + 'Teignmouth', + 'Canas', + 'Ajjampur', + 'Barhauna', + 'Zacharo', + 'Fujimi', + 'Billerica', + 'Falconara Marittima', + 'Alto Araguaia', + 'Tak Bai', + 'Bishops Cleeve', + 'Orhangazi', + 'Spokane Valley', + 'Kovel', + 'Walworth', + 'Zushi', + 'Aglasun', + 'Romainville', + 'Sorsogon', + 'Castellamonte', + 'Des Plaines', + 'Xai', + "'Ain Abid", + 'Plattekill', + 'Sinzheim', + 'Cipanas', + 'Paliaturutu', + 'Katwe', + 'Lorenskog', + 'San Tung Chung Hang', + 'Abrego', + 'Viana', + 'Ishtixon Shahri', + 'Kharika', + 'Sautron', + 'San Narciso', + 'Hilton Head Island', + 'Lingolsheim', + 'Bornheim', + 'Koregaon', + 'Matao', + 'Sumida', + 'Ketsch', + 'Gopalnagar', + 'Rodez', + 'Canelones', + 'Tolten', + 'Crawley', + 'Tillsonburg', + 'Wislane', + 'Mortsel', + 'Akitakata', + 'Halasztelek', + 'Herselt', + 'Kartal', + 'Balabac', + 'Ungaran', + 'Da', + 'Sao Joao del Rei', + 'Ghanipur Bejha', + 'Al Quway`iyah', + 'Zalaegerszeg', + 'Carquefou', + 'Huanimaro', + 'Ponte Nova', + 'Monte Azul', + 'Melito di Porto Salvo', + 'Shimenzhai', + 'Pinehurst', + "K'ebri Beyah", + 'Molsheim', + 'Konigstein im Taunus', + 'Taranagar', + 'Farciennes', + 'Bhilai', + 'Mathurapur', + 'Port-a-Piment', + 'Kyegegwa', + 'Ortakoy', + 'Antonibe', + 'Mercedes Umana', + 'Coronel', + 'Pedrinhas', + 'Suhagi', + 'Jaboatao dos Guararapes', + 'Oxon Hill', + 'Jalolquduq', + 'Morros', + 'Sumbas', + 'Chingola', + 'Rada Tilly', + 'Kolachel', + 'Bandarawela', + 'Pallattur', + 'Carauari', + 'Colares', + 'Santa Fe do Sul', + 'Musapur', + 'Arni', + 'Negage', + 'Graham', + 'Lake Grove', + 'Tolosa', + 'Marlboro', + 'Kandrawan', + 'Ponte Serrada', + 'Shanghai', + 'Ouedeme', + 'Saki', + 'Chembra', + 'Syston', + 'Palmeirais', + 'Borlange', + 'Bordj Bounaama', + 'Montceau-les-Mines', + 'Zhufeng', + 'Frei Paulo', + 'Western Springs', + 'Hemmingen', + 'Santa Cruz del Sur', + 'Pleasantville', + 'Chandla', + 'Maihma Sarja', + 'Sacaba', + 'Reynoldsburg', + 'Highland', + 'Sunyani', + 'Ajnala', + 'Ourem', + 'Zaltan', + 'Vannikkonendal', + 'Suchindram', + 'Metouia', + 'Bandar-e Lengeh', + 'Sestu', + 'Troisdorf', + 'Tibasosa', + "Villenave-d'Ornon", + 'Huseni', + 'Komorniki', + 'Ankerana', + 'Planura', + 'Saguenay', + 'Xiangping', + 'Almendralejo', + 'Slawno', + 'Bir Ghbalou', + 'Luna', + 'Tiaret', + 'Pulakurti', + 'General Santos', + 'Shibancun', + 'Lansing', + 'Lake Los Angeles', + 'Hala', + 'Port Washington', + 'Cortalim', + 'Apostoles', + 'Radnevo', + 'Reina Mercedes', + 'Tivoli', + 'Gomishan', + 'Maigh Nuad', + 'Gujiao', + 'Sorvagur', + 'Milpitas', + 'Ramnagar Bankat', + 'Longyearbyen', + 'Sarauni', + 'Angel R. Cabada', + 'Brooksville', + 'Bochaha', + 'Alguazas', + 'Tigaraksa', + 'Guiguinto', + 'Granbury', + 'Aiyetoro Gbede', + 'Zenica', + 'Itsoseng', + "Al Madrah Sama'il", + 'Murtajapur', + 'Gyongyos', + 'Kabale', + 'Armiansk', + 'Bandar-e Kong', + 'Makhambet', + 'Naval', + 'Issoudun', + 'Valmiera', + 'Virapandiyanpattanam', + 'Beirut', + 'Tagbilaran City', + 'El Factor', + 'Banikane', + 'Khartoum', + 'Jiangna', + 'Bhawanipatna', + 'Aungban', + 'Leonding', + 'Limeil-Brevannes', + 'Obernkirchen', + 'Nova Trento', + 'Zambezi', + 'Leith', + 'Gessate', + 'Huguan Nongchang', + 'Tirupati', + 'Cilimli', + 'Brie-Comte-Robert', + 'Cebu City', + 'Patti', + 'Germi', + 'Jaleshwar', + 'Piliscsaba', + 'Devipattinam', + 'Chato', + 'Khartoum North', + 'Brushy Creek', + 'Vlagtwedde', + 'Amacuzac', + 'Kosigi', + 'Aranjuez', + 'Leama', + 'Roanoke', + 'Limpio', + 'Kemalpasa', + 'Haisyn', + 'Peoria', + 'Stade', + 'In Guezzam', + 'Gashua', + 'Nerubaiske', + 'Ratlam', + 'Mahmutlu', + 'Srirampuram', + 'Veldurti', + 'Wemmel', + 'Phichit', + 'Dibaya-Lubwe', + 'Madurai', + 'Sao Goncalo do Para', + 'Vitry-le-Francois', + 'Anantarazupeta', + 'Boudinar', + 'Zschopau', + 'Quellon', + 'Longonjo', + 'Hexham', + 'Mangqu', + 'Hoxut', + 'Twickenham', + 'Gueckedou', + 'Labbaikkudikkadu', + 'Mittenwalde', + 'Hatton', + 'Feldbach', + 'Lahij', + 'Sasan', + 'Miastko', + 'Waitakere', + 'Shizuoka', + 'West Warwick', + 'Galati', + 'Biu', + 'Kudatini', + 'Viradouro', + 'Saffle', + 'Gyumai', + 'Zhongshan', + 'Picayune', + 'Antaly', + 'Anse-a-Veau', + 'Saint Peter Port', + 'Ambohitrolomahitsy', + 'Avadattur', + 'Calasiao', + 'Bambang', + 'Warder', + 'Koforidua', + 'Tangier', + 'Duggirala', + 'Glenville', + 'Bagrinagar', + 'Ingelmunster', + 'Carrigaline', + 'Ashtabula', + 'Galeras', + 'Ulchin', + 'Paarl', + 'Bandung', + 'Roxana', + 'Gulu', + 'Kesavapuram', + 'Beantake', + 'Yokoshiba', + 'Kaohsiung', + 'Piranguinho', + 'Port-de-Bouc', + 'Lakri', + 'Cadereyta Jimenez', + 'Merad', + 'Centralia', + 'Putte', + 'Baozhong', + 'Tougan', + 'Knutsford', + 'Estancia Velha', + 'Nawada', + 'Gangelt', + 'Frontignan', + 'Chiconcuac', + 'Gunnedah', + 'Lingen', + 'Bozmargi', + 'Porac', + 'St. Peter', + 'East Hempfield', + 'Tapalpa', + 'Jolfa', + 'Photharam', + '`Ajman', + 'Altunhisar', + 'Staufenberg', + 'Fgura', + 'Heist-op-den-Berg', + 'Colima', + 'Hoogstraten', 'Oi', - 'Grumo Nevano', - 'Ayinikkad', - 'Tricase', - 'Clitheroe', - 'Grenchen', - 'Berezhany', - 'Saguday', - 'Firminy', - 'Panchgram', - 'Fairview Park', - 'Ipaba', - 'Figline Valdarno', - 'Frederikssund', - 'Regeneracao', - 'Sallanches', - 'Beckley', - 'Peso da Regua', - 'Banovici', - 'Correntes', - 'Giria', - 'Sa`adat Shahr', - 'Marsabit', - 'Pouso Redondo', - 'Ejea de los Caballeros', - 'Manassas Park', - "Wadi Halfa'", - 'Barrington', - 'Ilaka Atsinanana', - 'Ban Phe', - 'Wang Tau Hom', - 'South Hadley', - 'Peruwelz', - 'Damous', - 'Kaukauna', + 'Rustington', + 'Vandamettu', + 'Manzanares el Real', + 'Laohekou', + 'Szigethalom', + 'Colindres', + 'Harrow', + 'Kishanganj', + 'Brejo Santo', + 'Dalfsen', + 'Werdau', + 'Rijkevorsel', + 'Coondapoor', + 'Kagizman', + 'Pardi', + 'Paombong', + 'Pitseng', + 'Chikwawa', + 'Togou', + 'Akanavaritota', + 'Ojus', + 'Buhl', + 'Ganjing', + 'Sona', + 'Vayalpad', + 'Taishacho-kizukikita', + 'Ocoee', + 'Noda', + 'Nurdagi', + 'Maidan Shahr', + 'Culleredo', + 'Paravurkambolam', + 'Olintepeque', + 'Kien Giang', + 'Kunoy', + 'Zawyat Sidi al Mekki', + 'Aleksinac', + 'Mandalay', + 'La Laguna', + 'Kanabur', + 'San Miguel Panan', + 'Batumi', + 'Gambolo', + 'Cibitoke', + 'Swatara', + 'Ganga', + 'Cotorro', + 'Skofljica', + 'Piranhas', + 'Aricak', + 'Darb-e Behesht', + 'Ampana', + 'North Bellmore', + 'La Roche-sur-Yon', + 'Challapata', + 'Binghamton', + 'Hatod', + 'Gouveia', + 'Gardendale', + 'Newnan', + 'Le Haillan', + 'Lencois Paulista', + 'Dangriga', + 'Mallan', + 'Forest Park', + 'Chiyoda', + 'Pirenopolis', + 'Sao Joao do Piaui', + 'Mahavanona', + 'Hanzhong', + 'Madalag', + 'Los Osos', + 'Guatajiagua', + 'Berri', + 'Lardero', + 'El Jicaral', + 'Ter Apel', + 'Kola', + 'Vasteras', + "Al 'Attawia", + 'Pamplona', + 'Tomobe', + 'Bejaia', + 'Kullorsuaq', + 'Arganil', + 'Comapa', + 'Dehqonobod', + 'Gaoping', + 'Buntok', + 'Somerton', + 'Herstal', + 'Igualada', + 'Tumaco', + 'Saint Joseph', + 'Mandeville', + 'Monterrey', + 'Jamindan', + 'Nguti', + 'Sidi Lahssen', + 'Redruth', + 'Akcakoca', + 'Jankampet', + 'Tataouine', + 'Manizales', + 'Narasannapeta', + 'Karempudi', + 'St. Augustine', + 'Cumanayagua', + 'Montesilvano', + 'Gracias', + 'Congaz', + 'Poso', + 'Humenne', + 'Shalqar', + 'Lago Ranco', + 'Morogoro', + 'Qingan', + 'Anini-y', + 'Marche-en-Famenne', + 'Erseke', + 'Presidente Venceslau', + 'Abomey', + 'Dorohoi', + 'Talipparamba', + 'Bonito', + 'Algarrobo', + 'Yamoussoukro', + 'Lafey', + 'Kadi', + 'Beberibe', + 'Yurihama', + 'Viana do Castelo', + 'Assen', + 'Sniatyn', + 'Spanish Fort', + 'Xintianfeng', + 'Bukungu', + 'Xiaqiaotou', + 'Peshtera', + 'Hueyapan de Ocampo', + 'Marreddipalli', + 'Kaimati', + 'Isabela', + 'Selfoss', + 'Delhi', + 'Fujikawaguchiko', + 'Marutharod', + 'Bom Repouso', + 'Jagadhri', + 'El Valle', + 'Zlotoryja', + 'Grover Beach', + 'Hashtpar', + 'San Alejo', + 'Nazarje', + 'Hillcrest', + 'Sananduva', + 'Peissenberg', + 'Bada Barabil', + 'Watampone', + 'Nove Mesto nad Metuji', + 'Karankot', + 'Pucon', + 'Guangshui', + 'Falls Church', + 'Danihe', + 'Mudakkiraye', + 'Ceuti', + 'Fussen', + 'Zaghouan', + 'Yongbei', + 'Hong Ngu', + 'Conchas', + 'Manivilundan', + 'Tadhwa Nandpur', + 'Monistrol-sur-Loire', + 'Chateaubriant', + 'Sangar', + 'Fafe', + 'Shoshong', + 'Madang', + 'Marcy', + 'Puttlingen', 'Groves', - 'Kutiyana', - 'Manaquiri', - 'Shoufeng', - 'Ignacio de la Llave', - 'Nova Pazova', - 'Bulbula', - 'Yizhu', - 'Tagounite', - 'Dilasag', - 'Ginir', - 'Taxtako`pir', - 'Xintangcun', - 'Pottassheri', - 'Mosbrough', - 'Santa Magdalena', - 'Braunau am Inn', - 'Kolaccheri', - 'Melfi', - 'Estelle', - 'Mata Roma', - 'San Esteban', - 'Tadigadapa', - 'Chandia', - 'Lake St. Louis', + 'Al Bahah', + 'Gorham', + 'Afogados da Ingazeira', + 'Knokke-Heist', + 'Pariyaram', + 'Zagreb', + 'Winton', + 'Les Iles-de-la-Madeleine', + 'Kusterdingen', + 'Paraguari', + 'Kuknur', + 'Black River', + 'Baishaling', + 'Sigulda', + 'Uppsala', + 'Selm', + 'Muy Muy', + 'Paracale', + 'Luleburgaz', + 'La Llagosta', + 'Demirci', + 'Kalasin', + 'Ibajay', + 'Ceska Lipa', + 'Camocim de Sao Felix', + 'Ogose', + 'Menlo Park', + 'Ouedo-Agueko', + 'Karakurisshi', + 'Franklin Lakes', + 'Ismayilli', + 'Gottingen', + 'Melmadai', + 'Meulaboh', + 'Ogre', + 'Bad Abbach', + 'Longmen', + 'Awka', + 'Braco do Norte', + 'Bigadic', + 'General Pacheco', + 'Sint-Oedenrode', + 'Annamalainagar', + 'Angamali', + 'Julio de Castilhos', + 'Capao Bonito', + 'Poynton', + 'Santa Cruz Atizapan', + 'Ekeren', + 'Gandara West', + 'Metairie', + 'Katsuren-haebaru', + 'Dupnitsa', + 'Tricase', + 'Mokpo', + 'Dassari', + 'Givatayim', + 'Jambai', + 'Hamsavaram', + 'Foggia', + 'Scott', + 'Inkhil', + 'Catamayo', + 'Nana', + 'Ntchisi', + 'Olomouc', + 'Madison Heights', + 'Genzano di Roma', + 'Vieux Fort', + 'Kagvad', + 'Motegi', + 'Breves', + 'Myitkyina', + 'Aqkol', + 'Al `Ashir min Ramadan', + 'Ariano Irpino', + 'Restrepo', + 'Jeumont', + 'Drazinda', + 'San Pedro de Ribas', + 'Chintakommadinne', + 'Tank', + 'Preili', + 'Konakli', + 'Julita', + 'Meda', + 'Ciudad Obregon', + 'Barabai', + 'Gizycko', + 'Boureit', + 'Arambagh', + 'Bonito Oriental', + 'Mbanga', + 'Chemmanam', + 'Kakira', + 'Mundka', + 'Noniya', + 'Marianske Lazne', + 'Khanaqin', + 'Pajacuaran', + 'Ain el Bya', + 'Bacliff', + 'Sewari', + 'Altusried', + 'Zinapecuaro', + 'Matsuo', + 'Vasylivka', + 'Peda-Houeyogbe', + 'Nossa Senhora dos Remedios', + 'Chaltabaria', + 'Hailakandi', + 'Poznan', + 'Taoudenni', + 'Sidhwan', + 'Guadalajara de Buga', + 'Rozhyshche', + 'Caracarai', + 'Suwannaphum', + "Bur Fu'ad", + 'Fderik', + 'Mezotur', + 'Las Vegas', + 'Limassol', + 'Jursinci', + 'Taggia', + 'Poco das Trincheiras', + 'Douar Oulad Naoual', + 'Calarca', + 'Mont-Tremblant', + 'Belterra', + 'Sheikhpura', + 'North Olmsted', + 'Ramdurg', + 'Orumanayur', + 'Villafranca de los Barros', + 'Esztergom', + 'Payakaraopeta', + 'Ramchandrapur', + 'Khajamahalpur', + 'Najafgarh', + 'Athni', + 'Mikkelin Maalaiskunta', + 'Bijnor', + 'Ighram', + 'Dragash', + 'Thargomindah', + 'Castel Maggiore', + 'Belambo', + 'Nueva Palmira', + 'Kurabur', + 'Yahsihan', + 'Chesterton', + 'Konduru', + 'Tordesillas', + 'Biala Podlaska', + 'Katsuragi', + 'South Bradenton', + 'Naranja', + 'Okhmalynka', + 'Newtownards', + 'Pimenta Bueno', + 'Naraura', + 'Craponne', + 'Auta', + 'Kumaravadi', + 'Anajas', + 'Mouiat Ouennsa', + 'Norvenich', + 'Jaruco', 'Stockelsdorf', - 'Toluprpatti', - 'Safety Harbor', - 'Lac', - 'Eutin', - 'Elias Fausto', - 'Usmanpur', - 'Denville', - 'El Segundo', - 'Peragamanna', - 'Sarotar', - 'Condeixa-a-Nova', - 'Zvenyhorodka', - 'Gudipallipadu', - 'San Rafael Cedros', - 'Sibinal', - 'Cinnaminson', - 'Puchov', - 'Svalyava', - 'Mannukara', - 'Ayikudi', - 'Challapalle', - 'Serra Dourada', - 'Crixas', - 'Guadarrama', - 'Kunzell', - 'Mavalli', - 'Upper Grand Lagoon', - 'Canon City', - 'Tifton', - 'Souto Soares', - 'Chuarrancho', - 'Paulino Neves', - 'Amfilochia', - 'Sidi Yakoub', - 'Tortum', - 'Condeuba', - 'Saint-Basile-le-Grand', - 'Kafr Zayta', - 'Itarantim', - 'La Garriga', - 'West Hempfield', - 'Kibungan', - 'Ruhango', - 'Canovellas', - 'Porteiras', - 'Guernica y Luno', - 'Caqueza', - 'Ilhota', - 'Knemis Dades', - 'Cheraro', - 'Terre Neuve', - 'Massapequa Park', - 'Kelheim', - 'Lons-le-Saunier', - 'Pernamitta', - 'Carlentini', - 'Kitanakagusuku', - 'Grojec', - 'Gennep', - 'Ribeiropolis', - 'Aricak', - 'Gachancipa', - 'Sinsina', - 'Tsararivotra', - 'Albal', - 'Milledgeville', - 'Rubeho', - 'Sao Simao', - 'Piranga', - 'Xinying', - 'Wadgassen', - 'Heysham', - 'Nayakanhatti', - 'Hinode', - 'Carius', - 'Kamenz', - 'Port Washington', - 'Karratha', - 'Macatuba', - 'Sitamau', - 'Penamiller', - 'Juazeirinho', - 'Avitanallur', - 'Wixom', - 'Upper Gwynedd', - 'Pendleton', - 'Brasnorte', - 'Saint-Cyr-sur-Loire', - 'Hannibal', - 'Baaqline', - 'Marosangy', - 'Tolongoina', - 'Etrotroka', - 'Ilakatra', - 'Ambila', - 'Marofoty', - 'Ambohitrolomahitsy', - 'Lazarivo', - 'Milanoa', - 'Isoanala', - 'Amboanjo', - 'Befotaka', - 'Tsarahonenana', - 'Antanimora Atsinanana', - 'Ankarongana', - 'Ambondromisotra', - 'Ambohitsimanova', - 'Anosivelo', - 'Manombo Atsimo', - 'Anosibe-Ifanja', - 'Beahitse', - 'Antsahavaribe', - 'Ambohipihaonana', - 'Mandritsara', - 'Ambolidibe Atsinanana', - 'Sadabe', - 'Dzitbalche', - 'Ghonchi', - 'Yangi Mirishkor', - 'Jayal', - 'Matauna', - 'Ad Dulu`iyah', - 'Santo Antonio do Leverger', - 'Hindarx', - 'Alauli', - 'Saint-Egreve', - 'Peraia', - 'Naula', - 'Santo Tomas de Janico', - 'Kakraul', - 'Tomas Oppus', - 'Itajobi', - 'Ban Rawai', - 'Ambalavayal', - 'Analanampotsy', - 'Shankar Saraiya', - 'Kawai', - 'Sikandra', - 'Lodwar', - 'Oulad Amrane', - 'Guisborough', - 'Brunico', - 'Bayt Ummar', - 'Ulubey', - 'Fortuna', - 'Arai', - 'Srikurmam', - 'San Juan Lalana', - 'Andranofasika', - 'Zarumilla', - "L'Ancienne-Lorette", - 'Ibitita', - 'Koroth', - 'Ramachandrapuran', - 'Ughara', - 'Geddes', - 'Serafina Corea', - 'Ginsheim-Gustavsburg', - 'Viroflay', - 'Yanggezhuang', - 'Berga', - 'Meltonakkal', - 'Bishunpura', - "Qal'at Mgouna", - 'Santana do Cariri', - 'Cercola', - 'Bou Hanifia el Hamamat', - 'Dirba', - 'Puerto Caimito', - 'Kombai', - 'Liuchuan', - 'Mers el Kebir', - 'Balmazujvaros', - 'Octeville', - 'Perupalem', - 'Acoyapa', - 'Hohenems', - 'Pozoblanco', - 'Myrtle Grove', - 'Garagoa', - 'Upper Saucon', - 'Adelphi', - 'Heber', - 'Namyslow', - 'San Jose de Chiquitos', - 'Hunfeld', - 'Hampton Bays', - 'Bridgeview', - 'Ashwaubenon', - 'Sarioglan', - 'Chavara Gramam', - 'Boki-Were', - 'Wondelgem', - 'Powder Springs', - 'Tibau do Sul', - 'Liuguoju', - "Long'e", - 'Morriston', - 'Aubange', + 'Moron de la Frontera', + 'Dalmine', + 'Le Pont-de-Claix', + 'Ambahy', + 'Fianga', + 'Pinecrest', + 'San Bonifacio', + 'Carpinteria', + 'Stip', + 'Ergolding', + 'Lokossa', + 'Siniloan', + 'Seeheim-Jugenheim', + 'Nottingham', + 'Abrantes', + 'San Felipe Jalapa de Diaz', + 'Boninal', + 'Digor', + 'Hosur', + 'Trepuzzi', + 'Koidu', + 'Kumta', + 'Paracatu', + 'Shinkai', + 'Thuan An', + 'Pokaran', + 'Betzdorf', + 'Binde', + 'Ghazni', + 'Vembur', + 'Pontivy', + 'Juterbog', + 'Sheerness', + 'Chhindwara', + 'Alagoinhas', + 'Itabira', + 'San Jose Ojetenam', + 'Mazatenango', + 'Nabinagar', + 'Manavgat', + 'Ovenden', + 'Lagkadas', + 'Gaildorf', + 'Chirpan', + 'Vidalia', + 'Maracaju', + 'Pindwara', + 'Nova Dubnica', + 'Mokarrampur', + 'Bocaue', + 'Warsop', + 'Florida', + 'Gangajalghati', + 'Monte Alegre do Sul', + 'Kibi', + 'Pirakkad', + 'Bani `Ubayd', + 'Tiberias', + 'Palombara Sabina', + 'Rongat', + 'Wabagai', + 'Maceio', + 'Agliana', + 'Bell', + 'Yosano', + 'Potiragua', + 'Mannamangalam', + 'Yerevan', + 'Valledupar', + 'Faversham', + 'Xavantes', + 'Embrach', + 'Desanagi', + 'Ciudad de Ceuta', + 'Contagem', + 'As Sib', + 'Kulgam', + 'Kanigiri', + 'Kuljibrin', + 'Palm Beach Gardens', + 'Mugnano di Napoli', + 'Chunian', + 'Merzig', + 'Dhilwan Kalan', + 'Stainz', + 'Betera', + 'Vallur', + 'Seva', + 'Puerto Lopez', + 'Inekar', + 'Suong', + 'Tiruvottiyur', + 'Baghlan', + 'Ilo', + 'Bautzen', + 'Koutiala', + 'Allahabad', + 'Lhokseumawe', + 'San Juan del Sur', + 'Taua', + 'Sapa Sapa', + 'Otuke', + 'Sabra', + 'Kutahya', + 'Coccaglio', + 'Mamun', + 'Billerbeck', + 'Weil am Rhein', + 'Lajia', + 'Argentan', + 'Ninheira', + 'Aranya Kalan', + 'Lumding', + 'Comendador Levy Gasparian', + 'Lilongwe', + 'Cerro Largo', + 'Oosterhout', + 'Oswestry', + 'Gaspar', + 'Videle', + 'Maumelle', + 'Azezo', + 'Osuna', + 'Pulla', + 'Yangshuling', + 'Khirkiyan', + 'Hamilton', + 'Kalgoorlie', + 'Rejiche', + 'Aylesford', + 'Nagaoka', + 'Monterey Park', + 'Potavaram', + 'Jequeri', + 'Boisbriand', + 'Meliana', + 'Quilenda', + 'Santa Leopoldina', + 'Lakeland', + 'Eatontown', + 'Basilisa', + 'Wernau', + 'Sassenheim', + 'Twistringen', + 'Talitay', + 'East Wenatchee', + 'Jinbi', + '`Anbarabad', + 'Shimanto', + 'Caputira', + 'Goppingen', + 'Turuttikkara', + 'Zhongtai', + 'San Francisco Zapotitlan', + 'Hazebrouck', + 'Clemencia', + 'Surandai', + 'Khijri', + 'Jacarezinho', + 'Lunsar', + 'Ouled Sidi Brahim', + 'Chaqra', + 'Distraccion', + 'Eppelborn', + 'Vakhrusheve', + 'San Carlos del Zulia', + 'Khairpur Tamewah', + 'Shongzhy', + 'Ban Bang Kaeo', + 'Murillo', + 'Ban Mai', + 'Lakoucun', + 'Kottaikuppam', + 'Sini', + 'Karditsa', + 'Penumur', + 'Ramos', + 'Arauco', + 'Chatayamangalam', + 'Nieuw-Lekkerland', + 'Ixhuatlan del Sureste', + 'Bog Walk', + 'Daltonganj', + 'Guamo', + 'Kiklah', + 'Bongouanou', + 'Las Pinas City', + 'Narni', + 'Olesa de Montserrat', + 'Barrancabermeja', + 'Souama', + 'Sokolow Podlaski', + 'Katakwi', + 'Sunset', + 'Dilawarpur', + 'Telagh', + 'Caapiranga', + 'Pavittiram', + 'Yunzhong', + 'Paicandu', + 'Farafangana', + 'Zawyat Sidi Ben Hamdoun', + 'Bosilegrad', + 'Cabanaquinta', + 'Eaubonne', + 'El Paujil', + 'Matca', + 'Rawdon', + 'Tongoma', + 'Monsefu', + 'Itaguara', + 'Mihama', + 'Alengad', + 'Zhumadian', + 'Schlieren', + 'Murree', + 'Seto', + 'Yenipazar', + 'Kharak Kalan', + 'Ambares-et-Lagrave', + 'Kawlin', + 'Sainte-Julienne', + 'Khagaul', + 'Dyersburg', + 'Ekuvukeni', + 'Virginopolis', + 'Zhenzhou', + 'Jiashizhuangcun', + 'Changchong', + 'Notodden', + 'Stephenville', + 'Rellingen', + 'Keolari', + 'Los Alcarrizos', + 'Brake', + 'Yuzawa', + 'Cabatuan', + 'Kanegasaki', + 'Vohiposa', + 'Arequipa', + 'Antseza', + 'Puspokladany', + 'Natick', + 'Astrea', + 'Auchel', + 'Aquidauana', + 'Mohlin', + 'Redcar', + 'Brookline', + 'Jekabpils', + 'Melville', + 'Pintadas', + 'Manfalut', + 'Aasiaat', + 'Sao Borja', + 'Ransiki', + 'Ibipetuba', + 'Kuala Lumpur', + "Tong'anyi", + 'Eklahra', + 'Satara', + 'Pupri', + 'Gualcince', + 'Friedberg', + 'Sinnai', + 'Saynshand', + 'Bupoto', + 'Kalanjur', + 'Hilversum', + 'Shobara', + 'Mahaplag', + 'Puturge', + 'Oued Jdida', + 'Melnik', + 'Pointe-Noire', + 'Tipton', + 'Tekari', + 'Ounagha', + 'Cavriago', + 'Lupon', + 'Paoay', + 'Follonica', + 'Bhachhi Asli', + 'Hofheim', + 'Kasukabe', + 'Viligili', + 'Tinton Falls', + 'Limay', + 'Pauktaw', + 'Sedziszow Malopolski', + 'Citrus', + 'Chirongui', + 'Mitane', + 'Payimattam', + 'Pajaros', + 'Gelves', + 'Tupi Paulista', + 'Pokhuria', + 'Thetford Mines', + 'Iselin', + 'Bandar Murcaayo', + 'Taungoo', + 'Hikawadai', + 'Los Santos', + 'Marbella', + 'Vranje', + 'Squamish', + 'Mahthi', + 'Toura', + 'Cicciano', + 'Wernigerode', + 'Xiaobazi', + 'Reforma', + 'Ispir', + 'Ntcheu', + 'Samboan', + 'Kelamangalam', + 'Diglipur', + 'Malkhaid', + 'Tomakomai', + 'Vidhareidhi', + 'Rio Grande City', + 'Puerto Libertador', + 'Ariccia', + 'Mashhad', + 'Renkum', + 'Sakabansi', + 'Dandeli', + 'Gahanna', + 'Waupun', + 'Sonoma', + 'Kutchan', + 'Phetchabun', + 'Bischwiller', + 'Barotac Viejo', + 'Giresun', + 'Caieiras', + 'Rodeiro', + 'Guabo', + 'Kusti', + 'Ketou', + 'Oestrich-Winkel', + 'Cayce', + 'Sume', + 'Yaese', + 'Zemamra', + 'Spring Garden', + 'Sheron', + 'Karnawad', + 'Neu-Ulm', + 'Grafelfing', + 'Costa Mesa', + 'Wangjia', + 'Joaquim Gomes', + 'Al Qurnah', + 'Naivasha', + 'Borgerhout', + 'Santa Rosalia', + 'Corocoro', + 'Liskeard', + 'Kruibeke', + 'Mingaora', + 'Latauna', + 'Sepolno Krajenskie', + 'Madison', + 'Berkane', + 'San Giovanni Rotondo', + 'Siwah', + 'Aldeia de Paio Pires', + 'Krosno Odrzanskie', + 'Zriba-Village', + 'Tampico', + 'Gastre', + 'Katrineholm', + 'Joao Pinheiro', + 'Martensville', + 'Karakocan', + 'San Antero', + 'Pocinhos', + 'Erravaram', + 'Ogaki', + 'Ezzhiliga', + 'Dimmbal', + 'Torul', + 'Darlaston', + 'Itapissuma', + 'Mragowo', + 'Buton', + 'Villach', + 'Xinzhancun', + 'Rusape', + 'Ialoveni', + 'Biltine', + 'Alukkuli', + 'Panpuli', + 'Barili', + 'Kempen', + "`Alem T'ena", + 'Wustermark', + 'Murnau am Staffelsee', + 'El Ghomri', + 'Kambhaladinne', + 'Ciego de Avila', + 'Khoragachhi', + 'Tiburon', + 'Ohata', + 'San Martin Zapotitlan', + 'Priego de Cordoba', + "Mun'gyong", + 'Placetas', + 'Comodoro Rivadavia', + 'Goluwali', + 'Janglot', + 'Ammanford', + 'Juquia', + 'Parapua', + 'Mitchell', + 'Lincoln', + 'Kafr Sa`d', + 'Dhanwada', + 'Vergiate', + 'Son Servera', + 'Uto', + 'Gesuba', + 'Jamaat Shaim', + 'Basirhat', 'Dalain Hob', - 'Tekanpur', - 'Eggenstein-Leopoldshafen', - 'Guadalupe Victoria', - 'Huruta', - 'Baikatpur', - 'Malancha', - 'Shingucho-shingu', - 'Carovigno', - 'Stockerau', - 'Governador Celso Ramos', - 'Glace Bay', - 'Cubellas', - 'McKinleyville', - 'Tobre', - 'Rio Bueno', + 'Bishenpur', + 'Regensburg', + 'Altensteig', + 'Kekem', + 'Sanwal', + 'Palankottai', + 'Raquira', + 'Antsahanoro', + 'Cerignola', + 'Beesel', + 'Burj al `Arab', + 'Rantepao', + 'Ankadindambo', + 'Jinotega', + 'Hechingen', + 'Ingersoll', + 'Vitoria da Conquista', + 'Parma', + 'Vaciamadrid', + 'Daita', + 'Santa Catarina Juquila', + 'Kozje', + 'Hagen', + 'Pargi', + 'Porto Nacional', + 'Krishnarajpur', + 'Huazangsi', + 'Blida', + 'Majra', + 'Sahasoa', + 'Inzai', + 'Murrysville', + 'Jalalpur', + 'Belakoba', + 'Ichalkaranji', + 'Almagro', + 'Vassouras', + 'Taubate', + 'Sarrat', + 'Jupiter', + 'Icara', + 'Avrankou', + 'Brick', + "Giv`at Shemu'el", + 'Bargarh', + 'Wang Tau Hom', + 'Teixeira', + 'Darmstadt', + 'Kasuya', + 'Periya Pattanam', + 'Dangbo', + 'El Viejo', + 'Xapuri', + 'Woodbury', + 'Pampatar', + 'Waspan', + 'Samabouro', + 'Al Ahad al Masarihah', + 'Koath', + 'Gwanda', + 'Vinhais', + 'Islahiye', + 'Mogpog', + 'Bayt Jala', + 'Nagireddipalli', + 'Miami Beach', + 'Conversano', + 'Quartier Militaire', + 'Cauto Cristo', + 'Arhribs', + "Villa O'Higgins", + 'Orange Walk', + 'Dharmavaram', + 'Paraiso do Tocantins', + 'Calolziocorte', + 'Capitan Sarmiento', + 'Tyagadurgam', + 'Vendram', + 'Harstad', + 'Caldogno', + 'Tlaxcoapan', + 'Jiangjiafan', + 'Arta', + 'Jacona de Plancarte', + 'Sarpol-e Zahab', + 'Nahuala', + 'Boa Esperanca', + 'Mealhada', + 'Troutdale', + 'Wharton', + 'Tournon-sur-Rhone', + 'Casino', + 'Saint-Lin--Laurentides', + 'Jaco', + 'Evander', + 'Figeac', + 'Elukone', + 'Camocim', + 'Sahpur', + 'Lower Tungawan', + 'Vengur', + 'Miraima', + 'Ximeicun', + 'Hoogland', + 'Weimar', + 'Kokkola', + 'Atiquizaya', + 'Oldenburg in Holstein', + 'Kulattuppalaiyam', + 'Ramada', + 'Itampolo', + 'Bommarbettu', + 'Piove di Sacco', + 'Kanavaypatti', + 'Ise', + "Oktyabr'sk", + 'Tigzirt', + 'Oulad Amrane', + 'Kundal', + 'Cheria', + 'Kalchini', + 'Dschang', + 'Bentiu', + 'Emboscada', + 'Sangram', + 'Plerin', + 'Kezi', + 'Grobenzell', + 'Tomino', + 'Santa Cruz do Rio Pardo', + 'Isorana', + 'Al Qbab', + 'Sleepy Hollow', + 'Dehloran', + 'Taixi', + 'Noamundi', + 'Ankilimalinika', + 'Hwasu-dong', + 'San Bruno', + 'Dijon', + 'Yiyang', + 'Guntakal', + 'Suluova', + 'Kottacheruvu', + 'Ludwigshafen', + 'Ghargaon', + 'Rosa', + 'Sual', + 'Miller Place', + 'Dronten', + 'Dobbs Ferry', + 'Santa Marta', + 'Khopoli', + 'Kelilalina', + 'Bela Cruz', + 'Klela', + 'Santomera', + 'Chortoq', + 'Kemp Mill', + 'Mae Rim', + 'Yalvac', + 'Meridiala', + 'Itaporanga', + 'Macerata Campania', + 'Maxeville', + 'Sierra Colorada', 'Ginatilan', + 'Fortaleza', + 'Tenmalai', + 'Oyonnax', + 'Taishi', + 'Krapkowice', + 'Sojitra', + "Alamat'a", + 'Flemalle-Haute', + 'Jeannette', + 'Edessa', + 'Fairview Park', + 'Pabianice', + 'An Nayrab', + 'Gussago', + 'Aridagawa', + 'Inebolu', + 'Ponte Buggianese', + 'Comallo', + 'Handeni', + 'Kadogawa', + 'Vesala', + 'Santana do Manhuacu', + 'Vicente Guerrero', + 'Trnovska Vas', + 'Franklin Square', + 'Hessle', + 'Tuvur', + 'Les Mureaux', + 'Rikuzen-Takata', + 'Shahmirzad', + 'Irshava', + 'Almirante Tamandare', + 'Bhairapura', + 'Grand Forks', + 'Adolfo Gonzales Chaves', + 'Donmatias', + 'Jobat', + 'Jami', + 'Norfolk', + 'Kasagi', + 'Senador Canedo', + 'Bhabanipur', + 'Danville', + 'Guaraciaba do Norte', + 'Perez', + 'Akaiwa', + 'Santa Cruz do Monte Castelo', + 'Deerlijk', + 'Key West', + 'Somandepalle', + 'Bartoszyce', + 'Tsuiki', + 'Hillegom', + "Qa'emiyeh", + 'Sahidganj', + 'Terrier Rouge', + 'Marikina City', + 'Vinzons', + 'Makouda', + 'Conceicao da Barra', + 'Tebesbest', + 'Hachinohe', + 'Carora', + 'Luckeesarai', + 'Castelo', + 'Bommagondanahalli', + 'Kutavur', + 'Bedworth', + 'Laarne', + 'East Grand Rapids', + 'Itatiba', + 'Pineville', + 'Banhatti', + 'Thiotte', + 'San Martin de las Piramides', + 'Puconci', + 'Saidpur Dabra', + 'Xaghra', + 'Zhuhai', + 'Altamonte Springs', + 'Warminster', + 'Zollikon', + 'Patiala', + 'Oxted', + 'Gornja Radgona', + 'Bade', + 'Dahe', + 'Risca', + 'Puxinana', + 'Mixtla de Altamirano', + 'Haderslev', + 'Sun Village', + 'Mahazoarivo', + 'Asara', + 'Tortosa', + 'Bellmead', + 'San Marino', + 'Khrestivka', + 'Usuki', + 'Yasynuvata', + 'North Valley', + 'Chennur', + 'Bishnupur', + 'Fanzhao', + 'Oltinko`l', + 'El Carmen', + 'Lagawe', + 'Argentona', + 'Torgau', + 'Tiflet', + 'Xincun', + 'Thap Khlo', + 'Havant', + 'Sulingen', + 'Apt', + 'Sabana de Torres', + 'Qyzylorda', + 'Hebburn', + 'Katerini', + 'Werota', + 'Taishan Houcun', + 'Zefyri', + 'Akseki', + 'Nkawkaw', + 'Sabangan', + 'West Sacramento', + 'Calandala', + 'Charcas', + 'Ash Shaykh `Uthman', + 'Mahajeran-e Kamar', + 'Toundout', + 'Mainvilliers', 'Kronach', - 'Zinapecuaro', - 'Carlopolis', - 'Mari`', - 'Findikli', - 'Masse', - 'Iziaslav', - 'Naranattenvanpatti', - 'Nidgundi', - 'Sidi Daoud', - 'High Blantyre', - 'Pallikapuzha', - 'Douar Lamjaara', - 'Ramayampet', - 'Dehaqan', - 'Laconia', - 'Tubaran', - 'Dazhangzicun', - 'Dazhangzi', + 'Jayal', + 'Ruthen', + 'Kamenz', + 'Cayirova', + 'Temple', + 'Sammamish', + 'Agstafa', + 'Gleno', + 'Sattahip', + 'Kichha', + 'Tartagal', + 'Pingliang', + 'Ganvie', + 'Zapotiltic', + 'Temsamane', + 'Gyegu', + 'Shangqiu', + 'Niquen', + 'Baotou', + 'Orzesze', + 'Ghanzi', + 'Manikkal', + 'Zaraza', + 'Sarbisheh', + 'Mabehiri', + 'Clitheroe', + 'Jastrebarsko', + 'Frydek-Mistek', + 'Taxila', + 'Valencia West', + 'Ambalaroka', + 'Fouriesburg', + 'Ojuelos de Jalisco', + 'Saurimo', + 'Bereket', + 'Ledbury', + 'Lenexa', + 'Bakhor', + 'Come', + 'Tonk Khurd', + 'Chak Jhumra', + 'Qarah', + 'Macaparana', + 'Dormagen', + 'Kamirenjaku', + 'Nhlangano', + 'Loughton', + 'Carcarana', + 'Bahawalpur', + 'Hengshui', + 'Pointe-a-Pitre', + 'Louvain-la-Neuve', + 'Lindong', + 'Elsfleth', + 'Gangavalli', + 'Aguelmous', + 'Termas de Rio Hondo', + 'Nueva Paz', + 'Karuvellur', + 'Dholka', + 'Dishashah', + 'Neropolis', + 'Ourilandia do Norte', + 'Gorna Oryahovitsa', + 'Dangyang', + 'Raiganj Bazar', + 'Piliv', + 'Chosei', + 'Chambas', + 'Ringwood', + 'Bongaigaon', + 'Polignano a Mare', + 'Naranda', + 'Mondai', + 'Babadag', + 'Nattam', + 'Crosne', + 'Ananipalle', + 'Sorata', + 'Collipulli', + 'Famenin', + 'Waddinxveen', + 'Koratgi', + 'Mojokerto', + 'Moreno Valley', + 'Baltit', + 'Wokha', + 'Salzwedel', + 'Shangtangcun', + 'Stahnsdorf', + 'Jetpur', + 'Vellallur', + 'Drouin', + 'Tochigi', + 'Kaniyambadi', + 'Aran Bidgol', + 'Park Ridge', + 'Ammon', + 'Guipavas', + 'Miaoli', + 'Monchengladbach', + 'Sulahpet', + 'McMinns Lagoon', + 'Palangotu Adwar', + 'Delray Beach', + 'Singura', + 'Oakland Park', + 'Goonellabah', + 'Drezdenko', + 'Athurugiriya', + 'Aizumi', + 'Maria la Baja', + 'Toshloq', + 'Pale', + 'Burhar', + 'Murrieta', + 'Loufan', + 'Kibungo', + 'Doi Lo', + 'New Bedford', + 'Srinivaspur', + 'Atru', + 'Mataili Khemchand', + 'Ashibetsu', + 'Hansi', + 'Bacong', + 'Rukhae', + 'Kosching', + 'Addison', + 'Rangpur', + 'Toppenish', + 'Eyvanekey', + 'Girardot', + 'Piravanthur', + 'Korem', + 'Porto Torres', + 'Lagoa Grande', + 'Aratuba', + 'Hadithah', + 'Bel Air South', + 'Buluko', + 'Ambala', + 'Baie du Tombeau', + 'El Cairo', + 'Caluire-et-Cuire', + 'Caluya', + 'Ponedera', + 'Ban Bang Mae Nang', + 'Leer', + 'Kissing', + 'Shamalgan', + "'s-Heerenberg", + 'Miguel Calmon', + 'Bar', + 'Birak', + 'Igana', + 'Onnaing', + 'Sveta Trojica v Slovenskih Goricah', + 'Boca do Acre', + 'Amaravati', 'Dhulkot', - 'Belle Glade', - 'Aklanpa', - 'Navalmoral de la Mata', - 'Fetromby', - 'Bruckmuhl', - 'Khed', - 'Colonial Park', - 'Ngara', - 'Morteros', - 'Sao Joao dos Poleiros', - 'Farmingville', - 'Vatutine', - 'Soumagne', - 'Ettaiyapuram', - 'Majra', - 'New Milford', - 'Miqiao', - 'Heidenau', - 'Azaourisse', - 'Chambellan', - 'Laferriere', - 'Ighram', - 'Bermeo', - 'Benesov', - 'La Quiaca', - 'Sada', - 'Agaram', - 'Boa Vista do Tupim', - 'Annonay', - 'Pleszew', - 'Bedigoazon', - 'Lamas', - 'Ashmyany', - 'Colesberg', - 'Canutama', - 'Thale', - 'Hosakote', - 'Le Pre-Saint-Gervais', - 'Bambara-Maounde', - 'Nerang', - 'Japaratuba', + 'Joubb Jannine', + 'Edeia', + 'Toda', + 'Okinoshima', + 'Murra', + 'East Renton Highlands', + 'Badshahpur', + 'Lalgudi', + 'Bomareddipalli', + 'Curaca', + 'Zetale', + 'Yuci', + 'Levittown', + 'Linbian', + 'Toyooka', + 'Krugersdorp', + 'Northfleet', + 'McKee City', + 'Atescatempa', + 'Dundo', + 'Sarableh', + 'Santo Domingo', + 'Lucca', + 'Le Chambon-Feugerolles', + 'Kanyato', + 'Sokoura', + 'Ponte de Lima', + 'Kafr Laha', + 'Covenas', + 'Shchastia', + 'Bamenda', + 'Tolmin', + 'Ottakkadai', + 'Palmetto Bay', + 'Castrop-Rauxel', + 'Barra dos Coqueiros', + 'Mahdishahr', + 'Angra do Heroismo', + 'Chulucanas', + 'Haslev', + 'Cahul', + 'Luocheng', + 'Asyut', + 'Muping', + 'Country Club Hills', + 'Ambondro', + 'Nakayama', + 'Boljevac', + 'Chaman', + 'Birqash', + 'Ghat', + 'Cungus', + 'Cuyapo', + 'Kissane Ltouqi', + 'Mexborough', + 'Mansinghpur Bijrauli', + 'Komlo', + 'Boissy-Saint-Leger', + 'Sabinopolis', + 'Talkhvoncheh', + "'s-Gravendeel", + 'Malkara', + 'Glace Bay', + 'San Andres Sajcabaja', + 'Pforzheim', + 'Wombwell', + 'New Hanover', + 'Schneverdingen', + 'Vidisha', + 'Neubiberg', + 'Banu Chhapra', + 'Pamidi', + 'Benkovac', + 'Cocoa', + 'Stawell', + 'Saint-Quentin', + 'Northdale', + 'Clermont', + 'Don Torcuato', + 'Hanchuan', + 'Hessisch Lichtenau', + 'Jena', + 'Tursunzoda', + 'Avintes', + 'Burela de Cabo', + 'Gladenbach', + 'Myszkow', + 'Quiroga', + 'Azove', + 'Sao Geraldo', + 'Penrith', + 'Arenapolis', + 'Miyada', + 'Jurbarkas', + 'Matias Olimpio', + 'Bindki', + 'Ditzingen', + 'Babaeski', + 'Lyngdal', + 'Baarn', + 'Xinmin', + 'Sondho Dullah', + 'San Onofre', + 'Halawah', + 'Soran', + 'Suihua', + 'Perere', + 'Ban Thum', + 'Massy', + 'Delta', + 'Qom', + 'Eldoret', + 'Tournavista', + 'Cangas', + 'Juchen', + 'Pattikonda', + 'Cacuaco', + 'Kamisato', + 'Ilarionove', + 'Spijkenisse', + 'Anavatti', + 'Seringueiras', + 'Beipiao', + 'Kouribga', + 'Kirangur', + 'Bismarck', + 'Ahaus', + 'Barajor', + 'Canta', + 'Sierre', + 'Gopalpur', + 'Fremont', + 'Baixa Grande', + 'Apolo', + 'Xigujing', + 'Vevcani', + 'Madhura', + 'Feucht', + 'Fehmarnsund', + 'Cesme', 'Nerviano', - 'Pampa', - 'Jask', - 'Alfajayucan', - 'Ban Tha Mai I', - 'Moraga', - 'Latifpur', - 'Sayarpuram', - 'Linnei', - 'Korem', - 'Maltby', - 'Rampur Jalalpur', - 'Rubano', - 'Lerum', - 'Sliema', - 'Pulimel', - 'Janakkala', - 'Bitburg', - 'Defiance', - 'Sao Pedro do Sul', - 'Pran Buri', - 'Finnentrop', - 'Madanpur', - 'Braunstone', - 'Fiorano Modenese', - 'Bostonia', - 'Haslingden', - 'Boden', - 'Azeffoun', - 'Meiti', - 'North Hykeham', - 'Shahkot', - 'Hot Springs Village', - 'Ain Feka', - 'Xixinzhuangzhen', - 'Vallegrande', - 'Wittenberge', - 'Lillerod', - 'Acharipallam', - 'Devizes', - 'Tsuiki', - 'Hrubieszow', - 'Trzcianka', - 'Montceau-les-Mines', - 'Saltash', - 'Vechur', - 'Mattoon', - 'Upper Chichester', - 'Washougal', - 'Haslemere', - 'Achaljamu', - 'Ratba', - 'Orastie', - 'Brixham', - 'Yabuki', - 'Salinas de Hidalgo', - 'Gemert', - 'Bhainsoda', - 'Makinsk', - 'Asten', - 'Dongjiangshui', - 'Saint Ives', - 'Kadikkad', - 'Sidi Lamine', - 'Bad Lippspringe', - 'Vazhani', - 'Baronissi', - 'Minamichita', - 'Daireaux', - 'Altintas', - 'Kodikulam', - 'Wyckoff', - 'Cerea', - 'Keetmanshoop', - 'Rijen', - 'Busolwe', + 'Brownsweg', + 'Baynala', + 'Ky Anh', + 'Khunti Dhanaili', + 'Arjona', + 'Ciudad Sandino', + 'Lyantonde', + 'Pililla', + "Santa Croce sull' Arno", + 'Liangshi', + 'Pirkkala', + 'Saligrama', + 'Odugattur', + 'Pullanvidudi', + 'Fort Irwin', + 'Veliko Gradiste', + 'Culiacan', + 'Singa', + "Conde-sur-l'Escaut", + 'North Fort Myers', + 'Martinez', + 'Raisinghnagar', + 'Heubach', + 'Accokeek', + 'Citta di Castello', + 'Sint-Genesius-Rode', + 'Iruma', + 'Curico', + 'Pitlam', + 'Niamey', + 'Araci', + 'Zaozhuang', + 'Az Zahiriyah', + 'Takouta', + 'Douar Bouchfaa', + 'Mirna', + 'Aron', + 'Firminopolis', + 'Niederwerrn', + 'Chandi', + 'Parana', + 'Bom Jesus do Galho', + 'Boussu', + 'General Nakar', + 'Elancourt', + 'Tirodi', + 'Cosenza', + 'Sooke', + 'Alga', + 'Duruma', + '`Amuda', + 'Aburi', + 'Short Hills', + 'Haripura', + 'Granada', + 'The Mumbles', + 'Yadavolu', + 'East Honolulu', + 'Vellalapuram', + 'Boufarik', + 'Oer-Erkenschwick', + 'Terkuvenganallur', + 'Orodara', + 'Didouche Mourad', + 'Stapleford', + 'Iles', + 'Cantilan', + 'Kennebunk', + 'Urasoe', + 'Singosari', + 'Onda', + 'Rushall', + 'Bukhara', + 'Ibbenburen', + 'Epsom', + 'Glendale Heights', + 'Ubai', + 'Chatra', + 'Ranavav', + 'Chevilly-Larue', + 'Kemijarvi', + 'Ungoofaaru', + 'Zaouiat Moulay Bouchta El Khammar', + 'Vinaninkarena', + 'Zaleze', + 'Zelenikovo', + 'Newfane', + 'Langedijk', + 'Orly', + 'Berchha', + 'Guimba', + 'Gamboula', + 'Alakamisy Itenina', + 'Alotau', + 'Sothgaon', + 'Bockum', + 'Sawai Madhopur', + 'Lahan', + 'Santa Ignacia', + 'Modesto', + 'Jales', + 'Baragaon', + 'Huarmey', + 'North Ridgeville', + 'Kolomyia', + 'San Martin de los Andes', + 'Saboeiro', + 'Bucay', + 'Xexeu', + 'Santo Stino di Livenza', + 'Boca Chica', + 'Keskin', + 'Namtu', + 'Nyenga', + 'Carlow', + 'Medemblik', + 'Cadoneghe', + 'Hagondange', + 'Zozocolco de Hidalgo', + 'Desamparados', + 'Bengonbeyene', + 'Bou Zemou', + 'Bellary', + 'Bremen', + 'Fitzgerald', + 'Finale Emilia', + 'Bilgi', + 'Starobilsk', + 'Korangal', + 'Ingeniero Maschwitz', + 'Akat Amnuai', + 'Afua', + 'Dondon', + 'Dhangaraha', + 'Avellaneda', + 'Castelfranco di Sopra', + 'Bang Racham', + 'Bisaul', + 'Persan', + 'Palaw', + 'Manja', + 'Lindesberg', + 'Halton Hills', + 'Mandaon', + 'Ratingen', + 'Staszow', + 'Sitakili', + 'Niebull', + 'Malabo', + 'Berceni', + 'Floha', + 'Wiltz', + 'Anamoros', + 'Banqiao', + 'Afgooye', 'Druzhba', - 'Maroochydore', - 'Astara', - 'Montornes del Valles', - 'Beinan', - 'Ambares-et-Lagrave', - 'Sinuni', - 'Kaliro', - 'Puliyankunnu', - 'Marib', - 'Famy', - 'Sierre', - 'Roxana', - 'Kamavarapukota', - 'Weehawken', - 'Cestas', - 'Tromsdalen', - 'Sao Paulo do Potengi', - 'Fazakerley', - 'El Rosario', - 'Sudak', - 'Batuco', - 'Kauhava', - 'Truckee', - 'Orta Nova', - 'Pionki', - 'Villeneuve-Loubet', - 'Tsundupalle', - 'Solothurn', - 'Palmetto Estates', - 'Ricany', - 'Windlesham', - 'Vila Bela da Santissima Trindade', - 'Latsia', - 'Buntok', - 'Sunland Park', - 'Ouaouzgane', - 'Posoltega', - 'Connahs Quay', - "'Ain Abessa", - 'Masamagrell', - 'Masif Sarsink', - 'Dhobauli', - 'Bauria', - 'Puerto Carreno', - 'Humacao', - 'Attappampatti', - 'Egirdir', - 'Havelock', - 'Yaglidere', - 'Young', - 'El Pinon', - 'Nandigaon', - 'Bovisio Masciago', - 'Djouab', - 'San Miguel de Salcedo', + 'Montevrain', + 'Socopo', + 'Logatec', + 'Prestatyn', + 'Lodhikheda', + 'Phuket', + 'Berriozabal', + 'Puan', + 'Brooklyn', + 'Casma', + 'New Square', + 'Lake Station', + 'San Juan de Rio Coco', + 'Korydallos', + 'Cubatao', + 'Stidia', + 'Kalamansig', + 'Amstetten', + 'Ventersburg', + 'Khovaling', + 'Millburn', + 'Halba', + 'Tenggarong', + 'Stelle', + 'Bacup', + 'Cacak', + 'Khamanon Kalan', + 'Fanyang', + 'Patikul', + 'Igarassu', + 'Lakeland Village', + 'Sanxing', + 'Kongsberg', + 'Harelbeke', + 'Chintalapudi', + 'Chinna Ganjam', + 'Utena', + 'Carai', + 'Calcoene', + 'Salgar', 'Maardu', - 'Chiva', - 'Swift Current', - 'Campo do Brito', - 'Chestnuthill', - 'Kadod', - 'Nuevo San Juan Parangaricutiro', - 'Shahba', - 'Konigstein im Taunus', - 'Thandla', - 'Kushima', - 'Donna', - 'New Port Richey', - 'Chinampa de Gorostiza', - 'Agua Clara', - 'Vimodrone', - 'Ribat Al Khayr', - 'Bytow', - 'Diksmuide', - 'Arakkal', - 'Yerbas Buenas', - 'Preganziol', - 'Plumstead', - 'Livinjipuram', - 'Burstadt', - 'Sobrado de Paiva', - 'Leixlip', - 'Boysun', - 'Dera', - 'Tengampudur', - "Bek'oji", - 'Kings Park', - 'Penzberg', - 'Takhatgarh', - 'Sendurai', - 'Roche-a-Bateau', - 'Hirna', - 'Katsuura', - 'Ponte de Sor', - 'Baicoi', - 'Holzkirchen', - 'Bredbury', - 'Chalala', - 'Konodimini', - 'Kukes', - 'Iluppur', - 'Fuying', - 'Fuyingzicun', - 'Dour', - 'Kodumudi', - 'Glanerbrug', - 'Klippansbruk', - 'Aston', - 'La Vista', - 'Cabeceiras de Basto', - 'Pisticci', - 'Firestone', - 'Saalfelden am Steinernen Meer', - 'Kattiyeri', - 'Gikongoro', - 'Balighattam', - 'Porto Acre', - 'Gonegandla', - 'Ban Wang Nok Aen', - 'Verdun', - 'Pazhayannur', - 'Piriyapatna', - 'East Greenbush', - 'Jalpa de Mendez', - 'Saran', - 'Nassjo', - 'Rotselaar', - 'Erumad', - 'Harborcreek', - 'Havi Bhauar', - 'Zafra', - 'Murraysville', - 'Deoria', - 'Ocho Rios', - 'Nea Makri', - 'Chateaurenard', - 'Phrae', - 'Kundal', - 'Campagna', - 'Murehwa', - 'Sao Caetano de Odivelas', - 'Zequ', - 'Banstead', - 'Kumage', - 'Riemst', - 'Przasnysz', - 'Podalakur', + 'Tarhunah', + 'Breaza', + 'Villamontes', + 'Vadakakarai', + 'Jaidte Lbatma', + 'Chautapal', + 'Dois Corregos', + 'Mahmudabad Nemuneh', + 'Raul Soares', + 'Walker Mill', + 'Qiaoyang', + 'Alachua', + 'Nailsea', + 'Ipaumirim', + 'Wakabadai', + 'Sebt Labrikiyne', + 'Anupshahr', + 'Calinog', + 'Hammamet', + 'Famagusta', + 'Norwich', + 'Little Falls', + 'Arealva', + 'Bad Schwalbach', + 'Dovzhansk', + 'Amiens', + 'Floridia', + 'Sukma', + 'Zoeterwoude', + 'Narahia', + 'Santo Nino', + 'Acate', + 'Zuromin', + 'Kagithane', + 'Quarrata', + 'Ivankiv', + 'Sougueur', + 'Ain Harrouda', + 'Temsia', + 'Yangjiang', + 'Baja', + 'Ampasina-Maningory', + 'Porto', + 'Kolavallur', + 'Dianbu', + 'Sakuragawa', + "L'Union", + 'Prattipadu', + 'Mogosoaia', + 'Lija', + 'Dornbirn', + 'Madera Acres', + 'Munro Turuttu', + 'Ban Ao Nang', + 'Catubig', + 'Kibungan', + 'Cienfuegos', + 'Taza', + 'Zoma-Bealoka', + 'Zabid', + 'Sandare', + 'Labuleng', + 'Dresden', + 'The Valley', + 'Le Kram', + 'Shihe', + 'Zira', + 'Kurume', + 'Wengtiancun', + 'Mucuri', + 'Burnley', + 'Aborlan', + 'Allen', + 'Diriomo', + 'Metro', + 'Mandalgovi', + 'Etten-Leur', + 'Almeria', + 'Wootton', + 'Doukouya', + 'Ban Tha Khlong', + 'Trikala', + 'Hasanpura', + 'Gisborne', + 'Cooper City', + 'Mukasi Pidariyur', + 'Oulad Yaich', + 'Ibitita', + 'Majarhat', + 'Naas', + 'Sete Barras', + 'Ongata Rongai', + 'El Parral', + 'Hayrabolu', + 'Kasipalaiyam', + 'Jamaame', + 'Tripoli', + 'Ettapur', + 'Gurnee', + 'Ofunato', + 'Statesville', + 'Taiwa', + 'Boekenhouthoek', + 'Bandar-e Khamir', + 'Meningie', + 'Valle de La Pascua', + 'Vinhedo', + 'Ksar', + 'Al Mindak', + 'Blackrock', + 'Kaua Kol', + 'Ban Yaeng', + 'Kodaimangalam', + 'Brownsville', + 'Zhushan', + 'Vrede', + 'Pombas', + 'Albatera', + 'Puerto Narino', + 'Pakpattan', + 'Awfouss', + 'Santa Cruz de Los Taques', + 'Thi Tran Ngai Giao', + 'Pakkam', + 'Chibok', + 'Wollert', + 'Berisso', + 'Pocone', + 'Eindhoven', + 'Eramala', + 'Alphen aan den Rijn', + 'Kamuli', + 'Puerto Quijarro', + 'Manaus', + 'Burleson', + 'Topsham', + 'Maribondo', + 'Buta', + 'Tampamolon Corona', + 'Alagoinha', + 'Valljkkod', + 'Nilo Pecanha', + 'Chachahuantla', + 'Dax', + 'Texcatepec', + 'Horizontina', + 'Serra Negra', + 'Kolda', + 'Bee Ridge', + 'Nekarikallu', + 'Wasilla', + 'Vatana', + 'Bestobe', + 'Fatsa', + "Sao Joao d'Alianca", + 'Sondrio', + 'Gorgonzola', + 'Nongstoin', + 'Yaguajay', + 'Solapur', + 'Abington', + 'Star', + 'Asuncion', + 'Valdosta', + 'Zhongtanying', + 'Rewahi', + 'Ankarana-Miraihina', + 'Debar', + 'Playa Grande', + 'Guabiruba', + 'Del Aire', + 'Tumen', + 'Perket', + 'Sinor', + 'Canford Cliffs', + 'Khorramdarreh', + 'Latehar', + 'Guerouma', + 'Pine Ridge', + 'Alba Iulia', + 'Qalansuwa', + 'Orocue', + 'Taraz', + 'Jesus Maria', + 'Langsa', + 'Trikkunnapuzha', + 'Nosy Varika', + 'Nishi', + 'Anjangaon', + 'Trebisacce', + 'Taucha', + 'Grosshansdorf', + 'Shirone', + 'Swakopmund', + "Bog'ot", + 'Antenor Navarro', + 'Parsippany-Troy Hills', + 'East Northport', + 'Sur Singh', + 'Huy', + 'Gandikunta', + 'Tamarakulam', + 'Cerknica', + 'Hindaun', + 'Vichy', + 'Hilo', + 'Branson', + 'Kalimala', + 'Othello', + 'Dol', + 'Nanga Eboko', + 'Angical', + 'Plains', + 'Culpeper', + 'Famjin', + 'Watrap', + 'Basrur', + 'Aracoiaba da Serra', + 'Bretten', + 'Gavere', + 'Lingxi', + 'Doctor Juan Eulogio Estigarribia', + 'Aracatuba', + 'Fredonia', + 'Wittmund', + 'Hirao', + 'Elmshorn', + 'Pfullingen', + 'Temse', + 'Betim', + 'Bhiraha', + 'Taquara', + 'Orivesi', + 'Thanh Pho Uong Bi', + 'Kamalganj', + 'Manamadurai', + 'Sint-Kruis', + 'Sankaramangalam', + 'Evergreen Park', + 'Catigbian', + 'Auhar Sheikh', + 'Gornji Vakuf', + 'Obanazawa', + 'Casandrino', + 'Saquisili', + 'Narsinghgarh', + 'Mitcham', + 'Carmelo', + 'Green', + 'Ringsted', + 'Timmins', + 'Wobulenzi', + 'Haddington', + 'Lohna', + 'West Mifflin', + 'Al Musayyib', + 'Brugg', + 'Jyvaskyla', + 'Al Muharraq', + 'Heroica Caborca', + 'Mapandan', + 'Osimo', + 'Srem', + 'Caxito', + 'Tantega', + 'Mahajamba', + 'Stara Tura', + 'Palo Alto', + 'Miskolc', + 'Dharmapuri', + 'Krefeld', + 'Sibutao', + 'Itinga', + 'Kuacjok', + 'Zhaodong', + 'Ambikapur', + 'Cologno al Serio', + 'Agua Branca', + 'Barskoon', + 'Jora', + 'Ciudadela', + 'Yenice', + 'Anderlecht', + 'Sunny Isles Beach', + 'Pilikodu', + 'San Marzano di San Giuseppe', + 'Hunenberg', + 'Khandpara', + 'Bieber', + 'Timezgana', + 'Sam Phran', + 'Yuquan', + '`Akko', + 'Ittikara', + 'Louveira', + 'Kalingiyam', + 'La Grande-Motte', + 'Maebara', + 'Billinghurst', + 'Bou Adel', + 'Leszno', + 'Inhumas', + 'Atoka', + 'Kerou', + 'Saint-Benoit', + 'Zhangzhou', + 'Belazao', + 'Senapparetti', + 'Cua', + 'Tangerang', + 'Zebbug', + 'Levanger', + 'Liminka', + 'Punceres', + 'Mavinpalli', + 'Jharsugra', + 'Hassan Abdal', + 'Karaburun', + 'Zazafotsy', + 'Simri Bakhriarpur', + 'Caprino Veronese', + 'Yorito', + 'Makaya', + 'Tenango de Doria', + 'Minamata', + 'Fujimino', + 'Vecchiano', + 'Tavas', + 'Punta Indio', + 'San Gregorio Atzompa', + 'Ambohimiarivo', + 'Hessisch Oldendorf', + 'Geretsried', + 'Calabozo', + 'Kara-Balta', + 'Pieta', + 'Grande Prairie', + 'Los Angeles', + 'Dingalan', + 'Potengi', + 'San Jose de Ocoa', + 'Suncheon', + 'Fornaka', + 'Rehti', + 'Bandixon', + 'Virapperumanallur', + 'North Lindenhurst', + 'Sainte-Julie', + 'Los Reyes de Salgado', + 'Pinamar', + 'Mayfield Heights', + 'Santa Apolonia', + 'Harpur Bhindi', + 'Campodarsego', + 'Urbana', + "Braine-l'Alleud", + 'Wukari', + 'Martahalli', + 'Leppavirta', + 'Kastel Stari', + 'Sansare', + 'Braganca Paulista', + 'Bridgeport', + 'Cecina', + 'Ossett', + 'Chepica', + 'Koratagere', + 'Muthuswamipuram', + 'Kamigori', + 'Tuchola', + 'Fukang', + 'Balanga', + 'Isola Capo Rizzuto', + 'Galmaarden', + 'Heinola', + 'Gioia Tauro', + 'Zelfana', + 'Quarai', + 'Frauenfeld', + 'Makole', + 'Puerto Lempira', + 'Brandenburg', + 'Kot Radha Kishan', + 'Armazem', + 'Mahaboboka', + 'Jingjiazhuang', + 'Ongole', + 'Magalhaes de Almeida', + 'Darat `Izzah', + 'Longtian', + 'Ahualulco de Mercado', + 'Alexander City', + 'Iwai', + 'Coolbaugh', + 'Khambhaliya', + 'Narayanavanam', + 'Littleton', + 'Ciudad Lerdo', + 'Martin Coronado', + 'Vialonga', + 'Hamminkeln', + 'Arrah', + 'Pianco', + 'Villa Elisa', + 'Tawaramoto', + 'Skien', + 'Santa Clara La Laguna', + 'Takad Sahel', + 'Giardini', + 'Barbosa Ferraz', + 'Brevnov', + 'Fuenlabrada', + 'Birhana', + 'Kaberamaido', + 'Siocon', + 'Loja', + 'Midori', + 'Sambhu Chak', 'Federacion', - 'Bassum', - 'Kruibeke', - 'Hueytown', - 'Kakkalapalle', - 'Whickham', - 'Beaver Dam', - 'Agourai', - 'Loxstedt', - 'Zvecan', - 'Berber', - 'Grangemouth', - 'Arani', - 'Sidi Ettiji', - 'Bogatynia', - 'Tawargeri', - 'Aracagi', + 'Masan', + 'Lousada', + 'Laguna Salada', + 'Pooler', + 'Geisenfeld', + 'Orlandia', + 'El Castillo de La Concepcion', + 'Koriyama', + 'Altagracia', + 'Minalin', + 'San Feliu de Llobregat', + 'Uithoorn', + 'Rivadavia', + 'Castello de Ampurias', + 'Zhur', + 'Greenock', + 'Criuleni', + 'Nangola', + 'Claymont', + 'Sihecun', + 'Palmers Green', + 'Guatica', + 'Mandaue City', + 'Pharkia', + 'Cambui', + 'Placerville', + 'Junin de los Andes', + 'Omachi', + 'Gaspar Hernandez', + 'Valinda', + 'Fort Walton Beach', + 'Arttuvattala', + 'Mahela', + 'Dowa', + 'Kelme', + 'Chippenham', + 'Metahara', + 'Marovantaza', + "Saint David's", + 'West Windsor', + 'Cleburne', + 'Itupiranga', + 'Trikarpur North', + 'Miyanaga', + 'Gandhari', + 'Tatarbunary', + 'Zholymbet', + 'Springwater', + 'Seekonk', + 'Groningen', + 'Chocaman', + 'Lianzhou', + 'Siggiewi', + 'Ig', + 'Sarh', + 'Al Hayy', + 'Chum Phae', + 'Meridjonou', + 'El Copey', + 'Salerno', + 'Antsampandrano', + 'Zahana', + 'Stuttgart', + 'Razan', + 'Hexiang', + 'North Merrick', + 'Hicksville', + 'Palmares Paulista', + 'Kalpi', + 'Sariyer', + 'Nandamuru', + 'Guidel', + 'Morinda', + 'Jinhe', + 'Yasinia', + 'Nova Friburgo', + 'Buriti Alegre', + 'Shahin Shahr', + 'Chivolo', + 'Gosforth', + 'Hunchun', + 'Gexianzhuang', + 'Mareno di Piave', + 'Montville', + 'Kikuyu', + 'Wauwatosa', + 'Dhalaa', + 'Villa del Carbon', + 'Tigbao', + 'Aidlingen', + 'Mekla', + 'Nieuwegein', + 'Geldern', + 'Pepillo Salcedo', + 'Belampalli', + 'Karakol', + 'Saint-Louis du Nord', + 'Bartabwa', + 'Zardab', + 'Kanakpur', + 'Dock Sur', + 'Todos Santos Cuchumatan', + 'Sunbat', + 'Matmata', + 'Le Passage', + 'Panr', + 'Galdacano', + 'Wa', + 'West Freehold', + 'Merville', + 'Sonderborg', + 'Corovode', + 'Tizgane', + 'Kadinhani', + 'Penalva', + 'Piqua', + 'Wenwu', + 'Castanuelas', + 'Jazan', + 'Nowe Miasto Lubawskie', + 'Velletri', + 'Cativa', + 'Niihama', + 'Carapebus', + 'Jai', + 'Sao Jose da Laje', + 'Southgate', + 'Ottaikkalmantapam', + 'Ladhuka', + 'Kulkent', + 'Mobetsu', + 'Pincourt', + 'Tagoloan', + 'Kiseljak', + 'Maryport', + 'Flores da Cunha', + 'Sao Jeronimo', + 'Ban Nong Han', + 'Kirk of Shotts', + 'Diyadin', + 'Uchti', + 'Marlboro Village', + 'El Consejo', + 'Dasraha Bhograjpur', + 'Hagenow', + 'Beniajan', + 'Halfway', + 'Jiming', + 'Antibes', + 'Manushmuria', + 'Nantucket', + 'La Mision', + 'Limbang', + 'Rubano', + 'Tchaourou', + 'Repatriacion', + 'Danyang', + 'Ad Duraykish', + 'Osterode', + 'Karvetnagar', + 'Secunda', + 'Kuhbanan', + 'Poissy', + 'Itupeva', + 'Liuhe', + 'New Smyrna Beach', + 'Okuta', + 'Shuangqiao', + 'Irati', + 'Lampa', + 'Gautampura', + 'Cacahoatan', + 'Mooirivier', + 'Spanaway', + 'Abu Hardub', + 'Bor', + 'Dingjiagouxiang', + 'Rehburg-Loccum', + 'Ambajogai', + 'Detmold', + 'Yuncheng', + 'Boyarka', + 'Eden', + 'Penne', + 'Barghat', + 'Ampahimanga', + 'Turkmenabat', + 'Zarqan', + 'Dover', + 'Sindirgi', + 'Panabo', + 'Holliston', + 'Tambolaka', + 'Ciudad Arce', + 'Nadbai', + 'Nova Era', + 'Bekodoka', + 'South Fayette', + 'Ampanavoana', + 'Mahbubabad', + 'Palkonda', + 'Alasehir', + 'Dongshicuo', + 'Uniondale', + 'Bhakua', + 'Damavand', + 'Kami-kawabe', + 'Deutschlandsberg', + 'Domahani', + 'Pallippatti', + 'Kaolack', + 'Bolhrad', + 'Murfreesboro', + 'Sankt Georgen im Schwarzwald', + 'Antanambe', + 'Macajuba', + 'Thies', + 'Tarlac City', + 'Taquaritinga', + 'City of Orange', + 'Glendora', + 'Tufanganj', + 'Claremore', + 'Zejtun', + 'Figueira da Foz', + 'Holmen', + 'Aiea', + 'Runkel', + 'Forbe Oroya', + 'Ondjiva', + 'Tosu', + 'Surinam', + 'Rahatgarh', + 'Winterswijk', + 'Sakiet ed Daier', + 'Kolonnawa', + 'Wawizaght', + 'Imisli', + 'Horokhiv', + 'Shenjiatun', + 'Lenguazaque', + 'Newington', + 'Lecheng', + 'Gamboma', + 'Manubolu', + 'Perumbalam', + 'Bougaribaya', + 'Dryden', + 'Kielce', + 'Edeleny', + 'Ouidah', + 'Comalapa', + 'Harrogate', + 'Qianwu', + 'Nguru', + 'South Daytona', + 'Corbin', + 'Abnub', + 'Saren', + 'Beydag', + 'Monthey', + 'Bonheiden', + 'August', + 'North Miami Beach', + 'Aulnay-sous-Bois', + 'Aaley', + 'Talne', + 'Kodungallur', + 'San Buenaventura', + 'Gerlingen', + 'West Earl', + 'Pacatu', + 'Hallein', + 'Nueva Ocotepeque', + 'Biassono', + 'Garfield Heights', + 'Motozintla', + 'Gerpinnes', + 'Mnasra', + 'Riohacha', + 'Etacheri', + 'Pudur', + "Sant'Antonio Abate", + 'Steinhagen', + 'Sfax', + 'San Miguel Chicaj', + 'El Congo', + 'Falimari', + 'Pinhal Novo', + 'Ystrad Mynach', + 'Wangen im Allgau', + 'Qazmalar', + 'Severinia', + 'Nonea', + 'Dargecit', + 'Sukumo', + 'Cittadella', + 'Yamba', + 'Sao Luis de Montes Belos', + 'Suleswaranpatti', + 'Abu Tisht', + 'Ploermel', + 'Arvika', + 'Warud', + 'Mazatlan Villa de Flores', + 'Inga', + 'Jaworzno', + 'Canalete', + 'Balayan', + 'Ankazomborona', + 'Nadimpalem', + 'Illintsi', + 'Laives', + 'Juchitan de Zaragoza', + 'Ponot', + 'Annan', + 'Fiorentino', + 'Lambarkiyine', + 'Linluo', + 'Neu-Anspach', + 'Rio Maria', + 'South Venice', + 'Moranbah', + 'North Haledon', + 'Orchard Park', + 'Pico Truncado', + 'Gomez Palacio', + 'I-n-Amenas', + 'Barreiros', + 'San Mateo', + 'Harran', + 'Toccoa', + 'Ghoradal', + 'Medgidia', + 'Roermond', + 'Madinat al Habbaniyah', + 'San Agustin Tlaxiaca', + 'Nakodar', + 'La Baneza', + 'Citrus Park', + 'Guttal', + 'Lovington', + 'Carahue', + 'Vicosa do Ceara', + 'Saitama', + 'Whistler', + 'Amjhera', + 'Rio Brilhante', + 'Mora', + 'I-n-Salah', + 'Sao Joaquim do Monte', + 'Huanian', + 'Alcalde Diaz', + 'Bijaynagar', + 'Lowton', + 'Anjahamarina', + 'Tohoue', + 'Birkenhead', + 'Ghogaon', + 'Kadachchinallur', + 'Lal-lo', + 'Colorado do Oeste', + 'Boukoumbe', + 'La Source', + 'Knittelfeld', + 'Guangping', + 'Torrington', + 'Yako', + 'Batesville', + 'Dhobipet', + 'Ain Kechera', + 'Prey Veng', + 'Webster Groves', + 'Huai Yot', + 'Thandewala', + 'Koksijde', + 'Vosselaar', + 'Ashtarak', + 'Timaru', + 'Myrtle Beach', 'Ban Na Sai', - 'Calera', - 'Khirhar', - 'Keynsham', - 'Barangka', - 'Itapiranga', - 'Shiraoi', - 'Lake Mary', - 'Ittiva', - 'Xiaolongtan', - 'Salitre', + 'Masbate', + 'Buloqboshi', + 'Trzebnica', + 'Biskra', + 'Sidi Bousber', + 'Jiangjiehe', + 'Qinhe', + 'Kunnur', + 'Palmerston North', + 'Kodanad', + 'Gulyam', + 'Gulou', + 'Fort Dodge', + "Mek'i", + 'Mount Olive', + 'Marco de Canavezes', + 'Ucuma', + 'Kucukkuyu', + 'Sendamaram', + 'Minacu', + 'Quezon City', + 'Caxias do Sul', + 'Banjarbaru', + 'Analamisampy', + 'Zhongwangzhuang', + 'Morroa', + 'Laghzawna', + 'Talakulam', + 'Pailin', + 'Clearfield', + 'Soumpi', + 'Drochtersen', + 'Lourinha', + 'Zerbst', + 'Beohari', + 'Marina di Carrara', + 'Sherpur Khurd', + 'Ploufragan', + 'Sucat', + 'Nadikude', + 'Live Oak', + 'Puerto Casado', + 'Mortara', + 'Beichengqu', + 'Iwanuma', + 'Melle', + 'Guney', + 'Geneva', + 'Whitley Bay', + 'Chintalavadi', + 'Buwama', + 'Midlothian', + 'Guatire', + 'Baghauni', + 'Chiang Mai', + 'East Ham', + 'Lenyenye', + 'Shirakawa-tsuda', + 'Dibulla', + 'Nocera Superiore', + 'Paispamba', + 'Puerto Princesa', + 'Ban Ton Thong Chai', + 'Markham', + 'Bileh Savar', + 'Timmapuram', + 'Kone', + 'Tchindjendje', + 'Bir el Djir', + 'Saldus', + 'Coalville', + 'Waterville', + 'North Canton', + 'Dalandzadgad', + 'New Franklin', + 'Presidencia de la Plaza', + "M'Chedallah", + 'Heves', + 'Brodnica', + 'Kicevo', + 'Niaogho', + 'Sao Pedro', + 'Connahs Quay', + 'Renningen', + 'Kaiwen', + 'Frejus', + 'Nobeji', + 'Le Bardo', + 'North Fair Oaks', + 'Metzingen', + 'Thonex', + 'Argos Orestiko', + 'Erdington', + 'Takasaki', + 'Storm Lake', + 'Ronnenberg', + 'Freetown', + 'Neuenburg', + 'Pinotepa', + 'Wood Buffalo', + 'Usme', + 'Kitaakita', + 'Nagykoros', + 'Midleton', + 'South Ockendon', + 'Brahmana Periya Agraharam', + 'Mantua', + 'Hayange', + 'Qarshi', + 'Komono', + 'Yasuj', + 'Cuartero', + 'Fuding', + 'Oberderdingen', + 'Consaca', + 'Calatrava', + 'San Vicente de Baracaldo', + 'Yakakent', + 'Sowan', + 'Major Isidoro', + 'Dongou', + 'Monza', + 'Millbrae', + 'Panshi', + 'Roquebrune-sur-Argens', + 'Satravada', + 'Visby', + 'Iseyin', + 'Kesarimangalam', + 'Greensburg', + 'Nova Paka', + 'Butterworth', + 'Fort Liberte', + 'Hongseong', + 'Anand', + 'Kalamasseri', + 'Kazhukambalam', + 'Beian', + 'Derik', + 'Malalag', + 'Prakhon Chai', + 'Laje', + 'Upper Uwchlan', + 'Sun Prairie', + 'Maghaghah', + 'Al Qaryatayn', + 'Ghonchi', + 'Masabdisa', + 'Luan Chau', + 'Czersk Pomorski', + 'Poggibonsi', + 'Privas', + 'Sa`adat Shahr', + 'Divinolandia', + 'Frontino', + 'Nurota', + 'Kpandae', + 'Kamitonda', + 'Molln', + 'Rogozno', + 'Kavital', + 'Sarlat-la-Caneda', + 'Reserva', + 'Ankazotsifantatra', + 'Shiraoka', + 'Baisha', + 'Sodertalje', + 'Sao Mateus do Sul', + 'Cimahi', + 'Nirakpurpali', + 'Baluntaicun', + 'Aloran', + 'Usmat Shaharchasi', + 'Jalpura', + 'Prairieville', + 'Neuenburg am Rhein', + 'Pangzawl', + 'Oshkosh', + 'Kalaidasht', + 'El Milia', + 'Williams Lake', + 'Lillebonne', + 'Kalyves Polygyrou', + 'Nova Europa', + 'Kawit', + 'Grande Saline', + 'Shuili', + 'Khanda', + 'Sa`idi', + 'Mount Eliza', + 'Queensferry', + 'Gibara', + 'Bathurst', + 'Itri', + 'Cosquin', + 'Dakovo', + 'Jimbolia', + 'Parsad', + 'Tartar', + 'Santarem', + 'Ingenio', + 'Az Za`ayin', + 'Avola', + 'Campiernagar', + 'Hioki', + 'Gaizhou', + 'Amancio', + 'Fort Salonga', + 'Ramhormoz', + 'Es Senia', + 'Konosu', + 'Tallaght', + 'San Giovanni in Marignano', + 'Al Mahallah al Kubra', + 'Nashville', + 'Nkongsamba', + 'Cazenga', + 'Teutonia', + 'Asthanwan', + 'Genappe', + 'Neuenstadt am Kocher', + 'Grammichele', + 'Latteri', + 'Aragarcas', + 'Thevur', + 'Yaglidere', + 'Radomir', + 'Bearsden', + 'Novo Airao', + 'Bierun Stary', + 'Lagunia Surajkanth', + 'Dengtangcun', + 'Schwechat', + 'Kalkar', + 'Cukurca', + 'Xiedian', + 'Teramo', + 'Yonago', + 'Samakhiali', + 'Pemba', + 'Rancho Palos Verdes', + 'Barclayville', + 'Bridgeton', + 'Eslov', + 'Shahpur', + 'Mandalgarh', + 'Nordstemmen', + 'Portlethen', + 'Opmeer', + 'Gemona del Friuli', + 'Askim', + 'Sidi Moussa', + 'Josefina', + 'Oskarshamn', + 'Kaujalgi', + 'Vicente Lopez', + 'Mandasa', + 'Bordj Menaiel', + 'Melgaco', + 'Beaufort', + 'Catskill', + 'Madaba', + 'Savoy', + 'Rahta', + 'Chiran', + 'London Grove', + 'Malov', + 'Serra Caiada', + 'Arico el Nuevo', + 'Dongping', + 'Elumalai', + 'Montelimar', + 'Weingarten', + 'Talbahat', + 'Bima', + 'Frouzins', + 'Kanur', + 'Beavercreek', + 'Vange', + 'Tianwei', + 'Westbury', + 'Donduseni', + 'Teotepeque', + 'Felidhoo', + 'McCordsville', + 'Catamarca', + 'Gurpinar', + 'Matola', + 'Lezajsk', + 'Chinna Gollapalem', + 'Fervedouro', + 'Ambodihara', + 'Bagalkot', + 'Quillabamba', + 'Boundiali', + 'Ankara', + 'Montfoort', + 'Union', + 'Pulheim', + 'Itako', + 'Kampong Tunah Jambu', + 'Bandar `Abbas', + 'Ghotki', + 'Phek', + 'Calabar', + 'Taft', + 'Nong Bua Lamphu', + 'Yenkuvarigudem', + 'Sebeta', + 'Freeport', + 'Gehrden', + 'Doctor Phillips', + 'Leers', + 'Mannedorf', + 'Linz', + 'Carvin', + 'Zhengdong', + 'Itabera', + 'Fujita', + 'Fazakerley', + 'Rillieux-la-Pape', + 'Xikou', + 'Grain Valley', + 'Chia', + 'Taiobeiras', + 'Kamianske', + 'Novyi Svit', + 'Pasni', + 'Nawanagar', + 'Zwickau', + 'Albstadt', + 'Tawau', + 'Sandnes', + 'Hilsa', + 'Trollhattan', + 'Le Mee-sur-Seine', + 'Villa del Rosario', + 'Barlinek', + 'Dacheng', + 'Ardestan', + 'Morbegno', + 'Bujaru', + 'Oued el Abtal', + 'Catio', + 'Mabalacat', + 'Venkidanga', + 'Leshou', + 'Makedonska Kamenica', + 'Pipra Latif', + 'Lae', + 'Myeik', + 'Lisburn', + 'Curralinho', + 'Cunen', + 'Wanparti', + 'Marica', + 'Muscle Shoals', + 'Nykobing Mors', + 'Rwamagana', + "Jin'e", + 'Quitandinha', + 'Nilufer', + 'Camisano Vicentino', + 'Masera di Padova', + 'Brockville', + 'Ashiya', + 'Velenje', + 'Chencha', + 'Pongotan', + 'Rogaska Slatina', + 'Barasat', + 'Lognes', + "N'Goussa", + 'Bordeaux', + 'Huaquillas', + 'Puvalur', + 'Pasraha', + 'Belladere', + 'Tonghae', + 'Montebelluna', + 'Nihonmatsu', + 'Mariano Roque Alonso', + 'Doura', + 'Xiangxiang', + 'Mang La', + 'Dumjor', + 'Jedrzejow', + 'Butler', + 'Rebola', + 'Douar Hammadi', + 'Sala Consilina', + 'Alassio', + 'Fenoarivobe', + 'Pueblo Rico', + 'Bramhapuri', + 'Mejillones', + 'Arcore', + 'Wiefelstede', + 'Wick', + 'Porsa', + 'Urdinarrain', + 'Seabra', + 'Pompton Plains', + 'Wells', + 'Paete', + 'Thorne', + 'Moss Vale', + 'Kortrijk', + 'San Giovanni in Fiore', + 'Dhar', + 'Bonneuil-sur-Marne', + 'Beregadougou', + 'Khandaich', + 'Arrigorriaga', + 'Glossop', + 'Neusass', + 'Olivenza', + 'Chaodongcun', + 'Lichtenburg', + 'Perupalem', + 'Pulimathu', + 'Buharkent', + 'Lancing', + 'Arendal', + 'Mpessoba', + 'Massillon', + 'Lordelo do Ouro', + 'Tlaltenango de Sanchez Roman', + 'Berkley', + 'Tracunhaem', + 'Avitanallur', + 'Livron-sur-Drome', + 'Badoc', + 'Salman Bak', + 'Vaihingen an der Enz', + 'Las Torres de Cotillas', + 'Claxton Bay', + 'Popasna', + 'Astana', + 'Fairhope', + 'Barras', + 'Acala', + 'Balti', + 'San Bartolome Jocotenango', + 'Capalonga', + 'Probistip', + 'Candoi', + 'Dapa', + 'Yei', + 'Roznov pod Radhostem', + "Oulad 'Azzouz", + 'Sherobod', + 'Andondabe', + 'Gedera', + 'Mandi Dabwali', + 'Le Blanc-Mesnil', + 'Elambalur', + 'Altlandsberg', + 'Chouafaa', + 'Sao Jose da Tapera', + 'Loimaa', + 'Concepcion', + 'Dhrol', + 'Kulpahar', + 'Mililani Town', + 'Goondiwindi', + 'Varzea Nova', + 'Sampgaon', + 'Dibraghani', + 'Wiwili', + 'Elk Grove', + 'Iskenderun', + 'Tandarampattu', + 'Bani Mazar', + 'Parramos', + 'Northwood', + 'Charabidya', + 'Villa Sandino', + 'Karsiyang', + 'Loughborough', + 'Tetari', + 'Nigde', + 'Yarmouth', + 'Bonen', + 'Monserrato', + 'Echirolles', + 'Iglesias', + 'Senges', + 'Tacambaro de Codallos', + 'Zwolle', + 'Baradero', + 'Belize City', + 'Ponmundam', + 'Vaterstetten', + 'Tiddas', + 'Uracoa', + 'Nandigaon', + 'Greven', + 'Vila Franca do Campo', + 'Dhumnagar', + 'Yiwu', + 'Casoria', + 'Tovuz', + 'Yakossi', + 'Domont', + 'Bai Chay', + 'Grimsby', + 'Manzini', + 'Tiszaujvaros', + 'Sapele', + 'Lihuzhuang', + 'Michalovce', + 'Tanamarina', + 'Apartado', + 'Albu Kamal', + 'Griffith', + 'Zhashkiv', + 'Oroco', + 'Falkirk', + 'Derassi', + 'Vipava', + 'Berriane', + 'Kiskunhalas', + 'Gradiska', + 'Doesburg', + 'Jamestown', + 'Kingston upon Hull', + 'Djibloho', + 'Sachin', + '`Aliabad-e Katul', + 'Bouanri', + 'Chandpur', + 'Godalming', + 'Toamasina', + 'Basarh', + 'Taviano', + 'Apricena', + 'Takayama', + 'Nossen', + 'Hashima', + 'Staines-upon-Thames', + 'Lachen', + 'Ecclesfield', + 'Kiraz', + 'Cercado Abajo', + 'Mangalpur Gudaria', + 'Anolaima', + 'Ban Mae Chedi', + 'Namur', + 'Bragadiru', + 'Cusano Milanino', + 'Shirosato', + 'Khilchipur', + 'Lymington', + 'Kuala Kurun', + 'Santa Cruz Balanya', + 'North Babylon', + 'Thogaduru', + 'Shirin', + 'El Ghourdane', + 'Qanliko`l', + 'Jangalapalli', + 'Mariakerke', + 'Kukkundur', + 'Coyula', + 'Meghauna', + 'Ain el Hadjar', + 'Sen Monorom', + 'Madakasira', + 'Shepton Mallet', + 'Biggleswade', + 'Llallagua', + 'Birzai', + 'Beneditinos', + "Kattaqo'rg'on Shahri", + 'La Crucecita', + 'Tall Abyad', + 'Ar Rahmaniyah', + 'Milnrow', + 'Shasta Lake', + 'San Giovanni Lupatoto', + 'Lovejoy', + 'Fo-Boure', + 'Konigswinter', + 'Ironton', + 'Sabirabad', + 'Sai Wan Ho', + 'Ueda', + 'Yinchengpu', + 'Miandrarivo', + 'Horley', + 'Djidian', + 'Koundara', + 'Dereli', + 'Sidi Merouane', + 'Alwal', + 'Debre Tabor', + 'Beltsville', + 'San Francisco de los Romo', + 'Singkawang', + 'Kryvyi Rih', + 'Cisnadie', + 'Altotting', + 'Cape Canaveral', + 'Mitsuke', + 'Baroueli', + 'Abrandabad-e Shahediyeh', + 'Merkanam', + 'Huazalingo', + "L'Hay-les-Roses", + 'Riorges', + 'Serra Dourada', + 'Woensdrecht', + 'Castelli Calepio', + 'Kiruna', + 'Fatima', + 'Bensonville', + 'Weissenhorn', + 'San Jose El Idolo', + 'Racconigi', + 'Lluchmayor', + 'Inabe', + 'Amgachia', + 'Aswapuram', + 'Wilmette', + 'Zwonitz', + 'Haji Shah', + 'Nava', + 'El Cerrito', + 'Tabira', + 'Treuchtlingen', + 'Ponte da Barca', + 'Poitiers', + 'Watari', + 'As Safirah', + 'Handsworth', + 'Muniz Freire', + 'God', + 'Nova Crixas', + 'Tujg', + 'Jakobstad', + 'San Bartolo Tutotepec', + 'Kennewick', + 'Baianopolis', + 'Las Navas', + 'Paracelis', + 'Moniquira', + 'Porumamilla', + 'Arroyo Seco', + 'Bom Sucesso', + 'West Haven', + 'Kinik', + 'Nangavalli', + 'Draksharama', + 'Wells Branch', + 'Shumanay', + 'Zlocieniec', + 'Monte di Procida', + 'Novodnistrovsk', + 'Chitungwiza', + 'San Pedro de Macoris', + 'Mombin Crochu', + 'Dumbarton', + 'Ostersund', + 'Le Grand-Saconnex', + 'Uijeongbu', + 'Lomianki', + 'Piazza Armerina', + 'Butebo', + 'Kirsehir', + 'Huamachuco', + 'Ismailpur', + 'North Amityville', + 'Lanquin', + 'Rio Negrinho', + 'Ukrainsk', + 'Rockingham', + 'Zarasai', + 'Terneuzen', + 'Musiri', + 'Badanahatti', + 'Edayikunnam', + 'Caridade', + 'Jensen Beach', + 'Kuriyama', + 'Antarvedi', + 'Amos', + 'Byatarayanpur', + 'Sao Domingos do Maranhao', + 'Tarutung', + 'Worthington', + 'Fujiidera', + 'Gerd Faramarz Shahediyeh', + 'Buchach', + 'Igarape', + 'Lincolnton', + 'Ameskroud', + 'Bad Oldesloe', + 'Yorii', + 'Juticalpa', + 'Lakshmaneswaram', + 'Catanduvas', + 'Ryhope', + 'Wesselsbron', + 'As Suwayhirah as Sahil', + 'Selvazzano Dentro', + 'Tanxia', + 'East Hampton', + 'Agua Fria', + 'Garanhuns', + 'Saint-Lazare', + 'Char Fasson', + 'Malanguan', + 'Waco', + 'Kanaya', + 'Totolapan', + 'Bloemhof', + 'Tokkavadi', + 'Nogent-sur-Marne', + 'Zhuolan', + 'Nandyalampeta', + 'Invercargill', + 'Trabia', + 'Boromo', + 'Blackfalds', + 'General Trias', + 'Kalakkadu', + 'Ellesmere Port', + 'Gampola', + 'Macclesfield', + 'Bachhauta', + 'Unzen', + 'Balbalan', + 'Maimon', + 'Minanba', + 'Andalucia', + 'Baclaran', + 'Sumqayit', + 'Amargosa', + 'Ghatawan', + 'Alajuela', + 'Maroaloka', + 'Bongandanga', + 'Papagos', + 'Bairia', + 'Ghagga', + 'Lillehammer', + 'Iizuna', + 'Kifosso', + 'Crailsheim', + 'Zvornik', + 'Devgadh Bariya', + 'Imola', + 'Estreito', + 'Haga', + 'Toyoyama', + 'Abeokuta', + 'Laoang', + 'West Seneca', + 'Kharhial', + 'Menzel Temime', + 'Jankinagar', + 'El Carmen de Chucuri', + 'Huari', + 'Maua', + 'Pekalongan', + 'Coltauco', + 'Carmen de Apicala', + 'Cacador', + 'Andohajango', + 'Yangiqo`rg`on', + 'Yesagyo', + 'Sahuayo de Morelos', + 'Nijmegen', + 'West Whittier-Los Nietos', + 'Santa Rosa del Sur', + 'Tharial', + 'Boves', + 'Bodhan', + 'Bagula', + 'Gobabis', + 'Ouahigouya', + 'Maubeuge', + 'Eldorado', + 'Bakhtawarpur', + 'Ternivka', + 'Kasserine', + 'Sayula de Aleman', + 'Fallanden', + 'Fonseca', + 'Lipari', + 'Bou Djeniba', + 'Jagraon', + 'Parrita', + 'Erongaricuaro', + 'Mizumaki', + 'Dieramana', + 'Moyamba', + 'La Linea de la Concepcion', + 'Kiffa', + 'Silleda', + 'Port Said', + 'Gross-Gerau', + 'Ilakatra', + 'Wooster', + 'Sicasica', + 'Eureka', + 'Dodworth', + 'Hereford', + '`Amran', + "La Chapelle d'Armentieres", + 'Pelsall', + 'Borshchiv', + 'Kaiyuan', + 'Pandag', + 'Mortagua', + 'Errachidia', + 'Gaya', + 'Dietzenbach', + 'An Najaf', + 'Dungarpur', + 'Oued Seguin', + 'Sampaloc', + 'Traralgon', + 'Andalatanosy', + 'Gillingham', + 'Mudon', + 'Deville-les-Rouen', + 'Xicheng', + 'Afonso Claudio', + 'Daanbantayan', + 'Horqueta', + 'Bahraigh', + 'North Brunswick', + 'Marotsiraka', + 'Ribnita', + 'North Royalton', + 'Kalemie', + 'El Oro de Hidalgo', + 'Woods Cross', + 'Tsiamalao', + 'Shankarampet', + 'Tecpan de Galeana', + 'Humlebaek', + 'Phatthalung', + 'Meddappakkam', + 'Raha', + 'Sensuntepeque', + 'Paidiipalli', + 'Itatira', + 'Siddapur', + 'Catemaco', + 'Joue-les-Tours', + 'Amal', + 'Bara Belun', + 'Hidalgotitlan', + 'Algeciras', + 'Carbonita', + 'Kulrian', + 'Kasaishi', + 'Pasir Gudang', + 'Yingchuan', + 'Owo', + 'Saanich', + 'Altos', + 'Dana Point', + 'Morro da Fumaca', + 'Copparo', + 'Gerze', + 'Werneck', + 'Athis-Mons', + 'Yanam', + 'Palmilla', + 'Port St. John', + 'Kapay', + 'Pottipuram', + 'Vaniyambadi', 'Glenmont', - 'Millbrook', - 'Mullanwala', - 'Tadaoka-higashi', - 'Seeheim-Jugenheim', - 'Red Wing', - 'Anisoc', - 'Tantega', - 'Tiahounkossi', - 'Medicina', - 'Epitacio Huerta', - 'Cleckheaton', - 'Pratteln', - 'Micoud', - 'Bull Run', - 'Brod', - 'Douar Tabouda', - 'El Escorial', - 'La Algaba', - 'Valu lui Traian', - 'Itororo', - 'Shpola', - 'Piquet Carneiro', - 'Ad Dis', - 'Banovce nad Bebravou', + 'Ocara', + 'Huasuo', + 'Raver', + 'Manouba', + 'Volklingen', + 'Calcado', + 'Kattiyeri', + 'West Boldon', + 'Asaita', + 'Maradah', + 'Nagasu', + 'Mundelein', + 'Boerne', + 'Kuji', + 'Voi', + 'Hafnarfjordhur', + 'Huatabampo', + 'Juliaca', + 'Parkland', + 'Kedougou', + 'Suqian', + 'Caicedonia', + 'Dhing', + 'Azambuja', + 'Sekimachi', + 'Jasauli', + 'Benxi', + 'Ifanhim', + 'Sparti', + 'Reichelsheim', + 'Beni Khalled', + 'Salkhua', + 'Rotenburg an der Fulda', + 'Cheticheri', + 'Dorking', + 'Al Majma`ah', + 'Ghajnsielem', + 'Yomou', + 'Monsummano', + 'Richton Park', + 'Capbreton', + 'Curitibanos', + 'East Brandywine', + 'Karmana', + 'As Salamiyah', + 'Pallippurattuseri', + 'Mareeba', + 'Port Sudan', + 'Jumilla', + 'Schleswig', + 'Cedar Lake', + 'Richmond West', + 'Puqi', + 'Sbeitla', + 'Vaddapalli', + 'River Grove', + 'Northbridge', + 'Erkoklu', + 'Miliana', + 'Autun', + 'Lohja', + 'Ixtaczoquitlan', + 'Tczew', + "Shaqra'", + 'Djugu', + "Ben N'Choud", + 'East Kilbride', + 'Ciudad Melchor Muzquiz', + 'Tezpur', + 'Aldershot', + 'Tankara', + 'Honganur', + 'Nikshahr', + 'Jeffersonville', + 'Portage', + 'Waremme', + 'Bacuag', + 'Bhajani', + 'Kutno', + 'Kinston', + 'Macabebe', + 'Greater Napanee', + 'Isla Vista', + 'Santona', + 'Rimavska Sobota', + 'Sultanganj', + 'Mittweida', + 'Humayingcun', + 'Buon Ma Thuot', + 'Meaux', + 'Beibu', + 'La Vergne', + 'Warri', + 'Huaibaijie', + 'Yasica Arriba', + 'Zayda', + 'East Whittier', + 'Wasquehal', + 'Elkton', + 'Pasupatikovil', + 'Leuna', + 'Jamtara', + 'Baildon', + 'Lobo', + 'Karor', + 'Havsa', + 'Puente de Piedra', + 'Santana do Ipanema', + 'Strombeek-Bever', + 'Egg', + 'Charter Oak', + 'Romit', + 'Sevenoaks', + 'Toshima', + 'Lashio', + 'Tocina', + 'Phu My', + 'El Fula', + 'Dimona', 'Leopoldshohe', - 'Wurzen', - 'Clearlake', - 'Mariestad', - 'Sedan', - 'Bargur', - 'Porec', - 'Zirara', - 'Ceadir-Lunga', - 'Noordwijkerhout', - 'Shek Wai Kok', - 'Khaniadhana', - 'Ibipeba', - 'Mangueirinha', - 'Marienberg', - 'Reinheim', - 'Lomas de Sargentillo', - 'Getulio Vargas', - 'Morton', - 'Kaatsheuvel', - 'Macetown', - 'Burbaliq', - 'Dilijan', - 'The Mumbles', - 'Pannaipuram', - 'Tukums', - 'Mauguio', - 'Three Lakes', - 'Rio Linda', - 'Saint-Jean-de-la-Ruelle', - 'San Juan Bautista', - 'Soumpi', - 'Wailuku', - 'Bijni', - 'Puerto El Triunfo', - 'Buritama', - 'Cidreira', - "N'Goussa", - 'Country Club Hills', - 'Lask', - 'Ilkhchi', - 'Ilkhechi', - 'La Sierpe', - 'Mohan Eghu', - 'Ippy', - 'San Giovanni Valdarno', - 'Heumen', - 'Barkot', - 'Pirque', - 'Eppelborn', - 'Miyazu', - 'Tongluo', - 'Paragaticherla', - 'Humble', - 'Menomonie', - 'Lakhipur', - 'Bhai Rupa', - 'Placido de Castro', - 'Mensora', - 'Cabaceiras do Paraguacu', - 'Guaymate', - 'Slany', - 'Itaquitinga', - 'Domchanch', - 'Indiaroba', - 'Coaraci', - 'Santa Maria das Barreiras', - 'Ramon Santana', - 'Honefoss', - 'West Richland', - 'Middelfart', - 'Tichi', - 'Sujina', - 'Regenstauf', - 'Cattolica', - 'Wentang', - 'Raunheim', - 'Kade', - 'Odumase', - 'Tamallalt', - 'Bogucice', - 'Parali', - 'Mangrauni', - 'Segbwema', - 'Marly-le-Roi', - 'Vero Beach', - 'Ahmetli', - 'Ledeberg', - 'Liangyi', - 'Ban Cho Ho', - 'Rentachintala', - 'Thi Tran Ngai Giao', - 'Hovelhof', - 'Brackenheim', - 'Mapiri', - 'Santa Maria Petapa', - 'Puerto Pilon', - 'Pedregulho', - 'Gussago', - 'Horodok', - 'Torre Maggiore', - 'Sunagawa', - 'Caiaponia', - 'Cassano al Ionio', - 'Thompson', - 'Ciudad Guadalupe Victoria', - 'Haji Shah', - 'Berezan', - 'Langrucun', - 'Espartinas', - "Sant'Elpidio a Mare", - 'Chinde', - 'Al Ghat', - 'Qarqin', - 'Qusar', - 'Cowley', - 'Pilappulli', - 'Mudakkiraye', - 'East Highland Park', - 'Amba Icharua', - 'Alpignano', - 'Ukiah', - 'Slubice', - 'Fleron', - 'Shintomi', - 'Adelfia', - 'Zapotlan de Juarez', - 'Jinjicun', - 'Jinji', - 'Tafresh', - 'Hebburn', - 'Linbian', - 'Ashby de la Zouch', - 'Milanowek', - 'Ham Lake', - 'Chorbogh', - 'Jasper', - 'Grimari', - 'Bobangui', - 'Kalundborg', - 'Rasivarai Tottam', - 'Reggello', - 'Antanambao Mahatsara', - 'Ervadi', - 'Braniewo', - 'Rajbalhai', - 'Hillcrest Heights', - 'Sabotsy', - 'Ban Lam Narai', - 'Enfield Lock', - 'Oyodo', - 'Fairburn', - 'Escoublac', - 'Mifune', - 'Dighaun', - 'Ujre', - 'Ban Nong Han', - 'Kirchhain', - 'Dahibhat Madhopur', - 'Loma Plata', - 'Kilwinning', - 'Chopadandi', - 'Mohanur', - 'San Casciano in Val di Pesa', - 'Lake Wales', - 'Fillmore', - 'Les Herbiers', - 'Ojus', - 'Wardenburg', - 'Nanbu', - 'Tohoku', - 'Sakardih', - 'Encruzilhada', - 'Churriana de la Vega', - 'Glenn Heights', - 'Albemarle', - 'Katosi', - 'Nakanoto', - 'Pianco', - 'Charqueada', - 'Ciney', - 'Cayetano Germosen', - 'Bordj Mokhtar', - 'Edmundston', - 'Cloverly', - 'Hannut', - 'Gurh', - 'Lufeng', + 'Marungur', + 'Goleniow', + 'Ouangani', + 'Dumalinao', + 'Sulz am Neckar', + 'Colchester', + 'Tarin Kot', + 'Bhairahawa', + 'Jaguaretama', + 'Shin', + "Pallazzolo sull'Oglio", 'Rajnagar', - 'Auburndale', - 'Pupiales', - 'Altena', - 'Rawa Mazowiecka', - 'Bilohirsk', - 'Vedelago', - 'Gasparillo', - 'Neopolis', - 'Bykhaw', - 'Boshruyeh', - 'Pearl River', - 'Pelhrimov', - 'Kierspe', - 'Peer', - 'Adjahome', - 'Batangafo', - 'Goulmima', - 'Curacautin', - 'Nilaiyur', - 'Spanish Springs', - 'Hilltown', - 'Westbury', - 'Lugu', - 'Cajari', - 'Hanover', - 'Uhersky Brod', - 'Petersberg', - 'Islam Qal`ah', - 'Portachuelo', - 'Baro', - 'Dyer', - 'Pudu', - 'Poing', - 'Raikal', - 'Mastchoh', - 'Ntungamo', - 'Las Cabezas de San Juan', - 'Pocking', - 'Dentsville', - 'Bosobolo', - 'Toro', - 'Pamiers', - 'Hatti', - 'Mahesh Khunt', - 'Passa Quatro', - 'Kastoria', - 'Freienbach', - 'Kesath', - 'Faxinal', - 'Gokavaram', - 'Tahlequah', - 'Outat Oulad Al Haj', - 'Poco Fundo', - 'Nova Resende', - 'Hollins', - 'Libiaz', - 'Karema', - 'Bou Hadjar', - 'Stone', - 'Khargapur', - 'Khirpai', - 'Puan', - 'Zhongzai', - 'Radford', - 'Taohongpozhen', - 'Malnate', - 'Divrigi', - 'Caridade', - 'Panukulan', - 'Pasaquina', - 'Brakel', - 'Hude', - 'Aki', - 'Moreau', - 'Angara-Debou', - 'Kingsborough', - 'Zitorada', - 'Kirchlengern', - 'Barra de Santo Antonio', - 'Straelen', - 'Denby Dale', - 'Phirangipuram', - 'Erba', - 'Guben', - 'Ubrique', - 'Sebt Ait Saghiouchen', - 'East Longmeadow', - 'Juchique de Ferrer', - 'Arteche', - 'Bagnacavallo', - 'Fairview Heights', - 'Usgao', - 'Nunna', - 'Mahalandi', - 'Chettinayakkanpatti', - 'Cosautlan', - 'Jambalo', - 'Sulzbach', - 'Nova Olimpia', - 'North Arlington', - 'Rolleston', - 'Barnia', - 'Moussoro', - 'Chinacota', - 'Wemmel', - 'Halver', - 'Ban Thung Tam Sao', - 'Galivedu', - 'Kakching', - 'Grossostheim', - 'Arenys de Mar', - 'Huong Canh', - 'Bad Essen', - 'Novoukrainka', - 'Kargil', - 'Grosse Pointe Woods', - 'Vadugappatti', - 'Villa San Jose', - 'Piru', - 'Carsibasi', - 'La Falda', - 'Ouled Chebel', - 'Crawfordsville', - 'Sahatavy', - 'Muscle Shoals', - 'Erwitte', - 'Baipingshan', - 'Mount Dora', - 'Westport', - 'Sunnyside', - 'Sananduva', - 'Shuzenji', - 'Bree', - 'Yoshinogari', - 'Elsen', - 'Bandar Murcaayo', - 'Guelendeng', - 'Srbobran', - 'Wallisellen', - 'Poplar Bluff', - 'Yuvileine', - 'Xianxi', - 'Changji', - 'Khunti Dhanaili', - 'Northbridge', - 'Bargteheide', - 'Schmelz', - 'Moroto', - 'Lyantonde', - 'Leini', - 'Birstall', - 'Noniya', - 'Umbertide', - 'Fort Drum', - 'Shuili', - 'Tremedal', - 'Shahriston', - 'Kodala', - 'Merchtem', - 'Arachchalur', - 'Sohtha', - 'Malhipur', - 'Bacuri', - "'Ayn Bni Mathar", - 'Acarape', - 'Barharwa Kalan', - 'Welby', - 'Sao Francisco do Guapore', - 'Birsinghpur', - 'Wiefelstede', - 'Dungannon', - 'Colle Salvetti', - 'Yorkton', - 'Zumarraga', - 'Raposos', - 'Kabo', - 'Omalur', - 'Center Point', - 'Carcarana', - 'Utinga', - 'Domoni', - 'Kassorola', - 'Nawnghkio', - 'Berriche', - 'Ripon', - 'Madukkur', - 'Ivanava', - 'Sabana de La Mar', - 'Nobsa', - 'General Villegas', - 'Martinsicuro', - 'Al Lataminah', - 'San Antonio Oeste', - 'Acahay', - 'Momil', - 'Brus', - 'Yotoco', - 'Taishacho-kizukikita', - 'Oyten', - 'Wendlingen am Neckar', - 'Kasumi', - 'Antsahanoro', - 'Goundam', - 'Radzionkow Nowy', - 'Ispica', - 'Bad Bentheim', - 'Naama', - 'Ambalabe', - 'Llanquihue', - 'Benjamin Aceval', - 'Montalvo', - 'Eghezee', - 'Bikou', - 'Az Zaydiyah', - 'Jalalpur', - 'Glen Allen', - 'Carhue', - 'Santomera', - 'Ransiki', - 'Targu Secuiesc', - 'Manamelkudi', - 'Balasamudram', - 'Parkway', - 'Khirbat Ghazalah', - 'Longchang', - 'Sparti', - 'Stepney', - 'Massakory', - 'Mukhtarpur Salkani', - 'Fiano Romano', - 'Artesia', - 'Garou', - 'Tadikalapudi', - 'San Martino Buon Albergo', - 'Chickasha', - 'Opa-locka', - 'Kunzelsau', - 'South Middleton', - 'El Penol', - 'Giaveno', - 'Oteapan', - 'Orimattila', + 'Massi', + 'Redlynch', + 'Badin', + 'Paredes de Coura', + 'Malambo', + 'Abjij', + 'Bekasi', + 'Shaomi', + 'Salzano', + 'Harlow', + 'Flower Hill', + 'Soasio', + 'Oakton', + 'Lukula', + 'Garhakota', + 'Monteforte Irpino', + 'Shamsabad', + 'Marsala', + 'Lauri', + 'Lala', + 'Siniscola', + 'Huixtla', + 'Taxisco', + 'Pesaro', + 'Khapalu', + 'Oyster Bay', + 'Ivanhoe', + 'Xai-Xai', + 'Medulla', + 'Naini', + 'Santa Cruz del Quiche', + 'Saint-Gratien', + 'Sante Bennur', + 'Al Brouj', + 'Raje', + 'Perladka', + 'Ban Laem Chabang', + 'Gora', + 'Monitos', + 'Panchanandapur', + 'Pandacan', + 'Surbiton', + 'Sandy', + 'Wittenheim', + 'Gujranwala', + 'Zaria', + 'Hirayama', + 'Neyveli', + 'Guane', + 'Oak Forest', + 'Suzhou', + 'Tulle', + 'Prantij', + 'Rocca di Papa', + 'Tielt', + 'Bleicherode', + 'Ponte San Pietro', + "'Ain el Turk", + 'Bagou', + 'Taragi', + 'Ukal', + 'Ruy Barbosa', + 'Siroki Brijeg', + 'Pabellon de Arteaga', + 'Granite City', + 'Ait Majdane', + 'Hirehaluhosahalli', + 'Pinabacdao', + 'Kawa', + 'Phaltan', + 'Piombino Dese', + 'Belmopan', + 'Kodad', + 'Bozova', + 'Quibala', + 'Nakur', + 'Berkovitsa', + 'Chiredzi', + 'Sanmenxia', + 'Bugdayli', + 'Nersingen', 'Palma Campania', - 'Yunshan', - 'Neratovice', - 'Turgutalp', - 'Oyamazaki', - 'Freiberg am Neckar', - 'Hermitage', - 'Kabugao', - 'Cotorra', - 'Ikast', - 'Hajdunanas', - 'Vitthalapuram', - 'Caykara', - 'Aranyaprathet', - 'Lemay', - 'Jicin', - 'Al Hibah', - 'Walnut Park', - 'Basford', - 'Landerneau', - 'eMuziwezinto', - 'Roznov pod Radhostem', - 'Burrillville', - 'Singhwara', - 'Santa Anita', - 'Altinopolis', - 'Stahnsdorf', - 'Porumamilla', - 'Silute', - 'Do`stobod', - 'Vodil', - 'Handlova', - 'San Pedro de Lloc', - 'Xiangjiaba', - 'Gokarna', - 'Taree', - 'Khutauna', - 'Saraikela', + 'Paceco', + 'Isesaki', + 'Lopatcong', + 'Pecan Grove', + 'Thomaston', + 'Sri Jayewardenepura Kotte', + 'Quang Yen', + 'Greeley', + 'Omidiyeh', + 'Namakkal', + 'Macuro', + 'Neuenkirchen', + 'Goure', + 'Kehen', + 'Dongyangshi', + 'Fiumefreddo di Sicilia', + 'Alta Floresta', + 'Ban Na Chom Thian', + 'Viet Tri', + 'Kashgar', + 'Shawinigan', + 'Danghara', + 'Belgrade', + 'Puerto Tejada', + 'Tulin', + 'Agblangandan', + 'Poranga', + 'Lagos', + 'Mallig', + 'Ciftlik', + 'Sao Francisco de Paula', + 'Kiyama', + 'Crespo', + 'Bad Salzungen', + 'Doganhisar', + 'Indargarh', + 'Miandrivazo', + 'Mondovi', + 'Quthing', + 'Guipos', + 'Dikhil', + 'Polakala', + 'Ambaliha', + 'Anuppampattu', + 'Aquitania', + 'La Rinconada', + 'Paramaribo', + "Ma'anshan", + 'Uniao da Vitoria', + 'Cuihua', + 'Areka', + 'Huldenberg', + 'Gudlavalleru', + 'Alasandigutta', + 'Changtoushang', + 'Segni', + 'Durlesti', + 'Chivhu', + 'Carmen de Carupa', + 'Prachin Buri', + 'Buzhum', + 'Phalodi', + 'Munak', + 'Rewari', + 'La Gomera', + 'Yuhuan', + 'Woburn', + 'Aghbal', + 'Santa Maria a Vico', + 'Bogo', + 'Mendon', + 'Kong', + 'Benapol', + 'Sakoueba', + 'Uruana', + 'Chengam', + 'Freising', + 'Nobsa', + 'Ciechocinek', + 'Chengjiao', + 'Cerca Carvajal', + 'Matawan', + 'Al Madamud', + 'Mettmann', + 'Yakumo', + 'Bir Mogrein', + 'Puerto Acosta', + 'Nunna', + 'Gunjapalle', + 'Collier', + 'Mateszalka', + 'Bento Goncalves', + 'Umbrete', + 'Kapakli', + 'Padada', + 'Oud-Turnhout', + 'Karukh', + 'Fort Meade', + 'Domanic', + 'Emsburen', + 'Braunsbedra', + 'Sacramento', + 'Vidauban', + 'Ranomafana', + 'Chone', + 'Malapannanagudi', + 'Siralkoppa', + 'Mequon', + 'Rottingdean', + 'Lindenwold', + 'Chanal', + 'Wakuya', + 'Malaba', + 'Chaabat el Leham', + 'Huinan', + 'Port-Vila', + 'Silopi', + 'Tanabi', + 'Yelmalla', + 'Siteki', + 'Casiguran', + 'Kennedale', + 'Kenduadih', + 'Intibuca', + 'Fos-sur-Mer', + 'Nueva Era', + 'Jicheon', + 'Rovigo', + 'Acipayam', + 'Bajala', + 'Drama', + 'Shiv', + 'San Giorgio a Cremano', + 'Antonio Dias', + 'Jalajala', + 'Ocsa', + 'Oviedo', + 'University City', + 'Boquira', + 'Gaura', + 'Naaldwijk', + 'Manteswar', + 'Farmingville', + 'Bokonbaev', + 'Qingxicun', + 'Scharbeutz', + 'Hamrun', + 'Lake Barcroft', + 'Adeje', + 'Saint Austell', + 'Jarrow', + 'Kandira', + 'Lincang', + 'Orsay', + 'Affoltern am Albis', + 'Bilozerka', + 'Lishaocun', + 'Ochanthururtha', + 'Koekelare', + 'Vengikkal', + 'Dysselsdorp', + 'New Scotland', + 'Isfara', + 'Cuers', + 'Derry', + 'Tampere', + 'Debiapur', + 'Yandian', + 'Awan Patti', + 'Kara-Kyshtak', + 'Oguz', + 'Qualiano', + 'Jose Maria Ezeiza', + 'Pfaffenhofen', + 'Sidi Ali', + 'Arayat', + 'Carvajal', + 'Palakollu', + 'Jingzhou', + 'Owerri', + 'Bato', + 'Yanyan', + 'Dasmarinas', + 'Srifa', + 'Duzhuang', + 'Qazi Ahmad', + 'Brook Park', + 'Market Drayton', + 'Kitahiroshima', + 'Swindon', + 'Pilibhit', + 'Hoyland', + 'Georgsmarienhutte', + 'Chigorodo', + 'Abu Qir', + 'Marysville', + 'Singerei', + "Town 'n' Country", + 'Jangany', + 'Atwater', + 'Fuchucho', + 'Rutana', + 'Shamgarh', + 'Cotegipe', + 'Atascadero', + 'Maisons-Alfort', + 'Bela Vista de Minas', + 'Kopervik', + 'Madugula', + 'Semra', + 'Binh Hoa', + 'Krnov', + 'Itapaci', + 'Sao Raimundo Nonato', + 'Sint-Joost-ten-Node', + 'Maski', + 'Regen', + 'Folkestone', + 'Rardhu', + 'Toyohashi', + 'Duragan', + 'Guelendeng', + 'Bugongi', + 'Montecchio Emilia', + 'Mahwah', + 'Dayrut', + 'Papeete', + 'Worsley', + 'Mponela', + 'Barakpur', + 'Broken Hill', + 'Sakiet ez Zit', + 'Glen Burnie', + 'Negapatam', + 'Itahari', + 'Kambainellur', + 'Cienega de Flores', + 'Jau', + 'Xalatlaco', + 'Dalaman', + 'Thi Tran Dong Dang', + 'Zacatlan', + 'Changbang', + 'Chikugo', + 'Uden', + 'Kansas City', + 'Sremska Mitrovica', + 'Pizhou', + 'Fannuj', + 'Slany', + 'Soye', + 'Painal', + 'Station des Essais M.V.A.', + 'Egg Harbor', + 'Morsi', + 'Araioses', + 'Escondido', + 'Castelnuovo Berardenga', + 'Ijra', + 'Ndora', + 'Ain Taya', + 'Essaouira', + 'Kimba', + 'Taher', + 'Bouar', + 'Kyrenia', + 'Chilca', + 'Quatis', + 'Badulla', + 'Kalpatta', + 'Turffontein', + 'Potunuru', + 'Karuhatan', + 'Amalfi', + 'Wuppertal', + 'Cayo Mambi', + 'Riva del Garda', + 'Boucau', + 'Sejong', + 'Elesbao Veloso', + 'Jiaojiangcun', + 'Pullanpallikonam', + 'Borborema', + 'Corella', + 'Schkeuditz', + 'Gurgenpinari', + 'Buddayyakota', + "Zd'ar nad Sazavou", + 'Jiangmen', + 'Tallahassee', + 'Ciudad Lazaro Cardenas', + 'Peabiru', + 'Ghomrassen', + 'Sultan Kudarat', + 'Brunswick', + 'Brookes Point', + 'Jihlava', + 'Kotharpettai', + 'Koumia', + 'Hasanpur', + 'Riachao do Dantas', + 'Tinqueux', + 'Stillwater', + 'Tempoal de Sanchez', + 'Weiterstadt', + 'Ichikikushikino', + 'Atlapadu', + 'Kiashahr', + 'Bertioga', + 'Centro Habana', + 'Makassar', + 'Rajakheri', + 'Kuhbil', + 'Baldwin Park', + 'Chunchura', + 'Shepshed', + 'Yakima', + 'Rayagada', + 'Saltpond', + 'Karamadai', + 'Sainte-Suzanne', + "St. John's", + 'Peddannavaripalle', + 'Ban Houayxay', + 'Pir Maker', + 'Bagewadi', + 'Chemancheri', + 'San Luis Rio Colorado', + 'Fullerton', + 'Khargram', + 'Yacuiba', + 'Rancho Grande', + 'Giurgiu', + 'San Blas Atempa', + 'Koulamoutou', + 'Jwaneng', + 'Kamalapuram', + 'Crna Trava', + 'Brooklyn Park', + 'Singapperumalkovil', + 'Kiban', + 'Budalur', + 'Yeonil', + 'Nsele', + 'Cumra', + 'Baie-Comeau', + 'Avila', + 'Chantilly', + 'Tongyangdao', 'Izamal', - 'Nakhon Nayok', - 'Ansfelden', - 'Brzesko', - 'Stallings', - 'Kozienice', - 'Bandora', - 'Hostomel', - 'Rosu', - 'Mastic Beach', - 'Bileh Savar', - 'Kanhauli Manohar', - 'Svitavy', - 'Tocantins', - 'Ampahimanga', - 'Attur', - 'Itahri', - 'Aruvapalam', - 'Castellaneta', - 'Harenkarspel', - 'Koprukoy', - 'Chotala', - 'Alsfeld', - 'Riversdale', - 'Segoubougou', - 'Ganeshpur', - 'West Norriton', - 'As Sukhnah', - 'Chorfa', - 'Readington', - 'Ocean Pointe', - 'Timezgana', - 'Huarmey', - 'Dyersburg', - 'South Houston', - 'Banora Point', - 'Kotoura', - 'Hibbing', - 'Talsint', - 'River Falls', - 'Bingawan', - 'Four Corners', - 'Al Qbab', + 'Yalaguina', + 'Obersiggenthal', + 'Sadalgi', + 'Cuprija', + 'Laufenburg (Baden)', + 'Bukan', + 'Siyana', + 'Kafue', + 'Portmore', + 'Perchtoldsdorf', + 'Catemu', + 'Kaimana', + 'Demir Hisar', + 'Tabor', + 'Alakamisy', + 'Bayt Lahya', + 'Rosiori de Vede', + 'Sarnia', + 'Venustiano Carranza', + 'Nunchia', + 'Kankakee', + 'Chittur', + 'Duma', + 'Bou Arada', + 'Burton', + 'Itatiaiucu', + 'Mason', + 'Araputanga', + 'San Juan Tecuaco', + 'Meghaul', + 'Abhwar', + 'Zhujiacun', + 'Saline', + 'Fethiye', + 'Leeds', + 'Ogori', + 'Keffi', + 'Karanja', + 'Heiligenhaus', + 'Haci Zeynalabdin', + 'Gubin', + 'Chenab Nagar', + 'Gormi', + 'Lydenburg', + 'Neuhaus am Rennweg', + 'Kings Grant', + 'Umi', + 'Dengka', + 'Gangaur', + 'Atsugicho', + 'Ibshaway', + 'Mananasy-Tsitakondaza', + 'Itacarambi', + 'Minowa', + 'Corzuela', + 'Vanduvancheri', + 'Bohl-Iggelheim', + 'Shinile', + 'Wilde', + 'Montlucon', + 'Latham', + 'Picana', + 'Tuao', + 'Drapetsona', + 'Mountain Brook', + 'Montechiarugolo', + 'Kasba Tanora', + 'Rajghat Garail', + 'Kasumpti', + 'Devirammanahalli', + 'Singalandapuram', + 'Chevy Chase', + 'Aspropyrgos', + "'Ain Taghrout", + 'Delft', + 'Beining', + 'Blainville', + 'Krasnohrad', + 'Siem Reap', + 'Betamcherla', + 'Labin', + 'Pompei', + 'Gospic', + 'Hakui', + 'Gomaringen', + 'Saint-Brevin-les-Pins', + 'Langtang', + 'Mangalapadi', + 'Santa Lucia del Camino', + 'East Whiteland', + 'Morioka', + 'Bouira', + 'Coria del Rio', + 'Varzea Paulista', + 'Araira', + 'Thana Bhawan', + 'Ain Taoujdat', + 'Mumbwa', + 'Comandante Luis Piedra Buena', + 'Powell River', + 'Nampa', + 'Nisang', + 'Piran', + 'Bude', + 'Merosina', + 'Kamez', + 'Fairborn', + 'Abhar', + 'Giffoni Valle Piana', + 'Jose Bonifacio', + 'Andhana', + 'Kisanuki', + 'Landover', + 'Dekanme', + 'Raposos', + 'Columbio', + 'Flieden', + 'Antalaha', + 'Impruneta', + 'Pyapali', + 'Butuan', + 'Hlevakha', + 'Braslovce', + 'Kalajoki', + 'Minami-Boso', + 'Tocumen', + 'Matan', + 'Zapopan', + 'Calbayog City', + 'Liloy', + 'Durgi', + 'Byadgi', + 'Vero Beach South', + 'Hongtuliang', 'Baharu', - 'Pujili', - 'Schluchtern', - 'Alcaniz', - 'Guerande', - 'Caldera', - 'Pielisjarvi', - 'Loimaa', - 'Agiripalle', - 'Troutdale', - 'Bni Tajjit', - 'Westwood', - 'Al Awjam', - 'Ban Kao', - 'Sikeston', - 'Rygge', - 'Castenaso', - 'Sayville', - 'Venustiano Carranza', - 'Voss', - 'Kittur', - 'Tyldesley', - 'Caravaggio', - 'Sylvan Lake', - 'Mafune', - 'Carlet', - 'Upala', - 'Santa Cruz Mulua', - 'Zegzel', - 'East Barnet', - 'Port-de-Bouc', - 'Easthampton', - 'Forks', - 'La Grange', + 'Hounslow', + 'Joquicingo', + 'Cranleigh', + 'Cassilandia', + 'Burton Latimer', + 'Poco Fundo', + 'Starogard Gdanski', + 'Paikpara', + 'Calera', + 'Gyumri', + 'Higashine', + 'Hialeah Gardens', + 'Moravce', + 'Lac', + 'Poruvakara', + 'Cadaval', + 'Pasig City', + 'Montpellier', + 'Nantang', + 'Baruni', + 'Imani', + 'Rommerskirchen', + 'Orizaba', + "Saint Ann's Bay", + "Olho d'Agua das Flores", + 'Amvrosiivka', + "M'dhilla", + 'Abulug', + 'Helmstedt', + 'La Chapelle-Saint-Luc', + 'Delitzsch', + 'Gurmaila', + 'Sainte-Anne-des-Plaines', + 'Gardhabaer', + 'Sodankyla', + 'Chandrakona', + 'Leczyca', + 'Madhipura', + 'Khargapur', + 'Cruz do Espirito Santo', + 'Gloucester City', + 'Latisana', + 'Doranda', + 'Holly Springs', + 'Mechtras', + 'Grenoble', + 'Red Bluff', + 'Titu', + 'Karavalur', + 'Chiquimulilla', + 'Kirkcaldy', + 'Soledad de Doblado', + 'Ben Nasseur', + 'Miyato', + 'Temecula', + 'Araripe', + 'Ambatoharanana', + 'Union Park', + 'Cuemba', + 'Birkirkara', + 'Ambohitsilaozana', + 'La Louviere', + 'Enniscorthy', + 'Ishkashim', + 'Touna', + 'Presidente Olegario', + 'Maranguape', + 'Mati', + 'Sainte-Catherine', + 'Nerja', + 'Freiburg im Breisgau', + 'Cairo Montenotte', + 'Uchchangidurgam', + 'Jhansi', + 'Elmali', + 'Al Jabin', + 'Orono', + 'Wickliffe', + 'Lontras', + 'Mound', + 'Cosio', + 'Drummondville', + 'Royal Tunbridge Wells', + 'Dolneni', + 'Tabogon', + 'Sosnowiec', + 'Badrashni', + 'Papanduva', + 'Kalayaan', + 'Zottegem', + 'General Salgado', + 'Ozatlan', + 'Southchase', + 'Santa Adelia', + 'Aribinda', + 'Nakanojomachi', + 'Coroata', + 'Marovatolena', + 'Saubara', + 'Pingtiancun', + 'Syosset', + 'Dinslaken', + 'Carpentras', + 'San Martino di Lupari', + 'Tabarka', + 'Yulara', + 'Ratzeburg', + 'Punta Gorda', + 'San Rafael del Yuma', + 'Arima', + 'Jannat Shahr', + 'El Escorial', + 'Honwada', + 'Bhagwanpur Khurd', + 'Ayutla de los Libres', + 'Guaiba', + 'Garzon', + 'Tarangnan', + 'Marktheidenfeld', + 'Ban Chang Phuak', + 'Aurad', + 'Epazoyucan', + 'Tone', + 'Seforong', + 'Lichtervelde', + 'Seriate', + 'Suileng', + 'Viraganur', + 'Novi Banovci', + 'Knaresborough', + 'Bulisa', + 'Shaqlawah', + 'Kingstowne', + 'Zalec', + 'Siano', + 'Flexeiras', + 'Ar Raqqah', + 'Kercem', + 'El Kef', + 'Cicero Dantas', + 'Schonefeld', + 'Neves Paulista', + 'Fish Hawk', + 'Akjoujt', + 'La Courneuve', + 'Biliran', + 'Telkap', + 'Sher Muhammadpuram', + 'Arapoti', + 'Laupheim', + 'Boden', + 'Ratau', + 'Rudesheim am Rhein', + 'Xintai', + 'Temerin', + 'Rebordosa', + 'Bernolakovo', + 'Sulat', + 'Ellwangen', + 'Gates', + 'Merano', + 'Nacozari de Garcia', + 'Camp Springs', + 'Taraka', + 'Yutiancun', + 'Soanpeta', + 'Navgilem', + 'Nagakute', + 'Ipetumodu', + 'Minnetonka', + 'The Acreage', + 'American Canyon', + 'Tripurantakam', + 'Acara', + 'Greer', + 'Conception Bay South', + 'Oiwa', + 'Ukhai Purbari Patti', + 'My Hoa', + 'Miklavz na Dravskem Polju', + 'Porbandar', + 'As Samawah', + 'Tamba', + 'Namangan', + 'Alluru', + 'Zinzana', + 'Karasburg', + "Ich'on", + 'Vojnik', + 'San Miguel Siguila', + 'Lome', + 'Vieiro', + 'Hardas Bigha', + "Jalawla'", + 'Belfast', + 'Sotik Post', + 'Hejiaji', + 'Lovech', + 'Rokupr', + 'Yalda', + 'Mangaldai', + 'Goodyear', + 'Kolakaluru', + 'Bonney Lake', + 'Alcobaca', + 'Bideford', + 'Godawari', + 'Parnaiba', + 'Eskilstuna', + 'Conceicao do Almeida', + 'San Carlos Park', + 'Dolyna', + 'East Liverpool', + 'Ceylanpinar', + 'Adachi', + 'Pottassheri', + 'Kauhajoki', + 'Rio Paranaiba', + 'Patos de Minas', + 'Saint-Jean-de-Monts', + 'Irapuato', + 'Zhuolu', + 'Miadanandriana', + 'Inashiki', + 'Hildesheim', + 'Cold Springs', + 'Merksplas', + 'Engen', + 'LaSalle', + 'Uyo', + 'Vinh Chau', + 'Parsuram', + 'Yoshimi', 'Jaypul', - 'Los Muermos', - 'Markranstadt', - 'Quarteira', - 'Noale', - 'Bang Phae', - 'Upton', - "'Ain Babouche", - 'Douar Azla', - 'Yeni Suraxani', - 'Buckley', - 'Jakkampalaiyam', - 'Chennur', - 'Ranong', - 'Bumpe', - 'Rustampur', - 'Simcoe', - 'Math Lohiyar', - 'Ustron', - 'Kamayakkavundanpatti', - 'Subachoque', - 'Jacupiranga', - 'Sultanabad', + 'Minooka', + 'Mehtar Lam', + 'Corsico', + 'Wanding', + 'Corbas', + 'Shaogang', + 'Lusanga', + 'Xining', + 'Navalgund', + 'Binh Minh', + 'Dindigul', + 'Doddanahalli', + 'Tefenni', + 'Samdrup Jongkhar', + 'Taylorsville', + 'Bulicun', + 'Lisieux', + 'Valley Falls', + 'Salpazari', + 'Pianoro', + 'Kedia', + 'Green Valley', + 'Cape Breton', + 'Rencun', + 'Bandar-e Genaveh', + 'Beaverton', + 'Purranque', + 'My Tho', + 'Wendlingen am Neckar', + 'Mohon', + 'Ngaoundere', + 'Boryslav', + 'Antonio Prado', + 'Ramgarh', + 'Gdynia', + 'Hoyland Nether', + 'Cori', + 'Adakli', + 'Na Wa', + 'Ramla', + 'Ellicott', + 'Nowa Sol', + 'Laakirchen', + 'Jalalpur Bhattian', + 'Jaragua do Sul', + 'Ilic', + 'Guimar', + 'Bullas', + 'Dalawarpur', + 'Anuradhapura', + 'Carnaubal', + 'Yokosuka', + 'Lake Mohawk', + 'Phulwar', + 'Bohemia', + 'Imzouren', + 'Tibigan', + 'Apostolove', + 'Cantley', + 'Mbuji-Mayi', + 'Uarini', + "Qarah Zia' od Din", + 'Cortes', + 'Cullercoats', + 'Reggio di Calabria', + 'Figline Valdarno', + 'Mutsu', + 'Maiquinique', + 'New Panamao', + 'Odder', + 'Mar de Espanha', + 'Bukedea', + 'Rath To', + 'Choppington', + 'Irugur', + 'Padang Besar', + 'Cine', + 'Beckett Ridge', + 'Baghuz Fawqani', + 'Campos del Puerto', + 'Bandar-e Torkaman', + 'Sakon Nakhon', + 'San Juan de Alicante', + 'Benicarlo', + 'Beuningen', + 'Vrable', + 'Hennebont', + 'Mamobihat', + 'Three Springs', + "Saint-Cyr-l'Ecole", + 'Brod', + 'Taourirt', + 'Sliven', + 'Stanytsia Luhanska', + 'Ruston', + 'Plauen', + 'Sarasota Springs', + 'Sao Gotardo', + 'Beloeil', + 'Liuguang', + 'Bani Suhayla', + 'Pilar', + 'Sao Joao do Araguaia', + 'Teseney', + 'Domzale', + 'Feira', + 'Ambatoria', + "Guang'an", + 'Carice', + 'Loha', + 'Carmo do Rio Claro', + 'Calle Larga', + 'Ban Yang Hom', + 'Ilha de Mocambique', + 'Barwani', + 'Lowes Island', + 'Liaocheng', + 'Shergarh', + 'La Loggia', + 'Halden', + 'Khowrzuq', + 'Sahavalanina-Antenina', + 'Alum Rock', + 'Kilakkarai', + 'Finsterwalde', + 'Ouedo', + 'Tlalnepantla', + 'Tafi Viejo', + 'Minnampalli', + 'Santa Comba', + 'Sant Joan de Vilatorrada', + 'Marl', + 'Hulkoti', + 'Libourne', + 'Orasje', + 'Svolvaer', + 'Villa Curuguaty', + 'Velden am Worthersee', + 'Riverton', + 'Selmane', + 'Jamshedpur', + 'Sinsina', + 'Amity', + 'Kani-Bonzon', + 'Ilopango', + 'Kiliia', + 'Trelew', + 'Kowdalli', + 'Sao Martinho do Bispo', + 'Bayabas', + 'Marcolandia', + 'Hemel Hempstead', + 'Titlagarh', + 'Thathupur', + 'Kavieng', + 'Pepa', + 'Mangarwara', + 'Wanderlandia', + 'Sokolka', + 'Nara', + 'Koror', + 'Mbamba Bay', + 'Wezembeek-Oppem', + 'Tanjombato', + 'Eichstatt', + 'Independence', + 'Kagoshima', + 'Velingara', + 'Ouistreham', + 'St. Stephens', + 'Altinova', + 'Juchipila', + 'Jiaxing', + 'Millcreek', + 'Ameca', + 'Palmacia', + 'Fiano Romano', + 'Costa Volpino', + 'Rioja', + 'Kalkara', + 'Zanica', + 'Husainabad', + 'Naters', + 'Mistrato', + 'Ambahive', + 'Savanna-la-Mar', + 'Irinjalakuda', + 'Padappakara', + 'Chiantla', + 'Cidade Gaucha', + 'Walton-on-the-Naze', + 'Habiganj', + 'Irukanni', + 'Tekpanja', + 'Ellisville', + 'Luancheng', + 'Rudauli', + 'Abu al Matamir', + 'Nabas', + 'Kagadi', + 'Los Llanos', + 'Ilovaisk', + 'Ar Rumaythah', + 'Melun', + 'Catral', + 'Canico', + 'Pandharpur', + 'Hiroshima', + 'Don Bosco', + 'Billericay', + 'Mentana', + 'Sandravinany', + 'Pacos de Ferreira', + 'Darsi', + 'Tuineje', + 'Medinipur', + 'Mensora', + 'Nikaia', + 'Tan Chau', + 'Ma`alot Tarshiha', + "Huai'an", + 'Spinea', + 'Silvia', + 'Alcarraz', + 'Dongxishan', + 'Putrajaya', + 'Two Rivers', + 'Inacio Martins', + 'Kharahara', + 'Jakarta', + 'Hurth', + 'Giengen an der Brenz', + 'New Delhi', + 'Morlenbach', + 'Krus na Ligas', + 'Tornquist', + 'Hacine', + 'Yanji', + 'Fraiburgo', + 'Gursu', + 'San Giljan', + 'Verin', + 'Moissac', + 'Baghambarpur', + 'Bhatpara', + 'Pontinha', + 'Cunha Alta', + 'Riacho das Almas', + 'Yadwad', + 'St. Albert', + 'Agno', + 'Sitarganj', + 'Budhni', + 'Comayagua', + 'Matagua', + 'Remagen', + 'Aigle', + 'Forest Hills', + 'Wangtan', + 'Avanhandava', + 'Karnobat', + 'Chanp', + 'Amherst', + 'Duiven', + 'Bilohirsk', + 'Pleternica', + 'Marogong', + 'Kefar Sava', + 'Quilmes', + 'Conchagua', + 'Al Khankah', + 'Dulken', + 'Lobatse', + 'Utehia', + 'Sotomayor', + 'Traunreut', + 'Aleksandrovka', + 'Hetane', + 'Bad Oeynhausen', + 'Pescara', + 'Ashkezar', + 'Seiro', + 'Torrejon de Ardoz', + 'Antanimora Atsinanana', + 'Yiewsley', + 'Fojnica', + 'Iharana', + 'Dutse', + 'Ban Lao Yao', + 'Dirusumarru', + 'Tame', + 'Beledweyne', + 'San Andres Xecul', + 'Formia', + 'Mengla', + 'Croix', + 'Kraslava', + 'Pedagadi', + 'Denbigh', + 'Barharwa Kalan', + 'Alexania', + 'Sakhnin', + 'Yenagoa', + 'Kaya', + 'Karlstad', + 'Bundibugyo', + 'Harrai', + 'Dragor', + 'San Jose de Las Matas', + 'Gabela', + 'Alpu', + 'Karema', + 'Yevlax', + 'Allanmyo', + 'Ghafurov', + 'Brandis', + 'Pulupandan', + 'Eidsvoll', + 'Hinunangan', + 'Manmad', + 'Guledagudda', + 'Bangshang', 'Kujwa', - 'Parrita', - 'Ambarakaraka', - 'Gubin', - 'Bals', - 'Medjana', - 'Ubata', - 'Chaona', - 'Cherukunnu', - 'Khusropur', - 'Saraland', - 'Tarqui', - 'El Ach', - 'Diabigue', - 'Masmouda', - 'Frogn', - 'Pilkha', - 'Bakarpur Ogairah', - 'Nonantola', - 'Bovolone', - 'Prinzapolka', - 'Canudos', - 'Kajur', - 'Nowogard', - 'Surappalli', - 'Panajachel', - 'Chinggil', - 'Birhana', - 'Michelstadt', - 'Hazro', - 'Nyahanga', - 'Anantapalle', - 'Ait Yaazem', - 'Chai Prakan', - 'Johnstone', + 'Fairview', + 'Arani', + 'Spoltore', + 'Peiting', + 'Panj', + 'Sahavato', + 'Cramlington', + 'Poggio a Caiano', + 'Sisauna', + 'Mamushe', + 'Tsevie', + 'Barikot', + 'Tecax', + 'Sivapuram', + 'Kalbacar', + 'Mitry-Mory', + 'Biguacu', + 'Trowbridge', + 'Hasanganj', + 'Chamblee', + 'Sid', + 'Alboraya', + 'Pinar del Rio', + 'Calvillo', + 'Mercedes', + 'Chapel en le Frith', + 'Kalat', + "Ra's al Khaymah", + 'Mapoteng', + 'Ponta de Pedras', + 'Glenfield', + 'Temple Terrace', + 'Tlokweng', + 'Raun', + 'Aquin', + 'Boiling Springs', + 'Slobozhanske', + 'Truckee', + 'Nuremberg', + 'Yanghe', + 'Charqueadas', + 'Clarkston', + 'Wallingford Center', + 'Colleferro', + 'Luxor', + 'Gadsden', + 'Dautphe', + 'Macedo de Cavaleiros', + 'Venissieux', + 'Shamva', + 'Chesapeake', + 'Felsberg', + 'East Los Angeles', + 'Monte Caseros', + 'Misawa', + 'Souaflia', + 'Bouguirat', + 'Talara', + 'Iarinarivo', + 'Atalaia do Norte', + 'Pangunattam', + 'Little Ferry', + 'Oulad Tayeb', + 'Masar', + 'Melena del Sur', + 'Miura', + 'Panihati', + 'Andresy', + 'Ramayampet', + 'Basoko', + 'Thala', + 'Chifeng', + 'Majhaul', + 'Nediyanad', + 'Chaumont', + 'Belen de Escobar', + 'Karak', + 'Araxa', + 'Canteleu', + 'Vanrhynsdorp', + 'Achaguas', + 'Norwood', + 'Kandahar', + 'Santa Teresa', + 'Salmon Arm', + 'Kalutara', + 'Greene', + 'Harrisonburg', + 'Lohur', + 'Dingman', + 'Phon Charoen', + 'Farakka', + 'College Place', + 'Wodzislaw Slaski', + 'Alimodian', + 'Kemi', + 'Khapdeh', + 'Xaafuun', + 'Pongalur', + 'Chandwara', + 'Tecali', + 'Villacanas', + 'Kalluru', + 'Bouarouss', + 'Misantla', + 'Mazinde', + 'Rixensart', + 'Satellite Beach', + 'Jinhua', + 'Reedsburg', + "Togoch'ale", + 'Marchena', + 'Wan Long', + "Lyuboml'", + 'Ivancice', 'Wendelstein', - 'Aurahi', - 'Aquitania', + 'Helston', + 'Manduria', + 'Shama', + 'Sedriano', + 'Cheruvaranam', + 'Nechi', + 'Mandu', + 'Binefar', + 'Sha Kok Mei', + 'Muta', + 'Caripito', + 'Petrolina de Goias', + 'Lianhe', + 'Brock', + 'Schonaich', + 'Aloguinsan', + 'Acapulco de Juarez', + 'Ayt Mohamed', + 'Poplar Bluff', + 'Limburgerhof', + 'Jaggampeta', + 'Ostroleka', + 'Kalamboli', + 'Ash Shihr', + 'Sasaima', + 'Vesele', + 'Lac-Brome', + 'Matnog', + 'Skokie', + "Ha'il", + 'Tzaneen', + 'Greenford', + 'Savanur', + 'Permet', + 'Mallapur', + 'Ladyzhyn', + 'Dama', + 'Angers', + 'Montigny-le-Bretonneux', + 'Xiaodian', + 'Narok', + 'Eching', + 'Castel San Pietro Terme', + 'Itondy', + 'Alcudia', + 'Periyanayakkanpalaiyam', + 'Artigues-pres-Bordeaux', + 'Marikina Heights', + 'Ben Zakkay', + 'Cachipay', + 'Hertzogville', + 'Daman', + 'Wilsdruff', + 'Ben Guerir', + 'Sciacca', + 'Signa', + 'Tuy', + 'Kireka', + 'Reston', + 'Sarab-e Taveh-ye `Olya', + 'Singida', + 'Waldorf', + 'Ain Jemaa', + 'Al Ghat', + 'Deodrug', + 'Kotmale', + 'Guemar', + 'Skoura', + 'Tuaran', + 'Outa Bouabane', + 'Talaivasal', + 'Jerusalem', + 'Hegang', + 'Daskasan', + 'Hannan', + 'Murowana Goslina', + 'Bomlo', + 'Nova Veneza', + 'Coppell', + 'Miguelopolis', + 'Stadtallendorf', + 'Kishundaspur', + 'Yuxiaguan', + 'Aleksandrovac', + 'Mianwali', + 'Mujikharf', + 'Develi', + 'Khawr Fakkan', + 'Billapadu', + 'Cacu', + 'Oldenburg', + 'Lens', + 'Veternik', + 'Canet de Mar', + 'Vellaturu', + 'Colmar', + 'Guadalupe Nuevo', + 'Hulin', + 'Talwandi Bhai', + 'Sighisoara', + 'Santa Monica', + 'Alessandria', + 'Idku', + 'Barsaun', + 'Podebrady', + 'Dona Ines', + 'Eppelheim', + 'Lonavale', + 'Comitan', + 'Darby', + 'Billingham', + 'Saint-Maximin-la-Sainte-Baume', + 'Volterra', + 'Kombissiri', + 'San Lorenzo de Guayubin', + 'Mashyal', + 'Cogua', + 'Parral', + 'Coaticook', + 'Bekobod', + 'Ribadeo', + 'Bhanukumari', + 'Kampong Chhnang', + 'Vrbovec', + 'South Sioux City', + 'Kalaki', + 'Panama City', + 'Mustafabad', + 'Morur', + 'Zurbatiyah', + 'Gamba', + 'Toukoroba', + 'Bully-les-Mines', + 'Nattakkadaiyur', + 'Sand Springs', + 'Turek', + 'Nejapa', + 'Woodridge', + 'Laranjeiras', + 'Xiaozui', + 'Kottaiyur', + 'Sebaste', + 'Penn Forest', + 'La Esmeralda', + 'Nohsa', + 'Eskisehir', + 'Chillan Viejo', + 'Kani', + 'Terdal', + 'Sarta', + 'Jinan', + 'Oborniki', + 'Taketoyo', + 'Badnor', + 'Panchkula', + 'Tres Passos', + 'Cartaya', + 'Barra de Santa Rosa', + 'Ganapavaram', + 'Mulampilli', + 'Damaishan', + 'Meihuacun', + 'Pahsara', + 'Atessa', + 'Toucheng', + 'Chamba', + 'Kranuan', + 'Pasaul', + 'Westview', + 'Grimari', + 'San Jacinto de Buena Fe', + 'Porecatu', + 'Ihtiman', + 'Misilmeri', + 'Friesenheim', + 'Wentang', + 'Bageshwar', + 'Mahtha', + 'Tenes', + 'Eraclea', + 'Evesham', + 'Elmhurst', + 'Nahorkatiya', + 'Oil City', + 'Sidi Jaber', + 'Laxou', + 'Royal Kunia', + 'Dong Xoai', + 'Hathauri', + 'Ambinanintromby', + 'Jurovski Dol', + 'Erwitte', + 'Jerada', + 'Costas de Cao', + 'Douetire', + 'Terku Valliyur', + 'Samesi', + 'Halgeri', + 'Huichapan', + 'Bolpur', + 'Ban Bu Sung', + 'Dandong', + 'Bucaramanga', + 'Bhavnagar', + 'Walia', + 'Puerto Vallarta', + 'Rishikesh', + 'Solebury', + 'Maratturai', + 'Lindlar', + 'Bariarpur Kandh', + 'Yerbas Buenas', 'Ottur', - 'Bouchabel', - 'Viskovo', - 'Fatipura', - 'Ottakkadai', - 'Bruggen', - 'South River', - 'Banigbe', - 'Semdinli', - 'Grossenkneten', - 'Kolluru', - 'Ramewadi', - 'Owase', - 'Santiago Tulantepec', - 'Wohlen', - 'Domont', - 'Mecheraa Asfa', - 'Olecko', - 'Tankal', - 'Federal', - 'Dalachi', - 'Kalanjur', - 'Eloy', - 'Quiindy', - 'Bhiloda', - 'Huyuk', - 'Middle Smithfield', - 'Yaojia', - 'Makhu', - 'Czernica', - 'Fartura', - 'Punta Umbria', - 'Vontimitta', - 'Safo', - 'Tachiarai', - 'Montbrison', - 'Badshahpur', - 'Baleyara', - 'Sulechow', - 'Serarou', - 'Mikkabi', - 'Ukrainka', - 'Strathroy', - 'Ayyampalaiyam', - 'Marbach am Neckar', - 'Marupe', - 'North Fayette', - 'Dickson', - 'Gardendale', - 'Agios Ioannis Rentis', - 'Bni Quolla', - 'Grovetown', - 'Stone Ridge', - 'Sivapuram', - 'Lady Lake', - 'Bay Village', - 'Telfs', - 'Al Hazm', - 'Mayilur', - 'Scordia', - 'Ranohira', - 'Duxbury', - 'Tourlaville', - 'Agudo', - 'Penugonda', - 'Fort Mohave', - 'Vaureal', - 'Hewitt', - 'Sulphur Springs', - 'Eilenburg', - 'Worcester Park', - 'Bou Djeniba', - 'Doganhisar', - 'Mahavelona', - 'Kayanna', - 'Samarate', - 'Mountain Home', - 'Ciudad de Huitzuco', - 'Az Zintan', - 'Cajueiro', - 'Preetz', - 'Azalea Park', - 'Zeulenroda', - 'Americus', - 'Lithia Springs', - 'Qazyan', - 'Grandville', - 'Rahon', - 'Marahom', - 'Khat Azakane', - 'Girua', - 'Ya`bad', - 'Locarno', - 'Aue', - 'Myrza-Ake', - 'Bracebridge', - 'Fort Hunt', - 'Satiro Dias', - 'Orsay', - 'Rani Shakarpura', - 'Sapatgram', - 'Utnur', - 'Turkeli', - 'Blanquefort', - 'Kumaranallur', - 'Sidi Azzouz', - 'Hoganas', - 'Sughrain', - 'Summerside', - 'Bethulie', + 'Torpa', + 'Debre Zeyit', + 'Lemgo', + 'Piritiba', + 'San Lorenzo de El Escorial', + 'Paterson', + 'Gonzaga', + 'Calabasas', + 'Miahuatlan', + 'Castelo do Piaui', + 'Sprockhovel', + 'Adelaide', + 'Clay Cross', + "Do'stlik Shahri", + 'Carrieres-sous-Poissy', + 'Hizan', + 'Mios', + 'Edenburg', + 'Worplesdon', + 'Le Kremlin-Bicetre', + 'Nanjundapuram', + 'Muratli', + 'Massena', + 'Girona', + 'Arifwala', + 'Chillum', + 'Salcedo', + 'Caoayan', + 'Kolonodale', + 'Curacautin', + 'Ixchiguan', + 'Dubnica nad Vahom', + 'Careiro da Varzea', + 'Meckenbeuren', + 'Lacombe', + 'Chifubu', + 'Kostinbrod', + 'Lipova', + 'Sao Joao Evangelista', + 'Messini', + 'Santangpai', + 'Viransehir', + 'Ait Ali', + 'Harsova', + 'Mamou', + 'Denkendorf', + 'Kalardasht', + 'Santo Antonio do Leverger', + 'Qusar', + 'San Tan Valley', + 'Kushima', + 'West Norriton', + 'Brasilia de Minas', + 'Hassleholm', + 'Shahdol', + 'Faqus', + 'Abbots Langley', + 'Zanandore', + 'Canon City', + 'Manjeri', + 'New Milton', + 'Regensdorf', + 'Flower Mound', + 'Dharphari', + 'Chapra', + 'Tazert', + 'Hirehadagalli', + 'Walkden', + 'Hatti', + 'Ohangaron', + 'Bujanovac', + 'Dharmapuram', + 'Munchenstein', + 'Ishigaki', + 'Cocody', + 'Karimpur', + 'Appukkudal', + 'New Kensington', + 'Palmas de Monte Alto', + 'Baghduma', + 'Sorisole', + 'Qarazhal', + 'Shemonaikha', + 'Korfez', + 'Mbale', + 'Shahar Telpa', + 'Gangwuzhen', + 'Qianzhou', + 'Potosi', + 'Monte Chingolo', + 'Baba Bakala', + 'Nottuln', + 'Talakad', + 'Dearborn Heights', + 'Mulakumud', + '`Ali Shahr', + 'Nashtifan', + 'Buriti', + 'Veliko Tarnovo', + 'Forest Lake', + 'Mizuho', + 'Birni Lafia', + 'Honda', + 'Fortin de las Flores', + 'Corral de Bustos', + 'Dracut', + 'Dighwa', + 'La Riche', + 'Karsaut', + 'Mito', + 'Xunjiansi', + 'Gandia', + 'Sidi Makhlouf', + 'Xibeijie', + 'Peritoro', + 'Sanjiangkou', + 'Bounaamane', + 'Barja', + 'San Felipe del Progreso', + 'Daisen', + 'Avadi', + 'North Bay Shore', + 'Dagohoy', + 'Fuying', + 'Dabas', + 'Koipadi', + 'Bloomington', + 'Mecheria', + 'Sundargarh', + 'Rajod', + 'Serramazzoni', + 'Kokofata', + 'Urlati', + 'Temixco', + 'Barbadanes', + 'Peddapalli', + 'Le Mont-sur-Lausanne', + 'Berthoud', + 'Navrongo', + 'Brockworth', + 'West Goshen', + 'Arcos de Valdevez', + 'Lalgola', + 'Bakhmut', + 'Majibacoa', + 'Yangfang', + 'Malisheve', + 'Cloverdale', + 'Petah Tiqwa', + 'Yamanashi', + 'Riofrio', + 'Merta', + 'Yoro', + 'Trinidad', + 'Sobreda', + 'Sidi Allal el Bahraoui', + 'Naranammalpuram', + 'Baicoi', + 'Rolling Meadows', + 'Linjiang', + 'Aralam', + "Citta Sant'Angelo", + 'Kaous', + 'Zacualpa', + 'Rivas', + 'Vellipalaiyam', + 'Ciudad Santa Catarina', + 'Chaungtha', + 'Los Lunas', + 'Crna na Koroskem', + 'San Miguel Ixtahuacan', + 'Pantukan', + 'Tsushima', + 'Donggangli', + 'Nalbach', + 'Begles', + 'Addlestone', + 'Maluso', + 'Atchison', + 'Vertentes', + 'Perth', + 'Deori Khas', + 'Cho Phuoc Hai', + 'Pacifica', + 'Belhatti', + 'Audincourt', + 'Baraidih', 'Tsiningia', - 'Antindra', - 'Andapafito', - 'Manompana', - 'Bevonotra', - 'Betanty', - 'Mandrosonoro', + 'Ampary', + 'Drobeta-Turnu Severin', + 'Tsumeb', + 'Atlantic City', + 'Villaguay', + 'Gyangze', + 'Wokingham', + 'Cowdenbeath', + 'Tehuacan', + 'Babanusah', + 'Kolobrzeg', + 'Iguala de la Independencia', + 'Shanklin', + 'Nasriganj', + 'Haql', + 'Bonab', + 'Ratnanagar', + 'Ermoupoli', + 'Besalampy', + 'Mannar', + 'Vigo', + 'Wolverhampton', + 'Idfu', + 'Zacapa', + 'Malacacheta', + 'Jersey City', + 'Tanmpegre', + 'Gemlik', + 'Bilovodsk', + 'Putyvl', + 'Memmelsdorf', + 'Ar Rustaq', + 'Munster', + 'Dano', + 'Barhan', + 'San Giorgio Ionico', + 'Shevington', + 'Larnaca', + 'Mawu', + 'Rio Verde de Mato Grosso', + 'Arroyos y Esteros', + 'Thoubal', + 'Breisach am Rhein', + 'Aizawl', + 'Bamessing', + 'Nurmo', + 'Lewistown', + 'Marseille', + 'Hyde Park', + 'Antsahalava', + 'Gardelegen', + 'Ramena', + 'Centerville', + 'Berdiansk', + 'Contla', + 'Lunavada', + 'Schwetzingen', + 'Vilangurichchi', + 'Lijiaxiang', + 'North Tustin', + 'Sycow', + 'San Severo', + 'Tugaya', + 'Luziania', + 'Bay', + 'Sete', + 'Torbat-e Heydariyeh', + 'Lerum', + 'Las Tunas', + 'Chalala', + 'Surat', + 'Tobias Barreto', + 'Svilengrad', + 'Viswanathaperi', + 'Duartina', + 'Basantpur', + 'Chikodi', + 'Joplin', + 'Hilongos', + 'Whitefish Bay', + 'Sisian', + 'Grimbergen', + 'Soham', + 'Bage', + 'Senlis', + 'Matungao', + 'Roche-a-Bateau', + 'Belfort', + 'Asarcik', + 'Alotenango', + 'Santa Catarina Ayotzingo', + 'Villa Tunari', + 'Dangcheng', + 'Sievierodonetsk', + 'Vigan', + 'Anahuac', + 'Iesolo', + 'Chandili', + 'Aleksandrow Lodzki', + 'Palkur', + 'Parwaha', + 'Machali', + 'Corleone', + 'Heemstede', + 'Vallehermoso', + 'Ermezinde', + 'Sedalia', + 'Guanxi', + 'Valea lui Mihai', + 'Montescaglioso', + 'Heerlerbaan', + 'Seika', + 'Tongxiao', + 'Ronneby', + 'Badou', + 'Andilana Avaratra', + 'Hope Mills', + 'Taiynsha', + 'Borgampad', + 'Gonder', + 'Weigelstown', + 'Boukhralfa', + 'Kurshab', + 'Bad Liebenwerda', + 'Hodal', + 'Franco da Rocha', + 'Gangtok', + 'Kamianka-Dniprovska', + 'Acilia', + 'Paks', + 'Dastgerd', + 'Montbeliard', + 'Molteno', + 'Lakshmipuram', + 'El Tabo', + 'North Massapequa', + 'San Juan Cotzal', + 'Buftea', + 'Freystadt', + 'Chiltiupan', + 'Jabera', + 'Ikizce', + 'Khurmi', + '`Ajlun', + 'Kalpitiya', + 'Idlib', + 'Yuza', + 'Gaohucun', + 'Lavis', + 'Olesnica', + 'Parnera', + 'Windorah', + 'Munnarkod', + 'Tuckahoe', + 'Schotten', + 'Blansko', + 'Carregal do Sal', + 'Okemos', + 'Central Coast', + 'Anjehalli', + 'West Hollywood', + 'Chanthaburi', + 'Barauna', + 'Chettinayakkanpatti', + 'Aomori', + 'Sukurhutu', + 'Tiruvalam', + 'Lisala', + 'Al Bajur', + 'Santa Filomena', + 'Padre Paraiso', + 'Boura', + 'Teocuitatlan de Corona', + 'Inowroclaw', + 'Nova Milanese', + 'Yalta', + 'Lukulu', + 'Ambila', + 'Oulad Hassoune', + 'Folignano', + 'Salaman', + 'Belem de Sao Francisco', + 'Khvaf', + 'Rio Bravo', + 'Kotri', + 'Bom Jesus', + 'Ambodibonara', + 'Balvi', + 'Jiaozishan', + 'Cubuk', + 'Cagnes-sur-Mer', + 'Harrow Weald', + 'Nantingcun', + 'Choctaw', + 'Adalaj', + 'Hoi An', + 'Chintamani', + 'Ajka', + 'Havelock', + 'Votuporanga', + 'Uta', + 'Incirliova', 'Ankazondandy', - 'Androrangavola', - 'Alarobia', - 'Inanantonana', - 'Ambalatany', - 'Andemaka', - 'Vohiposa', - 'Anjangoveratra', - 'Leanja', - 'Bekitro', - 'Ambohibe', - 'Tangainony', - 'Antsenavolo', - 'Analila', - 'Mangabe', - 'Baltit', - 'Tullinge', - 'Kafia Kingi', - 'Manafwa', - 'Buwama', - 'Sardoba', - 'Ishtixon Shahri', - 'Mong Duong', - 'Longji', - 'Koulamoutou', - 'Asara', - 'Dandu Mailaram', - 'Al Mazar ash Shamali', - 'Watrap', - 'Illingen', - 'Rumilly', - 'Chilgazi', - 'Weener', - 'Zemrane', - 'Neriyamangalam', - 'Dengka', - 'Dianga', - 'Usharal', - 'Caidat Sidi Boubker El Haj', - 'Youngsville', - 'Canmore', - 'East Finchley', - 'Ambohimalaza', - 'Guioyo', - 'Lewes', - 'Nanattuparai', - 'San Cesareo', - 'The Dalles', - 'Tasil', - 'Fussen', - 'Raiganj Bazar', - 'Hammam al `Alil', - 'Chornobaivka', - 'Yaypan', - 'Sao Lourenco da Serra', - 'St. Simons', - 'Vicente Guerrero', - 'Balneario do Rincao', - 'Saint-Amand-les-Eaux', - 'Jawalgeri', - 'Saint-Leu-la-Foret', - 'Kizhur', - 'Kudali', - 'Cruz Machado', - 'Ouamri', - 'Antadinga', - 'Este', - 'Yurihama', - 'Chittayankottai', - 'Neykkarappatti', - 'Mwingi', - 'Erlensee', - 'Finsterwalde', - 'Hayange', - 'Tuineje', - 'Chertsey', - 'Sukth', - 'Valavakattumula', - 'Mohanpur', - 'Amarwara', - 'Ambohidrapeto', - 'Bahutal', - 'Landen', - 'Zhytkavichy', - 'Kyabe', - 'Chivolo', - 'Viera West', - 'Ghomrassen', - 'Gentbrugge', - "L'Oulja", - 'Patapatnam', - 'Elbeuf', - 'Tagazhi', - 'Ishidoriyacho-eso', - 'Motru', - 'Mandiakui', - 'Coos Bay', - 'South Hayling', - 'Fontainebleau', - 'Valeggio sul Mincio', - 'Tarquinia', - 'Marco Island', - 'Suchteln', - 'Despujols', - 'Summerfield', - 'Alotau', - 'Androy', - "Stara L'ubovna", - 'Hongsi', - 'Brahmadesam', - 'Bellmore', - 'Alabat', - 'Schwarzenberg', - 'Campanha', - 'Manatanna', - 'Codru', - 'Konigslutter am Elm', - 'Gargzdai', - 'Apora', - 'Sertanopolis', - 'Xiaqiaotou', - 'Bailesti', - 'Penicuik', - 'Rasnov', - 'Cumaru', - 'Comarapa', - 'Middleburg Heights', - 'Dunaivtsi', - 'Verneuil-sur-Seine', - 'Ban Dung', - 'Karambakkudi', - 'Lakamane', + 'Ash Shunah ash Shamaliyah', + 'Skegness', + 'Kedu', 'Petite-Synthe', - 'Adwick le Street', - 'Alpine', - 'Quixelo', - 'Saint-Pierre-des-Corps', - 'Vlagtwedde', - 'Paso de Carrasco', - 'Sayalkudi', - 'Suchindram', - 'Nyasvizh', - 'Alexandreia', - 'San Giovanni in Fiore', - 'Kursumlija', - 'Calbuco', - 'Marmeleiro', - 'Lower Salford', - 'Schaesberg', - 'Heggadadevankote', - 'Fairhaven', - 'Haddada', - 'Aladag', - 'Piacabucu', - 'Bastogne', - 'Ostrov', - 'Zunil', - 'Sint-Kruis', - 'Eilendorf', - 'Walldorf', - 'Floral Park', - 'Greater Napanee', - 'Barentu', - 'Cerejeiras', - 'Skvyra', - 'Turffontein', - 'Vijayapuri North', - 'Wadern', - 'Gheorgheni', - 'Addlestone', - 'Vellikulangara', - 'Highland Village', - 'Lam Luk Ka', - 'Dighirpar', - 'Serta', - 'Concorezzo', - 'Benetuser', - 'Mahires', - 'Davutlar', - 'Brusciano', - 'Kulhudhuffushi', - 'Beek', - 'Drensteinfurt', - 'Kishundaspur', - 'Udayagiri', - 'Galvan', - 'Bar', - 'Sidi Allal el Bahraoui', - 'Alvaraes', - 'Villalbilla', - 'Gryfice', - 'Codroipo', - 'Mario Campos', - 'Prospect Heights', - 'Nidiyanga', + 'Mungeli', + 'Anjahabe', + 'Maceira', + 'Sakurai', + 'Talya', + 'Ochtrup', + 'Polur', + 'Wake Forest', + 'Bushenyi', + 'Yihezhuang', + 'Vega Baja', + 'East Goshen', + 'Serra Talhada', + 'Ribeira Grande', + 'Branquinha', + 'Chimakurti', + 'Smyrna', + 'Lamesa', + 'Tabuelan', + 'Tuxpam de Rodriguez Cano', + 'Satyamangalam', + 'El Sauce', + 'Nasrullahganj', + 'Acerra', + 'Horlivka', + 'Beloit', + 'Adigaratti', + 'Puraini', + 'Gueltat Sidi Saad', + 'Egra', + 'Comendador', + 'Verrieres-le-Buisson', + 'Novoberde', + 'Onchan', + 'Puri', + 'Oudtshoorn', + 'Ab Pakhsh', + 'Melouza', + 'Schoonhoven', + 'Quilicura', + 'Arlon', + 'Steinkjer', + 'Port Macquarie', + 'Inca', + 'Erkelenz', + 'Lebrija', + 'Mandla', + 'Brus Laguna', + 'Deniliquin', + 'Schramberg', + 'Mokhotlong', + 'Walbrzych', + 'Azarshahr', + 'Highland Springs', + 'Ambodilazana', + 'Timurni', + 'Corbera de Llobregat', + 'Sanand', + 'Lugu', + 'Plovdiv', + 'Nokia', + 'Emden', + 'Biganos', + 'Sao Joao do Triunfo', + 'Carrollton', + 'Qadian', + 'Lowenberg', + 'Hongshandian', + 'Sultanpur Mor', + 'Uusikaupunki', + 'Manosque', + 'Itapevi', + 'Saudade', + 'Russi', + 'Brecksville', + 'Abaran', + 'Abu Suwayr', + 'Laranjeiras do Sul', + 'Krasnyi Luch', + 'Chekkal', + 'Grimma', + 'Aksum', + 'Arari', + 'Bromborough', + 'Yufle', + 'Indio', + 'Xonobod', + 'Trairi', + 'The Pinery', + 'Wehrheim', + 'Martuni', + 'Burbank', + 'Muritiba', + 'Nieuw-Vennep', + 'Cannock', + 'Neuhausen am Rheinfall', + 'Rostamabad', + 'Broome', + 'Voru', + 'Asilah', + 'Fazendinha', + 'West Orange', + 'Sirigeri', + 'Gurmatkal', + 'Simplicio Mendes', + 'Ede', + 'Rolesville', + 'Ashtian', + 'Saint-Genis-Laval', + 'Morada Nova', + 'Rohri', + 'Easton', + 'Tonacatepeque', + 'Marmande', + 'Neratovice', + 'Mildenhall', + 'Telaprolu', + 'North Perth', + 'Vengat', + 'Shirako', + 'Khanewal', + 'Malitbog', + 'Uherske Hradiste', + 'Sinsheim', + 'Baguanos', + 'Guigang', + 'Kumarankari', + 'Minudasht', + 'Bilauri', + 'Sihushan', + 'El Dovio', + "Sant'Anastasia", + 'Puertollano', + 'Rotorua', + 'Douar Azla', + 'Tostedt', + 'Silkeborg', + 'Velakalnattam', + 'Malvik', + 'Redentora', + 'Kimhae', + 'Cankuzo', + 'Turuvanur', + 'Siliancun', + 'Davie', + 'Ouled Rahou', + 'Pederneiras', + 'Aviano', + 'Kwale', + 'Knik-Fairview', + 'Baiyashi', + 'Pendekallu', + 'Sarai Ranjan', + 'Appleton', + 'San Pedro', + 'Bautista', + 'Maurilandia', + 'San Giovanni in Persiceto', + 'East Bethel', + 'Slovenska Bistrica', + 'Caerdydd', + 'Satana', + 'Fakola', + 'Waukee', + 'Lindsay', + 'Bailleul', + 'Ventimiglia', + 'Zaltbommel', + 'Arua', + 'Mansingha', + 'Amauna', + 'Muridke', + 'Burgthann', + 'Kayapinar', + 'Kawachicho', + 'Jiuru', + 'Hartland', + 'Oberwingert', + 'Shiddapur', + 'Sherbrooke', + 'Divaca', + 'Tayum', + 'Trecate', + 'El Menzel', + 'Rawson', + 'Imaculada', + 'Mindat', + "L'Epiphanie", + 'Ambarimaninga', + 'Oststeinbek', + 'Kuala Terengganu', + 'Sankt Polten', + 'Pageralam', + 'Carmen de Viboral', + 'Kety', + 'Inhambupe', + 'Nonantola', + 'South Lake Tahoe', + 'Hiji', + 'Erbaocun', + 'Millis', + 'Chervonohrad', + 'Williamsport', + 'Son La', + 'Leon de los Aldama', + 'Kraulshavn', + 'Figuil', + 'Ritterhude', + 'Sahel', + 'Karaga', + 'Rosarno', + 'Chudamani', + 'Stonehaven', + 'Jataizinho', + 'Surdulica', + 'Veghel', + 'Oki', + 'Hoxter', + 'Memari', + 'Holubivske', + 'Texcoco', + 'Aja', + 'Bayyavaram', + 'Pueblo', + 'Fengcheng', + 'Mossingen', + 'Arinos', + 'Bedesa', + 'Dolenjske Toplice', + 'Shadegan', + 'Pontecorvo', + 'Camano', + 'Fairburn', + 'Villefranche-sur-Saone', + 'Maiduguri', + 'Roxas City', + 'Biddeford', + 'Sokone', + 'Aravelli', + 'Palikir', + 'Herford', + 'Otsego', + 'Kamiita', + 'Brambleton', + 'Hongsi', + 'Bamafele', + 'Al Qurayn', + 'Naousa', + 'Urdorf', + 'Esira', + 'Cachoeira do Sul', + 'Botevgrad', + 'Jamjamal', + 'Sowerby Bridge', + 'Remada', + 'Vistahermosa', + 'Los Lagos', + 'Abengourou', + 'Jean-Mermoz', + 'Parker', + 'Hisor', + 'Oulunsalo', + 'Aguilar', + 'Yuscaran', + 'Sedro-Woolley', + 'Lankaran', + 'Zaniena', + 'Lucerne', + 'Tortum', + 'Lynbrook', + 'Rasiari', + 'Trappes', + 'Kirkel', + 'Balakrishnanpatti', + 'Getafe', + 'Bad Vilbel', + 'Mankayan', + 'Trindade', + 'La Ceja', + 'Tacuba', + 'Tagbina', + 'Severna Park', + 'Canosa di Puglia', + 'Gasan', + 'Daiwanishi', + 'Polohy', + 'Qaraghandy', + 'Ziri', + 'San Antonio de Padua', + 'Rarott', + 'Itami', + 'Carapo', + 'La Cruz de Rio Grande', + 'Ruskin', + 'Camooweal', + 'Barika', + 'Tohoku', + 'Pante Macassar', + 'Vocklabruck', + 'Erutukada', + 'Koili Simra', + 'Edea', + 'Targoviste', + 'Antanankambano', + 'Bangzha', + 'Bankass', + 'Podstrana', + 'Kakuma', + 'Quezaltepeque', + 'Schaan', + 'Daxincun', + 'Trikodi', + 'Yawatahama-shi', + 'Pefki', + 'The Hague', + 'Tamu', + 'Guli', + 'Shing', + 'Bakersfield', + 'Lanxi', + 'Singaparna', + 'Aljustrel', + 'Chirchiq', + 'Rio Acima', + 'Halstenbek', + 'Pandhurna', + 'Boa Nova', + 'Cerkvenjak', + 'Saint-Jean-le-Blanc', + 'Largo', + 'Basse-Terre', + 'Jimalalud', + 'Bhanas Hivre', + "Sant'Ilario d'Enza", + 'Santa Lucia Utatlan', + 'Parasurampur', + 'New Providence', + 'Sofiivka', + 'Ban Muang Kham', + 'Pingdu', + 'Kyle', + 'Nellutla', + 'Hualqui', + 'New City', + 'Tangancicuaro de Arista', + 'Brawley', + 'Rucheng', + 'Bendorf', + 'Steinen', + 'Welby', + 'Valentigney', + 'Jacinto City', + 'Mweka', + 'Baler', + 'Sasso Marconi', + 'Fanzeres', + 'Sunrise', + 'Ovidiopol', + 'Canarana I', + 'Jaitwar', + 'Settat', + 'Villa Paranacito', + 'Lerdo de Tejada', + 'Westerstede', + 'Rangapukur', + 'Vinukonda', + 'Mastaga', + 'Terrasini Favarotta', + 'El Fuerte', + 'Heydarabad', + 'Rapperswil-Jona', + 'Preston', + 'Mahasamund', + 'Bossier City', + 'Kotamobagu', + 'Sowme`eh Sara', + 'Charala', + 'Gayeri', + 'Calape', + 'Villa Rica', + 'Panying', + 'Khandauli', + 'Oristano', + 'Ar Ramtha', + 'Ben Gardane', + 'Donnacona', + 'Bagamoyo', + 'Caras', + 'Chikha', + 'Kalikavu', + 'Lewiston', + 'Maseru', + 'Huanchaco', + 'Higuerote', + 'Yangshe', + 'Salinas Victoria', + 'Marofoty', + 'Yamen', + 'Hyderabad City', + 'Gusang', + 'Mexicali', + 'Yedtare', + 'Salgado de Sao Felix', + 'Gaffney', + 'Torcy', + 'Hodos', + 'Sangerhausen', + 'Tsuruta', + 'Bladensburg', + "Sach'on", + 'Sabanozu', + 'Agustin Codazzi', + 'Kings Park West', + 'Periyamuttur', + 'Varnsdorf', + 'Akbez', + 'The Woodlands', + 'Puente Nacional', + 'Golcuk', + 'Sandbach', + 'Tullamore', + 'Chimalhuacan', + 'Kula', + 'Oliveira de Frades', + 'Yuasa', + 'Jieyang', + 'Conceicao de Jacuipe', + 'Pezinok', + 'Malgrat de Mar', + 'Ceske Budejovice', + 'Qapshaghay', + 'Membakut', + 'General Acha', + 'Studenka', + 'Cleveland', + 'Mehnajpur', + 'Darasuram', + 'Rubengera', + 'Kusadasi', + 'Buddh Gaya', + "Clermont-l'Herault", + 'Bifeng', + 'Nakama', + 'Kuiju', + 'Scheessel', + 'Kajo Kaji', + 'Medina Estates', + 'Pointe-Claire', + 'Savannakhet', + 'Yarumal', + 'Saint-Egreve', + 'Sokoto', + 'Timonium', + 'Tire', + 'Ota', + 'Otwock', + 'Pretoria-Noord', + 'Iziaslav', + 'Bell Gardens', + 'Ecija', + 'Khunays', + 'Kottaipatti', + 'Garin', + 'Tuktukan', + 'Ibara', + 'Tyre', + 'Casteldaccia', + 'Gulgam', + 'Jaffna', + 'Gariadhar', + 'Zoetermeer', + 'Kasulu', + 'Santo Antonio dos Lopes', + 'Pannawonica', + 'Cajuru', + 'Belchertown', + 'Sonseca', + 'Non Sung', + 'Kardla', + 'Furstenfeldbruck', + 'Ban Tat', + 'Bydgoszcz', + 'Semere', + 'Fortuna', + 'Corralillo', + 'Coin', + 'Siegburg', + 'Comacchio', + 'Bellavista', + 'Mission Bend', + 'Avezzano', + 'Rancho Mission Viejo', + 'Mechraa Bel Ksiri', + 'Shirebrook', + 'Kizhariyur', + 'Bueng Kan', + 'Matigou', + 'Misratah', + 'Deventer', + 'Luau', + 'Kiratpur Rajaram', + 'Huanuni', + 'Kannamanayakkanur', + 'Kluczbork', + 'North Battleford', + 'Lukaya', + 'Bo`ka', + 'Baicheng', + 'Channahon', + 'Terrace Heights', + 'Uniao', + 'Kunigal', + "Porto Sant'Elpidio", + 'Marin', + 'Bimun', + 'Dilijan', + 'Satkhira', + 'Erie', + 'Hemsworth', + 'Gueppi', + 'Urubici', + 'Daraw', + 'Kastoria', + 'Yutz', + 'Lichtenstein', + 'Unquillo', + 'Homewood', + 'Accrington', + 'Kalyanpur', + 'Diego de Almagro', + 'Beeville', + 'Koila', + 'Hathiakan', + 'Coka', + 'Bouake', + 'Veyrier', + 'Akhaltsikhe', + 'Tinaquillo', + 'Moncada', + 'Gladbeck', + 'Telpaneca', + 'Central Elgin', 'Vari', - 'Tupi Paulista', - 'Baghlia', - "Hammam M'Bails", - 'Demerval Lobao', - 'Valabhipur', - 'Toma', - 'Sahambala', - 'Toul', - 'Dembeni', - 'Gatesville', - 'Lonigo', - 'Tamazouzt', - 'Xiaozhengzhuang', - 'Pawai', - 'Indianola', - 'La Lucila', - 'Osowa', - 'Jatauba', - 'Gandevi', - 'Brofodoume', - 'Chhapra Bahas', - 'Simmerath', - 'Saint-Julien-en-Genevois', - 'Dassari', - 'Taromske', - 'Odaiyakulam', - 'Overland', - 'Bruck an der Mur', - 'Vatomandry', - 'Mandialaza', - 'Hadjadj', - 'Kavarna', - 'Feke', - 'Rypin', - 'Le Pecq', - 'Hugo', - 'Miedzyrzec Podlaski', - 'Zhutian', - 'Elkton', - 'Dhusar Tikapatti', - 'Srimushnam', - 'Seven Oaks', - 'Kodikkulam', - 'Vallirana', - 'Kadamakudi', - 'Ascheberg', - 'Ban Samo Khae', - 'Port Orchard', - 'Rutland', - 'Tlaltetela', - 'Tapiramuta', - 'Pewaukee', - 'Lake Country', - 'Colonia Leopoldina', - 'Taucha', - 'Ropczyce', - 'Grottammare', - 'Tanakpur', - 'Saviano', - 'Opelousas', - 'Joao Neiva', - 'Kabayan', - 'Ash Shaddadah', - 'Serinyol', - 'Niceville', - 'Haftkel', - 'Cadoneghe', - 'Lentate sul Seveso', - 'Ixhuatlan del Sureste', - 'Adrasmon', - 'Maliana', - 'Cholai', - 'Tarancon', - 'Victor', - 'Whakatane', - 'Diang', - 'Breisach am Rhein', - 'Salonta', - 'Puluvappatti', - 'Dhani Sukhan', - 'Centre de Flacq', - 'Belaur', - 'Kunithala', - 'Longmeadow', - 'Dhumnagar', - 'Vardannapet', - 'Oarai', - 'Krapkowice', - 'Palagiano', - 'Waterville', - 'Palagonia', - 'Altopascio', - 'Kandla Port', - 'Chethakal', - 'Mahudha', - 'Ras El Oued', - 'San Bartolome Jocotenango', - 'Macedo de Cavaleiros', - 'Yorito', - 'Rahden', - 'Lara', - 'Ouadhia', - 'Ain Mediouna', - 'Ramada', - 'Miguelturra', - 'Laurentides', - 'Goubellat', - 'Garrel', - 'Novo Airao', - 'Gonohe', - 'Kannampalaiyam', - 'Al Mu`abbadah', - 'Pijino del Carmen', - 'Mansingha', - 'Sulat', - 'Akambadam', - 'Kalanadu', - 'Rupbas', - 'Kasimkota', - 'Uusikaupunki', - 'San Antonio Palopo', - 'Vieux Fort', - 'Patton', - 'Diafarabe', - 'Vendome', - 'Hennebont', - 'Sonapur', - 'Herisau', - 'Ardestan', - 'Quimavango', - 'General Pinedo', - 'Northallerton', - 'Titel', - 'Thibodaux', - "Sered'", - 'Itatim', - 'Susanville', - 'Santa Juliana', - 'Mirangaba', - 'Lindas', - 'Trisshileri', - 'Usuda', - 'Toyoyama', - 'Hille', - 'Correia Pinto', - 'Guasca', - 'Puduppatti', - 'Minamiminowa', - 'Lubbenau/Spreewald', - 'Lymington', - 'Carugate', - 'Orizona', - 'La Montanita', - 'Dubacherla', - 'Whitewater', - 'Vynnyky', + 'Plonsk', + 'Chateau-Thierry', + 'Schkopau', + 'Nawalpur', + 'Jagatpur', + 'La Ceiba', + 'Omuthiya', + 'Soalandy', + 'Kimberley', + 'Kappiyara', + 'Hyattsville', + 'Shichigahama', + 'Koronowo', + 'Modra', + 'Manolo Fortich', + 'Neuilly-sur-Marne', + 'San Juanito', + 'Sedhiou', + 'Pailon', + 'Vechta', + 'Schortens', + "Qia'erbagecun", + 'Coalinga', + 'Plankstadt', + 'Cachoeira Alta', + 'Grand Prairie', + 'Ulsan', + 'Bouguenais', 'Campina da Lagoa', - 'Baeza', - 'Lynden', - 'Ribnitz-Damgarten', - 'North Strabane', - 'San Jacinto Amilpas', - 'Zulte', - 'Tarur', - 'Maruim', - 'Langenberg', - 'Eravattur', - 'Newberry', - 'Bharanikavu Tekku', - 'Wolf Trap', - 'Coelemu', - 'Mennecy', - 'Sahar', - 'Steffisburg', - 'Castillo', - 'Morges', - 'Mwinilunga', - 'Pochampalli', - 'Hayden', - 'North Whitehall', - 'Southern Pines', + 'Sorong', + 'Churumuco de Morelos', + 'Byron Bay', + 'Sarny', + 'Bilbays', + 'Patiali', + 'Milagro', + 'Kothri Kalan', + 'Idaho Falls', + 'Bombo', + 'Muttunayakkanpatti', + 'Nidamanuru', + 'Countryside', + 'Buu Long', + 'Capitan Bado', + 'Surpur', + 'Reggane', + 'Campi Bisenzio', + 'Anantasagaram', + 'Salto Grande', + 'Baduria', + 'Echague', + 'Hollywood', + 'Rahat', + 'Lower Paxton', + 'Trebbin', + 'Wardha', + 'Beek en Donk', + 'Vilhena', + 'Bergeijk', + 'Chhapia', + 'Ganaram', + 'Chhanera', + 'Kapangan', + 'Roncade', + 'Walcourt', + 'Waltenhofen', + 'Bahar', + 'Oiba', + 'Willoughby', + 'Babol', + 'Alashankou', + 'Groton', + 'Ban Talat Rangsit', + 'Neijiang', + 'Johvi', + 'Ulao', + 'Nagold', + 'Lacey', + 'Marigot', + 'Zabljak', + 'Atushi', + 'Pileru', + 'Borodyanka', + 'Guaymate', + 'Alakamisy Anativato', + 'Montecchio Maggiore', + 'Umea', + 'Mekambo', + 'Jericho', + 'Urrao', + 'Conceicao do Mato Dentro', + 'Cutro', + 'Narayankher', + 'Ocoyoacac', + 'Las Margaritas', + 'North Cornwall', + 'Katiena', + 'Liangwancun', + 'Tarawan', + 'Tianjin', + 'Eltham', + 'Ampitasimo', + 'Patzcuaro', + 'Boortmeerbeek', + 'Zary', + 'New Tecumseth', + 'Izki', + 'Faradonbeh', + 'Ezine', + 'Mushie', + 'Kuvango', + 'La Quiaca', + 'Tamgrout', + 'Buenos Aires', + 'Khowrhesht', + 'Muskegon Heights', + 'Wangsicun', 'Kimwanyi', - 'Beko', - 'Dieburg', - 'Taima', - 'Hilvarenbeek', - 'Niepolomice', - 'Ebersbach an der Fils', - 'Si Satchanalai', - 'Turkaguda', - 'Damdama', - 'Grain Valley', - 'Bucimas', - 'Beernem', - 'Aabenraa', - 'Xixucun', - "'Ain el Arbaa", - 'Todi', - 'Ifanadiana', - 'Azzano Decimo', - 'Beaucaire', - 'Carterton', - "Nova Brasilandia d'Oeste", - 'Mount Clemens', - 'Binningen', - 'Yakumo', - 'Tiran', - 'Copparo', - 'Dhanot', - 'Renai', - 'Melonguane', - 'Namala Guimbala', - 'Bayt Saham', - 'Hedongcun', - 'Bububu', - 'Ponders End', - 'Ince-in-Makerfield', - 'Tsukumiura', - 'Colorado do Oeste', - 'Gaillac', - 'Wenwu', - 'Valmontone', - 'Bhit Bhagwanpur', - 'Kajha', - 'Dhemaji', - 'Soavina', - 'Mitchell', - 'Mecitozu', - 'Schiffweiler', - 'Marivorahona', - 'Arkivan', - 'Mindelheim', - 'Shchuchyn', - 'Ochiai', - 'Zarah Sharan', - 'Ban Tha Pho', - 'Northborough', - 'Le Vesinet', - 'Mvurwi', - 'Bengonbeyene', - 'Mezotur', - 'Balkonda', - 'Nioro du Rip', - 'Campulung Moldovenesc', - 'Ostroh', - 'Chenlu', - 'Baile an Bhiataigh', - 'Donacarney', - 'Yazu', - 'Capilla de Guadalupe', - 'Porthcawl', - 'Leso', - 'Chubbuck', - 'Molinella', - 'Jiaojiazhuang', - 'Toui', - 'Manujan', - 'Langenau', - 'Rajapur', - 'Coto de Caza', - 'Nailsea', - 'Manjil', - 'Boudjima', - 'Longwood', - 'Guinguineo', - 'Dammaj', + 'Narra', + 'Belton', + 'Khlong Luang', + 'Barhadashi', + 'Ixtlahuacan de los Membrillos', + 'Lauterbach', + 'Mohda', + 'Chepstow', + 'Blegny', + 'Reykjavik', + 'Jangalapalle', + 'Cumayeri', + 'Tarashcha', + 'Cervera', + 'Pouso Redondo', + 'Bunde', + 'Bariyarpur', + 'Zweibrucken', + 'Alzenau in Unterfranken', + 'Santo Tomas', + 'Taxtako`pir', + 'Colinas do Tocantins', + 'Vryburg', + 'Hooksett', + 'Rahui', + 'Daejeon', + 'Chinaval', + 'Pornichet', + 'Hazelwood', + 'Sherkot', + 'Shuishang', 'Palmitos', - 'Leopoldsburg', - 'Langenthal', - 'Loma de Cabrera', - 'Serpa', - 'Mayoyao', - 'Ashikita', - 'Cheramkod', - 'Solapuram', - 'Sukhothai', - 'Porto San Giorgio', - 'Tobetsu', - 'Dragasani', - 'Boppard', - 'Kara-Kulja', - 'Frecheirinha', - 'Fort Leonard Wood', - 'Tatahuicapan', - 'Rakvere', - 'Oswestry', - 'Jurawanpur Karari', - 'Olmue', - 'Dewangarh', - 'Mangqu', - 'Molnlycke', - 'Narendrapatnam', - 'Kolakaluru', - 'Antarvedi', - 'Sin-le-Noble', - 'Calumpang', - 'Luce', - 'Chembagaramanpudur', - 'Bilpura', - 'Porto Empedocle', - 'Templin', - 'Ermua', - 'Julita', - 'Shively', - 'Cumru', - 'Ponsacco', - 'Mouiat Ouennsa', - 'Sundarpur', - 'Crusinallo', - 'Dalanping', - 'Shizukuishi', - 'Mezokovesd', - 'Bhagta', - 'Bhagwangola', - 'Galliate', - 'Pozos', - 'Princeton Meadows', - 'Red Hill', - 'Baynala', - 'Akdepe', - 'Maullin', - 'Najasa', - 'Zevio', - 'Sebt Bni Smith', - 'Cosio', - 'Ban Pang Mu', - 'Kadaiyam', - 'Belo', - 'Kompalle', - 'Rakovnik', - 'Chamgardan', - 'Yigilca', - 'Southchase', - 'Cochoapa el Grande', - 'Ernagudem', - 'Juma Shahri', - 'Ipua', - 'Kasagi', - 'San Miguel Duenas', - 'Tung Tau Tsuen', - 'Miyota', - 'Vatluru', - 'Pequannock', - 'Canapi', - 'Bad Neustadt', - 'Frei Paulo', - 'Eppelheim', - 'El Chal', - 'Edakkazhiyur', - 'Puerto Pimentel', - 'Kezmarok', - 'Jasol', - 'West Ham', - 'Einsiedeln', - 'Chittur', - 'Saligrama', - 'Agrate Brianza', - 'Santa Cecilia', - 'Ponnamaravati', - 'Qaryat Suluq', - 'Scottsboro', - 'La Roda', - 'Ayas', - 'My Luong', - 'Palhalan', - 'Codogno', - 'Greenwood Village', - 'Rakhiv', - 'Souagui', - 'Kukkundur', - 'Sanatikri', - 'Kumaralingam', - 'Bissegem', - 'Bituruna', - 'Tidjikja', - 'Anar', - 'Kyazanga', - 'Wattignies', - 'Nannestad', - 'Wanda', - 'North Reading', - 'Itariri', - 'Lwengo', - 'Igapora', - 'Sainte-Luce-sur-Loire', - 'Bredasdorp', - 'Dastgerd', - 'Los Osos', - 'Rendon', - 'Aleg', - 'Hofgeismar', - 'Edinet', - 'Matlock', - 'Bokoro', - 'Kucevo', - 'Diapaga', - 'Lahoysk', - 'Certaldo', - 'Ebn Ziad', - 'Aldine', - 'Lezhe', - 'Palanisettipatti', - 'Sayo', - 'Sirali', - 'Meghauna', - 'Morteza Gerd', - 'Zhuolan', - 'Teodoro Schmidt', - 'Saffron Walden', - 'Rossville', - 'Kifosso', - 'Buston', - 'Cherryland', - 'Pipra Latif', - 'Kanan', - 'Nobres', - 'Pudtol', - 'Patilar', - 'Daigo', - 'Kurawar', - 'Banqiao', - 'Asthanwan', - 'Casalpusterlengo', - 'Vemuladivi', - 'Mauranwan', - 'Dejen', - 'Shipley', - 'Linguere', - 'Ain el Hadid', - 'Ternat', - 'Todmorden', - 'Skhour Rehamna', - 'Tizi-n-Tleta', - 'Tiszaujvaros', - 'White Center', - 'Overpelt', - 'Funyan Bira', - 'Maskanah', - 'Verkhnodniprovsk', - 'Pichhor', - 'Lajkovac', - 'Seekonk', - 'Nkouraba', - 'Budakeszi', - 'Isorana', - 'Ambaguio', - 'Moreni', - 'Skalica', - 'Ban Nong Kathao', - 'Fos-sur-Mer', - 'Hiep Hoa', - 'Traverse City', - 'Mainburg', - 'Sabana Grande de Palenque', - 'Corbera de Llobregat', - 'Sarai Jattan', - 'Amboavory', - 'Sagala', - 'Baiceng', - 'Neustadt in Holstein', - 'Kyzyl-Suu', - 'Ban Duea', - 'Altunhisar', - 'Noisiel', - 'Guipavas', - 'Udala', - 'Solec Kujawski', - 'Greeneville', - 'Yesilova', - 'Montivilliers', - 'Differdange', - 'Sandhausen', - 'Turhapatti', - 'Csongrad', - 'Phulaut', - 'Bilgi', - 'Pianezza', - 'Rosario Oeste', - 'Stapleford', - 'Soliera', - 'Kinna', - 'Mitrapur', - 'Weybridge', - 'Chilamatturu', - 'Ilovaisk', - 'Kestel', - 'Ventaquemada', - 'Santa Cruz de la Palma', - 'Knaresborough', - 'Kambaduru', - 'Bemidji', - 'Romit', - 'Broxburn', - 'Al Hammam', - 'Arumbavur', - "Bois-d'Arcy", - 'Cipanas', - 'Uthai Thani', - 'Jiblah', - 'Ezzhiliga', - 'Anazzou', - 'Estrela de Alagoas', - 'Dilarpur', - 'Nedumudi', - 'Northview', - 'Gehrden', - 'Ala-Buka', - 'Dacheng', - 'Nymburk', - 'Nuth', - 'Tarascon', - 'Manohisoa', - 'Yankton', - 'Saint-Rambert', - 'Odanavattam', - 'Vipparla', - 'Machelen', - 'Khao Yoi', - 'Efkarpia', - 'Bugganipalle', - 'Bruntal', - 'Clark', - 'Hartselle', - 'Tari', - 'Spittal an der Drau', - 'Robbinsville', - 'Tururu', - 'Nancagua', - 'Ezine', - 'Blomberg', - 'Sorrento', - 'Kerouane', - 'Dison', - 'Messias', - 'Zabbar', - 'Meco', - 'Chokkanathapuram', - 'Potenza Picena', - 'Grimes', - 'Andrakata', - 'Khampat', - 'Siladon', - 'Sodag', - 'Lal Khatanga', - 'Khijri', - 'Nova Olinda', - 'Malhada', - 'Landazuri', - 'Besana in Brianza', - 'Tendrara', - 'Jamao al Norte', - 'Seacombe', - 'Ac-cahrij', - 'Magdiwang', - 'Kurdamir', - 'Butiama', - 'Ambongamarina', - 'Ban Khek Noi', - 'Jelcz-Laskowice', - 'Samsikapuram', - 'Bradley', - 'Raspur Patasia', - 'Fraga', - 'Strzegom', - 'Gopalnagar', - 'Ayutla de los Libres', - 'Robinson', - 'San Policarpo', - 'Homosassa Springs', - 'Cruzilia', - 'Discovery Bay', - 'Putaendo', - 'Silvi Paese', - 'Thoen', - 'Baildon', - 'Kot Bhai', - 'Mortara', - 'Trelaze', - 'Talainayar Agraharam', - 'Lopare', - 'Kocakoy', - 'Urandi', - 'Rajgadh', - 'Frattaminore', - 'Genappe', - 'Tanhuato de Guerrero', - 'Mateszalka', - 'Sava', - 'Viseu de Sus', - 'Eden', - 'Dvur Kralove nad Labem', - 'Anao-aon', - 'San Luis del Palmar', - 'Kumaramputtur', - 'Bambous', - 'Amatitan', - 'Moul El Bergui', - 'Uvalde', - 'Bunnik', - 'Castro Daire', - 'Perivale', - 'Semra', - 'Bennington', - 'Kanegasaki', - 'Gomboussougou', - 'Chhajli', - 'Winkler', - 'Israin Kalan', - 'Khamir', - 'Fruitville', - 'Bad Bramstedt', + 'Erin', + 'Lagoa do Itaenga', + 'Uthal', + 'Whippany', + 'Zamboanguita', + 'Kasugai', + 'Kuurne', + 'Embarcacion', + 'Alsfeld', + 'Saint-Avertin', + 'Lokwabe', + 'Bronte', + 'Gemerek', + 'Diamond Bar', + 'Germantown', + 'Tengampudur', + 'Myanaung', + 'Amritpur', + 'Manhattan Beach', + 'Spring Valley Lake', + 'Niangoloko', + 'Crevalcore', + 'Bamble', + 'Hollabrunn', + 'Furtwangen im Schwarzwald', + 'Ariquemes', + 'Baruari', + 'Paura Madan Singh', + 'Bracknell', + 'Le Bouscat', + 'Pirapozinho', + 'Puyappalli', + 'Zhengjiatun', + 'Garibaldi', + 'Aydin', + 'Sestri Levante', + 'Panjampatti', + 'Chengbin', + 'Ambohitrambo', + 'Olympia Heights', + 'Fuxin', + 'Jupiter Farms', + 'Birjand', + 'Sugauna', + 'Villa La Angostura', + 'Abu Hummus', + 'Igreja Nova', + 'Sanghera', + 'Tremembe', + 'Bhopalia', + 'Vila Velha', + 'Papampeta', + 'Dhanga', + 'Sheyban', + 'Jaltenango', + 'Tagapul-an', + 'Kulusuk', + 'Montesson', + 'Chascomus', + 'Guernica y Luno', + 'Itamarati', + 'Metepec', + 'Wadersloh', + 'Costa Marques', + 'Barod', + 'Bhaisalotan', + 'Velez-Malaga', + 'Raunds', + 'Hushihacun', + 'Sindgi', + 'Quivican', + 'Ivoti', + 'Maroteza', + 'Bazar-Korgon', + 'Baduriatola', + 'Tysons', + 'Saidapet', + 'Busto Arsizio', + 'Cabanatuan City', + 'Sami', + 'Logansport', + 'Besozzo', + 'Sonaguera', + 'Acevedo', + 'Harbiye', + 'Prairie Ridge', + 'Kasaragod', + "Hosa'ina", + 'Borgo San Dalmazzo', + 'Cockeysville', + 'Kabirpur', + 'Mikuszowice', + 'Kamiichi', + 'Arsali', + 'Enugu', + 'Sahanivotry-Manandona', + 'Savar', + 'Al Khubar', 'Haddon', - 'Ratekau', - 'Basarh', - 'Jupi', - 'Maddikera', - 'Odenthal', - 'Amanganj', - 'Undi', - 'Villa Paranacito', - 'Bandar-e Khamir', - 'Inhuma', - 'Wombwell', - 'Sao Joao Evangelista', - 'Burbach', - 'Pihra', - 'Maydolong', - 'Atalaia do Norte', + 'Allahdurg', + 'Rodynske', + 'Puduru', + 'Jiquirica', + 'Kirishima', + 'Skive', + 'Aj Jourf', + 'Uedem', + 'Cananea', + 'Stryzhavka', + 'Bankapur', + '`Afrin', + 'Saint-Colomban', + 'Imperia', + 'Valsequillo de Gran Canaria', + 'Jette', + 'Hamm', + 'Piranga', + 'Rixheim', + 'Currimao', + 'Opuwo', + 'Herohalli', + 'Larreynaga', + 'Gravina in Puglia', + 'Benton Harbor', + 'Afragola', + 'Castelldefels', + 'Lubao', + 'Brahmanbaria', + 'Barkly West', + 'San Rafael del Norte', + 'Abu Dhabi', + 'Mamburao', + 'Chartres', + 'Hawick', + 'Shiruru', + 'Butajira', + 'Newcastle', + 'Igarape-Miri', + 'San Mariano', + 'Statesboro', + 'Cachoeira do Arari', + 'Goumori', + 'Kassaro', + 'Karaisali', + 'Yoshida', + 'Stekene', + 'Walajabad', + 'Alcorcon', + 'Seneca', + 'Cabagan', + 'Mansfield', + 'Valsad', + 'Monaragala', + 'Barro', + 'Assebroek', + 'Al Mubarraz', + "L'Isle-d'Abeau", + 'Cajueiro', + 'Wanstead', + 'Iten', + 'Salamina', + 'Jacinto Machado', + 'Kuyganyor', + 'Ar Rusayfah', + 'Morgantown', + 'Balta', + 'Anse-a-Foleur', + 'Crnomelj', + 'Dagbe', + 'Nubl', + 'Isumi', + 'Arumbavur', + 'Lohuti', + 'Backa Palanka', + 'Marktoberdorf', + 'Massango', + 'Gamay', + 'Asbury Park', + 'Piracicaba', + 'Tadas', + 'Malanvadi', + 'Ranko', + 'Falam', + 'Kerava', + 'Brevik', + 'Fort Madison', + 'San Pablo Villa de Mitla', + 'La Resolana', + 'Irun', + 'Santa Juana', + 'Senirkent', + 'Colbun', + 'Chasiv Yar', + 'Bailleston', + 'Mairwa', + 'Ba Don', + 'Caetanopolis', + 'Popovo', + 'Bandipura', + 'Brewer', + 'Raesfeld', + 'Chityal', + 'Bois-Guillaume', + 'Miahuatlan de Porfirio Diaz', + 'Eupen', + 'Riemst', + 'Reims', + 'Menen', + 'Wundanyi', + 'Guarenas', + 'Biankouma', + 'Vila Bela da Santissima Trindade', + 'Pallappalaiyam', + 'Farmington', + 'Bradenton', + 'Singoli', + 'Cainta', + 'Farahalana', + 'Simoes Filho', + 'San Zenon', + 'Planadas', + 'Catole do Rocha', + 'Solrod Strand', + 'Rovinj', + 'Dracena', + 'Jablonec nad Nisou', + 'Chhagalnaiya', + 'Ampataka', + 'Lohagara', + 'Zarautz', + 'Tiquisio', + 'Epinay-sous-Senart', + 'Soka', + 'Gandarbal', + 'Los Muermos', + 'Akyaka', + 'Az Zaqaziq', + 'Ibaretama', + 'San Jose Guayabal', + 'Phulparas', + 'Unity', + 'Anderson', + 'Post Falls', + 'Bandio', + 'Quiindy', + 'Mazoe', + 'Gokarna', + 'Weston-super-Mare', + 'Donihue', + 'Maliano', + 'Sahibganj', + 'Stropkov', + 'Williston', + 'Khutauna', + 'Mishrikot', + 'Rice Lake', + 'Boa Viagem', + 'Ashkhaneh', + 'Wabag', + 'Ban Mangkon', + 'Bognor Regis', + 'Alabel', + 'Hoor', + 'Perote', + 'Sotkamo', + 'Mukondapalli', + 'Kenzingen', + 'El Alia', + 'Barssel', + 'Libon', + 'Pljevlja', + 'Karumulaikkal', + 'Atlatlahucan', + 'Puteaux', + 'Ramnicu Sarat', + 'Karariya', + 'Floro', + 'Richard-Toll', + 'Semuto', + 'Jilotlan de los Dolores', + 'Nellikkuppam', + 'Malsch', + 'Khowrasgan', + 'Ambodimahabibo', + 'Safidon', + 'Canoinhas', + 'Ban Na Yang', + 'Kuttur', + 'Makubetsu', + 'Tsavo', + 'Guape', + 'Mapleton', + 'Sao Sebastiao da Grama', + 'Cannanore', + 'Sama', + 'Vail', + 'Alwar', + 'Cherlagandlapalem', + 'Zyryanovsk', + 'Kopong', + 'Wabrzezno', + 'Antsampanimahazo', + 'Forney', + 'Obock', + 'Banstead', + 'Kovurupalli', + 'Bientina', + 'Le Creusot', + 'Bontang', + 'Pierre', + 'Sidi Aissa', + 'San Ignacio Cerro Gordo', + 'Lancon-Provence', + 'Sao Bento do Sul', + 'Arkadelphia', + 'Lalru', + 'Neriyamangalam', + 'Kwai Chung', + 'Matsubara', + 'Metapan', + 'Hopatcong', + 'Baniyas', + 'Song Phi Nong', + 'Labason', + 'Kashima', + 'Bafanji', + 'Isola del Liri', + 'Las Rozas de Madrid', + 'Herdecke', + 'Ait Bousarane', + 'Itanhandu', + 'Odemis', + 'Mohgaon', + 'Bilgoraj', + 'Poquoson', + 'Dilolo', + 'Soliman', + 'Videira', + 'Sankt Augustin', + 'Hachimantai', + 'Oneida', + 'Medeiros Neto', + 'Sakri', + 'Chestnut Ridge', + 'Burubaytal', + 'Oruro', + 'Beauraing', + 'Mauli', + 'Curanilahue', + 'Great Neck', + 'Skofja Loka', + 'Aiken', + 'Roncador', + 'Temuco', + 'Oros', + 'Timmapur', + 'Kununurra', + 'Naqadeh', + 'Clarin', + 'Podgorica', + 'Beldanga', + 'Mutluru', + 'South Whitehall', + 'Prince Rupert', + 'Nirasaki', + 'Hodatsushimizu', + 'Trani', + 'Voghera', + 'Purkersdorf', + 'Medapadu', + 'Puerto Francisco de Orellana', + 'Fatao', + 'Sidi Yahia El Gharb', + 'Spiez', + 'Pujili', + 'Renk', + 'Quemado de Guines', + 'Antenetibe', + 'Rueil-Malmaison', + 'Saimbeyli', + 'Asagi Quscu', + 'Tsarahasina', + 'Hunasagi', + 'Chilpancingo', + 'Goycay', + 'Republic', + 'Bocholt', + 'Montgeron', + 'Dodji-Bata', + 'Panzgam', + 'Joinville-le-Pont', + 'Fergus', + 'Tenkasi', + 'Groveland', + 'El Carmen de Atrato', + 'Garou', + 'Sangao', + 'Buffalo', + 'Oulad Amrane el Mekki', + 'Bethune', + 'Sidfa', + 'Cuichapa', + 'Maria Aurora', + 'Sanzana', + 'Vaxjo', + 'Tsrar Sharif', + 'Samut Sakhon', + 'Novate Milanese', + 'Mirdaul', + 'Broadview Heights', + 'Domaa-Ahenkro', + 'Herseh Chhina', + 'Tupa', + 'Porec', + 'Mount Evelyn', + 'Balboa Heights', + 'Xuqiaocun', + 'Sumbawa Besar', + 'Nahiyat Khan Bani Sa`d', + 'Danli', + 'Bartin', + 'Feyzin', + 'Peruvanthanam', + 'Chene-Bougeries', + 'Malakal', + 'North Middleton', + 'Hauzenberg', + 'Datteln', + 'Goiatuba', + 'Solan', + 'Ol Kalou', + 'Kaedi', + 'Sakib', + 'Reyes', + 'Freudenstadt', + 'Anamalais', + 'Chengxiang', + 'Ely', + 'Monmouth', + 'Fukude', + 'Nepanagar', + 'Bousse', + 'Emba', + 'Ghusiya', + 'Noisiel', + 'Barharia', + 'Techiman', + 'Castilho', + 'Higashi-osaka', + 'Kerugoya', + 'Bouaiche', + 'Laurel', + 'Suluktu', + 'Hanzviur', + 'Rosrath', + 'Ciro Marina', + 'Cabanillas del Campo', + 'Qahjavarestan', + 'Zuidhorn', + 'Beilen', + 'Minami-Soma', + 'Douentza', + 'Florianopolis', + 'Darende', + 'Catanduva', + 'Wao', + 'Rasingapuram', + 'Huodoushancun', + 'Fontaine-les-Dijon', + 'Shinyanga', + 'Sargodha', + 'Penfield', + 'Dunaujvaros', + 'Ube', + 'Ain Dfali', + 'Andrembesoa', + 'Kochas', + 'Kondalampatti', + 'Khejroli', + 'Manassas', + 'Macaiba', + 'Uson', + 'Langelsheim', + 'Kottukal', + 'Sharan', + 'Longueuil', + 'Parappur', + 'Kurivikod', + 'Pindi Bhattian', + 'Buuhoodle', + 'Karjat', + 'Befandriana', + 'Alto Santo', + 'Pinneli', + 'Mlawa', + 'Cortez', + 'Katteragandla', + 'Badalona', + 'Zibo', + 'Keizer', + 'Marijampole', + 'Loncoche', + 'Mpika', + 'Hobro', + 'Mancora', + 'Bosconia', + 'Frohburg', + 'Weilerswist', + 'Las Charcas', + 'Carney', + 'Bhansia', + 'Simrahi', + 'Guildford', + 'Fuquay-Varina', + 'Braunau am Inn', + 'Pine Hills', + 'Franconville', + 'Noordwijkerhout', + 'Bezons', + 'Sliema', + 'Pinellas Park', + 'Kafr Qasim', + 'Dundee', + 'Valley', + 'Bromsgrove', + 'Coacalco', + 'Kralupy nad Vltavou', + 'Lafrayta', + 'Tunapuna', + 'Barmstedt', + 'Upper Saucon', + 'Palaiya Ayakkudi', + 'Mladenovac', + 'Qaratau', + 'Hurtgenwald', + 'Mailapur', + 'Tucurui', + 'Australia', + 'Cidelandia', + 'Holly Hill', + 'Kannandahalli', + 'Gilgit', + 'Roetgen', + 'Jirkov', + 'Madavur', + 'Eastham', + 'Kachavaram', + 'Qal`at an Nakhl', + 'Pearl River', + 'Oberstdorf', + 'Andilamena', + 'Tittagudi', + 'Ceel Baraf', + 'Meerbusch', + 'Jaunpur', + 'Terrell', + 'Ban Nong Kula', + 'Sarmiento', + 'Coaldale', + 'Baneh', + 'Leh', + 'Mirai', + 'Ambodisikidy', + 'Amtar', + 'Boise', + 'Solsona', + 'Maizuru', + 'Villa Luvianos', + 'Twentynine Palms', + 'Murapaka', + 'Monclova', + 'Miharu', + 'Krumbach', + 'Haldensleben', + 'Inaja', + 'Iguatu', + 'Ponto Novo', + 'Batabano', + 'Itape', + 'Poggiomarino', + 'Gayaspur', + 'Monte San Juan', + 'Kostiantynivka', + 'Bagalvad', + 'Pozoblanco', + 'Gaunivaripalle', + 'Gandhidham', + 'Pingxiangcheng', + 'Flers-lez-Lille', + 'Owasso', + 'Summerville', + 'Ban Tap Tao', + 'Mahisanrh', + 'Podaturpeta', + 'Kalanchak', + 'Lira', + 'Yaguaron', + 'Saharanpur', + 'Guthrie', + 'Tirat Karmel', + 'Sagala', + 'Griesheim', + 'Riesa', + 'Anaikal', + 'Kontiolahti', + 'Betania', + 'Varjota', + 'Pisaflores', + 'Encarnacion de Diaz', + 'Tafeng', + 'Ioannina', + 'Ha Giang', + 'Ash Shinan', + 'Maromiandra', + 'Kampel', + 'Seyyedan', + 'Elk', + 'Marcos Juarez', + 'Timri', + 'Ewarton', + 'Betul Bazar', + 'Sao Jose do Belmonte', + 'Amboahangibe', + 'Isser', + 'Yellayapalem', + 'Bhiwani', + 'Ad Dakhla', + 'Edmond', + 'Lourosa', + 'Aslanapa', + 'Ilsede', + 'Phoenix', + 'Negrine', + 'Prabhat Pattan', + 'Tapaktuan', + 'Camalig', + 'Upper Montclair', + 'Binh Long', + 'Trincomalee', + 'Yellowknife', + 'Turbo', + 'Kashaf', + 'Rapur', + 'Jamiltepec', + 'Zaggota', + 'Serui', + 'Ban Nam Dip Luang', + 'Sursee', + 'Miyoshidai', + 'Chichiriviche', + 'Kariat Ben Aouda', + 'Tranomaro', + 'Torokbalint', + 'Eiheiji', + 'Fartura', + 'Lonate Pozzolo', + 'Lixingcun', + 'Purwakarta', + "Fu'an", + 'Havi Bhauar', + 'Livinjipuram', + 'Sherwood', + 'Cayenne', + 'Hamme', + 'Bao Loc', + 'Cameta', + 'San Fructuoso de Bages', + 'Mawlamyine', + 'Yonkers', + 'Doudian', + 'Orebro', + 'Longvic', + 'Penaballi', + 'Sinzig', + 'Jambi', + 'Bandundu', + 'Poshkent', + 'Dhamdaha', + 'Springettsbury', + 'Savage', + 'Iga', + 'Narsimlapet', + 'Hatwans', + 'Marco Island', + 'Mallikkundam', + 'Loharda', + 'Aguada de Pasajeros', + 'Jining', + 'Dhana', + 'Raceland', + 'Wroclaw', + 'Sao Lourenco da Mata', + 'Kiblawan', + 'Alagoa Nova', + 'Trentham', + 'Alofi', + 'Missoula', + 'Pecanha', + 'Atok', + 'Paipa', + 'Kouroussa', + 'Arnavutkoy', + 'Ankaran', + 'Jorhat', + 'Susari', + 'Higashi-Hiroshima', + 'Incline Village', + 'Rafael Calzada', + 'Thetford', + 'Jelgava', + 'Manono', + 'Tuncheng', + 'Potrerillos', + 'Lopon', + 'Moline', + 'Cornelio Procopio', + 'Dali', + 'Agropoli', + 'Inazawa', + 'Korosavada', + 'Elne', + 'Karur', + 'Vasudevanallur', + 'Viti', + 'Rezina', + 'Paju', + 'Thohoyandou', + 'Enniskillen', + 'Bad Fallingbostel', + 'Sokobanja', + 'Pleven', + 'Bang Phongphang', + 'Danga', + 'Tahuna', + 'Belsara', + 'Battalgazi', + 'Paravada', + 'General Belgrano', + 'Qingping', + 'Jinsha', + 'Malmedy', + 'Santa Cruz Mulua', + 'Lindenberg im Allgau', + 'Karpenisi', + 'Dondo', + 'Viralippatti', + 'Tado', + 'Cimanggis', + 'Barra do Bugres', + 'Kudahuvadhoo', + 'Badru Khan', + 'Samorin', + 'Tiruverumbur', + 'Taloda', + 'Roding', + 'Bante', + 'La Independencia', + 'Basseterre', + 'Ati', + 'Cavinti', + 'Chitembo', + 'Ryugasaki', + 'Eschborn', + 'Vertientes', + 'Bobingen', + 'Haliyal', + 'Sao Gabriel da Cachoeira', + 'Dielheim', + 'Siirt', + 'Oosterend', + 'Aich', + 'Ilkhchi', + 'Labrador City', + 'Chioggia', + 'Neuquen', + 'Upper Allen', + 'Itajobi', + 'Baltimore', + 'Nagra', + 'Wegorzewo', + 'Sansa', + 'Suaita', + 'Purral', + 'Narwar', + 'Denan', + 'Kandla Port', + 'Koubel-Koundia', + 'Airdrie', + 'Karumandi Chellipalaiyam', + 'Parol', + 'San Francisco la Union', + 'Kocasinan', + 'Sidi Abdallah', + 'Merzenich', + 'Correntina', + 'Saunda', + 'Paducah', + 'Keve', + 'Nandiala', + 'Indramayu', + 'Qusmuryn', + 'Aramangalam', + 'Mavorano', + 'Koppaka', + 'Corroios', + 'Thornbury', + 'Palm City', + 'Sao Felix da Marinha', + 'Giffnock', + 'Cardenas', + 'Kyaunggon', + 'Zhoukou', + 'Red Deer', + 'Constanza', + 'Libertador General San Martin', + 'Ducheng', + 'Orsova', + 'Bures-sur-Yvette', + 'Tixtla de Guerrero', + 'Tlachichilco', + 'Kangan', + 'Lyndhurst', + 'Wexford', + 'Chitipa', + 'Palagonia', + 'Olsberg', + 'Antongomena-Bevary', + 'Wayaobu', + 'Irosin', + "Sa'ada", + 'Lamwo', + 'Bibemi', + 'Bartow', + 'Floresti', + 'Kemin', + 'Baramandougou', + 'Baybay', + 'Nansang', + 'Frenstat pod Radhostem', + 'Mizhhiria', + 'Zelino', + 'Beni Abbes', + 'Tarkwa', + 'Ezhipram', + 'Vicente Noble', + 'Hitachi-ota', + 'Muhembo', + 'Ksar el Hirane', + 'Lauchhammer', + 'Agboville', + 'Big Bear City', + 'Oradea', + 'Mabitac', + 'Trashigang', + 'An Nasiriyah', + 'Belo Oriente', + 'Pampas', + 'Schifferstadt', + 'Guatemala City', + 'Pithampur', + 'I`zaz', + 'Poranki', + 'Arcola', + 'Perugia', + 'Betmangala', + 'Haqqulobod', + 'Wujiaying', + 'Ankazoabokely', + 'Agrestina', + 'Rodenbach', + 'Nowshahr', + 'Sierning', + 'Santa Maria de Jesus', + 'Madalena', + 'Tarrafal', + 'Mitoma', + 'Roseaux', + 'Wichita', + 'Grudziadz', + 'Zarnesti', + 'Findikli', + 'Sarnen', + 'Irpin', + 'Rouen', + 'Qishe', + 'Dammartin-en-Goele', + 'Hazel Dell', + 'Charikar', + 'Ostrzeszow', + 'Tunari', + 'Kingri', + 'La Reina', + 'Boriziny', + 'Nangavaram', + 'Jahangirpur Salkhani', + 'Mangobandar', + 'Gustavia', + 'Alangudi', + 'Naumburg', + 'Sarikishty', + 'Dania Beach', + 'Budaka', + 'Tillmans Corner', + 'Ramotswa', + 'Menges', + 'Dasuya', + 'Darreh Shahr', + 'Perumkulam', + 'Moorreesburg', + 'El Ejido', + 'Lingayen', + 'Fontana', + 'Ubaporanga', + 'Shoo', + 'Heroica Matamoros', + 'Bayog', + 'Marikal', + 'Da Nang', + 'Lampertheim', + 'Basbiti', + 'Ramonville-Saint-Agne', + 'Kuwait City', + 'Manakana', + 'Mandra', + 'Tehata', + 'Stein bei Nurnberg', + 'Crigglestone', + 'Brofodoume', + 'Trnava', + 'Thimphu', + 'Gurmia', + 'Cacem', + 'Alahina', + 'Mongo', + 'Khayelitsha', + 'Sadri', + 'Fukui', + 'Dharmaj', + 'Kaatsheuvel', + 'Dammarie-le-Lys', + 'Matsakabanja', + 'Ait Ouaoumana', + 'Kirovsk', + 'Savur', + 'Baranivka', + 'Kodaikanal', + 'Lantana', + 'Shache', + 'Jacobabad', + 'President Quirino', + 'Kozienice', + 'Coatetelco', + 'Tha Muang', + 'Fanlu', + 'Ejutla de Crespo', + 'Senhora da Hora', + 'Bhadarwah', + 'Almazora', + 'Americus', + 'Schaesberg', + 'Liulin', + 'Shahrak-e Ja`fariyeh', + 'Pathankot', + 'Kirkkonummi', + 'Koyulhisar', + 'Adamankottai', + 'Ketama', + 'Irineopolis', + 'Kavali', + 'Sambalhera', + 'Nanjian', + 'San Juan de Uraba', + 'Tola Khadda', + 'Mulheim', + 'Berhoum', + 'Hawaiian Paradise Park', + 'Marg`ilon', + 'Eilendorf', + 'Oostzaan', + 'Evanston', + 'Mantasoa', + 'Ixtlahuaca', + 'Capao da Canoa', + 'Baker', + 'Altintas', + 'Taipei', + 'Siktiahi', + 'Ramabitsa', + 'Tarmount', + 'Haciqabul', + 'Ellore', + 'Palangkaraya', + 'Mugumu', + 'Ed Damer', + 'Steinfurt', + 'Malthone', + 'Villagarzon', + 'Elizabeth City', + 'La Farlede', + 'Binaqadi', + 'Barquisimeto', + 'Simaria', + 'Castel Volturno', + 'Frickenhausen', + 'Ait Ikkou', + 'Gauravaram', + 'Ubeda', + 'Simcoe', + 'Oakley', + 'Capas', + 'Jixian', + 'Muthabana', + 'Masalli', + 'Leganes', + 'Beidaying', + 'Hyeres', + 'Vinnamala', + 'Chatteris', + 'Parit Buntar', + 'Khelil', + 'Igaci', + 'Raytown', + 'Janakpur', + 'Ilford', + 'Bojnurd', + 'Toyota', + 'Orte', + 'Saint-Brieuc', + 'The Nation / La Nation', + 'Ghulja', + 'Lagoa do Mato', + 'Mohelnice', + 'Lavumisa', + 'Harda Khas', + 'Pendlebury', + 'Sonakhal', + 'Unagatla', + 'Sandhurst', + 'Villa Krause', + 'Sherghati', + 'Supaul', + 'Busovaca', + 'Luathaha', + 'Liversedge', + 'Liberty', + 'Yian', + 'Sion', + 'Itamogi', + 'Berrouaghia', + 'Bharuch', + 'Waunakee', + 'Adel', + 'Crestline', + 'Savissivik', + 'Meiganga', + 'Sannai', + 'Cuizhuangzi', + 'Cold Lake', + 'Agrigento', + 'Rio Branco do Sul', + 'Carneirinho', + 'Viborg', + 'Munsan', + 'Big Lake', + 'Rute', + 'Mela Gudalur', + 'Mbala', + 'Mateus Leme', + 'Kakamega', + 'Al Atarib', + 'Bad Harzburg', + 'Tigbauan', + 'Phak Hai', + 'San Juan de la Costa', + "Cornate d'Adda", + 'Bewdley', + 'Nyimba', + 'Vedelago', + 'Asaba', + 'Bozyazi', + 'Tuxtla', + 'Alvin', + 'Castiglion Fiorentino', + 'Umag', + 'Taquaritinga do Norte', + 'Ghoti Budrukh', + 'Relangi', + 'Woodward', + 'Santiago de Tolu', + 'Marcali', 'Stanley', - 'Bankheri', - 'Llantrisant', - 'Veys', - 'White', - 'Itajiba', - 'Mottola', - 'Bhanumukkala', - 'Guerouma', - 'Belchertown', - 'Broxbourne', - 'Dudhgaon', - 'Uirauna', - 'Andicun', - 'Elandakuttai', - 'Nagasu', - 'Tenafly', - 'Ladson', - 'Harper Woods', - 'Guamare', - 'Vennesla', - 'Medrissa', - 'Belari', - 'Erongaricuaro', - 'Norridge', - 'Shal', - 'Lagoa da Confusao', - 'Maryborough', - 'Clausthal-Zellerfeld', - 'Santa Ursula', - 'Saint-Charles-Borromee', - 'Chilcuautla', - 'Tekkampatti', - 'Matar', - 'Lyss', - 'Sidi Ghiles', - 'Atyra', - 'Ulladulla', - 'Cunit', - 'Sippola', - 'Shedbal', - 'Palmer Ranch', - 'Galanta', - 'Kalikapur', - 'Motiong', - 'Pereiro', - 'Chemini', - 'Boumahra Ahmed', - 'Peddaboddepalle', - 'Sahpur', - 'Udayendram', - 'Es Sebt', - 'Vincent', - 'Ain Jemaa', - 'San Rafael Arriba', - 'Wittenheim', - 'Mangawan', - 'Ratan', - 'Dawlish', - 'Shimohata', - 'Rio Grande City', - 'Pureparo de Echaiz', - 'Project Six', - 'Senlis', - 'Nonkon', - 'Ober-Ramstadt', - 'Penacova', - 'Ovruch', - 'Coulommiers', - 'Bouc-Bel-Air', - 'Vail', - 'Civita Castellana', - 'Volpiano', - 'Kinross', - 'Castellarano', - 'Dengshangcun', - 'Palmview', - 'Asbury Park', - 'Pichucalco', - 'Libagon', - 'Featherstone', - 'Mexborough', - 'Melissa', - 'Glenn Dale', - 'Tazert', - 'Anosy Avaratra', - 'La Solana', - 'Marui', - 'Kriel', - 'Beterou', - 'Itanhandu', - 'Metkovic', - 'Wilmington Island', - 'Kanding', - 'Pimpalgaon Raja', - 'Mulakaledu', - 'Cowansville', - 'Conchas', - 'Upper Southampton', - 'Rochedale', - 'Billapadu', - 'Vieiro', - 'Neston', - 'Sainte-Anne-des-Plaines', - 'Avsallar', - 'Chervonopartyzansk', - 'Tamesis', - 'Charam', - 'Bidston', - 'Rive-de-Gier', - 'Vammala', + 'Dulay` Rashid', + 'Five Forks', + 'Jandaia do Sul', + 'Culfa', + 'Suzano', + 'Motomachi', + 'Ahermoumou', + 'Jose Cardel', + 'Marsella', + 'Tyngsborough', + 'Eijsden', + 'Checy', + 'Hamidiye', + 'Mocimboa da Praia', + 'Cossato', + 'Adjohon', + 'Jamapa', + 'Dahana', + 'Banfora', + 'Rabo de Peixe', + 'Caloto', + 'West Lampeter', + 'Princeton Meadows', + 'Whitwick', + 'Siversk', + 'Mpraeso', + 'Borovskoy', + 'Cockermouth', + 'Mogadishu', + 'Traipu', + 'Frechen', + 'Cabras', + 'Enkakad', + 'Bocas de Satinga', + 'Tomares', + 'Umbauba', + 'Itiki', + 'Nordhorn', + 'Macetown', + 'Quilengues', + 'Chiclana de la Frontera', + 'Lagoa Seca', + 'Zielonka', + 'Xinqing', + 'Pedro Carbo', + 'Vespasiano', + 'Masis', + 'Prichard', + 'Sandomierz', + 'Fulwood', + 'Bad Liebenzell', + 'Zvenyhorodka', + 'Bellevue', + 'Gudgeri', + 'Srikrishnapur', + 'Madgaon', + 'Piedecuesta', + 'Ibrahimpatnam', + 'Mandrosonoro', + 'Tlumach', + 'Citrus Springs', + 'Cabestany', + 'Metuchen', + 'Baxiangshan', + 'Bithauli', + 'Araguaina', + 'Ban Piang Luang', + 'Kamrej', + 'Chicaman', + 'Kishiwada', + 'Tabua', + 'San Rafael del Sur', + 'Cibolo', + 'Le Relecq-Kerhuon', + 'Boca Raton', + 'Amecameca de Juarez', + 'Radstock', + 'Launceston', + 'Gorantla', + 'Babar', + 'Jammalamadugu', + 'Gordes', + 'Vich', + 'Arroyo Grande', + 'Dvur Kralove nad Labem', + 'Novoukrainka', + 'Gurgunta', + 'Oued Cheham', + 'Salinopolis', + 'Oak Lawn', + 'Fatehgarh Churian', + 'San Alberto', + 'Wetaskiwin', + 'San Jose Pinula', + 'Montataire', + 'Aduku', + 'Planken', + 'Trussville', + 'Sidi Lmokhtar', + 'Machchand', + 'Moletai', + 'Grand-Lahou', + 'Ergoldsbach', + 'Sao Joao dos Patos', + 'Cajapio', + 'Sestao', + 'Bayshore Gardens', + 'Jaragua', + 'Canuelas', + 'Campo do Meio', + 'Chada', + 'Bibala', + 'Suining', + 'Granby', + 'Ostend', + 'Split', + 'Clark', + 'Baikunthapur', + 'Eppingen', + 'Bara Khurd', + 'Las Vigas de Ramirez', + 'Sharm ash Shaykh', + 'Sainthia', + 'Lowestoft', + 'Kaldenkirchen', + 'Acailandia', + 'Rosita', + 'Antardipa', + 'Ihaddadene', + 'Kennett', + 'Houlong', + 'Sriramapuram', + 'Nava Raipur', + 'Zielona Gora', + 'Biella', + 'Niceville', + 'Koscierzyna', + 'Lonkly', + 'Miramas', + 'Zubin Potok', + 'Sao Vicente Ferrer', + 'Fouka', + 'Rasak', + 'Nyzhnia Krynka', + 'Bijni', + 'West Bend', + 'Kurumul', + 'Golbaf', + 'Carencro', + 'Mercer Island', + 'Lai', + 'Rimini', + 'Labutta', + 'Goubellat', + 'Yakymivka', + 'Fianarantsoa', + 'Zhengding', + 'Vittoria', + 'Tactic', + 'Arrecife', + 'Parkes', + 'Ibicoara', + 'Gidi', + 'Afumati', + 'Dongning', + 'Tameslouht', + 'Ashwaubenon', + 'Alto Parana', + 'Mattanur', + 'Chinchali', + 'Monte Siao', + 'Kallanai', + 'Florania', + 'Ghorahi', + 'Uchqurghon Shahri', + 'Tres Isletas', + 'Bambara-Maounde', + 'Bela Vista de Goias', + 'Nova Granada', + 'Kesap', + 'Beldibi', + 'Hyderabad', + 'Otaki', + 'Bhuban', + 'Stansbury Park', + 'Halgur', + 'Arda', + 'Dalupura', + 'Maraveh Tappeh', + 'Kankandighi', + 'Chornomorske', + 'Nikopol', + 'Shinagawa-ku', + 'Zeralda', + 'St. Michael', + 'Fortaleza dos Nogueiras', + 'Nansan', + 'Edattala', + 'Phu Tu Son', + 'Cipo', + 'Bintulu', + 'Amayan', + 'Rainbow City', + 'Dougabougou', + 'Levakant', + 'Allada', + 'Tabursuq', + 'Hoshangabad', + 'Gerli', + 'Bardsir', + 'Sarsawa', + 'Manicaragua', + 'Sint-Pieters-Leeuw', + 'Pescantina', + 'Nimule', + 'Ambovombe', + 'Navsari', + 'Wilbraham', + 'Keene', + 'Novska', + 'Vallabh Vidyanagar', + 'Kifri', + 'Gornji Petrovci', + 'Bareggio', + 'Tosa', + 'Kafr Shukr', + 'Konotop', + 'Frei Miguelinho', + 'Pirapora do Bom Jesus', + 'Nemocon', + 'Ribeirao Bonito', + 'Kundli', + 'Zola Predosa', + 'Bileca', + 'Vargem Grande', + 'Martinopolis', + 'Madna', + 'Colonial Park', + 'Fecamp', + 'Sesto Fiorentino', + 'Bouzina', + 'Bischofswerda', + 'Saulkrasti', + 'Margram', + 'Zapresic', + 'Muriyad', + 'Ayun', + 'Harlingen', + 'San Juan de los Morros', + 'Kozy', + 'Kandern', + 'Taibao', + 'Savonlinna', + 'Fountainebleau', + "L'Ile-Perrot", + 'Zomin Shaharchasi', + 'PortoAlexandre', + 'Nes Ziyyona', + 'Watervliet', + 'Bonito de Santa Fe', + 'Murgod', + 'Aurisina', + 'Kochlowice', + 'Lierre', + 'Wellesley', + 'East Greenwich', + 'Jacarau', + 'Nawa', + 'Upper St. Clair', + 'Qalyub', + 'Darbhanga', + 'Balakliia', + 'Makulubita', + 'Giesen', + 'Sarkeghat', + 'Paiania', + 'Thandla', + 'Gravata', + 'Ad Dis', + 'Nawada Gobindganj', + 'Mosrah', + 'Ballwin', + 'Rehovot', + "Chateau-d'Olonne", + 'Barendrecht', + 'Kihei', + 'Forbes', + 'Van Wert', + 'Angola', + 'Sokuluk', + 'Gadarpur', + 'Beji', + 'Palmela', + 'Bad Lippspringe', + 'Al Badrashayn', + 'Angelim', + 'Higashimurayama', + 'Tangshan', + 'Fritzlar', + 'Hobyo', + 'Erumapalaiyam', + 'Kahului', + 'Varkkallai', + 'Sayula', + 'Waverly', + 'Koranampatti', + 'Peristeri', + 'Weilheim an der Teck', + 'Mustafakemalpasa', + 'Babolsar', + 'Concepcion Chiquirichapa', + 'Yueshanwan', + 'Sangeorgiu de Mures', + 'Edamon', + 'Moston', + 'Gabes', + 'Heesch', + 'Sahjanwa', + 'Auburn', + 'Sorel-Tracy', + 'Sagua de Tanamo', + 'Wassenaar', + 'Sarospatak', + 'Sapahi', + 'Kangayam', + 'Oodweyne', + 'Bac Kan', + 'Hole Narsipur', + 'Canmore', + 'Mulungu do Morro', + 'Fagnano Olona', + 'Sawankhalok', + 'Odanavattam', + 'Tiruvambalapuram', + 'Torotoro', + 'Kil Valur', + 'Koshizuka', + 'Kyonpyaw', + 'Annaberg-Buchholz', + 'Lissone', + 'Maracana', + 'Paysandu', + 'Batu', + 'Ciudad Acuna', + 'Kanavaikuli', + 'Lahaina', + 'Ma`an', + 'Comala', + 'Xiongzhou', + 'Coalcoman de Vazquez Pallares', + 'Benemerito', + 'Kuchinarai', + 'Lugo', + 'Kibuku', + 'Pirajui', + 'Fountain Valley', + 'Zentsujicho', + 'Shahreza', + 'Dragomer', + 'Puyehue', + 'Floridablanca', + 'Bitterfeld', + 'Bozkurt', + 'Sewa', + 'Soreang', + 'Varedo', + 'Narot Mehra', + 'Rogasovci', + 'Nukan', + 'Skipton', + 'Bidur', + 'Walldurn', + 'Ipero', + 'Aritao', + 'Breckerfeld', + 'Manakayi', + 'Narapalli', + 'Waraseoni', + 'Nogent-sur-Oise', + 'Itumbiara', + 'Ban Mae Sam Laep', + 'El Retorno', + 'Dunfermline', + 'Tamaraikkulam', + 'Dingli', + 'Ouadda', + 'Hillview', + 'Eceabat', + 'Yangmei', + 'Mamoudzou', + 'Dietikon', + 'Siauliai', + 'Pierrelatte', + 'Hamada', + 'Hooper', + 'Sakuho', + 'Beijing', + 'Limoeiro do Norte', + 'Ladario', + 'Karuveppampatti', + 'Sheffield', + 'Aguas de Lindoia', + 'Boac', + 'Mende', + 'Gohuma Bairia', + 'Riscani', + 'Koroth', + 'Sibenik', + 'Avalurpet', + 'Roberval', + 'Madinat as Sadis min Uktubar', + 'Rosoman', + 'Porto Alegre', + 'Brugherio', + 'Brody', + 'Keuruu', + 'Lehre', + 'Zawiercie', + 'Dalyoni Bolo', + 'Loay', + 'Kolonia', + 'Bussy-Saint-Georges', + 'Oulad Imloul', + 'Lagoa Formosa', + 'Wurselen', + 'Kestel', + 'Orhei', + 'Lubuagan', + 'Quixere', + 'Scottdale', + 'Caparrapi', + "Bruay-sur-l'Escaut", + 'Nova Ponte', + 'Rostam Kola', + 'Asuncion Nochixtlan', + 'Colton', + 'Little River', + "Jian'ou", + 'Diekirch', + 'Fateha', + 'Cimitarra', + 'Hombal', + 'Lindenhurst', + 'Ouled Djellal', + 'Comanesti', + 'Bousso', + 'Streamwood', + 'Roulia', + 'Duzce', + 'Asuke', + 'Libona', + 'Rellivalasa', + 'Ukwa', + 'Yavatmal', + 'Greasley', + 'Sivas', + 'Hukumati Gizab', + 'Balikpapan', + 'Qincheng', + 'Hongfengcun', + 'Nakai', + 'Oued Zem', + 'Pumalakkundu', + 'Umaria', + 'Sao Lourenco da Serra', + 'Amawom', + 'Barra do Mendes', + 'Aklim', + 'Sambrial', 'Bunkeflostrand', - 'Capurso', - 'Shangtianba', - 'Musapur', - 'Saint-Brice-sous-Foret', - 'Humayingcun', - 'Macomb', - 'Sumidouro', - 'Phillipsburg', - 'Souk Et-Tleta des Oulad Hamdane', - 'Ljungby', - 'Aravakkurichchi', - 'Tirhassaline', - 'La Apartada', - 'Francheville', - 'Chateau-Thierry', - 'Barrocas', - 'Ceska Trebova', - 'Salesopolis', - 'Huasca de Ocampo', - 'Arnedo', - 'Zubin Potok', - 'Hallstahammar', - 'Gagarin Shahri', - 'Northenden', - 'Pyapali', - 'Kumiyama', - 'Davidson', - 'Chinsali', - 'Chellaston', - 'Ahram', - 'Mahaly', - 'Seshambe', - 'Mering', - 'Verwood', - 'Imerimandroso', - 'Adilcevaz', - 'Golmarmara', - 'Bangassi-Nangou', - 'Longwy', - 'Uchiko', - 'Melouza', - 'Jangid', - 'Tondangi', - 'Hebli', - 'San Vito al Tagliamento', - 'Dougouni', - 'Nakanojomachi', - 'Tasucu', - 'Azpeitia', - 'Domanic', - 'Schwyz', - 'Xiangyuncun', - 'Beech Grove', - 'Dorfen', - 'Adjud', - 'Gulf Shores', - 'Cessnock', - 'Wakuya', - 'Montagu', - 'Fray Luis A. Beltran', - 'Petlawad', - 'Espumoso', - 'Seven Pagodas', - 'Salua', - 'Gayeri', - 'Pa', - 'Niederkruchten', - 'Redruth', - 'Cumbum', - 'Greenlawn', - 'Waremme', - 'Rio San Juan', - 'Puliyur', - 'Hathiaundha', - 'Moura', - 'Ewa Beach', - 'Sobreda', - 'Douar El Arbaa Bou Quorra', - 'Yauco', - 'Lakhaura', - 'Gaspe', - 'Meruoca', - 'Palmers Green', - 'Totteridge', - 'Gurramkonda', - 'Kontiolahti', - 'Blaydon', - 'San Pedro Tapanatepec', - 'Biatorbagy', - 'Kawaminami', - 'Berkley', - 'Biritinga', - 'Kuusamo', - 'Whitman', - 'Mallapuram', - 'Mashpee', + 'Taskent', + 'Rakitovo', + 'Nerima', + 'Waxhaw', + 'Hoogezand', + 'San Vicente de Tagua Tagua', + 'Recreio', + 'Lope de Vega', + 'Hejin', + 'Margherita', + 'Bend', + 'Strijen', + 'Manin', + 'Nogi', + 'Tilothu', + 'Manching', + 'Masindi Port', + 'Sumba', + 'Amizmiz', + 'Canada de Gomez', + 'Siddhapur', + 'Ankaramena', + 'Aleppo', + 'Sansanding', + 'Tirumakudal Narsipur', + 'Gumla', + 'Usa', + 'At Tawahi', + 'Koumantou', + 'De Panne', + 'Kukes', + 'Lenoir City', + 'Tiruppalaikudi', + 'Canyon Lake', + 'Nanpingcun', + 'Gubbio', + 'Jasaan', + 'Galaosiyo Shahri', + 'Mount Sinai', + 'Tulshia', + 'Sankt Johann im Pongau', + 'Sandi', + 'Banda', + 'Kilkunda', + 'Solymar', + 'Shenzhou', + 'As Sallum', + 'Baohezhuangcun', + 'Gogui', + 'Aarschot', + 'Kadappuram', + 'Sorkheh', + 'Gawler', + 'La Falda', + 'Masqat', + 'Bazeh Kalagh', + 'Forfar', + 'Kelafo', + 'Conde', + 'Porciuncula', + 'Palanas', + 'Cuyo', + 'Las Cabezas de San Juan', + 'Kranidi', + 'New Orleans', + 'Mettupalaiyam', + 'Kati', + 'Carregado', + 'Hornsby Bend', + 'Salvatierra', + 'Begamganj', + 'Cishan', + 'Draa Ben Khedda', + 'Eshtehard', + 'Sidi Daoud', + 'Las Nieves', + 'Nea Alikarnassos', + 'San Francisco Ixhuatan', + 'Luodong', + 'Waihee-Waiehu', + 'Rosolini', + 'Tundla', + 'Ash Shihaniyah', + 'SeaTac', + 'Daigo', + 'Solana Beach', + 'Kittanapalli', + 'Guspini', + 'Rahimyar Khan', + 'Antanambao', + 'New Silksworth', + 'Bixby', + 'Sahnaya', + 'Kudal', + 'Guaira', + 'Ibaiti', + 'Iksan', + 'Muttamtura', + 'Darnetal', + 'Karma', + 'Leyland', + 'Strzelin', + 'Tam Diep', + 'Tagaytay', + 'Finale Ligure', + 'Cottonwood', + 'Cutlerville', + 'Santa Cruz de Bezana', + 'Frydlant nad Ostravici', + 'Aracuai', + 'Huangyadong', + 'Herzele', + 'Sakarya', + 'Extremoz', + 'Bauta', + 'Kela Khera', + 'Castelvetrano', + 'Kalisz', + 'Qorovul', + 'Sanchez', + 'Tamezmout', + 'Boundji', + 'Bellinzago Novarese', + 'Tungi', + 'Ichenhausen', + 'Sao Sebastiao do Uatuma', + 'Inver Grove Heights', + 'Villefranche-de-Rouergue', + 'Uad Damran', + 'Rishon LeZiyyon', + 'Nellimarla', + 'Bountiful', + 'Sahaswan', + 'Kamonkoli', + 'Santo Augusto', + 'Hammersmith', + 'Breyten', + 'Northwich', + 'Nagambhotlapalem', + 'Montabaur', + 'Ammavarikuppam', + 'Amasya', + 'Bhankarpur', + 'Santa Rosa del Penon', + 'Anshun', + 'Feidh el Botma', + 'Abdurahmoni Jomi', + 'Rionero in Vulture', + 'Bundi', + 'Almargem', + 'McNair', + 'East Palo Alto', + 'Las Flores', + 'Carmo da Mata', + 'Wilkau-Hasslau', + 'Barentin', + 'Outat Oulad Al Haj', + 'Chemax', + 'Ayapango', + 'Ramacca', + 'Oton', + 'Ghoswari', + 'Al Fallujah', + 'Cheviot', + 'Alnavar', + 'Al Qasr', + 'Santo Domingo Suchitepequez', + 'Sulleru', + 'Barahpur', + 'Chapalamadugu', + 'Ar Rutbah', + 'Areia Branca', + 'Avenel', + 'Hoover', + 'Velykodolynske', + 'Beladi', + 'Changchun', + 'Linden', + 'Hillside', + 'Taxco de Alarcon', + 'Kathri', + 'Belemoka', + 'San-Pedro', + 'Ban Huai Hin', + 'Olovo', + 'Sundekuppam', + 'El Alto', + 'Totonicapan', + 'Mujiayu', + 'Makhtal', + 'Ikoma', + 'Sylhet', + 'Passo de Camarajibe', + 'Bad Driburg', + 'Rangapara', + 'Komarom', + 'Bakhmach', + 'Qionghu', + 'Ecatzingo', + 'Pallipram', + 'Taicheng', + 'Datu Piang', + 'Tlaltetela', + 'Preveza', + 'Cambuci', + 'Werkendam', + 'Ipira', + 'Gosport', + 'Grytviken', + 'Rondonopolis', + 'Phra Phutthabat', + 'La Puebla de Cazalla', + 'Leposaviq', + 'San Juan Cotzocon', + 'Sederot', + 'Nidiyanga', + 'Makamba', + 'Resistencia', + 'Rio Blanco', + 'Monte Escobedo', + 'Vasylkiv', + 'Eyl', + 'Fenoarivo', + 'Pokrov', + 'Bang Sao Thong', + 'Granite Bay', + 'Fortul', + 'Lenoir', + 'Trent Hills', + 'Le Petit-Quevilly', + 'Tifra', + 'Jaroslaw', + 'Perrysburg', + 'Ericeira', + 'Maniago', + 'Al Qusiyah', + 'Norridge', + 'Palamos', + 'Pochampalli', + 'Buni', + 'Preetz', + 'Anaconda', + 'Chinde', + 'Bakouma', + 'Jakar', + 'Tavros', + 'Doranala', + 'Mayiladi', + 'Villecresnes', + 'Phulgachhi', + 'Pen', + 'Somersworth', + 'Igrejinha', + 'Umburetama', + 'Kakumiro', + 'Arauquita', + 'Schwieberdingen', + 'Berkeley', + 'Alquizar', + 'Adigappadi', + 'Hardinxveld-Giessendam', + 'Baindur', + 'Beko', + 'Belley', + 'Mousoulou', + 'Ome', + 'Finnsnes', + 'High Point', + 'Budenheim', + 'Temara', + 'Sulejowek', + 'Grecia', + 'Deoghar', + 'Macerata', + 'Monghyr', + 'Hullhorst', + 'Tervuren', + 'On Top of the World Designated Place', + 'Isernhagen-Sud', + 'Parner', + 'Llanera', + 'Tsurugashima', + 'Dhamaun', + 'Porto Valter', + 'Loyalsock', + 'Guntersville', + 'Gandorhun', + 'Zella-Mehlis', + 'Pazin', + 'Bunyan', + 'Toyama', + 'Lamrasla', + 'Huliyar', + 'Springville', + 'Orkelljunga', + 'Pillutla', + 'Paruthur', + 'Zahedan', + 'Baskil', + 'Morteza Gerd', + 'Remchi', + 'Chiaravalle', + 'Grunstadt', + 'Sofifi', + 'Londrina', + 'Mazatlan', + 'Khathjari', + 'Chiang Klang', + 'Wulfrath', + "Qal'at Mgouna", + 'Irigny', + 'Senahu', + 'Perenchies', + 'Vero Beach', + 'Ocho Rios', + 'Castanhal', + 'Soe', + 'My Drarga', + 'Boxtel', + 'Hoyo de Manzanares', + 'Cruz Machado', + 'Morges', + 'Guano', + 'Anantapalle', + 'Tvrdosin', + 'Caojia', + 'Plaza Huincul', + 'Ranillug', + 'Yonezawa', + 'Parnu', + 'Zerizer', + 'Rabta', + 'Suginami-ku', + 'San Jose del Guaviare', + 'Khaira Tola', + 'Ain Oussera', + 'Badvel', + 'Wijnegem', + 'Frome', + 'Theux', + 'Caimbambo', + 'Wang Saphung', + 'Dabhoi', + 'Gebre Guracha', + 'Basatpur', + 'Zambrano', + 'Puttai', + 'Brainerd', + 'San Salvador El Seco', + 'Shostka', + 'Tabocas do Brejo Velho', + 'Tabriz', + 'Bhatpuri', + 'Arpajon', + 'Curti', + 'Hyde', + 'Cayetano Germosen', + 'Cafelandia', + 'Mnagueur', + 'Rygge', + 'Landskrona', + 'Kokubunji', + 'Resende', + 'Aguasay', + 'Painan', + 'Komagane', + 'Malhada de Pedras', + 'Zhutian', + 'Baabda', + 'Jackson', + 'Qoorlugud', + 'Fraserpet', + 'La Crau', + 'Pioltello', + 'Araure', + 'Ilsenburg', + 'Yanhewan', + 'Narayanpur', + 'Holtsville', + 'Vimmerby', + 'Binzhou', + 'Ligang', + 'Quillota', + 'Montmagny', + 'Malaga', + 'Juatuba', + 'Ascope', + 'Effia-Kuma', + 'Bellwood', + 'Encarnacion', + 'Mannur', + 'Puerto Santander', + 'Kendraparha', + 'Wewak', + 'Sendjas', + 'San Pedro Pinula', + 'Kampong Thom', + 'Mpanda', + 'Trebaseleghe', + 'Kerkyra', + 'Rogatec', + 'Katigang', + 'Yushu', + 'Saint-Hyacinthe', + 'Capelle aan den IJssel', + 'Eisenach', + 'Reinfeld', + 'Idri', + 'Kunnattur', + 'Cakung', + 'Rayadrug', + 'Baoshan', + 'Laramie', + 'El Meghaier', + 'Naperville', + 'Macatuba', + 'Katalpur', + 'Carpina', + 'Blyth', + 'Veseli nad Moravou', + 'Burhia Dhanghatta', + 'Svitlodarsk', + 'Lugait', + 'Rancho Cucamonga', + 'Tabara Arriba', + 'Spondon', + 'Marienberg', + 'Middelburg', + 'Huyton', + 'Sroda Slaska', + 'Woomera', + 'Bethalto', + 'Concepcion de Ataco', + 'Fagersta', + 'Halfmoon Bay', + 'Estancia', + 'Makow Mazowiecki', + 'Malangas', + 'Pittsburg', + 'Adukam', + 'West Melbourne', + 'Haverstraw', + 'Lousa', + 'Kulpsville', + 'Plasnica', + 'Charuanwan', + 'Foca', + 'Gombe', + 'Cordeiropolis', + 'Chakicherla', + 'Licey al Medio', + 'Conceicao das Alagoas', + 'Colonia', + 'Yisuhe', + 'Vignola', + 'San Martin Sacatepequez', + 'Mbanza-Ngungu', + 'Oppatavadi', + 'Eitorf', + 'Ubach-Palenberg', + 'Ranibennur', + 'Aklvidu', + 'Capoeiras', + 'Mucambo', + 'Palmares do Sul', + 'Kondakomarla', + 'Niteroi', + 'Sai Ngam', + 'City Bell', + 'Biougra', + 'White', + 'Kumru', + 'Alcala de Henares', + 'Kalawit', + 'Porto Xavier', + 'Balancan', + 'Vodice', + 'Zouping', + 'Nagawaram', + 'Mareth', + 'Kakraul', + 'Horten', + 'Padinjarebagam', + 'Karattuppalaiyam', + 'Redding', + 'Wolgast', + 'Ambrolauri', + 'Dhanot', + 'Nilakkottai', + 'Abaete', + 'Veendam', + 'Oslo', + 'Paiganapalli', + 'White Center', + 'Taminango', + 'Constitucion', + 'Begijnendijk', + 'Baragua', + 'Inverigo', + 'Belsandi Tara', + 'Rumst', + 'Pinner', + 'Reinheim', + 'Liancourt', + 'Villa Canas', + 'Metlika', + 'Balderton', + 'Gauripur', + 'Yamada', + 'Cardona', + 'Sartalillo', + 'Odaiyakulam', + 'Laguna Paiva', + 'Carolina', + 'Bhilavadi', + 'Al Qardahah', + 'Campo Bom', + 'Laichingen', + 'Montero', + 'Nagoya', + 'Portici', + 'Sherpur', + 'Baiheqiao', + 'Saint-Chamas', + 'Bloemfontein', + 'Songyang', + 'Mamfe', + 'Bijiao', + 'Tongobory', + 'Barra do Dande', + 'Revere', + 'Celtik', + 'Carigara', + 'Laindon', + 'Chapa de Mota', + 'Djanet', + 'Vinings', + 'Saltillo', + 'Gueoul', + 'Parnagua', + 'Burton upon Trent', + 'Bocaiuva do Sul', + 'Nova Xavantina', + 'Esteli', + 'Sremska Kamenica', + 'Pennsauken', + 'Bad Wurzach', + 'Banbury', + 'Nkowakowa', + 'Koloti', + 'Chaita', + 'Las Parejas', + 'Guerande', + 'Ski', + 'Suphan Buri', + 'Cheyenne', + 'San Isidro de Lules', + 'Cisternino', + 'Rajbalhai', + 'San Ferdinando di Puglia', + 'Nosivka', + 'Singhwara', + 'Ankarabato', + 'Dod Ballapur', + 'Wattignies', + 'Lebu', + 'Elangunnapuzha', + 'Korneuburg', + 'Saint Andrews', + 'Exmouth', + 'Menaa', + 'Bungotakada', + 'Isagarh', + 'Bilecik', + 'Oulad Bou Rahmoun', + 'Manambondro', + 'Port Morant', + 'Townsend', + 'Ca Mau', + 'Kostolac', + 'Presov', + 'Valle', + 'Sahambala', + 'Chapala', + 'Tepechitlan', + 'Uruacu', + 'Bangued', + 'Renton', + 'Ummannur', + 'Lalmanirhat', + 'Nurkot', + 'Brownfield', + 'San Miguel del Padron', + 'Toualet', + 'San Antonio Aguas Calientes', + 'Los Alamitos', + 'Jilib', + 'San Mateo Ixtatan', + 'Anapolis', + 'Burhanpur', + 'Yokotemachi', + 'Torrinha', + 'Mouzaia', + 'Harshin', + 'Cirencester', + 'Bentley', + 'Man', + 'Yezhi', + 'Kota', + 'Sovicille', + 'Otawara', + 'Zihuatanejo', + 'Charata', + 'Paduma', + 'Otake', + 'Guanta', + 'Aduru', + 'Mannarai', + 'Youghal', + 'Haacht', + 'Stowmarket', + 'Fourou', + 'Barari', + 'Libanggaon', + 'Amari', + 'Lucknow', + 'Babra', + 'Idanre', + 'Bedigoazon', + 'Acari', + 'Burslem', + 'Lohara', + 'Beersel', + 'Polillo', + 'Librazhd-Qender', + 'Kumalarang', + 'Tzitzio', + 'Bisceglie', + 'Karayilan', + "Samarra'", + 'Bafwasende', + 'North Arlington', + 'Souq Sebt Oulad Nemma', + 'Bhalswa Jahangirpur', + 'Wolfsburg', + 'Eningen unter Achalm', + 'Szubin', + 'Varadarajampettai', + 'Zelenodolsk', + 'Karagwe', + 'Vissannapeta', + 'Cheramkod', + 'Sanandaj', + 'Karben', + 'Bueng Khong Long', + 'Jaboatao', + 'Vrilissia', + 'Cumaral', + 'Akil', + 'Ap Da Loi', + 'Normanton', + 'Trois-Rivieres', + 'Almirante', + 'Esperalvillo', + 'Kongupatti', + 'Quirinopolis', + 'Lask', + 'Sainte-Luce-sur-Loire', + 'Castel San Giorgio', + 'Bang Phae', + 'Chinnayagudem', + 'Arsin', + 'Numata', + 'Sab` al Bur', + 'Cumaru', + 'Tecamac', + 'Rodelas', + 'Seyah Cheshmeh', + 'Kashan', + 'Nanzhangcheng', + 'Kendari', + 'Jurado', + 'Monrovia', + 'Peshawar', + 'Guacharachi', + 'Kloten', + 'Bandirma', + 'Quevedo', + 'Adekar Kebouche', + 'Huinca Renanco', + 'Dakpatthar', + 'Chicoutimi', + 'Baiyan', + 'Pimenteiras', + 'Las Brenas', + 'Kusnacht', + 'Burnie', + 'Ercolano', + 'Kroonstad', + 'Modena', + 'Kalna', + 'Bonneville', + 'Bellair-Meadowbrook Terrace', + 'Jiyyammavalasa', + 'Kisai', + 'Vadodara', + 'Nagtala', + 'Kandiyankovil', + 'Lorena', + 'Taphan Hin', + 'Juneau', + 'Iati', + 'Niksar', + 'Roy', + 'Kapoeta', + 'Samdhin', + 'Arafat', + 'Kornepadu', + 'Ait Faska', + 'Olevsk', + 'Rantoul', + 'Glencoe', + 'Stocksbridge', + 'Tela', + 'Chethakal', + 'Canatlan', + 'Guia de Isora', + 'Veglie', + 'Taguig City', + 'Qillin', + 'Harsinghpur', + 'Sitangkai', + 'Michigan City', + 'Nagaizumi', + 'Guariba', + 'El Seibo', + 'Woolton', + 'Tainai', + 'Mukher', + 'Cartama', + 'Suknadanga', + 'Philippsburg', + 'Ladysmith', + 'Atherton', + 'Baeza', + 'Yazikonak', + 'Santa Maria Texmelucan', + 'Ban Mae Kaluang', + 'Khiriawan', + 'Eschen', + 'Tobetsu', + 'Nova Vicosa', + 'Ankarongana', + 'Shahedshahr', + 'Sonoita', + 'Kudligi', + 'Saint-Felicien', + 'Bukama', + 'Nilgiri', + 'Zwevegem', + 'Muang Sing', + 'Pinhal', + 'Saranga', + 'Ebelo', + 'Toli', + 'Cataguases', + 'Miyaki', + 'Caracol', + 'Amol', + 'Basdeopur', + 'Cevicos', + 'Charlotte', + 'Canavieiras', + 'Deva', + 'North Shields', + 'Icaraima', + 'Hoskins', + 'Kamalshahr', + 'Guapiles', + 'Araguari', + 'Bouhlou', + 'Castilla La Nueva', + 'Azemmour', + 'Juvignac', + 'Medjedel', + 'Goksun', + 'San Justo', + 'Iyo', + 'Teploklyuchenka', + 'Yaounde', + 'Ain Kercha', + 'Treviglio', + 'Novi Pazar', + 'San Lazzaro di Savena', + 'Nakhon Ratchasima', + 'Alcantara', + 'Bull Mountain', + 'Oldeani', + 'Chardonnieres', + 'Chini', + 'Piketberg', + 'Baranoa', + 'Buldon', + 'Akora', + 'Santa', + 'Olivet', + 'Kouinine', + 'Vanipenta', + 'Shahr-e Babak', + 'Porto de Moz', + 'The Hills', + 'Kaharlyk', + 'Manpaur', + 'G`azalkent', + 'Hodmezovasarhely', + 'Oak Creek', + 'Kladanj', + 'Merouana', + 'Hiratsuka', + 'Alvares Machado', + 'Lagoa Dourada', + 'Mishan', + 'Puerto Deseado', + 'Befandriana Atsimo', + 'Supia', + 'Avon Lake', + 'Rialto', + 'Renca', + 'Mesra', + 'Rognac', + 'Pongode', + 'Birkhadem', + 'Talacogon', + 'Turhapatti', + 'Szigetszentmiklos', + 'Onoto', + 'Norala', + 'Sorala', + 'Diallassagou', + 'Handa', + 'Wieliczka', + 'Tilougguit', + 'Jaimalpura', + 'Allentown', + 'Crissiumal', + 'Varberg', + 'Abidjan', + 'Cesky Tesin', + 'Burgkirchen an der Alz', + 'Nagina', + 'Shahpur Baghauni', + 'Itarhi', + 'Bad Pyrmont', + 'Raksaha', + 'Pandireddigudem', + 'Sinfra', + 'Bayonne', + 'Bahir Dar', + 'Bobo-Dioulasso', + 'Tubaran', + 'Chihuahua', + 'Hun', + 'Rexburg', + 'Kherson', + 'Harad', + 'Saint-Fons', + 'Iazizatene', + 'Sao Pedro do Sul', + 'Tirmaigiri', + 'Otumba', + 'East Cleveland', + 'Bankoumana', + 'Goiatins', + 'Kushtagi', + 'Patori', + 'Bertrix', + 'Palanan', + 'Achaljamu', + 'Elanad', + 'Mahmud-e Raqi', + 'Bougou', + 'American Fork', + 'East Barnet', + 'Mangrauni', + 'Raghunathpur', + 'Ierapetra', + 'Crvenka', + 'Mentor', + 'Fidirana', + 'Sangareddi', + 'Pflugerville', + 'Kupiskis', + "Vil'nyans'k", + 'Sonipat', + 'Zestaponi', + 'Goffstown', + 'Lengshuijiang', + 'Scottsdale', + 'Rosemont', + 'Garsekurti', + 'Collierville', + 'Bulaevo', + 'Tosagua', + 'Burzaco', + 'Silea', + 'Roosendaal', + 'Tuusula', + 'Turnu Magurele', + 'An Nabk', + 'Sasebo', + 'San Vicente de Castellet', + 'Andranomenatsa', + 'Tbilisi', + 'Postojna', + 'Kessel-Lo', + 'Arnsberg', + 'Itarare', + 'Mazeikiai', + 'Pujehun', 'Vicovu de Sus', - 'Telua', - 'Roanoke Rapids', - 'Depew', - 'Vandalia', - 'America Dourada', - 'Castiglione del Lago', - 'Weisswasser/Oberlausitz', - 'Sefaatli', - 'Vasterhaninge', - 'Pargas', - 'Grodzisk Wielkopolski', - 'Vesoul', - 'Gangapur', - 'Majiagoucha', - 'Ambohimierambe-Andranofito', - 'New Cassel', - 'Sansepolcro', - 'Swampscott', - 'Bayserke', - 'Raynham', - 'Ban Na Kham', - 'Warni', - 'Srivardhan', - 'Kutchan', - 'Jaguapita', - 'Zacualpan', - 'Klimavichy', - 'Mazagran', - 'Xihuangni', - 'Newport Pagnell', - 'Mahikeng', - 'Vize', - 'Rumst', - 'Koduman', - 'Oulad Bou Rahmoun', - 'Tamaki', - 'Gloversville', - 'Radviliskis', - 'Sakabansi', - 'Mirai', - 'Maesawa', - 'Bhoj', - 'Itki Thakurgaon', - 'Khaira', - 'Piratininga', - 'Chautham', - 'Doumanaba', - 'Tredegar', - 'Bilaua', - 'Silvino Lobos', - 'Putyvl', - 'Nopala de Villagran', - 'Cifteler', - 'Pacific Grove', - 'Huitzilan', - 'Wulflingen', - 'Tonawanda', - 'Galatone', - 'Brake', - 'Ban Ton Thong Chai', - 'Babhani Bholwa', - 'Schriesheim', - 'Al Madamud', - 'Bhatranha', - 'Kastsyukovichy', - 'Changamkari', - 'Canyon', - 'Cernavoda', - 'Putaparti', - 'Kidal', - 'Capotille', - 'Sooke', - 'Tabhka Khas', - 'Jadia', - 'Mellila', - 'Bonheiden', - 'Makapanstad', - 'Sultandagi', - 'Eggertsville', - 'Kohir', - 'Natividade do Carangola', - 'West Park', - 'Hatton', - 'Campodarsego', - 'Hasanganj', - 'Talladega', - 'Clevelandia', - 'Ipaucu', - 'Mani', - 'Peddapalle', - 'Devendranagar', - 'Hazel Park', - 'Neustadt bei Coburg', - 'Front Royal', - 'Ut Bulag', - 'Spring Creek', - 'Bad Wurzach', - 'Olonne-sur-Mer', - 'Montargis', - 'Sabou', - 'Alvinopolis', - 'Andondabe', - 'Pedara', - 'Tatarikan', - 'Kanungu', - 'Echuca', - 'Bolivia', - 'Markgroningen', - 'Patnanungan', - 'Royse City', - 'Rajni', - 'Mineral Wells', - 'Ekma', - 'Perchtoldsdorf', - 'Amlash', - 'La Magdalena Tlaltelulco', - 'Pontinia', - 'Boskoop', - 'Saint-Avold', - 'Murray Bridge', - 'Langelsheim', - 'Revur', - 'Kamitonda', - 'Burshtyn', - 'Ylivieska', - 'Ochanthururtha', - 'Carrieres-sur-Seine', - 'Villa Ocampo', - 'Chepica', - 'Grenzach-Wyhlen', - 'Mollerusa', - 'Contamana', - 'Tone', - 'Le Hochet', - 'Corupa', - 'Ritterhude', - 'Satyamangala', - 'Zozocolco de Hidalgo', - 'Filiasi', - 'Fritzlar', - 'Sabbah', - 'Udiyavara', - 'Ban Ho Mae Salong', - 'South Farmingdale', - 'Ferreiros', - 'Cuevas del Almanzora', - 'Swallownest', - 'Midar', - 'Kutavettur', - 'Brasilandia', - 'Ban Mae Sun Luang', - 'Puerto Salgar', - 'Boa Esperanca do Sul', - 'Netherton', - 'Aruvikkara', - 'Lockhart', - 'Kaintragarh', - 'Hudiksvall', - 'Konarka', - 'Shamsa', - 'Westervoort', - 'Busko-Zdroj', - 'Issoire', - 'Andorinha', - 'Canet de Mar', - 'Cassano delle Murge', - 'Struga', - 'Dionisio Cerqueira', - 'Dembecha', - 'Alpedrete', - 'Witzenhausen', - 'Wallan', - 'Novyi Buh', - 'Sarvar', - 'Barajor', - 'Pavannur', - 'Verdal', - 'California City', - 'Acala', - 'Kezi', - 'Ras Baalbek', - 'Quthing', - 'Manambondro', - 'Milenaka', - 'Soalala', - 'Ambodiriana', - 'Befasy', - 'Kopoky', - 'Ramainandro', - 'Ambatomanjaka', - 'Andranovelona', - 'Ianantsony', - 'Analamary', - 'Imanombo', - 'Beroy Atsimo', - 'Alarobia Bemaha', - 'Talata Ampano', - 'Ambatoharanana', - 'Sahave', - 'Bevoay', - 'Anahidrano', - 'Ambahive', - 'Ifatsy', - 'Ankisabe', - 'Anjoma-Ramartina', - 'Lokomby', - 'Behisatse', - 'Iharana', - 'Manandona', - 'Antanimenabaka', - 'Marofototra', - 'Tsiatajavona-Ankaratra', - 'Antsoso', - 'Ambesisika', - 'Ankilimivory', - 'Wan Long', - 'Kyaukmyaung', - 'Aiyetoro Gbede', - 'Amawom', + 'Okayama', + 'Sarauli', + 'Lakeville', + 'Dashtigulho', + 'Itapolis', + 'Al Hazm', + 'Hammelburg', + 'Berastagi', + 'Orlu', + 'Castanet-Tolosan', + 'Lumbayanague', + 'Oeiras do Para', + 'Whitney', + 'Tubara', + 'Santa Maria Madalena', + 'Salinas de Hidalgo', + 'Sangonera la Verde', + 'Noisy-le-Sec', + 'Glenview', + 'Bern', + 'Song Cau', + 'Dyer', + 'Chabal Kalan', + 'Segala Mba', + 'Upper Hutt', + 'Massigui', + 'Nalgonda', + 'Terra Boa', + 'Svrljig', + "'Ain Tellout", + 'Bellefontaine Neighbors', + 'Sahibpur Kamal', + 'Nieuwleusen', + 'Acarlar', + 'Chuo', + 'Hellesdon', + 'Kotor', + 'Montepulciano', + 'Emstek', + 'Daye', + 'Kona', + 'Saint-Genis-Pouilly', + 'Puerto Rico', + 'Sitamau', + 'Anguera', + 'North Lebanon', + 'Pesqueira', + 'Guarei', + 'Pendurti', + 'Falls', + 'Pinillos', + 'Sighetu Marmatiei', + 'Bangui', + 'Tchitado', + 'Tanga', + 'Kesamudram', + 'Narayangarh', + 'Dapitan', + 'Kaithahi', + 'Saint-Cyr-sur-Mer', + 'Jandaira', + 'Bedum', + 'Tomatlan', + 'Pirapemas', + 'Bemahatazana-Belobaka', + 'Poblacion', + 'El Cua', + 'Maldonado', + 'Pando', + 'Madappalli', + 'Cumru', + 'Al Mahwit', + 'Chake Chake', + 'Oria', + 'Zimnicea', + 'Kivisto', + 'Bumahen', + 'Wichian Buri', + 'Carrascal', + 'Pedro Betancourt', + 'Hire Megalageri', + 'Ternate', + 'Saoner', + 'Itaituba', + 'Vohitrafeno', + 'Caluula', + 'Muggia', + 'Aizenay', + 'Khokha', + 'Ipokia', + 'Venmani Padinjara', + 'Siklos', + 'Yangshuwa', + 'Kanekallu', + 'Golbey', + 'Gengzhuangqiaocun', + 'Gustavsberg', + 'Parabiago', + 'Ambohibary', + 'Valladolid', + 'Matamey', + 'Bisee', + 'Tete', + 'Vreden', + 'Toribio', + 'Fucecchio', + 'Zangareddigudem', + 'Ceglie Messapico', + 'Licinio de Almeida', + 'Ad Dabbah', + 'Sapian', + 'Naranjo', + 'Wollaston', + 'Celaya', + 'Dire', + 'Gajiginhalu', + 'Mulug', + 'Upper Makefield', + 'Rodriguez', + 'Bocoio', + 'Thalwil', + 'Carate Brianza', + 'Bondada', + 'Ayagoz', + 'Xiada', + 'Vohburg an der Donau', + 'Mansala', + 'Rafha', + 'Anastacio', + 'Nove Mesto na Morave', 'Ramechhap', - 'Bhimphedi', - 'Mian Sahib', - 'Awan Patti', - 'Koungheul', - 'Bakel', - 'Yufle', - 'Kuljibrin', - 'Sarmada', - 'Gammarth', - 'Ozdere', - 'Kalongo', - 'Matuga', - 'Zombo', - 'Mutukula', - 'Chaguaramas', - 'Clarines', - 'Fayroz Koh', - 'Taywarah', - 'Spitak', - 'Villa Ojo de Agua', - 'Baisari', - 'Jamaica', - 'Guayos', - 'Villaviciosa', - 'Saint-Avertin', - 'Hessle', - 'Tillor Khurd', - 'Chettikulam', - 'Aivanallur', - 'Shafinagar', - 'Damalcheruvu', - 'Cortalim', - 'Majhgawan', - 'Hombal', - 'Bellatti', - 'Singhanwala', - 'Hullahalli', - 'Muttamtura', - 'Sathamba', - 'Valattur', - 'Nedumpura', - 'Turori', - 'Khandhar', - 'Shirud', - 'Galatge', - 'Vasa', + 'Ambinanindrano', + 'Leibnitz', + 'Alvaraes', + 'Baure', + 'Sohano', + 'Tunja', + 'Goriar', + 'Msambweni', + 'Aibak', + 'Penugolanu', + 'Castagneto Carducci', + 'Ecclesall', + 'Dunmore', + 'North Londonderry', + 'Carnot-Moon', + 'Pau Brasil', + 'Taka', + 'Sihor', + 'Terra Nova', + 'Choachi', + 'Tenri', + 'Port Louis', + 'Laoag', + 'San Martin de la Vega', + 'Nguigmi', + 'Bendapudi', + 'Eminabad', + 'Aldenham', + 'Vianen', + 'Nagasamudram', + 'Zemst', + 'Khalkhal', + 'Mount Clemens', + 'Teotlaltzingo', + 'Siribala', + 'Ligao', + 'Dom Pedrito', + 'Bushey', + 'Namakgale', + 'Waiuku', + 'Juruaia', + 'Sikasso', + 'Laplace', + 'Gao', + 'Casarano', + 'Ratangarh', + 'Brunssum', + 'Castrovillari', + 'Tarkeshwar', + 'Ruisui', + 'Monschau', + 'Alat', + 'Hetauda', + 'Tunglangan', + 'Panipat', + 'El Chal', + 'Bhanumukkala', + 'Don Galo', + 'Saddiqabad', + 'Santo Domingo Petapa', + 'Bingol', + 'Piraju', + 'Camp Verde', + 'Chembagaramanpudur', + 'Behara', + 'Harrison', + 'Nagulapadu', + 'Knemis Dades', + 'Youwangjie', + 'Sarab', + 'Rustavi', + 'Obama', + 'Dymka', + 'Bijie', + 'Tairan Camp', + 'Sahoria Subhai', + 'Southampton', + 'Port Moody', + 'Guaratinga', + 'Xa Muteba', + 'Ahmadnagar', + 'Limanowa', + 'Dembi Dolo', + 'Samrala', + 'Aichach', + 'Codroipo', + 'Nattarampalli', + 'Induno Olona', + 'Gosen', + 'Bevato', + 'Elkridge', + 'Trissino', + 'Siping', + 'Bou Hanifia el Hamamat', + 'Juayua', + 'Tordera', + 'Osnabruck', + 'Zegoua', + 'Ramain', + 'Varanasi', + 'Miedzyrzecz', + 'Bradfordville', + 'Arkansas City', + 'Sidi Mohamed Lahmar', + 'Paravai', + 'Baltara', + 'Paide', + 'Manakara', + 'Edassheri', + 'Usiacuri', + 'Yildirim', + 'Keflavik', + 'Tsetserleg', + 'Paris', + 'Gagnoa', + 'Xintang', + 'Sarni', + 'Xico', + 'Capitan Bermudez', + 'Contenda', + 'Garhwa', + 'Huayin', + 'Basuo', + 'Tenjo', + 'Cachan', + 'Quimperle', + 'Misato', + 'Pittsgrove', + 'Dumont', + 'Salford', + 'Bontoc', + 'Lexington Park', + 'Yame', + 'Narasaraopet', + 'Kesla', + 'Ystad', + 'Laqraqra', + 'Milot', + 'Benoy', + 'Jalandhar', + 'Qahderijan', + 'Wake', + 'Flowing Wells', + 'Santana do Acarau', + 'Kurdi', + 'Sison', + 'Mazamet', + 'Montrouis', + 'Kalaruch', + 'Sarotar', + 'Dabuleni', + 'Thepaha Raja Ram', + 'Glenn Heights', + 'Tuxtepec', + 'Whickham', + 'Targu Frumos', + 'Lauriya Nandangarh', + 'Taineste', + 'Medjez el Bab', + 'Sagon', + 'Cinisello Balsamo', 'Bartalah', - 'Amirli', - 'Yinhua', - 'Winkfield', - 'Talpa de Allende', - 'Worthington', - 'Buda', - 'Sanyi', - 'Shambu', - 'Huchuan', - 'Anororo', - 'Santa', - 'Suvalan', - 'Buttelborn', - 'Kisvarda', - 'Shklow', - 'Djambala', - 'La Gloria', - 'Pyryatyn', - 'Kaguchi', - 'Salinas da Margarida', - 'Esbiaat', - "Sant'Arpino", - 'Calanogas', - 'Lapseki', - 'Yelur', - 'Mandleshwar', - 'Andipalaiyam', - 'Belkheir', - 'Bouchegouf', - 'Texenna', - 'Petersfield', - 'Casalmaggiore', - 'Candoi', - 'Tavros', - 'Chirpan', - 'Porcia', - 'Castelnuovo Rangone', - 'Laurinburg', - 'Chrysoupoli', - 'Avanos', - 'Mastic', - 'Kenora', - 'Kenley', - 'Douar Souk L`qolla', - 'Santa Brigida', - 'El Hadjira', - 'Tabant', - 'Paralimni', - 'Saint-Servan-sur-Mer', - 'West University Place', - 'Baucau', - 'Cold Lake', - "'Tlat Bni Oukil", - 'Veliki Preslav', - 'Goluwali', - 'Lakeland North', - 'Weigelstown', - 'Metuchen', - 'Bludenz', - 'Vianopolis', - 'Monkey Bay', - 'Sidi Zouine', - 'Catalpinar', - 'Dolo', - 'Coconuco', - 'Finale Emilia', - 'Wyke', - 'Ramonville-Saint-Agne', - 'Lambidou', - 'Vallur', - 'Mitane', - 'Mendrisio', - 'Bissendorf', - 'Baiersbronn', - 'Joaima', - 'Serhetabat', - 'Grande Saline', - 'Restinga Seca', - 'Majholi', - 'Newtown', - 'Avrille', - 'Ganjam', - 'Swidwin', - 'Kimyogarlar', - 'La Fleche', - 'Oued Jdida', - 'Schiffdorf', - 'Calkini', - 'Chandi', - 'Riverdale', - 'Itahara', - 'Jisr ez Zarqa', - 'Malsch', - 'Ahigbe Koffikro', - 'Beckingen', - 'Chemmanam', - 'Gourrama', - 'Nalerigu', - 'Usingen', + 'Valabhipur', + 'Tangdukou', + 'Barreirinha', + 'Calintaan', + 'Binan', + 'Rampur', + 'Malatya', + 'Clemson', + 'Wyszkow', + 'Carmiano', + 'Yeovil', + 'Cajobi', + 'Yabuki', + 'Dorud', + 'Marrupa', + 'Maitland', + 'Jahrom', + 'Kurgunta', + 'Tonyrefail', + 'Virreyes', + 'Kalu Khan', + 'Al Qurayya', + 'Libertyville', + 'Kharagpur', + 'Woodley', + 'Mineola', + 'Chalon-sur-Saone', + 'Bouhmama', + 'Mena', + 'San Cataldo', + 'Quipungo', + 'Alakamisy-Ambohimaha', + 'Gloversville', + 'Chuimatan', + 'Nadugadda', + 'Borjomi', + 'Sibonga', + 'Palanpur', + 'Kodinar', + 'Asingan', + 'Chahchaheh', + 'Dobrova', + 'Ruzomberok', + 'Chhoti Sadri', + 'Langzhong', + 'Anekal', + 'Pontal do Parana', + 'Muhammadabad', + 'Moreira', + 'Civita Castellana', + 'Kpalime', + 'Mahespur', + 'Louny', + 'Venkatapuram', + 'Khaw Zar Chaung Wa', + 'Dahutang', + 'Data', + 'Cheddra', + 'Madridejos', + 'DeLand', + 'Koewarasan', + 'Palaiseau', + 'Ropczyce', + 'Urakawa', + 'Tanque Novo', + 'Guider', + 'Kiruhura', + 'Kasese', + 'Murrhardt', + 'Andingcun', + 'Kuhdasht', + 'Freire', + 'Singera', + 'Panglong', + 'Tampa', + 'Mirik', + 'Hatti Mattur', + 'Nakatsugawa', + 'Jitwarpur Nizamat', + 'Carmo', + 'Jocotan', + 'Forquilha', + 'Vargem Grande do Sul', + 'Peniche', + 'Xinying', + 'Nahulingo', + 'Goranboy', + 'San Pedro Sula', + 'Burr Ridge', + 'Leatherhead', + 'Belisce', + 'Villalonga', + 'Santa Anita', + 'Mayluu-Suu', + 'Skovde', + 'Buston', + 'Domodossola', + 'Avelgem', + 'El Malah', + 'Azusa', + 'Neyriz', + 'Coronel Suarez', + 'Saquarema', + 'Meizhou', + 'Apia', + 'Jawor', + 'Saint-Pol-sur-Mer', + 'Heguri', + 'Bobangui', + 'Montalegre', + 'Ben Taieb', + 'Pande', + 'Horsell', + 'Sanjo', + '`Aynkawah', + 'Sfantu-Gheorghe', + 'Escuinapa', + 'Talikota', + 'Guapiara', + 'Point Pleasant', + 'Ambohipandrano', + 'Khangaon', + 'Namlea', + 'Kottapalem', + 'Sebastiao Laranjeiras', + 'Phra Samut Chedi', + 'Madanancheri', + 'Farnworth', + 'Coshocton', + 'Garrison', + 'Peso da Regua', + 'Jaguaruna', + 'Katihar', + 'West Fargo', + 'Melaka', + 'Ambohimanambola', + 'Pabegou', + 'Nossa Senhora das Dores', + 'Burladingen', + 'Byumba', + 'Vallikunnam', + 'Mohan Eghu', + 'San Julian', + 'Miracema do Tocantins', + 'Palma', + 'Goh', + 'DeKalb', + 'Azle', + 'Mont-de-Marsan', + 'Slovenske Konjice', + 'Manazary', + 'Shende', + 'Portland', + 'Lamarao', + 'Reinach', + 'Chrzanow', + 'Hendek', + 'Iwakura', + 'Agua Clara', + 'Capim', + 'Brasilandia', + 'Port Colborne', + 'Ilsfeld', + 'Cienaga de Oro', + 'Faxinal dos Guedes', + 'Earlestown', + 'Andranomeva', + 'Visalia', + 'Tazhava', + 'Linquan', + 'Rampur Jalalpur', + 'Cricova', + 'Cholula de Rivadabia', + 'Apiai', + 'Vilandai', + 'Castellana Grotte', + 'Baturbari', + 'Jandiala', + 'Rive-de-Gier', + 'Feltham', + 'Laguna Niguel', + 'Kannal', + 'Purmerend', + 'Succasunna', + 'Ejea de los Caballeros', + 'Dolisie', + 'Vernag', + 'Tabount', + 'Kirksville', + 'Rahuri', + 'Nanjai Kilabadi', + 'Parigi', + 'Dhamsain', + 'Bainbridge', + 'Zumpango', + 'Le Beausset', + 'Westphalia', + 'Cabinda', + 'Bagahi', + 'Valmontone', + 'Al `Ajami', + 'Maromby', + 'Maaseik', + 'Wuyishan', + 'Ulbroka', + 'Santiago Juxtlahuaca', + 'Ranomena', + 'Buadiposo-Buntong', + 'Khurai', + '`Aqrah', + 'Priverno', + 'Geldrop', + 'Balandougou', + 'Legnago', + 'Don Carlos', + 'Keitumkawn', + 'Levice', + 'Gulam', + 'Ratne', + 'Jiayuguan', + 'Gidha', + 'Juba', + 'Ksar Belezma', + 'Puerto Baquerizo Moreno', + 'Ponta Pora', + 'Sidrolandia', + 'Achim', + 'North Lynnwood', + 'Haslett', + 'Porto Ferreira', + 'Anqing', + 'Takahagi', + 'Fray Luis A. Beltran', + 'Basudebpur', + 'Concon', + 'Mangochi', + 'McKeesport', + 'Matheu', + 'Sumbha', + 'Murajpur', + 'Champerico', + 'Iki', + 'Port-Bouet', + 'Santa Luzia', + 'Chitaldrug', + 'Baliqchi', + 'Uthai Thani', + 'Az Zubaydiyah', + 'Cicero', + 'Rampurwa', + 'El Salto', + 'Duero', + 'Littleover', + 'Ropazi', + 'Andradas', + 'Tirur', + 'Caramoan', + 'San Carlos Alzatate', + 'Zuojiawu', + 'Karacasu', + 'Namioka', + 'Brumunddal', + 'West Milford', + 'Alandatte', + 'Dumingag', + 'Petrolandia', + 'Arachchalur', + 'Urussanga', + 'Cerrillos', + 'Ortega', + 'Kanyobagonga', + 'Atibaia', + 'Eustis', + 'Sefaatli', + 'Lasam', + 'Montalto di Castro', + 'Cihuatlan', + 'Cirebon', + 'Rangewala', + 'Tekkalakote', + 'Cameron Park', + 'Bardaskan', + 'Manambidala', + 'Bukittinggi', + 'Sora', + 'Dashouping', + 'Escarcega', + 'Tezoyuca', + 'Karadichittur', + 'Roskilde', + 'West Caln', + "Pereyaslav-Khmel'nyts'kyy", + 'Senmanat', + 'Formosa', + 'Schaumburg', + 'Tarnobrzeg', + 'Kadaladi', + 'Ouled Haddaj', + 'Vuyyuru', + 'Baruipur', + 'Teniente Primero Manuel Irala Fernandez', + 'Menaceur', + 'Sedeh Lanjan', + 'Ciney', + 'Amboavory', + 'Jale', + 'Kalmar', + 'Koori', + 'Alsager', + 'Gulagac', + 'Zwedru', + 'Kadiyampatti', + 'Wilkes-Barre', + 'Bremerhaven', + 'Motru', + 'Bad Tolz', + 'Nha Trang', + 'Andranomavo', + 'Punta Prieta', + 'Masmouda', + 'Vavatenina', + 'Divandarreh', + 'Atambua', + 'Krosuru', + 'Wrecsam', + 'Apache Junction', + 'Barri', + 'Shingucho-shingu', + 'Kusaha', + 'Sidi Ahmed El Khadir', + 'West Springfield', + 'Al Wajh', + 'Massangena', + 'Doda', + 'Shutayil', + 'Messamena', + 'Navalcarnero', + 'Bellaire', + 'Nichelino', + 'Serra Azul', + 'Rantabe', + 'Padaivedu', + 'Monteroni di Lecce', + 'Drodro', + 'Rees', + 'Bulgan', + 'Fraijanes', + 'Montbrison', + 'Kangaroo Flat', + 'Urbach', + 'Lindon', + 'Olen', + 'Langgons', + 'Velim', + 'Marhamat', + 'Anamur', + 'Milattur', + 'Forecariah', + 'Quartier Morin', + 'Worb', + 'Playas', + 'Kingsville', + 'North Strabane', + 'Kolumalapalle', + 'Narippatta', + 'Yotsukaido', + 'Takahashi', + 'Dulce Nombre de Maria', + 'Reguiba', + 'Dapi', + 'Elk River', + 'Karaagac', + 'Duba', + 'Rasnov', + 'Cabrobo', + 'Easthampton', + 'Parvatipuram', + 'Husainpur', + 'Nipomo', + 'Chettimangurichchi', + 'Bekitro', + 'Itapagipe', + 'Palestina', + "Erval d'Oeste", + 'Vasilika', + 'Kolappalur', + 'Batken', + 'Bank', + 'Qorako`l Shahri', + 'Manor', + 'Majanji', + 'Al Balyana', + 'Niederkassel', + 'Dulce Nombre de Jesus', + 'Mason City', + 'Lavello', + 'Zaruma', + 'Mignoure', + 'Namyslow', + 'Hagaranahalli', + 'Filippoi', + 'Ita', + 'Wuzhong', + 'Bedfordview', + 'Mollet', + 'Malipakar', + 'Innisfil', + 'Cehegin', + 'Stone', + 'Lake St. Louis', + 'Panskura', + 'Injibara', + 'Festus', + 'Cicevac', + 'Busra ash Sham', + 'Krompachy', + 'Mumford', + 'Phulmalik', + 'Jundiai', + 'Annaka', + 'Senhora dos Remedios', + 'Anthem', + 'Sadarak', + 'Naga City', + 'Xiping', + 'Planeta Rica', + 'Kilgore', + 'Ciudad Sabinas Hidalgo', + 'Tsaratanana', + 'Puduppalli Kunnam', + 'Manilva', + 'Colorno', + 'Majsperk', + 'Pibrac', + 'Nova Gorica', + 'Sorbolo', + 'Halberstadt', + 'Magalang', + 'Cozumel', + 'Chanco', + 'Gympie', + 'Colwood', + 'Vire', + 'Troina', + 'Oudenbosch', + 'Bertinoro', + 'El Bazouriye', + 'Cabra', + 'Alakamisy-Ambohimahazo', + 'Milan', + 'Sanare', + 'Trencin', + 'Minas', + 'Santa Vitoria do Palmar', + 'Saintes', + 'San Jose de las Lajas', + 'Governador Dix-Sept Rosado', + 'Ville-la-Grand', + 'Stjordal', + 'Kirkwall', + 'Aigaleo', + 'Uppukkottai', + 'Lakeway', + 'Cuchi', + 'Kamina', + 'Rawa Mazowiecka', + 'Xinyuan', + 'Scarsdale', + 'Tosashimizu', + 'Akot', + 'Yaritagua', 'East Rancho Dominguez', - 'Brooks', - 'Yellareddi', - 'Lanji', - 'Sembedu', - 'Lakkundi', - 'Tecuala', - 'Castanuelas', - 'Pursa', - 'Kunnumel', - 'Krasnohorivka', - 'Escaldes-Engordany', + 'Pongoz', + 'Ambazoa', + 'Liuchuan', + 'Higashiura', + 'Blackfoot', + 'Gniezno', + 'Blanchard', + 'Zadar', + 'Nakaechi', + 'Mairena del Aljarafe', + 'Massama', + 'Mobo', + 'Kezmarok', + 'La Porte', + 'Berching', + 'Siegsdorf', + 'New Albany', + 'Half Way Tree', + 'Jharka', + 'Zinacantepec', + 'Draveil', + 'Bek-Abad', + 'Fayetteville', + 'Oyam', + 'Pasil', + 'Clamart', + 'Mbuzini', + 'Ouenza', + 'Perdur', + 'Soamanandrariny', + 'Hanawa', + 'Yekambarakuppam', + 'Mashiki', + 'Thibodaux', + 'Nijkerk', + 'Hayang', + 'Malabon', + 'Aparri', + 'Bwana Mkubwa', + 'Charqueada', + 'Kuju', + 'Kwamhlanga', + 'Alimos', + 'Ypane', + 'Sahave', + 'Marib', + 'Shirley', + 'Bunbury', + 'Talayan', + 'Ljungby', + 'San Juan de Betulia', + 'Laixi', + 'La Ferte-Bernard', + 'Lagos de Moreno', + 'Tangbian', + 'Adalar', + 'Nyamira', + 'Desert Hot Springs', + 'Datia', + 'Cognac', + 'Jaltipan de Morelos', + 'Ponsacco', + 'Dindori', + 'Hlaingbwe', + 'Delijan', + 'Cirie', + 'Une', + 'Boldesti-Scaeni', + 'Sapeacu', + 'Nagdah', + 'Douar Ezzerarda', + 'Bali', + 'Stevenage', + 'Saryshaghan', + 'Melchor Romero', + 'Barbana', + 'Zanjan', + 'Sennan', + 'Ponta Delgada', + 'Royse City', + 'Wonthaggi', + 'Putaendo', + 'Kokawa', + 'Wloszczowa', + 'Warner Robins', + 'Kranenburg', + 'Tome', + 'Usilampatti', + 'Puerto Pinasco', + 'El Maiten', + 'Gurgaon', + 'Immenstadt im Allgau', + 'Wisla', + 'Gannavaram', + 'Yingzhong', + 'Masho Khel', + 'Reitz', + 'Belen de Umbria', + 'Ripollet', + 'Lauaan', + 'Beira', + 'Ratu', + 'Mure', + 'Medicine Hat', + 'Ixcatepec', + 'Bois-des-Filion', + 'Nogent-le-Rotrou', + 'Djibouti', + 'University of California-Santa Barbara', + 'Byahatti', + 'Bentonville', + 'Danau Kandimarg', + 'Tevragh Zeina', + 'Sattar', + 'Tranoroa', + 'Mengdong', + 'Luz', + 'Wuyang', + 'Batemans Bay', + 'Dinas', + 'Itauna', + 'Artena', + 'Carouge', + 'Xylokastro', + 'Bahia de Caraquez', + 'Marabella', + 'Bremerton', + 'Ixtlahuacan del Rio', + 'Garchitorena', + 'Huittinen', + 'Fonsorbes', + 'Bafia', + 'Da Lat', + 'Pasian di Prato', + 'Sarayonu', + 'Chiman', + 'Colombo', + 'Kirikera', + 'Pemmperena', + 'Grunwald', + 'Savalgi', + 'Chambly', + 'Puduppatti', + 'Himamaylan', + 'Lansdowne', + 'Douar Mzoura', + 'Powell', + 'Erfurt', + 'Kizhake Chalakudi', + "L'Arbaa Nait Irathen", + 'Galmi', + 'Junagarh', + 'Murgap', + 'Sallanches', + 'Loutete', + 'Rosa Zarate', + 'Caninde', + 'Santa Tecla', + 'Skoghall', + 'Banswada', + 'Cresskill', + 'Dabaozi', + 'Cortland', + 'Ennery', + 'Ifanirea', + 'Antsaidoha-Bebao', + 'Tepic', + 'Qiryat Gat', + 'Cabeceiras de Basto', + 'Pirot', + 'Waxahachie', + 'De Pere', + 'Salsomaggiore Terme', + 'Potenza Picena', + 'Wright', + 'Resadiye', + 'Melito di Napoli', + 'Toui', + 'Guercif', + 'Daga', + 'Porto Feliz', + 'Sinende', + 'Goasi', + 'Kikube', + 'North Tidworth', + 'Narona', + 'Capitao Eneas', + 'Makakilo', + 'Billere', + 'Tabas', + 'Klang', + 'Agogo', + 'Turnov', + 'Fairhaven', + 'Muriae', + 'Chakai', + 'Maniamkulam', + 'Seberang Jaya', + 'Jaboticatubas', + 'Burley', + 'Four Square Mile', + 'Kirchlinteln', + 'El Quetzal', + 'Mar del Plata', + 'Elattur', + 'Mezica', + 'Brunn am Gebirge', + 'Quetta', + 'Morokweng', + 'Kitanagoya', + 'Manacapuru', + 'Towamencin', + 'Aragona', + 'Regla', + 'Caldeirao Grande', + 'Musina', + 'Jacksonville', + 'Azul', + 'Winter Park', + 'Englefield Green', + 'Ambon', + 'Lucena', + 'Huntington Station', + 'Itarema', + 'San Francisco Chimalpa', + 'Ondokuzmayis', + 'Basford', + 'Antsaravibe', + 'Meilen', + 'Tangermunde', + 'Wijchen', + 'Castilleja de la Cuesta', + 'Lanark', + 'Usak', + 'Wall', + 'Mijas', + 'Sitionuevo', + 'East Lake', + 'Mahabo-Mananivo', + 'Dhoraji', + 'Jalacingo', + 'Willstatt', + 'Nakhl-e Taqi', + 'Opelousas', + 'Golo-Djigbe', + 'Santiago Nonualco', + 'Pulsano', + 'Simrol', + 'Ihnasya al Madinah', + 'Pozzallo', + 'Ramayipatti', + 'Sihaul', + 'Wanze', + 'Senduria', + 'Ergue-Gaberic', + 'Mauldin', + 'Sempeter pri Gorici', + 'Ammanabrolu', + 'Mitrapur', + 'Massarosa', + 'Binnish', + 'La Tour-de-Peilz', + 'Lavaltrie', + 'Barsbuttel', + 'Seberi', + "Murang'a", + 'Macherla', + 'Acharipallam', + 'Setana', + 'Yichun', + 'Lugus', + 'Parnamirim', + 'Kayes', + 'Chinu', + 'Tubmanburg', + 'Cekme', + 'Mehdauli', + 'Vaulx-en-Velin', + 'Waikabubak', + 'Fontibon', + 'Omaha', + 'Pambujan', + 'Kassorola', + 'Khonj', + 'La Maddalena', + 'Fandrandava', + 'Chinna Mupparam', + 'Nea Smyrni', + 'Burgdorf', + 'Ituporanga', + 'Rayamangalam', + 'Albury', + 'Paranapanema', + 'Smiltene', + 'Lohmar', + 'Puliyankunnu', + 'Tiruvalla', + 'Hochberg', + 'Minto', + 'Antelope', + 'Mohanur', + 'Wiang Sa', + 'Dobrich', + 'Ingelheim', + 'Shetou', + 'Gavle', + 'Svedala', + 'Borogani', + 'Kisoro', + 'Ortenberg', + 'Uttarpara', + 'Rajaldesar', + 'Al Badari', + 'Masinigudi', + 'Gold Coast', + 'Indiana', + 'Swissvale', + "Al Jazirah al Hamra'", + 'Santa Maria Capua Vetere', + 'Mangala', + 'Upper Bicutan', + 'Hacilar', + 'Woltersdorf', + 'Khwazakhela', + 'Santa Fe de Antioquia', + 'Gammasa', + 'Iwashita', + 'Bohmte', + 'Tondabayashicho', + 'Salobrena', + 'Unebicho', + 'Isaszeg', + 'Bloomsburg', + 'Vidor', + 'Niquero', + 'Niepolomice', + 'Halacho', + 'Khanpur Khairanti', + 'Sao Roque', + 'Shively', + 'Fox Crossing', + 'Postmasburg', + 'Vicentinopolis', + 'Rafael Delgado', + 'Fuglafjordhur', + 'Bekapaika', + 'Rastede', + 'Devnya', + 'Derecik', + 'Nida', + 'Odayarpatti', + 'Bala', + 'Harra', + 'Ain Youcef', + 'Kenge', + 'Sapone', + 'Dongtai', + 'Ratnapur', + 'Giron', + 'Kartuzy', + 'Lake Villa', + 'Kolaccheri', + 'Kiridh', + 'Hattersheim', + 'Daheba', + 'Et Taiyiba', + 'Ciudad del Plata', + 'Ohringen', + 'Tegina', + 'Ishii', + 'Gahmar', + 'Lancaster', + 'Carmel', + 'Firminy', + 'Akishima', + "Milla'ab", + 'Beparasy', + 'Esperanza', + 'Bignay', + 'Spruce Grove', + 'Krommenie', + 'Hollviken', + 'Westminster', + 'Shymkent', + 'Majhaulia', + 'Biscarrosse', + 'Kadur Sahib', + 'Luce', + "Al Ha'ir", + 'Teluk Intan', + 'Dubove', + 'Qiaotouba', + 'Qasbat Tadla', + 'North Walsham', + 'Aspe', + 'Dokkum', + 'Plaridel', + 'Sonsbeck', + "Cava de' Tirreni", + 'Santa Elena', + 'Barka Gaon', + 'Asagicinik', + 'Dagua', + 'Campina Verde', + 'Kaitaia', + 'Leverkusen', + 'Merchtem', + 'Kiwoko', + 'Samborondon', + 'Palm Valley', + 'Fengjia', + 'Muhos', + "'Ain Kerma", + 'Sihma', + 'Tuminkatti', + 'Letychiv', + 'Notse', + 'Pearsall', + 'Jeypore', + 'San Antonio Palopo', + 'Kingstown', + 'Lislique', + 'Sannat', + 'Monnickendam', + 'Kurabalakota', + 'Miranorte', + 'Rudersberg', + 'Kasama', + 'Granja', + 'Amarwa Khurd', + 'Ad Diwaniyah', + 'Evington', + 'Warman', + 'Kuttampuzha', + 'Mons', + 'Korsholm', + 'Gourma Rharous', + 'General Alvear', + 'Matelica', + 'Bongabon', + 'Irituia', + 'Son en Breugel', + 'Chauny', + 'Bayeux', + 'Unicov', + 'Shaler', + 'Aesch', + 'Rahata', + 'Porangaba', + 'Hattingen', + 'Ocampo', + 'Pirna', + 'Perunad', + 'Umm Badr', + 'Ramganj Mandi', + 'Saidia', + 'Mutata', + 'Manatuto', + 'Lambayeque', + 'Grasse', + 'Centreville', + 'Bandrele', + 'Glogow', + 'Canagatan', + 'Trisshileri', + 'Pavona', + 'Diamniadio', + 'Harsola', + 'Gulariya', + 'Dubendorf', + 'San Prisco', + 'Maissade', + 'Agios Nikolaos', + 'Dubak', + 'Nalut', + 'Bhadrachalam', + 'Upper Moreland', + 'Geyve', + 'El Tejar', + 'Castilla', + 'Amsin', + 'Meulebeke', + 'San Francisco El Alto', + 'Presidente Getulio', + 'Pakwach', + 'Mayfield', + 'Kalawana', + 'Evosmos', + 'Killarney', + 'Zhubei', + 'El Ksiba', + 'Sierpc', + 'Lambari', + 'Fakfak', + 'Dawlish', + 'Kambaliyampatti', + 'Dianke', + 'Gaoya', + 'Almenara', + 'Molina de Segura', + 'Zighout Youcef', + 'San Jose Poaquil', + 'Louvres', + 'Los Altos', + 'Newton Aycliffe', + 'Chesterfield', + 'Korhogo', + 'Srbac', + 'Warstein', + 'Talladega', + 'Tigaon', + 'Pozos', + 'Raja Pakar', + 'Kuttiyeri', + 'Tres Cachoeiras', + 'Luena', + 'Betatao', + 'Sredisce ob Dravi', + 'West Monroe', + 'Sonabedha', + 'Rhenen', + 'Talainayar Agraharam', + 'Serido', + 'Campobasso', + 'Zabkowice Slaskie', + 'Harji', + 'Ubata', + '`Ajab Shir', + 'Tatoufet', + 'Hailun', + 'Kiratot', + 'El Idrissia', + 'Liannong', + 'Nedelisce', + 'Pirangi', + 'Beringen', + 'Leopoldo de Bulhoes', + 'Northolt', + 'Quesada', + 'Peumo', + 'Zitiste', + 'Kerman', + 'Cigli', + 'Gaibandha', + 'Tostado', + 'Ilog', + 'Mohana', + 'Erbach', + 'Mahasoabe', + 'Latifpur', + 'Rajim', + 'Tirhassaline', + 'Rathenow', + 'Strendur', + 'Grigny', + 'Skoczow', + 'Belwa', + 'Kasavanampatti', + 'Kalinagar', + 'Navappatti', + 'Megara', 'Lolotique', - 'Lalejin', - 'Kew Green', - 'Hickory Hills', - 'Lagangilang', - 'Barra do Sul', - 'Sardinal', - 'Badarpur', - 'Kela Khera', - 'Ammur', - 'Aghbal', - 'Vinanivao', - 'Sindhnur', - 'Aizubange', - 'Kentville', - 'Castanet-Tolosan', - 'Morlaix', - 'Podebrady', - 'Torello', - 'Aiyampuzha', - 'Holliston', - 'Kurate', - 'Lake Arbor', - 'Vakhsh', - 'Qumqo`rg`on', - 'Chapelle-lez-Herlaimont', - 'Beizhou', - "Quan'ancun", - 'Cumayeri', - 'Tsabit', - 'Sisian', - 'Coquimatlan', - 'Naxxar', - 'Nastola', - 'Valangiman', - 'Dimiao', - 'Stolac', - 'Sassenheim', - 'Jhandapur', - 'Sahakevo', - 'Chemax', - 'West Wickham', - 'Parapatti', - 'Cerro Maggiore', - 'Bohodukhiv', - 'Taruma', - 'Branchburg', - 'Bacuag', - 'Przeworsk', - 'Doukouya', - 'Champapur', - 'Highland Springs', - 'Ngolobougou', - 'Grefrath', - 'San Tomas', - 'Lidzbark Warminski', - 'Sera', - 'Le Raincy', - 'Alampur', + 'Saint-Junien', + 'Pijino del Carmen', + 'Guelph/Eramosa', + 'Solok', + 'Ciudad del Este', + 'Khagaria', + 'Kinogitan', + 'La Garenne-Colombes', + 'Manaquiri', + 'Telgte', + 'Igaracu do Tiete', + 'Mantsala', + 'Bogatic', + 'St. Cloud', + 'Huntertown', + 'Smithville', + 'Nueva Valencia', + 'Piru', + 'Yukarikaraman', + 'Merzifon', + 'Cosham', + 'Kharian', + 'Mantes-la-Ville', + 'Duanzhuang', + 'Kashipur', + 'Seaside', + 'Orchha', + 'Djemmorah', + 'Kocarli', + 'Mojkovac', + 'Nigel', + 'Kursunlu', + 'Soyagaon', + 'Pamuru', + 'Bassila', + 'Di An', + 'Vaureal', + 'El Dificil', + 'Troyan', + 'Toca', + 'Bet Shemesh', + 'Kayalpattanam', + 'Bernards', + 'Zomba', + 'Okabecho-okabe', + 'Nedroma', + 'Kostel', + 'Mosbach', + 'Miyauchi', + 'Jhitkahiya', + 'Rhymney', + 'Banisilan', + 'Medina', + 'Sayarpuram', + 'Landsberg', + 'Sevastopol', + 'Ceara-Mirim', + 'Assisi', + 'Goudomp', + "Debark'", + 'Melrose Park', + 'Le Rheu', + 'Port Douglas', + 'San Andres Tuxtla', + 'Princetown', + 'Seybaplaya', + 'Riegelsberg', + 'Cagayan de Oro', + 'Lommel', + 'Wapi', + 'Feira de Santana', + 'Obertshausen', + 'Imarui', + 'Soavinandriana', + 'Strathmore', + 'Kanke', + 'Arraial do Cabo', + 'Matsudo', + 'Pandhana', + 'Sao Miguel do Guapore', + 'Medea', + 'Rheinfelden (Baden)', + 'Taglio', + 'Korgan', + 'Pantabangan', + 'Bhattiprolu', + 'Lingampet', + 'Puerto Pimentel', + 'Velampatti', + 'Vilsbiburg', + 'Mianpur Dubauli', + 'Panguipulli', + 'Hafr al Batin', + 'Brasnorte', + 'Vignate', + 'Frederikshavn', + 'Alpena', + 'Pagbilao', + 'Villers-les-Nancy', + 'Chagalamarri', + 'Dispur', + 'Menemen', + 'Baqershahr', + 'Jandola', + 'Oborniki Slaskie', + 'Bandlaguda', + 'Goulburn', + 'Safotulafai', + 'Dreieich', + 'Galatsi', + 'Meixedo', + 'Banovici', + 'San Martino Buon Albergo', + 'Recani', + 'Prudnik', + 'Sao Miguel do Araguaia', + 'Sunkarevu', + 'New Castle', + 'Ban Thung Tam Sao', + 'Nariman', + 'Pata Ellamilli', + 'Capitolio', + 'Dobele', + 'Leicester', + 'Giovinazzo', + 'Ribeiro do Amparo', + 'Pailitas', + 'San Pedro Ayampuc', + 'Stalowa Wola', + 'Khargone', + 'Lustenau', + 'Sale', + 'Narhan', + 'Rubiataba', + 'Arceburgo', + 'Hokitika', + 'Vila Frescainha', + 'Lomme', + 'Lazarevac', + 'Tikrit', + 'Sudak', + 'Phrae', + 'Ramapo', + 'Ninomiya', + 'Hrazdan', + 'Taguasco', + 'Serravalle', + 'Bushtyno', + 'Gobo', + 'Kuttalam', + 'Awans', + 'Chancay', + 'Jocotenango', + 'Woodhouse', + 'KwaDukuza', + 'Wildau', + 'Batobato', + 'Crest Hill', + 'Balvadi', + 'Karkudalpatti', + 'Santa Ines', + 'Guacari', + 'Mantena', + 'Ladera Ranch', + 'Sulechow', + 'Matruh', + 'Isla de Maipo', + 'Gothva', + 'Frutillar', + 'Raxruha', + 'Machesney Park', + 'Wingene', + 'Lejanias', + 'Le Chesnay', + 'Bissendorf', + 'Abadiania', + 'Ometepec', + 'Enna', + 'Petarukan', + 'Boone', + 'Awbari', + 'Annaram', + 'Boki-Were', + 'Al Mijlad', + 'Raiparthi', + 'Aougrout', + 'Ranchi', + 'Onojo', + 'Saumalkol', + 'Atri', + 'Kara-Kol', + 'Lauria Inferiore', + 'San Felice Circeo', + 'Wooburn', + 'Agualva', + 'Fotadrevo', + 'Herenfa', + 'Berlin', + 'Astolfo Dutra', + 'Gahini', + 'Ambanja', + 'Hargeysa', + 'Santa Cruz do Capibaribe', + 'Ertis', + 'Esperantina', + 'Biloxi', + 'Hang Tram', + 'Diinsoor', + 'Asfour', + 'Pula', + 'Cacaopera', + 'Noida', + 'Pittsfield', + 'Le Muy', + 'Barletta', + 'Buraydah', + 'Ingolstadt', + 'Chautham', + 'Northwest Harborcreek', 'Oldsmar', - 'Greensburg', - 'Shepshed', - 'Nisko', - 'Hanamsagar', - "Fiorenzuola d'Arda", - 'Sopelana', - 'Breaza', - 'Ravels', - 'Tayum', - 'Harchoune', - 'Bailleul', - 'Hedehusene', - 'Boulder City', - 'Yuchi', - 'Cujubim', - 'Vellalapuram', - 'Barharwa', - 'Ayni', - 'Grecia', - 'Tamani', - 'Chailaha', - 'Drahichyn', - 'Amberieu-en-Bugey', - 'Nagarur', - 'Red Oak', - 'Qiaoyang', - 'Forest City', - 'Bromborough', - 'Berlare', - 'Salida', - 'Niquinohomo', - 'Jever', - 'Chipurupalle', - 'Niedernhausen', - 'Madhuban', - 'Tremelo', - 'Terra Rica', - 'Gabane', - 'Avalpundurai', - 'Koumaira', - 'Huitan', - 'Nzalat Laadam', - 'Varnsdorf', - 'San Mateo del Mar', - 'Isny im Allgau', - 'San Vito', - 'Bela Vista do Paraiso', - 'Haga', - 'Le Bourget', - 'Chislehurst', - 'Jinta', - 'Taurianova', - 'Timissa', - 'Illzach', - 'Botelhos', - 'Betsukai', - 'Hariharpara', - 'Grandola', - 'Tall Abyad', - 'Huckeswagen', - 'Mercaderes', - 'Kumaramangalam', - 'Lemon Hill', - 'Cabral', - 'Vuhledar', - 'Tendukheda', - 'Tadjourah', - 'Ponto Novo', - 'Schwabmunchen', - 'Cabanas', - 'Cherrapunji', - 'Port Antonio', - 'Kumaripur', - 'Nenmini', - 'Fort Payne', - 'Tanque Verde', - 'Kochkor-Ata', - 'Huixcolotla', - 'Petrovaradin', - 'Candido de Abreu', - 'Ilkley', - 'Patrocinio Paulista', - 'Jozefoslaw', - 'Radzyn Podlaski', - 'Benipati', - 'Comox', - 'Astravyets', - "Ighrem n'Ougdal", - 'Buerarema', - 'Whitefish Bay', - 'Ogijares', - 'Dehmoi', - 'La Carolina', - 'Anta', - 'Weizhou', - 'Muthallath al Azraq', - 'Fameck', - 'Sullivan', - 'Devarapalle', - 'Merate', - 'Palod', - "Citta Sant'Angelo", - 'Baguley', - 'Waunakee', - 'Kapiri Mposhi', - 'Shuichecun', - 'Deblin', - 'Stony Point', - 'Lapy', - 'Pattensen', + 'Neder-Over-Heembeek', + 'Kamisu', + 'Puerto Piritu', + 'Ambatolahy', + 'Daru', + 'New Brighton', + 'Queluz', + 'Epernay', + 'Bacalar', + 'Ban Nikhom Phatthana', + 'Valbonne', + 'Yondo', + 'Khowrmuj', + 'Jingdezhen', + 'Campana', + 'Kuli', + 'Ogimachi', + 'Biskupiec', + 'Framingham', + 'Lomma', + 'Papraur', + 'Mukumbura', + 'Kawayan', + 'Ncora', + 'Zhaoling', + 'Boscombe', + 'Abbeville', + 'Reisterstown', + 'Tongeren', + 'Joal-Fadiout', + 'Rosario de Lerma', + 'Velpuru', + 'Douarnenez', + 'Sofia', + 'Itayanagi', + 'Ekinozu', + 'Bonanza', + 'Mohlanapeng', + 'Cudworth', + 'Barga', + 'Okinawa', + 'Owase', + 'Ainan', + 'Nyunzu', + 'Yokohama', + 'Aiud', + 'Tachov', + 'Khagam', + 'Anosiarivo', + 'Khust', + 'Apolda', + 'Bogra', + 'Djinet', + 'Holiday City-Berkeley', + 'Carmo do Rio Verde', + 'Kirchseeon', + 'Victorica', + 'Lahar', + 'Veranopolis', + 'Bechar', + 'Noceto', + 'Nossa Senhora da Gloria', + 'Bhaluhar', + 'Hofu', 'Sozopol', - 'Afdem', - 'Alexander City', - 'New Paltz', - 'Konina', - 'Araputanga', - 'Itamonte', - 'Bni Darkoul', - 'Oulad Dahmane', - 'Armagh', - 'Amasra', - 'Sanquelim', - 'Hilchenbach', - 'Montmagny', - 'Pontivy', - 'Sitio do Quinto', - 'Laterza', - 'Williamstown', - 'Clarksdale', - 'Romsey', - 'Kamrawan', - 'Piney Green', - 'Adams', - 'Romilly-sur-Seine', - 'Zitsa', - 'Curtorim', - 'Harhorin', - 'Hasanpur Juned', - 'Selb', - 'Chitila', - 'Lummen', - 'Villers-les-Nancy', - 'Diankabou', - "Bo'ness", - 'Obanazawa', - 'Cherupazhasshi', - 'Much', - 'Ludus', - 'Cumpana', - 'Haubourdin', - 'Hirono', - 'Matungao', - 'Penrith', - 'Maqat', - 'Deming', - 'Tiltil', - 'El Ateuf', - 'Briniamaro', - 'Balham', - 'Pincourt', - 'Mozarlandia', - 'Teignmouth', - 'Perunkolattur', - 'Sinmperekou', - 'Sasso Marconi', - 'Masalli', - 'Entre Rios de Minas', - 'Ijra', - 'Eshowe', - 'Friedland', - 'Banbridge', - 'Cocorna', - 'Havre de Grace', - 'Punata', - 'Dennis', - 'Driouch', - 'San Juan del Sur', - 'Torokbalint', - 'Garhpura', - 'Lilburn', - 'Larkhall', - 'Mississippi Mills', - 'Youdiou', - 'Vaddapalli', - 'Tepetzintla', - 'Breukelen', - 'Bodmin', - 'Andurkonam', - 'Cicekdagi', + 'Kyabe', + 'Sosua', + 'Benedikt', + 'Bad Neuenahr-Ahrweiler', + 'Narendrapatnam', + 'Gurramkonda', + 'Pinhel', + 'Shiling', + 'Nadol', + 'Paredes', + 'Adjido', + 'Trebnje', + 'Yelpur', + 'Sirpur', + 'Barvala', + 'Angol', + 'Birpur Barapatti Pindraun', + 'Hendijan', + 'Parakou', + 'Mangaratiba', + 'Schwabisch Hall', + 'Sarqan', + 'Aleshtar', + 'Warin Chamrap', + 'West Des Moines', + 'Cutervo', + 'Valiyakumaramangalam', + 'Kottoppadam', + 'Sukth', + 'Sambhal', + 'Velliyod', + 'Waldshut-Tiengen', + 'Lakhnaur', + 'Barrocas', + 'Djamaa', + 'Matale', + 'Ban Phai', + 'Sao Paulo de Olivenca', + 'Harar', + 'Barbasa', + 'Kukatpalli', + 'Aisho', + 'Raynham', + 'Harborcreek', + 'Bafra', + 'Gibsons', + 'Cluj-Napoca', + 'Hoeselt', + 'Acopiara', + 'Filipstad', + 'Camardi', + 'Bunol', + 'Rania', + "Su'ao", + 'Konen Agrahar', + 'Sidi Qacem', + 'Chapada dos Guimaraes', + 'Bad Berleburg', + 'Thabazimbi', + 'Bradley', + 'Masif Sarsink', + 'Anse Rouge', + 'Galten', + 'Oshoba', + "Alta Floresta D'Oeste", + 'Ranaghat', + 'Patchur', + 'Rameswaram', + 'Fonadhoo', + 'Kuraymah', + 'Bosanska Krupa', + 'Cajica', + 'Sabou', + 'Fundacion', + 'Koba', + 'Rudra Nagar', + 'Tskhinvali', + 'Itarantim', + 'Mirzapur', + 'Mocajuba', + 'Berazategui', + 'Penjamo', + 'Doctor Mora', + 'Boleslawiec', + 'Angat', + 'Siraha', + 'Rock Ferry', + 'Salt', + 'Az Zintan', + 'Livno', + 'Winterville', + 'Daryabad', + 'Newton Mearns', + 'Milovice', + 'Nanqiao', + 'Nord', + 'Doba', + 'Guayacanes', + 'Didcot', + 'Skelmersdale', + 'Ivoamba', + 'Roessleville', + 'Sadovoye', + 'Magugpo Poblacion', + 'Toritama', + 'Mulakaledu', + 'Baia da Traicao', + 'Pissila', + 'Echuca', + 'Les Cayes', + 'Gajwel', + 'San Jose de Jachal', + 'Swedru', + 'Ribeirao', + 'Zhetibay', + 'Monatele', + 'Gibraleon', + 'Kufstein', + 'Chak Five Hundred Seventy-five', + 'Sterling', + 'Khattan', + 'Kuse', + 'Euless', + 'Baggao', + 'Al Juwayyidah', + 'Ilobasco', + 'Assi Bou Nif', + 'Ikniwn', + 'Gudja', + 'Monteiro', + 'Bryn Mawr-Skyway', + 'Corona de Tucson', + 'Sonson', + 'Clevedon', + 'Palestrina', + 'Uberherrn', + 'Civitella in Val di Chiana', + 'Balya', + 'Vinanivao', + 'Alexandria', + 'Merida', + 'Kursumlija', + 'Delgado', + 'Menton', + 'Dharampur Bande', + 'Goiana', + 'Matican', + 'Carballo', + 'Itapebi', + 'Minsk Mazowiecki', + 'Bhadaur', + 'Saidu Sharif', + 'Lalla Mimouna', + 'Mian Sahib', + 'Borzna', + 'Pakenham', + 'Al Kut', + 'Guemoukouraba', + 'Dhandhuka', + 'Crawfordsville', + 'Arak', + 'Acahay', + '`Abasan al Kabirah', + 'Farashband', + 'San Tomas', + 'Calasparra', + 'Ambahoabe', + 'Bayindir', + 'Merauke', + 'Ayagawa', + 'Ndjamba', + 'Lakewood', + 'Krishnanagar', + 'Kyustendil', + 'Porto Franco', + 'Anoka', + 'Tulsa', + 'De Haan', + 'Caluco', + 'Dumraon', + 'Fauske', + 'Jogiara', + 'Rambha', + 'Campina Grande do Sul', + 'Pontevedra', + 'Brejolandia', + 'Sundarpur', + 'Waltikon', + 'Putten', + 'Jardim', + 'Siemianowice Slaskie', + 'Buchen in Odenwald', + 'Ningde', + 'Tonsberg', + 'Shaliuhe', + 'Siracusa', + 'Galleh Dar', + 'Ponneri', + 'Gifhorn', + 'Avarua', + 'Longzhou', + 'Wenxicun', + 'Pontardulais', + 'Alipur', + 'Doetinchem', + 'Maravatio de Ocampo', + 'Elma', + 'Paravur Tekkumbhagam', + 'Oak Hills Place', + 'Dorou', + 'Galapagar', + 'Prata', + 'Bytca', + 'Kanmaki', + 'Ban Pong Tao', + 'Antsohihy', + 'Ban Ang Sila', + 'Gorisnica', + 'Abrera', + 'Visaginas', + 'Suoluntun', + 'Le Perreux-Sur-Marne', + 'Durbat', + 'Ourinhos', + 'Homa Bay', + 'Kolkwitz', + 'Gornji Grad', + 'Soroca', + 'Licata', + 'Zhangshanying', + 'Shuangcheng', + 'Shariff Aguak', + 'Redcliff', + 'Selargius', + 'Zapotlan del Rey', + 'Uetersen', + 'Rochedale', + 'Mongeri', + 'Tonala', + 'Lloydminster', + 'Ribeira Brava', + 'Xingcheng', + 'Baku', + 'Ban Dung', + 'Klatovy', + 'Empangeni', + 'Chundale', + 'Sorontona', + 'Dieppe', + 'Grandville', + 'Udawantnagar', + 'Qaqortoq', + 'Bischheim', + 'Urucui', + 'Uychi', + 'Kalispell', + 'Amman', + 'Esplugas de Llobregat', + 'Lohfelden', + 'Nacimiento', + 'Phongsali', + 'Ngerulmud', + 'Mulsen', + 'Yby Yau', + 'Balassagyarmat', + 'Malingaon', + 'Xionglin', + 'Glenvar Heights', + 'Miho', + 'North Liberty', + 'Dongshan', + 'Bauang', + 'Beguedo', + 'Cruz Grande', + 'Douar Trougout', + 'Primrose', + 'Merrimack', + 'Raigarh', + 'Potomac', + 'Voorhees', + 'Dalippur', + 'Castle Pines', + 'La Montanita', + 'Sabang', + 'Vintar', + 'Mikumi', + 'Sydney', + 'Tarhjicht', + 'Nizao', + 'Cahors', + 'Elland', + 'Diplahan', + 'Kayankulam', + 'Custodia', + 'Felipe Carrillo Puerto', + 'Paraguacu', + 'Lohafary', + 'Austintown', + 'Huixquilucan', + 'Pulpi', + 'Oakleaf Plantation', + 'Katsina', + 'Florennes', + 'Bad Honnef am Rhein', + 'Brenes', + 'West Linn', + 'Xanthi', + 'Saint-Saulve', + 'Sierra Bullones', + 'Dravograd', + 'Bizen', + 'Kurman', + 'Kuzma', + 'Kolagallu', + 'Bordj Ghdir', + 'Jogeva', + "Sofiyivs'ka Borshchahivka", + 'Pipra', + 'Lubeck', + 'Oppegard', + 'Kuopio', + 'Tuscumbia', + 'Kasaji', + 'Fort Atkinson', + 'Tamar', + 'Middelfart', + 'Grumo Nevano', + 'Downey', + 'Singhanwala', + 'Kawasaki', + 'Opglabbeek', + 'Maun', + 'Bosel', + 'Benaulim', + 'Smethwick', + 'Maromandia', + 'Hawaiian Gardens', + 'Jantho', + 'Malangam', + 'Rock Hill', + 'Livingstone', + 'Jaranwala', + 'Krong Kep', + 'West Covina', + 'Belzig', + 'Kitagata', + 'Fountain', + 'San Lorenzo de Descardazar', + 'Bati', + 'Quzanli', + 'Hosuru', + 'Poco Verde', + 'Simeulu', + 'Yangquan', + 'Shahzadpur', + 'Lopik', + 'Tarogong', + 'Iraiyur', + 'Freiberg', + 'Corinto', + 'Ukiha', + 'Alindao', + 'Ambohimahavelona', + 'Sosan', + 'Bhagabanpur', + 'Madamba', + 'Liubymivka', + 'Hassan', + 'Sham Shui Po', + 'Barbalha', + 'Wonju', + 'Taftanaz', + 'Waipio', + 'Guidan Roumdji', + 'Vohringen', + 'Crusinallo', + 'Nagareyama', + 'Geel', + 'Takahama', + 'Czarna Bialostocka', + 'Matthews', + 'Fleury-Merogis', + 'Tall `Aran', + 'Kamikawa', + 'Rose Belle', + 'Anorombato', + 'Wolfsberg', + 'Montreal', + 'Macrohon', + 'Miribel', + 'Cobanlar', + 'Gelsenkirchen', + 'Noblesville', + 'Sabaur', + 'Aizkraukle', + 'El Bayadh', + 'Bir Jdid', + 'Gunjur', + 'Nauta', + 'Browns Mills', + 'Shawnee', + 'Bredasdorp', + 'Camas', + 'Malebennur', + 'Ninh Binh', + 'Alto do Rodrigues', + 'Wilton Manors', + 'Fort Hunt', + 'Usia', + 'Lorgues', + 'Sanrha', + 'Bluffton', + 'Kendallville', + 'Preddvor', + 'Xovos', + 'Staoueli', + 'James Island', + 'Pampa del Infierno', + 'Lucaya', + 'Chino Valley', + 'Fort Leonard Wood', + 'Mirpur Bhtoro', + 'Ixtapa Zihuatanejo', + 'Albemarle', + 'Bekkaria', + 'Payatas', + 'Vitanje', + 'Koila Dewa', + 'Zhaoqing', + 'Sabac', + 'Kakonko', + 'Hojambaz', + 'Voinjama', + 'Xiaba', + 'Ramasingavaram', + 'Of', + 'Champoton', + 'Burntwood', + 'Viernheim', + 'Estoril', + 'Aflou', + 'Ampanefena', + 'Kamiamakusa', + 'Juan L. Lacaze', + 'Motkur', + 'My Luong', + 'Vernouillet', + 'Balatan', + 'Samaipata', + 'Alwa Tirunagari', + 'Saku', + 'Kuilsrivier', + 'Lynn Haven', + 'Maisach', + 'Bingerville', + 'Alicia', + 'Riversdale', + 'Bishunpur', + 'Tepoztlan', + 'Vishakhapatnam', + 'Gameleira', + 'Nyanza', + 'Bad Frankenhausen', + 'Huasca de Ocampo', + 'Kasongan', + 'Tortoreto', + 'Moschato', + 'Requena', + 'Kelowna', + 'Nyahanga', + 'Pohadi', + 'Kalibo', + 'Round Rock', + 'Pequannock', + 'Haifa', + 'Ezpeleta', + 'Boosaaso', + 'Oberschleissheim', + 'Seesen', + 'Alexandreia', + 'Salihli', + 'Mandali', + 'Xoxocotla', + 'Jakkampalaiyam', + 'Bradford West Gwillimbury', + 'West Perth', + 'Jaszbereny', + 'Vukovar', + 'Wittstock', + 'Dartmouth', + 'Zacatecas', + 'Oswego', + "Debre Werk'", + 'Annemasse', + 'Juripiranga', + 'Tultitlan de Mariano Escobedo', + 'Coachella', + 'Zagubica', + 'Altepexi', + 'Balao', + 'Velappadi', + 'Pamukkale', + 'West Vancouver', + 'Encamp', + 'Gudibanda', + 'Bensenville', + 'Augusta', + 'Natitingou', + 'Ganyesa', + 'Jiujiang', + 'Bad Schwartau', + 'Kings Norton', + 'Dharampuri', + 'Huanta', + 'Iganga', + 'Buckeburg', + 'Perryville', + 'Bingham', + 'Severn', + 'As Sulayyil', + 'Les Coteaux', + 'Jinmingsi', + 'Mel Nariyappanur', + 'Timimoun', + 'Nato', + 'Unisan', + 'Danao', + 'Mount Hagen', + 'Fiesole', + 'Concepcion Las Minas', + 'Zagorje', + 'Eilenburg', + 'Vardenik', + 'Ribeirao Branco', + 'Bismil', + 'Lichinga', + 'Reinosa', + 'Paray-le-Monial', + 'Villamediana de Iregua', + 'Madisonville', + 'Cheam', + 'Qabatiyah', + 'Bagnacavallo', + 'Shankou', + 'San Giuseppe Vesuviano', + 'Penaflor', + 'Amatenango del Valle', + 'Vanderbijlpark', + 'Coelemu', 'Labiod Medjadja', - 'Sakha', - 'Hammonton', - 'Pindai', - 'Chaabat el Leham', - 'Joubb Jannine', - 'Pine', - 'Rellingen', - 'Roseau', - 'Great Bend', - 'Conwy', - 'Neqab', - 'Matsushige', - 'Greendale', - 'Isla Vista', - 'Muy Muy', - 'Baladharmaram', - 'San Gwann', - 'Prestwick', - 'Alagoinha', - 'Douar Oulad Driss', - 'Oulad Driss', - 'Riofrio', - 'Neustadt an der Donau', - 'Sahit', - 'Cesis', - 'Mediouna', - 'Troon', - 'Chhapia', - 'Tarumirim', - 'Paola', - 'Uch-Korgon', - 'Ochakiv', - 'Purisima de la Concepcion', - 'Plerin', - 'Shimubi', - "Santa Croce sull' Arno", - 'Cuarte de Huerva', - 'Hima', - 'Tirumalaiyampalaiyam', - 'Hooksett', - 'Gladeview', - 'Koteshwar', - 'Harsefeld', - 'Villa Alegre', - 'Surbo', - 'Ospitaletto', - 'Nishinoomote', - 'Onklou', - 'Guilford', - 'Tlaxcala', - 'Carmen de Areco', - 'Lope de Vega', - 'Kodangipatti', - 'Baie du Tombeau', - 'Gross-Zimmern', - 'Kurumbalur', - 'Ankadinandriana', - 'Collecchio', - 'Coremas', - 'Masty', - 'Paramati', - 'Hershey', - 'Rubiera', - 'Owosso', - 'Melksham', - 'Mahatsinjo', - 'Ngoulemakong', - 'Dinan', - 'Ranomafana', - 'Thuin', - 'Laxou', - 'Wibsey', - 'Corridonia', - 'Bar-le-Duc', - 'Fraser', - 'Lake Stickney', - 'Manantheri', - 'Bere', - 'Pudur', - 'Malvik', - 'Las Guaranas', - 'Santa Marta de Tormes', - 'Saint-Omer', - 'Kushimoto', - 'Dzuunmod', - 'Kysucke Nove Mesto', - 'Condoto', - 'Ifrane', - 'Piraziz', - 'Tapes', - 'Kamalganj', - 'St. Clair', - 'Rasulpur Dhuria', - 'Zlotoryja', - 'Capinopolis', - 'Mmopone', - 'Djanet', - 'At-Bashy', - 'Langwedel', - 'Malo', - 'Kujukuri', - 'North New Hyde Park', - 'Mulakad', - 'Lognes', - 'Great Baddow', - 'Boguszow-Gorce', - 'Kaonke', - 'Sprimont', - 'Ferrier', - 'Mangamila', - 'Mineral del Monte', - 'Vubatalai', - 'Goure', - 'Sisa', - 'Tecpan de Galeana', - 'Limanowa', - 'Nea Alikarnassos', - 'Woudrichem', - 'Mahinog', - 'Bilozerske', - 'Ibitiara', - 'Tiruvasaladi', - 'Bilina', - 'Sepidan', - 'Terrace', - 'Ternitz', - 'Combita', - 'Rosa', - 'Rio Piracicaba', - 'Teixeira', - 'Flower Hill', - 'Pinia', - 'Djebahia', - 'Misaki', - 'Mercier', - 'Parlier', - 'Lumino', - 'Skipton', - 'Chippewa Falls', - 'Narragansett', - 'Bahcesaray', - 'Dahe', - 'Abony', - 'Alanganallur', - 'Zontecomatlan de Lopez y Fuentes', - 'Port Glasgow', - 'Magione', - 'Vredefort', - 'Kalocsa', + 'Olkusz', + 'Shefar`am', + 'Ulan Hua', + 'Sirka', + 'Caceres', + 'Gurh', + 'Oildale', + 'Colonial Heights', + 'eMuziwezinto', + 'Uster', + 'Pampur', + 'Martinsville', + 'Suttamalli', + 'Go Cong', + 'San Miguel de Papasquiaro', + 'Aliabad', + 'Huaura', + 'Denderleeuw', + 'Kremiss', + 'Kattukkottai', + 'Sakaka', + 'Khuran Milik', + "Al Ma`alla'", + 'Belluno', + 'Liptovsky Mikulas', + 'Baghra', + 'Touboro', + 'Science City of Munoz', + 'Trzebinia', + 'Filandia', + 'Myjava', + 'Ramachandrapuran', + 'Agdangan', + 'Bourzanga', + 'Barstow', + 'Annigeri', + 'Taio', + 'Deokali', + 'Lake Country', + 'Taizhou', + 'Adwick le Street', + 'Quilon', + 'Partesh', + 'Cwmbran', + 'Vaerlose', + 'San Calixto', + 'Oued Sly', + 'Lomazzo', + 'Guzelbahce', + 'Fishkill', + 'Annapolis', + 'Washington Terrace', + 'Keansburg', + 'Xintangcun', + 'Eastwood', + 'Sinmperekou', + 'Long Hill', + 'Roswell', + 'Budakeszi', + 'Lincolnia', + 'Flagstaff', + 'Eynesil', + 'Ban Wiang Ka Long', 'Groveton', - 'Negresti-Oas', - 'Cambuci', - 'Guajiquiro', - 'Kankipadu', - 'Vemuluru', - 'Roncade', - 'Kiri', - 'Plochingen', - 'Paliaturutu', - 'Bartabwa', - 'Batuan', - 'Huasuo', - 'Castellammare del Golfo', - 'Anzegem', - 'Lapua', - 'Langenselbold', - 'Hatten', - 'Ispir', - 'Tullamore', - 'Lowton', - 'Carmignano', - 'Suo-Oshima', - 'Saint-Maurice', - 'Sinha', - 'Sveti Ivan Zelina', - 'Arroio dos Ratos', - 'Saint-Jean-de-Luz', - 'Uzun', - 'Cabarete', - 'Nova Ponte', - 'Verrieres-le-Buisson', - 'Montabaur', - 'Wilbraham', - 'Holalagondi', - 'Jedrzejow', - 'Tonya', - 'Guastalla', - 'Satyun', - 'Villa Yapacani', - 'Yokoshiba', - 'Kelamangalam', - 'Dinmanpur', - 'Sangota', - 'Palmeirais', - 'Cajetina', - 'Arnouville-les-Gonesse', - 'Sigulda', - 'Thillangeri', - 'Tostado', - 'Baligaon', - 'Broadlands', - 'Lucao', - 'Zabkowice Slaskie', - 'Agios Athanasios', - 'Lauda-Konigshofen', - 'Tostedt', - 'Aleksandrovka', - 'Severinia', - 'Red Bluff', - 'Falls Church', - 'Talya', - 'Port Royal', - 'Kanjikkovil', - 'Key Biscayne', - 'Tzaneen', - 'Jitwarpur Nizamat', - 'Pineto', - 'Wawizaght', - 'Lakkampatti', - 'Salem Lakes', - 'Burbage', - 'Edenburg', - 'Palayad', - 'Benfreha', - 'Paniem', - 'Breza', - 'Kottacheruvu', - 'Naivasha', - 'Qazyqurt', - 'Mocha', - 'Jastrebarsko', - 'Darpa', - 'Debar', - 'Essau', - 'Tiruppachur', - 'Relangi', - 'Saint-Genis-Pouilly', - 'Belvedere Park', - 'Ban San Phak Wan Luang', - 'Loviisa', - 'Stein bei Nurnberg', - 'Thorpe Saint Andrew', - 'Andoain', - 'Bijaipur', - 'Bicas', - 'Solila', - 'Ratzeburg', - 'Clarkston', - 'Adekar Kebouche', - 'Anamoros', - 'El Paisnal', - 'Wilsdruff', - 'Biscarrosse', - 'Halwara', - 'Altinekin', - 'Iakora', - 'Cecil', - 'Marofinaritra', - 'Gundlapelle', - 'Merimandroso', - "Les Sables-d'Olonne", - "Ayt 'Attou ou L'Arbi", - 'Stanytsia Luhanska', - 'Ottweiler', - 'Ban Du', - 'Pindorama', - 'Blidet Amor', - 'Australind', - 'Jun Bel', - 'Bom Jesus do Galho', - 'Arbon', - 'Bakun', - 'Abensberg', - 'Nagireddipalli', - 'Moultrie', - 'Rio Paranaiba', - 'Falagueira', - 'Sarmin', - 'Ain Nouissy', - 'Kusaha', - 'Ban Kaeng', - 'Pualas', - 'Kannamanayakkanur', - 'Reidsville', - 'Cadaval', - 'Dargahan', - 'Middlesex', - 'Agua Boa', - 'Vitomirice', - 'Sha Kok Mei', - 'Pandhana', - 'Herselt', - 'Minignan', - 'Anapoima', - 'Moston', - 'Sonora', - 'Saint-Fargeau', + 'Des Peres', + 'Namacunde', + 'Zlotow', + 'Chittoor', + 'Torre del Greco', + 'Morrinhos', + 'Upper Chichester', + 'Marousi', + 'Calimete', + 'Oytal', + 'Sao Joao dos Angolares', + 'Anenii Noi', + 'Perry', + 'Ait Melloul', + 'Kitchener', + 'Amboronabo', + 'Burtonwood', + 'Croydon', + 'San Celoni', + 'Suhaj', + 'Hod HaSharon', + 'Kitenkela', + 'Alagappapuram', + 'Ramat HaSharon', + 'Tortona', + 'Rota', + 'Innisfail', + 'Cuyahoga Falls', + 'Guadix', + 'Wil', + 'Vemuladivi', + 'Taungup', + 'Itaocara', + 'San Pedro Mixtepec', + 'Konce', + 'Puerto Guzman', + 'Mahuwa Singhrai', + 'North Merritt Island', + 'Most', + 'Lahstedt', + 'Westland', + 'Liuma', + 'Charagua', + 'Krasnogorskiy', 'Pakarya Harsidhi', - 'Tabuse', - 'Dieramana', - 'Reboucas', - 'Guachochi', - 'Mbuyapey', - 'Neu-Anspach', - 'Immenstadt im Allgau', - 'Mosina', - 'Montesson', - 'Valea Lupului', - 'Olsberg', - 'McCalla', - 'Quinapundan', - 'Chelsfield', - 'Oria', - 'Aberdare', - 'Suwasra', - 'San Martin de Loba', - 'Eberbach', - 'Farap', - 'Angus', - 'Nadisal', - 'Gavinivaripalem', - 'Surajpura', - 'Sadhoa', - 'Sokone', - 'Oyam', - 'Guanduqiao', - 'West Lincoln', - 'Yanhewan', - 'Ouled Sidi Brahim', - 'Ludvika', - 'Tenente Portela', - 'Agua Fria', - 'Lingal', - 'Thornbury', - 'Chinnavadampatti', - 'Poco das Trincheiras', - 'Uckfield', - 'Lakho', - 'Uhingen', - 'Barhni', - 'Deysbrook', - 'Harduli', - 'Ahmed Rachedi', - 'Askim', - 'Murra', - 'Madagh', - "Boula'wane", - 'Cehegin', - 'Burglengenfeld', - 'Flers', - 'Valenton', - 'Babhangawan', - 'Fujisaki', - 'Mesa Geitonia', - 'Eisenstadt', - 'Barroquinha', - 'Buggenhout', - 'Turnov', - 'Nampicuan', + 'Beni Oulid', + 'Daqing', + 'Ecorse', + 'Pineto', + 'Olbernhau', + 'Dorfen', + 'Madeira', + 'Sassnitz', + 'Susegana', + 'Suamico', + 'Spring', + 'Milazzo', + 'Erada', + 'Obernburg am Main', + 'Oak Harbor', + 'Marokarima', + 'Malangawa', + 'McAllen', + 'Merrill', + 'Pe de Serra', + 'Bilohorodka', + 'Dhakaich', + 'Malhador', + 'Wenatchee', + 'Almere', + 'Benguela', + 'Pisek', + 'Matam', + 'Sidi Bouzid', + 'Chhota Udepur', + 'Tehran', + 'Panjakent', + 'Itapage', + 'Quarteira', + "Mi'eso", + 'Saverne', + 'Panchimalco', + 'Parambil', + 'San Miguel de Salcedo', + 'Sanwas', + 'Sidhap Kalan', + 'Umraniye', + 'Falavarjan', + 'Gaalkacyo', + 'La Ferte-sous-Jouarre', + 'Schwalbach', + 'La Junta', + 'Timbuktu', + 'Jessore', + 'Tomisato', + 'Parachinar', + 'Myslowice', + 'Beelitz', + 'Minehead', + 'Samadiala', + 'Mankera', + 'San Pedro Sacatepequez', + 'Gaithersburg', + 'Pongnam', + 'Chambery', + 'Wareham', + 'Catu', + 'Gangania', + 'Shingu', + 'Sawahlunto', + 'Aydincik', + 'Somvarpet', + 'Beshariq', + 'Hongjiang', + 'Nallamadu', + 'Hengelo', + 'Sidi Tabet', + 'Pucioasa', + 'Salvaterra', + 'Zhongbai', + 'Pital', + 'Acu', + 'La Ligua', + 'Kalugumalai', + 'Raharpur', + 'La Grande', + 'Sint-Lievens-Houtem', + 'Ban Tha Pho', + 'Shangluhu', + 'Ciudad Madero', + 'Matias Barbosa', + 'Yara', + 'Lamitan', + 'Port Laoise', + 'Adiyaman', + 'Jaguey Grande', + 'Douai', + 'Tecuci', + 'Tifni', + 'Changsha', + 'Acatzingo', + 'Eilat', + 'South Ogden', + 'Talsi', + 'Dzuunmod', + 'Kafr al Kurdi', + 'Cochrane', + 'Xigaze', + 'Terra Santa', + 'Na Klang', + 'Parsa', + 'Side', + 'Noshiromachi', + 'Tepehuacan de Guerrero', + 'Makri', + 'Bernex', + 'Magway', + 'Modugno', + 'East Gwillimbury', + 'Dornakal', + 'The Crossings', + 'Gazi', + 'Dengjiazhuang', + 'Betroka', + 'Manno', + 'Hausjarvi', + 'Menifee', 'Qobustan', - 'Haacht', - 'Tlayacapan', - 'Markacho', - 'Roh', - 'Huizucar', - 'Khallikot', - 'Santaquin', - 'Ormeau', - 'Tiruvalanjuli', - 'Sommacampagna', - 'Plumtree', - 'Ichikawamisato', - 'Armthorpe', - 'Lagunia Surajkanth', - 'Ankaramena', - 'Yangasso', - 'Lopik', - 'Sassenberg', - 'Santo Domingo Xenacoj', - 'Larena', - 'Tarlapalli', - 'Scottsbluff', - 'Sopetran', - 'Shatrana', - 'Robbinsdale', - 'Gwanda', - 'Jacarau', - 'Narahia', - 'Bara', - 'Neubiberg', - 'Brwinow', - 'Roquebrune-sur-Argens', - 'Asagiri', - 'Short Hills', - 'West Freehold', - 'Tavagnacco', - 'Monticello', + 'Ban Bang Pu Mai', + 'Macau', + 'Lithgow', + 'Kissa', + 'Kenadsa', + 'Mosul', + 'Letterkenny', + 'Conda', + 'Poonamallee', + 'Huruta', + 'Chennevieres-sur-Marne', + 'Camiri', + 'Cazanga', + 'East Bakersfield', + 'Baiji', + 'Garsfontein', + 'Bad Iburg', + 'Glen Carbon', + 'Arvin', + 'Sobhapur', + 'Talas', + 'Aalborg', + 'Bagnara Calabra', + 'Pokhram', + 'Aragoiania', + 'Aravankara', + 'East Nottingham', + 'Ramjibanpur', + 'Kilmangalam', + 'Talisay', + 'Krusevac', + 'Baranain', + 'Gauli Palasiya', + 'Sieverne', + 'Chakradharpur', + 'Ipil', + 'Xiamen', + 'Henichesk', + 'Wajir', + 'Polonuevo', + 'Las Piedras', + 'Vysokyi', + 'Barra do Pirai', + 'Malancha', + 'Vendome', + 'Kisarazu', + 'Ambohidanerana', + 'Villareal', + 'San', + 'Ipele', + 'Bologna', + 'Berwyn', + 'Kadambanad', + 'Diest', + 'Tuy Hoa', + 'Neuilly-sur-Seine', + 'Kiryas Joel', + 'Takoma Park', + 'Suwa', + 'Heiloo', + 'Chorbogh', + 'Teror', + 'Passo do Sertao', + 'Akim Swedru', + 'Bucheon', + 'Upper', + 'Kobuleti', + 'Adesar', + 'Hugli', + 'El Khroub', + 'Mwaya', + 'Atome-Avegame', + 'Dhahran', + 'Ratnapura', + 'Roncq', + 'Ambatomena', + 'Ichihara', + 'Waiblingen', + 'Anapoima', + 'Tizi Nisly', + 'Schiffdorf', + 'Merrick', + 'Jesenik', + 'Jnane Bouih', + 'Victoria Falls', + 'Genhe', + 'Charne', + 'Bicas', + 'Yandrapalle', + 'Onklou', + 'Arezzo', + 'Taung', + 'Paphos', + 'Otacilio Costa', + 'Ichora', + 'Urlaha', + 'Espelkamp', + 'Birao', + 'Lora del Rio', + 'Altavilla Milicia', + 'Anchorage', + 'Pendik', + 'Bugojno', + 'Kadavur', + 'Zahirabad', + 'Oschersleben', + 'Guerrero Negro', + 'Posadas', + 'Tabligbo', + 'Bermeo', + 'Coquimatlan', + 'Farg`ona', + 'Resita', + 'Syurte', + 'Viacha', + 'Tsing Yi Town', + 'Pultusk', + 'Patratu', + 'Satbayev', + 'Bonga', + 'San Salvador', + 'Szentendre', + 'Yvetot', + 'Bilpura', + 'Kabugao', + 'Haskovo', + 'Ingleside', + 'Wapakoneta', + 'Alhendin', + 'Mandialaza', + 'Kharsawan', + 'Chanda', + 'Maulavi Bazar', + 'Rautara', + 'Ljig', + 'Iona', + 'Sakaiminato', + 'North Myrtle Beach', + 'Peralillo', + 'Santa Flavia', + 'Ban Thung Khao Phuang', + 'Mandalavadi', + 'Bulanik', + 'Chong-Aryk', + 'Jayamkondacholapuram', + 'Havran', + 'Belobaka', + 'Fujisawacho-niinuma', + 'Puyallup', + 'Anderanboukan', + 'San Lazaro', + 'Metpalli', + 'Cerkezkoy', + 'Attleborough', + 'Chunakara Vadakku', + 'Eqlid', + 'Rockhampton', + 'Onalaska', + 'Hani i Elezit', + 'Ituzaingo', + 'Teculutan', + 'Bajwara', + 'Loran', + 'Guinayangan', + 'Wunstorf', + 'Sheopur', + 'Gol Tappeh', + 'Casselberry', + 'Jurema', + 'Chimay', + 'Horasan', + 'Sankt Wendel', + 'Eksambe', + 'Francisco Morato', + 'Panfilovka', + 'Ensley', + 'Kudavasal', + 'Palpala', + 'Itapecerica', + 'Drancy', + 'Monaghan', + 'Beamsville', + 'Crato', + 'Keila', + 'Riedlingen', + 'Bucine', + 'Vadippatti', + 'Segou', + 'Bag`dod', + 'Vellanad', + 'Conceicao do Castelo', + 'Alenquer', + 'Kalgi', + 'Somers Point', + 'McMinnville', + 'Erlangen', + 'Dabeiba', + 'Selkirk', + 'Toffo', + 'Aba', + 'Landi Kotal', + 'Duyen Hai', + 'Ostermundigen', + 'Doutou', + 'Emmeloord', + 'Ainsdale', + 'Isla Mujeres', + 'Bosobolo', + 'Forst (Lausitz)', + 'Swarzedz', + 'Guttenberg', + 'Gibsonton', + 'Moa', + 'Nattarasankottai', + 'Itaberai', + 'Teghra English', + 'Bellingham', + 'Lafayette', + 'Fort Wayne', + 'Odranci', + 'Hannut', + 'Ashburn', + 'Malate', + 'Jardin', + 'Clarington', + 'Mandiakui', + 'Merrydale', + 'Uirauna', + 'Panvel', + 'Chaguanas', + 'Basaha', + 'Susanville', + 'Kharik', + 'Grandview', + 'Mallapalli', + 'Ban Krang', + 'Camaiore', + 'Gross-Zimmern', + 'Vehkalahti', + 'Merchweiler', + 'Mohnesee', + 'Beach Park', + 'Yeghvard', + 'Beckingen', + 'Monte Dourado', + 'Gori', + 'Striano', + 'Barueri', + 'Tinogasta', + 'Santa Isabel do Rio Negro', + 'Kriftel', + 'Shiroishi', + 'Uaua', + 'Pinamalayan', + 'Sitalpur', + 'Las Matas de Santa Cruz', + 'Longchang', + 'Causeni', + 'Lajinha', + 'Sabbashahr', + 'Itacoatiara', + 'Mashan', + 'Trondheim', + 'Walsall Wood', + 'Lompoc', + 'Ibicuitinga', + 'Machang', + 'Babai', + 'Kobe', + 'Imsida', + 'Florida Ridge', + 'Antanambao Mahatsara', + 'Gudivada', + 'Apopka', + 'Bissau', + 'Itaete', + 'Shuiding', + 'Bratunac', + 'Beaconsfield', + 'Attnang-Puchheim', + 'Mennzel Bou Zelfa', + 'Dourados', + 'Obukhiv', + 'Lengede', + 'Riberalta', + 'Cafayate', + 'Bourem Inali', + 'Carapicuiba', + 'Orangevale', + 'La Homa', + 'Jaladurgam', + 'Gilarchat', + 'Reyhanli', + 'Durango', + 'Carros', + 'Hima', + 'Panthersville', + 'Arab', + 'Parasia', + 'Graca', + 'Metekora', + 'Harunabad', + 'Thonon-les-Bains', + 'Kodikulam', + 'Sarai Jattan', 'Anderson Creek', - 'Tulchyn', - 'Chenove', - 'Nolensville', - 'Alginet', - 'Alloa', - 'Ait Yaich', - 'Vinci', - 'Eggenfelden', - 'Black Forest', - 'Claxton Bay', - 'Pahou', - 'Jacaraci', - 'Bokod', - 'Ban Ao Nang', - 'Barranco de Loba', - 'Sirmaur', - 'Araceli', - 'Rauch', - 'Ampohibe', - 'Perai', - 'Sainte-Maxime', - 'Nether Providence', - 'Busembatia', - 'Eching', - 'Kolwara', - 'Caln', - 'Ascension', - 'Morroa', - 'Baqiabad', - 'Bagulin', - 'Pilisvorosvar', - 'Szarvas', - 'Satwas', - 'Aartselaar', - 'Davorlim', - 'Alur', - 'Ulchin', - 'Dollis Hill', - 'Painan', - 'Dornakal', - 'Lavaltrie', - 'Villa Vasquez', - 'Kalyvia Thorikou', - 'Tirkarur', - 'Tagalft', - 'Kharki', - 'Cayey', - 'Mantaly', - 'Korsor', - 'Barhi', - 'Spenge', - 'Vadugapatti', - 'Magurele', + 'Gazulapalle', + 'Warrenton', + 'Qiman al `Arus', + 'Vaux-le-Penil', + 'Wuyi', + 'Calafell', + 'General Carneiro', + 'Sylvan Lake', + 'Onslow', + 'Sidi Amrane', + 'Heusden', + 'Yushan', + 'Kodakkal', + 'Dodvad', + 'Chaoshan', + 'San Jose de Urquico', + 'Rosmalen', + 'Sumilao', + 'Bharno', + 'Caversham', + 'Union Choco', + 'Annappes', + 'Angostura', + 'Nandasmo', + 'Ielmo Marinho', + 'Overland Park', + 'Umrapur', + 'Pirai do Sul', + 'Kumlu', + 'Kiyosu', + 'Paragaticherla', + 'Maayon', + 'Bardejov', + 'Masaka', + 'Maoming', + 'Santa Josefa', + 'Itarsi', + 'Prilep', + 'Pangil', + 'Kottapadi', + 'Central Falls', + 'Navarre', + 'Jatai', + 'Antsoantany', + 'Tiszavasvari', + 'Philadelphia', + 'Sundsvall', + 'Teapa', + 'Sansanne-Mango', + 'Itanhomi', + 'Upanema', + 'Longbridge', + 'Bryan', + 'Nueva Granada', + 'Malial', + 'Basud', + 'Kurichchi', + 'Pichidegua', + 'Amarante do Maranhao', + 'Kankol', + 'Tinajdad', + 'Amwa Majhar', + 'Pinetown', + 'Cherry Hill Mall', + 'Nangloi Jat', + 'Teopisca', + 'Bintuni', + 'Vengavasal', + 'Westmount', + 'Garmsar', + 'Sao Lourenco do Sul', + 'Duncan', + 'Kongarapalli', + 'Taounate', + 'Itapipoca', + 'Yungay', + 'Matalom', + 'Cartavio', + 'Bind', + 'Marck', + 'Galvarino', + 'Midvale', + 'Bangkok', + 'Tausa', + 'Gaoyou', + 'Balingen', + 'Wambrechies', + 'Pomerode', + 'Dolbeau', + 'Miyar', + 'Mahalapye', + 'Mandritsara', + 'Petrovske', + 'Mansa Konko', + 'Achern', + 'Malvern', + 'Veurne', + 'Tarauaca', + 'Sahna', + 'Patiram', + 'Nandurbar', + 'Nalwar', + 'Bahawalnagar', + 'Douar Ouled Ayad', + 'Guaitarilla', + 'Campo Mourao', + 'Sartana', + 'Yaojiazhuangcun', + 'Ma`raba', + 'Santo Tome', + 'Sapulpa', + 'Iasi', + 'Starkville', + 'Monte Cristi', + 'Youfangcun', + 'Vestal', + 'Shashemene', + 'Cambre', + 'Catonsville', + 'Honow', + 'Efkarpia', + 'West Caldwell', + 'Lianga', + 'Losser', + 'La Peche', + 'Kolea', + 'Avrig', + 'Mahatsinjony', + 'Sukhodilsk', + 'Le Bourget', + 'Sao Geraldo do Araguaia', + 'Palos Verdes Estates', + 'Millville', + 'Sao Miguel das Matas', + 'Saarbrucken', + 'Tres de Maio', + 'Sortobe', + 'Dhulia', + 'Pilate', + 'Itai', + 'Groot-Brakrivier', + 'Lemsid', + 'Cimarron Hills', + 'Boppard', + 'Shouguang', + 'Ares', + 'Aioun', + 'Catmon', + 'Kizilpinar', + "Ta' Xbiex", + 'Zuzemberk', + 'Vicksburg', + 'Koppies', + 'Karaj', + 'Cherrapunji', + 'Qasr-e Shirin', + 'El Penol', + 'Bacuri', + 'Rozenburg', + 'Phusro', + 'Howard', + 'Masquefa', + 'Taisar', + 'Tirebolu', + 'Wallenhorst', + 'Pa', + 'Baghpat', + 'Woodburn', + 'Tonawanda', + 'Mparo', + 'Douar Lamrabih', + 'Avondale', + 'Arenys de Mar', + 'Anguillara Sabazia', + 'Alblasserdam', + 'Otukpo', + 'Chandera', + 'Rubino', + 'Boskoop', + 'Boujad', + 'Bijai', + 'Teotihuacan', + 'Choba', + 'Swellendam', + 'Wood Dale', + 'Motta di Livenza', + 'Modakkurichchi', + 'Rajahmundry', + 'Rio Formoso', + 'Shantipur', + 'Wolvega', + 'Ennigerloh', + 'Seydi', + 'Melvindale', + 'Shangcaiyuan', + 'Gooty', + 'Ituiutaba', + 'Dakota Ridge', + 'Langen', + 'Klaukkala', + 'Lessines', + 'Saraykoy', + 'Oshu', + 'Kac', + 'Nanan', + 'Mandvi', + 'Larbert', + 'Garalo', + 'Binningen', + 'Templeton', + 'Yejituo', + 'San Estanislao', + 'Lake Stevens', + 'Kothanuru', + 'Dhanaura', + 'Goba', + 'Kasba', + 'Hot Springs', + 'Tiruvalur', + 'Birzebbuga', + 'Morafeno', + 'Cruzilia', + 'Sao Bras de Alportel', + 'Balingoan', + 'Purisima de la Concepcion', + 'Augustinopolis', + 'Caloocan City', + 'Itubera', + 'Lublin', + 'Temoaya', + 'Sebdou', + 'Beclean', + 'Itamarandiba', + 'Bayramic', + 'Ban Lam Narai', + 'Sirsa', + 'Talaja', + 'Amberieu-en-Bugey', + 'Arilje', 'Gorbea', - 'Killarney', - 'Brainerd', - 'General MacArthur', - 'Saint-Brevin-les-Pins', - "Chateau-d'Olonne", - 'Hopatcong', - 'Halawa', - 'Ghora Gali', - 'Skippack', - 'Pomorie', - 'Chik Banavar', - 'Yerere', - 'Valbom', - 'Paidiipalli', - 'Itau de Minas', - 'Mutyalapalle', - 'Minneola', - 'Wymondham', - 'Nagra', - 'Haldibari', - 'Dumas', - 'North Auburn', - 'Hetton le Hole', - 'Alindao', - 'Tupran', - 'Wangjiaxian', - 'Choszczno', - 'Sierra Vista Southeast', - 'Gernsbach', - 'Sorso', - 'Muqui', - 'West Bradford', - 'Chiconquiaco', - 'Lubbeek', - 'Lohfelden', - 'Kihoku', - 'Majia', - 'Hargawan', - 'Uzumlu', - 'Liestal', - 'Stafa', - 'Rheydt', - 'Anomabu', - 'Zaysan', - 'Mohanpur Gaughata', - 'Yamada', - 'Kusnacht', - 'Washington Court House', - 'Maria', - 'Karempudi', - 'Amersham', - 'Vasad', - 'West Derby', - 'Lake Wylie', - 'East Bridgewater', - 'Ourtzagh', - 'Kamatgi', - 'Natchez', - 'Impruneta', - 'Moorestown-Lenola', - 'New Hamburg', - 'Opwijk', - 'Saint Joseph', - 'Zolote', - 'Tezu', - 'Ozarow Mazowiecki', - 'Elizabethton', - 'Doria Sonapur', - 'Penuganchiprolu', - 'Sailana', - 'Cowes', - 'West Drayton', - 'Nacozari Viejo', - 'Rosarno', - 'Churumuco de Morelos', - 'Patiali', - 'Miena', - 'Mercerville', - 'West Nipissing / Nipissing Ouest', - 'Barela', - 'Riegelsberg', - 'Santa Rosalia', - 'Pineville', - 'Markdorf', - 'Serinhisar', - 'Artsyz', - 'Jitauna', - 'Miho', - 'Lobau', - 'Thondiamannu', - 'Simoes', - 'Tornesch', - 'Rehlingen-Siersburg', - 'Breyten', - 'Zaouiat Moulay Bouchta El Khammar', - 'Ihaddadene', - 'Niederzier', - 'Baulia', - 'Bihpuriagaon', - 'Bradley Gardens', - 'Zhutang', - 'Jiaoxiyakou', - 'Balangiga', - 'Tianguistengo', - 'Narhan', - 'Bhanukumari', - 'Wilkinsburg', - 'Alto Longa', - 'Strathmore', - 'Pont-a-Mousson', - 'Leno', - 'Hindalgi', - 'Monte Alegre de Sergipe', - 'San Andres Timilpan', - 'Pazar', - 'Conisbrough', - 'Muttukuru', - 'Belazao', - 'Mittweida', - 'Lakhsetipet', - 'Hasami', - 'Horta', - 'Yanshuiguan', - 'Brookside', - 'Mascali', - 'Anpachi', - 'Baia-Sprie', - 'Saldana', - 'Palda', - 'Walajabad', - "Vil'nyans'k", - 'Klasterec nad Ohri', - 'Rottingdean', - 'High River', - 'Gua', - 'Jori Kalan', - 'Tepecoyo', - 'Polaia Kalan', - 'Chikhli Kalan', - 'Ustka', - 'Sadovoye', - 'Kottavalasa', - 'Tenerife', - 'Kizhariyur', - 'Saddle Brook', - 'Balangkas', - 'Estremoz', - 'Saint-Paul-les-Dax', - 'Doctor Juan Eulogio Estigarribia', - 'Karkudalpatti', - 'Viraghattam', - 'Radzymin', - 'Lotte', - 'Peumo', - 'Iflissen', - 'Rokycany', - 'Sumbas', - 'Lengede', - 'Murak', - 'Mangoli', - 'Tsukawaki', - 'Amay', - 'Sarqan', - 'Santo Antonio dos Lopes', - 'Huliyar', - 'Woippy', - 'Fakola', - 'Novohrodivka', - 'Nagongera', - 'Romitan Shahri', - 'Sariosiyo', - 'Kidbrooke', - 'Roldan', - 'Kambainellur', - 'Rock Ferry', - 'Baruun-Urt', - 'Coronel Bogado', - 'Dayr al Barsha', - 'Neutraubling', - 'Pollokshaws', - 'Iona', - 'Algarrobo', - 'Bad Camberg', - 'Korangal', - 'Omegna', - 'Eski Ikan', - 'Ambohimanga Atsimo', - 'Orbetello', - 'Nasice', - 'Chiaravalle', - 'Chard', - 'Anantarazupeta', - 'Bariariya', - 'Loganville', - 'Bousso', - 'Ban Don Kaeo', - 'Grafing bei Munchen', - 'Brandermill', - 'East Greenwich', - 'Chicago Ridge', - 'Gualdo Tadino', - 'Unguturu', - 'Bialy Kamien', - 'Bikkavolu', - 'Somerton', - 'El Barrio de la Soledad', - 'Puxinana', - 'Patcham', - 'Santa Maria a Vico', - 'West Lealman', - 'Gantt', - 'Razan', - 'Nkhata Bay', - 'Mongeri', - 'Ban Nong Kula', - 'Ucar', - 'Ghaura', - 'Vedasandur', - 'Lai', - 'Pak Thong Chai', - 'Ban Tha Thong', - 'Cienega de Flores', - 'Bokonbaev', - 'Manoharpur', - 'Det Udom', - 'Saint-Gilles', - 'Mionica', - 'Bollullos par del Condado', - 'Marechal Floriano', - 'Bois-Guillaume', - 'Morokweng', - 'Poynton', - 'Ait Yazza', - 'Chikitigarh', - 'Ben Taieb', - 'Langerwehe', - 'Haramachida', - 'Levoca', - 'Mondolfo', - 'Svrljig', - 'Imbau', - 'Raje', - 'Aibongo', - 'Maria da Fe', - 'Prieska', - 'Tafrant', - 'Brazopolis', - 'Seacroft', - 'Kukdeshwar', - 'Opera', - 'Arvika', - 'Kodanad', - 'Wingene', - 'Horw', - 'Kelafo', - 'Neftcala', - 'Padavedu', - 'Manuel Ribas', - 'Sabinopolis', - 'Toubakoro', - 'Sines', - 'Saren', - 'North Mankato', - 'Knic', - 'Mahavanona', - 'Kashti', - 'Mapanas', - 'Bainbridge', - 'Omerli', - 'Pannimadai', - 'Zhabinka', - 'San Giorgio Ionico', - 'Forfar', - 'Nagardevla Budrukh', - 'Little Falls', - 'Bou Izakarn', - 'Al Mu`addamiyah', - 'Douar Hammadi', - 'Borborema', - 'Elk Plain', - 'Kouroussa', - 'Auray', - 'Ishikawa', - 'Maldon', - 'Terkuvenganallur', - 'Barkuhi', - 'Bennane', - 'Lich', - 'Crepy-en-Valois', - 'Shichinohe', - 'Aqkol', - 'Wennigsen', - 'Zeven', - 'Chebrolu', - 'Oleggio', - 'Cedar Lake', - 'Willowick', - 'Ad Dab`ah', - 'Kearsley', - 'Mykolaivka', - 'Mittegrossefehn', - 'Wulong', - 'Luling', - 'Campos Altos', - 'Antas', - 'Tapolca', - 'Kartuzy', - 'Siddapur', - 'Alangudi', - 'Rescaldina', - 'Minamiaizu', - 'Fallsburg', - 'Nafplio', - 'Bensville', - 'Panr', - 'Kaoma', - 'Bochil', - 'Assenede', - 'Adustina', - 'Maisach', - 'Mill Valley', - 'Saraykent', - 'Feldkirchen', - 'Tranas', - 'Almoloya de Alquisiras', - 'Miraima', - 'Kawaii', - 'Haaren', - 'Oschatz', - 'Odlabari', - 'Shinto', - 'Ayomi', - 'Kalkar', - 'Chesterton', - 'Hobe Sound', - 'Montelupo Fiorentino', - 'Mankera', - 'Juan de Acosta', - 'Leyton', - 'Puerto Deseado', - 'Hautmont', - 'Pansemal', - 'Vinto', - 'Murrhardt', - 'Mackworth', - 'Grenaa', - 'Mnagueur', - 'Huron', - 'Castelsarrasin', - 'Nallagunta', - 'Talbahat', - 'Coolidge', - 'Uslar', - 'Pirangut', - 'Bhulwal', - 'Edingen-Neckarhausen', - 'Federal Heights', - 'Bamble', - 'Birqash', - 'Sanlucar la Mayor', - 'Feucht', - 'Ashtead', - 'Bua Yai', - 'Sao Jose do Cedro', - 'Mers el Hadjad', - 'Orumanayur', - 'Santol', - 'Mirandiba', - 'Barwon Heads', - 'Raghudebbati', - 'Katravulapalle', - 'Douarnenez', - 'Juan Aldama', - 'Antarvedipalem', - 'Dippoldiswalde', - 'Plewiska', - 'Jitwarpur Kumhra', - 'Grajales', - 'Staszow', - 'Wombourn', - 'Pulur', - 'Alto Santo', - 'Shergarh', - 'Buhusi', - 'Kutavur', - 'Clearview', - 'Beronono', - 'Narvik', - 'Sao Martinho do Bispo', - 'Sanjiang Nongchang', - 'Sun Lakes', - 'Nesebar', - 'Rambha', - 'Yuscaran', - 'Lauchhammer', - 'East Whiteland', - 'Boutilimit', - 'Ipiranga', - 'Beekman', - 'Thong Pha Phum', - 'Usti nad Orlici', - 'Massalubrense', - 'Kerben', - 'Omis', - 'Storozhynets', - 'Astolfo Dutra', - 'Kakunodatemachi', - 'Sai Buri', - 'Shepherdsville', - 'Santiago Jocotepec', + 'Zakopane', + 'Izium', + 'Masvingo', + 'Shulan', + 'Chester', + 'Shinozaki', + 'Rupahi', + 'Douar Ait Taleb', + "'Ain Boucif", + 'San Gil', + 'Charters Towers', + 'Monovar', + 'Tierra Amarilla', + 'Toprakkale', + 'Pehcevo', + 'Cinfaes', + 'Lawang Bato', + 'Olinda', + 'Jiaoxi', + 'Bogatynia', + 'Bhawanipur Rajdham', + 'Jardin America', + 'Castelginest', + 'Herborn', + 'Cordeiro', + 'Dharmsala', + 'Gitega', + 'Vransko', + 'Pananaw', + 'Wettingen', + 'Deressia', + 'Secunderabad', + 'Queimada Nova', + 'Kollankulam', + 'Dharmaragar', + 'Beylaqan', + 'Lutsk', + 'Madinat as Sadat', + 'Shengping', + 'Yasu', + 'Hanmayingcun', + 'Ukiah', + 'Svilajnac', + 'Itoman', + 'Kathu', + 'Dugny', + 'Guanajuato', + 'Dreux', + 'Brovary', + 'Sicuani', + 'Hsenwi', + 'Manama', + 'Schleiden', + 'Kovancilar', + 'Tekkali', + 'Schlangen', + 'Zama', + 'Hostivice', + 'Calpulalpan', + 'Chalchihuitan', + 'Fondettes', + 'Messadine', + 'Duas Barras', + 'Alencon', + 'Cankiri', + 'Lake Zurich', + 'Bararam', + 'Nim ka Thana', + 'Woodlawn', + 'Contramaestre', + 'Monroe', + 'Kannod', + 'Ciechanow', + 'Kishunpur', + 'Haikou', + 'Fene', + 'Moree', + 'Rasulpur Dhuria', + 'Bowie', + 'Besiri', + 'Texistepec', + 'Langenau', + 'Nowra', + 'Metema', + 'Mokeri', + 'Kelibia', + 'Contamana', + 'Albergaria-a-Velha', + 'Paracuaro', + 'Kokshetau', + 'Campo Magro', + 'General Mariano Alvarez', + 'Stevenston', + 'Nagda', + 'Sliedrecht', + 'Kilmarnock', + 'Guantiankan', + 'Barira', + 'Dunn', + 'Portugalete', + 'Nizampatam', + 'Anse a Galets', + 'Louisville', + 'Policka', + 'Moita', + 'Sitanagaram', + 'Vrchlabi', + 'Greystones', + 'Kriel', + 'Guachochi', + 'Tuzla', + 'Juigalpa', + 'Paramonga', + 'Perali', + 'Idanha-a-Nova', + 'Ambilobe', + 'Kaga Bandoro', + 'Gilroy', + 'Nilavarappatti', + 'Tokat', + 'Miaojiaping', + 'Cascais', + 'Bilzen', + 'Malmo', + 'Tutong', + 'Tergnier', + 'Kalicherla', + 'Bishop Auckland', + 'Kyotamba', + 'Sonsonate', + 'Edmundston', + 'Ban Nong Tong', + 'Carnarvon', + 'Sloviansk', + 'Molave', + 'Kurobeshin', + 'Le Raincy', + 'Chinobod', + 'Alamnagar', + 'Kot Bhai', + 'Altenholz', + 'Esanai', + 'Kita-ku', + 'Lambidou', + 'Corumba', + 'North Providence', + 'Aulnoye-Aymeries', + 'Suifenhe', + 'Shar', + 'Vakfikebir', + 'Mudgee', + 'Vailoa', + 'Georgina', + 'Pachalum', + 'Al Fqih Ben Calah', + 'Lahti', + 'Eura', + 'Wolsztyn', + 'Santa Maria da Boa Vista', + 'Udipi', + 'Olgiate Olona', + 'Okinawa Numero Uno', + 'Albany', + 'Saint Sampson', + 'Bakel', + 'Governador Lindenberg', + 'Sannieshof', + 'Charlottetown', + 'Bidkhun', + 'Tenafly', + 'Dandarah', + 'Yunnanyi', + 'Mary', + 'Ouankoro', + 'Zhaicun', + 'Loboc', + 'Naduvannur', + 'Biedenkopf', + 'Jarash', + 'Yuanyangzhen', + 'Ashington', + 'Rufino', + 'Chodziez', + 'Heidenheim', + 'Aanekoski', + 'Puerto Tirol', + 'Attock Khurd', + 'Sihung', + 'Pennsville', + 'Vejen', + 'Sanford', + 'Loano', + 'West Deer', + 'Safsaf', 'Collingswood', - 'Sur Singh', - 'Bad Ischl', - 'Ipanguacu', - 'Villasanta', - 'Tepoztlan', - 'Belison', - 'Kilattingal', - 'Luino', - 'Gurinhem', - 'Leirvik', - 'El Rodeo', - 'Bovenden', - 'Thonex', - 'Natanz', - 'Matias Barbosa', - 'Landau an der Isar', - 'Port Lincoln', - 'Lakewood Park', - 'Charcas', - 'Curua', - 'Nowy Tomysl', - 'Noya', - 'Kisanuki', - 'Powell', - 'Siroda', - 'Phulwar', - 'Capitao Eneas', - 'Varde', - 'Fergus Falls', - 'Lagoa Real', - 'Pierre', - 'Sibundoy', - 'Wittstock', - 'Eraura', - "Mu'minobod", - 'Pelezi', - 'Banos', - 'Lachute', - 'Trepuzzi', - 'Niska Banja', - 'Valentim Gentil', - 'Kemp Mill', - 'Doranahalli', - 'Byahatti', - 'Castel San Giovanni', - 'Oneonta', - 'Belm', - 'Bougzoul', - 'Sideropolis', - 'Titiribi', - 'Hohenstein-Ernstthal', - 'Kinogitan', - 'Rajim', - 'Rosemere', - 'Beilen', - 'Emerald', - 'Adakplame', - 'Allouez', - 'El Guetar', - 'Sungai Guntung', - 'Tan Van', - 'Sidi Ben Adda', - 'Indiana', - 'Dunmore', - 'Aldenhoven', - 'Tamar', - 'Ershui', - 'Jodoigne', - 'Aiuaba', - 'Koundian', - 'Hidalgo', - 'Oostakker', - 'Italva', - 'Lagoa dos Gatos', - 'Bezou', - 'Neuenkirchen', - 'Jefferson Valley-Yorktown', - 'Ponnampatti', - 'Caudry', - 'Andalgala', - 'Bishops Cleeve', - 'Ban Mueang Nga', - 'Santiago de Anaya', - 'Rotenburg an der Fulda', - 'East Wenatchee', - 'Nantucket', - 'Sumbal', - 'Tibasosa', - 'Zazafotsy', - 'Arenoso', - 'Talwat', - 'Sjenica', - 'Nina Rodrigues', - 'Montalvania', - 'Vammanal', - 'Arboga', - 'Grunstadt', - 'Kerugoya', - 'Pedro Afonso', - 'Beylul', - 'Teploklyuchenka', - 'New Ulm', - 'Sasan', - 'Ezequiel Montes', - 'Fisciano', - 'Moudjbara', - 'Pilas', - 'Thonotosassa', - 'Ahrensfelde', - 'El Socorro', - 'El Carmen de Atrato', - 'Karugamad', + 'East Setauket', + 'Sever do Vouga', + 'Savona', + 'Mayilur', + 'Bouchabel', + 'Mbarara', + 'Bersenbruck', + 'Bevonotra', + 'Linghai', + 'Aksay', + 'Santiago Tangamandapio', + 'Changshu', + 'Buckhurst Hill', + 'Yangchun', + 'Tumbao', + 'Mazagran', + 'Bussy', + 'Meerzorg', + 'Veys', + 'Peddapuram', + 'Wuwei', + 'Kongnolli', + 'Uar Esgudud', + 'Munxar', + 'Targu Secuiesc', + 'Zuvvaladinne', + 'Tombos', + 'Sanjianxiang', + 'Colonie', + 'Velakkuttai', + 'Haveri', + 'Machilipatnam', + 'Witbank', + 'Tierralta', + 'Blytheville', + 'Gorgan', + 'Pallapatti', + 'Sariq', + 'Fort Worth', + 'Hatonuevo', + 'Steinbach', + 'Anloga', + 'East Stroudsburg', + 'Rioverde', + 'Villa Castelli', + 'Hopa', + 'Knysna', + 'Koumassi', + 'Pampierstad', + 'Agawam', + 'Utrera', + 'Oggaz', + 'Wadgira', + 'Pagqen', + 'Mizdah', + 'Bni Tajjit', + 'Douar Snada', + 'Sandy Springs', + 'Louviers', + 'Mamak', + 'Rimouski', + 'Giddarbaha', + 'Ittiva', + 'Pedro Luro', + 'Kerepestarcsa', + 'Shohimardon', + 'Santa Ana', + 'La Sierra', + 'Diguapo', + 'Soio', + 'Saint-Jean-de-Luz', + 'Illkirch-Graffenstaden', + 'Saint-Pierre-des-Corps', + 'Aivanallur', + 'Rio Piracicaba', + 'Kompalle', + 'Chiayi', + 'Rostraver', + 'Flossmoor', 'Frunze', - 'Gouveia', - 'Chelmza', - 'Karlivka', - 'Khadra', - 'Nantwich', - 'Cojedes', - 'Mazamitla', - 'Rio de Oro', - 'Berettyoujfalu', - 'Wauconda', - 'Itakura', - 'Sidi Abdelkarim', - 'Nelas', - 'Aguas Vermelhas', + 'General Roca', + 'Aglipay', + 'Nussloch', + 'Yakinca', + 'Kattupputtur', + 'Kolkata', + 'Bo', + 'San Antonio del Tachira', + 'Patrocinio', + 'Cuvelai', + 'Duarte', + 'Panetha', + 'Cave', + 'Lahore', + 'Maijdi', + 'Janhapara', + 'Tondi', + 'Al Hamalah', + 'Ludhiana', + 'El Hammadia', + 'Ejura', + 'Antsalova', + 'Fiadanana', + 'Nedumana', + 'Novo Aripuana', + 'Qufadah', + 'Igreja', + 'Punganuru', + 'Ranigaon', + 'Presidente Kennedy', + 'Pedda Kotayalanka', + 'Loudoun Valley Estates', + 'Vezirkopru', + 'Dronfield', + 'Ugo', + 'Obburdon', + 'Camiling', + 'Cermik', + 'Ampatuan', + 'Alangulam', + 'Candler-McAfee', + 'Behenjy', + 'Talanga', + 'Garissa', + 'Mbandaka', + 'Senboku', + 'Banganapalle', + 'Pedreiras', + 'Loreto', + 'Elias Fausto', + 'Columbia', + 'Sao Ludgero', + 'Revelganj', + 'Uhersky Brod', + 'Feira Grande', + 'Norten-Hardenberg', + 'Omura', + 'Wilcannia', + 'Bishopbriggs', + 'Dandoli', + 'Satna', + 'Palni', + 'Elda', + 'Bakhtiyarpur', + 'Kara-Tash', + 'Holden', + 'Kodumba', + 'Udayendram', + 'Wangjiaxian', + 'Ragusa', + 'Pijijiapan', + 'Muret', + 'Feldkirchen-Westerham', + 'Ineu', + 'Smithtown', + 'Incesu', + 'Svay Rieng', + 'Bhucho Mandi', + 'Mukaiengaru', + 'Maiquetia', + 'Manglaur', + 'Centennial', + 'Bonfinopolis', + 'Cova Figueira', + 'Ianca', + 'Mahesana', + 'San Francisco de Mostazal', + 'Langenfeld', + 'Buchholz in der Nordheide', + 'Coutras', + 'Grigiskes', + 'Biswan', + 'Perumbalai', + 'Shujalpur', + 'Ciudad Manuel Doblado', + 'Tunzi', + 'Great Harwood', + 'Andhra Tharhi', + 'Toudja', + 'Ramsar', + 'Gaesti', + 'Champigny-sur-Marne', + 'Ash Shaddadah', + 'Santaquin', + 'Quilpie', + 'Tubay', + 'Babylon', + 'Pualas', + 'Johi', + 'Sahaspur', + 'Padiham', + 'Busto Garolfo', + 'Kamatero', + 'Miary', + 'Ialysos', + 'Seydisehir', + 'Morgan Hill', + 'Malard', + 'Kafr ad Dawwar', + 'Sancoale', + 'Sakata', + 'Jinoba-an', + 'Sorgues', + 'Sumedang', + 'Sanrh Majhgawan', + 'Dalanzadgad', + 'Chundal', + 'Piombino', + 'Port Harcourt', + 'Goyang', + 'Puntarenas', + 'Gaszowice', + 'Santa Rosa de Copan', + 'Carmo da Cachoeira', + 'Bargersville', + 'Beius', + 'Stony Brook University', + 'Razlog', + 'Spenge', + 'Ban Mae Kha Tai', + 'Chilpur', + 'Pacific Grove', + 'Kalyan', + 'Balmazujvaros', + 'Hortolandia', + 'Pataili', + 'San Agustin de las Juntas', + 'Sao Felix do Xingu', + 'Prior Lake', + 'Puzol', + 'Udumanthala', + 'Novopskov', + 'Auerbach', + 'Zarate', + 'Makuyu', + 'Ertvelde', + 'Kommuru', + 'Manari', + 'Belonia', + 'Immokalee', + 'Kuiyibagecun', + 'Ascoli Piceno', + "Cassina de' Pecchi", + 'Sousa', + 'Alhaurin de la Torre', + 'Djidian Kenieba', + 'Los Rios', + 'Castel Goffredo', + 'Resana', + 'Rehli', + 'Puerto Boyaca', + 'Bandar-e Anzali', + 'Martha Lake', + 'Chopinzinho', + 'Friedrichsdorf', + 'La Granja', + 'San Agustin Loxicha', + 'Platteville', + 'Dighaun', + 'Mebane', + 'Pavumba', + 'Epinay-sur-Seine', + 'Alfredo Wagner', + 'Singen', + 'El Asintal', + 'Sankrail', + 'Nghi Son', + 'Pithoragarh', + 'Pudunagaram', + 'Tsuchiura', + 'Jhundpura', + 'Itapecuru Mirim', + 'Naranjal', + 'Pinneberg', + 'Schnaittach', + 'Penco', + 'Oissel', + 'Dungra Chhota', + 'Amudat', + "Qo'shko'pir", + 'Pachahi', + 'Sufian', + 'Haguenau', + 'Mansapur', + 'Discovery Bay', + "'Ain Leuh", + 'Tabernes de Valldigna', + 'Medvode', + 'Sillamae', + 'Baker City', + 'Gllogovc', + 'Dhrangadhra', + 'Homosassa Springs', + 'Outreau', + 'Beni', + 'Meltonakkal', + 'Mango', + 'San Pedro Jocopilas', + 'Roodepoort', + 'Unterhaching', + 'Ibiruba', + 'San Bernardo', + 'Marhanets', + 'Itapitanga', + 'Sivalarkulam', + 'Maguing', + 'Lianran', + 'Smila', + 'Forrest City', + 'Lumino', + 'Qingzhou', + 'Bajina Basta', + 'Bruggen', + 'Tapiramuta', + 'Ganga Sagar', + 'Hvardiiske', + 'Capitao Poco', + 'Carranglan', + 'Ekpe', + 'Camana', + 'Choyr', + 'Tullahoma', + 'Bothell', + 'Livadeia', + 'Samarate', + 'Brixham', + 'Anororo', + 'Ypejhu', + 'Bradford-on-Avon', + 'Wigston Magna', + 'Acigol', + 'Puerto Salgar', + 'Benicia', + 'Fundeni', + 'Dioumanzana', + 'Chellalat el Adhaouara', + 'Zonhoven', + 'Vellar', + 'Sceaux', + 'Luuka Town', + 'Kristiansand', + 'Ripley', + 'Lutry', + 'Gurabo al Medio', + 'Sepidan', + 'Chubbuck', + 'Harding', + 'Rogatica', + 'Maple Valley', + 'Qal`at Bishah', + 'Boladi', + 'Terlizzi', + 'Morriston', + 'Jaslo', + 'Mendrisio', + 'Valangiman', + 'Medveda', + 'Barton upon Humber', + 'Sauk Village', + 'Dison', + 'Little Bookham', + 'Marlton', + 'Harhorin', + 'Rampur Kalan', + 'Trofa', + 'Gatesville', + 'Etchojoa', + 'Baichigan', + 'New Hartford', + 'Charleville-Mezieres', + 'Anna', + 'Unchahra', + 'Porto de Mos', + 'Ambhua', + 'Al Minya', + 'Morro do Chapeu', + 'Saintard', + 'Bukwo', + 'Kawartha Lakes', + 'Badr Hunayn', + 'Valley Cottage', + 'Duxbury', + 'Baipingshan', + 'Fuente de Oro', + 'Nayudupet', + 'Zhexiang', + 'Khagra', + 'Sarakhs', + 'Saint-Pierre-du-Mont', + 'Urumqi', + 'Vannivedu', + 'Cesano Maderno', + 'Juarez', + 'Neuruppin', + 'Dig', + 'Momil', + 'Gondal', + 'Torres Novas', + 'Akkattettar', + 'Dourbali', + 'Ondo', + 'Monjas', + 'Mechernich', + 'Arlit', + 'Mandelieu-la-Napoule', + 'Murska Sobota', 'Daean', - 'Ostrzeszow', - 'Balassagyarmat', - 'Kottaiyur', - 'Mbini', - 'Amari', - 'Ciro Marina', - 'Suknadanga', - 'Karai', - 'Uttukkottai', - 'Rio Azul', - 'Mignoure', - 'Barari', - 'Primrose', - 'Itaguacu', - 'Sharonville', - 'Hazel Grove', - 'Kiashahr', - 'Gafanha da Nazare', - 'Wezembeek-Oppem', - 'Petrolandia', - 'Tierra Amarilla', - 'Famenin', - 'Santa Adelia', - 'Esquipulas Palo Gordo', - 'Morpeth', - 'Circleville', - 'Antohobe', - 'Lakoucun', - 'St. Helens', - 'Uttoxeter', - 'Sibirila', - 'Barjora', - 'Taguatinga', - 'Leuna', - 'Ollioules', - 'Ilampillai', - 'Hawaiian Gardens', - 'Haivoron', - 'Keal', - 'Hokuei', - 'Turuttiyad', - 'Selmana', - 'Ranapur', - 'Riposto', - 'Solhan', - 'Marlow', - 'Alewah', - 'Fujikawa', - 'Martinho Campos', - 'Rajasur', - 'Busto Garolfo', - 'Beraketa', - 'Ambahita', - 'Marotsiraka', - 'Mahajamba', - 'Ambatomarina', - 'Antanambaobe', - 'Kalandy', - 'Bekipay', - 'Marokarima', - 'Mahatsinjony', - 'Vanono', - 'Talata-Vohimena', - 'Vatolatsaka', - 'Belambo', - 'Beharona', - 'Ambohimitombo', - 'Tsarahasina', - 'Bevato', - 'Ankiliabo', - 'Amborondra', - 'Bealanana', - 'Sahalanona', - 'Ambodihara', - 'Ilha de Mocambique', - 'O`nhayot', - 'Shofirkon Shahri', - 'Rafai', - 'Takerbouzt', - 'Thouars', - 'Brahmanandapuram', - 'Tall Banat', - 'Milha', - 'Meilen', - 'Montfoort', - 'Persan', - 'Kamituga', - 'Beach Park', - 'Schneeberg', - 'Annaram', - 'Sahnaya', - 'Cristopolis', - 'Lone Tree', - 'Tulle', - 'Coribe', - 'Koundara', - 'Bandraboua', - 'Lorsch', - 'Pathum Thani', - 'Taiyong', - 'Shandiz', - 'Matane', - 'Donji Vakuf', - "Sao Joao d'Alianca", - 'Kongarapalli', - 'Ambohimiera', - 'Chumpak', - 'Bebra', - 'Fleury-Merogis', - 'East Norriton', - 'Kuraymah', - 'Ganguvarpatti', - 'Beiwusidui', - 'Thames Centre', - 'Felixlandia', - 'Mirinzal', - 'Oud-Turnhout', - 'Jardim de Piranhas', - 'Erbach', - 'Sutihar', - 'Boha', - 'Santa Branca', - 'Kambila', - 'Mankal', - 'East Milton', - 'Sogutlu', - 'Raydah', + 'Kalaleh', + 'Bamei', + 'Myingyan', + 'Lingquan', + 'Pescia', + 'Malloussa', + 'El Attaf', + 'Panmana', + 'Caqueza', + 'Moulay Bousselham', + 'Pathein', + 'Reha Mota', + 'Florencio Varela', + 'Al Lataminah', + 'Azogues', + 'Jhandapur', + 'Verucchio', + 'Subachoque', + 'Solila', + "Rava-Rus'ka", + 'Witu', + 'Gander', + 'General Pico', + 'Tongluo', + 'Serinhisar', + "Fiorenzuola d'Arda", + 'Vadamadurai', + 'Bayou Cane', + 'Plunge', + 'Quakertown', + "Limeira d'Oeste", + 'Qulan', + 'Agramonte', + 'Jamunamukh', + 'Gondomar', + 'Lajas', + 'Quinapundan', + 'Kurten', + 'Coremas', + 'Mafra', + 'Pinewood', + 'Linguere', + 'Miradouro', + 'Baganga', + 'Pauini', + 'Trebur', + 'Bollnas', + 'Romulus', + 'Banire Kore', + 'Legnaro', + 'Manatanna', + 'Deruta', + 'Finestrat', + 'Chico', + 'Mankono', + 'Pimentel', + 'Umirim', + 'Velanganni', + 'Natchitoches', + 'Kanungu', + 'West Palm Beach', + 'Caraballeda', + 'Tha Bo', + 'Nishio', + 'Bragado', + 'Palopo', + 'Concorezzo', + 'Nagla', + 'Nobres', + 'Sagada', + 'Bayona', + 'Cheat Lake', + 'Zion', + 'Kochi', + 'Cho Lach', + 'Sannicandro di Bari', + 'Pelotas', + 'Selb', + 'Sugarmill Woods', + 'Oatlands', + 'Basoda', + 'Lakewood Ranch', + 'Tenango del Aire', + 'Tulkarm', + 'Bella Union', + 'Heath', + 'Massaranduba', + 'Higashikagawa', + 'Barra do Choca', + 'Bolivar', + 'Aguacatan', + 'Yakacik', + 'Alexander Bay', + 'Dehri', + 'Mehnatobod', + 'Thol', + 'Burkburnett', + 'Sanarate', + 'Pollokshaws', + 'Sencur', + 'Zhanjiang', + 'San Pedro Ixcatlan', + 'Le Pre-Saint-Gervais', + 'Jamunia', + 'Opol', + 'Ambalajia', + 'Penola', + 'Mangindrano', + 'Oued el Alleug', + 'Marai Kalan', + 'Zatec', + 'Southern Cross', + 'San Luis de la Paz', + 'Omihachiman', + 'Illapel', + 'Tsianisiha', + 'Siteia', 'McFarland', - 'Beasain', - 'Ovidiu', - 'Merosina', - 'Thala', - 'Drapetsona', - 'Goianapolis', - 'Sakaki', - 'Lubben (Spreewald)', - 'Canteleu', - 'Grass Valley', - 'Roselle Park', - 'Pacaembu', - 'Hajdusamson', - 'Bedfordview', - 'Mjolby', - 'Kargipinar', - 'Meridjonou', - 'Chaugain', - 'Detva', - 'Eynesil', - 'Nova Ipixuna', - 'Alfredo Chaves', - 'McPherson', - 'Kepno', - 'Belwara', - 'Amaha', - 'Havelock North', - 'Kanakir', - 'La Entrada', - 'Belsandi Tara', - "Cassina de' Pecchi", - 'Misano Adriatico', - 'Bothell East', - 'Perdur', - 'Warrenville', - 'Audincourt', - 'Powell River', - 'Furukawamen', - 'Wells Branch', - 'Marostica', - 'Carleton Place', - 'Ichtegem', - 'Castellanza', - 'San Jose Acatempa', - 'Bang Racham', - 'Attibele', - 'Aracatu', - 'Sesquile', - 'Camp Pendleton South', - 'Brierley Hill', - 'Tsingoni', - 'Ibicui', - 'Tarhzout', - 'Montevrain', - 'Streetly', - 'Lower Moreland', - 'Vohringen', - 'Hunasagi', - 'Waimalu', - 'Hochstadt an der Aisch', - 'Grunberg', - 'Locorotondo', - 'Nachikatsuura', - 'Zhipingxiang', - 'Cossato', - 'Nyzhnia Krynka', - 'Khe Sanh', - 'Abre Campo', - 'Gesuba', - 'Sukma', - 'East Cleveland', - 'Julianadorp', - 'Diego de Almagro', - 'Asslar', - 'Destin', - 'Caybasi', - 'Viraganur', - 'Temsamane', - 'Papagaios', - 'Mansidao', - 'Royal Kunia', - 'Oued Taria', - 'Alterosa', - 'Lons', - 'Maracai', - 'Weissenhorn', - "Berre-l'Etang", - 'Muttunayakkanpatti', - 'Khergam', - 'Denzlingen', - 'Kelangah', - 'Alto Parana', - 'Oberhaching', - 'Sankt Leon-Rot', - "Debre Werk'", - 'Melsungen', - 'Midleton', + 'Nova Resende', + 'Rheinfelden', + 'Mubi', + 'Ourika Wawrmas', + 'Quinte West', + 'Korce', + 'Kalanaur', + 'Dhulian', + 'Balen', + 'Auterive', + 'Wronki', + 'Budha Theh', + 'Quy Nhon', + 'Cedro', + 'Garlasco', + 'Biharamulo', + 'Chateaurenard', + 'General Cabrera', + 'Gostynin', + 'Ad Diraz', + 'Asau', + 'Oceanside', + 'Longmont', + 'Nanzhuang', + 'Satadougou', + "Saint-Barthelemy-d'Anjou", + 'Owariasahi', + 'Zombo', + 'Dudley', + 'San Agustin Acasaguastlan', + 'Lochem', + 'Nidderau', + 'Devarkonda', + 'Leven', + 'Munchberg', + 'Mariani', + 'Cornillon', + 'Svidnik', + 'Heek', + 'Chak Thirty-six North Branch', + 'Tholey', + 'Charsadda', + 'Restinga Seca', + 'Villeneuve-Tolosane', + 'Profondeville', + 'Amla', + 'Ludwigslust', + 'Caterham', + 'Al Ghardaqah', + 'Mineral de la Reforma', + 'Kosice', + 'Sehnde', + 'Imam Qasim', + 'Ain El Aouda', + 'Candido Mendes', + 'Hacari', + 'Massafra', + 'Vittal', + 'Koh Kong', + 'Stockach', + "Saint Paul's Bay", + 'Tieshansi', + 'Xinyi', + 'Rawanduz', + 'Nanyuki', + 'Sarpamari', + 'Tres Coracoes', + 'Narutocho-mitsuishi', + 'Cukai', + 'Douchy-les-Mines', + 'Mandirituba', + 'Imouzzer Kandar', + 'Oulad Teima', + 'Lere', + 'Kanavaypudur', + 'Naugaon Sadat', + 'Bonnyrigg', + 'Charthawal', + 'Znojmo', + 'Cankova', + 'Tondo', + 'Badhan', + "Wu'an", + 'North Bellport', + 'Ambatosoratra', + 'Naduvattam', + 'Columbia Heights', + 'Neustadt am Rubenberge', + 'Maturin', + 'Ehringshausen', + 'Dandkhora', + 'Xinzhai', + 'Winter Gardens', + 'Bayur', + 'Dame-Marie', + 'Saco', + 'Metsemotlhaba', + 'Apen', + 'Nuevo Laredo', + 'Cofimvaba', + 'Miryal', + 'Shuangluan', + 'Thorold', + 'Zagarolo', + 'Wenling', + 'Dengtalu', + 'Oharu', + 'Sumoto', + 'Osmaniye', + 'Aquiraz', + 'Bury Saint Edmunds', + 'Nacajuca', + 'Baao', + 'Velbert', + 'Pyskowice', + 'North Platte', + 'Prostejov', + 'Paradise', + 'Newington Forest', + 'Gonghaur', + 'Rawicz', + 'Lamsabih', + 'Zaoqiao', + 'Chaoke', + 'Renala Khurd', + 'Saint-Sulpice-la-Pointe', + 'Kerkrade', + 'Glen Cove', + 'Cottbus', + 'Laurens', + 'Mont-Laurier', + 'Omalur', + 'Loum', + 'An Nu`maniyah', + 'Allende', + 'Jagdispur', + 'Bourgoin-Jallieu', + 'Icapui', + 'Niiza', + 'Disa', + 'Rhynern', + 'Mata', + 'Straubing', + 'Kingsnorth', + 'Esch-sur-Alzette', + 'Moyobamba', + 'Flores Costa Cuca', + 'Vetlanda', + 'Hengbei', + 'Hatillo de Loba', + 'Conway', + 'Ashta', + 'Diphu', + 'Sutculer', + 'Bad Worishofen', + 'Mahta', + 'Umm Qurun', + 'Strongsville', + 'Kamidani', + 'Playa del Carmen', 'Moralzarzal', - 'Buchloe', - 'Bickley', - 'Kubadupuram', - 'Guelph/Eramosa', - 'Krishnarayapuram', - 'Wood Dale', - 'Santo Augusto', - 'Tucacas', - 'Grao Mogol', - 'Bukedea', - 'Mogeiro', - 'Hall in Tirol', - 'Orikhiv', - 'Bhogpur', - 'Salaverry', - 'Shiloh', - 'Jiran', - 'Olean', - 'Bog Walk', - 'Galmi', - 'Meerane', - 'Tidjelabine', - 'Joaquim Pires', - 'Polukallu', + 'Lauffen am Neckar', + 'Kelishad va Sudarjan', + 'Cocentaina', + 'Harrislee', + 'Sojat', + 'Mahallat Damanah', + 'South Frontenac', + 'Ban Phan Chali', + 'San Sebastian Coatan', + 'Diego Martin', + 'Thai Nguyen', + 'Pewaukee', + 'Ifanadiana', + 'Asjen', + 'Mankachar', + 'Apparaopeta', + 'DeRidder', + 'Orleans', + 'Nagojanahalli', + 'Peddavadlapudi', + 'Dadrewa', + 'Sagure', + 'Natal', + 'Shirakawa', + 'Calera de Tango', + 'Sahbuz', + 'Rodeio', + 'Shaying', + 'Sakoabe', + 'Ramabhadrapuram', + 'Kararan', + 'Zolote', + 'El Espinal', + 'Laverton', + 'Ramgarha', + 'Sant Julia de Loria', + "Sant'Agnello", + 'Lidzbark Warminski', + 'Shu', + 'Pweto', + 'Burscough', + "Foum Jam'a", + 'Hua Hin', + 'Marovato', + 'Gangapatnam', + 'Rijeka', + 'Jihong', + 'Seacombe', + 'Friendswood', + 'Estreito de Camara de Lobos', + 'Loei', + 'Dan', + 'Jerez de Garcia Salinas', + 'Pukhrayan', + 'Choma', + 'Tlapa de Comonfort', + 'Catbalogan', + 'Boudenib', + 'Paraparaumu Beach', + 'East Lansing', + 'Stradella', + 'Tenali', + 'Irungalur', + 'Hollymead', + 'Farap', + 'Pitesti', + 'Muzambinho', + 'La Mesa', + 'Mulki', + 'Bruck an der Mur', + 'Gongguan', + 'Vayalar', + 'Freiberg am Neckar', + 'Passa e Fica', + 'Myrhorod', + 'Mutoko', + 'Warwick', + 'Shanmukhasundarapuram', + 'Koscian', + 'Nanyangcun', + 'Patton', + 'Grimes', + 'Vempatti', + 'Smizany', + 'Chipinge', + 'Miyota', + 'Villajoyosa', + 'Almoloya del Rio', + "'Ali Ben Sliman", + 'Brodosqui', + 'Vikrutamala', + 'Valatt', + 'Aparecida', + 'Guskhara', + 'Oke-Mesi', + 'Roche-la-Moliere', + 'Sentrupert', + 'Buraan', + 'Kisii', + 'Lohardaga', + 'Angleton', 'Quakenbruck', - 'Rustington', - 'Tumbippadi', - 'Philippsburg', - 'Eastham', - 'Areado', - 'Simplicio Mendes', - 'Makokou', - 'Cefalu', - 'Jabbeke', - 'Lauterbach', - 'Caselle Torinese', - 'Hockessin', - 'Sido', - 'Sunset', - 'Matican', - 'Friesenheim', - 'Beacon', - 'Tati', - 'New Franklin', - 'Hoa Thuong', - 'Ettenheim', - 'Torre del Campo', - "Ping'anbao", - 'Villalba', - 'Linganaboyinacherla', - 'Alcanena', - 'Taphan Hin', - 'Hilpoltstein', - 'Binkolo', - 'Tracunhaem', - 'Wakasa', - 'Oulad Chikh', - 'Billere', - 'Porto Alegre do Norte', - 'Ibipitanga', - 'Tamalameque', - 'Kishanpur Ratwara', - 'Artondale', - 'Polavaram', - 'Qiblai', - 'Manoel Vitorino', - 'Tarauna', - 'Avanhandava', - 'Shterpce', - 'Kingstown', - 'Huangyadong', - 'Weno', - 'Waycross', - 'Luozi', - 'Saboeiro', - 'Solaro', - 'Zhashkiv', - 'Carmopolis', - 'Markt Schwaben', - 'Grand Falls', - 'Toulal', - 'Zhovkva', - 'Iskapalli', - 'Millbury', - 'Polotitlan de la Ilustracion', - 'San Rafael Las Flores', - 'Amantea', - 'Bellair-Meadowbrook Terrace', - 'Parihara', - 'Dogachi', - 'Dryden', - 'Carapebus', - 'Oki', - 'Itaguara', - 'Beachwood', - 'Michendorf', - 'Mandalgarh', - 'Trinitapoli', - 'Mount Barker', - 'Kauriya', - 'Ribeiro do Amparo', - 'Hidaj', - "Khmis Sidi al 'Aydi", - 'Primavera', - 'Gangaikondan', - 'Saloa', - 'Barra do Mendes', - 'Tomino', - 'North Battleford', - 'Paripueira', - 'Valayam', - 'Fara in Sabina', - 'Kamigori', - 'South Sioux City', - 'Haidarnagar', - 'Vellodu', - 'Cosham', - 'Sauk Rapids', - 'Vembarpatti', - 'Strada', - 'Nules', - 'Pedro Velho', - 'Olympia Heights', - 'Maumee', - 'Bad Soden-Salmunster', - 'Enniskillen', - 'Khajawa', - 'Seiro', - 'Trbovlje', - 'Pigue', - 'Clemencia', - 'Wayland', + 'Bystrzyca Klodzka', + 'Ippagudem', + 'Lunner', + 'Almora', + 'Hasilpur', + 'Agiripalle', + 'Parys', + 'Loningen', + 'King City', + 'Suitland', + 'Bathnaha', + 'Gachancipa', + 'Bad Bentheim', + 'Fuyang', + 'Federal Heights', + 'Vallirana', + 'Manandroy', + 'Varidhanam', + 'Valreas', + 'Konstanz', + 'Hissaramuruvani', + 'Uripa', + 'Kimbe', + 'Medina Sidonia', + 'Tarragona', + 'Antindra', + 'Montana', + 'Cervignano del Friuli', + 'Hezuo', + 'Puerto Escondido', + 'Salto de Pirapora', + 'Gaobeidian', + 'Chak Husaini', + 'Grajales', + 'Lykovrysi', + 'Ankatafa', + 'Sbiba', + 'Matanog', + 'Sikka', + 'Avsallar', + 'Sarykemer', + 'Lighthouse Point', + 'Fatehpur Sikri', + 'Lakhminia', + 'Nagari', + 'Ansongo', + 'Bad Nauheim', + 'Trostberg an der Alz', + 'Mogila', + 'Mahrail', + 'Mouans-Sartoux', + 'Hude', + 'Lazi', + 'Berkhampstead', + 'Nehram', + 'Fussa', + 'Waipahu', + 'Dawei', + 'Haldia', + 'Olten', + 'Apastepeque', + 'Krzeszowice', + 'Koini', + 'Douar Messassa', + 'Lima', + 'Honcho', + 'Mulchen', + 'Acheres', + 'Harper Woods', + 'Tlacoachistlahuaca', + 'Baikonur', + 'De Bilt', + 'Vianden', + 'Arnold', + 'Bhabhua', + 'Al Ghizlaniyah', + 'Chakur', + 'Jixi', + 'Kibiti', + 'Viechtach', + 'Comalcalco', + 'Westfield', + 'Uacu Cungo', + 'Camargo', + 'San Juan del Rio del Centauro del Norte', + 'Bebington', + 'Largs', + 'Sompeta', + 'Ipsala', + 'Pola de Laviana', + 'Jose Maria Morelos', + 'Wasserburg am Inn', + 'Al Hawiyah', + 'Kilrajakularaman', + 'Chak Sixty-one Gugera Branch', + 'Jafaro', + 'Yattir', + 'Piura', + 'Dachau', + 'Bom Jesus dos Perdoes', + 'Itacare', + 'Delcevo', + 'Negombo', + 'Tenedla', + 'Amadora', + 'At-Bashy', + 'Fort Collins', + 'Amuria', + 'Vicuna', + 'Dahu', + 'Eloy Alfaro', + 'Beaumont', + 'Lloro', + 'Vinh Long', + 'Padiyanallur', + 'Tobruk', + 'Pazar', + 'Bideipur', + 'Magdalena de Kino', + 'Parla', + 'Kanuma', + 'Quatro Barras', + 'Chikusei', + 'Panambi', + 'Arecibo', + 'Bekatra Maromiandra', + 'Ahus', + 'Tilingzhai', + 'Hanahan', + 'Lunbei', + 'Majhua', + 'Bad Segeberg', + 'Holywell', + 'Tivim', + 'El Charco', + 'Mailiao', + 'Chenlu', + 'Beylul', + 'Camarajibe', + 'Le Puy-en-Velay', + 'Santander de Quilichao', + 'Nakasongola', + 'Shabestar', + 'Lindau', + 'Hathaura', + "Ayt 'Attou ou L'Arbi", + 'Fiuggi', + 'Dhekiajuli', + 'Shuyangzha', + 'Tokoroa', + 'Chaozhou', + 'Durres', + 'Old Jamestown', + 'Chimbote', + 'Ivanovka', + 'Silver Firs', + 'Santa Ana Nextlalpan', + 'Ourtzagh', + 'Lysa nad Labem', + 'Hirakata', + 'Udine', + 'Andrelandia', + 'Seysses', + 'Atami', + 'Woudrichem', + 'Brzeszcze', + 'Zhangping', + 'Rolante', + 'Mabai', + 'Varatanapalli', + 'Catak', + 'Mahabaleshwar', + 'Galgamuwa', + 'Kelso', + 'Esquipulas', + 'Seoni Malwa', + 'Laboulaye', + 'Winter Haven', + 'Jimaguayu', + 'Rury', + 'Lubbenau/Spreewald', + 'Dijiasuoxiang', + 'Wielsbeke', + 'Pagani', + 'Kizhur', + 'San Carlos City', + 'Chaudfontaine', + 'Camacupa', + 'Celina', + 'Roudnice nad Labem', + 'Rajni', + 'Umm Ruwaba', + 'Harir', + 'Suwasra', + 'Rio Casca', + 'Bry-sur-Marne', + 'Fleron', + 'Minamikyushu', + 'Tsallagundla', + 'Bashtanka', + 'Soresina', + 'Sogut', + 'Parkersburg', + 'Artesia', + 'Barka Parbatta', + 'San Carlos de Guaroa', + 'Abreus', + 'Sarsai Nawar', + 'Saint-Marc', + 'George', + 'Kamamaung', + 'Bayburt', + 'Narsampet', + 'As Sidrah', + 'Menasha', + 'Aberaman', 'Irikkur', - 'Hassfurt', - 'Teays Valley', - 'Skoczow', - 'eManzimtoti', - 'Wanzleben', - 'Worgl', - 'Schwaz', - 'Colangute', - 'Forest Hill', - 'Turuvanur', - 'Dowbaran', - 'Lieusaint', - 'Calafat', - 'Magalhaes de Almeida', - 'Meckenbeuren', - 'Krumbach', - 'Littleborough', - 'Ewarton', - 'Channahon', - 'Nawagarh', - 'Plav', - 'San Antonio de las Vueltas', - 'Passo de Camarajibe', - 'Tako', - 'Braselton', - 'Koppies', - 'Itagi', - 'Gangavalli', - 'Graca', - 'Villas', - 'Kamnik', - 'Boyovut', - 'Tachov', - 'Union de Tula', - 'Horodyshche', - 'Pierrelatte', - 'Kivertsi', - 'Ronne', - 'Achuapa', - 'Assai', - 'Vargem da Roca', - 'Carmo de Minas', - 'Iguatemi', - 'Loningen', - 'Bideipur', - 'Acajutiba', - 'Rixheim', - 'Sarayan', - 'Tibri', - 'Arbaa Laaounate', - 'Anapurus', - 'Lys-les-Lannoy', - 'San Giljan', - 'Oftringen', - 'Itapetim', - 'Hunxe', - 'Ban Bang Muang', - 'San Rafael Petzal', - 'Ban Tha Luang Lang', - 'Akropong', - 'Bellefontaine', - 'Roncq', - 'Siemiatycze', - 'Couvin', - 'Jinmingsi', - 'Rosyth', - 'Sannicandro Garganico', - 'Mont-Laurier', - 'Higashimiyoshi', - 'Yulee', - 'Ampasinambo', - 'Zhongliao', - 'Cacu', - 'Chaoyangdicun', - 'Lomma', - 'Guape', - 'Torul', - 'Morwell', - 'Grafelfing', - 'Varedo', - 'Arugollu', - 'Berceni', - 'Marianske Lazne', - 'Saint-Orens-de-Gameville', - 'Gouka', - 'Feliz', + 'Herning', + 'Apeldoorn', + 'El Campo', + 'Thakhek', + 'Karanjia', + 'Maullin', + 'Druten', + 'Mundra', + 'Paveh', + 'Carovigno', + 'Jodar', + 'Montevarchi', + 'LaGrange', + 'Masanasa', + 'Maddela', + 'Chicago', + 'Kamayakkavundanpatti', + 'Xiangyang', + 'Leizhou', + 'Atner', + 'Siderno Marina', + 'Agra', + 'Shin-Kamigoto', + 'Anenecuilco', + 'Sejenane', + 'Paletwa', + 'Pantanaw', + 'Senec', + 'Messaad', + 'Brielle', + 'Cangxi', + 'Dagarua', + 'Kingston South East', + 'Allestree', + 'Oslob', + 'Bolsover', + 'Grand Turk', + 'Bohodukhiv', + 'Boulogne-sur-Mer', + 'Kyotanabe', + 'Coimbatore', + 'Jinshi', + 'Ornskoldsvik', + 'Woonsocket', + 'Buhusi', + 'Villanueva de la Canada', + 'Karugamad', + 'Jumla', + 'Pueblo Nuevo Vinas', + 'Tres de Mayo', + 'Sal Rei', + 'Valkeakoski', + 'Kungsangen', + 'Zulte', + 'Kerewan', + 'Tabango', + 'Naha', + 'Akkus', + 'Tulcea', + 'Moratuwa', + 'Utsunomiya', + 'Noeux-les-Mines', + 'Los Barrios', + 'Agadi', + 'Hlohovec', + 'Gages Lake', + 'Tiverton', + 'Golmarmara', + 'Puszczykowo', + 'Mangabe', + 'Hohr-Grenzhausen', + 'Zango', + 'Cua Lo', + 'Mansalay', 'Leverano', - 'Snoqualmie', - 'Tampamolon Corona', - 'Taggia', - 'Kodigenahalli', - 'Willow Grove', - 'Eppstein', - 'Singalandapuram', - 'Sao Pedro do Piaui', - 'Gulcho', - 'Cayce', - 'Bandarbeyla', - 'Amrabad', - 'Travagliato', - 'Lipno', - 'Nehram', - 'Chityal', - 'Megarine', - 'Orange Walk', - 'Holzgerlingen', - 'Kannivadi', - 'Waianae', - 'Douar Lehgagcha', - 'Jardin', - 'Settara', - 'Moissac', - 'Uruoca', - 'Rostamabad', - 'Central Elgin', - 'Itinga', - 'Flores de Goias', - 'Urupes', - 'Manavalakurichi', - 'Barghat', - 'Msata', - 'Forster', - 'Hawick', - 'Mata', - 'Badarwas', - 'Tacaimbo', - 'Beverstedt', - 'Bondeno', - 'Ephrata', - 'Zarghun Shahr', - 'Sidmouth', - 'Ermoupoli', - 'Hazel Crest', - 'Ataleia', - 'Futrono', - 'Lyaskovets', - 'Guaraniacu', - 'Priverno', - 'Enghien', - 'Urbino', - 'Kudachi', - 'Palkur', - 'Bodagudipadu', - 'St. James', - 'Angical', - 'Ibateguara', - 'Taglio', - 'Darihat', - 'Uruana', - 'Saint-Martin-de-Crau', - 'Miami Springs', - 'Malepur', - 'Nova Trento', - 'Sao Joao do Triunfo', - 'Milford Haven', - 'Xireg', - 'Kidlington', - 'Sobraon', - 'Nonoai', - 'North Fair Oaks', - 'Mistassini', - 'Tamaraikkulam', - 'Rocky Point', - 'Wezep', - 'Nova Canaa', - 'Lamont', - 'Saugeen Shores', - 'Eichstatt', - 'Sher Chakla', - 'Marienheide', - 'Knottingley', - 'Ipecaeta', - 'Moberly', - 'Mions', - 'Kovilur', - 'Crevalcore', - 'Cerro Largo', - 'Ndele', - 'Kaleyanpur', - 'Coldwater', - 'Colesville', - 'Biedenkopf', - 'Quata', - 'South Park', - 'Montataire', - "Toyloq Qishlog'i", - 'Sariq', - 'Papagos', - 'Mohda', - 'Presidente Kennedy', - 'Tiruppanandal', - 'Hinabangan', - 'Ingersoll', - 'Auriflama', - 'Angermunde', - 'Valencia West', - 'Diai Koura', - 'Kraainem', - 'Boa Nova', - 'Itapagipe', - 'Uarini', - 'Mangha', - 'Santa Cruz de Bezana', - 'Castel San Giorgio', - 'Tarumizu', - 'San Pedro Pochutla', - 'Radomyshl', - 'Genthin', - 'Chak Husaini', - 'Schmolln', - 'Glenpool', - 'Quatis', - 'Palmito', - 'Motupe', - 'Cambados', - 'Karma', - 'Maribondo', - 'Hettstedt', - 'Kannadiparamba', + 'Yanahuanca', + 'Sinaia', + 'Gudluru', + 'Vadugapatti', + 'Ban Tha Phra', + 'Kikwit', + 'Cantagalo', + "Yan'an Beilu", + 'Tampakan', + 'Glanerbrug', 'Copalchi', - 'Kaladgi', - 'Slobozhanske', - 'Sansare', - 'Sendenhorst', - "Saint Ann's Bay", - 'Yongcong', - 'Normandia', - 'Altos del Rosario', - 'Bhimadolu', - 'Duverge', - 'Otley', - 'Rio Caribe', - 'San Ferdinando di Puglia', - 'Chiran', - 'Mucambo', - 'Pote', - 'Nova Veneza', - 'Jindayris', - 'Qantir', - 'Latham', - 'Bad Durrheim', - 'Namin', - 'Fiesole', - 'Warrensville Heights', - 'Xikou', - 'Isagarh', - 'El Crucero', - 'Saint-Jacques-de-la-Lande', - 'Chosei', - 'Pien', - 'Barahari', - 'Ajjampur', - 'Glen Carbon', - 'Mirabela', - 'Retirolandia', - 'Avalepalli', - 'San Agustin de Guadalix', - 'University Heights', - 'Jurema', - 'Domkonda', - 'Curiuva', - 'Shodoshima', - 'Speedway', - 'Lanuza', - 'Umburanas', - 'Helensburgh', - 'Childwall', - 'Woudenberg', - 'Pedreiras', - 'Beauharnois', - 'Kostolac', - 'El Kerma', - 'Beeville', - 'Frei Miguelinho', - 'Abadla', - 'Port Neches', - 'California', - 'Hammam el Rhezez', - 'Milovice', - 'Santa Coloma de Farnes', - 'Bunhe', - 'Kunjatturu', - 'Dantewara', - 'Uitgeest', - 'Trzebnica', - 'Pitlam', - 'Spring Garden', - 'Jiquirica', - 'Samorin', - 'Solonytsivka', - 'Balhapur', - 'Bamafele', - 'Boninal', - 'Engenheiro Caldas', - 'Allestree', - 'Ottaikkalmantapam', - 'Mahuwa Singhrai', - 'Saimbeyli', - 'Yesilli', - 'Jaca', - 'Maglie', - 'Babhanganwa', - 'Brecksville', - 'Ihtiman', - 'Santa Luzia do Itanhy', - 'Pfullendorf', - 'Artena', - 'Shamalgan', - 'Serra Branca', - 'Baianopolis', - 'Primeira Cruz', - 'Formello', - 'Oroco', - 'Brejo do Cruz', - 'Sao Felix do Araguaia', - 'Mantenopolis', - 'Verin', - 'Kyzyl-Adyr', - 'Castilla La Nueva', - 'Soller', - 'Kauhajoki', - 'Yamanobe', - 'Rozaje', - 'Tejutla', - 'Elesbao Veloso', - 'Karpi', - 'Kerepestarcsa', - 'Masangshy', - 'Combarbala', - 'Bollene', - 'Marchtrenk', - 'Qingxicun', - 'Chengara', - 'Amboasary-Gara', - 'Dongshicuo', - 'Barssel', - 'Atner', - 'Mohania', - 'Wyandanch', - 'Marhamat', - 'Vedi', - 'Vazquez', - 'Nighoj', - 'Jannat Shahr', - 'Danielskuil', - 'Rayapalle', - 'Razole', - 'Guerrero Negro', - 'Sisai', - 'Duvva', - 'Canasgordas', - 'Middlewich', - 'Okinoshima', - 'New Providence', - 'Amingarh', - 'Tapilula', - 'Doume', - 'Ixcatepec', - 'Raquira', - 'Leczyca', - 'Nybro', - 'Pirallahi', - 'Camapua', - 'Atome-Avegame', - 'Beaufort', - 'Rommerskirchen', - 'New Carrollton', - 'Pama', - 'Gonzalez', - 'West End', - 'San Jose Villanueva', - 'Wanze', - 'Neckargemund', - 'Gondalga', - 'Dueville', + 'Zacualtipan', + 'Fidenza', + 'Tsararano', + 'Ferguson', + 'Renukut', + 'Sao Sebastiao do Cai', + 'Mainburg', + 'Ceres', + 'Uluberiya', + 'Mauji', + 'Telfs', + 'Cachoeira dos Indios', + 'Triunfo', + 'Mittegrossefehn', + 'Murehwa', + 'Velika Polana', + 'Borgosesia', + 'Shichuanxiang', + 'Befandefa', + 'Pilar do Sul', + 'Quimper', + 'Saeby', + 'Netanya', + 'Peri-Mirim', + 'Tidjelabine', + 'Tecolutla', + 'Anakaputtur', + 'Quipapa', + 'Dikili', + 'Yuma', + 'Parakadavu', + 'Oxapampa', + 'Odense', + 'Tanambao-Daoud', + 'Bussum', + 'Dartford', + 'Bilaua', + 'Stoughton', + 'Alcanena', + 'Cloverleaf', + 'Akambadam', + 'Anomabu', + 'Lo Barnechea', + "Wen'anyi", + 'Port Orchard', + 'Ahuachapan', + 'Horta', + 'Bourg-de-Peage', + 'Neuville-les-Dieppe', + 'Walton upon Thames', + 'Jaguaquara', + 'Koshigaya', + 'Wendeburg', + 'Tall Shihab', + 'Tounfafi', + 'Al Hamah', + 'Mostar', + 'Illizi', + 'Khaspur', + 'Sirvan', + 'Lapu-Lapu City', + 'Sint-Gillis-Waas', + 'Cassongue', + 'Beahitse', + 'Virapalle', + 'Geislingen an der Steige', + 'Bogalusa', + 'Stavanger', + 'Jiaji', + 'Kannapuram', + 'Bamukumbit', + 'Maroua', + 'Correggio', + 'Bikkavolu', + 'Kumaranallur', + 'Guinagourou', + 'Salonta', + 'Zhutang', + 'Tamarankottai', + 'Tzucacab', + 'Gurais', + 'Taichung', + 'Oas', + 'Anjukulippatti', + 'Melchor Ocampo', + 'Nochistlan de Mejia', + 'Victor', + 'Limeira', + 'Chalfont Saint Peter', + 'La Marsa', + 'Cullinan', + 'Shimeo', + 'Neuhof', + 'Kannulu', + 'Daganbhuiya', + 'Antigua Guatemala', + 'Bowmanville', + 'Zemoura', + 'Tyele', + 'Cedartown', + 'Kingsland', + 'Toyomamachi-teraike', + 'Bni Khloug', + 'Montargis', + 'Sarasambo', + 'Aurora', + 'Nilka', + 'Siena', + 'Santa Vitoria', + 'Goz-Beida', + 'Murray', + 'Hennaya', + 'Santa Isabel Cholula', + 'Bellamkonda', + 'Andasibe', + 'Quvasoy', + 'Villa Park', + 'Thaon-les-Vosges', + 'Acri', + 'Limbdi', + 'Kaisariani', + 'Coconut Creek', + 'Kitakoriyamacho', + 'Gaggenau', + 'Newmarket', + 'Grombalia', + 'Dogansehir', + 'Chinsali', + 'Moisei', + 'La Vallee de Jacmel', + 'Kadamalaikkundu', + 'Wagga Wagga', + 'Sonthofen', + 'Sukkur', + 'Zhaozhou', + 'Boshruyeh', + 'Macara', + 'Cheongju', + 'Nisko', + 'Meftah', + 'Amilly', + 'Ageoshimo', + 'Butzbach', + 'Giria', + 'Sultonobod', + 'Sucua', + 'Keregodu', + 'Dudhgaon', + 'Chalma', + 'Pierre-Benite', + 'Oberriet', + 'Tramandai', + 'Shiggaon', + 'Whitestown', + 'Zaqatala', + 'Zaboli', + 'Houston', + 'Sorab', + 'Enkhuizen', + 'Kaniwara', + 'Sare-Yamou', + 'Kriens', + 'Petersburg', + 'Rawah', + 'Montenegro', + 'Boorama', + 'Gangawati', + 'Manjuyod', + 'Argostoli', + 'Clarksburg', + 'Fall River', + 'Boffa', + 'Sodag', + 'Hingyon', + 'Kanding', + 'Gresham', + 'Peruru', + 'Kemigawa', + 'Manbazar', + 'Capitol Hill', + 'Bo`z', + 'Murshidabad', + 'Resplendor', + 'Baishi Airikecun', + 'Bulancak', + 'Aibonito', 'East Islip', - 'Piquete', - 'Marghita', - 'Cervignano del Friuli', - 'Tokoroa', - 'Upanema', - 'Patalia', - 'Royal Wootton Bassett', - 'South Stormont', - 'Bridport', - 'Gran', - 'Presidente Bernardes', - 'Lappersdorf', - 'Serui', - 'Bardstown', - 'Latiano', - 'Dattapulia', - 'Pegnitz', - 'Sharm ash Shaykh', - 'Dhana', - 'Becancour', - 'Winsum', - 'Palestina', - 'Newington', - 'Asperg', - 'Talne', - 'Nalatvad', + 'Mengibar', + 'Kotwapatti Rampur', + 'Qaryat al Qi`an', + 'Estiva Gerbi', + 'Sipalay', + 'Mandrosohasina', + 'Hadera', + 'Partick', + 'Pulawy', + 'Lobamba', + 'Vitoria de Santo Antao', + 'Fada Ngourma', + 'Al Hoceima', + 'Agcogon', + 'Konina', + 'Mahbubnagar', + 'Temamatla', + 'Assab', + 'Gautier', + 'Mangalkot', + 'San Benito', + 'Ben Ahmed', + 'Natori-shi', + 'Wymondham', + 'Hassi el Ghella', + 'Pesca', + 'Kuttappatti', + 'Campo de Criptana', + 'Pelham', + 'Mont-Saint-Hilaire', + 'Sao Joaquim', + 'Lusca', + "Topol'cany", + 'Itagui', + 'Artur Nogueira', + 'Cheadle Hulme', + 'Timmiarmiut', + 'Carmopolis', + 'Dolhasca', + 'Mangghystau', + 'Much', + 'Vadamugam Vellodu', + 'Vamanapuram', + 'Bordj Mokhtar', + 'Tougouni', + 'Beldaur', + 'Limbuhan', + 'Paraibano', + 'Realeza', + 'Puchheim', + 'Cardedeu', + 'Cacocum', + 'Luacano', + 'Villavicencio', + 'Fray Bartolome de Las Casas', + 'Burke', + 'Dabiya', + 'Pizarra', + 'Kothapet', + 'Ile-Ife', + 'Chittattukara', + 'Chuadanga', + 'Wausau', + 'Ban Tha Ton', + 'Feyzabad', + 'Frankenberg', + 'Gostivar', + 'Magelang', + 'Sabaya', + 'Maleme Hodar', + 'Virakeralam', + 'Bhisho', + 'Rakhiv', + 'Manjimup', + 'Catalpinar', + 'Liaoyuan', + 'Akureyri', + 'Ris-Orangis', + 'Larena', + 'Ampelokipoi', + 'Waterloo', + 'Siguiri', + 'Sujina', + 'Monte Alegre do Piaui', + 'Maicao', + 'Ambohimiadana', + "Pan'an", + 'Vallauris', + 'Lingampalli', + 'Ewell', + 'Tambau', + 'South Union', + 'Moga', + 'Talghar', + 'Salinas', + 'Gonghe', + 'Temple City', + 'Ternat', + 'San Ramon de la Nueva Oran', + 'Donaueschingen', + 'Adilcevaz', + 'Plainedge', + 'Salotgi', + 'Barotac Nuevo', + 'Chevigny-Saint-Sauveur', + 'Jaisalmer', + 'Cameri', + 'Lowshan', + 'Pleasant View', + 'Gazipura', + 'Indwe', + 'Yen Bai', + 'Hospet', + 'Jamai', + 'Palmetto Estates', + 'Ponnani', + 'Hwlffordd', + 'Tiny', + 'Bhattu Kolan', + 'Yangsan', + 'Allanridge', + 'Quyang', + 'Agoo', + 'Sabbavaram', + 'Chamical', + 'Buritama', + 'Minna', + 'Millbury', + 'San Jose Villa de Allende', + 'Ercis', + 'Mogok', + 'Dona Remedios Trinidad', + 'Rio Novo do Sul', + 'Kormend', + 'Ambohimitombo', + 'New Carrollton', + 'Mount Airy', + 'Qinhuangdao', + 'Madingou', + 'Robbinsdale', + 'Huejucar', + 'Erraballa', + 'Andover', + 'Kefar Yona', + 'Sweet Home', + 'Deming', + 'Asakuchi', + 'Al Mu`abbadah', + 'Varna', + 'Pine Bluff', + 'Rovira', + 'Brackley', + 'Kodala', + 'Patu', + 'Satoraljaujhely', + 'Ambohimanga', + 'Cherukolattur', + 'Marechal Deodoro', + 'Pelaya', + 'Cape Town', + 'Sarakkayhalli', + 'Manado Light', + 'Ihsaniye', + 'Yangiobod', + 'Natagaima', + 'Mattathur', + 'Strathroy-Caradoc', + 'Talagante', + 'Montclair', + 'Kiryandongo', + 'Nzeto', + 'Pativilca', + 'Quiapo', + 'Pulilan', + 'Serra Preta', + 'Alagoa Grande', + 'Jerez', + 'Edam', + 'Merces', + 'Galaz', + 'Pahuatlan de Valle', + 'Nathpur', + 'Orem', + 'Milford Mill', + 'Vimercate', + 'Baie de Henne', + 'Fanandrana', + 'Stenungsund', + 'Fondi', + 'Vipparla', + 'Arroyomolinos', + 'Kaniyur', + 'Cristuru Secuiesc', + 'Marawi City', + 'Dong Hoa', + 'Moura', + 'Selsey', + 'Dinalupihan', + 'Busko-Zdroj', + 'Itatim', + 'Foumban', + 'Purwa', + 'Woippy', + 'Muzhakkunnu', + 'Backa Topola', + 'Colmenarejo', + 'Burg', + 'Ashoknagar', + 'Manerbio', + 'Montmorency', + 'Carteret', + 'Kotekara', + 'El Socorro', + 'Mayahaura', + 'Besigheim', + 'Barsinghausen', + 'Raita', + 'Zwenkau', + 'Fords', + 'Palamedu', + 'McHenry', + 'Rahovec', + 'Lajosmizse', + 'Sakhmohan', + 'Lyons', + 'Ulatu', + 'Tuskegee', + 'Humacao', + 'Launaguet', + 'Paranaiba', + 'Shitab Diara', + 'Asansol', + 'Signal Mountain', + 'Hammam Bou Hadjar', + 'Novi Sad', + 'Karghar', + 'Arzano', + 'Thatri', + 'Vossevangen', + 'Cuya', + 'Lymanka', + 'Bucak', + 'Cathedral City', + 'Sidi Slimane', + 'Tapejara', + 'Marco', + 'Tingloy', + 'Shelby', + 'Sijua', + 'Moss Point', + 'Satwas', + 'Parkal', + 'Sitapur', + 'Maniyamturuttu', + 'Nakhla', + 'Ispica', + 'Nayagaon', + 'Telimele', + 'Mono', + 'Kolga', + 'Mirjaveh', + 'Warrensburg', + 'Furstenfeld', + 'Oswiecim', + 'Pariyapuram', + 'Cuito Cuanavale', + 'Yoqne`am `Illit', + 'Komatsu', + 'Farmersville', + 'Mazar-e Sharif', + 'Tasil', + 'Surla', + '`Ain el Hadjel', + 'Potukonda', + 'Alcochete', + 'McKinleyville', + 'Lage', + 'Dugda', + 'Candijay', + "Intich'o", + 'Mercier', + 'Kamnik', + 'Tleta Taghramt', + 'Dungannon', + 'Montespertoli', + 'Port Jervis', + 'Matiguas', + 'Tago', + 'Oulad Daoud', + 'Haymana', + 'Tshela', + 'Aso', + 'South Hadley', + 'Doranahalli', + 'La Palma', + 'Laitila', + 'Stara Zagora', + 'Az Zuwaydah', + 'Storozhynets', + 'Muppalla', + 'Urganch', + 'Bialystok', + 'Libertad', + 'Bilara', + 'Zemio', + 'Mbabane', + 'Tsukawaki', + 'Middle Valley', + 'Sierra Vista Southeast', + 'Balboa', + 'Ostrowiec Swietokrzyski', + 'Lucapa', + 'Chiang Rai', + 'Khujand', + 'Great Baddow', + 'Buthidaung', + 'El Chol', + 'Albuera', + 'Carmignano', + 'Sommacampagna', + 'Kutum', + 'Cambambe', + 'Cunha Pora', + 'Longtaixiang', + 'Lawas', + 'Meru', + 'Ibiuna', + 'Aalen', + 'Kuah', + 'Bertem', + 'Consuegra', + 'Gamarra', + 'Chunakhali', + 'Tavsanli', + 'Kolwezi', + 'Dori', + 'Melsele', + 'Murugampalaiyam', + 'Yirga `Alem', + 'Vrnjacka Banja', + 'Bentota', + 'Bron', + 'Uncia', + 'Woerden', + 'San Juan Nonualco', + 'National City', + 'Rajshahi', + 'Mount Kisco', + 'Ludza', + 'Pattambi', + 'Korsimoro', + 'Keota', + 'Marion', + 'Kyaukmyaung', + 'Algun', + 'Montrose', + 'Loganville', + 'Gracemere', + 'Anthony', + 'Lapeer', + 'Blachownia', + 'Dimiao', + 'Dellys', + 'Haramachida', + 'Porto da Folha', + 'Ullo', + 'Iju', + 'Caister-on-Sea', + 'Dunaharaszti', + 'Ghanpur', + 'Ban Mae Ka Hua Thung', + 'Ajodhya', + 'La Garriga', + 'Canela', + 'Mallappadi', 'Rossington', - 'Bandar-e `Asaluyeh', - 'Western Springs', - 'Echelon', - 'Haselunne', - 'Hilsea', - 'Kurtkoti', - 'Stolin', - 'Nesconset', - 'Plover', - 'Bishenpur', - 'Chinique', - 'Mor', - 'Ugo', - 'Oosterzele', - 'Niaogho', - 'Rahui', - 'Karnawad', - 'Tamanique', - 'Hola Prystan', - 'Kaharlyk', - 'Dinant', - 'Mascote', - 'Castelfranco di Sotto', - 'Endicott', - 'Wentorf bei Hamburg', - 'Rukhae', - 'Martinsville', - 'Kheri Naru', - 'Lexington Park', - 'Bexley', - 'Beur', - 'Kharv-e Sofla', - 'Amriswil', - 'Thisted', - 'Wschowa', - 'Hemsworth', - 'Albertirsa', - 'Janapadu', - 'Spaichingen', - 'Koubel-Koundia', - 'Shangping', - "`Alem T'ena", - 'Rheinfelden', - 'Corabia', - 'South Charleston', - 'Darat `Izzah', - 'Llanes', - 'Antigua', - 'Pfarrkirchen', - 'Eatontown', - 'Tovuz', - 'Bad Salzdetfurth', - 'Borgaon', - 'Vaires-sur-Marne', - 'General Belgrano', - 'Novi Iskar', - 'Calolziocorte', - 'Kafr Nabudah', - 'Tauberbischofsheim', - 'Cayiralan', - 'Adh Dhakhirah', - 'Nynashamn', - 'Menaa', - 'Sao Ludgero', - 'Lourdes', - 'Nova Varos', - 'Ban Bung Kha', - 'Strabane', - 'Kodriva', - 'Glowno', - 'Hlucin', - 'Avidha', - 'Mqam at Tolba', - 'Ban Mae Kaluang', - 'Wiesmoor', - 'Calderara di Reno', - 'Perungala', - 'Muynoq', - 'Siriari', - 'Karuvellur', - 'Hard', + 'Suriapet', + 'La Caleta', + 'Kumbhraj', + 'Chengdu', + 'Tarnowskie Gory', + 'Wattwil', + 'Hoogeveen', + 'Jagalur', + 'Veymandoo', + 'Sahatona-Tamboharivo', + 'Jaqueira', + 'Marshfield', + 'Jonkoping', + 'Navabad', + 'Phuc Yen', + 'Pinyahan', + 'Palanga', + 'Fujiyoshida', + 'Quela', + 'Ulcinj', + 'Sao Raimundo das Mangabeiras', + "L'Oulja", + 'Polas', + 'Vattalkundu', + 'Lod', + 'Suwanee', + 'Asse', + 'Bensekrane', + 'Siki', + 'Neira', + 'Middelharnis', + 'Managua', + 'Ambatomborona', + 'Touama', + 'Karatepe', + 'Willoughby Hills', + 'Boonton', + 'Mwatate', + 'Sanchahe', + 'Bommayapalaiyam', + 'Fort Bliss', + 'Bronx', + 'Nahuizalco', + 'Ankazomiriotra', + 'East Kelowna', + 'Bacioi', + 'Hassloch', + 'Hengyang', + 'Xishan', + 'Tamuin', + 'Vestmanna', + 'Bochnia', + 'Znin', + 'Purattur', + 'Arapongas', + 'Montividiu', + 'Yagoua', + 'Chinna Annaluru', + 'Chiatura', + 'Dhalai', + 'El Tablon', + 'Jyllinge', + 'Ives Estates', + 'Arenoso', + 'Eppstein', + 'Stony Plain', + 'Charleroi', + 'Bressanone', + 'Graulhet', + 'Diksmuide', + 'Heverlee', + 'Nova Russas', + 'Sholaqqorghan', + 'Viskovo', + 'Palenque', + 'Gatada', + 'Kannanendal', + 'Wadenswil', + 'Nepomuceno', + 'Dalli Rajhara', + 'Okpo', + 'Canelinha', + 'Saharbani', + 'Somma Lombardo', + 'Bojnik', + 'Beylikduzu', + 'Ban Pha Bong', + 'Trumbull Center', + 'Mandera', + 'Rio do Pires', + 'Bagnolo in Piano', + 'Tianchang', + 'Lillerod', + 'Ipswich', + 'Olaippatti', + 'Duzici', + 'Pernamitta', + 'Villa de Zaachila', + 'Wakefield', + 'Mandello del Lario', + 'Heywood', + 'Adigrat', + 'Juchitepec', + 'Nizhyn', + 'San Miguel de Allende', + 'Salemata', + 'Fenton', + 'As Sulaymaniyah', + 'Olhanpur', + 'Moon', + 'Churchdown', + 'Berezne', + 'Avenal', + 'Mettuppalaiyam', + 'Fort St. John', + 'Ghogardiha', + 'Palia Kalan', + 'Dardenne Prairie', + 'Bezerros', + 'Iowa City', + 'Mondragone', + 'Baojishi', + 'Cuiaba', + 'Kopparam', + 'Gokavaram', + 'Karamursel', + 'Bariariya Tola Rajpur', + 'Guambog', + "Mirassol d'Oeste", + 'Manbengtang', + 'Cali', + 'Yaguachi Nuevo', + 'Tiruppalai', + 'Kodivalasa', + 'Elakadu', + 'Hadyach', + 'Kumaralingam', + 'La Victoria de Acentejo', + 'Busembatia', + 'Arbroath', + 'Mahanoro', + 'El Qaa', + 'Ixhuatlan de Madero', + 'Golub-Dobrzyn', + 'Bundala', + 'Lurate Caccivio', + 'Palapag', + 'Biba', + 'Gokceada', + 'Kuzhittura', + 'Assomada', + 'Imias', + 'Obihiro', + 'Makinohara', + 'Chettiyapatti', + 'Wuyuan', + 'Tukrah', + 'Gorinchem', + 'Chettikulam', + 'Knic', + 'Piratini', + 'Takamatsu', + 'Ichhapur', + 'Ross', + 'Jamay', + 'Coyotepec', + 'Hani', + 'Malilipot', + 'Kozloduy', + 'Antwerp', + 'Vikramasingapuram', + 'Houma', + 'Osawa', + 'Colonia del Sacramento', + 'Daulatnagar', + 'Nannamukku', + 'Wanderley', + 'Dunhuang', + 'Campolongo Maggiore', + 'Chiche', + 'Merksem', + 'Kaboila', + 'Boscoreale', + 'Lordegan', + 'Douar Laouamra', + 'General Juan Madariaga', + 'Kottangara', + 'Badurpalle', + 'Rumoi', + 'Blackstone', + 'Marinha Grande', + 'Honmachi', + 'Oostkamp', + 'Xingangli', + 'Castelfidardo', + 'Zemun', + 'Krishnagiri', + 'Haomen', + 'Korbach', + 'Governador Celso Ramos', + 'East Pennsboro', + 'Aurich', + 'Ajjipuram', + 'Bury', + 'Nazare da Mata', + 'Humberto de Campos', + 'Pechea', + 'Cinarcik', + 'Jidd Hafs', + 'Noyon', + 'Zhaodianzi', + 'Sacavem', + 'Bilopillya', + 'Pader', + 'Miami Lakes', + 'Aplao', + 'Camabatela', + 'Domingos Martins', + 'Mahon', + 'Takaba', + 'Konskie', + 'Basso', + 'San Juan Despi', + 'Picui', + 'Ranipet', + 'Shidongcun', + 'Santa Rita do Sapucai', + 'Park Hills', + 'Caldera', + 'Gorenja Vas', + 'Holborn', + 'Welland', + 'Radzyn Podlaski', + 'Riacho dos Machados', + 'Dukli', + 'Motherwell', + 'Santa Rosa de Viterbo', + 'El Ateuf', + 'Villa Corona', + 'Rajaram', + 'Payipira', + 'Molnlycke', + 'Kautalam', + 'Duisburg', + 'Ghoradongri', + 'Sangasso', + 'Tacna', + 'Santa Helena', + 'Casablanca', + 'Kalliyassheri', + 'Xiancun', + 'Dabaga', + 'Chilcuautla', + 'Sihora', + 'New Britain', + 'Kingsburg', + 'Saint-Raymond', + 'Garoua', + 'Tulunan', + 'Torello', + 'Punal', + 'Beutelsbach', + 'Telenesti', + 'Abim', + 'Ed Damour', + 'Tecamachalco', + 'Nootdorp', + 'Centar Zupa', + 'Bernay', + 'Jatauba', + 'Azrou', + 'Hashtrud', + 'Chimichagua', + 'Radzymin', + 'Feldkirchen', + 'Houzhuang', + 'Brant', + 'Saint-Mande', + 'Marauatpur', + 'Radovljica', + 'La Entrada', + 'Kidbrooke', + 'Dnestrovsc', + 'Melksham', + 'Keshan', + 'Stockholm', + 'Fort Mitchell', + 'Haigerloch', + 'Altinozu', + 'Odzaci', + 'La Dorada', + 'Al Buraymi', + 'New Glasgow', + 'Vermilion', + 'Chongshan', + 'Kavarna', + 'Ban San Phak Wan Luang', + 'Puliyampatti', + 'Benslimane', + 'Chaumont-Gistoux', + 'Mae Hong Son', + 'Agia Paraskevi', + 'Kattipparutti', + 'Afyonkarahisar', + 'Berdychiv', + 'Alewah', + 'Pachrukhi', + 'Warzat', + 'Tilaran', + "Gonfreville-l'Orcher", + 'Muradiye', + 'Qara', + 'Defiance', + 'Bagu Na Mohra', + 'Milenaka', + 'Ruda Slaska', + 'Suchiapa', + 'Pachuca', + 'Kingston upon Thames', + 'Kumiyama', + 'Enriquillo', + 'El Astillero', + 'Bergheim', + 'Pindoretama', + 'Ardabil', + 'Lucban', + 'Cacuso', + 'Merimandroso', + "Sa'in Qal`eh", + 'Paula Candido', + 'Varapatti', + 'Erikolam', + 'Clarksdale', + 'Carhue', + 'Lisle', + 'Teotitlan', + 'Chebrolu', + 'Gabrovo', + 'Shambhunath', + 'Creve Coeur', + 'Silver City', + 'Matehuala', + 'Tefe', + 'Nohfelden', + 'Yangambi', + 'Camotan', + 'Las Mercedes', + 'Chevella', + 'Sokolov', + 'Porto Calvo', + 'Kayattar', + 'Batu Gajah', + 'Uppada', + 'Majalgaon', + 'Saint-Ghislain', + 'Staveley', + 'Jaffar Khanpet', + 'Chaiyaphum', + 'Parole', + 'Arara', + 'Hatfield', + 'Santiago Chimaltenango', + 'Cao Bang', + 'Gungoren', + 'Marechal Floriano', + 'Rio Cuarto', + 'Tazishan', + 'Binjai', + 'Pattensen', + 'Zhangjiazhuang', + 'Maasin', + 'Kizhakkanela', + 'Taquarituba', + 'Quedlinburg', + 'Schorndorf', + 'Melilli', + 'Griffin', + 'Ambondromisotra', + 'Cetinje', + 'Channelview', + 'Hanur', + 'Kenmore', + 'Jayrud', + 'Dollis Hill', + 'Taldyqorghan', + 'Al `Uqaylah', + 'Mutia', + 'Dabra', + 'Mae Ai', + 'Bamban', + 'Mayantoc', + 'Mechta Ouled Oulha', + 'Sacapulas', + 'Jaynagar-Majilpur', + 'Gladeview', + 'Dayong', + 'Monte Rico', + 'Nova Soure', + 'San Juan Zitlaltepec', + 'Almel', + 'Sakhua', + 'Kromeriz', + 'Vitorino', + 'Hayward', + 'Kahnuj', + 'Manalurpettai', + 'Altstatten', + 'Sydney Mines', + 'Liuhu', + 'Kasaali', + 'Acton', + 'Jiquipilas', + 'Talegaon Dhamdhere', + 'San Antonio Enchisi', + 'Kaduna', + 'Saint-Ave', + 'Renapur', + 'Carlos Spegazzini', + 'Riverdale', + 'Sint-Gillis-bij-Dendermonde', + 'El Aioun', + 'Ichinoseki', + 'Phulera', + 'Donwari', + 'Motipur', + 'Capitao de Campos', + 'York', + 'Rancho Mirage', + 'Ekma', + 'Thogapalle', + 'Glodeni', + 'Sedan', + 'Cupar', + 'Charbagh', + 'Sahasmal', + "Bazal'tove", + 'Gorkha', + 'Banha', + 'Oguzeli', + 'Nauagarhi', + 'Zaio', + 'Pirojgarh', + 'Aoshang', + 'Faruka', + 'Boaco', + 'Rani Sagar', + 'Cao Lanh', + 'Boyabat', + 'Waslala', + 'Vohitsaoka', + 'Dayton', + 'Borujen', + 'Konya', + 'Naj` Hammadi', + 'Yatomi', + 'Laferriere', + 'Deo', + 'Pampan', + 'Citluk', + 'Naranjito', + 'Haiwei', + 'Bohinjska Bistrica', + 'Kochkor-Ata', + 'Chiromo', + 'Kimitsu', + 'Linkoping', + 'Valinhos', + 'Lozova', + 'Siyazan', + 'Blenheim', + "Olho d'Agua das Cunhas", + 'Oak Park', + 'La Macarena', + 'Tasso Fragoso', + 'Ladkhed', + 'Taber', + 'Atchoupa', + 'Quilpue', + 'Cimislia', + 'Cimerak', + 'Ar Ruhaybah', + 'Xo`jaobod', + 'Antombana', + 'Tarnos', + 'Blackhawk', + 'Hengchun', + 'Petrzalka', + 'Ambatolampy', + 'Renai', + 'Massalubrense', + 'Marcianise', + 'Mako', + 'Palmito', + 'Marshalltown', + 'Taywarah', + 'Guiyang', + 'Patan', + 'Montichiari', + 'Vittoriosa', + 'Chili', + 'Manasa', + 'Khushab', + 'Kujukuri', + 'Zhongzhai', + 'Cagua', + 'Kryzhopil', + 'Phuntsholing', + 'Chhapra Bahas', + 'Banak', 'Wolfhagen', - 'Shawangunk', - 'Ganxi', - 'Chima', - 'Kenadsa', - 'Sikat', - 'Courcouronnes', - 'Nemocon', - 'Cajabamba', - 'Hantsavichy', - 'Gardony', - 'Chandla', - 'Bayt Jala', - 'Stezzano', - 'Genas', - 'El Hachimia', - 'Marudur', - 'Squinzano', - 'Kriva Palanka', - 'Gines', - 'Gudikallu', - 'Vaghodia', - 'Chalma', - 'Schermbeck', - 'Afzala', - 'Fereydunshahr', - 'Ilamatlan', - 'Strand', - "Al Ha'ir", - 'Caapiranga', - 'Plouzane', - 'Bonita', - 'Itaete', - 'Madakkathara', - 'Fontenay-le-Comte', - 'King City', - 'Avocado Heights', - 'Little Hulton', - 'Jamira', - 'Elanad', - 'Kesariya', - 'Yedapalli', - 'Palakkuzhi', - 'Bad Laasphe', - 'Chembrassheri', - 'Sao Joao do Araguaia', - 'Dundigal', - 'Panjgirain Kalan', - 'General Viamonte', - 'Lake Forest Park', - 'Fruita', - 'Nagnur', - 'Nallajerla', - 'Gullapuram', - 'Moncks Corner', - 'San Juan de Limay', - 'Fontenay-le-Fleury', - 'Villanchirai', - 'Irondale', - 'Callaway', - 'Barro Alto', - 'Valdemorillo', - 'Mambore', - 'Beesel', - 'Dok Kham Tai', - 'Hevie', - 'Bou Sfer', - 'Bhakua', - 'Kulharia', - 'Taneichi', - 'Plougastel-Daoulas', - 'Sao Pedro da Agua Branca', - 'Kadattur', - 'Fort Lewis', - 'San Juan de Betulia', - 'Dakit', - 'Orkney', - 'Pefka', - 'Zabreh', - 'Uibai', - 'Ouargaye', - 'Tergnier', - 'Mallet', - 'Tucapel', - 'San Jacinto del Cauca', - 'Chinna Mushidivada', - 'Monteroni di Lecce', - 'Jucuaran', - 'Adis `Alem', - 'Avenal', - 'Versoix', - 'Anzin', - 'Germasogeia', - 'Veglie', - 'Daharia', - 'Ghordaur', - 'Nafpaktos', - 'Sultanpur Mor', + 'Biyala', + "An'gang", + 'Ban Phe', + 'Andoain', + 'Martina Franca', + 'Tadikonda', + 'Itapetininga', + 'Wusong', + 'La Carolina', + 'Greeneville', + 'Datori', + 'Gulbahor', + 'Weifen', + 'Farnley', + 'Piedade', + 'Reiskirchen', + 'Mahitsy', + 'Akouda', + 'Hucclecote', + 'Antsenavolo', + 'Jever', + 'Sablayan', + 'Holzkirchen', + 'Ramara', + 'Phulhara', + 'Ridgeland', + 'Youdiou', + 'Talwandi Chaudhrian', + 'Tadian', + 'Messias', + 'Suar', + 'Minamisuita', + 'Nipani', + 'Jugial', + 'Bisignano', + 'Opole', + 'El Jicaro', + 'Joensuu', + 'Todupulai', + 'Kamituga', + 'Guararapes', + 'Pike Creek Valley', + 'Taimali', + 'Chiconquiaco', + 'Brookfield', + 'Belo Jardim', + 'Uttaramerur', + 'Tokorozawa', + 'Mulungu', + 'Spencer', + 'Sopron', + 'Catape', + 'Mata-Utu', + 'Cha Grande', + 'Jandira', + 'Kunnatnad', + 'Kolhapur', + 'Manchenahalli', + "Cox's Bazar", + 'Mahisi', + 'Nunspeet', + 'Xocali', + 'Hitachiomiya', + 'Beaucaire', + 'Soissons', + 'Hjorring', + 'Antonio Cardoso', + 'Blaydon', + 'Jhalida', + 'Minden', + 'Wardenburg', + 'Ain Bessem', + 'Milwaukee', + 'Coventry', + 'Puli', + 'Arqalyq', + 'Januaria', + 'Los Almacigos', + 'Moreton', + 'Jennings', + 'Laguna Woods', + 'Biloela', 'Chaddesden', - 'Kotgir', - 'Dinklage', - 'Talegaon Dhamdhere', - 'Srebrenica', - 'Basaon', - 'Azle', - 'Tuchola', - 'Sitio do Mato', - 'Sunjiayan', - 'Vellarivalli', - 'Benaulim', - 'Richterswil', - 'Zawodzie', - 'Dyykan-Kyshtak', - 'Seyitgazi', - 'Chahbounia', - 'Vieste', - 'Villa Union', - 'Gaundra', - 'Inawashiro', - 'Ban Don Thong', - 'Heswall', - 'Kalardasht', - 'Mosgiel', - 'Kaabong', - 'Kaiwen', - 'Dalkeith', - 'San Juan La Laguna', - 'Kilgore', - 'Arklow', - 'Uppidamangalam', - 'Panapakkam', - 'Velanganni', - 'Testour', - 'Lacombe', - 'Balsa Nova', - 'Connersville', - 'Goudomp', - 'Kokri', - 'Drobak', - 'Amblecote', - 'Arruda dos Vinhos', - 'Vikravandi', - 'Joppatowne', - 'Targuist', - 'Kissane Ltouqi', - 'Abhwar', - 'Alsager', - 'Gien', - 'Telmar', - 'Butler', - 'Pottsville', - 'Lislique', - 'Besarh', - 'Palmetto', - 'Bouzina', - 'Sanankoro Djitoumou', - 'Aconibe', - 'Faberg', - 'Atlantic Beach', - 'Urziceni', - 'Amondara', - 'Chimalapadu', - 'Goldap', - 'Luis Antonio', - 'Suluktu', - 'Varzea Nova', - 'San Jose de Maipo', - 'Ribeira Brava', - 'Paruchuru', - 'Sainte-Sophie', - 'Wake', - 'Boechout', - 'Margraten', - 'Kawatana', - 'Feldbach', - 'Saint Budeaux', - 'Corsham', - 'Grez-Doiceau', - 'Bagli', - 'Zollikon', - 'Calle Larga', - 'Barka Parbatta', - 'Hatoyama', - 'El Almendro', - 'Arzachena', - 'River Ridge', - 'Yengema', - 'Jupiter Farms', - 'Zehak', - 'Hosbach', - 'Slupca', - 'Mangalapur', - 'Amity', - 'Qigexingcun', - 'Lake Station', - 'Makwassie', - 'Egg Buckland', - 'Mucur', - 'Tiorpara', - 'Port-Alfred', - 'Bijai', - 'Sabana Iglesia', - 'Kotor', - 'Cadereyta', - 'Zbarazh', - 'Peabiru', - 'Nattappettai', - 'Sigli', - 'Shetpe', - 'El Carmen', - 'Vemulapudi', - 'Carnot-Moon', - 'Payyanadam', - 'Czluchow', - 'Andrews', - 'Buli', - 'Barlinek', - 'Karapurcek', - 'Pazhanji', - 'Charlton', - 'Mangalapuram', - 'Rezzato', - 'Serrolandia', - 'Yantzaza', - 'Marungur', - 'Weilburg', - 'Alzano Lombardo', - 'Mountain Park', - 'Kumlu', - 'Ubstadt-Weiher', - 'La Grange Park', - "Sant'Angelo Lodigiano", - 'Sweden', - 'Hillcrest', - 'Puerto Morazan', - 'Itapui', - 'Val-des-Monts', - 'Torshavn', - 'Amarpura', - 'Santa Maria a Monte', - 'Dambal', - 'Blue Ash', - 'Okkerneutboom', - 'Tiruvarpu', - 'Pataili', - 'Bacup', - 'Dohta', - 'Beamsville', - 'Hanimciftligi', - 'Broussard', - 'Saint-Amable', - 'Bachhauta', - 'Kiiminki', - 'Carluke', + 'Monmouth Junction', + 'Sullivan', + 'Wassenberg', + 'Canyon', + 'Mograne', + 'Mardakan', + 'Areia', + 'El Tigre', + 'Wallingford', + 'Goshogawara', + 'Chandannagar', + 'San Marcos', + 'Pedra Branca', + 'Dhani Sukhan', + 'Barni', + 'Maumere', + 'Strathroy', + 'Guozhen', + 'Hlobyne', + 'Blace', + 'Pentecoste', + 'Malden', + 'Bad Orb', + 'Hallstahammar', + 'Delano', + 'Bhadsara', + 'Thal', + 'Dongnanyanfa', + 'Rio Bueno', + 'Vendas Novas', + 'Chhara', + 'Katarmala', + 'Ngorongoro', + 'Takaoka', + 'Kalianpur', + 'Smarje', + 'Mangaldan', + 'Aulla', + 'Koila Belwa', + 'Shenjiaba', + 'Emmen', + 'Ambalavayal', + 'Crepy-en-Valois', + 'Ladwa', + 'Oxchuc', + 'Khagaur', + 'Esmeraldas', + 'Cirkulane', + 'Kaviti', + 'Wadsworth', + 'Lukovit', + 'Venafro', + 'Saint-Gely-du-Fesc', + 'Paramount', + 'Dounan', + 'Fort Beaufort', + 'Ban Mueang Na Tai', + 'Hornsey', + 'Collingwood', + 'Lower Allen', + 'Rangwasa', + 'Merelbeke', + 'Jamao al Norte', + 'Caudebec-les-Elbeuf', + 'Cakovec', + 'Matatiele', + 'Carmen de Patagones', + 'Kivsharivka', + 'Faberg', + 'Doornkop', + 'Istres', + 'Ancud', + 'Ovidiu', + 'Strangnas', + 'Shazhou', + 'Gazantarak', + 'Daule', + 'El Ksar', + 'Riobamba', + 'Paxtakor Shahri', + 'Vontimitta', + 'Pyinmana', + 'Sunset Hills', + 'Raha Tiga', + 'Ujfeherto', 'Kiskoros', - 'Manerbio', - 'Kuurne', - 'Santa Marcela', - 'Morag', - 'Wabrzezno', - 'Dumaria', - 'Faradonbeh', - 'Shibam', - 'Coatesville', - 'Busra al Harir', - 'Duzkoy', - 'Nosivka', - 'Ostwald', - 'Chifubu', - 'Ampthill', - 'Sidi Abd el Moumene', - 'Narayangarh', - 'Ban Na Chom Thian', - 'Coomera', - 'White House', - 'Ambodilazana', - 'Grimstad', - 'Velen', - 'Kagvad', - 'Manching', - 'Saarwellingen', - 'Bouskene', - 'Torredonjimeno', - 'Makarska', - 'Kadena', - 'Woodinville', - 'Nishon Tumani', - 'Charxin', - 'Shirebrook', - 'Shiremoor', - 'Berck-sur-Mer', - 'Tounfit', - 'Goh', - 'Reeuwijk', - 'Ponte San Giovanni', - 'Elfers', - 'Sirhali Kalan', - 'Pushing', - 'Ratnapuram', - 'Undrajavaram', - 'Debno', - 'Argentan', - 'Woodland Park', - 'Soyaniquilpan', - 'Badhoevedorp', - 'San Rafael Oriente', - 'Arendonk', - 'Weinsberg', - 'Cremlingen', - 'Oued Tlelat', - 'Padaivedu', - 'El Tabo', - 'Berezne', - 'Catemu', - 'Reggada', - 'Zehdenick', - 'Aginiparru', - 'Bayt Sahur', - 'Bocaiuva do Sul', - 'Hullhorst', - 'Annamalainagar', - 'Kuhbil', - 'Panchgani', - 'Terebovlya', - 'Guillena', - 'Vetralla', - 'Gura Humorului', - 'Standish', - 'Ang Thong', - 'Carros', - 'Xylokastro', - 'Ikizce', - 'Ettapur', - 'Blytheville', - 'Tummanatti', - 'Montepulciano', - 'Schuttorf', - 'Thame', - 'Ergolding', - 'Urtaowul', - 'West Boldon', - 'Outreau', - 'Portage La Prairie', - 'Joaquim Nabuco', - 'Buttar', - 'Znin', - 'Sulingen', - 'Modakkurichchi', - 'Lincolnwood', - 'Secanj', - 'Amilly', - 'Ban Chomphu Nuea', - 'Bugugoucun', - 'Skoghall', - 'Tarhunah', - 'Tanagura', - 'Rabor', - 'North Greenbush', - 'Los Chiles', - 'Peringom', - 'Naranja', - 'Bas Goynuk', - 'Linlithgow', - 'Knutsford', - 'Aldeia de Paio Pires', - 'Liangwancun', - 'Karivalamvandanallur', - 'Doddipatla', - 'El Tablon', - 'Inderbor', - 'Orange City', - 'Kings Park West', - 'Olfen', - 'Peshkopi', - 'Ares', - 'Steamboat Springs', - 'Trophy Club', - 'Montespertoli', - 'Muragacha', - 'Khoyniki', - 'Herbrechtingen', - 'Fehmarnsund', - 'New Kingman-Butler', - 'Sumbha', - 'Empedrado', - 'Paraiso do Norte', - 'Usumatlan', - 'Ad Duraykish', - 'Kuttyattur', - 'Puerto San Martin', - 'Pe de Serra', - 'Ortaklar', - 'Chhapra', - 'Ostringen', - 'Lubsko', - 'Gangelt', - 'Manivilundan', - 'Sternberk', - 'Dharmaram', - 'Beverungen', - 'Lawang Bato', - 'Ulvila', - 'Daulatnagar', - 'Moody', - 'Ain Youcef', - 'Nanjai Kilabadi', - 'Dharphari', - 'Casandrino', - 'Casatenovo', - 'Borodyanka', - 'Damaishan', - 'Andresy', - 'Perladka', - 'Ivai', - 'Santa Juana', - 'Sebt Labrikiyne', + 'Benin City', + 'Delhi Cantonment', + 'Khowy', + 'Ban Rangsit', + 'Cabudare', + 'Valderrama', + 'Turki', + 'Lohne', + 'Pangkalpinang', + 'Bazhajiemicun', + 'Ribat Al Khayr', + 'Estaimpuis', + 'Mineros', + 'Huanghuajie', + 'Espungabera', + 'Bawku', + 'San Bartolo', + 'Raghogarh', + 'Jaito', + 'Kakiri', + 'Radzionkow Nowy', + 'Chilakalurupet', + 'Maragheh', + 'Alacati', + 'Gata', + 'Rohera', + 'Lakshmicharipara', + 'Myronivka', + 'Matriz de Camarajibe', + 'Tamarana', + "Ambinanin' Andravory", + 'Kirakira', + 'Bramhall', + 'Roccastrada', + 'Hasbergen', + 'Ranjal', + 'Sawakin', + 'Romblon', + 'Jogaili', + 'Kaga', + 'Jinka', + 'Limerick', + 'Chatou', + 'Narman', + 'Ponce', + 'Baskale', + 'Wilnsdorf', + "Saint-Michel de l'Atalaye", + 'Pakala', + 'Sao Sebastiao da Boa Vista', + 'Spring Hill', + 'Orkney', + 'Mahasolo', + 'Ranranagudipeta', + 'Oeiras', + 'Carlos Manuel de Cespedes', + 'Stavroupoli', + 'Conner', + 'Koscielisko', + 'San Donato Milanese', + 'Udon Thani', + 'Jinchang', + 'Dzuunharaa', + 'Castries', + 'Inegol', + 'Novohrodivka', + 'Chyhyryn', + 'Cabarete', + 'Ganderkesee', + 'Bielawa', + 'Roura', + 'Namegawa', + 'Shabqadar', + 'Geylegphug', + 'Guapi', + 'Urgnano', + 'Zhitiqara', + 'Wildberg', + 'Begusarai', + 'Heihe', + 'Zegzel', + 'Or Yehuda', + 'Uenohara', + 'Atherstone', + 'Taku', + 'Central Islip', + 'Dessel', + 'Coal', + 'Gaoua', + 'Narwana', + 'Shuzenji', + 'West Lafayette', + 'Hazar', + 'Kongsvinger', + 'Povoa de Varzim', + 'Zunheboto', + 'Kalmiuske', + 'Zacatepec', + 'Rethen', + 'Benjamin Aceval', + 'Bandeirantes', + 'Yakou', + 'Passi', + 'Malanje', + 'Catacaos', + 'Capelinha', + 'Qingyang', + 'Alcira', + 'La Gloria', + 'Tucson', + 'Ban Chorakhe Samphan', + 'Cienaga', + 'Pebane', + 'Lontra', + 'Haikoucun', + 'Dhanwar', + 'Weifang', + 'Thari Mir Wah', + 'Nakano', + 'Coron', + 'Maysville', + 'Jeonghae', + 'Trgoviste', + 'Salaga', + "Nan'ao", + 'Locri', + 'Kenndie', + 'Florsheim', + 'Ouroeste', + 'Pizzo', + 'Woodmere', + 'Muzaffarpur', + 'Vicencia', + 'Yuriria', + 'Andoas', + 'Chauhanpatti', + 'Debila', + 'Xiwanzi', + 'Mexico City', + 'Perico', + 'Nova Ipixuna', + 'Pullambadi', + 'Osaka', + 'Kazo', + 'Garut', + 'Tonya', + 'Zawiyat Razin', + 'Hajdunanas', + 'Mollerusa', + 'Nuevo San Carlos', + 'Inverurie', + 'Cuddapah', + 'Leiria', + 'Magdeburg', + 'As Saqlawiyah', + 'Sidhi', + 'Jitaicun', + 'Alegrete', + 'Arwal', + 'Pueblo Nuevo', + 'Kovilur', + 'Valaiyampattu', + 'Kollengode', + 'Southside', + 'Tiruvattar', + 'Ahlat', + 'Chandpura', + 'Singleton', + 'Valu lui Traian', + "K'olito", + 'Norzagaray', + 'Onet Village', + 'Maserada sul Piave', + 'Gaziantep', + 'Borgentreich', + 'Cheb', + 'Santa Maria Atzompa', + 'Caspe', + 'Dalton', + 'Ilebo', + 'Harpenden', + 'Tiznit', + 'Fredrikstad', + 'Itaparica', + 'Zabol', + 'Majali', + 'Ubombo', + 'Karaiyampudur', + 'Port Orange', + 'Atitalaquia', + 'Caldas', + 'Shyroke', + 'Songadh', + 'Hai Duong', + 'Ayamonte', + 'Heroica Guaymas', + 'Haraiya', + 'Iarintsena', + 'Cardoso', + 'Yoloten', + 'Tandrano', + 'Tingo Maria', + 'Quimbaya', + 'Jambalo', + 'Samaxi', + 'Leme', + 'Bougtob', + 'Sudipen', + 'Artigas', + 'Ambatotsipihina', + 'Charlottesville', + 'Creutzwald', + 'Mangbwalu', + 'Tempe', + 'Agareb', + 'Jurh', + 'Tambo', + 'Kungalv', + 'Navipet', + 'Ramapattanam', + 'Baykan', + 'Suhr', + 'Taurisano', + 'Maydolong', + 'Oulad Said', + 'Pianiga', + 'Jefferson Hills', + 'Paine', + 'Pocheon', + 'Vennesla', + 'Porto Recanati', + 'Mirpeta', + 'Sendenhorst', + 'Carmichael', + 'Borgo San Lorenzo', + 'Torton', + 'Banta', + 'Urbino', + 'Kedzierzyn-Kozle', + 'Yamunanagar', + 'Ishidoriyacho-eso', + 'Tatui', + 'Amarapura', + 'Kodoli', + 'Monterey', + 'Basavakalyan', + 'Beroun', + 'East Donegal', + 'To`raqo`rg`on', + 'Usharal', + 'Harihar', + 'Amborompotsy', + 'Barkly East', + 'Charaut', + 'Kuttattuppatti', + 'Aracagi', + 'Hongzhai', + 'Sonqor', + 'Krishnamsettipalle', + 'Balugan', + 'Agua Preta', + 'Laayoune', + 'Huyuk', + 'Muban Saeng Bua Thong', + 'Saviano', + 'Florina', + 'Naestved', + 'Itabaianinha', + 'Tekkumbagam', + 'Valls', + 'Ozuluama de Mascarenas', + 'Wanluan', + 'Toledo', + 'Beawar', + 'Parimpudi', + 'Ramachandrapuram', + 'Jalpatagua', + 'Chur', + 'Jajireddigudem', + 'Salgotarjan', + 'Thames Ditton', + 'Sao Joao dos Poleiros', + 'Japoata', + 'Backi Petrovac', + 'Mugalivakkam', + 'Bachra', + 'Ahmadpur East', + 'Ganserndorf', + 'Attibele', + 'Briniamaro', + 'Bazidpur', + 'Santos', + 'Aimores', + 'Ciudad de la Costa', + 'Westchester', + 'Brand', + 'Codlea', + 'Nallagunta', + 'Rovinari', + 'Schiedam', + 'Highland Village', + 'Heikendorf', + 'Ifs', + 'Chuzhou', + '`Anadan', + 'Acornhoek', + 'Fonds Verrettes', + 'Hikone', + 'Cartagena del Chaira', + 'Moyogalpa', + 'Cariari', + 'Moe', + 'Sahatavy', + 'Otley', + 'Nambiyur', + 'Camden', + 'Pomona', + 'Vizianagaram', + 'Lalo', + 'Kafr Zayta', + 'Bruchsal', + 'Gua', + 'Ali Sabieh', + 'Ouargaye', + 'Huzurnagar', + 'Pharaha', + 'Yayas de Viajama', + 'Novi di Modena', + 'Chofugaoka', + 'Besagarahalli', + 'Paulinia', + 'Davis', + 'Landhaura', + 'Apace', + 'San Felice sul Panaro', + 'Silvino Lobos', + 'Liugoucun', + 'Cislago', + 'Bububu', + 'Gohpur', + 'Bhatkal', + 'Kotal', + 'Lons-le-Saunier', + 'Sisai', + 'Palangarai', + 'Harohalli', + 'Tawargeri', + 'Newton', + 'Muscoy', + 'Kade', + 'Sene', + 'Morarano Chrome', + 'Nibria', + 'Rosbach vor der Hohe', + 'Hilpoltstein', + 'Seddouk Oufella', + 'Arbaa Sahel', + 'Olivar', + 'Sevan', + 'Forquilhinha', + 'Lake Mary', + 'Paramus', + 'Naula', + 'Hukeri', + 'Pinheiro', + 'Sivaganga', + 'Baleraja', + 'Koiri Bigha', + 'Le Pecq', + 'Koflach', + 'Namerikawa', + 'Yavuzeli', + 'Songzi', + 'Etawa', + 'Shek Tong Tsui', + 'Long Binh', + 'Tecuala', + 'Vyronas', + 'Potirendaba', + 'Luino', + 'Hazle', + 'Capitan Mauricio Jose Troche', + 'Attiecoube', + 'Queensburgh', + 'Santiponce', + 'Fleurus', + 'Ammapettai', + 'Montoro', + 'Al Waqf', + 'Bam', + 'Dehaqan', + 'Santa Lucia Cotzumalguapa', + 'Tucuran', + 'Ambesisika', + 'Bholsar', + 'Chino', + 'Androndrona Anava', + 'Country Club Estates', + 'Laren', + 'Asolo', + 'Aarsal', + 'Sumner', + 'Majalengka', + 'Barwaaqo', + 'Bon Air', + 'Ampitatafika', + 'Lizzano', + 'Majdel Aanjar', + 'Dahmani', + 'Bhauradah', + 'Qaha', + 'Khorramabad', + 'Shyamnagar', + 'Suisun City', + 'Frecheirinha', + 'Shaw', + 'Chepen', + 'Nulvi', + 'Sao Miguel Arcanjo', + 'Kollipara', + 'Pajara', + 'Kortemark', + 'Cha da Alegria', + 'Crawford', + 'Mistelbach', + 'Erkner', + 'Ituni', + 'Odate', + 'Nanded', + 'Piekary Slaskie', + 'Ainapur', + 'Kapaa', + 'Nemuro', + 'Huolu', + 'Banane', + 'Tredegar', + 'Farkhor', + 'Tlayacapan', + 'Szprotawa', + 'Panchari Bazar', + 'Hirson', + 'Kukrahill', + 'Zierikzee', + 'Talata-Volonondry', + 'Medjana', + 'Santa Maria La Pila', + 'Puligunta', + 'Kataha', + 'Weston', + 'Kaikalur', + 'Glen Ellyn', + 'East St. Paul', + 'Crown Point', + 'Lagoa', + 'Aybasti', + 'Awaji', + 'Sulibele', + 'Puerto Caicedo', + 'La Jigua', + 'Vera', + 'Friedrichsthal', + 'El Dorado', + 'Bezaha', + 'Pagegiai', + 'Ban Sai Ma Tai', + 'Trzic', + 'Sao Benedito do Rio Preto', + 'Arcata', + 'Brunete', + 'Cousse', + 'Itapeva', + 'Shaoshanzhan', + 'Ban Samo Khae', + 'Fort Smith', + 'Giannitsa', + 'Gerona', + 'Degeh Bur', + 'Awsim', + 'Blitar', + 'Basavilbaso', + 'Palsud', + 'Sibolga', + "Dias d'Avila", + 'Cascades', + 'Tecpan Guatemala', + 'Overland', + 'Levin', + 'Tolongoina', + 'Asten', + 'Tamandare', + 'Kannamangalam Tekku', + 'Kandakkadava', + 'Kilattingal', + 'Bayyanagudem', + 'Bremervorde', + 'Wyandanch', + 'Lutz', + 'Kasanda', + 'Tungavi', + 'Palompon', + 'Vinjamur', + 'Ponteland', + 'Kamienna Gora', + 'Springboro', + 'Morsbach', + 'Depalpur', + 'Londuimbali', + 'Garbagnate Milanese', + 'Yenimahalle', + 'Masagua', + 'Machiques', + 'Carbonia', + 'Pisco', + 'Lynwood', + 'Choisy-le-Roi', + 'Ambalaromba', + 'Seremban', + 'Kolar', + 'Telkapalli', + 'Deoria', + 'Glenn Dale', + 'Notre-Dame-des-Prairies', + 'Majayjay', + 'Luzhang', + 'Steha', + 'Sao Jose do Cerrito', + 'Zwettl', + 'Lubango', + 'Moka', + 'Sarpang', + 'Farrukhnagar', + 'Acanceh', + 'Dumas', + 'Minignan', + 'Mazatan', + 'Kadod', + 'Capotille', + 'Wertheim', + 'Gloucester Point', + 'Jibou', + 'Champasak', + 'Katuete', + 'Atuntaqui', + 'Tupi', + 'Nort-sur-Erdre', + 'Leland', + 'Zongolica', + 'North St. Paul', + 'O`nhayot', + 'South River', + 'Euclid', + 'Miedzyrzec Podlaski', + 'Madinat ash Shamal', + 'Sandanski', + 'Parora', + 'Gela', + 'Beronono', + 'Nederland', + 'Lower Macungie', + 'Acambay', + 'Cape Girardeau', + 'Mafamude', + 'Siddhirganj', + 'Gonbad-e Kavus', + 'San Antonio del Sur', + 'Tsuruga', + 'Sarcelles', + 'Pont-Saint-Esprit', + 'Serekali', + 'Iguape', + 'Rosemount', + 'Hulikal', + 'Nordenham', + 'Bannur', + 'Westerkappeln', + 'Bozdogan', + 'Eslohe', + 'Koth', + 'Kattari', + 'Caltanissetta', + 'Francavilla al Mare', + 'Iguai', + 'Moundou', + 'Kozakai-cho', + 'Alfaro', + 'Sonsoro', + 'Ljubljana', + 'Charakunda', + 'Ambohidranandriana', + 'Caraguatay', + 'Moriyama', + 'Voula', + 'Penamiller', + 'Ponnai', + 'Juan Aldama', + 'Douglasville', + 'Pati', + 'Pfarrkirchen', + 'Roman', + 'Busan', + 'Kottapeta', + 'Nagua', + 'Salaya', + 'Ciudad Dario', + 'Buttelborn', + 'Victorville', + 'San Pelayo', + 'Mauren', + 'Khairtal', + 'Bombarral', + 'Cadillac', + 'Isiro', + 'Cabral', + 'Pelagor', + 'Guastalla', + 'Cruces', + 'Gungu', + 'Milford', + 'Tigrana', + 'Mundargi', + 'Daram', + 'Saudharkrokur', + 'Canonsburg', + 'Aourir', + 'Blue Springs', + 'Commerce', + 'Saint-Die-des-Vosges', + 'Lubuklinggau', + 'Lake City', + 'Bougouni', + 'Netrakona', + 'Meral', + 'Csongrad', + 'Tokai', + 'Linthicum', + 'Taylorville', + 'Sano', + 'Araguatins', + 'Prokuplje', + 'Dhansaria', + 'Turtkul', + 'Gyzylgaya', + 'Bollullos de la Mitacion', + 'Mallagunta', + 'San Luis Potosi', + 'Ukmerge', + 'Chenove', + 'Huejuquilla el Alto', + 'South Gate', + 'Llantwit Major', + 'Thomazeau', + 'Memunda', + 'Stockton-on-Tees', + 'Himatnagar', + 'Rapid City', + 'Banes', + 'Rheydt', + 'Bobenheim-Roxheim', + 'Lauterach', + 'Kalmthout', + 'Yashan', + 'Baures', + 'Malanday', + 'Treviso', + 'Ico', + 'Vladimirci', + 'Dora', + 'Abergavenny', + 'Parow', + 'Tineghir', + 'Iapu', + 'Cremona', + 'Tazmalt', + 'Vernon Hills', + 'Palermo', + 'Ambiula', + 'Alaverdi', + 'Altamira', + 'Sao Goncalo', + 'Sakado', + 'Pingree Grove', + 'Newton Abbot', + 'Puerto Morelos', + 'Buesaco', + 'Santa Maria da Vitoria', + 'Zeuthen', + 'Hebri', + 'Petua', + 'Sertania', + 'Yangiyer', + 'Mahmudabad', + 'Dinhata', + 'Bariarpur', + 'Mondeville', + 'Efatsy-Anandroza', + 'Rasht', + 'Port Royal', + 'Marotta', + 'Suffern', + 'Pearland', + 'Paduvari', + 'Ain Lechiakh', + 'Ruvo di Puglia', + 'Wittingen', + 'Rochester Hills', + 'Matsavaram', + 'Dunakeszi', + 'Sowa Town', + 'Barneveld', + 'Koycegiz', + 'Shanhu', + 'Zaidpur', + 'Valenca', + 'Rockaway', + 'Champua', + 'Caojiachuan', + 'Saraykent', + 'Gheorgheni', + 'Shonai', + 'Itaueira', + 'Itanagar', + 'Bandar-e Mahshahr', + 'Yelandur', + 'Kempston', + 'Elazig', + 'San Juan Guichicovi', + 'Tom Price', + 'Zhegaozhen', + 'Igdir', + 'Chang', + 'Nyakrom', + 'Shamunpet', + 'Sultanabad', + 'Tazarka', + 'Rathdrum', + 'Souahlia', + 'Konnur', + 'Rinconada', + 'Lamballe', + 'Planaltina', + 'Sunadkuppi', + 'Mangpa', + 'Marsciano', + 'Eonyang', + 'Bani Murr', + 'Baba Hassen', + 'Colatina', + 'Tianningcun', + 'Morazan', + 'Guantingzhan', + 'Misserghin', + 'Carolina Forest', + 'Tanakallu', + 'Castellarano', + 'Kumla', + 'Yorktown', + 'Santo Domingo Xenacoj', + 'Louga', + 'Fort Lee', + 'Tepperumalnallur', + 'Ampanety', + 'Ajuy', + 'Idstein', + 'Pristina', + 'Snina', + 'Habaswein', + 'Joghtay', + 'Shimizucho', + 'Kotancheri', + 'Woodstock', + 'Falagueira', + 'Moorestown-Lenola', + 'San Juan Sacatepequez', + 'Rio do Sul', + 'Mirador', + 'Moba', + 'Hassi Khelifa', + 'Nossa Senhora Aparecida', + 'Ibiza', + 'Watauga', + 'Zemrane', + 'Santa Cruz Xoxocotlan', + 'Pilis', + 'Evian-les-Bains', + 'Beraketa', + 'Goldsboro', + 'Isulan', + 'Sundern', + 'Aikaranad', + 'Yola', + 'Sunderland', + 'Ouled Ben Abd el Kader', + 'Pakaur', + 'Antsirabe Avaratra', + 'Schofield Barracks', + 'Serang', + 'Lede', + 'Guernica', + 'Mostoles', + 'Villa Mercedes', + 'Carcar', + 'Beruniy', + 'Mariano Acosta', + 'Toin', + 'Kashikishi', + 'Dar Chabanne', + 'uMhlanga Rocks', + 'Mieres', + 'Chipurupalle', + 'Aranda', + 'Nacogdoches', + 'Benner', + 'Ahvaz', + 'Sint-Michiels', + 'Yamamoto', + 'Retie', + 'Pitman', + 'Bagabag', + 'Phalaborwa', + 'Couva', + 'Kheri Naru', + 'Bazidpur Madhaul', + 'Carlton Colville', + 'Al Mafraq', + 'Amasra', + 'Peruibe', + 'Cuarte de Huerva', + 'Labrador', + 'Bawshar', + 'Pirojpur', + 'Taraza', + 'Teminabuan', + 'Shimotsuke', + 'Garca', + 'Rifadpur', + 'Los Chiles', + 'Bhandarso', + 'Capurso', + 'Caetes', + 'Pajapita', + 'Puerto Real', + 'East York', + 'Teteven', + 'Coruche', + 'Wurzen', + 'Pescaria Brava', + 'Guzhou', + 'Stanwell', + 'Khanabad', + 'Xisa', + 'Guruzala', + 'Basla', + 'Sabana Larga', + 'Dom Feliciano', + 'Kuytun', + "L'Asile", + 'Bokhtar', + 'Nazarabad', + 'Leticia', + 'Malang', + 'Ambohimiera', + 'Amjhar', + 'Veitshochheim', + 'Besana in Brianza', + 'Lynn', + 'Barura', + 'Statte', + 'Balchik', + 'Ottappidaram', 'Afir', - 'Mahalpur', - 'Gopalasamudram', - 'Mesudiye', - 'Sarria', - 'Chiroqchi', - 'Nioaque', - 'Basseterre', - 'Orangeburg', - 'Beelitz', - 'Jula Buzarg', - 'Palos Verdes Estates', - 'Yakage', - 'Muriedas', - 'Arsali', - 'Bichkunda', - "Shin'onsen", - 'Blegny', - 'Lariano', - 'Morangis', - 'Yamato', - 'El Kansera', - 'Kathevaram', - 'Khiria', - 'San Martino di Lupari', - 'Dorado', - 'Walsall Wood', - 'Ambohidronono', - 'Bondada', - 'Chulumani', - 'Beyla', - 'Vaerlose', - 'Novellara', - 'Noceto', - 'Douar Sidi Laaroussi', - 'Xaafuun', - 'Camardi', - 'Benairia', - 'Tonakkal', - 'Guttal', - 'Kuressaare', - 'Trebur', - 'Ain Lechiakh', - 'Tempio Pausania', - 'Southwick', - 'Bombarral', - 'Chenggong', - 'Bundala', - 'Gmunden', - 'Nemours', - 'Hissaramuruvani', - 'Cheval', - 'Liedekerke', - 'Jobat', - 'Vila Pouca de Aguiar', - 'Carpinteria', - 'Ban Khlong', - 'Rio de Contas', - 'Villacidro', - 'Castelnuovo di Verona', - 'Marathalli', - 'Zayda', - 'Oncativo', - 'Parvomay', - 'Fraserburgh', - 'Puspokladany', - 'Cedar Grove', - 'Kingersheim', - 'Sovetskoe', - 'Auria', - 'Bischofsheim', - 'Hashikami', - 'Cariamanga', - 'Bagado', - 'Mouvaux', - 'Weddington', - 'Plaza Huincul', - 'Melilli', - 'Druskininkai', - 'Bou Arada', - 'Penamaluru', - 'La Llagosta', - 'Qal`eh Ganj', - 'Casale sul Sile', - 'Graulhet', - 'Lezajsk', - 'Medway', - 'Hajan', - 'Canals', - 'Santa Maria de Ipire', - 'Ceyu', - 'Samalsar', - 'Ridgefield Park', + 'Barleben', + 'Ashland', + 'Jirja', + 'Woodbridge', + 'Smithton', + 'Neustadt bei Coburg', + 'Hewitt', + 'Ulstein', + 'Nong Bua', + 'Piracanjuba', + 'New Mirpur', + 'Darabani', + 'Szolnok', + 'Nqutu', + 'Ii', + 'Glassmanor', + 'Eruvatti', + 'Magarao', + 'Sunam', + 'Sonaimukh', + 'Chapelle-lez-Herlaimont', + "Hai'an", + 'Blaricum', + 'El Marsa', + 'Jutiapa', + 'Cihanbeyli', + 'Bershad', + 'La Mujer', + 'Sompting', + 'Lomas de Sargentillo', + 'Guacui', + 'Mpwapwa', + 'Sanhe', + 'Kampong Trach', + 'Govindgarh', + 'Weilmunster', + 'Hopkinsville', + 'Xicotencatl', + 'Crikvenica', + 'Faizabad', + 'Dehgolan', + 'Changji', + 'Obita', + 'Ottobrunn', + 'Pak Phanang', + 'Dongta', + 'Guaduas', + 'Clarksville', + 'Luxembourg', + 'Kut-e `Abdollah', + 'Puerto Penasco', + 'Hebli', + 'Locust Grove', + 'Lappeenranta', + 'Kizilcasar', + 'Terenos', + 'Kamen', + 'Barra de Santo Antonio', + 'Saint-Servan-sur-Mer', + 'Pinto', + 'Beverly Hills', + 'Rouyn-Noranda', + 'Joaquim Pires', + 'Wichelen', + 'Saint-Medard-en-Jalles', + 'Dibrugarh', + 'Gouvieux', + 'Schriesheim', + 'Taliwang', + 'Prachuap Khiri Khan', + 'Salida', + 'Dahivel', + 'Tanjung Selor', + 'Tabio', + 'Ilampillai', + 'Acaxochitlan', + 'West Donegal', + 'Marosakoa', + 'Coahuitlan', + 'Valasske Mezirici', + 'Mengmeng', + 'Umm ar Rizam', + 'Altindag', + 'Lewisburg', + 'Kamifurano', + 'Pune', + 'Miami Springs', + 'San Sebastian de Yali', + 'Berwick', + 'Quixada', + 'Wujindian', + 'Jiadong', + 'Bagnan', + 'Puke', + 'Bogazliyan', + 'Sertaozinho', + 'Beiya', + 'Pragadavaram', + 'Alarobia Bemaha', + 'Lara', + 'Pyryatyn', + 'Kantabanji', + 'Kodusseri', + 'Meiningen', + 'Fontainebleau', + 'Panapur', + 'Ulaangom', + 'Bihpur', + 'Bodinayakkanur', + 'Lins', + 'Helsingor', + 'Maryanaj', + 'New Kru Town', + 'Mococa', + 'Bab Ezzouar', + 'Ghazaouet', + 'Pulaski', + 'Grenchen', + 'East Riverdale', + 'Bourne', + 'Maqat', + 'Oliveirinha', + 'Deltona', + 'Vermillion', + 'Chotala', + "Hong'an", + 'Houbu', + 'Furth', + 'Tchibanga', + 'Ishaka', + 'Namala Guimbala', + 'Aire-sur-la-Lys', + 'Shentang', + 'Guilford', + 'Oswaldtwistle', + 'Binga', + 'Birstall', + 'Kandukur', + 'Dunleary', + 'Majia', + 'Pamban', + 'Hata', + 'Mitchells Plain', + 'Blankenfelde', + 'Itoigawa', + 'Andriba', + 'Maghra', + 'Bugarama', + 'Urk', + 'Hoima', + 'Binbrook', + 'Manali', + 'Manevychi', + 'Gotzis', + 'Byala Slatina', + 'Capoocan', + 'Pepperell', + 'Ayr', + 'Saint-Jean-de-Braye', + 'Chungju', + 'Barobo', + 'Laamarna', + 'Mudichchur', + 'Madhyamgram', + 'Sefrou', + 'Haora', + 'Harlakhi', + 'Bremgarten', + 'Conselheiro Lafaiete', + 'Nanbei', + "'Ain Mabed", + 'Koper', + 'Knowle', + 'Cerkno', + 'Perai', + 'Baghin', + 'Colne', + 'Kingsborough', + 'Mahagaon', + 'Chengguan', + 'Santa Eugenia', + 'Yuli', + 'Bad Rothenfelde', + 'Chongqing', + 'Aviles', + 'Gokhulapur', + 'Lokapur', + 'Menfi', + 'Kisvarda', + 'Sungai Guntung', + 'Ambolidibe Atsinanana', + 'Oberkirch', + 'Poteau', + 'Raleigh', + 'Ulongue', + 'Floresta Azul', + 'Migori', + 'Veracruz', + 'Roubaix', + 'Mariscal Jose Felix Estigarribia', + 'Sint-Michielsgestel', + 'Gering', + 'Yanchep', + 'Hof', + 'Villa Regina', + 'South Amboy', + 'Songkhla', + 'Barwah', + 'Stourbridge', + 'Bodegraven', + 'New Windsor', + 'Kubadupuram', + 'Lagoa dos Gatos', + "Pa'in Chaf", + 'Allagadda', + 'Casilda', + 'Tarancon', + 'Adilabad', + 'Chakla Waini', + 'Sabadell', + 'Bekipay', + 'Tajimi', + 'Ciputat', + 'Oulad Khallouf', + 'Rajpur Kalan', + 'Ghadamis', + 'Nyaungdon', + 'Bimo', + 'Tena', + 'Kendall', + 'Muzaffarabad', + 'Tongren', + 'Vrbas', + 'Resende Costa', + 'Cherchell', + 'Namayingo', + 'Port Angeles', + 'Egersund', + 'Bhasaula Danapur', + 'Wavre', + 'Itariri', + 'Timbiras', + 'Mahajanga', + 'Lochearn', 'Vestby', - 'San Jeronimo', - 'Ban Chorakhe Samphan', - "'Ain Mouilah", - 'Villa Juarez', - 'Villa Sandino', - 'Mulungu do Morro', - 'Capaya', - 'Igrapiuna', - 'Mahao', - 'Matsushima', - 'Drochia', - 'South Glengarry', - 'Hulkoti', - 'Santa Maria Jalapa del Marques', - 'Tinglayan', - 'Caerfyrddin', - 'Pell City', - 'Nako', - 'Rio do Antonio', - 'Autun', - 'Ban Nong Hoi', - 'Singuilucan', - 'Glucholazy', + 'Kulgo', + 'Mola di Bari', + 'Istrana', + 'Shangtianba', + 'Aue', + 'Kirchzarten', + 'Lanling', + 'Tuneri', + 'Montrouge', + 'Taslicay', + 'Choro', + 'Schio', + 'Diadema', + 'Rosstal', + 'Taohongpozhen', + 'Nueva Guadalupe', + 'Tacoma', + 'Mayyanad', + 'Botou', + 'Alfonso', + 'Bexley', + 'Marginea', + 'Alliance', + 'Davuluru', + 'Candiac', + "Hammam M'Bails", + 'Corridonia', + 'Jaguarari', + 'Bouati Mahmoud', + 'Topeka', + 'Honiton', + 'Sambalpur', + 'Kalamner', + 'Tulua', + 'Baesweiler', + 'Chatra Gobraura', + 'Swanage', + 'Santa Magdalena', + 'Marrero', + 'Mizunami', + 'Bickley', + 'Ocala', + 'Dera Baba Nanak', + 'Reda', + 'Bourem Guindou', + 'Tagum', + 'Talata Ampano', + 'Poninguinim', + 'Bad Urach', + 'Alterosa', + 'Lake Hiawatha', + 'Rhosllanerchrugog', + 'Zirapur', + 'Bakixanov', + 'Scottburgh', + 'Laubach', + 'Bhakkar', + 'Bath', + 'Iztapa', + 'Kaabong', + 'Haiku-Pauwela', + 'Walthamstow', + 'Leiyang', + 'Silverton', + 'Hangzhou', + 'Namminikara', + 'Badr', + 'Ban Bang Rin', + 'Skydra', + 'Changting', + 'Bou Nouh', + 'Villorba', + 'Conceicao de Macabu', + 'Haldipur', + 'Chavakkad', + 'Artondale', + 'Isla Raton', + 'Taiyur', + 'Mel Bhuvanagiri', + 'Faratsiho', + 'Piso Firme', + 'Venlo', + 'Nules', + 'San Gaspar Ixchil', + 'London Colney', + 'Hesarghatta', + 'Gingee', + 'Shahpura', + 'Bhikhi', + 'Kamenice', + 'Amesbury', + 'Hanoi', + 'Davenport', + 'Bishunpur Sundar', + 'Oggiono', + 'Beinan', + 'Tsimasham', + 'Campos', + 'Chaponost', + 'Amondara', + 'Pariyari', + 'Brusque', + 'Coquimbo', + 'Promissao', + 'Malakoff', + 'Yunxian Chengguanzhen', + 'Baiao', + 'Tremelo', + 'Sesto Calende', + 'Pozega', + 'Liepaja', + 'Lonigo', + 'San Leonardo', + 'Gonabad', + 'Valdemoro', + 'Sikandra', + 'Vise', + 'Rybnik', + 'Hit', + 'Rosu', + 'Fengrenxu', + 'Barrie', + 'Adjud', + 'Manta', + 'Susuz', + 'Junin', + 'Lauda-Konigshofen', + 'Rocas de Santo Domingo', + 'Barjhar', + 'Kurdamir', + 'Prabumulih', + 'Miyazaki', + 'Menzel Kamel', + 'Micco', + 'Sankt Leon-Rot', + 'De Pinte', 'Chanaral', - 'Vigodarzere', - 'Alovera', - 'Balya', - 'Hamworthy', - 'Bajala', - 'Asjen', - 'Mutterstadt', - 'Crispiano', - 'Balsta', - 'Radomir', - 'Kaua Kol', - 'Sainte-Marie', - 'Novi Becej', - 'Latisana', - 'Bom Principio', - 'Shinile', - 'Gothva', - 'South Daytona', - 'Bensekrane', - 'North Perth', - 'Monteux', - 'Sarezzo', - 'Ketsch', - 'Qulan', - 'Kofele', - 'Tetari', - 'Saktipur', - 'Ksibet el Mediouni', - 'Ba Chuc', - 'Sankt Georgen im Schwarzwald', - 'Satoraljaujhely', - 'Ayodhyapattanam', - 'Plattling', - 'Cicuco', - 'Chino Valley', - 'Berkeley Heights', - 'Sidmant al Jabal', - 'General Enrique Mosconi', - 'Brieselang', - 'Giporlos', - "Alvorada D'Oeste", - 'Silago', - 'Koregaon', - 'Mahaboboka', - 'Maqsuda', - 'Tubmanburg', - 'Iraci', - 'Wehr', - 'Betatao', - 'Treuchtlingen', - 'Toura', - 'Rosbach vor der Hohe', - 'Brig-Glis', - 'Quattro Castella', - 'Phalaborwa', - 'Sargur', - 'Shitab Diara', - 'Kanabur', - 'Gland', - 'Wantage', - 'Rajupalem', + 'Abiko', + 'Carlos A. Carrillo', + 'Sarande', + 'Matoes', + 'Cholchol', + 'Gangarampur', + 'Aihua', + 'Yanggao', + 'Portalegre', + 'Falea', + 'Qapqal', + 'Gotenba', + 'Villanueva del Pardillo', + 'Boysun', + 'Bundu', + 'Jucas', + 'Abony', + 'Bahabad', + 'Paradarami', + 'Eerbeek', + 'Nyon', + 'Shannon', + 'Barreirinhas', + 'Manompana', + 'Fron', + 'Nathdwara', + 'Ganassi', + 'Korntal-Munchingen', + 'Tessenderlo', + 'Prescott', + 'Chivilcoy', + 'Juina', + 'Primero de Enero', + 'Campiglia Marittima', + 'Bharra', + 'Naju', + 'Halls Creek', + 'Sakawa', + 'Ain Temouchent', + 'Caimanera', + 'Mahao', + 'Zacatelco', + 'Perumuchchi', + 'Aberdeen', + 'Dentsville', + 'Lincoln Village', + 'Bou Hadjar', + 'Retiro', + 'Ouaouzgane', + 'Balrampur', + 'Iznik', + 'Coatepeque', + 'Dicle', + 'Phon', + 'Sanpaicun', + 'Zgornja Kungota', + 'Coulommiers', + 'Woodhaven', + 'Pirai', + 'Marana', + 'Benjamin Constant', + 'Kimpese', + 'Kashiba', + 'Vandithavalam', + 'Ar Ruseris', + 'Fusui', + 'Aalten', + 'Hiranai', + 'Kigumba', + 'Ocosingo', + 'Kotabommali', + 'Sugar Hill', + 'Covington', + 'Mielec', + 'Totness', + 'Ribeirao Preto', + 'Caotun', + 'Salaiya', + 'Karapurcek', + 'Hornchurch', + 'Hlyboka', + 'Azizpur Chande', + 'Sokhodewara', + 'Brus', + 'Dilovasi', + 'Manjathala', + 'Sabbah', + 'Sadiola', + 'Lomita', + 'Aveiro', + 'Kittur', + 'Rajpur', + 'Betsukai', + 'Shintomi', + 'Tahara', + 'Vuliyattara', + 'El Kelaa des Srarhna', + 'Gammarth', + "Sal'a", + 'Kolin', + 'Ceel Dheere', + 'Magpet', + 'Tarhzirt', + 'Chateauguay', + 'Qovlar', + 'Gryfice', + 'Bokakhat', + 'Terrace', + 'Acajutiba', + 'Tefam', + 'Wolow', + 'Kuaidamao', + 'Punnayur', + 'Maliana', + 'Ouando', + 'Howell', + 'Kodarma', + 'Gines', + 'Douglas', + 'Werve', + 'Corfe Mullen', + 'Rayon', + 'Tequila', + 'Kozani', + 'Rafina', + 'Placido de Castro', + 'Mascara', + 'Pszczyna', + 'Hochheim am Main', + 'Babahoyo', + 'Tanglou', + 'Villagarcia de Arosa', + 'Sao Romao', + 'Izmir', + 'Kabwe', + 'Wulan', + 'Lake Charles', + 'Babhantoli', + 'Villaviciosa', + 'Doljevac', + 'Achchippatti', + 'Parasbani', + 'Agadez', + 'Yalluru', + 'Saumur', + 'Ambodiriana', + 'Panda', + 'Jadupatti', + 'Santo Domingo Este', + 'Manakambahiny', + 'Hajduhadhaz', + 'Kitamilo', + 'Shenwan', + 'Madattukkulam', + 'La Romana', + 'Glasgow', + 'Aars', + 'Niquelandia', + 'South Farmingdale', + 'Mangalia', + 'Kualaserba', + 'Flandes', + 'Veroli', + 'Ixtapan de la Sal', + 'Makarska', + 'Lakho', + 'Dhanur Kalyanwadi', + 'Castillo', + 'Jamui', + 'Mutyalapalle', + 'Karaikkudi', + 'Gogounou', + 'Kurumbapalaiyam', + 'Myrne', + 'Maroamalona', + 'Collado-Villalba', + 'Sikandarpur', + 'Olonne-sur-Mer', + 'Cambundi Catembo', + 'Vohimasina', + 'Chenango', + 'Muara Teweh', + 'Las Matas de Farfan', + 'Livermore', + 'West Columbia', + 'Anqiu', + 'Mumbai', + 'Ogijares', + 'Bethesda', + 'Wyndham', + 'Lake Shore', + 'Yuchi', + 'Jalandhar Cantonment', + 'Manevy', + 'Sao Jose do Rio Pardo', + 'Chimoio', + 'Dagami', + 'Sagarejo', + "Lin'an", + 'Gobardhanpur Kanap', + 'Apple Valley', + 'Allauch', + 'Villafranca di Verona', + 'Yulin', + 'Herbolzheim', + 'Dolton', + 'Terebovlya', + 'Sri Madhopur', + 'Benifayo', + 'Valambur', + 'Sendrisoa', + 'Ranipur', + 'Media Luna', + 'Ocna Mures', + 'Kulundu', + 'Damdama', + 'Milagros', + 'Smithfield', + 'Lake Butler', + 'Ciudad Barrios', + 'Escuintla', + 'Cherry Hinton', + 'Solonytsivka', + 'Ribeirao Claro', + 'Balussheri', + 'Nanjikkottai', + 'Asela', + 'Martos', + 'Canto do Buriti', + 'Samalut', + 'Dhuburi', + 'Maltahohe', + 'Horst', + 'Bafang', + 'La Blanca', + 'Seraing', + 'Hedensted', + 'Chala', + 'Bou Salem', + 'Boralday', + 'Marktredwitz', + 'Neuenrade', + 'Muddada', + 'Serrinha', + 'Horizon West', + 'Machalpur', + 'Pathra', + 'Nelspruit', + 'Rankhandi', + 'Gaoniang', + 'Ohrid', + 'Conguaco', + 'Taylors', + 'Aqadyr', + 'Kirkop', + 'El Golea', + 'Slupsk', + 'Sawran', + 'Ansan', + 'Villa Dominico', + 'Kambia', + 'Sainte-Genevieve-des-Bois', + 'An Nuhud', + 'Samarkand', + 'Ringsaker', + 'Blangmangat', + 'Nuenen', + 'North Aurora', + 'Hoek van Holland', + 'Santa Cruz Cabralia', + 'Suvalan', + 'Phra Pradaeng', + 'Arnedo', + 'Pagsanjan', + 'Pietermaritzburg', + 'Weissenthurm', + 'Pebberu', + 'Kangazha', + 'Ancona', + 'Bou Noura', + 'Owensboro', + 'Catalina Foothills', + 'Alegre', + 'Douar Imoukkane', + 'Tirkadavur', + 'Washington Court House', + 'Colmenar Viejo', + 'Baikunthpur', + 'Sitrah', + 'Presidente Janio Quadros', + 'St. Louis Park', + 'Kempten', + 'Dergaon', + 'Pannaipuram', + 'Gifu', + 'Toul', + 'Sirakorola', + 'Vaals', + 'Barranca', + 'Elgoibar', + 'Kasamatsucho', + 'Ampitahana', + 'Totowa', + 'Mocoa', + 'Beni Slimane', + 'Bethany', + 'Ramdiri', + 'Bariadi', + 'Cofradia', + 'Tandil', + 'Bolton', + 'Sirat', + 'Uspenka', + 'Capim Branco', + 'Ozumba', + 'Dighawani', + 'Keonjhargarh', + 'Makurazaki', + 'Sada', + 'Sarmin', + 'Yamkanmardi', + 'Zhujiezhen', + 'Brampton', + 'Nynashamn', + 'Dawson Creek', + 'Analalava', + 'Dobrovnik', + 'Puxi', + 'Beni Tamou', + 'Damargidda', + 'San Casciano in Val di Pesa', + 'Springdale', + 'Luque', + 'Zara', + 'Dakit', + 'Urena', + 'Naduhatti', + 'General Jose de San Martin', + 'Raia', + 'Bhuj', + 'Tisnov', + 'Tekkekoy', + 'Faridpur', + 'Sao Vicente', + 'Bad Salzuflen', + 'Itororo', + 'Petersberg', + 'Castelsarrasin', + 'Madiama', + 'Voluntari', + 'Butaleja', + 'Carandai', + 'Arusha', + 'Strumica', + 'Quijingue', + 'Banovce nad Bebravou', + 'Huaibei', + 'Siswa', + 'Ansiao', + 'Baisa', + 'Kozuchow', + 'Mions', + 'Kenema', + 'Rajaudha', + 'Onga', + 'City of Calamba', + 'Buli', + 'Lokhvytsya', + 'Chak Thathi', + 'Qasr-e Qomsheh', + 'Wilson', + 'Tarawa', + 'Libjo', + 'Batocina', + 'Tajpur', + 'Kanyakulam', + 'Manzhouli', + 'Bougaa', + 'Kitzingen', + 'Fenoughil', + 'Dhanera', + 'Dhorgaon', + 'Abohar', + 'Zug', + 'Ghaura', + 'Aparecida do Taboado', + 'Zapotlanejo', + 'Natanz', + 'Guarda', + 'Chengara', + 'Tup', + 'Livani', + 'Sirsia Hanumanganj', + 'Qal`at al Madiq', + 'Tamarac', + 'South Miami', + 'Thung Sai', + 'Grodzisk Wielkopolski', + 'Jiutepec', + 'Nautanwa', + 'Grenada', + 'Nandod', + 'Helotes', + 'Nang Rong', + 'Makiivka', + 'Paxtaobod', + 'Susaki', + 'Fuso', + 'Tsawwassen', + 'Villeurbanne', + 'Ternopil', + 'Pandaul', + 'Nardo', + 'Puerto Aysen', + 'Marvdasht', + 'Funafuti', + 'Siraway', + 'El Milagro', + 'Dinapore', + 'Conisbrough', + 'Ban Duea', + 'Kawm Umbu', + 'Derhachi', + 'Setubinha', + 'Assis', + 'Shikarpur', + 'Hukumati Baghran', + 'Manuel Urbano', + 'Penacova', + 'Mishawaka', + 'Kremenchuk', + 'Salzkotten', + 'Sakai', + 'Ostercappeln', + 'Sebikhotane', + 'Mahatalaky', + 'Recanati', + 'Sainte-Foy-les-Lyon', + 'Hengshan', + 'Antonio Enes', + 'Adivala', + 'Odaipatti', + 'Aginiparru', + 'Sao Goncalo dos Campos', + 'Sagaing', + 'Anjad', + 'Jevargi', + 'Bastia', + 'General Tinio', + 'Kailua', + 'Fukutsu', + 'Nogata', + 'Park Forest', + 'Lolokhur', + 'Moengo', + 'Hermosillo', + 'Greencastle', + 'Pittsburgh', + 'Luuq', + 'Toluca', + 'Satgachia', + 'Nova Varos', + 'Tetovo', + 'Empalme', + 'Cherryland', + 'Ka-Bungeni', + 'Fernandopolis', + 'Oita', + 'Walnut', + 'Dalian', + 'Viersen', + 'Jyvaskylan Maalaiskunta', + 'Warragul', + 'Malaikkal', + 'Loule', + 'Honolulu', + 'Azalea Park', + 'Samba Cango', + 'Boblingen', + 'Istmina', + 'Southend', + 'Kallithea', + 'Khiria', + 'Huaral', + 'Mendota', + 'Upper Buchanan', + 'Damietta', + 'Porto Empedocle', + 'Santo Antonio do Ica', + 'Nunungan', + 'Naysar', + 'Pico Rivera', + 'Riano', + 'Snodland', + 'Sangre Grande', + 'Sun City', + 'Naunhof', + 'Fisciano', + 'Vedene', + 'Khawad', + 'Vernon', + 'Ahiro', + 'Chidambaram', + 'Chacabuco', + 'Elsdorf', + 'Chuhal', + 'Djelfa', + 'Qiryat Shemona', + 'Altamirano', + 'Cubellas', + 'Allonnes', + 'Aracaju', + 'Novi Knezevac', + 'Ikalamavony', + 'Staunton', + 'Mpophomeni', + 'Manombo Atsimo', + 'Madinat Hamad', + 'Guntramsdorf', + 'Elchuru', + 'Dongyang', + 'Gardony', + 'Taro', + 'Tablat', + 'Garulia', + 'Gopichettipalaiyam', + 'Raibari Mahuawa', + 'Tibba', + 'Taoyuan District', + 'Manavadar', + 'San Pedro Garza Garcia', + 'Amuntai', + 'Damua', + 'Desio', + 'Tomboutou', + 'Parlier', + 'Modasa', + 'Ubud', + 'Makan', + 'Vieux-Conde', + 'Maranga', + 'Acobamba', + 'Rugby', + 'Paramirim', + 'Nirgua', + 'Alto Paraiso de Goias', + 'Bandar Lampung', + 'Koumaira', + 'Sebt Ait Ikkou', + 'Vavuniya', 'Grand Terrace', - 'Sao Domingos', - 'Tirumakudal Narsipur', - 'Pavona', - 'Mounds View', - 'Kozy', - 'Miranda do Corvo', - 'Mazatlan Villa de Flores', - 'Kavital', - 'Medapadu', - 'Lake Los Angeles', - 'La Grande', - 'Barsbuttel', - 'San Martin Zapotitlan', - 'Kottaram', - 'Mercedes Umana', - 'Chos Malal', - 'Albatera', - 'Wollaston', - 'North Palm Beach', - 'Guclukonak', - 'Soddy-Daisy', - 'Wolvega', - 'Joure', - 'Pomfret', - 'Itano', - 'Al Jumayliyah', - 'Tonosho', - 'Akseki', - 'Kussnacht', - 'San Antonio del Tequendama', - 'New Hanover', - 'Phra Samut Chedi', - 'Betanzos', - 'Darlowo', - 'Ionia', - 'Horst', - 'Andarai', - 'Caldeirao Grande', - 'Great Driffield', - 'Gex', - 'Gurlapeta', - 'Takkolam', - 'Cavdir', - 'Simijaca', - 'Chandhaus', - 'Udaipur Bithwar', - 'Kamikawa', - 'Peddavadlapudi', - 'Ekwari', - 'Huguan Nongchang', - 'Nasiyanur', - 'Hungen', - 'Motobu', - 'Oatfield', - 'Gouande', - 'Fannuj', - 'Cherry Hill Mall', - 'Darmanesti', - 'Apostolove', - 'Pendlebury', - 'Goodmayes', - 'Makabana', - 'Killai', - 'Scheessel', - 'Kalikiri', - 'Pallappalaiyam', - 'Cotegipe', - 'Jalhalli', - 'Dinbela', - 'Adi Keyh', - 'Milnrow', - 'Ribeirao do Pinhal', - 'Paina', - 'West Carrollton', - 'Kuruman', - 'Hajduhadhaz', - 'Balua', - 'Mohgaon', - 'Kafr `Awan', - 'On Top of the World Designated Place', - 'Lamacaes', - 'Muri', + 'Surajgarha', + 'Pedro Velho', + 'Lanzhou', + 'Tieli', + 'Jadia', + 'Mapanas', + 'Nangan', + 'Glazoue', + 'Villa Literno', + 'Qianshanhong Nongchang', + 'Paso de Carrasco', + 'Calliaqua', + 'Watertown Town', + 'Tasgaon', + 'China', + 'Yoshinogari', + 'Warora', 'Castlebar', - 'Rabot', - 'Balatonfured', - 'Nidzica', - 'Alto Garcas', - 'Dom Feliciano', - 'Vetlanda', - 'Godella', - 'Gamboula', - 'Forlimpopoli', - 'Kani-Bonzon', - 'Alcacer do Sal', - 'Afanyangan', - 'Monte Belo', - 'Danga', - 'La Crucecita', - 'Turvo', - 'Pandireddigudem', - 'Hadamar', - 'Hawaiian Paradise Park', - 'Aberystwyth', - 'Drongen', - 'Rasauli', - 'Mettet', - 'Velykodolynske', - 'Dahu', - 'Charabidya', - 'Turbihal', - 'Olivar Bajo', - 'Olivar', - 'Rodental', - 'Tezontepec', - 'Stjordalshalsen', - 'Lowshan', - 'Shahr-e Herat', - 'Nova Gorica', - "Capo d'Orlando", - 'Ajas', - 'Fernandina Beach', - 'Darasuram', - 'Missoes', - 'Holborn', - 'San Pietro Vernotico', - 'Dayalpur Sapha', - 'Baraon', - 'Shin', - 'Bolongongo', - 'Neuri', - 'Dinshaway', - 'Brackley', - 'Ubaporanga', - 'Barah', - 'Candiba', - 'Tetiiv', - 'Linnich', - 'Leibnitz', - 'Peddakurapadu', - 'Gangoli', - 'Bohmte', - 'Kalaiyamputtur', - 'Belpukur', - 'Forrest City', - 'Ampanavoana', - 'Thara', - 'Montgomeryville', - 'Chandauli', - 'Sidhwan', - 'Kaji', - 'Wasserburg am Inn', - 'Lawaan', - 'Quzanli', - 'Webb City', - 'Kahhale', - 'Ambararata', - 'Marovandrika', - 'Andreba', - 'Ampitasimo', - 'Ambohimahavelona', - 'Isaka-Ivondro', - 'Ambodiampana', - 'Andranomamy', - 'Ihorombe', - 'Antongomena-Bevary', - 'Antsirabe Afovoany', - 'Sahavalanina-Antenina', - 'Belemoka', - 'Mavorano', - 'Evato', - 'Tranovaho', - 'Amborompotsy', - 'Ambalakindresy', - 'Ambahoabe', - 'Vohitrindry', - 'Befandriana', - 'Ampanefena', - 'Ankilivalo', - 'Anjiajia', - 'Ambatondrakalavao', - 'Kirano', - 'Sakoabe', - 'Maroviro', - 'Ambakireny', - 'Tsiately', - 'Ambohitsilaozana', - 'Ambazoa', - 'Ambodisakoana', - 'Bemanevika', - 'Ambondrona', - 'Bejofo', - 'Manambolo', - 'Mangindrano', - 'Ankilimalinika', - 'Sandrakatsy', + 'Hezhou', + 'Tijuana', + 'Vilachcheri', + 'Tama', + 'Stony Brook', + 'Puurs', + 'Dam Dam', + 'Muktsar', + 'Wishaw', + 'Clay', + 'Hattula', 'Marojala', - 'Ilafy', - 'Morarano', + 'Aguas Belas', + 'Ogano', + 'Kattagaram', + 'Sulakyurt', + 'Mariveles', + 'Kavala', + 'Leavenworth', + 'Ambohitsimanova', + 'Lingsugur', + 'Delicias', + 'Xihuachi', + 'Kukarmunda', + 'Saruu', + 'Lwengo', + 'Bokod', + 'Andraitx', + 'Polanco', + 'Willowbrook', + 'Peddapalle', + 'Doddipatla', + 'Basco', + 'Bhimavaram', + 'Timoktene', + 'Tizi', + 'Mettet', + 'Matadi', + 'Xiaotangzhuang', + 'Guna', + 'Villaricca', + 'Pfedelbach', + 'Barud', + 'San Antonio del Monte', + 'Advi Devalpalli', + 'Nowy Dwor Gdanski', + 'Hsinchu', + 'Bad Kreuznach', + 'Pasaje', + 'Miluo Chengguanzhen', + 'Puyang Chengguanzhen', + 'Vasto', + 'Abarkuh', + 'West Plains', + 'Carazinho', + 'Vedi', + 'Port Maria', + 'Karratha', + 'Fes', + 'Ghulakandoz', + 'Porto Acre', + 'Jinzhong', + 'Thyolo', + 'Dien Bien Phu', + 'Panniyannur', + 'Banbhag', + 'Saint-Lambert', + 'Bhoj', + 'Salug', + 'Sobraon', + 'Reigate', + 'Colts Neck', + 'Salcaja', + 'Liesti', + 'Tianyingcun', + 'Maia', 'Befeta', - 'Amboaboa', - 'Manambidala', - 'Andohajango', - 'Harmah', - 'Sunne', - 'Alaverdi', - 'Midsomer Norton', - 'Galashiels', - 'Jalam', - 'Ghoradongri', - 'Moviya', - 'Amauna', - 'Dammennu', - 'Timberlake', - 'Lavello', - 'Bhalil', - 'Ksar Sghir', - 'Vieira do Minho', - 'Bocas del Toro', - 'Jennings', - 'Manalalondo', - 'Sebt Bni Garfett', - 'Anandapuram', - 'Waconia', - 'Gornalwood', - 'Lohiyar Ujain', - 'Ficarazzi', - 'Baduriatola', - 'Kottapadi', - 'Kara-Kyshtak', - 'Chhara', - 'Chawalhati', - 'Nacozari de Garcia', - 'Noyon', - 'Ridge', - 'West Monroe', - 'Korneuburg', - 'Steinkjer', - 'Paso de los Toros', - 'Zandhoven', - 'Sai Wan Ho', - 'Kibiito', - 'Ivanic-Grad', - 'Kollipara', - 'Vrbovec', - 'Bisee', - 'Cha da Alegria', - 'Antonio Prado', - 'Yiewsley', - 'Chang', - 'Schleiden', - 'Hoor', - 'Jianganj', - 'San Lucas', - 'Kanel', - 'Fouriesburg', - 'Pretoria-Noord', + 'Ina', + 'Sutherlin', + 'Saint-Brice-sous-Foret', + 'St. Louis', + 'Bistaria', + 'Nixa', + 'Boqueirao', + 'Khimlasa', + 'Munai', + 'Encinitas', + 'Citlaltepec', + 'Tokigawa', + 'Kalloni', + 'Sachse', + 'Huckeswagen', + 'Meric', + 'Ilkal', + 'Bawana', + 'Greetland', + 'Alcazar de San Juan', + 'Soltau', + 'Wahiawa', + 'Mogogelo', + 'Villerupt', + 'Carqueiranne', + 'Morohongo', + 'Hervey Bay', + 'Lakhna', + 'Mardin', + 'Lidingo', + 'Dar Chioukh', + 'Juncos', + 'Alliston', + 'Ilorin', + 'Arita', + 'Skara', + 'Progress Village', + 'Savelugu', + 'Khirpai', + 'Kamalnagar', + 'Mount Holly', + 'Vreed-en-Hoop', + 'Akcakale', + 'Vence', + 'Kurawar', + 'Seoul', + 'Novi Grad', + 'Kudamatsu', + 'Colina', + 'Kottagudem', + 'Tankal', + 'Kazarman', + 'East Orange', + 'Mulanur', + 'Sfizef', + 'Larvik', + 'Pawni', + 'San Juan de Vilasar', + 'Venmani', + 'Gentilly', + 'Picnic Point', + 'Beiwusidui', + 'Pakdasht', + 'Tatvan', + 'Ardmore', + 'Capela do Alto Alegre', + 'Rakai', + 'Yakouren', + 'Puerto Asis', + 'Shirali', + 'Adjumani', + 'Huite', + 'Indaiatuba', + 'Ouled Moussa', + 'Tamboril', + 'Kasimkota', + 'Iligan', + 'Stratton Saint Margaret', + 'Jiancheng', + 'Mungod', + 'Sremcica', + 'Sara', + 'Garrel', + 'Narela', + 'Meilan', + 'Martinsicuro', 'Culaba', - 'Roding', - 'Sitalpur', - 'Ben', - 'Turi', - 'Barwat Pasrain', - 'Bachra', - 'Senmayacho-senmaya', - 'Larkspur', - 'An Thanh B', - 'Wanderley', - 'Rovinj', - 'Chapantongo', - 'Casinhas', - 'Wickede', - 'Lingamparti', - 'Itatiaiucu', - 'Abaran', - 'Uppada', - 'Juan de Herrera', - 'Palangarai', - 'Mizil', - 'Shenley Church End', - 'Campo de Criptana', - 'Montesarchio', - 'Cardoso Moreira', - 'Kingsbury', - 'Shanyincun', - 'Wicklow', - 'Kudangulam', - 'Schodack', - 'Pingtiancun', - 'Jhaua', - 'Montefiascone', - 'Pucioasa', - 'Saposoa', - 'Mirdaul', - 'Bocsa', - 'Mulakaluru', - 'Wachtersbach', - 'Vinings', - 'Jaitpur', - 'Solana Beach', - 'Tartarugalzinho', - "Sant Sadurni d'Anoia", - 'Lakkavaram', - 'Carpenedolo', - 'Cherutana Tekku', - 'Brejoes', - 'Maktar', - 'Shiwan', - 'Saint-Andre', - 'Camponogara', - 'Elandsdoorn', - 'Bou Fekrane', - 'Nossa Senhora do Livramento', - 'Gibraleon', - 'Sakhmohan', - 'Grantsville', - 'Japoata', - 'Amboise', - 'Rampur Shamchand', - 'North Adams', - 'Matinilla', - 'Trebaseleghe', - 'Gomparou', - 'Morungaba', - "'Ain Tolba", - 'Bni Khloug', - 'Isalo', - 'Meadville', - 'Kachavaram', - 'Song Phi Nong', - 'Atmakuru', - 'Qal`at al Madiq', - 'Lynnfield', - 'Nova Londrina', - 'Fengdeng', - 'Byram', - "D'Iberville", - 'Paranhos', - 'Woolton', - 'Sint-Gillis-bij-Dendermonde', - 'Tarnos', - 'Amarwa Khurd', - 'Tezze sul Brenta', - 'Chamical', - 'Holly Hill', - 'Mockern', - 'Castiglion Fiorentino', - 'Bujari', - 'Berja', - 'Statte', - 'St. Ann', - 'Messadine', - 'Kalanaur', - 'Balbalan', - 'Odder', - 'Schinnen', - 'Anolaima', - 'Leagrave', - 'Besigheim', - 'Chateaudun', - 'Cusset', - 'Cesky Krumlov', - 'Quierschied', - 'Lahaina', - 'Barra de Santa Rosa', - 'Tashi', - 'Fostoria', - 'Karahal', - 'Dardenne Prairie', - 'Khomam', - 'Bijelo Polje', - 'Amolatar', - 'Kapchorwa', - 'Goonellabah', - 'Corat', - 'Mayenne', - 'Cliftonville', - 'Kankandighi', - 'Trent Hills', - 'Vellakkinar', - 'Tirmaigiri', - 'Cho Moi', - 'Rossdorf', - 'Gurgunta', - 'Sisauna', - 'Kalappalangulam', - 'Monteprandone', - 'Bonneville', - 'Yuza', - 'Petrus Steyn', - 'Wommelgem', - 'Apuiares', - 'Saghar Sultanpur', - 'Bagewadi', - 'Moreira', - 'Esneux', - 'Elavanasur', - 'Pentapadu Kasba', - 'Barja', - 'Mandra', - 'Kalavai', - 'Crissiumal', - 'Uzwil', - 'Ambalarondra', - 'Bronderslev', - 'Highlands', - 'Kapelle', - 'Sangao', - 'Ayutla', - 'Khombole', - 'Ringnod', - 'Edattirutti', - 'Daru', - 'Suzu', - 'Cidelandia', - 'Suamico', - 'Moorreesburg', - 'Nurkot', - 'Frutillar', - 'Koturkolkara', - 'Keisen', - 'Causeni', - 'Kalush', - 'Lontras', - 'Palombara Sabina', - 'Kuala Kurun', - 'Finneytown', - 'Alayaman', - 'Colares', - 'Puren', - 'Red Bank', - 'Agutaya', - 'Tanakkangulam', - 'Woodhaven', - 'Vejer de la Frontera', - 'Chilwell', - 'Vadnais Heights', - 'Wadersloh', - 'Trail', - 'Muggia', - 'Calcinato', - 'Akayu', - 'Porto Murtinho', - 'Mansapur', - 'Rehti', - 'Mulaikkaraippatti', - 'Lanuvio', - 'Dhutauli', - 'Tehachapi', - 'Ecublens', - 'Saint-Andre-de-Cubzac', - 'Chinnasekkadu', + 'Suez', + 'Villamaria', + 'Baytunya', + 'Oleshky', + 'Mogaung', + 'Twinsburg', + 'Casatenovo', + 'Sadda', + 'Shiyali', + 'Independencia', + 'Jinotepe', + 'Guilin', + 'Samal', + 'Gouda', + 'Tarui', + 'Sao Felipe', + 'Srivilliputtur', + 'Malmal', + 'Pembroke Dock', + 'Schwaikheim', + 'Beizhou', + 'Horw', + 'Gohi Bishunpur', + 'Taby', + 'Ramallo', + 'Woodcrest', + 'San Jacinto Amilpas', + 'Sundarsi', + 'Basildon', + 'Harasta', + 'Brislington', + 'Collingdale', + 'Brezice', + 'Xam Nua', + 'Ans', + 'Hardiya', + 'Linnich', + 'Varamin', + 'Asuncion Mita', + 'Dalgan', + 'Sahawar', + 'Jiutai', + 'Bruckmuhl', + 'Bingley', + 'Dundigal', + 'Somers', + 'Villas', + 'Ouro Branco', + 'Apora', + 'Miduturu', + 'Manambolosy', + 'Wuchuan', + 'Kasumbalesa', + 'Brent', + 'Balma', + 'Beidou', + 'Farim', + 'Dagmara', + 'Bijaipur', + 'Karera', + 'Amersfoort', + 'Gold', + 'Patilar', + 'Tweed Heads', + 'San Quintin', + 'Saloa', + 'Ruiming', + 'Sarayan', + 'Silver Springs Shores', + 'Vakon', + 'Ingenbohl', + 'Chetma', + 'Blacksburg', + 'Pondokaren', + 'Queimadas', + 'Encantado', + 'Tsubata', + 'Mers el Hadjad', + 'Northglenn', + 'Genc', + 'Lohiyar Ujain', + 'Ruoqiang', + 'Madera', + 'Santana do Cariri', + 'Ramamangalam', + 'Bangawan', + 'Emirdag', + 'Santa Fe Springs', + 'Cabucgayan', + 'Beaver Falls', + 'Cypress', + 'Glanmire', + 'Ipua', + 'Jaca', + 'Pueblo Viejo', + 'Kashiwa', + 'Dos Hermanas', + 'Ras Tanura', + 'Sidi Abdellah Ben Taazizt', + 'Badger', + 'Velingrad', + 'Velsen-Zuid', + 'Iscuande', + 'Ziro', + 'Charneca', + 'Tourlaville', + 'Loma Linda', + 'Sevran', + 'Eraniel', + 'Trece Martires City', + 'Franceville', + 'Coari', + 'Khairabad', + 'Bunhe', + 'Taguatinga', + 'Gilan-e Gharb', + 'Nyborg', + 'Kawagoe', + 'Pinheiral', + 'Bavaro', + 'Lisse', + 'Shuilou', + 'Paraty', + 'San Pedro Huamelula', + 'Bamber Bridge', + 'Port Huron', + 'Quba', + 'Ajacuba', + 'Lambarene', + 'Sikandarabad', + 'Chornobaivka', + 'Dores de Campos', + 'Wakoro', + 'Palomares del Rio', + 'Ankola', + 'Chibia', + 'Birmingham', + 'Antrim', + 'Kingsport', + 'Rockledge', + 'Carrillos', + 'Irig', + 'Denekamp', + 'Oberhaching', + 'Tisma', + 'Uriangato', + 'Tori-Cada', + 'Wolomin', + 'Montignies-le-Tilleul', + 'Des Moines', + 'Angeles City', + 'Morinville', + 'Zunyi', + 'Port Blair', 'Daparkha', - 'Nuevo Ideal', - 'Malaryta', - 'Balao', - 'Abrera', - 'Saunshi', - 'Cheney', - 'Argentona', - 'Vedappatti', - 'Niandjila', - 'Zhongling', - 'Palmares do Sul', - 'Rahika', + 'Petrosani', + 'Lewes', + 'Douar Souk L`qolla', + 'Siaton', + 'Beyne-Heusay', + 'Padang', + 'Nova Kakhovka', + 'Assare', + 'Garh Sisai', + 'Ulster', + 'Magny-les-Hameaux', + 'Vallieres', + 'Garagoa', + 'Sungurlu', + 'Gadaul', + 'Taraclia', + 'Aden', + 'Grand Bourg', + 'Sao Francisco do Guapore', + 'Meruoca', + 'Oud-Beijerland', + 'Nitra', + 'Capoterra', + 'Tasikmalaya', + 'Cuevo', + 'Fruit Cove', + 'Le Teil', + 'Beur', + 'Bouskene', + 'Saint-Pierre', + 'Palitana', + 'Bourkika', + 'Jiquilisco', + 'Hassa', + 'Ixtapaluca', + 'Velyka Dymerka', + 'Kampli', + 'Caetano', + 'Luis Antonio', + 'Horgen', + 'Nalatvad', + 'Quime', + 'Betsiboka', + 'Rancheria Payau', + 'Dongxing', + 'Panagyurishte', + 'Soure', + 'Sinalunga', + 'Bhopatpur', + 'Tottington', + 'Zogno', + 'Alpinopolis', + 'Ibirite', + 'Talusan', + 'Mae Wang', + 'Prato', + 'Barvynkove', + 'Altavilla Vicentina', + 'Mussomeli', + 'Hilchenbach', + 'Agueda', + 'Botupora', + 'San Fernando', + 'Gallarate', + 'Balombo', + 'Philipsburg', + 'Oulad Aissa', + 'Brazzaville', + 'Tissaf', + 'Sanniquellie', + 'Zeist', + 'Turgutlu', + 'Ashikaga', + 'Seclin', + 'Actopan', + 'Accra', + 'Destelbergen', + 'Paiker', + 'Iowa Colony', + 'Muvattupula', + 'Springe', + 'Coqueiral', + 'Gmunden', + 'Perry Barr', + 'Cuneo', + 'Masur', + 'Calimera', + 'Diang', + 'Nacozari Viejo', + 'Jurmala', + 'Tsarasaotra', + 'Chon Thanh', + 'Dandenong', + 'Zutphen', + 'Bunawan', + 'Kottaram', + 'Majhgawan', + 'Macedonia', + 'Totogalpa', + 'Grand Junction', 'Medfield', - 'Aldoar', - 'Bihariganj', - 'Sidlice', - 'Acasusso', - 'Sugauna', - 'Meric', - 'Florida City', - 'Dedemsvaart', - 'Gueret', - 'Emeryville', - 'Lansdowne', - 'Auriol', - 'Cavallino', - 'Kallad', - 'Fuldatal', - 'Janai', - 'Meddappakkam', - 'Puerto Jimenez', - 'Bloomsburg', - 'Seclin', - 'San Pietro in Casale', - 'Terrasini Favarotta', - 'Santa Rosa de Calamuchita', - 'Kadachchinallur', + 'Tolcayuca', + 'Santiago del Estero', + 'Ibague', + 'Caucaia', 'Quartucciu', - 'Herzberg am Harz', - 'Sattar', - 'Barhauna', - 'Oxapampa', - 'Kaul', - 'Palacaguina', - 'San Juan Tecuaco', - 'Spilamberto', - 'Canelinha', - 'Raymond Terrace', - 'Mullassheri', - 'Nieuw Nickerie', - 'Salempur', - 'Fontanafredda', - 'Sugarland Run', - 'Juan L. Lacaze', - 'Tega Cay', - 'Nova Crixas', - 'Frederiksvaerk', - 'Santa Cruz Amilpas', - "M'dhilla", - 'Leopold', - 'Arakere', - 'Castellbisbal', - 'Antonivka', - 'Bad Urach', - 'Ganga', - 'Spiez', - 'Qazmalar', - 'The Nation / La Nation', - 'Bolintin Vale', - 'Nova Timboteua', - 'Ziro', - 'Bela Simri', - 'Bhagwanpur Khurd', - 'Douar Oulad Youssef', - 'Brenes', - 'Syston', - 'Little Lever', - 'Chiatura', - 'Venkatagirikota', - 'Rosario del Tala', - 'Bazidpur', - 'Ban Krang', - 'Bag`dod', - 'Yozyovon', - 'Santo Tomas La Union', - 'Govindgarh', - 'Yelmalla', - 'Rose Belle', - 'General Las Heras', - 'Teror', - 'Salzano', - 'Kachchippalli', - 'Spiesen-Elversberg', - 'Chinnakkampalaiyam', - 'Milngavie', - 'Tucson Estates', - 'Kalecik', - 'Arohi', - 'Overlea', - 'Toukoroba', - 'Kurwa Mathia', - 'Springbok', - 'Lokapur', - 'Florham Park', - 'Kyotera', - 'Rio Casca', - 'Santa Maria do Suacui', - 'Rampurwa', - 'Concepcion de Ataco', - 'Hulyaypole', - 'Mallapur', - 'Yavoriv', - 'Mesolongi', - 'Kasba Tanora', - 'Santa Ana de Yacuma', - 'Juvignac', - 'Aghbala', - 'Franeker', - 'Peissenberg', - 'Jasauli', - 'Oudenbosch', - 'Twistringen', - 'Kannudaiyampatti', - 'Sanderstead', - 'Kanbara', - 'Pichilemu', - 'Ocos', - 'Saint-Andre-les-Vergers', - 'Ashibetsu', - 'Tizgane', - 'Donwari', - 'Nangavalli', - 'Landeh', - 'Festus', - 'Velilla de San Antonio', - 'Chojnow', - 'Loyish Shaharchasi', - 'Gavere', - 'Lagoa Dourada', - 'Sorum', - 'Harpur Bochaha', - 'Nandyalampeta', - 'Huazalingo', - 'Chalfont Saint Peter', - 'Magdalena Milpas Altas', - 'Brzeg Dolny', - 'Agdangan', - 'Novo Lino', - 'Kaufungen', - 'Zag', - 'Perehinske', - 'San Anselmo', - 'Ban Tat', - 'Dhubaria', - 'Chahatpur', - 'Sedriano', - 'Sarahandrano', - 'Rodeio', - 'Bariyarpur', - 'Maheswa', - "Granarolo del l'Emilia", - 'Grover Beach', - 'Anaikal', - 'Antanandava', - 'Valbonne', - 'Big Bear City', - 'Casteel', - 'Kaeng Khoi', - 'Villa San Giovanni', - 'Kouti', - 'Vadasseri', - 'Nawada Gobindganj', - 'Barud', - 'Kolappalur', - 'Roudnice nad Labem', - 'Serra Azul', - 'Kamrej', - 'Maroli', - 'Eufaula', - 'Accokeek', - 'Rokupr', - 'Keerbergen', - 'Guymon', - 'Wietmarschen', - 'Begampur', - 'Ilicinia', - 'Dharampur Bande', - 'Cavarzere', - 'Terrabona', - 'Ban Sop Tia', - 'Bahadurpur', - 'Kochlowice', - 'Majarhat', - 'Chinna Gollapalem', - 'Calcinaia', - 'Mahabaleshwar', - 'Sebiston', - 'Vilanova del Cami', - 'Bandlaguda', - 'Chodov', - 'At Tur', - 'Jami', - 'Almirante', - 'Gartringen', - 'Koprubasi', - 'Sete Barras', - 'Chalette-sur-Loing', - 'Duvvuru', - 'Joanopolis', - 'Les Ponts-de-Ce', - 'Obalapuram', - 'Sulz am Neckar', - 'Canilla', - 'Ainsdale', - 'Ivanec', - 'Mar de Espanha', - 'Richton Park', - 'Oulad Rahmoun', - 'Khorol', - 'Brus Laguna', - 'Emmiganuru', - 'San Francisco de Mostazal', - 'Laamarna', - 'Debbache el Hadj Douadi', - 'San Antonio Aguas Calientes', - 'Bakhtawarpur', - 'Mahtha', - 'Kirchheim bei Munchen', - 'Varzaneh', - 'Kyotamba', - 'Pirnagar', - 'Annapolis Neck', - 'Hvardiiske', - 'Chaiyo', - 'Krupka', - 'Playa Grande', - 'Damarcherla', - 'Seiada', - 'Kaspi', - 'Sao Felix da Marinha', - 'Pennsville', - 'Sivalarkulam', - 'Madugula', - 'Buffelshoek', - 'Miranorte', - 'Nirakpurpali', - 'Serere', - 'Honggu', - 'Lymm', - 'Flitwick', - 'Zelzate', - 'Umag', - 'Samai', - 'Battulapalle', - 'Sason', - 'Puerto Ayora', - 'Caio', - 'Betton', - 'Sante Bennur', - 'Zelenodolsk', - 'Basmenj', - 'Librazhd-Qender', - 'Brad', - 'Peraiyur', - "Gricignano d'Aversa", - 'Altenstadt', - 'Buharkent', - 'Chuy', - 'Manakondur', - 'Bamhni', - 'Sangtuda', - 'Alampur Gonpura', - 'Bou Adel', - 'Dianguirde', - 'Dianke', - 'Challapata', - 'Santiago Amoltepec', - 'Ap Binh Thanh', - 'Feuchtwangen', - 'Mechtras', - 'Northlake', - 'Wawarsing', - 'Delemont', - 'Saint-Hilaire-de-Riez', - 'Hersbruck', - 'Maniyur', - 'Itayanagi', - 'Manorville', - 'Derventa', - 'Hedensted', - 'Luchong', - 'Cuisnahuat', - 'Brownhills', - 'Amos', - 'Beausoleil', - 'Ait Youssef Ou Ali', - 'Morazan', - 'Paradise Valley', - 'Winterberg', - 'Comines', - 'Olgiate Olona', - 'Neosho', - 'Taguai', - 'Ceuti', - 'Dunkirk', - 'Bad Abbach', - 'Diari', - 'Blaubeuren', - 'Meze', - 'Shirataka', - 'Fords', - 'Herk-de-Stad', - 'Wickliffe', - 'Kelso', - 'Gerpinnes', - 'Puduru', - 'Cairo Montenotte', - 'Hornsey', - 'Tamm', - 'Mugutkhan Hubli', - 'Valverde del Camino', - 'Santo Stino di Livenza', - 'Ahermoumou', - 'Kucove', - 'Malmedy', - 'Balpyq Bi', - 'Pasadena Hills', - 'Malhador', - 'Nakhla', + 'Shangshan', + 'Roldan', + 'Tiddim', + 'El Bosque', + 'Mangapet', + 'Enfield Lock', + 'Paulo Afonso', + 'Golden Gate', + 'Del City', + 'Brandys nad Labem-Stara Boleslav', + 'Ambatomasina', + 'San Pascual', + 'Gothurutha', + 'Budapest', + 'El Hamel', + 'Vadakadu', + 'Casalpusterlengo', + 'Vardannapet', + 'Glucholazy', + 'Talkha', + 'Victoriaville', + 'Fengdeng', + 'Bhalki', + "Sao Jorge d'Oeste", + 'Calaca', + 'Al `Awwamiyah', + 'Listowel', + 'Komenda', + 'Janiuay', + 'Copperas Cove', + 'Kovvali', + 'Cucer-Sandevo', + 'Birkat as Sab`', + 'Silaiyampatti', + 'Lianzhuangcun', + 'Arataca', + 'Natchez', + 'Guangyuan', + 'Ko Samui', + 'Hajduboszormeny', + 'Ambatondrazaka', + 'Akonolinga', + 'Barpeta', + 'Torrelodones', + 'Norrtalje', + 'Saurh', + 'Wohlen', + 'Felling', + 'Honjo', + 'Petare', + 'Proper Bansud', + 'Dendermonde', + 'Parauna', + 'Bibhutpur', + 'Sultepec', + 'Chiquinquira', + 'Lint', + 'Zhedao', + 'Santo Antonio de Padua', + 'Alburquerque', + 'Fuzuli', + 'Ocean Pines', + 'Atacames', + 'Francheville', + "Wadi Halfa'", + 'Ninh Hoa', + 'Baiquan', + 'Antigua', + 'Bevata', + 'Xinpo', + 'Warkan', + 'Qibray', + 'Gisors', + 'Pa Mok', + 'Tabuleiro do Norte', + 'Melres', + 'Sangam', + 'Ostrhauderfehn', + 'Buritirama', + 'Oleksandriia', + 'Dongzhang', + 'Rio Preto da Eva', + 'Idupugallu', + 'Florida City', + 'Tobias Fornier', + 'Newquay', + 'Ivins', + 'Kotah-ye `Ashro', + 'Klaksvik', + 'Klaeng', + 'Vatutine', + 'Rignano Flaminio', + 'Soamahamanina', + 'Essex', + 'Arenzano', + 'Arbaoun', + 'Ain Kansara', + 'Stein', + 'Gleisdorf', + 'Ottaviano', + 'Lloret de Mar', + 'Sindos', + 'Lausanne', + 'Swadlincote', + 'Buffalo Grove', + 'Coelho Neto', + 'Msata', + 'Ciudad Cuauhtemoc', + 'Home Gardens', + 'Resen', + 'Khergam', + 'Neu Isenburg', + 'Kiato', + 'Mahina', + 'Keelung', + 'Mahiari', + 'Itambacuri', + 'Tsiatajavona-Ankaratra', + 'Sake', + 'Narrabri', + 'Popovaca', + 'Uruma', + 'Doha', + 'Ilaiyankudi', + 'Cabo Frio', + 'Mustang', + 'Kolbermoor', + 'Anahidrano', + 'Skikda', + 'Omurtag', + 'Maqu', + 'Mouscron', + 'Anchieta', + 'Pendembu', + 'Mokokchung', + 'Cestos City', + 'Oulad Zemam', + 'Beerse', + 'Solin', + 'Orani', + 'Itapira', + 'Elburg', + 'Pretoria', + 'Nishihara', + 'Siparia', + 'Fort Riley', + 'Dar Chaifat', + 'Khiria Jhansi', + 'Rezvanshahr', + 'Gacheta', + 'Rio Mayo', + 'Huainan', + 'Sarkisla', + 'Frias', + 'Msila', + 'Neumarkt', + 'Ajjanahalli', + 'Santa Maria Xadani', + 'Loikaw', + 'Gebze', + "Shin'onsen", + 'Bhind', + 'Nakhon Si Thammarat', + 'Wangzhuang', + 'Ban Kao', + 'Barki Saria', + 'Wylie', + 'Birdsville', + 'Atoyac de Alvarez', + 'Bamberg', + 'Agourai', + 'Saavedra', + 'Gundelfingen', + 'Hunucma', + 'Ambohitrimanjaka', + 'San Pedro Necta', + 'Eeklo', + 'Gutalac', + 'Chankou', + 'Cerro Cora', + 'Gulfport', + 'Southaven', + 'Vemulapudi', + 'Pinal de Amoles', + 'Montgomery', + 'Conchali', + 'Cercola', + 'Baependi', + 'Urgup', + 'Qurayyat', + 'Ban Si Don Chai', + 'Duyun', + 'Gentio do Ouro', + 'Detroit Lakes', + 'Muna', + 'Pine Lake Park', + 'Omerli', + 'Ambatondrakalavao', + 'Las Cabras', + 'Dueville', + 'Darjeeling', + 'Los Gatos', + 'Poa', + 'Keren', + 'Jiajin', + 'Vogosca', + 'Radece', + 'Damonojodi', + 'Khurda', + 'Surallah', + 'Johor Bahru', + 'Cuervos', + 'Brixton', + 'Kasap', + 'San Juan La Laguna', + 'Dambai', + 'Marantao', + 'Aguazul', + 'Teoloyucan', + 'Munnar', + 'Madhopur Hazari', + 'Yaotsu', + 'Le Ray', + 'Segbwema', + 'La Apartada', + 'Vitrolles', + 'Amtali', + 'Neston', + 'Portage La Prairie', + 'Taytay', + 'Barahbatta', + 'Tiorpara', + 'Hajira', + 'As Sabburah', + 'Krynica', + 'East Rutherford', + 'Stovring', + 'Andernach', + 'Levski', + 'Vihiga', + 'Kadikkad', + 'Husepur', + 'Nokha', + 'Santa Isabel do Ivai', + 'Bithar', + 'Gaziemir', + 'Manapparai', + 'Sinait', + 'Brandfort', + 'Ibaraki', + 'General San Martin', + 'Parma Heights', + 'Yoshiwara', + 'Mudanya', + 'Bafq', + 'Mikolow', + "Chang'an", + 'Chota', + 'Kesbewa', + 'Sinacaban', + 'Ambarawa', + 'Molodohvardiisk', + 'Herat', + 'Sakaidecho', + 'Honefoss', + 'Handan', + 'Clydebank', + 'Glenpool', + 'Uman', 'San Biagio di Callalta', - 'Sheopuria', - 'Gaffney', - 'Branson', - 'Waltershausen', - 'Ouzera', - 'Sinincay', - 'Takamori', - 'Bom Repouso', - 'Qiaotouba', - 'Alpen', + 'Ocean City', + 'Qiryat Yam', + 'Baldwin', + 'Sweden', + 'Soavina', + 'Hugo', + 'Tra Vinh', + 'Taibet', + 'Turi', + 'Agua Blanca Iturbide', + 'Cherasco', + 'Parun', + 'Cedar Hills', + 'Arugollu', + 'Puduppattanam', + 'Monki', + 'Dorog', + 'Tissamaharama', + 'Seffner', + 'Tongchuan', + 'Nethirimangalam', + 'Ambalanirana', + 'Torbat-e Jam', + 'Balangkayan', + 'Malazgirt', + "Uchtepa Qishlog'i", + 'Les Anglais', + 'Sing Buri', + 'Zhaoxiang', + 'Porta Westfalica', + 'Kajur', + 'Casa Grande', + 'Nkoteng', + 'Pasca', + 'Merefa', + 'Perols', + 'Ellensburg', + 'Mannukara', + 'Rum', + 'Moglingen', + 'Tendrara', + 'Traiskirchen', + 'Dialoube', + 'Poona-Piagapo', + 'Orthez', + 'Hollinwood', + 'Ferryhill', + 'Heerhugowaard', + 'Bad Soden-Salmunster', + 'Twin Falls', + 'Imamoglu', + 'Gartringen', + 'Vaudreuil-Dorion', + 'Chonthrhu', + 'Aberbargoed', + 'Langar', + 'Cabarroguis', + 'Anakapalle', + 'Geraldton', + 'Seara', + 'Guasca', + 'Ban Mae Sun Luang', + 'Sankt Johann in Tirol', + 'Musselburgh', + 'Nave', + 'Bhola', + 'Mansehra', + 'Villa Sarmiento', + 'Sao Bento do Una', + 'Balasan', + 'Bocana de Paiwas', + 'Costesti', + 'Podu Iloaiei', + 'Jaitpura', + 'Rio Colorado', + 'Villa Nueva', + 'Tlaquepaque', 'Sutton on Hull', - 'Tilari', - 'Schongau', - 'Fulton', - 'Novhorod-Siverskyi', - 'Awantipur', - 'Newington Forest', - 'Robertsville', - 'Market Warsop', - 'Warsop', - 'Bad Windsheim', - 'Nangola', - 'Isla Mujeres', - 'Petrovske', - 'Ziama Mansouria', - 'El Menzel', - 'Al Muzayrib', - 'Fortaleza dos Nogueiras', - 'Saltcoats', - 'Ponduru', - 'Los Hidalgos', - 'Horndean', - 'Holiday City-Berkeley', - 'Melvindale', - 'Groutville', - 'Rio Vermelho', - 'Koyulhisar', - 'Puttanattam', - 'Kakan', - 'Tenmalai', - 'De Haan', - 'North Walsham', - 'Adukam', - 'Kanniyambram', - 'San Marco in Lamis', - 'Souakene', - 'Dores do Indaia', - 'Tomball', - 'Enumclaw', - 'Shchastia', - 'Jaromer', - 'Naduhatti', - 'Costa Marques', - 'Knittelfeld', - 'Burj al `Arab', - 'Kadiyampatti', - 'Ap Phu Hai', - 'Castel Goffredo', - 'Teroual', - 'Maxcanu', - 'Junin de los Andes', - 'Presidente Janio Quadros', - 'Jalpura', - 'Cunda dia Baze', - 'Ulster', - 'Cedral', - 'Gurgentepe', - 'Villeneuve-les-Avignon', - 'Motkur', - 'Xalpatlahuac', - 'Concepcion Las Minas', - 'Summerstrand', - 'Isla Raton', - 'Buchs', - 'Steinheim', - 'Juterbog', - 'Ullo', - 'Mamakating', - 'Tamsaout', - 'Santa Barbara de Pinto', - 'Toplita', - 'Chariyakulam', - 'Oulad Ouchchih', - 'Yenipazar', - 'Bretzfeld', - 'Levelland', - 'Winnetka', - 'Minooka', - 'Lakeland South', - 'Kharak Kalan', - 'Road Town', - 'Brunsbuttel', - 'Garh Sisai', - 'Belagal', + 'Radomyshl', 'Muttanampalaiyam', - 'Mendota', - 'Sariveliler', - 'Luchenza', - 'Galaosiyo Shahri', - 'Eski Arab', - 'Alat', - 'Angadikkal Tekkekara', - 'Hessisch Lichtenau', - 'Yzeure', - 'Canet-en-Roussillon', - 'Hosir', - 'Stupava', - 'Lamphun', - 'Khagra', - 'Grenada', - 'Wetaskiwin', - 'Dieli', - 'Brown Deer', - 'New Germany', - 'Dossenheim', - 'Minakshipuram', - 'Ibiracu', - "Jeppe's Reef", - 'Chropaczow', - 'Zimnicea', - 'Viota', - 'Cevicos', - 'Ban Tom Klang', - 'Kortemark', - 'Vilsbiburg', - 'Mahuakheraganj', - 'Koppal', - 'Hayashima', - 'Gaesti', - 'General Acha', - 'Sangar', - 'Wordsley', - 'Granville', - 'Jensen Beach', - 'Chandwa', - 'Lamballe', - 'Vatra Dornei', - 'Tuzdybastau', - 'Wieringerwerf', - 'Pago Pago', - 'Apricena', - 'Dabat', - 'Dingman', - 'Vidauban', - 'Karedu', - 'Dongyuancun', - 'Osecina', - 'Adre', - 'Saint-Jean-de-Vedas', - 'Appukkudal', - 'Chok Chai', - 'Vasylivka', - 'Duartina', - 'Gueltat Sidi Saad', - 'Tirukkattuppalli', - 'Kanra', - 'El Fuerte', - 'Campbelltown', - 'Lipari', - 'Tartar', - 'Quirihue', - 'Niefern-Oschelbronn', - 'Salobrena', - 'Croxley Green', - 'Upper', - 'Ancuabe', - 'Fene', - 'Prymorskyi', - 'Olen', - 'Maba', - 'Vohimarina', - 'Birni', - 'Cloquet', - 'Wadhraf', - 'Mandramo', - 'Rong Kwang', - 'Murud', - 'Nohsa', - 'Parasurampur', - 'Diamou', - 'Calanasan', - 'Cuers', - 'Armadale', - 'Pilich', - 'Marikal', - 'Devapur', - 'Osian', - 'Sankt Veit an der Glan', - 'Viera East', - 'Fonsorbes', - 'Pajo', - 'Dysselsdorp', - 'Sabugal', - 'Rantoul', - 'Monte Quemado', - 'Hirschaid', - 'Kwiha', - 'Monovar', - 'Cascades', - 'Ban Laem', - 'Chai Nat', - 'Conceicao do Rio Verde', - 'Makuyu', - 'Baraboo', - 'Luderitz', - 'Palos de la Frontera', - 'Kawamata', - 'Sarare', - 'Emstek', - 'North Smithfield', - 'Avrig', - 'Nakhtarana', - 'Varazze', - 'Kantang', - 'Jiuduhe', - 'Turki', - 'Hisarcik', - 'Rothenbach an der Pegnitz', - 'Preussisch Oldendorf', - 'Mablethorpe', - 'Chiampo', - 'Betma', - 'Mahrail', - 'Brock Hall', - 'Mayamankurichchi', - 'Bacalar', - 'Chikura', - 'Lake Norman of Catawba', - 'Villa Sola de Vega', - 'Hansot', - 'Justice', - 'Iconha', - 'Montegranaro', - 'Tola Khadda', - 'Fort Atkinson', - 'Montividiu', - 'Eloxochitlan', - 'Champadanga', - 'Kewatgawan', - 'Ereymentau', - 'West Grey', - 'Ladenburg', - 'Ialoveni', - 'Teulada', - 'Asbury Lake', - 'Zella-Mehlis', - 'Creutzwald', - 'Klobuck', - 'Gladenbach', - 'Gorazde', - 'Buchach', - 'Fort Bliss', - 'Campinorte', - 'Borgo San Dalmazzo', - 'Qarah', - 'Marabella', - 'Kashasha', - 'Beydag', - 'Edemissen', - 'Gumani', - 'Savalgi', - 'Borger', - 'Wolsztyn', - 'Pannaikkadu', - 'Sattegalam', - 'Stony Brook', - 'Miary', - 'Wlodawa', - 'Panj', - 'Culfa', - 'Dhanupra', - 'Sarasota Springs', - 'Anjahambe', - 'Paithan Kawai', - 'Giannouli', - 'Rionero in Vulture', - 'Goldenrod', - 'Codegua', - 'Nanzhai', - 'Coringa', - 'Puturge', - 'Wolverton', - 'Zuvvaladinne', - 'Gosaingaon', - 'Hincesti', - 'Uludere', - 'Canegrate', - 'Bauyrzhan Momyshuly', - 'Kingsburg', - 'Negotino', - 'Devsar', - 'Laarne', - 'Grave', - 'El Adjiba', - "Saint David's", - 'Vikasnagar', + 'Elon', + 'Great Falls', + 'Al `Amirat', + 'Ganzhu', + 'Machachi', + 'Lehututu', + 'Ambohimierambe-Andranofito', + 'Singur', + 'Lagindingan', + 'Bocaina', + 'Siguatepeque', + 'Jalalkhera', + 'Santa Lucija', + 'Colmeia', + 'Aneho', + 'Beterou', + 'Mont-Organise', + 'Cabanas', + 'Leduc', + 'Euxton', + 'Trebinje', + 'Patri', + 'Ostrava', + 'Bay Shore', + 'Ghatkesar', + 'Gia Nghia', + 'University Heights', + 'Montigny-les-Metz', + 'Pipraun', + 'Villa de Cura', + 'Polokwane', + 'Daloa', + 'Souma', + 'Cerea', + 'Gracanice', + 'Anteza', + 'Dedza', + 'Hilsea', + 'Koduvalli', + 'Katravulapalle', + 'Nembro', + 'Wanlaweyn', + 'Sardulgarh', + 'Hatibanda', + 'Khizrpur', + 'Sailana', + 'Holbrook', + 'Horwich', + 'Motibennur', + 'Kenner', + 'Bugallon', + 'Angermunde', + 'Boguszow-Gorce', + 'Motomiya', + 'Nanzhuangzhen', + 'Tangxing', + 'Tamanrasset', + 'Brasileia', + 'Canandaigua', + 'Gardez', + 'Qorasuv', + 'Halemba', + 'Biandanshan', + 'Mauleon', + 'Komarno', + 'Husi', + 'Ngaoundal', + 'Ferreiros', + 'Gatunda', + 'Aioi', + 'Jainagar', + 'Longyan', + 'Mocimboa', + 'Central Point', + 'Machadodorp', + 'Niesky', + 'Trets', + 'Kajang', + 'Tuxpan', + 'Anosy Avaratra', + 'Novhorod-Siverskyi', + 'Zhenjiang', + 'Srungavarapukota', + 'San Sebastian de la Gomera', + 'Frankston', + 'Ninga', + 'Morauna', + 'Saginaw', + 'Kussnacht', + 'Lerida', + 'Silchar', + 'Thakurainia', + 'Wote', + 'Riom', + 'Khachrod', + 'Takizawa', + 'Psychiko', + 'Niasso', + 'Rio das Pedras', + 'La Maquina', + 'Kaguchi', + 'San Fabian', + 'Devarapalle', + 'Nahiyat Ghammas', + 'Tlapacoyan', + 'Debe', + 'Santa Maria de Itabira', + 'Ifigha', + 'Neduvattur', + 'Monteprandone', + 'San Pedro Perulapan', + "Bou'nane", + 'Ponnagyun', + 'Guaicara', + 'Krivogastani', + 'Ino', + 'Stupava', + 'New Mills', + 'Ankadimanga', + 'Liaoyang', + 'Chittaurgarh', + 'Bim Son', + 'Cullera', + 'Blackburn', + 'Great Driffield', + 'Mukacheve', + 'Warka', + 'Villers-la-Ville', + 'Gavarr', + 'Khrustalnyi', + 'Easley', + 'Caykara', + 'Woudenberg', + 'Kismaayo', + 'Chojnice', + 'Holladay', + 'Leiderdorp', + 'Reading', + 'Evansville', + 'Bamaiya Harlal', + 'Johns Creek', + 'Qo`qon', + 'Tambaga', + 'Kouande', + 'Sapang Dalaga', + 'Rocafuerte', + 'Curepipe', + 'Jabuticabal', + 'Hasroun', + 'Nishinoomote', + 'Salemi', + 'Bailongqiaocun', + 'Niefern-Oschelbronn', + 'Jablah', + 'Susa', + 'Ortuella', + 'Bitonto', + 'Karadge', + 'Quelimane', + 'Pirthipur', + 'Crisopolis', + 'Venosa', + 'Anantapur', + 'Grajau', + 'Idah', + 'Sidlice', + 'Middle Smithfield', + 'Kanie', + 'Khari', + 'Patnagarh', + 'Tamentit', + 'Ciudad Valles', + 'Kampen', + 'Madangir', + 'Swidwin', + 'Analaroa', + 'Cayirli', + 'Cernay', + 'Houghton Regis', + 'Redon', + 'Belchatow', + 'Maktar', + 'Belagal', + 'Chikkarampalaiyam', + 'Novato', + 'Notre-Dame-de-Gravenchon', + 'Wuustwezel', + 'Palaiyampatti', + 'Kandanur', + 'Nahavand', + 'Tokushima', + 'Sandakan', + 'Avidha', + 'Chaital', + 'Shri Mahavirji', + 'Tashir', + 'Taghbalt', + 'Cottage Grove', + 'Paso de los Toros', + 'Ilicinia', + "Monteforte d'Alpone", + 'Helleland', + 'Corcuera', + 'Goa', + 'Oqqo`rg`on', + 'Chalco', + 'Chorwad', + 'Jhenida', + 'Triesen', + 'Ban Don Kaeo', + 'Nova Prata', + 'Pyrzyce', + 'Sogod', + 'Kilindoni', + 'Condega', + 'Qatana', + 'Nuth', + 'Ban Phru', + 'Kiiminki', + 'Antanandehibe', + 'La Concordia', + 'Guilherand', + 'Antsiranana', + 'Mersch', + 'Al Awjam', + 'Selouane', + 'Coronda', + 'Oregon City', + 'Bordj Zemoura', 'Alwarkurichchi', - 'Xavantes', - 'Alto do Rodrigues', - 'Kotwapatti Rampur', - 'Rozhyshche', - 'Bang Phlat', - 'Ingeniero Maschwitz', - 'Okinawa Numero Uno', - 'Neuenburg am Rhein', - "'Ain el Assel", - 'Jerome', - 'Ocna Mures', - 'Santany', - 'Domahani', - 'Naysar', - 'Thair', - 'Poquoson', - 'Mariental', - 'Kamin-Kashyrskyi', - 'Tiruppalai', - 'Chabal Kalan', - 'Lana', - 'Kathanian', - 'Pidigan', - 'La Argentina', - 'San Miguel Panan', - 'Arhribs', - 'Upper Uwchlan', - 'Kuttiyeri', - 'Andernos-les-Bains', - 'Bheja', - 'Zaladanki', - 'Made', - 'Raamsdonksveer', - 'Sedro-Woolley', - 'Ranranagudipeta', - 'Canovanas', - 'Lakshminarayanapuram', - 'Matatiele', - 'Santa Ana Maya', - 'Voerendaal', - 'Ban Bang Non', - 'Singerei', - 'Bryne', - 'Hacilar', - 'Sylacauga', - 'North St. Paul', - 'Kuhsan', - 'Costessey', - 'Baker', - 'Chaval', - 'Mongat', - 'Barton upon Irwell', - 'Patiram', - 'Eyvanekey', - 'eXobho', - 'Ounagha', - 'Reshuijie', - 'Xinyingheyan', - 'Cetinje', - 'Busogo', - 'Iferhounene', - 'Pont-du-Chateau', - 'San Bartolo', - 'Putussibau', - 'Guruvarajukuppam', - 'El Tambo', - 'Cromer', - 'Refahiye', - 'Santana do Matos', - 'Nakskov', - 'Bickenhill', - 'Haddonfield', - 'Highland City', - 'Rozenburg', - 'Vernouillet', - 'Engenheiro Beltrao', - 'Macara', - 'Sillamae', - 'Bad Sassendorf', - 'Graben-Neudorf', - 'Bandipur', - 'Tilbury', - 'Chigwell', - 'Castelnaudary', - 'Anna Regina', - 'Ahirauliya', - 'Harrai', - 'Fagnano Olona', - 'Bagnolo Mella', - 'Kobiri', - 'Zonnebeke', - 'Boumia', - 'Satao', - 'Gamarra', - 'Celakovice', - 'Prairie Ridge', - 'Ozatlan', - 'Bhanas Hivre', - 'Sangan', - 'San Marino', - 'Upper Montclair', - 'Finspang', - 'Kanoni', - 'Hanumantanpatti', - 'Wimauma', - 'Nelmadur', - 'Villa Literno', - 'Shichuanxiang', - 'Gravatal', - 'Bischwiller', - 'Matsukawa', - 'Kankon', - 'Gogui', - 'Goiatins', - 'Los Santos', - 'Gohpur', - 'Koszutka', - 'Bandalli', - 'Balchik', - 'Kallupatti', - 'Campiglia Marittima', - 'Sint-Michiels', - 'Velten', - 'Dhansura', - 'Oshikango', - 'Guatica', - 'Pueblo Rico', - 'Titara', - 'Massena', - 'Provadia', - 'Jequeri', - 'Chachagui', - 'Warman', - 'Gulshan', - 'Taiynsha', - 'El Ayote', - 'Mallappulasseri', - 'Los Bellosos', - 'Hersham', - 'Maglod', - 'Huodoushancun', - 'Hizan', - 'Gaildorf', - 'Hullatti', - 'Bayona', - 'Grammichele', - 'Madiama', - 'Meerzorg', - 'Aywaille', - 'Kadiana', - 'Vallejuelo', - 'Escanaba', - 'Kolattur', - 'Kegeyli Shahar', - 'Mango', - 'Las Lomitas', - 'Prilly', - 'Hagenow', - 'Maraiyur', - 'Hinundayan', - 'Siki', - 'Kika', - 'Neerijnen', - 'Koluszki', - 'Xinbocun', - 'Mikashevichy', - 'Xinchangcun', - 'Ponnai', - 'Buttayagudem', - 'Arcozelo', - 'Trogir', - 'Sarableh', - 'Ambinanynony', - 'Payyanpalli', - 'Calvizzano', - 'Poco Branco', - 'Titisee-Neustadt', - 'Kalingiyam', - 'Brignais', - 'Triel-sur-Seine', - 'Orzinuovi', - 'Amelia', - 'San Pedro Jicayan', - 'Ebersberg', - 'Ammavarikuppam', - 'Kamtaul', - 'El Aouana', - 'Bollnas', - 'Chennampatti', - 'Boortmeerbeek', - 'Quinta de Tilcoco', - 'Kallamalai', - 'Lyelchytsy', - 'Pira', - 'Spondon', - 'Attanur', - "Anzola dell'Emilia", - 'Panjipara', - 'College', - 'Lewisburg', - 'Las Parejas', - 'Sher', - 'Zlocieniec', - 'Estepa', - 'Saboya', - 'Arma', - 'Conneaut', - 'Asfarvarin', - 'Tyngsborough', - 'Avigliana', - 'Nanakuli', - 'Ilmajoki', - 'Olagadam', - 'Oissel', - 'Villafranca de los Barros', - 'Dokkum', - 'Ribeirao Claro', - 'Issum', - 'Seravezza', - 'Vardenis', - 'Dharhara', - 'Bad Freienwalde', - 'Aubenas', - 'Mi`rabah', - 'Sarrebourg', - 'Moka', - 'Essenbach', - "L'Union", - 'Forecariah', - 'Ichora', - 'Coseley', - 'Sever do Vouga', - 'Fojnica', - 'Torroella de Montgri', - 'Porto Recanati', + 'Kangasala', + 'Sonada', + 'Burdur', + 'Lollar', + 'Bethel Park', 'Higashiagatsuma', - 'Gonzales', - 'Taraclia', - 'Biliaivka', - 'Pola de Laviana', - 'Ierapetra', - 'Rezvanshahr', - 'Piano di Sorrento', - 'Arluno', - 'Tup', - 'Nitte', - 'Bayanauyl', - 'Sydney Mines', - 'Gaimersheim', - 'Nobeji', - 'Vobkent Shahri', - 'Ovenden', - 'Tenambakkam', - 'Chepstow', - 'Sabinov', - 'Drouin', - 'Dubak', - 'Blackfoot', - 'Kladanj', - 'Cobh', - 'Lye', - 'Payariq Shahri', - 'Jork', - 'Herrin', - 'Patchogue', - 'Rinconada de Malloa', - 'Oulad Fares', - 'San Miguel Xoxtla', - 'Razlog', - 'Bad Fallingbostel', - 'Capdepera', - 'Mandalgovi', - 'Tiszavasvari', - 'Huai Yot', - 'Mutoko', - 'Bourem Inali', - 'Nong Khae', - 'Bandwar', - 'Kalajoki', - 'Laguna Paiva', - 'Maqu', - 'Vysoke Myto', - 'Pontecorvo', - 'Soubala', - 'Mecatlan', - 'Yoko', - 'Oulad Aissa', - 'Bozkurt', - 'Aphaur', - 'Leonforte', - 'Jaidte Lbatma', - 'Hawsh al Bahdaliyah', - 'Periyakoduveri', - 'Boumalne', - 'Dehqonobod', - 'Dragor', - 'Diamniadio', - 'Enkesen', - 'Kibuye', - 'Kalymnos', - 'Kattukkottai', - 'Desri', - 'Bulgan', - 'Capul', - 'Navelim', - 'Dawson Creek', - 'Shuangxianxiang', - 'Teotepeque', - 'Valga', - 'Jankinagar', - 'Harnes', - 'Aubergenville', - 'Mende', - 'Crestwood', - 'Dasraha Bhograjpur', - 'Cottonwood', - 'North Castle', - 'Sedziszow Malopolski', - 'Cambuquira', - 'Quimperle', - 'Cypress Lake', - 'Bou Arkoub', - 'Anklam', - 'Ocean Pines', - 'Kotia', - 'Gravenhurst', - 'Enniscorthy', - 'Heliopolis', - 'Sureshjan', - 'Shamaldy-Say', - 'Lake City', - 'Nkheila', - 'Wernau', + 'Gandujie', + 'Talugtug', + 'Cocotitlan', + 'Cassano al Ionio', + 'New Hamburg', + 'Jacobina', + 'Tourougoumbe', + 'Ribeiropolis', + 'Midsomer Norton', + 'Gretz-Armainvilliers', + 'Nagqu', + 'Sunnyvale', + 'Canberra', + 'Rupana', + 'Owosso', + 'Sao Jose do Norte', + 'Mantaly', + 'Socota', + 'Cape St. Claire', + 'Lepakshi', + 'Rounia', + 'Tavira', + 'Qazyan', 'Chettipulam', - 'Pandalkudi', - 'Frohburg', - 'Biassono', - 'Makeni', - 'Aj Jourf', - 'Susa', - 'Tonyrefail', - 'Obikiik', + 'Grantsville', + 'Nagarote', + 'Baras', + 'Ashaiman', + 'Birendranagar', + 'West Allis', + 'Ouricuri', + 'Sarzana', + 'Vallegrande', + 'El Kseur', + 'Assenede', + 'Chitauria', + 'Steinheim', + 'Amsterdam', + 'Goth Tando Sumro', + 'Santa Cruz Itundujia', + 'Cartago', + 'Nandaime', + 'Andes', + 'Dialakorodji', + 'Schulzendorf', + 'Bantacan', + 'Calarasi', + "Ra's Gharib", + 'East Lake-Orient Park', + 'Baitoa', + 'Ormesson-sur-Marne', + 'El`ad', + 'Campechuela', + 'Shiotacho-matsusaki', + 'Kankaanpaa', + 'Ronda', + 'Urucuia', + 'Morlaix', + 'Satwar', + 'Bethel', + 'Corvallis', + 'Yinchuan', + 'Talavera', + 'Shahriston', + 'Royston', + 'Bexbach', + 'Vilangudi', + 'Brinkmann', + 'Hellendoorn', + 'Imi-n-Tanout', + 'South Hayling', + 'Schroeder', + 'Petrovka', + 'Zouerate', + 'Bingen am Rhein', + 'Bovenden', + 'Biri', + 'Teaneck', + 'Yvoir', + 'Santa Eulalia del Rio', + 'Rolleston', + 'Badantola', + 'Waimea', + 'Muzo', + 'Staro Nagoricane', + 'Paranhos', + 'Neustrelitz', + 'Paouignan', + 'Oakashicho', + 'Iygli', + 'Rangra', + 'Sassenage', + 'Lommedalen', + 'Giyon', + 'Conroe', + 'Upperu', 'Qorao`zak', - "G'oliblar Qishlog'i", - 'Giffnock', - 'Prince Rupert', - 'Sacacoyo', - 'Vocklabruck', - 'La Motte-Servolex', - 'La Chapelle-Saint-Luc', - 'Kakching Khunou', - 'Paikpar', - 'Sendafa', - 'Ar Rommani', - 'Acarlar', - 'Lavagna', - 'Jefferson Hills', - 'Veurne', - 'McComb', - 'Bom Retiro do Sul', - 'Kot Shamir', - 'Rivarolo Canavese', - 'Narman', - 'Arbelaez', - 'Sidi Makhlouf', - 'Charmahin', - 'Ain Kansara', - 'Pont-Sainte-Maxence', - 'New Mills', - 'Melavayi', - 'Guisser', - 'Sala', - 'Cananeia', - 'Pebberu', - 'Gandorhun', - 'Acala del Rio', - 'Lavinia', - 'German Flatts', - 'Claye-Souilly', - 'Lodhikheda', - 'Eraniel', - 'Kasaishi', - 'Penal', + 'Lingal', + 'Jasien', + 'Nonoichi', + 'Al Bardiyah', + 'Arrentela', + 'Saharsa', + 'Kalwakurti', + 'Lakeland North', + 'Bad Ems', + 'Quibaxi', + 'Huskvarna', + 'Bihac', + "'Ain Naga", + 'Euclides da Cunha', + 'East Grinstead', + 'Koneurgench', + 'Calauag', + 'Kiangan', + 'Mill Valley', + 'Turpan', + 'Cacimbinhas', + 'Urucuca', + 'Anouvong', + 'Kunimedu', + 'Islamabad', + 'Chahar Borj-e Qadim', + 'Maribor', + 'Ilgin', + 'Mount Lavinia', + 'Tsukumiura', + 'Aix-en-Provence', + 'Ipaporanga', + 'Pokotylivka', + 'Nazipur', + 'Tebingtinggi', + 'Wenzenbach', + 'Solingen', + 'Beveren', + 'Koszalin', + 'Ticul', + 'Kuroishi', + 'Marialva', + 'Auria', + 'Raffadali', + 'Kumagaya', + 'Ruppichteroth', + 'Dougoufe', + 'Dompu', + 'Petrus Steyn', + 'Lattes', + 'Raalte', + 'Taungdwingyi', + 'Guixi', + 'Ganta', + 'Schonwalde-Siedlung', + 'Ifatsy', + 'Baroda', + 'Los Andes', + 'Zhaitangcun', + 'Simraungadh', + 'Fada', + 'Moldova Noua', + 'Sankt Andra', + 'Ica', + 'Ngora', + 'Robbah', + 'Rahiar Kunchi', + 'Ouatagouna', + 'Benavente', + 'Suluru', + 'Burstadt', + 'Hindoli', + 'Santa Maria Petapa', + 'Sanana', + 'Mangidy', + 'Buldan', + 'Ustrzyki Dolne', + 'Bouznika', + 'Florstadt', + 'Santiago Papasquiaro', + 'Sirur Tajband', + 'Ottumwa', + 'Terralba', + 'Henrietta', + 'Adrar', + 'Koni', + 'Cardonal', + 'Haskah Menah', + 'Dawmat al Jandal', + 'Salzgitter', + 'Shikharpur', + 'So-Awa', + 'Baghmari', + "'Ain Arnat", + 'Gojra', + 'Majidpur', + 'Cayeli', + 'Bouansa', + 'Barhi', + 'New Amsterdam', + 'Ibigawa', + 'Schwarzenberg', + 'Darling', + 'Borgaon', + 'Daudnagar', + 'Kitsuki', + 'Fairfax', + 'Mannarakkat', + 'Oberasbach', + 'Murphy', + 'Laurentides', + 'Manjha', + 'Kobo', + 'Kameoka', + 'Bafut', + 'Krasyliv', + 'Saiha', + 'Edinburgh', + 'Kishkenekol', + 'Leyton', + 'Isiolo', + 'Maibog', + 'Chiranellur', + 'Athens', + 'Sampit', + 'Ak-Suu', + 'Toulal', + 'Rangia', + 'Morton Grove', + 'Kaithinia', + 'Antipolo', + 'Tabant', + 'Starachowice', + 'Al Yadudah', + 'Zonguldak', + 'Piaseczno', + 'Nirna', + 'Mitrovice', + 'Plainfield', + 'Wheat Ridge', + 'Oakbrook', + 'Yahualica de Gonzalez Gallo', + 'Drimmelen', + 'Campo de la Cruz', + 'El Roble', + 'Umarga', + 'Mqam at Tolba', + 'Consett', + 'Ponders End', + 'Mount Lebanon', + 'Harima', + 'Marquette-les-Lille', + 'Spata', + 'Panaon', + 'Viravada', + 'Juazeiro do Norte', + 'Tieling', + 'Montemorelos', + 'Manggar', + 'Scicli', + 'Gorlice', + 'Rong Kwang', + 'Mill Creek', + 'Rivne', + 'Linamon', + 'Creazzo', + 'Moody', + 'Patnanungan', + 'Qasr al Qarabulli', + 'Leingarten', + 'Saqultah', + 'Farob', + 'Chinju', + 'Bartolome Maso', + 'Pedreguer', + 'Kuldiga', + 'San Bernardo del Viento', + 'Kushiro', + 'Maha Sarakham', + 'Campbell River', + 'Balaxani', + 'Kilakkurichchi', + 'Uitenhage', + 'Tudela de Duero', + 'Brianka', + 'Garkha', + 'Kassel', + 'Avigliana', + 'Herk-de-Stad', + 'Kassama', + 'Al Jubayl', + 'Longavi', + 'Ugamedi', + 'Leutkirch im Allgau', + 'Lambeth', + 'Koduman', + 'Bais', + "Petite Riviere de l'Artibonite", + 'Presidencia Roque Saenz Pena', + 'Bad Munder am Deister', + 'Kottadindulu', + 'Thorigny-sur-Marne', + 'Tinkoni', + 'Bilacari', + 'Madruga', + 'Chula Vista', + 'Strzelce Opolskie', + 'Chalgeri', 'Teningen', - 'Bouca', - 'Haslev', - 'Thatto Heath', - 'Benisa', - 'Hathwan', - 'Streator', - 'Soklogbo', - 'Pendencias', - 'Home Gardens', - 'Doctor Phillips', - 'Yenkuvarigudem', - 'Lower Pottsgrove', - 'Fairfax Station', - 'Kafr Ruma', - 'Baikunthpur', - 'Kulattur', - 'Wolow', - 'Newman', - 'Gharbia', - 'Polas', - 'Burladingen', - 'Sevur', - 'Hatillo de Loba', - 'Ludwigslust', - 'Harrow on the Hill', - 'Bejar', - 'Dagmara', - 'Spearfish', - 'Dinkelsbuhl', - 'Pantepec', - 'Razua', - 'Jeronimo Monteiro', - 'Kamalnagar', - 'Beylaqan', - 'Cicciano', - 'Doi Lo', - 'Perth East', - 'Tzintzuntzan', - 'Godohou', - 'Neuhausen auf den Fildern', - 'Nurhak', - 'Teixeiras', - 'Gandara West', - 'Anderlues', - 'Gavardo', - 'Commerce', - 'Oulad Hamdane', - 'Ban Tap Tao', - 'Abu Dis', - 'Juchipila', - 'Marumori', - 'Malloussa', - 'Alucra', - 'Chasiv Yar', - 'Laichingen', - 'Paiker', - 'Mekra', - 'Mahespur', - 'Khujner', - 'West Deer', - 'West Plains', - 'Senjan', - 'Eral', - 'Ogulin', - 'Ouenou', - 'Kallanai', - 'Zaboli', - 'Boloso', - 'Effingham', - 'Doddanahalli', - 'Manamodu', - 'Engenheiro Paulo de Frontin', - 'Spresiano', - 'El Campo', - 'Porto Valter', - 'Lila', - 'Selston', - 'Ban Huai So Nuea', - 'Carnaubeira da Penha', - 'Neralakaje', - 'Narala', - 'Scotts Valley', - 'Cuichapa', - 'Nordstemmen', - 'Linkenheim-Hochstetten', - 'Tempoal de Sanchez', - 'Sala Consilina', - 'Beatrice', - 'Itiquira', - 'Sidi Aoun', - 'North Saanich', - 'Ramabitsa', - 'Kinrooi', - 'Zetel', - 'Newhaven', - 'Chamarru', - 'Presidencia de la Plaza', - 'Morbegno', - 'Hattem', - 'Steinheim am der Murr', - 'Bhachhi Asli', - 'Karrapur', - 'Affoltern am Albis', - 'Apen', - 'Emboscada', - 'Barra do Ribeiro', - 'Maxhutte-Haidhof', - 'Hassi Fedoul', - 'Bully-les-Mines', - 'Dharmastala', - 'Pathra', - 'Ujfeherto', - 'Bampur', - 'Obernai', - 'Puduvayal', - 'Malone', - 'Currimao', - 'Chene-Bougeries', - 'Fomeque', - 'Hanur', - 'Cedarburg', - 'Bom Lugar', - 'Arara', - 'Tsuruta', - 'Yakoma', - 'Chichli', - 'Okabecho-okabe', - 'Anao', - 'Hengshan', - 'Kumirimora', - 'Ghogha', - 'Lauriya Nandangarh', - 'Rottofreno', - 'Josefina', - 'Bershad', - 'Vrchlabi', - 'Profondeville', - 'Kolanpak', - 'Yakouren', - 'Koriukivka', - 'Brejinho', - 'Kottagudi Muttanad', - 'Montecorvino Rovella', - 'Karaburun', - 'Kuyganyor', - 'Yangiariq', - 'Sabbavaram', - 'Belwa', - 'Loberia', - 'Paranatama', - 'Sogndal', - 'Loiyo', - 'Concepcion Batres', - 'Cristais', - 'Santa Leopoldina', + 'Cumanda', + 'Ankilivalo', + 'Arica', + 'Mabacun', + 'Agios Dimitrios', + 'Pihuamo', + 'Bithlo', + 'Lititz', + 'Barth', + 'Nkhotakota', + 'Castellammare del Golfo', + 'Tearce', + 'Jinzhou', + 'Mahaditra', + 'Nelkattumseval', + 'Marinilla', + 'Taguai', + 'Ambohidronono', + 'Ansfelden', + 'Angus', + 'Chintalapalli', + 'Piedra Blanca', + 'Prenzlau', + 'San Manuel Chaparron', + 'Grantham', + 'Atyra', + 'Cornwall', + 'Conselice', + 'Brasilia', + 'Igarape Grande', + 'Toplita', + 'Malaimbandy', + 'Kasane', + 'Villa Ocampo', + 'Simarwara Durgapur', + 'Piripa', + 'Giza', + 'Xianyang', + 'Rodas', + 'Canal Winchester', + 'Vashon', + 'Pully', + 'Venice', + 'Miantsoarivo', + 'Rio Cauto', + 'Shahjanpur', + 'Motala', + "'Ain Azel", + 'Taebaek', + 'Mankato', + 'Sevres', + 'Sarangani', + 'Berndorf', + 'Paratinga', + 'Floral Park', + 'Santa Catalina', + 'Greenacres', + 'Verviers', + 'Deoni Buzurg', + 'Lantapan', + 'Brakpan', + 'Santa Ana Chiautempan', + 'Chamtha', + 'Umarkhed', + 'Chai Nat', + 'Willingboro', + 'Licab', + 'Esquel', + 'Santiago Tuxtla', + 'Suran', + 'Mazenod', + 'Holmdel', + 'Saguiaran', + 'Nidadavole', + 'Santa Rosa de Calamuchita', + 'Malkanur', + 'Avaniyapuram', + 'Saktipur', + 'Lynnfield', + 'Orange Park', + 'Lanuvio', + 'Magna', + 'Hanumangarh', + 'Ashmun', + 'Ayirapuram', + 'Viale', + 'Andarai', + 'Falesti', + 'Soverato Marina', + 'Loeches', + 'Ibirataia', + 'Chester-le-Street', + 'Gouna', + 'Azeffoun', + 'Burlingame', + 'Crest', + 'Flowood', + 'Lupane', + 'Iferhounene', + 'Eravattur', + 'Mayaguez', + 'Butte', + 'Azangaro', + 'Viladecans', + 'Argenta', + 'Rauma', + 'Khombole', + 'Trstenik', + 'Kiryu', + 'Mambusao', + 'Tan Uyen', + 'Yazoo City', + 'Turnisce', + 'Navolato', + 'San Giustino', + 'Lice', + 'Antsambahara', + 'Nagahama', + 'Herndon', + 'Phibun Mangsahan', + 'Lushnje', + 'Wanaque', + 'Chuncheon', + 'Thomassique', + 'Havza', + 'Wellington', + 'Nagato', + 'Aucamville', + 'Corupa', + "Ra's al Khafji", + 'Novi Ligure', + 'Isnos', + 'Taiyong', + 'Beigangwa', + 'Greymouth', + 'Sevilla', + 'Beech Grove', + 'Viry-Chatillon', + 'Bogdanci', + 'Hillsdale', + 'Pao de Acucar', + 'Fuqing', + 'Oderzo', + 'Osterholz-Scharmbeck', + 'Saint-Maurice', + 'Puluvappatti', + 'Kabala', + 'Marchtrenk', + 'Lorch', + 'Kamtaul', + 'San Rafael Pie de la Cuesta', + 'La Puente', + 'San Andres', + 'Robore', + 'Baladharmaram', + 'Breza', + 'Rio del Mar', + 'Bocas del Toro', + 'Gorleston-on-Sea', + 'Fair Oaks', + 'Rapallo', + 'Villahermosa', + 'Kalappatti', + 'Wilmington Island', + 'San Francisco Menendez', + 'Champahati', + 'Baden', + 'Maxaranguape', + 'Macas', + 'Rio Tinto', + 'Ingre', + 'Teroual', + 'Nikki', + 'Bir Tam Tam', + 'Myrtle Grove', + 'Wuxi', + 'Si Mustapha', + 'Rundu', + 'Bar Bigha', + 'Iriba', + 'Jebba', + 'Mohanpur Gaughata', + 'Fetromby', + 'Halwara', + 'Carignano', + 'Eagan', + 'Bambari', + 'Lachhmipur', + 'Khemis Miliana', + 'Candeias', + 'Nioro du Rip', + 'San Andres de la Barca', + 'San Juan Nepomuceno', + 'Knightdale', + 'Marano Vicentino', + 'Cergy', + "Ping'anbao", + 'Zhovti Vody', + 'Saalfelden am Steinernen Meer', + 'Lubumbashi', + 'Oxkutzkab', + 'Conakry', + 'Puenteareas', + 'Gotsucho', + 'Sohna', + 'Morehead City', + 'Lingshou', + 'Antotohazo', + 'Ceadir-Lunga', + 'Apucarana', + 'Ihosy', + 'Oulad Barhil', + 'Turkoglu', + 'Progreso', + 'Oued el Aneb', + 'Kendall West', + 'Kignan', + 'Camborne', + 'Bagha Purana', + 'Meskiana', + 'Do Gonbadan', + 'Geesthacht', + 'Lodja', + 'Winterthur', + 'Taketa', + 'Maple Heights', + 'Kelangah', + 'Stary Sacz', + 'Chaplynka', + 'Carlos Chagas', + 'Metlaoui', + 'Ciudad de Huitzuco', + 'Ranod', + 'Clevelandia', + 'Alabat', + 'Belovodskoe', + 'Arriaga', + 'Sandy Hook', + 'Sainte-Agathe-des-Monts', + 'Guacara', + "Quan'ancun", + 'Arques', + 'Nenmem', + 'Gravatal', + 'Saidabad', + 'Kolasin', + 'Merritt Island', + 'Jieshou', + 'Hvalba', + 'Maglaj', + 'Favara', + 'Elk Grove Village', + 'Oppeano', + 'Budai', + 'Novi', + 'Tambe', + 'Balungao', + 'Bocaranga', + 'Pickering', + 'Turuttiyad', + 'Fihaonana', + 'Kidira', + 'Hopkins', + 'Vitoria-Gasteiz', + 'Harpur', + 'Sibundoy', + 'El Kouif', + 'Furth im Wald', + 'Vazhani', + 'Mississippi Mills', + 'Sayville', + 'Bhawanipur', + 'Bel Air', + 'Lishui', + 'Katuria', + 'Sepatan', + 'Uwchlan', + 'Vieste', + 'Pfullendorf', + 'Poggio Renatico', + 'Balha', + 'Brandywine', + 'Manville', + 'Sokcho', + 'Gaigirgordub', + 'Kadattur', + 'Munnelli', + 'San Pancrazio Salentino', + 'Kourani', + 'As Suwayrah', + 'Lubliniec', + 'Poytya', + 'Stezzano', + 'Novomoskovsk', + 'Conchal', + 'Sandona', + 'Nishitokyo', + 'Gardnerville Ranchos', + 'Nyiregyhaza', + 'Encheng', + 'Al Maraghah', + 'Willmar', + 'Sharg`un', + 'Kaiken', + 'Peravur', + 'Ikot Abasi', + 'Swift Current', + 'Oizumi', + 'Lieksa', + 'Tarare', + 'Marton', + 'Berilo', + 'Oldham', + 'Kuppadi', + 'Horodnia', + 'Ataco', + 'Nassjo', + 'Wednesfield', + 'Los Bellosos', + 'Mombaca', + 'Recife', + 'Dalupo', + 'Capitan Pablo Lagerenza', + 'Tsarabaria', + 'La Guaira', + 'Ain Fakroun', + 'Tsiatosika', + 'Melikgazi', + 'San Gabriel', + 'Shek Wai Kok', + 'Pati do Alferes', + 'Nueva Santa Rosa', + 'Gerasdorf bei Wien', + 'Sesheke', + 'Nueva Rosita', + 'Diamante', + 'Fyzabad', + 'Masinloc', + 'Bejofo', + 'Ayolas', + 'Eski Arab', + 'Kaihua', + 'Narlica', + 'Amaga', + 'Haaltert', + 'Inhapim', + 'Itacurubi de la Cordillera', + 'Rawatsar', + 'Kakhovka', + 'Virapandi', + 'Dasai', + 'Laukaa', + 'Uummannaq', + 'Florin', + 'Perampuzha', + 'Mercato San Severino', + 'Zografos', + 'Bukit Gambir', + 'Mericourt', + 'Tchibota', + 'Mantova', + 'Santa Cruz Amilpas', + 'Atarra', + 'Saint-Jean', + 'Mansong', + 'Barbacha', + 'Perondi', + 'Lavasan', + 'Poljcane', + 'Haedo', + 'Sumber', + 'Riedisheim', + 'Manvel', + 'Willenhall', + 'Green Cove Springs', + 'Covasna', + 'Zantiebougou', + 'Mityana', + 'Schiffweiler', + 'San Antonio Sacatepequez', + 'Kalas', + 'Recreo', + 'Bugiri', + 'Rentachintala', + 'Babhani Bholwa', + 'Sedgley', + 'Dimapur', + 'Elkhart', + 'Musoma', + 'Luneburg', + 'New Iberia', + 'Espera Feliz', + 'Catumbela', + 'Leyte', + 'Palkot', + 'San Cugat del Valles', + 'Briancon', + 'Ermita', + 'Kunnumel', + 'Rain', + 'Barretos', + 'Jbail', + 'Hadibu', + 'Nagalapuram', + 'Sibagat', + 'Chamalieres', + 'Minamishibetsucho', + 'Gedaref', + 'Mrirt', + 'Rasra', + 'Holbeach', + 'San Angelo', + 'Olawa', + 'Sroda Wielkopolska', + 'Sabalpur', + 'Ban Plai Bua Phatthana', + 'Homer Glen', + 'Esparza', + 'Media', + 'Fasintsara', + 'Atarfe', + 'Tyamagondal', + 'Panganiban', + 'Arao', + 'Campogalliano', + 'Port Dickson', + 'Iracemapolis', + 'Ahmadabad', + 'Kruje', + 'Gourcy', + 'Penn', + 'Lubartow', + 'Yigilca', + 'Tiwi', + 'Buffelshoek', + 'Camacari', + 'Kunitomi', + 'Druento', + 'Qarabalyq', + 'Reghaia', + 'Edavanakad', + 'Baden-Baden', + 'Seevetal', + 'Puerto Viejo', + 'Segarai', + 'Khadbari', + 'Zag', + 'Amta', + 'Biritinga', + "Hayma'", + 'Nebbi', + 'Malacky', + 'Bacolod', + 'Nkouraba', + 'Cuatro Cienegas de Carranza', + 'Barishal', + 'Lower', + 'Lam Luk Ka', + 'Petershagen', + 'Balham', + 'Titusville', + 'Vijes', + 'Harpur Bochaha', + 'Sido', + 'Sogam', + 'Victorias', + 'Khaira', + 'Capanema', + 'Slatina', + 'Hajduszoboszlo', + 'Kentau', + 'Ba', + 'Amagasaki', + 'Changzhi', + 'Orange Lake', + 'Montigny-en-Gohelle', + 'Gangaikondan', + 'Shibin al Kawm', + 'Kai', + 'Bayanhongor', + 'Erer Sata', + 'Hamamatsu', + 'Cedar Rapids', + 'Lubbeek', + 'Pingyi', + 'Reo', + 'Ban Chomphu Nuea', + 'Mundi', + 'Kantai', + 'Genoa', + 'Agadir', + 'Wawarsing', + 'Best', + 'Tanjore', + 'Tiete', + 'Pacajus', + 'Varzea Grande', + 'Inawashiro', + 'Sigmaringen', + 'Banjarmasin', + 'Punata', + 'Fairview Heights', + 'Embu', + 'Brea', + 'Mohacs', + 'Rosedale', + 'Hammam al `Alil', + 'Papireddippatti', + 'Beaumont-sur-Oise', + 'Makokou', + 'Eastchester', + 'Huntington', + 'Zarumilla', + 'San Sebastian de Buenavista', + 'Ouezzane', + 'Ambalarondra', + 'Waukegan', + 'San Pablo Huixtepec', + 'Kasangati', + 'Boanamary', + 'Nancy', + 'El Pueblito', + 'South Miami Heights', + 'Sayyid Sadiq', + 'Xghajra', + 'Bulacan', + 'Tanichchiyam', + 'Heilbron', + 'Sao Caetano de Odivelas', + 'Ayos', + 'Rawasari', + 'Herve', + 'Fairview Shores', + 'Naklo nad Notecia', + 'San Carlos', + 'Varazze', + 'Konak', + 'Kattakampala', + 'New Berlin', + 'Tuam', + 'Talaigua Nuevo', + 'Suchanino', + 'Alcobendas', + 'Mangalapuram', + 'Lombard', + 'Temacine', + 'Fancheng', + 'Norristown', + 'Kasrawad', + 'Memuro-minami', + 'Newman', + 'Kumamoto', + 'Shimizu', + 'Adrogue', + 'Belo Horizonte', + 'Kurtalan', + 'Gulf Shores', + 'Kenitra', + 'Esquipulas Palo Gordo', + 'Dursunbey', + 'Pazhayannur', + 'Little Elm', + 'Bassersdorf', + 'Sant Just Desvern', + 'Surir', + 'Goodlettsville', + 'Nanjo', + 'Al Jammaliyah', + 'Binyin', + 'Osterwieck', + 'Novoishimskiy', + 'Ananas', + 'Lower Moreland', + 'Gradsko', + 'Qiaotou', + 'Gole', + 'Marale', + 'Kantang', + 'Rajapur', + 'Boha', + 'Orbetello', + 'Suances', + 'Cheshunt', + 'Nagykallo', + "Bu'aale", + 'Chikitigarh', + 'Djenne', + 'Le Luc', + 'Sankeshwar', + 'Hrebinka', + 'Ronchin', + 'Pugo', + 'Putnam Valley', + 'Valka', + 'Sig', + 'Andernos-les-Bains', + 'Neuchatel', + 'Varginha', + 'Noventa Vicentina', + 'Athy', + 'Aradeo', + 'Cururupu', + 'Funza', + 'Alghero', + 'Termiz', + 'Rockwall', + 'Joliet', + 'Alatri', + 'Damarcherla', + 'Nako', + 'Muzaffarnagar', + 'Kazlu Ruda', + 'Urun-Islampur', + 'Thorpe Saint Andrew', + 'Baubau', + 'Felixstowe', + 'Mimata', + 'Babenhausen', + 'Valley Center', + 'Trabzon', + 'Ban Pak Phun', + 'Koudougou', + 'Wisbech', + 'Danvers', + 'Dhamnod', 'Rudrur', - 'Diamond Springs', - 'Bukkapatnam', - 'Tamalpais-Homestead Valley', - 'Lake Tapps', - 'Te Awamutu', - 'Mariyammanahalli', - 'Doranda', - 'Lewisboro', - 'Kafr Buhum', - 'Port Victoria', - 'La Magdalena Chichicaspa', - 'Unguia', - 'North Merrick', - 'Hnivan', - 'Hobro', - 'Namchi', - 'Russi', - 'Chateaubriant', - 'Karimkunnum', - 'Malvinas Argentinas', - 'Saraiya', - 'San Mauro Pascoli', - 'Vulcanesti', - 'Oftersheim', - "'Ain Kerma", - 'Bashtanka', - 'Nevele', - 'Kuttur', - 'Kewanee', - 'Pianiga', - 'Pasca', - 'Rognac', - 'Bhaisalotan', - 'Katagon', - 'Uppukkottai', - 'Wrentham', - 'Moss Point', - 'Osterhofen', - 'Prevost', - 'Tomuk', - 'Ruti', - 'Ghoradal', - 'Sakawa', - 'Tiadiaye', - 'Rafina', - 'Olton', - 'Tioribougou', - 'Nemili', - 'Villamartin', - 'Cheadle', - 'Bhankarpur', - 'Riedisheim', - 'Bonyhad', - 'New Kensington', - 'Le Grand-Saconnex', - 'Matala', - 'Kayattar', - 'Brattleboro', - 'Puerto Nare', - 'Kottaya', - 'Vannivedu', - 'Na Wa', - 'Sagon', - 'Tholey', - 'Vandithavalam', - 'Khonobod', - 'Huetor Vega', - 'Claiborne', - 'Ebejico', - 'Encamp', - 'Barentin', - 'Choctaw', - 'Dranesville', - 'Gajhara', - 'Blonie', - 'Morab', - 'Oyon', - 'Liperi', - 'Samadh Bhai', - 'Wasilkow', - 'Rielasingen-Worblingen', - 'Marquetalia', - 'Arganil', - 'Gyomaendrod', - 'Kesarimangalam', - 'Ban Bo Luang', - 'Cocotitlan', - 'Havixbeck', - 'Panzgam', - 'Grumo Appula', - 'Tranent', - 'Eklahra', - 'Barsaun', - 'As Sars', - 'Mucuge', - 'Xiushuicun', - 'Muthuswamipuram', - 'Minabe', - 'Sainte-Adele', - 'Ban Bang Sai', - 'Ban Noen Phoem', - 'Sapna', - 'Sainte-Agathe-des-Monts', - 'Justo Daract', - 'Mulug', + 'Nueva Italia de Ruiz', + 'Beacon', + 'Deerfield Beach', + 'Tinkhang', + 'Aiyomojok', + 'Gevas', + 'Salou', + 'Pontarlier', + 'Valluvandad', + 'Pingtouchuanxiang', + 'Takasagocho-takasemachi', 'Marsaskala', - 'Meitingen', - 'Bomlo', - 'Camp Verde', - 'Strzelin', - 'Salgado de Sao Felix', - 'Pachchaimalaiyankottai', - 'Mangarwara', - 'Eura', - 'Mandu', - 'El Sobrante', - 'Bela Palanka', - 'Bamber Bridge', - 'Macedonia', - 'Hagfors', - 'Socuellamos', - 'Ampasimbe', - 'Antri', - 'Pornichet', - 'Velair', - 'Ishkashim', - 'Kuzhippilli', - 'Hassi el Ghella', - 'Saclepea', - 'Brzeziny', - 'Kamianka-Dniprovska', - 'Kok-Janggak', - 'North Middleton', - 'Maili', - 'Choro', - 'Champahati', - 'San Prisco', - 'Wyndham', - 'Quesnel', - 'Citlaltepec', - 'Yecuatla', - 'Perleberg', - 'Gistel', - 'Santa Filomena', - 'Pulakurti', - 'Sonupur', - 'Punnila', - 'Yedtare', - 'New Baltimore', - 'Jerico', - 'Saint-Cyr-sur-Mer', - 'Bharweli', - 'Mitchellville', - 'Tahannawt', - 'Kinkala', - 'Mayate', - 'San Carlos Yautepec', - 'Datoda', - 'Waikanae', - 'Glubczyce', - 'Gulbahor', - 'Taltal', - 'El Marsa', - 'Manegaon', - 'Lenyenye', - 'Tring', - 'Crossville', - 'Umm ar Rizam', - 'Mattenhof', - 'Benoy', - 'Lehre', - 'Gieraltowice', - 'Munchenstein', - 'Sable-sur-Sarthe', - 'Kirippatti', - 'Acandi', - 'Bhairapura', - 'Anndevarapeta', - 'Dire', - 'Villars-sur-Glane', - 'Sassenburg', - 'Pillanallur', - 'Osako', - 'Kosjeric', - 'Steenokkerzeel', - 'Mostardas', - 'North Tidworth', - 'Narhat', - 'Zlatograd', - 'Si Mustapha', - 'Albox', - 'Sedgley', - 'Baozhong', - 'Mmadinare', - 'Glen Rock', - 'Durmersheim', - 'Portales', - 'Lower Gwynedd', - 'Ban Muang Ngam', - 'Papampeta', - 'Ganapatipalaiyam', - 'Paal', - 'Ipaumirim', - 'Miesbach', - 'Louvres', - 'Mugalivakkam', - 'Birdaban', - 'Kodusseri', + 'Zequ', + 'Sarapui', + 'Bhangha', + 'Saint Albans', + 'Fountain Hills', + 'Bultfontein', + 'Plant City', + 'Bidestan', + 'Alvorada', + 'Faenza', + 'Benyahia Abderrahmane', + 'Al Hindiyah', + 'Vohitromby', + 'Guadalupe Victoria', + 'Croissy-sur-Seine', + 'Agudo', + 'Carire', + 'Rho', + 'Gassino Torinese', + 'Uzice', + 'Magny-le-Hongre', + 'Bazimini', + 'New York', + 'Croata', + 'Shahgarh', + 'Nyzhnohirskyi', + 'St. Simons', + 'Fleury-les-Aubrais', + 'Paulino Neves', + 'Buderim', + 'Kapchagay', + 'Ahogbeya', + 'Warabi', + 'Sasagawa', + 'Edappalli', + 'Bobleshwar', + 'Sardinata', + 'Niederhasli', + 'Grez-Doiceau', + 'Crimmitschau', + 'Bound Brook', + 'Magog', + 'Pottstown', + 'Loveland', + 'Fort Mill', + 'Kpandu', + 'Ngoc Son', + 'San Agustin', + 'Turkeli', + 'Keynsham', + 'Padre Las Casas', + 'Huangzhai', + 'Acul du Nord', + 'Sha Tin', + 'Reddipalle', 'Dalby', - 'Mettlach', - 'La Queue-en-Brie', - "Motta Sant'Anastasia", - 'Sollies-Pont', - 'Rampur Kudarkatti', - 'Nihal Singhwala', - 'Borgosesia', - 'Hasbrouck Heights', - 'Bridgnorth', - 'Viswanathaperi', - 'Bhagwanpur Desua', - 'Unebicho', - 'East Renton Highlands', - 'Iwate', - 'Uzyn', - 'Piketberg', - 'Ugento', - 'Falesti', - 'Paslek', - 'Kalaidasht', - 'Nova Laranjeiras', - 'Kesabpur', - 'Valley Falls', - 'Tabua', - 'Dhaula', - 'Fenton', - 'Liuba', - 'Sinalunga', - 'Woodward', - 'Filandia', - 'Le Chambon-Feugerolles', - 'Al Majma`ah', - 'Poranga', - 'Curiti', - 'Ciudad-Rodrigo', - 'Sao Francisco do Maranhao', - 'Oiba', - 'Bishnah', - 'Bharokhara', - 'Pharkia', - 'Ponte da Barca', - 'Hodatsushimizu', - 'Mays Chapel', - 'Arroio do Tigre', - 'Jacala', - 'Destrehan', - 'Gardnerville Ranchos', - 'Nattarampalli', - 'Tall Dhahab', - 'Wolgast', - 'Voru', - 'Raismes', - 'Walton-on-the-Naze', - 'Chalgeri', - 'Eiras', - 'Solofra', - 'Nilo Pecanha', - 'Bangawan', - 'Ban Pae', - 'Erfelek', - 'Goner', - "Novalukoml'", - 'Bentley', - 'Rosdorf', - 'Snihurivka', - 'Karagwe', - 'Gbanhi', - 'Lajia', - 'Honeygo', - 'Valenii de Munte', - 'Alavus', - 'Berwick-Upon-Tweed', - 'Sarmastpur', - 'Vilangurichchi', - 'North Lebanon', - 'Hwlffordd', - 'Pyrzyce', - 'Rocca Priora', - 'Baxiangshan', - 'Manne Ekeli', - 'Bagra', - 'St. Peter', - 'Mato Verde', - 'Pittalavanipalem', - 'Steha', - 'Kongsvinger', - 'Imassogo', - 'Karvetnagar', - 'Paramanandal', - 'Iapu', - 'Sabaur', - 'Celebration', - 'Ronneby', - 'Villa Berthet', - 'Edamon', - 'Slawno', - 'Assomada', - 'Gulni', + 'Chigwell', + 'Chaigoubu', + 'Marolinta', + 'Tarma', + 'Schwabisch Gmund', + 'La Teste-de-Buch', + 'Bouna', + 'Creil', + 'Balatonalmadi', + 'Srivardhan', + 'Ettenheim', + 'Spanish Town', + 'Castellabate', + 'Salimpur', + 'Bhusaval', + 'Ayomi', + 'Babhniyawan', + 'Dundankop', + 'Khulna', + 'Incheon', + 'Prizren', + 'Yuvileine', + 'Taastrup', + 'Maibara', + 'Liberec', + 'Bordj Bou Arreridj', + 'Bueu', + 'Baba I', + 'Uttarkashi', + 'Karuizawa', + 'Ikast', + 'Tapolca', + 'Matrah', + 'Chakia', + 'Sosa', + 'Kabalo', + 'High River', + 'Chemnitz', + 'Mirganj', + "Mohale's Hoek", + 'Capena', + "Fanja'", + 'Idumbavanam', + 'Travagliato', + 'Noicattaro', + 'Lasht-e Nesha', + 'Bel Air North', + 'Missour', + 'Itaipe', + 'Sandpoint', + 'Villepinte', + 'Tendukheda', + 'Ljubovija', + 'Mount Pleasant', + 'Yucca Valley', + 'Lai Chau', + 'Litija', 'Liberty Lake', - 'Rosaryville', - 'Theux', - 'Marly', - 'Chudamani', - 'Utehia', - 'River Edge', - 'Huite', - 'Kumarkhali', - 'Nariman', - 'Key Largo', - 'Beyne-Heusay', - 'Velivennu', - 'San Jose El Idolo', - 'Occhiobello', - 'Balha', - 'Fort Campbell North', - 'Saddlebrooke', - 'Budakalasz', - 'Tomar do Geru', - 'Sahtah', - 'Monfort Heights', - 'Al Fayd', - 'Les Iles-de-la-Madeleine', - 'Opmeer', - 'Monte San Giovanni Campano', - 'Raffadali', - 'Sam', - 'Verde Village', - 'Jardim Alegre', - 'Fuensalida', - 'Warka', - 'Singhbari', - 'Viyapuram', - 'San Gennaro Vesuviano', - 'Basantpur', - 'Keimoes', - 'Hasroun', - 'El Qaa', - 'Chaqra', - 'Bteghrine', - 'Qoubaiyat', - 'Ambolomoty', - 'Fanambana', - 'Ivoamba', - 'Ankafina Tsarafidy', - 'Andonabe', - 'Sorombo', - 'Itondy', - 'Iarinarivo', - 'Saharefo', - 'Vohindava', - 'Beandrarezona', - 'Andranovao', - 'Sendrisoa', - 'Maromiandra', - 'Ambalavero', - 'Bekapaika', - 'Anorombato', - 'Ambaliha', - 'Ambohinamboarina', - 'Anjanazana', - 'Andrembesoa', - 'Anjiamangirana I', - 'Nosiarina', - 'Antanamalaza', - 'Andramy', - 'Basibasy', - 'Ampondra', - 'Antaritarika', - 'Befody', - 'Maromby', - 'Omatjete', - 'Umm Badr', - 'Buqkoosaar', - 'Keve', - 'Bilovodsk', - 'Hukumati Gizab', - 'Jajce', - 'Karranah', - 'Ngou', - 'Tefam', - 'Mettingen', - 'Wells', - 'Madina do Boe', - 'Princetown', - 'Petit-Goave', - 'Huvin Hippargi', - 'Khanda', - 'Pinneli', - 'Dahivel', - 'Jai', - 'Sadalgi', - 'Halgar', - 'Arni ka Khera', - 'Pramatam', - 'Cecchina', - 'View Park-Windsor Hills', - 'Sokouhoue', - 'Oberschleissheim', - 'Urakawa', - 'Cimislia', - 'Arutla', - 'Talen', - 'Arkansas City', - 'Manuel Urbano', - 'Galvarino', - 'Boskovice', - 'Somersworth', - 'Wegrow', - 'Doranala', - 'Wang Saphung', - 'Mugdampalli', - 'Bolanos de Calatrava', - 'Alajuelita', - 'Mikkelin Maalaiskunta', - 'Martuni', - 'Shiotacho-matsusaki', - 'Rapho', - 'Husepur', - 'Winton', - 'Nagykata', - 'Tundhul', - 'Msambweni', - 'Yazihan', - 'Escazu', - 'Benifayo', - 'Kaviti', - 'Arth', - 'Iwanai', - 'Ifs', - 'Minehead', - 'Pata Putrela', - 'Klazienaveen', - 'Boldaji', - 'Tabocas do Brejo Velho', - 'Oulad Daoud', - 'Tryavna', - 'Gundelfingen', - 'Arakvaz-e Malekshahi', - 'Belampona', - 'Siruvachchur', - 'Minnal', - 'Kuangfu', - 'Rasingapuram', - 'Hathauri', - 'Erbaocun', - 'Santiago del Teide', - 'Marauatpur', - 'Kyzyl-Kyshtak', - 'Star', - 'Hadim', - 'Erkner', - 'Eraclea', - 'Kasaji', - 'Murnau am Staffelsee', - 'Froha', - 'Nueva Era', - 'Malthone', - 'Bernalda', - 'Mariana', - 'Sremska Kamenica', - 'Tetagunta', - 'Souq Jamaa Fdalate', - 'Welver', - 'Stidia', - 'Taran', - 'Palos Heights', - 'Bissora', - 'Bena', - 'Tigzirt', - 'Niagadina', - 'Saksohara', - 'Ballston', - 'Viralippatti', - 'Awankh', - 'Terranuova Bracciolini', - 'Kountouri', - 'Paispamba', - 'Provins', - 'Phuoc Long', - 'Karaund', - 'Adalaj', - 'Ibaretama', - 'Sidi Yahia', - 'Selimpasa', - 'Noria', - 'Vijayapati', - 'Spencer', - 'Jiajin', - 'Arrigorriaga', - 'Umurlu', - 'Blaricum', - 'Tori-Cada', - 'Jadayampalaiyam', - 'Nong Bua', - 'Sondho Dullah', + 'Kidamangalam', + 'Cambara', + 'Funchal', + 'Nansana', + 'Ongwediva', + 'Jamhra', + 'Gulbene', + 'Hot Springs Village', + 'Gothini', + "Douar 'Ayn Dfali", + 'Belsh', + 'Shimokodanaka', + 'Gerash', + "Welench'iti", + 'Pozorrubio', + 'Placer', + 'Streatham', + 'Muttalakanpatti', + 'Bougival', + 'Porteiras', + 'Liuguoju', + 'Sultanhani', + 'Dhutauli', + 'Jilin', + 'Dongsu', + 'Saho', + 'Santa Cecilia', + 'Jalor', + 'Kuruvambalam', + 'Maraba', + 'Yairipok', + 'Shafter', + 'Zabari', + 'Sauzal', + 'Barharwa', + 'Sisia', + 'Fabriano', + 'Buttar', + 'Corlu', + 'Kailashahar', + 'Mosina', + 'Novo Oriente', + 'Ploemeur', + 'Goshaingaon', + 'Amba Icharua', + 'Lehara', + 'eXobho', + 'Waldenbuch', + 'Marimba', + 'Kavundappadi', + 'Al Hudaydah', + "Castelnovo ne' Monti", + 'Ipuiuna', + 'Az Zawiyah', + 'Barros Blancos', + 'Royan', + 'Zaojiao', + 'Tiztoutine', + 'Tanashicho', + 'Ebbw Vale', + 'Swidnik', + 'Snohomish', + 'Melendugno', + 'Pavia', + 'Whitman', + 'Cuilo', + 'Russas', + 'Callao', + '`Izbat al Burj', + 'Lushoto', + 'Dayr al Barsha', + 'Pepinster', + 'Bustos', + 'Ureshinomachi-shimojuku', + 'Sabugal', + 'Forest City', + 'Afonso Bezerra', + 'Kaliganj', + 'Hato Mayor', + 'Kete Krachi', + 'Rasipuram', + 'Ennepetal', + "Cassano d'Adda", + 'Ronne', + 'Olpe', + 'Karlsruhe', + 'Janpur', + 'Wepener', + 'Happy Valley', + 'Bhadrakh', + 'Gaz', + 'Kayanza', + 'St. Ann', + 'Chitcani', + 'Tafrant', + 'Itabuna', + 'Iracoubo', + 'Mirzanagar', + 'Livry-Gargan', + 'Bequimao', + 'Dazhangzi', + 'Zhugang', + 'Waalre', + 'La Roda', + 'Kamthi', + 'Piggs Peak', + 'Mahadeopur', + 'Annakattumula', + 'Patterson', + 'Koriukivka', + 'Altenberge', + 'Rajula', + 'Hayden', + 'Yambio', + 'Saram', + 'Vereeniging', + 'Beauharnois', + 'La Ravoire', + 'Kulhudhuffushi', + 'Alatsinainy-Bakaro', + 'Nedugula', + 'Goaso', + 'Araucaria', + 'Fort Washington', + 'Sargur', + "Boula'wane", + 'Hussepur', + 'Frederick', + 'An Nimas', + 'Joao Pessoa', + 'La Eliana', + 'Samsun', + 'Bang Phlat', + 'Ketugram', + 'Dhobauli', + 'Bad Wildungen', + 'Estancia Pozo Colorado', + 'Roseller Lim', + 'Skarzysko-Kamienna', + 'Alba', + 'Sengurichchi', + 'Togitsu', + 'Chas', + 'Petlad', + 'El Rama', + 'Parkstone', + 'Lorca', + 'Western Bicutan', + 'Harare', + 'Fort Valley', + 'Staryy Beyneu', + 'Mainit', + 'Rosales', + 'Isafjordhur', + 'Moreau', + 'Kapra', + 'Tarascon', + 'Tubbergen', + 'Santa Comba Dao', + 'Fatikchari', + 'Sumy', + 'Ignacio de la Llave', + "Sant'Elpidio a Mare", + 'Pocono', + 'Kakogawacho-honmachi', + 'Guajara-Mirim', + 'Beekman', + 'Meymand', + 'University of Virginia', + 'Haines City', + 'Simao Dias', + 'Signal Hill', + 'Makedonski Brod', + 'Kamakurayama', + 'Blackpool', + 'Poxoreo', + 'Kohir', + 'Talata-Angavo', + 'Bielefeld', + 'Tomesti', + 'Universal City', + 'Kotka', + 'Uttukkottai', + 'Baruta', + 'Solana', + 'Ain Mediouna', + 'Garoowe', + 'Ap Tan Ngai', + 'Sarigol', + 'Muong Lay', + 'Guryongpo', + 'Moorestown', + 'Nottampatti', + 'Marienheide', + 'Tiruppur', + 'Bikkatti', + 'Fereydunshahr', + 'Ezhamkulam', + 'Ajax', + 'Buguda', + 'Shijiazhuang', + 'Pantanal', + 'Meylan', + 'Dobanovci', + 'Bizerte', + 'Gingin', + 'Baroni Khurd', + 'Cusseta', + 'Alhambra', + 'Chaoyang', + 'Wakema', + 'Holland', + 'Prunedale', + 'Akure', + 'Huautla', + 'Ghora Gali', + 'Ayase', + 'Ciudad de Loreto', + 'Bittou', + 'Andong', + 'Halluin', + 'Yuncos', + 'Eurajoki', + 'Morden', + 'Gueret', + 'Mutukula', + 'Abovyan', + 'Al Hufuf', + 'Tapaua', + 'Tegalbuleud', + 'Brackenheim', + 'Tanaina', + 'Siloam Springs', + 'Kuusankoski', + 'Concordia', + 'Parsippany', + 'Lapanga', + 'Manhuacu', + 'Extrema', + 'El Manteco', + 'Setti Fatma', + 'Guneysinir', + 'Sagara', + 'Kohima', + 'Guacheta', + 'Hidaj', + 'Gollalagunta', + 'Sawla', + 'Tamazouzt', + 'Qoryooley', + 'Constantine', + 'Boulsa', + 'Bhataulia', + 'Oued Athmenia', + 'Villa Ballester', + 'Leipzig', + 'Khewra', + 'Wondelgem', + 'Somanya', + 'Melissa', + 'Wangdue Phodrang', + 'Rietavas', + 'Kirkby in Ashfield', + 'Khadra', + 'Whitemarsh', + 'Palauig', + 'Aleg', + 'El Barrio de la Soledad', + 'Rosario Oeste', + 'Pappakudi', + 'Zorneding', + 'Grodzisk Mazowiecki', + 'Osowa', + 'Samayanallur', + 'Manampizha', + 'Bago', + 'Country Club', + "Lu'an", + 'Santa Teresinha (2)', + 'East Rockaway', + 'Minja', + 'Ilkhechi', + 'Moreno', + 'Novoazovsk', + 'Seondha', + 'Castleton', + 'Hannover', + 'Bhopal', + 'Barnoi', + 'Casaluce', + 'Hola', + "Trezzo sull'Adda", + 'Minxiong', + 'Eboli', + 'Bairiya', + 'Bad Waldsee', + 'Montagu', + 'Torres', + 'Pelitli', + 'Ararenda', + 'Coronel Fabriciano', + 'Monteria', + 'Kavlinge', + 'Grand Gosier', + 'Tidjikja', + 'Palayad', + 'Kattipudi', + 'Kibichuo', + 'Guoxing', + 'Viera West', + 'Aw Dheegle', + 'Ipanguacu', + 'Oued Fodda', + 'Yoju', + 'Leesburg', + 'Sathiala', + 'Senkaya', + 'Kucevo', + 'Mandal', + 'Dauis', + 'Oyon', + 'Kulmbach', + 'Macul', + 'Aysha', + 'Ash Shajarah', + 'Huishi', + 'Chiyoda-ku', + 'Ceccano', + 'Massenya', + 'Impasugong', + 'Champlin', + 'Saint Ives', + 'Sycamore', + 'Mahalgaon', + 'Yanqi', + 'Puren', + 'Koronadal', + 'Santa Catarina Ixtahuacan', + 'Dulmial', + 'Bourg-les-Valence', + 'Du Yar', + 'Marsa', + 'Bootle', + 'Swidnica', + 'Saint-Avold', + 'Goleta', + 'Peshkopi', + 'Ahenkro', + 'Fort Lewis', + 'Barra do Garcas', + 'Greytown', + 'Thouare-sur-Loire', + 'Abdul Hakim', + 'Pont-Sainte-Maxence', + 'Malindi', + 'Meridian', + 'Katsuyama', + 'Pigue', + 'Iradan', + 'Mukerian', + 'Yuzhang', + 'Quang Ngai', + 'Vila Nova de Gaia', + 'Tembagapura', + 'California City', + 'Dolores Hidalgo Cuna de la Independencia Nacional', + 'Guazacapan', + 'Tympaki', + 'Zhuozhou', + 'Tangub', + 'Gelemso', + 'Paal', + 'Hassi Berkane', + 'Plandiste', + 'Eduttavaynattam', + 'Alice', + 'Hannibal', + 'Novi Travnik', + 'Kairana', + 'Ilinden', + 'Mmabatho', + 'Hoyacho', + 'Menzel Bourguiba', + 'Tinsukia', + 'Medina del Campo', + 'Ramon', + 'Pierrefitte-sur-Seine', + 'Monroeville', + 'Randaberg', + 'Maple Shade', + 'Grottaglie', + 'Hisua', + 'Endicott', + 'Palagiano', + 'Martigues', + 'Huacho', + 'Wangtang', + 'Daiyue', + 'Chiguayante', + 'Einbeck', + 'Tezonapa', + 'Sousse', + 'Vikravandi', + 'Hellemmes-Lille', + 'Manampaneva', + 'Spresiano', + 'San Jose La Arada', + 'Salina Cruz', + 'Pindamonhangaba', + 'Bad Aibling', + 'Zhangjiazhuangcun', + 'Selestat', + 'Ascencion de Guarayos', + 'Hastinapur', + 'Xangda', + 'Trujillo Alto', + "Ji'an", + 'Dapaong', + 'Kernersville', + 'Conceicao do Coite', + 'Aguas Santas', + 'A Coruna', + 'Yanshanbu', + 'Boizenburg', + 'Zachary', + 'Lake Forest', + 'La Paz', + 'Malta', + 'Alfreton', + 'Halfeti', + 'Paracuru', + 'Valdivia', + 'Belen', + 'Cawayan', + 'Oda', + 'Ankililoaka', + 'Pondaluru', + 'Larkana', + 'Polaia Kalan', + 'Curua', + 'Hayashima', + 'Brigham City', + 'Beverungen', + 'Towcester', + 'Nove Zamky', + 'Palpa', + 'Gollapudi', + 'Gescher', + 'Camboriu', + 'El Plan', + 'Sokolo', + 'Titel', + 'Vallentuna', + 'Montreux', + 'Delmas', + 'Edirne', + 'Ngolonianasso', + 'Nsiika', + 'Rowlett', + 'Kuchlagh', + 'La Palma del Condado', + 'Senago', + 'Antanandava', + 'Steger', + 'Thatta', + 'Al Hamzah', + 'Krolevets', + 'Cabrera', + 'Baia-Sprie', + 'Santiago Suchilquitongo', + 'Aabenraa', + 'San Marco in Lamis', + 'Kota Bharu', + 'Guayabal', + 'Dasaut', + 'Kauhava', + 'Sabie', + 'Garrucha', + 'Maungdaw', + 'Kaduturutti', + 'Castenedolo', + 'Rio Rico', + 'Varese', + 'Chadchan', + 'Seoni Chhapara', + 'Rodeo', + 'Saint-Esteve', + 'Kierspe', + 'Velke Mezirici', + 'Khajuraho', + 'Thuin', + 'Douz', + 'Bac Lieu', + 'Differdange', + 'Imqabba', + 'Barao de Cocais', + 'Bijar', + 'Payerne', + 'Janakammapeta', + 'Takaishi', + 'Los Alamos', + 'Xianshuigu', + 'San Giuliano Terme', + 'Leigh', + 'Sinjar', + 'Chalastra', + 'Souakene', + 'Carmo do Cajuru', + 'Tirumangalam', + 'Nagardevla Budrukh', + 'Aqchah', + 'As Sars', + "'Ain el Assel", + 'Cusco', + 'Bacarra', + 'Maracacume', + 'Tanhuato de Guerrero', + 'Winston-Salem', + 'Fukuchiyama', + 'Grangemouth', + 'Olive Branch', + 'Zumpango del Rio', + 'Mardan', + 'Greenwood', + 'Torre de Moncorvo', + 'Nanthankulam', + 'Gadzin Han', + 'Manappakkam', + 'San Vicente Pacaya', + 'Suresnes', + 'Piraziz', + 'Anadia', + 'Valle Nacional', + 'Zhongdong Shequ', + 'Howick', + 'San Pedro de Uraba', 'Konaje', - "Trezzo sull'Adda", - 'Pecica', - 'Seberi', - 'Amarapuuram', - 'El Parral', - 'Avesta', - 'Mykhailivka', - 'Darabani', - 'Guidel', - 'Umri', - "Ait I'yach", - 'Zlate Moravce', - 'Joaquim Tavora', - 'South Miami', - 'Goulds', - 'Alijo', - 'Kozloduy', - 'Cano Martin Pena', - 'Governador Dix-Sept Rosado', - 'Sheerness', - 'Khem Karan', - 'Enns', - 'Cinisi', - 'Lienz', - 'Don Sak', - 'Salpazari', - 'Distraccion', - 'Lagoa do Ouro', - 'Rijkevorsel', - 'Parappukara', - 'Pfaffikon', - 'Backa Topola', - 'Dhanauri', - 'Matmata', - 'Tectitan', - 'Panuco de Coronado', - 'Totogalpa', - 'Cungus', - 'Andrelandia', - 'Heddesheim', - 'Saint-Ave', - 'Sai Kung Tuk', - 'Chaital', - 'Pedda Adsarlapalli', - 'Tosashimizu', - 'Schoonhoven', - 'Bueu', - 'Vehkalahti', - 'Mullurkara', - 'Patarra', - 'Athol', - 'Gisors', - 'Sandridge', - 'Sansale', - 'Tizi Nisly', - '`Anadan', - 'Mandasa', - 'Gig Harbor', - 'Bilauri', - 'Hatod', - 'Tache', - 'Brejetuba', - 'Wellington North', - 'Zhdanivka', - 'Paramankurichi', - 'Fort Bonifacio', - 'Edattala', - 'Grand Baie', - 'Lalmatie', - 'Aheqi', - 'Harrislee', - 'Bairo', - 'Huanian', - 'Kotla', - 'Kronshagen', - 'Tanakallu', - 'Kirikera', - 'Mamarappatti', - 'Halstead', - 'Bound Brook', - 'Williams Lake', - 'Chandpura', - 'Box Elder', - 'Zebbug', - 'Ried im Innkreis', - 'Craponne', - 'Tabontabon', - 'Ambatturai', - 'East Bethel', - 'Oqqo`rg`on', - 'Qorashina', - 'Bargoed', - 'Ajjanahalli', - 'Chinna Orampadu', - 'Kampenhout', - 'Bhansia', - 'Baohe', - 'Enamadala', - 'Zemamra', - 'Halasztelek', - 'Wanding', - 'Zumbagua', - 'Gundugolanu', - 'Talant', - 'Hamilton Square', - 'Mamqan', - 'Aragoiania', - 'Shamshernagar', - 'Pakra', - 'Gora Kalwaria', - 'Sultanhani', - 'Cousse', - 'Cachoeira de Minas', - 'Dom Basilio', - 'Lauria Inferiore', - 'Kagamino', - 'Ojuelos de Jalisco', - 'Imarui', - 'Mayiladi', - 'San Severino Marche', - 'Hattian Bala', - 'Gander', - 'Kamlapur', - 'Puliyampatti', - 'Benaguacil', - 'Gerstetten', - 'Jaltenango', - 'Onet Village', - 'Archdale', - 'Maisaka', - 'Badamdar', - 'Rushall', - 'Comasagua', - 'Linganore', - 'Mohnesee', - 'Epinay-sous-Senart', - 'Florange', - 'Mehsari', - 'Bernissart', - 'Snaresbrook', - 'Altavilla Vicentina', - 'Iwaka', - 'Eichenau', - 'Oulad Amrane el Mekki', - 'El Arba Des Bir Lenni', - 'Yuxiaguan', - 'Rudrangi', - "Sant'Agata di Militello", - 'Brunn am Gebirge', - 'Monschau', - 'Vanimo', - 'La Puebla del Rio', - 'Olgiate Comasco', - 'Meral', - 'Lake Elmo', - 'Malar', - 'Iacanga', - 'Ban', - 'Big Lake', - 'Aguasay', - 'Lissegazoun', - 'San Juan del Rio del Centauro del Norte', - 'Rankweil', - 'Lauenburg', - 'Eckington', - 'Khajuri', - 'Whistler', - 'Horodnia', - 'Hoyland Nether', - 'Chainpur', - 'Monte Compatri', - 'Ivybridge', - 'Sao Goncalo do Rio Abaixo', - 'Zriba-Village', - 'Imaculada', - 'Avadattur', - 'Miller Place', - 'Recreo', - 'Sixaola', - 'Vendas Novas', - 'Gberouboue', - "L'Isle-Adam", - 'Pedda Vegi', - 'Denduluru', - "Sant'Ambrogio di Valpolicella", - 'Myrne', - 'Monte di Procida', - 'Lapinig', - 'Bad Voslau', - 'Palmilla', - 'Dishashah', - 'Peonga', - 'Vellallur', - 'Torton', - 'Biltine', - 'Bibipet', - 'Lizzanello', - 'Kalipatnam', - 'Middleburg', - 'Angalakurichchi', - 'Cho Lach', - 'Trentham', - 'Chero', - 'Bordentown', - 'Wolnzach', - 'Son Servera', - 'Lahra Muhabbat', - 'Guabari', - 'Itamati', - 'Sirsia Hanumanganj', - 'Licinio de Almeida', - 'Locri', - 'Andraitx', - 'Bataredh', - 'Spilimbergo', - 'Bibbiena', - 'Mangpa', - 'Raesfeld', - 'Tiddas', - 'San Andres de Llevaneras', - 'Hirao', - 'Alum Rock', - 'Premnagar', - 'Bou Merdes', - 'La Tour-de-Peilz', - 'Areal', - 'Hemsbach', - 'San Pedro La Laguna', - 'Korahia', - 'Oiwa', - 'Pilis', - 'Endwell', - 'Rasulpur', - 'Vecchiano', - 'Ukrainsk', - 'Poulsbo', - 'Oestrich-Winkel', - 'Baranzate', - 'North Union', - 'Gross-Enzersdorf', - 'Camposampiero', - 'Chilonga', - 'Tapiratiba', - 'Leingarten', - 'Lauffen am Neckar', + 'Rayappanpatti', + 'Nanuque', + 'Zhutailing', + 'Bovec', + 'Villa Riva', + 'Sanza Pombo', + 'Brossard', + 'Olbia', + 'Bredene', + 'Kaliro', + 'Joetsu', + 'Kruszwica', + 'Surajpura', + 'Primeira Cruz', + 'Hanumana', + 'Ghattupal', + 'Changamkari', + 'Bistrita', + 'Les Herbiers', + 'As Suqaylibiyah', + 'Quebec City', + 'Wiehl', + 'Waltrop', + 'Kadiana', + 'Tadapurambakkam', + 'Delportshoop', + 'Pinghu', + 'Bad Endorf', + 'Singarayakonda', + 'Prestwich', + 'Weesp', + 'Itamukkala', + 'Ad Dab`ah', + 'Salvador', + 'Weipa', + 'Agdam', + 'Tolu Viejo', + 'Erzincan', + 'Arfoud', + 'Giulianova', + 'El Paso de Robles', + 'Pedda Nindrakolanu', + 'Shawangunk', + 'Flamanzi', + 'Icod de los Vinos', + 'Vatananto', + 'Frattaminore', + 'Sterling Heights', + 'Zhongliao', + 'Tirmalgiri', + 'Deutsch-Wagram', + 'Peddaboddepalle', + 'Kilosa', + 'Gulbaar', + 'Malema', + 'Novo Horizonte', + 'Blairgowrie', + 'Nieder-Olm', + 'Pertuis', + 'Xacmaz', + 'Tenerife', + 'Krishnapuram', + 'Molndal', + 'Luba', + 'Puttalam', + 'Jegunovce', + 'Kauniainen', + 'Zapatoca', + 'Abong Mbang', + 'Tiana', + 'Ryki', + 'Mitai', + 'Mullingar', + 'Dom Pedro', + 'Simiti', + 'Naguilian', + 'Roccapiemonte', + 'Lanaken', + 'Svatove', + 'Salto del Guaira', + 'Liman', + 'Paisley', + 'Skwierzyna', + 'Balagtas', + 'Belma', + 'Olathe', + 'Kumil', + 'Hamworthy', + 'Solwezi', + 'Fucheng', + 'Lanivo', + 'Dao', + 'Putao', + 'Rafaela', + 'Yozgat', + 'Sao Joao da Boa Vista', + 'Sapanca', + 'Prebold', + 'Gwangyang', + 'Imerintsiatosika', + 'Munnalam', + 'Tizayuca', + 'Sorso', + 'Anah', + 'Locarno', + 'Wageningen', + 'Muhammadganj', + 'Binangonan', + 'San Gregorio de Nigua', + 'Oneonta', + 'Bole', + 'Mannara', + 'Darnah', + 'Habo', + 'Aubagne', + 'Pinili', + 'Ostuni', + 'Jitwarpur Chauth', + 'Mainaschaff', + 'Inderbor', + 'Westlake', + 'Esher', + 'Gaimersheim', + 'Fort Knox', + 'Tiruvambadi', + 'Towada', + 'Kasangulu', + 'Chernihiv', + 'Pardubice', + 'Ekibastuz', + 'Tramore', + 'Luchenza', + 'Asarganj', + 'Mascalucia', + 'Bartica', + 'Ipixuna', + 'Gainza', + 'Buea', + 'Puerto Concordia', + 'Mohammadabad', + 'Kindia', + 'Kadingilan', + 'Amboasary-Gara', + 'Kanchanadit', + 'Sabaneta', + 'Amingaon', + 'Los Polvorines', + 'Catano', + 'Alto Longa', + 'Zharkent', + 'Samba', + 'Hempstead', + 'Arandelovac', + 'Ghogha', + 'Cluses', + 'Kumarapalaiyam', + 'Warendorf', + 'Ath', + 'Thanh Xuan', + 'Esik', + 'Luneville', + 'Burgstadt', + 'Deggendorf', + 'Kozlu', + 'Abdullahnagar', + 'Penarroya-Pueblonuevo', + 'Curug', + 'Cosmopolis', + 'Schoningen', + 'Desri', + 'Tandubas', + 'Masiu', + 'Petawawa', + 'Buxerolles', + 'Wazirabad', 'Wath upon Dearne', - 'Toualet', - 'Barokhar', - 'Sidi Amer El Hadi', - 'Mountougoula', - 'Wargal', - 'Menfi', - 'Jataizinho', - 'Langgons', - 'Walldurn', - 'Barrafranca', - 'Befandefa', - 'Tikar', - 'Holalu', - 'Senirkent', - 'Castle Pines', - 'Bocaina', - 'Dolo Bay', - 'Yakushima', - 'Portela', - 'Mboro', - 'Sonosari', - 'Chateau-Gontier', - 'Street', - 'South Yarmouth', - 'Virgem da Lapa', - 'Oberderdingen', - 'Winfield', - 'Picayune', - 'Oswaldtwistle', - 'Kakalur', - 'Ghabaghib', - 'Thogapalle', - 'Muscoy', - 'Serra do Salitre', - 'Jalalaqsi', - 'Hobyo', - 'Beladi', - 'Little Chute', - 'Portoferraio', - 'Barapire', - 'Deerlijk', - 'Oued Cheham', + 'Agios Athanasios', 'Novi Marof', - 'Sanpetru', - 'Neuenrade', - 'Fenoughil', - 'Oued Seguin', - 'Maizieres-les-Metz', - 'Susegana', - 'Le Relecq-Kerhuon', - 'Srirampuram', - 'Khanaqin', - 'Mountain Top', - 'Santa Cruz Michapa', - 'Axixa', - 'Somain', - 'Zao', - 'Muping', - 'Spreitenbach', - 'Kete Krachi', - 'Tortoreto', - 'Biknur', - 'Tiny', - 'Zwonitz', - 'Ryuo', - 'Cafayate', - 'Aougrout', - 'Vegarai', - 'Roda', - 'Hauzenberg', - 'Ngerengere', - 'Ronchi dei Legionari', - 'Portomaggiore', - 'Oak Hills', - 'Villecresnes', - 'Kehen', - 'Fiume Veneto', - 'Baitoa', - 'Yeniciftlik', - 'Pritzwalk', - 'Leutenbach', - 'Chiautla de Tapia', - 'Sidi Ladjel', - 'Olivenza', - 'Tarrytown', - 'Bechloul', - 'Sahasmal', - 'Vauvert', - 'Khansahibpuram', - 'Market Drayton', - 'Borgaro Torinese', - 'Alamedin', - 'Putnam Valley', - 'Negele', - 'Green River', - 'Pragatinagar', - 'Burgthann', - 'Sao Goncalo do Para', - 'Kankaanpaa', - 'Allur', - 'Sipalakottai', - 'Kotha Guru', - 'Bitetto', - 'Show Low', - 'Baranivka', - 'Brotas de Macaubas', - 'Guttenberg', - 'Mack', - 'Drolshagen', - 'Campos del Puerto', - 'Cogolin', - 'Hankey', - 'Soderhamn', - 'Tifni', - 'Batocina', - 'Picana', - 'Owk', - 'Agcogon', - 'Tornquist', - 'Jaitwar', - 'Kornepadu', - 'Alken', - 'Annakattumula', - 'Pastpar', - 'Sher Muhammadpuram', - 'Mapleton', - 'Bopfingen', - 'Hawkesbury', - 'Blace', - 'Elektrenai', - 'Kuchinarai', - 'Moncion', - 'Possneck', - 'Bad Durrenberg', - 'Agadi', - 'Jose Maria Morelos', - 'Waldniel', - 'Tiruvadanai', - 'Rajaram', - 'Padinjaremuri', - 'Murukondapadu', - 'Lawrenceburg', - 'Abhia', - 'Edeia', - 'Chinaval', - 'Tolcayuca', - 'Francofonte', - 'Bajiao', - 'Cernay', - 'Konand', - 'Bilopillya', - 'Rossmoor', - 'Kamianka', - 'Ovidiopol', - 'An Cabhan', - 'Bajestan', - 'Muong Theng', + 'Chotebor', + 'Ciudad General Belgrano', + 'Kitaibaraki', + "'s-Gravenzande", + 'Wellington North', + 'Jiuduhe', + 'Villingen-Schwenningen', + 'Stockbridge', + 'Wauconda', + 'Kayyngdy', + 'Sultandagi', + 'Torshavn', + 'Wadala Sandhuan', + 'Nordkirchen', + 'Nandikotkur', + 'Geisenheim', + 'Shirvan', + 'Port Victoria', + 'Santo Antonio de Jesus', + 'Matulji', + 'Bagaces', + 'Thisted', + 'Perur', + 'Coreau', + 'Chitose', + 'Marka', + 'Weener', + 'Barrinha', + 'Limburg', + 'Qazax', + 'Itapa-Ekiti', + 'Cajetina', + 'Bendougouba', + 'Buriti do Tocantins', + 'Uppur', + 'Hikari', + 'Parnarama', + 'Hammerfest', + 'Alcala la Real', + 'Deolali', + 'Arukutti', + 'Dar Si Aissa', + 'Ratia', + 'Gangaura Behra', + 'Mehdya', + 'Vagos', + 'Ramdeora', + 'Saint Helena Bay', + "'Ain Fekan", + 'Saint-Germain-les-Arpajon', + 'Farrukhabad', + 'Palmeiras', + 'Saint-Lo', + 'Marwa', + "Khmis Sidi al 'Aydi", + 'San Joaquin', + 'Koteshwar', + 'Pandalkudi', + 'Kukawa', + 'Lydney', + 'Kanchanpalli', + 'Chlef', + 'Moquegua', + 'Yanguancun', + 'Dalavaypattanam', + 'Gundlupet', + 'Sabinov', + 'Praia Grande', + 'Tamba-Sasayama', + 'Dachengzicun', + 'Biloziria', + 'Sanaur', + 'Rudehen', + 'Palmares', + 'Fairfax Station', + 'Bangor', + 'Mula', + 'North Chicago', + 'Koencho', + 'Mahibadhoo', + 'Vallejuelo', + 'Cajola', + 'Mvurwi', + 'Jinku', + 'Zgorzelec', + 'Barnstable', + 'San Ignacio de Velasco', + 'Fuquan', + 'Bayan Lepas', + 'Clovis', + 'Kappeln', + 'Ivaipora', + 'Piraquara', + 'Capul', + 'Sieradz', + 'Mombasa', + 'Bayawan', + 'Kahrizak', + 'Rohnert Park', + 'Ouzera', + 'Mampong', + 'Mezokovesd', + 'Briceni', + 'Pedara', + 'Koch Bihar', + 'Thaba Nchu', + 'Dehti', + 'Sebnitz', + 'Metz', + 'Mansa', + 'Sanwer', + 'Bingawan', + 'Vechur', + 'Kirkja', + 'Tororo', + 'Miandasht', + 'Peringom', + 'Nambutalai', + 'Zarafshon Shahri', + 'Deer Park', + 'Atalaia', + 'Congleton', + 'Srebrenik', + 'Rauch', + 'Slavuta', + 'Vengattur', + 'Bokoro', + 'Pureparo de Echaiz', + 'Osijek', + 'Divrigi', + 'East San Gabriel', + 'Gapan', + 'Comilla', + 'Ropar', + 'Oak Bay', + 'San Felipe', + 'Dinmanpur', + 'Konigslutter am Elm', + 'Nittenau', + 'Ardahan', + 'Kelaa Kebira', + 'Gulcho', + 'Sanzhou', + 'Albinea', + 'Acireale', + 'Wadegaon', + 'Australind', + 'Yaopu', + 'Ramnagar', + 'Tummalacheruvu', + 'Morretes', + 'Askoy', + 'Teziutlan', + 'Tupiza', + 'Monastir', + 'Dumri', + "Estrela d'Oeste", + 'Ribeirao Pires', + 'Holesov', + 'Ghatal', + 'Santa Maria Huatulco', + 'Vleuten', + 'Ambatomiady', + 'Isale', + 'Chalmette', + 'Tirukkoyilur', + 'Ishikari', + 'Lunglei', + 'Desuri', + 'Kaikoura', + 'Vaghodia', + 'Al Fayd', + 'Kahoku', + 'Bettendorf', + 'Palafolls', + 'Hadzici', + 'Jocoro', + 'Nanto', + 'Botelhos', + 'St. Clair Shores', + 'Rahon', + 'Monte Santo', + 'Watsonville', + 'Shankar Saraiya', + 'Zlin', + 'Maner', + 'Sauce', + 'Pudupattanam', + 'Midalt', + 'Jarinu', + 'Goma', + 'Laqtah', + 'Ghorbanki', + 'Nehoiu', + 'Comayaguela', + 'Sardhana', + 'Butiama', + 'Novo Hamburgo', + 'Isahaya', + 'Rouiba', + 'Minatitlan', + 'Devikolam', + 'Putatan', + 'Ala', + 'Sirsi', + 'Lawrence', + 'Sarapaka', + 'Turmalina', + 'Yaguara', + 'Tongjin', + 'Monte Alegre de Minas', + 'Nesher', + 'Morsand', + 'Rafsanjan', + 'Brisbane', + 'Rheinberg', + 'Assamannur', + 'Unterageri', + 'Sanquelim', + 'Steinhaus', + 'Banja Luka', + 'Guaimaro', + 'Luquembo', + 'Ambatomarina', + 'Kucove', + 'Thilogne', + 'Sangereng', + 'Beni Saf', + 'Itabela', + 'Woodfield', + 'Sandavagur', + 'Drobak', + 'Fuldabruck', + 'San Luis Obispo', + 'Chandralapadu', + 'Kanp', + 'Sainte-Sophie', + 'Karakopru', + 'Maple Grove', + 'Yachiyo', + 'Wuling', + 'Foammulah', + 'Mouvaux', + 'Gorizia', + 'Umarkot', + 'Forestdale', + 'Rawatbhata', + 'Bongaree', + 'Jalingo', + 'Koog aan de Zaan', + 'Lapy', + 'Rayleigh', + 'Khandsa', + "Fontaine-l'Eveque", + 'Den Helder', + 'Nanmucun', + 'Sakaraha', + 'Flixton', + 'Magenta', + 'Muroto-misakicho', + 'Panhar', + 'Ait Ourir', + 'Mawkanin', + 'Cheadle', + 'Kuusamo', + 'Velivennu', + 'Espoo', + 'Kakhandiki', + 'Kortenberg', + 'Krasnodon', + 'Hennigsdorf', + 'Olmos', + 'Maropaika', + 'Mahadipur', + 'Itatuba', + 'Uckfield', + 'Belle Glade', + 'Acatlan de Osorio', + 'Elfers', + 'Al Jumayl', + 'Hatsukaichi', + 'At Tall', + 'Uzynaghash', + 'Beatrice', + 'Frogn', + 'Yao', + 'Monfort Heights', + 'El Mansouria', + 'Sileby', + 'Emerald', + 'Alubijid', + 'Llanquihue', + 'Yerrapalem', + 'Tuguegarao', + 'Tiel', + 'Mahallat', + 'Varena', + 'Cherukunnu', + 'Lahat', + 'Nevsehir', + 'Suonan', + 'Cloncurry', + 'Chikhli Kalan', + 'Vedasandur', + 'Coyaima', + 'Yinajia', + 'Rewtith', + 'Villa Adelina', + 'Siur', + 'Urucania', + 'Petrinja', + 'Bruntal', + 'Wietmarschen', + 'Tumkur', + 'Qana', + 'Darlowo', + 'Qamdo', + 'Nova Gradiska', + 'Barhiya', + 'Balighattam', + 'St. Petersburg', + 'Paglat', + 'Nauhata', + 'Derdara', + 'Barai', + "King's Lynn", + 'San Pablo Tacachico', + 'Presidente Bernardes', + 'Elizabethton', + 'Ezhou', + 'Kallamalai', + 'Estrela', + 'Tuburan', + 'Solapuram', + 'Dohta', + 'Yazihan', + 'Monett', + 'Mayang Imphal', + 'Starse', + 'Chilon', + 'Libano', + 'Raneswar', + 'Raydah', + 'Tanjungpandan', + 'Puning', + 'Cabreuva', + 'Shoufeng', + 'Ipecaeta', + 'Lujan', + 'Sultanhisar', + 'Kaynarca', + 'Mwanza', + 'Newport', + 'Beypazari', + 'Ramshir', + 'Trakai', + 'Mohiuddinnagar', + 'Geddes', + 'Rinteln', + 'Nagarur', + 'Bagra', + 'Polkowice', + 'Ban Sathan', + 'Cotonou', + 'Trier', + 'Odenthal', + 'Oyim', + 'Tajarhi', + 'Birigui', + 'Moravske-Toplice', + 'Tatebayashi', 'Serravalle Pistoiese', - 'Carignan', - 'Ban Phan Don', - 'Scharbeutz', - 'Lindenberg im Allgau', - 'Vasylkivka', - 'Medina Sidonia', - 'Chaltabaria', - 'Vengavasal', - 'Palleja', - 'Yamamoto', - 'Lunenburg', - 'San Nicolas de los Ranchos', - 'General Cabrera', - 'Septemes-les-Vallons', - 'Hackney', - 'Chintapalle', - 'Rio Colorado', - 'Dinara', - 'Chaumont-Gistoux', - 'Zhetibay', - 'Altstatten', - 'Hardiya', - 'Sveti Nikole', - 'Mestrino', - 'Los Alamitos', - 'Mutia', - 'Ambatofisaka II', - 'Cossimbazar', - 'Shady Hills', - 'Irupi', - 'Koszeg', - 'Golub-Dobrzyn', - 'Baghauni', - 'Appingedam', - 'Guatajiagua', - 'Kruje', - 'Deutschlandsberg', - 'Nellipoyil', - 'Villefranche-de-Rouergue', - 'Carmiano', - 'Soalandy', - 'Aleksandrow Kujawski', - 'Chundal', - 'Auta', - 'Wetherby', - 'Nandimandalam', - 'Saaminki', - 'Spring Lake', - 'Ubai', - 'Macusani', - 'Costa de Caparica', - 'Sindalakkundu', - 'Malka', - 'Lantana', - 'Bithan', - 'Sowerby Bridge', - 'Semri', - 'Rattihalli', - 'Lower Burrell', - 'Bol', - 'Nakasongola', - 'Gatumba', - 'Chakai', - 'Geisenheim', - 'Tamezmout', - 'Sengurichchi', - 'Ujhana', + 'Targuist', + 'Datu Paglas', + 'Aral', + 'Mazarron', + 'Dank', + 'Elk City', + 'Chandankiari', + 'Shatiancun', + 'Kakamas', + 'Sikat', + 'Bhawanandpur', + 'Stone Ridge', + 'Kushimoto', + 'Great Wyrley', + 'Tall Banat', + 'Yunfu', + 'Westville', + 'Karkamis', + 'Ingabu', + 'Rensselaer', + 'Tonbridge', + 'Phai Sali', + 'Vaiano', + 'Bikramganj', + 'Nawsari', + 'Akcaabat', + "Al Qa'im", + 'Carambei', + 'Boloso', + 'Shijiazhuangnan', + 'Sidi Lahsene', + 'River Edge', + 'Shuozhou', + 'Walnut Park', + 'Ben Chicao', + 'Eggenfelden', + 'Floriano', + 'Sevilimedu', + 'Vesoul', + 'Chinna Kalaiyamputtur', + 'Los Cordobas', + 'Malimono', + 'Eslamabad-e Gharb', + 'Akersberga', + 'Bhaktapur', + 'Tokha', + 'Egelsbach', + 'Windham', + 'Shantou', + 'Joyo', + 'Asni', + 'Camacan', + 'Lomas de Zamora', + 'Pedernales', + 'Presidente Medici', + 'Itabirito', + 'Heris', + 'Zarraga', + 'Korgas', + 'Horti', + 'Aksaray', + 'Ghal Kalan', + 'Apex', + 'Tummapala', + 'Vavveru', + 'Maumee', + 'Chicomba', + 'La Madeleine', + 'Mekra', + 'Mataquescuintla', + 'Sitio do Quinto', + 'Khanah Sur', + 'World Golf Village', + 'Mambore', + 'Limoux', + 'Hinode', + 'Spodnji Duplek', + 'Yancheng', + 'Patia', + 'Caiguantun', + 'Gualdo Tadino', + 'Fulshear', + 'Dacun', + 'Nawabshah', + 'Sannicolau Mare', + 'Zontecomatlan de Lopez y Fuentes', + 'Devanangurichchi', + 'Kovur', + 'Manikganj', + 'Qal`ah-ye Zal', + 'Schuttorf', + 'Fushun', + 'Tsuruno', + 'Sikhio', + 'Tomelloso', + 'Israin Kalan', + 'Dinajpur', + 'Douar Oulad Mbarek', + 'Afanyangan', + 'North Branch', + 'Pattukkottai', + 'Malo Crnice', + 'Taboao da Serra', + 'Kathurah', + 'Tottori', + 'Gundlapelle', + 'Dusseldorf', + 'Guisser', + 'Abuyog', + 'Sabalgarh', + 'Cabugao', + 'Pata Kalidindi', + 'Mountain Top', + 'Limonar', + 'Urupes', + 'Mudhol', + 'Peranampattu', + 'Deyr', + 'San Enrique', + 'Santa Lucia', + 'Ghoriyan', + 'Pervomaiskyi', + 'Obikiik', + 'Jauli', + 'Grevenbroich', + 'Chupaca', + 'Ban Bueng Kok', + 'Rada`', + 'Chapeltique', + 'Ghazipur', + 'Barcarena Nova', + 'Kayaralam', + 'Saint-Gilles', + 'Crosby', + 'Tatahuicapan', + 'Nedumangad', + 'Meitingen', + 'Matomou', + 'Balud', + 'Yatou', + 'Stephanskirchen', + 'Same', + 'Rome', + 'Oud-Heverlee', + 'Mau Dhaneshpur', + 'Sparks', + 'Kyotango', + 'Hirokawa', + 'Kahama', + 'General Emilio Aguinaldo', + 'Bozhou', + 'Areiopolis', + 'Izumisano', + 'Karmauli', + 'Itele', + 'Ghedi', + 'Champdani', + 'Ringas', + 'Istog', + 'Madre de Deus', + 'San Jose', + 'Duraiswamipuram', + 'Kele', + 'Andujar', + 'Erdemli', + 'Iwakuni', + 'Clarines', + 'Saint-Martin-de-Crau', + 'Kankipadu', + 'Bantayan', + 'Kilibo', + 'Kerpen', + 'Moultrie', + 'Belaur', + 'Juan Rodriguez Clara', + "P'yongch'ang", + 'Verukulambu', + 'Esenyurt', + 'Ban Muang Ngam', + 'Wako', + 'Yankou', + 'Radeberg', + 'Haddada', + 'Mill Creek East', + 'Szekesfehervar', + 'Lower Saucon', + 'Lijiacha', + 'Xushan', + 'Tumauini', + 'Molakalumuru', + 'Mayureswar', + 'Gnarrenburg', + 'Kefamenanu', + 'Lockhart', + 'Pulgaon', + 'El Palmar', + 'Champlain', + 'Adalpur', + 'Omboue', + 'Yueyaquan', + 'Melila', + 'Potomac Park', + 'Barranqueras', + 'Santa Cruz de la Sierra', + "Yan'an", + 'Talwara', + 'Kod', + 'Hechi', + 'Green Bay', + 'Murzuq', + 'Farnham', + 'Roznava', + 'Merate', + 'Nathana', + 'Malakwal', + 'Buhi', + 'Tadepallegudem', + 'Monastyryshche', + 'Sneek', + 'Gaoshu', + 'Pergine Valsugana', + 'Fond des Blancs', + 'College', + 'Liuliang', + 'Huilongcun', + 'Ballymena', + 'Fitampito', + 'Herzogenaurach', + 'Weilheim', + 'Melegnano', + 'Coribe', + 'Thondiamannu', + 'Bermejo', + 'Granville', + 'Retalhuleu', + 'Mayari', + 'Tall Qasab', + 'Bisaria', + 'Bellinzona', + 'Klodzko', + 'Dessalines', + 'Zamosc', + 'Village St. George', + 'Sturgis', + 'Sanyi', + 'Vennandur', + 'El Paso', + 'Andurkonam', + 'Zitsa', + 'Dainyor', + 'Kaysville', + 'Tijucas do Sul', + 'Cap-Haitien', + 'Linslade', + 'Banki', + 'Santo Antonio do Amparo', + 'Diapaga', + 'Buqda Caqable', + 'Cochabamba', + 'Irthlingborough', + 'Ena', + 'Donostia', + 'Dippoldiswalde', + 'Gisenyi', + 'As Sanamayn', + "Capo d'Orlando", + 'Bahcesaray', + 'Yamanouchi', + 'Balangkas', + 'Mihona', + 'Ambodimandresy', + 'El Mirage', + 'Gazojak', + 'Marvast', + 'Etzatlan', + 'Sicklerville', + 'Pocao', + 'Nicoadala', + 'Belo Campo', + 'Maina', + 'Piripiri', + 'Bani Hasan ash Shuruq', + 'McComb', + 'Southeast', + 'Cavriglia', + 'Kole', + 'Granger', + 'Rivera', + 'Ponferrada', + 'St. Anthony', + 'Queanbeyan', 'Rangsdorf', - 'Olhanpur', - 'Risca', - 'Tibbar', - 'Elma', - 'Ringwood', - 'Kissing', - 'Vellar', - 'Zarach', - 'Ibira', - 'Waltikon', - 'Nova Gradiska', - 'Angel R. Cabada', - 'Hildburghausen', - 'Barkagaon', - 'James Island', - 'Schwaigern', - 'Rostam Kola', - 'Lom Sak', - 'Jaco', - 'Irmo', - 'Sao Bento do Sapucai', - 'Luis Alves', - 'Malial', - 'Mallikkundam', - 'Izola', - 'Peiting', - 'Hollabrunn', - 'Conceicao do Castelo', - 'Billerbeck', - 'Seven Hills', - 'Saint-Pierre-du-Perray', - 'Venkidanga', - 'Tirodi', - 'Torri di Quartesolo', - 'Ulverston', - 'Sothgaon', - 'Cornedo Vicentino', - 'Signal Hill', - 'Center', - 'Kibi', - 'Bellmawr', - 'Peligros', - 'Elland', - 'Prudhoe', - 'Kiskunmajsa', - 'Vilandai', - 'Bokakhat', - 'Alahina', - 'Bolsover', - 'Randaberg', - 'Skofja Loka', - 'Talakad', - 'Fgura', - 'Sao Sebastiao do Uatuma', - 'Kautalam', - 'Limburgerhof', - 'Keolari', - 'Nellipaka', - 'Karanchedu', - 'Vermillion', - 'Bayyanagudem', - 'Dent', - 'Elavalli', - 'Chittattukara', - 'Bullas', - 'Tiszakecske', - 'Narasapuram', - 'Hallbergmoos', - 'Bryn', - 'Lanham', - 'Sassenage', - 'Ponte San Pietro', - 'Marotta', - 'Bagaura', - 'Stokke', - 'Berlaar', - 'Bhainsahi', - 'Jardim do Serido', - 'Zofingen', - 'San Pedro Ixcatlan', - 'Lajosmizse', - 'La Riviera', - 'Raubling', - 'Nandavaram', - 'Panamaram', - 'Yirol', - 'Sukurhutu', - 'Lakri', - 'Jangy-Kyshtak', - 'Lessogou', - 'Mixtla de Altamirano', - 'Samesi', - 'Isaszeg', - 'Newport East', - 'Emmaus', - 'Bucyrus', - 'Isaka', - 'Ansiao', - 'Kattakampala', - 'Isapur', - 'Mitai', - 'Mendota Heights', - 'Brock', - 'Mount Sinai', - 'Carver', - 'Cowdenbeath', - 'Zaoqiao', - 'Kizhakkanela', - 'Miami Shores', - "L'Ile-Perrot", - 'Durbuy', - 'Dhanaura', - 'Kunkalagunta', - 'Azcoitia', - 'Lundazi', - 'Bolbec', - 'Sonada', - 'Hemiksem', - 'Karmauli', - 'Siur', - 'Nzeto', - 'Guaicara', - 'Thiers', - 'Knin', - 'Half Moon Bay', - 'Angicos', - 'Utiel', - "Diao'ecun", - 'Motegi', - 'Tlachichilco', - 'Derassi', - 'Burnham', - 'Ermenek', - 'Dammapeta', - 'Weiz', - 'Pongode', - 'Kallakkudi', - 'Pepperell', - 'Porecatu', - 'Bayou Blue', - 'Ostrhauderfehn', - 'Nawa Nagar Nizamat', - 'Lubaczow', - 'Henley on Thames', - 'Middle Valley', - 'Lenvik', - 'Annappes', - 'Ban Mae Tuen', - 'Mahta', - 'Santa Cruz Itundujia', - 'Moulay Driss Zerhoun', - 'Balaxani', - 'Ielmo Marinho', - 'Kotra', - 'Summerland', - 'Mala Vyska', - 'Baghambarpur', - 'Saint-Gaudens', - 'Manabo', - 'Ibicuitinga', - 'Xexeu', - 'Castello de Ampurias', - 'Ziyodin Shaharchasi', - 'Pirauba', - 'Veyrier', - 'Rokiskis', - 'Ambohimahasoa', - 'Sint Anthonis', - 'Betmangala', - 'Geisenfeld', - 'Qasr-e Qand', - 'Rayavaram', - 'Kalmiuske', - 'Ascot', - 'Sunninghill', - 'Wolmirstedt', - 'Gararu', - 'Abertillery', - 'Sewai', - 'Kolnad', - 'Cadale', - 'Tafaraoui', - 'Wallingford', - 'Schiller Park', - 'Fuente de Oro', - 'Devipattinam', - 'Gansbaai', - 'Shuinancun', - 'Aduru', - 'Santa Comba Dao', - 'Jiquipilas', - 'Cangas de Narcea', - 'Renapur', - 'Hartsville', - 'Mombris', - 'Guraahai', - 'Phon', - 'Bassersdorf', - 'Halsur', - 'Ankli', - 'Huandacareo', - 'Zero Branco', - 'Chambray-les-Tours', - 'Sablan', - 'Ross-Betio', - 'Tummalacheruvu', - 'Weeze', - 'Sakib', - 'St. Clements', - 'Khimlasa', - 'Morur', - 'Casteldaccia', - 'Gainza', + 'Rio Grande da Serra', + 'Carrieres-sur-Seine', + 'Brookhaven', + 'Lauderhill', + 'Puerto Jimenez', + 'Casas Adobes', + 'Aligudarz', + 'Buchireddipalem', + 'Mae Sai', + 'Guarai', + 'Sprimont', + 'Huizucar', + 'Teano', + 'Liria', + 'Zhemgang', + 'Funing', + 'Amorebieta', + 'Irece', + 'Bansang', + 'Shizukuishi', + 'Kummarapurugupalem', + 'Buzovna', 'Vadakkumbagam', - 'Kurabalakota', - 'Novoishimskiy', - 'Roessleville', - 'Yercaud', - 'Minnehaha', - 'Moss Bluff', - 'Oulad Friha', - 'Santa Genoveva de Docordo', - 'San Josecito', - 'Wichelen', - 'Ipaporanga', - 'Town and Country', - 'View Royal', - 'Gopalapuram', - 'Le Haillan', - 'Naigarhi', - 'Jethuli', - 'Castenedolo', - 'Bahadarpur', - 'Pettaivayttalai', - 'Jarabulus', - 'Haradok', - 'Jidigunta', - 'Okuizumo', - 'Ban Mae Kham Lang Wat', - 'Ban Wiang Phan', - 'Caraguatay', - 'Schwieberdingen', - 'River Forest', - 'Santa Cruz da Baixa Verde', - 'Onate', - 'Isola della Scala', - 'Pampas', - 'Kennebunk', - 'Eijsden', - 'Landsmeer', - 'Nieuwpoort', - 'Gold Canyon', - 'Gardere', - 'Puerto Suarez', - 'Uberherrn', - 'Loutraki', - 'Ghal Kalan', - 'Kushmanchi', - 'Navarro', - 'Kopervik', - 'Yangiqo`rg`on', - 'Xiaoba', - 'Messstetten', - "Ghinda'e", - 'Mistelbach', - 'Sathmalpur', - 'Khandpara', - 'Belgrave', - 'Aracas', - 'Perches', - 'Gulgam', - 'Cisneros', - 'Anatoli', - 'Stuarts Draft', - 'Molteno', - 'Kundiawa', - 'Leama', - 'Espita', - 'Itainopolis', - 'Perumbakkam', - 'Tadapurambakkam', - 'Esil', - 'Saint-Esteve', - 'Dabrowa Tarnowska', - 'Krosuru', - 'Sussex', - 'Derdara', - 'Bugongi', - 'Broome', - 'Carmo da Cachoeira', - 'Patera', - 'Downpatrick', - 'Ghambiraopet', - 'Port Lavaca', - 'Wanstead', - 'Muroto-misakicho', - 'Platteville', - 'Den Chai', - 'Chintalavadi', - 'Holesov', - 'Labbaikkudikkadu', - 'Sidi Kasem', - 'Kibungo', - 'Mangalkot', - 'Port Morant', - 'Matca', - 'Pieve di Soligo', - 'Lamosina', - 'Weinfelden', - 'Sinzheim', - 'Nalwar', - 'Roma', - 'Taineste', - 'Krapina', - 'Kantilo', - 'Saint Helena Bay', - 'Doda', - 'Mit Damsis', - 'Sunkarevu', - 'Bahagalpur', - 'Ichhapur', - 'Moparipalaiyam', - 'Maniago', - 'Okpo', - 'Nandipeta', - 'Ekero', - 'Quatipuru', - 'Budha Theh', - 'Golet', - 'Stelle', - 'Nidamangalam', - 'Epazoyucan', - 'Sahri', - 'Ingurti', - 'Ramena', - 'Calheta', - 'Noeux-les-Mines', - 'Doddappanayakkanur', - 'Shahpur Baghauni', - 'Giffoni Valle Piana', + 'Nago', + 'Toma', + 'Barra do Ribeiro', + 'Mentone', + 'Chorhat', + 'Norrkoping', + 'Hohoe', + 'Montefiascone', + 'Dario Meira', + 'Sopetran', + 'Dras', + 'Sadpur', + 'Miryang', + 'Jagoniguda', + 'Naklo', + 'Agcabadi', + 'Kermanshah', + 'Kauswagan', + 'Barah', + 'Araujos', + 'Herculandia', + 'Sironj', + 'Varazdin', + 'Macomb', + 'Corcoran', + 'Molfetta', + 'River Vale', + 'Ban Bang Krang', + 'Cutrofiano', + 'Muh Hasan', + 'Warnes', + 'Ottobeuren', + 'Pendencias', + 'Wood-Ridge', + 'Guttikonda', + "Saint John's", + 'White Marsh', + 'Vatomandry', + 'Shrirampur', + 'Ambahita', + 'Olean', + 'Hanno', + 'Jask', + 'Navelim', + 'Camalaniugan', + 'Boumahra Ahmed', + 'Porto Real do Colegio', + 'Geneseo', + 'Risod', + 'Rio Negro', + 'Kendu Bay', + 'Soro', + 'Etawah', + 'Khed Brahma', + 'Fukuyoshi', + 'Ikot Okoro', + 'Marahra', + 'Coimbra', + 'Svitavy', + 'Urdaneta', + 'Takhatgarh', + 'Khanjahanpur', + 'Chatelet', + 'Babile', + 'Budrio', + 'Samma', + 'Konigsbach-Stein', + 'Dobris', + 'Rheine', + 'Porkeri', + 'Menzel Abderhaman', + 'Jhonkar', + 'Torrance', + 'Ladan Kara', + 'Lealman', + 'Witzenhausen', + 'Ribeira do Pombal', + 'Madhopur', + 'Villarrica', + 'Makurdi', + 'Pleasanton', + 'Gullapuram', + 'Aboisso', + 'Gravatai', + 'Chinnamanur', + 'Longjia', + 'Chinna Orampadu', + 'Bangar', + 'Summerlin South', + 'Obiliq', + 'Kurate', + 'Wentzville', + 'Vallet', + 'Moalboal', + 'Ambohidrapeto', + 'Tecozautla', + 'Passagem Franca', + 'Armthorpe', + 'Kuchai Kot', + 'Lata', + 'Kashasha', + 'Auburndale', + 'Ban Tom Klang', + 'Shendurjana', + 'Chikushino', + 'Varandarapilli', + 'Highlands', + 'Harua', + 'Namaacha', + 'Presidente Dutra', + 'Ipu', + 'Bockhorn', + 'Davangere', + 'Saint-Michel-sur-Orge', + 'Crowley', + 'Tamganj', + 'Aklera', + 'Tiruppachur', + 'Candelaria de La Frontera', + 'Sidi Aoun', + 'Verrettes', + 'El Bolson', + 'Itamaraju', + 'Corbetta', + 'Borger', + 'Kodavatipudi', + 'Poisy', + 'Kakamigahara', + 'Petite Riviere de Nippes', + 'Hammanskraal', + 'Tonami', + 'Santa Maria Jalapa del Marques', + 'Los Palacios', + 'Rolim de Moura', + 'Ambahatrazo', + 'North Little Rock', + 'Cheyyar', + 'Masakkavundanchettipalaiyam', + 'Moorhead', + 'Khamir', + "L'Assomption", + 'Galliate', + 'Bad Zwischenahn', + 'Tiruvadi', + 'Ferreira do Zezere', + 'Brecht', + 'Mampikony', + 'La Pointe', + 'Ulipuram', + 'Rubizhne', + "Sant'Angelo in Lizzola", + 'Charkhari', + 'Atascocita', + 'Ternitz', + 'Olfen', + 'Hughenden', + 'Getulina', + 'Kewatgawan', + 'Konza', + 'Ocean', + 'Koziatyn', + 'Epanomi', + 'Mattul', + 'Meise', + 'Hazrat Shiura', + 'Plzen', + 'Tokunoshima', + 'Guelmim', + 'Targu Neamt', + 'Fugu', + 'Petroupoli', + 'Cueramaro', + 'Karaman', + 'Palmira', + 'Rajasur', + 'Calenzano', + 'Puerto Cabello', + 'Kaizu', + 'Pavullo nel Frignano', + 'Embalse', + 'Pocatello', + 'Milngavie', + 'Cachoeira de Minas', + 'Barra', + 'Savanette', + 'Surbo', + 'Ronda Alta', + 'Baghlia', + 'Chanasma', + 'Waterlooville', + 'Stord', + 'Kapiri Mposhi', + 'Plombieres', + 'Khutubi', + 'Pobe', + 'Trashi Yangtse', + 'Cranston', + 'Capinota', + 'Itambe', + 'Undi', + 'South Lyon', + 'St. George', + 'Anlu', + 'Anantavur', + 'Lake Arrowhead', + 'Kankuria', + 'Mellacheruvu', + 'Novy Bor', + 'Palacaguina', + 'La Corredoria', + 'Somerset', + 'Encrucijada', + 'Rampur Tilak', + 'Bay Point', + 'Changhua', + 'Ousseltia', + "Finch'a'a", + 'Ap Binh Thanh', + 'Coonoor', + 'Nachikatsuura', + 'Shanhur', + 'Proserpine', + 'Melavayi', + 'Celebration', + 'Chalkari', + 'Pedda Pendyala', + 'Aravakkurichchi', + 'Oranjemund', + 'Langfang', + 'Jinjiang', + 'Ziracuaretiro', + 'Misseni', + 'El Ayote', + 'Penamaluru', + 'Kadinamkulam', + 'Villa Hidalgo', + 'Hallandale Beach', + 'Periya Semur', + 'Ifakara', + 'Baucau', + 'Cesa', + 'Antiguo Cuscatlan', + 'Barnstaple', + 'Grottammare', + 'Rottenburg an der Laaber', + 'Befasy', + 'Nusaybin', + 'White Bear Lake', + 'Joaquin V. Gonzalez', + 'Dorval', + 'Raghopur', + 'La Garde', + 'Laukaha', + 'Chawalhati', + 'Burnham', + 'Padinska Skela', + 'Bilehra', + 'Rosemead', + 'Grafton', + 'Diemen', + 'Centre de Flacq', + 'Yomra', + 'Attanur', + 'Haspra', + 'Liquica', + 'Mala Vyska', + 'Sanger', + 'Ban Kat', + 'Miami', + 'Karmegh', + 'Montmelo', + 'Santa Cruz Verapaz', + 'Sao Gabriel', + 'Jose Marmol', + 'Wallisellen', + 'Izumiotsu', + 'Mashhad Rizeh', + 'Tiszafoldvar', + 'Limoges', + 'Kuzhippilli', + 'Vergara', + 'Bukavu', + 'Awasa', + 'Rusera', + 'Baragoi', + 'Coolidge', + 'Karjan', + 'Jagannathpur', + 'Somireddipalle', + 'Hamura', + 'Domchanch', + 'Salama', + 'Charmahin', + 'Ocotlan', + 'Cajidiocan', + 'Dembecha', + 'Great Sankey', + 'Katsepy', + 'Casteel', + 'Netapur Tanda', + 'Vangviang', + 'Lala Musa', + 'Treia', + 'Coon Rapids', + 'Jaromer', + 'Sociedad', + 'Ganda', + 'Belao', + 'Una', + 'Feijo', + 'Halen', + 'Courrieres', + 'Rendsburg', + 'Djangoa', + 'Gotse Delchev', + 'Pematangsiantar', + 'City of Isabela', + 'Traversetolo', + 'Sahuria', + 'Hardia', + 'Bhagwanpur Desua', + 'Karamay', + 'Dammennu', + 'Pedra Preta', + 'Zakiyah', + 'Wagner', + 'Naka', + 'Searcy', + 'Pak Chong', + 'Kreuzau', + 'Ammur', + 'Curimata', + 'Oued Lill', + 'Esplanada', + 'Dagana', + 'Villalba', + 'Qorovulbozor', + 'Mengdan', + 'Kenosha', + 'Lumbatan', + 'Beyla', + 'Billdal', + 'Barao do Grajau', + 'Antsatramidola', + 'Moirang', + 'Jalakati', + 'Sakhipur', + 'Tyler', + 'Gornji Milanovac', + 'Ootacamund', + 'Luruaco', + 'Cowra', + 'Jenison', + 'Dar`a', + 'Guamare', + 'Palatka', + 'Brooklyn Center', + 'Bondo', + 'Paracuellos de Jarama', + 'Troon', + 'Passy', + 'Laredo', + 'Rubim', + 'Brand-Erbisdorf', + 'Pofadder', + 'Itzehoe', + 'Yuyao', + 'Sao Carlos', + 'Jiangdi', + 'Avon', + 'Mission Viejo', + 'Mbaiki', + 'Kakan', + 'Aland', + 'Marlborough', + 'Mesetas', + 'Shahrinav', + 'Kourou', + 'Kobilje', + 'Kragujevac', + 'Corigliano Calabro', + 'Jalpan', + 'Kongoussi', + 'Sursand', + 'Jiangjiadong', + 'Ja`fariyeh', + 'Fulham', + 'Jhabrera', + 'Tumberi', + 'Masunga', + 'Schellenberg', + 'Binfield', + 'Jose C. Paz', + 'Padre Garcia', + 'Tillor Khurd', + 'Alta Gracia', + 'Subotica', + 'Zaandijk', + 'Ochsenfurt', 'Cholpon-Ata', - 'Loyalsock', - 'Olintla', - 'Jucati', - 'Velke Mezirici', - 'Gorey', - 'Kundurpi', + 'Veinticinco de Diciembre', + 'Shuangtian', + 'Madalum', + 'Dianguirde', + 'Pitangui', + 'Patacamaya', + 'Kosvik', + 'Xiba', + 'Debagram', + 'Ban Na Kham', + 'Sao Francisco do Conde', + 'Stegen', + 'Bulalacao', + 'Pala Oua', + 'Pak Kret', + 'Mundahal Khurd', + 'Befotaka', + 'Gobindpura', + 'Al Aaroui', + 'Mwenga', + 'Caturama', + 'Pelengana', + 'Kandel', + 'Vila Real', + 'Bechloul', + 'Nykobing Falster', + 'Mazabuka', + 'Binka', + 'Konongo', + 'Wrzesnia', + 'Vasiana', + 'Khan Shaykhun', + 'Tolna', + 'Piedrahita', + 'Wilsele', + 'Ye', + 'Acucena', + 'Ames', + 'Ventnor City', + 'Elhovo', + 'Bajiao', + 'Torreon', + 'Lana', + 'Herrenberg', + 'Pira', + 'Pascagoula', + 'Takeo', + 'Nuevitas', + 'Foothill Farms', + 'Mogotes', + 'Los Palacios y Villafranca', + 'Tanuku', + 'Oroszlany', + 'Sanyo-Onoda', + 'Eichenau', + 'Sundapalaiyam', + 'Kanoni', + 'Dioungani', + 'Evora', + 'Funtua', + 'Kawkareik', + 'Coffs Harbour', + 'Villiers', + 'Caldiran', + 'Palakkuzhi', + 'Sassenburg', + 'Oravita', + 'Liaojiayuan', + 'Nisshin', + 'Sirkhandi Bhitha', + 'Union de Tula', + 'Chitila', + 'Montecito', + 'Bozuyuk', + 'Sahiwal', + 'Nidamangalam', + 'Beixingzhuang', + 'Alaminos', + 'Kobiri', 'Drawsko Pomorskie', - 'Raun', - 'Blundellsands', - 'Cachoeira Alta', - 'Desanagi', - 'Mirik', - 'Grosse Pointe Park', - 'San Carlos de Guaroa', - 'Hlaingbwe', - 'Brislington', - 'Orchha', - 'Doukombo', - 'Sagada', - 'Nova Odesa', - 'Coronel Dorrego', - 'Belp', - 'San Lazaro', - 'Pakkam', - 'Piprahi', - 'Zejtun', - 'Xuan Trung', - 'Burley', - 'Radnevo', - 'Badou', - 'Hang Tram', - "Al M'aziz", - 'Estiva', - 'Gospic', - 'Dzouz', - 'Beniel', - 'Fort Morgan', - 'Liubashivka', - 'Dang`ara', - 'Liman', - 'Strombeek-Bever', - 'Kaboua', - 'Unterfohring', - 'Ostbevern', - 'Elgoibar', - 'Lencois', - "'Ain Roua", - 'Devikapuram', - 'Taviano', - 'Nova Ubirata', - 'Chauny', - 'Baruari', - 'Lovington', - 'Bouabout', - 'Kemigawa', - 'Elk City', - 'Mercogliano', - 'Oskaloosa', - 'Zeuthen', - 'Ihumwa', - 'Guayabal', - 'Wittingen', - 'Mount Fletcher', - 'Tawnza', - 'Oxelosund', - 'Sathiala', - 'Ridgefield', - 'Moyamba', - 'Lokhvytsya', - 'Tinogasta', - 'Novy Bor', - 'Westerkappeln', - 'San Gregorio di Catania', - 'Leon Valley', - 'Revuca', - 'Diosd', - 'Bank', - 'Peringottukurusshi', - 'Yakymivka', - 'Gaurihar Khaliqnagar', - 'Healdsburg', - 'Fatehpur Shahbaz', - 'Alto Alegre dos Parecis', - 'Myronivka', - 'Jamsaut', - 'Panapur Langa', - 'Lindon', - 'Alfonsine', - 'East Glenville', - 'Bek-Abad', - 'Raca', - 'Sarbogard', - 'Satyavedu', - 'Kuriyama', - 'Gotzis', - 'Tadley', - 'Kavaratti', - 'Valea Adanca', - 'Lebon Regis', - 'Vengikkal', - 'Poldasht', - 'Sun Village', - 'Gonubie', - 'Pirangi', - 'Sinkolo', - 'Muna', - 'El Ancor', - 'Mios', - 'Hoenheim', - 'Kari', - 'Arasur', - 'Rupenaguntla', - 'Shanmukhasundarapuram', - 'Vlasenica', - 'Cidade Gaucha', - 'Prudente de Morais', - 'Agame', - 'Bhabanipur', - 'Fuller Heights', - 'Duruma', - 'Mariehamn', - 'Loran', - 'Ninga', - 'Kalakada', - 'Rengali', - 'Kashaf', - 'Douar Trougout', - 'Vedene', - 'Eningen unter Achalm', - 'Fourmies', - 'Khangaon', - 'Maruttuvakkudi', - 'Buram', - 'Vitry-le-Francois', - 'Culcheth', - 'Shingbwiyang', - 'Mogilno', - 'Egelsbach', - 'Pike Creek Valley', - 'Ahlaf', - 'Cocentaina', - 'Chakwai', - 'Wilton Manors', - 'Bellegarde-sur-Valserine', - 'Jodar', - 'Cantley', - 'Esmoriz', - 'Paro', - 'Chitauria', - 'Florestopolis', - 'Grafenhainichen', - 'Sidi Moussa Ben Ali', - 'Kirchhundem', - 'Odatturai', - 'El Khemis des Beni Chegdal', - 'Ban Saeo', - 'Satuek', - 'Montanhas', - 'Trostberg an der Alz', - 'Baroni Khurd', - 'North Wantagh', - 'Sideradougou', - 'Cumanda', - 'La Londe-les-Maures', - 'Milici', - 'New Garden', - 'University of California-Santa Barbara', - 'Sonoita', - 'Enghien-les-Bains', - 'Port Salerno', - 'Ajijic', - 'Dhalaa', - 'Erin', - 'Amdel', - 'Varzobkala', - 'Saubara', - 'Vlasim', - 'Harsum', - 'Lendinara', - 'Caetanopolis', - 'Gloucester City', - 'Campbellsville', - 'Egersund', + 'Manassas Park', + 'Nu`ayjah', + 'Ndjili', + 'Hamidiyeh', + 'Pleiku', + 'Candon', + 'Samokov', + 'La Belleza', + 'Kargil', + 'Barugo', + 'Leichlingen', + 'Rizal', + 'Chhabila', + 'Sinanpasa', + 'Kabudarahang', + 'Yonghetun', + 'Selden', + 'Longchuan', + 'Guanduqiao', + 'Tinnanur', + 'Mandsaur', + 'Joso', + 'Besarh', + 'Decin', + 'Kut Chap', + 'Botolan', + 'Grad', + 'Dumaguete City', + 'Mimoso do Sul', + 'Tello', + 'Iwate', + 'Pordenone', + 'Naihati', + 'Painesville', + 'Alatsinainy Ialamarina', + 'Rinopolis', + 'Mut', + 'Shirahama', + 'Port Alfred', + 'Nantan', + 'Catuipe', + 'Isola Vicentina', 'Barahkurwa', - 'Gandhari', - 'Woods Cross', - 'Tlacolulan', - 'Hato Corozal', - 'Mericourt', - 'Holyhead', - 'Dobbs Ferry', - 'Er Regueb', - 'Bad Schwalbach', - 'Ramallo', - "Notre-Dame-de-l'Ile-Perrot", - 'San Jose de Guaribe', - 'Mogogelo', - 'Kumari', - 'Stradella', - 'Koori', - 'Dorog', - 'Kuse', - 'Pallipattu', - 'Ain Legdah', - 'Malo Crnice', - 'Hohenkirchen-Siegertsbrunn', - 'Vakhrusheve', - 'Nemyriv', - 'Velimese', - 'Laqraqra', - 'Kinattukkadavu', - 'Dautphe', - 'Kondhali', - 'Haydock', - 'Casier', - 'Sanniquellie', - 'Qax', - 'Naliya', - 'Bytca', - 'Cadolzburg', - 'Jimani', - 'Tourougoumbe', - 'Mahagama', - 'Kostinbrod', - 'Guinagourou', - 'Sales Oliveira', + 'Kladno', + 'Biritiba-Mirim', + 'Southwater', + 'Kariya', + 'Kearney', + 'Botosani', + 'Queen Creek', + 'Tamanique', + 'Putla Villa de Guerrero', + 'Visbek', + 'Apac', + 'Grossbeeren', + 'Chislehurst', + 'Esposende', + 'Winnipeg', + 'Thermi', + 'Mahires', + 'Neshannock', + 'Clearwater', + 'Tallinn', + 'Manegaon', + 'Nabua', + 'Baxter', + 'Arlington Heights', + 'Manafwa', + 'Groenlo', + 'Ngerengere', + 'Lakato', + 'Corner Brook', + 'Palakodu', + 'San Pietro Vernotico', + 'Arouca', + 'Bad Nenndorf', + 'Ban Nong Hoi', + 'Grand Island', + 'Perris', + 'Long My', + 'Contai', + 'Berlare', + 'Hlinsko', + 'Oum Hadjer', + 'Kusatsu', + 'Kamudi', + "N'Zerekore", + 'Minoo', + 'Moulares', + 'Taybad', + 'Nayanagar', + 'Barberena', + 'Oromocto', + 'Phirangipuram', + 'Neosho', + 'Leno', + 'Fakirtaki', + 'Noto', + 'Phulpur', + 'Karahal', + 'Alur', + 'Garcia Hernandez', + 'Zawodzie', + 'Gararu', + 'Wallsend', + 'Debre Birhan', + 'Bargaon', + 'Washougal', + 'Wutong', + 'Kajha', + 'Tamilisan', + 'Ambohimasina', + 'Abha', + 'Holguin', + 'Epe', + 'Owen Sound', + 'Essen', + 'Sermadevi', + 'Naga', + 'Kanjikkovil', + 'Maracai', + 'Kyongju', + 'Oulad Friha', + 'Camp Pendleton South', + 'Govindapuram', + 'Sligo', + 'Cubal', + 'Mamuju', + 'Talca', + 'Carcagente', + 'Bagepalli', + 'Liuba', + 'Nao-Me-Toque', + 'Punitaqui', + 'Saint-Pierre-du-Perray', + 'Manila', + 'Alkmaar', + 'Providence', + 'Xinguara', + 'Jangaon', + 'Ibimirim', + 'McAlester', + 'Saalfeld', + 'Palladam', + 'Yacuanquer', + 'Port Denison', + 'Mama Khel', + 'Stabroek', + 'Lake Arbor', + 'Killingworth', + 'Ouled Chebel', + 'Utnur', + 'Kandangan', + 'Soest', + 'Tbeng Meanchey', + 'Haoping', + 'Sater', + 'West Bromwich', + 'Mandiraja Kulon', + 'Karczew', + 'Krems an der Donau', + 'Osako', + 'Budwan', + 'Scalea', + 'Gersthofen', + 'Shiloh', + 'Kopargo', + 'Trotwood', + 'Teltow', + 'Annonay', + 'Makwassie', + 'Ouled Rached', + 'Rankweil', + 'Farmington Hills', + 'Mbini', + 'Horice', + 'Jacqueville', + 'Banbishancun', + 'Tamanar', + 'Konidena', + 'Hengzhou', + 'Liverpool', + 'Marofototra', + 'Cheruvannur', + 'Iormughanlo', + 'Tomar', + 'Si Satchanalai', + 'Guiseley', + 'Bicske', + 'Richland', + 'Elizabeth', + 'Linares', + 'Narbonne', + 'Agua Azul do Norte', + 'Crateus', + 'Luton', + 'Bardstown', + 'Amiawar', + 'Dulhanganj', + 'Senanga', + 'Kobylka', + 'Imlil', + 'St. Catharines', + 'Laziska Gorne', + 'An Cabhan', + 'Tarbes', + 'Leutenbach', + 'Frederiksvaerk', + 'Sechura', + 'Geldermalsen', + 'Krishnarajasagara', + 'Catarroja', + 'Dugo Selo', + 'Brieselang', + 'Kosum Phisai', + 'East Fishkill', + 'Sendhwa', + 'Ampasinambo', + 'Urbano Santos', + 'Myaydo', + 'Premnagar', + 'Andovoranto', + 'Yaraka', + 'Fuller Heights', + 'Tarqui', + 'Struer', + 'Chintalapalle', + 'Boali', + 'Keswick', + 'Deal', + 'Tayasan', + 'Sakha', + 'Vandalur', + 'Somma Vesuviana', + 'Almaguer', + 'Jacksonville Beach', + 'Yuxi', + 'Torhout', + 'Buqkoosaar', + "O'Hara", + 'Dortmund', + 'Freeport City', + 'Poptun', + 'Upper Grand Lagoon', + 'Shendi', + 'Cuautitlan Izcalli', + 'Blagnac', + 'Letpandan', + 'Bhachhi', + 'Dunavarsany', + 'Lessogou', + 'Elze', + 'Clare', + 'Harvey', + 'Ain Feka', + 'Wayne', + 'Pohang', 'Pothia', - 'Senduria', - 'Raibari Mahuawa', - 'Ulricehamn', - 'Florennes', - 'Sao Amaro das Brotas', - 'Cabo Verde', - 'Sociedad', - 'Lopon', - 'Prataparampuram', - 'Tysvaer', - 'Lumaco', - 'Majdal Shams', - 'Ganserndorf', - 'Scottburgh', - 'Pelileo', - 'Laren', - 'Buzhum', - 'Dawley', - 'Saint-Cyprien', - 'Rostraver', - 'Plan-de-Cuques', - 'Byerazino', - 'Gundrajukuppam', - 'Wealdstone', - 'San Michele al Tagliamento', - 'Enebakk', + 'Pokhraira', + 'Pontalina', + 'Amatura', 'Sao Joao das Lampas', - 'Montegrotto Terme', - 'Saverne', - 'Yalluru', - 'Greetland', - 'Higashiizu', - 'Kincardine', - 'Marktheidenfeld', - 'Nyirbator', - 'Simrahi', - 'Clawson', - 'Douar Sgarta', - 'Saint-Junien', - 'Sidi Tabet', - 'Guacheta', - 'Yvetot', - 'Falimari', - 'East Grand Rapids', - 'Anjuna', - 'Hejiaji', - 'Grunwald', - 'Konakondla', - 'Campobello di Mazara', - 'Lijiacha', - 'Samayanallur', - 'Halavagalu', - 'Buckhurst Hill', - 'Baghmaria', - 'Harji', - 'Bind', - 'Hirnyk', - 'Onoto', - 'Sarjapur', - 'Snyder', - 'Rosario de Mora', - 'Campo do Meio', - 'Salamedu', - 'Pir Maker', - 'Staden', - 'Harrow Weald', - 'Suffern', - 'Mancha Real', - 'Great Bookham', - 'Little Bookham', - 'Lahfayr', - 'Bansbari', - 'Boudenib', - 'Buuhoodle', - 'Uchchangidurgam', - 'Kochkor', - 'Morgan City', - 'Tilmi', - 'Musile di Piave', - 'Elliot Lake', - 'Douar Oulad Naoual', - 'Pelsall', - 'Recke', - 'Kamiita', - 'Humahuaca', - 'Alcantaras', - 'Ploufragan', - 'Bhagwatpur', - 'Biddupur', - 'Puyehue', - 'Zambrano', - 'Parora', - 'Okmulgee', + 'Pinan', + 'Sidi Lakhdar', + 'Badami', + 'Matadepera', + "Sant'Agata di Militello", + 'Laiyang', + 'Selmana', + 'Rothwell', + 'Kamareddipet', + 'Hobe Sound', + 'Mong Tun', + 'Armur', + 'Islampur', + 'Wadgassen', + 'Selma', + 'Momanpet', + 'Aktepe', + 'Mjolby', + 'Patchogue', + 'Nueva Loja', + 'Kronjo', + 'Turuvekere', + 'Tejupilco', + 'Vetraz-Monthoux', + 'Rickmansworth', + 'Cicuco', + 'Chandigarh', + 'Winslow', + 'Amtala', + 'Waingapu', + 'Mayuge', + 'Ruse', + 'Sindangan', + 'Xankandi', + 'Al Qutayfah', + 'Llorente', + 'Naliya', + "Az Zarqa'", + 'Bomporto', + 'Wadern', + 'Cegled', + 'Jalapa', + 'Shizhaobi', + 'Union de Reyes', + 'Nahargarh', + 'Massapequa Park', + 'Kalvarija', + 'Portes-les-Valence', + 'Sidi ech Chahmi', + 'Hope', + 'Cumbal', + 'Soalkuchi', + 'Modling', + 'Khujner', + 'Biederitz', + 'Laval', + 'Mikkeli', + 'Otopeni', + 'Qashyr', + 'Noisy-le-Grand', + 'Titao', + 'Koga', + 'Tipasa', + 'Bukoba', + 'Pruszcz Gdanski', + 'Tachiarai', + 'Na Yung', + 'Oignies', + 'Fillmore', + 'Tachilek', + 'Lathrop', + 'Binalbagan', + 'Kallidaikurichi', + 'Leova', + 'Adazi', + 'Caibarien', + 'El Obeid', + 'Pareo', + 'Whitstable', + 'Raymond', + 'Centenario', + 'Zhangziying', + 'Satyavedu', + 'Uspantan', + 'Castelli', + 'Zuitou', + 'Chiradzulu', + 'Tadif', + 'Stains', + 'Mathba', + 'St. Clair', + 'Beni Ounif', + 'Aripuana', + 'Cumana', + 'Bhui', + 'Jeddah', + 'Settara', + 'San Andres de Llevaneras', + 'Fermo', + 'Kinross', + 'Sanjiaocheng', + 'Serrita', + 'Analapatsy', + 'La Bruyere', + 'Bac Giang', + 'Manticao', + 'Jaen', + 'Uzumlu', + 'Pauri', + 'Fernandina Beach', + 'Mullaittivu', + 'Fairfield Glade', + 'Dougouni', + 'Shuangyashan', + 'Ashford', + 'Dalan', + 'Longchamps', + 'Berat', + 'Mirangaba', + 'Bhagta', + 'Bodmin', + 'Wittenbach', + 'Capriolo', + 'Plock', + 'Petropolis', + 'Nimmekal', + 'Eisenberg', + 'Minakshipuram', + 'Fox Lake', + 'Simunul', + 'Zhangatas', + 'Besikduzu', + 'Diepenbeek', 'Castalla', - 'Baghra', - 'Atharga', - 'Yangirabot', - 'San Jose del Fragua', - 'Lonate Pozzolo', - 'Progress', - 'Arumbakkam', - 'Meghraj', - 'Altdorf', - 'Jamhor', - 'Pachahi', - 'Manpaur', - 'Zierikzee', - 'Lyuban', - 'Sidi Baizid', - 'Carnoustie', - 'Gardone Val Trompia', - 'Bankya', - 'Rudersberg', - 'Phulparas', - 'Manappakkam', - 'Kalinagar', - 'Bromont', - 'Engen', - 'Parvatgiri', - 'Perampuzha', - 'Medulla', - 'Bargaon', - "Monte Sant'Angelo", - 'Rodenbach', - 'Catskill', - 'Klyetsk', - 'Talaigua Nuevo', - 'Bataipora', - 'Rothenburg ob der Tauber', - 'Charouine', - 'Ochsenfurt', - 'Vaal Reefs', - 'Cardoso', - 'Handewitt', - 'Taurisano', - 'Tegueste', - 'Nalambur', - 'Rheinau', - 'Knowsley', - 'Cherlagandlapalem', - 'Pimenteiras', - 'Lamsabih', - 'Capaci', - 'Ouaklim Oukider', - 'Teniet el Abed', - 'Domnesti', - 'Kurgunta', - 'Welzheim', - 'Dharmaj', - 'Cocoa Beach', - 'Yanahuanca', - 'Gustavsberg', - 'Waidhofen an der Ybbs', - 'Machados', - 'Humpolec', - 'Tokol', - 'Besalampy', - 'Gouvea', - 'Nussloch', - 'Ialysos', - 'Natshal', - 'Pemmperena', - 'El Quisco', - 'Papireddippatti', - 'Dugny', - 'Tiruvennanallur', - 'Langarivo', - 'Mashyal', - 'Rio Novo do Sul', - 'Ban Bang Lamung', - 'Barigarh', - 'Virton', - 'Tabapua', - 'Lardero', - 'Masinigudi', - 'Capitan Bado', - 'Varadarajampettai', - 'Taylorville', - 'Tosagua', - 'Capitan Sarmiento', - 'Leatherhead', - 'Gracemere', - 'Bitritto', + 'Nakaseke', + 'Daimiel', + 'Aguascalientes', + 'Bluefields', + 'Weinheim', + 'Khirhar', + 'Vilkaviskis', + 'Gorha', + 'Condeixa-a-Nova', + 'Shikokuchuo', + 'Maghar', + 'Khutha Baijnath', + 'Kathmandu', + 'Tornesch', + 'Isernia', + 'Koriapatti', + 'Tharike', + 'Hastings', + 'Pindra', + 'Eislingen', + 'Bridgetown', + 'Salt Lake City', + 'Kashti', + 'Hulyaypole', + 'Sexmoan', + 'Shrewsbury', + 'Tha Yang', + 'Waghai', + 'Scone', + 'Ritto', + 'Sukrah', + 'Strausberg', + 'Kurhani', + 'Nesarg', + 'Ciudad Constitucion', + 'Francavilla Fontana', + 'Langenselbold', + 'Soklogbo', + 'Deinze', + 'Zaanstad', + 'Lafia', + 'Prosperidad', + 'Rumuruti', + 'Savigliano', + 'Hundested', + 'Neuhausen auf den Fildern', + 'Chitre', + 'Sarrebourg', + 'Ayanikkad', + 'Dapoli', + 'Centerton', + 'Plettenberg', + 'Skocjan', + 'Oamishirasato', + 'Penticton', + 'Aurillac', + 'Red Hook', + 'Kiel', + 'Mannadipattu', + 'Ronchi dei Legionari', + 'Az Zuwaytinah', + 'Ulverston', + 'Tholikuzhi', + 'Phrai Bueng', + 'St. Paul', + 'Shenley Church End', + 'Gourrama', + 'Itiuba', + 'Bena', + 'Partinico', + 'Fort Thomas', 'Marasesti', - 'Oxted', - 'Burslem', - 'Mulheim-Karlich', - 'Worb', - 'Tenenkou', - "Bruay-sur-l'Escaut", - 'Tazhakudi', - 'Janow Lubelski', - 'Hipperholme', - 'Edasseri', - 'Dimmbal', - 'Zimna Voda', - 'Saint-Germain-les-Arpajon', - 'Arnprior', - 'Villa Purificacion', - 'Denkendorf', - 'Ikhlaspur', - 'Sabana Yegua', - "Jem'at Oulad 'Abbou", - 'Periya Soragai', - 'Lafrayta', - 'Sebba', - 'Inhassoro', - 'Lieksa', - 'Caldogno', - 'Ichinohe', - 'Estiva Gerbi', - 'Gualcince', - 'Batemans Bay', - 'Caotan', - 'Singura', - 'Commune Sidi Youssef Ben Ahmed', - 'El Ghourdane', - 'Arslanbob', - 'Drochtersen', - 'Bad Nenndorf', - 'Panpuli', - 'Teano', - 'Getulina', - 'Chorleywood', - 'Antsambalahy', - 'Golfito', - 'Batonyterenye', - 'Tikota', - 'Amatenango del Valle', - 'Ban Kat', - 'Stamboliyski', - 'Svitlodarsk', - 'Pedro de Toledo', - 'Arpajon', - 'Norwell', - 'Dourdan', - 'Limavady', - 'Stanwell', - 'De Doorns', - 'Beldibi', - 'North Dundas', - 'Eichenzell', - 'Tramore', - 'Lakeland Highlands', - 'Pipariya', - 'Somavarappatti', - 'Biri', - 'Majanji', - 'Sajoszentpeter', - 'Kanhaipur', - 'Caimanera', - 'Bhilavadi', - 'Seneffe', - 'Dammartin-en-Goele', - 'Iskapalem', - 'Curimata', - 'Covenas', - 'Astley', - 'Fallersleben', - 'Riebeeckstad', - 'Simeria', - 'Sinor', - 'Asthal Bohar', - 'Caetano', - 'Bicske', - 'Samahuta', - 'Burtonwood', - 'Banavar', - 'Trecastagni', - 'Lowes Island', - 'Manvel', - 'Derecik', - 'Kurim', - 'La Roche-sur-Foron', - 'Sirpanandal', - 'Maryport', - 'Bara Belun', - 'Ventersburg', - 'Sogne', - 'Beclean', - 'Largs', - 'Westphalia', - 'Ocean City', - 'Edd', - 'Arcachon', - 'Boultham', - 'Datiana', - 'Kovurupalli', - "Sant'Ilario d'Enza", - 'Niasso', - 'North Valley', - 'Jadopur Shukul', - 'Groton', - 'Poko', - 'Narayanavanam', - 'El Playon', - 'Kin', - 'Two Rivers', - 'Jamaat Shaim', - 'Roncador', - 'Deodha', - 'Lang Suan', - 'Priolo Gargallo', - 'Quebrangulo', - 'Farciennes', - 'Pulpi', - 'Malkanur', - 'Alburquerque', - 'Sao Joao do Manhuacu', - 'Scalea', - 'Kings Mountain', - 'Sahsaul', - 'Moglingen', - 'Willistown', - 'Touama', - 'Prien am Chiemsee', - 'Las Charcas', - 'Saint-Jean', - 'Kingsnorth', - 'Makhmalpur', - 'Alpu', - 'Mannedorf', - 'Eranapuram', - 'Greasley', - 'Cranleigh', - 'Retie', - 'Kpandae', - 'Chintakunta', - 'Bramhabarada', - 'Bardiha Turki', - 'Attippattu', - 'Gethaura', - 'Kishunpur', - 'San Pablo Atlazalpan', - 'Akjoujt', - 'Sankt Johann im Pongau', - 'Pueblo Viejo', - 'Lavandevil', - 'Kourouma', - 'Derbisek', - 'Hagen im Bremischen', - 'Beniajan', - 'Tentena', - 'Bora', - 'Betania', - 'Mineiros do Tiete', - 'Resende Costa', - 'Mountain Ash', - 'Inzago', - 'Werther', - 'Lauingen', - 'Porto-Vecchio', - 'Moyuta', - 'Pasaco', - 'Monteforte Irpino', - 'Sidi Abdellah Ben Taazizt', - 'Anenecuilco', - 'Ortakent', - 'Rahiar Kunchi', - 'Crayford', - 'West Point', - 'Koog aan de Zaan', - 'Amarchinta', - 'Jagdishpur', - 'Lincolnton', - 'Aratuba', - 'Antonio Carlos', - 'Herbolzheim', - 'Hormigueros', - 'Gravelines', - 'Belauncha', - 'Vahdattiyeh', - 'Kassa', - 'Djemmorah', - 'Amala', - 'Granbury', - 'Kaset Wisai', - 'Vanj', - 'Castle Bromwich', - 'Wanaque', - 'Kedougou', + "Monte Sant'Angelo", + 'Lubbecke', + 'Grande-Synthe', + 'Jincheng', + 'Monteros', + 'Randburg', + 'Shakopee', + 'Escuque', + 'Bauko', + 'Muscatine', + 'Ralla', + 'Usuppur', + 'Iwaki', + 'Compton', + 'Isna', + 'Suhbaatar', + 'Igboho', + 'San Rafael Cedros', + 'Lapua', + 'Zdzieszowice', + 'Arcadia', + 'Orotina', + 'Bogande', + 'Alpignano', + 'Highland Park', + 'Newberg', + 'Veles', + 'Scituate', + 'Bellatti', + 'Tempio Pausania', + 'Buri Ram', + 'Marquette', + 'Niquinohomo', + 'Cuddalore', + 'Waimalu', + 'Potiskum', + 'Mohammedia', + 'Bamiantong', + 'La Trinitaria', + 'Bekes', + 'Cajabamba', + 'Conyers', + 'Malungun', + 'Takehara', + 'Aspen Hill', + 'Suzuka', + 'Ait Youssef Ou Ali', + 'Klaipeda', + 'Churriana de la Vega', + 'Malpura', + 'Romano di Lombardia', + 'Jose de Freitas', + 'Soc Trang', + 'Brahmadesam', + 'Chalons-en-Champagne', + 'Guria', + 'Talwandi Sabo', + 'Makhmur', + 'Podvelka', + 'Satghara', + 'Chimteppa', + 'Yaypan', + 'Kearsley', + 'Qianwangcun', + 'Suratgarh', + 'Santa Helena de Goias', + 'San Andres Itzapa', + 'Zulakallu', + 'Pinos Puente', + 'El Carmen de Bolivar', + 'Nahiyat al Iskandariyah', + 'Kasterlee', + 'Cabries', + 'Dakhan', + 'Senguio', + 'Lachute', + 'Bni Quolla', + 'Indanan', + 'Spennymoor', + 'Pottireddippatti', + 'Chaville', + 'Goto', + 'Somoto', + 'Antaritarika', + 'Chikkala', + 'Maheswa', + 'Schmallenberg', + 'Itajuba', + 'Udarband', + 'Itanhaem', + 'Sandiacre', + 'Castlegar', + 'Maler Kotla', + 'Kuressaare', + 'Huangxicun', + 'Sand', + 'Farrokh Shahr', + 'Valandovo', + 'Madakkathara', + 'Kaurihar', + 'Santa Lucia La Reforma', + 'Gjirokaster', + 'Indore', + 'Thorigne-Fouillard', + 'Fiorano Modenese', + 'Drexel Hill', + 'Ash Shamiyah', + 'Baia Farta', + 'Chakdaha', + 'Dambulla', + 'Muttukuru', + 'Chiesanuova', + 'Mehran', + 'Metkovic', + 'Portomaggiore', + 'Spokane', + 'Oldbury', + 'Vilattikulam', + 'Nasushiobara', + 'San Martin de Loba', + 'Campo Largo', + 'Yenakiieve', + 'Uropa', + 'Kaleybar', + 'Mit Salsil', + 'Hedehusene', + 'Gross-Enzersdorf', + 'Germiston', + 'Qal`eh Chan`an', + 'Rocky Point', + 'Cingoli', + 'Garden Grove', + 'Ouro Preto', + 'Mead Valley', + 'Liwonde', + 'Kokologo', + 'Monona', + 'Funato', + 'College Park', + 'Tighedouine', + 'Peringottukurusshi', + 'Ankilimivory', + 'Tabina', + 'Bahagalpur', + 'Huelva', + 'Musashino', + 'Igapora', + 'San Antonio Huista', + 'Cristais', + 'Rajkot', + 'Hasseh', + 'Wyckoff', + 'Rukungiri', + 'Rio Pomba', + 'Morteros', + 'Camillus', + 'Cholai', + 'Alto Rio Doce', + 'Imperatriz', + 'Ross on Wye', + 'Gairtganj', + 'Sakubva', + 'Porsgrunn', + 'Oss', + 'Dickson', + 'Famailla', + 'Napak', + 'La Tebaida', + 'Dhaka', + 'Pulicat', + 'Dayr Mawas', + 'Rampur Kudarkatti', + 'La Rochelle', + 'Cowansville', + 'Van Buren', + 'Montevideo', + "Sant'Antimo", + 'IJmuiden', + 'Urtaowul', + 'Chtiba', + 'Bavanat', + 'Mooresville', + 'Longbangcun', + 'Marawi', + 'Meppel', + 'Ha Long', + 'Matsubushi', + 'Massakory', + 'Jamsaut', + 'Uzungoz', + 'Phatthaya', + 'Glew', + 'Gavimane', + 'Ionia', + 'Hackney', + 'Shanshan', + 'Chilanga', + 'Puerto El Triunfo', + 'Egg Buckland', + 'Ladner', + 'Chapadinha', + 'Mangualde', + 'Aisai', + 'Itamati', + 'Kunkalagunta', + 'Yucheng', + 'Ozhur', + 'Volochysk', + 'Garliava', + 'Ananindeua', + 'Naugatuck', + 'Toronto', + 'Daoukro', + 'Isperih', + 'Sebaco', + 'Apizaco', + 'Curepto', + 'Phimai', + 'Melzo', + 'Edd', + 'Santo Agostinho', + 'Chystiakove', + 'Kobilo', + 'Rafai', + 'Potchefstroom', + 'Ban Bang Sai', + 'Makato', + 'Mairinque', + 'Suwalki', + 'Vinh Yen', + 'Odobesti', + 'Rogerstone', + 'Campos Belos', + 'Nanguneri', + 'Ban Mon Pin', + 'Bududa', + 'Devikapuram', + 'Pietrasanta', + 'Lienen', + 'Ma`arrat an Nu`man', + 'Jicome', + 'Bockenem', + 'Bossembele', + 'Dongchuan', + 'Tepetlan', + 'Piddig', + 'Cheektowaga', + 'Vohipeno', + 'Soubala', + 'Xalapa', + 'Peru', + 'Middlesborough', + 'Oral', + 'Villa Celina', + 'Bacacay', + 'Gangapur', + 'Loyola Heights', + 'South Riding', + 'Gurupi', + 'Galapa', + 'Bagor', + 'Chitemo', + 'Birnin Kebbi', + 'Tagajo', + 'Maychew', + 'Worms', + 'Tesanj', + 'South El Monte', + 'Kitcharao', + 'Shorewood', + 'Agen', + 'Kargi', + 'Oppicherla', + 'Van', + 'Port Augusta', + 'Ahlen', + 'Moudjbara', + 'Ghaxaq', + 'El Arrouch', + 'Carson', + 'Kitatajima', + 'Kamp-Lintfort', + 'Kachhari', + 'Fort Myers', + 'Imbituva', + 'North Charleston', + 'Unterfohring', + 'Triangle', + 'Tuntum', + 'Dollard-des-Ormeaux', + 'Eschweiler', + 'Pomorie', + 'Xewkija', + 'Buenavista', + 'Arsanjan', + 'Demnat', + 'Saharefo', + 'Maragogi', + 'Odivelas', + 'Villaviciosa de Odon', + 'Keszthely', + 'Alcantarilla', + 'Loutraki', + 'Falou', + 'Linfen', + 'Azamnagar', + 'Karvina', + 'Shady Hills', + 'Chopda', + 'Vredefort', + 'Westmont', + 'Ulaanbaatar', + 'Southbridge', + 'North Druid Hills', + 'Viseu', + 'Le Thor', + 'Tacaratu', + 'Elur', + 'Motupe', + 'Trim', + 'Chorzow', + 'Kelle', + 'Ljutomer', + 'Kanbara', + 'Maroviro', + 'Zapotitlan', + 'Forlimpopoli', + 'Dhuusamarreeb', + 'Bakwa-Kalonji', + 'Bakeshiyingcun', + 'Ngoulemakong', + 'Nor Hachn', + 'Ejmiatsin', + 'Handlova', + 'Pillaiyarkuppam', + 'Miramar', + 'Nanyo', + 'Northampton', + 'Heerenveen', + 'Doiwala', + 'Engenheiro Caldas', + 'Undrajavaram', + 'Mahudha', + 'Ashtead', + 'Kotagiri', + 'Nieuw Amsterdam', + 'Hamakita', + 'Ipueiras', + 'Mannargudi', + 'Ramsey', + 'La Mata', + 'Strabane', + 'Meaford', + 'Truseni', + 'Kanhangad', + 'Matanga', + 'Seohara', + 'Hijuelas', + 'Narvik', + 'Alamada', + 'Moslem Ebn-e `Aqil', + 'Kabasalan', + 'Mataram', + 'Jagodina', + 'Zifta', + 'Jambughoda', + 'Ledeberg', + 'Melonguane', + 'Okuizumo', + 'Petion-Ville', + 'Coweta', + 'Chiniot', + 'Ntara', + 'Munuf', + 'West Falls Church', + 'Kanchanaburi', + 'Nahiyat al Kifl', + 'Aqsu', + 'Ghaziabad', + 'Katpadi', + 'Midalam', + 'Omegna', + 'Noci', + 'Taniyama-chuo', + 'Patrocinio Paulista', + 'Merseburg', + 'Nashua', + 'Lamut', + 'Ankang', + 'Ahor', + 'Edakkunnam', + 'South Shields', + 'Liangwu', + 'Sonbari', + 'Shinjo', + 'Patuvilayi', + 'Ponte de Sor', + 'Kawamata', + 'Ulvila', + 'Polomolok', + 'Saila', + 'Mahaiza', + 'El Trebol', + 'Cisterniga', + 'Fossombrone', + 'Nyala', + 'Villa Gesell', + 'Lapa', + 'Nidamaluru', + 'Peraiyur', + 'Dodarasinakere', + 'Pachino', + 'Saint-Etienne-du-Rouvray', + 'Gilching', + 'Laurentian Valley', + 'Garhshankar', + 'Lambesc', + 'Hanamaki Onsen', + 'Seagoville', + 'Rheda-Wiedenbruck', + 'Sutton Coldfield', + 'Safaja', + 'Enns', + 'Mutki', + 'Villa de Leyva', + 'Chauk', + 'Aadorf', + 'Lukow', + 'Yuanquan', + 'Muniz', + 'Maxixe', + 'Soquel', + 'Hillcrest Heights', + 'Mancheral', + 'Featherstone', + 'Chelak', + 'Tondela', + 'Hostomel', + 'Alfonsine', + 'Iskilip', + 'Jaciara', + 'Gidri', + 'Tulare', + 'Mushabani', + 'Patharia', + 'Coudekerque-Branche', + 'Bastos', + 'San Antonio Abad', + 'Eagle Point', + 'Fernando de la Mora', + 'Mhajar', + 'Longhua', + 'Sevnica', + 'Karian', + 'Narsipatnam', + 'Nuuk', + 'Mount Juliet', + 'Tome-Acu', + 'Ferozepore', + 'Sirakoro', + 'Barra Velha', + 'Zabok', + 'Azandarian', + 'Conewago', + 'El Gara', + 'Mamungan', + 'Livorno', + 'Ain Zaouia', + 'Ilamatlan', + "Anse d'Hainault", + 'Voloina', + 'Itaitinga', + 'Odatturai', + 'Vedaranniyam', + 'Bretzfeld', + 'Lom Sak', + 'Yingyangcun', + 'Manamodu', + 'Cerqueira Cesar', + 'Sorgun', + 'Ban', + 'Oyrarbakki', + 'Mandaguacu', + "Sered'", + 'Ringkobing', + 'Kalihati', + 'Modi`in Makkabbim Re`ut', + 'Malverne', + 'Copenhagen', + "L'Ancienne-Lorette", + 'Dagenham', + 'Marovandrika', + 'Nossa Senhora dos Milagres', + 'Sacueni', + 'Santa Maria a Monte', + 'Souq Jamaa Fdalate', + 'Chinguar', + 'Swiedbodzin', + 'Mangalme', + 'San Anselmo', + 'Ban Patong', + 'Bazar-e Yakawlang', + 'Teresopolis', + 'Baliangao', + 'Hunsur', + 'Idigny', + 'Kose', + 'Pedra Azul', + 'Mount Vernon', + 'Uzun', 'Hamadanak', - 'Miechow', - 'Sayda', - 'Sanzana', - 'Holic', - 'Pinheiro Machado', - 'Mannarai', - 'Hambantota', - 'Marquette-les-Lille', - 'Dhakaich', - 'Talupula', - 'Ranti', - 'Emba', - 'Prachatice', - 'Diez', - 'Montechiarugolo', - 'Nembro', - 'Schoningen', - 'Beni Ounif', - 'Khargram', - 'Isselburg', - 'Temamatla', - 'Tittachcheri', - 'Kummarapurugupalem', - 'Sonseca', - 'Lathasepura', - 'Carbonera', - 'Ichikai', - 'Guilherand', - 'Laukaria', - 'Lommedalen', - 'Budili', - 'Tagami', - 'Namli', - 'Kalasa', - 'Iygli', - 'Lloro', - 'Sanjiaocheng', - 'Tissa', - 'Valkeala', - 'Sarab-e Taveh-ye `Olya', - 'Borjomi', - 'Sirgora', - 'Chamestan', - 'Storm Lake', - 'Chikni', - 'Bhisho', - 'Pihuamo', - 'Faxinal dos Guedes', - 'Tournon-sur-Rhone', - 'Shahmirzad', - 'Kazarman', - 'Boiling Springs', - 'Feldkirchen-Westerham', - 'Mpraeso', - 'Busumbala', - 'Siniscola', - 'Nambour', - 'Guntupalle', - 'Damonojodi', - 'Arambakkam', - 'Pacoti', - 'Linslade', - 'Ilfracombe', + 'As', + 'Tounfit', + 'Blumberg', + 'Konstancin-Jeziorna', + 'Ebino', + 'Hull', + 'Tajumulco', + 'Castellaneta', + 'Sidhapa', + 'Slagelse', + 'Dunbar', + 'Nahariyya', + 'Tsuyama', + 'Selston', + 'Brummen', + 'Gigante', + 'Caluquembe', + 'Nirkunnam', + 'Peabody', + 'Braunstone', + 'San Fernando de Henares', + 'Sebt Bni Smith', + 'Lakkampatti', + 'Miami Gardens', + 'Gluckstadt', + 'Santa Maria de Palautordera', + 'Bas Limbe', + 'El Puerto de Santa Maria', + 'Bundaberg', + 'Giszowiec', + 'Gweru', + 'Belle-Anse', + 'Bodupal', + 'Inopacan', + 'Pencoed', + 'Zittau', + 'Sialkot City', + 'Obera', + 'Naikankudi', + "L'Aquila", + 'Plan-les-Ouates', + "Ch'ungmu", + 'Corte Madera', + 'Kaukauna', + 'Tsararafa', + 'Lembok', + 'Altena', + 'Gliwice', + 'Bora', + 'Hagen im Bremischen', + 'Tsaramasoandro', + 'Alto Rio Senguer', + 'Inungur', + 'Alor Setar', + 'Al Hajar al Aswad', + 'Kurunegala', + 'Efringen-Kirchen', + 'Little Egg Harbor', + 'Itagi', + 'Koppunur', + 'Bemidji', + 'Tantoyuca', + 'Guiratinga', + 'Barton', + 'An Khe', + 'Yamagata', + "Lee's Summit", + 'Nea Filadelfeia', + 'Bagneux', + 'Samtredia', + 'Yingcheng', + 'Shibata', + 'Mount Pearl Park', + 'Arendonk', + 'Dhenkanal', + 'Kapenguria', + 'Saida', + 'Gloucester', + 'Bibai', + 'Lebbeke', + 'Dhusar Tikapatti', + 'Rondon', + 'Tamayo', + 'Daksinkali', + 'Plymouth', + 'Scordia', + 'Haywards Heath', + 'Battle Ground', + 'Fishers', + 'Gonen', + 'Xingren', + 'Queenstown', + 'Port Coquitlam', + 'Raritan', + 'Nagykovacsi', + 'North Bend', + 'Wilmot', + 'Taal', + 'Ruhengeri', + 'Zhovkva', + 'Sangtuda', + 'Pont-Rouge', + 'Urbandale', + 'Reeuwijksebrug', + 'Hamburg', + 'Midsayap', + 'Janai', + 'Harrow on the Hill', + 'Nakao', + 'Kaoma', + 'Verbania', + 'Dancagan', + 'Tecumseh', + 'Luhansk', + 'Elanjivaliseri', + 'Dhariwal', + 'Mahuva', + 'Dabhaura', + 'Pilisvorosvar', + 'Ravne na Koroskem', + 'As Suwayq', + 'Semri', + 'Siliana', + 'Noria', + 'Chabahar', + 'Gimpo', + 'Parempuyre', + 'Tam Hiep', + 'Bir', + 'Miranda', + 'Dhemaji', + 'Menongue', + 'Argao', + 'Fuldatal', + 'Gualeguaychu', + 'Hoboken', + 'Melgar', + 'Bishunpura', + 'Karabuk', + 'Tirthahalli', + 'Binmaley', + 'Trajano de Morais', + 'Villeneuve-Saint-Georges', + 'Moribabougou', + 'Al Mansurah', + 'Palangavangudi', + 'Nasugbu', + 'Giugliano in Campania', + 'Emsdetten', + 'Satte', 'Prescot', - 'Bucheya', - 'Barka Gaon', - "Montopoli in Val d'Arno", - 'Los Almacigos', - 'Capilla del Monte', - 'Armstrong', - 'Kranenburg', - 'Parbata', - 'Wootton', - 'Malkhaid', - 'Aurelino Leal', - 'Hinwil', - 'Pungulam', - 'Harsinghpur', - 'Kawadgaon', - 'Baryshivka', - 'Rychnov nad Kneznou', - 'Chikkarampalaiyam', - 'Satellite Beach', - 'Mhangura', - 'Moreira Sales', - 'Vaux-le-Penil', - 'Gora', - 'Arvand Kenar', - 'Hoeilaart', - 'Grobbendonk', - 'Belzig', - 'Kuzuculu', - 'Seringueiras', - 'Westtown', - 'Tucson Mountains', - 'Coldstream', - 'Galbois', - 'Stonehaven', - 'New Port Richey East', - 'Potukonda', - 'Douar Jwalla', - 'Romanshorn', - 'Boujediane', - 'Nagalapuram', - 'Douar Ain Maatouf', - 'Rasaunk', - 'Penne', - 'Marginea', - 'Palukudoddi', - 'Targu Lapus', - 'Batesville', - 'San Jose de Aerocuar', - 'Sater', - 'Kumbadaje', - 'Margherita di Savoia', - 'Piedmont', - 'Elon', - 'Zaouiet Says', - 'Bollullos de la Mitacion', - 'Creazzo', - 'Vosselaar', - 'Capela de Santana', - 'Areiopolis', - 'Dorking', - 'Prymorsk', - 'Cacequi', - 'Bernardino de Campos', - 'Cherry Creek', - 'Chikha', - 'Honiton', - 'Inwood', - 'Mangalme', - 'Gerasdorf bei Wien', - 'North Lindenhurst', - 'Tambaga', - 'Kriftel', - 'Aylestone', - 'Bhandarso', - 'Sierra Madre', - 'Villepreux', - 'Aukstieji Paneriai', - 'Somnaha', - 'Hauterive', - 'Begogo', - 'Antonio Cardoso', - 'Finale Ligure', - 'Planura', - 'Bailin', - 'Mortugaba', - 'Waldkirchen', - 'Balve', - 'Sihaul', - 'Sonbari', - 'Bannewitz', - 'Mayureswar', - 'Okhargara', - 'Birch Bay', - 'Atru', - 'Pulsano', - 'Cerese', - 'Lloyd', - 'Barbadanes', - 'Cesson', - 'Dorridge', - 'Olaippatti', - 'Stollberg', - 'Hexham', - 'Cisternino', - 'Enfida', - 'Saadatpur Aguani', - 'Waipio', - 'Guebwiller', - 'Novska', - 'Banagi', - 'Balehonnur', - 'Oberwil', - 'Pongalur', - 'Kilkottai', - 'Ecaussinnes-Lalaing', - 'Kanamadi', - 'Udawantnagar', - 'Kurman', - "Finch'a'a", - 'Murapaka', - 'Roscoe', - "Ambinanin'i Sakaleona", - 'Evington', - 'Achankovil', - 'Jamapa', - 'Sheron', - 'Iazizatene', - 'Braunfels', - 'Kowdalli', - 'Valmadrera', - 'Burr Ridge', - 'Fagersta', - 'Kumharsan', - 'De Panne', - 'Brugg', - 'Quintanar de la Orden', - 'Orono', - 'Itanhomi', - 'Panhar', + 'Carles', + 'Razkrizje', + 'Djado', + 'Wurzburg', + 'Langhnaj', + 'Kysucke Nove Mesto', + 'Ar Rastan', + 'Huehuetoca', + 'Cerca la Source', + 'Goris', + 'Plon', + 'Bad Lauterberg', + 'Gasparillo', + 'Sao Amaro das Brotas', + 'Rangvasa', + 'Kolokonde', + 'Osmancik', 'Trofaiach', - 'Southborough', - 'Camisano Vicentino', - 'Elwood', - 'Congaz', - 'Shahrinav', - 'Mortad', - 'Kachnar', - 'White City', - 'Langeloop', - 'Puerto Caicedo', - 'Unicov', - 'Sao Jose do Campestre', - 'Nandayure', - 'Nawalpur', - 'Morant Bay', - 'Matsuo', - 'Mineral de Angangueo', - 'Hasbergen', - 'Iver', - 'Iuiu', - 'Saint-Saulve', - 'Gengenbach', - 'Kattupputtur', - 'La Massana', - 'Phulgachhi', - 'Kall', - 'Oporapa', - 'Alto Parnaiba', - 'Ikkadu', - 'Waupun', - 'Vila Frescainha', - 'Tha Chang', - 'An Phu', - 'Caorle', - 'Sorontona', - 'Firoza', - 'Murska Sobota', + 'Seaford', + 'Appley Bridge', + 'Majadahonda', + 'Sudley', + 'Raman Mandi', + 'Diyarbakir', + 'Xiaoxita', + 'Azacualpa', + 'Mullassheri', + 'Aruppukkottai', + 'El Rosario', + 'Puyo', + 'Pomichna', + 'Plaisance-du-Touch', + 'Ghosrawan', + 'Yuba City', + 'Homs', + 'Baunatal', + 'Cape Coral', + 'Umburanas', + 'Kakegawa', + 'Shahr-e Pir', + 'Neiba', + 'Thiers', + 'Chorbog', + 'Melton Mowbray', + 'Ariyalur', + 'Suarez', + 'Manoel Vitorino', + 'Sint-Katelijne-Waver', + 'Nongzhangjie', + 'Bayan', + 'Ceduna', + 'Grand Falls', + 'Masallatah', + 'Meppen', + 'Bromley', + 'Vanves', + 'Novelda', + 'Kaspi', + 'Horseheads', + 'Rath', + 'Vadakarai Kil Pidagai', + 'El Kansera', + 'Tanmen', + 'Henin-Beaumont', + 'Fort Payne', + 'Southlake', + 'Kaeng Khoi', + 'Broughton Astley', + 'Oyamazaki', + 'Rodolfo Sanchez Taboada', + 'Devrukh', + 'Kombai', + 'Juvisy-sur-Orge', + 'Aigua', + 'Sandridge', + 'Oum el Bouaghi', 'Marilandia', - 'Comarnic', - 'Peri-Mirim', - 'Yamanouchi', - 'Mierlo', - "'Ain Taghrout", - 'Ollerton', - 'Port Wentworth', - 'Hatwans', - 'Kariz', - 'East Hanover', - 'Castelvetro di Modena', - 'Capitao de Campos', - 'Georgian Bluffs', - 'Oud-Heverlee', - 'Nagojanahalli', - 'Parapua', - 'Duggirala', - 'Ararenda', - 'Gucheng', - 'Illintsi', - 'Ksar Sbahi', - 'Biganos', - 'Yargatti', - 'Alcoa', - 'Raceland', - 'Melsele', - 'Calcado', - 'Bang Ban', - 'Chassieu', - 'Bhattiprolu', - 'Ban Wang Daeng', - 'Panguipulli', - 'Wulingshancun', - 'San Luis de La Loma', - 'Si Wilai', - 'Terku Valliyur', - 'Aydincik', - 'Herrsching am Ammersee', - 'Kariat Ben Aouda', - 'Ceu Azul', - 'Bagamanoc', - 'El Trebol', - 'Divinolandia', - 'Gacheta', - 'Canandaigua', - 'Juruaia', + 'Pirbahora', + 'Bauria', + 'Matsushige', + 'Ipatinga', + 'Venkatagirikota', + 'Hazel Crest', + 'Codegua', + 'North Castle', + 'Talhar', + 'Kirchberg', + 'Achocalla', + 'Apam', + 'Cloverly', + 'La Trinite', + 'Zivinice', + 'Thanh Hoa', + 'Pocao de Pedras', + 'Tiruvadanai', + 'Koshu', + 'Cuencame de Ceniceros', + 'Tellar', + 'Praia do Carvoeiro', + 'Pursat', + 'Cunupia', + 'North Lakhimpur', + 'Carlsbad', + 'Breinigsville', + 'Saint-Bruno-de-Montarville', + 'Oro Valley', + 'Msemrir', + 'Papendrecht', 'Pedersore', - 'Congonhal', - "Sa'in Qal`eh", + 'Balasore', + 'Cadale', + 'Viera East', + 'Kambila', + 'Snaresbrook', + 'Rockville', + 'Culcheth', + 'San Valentino Torio', + 'Sharbaqty', + 'Chainpura', + 'Laligam', + 'Huntsville', + 'Pidigan', + 'Hohenems', + 'Rabinal', + 'Campo do Brito', + 'Les Lilas', + 'Kudali', + 'Binnaguri', + "Land O' Lakes", + 'Hatch End', + 'Abiy Adi', + 'Prijedor', + 'Affton', + 'Pilon', + 'Boditi', + 'Ferdows', + 'Villa Dolores', + 'Desenzano del Garda', + 'Venaria Reale', + 'Cuite', + 'Nonthaburi', + 'Lawrenceburg', + 'Guasipati', + 'Tottenham', + 'Utica', + 'Al Basrah', + 'Gorukle', + 'Caranavi', + 'Douglass', + 'Havirov', + 'Sukheke Mandi', + 'Audubon', + 'Puerto del Rosario', + 'Chilkuru', + 'Burco', + 'La Mornaghia', + 'Amatitan', + 'Songhuajiangcun', + 'San Antonio de las Vueltas', + 'Azadshahr', + 'Bislig', + 'Rampura', + 'Ban Klang', + 'Granadero Baigorria', + 'Usuda', + 'Montego Bay', + 'Chornomorsk', + 'Saint-Lys', + 'Sabana Grande de Palenque', + 'Xiluodu', + 'Gigaquit', + 'Carrollwood', + 'Kigali', + 'Lyman', + 'Sao Luis', + 'Patakakani', + 'Mar de Ajo', + 'Inverell', + 'Neuville-en-Ferrain', + 'Molde', + 'Petrel', + 'Indian Harbour Beach', + 'Gahi Mammar', + 'Alanya', + 'Shazand', + 'Leso', + 'Auray', + 'Panauti', + 'Ovada', + 'Tokoname', + 'Junnar', + 'Chahar Dangeh', + 'Monte Aprazivel', + 'Maida Babhangawan', + 'Matias Romero', + 'Nasu', + 'Quata', + 'Barracao', + 'Dila', + 'Piatykhatky', + 'Sikeston', + 'Luzzi', + 'Diabougou', + 'Wiesbaden', + 'Chumphon', + 'Cervia', + 'South Dundas', + 'Halfmoon', + 'Jardim de Piranhas', + 'Carol Stream', + 'Coronel Du Graty', + "L'Isle-sur-la-Sorgue", + 'Kapolei', + 'Bad Windsheim', + 'Hitchin', + 'Almeirim', + 'Kurakhove', + 'Mataro', + 'Khao Yoi', + 'Shihezi', + 'Itaiopolis', + 'Iskandar', + 'Pinamungahan', + 'Highland City', + "Ping'an", + 'Khe Sanh', + 'Konigs Wusterhausen', + 'Kottampatti', + 'Tshabong', + 'Gastonia', + 'Fuensalida', + 'Cabot', + 'Celldomolk', + 'Sakiai', + 'Pirmasens', + 'Bostonia', + 'Ngathainggyaung', + 'Nattappettai', + 'Oulad Hamdane', + 'Campo Belo', + 'Portsmouth', + 'Birmitrapur', + 'La Fare-les-Oliviers', + 'Biberach', + 'Kadoli', + 'Sremski Karlovci', + 'Leon Valley', + 'La Huacana', + 'Cambados', + 'Ban Bang Non', + 'Ranai', + 'Orumiyeh', + 'Moyuta', + 'Hansot', + 'Pasewalk', + 'Ukunda', + 'Guarne', + 'Bethal', + 'Schwabach', + 'Laventille', + 'North Reading', + 'Hithadhoo', + 'Shubrakhit', + 'Overath', + 'Karikad', + 'Nakatsu', + 'Pancevo', + 'Hamirpur', + 'Pilar de la Horadada', + 'Akdepe', + 'Phillaur', + 'Itaquaquecetuba', + 'Bridport', + 'Marotaolana', + 'Kowary', + 'Ibaan', + 'Derazhnia', + 'Baishan', + 'Strzelce Krajenskie', + 'Ampere', + 'West Nipissing / Nipissing Ouest', + 'Dashiqiao', 'Iguaraci', - 'Ramanayakkanpalaiyam', - 'Belen de los Andaquies', - 'Pata Ellamilli', - 'Moorslede', - 'Paullo', - 'Piazzola sul Brenta', - 'Pirapetinga', - 'Basaithi', - "Wen'anyi", - 'Pontchateau', - 'Arenzano', - 'Citrus Springs', - 'Berane', - 'Lalsaraia', - 'Dayalpur', + 'Minglanilla', + 'Andalgala', + 'Dili', + 'Galena Park', + 'Cinar', + 'Akropong', + 'Aston', + 'Ire', + 'Vrhnika', + 'Randfontein', + 'Rorvik', + 'Sugbongkogon', + 'Trancas', + 'Dusti', + 'Pernes-les-Fontaines', + 'Gamharia', + 'Rozdilna', + 'Harchoune', + 'Cherakara', + 'Valantaravai', + 'Todmorden', + 'Rehau', + 'Draguignan', + 'Clifton', + 'Murud', + 'Jalna', + 'Chhatarpur', + 'Palavur', + 'Balangiga', + 'Canete', + 'Stoneham-et-Tewkesbury', + 'Puttanattam', + 'Lisen', + 'Carrefour', + 'Qostanay', + 'Triggiano', + 'Chingleput', + 'Sonupur', + 'Spodnje Hoce', + 'Oftersheim', + 'Chom Thong', + 'Nagod', + 'Ecoporanga', + 'Cowley', + 'Schiltigheim', + 'San Andres del Rabanedo', + 'Velilla de San Antonio', + 'Bad Neustadt', + 'Timbo', + 'Muskogee', + 'Enid', + 'Batouri', + 'Kragero', + 'Mirano', + 'Alangayam', + 'Cianorte', + 'Crystal Lake', + 'Sebt Gzoula', + 'Kyazanga', + 'Lendava', + 'Bad Durrheim', + 'Jiangguanchi', + 'Gonzalez Catan', + 'La Roche-sur-Foron', + 'Itapiranga', + 'Aktuluk', + 'Uslar', + 'Luis Correia', + 'Anjahamana', + 'Dracevo', + 'Pavlikeni', + 'Salvatierra de Mino', + 'El Karimia', + 'Heilsbronn', + 'Honaz', + 'Multai', + 'Zarghun Shahr', + 'Jesenice', + 'Catanauan', + 'Haaksbergen', + 'Tiruvasaladi', + 'Karvarakundu', + 'Malay', + 'Tamura', + 'Loma Plata', + 'Hamilton Square', + 'Dewal Thal', + 'Partur', + 'Koilakh', + 'Great Dunmow', + 'Sinj', + 'Bekily', + 'Hercules', + 'Dunstable', + 'Kosgi', + 'Xinsi', + 'Tomboco', + 'Southwick', + 'Sangamner', + 'Mossoro', + 'Khon Kaen', + 'Dhamnagar', + 'Denain', + 'Berezivka', + 'Humaita', + 'Malhipur', + 'San Luis de Since', + 'Martin', + 'Rajapudi', + 'Yucaipa', + 'Ortigueira', + 'City of Paranaque', + 'Kabira', + 'Kalandy', + 'Uwajima', + 'Fantino', + 'San Juan Atitan', + 'Kennesaw', + 'Prattville', + 'Showa', + 'Hakmana', + 'Maastricht', + 'Pesqueria', + 'Ban Ngao', + 'Amparafaravola', + 'Bhagwatpur', + 'Landshut', + 'Justo Daract', + 'San Vicente', + 'Hall in Tirol', + 'Avare', + 'Binxian', + 'Llaillay', + 'Hoskote', + 'La Massana', + 'Tucker', + 'Pacasmayo', + 'Ambato', + 'Apiuna', + 'Shaxi', + 'Mpigi', + 'Evere', + 'Sakaki', + 'Sampona', + 'Puerto Leguizamo', + 'Santiago del Teide', + 'Wudalianchi', + 'Blieskastel', + 'Rutesheim', + 'Phan Ri Cua', + 'Itahri', + 'Chilibre', + 'Schalksmuhle', + 'Askale', + 'Vite', + 'Ibipora', + 'Haugesund', + 'Valdemorillo', + 'Iringal', + 'Tariba', + 'Hays', + 'Annur', + 'Mariental', + 'Cieza', + 'Kirkland', + 'Nohar', + 'Shiso', + 'Yoshinogawa', + 'La Motte-Servolex', + 'Sippola', + 'Bonthe', + 'Rijswijk', + 'Pontinia', + 'Aarhus', + 'Kitaotao', + 'Rreshen', + 'Mahinawan', + 'Manrar', + 'Pattanapuram', + 'Baidoa', + 'Zhongxiang', + 'La Colonia Tovar', + 'Amelia', + 'Fuveau', + 'Aguas Formosas', + 'Trikonavattam', + 'Chewara', + 'Bhado Khara', + 'Novyi Rozdil', + 'Palepalli', + 'Ellamanda', + 'San Martin Totolan', + 'Edinet', + 'Weihai', + 'Granadilla de Abona', + 'Sulphur Springs', + 'Astoria', + 'Seyitgazi', + 'Kingsteignton', + 'Weybridge', + 'Plumtree', + 'Brugnera', + 'Stony Point', + 'Shikrapur', + 'Canguaretama', + 'Pedreira', + 'Kot Kapura', + 'Banyuwangi', + 'Sueca', + 'Afzala', + 'Kenilworth', + 'Stuhr', + 'Riverbank', + 'Jdour', + 'Al Minshah', + 'Warren', + 'Kalundborg', + 'Farroupilha', + 'Walsrode', + 'Ilheus', + 'Heroica Ciudad de Tlaxiaco', + 'Smoline', + 'Cueto', + 'Pingtang', + 'Khorugh', + 'Engandiyur', + 'Canlaon', + 'El Reno', + 'Gadwal', + 'Villa Verde', + 'Pulluru', + 'Talatona', + 'Badepalli', + 'Oltiariq', + 'Aizumisato', + 'Antsoso', + 'Jianganj', + 'Mullurkara', + 'Taouloukoult', + 'Chambray-les-Tours', + 'Tabarre', + 'Bamumkumbit', + 'Maquela do Zombo', + 'Widnau', + 'Kurihara', + 'Shumen', + 'Kosatarosh', + 'Villa Vasquez', + 'Nampicuan', + 'Waasmunster', + 'Wilmington', + 'Silao', + 'Geseke', + 'Jamsa', + 'Forres', + 'Tukh', + 'Aversa', + 'Sanpetru', + 'Terra de Areia', + 'Samahuta', + 'North Kingstown', + 'Chiplun', + 'Sztum', + 'Neustadt an der Donau', + 'Alajuelita', + 'Peyziwat', + 'San Carlos Sija', + "Ji'an Shi", + 'Ciudad de Allende', + 'Carmo do Paranaiba', + 'Dakar', + 'Paulista', + "Rignano sull'Arno", + 'Papenburg', + 'Imanombo', + 'Cabangan', + 'Miedzychod', + 'Guanabacoa', + 'Djemmal', + 'Alpedrete', + 'Alcacer do Sal', + 'Barhagarh', + 'Nong Ki', + 'Kot Shamir', + 'Yugawara', + 'Polangui', + 'Villa Ygatimi', + 'Mathura', + 'Morley', + 'Gokak', + 'Red Hill', + 'Bad Durrenberg', + 'Yeghegnadzor', + 'Muroran', + 'Fair Lawn', + 'Urai', + 'Caiaponia', + 'Chimbarongo', + 'Buabidi', + 'Erba', + 'Elandsdoorn', + 'Mongar', + 'Basankusu', + 'Longji', + 'Sucun', + 'Kakata', + 'Altus', + 'Elizabethtown', + 'Kamlapur', + 'Birkenau', + 'San Mateo Atenco', + 'Viqueque', + 'Dibaya', + 'Sao Benedito', + 'Daphne', + 'Irving', + 'Randazzo', + 'Cameron', + 'Gasa', + 'Salyan', + 'Magadi', + 'Pingzhen', + 'Kibiito', + 'Katherine', + 'Sebekoro', + 'Itamaraca', + 'Changling', + 'Tunduru', + 'River Ridge', + 'El Adjiba', + 'Pardiguda', + 'Guaranesia', + 'Subaykhan', + 'Dar Naim', + 'Fulda', + 'Meiti', + 'Choybalsan', + 'Granollers', + 'Al Qays', + 'Moldava nad Bodvou', + 'El Molar', + 'Bayt Saham', + 'Coruripe', + 'Leawood', + "Kunp'o", + 'Aracati', + 'Soaserana', + 'Ambatofotsy', + 'Linganore', + 'Rotterdam', + 'Kumano', + 'Shoeburyness', + 'Palayan City', + 'Oak Island', + 'Saylac', + 'Darwa', + 'Heidelberg', + 'Puerto Maldonado', + 'Szazhalombatta', + 'Fatwa', + 'Kolattupuzha', + 'Mahinog', + 'Villa Rumipal', + 'Somnaha', + 'Veauche', + 'Baheri', + 'Sangzishi', + 'Moser', + 'Cologne', + 'Rypin', + 'Salinas da Margarida', + 'Carini', + 'Gloria do Goita', + 'Tekes', + 'Northport', + 'Seven Oaks', + 'Nemmara', + 'Consolacion del Sur', + 'El Calafate', + 'Foumbot', + 'Magnolia', + 'Carangola', + 'Caracas', + 'Vallahbhapuram', + 'Al `Aqiq', + 'Sincan', + 'Bebra', + 'Malkapur', + 'Valongo', + 'Flawil', + 'Piprahi', + 'Cheney', + 'Tarar', + 'Gode', + 'Tangkak', + 'La Canada Flintridge', + 'Schwanewede', + 'Thomasville', + 'Wolossebougou', + 'Zunilito', + 'Aristobulo del Valle', + 'Staden', + 'Bakhri', + 'Chatillon', + 'Puerto Varas', + 'El Tarf', + 'Goianinha', + 'Bimgal', + 'Abu Qurqas', + "Aghbalou n'Kerdous", + 'Tayakou', + 'Johnson City', + 'Stjordalshalsen', + 'Kot Mumin', + 'Orbassano', + 'Carius', + 'Dikwella South', + 'Gallipoli', + 'Wschowa', + 'Sundarnagar', + 'Gustrow', + 'Pindai', + 'Mit Ghamr', + 'Xinyaoshang', + 'Torbeck', + 'Marrakech', + 'Xiushuicun', + 'Valasa', + 'Tuttlingen', + 'Avesta', + 'Highgate', + 'Osian', + 'Kanniyambram', + 'Malinao', + 'Xingsha', + 'Oltenita', + 'Capiata', + 'Malanville', + 'Hunters Creek', + 'Balwa', + 'Muli', + 'Lotte', + 'Hikkaduwa', + 'Pelahiivka', + 'Chilapa de Alvarez', + 'Farafenni', + 'Tanbaichicho', + 'Saks', + 'Calilabad', + 'Salvaterra de Magos', + 'Chittayankottai', + 'Popondetta', + 'Synelnykove', + 'Flying Fish Cove', + 'Gikongoro', + 'Baraki', 'Karebilachi', - 'Codigoro', - 'Nossa Senhora dos Milagres', - 'Hebri', - 'Elchuru', - 'Merriam', - 'Niemasson', - 'El Aguila', - 'Tyrnavos', - 'Szprotawa', - 'Passy', - 'Kac', - 'Dois Riachos', - 'Stiring-Wendel', - 'Wyomissing', + 'El Hachimia', + 'Highland Heights', + 'Chilecito', + 'Kawashiri', + 'Scotch Plains', + 'Adi Keyh', + 'Cheung Chau', + 'Therwil', + 'Tiruvalanjuli', + 'Bagrami', + 'San Juan Lalana', + 'Nodinge-Nol', + 'Gonzalez', + 'Moshi', + 'Zhangjiajie', + 'Bafilo', + 'Presidente Prudente', + 'Sassenberg', + 'Kot Addu', + 'Nicholasville', + 'Magitang', + 'Glauchau', + 'Bendrahalli', + 'Mislinja', + 'Nysa', + 'Tomaz pri Ormozu', + 'Tassin-la-Demi-Lune', + 'Schubelbach', + 'Juban', + 'Epinay-sur-Orge', + 'West Bradford', + 'Genk', + 'Miyakonojo', + 'Eastpointe', + 'Quispamsis', + 'Gadda Madiral', + 'Nouadhibou', + 'Neuss', + 'Yanagawa', + 'Kirano', + 'Sheldon', + 'Florange', + 'Albert', + 'Vilcun', + 'Mannheim', + 'Qahramon', + 'Joaquim Tavora', + 'Amravati', + 'Small Heath', + 'Ancon', + 'San Juan Chamelco', + 'Neunkirchen', + 'Timargara', + 'Poole', + 'Tenkodogo', + 'Jidigunta', + 'Agoncillo', + 'Diosd', + 'Kondaparti', + 'Darauli', + 'San Giuliano Milanese', + 'Farkhana', + 'Upernavik', + 'Isehara', + 'Ginsheim-Gustavsburg', + "Port Saint John's", + 'Shekhupura', + 'Malvinas Argentinas', + 'Mirbat', + 'Kishangarh', + 'Ibicui', + 'Tangalla', + 'Napa', + 'Tavares', + 'Koro', + 'Edasseri', + 'Negotin', + 'Barcs', + 'Keshwari', + 'Depew', + 'Kottaya', + 'Khair Khan', + 'Toviklin', + 'New Port Richey East', + 'Tarrega', + 'Mariel', + 'Krabi', + 'Rinconada de Malloa', + 'Felida', + 'Sidi Ifni', + 'Tobre', + 'Yorba Linda', + 'Casper', + 'Hartswater', + 'Guanambi', + 'Winthrop', + 'Marcacao', + 'Bridlington', + 'Feicheng', + 'Pinhalzinho', + 'Dubai', + 'Periyakulam', + 'Tranent', + 'Hammam Sousse', + 'Ampasimbe', 'Santa Mariana', - 'Barton upon Humber', - 'Cologno al Serio', - 'Lake Grove', - 'Shamunpet', - 'Marinette', - 'Doesburg', - 'Mahin', - 'Norvenich', - 'Panazol', - 'Kaniyambadi', - 'Villa La Angostura', - 'Longtaixiang', + 'San Antonio de Ibarra', + 'Charlton Kings', + 'Tecoanapa', + 'Kamwenge', + 'Arai', + 'Jocotepec', + 'Kiziltepe', + 'Hadali', + 'Bahadurpur', + 'Thoen', + 'Nakhon Phanom', + 'Nayoro', + 'Baramati', + 'Lamas', + 'Krupanj', + "Ning'an", + 'Monfalcone', + 'Hitachi-Naka', + 'Lower Burrell', + 'Formoso do Araguaia', + 'Vadigenhalli', + 'Bansbaria', + 'Tupanatinga', + 'Dome', + 'Niles', + 'Siquirres', + 'Boddikurapadu', + 'Bryant', + 'Serebryansk', + "'Ain el Hammam", + 'Aldo Bonzi', + 'Gajhara', + 'Tokyo', + 'Karakthal', + 'Cabildo', + 'Buon Trap', + 'Liushui', + 'Echternach', + 'Vagur', + 'Bicester', + 'Rheden', + 'Asaka', + 'Ulladulla', + 'Titara', + 'Haya', + 'Francisville', + 'Robat Karim', + 'Shidong', + 'Bhadohi', + 'Otsuki', + 'Barnaon', + 'Valavanur', + 'Kyenjojo', + 'Mara Rosa', + 'Markgroningen', 'Planegg', - 'Penagam', - 'General Carneiro', - 'La Calamine', - 'Timperley', - 'Whitchurch', - 'Great Wyrley', - 'San Giustino', - 'Great Neck', - 'Jayaque', - 'Korb', - 'Dalippur', - 'Lower Saucon', - 'Mainvilliers', - 'Hathidah Buzurg', - 'Bangramanjeshvara', - 'Rutesheim', - 'Devanakavundanur', - 'La Trinitaria', - 'San Carlos Centro', - 'Floresta Azul', - 'Shankarpalli', - 'Chhabila', - 'Kadur Sahib', - 'Coshocton', - 'Monmouth', - 'Mandal', - 'Awash', - 'Le Luc', - 'Nanpala', - 'Pharaha', - 'Pompton Lakes', - 'Novoazovsk', - 'Thanh Xuan', - 'Moita Bonita', - 'Wangjiabian', - 'Larbert', - 'Sturgis', - 'Brzeszcze', - 'Fagundes', - 'Glyka Nera', - 'Montlouis-sur-Loire', - 'Ballymoney', - 'Kisara', - 'Epping', - 'Madhopur', - 'Petal', - 'De Pinte', - 'Riorges', - 'Mukasi Pidariyur', - 'Andacollo', - 'Magnolia', - 'Rackeve', - 'Puliyara', - 'Joquicingo', - 'Jacinto', - 'Mohlin', - 'Bithlo', - 'Feira', - 'Sao Sebastiao de Lagoa de Roca', - 'Chornomorske', - 'Sankhavaram', - 'Sakkamapatti', - 'Bottesford', - 'Konen Agrahar', - 'Hikawadai', - 'Yuasa', - 'Lindome', - 'Athy', - 'Koch', - 'Perali', - 'Tezoatlan de Segura y Luna', - 'Aperibe', - 'Kenduadih', - 'Murgod', - 'Rezina', - 'Phanat Nikhom', - 'Tonse West', - 'Delvada', - 'Anguera', - 'Hornsby Bend', - 'Fanlu', - 'Riedlingen', - 'Waihee-Waiehu', - 'Cold Springs', - "Vel'ky Krtis", - 'Sao Felix', - 'Tekkumbagam', - 'Bertinoro', - 'Milicz', - 'Botupora', - 'Gernsheim', - 'Maromme', - 'Amha', - 'Qal`at an Nakhl', - 'Kongupatti', - 'Tirumayam', - 'Balingoan', - 'Brumunddal', - 'Corinda', - 'Carmo da Mata', - 'Weyburn', - 'Ekuvukeni', - 'El Hamel', - 'Tavistock', - 'Allahdurg', - 'Velddrif', - 'Nedelisce', - 'Sannieshof', - 'Itatuba', - 'Bir Ghbalou', - 'Greentree', - 'Gloucester Point', - 'Mawu', - 'Kiwoko', - 'Allonnes', - 'Chatteris', - 'Sarauni Kalan', - 'Fairview Shores', - 'Xinyaoshang', - 'Vijes', - 'Domazlice', - 'Patu', - 'Walur', - 'Dolhasca', - 'Franklin Lakes', - 'Chinna Annaluru', - 'Sebring', - 'Regen', - 'Solymar', - 'Saucillo', - 'Almhult', - 'Lorch', - 'Chauki', - 'Collegedale', - 'La Tuque', - 'Abasingammedda', - 'Ambotaka', - 'Kalafotsy', - 'Antsoha', - 'Maroambihy', - 'Voloina', - 'Ambatomasina', - 'Antsakanalabe', - 'Antsahabe', - 'Antakotako', - 'Tsararano', - 'Mahazony', - 'Fotsialanana', - 'Ambinanindovoka', - 'Ankavandra', - 'Manambolosy', - 'Ambohidranandriana', - 'Tsinjomitondraka', - 'Amporoforo', - 'Ambodimangavolo', - 'Analamitsivalana', - 'Bevata', - 'Antsambahara', - 'Androndrona Anava', - 'Sampona', - 'Marolinta', - 'Andranomeva', - 'Ambodimanary', - 'Maroamalona', - 'Marovantaza', - 'Marotandrano', - 'Efatsy-Anandroza', - 'Manandroy', - 'Tranomaro', - 'Vinaninkarena', - 'Soaserana', - 'Soamanova', - 'Loikaw', - 'Side', - 'Cerro Cora', - 'Zhamog', - 'Pingcha', - 'Al `Amadiyah', - 'Santa Flavia', - 'Itirucu', - 'Saint-Martin-Boulogne', - 'Byelaazyorsk', + 'Cajvana', + 'Tatabanya', + 'Andemaka', + 'Nazilli', + 'Leusden', + 'Kanada', + 'Dasol', + 'Al Wakrah', + 'Lucan', + 'Jelilyuzi', + 'Puerto Quito', + 'Cran-Gevrier', + 'Damous', + 'Gunungsitoli', + 'Minamikarasuyama', + 'Sandton', + 'San Antonio del Tequendama', + 'Paiporta', + 'Guying', + 'Fontenay-le-Fleury', + 'Denov', + 'Bulambuli', + 'Yulu', + 'Cajamar', + 'Brvenica', + 'Ocozocoautla de Espinosa', + 'Panapur Langa', + 'Memmingen', + 'Ban Non Sombun', + 'Oegstgeest', + 'Aigio', + 'Bhanuvalli', + 'Rankovce', + 'Bagchini', + 'Voitsberg', + 'Ban Nong Kathao', + 'Canby', + 'Cosne sur Loire', + 'Nilothi', + 'Ma`arratmisrin', 'Lyndon', - 'Edlapadu', - 'Bagnan', - 'Jagannathpur', - 'Agua de Dios', - 'Patori', - 'Vengapalli', - 'Farkhana', - 'Llandybie', - 'Matino', - 'Issoudun', - 'Westview', - 'Dhilwan Kalan', - 'Meaford', - 'Komorniki', - 'Churchdown', - 'Guspini', - 'Ribeirao Bonito', - 'Schkopau', - "Ma'ai", - 'Bardipuram', - 'Mansinghpur Bijrauli', - 'Myjava', - 'Akyaka', + 'Gurgentepe', + 'Adjahome', + 'Andippatti', + 'West Manheim', + 'Brunsbuttel', + 'Grave', + 'Zapotlan de Juarez', + 'Yakkabog`', + 'Tan Phuoc Khanh', + 'Tinley Park', + 'Baligaon', + 'Bell Ville', + 'Gwagwalada', + 'Pie de Pato', + 'Mount Fletcher', + 'Waris Aliganj', + 'Queens', + 'Tamana', + 'Craibas', + 'Caivano', + 'Grants Pass', + 'Citrus Hills', + 'Elko', + 'El Abiodh Sidi Cheikh', + 'Pathardi', + 'Acatlan', + 'Westwood', + 'Cibinong', 'Dayr `Atiyah', - 'Sabalito', - 'Wildau', + 'Ja`ar', + 'Archdale', + 'Seguin', + 'Vif', + 'San Vicente de Canete', + 'Limbe', + 'Calumet City', + 'Ain el Hadid', + 'Sint-Andries', + 'Skhirate', + 'Assi-Ben Okba', + 'San Ildefonso', + 'Saint-Raphael', + 'Dire Dawa', + 'Koropi', + 'Murata', + 'Mongu', + 'Villa Maria', + 'Taqah', + 'I-n-Amguel', + 'Moloacan', + 'Milford Haven', + 'Campo Alegre', + 'Atlantic Beach', + 'Kalikapur', + 'Fuefuki', + 'Centralina', + 'Sarafand', + 'Chuangjian', + 'Kheralu', + 'Sulecin', + 'Kirchhain', + 'Coffeyville', + 'Uji', + 'Westport', + 'Compostela', + 'Stratford-upon-Avon', + 'Tougue', + 'Neves', + 'Satiro Dias', + 'Numbrecht', + 'Galle', + 'Ilion', + 'Dasarhalli', + 'Flat Rock', + 'Old Bridge', + 'Barbacena', + 'Essa', + 'Peddakurapadu', + 'Chervonopartyzansk', + 'Perth East', + 'Margosatubig', + 'Bossangoa', + 'Ngorkou', + 'Frankenthal', + 'Reguengos de Monsaraz', + 'Roverbella', + 'Annecy-le-Vieux', + 'Woodmoor', + 'Imizucho', + 'Villanueva de la Serena', + 'Kinalur', + 'Depok', + 'Ahrensburg', + 'Kingman', + 'Magu', + 'Guiping', + 'Kopavogur', + 'Hunasamaranhalli', + 'Tora', + 'Malvar', + 'Lentini', + 'Pont-du-Chateau', + 'Laghouat', + 'Jima Abajo', + 'Garbahaarrey', + 'Samsikapuram', + 'Vinanitelo', + 'Nong Wua So', + 'Jawad', + 'Tirunageswaram', + 'Koure', + 'Villabate', + 'Rezekne', + 'Nenton', + 'Canovanas', + 'Los Banos', + "Berre-l'Etang", + 'Al Qunfudhah', + 'Buenopolis', + 'Le Plessis-Robinson', + 'Bilar', + 'San Antonio de Los Altos', + 'Elblag', + 'Masamba', + 'Czeladz', + 'Tmassah', + 'San Vicente del Raspeig', + 'Tejutla', + 'Albano Laziale', + 'Sibkund', + 'Goio-Ere', + 'Kanoya', + 'Dahibhat Madhopur', + 'Santa Maria Ajoloapan', + 'Srebrenica', + 'Bacoor', + 'Novopavlovka', + 'Marcory', + 'Argos', + 'Ivandrika', + 'Iqaluit', + 'Kondazhi', + 'Kos', + 'Newhaven', + 'Bakwa', + 'Mirante da Serra', + 'Limbach-Oberfrohna', + 'Asadabad', + 'Damulog', + 'Bishops Stortford', + 'Jaguaribara', + 'Vadasikarambattu', + 'Kairaki', + 'Koidu-Bulma', + 'Alto-Cuilo', + 'Mondoro', + 'Buon Ho', + 'Laibin', + 'Prymorskyi', + 'Berane', + 'Wulongpu', + 'Bernalillo', + 'Koturkolkara', + 'Bellerive-sur-Allier', + 'Jambe', + 'Kerwada', + 'Kadoma', + 'Antanamalaza', + 'Yildiz', + 'Kamrawan', + "Kan'onjicho", + 'Sekiyado', + 'Tartarugalzinho', + 'Kudra', + 'Mauban', + 'El Tambo', + 'Taquarana', + 'Winneba', + 'Damghan', + 'Balikumbat', + 'Ulundi', + 'Salo', + 'Nyakosoba', + 'Jeffersontown', + 'Lievin', + 'Santeramo in Colle', + 'Casale Monferrato', + 'Palma del Rio', + 'Yizhu', + 'Ankafina Tsarafidy', + 'Nisarpur', + 'Tadpatri', + 'Peebles', + 'Nawalgarh', + 'Ulliyil', + 'Paittur', + 'Chhajli', + 'Concepcion Batres', + 'Nkpor', + 'DuPont', + 'Burgum', + 'Kaposvar', + 'Labangan', + 'Santany', + 'Appingedam', + 'Barton upon Irwell', + 'Bagli', + 'Hatta', + 'Leeds and the Thousand Islands', + 'Catende', + 'Friedeburg', + 'Udaipura', + 'Aranzazu', + 'Umga', + 'Vize', + 'Coriano', + 'Janjgir', + 'Brwinow', + 'Teays Valley', + 'Ban Kaeng', + 'Huebampo', + 'Oadby', + 'Hovsan', + 'Torre-Pacheco', + 'Kolluru', + 'Araban', + 'Ishiki', + 'Daganzo de Arriba', + 'Jagannadapuram', + 'Quinhamel', + 'Nsukka', + 'Midwest City', + 'Alcala', + 'Payson', + 'Kita Chauhattar', + 'Sao Luis Gonzaga do Maranhao', + 'Quezon', + 'Mani', + 'Khammam', + 'Belo Tsiribihina', + 'Carmaux', + 'Idar', + 'Denison', + 'Lucera', + 'Buda', + 'Ankofa', + 'San Miguel', + 'Isaka', + 'Netherton', + 'Conil de la Frontera', + 'Gorazde', + 'Manullahpatti', + 'Preah Vihear', + 'Coello', + 'Sopo', + 'Valadares', + 'Suruc', + 'Ros Comain', + 'Alto Hospicio', + 'Bargas', + "Anzola dell'Emilia", + 'Eichenzell', + 'Lucelia', + 'Betsiaka', + 'Sidi Bibi', + 'Thale', + 'South Stormont', + 'Kaladgi', + 'Alpen', + 'Zumbagua', + 'Encruzilhada do Sul', + 'Megrine', + 'Panorama', + 'Chitrada', + 'Adamantina', + 'Harsum', + 'Unguturu', + 'San Juan Capistrano', + 'Klasterec nad Ohri', + 'Fernley', + 'Aldenhoven', + 'Pien', + 'Cansancao', + 'Kuje', + 'Valenca do Piaui', + 'Fraga', + 'Carleton Place', + 'Castle Bromwich', + 'Leichi', + 'Armacao dos Buzios', + 'Valenton', + 'Myawadi', + 'Leandro N. Alem', + 'Merlo', + 'Lugazi', + 'Foster City', + 'Shurugwi', + 'Labe', + 'Ruwa', + 'Inongo', + 'Coto Brus', + 'Tiruchengodu', + 'Dharmasagaram', + 'Ommen', + 'Khajawa', + 'Urandi', + 'Fayroz Koh', + 'Bajpe', + 'Epalinges', + 'Longreach', + 'Omdurman', + 'Campos Altos', + 'East Lampeter', + 'Podilsk', + 'Bemaharivo', + 'Al Ahmadi', + 'Vallapuram', + 'Sirvel', + 'Gaurdah', + 'Cottica', + 'Izmail', + 'Orangeburg', + 'Crystal Beach', + 'Toumoukro', + 'Chittarkottal', + 'Klipphausen', + 'Donji Vakuf', + 'Tazah Khurmatu', + 'Laur', + 'Raiyam', + "Saint-Jean-d'Illac", + 'Dubrovnik', + 'Mikkabi', + 'Masasi', + 'Artvin', + 'Maisaram', + 'Ostwald', + 'Wuzhou', + 'San Bartolome Milpas Altas', + 'Zhunan', + 'Pine', + 'Susner', + 'Sibalom', + 'Ormoc', + 'Dimataling', + 'Maroantsetra', + 'Trevignano', + 'La Presa', + 'North Dumfries', + 'Munguia', + 'Mangalam', + 'Kraainem', + 'Bathgate', + 'Russell', + 'Oliveira do Bairro', + 'Vettur', + 'Basavana Bagevadi', + 'Ub', + 'Yepocapa', + 'Spearfish', + 'Stassfurt', + 'Irvine', + 'Bratislava', + 'Coatbridge', + 'Hudli', + 'Beni Amrane', + 'Mansourah', + 'Addanki', + 'Volnovakha', + 'Lagoa Real', + 'Salua', + 'Talata-Vohimena', + 'Kyotera', + 'Rovato', + 'Vilankulo', + 'Nanterre', + 'Timahdit', + 'Blandford Forum', + 'Bombardopolis', + 'eManzimtoti', + 'Garges-les-Gonesse', + 'Araceli', + 'Weslaco', + 'Catembe', + 'Ta Khmau', + 'Zempoala', + 'Terracina', + 'Sint-Amandsberg', + 'Monte Santo de Minas', + 'Umm Salal `Ali', + 'Mudbidri', + 'Dores do Indaia', + 'Osilnica', + 'Eger', + 'Chi Linh', + 'El Omaria', + 'Itapui', + 'Ban Bueng', + 'Balad', + 'Blooming Grove', + 'Kivertsi', + 'Bacabal', + 'Fujin', + 'Combs-la-Ville', + 'Aschheim', + 'Kettering', + 'Chinggil', + 'Nangandao', + 'Avalepalli', + 'London', + 'Aguachica', + 'Leidschendam', + 'Sannicandro Garganico', + 'Cambrils', + 'Tenenkou', + 'Lincoln City', + 'San Gennaro Vesuviano', + 'Dumaran', + 'Yuki', + 'Llanes', + 'Ksar Hellal', + 'Clanton', + 'Khomeyn', + 'Petrovaradin', + 'Whitecourt', + 'San Sebastian Salitrillo', + 'Steubenville', + 'Santiago Atitlan', + 'Cecil', + 'Barnegat', + 'Alto Garcas', + 'Xinfeng', + 'Innsbruck', + 'Santa Margarita de Mombuy', + 'Goya', + 'Inisa', + 'Temascalapa', + 'Ouake', + 'Ambararatabe', + 'Las Delicias', + 'Zawal', + 'Longkoucun', + "Fil'akovo", + 'Concepcion del Uruguay', + 'Seixal', + 'Empedrado', + 'Meram', + 'Matagob', + 'Boufatis', + 'Juanjui', + 'Butha-Buthe', + 'Mutterstadt', + 'Koulikoro', + 'Narhat', + 'Hateg', + 'Americana', + 'Copacabana', + 'Lajkovac', + 'Beasain', + 'Miyoshi', + 'Mooka', + 'Zhuangwei', + 'Dobeln', + 'Brest', + 'Hartlepool', + 'Jajpur', + 'Moncagua', + 'Tarnow', + 'Holt', + 'Hancheng', + 'Ciudad Guzman', + 'Boudouaou el Bahri', + 'Suhiya', + 'Oteapan', + 'Zhoujia', + 'Hohhot', + 'Bulle', + 'Helensburgh', + 'San Jose Villanueva', + 'Lethem', + 'Landen', + 'Gonaives', + 'Mahopac', + 'Tuyen Quang', + 'Shaowu', + 'Celbridge', + 'Artsyz', + 'Heshan', + 'Boutilimit', + 'Bure', + 'Jangid', + 'Doberlug-Kirchhain', + 'Kawara', + 'Meldola', + 'Xinglong', + 'Ntungamo', + 'Shubra al Khaymah', + 'Eldama Ravine', + 'Sukuta', + 'Ain Tedeles', + 'Bara', + 'Barei', + 'Caballococha', + 'Locorotondo', + 'Pine Creek', + 'Mechanicsville', + 'Baxdo', + 'Mysliborz', + 'Androtsy', + 'Newcastle under Lyme', + 'San Jose de Chiquitos', + 'Forchheim', + 'Sabana Iglesia', + 'Saint-Max', + 'Cordenons', + 'Dent', + 'Verdejante', + 'Enkoping', + 'Paradise Valley', + 'Arnaud', + 'Janapul', + 'Sintra', + 'Misserete', + 'Lapinig', + 'Singhbari', + 'Librazhd', + 'Amberg', + 'Pires do Rio', + 'Kenora', + 'Satosho', + 'Anosivelo', + 'Coos Bay', + 'Pathum Thani', + 'Curchorem', + 'Bergambacht', + 'Dahbed', + 'Haslingden', + 'Shahin Dezh', + 'Faridabad', + 'Patera', + 'Saint-Cyr-sur-Loire', + 'Ilhota', + 'Chianki', + 'Garcia', + 'Meine', + 'Kalamazoo', + 'Spitalfields', + 'Maralal', + 'Aruvapalam', + 'Pedro Juan Caballero', + 'Antanifotsy', + 'Suhl', + 'Hancha', + 'Sansepolcro', + 'Villa Martin Colchak', + 'Ksar Chellala', + 'Voznesensk', + 'Requinoa', + 'Vemalwada', + 'Athieme', + 'Neuburg', + 'Tikamgarh', + 'Mazidagi', + 'Florence-Graham', + 'Ikeja', + 'Dinara', + 'Ampanihy', + 'Woodinville', + 'El Palomar', + 'Shafinagar', + 'Jandrapeta', + 'Finglas', + 'Pikesville', + 'Sidney', + 'Tiffin', + 'Belvedere Park', + 'Bad Breisig', + 'Afega', + 'Canilla', + 'Hisarcik', + 'Hertford', + 'Chichkah', + 'Santa Rosa', + 'Palampur', + 'Sanmu', + 'Apuiares', + 'Courtenay', + 'Aiuaba', + 'Hidirbey', + 'Chikuma', + 'Hiddenhausen', + 'Shikohabad', + 'Chilliwack', + 'Tagalft', + 'Chelmno', + 'Colfontaine', + 'Upper Dublin', + 'Ungheni', + 'Estiva', + 'Sveta Ana', + 'Watsa', + 'Gilbert', + 'At Turrah', + 'Payariq Shahri', + 'Ibipeba', + 'San Juan de los Lagos', + 'Barcelona', + 'Ambalamanasy II', + 'Homnabad', + 'Bad Freienwalde', + 'Chandauli', + 'Comitancillo', + 'Bad Konig', + "Sint-Job-in-'t-Goor", + 'Templin', + "D'Iberville", + 'Adelanto', + 'Tepeapulco', + 'Moreni', + 'Blois', + 'Moberly', + 'Encruzilhada', + 'Tokol', + 'Kaneohe', + 'Macomia', + 'Tlalpujahua de Rayon', + 'Kaglipur', + 'Baiceng', + 'Muisne', + 'Fareham', + 'Polistena', + 'Razampeta', + 'Ipojuca', + 'Sandrakatsy', + 'Dagiapara', + 'Madhurapur', + 'Zhuangyuan', + 'Shkoder', + 'Hillsboro', + 'Vidin', + 'Quatipuru', + 'Dubrajpur', + 'Capenda Camulemba', + 'Jaisinghpur', + 'Sonneberg', + 'Gonesse', + 'Toging am Inn', + 'Laranjal Paulista', + 'Tucuru', + 'Arcueil', + 'Francisco I. Madero', + 'Tarumizu', + 'Estrela de Alagoas', + 'Charleston', + 'Cowes', + 'Sessa Aurunca', + 'Fougeres', + "Gricignano d'Aversa", + 'New Germany', + 'Paraparaumu', + 'Pleasant Prairie', + 'Alfena', + 'Payakumbuh', + 'Ramree', + 'Maromme', + 'Kovvur', + 'Derince', + 'Caledon', + 'Jieshang', + 'Navan', + 'Kumbo', + 'Santa Rita do Passa Quatro', + 'Ridgefield', + 'Kllokot', + 'Niramaruthur', + 'Despujols', + 'Narammala', + 'Oroqen Zizhiqi', + 'San Luis del Palmar', + 'Mallawi', + 'Polzela', + 'Troy', + 'El Refugio', + 'Marau', + 'Thaton', + 'Gerede', + 'Lakhanapuram', + 'Chinchina', + 'Duenas', + 'Devizes', + 'Amarillo', + 'Dakor', + 'Brotas', + 'North Auburn', + 'Soamanonga', + 'Villa Alemana', + 'Sathamba', + 'Kanazawa', + 'Namayumba', + 'Ngozi', + 'Mavalli', + 'Maxhutte-Haidhof', + 'Ratnapuram', + 'Midoun', + 'Gostyn', + 'Olopa', + 'Fugangcun', + 'Perungala', + 'Mount Washington', + 'Tekirdag', + 'Cerro Azul', + 'Lahra Muhabbat', + 'Ontario', + 'Santa Maria Chiquimula', + 'North Hempstead', + 'Arma', + 'Awash', + 'Felanitx', + 'Olmaliq', + 'Torremolinos', + 'Gbawe', + 'Sivrihisar', + 'Preussisch Oldendorf', + 'Herrin', + 'Vellalur', + 'Doboj', + 'Guaramirim', + 'Bafoulabe', + 'Nolensville', + 'Acomb', + 'Balaungi', + 'San Juan Ixcaquixtla', + 'Cadereyta', + 'Tarra', + 'Ponta do Sol', + 'Ikaruga', + 'Kaboua', + 'Inagawa', + 'Jacaltenango', + 'Nankana Sahib', + 'Ciudad Melchor de Mencos', + 'Braine-le-Chateau', + 'Gerzat', + 'Abaiara', + 'Maricopa', + 'Saint Neots', + 'Sao Goncalo do Sapucai', + 'Myebon', + 'Markapur', + 'Nova Zagora', + 'Gombong', + 'Gambela', + 'Magsingal', + 'Brezovica', + 'Greifswald', + 'Saint-Nazaire', + 'Poinciana', + 'Hombori', + 'Tsivory', + 'Weiz', + 'Jaguaripe', + 'Kibaya', + 'Wallasey', + 'Nangal Township', + 'Chongzuo', + 'Takamori', + 'Pajo', + 'Daboh', + 'Jisr ez Zarqa', + 'Tizi Rached', + 'Nangal Chaudhri', + 'North Huntingdon', + 'Balilihan', + 'San Josecito', + 'Steinfeld', + 'Velika Gorica', + 'New Cassel', + 'Kyaukme', + 'Kafr Batna', + 'Tepetzintla', + 'Takaharu', + 'Valdepenas', + 'Old Harbour', + 'Siruguppa', + 'Arasur', + 'Grajewo', + 'Aci Catena', + 'Itau de Minas', + 'Zundert', + 'Djakotome', + 'Toulou', + 'Sahar', + 'Opfikon', + 'Damanhur', + 'Yengema', + 'Subic', + 'Kolambugan', + 'Taougrite', + 'Eriyodu', + 'Kiskunmajsa', + 'Germasogeia', + 'Peresecina', + 'Yoshikawa', + "Coeur d'Alene", + 'Mobaye', + 'Borda da Mata', + 'Vecses', + 'Kui Buri', + 'Newport Beach', + 'Palo del Colle', + 'Ripoll', + 'Galsi', + 'Aldama', + 'La Grita', + 'Paese', + 'Sambir', + 'Chapelle', + 'Canteras', + 'Vega Alta', + 'Bhachau', + 'Nanfengcun', + 'Nelson', + 'Chikuzen', + 'Burrillville', + 'Nambour', + 'Sanganakallu', + 'Punch', + 'Borehamwood', + 'Bagan Si Api-api', + 'Tiogollo', + 'Pratteln', + 'Coleford', + 'Huajing', + 'Amoucha', + 'Kannivadi', + 'Winfield', + 'Kimilili', + 'Bugganipalle', + 'Mont-Dore', + 'Chaukhata', + 'Long Lama', + 'Taysan', + 'Caico', + 'Sakardih', + 'Owando', + 'Foleshill', + 'Katlehong', + 'Falkoping', + 'Vellithiruthi', + 'Pancas', + 'Rojales', + 'Juazeiro', + 'Sluis', + 'Matala', + 'Banikoara', + 'Ilicakoy', + 'Montalban', + 'La Algaba', + 'Makeni', + 'Mangrol', + 'Shirdi', + 'Kamphaeng Phet', + 'Prelouc', + 'Podujeve', + 'Redencao', + 'Isaka-Ivondro', + 'Pollensa', + 'Eemnes', + 'Kogon Shahri', + 'Asarhi', + 'Bang Khla', + 'San Andres de Sotavento', + 'Shertallai', + 'Fenglu', + 'El Doncello', + 'Prachatice', + 'Biel/Bienne', + 'Tsabit', + 'Mirante do Paranapanema', + 'Kotoura', + 'Port St. Lucie', + 'Minamichita', + 'Arapiraca', + 'Balcarce', + 'Scionzier', + 'Kharv-e Sofla', + 'Redan', + 'Rolandia', + 'Turrialba', + 'Tsaravary', + 'Sayda', + 'Banepa', + 'Soller', + 'Kaith', + 'Mahdasht', + 'Sandhausen', + 'Redditch', + 'Bemiss', + 'Callaway', + 'Rioblanco', + 'Maesteg', + 'Saronno', + 'Fulgazi', + 'Revuca', + 'Lysychansk', + 'Mandan', + 'Wangjiazhai', + 'Capela de Santana', + 'Toukoto', + 'Vwawa', + 'Dublin', + 'Newark upon Trent', + 'Zacoalco de Torres', + 'Pustomyty', + 'Sangi', + 'Zymohiria', + 'Clinton', + 'Nenjiang', + 'Nova Ubirata', + 'Cosautlan', + 'Kibuye', + 'Darfield', + 'Cornaredo', + 'Ciudad Choluteca', + 'Tvoroyri', + 'Giussano', + 'Manambur', + 'Benfreha', + 'Medarametla', + 'Meridianville', + 'Al Qa`idah', + 'Treinta y Tres', 'Nagar Nahusa', - 'Argostoli', - 'Colwyn Bay', - 'Santa Cruz Balanya', - 'Honwada', - 'North Logan', - 'Parauna', - 'Duas Barras', + 'Kedainiai', + 'Kursenai', + 'Shunan', + 'Dzolokpuita', + 'Lyon', + 'Kleve', + 'Sadon', + 'Fort Pierce', + 'Sanski Most', + 'Zedelgem', + 'Paracho de Verduzco', + 'Hattem', + 'Cantel', + 'Miary-Taheza', + 'Maintirano', + 'Denham Springs', + 'Ap Khanh Hoa', + 'Kaler', + 'Le Pradet', + 'Uxbridge', + 'Cugnaux', + 'Altdorf', + 'Oberhausen', + 'Caacupe', + 'Moyo', + 'Muchun', + 'Roquevaire', + 'Tubod', + 'Bacolor', + 'Nijgaon Paranpur', + 'Sao Pedro da Aldeia', + 'Adrian', + 'Remedios de Escalada', + 'Pehowa', + 'Orlando', + "Mosciano Sant'Angelo", + 'Kasempa', + 'Tomigusuku', + 'Naic', + 'Blanes', + 'Iguacu', + 'Ben Arous', + 'Ben', + 'Westborough', + 'Parkent', + 'Nokaneng', + 'Goianesia', + 'Raniwara Kalan', + 'Lambersart', + 'Handewitt', + 'Beni Haoua', + 'Pargas', + 'Temascalcingo', + 'Abano Terme', + 'Petmanhalli', + 'Karis', + 'Dezhou', + 'Guigue', + 'Melitopol', + 'Tajerouine', + 'Malaimarpuram', + 'Asti', + 'Hanimciftligi', + 'Isua', + 'Enkesen', + 'Birtouta', + 'Relizane', + 'Igrapiuna', + 'Belle Chasse', + 'Calubian', + 'Ararat', + 'Caucete', + 'Hybla Valley', + 'Wipperfurth', + 'Bom Jesus da Lapa', + 'North Salt Lake', + 'Dayan', + 'Zouar', + 'Parang', + 'Mandi Bahauddin', + 'Rovereto', + 'Jinta', + 'Araua', + 'Eugenopolis', + 'Chota Mollakhali', + 'Nabha', + 'Mit Nama', + 'Baia Mare', + 'Katridih', + 'Iwamuro-onsen', + 'Sao Miguel do Iguacu', + 'Suesca', + 'Al Mudaybi', + 'Nauen', + 'Nansio', + 'Nada', + 'Camaligan', + 'Catandica', + 'Ostrov', + 'Wargal', + 'Simarbani', + 'Santa Venera', + 'Bad Gandersheim', + 'Kumbadaje', + 'Samrong', + 'Higashiomi', + 'Chandragiri', + 'General Enrique Mosconi', + 'Seregno', + 'La Florida', + 'Envigado', + 'Landerneau', + 'Sao Pedro da Agua Branca', + 'Orion', + 'Mudgere', + 'Kentwood', + 'Hirono', + 'Kongen', + 'Swamimalai', + 'Tiruchendur', + 'Piploda', + 'Cajamarca', + 'Upata', + 'Lobau', + 'Les Pavillons-sous-Bois', + 'Karungu', + 'Araruama', + 'Fraser', + 'Queven', + 'Kibingo', + 'Senden', + 'Zarbdor Shaharchasi', + 'Goner', + 'West Athens', + 'Butembo', + 'Vadakku Valliyur', + 'Huasco', + 'Brandsen', + 'Halikko', + 'Sabinanigo', + 'Niagara Falls', + 'Sarikei', + 'Okegawa', + 'Reichenbach/Vogtland', + 'Triuggio', + 'Villa Hayes', + 'Tiruttangal', + 'Hasuda', + 'Marpingen', + 'Toms River', + 'Belalcazar', + 'Gembloux', + 'Shuizhai', + 'Ihumwa', + 'Zacualpan de Amilpas', + 'Doddappanayakkanur', + 'Covina', + 'Brikama Ba', + 'Yerkoy', + 'Essenbach', + 'Xiushui', + 'Obuase', + 'Riga', + 'Pokhara', + 'Somoniyon', + 'Itogon', + 'Zelzate', + 'Valence', + 'Bourges', + 'Samthar', + 'Elavalli', + 'Ibitinga', + 'Chembrassheri', + 'Pilao Arcado', + 'Carignan', + 'Sipilou', + 'Colonia Nicolich', + 'Valbom', + 'Naogaon', + 'Decan', + 'Nellore', + 'Makilala', + 'Borgne', + 'Santa Clarita', + 'Vadso', + 'Nandura Buzurg', + 'Polavaram', + 'Bike', + 'Lapinlahti', + 'Cambanugoy', + 'Umri', + 'Kribi', + 'Dogachi', + 'Kara-Kulja', + 'Karibib', + 'La Salvetat-Saint-Gilles', + 'Sidi Ben Adda', + 'Tinpiple', + 'Santa Perpetua de Moguda', + 'Dushanove', + 'Plewiska', + 'Filderstadt', + 'Yerres', + 'Verkhivtseve', + 'Lop Buri', + 'Saldana', + 'Gujo', + 'Dodge City', + 'Belari', + 'Minano', + 'Hamira', + 'Keles', + 'Bichena', + 'Lagoa da Prata', + 'Ormskirk', + 'Heide', + 'Borj Hammoud', + 'Zhuzhou', + 'Heilbronn', + 'Geertruidenberg', + 'Salumbar', + 'Kings Park', + 'Neralakaje', + 'Ciudad Apodaca', + 'Amircan', + 'Samalkha', + 'Hvannasund', + 'Lier', + 'Skadovsk', + 'Nong Khai', + 'Soderhamn', + 'Aghbala', + 'Ban Wisit', + 'Ahram', + 'Dianopolis', + 'North College Hill', + 'Barrechid', + 'Elandakuttai', + 'Yatagan', + 'Macae', + 'Fukayacho', + 'Camaqua', + 'Ypacarai', + 'Santa Paula', + 'Manjo', + 'Sarmada', + 'La Seyne-sur-Mer', + 'Heze', + 'Auch', + 'Nuvem', + 'Lowicz', + 'Erdokertes', + 'Kothia', + 'Bassenge', + 'Bagh-e Malek', + 'New Port Richey', + 'Soisy-sous-Montmorency', + 'Toluprpatti', + 'Niimi', + 'Huaniu', + 'Marratxi', + 'Schwerte', + 'Kontich', + 'Jaynagar', + 'Saint-Fargeau', + 'Tamm', + 'Ain Sefra', + 'Glassboro', + 'Pitoa', + 'Hohenhameln', + 'Babati', + 'Madnur', + 'Chicopee', + 'Tanza', + 'Burke Centre', + 'Guntur', + 'Arvayheer', + 'Ban Pa Hung', + 'Santa Margarita', + 'Manihari', + 'Lamorlaye', + 'Mengen', + 'Pullach im Isartal', + 'Orleaes', + 'Patuakhali', + 'Kharan', + 'Berriozar', + 'Arad', + 'Bra', + 'Bucimas', + 'Lindas', + 'Datca', + 'Vlotho', + 'Zabalj', + 'San Jose del Cabo', + 'Aflao', + 'Joliette', + 'Mamidipalli', + 'Ganguvarpatti', + 'Sitamarhi', + 'Hockessin', + 'Piamonte', + 'Arroyohondo', + 'Alapli', + 'Conflans-Sainte-Honorine', + 'San Lawrenz', + 'Cangas de Narcea', + 'Apaseo el Alto', + 'Castelfranco Emilia', + 'Boucan Carre', + 'Mongat', + 'Sutton', + 'Koungheul', + 'Capodrise', + 'Manhumirim', + 'Mohnyin', + 'San Francisco de Macoris', + 'Veraval', + 'Sint-Martens-Lennik', + 'Ban Bo Haeo', + 'Colinas', + 'Ajaigarh', + 'Arroyito', + 'Gravelines', + 'Little Lever', + 'Sayama', + 'Vitoria do Mearim', + 'Ariana', + 'Thatcham', + 'Chateaudun', + 'Laranja da Terra', + 'Sidi Azzouz', + 'Lokoja', + 'Chamgardan', + 'Worcester Park', + 'Bagnolo Mella', + 'Dewas', + 'Safo', + 'Villanueva y Geltru', + 'Shangxiao', + 'Ayabe', + 'Neo Psychiko', + 'Appenzell', + 'Pototan', + 'Carlos Casares', + 'Vandoeuvre-les-Nancy', + 'Blagoevgrad', + 'Amirli', + 'Jalalpur Jattan', + 'Bilis Qooqaani', + 'Hemsbach', + 'Woodway', + 'Stow', + 'Fukuyama', + 'Geilenkirchen', + 'Villa Isabela', + 'Mosjoen', + 'High Wycombe', + 'Yumbel', + 'Ampasimazava', + 'Mulbagal', + 'Payao', + 'New Garden', + 'Newburn', + "Ak'ordat", + 'Northborough', + 'Pueblo Bello', + 'Prijepolje', + "Espigao D'Oeste", + 'Horstel', + 'Seropedica', + 'Terrytown', + 'Kinnelon', + 'Menggala', + 'Atimonan', + 'Grand Baie', + 'Dodoni', + 'Engenheiro Coelho', 'Santa Croce Camerina', - 'Burkburnett', - 'Citrus', - 'Fao Rai', - 'Pingtouchuanxiang', - 'Bargas', - 'Paura Madan Singh', - 'Warden', - 'Cudworth', - 'Singoli', - 'Pebble Creek', - 'Chicureo Abajo', - 'Oakham', - 'Yelpur', - 'Sesto Calende', - 'Totowa', - 'Easttown', - 'Adjala-Tosorontio', - 'Koronowo', - 'Ahmadli', - 'Pirai do Norte', - 'Xintianfeng', - 'Manaira', - 'Staryya Darohi', - 'Rekovac', - 'Punjai Turaiyampalaiyam', - 'Cachira', - 'As Sabburah', - 'Mallagunta', - 'Satosho', - 'Takad Sahel', - 'Tixkokob', - 'Acanceh', - 'Haigerloch', - 'Cabanillas del Campo', - 'Bawali', - 'North Branch', - 'Champua', - 'Vochaiko', - 'Bhangha', - 'Campagnano di Roma', - 'Sarafand', - 'Ongwediva', - 'Guiratinga', - 'Medog', - 'Zhydachiv', - 'Tres Cachoeiras', - 'Ramabhadrapuram', - 'Alamos', - 'Vengur', - 'Masakkavundanchettipalaiyam', - 'Peschiera del Garda', - 'Grand Haven', - 'Volda', - 'Memunda', - 'Boekel', - 'Szydlowiec', - 'Rogozno', - 'Quimili', - "Dek'emhare", - 'Matias Olimpio', - 'Tarra', - 'El Tarra', - 'Eisenberg', - 'Ruthen', - 'Hellesdon', - 'Nacajuca', - 'Punitaqui', + 'Mambajao', + 'Fateh Nangal', + 'Karimnagar', + 'Oliveira dos Brejinhos', + 'Neykkarappatti', + 'Hooglede', + 'Malacatan', + 'Gbadolite', + 'Bhai Rupa', + 'Khallikot', + 'Uiwang', + 'Kamianka', + 'Omuta', + 'Okagaki', + 'Stepanavan', + 'Kisujszallas', + 'Digar', + 'Glenwood', + 'Siqba', + 'Olsztyn', + 'Zargar', + 'Leamington', + 'Seymour', + 'Ban Mae Ngon Khilek', + 'Wyomissing', + 'Anyang', + 'Paranacity', + 'Paderno Dugnano', + 'Haselunne', + 'Kampong Thum', + 'Paldorak', + 'Brandermill', + 'Wunsiedel', + 'Ribeirao do Largo', + 'Shirud', + 'Melong', + 'Romeoville', + 'Palma Soriano', + 'Filadelfia', + 'Taiyuan', + 'Medicina', + 'Kara', + 'Perunturuttu', + "Sant'Eufemia Lamezia", + 'Villa Canales', + 'Boankra', + 'Dildarnagar', + 'Arraijan', + 'Sonzacate', + 'Manghit', + 'La Valette-du-Var', + 'Loon op Zand', + 'Mutis', + 'Ewa Gentry', + 'Congonhal', + 'Tirua', + 'Firuzoba', + 'Mushin', + 'Okazaki', + 'Thornton', + 'Torbali', + 'Rumburk', + 'Sgamna', + 'Bel-Air', + 'Cassia', + 'Oliveira de Azemeis', + 'Sangrur', + 'Thongwa', + 'Cunco', + 'Bonn', + 'Kalanadu', + 'Magalia', + 'Ficarazzi', + 'Bemarivo', + 'Hadim', + 'Forster', + 'Mahis', + 'Axixa', + 'Putignano', + 'Claye-Souilly', + 'Jaguariuna', + 'Kilifi', + 'Santo Cristo', + 'Gandlapenta', + 'Langenhagen', + 'Orillia', + 'Tshilenge', + 'Donggou', + 'West Lincoln', + 'Victoria', + 'Hoh Ereg', + 'Queensbury', + 'Snovsk', + 'Dabrowa Gornicza', + 'Rosenberg', + 'Nayanakulam', + 'Kreminna', + 'Bissora', + 'Brezno', + 'Xireg', + 'Wittlich', + 'Kanyana', + 'Ohrdruf', + 'Libagon', + 'Fot', + 'Ban Ratchakrut', + 'Xinnongcun', + 'Sotik', + 'Hindarx', + 'Engelskirchen', + 'Marcos', + 'San Miguel Acatan', + 'Mariano Escobedo', + 'Capdepera', + 'Camarate', + 'Corinth', + 'Mejicanos', + 'Sirohi', + 'Takhli', + 'Hodonin', + 'Dabat', + 'Humansdorp', + 'Doncaster', + 'Ballitoville', + 'Combita', + 'Beilngries', + 'Soanierana Ivongo', + 'Mella', + 'Poti', + 'Dongola', + 'Deptford', + 'Azaourisse', + 'Itabirinha de Mantena', + 'Saluzzo', + 'Dumbravita', + 'Cacongo', + 'Mechelen', + 'Sablan', + 'Doaba', + 'Borre', + 'Benghazi', + 'Vasilevo', + 'Nyuzen', + 'Thames Centre', + 'Chavara Gramam', + 'Nivelles', + 'Fairmont', + 'Villa Luzuriaga', + 'Carletonville', + 'Varash', + 'Montemurlo', + 'Mukocho', + 'Sa Kaeo', + 'Gonegandla', + 'Bebandem', + 'Kulp', + 'Plainsboro', + 'Pedro Leopoldo', + 'Mokolo', + 'Mesolongi', + 'Formosa do Rio Preto', + 'Vellmar', + 'Yoko', + 'Sax', + 'Sirvar', + 'Boadilla del Monte', + 'Ziama Mansouria', + 'Brasov', + 'Remedios', + 'Rita', + 'Thane', + 'Fukusaki', + 'Pontypridd', + 'Beysehir', + 'Uchquduq Shahri', + 'Feilding', + 'Silves', + 'Galvan', + 'Great Linford', + 'Zimna Voda', + 'Hirado', + 'Edinburgh of the Seven Seas', + 'Vellodu', + 'Prayagraj', + 'Clermont-Ferrand', + 'La Crosse', + 'San Cristobal Verapaz', + 'Apollo Beach', + 'Cerete', + 'Leskovac', + 'Poltava', + 'Anan', + 'Al Fujayrah', + 'Leramatang', + 'Guastatoya', + 'Fort Wellington', + 'Erumad', + 'Genet', + 'Jondor Shaharchasi', + 'Pudong', + 'Dip', + 'Bystrc', + 'Gakuch', + 'Napoleon', + 'Mathigeri', + 'Hathapur', + 'Kinh Mon', + 'Eidsberg', + 'Quincy-sous-Senart', + 'Yardimli', + 'San Juan Cancuc', + 'Kolbuszowa', + 'Conegliano', + 'Eski Ikan', + 'Hildburghausen', + 'Tirubhuvane', + 'Nikaido-kaminoshocho', + 'Simbahan', + 'Havixbeck', + 'Para', + 'Blomberg', + 'Tionk Essil', + 'Clearview', + 'Imassogo', + 'Whittlesey', + 'Panchgani', + 'Gumani', + 'Kaikkudi', + 'Amatepec', + 'Klotze', + 'Kohtla-Jarve', + 'Vilanova del Cami', + 'Belison', + 'Kakinada', + 'Monte Alto', + 'Walldorf', + 'Alangalang', + 'Carson City', + 'Moises Padilla', + 'Ad Dir`iyah', + 'Hlatikulu', + 'Vigna di Valle', + 'Mosta', + 'Eastern Goleta Valley', + 'Ballenger Creek', + 'Tsukubamirai', + 'Metu', + 'Modachchur', + 'Sukabumi', + 'San Nicolas de los Arroyos', + 'Umingan', + 'Tinnevelly', + 'San Juan Opico', + 'San Vicente de Chucuri', + 'Jacunda', + 'Kaura Namoda', + 'Lodi', + 'Nakhon Sawan', + 'Dunwoody', + 'Katahra', + 'Zhonghechang', + 'Troyes', + 'Goalundo Ghat', + 'Saadatpur Aguani', + 'Ji-Parana', + 'Baroy', + 'Scoresbysund', + 'Santurce-Antiguo', + 'Gagny', + 'La Libertad', + 'Beypore', + 'Puerto Cumarebo', + 'Rasol', + 'Kamalia', + 'Singhana', + 'Vancouver', + 'Angouleme', + 'Cacapava', + 'Laurinburg', + 'Ilhavo', + 'Rangamati', + 'Leogane', + 'Ilkeston', + 'Luganville', + 'Somerville', + 'Biot', + 'Nanyang', + 'Sidi Yahya Zaer', + 'Saltangara', + 'Ban Doi Suthep', + 'San Lorenzo de Esmeraldas', + 'Srinagar', + 'Alberton', + 'Khenchela', + 'Belcista', + 'Chiramanangad', + 'Ordu', + 'Channubanda', + 'Niandjila', + 'Tellicherry', + 'Steenokkerzeel', + 'Conceicao do Rio Verde', + 'Kusapin', + 'Sanjat', + 'Nanxicun', + 'Cedros', + 'Soanenga', + 'La Orotava', + 'Pasvalys', + 'Verdal', + 'Romans-sur-Isere', + 'Katangi', + 'Zhob', + 'Frosinone', + 'Plan-de-Cuques', + 'Bree', + 'Sveti Nikole', + 'Ciudad Tecun Uman', + 'Helsinge', + 'Velez', + 'Balcova', + 'Beni Yakhlef', + 'Arumuganeri', + 'Condado', + 'Xiangkhoang', + 'Parsons', + 'Rouissat', + 'Cetraro', + 'Ozieri', + "Say'un", + 'San Luis Jilotepeque', + 'Vynohradiv', + 'Nampula', + 'Kunsan', + 'Hounde', + 'Robertson', + 'Oarai', + 'Sigus', + 'Golborne', + 'Richmond Heights', + 'Gateshead', + 'Zhenbeibu', + 'Chesham', + 'Canals', + 'Bakau', + 'Belas', + 'Hurricane', + 'Oyo', + 'Ciudad Piar', + 'Palmerston', + 'Chik Ballapur', + 'Bressuire', + 'Mountain Park', + 'Pantelimon', + 'Gooik', + 'Flitwick', + 'Kulattur', + 'Plumstead', + 'Verzej', + 'Kapasiawan', + 'Olds', + 'Nidgundi', + 'Santo Antonio', + 'Dimitrovgrad', + 'Oued Zenati', + 'Kahramanmaras', + 'Chengtangcun', + 'Gonikoppal', + 'Skidaway Island', + 'Moriguchi', + 'Devonport', + 'Samamea', + 'Tsimafana', + 'Lakeside', + 'San Matias', + 'Visconde do Rio Branco', + 'Rivarolo Canavese', + 'Normal', + 'Bahharet Oulad Ayyad', + 'Hurzuf', + 'Allendale', + 'Saint-Charles-Borromee', + 'Netivot', + 'Tunasan', + 'Mazagao', + 'Czarnkow', + 'Ubatuba', + 'Baco', + 'Aralik', + 'Rosamond', + 'Masindi', + 'Vargem da Roca', + 'Mbeya', + 'Byram', + 'Court-Saint-Etienne', + 'Karath', + 'Sidcup', + 'Anage', + 'Midway', + 'Mountain Ash', + 'Agouna', + 'Iakora', 'Adendorf', - 'Neuhof', - 'Highgate', - 'Tirupporur', - 'Iioka', - 'Little Ferry', - 'Cunha Pora', - 'Burgkirchen an der Alz', - 'Tortoli', - 'Lezignan-Corbieres', - 'Longford', + 'Warni', + 'Nakhon Nayok', + 'G`ozg`on', + 'Achacachi', + 'Soamanova', + 'Sao Mamede de Infesta', + 'Brumadinho', + 'Kosamba', + 'Sabuncu', + 'Alicante', + 'Youganning', + 'Neviges', + 'Jaro', + 'Juangriego', + 'Meshkin Dasht', + 'Veinticinco de Mayo', + 'Buyan', + 'Khirbat Ghazalah', + 'Dabola', + 'Bundehra', + 'Bierbeek', + 'Gherla', + 'Tammampatti', + 'Avranches', + 'Dubbo', + 'Southport', + 'Ban Om Noi', + 'Koumra', + 'Bridgeview', + 'Madipakkam', + 'Fiche', + 'Gura Humorului', + 'Satsumasendai', + 'Nautan Dube', + 'Ngaputaw', + 'Erlin', + 'Segorbe', + 'Khandela', + 'Bikrampur Bande', + 'Diavata', + 'Taurage', + 'Tula de Allende', + 'Minato', + 'Tumba', + "Trostyanets'", + 'La Matanza de Acentejo', + 'Sathmalpur', + 'Coycoyan de las Flores', + 'Sierra Madre', + 'Masjed Soleyman', + 'Yokoshibahikari', + 'Trezzano sul Naviglio', + 'Leon', + 'Xinpu', + 'Karacabey', + 'Graaff-Reinet', + 'Maputo', + 'Bargoed', + 'Ndali', + 'Vettikkavala', + 'Bat Yam', + 'Boxmeer', + 'Anao', + 'Riccione Marina', + 'Marilao', + "Saint-Martin-d'Heres", + 'Badamdar', + 'Shaoguan', + 'Asker', + 'Benedito Novo', + 'Az Zubayr', + 'Nemyriv', + 'Madanpur', + 'Hakha', + 'Bumba', + 'Fushe Kosove', + 'Shahrisabz', + 'Clondalkin', + 'Delvada', + 'Waldwick', + 'Pemagatshel', + 'Tubingen', + 'Ejido', + 'Awankh', + 'Shyorongi', + 'Houghton le Spring', + 'Albert Lea', + 'Lazdijai', + 'Sanando', + 'Galugah', + 'Nagcarlan', + 'Huong Thuy', + 'Nettuno', + 'Baalbek', + 'Kunnamkulam', + 'Oiso', + 'Barra do Sul', 'Bishunpur Hakimabad', - 'Palsud', - 'Borsbeek', - 'Devgeri', - 'Satai', - 'Al Ghayzah', - 'Ibiraci', - 'Uttukkuli', + 'North Adams', + 'Shamsa', + 'Madhuban', + 'Tirumala', + 'Ganthier', + 'Guben', + 'Lakamane', + 'Preakness', + 'Caraguatatuba', + 'Ferrol', + 'Partibanur', + 'Venkatadripalem', + 'Aquidaba', + 'Sedico', + 'Baixo Guandu', + 'Navadwip', + 'Zgharta', + 'Morro Bay', + 'Miramichi', + 'Jose Batlle y Ordonez', + 'Zuwarah', + 'Espinal', + 'Brcko', + 'Cham', + 'Kika', + 'Helixi', + 'Pillaro', + 'Lam Tin', + 'Trzebiatow', + 'Nidda', + 'Paulo Lopes', + "Santa Barbara d'Oeste", + 'San Pedro de Ycuamandiyu', + 'Wenchang', + 'Hovd', + 'Scunthorpe', + 'Maspalomas', + 'Oskemen', + 'Raibhir', + 'Palmview', + 'Herrsching am Ammersee', + 'Frederikssund', + 'Yachimata', + 'Rosario de la Frontera', + 'Sinimbu', + 'Valdagno', + 'Roseto degli Abruzzi', + 'Sidi Allal Tazi', + 'Gantt', + 'Pulimel', + 'Ambatomainty', + 'Kumaripur', + 'Haldwani', + 'Zwiesel', + 'Nanqiaotou', + 'Jovellar', + 'Mizhou', + 'Asafabad', + 'Kielczow', + 'Ciying', + 'Erice', + "Palmeira d'Oeste", + 'Comiso', + 'Colac', + 'St. Peters', + 'Gutersloh', + 'Chililabombwe', + 'Joure', + 'Axixa do Tocantins', + 'Celeken', + 'Khvansar', + 'Shepperton', + 'Baghdad', + 'Darwin', + 'Pasaco', + 'Diamond Harbour', + 'Tiruvallur', + 'Hackettstown', + 'Santo Antonio da Platina', + 'General Eugenio A. Garay', + 'St. Helens', + 'Hollister', + 'Patra', + 'Casalmaggiore', + 'Villarrubia de los Ojos', + 'Brejo da Madre de Deus', + 'Attapu', + 'Bambous', + 'Neuenhof', + 'Massape', + 'Hurlingham', + 'Longxing', + 'Xinjun', + 'Yaofeng', + 'Ipubi', + 'Sarikaya', + 'Pambadi', + 'Qinggang', + 'Pirai do Norte', + 'Tha Mai', + 'Scranton', + 'Dang`ara', + 'Murliganj', + 'Villa Sola de Vega', + 'Diedorf', + 'Panchi', + 'Pagadian', + 'Unna', + 'Dongyuancun', + 'Joacaba', + 'San Andres de Giles', + 'Niigata', + 'Bihat', + 'Torqabeh', + 'Rio do Fogo', + 'Yogyakarta', + 'Candido Sales', + 'Barangka', + 'Paramati', + 'Imito', + 'Sugar Land', + 'Kyaliwajjala', + 'Silappadi', + 'Golfito', + 'Kilcock', + 'Moinesti', + 'Gujrat', + 'Keevallur', + 'Culasi', + 'Inanantonana', + 'Sidi Ghiles', + 'Cacolo', + 'Nierstein', + 'Guia Lopes da Laguna', + 'Takieta', + 'Lumaco', + 'Gatteo', + 'Weehawken', + 'Logan', + 'Olimpia', + 'Sidi Zouine', + 'Pardanjan', + 'Celle', + 'Santa Brigida', + 'Kifisia', + 'Leimen', + 'Denizciler', + 'Berezhany', + 'Rangkasbitung', + 'Pagidyala', + 'Infanta', + 'Hackensack', + 'Nakhon Pathom', + 'Tamsaout', + 'Towson', + 'San Teodoro', 'Mahmuda', - 'Volkermarkt', - 'Lichtenstein', - 'Nao Kothi', - 'Cepagatti', - 'Timahdit', - 'Vadamugam Vellodu', - 'Pottireddippatti', - 'Ruisui', - 'Chevigny-Saint-Sauveur', - 'Nallamada', - 'Cacaopera', - 'Ebreichsdorf', - 'Hasseh', - 'Pleasant View', - 'Hamilton Township', - 'Kalavapudi', - 'Pompton Plains', - 'Rialma', - 'Ban Yang Hom', - 'Vashon', + 'Port-Gentil', + 'Federal Way', + 'Kondapalle', + 'Missao Velha', + 'Castres', + "Ash Shuhada'", + 'Almusafes', + 'Limbiate', + 'Jiguani', + 'Amherstburg', + 'Ryde', + 'Nazare Paulista', + 'Lqoliaa', + 'Balua', + 'Pathrajolhania', + 'Ain Karma', + 'Ekangar Sarai', + 'Dunhua', + 'Cherupulassheri', + 'Vutukuru', + 'Cesario Lange', + 'Coevorden', + 'Xiayang', + 'Converse', + 'Shivpuri', + 'Lido di Iesolo', + 'Capao do Leao', + 'Yangliuqing', + 'Kanata', + 'Vientiane', + 'Darhan', + 'Pola', + 'Bardai', + 'Taskopru', + 'Marcq-en-Baroeul', + 'Chestnuthill', + 'Tonse West', + 'Ibirapitanga', + 'Carmo de Minas', + 'Nirala', + 'Gardner', + 'Chorozinho', + 'Novo Selo', + 'Koilkuntla', + 'Ixmiquilpan', + 'Pinole', + 'Kirkby', 'Rokytne', - 'Quilombo', - 'Itamarati', - 'Rumburk', - 'The Hills', - 'Pedappai', - 'Mena', - 'Semuto', - 'Nadendla', - 'Bni Drar', - 'Texcatepec', - 'Vimmerby', - 'Kabirpur', - 'Garmeh', - 'Shoo', - 'Bedford Heights', - 'Corbas', - 'Mazzarino', - 'Sangeorz-Bai', - 'Attard', - 'Etaples', - 'Kaniyur', - 'Orsta', - 'Malente', - 'Chaoke', - 'Valley Center', - 'Ingelmunster', - 'Swarna', - 'Donzdorf', - 'Karakthal', - 'West Caldwell', - 'Minamiise', - 'Sisia', - 'Hakone', - 'Chinnatadagam', - 'Bariarpur Kandh', - 'Basbiti', - 'Madna', - 'Wustermark', - 'Ponteland', - 'Mossley', - 'Ferney-Voltaire', - 'Hollinwood', - 'Kuttappatti', - 'Pellezzano', - 'Barberino di Mugello', - 'Berriozar', - 'Tibubeneng', - 'Wronki', - 'Gueoul', - 'Meliana', - 'Sontha', - 'Altensteig', - 'Karlsdorf-Neuthard', - 'Blitta', - 'Tizi', - 'Prineville', - 'Arniya', - 'Venosa', - 'Timberlane', - 'Bueno Brandao', - 'Groairas', - 'Rincon', - 'Kavaklidere', - 'Kenzingen', - 'Costesti', - 'Meulebeke', - 'Krosno Odrzanskie', - 'Oued Sebbah', - 'Keila', - 'Ogose', - 'Lehman', - 'Yairipok', - 'Koilakh', - 'Roque Perez', - 'Chenango', - 'Muswellbrook', - 'Khanjahanpur', - 'Sangram', - 'Nishi', - 'Pocono', - 'Bobrynets', - 'Osterwieck', - 'Karikad', - 'Chiltiupan', - 'Gages Lake', - 'Passa e Fica', - 'Tarwara', - 'Minamisanriku', - 'Imeni Chapayeva', - 'Bobrovytsia', - 'Xudat', - 'Castel Mella', - 'Nyakosoba', - 'Gilbues', - 'Santona', + 'Haivoron', + 'Charana', + 'Shreveport', + 'Dunkerque', + 'Businga', + 'El Salvador', + 'Teustepe', + 'Begowal', + 'Al `Ayn', + 'Xiaguanying', + 'Mhow', + 'Vittorio Veneto', + 'Savignano sul Rubicone', + 'Bitola', + 'Chomutov', + 'Natividad', + 'Pont-a-Mousson', + 'Ballincollig', + 'Ballymoney', + 'Peixe', + 'As Saff', + 'San Antonio de Areco', + 'Ibi', + 'Hathwan', + 'Esperance', + 'Wangjiabian', + 'Pokrovsk', + 'Davao', + 'Anniston', + 'Rodental', + 'Maple Ridge', + 'Esneux', + 'Ahwa', + 'Monticello Conte Otto', + 'Royal Leamington Spa', + 'Carei', + 'Real', + 'Burjasot', + 'Pingdingshan', + 'Wumayingcun', + 'Asane', + 'Souto Soares', + 'Arvada', + 'Palu', + 'Narasapur', + 'Ivry-sur-Seine', + "Saint-Ouen-l'Aumone", + 'High Blantyre', + 'Draganesti-Olt', + 'Pattoki', + 'Cologno Monzese', + "Ville-d'Avray", + 'Dornava', + 'Ambatomanoina', + 'Qinbaling', + 'So', + 'Villanchirai', + 'Emet', + 'Agatogba', + 'Saint-Laurent-du-Var', + 'Airway Heights', + 'Brasil Novo', + 'Fangting', + 'Mutukuru', + 'Erlensee', + 'Mangur', + 'Olivenca', + "L'Isle-Jourdain", 'Kodmial', - 'Manville', - 'Berthoud', - 'Alto Rio Doce', - 'Kiratpur Rajaram', - 'Haysville', - 'Soyalo', - 'Great Harwood', - 'Hardia', - 'Ghanpur', - 'Qasr-e Qomsheh', - 'Terryville', - 'Bernardo de Irigoyen', - 'Wisla', - 'Saire', - 'Yacopi', - 'Langenzenn', - 'Erstein', - 'Fife', - 'Triangle', - 'Gottmadingen', - 'Gluckstadt', - 'Beni Abbes', - 'Inverurie', - 'Gentio do Ouro', - 'Coroaci', - 'Yungay', - 'La Puebla de Cazalla', - 'Hammelburg', - 'Nova Vodolaha', - 'Itarana', - 'Conceicao dos Ouros', - 'Rambilli', + 'Manresa', + 'Antsahadinta', + 'Fort-Shevchenko', + 'Eisenhuttenstadt', + 'Nicastro', + 'Widekum', + 'Delmenhorst', + 'San Gwann', + 'Soalala', + 'Soweto', + 'Pachor', + 'Naugachhia', + 'Mount Isa', + 'Afmadow', + 'Suzukawa', + 'Radcliffe', + 'Boksburg', + 'Hipperholme', + 'Harim', + 'Chinnampalaiyam', + 'Tilari', + 'Giporlos', + 'Perleberg', + 'Bankya', + 'Capua', + 'Lilio', + 'Qinzhou', + 'Aratuipe', + 'Itaborai', + 'Oldebroek', + 'Tibbar', + 'Douar Ain Chkef', + 'Nueva Tolten', + 'Tetela de Ocampo', + 'Denby Dale', + 'Viareggio', + 'Gangadhar', + 'Durgapur', + 'Arcahaie', + 'Kupiansk', + 'Achhnera', + 'Cherupazhasshi', + 'Benalla', + 'Labhgaon', + 'Bou Fekrane', + 'Chahbounia', + 'Middlebury', + 'Wallerfangen', + 'Fribourg', + 'Chilly-Mazarin', + 'Tibu', + 'Wachtersbach', + 'Valparaiso', + 'Vettavalam', + 'Zamania', + 'Farmers Branch', + 'Neqab', + 'Ayinikkad', + 'Messkirch', + 'Nagamangala', + 'Joinvile', + "M'diq", + 'Schwaigern', + 'Ban Bang Phun', + 'Xudat', + 'Silay', + 'Thikriwala', + 'Lake Wylie', + 'Doukombo', + 'Tual', + 'Phu Quoc', + 'Huludao', + 'Jabonga', + 'Uetze', + 'San Mauro Pascoli', + 'Sao Desiderio', + 'Brignais', + 'Rancho Cordova', + 'Pelezi', + 'Sangota', + 'Ikhlaspur', + 'Guaratuba', + 'Mibu', + 'Arris', + 'Lysander', + 'Kameda-honcho', + 'Mzuzu', + 'Shibukawa', + 'Dongyuya', + 'Allahpur', + 'Harrodsburg', + 'Brig-Glis', + 'Villa San Giovanni', + 'Zhangaozen', + 'Alabang', + 'Saint-Jacques-de-la-Lande', + 'Rampur Rajwa', + 'Te Anau', + 'Ashwaraopeta', + 'Fridley', + 'Hukou', + 'Yerere', + 'Itajuipe', + 'Toda Rai Singh', + 'Oconomowoc', + 'Hudiksvall', + 'Ploiesti', + 'Camilo Ponce Enriquez', + 'Aheqi', + 'Povoa de Santa Iria', + 'Salaspils', + 'Marti', + 'Heswall', + 'Barcelos', + 'Axim', + 'Datoda', + 'Kandra', + 'Montreuil', + 'Lakhnadon', + 'Tarnok', + 'Brades', + 'Sabana Yegua', + 'Ed Daein', + 'Mchinji', + 'Jaral del Progreso', + 'Bouskoura', + 'Gradignan', + 'Norresundby', + 'Bairagnia', + 'Chai Prakan', + 'Cocos', + 'Mwingi', + 'Lucao', + 'Matauna', + 'Pihani', + 'Taishan', + 'Mocamedes', + 'Didieni', + 'Ankiabe-Salohy', + 'Dammapeta', + "La'tamna", + 'Upi', + 'Annakunnu', + 'Iizuka', + 'Pattani', + 'Qiqihar', + 'Maharlika Village', + 'Harborne', + 'Chamusca', + 'Nanshuicun', + 'Milledgeville', + 'Seven Pagodas', + 'Semirom', + 'Candiba', + 'Antofagasta', + 'Tayug', + 'Konobougou', + 'Profesor Salvador Mazza', + 'Perry Heights', + 'Charouine', + 'Unterschleissheim', + 'Kyzyl-Kyya', + 'Hadjout', + 'Zhailuo', + 'Bobigny', + 'Champs-Sur-Marne', + 'Amatan', + 'Tadmait', + 'Zao', + 'Temperance', + 'Grenaa', + 'Zebala', + 'Steynsrus', + 'Buka', + 'Itapororoca', + 'Maranchi', + 'Sikandra Rao', + 'Neftcala', + 'Nguekhokh', + 'Pawtucket', + 'Mechanicsburg', + 'Mold', + 'Tipitapa', + 'Gobindgarh', + 'Bemanevika', + 'Sureshjan', + 'Abomey-Calavi', + 'Caracuaro', + 'Vohimarina', + 'Didim', + 'Getulio Vargas', + 'Hoogvliet', + 'Denton', + 'Rodgau', + 'Abbiategrasso', + 'Oum Drou', + 'Sagwara', + 'Huetor-Tajar', + 'Canovellas', + 'Calan', + 'Droitwich', + 'Gradacac', + 'Czechowice-Dziedzice', + 'Newton in Makerfield', + 'Zabreh', + 'Otavi', + 'Molina', + 'Duncanville', + 'Kumaramputtur', + 'Visnagar', + 'Ichikawa', + 'Shiojiri', + 'Trinity', + 'Shchuchinsk', + 'Kemberg', + 'Isla', + 'Bedele', + 'Cocorna', + 'Pozo Colorado', + 'Motobu', + 'Rodinghausen', + 'Osterhofen', + 'Beckwith', + 'Yafran', + 'Buguey', + 'Hawkesbury', + 'Seria', + 'New London', + 'Agia Varvara', + 'Talisayan', + 'Pothuhera', + 'Tiruppuvanam', + 'Koumpentoum', + 'Sesquile', + 'Freehold', + 'El Haouaria', + 'Tall Rif`at', + 'Nova Timboteua', + 'Novi Iskar', + 'Choghadak', + 'Trinitapoli', + 'Orimattila', + 'Mussoorie', + 'Kozan', + 'Mahatsinjo', + 'Guajiquiro', + 'Bear', + 'Zhoushan', + 'Safford', + 'M.A. Rasulzada', + 'Kalaun', + 'Grijo', + 'San Cristobal Totonicapan', + 'Marbach am Neckar', + 'Panukulan', + 'Salcininkai', + 'Neptune', + 'Cerro de Pasco', + 'Pisac', + 'Puttankulam', + 'Vordingborg', + 'Coto de Caza', + 'Ahumada', + 'Angicos', + 'Jeonju', + 'Detroit', + 'La Gi', + 'Puerto Ayacucho', + 'La Reja', + 'Mymensingh', + 'Bondy', + 'Altoona', + 'Loberia', + 'Novooleksiivka', + 'Vriddhachalam', + 'Tirumalaippatti', + 'Kontcha', + 'Chennai', + 'Nagykata', + 'Havre de Grace', + 'Jimani', + 'Beaune', + 'Montornes del Valles', + 'Dothan', + 'Saiki', + 'Indaial', + 'Nantwich', + 'Foshan', + 'Abu Hamad', + 'Prilly', + 'Chelora', + 'Santa Isabel Ishuatan', + 'Urpaar', + 'Highfields', + 'Choix', + 'Poway', + 'Ormeau', + 'Pulivalam', + 'Maruim', + 'Minobu', + 'Circleville', + 'Noksan', + 'Almada', + 'Sali', + 'New Brunswick', + 'Ottapparai', + 'Sadabe', + 'Tomi', + 'Ramanayakkanpalaiyam', + 'Golpazari', + 'Grunheide', + 'Punalur', + 'Essex Junction', + "Ibra'", + 'Balupur', + 'Collegno', + 'Gzira', + 'Santa Cruz', + 'Les Irois', + 'Lobos', + 'Slubice', + 'Ichinohe', + 'Phonsavan', + 'Had Oulad Issa', + 'Diffun', + 'Cuijk', + 'Algete', + 'Laascaanood', + 'Sayo', + 'Sayada', + 'Xonqa', + 'Numan', + 'Benetuser', + 'Ilaka Atsinanana', + 'Debno', + 'Nagtipunan', + 'Chegutu', + 'Yabu', + 'Maskanah', + 'Tiruvankod', + 'Japaratinga', + 'Horodok', + 'Maevatanana', + 'Lanester', + 'Jequitinhonha', + 'Gibraltar', + 'Acqui Terme', + 'Acasusso', + 'Cumberland', + 'Yildizeli', + 'Coronel Bogado', + 'Daruvar', + 'Dupax del Sur', + 'Gharb', + 'Becerril', + 'Peachtree City', + 'Najrij', + 'Pabna', + 'Millstone', + 'Blidet Amor', + 'Kayapa', + 'Progress', + 'San Pedro del Pinatar', + 'Ambakireny', + 'Afranio', + 'Salangaippalaiyam', + 'Cupira', + 'Elmas', + 'Taunton', + 'Bianyang', + 'Piracaia', + 'Pudsey', + 'Qiryat Ata', + 'Lusaka', + 'Carterton', + 'Robbinsville', + 'Namorona', + 'Vicam Pueblo', + 'Baytown', + 'Kapfenberg', + 'Makoua', + 'Sobral de Monte Agraco', + 'Belek', + 'Rio de Oro', + 'Biga', + 'Shiliguri', + 'Agdas', + 'Bougara', + 'Mit Damsis', + 'Alto Alegre dos Parecis', + 'Cantillana', + 'Waldfeucht', + 'Urcos', + 'Kishanpura Kalan', + 'Buchloe', + 'Suffolk', + 'Gummersbach', + 'Khandhar', + 'Coracora', + 'Mpondwe', + 'Lalin', + 'Xiulin', + 'Chanwari', + 'Kumba', + 'Aware', + 'Colgong', + 'Zeven', + 'Mariano Comense', + 'Campos Lindos', + 'Diu', + 'Aligarh', + 'Nova Pazova', + 'Barhni', + 'Djibo', + 'Soddy-Daisy', + 'Seneffe', + 'Tarn Taran', + 'Dragasani', + 'Bannewitz', + 'Badagabettu', + 'Angichettippalaiyam', + 'Heroica Nogales', + 'Osecina', + 'Kuhsan', + 'Grimstad', + 'Tufanbeyli', + 'Sweetwater', 'Chandur', - 'Wegorzewo', - 'Mae Wang', - 'Bofete', - 'Harri', - 'Garkha', - 'Petrovka', - 'Serravalle', - 'Sahoria Subhai', - 'Khan Bebin', - 'Nivala', - 'Castelginest', - 'Siversk', + 'Novyi Buh', + 'Alzey', + 'Telsiai', + 'Purwokerto', + 'Tarakeswar', + 'Slupca', + 'Malone', + 'Nowrangapur', + 'Khorol', + 'Gudofredo Viana', + 'Od', + 'Tavriisk', + 'Shakhtarsk', + 'Silago', + 'Muskego', + 'Kartarpur', + 'Shofirkon Shahri', + 'Zhangjiakou Shi Xuanhua Qu', + 'Lloyd', + 'Togane', + 'Minabe', + 'Paloma Creek South', + 'Koelwar', + 'Takestan', + 'Cotorra', + 'Lugang', + 'Osaki', + 'Adiyakkamangalam', + 'Fatipura', + 'Jiaoxiyakou', + 'Lakkireddipalle', + 'Calamar', + 'Eastbourne', + 'Manlleu', + 'Santo Andre', + 'Glowno', + 'Ozorkow', + 'Herzliyya', + 'Zaladanki', + 'Druzhkivka', + 'Naron', + 'Nasim Shahr', + 'Penicuik', + 'Kamianets-Podilskyi', + 'Rezzato', + 'Wandlitz', + 'Eufaula', + 'El Hamma', + 'Kattirippulam', + 'Tafo', + 'Bad Sassendorf', + 'Tuticorin', + 'Venado Tuerto', + 'Kanasanapalle', + 'Paulistana', + 'Tauberbischofsheim', + 'Mino', + 'Bapaura', + 'Lao Cai', + 'Winchendon', + 'Akyazi', + 'Baclayon', + 'Radhanpur', + 'Inkerman', + 'Donsol', + 'Vila Real de Santo Antonio', + 'Bottrop', + 'South Orange Village', + 'Grezzana', + 'Konkavaripalle', + 'Nybro', + 'Dharmastala', + 'Waldbrol', + 'Shimomura', + 'Hangal', + 'Ribeirao das Neves', + 'Hachirud', + 'Asmara', + 'Mercogliano', + 'Isparta', + 'Choshi', + 'Rosetta', + 'Shimotsuma', + 'Souagui', + 'Nishigo', + 'Duitama', + 'Salkhad', + 'Tenares', + 'Paita', + 'Zephyrhills', + 'Nacaome', + 'Lezignan-Corbieres', + 'Moncks Corner', + 'Maracena', + 'Gutao', + 'Coseley', + 'Susurluk', + 'Hoofddorp', + 'Taufkirchen', + 'Lebork', + 'West Bridgford', + 'Roda', + 'Laatatra', + 'Sin-le-Noble', + 'Lake Morton-Berrydale', + 'Junik', + 'Gorey', + 'Ferrara', + 'Falla', + 'Atotonilco el Grande', + 'Barnala', + 'Port Chester', + 'Rutland', + 'Gistel', + 'Palestina de los Altos', + 'Manujan', + 'Koja', + 'Vitre', + 'Antsambalahy', + 'Ewo', + 'Silivri', + 'Nitte', + 'Riyadh', + 'Ginir', + 'Figueras', + 'Porvoo', + 'Belamoty', + 'Vista Hermosa de Negrete', + 'Heysham', + 'Laoac East', + 'Ad Dammam', + 'Chisinau', + 'Lanus', + 'Lockport', + 'Powder Springs', + 'Panamarattuppatti', + 'Bisingen', + 'Cotacachi', + 'Bayanan', + 'Ozoir-la-Ferriere', + 'Ouyen', + 'Kuttuparamba', + 'Velimese', + 'Nabeul', + 'Anisio de Abreu', + 'Uozu', + 'Cumaribo', + 'Bhadravati', + 'Kuroshio', + "Barano d'Ischia", + "Qian'an", + 'Oulmes', + 'Bethulie', + 'Tebessa', + 'Columbia City', + 'Kalvarpatti', + 'Nesconset', + 'Quilali', + 'Uddevalla', + 'Teplice', + 'Pindobacu', + 'Xihu', + 'Altonia', + 'Asudapuram', + 'North Fayette', + 'Konstantynow Lodzki', + 'Castellanza', + 'Penalolen', + 'Zimatlan de Alvarez', + 'Minad', + 'Martellago', + 'Chitral', + 'Yumbo', + 'Dunajska Streda', + 'Didy', + 'Horquetas', + 'Pinas', + 'Farragut', + 'Castro Alves', + 'Saatli', + 'Naranapuram', + 'Pine Castle', + 'Penzberg', + 'Fomeque', + 'Goodmayes', + 'Aru', + 'Dobrovo', + 'Martinez de la Torre', + 'West Glens Falls', + 'Vaddadi', + 'Barra da Estiva', + 'Whitefield', + 'Milford city', + 'Guarulhos', + 'Fangchenggang', + 'Edwardsville', + 'Broussard', + 'Lieto', + 'Quimili', + 'Kaiyun', + 'Mocha', + 'Volkach', + 'Vazante', + 'Thu Duc', + 'Penapolis', + 'Nanchital de Lazaro Cardenas del Rio', + 'Phayao', + 'Talwat', + 'Tineo', + 'Opwijk', + 'Diabali', + 'Andranovorivato', + 'Huron East', + 'Poirino', + 'Juquitiba', + 'Tizi Gheniff', + 'Rudolstadt', + 'Kozhinjampara', + 'Huangyoutang', + 'Triel-sur-Seine', + 'Bordj el Kiffan', + 'Unwana', + 'Vanthli', + 'Gramado', + 'Ogawara', + 'Arbatache', + 'Mubende', + 'Itaperuna', + 'Beccles', + 'Balabagan', + 'Jeomchon', + 'Fountain Inn', + 'Passaic', + 'Apaxco de Ocampo', + 'Bhairi', + 'Kalayapuram', + 'Tlahualilo de Zaragoza', + 'Mangasamudram', + 'Kvivik', + 'Arnstadt', + 'South Lebanon', + 'Vinnytsia', + 'Bhimbar', + 'Panakkudi', + 'Paraisopolis', + 'Deux-Montagnes', + 'Antarvedipalem', + 'Pushing', + 'Ichinomiya', + 'Padre Bernardo', + 'Jiblah', + 'Bestwig', + 'Tuba', + 'Porto Amboim', + 'Gonohe', + 'Caernarfon', + 'Oostakker', + 'Ataq', + 'General Panfilo Natera', + 'Sabratah', + 'Andira', + 'Ichtegem', + 'Coban', + 'Sangli', + 'Balhapur', + 'Narayanraopet', + 'Paimio', + 'Alvorada do Sul', + 'El Transito', + 'Tonk', + 'Methil', + 'Ban Phonla Krang', + 'Arac', + 'Selydove', + 'Pecinci', + 'Benidorm', + 'Binkolo', + 'Kailaras', + 'Quibdo', + 'Nieuw Nickerie', + 'Magstadt', + 'Bhirua', + 'Pallipalaiyam', + 'Ampasimatera', + 'Vila do Conde', + 'Fariman', + 'Darihat', + 'Jurong', + 'Zurrieq', + 'Oschatz', + 'Godella', + 'Martano', + 'Wuhu', + 'Gafanha da Nazare', + 'Elsmere', + 'Malior', + 'Sidi el Mokhfi', + 'Mingxing', + 'Elsen', + 'Zinvie', + 'Orange', + 'Rakovnik', + 'Courcouronnes', + 'Eregli', + 'Shengaocun', + 'Badkulla', + 'Zile', + 'North Highlands', + 'Bhubaneshwar', + 'Deurne', + 'Bassano del Grappa', + 'Paonta Sahib', + 'Chapantongo', + 'Samannud', + 'Narayanpet', + 'Chintapalle', + 'Myslenice', + 'Pama', + 'Pedro II', + 'Imperial', + 'Tuvagudi', + 'Erftstadt', + 'Ningbo', + 'Burglengenfeld', + 'Coatepec', + 'Horr-e Riahi', + 'Duayaw-Nkwanta', + 'Unchagao', + 'Sayram', + 'Herouville-Saint-Clair', + 'Nurhak', + 'Joniskis', + 'Fish Town', + "Vranov nad Topl'ou", + 'Thief River Falls', + 'North Miami', + 'Szarvas', + 'Poing', + 'Xanxere', + 'Bulolo', + 'Tin Shui Wai', + 'Auriol', + 'La Calera', + 'Mannachchanellur', + 'San Miguelito', + 'Harsefeld', + 'Zdunska Wola', + 'Hellin', + 'Tours', + 'Uryzhar', + 'Villebon-sur-Yvette', + "'Ain Kihal", + 'Ocean Acres', + 'Paranagua', + 'Coaraci', + 'Saaminki', + 'Ullur', + 'Muttatodi', + 'Abashiri', + 'Tadikalapudi', + 'Mahin', + 'Duderstadt', + 'Utazu', + 'Oleiros', + 'Bolekhiv', + 'Beuvry', + 'Ilagan', + 'Lakhipur', + 'Tepotzotlan', + 'Vallendar', + 'Quimavango', + 'Cobh', + 'Ayutla', + 'Pau', + 'Ngong', + 'Doorn', + 'Libenge', + 'Bin-Houye', + 'Shahr-e Kord', + 'Santiago de Maria', + 'Sabya', + 'Sunninghill', + 'Alhama de Murcia', + 'Usakos', + 'Boke', + 'Ingichka', + 'Montgomery Village', + 'Almonte', + 'Campagnano di Roma', + 'Akbou', + 'Andaingo Gara', + 'Herzberg', + 'Sande', + 'Aracataca', + 'Dipaculao', + 'La Celle-Saint-Cloud', + 'Soja', + 'Semari', + 'Bareilly', + 'Mahna', + 'Wandsworth', + 'Danwan', + 'Manganam', + 'Dinant', + 'Delran', + 'Shangzhen', + 'Mallampalli', + 'Czluchow', + 'San Borja', + 'Sanya', + 'Galion', + 'Tinchlik', + 'Show Low', + 'Mbouda', + 'Hong Kong', + 'Cedar Hill', + 'Baraawe', + 'Rabaul', + 'Matsukawa', + 'Farum', + 'Jishi', 'Rush', - 'Pallarimangalam', - 'Schonaich', - 'Kothri Kalan', - 'Shing', - 'Santa Rosa de Rio Primero', - 'Figuig', - 'Anenii Noi', - 'Herxheim', - 'Estanzuela', - 'Panetha', - 'Guthrie', - 'Sant Joan de Vilatorrada', - 'Sagarejo', - 'Ankasakasabe', - 'Governador Lindenberg', - 'Puck', - 'Arapgir', - 'Lichtenau', - 'Avelino Lopes', - 'Ramchandarpur', - 'Rio dos Cedros', - 'Phrai Bueng', - 'Guantingzhan', - 'Bistan', - 'Tanippadi', - 'Amjhera', - 'Mataili Khemchand', - 'Burrel', - 'Etoumbi', - 'Davos', - 'Bondoufle', - 'Peru', - 'Geldermalsen', - 'Sanjiangkou', - 'Mogotes', - 'Soham', - 'Whitburn', - 'Wan Tau Tong', - 'Nirpur', - 'Malvern', - 'Worth', - 'Sarmiento', - 'Ukal', - 'Belmonte Mezzagno', - 'Adda-Doueni', - 'Risch', - 'Hambuhren', - 'Chirak', - 'Rianxo', - 'Rainhill', - 'Mudki', - 'Johvi', - 'Grand Gosier', - 'Venafro', - 'Onna', - 'Pir Bakran', - 'Estevan', - 'Anuppampattu', - 'Tiruppalaikudi', - 'Gol Tappeh', - 'Venmani Padinjara', - 'Dolbeau', - 'Palakollu', - 'Maryanaj', - 'Martinopole', - 'Steinbach am Taunus', - 'Sucua', - 'Kapaa', - 'Travilah', - 'Brunete', - 'Kyjov', - 'Patrasaer', - 'Yellayapalem', - 'Phibun Mangsahan', - 'Villa Corzo', - 'Pattanam', - 'Nauheim', - 'Afonso Bezerra', - 'Ghagga', - 'Kulgo', - 'Avintes', - 'Vargaur', - 'Ngorongoro', - 'Tatarbunary', - 'Cassa de la Selva', + 'Ubay', + 'Schleusingen', + 'Hengken', + 'Pawai', + 'Margherita di Savoia', + 'Togba', + 'Faradabad', + 'Soron', + 'Ban Tha Mai I', + 'Santa Marta de Tormes', + 'Llantrisant', + 'Huauchinango', + 'Darmaha', + 'Hadano', + 'Porto Real', + 'Pakri', + "N'Djamena", + 'Skuvoy', + 'Novopokrovka', + 'Dighirpar', + 'Summerside', + 'Young', + 'Campagna', + 'Chavuttahalli', + 'Malalbergo', + 'San Victor Abajo', + 'Robertsganj', + 'Toubakoro', + 'Namakadu', + 'Clayton', + 'Xalqobod', + 'Moerdijk', + 'Bergerac', + 'Linxi', + 'La Barca', + 'Hopewell', + 'Riverview', + 'Nanfang', + 'Garwolin', + 'Gannan', + 'Cowell', + 'Zhongguyue', + 'Cacapava do Sul', + 'Fenyang', + 'Chimore', + 'Bahadurganj', + 'Dantewara', + 'San Feliu de Guixols', + 'Puente-Genil', + 'Basmanpur', + 'Baar', + 'Chinautla', + 'Iriga City', + 'Gonglang', + 'Pecs', + 'La Paz Centro', + 'Lienz', + 'Japaratuba', + 'Chiba', + 'Havlickuv Brod', + 'Ranchos', + 'Corning', + 'Zinder', + 'Sankt Gallen', + 'Al Lith', + 'Kaminoyama', + 'Morarano', + 'Sokyriany', + 'Untergruppenbach', + 'Makapanstad', + 'Hullahalli', + 'Empoli', + 'Melton', + 'Abiramam', + 'Villapinzon', + 'Le Vesinet', + 'Den Chai', + 'Khasab', + 'General Deheza', + 'Rideau Lakes', + 'Banora Point', + 'Dillenburg', + 'Acarape', + 'Olympia', + 'Zilina', + 'Chuarrancho', + 'Jaipur Chuhar', + 'Scaggsville', + 'Bat Khela', + 'Villa Jaragua', + 'Oosterzele', + 'La Banda', + 'West Pensacola', + 'Cleckheaton', + 'Gizo', + 'Guaimaca', + 'Chalkida', + 'Namegata', + 'Shibam', + 'Duekoue', + 'Bir Anzarane', + 'Sidi Yahia', + 'Port Hedland', + 'Cisterna di Latina', + 'Dolo', + 'Castro Daire', + 'Kolattur', + 'Hachioji', + 'Sakti', + 'Stanford', + 'Asakapalle', + 'Mazhang', + 'Claypole', + 'Sokal', + 'Byureghavan', + 'Ghasri', + 'Harbin', + 'Renqiu', + 'Bhaur', + 'Canillo', + 'Capellen', + 'Kenton', + 'Balasamudram', + 'Sondershausen', + 'Coburg', + 'Makrana', + 'Zvishavane', + 'Petapa', + 'Piparia', + 'Kiamba', + 'Meyerton', + 'Yi Xian', + 'Tewkesbury', + 'Menomonee Falls', + 'Wilkinsburg', + 'Cildir', + 'Sao Mateus do Maranhao', + 'Belleville', + 'Sandefjord', + 'Santa Branca', + 'Hinckley', + 'Tomblaine', + 'Chizhou', + 'Hardenberg', + 'Victor Harbor', + 'Broadlands', + 'Iskourane', + 'Yuanli', + 'Erattukulakkada', + 'Selcuklu', + 'Colesville', + 'Port Hope', + 'Sidi Amer El Hadi', + 'Bowringpet', + 'Kalpakathukonam', + 'Adonara', + 'Mesquite', + 'Papara', + 'Karambakkudi', + 'El Aguila', + 'West Derby', + 'Bhanvad', + 'Borj el Qoble', + 'Kamikita-kita', + 'Rio Pardo de Minas', + 'Paso Canoas', + 'Holalu', + 'Owani', + 'Katoya', + 'Semdinli', + 'Manaratsandry', + 'San Martin Texmelucan de Labastida', + 'Palo', + 'Vestavia Hills', + 'Deogarh', + 'San Juan del Cesar', + 'Teorama', + 'Secaucus', + 'Tepecoyo', + 'Kadur', + 'Belampona', + 'Ghattu', + 'Sao Jose do Calcado', + 'Shinto', + 'Al Hibah', + 'Gateway', + 'Werdohl', + 'Lenzburg', + 'Gjilan', + 'Zory', + 'Vodurivandlagudem', + 'Hoddesdon', + 'Rawmarsh', + 'Yajalon', + 'Taisheng', + 'Kizhattur', + 'Yongcong', + 'Macomer', + 'Iwamizawa', + 'Bail-Hongal', + 'Maglod', + 'Jauja', + 'Kadiyadda', + 'Tiruvengadam', + 'Alovera', + 'Sao Goncalo do Rio Abaixo', + 'Velike Lasce', + 'Foxborough', + 'Collo', + 'Cincinnati', + 'Manambolo', + 'Rugeley', + 'Kulob', + 'Saparua', + 'Plympton', + 'Malekan', + 'Calheta', + 'Kalanak', + 'Sines', + 'San Ignacio Cohuirimpo', + 'Grottaferrata', + 'Skhira', + 'Harker Heights', + 'El Nido', + 'Morangis', + 'Belp', + 'Estremoz', + 'Baft', + 'State College', + 'Likak', + 'Kanjiza', + 'Schwabmunchen', + 'Adzope', + 'Balamban', + 'Yaojiafen', + 'Klosterneuburg', + 'Coracao de Jesus', + 'Pereshchepyne', + 'Dayr Abu Sa`id', + 'Tofol', + 'Vasad', + 'Rychnov nad Kneznou', + 'Sontha', + 'Mandza', + 'Jatibonico', + 'North Whitehall', + 'Ringnod', + 'Palamel', + 'Pampa', + 'Ahrensfelde', + 'Barwat Pasrain', + 'Haider Khel', + 'Zuera', + 'Yampil', + 'Wyoming', + 'El Outaya', + 'Kikinda', + 'Zefat', + 'Naganuma', + 'Chingford', + 'Weisswasser/Oberlausitz', + 'Stockton', + 'Tournefeuille', + 'Wolfenbuttel', + 'Kieta', + 'Manambaro', + 'Abejorral', + 'Tchitato', + 'Horsforth', + 'Kunithala', + 'Yesilhisar', + 'Gulshan', + 'Sanuki', + 'Laanoussar', + 'Kerouane', + 'Huaycan', + 'Curtorim', + 'Tamallalt', + 'Coronado', + 'Mata Verde', + 'Charenton-le-Pont', + 'Tamri', + 'Villiersdorp', + 'Miorimivalana', + "Ain M'Lila", + 'Siruvachchur', + 'Valdez', + 'Bou Arfa', + 'Bonifacio', + 'Valpoy', + 'Jun Bel', + 'Northcote', + 'Macenta', + 'Guira de Melena', + 'Moranha', + "Jem'at Oulad 'Abbou", + 'Upminster', + 'Bulawayo', + 'Laguna', + 'Adria', + 'Qatlupur', + 'Rumphi', + 'Omaezaki', + 'Ksar El Kebir', + 'Cruzeiro', + 'Semic', + 'Moparipalaiyam', + 'Quanzhou', + 'Wisil', + 'Meadow Lakes', + 'Qrendi', + 'Ang Thong', + 'Nandi Hills', + 'Grayslake', + 'Teguise', + 'Kakunodatemachi', + 'Marupe', + 'Mayen', + 'Miguel Alves', + 'Karnal', + 'Owings Mills', + 'Lewe', + 'Dyykan-Kyshtak', + 'Kentville', + 'Ilijas', + 'San Pedro de Coche', + 'Yermal', + 'Zipaquira', + 'Linganaboyinacherla', + 'Es Sebt', + 'Luisiana', + 'Tamahu', + 'Kudowa-Zdroj', + 'Susice', + 'Saucillo', + 'Castelletto sopra Ticino', + 'Repentigny', + 'Manganj', + 'Algemesi', + 'Methuen Town', + 'Reota', + 'Aiyampuzha', + 'Nisia Floresta', + 'Tukwila', + 'Cayey', + 'Phu Tho', + 'Pishin', + 'Manuel B. Gonnet', + 'Moguer', + 'Petit-Goave', + 'Oulad Salmane', + 'Kadikoy', + 'Cocoa Beach', + "Bulung'ur Shahri", + 'Ambalavato', + 'Qal`eh Ganj', + 'Quierschied', + 'Barrow in Furness', + 'Beifan', + 'Cubulco', + 'Hallbergmoos', + 'Porcari', + 'Kombolcha', + 'Kirkagac', + 'Cacule', + 'Daraga', + 'Qandala', + 'Bagaha', + 'Isoanala', + 'Baulia', + 'Boultham', + 'Samundri', + 'Amangal', + 'Perambalur', + 'Gose', + 'San Pedro La Laguna', + 'Mahendragarh', + 'Offenburg', + 'Sagae', + 'Uttamapalaiyam', + 'Lesquin', + 'Novohrad-Volynskyi', + 'Takab', + 'Shahmirpet', + 'Dom Basilio', + 'Witten', + 'Lavandevil', + 'Katowice', + 'Valavakattumula', + 'Mel Seval', + 'Santa Catarina Otzolotepec', + 'Engenheiro Paulo de Frontin', + 'Alta', + 'Uran', + 'Santo Tirso', + 'Hochstadt an der Aisch', + 'Texistepeque', + 'Stevens Point', + 'Karadipara', + 'Diafarabe', + 'Travnik', + 'Sibi', + 'Bichkunda', + 'Tarpon Springs', + 'Cuicatlan', + 'Bealanana', + 'Nalhati', + 'Surak', + 'Kurumbalur', + 'Whangarei', + 'Hatten', + 'Valrico', + 'Johnstone', + 'Enterprise', + 'Olutanga', + 'Aguelhok', + 'Mezdra', + 'Tanghin-Dassouri', + 'Kamien Pomorski', + 'Santo Domingo Tehuantepec', + 'Ap Phu My', + 'Stamboliyski', + 'Kilis', + 'Ho Nai', + 'Taree', + 'Teulada', + 'Virac', + 'Vigia', + 'Shahrak-e Pars', + 'Zhengzhou', + 'Vikarabad', + 'Liubotyn', + 'Tremonton', + 'Tirmitine', + 'Genas', + 'Evato', + 'Pisa', + 'Kathua', + 'El Bordo', + 'Surin', + 'Bariri', + 'Trelaze', + 'Thatto Heath', + 'Takon', + 'Praya', + 'Baoding', + 'Nakashunbetsu', + 'Eloy', + 'Sao Miguel de Touros', + 'Moulay Driss Zerhoun', + 'El Pinar', + 'Mongomo', + 'Andranovelona', + 'Malbork', + 'Soatanana', + 'Hillerod', + 'Cape Elizabeth', + 'Tirwa', + 'Salatiga', + 'Roncaglia', + 'Selu', + 'Borgo Maggiore', + 'Shelbyville', + 'Bandar-e `Asaluyeh', + 'Ferizaj', + 'Ufeyn', + 'Devanhalli', + 'Akyurt', + 'Jawalgeri', + 'Cambita Garabitos', + 'Manalapan', + 'Surendranagar', + 'Tadinada', + 'Heumen', + 'Inzago', + 'Bulach', + 'Tinipuka', + 'Manohisoa', + 'Leisure City', + 'Hilvan', + 'La Estrella', + 'Vulcan', + 'Wallan', + 'Ramareddi', + 'Gava', + 'Beroy Atsimo', + 'Huejotzingo', + 'Tucupita', + 'Ouled Beni Messous', + 'Bedzin', + 'Bidston', + 'Marilandia do Sul', + 'Sechelt', + 'Beernem', + 'Palwal', + 'Puerto Iguazu', + 'Banchpar', + 'Targu Ocna', + 'Sacile', + 'Lajeado', + 'Razole', + 'Peringalam', + 'Cavaillon', + 'Panaji', + 'Kesennuma', + 'Linhai', + 'Silvi Paese', + 'Bairnsdale', + 'Mehidpur', + 'Sivrice', + 'Waynesville', + 'Oulu', + 'Mairena del Alcor', + 'Omatjete', + 'Mokena', + 'Awlouz', + 'Douar Bni Malek', + 'Bonao', + 'Al Karak', + 'Pitimbu', + 'Pandami', + 'Monzon', + 'Molbergen', + 'Sahit', + 'Castleford', + 'Perungulam', + 'Tonekabon', + 'Jasdan', + 'Dharmajigudem', + 'El Cacao', + 'Salavan', + 'Plato', + 'Fontenay-aux-Roses', + 'San Luis de La Loma', + 'Dinbela', + 'Hawthorn Woods', + 'Corabia', + 'Arboledas', + 'Utrecht', + 'Douar Lehouifrat', + 'Dois Vizinhos', + 'Cabo Bojador', + 'Amalou', + 'Rock Falls', + 'Sitebe', + 'Vakkam', + 'Dasnapur', + 'Ankirondro', + 'Rajupalem', + 'El Cajon', + 'Gunbarrel', + 'Yulee', + 'Chatan', + 'Palmer', + 'Fronteiras', + 'Chicureo Abajo', + 'Newberry', + 'Severance', + 'Sattenapalle', + 'Koping', + 'Muhlhausen', + 'Sylvania', + 'San Elizario', + 'Hameenkyro', + 'Confresa', + 'Barbate de Franco', + 'Ararangua', + 'Boston', + 'Frankfurt (Oder)', + 'Ganshoren', + 'Mehdipur', + 'Ambodinonoka', + 'Cajari', + 'La Primavera', + 'Brahmanandapuram', + 'Oued Rhiou', + 'Polegate', + 'Dodoma', + 'Mecheraa Asfa', + 'Aracas', + 'Rushden', + 'Korosten', + 'Deodora', + 'Pell City', + 'Beppu', + 'Greenburgh', + 'Analaiva', + 'Haar', + 'Cervantes', + 'Uelzen', + 'Budd Lake', + 'Puyang', + 'Aladag', + 'Hajeb el Aioun', + 'Camajuani', + 'Savannah', + 'Pithapuram', + 'Eldersburg', + 'San Policarpo', + 'Mennecy', + 'Ibirapua', + 'Gholia Kalan', + 'Pickerington', + 'Qadsayya', + 'Waldniel', + 'Bagalur', + 'Sao Pedro do Piaui', + 'Bar-le-Duc', + 'Nakhyaungcharipara', + 'Tralee', + 'Penukonda', + 'Ghosai', + 'Pasaquina', + 'Gevgelija', + 'Chokkampatti', + 'Illzach', + 'Huadian', + 'Baryshivka', + 'Siofok', + 'Yutan', + 'Njombe', 'Khlung', - 'Mount Kisco', - 'Urubici', - 'Lake Monticello', - 'Atchison', - 'Pottipuram', - 'South Dundas', - 'Dabiya', - 'Roseira', - 'Centenario do Sul', - 'Pua', - 'Mutluru', - 'Chiyoda', - 'Khattab', - 'Sitio Novo de Goias', - 'Sao Jeronimo da Serra', - 'Igaratinga', - 'Lavaur', - 'Earlestown', - 'Boizenburg', - 'Jitwarpur Chauth', - 'Reguengos de Monsaraz', - 'Amneville', - 'Jauli', - 'Van Wert', - 'Rajghat Garail', - 'Probistip', - 'Laranja da Terra', - 'Gamharia', - 'Kurwar', - 'Snovsk', - 'Manevychi', - 'Rampur Kalan', - 'Zurrieq', - 'Sao Luis do Curu', - 'Banu Chhapra', - 'Sugarmill Woods', - 'Union Park', - 'Susice', - 'East Cocalico', - 'Amatura', - 'Serekali', - 'Oliveirinha', - 'Dario Meira', - 'Stephanskirchen', - 'Biggin Hill', - 'Kurikuppi', - 'Alberique', - 'Cividale del Friuli', - 'San Valentino Torio', - 'Yuncos', - 'Hejamadi', - 'Alipur', - 'Olivenca', - 'Mulsen', - 'Keza', - 'Shepton Mallet', - 'Kaurihar', - 'Balupur', - 'Ugrinovci', - 'Bileca', - 'Rejiche', - 'Holmen', - 'Le Pont-de-Claix', - 'Chhatapur', - 'Andhana', - 'Tyamagondal', - 'Borshchiv', - 'Gympie', - 'Matomou', - 'Darmaha', - 'Eugenopolis', - 'Icononzo', - 'Palamedu', - 'Mangobandar', - 'Castano Primo', - 'Amuru', - 'Eski Yakkabog`', - 'Tallimarjon Shahri', - 'Bouchagroun', - 'Methil', - 'Terra Boa', - 'Wambrechies', - 'Fox Lake', - 'Panaon', - 'Papraur', - 'Kara-Tash', - 'South Union', - 'Guaraciaba', - 'Scornicesti', - 'Barbosa Ferraz', - 'Capena', - "Cornate d'Adda", - 'Muzaffarnagar', - 'Scaggsville', - 'Timonium', - 'Argeles-sur-Mer', - 'Wooburn', - 'Zafarabad', - 'Wald-Michelbach', - 'Binbrook', - 'Totolapan', - 'Seonar', - 'Marreddipalli', - 'Paduma', - 'Telkap', - 'Kuppachchipalaiyam', - 'Ambohidanerana', - 'Flixton', + 'Dabouziya', + 'Tumpat', + 'Tangpingcun', + 'Chinna Salem', + 'Basaithi', + 'Aranguez', + 'Marand', + 'Tanudan', + "Bet She'an", + 'Pingxiang', + 'Westerlo', + 'Jomasho`y', + 'Brussels', + 'Kempele', + 'Kiranomena', + 'Porto Esperidiao', + 'Padre Burgos', + 'Banda del Rio Sali', + 'Cortlandt', + 'Tepatitlan de Morelos', + 'Eau Claire', + 'Saint-Constant', + 'Schermbeck', + 'Cuautitlan', + 'Kolnur', + 'Ehden', + 'Dazhuangzi', + 'Pebble Creek', + 'Meihekou', + 'Qianjiang Shequ', + 'Matamoros', + 'Calama', + 'Stoneham', + 'Dassel', + 'Khanna', + 'Cankaya', + 'Palos Hills', + 'Elurpatti', + 'Kallakkurichchi', + 'Monte San Giovanni Campano', + 'Orhaneli', + 'Bungoono', + 'Blankenberge', + 'Cordele', + 'Kure', + 'Bolgatanga', + 'Bansalan', + 'Race', + 'Morales', + 'Courcelles', + 'Evaz', + 'Pantepec', + 'Nyirbator', + 'Bellegarde-sur-Valserine', + 'Barahi', + 'Espinosa', + 'Fatehgarh', + 'Tangcun', + 'Brzeziny', + 'Pardwal', + 'Gonzales', + 'San Juan y Martinez', + 'Hirriyat Raznah', + 'Rokhaty', + 'Jiangyin', + 'Andahuaylas', + 'Pamiers', + 'Pinarbasi', + 'Rio Vermelho', + 'Boca del Rio', + 'Timana', + 'Cambridge', + 'Shancheng', + 'San German', + 'Mata Roma', + 'Compiegne', + 'Kadanganeri', + 'Argelato', + 'Torokszentmiklos', + 'Ardesen', + 'Cariamanga', + 'Korahia', + 'Saarwellingen', + 'South Abington', + 'Balete', + 'Fuman', + 'Amdel', + 'Dedemsvaart', + 'Plasencia', + 'Sharonville', + 'Villamarchante', + 'Slobozia', + 'Jinji', + 'Malak Abad', + 'Adakplame', + 'Manoke', + 'Companiganj', + 'Ozu', + 'Friedrichshafen', + 'Loudi', + 'Meerut', + 'Sheohar', + 'Sanjiang Nongchang', + 'Jos', + 'Zhangmu Touwei', + 'Siuna', + 'Clervaux', + 'Nocera Inferiore', + 'Borvayeh-ye Al Bu `Aziz', + 'Uki', + 'Humble', + 'Valaparla', + 'Ajim', + 'Kok-Janggak', + 'Etropole', + 'Idukki', + 'Olmue', + 'Maracanau', + 'Ar Rass', + 'Anivorano Avaratra', + 'Jonesboro', + 'Sanlucar de Barrameda', + 'Estahban', + 'Sujapur', + 'Yilong', + 'Ciudad Altamirano', + 'Rudnyy', + 'Wladyslawowo', + 'Hekinan', + 'Cittanova', + 'Schonebeck', + 'Mangalore', + 'Pehonko', + 'Kacanik', + 'Cauquenes', + 'Chikni', + 'Yongcheng', + 'Town and Country', + 'Assai', + 'Liujiaxia', + 'Harwich', + 'Attur', + 'Ganjam', + 'Matar', + 'Grovetown', + 'Hazro', + 'Findlay', + 'Lower Merion', + 'Hennef', + 'Musikot-Khalanga', + 'Vinjam', + 'Sao Jose', + 'Gengenbach', + 'Salmon Creek', + 'Katoomba', + 'Arrapalli', + 'Krasnystaw', + 'Ban Chang', + "Tai'an", + 'Manucan', + 'Bopolu', + 'Tissint', + 'Vohimasy', + 'Ocana', + 'Dickinson', + 'Middelkerke', + 'Jarajus', + 'El Jadid', + 'Altinyayla', + 'Rongcheng', + 'Puthupalli', + 'Pedro Afonso', + 'Muurame', + 'Castro Valley', + 'Cookstown', + 'Santa Maria das Barreiras', + 'Konand', + 'Dilbeek', + 'Meicheng', + 'Hamma Bouziane', + 'Rottweil', + 'Sao Luis do Curu', + 'Dowlatabad', + 'South Strabane', + 'Schenectady', + 'Baihar', + 'Blacklick Estates', 'Villa Nougues', - 'Los Corrales de Buelna', - 'Nurmo', - 'Sanson', - 'Kondakomarla', - 'Ravutulapudi', - 'Ousseltia', - 'Thouare-sur-Loire', - 'Miyato', - 'Cantillana', - 'Anavatti', - 'Belle Chasse', - 'Bougoula', - 'Annoeullin', - 'Tamiang Layang', - 'Parkstone', - 'Paceco', - 'Ovada', - 'Guaraci', - 'Nekarikallu', - 'Cave', - 'Chiramanangad', - 'Nilavarappatti', - 'Guaitarilla', - 'Matulji', - 'Bhanghi', - 'Nuvem', - 'Raymond', - 'Villamarchante', - 'Naranapuram', - 'Itamogi', - 'Nirkunnam', - 'Akhnur', - 'Pipalrawan', - 'Bhauradah', - 'Waasmunster', - 'Errahalli', - 'Punjai Kalamangalam', - 'Ban Bang Yai', - 'Gounarou', - 'DeForest', - 'Suyo', - 'Morro Bay', - 'Valentigney', - 'Mutukuru', - 'Langhirano', - 'Kirchseeon', - 'Qal`eh Chan`an', - 'Basht', - 'Gleisdorf', - 'Agouna', - 'Khrystynivka', - 'Vire', - 'Sarsai Nawar', - 'Kuhbanan', - 'Epinay-sur-Orge', - 'Kajhi Hridenagar', - 'Jhundo', - 'Niquen', - 'Antanandehibe', - 'Jarjanaz', - 'Kuruvambalam', - 'Rudra Nagar', - 'Del Aire', - 'Lulhaul', - 'Sambre', - 'Odugattur', - 'Pragadavaram', - 'Kilrajakularaman', - 'Alakamisy Anativato', - 'Ilicakoy', - 'East Bakersfield', - 'St. Albans', - 'Bendougouba', - 'Iramaia', - 'Barnoldswick', - 'Tiszafured', - 'Moda', - 'Sunadkuppi', - 'Lyngdal', - 'Suhagi', - 'Kattari', - 'Ogano', - 'Doi Saket', - 'Imi Mokorn', - 'Kuttattuppatti', - 'Jaladurgam', - 'Kelilalina', - 'Wang Sombun', - 'Kleinblittersdorf', - 'Kingri', - 'Babhnoul', - 'Komarolu', - 'Lieshout', - 'Deville-les-Rouen', - 'Lehigh', - 'Itacurubi de la Cordillera', - 'Capela do Alto Alegre', - 'Goasi', - 'Placerville', - 'Mogwase', - 'Na Sceiri', - 'Racale', - 'Jurua', - 'Fondettes', - 'Sarospatak', - 'Karuvelampatti', - 'Padiyur', - 'Munhall', - 'Selsey', - 'Brdovec', - 'Chanteloup-les-Vignes', - 'Kumaravadi', - 'Isola del Liri', - 'West Hanover', - 'Pia', - 'Chandreru', - 'Nandasmo', - 'Bhalpatti', - 'Raybag', - 'Vellavadanparappu', - 'Vidalia', - 'Martinengo', - 'Motta di Livenza', - 'Middle Island', - 'Linthicum', - 'Tuktukan', - 'Choachi', - 'Chapeltique', - 'Le Pradet', - 'Kerai', - 'Le Taillan-Medoc', - 'La Palma del Condado', - 'Deh Bakri', - 'Uropa', - 'Gaohucun', - 'Bad Orb', - 'Panamarattuppatti', - 'Maniamkulam', - 'Monte San Pietro', - 'Westwood Lakes', - 'Douar Bouchfaa', - 'Forestville', - 'Andovoranto', - 'Ankarabato', - 'Taimali', - 'Rogatica', - 'Bazid Chak Kasturi', - 'Zwettl', - 'Rajanagaram', - 'Grezzana', - 'Ripoll', - 'Voisins-le-Bretonneux', - 'Sapahi', - 'Edwards', - 'Sacueni', - 'Asalem', - 'Fujino', - 'Alagappapuram', - 'Otsuchi', - 'Ubala', - 'Gulbaar', - 'Sharg`un', - 'Campolongo Maggiore', - 'Novomyrhorod', - 'Ymittos', - 'Ormesby', - 'Diss', - 'Imani', - 'Richmond Heights', - 'Qaminis', - 'Villers-la-Ville', - 'Xiaozui', - 'Parnera', - 'Tigrana', - 'Nandiala', - 'Thevur', - 'Sivrice', - 'Louvain-la-Neuve', - 'Candiota', - 'Ichnia', - 'Frenstat pod Radhostem', - 'Enumulapalle', - 'Leognan', - 'Sutculer', - 'Raeren', - 'Tamarana', - 'Rewtith', - 'Tanant', - 'Chittarkottal', - 'Sidhap Kalan', - 'Waggaman', - 'Arbaa Sahel', - 'Sesori', - 'Diedorf', - 'Goynucek', - 'Botticino Sera', - 'Santa Catarina Ayotzingo', - 'Sonoma', - 'Morbach', - 'Jyllinge', - 'Bou Khadra', - 'Loano', - 'Shurobod', - 'Aduku', - 'Lwakhakha', - "Bog'ot", - 'Aliabad', - 'Mara Rosa', - 'Ross on Wye', - 'Marcali', - 'Galsi', - 'Tafalla', - 'Sangam', - 'Qal`eh Tall', - 'Malibu', - 'Pine Hill', - 'Ambohinihaonana', - 'Borgloon', - 'Desborough', - 'Tolna', - 'San Felice sul Panaro', - 'Potomac Park', - 'Rancho Mission Viejo', - 'Sam Ko', - 'Tarboro', - 'Sebin Karahisar', - 'Bestwig', - 'Milattur', - "Ville-d'Avray", - 'Kurdi', - 'Hatch End', - 'Sangalbahita', - 'Trevignano', - 'Doraville', - 'Baghuz Fawqani', - 'Bogalusa', + 'Al Qurayyat', + 'Sao Jose de Mipibu', + 'Huddersfield', + 'Chibuto', + 'Groutville', + 'Vert-Saint-Denis', + 'Patzicia', + 'Kankon', + 'La Chaux-de-Fonds', + 'Altenbeken', + 'Blonie', + 'Anda', + 'Masterton', + 'Wieringerwerf', + 'Peruwelz', + 'Ilawa', + 'Dirba', + 'Shankarpalli', + 'Longquan', + 'Bodippatti', + 'Nasukarasuyama', + 'Sam', + 'Ban Nong Prue', + 'Monreale', + 'Barreira', + 'Hetanpur', + 'Shishgarh', + 'Tafresh', + 'Saltcoats', + 'Gopalasamudram', + 'Kafr Saqr', + 'Espinho', + 'Peine', + 'Radevormwald', + 'Pompano Beach', + 'Chavinda', + 'Yishi', + 'Janauba', + 'Ankalgi', + 'Pluderhausen', + 'Sopot', + 'Varpalota', + 'Sanming', + 'Santander', + 'Niskayuna', + 'Gumushacikoy', + 'Obalapuram', + 'Bollate', + 'Ghardaia', + 'Davorlim', + 'San Jacinto del Cauca', + 'Ridderkerk', + 'Athiringal', + 'Jimenez', + 'Ketrzyn', + 'Grugliasco', + 'Segoubougou', + 'Lanji', + 'Cocorote', + 'Mizil', + 'Francisco Beltrao', + 'Toksun', + 'Haka', + 'Bilasuvar', + 'Sabaneta de Yasica', + 'Abqaiq', + 'Hinundayan', + 'King', + 'Satun', + 'Fujioka', + 'Ankadinondry-Sakay', + 'Sentani', + 'Bady Bassitt', + 'Concepcion Tutuapa', + 'Woking', + 'Manlius', + 'Mutsamudu', + 'Khuzdar', + 'Czernica', + 'Balzers', + 'Saydnaya', + 'Suthalia', + 'Stevenson Ranch', + 'Dar Ould Zidouh', + 'South Salt Lake', + 'Voerde', + 'South San Francisco', + 'Sarstedt', + 'Neuwied', + 'Northview', + 'Diez', + 'Cuscatancingo', + 'Worth', + 'Wrentham', + 'Pueblo West', + 'Bispham', + 'Shillong', + 'Goes', + 'Talayazham', + 'Kosk', + 'Imus', + 'Montigny-les-Cormeilles', + 'El Guetar', + 'Campinas', + 'Muggio', + 'Latsia', + 'Leopoldsburg', + 'Tagazhi', + 'Tacaimbo', + 'Karimkunnum', + 'Olifantshoek', + 'Cocal', + 'Petrovac na Mlavi', + 'Likasi', + 'Marmaris', + 'Qarabulaq', + 'Dalin', + 'Straseni', + 'Tamluk', + 'Lemon Grove', + 'Shoreview', + 'Ewa Beach', + 'Ado-Ekiti', + 'Rio Verde', + 'Marina', + "Xi'an", + 'Jutai', + "Quartu Sant'Elena", + 'Santa Ursula', + 'Padiala', + 'Sigatoka', + 'Bien Unido', + 'Yotoco', + 'Goundam', + 'Iconha', + 'Pathari', + 'Kotra', + 'Brookside', + 'Palos de la Frontera', + 'Ban Bang Phlap', + 'Halwan', + 'Arth', + 'Jiaoxiling', + 'Dicholi', + 'Uruapan', + 'Bromont', + 'Yaprakli', + 'Junagadh', + 'Sirvintos', + 'Nandayure', + 'Karimama', + 'Pangantocan', + 'Kanpur', + 'Sao Manuel', + 'Schwelm', + 'North Bergen', + 'Curvelo', + 'Zafargarh', + 'Travilah', + 'Arifiye', + 'Eusebio', + 'Ba`qubah', + 'Nutakki', + 'Hermantown', + 'Kremenets', + 'Enrile', + 'Tavarede', + 'Wiesmoor', + 'Soke', + 'Bandraboua', + 'Dera Allahyar', + 'Welzheim', + 'Calbuco', + 'Markovci', + 'Dumka', + 'Dumaria', + 'Bogue', + 'Manuel Tames', + 'Longjumeau', + 'Igny', + 'Medenine', + 'Govindapalle', + 'Justice', + 'Surappalli', + 'Fara', + 'Sao Francisco do Maranhao', + 'Nandiyalam', + 'Tarrasa', + 'Amaliada', + 'El Hadjira', + 'Hickory', + 'Mandramo', + 'Celendin', + 'Almansa', + 'Yamatotakada', + 'Rhaude', + 'Lingtang', + 'Kfar Kidde', + 'Abadla', + 'Nova Serrana', + 'La Victoria', + 'Adis Zemen', + 'Nanticoke', + 'Douar El Arbaa Bou Quorra', + 'Passo Fundo', + 'Ain el Mediour', + 'Ban Lam Sam Kaeo', + 'Hinwil', + 'Moradabad', + 'Douar Toulal', + 'Hong', + 'Lubbock', + 'Higashikagura', + 'Trentola', + 'Prymorsk', + 'Trzcianka', + 'Borujerd', + 'Elefsina', + 'Teruel', + 'Mugdampalli', + 'Manampatrana', + 'Sisak', + 'Simpelveld', + 'Jonava', + 'Solola', + 'Santo Anastacio', + 'Nalayh', + 'Dumarao', + 'Imgarr', + 'Puerto Triunfo', + 'Dhubaria', + 'San Jose de Aerocuar', + 'Destrnik', + 'Dasso', + 'Calanogas', + 'Ash Shaykh Badr', + 'Klerksdorp', + 'Sardasht', + 'Udamalpet', + 'Xihuangni', + 'Agudos do Sul', + 'Ciudad de Atlixco', + 'Huntley', + 'Leonberg', + 'North Glengarry', + 'Baciu', + 'Hemmoor', + "Montopoli in Val d'Arno", + 'Settimo Torinese', + 'Pul-e `Alam', + 'Kizilcahamam', + 'Bulnes', + 'Koiridih', + 'Ho', + 'Heber', + 'Bristol', + 'Turbaco', + 'Arbaa Laaounate', + 'Ayyagarpet', + 'Xiluo', + 'Nordre Fale', + 'Stara Pazova', + 'Uchinada', + 'Bhikkiwind Uttar', + 'Guerou', + 'Landeh', + 'Lilburn', + 'Calvizzano', + 'San Jose del Rincon Centro', + 'Bagh', + 'Mau', + 'Vincennes', + 'Warrenville', + 'Madiun', + 'Boma', + 'Vettam', + 'Magione', + 'Piscataway', + 'Souk et Tnine Jorf el Mellah', + 'Marly-le-Roi', + 'Khansahibpuram', + 'Otsu', + 'Vitoria', + 'Motril', + 'Asheboro', + 'Cobham', + 'Kalilangan', + 'Dahua', + 'Pozo Almonte', + 'Salem', + 'Babhangaon', + 'Zero Branco', + 'Berberati', + 'Laharpur', + 'Nihal Singhwala', + 'Pesnica', + 'Santa Cruz da Baixa Verde', + 'Newburyport', + 'Alcala de Guadaira', + 'Sodegaura', + 'Al Mazar ash Shamali', + 'Aransas Pass', + 'Xuddur', + 'Port-de-Paix', + 'Kirkstall', + 'Erd', + 'Saint-Martin-Boulogne', + 'Wulong', + 'Nagdha Simla', + 'Roeselare', + 'Lubin', + 'Barberino di Mugello', + 'Cranberry', + 'Oldenzaal', + 'Mascouche', + 'Ashgabat', + 'Mtwara', + 'Mankal', + 'Este', + 'Caririacu', + 'Piranshahr', + 'Xiaozhengzhuang', + 'Khamis Mushayt', + 'Prineville', 'Sidi Namane', - 'Lachhmipur', - 'Sahuli', - 'Dallgow-Doberitz', - 'Santa Ana Huista', - 'Medesano', - 'Lyons', - 'Bischofswerda', - 'Querencia do Norte', - 'Darfield', - 'Gairtganj', - 'Corning', - 'Iretama', - 'Orthez', - 'Jhundpura', - 'Taouloukoult', - 'Peralillo', - 'Gambettola', - 'Matsuda-soryo', - 'Baetov', - 'Darby', - 'Agdz', - 'Tisma', - 'Talsur', - 'Kattipudi', - 'Yampil', - 'Valadares', - 'Trets', - 'Knowle', - 'Cerreto Guidi', - 'Powdersville', - 'Fo-Boure', - 'Uzda', - 'Sebt Ait Ikkou', - 'Mathigeri', - 'Gracanice', - 'Bela Crkva', - 'Cazzago San Martino', - 'Iwai', - 'Fountain Inn', - 'Huetor-Tajar', - 'Bhaur', - 'Dakhram', - 'Maynard', - 'Lohariandava', - 'Ardrossan', - 'Konganapuram', - 'Hemavati', - 'Darb-e Behesht', - 'Clute', - 'Cricova', - 'Itarhi', - 'Singapperumalkovil', - 'Katra', - 'Besagarahalli', - 'Hosahalli', - 'Anoviara', - 'Jesenik', - 'Kivisto', - 'Kankol', - 'Salotgi', - 'Dakhan', - 'Cameri', - 'Capim Branco', - 'Broomall', - 'Sao Bras de Alportel', - 'Betsiaka', - 'La Homa', - 'Monte Alegre do Piaui', - 'Aylesford', - 'Chuqung', - 'Joutseno', - 'Chettimangurichchi', - 'Al Atarib', - 'Gurun', - 'Yeghvard', - 'Plan-les-Ouates', - 'Aulla', - 'Puranattukara', - 'Kala Diara', - 'Malapannanagudi', - 'Leninskoe', - 'Myers Corner', - 'Nakonde', - 'Kursenai', - 'Lamhadi', - 'Bharra', - 'Teus', - 'Daganzo de Arriba', - 'Mysliborz', - 'Ponte Serrada', - 'West Haverstraw', - 'Antsaravibe', - 'Nowa Deba', - 'Novotroitske', - 'Corocoro', - 'Ramareddi', - 'Cookstown', - 'Essex Junction', - 'Hrebinka', - 'Santa Terezinha de Goias', - 'Kadwa', - "Sant'Antioco", - 'Filipstad', - 'Tinchlik', - 'Coite do Noia', - 'Gudibanda', - 'Veseli nad Moravou', - 'Gobardhanpur Kanap', - 'Karadichittur', - 'Galena Park', - 'Atlit', - 'Amayan', - 'Friendly', - 'Almoloya', - 'Lacarak', - 'Ruppichteroth', - 'Sedavi', - 'Bellefontaine Neighbors', - 'Pernes-les-Fontaines', - 'Kumbhari', - 'Sirugudi', - 'Maghra', - 'Felsberg', - 'Ngaputaw', - 'Asfour', - 'Hajeb el Aioun', - 'Lambton Shores', - 'Delareyville', - 'Nueva Helvecia', - 'Barmstedt', - 'Sannicolau Mare', - 'Svedala', - 'Lubawa', - 'Emsburen', - 'Jacinto Machado', - 'Jiwachhpur', - 'Kendall Park', - 'Little Canada', + 'Tapachula', + 'Massawa', + 'Ramewadi', + 'Abancay', + 'Biratnagar', + 'Chilakhana', + 'Tadepalle', + 'Passau', + 'Imerimandroso', + 'Nilanga', + 'Tsukuba-kenkyugakuen-toshi', + 'Veldhoven', + 'Longjiang', + 'Armidale', + 'Alcoy', + 'Gabaldon', + 'Klippansbruk', + 'Yongyang', + 'Canton', + 'Hammonton', + 'Pena Forte', + 'Panamaram', + 'Kankan', + 'Sanaa', + 'Kilchberg', + 'Fulton', + 'Prainha', + 'Andranofasika', + 'Barela', + 'Bhogpur', + 'Crayford', + 'Glenshaw', + 'San Lorenzo', + 'Thiais', + 'Bahce', + 'Oliveira do Hospital', + 'Bhander', + 'Taitung', + 'Caldas da Rainha', + 'Decatur', + 'Basaon', + 'Matteson', + 'Al Hammam', + 'Tayyibat al Imam', + 'Jhakhra', + 'Stiring-Wendel', + 'Vlissingen', + 'Zhongling', + 'Palm Springs', + "Qacha's Nek", + 'Kambaneri Pudukkudi', + 'Khardah', + 'Artashat', + 'Bua Yai', + 'Point Pedro', + 'Tozeur', + 'Luxitun', + 'San Sebastian de Mariquita', + 'Saint-Sauveur', + 'Rumilly', + 'Mortad', + 'Kaithwar', + 'Abertillery', + 'Sulzbach', + 'Tillaivilagam', + 'Veroia', + 'Zeitz', + 'Graz', + 'Kitakyushu', + 'Picasent', + 'Rahden', + 'Mecatlan', + 'Tehri', + 'Mauganj', + 'Burshtyn', + 'Espargos', + 'Travis Ranch', + 'Chokkanathapuram', + 'Bhalil', + 'Pateros', + 'Nambuangongo', + 'Beckum', + 'Sanary-sur-Mer', + 'Budili', + 'Akalapura', + 'Belo Vale', + 'Pavlohrad', + 'Swinton', + 'Cento', + 'Nantou', + 'Flora', + 'Carnaiba', + 'Piotrkow Trybunalski', + 'Conceicao da Feira', + 'Dohazari', + 'Sugito', + 'Si Sa Ket', + 'Sirjan', + 'Zaandam', + 'Titisee-Neustadt', + 'Rafelbunol', + 'Abadou', + 'Suhareke', + 'Pipariya', + 'Binidayan', + 'Kunzelsau', + 'Panjgur', + 'Juana Diaz', + 'Afzalpur', + 'Porirua', + 'Elbasan', + 'Hardi', + 'Forbesganj', + 'Shah Alam', + 'Tiruvegapra', + 'Cat', + 'Clichy-sous-Bois', + 'Qumqo`rg`on', + 'Ban Tha Thong', + 'Auburn Hills', + 'Castelo Branco', + 'Borgo', + 'Rich', + 'Karukachal', + 'Maltby', + 'Notteroy', + 'Glens Falls North', + 'Cunha', + 'Alebtong', + 'Balneario de Camboriu', + 'Anandapuram', + 'Bambalang', + 'Touggourt', + 'Taihe', + 'Saidoke', + 'Jori Kalan', + 'Golet', + 'Sankaranayinar Kovil', + 'Sao Sepe', + 'Saugus', + 'Capaci', + 'Puerto Morazan', + 'Fao Rai', + 'Caracase', + 'Tranas', + 'San Giorgio del Sannio', + 'Abeche', + 'Pak Thong Chai', + 'Sola', + 'Bensalem', + 'Talen', + 'Cidreira', + 'Phangnga', + 'Kalavapudi', + 'Kapsabet', + 'Nawan Shahr', + 'Pyu', + 'Mitsinjo', + 'Bradford', + "N'Gaous", + 'Mionica', + 'Echelon', + 'Antonio Carlos', + 'La Tuque', + 'Nairn', + 'Steenbergen', + 'Sidi Abdelaziz', + 'Jijel', + 'Manzanares', + 'Zofingen', + 'Ryuyo', + 'Tigard', + 'Belm', + 'Piastow', + 'Sebring', + 'Vastervik', + 'Hengshuicun', + 'Riverside', + 'Montecristi', + 'Aprilia', + 'Penistone', + 'Mogeiro', + 'Sao Joao de Ver', + 'Robles', + 'Saint-Germain-en-Laye', + 'Bethelsdorp', + 'Saka', + 'Butia', + 'Gudipallipadu', + 'Pulivendla', + 'Huntingdon', + 'Vila Teixeira da Silva', + 'Antsakanalabe', + 'Amneville', + 'Lummen', + 'Dbaiye', + 'Semmarikulan', + 'Risalpur Cantonment', + 'Acala del Rio', + 'Porur', + 'Amarchinta', + 'Olamze', + 'Kairouan', + 'Qiantangcun', + 'Montegrotto Terme', + 'Bensheim', + 'Lenvik', + 'Pariquera-Acu', + 'Sambre', + 'Tekkebhagam', + 'Blerick', + 'Parobe', + 'Clive', + 'Davos', + 'Devanakavundanur', + 'Tupran', + 'Rossano', + 'Raman', + 'Hosan', + 'Erding', + 'Ban Tha Kham', + 'Huercal-Overa', + 'Fairmount', + 'Kamabougou', + 'Alcaudete', + 'El Banco', + 'Saksohara', + 'Ferkessedougou', + 'Darsur', + 'Gagnef', + 'Mostaganem', + 'Opatija', + 'Cambira', + 'Moninnpebougou', + 'Pinia', + 'Sillod', + 'Santo Antonio do Sudoeste', + 'Baxt', + 'Yomitan', + 'Porto Firme', + 'Kalungu', + 'Tarime', + 'Dingxi', + 'Garuva', + 'Alton', + 'Poprad', + 'Comandante Fontana', + 'Luanzhou', + 'Cuitzeo del Porvenir', + "Sant'Agata de' Goti", + 'Tsinjoarivo', + 'Tamiahua', + 'Barnis', + 'Minami-Alps', + 'Jalam', + 'Arandu', + 'Spanish Fork', + 'Tiruvennanallur', + 'Mohammadia', + 'Bayt Sahur', + 'Wilhelmshaven', + 'Claudio', + 'Nelali', + 'San Andres Villa Seca', + 'North Dundas', + 'Kilminnal', + 'Alamogordo', + 'Antsakabary', + 'Ibicarai', + 'Eral', + 'Zdolbuniv', + 'Drochia', + 'Saikaicho-kobago', + 'Coroneo', + 'Gabasumdo', + 'River Forest', + 'Ecatepec', + 'Bekopaka', + 'Fort McMurray', + 'Ban Mae Tuen', + 'Dizicheh', + 'Biggin Hill', + 'Lower Bicutan', + 'Tunceli', + 'Kurim', + 'Curiti', + 'Seminole', + 'Tori-Bossito', + 'Lake Havasu City', + 'San Benito Abad', + "'Ain el Bell", + 'Bocsa', + 'Batuco', + 'Ughara', + 'Kakdwip', + 'Nallajerla', + 'Lumbang', + 'Sarbogard', + 'Bowral', + 'Kristinehamn', + 'Meiwa', + 'Tetela del Volcan', + 'Rupenaguntla', + 'Palera', + 'Attleboro', + 'Vitomarci', + 'Guraahai', + 'Henley on Thames', + 'Stanford le Hope', + 'Cazones de Herrera', + 'Middleborough', + 'Port Perry', + 'Saryaghash', + 'Tay', + 'Marlow', + "Granarolo del l'Emilia", + 'Whitby', + 'Pahou', + 'Santa Maria di Sala', + 'Rani Sawargaon', + 'Moore', + 'Tizimin', + 'Gabane', + 'Lichtenau', + 'Wetter (Ruhr)', + 'Quva', + 'Ipaucu', + 'Tahla', + 'Enschede', + 'Padinjaremuri', + 'Oued Essalem', + 'Sanatikri', + 'Razanj', + 'Ban Bang Lamung', + 'Camberley', + 'Avignon', + 'Sittingbourne', + 'Maduraivayal', + 'Onate', + 'Arboga', + 'Duluth', + 'Iluppur', + 'Tehachapi', + 'Tijucas', + 'Bahadarpur', + 'Bugugoucun', + 'Bayi', + 'Nakuru', + 'Fontenay-sous-Bois', + 'Tachikawa', + 'Amroha', + 'Boo', + 'Fochville', + 'Idak', + 'Campbellsville', + 'Limonade', + 'Lucea', + 'Tetouan', + 'Sesori', + 'Criciuma', + 'Bedford', + 'Osvaldo Cruz', + 'Karacoban', + 'Rafael Castillo', + 'Faranah', + 'Paina', + 'Santa Maria del Tule', + 'Puno', + 'Cove', + 'Sanankoroba', + 'Nowogard', + 'Pallipattu', + 'Bhalwal', + 'Torre Annunziata', + 'Gavinivaripalem', + 'Harike', + 'Kameyama', + 'Amala', + 'Struthers', + 'Ilindu Kothi', + 'Rio Grande', + 'Coral Gables', + 'San Francisco Libre', + 'Esteban Echeverria', + 'Than', + 'Bere', + 'Villa San Jose', + 'Gaurihar Khaliqnagar', + 'Yonabaru', + 'Kretinga', + 'Banolas', + 'Kalocsa', + 'Atlautla', + 'Al Muzayrib', + 'Tsitondroina', + 'Picture Rocks', + 'Ostbevern', + 'Purwa Utar', + 'Pontchateau', + 'Bandiagara', + 'Midar', + 'Abasingammedda', 'Chinnamandem', - 'Adohoun', - 'Blackhawk', - 'Dinagat', - 'Mount Airy', - 'Kralendijk', - 'Schleusingen', - 'Paimio', - 'Groot-Brakrivier', - 'Villa Jaragua', - 'Opatija', - 'Hanson', - 'North Dumfries', - 'Hetane', - 'Altamirano', - 'Diessen am Ammersee', - 'Longbenton', - 'Nakayama', - 'Kilibo', - 'Oloron-Sainte-Marie', - 'Usuppur', - 'Partap Tanr', - 'Kanur', - 'Mittahalli', - 'Urcos', - 'Bouhmama', - 'Avigliano', - 'Itzer', - 'Lyakhavichy', - 'Cadelbosco di Sopra', - 'Calcoene', - 'Standerton', - 'Jilava', - 'Ouedo-Agueko', - 'Antardipa', - 'Canapolis', - 'Ghattu', - 'Hollviken', - 'Felton', - 'Englefield Green', - 'Sabnima', - 'Munnuru', - 'Toundout', - 'San Ignacio Cohuirimpo', - 'Lunca Cetatuii', - 'Pires Ferreira', - 'Barharia', - 'Nanticoke', - 'Mantasoa', - 'Kucukkuyu', - 'Aranda', - 'Massa Lombarda', - 'Bajpe', - 'Abadou', - 'Tubara', - 'Ain Zora', - 'Khovaling', - 'Kucuk Dalyan', - 'Urucania', - 'Pont-Saint-Esprit', - 'Kingsteignton', - 'Killiney', - 'Khokri Kalan', - 'Tangerhutte', - 'Sokhodewara', - 'Douglass', - 'Acari', - 'West Perrine', - 'Ironton', - 'Inebolu', - 'Al Mahwit', - 'La Maddalena', - 'Golpazari', - 'Lake Barcroft', - 'Miro Khan', - 'Karpuzlu', - 'Lymanka', - 'Monte Dourado', - 'Ghoswari', - 'Dasai', - 'Kabira', - 'Kurhani', - 'Sumner', - 'Ninheira', - 'Ait Hani', - 'Hoogland', - 'Ranko', + 'Zhydachiv', + 'Fayzobod', + 'Bad Bevensen', + 'Nedumpura', + 'Azua', + 'Earley', + 'Sao Sebastiao do Maranhao', + 'Nossa Senhora do Livramento', + 'Desaguadero', + 'The Village', + 'Richfield', + 'Medway', + 'Panglao', + 'Erraguntla', + 'Tapilula', + 'South Park', + 'Shovot', + 'Samaca', + 'Fehrbellin', + 'Pouytenga', + 'Wenping', + 'Mendefera', + 'Matanao', + 'Bataguacu', + 'Kljuc', + 'Saint-Malo', + 'Hiriyur', + 'Copan', + 'Comodoro', + 'Ampasimpotsy-Gara', + 'Issum', + 'Thundersley', + 'Nandavaram', + 'Ivisan', + 'Uvinza', + 'Bituruna', + 'Salzhemmendorf', + 'Oguchi', + 'Maubin', + 'Pullman', + 'Lower Gwynedd', + 'Kidal', + 'Ghariyah al Gharbiyah', + 'Sagarpur', + 'Cottage Lake', + 'Macon', + 'Siayan', + 'Fatick', + 'Hinda', + 'Betio', + 'Ramos Arizpe', + 'Mbuyapey', + 'Tirana', + 'Uzyn', + 'Jolo', + 'Knoxville', + 'Durant', + 'Khmelnytskyi', + 'Mong Duong', + 'Mujui dos Campos', + 'Hendaye', + 'Despatch', + 'Borne', + 'Goirle', + 'Petnjica', + 'Barda', + 'Feliz', + 'Ut Bulag', + 'Fasano', + 'Gtarna', + 'Greensboro', + 'Boskovice', + 'Barrafranca', + 'Estero', + 'Osmangazi', + 'Demre', + 'Manjil', + 'Temascaltepec de Gonzalez', + 'Mendota Heights', + 'Nalgora', + 'Gwangju', + 'Qitai', + 'Zakhu', + 'Krishnarajpet', + 'Hayes', + 'Vitthalapuram', + 'Burla', + 'Salay', + 'Skuodas', + 'Nagano', + 'Dambal', + 'Sarauni Kalan', + 'Bocaiuva', + 'Chimbas', + 'South Pasadena', + 'Dar El Kebdani', + 'Matanzas', + 'Jarocin', + 'Sarioglan', + 'Ibate', + 'Kisenzi', + 'Shibirghan', + 'Viseu de Sus', + 'Majhariya Sheikh', + 'Qulicun', + 'Aswan', + 'Kowloon City', + 'Yverdon-les-Bains', + 'Sera', + 'Mililani Mauka', + 'Acworth', + 'Tibubeneng', + 'Saijo', + 'Wetzikon', + 'Americo Brasiliense', + 'Nova Cruz', + 'Pantao-Ragat', + 'Chichibu', + 'Kyankwanzi', + 'Jabalya', + 'Caparica', + 'Rewa', + 'Castiglione delle Stiviere', + 'Demir Kapija', + 'Ramat Gan', + 'Porto-Novo', + 'River Road', + 'Canarana', + 'Penagam', + 'Maldah', + 'Rapho', + 'Vilvoorde', + 'Gauting', + 'Aschaffenburg', + 'Samux', + 'Ekamba', + 'Kepsut', + 'Esfahan', + 'Andramy', + 'Sarezzo', + 'Miracatu', + 'Kramatorsk', + 'Daping', + 'Tunuyan', + 'Bonyhad', + 'Sao Joao da Barra', + 'Kidsgrove', + 'San Jeronimo', + 'Chinnachauku', + 'Abai', + 'Kaipram', + 'Paleng', + 'Devarshola', + 'Utraula', + 'Meadville', + 'Satupa`itea', + 'Pacatuba', + 'Saint-Georges', + 'Remigio', + 'Puerto Suarez', + 'Arden-Arcade', + 'Kankanalapalle', + 'Mankada', + 'Willow Grove', + 'Tamaki', + 'Pijnacker', + 'Naryai ka Puri', + 'Al Mazyunah', + 'Bharhopur', + 'Ekero', + 'Deh', + 'El Jem', + 'Curacavi', + 'Ladue', + 'Barki Ballia', + 'Yecapixtla', + 'Petaluma', + 'Bradley Gardens', + 'Caapora', + 'Dinklage', + 'Karad', + 'Niuchangqiao', + 'Mahalingpur', + 'Walcz', + 'Mannamturuttu', + 'Les Clayes-sous-Bois', + 'Garhara', + 'Mumaradikop', + 'Davutlar', + 'Haripur', + 'Sahsaul', + 'Pachora', + 'Testour', + 'Ratchaburi', + 'Marovoay', + 'Valente', + 'Pouso Alegre', + 'Chinnavadampatti', + 'Mariana', + 'Unjha', + 'Keighley', + 'Detva', + 'Allouez', + 'Bamako', + 'Adrasmon', + 'Ramannapeta', + 'Fort Lauderdale', + 'Webuye', + 'Peligros', + 'Leeton', + 'Bollene', + 'Lianjiang', + 'Antsirabe Afovoany', + 'Ada', + 'Tixkokob', + 'Kamagaya', + 'Cassa de la Selva', + 'Takeocho-takeo', + 'Butig', + 'Algiers', + 'Straelen', + 'Mechelen-aan-de-Maas', + 'Esmeralda', + 'Nuevo Casas Grandes', + 'Houilles', + 'Itano', + 'San Javier', + 'Emiliano Zapata', + 'Seattle', + 'Narino', + 'Tiruvannamalai', + 'Clausthal-Zellerfeld', + 'Asola', + 'Antonina', + 'Dun Dealgan', + 'Rifle', + 'Maharajgani', + 'Las Cruces', + 'Mossel Bay', + 'Tinglayan', + 'Arapgir', + 'Locogahoue', + 'White House', + 'Havana', + 'Zhetisay', + 'Navinipatti', + 'Duptiair', + 'Abcoude', + 'Capinopolis', + 'Arucas', + 'Nova Lima', + 'Cunhinga', + 'Haftkel', + 'Andacollo', + 'Kawachinagano', + 'Mountlake Terrace', + 'Kalynivka', + 'Perintalmanna', + 'Rio Real', + 'Cottingham', + 'Bas Goynuk', + 'Jianshe', + 'Wermelskirchen', + 'Hariharpara', + 'Jucuapa', + 'Choa Saidan Shah', + 'Agaram', + 'Carmen', + 'Anguo', + 'Challakere', + 'Rahimpur', + 'Pitanga', + 'Zumarraga', + 'Gohna', + 'Coyuca de Catalan', + 'Matinhos', + 'Torun', + 'Taluqan', + 'Aurad Shahjahani', + 'Persembe', + 'Bochil', + 'Nadvirna', + 'Niagadina', + 'Gubeng', + 'Sitalkuchi', + 'Dashtobod', + 'Lascano', + 'Bergisch Gladbach', + 'Dumalag', + 'Wahga', + 'Guarambare', + 'Raniyah', + 'Maddur', + 'Buba', + 'Mobarakeh', + 'Ouaklim Oukider', + 'Ito', + 'Lonar', + 'Okhargara', + 'Esil', + 'Devrek', + 'Pefka', + 'Chamonix-Mont-Blanc', + 'Bad Bergzabern', + 'Las Condes', + 'Ptolemaida', + 'Helena-West Helena', + 'Chimboy Shahri', + 'Franconia', + 'Szentes', + 'San Vito', + 'Panasapadu', + 'Ogden', + 'Harpalpur', + 'Road Town', + 'Montague', + 'Issoire', + 'Bagac', + 'Shuichecun', + 'Aylesbury', + 'Jijiga', + 'Dettingen an der Erms', + 'Thakraha', + 'Worth am Rhein', + 'Moissy-Cramayel', + 'Possneck', + 'Punjai Turaiyampalaiyam', + 'Ustka', + 'Velair', + 'As Sukhnah', + 'Carlisle', + 'Alausi', + 'Chantal', + 'Ouro Fino', + 'Korsun-Shevchenkivskyi', + 'North Andover', + 'Melekeok', + 'Mbake', + 'San Vito dei Normanni', + 'Cheranallur', + 'Whitewater', + 'Port Moresby', + 'Bryans Road', + 'Vegachi', + 'Yolombo', + 'Kewanee', + 'Mingjian', + 'Thonotosassa', + 'Isapur', + 'Kostrzyn nad Odra', + 'Friesoythe', + 'Lalam', + 'Maruturu', + 'Pudu', + 'Zahed Shahr', + 'Dungu', + 'Manica', + 'Draa el Mizan', + 'Tolmezzo', + 'Farsley', + 'Agame', + 'Pachauth', + 'Sittard', + 'Mableton', + 'Guaratingueta', + 'Lucenec', + 'Catchiungo', + 'Pitalito', + 'Bensville', + 'Shimohata', + 'Zawiat Moulay Brahim', + 'Anilao', + 'Eloi Mendes', + 'Erlanger', + 'Minamiaso', + 'Diffa', + 'Shark', + 'Osterburg', + 'Barwell', + 'Ambalanur', + 'Sigaboy', + 'Iretama', + 'Alucra', + 'Sivandipuram', + 'Opalenica', + 'Fray Bentos', + 'Kottur', + 'Yasugicho', + 'Anacortes', + 'Sangola', + 'Vanimel', + 'Guatape', + 'Zorbig', + 'Pitogo', 'Busayra', - 'Murtosa', - 'Tamanar', - 'Iaciara', - 'Linluo', - 'Bohl-Iggelheim', - 'Vellipalaiyam', - 'Maida Babhangawan', - 'Sonakhal', - 'San Gaspar Ixchil', - 'Had Laaounate', - 'Jablanica', - 'Sao Joao de Ver', - 'Chorrocho', - 'Jaguari', - 'Yacuanquer', - 'Tenango del Aire', - 'Grijo', - 'Kimpese', - 'Trofarello', - 'Tourza', - 'Pasil', - 'Abergele', - 'Sirur Tajband', - 'Lejanias', - 'Acate', - 'Wendell', - 'Amtar', - 'Rocafuerte', - 'Bodippatti', - 'Pariconia', - "'Ain Fekan", - 'Zapotitlan', - 'Yazoo City', - 'Kielczow', - 'Kolarovo', - 'Lagoa do Mato', - 'Jurbarkas', - 'Schonwalde-Siedlung', - 'Sawadah', - 'Shampur', - 'Tekkattur', - 'Aerzen', - 'Alachua', - 'Airway Heights', - 'Mulungu', - 'Porto Firme', - 'Lenzburg', - 'Longuenesse', - 'Gajiginhalu', - 'Daskasan', - 'Catanduvas', - 'Scottdale', - 'Tarazona de Aragon', - 'Kasavanampatti', - 'Lakeland Village', - 'Vouzela', - 'Monsenhor Gil', - 'Puligunta', - 'Yorkshire', - 'Corumba de Goias', - 'Flamanzi', - 'Ban Ko', - 'Sao Tiago', - 'Bangshang', - 'Neuenhaus', - 'Briancon', - 'Flers-lez-Lille', - 'Trabia', - 'Ambolotarakely', - 'Ascope', - 'Koppaka', - 'Acushnet', - 'Bad Iburg', - 'Las Matas de Santa Cruz', - 'Kien Giang', + 'Puerto Carreno', + 'Nandigama', + 'Ampasimanolotra', + "Ma'ai", + 'Mapiri', + 'Serra', + 'Santa Iria da Azoia', + 'Pyeongtaek', + 'Hartford', + 'Hokuei', + 'Caldicot', + 'Tucacas', + 'Santiago Texacuangos', + 'Turvo', + 'Torredonjimeno', + 'Fontanafredda', + 'Rhede', + 'Agri', + 'Mandawa', + 'Sibate', + 'Tutrakan', + 'Dinga', + 'San Andres Cholula', + 'Sarpsborg', + 'Palashi', + 'Attili', + 'Pilas', + 'Libonik', + 'Tulum', + 'Tomarza', + 'Pato Branco', + 'Currumbin', + 'Fourmies', + 'Caxias', + 'Okondja', + 'Cantu', + 'Jeremoabo', + 'Ciudad General Escobedo', + 'Amberomanga', + 'Magdiwang', + 'Baardheere', + 'Ubala', + 'Chakwai', + 'Uibai', + 'Achuapa', + 'Nastola', + 'Partapnagar', + 'Naujan', + 'Letchworth', + 'Calceta', + 'Jafarabad', + 'Mamnur', + 'Merthyr Tudful', + 'Sept-Iles', + 'Bekalta', + 'Cambrai', + 'Rokiskis', + 'Pamukova', + 'Bad Laasphe', + 'Harper', + 'Registro', + 'Fern Down', + 'Perkiomen', + 'Lushar', + 'Lautaro', + 'Bhainsahi', + 'Welling', + 'Imaricho-ko', + 'Caerphilly', + 'Cunda dia Baze', + 'Monte Quemado', + 'Khipro', + 'Reriutaba', + 'DeBary', + 'Talapalli', + 'Taverny', + 'Jarjanaz', + 'Targu-Mures', + 'Bhasawar', + 'Siverek', + 'Grenade', + 'Sinincay', + 'Soledade', + 'Chattogram', + 'Srikurmam', + 'Daitocho', + 'Rombas', + 'Surabaya', + 'Le Mans', + 'Varzea Alegre', + 'Jonuta', + 'Batavia', + 'Pulimakkal', + 'Giaveno', + 'Sarangpur', + 'Septemes-les-Vallons', + 'Dolynska', + 'Targovishte', + 'Aldridge', + 'Abilene', + 'Santa Maria Jacatepec', + 'Khash', + 'Reni', + 'Denville', + 'Caracal', + 'Puebla', + 'Paravakkottai', + 'Great Bookham', + 'Bodo', + 'Mountougoula', + 'Mogi Guacu', + 'Yanagawamachi-saiwaicho', + 'Datu Odin Sinsuat', + 'Morbach', + 'Chincholi', + 'Cangzhou', + 'Pichilemu', + 'Saravan', + 'Sainte-Adele', + 'Rapar', + 'Langford Station', + 'Porthcawl', + 'Hilvarenbeek', + 'Jalarpet', + 'Bellview', + 'Initao', + 'Antaretra', + 'Iriona', + 'Peonga', + 'Vadavalli', + 'Port Talbot', + "Arbi'a Tighadwiyn", + 'Ciudad Vieja', + 'Newtown', + 'Sarasota', + 'Rohtak', + "'s-Hertogenbosch", + 'Ras Baalbek', + 'Harinakunda', + 'Calahorra', + 'Beitbridge', + 'Las Tablas', + 'Zhongli', + 'Dauin', + 'Saraqib', + 'Karranah', + 'Solaro', + 'Dehra Dun', + 'Riolandia', + 'Wai', + 'Golubovci', + 'Lomza', + 'Nkurenkuru', + 'Oudenburg', + 'North Laurel', + 'Ammi Moussa', + 'Puruliya', + 'Ayungon', + 'Mailavaram', + 'Ban Dong Mada', + 'San Sebastian', + 'Le Petit-Couronne', + 'Bani Walid', + 'Molins de Rey', + 'Bekoratsaka', + 'Luperon', + 'Abakaliki', + 'Vila Nova de Cerveira', + 'Rocca Priora', + 'Raurkela', + 'Romny', + 'Santa Marcela', + 'Chinhoyi', + 'Tanki Leendert', + 'Dej', + 'Berber', + 'Perryton', + 'Haarlem', + 'Xique-Xique', + 'Mirdoddi', + 'El Rodeo', + 'Truskavets', + 'Zugdidi', + 'Dharhwa', + 'Esslingen', + 'Kakching Khunou', + 'Campos Sales', + 'Saundhonwali', + 'Hemei', + 'Pindorama', + 'Cospicua', + 'Sevur', + 'Fiume Veneto', + 'South Hill', + 'Charipara', + 'Borio', + 'Mount Barker', + 'Soliera', + 'San Clemente', + 'Polonne', + 'Barreiras', + 'Cabrero', + 'Sainte-Therese', + 'Merredin', + 'Doume', + 'Guaynabo', + 'Mohyliv-Podilskyi', + 'Santiago de Chuco', + 'Auriflama', + 'Sao Jeronimo da Serra', + 'Rowland Heights', + 'Telkathu', + 'Zhentang', + 'Ifrane', + 'Chailaha', + 'Acoyapa', + 'Grunberg', + 'Illescas', + 'Jacare', + 'Grabels', + 'Anshan', + 'Caloundra', + 'Ruyigi', + 'Kalleribhagam', + 'Rochester', + 'Ban Rawai', + 'Dera', + 'Takanezawa', + 'Palmer Ranch', + 'Rampatti', + 'Heyunkeng', + 'Sittwe', + 'Hiep Hoa', + 'Gorlitz', + 'Yanggezhuang', + 'Ogawa', + 'Zafarwal', + 'Cachoeirinha', + 'Ra`ananna', + 'Raymore', + 'Deneysville', + 'Nurpur', + 'Nosibe', + 'Minamishiro', + 'Northbrook', + 'Colonia General Felipe Angeles', + 'Acacias', + 'G`uzor', + 'Oberwil', + 'Yanjiang', + 'Iflissen', + 'Vsetin', + 'Nimes', + 'Sangrampur', + 'Germering', + 'Coulsdon', + 'Lebon Regis', + 'Malaimachchampatti', + 'Rarz', + 'Clacton-on-Sea', + 'Droylsden', + 'Maroli', + 'Xintian', + 'Wangi', + 'Blaine', + 'Aliganj', + 'Michendorf', + 'Kalaikunda', + 'Betigeri', + 'Talipao', + 'Bheja', + 'Red Wing', + 'Merrillville', + 'Minamisatsuma', + 'Ramsbottom', + 'Catarina', + 'Korb', + 'Lingyuan', + 'Rendon', + 'Ambongo', + 'Aliyabad', 'Millington', - 'Kanagicho', - 'Puente de Piedra', - 'Pachauth', - 'Pella', + 'Brdovec', + 'Gujar Khan', + 'Heeze', + 'Binondo', + 'Aix-les-Bains', + 'Civril', + 'Aranyaprathet', + 'Bargteheide', + 'Ambodiangezoka', + 'Talsint', + 'Silvania', + 'Jindayris', + 'Pacuarito', + 'Nuku`alofa', + 'Imi Mokorn', + 'Panjipara', + 'Portales', + 'Ksebia', + 'Sodo', + 'Hoppegarten', + 'Amparo', + 'Pirayu', + 'Narat', + 'Bagaura', + 'Puerto Gaitan', + 'Hoyerswerda', + 'Beckley', + 'Tsarazaza', + 'Mari`', + 'Panitan', + 'Phoenixville', + 'Kinkala', + 'Pilachikare', + 'Chellaston', + 'Ranchuelo', + 'Schuylkill', + 'Can-Avid', + 'Northam', + 'Dedham', + 'Bad Camberg', + 'Oyten', + 'Guaymas', + 'Gaeta', + 'Ankadinandriana', + 'Holalagondi', + 'North Guwahati', + 'Saint-Gaudens', + 'Rancho San Diego', + 'Vicar', + 'San Pedro Pochutla', + 'Uhingen', + 'Policoro', + 'Nabilatuk', + 'Bauyrzhan Momyshuly', + 'Mulakad', + 'Kesan', + 'Asosa', + 'Dewangarh', + 'Ash Shaykh Zuwayd', + 'Nunihat', + 'Itki Thakurgaon', + 'Korsor', + 'Cenovi', + 'Aroali', + 'Schweinfurt', + 'Hirpardangal', + 'Nadisal', + 'El Amim', + 'Zeewolde', + 'Plaisance', + 'Mokronog', + 'Xiaojiangcun', + 'Muhradah', + 'Santa Rosa de Lima', + 'Halvad', + 'Welkenraedt', + 'Kronberg', + 'Lagoa Santa', + 'Liutuancun', + 'Iguig', + 'Blue Island', + 'Codru', + 'Caramoran', + 'Stuart', + 'Marino', + 'Tacheng', + 'Bandar-e Gaz', + 'San Leandro', + 'Athi River', + 'Leirvik', + 'Wattrelos', + "As Suwayda'", + 'Singampunari', + 'Velampalaiyam', + 'Semarang', + 'Garland', + 'Coronel Oviedo', + 'Waldkirch', + 'Gusau', 'Campton Hills', - 'Sawla', - 'Chitaga', - 'Pelissanne', - 'Loharda', - 'Darauli', - 'Kuiyibagecun', - 'Fenglin', - 'Tinqueux', - 'Nave', - 'Don Galo', - 'Weinbohla', - 'Le Mars', - 'Martensville', - '`Utaybah', - 'Sihma', - 'Monument', - 'Mancora', - 'Paddhari', - 'Usmate Velate', - 'Niel', - 'Sao Jose do Calcado', - 'Budelsdorf', - 'Mathila', - 'Excelsior Springs', - 'Mokrisset', - 'Sabaneta de Yasica', + 'Kalangala', + 'Palafrugell', + 'Esfarayen', + 'Qazaly', + 'Chelsea', + 'Gokce', + 'Harrisonville', + 'Weare', + 'Shiji', + 'Bakharia', + 'Soanindrariny', + 'Dhanbad', + 'Jayaque', + 'Tanque Verde', + 'Northenden', + 'Matias Cardoso', + 'St. Charles', + 'Gaomi', + 'Moreira Sales', + 'Bharatpur', + 'Chauki', + 'Gokcebey', + 'Kishtwar', + 'Hambantota', + 'Ez Zahra', + 'Ain Beida', + 'Bauru', + 'Chickasha', + 'Simpsonville', + 'Taman Johor Jaya', + 'Skelleftea', + 'Bellaa', + 'Narlidere', + 'Lanciano', + 'Bellmawr', + 'Tataltepec de Valdes', + 'Molo', + 'Kiskunfelegyhaza', + 'Kaisiadorys', + 'San Dionisio', + 'Corpus Christi', + 'Tutin', + 'Betanty', + 'Ambatomanjaka', + 'Koprukoy', + 'Matuga', + 'South Normanton', + 'Kalamata', + 'Trieste', + 'Balikesir', + 'Magsaysay', + 'Fuji', + 'Dorado', + 'Teyateyaneng', + 'Foiano della Chiana', + 'Borba', + 'Gaborone', + 'Puerto Armuelles', + 'Edgware', + 'Ahirauliya', + 'Felpham', + 'Amboaboa', + 'Paso del Macho', + 'Raymond Terrace', + 'Kambam', + 'Los Arabos', + 'Johnston', + 'Placentia', + 'Kharkiv', + 'Sault Ste. Marie', + 'East Glenville', + 'Tamza', + 'Akalgarh', + 'Nwoya', + 'Ordubad', + 'Bulan', + 'Musashimurayama', + 'Lipa City', + 'Tirupporur', + 'Kannudaiyampatti', + 'Sendafa', + 'Angelholm', + 'Carneiros', + 'Vellikulangara', + 'Andanappettai', + 'Mira', + 'Wangqing', + 'Asahikawa', + 'Stryi', + 'Kittery', + 'Rosso', + 'Ramsgate', + 'Diabigue', + 'Anjarkandi', + 'Santiago Tulantepec', + 'Kaul', + 'Pruszkow', + 'Karlskrona', + 'Porto-Vecchio', + 'Pasadena Hills', + 'Ban Bung Kha', + 'Wilmslow', + 'San Juan de Limay', + 'Puran Bigha', + 'Paramagudi', + 'Xima', + 'Khashuri', + 'San Lorenzo della Costa', + 'Medikunda', + 'Belpara', + 'Mountain Home', + 'Burnaby', + 'Sapouy', + 'Rhar el Melah', + 'Pessac', + 'Grevenmacher', + 'Santo Antonio do Monte', + 'Gros Islet', 'Tarabha', - 'Tilougguit', - 'Phaphot', - 'Kulrian', - 'Bir Ben Laabed', - 'Urrugne', - 'Chervyen', - 'Wendeburg', - 'Sambalhera', - 'Bischofshofen', - 'Ormesson-sur-Marne', - 'Werlte', - 'Lasht-e Nesha', - 'Marotaolana', - 'Grevesmuhlen', - 'Torpa', - 'Madathapatti', - 'Montalegre', - 'Saint-Gely-du-Fesc', - 'Aravelli', - 'Chota Mollakhali', - 'Jhonkar', - 'Antenetibe', - 'Apt', - 'Pallattur', - 'San Juanito', - 'Torotoro', - 'Maevka', - 'Nagambhotlapalem', - 'The Pinery', - 'Mfou', - 'Kakhandiki', - 'River Grove', - 'Mouans-Sartoux', - 'Tamarankottai', - 'North Bellport', - 'Rabta', - 'Sidi Bousber', - 'Garag', - 'Pazaryeri', - 'Reiskirchen', - 'Cotacachi', - 'Alcora', - 'Tarnok', - 'Skillounta', - 'Alderwood Manor', - 'Dhilwan', - 'Tulshia', - 'Karukkalvadi', - 'Saks', - 'Wanderlandia', - 'La Virgen', - 'Benedito Novo', - 'Recreio', - 'Flawil', - 'Felida', - 'Rasebetsane', - 'Parczew', - 'Sahuria', - 'Nahargarh', - 'Buttar Khurd', - 'Montale', - 'Xambioa', - 'Paittur', - 'Simpelveld', - 'Golyaka', - 'Floha', - 'Sainte-Savine', - 'Pierre-Benite', - 'Heris', - 'Naganuma', - 'Loudoun Valley Estates', - 'Forest Acres', - 'Shumanay', - 'Perur', - 'Vargem', - 'Boudouaou el Bahri', - 'Stansbury Park', - 'Plankstadt', - 'Hilter', - 'Neuhausen am Rheinfall', - 'Obuse', - 'Winterville', - 'Burgau', - 'Bagrinagar', - 'Nallippalaiyam', - 'Surinam', - 'Santiago Chimaltenango', - 'Murata', - 'Morsand', - 'Soquel', - 'Imst', - 'Andonabe Atsimo', - 'Heule', - 'Ertvelde', - 'Cristino Castro', + 'Wimauma', + 'Kumage', + 'Sivamalai', + 'Salmas', + 'Bad Salzdetfurth', + 'Taohuajiang', + 'Tsirang', + 'Dera Ismail Khan', + 'Westbrook', + "'Ayn Bni Mathar", + 'Veppattur', + 'Nettappakkam', + 'Saint-Herblain', + 'Cassano delle Murge', + 'San Jose Acatempa', + 'Sripur', + 'Rae Bareli', + 'Dazaifu', + 'Benguema', + 'Dobni Para', + 'Hajipur', + 'Villars-sur-Glane', + 'Tejen', + 'Itabaiana', + 'Exu', + 'Ninove', + 'Riposto', + 'Baraki Barak', + 'Surat Thani', + 'Setlagode', + 'Rajhanpur', + 'Wancheng', + 'Bom Conselho', + 'Karkkila', + 'Arden Hills', + 'Jasim', + 'Tangainony', + 'Ganguru', + 'Tamiami', + 'Anjiajia', + 'Angren', + 'Balimbing', + 'Vallejo', + 'Sabae', + 'Podgorze', + 'Rio Pardo', + 'Sarzeau', + 'Koniz', + 'El Segundo', + 'Werther', + 'Phalia', + 'Sidi Abd el Moumene', + 'Rajanagaram', + 'Riachao das Neves', + 'Betrandraka', + 'Graben-Neudorf', + "Ighrem n'Ougdal", + 'Kourimat', + 'Reno', + 'Verwood', + 'Naspur', + 'Douar El Mellaliyine', + 'Pichanal', + 'Octeville', + 'Hamadan', + 'Rackeve', + 'Khesht', + 'Anew', + 'South Fulton', + 'Cabo Verde', + 'Cooma', + 'Unnao', + 'Kandanati', + 'Sainkhera', + 'Hasbrouck Heights', + 'Antananarivo', + 'Puca Urco', + 'Hebron', + 'Qal`ah-ye Now', + 'Bara Malehra', + 'Vinales', + 'Kotturu', + 'Ainaro', + 'Kawambwa', + 'Santiago Ixcuintla', + 'Donzdorf', + 'Thong Pha Phum', + 'West Carrollton', + 'Imbau', + 'Shatrana', + 'Nalerigu', + 'Namli', + 'Cumbernauld', + 'Al Musayfirah', + 'Lulea', + 'Jamaica', + 'Vijayapati', + 'Monte Porzio Catone', + 'Carshalton', + 'Gumia', + 'Arvand Kenar', + 'Karaund', + 'Minamiaizu', + 'Gronau', + 'Jinxing', + 'Sixaola', + 'Oulad Hammou', + 'Trongsa', + 'Khenichet-sur Ouerrha', + 'Naifaru', + "K'ebri Dehar", + 'Namagiripettai', + 'East London', + 'Neibu', + 'Himi', + 'Cameron Highlands', + 'Amfilochia', + 'Saranambana', + 'Qingshan', + 'Ishikawa', + 'Monkseaton', + "Al Jahra'", + 'Simmerath', + "At Ta'if", + 'Bama', + 'Meknes', + 'Tiahounkossi', + 'Tucuma', + 'Lower Salford', + 'Punto Fijo', + 'East Greenbush', + 'Ambodimanary', + 'Nilambur', + 'Jalalabad', + 'Qingnian', + 'Barberton', + 'Atari', + 'Jilikul', + 'Cranbrook', + 'Lobogo', + 'Xiegang', + 'La Habra', + 'Alingsas', + 'Onverwacht', + 'Pimpri-Chinchwad', + 'Yatangcun', + 'Coueron', + 'Yaren', + 'Kazincbarcika', + 'Tanta', + 'Rasaunk', + 'Campoalegre', + 'Jurua', + 'Kallur', + 'Cekerek', + 'Tarwara', + 'Burketown', + 'South St. Paul', + 'Corgao', + 'An Thanh B', + 'Borgholzhausen', + 'Tahlequah', + 'Vierzon', + 'Qagan Us', + 'Baravat', + 'Vrsac', + "Za'roura", + 'Bennington', + 'Talamba', + 'Nandyal', + 'Laiwu', + 'Tacuarembo', + 'Cuncolim', + 'Xiaping', + 'Landazuri', + 'Cuautla', + 'Pires Ferreira', + 'Banaz', + 'Cote-Saint-Luc', + 'Manacor', + 'Tantangan', + 'Emmaus', + 'Sonora', + 'Pontiac', + 'Chinandega', + 'Armutlu', + 'Besni', + 'Qingquan', + 'Ceyu', + 'Majuro', + 'Herxheim', + 'Bluefield', + 'Oerlinghausen', + 'Aigues-Mortes', + 'Tosya', + "L'Ile-Saint-Denis", + 'Ban Ngio Ngam', + 'Fortim', + 'Rio Gallegos', + 'Schleiz', + 'Zoudjame', + 'Ondangwa', + 'Ampasimanjeva', + 'Altamont', + 'Wittelsheim', + 'Jayapura', + 'Arni ka Khera', + 'Commack', + 'Morombe', + 'Akdagmadeni', + 'Reidsville', + 'Chinnakkampalaiyam', + 'Girau do Ponciano', + 'Ardrossan', + 'Cherutana Tekku', + 'Kondur', + 'Gwelej', + 'Traiguen', + 'Sannois', + 'Zarach', + 'Lhuentse', + 'Redondo Beach', + 'Maynard', + 'Carmopolis de Minas', + 'Chino Hills', + 'Sohta', + 'Velddrif', + 'Tarifa', + 'Wheatfield', + 'Lasko', + 'Ho Chi Minh City', + 'Osakarovka', + 'Sirajganj', + 'Waidhofen an der Ybbs', + 'Lieusaint', + 'Worsborough', + 'Mandoto', + 'Kochkor', + 'Hindang', + 'Wolmirstedt', + 'Angri', + 'Bagnolet', + 'Hatogaya-honcho', + 'Panelas', + 'Campestre', + 'Boras', + 'Danderesso', + 'Vila Verde', + 'Amborondra', + 'Itapemirim', + 'Muthutala', + 'Qeshm', + 'Halawa', + 'Dosso', + 'Villazon', + 'Breukelen', + 'Pandi', + 'Audenge', + 'Ngou', + 'Urucara', + 'Baham', + 'Mudukulattur', + 'Tubarao', + "Dek'emhare", + 'Sidi Yakoub', + 'Bandhi', + 'Karsiyaka', + 'Shibin al Qanatir', + 'Ajas', + 'Dunedin', + 'Asturias', + 'California', + 'Catania', + 'Vinh', + 'Celano', 'Tierra Colorada', - 'Celic', - 'Agramonte', - 'Riesi', - 'San Ricardo', - 'Ban Thung Khao Phuang', - 'Usmat Shaharchasi', - 'Nuriston', - 'Bibala', - 'Court-Saint-Etienne', - 'Pocao', - 'Angostura', - 'Vembur', - 'Balwa', - 'Samakhiali', - 'Yedappalli', - 'Kamifurano', - 'Presidente Vargas', - 'Markt Indersdorf', - 'Candelaria Loxicha', - 'Susuz', - 'Rio do Pires', - 'Sadon', - 'Lighthouse Point', - 'Buriti Alegre', - 'Bad Wildbad', - 'Kibichuo', - 'Marck', - 'Bhopalia', - 'Naini', - 'Adalpur', - 'Devanakonda', - 'Nowe Miasto Lubawskie', - 'Krishnamsettipalle', - 'Heath', - 'Santa Maria de Itabira', - 'Grinon', - 'Gudlavalleru', - 'Hoki', - 'Soledar', - 'Likiskiai', - 'Regidor', - 'Whitnash', - 'Souq Sebt Says', - 'Chencha', - 'Duraiswamipuram', - 'Ingeniero White', - 'Rajpur Kalan', - 'Gommern', - 'Bonham', - 'Ryhope', - 'Ouolodo', - 'Coacoatzintla', - 'Leidschendam', - 'Attleborough', - 'Somers Point', - 'Sidi Abdallah', - 'Alfredo Wagner', - 'Buraan', - 'Ban Lueak', - 'Lake Hopatcong', - 'Bellmead', - 'Folomana', - 'Las Veredas', - 'Saude', - 'La Escala', - 'Hericourt', - 'Ambhua', - 'Bolekhiv', - 'Cacimbinhas', - 'Arkalochori', - 'Burgstadt', - 'Tiruvalam', - 'Machulishchy', - 'Rokunohe', - 'Espanola', - 'Hulshout', - 'Taormina', - 'Palatka', - 'Nova Dubnica', - 'Corzuela', - 'Luanco', - 'Balua Rampur', - 'Tokigawa', - 'Ambahy', - 'Caslav', - 'Kremiss', - 'Bordj Okhriss', - 'Al Musayfirah', - 'Hartswater', - 'Belao', - 'Dighawani', - 'Santiago Tangamandapio', - 'Novodnistrovsk', - 'Itaipe', - 'Wepangandla', - 'Vaddepalli', - 'Dhanwar', - 'Gemona del Friuli', - 'Macajuba', - 'Vermilion', - 'Olbernhau', - 'Friedeburg', - 'Holbeach', - 'Waimea', - 'East Bradford', - 'Karahalli', - 'Vikrutamala', - 'Burhia Dhanghatta', - 'Lake Morton-Berrydale', - 'Teotlaltzingo', - 'Santa Margarita de Mombuy', - 'Gokce', - 'Lollar', - 'Villers-Cotterets', - 'Kopparam', - 'Pedras de Maria da Cruz', - 'Khurmi', - 'Phai Sali', - 'Valpoy', - 'Minanba', - 'Flat Rock', - 'Braine-le-Chateau', - 'Da', - 'Vieux-Conde', - 'Bakwa', - 'Lonkly', - 'Fervedouro', - 'El Chol', - 'Birzai', - 'Catunda', - 'Burton Latimer', - 'Saidapet', - 'Plaine Magnien', - 'Timra', - 'Muquem de Sao Francisco', - 'Wildberg', - 'Valley', - 'Santa Teresinha', - 'Sao Sebastiao da Grama', - 'Litomysl', - 'Ulft', - 'Thilogne', - 'Mochizuki', - 'Minobu', - 'Wapienica', - 'Ivankiv', - 'Nova Europa', - 'Koth', - 'Silverton', - 'Sidi Boushab', - 'Yelm', - 'Manakana', - 'Kamthi', - 'Balia', - 'Dnestrovsc', - 'Yesilkoy', - 'Karkamis', - 'Zawyat Ahancal', - 'Antsahadinta', - 'Choyr', - 'Difficult Run', - 'Le Locle', - 'Eccleston', - 'Melito di Porto Salvo', - 'Plattekill', - 'Venganellur', - 'Ibiassuce', - 'Kiso', - 'Lovejoy', - 'Kraluv Dvur', - 'Tarare', - 'Awfouss', - 'Estaimpuis', - 'Takon', - 'Suhr', - 'Labin', - 'Warr Acres', - 'Sotkamo', - 'Portes-les-Valence', - 'South Lebanon', - 'Darling', - 'Rifle', - 'Firminopolis', - 'Nideggen', - 'Valatt', - 'Nagtala', - 'Roca Sales', - 'Coriano', - 'Libanggaon', - 'Nahulingo', - 'Jurbise', - 'Wabash', - 'Simbach am Inn', - 'Smithville', - 'Rawdon', - 'Bogue', - 'Ciechocinek', - 'Altenberge', - 'Chandera', - 'Kragero', - 'Trat', - 'Dona Ines', - 'Shenjiaba', - 'Phangnga', - 'Kalanak', - 'Oulad Slim', - 'Targu Ocna', - 'Prestonpans', + 'Dosquebradas', + 'Dunblane', + 'Brejao', + 'Toguere-Koumbe', + 'Lianshan', + 'Roghun', + 'Gokdepe', + 'Aul', + 'Gotvand', + 'Harnes', + 'Choloma', + 'Mamanguape', + 'Miguelturra', + 'Karlovo', + 'Goole', + 'Emir Abdelkader', + 'Sironko', + 'Bokaro Steel City', + 'Altos del Rosario', + 'Saint-Jean-de-Vedas', + 'Hyosha', + 'Tamiang Layang', 'Scartho', - 'Machalpur', - 'Cunha Alta', - 'Corral de Bustos', - 'Telsang', - 'Baghin', - 'Urai', - 'Oued Amlil', - 'Villeneuve-les-Maguelone', - 'Thorigny-sur-Marne', - 'Bradford-on-Avon', - 'Prakhon Chai', - 'Kotharpettai', - 'Kiho', - 'Opglabbeek', - 'Podstrana', - 'Marlton', - 'Koffiefontein', - 'Nordkirchen', - 'Koduru', - 'Ban Ueam', - 'Plombieres', - 'Braunsbedra', - 'Cislago', - 'Fayzobod', - 'Masindi Port', - 'Terra Alta', - 'Banta', - 'Cadillac', - 'Brikcha', - 'Croissy-sur-Seine', - 'Mount Vista', - 'Hithadhoo', - 'Hachirud', - 'Montecchio Emilia', - 'Fairmount', - 'Santiago Suchilquitongo', - 'Kamianka-Buzka', - 'Sainkhera', - "Fanja'", - 'Great Dunmow', - 'Charlton Kings', - 'Sleepy Hollow', - 'Cuatro Cienegas de Carranza', - 'Lemmer', - 'Demmin', - 'Velappadi', - 'Eriyodu', - 'Gateway', - 'Turmanin', - 'Kangaroo Flat', - 'Uchoa', - 'Narkatpalli', - 'Farmersville', - 'Suchanino', - 'Puerto Quijarro', - 'Tripurantakam', - 'Leones', - 'Santa Clara La Laguna', - 'Nossen', - 'Jigani', - 'Coronel Freitas', - 'Kaufering', - 'Gelves', - 'Matsavaram', - 'Dougba', - 'Ickenham', - 'Alacati', - 'Gokinepalle', - 'Molango', - 'Constantina', - 'Morinville', - 'Senhora dos Remedios', - 'Caem', - 'Paramoti', - 'Telkapalli', - 'Nakasato', - 'Spout Springs', - 'Gayaspur', - 'Kennett', - 'Cholchol', - 'Faradabad', - 'Jalihalli', - 'Truseni', - 'Zdzieszowice', - 'Capitolio', - 'Akim Swedru', - 'Paraippatti', - 'Comstock Park', - 'Spa', - 'Belem de Maria', - 'Altusried', - 'Galion', - 'Fasintsara', - 'Steinfeld', - 'Desuri', - 'Nukan', - 'Ban Non Sombun', - 'Nidamanuru', - 'Merces', - 'Nalgora', - 'Ordubad', - 'Neuenstadt am Kocher', - 'Madhopur Hazari', - 'Winchendon', - 'Douar Echbanat', - 'Conceicao da Aparecida', + 'Oltu', + 'Sillanwali', + 'Tadangam', + 'Loures', + 'Kalecik', + 'Sao Jose do Egito', + 'Morelia', + 'Mizan Teferi', + 'Dar Bel Hamri', + 'Ingeniero Guillermo N. Juarez', + 'Vendrell', + 'Wembley', + 'Fritissa', + 'Narasingapuram', + 'Hatvan', + 'Gharyala', + 'Cachoeira Paulista', + 'Pata Putrela', + 'Batang', + 'Burnham-on-Sea', + 'Stuarts Draft', + 'Balzan', + 'Pollachi', + 'Rajpura', + 'Drachten', + 'Agadallanka', + 'Habikino', + 'Mabole', + 'Katipunan', + 'Pachhapur', + 'Banaso', + 'Grinnell', + 'Euskirchen', + 'Ahar', + 'Iranshahr', + 'Mostardas', + 'Shimotsucho-kominami', + 'Maharagama', + 'Owego', + 'Madan', + 'Tomaszow Lubelski', + 'Oisterwijk', + 'Sao Francisco', + 'San Martin Jilotepeque', + 'Iperu', + 'Balaoan', + 'Dubno', + 'Tall `Afar', + 'Kaufungen', + 'Sohwal', + 'Guamuchil', + 'Fosses', + 'Casillas', + 'Ban Noen Phoem', + 'Cuellar', + 'Aurelino Leal', + 'Zeulenroda', + 'Porto Tolle', + 'Lower Hutt', + 'Castelnau-le-Lez', + 'Matabhanga', + 'Ban Ko', + 'Balsa Nova', + 'Brentwood', + 'Brumath', + 'Luban', + 'Mainaguri', + 'Buwenge', + 'Qabqa', + 'Al `Aziziyah', + 'Frutillar Alto', + 'Vatluru', + 'Casale', + 'Ambararata', + 'Studenicani', + 'Lanskroun', + 'Sveti Ivan Zelina', + 'Tokamachi', + 'Bishopstoke', + 'Broxburn', + 'Timizart', + 'Maroharatra', + 'Isselburg', + 'Vandiyur', + 'Los Llanos de Aridane', + 'Winder', + 'Banga', + 'Trophy Club', + 'Olmsted Falls', + 'Zanesville', + 'Zhudong', + 'Bapatla', + 'Peringanad', + 'Cedar Falls', + 'Leanja', + 'Eydhafushi', + 'Paoua', + 'Andribavontsona', + 'Pergamino', + 'Kouri', + 'Bellmore', + 'Bondeno', + 'Comines', + 'Volendam', + 'Pio IX', + 'Cotija de la Paz', + 'Koratla', + 'Tallbisah', + 'Hakubacho', + 'Helsingborg', + 'Braila', + 'Samalpur', + 'Afourar', + 'Briceno', + 'Kabanga', + 'Ambohimahamasina', + 'Quirima', + 'Hakone', + 'Nova Londrina', + 'Nuneaton', + 'Plaisir', + 'Kirikhan', + 'Eccles', + 'West Little River', + 'Nideggen', + 'Gyor', + 'Parchim', + 'Hagere Hiywet', + 'Mirinzal', + 'Lupi Viejo', + 'Buckeye', + 'Ravutulapudi', + 'Landupdih', + 'Santa Barbara de Pinto', + 'Haysville', + 'Dimbokro', + 'Toulouse', + 'Mangdongshan', + 'Vladicin Han', + 'Soma', + 'Springfield', + 'Wedel', + 'Dokuchaievsk', + 'Thai Binh', + 'Mbulu', + 'Muconda', + 'Pearl', + 'Pleszew', + 'Qualicum Beach', + 'Harihans', + 'Yangtangxu', + 'Boa Esperanca do Sul', + 'Saravia', + 'Wepangandla', + 'Morristown', + 'Karaikandi', + 'Elverum', + 'Mexicaltzingo', + 'Kamdoli', + 'Tayabas', + 'Hillsborough', + 'Joao Monlevade', + 'Syracuse', + 'Elliot Lake', + 'Ciudad Guadalupe Victoria', + 'Shampur', + 'Beverstedt', + 'Miajadas', + 'Erode', + 'Sao Pedro do Ivai', + 'Volkermarkt', + 'Lagoa de Itaenga', + 'Kokstad', + 'Jinshui', + 'Miesbach', + 'Lakeland South', + 'Dong Hoi', + 'Illingen', + 'San Dona di Piave', + 'Liantang', + 'Jujutla', + 'Ad Darb', + 'Osicala', + 'Huehuetla', + 'Yambol', + 'Muthallath al Azraq', + 'Asago', + 'Periya Soragai', + 'Anar', + 'Velika Plana', + 'Becej', + 'Hengnan', + 'Brad', + 'Tudiyalur', + 'Skhour Rehamna', + 'Seonar', + 'Muktagacha', + 'Saffron Walden', + 'Cilacap', + 'Ankiliabo', + 'Ramon Magsaysay', + 'Sarenja', + 'Yamanobe', + 'Marcinelle', + 'Abergele', + 'Saraunja', + 'Arankhola', + 'Calexico', + 'Dalaguete', + 'Owatonna', + 'Jalpa de Mendez', + 'Villalbilla', + 'Frameries', + 'Lakewood Park', + 'Erlun', + 'Thandwe', + 'Mons-en-Baroeul', + 'Netishyn', + 'Mindelo', + 'Repelon', + 'Sidon', + 'Ouinhri', + 'Miramar Beach', + 'Cam Ranh', + 'Certaldo', + 'Vedurupavaluru', + 'Alginet', + 'Egil', + 'Ruteng', + 'Chesapeake Ranch Estates', + 'Sao Jose do Jacuipe', + 'Perafita', + 'Barnsley', + 'Hammond', + 'Simav', + 'South Euclid', + 'Tiquipaya', + 'Moorpark', + 'Chernivtsi', + 'Joigny', + 'Cary', + 'Pennadam', + 'Yongping', + 'Sagnay', + 'Lalibela', + 'Tazoult-Lambese', + 'Orta Nova', + 'Dumangas', + 'Trujillo', + 'Borovnica', + 'Buttayagudem', + 'Kegalle', + 'Oshikango', + 'San Juan de Arama', + 'Hathiaundha', + 'Eirunepe', + 'Pakka Kalan', + 'Kita', + 'Msoga', + 'Solothurn', + 'Welkom', + 'La Quinta', + 'Stamford', + 'Serpa', + 'Cadelbosco di Sopra', + "'Ain Tolba", + 'Chaiwu', + 'Kundiawa', + 'Clorinda', + 'Liushuquan', + 'Pingquan', + 'Ouesso', + 'Jiaganj', + 'Ibiraci', + 'Varaklani', + 'Whakatane', + 'Brzesko', + 'Fort Oglethorpe', + 'Pervomaisk', + 'Guiuan', + 'Hadiaya', + 'El Zulia', + 'Mahates', + 'Rio Segundo', + 'Patos', + 'Summerland', + 'Zalantun', + 'Khundawandpur', + 'Soledad de Graciano Sanchez', + 'Xocavand', + 'Denizli', + 'Mangai', + 'Chedaopo', + 'Rathfarnham', + 'Sibanicu', + 'Oxnard', + 'Surubim', + 'Bergama', + 'Keta', + 'Ochiai', + 'Yellanda', + 'Wilsonville', + 'Iguidiy', + 'Cordoba', + 'Tsarahonenana', + 'Flint', + 'Valentim Gentil', + 'Gumushane', + 'Cherbourg', + 'Hosir', + 'Makariv', + 'Pikine', + 'Acayucan', + 'Trebisov', + 'Bagong Pag-Asa', + 'Barr Elias', + 'Santa Coloma de Farnes', + 'Simao', + 'Ballarat', + 'Andoharanomaitso', + 'Bethlehem', + 'Mevani', + 'Sao Miguel dos Campos', + 'Heinsberg', + 'Al Kufah', + 'Pont Sonde', + 'Turkmenbasy', + 'Goldasht', + 'Hamar', + 'Pastores', + 'Veruela', + "Nong'an", + 'Senica', 'Steinau an der Strasse', - 'Sidi Brahim', - 'Phek', - 'Millstone', - 'Czarnkow', - 'Mankur', - 'Sarapui', - 'Villeneuve-Tolosane', - 'Gharyala', - 'Sarnen', - 'Haikoucun', - 'Atripalda', - 'Klipphausen', - 'Kottapuram', - 'Cori', - 'Calimesa', - 'Tnine Sidi Lyamani', - 'Libante', - 'Augustdorf', - 'Kalgi', - 'Bommarbettu', - 'Momanpet', - 'Corleone', - 'Ambalanur', - 'Peravali', - 'Itabirinha de Mantena', - 'Nieder-Olm', - 'Fakirtaki', - 'Shasta Lake', - 'Tavriisk', - 'Bassian', - 'Anrochte', - 'Phon Charoen', - 'Itri', - 'Dan', - 'Jaguaribara', - 'Phulmalik', - 'Bonate di Sopra', - 'Blandford Forum', - 'Khawaspur', - 'Kemin', - 'Arkadelphia', - 'Kelandis', - 'Scotchtown', - 'Aesch', - 'Siktiahi', - 'Krasnoilsk', - 'Rio do Fogo', - 'Kiklah', - 'Nijoni', - 'Sartana', - 'Gourock', - 'Hirehadagalli', - 'Rounia', - 'Harlau', - 'Ravanusa', - 'El Refugio', - 'Mallan', - 'Coroneo', - 'Vellaturu', - 'Woodlyn', - 'Delportshoop', - 'Maruteru', - 'Kiridh', - 'Srikrishnapur', - 'Villacarrillo', - 'Shahrak-e Enqelab', - 'Maria Pinto', - 'Brikama Ba', - 'Silea', - 'Canatlan', - 'Jeumont', - 'Mokarrampur', - 'Konkavaripalle', - 'Itape', - 'Cheruvannur', - 'Brewster', - 'Hoek van Holland', - 'Ganga Sagar', - 'Forde', - 'Natonin', - 'Steinen', - 'Chestnut Ridge', - 'Aulendorf', - 'Cabestany', - 'Sonwan', - 'Atessa', - 'Sao Luis do Paraitinga', - 'Tirkha', - 'White Marsh', - 'Garrucha', - 'Caspe', - 'Letychiv', - 'Bowral', - 'Trumbull Center', - 'Sao Miguel das Matas', - 'Wittelsheim', - 'Levanger', - 'Dabuleni', - 'Thanh Phu', - 'Firou', - 'Aydarken', - 'Benalla', - 'Ahogbeya', - 'Ben Nasseur', - 'Teddington', - 'Oppatavadi', - 'Ban Dan Na Kham', - 'Melres', - 'Gagnef', - 'Santo Antonio do Jacinto', - 'Qari Kola-ye Arateh', - 'El Jicaral', - 'Alvorada do Sul', - 'Erlenbach am Main', - 'Oneida', - 'Sirakoro', - 'Ananas', - 'Pintadas', - 'Inhangapi', - 'La Riche', - 'Babhniyawan', - 'Watervliet', - 'Beni Oulid', - 'Meerhout', - 'Weilheim an der Teck', - 'Vila Franca do Campo', - 'Itaueira', - 'Wallaceburg', - 'Arvorezinha', - 'El Alamo', - 'Villebon-sur-Yvette', - 'Riano', - 'Arimalam', - 'Appenweier', - 'Stranraer', - 'Ranchos', - 'Hochst im Odenwald', - 'Harsola', - 'Dombachcheri', - 'Hariana', - 'Kamepalle', - 'Caracol', - 'Berwick', - 'Teocuitatlan de Corona', - 'Karuzi', - 'Penarroya-Pueblonuevo', - 'Yadavolu', - 'Azamnagar', - 'Chong-Aryk', - 'Geneseo', - 'Etropole', - 'Burtonsville', - 'Sao Romao', - 'Mildenhall', - 'West Vero Corridor', - 'Blackfalds', - 'Virginopolis', - 'Umbita', - "Aghbalou n'Kerdous", - 'Agua Blanca Iturbide', - 'Amurrio', - 'Bacliff', - 'Wood River', - 'General Salgado', - 'Pola de Lena', - 'Brookdale', - 'Solim', - 'Bounaamane', - 'Haspra', - 'Qiushanxiang', - 'Auhar Sheikh', - 'Motibennur', - 'Riolandia', - 'Rodelas', - 'Kursunlu', - 'Buriti do Tocantins', - 'Khiram', - 'South Huntington', - 'Waynesville', - 'Jaqma', - 'Grossburgwedel', - 'Moldava nad Bodvou', - 'Mwaya', - 'Maurilandia', - 'Jordania', - 'Qanliko`l', - 'Pyetrykaw', - 'Broadstone', - 'Lakkireddipalle', - 'Trajano de Morais', - 'Merzenich', - 'Limoux', - 'Knezha', - 'Baran', - 'Caparrapi', - 'Bel Imour', - 'Sabana Grande', - 'Raymondville', - 'Orkelljunga', - 'Kangning', - 'Birsfelden', - 'Rancho Arriba', - 'Kalamula', - 'Boldesti-Scaeni', - 'Alto Paraiso de Goias', - 'Rubim', - 'Nana', - 'Shahar Telpa', - 'Bad Lauterberg', - 'Locate di Triulzi', - 'Murrells Inlet', - 'Armanaz', - 'Bonfinopolis', - 'Bordj Zemoura', - "Lyuboml'", - 'Kirchlinteln', - 'Castelli Calepio', - 'Ouroeste', - 'Ratauli', - "Castelnovo ne' Monti", - 'Morsbach', - 'Balaungi', - 'Zawal', - 'Fort Madison', - 'Dalgan', - 'Vilkaviskis', - 'Jordbro', - 'Serido', - 'Lenoir City', - 'Ma`raba', - 'Ekinozu', - 'Billdal', - 'Lutry', - 'Miedzychod', - 'Srisailain', - 'Simarwara Durgapur', - 'Arraias', - 'Lishuping', - 'Terra de Areia', - "'Ain Tellout", - 'Spitalfields', - 'Rayen', - 'Hecelchakan', - 'Irineopolis', - 'Cheam', - 'Arlov', - 'Schalksmuhle', - 'Jankampet', - 'Tangermunde', - 'Kandrawan', - 'Bandrele', - 'Sidi Bou Ali', - 'San Jose de Feliciano', - 'Sao Geraldo', - "Sant'Agata de' Goti", - 'Sidi Embarek', - 'Ganvie', - 'Venecia', - 'Shirako', - 'Itapitanga', - 'Bagh-e Bahadoran', - 'Oppeano', - 'Ban Wisit', - 'Bogen', - 'San Maurizio Canavese', - 'Selkirk', - 'Saint-Felicien', - 'La Trinite', - 'Dora', - 'Potiragua', - 'Salvatierra de Mino', - 'Mehdauli', - 'Meghaul', - 'Marina del Rey', - 'Tello', - 'Tremonton', - 'Gafour', - 'Tekkekara', - 'Kilminnal', - 'Gaunivaripalle', - 'Tabubil', - 'Ullur', - 'Carroll', - 'Estreito de Camara de Lobos', - 'Bhikkiwind Uttar', - 'Mel Seval', - 'Pine Ridge', - 'Lenguazaque', - 'Somireddipalle', - 'Dar Si Aissa', - 'Reddipalle', - 'Tipp City', + 'Wibsey', + 'Long Khanh', + 'Lubny', + 'Aalsmeer', + 'Citong', + 'Charxin', + 'Soyapango', + 'Avanos', + 'Milas', + 'Padmanabhapuram', + 'Les Palmes', + 'Rangoon', + 'Guichen', + 'Vadakkum', + 'Holon', + 'Faraskur', + 'Cifteler', + 'Malente', + 'Salgado', + 'Udalguri', + 'Broadwater', + 'Olot', + 'Kirkintilloch', + 'Amares', + 'West Drayton', + 'Pliezhausen', + 'Manicore', + 'Kanniparamba', + 'Larisa', + 'Stans', + 'Entraigues-sur-la-Sorgue', + 'Bhelsi', + 'Nuwara Eliya', + 'Montignoso', + 'Yavoriv', + 'Thillangeri', + 'Gajendragarh', + 'Narva', + 'Chirak', + 'Forestville', + 'Waitangi', + 'Yicheng', + 'Machagai', + 'Rasivarai Tottam', + 'Poienile de sub Munte', + 'Dogubayazit', + 'Abhia', + 'Etampes', + 'Puerto San Martin', + 'Panama City Beach', + 'Mittahalli', + 'Rudravaram', + 'Nassau', + 'Bladel', + 'Bauan', + 'Bryne', + 'Mandi Bamora', + 'Schenefeld', + 'Gosaingaon', + 'Nallur', + 'Soanierana', + 'Akhnur', + 'Pedda Adsarlapalli', + 'Waalwijk', + 'Sekondi', + 'Kelo', + 'Squinzano', + 'Itikalapalle', + 'Tattamangalam', + 'Segue', 'Jaltocan', - 'Saudade', - 'Alcaudete', - 'Rockport', - 'Chivhu', - 'Goldenstedt', - 'Indalvai', - 'Tenente Ananias Gomes', - 'Axixa do Tocantins', - 'Nazaria', - 'Lahstedt', - 'North Lakes', - 'Oliveira de Frades', - 'Rio Acima', - 'Ericeira', - 'Tettuppatti', - 'Hopetown', - 'Westonaria', - 'Kut Chap', - 'Fronteiras', - 'Chavinda', - 'Gerzat', - 'Hameenkyro', - 'Gohuma Bairia', - 'Querfurt', - 'Blumberg', - 'Sint-Lievens-Houtem', - 'Maxaranguape', - 'Popovaca', - 'Kormend', - 'Shahmirpet', - 'Tarar', - 'Barai', - 'Siparia', - 'Enriquillo', - 'Elkhorn', - 'Bonito de Santa Fe', - 'Kirchzarten', - 'Bougaribaya', - 'Lonquimay', - 'Ostercappeln', - 'Fenggeling', - 'Goldbach', - 'North Bend', - 'Puerto Santander', - 'Sussen', - 'Alberobello', - 'Boaz', - 'East Whittier', - 'Murowana Goslina', - 'Jaqueira', - 'Nayanagar', - 'Rovinari', - 'Robstown', - 'Sgamna', - 'Badru Khan', - 'Induno Olona', - 'Galimuyod', - 'Santa Teresinha (2)', - 'Vairampatti', - 'San Marzano sul Sarno', - 'Catarina', - 'Palmacia', - 'Lugovoy', - 'Santa Isabel Ishuatan', - 'Angelim', - 'Vila Muriqui', - 'Maheshram', - 'San Diego Country Estates', - 'Jean-Mermoz', - 'Avranches', - 'Khair Khan', - 'Vellur', - 'Sucupira do Norte', + 'Coram', + 'Entre Rios', + 'Hafizabad', + 'Konarak', + 'Betsizaraina', + 'Ulanhot', + 'Augsburg', + 'Modica', + 'Nova Olinda', + 'Eastvale', + 'Lechang', + 'Wanaka', + 'Ormesby', + 'Malegaon', + 'Rincon de Romos', + 'Bihta', + 'Mukilteo', + 'Codajas', + 'Hindalgi', + 'Radviliskis', + 'Vasai-Virar', + 'Salor', + 'Eraura', + 'Labrea', + 'Nanuet', + 'Maryborough', + 'Bramhabarada', + 'Rubeho', + 'Scherpenzeel', + 'Osan', + 'Obando', + 'San Antonio', + 'Mamarappatti', + 'Padangpanjang', + 'Wau', + 'Thiene', + 'Avocado Heights', + 'Lake Forest Park', + 'Sallaumines', + 'Nova Venecia', + 'Varadero', + 'Amalner', + 'Debaltseve', + 'Levoca', + 'Beachwood', + "Motta Sant'Anastasia", + 'Kreuztal', + 'Kirundo', + 'Ingeniero White', + 'Tasucu', 'Spelle', - 'Brumath', - 'Ksar Lmajaz', - 'Pfastatt', - 'Kiramangalam', - 'Apparaopeta', - 'Konigsbach-Stein', - 'Borgampad', - 'New Hyde Park', - 'Marawi', - 'Puvalur', - 'East Setauket', - 'Olifantshoek', - 'Agudos do Sul', - 'Bernex', - 'Rotonda', - 'Glogow Malopolski', - 'Santa Maria Madalena', - 'Chantepie', - 'Partibanur', - 'Gislaved', - 'Igarape Grande', - 'Treillieres', - 'Raibhir', - 'Vigasio', - 'Concordia Sagittaria', - 'Akbez', - 'Samux', - 'Governador Archer', - 'Lemington', - 'Muttam', - 'Isola Vicentina', - 'Roberval', - 'Villanueva de Arosa', - 'Miribel', - 'Monte San Juan', - 'Potunuru', - 'Duque Bacelar', - 'Betzdorf', - 'Luathaha', - 'Ahiro', - 'Benyahia Abderrahmane', - 'Koila Dewa', - 'Sao Miguel de Touros', - 'Halfway', - 'Neo Karlovasi', - 'Tha Muang', + 'Radomsko', + 'Baleyara', + 'Wencheng', + 'Ambohijanahary', + 'Oullins', + 'Ain Oulmene', + 'Sakete', + 'Alattur', + 'Sobradinho', + 'Hoki', + 'Calgary', + 'Praia', + 'Atbasar', + 'Kisslegg', + 'Chapaev', + 'Chipindo', + 'Livramento de Nossa Senhora', + 'Odemira', + 'Molango', + 'Mortugaba', + 'Kuttanallur', + 'Dahegam', + 'Gardena', + 'Round Lake', + 'San Nicolas', + 'Kinhalu', + 'Osorio', + 'Alanganallur', + 'Santa Cruz del Norte', + 'La Grange', + 'Habra', + 'Ciamis', + 'Zhuji', + 'Maduru', + 'Manyas', + "'Ain el Arbaa", + 'Alampalaiyam', + 'Ribera', + 'Qorashina', + 'Penafiel', + 'Tiraspol', + 'Pitou', + 'Pallikondai', + 'Kabuga', + 'Westerland', + 'Luckau', + 'Saddlebrooke', + 'Bijeljina', + 'Villepreux', + 'Karianga', + 'Tomar do Geru', + 'Guaraniacu', + 'Moravska Trebova', + 'Sunrise Manor', + 'King of Prussia', + 'Lemon Hill', + 'Condeuba', + 'Sikonge', + 'Metlili Chaamba', + 'Maplewood', + 'Qasigiannguit', + 'Banjar', + 'Cucuta', + 'Vazquez', + 'Sour el Ghozlane', + 'Oran', + 'Long Thanh', + 'Sao Domingos do Prata', + 'Fungurume', + 'Grado', + 'Sezze', + 'San Pedro Tapanatepec', + 'Uvalde', + 'Buenaventura', + 'Kanhauli', + 'Tadaoka-higashi', + 'Svitlovodsk', + 'Samut Songkhram', + 'Scherpenheuvel', + 'Filomeno Mata', + 'Mallappulasseri', + 'Royken', + 'Westerville', + 'Nioro', + 'Devendranagar', + 'Itabashi', + 'Itapuranga', + 'Chanteloup-les-Vignes', + 'Santa Lucia di Piave', + 'Satu Mare', + 'Tuni', + 'Chouafa', + 'Sevilla La Nueva', + 'Chaugain', + 'Cuquio', + 'Palm Coast', + 'Antanimieva', + 'Baltasar Brum', + 'Harnaut', + 'Lagoa do Carro', + 'Arenys de Munt', + 'Landecy', + 'Tancitaro', + 'Shanawan', + 'Mangoli', + 'Baharestan', + 'Pia', + 'Witney', + 'Guillena', + 'Namchi', + 'Naryn', + 'Ujhana', + 'Itigi', + 'Douar Oulad Sidi Moussa', + 'Natuba', + 'Hazel Park', + 'Farias Brito', + 'Corumba de Goias', + 'Rhyl', + 'Barkuhi', + 'Piracuruca', + 'Ranst', + 'Koka', + 'Yunshan', + 'Jiran', + 'Zanhuang', + 'Grahamstown', + 'Erandio', + 'Podili', + 'Neerpelt', + 'Leczna', + 'Richterich', + 'Narsingdi', + 'Arnhem', + 'Vodil', + 'Hakkari', + 'Simbach am Inn', + 'Panzos', + 'Chichester', + 'Driouch', + 'Tezontepec', + 'Palmeiras de Goias', + 'Tizi-n-Bechar', + 'Rosyth', + 'Greenlawn', + 'Mali', + 'Sidi Chiker', + 'Kwiha', + 'Busaar', + 'Gangammapeta', + "Be'er Ya`aqov", + 'Potangal', + 'Murayama', + 'Bang Bua Thong', + 'Lerma', + 'Santo Antonio do Taua', + 'Fair Lakes', + 'Creteil', + 'Qigexingcun', + 'Ymittos', + 'Flemington', + 'Northlake', + 'Edlapadu', + 'Angalakuduru Malepalle', + 'Pila', + 'Sinop', + 'La Higuerita', + 'Plymstock', + 'Cateel', + 'Augustow', + 'Ianantsony', + 'Bando', + 'Sizhan', + 'Uppalaguptam', + 'Damu', + 'Bordj Okhriss', + 'Panjab', + 'North Versailles', + 'Adh Dhakhirah', + 'Grove City', + 'Le Poire-sur-Vie', + 'Keshod', + 'Corby', + 'Inhassoro', + 'Hinesville', + 'Espartinas', + 'Gien', + 'Chennirkara', + 'Time', + 'Ziar nad Hronom', + 'Ravels', + 'Pakxan', + 'Namin', + 'Yaragol', + 'Maimbung', + 'Kominato', + 'Bayghanin', + 'South Bend', + 'Manzanillo', + 'Hartselle', + 'Balarampuram', + 'Cay', + 'Estepa', + 'Heliopolis', + 'Analila', + 'Korba', + 'Gusinje', + 'Lake Magdalene', + 'Ambahikily', + 'Rijen', + 'Tuta', + 'Jardinopolis', + 'Cypress Gardens', + 'Bijawar', + 'Soeda', + 'Buena Vista Tomatlan', + 'Lalejin', + 'Muro del Alcoy', + 'Lincoln Park', + 'Beecher', + 'Tansandra', + 'Ambohimanga Atsimo', + 'Manjhi', + 'Nahiyat al Karmah', + 'Rainhill', + 'Elizabethtown-Kitley', + 'Palotina', + 'Alfter', + 'Meppayyur', + 'Domoni', + 'Abay', + 'Nettetal', + 'Paithan', + 'Hafshejan', + 'Dubliany', + 'Balaka', + 'Barauli', + 'Kleinblittersdorf', + 'Belpasso', + 'Shopokov', + 'Eugene', + 'Navalyal', + 'Cieszyn', + 'Bom Retiro do Sul', + 'Taylor', + 'Perehinske', + 'Montale', + 'Attingal', + 'Fresnes', + 'Marofinaritra', + 'Arumbakkam', + 'Djebahia', + 'Diai Koura', + 'Candelaria Loxicha', + 'Boituva', + 'Broni', + 'Orangetown', + 'Pastos Bons', + 'Derinkuyu', + 'Stratford', + 'Ocotlan de Morelos', + 'Trbovlje', + 'Kitui', + 'Dhone', + 'Mohdra', + 'Zwijndrecht', + 'Chocen', + 'Hameenlinna', + 'Londonderry', + 'Ujre', + 'Koko', + 'Pomfret', + 'Rosdorf', + 'Monopoli', + 'Lingig', + 'Ravenna', + 'Herenthout', + 'Bovalino Marina', + 'Wheaton', + 'Almoradi', + 'Estanzuelas', + 'Sao Sebastiao do Passe', + 'Pont-y-pwl', + 'Puliyur', + 'Lagoa da Confusao', + 'Nighoj', + 'Giannouli', + 'Paivalike', + 'Yalamakuru', + 'Aplahoue', + 'Kotabumi', + 'Los Corrales de Buelna', + 'Marumori', + 'Sujnipur', + 'Pleasant Valley', + 'Buala', + 'Downers Grove', + 'Magallanes', + 'Bayt al Faqih', + 'Hualien', + 'Edgewater Park', + 'Pascani', + 'Ukkayapalle', + 'Cabrayil', + 'Xizhou', + 'Ravulapalem', + 'Villefontaine', + 'Al Fayyum', + 'Ulukisla', + 'Hargawan', + 'Tummanatti', + 'Pearl City', + 'Mucuge', + 'Selibe Phikwe', + 'Itsukaichi', + 'Seravezza', + 'Gopalganj', + 'Bodoco', + 'Paderborn', + 'Butare', + 'Sandur', + 'Zgornja Hajdina', + 'Stilfontein', + 'Xuan Trung', + 'Alampur Gonpura', + 'Thimiri', + 'Buhriz', + 'Ballston', + 'Kotla Qasim Khan', + 'Mannegudam', + 'Marinka', + 'Machakos', + 'Mankoeng', + 'Mirandola', 'Dinard', - 'Alguazas', - 'La Chapelle-Saint-Mesmin', - 'Vadakku Ariyanayakipuram', - 'Kowary', - 'Dangriga', - 'Alhendin', - 'Nasaud', - 'Campo Redondo', - 'Csomor', - 'Multi', - 'Tanggemu Nongchang', - 'Nagasamudram', - 'Divisopolis', - 'Lystrup', - 'Igny', - 'Pingree Grove', - 'Moimenta da Beira', - 'Pantano Grande', - 'Duga Resa', - 'Kandulapuram', - 'Minamiaso', - 'Charala', - 'Zumaia', - 'Aubiere', - 'Snodland', - 'Ramacca', - 'Oignies', - 'Cordele', - 'Tlalixtac de Cabrera', - 'Varre-Sai', - 'Centralina', - 'Huittinen', - 'Douchy-les-Mines', - 'Rideau Lakes', - 'Bonthe', - 'Vejen', - 'Borzna', - 'Porto Esperidiao', - 'Flowood', - 'Ouangani', - 'Miani', - 'Fort Oglethorpe', - 'Pintuyan', - 'Shyroke', - 'Kastav', - 'Ramannapeta', - 'Oudewater', - 'Canta', - 'Tefenni', - 'Chavkandak', - 'Ellon', - 'Alpena', - 'Sechelt', - 'Tetela del Volcan', - 'Rehburg-Loccum', - 'Courrieres', - 'Inkerman', - 'Bosanska Krupa', - 'Florania', - 'Tarashcha', - 'Beilngries', - 'Douar Mzoura', - 'New Silksworth', - 'Kottapalem', - 'Baragaon', - 'Tokunoshima', - 'Carencro', - 'Niebull', - 'Eleskirt', - 'Arataca', - 'Claymont', - 'Phra Pradaeng', - 'Radyvyliv', - "Al Jazirah al Hamra'", - 'Pescaria Brava', - 'Narasingam', - 'Barahi', - 'Lake Arrowhead', - 'Jemaat Oulad Mhamed', - 'San Blas', - 'Sao Jose do Jacuipe', - 'Mirante', - 'Blain', - 'Gudofredo Viana', - 'Carmo do Rio Verde', - 'Venkatapuram', - 'Celano', - 'Randazzo', - 'Balangkayan', - 'Zaleze', - 'Rainbow City', - 'Astoria', - 'Biandanshan', - 'Poirino', - 'Pechea', - 'Chaungtha', - 'Nanfang', - 'Carice', - 'Jimbolia', - 'Munchberg', - 'Amgachia', - 'Birao', - 'Angwali', - 'Aliganj', - 'Kothi', - 'Darwa', - 'Akil', - 'Kaynasli', - 'Shirbadgi', - 'Halgur', - 'Kendallville', - 'Bacioi', - 'Olovo', - 'Gaillard', - 'Fort William', - 'Remada', - 'Surla', - 'Birkenfeld', - 'Jhakhra', - 'Panchi', - 'Jandiala', - 'Kulundu', - 'Kranuan', - 'Jesenice', - 'Ajjipuram', - 'Pipra Naurangia', - 'Bellamkonda', - 'Svidnik', - 'Ban Bong Tai', - 'Bela Vista de Minas', - 'Canteras', - 'Bomporto', - 'Evander', - 'Morlenbach', - 'Cedartown', - 'Korolevo', - 'Fanzhao', - 'Labhgaon', - 'Katalpur', - 'Ban Bang Toei', - 'Roddam', - 'Biskupiec', - 'Balikumbat', - 'Bleicherode', - 'Foz', - 'Mexicaltzingo', - 'Tut', - 'Zelfana', - 'Calasparra', - 'Jadupatti', - 'Port Townsend', - 'Neuville-en-Ferrain', - 'Bordighera', - 'Castleton', - 'Bois-des-Filion', - 'Rogerstone', - 'New Richmond', - 'Toca', - 'Sobral de Monte Agraco', - 'Pabegou', - 'Togamalai', - 'Corte Madera', - 'Vutukuru', - 'Msila', - 'Sidi Abdelaziz', - 'Akhaltsikhe', - 'Narot Mehra', - 'Shioya', - 'Higashikagura', - 'Ain Zohra', - 'Valaparla', - 'Kilkunda', - 'Hazle', - 'Teplodar', - 'Tiruchchuli', - 'Kanteru', - 'Telnal', - 'Arcola', - 'Molalla', - 'Choele Choel', - 'Werneck', - 'Lenggries', - 'Masanasa', - 'Caudete', - 'Aizenay', - 'Kaza', - 'Msoga', - 'Busca', - 'Gakuch', - 'Zhengdong', - 'Ouled Rabah', - 'Parempuyre', - 'Visbek', - 'Mungod', - 'Periyanegamam', - 'Vernal', - 'Bibbiano', - 'Alella', - 'Ban Pa Hung', - 'Great Missenden', - 'North Gates', - "Za'roura", + 'Komen', + 'Highlands Ranch', + 'Kanra', + 'Boldaji', + 'Kampenhout', + 'Ardea', + 'Long Branch', + 'Katiola', + 'Rancagua', + 'Taima', + 'Innsbrook', + 'Fedosiia', + 'Vohitrindry', + 'Tres Pontas', + 'Kharial', + 'Belinta', + 'Tsu', + 'Zhucaoying', + 'West Chicago', + 'Exeter', + 'Ovar', + 'Fort Portal', + 'Upper Merion', + 'Tiruvarpu', + 'Karmiel', + 'Ivanec', + 'Project Six', + 'Luofeng', + 'Muttayyapuram', + 'Kawaminami', + 'Bila Tserkva', + 'Pfungstadt', + 'Hebi', + 'Kizugawa', + 'Gumusova', + 'Wellingborough', + 'Shimencun', + 'Ourense', + 'Sollies-Pont', + 'Jatani', + 'Ushuaia', + 'Drongen', + 'Lagarto', + 'Las Guaranas', + 'Minas Novas', + 'Ponnampatti', + 'Hola Prystan', + 'Cojutepeque', + 'Randolph', + 'Matsue', + 'Adohoun', 'Divonne-les-Bains', - 'Neo Psychiko', - 'Villasagar', - 'San Felice Circeo', - 'Cabo Rojo', - 'Montignies-le-Tilleul', - 'Okondja', - 'Caudebec-les-Elbeuf', - 'Rignano Flaminio', - 'Hermantown', - 'Elattur', - 'Iizuna', - 'Liminka', - 'Corfe Mullen', - 'Filippoi', - 'Dhanur Kalyanwadi', - 'Snohomish', - 'Siswar', - 'Haldipur', - 'Urlati', - 'Aigle', - 'Rompicherla', - 'Solindabad', - 'Raparla', - 'Hire Megalageri', - 'Qovlar', - 'Potavaram', - 'Kirkel', - 'Serebryansk', - 'Scherpenzeel', - 'Genova', - 'Deulgaon Mahi', - 'Auterive', - 'Serra Caiada', - 'Bilga', - 'Kondalahalli', - 'Bhagirathpur', - 'Hillsdale', - 'Doorn', - 'Borim', - 'Mawai', - 'Garden Acres', - 'Monaragala', - 'Pocklington', - 'Beccles', - 'Manglur', - 'Sirigeri', - 'Ankily', - 'Eidsberg', - 'Cajapio', - 'Belagola', - 'Sulagiri', - 'Oggaz', - 'Meymand', - 'Kabatas', - 'Altotting', - 'Meuselwitz', - 'Rettanai', - 'Hipparga', - 'Begowal', - 'Nathpur', - 'Sedico', - 'Hull', - 'Fuveau', - 'Aroali', - 'Rasak', - 'Torre Santa Susanna', - 'Vaddadi', - 'Kalakeri', - 'Anandnagar', - 'Horti', - 'Ardal', - 'Corcuera', - 'Komorowice', - 'Struer', - 'Safford', - 'Masdi', - 'Kondakindi Agraharam', - 'Adigappadi', - 'Hackettstown', - 'Garliava', - 'Marondry', - "Uchtepa Qishlog'i", - 'Bandixon', - 'Baker City', - 'North Glengarry', - 'Turkan', - 'Gunbarrel', - 'Videle', - "M'Chouneche", - 'Tutzing', - 'Zerizer', - 'Buxerolles', - 'Daruvar', - 'Mashhad Rizeh', - 'Perumuchchi', - 'Parnagua', - 'Kittery', - 'Sycow', - 'Gambissara', - 'Cuapiaxtla de Madero', - 'Havanur', - 'Nizza Monferrato', - 'Nkokonjeru', - 'Jomasho`y', - 'Shohimardon', - 'Naftalan', - 'Forres', - 'Chauki Hasan Chauki Makhdum', - 'Glenwood Springs', - 'Rokkasho', - 'Sariz', - 'Robore', - 'Fouesnant', - 'Padiham', - 'Machchand', - 'Shahpur Chaumukhi', - 'Muurame', - 'La Mision', - 'Talugai', - 'Korosavada', - 'Progress Village', - 'South Huron', - 'Guemoukouraba', - 'Kumcati', - 'Sahidganj', - 'Marieville', - 'Kadaladi', - 'Procida', - 'Worsley', - 'Ekamba', - 'Nong Ki', - 'Quartz Hill', - 'Warfield', - 'Jangalapalle', - 'Advi Devalpalli', - 'Brandywine', - 'Mellieha', - 'Kapyl', - 'Erutukada', - 'Mihqan', - 'Hardas Bigha', - 'Karapa', - 'Onan', - 'Vaals', - 'Kafr Takharim', - 'Kele', - 'Padugaipattu', - 'Rosstal', - 'Gignac-la-Nerthe', - 'Spanish Fort', - 'Primeiro de Maio', - 'Fiuggi', - 'Cody', - 'Zuidlaren', - 'Bingham', - 'Kilsyth', - 'Thikriwala', - 'Chichihualco', - 'Sao Sebastiao do Maranhao', - 'Hongliuwan', - 'Tympaki', - 'Pinczow', - 'Umarizal', - 'Weil im Schonbuch', - 'Abergavenny', - 'Rath To', - 'Eumseong', - 'Penetanguishene', - 'Santa Catarina Masahuat', - 'Hozin', - 'Saladoblanco', - 'Kouinine', - 'Cabanaquinta', - 'Mondeville', - 'Malinagar', - 'Sapkyo', - 'Rio Vista', - 'Naters', - 'Saint-Max', - 'Kuroshio', - 'Sax', - 'Ghatawan', - 'Novi di Modena', - 'San Elizario', - 'Celtik', - 'Roelofarendsveen', - 'Bieber', - 'Binefar', - 'Cabries', - 'Yaotsu', - 'Atoka', - 'East Rockaway', - 'Villerupt', - 'Bee Ridge', - 'Neves', - 'San Vicente de Castellet', - 'Badia Polesine', - 'Waldwick', - 'Stropkov', - 'La Leonesa', - 'Goytapa', - 'Ouedo', - 'Porangaba', - 'Antanananivo', - 'Mondai', - 'Bagalur', - 'Vrnjacka Banja', - 'Kidira', - 'Avelgem', - 'Swieqi', - 'Valozhyn', - 'Willstatt', - 'Mazamet', - 'Lake Hiawatha', - "La'tamna", - 'Ban Bu Sung', - 'Mstsislaw', - 'Heubach', - 'Kwale', - 'Olaine', - 'Bobenheim-Roxheim', - 'Were Ilu', - 'Auchel', - 'Sung Noen', - 'Struthers', - 'Jafra', - 'Jocoro', - 'Radlett', - 'Browns Mills', - 'Orange Lake', - 'Dudhpura', - 'Shahpur Undi', - 'Bara Khurd', - 'Mocharim', - 'Alassio', - 'Scenic Oaks', - 'Burgum', - 'Parthenay', - 'Mold', - 'Rupana', - 'Abjij', - 'Macerata Campania', + 'Talsur', + 'Auki', + 'Obo', + 'Spilamberto', + 'Konodimini', + 'Hanam', + 'Gopavaram', + 'Xambioa', + 'Terra Rica', + 'Pitea', + 'Jussara', + 'Ahuimanu', + 'Hampstead', + 'Bala Cynwyd', + 'El Rosal', + 'Labasa', + 'Garner', + 'Las Maravillas', + 'Toowoomba', + 'Kukshi', + 'Buzau', + 'Tahoua', + 'Koboko', + 'Carlopolis', + 'Wildeshausen', + 'Hershey', + 'Landsmeer', + 'Swarna', + 'Wordsley', + 'Gagarin Shahri', + 'Bad Laer', + 'Adigoppula', + 'Kratovo', + 'Desavilakku', + 'Qalat', + 'Senador Pompeu', + 'Solonopole', + 'Bainet', + 'Mandurah', + 'Kyaukpyu', + 'Willistown', + 'Pirri', + 'Aweil', + 'Akividu', + 'Majdanpek', + 'Qal`eh Tall', + 'Garopaba', + 'Sograha', + 'Al Jizah', + 'Shurobod', + 'Warden', + 'Danielskuil', + 'Paidha', + 'Vargem Alta', + 'Chamestan', + 'Kumasi', + 'Kafr ash Shaykh', + 'Chirundu', + 'Arzachena', + 'Dobrada', + 'Arcot', + 'Matlock', + 'Usmanpur', + 'Silute', + 'Al Qunaytirah', + 'Jablanica', + 'Gaada', + 'Tarazu', + 'Lagoa do Ouro', + 'Yuksekova', + 'Mirfield', + 'Kurmuk', + 'Macia', + 'Karuvakulam', + 'Nice', + 'Ignalina', + 'East Franklin', + 'Malhada', + 'Imbituba', + 'Kasumi', + 'Tiangua', + 'Leonforte', + 'Enumulapalle', + 'Pushpattur', + 'Romford', + 'El Talar de Pacheco', + 'Osakasayama', + 'Lanuza', + 'Bordighera', + 'Bennane', + 'Japura', + 'Yesilli', + 'Marcos Paz', + 'Hickam Housing', + 'Ban Khamen', + 'Shirguppi', + 'Chemmaruthi', + 'Woodlesford', + 'Povazska Bystrica', + 'Kotia', + 'Gunri', + 'Nawagarh', + 'Judenburg', + 'Hammam-Lif', + 'Matina', + 'Verkhnodniprovsk', + 'San Lucas', + 'Jacaraci', + 'Glarus', + 'Manoli', + 'Monticello', + 'Urziceni', + 'Pryluky', + 'Langhirano', + 'Buriti Bravo', + 'Skenderaj', + 'Bari', + 'Cho Moi', + 'Kahla', + 'Grojec', + 'Berea', + 'Wyandotte', + 'Jaguapita', + 'Modavandisatyamangalam', + 'Danesfahan', + 'Larache', + 'North Potomac', + 'Kharupatia', + 'Kisangani', + 'Nuoro', + 'Janakkala', + 'Bhatkhori', + 'Mungaoli', + 'Yalova', + 'Qaratog', + 'Yesilova', + 'Tualatin', + 'Sandviken', + 'Bickenhill', + 'Inwood', + 'Meckenheim', + 'Davidson', + 'Kanhaipur', + 'Longton', + 'Sendurai', + 'Paniem', + 'Jujharpur', + 'Sasolburg', + 'Rambouillet', + 'March', + 'Ewing', + 'Seogwipo', + 'Huber Heights', + 'Calabanga', + 'Mallasamudram', + 'Dharawat', + 'Ngara', + 'Pensacola', + 'Tuzluca', + 'Lauenburg', + 'Kidangazhi', + 'Ucu Seles', + 'Enebakk', + 'Nalua', + 'Aubiere', + 'Manfredonia', + 'Nacunday', + 'Street', + 'Sao Bernardo do Campo', + 'Sidhauli', + 'Igarape-Acu', + 'Teodoro Schmidt', + 'Barra do Corda', + 'Tangua', + 'Yibin', + 'Ozdere', + 'Chak Habib', + 'Medchal', + 'Surab', + 'Snyder', + 'Teus', + 'Oulad Slim', + 'Ingurti', + 'Manaure', + 'Jaipur', + 'Zlate Moravce', + 'Castillejos', + 'Kalakeri', + 'Mahavelona', + 'Iesi', + 'Bedford Heights', + 'Dinokana', + 'Shimogamo', + 'Mohammad Yar', + 'Ban Kham Pom', + 'Nannestad', + 'Espiye', 'Jiji', - 'Calan', - 'Kisujszallas', - 'Dhamua', - 'Taghbalt', - 'San Ignacio de Moxo', - 'Rudesheim am Rhein', - "'Ain Naga", - 'Dalawarpur', - 'Begijnendijk', - 'Satipo', - 'Verucchio', - 'Saha', - 'Rangasamudram', - 'Vange', - 'Lysa nad Labem', - 'La Baneza', - 'Blackwells Mills', - 'Namorona', - 'Levski', - 'Mery-sur-Oise', - 'Al Hamah', - 'Vysokyi', - 'Schotten', - 'Oakbrook', - 'Ilic', - 'Francisville', - 'Ciudad Tula', - 'Chapeltown', - 'Lydney', - 'Taiyur', - 'Gauli Palasiya', - 'Petmanhalli', - 'Pajaros', - 'Buyukorhan', - 'Tinkoni', - 'Lepakshi', - 'Sakuho', - 'Makaha', - 'Mikuszowice', - 'Mengibar', - 'Lipova', - 'Tiszafoldvar', - 'Glocester', - 'Zaniena', - 'Abaiara', - 'Nallikodur', - 'Sermoneta', - 'Cross Lanes', - 'Parilla', - "Bou'nane", - 'Vembaditalam', - 'Cheat Lake', - 'Maharajapuram', - 'Baldeogarh', - 'Volpago del Montello', - 'Tay', - 'Zaggota', - 'Olevsk', - 'Houthulst', - 'Suthalia', - 'Puduparambubhagam', - 'Basmakci', - 'Sirugamani', - 'Nikaido-kaminoshocho', - 'Massi', - 'Red Hook', - 'Castlegar', - 'Lauterach', - 'Munagapaka', - 'Goito', - 'Benemerito', - 'Novooleksiivka', - 'Tomboutou', + 'Bulandshahr', + 'Wetteren', + 'Valattur', + 'Hejian', + 'Wete', + 'Beverley', + 'Marar', + 'Olecko', + 'Chalatenango', + 'Dommasandra', + 'Chilamatturu', + 'Petit-Trou de Nippes', + 'Ratnagiri', + 'Crozet', + 'Birganj', + 'Dehiba', + 'Vettweiss', + 'Kucuk Dalyan', + 'Nirmal', + 'Simi Valley', + 'Wels', + 'Fredericton', + 'Nykoping', + 'Salgueiro', + 'Naantali', + 'Koliakkod', + 'Cruz das Almas', + 'Cardoso Moreira', + 'Sao Paulo', + 'Lugovoy', + 'Sheffield Lake', + 'Focsani', + 'Saarijarvi', + 'La Magdalena Chichicaspa', + 'Clarkstown', + 'Bongabong', + 'Raisen', + 'Aguadas', + 'Pomaz', + 'Shahpur Undi', + 'Wervershoof', + 'Cochoapa el Grande', + 'Malaybalay', + 'Mesudiye', + 'Caravaggio', + 'Moviya', + 'Manay', + 'Kitanakagusuku', + 'Basi', + 'Kant', + 'Garmeh', + 'Weeze', + 'Kenieran', + 'Epping', + 'Serra do Salitre', + 'Sabzevar', + 'Timbiqui', + 'Andilanatoby', + 'West Point', + 'Nneyi-Umuleri', + 'Brembate', + 'Bendigo', + 'Pitrufquen', + 'Mobara', + 'Tuku', + 'Herkimer', + 'Rokunohe', + 'Aliso Viejo', + 'Shirataka', + 'Huajiang', + 'Imam Sahib', + 'Toyoake', + 'Cidade Velha', + 'Bull Run', + 'Leguevin', + 'Sao Domingos', + 'Sidi Barani', + 'Ejeda', + 'Xishrov', + 'Ebebiyin', + 'Oruvadalkotta', + 'Gurwalia Biswas', + 'Mariupol', + 'Ulft', + 'Necocli', + 'Ambriz', + 'Saltsjobaden', + 'Oulad Dahmane', + 'Adelaide River', + 'Bikaner', + 'Condoto', + 'Shah Latif Town', + 'Manantheri', + 'Mossley', + 'Piracununga', + 'Parappanangadi', + 'Revel', + 'Atmakuru', + 'Pullappalli', + 'Shengli', + 'Salto', + 'Los Mochis', + 'Pattittara', + 'Dahuaishu', + 'Yamasa', + "Val-d'Or", + 'Holic', + 'Tarxien', + 'Meishan', + 'Baghant', 'Panrepatti', - 'Lalmunia Munhara', - 'Kuchesfahan', - 'Bierbeek', - 'Steinhaus', - 'Kaldenkirchen', - 'Southwater', - 'Kirundo', - 'Kil Perambalur', - 'Harrisonville', - 'Canelli', - 'Toukoto', - 'Kingaroy', - 'Airmont', - 'East Rutherford', - 'Kuldiga', - 'Reedsburg', - 'An Nayrab', - 'Grosse Pointe Farms', - 'George Mason', - 'Trebbin', - 'Belpara', - 'Cavan Monaghan', - 'Huejuquilla el Alto', - 'Ramiriqui', - 'Montignoso', - 'Chesapeake Ranch Estates', - 'Pajacuaran', - 'San Pedro Huamelula', - 'Dhangaraha', - 'Manahari', - 'Pakka Kalan', - 'Silamalai', - 'Juripiranga', - 'Mayfield', - 'Roslyn', - 'Fort Meade', - 'Piedrahita', - 'Saint-Laurent-de-la-Salanque', - 'Dagiapara', - 'North Versailles', - 'Platon Sanchez', - 'Strasshof an der Nordbahn', - 'Vandamettu', - 'Dores de Campos', - 'Le Beausset', - 'Capodrise', - 'Moba', - 'Suaita', - 'Alajarvi', - 'Senanga', - 'Zaruma', - 'Saint-Loubes', - 'Villiersdorp', - 'Horbury', - 'Tiri', - 'Amwa Majhar', - 'Soahany', - 'Haider Khel', - 'Krynica', - 'Shengping', - 'Kolagallu', - 'Srifa', - 'Chartoun', - 'Qana', - 'Amioun', - 'Ras el Metn', - 'Ed Damour', - 'Butha-Buthe', - 'Ghadamis', - 'Belavabary', - 'Mahabako', - 'Boanamary', - 'Esira', - 'Sandravinany', - 'Bedidy', - 'Vohitrafeno', - 'Daraina', - 'Masiaboay', - 'Ambatomivary', - 'Ambodisikidy', - 'Ambohimiarivo', - 'Bekodoka', - 'Maroharatra', - 'Ambararatabe', - 'Ambatomifanongoa', - 'Ambohitrambo', - 'Ebelo', - 'Analalava', - 'Lohafary', - 'Antsoantany', - 'Ambovonomby', - 'Isahara', - 'Ambodivoara', - 'Vodiriana', + 'Edemissen', + 'Rockport', + 'Chavassheri', + 'Swampscott', + 'Torroella de Montgri', + 'Chauk Azam', + 'Moul El Bergui', + 'Isla-Cristina', + 'Oulad Ayyad', + 'Qorveh', + 'Yoshiicho-shimobaru', + 'Jangipur', + 'Port Alberni', + 'Beauchamp', + 'Ratba', + 'Beni Douala', + 'Kunduz', + 'Seosaeng', + 'Etaples', + 'Bludenz', + 'Golaghat', + 'Sujanpur', + 'Doctor Arroyo', + 'Bugho', + 'Borgarnes', + 'Solanea', + 'Boulogne-Billancourt', + 'Khosrowshahr', + 'Paithan Kawai', + 'Kaltenkirchen', + 'Jordan', + 'Motiong', + 'Daraj', + 'Manhattan', + 'Debica', + 'Bina', + 'Nanjanad', + 'Campina', + 'Antsahavaribe', + 'Maizal', + 'Saint-Nicolas', + 'Round Lake Beach', + 'Kamalasai', + 'Yeola', + 'Dangila', + 'East Bradford', + 'Noale', + 'Germencik', + 'De Aar', + 'Taihecun', + 'Kilinochchi', + 'Karivalamvandanallur', + 'Vinany', + 'Pudtol', + 'Visselhovede', + 'Perigny', + 'Izalco', + 'Dhuri', + 'Rudarpur', + 'San Marzano sul Sarno', + 'Kambar', + 'Le Hochet', + 'Skalavik', + 'Dharhara', + 'Agutaya', + 'Montpelier', + 'Santa Pola', + 'Budelsdorf', + 'Gyapekurom', + 'Medan', + 'Egilsstadhir', + 'Somasso', + 'Carsamba', + 'Nepalganj', + 'Bobil', + 'San Guillermo', + 'Hyrum', + 'Dhauni', + 'Al Hisn', + 'Hengkou', + 'Nenagh', + 'Lake Monticello', + 'Kokiladanga', + 'Aves', + 'Iwaizumi', + 'Santa Quiteria do Maranhao', + 'Kusugal', + 'Misano Adriatico', + 'Liangyi', + "Qa'em Shahr", + 'Okene', + 'Dorsten', + 'Inglewood', + 'Waianae', + 'Nerupperichchal', + 'Ghandinagar', + 'Le Portel', + 'Nazare', + 'Douar Lehgagcha', + 'Boende', + 'Aracruz', + 'Atar', + 'Golhisar', + 'Niar', + 'Kristiansund', + "Mu'minobod", + 'Ilchester', + 'Jodoigne', + 'Mudanjiang', + 'Parapatti', + 'Youssoufia', + 'Has', + 'Rzeszow', + 'View Park-Windsor Hills', + 'Redland', + 'Bni Sidel', + 'Cumbum', + 'Sue', + 'Ban Pae', + 'Eghezee', + 'Lebedinovka', + 'Demerval Lobao', + 'Teplodar', + 'Moose Jaw', + 'Rahika', + 'Edwards', + 'Imdina', + 'Zuhres', + 'Gillette', + 'Tixter', + 'Valenii de Munte', + 'Zhangliangcun', + 'Failsworth', + 'Dormentes', + 'Chowchilla', + 'Osasco', + 'Cheste', + 'Elmadag', + 'Timberwood Park', + 'Tiruttani', + 'Souba', + 'Maripad', + 'Tiltil', + 'Piossasco', + 'Comstock Park', + 'Sagrada Familia', + 'San Raimundo', + 'Killeen', + 'Miracema', + 'Singapore', + 'Olocuilta', + 'Ribeirao do Pinhal', + 'Itaquitinga', + 'Haltom City', + 'Chanderi', + 'Jarabulus', + 'Chennampatti', + 'Izumo', + 'Taruma', + 'Sottaiyampalaiyam', + 'Ichikawamisato', + 'Brockton', + 'Pandua', + 'Willow Street', + 'Truro', + 'Topola', + 'Blumenau', + 'Braine-le-Comte', + 'Duga Resa', + 'Liesveld', + 'Cairu', + 'Kolongo-Bozo', + 'Huanghua', + 'La Oliva', + 'Yokkaichi', + 'Tres Lagoas', + 'Westervoort', + 'Michelstadt', + 'Cavalcante', + 'La Lima', + 'Ampanotokana', + 'Roma', + 'Latacunga', + 'Eckington', + 'Cam Pha', + 'Kangqiao', + 'Remanso', + 'Jipijapa', + 'Dbarwa', + 'Cody', + 'Narsarsuaq', + 'Windhoek', + 'Razgrad', + 'Xinhualu', + 'Aosta', + "M'Chouneche", + 'Aydarken', + 'Analamitsivalana', + 'Boro', + 'Yelur', + 'Manteno', + 'As Sarw', + 'Ban Bueng Phra', + 'Puliyankudi', + 'Istaravshan', + 'Pithaura', + 'Onex', + 'Chakdarra', + 'Kareli', + 'Dinshaway', + 'Matalam', + 'Yongju', + 'Kumarapuram', + 'Yidu', + 'St. Joseph', + 'Fort Bonifacio', + 'Mecayapan', + 'Saint-Dizier', + 'Sharurah', + 'Uruara', + 'Macusani', + 'Stollberg', + 'Avelino Lopes', + 'Eschenbach', + 'Kamianka-Buzka', + 'Merced', + 'Ishizaki', + 'Ratan', + 'Majholi', + 'Portimao', + 'Guyancourt', + 'Ampasimena', + 'Dengshangcun', + 'Teno', + 'Cachira', + 'Davaci', + 'Tamamura', + 'Clifton Park', + 'Ma`bar', + 'Aartselaar', + 'Blundellsands', + 'Richards Bay', + 'Bussolengo', + 'Ratnahalli', + 'Bestensee', + 'Manjacaze', + 'Solano', + 'Mercerville', + 'Wujie', + 'Luderitz', + 'Campo Formoso', + 'Pobiedziska', + 'Ennamangalam', + 'Claiborne', + 'Elesvaram', + 'Begogo', + 'San Salvo', + 'Tambura', + 'Zumbo', + 'Margate', + 'Naini Tal', + 'Mao', + 'Castelfranco di Sotto', + 'Guachaves', + 'Artemisa', + 'Ovalle', + 'Piedras Blancas', + 'Dhanauri', + 'Vengapalli', + 'Tnine Sidi Lyamani', + 'Balindong', + 'Busia', + 'Codigoro', + 'Shiqiao', + 'Eidson Road', + 'Malita', + 'Kapatagan', + 'Ervalia', + 'Sibuco', + 'Rattaphum', + 'Wolfratshausen', + 'Jucurucu', + 'Lismore', + 'Lagangilang', + 'Ech Chaibat', + 'Iguaba Grande', + 'Bayan Hot', + 'Senjan', + 'Mihara', + 'Sandwich', + 'Huanglongsi', + 'Hualaihue', + 'Campos do Jordao', + 'Radauti', + 'Hersham', + 'Rutherford', + 'Kavallemmavu', + 'Bindura', + 'Niono', + 'Hammam Dalaa', + 'Varto', + 'Qina', + 'Aringay', + 'Trofarello', + 'Goshikicho-aihara-minamidani', + 'Taozhou', + 'Wickford', + 'Casale sul Sile', + 'Pointe a Raquettes', + 'Dolianova', + 'Morpeth', + 'Safdarabad', + 'Asamankese', + 'Mifune', + 'South Huntington', + 'Antri', 'Ambohimahazo', - 'Ambodimadiro', - 'Andranambolava', - 'Marosakoa', - 'Soavimbahoaka', - 'Erada', - 'Mahabe', - 'Mahabo-Mananivo', - 'Miary-Taheza', - 'Ankadindambo', - 'Antaretra', - 'Betrandraka', - 'Amparihy', - 'Tanamarina', - 'Sahanivotry-Manandona', - 'Andranomenatsa', - 'Ambodimandresy', - 'Anontsibe-Sakalava', - 'Amparihitsokatra', - 'Ambatolava', - 'Ankerana', - 'Sihanamaro', - 'Vinanitelo', - 'Ifarantsa', - 'Ampasimazava', - 'Vohitany', - 'Vohitsaoka', - 'Andranopasy', - 'Beheloka', - 'Ankirondro', - 'Tamponala', - 'Katsepy', + 'Nangis', + 'Lincolnwood', + 'Vieira do Minho', + 'Marigliano', + 'Sankt Valentin', + 'Ota-ku', + 'Montes Claros', + 'Scottsboro', + 'Gulni', + 'Bogovinje', + 'Tlalnelhuayocan', + 'Little Canada', + 'Bni Bouayach', + 'Porto Rafti', + 'Pontal', + 'Milha', + 'Kigoma', + 'Littleborough', + 'Tarur', + 'Myers Corner', + 'Salamedu', + 'Hernando', + 'Sava', + 'Rowley Regis', + 'Qax', + 'Mor', + 'Jalalaqsi', + 'Fereydun Kenar', + 'Aubergenville', + 'Puranattukara', 'Vondrozo', - 'Tanambao-Daoud', - 'Sahatona-Tamboharivo', - 'Beanana', - 'Soatanana', - 'Ampitahana', - 'Anosimparihy', - 'Vatana', - 'Ambalanjanakomby', - 'Zoma-Bealoka', - 'Jangany', - 'Ianapera', - 'Ambahatrazo', - 'Fanjakana', - 'Putao', - 'China', - 'Padang Besar', - 'Zavora', - 'Outjo', - 'Al Mazyunah', - 'Surmon Chogga Grong', - 'Basla', - 'Gadani', - 'Bunji', - 'Ghota Fatehgarh', - 'Setubal', - 'Diabougou', - 'Koumpentoum', - 'Gadoon', - 'Murgap', - 'Khunays', - 'Kadama', - 'Bukomansimbi', - 'Xishrov', - 'Oyim', - 'Tujg', - 'Boladi', - 'Fatikchari', + 'Pombal', + 'Upper Providence', + 'Huizhou', + 'Mali Idos', + 'Townsville', + 'Bolbec', + 'Nanpara', + 'Tocantins', + 'Oulgaret', + 'Marmara Ereglisi', + 'Pedra', + 'Sahapur', + 'Puerto Lleras', + 'Soccorro', + 'Enerhodar', + 'Adams', + 'Khetko', + 'Bacobampo', + 'Naxxar', + 'Wilton', + 'Manantenina', + 'Montecatini Terme', + 'Ocumare del Tuy', + 'Kas', + 'Nagarpara', + 'Tagounite', + 'Magnago', + 'Paripueira', + 'Guerra', + 'Ecaussinnes-Lalaing', + 'Tittachcheri', + 'Cariacica', + 'Missaglia', + 'Niscemi', + 'Ajdabiya', + 'Santa Cruz das Palmeiras', + 'Bogucice', + 'Centurion', + 'Aalst', + 'Tupelo', + 'Kochhor', + 'Riihimaki', + 'Sjobo', + 'Dongguan', + 'Melbourne', + 'Goluchow', + 'Devapur', + 'Merimbula', + 'North Port', + 'Bou Izakarn', + 'Cuisnahuat', + 'Cunday', + 'Sao Bernardo', + 'Everett', + 'Gyal', + 'Cedar Grove', + 'Piriapolis', + 'Mamakating', + 'Narathiwat', + 'Wood River', + 'Kebemer', + 'Salzburg', + 'Roebourne', + 'Port-au-Prince', + 'Ulliyeri', + 'Simferopol', + 'Navojoa', + 'Kuna', + 'Ikeda', + 'Dinan', + 'Champadanga', + 'Kottayam', + 'Itajai', + 'Moulay Abdallah', + 'Ponnuru', + 'Pakribarawan', + 'Canakkale', + 'Mestre', + 'Kannampalaiyam', + 'Lang Suan', + 'Libiaz', + 'Naftalan', + 'Guanzhai', + 'Juruti', + 'Hautmont', + 'Coro', + 'Navani', + 'Cagdianao', + 'Bauska', + 'Waltershausen', + 'Karippira', + 'Kodiyeri', + 'Huercal de Almeria', + 'Lebane', + 'Tando Allahyar', + 'El Bordj', + 'Polva', + 'Asasa', + 'Capilla de Guadalupe', + 'Vadapalanji', + 'Mekhe', + 'Leigh-on-Sea', + 'Velykyi Bychkiv', + 'Sihali Jagir', + 'Tepetitlan', + 'Sincelejo', + 'Caorle', + 'Burrel', + 'Ebetsu', + 'Niagara-on-the-Lake', + 'Tucson Mountains', + 'Manawar', + 'Uige', + 'Ankaramy', + 'Guinobatan', + 'Andrakata', + 'Patulul', + 'Patnos', + 'Bengkulu', + 'Strakonice', + 'Bairo', + 'Sint Anthonis', + 'Astorp', + 'Chantepie', + 'Stara Gora', + 'Fierenana', + 'Phenix City', + 'Schmalkalden', + 'Nadi', + 'Vimodrone', + 'Maramag', + 'Satipo', + 'El Oued', + 'Dogbo', + 'Needham', + 'Mitu', + 'North Vancouver', + 'Belmonte', + 'Turmanin', + 'Beandrarezona', + 'Shiraz', + 'Edgewood', + 'Eqbaliyeh', + 'West Whiteland', + 'Nchelenge', + 'Sason', + 'Suknah', + 'Alhandra', + 'Boghni', + 'Versoix', + 'Beverwijk', + 'Satyun', + 'Village Green-Green Ridge', + 'Luuk', + 'Speedway', + 'Yanbu', + 'Bhitarwar', + 'Kluang', + 'Sastamala', + 'Mulangodi', + 'Olivares', + 'Kondhali', + 'Inkollu', + 'Piedras Negras', + 'Consuelito', + 'Uruguaiana', + 'Nowy Targ', + 'Puvali', + 'Hulshout', + 'Pleasant Grove', + 'Armant', + 'Viga', + 'Igbanke', + 'Plover', + 'Bene Beraq', + 'Yopougon', + 'San Nicolas de los Ranchos', + 'Piui', + 'Gieraltowice', + 'Tarana', + 'Yanai', + 'Chariyakulam', + 'Bogota', + 'Minamisanriku', + 'Werl', + 'Manuel Ribas', + 'Heusenstamm', + 'Grosseto', + 'Villeparisis', + 'Serramanna', + 'Sudlohn', + 'Mawatagama', + 'Starokostiantyniv', + 'Vaikam', + 'Ipiales', + 'New Baltimore', + 'Quinta de Tilcoco', + 'Borgaro Torinese', + 'Tapiratiba', + 'Cazzago San Martino', + 'Esperanca', + 'Yirol', + 'Mila', + 'Tangalan', + 'Sardarshahr', + 'Palmetto', + 'Heddesheim', + 'Grossburgwedel', + 'Pradera', + 'Bela Vista do Paraiso', + 'Kilwinning', + 'Dunn Loring', + 'Bcharre', + 'Bhagirathpur', + 'Cabadbaran', + 'Hino', + 'Runcorn', + 'Santiago de Compostela', + 'Sotouboua', + 'Tecate', + 'Morasar', + 'Vanono', + 'Sankt Ingbert', + 'Jajce', + 'Xinyu', + 'Hochst im Odenwald', + 'Kawthoung', + 'Cherry Hill', + 'Riebeeckstad', + 'Cacheu', + 'Tranovaho', + 'Douar Sgarta', + 'Tlemcen', + 'Mandabe', + 'Idil', + 'Bohicon', + 'East Cocalico', + 'Wekiwa Springs', + 'Magdalena Milpas Altas', + 'South Charleston', + 'Dougba', + 'Glenwood Springs', + 'Dumfries', + 'Moyale', + 'Mabini', + 'Santa Terezinha de Goias', + 'Evergreen', + 'Watford', + 'Rabor', + 'Castel Mella', + 'Tanabe', + 'Tafaraoui', + 'Hilter', + 'Shujaabad', + 'Videm', + 'Kecskemet', + 'Obertraubling', + 'Folomana', + 'Novi Becej', + 'Molalla', + 'Hagta', + 'Tisina', + 'Raikal', + 'Wendell', + 'Canet-en-Roussillon', + 'Kennedy', + 'Herzberg am Harz', + 'San Simon', + 'Miyatoko', + 'Pali', + 'Copiapo', + 'Muhldorf', + 'Bambadinca', + 'Igbaras', + 'Kothi', + 'Souq Sebt Says', + 'San Rafael Abajo', + 'Halisahar', + 'Mamaroneck', + 'Varisshiyakuni', + 'Matsoandakana', + 'Burgas', + 'Bhanghi', + 'Beverly', + 'Raichur', + 'Tahannawt', + 'Tota', + 'Lunel', + 'Souk Tlet El Gharb', + 'Racine', + 'Stockerau', + 'Mazamitla', + 'Guachucal', + 'Malepur', + 'Sarikamis', + 'Gothenburg', + 'Suganwan', + 'Kirikkale', + 'Maghull', + 'Chonchi', + 'Ospitaletto', + 'Maria da Fe', + 'Chalandri', + 'Bobon', + 'Naqadah', + 'Martinopole', + 'Enghien', + 'Savigny-le-Temple', + 'Ramchandarpur', + 'Caio', + 'Belo', + 'Bukowno', + 'Tel Aviv-Yafo', + 'Avabodji', 'Puerto America', - 'Mboki', - 'Gar', - 'Ziketan', - 'Sola', - 'Matagua', - 'Morayra', - 'Karaga', - 'Rebola', - 'Pont Sonde', - 'Haria', - 'Waghai', - 'Ghargaon', - 'Deh', - 'Medarametla', - 'Hanzviur', - 'Amsin', - 'Muttalakanpatti', - 'Isnapuram', - 'Karumulaikkal', - 'Dhalai', - 'Nidamaluru', - 'Budwan', - 'Chhimluang', - 'Dhirwas', - 'Siddarampuram', - 'Reha Mota', - 'Paravakkottai', - 'Mevani', - 'Tharial', - 'Dewal Thal', - 'Lakshmipuram', - 'Gandhali', - 'Fatehgarh', - 'Kambhaladinne', - 'Kerwada', - 'Ulipuram', - 'Kochhor', - 'Betnoti', - 'Balagam', - 'Sotik', - 'Kargi', - 'Kourani', - 'Kolno', - 'Ramamangalam', - 'Wahlstedt', - 'Pierrelaye', - 'Bomareddipalli', - 'Czersk Pomorski', - 'Aniche', - 'Rakhwari', - 'Atri', - 'Melendugno', - 'Bad Frankenhausen', - 'Mengen', - 'Soyaux', - 'Downham Market', - 'Vilpatti', - 'Euxton', - 'Erraballa', - 'Paikpara', - 'Lambesc', - 'Yadwad', - 'Monteriggioni', - 'Marton', - 'Ketugram', - 'Tarhjicht', - 'Lillers', - 'Praia do Carvoeiro', - 'Stenungsund', - 'Rangamati', - 'Barkly East', - 'Pavlikeni', - 'Salemi', - 'Kinnelon', - "Ben N'Choud", - 'Fateha', - 'Kengarai', - 'Pullambadi', - 'Chada', - 'Dilra', - 'Asagi Ayibli', - 'Gudensberg', - 'Inungur', - 'Budd Lake', - 'Mahajjah', - 'Lapinlahti', - 'Galleh Dar', - 'Leninskiy', - 'Gulyam', - 'Crikvenica', - 'Itikalapalle', - 'Cape Canaveral', - 'Painal', - 'Penn Forest', - 'Sulecin', - 'Wood-Ridge', - 'Yueyaquan', - 'Dettingen an der Erms', - 'Cedar Hills', - 'El Cairo', - 'Shildon', - 'Kanyana', - 'Mahalleh-ye Shirinu', - 'Ainring', - 'Ringkobing', - 'Tansandra', - 'Bolsward', - 'Eybens', - 'Bishopstoke', - 'Erenler', - 'Valdobbiadene', - 'Quinto di Treviso', - 'Walker Mill', - 'San Nicolas Buenos Aires', - 'Tsuno', - 'Willoughby Hills', - 'Prelouc', - 'Ottendorf-Okrilla', - "Barano d'Ischia", - 'Boundji', - 'Bananal', - 'Mamobihat', - 'Colts Neck', - 'East Liverpool', - 'Casino', - 'Kottaipatti', - 'Tzucacab', - 'Gaolingcun', - 'Singera', - 'Tan Son', - 'Dujiashigou', - 'Vegachi', - 'Erraguntlakota', - 'Detroit Lakes', - 'Altenholz', - 'Cuesmes', - 'Aberaman', - 'Tokkavadi', - 'Hiranai', - 'Los Rios', - 'Kambaliyampatti', - 'Sufian', - 'Iwashita', - 'Anama', - 'Chakicherla', - 'San Calixto', - 'Birchington', - 'Judenburg', - 'Sagure', - 'Nairn', - 'Makale', - 'Sundekuppam', - 'Kapasiawan', - 'Padinjarebagam', - 'Khandsa', - 'Bastak', - 'Aibak', - 'Bertem', - 'Friedrichsthal', - 'Mahem', - 'Siechnice', - 'Sankt Andra', - 'Handsworth', - 'Conselve', - 'Ettimadai', - 'Khuran Milik', - 'Ratne', - 'Kawara', - 'Bastrop', - 'DuPont', - 'Halls', - 'Souama', - 'Saharbani', - 'Muskegon Heights', - 'Koloti', - 'Leppavirta', - 'Kapuvar', - 'Anahuac', - 'Fallston', - 'Aich', - 'Bad Konig', - 'Oelsnitz', - 'Sorkheh', - 'Picnic Point', - 'Hooglede', - 'Coal', - "Fil'akovo", - 'Verkhivtseve', - 'Qufadah', - 'Sellersburg', - 'Araua', - 'Torrejon de la Calzada', - 'Birni Lafia', - 'Ennamangalam', - 'Cuicatlan', - 'Heeze', - 'Aboso', - 'Chavusy', - 'Tamzoura', - 'Bhado Khara', - 'Ban Ngao', - 'Payerne', - 'Bad Bevensen', - 'Balatonalmadi', - 'Kamalasai', - 'Sniatyn', - 'Thi Tran Mau A', - 'Consuegra', - 'Aldenham', - 'Ocsa', - 'Erquelinnes', - 'Caraibas', - 'Nariar', - 'Fino Mornasco', - "P'yongch'ang", - 'Pachchampalaiyam', - 'Dubove', - 'Porto Xavier', - 'Ammanabrolu', - 'Padilla', - 'Kenafif', - 'Coycoyan de las Flores', - 'Bad Ems', - 'Ipupiara', - 'Dongou', - 'La Sierra', - 'Marpingen', - 'Burscough', - 'Kamdoli', - 'Nohfelden', - 'Kraaipan', - 'Waltenhofen', - 'Miandasht', - 'Hingyon', - 'La Pointe', - 'Akalapura', - 'Telpur', - 'Kinalur', - 'Fosses', - 'Khapdeh', - 'Bucine', - 'Birkenau', - 'Karimunjawa', - 'Kalimala', - 'Kadrabad', - 'Parwaha', - 'Farsund', - 'Grossos', - 'Talkhvoncheh', - 'Heves', - 'Vedurupavaluru', - 'Rockcreek', - 'Ban Pong Yaeng Nai', - 'Oldenburg in Holstein', - 'Kargahia Purab', - 'Nanzhou', - 'Maxeville', - 'Bajwara', - 'Capitola', - 'Welkenraedt', - 'Dongcha', - 'Angalakuduru Malepalle', - 'Rye Brook', - 'Temiskaming Shores', - 'Nove Mesto na Morave', - 'Minnampalli', - 'Jilotlan de los Dolores', + 'Hanson', + 'Huangshan', + 'Bulusan', + 'Domazlice', + 'Linkenheim-Hochstetten', + 'Suaza', + 'Mangalagiri', + 'Rocky River', + 'Tanakoub', + 'Canicatti', + 'Las Rosas', + 'Mahlaing', + 'Jelenia Gora', + 'Mathila', + 'Aizawa', + 'Itatiaia', + 'Neuri', + 'Chivacoa', + 'Arvorezinha', + 'Armanaz', + 'Buritizeiro', + 'Bien Hoa', + 'Bruchkobel', + 'Dolo Bay', + 'Lefkada', + 'Tasiusaq', + 'Pallappatti', + 'Kanchrapara', + 'San Roque', + 'Jefferson', + 'Santiago de Baney', + 'Kofu', + 'Harchandpur', + 'Moss Bluff', + 'Vushtrri', + 'Mithi', + 'Smederevska Palanka', + 'Apan', + 'Deodha', + 'Nallihan', + 'Guapo', + "Ghinda'e", + 'Sar-e Pul', + 'Christiansburg', + 'Pont-a-Celles', + 'Overijse', + 'Trecastagni', + 'Oulad Embarek', + 'Dayr Hafir', + 'Caldas de Reyes', + 'Arkalochori', + 'Gafsa', + 'Cipolletti', + 'Kaikaram', + 'Shuangshuicun', + 'Iquitos', + 'Hazaribagh', + 'Bedidy', + 'Mayate', + 'Chumbicha', + 'Dilasag', + 'Karapa', + 'Petaling Jaya', + 'Castel Gandolfo', + 'Yevpatoriia', + 'Kuchaiburi', + 'Hanyu', + 'Horn Lake', + 'Kadiria', + 'Zhongba', + 'Godoy Cruz', + 'Malappuram', + 'East Peoria', + 'Markranstadt', + 'Livonia', + 'Dongen', + 'Golbasi', + 'Bhagwangola', + 'Elektrenai', + 'Hat Yai', + 'Saint John', + 'Torihama', + 'Galimuyod', + 'Raikot', + 'Bagre', + 'Komijan', + 'Ibia', + 'Holyhead', + 'Akwatia', + 'Elavanasur', + 'Tandag', + 'Chilwell', + 'Ciudad Ojeda', + 'Ciudad Serdan', + 'Radlett', + 'Vembarpatti', + 'Atripalda', + 'Gourock', + 'Anama', + 'Amblecote', + 'Excelsior Springs', + 'Dadu', + 'Offa', + 'Brindisi', + 'Kovilpatti', + 'Chrudim', + 'Cesson-Sevigne', + 'Mediouna', + 'Zengqiao', + 'Aguilares', + 'Siay', + 'Mananjary', + 'Kolarovo', + 'Melissia', + 'Stari Trg', + 'Viadana', + 'Stolberg', + 'Berekum', + 'Farako', + 'Joyabaj', + 'San Giorgio di Piano', + 'Carbonera', + 'Mackay', + 'Meltham', + 'Challapalle', + 'Saricam', + 'Tres Barras', + 'Cannes', + 'Upper Darby', + 'Arlington', + 'Sanxi', + 'Sanankoro Djitoumou', + 'Birur', + 'Manne Ekeli', + 'Regenstauf', + 'Midsalip', + 'Reggello', + 'Corinda', + 'Babatngon', + 'Bungku', + 'Zhangshu', + 'Idiofa', + 'Amboanana', + 'Langley', + 'Fishersville', + 'Mateare', + 'Linda', + 'Helena', + 'Hohenstein-Ernstthal', + 'Korla', + 'Bairuo', + 'Limoeiro do Ajuru', + 'Gandevi', + 'Rogers', + 'Dexing', + 'Padugaipattu', + 'Ilmenau', + 'Litovel', + 'Yasenivskyi', + 'Boca da Mata', + 'Sarkad', + 'Pawayan', + 'Avon Park', + 'Kondarangi Kiranur', 'Novgorodskoye', - 'Setubinha', - 'Bekkaria', - 'Balderton', - 'Pavittiram', - 'Fair Oaks Ranch', - 'Saarijarvi', - 'Barni', - 'Ellisville', - 'Varzedo', - 'Pipraun', - 'Mussomeli', + 'Nanattuparai', + 'Krishnapur', + 'Mendez-Nunez', + 'Alacam', + 'Pelissanne', + 'Colotlan', + 'Raahe', + 'Ridder', + 'Jisr ash Shughur', + 'Hoveyzeh', + 'Rokkasho', + 'Muquem de Sao Francisco', + 'Tsuru', + 'Ross-Betio', + 'Escanaba', + 'Tacana', + 'Traverse City', + 'Gounarou', + 'Fontaine', + 'Sahuarita', + 'Bracciano', + 'Araripina', + 'Gambissara', + 'Lumphat', + 'Gwangmyeongni', + 'Kirrayach', + 'University Place', + 'Unai', + 'Paracin', + 'Juara', + 'Ware', + 'Hilltown', + 'Summit Park', + 'Mislata', + 'Rottofreno', 'Uniontown', - 'Strzelce Krajenskie', - 'Liskeard', - 'Pudimadaka', - 'Dar El Kebdani', - 'Mandello del Lario', - 'Pokrovske', - 'Manduri', - 'Epanomi', - 'Kunnur', - 'Karajgi', - 'Polistena', - 'Arroyohondo', - 'Sidi Rahhal', - 'Boufatis', - 'Kaunra', - 'Vaiano', - 'Phak Hai', - 'Holsbeek', - 'Glanmire', - 'Bharhopur', - 'Lomazzo', - 'Coweta', - 'Kaith', - 'Ogdensburg', - 'Maceira', - 'Zefyri', - 'Navinipatti', - 'Panjab', - 'Sursee', - 'Baldock', - 'Matadepera', - 'Carmaux', - 'Suhiya', - 'Kourimat', - 'Maisenhausen', - 'Pachalum', - 'Shankarampet', - 'Tonse East', - 'Nenagh', - 'Wangi', - 'Kummersbruck', - 'Bilehra', - 'Pliezhausen', - 'Wilsele', - 'Huldenberg', - 'Schlitz', - 'Dera Baba Nanak', - 'Ippagudem', - 'Asola', - 'Golden Hills', - 'Rodinghausen', - 'Brinkmann', - 'Frydlant nad Ostravici', - 'Diavata', - 'Siruvalur', - 'Urgnano', - 'Miadanandriana', - 'Messini', - 'Baghant', - 'Jettihalli', - 'Koflach', - 'Ivancice', - 'Suknah', - 'Coello', - 'Pizarra', - 'Gudgeri', - 'Soulei', - 'Namakadu', - 'Campi Salentina', - 'River Vale', - 'Qiziltepa', - 'Muthabana', - 'Bhadsara', - 'Saquisili', - 'St. Augustine Shores', - 'Mohlanapeng', - 'Kaimati', - 'Kadanganeri', - 'Gurwalia Biswas', - 'Hinton', - 'Petorca', - 'Saint-Sauveur', - 'Ankazotsifantatra', - 'Vardenik', - 'Biot', - 'Beckett Ridge', - 'Ga-Kgapane', - 'Kaiken', - 'Ploermel', - 'Meldola', - 'Wapakoneta', - 'Trancoso', - 'Ech Chaibat', - 'Chupaca', - 'Barahra', - 'Margarita', - 'Baltara', - 'Kosching', - 'Heilsbronn', - 'Krasnyy Yar', - 'Widhwidh', - 'Ban Pha Bong', - 'Vetraz-Monthoux', - "Foum Jam'a", - 'Ban Phan Chali', - 'Beneditinos', - 'Reddigudem', - 'Heerlerbaan', - 'Ruoqiang', - 'Santa Maria de Palautordera', - 'Kanjiza', - 'Saint-Pierre-du-Mont', - 'Qazigund', - 'Douar Snada', - 'Metsamor', - 'Alcorta', - 'Ouled Brahim', - 'Montigny-en-Gohelle', - 'Chegur', - 'Ommangi', - 'Stocksbridge', - 'San Miguel Siguila', - 'Sarkeghat', - 'Krzeszowice', - 'Keokuk', - 'Therwil', - 'Palepalli', - 'Iwamuro-onsen', - 'Greencastle', - 'Berd', - 'Swan Hill', - 'Muttattuteruvu', - 'Boudinar', - 'Ntorosso', - 'Roche-la-Moliere', - 'Poggio a Caiano', - 'Sauk Village', - 'Laakirchen', - 'Vettaikkaraniruppu', - 'Celldomolk', - 'Lingampet', - 'Mahisanrh', - 'Geylegphug', - 'Independent Hill', - 'Nueva Palmira', - 'Tanichchiyam', - 'Outa Bouabane', - 'Zinkiv', - 'Paradarami', - 'Humlebaek', - 'Abram', - 'Berikai', - 'Ciudad de Loreto', - 'Aranzazu', - 'Mittenwalde', - 'Dandoli', - 'Huichapan', - 'Ii', - 'Sovicille', - 'Nhandeara', - 'Narasimharajapura', - 'Sweet Home', - 'Fundeni', - 'Rodynske', - 'Pailon', - 'Renaico', - 'Norosi', - 'Fuente Palmera', - 'Feyzin', - 'DeRidder', - 'Juru', - 'Achchippatti', - 'Kadoli', - 'Santo Stefano di Magra', - 'Cuencame de Ceniceros', - 'Altofonte', - 'Plains', - 'Mariluz', - 'Anjahamana', - 'Lambertville', - 'Eerbeek', - 'Berezivka', - 'Barcs', - 'Surir', - 'Hochdorf', - 'Bisingen', - 'Tulin', - 'Boriguma', - 'Mosjoen', - 'Tha Mai', - 'Merchweiler', - 'Katarmala', - 'Cavriago', - 'Sturbridge', - 'Kobeliaky', - 'Chimay', - 'Hansa', - 'Dindanko', - 'Masquefa', - 'Kharial', - 'Kokiladanga', - 'Pedda Kotayalanka', - 'Itamukkala', - 'Kaimuh', - 'Shahzadpur', - 'Manubolu', - 'Partanna', - 'Qarabalyq', - 'Saint-Gregoire', - 'Patsanda', - 'Philipstown', - 'Makariv', - 'Chandankiari', - 'Ozieri', - 'Fort Salonga', - 'Carregal do Sal', - 'Touwu', - 'Karghar', - 'Vigonovo', - 'Succasunna', - 'Tekit', - 'Bardmoor', - 'Cildir', - 'Aramari', - 'Cachipay', - 'Tolmezzo', - 'Sieverne', - 'Parkes', - 'Etchojoa', - 'Iraiyur', - 'Pushpattur', - 'Terku Narippaiyur', - 'Birpur Barapatti Pindraun', - 'Mudgee', - 'Bockenem', - 'Kodivalasa', - 'Kamikita-kita', - 'Ribadeo', - 'Couzeix', - 'Basso', - 'Toudja', - 'Gangapur Athar', - 'Berilo', - 'Ilsfeld', - 'Padarti', - 'Nisarpur', - 'Loudonville', - 'Kusugal', - 'Guia Lopes da Laguna', - 'Alfaro', - 'Nodinge-Nol', - 'Jixian', - 'Pithaura', - 'Mogosoaia', - 'San Rafael Obrajuelo', - 'Nagulapadu', - 'Amjhar', - 'Castelletto sopra Ticino', - 'Jesup', - 'Nong Wua So', - 'Pillaro', - 'Indurti', + 'Kulu', + 'Bunia', + 'Ciudad Bolivar', + 'Gitagum', + 'Uniao dos Palmares', + 'Erumaippatti', + 'Pichhor', + 'Yuanlin', + 'Bulungu', + 'Kadakola', + 'Harur', + 'Raunheim', + 'Mothihari', + 'Malahide', + 'Macapa', + 'Mahabo', + 'Andonabe Atsimo', + 'Hita', + 'Salesopolis', + 'Tirkakara', + 'Malhargarh', + 'Oakengates', + 'Agrinio', + 'Whitehall', + 'Lapuyan', + 'Botticino Sera', + 'Tinoc', + 'Jiquilpan de Juarez', + 'Rockville Centre', + 'Ibatiba', + 'Ballina', + 'Broken Arrow', + 'Ziniare', + 'Clayton le Moors', + 'Fredensborg', + 'Kharod', + 'Umm al `Abid', + 'Goldenrod', + 'Yacopi', + 'Halsur', + 'Opoczno', + 'Kottapalle', + 'Ubrique', + 'Sodrazica', + 'Irakleia', + 'Sao Luis Gonzaga', + 'Sao Paulo do Potengi', + 'North Gates', + 'Alsip', + 'Choele Choel', + 'Antsiatsiaka', + 'Beocin', + 'Tenancingo', + 'Monselice', + 'Marpalli', + 'Yangqingcun', + 'Columbine', + 'Sahamadio', + 'San Nicolas Buenos Aires', + 'Tiruvur', + 'Anosimparihy', + 'Lariano', + 'Chaval', + 'Karavan', + 'Kingsbury', + 'Koduru', + 'Bangolo', + 'Heidenau', + 'Petrolina', + 'Archena', + 'Natonin', + 'Casalnuovo di Napoli', + 'Nova Odessa', + 'Kariz', + 'Caen', + 'Scugog', + 'Bangalore', + 'Zijinglu', + 'Catford', + 'Chakapara', + 'Safita', + 'Acquaviva', + 'Satai', + 'Ghabaghib', + 'La Spezia', + 'Iquique', + 'Barhampur', + 'Chalungalpadam', + 'Kerur', + 'Gulnar', + 'Banigbe', + 'Metamorfosi', + "Ma'muniyeh", + 'Tura', + 'Seelze', + 'White Plains', + 'Reddippatti', + 'Ticuantepe', + 'Ntoroko', + 'Nairobi', + 'Glubczyce', + 'Safi', + 'Larne', + 'Sebin Karahisar', + 'Donegal', + 'Pasto', + 'Ceyhan', + 'East Grand Forks', + 'Qarqan', + 'Ferney-Voltaire', + 'Caybasi', + 'Ayanavelikulangara Tekku', + 'Derventa', + 'Homburg', + 'Zaouiet Says', + 'Jethuli', + 'Ketti', + 'Rochdale', + 'Zevio', + 'Made', + 'Eleskirt', + 'Iijima', + 'Rubirizi', + 'Mombris', + 'Santa Teresita', + 'Pedappai', + 'Vineland', + 'Saint-Amable', + 'Awara', + 'Betton', + 'Alsbach-Hahnlein', + 'Tongzhou', + 'Nopala de Villagran', + 'Propria', + 'Jawkatia', 'Morrovalle', - "Oulad 'Azzouz", - 'Gorha', - 'Little River', - 'El Espinar', - 'Plainville', - 'Caldicot', - 'Socota', - 'Haapsalu', - 'Kiato', - 'Apiuna', - 'Pasewalk', - 'Vettweiss', - 'Chuhal', - 'Kostrzyn', - 'Kouarfa', - 'Samabouro', - 'Altlandsberg', - 'Kongen', - 'Basapatna', - 'Pasupatikovil', - 'Jerissa', - 'Sasaima', - 'Nordwalde', - 'Kalas', - 'Vlist', - 'Banino', - 'Coamo', - 'Vidor', - 'Sande', - 'Portet-sur-Garonne', - 'Arden Hills', - 'Palkot', - 'San Vendemiano', - 'Grey Highlands', - 'Gangaur', - 'Sorab', - 'Ban Mae Sam Laep', - 'Kinhalu', - 'Kalyanpur', - 'Paravada', - 'Bergambacht', - 'Laubach', - 'Kil Valur', - 'Keshwari', - 'Alden', - 'Djangoa', - 'Olmos', - 'Drezdenko', - 'Honow', - 'Manushmuria', - 'Mae O', - 'Bauska', - 'Imlil', - 'Pisac', - 'Velpuru', - 'College Place', - 'Resadiye', - 'Bad Liebenzell', - 'Boscotrecase', - 'Pleasant Valley', - 'Sabana Larga', - 'Madera Acres', - 'Altmunster', - 'Silvarpatti', - 'Khathjari', - 'Hawera', - 'Lobez', - 'Dangcheng', - 'Visselhovede', - 'Alamosa', - 'Bukowno', - 'Veppattur', - 'Kominato', - 'Lincoln City', - 'Magstadt', - 'Seysses', - 'Avon Park', - 'Chevy Chase', - 'Marathon', - 'Tiztoutine', - 'Trescore Balneario', - 'Bagnolo in Piano', - 'Bay St. Louis', - 'Alcarraz', - 'Choppington', - 'Chak That', - 'Bag', - 'El Roble', - 'Kippax', - 'Bamora', - 'Ghariyah al Gharbiyah', - 'Valpovo', - 'Kami-kawabe', - 'Gokceada', - 'Tottington', - 'Kotli Ablu', - 'Jhitkahiya', - 'Kiban', - 'Albert', - 'Alagarai', - 'Koini', - 'Terrace Heights', - 'Helston', - 'Rute', - 'Neshannock', - 'Sturovo', - 'Chom Thong', - 'Bueng Khong Long', - 'Ronda Alta', - 'Dodworth', - 'Charne', - 'Gangania', - 'Nueva Tolten', - 'Bavanat', - 'Muddanuru', - 'Biei', - 'Repatriacion', - 'Nallamadu', - 'Ramnagar Bankat', - 'Derazhnia', - 'Oulunsalo', - 'Miastko', - 'Figeac', - 'Stonegate', - 'Farako', - 'Manalurpettai', - 'Cittanova', - 'Urdorf', - 'Pakri', - 'Valantaravai', - 'Tesalia', - 'Pepinster', - 'Sugbongkogon', - 'Perket', - 'Karankot', - 'Garrison', - 'Puerto Tirol', - 'Zell am See', - 'Wolfersheim', - 'Loudeac', - 'Montemarciano', - 'Mahinathpur', - 'Keansburg', - 'Pluderhausen', - 'Camoluk', - 'Barracao', - 'El Molar', - 'Agatogba', - 'Wald', - 'Voreppe', - 'Kanchanpur', - 'Jaisinghnagar', - 'Kattagaram', - 'Green Cove Springs', - 'Ganguru', - 'Salkhua', - 'Fultondale', - 'Ncora', - 'Gaszowice', - 'Pobiedziska', - 'Ingre', - 'Erravaram', - 'Aramangalam', - 'Kolnur', - 'Xiba', - 'Oberstdorf', - 'Shepperton', - 'Pembroke Dock', - 'Gorom-Gorom', - 'Dhamsain', - 'Mesetas', - "Sant'Egidio alla Vibrata", - 'Grigiskes', - 'Tadla', - 'Wloszczowa', - 'Sankt Johann in Tirol', - 'Chegurumomadi', - 'Monmouth Junction', - 'Byalynichy', - 'Satuluru', - 'Ambinanintromby', - 'Ghabrah', - 'Dubliany', - 'Alayor', - 'Tsaramasoandro', - 'Liesveld', + 'Bella Vista', + 'Lufeng', + 'Lebach', + 'Wanda', + 'East Highland Park', + 'Phu Yen', + 'Masangshy', + 'Bou Sfer', + 'Kumirimora', + 'Shibushi', + 'Falticeni', + 'Wallington', + 'Bryn', + 'Dornstadt', + 'Sembe', + 'Onan', + 'Brandizzo', + 'Voerendaal', + 'Qaladizay', + 'Butwal', + 'Kunzell', + 'Dindanko', + 'Knezha', + 'Half Moon Bay', + 'Upleta', + 'Cambuslang', + 'Zupanja', + 'Ronse', + 'Seneca Falls', + 'Karlshamn', + 'Attippattu', + 'Terzigno', + 'Brumado', + 'Bangaon', + 'Szczecin', + 'Jauharabad', + 'Pisticci', + 'Gukeng', + 'Conceicao do Araguaia', + 'Saltash', + 'Parvomay', + 'Ban Wat Phrik', + 'Cabaiguan', + 'Awa', + 'Nemours', + 'Yukuhashi', + 'Bujari', + 'Jiwachhpur', + 'Rongwo', + 'Puerto Nare', + 'Anjomachi', + 'Lagbe', + 'Mickleover', + 'Mianyang', + 'Eshowe', + 'Bonnievale', 'Radekhiv', - 'Felpham', - 'Beius', - 'Hacari', - 'Urlaha', - 'Puerto Narino', - 'Dulce Nombre de Jesus', - 'Undavalli', - 'Dhanwada', - 'Andrainjato', - 'Fandrandava', - 'Ban Mae Chedi', - 'Basavilbaso', - "Skidal'", - 'Sirdala', - 'Hunasamaranhalli', - 'Ciudad Cuauhtemoc', - 'Ribeirao do Largo', - 'Bad Breisig', - 'Cobham', - 'Sedona', - 'Ain Karma', - 'Redentora', - 'Twist', - 'Darnetal', - 'Raynes Park', - 'Lykovrysi', - 'Murungattoluvu', - 'Birzebbuga', - 'Furstenau', - 'Osthofen', - 'Ghusiya', - 'Motipur', - 'Eagle Point', - 'Everswinkel', - 'Semmarikulan', - 'Calca', - 'Quiculungo', - 'Giesen', - 'Bou Nouh', - 'Kaithinia', - 'Non Sung', - 'Bom Jesus da Serra', - 'Gambolo', - 'Moyogalpa', - 'Alto Piquiri', - 'Kitee', - 'San Giorgio del Sannio', - 'Grand-Couronne', - 'Kusumha', - 'Hadiaya', - 'East Brandywine', - 'East St. Paul', - 'Nova Floresta', - 'Atlapadu', - 'Draganesti-Olt', - 'Chiang Klang', - 'Seforong', - 'Thomaston', - 'Vesele', - 'Karattuppalaiyam', - 'Elambalur', - 'Zahed Shahr', - 'Terralba', - 'Oudenburg', - 'Idanha-a-Nova', - 'Ledegem', - 'Tayakou', - 'Bareh', - 'Kakkat', - 'Tivim', - 'Aghbalou Aqourar', - 'Mahuver', - 'Carnaubais', - 'La Ferte-sous-Jouarre', - 'Panganiban', - 'Bondues', - 'Tellar', - 'Ingleside', - 'Estavayer-le-Lac', - 'Litovel', - 'Qahjavarestan', - 'Wijnegem', - 'Pine Lake Park', - 'Haraiya', - 'Oberhausen-Rheinhausen', - 'Aqadyr', - 'Lanskroun', - 'Kottampatti', - 'Sundarapandiyam', - 'Poggio Renatico', + 'Sagauli', + 'Ankirihitra', + 'University Park', + 'Punjai Lakkapuram', + 'Hamlin', + 'Feni', + 'Legnica', + 'Gandhali', + 'Deyang', + 'Scotts Valley', + 'North Ogden', + 'Tocantinopolis', + 'Princesa Isabel', + 'Weert', + 'Chos Malal', + 'West Odessa', + 'Mawanella', + 'Aljaraque', + 'Majhariya', + 'Nagayalanka', + 'Tring', + 'Lenox', + 'Kebila', + 'Fatehpur Bala', + 'Mucheln', + 'Sangolqui', + 'Gohadi', + 'Komaki', + 'Malaudh', + 'Coquitlam', + 'Florencia', + 'Kalisizo', + 'Eslamshahr', + 'Tychy', + 'Lazaro Cardenas', + 'Pallarimangalam', + 'Yang Talat', + 'Arsuz', + 'Bhavani', + 'Maniwa', + 'Santa Luzia do Itanhy', + 'Oranienburg', + 'Huangshi', + 'Zaranj', + 'Halver', + 'Areado', + 'Hadjadj', + 'Balykchy', + 'Effingham', + 'Valley Stream', + 'Pinhao', + 'West New York', + 'Heishanzuicun', + 'Bordentown', + 'Inirida', + 'La Huerta', + "Sant'Egidio alla Vibrata", + 'Dharapuram', + 'Ad Dulu`iyah', + 'Kaarina', + 'Rekovac', + 'Manitowoc', + 'Goroka', + 'Motul', + 'Narasingam', + 'Beckenham', + 'Kirkwood', + 'Kolondieba', + 'Pasadena', + 'Qo`ng`irot Shahri', + 'Winsen', + 'Mers el Kebir', + 'Poro', + 'Knjazevac', + 'Dajiecun', + 'Tangjin', + 'Karbinci', + 'Beykoz', + 'Amadeo', + 'Manamelkudi', + 'Tekanpur', + 'Busolwe', + 'Ac-cahrij', + 'Coroico', + 'Inhambane', + 'Jacinto', + 'Carlentini', + 'Skippack', + 'Federal', + 'Valenzano', + 'Zhangcun', + 'Loenen', + 'Muswellbrook', + 'Tamazunchale', + 'Moatize', + 'Port Salerno', + 'Lisbon', + 'Santo Estevao', + 'Irondequoit', + 'Levallois-Perret', + 'San Antonio Suchitepequez', + 'Zvecan', + 'Douar Lamjaara', + 'Winter Springs', + 'Bimawan', + 'Pentapadu Kasba', + 'Montijo', + 'Sena Madureira', + 'Virei', + 'Varzaneh', + 'Sariveliler', + 'Vatakemuri', + 'Machelen', + 'Nabunturan', + "Yong'ancun", + 'Dalsingh Sarai', + 'Etoumbi', + 'Funadhoo', + 'Antur', + 'Superior', + 'Matouying', + 'Abucay', + 'Kengarai', + 'Paterna', + 'Saqqez', + 'Spring Creek', + 'Garaimari', + 'Nan Zhuang', + 'Jones', + 'Bou Khadra', + 'Rosh Ha`Ayin', + 'Adalhat', + 'Capaya', + 'Kuruman', + 'Chaoyangdicun', + 'Villacarrillo', + 'South Portland', + 'Bambui', + 'Apalit', + 'Biddupur', + 'Baqiabad', + 'Kostanjevica na Krki', + 'Rechaiga', + 'Morwell', + 'Koundian', + 'Higashimiyoshi', + 'Castro', + 'At Tur', + 'Pirnagar', + 'Vandalia', + 'Nellipaka', + 'Zerong', + 'Goodlands', + 'Hatay', + 'Bielsko-Biala', + 'Grosse Pointe Woods', + 'Ajijic', + 'Dhanupra', + 'Pachrukha', + 'Handwara', + 'Ranopiso', + 'Vallenar', + 'Santa Maria do Suacui', + 'Loyalist', + 'Chinameca', + 'Mahazoma', + 'Silifke', + 'Falakata', + 'Ghordaur', + 'Black Forest', + 'Dale City', + 'Ranbirsinghpura', + 'Ibiassuce', + 'Tetagunta', + 'Pereiro', + 'Marmagao', + 'Amparihy', + 'Ereymentau', + 'Heishuikeng', + 'As Salt', + 'Los Patios', + 'Masyaf', + 'Ban Sai Yoi', + 'Abre Campo', + 'El Maknassi', + 'Rosaryville', + 'Dupax Del Norte', + 'Kosai', + 'La Queue-en-Brie', + 'Rasulpur', + 'Chelm', + 'Caserta', + 'Devmaudaldal', + 'Biancavilla', + 'Nilaiyur', + 'Budhanilkantha', + 'Weyburn', + 'Schertz', + 'Bela Simri', + 'Kimje', + 'Jerome', + 'Rangapuram', + 'Sandalpur', + 'Nea Erythraia', + 'Entebbe', + 'San Bartolome', + 'Al Karnak', + 'Estepona', + 'Lempdes', 'Zengjiaba', - 'Worpswede', - 'Lapanga', - 'Mentone', - 'Wakoro', - 'Vitorino', - 'Serris', - 'Douar Lehouifrat', - 'Tiruvengadam', - 'Harvard', - 'Kokologo', - 'Periyapuliyur', - 'Kannandahalli', - 'Vanipenta', - 'Goluchow', - 'Sovata', - 'Lovendegem', - 'Punnavalli', - 'Belsara', - 'Bararam', - 'Lake Mohawk', - 'Mount Evelyn', - 'Schwaikheim', - 'Pipra Dewas', - 'Atturkuppam', - 'Eksjo', - 'Poloros', - 'Purkersdorf', - 'Genemuiden', - 'Huari', - 'Chilanga', - 'Sirka', - 'Wadgira', - 'Tungavi', - 'Flowery Branch', - 'Mae Ai', - 'Imias', - 'Asuke', - 'Dassel', - 'Zafargarh', - 'Rombas', - 'Rolesville', - 'Aklim', - 'Pai Bigha', - 'Sant Julia de Loria', - 'Neu Bleckede', - 'Rhosllanerchrugog', - 'Kokoszki', - 'Dodoni', - 'Latteri', - 'Cypress Gardens', - 'White Horse', - 'Imam Sahib', - 'Talachyn', - 'Wittenbach', - 'Pakhtaobod', - 'Neves Paulista', - 'Gorgab', - 'Oostzaan', - 'Sigtuna', - 'Ban Bueng Kok', - 'Sidi Ahmed El Khadir', - 'Santamaguluru', - 'Mohdra', - 'Malhargarh', - 'Velakkuttai', - 'Raseiniai', - 'Guifoes', - 'Saint-Lys', - 'Porto Rafti', - 'Hoeselt', - 'Moravska Trebova', - 'Bohechio', - 'Eidson Road', - 'Savja', - 'Avalurpet', - 'Santo Tomas de los Platanos', - 'Saint-Vith', - 'Tanaina', - 'Stoneham-et-Tewkesbury', - 'Fuli', - 'Ventania', - 'Lentvaris', - 'Amritpur', - 'Klotze', - 'Benkovac', - 'Csorna', - 'Hyrum', - 'Alfred and Plantagenet', - 'Alberdi', - 'Grossrohrsdorf', - 'Borgo', - 'Pulluru', - 'Pondaluru', - 'Jibou', - 'Ak-Suu', - 'Thap Khlo', - 'Ban Kang', - 'Ingichka', - 'Brandis', - 'Makri', - 'Piprai', - 'Monki', - 'Lambeth', - 'Pindra', - 'Crosia', - 'Lurate Caccivio', - 'Ottappidaram', - 'Castellamonte', - 'Zoudjame', - 'Tuta', - 'Lindesberg', - 'Canonsburg', - 'San Gregorio Atzompa', - 'Pathari', - 'Inacio Martins', - 'Makhar', - "'Ain Leuh", - 'Donabate', - 'Tepetlan', - 'Valsequillo de Gran Canaria', - 'Villarrubia de los Ojos', - 'Parmanpur', - 'Laligam', - 'Bithauli', - 'Langar', - 'Manrar', - 'Oued Laou', - 'Huachipato', - 'Revel', - 'San Francisco la Union', - 'Cepin', - 'Orotina', - 'Pinos Puente', - 'Alesd', - 'Thepaha Raja Ram', - 'Reddippatti', - 'Pareo', - 'Palafolls', - 'Karimpur', - 'Kishanpura Kalan', - 'San Juan del Puerto', - 'Kadriye', - 'La Farlede', - 'Dundankop', - 'Byarozawka', - 'Bradwell', - 'Dahua', - 'Masku', - 'Talapalli', - 'Salmanshahr', - 'Jucurucu', - 'Arques', - 'Inverell', - 'Bni Boufrah', - 'Barahbatta', - 'Merville', - 'Dandkhora', - 'Pike Road', - 'Palmares Paulista', - 'Sallaumines', - 'Tiruvambalapuram', - 'Konidena', - 'Silver City', - 'Comala', - 'Nova Bassano', - 'Dhorgaon', - 'Sangonera la Verde', - 'University of Virginia', - 'Tuam', - 'Simrol', - 'Le Muy', - 'Countryside', - 'Mont-Tremblant', - 'Saint-Doulchard', - 'Ikkarai Boluvampatti', - 'Delcevo', - 'Tirua', - 'Akabira', - 'Glenfield', - 'Nanjundapuram', - 'Kataha', - 'Torihama', - 'Ban Dong Mada', - 'Immingham', - 'Beltangadi', - 'Ban Lao Yao', - 'Fron', - 'Willow Street', - 'Pereshchepyne', - 'Bendrahalli', - 'Piploda', - 'Kathurah', - 'San Lorenzo della Costa', - 'Adamankottai', - 'Nueva Esparta', - 'Bhagsar', - 'Broni', - 'Argelato', - 'Orange Cove', - 'Veitshochheim', - 'Racconigi', - 'Dombasle-sur-Meurthe', - 'Brewer', - 'Monett', - 'Morehead City', - 'Madari Hat', - 'Dobre Miasto', - 'El Haouaria', - 'Banska Stiavnica', - 'Bochaha', - 'Kudowa-Zdroj', - 'Pinhel', - 'Itasca', - 'Armutlu', - 'Uracoa', - 'Gundi', - 'Nambutalai', - 'Colonia Nicolich', - 'Kauniainen', - 'Selfoss', - 'Kushijima', - 'St. Stephens', - 'Campo Ere', - 'Aweitancun', - 'Sigatoka', - 'Bernay', - 'Sabangan', - 'Caldas de Reyes', - 'Anantpur', - 'Sturgeon Bay', - 'Saint-Remy-de-Provence', - 'Bluefield', - 'Port Elgin', - 'Nowy Dwor Gdanski', - 'Flexeiras', + 'Lipkovo', + 'Buckingham', + 'Bevoay', + 'Sokouhoue', + 'Tecklenburg', + 'Bochum', + 'San Luis Talpa', + 'Ijui', + 'Woodlyn', + 'Capivari', + 'Purna', + 'Bayugan', + 'Imbert', + 'Durgauti', + 'Belen de los Andaquies', + 'Menghan', + 'Gangapur Athar', + 'Inza', + 'Tiaong', + 'Cagliari', + 'Inverness', + 'Ciudad Sahagun', + 'Gerakas', + 'Vubatalai', + 'Ratauli', + 'Catalao', + 'Telsen', + 'Secovce', + 'Sirugamani', + 'Lake Norman of Catawba', + 'Vevey', + 'Quakers Hill', + 'Struga', + 'Amarwara', + 'Mont-Saint-Martin', + 'Nova Crnja', + 'Hirehalli', + 'Ablu', + 'Llavallol', + 'El Almendro', + 'Ad Darwa', + 'Bietigheim-Bissingen', + 'Ul', + 'Indianola', + 'Ankisabe', + 'Minster', + "Wik'ro", + 'Barapire', + 'A Yun Pa', + 'Retirolandia', + 'Shahkot', + 'Itaberaba', + 'Pilappulli', + 'Coesfeld', + 'Azare', + 'Dix Hills', + 'Nazira', + 'Velen', + 'Mnichovo Hradiste', + 'Cedar City', + 'Bofete', + 'Haiphong', + 'Tokmok', + 'Goianapolis', + 'Texas City', + 'Marakkara', + 'Cameli', + 'Lundazi', + 'Antanambaobe', + 'Akhmim', + 'Abhayapuri', + 'Saint-Philbert-de-Grand-Lieu', + 'Lutterworth', + 'Vinci', + 'Kidlington', + 'Sao Joao', + 'Leopold', + 'Vigevano', + 'Croix-des-Bouquets', + 'Zele', + 'Ibateguara', + 'West Lealman', + 'Taran', + 'Pingshang', + 'Douar Ait Sidi Daoud', + 'San Martin', + 'Bajram Curri', + 'Fouesnant', + 'Hosbach', + 'Jiamusi', + 'Mendi', + 'Gennevilliers', + 'Suramala', + 'Lambunao', + 'Guatuba', + 'Hassi Bahbah', + 'Mineral del Monte', + 'Menglie', + 'Chitarpur', + 'Cristopolis', + 'Ad Diwem', + 'Tocopilla', + 'Calella', + 'Bedwas', + 'Sarur', + 'Wuhai', + 'Flero', + 'Jork', + 'Juma Shahri', + 'Hawtat Sudayr', + 'Viyapuram', + 'La Nucia', + 'Chalhuanca', + '`Utaybah', + 'Ilkley', + 'Bloomfield', + 'Dobhawan', + 'Chempalli', + 'Tipo-Tipo', + 'Risch', + 'Marosangy', + 'Kirchheim bei Munchen', + 'Ubaira', + 'Maragondon', + 'Al `Aydabi', + 'Lamia', + 'Chippewa Falls', + 'Ora', + 'Androy', + 'Valle del Guamuez', + 'Sykies', + 'Barahari', + 'Peters', + 'Naxcivan', + 'Anderlues', + 'Doraville', + 'Banaue', + 'Eersel', + 'Ganapatipalaiyam', + 'Bernal', + 'Tole Bi', + 'Badiangan', + 'Newry', + 'Boom', + 'Baguineda', + 'Thulusdhoo', + 'Kanniyakumari', + 'Ramagiri Udayagiri', + 'Tangjiacun', + 'Naranattenvanpatti', + 'Megarine', + 'Angallu', + 'Yeni Suraxani', + 'Gudimulakhandrika', + 'Port-Alfred', + 'Bantval', + 'Banska Bystrica', + 'Ratanpur', + 'Sihui', + 'Ambohimangakely', + 'Mineshita', + 'San Rafael', + 'Bhambia Bhai', + 'Nauheim', + 'Russellville', + 'Naushahro Firoz', + 'Sarvestan', + 'Pagalungan', + 'Carsibasi', + 'Emirgazi', + 'Ciudad Rio Bravo', + 'Proddatur', + 'Bruz', + 'Bartlett', + 'Yeadon', + 'Timbedgha', + 'Rishton', + 'Thaba-Tseka', + 'Pappampatti', + 'Alianca', + 'Skowhegan', + 'Gongzhuling', + 'Port Arthur', + 'Budingen', + 'Vallam', + 'Agios Ioannis Rentis', + 'Birine', + 'Quirino', + 'Honeygo', + 'Usulutan', + 'Abram', + 'Taranto', + 'Tyrnavos', + 'Nagongera', + 'Farsan', + 'Santa Rita', + 'Bueno Brandao', + 'Amingarh', + 'Port Loko', + 'Hellevoetsluis', + 'Surigao', + 'Pattamadai', + 'Balsas', + 'Matipo', + 'Onitsha', + 'Strasshof an der Nordbahn', + 'Rochefort', + 'Doral', + 'Limoeiro', + 'Ambalanjanakomby', + 'Cohoes', + 'Jaguaruana', + 'Vadakethara', + 'Prospect Heights', + 'Bonita', + 'Jarvenpaa', + 'Baj Baj', + 'Alamadi', + 'Nanzhou', + 'Sanatoga', + 'Arruda dos Vinhos', + 'Malapatan', + 'Soroti', + 'Dargahan', + 'Meze', + 'Pemangkat', + 'Dinagat', + 'Villemomble', + 'Donetsk', + 'Viru', + 'Dazhangzicun', + 'Vigneux-sur-Seine', + 'Amolatar', + 'Nemili', + 'Nagykanizsa', + 'Kedgaon', + 'Boumia', + 'Guisa', + 'Maur', + 'Saint-Laurent-du-Maroni', + 'Chenggong', + 'Rengali', + 'Bacau', + 'Kaunra', + 'Ballyfermot', + 'Aurahi', + 'Perito Moreno', + 'Shetang', + 'Suwon', + 'Virappanchathiram', + 'Celje', + 'Turhal', + 'Taquari', + 'Ikot Ekpene', + 'Allinagaram', + 'Bolintin Vale', + 'Maga', + 'Kolnad', + 'Sori', + 'Totoro', + 'San Rafael Obrajuelo', + 'Alayaman', + 'Ouani', + 'Tadla', + 'Pirque', + 'Cuxhaven', + 'Zhongzai', + 'Aliwal North', + 'Plum', + 'Saint Helier', + 'Dongcha', + 'Gokarn', + 'Sassandra', + 'Balneario do Rincao', + 'Kafr Buhum', + 'Hlukhiv', + 'Sandacho', + 'Arizona City', + 'Silamalai', + 'Mohanpur', + 'Diaobingshancun', + 'Ratekau', + 'Halgar', + 'Albertville', + 'Gadani', + 'Ascheberg', + 'Godda', + 'Tangdong', + 'Sholinghur', + 'Zuidlaren', + 'Jadopur Shukul', + 'Ekalbehri', + 'Puerto Plata', + 'Ambatturai', + 'Masanwa', + 'Crystal', + 'Dasungezhuang', + 'Eenhana', + 'Xiangtan', + 'Arbon', + 'Jerez de la Frontera', + 'Barkagaon', + 'Sumter', + 'Maroochydore', + 'Rach Gia', + 'Mirna Pec', + 'St. John', + 'Medianeira', + 'Muqui', + 'Farah', + 'Dedougou', + 'Manduri', + 'Monserrat', + 'Myrnohrad', + 'Segbana', + 'Gelnhausen', + 'Chuanliaocun', + 'Reshetylivka', + 'College Station', + 'Wum', + 'Imst', + 'Kumar Khad', + 'Bjarred', + 'Ambatofisaka II', + 'Nocatee', + 'Kanel', + 'Philipstown', + 'Torrevieja', + 'Frankfort Square', + 'Gudur', + 'Oak Grove', + 'Santana', + 'Polukallu', + 'Kanhai', + 'Trapani', + 'Sanchez-Mira', + 'Wangtuan', + 'Punta del Este', + 'Zevenaar', + 'Ban Tha Pha', + 'Sainte-Marie', + 'Karonga', + 'Cremlingen', + 'Ramallah', + 'Gatumba', + 'Caowotan', + 'Tomah', + 'Lorraine', + 'Odumase', + 'Amritsar', + 'Vlasim', + 'Yangcunzai', + 'Prataparampuram', + 'Indurti', + 'Tanjay', + 'Brzeg', + 'Manthani', + 'Passa Quatro', + 'Dallas', + 'Chinnatadagam', + 'Roxborough Park', + 'Ban Wang Pradu', + 'Were Ilu', + 'Tourcoing', + 'Shimokizukuri', + 'Dehui', + 'Ithaca', + 'Hamtic', 'Saint-Zotique', - 'Tadhwa Nandpur', - 'Babhantoli', - 'South Strabane', - 'Widnau', - 'Sudlohn', - 'Grado', - 'Neuville-les-Dieppe', - 'Hockley', - 'Datori', - 'Caernarfon', - 'Boves', - 'Saint-Raymond', - 'Oulad Imloul', - 'Kfar Aabida', - 'Wladyslawowo', - 'Ohrdruf', - 'Masar', - 'Bowen', - 'Alcanar', - 'Epalinges', - 'Nersingen', - 'Fernan-Nunez', - 'Gandlapenta', - 'Agareb', - 'Tila', - 'Cuprija', - 'Izium', - 'Muyinga', - 'Thogaduru', - 'Kirlampudi', - 'Cuellar', - 'Herkimer', - 'Mortagua', - 'Dasso', - 'Yazikonak', - 'Postojna', - 'Dessel', - 'Sannicandro di Bari', - 'Sandy Hook', - 'Branquinha', - 'Guateque', - 'Bhawanandpur', - 'Nakaechi', - 'Gibsons', - 'Eschenbach', - 'North College Hill', - 'Jessup', - 'Swanage', - 'Hindoli', - 'Nurobod Shahri', - 'Yarm', - 'Hemau', - 'Khesht', - 'Oil City', - 'Hartland', - 'Yalaguina', - 'Targu Frumos', - 'Sofiivka', - 'Balsamo', - 'Hlinsko', - 'Petua', - 'Has', - 'Dobhawan', - 'Szigetvar', - 'Xicotencatl', - 'Ban Nam Dip Luang', - 'Hochberg', - 'Gonikoppal', - 'Chavuttahalli', - 'Trzebiatow', - 'Chilpur', - 'Ferros', - 'Beaumont-sur-Oise', - 'Kudayattur', - 'Agoue', - 'Cavalcante', - "'Ain Kihal", - 'Soanpeta', - 'Jacinto City', - 'Leers', - 'Majali', - 'Wiang Sa', - 'Sulibele', - 'Casaluce', - 'Grimmen', - 'Sarahs', - 'Luchow', - 'Aire-sur-la-Lys', - 'Pachhapur', - 'Banaso', - 'Wielsbeke', - 'Ratnahalli', - 'Puduppattanam', - 'Cingoli', - 'Bou Zemou', - 'Shiyuan', - 'Ramree', - 'Rellivalasa', - 'Talavadi', - 'Osterburg', - 'Bunol', - 'Perumbalai', - 'Pagidyala', - 'Avanashipalaiyam', - 'Lizzano', - 'Bourg-de-Peage', - 'Aytre', - 'Vasilika', - 'New Square', - 'Saint-Sulpice-la-Pointe', - 'Nagathan', - 'Photharam', - 'Lago Ranco', - 'Schulzendorf', - 'Bladensburg', + 'Mossendjo', + 'Ban Bo Phlap', + 'Arar', + 'Meekatharra', + 'Ghouazi', + 'Amora', + 'Yongji', + 'Nurtingen', + 'Pantar', + 'Yantai', + 'Shamli', + 'Sidi Kasem', + 'League City', + 'Ylojarvi', + 'Chakpi Karong', + 'Lehman', + 'Gunzenhausen', + 'Pirpirituba', + 'Titz', + 'Vynnyky', + 'Nicolas Romero', + 'Tekit', + 'Prinzapolka', + 'Nueva Esparta', + 'Hedongcun', + 'Lobougoula', + 'Socuellamos', + 'East Hemet', + 'Sebiston', + 'Ban Laem', + 'Mukono', + 'Mineiros do Tiete', + 'Warrnambool', + 'Normandia', + 'Monte Alegre', + 'Volda', + 'Yasothon', + 'Kearny', + 'Kahan', + 'Mihqan', + 'Playa Vicente', + 'Shimoga', + 'Konseguela', + 'Outapi', + 'Layton', + 'Brock Hall', + 'Kilsyth', + 'Al Mukalla', + 'Dhamtari', + 'Alijo', + 'Alacuas', + 'Higashiizu', + 'Lopez', + 'Ta`izz', + 'Corato', + 'Chuhuiv', + 'Albacete', + 'Gundumal', + 'Sidi Embarek', + 'Calais', + 'Camapua', + 'Portogruaro', + 'Bad Langensalza', + 'Tecolotlan', + 'Roseburg', + 'Saint-Jerome', + 'Sandila', + 'Coldwater', + 'Zhongcun', + 'Westonaria', + 'Pattanam', + 'Guihulngan', + 'Phaphot', + 'Huili Chengguanzhen', + 'Mabinay', + 'Bothell East', + 'Banavar', + 'Nallippalaiyam', + 'Quetigny', + 'Tsuno', + 'Geiro', + 'Zarrin Shahr', + 'Balpyq Bi', + 'San Antonio Oeste', + 'Krasnohorivka', + 'Bled', + 'Ama', + 'Lototla', + 'Azzano', + 'Ivai', + 'Mitanty', + 'Calicut', + 'Chelghoum el Aid', + 'Kitee', + 'Koffiefontein', + 'Fair Oaks Ranch', + 'Sao Marcos', + 'Disuq', + 'Bouzeghaia', + 'Hudson', + 'Fortuna Foothills', + 'Raska', + 'Rafah', + 'Birsfelden', + 'Loon', + 'Ivrindi', + 'Pacho', + 'Sasaguri', + 'Oroville', + 'Odiongan', + 'Bagua Grande', + 'Dera Ghazi Khan', + 'Moorslede', + 'Pilkha', + 'Kalar', + 'Odawara', + 'Monte Belo', + 'Ludwigsfelde', + 'Lopary', + 'Boriguma', + 'Storrs', + 'Khrystynivka', 'Villa Aldama', - 'Petrolina de Goias', - 'Ezanville', - 'Cuervos', - 'Fauske', - 'Ban Wiang Ka Long', - 'Parur', - 'Sarmera', - 'Cesa', - 'Aiea', - 'Sanampudi', - 'Gawan', - 'Ittikelakunta', - 'Mae Rim', - 'Mizhhiria', - 'Kochgawan', - 'Oulad Ayyad', - 'Karczew', - 'Miltenberg', - 'Nandamuru', - 'Topsham', - 'McKee City', - 'Bilozerka', - 'Daulatpur', - 'Girard', - 'West Glens Falls', - 'Sitebe', - 'Erdokertes', - 'Parsons', - 'Szubin', - 'Maliano', - 'Savignano sul Panaro', - 'Sorbolo', - 'Borogani', + 'Sirali', + 'Bulwell', + 'Vadacheri', + 'Aytre', + 'Kwidzyn', + 'Furukawa', + 'Sukand', + 'Esquimalt', + 'Caraubas', + 'Antsohimbondrona', + 'Waltham Abbey', + 'Sagua la Grande', + 'Taulaha', + 'Roslyn', + 'Hale Dyamavvanahalli', + 'Cortona', + 'Minnal', + 'Brunoy', + 'Kunisakimachi-tsurugawa', + 'Rincao', + 'Golden Glades', + 'Matsuda-soryo', + 'Pirauba', + 'Ghriss', + 'Mopipi', + 'Chateauroux', + 'Chortkiv', + 'Theniet el Had', + 'Balkh', + 'Casalecchio di Reno', + 'Guacimo', + 'Arona', + 'Novaci', + 'Diakon', + 'Taunusstein', + 'Sawangan', + 'Jigani', + 'Parabita', + 'Candaba', + 'Jardim Alegre', + 'Berovo', + 'Cascina', + 'Ambohijanaka', + 'Sao Tome', + 'Cleethorpes', + 'Kalmunai', + 'Vaslui', + 'Fort William', + 'Bolobo', + 'Sanlucar la Mayor', + 'El Hajeb', + 'Quesnel', + 'Leuwiliang', + 'Caraibas', + 'Sugaon', + 'Villers-Cotterets', + 'Santamesa', + 'Santa Teresinha', + 'Anosibe-Ifanja', + 'Agarpur', + 'Kutavettur', + 'Itapetinga', + 'Lubsko', + 'Banbalah', + 'Tala', + 'Arcachon', + 'Muturkha', + 'Miyazu', + 'Akcadag', + 'Castaic', + 'Xindian', + 'Los Hidalgos', + 'Kekava', + 'Jacala', + 'Lapseki', + 'Cartaxo', + 'Londerzeel', + 'Ermua', + 'Ipiranga', + 'Trat', + 'Guiglo', + "Sant'Antioco", + 'Linton Hall', + 'Huaiyin', + 'San Salvador de Jujuy', + 'Ksour Essaf', + 'El Quisco', + 'Central', + 'Muttupet', + 'Juan de Herrera', + 'Qaryat Suluq', + 'Kressbronn am Bodensee', + 'Kall', + 'Thingangyun', + 'Lauf', + 'Villa de Alvarez', + 'Sipacate', + 'Andirin', + "Cournon-d'Auvergne", + 'Bhayandar', + 'Borongan', + 'Meerane', + 'Pekanbaru', + 'Szczytno', + 'Obu', + 'Chinnalapatti', + 'Angalakurichchi', + 'Caldas de Montbuy', + 'Altata', + 'Sonepur', + 'Benisa', + 'San Lucas Toliman', + 'Japeri', + 'Ecublens', + 'Kowloon', + 'Ivancna Gorica', + 'Bougzoul', + 'Jelcz-Laskowice', + 'Engenheiro Beltrao', + 'Stonecrest', + 'Cheltenham', + 'Ospino', + 'Qingdao', + 'Port Lavaca', + 'Weichanglu', + 'Gudiyattam', + 'Fujikawa', + 'Bamhni', + 'Porterville', + 'El Khemis des Beni Chegdal', 'Surany', - 'Baretha', - 'Perols', - 'Chansolme', - 'Kayyngdy', - 'Xiada', - 'Adesar', - 'Mianpur Dubauli', - 'Koranampatti', - 'Traversetolo', - 'Lititz', - 'Palankottai', - 'Bisaria', - 'Zymohiria', - 'Paranacity', - 'Vares', - 'Parauli', - 'Virapandiyanpattanam', - 'Rathdrum', - 'Pine Castle', - 'Lower Swatara', - 'Basse-Goulaine', - 'Kamargani', - 'Velyka Dymerka', - 'Boxley', - 'Vemulanarva', - 'Wepener', - 'Lincoln Village', - 'Port Perry', - 'Bad Gandersheim', - 'Nazira', - 'Sevilla La Nueva', - 'Kondaparti', - 'Fontoura Xavier', - 'Ekalbehri', - 'Vardhamankota', - 'Teixeira Soares', - 'Gobindpura', - 'Dakpatthar', - 'Kannulu', - 'Sangi', - 'Boulder Hill', - 'Fitampito', - 'Salehpur', - 'Arrapalli', - 'Matawan', - 'Mahomet', - 'Elizabethtown-Kitley', - 'Harding', - 'Cunday', - 'Thikri', - 'Dabhaura', - 'Naruar', - 'Paso Canoas', - 'Kadikoy', - 'Rauco', - 'Berchha', - 'Ramasingavaram', - 'Gangadhar', - 'Bjarred', - 'Lorgues', - 'Lototla', - 'Nieuw-Lekkerland', - 'Dodarasinakere', - 'Conselice', - 'Ehringshausen', - 'El Cacao', - 'Capitan Mauricio Jose Troche', - 'Chaplynka', - 'Hohenhameln', - 'Kanhai', - 'Udburu', - 'Listowel', - 'Kakamas', - 'Mezobereny', - 'Khundawandpur', - 'Volterra', - 'Bethel', - 'Jinshui', - 'Mama Khel', - 'Newburn', - 'Le Rheu', - 'Navani', - 'Ekhari', - 'Khaspur', - 'Wilkau-Hasslau', - 'Colmenarejo', - 'Jalkaura', - 'Bohemia', - 'Chanal', - 'Piedras Blancas', - 'Barskoon', - 'Menzel Kamel', - 'Jianshi', - 'Crosne', - 'Kaikaram', - 'Vatakemuri', - 'Rampur Rajwa', - 'Crystal Beach', - 'Tounfafi', - 'Pagqen', - 'Pedra Badejo', - 'Somvarpet', - 'Yamakita', - 'Falam', - 'Santa Rosa del Penon', - 'Psychiko', - 'Mallampalli', - 'Xinpi', - 'Meridianville', - 'Tatoufet', - 'Barwadih', - 'Castel Bolognese', - 'Tomah', - 'Ankadimanga', - 'Sroda Slaska', - 'Lescar', - 'Cuorgne', - 'Esopus', - 'Atari', - 'Sebnitz', - 'Tadworth', - 'Zawyat Sidi Ben Hamdoun', - 'Eurajoki', - 'Manbazar', - 'Valaiyampattu', - 'Bargersville', - 'Aguia Branca', - 'Cape Elizabeth', - 'Puigcerda', - 'Steger', - 'Tlahualilo de Zaragoza', - 'Basco', - 'Shevington', - 'Smiths Falls', - 'Worsborough', - 'Castelfranco di Sopra', - 'Seybaplaya', - 'Sztum', - 'Janapul', - 'Adivala', - 'Bni Gmil', - 'Salcea', - 'Byureghavan', - 'Ban Nong Tong', - 'Sabaoani', - 'Kalladai', - 'Grinnell', - 'Oosterwolde', - 'Manchenahalli', - 'Rampur Parhat', - 'Hohr-Grenzhausen', - 'Nagyatad', - 'Khagam', - 'Vandam', - 'London Colney', - 'Trovagunta', - 'Amityville', - 'Elhovo', - "Vaprio d'Adda", - 'Bougou', - 'Kujri', - 'Anjukulippatti', - 'Garlasco', - 'Wagner', - 'Dhantola', - 'Arenapolis', - 'Hickam Housing', - 'Lorraine', - 'Douar Messassa', - 'Muh Hasan', - 'Sonsoro', - 'Luckau', - 'San Sebastian de la Gomera', - 'Bisignano', - 'Ngaparou', - 'Tambura', - 'Bulisa', - 'Jingjiazhuang', - 'Bagor', - 'Nathana', - 'Ranigaon', - 'Mangrawan', - 'Iowa Colony', - 'Dagbe', - 'Grosshansdorf', - 'South Abington', - 'Fochville', - 'Gaada', - 'Muddada', - 'Ilami', - 'Devmaudaldal', - 'Oakwood', - 'Pedro Luro', - 'Saldus', - 'Sokotindji', - 'Tixter', - 'Baghduma', - 'Kanchanadit', - 'Emsworth', - 'Kaithwar', - 'Valtoha', - 'Saltsjobaden', - 'Madhuban Bediban', - 'Nea Artaki', - 'Karath', - 'Mehdipur', - 'Astorp', - 'Ramara', - 'Maizal', - 'Llantwit Major', - 'Narayanraopet', - 'Caracuaro', - 'Hesarghatta', - 'Malaudh', - 'Katigang', - 'Nadimpalem', - 'Lucon', - 'Deh-e Shu', - 'Ekchari', - 'Viralimalai', - 'Tamentit', - 'Tepperumalnallur', - 'Durgi', - 'Saumalkol', - 'Pryor Creek', - 'Corella', - 'Cherniakhiv', - 'The Village', - 'Periya Pattanam', - 'Columbia City', - 'Ilsenburg', - 'Quincy-sous-Senart', - 'Bimun', - 'Molagavalli', - 'Santa Maria Jacatepec', - 'Highfields', - 'Senmanat', - 'Leguevin', - 'Foix', - 'Malaimachchampatti', - 'Israna', - 'Ban Krot', - 'Sundarsi', - 'Notre-Dame-des-Prairies', - 'Puszczykowo', - 'Wertingen', - 'Bewdley', - "Anan'evo", - 'Helena-West Helena', - 'Berkine', - 'Molbergen', - 'Cervello', - 'Elurpatti', - 'Asahni', - 'Vallet', - 'Kemberg', - 'Rafelbunol', - 'Marne', - 'Alawalpur', - 'Woodfield', - 'Casca', - 'Toging am Inn', - 'Cherasco', - 'Leeds and the Thousand Islands', - 'Denyekoro', - 'Nehoiu', - 'Uppur', - 'Koufalia', - 'Halen', - 'Quixabeira', - 'Inole', - 'Bridge City', - 'Syurte', - 'Nyzhnohirskyi', - 'Cambira', - "Saint-Barthelemy-d'Anjou", - 'Saint-Amand-Montrond', - 'Legnaro', - 'Runkel', - 'Hohenmolsen', - 'Frouzins', - 'Tabernes Blanques', - 'Mareno di Piave', - 'El Amim', - 'Burela de Cabo', - 'Ban Sathan', - 'Cervera', - 'Gold', - 'Kranidi', - 'Kerap', - 'Shahrak-e Ja`fariyeh', - 'Dolianova', - 'Laurentian Valley', - 'Nittenau', - 'Idumbavanam', - 'Bijeraghogarh', - 'Narsingi', - 'Guney', - 'Khawad', - 'Erikolam', - 'Kadanadu', - 'Cicevac', - 'Negrine', - 'South Normanton', - 'Killamarsh', - 'Tissaf', - 'Kommuru', - 'Gonghaur', - 'Novi Banovci', - 'Dachengzicun', - 'Jisrayn', - 'Deruta', - 'Tavarede', - 'Raitar', - 'Monnickendam', - 'Jantho', - 'Eunice', - 'Rorschach', - 'Tarmount', - 'Dhanga', - 'Kankanalapalle', - 'Adolfo Gonzales Chaves', - 'Cosne sur Loire', - 'Bezliudivka', - 'Pipra', - 'Assi-Ben Okba', - 'Anaconda', - 'Tissint', - 'Ban Bang Phlap', - 'Villacanas', - 'Danesfahan', - 'Borovskoy', - 'Banikane', - 'San Juanito de Escobedo', - 'Villa Canas', - 'Wiener Neudorf', - 'Chewara', - 'Elne', - 'Olivares', - 'Harlakhi', - 'Rasol', - 'Ghosrawan', - 'Saidoke', - 'Huinca Renanco', - 'Braslaw', - 'Medleri', - 'Madeira', - 'Ban San Pong', - 'Abra Pampa', - 'Segorbe', - 'Lerici', - 'Dubrovytsya', - 'Mohelnice', - 'Khanpur Khairanti', - 'Bairiya', - 'Hertzogville', - 'Odobesti', - 'Ahus', - 'Soubakaniedougou', - 'Sabinanigo', - 'Elurupadu', - 'Lugoff', - 'Carneirinho', - 'Teisendorf', - 'Brockworth', - 'Dibraghani', - 'Vadakethara', - 'Ghanipur Bejha', - 'Fishersville', - 'Sidi El Hattab', - 'Basni', - 'Mono', - 'Ipiranga do Piaui', - 'Tocina', - 'Budalur', - 'Anjehalli', - 'Naurhiya', - 'Andergrove', - 'Embrach', - 'Radstock', - 'Sadiqpur Maraul', - 'Bendarhalli', - 'Simarbani', - 'Sivamalai', - 'Glenshaw', - "Estrela d'Oeste", - 'Carqueiranne', - 'Rochelle', - 'San Francisco Libre', - 'An Chau', - 'Jawasa', - 'Bobil', - 'Sarpamari', - 'Nirna', - 'Barga', - 'Coral Hills', - 'Bystrzyca Klodzka', - 'Iawar', - 'Khari', - 'Cavriglia', - 'Aschheim', - 'Arenys de Munt', - 'Halacho', - 'Ngoc Son', - 'Sa Pa', - 'Muhammadganj', - 'Dharir', - 'Ostroda', - 'Dunblane', - 'Kallayi', - 'Gumusova', - 'Benbutucun', - 'Kurort Steinbach-Hallenberg', - 'Orivesi', - 'San Giovanni in Marignano', - 'Anisio de Abreu', - 'Siano', - 'Bellinzago Novarese', - 'Chahar Borj-e Qadim', - 'Elmas', - 'Flossmoor', - 'Hani i Elezit', - 'Voitsberg', - 'Danau Kandimarg', - 'Ramdeora', - 'Mechanicsburg', - 'Cusseta', - 'Mutis', - 'Thames Ditton', - 'Hayle', - 'Ramkali', - 'Recco', - 'Woodway', - 'Dushanove', - 'Pettampalaiyam', - 'Uppalaguptam', - 'Piombino Dese', - 'Kapelle-op-den-Bos', - 'Makamba', - "Conde-sur-l'Escaut", - 'Pokotylivka', - 'Negrete', - 'Taisar', - 'Hazrat Shiura', - 'Denham Springs', - 'Hsenwi', - 'Novopskov', - 'Resana', - 'Magnago', - 'Cetraro', - 'Sint Willebrord', - 'Capriolo', - 'Gammasa', - 'Tazarka', - 'Saint-Philbert-de-Grand-Lieu', - 'Kose', - 'Narpes', - 'Jamunamukh', - 'Vempatti', - 'Ja`fariyeh', - 'Mhajar', - 'Magny-les-Hameaux', - 'Ukwa', - 'Gaurdah', - 'Cutro', - 'Horsell', - 'Middlesborough', - 'Kungsangen', - 'Kadimetla', - 'Grigoriopol', - 'Nepi', - 'Curepto', - 'Saint-Jean-le-Blanc', - 'Raunds', - 'Marvast', - "Sao Jorge d'Oeste", - 'Nove Mesto nad Metuji', - 'Salzhemmendorf', - 'Jhabrera', - 'Sarakkayhalli', - 'Cermenate', - 'Kharagbani', - 'Kakarati', - 'Dymka', - 'Umbrete', - 'San Giorgio di Piano', - 'Rangapuram', - 'Jarville-la-Malgrange', - 'Tirubhuvane', - 'Helena Valley Southeast', - 'Topoloveni', - 'Le Passage', - 'Broadwater', - 'Pumalakkundu', - 'Bakharia', + 'Knurow', + 'Znamianka', + 'Huntersville', + 'El Eulma', + 'Bungoma', + 'Al Kharjah', + 'Rivesaltes', + 'Denzlingen', + 'Pul-e Khumri', + 'Niedernhausen', + 'Nova Floresta', + 'Cazin', + 'Virginia Beach', + 'Cassino', + 'Finnentrop', + 'Khajuri', + 'Cotabato', + 'Mahamaibe', + 'Aksu', + 'Campbellton', + 'Panay', + 'Otofuke', + 'Sarria', + 'Oklahoma City', + 'Waggaman', + 'Powdersville', + 'Ambongamarina', + 'Mirpur Khas', + 'Jamhor', + 'Florham Park', + 'Seram', + 'Senda', + 'Mancha Real', + 'Mint Hill', + 'Eggenstein-Leopoldshafen', + 'Bachhraon', + 'Friern Barnet', + 'Toboso', + 'Caledonia', + 'Dawley', + 'Bataredh', + 'Podenzano', + 'Hemiksem', + 'Pielisjarvi', + 'Pursa', + 'Marsabit', + 'Malar', + 'Tabubil', + 'White Meadow Lake', + 'Winter Garden', + 'Ryuo', + 'Jequie', + 'Ravar', + 'Gudalur', + 'Yenisehir', + 'Brookings', + 'Hamtramck', + 'Orizona', + 'Saint-Ouen', + 'Wietze', + 'Hwange', + 'Barentu', + 'Yedappalli', + 'Caucagua', + 'Gudensberg', + 'New Hope', + 'Benaguacil', + 'Aymangala', + 'Waltham', + 'Horndean', + 'Torquay', + 'Amulung', + 'Woolwich', + 'Sentjur', + 'Gondauli', + 'Krosno', + 'Nagasaki', + 'Luebo', + 'Sogutlu', + 'Valle de Santiago', + 'Ranzan', + 'Chachoengsao', + 'Golpayegan', + 'Mocuba', + 'Warrington', + 'Yercaud', + 'Capinzal', + 'Paullo', + 'Ozark', + 'Kargahia Purab', + 'Villanueva', + 'Jbabra', + 'Chunar', + 'Likiskiai', + 'Al Husayniyah', + 'Rockcreek', + 'Chichicastenango', + 'Siasi', + 'Beni Zouli', + 'Saint-Hilaire-de-Riez', + 'Devgeri', + 'Arniya', + 'Dennis', + 'Bopa', + 'East Norriton', + 'Marancheri', + 'Kalghatgi', + 'Andkhoy', + 'Dinanagar', + 'Kaifeng Chengguanzhen', + 'Jieshangya', + 'Yima', + 'Gamu', + 'Safashahr', + 'Pervari', + 'Agoue', + 'Presidente Franco', + 'Bad Homburg', + 'Taveta', + 'Croxley Green', + 'Bani', + 'Liberal', + 'Santa Maria de Ipire', + 'Hranice', + 'Mery-sur-Oise', + 'Ipupiara', + 'Takanabe', + "G'allaorol Shahri", + 'Syke', + 'Sembabule', + 'Kenley', + 'Bishnah', + 'Santa Lucia Milpas Altas', + 'Ahfir', + 'Virudunagar', + 'Cuapiaxtla de Madero', + 'Erquelinnes', + 'Galanta', + 'Islington', + 'Alaca', + 'Ganca', + 'Colcapirhua', + 'Katano', + 'White Oak', + 'Burgos', + 'Macalelon', + 'Bullhead City', + 'Obukhivka', + 'Krupka', + 'Rovaniemi', + 'Vrapciste', + 'Puerto Padre', + 'Cristalina', + 'Drug', + 'Bocono', + 'Abaji', + 'Annoeullin', + 'Savja', + 'El Coco', + 'Vauvert', + 'Rumbek', + 'Tettnang', + 'Tatsuno', + 'Olton', + 'Kabinda', + 'Miami Shores', + 'Chinnasekkadu', + 'Cotia', + 'Sapiranga', + 'Bad Rappenau', + 'Sharunah', + 'Cormeilles-en-Parisis', + 'Dossenheim', + 'Ozarow Mazowiecki', + 'Pichucalco', + 'Dowlaiswaram', + 'Palm Harbor', + 'Longba', + 'Chinique', + 'Roscoe', 'Douar Oulad Bouziane', - 'Pustomyty', - 'Ichenhausen', - 'Ukhai Purbari Patti', - 'Madaya', - 'Sierning', - 'Audenge', - 'Zacualpan de Amilpas', - 'Pau Brasil', - 'Mega', - 'Barjhar', - 'Hamira', - 'Ecatzingo', - 'Zorneding', - 'Rehau', - 'Werneuchen', - 'Hathaura', - 'Chhapera', - 'Tivat', - 'Locust Grove', - 'Frankfort Square', - 'Langnau', - 'Tandarampattu', - 'Baisuhalli', - 'Barahpur', - 'Langhnaj', - 'Shahr-e Majlesi', - 'Eemnes', - 'Punta Indio', - 'Tiruvaduturai', - 'Muppalla', - 'Opalenica', - 'Sebastiao Laranjeiras', - 'Obernkirchen', - 'Tadangam', - 'Diamondhead', - 'Maraial', - 'Miajadas', - 'Hattula', - 'Molsheim', - 'Mirjaveh', - 'Ubbergen', - 'Wallerfangen', - 'Tassera', - 'Wilnecote', - 'Southside', - 'Ntchisi', - 'Schlangen', - 'Bagchini', - 'Mahalgaon', - 'Canal Winchester', - 'Bayaram', - 'Kirangur', - 'Awans', - 'Lutterworth', - 'Chinnampalaiyam', - 'Ruffano', - 'Adelsdorf', - 'Aidlingen', - 'Gore', - 'Ameskroud', - 'Orlu', - 'Savenay', - 'Queensferry', - 'Sherborne', - 'Asudapuram', - 'Igarata', - 'Aucamville', - 'Chilmil', - 'Kolkwitz', - 'Siteia', - 'Chiman', - 'Oravita', - 'Modra', - 'Palhano', - 'Schaafheim', - 'Valreas', - 'Qutubpur', - 'East Stroudsburg', - 'Suan', - 'Barpathar', - 'Kalaikunda', - 'Laanoussar', - 'Harqalah', - 'San Agustin de las Juntas', - 'Santa Comba', - 'Nea Moudania', - 'Ladhuka', - 'Yezhi', - 'Nogent-le-Rotrou', - 'Chandwara', - 'Bhogapuram', - 'Sankt Valentin', - 'Pirpirituba', - 'Wehrheim', - 'Lancon-Provence', - 'Doctor Arroyo', - 'Parol', - 'Minano', - 'Rum', - 'Tonneins', - 'Nattakkadaiyur', - 'Katuria', - 'Takkali', - 'South Amboy', - 'Torrinha', - 'Mallappadi', - 'Santa Teresa di Riva', - 'Crestline', - 'Charter Oak', - 'Blachownia', - 'Ban Khi Lek', - 'Macomer', - 'Rodeo', - 'Zwenkau', - 'St. Anthony', - 'Havre', - 'Ouistreham', - 'Kesli', - 'Manteswar', - 'Nulivedu', - 'Sainte-Julienne', - 'Heiligenhafen', - 'Chinnakkavundanur', - 'Jaffar Khanpet', - 'Boddikurapadu', - 'Tarawan', - 'Pelagor', - 'Nort-sur-Erdre', - 'Studenka', - 'Samdrup Jongkhar', - 'Bruchhausen-Vilsen', - 'Irthlingborough', - 'Sujapur', - 'Vanzago', - 'Gatteo', - 'Chupinguaia', - "L'Isle-Jourdain", - 'Sosale', - 'Kaleybar', - 'Zafferana Etnea', - 'Fort Stewart', - 'Lubuagan', - 'Pesca', - 'Hagondange', - 'Hasanpura', - 'Nagayalanka', - 'Kopong', - 'Lac des Oiseaux', - 'Unao', - 'Telkathu', - 'Kalvarpatti', - 'Oued Essalem', - 'Maihma Sarja', - 'Jahangirpur Salkhani', - 'Bull Mountain', - 'Moisei', - 'Peixe', - 'Baisa', - 'Angola', - 'Santa Maria de Cayon', - 'Laghzawna', - 'Adakli', - 'Ehningen', - 'Timmapuram', - 'Boali', - 'Shanhur', - 'San Pablo Huixtepec', - 'Imielin', - 'Rudraprayag', - 'Janpur', - 'Mohammad Yar', - 'Monserrat', - 'Redon', - 'Chianki', - 'Bang Khla', - 'Ouled Rached', - 'Ralla', - 'Pangunattam', - 'Altinyayla', - 'Dornstadt', - 'Quakertown', - 'East Franklin', - 'Nor Hachn', - 'Torgelow', - 'Rupahi', - 'Choix', - 'Sadarak', - 'Pfedelbach', - 'Shimizu', - "Saint-Jean-d'Illac", - 'Hualane', - 'Patchur', - 'Mariyadau', - 'Satravada', - 'Qualicum Beach', - 'Nieuwleusen', - 'San Jose Guayabal', - 'Frodsham', - 'Polegate', - 'Pasraha', - 'Ilvesheim', - 'Draksharama', - 'Livron-sur-Drome', - 'Farsala', - 'Uranganpatti', - 'Mumaradikop', - 'Barros Cassal', - 'Honganur', - 'Porto de Pedras', - 'Rosario do Catete', - 'Le Cres', - 'Isua', - 'Bo`z', - 'Shende', - 'Kanajanahalli', - 'Khandaich', - 'Ecorse', - 'Skidaway Island', - 'Newfane', - 'Malahide', - 'Titu', - 'Poienile de sub Munte', - 'Perwez', - 'Modavandisatyamangalam', - 'Kharahara', - 'Gassino Torinese', - 'Kisslegg', - 'Ledbury', - 'Sindos', - 'Kruszwica', - 'Juprelle', - 'Tecklenburg', - 'La Jigua', - 'Dahi', - 'Milajerd', - 'St. Francis', - 'Tysmenytsia', - 'Asarhi', - 'Bernalillo', - 'Jandaira', - 'Marano Vicentino', - 'Ventnor City', - 'Bad Liebenwerda', + 'Dayr az Zawr', + 'French Valley', + 'Kalasa', + 'Cave Spring', + 'Yakage', + 'Phagu', + 'Taishituncun', + 'Sumisip', + 'Littleport', + 'Kulachi', + 'Saravena', + 'Aguai', + 'Nederweert', + 'Haskoy', + 'Saguday', + 'Shushtar', + 'Cuilapa', + 'Formigine', + 'Kalateh-ye Mir Ab', + 'Farsund', + 'Ripon', + 'Munich', + 'Himora', + 'Banamba', + 'Mkokotoni', + 'Anori', + 'Hartsville', + 'Thikri', + 'Xiantao', + 'Libmanan', + 'Shahritus', + 'Hayle', + 'Arakkal', + 'Hoa Thanh', + 'Chetumal', + 'Cormano', + 'Witham', + 'Cleveland Heights', + 'Ludus', + 'Tolanaro', + 'Saint-Doulchard', + 'Pradopolis', + 'Lourdes', + 'Siswar', + 'Alabaster', + 'Kasibu', + 'Saint-Leu-la-Foret', + 'Sakaddi', + 'Entre Ijuis', + 'Bilina', + 'Boyovut', + 'Ambohinihaonana', + 'Patrasaer', + 'North Augusta', + 'Ciudad Nezahualcoyotl', + 'Jenks', + 'Shiyuan', + 'San Carlos Yautepec', + 'Kabarore', + 'Durban', + 'Dajabon', + 'Leognan', + "Chech'on", + 'Guelma', + 'Rossmoor', + 'Cano Martin Pena', + 'Standerton', + 'Kaimuh', + 'Bellflower', + 'Sibutu', + 'Guateque', + 'Vejer de la Frontera', + 'Gornalwood', + 'Serhetabat', + 'Kondayampalaiyam', + 'Andal', + 'Kingersheim', + 'Ait Ben Daoudi', + 'Ixhuatlancillo', + 'Song Doc', + 'Schoten', + 'Gan Yavne', + 'Koprivnice', + 'Wadi', + 'Belvidere', + 'Haibach', + 'Chishtian', + 'Ras El Oued', + 'New Haven', + 'Alamuru', + 'Qaminis', + 'Saint-Eustache', + 'Port Wentworth', + 'Hashimoto', + 'Thara', + 'Qingzhen', + 'Sancti Spiritus', + 'Andiyappanur', + 'Pozi', + 'Songnam', + 'Alken', + 'Horsens', + 'Al Hashimiyah', + 'Vanadzor', + 'Fatehpur', + 'Necochea', + 'Sagbayan', + 'La Virgen', + 'Villagran', + 'Elyria', + 'Perunkolattur', + 'Talavadi', + 'Melrose', + 'Penaranda', + 'Aroeiras', + 'Caucasia', + 'Maryland Heights', + 'Ambatomifanongoa', + 'Fairfield', + 'Liuquancun', + 'Siqueira Campos', + 'Villa Carlos Paz', + 'Blitta', + 'Ciudad de Melilla', + 'Arajpur', + 'Pantano Grande', + 'Central Signal Village', + 'Tirumuruganpundi', + 'Vilakkudi', + 'Kavadarci', + 'La Plata', + 'Short Pump', + 'Shivganj', + 'Fangasso', + 'Douar Ain Maatouf', + 'Harlau', + 'Egypt Lake-Leto', + 'Greiz', + 'Al Khums', + 'Inabanga', + 'Ylivieska', + 'Halmstad', + 'West St. Paul', + 'Boudouaou', + 'Banaybanay', + 'Pinheiro Machado', + 'Bongao', + 'Parras de la Fuente', + 'Tabhka Khas', + 'Basingstoke', + 'Ovejas', + 'Bandwar', + 'Abu Ghurayb', + 'Bekescsaba', + 'Arutla', + 'Kadwa', + 'Kyaukse', + 'North Bethesda', + 'Jilotepec', + 'Kafr `Awan', + 'Takua Pa', + 'Aberystwyth', + 'Bataipora', + 'Timmarasanayakkanur', + 'Aradippou', + 'Khampat', + 'Caln', + 'Ambodimadiro', + 'Paso de Ovejas', + 'Manavalakurichi', + 'Chajari', + 'Jacarei', + 'Bals', + 'Bishkek', + 'Ikela', + 'Saladoblanco', + 'Sirsilla', + 'Dara', + 'Wuchang', + 'Haiyang', + 'Arida', + 'Kalaiyamputtur', + "'Tlat Bni Oukil", + 'Dixon', + 'Mogi das Cruzes', + 'Tizi Ouzou', + 'Hopkinton', + 'Buchanan', + 'Amami', + 'Juiz de Fora', + 'Kargipinar', + 'Saint-Orens-de-Gameville', + 'Charlton', + 'Dortyol', + 'Parepare', + 'Cadaado', + 'Boryspil', + 'Marina del Rey', + 'Uchen', + 'Betulia', + 'Kerema', + 'Chartoun', + 'Shajapur', + 'Brooks', + 'Nova Odesa', + 'Sogne', + 'Sarahandrano', + 'Nea Ionia', + 'Sumidouro', + 'Yayladagi', + 'Cesky Krumlov', + 'Tay Ninh', + 'Ottweiler', + 'Pedro Brand', + 'Neka', + 'Masse', + 'Darcheh', + 'Adelphi', + 'Melur', + 'Bergneustadt', + 'Salempur', + 'Avanigadda', + 'Guruvarajukuppam', + 'Chandwa', + 'Saclepea', + 'Kathanian', + 'Kari', + 'San Jacinto', + 'Southall', + 'Jinja', + 'Sungaiselam', + 'Sirmaur', + 'Friedland', + 'Alpine', + 'Kerben', + 'Lubaczow', + 'Ambodimangavolo', + 'Chuxiong', + 'Ciudad Mante', + 'Chorkuh', + 'Indalvai', + 'Fengruncun', + 'Azpeitia', + 'Sallisaw', + 'Karanganyar', + 'Tokmak', + 'Baripada', + 'St. Marys', + 'Platon Sanchez', + 'Bugembe', + 'Nihtaur', + 'Kharsod B', + 'Shahriar', + 'Jabbeke', + 'Mogtedo', + 'Mayorga', + 'Rastatt', + 'Prairie Village', + 'Hato Corozal', + 'Dubuque', + 'Rocha', + 'Pataskala', + 'Blue Ash', + 'Sarandi', + 'Nkayi', + 'Coldstream', + 'Guru Har Sahai', + 'Gardanne', + 'Waukesha', + 'Saran', + 'Alfred and Plantagenet', + 'Tiadiaye', + 'Huchuan', + 'Lujan de Cuyo', + 'Fundao', + 'Ben Tre', + 'Balingasag', + 'Safipur', + 'Mitoyo', + 'At Taji', + 'Doany', + 'Fuyuan', + 'Hayesville', + 'Schwerin', + 'Phelan', + 'Bethanie', + 'Weymouth', + 'Kibanseke Premiere', + 'Buey Arriba', + 'Ibotirama', + 'Yamaguchi', + 'Vadasseri', + 'Wantage', + 'Iaboutene', + 'Karlivka', + 'Manabo', + 'San Kamphaeng', + 'El Hermel', + 'Corrente', + 'Voisins-le-Bretonneux', + 'Vemuluru', + 'Jasauli Patti', + 'Paraguacu Paulista', + 'Umreth', + 'Rakovski', + 'Kottagudi Muttanad', + 'Sao Felix do Araguaia', + 'Huong Tra', + 'Yukon', + 'Miena', + 'Datang', + 'Petrich', + 'Tholen', + 'Mosopa', + 'Fara in Sabina', + 'Alesund', + 'Penwortham', + 'Poyo', + 'Ruma', + 'Scorze', + 'Cedral', + 'Forest Grove', + 'Szeged', + 'Firavahana', + 'Bagno a Ripoli', + 'Caravelas', + 'Horn-Bad Meinberg', + 'Porto Alegre do Norte', + 'Shtime', + 'Raba', + 'Chisec', 'Lagunia Raghukanth', - 'Kollankulam', - 'Mabeskraal', - 'Analaroa', - 'Kunnattur', - 'Uppalapadu', - 'Ban Bo Phlap', - 'San Pancrazio Salentino', - 'Bethalto', - 'Frickenhausen', - 'Bagnara Calabra', - 'Moldova Noua', - 'Nakhon Thai', - 'Herculandia', - 'Chicholi', - 'Punta del Este', - 'Pozo Almonte', - 'Laurens', - 'Elsenfeld', - 'Catral', - 'Majhariya', - 'Bhachhi', - 'Altun Kawbri', - 'Nakoushi', - 'Thakurainia', - 'Almagro', - 'Coleford', - 'Leonia', - 'Mascota', - 'Skwierzyna', - 'Abuzar-e Ghaffari', - 'Gaggiano', - 'Nakao', - 'Mound', - 'Crigglestone', - 'Teplohirsk', - 'Gainrha', - 'Goldach', - "Clermont-l'Herault", - 'Deokali', - 'Joghtay', - 'Rajapudi', - 'Punnaikkayal', - 'Wasilla', - 'Guneysinir', - 'Oppicherla', - 'Merrill', - 'Freystadt', - 'Pappampatti', - 'Tlahuiltepa', - 'Niederhasli', - 'Macedon', - 'Padinska Skela', - 'Didymoteicho', - 'Alukkuli', - 'Chilakhana', - 'Khotyn', - 'Walworth', - 'Ochsenhausen', - 'Douar Oulad Sidi Moussa', - 'Ain el Hadjar', - 'Launaguet', - 'Sidi Lahsene', - 'Riscani', - 'Barei', - 'Rinopolis', - 'Piamonte', - 'Weissenthurm', - 'Edeleny', - 'Itiki', - 'Barnaon', - 'Picture Rocks', - 'Aljustrel', - 'Fairfield Glade', - 'Bojaca', - 'Pedda Tumbalam', - 'Las Tablas', - 'Velykyi Bychkiv', + 'Ensenada Berisso', + 'Do`stobod', + 'Amarpur', + 'Lunca Cetatuii', + 'Dagupan City', + 'Saumlaki', + 'Karkamb', + 'Sobrado de Paiva', + 'Kalappalangulam', + 'Joao Lisboa', + 'The Dalles', + 'Slateng Dua', + 'Lingwala', + 'Latiano', + 'Orangeville', + 'Borazjan', + 'Pizarro', + 'Pilich', + 'Veintiocho de Noviembre', + 'Huntington Park', + 'Jesus Menendez', + "'Ain Abessa", + 'Descalvado', + 'Krapina', + 'Harwood Heights', + 'Banco Filipino International Village', + 'Guadarrama', + 'Channagiri', + 'Mokri', + 'Sanjiang', + 'Kokri', + 'Tirkha', + 'Zhangjiakou', + 'Veresegyhaz', + 'Zhuanghe', + 'Balkonda', + 'Siemiatycze', + 'Ban Saeo', + 'Torrijos', + 'Faches-Thumesnil', + 'Campo Alegre de Lourdes', + 'Francofonte', + 'Alarobia', + 'Worthing', + 'Rochelle', + 'Ilvesheim', + 'Billings', + 'Batangas', + 'Vochaiko', + 'Zaragoza', + 'Heppenheim', + 'La Mana', + 'Son Tay', + 'Magilampupuram', + 'Logrono', + 'Chiavari', + 'Gujan-Mestras', + 'Katako-Kombe', + 'Chaparral', + 'Batie', + 'Foligno', + 'University', + 'Iruttarakonam', + 'Kotla', + 'East Hanover', + 'Jomboy Shahri', + 'Changanacheri', + 'Kensington', + 'Dobje', + 'Maisons-Laffitte', + 'Oroquieta', + 'Parambatt Kavu', + 'Dois Riachos', + 'Latina', + 'Babhanganwa', + 'Ambohimahasoa', + 'Pandino', + 'Chefchaouene', + 'Teixeiras', + 'Saveh', + 'Glens Falls', + 'Tonj', + 'Bhulwal', + 'Luozi', + 'Adoni', + 'Mahazony', + 'Setagaya', + 'Banning', + 'Minamishimabara', + 'Tuz Khurmatu', + 'Sundarapandiyam', + 'Kodaira', + 'Santa Cruz de la Palma', + 'Candiota', + 'Pittsford', + 'Yakeshi', + 'Lengerich', + "Da'an", + 'Pacaembu', + 'East Point', + 'Miacatlan', + 'Sendamangalam', + 'Sidi Khaled', + 'Landquart', + 'Reinbek', + 'Millau', + 'Itaosy', + 'Bellefontaine', + 'Aracoiaba', + 'Melipilla', + 'Monor', + 'Collinsville', + 'Lenggries', + 'Pio Duran', + 'Rhondda', + 'Abu Sir Bana', + 'Cholavaram', + 'Kamepalle', + 'Yeppoon', + 'Sangenjo', + 'Hradec Kralove', + 'Kibeho', + 'Ahmetli', + 'Yurihonjo', + 'Pontassieve', + 'Cahokia Heights', + 'Ubaidullahganj', + 'Brakel', + 'Berezan', + 'Noya', + 'Reggio Emilia', + 'Huesca', + 'Bopfingen', + 'Bhainsa', + 'Dhupgari', + 'Itaiba', + 'Camenca', + 'Chmistar', + 'Sao Luis do Quitunde', + 'Foix', + 'Kond Rud', + 'Laterza', + 'Schopfheim', + 'Kasuga', + 'Ouadhia', + 'Dala', + 'Sonagazi', + 'Songjiangcun', + 'Mamidalapadu', + 'Biarritz', + 'Theodore', + 'Ngudu', + 'Ntorosso', + 'Buxar', + 'Kaliyaganj', + 'Milanoa', + 'Spisska Nova Ves', + 'Fuli', + 'Kisi', + 'Jhargram', + 'Zaporizhzhia', + 'Gazipasa', + 'Suyo', + 'North Saanich', + 'San Ricardo', + 'Komatipoort', + 'Mallapuram', + 'Yitiaoshan', + 'Kargilik', + 'Kinoni', + 'Qazyqurt', + 'Cajazeiras', + 'Semnan', + 'Pandan', + 'Koceljeva', + 'Ambodimotso Atsimo', + 'Valenza', + 'Puerto de la Cruz', + 'Tepetlaoxtoc', + 'Adjala-Tosorontio', + 'Zillah', + 'Diamondhead', + 'Hallstadt', + 'Anseong', + 'Libacao', + 'Bharella', + 'Yilan', + 'Cadolzburg', + 'Papantla de Olarte', + 'Fengguangcun', + 'Jhelum', + 'Dalanping', + 'Tegucigalpa', + 'Batala', + 'El Kerma', + 'Yangzhou', + 'Passira', + 'Hagonoy', + 'Kambaduru', + 'Jambusar', + 'Teddington', + 'Murambi', + 'Corsham', + 'Arzew', + 'Nittedal', + 'Paingkyon', + 'Maravilha', + 'Edison', + 'Montlhery', + 'Mokameh', + 'Canegrate', + 'Tezoatlan de Segura y Luna', + 'Iraucuba', + 'Kattivakkam', + 'Lino Lakes', + 'Kalyani', + 'El Playon', + 'Kabbur', + 'San Miguel Xoxtla', + 'Zirndorf', + 'Guama Abajo', + 'Sevlievo', + 'Kawai', + 'Edingen-Neckarhausen', + 'Chimalapadu', + 'Huatan', + 'Cascavel', + 'Naravarikuppam', + 'Pasighat', + 'Chimthana', + 'Priolo Gargallo', + 'Diema', + 'Yingshouyingzi', + 'Hardoi', + 'Shpola', + 'Alipur Duar', + 'Parambu', + 'Igaratinga', + 'Xinxing', + 'Damboa', + 'Edgemere', + 'Cypress Lake', + 'Lemont', + 'Karedu', + 'Puerto Villamil', + 'Thornaby on Tees', + 'Basarabeasca', + 'Bolama', + 'Islip', + 'Sonkach', + 'Cinco Ranch', + 'Tibiao', + 'Kuala Belait', + 'Nahazari', + 'Culion', + 'Villa Alegre', + 'Santiago Amoltepec', + 'Edgewater', + 'Sinuni', + 'Posusje', + 'Castellbisbal', + 'Bhainsoda', + 'Jindrichuv Hradec', + 'Pattiyurgramam', + 'Manlin', + 'Kabayan', + 'Boulder Hill', + 'Pastpar', + 'Mablethorpe', + 'Kodumur', + 'Kegen', + 'Wugang', + 'Cerquilho Velho', + 'Bent Jbail', + 'Bornova', + 'Hoganas', + 'Queretaro', + 'Ar Rayyan', + 'Bondues', + 'Pierrelaye', + 'Baiyin', + 'La Sierpe', + 'Selendi', + 'Antony', + 'Mathukumnel', + 'Kingoonya', + 'Nueva Gerona', + 'Alitagtag', + 'Simojovel de Allende', + 'Kralendijk', + 'Kanal', + 'Umm al Qaywayn', + 'Dodola', 'Risaralda', - 'Bures-sur-Yvette', - 'Borgholzhausen', - 'Muro del Alcoy', - 'Escaudain', - 'San Pedro Nonualco', - 'Gomaringen', - 'Towcester', - 'Pasian di Prato', - 'Rensselaer', - 'Sugar Grove', - 'Kudelstaart', - 'Keuruu', - 'Ganaram', - 'Algun', - 'Samalpur', - 'Douar Ezzerarda', - 'Schubelbach', - 'Niesky', - 'San Jose La Arada', - 'Gandikunta', - 'Vittuone', - 'Manzanares el Real', - 'Bendapudi', - 'Katteragandla', - 'Sitanagaram', - 'Ban Son Loi', - 'Magalia', - 'Haiku-Pauwela', - 'Diouna', - 'Hamrun', - 'Capilla del Senor', - 'Benahavis', - 'Smoline', - 'Wunsiedel', - 'Fallon', - 'Otumba', - 'Mels', - 'Harbatpur', - 'Loria', - 'Lesquin', - 'Chunakhali', - 'Montescaglioso', - 'Talata-Angavo', - 'Chala', - 'Reshetylivka', - 'Fatao', - 'Paray-le-Monial', - 'Belley', - 'Barleben', - 'Rain', - 'Iarpur', - 'Raipur Buzurg', - 'Hailey', - 'Oulad Cherif', - 'Bandio', - 'Romang', - 'Tanakoub', - 'Santa Isabel Cholula', - 'Gooik', - 'Zoubiria', - 'Mamidipalli', - 'Aranya Kalan', - 'Nutakki', - 'Tanamarina-Sakay', - 'Momchilgrad', - 'Mirante da Serra', - 'Tasso', - 'Juraqan', - 'Kahla', - 'Nossa Senhora Aparecida', - 'Dielheim', - 'Sandalpur', - 'Bahabad', - 'Rethen', - 'Giardini', - 'Stevenston', - 'Karsaut', - 'Vallapuram', - 'Ryki', - 'Brugnera', - 'Philippeville', - 'Carrillos', - 'La Victoria de Acentejo', - 'Bowdon', - 'Kondrukota', - 'Vaikuntam', - 'Castelleone', - 'Kesap', - 'San Lorenzo de Descardazar', - 'Kaujalgi', - 'Hlyboka', - 'La Bruyere', - 'Fazendinha', - 'I-n-Amenas', - 'Aslanapa', - 'Kalanchak', - 'Baia da Traicao', - 'Kondayampalaiyam', - 'Tisnov', - 'Jajireddigudem', - 'White Meadow Lake', - 'Oromocto', - 'Borja', - 'Clay Cross', - 'Bude', - 'Shannon', - 'Gudimulakhandrika', - 'Bad Laer', - 'Baluntaicun', - 'Gandhwani', - 'Vallahbhapuram', - 'Badagabettu', - 'Gangaura Behra', - 'Washington Terrace', - 'Japaratinga', - 'Antonio Dias', - 'Mejillones', - 'Joigny', - 'Inverigo', - 'Badnor', - 'Nonea', - 'Saraunja', - 'Kandiyankovil', - 'Ottapparai', - 'Swamimalai', - 'Evian-les-Bains', - 'Totnes', - 'Babadag', - 'Nong Kung Si', - 'Ghattupal', - 'Sholaqqorghan', - 'Altenbeken', - 'Kandel', - 'Kharika', - 'Kodakkal', - 'Castrolibero', - 'Qarqaraly', + 'Lugoff', + 'Steinheim am Albuch', + 'Sussen', + 'Mulavana', + 'Loanda', + 'Holiday', + 'Catriel', + 'Rotonda', + 'North Codorus', + 'Amanganj', + 'Sahakevo', + 'Cadca', + "Ch'onan", + 'Ponte San Giovanni', + 'Villa Altagracia', + 'Maywood', + 'Saraburi', + 'Tyldesley', + 'Satuluru', + 'Neufahrn bei Freising', + 'Zigon', + 'Calne', + 'Serere', + 'Cumberland Hill', + 'Ivanjica', + 'Konz', + 'Perth Amboy', + 'Alerce', + 'Berikai', + 'Foum Zguid', + 'Had Dra', + 'Cinere', + 'Dalkeith', + 'Fresnillo', + 'Yaizu', + 'Ciro Redondo', + 'Despotovac', + 'Kakkat', + 'Bassum', + 'Najran', + 'Segrate', + 'Mexico', + 'Kinrooi', + 'Moknine', + 'Andreba', + 'Bresso', + 'Venadillo', + 'Reoti', + 'Baharly', + 'Los Palmitos', + 'Jordania', + 'Great Missenden', + 'Puerto Cortes', + 'Los Alcazares', + 'Agbangnizoun', + 'Chausa', + 'Capistrano', + 'West Richland', + 'Pingyuanjie', + 'Coomera', + 'Bteghrine', + 'Occhiobello', + 'Olagadam', + 'Deerfield', + 'Aroroy', + 'Macedon', + 'Spout Springs', + 'East Patchogue', + 'Ebina', + 'Soria', + 'Ouled Mimoun', + 'Navapur', + 'Balumath', + 'Hennenman', + 'Barkot', + 'Denduluru', + 'Raca', + 'Kumbhari', + 'Bayaram', + 'Liuzhou', + 'Belmonte Mezzagno', + 'Harvard', + 'Wandiwash', + 'Cukurcayir', + 'Dinkelsbuhl', + 'Chero', + 'Ngolobougou', + 'Quilevo', + 'Saint-Claude', + 'Sonari', + 'Zaventem', + 'Venecia', + 'Sharjah', + 'Shoreham-by-Sea', + 'Governador Archer', + 'Cerese', + 'Lazarivo', + 'Angara-Debou', + 'Kaele', + 'Mahe', + 'Leighton Buzzard', + 'Erfelek', + 'Willimantic', + 'Sao Joaquim da Barra', + 'Littau', + 'Kayanna', + 'Temperley', + 'Jirwa', + 'Moses Lake', + 'Merriam', + 'Cerreto Guidi', + 'San Miniato', + 'Tumby Bay', + 'Wielun', + 'Tirukkattuppalli', + 'North Las Vegas', + 'Mahemdavad', + 'Nagaiyampatti', + 'Atyrau', + 'Chorley', + 'Ravansar', + 'Bettioua', + 'Green River', + 'Chicacao', + 'Karukkalvadi', + 'Dar el Beida', + 'Langarivo', + 'Tettu', + 'Santa Barbara', + 'Ban Pong', + 'San Nicolas de los Garza', + 'Tres Coroas', + 'Muttattuteruvu', + 'Coracao de Maria', + 'Nieuwpoort', + 'Laatzen', + 'Kusumbe', + 'Xiangyuncun', + 'Coral Springs', + 'Escaldes-Engordany', + 'Durpalli', + 'Kundian', + 'Acatlan de Perez Figueroa', + 'Mendes', + 'Sansale', + 'Batan', + 'Paslek', + 'San Severino Marche', + 'Madinat `Isa', + 'Youwarou', + 'Paghman', + 'Aruvikkara', + 'Osthofen', + 'Tianzhong', + 'Marudur', + 'Crensovci', + 'Ceerigaabo', + 'Brusciano', + 'Sabana de La Mar', + 'Aileu', + 'Kutaisi', + 'Maebashi', + 'Wanggezhuang', + 'Banska Stiavnica', + 'Tola', + 'Hovelhof', + 'Johannesburg', + "Sant Sadurni d'Anoia", + 'Binalonan', + 'Dingcheng', + 'Henderson', + 'Bloxwich', + 'Gberouboue', + 'Dharmaram', + 'Abomsa', + 'Imtarfa', + 'Rancho Santa Margarita', + 'Meuselwitz', + 'Ad Dali`', + 'Nilandhoo', + 'Bayramaly', + 'Lufkin', + 'Talcher', + 'Menaka', + 'Rupauli', + 'Ipanema', + 'Tindwara', + 'Piendamo', + 'Gennep', + 'Kachnar', + 'Vitez', + 'Oporapa', + 'Litvinov', + 'Lich', + 'Hericourt', + 'Sanghar', + 'Sao Lourenco', + 'Bir Ali Ben Khalifa', + 'Hlucin', + 'Erith', + 'Ebejico', + 'Qulsary', + 'Pichor', + 'Lubon', + 'Lufilufi', + 'Mayamankurichchi', + 'Kulittalai', + 'Marshall', + 'Weil der Stadt', + 'Mahabako', + 'Lemoore', + "Al M'aziz", + 'Behat', + 'Mauriti', + 'Memphis', + 'Antas', + 'Novo Mesto', + 'Zinkiv', + 'Mi`rabah', + 'Ksar Sghir', + 'Mandapam', + 'Cupang', + 'Mina', + 'Bytom', + 'Kikuyo', + 'Yankton', + 'Spilimbergo', + 'Gottmadingen', + 'Vanersborg', + 'Harduli', + 'Wierden', + 'Paloncha', + 'Chikmagalur', + 'Qubadli', + 'Longwood', + 'Nay Pyi Taw', + 'Wald-Michelbach', + 'Kafr al Battikh', + 'Orai', + 'Juchique de Ferrer', + 'Swiebodzice', + 'Behbahan', + 'Sehore', + 'Te Awamutu', + 'Shacheng', + 'Kano', + 'Ciftlikkoy', + 'Op', + 'Yendi', + 'Sun Valley', + 'Guabari', + 'Kalyanpur Bamaiya', + 'Rauco', + 'Pedro de Toledo', + 'Kandhkot', + 'Degollado', + 'Kasai', + 'Krasnik', + 'Abu Khashab', + 'Middlesbrough', + 'Cifuentes', + 'Ganxi', + 'Mae Sot', + 'Raubling', + 'Myoko', + 'McLean', + 'Trail', + 'Reggada', + 'Migdal Ha`Emeq', + 'Banni', + 'La Grange Park', + 'Ojiya', + 'Youngstown', + 'East Longmeadow', + 'Perunkalattu', + 'Guimaraes', + 'Sete Lagoas', + 'Bhandaria', + 'Stretford', + 'Corrientes', + 'Hurst', + 'Satuek', + 'Suhum', + 'Majiagoucha', + 'Caltagirone', + 'Asthal Bohar', + 'Chipiona', + 'Aravan', + 'Kiboga', + 'Ephrata', + 'Lystrup', + 'Nowa Deba', + 'Vangaindrano', + 'New Westminster', + 'Cestas', + 'Bithan', + 'Saraiya', + 'Bad Soden am Taunus', + 'Cinnaminson', + 'Mansidao', + 'Heroldsberg', + 'Opovo', + 'Shinhidaka', + 'Mildura', + 'Sahatsiho-Ambohimanjaka', + 'Dok Kham Tai', + 'Szombathely', + 'Nova Olinda do Norte', + 'Brantford', + 'Cobram', + 'Sulzbach-Rosenberg', + 'Key Biscayne', + 'South Ubian', + 'Varde', + 'Scandiano', + 'Santa Cruz do Sul', + 'Cedar Park', + 'Erstein', + 'Matozinhos', + 'Buxin', + 'Chortiatis', + 'Camrose', + 'Ettimadai', + 'Montagnana', + 'Ivybridge', + 'Middlewich', + 'Tivat', + 'Babai Kalan', + 'Al Qusayr', + 'Vatolatsaka', + 'Cruz', + 'Linstead', + 'Lakkundi', + 'Serrolandia', + 'Shuibian', + 'Llanelli', + 'Six-Fours-les-Plages', + 'Entre Rios de Minas', + 'Saude', + "Karbala'", + 'Godinlabe', + 'Ocatlan', + 'Paranatama', + 'Begampur', + 'Khulm', + 'Alegria', + 'Partanna', + 'Bothaville', + 'Vaal Reefs', + "Alvorada D'Oeste", + 'Cotes de Fer', + 'Sibirila', + 'Heshancun', + 'Adustina', + 'Uberlingen', 'Shawano', - 'Cape St. Claire', - 'Kannavam', - 'Pong Nam Ron', - 'Ban Kham Pom', - 'Pohrebyshche', - 'Jambukuttaippatti', - 'Chokkalingapuram', - 'Badanahatti', - 'Covasna', - 'Llagostera', - 'Surak', - 'Waseca', - "O'Hara", - 'Gnarrenburg', - 'Golbaf', - 'Palm Beach', - 'Falan', - 'Elsfleth', - 'Arlesheim', - 'Mont-Saint-Martin', - 'Cullercoats', - 'Vadavalam', - 'Irungalur', - 'Xalqobod', - 'Qorovulbozor', - 'Gothurutha', - 'Ramayipatti', - 'Araujos', - 'Sassnitz', - 'Laheji', - 'Paredes de Coura', - 'Tiana', - 'Spata', - 'Aliquippa', - 'San Fausto de Campcentellas', - 'Bike', - 'Damargidda', - 'Panthersville', - 'Une', - 'Jamhra', - 'Susari', - 'Valkurti', - 'Blackstone', - 'Whitecourt', - 'Nowra', - 'Tenedla', - 'Leichi', + 'Santa Fe', + 'Bolivia', + 'Maniche', + 'Chikura', + 'Amstelveen', + 'Mwinilunga', + 'Tetiiv', + 'Losal', + 'Ortakent', + 'Mirassol', + 'Yerba Buena', + 'Kasongo-Lunda', + 'Zongdi', + 'Pirmed', + 'Ashton', + 'La Union', + 'Anaco', + 'Front Royal', + 'Faro', + 'Votorantim', + 'Bengbu', + 'Aldaya', + 'Khem Karan', + 'Dushanbe', + 'Campulung Moldovenesc', + 'Quixeramobim', + 'Chabet el Ameur', + 'Pingtung', + 'Fukuoka', + 'Itapiuna', + 'Khiram', + 'Lami', + 'Morubagalu', + 'South Kingstown', + 'Chatham', + 'Cefalu', + 'Pattanakkad', + 'Silvan', + 'Souk Et-Tleta des Oulad Hamdane', + "Mai'Adua", + 'Ban Bang Khu Wat', + 'Ardal', + 'Collegedale', + 'Irbid', + 'Lanham', + 'San Pablo Jocopilas', + 'Santuario', + 'Betma', + 'Inezgane', + 'Pout', + 'Batcha', + 'Irlam', + 'Aldoar', + 'Atakpame', + 'Ban Bo Luang', + 'Finchley', + 'Tamalous', + 'Bagnols-sur-Ceze', + 'Matsushima', + 'Yecuatla', + 'Wuxue', + 'Ocean Springs', + 'Petilia Policastro', + 'Benenitra', + 'Elgin', + 'Guntupalle', + 'Itirucu', + 'Chengde', + 'Castelvetro di Modena', + 'Ramkali', + 'Marki', + 'Loudima Poste', + 'Usta Muhammad', + 'Banfield', + 'Patna', + 'Lendinara', + 'Toliara', + 'Tioribougou', + 'Mosbrough', + 'Yenangyaung', + 'Analanampotsy', + 'Zgornje Gorje', + 'Al Qubbah', + 'Lakeshore', + 'Kocaali', + 'Sombor', + 'Punta Arenas', + 'Elmira', + 'Serekunda', + 'Ban Khlong', + 'Ried im Innkreis', + 'Olivehurst', + 'Naruto', + 'Plainville', + 'Nakhal', + 'Hampton Bays', + 'Yaita', + 'Ambatosia', + 'Guindulman', + 'Wommelgem', + 'Jasper', + 'Sao Joao da Madeira', + 'Curiuva', + 'Destin', + 'Zigong', + 'Kushijima', + 'Fameck', + 'Telmar', + 'Noboribetsu', + 'Guanare', + 'Adis `Alem', + 'Angatuba', + 'Santa Cruz Zenzontepec', + 'Dongguazhen', + 'Castle Rock', + 'Millbrook', + 'Erlenbach am Main', + 'Kamloops', + 'South Jordan', + 'Colombia', + 'Baguio City', + 'Turkaguda', + 'Momchilgrad', + 'Aiyappan Kovil', + 'Strada', + 'Rostock', + 'Lichtenfels', + 'Al Majaridah', + 'Bagh-e Bahadoran', + 'Irvington', + 'Maheshwar', + 'Jhagarua', + 'Birchington', + 'Iba', + 'Wang Nam Yen', + 'Heilbad Heiligenstadt', + 'Meinerzhagen', + 'Shandiz', + 'Fallston', 'Landivisiau', - 'Ban Chang Phuak', - 'Muli', - 'Vignate', - 'Cobanlar', - 'Stovring', - 'Shirguppi', - 'Chalkari', - 'Jogaili', - 'As Sidrah', - 'Tibana', - 'Tepe-Korgon', - 'Santa Maria Ajoloapan', - 'Capbreton', - 'Tilehurst', - 'Chikkala', - 'Sewa', - 'Aberbargoed', - 'Olds', - 'Suwannaphum', - 'Jagannadapuram', - 'Himmatpura', - 'Rajepur', - 'Sukkampatti', - 'Roux', - 'Canela Baja', - 'Cisterniga', - 'Tiptree', - 'Conshohocken', - 'Sidi Bou Othmane', - 'Hirehalli', - 'Maidencreek', - 'Guntramsdorf', - 'Harpur Bhindi', - 'Vega Alta', - 'Cerro Grande', - 'Alsbach-Hahnlein', - 'Douar El Mellaliyine', - 'Arceburgo', - 'Galten', - 'Madepalli', - 'Nelali', - 'Horr-e Riahi', - 'Grants', - 'Ahuimanu', - 'Elze', - 'Hacine', - 'Yatton', - 'Budhma', - 'Nashtifan', - 'Obukhivka', - 'Itapebi', - 'Yaxley', - 'Ivins', - 'Rockingham', - 'Makow Mazowiecki', - 'Murfatlar', - 'Tuskegee', - 'Binisalem', - 'Onchan', - 'Waiuku', - 'Ban Wat Chan', - 'Jerez de los Caballeros', - 'Sarkad', - 'Ban Yaeng', - 'Trittau', - 'Biblis', - 'Dorverden', - 'Marale', - 'Matelica', - 'Verdejante', - 'Xiangping', - 'Ville-la-Grand', - 'Littleport', - 'Monte Rico', - 'Boekenhouthoek', - 'Foammulah', - 'Pencoed', - 'West Manheim', - 'Dommasandra', - 'Corumbaiba', - 'Waldfeucht', - 'Micco', - 'Flanders', - 'Irshava', - 'Yvoir', - 'Abalessa', - 'Incline Village', - 'Zabalj', - 'Gadabay', - 'Palomares del Rio', - 'Reggiolo', - 'Beauraing', - 'Ifigha', - 'Op', - 'Ussel', - 'Banbhag', - 'Bariariya Tola Rajpur', - 'Entre Ijuis', - 'Beauchamp', - 'Halgeri', - 'Santo Domingo Petapa', - 'Gualaquiza', - 'San Fructuoso de Bages', - 'Sungal', - 'Pilikodu', - 'Wysokie Mazowieckie', - 'Fateh Nangal', - 'Zorbig', - 'Zupanja', - 'Imotski', - 'Piripa', - 'Grunheide', + 'San Juan de Aznalfarache', + 'Ettaiyapuram', + 'Kota Kinabalu', + 'Roseira', + 'Fusagasuga', + 'Bovisio Masciago', + 'Vilpatti', + 'Old Forge', + 'Kadiyam', + 'Goraya', + 'Almelo', + 'Rescaldina', + 'Bad Munstereifel', + 'Atebubu', + 'Panapakkam', + 'Morag', + 'Ferrier', + 'Velaux', + 'Sellersburg', + 'Kambhampadu', + 'Ubbergen', + 'Quilandi', + 'Digos', + 'Slavutych', + 'Terre Haute', + 'Schlitz', + '`Unayzah', + 'Zaoyang', + 'Beauvais', + 'Allacapan', + 'Shangjing', + 'Nayagarh', + 'Kanasin', + 'Velasco Ibarra', + 'Agan', + 'Nouna', + 'Puthiyangadi', + 'Salar', + 'Povoa de Lanhoso', + 'Brotas de Macaubas', + 'Donggang', + 'Inuyama', + 'Balakan', + 'Camara de Lobos', + 'Tanauan', + 'Ribas do Rio Pardo', + 'Fagundes', + 'San Rafael Petzal', + 'Iraci', + 'Kadena', + 'Ramos Mejia', + 'Vaasa', + 'Goribidnur', + 'Changping', + 'Oregon', + 'Schiller Park', + 'Mereeg', + 'Toro', + 'Lynnwood', + 'Iiyama', + 'Punta Alta', + 'Cervello', + 'Sariosiyo', + 'Kunitachi', + 'Thu Dau Mot', + 'Viljandi', + 'Kurichedu', + 'Saugerties', + 'Noveleta', + 'Paripiranga', + 'Odesa', + 'Ibirama', + 'Coamo', + 'Smolyan', + 'Montilla', + 'Khan Bebin', + 'Ambovonomby', + 'Serinyol', + 'Ayapel', + 'San Antonio de los Cobres', + 'Kadiri', + 'Quatre Bornes', + 'Bareh', + 'Buritis', + 'Los Cerrillos', + 'Potenza', + 'Sughrain', + 'Nehbandan', + 'Ampthill', + 'Palmeira das Missoes', + 'Dombovar', + 'Angadanan', + 'Yuanping', + 'Martapura', + 'Curumani', + 'Benhao', + 'Ban Bang Toei', + 'Stadskanaal', + 'Secanj', + 'Renaico', + 'Buckhall', + 'Tirutturaippundi', + 'Komotini', + 'Suroth', + 'Guene', + 'Canudos', + 'Bhagsar', + 'Lubben (Spreewald)', + 'La Ciotat', + 'Stirling', + 'Praia da Vitoria', + 'Pakra', + 'Harpanahalli', + 'Tururu', + 'Andranomanelatra', + 'Sirnia', + 'Steyr', + 'Lake Stickney', + 'Villa Ojo de Agua', + 'Tuyserkan', + 'Saint-Jean-de-la-Ruelle', + 'Ranapur', + 'Kheiredine', + 'Villa El Carmen', + 'Sherborne', + 'Kerai', + 'Barughutu', + 'Tienen', + 'Cherkasy', + 'Turmero', + 'Ahigbe Koffikro', + 'Rio Azul', + 'Baro', + 'Koshanam', + 'Malinalco', + 'Afula', + 'Perpignan', + 'Timayy al Imdid', + 'Kotgir', + 'Forbach', + 'Malka', + 'Palm Beach', + 'Falmouth', + 'Beihai', + 'Kalbarri', + 'Ivato', + 'Picos', + 'Marcon', + 'Pieksamaki', + 'Carlet', + 'Salobe', + 'Yacimiento Rio Turbio', + 'Omiyacho', + 'Kodikkulam', + 'Shorapur', + 'Dniprorudne', + 'Neutraubling', + 'Kizhakkemanad', + 'Banagi', + 'Mount Gambier', + 'Malkajgiri', + 'Sokhumi', + 'Douera', + 'Chekfa', + 'Mairi', + 'Ortaca', + 'Loria', + 'San al Hajar al Qibliyah', + 'Galeana', + 'Aguadulce', + 'Carepa', + 'Jogipet', + 'Tambacounda', + 'Hingham', + 'Huntington Beach', + 'Yeniciftlik', + 'Talupula', + 'Naruar', + 'Tudela', + 'Ayyampalaiyam', + 'Kolwara', + 'Cisauk', + 'Jettihalli', + 'Surt', + 'Allen Park', + 'Casier', + 'Zhaxi', + 'Itu', + 'Quilombo', + 'Gharghur', + 'Keerbergen', + 'Gbarnga', + 'Degana', + 'Gretna', + 'Cerro Maggiore', + 'Santa Cruz Michapa', + 'Diamou', + 'Tiruppanandal', + 'Bayji', + 'Njeru', + 'Sour', + 'Martinengo', + 'Rocklin', + 'Saint-Vallier', + 'Yabrud', + 'Alfortville', + 'Kopoky', + 'Phuoc Long', + 'Giarre', + 'Kindu', + 'Ain Cheggag', + 'Babila', + 'Busumbala', + 'Basmenj', + 'Tangjia', + 'Karimunjawa', + 'Bhagatpur', + 'Murtazabad', + 'Konganapuram', + 'Kapelle', + 'Sidi Lamine', + 'Nezahualcoyotl', + 'Prague', + 'Chandreru', + 'Nelliyalam', + 'Kouhu', + 'Bollullos par del Condado', + 'Chiryu', + 'Ain Defla', + 'Trzin', + 'Llandybie', + 'Ushtobe', + 'Mecitozu', + 'Lys-les-Lannoy', + 'Campo Ere', + 'Antambohobe', + 'Kanifing', + 'Mulukuku', + 'Micoud', + 'Siran', + 'Markt Schwaben', + 'Porangatu', + 'Manimala', + 'Liege', + 'Shiremoor', + 'Itaperucu', + 'Puerto Pilon', + 'Bourg-la-Reine', + 'Kadalur', + 'Kodikuthi', + 'Thame', + 'Soahany', 'Kyritz', - 'Morubagalu', + 'Longtoushan Jiezi', + 'Meiktila', + 'Centenario do Sul', + 'Cunit', + 'Engerwitzdorf', + 'Ebreichsdorf', + 'Newbury', + 'Almoloya de Alquisiras', + 'Krishnarayapuram', + 'Kadamakudi', + 'Yongzhou', + 'Sartell', + 'Madeley', + 'Koszutka', + 'Iacanga', + 'Ekhari', + 'Kratie', + 'Nyeri', + 'Qazigund', + 'Langdu', + 'Pong Nam Ron', + 'Timon', + 'Gyeongsan', + 'Minerbio', + 'Singia', + 'East Niles', + 'Mmopone', + 'Masaurhi Buzurg', + 'Liantangcun', + 'Banino', + 'Altopascio', + 'Tillaberi', + 'Riachao do Jacuipe', + 'Nalikkalpatti', + 'Romanshorn', + 'Xinjing', + 'Cha-am', + 'Cumpana', + 'Shenandoah', + 'Pathanamthitta', + 'Tata', + 'Lake Elsinore', + 'Vilavur', + 'Ogdensburg', + 'Santa Maria de Cayon', + 'Rakvere', + 'Baretha', + 'Ankaraobato', + 'Miguel Pereira', + 'West Islip', + 'Tekkekara Kizhakku', + 'Chita', + 'Futrono', + 'Cordon', + 'Ampefy', + 'Santo Domingo de los Colorados', + 'Mtskheta', + 'Dassa-Zoume', + 'San Cristobal', + 'Corona', + 'Telemaco Borba', + 'Pedregulho', + 'Walajapet', + 'Kurnool', + 'Bois-Colombes', + 'Bitritto', + 'Baia Formosa', + 'Mopti', + 'Sassari', + 'General Pinedo', + 'Capim Grosso', + 'Sanok', + 'Nawashahr', + 'Radom', + 'Esbjerg', + 'Scheveningen', + 'Woodland Park', + 'Ljubno', + 'Tirkarur', + 'Mississauga', + 'Oudewater', + 'Plochingen', + 'Villa Donato Guerra', + 'Kuangfu', + 'Mabuhay', + 'Deh-e Shu', 'Anjur', - 'Narayanpur', - 'Cachoeira dos Indios', - 'Vallendar', - 'Belakvadi', - 'Razanj', - 'Buenopolis', - 'Chinnayagudem', - 'Felino', - 'Lavis', - 'Al Bardiyah', - 'Sangeorgiu de Mures', - 'Sabie', - 'Gondizalves', - 'Konduru', - 'Sansa', - 'Veinticinco de Diciembre', - 'Mangasamudram', - 'Sauzal', - 'Maserada sul Piave', - 'Japura', - 'Santa Lucia di Piave', - 'Kaithahi', - 'Bir Tam Tam', - 'Damu', - 'Sibkund', - 'Nerinjippettai', - 'Seven Corners', - 'Audubon', - 'Helotes', - 'Des Peres', - 'Cajvana', - 'Caluco', + 'Sung Noen', + 'Fife', + 'Mhangura', + 'Chalchuapa', + 'Herisau', + 'Cesis', + 'Flensburg', + 'Prado', + 'Fujisaki', + 'Winterveld', + 'Mlimba', + 'Chintakunta', + 'Marsaxlokk', + 'Munakata', + 'Corciano', + 'Sibilia', + 'Pullalacheruvu', + 'Trescore Balneario', + 'Querfurt', + 'Palestine', + 'Salta', + 'Scafati', + 'Atbara', + 'Unhel', + 'Rosenheim', + 'Khambhat', + 'Serafina Corea', + 'Guayos', + 'Ladson', + 'Martinho Campos', + 'Rondon do Para', + 'Gandajika', + 'Konigsbrunn', + 'Dabrowa Tarnowska', + 'Dudhpura', + 'Hurdiyo', + 'Vi Thanh', + 'Blaubeuren', + 'Berubari', + 'Wujiaqu', + 'Warrensville Heights', + 'Duc Pho', + 'Misungwi', + 'Jeju', + 'Diamond Springs', + 'Rabot', + 'Chateau-Gontier', + 'Culver City', + 'Chanhassen', + 'Campamento', + 'Venturosa', + 'Bom Principio', + 'Huquan', + 'Odlabari', + 'Burbage', + 'Siladon', + 'Nutley', + 'Kinzau-Vuete', + 'Ickenham', + 'Belavabary', + 'Kariyapatti', + 'Dzierzoniow', + 'North Cowichan', + 'Mine', + 'Srvanampatti', + 'Uba', + 'Monte Alegre de Sergipe', + 'Espanola', + 'Lenart v Slovenskih Goricah', + 'Hirske', + 'Nallikodur', + 'Kisara', + 'Salamanca', + 'North New Hyde Park', + 'Prudente de Morais', + 'Peragamanna', + 'Kaippakancheri', + 'Venray', + 'Kitakata', + 'Napindan', + 'Beinasco', + 'Anyksciai', + 'Piera', + 'Morab', + 'Charef', + 'Fraserburgh', + 'Maghalleen', + 'Palatine', + 'Batuan', + 'Maldegem', + 'Kalabahi', + 'Hollola', + 'Quimbele', + 'Ippy', + 'Oirschot', + 'Hrib-Loski Potok', + 'Ras el Metn', + 'Dalaba', + 'Thun', + 'Caguas', + 'Jadayampalaiyam', + 'Biaora', + 'Brno', + 'Fino Mornasco', + 'Lohagaon', + 'Silale', + 'Kouka', + 'Tulchyn', + 'Caimito', + 'Teijlingen', + 'Szczecinek', + 'Oulad Rahmoun', + 'Khat Azakane', + 'Koupela', + 'Giddalur', + 'Francisco Sa', + 'Adda-Doueni', + 'Santa Catarina Mita', + 'Nova Olimpia', + 'Sabalito', + 'Hire Vadvatti', + 'Duvva', + 'Iloilo', + 'Catalca', + 'Pribram', + 'McCalla', + 'Oleggio', + 'Lajes', + 'Entroncamento', + 'Vidapanakallu', + 'Moju', + 'East Brunswick', + 'Samalkot', + 'Birnin Konni', + 'Ipaba', + 'Sebba', + 'Joao Camara', + 'Sho`rchi', + 'De Witt', + 'Ebolowa', + 'Nandipeta', + 'Bokaro', + 'Port Glasgow', + 'Vellakkinar', + 'Goldenstedt', + 'Al Jawf', + 'Adliswil', + 'Castelnaudary', + 'Bula', + 'Swan Hill', + 'Brikcha', + 'Valkurti', + 'Lake Hopatcong', + 'Ingeniero Jacobacci', + 'Kemise', + 'Obidos', + 'Central Saanich', + 'Shioya', + 'Ulus', + 'Chicago Heights', + 'Tracy', + 'Al Matariyah', + 'Chelmza', + 'Ban Wat Chan', + 'Chelles', + 'Basni', + 'Moriya', + 'Arzignano', + 'Bharanikavu Tekku', + 'Paikpar', + 'Lake Elmo', + 'Pottanikad', + 'Gorakhpur', + 'Rose Hill', + 'Sallimedu', + 'Kearns', + 'Berehove', + 'Kidderminster', + 'Marieville', + 'Lillers', + 'Voreppe', + 'Rovenky', + 'Spittal an der Drau', + 'Vohipaho', + 'Selnica ob Dravi', + 'Musile di Piave', + 'Sado', + 'El Ancer', + 'Lamego', + 'Kaeng Khro', + 'Laguna Hills', + 'Bag', + 'Krotoszyn', + 'Makhu', + 'Kotha Guru', + 'Bandar-e Bushehr', + 'Borsbeek', + 'Manbij', + 'Mabaruma', + 'Godohou', + 'Landau an der Isar', + 'Zamboanga City', + 'Bendarhalli', + 'Vanavasi', + 'Karlovac', + 'Saraland', + 'Vaucresson', + 'Clusone', + 'Kumi', + 'Turayf', + 'Konakondla', + 'Adet', + 'Yuanhucun', + 'Iramaia', + 'Buttar Khurd', + 'New Richmond', + 'McDonough', + 'Monte Cristo', + 'Save', + 'Khutaha', + 'Erzin', + 'Lovrenc na Pohorju', + 'Tangail', + 'Tadmur', + 'Midyat', + 'Guanajay', + 'Colombes', + 'Garbsen', + 'Leribe', + 'Gamail', + 'Abu Hulayfah', + 'Azcoitia', + 'Abelardo Luz', + 'Kamavarapukota', + 'Bolongongo', + 'Paraiso', + 'Dum Duma', + 'Auckland', + 'Peterlee', + 'Turiacu', + 'Xaignabouli', + 'Huangyan', + 'Camarillo', + 'Volksrust', + 'San Jose de Guaribe', + 'Roca Sales', + 'Glogow Malopolski', + 'Tototlan', + 'Murrells Inlet', + 'Oxford', + 'Amodei', + 'Harbel', + 'Hue', + 'Kajhi Hridenagar', + 'Silvani', + 'Voorschoten', + 'Villeneuve-sur-Lot', + 'Kavaklidere', + 'Chibemba', + 'Avellino', + 'Brejinho', + 'Oulad Cherif', + 'Abra de Ilog', + 'Kurtkoti', + 'Tovala', + 'Gqeberha', + 'Almoloya', + 'Sao Joao do Paraiso', + 'Pella', + 'Zabre', + 'Higashimatsushima', + 'Fairland', + 'Arambakkam', + 'Skvyra', + 'Lamacaes', + 'Lumbreras', + 'Campbelltown', + 'Anoviara', + 'Jurawanpur Karari', + 'Imatra', + 'Medford', + 'Ban Phan Don', + 'Marietta', + 'Pennagaram', + 'Rotselaar', + 'Tezze sul Brenta', + 'Ponnada', + 'Golmud', + 'Ehningen', + 'Amambai', + 'Princeton', + 'Tepeji del Rio de Ocampo', + 'Mosonmagyarovar', + 'Tianguistengo', + 'Mongagua', + 'Elkhorn', + 'Langenthal', + 'Mehrabpur', + 'Obra', + 'Kabo', + 'Ban Mueang Nga', + 'Nga Bay', + 'Kannankurichchi', + 'Bayou Blue', + 'Et Tira', 'Solita', - 'Copceac', - 'Lagbe', - 'Pleternica', - 'Dihri', - 'Bhargaon', - 'Forestdale', - 'Huron East', - 'Stryzhavka', - 'Bilenke', - 'Laufenburg (Baden)', - 'Pepillo Salcedo', - 'Guano', - 'Gavirate', - 'Ipuiuna', - 'Tecoh', - 'Ban Wang Krachae', - 'Nagykallo', - 'Tafersit', - 'Ciudad Insurgentes', - 'Cajobi', - 'Malingaon', - 'North Codorus', - 'West Athens', - 'Dazhuangzi', - 'Haddington', - 'Yenmangandla', - 'Govindapalle', - 'Malalbergo', - 'Perkasie', - 'Mwaline al Oued', - 'Lanta', - 'Mokri', - 'Mendig', - 'Jandola', - 'San Manuel Chaparron', - 'Masera di Padova', - 'Elsmere', - 'Denekamp', - 'Montoro', - 'Umburetama', - 'Crawford', - 'Marlboro Village', - 'Amatlan de los Reyes', - 'Hostivice', - 'Shanklin', - 'Middlebury', - 'Chtiba', - 'Peresecina', - 'Olesno', - 'Chitrada', - 'Nandiyalam', - 'Currumbin', - 'Rothrist', - 'Guatape', - 'Tettu', - 'Temperance', - 'Sunset Hills', - 'Piranguinho', - 'Palocabildo', - 'Groenlo', - 'Dodji-Bata', - 'Bamaiya Harlal', - 'Killimangalam', - 'Bad Schussenried', - 'Kongnolli', - 'East Grand Forks', - 'Hurzuf', - 'Alawandi', - 'Kaglipur', - 'Koheda', - 'Dospat', - 'Sauce', - 'Phagu', - 'Sihali Jagir', - 'Eshkanan', - 'Miramar Beach', - 'Kuduru', - 'Istrana', - 'Horodenka', - 'Mata Verde', + 'Bauchi', + 'Uribia', + 'Painkulam', + 'Calkini', + 'Sanchor', + 'Zoersel', + 'Tomiya', + 'Huvin Hippargi', + 'Teodoro Sampaio', + 'Lambton Shores', + 'Tissemsilt', + 'Kolding', + 'Quillacollo', + 'Tenosique', + 'Birnagar', + 'Laeken', + 'Talant', + 'Richterswil', + 'Kundgol', + 'Vitry-sur-Seine', + 'Conwy', + 'Oqtosh Shahri', + 'Yellapur', + 'Kumbakonam', + 'Jizhou', + 'Visoko', + 'Kassala', + 'Bloemendaal', + 'Perl', + 'Kaniv', + 'Ensenada', + 'Armavir', + 'Hirnyk', + 'Turgutalp', + 'Gaoual', + 'Mazzarino', + 'Batley', + 'Trichinopoly', + 'Ban Kang', + 'Manado', + 'Gerstetten', 'Nechmeya', - 'Pattiswaram', - 'Tunari', - 'Zeydabad', - 'Fujisawacho-niinuma', - 'Montes Altos', - 'Beuvry', - 'Hawthorn Woods', - 'Zarbdor Shaharchasi', - 'Andre Fernandes', - 'Reinfeld', - 'Miryal', - 'Odayarpatti', - 'Herenthout', - 'Carmen de Carupa', - 'Chotebor', - 'Prabhat Pattan', - 'Fairless Hills', - 'Flemington', - 'Brejolandia', - 'Loeches', - 'Uchti', - 'Satghara', - 'Weare', - 'Embalse', - 'San Zenon', - 'Tekpanja', - 'Steynsrus', - 'Rebordosa', - 'Govindapuram', - 'Kod', - 'Cresskill', - 'Westampton', - 'Chaukhata', - 'Belek', - 'Datian', - 'Oborniki Slaskie', - 'Cameron', - 'Benton Harbor', - 'Iguidiy', - 'Hirske', - 'Katakwi', - 'Nalbach', - 'Usworth', - 'Gok', - 'Orosi', - 'Ouedeme', - 'Consaca', - 'Rivesaltes', - 'Guryongpo', - 'Rada Tilly', - 'Rincao', - 'McCordsville', - 'Rondon', - 'Ambara', - 'Tineo', - 'Urbach', - 'Coatetelco', - 'Fehrbellin', - 'Pithiviers', - 'Sogam', - 'Zeerust', + 'Khan Yunis', + 'Anatuya', + 'Sosale', + 'Nindiri', + 'Uzwil', + 'Kesli', + 'Srbobran', + 'Jacmel', + 'Malibu', + 'Mulongo', + 'Balehonnur', + 'Froyland', + 'Vernal', + 'Kollegal', + 'San Juan', + 'Wayland', + 'Sirdala', + 'Redwood City', + 'Patalia', + 'Lycksele', + 'Alcantaras', + 'Majdal Shams', + 'Villa de San Diego de Ubate', + "Sa-ch'on", + 'Jalakandapuram', + 'Husum', + 'Coral Terrace', + 'Chropaczow', + 'Khalari', + 'Talence', + 'Arroyo Naranjo', + 'Gundrajukuppam', + 'Hinis', + 'Luoyang', + 'Argenteuil', + 'Dnipro', + 'Zajecar', + 'Usgao', + 'Serra Branca', + 'Hunduan', + 'Anosipatrana', + 'Constantina', + 'Sirur', + 'Bandar Seri Begawan', + 'Zavrc', + 'Rampur Parhat', + 'Saito', + 'Jurupa Valley', + 'Pedras de Fogo', + 'Kalymnos', + 'Jerissa', + 'Beni Khiar', + 'Ginebra', + 'Recco', + 'Kanajanahalli', + 'Miani', + 'Rionegro', + 'Honavar', + 'Bolu', + 'Shepherdsville', + 'Babura', + 'Vilnohirsk', + 'Saint-Loubes', + 'Machados', + 'Roselle', + 'Valle de Bravo', + 'Stoke Gifford', + 'Settiyarpatti', + 'Citrus Heights', + 'Amityville', + 'Muntinlupa City', + 'Poco Branco', + 'Ciudad Cortes', + 'Muncie', + 'Ballenstedt', + 'Kipushi', + 'Simri', + 'Satrovka', + 'Parasi', + 'Dumra', + 'Tha Luang', + 'Galatina', + 'Chiampo', + 'Robinson', + 'Chelsfield', + 'Hersbruck', + 'Ambodivoanio', + 'Carache', + 'Hagfors', + 'Hazlet', + 'Luchong', + 'Maili', + 'Kiangara', + 'Dengtacun', + 'Tuodian', + 'Prudhoe', + 'Codogno', + 'Philippeville', + 'Agsu', + 'Onomichi', + 'Kajiado', + 'Louang Namtha', + 'Sobral', + 'Hermosa', + 'Ouargla', + 'Welwyn Garden City', + 'Niel', + 'San Ramon', + 'Eutin', + 'Patarra', + 'Plainview', + 'Iioka', + 'Shamshernagar', + 'Ravanusa', + 'Madha', + 'Mmadinare', + 'Rawalpindi', + 'Calcinaia', + 'Chak Pahar', + 'Sunbury', + 'Cruzeiro do Oeste', + 'Pemberton', + 'Putian', + 'Sapucaia', + 'Worpswede', + 'Anaheim', + 'Tupancireta', + 'Lyaskovets', + 'Setouchi', + 'Tanay', + 'Takerbouzt', + 'Tarabuco', + 'Volpago del Montello', + 'Al `Arish', + 'Foley', + 'Avion', + 'Dina', + 'Kazerun', + 'Tuljapur', + 'Tocuyito', + 'Arakawa', + 'Sao Jose do Rio Preto', + 'Labuan', + 'Kadama', + 'Kollo', + 'Nieuwkoop', + 'Butalangu', + 'Haeryong', + 'Minbu', + 'Nobeoka', + 'Heunghae', + 'Chaidari', + 'Hoa Thuong', + 'Oelde', + 'Finote Selam', + 'Valayam', + "O'Fallon", + 'Araquari', + 'Nazaria', + 'Hofgeismar', + 'Masaya', + 'Saarlouis', + 'Schluchtern', + 'Mankara', + 'Mersa', + 'Sioux Falls', + 'Altinopolis', + 'South Plainfield', + 'Eccleston', + 'Louangphabang', + 'Kudachi', + 'Outjo', + 'Arluno', + 'Almus', + 'Zehak', + 'Elsenfeld', + 'Garag', + 'Agano', + 'Ferndale', + 'Yui', + 'Kasba Maker', + 'Krakow', + 'Aghbalou Aqourar', + 'Zakynthos', + 'Zhuchangba', + 'Tan Van', + 'Xiezhou', + 'Cinisi', + 'Drogheda', + 'Balurghat', + 'San Sebastian de los Reyes', + 'Kavaratti', + 'Egirdir', + 'Tolentino', + 'Iwanai', + 'Bhongir', + 'Nuzvid', + 'Amaha', + 'Jemaat Oulad Mhamed', + 'Karlovy Vary', + 'Kengri', + 'Khawaspur', + 'Palm Bay', + 'Murungattoluvu', + 'Autlan de Navarro', + 'Bursa', + 'Bruhl', + 'Montemor-o-Velho', + 'Berbera', + 'Mattoon', + 'Mboro', + 'Texcaltitlan', + 'Ellicott City', + 'Banbridge', + 'Bandipur', + 'Talakkad', + 'Ostroda', + 'Imphal', + 'Porto Belo', + 'Chattanooga', + 'Cogan', + 'Oued el Kheir', + 'Girard', + 'Tongshan', + 'Bhogapuram', + 'Cabanglasan', + 'Caleta Olivia', + 'Lozovo', + 'Hythe', + 'Izra', + 'Toba', + 'Sipocot', + 'Borgosatollo', + 'Messina', + 'Manadhoo', + 'Jumri Tilaiya', + 'Ollerton', + 'Riverhead', + 'Dinguiraye', + 'Salehpur', + 'Horizon City', + 'Tettuppatti', + 'Manorville', + 'Gumaca', + 'Barpathar', + 'Ankasakasabe', + 'Rio Caribe', + 'Mutare', + 'Kiramangalam', + 'Voorst', + 'El Ancor', + 'Marsta', + 'Wombourn', + 'Bagong Silangan', + 'Mogiyon', + 'Maracaibo', + 'Amay', + 'Ostrow Wielkopolski', + 'Herent', + 'Yecla', + 'Barrington', + 'Cananeia', + 'Crowborough', + 'Kandori', + 'Toconao', + 'Cazombo', + 'Basel', + 'Halavagalu', + 'Baile an Bhiataigh', + 'Baraboo', + 'Kambla', + 'Hung Yen', + 'Sun City Center', + 'Panniperumthalai', + 'Gwacheon', + 'Hikawa', + 'Zamora', + 'Las Lajas', + 'Dan Gorayo', + 'Racale', + 'La Paloma', + 'Kon Tum', + 'Oloron-Sainte-Marie', + 'Piacabucu', + 'Bourke', + 'Piraeus', + 'Ciudad Benito Juarez', + 'Peje', + 'Sagar', + 'Sivagiri', + 'Biyahmu', + 'Vianopolis', + 'Curitiba', + 'Larkspur', + 'Harenkarspel', + 'Reghin', + 'Kapchorwa', + 'Hohenau', + 'Villa Alsina', + 'Tagami', + 'We', + 'Lac des Oiseaux', + 'Pariharpur', + 'Volodymyrets', + 'Areraj', + 'Chupinguaia', + 'Anantpur', + 'Gif-sur-Yvette', + 'Bronkhorstspruit', + 'Krimpen aan den IJssel', + 'Rock Island', + 'Ban Huai So Nuea', + 'Barcellona-Pozzo di Gotto', + 'Tumbippadi', + 'Pontoise', + 'Bandar Emam', + 'Reconquista', + 'Braniewo', + 'Vettaikkaraniruppu', + 'Ancuabe', + 'Hitachi', + 'Malolos', + 'Ngaparou', + 'Bayamon', + 'Abyek', + 'Tlahuiltepa', + 'Lugano', + 'Crispiano', + 'Padre Hurtado', + 'Wlodawa', + 'Placheri', + 'General Martin Miguel de Guemes', + 'Yangyuhe', + 'La Chapelle-Saint-Mesmin', + 'Darmanesti', + '`Ayn al `Arab', + 'Yorkshire', + 'Calcinato', + 'Sadiqpur Maraul', + 'Tadley', + 'Nkokonjeru', + 'Fatime', + 'Selby', + 'Kafr Ruma', + 'South Brunswick', + 'Yahotyn', + 'North Grenville', + 'Mahajjah', + 'Wangyuanqiao', + 'Hrastnik', + 'Luckenwalde', + 'Kalaiya', + 'Matagalpa', + 'Bulbula', + 'Shirva', + 'Nogoya', + 'Leulumoega', + 'San Diego Country Estates', + 'Magong', + 'Kourouma', + 'Vorkadi', + 'Shibuya', + 'Madathapatti', + 'Cilegon', + 'Betun', + 'Mantes-la-Jolie', + 'Tokar', + 'Medog', + 'Medleri', + 'El Viso del Alcor', + 'Sao Joaquim de Bicas', + 'Cyuve', + 'Igarapava', + 'Hamilton Township', + 'Baldock', + 'Evren', + 'Sangarebougou', + 'Sohagpur', + 'Razua', + 'Naurhiya', + 'Tromsdalen', + 'Mairipora', + 'Yesilyurt', + 'Malacatancito', + 'Szydlowiec', + 'Masiaboay', + 'Taozhuangcun', + 'Gongyefu', + 'Qiziltepa', + 'Pivnichne', + 'Anandpur', + 'Machinga', + 'Irmo', + 'Guntapalli', + 'Indang', + 'Baetov', + 'Sarvar', + 'Eberbach', + 'Douar Oulad Driss', + 'Tanagura', + 'Ikare', + 'Yumurtalik', + 'Kapuvar', + 'Margraten', + 'General Las Heras', + 'Yinhua', + 'Badnawar', + 'Grao Mogol', + 'Dalja', + 'Abensberg', + 'Roque Perez', + 'Rustampur', + 'Cajati', + 'Sarso', + 'Samadh Bhai', + 'Azazga', 'Kenar', - 'Bonnievale', - 'La Matanza de Acentejo', - 'Davuluru', - 'Nagaoki', - 'Bemarivo', - 'Logatec', - 'Suances', - 'Greytown', - 'Ouaregou', - 'Portlethen', - 'Kiskunlachaza', - 'Koila Belwa', - 'Yeldurti', - 'Huntertown', - 'Marinka', - 'August', - 'Mendon', - 'Dasaut', - 'Hokur Badasgom', - 'Haripura', - 'Sidi Ouassay', - 'Paraparaumu Beach', - 'New Scotland', - 'Kozuchow', - 'Bimawan', - 'Absecon', - 'Olalapadi', - 'Mauji', - 'Yui', - 'Beecher', - 'Gtarna', - 'Majhaulia', - 'Periyamuttur', - 'Hussepur', - 'Daita', - 'Velampatti', - 'Hooper', - 'Brejao', - 'Bageshwar', - 'Andiyappanur', - 'Dinnington', - 'Mirzanagar', - 'Banaruyeh', - 'Kanasanapalle', - 'Gurmia', - 'Carignano', - 'Ban Tha Phra', - 'Mainaschaff', - 'Jamunia', - 'Karayilan', - 'Mendicino', - 'Jumla', - 'Grossbeeren', - 'Pontardulais', - 'Suganwan', - 'Fiumefreddo di Sicilia', - 'Notodden', - 'Kirchberg', - "Mosciano Sant'Angelo", - 'Sinaia', - 'Sibilia', - 'Pedda Mupparam', - 'Marai Kalan', - 'Mbuzini', - 'Luis Gomes', - 'Hagaranahalli', - 'Townsend', - 'Fatehpur Bala', - 'Valley Cottage', - 'Nykobing Mors', - 'Viravada', - 'Gidha', - 'Ghat Borul', - 'Vinhais', - 'Carregado', - 'Paulo Lopes', - 'Morada Nova de Minas', - 'Chalastra', - 'Amal', - 'Puttai', - 'Orte', - 'Berndorf', - 'Adjido', - 'Iquira', - 'Magny-le-Hongre', - 'Venkatadripalem', - 'Oggiono', - 'Economy', - 'Ewo', - 'Campobello di Licata', - 'Sarauni', - 'Wollert', + 'Ealing', + 'Versailles', + 'Kalima', + 'Stillorgan', + 'Portao', + 'Kwinana', + 'Gemena', + 'Oulad Chikh', + 'Arslanbob', + 'Sumenep', + 'Kleppe', + 'Anisoc', + 'Chapel Hill', + 'Timisoara', + 'Saint-Denis', + 'Temescal Valley', + 'Alayor', + 'Siuri', + 'Puerto Colombia', + 'San Andres Timilpan', + 'Tadjenanet', + 'La Londe-les-Maures', + 'Tivaouane', + 'Singaraja', + 'Frisco', + 'Pozzuoli', + 'Robe', + 'Kutina', + 'Escoublac', + 'Ginosa', + 'Weil im Schonbuch', + "Jeffrey's Bay", + 'Emporia', + 'Arbaoua', + 'Saint-Augustin-de-Desmaures', + 'Asslar', + 'Bischofshofen', + 'Vakhsh', + 'Upper Macungie', + 'Karpuzlu', + 'Dattapara', + 'Vaikuntam', + 'Haverhill', + 'Craiova', + 'Santo Amaro da Imperatriz', + 'Orpington', + 'Tibri', + 'Arlov', + 'Luwuk', + 'Pipra Naurangia', + 'Yingkou', + 'Sidi Okba', + 'Torrox', + 'Toki', + 'Matera', + 'Cristinapolis', + 'Ivano-Frankivsk', + 'Ramu', + 'Mangawan', + 'Ishioka', + 'Leones', + 'Mougins', + 'Maco', + 'Hanko', + 'Backnang', + 'Bakamune', + 'Gubbi', + 'Bazhou', + 'Guangzhou', + 'Badajoz', + 'Masdi', + 'Estcourt', + 'Kale', + 'Amaraji', + 'Guire', + 'Mesa', + 'Utebo', + 'Al Khawr', + 'Pararia', + 'Hapur', + 'Maigo', + 'Grimmen', + 'Saratoga Springs', + 'Villejuif', + 'Tucapel', + 'Zhoujiajing', + 'Nicosia', + 'Tirumalaiyampalaiyam', + 'Tamorot', + 'Radford', + 'Ambarakaraka', + 'Maragogipe', + 'Mettlach', + 'Nautla', + 'Nuevo Paysandu', + 'Kuppachchipalaiyam', + 'Steinbach am Taunus', + 'Calverton', + 'Ainring', + 'Olanchito', + 'Calayan', + 'Girardota', + 'Salem Lakes', + 'South Houston', + 'Maharajpur', + 'Saboya', + 'San Jose de Maipo', + 'Chennimalai', + 'Kecioren', + 'Auchi', + 'Elk Plain', + 'Galbois', + 'Shuilin', + 'Malabuyoc', + 'Buyuk Cakirman', + 'Rishra', + 'Aruja', + 'Piata', + 'Uvira', + 'Sohana', + 'Garmdarreh', + 'Wulingshancun', + 'Nijoni', + 'Kudlu', + 'Braunfels', + 'Attappampatti', + 'Pedana', + 'Guayaquil', + 'Crotone', + 'Anse a Pitre', + 'Svishtov', + 'Couzeix', + 'Seinajoki', + 'Schagen', + 'Weatherford', + 'Hidaka', + 'Klazienaveen', + 'Al Harah', + 'Qabb Elias', + 'Al Fashn', + 'Berja', + 'Prieska', + 'Ban Son Loi', + 'Togo', + 'Asagiri', + 'Zafferana Etnea', + 'The Bottom', + 'Kannapolis', + 'Ussel', + 'Nukus', + 'Susehri', + 'Yawata-shimizui', + 'Bhayala', + 'Leagrave', + 'Hermitage', + 'Seynod', + 'Lubawa', + 'Gran', + 'Nazerabad', + 'Shenzhen', + 'Lone Tree', + 'Birecik', + 'Ikongo', + 'Amudalavalasa', + 'Rajgarh', + 'Xalpatlahuac', + 'Lunga-Lunga', + 'Haubourdin', + 'Ambolomoty', + 'Nyamata', + 'Sukhsena', + 'Wanzleben', + 'Brazopolis', + 'Pupiales', + 'Smederevo', + 'Bischofsheim', + 'Mato Verde', + 'Jawhar', + 'Shiraoi', + 'Huanghuajing', + 'San Rafael Arriba', + 'Freienbach', + 'Edegem', + 'Sao Sebastiao de Lagoa de Roca', + 'Yangirabot', + 'Chhapera', + 'Izu', + 'East St. Louis', + 'Chegur', + 'Naawan', + 'Shuangxianxiang', + 'Kalamaria', + 'Shangzhi', + 'Bardiha Turki', + 'Alfeld', + 'Sacele', + 'Pereira Barreto', + 'Tiptree', + 'Bala Koh', + 'Buyende', + 'Macuspana', + 'Gediz', + 'Tocancipa', + 'Taneichi', + 'Makabana', + 'Richland Hills', + 'Puerto Limon', + 'Dighwara', + 'Radovis', + 'Hobbs', + 'Quinchia', + 'Santa Catarina Masahuat', + 'Roquetas de Mar', + 'Willowick', + 'Chahana', + 'Samai', + 'Tasiilaq', + 'Anao-aon', + 'Kattanam', + 'Derbisek', + 'Changuinola', + 'Schwalmstadt', + 'Camposampiero', + 'Mayumba', + 'Raipur', + 'Stanmore', + 'Wesseling', + 'Poldasht', + 'Keora', + 'Hettstedt', + 'Kihoku', + 'Cabimas', + 'Stadthagen', + 'Gorontalo', + 'Cherial', + 'Khonobod', + 'Barntrup', + 'Bhojpur Kadim', + 'Jaltenco', + 'Attendorn', + 'Andranovory', + 'Binche', + 'Muscat', + 'Ludwigsburg', + 'Ain Zora', + 'Dabutou', + 'Landgraaf', + 'Kaunas', + 'Sandwa', + 'Dingolfing', + 'Rothenbach an der Pegnitz', + 'Sheghnan', + 'Mawai', + 'Sunnyside', + 'Esteio', + 'Carnoustie', + 'Sakura', + 'Monte Compatri', + 'Rize', + 'Walvisbaai', + 'Gouande', + 'Bardipuram', + 'Rockford', + 'Pipra Dewas', + 'Jagdishpur', + 'Sonwan', + 'Bridgewater', + 'Akpassi', + 'Zoumi', + 'Tongchuanshi', + 'Guagua', + 'Ayacucho', + 'Lom', + 'Wang Sombun', + 'Pran Buri', + 'Rass el Djebel', + 'Pita', + 'Ait Hani', + 'Saraikela', + 'Cepagatti', + 'Monte Patria', + 'Bessemer', + 'Santa Juliana', + 'Obuse', + 'Schilde', + 'Varel', + 'Almhult', + 'Wesel', + 'Xanten', + 'Bastogne', + 'Glyka Nera', + 'Tasova', + 'Rampur Shamchand', + 'Maarssen', + 'La Asuncion', + 'Streaky Bay', + 'Ridgefield Park', + 'Tichi', + 'Busuanga', + 'Arakvaz-e Malekshahi', + 'Ban Bong Tai', + "Vel'ke Kapusany", + 'Maracas', + 'Rio das Flores', + 'Moers', + 'Bexleyheath', + 'Savsat', + 'Morsott', + 'Germersheim', + 'Pungulam', + 'Sussex', + 'Bilwi', + 'Abare', + 'El Tumbador', + 'Guebwiller', + 'Bourg-en-Bresse', + 'Koskapur', + 'Orvieto', + 'Quartz Hill', + 'Espita', + 'Vechelde', + 'Banting', + 'Cancun', + 'Humahuaca', + 'Hockley', + 'Barwan', + 'Gravesend', + 'Palhalan', + 'Galway', + 'Shotley Bridge', + 'Guioyo', + 'Xaxim', + 'Dunkirk', + 'Amreli', + 'Balqash', + 'Buruanga', + 'Nachchandupatti', + 'Nejo', + 'Lumba-a-Bayabao', + 'Harri', + 'Gaoliying Ercun', + 'Erumakkuzhi', + 'Campina Grande', + 'Palimbang', + 'Al Jabayish', + 'Gurdaspur', + 'Spaichingen', + 'Le Pontet', + 'Villiers-sur-Marne', + 'Doruma', + 'Isa', + 'Puerto San Jose', + 'Gunupur', + 'Salcea', + 'Maruttuvakkudi', + 'Nsanje', + 'Mahamda', + 'Pola de Siero', + 'Radenci', + 'Chincha Alta', + 'Ed Damazin', + 'Red Bank', + 'Whitehaven', + 'Oulad Driss', + 'Edinburg', + 'Floresta', + 'Vili', + 'Saghar Sultanpur', + 'Salon-de-Provence', + 'Batufah', + 'Dalkola', + 'Fostoria', + 'Yauco', + 'Maridi', + 'Nueva Imperial', + 'Saint-Jean-sur-Richelieu', + 'Tupaciguara', + 'Palmdale', + "Notre-Dame-de-l'Ile-Perrot", + 'Rio Largo', + 'Ntossoni', + 'Nagnur', + 'Wallkill', + 'Breda', + 'Solindabad', + 'Penkridge', + 'Agui', + 'George Mason', + 'Aliartos', + 'Itatinga', + 'Tekkampatti', + 'Turicato', + 'Chorleywood', + 'Grootfontein', + 'Kassa', + 'Kotli', + 'Sayreville', + 'Kottavalasa', + 'North Plainfield', + 'Madanapalle', + 'Santa Eulalia', + 'Farnborough', + 'Lerwick', + 'Rohar', + 'Holalkere', + 'Gavirate', + 'Pace', + 'Bharokhara', + 'Oraiokastro', + 'Senekane', + 'Ambohitrarivo', + 'Regente Feijo', + 'Ambotaka', + 'El Crucero', + 'Gummudipundi', + 'Romilly-sur-Seine', + 'Tanggemu Nongchang', + 'Chubek', + 'Quattro Castella', + 'Sai Buri', + 'Piuma', + 'Cerveteri', + 'West Rancho Dominguez', + 'Carmona', + 'Santa Maria', + 'Cayiralan', + 'Wennigsen', + 'Batalha', + 'Vatican City', + 'Bahrain', + 'Tenente Ananias Gomes', + 'Lusambo', + 'Angra dos Reis', + 'Pilkhua', + 'San Marcelino', + 'Kuching', + 'Moche', + 'Straza', + 'Ban Ueam', + 'Kibale', + 'Shahdadpur', + 'West Long Branch', + 'Killai', + 'Chandia', + 'Los Teques', + 'Hpa-An', + 'Wenden', + 'Sao Bento', + 'Wentorf bei Hamburg', + 'Farajok', 'Uppugunduru', - 'Strehaia', - 'Scionzier', - 'Harrodsburg', - 'Country Club Estates', - 'Roxborough Park', - 'Lacchiarella', - 'Toccoa', - 'Northwest Harborcreek', - 'Chaponost', - 'Januario Cicco', - 'Udarband', - 'Ayanikkad', - 'Salto Grande', - 'Bonhill', - 'Lanark', - 'Kegen', - 'Bemiss', - 'Colac', - "Intich'o", - 'Mohon', - 'Manoke', - 'Poiana Mare', - 'Mamnur', - 'Borgosatollo', - 'Orange Park', - 'Abu Khashab', - 'Khasbalanda', - 'Livno', - 'Zwiesel', - 'Banire Kore', - 'Berching', - 'Harahan', - 'Andilana Avaratra', - 'La Ravoire', - 'Janhapara', - 'Fossombrone', - 'Breckerfeld', - 'Podenzano', - 'Ban Ngio Ngam', - 'Santa Sylvina', - 'Leven', - 'Warkan', - 'Dadrewa', - 'Old Orchard Beach', - 'Charakunda', - "Monteroni d'Arbia", - 'Iijima', - 'Meridiala', - 'Travis Ranch', - 'Beregadougou', - 'Aadorf', - 'Tajpur', - 'Villa Castelli', - 'Nova Paka', - 'Bockhorn', - 'Breinigsville', - 'Adami Tulu', - 'Gohi Bishunpur', - 'Lapeer', - 'Waldheim', - 'Ksar Belezma', - 'North Merritt Island', - 'Cayirli', - 'Westerland', - 'Doberlug-Kirchhain', - 'Furth im Wald', - 'Bougival', - 'Les Sorinieres', - 'Porto Tolle', - 'Dunbar', - 'Nanzhuang', - 'Monticello Conte Otto', - 'Tuscumbia', - 'Velyki Luchky', - 'Nhan Trach', - 'Kurichedu', - 'Kannal', - 'Katsuyama', - 'Booneville', - 'Pullach im Isartal', - 'Hemmoor', - 'Pivnichne', - 'Sint-Martens-Lennik', - 'Rampur Khajuriya', - 'Ampasimpotsy-Gara', - 'Ceelbuur', - 'Coqueiral', - 'Manatuto', - 'Barwell', - 'Sahapur', - 'Odzaci', - 'Zalishchyky', - 'Beckwith', - 'Arico el Nuevo', - 'Blairgowrie', - 'Cupar', - 'Nadol', - 'Bala Cynwyd', - 'Muhos', - 'Tomblaine', - 'Kaniwara', - 'Foiano della Chiana', - 'Moman Barodiya', - 'Ban Wang Pradu', - 'Karliova', - 'Mandishah', - 'Babai Kalan', - 'Aplao', - 'Estanzuelas', - 'Coronel Du Graty', - 'Dhauni', - 'Madhurapur', - 'Basdeopur', - 'Hatti Mattur', - 'Akat Amnuai', - 'Treia', - 'Craig', - 'Kaeng Khro', - 'Mburucuya', - 'Harua', - 'Gerstungen', - 'Labrador City', - 'Brand-Erbisdorf', - 'Moranha', - 'Blacklick Estates', - 'Kasane', - 'Rio del Mar', - 'Tutrakan', - 'Mishrikot', - 'Perondi', - 'Seneca Falls', - 'Rafard', - 'Furtwangen im Schwarzwald', - 'Le Teich', - 'Venturina', - 'Lunner', - 'Tha Luang', - 'Chanco', - 'Kambaneri Pudukkudi', - 'Crvenka', - 'Lago Vista', - 'Ain el Mediour', - 'Chitcani', - 'Maropaika', - 'Soamahamanina', - 'Ambodivoanio', - 'Tsimafana', - 'Sahatsiho-Ambohimanjaka', - 'Ranopiso', - 'Ivandrika', - 'Marotolana', - 'Ambatoria', - 'Lanivo', - 'Sarasambo', - 'Antambohobe', - 'Ambalajia', - 'Nato', - 'Mahamaibe', - 'Mitanty', - 'Salobe', - 'Ambariokorano', - 'Vatananto', - 'Iara', - 'Ampary', - 'Ambalaromba', - 'Soamanonga', - 'Bemaharivo', - 'Anteza', - 'Bekopaka', - 'Antaly', - 'Anjialava', - 'Ankarana-Miraihina', - 'Antsaidoha-Bebao', - 'Nosibe', - 'Soanierana', - 'Soanenga', - 'Manampaneva', - 'Manja', - "Ambinanin' Andravory", - 'Belinta', - 'Marovatolena', - 'Antseza', - 'Andribavontsona', - 'Antanankambano', - 'Alakamisy-Ambohimahazo', - 'Benato-Toby', - 'Ankirihitra', - 'Antsatramidola', - 'Amboronabo', - 'Manevy', - 'Beparasy', - 'Tandrano', - 'Ambarimaninga', - 'Ambodimahabibo', - "'s-Gravendeel", - 'Dhiban', - 'Dahbed', - 'Qahramon', - 'Lo Miranda', - 'Bovingdon', - 'Diabugu', - 'Jangalapalli', - 'Urpaar', - 'Lohara', - 'Rohera', - 'Ugamedi', - 'Carneiros', - 'Marcacao', - 'Puerto Octay', - 'Patut', - 'Hetanpur', - 'Kalicherla', - 'Rarz', - 'San Pedro Atocpan', - 'Mbamba Bay', - 'Neuotting', + 'Samkir', + 'Samraong', + 'Pind Dadan Khan', + 'Rajmahal', + 'Paz de Ariporo', + 'Rincon de la Victoria', + 'Vyshhorod', + 'Khaniadhana', + 'Fuxing', + 'Xibang', + 'Antanananivo', + 'Peekskill', + 'Kanhauli Manohar', + 'Kengtung', + 'Yahyali', + 'Yecun', + 'Albolote', + 'Etrotroka', + 'Robstown', + 'Bacoli', + 'Godfrey', + 'Savastepe', + 'Netphen', + 'Cam', + 'Moortebeek', + 'Koufalia', + 'Tabatinga', + 'Qadirganj', + 'Tlanchinol', + 'Kokopo', + 'Parelhas', + 'Bergkamen', + 'Crossville', + 'Charallave', + 'Mahugaon', + 'Tazhakudi', + 'Nawa Nagar Nizamat', + 'Rizhao', + 'Bilasipara', + 'Kfar Aabida', + "E'erguna", + 'Rio Branco', + 'Buique', + 'Maesawa', + 'Rabak', + 'Noqui', + 'Maxcanu', + 'Otegen Batyr', + 'Nellipoyil', + 'Oakville', + 'Serowe', + 'Conselheiro Pena', + 'Ban Fang Tuen', + 'Santa Isabel', + 'Sukhasan', + 'Ocos', + 'Cai Lay', + 'Mangamila', + 'Sikar', + 'Ogoshi', + 'Wimbledon', + 'Islam Qal`ah', + 'Iawar', + 'Kuala Lipis', + 'Gressier', + 'South Laurel', + 'Greendale', + 'Ilfracombe', + 'Prestonpans', + 'Stonegate', + 'Willich', + 'Forssa', + 'Enghien-les-Bains', + 'Balintawak', + 'Kitgum', + 'Pucallpa', + 'Bhilai Karanja', + 'Uzundere', + 'Boshof', + 'Maradi', + 'Bekasi Kota', + 'Mission', + 'Lecherias', + 'Valverde del Camino', + 'Bojaca', + 'Khowai', + 'Heerlen', + 'Bucyrus', + 'Ipameri', + 'Kadaiyam', + 'Guanagazapa', + 'Lencois', + 'Riosucio', + 'Sredets', + 'Rio de Janeiro', + 'Peringuzha', + 'Rabat', + 'Kupang', + 'Louis Trichardt', + 'Tlalixtac de Cabrera', + 'Quincy', + 'Kerrville', + 'Khandala', + 'Waconia', + 'Aventura', + 'Mahabad', + 'Ciudad Miguel Aleman', + 'Al Hamdaniyah', + 'Mankur', + 'Dumbea', + 'Sungailiat', + 'Huitan', + 'Naubatpur', + 'Soubre', + 'Kaniama', 'Dholbaja', - 'Novyi Svit', - 'Zschopau', - 'Almusafes', - 'Hirehaluhosahalli', - 'Lake Park', - 'Glens Falls North', - 'Guichen', - 'Rajod', - 'Pomichna', - 'Panasapadu', - 'Druento', - 'Lamorlaye', - 'Settivaripalle', - 'Peddannavaripalle', - 'Ixtapa Zihuatanejo', - 'Podu Iloaiei', - 'Perl', - 'Veauche', - 'Harleysville', - 'Saffle', - 'Icaraima', - 'Devanangurichchi', + 'Kuala Kapuas', + 'Oplotnica', + 'Rampur Hat', + 'Sangaree', + 'Fatoma', + 'El Arba Des Bir Lenni', + 'Huamantla', + 'Enamadala', + 'Alibunar', + 'Madirovalo', + 'Bampur', + 'Karachi', + 'Lehi', + 'Cross Lanes', + 'Abou el Hassan', + 'Telwa', + 'Ga-Kgapane', + 'Navraftor', + 'Janapadu', + 'Garesnica', + 'Awantipur', + 'El Fanar', + 'Ayyampettai', + 'Shangzhuangcun', + 'Gainesville', + 'Santanopolis', + 'La Goulette', + 'Chiknayakanhalli', + 'Murtosa', + 'Tirano', + 'Heckmondwike', + 'Mantenopolis', + 'Villa Corzo', 'Gacko', - 'Kandra', - 'Rice Lake', - 'Had Dra', - 'Apahida', - 'Kozova', - 'Iscuande', - 'Gudluru', - 'Chundale', - 'Shelburne', - 'Ardooie', - 'Togou', - 'Dulce Nombre de Maria', - 'Santana do Manhuacu', - 'Wenzenbach', - 'Kanchanpalli', - 'East Nottingham', - 'Foum Zguid', - 'Urdinarrain', - 'Bassenge', - 'Denbigh', - 'Hirayama', - 'Kosum Phisai', - 'Arboledas', - 'Telaprolu', - 'Almargem', - 'Tiou', - 'Seydunganallur', - 'Puerto Lleras', - 'Hilzingen', - 'Khiriawan', - 'Pulaski', - 'Yaprakli', - 'Brooksville', - 'Lopatcong', - 'San Francisco Ixhuatan', - 'Acobamba', + 'Etterbeek', + 'Dargot', 'Kattamuru', - 'Bayabas', - 'Akpassi', - 'Hosuru', - 'Sanganakallu', - 'Pulimakkal', - 'Taber', - 'Huasco', - 'Sarzeau', - 'Pedda Pendyala', - 'Higuera de Zaragoza', - 'Leisure World', - 'Uspenka', - 'Ponnada', - 'Bhirua', - 'Barwan', - 'Grabels', - 'Iseo', - 'Saline', - 'Tepechitlan', - 'Pena Forte', - 'Yekambarakuppam', - 'Fitzgerald', - 'Evergreen', - 'Thung Sai', - 'Roztoky', - 'Talevad', - 'Mahamda', - 'Pararia', - 'Tulbagh', - 'Valea lui Mihai', - 'Ianca', - 'Vrhnika', - 'Borgoricco', - 'Miradouro', - 'Lolokhur', - 'Perkiomen', - 'Al Yadudah', - 'Neuried', - 'Fort Irwin', - 'Tzitzio', - 'Saint Sampson', - 'Kharsawan', - 'Siachoque', - 'Cloverdale', - 'Plainedge', - 'Ortenberg', - 'Cheste', - 'Mudgere', - 'Park Forest Village', - 'Aver-o-Mar', - "Gonfreville-l'Orcher", - 'Grenade', - 'Tovala', - 'Fredensborg', - 'Sileby', - 'Segni', - 'Nuqui', - 'Unagatla', - 'Sheffield Lake', - 'Sarenja', - 'Gazulapalle', - 'Hlobyne', - 'Rio das Flores', - 'Wangdue Phodrang', - 'Villamediana de Iregua', - 'Sanchi', - 'San Francisco Chimalpa', - 'Fuldabruck', - 'Zacharo', - 'Bayyavaram', - 'Kusmaul', - 'Tvrdosin', - 'Velden am Worthersee', - 'Yaguara', - 'Noventa Vicentina', - 'Bazimini', - 'Donnacona', - 'Sucha Beskidzka', - 'Emirgazi', - 'Mnichovo Hradiste', - 'Karadge', - 'Phulhara', - 'Vanavasi', - 'Gross Kreutz', - 'Ouled Rahou', - 'Sambhu Chak', - 'Bawana', - 'Aviano', + 'Thazhamel', + 'Armilla', + 'Eisenstadt', + 'Elbeuf', + 'Metsamor', + "'Ain el Melh", + 'Karunagapalli', + 'Dayr al Balah', + 'Qazvin', + 'Brokopondo', + 'Keetmanshoop', + 'Chopadandi', + 'Shinas', + 'Silverdale', + 'Orcutt', + 'La Concepcion', + 'Kebili', + 'Tecoluca', + 'Kursaha', + 'Laiyuan', + 'Hilliard', + 'Summit', + 'Vadakku Viravanallur', + 'Phanat Nikhom', + 'Vila Rica', + 'Vantaa', + 'Saint-Amand-les-Eaux', + 'Inole', + 'Barrancas', + 'Upala', + 'Albania', + 'Puerto Galera', + 'Calulo', + 'Mioveni', + 'Yangiariq', + 'Newport News', + 'Puerto Villarroel', + 'San Juan del Rio', + 'Badarwas', + 'Chertsey', + 'Montalvo', + 'Nulivedu', + 'Ain Nouissy', + 'Linhares', + 'Sao Joao da Ponte', + 'Palos Heights', + 'Mondolfo', + 'Vibo Valentia', + "Colle di Val d'Elsa", + 'Tache', + 'Mixquiahuala de Juarez', + 'Montegiardino', + 'Franca', + 'Iwo', + 'Northfield', + 'Neyyattinkara', + 'Hirna', + 'Acquaviva delle Fonti', + 'Voiron', + 'Iturama', + 'Aklanpa', + 'Raymondville', + 'Ambohimandroso', + 'Lakshmipur', + 'Torgelow', + 'Trento', + 'Neiva', + 'Umuarama', + 'San Mauro Torinese', + 'Pago Pago', + 'Ulricehamn', + 'San Cristobal Cucho', + 'Owendo', + 'Basht', + 'Conthey', + 'Damba', + 'Senmayacho-senmaya', + 'Gdansk', + 'Antilla', + 'Husavik', + 'Frankfurt', + 'Seaham', + 'Zagan', + 'Westerly', + 'Sivasli', + 'Nablus', + 'El Wak', + 'Saddle Brook', + 'Tepelene', + 'Vyskov', + 'Tavagnacco', + 'Ndende', + 'Salanso', + 'Laranjeira', + 'Tranquebar', + 'Battulapalle', + 'Bhilwara', + 'Cork', + 'Ennis', + 'Danjiangkou', + 'North Logan', + 'Viralimalai', + 'Firoza', + 'Bettiah', + 'Atharga', + 'Tallimarjon Shahri', + 'Yangi Marg`ilon', + 'Lohariandava', + 'Opera', + 'Gampaha', + 'Teboulba', + 'Solofra', + 'Portoferraio', + 'Daijiazhuang', + 'Jiexiu', + 'Sinkolo', + 'Joutseno', + 'Donauworth', + 'South Glengarry', + 'Nawabganj', + 'Lodhran', + 'Rio San Juan', + 'Kriva Palanka', + 'Rozaje', + 'Manapla', + 'Negresti-Oas', + 'Plaine Magnien', + 'Satsuma', + 'Fatehabad', + 'Rio do Antonio', + 'Calafat', + 'Preganziol', + 'Spalding', + 'Xinji', + 'Kilkottai', + 'Guding', + 'Milici', + 'Paranavai', + 'Skopun', + "Debre Mark'os", + 'Isingiro', + 'Port-Margot', + 'Ludinghausen', + 'Grossenluder', + 'Fenyuan', + 'Araras', + 'Terme', + 'Conneaut', + 'Winnetka', + 'Pelhrimov', + 'Pir Bakran', + 'Sukkampatti', + 'Shrirangapattana', + 'Vatra Dornei', + 'Palmaner', + 'Goose Creek', + 'Hailsham', + 'Douar Tabouda', + 'Douar Echbanat', + 'Adre', + 'Quinto di Treviso', + 'Lagoa Vermelha', + 'Ambatomivary', + 'Maidencreek', + 'Huanuco', + 'Sommerda', + "Sant'Arcangelo di Romagna", + 'Huancavelica', + 'Erramvaripalem', + 'Gyomaendrod', + 'Szigetvar', + "Xin'an", + 'Behror', + 'Antanimenabaka', + 'Sonbarsa', + 'Cuajinicuilapa', + 'Lovosice', + 'Carlos Barbosa', + 'Mlada Boleslav', + 'Wesley Chapel', + 'Adelsdorf', + 'Temascal', + 'Novovolynsk', + 'Brattleboro', + 'Yapacani', + 'Sao Sebastiao do Curral', + 'Makinsk', + 'Ojinaga', + 'Shaoxing', + 'Numazu', + 'Edakkazhiyur', + 'Riesi', + 'Bagamanoc', + 'Inkster', + 'Sugarland Run', + 'Savenay', + 'Eidhi', + 'Elvas', + 'Pannimadai', + 'Dorverden', + 'Luanshya', + 'Grays', + 'Tenente Portela', + 'Iuna', + 'Okmulgee', + 'Busra al Harir', + 'Kil Perambalur', + 'Urucurituba', 'Villa Aberastain', - 'Angelopolis', - 'Ben Chicao', - 'Cebazat', - 'Baba Bakala', - 'Natuba', - 'Bhelsi', - 'Jasauli Patti', - 'Dalavaypattanam', - 'West Donegal', - 'Haledon', - 'Attnang-Puchheim', - 'Sene', - 'Indian Harbour Beach', - 'Czarna Bialostocka', - 'Yasenivskyi', - 'Acucena', - 'Chitvel', - 'Nanmucun', - 'Ferryhill', - 'Munagala', - 'Harwood Heights', - 'Colmeia', - 'Plon', - 'Corgao', - 'Bikkatti', - 'Esanai', - 'Malior', - 'Kotabommali', - 'Yellanda', - 'Colorno', - 'Peebles', - 'Broughton Astley', - 'Almoloya del Rio', - 'Viale', - 'Tshabong', - 'Bad Lauchstadt', - 'Borio', - 'Ramgarha', - 'Belma', - 'Juncos', - 'Montagnana', - 'Ban Nikhom Phatthana', - 'Caputira', - 'Sampgaon', - 'Kafr Sajnah', - 'Khagaur', - 'Ladue', - 'Beaver Falls', - 'Chinna Kalaiyamputtur', - 'Bestensee', - 'Glastonbury', - "Monteforte d'Alpone", - 'Thap Than', - 'Seddouk Oufella', - 'Guttikonda', - 'Qashyr', - 'Bni Sidel', - 'La Junta', - 'West Caln', - 'Hurtgenwald', - 'Nunchia', - 'Purcellville', - 'Zhur', - 'Neuhaus am Rennweg', - 'Shahr-e Pir', - 'Floro', - 'Monastyryshche', - 'Horokhiv', - 'Monistrol-sur-Loire', - 'Kovvali', - 'Gouvieux', - 'Balvadi', - 'Castelnuovo Berardenga', - 'Vila Nova de Cerveira', - 'Sai Ngam', - 'Cholavaram', - 'Kara-Bak', - 'Thi Tran Dong Dang', - 'Libonik', - 'Morieres-les-Avignon', - 'Edgewater Park', - 'Ramapattanam', - 'Hope', - 'Chirongui', - 'Zawyat Sidi al Mekki', - 'Terra Nova', - 'Eslohe', - 'Mangalpur Gudaria', - 'Nanguneri', - 'Somero', - 'Khoragachhi', - 'Upper Leacock', - 'Village St. George', - 'Santa Maria del Tule', - 'Bayport', - 'Fair Lakes', - 'Filottrano', - 'Kui Buri', - 'Weilmunster', - 'Barhagarh', - 'Asolo', - 'Penaballi', - 'Kilankundal', - 'Sepolno Krajenskie', - 'Dashouping', - 'Eceabat', - 'Santa Isabel do Ivai', - 'Ingenbohl', - 'Brownfield', - 'Dayr as Sanquriyah', - 'Policka', - 'Periyapodu', - 'Santa Cruz Atizapan', - 'Osicala', - 'Corman Park No. 344', - 'Felling', - 'Great Cornard', - 'Segarai', - 'Litchfield Beach', - 'Basaha', - 'Channubanda', - 'Helsinge', - 'Enkakad', - 'Bhadwar', - 'Nueva Guadalupe', - 'Devnya', - 'Belvedere Marittimo', - 'Makhambet', + 'Sitakund', + 'Ras el-Barr', + 'Luwero', + 'Itaguacu', + 'Vadasinor', + 'Sile', + 'Inhapi', + 'Tanguieta', + 'Olney', + 'Sonpur', + 'Gillitts', + 'Fond du Lac', + 'Aboso', + 'Oujda-Angad', + 'Tiquisate', + 'Chuqung', + 'Jose Abad Santos', + 'Holsbeek', + 'Lioua', + 'Wiang Haeng', + 'Sirugudi', + 'Gomparou', + 'Kodangipatti', + 'Jitwarpur Kumhra', + 'Dhaula', + 'Monte Carmelo', + 'Zhytomyr', + 'Copertino', + 'Panggezhuang', + "M'lang", + 'Caconde', + 'Sao Sebastiao', + 'Rurrenabaque', + 'Canaman', + 'Vienna', + 'Shichinohe', + 'Catia La Mar', + 'Pachchaimalaiyankottai', + 'Bema', + 'Guadalupe', + 'Fouchana', + 'Takatsuki', + 'Nakrekal', + 'Greenfield', + 'Mirabel', + 'Sharon', + 'Valenzuela', + 'Shiroi', + 'Polotitlan de la Ilustracion', + 'Skawina', + 'Merrifield', + 'Bitetto', + 'Hinsdale', + 'Kalafotsy', + 'Reddigudem', + 'El Colegio', + 'Santa Ana Jilotzingo', + 'Korkuteli', + 'Xieqiaocun', + 'Nikko', + 'Purulha', + 'Al Hasakah', + 'Puigcerda', + 'Diabugu', + 'Sao Joao de Pirabas', + 'Yegainnyin', + 'Itasca', + 'Italva', + 'Olavarria', + 'Dikirnis', + 'Tantoucun', + 'Al Khmissat', + 'Woodland', + 'Vasco Da Gama', + 'Amalapuram', + 'Los Amates', + 'Gotha', + 'Burscheid', + 'Tanippadi', + 'Xinyingheyan', 'St. Pete Beach', - 'Lakhanapuram', - 'Rock Falls', - "Palmeira d'Oeste", - 'Argos Orestiko', - 'Potangal', - 'Tullukuttinayakkanur', - 'Florstadt', - 'Le Teil', - 'Caister-on-Sea', - 'Wanaka', - 'Amuria', - 'Yangiobod', - 'Vadasikarambattu', - 'Karor', - 'Sandpoint', - 'Nangis', - 'Orting', - 'Le Portel', - 'San Jose de Gracia', - 'Ibirapua', - 'Punjai Lakkapuram', - 'Kishtwar', - 'Maddur', - 'Matias Cardoso', - 'Bosel', - 'Wabagai', - 'Prienai', - 'Crozet', - 'Tepetitlan', - 'San Marzano di San Giuseppe', - 'Kanhauli', - 'Oststeinbek', - 'Sandiacre', - 'Douar Ait Taleb', - 'Zunilito', - 'Whippany', - 'Napoleon', - 'Tiachiv', - 'Ap Tan Ngai', - 'Shoshong', - 'Allahpur', - 'Tarcento', - 'Tlumach', - 'Holywell', - 'Melpanaikkadu', - 'Bidkhun', - 'Ladan Kara', - 'Chachersk', - 'Francisco Caballero Alvarez', - 'Metsemotlhaba', - 'Partick', - 'Belisce', - 'Tharike', - 'Bargara', - 'North Londonderry', - "L'Epiphanie", - 'Ifield', - 'Rewahi', - 'Carmen de Apicala', - 'Palangavangudi', - 'Halikko', - 'Majhariya Sheikh', - 'Edgemere', + 'Chieri', + 'Ahmadpur', + 'Capela do Alto', + 'Ebn Ziad', + 'Moimenta da Beira', + 'Schwarzenbek', + 'Sasthankotta', + 'Lannion', + 'Oupeye', + 'Digne-les-Bains', + 'Kami', + 'Widnes', + 'Bala Cangamba', + 'Edmonds', + 'Qabr as Sitt', + 'Lorient', + 'Antsinanantsena', 'Liteni', - 'Oberriet', - 'Polakala', - 'Makaya', - 'Gurmaila', - 'Hallstadt', - 'Silleda', - 'Alwa Tirunagari', - 'Kulpsville', - 'Zuchwil', - 'Khem Karan Saray', - 'Balumath', - 'Nanan', - 'Bhagatpur', - 'Padakanti', - 'Breuillet', - 'Kharsod B', - 'Mosrah', - 'Camenca', - 'Hohenbrunn', - 'Khandrauli', - 'Thief River Falls', - 'Imilchil', - 'Bhataulia', - 'Agadallanka', - 'Minerbio', - 'Pearsall', - 'Tataltepec de Valdes', - 'Quetigny', - 'Ghorbanki', - 'Unterageri', - 'La Fare-les-Oliviers', - 'Irigny', - 'Mallaram', - 'Gangapatnam', - 'Iskourane', - 'Msemrir', - 'Hunduan', - 'Rabo de Peixe', - 'Papara', - 'Schleiz', - 'Kambur', - 'Golakpur', - 'Chiranellur', - 'Cumberland Hill', - 'Ait Ikkou', - 'Ainapur', - 'Katahra', - 'Kanakpur', - 'Teolo', - 'Collingdale', - 'West Perth', - 'Ayapango', - 'Yakakent', - 'Yelsk', - 'Kusterdingen', - 'Mannamangalam', - 'Muriyad', - 'Ponta do Sol', - 'Tasso Fragoso', - 'Kelle', - 'Sorisole', - 'Al Abraq', - 'Pullalacheruvu', - 'Sirikonda', - 'Jogiara', - 'Gondauli', - 'Viagrande', - 'Rocas de Santo Domingo', - 'Striano', - 'Yanchep', - 'Woodmoor', - 'Collier', - 'Le Thor', - 'Achacachi', - "Ak'ordat", - 'Vannikkonendal', - 'Pandino', - 'Bellheim', - 'El Valle', - 'Bellerive-sur-Allier', - 'Ilarionove', - 'Amtala', - 'Sulahpet', - 'East York', - 'Poteau', - 'Gilgit', - 'Kilchberg', - 'Mandalavadi', - 'Sakaddi', - 'Australia', - 'Bersenbruck', - 'Keora', - 'Kadiyadda', - 'Khetko', - 'Ait Ouaoumana', - 'Hlevakha', - 'Landquart', - 'Golbey', - 'Shankarpur', - 'Agadir Melloul', - 'Fontaine-les-Dijon', - 'Malangam', - 'Aradeo', - 'Ban Pong Tao', - 'Jaimalpura', - 'Karariya', - 'Rhymney', - 'Tirumalaippatti', - 'Sewari', - 'Kalkuni', - 'Nimmekal', - 'Casorate Primo', - 'Zoeterwoude', - 'Sabanozu', - 'Volkach', - 'Bansang', - 'Drazinda', - 'Nellutla', - 'Pallippatti', - 'Coffeyville', - 'Caturama', - 'Madnur', - 'Andalusia', - 'Chak Habib', - "Pa'in Chaf", - 'Naunhof', - 'Smizany', - 'Ban Noen Kum Nueng', - 'Ban Muang Kham', - 'Vinjam', - 'Saeby', - 'Finestrat', - 'Madanancheri', - 'Machadodorp', - 'El Realejo', - 'Armazem', - 'Ospina', - 'Steinheim am Albuch', - 'Seneca', - 'Potengi', - 'Pedrinhas', - 'Urania', - 'Sanwas', - 'Moslem Ebn-e `Aqil', - 'Signal Mountain', - 'Campbellton', - 'Al Buwaydah', - 'Cortez', - 'San Juan de la Costa', - 'Dobris', - 'Maysville', - 'Piriapolis', - 'Qizilhacili', - 'Heek', - 'Cumnock', - 'Ablu', - 'Tamganj', - 'Maria Enzersdorf', - 'Kressbronn am Bodensee', - 'Sanatoga', - 'Dardilly', - 'Hamsavaram', - 'Tirano', - 'Con Dao', - 'Memmelsdorf', - 'Gibsonville', - 'Hucclecote', - 'Montmelo', - 'Mahagaon', - 'Reyes', - 'Baia Formosa', - 'Neuenhof', - 'Satwar', - 'Ramgarh', - 'Missaglia', - 'Bouati Mahmoud', - 'Vert-Saint-Denis', - 'Jonnagiri', - 'Chakla Waini', - 'Kodavatipudi', - 'Fort Valley', - 'Amarzgane', - 'Entrerrios', - 'Toppenish', - 'Baciu', - 'Valasa', - 'Hish', - 'Basmanpur', - 'Vadapalanji', - 'Albinea', - 'Adigoppula', - 'Soresina', - 'Takua Pa', - 'Sao Sebastiao do Curral', - 'Upper Makefield', - 'Baramandougou', - 'Yacimiento Rio Turbio', - 'Rangvasa', - 'Ban Si Don Chai', - 'Oak Hills Place', - 'San Martin de Valdeiglesias', - 'Sarlat-la-Caneda', - 'Mansong', - 'Takouta', - 'Hoyo de Manzanares', - 'Parame', - 'Barun', - 'Sorala', - 'Jolfa', - 'Porto Santo Stefano', - 'Mokhotlong', - 'Kampong Tunah Jambu', - 'Boucau', - 'Bolszewo', - 'Checy', - 'Ineu', - 'Hunenberg', - 'Malipakar', - 'Mousoulou', - 'Lusca', - 'Ala', - 'Tagapul-an', - 'Pitman', - 'Rreshen', - 'Lovosice', - 'Iklod', - 'Dhobipet', - 'Ranjal', - 'Bernolakovo', - 'Beni Hassane', - 'Angor', - 'Tausa', - 'Obernburg am Main', - 'Tillaivilagam', - 'North Haledon', - 'G`ozg`on', - 'Taragi', - "Vel'ke Kapusany", - 'La Ferte-Bernard', - 'Dunavarsany', - 'Pittsgrove', - 'London Grove', - 'Ulstein', - 'Cristuru Secuiesc', - 'Rouvroy', - 'Penugolanu', - 'Vanduvancheri', - 'Bommayapalaiyam', - 'Uta', - 'Santa Maria Xadani', - 'Maisaram', - 'Ballenstedt', - 'Baikunthapur', - 'Ntossoni', - 'Strijen', - 'Hateg', - 'Lichtervelde', - 'Entraigues-sur-la-Sorgue', - 'Chichkah', - 'Abcoude', - 'Rautara', - 'Engerwitzdorf', - 'Lontra', - 'Queven', - 'Jeannette', - 'Kukrahill', - 'Falla', - 'Nagykovacsi', - 'Miyar', - 'Hassi Berkane', - 'Kryzhopil', - 'Brimington', - 'Varatanapalli', - 'Gholia Kalan', - 'Porcari', - 'Treze Tilias', - 'El Outaya', - 'Karis', - 'Tlagasana', - 'Soeda', - 'Toulou', - 'Sowan', - 'La Loggia', - 'Ban Sai Yoi', - 'Koekelare', - 'Dharawat', - 'Schuylkill', - 'Cofimvaba', - 'Lienen', - 'Costa Volpino', - 'Sodankyla', - 'Essey-les-Nancy', - 'Belsh', - 'Chahana', - 'Garsekurti', - 'Bhasaula Danapur', - 'Boonton', - 'Saidia', - 'Cherry Hinton', - 'Annan', - 'Nueva Ocotepeque', - 'Kampel', - 'Waldenbuch', - 'Bachchannapet', - 'Yelandur', - 'Kunimedu', - 'Moe', - 'Garching an der Alz', - 'La Mujer', - 'Bundehra', - 'Barth', - 'Monforte del Cid', - 'Cinderford', - 'Adiyakkamangalam', - 'Komijan', - 'Clanton', - 'Nea Michaniona', - 'Deodora', - 'Aliartos', - 'Somarasampettai', - 'Kusumbe', - 'Mahopac', - 'Tiqqi', - 'Pereiras', - 'Efringen-Kirchen', - 'Poisy', - 'Gessate', - 'Meadow Lakes', - 'Amberomanga', - 'Brevik', - 'Luzzi', - 'Presque Isle', - 'Paratdiha', - 'Bee Cave', - 'Coaldale', - 'Muturkha', - 'Cunupia', - 'Vicentinopolis', - 'Kirrayach', - 'Chartiers', - 'Taskent', - 'Hirni', - 'Chinna Mupparam', - 'Boukhralfa', - 'Sriramapuram', - 'Aragona', - 'Pizzo', - 'Grossenluder', - 'Idupugallu', - 'Spring Valley Lake', - 'Bertrix', - 'Rampatti', - 'Vidapanakallu', - 'Ashtian', - 'Marrupa', - 'Zapatoca', - 'Abiramam', - 'Otaki', - 'Perry Heights', - 'Mascoutah', - 'Borgentreich', - 'Cockermouth', - 'Borgo a Buggiano', - 'Galela', - 'Zulakallu', - 'Pukkulam', - 'Kibaya', - 'Fully', - 'Pa Mok', - 'Ottobeuren', - 'Saint-Paul-Trois-Chateaux', - 'Rani Sawargaon', - 'San Pedro de Coche', - 'Riacho dos Machados', - 'Hombrechtikon', - 'Pacuarito', - 'Vohburg an der Donau', - 'Aulnoye-Aymeries', - 'Crest', - 'Hiramandalam', - 'Damal', - 'Budamangalam', - 'Stony Brook University', + 'Belsand', + 'Tibau do Sul', + 'Melpanaikkadu', + 'Uranganpatti', + 'Canasgordas', + 'Totnes', + 'King Edward Point', + 'Ben Daoud', + 'Aarau', + 'San Sebastiano al Vesuvio', + 'Bagam', + 'Hobart', + 'Shimada', + 'Roelofarendsveen', + 'Broomfield', + 'Palenga', + 'Rainham', + 'Molepolole', + 'Hayama', + 'Guines', + 'Gonubie', + 'Filiasi', + 'Gethaura', + 'General Rodriguez', + 'Guilderland', + 'Acarigua', + 'Lowell', + 'Subulussalam', + 'Boiro', + 'Workington', + 'Sebes', + 'Konibodom', + 'Grevesmuhlen', + 'Mixco', + 'St. Andrews', + 'Tirora', + 'Gubat', + 'Edattirutti', + 'Bad Wildbad', + 'Newport Pagnell', + 'Jadcherla', + 'Mountain House', + 'Pindare-Mirim', + 'Hollins', + 'Barddhaman', + 'Castro-Urdiales', + 'Bandora', + 'Masandra', + 'Charo', + 'Qiryat Bialik', + 'Turangi', + 'Lavras da Mangabeira', + 'Hanover', + 'Middleburg', + 'Umm Qasr', + 'Kingswinford', + 'Dachne', + 'Surcin', + 'Al Manaqil', + 'Sorombo', + 'Maruteru', + 'Chaona', + 'Morbi', + 'Rani Shakarpura', + 'Tiko', + 'Picarras', + 'Keratsini', + 'West Deptford', 'Natividade', - 'Lachen', - 'Angichettippalaiyam', - 'Habo', - 'Daping', - 'Banak', - 'San Juan Ixcaquixtla', - 'Lenox', - 'Pasivedalajimma', - 'Sremski Karlovci', + 'Kalale', + 'Hohenkirchen-Siegertsbrunn', + 'Huachipato', + 'Ubaitaba', + 'Shashijie', + 'Nalambur', + 'Monte Mor', + 'Halikner', + 'Pinczow', + 'Vellavadanparappu', + 'Ankli', + 'Oakdale', + 'Ar Rommani', + 'Phulwaria', + 'Berchem', + 'Ban Bang Muang', + 'Mangalapur', + 'Maki', + 'Puente Alto', + 'Paoy Paet', + 'Parsagarhi', + 'Gobernador Galvez', + 'Narpes', + 'Kodumudi', + 'Vostochnyy', + 'Grabouw', + 'Volketswil', + 'Qabala', + 'Falan', + 'Sankt Veit an der Glan', + 'Bargur', + 'Zalishchyky', + 'Paraiso do Norte', + 'Guymon', + 'Corsicana', + 'Malargue', + 'Cheran', + 'Makhmalpur', + 'Mitchellville', + 'Ouamri', + 'Kegeyli Shahar', + 'Nalbari', + 'Caazapa', + 'Bebedouro', + 'Crixas', + 'Jaisinghnagar', + 'Cuimba', + 'Ankireddikuntapalem', + 'Biknur', + 'Parauli', + 'Solec Kujawski', + 'La Riviera', + 'Sakae', + 'Ville Bonheur', + 'Galkot', + 'Tessalit', + 'Joao Alfredo', + 'Vinkovci', + 'Karuppur', + 'Vedappatti', + 'Palocabildo', + 'Nanjing', + 'Haidarnagar', + 'Kabankalan', + 'Acapetahua', + 'Yashio', + 'Wasaga Beach', + 'Gorzow Wielkopolski', + 'Erzurum', + 'Jordbro', + 'Ilmajoki', + 'Cuauhtemoc', + 'Soldanesti', + 'Kontagora', + 'Baleno', + 'Umbertide', + 'Cividale del Friuli', + 'Maidenhead', + 'Taupo', + 'Potters Bar', + 'Hubli', + 'Kakching', + 'Aguadilla', + 'Dobrna', + 'Souk Ahras', + 'Giessen', + 'Feriana', + 'Simdega', + 'Kadugli', + 'Makati City', + 'Harqalah', + 'Flowery Branch', + 'Spartanburg', + 'Royal Oak', + 'Fukuroi', + 'Kishmat Dhanbari', + 'Somerset East', + 'Behisatse', + 'Tummalapenta', + 'Central District', + 'Tubize', + 'Issy-les-Moulineaux', + 'Lezhe', + 'Buriti dos Lopes', + 'Krusevo', + 'Shibuya-ku', + 'Cachoeira', + 'Takahata', + 'Bozeman', + 'Yongqing', + 'Rio Vista', + 'Primavera', + 'Bainbridge Island', + 'Lo Miranda', + 'Sanharo', + 'Sentjernej', + 'Coral Hills', + 'Serres', + 'Kapan', + 'Caruaru', + 'Shijonawate', + 'Para de Minas', + 'Buco Zau', + 'Shaker Heights', + 'Zhaoyu', + 'Koto-ku', + 'Parvatgiri', + 'Evergem', + 'Asalem', + "Mu'tah", + 'Mahalleh-ye Shirinu', + 'Douar Oulad Hssine', + 'Villa Purificacion', + 'Arras', + "Sao Lourenco d'Oeste", + 'Bad Krozingen', + 'Olgiate Comasco', + 'Hanumannagar', + 'Echemmaia Est', + 'Lennox', + 'Kalimpong', + 'Kitob', + 'Las Palmas', + 'Guacima', + 'Urgut Shahri', + 'Carnot', + 'Lambertville', + 'Sabara Bangou', + 'Shahr-e Herat', + 'Longford', + 'Kambove', + 'Cartagena', + 'Odessa', + 'Bani Suwayf', + 'Toqsu', + 'Bibbiano', + 'Torres Vedras', + 'Bareja', + 'Maying', + 'Gross-Umstadt', + 'Anzoategui', + 'Holstebro', + 'Baturite', + 'Neduvannur', + "Terra Roxa d'Oeste", + 'Cencheng', + 'Marondera', + 'Azumino', + 'Sanha', + 'Porto Grande', + 'Ansermanuevo', + 'Perigueux', + 'Makronia', + "Bek'oji", + 'Los Blancos', + 'Argeles-sur-Mer', + 'Khorabar', + 'Fushe-Kruje', + 'Fotsialanana', + 'Aomar', + 'Guardamar del Segura', + 'Ksibet el Mediouni', + 'Georgian Bluffs', + 'Stockport', + 'Saray', + 'Buckley', + 'Daventry', + 'Jaqma', + 'Guifoes', + 'Patpara', + 'Bonhill', + 'Presidente Figueiredo', + 'Cutral-Co', + 'Morgan City', + 'Cernusco sul Naviglio', + 'Beheloka', + 'Bargny', + 'Brits', + 'Nakasato', + 'San Jose de Feliciano', + 'Lithia Springs', + 'Kushtia', + 'Nasipit', + 'Alsdorf', + 'Rockland', + 'Homestead', + 'Ziketan', + 'Ludvika', + 'Erbil', + 'Meguro', + 'Teolo', + 'Lapovo', + 'Streetly', + 'Dar es Salaam', + 'Middleton', + 'Ayancik', + 'Canoas', + 'Kanrangana', + 'Parczew', + 'Puck', + 'Mario Campos', + 'Bedourie', + 'Bohumin', + 'Freha', + 'Juventino Rosas', + 'Kolaras', + 'Oued Sebbah', + 'Kinattukkadavu', + 'Peravurani', + 'Barahona', + 'Kalabo', + 'Kumluca', + 'Saint-Priest', + 'Tagkawayan', + 'Durazno', + 'Ouled Rabah', + 'Susangerd', + 'Reynosa', + 'Araraquara', + 'Ambinanynony', + 'Puerto Madryn', + 'Villa Juarez', + 'Bletchley', + 'Santo Tomas de Janico', + 'El Arahal', + 'Bijapur', + 'Villeneuve-la-Garenne', + 'Nantong', + 'Semera', + 'Dean Funes', + 'Koblenz', + 'Montebello', + 'Sideradougou', + 'Luzhou', + 'Yuanchang', + 'Tulbagh', + 'Hitoyoshi', + 'Wijk bij Duurstede', + 'Damascus', + 'Branchburg', + 'Bahutal', + 'Payyanpalli', + 'Gjovik', + 'Pudukkottai', + 'Lakhdaria', + 'Paracambi', + 'El Bagre', + 'Ban Cho Ho', + 'Villamartin', + 'Natogyi', + 'Wildwood', + 'Tall Salhab', + 'Fort Erie', + 'Kirtipur', + 'Quirihue', + 'Masamagrell', + 'Medak', + 'Futtsu', + 'Cuamba', + 'Zbarazh', + 'Beniel', + 'Azzaba', + 'Banaruyeh', + 'Denver', + 'Slough', + 'Khenifra', + 'Nanbu', + 'Ibarra', + 'Galashiels', + 'Malyn', + 'Biei', + 'Eranapuram', + 'Miechow', + 'San Benedetto del Tronto', + 'St. Matthews', + 'Muhlenberg', + 'Cape Coast', + 'Massa Lombarda', + 'Raybag', + 'Villeta', + 'Jogbani', + 'Agua Blanca', + 'Kaluderica', + 'Dinnington', + 'Jepara', + 'Bhimadolu', + 'Ortona', + 'Xincheng', + 'Huancayo', + 'Crewe', + 'Koduvilarpatti', + 'Eggertsville', + 'Agege', + 'Gharyan', + 'Sucupira do Norte', + 'Datian', + 'Kaldsletta', + 'Paillaco', + 'Anjanazana', + 'Sulphur', + 'Kakrala', + 'Walin', + 'Francisco Caballero Alvarez', + 'Frenda', + 'Robertsport', + 'Simanggang', + 'Flers', + 'Tindouf', + 'Azna', + 'Umrat', + 'Chhimluang', + 'Felixlandia', + 'Tung Tau Tsuen', + 'Soledar', + 'Mejorada del Campo', + 'Nijlen', + 'Przeworsk', + 'Upper Leacock', + 'Machico', + 'Arakkapadi', + 'Gawan', + 'Tracuateua', + 'Tilbury', + 'Indiaroba', + 'Villa Constitucion', + 'Gil', + 'Soyaniquilpan', + 'Nanchang', + 'Guaxupe', + 'Gardone Val Trompia', + 'Lampang', + 'Kahror Pakka', + 'Kundurpi', + 'Gallatin', + 'Belper', + 'Beruri', + 'El Pinon', + 'Chengjiao Chengguanzhen', + 'Ad Darbasiyah', + 'Neo Karlovasi', + 'Mersin', + 'Glyfada', + 'Bastak', + 'Wolfersheim', + 'Albenga', + 'Kuqa', + 'Isanlu', + 'Kaji', + 'Barranquilla', + 'Sai Kung Tuk', + 'Hish', + 'Overpelt', + 'La Vista', + 'Livingston', + 'Bangassi-Nangou', + 'Purcellville', + 'Mashpee', + 'Alushta', + 'Tikar', + 'Katima Mulilo', + 'Duvvuru', + 'Paragominas', + 'Mosquera', + 'Yuzhnoukrainsk', + 'Senador Jose Porfirio', + 'Mutuipe', + 'Castenaso', + 'Schmolln', + 'Mporokoso', + 'Tawsalun', + 'Malo', + 'Myedu', + 'Orsta', + 'Staten Island', + 'Goch', + 'Dulag', + 'Bedlington', + 'Mangatarem', + 'Lubok Antu', + 'Zongo', + 'Toktogul', + 'Sabana Grande de Boya', + 'Mullheim', + 'Mogilno', + 'Abra Pampa', + 'Sidi Baizid', + 'Rostusa', + 'Glen Allen', + 'Barra de Sao Francisco', + 'Jocotitlan', + 'Pensilvania', + 'Petropavl', + 'Radlje ob Dravi', + 'Chichaoua', + 'Irondale', + 'Namhkam', + 'Liestal', + 'Yazu', + 'Douar Olad. Salem', + 'Mecca', + 'Fergus Falls', + 'Shimotoba', + 'Purificacion', + 'Qal`at Sukkar', + 'Zhezqazghan', + 'Kenafif', + 'Chak That', + 'Roanoke Rapids', + 'Manakondur', + 'Beni Enzar', + "Nefas Mewch'a", + 'Kerap', + 'Narsingi', + 'Arys', + 'Ajaccio', + 'Lihue', + 'Herentals', + 'Tarakan', + 'San Jose del Fragua', + 'Sitio Novo de Goias', + 'Jammu', + 'Ballesteros', + 'Bayreuth', + 'Schererville', + 'Kara-Suu', + 'Mbandjok', + 'Xinpi', + 'Caudry', + 'Jalhalli', + 'Rosario de Mora', + 'Hampden', + 'Tevaram', + 'Annapolis Neck', + 'Minokamo', + 'Ghataro Chaturbhuj', + 'Neyshabur', + 'North Mankato', + 'Nea Makri', + 'Matino', + 'San Vito al Tagliamento', + 'Shangchuankou', + 'Maldon', + 'Tirupparangunram', + 'Chateauneuf-les-Martigues', + 'Sumare', + 'La Calamine', + 'Plettenberg Bay', + "Monteroni d'Arbia", + 'Ban Charoen Mueang', + 'Pukekohe East', + 'Ban Sop Tia', + 'Barbacoas', + 'Plottier', + 'Fleetwood', + 'Fultondale', + 'Karahia', + 'Grefrath', + 'Kalavai', + 'Borsa', + 'Bournville', + 'Changwon', + 'Chik Banavar', + 'Kungsbacka', + 'Yunoshima', + 'Pithiviers', + 'Zepce', + 'Rosario do Sul', + 'Nadiad', + 'Besancon', + 'Rupbas', + 'Muong Theng', + 'Dubrovytsya', + 'Someren', + 'Lianyuan', + 'Huilongping', + 'Zrenjanin', + 'Ban Wiang Phan', + 'Jucurutu', + 'Alamos', + 'Zetang', + 'Lymm', + 'Sarajevo', + 'Saint-Sebastien-sur-Loire', + 'Sereflikochisar', + 'Suai', + 'La Leonesa', + 'Tequisquiapan', + 'Faya', + 'Fort Saskatchewan', + 'Neuilly-Plaisance', + 'Elenga', + 'Dearborn', + 'Gok', + 'Ipora', + 'Mierlo', + 'Ottappalam', + 'Mirandiba', + 'Rongjiawan', + 'Sarno', + 'Volpiano', + 'Ain Touta', + 'Swietochlowice', + 'San Dimas', + 'Brenham', + 'Birkenfeld', + 'Sveti Jurij', + 'Montfermeil', + 'Bowen', + 'Xiangcheng', + 'Bariariya', + 'Albufeira', + 'Pantin', + 'Ruffano', + 'Buurhakaba', + 'Kulai', + 'Nordlingen', + 'Alcanar', + 'Ostfildern', + 'San Juan del Puerto', + 'Zunhua', + 'Yuregir', + 'Amha', + 'San Antonio de los Banos', + 'Pojuca', + 'Cernavoda', + 'Maria', + 'Saky', + 'Ciudad Victoria', + 'Qasr-e Qand', + 'North Lauderdale', + 'Manahari', + 'Kartikapalli', + 'Herne', + 'Zabki', + 'Middle River', + 'Moncion', + 'Er Regueb', + 'Ridge', + 'Tezu', + 'Djendel', + 'Tynaarlo', + 'Katra', + 'Le Plessis-Trevise', + 'Pernik', + 'Grossostheim', + 'Dharir', + 'Kherrata', + 'Guamal', + 'Mangrawan', + 'Haldibari', + 'Yingzhou Linchang', + 'Zgierz', + 'Brownsburg', + 'Radebeul', + 'Novara', + 'Markacho', + 'Lochristi', + 'Oyem', + 'Porcia', + 'Bogoso', + 'Tapa', + 'Carmagnola', + 'Alto Parnaiba', + 'Prosper', + 'Nossombougou', + 'Tohana', + 'Turlock', + 'Gualaquiza', + 'Masrakh', + "Arba Minch'", + 'Moroto', + 'Carcassonne', + 'Paraipaba', + 'Jajarm', + 'Raparla', + "Diao'ecun", + 'Oued Laou', + 'Sint-Niklaas', + 'Masuda', 'Tilvalli', - "Sant'Angelo in Lizzola", - 'Mozzate', - 'Coccaglio', - 'Shopokov', - 'Bouhlou', - 'Afumati', - 'Sanrha', - 'Castagneto Carducci', - 'Civitella in Val di Chiana', - 'Summit View', - 'Rudewa', - 'Sonsbeck', - 'Roccastrada', - 'Wervershoof', - 'Tanudan', - 'Stary Sacz', - 'Lamarao', - 'Jabera', - 'Ranod', - 'Leopoldo de Bulhoes', - 'Kanavaypudur', - 'Rahta', - 'Hoshoot', - 'Koror', - 'Uzundere', - 'Biederitz', - 'Notre-Dame-de-Gravenchon', - 'Murillo', - 'Teranikallu', - 'Dhanauli', - 'Nam Som', - 'Rio Jimenez', - 'Wingles', - 'Pullanvidudi', - 'Vadakadu', - 'Hoquiam', - 'Corona de Tucson', - 'Comendador Levy Gasparian', - 'Perigny', - 'Saint-Jean-de-Monts', - 'Hakka', - 'Pedda Nindrakolanu', - 'Parabita', - 'Doornkop', - 'Lichana', - 'Rudravaram', - 'Hollymead', - 'Krompachy', - 'Sanjat', - 'Queimada Nova', - 'Harsova', - 'Messkirch', - 'Malaimarpuram', - 'Mirchpur', - 'Aktepe', - 'Wattwil', - 'Bussy', - 'Rauenberg', - 'Moranbah', - 'Igana', - 'Bhui', - 'Ekangar Sarai', - 'Velakalnattam', - 'Bharno', - 'Ellicott', - 'Gundumal', - 'Folignano', - 'Karuveppampatti', - 'Satgachia', - 'Hostotipaquillo', - 'Bad Bergzabern', - 'Lowenberg', - 'Jalalkhera', - 'Maiquinique', - 'Herzberg', - 'Obertraubling', - 'Lillebonne', - 'Nagaiyampatti', - 'San Juan de Arama', - 'Cabras', - 'Carlosama', - 'Roetgen', - 'Saint-Claude', - 'Tsrar Sharif', - 'Pendekallu', - 'Galmaarden', - 'Narona', - 'Montalto di Castro', - 'Port Jervis', - 'Gendou', - 'Stara Tura', - 'Buved', - 'Ragampet', - 'Pont-Rouge', - 'Guneysu', - 'Pillutla', - 'Siggiewi', - 'Cutrofiano', - 'Hualaihue', - 'Virapalle', - 'Aransas Pass', - 'Onnaing', - "La Chapelle d'Armentieres", - 'Navappatti', - 'South Londonderry', - 'Ustrzyki Dolne', - 'Punnappatti', - 'Ponte Buggianese', - 'Santanopolis', - 'Margny-les-Compiegne', - 'Iaboutene', - 'Akalgarh', - 'Angallu', - 'Barbana', - 'Bommagondanahalli', - 'Sarbisheh', - 'Inekar', - 'Azizpur Chande', - 'Tomesti', - 'Velaux', - 'Uchen', - 'Chanute', - 'Talsi', - 'Gigmoto', - 'Al Quway`iyah', - 'Ouando', - 'Besozzo', - 'Hamlin', - 'Kolbuszowa', - 'Sohta', - 'Doiwala', - 'Sao Jose do Cerrito', - 'Chocen', - 'Gangajalghati', - 'Blanchard', - 'Anthony', - 'Summit Park', - 'Nanzhangcheng', - 'Dunn Loring', - 'Tleta Taghramt', - 'Gyumai', - 'Bhanuvalli', - 'Roccapiemonte', - 'Champlain', - 'Sidi el Mokhfi', - 'Lazaro Cardenas', - 'Janglot', + 'Tauranga', + 'Upplands Vasby', + 'Wabash', + 'Tapas', + 'Al `Alamayn', + 'Huozhou', + 'Tshikapa', + 'Kennedy Town', + 'Wisconsin Rapids', + 'Yangiyul', + 'Quezalguaque', + 'Bougado', + 'Cuautepec de Hinojosa', + 'Mundo Novo', + 'Verl', + 'Maghnia', + 'Dzouz', + 'Principe da Beira', + 'Bamessi', + 'Soloma', + 'Basay', + 'Closter', + 'Amatenango de la Frontera', + 'Bazarak', + 'Benairia', + 'Mocharim', + 'Kuchesfahan', + 'Kurayoshi', + 'Luohe', + 'Kampot', + 'Chaska', + 'Lynden', + 'Purushottampur', + 'Konin', + 'Long Xuyen', + 'Kizhakkott', + 'Peachtree Corners', + 'Natshal', + 'Saleaula', + 'Bahia Blanca', + 'Semey', + 'Rianxo', + 'Caridad', + 'Hammam el Rhezez', + 'Kudelstaart', + 'Huizen', + 'Narasapuram', + 'Parkville', + 'Kadungapuram', + 'Garden City', + 'Daulatkhan', + 'Tectitan', + 'Maroambihy', + 'Pallini', + 'Center Point', + 'North Bay', + 'Maihar', + 'Lons', + 'Huehuetenango', + 'Qalqilyah', + 'Koryo', + 'Betafo', + 'Rheinbach', + 'Surprise', + 'Sumbawanga', + 'Thatha', + 'Kurugodu', + 'Neustadt in Holstein', + 'Jupi', + 'Santa Isabel do Para', + 'Chandrawada', + 'Tamra', + 'Cusset', + 'Le Cres', + 'Tunduma', + "Toyloq Qishlog'i", + 'Southbourne', + 'Hempfield', + 'Dhilwan', + 'Roseville', + 'Sisimiut', + 'Aizubange', + 'Lleida', + 'Muri', + 'Phalombe', + 'Antsoha', + 'Saha', + 'Muana', + 'Djambala', + 'Istanbul', + 'Andoharanofotsy', + 'Seligenstadt', + 'Djougou', + 'Boukadir', + 'Ingeniero Pablo Nogues', + 'Barwon Heads', + 'Hazleton', + 'Ciudad Tula', + 'Northeim', + 'Galela', + 'Rehoboth', + 'Bemanonga', + 'Nawucun', + 'Gallup', + 'Malayer', + 'Abu Za`bal', + 'Seia', + 'Samalsar', + 'Melfi', + 'Puduvayal', + 'Namsos', + "Bailey's Crossroads", + 'Gardere', + 'Bermo', + 'Gaillard', + 'Qiushanxiang', + 'Rokycany', + 'Cesena', + 'Alto Piquiri', + 'Mendoza', + 'Rudrangi', + 'Kotido', + 'Turbihal', + 'Comox', + 'Shangpa', + 'Tzintzuntzan', + 'Nao Kothi', + 'Cogolin', + 'Nhan Trach', + 'Royal Wootton Bassett', + 'Suhar', + 'Prestea', + 'Zahle', + 'Cherniakhiv', + 'Thinadhoo', + 'Phuthaditjhaba', + 'Pasco', + 'Madhavaram', + 'Chuo-ku', + 'Kishi', + 'Tavistock', + 'Jitpur', + 'Legnano', + 'Heusweiler', + 'Punnila', + 'Bonoufla', + "Qiryat Mal'akhi", + 'Jaguari', + 'Erraguntlakota', + 'Valdobbiadene', + 'Lupao', + 'Hille', + 'Cosamaloapan', + 'Tromso', + 'Charkhi Dadri', + 'Dolo Odo', + 'Ebersbach an der Fils', + 'Chojnow', + 'Perkasie', + 'Zhamog', + 'Seiada', + 'Bjelovar', + 'Puerto Natales', + 'Camaguey', + 'Dabakala', + 'Katagami', + 'Panchla', + 'Borgoricco', + 'St. Albans', + 'Campeche', + 'Kontela', + 'Broughty Ferry', + 'Shihuajie', + 'Alvinopolis', + 'Parilla', + 'Georgetown', + 'North Palm Beach', + 'Canela Baja', + 'Darpa', + 'Battipaglia', + 'Upland', + 'Bombinhas', + 'Houten', + 'Ibiracu', + 'Paraopeba', + 'Hokota', + 'Whitpain', + 'Nakoushi', + 'Krasnoilsk', + 'Guapimirim', + 'Bom Jesus da Serra', + 'Tesalia', + 'Arohi', + 'Pyay', + 'Tryavna', + 'Mufulira', + 'Weligama', + 'Gaillac', + 'Rettanai', + 'Marano di Napoli', + 'Jefferson City', + 'Tulagi', + 'Nirmali', + 'Passos', + 'Htison', + 'Harewa', + 'Miren', + 'Shika', + 'Alfajayucan', + 'San Pedro Masahuat', + 'Galhinna', + 'Silla', + 'Dong Ha', + 'Legazpi City', + 'Hassi Messaoud', + 'Bhadrapur', + 'Anjahambe', + 'Sirsaganj', + 'Menglang', + 'Qarchak', + 'Gandhwani', + 'Penedo', + 'Peralta', + 'Rappang', + 'Bad Bramstedt', + 'Weinfelden', + 'Aliaga', + 'Douar Sidi Laaroussi', + 'Regedor Quissico', 'Sidi Dahbi', - 'Havsa', - 'Asagi Quscu', - 'Iles', - 'Richterich', - 'Lake Villa', - 'Bududa', - 'Jondor Shaharchasi', - 'Tashir', - 'Siklos', - 'Sini', - 'Volodymyrets', - 'Pardanjan', - 'Innsbrook', - 'Zawiat Moulay Brahim', - 'Koppunur', - 'Vadacheri', - 'Raia', - 'Pulivalam', - 'Flero', - 'Caprino Veronese', - 'Coaticook', - 'Marcy', - 'Phimai', + 'Joppatowne', + 'Borgo a Buggiano', + 'Tiqqi', + 'Stakhanov', + 'Basmakci', + 'Oulad Fraj', + 'Moron', + 'Thunder Bay', + 'Manoharpur', + 'Kuniyamuttur', + 'Onondaga', + 'Lopare', + 'Zumaia', + 'Kahemba', + 'Altenstadt', + 'Cabuyao', + 'Kafr az Zayyat', + 'Burriana', + 'Kulharia', + 'Barinas', + 'Nelmadur', + 'Demirozu', + "Bois-d'Arcy", + 'Lahad Datu', + 'Venganellur', + 'Tsuruoka', + 'Bordertown', + 'Amrabad', + 'Sala', + 'Coronel Freitas', + 'Bassin Bleu', + 'Porto Santo Stefano', + 'Ait Yazza', + 'Thanhlyin', + 'Tournai', + 'Valea Adanca', + 'Saint-Cloud', + 'Ginowan', + "Welk'it'e", + 'Siilinjarvi', + 'Inhangapi', + 'Huazhou', + 'Eski Yakkabog`', + 'Tobelo', + 'Horsholm', + 'Springs', + 'Lorengau', + 'Manwat', + 'Khmilnyk', + 'Hrubieszow', + 'Santa Teresa di Riva', + 'Portel', + 'El Dorado Hills', + 'Pattiswaram', + 'Bad Reichenhall', + 'Dourdan', + 'Dakhram', + 'Rio de Contas', + 'Pagudpud', + 'Sao Felix', + 'Kosjeric', + 'Lebanon', + 'Fargo', + 'Mont-Saint-Aignan', + 'Wald', + 'Eckernforde', + 'Chicholi', + 'Goldap', + 'Kurashiki', + 'Santa Maria Colotepec', + 'Kawaii', + 'Narapala', + 'Maimanah', + 'Ponda', + "'Ain Roua", + 'Manyoni', + 'Mineiros', + 'Moussoro', + 'Olhao', + 'Ridley', + 'Sidi Ouassay', + 'Nancagua', + 'Sagay', + 'Majurwa', + 'Okotoks', + 'Chengannur', + 'Middletown', + 'Heredia', + 'Mbanza Kongo', + 'Texenna', + 'Urania', + 'Cantemir', + 'Albertirsa', + 'Qala', + 'Molinella', + 'Pahrump', + 'Padugupadu', + 'Utiel', + 'Harbatpur', + 'Orestiada', + 'Tiachiv', + 'Kahta', + 'Cesenatico', + 'Omaruru', + 'Siquijor', + 'America Dourada', + 'Kilkis', + 'Ascot', + 'Zhujiagua', + 'Bagheria', + 'Puerto Wilches', + 'Torre Maggiore', + 'Tomuk', + 'Huanggang', + 'Trovagunta', + 'Devanakonda', + 'Sa Pa', + 'Narashino', + 'Koganei', + 'West Memphis', + 'Pendleton', + 'Edenvale', + 'Dieburg', + 'Ankavandra', + 'Gondalga', + 'Quang Ha', + 'Xochistlahuaca', + 'Niiyama', + 'Viedma', + 'Sukhothai', + 'Cuorgne', + 'Janzur', + 'Dhansura', + 'Rio Maior', + 'Penuganchiprolu', + 'Jaora', + 'Kanzakimachi-kanzaki', + 'Hunfeld', + 'Yabayo', + 'Torre del Mar', + 'Shenyang', + 'Odacho-oda', + 'Lagdo', + 'Otuzco', + 'Hagi', + 'Pompeu', + 'Repalle', + 'Majagual', + 'Yulinshi', + 'Periyakoduveri', + 'Ubon Ratchathani', + 'Al `Amadiyah', + 'Saint-Andre', + 'Omis', + 'Arcozelo', + 'Doujing', + 'Vuhledar', + 'Hindley', + 'Aphaur', + 'Oliveira', + 'Nasir', + 'Palm Desert', + 'Khategaon', + 'Esmoriz', + 'Belmont', + 'Koani', + 'Gyomro', + 'Mackworth', + 'Rubio', + 'Zafra', + 'San Juan Evangelista', + 'Qoubaiyat', + 'Lautoka', + 'Cerkes', + 'Villeneuve-le-Roi', + 'Xinhua', + 'Touros', + 'Nyaungu', + 'Chakand', + 'Aluksne', + 'Yishui', + 'Timperley', + 'Oakwood', + 'Chakwal', + 'Tarauna', + 'Khandrauli', + 'Huaquechula', + 'Bhatinda', + 'Puerto Williams', + 'Tongliao', + 'Staffanstorp', + 'Kisumu', + 'Mangueirinha', + 'Leopoldina', + 'Luchow', + 'Harrismith', + 'Indija', + 'Campo Redondo', + 'Lastra a Signa', + 'Akhisar', + 'Alnif', + 'Tega Cay', + 'Foughala', + 'Jinjicun', + 'Kangning', + 'Treze Tilias', + 'Landau', + 'Vaires-sur-Marne', + 'Udiyavara', + 'Boquim', + 'Hekou', + 'Kirchheim unter Teck', + 'Kondakindi Agraharam', + 'Sao Mateus', + 'Simonesia', + 'Pinerolo', + 'Ptuj', + 'Mezobereny', + 'Gex', + 'Unnan', + 'Dayr Abu Hinnis', + 'Sanampudi', 'Simon Bolivar', - 'Tonk Khurd', - 'Karadipara', - 'Roverbella', - 'Stauceni', - 'Pokhraira', - 'Pappakudi', - 'Torre Boldone', - 'Cullinan', - 'Malov', - 'Nattarasankottai', - 'Solebury', - 'Mirdoddi', - 'Conthey', - 'Wietze', - 'Sao Pedro do Ivai', - 'Ergoldsbach', + 'Oteiza', + 'Gragnano', + 'Khartsyzk', + 'Beramanja', + 'Richmond Hill', + 'Juru', + 'Padavedu', + 'Ekwari', + 'Brescia', + 'La Cruz', + 'Pulimaddi', + 'Pleasant Hill', + 'Hozin', + "Sant'Ambrogio di Valpolicella", + 'Telua', + 'Bilozerske', + 'Adami Tulu', + 'Manteca', + 'Delmiro Gouveia', + 'Mindelheim', + 'Fate', + 'Hokur Badasgom', + 'Sidi Kada', + 'Talayolaparambu', + 'Connersville', + 'Gurinhem', + 'Skopje', + 'Fairless Hills', + 'Debrecen', + 'El Realejo', + 'Gadhada', + 'Schwalmtal', + 'Yamaga', + 'Bihar', + 'Pakil', + 'Loni', + 'Chilgazi', + 'Varzobkala', + 'Samandag', + 'Portela', + 'Wanghong Yidui', + 'Qianxi', + 'Dese', + 'Hathidah Buzurg', + 'Periyapuliyur', + 'Bilston', + 'Laja', + 'Makhdumpur', + 'Les Pennes-Mirabeau', + 'Himmatpura', + 'Denia', + 'Keimoes', + 'Castillo de Teayo', + 'Conselve', + 'Longmeadow', + 'Herne Bay', + 'Sao Miguel do Guama', + 'Sunland Park', + 'Israna', + 'Bassian', + 'Qift', + 'Behshahr', + 'Kotli Ablu', + 'Hidrolandia', + 'Torre Santa Susanna', + 'Kirdasah', + 'Tanjungpinang', + 'Reshuijie', + 'Wappinger', + 'Perungudi', 'Goworowo', - 'Binfield', - 'Dharhwa', - 'Heikendorf', - 'Le Petit-Couronne', - 'Gadaul', - 'Katridih', - 'Painkulam', - 'Koshanam', - 'Lequile', - "Limeira d'Oeste", - 'Newstead', - 'Stainz', - 'Titz', - 'Zanica', - 'Aigues-Mortes', - 'Azandarian', - 'Duchcov', - 'Monte Escobedo', - 'Murajpur', - 'Bagalvad', - 'Gobindpur', - 'Savoy', - 'Cheviot', - 'Kaldsletta', - 'Katuete', - 'Tordesillas', - 'Kambhampadu', - 'Hillview', - 'Pyalakurti', - 'Kursaha', - 'Brandizzo', - 'Sangaree', - 'Embrun', - 'Camliyayla', - 'Suttamalli', - 'Kottur', - 'Pibrac', - 'Aratuipe', - 'Marilandia do Sul', - 'Tilaran', - 'Chetma', - 'Chakand', - 'Guntapalli', - 'Castellabate', - 'Glodeni', - 'Longvic', - 'Teotitlan', - 'River Road', - 'Catuipe', - 'Kilcock', - 'Briceno', - 'Flieden', - 'Roquevaire', - 'Herseh Chhina', - 'Bhatkhori', - 'Parasbani', - 'Triuggio', - 'Ter Apel', - 'Al Qardahah', - 'Maraveh Tappeh', - 'Minto', - 'Malhada de Pedras', - 'Montlhery', - 'Atherstone', - 'Olmsted Falls', - 'Chelmek', - 'Norten-Hardenberg', - 'Coutras', - 'Owani', - 'Wharton', - 'Heartland', - 'Avabodji', - 'Passo do Sertao', - 'Altavilla Milicia', - 'North Cornwall', - 'Baxter', - 'Meine', - 'Domerat', - 'Amiawar', - 'Fort Mitchell', - 'Yang Talat', - 'Jujharpur', - 'Mustafabad', - 'Rodeiro', - "L'Ile-Saint-Denis", - 'Pathraha', - 'San Sebastiano al Vesuvio', - 'Perryton', - 'Lempdes', - 'Ohata', - 'Hirson', - 'Harike', - 'Benner', - 'Gillitts', - 'Koscielisko', - 'Chintakommadinne', - 'Barvynkove', - 'Paula Candido', - 'Chyhyryn', - 'Nagdah', - 'Clarendon Hills', - 'Abu Hardub', - 'Demirozu', - 'Aars', - 'Tumberi', - 'Dilawarpur', - 'Karavan', - 'Najrij', - 'Zabok', - 'Belhatti', - 'Ballina', - 'Tirschenreuth', - 'Fort Knox', - 'Campos Lindos', - 'Eduttavaynattam', - 'Bikrampur Bande', - 'Park Hills', - 'Ankatafa', - 'Sokyriany', - 'Chak Pahar', - 'Village Green-Green Ridge', - 'Highland Heights', - 'Deutsch-Wagram', - 'Untergruppenbach', - 'Logten', - 'Bedum', - 'Farob', - 'Seosaeng', - 'Le Loroux-Bottereau', - 'Isbergues', - 'Vodice', - 'Lihue', - 'Tudela de Duero', - 'Thathupur', + 'Knin', + 'Vardhamankota', + 'Campo Limpo', + 'Sermoneta', + 'Limoeiro de Anadia', + 'Otsuchi', + 'Niamina', + 'Kasumigaura', + 'West Puente Valley', + 'Sungai Petani', + 'East Windsor', + 'Pedro Celestino Negrete', + 'Yorkton', + 'Gueznaia', + 'Telica', + 'Mong Cai', + 'El Paisnal', + 'Provo', + 'Stefan Voda', + 'Vargem', + 'Treillieres', + 'Procida', + 'Sens', + 'Aperibe', + 'Comasagua', + 'Hulbuk', + 'Talakag', + 'Puduva', + 'Hashikami', + 'Randallstown', + 'Sahline', + 'Bejar', + 'Isnapuram', + 'Teghra', + 'Eschwege', + 'Carver', + 'Franklin Park', + 'Tremedal', + 'Itahara', + 'Lancut', + 'Vettikattiri', + 'Meyzieu', + 'Al Abraq', + 'Basista', + 'Charlotte Amalie', + 'Palembang', + 'Esparraguera', + 'Villacidro', + 'Berettyoujfalu', + 'Peravali', + 'Mastic Beach', + 'Perundurai', + 'San Francisco', + 'Bangassou', + 'Kauriya', + 'Carinhanha', + 'Otjiwarongo', + 'Minot', + 'Covilha', + 'Shahe', + 'Petrila', + 'Portchester', + 'Ban Lueak', + 'Aminpur', + 'Calenga', + 'Bafata', + 'Cumnock', + 'Clichy', + 'Tabernes Blanques', + 'Siloe', + 'Qiaotouyi', + 'Candido Mota', + 'Barbosa', + 'Borcka', + 'Maryland City', + 'Lacarak', + 'Crestview', + 'Jounie', + 'Hochdorf', + 'Montelibano', + 'Tundhul', + 'Osku', + 'Monsenhor Tabosa', + 'Anosiala', + 'Ban Pa Sak', + 'Kanakir', + 'Wakayama', + 'Muttenz', + 'Makale', + 'Medesano', + 'Lamerd', + 'Bakarpur Ogairah', + 'Wetherby', + 'Nakagawa', + 'Sao Jose dos Pinhais', + "Nova Brasilandia d'Oeste", + 'Piquet Carneiro', + 'Valmadrera', + 'Pua', + 'Chak Forty-one', + 'Sandvika', + 'Stansted Mountfitchet', + 'Snoqualmie', + 'Pereiras', + 'Joaquim Nabuco', + 'Mondragon', + 'Huixcolotla', + 'Minamiuonuma', + 'Gap', + 'General Villegas', + 'Matane', + 'El Monte', + 'Minamiminowa', + 'Saint-Andre-les-Vergers', + 'Ibb', + 'Oudenaarde', + 'Lainate', + 'Box Elder', + 'Karanchedu', + 'Guanhaes', + 'Calderara di Reno', + 'Itainopolis', + 'Gattaran', + 'Muhlacker', + 'Rengo', + 'Winkler', + 'Marathalli', + 'Cambuquira', + 'Ilulissat', + 'Kalyandrug', + 'Kesabpur', + 'Santiago de Anaya', + 'Ano Liosia', + 'Vung Tau', + 'Monaco', + 'Cuesmes', + "Ra's al `Ayn", + 'Rasebetsane', + 'Tagudin', + 'Basopatti', + 'Mack', + 'Pedra Badejo', + "Les Sables-d'Olonne", + 'Hosakote', + 'Barbastro', + 'Tutoia', + 'Manpur', + 'Higashiyamato', + 'Varvarin', + 'Manhica', + 'Kachchippalli', + 'Velugodu', + 'Palin', + 'Xinchangcun', + 'Alchevsk', + 'Anzegem', + 'Doi Saket', + 'Amersham', + 'Namburu', + 'Union Hill-Novelty Hill', + 'Apopa', + 'Zafarabad', + 'Nanminda', + 'Burlington', + 'Hibbing', + 'Galloway', + 'Union City', + 'Dukinfield', + 'Montecristo', + 'Shrigonda', + 'Uchoa', + 'Tizi-n-Tleta', + 'Stellenbosch', + 'Olaine', + 'Isabel', + 'Luqa', + 'Matinha', + 'Bni Rzine', + 'Attimarappatti', + 'Circasia', + 'Ban Krot', + 'Selimpasa', + 'Xangongo', + 'Simiganj', + 'Coacoatzintla', + 'Nueva Helvecia', + 'Chenzhou', + 'Lota', + 'Lawrenceville', + 'Vayanur', + 'Tobe', + 'Ende', + 'Haslemere', + 'Calabayan', + 'Pakxe', + 'Pajapan', + 'Udhampur', + 'Tsararivotra', + 'Telerghma', + 'Haydock', + 'Surmon Chogga Grong', + 'Trebic', + 'Alafaya', + 'Kafr Sajnah', + 'Conceicao', + 'Vellore', + 'Usingen', + 'Terenure', + 'Bouca', + 'Ghat Borul', + 'Baisuhalli', + 'Daulatpur', + 'Grossrohrsdorf', + 'Lorica', + 'Hagaribommanahalli', + 'Ban Thoet Thai', + 'Loznica', + 'Ponmala', + 'Padiyur', + 'Tigoa', + 'Budva', + 'Mistassini', + "'Ain Babouche", + 'El Limon', + 'Diouna', + 'Rieti', + 'Kuttyadi', + 'Xinyang', + 'Killiney', + 'Pop', + 'Guaymango', + 'Springbok', + 'Presque Isle', + 'Timra', + 'Abuja', + 'Miyakojima', + 'Payyannur', + 'Xunyang', + 'Bailen', + 'Chambellan', + 'Bukit Mertajam', + 'Cattolica', + 'Serdar', + 'Sarare', + 'Coronel Vivida', + 'Herriman', + 'Guliston', + 'Rouvroy', + 'Garfield', + 'Elmina', + 'Sarreguemines', + 'Milwaukie', + 'Ershui', + 'Garot', + 'Czestochowa', + 'Kirklareli', + 'La Jagua de Ibirico', + 'Stroud', + 'Kocaeli', + 'Calimaya', + 'Savalou', + 'Manalalondo', + 'Cikupa', + 'Cide', + 'Idylwood', + 'East Massapequa', + 'Andijon', + 'Ibusuki', + 'Brahmapur', + 'Mount Prospect', + 'St. James', + 'Vila Franca de Xira', + 'Bhadreswar', + 'Khandwa', + 'Amporoforo', + 'Celic', + 'Gomec', + 'Fort Carson', + 'Kosiv', + 'Fria', + 'Cliftonville', + 'Narvacan', + 'Ramanathapuram', + 'Jawasa', + 'Guclukonak', + 'Samobor', + 'Ceska Trebova', + "Anan'evo", + 'Zinjibar', + 'Indianapolis', + 'Yanggok', + 'Aberdare', + 'Palm River-Clair Mel', + 'Diari', + 'Chilmil', + 'Callosa de Segura', + 'Kummersbruck', + 'Sambava', + 'Pritzwalk', + 'Karai', + 'Lachhmangarh Sikar', + 'Wade Hampton', + 'Rapla', + 'Assa', + 'Malavalli', + 'Trinec', + 'La Verne', + 'Selibaby', + 'Zagnanado', + 'Commerce City', + 'Tredyffrin', + 'Salaberry-de-Valleyfield', + 'Longtan', + 'Karatsu', + 'Badian', + 'Sao Sebastiao do Paraiso', + 'Satyamangala', + 'Balsta', + 'Gamagori', + 'Chinampa de Gorostiza', + "Ambinanin'i Sakaleona", + 'Itiquira', + 'Center', + 'Umargam', + 'Ozurgeti', + 'Montereau-faut-Yonne', + 'Amau', + 'Nova Esperanca', + 'Venezuela', + 'Kafia Kingi', + 'Tanguturu', + 'Vinto', + 'Sonosari', + 'Sturovo', + 'Date', + 'Niska Banja', + 'An Nhon', + 'Littlehampton', + 'Fuente Palmera', + 'Sokode', + 'Donghua', + 'South Holland', + 'Frimley', + 'Bachchannapet', + 'Junnardev', + 'Dole', + 'Neuotting', + 'Monforte del Cid', + 'Baguley', + 'Brimington', + 'Calauan', + 'Durmersheim', + 'Wittenberge', + 'Echizen', + 'Dobropillia', + 'Ayuquitan', + 'Viramgam', + 'Matsuura', + 'Abu Dis', + 'Winsum', + 'Gentbrugge', + 'Villa Victoria', + 'Yovon', + 'Boaz', + 'Kotta Kalidindi', + 'Great Bend', + 'Tarcento', + 'Limbazi', + 'Bajos de Haina', + 'Karakax', + 'Ibira', + 'Yakushima', + 'Goito', + 'Nabari', + 'Sabanalarga', + 'Tiou', + 'Renens', + 'Dolores', + 'Agago', + 'Madakalavaripalli', + 'Mapastepec', + 'La Lucila', + 'Cherakhera', + 'Sadaseopet', + 'Neerijnen', + 'Krathum Baen', + 'Gansbaai', + 'Mahalandi', + 'Chanaur', + 'La Argentina', + 'Jesup', + 'Bela Crkva', + 'Soteapan', + 'Siechnice', + 'Lwakhakha', + 'Uspallata', + 'Imbatug', + 'Altavas', + 'Jaglot', + 'Colangute', + 'Kumatori', + 'Andapa', + 'Choconta', + 'Sarhari', + 'Santiago Jocotepec', + 'Arauca', + 'Hailin', + 'Shahr-e Majlesi', + 'Guyuan', + 'Murfatlar', + 'Chon Buri', + 'Bacnotan', + 'Kutna Hora', + 'Xiva', + 'Mizque', + 'West Ham', + 'Roatan', + 'Doylestown', + 'Tarichar Kalan', + 'Foz do Iguacu', + 'Garching an der Alz', + 'Tifariti', + 'Longwy', + 'Tarikere', + 'Alameda', + 'Gbanhi', + 'Catunda', + 'Kirchhundem', + 'Cuenca', + 'Delareyville', + 'Cliffside Park', + 'Orting', + 'Kapadvanj', + 'Nigran', + 'Fengyicun', + 'Pazardzhik', + 'Yeddumailaram', + 'Longkeng', + 'Nikaho', + 'Altofonte', + 'Douar Oulad Youssef', + 'Lathi', + 'Osh', + 'Daytona Beach', + 'Atharan Hazari', + 'Ami', + 'Balaguer', + 'Malnate', + 'Quanzhang', + 'Rio Claro', + 'Hajdusamson', + 'Gouvea', + 'Kunming', + 'Kulasegaram', + 'Pori', + 'Braintree', + 'Bijelo Polje', + 'Mateur', + 'Kozova', + 'Fenoarivo Atsinanana', + 'Leisure World', + 'Taman Senai', + 'Nerinjippettai', + 'Washington', + 'Basapatna', + 'Mwene-Ditu', + 'Norak', + 'South Upi', + 'Yokadouma', + 'Abbigeri', + 'Kouoro', + 'Freilassing', + 'Nymburk', + 'Cangandala', + 'Dihri', + 'Arakli', + 'Huaihua', + 'Turkauliya', + 'Ramainandro', + 'Aytos', + 'Lihe', + 'Raseborg', + 'Tomioka', + 'Sakrand', + 'Belur', + 'Kaseda-shirakame', + 'Mettingen', + 'Bugalagrande', + 'Annandale', + 'Mambere', + 'Oume', + 'Al Buwaydah', + 'Eagle', + 'Ustron', + 'Pegnitz', + 'Massaguet', + 'Bibbiena', + 'Saint-Vith', + 'Geelong', + 'Glen Rock', + 'Miarinavaratra', + 'Sao Simao', + 'Gurlan', + 'La Escala', + 'Mian Channun', + 'Tono', + 'Kevelaer', + 'Jiaozhou', + 'Einsiedeln', + 'Udaypur Gadhi', + 'Molagavalli', + 'Sira', + 'Ospina', + 'Kuduru', + 'Komarolu', + 'Arnprior', + 'Breclav', + 'Qornet Chahouane', + 'Okaya', + 'Montesarchio', + 'Tecoh', + 'Dezful', + 'Quiculungo', + 'Tam Ky', + 'Qaracuxur', + 'Daxin', + 'Horsham', + 'Tafalla', + 'Yehud', + 'Abertawe', + 'Darien', + 'Shodoshima', + 'El Arenal', + 'Litomerice', + 'Caboolture', + 'Norwalk', + 'Mananara Avaratra', + 'Herten', + 'Kihihi', + 'Aira', + 'Kuttampala', + 'Noumea', + 'Phon-Hong', + 'Thair', + 'Herzogenrath', + 'Planalto', + 'Arrecifes', + 'Fuente-Alamo de Murcia', + 'Gilbues', + 'Miltenberg', + 'Bubong', + 'Henstedt-Ulzburg', + 'Rayavaram', + 'Alberique', + 'Pimpalgaon Raja', + 'Palencia', + 'Lalganj', + "L'Isle-Adam", + 'Abasolo', + 'Sirikonda', + 'Devadanappatti', + 'Pokrovka', + 'Baliguian', + 'Corum', + 'Tlacolula de Matamoros', + 'Jeremie', + 'Myaungmya', + 'Tissa', + 'Capljina', + 'Ambariokorano', + 'Gemert', + 'Akayu', + 'Bhiwandi', + 'Chishui', + 'Abbotsford', + 'La Carlota', + 'Antalya', + 'Yongjing', + 'Tres Marias', + 'Haa', + 'Meerhout', + 'Sibu', + 'Astara', + 'Gar', + 'Ndola', + 'Sao Tiago de Custoias', + 'Karrapur', + 'Chartiers', + 'Songea', + 'Mouila', + 'Streator', + 'Al Qamishli', + 'Nikaweratiya', + 'Delbruck', + 'Batonyterenye', + 'Odzak', + 'Agudos', + 'Gatineau', + 'Vineyard', + 'Saint-Rambert', + 'Kesath', + 'Sugar Grove', + 'Tuensang', + 'Los Reyes de Juarez', + 'Sardinal', + 'Eksjo', + 'Safety Harbor', + 'Kilkenny', + 'Tsiroanomandidy', + 'Agartala', + 'Agrate Brianza', + 'Nomimachi', + 'North Tonawanda', + 'Stafford', + 'Paramoti', + 'Cavdir', + 'Houmt Souk', + 'Domagnano', + 'Kaset Wisai', + 'Piedmont', + 'Nazareth', + 'Anjialava', + 'Stebnyk', + 'Golyaka', + 'Zehdenick', + 'Birstonas', + 'Chaklasi', + 'Carira', + 'Sapatgram', + 'Bankura', + 'Rosignano Marittimo', + 'Quchan', + 'Hoeilaart', + 'Angul', + 'Erechim', + 'Xinshi', + 'Jima', + 'Upper Southampton', + 'Baramula', + 'Joao Neiva', 'Vanukuru', - 'Kottadindulu', - "Sint-Job-in-'t-Goor", - 'Halawah', - 'Ouda-daito', - 'Gulf Hills', - 'Timmendorfer Strand', - 'Bishamagiri', - 'Pa Sang', - 'Redlynch', - 'Artigues-pres-Bordeaux', - 'Dirusumarru', - 'Serramazzoni', - 'Dobele', - 'Nansio', - 'Nandnawan', - 'Bovalino Marina', - 'Guntersville', - 'Solleftea', - 'Saint-Chamas', - 'Chamonix-Mont-Blanc', - 'San Bartolome Milpas Altas', - 'Lint', - 'Vergiate', - 'Buckie', - "Sant'Agnello", - 'Budenheim', - 'Sobhapur', - 'Anyksciai', - 'Rakitovo', - 'Kaoni', - 'Mahadipur', - 'Lourosa', - 'Niederwerrn', - 'Bisaul', - 'Panfilovka', - 'La Peche', - "'s-Heerenberg", - 'Bouaiche', - 'Chapel en le Frith', - 'Pinjranwan', - 'Digar', - 'Beibu', - 'Solotvyno', - 'Zuera', - 'Rangwasa', - 'Manteno', - 'Wiang Haeng', - 'Slateng Dua', - 'Parsad', - 'Tokatippa', - 'Long Hill', - 'Pantelho', - 'Ulatu', - 'Gokhulapur', - 'Belo Vale', - 'Monte Alegre do Sul', - 'Kilakkurichchi', - 'Kattirippulam', - 'Rajhanpur', - 'Cradock', - 'Chop', - 'Le Poire-sur-Vie', - 'Sa`idi', - 'East Donegal', - 'Vyetka', - 'Midalam', - 'Khandauli', - 'Shahrak-e Pars', - 'Sredets', - 'Garesnica', - 'Fort Riley', - 'Beutelsbach', - 'Basrur', - 'Mannegudam', - 'Chettiyapatti', - 'Nierstein', - 'Stansted Mountfitchet', - 'Hakubacho', - 'Ouro Verde', - 'Canford Cliffs', - 'Segaon', - 'Martano', - 'Mechanicstown', - 'Ferreira do Zezere', - 'Tarazu', - 'Panjampatti', - 'Hathiakan', - 'Trissino', - 'Buda-Kashalyova', - 'Raiparthi', - 'Hire Vadvatti', - 'Soverato Marina', - 'Moribila', - 'Tibro', - 'Magam', - 'Saidabad', - 'Chanp', - 'Petilia Policastro', - 'Templeton', - 'Arealva', - 'Santa Cruz do Monte Castelo', - 'Bremgarten', - 'Manpur', - 'Pirojgarh', - 'Whitwick', - 'Piliscsaba', - 'Barntrup', - 'Vostochnyy', - 'Corbin', - 'Ammanford', - 'New Ross', - 'Antargangi', - 'Tombos', - 'Aurisina', - 'Kappeln', - 'Kharod', - 'Carneys Point', - 'Oulad Khallouf', - 'Teghra', - 'Achchampeta', - 'Narino', - 'Karkkila', - 'Khaur', - 'Skowhegan', - 'Amalou', - 'Pasaul', - 'Jainagar', - 'Silaiyampatti', - 'Kanavaypatti', - 'Bientina', - 'Mudichchur', - 'Shyamnagar', - 'Zaandijk', - 'Nakaseke', - 'Schwarzenbruck', - 'Nefasit', - 'Chamba', - 'Velim', - 'Kennedy', - 'Citrus Hills', - 'Ueckermunde', - 'Hata', - 'Bad Rothenfelde', - 'Mauleon', - 'Seffner', - 'Egg', - 'La Belleza', - 'Peralta', - 'Balakrishnanpatti', - 'Serramanna', - 'Aibonito', - 'Amingaon', - 'Pariyari', - 'Koila', - 'Vrable', - 'Miyada', - 'Zuromin', - 'Dobrada', - 'Haibach', - 'Bryans Road', - 'Monona', - 'Quezalguaque', - 'Kanyakulam', - 'Amudalapalle', - 'Piliv', - 'Rayon', - 'Jalhay', - 'Kennedale', - 'Plabennec', - 'Roussillon', + 'Shiwan', + 'White Horse', + 'Morong', + 'Frascati', + 'Schrobenhausen', + 'Luvungi', + 'Itirapina', + 'Nari Bhadaun', + 'Tarnaveni', + 'Mytilini', + 'Destrehan', + 'Eybens', + 'Dianga', + 'Pasarkemis', + 'Najafabad', + 'Swiecie', + 'Cobourg', + 'San Jorge', + 'Pfastatt', + 'Kusmaul', + 'Fallersleben', + 'Pershotravensk', + 'Mahambo', + 'Sigli', + 'Annaba', + 'Turku', + 'Pedda Vegi', + 'Mesa Geitonia', + 'Charam', + 'Charentsavan', + 'Imielin', + 'Orvault', + 'Lodz', + 'Sam Ko', + 'Foz', + 'Alexandroupoli', + 'Demmin', + 'Castelleone', + 'Burauen', + 'Capilla del Monte', + 'Ettlingen', 'Srirangapur', - 'Merksplas', - 'Anantasagaram', - 'Swissvale', - 'Eden Isle', - 'Gundur', - 'Adalar', - "Rava-Rus'ka", - 'Mareeba', - 'Viechtach', - 'El Ghomri', - 'Vinica', - 'Vif', - 'Tarxien', - 'Lakhzazra', - 'Gidan Ider', - 'Heroldsberg', - 'Thorigne-Fouillard', - 'Jagta', - 'Othello', - 'Gering', - 'Kizilcasar', - 'Dekanme', - 'Monte Porzio Catone', - 'Tamza', - 'Tougouni', - 'Yasinia', - 'Moss Vale', - 'Vicam Pueblo', - 'Liubymivka', - 'Nuevo Paysandu', - 'Sinimbu', - 'Ouled Abbes', - 'Kalaun', - 'Yali', - 'Waltham Cross', - 'Trebisacce', - 'Bandamurlanka', - 'El Espinal', - 'Ahumada', - 'Fallanden', - 'Karpenisi', - 'Kaliganj', - 'Seyyedan', - 'La Grande-Motte', - 'Nunihat', - 'Hale Dyamavvanahalli', - 'Virapperumanallur', - 'Torre de Moncorvo', - 'Steti', - 'Bucksburn', - 'Nettadahalli', - 'Rani Sagar', - 'Masandra', - 'Lalam', - 'Lamesa', - 'Reinosa', - 'Janze', - 'Kirk of Shotts', - 'Charuanwan', - 'Shiddapur', - 'Ban Ratchakrut', - 'Babhangaon', - 'Gamail', - 'Landupdih', - 'Locogahoue', - 'Biberist', + 'Camamu', + 'Saruhanli', + 'Ferfer', + 'Aurangabad', + 'Taromske', + 'Hinigaran', + 'San Juan de Dios', + 'Saint-Maur-des-Fosses', + 'Bunkyo-ku', + 'Renfrew', + 'Mus', + 'Lake Jackson', + 'Xirdalan', + 'Samayac', + 'Spanish Lake', + 'Izegem', + 'Nema', + 'Dongducheon', + 'Hecelchakan', + 'Seoni', + 'Wood Green', + 'Castelfranco Veneto', + 'Bostanici', + 'Itajiba', + 'Inagi', + 'Oakham', + 'Boa Vista', + 'Puquio', + 'Chittaranjan', + 'Tibro', + 'Pitangueiras', + 'Rouached', + 'Nouakchott', + 'Nuevo San Juan Parangaricutiro', + 'Sao Jose do Campestre', + 'Heyin', + 'Vacaria', + 'Lukavac', + 'Katy', + 'Caibiran', + 'Villasis', + 'Pontianak', + 'Pallijkarani', + 'Rayapalle', + 'San Pedro Carcha', + 'Kabirwala', + 'Idhna', + 'Kiama', + 'Armadale', + 'Braunschweig', + 'Lathasepura', + 'Bajo Boquete', + 'Shal', + 'Balyqshy', + "Long'e", + 'Felgueiras', + 'Arteijo', + 'Dhanaula', + 'Kaoni', + 'Telford', + 'Laukaria', + 'Druskininkai', + 'Sayhat', + 'Skanderborg', + 'Lindome', + 'Paramanandal', + 'Quebrangulo', + 'Bida', + 'Narragansett', + 'Valle Hermoso', + 'Santa Catarina Pinula', + 'Muriedas', + 'Tawnza', + 'Arnouville-les-Gonesse', + 'Ouaoula', + 'Shahrixon', + 'Alcamo', + 'Naujoji Akmene', + 'Pappakurichchi', + 'Toyonaka', + 'Uttukkuli', + 'Ilave', + 'Villupuram', + 'Bhojpur Jadid', + 'Ischia', + 'Rio Verde Arriba', + 'Radolfzell am Bodensee', + 'Llica', + 'Erjie', + 'Qiaomaichuan', + 'Lamont', + 'Bezliudivka', + 'Five Corners', + 'Niksic', + 'Hnivan', + 'Tamale', + 'Khanapur', + 'Ichnia', + 'Sesvete', + 'Reeuwijk', + 'Qutur', + 'Moana', + 'San Pedro Atocpan', + 'Osny', + 'Toda Bhim', + 'Zaouiet Sousse', + 'Lavras', + 'Ouardenine', + 'Katakos', + 'Hetton le Hole', + 'Iseo', + 'Lehigh', + 'Hallim', + 'Bonou', + 'Moita Bonita', + 'Shakargarh', + 'Chiapa de Corzo', + 'Zhanggu', + 'Meudon', + 'Ayikudi', + 'Cunduacan', + 'Jingling', + 'Jiantang', + 'Laojiezi', + 'Bazid Chak Kasturi', + 'Elliniko', + 'Rifu', + 'Duanshan', + 'Busselton', + 'Liubashivka', + 'Maniyur', + 'Singuilucan', + 'Erkrath', + 'Mucari', + 'Tumwater', + 'Yaoquan', + 'Santa Maria Ixhuatan', + 'Sidi Bel Abbes', + 'Namanga', + 'Afsin', + 'An Phu', + 'Bamyan', + 'Mannanchori', + 'Shahr-e Qods', + 'Bierun', + 'Vijapur', + 'Boli', + 'Hirni', + 'Ibitiara', + 'Pachchampalaiyam', + 'Hutto', + 'Talibon', + 'Bilbao', + 'Readington', + 'Pasivedalajimma', + 'Sariaya', + 'Lappersdorf', + 'Jodhpur', + 'Opava', + 'Shelton', + 'Ledegem', + 'Cabedelo', + 'Tiptur', + 'Narsapur', + 'Jamira', + 'Kaufbeuren', + 'Ricany', + 'Ansonia', + 'Mirandopolis', + 'Gondizalves', + 'Brilon', + 'Tarumirim', + 'Leek', + 'Sheopuria', + 'Dongfeng', + 'Pozanti', + 'Fuyingzicun', + 'Sartrouville', + 'Vigonovo', + 'Tatakan', + 'Kountouri', + 'Gharbia', + 'Figuig', + 'Shire', + 'Swabi', + 'Wismar', + 'Chachagui', + 'Nedumudi', + 'Carrickfergus', + 'St. Thomas', + 'Jaicos', + 'Tiruvaduturai', + 'Bolinao', + 'Eumseong', + 'Edina', + 'Essey-les-Nancy', + 'Saint-Julien-en-Genevois', + 'Grosuplje', + 'Grand Haven', + 'Al Faw', + 'Androrangavola', + 'Hassi Maameche', + 'Rubi', + 'Busesa', + 'Villa Tapia', + 'Divo', + 'Benalmadena', + 'Redmond', + 'Rajaori', + 'Kraaipan', + 'Nisporeni', + 'Wandan', + 'Aguia Branca', + 'Lake Park', + 'Hoquiam', + 'Jan Kempdorp', + 'Lentvaris', + 'Waikanae', + 'Reboucas', + "Pomigliano d'Arco", + 'Meycauayan', + 'Saugor', + 'Pasacao', + 'Schinnen', + 'Glan', + 'Lavagna', + 'Betnoti', + 'Ban Wat Sala Daeng', + 'Romsey', + 'Campi Salentina', + 'Glinde', + 'Gamprin', + 'Chandanais', + 'Taiping', + 'Marivorahona', + 'Store', + 'Vardenis', + 'Salima', + 'Kadanadu', + 'Jarqo`rg`on', + 'Barlad', + 'Bethpage', + 'Boscotrecase', + 'Dhamua', + 'Yelm', + 'Tlacotepec', + 'Parame', + 'Haapsalu', + 'Diadi', + 'Huetor Vega', + 'Jozefow', + 'Diessen am Ammersee', + 'Meyrin', + 'Crofton', + 'Galvez', + 'Boulder', + 'Masi-Manimba', + 'Aubervilliers', + 'Unguia', + 'Caslav', + 'El Centro', + 'El Fasher', + 'Beersheba', + 'Hujra Shah Muqim', + 'Bajil', + 'Tomas Oppus', + 'Liancheng', + 'Arkivan', + 'Jasidih', + 'Marturu', + 'Evry', + 'Easttown', + 'Lebedyn', + 'Garhpura', + 'Chinaur', + 'Jean-Rabel', + 'Chichigalpa', + 'Talukkara', + 'Kakuda', + 'Bozoum', + 'Tuzdybastau', + 'Pudimadaka', + 'Iraquara', + 'Blanquefort', + 'Batman', + 'Iserlohn', + 'Castano Primo', + 'Uttaradit', + 'Bartlesville', + 'Sapna', + 'Humpolec', + 'Avanashipalaiyam', + 'Rawajaya', + 'Gadarwara', + 'Mascote', + 'Narkatpalli', + 'Kendale Lakes', + 'White City', + 'Moss', + 'Nnewi', + 'Douar Oulad Aj-jabri', + 'Pata Uppal', + 'Dhiban', + 'Salitre', + 'West Babylon', + 'Khulays', + 'Teplohirsk', + 'Bannu', + 'Mudki', + 'Agar', + 'Al Madad', + 'Chokwe', + 'Udala', + 'Chichli', + 'Lemington', + 'Khatima', + 'Shangrao', + 'Chiriguana', + 'Baliuag', + 'Balua Rampur', + 'Nafplio', + 'Kudat', + 'Cabusao', + 'Acatic', + 'Madougou', + 'Tiszafured', + 'Akurana', + 'Kingston', + 'Pariaman', + 'Seacroft', + 'Tecoman', + 'Alavus', + 'Kanteru', + 'Jaramana', + 'Schodack', + 'Eniwa', + 'Fuzhou', + 'Klobuck', + 'Budhma', + 'Lelydorp', + 'Great Yarmouth', + 'Missoes', + 'Porto Velho', + 'Muhanga', + 'Porto Ingles', + 'Harderwijk', + 'Ubungo', + 'Phopnar Kalan', + 'Chrysoupoli', + 'Zarzis', + 'Nanning', + 'Tekeli', + 'Drammen', + 'Montivilliers', + 'Gualeguay', + 'Nishinomiya-hama', + 'Laguna de Duero', + 'Moraga', + 'Alzano Lombardo', + 'Miki', + 'Janin', + 'Frederico Westphalen', + 'Moulins', + 'Kuningan', 'Castelnuovo di Porto', - 'Coahuitlan', - 'Semere', - 'Vaucresson', - 'Obersiggenthal', - 'Millis', - 'Anjahamarina', - 'Kamien Pomorski', - 'Na Yung', - 'Youghal', - 'Dharmajigudem', - 'Castel Gandolfo', - 'Oak Island', - 'Navipet', - 'Vicopisano', - 'Shediac', - 'Loenen', - 'Bushtyno', - 'Horice', - 'Poytya', - 'Miduturu', - 'San Pedro Ixtlahuaca', - 'Usiacuri', - 'Sompting', - 'Kings Grant', - 'Reeuwijksebrug', - 'Tanmpegre', - 'Chapalamadugu', - 'Lambarkiyine', - 'Ayotoxco de Guerrero', - 'Nerubaiske', - 'Pedreguer', + 'Irimbiliyam', + 'Kharar', + 'Cholavandan', + 'Csomor', + 'Amurrio', + 'Tiruchchuli', + 'Steffisburg', + 'Parksville', + 'Anontsibe-Sakalava', + 'Nueva Concepcion', + 'Le Locle', + 'Harsewinkel', + 'Kaonke', + 'Sao Joao Batista', + 'Hokuto', + 'Aubange', + 'Bni Boufrah', + 'Sirmatpur', + 'Gignac-la-Nerthe', + 'Igarata', + 'Kharki', + 'Pamarru', + 'Bhimunipatnam', + 'Perdoes', + 'Qarqaraly', + 'Iisalmi', + 'Koussane', + 'Pittalavanipalem', + 'Tilakpur', + 'Okuchi-shinohara', + 'Alfenas', + 'Mindouli', + 'Chokkalingapuram', + 'Webster', + 'Rorschach', + 'Mascali', + 'Stauceni', + 'Mucaba', + 'Heemskerk', + 'Tari', + 'Bitam', + 'Ullal', + 'Qari Kola-ye Arateh', + 'Brownwood', + 'Santee', + 'Akbarpur', + 'Mega', + 'Motosu', + 'Csorna', + 'Cavarzere', + 'Omallur', + 'Virarajendrapet', + 'Wixom', + 'Murak', + 'Niederkruchten', + 'Aldine', + 'Jalihalli', + 'Batajnica', + 'Bardibas', + 'Madina do Boe', + 'Kallar', + 'Rhennouch', + 'East Providence', + 'Oras', + 'Vittuone', + 'Corbelia', + 'San Pedro Jicayan', + 'Telnal', + 'Parmanpur', + 'Morena', + 'Olindina', + 'Sumpango', + 'Bielsk Podlaski', + 'Mogoditshane', + 'Gulsehir', + 'Kumari', + 'Yantzaza', + 'Ambalavao', + 'Vohitany', + 'Qianxucun', + 'Pragatinagar', + 'Siaya', + 'Pombos', + 'Thuan Tien', + 'Minas de Matahambre', + 'Haaren', + 'Concarneau', + 'Al Marj', + 'Desborough', + 'Brewster', + 'San Miguel Ocotenco', + 'Toba Tek Singh', + 'Quito', + 'Pushkar', + 'Bagasra', + 'Snihurivka', + 'Nsawam', 'Raonta', - 'Paloma Creek South', - 'Dougoufe', - 'Brembate', - 'Merrydale', - 'Gretz-Armainvilliers', - 'Buba', - 'Harewa', - 'Lohna', - 'Closter', - 'Takieta', - 'Kodaimangalam', - 'Yaragol', - 'Modachchur', - "Nerk'in Getashen", - 'Ergue-Gaberic', + 'Pishbar', + 'Hanamsagar', + 'Lemay', + 'Douliu', + 'Linlithgow', + 'Mamqan', + 'Phulaut', + 'Colwyn Bay', 'East Leake', - 'Sakhua', - 'Nesarg', - 'Vairichettipalaiyam', - 'Nulvi', - 'Arab', - 'Conewago', - 'Ad Darbasiyah', - 'Staufenberg', - 'Sukand', - 'Troina', - 'Monte San Savino', - 'Dachne', - 'Furstenfeld', - 'Colindres', - 'Iwaizumi', - 'Dunn', - 'Muzo', - 'Tadinada', - 'Tifra', - 'Pata Uppal', - 'West Long Branch', - 'Barton', - 'Hadibu', - 'Imsida', - 'Paszto', - 'Yamkanmardi', - 'Wissen', - 'Siegsdorf', - 'Bad Endorf', - 'Mucheln', - 'Glenwood', - 'Privas', - 'Reddiyapatti', - 'Kolumalapalle', - 'Arizona City', - 'Taftanaz', - 'Bacobampo', - 'Alfonso Castaneda', - 'Santiponce', - 'Zogno', - 'Bifeng', - 'Aglasun', - 'Kandern', - 'Tsallagundla', - 'Puran Bigha', - 'Kandanati', - 'Clusone', - 'Ortuella', - 'Talwandi Chaudhrian', - 'Nangal Chaudhri', - 'Perryville', - 'Chak Thathi', - 'Talakulam', - 'Guria', - 'Ban Charoen Mueang', - 'Meltham', - 'Ban Wat Phrik', - 'Marcolandia', - 'Rottenburg an der Laaber', - 'Bartica', - 'Dattapara', - 'Sulakyurt', - 'Mangala', - 'Poninguinim', - 'Bushkill', - 'Chamusca', - 'Worplesdon', - 'Montecito', - 'Keregodu', - 'Hongtuliang', - 'Montague', - 'Secovce', - 'Nonnweiler', - 'Penkridge', - 'Severance', - 'Malverne', - 'Ararica', - 'Nossa Senhora dos Remedios', - 'Kasap', - 'Phopnar Kalan', - 'Mockmuhl', - 'La Salvetat-Saint-Gilles', - 'Sallisaw', - 'Le Mont-sur-Lausanne', - 'Nijgaon Paranpur', - 'Kosiv', - 'Clayton le Moors', - 'Pokrovka', - 'Lewistown', - 'Lanco', - 'Nawanagar', - "Ra's al Ma`arrah", - 'Qorovul', - 'Woltersdorf', - 'Hundested', - 'Laitila', - 'Cam', - 'Thandewala', - 'Khutha Baijnath', - 'Kandanur', - 'Medikunda', - 'Perenchies', - 'Andanappettai', - 'Delavan', - 'Olamze', - 'Neuenburg', - 'Kond Rud', - 'Poniatowa', - 'Reichelsheim', - 'Moser', - 'Hanko', - 'Oakengates', - 'Schnaittach', - 'Perungulam', - 'Dodvad', - 'Santa Margherita Ligure', - 'Wieruszow', - 'Hathapur', - 'Lycksele', - 'Uedem', - 'Thaon-les-Vosges', - 'Sutherlin', - 'Richland Hills', - 'Carbonita', - 'Sautron', - 'Bedwas', - 'Sagarpur', - 'Darsur', - 'Whitehouse', + 'Bargara', + 'Phan Rang-Thap Cham', + 'Jouy-le-Moutier', + 'Whyalla', + 'La Rioja', + 'Ferrenafe', + 'Yenmangandla', + "Ben 'Aknoun", + 'Fier', + 'Baharampur', + 'Kin', + 'Staphorst', + 'Gondar', + 'Pantnagar', + 'Barnagar', + 'Campobello di Licata', + 'Rukan', + 'Masatepe', + 'Barroso', + 'Savnik', + 'Huilong', + 'Porto Seguro', + 'Tanjungbalai', + 'Sembedu', + 'Lunenburg', + 'Kampung Tengah', + 'Tatsunocho-tominaga', + 'Oosterwolde', + 'Aver-o-Mar', + 'Poughkeepsie', + 'Anjozorobe', + 'Zengcun', + 'Soavimbahoaka', + 'Warr Acres', + 'Donacarney', + 'Galesburg', + 'Alma', + 'Fuchu', + 'Lehrte', + 'Angelopolis', + 'Ventanas', + 'Barro Alto', + 'Santana do Matos', + 'Patnongon', + 'East Dereham', + 'Tibagi', + 'Rambilli', + 'Punturin', + 'Balzar', + 'Beaufort West', + 'Sendai', + 'Szekszard', + 'Kaizuka', + 'Motatan', + 'Smiths Falls', + 'Litherland', + 'Maisenhausen', + 'Gandara', + 'Ban Mae Kham Lang Wat', + 'Madrid', + 'Pasrur', + 'Shahganj', + 'Escazu', + 'Pakruojis', + 'Shiogama', + 'Kallad', + 'Matinilla', + 'Delemont', + 'Bilga', + 'Kasur', + 'Khattab', + 'Palmi', + 'Sariz', + 'Didymoteicho', + 'Pallippuram', + 'Wagrowiec', + 'Munro', + 'Aschersleben', + 'Ndalatando', + 'Cecchina', + 'Meizichong', + 'Elamattur', + 'Umred', + 'Bonita Springs', + 'Cujubim', + 'Red Oak', + 'Montlouis-sur-Loire', + 'Santa Rosa de Osos', + 'Dehmoi', + 'Pesochin', + 'Sadao', + 'Nagyatad', + 'Khusropur', + 'Klagenfurt', + 'Bou Merdes', + 'Acatenango', + 'Demiryol', + 'Sinnuris', + 'Juazeirinho', + 'Sivakasi', + 'Hunxe', + 'Lamu', + 'Ravensthorpe', + 'Streetsboro', + 'Marugame', + 'Nizampur', + 'Salina', + 'Baglung', + 'Aketao', + 'Schwedt (Oder)', + 'Medrissa', + 'Nordwalde', + 'Rielasingen-Worblingen', + 'Santiago Tianguistenco', + 'Dahuk', + 'Lubutu', + 'Ambohipihaonana', + 'Felino', + 'Kitwe', + 'Langarud', + 'San Rafael Las Flores', + 'Kurwa Mathia', + 'Deuil-la-Barre', + 'Sitampiky', + 'Westchase', + 'Korkut', + 'Aracariguama', + 'Verneuil-sur-Seine', + 'Sucy-en-Brie', + 'Vulcanesti', + 'Berkeley Heights', + 'Suhut', + 'Saratamata', + 'Owk', + 'Holzgerlingen', + 'Neckargemund', + 'Piacenza', + 'Kakkalapalle', + 'Tendo', + 'Atlanta', + 'Kamsar', + 'East Bridgewater', + 'Krizevci', + 'Mandapeta', + 'Kusumha', + 'South Valley', + 'Bhargaon', + 'Birkerod', + 'Olintla', + 'Jiabong', + 'Winona', + 'Ambinanitelo', + 'Tlajomulco de Zuniga', + 'Monument', + 'Matay', + 'Jingping', + 'Gadoon', + 'Yingmen', + 'Bondoukou', + 'Sirpanandal', + 'Materi', + 'Englewood', + 'Nea Moudania', + 'Shanglingcun', + 'Sutton in Ashfield', + 'Maule', + 'Djidja', + 'Long Eaton', + 'Wasco', + 'Satao', + 'Idrija', + 'Catacamas', + 'Oga', + 'Canelli', + 'Seydunganallur', + 'Sidi Ettiji', + 'Civitavecchia', + 'Bouc-Bel-Air', + 'Itapetim', + 'Shizuishan', + 'Ron', + 'San Sebastian Tutla', + 'Lupeni', + 'Buenaventura Lakes', + 'Morsang-sur-Orge', + 'Adamstown', + 'Daraina', + 'Penugonda', + 'Pachkhal', + 'Genemuiden', + 'Supe', + 'Sahri', + 'Ingraj Bazar', + 'Poloros', + 'Chalil', + 'Collecchio', + 'Ipiranga do Piaui', + 'Hove', + 'Ahmadli', + 'Karahalli', + 'Matosinhos', + 'Navalmoral de la Mata', + 'Bialogard', + 'Radcliff', + 'Padakanti', + 'Malasiqui', + 'Mendicino', + 'Fredericksburg', + 'Javanrud', + 'Tegal', + 'Bailesti', + 'Beeston', + 'Huaixiangcun', + 'Puranpur', + 'Manlio Fabio Altamirano', + 'Roddam', + 'Celakovice', + 'El Espinar', + 'Plattling', + 'Juan de Acosta', + 'Sidi Rahal', + 'Zrnovci', + 'Montepuez', + 'Guruvayur', + 'Kouti', + 'Sipalakottai', + 'Vuzenica', + 'Fontenay-le-Comte', + 'Jianshi', + 'Soignies', + 'Tewksbury', + 'Montelupo Fiorentino', + 'Lacin', + 'Kibaha', + 'Minakami', + 'Bedburg', + 'Cuttack', + 'Had Zraqtane', + 'Mandamari', + 'Sadabad', + 'Azhikkal', + 'Huaiyang', + 'Ovruch', + 'Khetia', + 'Monte Azul Paulista', + 'Amparihitsokatra', + 'Luling', + 'Ayaviri', + 'Pekin', + 'Dhihdhoo', + 'Sylacauga', + 'Venkatagiri', + 'Piro', + 'Rasauli', + 'Verde Village', + 'Ostrow Mazowiecka', + 'Bahon', + 'Teixeira Soares', + 'Qasr al Farafirah', + 'Ambohimalaza', + 'Tabuk', + 'Tubungan', + 'Norseman', + 'Fresno', + 'Lingamparti', + 'Burgau', + 'Coatepec Harinas', + 'Haridwar', + 'Itaugua', + 'Cruz del Eje', + 'Hidalgo', + 'Nellaya', + 'Mandishah', + 'Digboi', + 'Darlington', + 'Solim', + 'Kintampo', + 'Rancho Arriba', + 'San Isidro', + 'Atlapexco', + 'Morada Nova de Minas', + 'Dwarka', + 'Ambatofinandrahana', + 'Tha Chang', + 'Wangguanzhuang Sicun', + 'Chatellerault', + 'Benicasim', + 'Norwell', + 'Moanda', + 'Balsamo', + 'Cesson', + 'Mels', + 'Lokbatan', + 'Karlapalem', + 'Otar', + 'Gainrha', + 'Panajachel', + 'Mulhouse', + 'Rafard', + 'Tabora', + 'Barroquinha', + 'Newport East', + 'Smarjeske Toplice', + 'Mallaram', + 'Qutubpur', + 'El Tortuguero', + 'Obernai', + 'Alella', + 'Susquehanna', + 'Caxambu', + 'Sibulan', + 'Kaleyanpur', + 'Asheville', + 'Albal', + 'Seshambe', + 'Sanga', + 'Furstenau', + 'Nea Artaki', + 'Flores', + 'Hualane', + 'Altun Kawbri', + 'McCandless', + 'Essau', + 'Andoany', + 'Navodari', + 'Cherry Creek', + 'Quitilipi', + 'Ermelo', + 'Arco', + 'Rosario del Tala', + 'Ravensburg', + 'Seveso', + 'Puerto Barrios', + 'Lucon', + 'Tadworth', + 'Banzhuangcun', + 'Sinnar', + 'Ladenburg', + 'Changzhou', + 'Futog', + 'Veenoord', + 'Pardes Hanna Karkur', + 'Palhoca', + 'Schaarbeek', + 'Jarabacoa', + 'Nazca', + 'Zurich', + 'Pacoti', + 'Lemmer', + 'Weizhou', + 'Nagpur', 'Hueyotlipan', - 'Takaharu', - 'Kuchai Kot', - 'Boshof', - 'West Auckland', - 'El Dovio', - 'Mandalapalle', - 'Pachrukhi', - 'Repala', - 'Tionk Essil', - 'Zhujiagua', - 'Liffre', - 'Pedda Penki', - 'Orsova', - 'Biloziria', - 'Nottampatti', - 'Old Forge', - 'Liesti', - 'Carlton Colville', - 'Hausjarvi', - 'Kalloni', - 'Campogalliano', - "Rignano sull'Arno", - 'West Earl', - 'Dobanovci', - 'Staufen im Breisgau', - 'Saint-Vallier', - 'Nalikkalpatti', - 'Chinaur', - 'Munnelli', + 'Araria', + 'Kulat', + 'Horodenka', + 'Irupi', + 'Cinco Saltos', + 'Bhainsdehi', + 'Wamena', + 'West Haverstraw', + 'Ellon', + 'Fasa', + 'Turkan', + 'Tuzi', + 'Conjeeveram', + 'Imperial Beach', + 'Simria', + 'Golden Valley', + 'Tafas', + 'Hohenbrunn', + 'Harsin', + 'Mulundo', + 'Delaware', + "Sant'Angelo Lodigiano", + 'El Reten', + 'Madukkur', + 'Padalarang', + 'Paraiba do Sul', + 'Toboali', + 'Bagcilar', + 'Dejen', + 'Carthage', + 'Yusufeli', + 'Ponduru', + 'Conceicao dos Ouros', + 'Finnkolo', + 'San Francisco Solano', + 'Vetralla', + 'Kheda', + 'Chauddagram', + 'Vinaroz', + 'Galatge', + 'Bradwell', + 'Orlova', + 'Korostyshiv', + 'San Adrian de Besos', + 'Bernburg', + 'Galatone', + 'Paradip Garh', + 'Kukraun', + 'Bruges', + 'Karuzi', + 'Hemet', + 'Vadnagar', + 'Bernardino de Campos', + 'Pansol', + 'Keystone', + 'Satuba', + 'Weinbohla', + 'Morris', + 'Piazzola sul Brenta', + 'Shalingzicun', + 'Falkensee', + 'Uberlandia', + 'Norco', + 'Narala', + 'Widhwidh', + 'Yahualica', + 'Mokrisset', + 'Bandalli', + 'Nizwa', + 'Seal Beach', + 'Shahpur Chaumukhi', + 'Bhangar', + 'Soldado Bartra', + 'Paratdiha', + 'Esme', + 'Goulmima', + 'Waiyuanshan', + 'Fukagawa', + 'Brookdale', + 'Leiktho', + 'West University Place', + 'Kaarst', + 'Sausar', + 'Pivijay', + 'Paraibuna', + 'Saint Bernard', + 'Ponta Grossa', + 'Ushiku', + 'Greenville', + 'Peduasi', + 'Le Loroux-Bottereau', + 'Sturbridge', + '`Ibri', + 'Bururi', + 'Itarana', + 'Santol', + 'Saint-Amand-Montrond', + 'Palod', + 'Erdenet', + 'Bangramanjeshvara', + 'Schongau', + 'Tirumayam', + 'Barigarh', + 'Kinna', + 'Sarmera', + 'Middlesex', + 'Xixucun', + 'Anatoli', + 'Santa Cruz Naranjo', + 'Tocoa', + 'Cabo San Lucas', + 'Ban Dan Na Kham', + 'Martigny', + 'Morganton', + 'Caseros', + 'Ljubuski', + 'Itzer', + 'Januario Cicco', + 'Derzhavinsk', + 'Timoteo', + 'Cloppenburg', + 'Chirilagua', + 'Ordino', + 'Birsinghpur', + 'Nea Michaniona', + 'Sisophon', + 'Setif', + 'Porto San Giorgio', + 'Lakheri', + 'Gobernador Gregores', + 'Mazapil', + 'Arsikere', + 'Leon Postigo', + 'Ambovombe Afovoany', + 'Corbeil-Essonnes', + 'Ouda-yamaguchi', + 'Schloss Holte-Stukenbrock', + 'Ujjain', + 'Komorowice', + 'Pueblo Juarez', + 'Cookeville', + 'Caombo', + 'Heiligenhafen', + 'Lexington', + 'Maassluis', + 'Allschwil', + 'Ogulin', + 'Galveston', + 'Tepalcatepec', + 'Jericoacoara', + 'Gurupa', + 'Combarbala', + 'Poulton le Fylde', + 'Brandon', + 'Famy', + 'Fenggang', + 'Leping', + 'Recica', + 'Founougo', + 'San Diego', + 'Athar', + 'Teresina', + 'Xinbocun', + 'Piduguralla', + 'Buyukorhan', + "'Ain Merane", + 'Bolvadin', + 'Carpenedolo', + 'Onna', + 'Nalegaon', + 'Grandola', + 'Frondenberg', + 'Hagerstown', + 'Lalmunia Munhara', + 'Shelburne', + 'Boulia', + 'Bni Drar', + 'Courbevoic', + 'Cocieri', + 'Lentate sul Seveso', + 'Claveria', + 'Margny-les-Compiegne', + 'Leoben', + 'Pavugada', + 'Werlte', + 'Turori', + 'Puerto Montt', + 'Hauppauge', 'Nalas', - 'Tarichar Kalan', - 'Setana', - 'Saruu', - 'Rakai', - 'Chapaev', - 'Basarabeasca', - 'Namsos', - 'Joniskis', - 'Orocue', - 'Zardab', - 'As Sallum', - 'Gramsh', - 'Bulaevo', - 'Stans', - 'Gadzin Han', - 'Gunnedah', - 'Kaisiadorys', - 'Golubac', - 'Pazin', - 'Cowra', - 'Moengo', - 'Slovenska Bistrica', - 'Rubirizi', - 'Pampa del Infierno', - 'Tweed Heads', - 'Naujoji Akmene', - 'Shar', - 'Kocevje', - 'Kone', - 'Gleno', - 'Putina', - 'Paide', - 'Aguelhok', - 'Hammerfest', - 'Beocin', - 'Qusmuryn', - 'Osakarovka', - 'Varena', - 'Charters Towers', - 'Montpelier', - 'Gzira', - 'Kontcha', - 'Oldeani', - 'Nisporeni', - 'Sokobanja', - 'Ciudad Cortes', - 'Greymouth', - 'Katoomba', - 'Amapa', - 'Sharbaqty', - 'Port Maria', - 'Alebtong', - 'Monaghan', - 'Auki', - 'Dilolo', - 'Sembabule', - "Ch'osan-up", - 'Bentiu', - 'Ertis', - 'Iqaluit', - 'Luba', - 'Kalabo', - 'Grosuplje', - 'Qazaly', - 'Bayghanin', - 'Lascano', - 'Heyin', - 'Ludza', - 'Yeghegnadzor', - 'Yardimli', - 'Mtskheta', - 'Kibale', - 'Jacareacanga', - 'Bairnsdale', - 'San Pablo Villa de Mitla', - 'Castillos', - 'Kemijarvi', - 'Kelme', - 'Sen Monorom', - 'Gaoual', - 'Zhanibek', - 'Backi Petrovac', - 'Leova', - 'Leeton', - 'Coracora', - 'Kirkwall', - 'Goranboy', - 'Adazi', - 'Nangan', - 'Aiquile', - 'Ravne na Koroskem', - 'Luan Chau', - 'Aracinovo', - 'Briceni', - 'Lerik', - 'Thames', - 'Puerto Baquerizo Moreno', - 'Bossembele', - 'Kicevo', - 'Mongomo', - 'Slovenj Gradec', - 'Tranqueras', - 'Telenesti', - 'Bestobe', - 'Obo', - 'Mobaye', - 'Tobyl', - 'Lapovo', - 'Ruyigi', - 'Dowa', - 'Novoberde', - 'Donduseni', - 'Debe', - 'Stefan Voda', - 'Zambezi', - 'Moree', - 'Diekirch', - 'In Guezzam', - 'Wick', - 'Thyolo', - 'Rabaul', - 'Oguz', - 'Kapoeta', - 'Kraslava', + 'Daxiang', + 'Polygyros', + 'Asahni', + 'Dzhankoi', + 'Sanliurfa', + 'Motema', + 'Gadag', + 'Negele', + 'Cuevas del Almanzora', + 'David', + 'Singhanakhon', + 'Siwan', + 'Kalush', + 'Carnaubeira da Penha', + 'Odenton', + 'Caldono', + 'Ampahana', + 'Mozzate', + 'Hemer', + 'Barcaldine', + 'Kanan', + 'Itapecerica da Serra', + 'Toftir', + 'Peterhead', + 'Xishancun', + 'Worgl', + 'Hermanus', + 'Derby', + 'Aranda de Duero', + "Aci Sant'Antonio", + 'Fetesti', + 'Masantol', + 'Vyara', + 'Puerto Berrio', + 'Norton', + 'St. Augustine Shores', + 'East Moline', + 'Shahbazpur', + 'Congonhas', + 'Naples', + 'Coromandel', + 'Aguas Zarcas', + 'Ceu Azul', + 'Sabanagrande', + 'Ranti', + 'Palapye', + 'Jitauna', + 'Brejo', + 'Abrisham', + 'Placilla de Penuelas', + 'Worcester', + 'Graneros', + 'Ras el Oued', + 'Tominian', + 'Kamatgi', + 'Tonakkal', + 'Dranesville', + 'Stepnogorsk', + 'Suchteln', + 'Casorate Primo', + 'Lajedo', + 'Chichihualco', + 'Loos', + 'Chust', + 'Winchester', + 'Tifton', + 'Deblin', + 'Armagh', + 'Mahonda', + 'Cheval', + 'Dzitbalche', + 'New Bern', + 'Le Teich', + 'Lamosina', + 'Oatfield', + 'Autazes', + 'Kikuchi', + 'Bni Gmil', + 'Ligonha', + 'Nepi', + 'Vohilengo', + 'Uruburetama', + 'Bajestan', + 'Al Kharj', + 'Cuito', + 'Vadakku Ariyanayakipuram', + 'Itaqui', + 'Cerro', + 'Acajutla', + 'Adjaouere', + 'Christchurch', + 'Miantso', + 'Damaturu', + 'Teluknaga', + 'Shaoyang', + 'Parappukara', + 'Buyukcekmece', + 'Pontefract', + 'Sangju', + 'Posoltega', + 'Longshan', + 'Scottsbluff', + 'Yate', + 'Rossville', + 'Khed', + 'Lokomby', + 'Pocking', + 'Duverge', + 'Mundamala', + 'Arivonimamo', + 'Bhimphedi', + 'Akiruno', + 'Toufen', + 'Civitanova Marche', + 'Chandlers Ford', + 'Titagarh', + 'Bengkalis', + 'Roth', + 'Lugoj', + "Yong'an", + 'Sandusky', + 'Karuvambram', + 'Chambersburg', + 'Perivale', + 'Dayalpur', + 'Gafour', + 'Zeboudja', + 'Bee Cave', + 'El Amria', + 'Agioi Anargyroi', + 'Biberist', 'Kerikeri', - 'Novi Knezevac', - 'Kieta', - 'Aizkraukle', - 'Bongaree', - 'Nicoadala', - 'Librazhd', - 'Santa Venera', - 'Hola', - 'Livani', - 'Kiruhura', - 'Kiama', - 'Lerwick', - 'Zholymbet', - 'Borgo Maggiore', - 'Obiliq', - 'Brezice', - 'Ajdovscina', - 'Salcininkai', - 'Forbes', - 'Nata', - 'Gulbene', - 'Charagua', - 'Kishkenekol', - 'Magugpo Poblacion', - 'Criuleni', - 'Limbazi', - 'Litija', - 'Madona', - 'Carnarvon', - 'Awjilah', - 'Port Augusta', - 'Mazoe', - 'Ros Comain', - 'Kerema', - 'Northam', - 'Cliza', - 'Mae Hong Son', - 'Bogatic', - 'Oficina Maria Elena', - 'Ingeniero Guillermo N. Juarez', - 'Cooma', - "Port Saint John's", - 'Ndende', - 'Zouar', - 'Deniliquin', - 'Pasvalys', - 'Melut', - 'Comandante Luis Piedra Buena', - 'Siteki', - 'Medveda', - 'Sal Rei', - 'Dalaba', - 'Yeppoon', - 'Lorengau', - 'Derzhavinsk', - 'Omaruru', - 'Vanrhynsdorp', - 'Aluksne', - 'Punakha', - 'Ingeniero Jacobacci', - 'Bir Anzarane', - 'Jakar', - 'Phalombe', - 'Queanbeyan', - 'Tumut', - 'Kavadarci', - 'Palikir', - 'Moss', - 'Ub', - 'Kupiskis', - 'Espargos', - 'Gizo', - 'Veintiocho de Noviembre', - 'Menges', - 'Bac', - 'Junik', - 'Viqueque', - 'Yamba', - 'Kolonia', - 'Alausi', - 'Cabrayil', - 'Dinguiraye', - 'Sezana', - 'Funafuti', - 'Zagorje', + 'Lequile', + 'DeSoto', + 'Waddan', + 'Sopur', + 'Ambattur', + 'Guayama', + 'Pontes e Lacerda', + 'Vellur', + 'Thebes', + 'Cedarburg', + 'Dzialdowo', + 'Mestrino', + 'Valeggio sul Mincio', + 'San Ignacio', + 'Dafni', + 'Burbach', + 'Milton Keynes', + 'Moman Barodiya', + 'Rantau Prapat', + 'Silver Spring', + 'Goldbach', + 'Bottesford', + 'Peruvancha', + 'Bad Ischl', + 'Olivar Bajo', + 'Shitan', + 'Vohilava', + 'Pinukpuk', + 'Dashao', + 'Pocharam', + 'Daireaux', + 'Putaparti', + 'Eysines', + 'Hasanparti', + 'Gumdag', + 'Chicago Ridge', + 'Quissama', + 'Colonia Leopoldina', + 'General Mamerto Natividad', + 'Steamboat Springs', + 'Walpole', + 'Mockern', + 'Sheboygan', + 'Korolevo', + 'Wichita Falls', 'Chepes', - 'Lucea', - 'Maltahohe', - 'Mitoma', - 'Gyangze', - 'Schaan', - 'Glarus', - 'Radovljica', - 'Preili', - 'Luqa', - 'Permet', - 'Zarasai', - 'Trakai', - 'Soldanesti', - 'Echternach', - 'Kaitaia', - 'Rutana', - 'Berovo', - 'Idrija', - 'Sirvintos', - 'Ranillug', - 'Lobamba', - 'Aiyomojok', - 'Moletai', - 'Biloela', - 'Piggs Peak', - 'Appenzell', - 'Uncia', - 'Xocavand', - 'Vaduz', - 'Masunga', - 'Cacheu', - 'Balvi', - 'Nieuw Amsterdam', - 'Chonchi', - 'Stawell', - 'Hermanus', - 'Babak', - 'Sisimiut', - 'Muisne', - 'Vossevangen', - 'Fort-Shevchenko', - 'Mwatate', - 'Polva', - 'Eenhana', - 'Byron Bay', - 'Mamushe', - 'Kazlu Ruda', - 'Namanga', - 'Narrabri', - 'Crnomelj', - 'General Conesa', - 'Petnjica', - 'San Antonio de los Cobres', - 'Mali Idos', - 'Muramvya', - 'Sakiai', - 'Goondiwindi', - 'Ouadda', - 'Wiltz', - 'Thaba-Tseka', - 'Kratovo', - 'Kovacica', - 'Cospicua', - 'Saint-Pierre', - 'Cobram', - 'Medvode', - 'Witu', - 'San Matias', - 'Rapla', - 'Skuodas', - 'Bajram Curri', - 'Hohenau', - 'Napak', - 'Torghay', - 'Triesen', + 'Airmont', + 'El Geneina', + 'Fruitville', + 'Hernani', + 'Casinhas', + 'Neuried', + 'Ain Aicha', + 'Correntes', + 'Loxstedt', + 'Yakoma', + 'Aqtau', + 'Aubenas', + 'Cedar Mill', + 'Drensteinfurt', + 'Bankheri', + 'Comarnic', + 'San Ignacio de Moxo', + 'Kattagan', + 'Podcetrtek', + 'Armenia', 'Albina', - 'Otavi', - 'Thinadhoo', - 'Jogeva', - 'Mayumba', - 'Kalangala', - 'Jinzhong', - 'Canillo', - 'Slovenske Konjice', - 'Danilovgrad', - 'Liquica', - 'Karibib', - 'Smiltene', - 'Rogaska Slatina', - 'Roatan', - 'Kekava', - 'McMinns Lagoon', - 'Scone', - 'Zalec', - 'Puerto Casado', - 'Singleton', - 'Qasr al Farafirah', - 'Ignalina', - 'Grevenmacher', - 'Samtse', - 'Gevgelija', - 'Wonthaggi', - 'Hrastnik', - 'Sembe', - 'Lithgow', - 'Valdez', - 'Sentjur', - 'Bled', - 'Mitzic', - 'Vadso', - 'Mekambo', - 'Xaghra', - 'Vrapciste', - 'Ordino', - 'Irig', - 'Bolama', - 'Albury', - 'Brownsweg', - 'Tuzi', - 'Carrick on Shannon', - 'Ilulissat', - 'Halba', - 'Ghaxaq', - 'Fderik', - 'Coka', - 'Silale', - 'Svolvaer', - 'Komatipoort', - 'Radovis', - 'Klaksvik', - 'Finnsnes', - 'Balzers', - 'Bongandanga', - 'Prevalje', - 'Perito Moreno', - 'Outapi', - 'Valka', - 'Opovo', - 'Otar', - 'Sevnica', - 'Kununurra', - 'Nadur', - 'Fuerte Olimpo', - 'Gobernador Gregores', - 'Bueng Kan', - 'Pakruojis', - 'Svencionys', - 'Bururi', - 'Al Qasr', - 'Eschen', - 'Victorica', - 'Qivraq', - 'Mauren', - 'Marsa', - 'Karasburg', - 'Samaipata', - 'Saryshaghan', - 'Tepelene', - 'Ingham', - 'Ilirska Bistrica', - "Saint George's", - 'Dehiba', - 'Nwoya', - 'Bekily', - 'Comandante Fontana', - 'Narrogin', - 'Black River', - 'Kuala Belait', - 'Victor Harbor', - 'I-n-Amguel', - 'Manjimup', - 'Calheta de Sao Miguel', - 'Krusevo', - 'Naifaru', - 'Bensonville', - 'Berri', - 'Port Hedland', - 'Las Lajas', - 'Wabag', - 'Corovode', - 'Kalvarija', - 'Pieta', - 'Cerknica', - 'Remich', - 'El Maiten', - 'Avarua', - 'Manica', - 'Aliwal North', - 'Balzan', - 'Robertsport', - 'Karmah an Nuzul', - 'Trebnje', - 'Trzin', - 'Oranjemund', - 'Bethanie', - 'Bir Mogrein', - 'Lazdijai', - 'Butalangu', - 'Neiafu', - "P'ungsan", - 'Plandiste', - 'Sicasica', - 'Vergara', - 'Miklavz na Dravskem Polju', - 'Decan', - 'Omuthiya', - 'Piran', - 'Agdam', - 'Teseney', - 'Erseke', + 'Ferraz de Vasconcelos', + 'Kibawe', + 'Navegantes', + 'Panna', + 'Sebt Ait Saghiouchen', + 'Nuevo Arraijan', + 'Milicz', + 'Alleppey', + 'Mondlo', + 'Tallmadge', + 'Birni', + 'Langrucun', + 'Maria Enzersdorf', + 'Birdaban', + 'Kalingalan Caluang', + 'Ormond Beach', + 'Pontedera', + 'Jilava', + 'Guduru', + 'Ashikita', + 'Port Antonio', + 'Termini Imerese', + 'Stranraer', + 'Muheza', + 'Sonapur', + 'Rothenburg ob der Tauber', + 'De Doorns', + 'Libreville', + 'Vargaur', + 'Madona', + 'Kirlampudi', + 'Usworth', + 'Ichchapuram', + 'Groairas', + 'Raipura', + 'Thanesar', + 'Gracanica', + 'Bukkarayasamudram', + 'Brunico', + 'Spremberg', + 'Sidi El Hattab', + 'Imeni Chapayeva', + 'Tandwa', + 'Ap Khanh Hung', + 'Bagulin', + 'Ziyodin Shaharchasi', + 'Catanzaro', + 'Kavak', + 'Nalchiti', + 'Pannaikkadu', + 'Vysoke Myto', + 'Punnappatti', + 'Kanchika', + 'Sibut', + 'Marblehead', + 'Mayenne', + 'Concepcion Huista', + 'Birch Bay', + 'Mulakaluru', + 'Lynchburg', + 'Titay', + 'Trou du Nord', + 'Murraysville', + 'Kalladai', + 'Ipoh', + 'Santa Maria Chilchotla', + 'Wervik', + 'Casa de Oro-Mount Helix', + 'Jamnagar', + 'Caotan', + 'Dewsbury', + 'La Pintana', + 'Betong', + 'Jhundo', + 'Saint-Gregoire', + 'Channarayapatna', + 'Lennestadt', + 'Bir Kasdali', + 'Kissidougou', + 'Palghat', + 'Winterberg', + 'San Jose Tenango', + 'Mays Chapel', + 'Barreiro', + 'Latakia', + 'Loudeac', + 'Periyapodu', + 'Bad Schussenried', + 'Himeji', 'Ulaan-Uul', - 'Grand Turk', - 'Lavumisa', - 'Sempeter pri Gorici', - 'Massenya', - 'Trzic', - 'Ziri', - 'Makedonski Brod', - 'Katanning', - 'Imgarr', - 'Cankuzo', - 'Tessalit', - 'Ribnica', - 'Dingli', - 'Puke', - 'Sao Joao dos Angolares', - 'Mojkovac', - 'Janjanbureh', - 'Lismore', - 'Villa Ygatimi', - 'Domagnano', - 'Merimbula', - 'Marsaxlokk', - 'Kirkenes', - 'Tolmin', - 'Ceduna', - 'Port Douglas', - 'Mongar', - 'Ligonha', - 'Kirakira', - 'La Paloma', - 'Wallaroo', - 'Proserpine', - 'Uspallata', - 'Alibunar', - 'Cantemir', - 'Darregueira', - 'Kaberamaido', - 'Malisheve', - 'Trancas', - 'Lukulu', - 'Fish Town', - 'Clare', - 'Turangi', - 'Imqabba', - 'Xewkija', - 'Weipa', - 'Lasko', - 'Pofadder', - 'Lenart v Slovenskih Goricah', - 'Smithton', - 'Demir Kapija', - 'The Valley', - 'Rietavas', - 'Ljutomer', - 'Jurado', - 'Domzale', - 'Metlika', - 'Rorvik', - 'Ankaran', - 'Brezovica', - 'Ghajnsielem', - 'Sinnamary', - 'Mezica', - 'Evinayong', - 'Brandfort', - 'Ocnita', - 'Kudahuvadhoo', - 'Saulkrasti', - 'Iklin', - 'Sencur', - 'Golubovci', - 'Birstonas', - 'Dravograd', - 'Gornja Radgona', - 'Ainaro', - 'Lija', - 'Zelezniki', - 'Aasiaat', - 'Mopipi', - 'Porto Ingles', - 'Arroyos y Esteros', - 'Qaqortoq', - 'Tearce', - 'Trashigang', - 'Ulbroka', - 'Skofljica', - 'Abai', - 'Taoudenni', - 'Kardla', - 'Kalkara', - 'Tifariti', - 'Mahibadhoo', - 'Lethem', - 'Gudja', - 'Al Jaghbub', - 'Lendava', - 'Bogdanci', - 'Rogasovci', - 'Sostanj', - 'Zrece', - 'Sowa Town', - 'Bopolu', - 'Zitiste', - 'Hokitika', - 'Nautla', - 'Tom Price', - 'Radlje ob Dravi', - 'Bordertown', - 'Villalonga', - 'Viligili', - 'Mangbwalu', - 'Buala', - 'Rio Mayo', - 'Senglea', - 'Gharghur', - 'Qrendi', - 'Kerewan', - 'Hlatikulu', - 'Longreach', - 'Trashi Yangtse', - 'Barclayville', - 'Kolasin', + 'Qormi', + 'Wamba', + 'Bovolone', + 'Limavady', + 'Kara-Bak', + 'Wilrijk', + 'Bissegem', + 'Richmond', + 'Quzhou', + 'Chamarru', + 'Arhavi', + 'Tartus', + 'Mboki', + 'Gramsh', + 'Jizhuang', + 'Capitola', + 'Ashby de la Zouch', + 'Saga', + 'Mage', + 'Manvi', + 'Baud', + 'Hincesti', + 'Santiago Sacatepequez', + 'Astley', + 'Moramanga', + 'Le Mars', + 'Mahinathpur', + 'Fort Mohave', + 'Turda', + 'Kadiolo', + 'Kannan', + 'Grossenkneten', + 'Tsiately', + 'Zhipingxiang', + 'Al `Amarah', + 'Florestopolis', + 'Mazara del Vallo', + 'Antonivka', + 'Laconia', + 'Bouka', + 'Vemulanarva', + 'Budakalasz', + 'Kelkheim (Taunus)', + 'Ventania', + 'Castanos', + 'Ganzhou', + 'Lauingen', + 'Borbon', + 'Lodwar', + 'Ober-Ramstadt', + 'Qardho', + 'Kathevaram', + 'Colorado', + 'Sierra Vista', + 'Walnut Creek', + 'Tainan', + 'Guaraciaba', + 'Beni Hassane', + 'Tabuse', + 'Isfisor', + 'Long Beach', + 'Mahraurh', + 'Langerwehe', + 'An', + 'Nueve de Julio', + 'Kastamonu', + 'Harmanli', + 'Welver', + 'Binisalem', + "Imi n'Oulaoun", + 'Lizzanello', + 'Itapema', + 'Colon', + 'Andolofotsy', + 'Ilafy', + 'Chivasso', + 'Al Ghayzah', + 'Weno', + 'Hostotipaquillo', + 'Talugai', + 'Tomohon', + 'Saint-Remy-de-Provence', + 'Takikawa', + 'Ramgundam', + 'Shamaldy-Say', + 'Buram', + 'Curtea de Arges', + 'Labo', + 'Chahatpur', + 'Upington', + 'Andorinha', + 'Saymayl', + 'Nkheila', + 'Lindi', + 'Rio Tercero', + 'Grevena', + 'Peschiera del Garda', + 'Las Terrenas', + 'Holzwickede', + 'Mallet', + 'Ambara', + 'San Gregorio di Catania', + 'Chiramba', + 'Marudi', + 'Donji Kakanj', + 'Strand', + 'Azzano Decimo', + 'San Remo', + 'Brasschaat', + 'Barokhar', + 'Torghay', + 'Soledad', + 'Alfredo Chaves', + 'Dongsheng', + 'Enumclaw', + 'Bouafle', + 'Navotas', + 'Ambohitoaka', + 'Marotandrano', + 'Sao Miguel do Tapuio', + 'Wevelgem', + 'Pio XII', + 'Vigodarzere', + 'Gargzdai', + 'Rennes', + 'Lucala', + 'Piney Green', + 'Stokke', + 'Al `Ayyat', + 'Agoura Hills', + 'Akabira', + 'Cabiao', + 'Sevilla de Niefang', + 'Coconuco', + 'Yaxley', + 'Morondava', + 'Francistown', + 'Shush', + 'Papillion', + 'Morawa', + 'Halstead', + 'Lower Pottsgrove', + 'Rende', + 'Opelika', + 'Tanakpur', + 'Bolsward', + 'Majene', + 'Tullinge', + 'Ifield', + 'Calumpit', + 'Brajarajnagar', + 'Laon', + 'Tamagawa', + 'Avcilar', + 'Manikpur', + 'Portet-sur-Garonne', + 'East Chicago', + 'Reddiyapatti', + 'Bananal', + 'Somero', + 'Sabara', + 'Ragay', + 'Cupertino', + 'Kuala Pembuang', + 'Andranomamy', + 'Kavar', + 'Gommern', + 'Oxelosund', + 'Cheraro', + 'Repala', + 'Sannar', + 'Blaj', + 'Clemmons', + 'Kakarati', + 'Valenciennes', + 'Batad', + 'Kyeintali', + 'Mengjiacun', + 'Agdz', + 'Ula', + 'Parede', + 'Buguias', + 'Palleja', 'Urubamba', - 'Trongsa', - 'Race', - 'Borovnica', - 'Eydhafushi', - 'Triesenberg', - 'Vittoriosa', - 'Isafjordhur', - 'Donegal', - 'Saudharkrokur', - 'Tofol', - 'Cestos City', - 'Imtarfa', - 'Mkokotoni', - 'Chumbicha', - 'Kllokot', - 'Rosoman', - 'Charleville', - 'Fiorentino', - 'Baltasar Brum', - 'Cloncurry', - 'Nauta', - 'Mariscal Jose Felix Estigarribia', - 'Capitol Hill', - 'Brokopondo', - 'Vojnik', - 'Aigua', - 'Tarabuco', - 'Quime', - 'Demir Hisar', - 'Beltinci', - 'Al `Alamayn', - 'Hofn', - 'Jaque', - 'Nida', - 'Merredin', - 'Karungu', - 'Vevcani', - 'Polzela', - 'Bloemhof', - 'Sohano', - 'Zhemgang', - 'Boffa', - 'Egilsstadhir', - 'Coroico', - 'Krsko', - 'Gustavia', - 'Ypejhu', + 'Bobbili', + 'Damalcheruvu', + 'Wantagh', + 'Wailuku', + 'La Piedad', + 'Texarkana', + 'Isangel', + 'Rosario', + 'Tublay', + 'Zapote', + 'Albox', + 'Kandulapuram', + 'Vrindavan', + 'Amudalapalle', + 'Cabo Rojo', + 'Sternberk', + 'Telde', + 'Kreuzlingen', + 'Dudu', + 'Vouzela', + 'Hullatti', + 'Yellandu', + 'Suzaka', + 'Ouled Abbes', + 'Ankilizato', + 'Pocklington', + 'Lescar', + 'Belgrave', + 'Az Zabadani', + 'Battambang', + 'Lehigh Acres', + 'Magurele', + 'Kato', + 'Bailin', + 'Kobarid', + 'Aketi', + 'Pokrovske', + 'Pecica', + 'Coringa', + 'Dosemealti', + 'Oued Amlil', + 'Gaotan', + 'Warburg', + 'Virgem da Lapa', + 'Amdjarass', + 'Duijiang', + 'Bagado', + 'Pujali', + 'Nan', + 'Ibrahimpatan', + 'Tornio', + 'Mount Vista', + 'Sanso', + 'Nam Dinh', + 'Martinsburg', + 'Eshkanan', + 'Maringa', + 'Alamosa', + 'Suzzara', + 'Portachuelo', + 'Vempalle', + 'San Antonio La Paz', + 'Stafa', + 'Basey', + 'Sabaudia', + 'Veliki Preslav', + 'West Manchester', + 'Weissenburg', + 'Le Havre', + 'Togamalai', + 'Omitama', + 'Bihariganj', + 'Redange-sur-Attert', + 'Saint-Chamond', + 'Anklam', + 'Perwez', + 'Qivraq', + 'Chieti', + 'Gossau', + 'Tutzing', + 'Bacaadweyn', + 'Kohat', + 'Durbuy', + 'Clarence', + 'Olesno', + 'Uberaba', + 'Andorra la Vella', + 'Ranong', + 'Meshgin Shahr', + 'Senigallia', + 'Siahkal', + 'Apatin', + 'West Park', + 'Fallsburg', + 'Bom Lugar', + 'Chassieu', + 'Chauki Hasan Chauki Makhdum', + 'Hejamadi', + 'Santa Maria do Para', + 'Al Jumayliyah', + 'Harij', + 'Reedley', + 'Wafangdian', + 'Suzak', + 'Hirekerur', + 'Muar', + 'Xarardheere', + 'Tando Muhammad Khan', + 'Uchturpan', + 'Kalba', + 'Clearlake', + 'Aulendorf', + 'Parur', + 'Joanopolis', + 'Belagola', + 'Chapeltown', + 'Shildon', + 'Uruoca', + 'Gevelsberg', + 'Hindoria', + 'Przasnysz', + 'Vigasio', + 'Alamedin', + 'Namrup', + 'Luenoufla', + 'Teofilo Otoni', + 'Gopalapuram', + 'Shahhat', + 'Mesagne', + 'Maisaka', + 'San Pedro Nonualco', + 'Panevezys', + 'Quibor', + 'Frutal', + 'Casa Branca', + 'Furukawamen', + 'Presidente Vargas', + 'Vadugappatti', + 'Nefta', + 'Maipu', + 'Opa-locka', + 'Maidstone', + 'Santo Tomas La Union', + 'Wheeling', + 'Kamakhyanagar', + 'Rozzano', + 'Boljoon', + 'Aconibe', + 'Huzhou', + 'Kongolo', + 'Tacloban', + 'Escalante', + 'Wadowice', + 'Machala', + 'Lagonoy', + 'Carnaubais', + 'Lubuk Sikaping', + 'Yupiltepeque', + 'Gwoza', + 'Padilla', + 'Dhari', + 'Refahiye', + 'Sevierville', + 'Fellbach', + 'Raub', + 'Plaine du Nord', + 'Tepexi de Rodriguez', + 'Garango', + 'Nakapiripirit', + 'Grosse Pointe Park', + 'Aerzen', + 'Lingcheng', + 'Mogliano Veneto', + 'Wiesloch', + 'Tokatippa', + 'Bezou', + 'Bela', + 'Wahlstedt', + 'Huichang', + 'Raghudebbati', + 'El Sobrante', + 'Badarpur', + 'Nakskov', + 'Kurwar', + 'Siquinala', + 'Berga', + 'Jamalpur', + 'Sidi Taibi', + 'Crema', + 'Tharad', + 'Colomba', + 'Marostica', + 'Temiskaming Shores', + 'Karwar', + 'Pallavaram', + 'Dokolo', + 'Nawai', + 'Cullman', + 'Waldkraiburg', + 'Yoichi', + 'Nizip', + 'Litomysl', + 'Huong Canh', + 'Appenweier', + 'Gimbi', + 'Hulst', + 'Beshkent Shahri', + 'Ban Wat Lak Hok', + 'San Martin De Porres', + 'Chuy', + 'Fallon', + 'Domerat', 'Ruggell', - 'Tolten', - 'Muta', - 'Sveta Ana', - 'Qala', - 'Lehututu', - 'Sahbuz', - 'Store', - 'Te Anau', - 'Ig', - 'Maradah', - 'Roura', - 'Onverwacht', - 'Gradsko', - 'Desaguadero', - 'Sorata', - 'Mwenga', - 'El Manteco', - 'Kaikoura', - 'Floriana', - 'Ivancna Gorica', - 'Jose Batlle y Ordonez', - 'Crna na Koroskem', - 'Puerto Villamil', - 'Kirkop', - 'Lacin', - 'Radenci', - 'Vianden', - 'Totness', - 'Cidade Velha', - 'Acquaviva', - 'Pozo Colorado', - 'Baures', - 'Apolo', - 'Sannat', - 'Spodnje Hoce', - 'Funadhoo', - 'Vipava', - 'Esperance', - 'Pivka', - 'Omboue', - 'Mozirje', - 'Manadhoo', - 'Pukekohe East', - 'Waitakere', - 'Waitangi', - 'Semic', - 'Ambrolauri', - 'Damongo', - 'Konza', - 'Altata', - 'Heydarabad', - 'Djibloho', - 'Sofifi', - 'Afega', - 'Radece', - 'Valandovo', - 'Lovrenc na Pohorju', - 'Capellen', - 'Tasiilaq', - 'Ormoz', - 'Borgarnes', - 'Katwe', - 'Straza', - 'Kercem', - 'Zabljak', - 'Abuna', - 'Amudat', - 'Philipsburg', - 'Taedong', - 'Krivogastani', - 'Mislinja', - 'Balakan', - "Ta' Xbiex", - 'Naklo', - 'Bohinjska Bistrica', - 'Nokaneng', - 'Smarje', - 'Longyearbyen', - 'Nasir', - 'Partesh', - 'Divaca', - 'Xghajra', - 'Cerklje na Gorenjskem', - 'Varaklani', - 'Spodnji Duplek', - 'Pehcevo', - 'Ropazi', - 'Gusinje', - 'Gamprin', - 'Parun', - 'Puerto Williams', - 'Cuevo', - 'Capitan Pablo Lagerenza', - 'Odranci', - 'Lifford', - 'Prebold', - 'Flying Fish Cove', - 'Zgornja Kungota', - 'Xizi', - 'Bovec', - 'Plasnica', - 'Chiradzulu', - 'Alto Rio Senguer', - 'Sierra Colorada', - 'Rogatec', - 'Gharb', - 'Iracoubo', - 'Bourke', - 'Zrnovci', - 'Kipili', - 'Ungoofaaru', - 'Vuzenica', - 'Tumby Bay', - 'Turnisce', - 'Miren', - 'Chibemba', - 'Alexander Bay', - 'Halls Creek', - 'Tajarhi', - 'Nova Crnja', - 'Lokwabe', - 'Clervaux', - 'Dragomer', - 'Munxar', + 'Subang', + 'Kapalong', + 'Shahrak-e Enqelab', + 'Finneytown', + 'Casamassima', + 'Forks', + 'Silvassa', + 'Pharr', + 'Ait Bouziyane', + 'Sirari', + 'Saint-Etienne', + 'Halol', + 'Aregua', + 'Calatagan', + 'Palmas', + 'Milajerd', + 'Ar Riqqah', + 'Waghausel', + 'Tlaxcala', + 'Pellezzano', + 'Segovia', + 'Villeneuve-les-Maguelone', + 'Narrogin', + 'Vila Pouca de Aguiar', + 'Madagh', + 'Tanambe', + 'Rheinau', + 'Tsubame', + 'Kozluk', + 'El Ghaziye', + 'Ciudad Insurgentes', + 'Zuchwil', + 'Shangzhou', + 'Morton', + 'Ieper', + 'Hefei', + 'Qiryat Ono', + 'West Vero Corridor', + 'Rumonge', + 'Suohe', + 'Juprelle', + 'Airmadidi', + 'Pecel', + 'Pa Sang', + 'Phra Nakhon Si Ayutthaya', + 'Castrolibero', + 'Koprivnica', + 'Formiga', + 'Petatlan', + 'Xuanzhou', + 'Navirai', + 'Weilburg', + 'Belgaum', + 'Sovetskoe', + 'Mwaline al Oued', + 'Fort-de-France', + 'Belkheir', + 'Sarapiqui', + 'Manandona', + 'Ernagudem', + 'Dunaivtsi', + 'Perama', + 'Eastmont', + 'Zeerust', + 'Sao Miguel', + 'La Crescenta-Montrose', + 'Kardzhali', + 'Faisalabad', + 'Asan', + 'Trenton', + 'Kuttyattur', + 'Ban Thap Kwang', + 'Sahtah', + 'Tila', + 'Ait Tamlil', + 'Tomball', + 'Pathiyanikunnu', + 'Markdorf', + 'Kitakami', + 'Zacatecoluca', + 'Thouars', + 'Belem', + 'Albuquerque', + 'Veenendaal', + 'Namutumba', + 'Chalette-sur-Loing', + 'Shilan', + 'Consolacion', + 'Brahmanpara', + 'Pola de Lena', + 'Gislaved', + 'Arlesheim', + 'Inuma', + 'Royton', + 'Sawadah', + 'La Magdalena Tlaltelulco', + 'Wenlan', + 'Portoviejo', + 'Jaguarao', + 'Atlit', + 'Yellareddi', + 'Chima', + 'Ribnica', + 'Loves Park', + 'Vera Cruz', + 'Sape', + 'Alauli', + 'Antargangi', + 'DeForest', + 'Lethbridge', + 'Fuerte Olimpo', + 'Kiskunlachaza', + 'Mahagama', + 'Ulubey', + 'Cacimba de Dentro', + 'Thames', + 'Junqueiropolis', + 'Ganeshpur', + 'Avrille', + 'Guediawaye', + 'Flores de Goias', + 'Nevele', + 'Osisioma', + 'Valtoha', + 'Alfonso Castaneda', + 'Embu-Guacu', + 'Ballia', + 'Elmont', + 'Adampur', + 'Montalto Uffugo', + 'Locate di Triulzi', + 'Jinju', + 'Xenia', + 'Douar Jwalla', + 'Zanzibar', + 'Ansbach', + 'Cafarnaum', + 'Riacho de Santana', + 'Magburaka', + 'Hampton', + 'Kumo', + 'Adana', + 'Salisbury', + 'Begoro', + 'Rehlingen-Siersburg', + 'Tambulig', + 'Howli', + 'Port Hueneme', + 'Saire', + 'Lishanpu', + 'Mykhailivka', + 'Xiazhai', + 'Sochaczew', + 'Minbya', + 'Vienne', + 'Shegaon', + 'Hajnowka', + 'Alberobello', + 'Karatas', + 'Nyamti', + 'Tatarikan', + 'Puqiancun', + 'Andrews', + 'Kraluv Dvur', + 'Calnali', + 'Anna Regina', + 'Voss', + 'Rietberg', + 'Baracoa', + 'Caglayancerit', + 'Larkhall', + 'Fairwood', + 'Sardoba', + 'Beni Fouda', + 'Lakshminarayanapuram', + 'Kandy', + 'Pigcawayan', + 'Yuchengcun', + 'Barru', + 'Wulflingen', + 'Koktokay', + 'Santa Rosa de Cabal', + 'Ramona', + 'Rucphen', + 'Jinghai', + 'Twist', + 'Alberdi', + 'Izola', + 'Bom Jardim', + 'Benito Juarez', + 'Grinon', + 'Mundgod', + 'Manito', + 'Ban Tha Luang Lang', + 'Colesberg', + 'Hinche', + 'Sidmant al Jabal', + 'Vilnius', + 'Mount Laurel', + 'Dyero', + 'Madari Hat', + 'Patian', + 'Guimbal', + 'Linnei', + 'Astaneh-ye Ashrafiyeh', + 'Delfzijl', + 'Walla Walla', + 'Saint-Louis du Sud', + 'Shilou', + 'Puchov', + 'Trossingen', + 'Spring Valley', + 'May Pen', + 'Hadleigh', + 'Hoffman Estates', + 'Hirschaid', + 'Dorridge', + 'Ampohibe', + 'Amapa', + 'Temirtau', + 'Lakhsetipet', + 'Raeren', + 'Liffre', + 'Hassi Fedoul', + 'West Grey', + 'Jaggayyapeta', + 'Akita', + 'Burien', 'Kranjska Gora', - 'Sentjernej', - 'Cerkno', - 'Oplotnica', - 'Machinga', - 'Port Denison', - 'Tsau', - 'Uummannaq', - 'Xocali', - 'Smartno', - 'Penola', - 'Mirna', - 'Selnica ob Dravi', - 'Kingston South East', - 'Nyimba', - 'Veymandoo', - 'Lubutu', - 'Wagin', - 'Fulacunda', - 'Paamiut', - 'Bala Cangamba', - 'Tarutung', - 'Novaci', - 'Bosilovo', + 'Urla', + 'Apapa', + 'Tucano', + 'Stouffville', + 'Bayt Ummar', + 'Chamrajnagar', + 'Cagwait', + 'Sorada', + 'Saoula', + 'Cavan Monaghan', + 'Somotillo', + 'Kabarnet', + 'Ash Shatrah', + 'Forest Hill', + 'Colleyville', + 'Nzega', + 'Kaufering', + 'Bikou', + 'Ksar Sbahi', + 'Muramvya', + 'Impfondo', + 'Dalachi', + 'Janze', + 'Baruun-Urt', + 'Scornicesti', + 'Caem', + 'Darayya', + 'Foya Tangia', + 'Robertsville', + 'Ban Ho Mae Salong', + "Bi'r al `Abd", + 'Giyani', + 'Dhamar', + 'Bni Frassen', + 'Brownhills', + 'Buckie', + 'Majagua', + 'Gainsborough', + 'Ayotoxco de Guerrero', + 'East Milton', + 'Sanchi', + 'Pogradec', + 'Yurimaguas', + 'Xingyi', + 'Tripunittura', + 'Lady Lake', 'Safotu', - 'Kalbarri', - 'Villa Rumipal', - 'Dornava', - 'Mogila', - 'Kidricevo', - 'Katherine', - 'Mabaruma', - 'Tulagi', - 'Novo Selo', - 'Barcaldine', - 'Villa Martin Colchak', - 'Ubombo', - 'Regedor Quissico', - 'Celeken', - 'Isangel', - 'Buluko', - 'Leulumoega', - 'Faetano', - 'Horjul', - 'Crensovci', - 'Daga', - 'Los Blancos', - 'Kanal', - 'Asau', - 'Gorenja Vas', - 'Puerto Acosta', - 'Mirbat', - 'Nacunday', - 'Poljcane', - 'Uad Damran', - 'Pluzine', - 'Ljubno', - 'Susques', - 'Upernavik', - 'Schellenberg', - 'Innisfail', - 'Kobarid', - 'Qasigiannguit', - 'Benedikt', - 'Mazatan', - 'Hagta', - 'Fulin', - 'Andrijevica', - 'Mata-Utu', - 'Ouyen', - 'Gornji Grad', - 'Mirna Pec', - 'Hughenden', - 'Haya', - 'Cowell', + 'Gabu', + 'Pitt Meadows', + 'Sahalanona', + 'Vilaseca de Solcina', + 'Shinjuku', + 'Phnom Penh', + 'Espumoso', + 'Tiantoujiao', + 'Haukipudas', + 'Cuilapan de Guerrero', + 'Bafoussam', + 'Sunjiayan', + 'Bhanpura', + 'Sarangapuram', + 'Frontera', + 'Roh', + 'Prince Albert', + 'San Bernardino', + 'Maranello', + 'Ales', + 'Shenley Brook End', + 'Morayra', + 'Maba', + 'Pelileo', + 'Majiadiancun', + 'Broadstone', + 'Eski-Nookat', + 'Axapusco', + 'Najasa', + 'Iuiu', + 'Morieres-les-Avignon', + 'Capilla del Senor', + 'Amarante', + 'Bretigny-sur-Orge', + 'Jhaua', + 'Deulgaon Mahi', + 'Waterbury', + 'Euriapolis', + 'Thika', + 'Rothrist', + 'Tinja', + 'Umarizal', + 'Vihari', + 'Tepatlaxco', + 'Tan Son', + 'Anjangoveratra', 'Yelimane', - 'Sredisce ob Dravi', - 'General Eugenio A. Garay', - 'Montegiardino', - 'Streaky Bay', - 'Moravce', - 'Principe da Beira', - 'Lufilufi', - 'Dobrovnik', - 'Daraj', - 'Dobrova', - 'Konce', - 'Shamva', - 'Laverton', - 'Verzej', - 'Komenda', - 'Dolenjske Toplice', - 'Nazarje', - 'Rostusa', - 'Hoskins', - 'Velika Polana', + 'Poulsbo', + 'Hutchinson', + 'Ittikelakunta', + 'Villena', + 'Mositai', + 'Roi Et', + 'Tulsipur', + 'Munhall', + 'Staufen im Breisgau', + 'Ciudad Hidalgo', + 'Naama', + 'Vratsa', + 'Sales Oliveira', + 'Xingtai', + 'Monteriggioni', + 'Grey Highlands', + 'Camoluk', + 'Ochsenhausen', + 'Winnenden', + 'Bogen', + 'Ambinanisakana', + 'Rolla', + 'New Philadelphia', + 'Varzelandia', + 'Can Tho', + 'Tepetlixpa', + 'Gursarai', + 'Grumo Appula', + 'Rudraprayag', + 'Kelheim', + 'Pionki', + 'Kedavur', + 'Frankfort', + 'Bishamagiri', + 'Shingbwiyang', + 'Montes Altos', + 'Longtangwan', + 'Veszprem', + 'Vadnais Heights', + 'Pozarevac', + 'Zyrardow', + 'Nis', + 'Julianadorp', + 'Beigang', + 'Wuhuang', + 'Ambalakindresy', + 'Yeosu', + 'Hisar', + 'Chithara', + 'Caldwell', + 'San Remigio', + 'Budamangalam', + 'Tamani', + 'Shetpe', + 'Velyki Luchky', + 'Jaramijo', + 'East Finchley', + 'Siedlce', + 'Tadigadapa', + 'Umuahia', + 'Jalgaon', + 'Schneeberg', + 'Chilonga', + 'Zhdanivka', + 'Bananeiras', + 'Nasaud', + 'Karlsdorf-Neuthard', + 'Culemborg', + 'Luanco', + 'Analamary', + 'Hinabangan', + 'Borgomanero', + 'Don Sak', + 'Newark', + 'Salqin', + 'Tafersit', + 'Siyang', + 'Goussainville', + 'Cermenate', + 'Gurlapeta', + 'Kiri', + 'Luis Gomes', + 'Partizanske', + 'Puducherry', + 'Strzegom', + 'Sai Mai', + 'Petlawad', + 'Vicenza', + 'Debbache el Hadj Douadi', + 'Amarpura', + 'Val-des-Monts', + 'Haicheng', + 'Kempton Park', + 'Raspur Patasia', + 'Killimangalam', + 'Thanatpin', + 'Oji', + 'Neno', + 'Kato Polemidia', + 'Anapurus', + 'Shakiso', + 'Diepholz', + 'Altrincham', + 'Nowa Ruda', + 'Sirnak', + 'Pettaivayttalai', + 'Schmelz', + 'Velur', + 'Wolverton', + 'Goygol', + 'Groesbeek', + 'Kannavam', + 'Bujumbura', + 'Ihorombe', + 'Hasami', + 'Revur', + 'Nosiarina', + 'Ciudad Guayana', + 'Economy', + 'Rayachoti', + 'Naciria', + 'Rompicherla', + 'Fairbanks', + 'Timbio', + 'Santo Amaro', + 'Vares', + 'Mafeteng', + "G'oliblar Qishlog'i", + 'Kumul', + 'Kline', + 'Alampur', + 'Moda', + 'Lhasa', + 'Sirhali Kalan', + 'Lower Providence', + 'Fuengirola', + 'Naigarhi', + 'Cottonwood Heights', + 'Aldeias Altas', + 'Sibinal', + 'Sulaco', + 'Pintuyan', + 'Sombrio', + 'Negrete', + 'Tsau', + 'Casa Nova', + 'Garupa', + 'Pencheng', + 'Langnau', + 'Gokinepalle', + 'General Conesa', + 'Bandamurlanka', + 'Morarano-Gara', + 'Tartu', + 'Hombrechtikon', + 'Wegberg', + 'Argelia', + 'Neubrandenburg', + 'Bardmoor', + 'Benipati', + 'Saint-Laurent-de-la-Salanque', + 'Sungai Penuh', + 'Iklod', + 'Alem Paraiba', + 'Uitgeest', + 'Kiranur', + 'Tinambac', + 'Ait Yaich', + 'Teniet el Abed', + 'Middlesex Centre', + 'Grand-Bassam', + 'Redhill', + 'Zhaotong', + 'Mohammad Shahr', + 'Cranendonck', + 'Vanzago', + 'Wiener Neustadt', + 'Telavi', + 'Fonte Boa', + 'Svalyava', + 'Valea Lupului', + 'Kitale', + 'Campos Gerais', + 'Dayr as Sanquriyah', + 'Atmakur', + 'Boynton Beach', + 'Can', + 'Kalongo', + 'Bad Voslau', + 'Trutnov', + 'Sunagawa', + 'Bandarbeyla', + 'San Pedro Ixtlahuaca', + 'Lonquimay', + 'Kangal', + 'Bornem', 'Luanza', - 'Meningie', - 'Vitanje', - 'Gorisnica', - 'Yulara', - 'Gingin', - 'Jegunovce', - 'Ozurgeti', - 'Pesnica', - 'Sodrazica', - 'Godhavn', - 'Stari Trg', - 'Preddvor', - 'Vatican City', - 'Charana', - 'Onslow', - 'Zgornja Hajdina', - 'Bicheno', - 'Vailoa', - 'Starse', - 'Muhembo', - 'Sveta Trojica v Slovenskih Goricah', - 'Moravske-Toplice', - 'San Lawrenz', - 'Yaren', - 'Rankovce', - 'Comallo', - 'Velike Lasce', - 'Hvalba', - 'Satadougou', - 'Lakatoro', - 'Mokronog', - 'Roebourne', - 'Zhaltyr', - 'Sopiste', - 'Kostanjevica na Krki', - 'Pannawonica', - 'Linxi', - 'Ituni', - 'Meekatharra', - 'Oblesevo', - 'Qubadli', - 'Leonora', - 'Massangena', - 'Gawler', - 'Qaanaaq', - 'Komen', - 'Kozje', - 'Puconci', - 'Vasilevo', - 'Grad', - 'Nkurenkuru', - 'Tigoa', - "Villa O'Higgins", - 'Kimba', - 'Majsperk', - 'Dibaya', - 'Panda', - 'Gastre', - 'Saleaula', - 'Kalbacar', - 'Alofi', - 'Quilpie', - 'Videm', - 'Podcetrtek', - 'Karbinci', - 'Sabaya', - 'Oatlands', - 'Zgornje Jezersko', - 'Chiramba', - 'Norseman', - 'Lata', - 'Llica', - 'Mereeg', - 'Telsen', - 'Apace', - 'Kobilje', - 'Wilcannia', - 'Dobrna', - 'Zgornje Gorje', - 'Calenga', - 'Southern Cross', - 'Lozovo', - 'Recica', - 'Caluula', - 'Tournavista', - 'Felidhoo', - 'Tmassah', - 'Puerto Pinasco', - 'Tchitado', - 'Yakossi', - 'Markovci', - 'Staro Nagoricane', - 'Smarjeske Toplice', - 'Karumba', - 'Planken', - 'Kempsey', - 'Mount Magnet', - 'Vreed-en-Hoop', - 'The Bottom', - 'Kullorsuaq', - 'Cirkulane', - 'Videm pri Ptuju', - 'Woomera', - 'Brvenica', - 'Dhuusamarreeb', - 'Skopun', - 'Morawa', - 'Lukovica', - 'Theodore', - 'Crna Trava', - 'Kuzma', - 'Eidsvold', - 'Ghasri', - 'Buabidi', - 'Montes Claros', - 'Cankova', - 'Hvannasund', - 'Tsavo', - 'Gornji Petrovci', - 'Tisina', - 'Tandil', - 'Espungabera', + 'Tacurong', + 'Totteridge', + 'Kumcati', + "Saint George's", + 'Uttoxeter', + 'Neath', + 'Cairns', + 'Kelkit', + 'Banlung', + 'Minneola', + 'Nedre Eiker', + 'Vembaditalam', + 'Ramanayyapeta', + 'New Ross', + 'Szamotuly', + 'Lapao', + 'Sakkamapatti', + 'Anjuna', + 'Lower Southampton', + 'Uch-Korgon', 'Salovci', - 'Brades', - 'Jursinci', - 'Podlehnik', - 'Braslovce', - 'Toconao', - 'Trnovska Vas', - 'Savnik', - 'Rinconada', - 'Jurovski Dol', - 'Three Springs', - 'Centar Zupa', - 'Hrib-Loski Potok', - 'Ravensthorpe', - 'Scoresbysund', - 'Vitomarci', - 'Burubaytal', - 'Dobrovo', - 'Leava', - 'Pine Creek', - 'Keflavik', - 'Sentrupert', - 'Basse-Terre', - 'Umm al `Abid', - 'Dolneni', - 'Araouane', - 'Halfmoon Bay', - 'Buur Gaabo', - 'Podvelka', - 'Cazombo', - 'Belcista', - 'Porkeri', - 'Nova Vas', - 'Yaupi', - 'Imdina', - 'Ikela', - 'Hodos', - 'Dol', - 'Cucer-Sandevo', - 'Zelenikovo', - 'Melekeok', - 'Ngerulmud', - 'Andamooka', - 'Tomaz pri Ormozu', - 'Tasiusaq', - 'Adelaide River', - 'Kulusuk', - 'Burketown', - 'Bistrica ob Sotli', - 'Skocjan', - 'Kanyato', - 'Amau', - 'Kairaki', - 'Makole', - 'Boulia', - 'Sveti Jurij', - 'Solcava', - 'Thargomindah', - 'Destrnik', - 'Kraulshavn', - 'Lusanga', - 'Hurdiyo', - 'Port Pirie', - 'Cerkvenjak', - 'Ivanhoe', - 'Al Qunaytirah', - 'Camooweal', - 'Bafwasende', - 'Razkrizje', - 'Buton', - 'Bifoun', - 'Kangersuatsiaq', - 'Narsarsuaq', - 'Bedourie', - 'Petrovec', - 'Mount Isa', - 'Fort Wellington', - 'Dobje', - 'Punta Prieta', - 'Birdsville', - 'Star Dojran', - 'Zelino', - 'Windorah', - 'Al `Uqaylah', - 'Lemsid', - 'Grytviken', - 'Fuzuli', - 'Venado Tuerto', - 'Famjin', - 'Osilnica', - 'Piso Firme', - 'Studenicani', - 'Pagegiai', - 'Savissivik', - 'Adamstown', - 'Samamea', - 'Cauquenes', - 'Bogovinje', - 'Cuya', - 'Vransko', - 'Zillah', - 'Chegga', - 'Djado', - 'Gaigirgordub', - 'Andoas', - 'Puca Urco', - 'Soldado Bartra', - 'Gueppi', - 'Kostel', - 'Puerto Heath', - 'Lagunas', - 'Barnis', - 'Gamba', - 'Nord', - 'Timmiarmiut', - 'Kingoonya', - 'Sabha', - '`Amran', - 'Al Jabin', - 'Nelspruit', - 'Lupane', - 'Anouvong', - 'Xekong', - 'Phon-Hong', - "Qacha's Nek", - 'Mersch', - 'Redange-sur-Attert', - 'Idri', - 'Cocieri', - 'Lipkovo', - 'Ilinden', - 'Resen', - 'Makedonska Kamenica', - 'Dalandzadgad', - 'Tevragh Zeina', - 'Santa Lucija', - 'Rasdhoo', - 'Dhihdhoo', - 'Fonadhoo', - 'Nilandhoo', - 'Thulusdhoo', - 'Balaka', - 'Neno', - 'Chikwawa', - 'Usakos', - 'We', - 'Abakaliki', - 'Yenagoa', - 'Isemi-Ile', - "Hayma'", - 'Suhar', - 'Union Choco', - 'Sieyik', - 'Kurumul', - 'Buka', - 'Az Za`ayin', - 'Umm Salal `Ali', - 'Madinat ash Shamal', - 'Bosilegrad', - 'Zagubica', - 'Doljevac', - 'Boljevac', - 'Ljubovija', - 'Babusnica', - 'Presevo', - 'Ljig', - 'Mali Zvornik', - 'Priboj', - 'Bojnik', - 'Koceljeva', - 'Zabari', - 'Trgoviste', - 'Taro', - 'Rabak', - 'El Fula', - 'Edinburgh of the Seven Seas', - 'Zetale', - 'Sentilj', - 'Zuzemberk', - 'Zavrc', - 'Chiesanuova', - 'Sedhiou', - 'Ceerigaabo', - 'Laascaanood', - 'Boorama', - 'Nhlangano', - 'Pala', - 'Bardai', - 'Kara', - 'Ban Huai Hin', - 'Lospalos', - 'Aileu', - 'Pante Macassar', - 'Suai', - 'Aranguez', - 'Mahonda', - 'Vwawa', - 'Koani', - 'Namutumba', - 'Maracha', - 'Luuka Town', - 'Kasanda', - 'Kinoni', - 'Busesa', - 'Bulambuli', - 'Ntoroko', - 'Otuke', - 'Bupoto', - 'Agago', - 'Kitamilo', - 'Nsiika', - 'Kalaki', - 'Kasaali', - 'Nakapiripirit', - 'Pader', - 'Kakumiro', - 'Mparo', - 'Lamwo', - 'Kyankwanzi', - 'Ntara', - 'Bukwo', - 'Butebo', - 'Binyin', - 'Palenga', - 'Kibingo', - 'Kole', - 'Nabilatuk', - 'Rubanda', - 'Kalungu', - 'Kon Tum', - 'Da Nang', - 'Saratamata', - 'Safotulafai', - 'Mulifanua', - 'Satupa`itea', - 'Sharan', - 'Nili', - 'Davaci', - 'Sarur', - 'Qabala', - 'Isale', - 'Dogbo', - 'Tutong', - 'Sarpang', - 'Pemagatshel', - 'Tsimasham', - 'Gasa', - 'Haa', - 'Lhuentse', - 'Tsirang', - 'Loango', - 'Bangolo', - 'Chuquicamata', - 'Panying', - 'Chengde', - 'Huinan', + 'Bhawanigarh', + 'Venceslau Bras', + 'Hosahalli', + 'Sibsagar', + 'Pazarcik', + 'Grigoriopol', + 'Shencottah', + 'Trenque Lauquen', + 'Oak Hills', + 'Magangue', + 'Beharona', + 'Hirakawacho', + 'Katsuura', + 'Belpukur', + 'Xingang', + 'Topoloveni', + 'Auxerre', + 'Caba', + 'Amioun', + 'Lake Oswego', + 'Nicoya', + 'Piprai', + 'Takhemaret', + 'Jula Buzarg', + 'Nam Som', + 'Wad Medani', + 'Dubasari', + 'Ricaurte', + 'Kocevje', + 'Torit', + 'Kanamadi', + 'Tasso', + 'Hermiston', + 'Seven Hills', + 'Ahmed Rachedi', + 'Maryville', + 'Lunen', + 'Marondry', + 'Ridgewood', + 'Chajul', + 'Norosi', + 'Amatitlan', + 'Williamstown', + 'Uliastay', + 'Lorsch', + 'Tekkekara', + 'Manisa', + 'Piatra Neamt', + 'Serta', + 'Padarti', + 'Agaro', + 'Boa Vista do Tupim', + 'Hariana', + 'Kobayashi', + 'Jessup', + 'Chahe', + 'Bournemouth', + 'Anajatuba', + 'Tugatog', + 'Vavur', + 'Ksar el Boukhari', + 'Masku', + 'Sungandiancun', + 'Candoni', + 'Mori', + 'Saint-Omer', + 'Alhaurin el Grande', + 'Atasu', + 'Rodos', + 'Bordj el Bahri', + 'Iheddadene', + 'Golden Hills', + 'Vista', + 'Cabrican', + 'Guara', + 'Sendarappatti', + 'Djouab', + 'Altea', + 'Omagari', + 'Firou', + 'Guinguineo', + 'Poytug`', + 'Chennamangalam', + 'Ramantali', + 'Penonome', + 'Tindivanam', + 'New River', + 'Pedda Tumbalam', + 'Hendersonville', + 'East Ridge', + 'The Colony', + 'Velizy-Villacoublay', + 'Koheda', + 'Ouaregou', + 'Sint-Truiden', + 'Zonnebeke', + 'Cartersville', + 'Serro', + 'Smorumnedre', + 'Sebt Bni Garfett', + 'Budhlada', + 'Malmesbury', + 'Kranj', + 'Union de San Antonio', + 'Batu Pahat', + 'Lian', + 'Baldeogarh', + 'Katsushika-ku', + 'Kiho', + 'Decines-Charpieu', + 'Jangy-Nookat', + 'Mudgal', + 'Pocoes', + 'Nanping', + 'Mota', + 'Maoussa', + 'Wolnzach', + 'Deysbrook', + 'Bad Essen', + 'Edogawa', + 'Cromer', + 'Brejetuba', + 'Wasilkow', + 'Beni Rached', + 'Balch Springs', + 'Folsom', + 'Nakonde', + 'Priboj', + 'Sigma', + 'Monywa', + 'Raismes', + 'Patut', + 'Kangar', + 'Kostrzyn', + 'Settsu', + 'Nandongcun', + 'Moosburg', + 'Vohitrandriana', + 'Sidi Bou Othmane', + 'Had Sahary', + 'Prescott Valley', + 'Burghausen', + 'Meco', + 'Bourbonnais', + 'San Maurizio Canavese', + 'Tequixquiac', + 'Wanyuan', + 'Hungund', + 'Huambo', + 'Sopelana', + 'Madaoua', + 'Mottola', + 'North Valley Stream', + 'Schaafheim', + 'Mataas Na Kahoy', + 'Maracay', + 'Deh Bakri', + 'Turkistan', + 'Spiesen-Elversberg', + 'Lansdale', + 'Sinha', + 'Haddonfield', + 'Mechanicstown', + 'San Vicente del Caguan', + 'Middleburg Heights', + 'New Lenox', + 'Mehlville', + 'Ambalakirajy', + 'Tak', + 'Willemstad', + 'Yato', + 'Carbondale', + 'Wakiso', + 'Farsala', + 'Gudarah', + 'Dorchester', + 'Ban Pang Mu', + 'Mosgiel', + 'Grafing bei Munchen', + 'Domkonda', + 'Challans', + 'Sulmona', + 'Ayirurpara', + 'Kaman', + 'Kumaramangalam', + 'Jiaojiazhuang', + 'Kelsterbach', + 'Saratoga', + 'Haledon', + 'Apodi', + 'Kuchinda', + 'Slidell', + 'Miamisburg', + 'Ponmana', + 'Icatu', + 'Oliva', + 'Cliza', + 'Ellenabad', + 'Pikit', + 'Fengning', + 'Erbaa', + 'Koraput', + 'Bhiloda', + 'Thenia', + 'Chinoz', + 'Zaysan', + 'Sarmastpur', + 'Lerici', + 'Wachtberg', + 'Kunjatturu', + 'Mzimba', + 'Oficina Maria Elena', + 'Paco do Lumiar', + 'Swansea', + 'Showt', + 'Batroun', + 'El Hadjar', + 'Childwall', + 'Xekong', + 'Anta', + 'Khem Karan Saray', + 'Panruti', + 'Yatton', + 'Avalpundurai', + 'Kudayattur', + 'Al Miqdadiyah', + 'Humanes de Madrid', + 'Tako', + 'As Sa`diyah', + 'Santana do Livramento', + 'Terrebonne', + 'Caninde de Sao Francisco', + 'Dombachcheri', + 'Podlehnik', + 'Andergrove', + 'Mima', + 'San Vendemiano', + 'Kindi', + 'Mengdingjie', + 'Xindi', + 'Kembhavi', + 'Verden', + 'Tarboro', + 'Manga', + 'Santa Rosa Jauregui', + 'Eiras', + 'Sapporo', + 'Puerto Octay', + 'Bothell West', + 'Almolonga', + 'Asperg', + 'Nanchong', + 'Honnali', + 'Orange City', + 'Ommangi', + 'Marilia', + 'Tobyl', + 'Coatesville', + 'Laualagaon', + 'Chinacota', + 'Breuillet', + 'Sinnamary', + 'Sun Lakes', + 'Tandur', + 'La Uruca', + 'Ann Arbor', + 'Boumerdes', + 'Cizre', + 'Bicheno', + 'Ebersberg', + 'Diangoute Kamara', + 'Havanur', + 'Barra Mansa', + 'Santa Margherita Ligure', + 'Bruchhausen-Vilsen', + 'Daet', + 'Dumai', + 'Lanta', + 'Cahama', + 'Rajgadh', + 'Kapurthala', + "Sidi Smai'il", + 'Bir el Ater', + 'Yesilkoy', + 'Yanshuiguan', + 'Arantangi', + 'Gaza', + 'Alajarvi', + 'Kondalahalli', + 'Salmanshahr', + 'Campo Maior', + 'Lago Vista', + 'Savignano sul Panaro', + 'Nong Kung Si', + 'Barnia', + 'Puttige', + 'Bracebridge', + 'Hipparga', + 'Bramsche', + 'Yangi Mirishkor', + 'Kimyogarlar', + 'Khemis el Khechna', + 'Maizieres-les-Metz', + 'Beyneu', + 'Eden Isle', + 'South Burlington', + 'Ramnagar Farsahi', + 'Vught', + 'Hexiwu', + 'Bhatpalli', + 'Kokoszki', + 'Rocky Mount', + 'Ano Syros', + 'Lutayan', + 'Ridgecrest', + 'Ranpur', + 'Ituango', + 'Kapelle-op-den-Bos', + 'Ladol', + 'Ambalabe', + 'Taramangalam', + 'Kumanovo', + 'Funyan Bira', + "Itaporanga d'Ajuda", + 'Samana', + 'Nij Khari', + 'Kafr Nabudah', + 'Dombasle-sur-Meurthe', + 'Jurbise', + 'Ciudad del Carmen', + 'Toon', + 'Big Spring', + 'Talpa de Allende', + 'Hinton', + 'Araouane', + 'Morungaba', + 'Stolac', + 'Lobez', + 'Toulon', + 'San Cesareo', + 'Three Lakes', + 'Jacareacanga', + 'Marne', + 'Fredericia', + 'Convencion', + 'Tarquinia', + 'Tepe-Korgon', + 'El Ghiate', + 'Tashkent', + 'Kirchlengern', + 'Roseau', + 'Nahan', + 'Givors', + 'Ikom', + 'Bumpe', + 'Shirhatti', + 'Reggiolo', + 'San Blas', + 'Cholet', + 'Dhirwas', + 'Bata', + 'Taito', + 'Jind', + 'Sahil', + 'La Fleche', + 'Ardakan', + 'Batangafo', + 'Kaza', + 'Bac', + 'Rio Jimenez', + 'Caycuma', + 'Kippax', + 'Denyekoro', + 'Ganganagar', + 'Mahalpur', + 'Sarpavaram', + 'Punarakh', + 'Cessnock', + 'San Fausto de Campcentellas', + 'Scandicci', + 'Valle Vista', + 'Manaoag', + 'Noe', + 'Penha', + 'Couvin', + 'Bakun', + 'Porto Uniao', + 'Bolanos de Calatrava', + 'Sun City West', + 'Orzinuovi', + 'Carrara', + 'Tilhar', + 'Prudentopolis', + 'Ciudad Real', + 'Ermont', + 'Sulop', + 'Brive-la-Gaillarde', + 'El Estor', + 'Tirschenreuth', + 'Foum el Anser', + 'Ban Pong Yaeng Nai', + 'Lissegazoun', + 'Gucheng', + 'Louth', + 'Minamiise', + 'Janow Lubelski', + 'Zacualpan', + 'Bobrynets', + 'Bel Imour', + 'El Valle del Espiritu Santo', + 'Vodiriana', + 'Ad Dujayl', + 'Puerto La Cruz', + 'Cadiz', + 'Basse Santa Su', + 'Longuenesse', + 'Kalamula', + 'Ponca City', + 'Lebowakgomo', + 'Chittandikavundanur', + 'Villarrobledo', + 'Settivaripalle', + 'Maksi', + 'Whitnash', + 'Parintins', + 'Mykolaiv', + 'Somavarappatti', + 'Az Zaydiyah', + 'Chop', + 'Pingcha', + 'Gojo', + 'Anicuns', + "Vaprio d'Adda", + 'Ailan Mubage', + 'Gernsheim', + 'Ozamiz City', + 'Bamendjou', + 'Mantingan', + 'Centre Wellington', + 'Somolu', + 'Ijevan', + 'Gurun', + 'Sonhauli', + 'Hoshoot', + 'Lippstadt', + 'Payshamba Shahri', + 'Pirapora', + 'Mariyadau', + 'Touba', + 'Cavallino', + 'Broomall', + 'Saint-Paul-Trois-Chateaux', + 'Pirangut', + 'Monte San Savino', + 'Addis Ababa', + 'Wenzhou', + 'Hongshui', + 'Bamora', + 'Dadeldhura', + 'Barrhead', + 'Qizilhacili', + 'Cenon', + 'Yany Kapu', + 'Lauderdale Lakes', + 'Franklin Farm', + 'Licheng', + 'Lacchiarella', + 'Oshwe', + 'Blantyre', + 'Birpur', + 'Bucha', + 'San Manuel', + 'Laguna Beach', + 'Donna', + 'Clute', + 'Achchampeta', + 'Rajapalaiyam', + 'Koszeg', + 'Venancio Aires', + 'Romang', + 'Four Corners', + 'Sturgeon Bay', + 'Tuscaloosa', + 'Goianira', + 'Chattamangalam', + 'Tadotsu', + 'Sindhnur', + 'Ouda-daito', + 'Harmah', + 'Nordhausen', + 'Had Laaounate', + 'Dolny Kubin', + 'Penarth', + 'Androka', + 'Cajibio', + 'Molesey', + 'Zhanjia', + 'Abuzar-e Ghaffari', + 'Sayaxche', + 'Austin', + 'Pipalrawan', + 'Chillan', + 'Baena', + 'Langenberg', + 'Mykolaivka', + 'Ferentino', + 'Biddulph', + 'Harnosand', + 'Koekelberg', + 'Little Hulton', + 'Al Qitena', + 'Lewisville', + 'Turaiyur', + 'Chakkuvarakal', + 'Tres Rios', + 'Banabuiu', + 'Muzaffargarh', + 'Erragondapalem', + 'Ghambiraopet', + 'Okara', + 'Ilioupoli', + 'Paddhari', + 'Nariar', + 'Longjing', + "M'Sila", + 'Bongor', + 'Viterbo', + 'Vlasenica', + 'Montalvania', + 'Parali', + 'Spa', + 'Westford', + 'Muttam', + 'Raamsdonksveer', + 'Garoua Boulai', + 'Batarasa', + 'Vasylkivka', + 'Estevan', + 'Luanda', + 'MacArthur', + 'Zulpich', + 'Phulbani', + 'Ifarantsa', + 'Umbita', + 'Korogwe', + 'Ilhabela', + 'Baronissi', + 'Kalyvia Thorikou', + 'Lahfayr', + 'Ba Ria', + 'Bronderslev', + 'Kaynasli', + 'Usmate Velate', + 'Hirosaki', + 'Quedgeley', + 'Zawyat ech Cheikh', + 'Soledad Atzompa', + 'Ambohitromby', 'Joao Teves', - 'Igreja', - 'Nova Sintra', - 'Pombas', - 'Cova Figueira', - 'Erfurt', - 'Fuglafjordhur', - 'Hov', - 'Vagur', - 'Saltangara', - 'Kvivik', - 'Sumba', - 'Vidhareidhi', - 'Nordhragota', - 'Toftir', - 'Kirkja', - 'Eidhi', - 'Sandavagur', - 'Skuvoy', - 'Skalavik', - 'Sorvagur', - 'Vestmanna', - 'Strendur', - 'Tvoroyri', - 'Husavik', - 'Kunoy', - 'Oyrarbakki', - 'Goaso', - 'Dambai', - 'Sefwi Wiawso', - 'Kanifing', - 'King Edward Point', - 'Tanjung Selor', - 'Trim', - 'Jaitpura', - 'Navsari', - 'Tonk', - 'Sari', - 'Nyamira', - 'Siaya', - "Murang'a", - 'Ol Kalou', - 'Sotik Post', - 'Kapenguria', - 'Kabarnet', - 'Migori', - 'Pailin', - 'Ta Khmau', - 'Sariwon-si', - 'Munha-dong', - 'Sil-li', - 'Muan', - 'Hongseong', - 'Charlotte Amalie', + 'Siddipet', + 'Bitkine', + 'Bellshill', + 'Feke', + 'Grass Valley', + 'Ashton in Makerfield', + 'Punjai Puliyampatti', + 'Lobito', + 'Bernalda', + 'Loudonville', + 'Asbury Lake', + 'Gyoda', + 'Artik', + 'Rio Rancho', + 'Roissy-en-Brie', + 'Garches', + 'Chemini', ]; diff --git a/drizzle-seed/src/datasets/countries.ts b/drizzle-seed/src/datasets/countries.ts index c251f25e8..11bc64e91 100644 --- a/drizzle-seed/src/datasets/countries.ts +++ b/drizzle-seed/src/datasets/countries.ts @@ -13,7 +13,6 @@ export default [ 'Bahrain', 'Bangladesh', 'Barbados', - 'Belarus', 'Belgium', 'Belize', 'Benin', @@ -124,7 +123,6 @@ export default [ 'Portugal', 'Qatar', 'Romania', - 'Russia', 'Rwanda', 'Samoa', 'Saudi Arabia', diff --git a/drizzle-seed/src/datasets/phonesInfo.ts b/drizzle-seed/src/datasets/phonesInfo.ts index fc1f26750..d3ed9663f 100644 --- a/drizzle-seed/src/datasets/phonesInfo.ts +++ b/drizzle-seed/src/datasets/phonesInfo.ts @@ -80,18 +80,6 @@ export default [ '880,18,10', '880,19,10', '1,246,10', - '375,25,9', - '375,29 1,9', - '375,29 2,9', - '375,29 3,9', - '375,29 4,9', - '375,29 5,9', - '375,29 6,9', - '375,29 7,9', - '375,29 8,9', - '375,29 9,9', - '375,33,9', - '375,44,9', '32,456,9', '32,47,9', '32,48,9', @@ -438,18 +426,6 @@ export default [ '81,070,11', '81,080,11', '81,090,11', - '7,700,10', - '7,708,10', - '7,701,10', - '7,702,10', - '7,775,10', - '7,778,10', - '7,705,10', - '7,771,10', - '7,776,10', - '7,777,10', - '7,707,10', - '7,747,10', '254,10,10', '254,11,10', '254,70,10', diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts index 635f4d15f..a036e63cd 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -76,7 +76,7 @@ function createGenerator, T>( // Generators Classes ----------------------------------------------------------------------------------------------------------------------- export class GenerateWeightedCount extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'GenerateWeightedCount'; + static override readonly [entityKind]: string = 'GenerateWeightedCount'; private state: { rng: prand.RandomGenerator; @@ -114,7 +114,7 @@ export class GenerateWeightedCount extends AbstractGenerator<{}> { } export class HollowGenerator extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'HollowGenerator'; + static override readonly [entityKind]: string = 'HollowGenerator'; init() {} @@ -124,7 +124,7 @@ export class HollowGenerator extends AbstractGenerator<{}> { export class GenerateDefault extends AbstractGenerator<{ defaultValue: unknown; }> { - static readonly [entityKind]: string = 'GenerateDefault'; + static override readonly [entityKind]: string = 'GenerateDefault'; init() {} @@ -141,7 +141,7 @@ export class GenerateValuesFromArray extends AbstractGenerator< isUnique?: boolean; } > { - static readonly [entityKind]: string = 'GenerateValuesFromArray'; + static override readonly [entityKind]: string = 'GenerateValuesFromArray'; public weightedCountSeed: number | undefined = undefined; public maxRepeatedValuesCount?: number | { weight: number; count: number | number[] }[] = undefined; @@ -398,7 +398,7 @@ export class GenerateValuesFromArray extends AbstractGenerator< } export class GenerateSelfRelationsValuesFromArray extends AbstractGenerator<{ values: (number | string | boolean)[] }> { - static readonly [entityKind]: string = 'GenerateSelfRelationsValuesFromArray'; + static override readonly [entityKind]: string = 'GenerateSelfRelationsValuesFromArray'; private state: { rng: prand.RandomGenerator; @@ -438,7 +438,7 @@ export class GenerateSelfRelationsValuesFromArray extends AbstractGenerator<{ va } export class GenerateIntPrimaryKey extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'GenerateIntPrimaryKey'; + static override readonly [entityKind]: string = 'GenerateIntPrimaryKey'; public maxValue?: number | bigint; @@ -465,7 +465,7 @@ export class GenerateNumber extends AbstractGenerator< isUnique?: boolean; } | undefined > { - static readonly [entityKind]: string = 'GenerateNumber'; + static override readonly [entityKind]: string = 'GenerateNumber'; private state: { rng: prand.RandomGenerator; @@ -529,7 +529,7 @@ export class GenerateUniqueNumber extends AbstractGenerator< isUnique?: boolean; } | undefined > { - static readonly [entityKind]: string = 'GenerateUniqueNumber'; + static override readonly [entityKind]: string = 'GenerateUniqueNumber'; private state: { genUniqueIntObj: GenerateUniqueInt; @@ -581,7 +581,7 @@ export class GenerateInt extends AbstractGenerator<{ maxValue?: number | bigint; isUnique?: boolean; }> { - static readonly [entityKind]: string = 'GenerateInt'; + static override readonly [entityKind]: string = 'GenerateInt'; private state: { rng: prand.RandomGenerator; @@ -606,7 +606,7 @@ export class GenerateInt extends AbstractGenerator<{ } if (minValue === undefined) { - minValue = maxValue === undefined ? -1000 : -maxValue; + minValue = -maxValue; } if (typeof minValue === 'number' && typeof maxValue === 'number') { @@ -655,7 +655,7 @@ export class GenerateUniqueInt extends AbstractGenerator<{ maxValue?: number | bigint; isUnique?: boolean; }> { - static readonly [entityKind]: string = 'GenerateUniqueInt'; + static override readonly [entityKind]: string = 'GenerateUniqueInt'; public genMaxRepeatedValuesCount: GenerateDefault | GenerateWeightedCount | undefined; public skipCheck?: boolean = false; @@ -833,7 +833,7 @@ export class GenerateUniqueInt extends AbstractGenerator<{ } export class GenerateBoolean extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'GenerateBoolean'; + static override readonly [entityKind]: string = 'GenerateBoolean'; private state: { rng: prand.RandomGenerator; @@ -858,7 +858,7 @@ export class GenerateBoolean extends AbstractGenerator<{}> { } export class GenerateDate extends AbstractGenerator<{ minDate?: string | Date; maxDate?: string | Date }> { - static readonly [entityKind]: string = 'GenerateDate'; + static override readonly [entityKind]: string = 'GenerateDate'; private state: { rng: prand.RandomGenerator; @@ -946,7 +946,7 @@ export class GenerateDate extends AbstractGenerator<{ minDate?: string | Date; m // } export class GenerateTime extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'GenerateTime'; + static override readonly [entityKind]: string = 'GenerateTime'; private state: { rng: prand.RandomGenerator; @@ -1008,7 +1008,7 @@ export class GenerateTime extends AbstractGenerator<{}> { // } export class GenerateTimestampInt extends AbstractGenerator<{ unitOfTime?: 'seconds' | 'milliseconds' }> { - static readonly [entityKind]: string = 'GenerateTimestampInt'; + static override readonly [entityKind]: string = 'GenerateTimestampInt'; private state: { generateTimestampObj: GenerateTimestamp; @@ -1041,7 +1041,7 @@ export class GenerateTimestampInt extends AbstractGenerator<{ unitOfTime?: 'seco } export class GenerateTimestamp extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'GenerateTimestamp'; + static override readonly [entityKind]: string = 'GenerateTimestamp'; private state: { rng: prand.RandomGenerator; @@ -1083,7 +1083,7 @@ export class GenerateTimestamp extends AbstractGenerator<{}> { } export class GenerateDatetime extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'GenerateDatetime'; + static override readonly [entityKind]: string = 'GenerateDatetime'; private state: { rng: prand.RandomGenerator; @@ -1125,7 +1125,7 @@ export class GenerateDatetime extends AbstractGenerator<{}> { } export class GenerateYear extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'GenerateYear'; + static override readonly [entityKind]: string = 'GenerateYear'; private state: { rng: prand.RandomGenerator; @@ -1158,7 +1158,7 @@ export class GenerateYear extends AbstractGenerator<{}> { } export class GenerateJson extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'GenerateJson'; + static override readonly [entityKind]: string = 'GenerateJson'; private state: { emailGeneratorObj: GenerateEmail; @@ -1277,7 +1277,7 @@ export class GenerateJson extends AbstractGenerator<{}> { // } export class GenerateEnum extends AbstractGenerator<{ enumValues: (string | number | boolean)[] }> { - static readonly [entityKind]: string = 'GenerateEnum'; + static override readonly [entityKind]: string = 'GenerateEnum'; private state: { enumValuesGenerator: GenerateValuesFromArray; @@ -1300,7 +1300,7 @@ export class GenerateEnum extends AbstractGenerator<{ enumValues: (string | numb } export class GenerateInterval extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateInterval'; + static override readonly [entityKind]: string = 'GenerateInterval'; private state: { rng: prand.RandomGenerator } | undefined; override uniqueVersionOfGen = GenerateUniqueInterval; @@ -1363,7 +1363,7 @@ export class GenerateInterval extends AbstractGenerator<{ isUnique?: boolean }> } export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateUniqueInterval'; + static override readonly [entityKind]: string = 'GenerateUniqueInterval'; private state: { rng: prand.RandomGenerator; @@ -1433,7 +1433,7 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boole } export class GenerateString extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateString'; + static override readonly [entityKind]: string = 'GenerateString'; private state: { rng: prand.RandomGenerator } | undefined; override uniqueVersionOfGen = GenerateUniqueString; @@ -1482,7 +1482,7 @@ export class GenerateString extends AbstractGenerator<{ isUnique?: boolean }> { } export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateUniqueString'; + static override readonly [entityKind]: string = 'GenerateUniqueString'; private state: { rng: prand.RandomGenerator } | undefined; public override isUnique = true; @@ -1527,7 +1527,7 @@ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean export class GenerateFirstName extends AbstractGenerator<{ isUnique?: boolean; }> { - static readonly [entityKind]: string = 'GenerateFirstName'; + static override readonly [entityKind]: string = 'GenerateFirstName'; override timeSpent: number = 0; private state: { @@ -1567,7 +1567,7 @@ export class GenerateFirstName extends AbstractGenerator<{ export class GenerateUniqueFirstName extends AbstractGenerator<{ isUnique?: boolean; }> { - static readonly [entityKind]: string = 'GenerateUniqueFirstName'; + static override readonly [entityKind]: string = 'GenerateUniqueFirstName'; private state: { genIndicesObj: GenerateUniqueInt; @@ -1600,7 +1600,7 @@ export class GenerateUniqueFirstName extends AbstractGenerator<{ } export class GenerateLastName extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateLastName'; + static override readonly [entityKind]: string = 'GenerateLastName'; private state: { rng: prand.RandomGenerator; @@ -1633,7 +1633,7 @@ export class GenerateLastName extends AbstractGenerator<{ isUnique?: boolean }> } export class GenerateUniqueLastName extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateUniqueLastName'; + static override readonly [entityKind]: string = 'GenerateUniqueLastName'; private state: { genIndicesObj: GenerateUniqueInt; @@ -1666,7 +1666,7 @@ export class GenerateUniqueLastName extends AbstractGenerator<{ isUnique?: boole export class GenerateFullName extends AbstractGenerator<{ isUnique?: boolean; }> { - static readonly [entityKind]: string = 'GenerateFullName'; + static override readonly [entityKind]: string = 'GenerateFullName'; private state: { rng: prand.RandomGenerator; @@ -1709,7 +1709,7 @@ export class GenerateFullName extends AbstractGenerator<{ export class GenerateUniqueFullName extends AbstractGenerator<{ isUnique?: boolean; }> { - static readonly [entityKind]: string = 'GenerateUniqueFullName'; + static override readonly [entityKind]: string = 'GenerateUniqueFullName'; private state: { fullnameSet: Set; @@ -1763,7 +1763,7 @@ export class GenerateUniqueFullName extends AbstractGenerator<{ } export class GenerateEmail extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'GenerateEmail'; + static override readonly [entityKind]: string = 'GenerateEmail'; private state: { genIndicesObj: GenerateUniqueInt; @@ -1820,7 +1820,7 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ prefixes?: string[]; generatedDigitsNumbers?: number | number[]; }> { - static readonly [entityKind]: string = 'GeneratePhoneNumber'; + static override readonly [entityKind]: string = 'GeneratePhoneNumber'; private state: { rng: prand.RandomGenerator; @@ -1993,7 +1993,7 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ } export class GenerateCountry extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateCountry'; + static override readonly [entityKind]: string = 'GenerateCountry'; private state: { rng: prand.RandomGenerator; @@ -2029,7 +2029,7 @@ export class GenerateCountry extends AbstractGenerator<{ isUnique?: boolean }> { } export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateUniqueCountry'; + static override readonly [entityKind]: string = 'GenerateUniqueCountry'; private state: { genIndicesObj: GenerateUniqueInt; @@ -2060,7 +2060,7 @@ export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolea } export class GenerateJobTitle extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'GenerateJobTitle'; + static override readonly [entityKind]: string = 'GenerateJobTitle'; private state: { rng: prand.RandomGenerator; @@ -2085,7 +2085,7 @@ export class GenerateJobTitle extends AbstractGenerator<{}> { } export class GenerateStreetAdddress extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateStreetAdddress'; + static override readonly [entityKind]: string = 'GenerateStreetAdddress'; private state: { rng: prand.RandomGenerator; @@ -2130,7 +2130,7 @@ export class GenerateStreetAdddress extends AbstractGenerator<{ isUnique?: boole } export class GenerateUniqueStreetAdddress extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateUniqueStreetAdddress'; + static override readonly [entityKind]: string = 'GenerateUniqueStreetAdddress'; private state: { rng: prand.RandomGenerator; @@ -2215,7 +2215,7 @@ export class GenerateUniqueStreetAdddress extends AbstractGenerator<{ isUnique?: } export class GenerateCity extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateCity'; + static override readonly [entityKind]: string = 'GenerateCity'; private state: { rng: prand.RandomGenerator; @@ -2249,7 +2249,7 @@ export class GenerateCity extends AbstractGenerator<{ isUnique?: boolean }> { } export class GenerateUniqueCity extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateUniqueCity'; + static override readonly [entityKind]: string = 'GenerateUniqueCity'; private state: { genIndicesObj: GenerateUniqueInt; @@ -2280,7 +2280,7 @@ export class GenerateUniqueCity extends AbstractGenerator<{ isUnique?: boolean } } export class GeneratePostcode extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GeneratePostcode'; + static override readonly [entityKind]: string = 'GeneratePostcode'; private state: { rng: prand.RandomGenerator; @@ -2333,7 +2333,7 @@ export class GeneratePostcode extends AbstractGenerator<{ isUnique?: boolean }> } export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateUniquePostcode'; + static override readonly [entityKind]: string = 'GenerateUniquePostcode'; private state: { rng: prand.RandomGenerator; @@ -2410,7 +2410,7 @@ export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boole } export class GenerateState extends AbstractGenerator<{}> { - static readonly [entityKind]: string = 'GenerateState'; + static override readonly [entityKind]: string = 'GenerateState'; private state: { rng: prand.RandomGenerator; @@ -2435,7 +2435,7 @@ export class GenerateState extends AbstractGenerator<{}> { } export class GenerateCompanyName extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateCompanyName'; + static override readonly [entityKind]: string = 'GenerateCompanyName'; private state: { rng: prand.RandomGenerator; @@ -2499,7 +2499,7 @@ export class GenerateCompanyName extends AbstractGenerator<{ isUnique?: boolean } export class GenerateUniqueCompanyName extends AbstractGenerator<{ isUnique?: boolean }> { - static readonly [entityKind]: string = 'GenerateUniqueCompanyName'; + static override readonly [entityKind]: string = 'GenerateUniqueCompanyName'; private state: { rng: prand.RandomGenerator; @@ -2603,7 +2603,7 @@ export class GenerateUniqueCompanyName extends AbstractGenerator<{ isUnique?: bo } export class GenerateLoremIpsum extends AbstractGenerator<{ sentencesCount?: number }> { - static readonly [entityKind]: string = 'GenerateLoremIpsum'; + static override readonly [entityKind]: string = 'GenerateLoremIpsum'; private state: { rng: prand.RandomGenerator; @@ -2632,7 +2632,7 @@ export class GenerateLoremIpsum extends AbstractGenerator<{ sentencesCount?: num } export class WeightedRandomGenerator extends AbstractGenerator<{ weight: number; value: AbstractGenerator }[]> { - static readonly [entityKind]: string = 'WeightedRandomGenerator'; + static override readonly [entityKind]: string = 'WeightedRandomGenerator'; private state: { rng: prand.RandomGenerator; @@ -2701,7 +2701,7 @@ export class GeneratePoint extends AbstractGenerator<{ minYValue?: number; maxYValue?: number; }> { - static readonly [entityKind]: string = 'GeneratePoint'; + static override readonly [entityKind]: string = 'GeneratePoint'; private state: { xCoordinateGen: GenerateNumber; @@ -2761,7 +2761,7 @@ export class GenerateUniquePoint extends AbstractGenerator<{ maxYValue?: number; isUnique?: boolean; }> { - static readonly [entityKind]: string = 'GenerateUniquePoint'; + static override readonly [entityKind]: string = 'GenerateUniquePoint'; private state: { xCoordinateGen: GenerateUniqueNumber; @@ -2814,7 +2814,7 @@ export class GenerateLine extends AbstractGenerator<{ minCValue?: number; maxCValue?: number; }> { - static readonly [entityKind]: string = 'GenerateLine'; + static override readonly [entityKind]: string = 'GenerateLine'; private state: { aCoefficientGen: GenerateNumber; @@ -2891,7 +2891,7 @@ export class GenerateUniqueLine extends AbstractGenerator<{ maxCValue?: number; isUnique?: boolean; }> { - static readonly [entityKind]: string = 'GenerateUniqueLine'; + static override readonly [entityKind]: string = 'GenerateUniqueLine'; private state: { aCoefficientGen: GenerateUniqueNumber; @@ -3384,7 +3384,7 @@ export const generatorsFuncs = { * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ * users: { * columns: { - * city: funcs.cityName({isUnique: false}) + * city: funcs.city({isUnique: false}) * }, * }, * })); diff --git a/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts b/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts index 5f8356da5..1e01d0453 100644 --- a/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts +++ b/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts @@ -8,6 +8,8 @@ import { reset, seed } from '../../../index.ts'; import * as schema from './pgSchema.ts'; import { sql } from 'drizzle-orm'; +import cities from '../../../datasets/cityNames.ts'; +import countries from '../../../datasets/countries.ts'; import firstNames from '../../../datasets/firstNames.ts'; import lastNames from '../../../datasets/lastNames.ts'; @@ -977,7 +979,7 @@ test('country unique generator test', async () => { // countryUniqueTable----------------------------------------------------------------------------------- await seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ countryUniqueTable: { - count: 167, + count: countries.length, columns: { countryUnique: funcs.country({ isUnique: true }), }, @@ -992,7 +994,7 @@ test('country unique generator test', async () => { await expect( seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ countryUniqueTable: { - count: 168, + count: countries.length + 1, columns: { countryUnique: funcs.country({ isUnique: true }), }, @@ -1023,7 +1025,7 @@ test('city unique generator test', async () => { await reset(db, { cityUniqueTable: schema.cityUniqueTable }); await seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ cityUniqueTable: { - count: 42984, + count: cities.length, columns: { cityUnique: funcs.city({ isUnique: true }), }, @@ -1038,7 +1040,7 @@ test('city unique generator test', async () => { await expect( seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ cityUniqueTable: { - count: 42985, + count: cities.length + 1, columns: { cityUnique: funcs.city({ isUnique: true }), }, From c459f9868700ec374b56c2828878c89a3b2cff07 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 20 Nov 2024 19:53:37 +0200 Subject: [PATCH 369/492] Add drizzle-seed to releases --- .github/workflows/release-feature-branch.yaml | 1 + .github/workflows/release-latest.yaml | 1 + drizzle-orm/package.json | 2 +- drizzle-seed/package.json | 3 +++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-feature-branch.yaml b/.github/workflows/release-feature-branch.yaml index eb360da2d..3868db792 100644 --- a/.github/workflows/release-feature-branch.yaml +++ b/.github/workflows/release-feature-branch.yaml @@ -16,6 +16,7 @@ jobs: - drizzle-orm - drizzle-kit - drizzle-zod + - drizzle-seed - drizzle-typebox - drizzle-valibot - eslint-plugin-drizzle diff --git a/.github/workflows/release-latest.yaml b/.github/workflows/release-latest.yaml index f9292b2e0..fdab8f90e 100644 --- a/.github/workflows/release-latest.yaml +++ b/.github/workflows/release-latest.yaml @@ -12,6 +12,7 @@ jobs: - drizzle-orm - drizzle-kit - drizzle-zod + - drizzle-seed - drizzle-typebox - drizzle-valibot - eslint-plugin-drizzle diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index fedd4073c..809a28520 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.36.3", + "version": "0.36.4", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index 8f3aa11d4..bb8f4a26b 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -34,6 +34,9 @@ "default": "./index.mjs" } }, + "peerDependencies": { + "drizzle-orm": ">=0.36.4" + }, "peerDependenciesMeta": { "drizzle-orm": { "optional": true From 2ce4da7a6baa517b055ad0cdb02175cf4c5d5513 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 21 Nov 2024 10:59:20 +0200 Subject: [PATCH 370/492] Upgrade to 0.0.2 --- drizzle-seed/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index bb8f4a26b..95dcf1725 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-seed", - "version": "0.0.1", + "version": "0.0.2", "main": "index.js", "type": "module", "scripts": { From 9b4c9edc6fa4c940263e88911db44ca214ed052a Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 21 Nov 2024 11:39:58 +0200 Subject: [PATCH 371/492] Update Drizzle Seed npm --- drizzle-seed/package.json | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index 95dcf1725..c529f22e8 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-seed", - "version": "0.0.2", + "version": "0.1.1", "main": "index.js", "type": "module", "scripts": { @@ -17,9 +17,37 @@ "start:sqlite": "npx tsx ./src/tests/northwind/sqliteTest.ts", "benchmark": "npx tsx ./src/tests/benchmarks/generatorsBenchmark.ts" }, - "author": "", - "license": "ISC", - "description": "", + "author": "Drizzle Team", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/drizzle-team/drizzle-orm/issues" + }, + "keywords": [ + "drizzle", + "orm", + "pg", + "mysql", + "postgresql", + "postgres", + "sqlite", + "database", + "sql", + "typescript", + "ts", + "drizzle-orm", + "drizzle-seed", + "seeding", + "seed" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/drizzle-team/drizzle-orm.git" + }, + "publishConfig": { + "provenance": true + }, + "sideEffects": false, + "description": "A package to seed your database using Drizzle ORM", "exports": { ".": { "import": { From 83cac0bcf2fba544e497fd5e60c131afd601201f Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 21 Nov 2024 12:03:08 +0200 Subject: [PATCH 372/492] Create identity test --- integration-tests/tests/seeder/pg.test.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/integration-tests/tests/seeder/pg.test.ts b/integration-tests/tests/seeder/pg.test.ts index f0bce90df..b820189be 100644 --- a/integration-tests/tests/seeder/pg.test.ts +++ b/integration-tests/tests/seeder/pg.test.ts @@ -609,6 +609,16 @@ const createAllGeneratorsTables = async () => { ); `, ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."identity_columns_table" ( + "id" integer GENERATED ALWAYS AS IDENTITY, + "id1" integer, + "name" text + ); + `, + ); }; beforeAll(async () => { @@ -616,7 +626,7 @@ beforeAll(async () => { db = drizzle(client); - await db.execute(sql`CREATE SCHEMA "seeder_lib_pg";`); + await db.execute(sql`CREATE SCHEMA IF NOT EXISTS "seeder_lib_pg";`); await createNorthwindTables(); await createAllDataTypesTable(); From e9e8cad85a7290056e68f48f1cbaccf3db32a932 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 21 Nov 2024 12:18:11 +0200 Subject: [PATCH 373/492] Fix tests --- integration-tests/tests/seeder/pg.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/tests/seeder/pg.test.ts b/integration-tests/tests/seeder/pg.test.ts index b820189be..5eef08fe5 100644 --- a/integration-tests/tests/seeder/pg.test.ts +++ b/integration-tests/tests/seeder/pg.test.ts @@ -1384,7 +1384,7 @@ test('country unique generator test', async () => { // countryUniqueTable----------------------------------------------------------------------------------- await seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ countryUniqueTable: { - count: 167, + count: 160, columns: { countryUnique: funcs.country({ isUnique: true }), }, @@ -1430,7 +1430,7 @@ test('city unique generator test', async () => { await reset(db, { cityUniqueTable: schema.cityUniqueTable }); await seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ cityUniqueTable: { - count: 42984, + count: 42884, columns: { cityUnique: funcs.city({ isUnique: true }), }, From 789b25abb88862571f39efbaff71ed12f1822088 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 21 Nov 2024 12:33:55 +0200 Subject: [PATCH 374/492] Fix tests --- integration-tests/tests/seeder/pg.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/tests/seeder/pg.test.ts b/integration-tests/tests/seeder/pg.test.ts index 5eef08fe5..8d074e747 100644 --- a/integration-tests/tests/seeder/pg.test.ts +++ b/integration-tests/tests/seeder/pg.test.ts @@ -1430,7 +1430,7 @@ test('city unique generator test', async () => { await reset(db, { cityUniqueTable: schema.cityUniqueTable }); await seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ cityUniqueTable: { - count: 42884, + count: 38884, columns: { cityUnique: funcs.city({ isUnique: true }), }, From f882b728c6a92437a025fdbb38846f9f5d68ce9a Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 21 Nov 2024 13:24:05 +0200 Subject: [PATCH 375/492] Review fixes --- drizzle-seed/src/index.ts | 97 +- .../src/services/GeneratorsWrappers.ts | 183 - drizzle-seed/src/services/SeedService.ts | 96 +- drizzle-seed/src/services/utils.ts | 11 - .../tests/benchmarks/generatorsBenchmark.ts | 11 - drizzle-seed/src/tests/mysql/mysqlSchema.ts | 26 - .../src/tests/northwind/mysqlSchema.ts | 26 - drizzle-seed/src/tests/northwind/pgSchema.ts | 26 - .../src/tests/northwind/sqliteSchema.ts | 24 - .../src/tests/northwind/sqliteTest.ts | 2 - drizzle-seed/src/tests/sqlite/sqliteSchema.ts | 24 - integration-tests/tests/seeder/firstNames.ts | 30276 ---------- integration-tests/tests/seeder/lastNames.ts | 50000 ---------------- integration-tests/tests/seeder/pg.test.ts | 4 +- 14 files changed, 13 insertions(+), 80793 deletions(-) delete mode 100644 integration-tests/tests/seeder/firstNames.ts delete mode 100644 integration-tests/tests/seeder/lastNames.ts diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 545b9295d..47c9f408e 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -44,9 +44,6 @@ type InferCallbackType< column in keyof SCHEMA[table] as SCHEMA[table][column] extends PgColumn ? column : never ]?: AbstractGenerator; - // ReturnType< - // (typeof generatorsFuncs)[keyof typeof generatorsFuncs] - // > }; with?: { [ @@ -79,9 +76,6 @@ type InferCallbackType< column in keyof SCHEMA[table] as SCHEMA[table][column] extends MySqlColumn ? column : never ]?: AbstractGenerator; - // ReturnType< - // (typeof generatorsFuncs)[keyof typeof generatorsFuncs] - // >; }; with?: { [ @@ -114,9 +108,6 @@ type InferCallbackType< column in keyof SCHEMA[table] as SCHEMA[table][column] extends SQLiteColumn ? column : never ]?: AbstractGenerator; - // ReturnType< - // (typeof generatorsFuncs)[keyof typeof generatorsFuncs] - // >; }; with?: { [ @@ -196,50 +187,6 @@ class SeedPromise< await seedFunc(this.db, this.schema, this.options, refinements); } } -// type DrizzleStudioColumnType = { -// default?: unknown, -// autoincrement: boolean, -// name: string, -// type: string, -// primaryKey: boolean, -// notNull: boolean, -// }; - -// export type DrizzleStudioObjectType = { -// schemas: { -// [schemaName: string]: { -// tables: { -// [tableName: string]: { -// name: string, -// type: string, -// indexes: {}, //TODO change to real type -// schema: string, -// columns: { -// [columnName: string]: DrizzleStudioColumnType -// }, -// foreignKeys: {}, //TODO change to real type -// compositePrimaryKeys: {}, //TODO change to real type -// uniqueConstraints: {}, //TODO change to real type -// } -// }, -// views: { -// [viewName: string]: { -// name: string, -// type: string, -// indexes: {}, //TODO change to real type -// schema: string, -// columns: { -// [columnName: string]: DrizzleStudioColumnType -// }, -// foreignKeys: {}, //TODO change to real type -// compositePrimaryKeys: {}, //TODO change to real type -// uniqueConstraints: {}, //TODO change to real type -// } -// }, -// enums: {} -// } -// } -// }; export function getGeneratorsFunctions() { return generatorsFuncs; @@ -254,8 +201,6 @@ export async function seedForDrizzleStudio( options?: { count?: number; seed?: number }; }, ) { - // where can I find primary keys? - // where can I find relations? const generatedSchemas: { [schemaName: string]: { tables: { @@ -297,7 +242,6 @@ export async function seedForDrizzleStudio( ? schemasRefinements[schemaName] : undefined; - // console.log("tables:", tables) const generatedTablesGenerators = seedService.generatePossibleGenerators( sqlDialect, tables, @@ -305,9 +249,7 @@ export async function seedForDrizzleStudio( refinements, options, ); - // console.log("generatedTablesGenerators:", generatedTablesGenerators[0]?.columnsPossibleGenerators) - // console.time("generateTablesValues"); const generatedTables = await seedService.generateTablesValues( relations, generatedTablesGenerators, @@ -315,7 +257,6 @@ export async function seedForDrizzleStudio( undefined, { ...options, preserveData: true, insertDataInDb: false }, ); - // console.log("generatedTables:", generatedTables) generatedSchemas[schemaName] = { tables: generatedTables }; } @@ -336,13 +277,13 @@ export async function seedForDrizzleStudio( * * @example * ```ts - * //base seeding + * // base seeding * await seed(db, schema); * - * //seeding with count specified + * // seeding with count specified * await seed(db, schema, { count: 100000 }); * - * //seeding with count and seed specified + * // seeding with count and seed specified * await seed(db, schema, { count: 100000, seed: 1 }); * * //seeding using refine @@ -400,7 +341,6 @@ const seedFunc = async ( options: { count?: number; seed?: number } = {}, refinements?: RefinementsType, ) => { - // console.time("seedFunc"); if (is(db, PgDatabase)) { const { pgSchema } = filterPgTables(schema); @@ -416,7 +356,6 @@ const seedFunc = async ( } else { throw new Error('given db is not supported.'); } - // console.timeEnd("seedFunc"); }; /** @@ -543,7 +482,6 @@ const seedPostgres = async ( options, ); - // console.time("generateTablesValues"); await seedService.generateTablesValues( relations, generatedTablesGenerators, @@ -551,14 +489,6 @@ const seedPostgres = async ( schema, options, ); - // console.timeEnd("generateTablesValues"); - - // for (const generatedTable of generatedTables) { - // await db - // .insert(schema[generatedTable.tableName]) - // .values(generatedTable.rows) - // .execute(); - // } }; const getPostgresInfo = (schema: { [key: string]: PgTable }) => { @@ -653,7 +583,6 @@ const resetMySql = async ( ) => { const tablesToTruncate = Object.entries(schema).map(([_tsTableName, table]) => { const dbTableName = getTableName(table); - // console.log(config) return dbTableName; }); @@ -661,7 +590,6 @@ const resetMySql = async ( for (const tableName of tablesToTruncate) { const sqlQuery = `truncate \`${tableName}\`;`; - // console.log(sqlQuery) await db.execute(sql.raw(sqlQuery)); } @@ -709,13 +637,6 @@ const seedMySql = async ( schema, options, ); - - // for (const generatedTable of generatedTables) { - // await db - // .insert(schema[generatedTable.tableName]) - // .values(generatedTable.rows) - // .execute(); - // } }; const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { @@ -809,7 +730,6 @@ const resetSqlite = async ( ) => { const tablesToTruncate = Object.entries(schema).map(([_tsTableName, table]) => { const dbTableName = getTableName(table); - // console.log(config) return dbTableName; }); @@ -817,7 +737,6 @@ const resetSqlite = async ( for (const tableName of tablesToTruncate) { const sqlQuery = `delete from \`${tableName}\`;`; - // console.log(sqlQuery) await db.run(sql.raw(sqlQuery)); } @@ -865,13 +784,6 @@ const seedSqlite = async ( schema, options, ); - - // for (const generatedTable of generatedTables) { - // await db - // .insert(schema[generatedTable.tableName]) - // .values(generatedTable.rows) - // .execute(); - // } }; const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { @@ -956,3 +868,6 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { return { tables, relations }; }; + +export { default as firstNames } from './datasets/firstNames.ts'; +export { default as lastNames } from './datasets/lastNames.ts'; diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts index a036e63cd..266c0277b 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -30,37 +30,6 @@ export abstract class AbstractGenerator { abstract generate(params: { i: number }): number | string | boolean | unknown | undefined | void; } -// type OptionalSpread = -// T extends undefined -// ? [] -// : [T]; - -// function createGenerator>( -// generatorConstructor: new ({ }: T) => GT -// ) { -// return (...args: OptionalSpread): GT => { -// if (params === undefined) params = {} as T; -// return new generatorConstructor(params); -// }; -// } - -// function foo(...args: OptionalSpread) { -// const arg = args[0] // Type of: T = undefined -// return arg; -// } - -// foo(1) - -// function createGenerator( -// generatorConstructor: new ({ }: T) => AbstractGenerator -// ) { -// return (...args: IsRequired extends true ? [T] : ([] | [T])): AbstractGenerator => { -// let params = args[0]; -// if (params === undefined) params = {} as T; -// return new generatorConstructor(params); -// }; -// } - function createGenerator, T>( generatorConstructor: new(params: T) => GeneratorType, ) { @@ -150,8 +119,6 @@ export class GenerateValuesFromArray extends AbstractGenerator< values: | (number | string | boolean | undefined)[] | { weight: number; values: (number | string | boolean | undefined)[] }[]; - // valuesCount: { [key: string | number]: number }; - // indicesCount: { [key: number]: number }; genIndicesObj: GenerateUniqueInt | undefined; genIndicesObjList: GenerateUniqueInt[] | undefined; valuesWeightedIndices: number[] | undefined; @@ -244,16 +211,6 @@ export class GenerateValuesFromArray extends AbstractGenerator< const { params, isUnique, notNull, weightedCountSeed } = this; const values = params.values; - // let values; - // if (typeof this.params.values[0] === "object") { - // values = this.params.values.slice(); - // } - // else { - // values = this.params.values; - // } - - // const valuesCount = {}; - // const indicesCount = {}; let valuesWeightedIndices; if (typeof values[0] === 'object') { @@ -268,9 +225,7 @@ export class GenerateValuesFromArray extends AbstractGenerator< indicesCounter[valueIdx]! += 1; } - // console.log(values, indicesCounter) for (const [idx, value] of values.entries()) { - // console.log((value as { values: (number | string | boolean | undefined)[] }).values.length) if ((value as { values: (number | string | boolean | undefined)[] }).values.length < indicesCounter[idx]!) { throw new Error( 'weighted values arrays is too small to generate values with specified probability for unique not null column.' @@ -328,28 +283,22 @@ export class GenerateValuesFromArray extends AbstractGenerator< generate() { const t0 = new Date(); - // let { maxRepeatedValuesCount } = this; if (this.state === undefined) { throw new Error('state is not defined.'); } - // logic for this generator let idx: number, value: string | number | boolean | undefined; let valueIdx: number; if (this.state.valuesWeightedIndices === undefined) { if (this.state.genIndicesObj === undefined) { - // isUnique !== true [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.values.length - 1, this.state.rng); } else { - // isUnique === true idx = this.state.genIndicesObj.generate() as number; - // console.log("maxRepeatedValuesCount:", this.maxRepeatedValuesCount, "idx:", idx) } - // [idx, this.rng] = prand.uniformIntDistribution(0, this.values!.length - 1, this.rng!); value = (this.state.values as (number | string | boolean | undefined)[])[idx]; } else { // weighted values @@ -371,27 +320,6 @@ export class GenerateValuesFromArray extends AbstractGenerator< value = currValues[idx]; } - // if (maxRepeatedValuesCount !== undefined) { - // if (this.state.valuesCount[value as string | number] === undefined) { - // this.state.valuesCount[value as string | number] = this.state.genMaxRepeatedValuesCount!.generate() as number; - // } - // this.state.valuesCount![value as string | number] -= 1; - - // // this.state.indicesCount[idx] = this.state.valuesCount[value as string | number]; - // console.log("indicesCount", this.state.indicesCount) - - // if (this.state.valuesCount![value as string | number] === 0) { - // if (this.state.valuesWeightedIndices !== undefined) { - // // this.values!.splice(idx, 1); - // const currValues = (this.state.values![valueIdx!] as { weight: number, values: (number | string | boolean | undefined)[] }).values; - // currValues.splice(idx, 1); - // if (currValues.length === 0) { - // this.state.values!.splice(valueIdx!, 1); - // } - // } - // } - // } - this.timeSpent += (Date.now() - t0.getTime()) / 1000; return value; } @@ -423,14 +351,12 @@ export class GenerateSelfRelationsValuesFromArray extends AbstractGenerator<{ va } const { values } = this.params; - // logic for this generator let idx: number; if (i < this.state.firstValuesCount) { this.state.firstValues.push(values[i]!); return values[i]; } else { - // i >= this.state.firstValuesCount [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.firstValues.length - 1, this.state.rng); return this.state.firstValues[idx]; } @@ -487,7 +413,6 @@ export class GenerateNumber extends AbstractGenerator< } let { minValue, maxValue, precision } = this.params; - // logic for this generator if (precision === undefined) { precision = 100; } @@ -719,9 +644,6 @@ export class GenerateUniqueInt extends AbstractGenerator<{ if (this.state.intervals.length === 0) { if (this.skipCheck === false) { - // console.log(`i:${i}`); - // console.log("integersCount", integersCount, "maxValue", maxValue) - // console.log("maxValue", this.state.maxValue, "minValue", this.state.minValue, this.skipCheck) throw new RangeError( 'generateUniqueInt: count exceeds max number of unique integers in given range(min, max), try to increase range.', ); @@ -772,8 +694,6 @@ export class GenerateUniqueInt extends AbstractGenerator<{ this.state!.integersCount.set(numb, this.state!.integersCount.get(numb)! - 1); } - // console.log("integersCount", this.state.integersCount); - if (this.state!.integersCount.get(numb) === undefined || this.state!.integersCount.get(numb) === 0) { if (numb === currMinNumb) { intervalsToAdd = numb + 1 <= currMaxNumb ? [[numb + 1, currMaxNumb]] : []; @@ -786,11 +706,9 @@ export class GenerateUniqueInt extends AbstractGenerator<{ ]; } - // delete intervals[intervalIdx]; const t0 = new Date(); this.state!.intervals[intervalIdx] = this.state!.intervals[this.state!.intervals.length - 1]!; this.state?.intervals.pop(); - // this.state!.intervals.splice(intervalIdx, 1); this.timeSpent += (Date.now() - t0.getTime()) / 1000; this.state!.intervals.push(...intervalsToAdd); } @@ -808,7 +726,6 @@ export class GenerateUniqueInt extends AbstractGenerator<{ this.state!.integersCount.set(numb, this.state!.integersCount.get(numb)! - 1); } - // console.log("integersCount", this.state.integersCount); if (this.state!.integersCount.get(numb) === undefined || this.state!.integersCount.get(numb) === 0) { if (numb === currMinNumb) { intervalsToAdd = numb + BigInt(1) <= currMaxNumb ? [[numb + BigInt(1), currMaxNumb]] : []; @@ -821,8 +738,6 @@ export class GenerateUniqueInt extends AbstractGenerator<{ ]; } - // delete intervals[intervalIdx]; - // this.state!.intervals.splice(intervalIdx, 1); this.state!.intervals[intervalIdx] = this.state!.intervals[this.state!.intervals.length - 1]!; this.state?.intervals.pop(); this.state!.intervals.push(...intervalsToAdd); @@ -871,9 +786,6 @@ export class GenerateDate extends AbstractGenerator<{ minDate?: string | Date; m let { minDate, maxDate } = this.params; const anchorDate = new Date('2024-05-08'); - // const formatter = new Intl.DateTimeFormat("en-US", { year: "numeric", month: "2-digit", day: "2-digit", }); - // anchorDate.toLocaleDateString("en-US", { year: "numeric", month: "2-digit", day: "2-digit", }) - // fourYearsInMilliseconds const deltaMilliseconds = 4 * 31536000000; if (typeof minDate === 'string') { @@ -917,34 +829,9 @@ export class GenerateDate extends AbstractGenerator<{ minDate?: string | Date; m if (this.dataType === 'string') { return date.toISOString().replace(/T.+/, ''); } - // this.dataType === "date" return date; } } - -// export class GenerateDateString extends AbstractGenerator<{}> { -// private state: { -// dateGen: GenerateDate -// } | undefined; - -// init({ seed }: { seed: number }) { -// const dateGen = new GenerateDate({}); -// dateGen.init({ seed }); - -// this.state = { dateGen }; -// } - -// generate() { -// if (this.state === undefined) { -// throw new Error("state is not defined."); -// } - -// const date = this.state.dateGen.generate(); - -// return date.toISOString().replace(/T.+/, ""); -// } -// } - export class GenerateTime extends AbstractGenerator<{}> { static override readonly [entityKind]: string = 'GenerateTime'; @@ -979,34 +866,6 @@ export class GenerateTime extends AbstractGenerator<{}> { return date.toISOString().replace(/(\d{4}-\d{2}-\d{2}T)|(\.\d{3}Z)/g, ''); } } - -// export class GenerateTimestampString extends AbstractGenerator<{}> { -// private state: { -// generateTimestampObj: GenerateTimestamp; -// } | undefined; - -// init({ seed }: { seed: number }) { -// const generateTimestampObj = new GenerateTimestamp({}); -// generateTimestampObj.init({ seed }); - -// this.state = { generateTimestampObj }; -// } - -// generate() { -// if (this.state === undefined) { -// throw new Error("state is not defined."); -// } - -// let date: Date; -// date = this.state.generateTimestampObj.generate(); - -// return date -// .toISOString() -// .replace("T", " ") -// .replace(/\.\d{3}Z/, ""); - -// } - export class GenerateTimestampInt extends AbstractGenerator<{ unitOfTime?: 'seconds' | 'milliseconds' }> { static override readonly [entityKind]: string = 'GenerateTimestampInt'; @@ -1258,24 +1117,6 @@ export class GenerateJson extends AbstractGenerator<{}> { } } -// export class GenerateJsonb extends AbstractGenerator<{}> { -// private state: { jsonGeneratorObj: GenerateJson } | undefined; - -// init({ count, seed }: { count: number, seed: number }) { -// const jsonGeneratorObj = new GenerateJson({}); -// jsonGeneratorObj.init({ count, seed }); - -// this.state = { jsonGeneratorObj }; -// } - -// generate({ i }: { i: number }) { -// if (this.state === undefined) { -// throw new Error("state is not defined."); -// } -// return this.state.jsonGeneratorObj.generate({ i }) -// // return JSON.parse(this.state.jsonGeneratorObj.generate({ i })); -// } - export class GenerateEnum extends AbstractGenerator<{ enumValues: (string | number | boolean)[] }> { static override readonly [entityKind]: string = 'GenerateEnum'; @@ -1336,20 +1177,12 @@ export class GenerateInterval extends AbstractGenerator<{ isUnique?: boolean }> [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); - // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); - // daysNumb = randVal === 0 ? 0 : daysNumb; [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); - // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); - // hoursNumb = randVal === 0 ? 0 : hoursNumb; [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); - // minutesNumb = randVal === 0 ? 0 : minutesNumb; [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); - // secondsNumb = randVal === 0 ? 0 : secondsNumb; interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` @@ -1398,22 +1231,10 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boole for (;;) { [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); - [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); - // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); - // daysNumb = randVal === 0 ? 0 : daysNumb; - [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); - // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); - // hoursNumb = randVal === 0 ? 0 : hoursNumb; - [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); - // minutesNumb = randVal === 0 ? 0 : minutesNumb; - [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - // [randVal, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); - // secondsNumb = randVal === 0 ? 0 : secondsNumb; interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` @@ -1575,11 +1396,9 @@ export class GenerateUniqueFirstName extends AbstractGenerator<{ public override isUnique = true; init({ count, seed }: { count: number; seed: number }) { - // console.log("1-------", count, firstNames.length) if (count > firstNames.length) { throw new Error('count exceeds max number of unique first names.'); } - // console.log("2-------") const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: firstNames.length - 1 }); genIndicesObj.init({ count, seed }); @@ -1895,8 +1714,6 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ } if (new Set(prefixesArray).size !== prefixesArray.length) { - // prefixesArray.forEach(prefix => console.log(prefix)) - // console.log(prefixesArray.length - new Set(prefixesArray).size) throw new Error('prefixes are not unique.'); } diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 4ec70118b..d5166faae 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -63,19 +63,18 @@ class SeedService { let tablePossibleGenerators: Prettify; const customSeed = options?.seed === undefined ? 0 : options.seed; - // console.log("relations:", relations); // sorting table in order which they will be filled up (tables with foreign keys case) // relations = relations.filter(rel => rel.type === "one"); const tablesInOutRelations = this.getTablesInOutRelations(relations); const orderedTablesNames = this.getOrderedTablesList(tablesInOutRelations); - tables = tables.sort((tabel1, tabel2) => { - const tabel1Order = orderedTablesNames.indexOf( - tabel1.name, + tables = tables.sort((table1, table2) => { + const table1Order = orderedTablesNames.indexOf( + table1.name, ), - tabel2Order = orderedTablesNames.indexOf( - tabel2.name, + table2Order = orderedTablesNames.indexOf( + table2.name, ); - return tabel1Order - tabel2Order; + return table1Order - table2Order; }); const tablesPossibleGenerators: Prettify< @@ -104,8 +103,6 @@ class SeedService { } } - // console.time("generatePossibleGenerators_refinements section"); - // console.log(refinements) if (refinements !== undefined && refinements[table.name] !== undefined) { if (refinements[table.name]!.count !== undefined) { tablesPossibleGenerators[i]!.count = refinements[table.name]!.count; @@ -151,18 +148,13 @@ class SeedService { weightedCountSeed = customSeed + generateHashFromString(`${table.name}.${fkTableName}`); - // const repeatedValuesCount = this.getCountFromWeightedCount(weightedRepeatedValuesCount, seed); - // refinements![table.name].with![fkTableName] = repeatedValuesCount; - // console.time("getWeightedWithCount") newTableWithCount = this.getWeightedWithCount( weightedRepeatedValuesCount, (tablesPossibleGenerators[i]!.withCount || tablesPossibleGenerators[i]!.count)!, weightedCountSeed, ); - // console.timeEnd("getWeightedWithCount") - // console.log("newTableWithCount:", newTableWithCount) } if ( @@ -176,14 +168,10 @@ class SeedService { repeatedValuesCount: refinements[table.name]!.with![fkTableName]!, weightedCountSeed, }; - - // tablesPossibleGenerators[idx].withFromTableName = table.name; } } } } - // console.timeEnd("generatePossibleGenerators_refinements section"); - // console.time("generatePossibleGenerators_generatorPick section"); tablePossibleGenerators = tablesPossibleGenerators[i]!; for (const col of table.columns) { // col.myType = typeMap[col._type as keyof typeof typeMap]; @@ -202,7 +190,6 @@ class SeedService { && refinements[table.name]!.columns[col.name] !== undefined ) { const genObj = refinements[table.name]!.columns[col.name]!; - // if (genObj instanceof GenerateValuesFromArray) // for now only GenerateValuesFromArray support notNull property genObj.notNull = col.notNull; @@ -236,7 +223,6 @@ class SeedService { } if (columnPossibleGenerator.generator === undefined) { - // console.log("column:", col); throw new Error( `column with type ${col.columnType} is not supported for now.`, ); @@ -247,19 +233,13 @@ class SeedService { tablePossibleGenerators.columnsPossibleGenerators.push( columnPossibleGenerator, ); - // console.log("column:", col, columnPossibleGenerator.generator) } - // console.timeEnd("generatePossibleGenerators_generatorPick section"); } - // console.timeEnd("generatePossibleGenerators"); return tablesPossibleGenerators; }; getOrderedTablesList = (tablesInOutRelations: ReturnType): string[] => { - // console.time("getOrderedTablesList"); - // const tablesInOutRelations = this.getTablesInOutRelations(relations); - const leafTablesNames = Object.entries(tablesInOutRelations) .filter( (tableRel) => @@ -269,18 +249,11 @@ class SeedService { ) .map((tableRel) => tableRel[0]); - // console.log("leafTablesNames", leafTablesNames); const orderedTablesNames: string[] = []; - // BFS let parent: string, children: string[]; for (let i = 0; leafTablesNames.length !== 0; i++) { - // console.log(i); - // console.log("leafTablesNames", leafTablesNames); - // console.log("orderedTablesNames", orderedTablesNames); parent = leafTablesNames.shift() as string; - // console.log(parent, tablesInOutRelations[parent].requiredTableNames) - if (orderedTablesNames.includes(parent)) { continue; } @@ -301,18 +274,9 @@ class SeedService { continue; } - // children = relations - // .filter((rel) => rel.refTable === parent) - // .map((rel) => rel.table) - // .filter((child) => child !== parent); - children = [...tablesInOutRelations[parent]!.dependantTableNames]; - // console.log("children", children); - // console.log("children1", tablesInOutRelations[parent].dependantTableNames); leafTablesNames.push(...children); } - // console.log("orderedTablesNames", orderedTablesNames); - // console.timeEnd("getOrderedTablesList"); return orderedTablesNames; }; @@ -371,14 +335,12 @@ class SeedService { count: number, seed: number, ) => { - // const gen = (new GenerateWeightedCount({})).execute({ weightedCount, count, seed }); const gen = new GenerateWeightedCount({}); gen.init({ count: weightedCount, seed }); let weightedWithCount = 0; for (let i = 0; i < count; i++) { weightedWithCount += gen.generate(); } - // gen.return(); return weightedWithCount; }; @@ -867,7 +829,6 @@ class SeedService { // TODO: now I'm generating tablesInOutRelations twice, first time in generatePossibleGenerators and second time here. maybe should generate it once instead. const tablesInOutRelations = this.getTablesInOutRelations(relations); for (const table of tablesGenerators) { - // console.log("tableName:", table) tableCount = table.count === undefined ? options?.count || this.defaultCountForTable : table.count; tableGenerators = {}; @@ -887,7 +848,6 @@ class SeedService { )) : (customSeed + generateHashFromString(`${table.tableName}.${col.columnName}`)); - // console.log(pRNGSeed); tableGenerators[col.columnName] = { pRNGSeed, ...col, @@ -978,11 +938,6 @@ class SeedService { ? false : true; - // if (table.tableName === "products") { - // console.log("tableGenerators:", tableGenerators); - // console.log("name:", tableGenerators["name"].generator?.params) - // } - // console.time("generateColumnsValuesByGenerators"); tableValues = await this.generateColumnsValuesByGenerators({ tableGenerators, db, @@ -992,7 +947,6 @@ class SeedService { preserveData, insertDataInDb, }); - // console.timeEnd("generateColumnsValuesByGenerators"); if (preserveData === true) { tablesValues.push({ @@ -1014,11 +968,8 @@ class SeedService { tablesInOutRelations[table.tableName] !== undefined && tablesInOutRelations[table.tableName]!.in > 0, ); } - - // console.timeEnd("generateOneTableValues"); } - // console.log("tablesValues", tablesValues); return tablesValues; }; @@ -1048,33 +999,19 @@ class SeedService { count = this.defaultCountForTable; } - // console.log("count:", count); let columnGenerator: (typeof tableGenerators)[string]; - // const columnsGenerators: { - // [columnName: string]: Generator< - // number | string | boolean | unknown, - // void, - // unknown - // >; - // } = {}; const columnsGenerators: { [columnName: string]: AbstractGenerator; } = {}; let generatedValues: { [columnName: string]: number | string | boolean | undefined }[] = []; - // console.time("initiate generators"); let columnsNumber = 0; let override = false; - // console.log("before init") for (const columnName of Object.keys(tableGenerators)) { columnsNumber += 1; columnGenerator = tableGenerators[columnName]!; override = tableGenerators[columnName]?.generatedIdentityType === 'always' ? true : override; - // columnsGenerators[columnName] = columnGenerator.generator!.execute({ - // count, - // seed: columnGenerator.pRNGSeed, - // }); columnsGenerators[columnName] = columnGenerator.generator!; columnsGenerators[columnName]!.init({ count, @@ -1097,14 +1034,7 @@ class SeedService { columnsGenerators[columnName] = uniqueGen; } - - // console.log("col:", columnName, columnsGenerators[columnName]); } - // if (tableName === "products") { - // // console.log("tableGenerators:", tableGenerators); - // console.log("name:", (tableGenerators["name"].generator as GenerateValuesFromArray)) - // } - // console.timeEnd("initiate generators"); let maxParametersNumber: number; if (is(db, PgDatabase)) { maxParametersNumber = is(db._.session, PgliteSession) @@ -1119,12 +1049,10 @@ class SeedService { const maxBatchSize = Math.floor(maxParametersNumber / columnsNumber); batchSize = batchSize > maxBatchSize ? maxBatchSize : batchSize; - // console.time("columnsGenerators"); if ( insertDataInDb === true && (db === undefined || schema === undefined || tableName === undefined) ) { - // console.log(db, schema, tableName); throw new Error('db or schema or tableName is undefined.'); } @@ -1145,7 +1073,6 @@ class SeedService { | string | number | boolean; - // console.log("generatedValue:", generatedValue); row[columnName as keyof typeof row] = generatedValue; } @@ -1189,13 +1116,6 @@ class SeedService { } } - // for (const columnName of Object.keys(columnsGenerators)) { - // console.log( - // `timeSpent to generate ${columnName}:`, - // columnsGenerators[columnName]!.timeSpent - // ); - // } - return preserveData === true ? generatedValues : []; }; @@ -1219,21 +1139,17 @@ class SeedService { tableName: string; override: boolean; }) => { - // console.log(tableName, generatedValues); if (is(db, PgDatabase)) { - // console.log("table to insert data:", tableName, ";columns in table:", Object.keys(generatedValues[0]!).length, ";rows to insert:", generatedValues, ";overall parameters:", generatedValues.length * Object.keys(generatedValues[0]!).length); const query = db.insert((schema as { [key: string]: PgTable })[tableName]!); if (override === true) { return await query.overridingSystemValue().values(generatedValues); } await query.values(generatedValues); } else if (is(db, MySqlDatabase)) { - // console.log("table to insert data:", tableName, ";columns in table:", Object.keys(generatedValues[0]).length, ";rows to insert:", generatedValues, ";overall parameters:", generatedValues.length * Object.keys(generatedValues[0]).length); await db .insert((schema as { [key: string]: MySqlTable })[tableName]!) .values(generatedValues); } else if (is(db, BaseSQLiteDatabase)) { - // console.log("table to insert data:", tableName, ";columns in table:", Object.keys(generatedValues[0]).length, ";rows to insert:", generatedValues.length, ";overall parameters:", generatedValues.length * Object.keys(generatedValues[0]).length); await db .insert((schema as { [key: string]: SQLiteTable })[tableName]!) .values(generatedValues); diff --git a/drizzle-seed/src/services/utils.ts b/drizzle-seed/src/services/utils.ts index dfe52253a..6f59fc63c 100644 --- a/drizzle-seed/src/services/utils.ts +++ b/drizzle-seed/src/services/utils.ts @@ -81,14 +81,3 @@ export const fillTemplate = ({ template, placeholdersCount, values, defaultValue return resultStr; }; - -// let count = 0; -// for (let i = 0; i < 3; i++) { -// for (let j = 0; j < 3; j++) { -// for (let k = 0; k < 3; k++) { -// console.log([i, j, k], "===", fastCartesianProduct([[0, 1, 2], [0, 1, 2], [0, 1, 2]], count)); -// count++; -// } - -// } -// } diff --git a/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts b/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts index 7eff3c751..cfd275da0 100644 --- a/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts +++ b/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts @@ -49,17 +49,6 @@ const benchmark = ({ generatorName, generator, count = 100000, seed = 1 }: { seed?: number; }) => { generator.init({ count, seed }); - // if (generator.uniqueVersionOfGen !== undefined && generator.isUnique === true) { - // const uniqueGen = new generator.uniqueVersionOfGen({ ...generator.params }); - // uniqueGen.init({ - // count, - // seed - // }); - // uniqueGen.isUnique = generator.isUnique; - // uniqueGen.dataType = generator.dataType; - - // generator = uniqueGen; - // } let timeSpentToInit = 0, timeSpent = 0; const t0 = new Date(); diff --git a/drizzle-seed/src/tests/mysql/mysqlSchema.ts b/drizzle-seed/src/tests/mysql/mysqlSchema.ts index 684a5d798..624d45d3e 100644 --- a/drizzle-seed/src/tests/mysql/mysqlSchema.ts +++ b/drizzle-seed/src/tests/mysql/mysqlSchema.ts @@ -1,29 +1,3 @@ -// import { serial, int, varchar, mysqlTable } from "drizzle-orm/mysql-core"; - -// export const schema = mysqlSchema("public"); - -// export const users = mysqlTable("users", { -// id: int("id").autoincrement().primaryKey(), -// name: varchar("name", { length: 256 }), -// email: varchar("email", { length: 256 }), -// phone: varchar("phone", { length: 256 }), -// password: varchar("password", { length: 256 }) -// }); - -// export const posts = mysqlTable("posts", { -// id: int("id").autoincrement().primaryKey(), -// title: varchar("title", { length: 256 }), -// content: varchar("content", { length: 256 }), -// userId: int("user_id").references(() => users.id) -// }); - -// export const comments = mysqlTable("comments", { -// id: serial("id").primaryKey(), -// content: varchar("content", { length: 256 }), -// postId: int("post_id").references(() => posts.id), -// userId: int("user_id").references(() => users.id) -// }); - import type { AnyMySqlColumn } from 'drizzle-orm/mysql-core'; import { float, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'; diff --git a/drizzle-seed/src/tests/northwind/mysqlSchema.ts b/drizzle-seed/src/tests/northwind/mysqlSchema.ts index 337d43948..624d45d3e 100644 --- a/drizzle-seed/src/tests/northwind/mysqlSchema.ts +++ b/drizzle-seed/src/tests/northwind/mysqlSchema.ts @@ -1,29 +1,3 @@ -// import { serial, int, varchar, mysqlTable } from "drizzle-orm/mysql-core"; - -// // export const schema = mysqlSchema("public"); - -// export const users = mysqlTable("users", { -// id: int("id").autoincrement().primaryKey(), -// name: varchar("name", { length: 256 }), -// email: varchar("email", { length: 256 }), -// phone: varchar("phone", { length: 256 }), -// password: varchar("password", { length: 256 }) -// }); - -// export const posts = mysqlTable("posts", { -// id: serial("id").primaryKey(), -// title: varchar("title", { length: 256 }), -// content: varchar("content", { length: 256 }), -// userId: int("user_id").references(() => users.id) -// }); - -// export const comments = mysqlTable("comments", { -// id: serial("id").primaryKey(), -// content: varchar("content", { length: 256 }), -// postId: int("post_id").references(() => posts.id), -// userId: int("user_id").references(() => users.id) -// }); - import type { AnyMySqlColumn } from 'drizzle-orm/mysql-core'; import { float, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'; diff --git a/drizzle-seed/src/tests/northwind/pgSchema.ts b/drizzle-seed/src/tests/northwind/pgSchema.ts index 2855df3fd..f0f9a05fb 100644 --- a/drizzle-seed/src/tests/northwind/pgSchema.ts +++ b/drizzle-seed/src/tests/northwind/pgSchema.ts @@ -1,29 +1,3 @@ -// import { serial, integer, varchar, pgSchema, getTableConfig as getPgTableConfig } from "drizzle-orm/pg-core"; - -// export const schema = pgSchema("seeder_lib_pg"); - -// export const users = schema.table("users", { -// id: serial("id").primaryKey(), -// name: varchar("name", { length: 256 }), -// email: varchar("email", { length: 256 }), -// phone: varchar("phone", { length: 256 }), -// password: varchar("password", { length: 256 }) -// }); - -// export const posts = schema.table("posts", { -// id: serial("id").primaryKey(), -// title: varchar("title", { length: 256 }), -// content: varchar("content", { length: 256 }), -// userId: integer("user_id").references(() => users.id) -// }); - -// export const comments = schema.table("comments", { -// id: serial("id").primaryKey(), -// content: varchar("content", { length: 256 }), -// postId: integer("post_id").references(() => posts.id), -// userId: integer("user_id").references(() => users.id) -// }); - import type { AnyPgColumn } from 'drizzle-orm/pg-core'; import { integer, numeric, pgSchema, text, timestamp, varchar } from 'drizzle-orm/pg-core'; diff --git a/drizzle-seed/src/tests/northwind/sqliteSchema.ts b/drizzle-seed/src/tests/northwind/sqliteSchema.ts index 5a053dcad..fa00dd365 100644 --- a/drizzle-seed/src/tests/northwind/sqliteSchema.ts +++ b/drizzle-seed/src/tests/northwind/sqliteSchema.ts @@ -1,27 +1,3 @@ -// import { integer, text, sqliteTable } from "drizzle-orm/sqlite-core"; - -// export const users = sqliteTable("users", { -// id: integer("id").primaryKey(), -// name: text("name", { length: 256 }), -// email: text("email", { length: 256 }), -// phone: text("phone", { length: 256 }), -// password: text("password", { length: 256 }) -// }); - -// export const posts = sqliteTable("posts", { -// id: integer("id").primaryKey(), -// title: text("title", { length: 256 }), -// content: text("content", { length: 256 }), -// userId: integer("user_id").references(() => users.id) -// }); - -// export const comments = sqliteTable("comments", { -// id: integer("id").primaryKey(), -// content: text("content", { length: 256 }), -// postId: integer("post_id").references(() => posts.id), -// userId: integer("user_id").references(() => users.id) -// }); - import { foreignKey, integer, numeric, sqliteTable, text } from 'drizzle-orm/sqlite-core'; export const customers = sqliteTable('customer', { diff --git a/drizzle-seed/src/tests/northwind/sqliteTest.ts b/drizzle-seed/src/tests/northwind/sqliteTest.ts index 4f9d328d5..d64f2c447 100644 --- a/drizzle-seed/src/tests/northwind/sqliteTest.ts +++ b/drizzle-seed/src/tests/northwind/sqliteTest.ts @@ -18,8 +18,6 @@ console.log('database connection was established successfully.'); migrate(db, { migrationsFolder: path.join(__dirname, '../../../sqliteMigrations') }); console.log('database was migrated.'); - // await seed(db, schema, { count: 100000, seed: 1 }); - const titlesOfCourtesy = ['Ms.', 'Mrs.', 'Dr.']; const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100]; const reorderLevels = [0, 5, 10, 15, 20, 25, 30]; diff --git a/drizzle-seed/src/tests/sqlite/sqliteSchema.ts b/drizzle-seed/src/tests/sqlite/sqliteSchema.ts index 5a053dcad..fa00dd365 100644 --- a/drizzle-seed/src/tests/sqlite/sqliteSchema.ts +++ b/drizzle-seed/src/tests/sqlite/sqliteSchema.ts @@ -1,27 +1,3 @@ -// import { integer, text, sqliteTable } from "drizzle-orm/sqlite-core"; - -// export const users = sqliteTable("users", { -// id: integer("id").primaryKey(), -// name: text("name", { length: 256 }), -// email: text("email", { length: 256 }), -// phone: text("phone", { length: 256 }), -// password: text("password", { length: 256 }) -// }); - -// export const posts = sqliteTable("posts", { -// id: integer("id").primaryKey(), -// title: text("title", { length: 256 }), -// content: text("content", { length: 256 }), -// userId: integer("user_id").references(() => users.id) -// }); - -// export const comments = sqliteTable("comments", { -// id: integer("id").primaryKey(), -// content: text("content", { length: 256 }), -// postId: integer("post_id").references(() => posts.id), -// userId: integer("user_id").references(() => users.id) -// }); - import { foreignKey, integer, numeric, sqliteTable, text } from 'drizzle-orm/sqlite-core'; export const customers = sqliteTable('customer', { diff --git a/integration-tests/tests/seeder/firstNames.ts b/integration-tests/tests/seeder/firstNames.ts deleted file mode 100644 index ac6e1b74a..000000000 --- a/integration-tests/tests/seeder/firstNames.ts +++ /dev/null @@ -1,30276 +0,0 @@ -export default [ - 'Robert', - 'John', - 'Michael', - 'David', - 'James', - 'Richard', - 'Christopher', - 'William', - 'Daniel', - 'Mark', - 'Thomas', - 'Jose', - 'Joseph', - 'Matthew', - 'Jason', - 'Andrew', - 'Joshua', - 'Steven', - 'Anthony', - 'Jonathan', - 'Angel', - 'Ryan', - 'Kevin', - 'Jacob', - 'Nicholas', - 'Brandon', - 'Justin', - 'Charles', - 'Gary', - 'Paul', - 'Scott', - 'George', - 'Christian', - 'Eric', - 'Brian', - 'Alexander', - 'Ronald', - 'Jayden', - 'Juan', - 'Edward', - 'Noah', - 'Diego', - 'Donald', - 'Ethan', - 'Kyle', - 'Peter', - 'Jeffrey', - 'Luis', - 'Timothy', - 'Nathan', - 'Tyler', - 'Frank', - 'Stephen', - 'Dennis', - 'Larry', - 'Jesus', - 'Kenneth', - 'Austin', - 'Adrian', - 'Adam', - 'Sebastian', - 'Gregory', - 'Carlos', - 'Aiden', - 'Gabriel', - 'Isaac', - 'Zachary', - 'Julian', - 'Benjamin', - 'Liam', - 'Billy', - 'Miguel', - 'Mason', - 'Aaron', - 'Mike', - 'Dylan', - 'Sean', - 'Alejandro', - 'Bryan', - 'Jordan', - 'Cody', - 'Jeremy', - 'Samuel', - 'Harry', - 'Victor', - 'Joe', - 'Eduardo', - 'Isaiah', - 'Jorge', - 'Logan', - 'Elijah', - 'Bruce', - 'Patrick', - 'Jerry', - 'Jesse', - 'Lawrence', - 'Steve', - 'Walter', - 'Harold', - 'Arthur', - 'Lucas', - 'Francisco', - 'Douglas', - 'Oscar', - 'Craig', - 'Alexis', - 'Todd', - 'Randy', - 'Alan', - 'Raymond', - 'Damian', - 'Willie', - 'Albert', - 'Ricardo', - 'Louis', - 'Luke', - 'Edgar', - 'Travis', - 'Evan', - 'Ricky', - 'Aidan', - 'Jack', - 'Jeff', - 'Jimmy', - 'Manuel', - 'Oliver', - 'Mateo', - 'Johnny', - 'Henry', - 'Cristian', - 'Terry', - 'Dominic', - 'Cameron', - 'Gerald', - 'Caleb', - 'Christop', - 'Bobby', - 'Alex', - 'Gavin', - 'Shawn', - 'Jackson', - 'Ivan', - 'Keith', - 'Antonio', - 'Vincent', - 'Philip', - 'Chad', - 'Alfred', - 'Eugene', - 'Erik', - 'Martin', - 'Omar', - 'Chris', - 'Stanley', - 'Sergio', - 'Francis', - 'Mario', - 'Fernando', - 'Taylor', - 'Herbert', - 'Santiago', - 'Nathaniel', - 'Cesar', - 'Barry', - 'Trevor', - 'Dustin', - 'Hunter', - 'Roger', - 'Andres', - 'Javier', - 'Bernard', - 'Jim', - 'Ian', - 'Wayne', - 'Leonardo', - 'Giovanni', - 'Josiah', - 'Jeremiah', - 'Glenn', - 'Hector', - 'Roberto', - 'Rodney', - 'Howard', - 'Eli', - 'Xavier', - 'Jaxon', - 'Levi', - 'Derek', - 'Danny', - 'Jared', - 'Landon', - 'Ralph', - 'Ruben', - 'Gael', - 'Connor', - 'Tommy', - 'Tony', - 'Marc', - 'Wyatt', - 'Rick', - 'Carter', - 'Ayden', - 'Tim', - 'Roy', - 'Owen', - 'Greg', - 'Joel', - 'Leonard', - 'Frederick', - 'Russell', - 'Jon', - 'Jaden', - 'Jeffery', - 'Irving', - 'Erick', - 'Darren', - 'Dale', - 'Carl', - 'Brayden', - 'Ronnie', - 'Gerardo', - 'Pedro', - 'Raul', - 'Elias', - 'Chase', - 'Alberto', - 'Troy', - 'Tom', - 'Axel', - 'Julio', - 'Emmanuel', - 'Edwin', - 'Norman', - 'Marcus', - 'Fred', - 'Bill', - 'Jake', - 'Marco', - 'Leo', - 'Rafael', - 'Armando', - 'Jace', - 'Garrett', - 'Jaime', - 'Earl', - 'Shane', - 'Cole', - 'Phillip', - 'Seth', - 'Corey', - 'Nicolas', - 'Randall', - 'Hayden', - 'Abraham', - 'Grayson', - 'Tristan', - 'Cory', - 'Josue', - 'Andy', - 'Warren', - 'Roman', - 'Devin', - 'Salvador', - 'Shaun', - 'Spencer', - 'Infant', - 'Ryder', - 'Dillon', - 'Max', - 'Salvatore', - 'Bradley', - 'Seymour', - 'Arturo', - 'Iker', - 'Dean', - 'Milton', - 'Sidney', - 'Gustavo', - 'Alfredo', - 'Blake', - 'Clarence', - 'Brody', - 'Enrique', - 'Brett', - 'Colton', - 'Dan', - 'Brendan', - 'Charlie', - 'Darrell', - 'Hudson', - 'Ezra', - 'Emiliano', - 'Ashton', - 'Darryl', - 'Dave', - 'Nolan', - 'Theodore', - 'Casey', - 'Colin', - 'Easton', - 'Caden', - 'Marcos', - 'Cooper', - 'Mitchell', - 'Morris', - 'Don', - 'Eddie', - 'Jay', - 'Marvin', - 'Kaden', - 'Curtis', - 'Lance', - 'Gerard', - 'Israel', - 'Ramon', - 'Rickey', - 'Alec', - 'Carson', - 'Ernesto', - 'Riley', - 'Kai', - 'Ezekiel', - 'Yahir', - 'Dakota', - 'Ron', - 'Bob', - 'Saul', - 'Kayden', - 'Adan', - 'Fabian', - 'Maxwell', - 'Allen', - 'Micheal', - 'Parker', - 'Micah', - 'Miles', - 'Gilbert', - 'Grant', - 'Malik', - 'Abel', - 'Darrin', - 'Johnathan', - 'Jase', - 'Kaleb', - 'Ray', - 'Jaxson', - 'Brent', - 'Wesley', - 'Tanner', - 'Chester', - 'Bryce', - 'Lincoln', - 'Preston', - 'Maximiliano', - 'Jerome', - 'Sam', - 'Ernest', - 'Bentley', - 'Colby', - 'Elmer', - 'Moises', - 'Joaquin', - 'Arnold', - 'Stuart', - 'Murray', - 'Asher', - 'Andre', - 'Neil', - 'Allan', - 'Brady', - 'Brad', - 'Maximus', - 'Dalton', - 'Jonah', - 'Kim', - 'Kirk', - 'Bryson', - 'Kurt', - 'Angelo', - 'Rene', - 'Jimmie', - 'Emilio', - 'Damien', - 'Harvey', - 'Moshe', - 'Derrick', - 'Kelly', - 'Franklin', - 'Rodrigo', - 'Woodrow', - 'Leon', - 'Esteban', - 'Hugo', - 'Clayton', - 'Guadalupe', - 'Darin', - 'Pablo', - 'Luca', - 'Ken', - 'Ismael', - 'Leroy', - 'Guillermo', - 'Tracy', - 'Melvin', - 'Lorenzo', - 'Clifford', - 'Hugh', - 'Mathew', - 'Jameson', - 'Billie', - 'Nelson', - 'Herman', - 'Ira', - 'Jamie', - 'Alexande', - 'Lester', - 'Glen', - 'Damon', - 'Emanuel', - 'Maverick', - 'Braxton', - 'Zayden', - 'Dominick', - 'Irwin', - 'Rudy', - 'Calvin', - 'Julius', - 'Jermaine', - 'Jakob', - 'Donovan', - 'Lee', - 'Shaquille', - 'Gordon', - 'Peyton', - 'Duane', - 'Declan', - 'Jalen', - 'Jude', - 'Tyrone', - 'Bret', - 'Gene', - 'Felix', - 'Guy', - 'Devon', - 'Cruz', - 'Rylan', - 'Clinton', - 'Jonathon', - 'Kaiden', - 'Kingston', - 'Kristopher', - 'Felipe', - 'Collin', - 'Alfonso', - 'Rodolfo', - 'King', - 'Everett', - 'Chance', - 'Johnnie', - 'Clyde', - 'Weston', - 'Karl', - 'Camden', - 'Maddox', - 'Bryant', - 'Gage', - 'Dwayne', - 'Shannon', - 'Gilberto', - 'Braden', - 'Lewis', - 'Greyson', - 'Rudolph', - 'Floyd', - 'Jayce', - 'Harrison', - 'Brayan', - 'Cayden', - 'Reginald', - 'Jaiden', - 'Brantley', - 'Hyman', - 'Perry', - 'Kent', - 'Alvin', - 'Cade', - 'Doug', - 'Romeo', - 'Jax', - 'Silas', - 'Ty', - 'Emmett', - 'Jackie', - 'Leslie', - 'Vernon', - 'Jessie', - 'Lloyd', - 'Cecil', - 'Roland', - 'Ted', - 'Amir', - 'Cash', - 'Gregg', - 'Uriel', - 'Donnie', - 'Noel', - 'Mauricio', - 'Dana', - 'Osvaldo', - 'Sawyer', - 'Rogelio', - 'Terrence', - 'Conner', - 'Darius', - 'Chaim', - 'Maurice', - 'Male', - 'Malachi', - 'Issac', - 'Ramiro', - 'Zane', - 'Jaylen', - 'Dawson', - 'Willard', - 'Randolph', - 'Wilbur', - 'Noe', - 'Huey', - 'Sammy', - 'Lonnie', - 'Morton', - 'Chandler', - 'Elliot', - 'Geoffrey', - 'Robin', - 'Muhammad', - 'Wallace', - 'Matt', - 'Drew', - 'Bailey', - 'Orlando', - 'Jasper', - 'Tyrese', - 'Matteo', - 'Leonel', - 'Simon', - 'Braylon', - 'Corbin', - 'Jayceon', - 'Gunner', - 'Dante', - 'Daryl', - 'Bennett', - 'Ulises', - 'Efrain', - 'Drake', - 'Rolando', - 'Lukas', - 'Arian', - 'Trenton', - 'Humberto', - 'Ryker', - 'Aldo', - 'Landen', - 'Xander', - 'Dwight', - 'Alvaro', - 'Sheldon', - 'Freddie', - 'Vicente', - 'Avery', - 'Marty', - 'Irvin', - 'Ariel', - 'Lane', - 'Nestor', - 'Chuck', - 'Dominique', - 'Baby', - 'Kerry', - 'Enzo', - 'Nick', - 'Yosef', - 'Edmund', - 'Oswaldo', - 'Kobe', - 'Aden', - 'Clair', - 'Freddy', - 'Karter', - 'Stacy', - 'Byron', - 'Roosevelt', - 'Claude', - 'Marion', - 'Thiago', - 'Colt', - 'Sol', - 'Lamont', - 'Neal', - 'August', - 'Cason', - 'Kason', - 'Reynaldo', - 'Malcolm', - 'Beau', - 'Ignacio', - 'Kareem', - 'Laurence', - 'Finn', - 'Domingo', - 'Rigoberto', - 'Solomon', - 'Aaden', - 'Case', - 'Horace', - 'Griffin', - 'Rocco', - 'Pete', - 'Ross', - 'Skyler', - 'Kenny', - 'Tucker', - 'Morgan', - 'Forrest', - 'Timmy', - 'Clint', - 'Garry', - 'Elwood', - 'Knox', - 'Elian', - 'Zion', - 'Trey', - 'Vito', - 'Jamel', - 'Junior', - 'Roderick', - 'Brooks', - 'Isidore', - 'Kelvin', - 'Ali', - 'Octavio', - 'Luther', - 'Milo', - 'Jett', - 'Unknown', - 'Milan', - 'Nickolas', - 'German', - 'Terence', - 'Virgil', - 'Conor', - 'Isaias', - 'Cristopher', - 'Jayson', - 'Brenden', - 'Joey', - 'Tevin', - 'Branden', - 'Arjun', - 'Carmine', - 'Wendell', - 'Judah', - 'Nikolas', - 'Izaiah', - 'Dick', - 'Jairo', - 'Giovani', - 'Ervin', - 'Graham', - 'Trent', - 'Tyson', - 'Cedric', - 'Elliott', - 'Myles', - 'Kameron', - 'Jaylon', - 'Hubert', - 'Grady', - 'Homer', - 'Quinn', - 'Payton', - 'Bennie', - 'River', - 'Dexter', - 'Emil', - 'Jamal', - 'Orion', - 'Alonzo', - 'Paxton', - 'Ashley', - 'Desmond', - 'Waylon', - 'Patsy', - 'Agustin', - 'Shimon', - 'Jarrod', - 'Rex', - 'Pat', - 'Rhett', - 'Benny', - 'Adriel', - 'Moses', - 'Daquan', - 'Johan', - 'Adolfo', - 'Otis', - 'Kadeem', - 'Jody', - 'Wilson', - 'Pasquale', - 'Kendrick', - 'Alonso', - 'Ben', - 'Ezequiel', - 'Jair', - 'Tomas', - 'Zackary', - 'Dane', - 'Nasir', - 'Alton', - 'Tristen', - 'Wilfredo', - 'Lyle', - 'Rowan', - 'Deandre', - 'Mordechai', - 'Mohamed', - 'Khalil', - 'Maximilian', - 'Devante', - 'Wade', - 'Norbert', - 'Yehuda', - 'Dallas', - 'Menachem', - 'Anderson', - 'Jonas', - 'Zachery', - 'Zaiden', - 'Giovanny', - 'Clifton', - 'Tommie', - 'Ronaldo', - 'Major', - 'Barrett', - 'Darnell', - 'Keegan', - 'Randal', - 'Aarav', - 'Burton', - 'Terrance', - 'Reid', - 'Fredrick', - 'Bobbie', - 'Ace', - 'Kyler', - 'Yoel', - 'Earnest', - 'Toby', - 'Merle', - 'Archer', - 'Santos', - 'Nico', - 'Beckett', - 'Yisroel', - 'Nehemiah', - 'Lynn', - 'Holden', - 'Matias', - 'Rufus', - 'Mohammed', - 'Hayes', - 'Marshall', - 'Trinidad', - 'Valentin', - 'Heath', - 'Weldon', - 'Ed', - 'Lionel', - 'Jaret', - 'Aron', - 'Bernardo', - 'Zander', - 'Devonte', - 'Meyer', - 'Ulysses', - 'Myron', - 'Lowell', - 'Linwood', - 'Rocky', - 'Phoenix', - 'Antoine', - 'Cyrus', - 'Demarcus', - 'Bruno', - 'Titus', - 'Madison', - 'Jarod', - 'Caiden', - 'Kash', - 'Jarvis', - 'Clay', - 'Notnamed', - 'Doyle', - 'Dallin', - 'Atticus', - 'Orville', - 'Nixon', - 'Loren', - 'Wilbert', - 'Karson', - 'Brennan', - 'Brittany', - 'Marlon', - 'Gonzalo', - 'Carlton', - 'Cary', - 'Marquis', - 'Amari', - 'Rohan', - 'Terrell', - 'Gianni', - 'Johnathon', - 'Jan', - 'Boston', - 'Ibrahim', - 'Yitzchok', - 'Jean', - 'Camron', - 'Ronny', - 'Porter', - 'Adonis', - 'Alessandro', - 'Stefan', - 'Giancarlo', - 'Clark', - 'Lupe', - 'Edgardo', - 'Scotty', - 'Messiah', - 'Benito', - 'Zachariah', - 'Kristian', - 'Bodhi', - 'Ronan', - 'Emerson', - 'Wilfred', - 'Heriberto', - 'Davis', - 'Stewart', - 'Efren', - 'Brock', - 'Christophe', - 'Sammie', - 'Kade', - 'Denis', - 'Ernie', - 'Kayson', - 'Quincy', - 'Abe', - 'Estevan', - 'Jamari', - 'Mohammad', - 'Kendall', - 'Demetrius', - 'Walker', - 'Shlomo', - 'Louie', - 'Kody', - 'Valentino', - 'Jaheim', - 'Vince', - 'Frankie', - 'Aubrey', - 'Quinton', - 'Royce', - 'Ari', - 'Abram', - 'Jessica', - 'Curt', - 'Bart', - 'Daren', - 'Braylen', - 'Alexandro', - 'Lamar', - 'Kasen', - 'Willis', - 'Vihaan', - 'Delbert', - 'Triston', - 'Yakov', - 'Courtney', - 'Niko', - 'Pierre', - 'Jaquan', - 'Braulio', - 'Santino', - 'Quentin', - 'Dario', - 'Dusty', - 'Neymar', - 'Bridger', - 'Tyrell', - 'Bertram', - 'Raymundo', - 'Isiah', - 'Reed', - 'Archie', - 'Prince', - 'Rory', - 'Davon', - 'Stacey', - 'Bradford', - 'Nikolai', - 'Kian', - 'Kase', - 'Casen', - 'Dion', - 'Isai', - 'Armand', - 'Percy', - 'Emily', - 'Leland', - 'Sterling', - 'Yandel', - 'Olin', - 'Sanford', - 'Marlin', - 'Denzel', - 'Mekhi', - 'Elbert', - 'Braydon', - 'Dewey', - 'Dudley', - 'Shmuel', - 'Jadon', - 'Braeden', - 'Yair', - 'Rob', - 'Mickey', - 'Monty', - 'Hannah', - 'Luciano', - 'Remington', - 'Akeem', - 'Julien', - 'Carmen', - 'Jensen', - 'Johnie', - 'Mack', - 'Rickie', - 'Javon', - 'Misael', - 'Elvis', - 'Eden', - 'Jess', - 'Phil', - 'Malakai', - 'Melvyn', - 'Rod', - 'Arnulfo', - 'Cohen', - 'Fidel', - 'Levar', - 'Dominik', - 'Grover', - 'Yaakov', - 'Landyn', - 'Colten', - 'Dorian', - 'Keaton', - 'Loyd', - 'Brodie', - 'Otto', - 'Eliezer', - 'Ahmed', - 'Shelby', - 'Hernan', - 'Odin', - 'Regis', - 'Jaydon', - 'Uriah', - 'Remy', - 'Tariq', - 'Sonny', - 'Carroll', - 'Xavi', - 'Christia', - 'Marcel', - 'Brendon', - 'Kellan', - 'Bowen', - 'Unnamed', - 'Scottie', - 'Justice', - 'Kurtis', - 'Stephan', - 'Daxton', - 'Coby', - 'Jadiel', - 'Dashawn', - 'Amare', - 'Cannon', - 'Blaine', - 'Tate', - 'Talmadge', - 'Nathanael', - 'Adolph', - 'Talan', - 'Tobias', - 'Sylvester', - 'Tadeo', - 'Darrel', - 'Winston', - 'Garland', - 'Meir', - 'Kory', - 'Joseluis', - 'Wilburn', - 'Rusty', - 'Avraham', - 'Ayaan', - 'Theo', - 'Mathias', - 'Marcelo', - 'Dino', - 'Kolby', - 'Cael', - 'Tzvi', - 'Davion', - 'Aryan', - 'Rhys', - 'Cain', - 'Duke', - 'Pierce', - 'Landry', - 'Tristin', - 'Emma', - 'Zackery', - 'Antone', - 'Rayan', - 'Hendrix', - 'Lucca', - 'Luka', - 'Jarrett', - 'Miguelangel', - 'Rodger', - 'Kevon', - 'Jacoby', - 'Damion', - 'Maximo', - 'Robbie', - 'Jovanny', - 'Trace', - 'Gunnar', - 'Kieran', - 'Cristobal', - 'Kris', - 'Ellis', - 'Matthias', - 'Eloy', - 'Sarah', - 'Donny', - 'Donte', - 'Ronin', - 'Reece', - 'Alijah', - 'Zayne', - 'Jamarion', - 'Laverne', - 'Gregorio', - 'Kellen', - 'Nathen', - 'Gideon', - 'Rosario', - 'Erwin', - 'Jakub', - 'Normand', - 'Rey', - 'Trevon', - 'Stetson', - 'Carmelo', - 'Rashad', - 'Tod', - 'Elizabeth', - 'Harley', - 'Darian', - 'Scot', - 'Tavon', - 'Keven', - 'Merlin', - 'Nash', - 'Deangelo', - 'Raiden', - 'Jahir', - 'Isidro', - 'Davian', - 'Raekwon', - 'Alphonse', - 'Reese', - 'Abigail', - 'Deshawn', - 'Ahmad', - 'Conrad', - 'Truman', - 'Kolton', - 'Ryland', - 'Jamaal', - 'Abdiel', - 'Aditya', - 'Keenan', - 'Brycen', - 'Thaddeus', - 'Austen', - 'Leonidas', - 'Raphael', - 'Jovani', - 'Brenton', - 'Jasmine', - 'Thurman', - 'Russel', - 'Emory', - 'Cornelius', - 'Roel', - 'Xzavier', - 'Jovanni', - 'Zev', - 'Eldon', - 'Deven', - 'Kamden', - 'Eliseo', - 'Franco', - 'Duncan', - 'Anton', - 'Amarion', - 'Deron', - 'Sage', - 'Babyboy', - 'Fredy', - 'Russ', - 'Omarion', - 'Ryne', - 'Jovany', - 'Camilo', - 'Stan', - 'Cullen', - 'Armani', - 'Adrien', - 'Royal', - 'Kane', - 'Ishaan', - 'Spenser', - 'Antwan', - 'Stephon', - 'Juanpablo', - 'Tiffany', - 'Garret', - 'Jagger', - 'Will', - 'Nigel', - 'Chadwick', - 'Casimir', - 'Abdirahman', - 'Odell', - 'Keanu', - 'Josh', - 'Mortimer', - 'Raheem', - 'Jordon', - 'Nery', - 'Monte', - 'Jaxton', - 'Deacon', - 'Reuben', - 'Carlo', - 'Skylar', - 'Jamarcus', - 'Robby', - 'Jaycob', - 'Kristofer', - 'Buddy', - 'Korbin', - 'Arlo', - 'Jennifer', - 'Rodrick', - 'Juwan', - 'Latrell', - 'Chaz', - 'Lawson', - 'Mendel', - 'Jordy', - 'Dirk', - 'Finnegan', - 'Eason', - 'Atlas', - 'Eddy', - 'Mitch', - 'Reagan', - 'Clement', - 'Jamar', - 'Kamari', - 'Jarred', - 'Lauren', - 'Roscoe', - 'Jefferson', - 'Devan', - 'Elton', - 'Cortez', - 'Leandro', - 'Finley', - 'Cordero', - 'Dov', - 'Eliyahu', - 'Princeton', - 'Avrohom', - 'Hassan', - 'Dangelo', - 'Shamar', - 'Gino', - 'Yusuf', - 'Jaylin', - 'Martez', - 'Shad', - 'Keyshawn', - 'Nikhil', - 'Yael', - 'Harlan', - 'Jeffry', - 'Frederic', - 'Derick', - 'Dondre', - 'Vance', - 'Markus', - 'London', - 'Arman', - 'Marley', - 'Van', - 'Jaeden', - 'Krish', - 'Benson', - 'Marquise', - 'Cristofer', - 'Dewayne', - 'Gannon', - 'Genaro', - 'Crew', - 'Rashawn', - 'Rayden', - 'Raylan', - 'Jaxen', - 'Fredric', - 'Beckham', - 'Tripp', - 'Mckay', - 'Deonte', - 'Johann', - 'Johnpaul', - 'Santo', - 'Hakeem', - 'Federico', - 'Bert', - 'Flynn', - 'Edison', - 'Enoch', - 'Shulem', - 'Jovan', - 'Art', - 'Isadore', - 'Hal', - 'Cristiano', - 'Urijah', - 'Dilan', - 'Benicio', - 'Kingsley', - 'Aydan', - 'Syed', - 'Nicole', - 'Rachel', - 'Tyree', - 'Maximillian', - 'Branson', - 'Davin', - 'Layton', - 'Joan', - 'Darien', - 'Deion', - 'Augustus', - 'Dariel', - 'Oziel', - 'Juancarlos', - 'Pranav', - 'Danielle', - 'Rubin', - 'Jerald', - 'Wilmer', - 'Deegan', - 'Teddy', - 'Mariano', - 'Nathanie', - 'Stevie', - 'Dorsey', - 'Maxim', - 'Jaron', - 'Coty', - 'Damarion', - 'Semaj', - 'Maria', - 'Jamison', - 'Domenick', - 'Emile', - 'Armaan', - 'Arnav', - 'Mackenzie', - 'Everardo', - 'Aurelio', - 'Cayson', - 'Edwardo', - 'Charley', - 'Geovanni', - 'Vincenzo', - 'Yadiel', - 'Francesco', - 'Koby', - 'Joziah', - 'Jasiah', - 'Makai', - 'Long', - 'Cassius', - 'Omari', - 'Ferdinand', - 'Samir', - 'Cleveland', - 'Olivia', - 'Lanny', - 'Sincere', - 'Hyrum', - 'Christina', - 'Lucian', - 'Margarito', - 'Osiel', - 'Kinsler', - 'Sydney', - 'Slade', - 'Lazaro', - 'Sal', - 'Lipa', - 'Hobert', - 'Coy', - 'Elroy', - 'Tatum', - 'Katherine', - 'Chloe', - 'Kyrie', - 'Amanda', - 'Buford', - 'Kymani', - 'Kacper', - 'Elmo', - 'Alphonso', - 'Ramses', - 'Homero', - 'Sherman', - 'Reinaldo', - 'Yechiel', - 'Jonatan', - 'Mychal', - 'Gustave', - 'Paris', - 'Zain', - 'Markanthony', - 'Dimitri', - 'Mamadou', - 'Apollo', - 'Bronson', - 'Hamza', - 'Samson', - 'Madden', - 'Tylor', - 'Jacquez', - 'Garth', - 'Giuseppe', - 'Stephanie', - 'Darion', - 'Yurem', - 'Antony', - 'Rico', - 'Rich', - 'Dontavious', - 'Erin', - 'Kannon', - 'Isaak', - 'Dovid', - 'Coleman', - 'Monroe', - 'Bryon', - 'Asa', - 'Patricio', - 'Arnoldo', - 'Alexandra', - 'Jessy', - 'Jules', - 'Alexzander', - 'Jerrod', - 'Talon', - 'Elvin', - 'Chace', - 'Amos', - 'Galen', - 'Kenji', - 'Rahul', - 'Delmar', - 'Nakia', - 'Abdullah', - 'Deon', - 'Brice', - 'Osbaldo', - 'Favian', - 'Mauro', - 'Tristian', - 'Leopoldo', - 'Hans', - 'Hank', - 'Tou', - 'Demond', - 'Jemal', - 'Ladarius', - 'Kylan', - 'Braiden', - 'Darwin', - 'Kamron', - 'Millard', - 'Dax', - 'Shaquan', - 'Aloysius', - 'Tyshawn', - 'Westley', - 'Marquez', - 'Shayne', - 'Kasey', - 'Usher', - 'Ares', - 'Killian', - 'Maynard', - 'Jeshua', - 'Vaughn', - 'Shia', - 'Naftali', - 'Zaire', - 'Taj', - 'Edmond', - 'Zechariah', - 'Ollie', - 'Hoyt', - 'Donnell', - 'Soren', - 'Isac', - 'Tyquan', - 'Legend', - 'Devyn', - 'Shon', - 'Gerry', - 'Ellsworth', - 'Naftuli', - 'Johnson', - 'Haywood', - 'Aydin', - 'Junius', - 'Wiley', - 'Lennox', - 'Siddharth', - 'Odis', - 'Zaid', - 'Lacy', - 'Hussein', - 'Nicklas', - 'Callen', - 'Izayah', - 'Jaziel', - 'Claud', - 'Horacio', - 'Cyril', - 'Jariel', - 'Shemar', - 'Rebecca', - 'Reyes', - 'Denny', - 'Dereck', - 'Marcelino', - 'Najee', - 'Mac', - 'Hollis', - 'Korey', - 'Addison', - 'Jordi', - 'Eleazar', - 'Lisandro', - 'Dayton', - 'Ammon', - 'Reymundo', - 'Erich', - 'Tenzin', - 'Mitchel', - 'Kristoffer', - 'Jerrold', - 'Kristoph', - 'Refugio', - 'Erasmo', - 'Samantha', - 'Simcha', - 'Abdullahi', - 'Booker', - 'Quadir', - 'Kyson', - 'Hoover', - 'Gus', - 'Azael', - 'Mervin', - 'Yoshio', - 'Jorje', - 'Jesiah', - 'Shirley', - 'Brigham', - 'Memphis', - 'Reyansh', - 'Flavio', - 'Lavern', - 'Rosendo', - 'Dantrell', - 'Devonta', - 'Forest', - 'Alden', - 'Lyndon', - 'Luiz', - 'Elisha', - 'Al', - 'Bentlee', - 'Eriberto', - 'Marques', - 'Alexandre', - 'Fidencio', - 'Jabari', - 'Arsenio', - 'Kaysen', - 'Ethen', - 'Cleo', - 'Blaze', - 'Aryeh', - 'Dequan', - 'Denver', - 'Luc', - 'Delmas', - 'Javion', - 'Gauge', - 'Martell', - 'Ever', - 'Gavyn', - 'Aldair', - 'Okey', - 'Carey', - 'Geovanny', - 'Kalel', - 'Layne', - 'Hiroshi', - 'Ayan', - 'Akiva', - 'Clare', - 'Sigmund', - 'Furman', - 'Claudio', - 'Garrison', - 'Draven', - 'Aidyn', - 'Vern', - 'Andreas', - 'Kwame', - 'Imanol', - 'Jorden', - 'Glynn', - 'Adalberto', - 'Varun', - 'Dashiell', - 'Baron', - 'Jasen', - 'Child', - 'Earle', - 'Izaac', - 'Vivaan', - 'Koa', - 'Lennon', - 'Marcoantonio', - 'Gaetano', - 'Sumner', - 'Barney', - 'Demarion', - 'Abner', - 'Delonte', - 'Val', - 'Jacky', - 'Demario', - 'Zavier', - 'Kale', - 'Wilton', - 'Jordyn', - 'Tatsuo', - 'Boyd', - 'Zayn', - 'Darron', - 'Moe', - 'Dillan', - 'Naquan', - 'Ned', - 'Kaylee', - 'Kelton', - 'Sahil', - 'Kermit', - 'Abelardo', - 'Sullivan', - 'Crosby', - 'Hagen', - 'Tyreek', - 'Jaquez', - 'Andrea', - 'Kyan', - 'Jeremias', - 'Tracey', - 'Ward', - 'Brixton', - 'Seamus', - 'Cedrick', - 'Enrico', - 'Emmitt', - 'Ford', - 'Travon', - 'Felton', - 'Blair', - 'Rio', - 'Dandre', - 'Kaeden', - 'Tiger', - 'Orval', - 'Castiel', - 'Yousef', - 'Anson', - 'Callan', - 'Jamey', - 'Darrius', - 'Tre', - 'Michel', - 'Mcarthur', - 'Rasheed', - 'Jamir', - 'Herschel', - 'Anibal', - 'Kinnick', - 'Hilario', - 'Shea', - 'Jencarlos', - 'Darrick', - 'Rishi', - 'Shaya', - 'Haden', - 'Ean', - 'Jaylan', - 'Rolland', - 'Leobardo', - 'Fermin', - 'Keon', - 'Lucio', - 'Keagan', - 'Savion', - 'Masao', - 'Damari', - 'Aarush', - 'Nunzio', - 'Anakin', - 'Mayson', - 'Westin', - 'Norberto', - 'Tavares', - 'Gorge', - 'Tavaris', - 'Joesph', - 'Sylas', - 'Huy', - 'Gerson', - 'Augustine', - 'Buster', - 'Jelani', - 'Haley', - 'Filip', - 'Shmiel', - 'Lucius', - 'Rojelio', - 'Gale', - 'Quintin', - 'Channing', - 'Brayton', - 'Keshawn', - 'Osmar', - 'Otha', - 'Eder', - 'Mary', - 'Eusebio', - 'Matheus', - 'Randell', - 'Brennen', - 'Trae', - 'Paolo', - 'Caesar', - 'Estill', - 'Camren', - 'Dhruv', - 'Cutter', - 'Rayyan', - 'Jeramiah', - 'Anish', - 'Donavan', - 'Sunny', - 'Hershel', - 'Salvator', - 'Jedidiah', - 'Romario', - 'Hershy', - 'Anders', - 'Trevion', - 'Murphy', - 'Kanye', - 'Jionni', - 'Bradyn', - 'Cordell', - 'Alek', - 'Luisangel', - 'Norris', - 'Nevin', - 'Jaleel', - 'Lenny', - 'Judson', - 'Tayshaun', - 'Aedan', - 'Rhyder', - 'Domenic', - 'Santana', - 'Rahsaan', - 'Sebastien', - 'Corban', - 'Rowdy', - 'Kiyoshi', - 'Armen', - 'Efraim', - 'Vladimir', - 'Callum', - 'Abdul', - 'Gianluca', - 'Mayer', - 'Mustafa', - 'Demarco', - 'Neyland', - 'Vidal', - 'Marshawn', - 'Rudolfo', - 'Nazir', - 'Azariah', - 'Shoji', - 'Worth', - 'Levern', - 'Jai', - 'Antione', - 'Dickie', - 'Yehoshua', - 'Cliff', - 'Kaison', - 'Kye', - 'Jaren', - 'Emir', - 'Henrik', - 'Maxx', - 'Kainoa', - 'Athan', - 'Cletus', - 'Jasir', - 'Dejon', - 'Jadyn', - 'Houston', - 'Kadin', - 'Erubiel', - 'Hadi', - 'Jaydin', - 'Brianna', - 'Alyssa', - 'Marcello', - 'Omer', - 'Ikaika', - 'Ramel', - 'Arron', - 'Bently', - 'Daron', - 'Avi', - 'Jerod', - 'Shelton', - 'Winfred', - 'Mendy', - 'Ryu', - 'Nikko', - 'Arley', - 'Kamdyn', - 'Bo', - 'Erica', - 'Faustino', - 'Fletcher', - 'Dionte', - 'Boyce', - 'Kennedy', - 'Reyli', - 'Paulo', - 'Baruch', - 'Bernie', - 'Mohamad', - 'Kahlil', - 'Kong', - 'Baldemar', - 'Murry', - 'Rogers', - 'Sandy', - 'Bodie', - 'Ivory', - 'Youssef', - 'Kee', - 'Jahiem', - 'Isabella', - 'Keoni', - 'Michelle', - 'Luigi', - 'Marcanthony', - 'Jericho', - 'Achilles', - 'Everette', - 'Americo', - 'Edson', - 'Hiram', - 'Jeramy', - 'Metro', - 'Davi', - 'Hezekiah', - 'Harper', - 'Kiel', - 'Brandan', - 'Said', - 'Noam', - 'Tarik', - 'Raquan', - 'Zeb', - 'Broderick', - 'Arath', - 'Emery', - 'Kip', - 'Tymir', - 'Garrick', - 'Anfernee', - 'Khalid', - 'Jamil', - 'Demian', - 'Amador', - 'Oran', - 'Franklyn', - 'Porfirio', - 'Delano', - 'Justyn', - 'Aharon', - 'Karol', - 'Alva', - 'Nicky', - 'Zack', - 'Jerimiah', - 'Josef', - 'Errol', - 'Hideo', - 'Tahj', - 'Ilan', - 'Kennith', - 'Nathanial', - 'Kyron', - 'Merton', - 'Danial', - 'Tuan', - 'Hung', - 'Massimo', - 'Krew', - 'Arya', - 'Jedediah', - 'Nosson', - 'Jakobe', - 'Eitan', - 'Edmundo', - 'Olen', - 'Benedict', - 'Quintavious', - 'Shalom', - 'Akash', - 'Maxton', - 'Anna', - 'Julia', - 'Melissa', - 'Victoria', - 'Kekoa', - 'Konner', - 'Kirby', - 'Heyward', - 'Davonte', - 'Magnus', - 'Zeus', - 'Neel', - 'Franky', - 'Isael', - 'Gaylon', - 'Kole', - 'Axton', - 'Brando', - 'Mateusz', - 'Lucien', - 'Marquavious', - 'Lon', - 'Gian', - 'Savannah', - 'Trinity', - 'Harris', - 'Kamarion', - 'Aydenn', - 'Cale', - 'Neo', - 'Justus', - 'Mose', - 'Tiago', - 'Saverio', - 'Eligh', - 'Mikel', - 'Eliot', - 'Alvis', - 'Argenis', - 'Musa', - 'Lonny', - 'Thad', - 'Guido', - 'Ceasar', - 'Obed', - 'Pinchas', - 'Barton', - 'Durell', - 'Johnatha', - 'Aric', - 'Geovany', - 'Fransisco', - 'Jaheem', - 'Jarett', - 'Yeshua', - 'Karim', - 'Aayden', - 'Merrill', - 'Michele', - 'Jaydan', - 'Octavius', - 'Jermiah', - 'Alexavier', - 'Brandyn', - 'Arvid', - 'Brentley', - 'Sutton', - 'Coen', - 'Ameer', - 'Giovany', - 'Ishan', - 'Blaise', - 'Bayron', - 'Kamil', - 'Brooklyn', - 'Catherine', - 'Akira', - 'Briggs', - 'Damani', - 'Rasheen', - 'Rayford', - 'Moishe', - 'Ephraim', - 'Esequiel', - 'Kenyon', - 'Constantine', - 'Silvio', - 'Brain', - 'Daylon', - 'Raymon', - 'Ayush', - 'Lazer', - 'Telly', - 'Elan', - 'Stone', - 'Marland', - 'Donn', - 'Shamel', - 'Silvestre', - 'Zephyr', - 'Merrick', - 'Fausto', - 'Dedrick', - 'Cornell', - 'Whitney', - 'Derrell', - 'Mitsuo', - 'Lucious', - 'Tad', - 'Lyric', - 'Darrion', - 'Dannie', - 'Gayle', - 'Burl', - 'Jayquan', - 'Carrol', - 'Laquan', - 'Tyrek', - 'Natividad', - 'Casimer', - 'Jael', - 'Aven', - 'Arnaldo', - 'Yovani', - 'Laura', - 'Dejuan', - 'Dimitrios', - 'Yash', - 'Esai', - 'Zavion', - 'Ora', - 'Durward', - 'Bradly', - 'Hazel', - 'Che', - 'Richie', - 'Diana', - 'Alois', - 'Lynwood', - 'Luverne', - 'Zeke', - 'Dash', - 'Cairo', - 'Delvin', - 'Kawika', - 'Josemanuel', - 'Devean', - 'Sameer', - 'Seneca', - 'Presley', - 'Jed', - 'Malaki', - 'Dominque', - 'Dontae', - 'Dev', - 'Darey', - 'Reggie', - 'Izaak', - 'Manny', - 'Jere', - 'Minh', - 'Ryden', - 'Montana', - 'Kaleo', - 'Jacorey', - 'Ignatius', - 'Filiberto', - 'Cache', - 'Yitzchak', - 'Yaseen', - 'Kentrell', - 'Basil', - 'Ivy', - 'Migel', - 'Jalon', - 'Lenwood', - 'Ellwood', - 'Zakary', - 'Haiden', - 'Dontrell', - 'Braedon', - 'Lorne', - 'Trever', - 'Mikael', - 'Kenzo', - 'Javaris', - 'Ambrose', - 'Alain', - 'Columbus', - 'Leif', - 'Jerold', - 'Anwar', - 'Gabino', - 'Dillion', - 'Kelby', - 'Denzil', - 'Ulisses', - 'Sami', - 'Jahmir', - 'Elimelech', - 'Dock', - 'Zahir', - 'Hardy', - 'Florian', - 'Jewel', - 'Tobin', - 'Curley', - 'Mahdi', - 'Mccoy', - 'Jaquavious', - 'Justen', - 'Lino', - 'Teodoro', - 'Kazuo', - 'Lenard', - 'Robb', - 'Takashi', - 'Maison', - 'Merlyn', - 'Brecken', - 'Ricki', - 'Jet', - 'Lars', - 'Ulices', - 'Dereon', - 'Fox', - 'Ajay', - 'Geraldo', - 'Maksim', - 'Jullian', - 'Kalani', - 'Andrei', - 'Jaidyn', - 'Maxie', - 'Javen', - 'Gail', - 'Ely', - 'Caroline', - 'Amber', - 'Crystal', - 'Kiara', - 'Megan', - 'Reilly', - 'Eugenio', - 'Fisher', - 'Langston', - 'Gavriel', - 'Abhinav', - 'Dee', - 'Kace', - 'Axl', - 'Isabel', - 'Uziel', - 'Sabastian', - 'Rylee', - 'Eliazar', - 'Renato', - 'Harland', - 'Lavar', - 'Stefano', - 'Mayra', - 'Valentine', - 'Bud', - 'Hasan', - 'Zaden', - 'Truett', - 'Korbyn', - 'Toshio', - 'Stockton', - 'Edd', - 'Trystan', - 'Daylan', - 'Jayven', - 'Dewitt', - 'Kraig', - 'Wilford', - 'Celestino', - 'Jacobo', - 'Patryk', - 'Hailey', - 'Nainoa', - 'Haskell', - 'Sharif', - 'Jerad', - 'Raynaldo', - 'Jacques', - 'Jessi', - 'Geary', - 'Gaige', - 'Garnett', - 'Jakari', - 'Yonatan', - 'Eino', - 'Phong', - 'Jerel', - 'Benzion', - 'Quinten', - 'Amado', - 'Blas', - 'Kimberly', - 'Cuauhtemoc', - 'Aayan', - 'Catarino', - 'Jeromy', - 'Kyree', - 'Apolonio', - 'Boy', - 'Antwon', - 'Hakim', - 'Creed', - 'Shiloh', - 'Shepherd', - 'Garett', - 'Oakley', - 'Miller', - 'Dajuan', - 'Mattias', - 'Titan', - 'Immanuel', - 'Lamarcus', - 'Devontae', - 'Reef', - 'Brayson', - 'Grey', - 'Deante', - 'Yariel', - 'Makhi', - 'Jayse', - 'Corbyn', - 'Domenico', - 'Sedrick', - 'Deontae', - 'Kou', - 'Shant', - 'Willy', - 'Austyn', - 'Shloime', - 'Masen', - 'Linus', - 'Florentino', - 'Gionni', - 'Boden', - 'Torrey', - 'Minoru', - 'Daulton', - 'Kolten', - 'Jennings', - 'Noble', - 'Hersh', - 'Kelsey', - 'Nicholaus', - 'Florencio', - 'Nam', - 'Juelz', - 'Kainalu', - 'Destin', - 'Damarcus', - 'Jacolby', - 'Nikita', - 'Artis', - 'Bilal', - 'Kendell', - 'Alexsander', - 'Parth', - 'Esau', - 'Glennon', - 'Kohen', - 'Isacc', - 'Aleksander', - 'Vinh', - 'Trenten', - 'Koen', - 'Candelario', - 'Connie', - 'Aram', - 'Wolfgang', - 'Amit', - 'Om', - 'Shyheim', - 'Raven', - 'Kendra', - 'Eliel', - 'Viet', - 'Kenyatta', - 'Sky', - 'Binyomin', - 'Deanthony', - 'Lachlan', - 'Tory', - 'Kenton', - 'Tamir', - 'Kramer', - 'Deshaun', - 'Javian', - 'Haruo', - 'Rupert', - 'Jevon', - 'Shlome', - 'Danilo', - 'Vanessa', - 'Fernand', - 'Daveon', - 'Les', - 'Marko', - 'Delmer', - 'Marlyn', - 'Winfield', - 'Wes', - 'Rosevelt', - 'Rayshawn', - 'Tai', - 'Kalvin', - 'Jerardo', - 'Sarkis', - 'Bertrand', - 'Kaimana', - 'Kaitlyn', - 'Summer', - 'Veer', - 'Waymon', - 'Evin', - 'Andrey', - 'Iain', - 'Kimi', - 'Foster', - 'Servando', - 'Mychael', - 'Derik', - 'Ryon', - 'Rowen', - 'Mel', - 'Ibn', - 'Werner', - 'Jameel', - 'Avrum', - 'Nachman', - 'Jomar', - 'Rudolf', - 'Tyrique', - 'Rayburn', - 'Khalif', - 'Rondal', - 'Bijan', - 'Rohit', - 'Jeremie', - 'Kain', - 'Nicola', - 'Bode', - 'Brogan', - 'Trayvon', - 'Turner', - 'Dwain', - 'Konnor', - 'Lev', - 'Zayd', - 'Finnley', - 'Brantlee', - 'Deonta', - 'Demetrio', - 'Ajani', - 'Arther', - 'Bianca', - 'Takeo', - 'Harding', - 'Jareth', - 'Rigo', - 'Epifanio', - 'Nahum', - 'Carleton', - 'Cosmo', - 'Shigeru', - 'Josias', - 'Takeshi', - 'Jacobi', - 'Michal', - 'Dorris', - 'Treveon', - 'Jaxx', - 'Aren', - 'Tejas', - 'Beverly', - 'Geoff', - 'Maddux', - 'Camryn', - 'Burt', - 'Norwood', - 'Sholom', - 'Ahron', - 'Macario', - 'Carol', - 'Camdyn', - 'Gennaro', - 'Leeroy', - 'Pinchus', - 'Kaito', - 'Burnell', - 'Frantz', - 'Laron', - 'Clemente', - 'Chasen', - 'Neri', - 'Jerrell', - 'Kashawn', - 'Keola', - 'Alvan', - 'Amar', - 'Ubaldo', - 'Roque', - 'Zalmen', - 'Daylen', - 'Kadyn', - 'Gil', - 'Bernice', - 'Yosgart', - 'Shaan', - 'Yahel', - 'Elon', - 'Levon', - 'Kit', - 'Brodrick', - 'Gaven', - 'Kaidyn', - 'Ansel', - 'Jewell', - 'Mikhail', - 'Derian', - 'Elam', - 'Tye', - 'Leigh', - 'Wayde', - 'Rian', - 'Artemio', - 'Ibrahima', - 'Noa', - 'Autumn', - 'Kylie', - 'Pernell', - 'Britton', - 'Deondre', - 'Arlen', - 'Aman', - 'Kelley', - 'Eliud', - 'Dijon', - 'Imran', - 'Eulalio', - 'Juvenal', - 'Agapito', - 'Brant', - 'Nima', - 'Yisrael', - 'Yerik', - 'Ewan', - 'Lathan', - 'Adair', - 'Gentry', - 'Kyren', - 'Lian', - 'Tayshawn', - 'Alejandra', - 'Jeancarlos', - 'Keyon', - 'Jade', - 'Shayan', - 'June', - 'Christos', - 'Adrain', - 'Jarom', - 'Kathryn', - 'Thor', - 'Haven', - 'Duy', - 'Enmanuel', - 'Montavious', - 'Cortney', - 'Teagan', - 'Blayne', - 'Anselmo', - 'Leyton', - 'Jonny', - 'Braylin', - 'Albaro', - 'Pascual', - 'Gasper', - 'Waldo', - 'Tyreke', - 'Dylon', - 'Narciso', - 'Ebony', - 'Hilton', - 'Margaret', - 'Brighton', - 'Martavious', - 'Demetrios', - 'Kishan', - 'Ansh', - 'Treyton', - 'Albin', - 'Rashon', - 'Rony', - 'Krystian', - 'Amrom', - 'Korver', - 'Richardo', - 'Kayla', - 'Katelyn', - 'Milford', - 'Bishop', - 'Ottis', - 'Emmet', - 'Codey', - 'Ayub', - 'Isreal', - 'Karas', - 'Kendarius', - 'Isamu', - 'Kunta', - 'Jermey', - 'Arvin', - 'Kayleb', - 'Sione', - 'Taurean', - 'Tyron', - 'Mihir', - 'Rami', - 'Vincente', - 'Zayan', - 'Mahlon', - 'Clovis', - 'Kirt', - 'Dyllan', - 'Ramsey', - 'Jeramie', - 'Nikolaus', - 'Edsel', - 'Asael', - 'Andrik', - 'Lisa', - 'Sandro', - 'Desean', - 'Narek', - 'Kiran', - 'Elzie', - 'Jered', - 'Arlie', - 'Yahya', - 'Lizandro', - 'Rollin', - 'Khiry', - 'Yuvraj', - 'Jeancarlo', - 'Anay', - 'Freeman', - 'Stevan', - 'Keller', - 'Ledger', - 'Jasiel', - 'Jacinto', - 'Sherwin', - 'Beaux', - 'Campbell', - 'Sherwood', - 'Torrence', - 'Daryle', - 'Chevy', - 'Adiel', - 'Patricia', - 'Jameer', - 'Bilbo', - 'Jayvon', - 'Early', - 'Boruch', - 'Jadarius', - 'Alpha', - 'Amadou', - 'Reino', - 'Betty', - 'Moussa', - 'Wolf', - 'Jenna', - 'Grace', - 'Natalie', - 'Javonte', - 'Crawford', - 'Damir', - 'Mckinley', - 'Elden', - 'Jhon', - 'Lemuel', - 'Colston', - 'Donta', - 'Pearl', - 'Taquan', - 'Salman', - 'Palmer', - 'Muhammed', - 'Brennon', - 'Cashton', - 'Ysidro', - 'Salomon', - 'Ocean', - 'Anirudh', - 'Aksel', - 'Cal', - 'Ishmael', - 'Brenda', - 'Abran', - 'Rome', - 'Leighton', - 'Canyon', - 'Kael', - 'Amin', - 'Antoni', - 'Tiara', - 'Heather', - 'Christine', - 'Brittney', - 'Angela', - 'Johathan', - 'Cipriano', - 'Coltin', - 'Verne', - 'Darrien', - 'Eamon', - 'Oskar', - 'Mikah', - 'Matix', - 'Kooper', - 'Antonino', - 'Duwayne', - 'Dagoberto', - 'Kolt', - 'Sanjay', - 'Tayden', - 'Waverly', - 'Abrahan', - 'Diamond', - 'West', - 'Jefferey', - 'Shigeo', - 'Kabir', - 'Jamell', - 'Jaedyn', - 'Malcom', - 'Gadiel', - 'Manav', - 'Audie', - 'Hipolito', - 'Theron', - 'Codie', - 'General', - 'Lindy', - 'Carver', - 'Nat', - 'Jacari', - 'Khamari', - 'Wally', - 'Kay', - 'Anastacio', - 'Jaymes', - 'Skip', - 'Cheyne', - 'Dameon', - 'Geronimo', - 'Kevyn', - 'Toney', - 'Arden', - 'Dontavius', - 'Rasheem', - 'Geovani', - 'Gaspar', - 'Baltazar', - 'Bladimir', - 'Rashan', - 'Rulon', - 'Karan', - 'Jory', - 'Chet', - 'Abiel', - 'Lazarus', - 'Britt', - 'Rodriquez', - 'Akil', - 'Zuriel', - 'Rylen', - 'Aston', - 'Graysen', - 'Jaysen', - 'Hillel', - 'Alford', - 'Tyriq', - 'Cassidy', - 'Rahiem', - 'Juanmanuel', - 'Demetri', - 'Jayton', - 'Timoteo', - 'Infantof', - 'Braedyn', - 'Corde', - 'Bee', - 'Valente', - 'Gildardo', - 'Feliciano', - 'Dalvin', - 'Tadashi', - 'Claudie', - 'Teng', - 'Genesis', - 'Tayler', - 'Joeangel', - 'Teruo', - 'Tylan', - 'Markel', - 'Linda', - 'Taven', - 'Pierson', - 'Newton', - 'Keandre', - 'Jayvion', - 'Donavon', - 'Encarnacion', - 'Melton', - 'Ritchie', - 'Erika', - 'Edgard', - 'Christoper', - 'Rocio', - 'Alvie', - 'Josedejesus', - 'Dashaun', - 'Travion', - 'Johny', - 'Marcell', - 'Monique', - 'Caitlin', - 'Durwood', - 'Gustav', - 'Rosalio', - 'Farhan', - 'Benuel', - 'Lashawn', - 'Shakeem', - 'Ocie', - 'Yasir', - 'Szymon', - 'Aaryan', - 'Hansel', - 'Slater', - 'Samarth', - 'Kiyan', - 'Storm', - 'Ava', - 'Yassin', - 'Dayquan', - 'Sherrill', - 'Khari', - 'Anas', - 'Cheskel', - 'Kamryn', - 'Zyaire', - 'Cristo', - 'Christofer', - 'Akhil', - 'Shreyas', - 'Ryley', - 'Gibson', - 'Haziel', - 'Talen', - 'Bracken', - 'Dallen', - 'Rashard', - 'Rockwell', - 'Colie', - 'Del', - 'Jihad', - 'Simeon', - 'Jahmari', - 'Ashwin', - 'Shraga', - 'Cian', - 'Alistair', - 'Cartier', - 'Stoney', - 'Verlyn', - 'Kavon', - 'Konrad', - 'Conrado', - 'Colon', - 'Randel', - 'Christ', - 'Jeremey', - 'Raleigh', - 'Lauro', - 'Dionicio', - 'Kauan', - 'Piotr', - 'Cleon', - 'Malique', - 'Rand', - 'Fritz', - 'Cordaro', - 'Pietro', - 'Faris', - 'Ezio', - 'Atharv', - 'Karthik', - 'Jahsir', - 'Saleem', - 'Abdoulaye', - 'Jiovanni', - 'Ezrah', - 'Everest', - 'Bronx', - 'Kruz', - 'Viktor', - 'Yasiel', - 'Thatcher', - 'Michelangelo', - 'Alaric', - 'Oneal', - 'Sahib', - 'Osiris', - 'Teo', - 'Joseangel', - 'Nate', - 'Walton', - 'Yousif', - 'Ezzard', - 'Yamil', - 'Angus', - 'Jhonny', - 'Fabio', - 'Darold', - 'Junious', - 'Atreyu', - 'Beck', - 'Adriano', - 'Amani', - 'Trevin', - 'Rudra', - 'Parsa', - 'Breon', - 'Umar', - 'Taha', - 'Cormac', - 'Yossi', - 'Jaison', - 'Saad', - 'Shloimy', - 'Chesky', - 'Ayman', - 'Alicia', - 'Chadd', - 'Broc', - 'Cynthia', - 'Reynold', - 'Ismail', - 'Gaylord', - 'Saburo', - 'Kao', - 'Masato', - 'Alfonzo', - 'Joshue', - 'Earvin', - 'Patric', - 'Robinson', - 'Serjio', - 'Gavino', - 'Stanford', - 'Thanh', - 'Kamren', - 'Vikram', - 'Roan', - 'Jeronimo', - 'Zahid', - 'Anjel', - 'Jayro', - 'Skye', - 'Baylor', - 'Drayden', - 'Pheng', - 'Yeng', - 'Wilber', - 'Meng', - 'Arik', - 'Jamarius', - 'Avigdor', - 'Ladarrius', - 'Nicklaus', - 'Gatlin', - 'Boone', - 'Jacen', - 'Antonia', - 'Kyran', - 'Quintavius', - 'Estil', - 'Casimiro', - 'Prentice', - 'Jodie', - 'Rashaad', - 'Konstantinos', - 'Allison', - 'Sophia', - 'Makayla', - 'Lillian', - 'Zymir', - 'Canaan', - 'Delfino', - 'Benton', - 'Apolinar', - 'Winford', - 'Dayne', - 'Shivam', - 'Fredi', - 'Yves', - 'Jarrell', - 'Ignazio', - 'Gamaliel', - 'Young', - 'Kiefer', - 'Juanjose', - 'Rehan', - 'Kegan', - 'Davante', - 'Naim', - 'Lyman', - 'Erskine', - 'Toivo', - 'Darrian', - 'Jad', - 'Ender', - 'Remi', - 'Rishaan', - 'Shaurya', - 'Viaan', - 'Chelsea', - 'Molly', - 'Sara', - 'Leib', - 'Azriel', - 'Howell', - 'Briar', - 'Korben', - 'Manning', - 'Job', - 'Brandt', - 'Jaedon', - 'Ozzy', - 'Cordarius', - 'Lannie', - 'Stanton', - 'Radames', - 'Blease', - 'Zyon', - 'Chadrick', - 'Watson', - 'Kentavious', - 'Taurus', - 'Adin', - 'Jordin', - 'Bryden', - 'Susumu', - 'Tamotsu', - 'Yukio', - 'Granville', - 'Ashby', - 'Tristyn', - 'Devaughn', - 'Deric', - 'Cecilio', - 'Pershing', - 'Noboru', - 'Rashaun', - 'Masaichi', - 'Juventino', - 'Norton', - 'Serafin', - 'Windell', - 'Cris', - 'Curtiss', - 'Boris', - 'Elio', - 'Williams', - 'Trung', - 'Torao', - 'Karon', - 'Canon', - 'Tyrik', - 'Naythan', - 'Michaelangelo', - 'Kavin', - 'Akshay', - 'Broden', - 'Quran', - 'Rishabh', - 'Hilbert', - 'Abbas', - 'Damoni', - 'Dillard', - 'Tigran', - 'Romel', - 'Chip', - 'Aeden', - 'Deagan', - 'Treyson', - 'Brannon', - 'Tremaine', - 'Fay', - 'Bryton', - 'Lucky', - 'Izak', - 'Edan', - 'Casper', - 'Koda', - 'Saquan', - 'Alcide', - 'Quinlan', - 'Maddex', - 'Hoyle', - 'Sandra', - 'Joshuah', - 'Lindsay', - 'Donato', - 'Jancarlos', - 'Kalin', - 'Zigmund', - 'Kalen', - 'Jalil', - 'Bonifacio', - 'Gabrielle', - 'Destiny', - 'Cheyenne', - 'Ulyses', - 'Rueben', - 'Markell', - 'Jermel', - 'Corwin', - 'Justine', - 'Idris', - 'Pilar', - 'Torrance', - 'Raeford', - 'Olan', - 'Octavious', - 'Quantavious', - 'Modesto', - 'Kashton', - 'Librado', - 'Bonnie', - 'Lois', - 'Justo', - 'Mahmoud', - 'Divine', - 'Baylen', - 'Rakeem', - 'Diesel', - 'Kyng', - 'Daisy', - 'Armon', - 'Joseantonio', - 'Montel', - 'Gearld', - 'Cloyd', - 'Lindell', - 'Nile', - 'Kashif', - 'Johnmichael', - 'Aramis', - 'Leopold', - 'Kamal', - 'Jerrad', - 'Jadin', - 'Mykel', - 'Jahlil', - 'Cheng', - 'Ezriel', - 'Aria', - 'Dajon', - 'Holt', - 'Chauncey', - 'Karsen', - 'Stryker', - 'Olaf', - 'Reno', - 'Colter', - 'Schuyler', - 'Orvil', - 'Auden', - 'Eyan', - 'Tyce', - 'Barbara', - 'Zamir', - 'Alexi', - 'Braelyn', - 'Brook', - 'Marchello', - 'Tyrel', - 'Oracio', - 'Jalin', - 'Verlon', - 'Raj', - 'Lindsey', - 'Andon', - 'Devlin', - 'Brysen', - 'Harman', - 'Treyvon', - 'Foy', - 'Arash', - 'Cuong', - 'Torin', - 'Rommel', - 'Lorenza', - 'Vishal', - 'Kenya', - 'Heber', - 'Victoriano', - 'Shay', - 'Tremayne', - 'Natanael', - 'Zachry', - 'Eros', - 'Veronica', - 'Wayland', - 'Rayquan', - 'Ana', - 'Jaceon', - 'Yida', - 'Rahmel', - 'Alter', - 'Lamarion', - 'Tavion', - 'Javin', - 'Lawerence', - 'Alessio', - 'Kristen', - 'Jacqueline', - 'Oren', - 'Aahil', - 'Adyan', - 'Augustin', - 'Coleton', - 'Wilfrid', - 'Dezmond', - 'Keelan', - 'Ike', - 'Kanoa', - 'Kedrick', - 'Chue', - 'Danniel', - 'Jowell', - 'Micahel', - 'Yonathan', - 'Finnian', - 'Garfield', - 'Joao', - 'Ezell', - 'Masaru', - 'Yoshito', - 'Pasco', - 'Yechezkel', - 'Shloma', - 'Adnan', - 'Jaythan', - 'Laith', - 'Greysen', - 'Maddix', - 'Alfonse', - 'Ernst', - 'Hobart', - 'Tavin', - 'Dajour', - 'Cy', - 'Estel', - 'Osman', - 'Vedant', - 'Rolf', - 'Ova', - 'Colson', - 'Kelan', - 'Oumar', - 'Olivier', - 'Seichi', - 'Tayson', - 'Roshan', - 'Blane', - 'Baxter', - 'Vu', - 'Tam', - 'Pao', - 'Wardell', - 'Davonta', - 'Montrell', - 'Ravi', - 'Durrell', - 'Bastian', - 'Aj', - 'Ren', - 'Loki', - 'Kairo', - 'Rock', - 'Mylo', - 'Lavell', - 'Bjorn', - 'Arvil', - 'Reinhold', - 'Yesenia', - 'Carsen', - 'Zephaniah', - 'Renzo', - 'Willem', - 'Unique', - 'Elmore', - 'Kalob', - 'Payne', - 'Leeland', - 'Naseem', - 'Yusef', - 'Aboubacar', - 'Ioannis', - 'Bohdan', - 'Javien', - 'Jakobi', - 'Dempsey', - 'Xavian', - 'Antavious', - 'Jc', - 'Dara', - 'Obie', - 'Celso', - 'Tyrin', - 'Eian', - 'Elgin', - 'Jaylyn', - 'Brandin', - 'Adyn', - 'Gabriela', - 'Jaidon', - 'Zavian', - 'Lonzo', - 'Elwin', - 'Tsutomu', - 'Jeanluc', - 'Caeden', - 'Auston', - 'Jasson', - 'Omid', - 'Gray', - 'Vang', - 'Nancy', - 'Nader', - 'Kylen', - 'Jarell', - 'Prentiss', - 'Tahir', - 'Ahmir', - 'Terell', - 'Ludwig', - 'Biagio', - 'Douglass', - 'Nafis', - 'Harlem', - 'Phineas', - 'Lochlan', - 'Hermon', - 'Wilder', - 'Aniello', - 'Attilio', - 'Shiv', - 'Montgomery', - 'Bowie', - 'Aries', - 'Itzae', - 'Isa', - 'Huxley', - 'Elwyn', - 'Advik', - 'Mahamadou', - 'Grayden', - 'Landin', - 'Decker', - 'Dakotah', - 'Ella', - 'Md', - 'Shayaan', - 'Isidor', - 'Joahan', - 'Tillman', - 'Jafet', - 'Panagiotis', - 'Jajuan', - 'Cristhian', - 'Demetric', - 'Zaylen', - 'Kacen', - 'Sloan', - 'Shedrick', - 'Denilson', - 'Buck', - 'Dyland', - 'Aris', - 'Demonte', - 'Telvin', - 'Raynard', - 'Quantavius', - 'Neftali', - 'Alma', - 'Kadarius', - 'Philippe', - 'Laurel', - 'Vadhir', - 'Juandiego', - 'Alekzander', - 'Napoleon', - 'Fabrizio', - 'Abisai', - 'Yasin', - 'Kamran', - 'Ole', - 'Nicolai', - 'Erling', - 'Jathan', - 'Zen', - 'Shiven', - 'Keshaun', - 'Nikola', - 'Loy', - 'Usman', - 'Concepcion', - 'Verlin', - 'Dedric', - 'Derwin', - 'Graig', - 'Serge', - 'Merritt', - 'Kervin', - 'Maleek', - 'Baldomero', - 'Germaine', - 'Hampton', - 'Shan', - 'Alvino', - 'Davy', - 'Arlington', - 'Brandy', - 'Timmie', - 'Andrae', - 'Terrion', - 'Quang', - 'Jeb', - 'Clem', - 'Judd', - 'Severo', - 'Woody', - 'Toan', - 'Alonza', - 'Gardner', - 'Delton', - 'Vinny', - 'Vilas', - 'Welton', - 'Sabian', - 'Dell', - 'Randolf', - 'Tyren', - 'Glenwood', - 'Antwain', - 'Savon', - 'Lesley', - 'Rashid', - 'Tavian', - 'Marvens', - 'Aleksandr', - 'Vivek', - 'Maximino', - 'Pavel', - 'Renee', - 'Charly', - 'Donell', - 'Shariff', - 'Ennis', - 'Menashe', - 'Ygnacio', - 'Hoke', - 'Lebron', - 'Hillard', - 'Xavion', - 'Nicolaus', - 'Kemari', - 'Sammuel', - 'Jessiah', - 'Virgle', - 'Niklas', - 'Allante', - 'Keenen', - 'Albino', - 'Rivaldo', - 'Jospeh', - 'Broadus', - 'Trequan', - 'Finis', - 'Sabas', - 'Abdoul', - 'Tyronne', - 'Tyreik', - 'Tyriek', - 'Linton', - 'Jashawn', - 'Ivey', - 'Janiel', - 'Jayme', - 'Lamarr', - 'Tiernan', - 'Meilech', - 'Fitzgerald', - 'Jonnathan', - 'Tashawn', - 'Verl', - 'Nichoals', - 'Urban', - 'Marquan', - 'Montez', - 'Akshaj', - 'Syrus', - 'Nehemias', - 'Nova', - 'Makaio', - 'Joselito', - 'Armin', - 'Monica', - 'Natasha', - 'Leonce', - 'Corby', - 'Doris', - 'Chancellor', - 'Yonah', - 'Gaston', - 'Alston', - 'Tyreese', - 'Gaither', - 'Donna', - 'Graeme', - 'Frances', - 'Earlie', - 'Oral', - 'Ruby', - 'Krishna', - 'Berkley', - 'Viraj', - 'Jame', - 'Judge', - 'Denim', - 'Guilherme', - 'Salim', - 'Rondell', - 'Marek', - 'Zac', - 'Seven', - 'Stellan', - 'Calder', - 'Eithan', - 'Eliam', - 'Gareth', - 'Auther', - 'Theodis', - 'Denzell', - 'Octave', - 'Destry', - 'Bartholomew', - 'Rajiv', - 'Jaxxon', - 'Maxson', - 'Adler', - 'Tyran', - 'Carnell', - 'Alben', - 'Saif', - 'Merwin', - 'Binyamin', - 'Hayward', - 'Arav', - 'Berry', - 'Daunte', - 'Arvo', - 'Gerhard', - 'Selmer', - 'Davie', - 'Courtland', - 'Athanasios', - 'Ori', - 'Aadi', - 'Kamar', - 'Jeremih', - 'Jayvian', - 'Doyne', - 'Macarthur', - 'Elza', - 'Harden', - 'Soham', - 'Alder', - 'Josemaria', - 'Iziah', - 'Jin', - 'Woodie', - 'Alfie', - 'Stefon', - 'Oswald', - 'Talmage', - 'Leander', - 'Jancarlo', - 'Sasha', - 'Lorin', - 'Roby', - 'Juanmiguel', - 'Johannes', - 'Allie', - 'Demetris', - 'Sharod', - 'Mynor', - 'Lex', - 'Tito', - 'Domonique', - 'Seferino', - 'Jourdan', - 'Marcial', - 'Herminio', - 'Mikal', - 'Alegandro', - 'Makana', - 'Bb', - 'Jarret', - 'Jemel', - 'Kareen', - 'Sierra', - 'Michale', - 'Jalyn', - 'Meredith', - 'Gracie', - 'Dawud', - 'Raylon', - 'Avan', - 'Dayshawn', - 'Livan', - 'Kendal', - 'Otho', - 'Dung', - 'Reuven', - 'Karmelo', - 'Myer', - 'Tadao', - 'Bentzion', - 'Tex', - 'Jamin', - 'Clois', - 'Sadao', - 'Tetsuo', - 'Izrael', - 'Avion', - 'Katsumi', - 'Gerrit', - 'Jamauri', - 'Kunal', - 'Nickolaus', - 'Hoang', - 'Bernabe', - 'Khristian', - 'Arne', - 'Javeon', - 'Vasilios', - 'Noach', - 'Ruger', - 'Kutter', - 'Kyden', - 'Marshal', - 'Jaelon', - 'Raffi', - 'Rito', - 'Parrish', - 'Duvid', - 'Jamario', - 'Verle', - 'Harmon', - 'Thai', - 'Claire', - 'Daiquan', - 'Didier', - 'Jonnie', - 'Arlan', - 'Taggart', - 'Henri', - 'Rogan', - 'Woodford', - 'Maceo', - 'Nyjah', - 'Smith', - 'Syncere', - 'Ballard', - 'Kenichi', - 'Khaled', - 'Dwaine', - 'Mathieu', - 'Ousmane', - 'Emmit', - 'Aayush', - 'Elyas', - 'Taysom', - 'Azaiah', - 'Axle', - 'Ander', - 'Azaan', - 'Vic', - 'Terrel', - 'Alen', - 'Fabricio', - 'Yeshaya', - 'Greggory', - 'Derrik', - 'Esgar', - 'Selwyn', - 'Binh', - 'Tarun', - 'Quoc', - 'Corry', - 'Wylie', - 'Jadan', - 'Aamir', - 'Barron', - 'Ciaran', - 'Melville', - 'Bronislaus', - 'Fong', - 'Hakop', - 'Jashua', - 'Stanislaus', - 'Keion', - 'Timmothy', - 'Kenan', - 'Banks', - 'Ammar', - 'Maxfield', - 'Tyre', - 'Chistian', - 'Son', - 'Shaka', - 'Jahmal', - 'Jerell', - 'Beckam', - 'Zakariya', - 'Jayshawn', - 'Orvel', - 'Yona', - 'Derrek', - 'Warner', - 'Rollie', - 'Adelbert', - 'Von', - 'Kathleen', - 'April', - 'Nikolaos', - 'Alika', - 'Barrington', - 'Inez', - 'Len', - 'Arsh', - 'Elyjah', - 'Eshaan', - 'Shayden', - 'Jaykob', - 'Raziel', - 'Makoa', - 'Cornelio', - 'Rufino', - 'Leamon', - 'Terrill', - 'Hai', - 'Jonerik', - 'Hamilton', - 'Lindbergh', - 'Enos', - 'Sabino', - 'Ara', - 'Raudel', - 'Jones', - 'Cedar', - 'Yohan', - 'Janet', - 'Archibald', - 'Boaz', - 'Cleotha', - 'Dontez', - 'Eldridge', - 'Abhay', - 'Butch', - 'Jayvien', - 'Rowland', - 'Kimo', - 'Gurney', - 'Virgilio', - 'Alfonza', - 'Perley', - 'Silverio', - 'Amilcar', - 'Kapena', - 'Issak', - 'Josemiguel', - 'Mikey', - 'Camille', - 'Gershon', - 'Mehki', - 'Carsten', - 'Lavelle', - 'Jamere', - 'Natale', - 'Elya', - 'Antwone', - 'Pedrohenrique', - 'Kyjuan', - 'Shakim', - 'Evaristo', - 'Lionell', - 'Helen', - 'Aariz', - 'Paige', - 'Jaquavius', - 'Adolphus', - 'Faith', - 'Breanna', - 'Martavius', - 'Armondo', - 'Yobani', - 'Missael', - 'Marcellus', - 'Rishab', - 'Jaxsen', - 'Jahleel', - 'Bernell', - 'Woodroe', - 'Breck', - 'Paden', - 'Trumaine', - 'Rogerio', - 'Cleve', - 'Ameen', - 'Jermain', - 'Shakir', - 'Berl', - 'Conley', - 'Vinson', - 'Andru', - 'Andrue', - 'Suraj', - 'Ruvim', - 'Rodriguez', - 'Benji', - 'Kylon', - 'Matheo', - 'Kellin', - 'Karsyn', - 'Izan', - 'Caysen', - 'Caison', - 'Witten', - 'Issa', - 'Audrey', - 'Sekou', - 'Januel', - 'Christpher', - 'Octaviano', - 'Jereme', - 'Basilio', - 'Kaine', - 'Jayvyn', - 'Vishnu', - 'Umberto', - 'Keondre', - 'Delroy', - 'Herve', - 'Rakim', - 'Denton', - 'Donavin', - 'Elder', - 'Ger', - 'Jazmin', - 'Schneider', - 'Ethyn', - 'Davien', - 'Cross', - 'Reginal', - 'Maksymilian', - 'Rahim', - 'Ridge', - 'Ved', - 'Bartosz', - 'Kaye', - 'Quamir', - 'Jasmin', - 'Diante', - 'Codi', - 'Khamani', - 'Juliocesar', - 'Lydell', - 'Dakari', - 'Eluzer', - 'Daniyal', - 'Isidoro', - 'Yousuf', - 'Rider', - 'Winthrop', - 'Diogo', - 'Kejuan', - 'Micaiah', - 'Ransom', - 'Rolla', - 'Leibish', - 'Ilyas', - 'Arham', - 'Adham', - 'Abdulrahman', - 'Lateef', - 'Rahmir', - 'Kollin', - 'Jamaine', - 'Khary', - 'De', - 'Jabbar', - 'Hardin', - 'Deryl', - 'Yanky', - 'Aviel', - 'Boubacar', - 'Eshan', - 'Hanley', - 'Hussain', - 'Tylon', - 'Leldon', - 'Raoul', - 'Braheem', - 'Kaseem', - 'Tyshaun', - 'Rashaan', - 'Kordell', - 'Anil', - 'Devion', - 'Mervyn', - 'Shaquil', - 'Shaquill', - 'Shaul', - 'Musab', - 'Muad', - 'Tomasz', - 'Madeline', - 'Delante', - 'Jahari', - 'Leah', - 'Tamika', - 'Britney', - 'Jeriel', - 'Yidel', - 'Jarad', - 'Oneil', - 'Fransico', - 'Shamir', - 'Carmello', - 'Abdulahi', - 'Shneur', - 'Yehudah', - 'Brown', - 'Sylvan', - 'Dontay', - 'French', - 'Griffen', - 'Faisal', - 'Dru', - 'Demitri', - 'Faron', - 'Deloy', - 'Juston', - 'Charleston', - 'Farrell', - 'Tab', - 'Donaciano', - 'Candido', - 'Joyce', - 'Marquel', - 'Lamonte', - 'Raheen', - 'Dashon', - 'Hieu', - 'Tyus', - 'Ciro', - 'Naeem', - 'Rush', - 'Keifer', - 'Christion', - 'Bladen', - 'Kobie', - 'Darell', - 'Mouhamed', - 'Jia', - 'Shepard', - 'Price', - 'Kasyn', - 'Truitt', - 'Jenson', - 'Aizen', - 'Markeith', - 'Braylan', - 'Jonmichael', - 'Damond', - 'Jaycion', - 'Platon', - 'Amaury', - 'Amaan', - 'Daven', - 'Tobey', - 'Hymen', - 'Altariq', - 'Jacory', - 'Ashtin', - 'Domonic', - 'Demari', - 'Denise', - 'Abimael', - 'Izaya', - 'Jovon', - 'Harout', - 'Caelan', - 'Donal', - 'Martel', - 'Jaskaran', - 'Alante', - 'Bradon', - 'Deborah', - 'Harrell', - 'Kaipo', - 'Klayton', - 'Danthony', - 'Justino', - 'Kamuela', - 'Barrie', - 'Argelis', - 'Dolores', - 'Jahaziel', - 'Iram', - 'Adian', - 'Rance', - 'Karsten', - 'Christain', - 'Jamarian', - 'Yee', - 'Adriana', - 'Jamichael', - 'Waino', - 'Anh', - 'Casmer', - 'Ronnell', - 'Tong', - 'Vicent', - 'Jarius', - 'Tiburcio', - 'Burdette', - 'Amadeo', - 'Kevan', - 'Arlyn', - 'Derald', - 'Waleed', - 'Jabez', - 'Khoa', - 'Neville', - 'Susan', - 'Leandre', - 'Jorgeluis', - 'Angelica', - 'Regan', - 'Froylan', - 'Tevita', - 'Sagar', - 'Drayton', - 'Zade', - 'Karriem', - 'Townes', - 'Ram', - 'Jaceyon', - 'Keng', - 'Isao', - 'Unkown', - 'Vivian', - 'Mamoru', - 'Dyllon', - 'Hagop', - 'Masami', - 'Shoichi', - 'Landan', - 'Cadence', - 'Yanixan', - 'Xzavion', - 'Javan', - 'Avian', - 'Cadyn', - 'Collier', - 'Clarance', - 'Karen', - 'Christy', - 'Toriano', - 'Diallo', - 'Mateus', - 'Caio', - 'Larue', - 'Gilmer', - 'Rhyan', - 'Elijiah', - 'Curren', - 'Souleymane', - 'Deklan', - 'Zakaria', - 'Hayk', - 'Ric', - 'Briley', - 'Oval', - 'Lovell', - 'Daryn', - 'Franz', - 'Spurgeon', - 'Giacomo', - 'Orrin', - 'Vester', - 'Taran', - 'Salem', - 'Naveen', - 'Linkin', - 'Kallen', - 'Kongmeng', - 'Patrice', - 'Bibb', - 'Arjan', - 'Fateh', - 'Clive', - 'Pharaoh', - 'Subhan', - 'Rayaan', - 'Zebulon', - 'Webster', - 'Raghav', - 'Zakai', - 'Ekam', - 'Caspian', - 'Atom', - 'Athen', - 'Esdras', - 'Vihan', - 'Ronav', - 'Arrow', - 'Izek', - 'Gaines', - 'Trajan', - 'Onofrio', - 'Romello', - 'Ramone', - 'Symir', - 'Kanyon', - 'Shomari', - 'Christo', - 'Anthoney', - 'Giovonni', - 'Gurshan', - 'Nathon', - 'Zach', - 'Jhonatan', - 'Shakur', - 'Favio', - 'Imani', - 'Asad', - 'Brien', - 'Aureliano', - 'Fischer', - 'Yadier', - 'Marino', - 'Kimball', - 'Saleh', - 'Greco', - 'Helmer', - 'Sai', - 'Khai', - 'Marius', - 'Joy', - 'Amauri', - 'Tegan', - 'Darl', - 'Cosimo', - 'Armond', - 'Yecheskel', - 'Natan', - 'Shabazz', - 'Devine', - 'Fabrice', - 'Tarek', - 'Renaldo', - 'Jarrel', - 'Gamal', - 'Rajesh', - 'Lavon', - 'Ahnaf', - 'Cono', - 'Gaspare', - 'Chas', - 'Jaspreet', - 'Tevon', - 'Kush', - 'Nuchem', - 'Jostin', - 'Wm', - 'Darnel', - 'Thurston', - 'Maliek', - 'Shakeel', - 'Coolidge', - 'Shaheed', - 'Anastasios', - 'Wesson', - 'Humza', - 'Kofi', - 'Jamelle', - 'Davey', - 'Llewellyn', - 'Nashawn', - 'Odie', - 'Jun', - 'Jahmere', - 'Bienvenido', - 'Safwan', - 'Mordche', - 'Demarius', - 'Cillian', - 'Alexandros', - 'Nochum', - 'Shareef', - 'Pawel', - 'Theadore', - 'Dorothy', - 'Geno', - 'Haris', - 'Dayvon', - 'Lemarcus', - 'Rayvon', - 'Laird', - 'Zayvion', - 'Dennie', - 'Dwane', - 'Orvis', - 'Chalmer', - 'Adil', - 'Zamari', - 'Kodi', - 'Braxtyn', - 'Fahim', - 'Merl', - 'Name', - 'Aaiden', - 'Dyson', - 'Westyn', - 'Wells', - 'Niles', - 'Nabil', - 'Kaelan', - 'Dmitri', - 'Demitrius', - 'Arlis', - 'Reco', - 'Glendon', - 'Abhishek', - 'Jammie', - 'Grabiel', - 'Jerson', - 'Gerhardt', - 'Kyrin', - 'Kipton', - 'Bear', - 'Jaciel', - 'Dakoda', - 'Kaelin', - 'Keilan', - 'Brendyn', - 'Fortino', - 'Diondre', - 'Arin', - 'Cleophus', - 'Dimas', - 'Caine', - 'Jakoby', - 'Hagan', - 'Layden', - 'Calen', - 'Nils', - 'Cisco', - 'Jerrick', - 'Gevork', - 'Mckenzie', - 'Justis', - 'Coltyn', - 'Brazos', - 'Jaycen', - 'Kemauri', - 'Tyrus', - 'Zaidyn', - 'Lenin', - 'Karlos', - 'Shrey', - 'Edric', - 'Tino', - 'Macklin', - 'Nevan', - 'Lawrance', - 'Arno', - 'Irby', - 'Namir', - 'Chayse', - 'Ronit', - 'Clemens', - 'Giorgio', - 'Khriz', - 'Khang', - 'Zidane', - 'Nomar', - 'Glade', - 'Doyce', - 'Kaya', - 'Surya', - 'Jaelen', - 'Vernell', - 'Issiah', - 'Henderson', - 'Jessejames', - 'Gaylen', - 'Aldahir', - 'An', - 'Asencion', - 'Garner', - 'Treston', - 'Evans', - 'Salome', - 'Cyle', - 'Sang', - 'Isaih', - 'Kirkland', - 'Loyal', - 'Jonpaul', - 'Cindy', - 'Bao', - 'Laurie', - 'Monico', - 'Kiptyn', - 'Toribio', - 'Cresencio', - 'Ruperto', - 'Dat', - 'Rustin', - 'Kendric', - 'Miquel', - 'Hasani', - 'Caron', - 'Jarron', - 'Enrigue', - 'Evelyn', - 'Paulino', - 'Eligio', - 'Melchor', - 'Deshon', - 'Johndavid', - 'Cliffton', - 'Ovidio', - 'Jacorian', - 'Laken', - 'Aedyn', - 'Ichiro', - 'Derion', - 'Sharon', - 'Yasuo', - 'Masayuki', - 'Andrez', - 'Dustyn', - 'Toua', - 'Jossue', - 'Zakkary', - 'Bernardino', - 'Deward', - 'Joanthan', - 'Sandeep', - 'Hercules', - 'Claudia', - 'Sampson', - 'Jacobe', - 'Hulon', - 'Ventura', - 'Blade', - 'Jayzen', - 'Jarren', - 'Nakoa', - 'Chan', - 'Jerrel', - 'Isamar', - 'Artie', - 'Amy', - 'Meghan', - 'Rockey', - 'Sixto', - 'Ascencion', - 'Damonte', - 'Golden', - 'Bubba', - 'Randle', - 'Adelard', - 'Rumaldo', - 'Nieves', - 'Marshaun', - 'Kavion', - 'Mikolaj', - 'Brees', - 'Gayland', - 'Herb', - 'Quenton', - 'Flint', - 'Lennie', - 'Tramaine', - 'Nadir', - 'Timur', - 'Keshav', - 'Malek', - 'Ozzie', - 'Dresden', - 'Eliah', - 'Benaiah', - 'Muhsin', - 'Walt', - 'Damen', - 'Enoc', - 'Giancarlos', - 'Darsh', - 'Maximilliano', - 'Yaniel', - 'Jeevan', - 'Malakhi', - 'Viggo', - 'Karlo', - 'Yosgar', - 'Xavior', - 'Frazier', - 'Orin', - 'Payson', - 'Tonatiuh', - 'Amando', - 'Angad', - 'Gibran', - 'Eben', - 'Deaundre', - 'Rajon', - 'Anand', - 'Andree', - 'Dany', - 'Kayvon', - 'Joell', - 'Jahsiah', - 'Rosaire', - 'Kc', - 'Page', - 'Salvadore', - 'Arjen', - 'Torey', - 'Manraj', - 'Lyam', - 'Mazen', - 'Autry', - 'Coopar', - 'Ranveer', - 'Santhiago', - 'Ronen', - 'Remmy', - 'Kamauri', - 'Andra', - 'Sohan', - 'Cayetano', - 'Jarrad', - 'Fortunato', - 'Magdaleno', - 'Dorman', - 'Cesario', - 'Doroteo', - 'Roddy', - 'Matilde', - 'Lafayette', - 'Edelmiro', - 'Higinio', - 'Yancy', - 'Zvi', - 'Pascal', - 'Timm', - 'Dickey', - 'Spiros', - 'Georgios', - 'Jarid', - 'Johnatho', - 'Nachum', - 'Efrem', - 'Stafford', - 'Pajtim', - 'Amelia', - 'Jada', - 'Lily', - 'Lydia', - 'Sherrod', - 'Stedman', - 'Ardis', - 'Levy', - 'Ulysse', - 'Zalman', - 'Marquette', - 'Gabe', - 'Blaize', - 'Ashanti', - 'Shaheem', - 'Hervey', - 'Abbott', - 'Boleslaw', - 'Tyshon', - 'Kimani', - 'Beecher', - 'Diquan', - 'Eulogio', - 'Arvel', - 'Kennth', - 'Benigno', - 'Luz', - 'Dionisio', - 'Eustacio', - 'Trino', - 'Eldred', - 'Primitivo', - 'Perfecto', - 'Delma', - 'Cosme', - 'Milburn', - 'Shameek', - 'Quayshaun', - 'Evert', - 'Green', - 'Brylan', - 'Crit', - 'Haskel', - 'Ancil', - 'Rayhan', - 'Rose', - 'Gianfranco', - 'Matan', - 'Derin', - 'Artem', - 'Abhiram', - 'Yovanni', - 'Stevenson', - 'Crue', - 'Krue', - 'Jethro', - 'Jakai', - 'Mattix', - 'Daxon', - 'Dallan', - 'Murl', - 'Harsh', - 'Uzziel', - 'Kemarion', - 'Jashaun', - 'Rodman', - 'Elie', - 'Desi', - 'Malikai', - 'Angello', - 'Amogh', - 'Advaith', - 'Adryan', - 'Nazareth', - 'Adolf', - 'Bosco', - 'Arshan', - 'Abdulaziz', - 'Theseus', - 'Riaan', - 'Reza', - 'Radley', - 'Mars', - 'Kirin', - 'Kiaan', - 'Evander', - 'Indiana', - 'Hanson', - 'Viliami', - 'Jaydenn', - 'Ilya', - 'Draco', - 'Riyan', - 'Onyx', - 'Xian', - 'Khristopher', - 'Ayrton', - 'Aurelius', - 'Crosley', - 'Obadiah', - 'Nihal', - 'Rithvik', - 'Constantino', - 'Jeyden', - 'Jaycee', - 'Bane', - 'Aakash', - 'Aniket', - 'Mathis', - 'Maximos', - 'Kohl', - 'Fuquan', - 'Rahman', - 'Aziel', - 'Alexys', - 'Iverson', - 'Marck', - 'Criss', - 'Arsen', - 'Angelgabriel', - 'Ronak', - 'Selvin', - 'Ibraheem', - 'Yordi', - 'Taylen', - 'Javari', - 'Jairus', - 'Hamzah', - 'Sacha', - 'Nayan', - 'Marciano', - 'Aneesh', - 'Manfred', - 'Adal', - 'Bernhard', - 'Jeovanny', - 'Satvik', - 'Nicolo', - 'Julious', - 'Weyman', - 'Roswell', - 'Brevin', - 'Amedeo', - 'Deforest', - 'Barnett', - 'Braydin', - 'Italo', - 'Adrienne', - 'Anne', - 'Jr', - 'Krystal', - 'Brion', - 'Wilberto', - 'Detrick', - 'Bucky', - 'Kristin', - 'Christohper', - 'Laddie', - 'Creighton', - 'Gust', - 'Darby', - 'Shanon', - 'Darious', - 'Josua', - 'Thang', - 'Demarkus', - 'Chistopher', - 'Ehren', - 'Marlo', - 'Matas', - 'Augusto', - 'Diamonte', - 'Maciej', - 'Jamon', - 'Marcin', - 'Valdemar', - 'Nickey', - 'Niam', - 'Ambrosio', - 'Crispin', - 'Lukasz', - 'Yazan', - 'Romell', - 'Darryle', - 'Renard', - 'Ewald', - 'Quint', - 'Andrzej', - 'Vittorio', - 'Keonte', - 'Lavonte', - 'Cordale', - 'Darvin', - 'Marvell', - 'Krzysztof', - 'Corben', - 'Keylan', - 'Haydon', - 'Ociel', - 'Zeth', - 'Ahmari', - 'Texas', - 'Yutaka', - 'Isami', - 'Adarius', - 'Juaquin', - 'Jaydn', - 'Jaidan', - 'Exavier', - 'Steffan', - 'Vahe', - 'Crystian', - 'Edilberto', - 'Jaquavion', - 'Xavien', - 'Delvon', - 'Otoniel', - 'Demontae', - 'Collins', - 'Keoki', - 'Nolberto', - 'Leng', - 'Karina', - 'Grigor', - 'Isrrael', - 'Kaoru', - 'Hisao', - 'Masayoshi', - 'Satoru', - 'Satoshi', - 'Nobuo', - 'Michaelanthony', - 'Lucero', - 'Jocelyn', - 'Yovany', - 'Joangel', - 'Jaelyn', - 'Caedmon', - 'Granger', - 'Heston', - 'Rhodes', - 'Kanon', - 'Judith', - 'Montavius', - 'Antron', - 'Xaiden', - 'Burhanuddin', - 'Stratton', - 'Kadence', - 'Jhett', - 'Jacion', - 'Aiyden', - 'Journey', - 'Jaziah', - 'Thien', - 'Travious', - 'Carsyn', - 'Quindarius', - 'Masyn', - 'Jalan', - 'Jaelin', - 'Dorien', - 'Aarron', - 'Dmarcus', - 'Ramin', - 'Christan', - 'Blain', - 'Rosa', - 'Christoher', - 'Vadim', - 'Martha', - 'Osher', - 'Laakea', - 'Chayton', - 'Keahi', - 'Johnatan', - 'Juanantonio', - 'Kahiau', - 'Sheridan', - 'Samual', - 'Luisalberto', - 'Zacharias', - 'Phi', - 'Marquice', - 'Chong', - 'Harpreet', - 'Fue', - 'Derrion', - 'Eber', - 'Kevion', - 'Beryl', - 'Gavan', - 'Liliana', - 'Fernie', - 'Sulo', - 'Jayren', - 'Lior', - 'Ruth', - 'Carlie', - 'Thierno', - 'Davontae', - 'Jamier', - 'Arye', - 'Kiernan', - 'Hanad', - 'Huston', - 'Winson', - 'Hobson', - 'Yates', - 'Kaua', - 'Einar', - 'Berish', - 'Annie', - 'Mahir', - 'Amr', - 'Sabir', - 'Ewell', - 'Orland', - 'Dujuan', - 'Harvie', - 'Dahmir', - 'Hosea', - 'Haneef', - 'Wei', - 'Nello', - 'Fishel', - 'Amere', - 'Rafi', - 'Charlton', - 'Colden', - 'Hughes', - 'Laurier', - 'Blong', - 'Shimshon', - 'Jahmel', - 'Steward', - 'Milbert', - 'Buel', - 'Hallie', - 'Comer', - 'Tafari', - 'Iver', - 'Evangelos', - 'Jaquarius', - 'Azan', - 'Braedan', - 'Jadarrius', - 'Vernie', - 'Andi', - 'Darry', - 'Jawad', - 'Uri', - 'Kennard', - 'Yishai', - 'Kijana', - 'Brekken', - 'Rajan', - 'Stevens', - 'Sunil', - 'Siddhant', - 'Sir', - 'Sire', - 'Jansen', - 'Theodor', - 'Kaedyn', - 'Tymere', - 'Zyair', - 'Tron', - 'Sanchez', - 'Amaru', - 'Anastasio', - 'Agastya', - 'Hawk', - 'Honor', - 'Sotero', - 'Saeed', - 'Ziggy', - 'Conan', - 'Arie', - 'Gloria', - 'Onesimo', - 'Wellington', - 'Alexei', - 'Tavarus', - 'Cayleb', - 'Arion', - 'Amadeus', - 'Bryer', - 'Jeter', - 'Merced', - 'Kaylon', - 'Lakendrick', - 'Nolen', - 'Niccolo', - 'Halston', - 'Deontre', - 'Ash', - 'Arush', - 'Artur', - 'Bidwell', - 'Tomie', - 'Author', - 'Izik', - 'Jeriah', - 'Edwyn', - 'Zhi', - 'Gilman', - 'Jawan', - 'Bryar', - 'Giles', - 'Talha', - 'Gill', - 'Abelino', - 'Kwasi', - 'Stavros', - 'Juanita', - 'Tri', - 'Consuelo', - 'Khambrel', - 'Peterson', - 'Brantly', - 'Brently', - 'Vitaliy', - 'Hashim', - 'Rain', - 'Quintus', - 'Matthieu', - 'Kayne', - 'Icker', - 'Valen', - 'Nels', - 'Josephus', - 'Nasario', - 'Romulo', - 'Kaisen', - 'Sulaiman', - 'Selim', - 'Mahad', - 'Steele', - 'Stryder', - 'Cristina', - 'Thornton', - 'Girard', - 'Prudencio', - 'Ethaniel', - 'Laurent', - 'Jayvin', - 'Jayveon', - 'Eladio', - 'Ellison', - 'Caius', - 'Christiano', - 'Navid', - 'Gerold', - 'Sven', - 'Advay', - 'Cabell', - 'Marcio', - 'Luisalfredo', - 'Ryatt', - 'Elijio', - 'Pax', - 'Neev', - 'Mehtab', - 'Eluterio', - 'Tahmir', - 'Davit', - 'Eliott', - 'Keane', - 'Kysen', - 'Rafe', - 'Legacy', - 'Erie', - 'Orlin', - 'Dawn', - 'Calum', - 'Adithya', - 'Adarsh', - 'Ulysee', - 'Thurmond', - 'Christen', - 'Thayne', - 'Sriram', - 'Yoav', - 'Lawton', - 'Kemar', - 'Duston', - 'Jatavious', - 'Luisfernando', - 'Maxime', - 'Rithik', - 'Dior', - 'Phuong', - 'Roni', - 'Manu', - 'Esteven', - 'Hazen', - 'Farris', - 'Leverne', - 'Ryen', - 'Tanay', - 'Seaborn', - 'Cicero', - 'Gianmarco', - 'Isak', - 'Lige', - 'Burke', - 'Authur', - 'Javarius', - 'Jeromie', - 'Jerred', - 'Silvano', - 'Keyan', - 'Briant', - 'Arun', - 'Jeremi', - 'Decarlos', - 'Jeanpierre', - 'Haydn', - 'Ab', - 'Anmol', - 'Shaye', - 'Nana', - 'Mateen', - 'Maurisio', - 'Nitin', - 'Dustan', - 'Srikar', - 'Arlin', - 'Burnett', - 'Johnathen', - 'Wyman', - 'Aleksandar', - 'Agustine', - 'Ronney', - 'Marisol', - 'Dmarion', - 'Keir', - 'Demetrice', - 'Jawon', - 'Ricci', - 'Javontae', - 'Armoni', - 'Alto', - 'Dawid', - 'Zakir', - 'Jarek', - 'Lary', - 'Dez', - 'Kaydon', - 'Henley', - 'Adonai', - 'Zahmir', - 'Youssouf', - 'Oisin', - 'Deniz', - 'Antonios', - 'Netanel', - 'Shlok', - 'Ranger', - 'Uzziah', - 'Eryk', - 'Sid', - 'Andersen', - 'Daylin', - 'Naftoli', - 'Lyn', - 'Orvin', - 'Kesean', - 'Hanif', - 'Adael', - 'Maury', - 'Ronn', - 'Carlyle', - 'Ankur', - 'Takumi', - 'Piero', - 'Jeanpaul', - 'Hoa', - 'Jacarri', - 'Jakhi', - 'Zyion', - 'Jeovany', - 'Eoin', - 'Etienne', - 'Amrit', - 'Dang', - 'Juliano', - 'Blakely', - 'Tauno', - 'Edin', - 'Dmitriy', - 'Lambert', - 'Roderic', - 'Felice', - 'Zaki', - 'Debra', - 'Teegan', - 'Tosh', - 'Nicholai', - 'Erickson', - 'Atharva', - 'Aaditya', - 'Anuj', - 'Diane', - 'Sachin', - 'Elazar', - 'Torian', - 'Tan', - 'Cristoval', - 'Jonathen', - 'Kobi', - 'Yuki', - 'Jacori', - 'Eduard', - 'Keron', - 'Tysean', - 'Deshun', - 'Hewitt', - 'Kaulana', - 'Jaydyn', - 'Sebastia', - 'Shamell', - 'Trysten', - 'Treshawn', - 'Samer', - 'Burnice', - 'Da', - 'Parris', - 'Royer', - 'Tien', - 'Tj', - 'Andranik', - 'Nino', - 'Luisenrique', - 'Andrick', - 'Graydon', - 'Pookela', - 'Nevaeh', - 'Zoe', - 'Hanna', - 'Joniel', - 'Jamarious', - 'Hurley', - 'Avante', - 'Iban', - 'Isaiha', - 'Chee', - 'Kealii', - 'Irbin', - 'Maynor', - 'Wendy', - 'Germain', - 'Shamus', - 'Zygmunt', - 'Garnet', - 'Lopaka', - 'Damar', - 'Ramy', - 'Everton', - 'Raylen', - 'Tryston', - 'Kullen', - 'Therman', - 'Khaliq', - 'Alon', - 'Arch', - 'Tylen', - 'Kalan', - 'Zacharia', - 'Dalen', - 'Bedford', - 'Lou', - 'Tsuneo', - 'Kalub', - 'Dadrian', - 'Jiro', - 'Fahad', - 'Quashawn', - 'Hisashi', - 'Fumio', - 'Carlito', - 'Ewing', - 'Zarek', - 'Leron', - 'Cardell', - 'Westen', - 'Hogan', - 'Payden', - 'Chazz', - 'Jarryd', - 'Sedric', - 'Homar', - 'Tylar', - 'Keone', - 'Dasean', - 'Lake', - 'Joeanthony', - 'Haroon', - 'Adonys', - 'Grayling', - 'Braelon', - 'Loras', - 'Jontavious', - 'Nesanel', - 'Carlisle', - 'Camillo', - 'Mandeep', - 'Yang', - 'Blayden', - 'Niall', - 'Evelio', - 'Zaragoza', - 'Shlomie', - 'Percell', - 'Baylee', - 'Garold', - 'Eriq', - 'Ozell', - 'Benjiman', - 'Wayman', - 'Saturnino', - 'Moody', - 'Deandra', - 'Estanislado', - 'Curvin', - 'Demonta', - 'Crimson', - 'Scout', - 'Daequan', - 'Izael', - 'Trine', - 'Demontre', - 'Rexford', - 'Fenix', - 'Raheim', - 'Rivers', - 'Cobe', - 'Jeron', - 'Yanuel', - 'Naftula', - 'Dwan', - 'Kanai', - 'Nicco', - 'Kaeson', - 'Shadman', - 'Cobi', - 'Raequan', - 'Shae', - 'Osama', - 'Ernan', - 'Dennys', - 'Aquil', - 'Tierra', - 'Sabrina', - 'Mia', - 'Melanie', - 'Marissa', - 'Carolyn', - 'Arielle', - 'Zaine', - 'Macen', - 'Shahin', - 'Casyn', - 'Osmin', - 'Alphonsus', - 'Carrington', - 'Chayce', - 'Opal', - 'Taylon', - 'Koy', - 'Ebenezer', - 'Amarii', - 'Keshun', - 'Kolin', - 'Aspen', - 'Cort', - 'Zaylon', - 'Zaedyn', - 'Zaydyn', - 'Tuff', - 'Holton', - 'Ashtyn', - 'Lathen', - 'Hershell', - 'Jerre', - 'Tsugio', - 'Josealberto', - 'Adien', - 'Acen', - 'Maurilio', - 'Ashten', - 'Wataru', - 'Keontae', - 'Donaven', - 'Javonta', - 'Jacobie', - 'Peng', - 'Ector', - 'Ankit', - 'Ann', - 'Kasim', - 'Parley', - 'Mizael', - 'Maxon', - 'Kylar', - 'Jjesus', - 'Kaven', - 'Curran', - 'Edvin', - 'Enrrique', - 'Donovin', - 'Godfrey', - 'Xayden', - 'Xzavian', - 'Carlosmanuel', - 'Ladainian', - 'Keithan', - 'Azrael', - 'Jae', - 'Marlow', - 'Aviv', - 'Orson', - 'Zamarion', - 'Chason', - 'Henrry', - 'Gevorg', - 'Dartagnan', - 'Zakee', - 'Giovannie', - 'Halen', - 'Vinay', - 'Wilfrido', - 'Winton', - 'Garet', - 'Josafat', - 'Manjot', - 'Juandaniel', - 'Manley', - 'Oshea', - 'Wali', - 'Reymond', - 'Harjot', - 'Sidharth', - 'Amer', - 'Camari', - 'Quincey', - 'Dawan', - 'Newell', - 'Sigurd', - 'Logen', - 'Rafiq', - 'Delonta', - 'Katrina', - 'Kristina', - 'Octavia', - 'Sade', - 'Ziyad', - 'Tovia', - 'Malachai', - 'Briana', - 'Alison', - 'Ashleigh', - 'Jerick', - 'Benedetto', - 'Fiore', - 'Mikail', - 'Qasim', - 'Yochanan', - 'Ettore', - 'Ferris', - 'Aziz', - 'Naseer', - 'Jabril', - 'Brodey', - 'Alvah', - 'Kalman', - 'Ziyon', - 'Zakery', - 'Sedale', - 'Jevin', - 'Kalmen', - 'Moishy', - 'Shai', - 'Zakari', - 'Bradlee', - 'Kenley', - 'Pratham', - 'Izeah', - 'Ilias', - 'Emari', - 'Race', - 'Zacarias', - 'Yuri', - 'Kleber', - 'Kailer', - 'Jhovany', - 'Iven', - 'Issaiah', - 'Hosie', - 'Dixon', - 'Massiah', - 'Remo', - 'Pinchos', - 'Mahki', - 'Gunther', - 'Irene', - 'Jamarie', - 'Kaan', - 'Jayon', - 'Moroni', - 'Jkwon', - 'Barack', - 'Alastair', - 'Fares', - 'Zackariah', - 'Yoshua', - 'Tanish', - 'Iann', - 'Linden', - 'Avinash', - 'Willam', - 'Iman', - 'Domanic', - 'Lenton', - 'Samad', - 'Aimar', - 'Buddie', - 'Jozef', - 'Josmar', - 'Mercer', - 'Collie', - 'Nephi', - 'Kenai', - 'Alquan', - 'Cezar', - 'Verbon', - 'Aeneas', - 'Jeremyah', - 'Eren', - 'Tej', - 'Jahad', - 'Deep', - 'Augusta', - 'Yaqub', - 'Yahye', - 'Vashon', - 'Kristoff', - 'Penn', - 'Loukas', - 'Kaydin', - 'Kaius', - 'Perseus', - 'Mykah', - 'Joab', - 'Cylus', - 'Emrys', - 'Mikko', - 'Jaxsyn', - 'Sudais', - 'Tiberius', - 'Rooney', - 'Yuvan', - 'Cletis', - 'Liev', - 'Ester', - 'Harlow', - 'Shreyan', - 'Samar', - 'Saharsh', - 'Ruhaan', - 'Zyler', - 'Yuma', - 'Dwyane', - 'Yanni', - 'Dutch', - 'Rajveer', - 'Tayton', - 'Kasir', - 'Luster', - 'Tage', - 'Damarius', - 'Elihu', - 'Heinz', - 'Manolo', - 'Makhai', - 'Madhav', - 'Sohum', - 'Omri', - 'Egbert', - 'Marie', - 'Keshon', - 'Jahmier', - 'Nachmen', - 'Mckade', - 'Moise', - 'Ames', - 'Iden', - 'Benard', - 'Yannick', - 'Pasha', - 'Sherrick', - 'Jordany', - 'Fenton', - 'Tytan', - 'Dashel', - 'Daksh', - 'Juliani', - 'Jhonathan', - 'Broxton', - 'Essie', - 'Devontay', - 'Maksym', - 'Park', - 'Dasani', - 'Severiano', - 'Kamel', - 'Chayanne', - 'Jarel', - 'Yolanda', - 'Tylik', - 'Marquell', - 'Jamarr', - 'Micky', - 'Socorro', - 'Waymond', - 'Michial', - 'Yoseph', - 'Lumir', - 'Placido', - 'Asif', - 'Needham', - 'Claiborne', - 'Tennis', - 'Burley', - 'Raffaele', - 'Shavar', - 'Atanacio', - 'Jahmar', - 'Arben', - 'Nabeel', - 'Cordarryl', - 'Danyal', - 'Bryston', - 'Lemont', - 'Elston', - 'Kerwin', - 'Riccardo', - 'Danzel', - 'Waldemar', - 'Ledarius', - 'Omarr', - 'Wilho', - 'Alger', - 'Raymie', - 'Kenney', - 'Abdallah', - 'Aristides', - 'Avram', - 'Tayvion', - 'Urbano', - 'Deontay', - 'Darcy', - 'Robbin', - 'Bartlomiej', - 'Dann', - 'Tyjuan', - 'Khaleel', - 'Winifred', - 'Claron', - 'Linford', - 'Hilliard', - 'Arlon', - 'Yong', - 'Malvin', - 'Zymere', - 'Newborn', - 'Eleuterio', - 'Glyn', - 'Koltyn', - 'Serapio', - 'Pius', - 'Ines', - 'Harrold', - 'Caitlyn', - 'Rajeev', - 'Constantinos', - 'Abid', - 'Calvert', - 'Parnell', - 'Aubry', - 'Damone', - 'Akim', - 'Adem', - 'Othel', - 'Joaopedro', - 'Tomer', - 'Brentlee', - 'Melquan', - 'Elpidio', - 'Jenny', - 'Alejos', - 'Romie', - 'Ardell', - 'Doctor', - 'Virginia', - 'Makenzie', - 'Maggie', - 'Tywan', - 'Elisaul', - 'Luby', - 'Teofilo', - 'Jermell', - 'Gumesindo', - 'Harless', - 'Croix', - 'Obinna', - 'Traveon', - 'Coley', - 'Tu', - 'Brylon', - 'Carlin', - 'Daneil', - 'Garen', - 'Ronell', - 'Chesley', - 'Tyrece', - 'Arville', - 'Eamonn', - 'Kayshawn', - 'Wilkie', - 'Zacchaeus', - 'Rapheal', - 'Cordaryl', - 'Quan', - 'Nhan', - 'Vann', - 'Franciscojavier', - 'Kinte', - 'Rui', - 'Chuong', - 'Chao', - 'Chai', - 'Linh', - 'Cirilo', - 'Ky', - 'Gwyn', - 'Hearl', - 'Tray', - 'Carmon', - 'Phuc', - 'Neiman', - 'Ladon', - 'Moua', - 'Eulises', - 'Jonte', - 'Yusuke', - 'Vinnie', - 'Seanpatrick', - 'Pearson', - 'Daemon', - 'Reyn', - 'Daekwon', - 'Garron', - 'Sequan', - 'Zavien', - 'Geovanie', - 'Jessee', - 'Richmond', - 'Osualdo', - 'Artin', - 'Devone', - 'Makoto', - 'Hitoshi', - 'Shinichi', - 'Samari', - 'Saxon', - 'Glennis', - 'Fadi', - 'Bronislaw', - 'Estuardo', - 'Shaheen', - 'Saman', - 'Lue', - 'Djuan', - 'Cord', - 'Linville', - 'Landis', - 'Cameren', - 'Herson', - 'Ellie', - 'Seanmichael', - 'Froilan', - 'Delon', - 'Jestin', - 'Mattew', - 'Toni', - 'Kelii', - 'Maribel', - 'Jadrian', - 'Traylon', - 'Kaiea', - 'Kaeo', - 'Taft', - 'Dameion', - 'Darryn', - 'Dondi', - 'Clell', - 'Corbett', - 'Lyndell', - 'Avenir', - 'Seldon', - 'Jakwon', - 'Jacque', - 'Deane', - 'Cheikh', - 'Carmel', - 'Kieth', - 'Tahmid', - 'Lillard', - 'Tasheem', - 'Jens', - 'Christobal', - 'Delos', - 'Lashon', - 'Jaimie', - 'Kary', - 'Kendarious', - 'Johnell', - 'Harlen', - 'Terron', - 'Corliss', - 'Liston', - 'Seng', - 'Phu', - 'Rasean', - 'Sung', - 'San', - 'Babak', - 'Adel', - 'Gillermo', - 'Avon', - 'Harlon', - 'Allyn', - 'Clary', - 'Orry', - 'Nazario', - 'Jamail', - 'Daeshawn', - 'Tal', - 'Moustafa', - 'Tarell', - 'Jahquan', - 'Jian', - 'Lazar', - 'Adama', - 'Benyamin', - 'Tayvon', - 'Lamel', - 'Davonne', - 'Tayquan', - 'Jusitn', - 'Shjon', - 'Leotis', - 'Kasheem', - 'Ilir', - 'Ravon', - 'Parish', - 'Ehan', - 'Daishawn', - 'Islam', - 'Pinches', - 'Ovadia', - 'Mechel', - 'Berlin', - 'Deryk', - 'Tymel', - 'Vijay', - 'Dyquan', - 'Agron', - 'Tarrell', - 'Itamar', - 'Mordcha', - 'Chrisotpher', - 'Alban', - 'Stephane', - 'Tanvir', - 'Demetriu', - 'Yan', - 'Asim', - 'Ahsan', - 'Mackenzi', - 'Kristofe', - 'Kenrick', - 'Cuahutemoc', - 'Tavis', - 'Audric', - 'Deaven', - 'Nicanor', - 'Mick', - 'Geoffery', - 'Timofey', - 'Dolphus', - 'Franciso', - 'Gorje', - 'Jobany', - 'Abdelrahman', - 'Clenton', - 'Yohance', - 'Milad', - 'Juanluis', - 'Luismario', - 'Marvyn', - 'Rushil', - 'Tenoch', - 'Trentin', - 'Fardeen', - 'Shashank', - 'Yuta', - 'Ritvik', - 'Akili', - 'Aleksei', - 'Gaurav', - 'Iran', - 'Caillou', - 'Borach', - 'Keisuke', - 'Kaushik', - 'Hari', - 'Izac', - 'Josejulian', - 'Juanangel', - 'Kasra', - 'Anthonie', - 'Daivd', - 'Dain', - 'Toren', - 'Sesar', - 'Eldor', - 'Pieter', - 'Yu', - 'Cloyce', - 'Dusten', - 'Aquiles', - 'Aslan', - 'Sevastian', - 'Siddarth', - 'Tysen', - 'Johncarlo', - 'Idan', - 'Daymian', - 'Domanick', - 'Arnie', - 'Bartley', - 'Newman', - 'Akram', - 'Abdulla', - 'Lew', - 'Geremy', - 'Jehu', - 'Josejuan', - 'Jailen', - 'Etai', - 'Fabien', - 'Victormanuel', - 'Ossie', - 'Egan', - 'Eldin', - 'Shamari', - 'Nussen', - 'Arda', - 'Sina', - 'Tytus', - 'Pranay', - 'Dylen', - 'Juandavid', - 'Kalil', - 'Kushal', - 'Hazael', - 'Lecil', - 'Belton', - 'Aleczander', - 'Terance', - 'Faizan', - 'Naithan', - 'Koji', - 'Akshat', - 'Andruw', - 'Bram', - 'Dieter', - 'Saahil', - 'Saulo', - 'Arnel', - 'Demarea', - 'Farhad', - 'Joeseph', - 'Alondra', - 'Belal', - 'Antoniodejesus', - 'Anival', - 'Choua', - 'Cha', - 'Bryn', - 'Xiong', - 'Aristeo', - 'Mehmet', - 'Moustapha', - 'Jandel', - 'Asante', - 'Yunus', - 'Schneur', - 'Steffen', - 'Leovardo', - 'Kacey', - 'Payam', - 'Salbador', - 'Nicholes', - 'Neema', - 'Clarke', - 'Marqus', - 'Araceli', - 'Jerman', - 'Marioalberto', - 'Joseguadalupe', - 'Emigdio', - 'Krishan', - 'Jessey', - 'Arcadio', - 'Zong', - 'Yoni', - 'Tirso', - 'Thompson', - 'Damarea', - 'Everado', - 'Edy', - 'Edder', - 'Nikki', - 'Clemmie', - 'Willian', - 'Marquese', - 'Perris', - 'Miriam', - 'Shelly', - 'Bulmaro', - 'Jasdeep', - 'Irvine', - 'Hue', - 'Gurpreet', - 'Donaldo', - 'Jonthan', - 'Geroge', - 'Francois', - 'Duc', - 'Jerico', - 'Avedis', - 'Chang', - 'Damario', - 'Kenta', - 'Nikkolas', - 'Khoi', - 'Garren', - 'Norma', - 'My', - 'Lam', - 'Sahir', - 'Yer', - 'Jaskarn', - 'Jeric', - 'Maximillion', - 'Elson', - 'Marin', - 'Loc', - 'Lemar', - 'Kristofor', - 'Nai', - 'Takoda', - 'Tung', - 'Thong', - 'Rayshaun', - 'Derreck', - 'Regino', - 'Nadav', - 'Luismiguel', - 'Josede', - 'Hao', - 'Rayce', - 'Zacary', - 'Nareg', - 'Khyree', - 'Chi', - 'Joanna', - 'Sevag', - 'Garin', - 'Juluis', - 'Petros', - 'Berel', - 'Abubakar', - 'Jorel', - 'Kazi', - 'Jaiceon', - 'Haider', - 'Feynman', - 'Muhammadali', - 'Jassiel', - 'Morrison', - 'Nakai', - 'Oden', - 'Odysseus', - 'Quest', - 'Kaidan', - 'Kilian', - 'Kirill', - 'Thorin', - 'Tru', - 'Xzander', - 'Taniela', - 'Roen', - 'Sho', - 'Aarin', - 'Gracen', - 'Gurfateh', - 'Gurman', - 'Hiro', - 'Edrick', - 'Esaias', - 'Johncarlos', - 'Sidi', - 'Cataldo', - 'Noor', - 'Philbert', - 'Eyad', - 'Arber', - 'Abrar', - 'Ladislaus', - 'Serafino', - 'Mannie', - 'Daevon', - 'Haseeb', - 'Yale', - 'Spiro', - 'Emre', - 'Daryan', - 'Camrin', - 'Kavi', - 'Doran', - 'Vaibhav', - 'Rayne', - 'Derric', - 'Orbie', - 'Reily', - 'Gio', - 'Gurnoor', - 'Jaasiel', - 'Naman', - 'Josaiah', - 'Josiyah', - 'Kasper', - 'Filippo', - 'Sigfredo', - 'Joesiah', - 'Rei', - 'Nahom', - 'Ojas', - 'Vladislav', - 'Hilary', - 'Rinaldo', - 'Even', - 'Gautam', - 'Cornel', - 'Julyan', - 'Inaki', - 'Iseah', - 'Itai', - 'Laurance', - 'Garey', - 'Lawerance', - 'Quindon', - 'Levin', - 'Leviticus', - 'Link', - 'Glenford', - 'Avyan', - 'Dmitry', - 'Eiden', - 'Advait', - 'Ahaan', - 'Arhaan', - 'Kassius', - 'Hendrick', - 'Jaiveer', - 'Nirvaan', - 'Reeve', - 'Torsten', - 'True', - 'Iwao', - 'Jahvon', - 'Paxson', - 'Kali', - 'Kwesi', - 'Yaron', - 'Ami', - 'Dashiel', - 'Meliton', - 'Sylus', - 'Mika', - 'Jireh', - 'Selig', - 'Adi', - 'Brenner', - 'Breyden', - 'Mitsuru', - 'Farley', - 'Montrel', - 'Kyland', - 'Jadakiss', - 'Tadarius', - 'Brooke', - 'Alexandria', - 'Alexa', - 'Abby', - 'Hayley', - 'Mallory', - 'Madelyn', - 'Layla', - 'Kirsten', - 'Quayshawn', - 'Deadrick', - 'Hobby', - 'Eunice', - 'Macon', - 'Ysabel', - 'Secundino', - 'Hulen', - 'Estle', - 'Tolbert', - 'Baker', - 'Tilford', - 'Shyheem', - 'Orbin', - 'Ruel', - 'Hurshel', - 'Jailyn', - 'Dequincy', - 'Jamall', - 'Draper', - 'Kenric', - 'Aime', - 'Cam', - 'Connell', - 'Treylon', - 'Bethel', - 'Rommie', - 'Alphonza', - 'Gussie', - 'Elridge', - 'Hillery', - 'Ruffin', - 'Farrel', - 'Wendall', - 'Gerome', - 'Ferrell', - 'Uvaldo', - 'Marshon', - 'Jawaun', - 'Trevell', - 'Tyvon', - 'Telesforo', - 'Ellery', - 'Cordae', - 'Loran', - 'Travell', - 'Lamari', - 'Errick', - 'Antwoine', - 'Starsky', - 'Chirag', - 'Donzell', - 'Tierre', - 'Ketan', - 'Crespin', - 'Orris', - 'Bawi', - 'Wanda', - 'Canuto', - 'Aniceto', - 'Braxten', - 'Audry', - 'Bartolo', - 'Brigido', - 'Garvin', - 'Vergil', - 'Olegario', - 'Thelma', - 'Crecencio', - 'Eleno', - 'Wright', - 'Burtis', - 'Dicky', - 'Avelino', - 'Norval', - 'Cirildo', - 'Darwyn', - 'Delwin', - 'Henery', - 'Beauford', - 'Little', - 'Ameir', - 'Arland', - 'Verner', - 'Taron', - 'Undra', - 'Khasir', - 'Kymir', - 'Aleem', - 'Ordean', - 'Carmino', - 'Lucus', - 'Jodeci', - 'Linn', - 'Sinclair', - 'Delorean', - 'Chalmers', - 'Kentavius', - 'Jarious', - 'Lajuan', - 'Narada', - 'Hussien', - 'Alonte', - 'Damarco', - 'Benjamen', - 'Randon', - 'Jabree', - 'Lawyer', - 'Wanya', - 'Samie', - 'Sim', - 'Washington', - 'Isom', - 'Keyton', - 'Quin', - 'Mahamed', - 'Liban', - 'Ramir', - 'Samaj', - 'Kipp', - 'Prentis', - 'Jibril', - 'Kyaire', - 'Buell', - 'Nasim', - 'Adell', - 'Mohamedamin', - 'Abdiaziz', - 'Harun', - 'Amire', - 'Eligah', - 'Parks', - 'Colonel', - 'Joaovictor', - 'Vinicius', - 'Mcdonald', - 'Manly', - 'Phares', - 'Geza', - 'Kemp', - 'Alphonzo', - 'Loring', - 'Haig', - 'Joaquim', - 'Craven', - 'Bynum', - 'Parke', - 'Ignatz', - 'Hebert', - 'Berton', - 'Ayomide', - 'Kidus', - 'Ayven', - 'Aziah', - 'Banner', - 'Barret', - 'Blayze', - 'Braddock', - 'Javoris', - 'Cortland', - 'Antavius', - 'Amaziah', - 'Santonio', - 'Slate', - 'Sylis', - 'Thierry', - 'Joanthony', - 'Rhylan', - 'Pryce', - 'Riggin', - 'Dequavious', - 'Bakari', - 'Marquavius', - 'Artavious', - 'Desmon', - 'Rajohn', - 'Faheem', - 'Kage', - 'Arkeem', - 'Jaquon', - 'Dontavis', - 'Quentavious', - 'Braysen', - 'Bricen', - 'Traevon', - 'Caidyn', - 'Collyn', - 'Joah', - 'Patton', - 'Coleson', - 'Eythan', - 'Hadley', - 'Jaaziel', - 'Johntavious', - 'Quadarius', - 'Rafeal', - 'Karam', - 'Krishiv', - 'Majd', - 'Yeray', - 'Whitten', - 'Johnluke', - 'Demani', - 'Easten', - 'Ediel', - 'Tellis', - 'Delvecchio', - 'Aleks', - 'Rylie', - 'Osmel', - 'Lelan', - 'Tamarion', - 'Cayman', - 'Hajime', - 'Akio', - 'Takao', - 'Seiji', - 'Ah', - 'Mitsugi', - 'Koichi', - 'Ikenna', - 'Tyquavious', - 'Brannen', - 'Slayde', - 'Sultan', - 'Cage', - 'Jillian', - 'Kara', - 'Simone', - 'Theresa', - 'Julie', - 'Alisha', - 'Candace', - 'Candice', - 'Jazmine', - 'Domani', - 'Tiana', - 'Jeovanni', - 'Khaleb', - 'Copeland', - 'Dathan', - 'Deleon', - 'Jakori', - 'Jayke', - 'Kadon', - 'Camdon', - 'Shandon', - 'Mylan', - 'Jaxin', - 'Beverley', - 'Dallon', - 'Jakeem', - 'Tallon', - 'Vraj', - 'Welford', - 'Jadarian', - 'Yancarlos', - 'Omkar', - 'Jamaree', - 'Alix', - 'Trevyn', - 'Orestes', - 'Trevis', - 'Refoel', - 'Roddrick', - 'Tarvis', - 'Tamarick', - 'Denard', - 'Kerem', - 'Treyden', - 'Stephano', - 'Shubh', - 'Carston', - 'Utah', - 'Treven', - 'Reshard', - 'Yerachmiel', - 'Osmany', - 'Vansh', - 'Samaad', - 'Shakil', - 'Saford', - 'Doyal', - 'Cai', - 'Alexey', - 'Cruze', - 'Masiah', - 'Kitai', - 'Fedor', - 'Algie', - 'Worley', - 'Jakhari', - 'Brison', - 'Lanier', - 'Eston', - 'Qadir', - 'Lonzie', - 'Rayfield', - 'Chirstopher', - 'Eron', - 'Deontray', - 'Zoltan', - 'Christon', - 'Byford', - 'Mikeal', - 'Talyn', - 'Stormy', - 'Laramie', - 'Chrisopher', - 'Breckin', - 'Kennon', - 'Json', - 'Deiondre', - 'Heron', - 'Mykal', - 'Kalai', - 'Ervey', - 'Brayam', - 'Alakai', - 'Maika', - 'Kelson', - 'Trevaughn', - 'Aundre', - 'Eathan', - 'Keylon', - 'Kolbe', - 'Sebastion', - 'Kalib', - 'Jermy', - 'Jarrid', - 'Gumaro', - 'Maliq', - 'Armstead', - 'Stephone', - 'Oris', - 'Hassel', - 'Antwine', - 'Lorraine', - 'Budd', - 'Irfan', - 'Kamrin', - 'Araf', - 'Affan', - 'Leiby', - 'Sruly', - 'Peretz', - 'Mildred', - 'Louise', - 'Ryken', - 'Ryler', - 'Tayven', - 'Taysen', - 'Brexton', - 'Zayaan', - 'Oronde', - 'Firman', - 'Collen', - 'Letcher', - 'Clearence', - 'Braydan', - 'Yasser', - 'Jeferson', - 'Yahsir', - 'Cavan', - 'Ivor', - 'Hasker', - 'Kodie', - 'Lori', - 'Jaysean', - 'Cadin', - 'Breydon', - 'Amaree', - 'Nyeem', - 'Menno', - 'Orlo', - 'Nassir', - 'Sylar', - 'Drevon', - 'Burech', - 'Lenox', - 'Shloima', - 'Daris', - 'Diontae', - 'Aidin', - 'Brydon', - 'Jasean', - 'Nasier', - 'Johney', - 'Gabrial', - 'Fate', - 'Colyn', - 'Kaleem', - 'Capers', - 'Rembert', - 'Jquan', - 'Legrand', - 'Kirubel', - 'Gaberiel', - 'Thaddaeus', - 'Rece', - 'Dymir', - 'Tylil', - 'Remigio', - 'Ahad', - 'Melquiades', - 'Ethel', - 'Euel', - 'Harvy', - 'Margarita', - 'Jakeb', - 'Kagan', - 'Trinton', - 'Faiz', - 'Iliyan', - 'Emeterio', - 'Ferman', - 'Keeton', - 'Decorian', - 'Hadyn', - 'Rashaud', - 'Davontay', - 'Brallan', - 'Benancio', - 'Espiridion', - 'Seledonio', - 'Estefan', - 'Chanse', - 'Dade', - 'Sisto', - 'Herbie', - 'Janson', - 'Eusevio', - 'Loye', - 'Leocadio', - 'Kaelon', - 'Trevian', - 'Christien', - 'Chrystian', - 'Daegan', - 'Rosbel', - 'Romero', - 'Kylin', - 'Treyvion', - 'Ezekial', - 'Jaice', - 'Jantzen', - 'Aadyn', - 'Tennyson', - 'Kaedan', - 'Kaiser', - 'Kanin', - 'Jerron', - 'Jonaven', - 'Elija', - 'Amon', - 'Valton', - 'Derwood', - 'Atilano', - 'Jovanie', - 'Kaemon', - 'Oluwatobi', - 'Atlee', - 'Tadd', - 'Tammy', - 'Lem', - 'Hilmar', - 'Foch', - 'Clenard', - 'Jd', - 'Jiovanny', - 'Ladarion', - 'Lleyton', - 'Adrik', - 'Webb', - 'Toddrick', - 'Jerrett', - 'Omero', - 'Wendel', - 'Teresa', - 'Cass', - 'Kedric', - 'Heraclio', - 'Rainier', - 'Lakota', - 'Sanjuan', - 'Daymon', - 'Rodd', - 'Yancey', - 'Trampas', - 'Viviano', - 'Heith', - 'Bj', - 'Trevante', - 'Ildefonso', - 'Jaeger', - 'Jamarkus', - 'Remijio', - 'Desiderio', - 'Ausencio', - 'Alejo', - 'Keldrick', - 'Sigifredo', - 'Treavor', - 'Britain', - 'Macedonio', - 'Kourtney', - 'Gerrick', - 'Jousha', - 'Klinton', - 'Montreal', - 'Catlin', - 'Danner', - 'Eliberto', - 'Eliodoro', - 'Lonnell', - 'Michiel', - 'Hermilo', - 'Jackey', - 'Todrick', - 'Irineo', - 'Wenceslao', - 'Duaine', - 'Cleto', - 'Gaylan', - 'Derrel', - 'Nabor', - 'Huck', - 'Hoy', - 'Antwaun', - 'Hoyte', - 'Flournoy', - 'Mayford', - 'Harlie', - 'Hansford', - 'Cutler', - 'Amerigo', - 'Teague', - 'Griffith', - 'Emidio', - 'Kenna', - 'Cru', - 'Arnett', - 'Gay', - 'Dencil', - 'Carman', - 'Doy', - 'Trevan', - 'Jahziel', - 'Rodricus', - 'Copper', - 'Dael', - 'Aydon', - 'Ricco', - 'Judas', - 'Kessler', - 'Romelo', - 'Slayton', - 'Marico', - 'Leevi', - 'Xadrian', - 'Jceon', - 'Kross', - 'Chancey', - 'Bayne', - 'Brylen', - 'Eidan', - 'Olvin', - 'Pearce', - 'Zak', - 'Jaiven', - 'Dani', - 'Bairon', - 'Cordarious', - 'Jaxyn', - 'Rylin', - 'Avin', - 'Bransen', - 'Eastyn', - 'Eyden', - 'Brenham', - 'Chaston', - 'Horatio', - 'Dakarai', - 'Jencarlo', - 'Jevan', - 'Jhayden', - 'Tracen', - 'Peggy', - 'Wynn', - 'Bennet', - 'Milas', - 'Ronal', - 'Kadrian', - 'Jhase', - 'Callahan', - 'Hays', - 'Braidyn', - 'Ezana', - 'Chidubem', - 'Virat', - 'Maxemiliano', - 'Ozias', - 'Pace', - 'Mordecai', - 'Tabor', - 'Phillipe', - 'Maritza', - 'Ricahrd', - 'Jeanette', - 'Sundeep', - 'Tyric', - 'Mina', - 'Nasser', - 'Nhia', - 'Giuliano', - 'Farid', - 'Ryo', - 'Delmont', - 'Klaus', - 'Traquan', - 'Dawayne', - 'Broward', - 'Drequan', - 'Cagney', - 'Shellie', - 'Torre', - 'Deepak', - 'Janmichael', - 'Lan', - 'Quentavius', - 'Quantez', - 'Markevious', - 'Melbourne', - 'Melford', - 'Xue', - 'Samnang', - 'Jarquez', - 'Montrez', - 'Dao', - 'Luvern', - 'Vue', - 'Jenaro', - 'Wacey', - 'Lorena', - 'Ly', - 'Casmere', - 'Marsean', - 'Marinus', - 'Shiro', - 'Shizuo', - 'Knowledge', - 'Baudelio', - 'Cher', - 'Christiaan', - 'Adriane', - 'Wilgus', - 'Gustabo', - 'Barnet', - 'Xeng', - 'Priscilla', - 'Sou', - 'Sumeet', - 'Vartan', - 'Herschell', - 'Montell', - 'Illya', - 'Flem', - 'Marwan', - 'Johnrobert', - 'Boleslaus', - 'Christie', - 'Ericberto', - 'Esmeralda', - 'Cecilia', - 'Purvis', - 'Benjie', - 'Sutter', - 'Sufyan', - 'Viraaj', - 'Sathvik', - 'Quitman', - 'Liborio', - 'Humbert', - 'Zakariah', - 'Yichen', - 'Seward', - 'Alf', - 'Sebastiano', - 'Guiseppe', - 'Stanislaw', - 'Tyrice', - 'Lenell', - 'Kewon', - 'Bahe', - 'Recardo', - 'Paola', - 'Ronson', - 'Naveed', - 'Karla', - 'Lamberto', - 'Leoncio', - 'Sandor', - 'Diamante', - 'Woodson', - 'Hargis', - 'Kelcey', - 'Daquon', - 'Estell', - 'Christapher', - 'Jalal', - 'Tania', - 'Tramell', - 'Victoralfonso', - 'Kento', - 'Kiet', - 'Krystopher', - 'Shaine', - 'Bejamin', - 'Virgel', - 'Toxie', - 'Goebel', - 'Tyon', - 'Norvin', - 'Savalas', - 'Othmar', - 'Jakaiden', - 'Reis', - 'Pratik', - 'Ashish', - 'Hutson', - 'Karmello', - 'Dacari', - 'Katsuji', - 'Sadamu', - 'Masatoshi', - 'Kiyoto', - 'Carols', - 'Waylen', - 'Shain', - 'Alexandru', - 'Jomo', - 'Kalei', - 'Shyam', - 'Zyan', - 'Tamar', - 'Prem', - 'Jamiyl', - 'Remmel', - 'Harlin', - 'Novak', - 'Fynn', - 'Gonsalo', - 'Maliki', - 'Loghan', - 'Cauy', - 'Kassem', - 'Jitsuo', - 'Itsuo', - 'Atsushi', - 'Sunao', - 'Sueo', - 'Hiromu', - 'Toshiyuki', - 'Osamu', - 'Mena', - 'Aldin', - 'Leticia', - 'Darick', - 'Kawan', - 'Rajahn', - 'Asmar', - 'Emarion', - 'Hilmer', - 'Dameyune', - 'Rondarius', - 'Brinson', - 'Trason', - 'Chung', - 'Eran', - 'Khanh', - 'Javarious', - 'Makel', - 'Zyquan', - 'Quintarius', - 'Duran', - 'Veasna', - 'Thao', - 'Gracin', - 'Eberardo', - 'Ming', - 'Lusiano', - 'Kaveh', - 'Truong', - 'Ying', - 'Kentravious', - 'Dillen', - 'Jamonte', - 'Arthuro', - 'Camarion', - 'Avett', - 'Mehdi', - 'Nishant', - 'Bartek', - 'Aarnav', - 'Jeffory', - 'Deen', - 'Dayshaun', - 'Kemonte', - 'Petar', - 'Yug', - 'Donat', - 'Sylvio', - 'Magdiel', - 'Christianjames', - 'Lessie', - 'Sander', - 'Rajvir', - 'Nahuel', - 'Pearlie', - 'Aaren', - 'Dimitry', - 'Aravind', - 'Aristotle', - 'Jeury', - 'Naji', - 'Tysheem', - 'Alcee', - 'Gustaf', - 'Jamarrion', - 'Zollie', - 'Malick', - 'Navin', - 'Juwon', - 'Usama', - 'Walid', - 'Quamel', - 'Sadiq', - 'Tamarcus', - 'Merwyn', - 'Ferdie', - 'Kalif', - 'Latif', - 'Davidson', - 'Aahan', - 'Shahid', - 'Min', - 'Kieren', - 'Oz', - 'Oryan', - 'Madox', - 'Kota', - 'Gurshaan', - 'Gagik', - 'Finnigan', - 'Finlay', - 'Exodus', - 'Kaileb', - 'Jullien', - 'Jiovani', - 'Maryland', - 'Weaver', - 'Williard', - 'Keyondre', - 'Kailen', - 'Kanan', - 'Luisantonio', - 'Izack', - 'Daniela', - 'Colm', - 'Raja', - 'Keeshawn', - 'Adhemar', - 'Hillary', - 'Abdimalik', - 'Roark', - 'Kolston', - 'Cheryl', - 'Richardson', - 'Arif', - 'Jahkeem', - 'Kumar', - 'Raywood', - 'Jaiquan', - 'Earley', - 'Buren', - 'Rossie', - 'Jakayden', - 'Ruffus', - 'Zaquan', - 'Tamer', - 'Devonne', - 'Ikeem', - 'Dhruva', - 'Georges', - 'Kwabena', - 'Yeriel', - 'Glover', - 'Sanders', - 'Adonay', - 'Gillis', - 'Yomar', - 'Ediberto', - 'Antwane', - 'Isahi', - 'Haidyn', - 'Elizandro', - 'Markjoseph', - 'Jezreel', - 'Isayah', - 'Zedekiah', - 'Nikolay', - 'Jenner', - 'Uriyah', - 'Taiga', - 'Daniele', - 'Zacharie', - 'Joanne', - 'Manpreet', - 'Mohan', - 'Eliu', - 'Faraz', - 'Robah', - 'Isham', - 'Omarian', - 'Gagandeep', - 'Zeno', - 'Waddell', - 'Plato', - 'Quavon', - 'Talib', - 'Bascom', - 'Mayo', - 'Tequan', - 'Teron', - 'Anatole', - 'Tajh', - 'Algenis', - 'Liridon', - 'Kervens', - 'Yunior', - 'Kenson', - 'Wesly', - 'Antwann', - 'Zelig', - 'Demetrious', - 'Johnbenedict', - 'Josecarlos', - 'Kona', - 'Cj', - 'Atul', - 'Asaf', - 'Aleck', - 'Anthoni', - 'Anuar', - 'Gedalya', - 'Rafay', - 'Eyal', - 'Andry', - 'Natanel', - 'Nissim', - 'Jahdiel', - 'Jophy', - 'Rehaan', - 'Jhovani', - 'Maxximus', - 'Nain', - 'Yomtov', - 'Sheikh', - 'Demir', - 'Markos', - 'Mouhamadou', - 'Ousman', - 'Izreal', - 'Hadrian', - 'Aldrin', - 'Conlan', - 'Degan', - 'Toi', - 'Finneas', - 'Latroy', - 'Adon', - 'Antuan', - 'Elchonon', - 'Uzair', - 'Mohid', - 'Nazier', - 'Eliab', - 'Roc', - 'Pavan', - 'Yovanny', - 'Sinjin', - 'Tavoris', - 'Asiel', - 'Brayant', - 'Alexsandro', - 'Adrean', - 'Darel', - 'Olajuwon', - 'Corderro', - 'Tynan', - 'Xaiver', - 'Travaris', - 'Yonis', - 'Gerren', - 'Demon', - 'Furnell', - 'Juel', - 'Harish', - 'Raiyan', - 'Elia', - 'Elijha', - 'Gautham', - 'Arvind', - 'Audel', - 'Almer', - 'Djimon', - 'Jahi', - 'Gehrig', - 'Avant', - 'Arnell', - 'Eliaz', - 'Kaedon', - 'Jaedin', - 'Voshon', - 'Malachy', - 'Gilad', - 'Gabriele', - 'Riku', - 'Cameran', - 'Yoskar', - 'Jahfari', - 'Alexiz', - 'Javante', - 'Gregor', - 'Izel', - 'Donnovan', - 'Nikos', - 'Kodey', - 'Eytan', - 'Betzalel', - 'Dimitrius', - 'Chananya', - 'Graylin', - 'Samvel', - 'Yi', - 'Wassillie', - 'Kelechi', - 'Erroll', - 'Ardit', - 'Rahn', - 'Delaine', - 'Jule', - 'Idus', - 'Dessie', - 'Juda', - 'Levester', - 'Kiante', - 'Earnie', - 'Ihor', - 'Kapono', - 'Akoni', - 'Koamalu', - 'Sholem', - 'Howie', - 'Dariusz', - 'Hall', - 'Kekai', - 'Onix', - 'Ozie', - 'Liem', - 'Collis', - 'Lemon', - 'Hinton', - 'Guss', - 'Ronda', - 'Siddhartha', - 'Owyn', - 'Rye', - 'Riot', - 'Vander', - 'Selena', - 'Barnie', - 'Lewie', - 'Jaxiel', - 'Kaizen', - 'Haloa', - 'Dermot', - 'Misha', - 'Mister', - 'Nicholis', - 'Kevork', - 'Kia', - 'Houa', - 'Huriel', - 'Jesu', - 'Dionta', - 'Silvino', - 'Ivery', - 'Iokepa', - 'Geo', - 'Dex', - 'Izaan', - 'Jasraj', - 'Jakson', - 'Niel', - 'Avelardo', - 'Arjay', - 'Aran', - 'Alanzo', - 'Aidric', - 'Lomax', - 'Rawn', - 'Simmie', - 'Tonnie', - 'Yuto', - 'Mataio', - 'Nicodemus', - 'Maximilien', - 'Raider', - 'Ridley', - 'Orest', - 'Ramzi', - 'Kaikea', - 'Kamahao', - 'Kyrillos', - 'Mace', - 'Lyrik', - 'Lyon', - 'Lux', - 'Ashkan', - 'Jurgen', - 'Khachik', - 'Maher', - 'Jaccob', - 'Jagdeep', - 'Wash', - 'Simpson', - 'Macy', - 'Haylee', - 'Hope', - 'Katie', - 'Thurmon', - 'Savanna', - 'Zoey', - 'Atiba', - 'Dylann', - 'Kaylen', - 'Helio', - 'Geovannie', - 'Praneel', - 'Kamau', - 'Rhamel', - 'Knoah', - 'Harm', - 'Nyle', - 'Maveric', - 'Neithan', - 'Niklaus', - 'Lejon', - 'Wai', - 'Indigo', - 'Sayed', - 'Abdias', - 'Daniil', - 'Rashod', - 'Wren', - 'Chico', - 'Jamarri', - 'Leiland', - 'Ranvir', - 'Mavrick', - 'Matai', - 'Deveon', - 'Teyon', - 'Ramell', - 'Haik', - 'Dupree', - 'Emon', - 'Jermal', - 'Bayley', - 'Marshell', - 'Blouncie', - 'Larson', - 'Lorenz', - 'Jhovanny', - 'Jeffie', - 'Portia', - 'Adron', - 'Calogero', - 'Mathews', - 'Aundra', - 'Aariv', - 'Keniel', - 'Jameis', - 'Konstantin', - 'Khayden', - 'Manford', - 'Polo', - 'Chanel', - 'Brittani', - 'Kazuki', - 'Kaelen', - 'Alice', - 'Maya', - 'Madeleine', - 'Kiana', - 'Latasha', - 'Felicia', - 'Gabriella', - 'Bolivar', - 'Eileen', - 'Alister', - 'Aidenn', - 'Nina', - 'Ellington', - 'Alecsander', - 'Ja', - 'Jarmaine', - 'Kyriakos', - 'Apostolos', - 'Leshawn', - 'Shondell', - 'Matvey', - 'Savino', - 'Zakariye', - 'Dozier', - 'Holland', - 'Haruto', - 'Hendrik', - 'Allah', - 'Johnanthony', - 'Eliyah', - 'Champ', - 'Dastan', - 'Caliph', - 'Manish', - 'Agostino', - 'Kaio', - 'Avyaan', - 'Gerasimos', - 'Refujio', - 'Munir', - 'Abdurrahman', - 'Selso', - 'Epimenio', - 'Suhayb', - 'Jock', - 'Larwence', - 'Saadiq', - 'Lilburn', - 'Selestino', - 'Randi', - 'Nysir', - 'Harlyn', - 'Basir', - 'Kathy', - 'Teddie', - 'Luqman', - 'Tyhir', - 'Mubarak', - 'Ridwan', - 'Filemon', - 'Bergen', - 'Danney', - 'Eual', - 'Melburn', - 'Esiquio', - 'Cree', - 'Dorwin', - 'Naasir', - 'Ysmael', - 'Nirav', - 'Chuckie', - 'Lashaun', - 'Darris', - 'Blase', - 'Kiley', - 'Demarko', - 'Taiwan', - 'Lamon', - 'Corrie', - 'Feras', - 'Excell', - 'Cornelious', - 'Martinez', - 'Marvel', - 'Climmie', - 'Martrell', - 'Valley', - 'Lonie', - 'Jovante', - 'Lavante', - 'Lugene', - 'Cordarro', - 'Lacey', - 'Derrius', - 'Tedd', - 'Levell', - 'Linas', - 'Taras', - 'Toma', - 'Klint', - 'Gualberto', - 'Feliberto', - 'Tarrance', - 'Theran', - 'Lakeith', - 'Mearl', - 'Karry', - 'Denarius', - 'Dontarius', - 'Nikia', - 'Rakesh', - 'Not', - 'Darek', - 'Gery', - 'Ontario', - 'Jimi', - 'Shamarion', - 'Kedarius', - 'Jermarcus', - 'Amarie', - 'Kordae', - 'Montie', - 'Haleem', - 'Inocencio', - 'Brockton', - 'Yoshiaki', - 'Ponciano', - 'Silvester', - 'Derron', - 'Davaughn', - 'Urie', - 'Juanito', - 'Corky', - 'Pasqual', - 'Marilyn', - 'Morley', - 'Ayoub', - 'Eliasar', - 'Mickel', - 'Skylor', - 'Kewan', - 'Teon', - 'Rafal', - 'Devanta', - 'Rosco', - 'Tywon', - 'Evon', - 'Cleven', - 'Hardie', - 'Tori', - 'Trayvond', - 'Maaz', - 'Masashi', - 'Neno', - 'Kahari', - 'Terri', - 'Toru', - 'Jalynn', - 'Avonte', - 'Satchel', - 'Tanya', - 'Kalab', - 'Avetis', - 'Miko', - 'Kodiak', - 'Lang', - 'Leondre', - 'Purnell', - 'Harutyun', - 'Gorman', - 'Vong', - 'Shervin', - 'Soloman', - 'Sue', - 'Amandeep', - 'Amritpal', - 'Leonides', - 'Melecio', - 'Mikhael', - 'Estaban', - 'Arius', - 'Calix', - 'Gurtaj', - 'Dilraj', - 'Dillinger', - 'Aidden', - 'Shivansh', - 'Shravan', - 'Saud', - 'Yarel', - 'Riker', - 'Yareth', - 'Zeppelin', - 'Ladarious', - 'Lucan', - 'Terren', - 'Tustin', - 'Nicolaas', - 'Rakan', - 'Johnjoseph', - 'Hovanes', - 'Navjot', - 'Henrique', - 'Marsalis', - 'Karanveer', - 'Jeffren', - 'Khairi', - 'Haruki', - 'Jadden', - 'Iliya', - 'Hansen', - 'Srihan', - 'Sartaj', - 'Rishik', - 'Rishan', - 'Octavian', - 'Ranbir', - 'Padraic', - 'Tanush', - 'Tlaloc', - 'Cadarius', - 'Yared', - 'Vahan', - 'Lakai', - 'Fionn', - 'Eziah', - 'Emillio', - 'Hakob', - 'Gryphon', - 'Harsha', - 'Hiroto', - 'Nivaan', - 'Radin', - 'Nicasio', - 'Mael', - 'Lysander', - 'Rees', - 'Roemello', - 'Bretton', - 'Christoph', - 'Eliceo', - 'Armany', - 'Axell', - 'Bogdan', - 'Luan', - 'Aldon', - 'Aeson', - 'Adhvik', - 'Jese', - 'Blanca', - 'Crisanto', - 'Dietrich', - 'Tarin', - 'Yama', - 'Yia', - 'Omeed', - 'Arbie', - 'Shayn', - 'Ranferi', - 'Ricard', - 'Farmer', - 'Goble', - 'Herald', - 'Hager', - 'Elva', - 'Carlis', - 'Evertt', - 'Ledford', - 'Dequarius', - 'Hughie', - 'Burgess', - 'Kourosh', - 'Jaun', - 'Nicko', - 'Victorhugo', - 'Roverto', - 'Shadi', - 'Sopheak', - 'Acie', - 'Demar', - 'Carolina', - 'Vinal', - 'Earland', - 'Sergey', - 'Dayon', - 'Kwamaine', - 'Kerney', - 'Ola', - 'Welby', - 'Kyon', - 'Tyion', - 'Kiyon', - 'Neng', - 'Raquel', - 'Nadeem', - 'Terran', - 'Tin', - 'Rudi', - 'Murad', - 'Murrell', - 'Lenville', - 'Rondall', - 'Han', - 'Hovhannes', - 'Karapet', - 'Hamed', - 'Alasdair', - 'Agam', - 'Areg', - 'Ariston', - 'Askari', - 'Ayansh', - 'Byran', - 'Dolan', - 'Devonn', - 'Edith', - 'Christoffer', - 'Alaa', - 'Ashraf', - 'Rondle', - 'Tavarius', - 'Michaeljames', - 'Nichols', - 'Sonia', - 'Ryanchristopher', - 'Garo', - 'Hien', - 'Corin', - 'Dillin', - 'Jerid', - 'Jesusalberto', - 'Zeferino', - 'Gobel', - 'Tykeem', - 'Miking', - 'Juno', - 'Jiraiya', - 'Kailash', - 'Madix', - 'Lucciano', - 'Llewyn', - 'Leone', - 'Knight', - 'Dorse', - 'Oak', - 'Irie', - 'Brodi', - 'Hridhaan', - 'Coda', - 'Dekker', - 'Evren', - 'Eisen', - 'Eddison', - 'Donatello', - 'Happy', - 'Devron', - 'Suleiman', - 'Siddhanth', - 'Zorawar', - 'Zadkiel', - 'Waylan', - 'Valor', - 'Triton', - 'Govanni', - 'Angelus', - 'Ashvin', - 'Matthews', - 'Elver', - 'Brendin', - 'Rhea', - 'Jyron', - 'Matisse', - 'Karanvir', - 'Kenshin', - 'Saketh', - 'Trigo', - 'Wil', - 'Tyrick', - 'Trejon', - 'Manvir', - 'Sascha', - 'Samay', - 'Prabhjot', - 'Piers', - 'Arshia', - 'Karo', - 'Makani', - 'Ludwin', - 'Kean', - 'Nikoli', - 'Garlin', - 'Georgio', - 'Jyren', - 'Ledell', - 'Jayceion', - 'Wiltz', - 'Elgie', - 'Jediah', - 'Izzac', - 'Izeyah', - 'Jeyson', - 'Hamid', - 'Jalani', - 'Rohin', - 'Shiva', - 'Ramces', - 'Claudell', - 'Daymien', - 'Aeron', - 'Aadan', - 'Alesandro', - 'Aleksey', - 'Galileo', - 'Esvin', - 'Indy', - 'Graden', - 'Gor', - 'Vlad', - 'Kendrell', - 'Saket', - 'Asahel', - 'Blue', - 'Arshdeep', - 'Adain', - 'Keneth', - 'Jacy', - 'Dasan', - 'Haniel', - 'Ethin', - 'Ericson', - 'Izick', - 'Elisandro', - 'Coltrane', - 'Kemani', - 'Josearmando', - 'Josealfredo', - 'Alias', - 'Anurag', - 'Carlitos', - 'Ceaser', - 'Sukhraj', - 'Severin', - 'Nishanth', - 'Mattox', - 'Rhiley', - 'Dareon', - 'Danyel', - 'Calan', - 'Nithin', - 'Donivan', - 'Taye', - 'Trustin', - 'Igor', - 'Jayr', - 'Kayin', - 'Pleas', - 'Aadit', - 'Balam', - 'Jovannie', - 'Quintrell', - 'Japheth', - 'Hero', - 'Edu', - 'Duvan', - 'Anden', - 'Anshul', - 'Ailton', - 'Raybon', - 'Rabon', - 'Kendry', - 'Manases', - 'Damyan', - 'Braven', - 'Dhani', - 'Isaia', - 'Hovik', - 'Sonnie', - 'Wolfe', - 'Banyan', - 'Hiroki', - 'Matin', - 'Sequoia', - 'Acelin', - 'Aarya', - 'Arsalan', - 'Carlosdaniel', - 'Jaryd', - 'Ariana', - 'Kylee', - 'Mariah', - 'Serenity', - 'Kailey', - 'Delaney', - 'Emilee', - 'Isabelle', - 'Jayla', - 'Drue', - 'Emani', - 'Juandedios', - 'Kedar', - 'Baily', - 'Daijon', - 'Daman', - 'Kentaro', - 'Damaria', - 'Mareco', - 'Valmore', - 'Theophile', - 'Winslow', - 'Ugo', - 'Cainan', - 'Finian', - 'Keiji', - 'Issack', - 'Blanchard', - 'Domingos', - 'Jarin', - 'Giovan', - 'Ovila', - 'Lovelace', - 'Albion', - 'Curry', - 'Christophr', - 'Nolton', - 'Unborn', - 'Torry', - 'Yoshi', - 'Perrion', - 'Nathyn', - 'Syler', - 'Sheila', - 'Jaedan', - 'Cobey', - 'Bashar', - 'Ehsan', - 'Daryll', - 'Seann', - 'Niels', - 'Nazar', - 'Frederico', - 'Esther', - 'Bobie', - 'Loyce', - 'Heberto', - 'Bentura', - 'Jafar', - 'Keigan', - 'Bertil', - 'Aloys', - 'Janie', - 'Paz', - 'Damacio', - 'Oiva', - 'Ingvald', - 'Walfred', - 'Jakeob', - 'Georgie', - 'Alcuin', - 'Raynold', - 'Josey', - 'Lasaro', - 'Jo', - 'Hjalmer', - 'Philemon', - 'Paula', - 'Christophor', - 'Estanislao', - 'Angelita', - 'Anacleto', - 'Alfons', - 'Lawayne', - 'Delrico', - 'Clemson', - 'Jaleen', - 'Jerimy', - 'Javaughn', - 'Tiofilo', - 'Hubbard', - 'Abundio', - 'Derl', - 'Keagen', - 'Aymen', - 'Freedom', - 'Venancio', - 'Pauline', - 'Gorden', - 'Hani', - 'Pharrell', - 'Jager', - 'Nyair', - 'Azeem', - 'Khyir', - 'Jabriel', - 'Yandiel', - 'Zaahir', - 'Laine', - 'Xai', - 'Vernard', - 'Augie', - 'Sostenes', - 'Darryll', - 'Asir', - 'Lindon', - 'Jearl', - 'Peder', - 'Rudolpho', - 'Clancy', - 'Yue', - 'Ronnald', - 'Onofre', - 'Kysir', - 'Helmuth', - 'Marlowe', - 'Derk', - 'Demetrick', - 'Jefrey', - 'Burrell', - 'Robie', - 'Marlan', - 'Thane', - 'Jamire', - 'Donnel', - 'Syaire', - 'York', - 'Asaad', - 'Kyair', - 'Devere', - 'Wing', - 'Yaniv', - 'Mathhew', - 'Silvia', - 'Chia', - 'Bren', - 'Cavin', - 'Aldrich', - 'Judy', - 'Erron', - 'Butler', - 'Carole', - 'Almon', - 'Gilles', - 'Christin', - 'Renald', - 'Sony', - 'Chavis', - 'Nghia', - 'Mercedes', - 'Real', - 'Josejesus', - 'Ryman', - 'Kori', - 'Ichael', - 'Jabier', - 'Nguyen', - 'Angeldejesus', - 'Bobak', - 'Brittan', - 'Shaunt', - 'Karlton', - 'Jerin', - 'Gerado', - 'Raymund', - 'Kerolos', - 'Rolan', - 'Wilbern', - 'Sipriano', - 'Hermes', - 'Robyn', - 'Ynes', - 'Vernice', - 'Pink', - 'Jevonte', - 'Jerame', - 'Tajuan', - 'Mingo', - 'Jeremia', - 'Edmon', - 'Castulo', - 'Cleofas', - 'Arlee', - 'Oather', - 'Larkin', - 'Mcarther', - 'Ryann', - 'Hong', - 'Jamieson', - 'Enedino', - 'Gerad', - 'Lenord', - 'Alireza', - 'Hollie', - 'Gilford', - 'Lajuane', - 'Izell', - 'Trenidad', - 'Shelley', - 'Ulysees', - 'Juana', - 'Coalton', - 'Remer', - 'Raiford', - 'Caydon', - 'Dalyn', - 'Wilhelm', - 'Lenzy', - 'Bartow', - 'Tibor', - 'Cebert', - 'Elizar', - 'Ellen', - 'Uchenna', - 'Toy', - 'Curlee', - 'Ralf', - 'Giulio', - 'Conway', - 'Ngai', - 'Chaka', - 'Engelbert', - 'Auburn', - 'Socrates', - 'Kostas', - 'Kamalei', - 'Kupono', - 'Carrell', - 'Lister', - 'Mattie', - 'Thermon', - 'Tina', - 'Kennan', - 'Adison', - 'Dalon', - 'Ephram', - 'Jaylynn', - 'Zabdiel', - 'Kaidon', - 'Juvencio', - 'Havis', - 'Dagan', - 'Dacorian', - 'Donavyn', - 'Evyn', - 'Issai', - 'Zenon', - 'Inman', - 'Hason', - 'Lehman', - 'Afton', - 'Clayborn', - 'Abrahm', - 'Neill', - 'Conard', - 'Mutsuo', - 'Seikichi', - 'Wetzel', - 'Masaji', - 'Masanobu', - 'Shigeto', - 'Edgel', - 'Goro', - 'Lovett', - 'Seiko', - 'Sakae', - 'Roshawn', - 'Antjuan', - 'Erby', - 'Jobe', - 'Ladarian', - 'Cyler', - 'Edel', - 'Hartsel', - 'Jill', - 'Jami', - 'Rabun', - 'Fulton', - 'Dreddy', - 'Corrado', - 'Harald', - 'Alterick', - 'Hala', - 'Powell', - 'Lesly', - 'Kalon', - 'Theodoros', - 'Etan', - 'Trev', - 'Javiel', - 'Jusiah', - 'Joncarlos', - 'Jhamari', - 'Rasheim', - 'Raysean', - 'Kreg', - 'Rahmell', - 'Kerby', - 'Eliga', - 'Clemon', - 'Aneudy', - 'Keiran', - 'Kensley', - 'Ludie', - 'Jorell', - 'Can', - 'Demondre', - 'Cierra', - 'Maurizio', - 'Tacuma', - 'Ryzen', - 'Jabar', - 'Tara', - 'Reign', - 'Jashon', - 'Lasean', - 'Artavius', - 'Akbar', - 'Un', - 'Kaikane', - 'Tanisha', - 'Elena', - 'Bridget', - 'Asia', - 'Latisha', - 'Rachael', - 'Latoya', - 'Elisabeth', - 'Janelle', - 'Ikea', - 'Kobey', - 'Kamaehu', - 'Keona', - 'Calixto', - 'Theotis', - 'Worthy', - 'Galo', - 'Holly', - 'Sevyn', - 'Petr', - 'Cerrone', - 'Tedrick', - 'Kymari', - 'Gerrard', - 'Eldo', - 'Alcides', - 'Derrian', - 'Eulas', - 'Leodis', - 'Akai', - 'Dalonte', - 'Pantelis', - 'Sheron', - 'Tommaso', - 'Treg', - 'Shirl', - 'Abrian', - 'Brewer', - 'Yamir', - 'Zadok', - 'Holdyn', - 'Jayanthony', - 'Eh', - 'Dayson', - 'Khaden', - 'Quintez', - 'Rontavious', - 'Markese', - 'Quintavis', - 'Daveion', - 'Tonny', - 'Jaevon', - 'Ahkeem', - 'Hy', - 'Adams', - 'Marian', - 'Huner', - 'Jarmarcus', - 'Treyon', - 'Tullio', - 'Oreste', - 'Oleg', - 'Xzavien', - 'Atzel', - 'Brenan', - 'Abriel', - 'Braylyn', - 'Chidera', - 'Lebaron', - 'Jameir', - 'Kameryn', - 'Shade', - 'Koltin', - 'Cordarrius', - 'Amelio', - 'Demarquez', - 'Tarus', - 'Calob', - 'Dmarco', - 'Creek', - 'Amen', - 'Cylas', - 'Davyn', - 'Haygen', - 'Godric', - 'Garn', - 'Renardo', - 'Locke', - 'Lexington', - 'Mazin', - 'Othniel', - 'Kruze', - 'Jaxston', - 'Jaxten', - 'Jeziah', - 'Jettson', - 'Zebastian', - 'Sarim', - 'Jawuan', - 'Tremain', - 'Hassell', - 'Quartez', - 'Hawkins', - 'Riggs', - 'Rebel', - 'Nael', - 'Kaycen', - 'Kamsiyochukwu', - 'Kagen', - 'Jrue', - 'Jaydeen', - 'Azazel', - 'Ayson', - 'Cheston', - 'Aarian', - 'Chavez', - 'Void', - 'Zacariah', - 'Keena', - 'Antwuan', - 'Labarron', - 'Quamere', - 'Mikell', - 'Prestyn', - 'Savian', - 'Dayden', - 'Jaivion', - 'Geremiah', - 'Aidon', - 'Bralyn', - 'Gianncarlo', - 'Jarquavious', - 'Muriel', - 'Akshar', - 'Kadir', - 'Najir', - 'Neko', - 'Jahaad', - 'Jdyn', - 'Kashon', - 'Jaquil', - 'Wah', - 'Delmos', - 'Masuo', - 'Nobuichi', - 'Kiichi', - 'Jerone', - 'Tatsumi', - 'Damarian', - 'Elier', - 'Lansing', - 'Heinrich', - 'Hasson', - 'Larrie', - 'Phyllis', - 'Jamoni', - 'Zylen', - 'Demoni', - 'Harrel', - 'Levie', - 'Zaryan', - 'Orazio', - 'Seymore', - 'Florence', - 'Kolter', - 'Kemper', - 'Daelyn', - 'Haddon', - 'Syon', - 'Sair', - 'Filadelfio', - 'Marquavion', - 'Breylon', - 'Filimon', - 'Abie', - 'Cortavious', - 'Achille', - 'Dontrez', - 'Matty', - 'Darshawn', - 'Overton', - 'Bashir', - 'Kavan', - 'Caidan', - 'Braelen', - 'Param', - 'Kani', - 'Percival', - 'Hartley', - 'Erminio', - 'Candler', - 'Ulyssee', - 'Damontae', - 'Ellijah', - 'Cesare', - 'Eleanor', - 'Eustace', - 'Joachim', - 'Tarique', - 'Altin', - 'Tyleek', - 'Posey', - 'Awais', - 'Daivon', - 'Zi', - 'Hammad', - 'Meshulem', - 'Nickie', - 'Brehon', - 'Dacoda', - 'Kwamane', - 'Rafuel', - 'Mikai', - 'Hensel', - 'Thelbert', - 'Valerio', - 'Trevonte', - 'Koran', - 'Cheick', - 'Shahzaib', - 'Tahsin', - 'Derry', - 'Mustapha', - 'Chucky', - 'Osborne', - 'Daquarius', - 'Marque', - 'Raquon', - 'Cherokee', - 'Keyshaun', - 'Mohamadou', - 'Keishawn', - 'Jahmeek', - 'Junaid', - 'Amil', - 'Mckoy', - 'Zackry', - 'Nyheim', - 'Nkosi', - 'Kweli', - 'Tydarius', - 'Umer', - 'Demorris', - 'Demarquis', - 'Hersch', - 'Luzer', - 'Li', - 'Aly', - 'Quade', - 'Quamaine', - 'Markee', - 'Jhoan', - 'Mert', - 'Supreme', - 'Tyheem', - 'Gomer', - 'Taseen', - 'Yousaf', - 'Yonason', - 'Gifford', - 'Ashar', - 'Sender', - 'Salah', - 'Saifan', - 'Raihan', - 'Nizar', - 'Abrahim', - 'Kunga', - 'Javis', - 'Evens', - 'Bayard', - 'Kaysan', - 'Padraig', - 'Ney', - 'Ahmet', - 'Misty', - 'Ayyan', - 'Saint', - 'Fern', - 'Wasil', - 'Nolie', - 'Zarif', - 'Younis', - 'Eesa', - 'Ketrick', - 'Veryl', - 'Refael', - 'Motty', - 'Naftuly', - 'Waseem', - 'Yusif', - 'Brigg', - 'Zaheer', - 'Shiya', - 'Karma', - 'Meilich', - 'Mihran', - 'Javares', - 'Efe', - 'Abubakr', - 'Avrumi', - 'Nayshawn', - 'Mostafa', - 'Hinckley', - 'Jahmeir', - 'Fintan', - 'Sollie', - 'Amiel', - 'Abu', - 'Yaro', - 'Josha', - 'Jermane', - 'Bertis', - 'Hernando', - 'Gerrod', - 'Haim', - 'Frandy', - 'Andrews', - 'Dayle', - 'Fleming', - 'Volvi', - 'Savior', - 'Shuford', - 'Plummer', - 'Ralston', - 'Dayvion', - 'Muhamed', - 'Naheem', - 'Nataniel', - 'Kaeleb', - 'Billyjoe', - 'Able', - 'Fareed', - 'Purcell', - 'Trayson', - 'Mackay', - 'Moyer', - 'Haynes', - 'Domnick', - 'Burnie', - 'Gleen', - 'Leavy', - 'Lennart', - 'Breken', - 'Arlind', - 'Clarnce', - 'Nissen', - 'Josiel', - 'Alvester', - 'Jaquay', - 'Nickolaos', - 'Ruddy', - 'Berkeley', - 'Flamur', - 'Sherif', - 'Shateek', - 'Ayodele', - 'Davone', - 'Meshach', - 'Kinston', - 'Algernon', - 'Dvonte', - 'Jawara', - 'Zamar', - 'Dayron', - 'Jaequan', - 'Tyrelle', - 'Jazion', - 'Tamel', - 'Torris', - 'Marguis', - 'Yuniel', - 'Saige', - 'Gottlieb', - 'Cori', - 'Dre', - 'Yordan', - 'Shaquell', - 'Jonel', - 'Kashaun', - 'Arjenis', - 'Tashan', - 'Fitzroy', - 'Francisc', - 'Kwaku', - 'Jakyri', - 'Trayton', - 'Jarrick', - 'Reginaldo', - 'Facundo', - 'Elma', - 'Dardan', - 'Dreshawn', - 'Demontray', - 'Chaddrick', - 'Roper', - 'Taariq', - 'Ausitn', - 'Jachai', - 'Duval', - 'Braun', - 'Taylan', - 'Dionis', - 'Samy', - 'Armistead', - 'Alize', - 'Tayshon', - 'Ainsley', - 'Kaheem', - 'Jaire', - 'Kyshawn', - 'Nahshon', - 'Aaliyah', - 'Shanard', - 'Azion', - 'Alana', - 'Alexia', - 'Breyon', - 'Trigg', - 'Wylder', - 'Zaydin', - 'Ziaire', - 'Zixuan', - 'Yanis', - 'Zair', - 'Zaven', - 'Alanmichael', - 'Viyan', - 'Vivan', - 'Klay', - 'Erico', - 'Tycho', - 'Waris', - 'Winter', - 'Aliyah', - 'Kamilo', - 'Kei', - 'Glendell', - 'Lilly', - 'Lauryn', - 'Jovian', - 'Shayla', - 'Tessa', - 'Jupiter', - 'Aaric', - 'Aadhav', - 'Jetson', - 'Abir', - 'Adhrit', - 'Alexandr', - 'Brooklynn', - 'Callie', - 'Ashlee', - 'Ashlyn', - 'Haleigh', - 'Heaven', - 'Jahkari', - 'Izaiyah', - 'Troyce', - 'Bige', - 'Hayze', - 'Neldon', - 'Marven', - 'Beckem', - 'Dvante', - 'Navarro', - 'Neiko', - 'Noeh', - 'Jen', - 'Torrian', - 'Helios', - 'Macallan', - 'Lio', - 'Wilkens', - 'Merrik', - 'Ameal', - 'Mujtaba', - 'Iktan', - 'Kavious', - 'Monterrio', - 'Hughey', - 'Calin', - 'Cali', - 'Jamaar', - 'Kenith', - 'Rihaan', - 'Deaglan', - 'Kelso', - 'Lavaris', - 'Ashot', - 'Marshun', - 'Rainer', - 'Rivan', - 'Talal', - 'Taiyo', - 'Minor', - 'Yvon', - 'Stonewall', - 'Merril', - 'Okie', - 'Trevino', - 'Imari', - 'Ithan', - 'Izmael', - 'Jayan', - 'Harut', - 'Harshaan', - 'Kainen', - 'Kalyan', - 'Kanishk', - 'Kotaro', - 'Josyah', - 'Vola', - 'Omarie', - 'Dmari', - 'Mannix', - 'Elad', - 'Shun', - 'Andriy', - 'Angelino', - 'Ary', - 'Axcel', - 'Becker', - 'Daxten', - 'Daemian', - 'Cypress', - 'Jakhai', - 'Warnie', - 'Maikel', - 'Davinci', - 'Calloway', - 'Vernal', - 'Tyrome', - 'Mont', - 'Ovie', - 'Hester', - 'Arvis', - 'Corbit', - 'Tarvaris', - 'Audra', - 'Cloud', - 'Taveon', - 'Balian', - 'Bodi', - 'Brodee', - 'Kainan', - 'Dezi', - 'Devesh', - 'Emad', - 'Esa', - 'Massie', - 'Moir', - 'Markavious', - 'Veachel', - 'Dalan', - 'Carles', - 'Antawn', - 'Jermichael', - 'Talin', - 'Sy', - 'Murrel', - 'Elster', - 'Kru', - 'Okley', - 'Maverik', - 'Diangelo', - 'Burns', - 'Jamaris', - 'Jayshaun', - 'Dantae', - 'Rahil', - 'Renny', - 'Rohith', - 'Strummer', - 'Birchel', - 'Astor', - 'Nolyn', - 'Neeko', - 'Reyan', - 'Kailan', - 'Jaideep', - 'Manveer', - 'Maeson', - 'Khris', - 'Lancelot', - 'Shaunak', - 'Shubham', - 'Siaosi', - 'Ruslan', - 'Sajan', - 'Renwick', - 'Yann', - 'Vitali', - 'Zealand', - 'Vyom', - 'Xabi', - 'Yazid', - 'Terrelle', - 'Oaks', - 'Kache', - 'Arjuna', - 'Cephas', - 'Holmes', - 'Rockie', - 'Elray', - 'Doc', - 'Mell', - 'Tyresse', - 'Maguire', - 'Sheddrick', - 'Loney', - 'Helaman', - 'Andrus', - 'Asberry', - 'Love', - 'Clebert', - 'Cashius', - 'Egypt', - 'Devansh', - 'Elige', - 'Tobe', - 'Taten', - 'Arias', - 'Leandrew', - 'Dekota', - 'Varian', - 'Lehi', - 'Colbert', - 'Ignace', - 'Suhas', - 'Syris', - 'Ahan', - 'Aithan', - 'Aiven', - 'Akshath', - 'Hamp', - 'Kato', - 'Leeon', - 'Reubin', - 'Lukah', - 'Wilmon', - 'Tait', - 'Theophilus', - 'Sion', - 'Maysen', - 'Nicoli', - 'Nason', - 'Mykell', - 'Montae', - 'Laszlo', - 'Lestat', - 'Prithvi', - 'Maxi', - 'Mekhai', - 'Hammond', - 'Atiksh', - 'Aldean', - 'Aldine', - 'Jedi', - 'Almond', - 'Edahi', - 'Hisham', - 'Clide', - 'Cosby', - 'Hayato', - 'Harnoor', - 'Gurjot', - 'Ethridge', - 'Dublin', - 'Daimian', - 'Derreon', - 'Hansell', - 'Mae', - 'Semisi', - 'Ulysess', - 'Render', - 'Eschol', - 'Rodell', - 'Atzin', - 'Alik', - 'Amiri', - 'Keyvon', - 'Noland', - 'Terius', - 'Isauro', - 'Harshith', - 'Pledger', - 'Tilman', - 'Lennis', - 'Jovin', - 'Jaymin', - 'Jaydee', - 'Asbury', - 'Lovie', - 'Mcclinton', - 'Grayton', - 'Cardin', - 'Jacey', - 'Gurveer', - 'Ethanmatthew', - 'Aaronjames', - 'Ascher', - 'Aarion', - 'Windle', - 'Jahan', - 'Jayen', - 'Jatin', - 'Jedrek', - 'Anthonyjr', - 'Dabney', - 'Galvin', - 'Ilijah', - 'Gohan', - 'Quaid', - 'Teancum', - 'Chael', - 'Chetan', - 'Cylis', - 'Manas', - 'Logun', - 'Karston', - 'Mickeal', - 'Iskander', - 'Isaah', - 'Aryaman', - 'Juvens', - 'Joncarlo', - 'Gurkirat', - 'Laymon', - 'Salesi', - 'Rion', - 'Tao', - 'Tadhg', - 'Stephens', - 'Terryl', - 'Jacquan', - 'Zubin', - 'Yul', - 'Yadriel', - 'Dolph', - 'Keiden', - 'Koston', - 'Demetre', - 'Kameren', - 'Kaedin', - 'Zebedee', - 'Tyrie', - 'Truth', - 'Lanorris', - 'Tilden', - 'Tidus', - 'Thelonious', - 'Tennessee', - 'Sirius', - 'Pervis', - 'Saatvik', - 'Adley', - 'Amarian', - 'Numa', - 'Bronco', - 'Zian', - 'Zephan', - 'Yaziel', - 'Ajit', - 'Arick', - 'Ollin', - 'Kort', - 'Tayvin', - 'Grason', - 'Leonid', - 'Nihaal', - 'Koah', - 'Southern', - 'Kavish', - 'Joeziah', - 'Javi', - 'Kaiyan', - 'Kyro', - 'Ziad', - 'Maxen', - 'Xion', - 'Mica', - 'Mansour', - 'Matteus', - 'Renner', - 'Jonan', - 'Shilo', - 'Josedaniel', - 'Kaj', - 'Robel', - 'Krithik', - 'Lautaro', - 'Evann', - 'Carden', - 'Nathaneal', - 'Wirt', - 'Kile', - 'Kevonte', - 'Jazz', - 'Vardan', - 'Tanav', - 'Tamim', - 'Ojani', - 'Raydel', - 'Rigel', - 'Sheamus', - 'Cameryn', - 'Jedd', - 'Dalessandro', - 'Daejon', - 'Zacheriah', - 'Jt', - 'Valeria', - 'Treshon', - 'Martynas', - 'Markeese', - 'Ladislado', - 'Fidensio', - 'Cincere', - 'Amonte', - 'Erion', - 'Emin', - 'Tayten', - 'Zachory', - 'Ysidoro', - 'Treshaun', - 'Franciszek', - 'Adit', - 'Neftaly', - 'Kaylan', - 'Dezmon', - 'Joby', - 'Terrick', - 'Irma', - 'Isiaha', - 'Micha', - 'Sylvia', - 'Dejan', - 'Kippy', - 'Tyreece', - 'Corie', - 'Martese', - 'Senovio', - 'Lexus', - 'Freddrick', - 'Jemarcus', - 'Kuba', - 'Corion', - 'Andrian', - 'Romualdo', - 'Lyndal', - 'Kalem', - 'Laderrick', - 'Jobin', - 'Chaise', - 'Naren', - 'Reynol', - 'Ohm', - 'Trashawn', - 'Danyell', - 'Diron', - 'Kameran', - 'Dunte', - 'Ikechukwu', - 'Trendon', - 'Visente', - 'Valeriano', - 'Dillian', - 'Chantz', - 'Bacilio', - 'Crescencio', - 'Policarpio', - 'Janice', - 'Kem', - 'Rutilio', - 'Jaqualin', - 'Kendon', - 'Keevin', - 'Adelaido', - 'Coltan', - 'Theodoro', - 'Devondre', - 'Dekendrick', - 'Deionte', - 'Taz', - 'Jimmey', - 'Cristan', - 'Chancelor', - 'Ascension', - 'Kemon', - 'Makari', - 'Cordel', - 'Colbey', - 'Ambrocio', - 'Marselino', - 'Dewain', - 'Graciano', - 'Gumecindo', - 'Lorenso', - 'Quaylon', - 'Halbert', - 'Celedonio', - 'Terrin', - 'Zuri', - 'Sherod', - 'Ermal', - 'Elisa', - 'Larnell', - 'Tully', - 'Wenceslaus', - 'Lashun', - 'Duan', - 'Correy', - 'Wilburt', - 'Antwoin', - 'Lynell', - 'Ramond', - 'Victorio', - 'Antion', - 'Dragan', - 'Priest', - 'Marice', - 'Laroy', - 'Ninos', - 'Byrl', - 'Ebert', - 'Keita', - 'Dimitris', - 'Zoran', - 'Khaalis', - 'Rollo', - 'Alwin', - 'Loraine', - 'Jerard', - 'Lyndle', - 'Quirino', - 'Ramey', - 'Jarian', - 'Marky', - 'Adlai', - 'Shamon', - 'Treyshawn', - 'Shaft', - 'Gumercindo', - 'Rita', - 'Derryl', - 'Chancy', - 'Kacy', - 'Jonothan', - 'Ruston', - 'Ranulfo', - 'Talik', - 'Johntae', - 'Kendale', - 'Diandre', - 'Reginold', - 'Tyris', - 'Davell', - 'Ladell', - 'Raymone', - 'Mariusz', - 'Edvardo', - 'Joh', - 'Lavontae', - 'Markie', - 'Laquinton', - 'Alexandar', - 'Divante', - 'Jabin', - 'Shawon', - 'Jawann', - 'Ladd', - 'Khali', - 'Gilmore', - 'Oliverio', - 'Thuan', - 'Daiel', - 'Kierre', - 'Javar', - 'Stevon', - 'Derius', - 'Chadley', - 'Manual', - 'Johnaton', - 'Lc', - 'Erek', - 'Jakaden', - 'Jden', - 'Drayke', - 'Dawsen', - 'Jadarion', - 'Shriyans', - 'Raylin', - 'Kaydan', - 'Lynden', - 'Duard', - 'Elo', - 'Amarius', - 'Cleburne', - 'Dailen', - 'Brance', - 'Braycen', - 'Daiden', - 'Cruzito', - 'Caedyn', - 'Aizik', - 'Abyan', - 'Felisiano', - 'Taevion', - 'Zaeden', - 'Zadrian', - 'Fredie', - 'Burnis', - 'Cleave', - 'Ki', - 'Quandarius', - 'Quavion', - 'Makell', - 'Myrl', - 'Tae', - 'Melik', - 'Samarion', - 'Branton', - 'Vollie', - 'Reynolds', - 'Draylon', - 'Keivon', - 'Kevontae', - 'Deundre', - 'Zaydrian', - 'Zaydan', - 'Jotham', - 'Janthony', - 'Sahid', - 'Keilon', - 'Lain', - 'Kenechukwu', - 'Kanaan', - 'Kamdon', - 'Ahmod', - 'Dong', - 'Nnamdi', - 'Jontavius', - 'Kelijah', - 'Searcy', - 'Wheeler', - 'Francisca', - 'Burrel', - 'Zyquavious', - 'Kortez', - 'Tres', - 'Tranquilino', - 'Guinn', - 'Hiawatha', - 'Jasiyah', - 'Arlos', - 'Celestine', - 'Deadrian', - 'Chinedu', - 'Cane', - 'Caedon', - 'Gabryel', - 'Garon', - 'Solon', - 'Udell', - 'Medardo', - 'Chon', - 'Zakk', - 'Trip', - 'Somtochukwu', - 'Shooter', - 'Frutoso', - 'Laurencio', - 'Izayiah', - 'Franko', - 'Izzak', - 'Braelan', - 'Dryden', - 'Wilborn', - 'Newt', - 'Petronilo', - 'Nathanel', - 'Jatavius', - 'Locadio', - 'Tyquez', - 'Laiden', - 'Allister', - 'Javarion', - 'Demarrio', - 'Shenouda', - 'Rodriques', - 'Jenard', - 'Azarias', - 'Axxel', - 'Ariyan', - 'Pate', - 'Raidyn', - 'Saylor', - 'Kreed', - 'Kayce', - 'Bray', - 'Zyren', - 'Zayvien', - 'Yeiden', - 'Kinta', - 'Trampus', - 'Lofton', - 'Zayvian', - 'Zaydon', - 'Zaidan', - 'Weslee', - 'Robben', - 'Rook', - 'Roston', - 'Trigger', - 'Steel', - 'Rustyn', - 'Jaeceon', - 'Hutton', - 'Hatcher', - 'Kartier', - 'Kallan', - 'Daxtyn', - 'Corvin', - 'Deklyn', - 'Kaveon', - 'Leviathan', - 'Leelan', - 'Lael', - 'Prynce', - 'Korban', - 'Khyren', - 'Omran', - 'Oluwademilade', - 'Orenthal', - 'Dequavius', - 'Quinterrius', - 'Quantavis', - 'Astin', - 'Asaiah', - 'Dace', - 'Brylee', - 'Kenyan', - 'Jeovani', - 'Kolson', - 'Dreyden', - 'Jujuan', - 'Gregoria', - 'Abdon', - 'Javious', - 'Latravious', - 'Nanya', - 'Kaleel', - 'Elsie', - 'Iris', - 'Javarus', - 'Hunner', - 'Ebubechukwu', - 'Ashaz', - 'Huntley', - 'Montravious', - 'Argelio', - 'Amaar', - 'Abdulmalik', - 'Deronte', - 'Ramirez', - 'Travius', - 'Xavius', - 'Rashamel', - 'Martice', - 'Oshay', - 'Jamerson', - 'Derico', - 'Benino', - 'Otilio', - 'Palani', - 'Trystin', - 'Domonick', - 'Jayron', - 'Josephine', - 'Dora', - 'Larence', - 'Feliz', - 'Tereso', - 'Natalio', - 'Olga', - 'Bralen', - 'Temple', - 'Keala', - 'Anita', - 'Eathen', - 'Lamond', - 'Jakobie', - 'Johnthan', - 'Elnathan', - 'Edris', - 'Alcario', - 'Cornie', - 'Ival', - 'Pantaleon', - 'Deavion', - 'Daevion', - 'Dorance', - 'Jailon', - 'Ragene', - 'Kaena', - 'Kaimipono', - 'Keaka', - 'Kiai', - 'Babygirl', - 'Aukai', - 'Kaitlin', - 'Kaikoa', - 'Jedadiah', - 'Pono', - 'Layth', - 'Kolbie', - 'Naaman', - 'Pacey', - 'Jearld', - 'Corinthian', - 'Bryceson', - 'Kayzen', - 'Mana', - 'Janee', - 'Janae', - 'Kelli', - 'Tamara', - 'Nora', - 'Sophie', - 'Rashida', - 'Princess', - 'Lakeisha', - 'Nadia', - 'Monet', - 'Meaghan', - 'Marquita', - 'Chiquita', - 'Charlotte', - 'Chantelle', - 'Cassandra', - 'Cara', - 'Brandi', - 'Asha', - 'Tatiana', - 'Haaheo', - 'Valerie', - 'Valencia', - 'Shoso', - 'Yoshimi', - 'Bristol', - 'Mikio', - 'Nobuyuki', - 'Tomio', - 'Kazumi', - 'Kunio', - 'Yoshiharu', - 'Balentin', - 'Paublo', - 'Nobuyoshi', - 'Toshiaki', - 'Matsuo', - 'Hachiro', - 'Tokio', - 'Eichi', - 'Manabu', - 'Masanori', - 'Yoshiyuki', - 'Tokuo', - 'Eustolio', - 'Petra', - 'Fukuichi', - 'Haruyoshi', - 'Eastin', - 'Keygan', - 'Kelin', - 'Lalo', - 'Ramona', - 'Felis', - 'Rodgers', - 'Deigo', - 'Guerin', - 'Arrington', - 'Bradin', - 'Aurora', - 'Calistro', - 'Ervie', - 'Velma', - 'Whit', - 'Adarian', - 'Jakevion', - 'Jadrien', - 'Calub', - 'Kaegan', - 'Jamorian', - 'Milam', - 'Usiel', - 'Drayven', - 'Orange', - 'Daelon', - 'Jatavion', - 'Vastine', - 'Preciliano', - 'Floyce', - 'Billye', - 'Burney', - 'Consepcion', - 'Dason', - 'Osie', - 'Tashaun', - 'Sajid', - 'Umair', - 'Tymarion', - 'Jakorian', - 'Ginobili', - 'Areeb', - 'Jonovan', - 'Jonavan', - 'Jaqualyn', - 'Billey', - 'Luisgustavo', - 'Lamario', - 'Telford', - 'Lekendrick', - 'Brinton', - 'Lebarron', - 'Marrio', - 'Tyshun', - 'Kendarrius', - 'Zylan', - 'Jarrius', - 'Kadarrius', - 'Marvis', - 'Orie', - 'Kimber', - 'Jakevious', - 'Shawndale', - 'Jakel', - 'Jaquarious', - 'Deakon', - 'Brevan', - 'Rochester', - 'Lemmie', - 'Athony', - 'Rosie', - 'Lillie', - 'Mozell', - 'Aubert', - 'Kimble', - 'Jaymon', - 'Gaza', - 'Lysle', - 'Wasco', - 'Zigmond', - 'Addie', - 'Erastus', - 'Claudius', - 'Audley', - 'Thadeus', - 'Exum', - 'Caldwell', - 'Emmert', - 'Teagen', - 'Royden', - 'Mykale', - 'Lindberg', - 'Elmon', - 'Norfleet', - 'Radford', - 'Romulus', - 'Thedore', - 'Cor', - 'Ledarrius', - 'Cyncere', - 'Hurbert', - 'Pearly', - 'Jobie', - 'Garvey', - 'Meade', - 'Casmir', - 'Bertie', - 'Belvin', - 'Lynford', - 'Verdun', - 'Junie', - 'Dover', - 'Harlee', - 'Romolo', - 'Sirr', - 'Bradey', - 'Kingsten', - 'Manuelito', - 'Leno', - 'Primo', - 'Antonie', - 'Jane', - 'Halsey', - 'Mujahid', - 'Quron', - 'Cleophas', - 'Amedio', - 'Gildo', - 'Norvel', - 'Livingston', - 'Norvell', - 'Fard', - 'Khaleef', - 'Dorr', - 'Chaquille', - 'Giro', - 'Verdell', - 'Concetto', - 'Taevon', - 'Amato', - 'Hasaan', - 'Burr', - 'Payten', - 'Baden', - 'Abdirizak', - 'Emran', - 'Abdurahman', - 'Greig', - 'Sabree', - 'Shymir', - 'Haakon', - 'Aasim', - 'Abdifatah', - 'Cheemeng', - 'Yuepheng', - 'Hamsa', - 'Abdalla', - 'Samatar', - 'Joshawa', - 'Leeman', - 'Hershal', - 'Fayette', - 'Patty', - 'Thom', - 'Yaaseen', - 'Alven', - 'Hillis', - 'Bard', - 'Nymir', - 'Imir', - 'Mohamud', - 'Muaad', - 'Mickael', - 'Hermann', - 'Varner', - 'Norm', - 'Suheyb', - 'Eivin', - 'Jamy', - 'Taro', - 'Caydin', - 'Masaharu', - 'Cassie', - 'Virgie', - 'Oddie', - 'Pamela', - 'Emmette', - 'Rayshon', - 'Vardaman', - 'Ruble', - 'Clance', - 'Rigdon', - 'Osborn', - 'Gina', - 'Rozell', - 'Marcy', - 'Farron', - 'Bartolomeo', - 'Dierre', - 'Demetrus', - 'Yoneo', - 'Blayke', - 'Decarlo', - 'Sebert', - 'Quayon', - 'Nihar', - 'Segundo', - 'Ritik', - 'Aljaquan', - 'Lealon', - 'Opie', - 'Darshan', - 'Trapper', - 'Ladarrion', - 'Thaine', - 'Abanoub', - 'Filipe', - 'Oley', - 'Zaylan', - 'Rushi', - 'Watie', - 'Cleatus', - 'Harshil', - 'Alferd', - 'Carthel', - 'Ogden', - 'Carmin', - 'Hiren', - 'Harl', - 'Drexel', - 'Shadeed', - 'Malvern', - 'Argus', - 'Sharief', - 'Almalik', - 'Audy', - 'Terral', - 'Nuno', - 'Verna', - 'Alim', - 'Sherron', - 'Terek', - 'Clardie', - 'Shadee', - 'Clendon', - 'Johnpatrick', - 'Chritopher', - 'Taheem', - 'Jahid', - 'Waitman', - 'Jabraylen', - 'Quasim', - 'Azim', - 'Eulis', - 'Wladyslaw', - 'Delmus', - 'Minter', - 'Kharter', - 'Zavhary', - 'Taji', - 'Hoskie', - 'Colsen', - 'Orlanda', - 'Shawntez', - 'Obryan', - 'Emanual', - 'Silviano', - 'Chrishawn', - 'Rayon', - 'Martino', - 'Fairley', - 'Lenward', - 'Autzen', - 'Selby', - 'Odus', - 'Redell', - 'Seavy', - 'Dennison', - 'Jamiere', - 'Rondy', - 'Donold', - 'Lindwood', - 'Laudie', - 'Obert', - 'Jahki', - 'Braidon', - 'Zalen', - 'Zymier', - 'Jahzir', - 'Nahsir', - 'Vikrant', - 'Shourya', - 'Eliyohu', - 'Tyheim', - 'Keyshon', - 'Kaydence', - 'Ekin', - 'Tresean', - 'Quendarius', - 'Shammond', - 'Malakye', - 'Findlay', - 'Ashrith', - 'Elfego', - 'Jalik', - 'Nyzir', - 'Boe', - 'Abdikadir', - 'Jameek', - 'Gyasi', - 'Khyri', - 'Mohit', - 'Shayquan', - 'Sivan', - 'Steffon', - 'Lord', - 'Leor', - 'Kujtim', - 'Haaris', - 'Rafid', - 'Nechemia', - 'Nyles', - 'Khalik', - 'Tysheen', - 'Shaheim', - 'Starling', - 'Taiquan', - 'Takeem', - 'Teshawn', - 'Tuvia', - 'Shu', - 'Schyler', - 'Indalecio', - 'Edouard', - 'Alverto', - 'Alexio', - 'Aurash', - 'Fabiola', - 'Firas', - 'Fredis', - 'Guthrie', - 'Babacar', - 'Ayinde', - 'Khallid', - 'Shadrach', - 'Rikki', - 'Prescott', - 'Saam', - 'Perla', - 'Michell', - 'Markis', - 'Nou', - 'Sher', - 'Tor', - 'Kyre', - 'Shykeem', - 'Jilberto', - 'Klye', - 'Jeramey', - 'Herber', - 'Kue', - 'Mainor', - 'Macaulay', - 'Jequan', - 'Bond', - 'Hykeem', - 'Husam', - 'Catalina', - 'Danh', - 'Aaronmichael', - 'Anthonyjames', - 'Jerrid', - 'Jobani', - 'Kenia', - 'Oshae', - 'Michaelvincent', - 'Mong', - 'Dawit', - 'Dabid', - 'Daisuke', - 'Geddy', - 'Ehab', - 'Jarmal', - 'Caelin', - 'Barak', - 'Gurtej', - 'Geordan', - 'Jacobb', - 'Estefani', - 'Esaul', - 'Karandeep', - 'Jevaughn', - 'Kassim', - 'Kion', - 'Vikas', - 'Infinite', - 'Yekusiel', - 'Zohaib', - 'Yaw', - 'Sakib', - 'Shah', - 'Zeshan', - 'Hassaan', - 'Masai', - 'Mattheus', - 'Jeniel', - 'Martine', - 'Maalik', - 'Jeanclaude', - 'Stirling', - 'Trayveon', - 'Paymon', - 'Ajai', - 'Habib', - 'Enis', - 'Grafton', - 'Nissan', - 'Oshane', - 'Mirza', - 'Malike', - 'Yianni', - 'Zachari', - 'Tadeh', - 'Patrik', - 'Richy', - 'Riki', - 'Yao', - 'Yadira', - 'Nylan', - 'Lennard', - 'Roldan', - 'Admir', - 'Oniel', - 'Addam', - 'Itzel', - 'Ivann', - 'Shabab', - 'Honorio', - 'Hrag', - 'Harutun', - 'Keano', - 'Kayvan', - 'Takahiro', - 'Juanfrancisco', - 'Eri', - 'Ermon', - 'Ramzy', - 'Selma', - 'Kasean', - 'Obrian', - 'Jonatha', - 'Jonahtan', - 'Davione', - 'Chandara', - 'Chantha', - 'Lo', - 'Loreto', - 'Derell', - 'Ganesh', - 'Janathan', - 'Alejandr', - 'Rodolphe', - 'Isaul', - 'Bejan', - 'Doron', - 'Yvette', - 'Erlon', - 'Erland', - 'Yuji', - 'Milagro', - 'Ndrew', - 'Pedram', - 'Thinh', - 'Vandy', - 'Vi', - 'Ryanjoseph', - 'Richar', - 'Hosey', - 'Adeel', - 'Nicholos', - 'Michaeljohn', - 'Philipe', - 'Bravlio', - 'Anup', - 'Davide', - 'Daquann', - 'Lequan', - 'Raymel', - 'Rahsean', - 'Woodley', - 'Jarmel', - 'Wiliam', - 'Joseh', - 'Somnang', - 'Colvin', - 'Jenkins', - 'Jaquawn', - 'Javonne', - 'Javed', - 'Joelle', - 'Lameek', - 'Kishawn', - 'Krikor', - 'Christipher', - 'Ghassan', - 'Essa', - 'Hovig', - 'Nayquan', - 'Shawndell', - 'Rawle', - 'Marwin', - 'Record', - 'Dmario', - 'Crist', - 'La', - 'Access', - 'Shaquel', - 'Tyrrell', - 'Tiquan', - 'Shavon', - 'Shatique', - 'Yochanon', - 'Keontay', - 'Shaquelle', - 'Kshawn', - 'Armend', - 'Eliazer', - 'Diony', - 'Saddam', - 'Takayuki', - 'Sukhdeep', - 'Shahan', - 'Valon', - 'Orel', - 'Tremell', - 'Chayim', - 'Jaquille', - 'Ayodeji', - 'Bekim', - 'Besnik', - 'Oluwanifemi', - 'Stalin', - 'Sadam', - 'Aniel', - 'Laureat', - 'Dyrell', - 'Jhony', - 'Barkim', - 'Ludger', - 'Mahendra', - 'Kadeen', - 'Jovaughn', - 'Khadeem', - 'Ardian', - 'Ravindra', - 'Harpal', - 'Jatinder', - 'Erving', - 'Gerrell', - 'Sylvestre', - 'Luismanuel', - 'Pharell', - 'Jahziah', - 'Salif', - 'Jakyrin', - 'Idrissa', - 'Daoud', - 'Swan', - 'Pryor', - 'Polk', - 'Rameses', - 'Prateek', - 'Lelon', - 'Ebrima', - 'Ezechiel', - 'Tevan', - 'Sohail', - 'Luiseduardo', - 'Clearance', - 'Brayn', - 'Alexsis', - 'Edwar', - 'Johnmark', - 'Hikaru', - 'Edon', - 'Chezkel', - 'Dinari', - 'Ahmadou', - 'Jadien', - 'Ismaeel', - 'Heshy', - 'Jhan', - 'Dejohn', - 'Ajdin', - 'Damier', - 'Cashmere', - 'Amitai', - 'Alp', - 'Avrahom', - 'Hooper', - 'Daichi', - 'Dariush', - 'Bryen', - 'Oseas', - 'Moyses', - 'Alderic', - 'Dickson', - 'Joon', - 'Justinkyle', - 'Jassiah', - 'Jaidin', - 'Lexie', - 'Mieczyslaw', - 'Joffre', - 'Augustino', - 'Adelino', - 'Tadeusz', - 'Humphrey', - 'Lonas', - 'Avry', - 'Tylin', - 'Dixie', - 'Goldman', - 'Yissachar', - 'Toure', - 'Yafet', - 'Siraj', - 'Nasiah', - 'Maor', - 'Roniel', - 'Kerim', - 'Danieljr', - 'Django', - 'Lion', - 'Baruc', - 'Cervando', - 'Akul', - 'Abdi', - 'Ameya', - 'Arhan', - 'Aliou', - 'Arcangel', - 'Avrumy', - 'Deandrea', - 'Dontreal', - 'Yossef', - 'Walden', - 'Tameem', - 'Kenderick', - 'Yassine', - 'Zeyad', - 'Riyad', - 'Kashmere', - 'Tevis', - 'Malichi', - 'Malakhai', - 'Yulian', - 'Clearnce', - 'Esco', - 'Fabrizzio', - 'Gianpaolo', - 'Jaskirat', - 'Termaine', - 'Daouda', - 'Abba', - 'Aaban', - 'Chanoch', - 'Raynell', - 'Ihsan', - 'Djibril', - 'Cassiel', - 'Ishaq', - 'Azlan', - 'Behruz', - 'Amirjon', - 'Anisjon', - 'Asadbek', - 'Dhilan', - 'Dream', - 'Daviel', - 'Mosha', - 'Rayane', - 'Shabsi', - 'Olie', - 'Vinicio', - 'Yuda', - 'Shohjahon', - 'Kylematthew', - 'Kien', - 'Matthewjames', - 'Giorgi', - 'Konstantine', - 'Jibreel', - 'Jadriel', - 'Lliam', - 'Travonte', - 'Taiki', - 'Rendell', - 'Wyland', - 'Arafat', - 'Tajon', - 'Loic', - 'Shaw', - 'Sukhman', - 'Randiel', - 'Stefanos', - 'Lukus', - 'Majesty', - 'Massimiliano', - 'Burach', - 'Jansel', - 'Ismaila', - 'Henoch', - 'Daelin', - 'Giordano', - 'Huber', - 'Rontrell', - 'Simran', - 'Majid', - 'Rayjon', - 'Pharoah', - 'Lamine', - 'Hanoch', - 'Chidi', - 'Jahmani', - 'Javid', - 'Kamani', - 'Endrit', - 'Endy', - 'Nasean', - 'Danyael', - 'Cinque', - 'Akaash', - 'Zeeshan', - 'Amel', - 'Adib', - 'Aboubakar', - 'Artan', - 'Burak', - 'Serigne', - 'Samin', - 'Hovsep', - 'Jomari', - 'Cesareo', - 'Dajohn', - 'Charbel', - 'Bakary', - 'Camerin', - 'Jaquel', - 'Pape', - 'Jahrel', - 'Jahrell', - 'Khadim', - 'Jeison', - 'Yobany', - 'Zaul', - 'Taryn', - 'Abou', - 'Besim', - 'Abdur', - 'Ebrahim', - 'Albi', - 'Haadi', - 'Saba', - 'Wen', - 'Felipedejesus', - 'Dragon', - 'Jamiel', - 'Alecxis', - 'Ashkon', - 'Tejon', - 'Meelad', - 'Renan', - 'Brailyn', - 'Harel', - 'Abdou', - 'Amier', - 'Jonathanjoseph', - 'Juanalberto', - 'Larenz', - 'Nerses', - 'Emmanuelle', - 'Jasmeet', - 'Jahred', - 'Elsworth', - 'Nyshawn', - 'Alexes', - 'Cranford', - 'Trenell', - 'Cephus', - 'Costas', - 'Rama', - 'Nickalas', - 'Moultrie', - 'Deklin', - 'Saafir', - 'Alexie', - 'Kajuan', - 'Jamahl', - 'Robet', - 'Antoin', - 'Turhan', - 'Mart', - 'Richrd', - 'Ante', - 'Bransyn', - 'Dargan', - 'Levan', - 'Milledge', - 'Ollis', - 'Morey', - 'Jeromey', - 'Ebon', - 'Nicholus', - 'Yvonne', - 'Gladstone', - 'Kwan', - 'Sherry', - 'Romney', - 'Nicolaos', - 'Oded', - 'Koty', - 'Mandy', - 'Adger', - 'Esaw', - 'Shaunte', - 'Nimesh', - 'Ahren', - 'Marcellino', - 'Attila', - 'Pinkney', - 'Reinhard', - 'Deanna', - 'Shanti', - 'Calmer', - 'Reda', - 'Darral', - 'Monserrate', - 'Levert', - 'Harce', - 'Ayham', - 'Breslin', - 'Dom', - 'Darrow', - 'Haidar', - 'Willaim', - 'Shann', - 'Regina', - 'Einer', - 'Zui', - 'Shonn', - 'Skipper', - 'Henning', - 'Jacek', - 'Wendelin', - 'Wilmar', - 'Algot', - 'Marlen', - 'Dquan', - 'Emanuele', - 'Erol', - 'Boby', - 'Elbin', - 'Londell', - 'Bradd', - 'Malo', - 'Mohamadali', - 'Toussaint', - 'Roald', - 'Trini', - 'Stace', - 'Erubey', - 'Labron', - 'Kyseem', - 'Duong', - 'Rande', - 'Siegfried', - 'Mamon', - 'Va', - 'Quy', - 'Raman', - 'Ramil', - 'Jasai', - 'Carla', - 'Belen', - 'Lawernce', - 'Jemar', - 'Markham', - 'Kym', - 'Jemaine', - 'Baldwin', - 'Damany', - 'Timonthy', - 'Tesfa', - 'Vinod', - 'Albertus', - 'Yupheng', - 'Danie', - 'Tashiem', - 'Uno', - 'Onnie', - 'Juliana', - 'Duff', - 'Doua', - 'Orman', - 'Kamaal', - 'Godwin', - 'Ulric', - 'Darrold', - 'Rennie', - 'Lory', - 'Jamile', - 'Terril', - 'Gable', - 'Hanh', - 'Grisel', - 'Jimmylee', - 'Mikkel', - 'Victorino', - 'Jaymere', - 'Rayn', - 'Duriel', - 'Ceferino', - 'Autrey', - 'Durant', - 'Kolsen', - 'Abayomi', - 'Azell', - 'Spyros', - 'Ato', - 'Damin', - 'Diogenes', - 'Barnaby', - 'Pinckney', - 'Keno', - 'Sherard', - 'Chukwuemeka', - 'Akin', - 'Harvel', - 'Marv', - 'Kenyetta', - 'Huel', - 'Royzell', - 'Luddie', - 'Olden', - 'Ardith', - 'Branch', - 'Bertha', - 'Hillman', - 'Namon', - 'Donnis', - 'Fitzhugh', - 'Lavaughn', - 'Lucille', - 'Amanuel', - 'Carvin', - 'Minnie', - 'Tivis', - 'Birt', - 'Bronner', - 'Vaden', - 'Joenathan', - 'Alphonsa', - 'Elvie', - 'Alpheus', - 'Clausell', - 'Clayburn', - 'Demetrias', - 'Avis', - 'Garlon', - 'Romaine', - 'Jamorris', - 'Swanson', - 'Perez', - 'Hurschel', - 'Virge', - 'Rutherford', - 'Lelton', - 'Tarris', - 'Denson', - 'Benjaman', - 'Rashun', - 'Keino', - 'Cedarius', - 'Keanthony', - 'Blakeley', - 'Burwell', - 'Kasai', - 'Euell', - 'Eldrick', - 'Ashford', - 'Demetruis', - 'Wood', - 'Blanton', - 'Daniell', - 'Robt', - 'Lamorris', - 'Waller', - 'Devoris', - 'Herley', - 'Jermery', - 'Jamicheal', - 'Horton', - 'Gradie', - 'Etheridge', - 'Millie', - 'Jammy', - 'Karey', - 'Rodregus', - 'Cordera', - 'Embry', - 'Forney', - 'Sims', - 'Gergory', - 'Rosser', - 'Benjamine', - 'Erskin', - 'Heflin', - 'Torrie', - 'Norville', - 'Arvie', - 'Bessie', - 'Keonta', - 'Tarrence', - 'Chapman', - 'Limmie', - 'Tavius', - 'Reynard', - 'Lonza', - 'Detroit', - 'Camauri', - 'Clanton', - 'Obbie', - 'Mizell', - 'Marshel', - 'Tollie', - 'Jondarius', - 'Therion', - 'Antoino', - 'Beatrice', - 'Keyonte', - 'Littleton', - 'Hozie', - 'Atwell', - 'Ottie', - 'Pelham', - 'Vickie', - 'Cederick', - 'Zaykeese', - 'Jadarious', - 'Shin', - 'Tizoc', - 'Mischa', - 'Tycen', - 'Jubal', - 'Kito', - 'Sabin', - 'Brannan', - 'Baltasar', - 'Hilda', - 'Orasio', - 'Bassel', - 'Ameet', - 'Talus', - 'Renne', - 'Reuel', - 'Saro', - 'Kam', - 'Heliodoro', - 'Hodari', - 'Mondo', - 'Damaso', - 'Damein', - 'Thunder', - 'Ravinder', - 'Remberto', - 'Rodel', - 'Yvan', - 'Marcelle', - 'Kiril', - 'Shem', - 'Bardo', - 'Carlson', - 'Jebediah', - 'Austreberto', - 'Hannibal', - 'Shawnn', - 'Kenyatte', - 'Geoffry', - 'Hadden', - 'Natnael', - 'Edurdo', - 'Errik', - 'Eva', - 'Gaelan', - 'Gilverto', - 'Antwaine', - 'Barclay', - 'Rithy', - 'Sarath', - 'Sasan', - 'Stefen', - 'Susana', - 'Le', - 'Mai', - 'Marquies', - 'Neeraj', - 'Galdino', - 'Cuitlahuac', - 'Griselda', - 'Jerret', - 'Filbert', - 'Travone', - 'Lizette', - 'Lourdes', - 'Ratana', - 'Sarith', - 'Ku', - 'Jocob', - 'Jushua', - 'Shaughn', - 'Sophal', - 'Sophana', - 'Stepan', - 'Tramel', - 'Veniamin', - 'Ha', - 'Halley', - 'Hiep', - 'Maclain', - 'Alberta', - 'Alejando', - 'Eliana', - 'Chay', - 'Esmond', - 'Frisco', - 'Dai', - 'Marta', - 'Man', - 'Kha', - 'Kin', - 'Sun', - 'Paulmichael', - 'Rj', - 'Jeoffrey', - 'Custodio', - 'Herberth', - 'Gerrad', - 'Seanpaul', - 'Sten', - 'Nereida', - 'Jasun', - 'Micharl', - 'Robbert', - 'Ronnel', - 'Rosio', - 'Othon', - 'Chau', - 'Hart', - 'Atthew', - 'Angelito', - 'Debbie', - 'Randol', - 'Jeffrie', - 'Kern', - 'Rohn', - 'Raef', - 'Arleigh', - 'Jef', - 'Reg', - 'Vinton', - 'Perrin', - 'Parry', - 'Sally', - 'Hoby', - 'Vint', - 'Dagmawi', - 'Mat', - 'Gregrey', - 'Darol', - 'Merik', - 'Rickard', - 'Clete', - 'Fredrik', - 'Darrol', - 'Lyall', - 'Jamare', - 'Duffy', - 'Barre', - 'Shawnee', - 'Tige', - 'Whittaker', - 'Tyrion', - 'Jamas', - 'Jud', - 'Spence', - 'Dione', - 'Erinn', - 'Bron', - 'Ackley', - 'Dal', - 'Monti', - 'Paco', - 'Kjell', - 'Gabor', - 'Davinder', - 'Shonte', - 'Maximiano', - 'Heshimu', - 'Jassen', - 'Jerami', - 'Jermon', - 'Keefe', - 'Keri', - 'Daric', - 'Christropher', - 'Johnney', - 'Dodd', - 'Wilferd', - 'Raymondo', - 'Keary', - 'Orlan', - 'Gerhart', - 'Clemence', - 'Pepe', - 'Whitaker', - 'Vaughan', - 'Wess', - 'Abenezer', - 'Miroslav', - 'Kurk', - 'Helmut', - 'Timothey', - 'Annette', - 'Cruise', - 'Jahel', - 'Itay', - 'Isaiahs', - 'Isack', - 'Eagan', - 'Finbar', - 'Famous', - 'Ethanjoseph', - 'Ethanjames', - 'Edi', - 'Isais', - 'Albeiro', - 'Abhijot', - 'Joshuajames', - 'Amine', - 'Edwardjames', - 'Donyae', - 'Danieljohn', - 'Avaneesh', - 'Aryav', - 'Andoni', - 'Yeison', - 'Lowen', - 'Obi', - 'Mycah', - 'Moksh', - 'Miliano', - 'Maxamillion', - 'Lazlo', - 'Jocsan', - 'Jibran', - 'Jerimyah', - 'Jefte', - 'Korde', - 'Kanav', - 'Tavita', - 'Taesean', - 'Yoltzin', - 'Xzavior', - 'Vibhav', - 'Romen', - 'Rocket', - 'Rai', - 'Orian', - 'Rumi', - 'Shota', - 'Shaheer', - 'Sadrac', - 'Semaje', - 'Sohrob', - 'Yuval', - 'Yuren', - 'Yannis', - 'Vineet', - 'Yarden', - 'Jesusjr', - 'Kartik', - 'Jairon', - 'Millen', - 'Nahun', - 'Krisna', - 'Kyrese', - 'Mher', - 'Mayan', - 'Kais', - 'Joshuan', - 'Jometh', - 'Keawe', - 'Siris', - 'Sinai', - 'Shuban', - 'Shian', - 'Sneijder', - 'Sota', - 'Uday', - 'Sevak', - 'Royale', - 'Yuuki', - 'Reyhan', - 'Seena', - 'Moisses', - 'Nayib', - 'Sumit', - 'Dayveon', - 'Christianpaul', - 'Garrin', - 'Edgerrin', - 'Edrees', - 'Estephan', - 'Assael', - 'Azad', - 'Tydus', - 'Yosuf', - 'Zekiel', - 'Strider', - 'Senai', - 'Edmar', - 'Dmorea', - 'Eman', - 'Darran', - 'Keston', - 'Keny', - 'Hardeep', - 'Heladio', - 'Hernesto', - 'Hovannes', - 'Sankalp', - 'Brenten', - 'Navraj', - 'Mavrik', - 'Nilmar', - 'Rishit', - 'Edwing', - 'Eswin', - 'Flabio', - 'Jasn', - 'Romar', - 'Sevan', - 'Shahab', - 'Justinmichael', - 'Joseandres', - 'Marcelus', - 'Mariana', - 'Andhy', - 'Angeles', - 'Tannor', - 'Tristain', - 'Joshuaray', - 'Luisdavid', - 'Damaris', - 'Daymond', - 'Anthonyjohn', - 'Dezhon', - 'Emelio', - 'Eulices', - 'Maclean', - 'Jaeson', - 'Ethanjohn', - 'Ethanjacob', - 'Jasiri', - 'Kaisei', - 'Khyle', - 'Jona', - 'Jeren', - 'Jeramyah', - 'Jesusantonio', - 'Jguadalupe', - 'Joseeduardo', - 'Elkin', - 'Prashant', - 'Anguel', - 'Anant', - 'Aisea', - 'Abhimanyu', - 'Daelen', - 'Dylin', - 'Dodge', - 'Nazaret', - 'Mikie', - 'Matthewjoseph', - 'Maximillan', - 'Savir', - 'Dhillon', - 'Donoven', - 'Ebin', - 'Edrei', - 'Elek', - 'Nykolas', - 'Nikash', - 'Nik', - 'Reyly', - 'Razi', - 'Presten', - 'Arul', - 'Avo', - 'Yandell', - 'Wynston', - 'Tallen', - 'Suhaib', - 'Joshuajohn', - 'Jesusmanuel', - 'Malacai', - 'Kethan', - 'Londen', - 'Larenzo', - 'Kriss', - 'Kohei', - 'Hamlet', - 'Martinjr', - 'Mansoor', - 'Archit', - 'Aniketh', - 'Kincaid', - 'Lunden', - 'Masaki', - 'Salam', - 'Sahith', - 'Nour', - 'Miqueas', - 'Estefano', - 'Hatim', - 'Gurvir', - 'Adeeb', - 'Tobiah', - 'Torrin', - 'Tushar', - 'Tyee', - 'Sulayman', - 'Takai', - 'Tayo', - 'Yoan', - 'Vegas', - 'Duilio', - 'Dyami', - 'Greko', - 'Harim', - 'Ioane', - 'Ashmit', - 'Bora', - 'Alekxander', - 'Alexanderjames', - 'Amanpreet', - 'Anthonny', - 'Brandom', - 'Daimon', - 'Sirus', - 'Seananthony', - 'Vignesh', - 'Vir', - 'Wisdom', - 'Rameen', - 'Kenzie', - 'Joshuamichael', - 'Josejr', - 'Joseenrique', - 'Jacksen', - 'Jeriko', - 'Jesua', - 'Myka', - 'Naithen', - 'Saurav', - 'Shalim', - 'Puneet', - 'Denali', - 'Daveyon', - 'Sohil', - 'Edilson', - 'Jafeth', - 'Nathin', - 'Maurion', - 'Mekai', - 'Nadim', - 'Jamani', - 'Jamisen', - 'Gared', - 'Gahel', - 'Emron', - 'Hanzel', - 'Xaviar', - 'Yohann', - 'Alam', - 'Brasen', - 'Ashlan', - 'Rury', - 'Ralphie', - 'Robertanthony', - 'Tomoki', - 'Zamuel', - 'Urian', - 'Vinayak', - 'Wilberth', - 'Jazziel', - 'Mizraim', - 'Mosiah', - 'Muneeb', - 'Lennin', - 'Chaitanya', - 'Cyrille', - 'Dilpreet', - 'Bhargav', - 'Captain', - 'Camil', - 'Jaion', - 'Eithen', - 'Dominyk', - 'Domenik', - 'Imad', - 'Dabin', - 'Ceejay', - 'Avishek', - 'Anoop', - 'Aaronjoshua', - 'Billal', - 'Euan', - 'Eion', - 'Beauregard', - 'Fouad', - 'Chriss', - 'Daimien', - 'Cyan', - 'Conall', - 'Inigo', - 'Jashan', - 'Jaicob', - 'Arek', - 'Benjaminjoseph', - 'Bodey', - 'Andrewjames', - 'Abdel', - 'Alian', - 'Artyom', - 'Anik', - 'Angeljesus', - 'Shriyan', - 'Sosaia', - 'Shabd', - 'Tayveon', - 'Samik', - 'Josephanthony', - 'Kaushal', - 'Gerardojr', - 'Haile', - 'Henok', - 'Imer', - 'Izaiha', - 'Vedanth', - 'Rishav', - 'Praveen', - 'Kenner', - 'Juanjr', - 'Kinan', - 'Maven', - 'Neven', - 'Niccolas', - 'Raynav', - 'Rani', - 'Noahjames', - 'Nirvan', - 'Nevaan', - 'Naythen', - 'Rhythm', - 'Samyak', - 'Sahas', - 'Roczen', - 'Kroy', - 'Johanna', - 'Miro', - 'Mayank', - 'Masson', - 'Yamato', - 'Xaden', - 'Vin', - 'Tyden', - 'Gaudencio', - 'Garreth', - 'Toryn', - 'Jaswinder', - 'Stiles', - 'Graciela', - 'Rutger', - 'Razmig', - 'Keo', - 'Kavir', - 'Kalev', - 'Kal', - 'Kabeer', - 'Jianni', - 'Terrace', - 'Vicken', - 'Westly', - 'Pardeep', - 'Lizeth', - 'Lucia', - 'Mandela', - 'Maricela', - 'Joshus', - 'Kayle', - 'Klyde', - 'Djavan', - 'Wang', - 'Aljandro', - 'Belisario', - 'Cristino', - 'Yihan', - 'Carina', - 'Chritian', - 'Juanramon', - 'Khan', - 'Jaiver', - 'Nefi', - 'Murtaza', - 'Raciel', - 'Marlene', - 'Maira', - 'Chima', - 'Cheenou', - 'Bijon', - 'Dorion', - 'Elber', - 'Emeka', - 'Ge', - 'Ratha', - 'Jaxxson', - 'Ryanjames', - 'Shannen', - 'Shue', - 'Sia', - 'Romaldo', - 'Zareh', - 'Tomy', - 'Vanna', - 'Xao', - 'Bertin', - 'Dhyan', - 'Dexton', - 'Esiah', - 'Ayce', - 'Avyukt', - 'Avner', - 'Caspar', - 'Cove', - 'Ciel', - 'Yen', - 'Yessenia', - 'Yony', - 'Fin', - 'Ezrael', - 'Ezel', - 'Ilay', - 'Harveer', - 'Hamad', - 'Asiah', - 'Ashwath', - 'Arcenio', - 'Aroldo', - 'Awet', - 'Alexx', - 'Arihant', - 'Arihaan', - 'Apolo', - 'Aero', - 'Advith', - 'Arren', - 'Beatriz', - 'Jony', - 'Joseramon', - 'Justinray', - 'Jamaul', - 'Tarren', - 'Cristal', - 'Dinh', - 'Chantra', - 'Dshawn', - 'Geraldine', - 'Fuad', - 'Edlin', - 'Jerren', - 'Jerrin', - 'Josje', - 'Chrystopher', - 'Darriel', - 'Takuya', - 'Vannak', - 'Zenas', - 'Miklos', - 'Marten', - 'Rondale', - 'Rothana', - 'Randeep', - 'Ryle', - 'Eduardoluis', - 'Christepher', - 'Davionne', - 'Eriverto', - 'Farbod', - 'Chauncy', - 'Charle', - 'Bayardo', - 'Ashneel', - 'Shoua', - 'Redmond', - 'Ustin', - 'Johnnathan', - 'Josephmichael', - 'Marisela', - 'Markandrew', - 'Michaeljoseph', - 'Marcua', - 'Nidal', - 'Phat', - 'Pritesh', - 'Seaver', - 'Ryananthony', - 'Tyan', - 'Vatche', - 'Thoren', - 'Othoniel', - 'Nicandro', - 'Rajdeep', - 'Tulio', - 'Soua', - 'Jovonte', - 'Kalyn', - 'Jamesryan', - 'Navdeep', - 'Maxmillian', - 'Kayon', - 'Koua', - 'Aaryn', - 'Wilver', - 'Zubair', - 'Ankush', - 'Andie', - 'Adonnis', - 'Jacobanthony', - 'Izekiel', - 'Izacc', - 'Escher', - 'Elijahjames', - 'Edrik', - 'Drayson', - 'Dj', - 'Giordan', - 'Dejaun', - 'Davidmichael', - 'Deshone', - 'Auron', - 'Auguste', - 'Athos', - 'Cutberto', - 'Hairo', - 'Anvay', - 'Adrick', - 'Aydeen', - 'Bassam', - 'Basem', - 'Kyrell', - 'Rjay', - 'Ozil', - 'Taisei', - 'Samanyu', - 'Marvion', - 'Mykael', - 'Mukund', - 'Namish', - 'Naoki', - 'Nishan', - 'Aideen', - 'Aalijah', - 'Hassani', - 'Harkirat', - 'Exzavier', - 'Hudsen', - 'Hrach', - 'Caelum', - 'Caeleb', - 'Destan', - 'Jaspal', - 'Huan', - 'Marcellous', - 'Mehran', - 'Luisfelipe', - 'Gelacio', - 'Eris', - 'Eneas', - 'Terin', - 'Sohrab', - 'Ravneet', - 'Uziah', - 'Vedansh', - 'Peni', - 'Nethaniel', - 'Niraj', - 'Odilon', - 'Kalden', - 'Mariela', - 'Levonte', - 'Elih', - 'Ej', - 'Eames', - 'Jarome', - 'Jishnu', - 'Gurtaaj', - 'Hamish', - 'Gryffin', - 'Jayin', - 'Trong', - 'Sebastain', - 'Sargon', - 'Wa', - 'Cheveyo', - 'Ariv', - 'Aum', - 'Caellum', - 'Bayan', - 'Balthazar', - 'Sagan', - 'Rowyn', - 'Sehaj', - 'Ivon', - 'Stavro', - 'Shrihan', - 'Noey', - 'Oswin', - 'Abrham', - 'Adalid', - 'Aldric', - 'Zayed', - 'Vonn', - 'Vaishnav', - 'Urias', - 'Yahshua', - 'Yago', - 'Darith', - 'Mantej', - 'Kyo', - 'Khyler', - 'Marcjacob', - 'Nayden', - 'Morrissey', - 'Benedicto', - 'Kendrix', - 'Xang', - 'Ranjit', - 'Raymar', - 'Milos', - 'Rayansh', - 'Rawley', - 'Paxon', - 'Krishang', - 'Leeam', - 'Yerick', - 'Yegor', - 'Viren', - 'Saathvik', - 'Shailen', - 'Sahaj', - 'Rydan', - 'Rollins', - 'Rivaan', - 'Soul', - 'Aerick', - 'Aladdin', - 'Catalino', - 'Berenice', - 'Branndon', - 'Kyleanthony', - 'Maclovio', - 'Kiven', - 'Johnchristopher', - 'Jonh', - 'Kassandra', - 'Jobanny', - 'Pastor', - 'Michaela', - 'Montre', - 'Morgen', - 'Gerber', - 'Danish', - 'Haroutun', - 'Duron', - 'Adrion', - 'Evrett', - 'Reegan', - 'Haskie', - 'Quamane', - 'Derrike', - 'Haydyn', - 'Glenville', - 'Dearl', - 'Deroe', - 'Dewell', - 'Lundy', - 'Cleaster', - 'Jeral', - 'Delontae', - 'Delford', - 'Argie', - 'Loise', - 'Elmar', - 'Donley', - 'Ferrel', - 'Carrel', - 'Athel', - 'Rector', - 'Cledith', - 'Dail', - 'Donzel', - 'Lenoard', - 'Winferd', - 'Birl', - 'Dorsie', - 'Olee', - 'Erman', - 'Dorsel', - 'Roma', - 'Othell', - 'Herold', - 'Chaffee', - 'Trygve', - 'Aubra', - 'Opha', - 'Dionne', - 'Colleen', - 'Ciara', - 'Cleotis', - 'Alissa', - 'Alesha', - 'Elise', - 'Emilie', - 'Tiera', - 'Tia', - 'Suzanne', - 'Jaleesa', - 'Jaclyn', - 'Ingrid', - 'India', - 'Georgia', - 'Francesca', - 'Female', - 'Fatima', - 'Rochelle', - 'Precious', - 'Nichelle', - 'Martina', - 'Lucy', - 'Latonya', - 'Cline', - 'Ott', - 'Ona', - 'Otmer', - 'Ersel', - 'Olufemi', - 'Gordy', - 'Marne', - 'Jahquez', - 'Daeshaun', - 'Nashaun', - 'Seiichi', - 'Shigeki', - 'Kazuto', - 'Shozo', - 'Alhaji', - 'Lonn', - 'Tevion', - 'Kaige', - 'Darlene', - 'Braydyn', - 'Masaaki', - 'Graeson', - 'Bernerd', - 'Lynne', - 'Dewaine', - 'Shig', - 'Junichi', - 'Toshiro', - 'Azavion', - 'Michio', - 'Yoshiro', - 'Heraldo', - 'Epitacio', - 'Mas', - 'Taequan', - 'Trindon', - 'Tirrell', - 'Dmonte', - 'Jaquante', - 'Yeeleng', - 'Maleik', - 'Airam', - 'Noname', - 'Shyhiem', - 'Tyquon', - 'Damonta', - 'Undray', - 'Shadrick', - 'Durwin', - 'Lataurus', - 'Corneall', - 'Dantonio', - 'Tilmon', - 'Mackie', - 'Ebbie', - 'Eligha', - 'Beth', - 'Barth', - 'Hezzie', - 'Artha', - 'Darrie', - 'Frederi', - 'Benford', - 'Elves', - 'Theodia', - 'Jaye', - 'Fran', - 'Khylan', - 'Berwyn', - 'Constance', - 'Markevion', - 'Martavion', - 'Jashun', - 'Jermarion', - 'Taylin', - 'Breland', - 'Franchot', - 'Chrishun', - 'Davarius', - 'Dearius', - 'Tredarius', - 'Jayland', - 'Cortavius', - 'Deyonta', - 'Tradarius', - 'Kemarrion', - 'Markavion', - 'Jmarion', - 'Jacarius', - 'Kairi', - 'Rasool', - 'Jarreau', - 'Khayree', - 'Brahin', - 'Hameed', - 'Rolen', - 'Cleason', - 'Cartez', - 'Nicholad', - 'Brahim', - 'Bryheem', - 'Khalief', - 'Anel', - 'Mcgwire', - 'Lula', - 'Gaddis', - 'Lowery', - 'Odies', - 'Rannie', - 'Artee', - 'Aurther', - 'Bookert', - 'Lenon', - 'Oree', - 'Gennie', - 'Emitt', - 'Sedgie', - 'Claudy', - 'Coyt', - 'Lieutenant', - 'Zannie', - 'Kenn', - 'Roosvelt', - 'Vertis', - 'Elex', - 'Eula', - 'Abron', - 'Perkins', - 'Emersyn', - 'Lakin', - 'Dravin', - 'Other', - 'President', - 'Carrie', - 'Cleother', - 'Estus', - 'Tee', - 'Raymont', - 'Woodard', - 'Ras', - 'Zennie', - 'Versie', - 'Mansfield', - 'Atha', - 'Bossie', - 'Smiley', - 'Kenard', - 'Jermie', - 'Vardell', - 'Kadan', - 'Roney', - 'Furney', - 'Caroll', - 'Benjy', - 'Shamond', - 'Tyrease', - 'Dontre', - 'Raekwan', - 'Raequon', - 'Chrishon', - 'Jahmez', - 'Jaques', - 'Zaveon', - 'Zaccheus', - 'Demaris', - 'Shaquile', - 'Shiheem', - 'Santario', - 'Monterio', - 'Jawaan', - 'Lavere', - 'Levere', - 'Guerino', - 'Lisle', - 'Fraser', - 'Grier', - 'Gurnie', - 'Lattie', - 'Wassil', - 'Domer', - 'Melio', - 'Zolton', - 'Haines', - 'Gervase', - 'Fermon', - 'Geneva', - 'Trask', - 'Linward', - 'Colen', - 'Dossie', - 'Zygmund', - 'Teofil', - 'Talbert', - 'Mosby', - 'Elworth', - 'Garvie', - 'Jiles', - 'Mallie', - 'Flay', - 'Stokes', - 'Bernis', - 'Gardiner', - 'Deno', - 'Algerd', - 'Handy', - 'Flake', - 'Hallet', - 'Coyte', - 'Wingate', - 'Burlie', - 'Sigmond', - 'Myrle', - 'Stiney', - 'Americus', - 'Claxton', - 'Acy', - 'Hill', - 'Fenner', - 'Festus', - 'Linnie', - 'Guilford', - 'Artice', - 'Constant', - 'Faber', - 'Jb', - 'Pleasant', - 'Dallis', - 'Vestal', - 'Terez', - 'English', - 'Allard', - 'Ingram', - 'Beaufort', - 'Chene', - 'Dequante', - 'Bubber', - 'Jamone', - 'Zebulun', - 'Daqwan', - 'Delshawn', - 'Jamond', - 'Dacota', - 'Wilmot', - 'Prue', - 'Wister', - 'Kenyata', - 'Darik', - 'Sumter', - 'Hovie', - 'Tallie', - 'Diontay', - 'Dontaye', - 'Brentt', - 'Felder', - 'Chappell', - 'Ralpheal', - 'Wofford', - 'Stclair', - 'Aiken', - 'Hashem', - 'Daire', - 'Grahm', - 'Jaivon', - 'Davarion', - 'Arnez', - 'Ryer', - 'Mousa', - 'Jahlon', - 'Leyland', - 'Maizen', - 'Zadyn', - 'Zein', - 'Amarri', - 'Hady', - 'Keegen', - 'Taeshawn', - 'Jontae', - 'Radwan', - 'Jsean', - 'Hartwell', - 'Roddey', - 'Arend', - 'Marjorie', - 'Clements', - 'Rae', - 'Pressley', - 'Saintclair', - 'Derrill', - 'Joann', - 'Cote', - 'Philo', - 'Urho', - 'Evart', - 'Vada', - 'Deo', - 'Tonie', - 'Irven', - 'Stjulian', - 'Durand', - 'Diarra', - 'Burnet', - 'Steed', - 'Demont', - 'Burris', - 'Donyell', - 'Gjon', - 'Demone', - 'Jodi', - 'Boban', - 'Brunson', - 'Mackey', - 'Delwyn', - 'Gordie', - 'Owens', - 'Efton', - 'Uel', - 'Ancel', - 'Zafir', - 'Kyeem', - 'Vencil', - 'Irl', - 'Tymeer', - 'Dymere', - 'Kier', - 'Murel', - 'Hale', - 'Lorn', - 'Tahjir', - 'Sufyaan', - 'Trig', - 'Yacqub', - 'Khadir', - 'Najib', - 'Ayuub', - 'Hamse', - 'Yassir', - 'Yussuf', - 'Abdihafid', - 'Abdinasir', - 'Abdiqani', - 'Tayon', - 'Abdirahim', - 'Abdishakur', - 'Mukhtar', - 'Bauer', - 'Damere', - 'Rashee', - 'Kalief', - 'Shyheed', - 'Dejour', - 'Kuran', - 'Qaadir', - 'Aldor', - 'Jasyah', - 'Hajj', - 'Ordell', - 'Gradyn', - 'Ayyub', - 'Atley', - 'Mahkai', - 'Lochlann', - 'Sakai', - 'Saamir', - 'Bernhardt', - 'Willmer', - 'Swen', - 'Hilding', - 'Knute', - 'Wael', - 'Thorvald', - 'Erle', - 'Melroy', - 'Valerian', - 'Jorgen', - 'Dacotah', - 'Shaydon', - 'Lamir', - 'Kahseem', - 'Jihaad', - 'Tylee', - 'Sakariye', - 'Qalid', - 'Syair', - 'Syire', - 'Safi', - 'Zaakir', - 'Sahmir', - 'Saahir', - 'Karlin', - 'Kowen', - 'Kahne', - 'Azir', - 'Tysir', - 'Maki', - 'Zekhi', - 'Pater', - 'Louden', - 'Jandiel', - 'Khaseem', - 'Livio', - 'Pellegrino', - 'Loretta', - 'Lothar', - 'Morty', - 'Harvard', - 'Jeris', - 'Arlene', - 'Salvotore', - 'Erasmus', - 'Canio', - 'Heywood', - 'Ivar', - 'Maitland', - 'Neale', - 'Gladys', - 'Ethelbert', - 'Fergus', - 'Arcangelo', - 'Sigismund', - 'Fremont', - 'Stillman', - 'Egidio', - 'Pincus', - 'Sabatino', - 'Solly', - 'Bela', - 'Stanly', - 'Faust', - 'Gesualdo', - 'Adolphe', - 'Ladislav', - 'Mandel', - 'Philander', - 'Catello', - 'Fordyce', - 'Brownie', - 'Darnley', - 'Alfio', - 'Emerito', - 'Darrly', - 'Delfin', - 'Chiam', - 'Beril', - 'Albie', - 'Roberts', - 'Ferdinando', - 'Maureen', - 'Herberto', - 'Lamark', - 'Philipp', - 'Uwe', - 'Dermott', - 'Amalio', - 'Sandford', - 'Shawnta', - 'Shannan', - 'Sheppard', - 'Jerauld', - 'Antoinne', - 'Oleh', - 'Tobie', - 'Thoms', - 'Valice', - 'Thurnell', - 'Deamonte', - 'Kendel', - 'Trevone', - 'Kaylob', - 'Carder', - 'Antrell', - 'Traven', - 'Jaymir', - 'Joni', - 'Keisean', - 'Krishawn', - 'Marquelle', - 'Dearis', - 'Delvonte', - 'Jamez', - 'Zebadiah', - 'Kreig', - 'Teran', - 'Resean', - 'Zackory', - 'Lamontae', - 'Albieri', - 'Albiery', - 'Chen', - 'Alexy', - 'Arslan', - 'Taliek', - 'Nakhi', - 'Naphtali', - 'Papa', - 'Pesach', - 'Michoel', - 'Salih', - 'Harshdeep', - 'Elhadj', - 'Izzy', - 'Jahkai', - 'Tyliek', - 'Vasilis', - 'Yaacov', - 'Sohaib', - 'Yissochor', - 'Mir', - 'Jasin', - 'Jensy', - 'Rehman', - 'Nazeer', - 'Jahmil', - 'Enson', - 'Nasif', - 'Rizwan', - 'Samiul', - 'Rahat', - 'Angelos', - 'Avroham', - 'Abdulai', - 'Adir', - 'Enes', - 'Yishay', - 'Doyt', - 'Gal', - 'Shoaib', - 'Quaron', - 'Ishraq', - 'Nazaire', - 'Nyzaiah', - 'Mattia', - 'Javone', - 'Mahesh', - 'Mamady', - 'Johnattan', - 'Jorman', - 'Kaliq', - 'Devendra', - 'Burhan', - 'Zishe', - 'Zeandre', - 'Arel', - 'Shalik', - 'Shameer', - 'Nisson', - 'Ralik', - 'Agim', - 'Amauris', - 'Atif', - 'Samory', - 'Shatiek', - 'Taner', - 'Rafat', - 'Zhen', - 'Radhames', - 'Raliek', - 'Ronel', - 'Sabbir', - 'Saqib', - 'Jeudy', - 'Hesham', - 'Hyun', - 'Lakeem', - 'Mishael', - 'Ivo', - 'Tajay', - 'Taleek', - 'Tishawn', - 'Tyreem', - 'Samori', - 'Nickholas', - 'Pearse', - 'Mamadi', - 'Elhadji', - 'Dawood', - 'Dilon', - 'Ishmel', - 'Yiannis', - 'Jahquel', - 'Jahquell', - 'El', - 'Equan', - 'Ho', - 'Delno', - 'Dinesh', - 'Damel', - 'Temitayo', - 'Tenzing', - 'Wahab', - 'Alisher', - 'Adonijah', - 'Bradan', - 'Efrayim', - 'Elnatan', - 'Elmin', - 'Hossain', - 'Eliav', - 'Azimjon', - 'Dovber', - 'Sheya', - 'Yahia', - 'Jasani', - 'Liav', - 'Kamare', - 'Kaysean', - 'Kinsley', - 'Nikoloz', - 'Nyrell', - 'Wyeth', - 'Jeremaih', - 'Mahin', - 'Matis', - 'Oriel', - 'Mourad', - 'Shmeil', - 'Messi', - 'Jonibek', - 'Jeyren', - 'Keyden', - 'Temur', - 'Tanveer', - 'Zyir', - 'Zidan', - 'Zayyan', - 'Varick', - 'Wesam', - 'Abdoulie', - 'Aqib', - 'Asani', - 'Bless', - 'Hasnain', - 'Hamdan', - 'Getzel', - 'Fatin', - 'Huzaifa', - 'Jarif', - 'Jahlani', - 'Davier', - 'Chuna', - 'Eashan', - 'Rafan', - 'Rakin', - 'Ngawang', - 'Mouhamad', - 'Rohaan', - 'Vanness', - 'Volvy', - 'Javel', - 'Jabir', - 'Jaevion', - 'Fahd', - 'Lean', - 'Machai', - 'Juniel', - 'Kaylin', - 'Jeremiyah', - 'Matisyahu', - 'Menasha', - 'Mikaeel', - 'Gaspard', - 'Lorik', - 'Shuaib', - 'Seif', - 'Shlomy', - 'Shneor', - 'Sonam', - 'Volf', - 'Yussef', - 'Ziv', - 'Krrish', - 'Machi', - 'Endi', - 'Frederik', - 'Abdo', - 'Alif', - 'Elchanan', - 'Yordy', - 'Shafin', - 'Siam', - 'Furkan', - 'Fallou', - 'Devyne', - 'Chaskel', - 'Arbi', - 'Younes', - 'Ziare', - 'Tanyon', - 'Terique', - 'Nicholaos', - 'Nickita', - 'Mordchai', - 'Saifullah', - 'Saliou', - 'Savier', - 'Jahmiere', - 'Jahson', - 'Javoni', - 'Jayel', - 'Jie', - 'Kwadwo', - 'Kahmani', - 'Johansel', - 'Murat', - 'Nasire', - 'Nezar', - 'Seydou', - 'Jamair', - 'Jahmeer', - 'Chanina', - 'Chezky', - 'Zyire', - 'Yoscar', - 'Alassane', - 'Aitan', - 'Dannon', - 'Donelle', - 'Harrington', - 'Sha', - 'Shamal', - 'Josph', - 'Torrell', - 'Ralphy', - 'Sharron', - 'Eleftherios', - 'Gedalia', - 'Kasheen', - 'Manoj', - 'Nuri', - 'Daran', - 'Devanand', - 'Evagelos', - 'Fatmir', - 'Haralambos', - 'Biju', - 'Nilson', - 'Wane', - 'Tarig', - 'Rober', - 'Sharone', - 'Lezer', - 'Odalis', - 'Glenston', - 'Josip', - 'Kostantinos', - 'Rahshawn', - 'Osei', - 'Shariyf', - 'Sotirios', - 'Aneudi', - 'Marios', - 'Biff', - 'Damiano', - 'Shean', - 'Rajendra', - 'Mare', - 'Richad', - 'Jaja', - 'Efstathios', - 'Nephtali', - 'Kowan', - 'Rhonda', - 'Pasqualino', - 'Confesor', - 'Linc', - 'Safet', - 'Sharrieff', - 'Kiron', - 'Damain', - 'Aurohom', - 'Kariem', - 'Tiheim', - 'Dushawn', - 'Kindu', - 'Aswad', - 'Kwane', - 'Oba', - 'Jermayne', - 'Dakeem', - 'Babatunde', - 'Ackeem', - 'Alvi', - 'Adetokunbo', - 'Akeel', - 'Kedwin', - 'Kayron', - 'Mergim', - 'Wilkins', - 'Wojciech', - 'Omair', - 'Kushtrim', - 'Kwamel', - 'Saiquan', - 'Naquon', - 'Quandell', - 'Veton', - 'Shaune', - 'Daguan', - 'Duquan', - 'Jency', - 'Ka', - 'Waqas', - 'Xiao', - 'Mahlik', - 'Kasiem', - 'Navindra', - 'Sayquan', - 'Shaquon', - 'Shiquan', - 'Rameek', - 'Jerelle', - 'Devaun', - 'Jakim', - 'Jaquell', - 'Eury', - 'Shaiquan', - 'Shakeal', - 'Shakiem', - 'Shaleek', - 'Ramesh', - 'Suhail', - 'Tylique', - 'Jawanza', - 'Jonell', - 'Hamdi', - 'Jaimeson', - 'Kerven', - 'Demetreus', - 'Giselle', - 'Aikeem', - 'Akiem', - 'Rondel', - 'Dow', - 'Gregroy', - 'Darnelle', - 'Naguan', - 'Tyronn', - 'Ricke', - 'Dishawn', - 'Rishawn', - 'Tarick', - 'Tynell', - 'Japhet', - 'Francesc', - 'Maximili', - 'Herby', - 'Jaqwan', - 'Kemal', - 'Akeen', - 'Azeez', - 'Devindra', - 'Deryck', - 'Deval', - 'Alessand', - 'Masood', - 'Uladimir', - 'Cadon', - 'Quanah', - 'Zimere', - 'Chatham', - 'Koi', - 'Zymire', - 'Jamaury', - 'Jahmire', - 'Ziyan', - 'Cowen', - 'Jamaurie', - 'Nyquan', - 'Jayleen', - 'Zymiere', - 'Zymarion', - 'Kahmari', - 'Langdon', - 'Zymari', - 'Jymir', - 'Kamaree', - 'Nycere', - 'Sayvion', - 'Jahmarion', - 'Justyce', - 'Tuck', - 'Thayer', - 'Mung', - 'Graison', - 'Delane', - 'Lemoyne', - 'Cinch', - 'Nevada', - 'Dhairya', - 'Jyaire', - 'Yazir', - 'Tahjmir', - 'Sequoyah', - 'Quention', - 'Tanmay', - 'Shreyansh', - 'Ahyan', - 'Aaryav', - 'Zaylin', - 'Laksh', - 'Basheer', - 'Bhavik', - 'Orley', - 'Vestel', - 'Altus', - 'Choice', - 'Bufford', - 'Quasir', - 'Emry', - 'Tressel', - 'Eppie', - 'Jayvier', - 'Prestin', - 'Haydin', - 'Caydan', - 'Corday', - 'Camdin', - 'Brodyn', - 'Liberato', - 'Trayon', - 'Telesfor', - 'Jayko', - 'Lavi', - 'Procopio', - 'Rubel', - 'Karder', - 'Jaymar', - 'Bryor', - 'Gottlob', - 'Saladin', - 'Tunis', - 'Saheed', - 'Alsexander', - 'Davonn', - 'Jaquill', - 'Shakeil', - 'Krunal', - 'Tashon', - 'Doyel', - 'Odes', - 'Thoams', - 'Rasul', - 'Wendyl', - 'Glendale', - 'Ahmid', - 'Altarik', - 'Amish', - 'Jaquis', - 'Dashan', - 'Salaam', - 'Bhavin', - 'Nashid', - 'Tauheed', - 'Jamill', - 'Cordney', - 'Derly', - 'Jamale', - 'Hristopher', - 'Camaron', - 'Domanique', - 'Desmund', - 'Keenon', - 'Paulanthony', - 'Demarques', - 'Meryl', - 'Medard', - 'Erbey', - 'Adrin', - 'Evo', - 'Pal', - 'Deke', - 'Glendal', - 'Tramayne', - 'Aloysuis', - 'Berthal', - 'Ashly', - 'Arien', - 'Teodulo', - 'Johsua', - 'Kelwin', - 'Quintan', - 'Mauel', - 'Quisto', - 'Gaylin', - 'Trayvion', - 'Tracer', - 'Ramsay', - 'Verlan', - 'Kyndal', - 'Donovon', - 'Samuell', - 'Treyveon', - 'Nereo', - 'Areli', - 'Dashun', - 'Devontre', - 'Stran', - 'Zarian', - 'Pacen', - 'Kamakani', - 'Alii', - 'Chidozie', - 'Cobie', - 'Acxel', - 'Jatavian', - 'Kelvon', - 'Keldon', - 'Giezi', - 'Gavon', - 'Virtus', - 'Burdell', - 'Dorrance', - 'Naail', - 'Lantz', - 'Travian', - 'Cleland', - 'Arish', - 'Elyan', - 'Chukwudi', - 'Shahrukh', - 'Coulter', - 'Karver', - 'Seeley', - 'Wynton', - 'Detric', - 'Quenten', - 'Joemichael', - 'Daruis', - 'Tyeler', - 'Montray', - 'Hermenegildo', - 'Donathan', - 'Mckenna', - 'Kijuan', - 'Braijon', - 'Vashawn', - 'Darvell', - 'Kennie', - 'Rejino', - 'Vickey', - 'Lyndall', - 'Reynoldo', - 'Malyk', - 'Armarion', - 'Brit', - 'Trayshawn', - 'Contrell', - 'Eutimio', - 'Dantrel', - 'Darrious', - 'Dawon', - 'Richey', - 'Arrion', - 'Zohair', - 'Randale', - 'Keyshone', - 'Kiwane', - 'Jibri', - 'Devell', - 'Beto', - 'Jaymz', - 'Ritchey', - 'Tremel', - 'Keante', - 'Vontrell', - 'Guadlupe', - 'Esiquiel', - 'Erasto', - 'Dub', - 'Augustas', - 'Panfilo', - 'Vuk', - 'Mickie', - 'Javonni', - 'Riddick', - 'Nikodem', - 'Marrion', - 'Kamareon', - 'Maks', - 'Eliverto', - 'Cresenciano', - 'Jerrol', - 'Joakim', - 'Maddax', - 'Kayvion', - 'Khizar', - 'Haze', - 'Aveon', - 'Amjad', - 'Audwin', - 'Almir', - 'Vicky', - 'Lonell', - 'Jabarie', - 'Jaylun', - 'Damarrion', - 'Mantas', - 'Dannye', - 'Aadarsh', - 'Caelen', - 'Tilton', - 'Kimmie', - 'Josgar', - 'Oleksandr', - 'Keyontae', - 'Fidelio', - 'Wiktor', - 'Maxymilian', - 'Cayce', - 'Rodric', - 'Manrique', - 'Kestutis', - 'Donnald', - 'Grayland', - 'Lavance', - 'Medgar', - 'Chaney', - 'Monta', - 'Lemond', - 'Medford', - 'Mareo', - 'Camerino', - 'Ronold', - 'Lancer', - 'Credell', - 'Elbridge', - 'Stony', - 'Dvid', - 'Hilberto', - 'Erineo', - 'Jerrald', - 'Antawan', - 'Cordario', - 'Levelle', - 'Ramsen', - 'Jigar', - 'Laroyce', - 'Lazerrick', - 'Artez', - 'Cordelro', - 'Creon', - 'Lonzell', - 'Shanton', - 'Orpheus', - 'Terris', - 'Renauld', - 'Deondra', - 'Fontaine', - 'Airrion', - 'Branko', - 'Enemencio', - 'Antiono', - 'Caprice', - 'Danyale', - 'Valdez', - 'Oswell', - 'Tahitoa', - 'Fannie', - 'Estes', - 'Herchel', - 'Seabron', - 'Bunyan', - 'Thelmon', - 'Agnew', - 'Broughton', - 'Harwell', - 'Mather', - 'Quillie', - 'Hardwick', - 'Phinizy', - 'Pope', - 'Addis', - 'Seals', - 'Thelman', - 'Summie', - 'Romano', - 'Zacari', - 'Kortney', - 'Makye', - 'Graycen', - 'Kavari', - 'Kamarri', - 'Ajahni', - 'Dayan', - 'Sharrod', - 'Pheonix', - 'Trentyn', - 'Jacai', - 'Jamesley', - 'Destyn', - 'Maddon', - 'Gianlucas', - 'Aydrian', - 'Bader', - 'Jaise', - 'Godson', - 'Gleb', - 'Jatniel', - 'Yaxiel', - 'Marvins', - 'Miron', - 'Yaroslav', - 'Legrande', - 'Lonzy', - 'Merrell', - 'Flemming', - 'Guerry', - 'Kimothy', - 'Remus', - 'Wyndell', - 'Barnard', - 'Denorris', - 'Edna', - 'Bevan', - 'Warnell', - 'Josie', - 'Arthor', - 'Theartis', - 'Kimsey', - 'Wymon', - 'Duglas', - 'Reshawn', - 'Natrone', - 'Treysen', - 'Davaris', - 'Jocqui', - 'Traivon', - 'Trevonne', - 'Tavarious', - 'Monson', - 'Kevis', - 'Ladonte', - 'Mackenson', - 'Bodee', - 'Chayden', - 'Dequon', - 'Keiondre', - 'Dewan', - 'Taige', - 'Renel', - 'Jasher', - 'Bayler', - 'Dodger', - 'Tyke', - 'Jarvin', - 'Edner', - 'Travonn', - 'Traxton', - 'Malosi', - 'Lavonta', - 'Janard', - 'Kyzer', - 'Packer', - 'Travoris', - 'Frantzy', - 'Makay', - 'Tamari', - 'Kanard', - 'Dairon', - 'Gabriell', - 'Kemaury', - 'Jshaun', - 'Karel', - 'Jakarri', - 'Rubens', - 'Zamauri', - 'Winsley', - 'Giulian', - 'Yosbel', - 'Kevaughn', - 'Jimson', - 'Kendly', - 'Dishon', - 'Dallyn', - 'Jephthe', - 'Luccas', - 'Kemuel', - 'Eddrick', - 'Ahmarion', - 'Amariyon', - 'Artavis', - 'Dewin', - 'Jacarie', - 'Jahn', - 'Janari', - 'Geordy', - 'Mardochee', - 'Jimari', - 'Yoshinobu', - 'Eiji', - 'Yasunobu', - 'Koon', - 'Hidemi', - 'Norio', - 'Kiyomi', - 'Shuichi', - 'Kazuyoshi', - 'Yoshitaka', - 'Kanji', - 'Tetsuro', - 'Asao', - 'Dominador', - 'Shogo', - 'Jakye', - 'Braelin', - 'Chrisangel', - 'Calab', - 'Morio', - 'Seiki', - 'Tsuyoshi', - 'Soichi', - 'Masakatsu', - 'Tadayoshi', - 'Tokuichi', - 'Yoshikatsu', - 'Matsuichi', - 'Lorrin', - 'Javeion', - 'Kail', - 'Jvon', - 'Joshwa', - 'Keylen', - 'Rylon', - 'Oved', - 'Kraven', - 'Koben', - 'Klever', - 'Nedved', - 'Dago', - 'Cortlen', - 'Reeves', - 'Yhair', - 'Xane', - 'Jamori', - 'Jayshon', - 'Jaiveon', - 'Joseth', - 'Drelynn', - 'Haldrin', - 'Keelyn', - 'Nathanuel', - 'Kvon', - 'Jayln', - 'Khyrie', - 'Zayveon', - 'Braxston', - 'Jaceion', - 'Jonavon', - 'Jesaiah', - 'Gaddiel', - 'Tobyn', - 'Becket', - 'Aydyn', - 'Arinze', - 'Dacian', - 'Aadin', - 'Fender', - 'Brysun', - 'Demarious', - 'Kaimi', - 'Ryson', - 'Jarrin', - 'Maleko', - 'Kamakana', - 'Kamalani', - 'Johnavon', - 'Kawena', - 'Aadil', - 'Blayde', - 'Garyn', - 'Izaih', - 'Bryndon', - 'Drelyn', - 'Demarian', - 'Kupaa', - 'Nalu', - 'Makena', - 'Lawaia', - 'Kaimalu', - 'Kanaloa', - 'Oshen', - 'Mj', - 'Kahekili', - 'Koalii', - 'Makua', - 'Promise', - 'Keylin', - 'Kevondrick', - 'Tobenna', - 'Infantboy', - 'Oluwatimilehin', - 'Nathanal', - 'Zakkery', - 'Shariq', - 'Sadler', - 'Rockne', - 'Drelon', - 'Ethon', - 'Catcher', - 'Clayten', - 'Kaniela', - 'Isaack', - 'Josten', - 'Zarius', - 'Tayte', - 'Ugochukwu', - 'Aiman', - 'Eduar', - 'Basel', - 'Canton', - 'Dyron', - 'Keaden', - 'Kayceon', - 'Kyrian', - 'Kree', - 'Jj', - 'Iaan', - 'Hudsyn', - 'Graceson', - 'Gatlyn', - 'Eydan', - 'Jak', - 'Townsend', - 'Owais', - 'Nandan', - 'Rayland', - 'Ridhaan', - 'Dantavious', - 'Lavoris', - 'Maricus', - 'Rodrigus', - 'Aayansh', - 'Chasten', - 'Durante', - 'Johnta', - 'Detavious', - 'Donterrius', - 'Rilyn', - 'Rilee', - 'Marquize', - 'Quinterius', - 'Jamarco', - 'Quinnton', - 'Deston', - 'Aceson', - 'Britten', - 'Adric', - 'Tabias', - 'Lajarvis', - 'Corderius', - 'Romon', - 'Que', - 'Nord', - 'Lerone', - 'Skylan', - 'Tobi', - 'Mccrae', - 'Mathayus', - 'Marcuz', - 'Levii', - 'Lander', - 'Oluwadarasimi', - 'Miklo', - 'Nijah', - 'Nero', - 'Quavis', - 'Zailyn', - 'Whitman', - 'Zavior', - 'Zlatan', - 'Crixus', - 'Cotton', - 'Chukwuebuka', - 'Draden', - 'Caston', - 'Aceyn', - 'Caeson', - 'Brax', - 'Azel', - 'Kaisyn', - 'Hunt', - 'Gaius', - 'Gabrian', - 'Falcon', - 'Iyan', - 'Jayjay', - 'Altonio', - 'Woodruff', - 'Tavare', - 'Kawaski', - 'Dontravious', - 'Gabreil', - 'Holten', - 'Dayvian', - 'Brennyn', - 'Chayson', - 'Dailon', - 'Keyshun', - 'Jaryn', - 'Jamyron', - 'Jakavion', - 'July', - 'Jonanthony', - 'Trenden', - 'Tobechukwu', - 'Yostin', - 'Casin', - 'Kaydyn', - 'Jshawn', - 'Keaghan', - 'Khalen', - 'Haylen', - 'Jamarques', - 'Alyjah', - 'Baylon', - 'Kemontae', - 'Taysean', - 'Slaton', - 'Saxton', - 'Yadir', - 'Tramon', - 'Traevion', - 'Raydon', - 'Raahim', - 'Olamide', - 'Oreoluwa', - 'Zyien', - 'Zayde', - 'Marqavious', - 'Marquavis', - 'Trevious', - 'Zyshonne', - 'Quindarrius', - 'Quintarious', - 'Quinterious', - 'Rodarius', - 'Deontavious', - 'Champion', - 'Decklan', - 'Daxx', - 'Pecos', - 'Jovonni', - 'Jaydrian', - 'Montravius', - 'Gunter', - 'Zerrick', - 'Quontavious', - 'Ayeden', - 'Audi', - 'Bentlie', - 'Brek', - 'Travonne', - 'Daquavious', - 'Jartavious', - 'Keldric', - 'Alezander', - 'Kamen', - 'Taytum', - 'Siler', - 'Yavuz', - 'Zaniel', - 'Yuriel', - 'Draiden', - 'Axzel', - 'Castin', - 'Keeland', - 'Jrake', - 'Jonhatan', - 'Jeziel', - 'Javery', - 'Severino', - 'Olavi', - 'Benoit', - 'Phillips', - 'Lothrop', - 'Konstanty', - 'Mato', - 'Carney', - 'Keithen', - 'Easley', - 'Chanler', - 'Erbie', - 'Ephriam', - 'Kentravion', - 'Kesan', - 'Ladamien', - 'Treshun', - 'Jakyron', - 'Burch', - 'Kaston', - 'Kyndall', - 'Jarden', - 'Shields', - 'Jontrell', - 'Thales', - 'Minnis', - 'Ida', - 'Hildred', - 'Helder', - 'Fernell', - 'Shone', - 'Laterrance', - 'Tuyen', - 'Roshun', - 'Vincient', - 'Ory', - 'Hilman', - 'Calton', - 'Clydell', - 'Vick', - 'Derrin', - 'Silton', - 'Tandy', - 'Emeal', - 'Rual', - 'Cardarius', - 'Jylan', - 'Hodge', - 'Charls', - 'Jacobey', - 'Jaqualon', - 'Jyrin', - 'Calib', - 'Fowler', - 'Kalep', - 'Osco', - 'Treylan', - 'Paschal', - 'Lowry', - 'Tydrick', - 'Ladavion', - 'Roe', - 'Jarmall', - 'Josuha', - 'Quindell', - 'Tra', - 'Jamaria', - 'Jermicheal', - 'Hobie', - 'Oluwaseun', - 'Trimayne', - 'Kaire', - 'Katrell', - 'Tradd', - 'Yohannes', - 'Oluwaseyi', - 'Tyski', - 'Lansana', - 'Tion', - 'Delontay', - 'Tavone', - 'Quante', - 'Taavon', - 'Daquane', - 'Burleigh', - 'Eyoel', - 'Cung', - 'Khodee', - 'Emilien', - 'Laurien', - 'Leonide', - 'Loomis', - 'Antrone', - 'Sewall', - 'Nicollas', - 'Vitor', - 'Jaythian', - 'Jasaun', - 'Tighe', - 'Colman', - 'Antionne', - 'Nygel', - 'Garnell', - 'Jamareon', - 'Alvey', - 'Carvel', - 'Carville', - 'Carlester', - 'Rutledge', - 'Mills', - 'Rayner', - 'Doil', - 'Gregario', - 'Aniseto', - 'Audon', - 'Brevyn', - 'Pio', - 'Tanis', - 'Jasinto', - 'Jaxtin', - 'Nugent', - 'Eldredge', - 'Egon', - 'Jong', - 'Pancho', - 'Lionardo', - 'Susano', - 'Trueman', - 'Braxtin', - 'Delphine', - 'Harroll', - 'Goree', - 'Manuela', - 'Epigmenio', - 'Laureano', - 'Josefina', - 'Tiodoro', - 'Silbestre', - 'Patrocinio', - 'Corando', - 'Maciah', - 'Quintyn', - 'Wrigley', - 'Onie', - 'Noal', - 'Duward', - 'Filomeno', - 'Cleburn', - 'Garvis', - 'Bisente', - 'Cedell', - 'Jap', - 'Rube', - 'Mavis', - 'Jarold', - 'Hijinio', - 'Dewie', - 'Trinida', - 'Jung', - 'Byrd', - 'Mcadoo', - 'Floy', - 'Eldie', - 'Volney', - 'Saragosa', - 'Derward', - 'Francico', - 'Genovevo', - 'Lindley', - 'Lasalle', - 'Borden', - 'Bonny', - 'Claudis', - 'Silberio', - 'Asuncion', - 'Rolly', - 'Doak', - 'Luvender', - 'Thurl', - 'Garl', - 'Arvine', - 'Johnnye', - 'Emiterio', - 'Crisoforo', - 'Eulojio', - 'Edell', - 'Infboy', - 'Ural', - 'Natalia', - 'Delia', - 'Acencion', - 'Joas', - 'Keagon', - 'Reice', - 'Esperanza', - 'Velton', - 'Eufemio', - 'Frumencio', - 'Dominga', - 'Eutiquio', - 'Dois', - 'Gean', - 'Odaniel', - 'Lyndel', - 'Kreigh', - 'Bobbye', - 'Rogue', - 'Deundra', - 'Cambron', - 'Kaitlynn', - 'Kayleigh', - 'Hailee', - 'Piper', - 'Sofia', - 'Carly', - 'Abigayle', - 'Angelina', - 'Tavish', - 'Christophere', - 'Anterrio', - 'Thimothy', - 'Montarius', - 'Marquarius', - 'Labradford', - 'Lawless', - 'Lenis', - 'Camile', - 'Tonya', - 'Hersey', - 'Abbie', - 'Loveless', - 'Aristide', - 'Ovey', - 'Ovide', - 'Robley', - 'Elward', - 'Leory', - 'Earlis', - 'Gaynell', - 'Printes', - 'Elzy', - 'Aswell', - 'Waver', - 'Wilma', - 'Minos', - 'Euclide', - 'Aster', - 'Demarrion', - 'Selbert', - 'Stoy', - 'Brack', - 'Strother', - 'Osa', - 'Ovel', - 'Custer', - 'Keveon', - 'Lenvil', - 'Hargus', - 'Kline', - 'Goldie', - 'Warfield', - 'Wavy', - 'Carless', - 'Proctor', - 'Holston', - 'Philopateer', - 'Loman', - 'Vernis', - 'Forster', - 'Jakie', - 'Martavis', - 'Louard', - 'Corbet', - 'Waldon', - 'Cluster', - 'Lafe', - 'Tayshun', - 'Browder', - 'Moss', - 'Rudell', - 'Loyde', - 'Glendel', - 'Elby', - 'Shafter', - 'Camila', - 'Elaine', - 'Scarlett', - 'Gertrude', - 'Bella', - 'Penelope', - 'Cathy', - 'Lizbeth', - 'Arianna', - 'Agnes', - 'Vicki', - 'Mila', - 'Ximena', - 'Delilah', - 'Stella', - 'Miranda', - 'Valentina', - 'Rosemary', - 'Khloe', - 'Heidi', - 'Desiree', - 'Violet', - 'Gianna', - 'Nayeli', - 'Luna', - 'Doreen', - 'Jennie', - 'Roberta', - 'Sheri', - 'Jeanne', - 'Alina', - 'Celeste', - 'Rosalie', - 'Naomi', - 'Teri', - 'Maryann', - 'Glenda', - 'Lynda', - 'Annabelle', - 'Antoinette', - 'Stephani', - 'Marcia', - 'Sherri', - 'Clara', - 'Julissa', - 'Becky', - 'Marianne', - 'Melody', - 'Sadie', - 'Sienna', - 'Marsha', - 'Belinda', - 'Jaylah', - 'Harriet', - 'Kristine', - 'Elizabet', - 'Paisley', - 'Genevieve', - 'Melinda', - 'Leilani', - 'Aubree', - 'Keira', - 'Kristy', - 'Sheryl', - 'Fernanda', - 'Tami', - 'Daleyza', - 'Rosemarie', - 'Francine', - 'Kristi', - 'Jaqueline', - 'Meagan', - 'Nichole', - 'Athena', - 'Anahi', - 'Marisa', - 'Yaretzi', - 'Lena', - 'Serena', - 'Miley', - 'Izabella', - 'Kate', - 'Joselyn', - 'Margie', - 'Krystle', - 'Dulce', - 'Pam', - 'Traci', - 'Mikayla', - 'Shari', - 'Delores', - 'Nellie', - 'Gisselle', - 'Blanche', - 'Clarissa', - 'Dianne', - 'Maxine', - 'Janis', - 'Carmela', - 'Mabel', - 'Estrella', - 'Emely', - 'Viola', - 'Penny', - 'Viviana', - 'Estelle', - 'Krista', - 'Adalynn', - 'Julianna', - 'Danna', - 'Marina', - 'Sheena', - 'Shawna', - 'Mya', - 'Leona', - 'Leila', - 'Isla', - 'Charlene', - 'Mindy', - 'Bernadette', - 'Audrina', - 'Tricia', - 'Adele', - 'Myrtle', - 'Nataly', - 'Kimberley', - 'Gwendolyn', - 'Emilia', - 'Janine', - 'Paulina', - 'Stefanie', - 'Marguerite', - 'Dayanara', - 'Katina', - 'Brielle', - 'Vera', - 'Jimena', - 'Aileen', - 'Bethany', - 'America', - 'Kellie', - 'Shanice', - 'Roxanne', - 'Darla', - 'Mamie', - 'Jocelyne', - 'Katherin', - 'Lyla', - 'Sonya', - 'Allyson', - 'Debora', - 'Chaya', - 'Jaslene', - 'Malia', - 'Daniella', - 'Alessandra', - 'Aimee', - 'Dina', - 'Arabella', - 'Juliet', - 'Laila', - 'Rhoda', - 'Angie', - 'Everly', - 'Adrianna', - 'Shelia', - 'Jana', - 'Analia', - 'Kamila', - 'Rebekah', - 'Myrna', - 'Concetta', - 'Amaya', - 'Juliette', - 'Litzy', - 'Marely', - 'Londyn', - 'Patti', - 'Adalyn', - 'Marla', - 'Tammie', - 'Cora', - 'Angelique', - 'Fiona', - 'Kari', - 'Jaylene', - 'Lucile', - 'Rubi', - 'Vivienne', - 'Hattie', - 'Noemi', - 'Celina', - 'Dena', - 'Sherlyn', - 'Selina', - 'Bonita', - 'Paulette', - 'Aisha', - 'Susie', - 'Adeline', - 'Elsa', - 'Shania', - 'Yasmin', - 'Dalia', - 'Jacquelyn', - 'Thalia', - 'Trina', - 'Allisson', - 'Chana', - 'Olive', - 'Helene', - 'Nelda', - 'Mireya', - 'Chelsey', - 'Cheri', - 'Kira', - 'Karissa', - 'Lynette', - 'Deneen', - 'Ivette', - 'Roslyn', - 'Kinley', - 'Rosalinda', - 'Lila', - 'Kaylie', - 'Dayana', - 'Melany', - 'Carissa', - 'Aniyah', - 'Kyla', - 'Yulissa', - 'Trisha', - 'Camilla', - 'Ansley', - 'Sarai', - 'Lola', - 'Arline', - 'Lara', - 'Stacie', - 'Annika', - 'Christi', - 'Brisa', - 'Gia', - 'Therese', - 'Abril', - 'Angeline', - 'Isabela', - 'Marcella', - 'Shanna', - 'Stephany', - 'Henrietta', - 'Tasha', - 'Brianne', - 'Rosanne', - 'Luann', - 'Frieda', - 'Renata', - 'Dianna', - 'Celia', - 'Sondra', - 'Aylin', - 'Melba', - 'Catina', - 'Alayna', - 'Mollie', - 'Nathalie', - 'Tabitha', - 'Tracie', - 'Scarlet', - 'Jayne', - 'Rachelle', - 'Jeannette', - 'Addyson', - 'Cecelia', - 'Annabella', - 'Dahlia', - 'Dorothea', - 'Annmarie', - 'Marlys', - 'Deirdre', - 'Evangeline', - 'Melina', - 'Erma', - 'Jeanine', - 'Roxana', - 'Yaritza', - 'Montserrat', - 'Lizzie', - 'Kerri', - 'Yoselin', - 'Migdalia', - 'Rivka', - 'Cathleen', - 'Lorene', - 'Yareli', - 'Bette', - 'Kyra', - 'Janette', - 'Beulah', - 'Danica', - 'Arely', - 'Lexi', - 'Shana', - 'Sherrie', - 'Alexus', - 'Mable', - 'Citlalli', - 'Nadine', - 'Shauna', - 'Ryleigh', - 'Jeri', - 'Phoebe', - 'Jazlyn', - 'Noreen', - 'Keisha', - 'Lora', - 'Brynlee', - 'Alivia', - 'Lottie', - 'Monserrat', - 'Giuliana', - 'Adelyn', - 'Deana', - 'Jacqueli', - 'Makenna', - 'Jeannie', - 'Noelle', - 'Imogene', - 'Daphne', - 'Reyna', - 'Katelynn', - 'Bettie', - 'Carmella', - 'Estefania', - 'Cassandr', - 'Betsy', - 'Brianda', - 'Iliana', - 'Bryanna', - 'Aranza', - 'Rihanna', - 'Anissa', - 'Alisa', - 'Azul', - 'Milagros', - 'Gemma', - 'Freda', - 'Ada', - 'Bettye', - 'Nia', - 'Oralia', - 'Alaina', - 'Anabelle', - 'Destinee', - 'Sallie', - 'Sonja', - 'Willow', - 'Staci', - 'Lia', - 'Breana', - 'Eliza', - 'Mikaela', - 'Mona', - 'Cataleya', - 'Jeannine', - 'Lilah', - 'Anabel', - 'Ashlynn', - 'Aleena', - 'Estella', - 'Ayla', - 'Adelaide', - 'Lilliana', - 'Kristie', - 'Nettie', - 'Cherie', - 'May', - 'Myra', - 'Nicolette', - 'Lissette', - 'Siena', - 'Ivanna', - 'Christa', - 'Caylee', - 'Roseann', - 'Anastasia', - 'Karin', - 'Corinne', - 'Ginger', - 'Flora', - 'Bria', - 'Gretchen', - 'Maryellen', - 'Lana', - 'Harmony', - 'Elvira', - 'Ilene', - 'Iesha', - 'Celine', - 'Faye', - 'Khadijah', - 'Elyse', - 'Joana', - 'Sharyn', - 'Leia', - 'Catherin', - 'Corina', - 'Sheree', - 'Salma', - 'Deja', - 'Liz', - 'Aracely', - 'Roselyn', - 'Samara', - 'Lorrie', - 'Frida', - 'Tessie', - 'Talia', - 'Rosalind', - 'Jailene', - 'Lisette', - 'Raelynn', - 'Yetta', - 'Catharine', - 'Adelynn', - 'Odalys', - 'Jolene', - 'Charity', - 'Aniya', - 'Sanjuanita', - 'Norah', - 'Terrie', - 'Yuliana', - 'Lorie', - 'Yazmin', - 'Eleanore', - 'Anika', - 'Elida', - 'Valery', - 'Matilda', - 'Nannie', - 'Eloise', - 'Gillian', - 'Tatyana', - 'Kimora', - 'Brynn', - 'Maliyah', - 'Madilyn', - 'Jenifer', - 'Maddison', - 'Colette', - 'Nanette', - 'Ayleen', - 'Winnie', - 'Jayda', - 'Deloris', - 'Tillie', - 'Kizzy', - 'Galilea', - 'Janessa', - 'Brenna', - 'Amelie', - 'Marybeth', - 'Lorna', - 'Kaia', - 'Sarahi', - 'Viridiana', - 'Rebeca', - 'Ericka', - 'Mareli', - 'Anaya', - 'Nathaly', - 'Candy', - 'Larissa', - 'Elle', - 'Yasmine', - 'Claudine', - 'Kyleigh', - 'Paloma', - 'Lenore', - 'Citlali', - 'Rosanna', - 'Misti', - 'Kasandra', - 'Zara', - 'Isis', - 'Alisson', - 'Cheyanne', - 'Reba', - 'Ariella', - 'Lavonne', - 'Miah', - 'Roxanna', - 'Anabella', - 'Suzette', - 'Kiera', - 'Gitty', - 'Farrah', - 'Helena', - 'Shaniqua', - 'Maryanne', - 'Liana', - 'Arleen', - 'Belle', - 'Katy', - 'Anya', - 'Selene', - 'Maura', - 'Chantel', - 'Keyla', - 'Maryjane', - 'Tisha', - 'Kisha', - 'Kaelyn', - 'Malka', - 'Maci', - 'Evelin', - 'Julianne', - 'Magdalena', - 'Kimberlee', - 'Ernestine', - 'Alyson', - 'Kaley', - 'Danika', - 'Kecia', - 'Leanne', - 'Tonia', - 'Nyla', - 'Ivonne', - 'Madelynn', - 'Ofelia', - 'Lakisha', - 'Adilene', - 'Wendi', - 'Susanne', - 'Katharine', - 'Faigy', - 'Raizy', - 'Tawny', - 'Jackeline', - 'Ariadne', - 'Giovanna', - 'Janiyah', - 'Alani', - 'Nayely', - 'Lilian', - 'Saundra', - 'Jazlynn', - 'Jaelynn', - 'Elliana', - 'Gayla', - 'Deena', - 'Earnestine', - 'Margo', - 'Herlinda', - 'Elinor', - 'Salina', - 'Casandra', - 'Nathalia', - 'Kaila', - 'Deanne', - 'Desirae', - 'Liza', - 'Bobbi', - 'Briella', - 'Gilda', - 'Averie', - 'Charlize', - 'Azalea', - 'Sanjuana', - 'Yajaira', - 'Brandie', - 'Aleah', - 'Della', - 'Elaina', - 'Yahaira', - 'Aja', - 'Bernadine', - 'Lela', - 'Annabel', - 'Xiomara', - 'Kassidy', - 'Nohely', - 'Aubrie', - 'Angelia', - 'Macie', - 'Shelbi', - 'Chelsie', - 'Lilyana', - 'Jazlene', - 'Amina', - 'Dorthy', - 'Noelia', - 'Addisyn', - 'Dalilah', - 'Clarisa', - 'Chrystal', - 'Oleta', - 'Georgina', - 'Adelina', - 'Edythe', - 'Lucinda', - 'Jannie', - 'Minerva', - 'Kelsie', - 'Madisyn', - 'Aida', - 'Katlyn', - 'Julieta', - 'Violeta', - 'Heidy', - 'Lea', - 'Leola', - 'Chasity', - 'Nell', - 'Felicity', - 'Kathi', - 'Karyn', - 'Hana', - 'Micaela', - 'Chandra', - 'Liberty', - 'Cielo', - 'Tameka', - 'Maude', - 'Malky', - 'Coraima', - 'Haylie', - 'Vanesa', - 'Sloane', - 'Karyme', - 'Evelynn', - 'Batsheva', - 'Nallely', - 'Tamra', - 'Maricruz', - 'Paislee', - 'Kynlee', - 'Marcela', - 'Marci', - 'Vonda', - 'Cinthia', - 'Amiyah', - 'Breanne', - 'Lisbeth', - 'Leanna', - 'Anais', - 'Flor', - 'Annemarie', - 'Amie', - 'Estela', - 'Tammi', - 'Rhiannon', - 'Denisse', - 'Leyla', - 'Iridian', - 'Dariana', - 'Romina', - 'Yamileth', - 'Lidia', - 'Sybil', - 'Elvia', - 'Debby', - 'Philomena', - 'Jacklyn', - 'Charlee', - 'Kathie', - 'Aryanna', - 'Katarina', - 'Elianna', - 'Zariah', - 'Andreina', - 'Filomena', - 'Xochitl', - 'Mariam', - 'Myla', - 'Janiya', - 'Kristal', - 'Estefany', - 'Debi', - 'Miracle', - 'Shaindy', - 'Evangelina', - 'Naya', - 'Maeve', - 'Judi', - 'Effie', - 'Lilia', - 'Dayami', - 'Kierra', - 'Vincenza', - 'Cari', - 'Lauri', - 'Bethzy', - 'Trudy', - 'Deidre', - 'Melisa', - 'Luciana', - 'Chantal', - 'Laisha', - 'Kennedi', - 'Ayanna', - 'Madalyn', - 'Dania', - 'Jaliyah', - 'Madilynn', - 'Citlaly', - 'Lolita', - 'Drema', - 'Iva', - 'Kailee', - 'Grecia', - 'Kailyn', - 'Ladonna', - 'Latanya', - 'Maia', - 'Jaquelin', - 'Alanna', - 'Etta', - 'Marlee', - 'Reina', - 'Aiyana', - 'Carolann', - 'Gizelle', - 'Greta', - 'Lynnette', - 'Cecile', - 'Shayna', - 'Savanah', - 'Annalise', - 'Nylah', - 'Lesa', - 'Jolie', - 'Arleth', - 'Laraine', - 'Selah', - 'Alysha', - 'Bridgette', - 'Madyson', - 'Marylou', - 'Adela', - 'Shaina', - 'Trista', - 'Katia', - 'Kayleen', - 'Lilianna', - 'Tamera', - 'Millicent', - 'Eugenia', - 'Myrtice', - 'Baila', - 'Charmaine', - 'Maegan', - 'Ruthie', - 'Jovanna', - 'Julisa', - 'Mayte', - 'Latrice', - 'Priscila', - 'Glenna', - 'Yitty', - 'Tawana', - 'Yessica', - 'Ina', - 'Brittni', - 'Johana', - 'Tess', - 'Caryn', - 'Natalee', - 'Barb', - 'Journee', - 'Malaysia', - 'Yulisa', - 'Alta', - 'Shaila', - 'Maurine', - 'Amira', - 'Tiffani', - 'Danette', - 'Fanny', - 'Justina', - 'Leann', - 'Dafne', - 'Ima', - 'Azucena', - 'Braylee', - 'Amaris', - 'Bailee', - 'Giana', - 'Josette', - 'Raegan', - 'Gena', - 'Luella', - 'Nita', - 'Laney', - 'Gisela', - 'Alexandrea', - 'Rosalia', - 'Odessa', - 'Laci', - 'Yamilex', - 'Tamia', - 'Astrid', - 'Luanne', - 'Gwen', - 'Tabatha', - 'Rivky', - 'Laureen', - 'Zina', - 'Amara', - 'Itzayana', - 'Adamaris', - 'Laylah', - 'Luisa', - 'Georgette', - 'Joselin', - 'Yamilet', - 'Nilda', - 'Luisana', - 'Coleen', - 'Cecily', - 'Jocelynn', - 'Mirella', - 'Jessika', - 'Moriah', - 'Halle', - 'Caren', - 'Earline', - 'Shantel', - 'Aliana', - 'Keila', - 'Maryam', - 'Marianna', - 'Magaly', - 'Sariah', - 'Marnie', - 'Kiersten', - 'Janeth', - 'Lyndsey', - 'Shelli', - 'Jaylee', - 'Ashlie', - 'Tianna', - 'Bree', - 'Isela', - 'Krystina', - 'Yaretzy', - 'Evelina', - 'Sarina', - 'Tyra', - 'Eloisa', - 'Maite', - 'Leilah', - 'Marcie', - 'Imelda', - 'Alena', - 'Juniper', - 'Shelbie', - 'Shakira', - 'Ember', - 'Emmalyn', - 'Elissa', - 'Skyla', - 'Lylah', - 'Xitlali', - 'Gisele', - 'Polly', - 'Ernestina', - 'Sandi', - 'Emmy', - 'Josefa', - 'Magali', - 'Ashely', - 'Eve', - 'Jayde', - 'Rosella', - 'Yuridia', - 'Sheyla', - 'Raelyn', - 'Domenica', - 'Valarie', - 'Herminia', - 'Katalina', - 'Shaquana', - 'Nelly', - 'Rosalyn', - 'Denice', - 'Saanvi', - 'Cambria', - 'Joseline', - 'Tomasa', - 'Milana', - 'Harriett', - 'Devorah', - 'Jackelyn', - 'Jacquelin', - 'Yadhira', - 'Antonella', - 'Shreya', - 'Janay', - 'Betzy', - 'Kaiya', - 'Terra', - 'Roseanne', - 'Karime', - 'Lina', - 'Macey', - 'Vilma', - 'Shaniya', - 'Deyanira', - 'Cindi', - 'Mandi', - 'Sanaa', - 'Lakesha', - 'Essence', - 'Faviola', - 'Brinley', - 'Kirstie', - 'Brissa', - 'Alia', - 'Janney', - 'Kaylynn', - 'Kamilah', - 'Kianna', - 'Adrianne', - 'Yasmeen', - 'Jerri', - 'Anayeli', - 'Ambar', - 'Lorri', - 'Hailie', - 'Demetria', - 'Awilda', - 'Isabell', - 'Leonor', - 'Florine', - 'Tennille', - 'Deann', - 'Nyah', - 'Jolette', - 'Xitlaly', - 'Vienna', - 'Lenora', - 'Keily', - 'Syble', - 'Ciera', - 'Milania', - 'Lainey', - 'Nyasia', - 'Carley', - 'Kelsi', - 'Blossom', - 'Maranda', - 'Ally', - 'Serina', - 'Charli', - 'Taraji', - 'Jena', - 'Natalya', - 'Hortencia', - 'Ila', - 'Kailani', - 'Mira', - 'Evie', - 'Ione', - 'Briseyda', - 'Aryana', - 'Yarely', - 'Susanna', - 'Amya', - 'Kaleigh', - 'Qiana', - 'Juli', - 'Mckayla', - 'Suzan', - 'Fallon', - 'Jacalyn', - 'Ileana', - 'Yesica', - 'Willa', - 'Fatoumata', - 'Arly', - 'Jakayla', - 'Chyna', - 'Jaida', - 'Sunshine', - 'Beyonce', - 'Lawanda', - 'Flossie', - 'Lupita', - 'Demi', - 'Keely', - 'Aliya', - 'Jeanie', - 'Tamiko', - 'Gigi', - 'Brissia', - 'Mariel', - 'Lluvia', - 'Jasleen', - 'Lizet', - 'Brittanie', - 'Kaci', - 'Alycia', - 'Madalynn', - 'Milena', - 'Coraline', - 'Kaela', - 'Soraya', - 'Mozelle', - 'Jessenia', - 'Wilhelmina', - 'Jazmyn', - 'Stefani', - 'Natali', - 'Christiana', - 'Ivana', - 'Eiza', - 'Zaria', - 'Zaira', - 'Lorelei', - 'Cherry', - 'Aline', - 'Briseida', - 'Siani', - 'Yara', - 'Rhianna', - 'Kalia', - 'Destiney', - 'Hindy', - 'Arlette', - 'Shyanne', - 'Joceline', - 'Janell', - 'Vianey', - 'Elnora', - 'Zoie', - 'Elba', - 'Jamila', - 'Rena', - 'Mari', - 'Chava', - 'Scarlette', - 'Shyla', - 'Corine', - 'Kaliyah', - 'Ailyn', - 'Liv', - 'Freya', - 'Diya', - 'Myrtis', - 'Aliah', - 'Margery', - 'Gracelyn', - 'Shira', - 'Riya', - 'Breann', - 'Siobhan', - 'Rochel', - 'Tiffanie', - 'Mirna', - 'Nilsa', - 'Tenley', - 'Aliza', - 'Celena', - 'Vianney', - 'Janel', - 'Toccara', - 'Dayna', - 'Rona', - 'Alba', - 'Althea', - 'Josselyn', - 'Karlie', - 'Alyce', - 'Erlinda', - 'Kadijah', - 'Rosalba', - 'Tangela', - 'Marlena', - 'Delois', - 'Chastity', - 'Coral', - 'Braelynn', - 'Dalila', - 'Rosetta', - 'Lu', - 'Venessa', - 'Kayley', - 'Barbra', - 'Jesica', - 'Dona', - 'Mitzi', - 'Catrina', - 'Gracelynn', - 'Ophelia', - 'Ayana', - 'Mara', - 'Calista', - 'Adyson', - 'Marilynn', - 'Tomeka', - 'Britni', - 'Whitley', - 'Karly', - 'Verenice', - 'Raylee', - 'Dayanna', - 'Shonda', - 'Felecia', - 'Betzaida', - 'Kaylani', - 'Shaylee', - 'Jazzlyn', - 'Giavanna', - 'Vivianna', - 'Jesusa', - 'Lashonda', - 'Maile', - 'Suzy', - 'Vania', - 'Giada', - 'Maisie', - 'Venus', - 'Emerald', - 'Wilda', - 'Saniya', - 'Naydelin', - 'Enid', - 'Leilany', - 'Jesenia', - 'Maliah', - 'Dortha', - 'Dalary', - 'Chany', - 'Amia', - 'Amalia', - 'Khaleesi', - 'Taina', - 'Abbey', - 'Dollie', - 'Joslyn', - 'Sommer', - 'Lilibeth', - 'Charleigh', - 'Sydell', - 'Shoshana', - 'Nechama', - 'Jamya', - 'Jeanmarie', - 'Albertha', - 'Akeelah', - 'Aanya', - 'Destini', - 'Kacie', - 'Maleah', - 'Cayla', - 'Bryana', - 'Zelma', - 'Anjanette', - 'Kaylah', - 'Tonja', - 'Amairani', - 'Karli', - 'Elina', - 'Aurelia', - 'Judie', - 'Letha', - 'Brittnee', - 'Yanira', - 'Ariza', - 'Kataleya', - 'Berta', - 'Soleil', - 'Marleen', - 'Desteny', - 'Gissel', - 'Suri', - 'Anjelica', - 'Lilith', - 'Breeanna', - 'Krysta', - 'Alysia', - 'Chrissy', - 'Lailah', - 'Cathryn', - 'Dawna', - 'Myah', - 'Lelia', - 'Aviana', - 'Xena', - 'Pansy', - 'Jazleen', - 'Kaylyn', - 'Mariann', - 'Celene', - 'Berniece', - 'Anjali', - 'Benita', - 'Reanna', - 'Sydnee', - 'Taliyah', - 'Raylene', - 'Kristyn', - 'Latonia', - 'Pa', - 'Nola', - 'Lyanne', - 'Danae', - 'Sharla', - 'Chanelle', - 'Aleyda', - 'Deb', - 'Sofie', - 'Shameka', - 'Emelia', - 'Miya', - 'Latricia', - 'Claribel', - 'Lacie', - 'Taisha', - 'Queen', - 'Breeana', - 'Ilana', - 'Erna', - 'Neha', - 'Melodie', - 'Ariah', - 'Ursula', - 'Janna', - 'Cienna', - 'Maryjo', - 'Vannessa', - 'Saniyah', - 'Mariajose', - 'Malaya', - 'Abbigail', - 'Elin', - 'Emi', - 'Shanaya', - 'Zahra', - 'Lorine', - 'Karrie', - 'Johnna', - 'Marni', - 'Karis', - 'Shelba', - 'Omayra', - 'Claudette', - 'Anitra', - 'Jenelle', - 'Zelda', - 'Alyse', - 'Alethea', - 'Jannet', - 'Myranda', - 'Corinna', - 'Pattie', - 'Jemma', - 'Avah', - 'Joycelyn', - 'Loriann', - 'Kirstin', - 'Davina', - 'Clementine', - 'Arantza', - 'Esme', - 'Vida', - 'Samira', - 'Alysa', - 'Ananya', - 'Cherish', - 'Jocelin', - 'Renae', - 'Jalisa', - 'Elease', - 'Salena', - 'Zhane', - 'Zulema', - 'Rubye', - 'Amerie', - 'Leatrice', - 'Geralyn', - 'Brigitte', - 'Sibyl', - 'Corrina', - 'Phylicia', - 'Karlee', - 'Kerrie', - 'Addilyn', - 'Alayah', - 'Jacquely', - 'Mirian', - 'Jovana', - 'Katelin', - 'Marielena', - 'Libby', - 'Aditi', - 'Nalani', - 'Lilyanna', - 'Mylee', - 'Goldy', - 'Melia', - 'Audriana', - 'Lillyana', - 'Enriqueta', - 'Tasia', - 'Debbi', - 'Ani', - 'Elyssa', - 'Yamile', - 'Bridgett', - 'Taniya', - 'Britany', - 'Latosha', - 'Shanda', - 'Estephanie', - 'Maudie', - 'Mariyah', - 'Tana', - 'Neva', - 'Kalea', - 'Oma', - 'Jazelle', - 'Neveah', - 'Leonora', - 'Miesha', - 'Corrine', - 'Jordynn', - 'Cornelia', - 'Ronni', - 'Malinda', - 'Janeen', - 'Neriah', - 'Brigette', - 'Windy', - 'Cassondra', - 'Klarissa', - 'Lizzette', - 'Tanika', - 'Izamar', - 'Tera', - 'Arianny', - 'Florene', - 'Evalyn', - 'Poppy', - 'Deisy', - 'Jannette', - 'Thania', - 'Kelsea', - 'Taniyah', - 'Geri', - 'Allyssa', - 'Zariyah', - 'Averi', - 'Leeann', - 'Kallie', - 'Loni', - 'Bryleigh', - 'Rosina', - 'Carlee', - 'Preslee', - 'Alexsandra', - 'Adamari', - 'Saray', - 'Yaneli', - 'Raina', - 'Lianna', - 'Keilani', - 'Tamela', - 'Ninfa', - 'Ireland', - 'Shante', - 'Racheal', - 'Zainab', - 'Blima', - 'Yocheved', - 'Gema', - 'Sayra', - 'Aretha', - 'Nya', - 'Criselda', - 'Anai', - 'Bracha', - 'Amirah', - 'Sury', - 'Twila', - 'Arissa', - 'Livia', - 'Jacquline', - 'Chiara', - 'Anneliese', - 'Quiana', - 'Monika', - 'Charisse', - 'Emerie', - 'Rosalva', - 'Halie', - 'Jenesis', - 'Zaylee', - 'Pricilla', - 'Ouida', - 'Felipa', - 'Latifah', - 'Kalley', - 'Clarice', - 'Nona', - 'Jaunita', - 'Hermelinda', - 'Analy', - 'Jizelle', - 'Theda', - 'Yoselyn', - 'Dottie', - 'Brittaney', - 'Meghann', - 'Azeneth', - 'Richelle', - 'Peggie', - 'Brittny', - 'Jaci', - 'Marietta', - 'Gissell', - 'Evolet', - 'Abbygail', - 'Naima', - 'Noelani', - 'Jaslyn', - 'Katheryn', - 'Ruthann', - 'Shelva', - 'Ashli', - 'Alianna', - 'Felicitas', - 'Delfina', - 'Rayna', - 'Christal', - 'Leta', - 'Tawnya', - 'Zaniyah', - 'Cathie', - 'Antonette', - 'Bethann', - 'Nannette', - 'Vita', - 'Santa', - 'Dejah', - 'Patience', - 'Alessia', - 'Ahuva', - 'Karely', - 'Anette', - 'Alfreda', - 'Cyndi', - 'Cami', - 'Shirlee', - 'Roxann', - 'Alvina', - 'Sima', - 'Star', - 'Tatianna', - 'Krissy', - 'Dreama', - 'Diann', - 'Birdie', - 'Yoshiko', - 'Violette', - 'Mylah', - 'Rosita', - 'Eartha', - 'Miabella', - 'Shanika', - 'Gricel', - 'Ariyah', - 'Emmalee', - 'Nidia', - 'Gladis', - 'Roxie', - 'Zoraida', - 'Kandace', - 'Annamarie', - 'Alannah', - 'Abrielle', - 'Mercy', - 'Lesli', - 'Sydni', - 'Kathrine', - 'Jiselle', - 'Anisa', - 'Felisha', - 'Kayli', - 'Nanci', - 'Ria', - 'Cailyn', - 'Melani', - 'Alyna', - 'Bambi', - 'Avril', - 'Amberly', - 'Towanda', - 'Malissa', - 'Kaleena', - 'Kinsey', - 'Andria', - 'Emogene', - 'Milani', - 'Milah', - 'Hadassah', - 'Avianna', - 'Aubri', - 'Pessy', - 'Dori', - 'Tea', - 'Keshia', - 'Adina', - 'Esha', - 'Magnolia', - 'Moesha', - 'Elana', - 'Vikki', - 'Lakendra', - 'Ilse', - 'Sydnie', - 'Laquita', - 'Hortense', - 'Elouise', - 'Tarah', - 'Shamika', - 'Genoveva', - 'Margot', - 'Aubrielle', - 'Aya', - 'Aleta', - 'Shantell', - 'Angelle', - 'Lakeshia', - 'Leota', - 'Stormie', - 'Caryl', - 'Cristy', - 'Sydelle', - 'Analisa', - 'Earlene', - 'Syreeta', - 'Paityn', - 'Citlally', - 'Nikole', - 'Leandra', - 'Elda', - 'Lizbet', - 'Blimy', - 'Lorelai', - 'Gittel', - 'Jasmyn', - 'Verania', - 'Zoya', - 'Anyssa', - 'Jeniffer', - 'Dorene', - 'Makaila', - 'Earlean', - 'Ysabella', - 'Brandee', - 'Nailea', - 'Stefany', - 'Amiya', - 'Carolee', - 'Kassie', - 'Theodora', - 'Merissa', - 'Skylah', - 'Alesia', - 'Leela', - 'Madge', - 'Shanta', - 'Soledad', - 'Sharonda', - 'Thea', - 'Capri', - 'Amparo', - 'Concha', - 'Karolina', - 'Keitha', - 'Harriette', - 'Evette', - 'Mylie', - 'Isha', - 'Suzie', - 'Carlene', - 'Brunilda', - 'Annamae', - 'Ariadna', - 'Sanai', - 'Gisell', - 'Danelle', - 'Dovie', - 'Lani', - 'Shavonne', - 'Janiah', - 'Kora', - 'Jessa', - 'Melva', - 'Yehudis', - 'Analee', - 'Enedina', - 'Oaklee', - 'Aubrianna', - 'Velia', - 'Zooey', - 'Dolly', - 'Shanae', - 'Lyndsay', - 'Allene', - 'Kamya', - 'Tedra', - 'Yecenia', - 'Nyree', - 'Shyann', - 'Kandice', - 'Edwina', - 'Aiyanna', - 'Carli', - 'Sariyah', - 'Gwyneth', - 'Roseanna', - 'Charla', - 'Nereyda', - 'Yides', - 'Helaine', - 'Evita', - 'Alanis', - 'Starr', - 'Rosalee', - 'Yaire', - 'Risa', - 'Kristel', - 'Greidys', - 'Lillianna', - 'Khushi', - 'Triniti', - 'Lilyan', - 'Myesha', - 'Kala', - 'Moira', - 'Neida', - 'Gisel', - 'Myriam', - 'Anali', - 'Izabel', - 'Savana', - 'Sanjana', - 'Willodean', - 'Briza', - 'Lyra', - 'Merry', - 'Cheryle', - 'Porsha', - 'Kaili', - 'Buffy', - 'Deidra', - 'Everleigh', - 'Gardenia', - 'Italia', - 'Novella', - 'Sahara', - 'Sirena', - 'Elide', - 'Madisen', - 'Katerina', - 'Ashlea', - 'Rianna', - 'Samatha', - 'Diandra', - 'Shanell', - 'Annalee', - 'Samiyah', - 'Joselyne', - 'Maylin', - 'Jazmyne', - 'Terese', - 'Nydia', - 'Stasia', - 'Saira', - 'Carlota', - 'Kathia', - 'Katya', - 'Elodie', - 'Priya', - 'Malena', - 'Aadhya', - 'Meera', - 'Tayla', - 'Jovita', - 'Rafaela', - 'Faiga', - 'Jaquelyn', - 'Elisheva', - 'Debbra', - 'Melyssa', - 'Chelsi', - 'Gricelda', - 'Tawanda', - 'Sharlene', - 'Mellissa', - 'Alene', - 'Amayah', - 'Nicolle', - 'Yanet', - 'Zissy', - 'Candi', - 'Hedwig', - 'Leyna', - 'Nichol', - 'Reva', - 'Fraidy', - 'Esty', - 'Kaily', - 'Mimi', - 'Shani', - 'Hadlee', - 'Naomy', - 'Kinslee', - 'Emmalynn', - 'Alverta', - 'Anushka', - 'Tinsley', - 'Armida', - 'Cleta', - 'Analise', - 'Ahtziri', - 'Anakaren', - 'Tracee', - 'Glynda', - 'Kaelynn', - 'Carie', - 'Avalon', - 'Eboni', - 'Shameeka', - 'Letitia', - 'Enola', - 'Rasheeda', - 'Taylee', - 'Jerrica', - 'Janely', - 'Taya', - 'Xochilt', - 'Rosana', - 'Doretha', - 'Henny', - 'Shaniece', - 'Charleen', - 'Abigale', - 'Marylyn', - 'Retha', - 'Keren', - 'Elly', - 'Ailani', - 'Aarna', - 'Starla', - 'Maren', - 'Nan', - 'Marivel', - 'Georgianna', - 'Era', - 'Kirra', - 'Maisha', - 'Caydence', - 'Dinah', - 'Noemy', - 'Tamatha', - 'Madonna', - 'Kristan', - 'Keana', - 'Kloe', - 'Maribeth', - 'Sana', - 'Korina', - 'Irania', - 'Izabelle', - 'Roxy', - 'Mariaguadalupe', - 'Sulema', - 'Vivien', - 'Tatia', - 'Holli', - 'Debrah', - 'Kattie', - 'Kaidence', - 'Cathey', - 'Anniston', - 'Refugia', - 'Renita', - 'Aubriella', - 'Kaleah', - 'Zuleyka', - 'Sherie', - 'Tomika', - 'Charisma', - 'Caridad', - 'Kailynn', - 'Gertie', - 'Jaslynn', - 'Agatha', - 'Avani', - 'Hennessy', - 'Pamala', - 'Malak', - 'Raizel', - 'Kami', - 'Rosalina', - 'Ferne', - 'Cloe', - 'Jeryl', - 'Louann', - 'Jacie', - 'Tais', - 'Johnsie', - 'Brittnie', - 'Collette', - 'Lettie', - 'Jeanna', - 'Kyara', - 'Renada', - 'Abrianna', - 'Nayelli', - 'Alda', - 'Yuna', - 'Cristi', - 'Yazmine', - 'Marlie', - 'Milly', - 'Anastacia', - 'Daria', - 'Caitlynn', - 'Shriya', - 'Vianca', - 'Sayuri', - 'Dennise', - 'Aleyna', - 'Jenni', - 'Tanesha', - 'Suzanna', - 'Zaniya', - 'Kesha', - 'Edie', - 'Ansleigh', - 'Emmie', - 'Marjory', - 'Lanette', - 'Babette', - 'Alaya', - 'Palma', - 'Tamie', - 'Nelle', - 'Haydee', - 'Zeinab', - 'Stephania', - 'Biridiana', - 'Yoshie', - 'Mayme', - 'Michaele', - 'Marimar', - 'Winona', - 'Christene', - 'Meadow', - 'Ariya', - 'Daleysa', - 'Thuy', - 'Nautica', - 'Hadleigh', - 'Aliyana', - 'Annabell', - 'Stacia', - 'Leonore', - 'Albina', - 'Daira', - 'Rhona', - 'Lisbet', - 'Alizae', - 'Aminata', - 'Samanta', - 'Jerilyn', - 'Darci', - 'Sudie', - 'Kynleigh', - 'Marva', - 'Karie', - 'Marbella', - 'Franchesca', - 'Kylah', - 'Lillyanna', - 'Melony', - 'Abygail', - 'Yulianna', - 'Sahana', - 'Velvet', - 'Michelina', - 'Treva', - 'Iona', - 'Adilynn', - 'Milla', - 'Teressa', - 'Coretta', - 'Venita', - 'Evalynn', - 'Chynna', - 'Janett', - 'Nohemi', - 'Symone', - 'Kaycee', - 'Racquel', - 'Jerica', - 'Chanda', - 'Vannesa', - 'Deasia', - 'Alanah', - 'Dasha', - 'Dian', - 'Iyana', - 'Katlin', - 'Shizue', - 'Mitsuko', - 'Shara', - 'Shanelle', - 'Sinead', - 'Jacinda', - 'Alecia', - 'Tanvi', - 'Genese', - 'Crissy', - 'Niki', - 'Shanequa', - 'Trish', - 'Shalonda', - 'Darleen', - 'Magda', - 'Annalisa', - 'Lashanda', - 'Carin', - 'Nahomi', - 'Londynn', - 'Alaysia', - 'Annaliese', - 'Valorie', - 'Naidelyn', - 'Abbe', - 'Karley', - 'Cinda', - 'Marilu', - 'Azaria', - 'Kitty', - 'Mechelle', - 'Jazzmin', - 'Malina', - 'Cianna', - 'Leesa', - 'Nahla', - 'Dorotha', - 'Jaeda', - 'Tinley', - 'Kelis', - 'Ayesha', - 'Cinthya', - 'Shawnte', - 'Fawn', - 'Calleigh', - 'Mittie', - 'Aide', - 'Lisset', - 'Tyesha', - 'Devora', - 'Analeigh', - 'Anahy', - 'Donnamarie', - 'Nala', - 'Haruko', - 'Lesia', - 'Aideliz', - 'Emme', - 'Mitsue', - 'Jamiya', - 'Joleen', - 'Missy', - 'Shawanda', - 'Chastelyn', - 'Jaleah', - 'Eulalia', - 'Elvera', - 'Kalina', - 'Adrina', - 'Nicolasa', - 'Belia', - 'Elodia', - 'Kazuko', - 'Ixchel', - 'Leena', - 'Yoseline', - 'Yocelin', - 'Jamiyah', - 'Mariama', - 'Audrianna', - 'Dasia', - 'Ieshia', - 'Malorie', - 'Toniann', - 'Genessis', - 'Makeda', - 'Cherise', - 'Tarsha', - 'Karri', - 'Romayne', - 'Beronica', - 'Nubia', - 'Shasta', - 'Cristin', - 'Cristine', - 'Eryn', - 'Jazzmine', - 'Alyssia', - 'Verona', - 'Divya', - 'Beatrix', - 'Chiyoko', - 'Destinie', - 'Hali', - 'Myisha', - 'Sabina', - 'Chante', - 'Brea', - 'Aundrea', - 'Harmoni', - 'Iyanna', - 'Rosaria', - 'Hettie', - 'Bronte', - 'Constanza', - 'Heavenly', - 'Georgiana', - 'Coco', - 'Eleni', - 'Brylie', - 'Ajee', - 'Jerrie', - 'Zella', - 'Xenia', - 'Djuana', - 'Bianka', - 'Lizett', - 'Destany', - 'Bettina', - 'Pennie', - 'Ciji', - 'Ciani', - 'Tosha', - 'Roxane', - 'Tenisha', - 'Pepper', - 'Ayva', - 'Dynasty', - 'Krysten', - 'Maud', - 'Janene', - 'Yomaira', - 'Kizzie', - 'Oriana', - 'Antionette', - 'Kamille', - 'Candis', - 'Kimberlie', - 'Britta', - 'Malika', - 'Khalilah', - 'Louisa', - 'Maiya', - 'Shanay', - 'Kellye', - 'Gaye', - 'Rosangelica', - 'Breonna', - 'Jenae', - 'Kaylene', - 'Rileigh', - 'Linnea', - 'Tawanna', - 'Harleen', - 'Tamya', - 'Makaylah', - 'Annabeth', - 'Alysson', - 'Adella', - 'Adalee', - 'Karisa', - 'Rosangela', - 'Ema', - 'Dayra', - 'Tena', - 'Mathilda', - 'Magan', - 'Dayanira', - 'Annelise', - 'Takisha', - 'Rosamaria', - 'Shifra', - 'Vianna', - 'Daysi', - 'Jalissa', - 'Samaya', - 'Aubriana', - 'Alora', - 'Emmeline', - 'Elora', - 'Laylani', - 'Willene', - 'Cathrine', - 'Ginny', - 'Lashunda', - 'Mikalah', - 'Kiyoko', - 'Wynter', - 'Zuleima', - 'Alease', - 'Louella', - 'Jubilee', - 'Allegra', - 'Karmen', - 'Emiliana', - 'Jianna', - 'Eisley', - 'Emmaline', - 'Teresita', - 'Mackenna', - 'Lauretta', - 'Krystin', - 'Kalene', - 'Aviva', - 'Zena', - 'Shanique', - 'Glynis', - 'Toya', - 'Linsey', - 'Denisha', - 'Marysol', - 'Marcelina', - 'Makiyah', - 'Masako', - 'Cintia', - 'Sharen', - 'Lahoma', - 'Magen', - 'Alyvia', - 'Shaniyah', - 'Anamaria', - 'Shivani', - 'Hannia', - 'Chavy', - 'Hayleigh', - 'Jaycie', - 'Mayah', - 'Delila', - 'Danita', - 'Modesta', - 'Arcelia', - 'Deedee', - 'Monserrath', - 'Angelie', - 'Mellisa', - 'Leisa', - 'Melannie', - 'Mafalda', - 'Kinlee', - 'Annetta', - 'Freida', - 'Anisha', - 'Mayrin', - 'Dajah', - 'Delylah', - 'Hortensia', - 'Joretta', - 'Lexy', - 'Laysha', - 'Anessa', - 'Jesusita', - 'Pearline', - 'Caleigh', - 'Liset', - 'Leilene', - 'Jaya', - 'Haily', - 'Tatyanna', - 'Desire', - 'Lisha', - 'Mindi', - 'Ivelisse', - 'Amariah', - 'Blythe', - 'Treasure', - 'Latarsha', - 'Emelda', - 'Latavia', - 'Debanhi', - 'Brynleigh', - 'Gala', - 'Jurnee', - 'Joslynn', - 'Harleigh', - 'Trang', - 'Audree', - 'Brande', - 'Genea', - 'Carri', - 'Kandy', - 'Kenisha', - 'Georgene', - 'Kamora', - 'Anabell', - 'Meranda', - 'Renesmee', - 'Rosaura', - 'Linette', - 'Rosamond', - 'Candida', - 'Crista', - 'Keeley', - 'Mykayla', - 'Rina', - 'Jonna', - 'Lorinda', - 'Wynona', - 'Kylene', - 'Kellee', - 'Elayne', - 'Chela', - 'Zykeria', - 'Shawnna', - 'Jaimee', - 'Zuleyma', - 'Britnee', - 'Mikala', - 'Coletta', - 'Morelia', - 'Isadora', - 'Anayah', - 'Amiah', - 'Ailin', - 'Jordana', - 'Casie', - 'Shakia', - 'Cordelia', - 'Analeah', - 'Janelly', - 'Adelita', - 'Yoana', - 'Lizabeth', - 'Latoria', - 'Pricila', - 'Margaretta', - 'Fumiko', - 'Lura', - 'Toshiko', - 'Marge', - 'Luana', - 'Marilee', - 'Jeana', - 'Tallulah', - 'Zia', - 'Betsabe', - 'Delanie', - 'Jenicka', - 'Kensington', - 'Navya', - 'Golda', - 'Kambree', - 'Orpha', - 'Rayleigh', - 'Kinleigh', - 'Karleigh', - 'Avalynn', - 'Addilynn', - 'Cambree', - 'Brinlee', - 'Liba', - 'Zendaya', - 'Farah', - 'Oumou', - 'Aislinn', - 'Karena', - 'Erendira', - 'Mariaelena', - 'Temperance', - 'Angelic', - 'Khadija', - 'Jonelle', - 'Aniah', - 'Aleigha', - 'Samaria', - 'Dedra', - 'Sammantha', - 'Bernardine', - 'Leilanie', - 'Makaela', - 'Samiya', - 'Porsche', - 'Krystel', - 'Simona', - 'Catarina', - 'Joi', - 'Etty', - 'Jannat', - 'Rubie', - 'Waneta', - 'Shaquita', - 'Shaindel', - 'Alida', - 'January', - 'Riana', - 'Jamilet', - 'Jala', - 'Gearldine', - 'Iola', - 'Tiesha', - 'Ariyana', - 'Josslyn', - 'Verla', - 'Gerri', - 'Emili', - 'Jennyfer', - 'Halo', - 'Raya', - 'Asusena', - 'Jessalyn', - 'Anaiah', - 'Sabine', - 'Dorinda', - 'Andriana', - 'Charissa', - 'Cambrie', - 'Daija', - 'Danyelle', - 'Maricarmen', - 'Melania', - 'Glinda', - 'Jaretzy', - 'Keesha', - 'Lucie', - 'Persephone', - 'Veda', - 'Avalyn', - 'Odilia', - 'Teena', - 'Daisha', - 'Shianne', - 'Nadya', - 'Peighton', - 'Shawana', - 'Lateefah', - 'Geena', - 'Aixa', - 'Magdalene', - 'Estefana', - 'China', - 'Tamekia', - 'Audrie', - 'Angely', - 'Charline', - 'Britny', - 'Quanisha', - 'Erykah', - 'Kenzi', - 'Carleigh', - 'Kamiyah', - 'Zayra', - 'Abagail', - 'Sulay', - 'Shelita', - 'Cattleya', - 'Ariela', - 'Yalitza', - 'Marleigh', - 'Colbie', - 'Lavergne', - 'Pyper', - 'Tawni', - 'Kasie', - 'Kati', - 'Cinnamon', - 'Trana', - 'Verda', - 'Romana', - 'Merrily', - 'Landri', - 'Bruchy', - 'Irlanda', - 'Lanie', - 'Kendyl', - 'Sanvi', - 'Akshara', - 'Aneesa', - 'Giulia', - 'Ruchy', - 'Giulianna', - 'Zahara', - 'Sumaya', - 'Guillermina', - 'Araseli', - 'Jackelin', - 'Norine', - 'Ariane', - 'Naidelin', - 'Gwenyth', - 'Kya', - 'Liyah', - 'Danya', - 'Sujey', - 'Grayce', - 'Honey', - 'Assunta', - 'Aleksandra', - 'Almeda', - 'Devany', - 'Spring', - 'Patrica', - 'Delisa', - 'Fantasia', - 'Cydney', - 'Laquisha', - 'Lynsey', - 'Stephenie', - 'Cassaundra', - 'Elisabet', - 'Echo', - 'Juliann', - 'Micayla', - 'Iridiana', - 'Antonietta', - 'Rosaisela', - 'Bayleigh', - 'Candelaria', - 'Zaida', - 'Mercedez', - 'Kindra', - 'Malayah', - 'Stephaine', - 'Nayla', - 'Tameeka', - 'Kiesha', - 'Pooja', - 'Sahar', - 'Paisleigh', - 'Kynslee', - 'Idella', - 'Arelis', - 'Shizuko', - 'Leslee', - 'Acacia', - 'Elexis', - 'Violetta', - 'Sailor', - 'Marceline', - 'Una', - 'Kamilla', - 'Aulani', - 'Aracelis', - 'Kikue', - 'Kasi', - 'Elwanda', - 'Brookelyn', - 'Kellyann', - 'Shaquanna', - 'Marielle', - 'Isel', - 'Agustina', - 'Vergie', - 'Arriana', - 'Perel', - 'Maylee', - 'Navy', - 'Lanell', - 'Rosann', - 'Carmelita', - 'Deisi', - 'Alyza', - 'Nailah', - 'Somaya', - 'Kiarra', - 'Tatiyana', - 'Nelida', - 'Demetra', - 'Thais', - 'Syriana', - 'Nicki', - 'Tyanna', - 'Idaly', - 'Ramonita', - 'Zuzanna', - 'Aiza', - 'Larae', - 'Alyanna', - 'Aleyah', - 'Elayna', - 'Blaire', - 'Laniyah', - 'Rilynn', - 'Kandi', - 'Sherryl', - 'Marti', - 'Cherri', - 'Kimberli', - 'Carma', - 'Trena', - 'Darcie', - 'Evelyne', - 'Allissa', - 'Meliza', - 'Regine', - 'Adalina', - 'Siya', - 'Seraphina', - 'Calliope', - 'Jiya', - 'Talisa', - 'Mistie', - 'Ignacia', - 'Crysta', - 'Lona', - 'Voncile', - 'Rutha', - 'Kamiya', - 'Anslee', - 'Janya', - 'Berenise', - 'Sonji', - 'Yaeko', - 'Nika', - 'Queena', - 'Yatziri', - 'Aiko', - 'Lisamarie', - 'Evalina', - 'Alline', - 'Alejandrina', - 'Trula', - 'Hinda', - 'Delinda', - 'Brisia', - 'Aminah', - 'Mariella', - 'Nayzeth', - 'Sherlin', - 'Idalia', - 'Madaline', - 'Shenika', - 'Janaya', - 'Fabiana', - 'Aleeah', - 'Lasonya', - 'Jania', - 'Breindy', - 'Mitzy', - 'Yaquelin', - 'Tzipora', - 'Serene', - 'Mikaila', - 'Aicha', - 'Brucha', - 'Myrka', - 'Kaaren', - 'Meg', - 'Lise', - 'Suhani', - 'Liane', - 'Celisse', - 'Jasmyne', - 'Sharde', - 'Dannielle', - 'Crystle', - 'Jenniffer', - 'Shaneka', - 'Leslye', - 'Hedy', - 'Tashina', - 'Letisia', - 'Carys', - 'Antonetta', - 'Tamisha', - 'Kaniya', - 'Darline', - 'Alizay', - 'Minna', - 'Raelene', - 'Rebecka', - 'Martika', - 'Makiya', - 'Idalis', - 'Keasia', - 'Breeann', - 'Vlasta', - 'Ellianna', - 'Caelyn', - 'Kaytlin', - 'Cathi', - 'Jamia', - 'Tahnee', - 'Zulma', - 'Mallorie', - 'Katlynn', - 'Mahi', - 'Carleen', - 'Honesty', - 'Rasheedah', - 'Ronna', - 'Lissa', - 'Sherika', - 'Carolynn', - 'Romona', - 'Jamesha', - 'Shakiyla', - 'Mccall', - 'Joanie', - 'Makala', - 'Brionna', - 'Shaunna', - 'Hawa', - 'Marylin', - 'Baylie', - 'Preslie', - 'Aaralyn', - 'Pia', - 'Beatris', - 'Adria', - 'Arianne', - 'Carmina', - 'Sebrina', - 'Malani', - 'Lovely', - 'Jahaira', - 'Miyah', - 'Sylvie', - 'Cassi', - 'Kaniyah', - 'Cailin', - 'Santina', - 'Nariah', - 'Calandra', - 'Georgine', - 'Serafina', - 'Keyana', - 'Amethyst', - 'Tehya', - 'Avni', - 'Alessa', - 'Novalee', - 'Mayleen', - 'Aadya', - 'Jacquelynn', - 'Izetta', - 'Sumiko', - 'Irasema', - 'Annamaria', - 'Niya', - 'Latrina', - 'Cicely', - 'Kristiana', - 'Kimiko', - 'Keara', - 'Mazie', - 'Najah', - 'Evelia', - 'Tiarra', - 'Jaela', - 'Montine', - 'Mandie', - 'Lavada', - 'Dimple', - 'Emiko', - 'Yocelyn', - 'Issabella', - 'Rowena', - 'Tanja', - 'Velda', - 'Chantell', - 'Gretel', - 'Jacelyn', - 'Kambri', - 'Zayla', - 'Anasofia', - 'Atiana', - 'Dulcemaria', - 'Zulay', - 'Tari', - 'Sahasra', - 'Rayleen', - 'Greydis', - 'Shiela', - 'Florinda', - 'Samya', - 'Shakima', - 'Shakeema', - 'Yanely', - 'Lavina', - 'Azalee', - 'Oneta', - 'Tammye', - 'Kelsy', - 'Kalie', - 'Keanna', - 'Daniya', - 'Antonina', - 'Katharin', - 'Tiare', - 'Yorley', - 'Jeslyn', - 'Emeli', - 'Zakia', - 'Massiel', - 'Latesha', - 'Jenessa', - 'Jayna', - 'Raylynn', - 'Ainslee', - 'Aralynn', - 'Khloee', - 'Ily', - 'Emeri', - 'Jeni', - 'Kassi', - 'Nakita', - 'Lakia', - 'Ariyanna', - 'Addalyn', - 'Keyanna', - 'Bibiana', - 'Genna', - 'Kathya', - 'Leana', - 'Trane', - 'Yomira', - 'Brigid', - 'Dionna', - 'Jerilynn', - 'Sarita', - 'Altha', - 'Laniya', - 'Zakiya', - 'Akilah', - 'Celestina', - 'Priyanka', - 'Taliah', - 'Donya', - 'Soila', - 'Quetzalli', - 'Cristel', - 'Naia', - 'Kailah', - 'Zitlaly', - 'Tonda', - 'Cate', - 'Lizzet', - 'Vesta', - 'Sherilyn', - 'Teruko', - 'Aldona', - 'Armandina', - 'Ciana', - 'Amairany', - 'Elysia', - 'Samarah', - 'Janyla', - 'Skylee', - 'Rolanda', - 'Sapphire', - 'Setsuko', - 'Miyoko', - 'Contina', - 'Imogen', - 'Jailine', - 'Vanellope', - 'Leora', - 'Jennah', - 'Perl', - 'Analiyah', - 'Hellen', - 'Tyasia', - 'Symphony', - 'Amada', - 'Otilia', - 'Avigail', - 'Tzivia', - 'Fradel', - 'Mariadelcarmen', - 'Ilona', - 'Dyan', - 'Zahraa', - 'Patrisia', - 'Jersey', - 'Lilla', - 'Lossie', - 'Somer', - 'Deserie', - 'Jaila', - 'Briseis', - 'Aniston', - 'Idell', - 'Raeleigh', - 'Gracyn', - 'Everlee', - 'Laurene', - 'Sherita', - 'Pinkie', - 'Nakisha', - 'Olevia', - 'Corene', - 'Loreen', - 'Sandie', - 'Keosha', - 'Kenleigh', - 'Alli', - 'Alyana', - 'Prisha', - 'Brookelynn', - 'Thaily', - 'Maddie', - 'Grettel', - 'Kinzley', - 'Jailynn', - 'Kalli', - 'Jazzlynn', - 'Klaudia', - 'Blanch', - 'Mariafernanda', - 'Makenzi', - 'Shonna', - 'Lita', - 'Karima', - 'Rebeccah', - 'Isaura', - 'Kalee', - 'Jori', - 'Allysa', - 'Tonisha', - 'Neda', - 'Jenine', - 'Chanell', - 'Jamaya', - 'Lorrayne', - 'Birtha', - 'Kanisha', - 'Nicollette', - 'Desiray', - 'Kaity', - 'Shamya', - 'Kathlene', - 'Jann', - 'Sari', - 'Lucila', - 'Tressie', - 'Charise', - 'Kalista', - 'Jamileth', - 'Kalena', - 'Sakura', - 'Blondell', - 'Thomasina', - 'Aila', - 'Mossie', - 'Tamala', - 'Siri', - 'Gertha', - 'Reta', - 'Easter', - 'Tala', - 'Vivianne', - 'Nila', - 'Merida', - 'Ahana', - 'Lanelle', - 'Hilaria', - 'Arlys', - 'Inell', - 'Rylynn', - 'Cosette', - 'Penne', - 'Jenevieve', - 'Jenilee', - 'Carlotta', - 'Ziva', - 'Hildegard', - 'Aleshia', - 'Nedra', - 'Madelaine', - 'Lisandra', - 'Pang', - 'Sindy', - 'Zenaida', - 'Lulu', - 'Shanya', - 'Shakema', - 'Katiria', - 'Raffaela', - 'Solange', - 'Illiana', - 'Chelsy', - 'Shanee', - 'Adriene', - 'Tyla', - 'Cailey', - 'Daijah', - 'Melonie', - 'Courteney', - 'Deysi', - 'Makinley', - 'Brynna', - 'Hildegarde', - 'Fiorella', - 'Kenadee', - 'Ellyn', - 'Ebonie', - 'Thu', - 'Charde', - 'Kaytlyn', - 'Kenadie', - 'Georgeann', - 'Analicia', - 'Emalee', - 'Shatara', - 'Lucerito', - 'Mckell', - 'Atiya', - 'Stormi', - 'Maleny', - 'Nariyah', - 'Steffanie', - 'Kirstyn', - 'Zayda', - 'Mariadejesus', - 'Deeann', - 'Abcde', - 'Eleanora', - 'Pearle', - 'Seana', - 'Denine', - 'Presleigh', - 'Keziah', - 'Queenie', - 'Henchy', - 'Merari', - 'Joscelyn', - 'Celest', - 'Mirel', - 'Sania', - 'Maryah', - 'Angelena', - 'Emelyn', - 'Gissele', - 'Fanta', - 'Gaylene', - 'Adelaida', - 'Madie', - 'Maja', - 'Nashaly', - 'Christel', - 'Rachele', - 'Raniyah', - 'Rashel', - 'Kavya', - 'Callista', - 'Elmira', - 'Rifky', - 'Syeda', - 'Tresa', - 'Detra', - 'Jarely', - 'Prisila', - 'Enedelia', - 'Trany', - 'Lainie', - 'Yisel', - 'Alynna', - 'Allysson', - 'Tamica', - 'Velva', - 'Nancee', - 'Breleigh', - 'Shanita', - 'Orelia', - 'Patrici', - 'Daja', - 'Shardae', - 'Abriana', - 'Halee', - 'Dorcas', - 'Kathey', - 'Rosia', - 'Princesa', - 'Lezly', - 'Dawnmarie', - 'Gaby', - 'Ania', - 'Denae', - 'Jahzara', - 'Jaymie', - 'Bari', - 'Suzann', - 'Alnisa', - 'Fatimah', - 'Zakiyyah', - 'Yana', - 'Naimah', - 'Tyisha', - 'Kathaleen', - 'Sameerah', - 'Chesney', - 'Shanteria', - 'Pamella', - 'Rayven', - 'Romelia', - 'Lucretia', - 'Tova', - 'Aura', - 'Chelsee', - 'Roizy', - 'Manha', - 'Nisha', - 'Tierney', - 'Girl', - 'Taelor', - 'Litzi', - 'Sneha', - 'Natisha', - 'Alliyah', - 'Sully', - 'Twyla', - 'Daisey', - 'Sarahy', - 'Shemeka', - 'Lexis', - 'Shalanda', - 'Kelcie', - 'Natacha', - 'Amyah', - 'Byanka', - 'Kymberly', - 'Navil', - 'Britani', - 'Karolyn', - 'Emelie', - 'Zana', - 'Vernita', - 'Leigha', - 'Romy', - 'Arlet', - 'Jazlin', - 'Laynie', - 'Jesslyn', - 'Adilyn', - 'Karoline', - 'Nyomi', - 'Maycee', - 'Nicol', - 'Daliah', - 'Lillyann', - 'Shawnda', - 'Dede', - 'Wiktoria', - 'Liah', - 'Liya', - 'Emmerson', - 'Aarohi', - 'Aribella', - 'Brayleigh', - 'Sumie', - 'Elke', - 'Taja', - 'Ahsley', - 'Tisa', - 'Dannette', - 'Gidget', - 'Misao', - 'Adelle', - 'Jamiah', - 'Joselynn', - 'Jalyssa', - 'Marnita', - 'Trinitee', - 'Bev', - 'Aleida', - 'Cloey', - 'Tahlia', - 'Melodee', - 'Anaiya', - 'Clover', - 'Prudence', - 'Kalynn', - 'Dezirae', - 'Solana', - 'Reena', - 'Mariko', - 'Tiffiny', - 'Elinore', - 'Madelyne', - 'Anela', - 'Bess', - 'Perri', - 'Loree', - 'Cyndy', - 'Yolonda', - 'Jolee', - 'Tequila', - 'Sumer', - 'Cherilyn', - 'Ela', - 'Kenlee', - 'Alexxis', - 'Larisa', - 'Nevaeha', - 'Nira', - 'Shaquasia', - 'Shanel', - 'Medina', - 'Rifka', - 'Sable', - 'Atara', - 'Aissatou', - 'Mecca', - 'Anastasi', - 'Falon', - 'Holley', - 'Yuliza', - 'Lili', - 'Siara', - 'Kiarah', - 'Tiffaney', - 'Alyah', - 'Annalia', - 'Naila', - 'Analiah', - 'Aymar', - 'Tambra', - 'Elna', - 'Eola', - 'Tkeyah', - 'Zola', - 'Francheska', - 'Aidee', - 'Alexzandra', - 'Cianni', - 'Myasia', - 'Carisa', - 'Ilah', - 'Yenifer', - 'Veronika', - 'Nahomy', - 'Madysen', - 'Elsy', - 'Lilli', - 'Belva', - 'Steffie', - 'Kaylea', - 'Ginamarie', - 'Sharman', - 'Latia', - 'Shakeria', - 'Audelia', - 'Odette', - 'Shaniah', - 'Diamantina', - 'Lorayne', - 'Ciarra', - 'Wilhelmena', - 'Zaina', - 'Niesha', - 'Kanesha', - 'Turquoise', - 'Tziporah', - 'Timi', - 'Fatou', - 'Karna', - 'Matsue', - 'Vina', - 'Ronisha', - 'Layan', - 'Viktoria', - 'Lilyann', - 'Maliya', - 'Jamilex', - 'Epifania', - 'Fidela', - 'Delphia', - 'Starasia', - 'Glennie', - 'Teodora', - 'Hatsue', - 'Margarett', - 'Margarette', - 'Laronda', - 'Vicenta', - 'Cotina', - 'Meilani', - 'Mannat', - 'Leylani', - 'Lailani', - 'Seerat', - 'Reya', - 'Amilia', - 'Avary', - 'Brocha', - 'Daneen', - 'Kimie', - 'Trudi', - 'Margret', - 'Djuna', - 'Charis', - 'Izzabella', - 'Brionne', - 'Elenora', - 'Lakeitha', - 'Jacki', - 'Beckie', - 'Guinevere', - 'Inara', - 'Landrie', - 'Nicoletta', - 'Ayari', - 'Zaniah', - 'Merlene', - 'Keli', - 'Maricella', - 'Leonela', - 'Donita', - 'Tehani', - 'Susannah', - 'Journi', - 'Machelle', - 'Tammara', - 'Cherrie', - 'Nelva', - 'Destanie', - 'Neyda', - 'Tabetha', - 'Wilhelmenia', - 'Brieanna', - 'Turkessa', - 'Ameera', - 'Avital', - 'Marycruz', - 'Zoila', - 'Tressa', - 'Joellen', - 'Raisa', - 'Bethanie', - 'Ermelinda', - 'Asiyah', - 'Monifa', - 'Samia', - 'Adamary', - 'Anahit', - 'Rania', - 'Miri', - 'Ether', - 'Desirea', - 'Chimere', - 'Erla', - 'Karisma', - 'Nalleli', - 'Larhonda', - 'Darlyn', - 'Anaisa', - 'Suellen', - 'Kamaria', - 'Nashla', - 'Yuriko', - 'Tzirel', - 'Tehila', - 'Myriah', - 'Frimet', - 'Cesilia', - 'Marika', - 'Frady', - 'Deloise', - 'Saleen', - 'Betsey', - 'Merri', - 'Laurette', - 'Sharita', - 'Shena', - 'Porscha', - 'Aerial', - 'Florrie', - 'Ayah', - 'Anusha', - 'Jeanelle', - 'Lessly', - 'Mahogany', - 'See', - 'Hang', - 'Karinna', - 'Leighann', - 'Elexus', - 'Markayla', - 'Kaneesha', - 'Barbie', - 'Aurea', - 'Kaeli', - 'Arwen', - 'Angelyn', - 'Jaclynn', - 'Tesla', - 'Maritsa', - 'Madelin', - 'Alisia', - 'Tyana', - 'Kimberlyn', - 'Dejanae', - 'Dalena', - 'Blessing', - 'Courtnie', - 'Amaria', - 'Micki', - 'Safa', - 'Jadah', - 'Mele', - 'Maryssa', - 'Channel', - 'Lianne', - 'Alea', - 'Chyanne', - 'Addelyn', - 'Aaleyah', - 'Michela', - 'Torri', - 'Indira', - 'Kanani', - 'Lashundra', - 'Mikaylah', - 'Zoee', - 'Taelyn', - 'Noheli', - 'Sarena', - 'Dariela', - 'Adalie', - 'Meggan', - 'Daniyah', - 'Sela', - 'Shaelyn', - 'Maylen', - 'Giovana', - 'Ayvah', - 'Arabelle', - 'Adaline', - 'Isyss', - 'Melanny', - 'Margaux', - 'Klara', - 'Janey', - 'Idolina', - 'Georgetta', - 'Amaiya', - 'Sianna', - 'Rebeka', - 'Meleny', - 'Kelle', - 'Angelika', - 'Malerie', - 'Latara', - 'Niamh', - 'Yevette', - 'Yomayra', - 'Karizma', - 'Nayelie', - 'Shantal', - 'Latoyia', - 'Jenee', - 'Shandra', - 'Magdalen', - 'Yatzari', - 'Jettie', - 'Charlsie', - 'Idy', - 'Inaya', - 'Yitta', - 'Reem', - 'Basya', - 'Skylynn', - 'Elyana', - 'Brynley', - 'Amor', - 'Amberlee', - 'Eternity', - 'Niyah', - 'Emiley', - 'Madeleyn', - 'Korie', - 'Sanaya', - 'Meira', - 'Chevonne', - 'Sabra', - 'Uma', - 'Kaira', - 'Isobel', - 'Elli', - 'Gurleen', - 'Berneice', - 'Alvera', - 'Ambrosia', - 'Roya', - 'Bettyann', - 'Alverda', - 'Tinamarie', - 'Tanasia', - 'Lavonda', - 'Jorja', - 'Heide', - 'Marwa', - 'Annaly', - 'Aaliah', - 'Ileen', - 'Lamonica', - 'Enjoli', - 'Ninel', - 'Milissa', - 'Dawne', - 'Joie', - 'Ashlei', - 'Elidia', - 'Maybelle', - 'Getsemani', - 'Gisella', - 'Mariya', - 'Adisyn', - 'Adia', - 'Caterina', - 'Bettyjane', - 'Kaydee', - 'Rasheda', - 'Camisha', - 'Chassidy', - 'Sadia', - 'Aislyn', - 'Ngoc', - 'Mirka', - 'Lanita', - 'Lashawnda', - 'Liridona', - 'Tynisa', - 'Arnelle', - 'Librada', - 'Marita', - 'Makyla', - 'Raniya', - 'Kandis', - 'Ethelyn', - 'Divina', - 'Genevie', - 'Jadelyn', - 'Ashleen', - 'Saya', - 'Marli', - 'Calli', - 'Anyla', - 'Sheng', - 'Vasiliki', - 'Yelena', - 'Darya', - 'Clarabelle', - 'Shirlene', - 'Tommye', - 'Julieann', - 'Jennefer', - 'Rana', - 'Raeann', - 'Suleima', - 'Lilyanne', - 'Jelisa', - 'Jaymee', - 'Rhylee', - 'Keyli', - 'Brooklin', - 'Meta', - 'Shakirah', - 'Loria', - 'Sharyl', - 'Sharday', - 'Manuelita', - 'Debera', - 'Lera', - 'Jacquie', - 'Ardella', - 'Jameria', - 'Winnifred', - 'Rossana', - 'Shemika', - 'Sedona', - 'Arvilla', - 'Samaira', - 'Aitana', - 'Daiana', - 'Cassia', - 'Lucianna', - 'Tama', - 'Shigeko', - 'Sueko', - 'Hatsuko', - 'Hazle', - 'Lida', - 'Wylene', - 'Sachiko', - 'Tahiry', - 'Renea', - 'Janina', - 'Becki', - 'Vy', - 'Cherryl', - 'Arionna', - 'Marrissa', - 'Randee', - 'Norita', - 'Sonali', - 'Susann', - 'Rachell', - 'Natashia', - 'Aspyn', - 'Malaika', - 'Nuvia', - 'Safiya', - 'Contessa', - 'Julyssa', - 'Analiese', - 'Jacee', - 'Kathlyn', - 'Gracey', - 'Chassity', - 'Kady', - 'Tytiana', - 'Katiana', - 'Eneida', - 'Teela', - 'Roiza', - 'Alaura', - 'Giuseppina', - 'Randa', - 'Danisha', - 'Mariza', - 'Marquisha', - 'Sharese', - 'Deseree', - 'Inaaya', - 'Rivkah', - 'Tawnie', - 'Miriah', - 'Shereen', - 'Candra', - 'Tomiko', - 'Whittney', - 'Aziza', - 'Ayala', - 'Hafsa', - 'Zaynab', - 'Kaileigh', - 'Yarima', - 'Danitza', - 'Maram', - 'Shakeya', - 'Emmer', - 'Kareema', - 'Maayan', - 'Rheanna', - 'Jaritza', - 'Marleny', - 'Zitlali', - 'Vanity', - 'Apryl', - 'Zully', - 'Tashia', - 'Courtnee', - 'Laporsha', - 'Luvenia', - 'Batya', - 'Ayelet', - 'Quetcy', - 'Tiny', - 'Felicita', - 'Omaira', - 'Nyssa', - 'Krystine', - 'Stevi', - 'Michiko', - 'Tennie', - 'Tomekia', - 'Billiejo', - 'Yohana', - 'Krystyna', - 'Kacee', - 'Naja', - 'Charmayne', - 'Twana', - 'Jeane', - 'Brittnay', - 'Cherelle', - 'Raechel', - 'Temeka', - 'Jasmeen', - 'Zuria', - 'Zailey', - 'Saydee', - 'Renatta', - 'Neta', - 'Bg', - 'Italy', - 'Terrica', - 'Goldia', - 'Monae', - 'Yelitza', - 'Ryanne', - 'Samirah', - 'Breckyn', - 'Nicolina', - 'Olympia', - 'Almeta', - 'Tamesha', - 'Zora', - 'Emmaleigh', - 'Loralei', - 'Kennadi', - 'Julieanna', - 'Jenavieve', - 'Shylah', - 'Akemi', - 'Fonda', - 'Nizhoni', - 'Iqra', - 'Gaetana', - 'Coreen', - 'Evonne', - 'Sadako', - 'Angele', - 'Macel', - 'Alinna', - 'Avneet', - 'Jannah', - 'Nickole', - 'Lotus', - 'Yukie', - 'Laiyah', - 'Kynzlee', - 'Mailen', - 'Nobuko', - 'Annaleigh', - 'Otila', - 'Shona', - 'Kimberely', - 'Delcie', - 'Zula', - 'Roselynn', - 'Aleeyah', - 'Bellarose', - 'Damya', - 'Cammie', - 'Treena', - 'Chanie', - 'Kaliah', - 'Abella', - 'Aahana', - 'Mileena', - 'Adaleigh', - 'Keiry', - 'Journie', - 'Myrtie', - 'Tsuruko', - 'Lyda', - 'Fernande', - 'Julee', - 'Estephany', - 'Louvenia', - 'Monserat', - 'Meena', - 'Jayline', - 'Brie', - 'Elicia', - 'Suzana', - 'Dusti', - 'Odile', - 'Hilma', - 'Katarzyna', - 'Jenise', - 'Hiromi', - 'Huong', - 'Deolinda', - 'Pamelia', - 'Awa', - 'Odelia', - 'Mattison', - 'Gwenda', - 'Sera', - 'Yuritzi', - 'Karishma', - 'Kaina', - 'Henna', - 'Norene', - 'Brina', - 'Chyenne', - 'Moncerrat', - 'Keilah', - 'Saphira', - 'Marylee', - 'Meri', - 'Lajuana', - 'Lindsy', - 'Shanise', - 'Sugey', - 'Jaimi', - 'Viki', - 'Ceola', - 'Naiya', - 'Adysen', - 'Shantavia', - 'Amberlyn', - 'Brihanna', - 'Laela', - 'Kenadi', - 'Hermine', - 'Bernita', - 'Deziree', - 'Anja', - 'Lawana', - 'Aletha', - 'Nella', - 'Irelyn', - 'Jakira', - 'Wynema', - 'Janai', - 'Keondra', - 'Venice', - 'Zenobia', - 'Jaelene', - 'Ammy', - 'Alizah', - 'Lakiesha', - 'Azure', - 'Aysha', - 'Saniah', - 'Mahnoor', - 'Ananda', - 'Asma', - 'Aissata', - 'Jaileen', - 'Yailin', - 'Xiana', - 'Laiza', - 'Liseth', - 'Marykate', - 'Daizy', - 'Neoma', - 'Tykeria', - 'Shamiya', - 'Nykeria', - 'Addalynn', - 'Kenzley', - 'Ardyce', - 'Anylah', - 'Vallie', - 'Darlyne', - 'Makiah', - 'Neela', - 'Naraly', - 'Danni', - 'Jolina', - 'Ailene', - 'Lyndia', - 'Erminia', - 'Asiya', - 'Alexius', - 'Mc', - 'Maylene', - 'Signe', - 'Adelfa', - 'Yusra', - 'Keyonna', - 'Yasuko', - 'Yukiko', - 'Augustina', - 'Leen', - 'Fumie', - 'Amora', - 'Annaleah', - 'Anvi', - 'Indie', - 'Haya', - 'Emmarie', - 'Enya', - 'Chieko', - 'Kinsleigh', - 'Shiann', - 'Eufemia', - 'Fusae', - 'Akiko', - 'Hosanna', - 'Alitzel', - 'Araya', - 'Anaiyah', - 'Rosy', - 'Nishka', - 'Gao', - 'Tamiya', - 'Lillyan', - 'Eudelia', - 'Kamea', - 'Berlyn', - 'Kahlan', - 'Alinah', - 'Mahealani', - 'Leeah', - 'Rosalynn', - 'Zadie', - 'Aolanis', - 'Esta', - 'Maisy', - 'Chevelle', - 'Jalayah', - 'Yatziry', - 'Alyne', - 'Jodell', - 'Sariya', - 'Yashica', - 'Jissel', - 'Letty', - 'Mariaisabel', - 'Lizzeth', - 'Yovana', - 'Dyanna', - 'Tamyra', - 'Monzerrat', - 'Seanna', - 'Eldora', - 'Mattea', - 'Zahira', - 'Jeanetta', - 'Aysia', - 'Ashlin', - 'Tenika', - 'Lezlie', - 'Kailie', - 'Jariyah', - 'Jovie', - 'Kiyah', - 'Lynlee', - 'Abriella', - 'Adleigh', - 'Ranada', - 'Vertie', - 'Flonnie', - 'Kynnedi', - 'Lya', - 'Acelynn', - 'Emalyn', - 'Emberly', - 'Yalexa', - 'Izabela', - 'Sadye', - 'Kamyla', - 'Jayleigh', - 'Cayleigh', - 'Ceil', - 'Inger', - 'Cindee', - 'Nena', - 'Loan', - 'Kiya', - 'Laure', - 'Cristen', - 'Celenia', - 'Fredda', - 'Ravyn', - 'Mee', - 'Graci', - 'Azalia', - 'Latina', - 'Hassie', - 'Dinorah', - 'Virna', - 'Autum', - 'Michala', - 'Macayla', - 'Franca', - 'Corissa', - 'Alysse', - 'Monisha', - 'Jessyca', - 'Nisa', - 'Jacqulyn', - 'Makaylee', - 'Ellin', - 'Jameelah', - 'Shalon', - 'Jlynn', - 'Kennady', - 'Brinkley', - 'Providence', - 'Phylis', - 'Eugenie', - 'Clementina', - 'Kadynce', - 'Yuvia', - 'Mailyn', - 'Taneisha', - 'Samone', - 'Aurore', - 'Brienne', - 'Tritia', - 'Fayth', - 'Jayci', - 'Jorie', - 'Loreal', - 'Taylar', - 'Maryn', - 'Melissia', - 'Midori', - 'Hisako', - 'Hulda', - 'Bobbijo', - 'Bulah', - 'Nancye', - 'Melvina', - 'Sherree', - 'Kierstin', - 'Merrilee', - 'Lonna', - 'Judyth', - 'Nancie', - 'Lark', - 'Candyce', - 'Kadejah', - 'Kenda', - 'Fara', - 'Estephania', - 'Cady', - 'Marilin', - 'Kadie', - 'Suleyma', - 'Jacquelyne', - 'Vonetta', - 'Tanairi', - 'Charlott', - 'Shannel', - 'Zenia', - 'Alise', - 'Takara', - 'Lyndsie', - 'Ivett', - 'Letisha', - 'Idania', - 'Lacee', - 'Candie', - 'Camelia', - 'Brittanee', - 'Mariaeduarda', - 'Geovanna', - 'Kirsti', - 'Michaella', - 'Kelsee', - 'Cheryll', - 'Cyrstal', - 'Keriann', - 'Latrisha', - 'Exie', - 'Deborha', - 'Verdie', - 'Zahava', - 'Zuleika', - 'Dorla', - 'Dominiqu', - 'Sharina', - 'Ardeth', - 'Alethia', - 'Starlene', - 'Shamira', - 'Shantelle', - 'Marilou', - 'Kyah', - 'Kyana', - 'Clemencia', - 'Cordie', - 'Meagen', - 'Xitlalic', - 'Gaia', - 'Ellia', - 'Elani', - 'Jaylani', - 'Krisha', - 'Khalia', - 'Aaradhya', - 'Aeris', - 'Avamarie', - 'Artemis', - 'Sheana', - 'Jolynn', - 'Sandee', - 'Wendie', - 'Willia', - 'Loriene', - 'Apolonia', - 'Eusebia', - 'Kazue', - 'Synthia', - 'Harue', - 'Siomara', - 'Nhi', - 'Maleni', - 'Toyoko', - 'Freeda', - 'Hideko', - 'Sherrye', - 'Bethanne', - 'Merrie', - 'Peri', - 'Ozella', - 'Venetia', - 'Revonda', - 'Breauna', - 'Arika', - 'Annissa', - 'Leeza', - 'Siera', - 'Jakiyah', - 'Kamaya', - 'Lashay', - 'Elvina', - 'Laquinta', - 'Faren', - 'Harmonie', - 'Brianny', - 'Jama', - 'Johna', - 'Sharalyn', - 'Aziyah', - 'Hadassa', - 'Shantinique', - 'Treasa', - 'Penni', - 'Shakera', - 'Carolyne', - 'Shaunda', - 'Talya', - 'Karyna', - 'Natosha', - 'Vivica', - 'Pauletta', - 'Laverna', - 'Danasia', - 'Shakita', - 'Sharee', - 'Yajayra', - 'Karlene', - 'Reatha', - 'Laiba', - 'Zamiyah', - 'Shirleen', - 'Bettylou', - 'Nakiya', - 'Eryka', - 'Bailie', - 'Janiece', - 'Keisa', - 'Kiah', - 'Jennica', - 'Niasia', - 'Hildy', - 'Jacquel', - 'Mahina', - 'Eshal', - 'Khloey', - 'Emelin', - 'Eesha', - 'Kaylei', - 'Aymee', - 'Alona', - 'Catelyn', - 'Arushi', - 'Ameerah', - 'Regenia', - 'Brailey', - 'Sparkle', - 'Giavonna', - 'Ashunti', - 'Naudia', - 'Kyrsten', - 'Emmalina', - 'Neve', - 'Aolani', - 'Gizella', - 'Tameika', - 'Leocadia', - 'Nidhi', - 'Wende', - 'Eshaal', - 'Cherice', - 'Lakeysha', - 'Menucha', - 'Ameena', - 'Kloey', - 'Nayelly', - 'Kathryne', - 'Lashawna', - 'Kristle', - 'Zaylie', - 'Keylee', - 'Landree', - 'Wynell', - 'Dezarae', - 'Angelli', - 'Haddie', - 'Ilyana', - 'Jaleigh', - 'Brilee', - 'Lakeya', - 'Kanika', - 'Lavinia', - 'Marykay', - 'Ruthanne', - 'Tenille', - 'Dorine', - 'Esabella', - 'Genavieve', - 'Zarah', - 'Mileidy', - 'Solara', - 'Yamila', - 'Amaia', - 'Season', - 'Cheree', - 'Luise', - 'Tracye', - 'Christeen', - 'Florida', - 'Breona', - 'Kathe', - 'Jakyra', - 'Zury', - 'Lakeesha', - 'Yaneth', - 'Keandra', - 'Agnieszka', - 'Markita', - 'Mariska', - 'Zada', - 'Breasia', - 'Aaniyah', - 'Kambria', - 'Lilit', - 'Sheilah', - 'Cherisse', - 'Hermione', - 'Angeli', - 'Britnie', - 'Lisett', - 'Joette', - 'Nga', - 'Ruthe', - 'Anamarie', - 'Mayeli', - 'Takia', - 'Lien', - 'Tenaya', - 'Kera', - 'Meah', - 'Mei', - 'Anoushka', - 'Annalyse', - 'Persia', - 'Sheccid', - 'Kyndra', - 'Susy', - 'Steffany', - 'Jennavecia', - 'Briannah', - 'Kynlie', - 'Alexxa', - 'Paizlee', - 'Jesika', - 'Kinzlee', - 'Ishani', - 'Freyja', - 'Julietta', - 'Raynette', - 'Nely', - 'Zayleigh', - 'Amberlynn', - 'Journei', - 'Eimy', - 'Delany', - 'Emarie', - 'Brilynn', - 'Audri', - 'Abilene', - 'Saoirse', - 'Naveah', - 'Ayelen', - 'Emeline', - 'Loryn', - 'Mykaela', - 'Skarlett', - 'Tionne', - 'Rashelle', - 'Jerline', - 'Ofilia', - 'Rufina', - 'Phillis', - 'Jenica', - 'Dineen', - 'Glory', - 'Camellia', - 'Alane', - 'Angelyna', - 'Amalie', - 'Kina', - 'Kateri', - 'Neyva', - 'Malisa', - 'Saida', - 'Jerika', - 'Bayli', - 'Crystale', - 'Silvana', - 'Inga', - 'Lyndi', - 'Leeanna', - 'Cheyanna', - 'Fayrene', - 'Torie', - 'Latashia', - 'Baleigh', - 'Fidencia', - 'Rori', - 'Lorianne', - 'Catrice', - 'Cherrelle', - 'Lashaunda', - 'Sammi', - 'Thomasena', - 'Roshanda', - 'Alazae', - 'Enza', - 'Mairead', - 'Pandora', - 'Kortni', - 'Timber', - 'Chasidy', - 'Danesha', - 'Camry', - 'Charlette', - 'Kaneshia', - 'Shadae', - 'Keturah', - 'Randye', - 'Kiyana', - 'Charlean', - 'Delana', - 'Tomasita', - 'Lilliam', - 'Bibi', - 'Marguita', - 'Maryalice', - 'Iraida', - 'Tyhessia', - 'Makeba', - 'Tanaya', - 'Keiara', - 'Madlyn', - 'Jelissa', - 'Shakayla', - 'Mickayla', - 'Aleisha', - 'Keyara', - 'Mekayla', - 'Mykala', - 'Riva', - 'Inaara', - 'Paulita', - 'Lashae', - 'Destynee', - 'Christianna', - 'Rise', - 'Larraine', - 'Luetta', - 'Merna', - 'Francena', - 'Diedre', - 'Georgiann', - 'Rubbie', - 'Denita', - 'Dyani', - 'Laticia', - 'Ludivina', - 'Suanne', - 'Hareem', - 'Nava', - 'Florie', - 'Sherly', - 'Vidhi', - 'Camie', - 'Sharell', - 'Chole', - 'Jolin', - 'Polina', - 'Brittiany', - 'Delicia', - 'Brystol', - 'Beaulah', - 'Leatha', - 'Jamilah', - 'Zona', - 'Elliette', - 'Joye', - 'Aashi', - 'Kerriann', - 'Xin', - 'Michaelene', - 'Senaida', - 'Emaan', - 'Nakayla', - 'Aine', - 'Jadalyn', - 'Maimouna', - 'Klaire', - 'Macee', - 'Shandi', - 'Heily', - 'Braylynn', - 'Aislynn', - 'Chevon', - 'Henretta', - 'Bellamy', - 'Icie', - 'Draya', - 'Darianna', - 'Zyana', - 'Zaelynn', - 'Story', - 'Kambrie', - 'Ranae', - 'Florencia', - 'Porfiria', - 'Elianny', - 'Karren', - 'Yachet', - 'Euna', - 'Naoma', - 'Stefania', - 'Liora', - 'Zlaty', - 'Margene', - 'Denna', - 'Isidra', - 'Faustina', - 'Bintou', - 'Arbutus', - 'Kelci', - 'Evelena', - 'Maudine', - 'Agapita', - 'Olyvia', - 'Loma', - 'Veola', - 'Mckinlee', - 'Lamya', - 'Nashali', - 'Baileigh', - 'Josselin', - 'Kaydance', - 'Paiton', - 'Myleigh', - 'Jazlyne', - 'Indya', - 'Siham', - 'Aryn', - 'Madalene', - 'Nefertiti', - 'Meridith', - 'Kamesha', - 'Peg', - 'Shelbey', - 'Pearlean', - 'Jamika', - 'Maryama', - 'Sabria', - 'Taniqua', - 'Maraya', - 'Joely', - 'Karys', - 'Charolette', - 'Orly', - 'Jennipher', - 'Kimbra', - 'Krislynn', - 'Kenlie', - 'Karrington', - 'Kambry', - 'Alasia', - 'Carletta', - 'Maija', - 'Nadirah', - 'Gladyce', - 'Shevy', - 'Jalessa', - 'Mushka', - 'Cyre', - 'Mabry', - 'Arihanna', - 'Brithany', - 'Ilianna', - 'Jozlynn', - 'Zandra', - 'Serinity', - 'Passion', - 'Lacresha', - 'Jeraldine', - 'Henriette', - 'Elenore', - 'Nastassia', - 'Ruchel', - 'Amal', - 'Madina', - 'Rosaline', - 'Liyana', - 'Pasqualina', - 'Keyra', - 'Kaycie', - 'Lyanna', - 'Naina', - 'Gennesis', - 'Aarushi', - 'Lariah', - 'Jakiya', - 'Kareena', - 'Rhiana', - 'Emilly', - 'Yeimi', - 'Matsuko', - 'Makhia', - 'Alin', - 'Addisen', - 'Lanae', - 'Oceana', - 'Laquanda', - 'Coralie', - 'Arina', - 'Harini', - 'Emy', - 'Emmarose', - 'Ellyana', - 'Eila', - 'Havana', - 'Dagny', - 'Leylah', - 'Shawanna', - 'Aleenah', - 'Adalia', - 'Aaliya', - 'Zyanya', - 'Felisa', - 'Tameca', - 'Sama', - 'Ripley', - 'Nayomi', - 'Quanesha', - 'Shequita', - 'Shanik', - 'Savina', - 'Nalah', - 'Magaby', - 'Cattaleya', - 'Calla', - 'Lillia', - 'Kaida', - 'Izabell', - 'Francia', - 'Caylin', - 'Bianey', - 'Hanah', - 'Julienne', - 'Viva', - 'Xochil', - 'Staphany', - 'Rayanne', - 'Marialuisa', - 'Devina', - 'Sabryna', - 'Estefanie', - 'Dinora', - 'Clarisse', - 'Josephina', - 'Milca', - 'Anjolie', - 'Akayla', - 'Malea', - 'Mea', - 'Meghana', - 'Briceida', - 'Betsaida', - 'Roselin', - 'Anuhea', - 'Megha', - 'Azusena', - 'Nandini', - 'Prisilla', - 'Shelsy', - 'Olene', - 'Kaneisha', - 'Onalee', - 'Jadore', - 'Monteen', - 'Trudie', - 'Leisha', - 'Drucilla', - 'Tamiyah', - 'Ashante', - 'Daysha', - 'Caliyah', - 'Sabella', - 'Emoni', - 'Jakyla', - 'Reginae', - 'Anyah', - 'Kierstyn', - 'Sharleen', - 'Doretta', - 'Harlene', - 'Gerrie', - 'Zofia', - 'Albertine', - 'Bronwyn', - 'Terresa', - 'Delta', - 'Anijah', - 'Mathilde', - 'Cindie', - 'Dalene', - 'Cyndee', - 'Eulah', - 'Ayako', - 'Beverlee', - 'Nicholle', - 'Kaitlan', - 'Yeraldin', - 'Tawney', - 'Tawnee', - 'Britteny', - 'Alishia', - 'Shireen', - 'Byanca', - 'Rebekka', - 'Annel', - 'Krizia', - 'Kerstin', - 'Shera', - 'Uyen', - 'Ligia', - 'Dallana', - 'Itsel', - 'Karine', - 'Sharmaine', - 'Noely', - 'Marrisa', - 'Karah', - 'Rayann', - 'Oksana', - 'Stephannie', - 'Brynne', - 'Alixandra', - 'Dyana', - 'Emilce', - 'Delmy', - 'Jamee', - 'Caitlan', - 'Marily', - 'Kiani', - 'Jennafer', - 'Nissa', - 'Jenell', - 'Jennette', - 'Marquitta', - 'Chimene', - 'Justyna', - 'Jenette', - 'Cassy', - 'Temika', - 'Katrice', - 'Brandis', - 'Consuela', - 'Chavon', - 'Angella', - 'Shantrell', - 'Christiane', - 'Shenna', - 'Donia', - 'Angelise', - 'Janyah', - 'Damiyah', - 'Luzmaria', - 'Meghna', - 'Natally', - 'Nerissa', - 'Kaori', - 'Laya', - 'Analyssa', - 'Teya', - 'Alizon', - 'Jasline', - 'Lavette', - 'Emmi', - 'Kamisha', - 'Taleah', - 'Shenita', - 'Kaytlynn', - 'Azariyah', - 'Dominica', - 'Malvina', - 'Skyy', - 'Shondra', - 'Lorina', - 'Donielle', - 'Kaisley', - 'Katalyna', - 'Jesslynn', - 'Yasmina', - 'Glada', - 'Maliha', - 'Irina', - 'Hiba', - 'Trinette', - 'Oona', - 'Aleeza', - 'Arisha', - 'Janean', - 'Cristie', - 'Syd', - 'Lavona', - 'Kennia', - 'Kyanna', - 'Lovenia', - 'Julieanne', - 'Launa', - 'Taunya', - 'Tytianna', - 'Becca', - 'Deonna', - 'Jihan', - 'Jomaira', - 'Shantay', - 'Talitha', - 'Shyra', - 'Alverna', - 'Chere', - 'Kamela', - 'Phaedra', - 'Stacee', - 'Gretta', - 'Kathyrn', - 'Shalee', - 'Beautiful', - 'Lissett', - 'Georgann', - 'Corrin', - 'Chelsa', - 'Cera', - 'Layna', - 'Lizanne', - 'Mariellen', - 'Lashandra', - 'Sophya', - 'Shruti', - 'Janea', - 'Rheta', - 'Jezebel', - 'Alizee', - 'Delaila', - 'Dayani', - 'Arieanna', - 'Amarah', - 'Janyia', - 'Makalah', - 'Dorie', - 'Tynisha', - 'Tran', - 'Prisma', - 'Shirin', - 'Tonette', - 'Suzi', - 'Alajah', - 'Lurline', - 'Adelia', - 'Tani', - 'Cassey', - 'Maha', - 'Cheyann', - 'Keyona', - 'Yezenia', - 'Vaness', - 'Stephine', - 'Cyndie', - 'Jaylanie', - 'Jeannemarie', - 'Mammie', - 'Sherice', - 'Delynn', - 'Aoife', - 'Kadiatou', - 'Sherese', - 'Trenyce', - 'Anaiz', - 'Anaiza', - 'Dajanae', - 'Lisaann', - 'Keiko', - 'Martiza', - 'Elysa', - 'Petrina', - 'Dierdre', - 'Davida', - 'Falyn', - 'Briona', - 'Maryjean', - 'Lanisha', - 'Marlenne', - 'Nawal', - 'Ethelene', - 'Alya', - 'Ariannah', - 'Jacinta', - 'Alaia', - 'Sindee', - 'Jalaya', - 'Mellanie', - 'Lasya', - 'Kyrah', - 'Mirabella', - 'Renay', - 'Seren', - 'Hiliana', - 'Kinzie', - 'Isra', - 'Hanan', - 'Kaleia', - 'Melynda', - 'Marine', - 'Twanna', - 'Lekisha', - 'Jamecia', - 'Penney', - 'Tiwanna', - 'Rylea', - 'Shekinah', - 'Mckenzi', - 'Abigael', - 'Patrizia', - 'Jamillah', - 'Caris', - 'Karmyn', - 'Kyli', - 'Princessa', - 'Sakinah', - 'Deserae', - 'Patrina', - 'Carmelina', - 'Mayela', - 'Sherise', - 'Ilda', - 'Florentina', - 'Nelwyn', - 'Jennine', - 'Aleeya', - 'Kynsley', - 'Arlett', - 'Tarra', - 'Lakyn', - 'Tyeisha', - 'Temima', - 'Mallori', - 'Ingeborg', - 'Elizaveta', - 'Jentry', - 'Kymber', - 'Maddisyn', - 'Allana', - 'Anistyn', - 'Emberlynn', - 'Faithlynn', - 'Arianah', - 'Tionna', - 'Lenda', - 'Laveta', - 'Alayla', - 'Aisling', - 'Miryam', - 'Marena', - 'Aneta', - 'Yzabella', - 'Mihika', - 'Raine', - 'Samiah', - 'Raveena', - 'Elfrieda', - 'Niccole', - 'Tatanisha', - 'Medha', - 'Katharina', - 'Jazmen', - 'Cally', - 'Louanne', - 'Caress', - 'Naylea', - 'Avarie', - 'Madelynne', - 'Dayla', - 'Shanterria', - 'Tesha', - 'Thanya', - 'Jalia', - 'Josalyn', - 'Ailey', - 'Brooklynne', - 'Dodie', - 'Champagne', - 'Taneka', - 'Tenesha', - 'Tinisha', - 'Deeanna', - 'Shelvia', - 'Chenoa', - 'Darcel', - 'Kailea', - 'Jatziry', - 'Merryl', - 'Sharlyn', - 'Harolyn', - 'Rilla', - 'Ayisha', - 'Jacklynn', - 'Chloee', - 'Makynzie', - 'Leyah', - 'Aalyiah', - 'Tynlee', - 'Statia', - 'Tyronda', - 'Tsuyako', - 'Casimira', - 'Kehaulani', - 'Ragan', - 'Lorissa', - 'Abelina', - 'Cuca', - 'Sachi', - 'Evany', - 'Elektra', - 'Sianni', - 'Raychel', - 'Natassia', - 'Vermell', - 'Sharifa', - 'Everley', - 'Ivanka', - 'Arisbeth', - 'Aleyza', - 'Bay', - 'Deedra', - 'Zarina', - 'Regena', - 'Kitana', - 'Latoshia', - 'Virgia', - 'Aili', - 'Breslyn', - 'Ishika', - 'Jhoana', - 'Dorrace', - 'Chanice', - 'Sheniqua', - 'Tashana', - 'Joetta', - 'Sanya', - 'Altamese', - 'Pari', - 'Niah', - 'Ysabelle', - 'Lisseth', - 'Parisa', - 'Aislin', - 'Leiah', - 'Atziri', - 'Anvita', - 'Jaydah', - 'Gabby', - 'Ashia', - 'Dymond', - 'Marah', - 'Uniqua', - 'Blimie', - 'Anny', - 'Dalinda', - 'Wauneta', - 'Gionna', - 'Rabia', - 'Jayanna', - 'Anica', - 'Maybell', - 'Kathern', - 'Amrita', - 'Mayerli', - 'Irais', - 'Kemberly', - 'Vena', - 'Kamri', - 'Destine', - 'Adreanna', - 'Seleste', - 'Claretha', - 'Brynnlee', - 'Anquette', - 'Komal', - 'Lysette', - 'Michayla', - 'Zamya', - 'Sierrah', - 'Felica', - 'Otelia', - 'Rihana', - 'Doloris', - 'Alanie', - 'Angelly', - 'Kassandr', - 'Rosemari', - 'Shaday', - 'Annemari', - 'Marlana', - 'Clorinda', - 'Oneida', - 'Shaunta', - 'Alexcia', - 'Takesha', - 'Amiracle', - 'Sharion', - 'Joline', - 'Jaziyah', - 'Teal', - 'Sueann', - 'Sora', - 'Kamiah', - 'Caressa', - 'Eleana', - 'Bernetha', - 'Alexyss', - 'Sharda', - 'Aishwarya', - 'Suhaill', - 'Radhika', - 'Wonda', - 'Renda', - 'Janny', - 'Ardelle', - 'Malory', - 'Jossie', - 'Anaid', - 'Mitsuye', - 'Shizuye', - 'Fariha', - 'Aiesha', - 'Nitya', - 'Nadiya', - 'Katerin', - 'Bruna', - 'Varsha', - 'Yaretsi', - 'Xitlalli', - 'Leshia', - 'Eda', - 'Sheronda', - 'Malikah', - 'Tayah', - 'Briann', - 'Tasnim', - 'Jayonna', - 'Kenedy', - 'Anarosa', - 'Zaya', - 'Kerline', - 'Brinda', - 'Amna', - 'Desarae', - 'Sarrah', - 'Silva', - 'Steffani', - 'Almarosa', - 'Alyshia', - 'Ariell', - 'Breeanne', - 'Alyxandra', - 'Juliane', - 'Jesseca', - 'Janisha', - 'Donisha', - 'Darnisha', - 'Jakeria', - 'Kirsty', - 'Markeisha', - 'Breena', - 'Selin', - 'Nikisha', - 'Adreana', - 'Elois', - 'Arrianna', - 'Melenie', - 'Rayanna', - 'Kaelee', - 'Shakyra', - 'Clotee', - 'Jakeline', - 'Kalysta', - 'Cesia', - 'Ankita', - 'Cristela', - 'Shunta', - 'Mozella', - 'Chrissie', - 'Adora', - 'Ashanty', - 'Ashna', - 'Lehua', - 'Nohealani', - 'Shruthi', - 'Metzli', - 'Jakelin', - 'Jisel', - 'Mikenna', - 'Miroslava', - 'Mansi', - 'Daphney', - 'Amisha', - 'Adara', - 'Alexzandria', - 'Alliah', - 'Yuriana', - 'Nanea', - 'Kahealani', - 'Ritika', - 'Arica', - 'Amayrani', - 'Kealani', - 'Dorina', - 'Lucienne', - 'Estrellita', - 'Kimberlin', - 'Lai', - 'Yovanna', - 'Rebekkah', - 'Azra', - 'Nada', - 'Gabryella', - 'Avigayil', - 'Binta', - 'Devoiry', - 'Raeanna', - 'Arlena', - 'Briauna', - 'Itati', - 'Grabiela', - 'Noella', - 'Teaghan', - 'Tzippy', - 'Faiza', - 'Zaara', - 'Tehilla', - 'Miki', - 'Sendy', - 'Kassondra', - 'Katherina', - 'Lissete', - 'Livier', - 'Lauran', - 'Dandrea', - 'Chelse', - 'Lizmarie', - 'Sunday', - 'Haidee', - 'Carrissa', - 'Nicholette', - 'Katey', - 'Katheryne', - 'Katty', - 'Kimia', - 'Leeanne', - 'Lizmary', - 'Jani', - 'Emmanuella', - 'Jahniya', - 'Talar', - 'Sintia', - 'Narda', - 'Chriselda', - 'Candance', - 'Delorise', - 'Daysy', - 'Lusine', - 'Raeanne', - 'Cherylann', - 'Ayat', - 'Halima', - 'Zissel', - 'Courtni', - 'Adahli', - 'Der', - 'Emree', - 'Brynlie', - 'Cherlyn', - 'Bostyn', - 'Francie', - 'Oaklie', - 'Shakeerah', - 'Hertha', - 'Haneefah', - 'Taheerah', - 'Nikkia', - 'Sheryll', - 'Donnabelle', - 'Teddi', - 'Jodee', - 'Tammera', - 'Janylah', - 'Laquesha', - 'Penina', - 'Gracee', - 'Thomasine', - 'Janyce', - 'Randie', - 'Mela', - 'Alka', - 'Cordia', - 'Shaquetta', - 'Mi', - 'Jaquetta', - 'Yoshiye', - 'Haruye', - 'Yoneko', - 'Fumi', - 'Wava', - 'Congetta', - 'Denee', - 'Kandyce', - 'Soraida', - 'Triana', - 'Kenedi', - 'Abena', - 'Talisha', - 'Rochell', - 'Sharisse', - 'Tijuana', - 'Amiee', - 'Nyesha', - 'Towana', - 'Lore', - 'Melodye', - 'Hayli', - 'Joyelle', - 'Shareen', - 'Amarilis', - 'Takiyah', - 'Takiya', - 'Keysha', - 'Feige', - 'Diahann', - 'Kloie', - 'Laynee', - 'Mariely', - 'Rainey', - 'Alizabeth', - 'Alyssandra', - 'Cambry', - 'Jadelynn', - 'Marylynn', - 'Keoka', - 'Jamaica', - 'Lus', - 'Shonta', - 'Kameelah', - 'Danell', - 'Evamarie', - 'Francoise', - 'Beata', - 'Caylie', - 'Elexa', - 'Joscelin', - 'Hessie', - 'Alazay', - 'Robena', - 'Texie', - 'Clarine', - 'Makennah', - 'Arletha', - 'Willette', - 'Amee', - 'Jetaun', - 'Anyia', - 'Aryssa', - 'Bonni', - 'Graciella', - 'Haileigh', - 'Sharae', - 'Shanea', - 'Ieisha', - 'Porche', - 'Teanna', - 'Ashanta', - 'Taiya', - 'Nicolett', - 'Naisha', - 'Sharice', - 'Madelein', - 'Kimberle', - 'Monifah', - 'Cameo', - 'Evelynne', - 'Edlyn', - 'Porcha', - 'Maricel', - 'Waleska', - 'Shakeena', - 'Shavone', - 'Ashlynne', - 'Yahira', - 'Shamecca', - 'Yashira', - 'Sherell', - 'Fiorela', - 'Nansi', - 'Shawntae', - 'Poonam', - 'Shala', - 'Kellyn', - 'Jazzmyn', - 'Asya', - 'Shatoya', - 'Yury', - 'Weronika', - 'Dawnette', - 'Lorita', - 'Michaelle', - 'Tomi', - 'Abbi', - 'Maudry', - 'Jaylinn', - 'Kynzie', - 'Lynnlee', - 'Madisson', - 'Denese', - 'Devona', - 'Sharika', - 'Sharilyn', - 'Zayna', - 'Janalee', - 'Sherril', - 'Timika', - 'Lynelle', - 'Rolayne', - 'Lubertha', - 'Jariah', - 'Kamala', - 'Taffy', - 'Marquetta', - 'Honora', - 'Frederica', - 'Monalisa', - 'Rashonda', - 'Francene', - 'Diedra', - 'Ceara', - 'Marylouise', - 'Kenesha', - 'Aisley', - 'Donnalee', - 'Genisis', - 'Debroah', - 'Helayne', - 'Raelee', - 'Maryrose', - 'Yalonda', - 'Chyla', - 'Edelmira', - 'Roselle', - 'Alyssah', - 'Brenley', - 'Gaynelle', - 'Shelvie', - 'Mackayla', - 'Linley', - 'Allizon', - 'Alonna', - 'Kendalyn', - 'Jozlyn', - 'Gwenn', - 'Jina', - 'Zariya', - 'Rosabella', - 'Emrie', - 'Tamu', - 'Senta', - 'Myia', - 'Emberlyn', - 'Emorie', - 'Arantxa', - 'Richele', - 'Christianne', - 'Lashan', - 'Koren', - 'Buffie', - 'Ronnette', - 'Marna', - 'Tuesday', - 'Helga', - 'Emilyn', - 'Cailee', - 'Shaquilla', - 'Dyamond', - 'Gerda', - 'Mckynzie', - 'Khloie', - 'Kendyll', - 'Maryfrances', - 'Khadejah', - 'Annalie', - 'Adaya', - 'Akia', - 'Markia', - 'Iyla', - 'Kaely', - 'Rafaella', - 'Tali', - 'Sukhmani', - 'Mili', - 'Kaylanie', - 'Maribelle', - 'Zharia', - 'Georgeanne', - 'Shamekia', - 'Siyona', - 'Layah', - 'Maylani', - 'Elianah', - 'Ellena', - 'Elyanna', - 'Yanilen', - 'Jashanti', - 'Lakita', - 'Juanell', - 'Caley', - 'Annella', - 'Vinita', - 'Zakiyah', - 'Sherian', - 'Palmira', - 'Delpha', - 'Creola', - 'Veta', - 'Sheneka', - 'Ameria', - 'Keonna', - 'Nathali', - 'Vaishnavi', - 'Zurisadai', - 'Mily', - 'Aalyah', - 'Hasini', - 'Irelynn', - 'Taneshia', - 'Lashanti', - 'Shatavia', - 'Shantoria', - 'Avelina', - 'Vanya', - 'Erline', - 'Surina', - 'Maribella', - 'Julieana', - 'Jazel', - 'Kalissa', - 'Marlis', - 'Hadasa', - 'Iveth', - 'Miliani', - 'Leiana', - 'Devynn', - 'Ahtziry', - 'Shilah', - 'Sicily', - 'Ashari', - 'Yarenis', - 'Tamiah', - 'Annis', - 'Azzie', - 'Sedalia', - 'Maebell', - 'Empress', - 'Fairy', - 'Najma', - 'Loreta', - 'Suhayla', - 'Sundus', - 'Vayda', - 'Doshia', - 'Ahlam', - 'Lashondra', - 'Ryanna', - 'Lala', - 'Merline', - 'Severa', - 'Kymora', - 'Fae', - 'Jameka', - 'Othella', - 'Wyoma', - 'Ailee', - 'Aishani', - 'Fransisca', - 'Noma', - 'Meztli', - 'Miliana', - 'Navaeh', - 'Swara', - 'Malillany', - 'Jaina', - 'Dia', - 'Ivyanna', - 'Jamira', - 'Jazaria', - 'Oletha', - 'Julieth', - 'Avia', - 'Elizebeth', - 'Yareni', - 'Korra', - 'Miraya', - 'Bernetta', - 'Helyn', - 'Suhaylah', - 'Laina', - 'Lassie', - 'Anyae', - 'Maleena', - 'Nirvana', - 'Danely', - 'Keilana', - 'Hildur', - 'Mariaclara', - 'Toshie', - 'Maniyah', - 'Hanako', - 'Asako', - 'Hiroko', - 'Hisae', - 'Suraya', - 'Kaileen', - 'Pearla', - 'Layal', - 'Batoul', - 'Johannah', - 'Gizel', - 'Venecia', - 'Yanelly', - 'Atianna', - 'Apple', - 'Arizbeth', - 'Sriya', - 'Natania', - 'Mayline', - 'Emmagrace', - 'Meriam', - 'Laree', - 'Tempie', - 'Sedonia', - 'Evalee', - 'Laquana', - 'Sheli', - 'Liesl', - 'Hazeline', - 'Blanchie', - 'Samyra', - 'Keelie', - 'Krislyn', - 'Yanelis', - 'Addysen', - 'Inis', - 'Tammra', - 'Johnette', - 'Amery', - 'Alayza', - 'Alaiyah', - 'Abree', - 'Amri', - 'Anapaula', - 'Jacelynn', - 'Kenzleigh', - 'Kenzlee', - 'Jaelah', - 'Brenlee', - 'Avalee', - 'Paizley', - 'Columbia', - 'Benedetta', - 'Daeja', - 'Myeshia', - 'Jeanene', - 'Terina', - 'Ethyl', - 'Oliwia', - 'Taniah', - 'Yaiza', - 'Eveline', - 'Monnie', - 'Margherita', - 'Jayana', - 'Macil', - 'Leontine', - 'Catera', - 'Wynelle', - 'Eldana', - 'Sallyann', - 'Yolande', - 'Marybelle', - 'Leanore', - 'Clothilde', - 'Tonita', - 'Kimaya', - 'Sumayah', - 'Latrenda', - 'Kelleen', - 'Deatrice', - 'Madelon', - 'Phyliss', - 'Argelia', - 'Mellie', - 'Emmah', - 'Jorley', - 'Muna', - 'Daphine', - 'Darina', - 'Bliss', - 'Karyl', - 'Taelynn', - 'Blenda', - 'Tonika', - 'Jerrilyn', - 'Sahra', - 'Keilyn', - 'Pearlene', - 'Arrie', - 'Ellene', - 'Fredericka', - 'Ladawn', - 'Maudell', - 'Rahma', - 'Jaylie', - 'Jaidah', - 'Vernetta', - 'Aleya', - 'Aubreigh', - 'Alaysha', - 'Adena', - 'Jacara', - 'Elfriede', - 'Maysel', - 'Munira', - 'Mumtaz', - 'Dorathy', - 'Chanin', - 'Ronette', - 'Maymie', - 'Providencia', - 'Mirta', - 'Loida', - 'Blakelyn', - 'Bentleigh', - 'Alliana', - 'Aleen', - 'Daliyah', - 'Jodene', - 'Johanne', - 'Timeka', - 'Ilhan', - 'Aloma', - 'Maris', - 'Arlyne', - 'Jene', - 'Hazelene', - 'Shakela', - 'Maida', - 'Maycie', - 'Makynlee', - 'Kawanda', - 'Consuella', - 'Sephora', - 'Andrianna', - 'Joshlyn', - 'Hollyn', - 'Kyliee', - 'Adaly', - 'Dailyn', - 'Averee', - 'Berklee', - 'Marly', - 'Gianella', - 'Ekaterina', - 'Colene', - 'Dayonna', - 'Shareka', - 'Roshni', - 'Latifa', - 'Merilyn', - 'Vernelle', - 'Marlyce', - 'Sabrena', - 'Jeneen', - 'Genie', - 'Lawanna', - 'Tashara', - 'Kayzlee', - 'Skylie', - 'Iyonna', - 'Honesti', - 'Cherylene', - 'Tahira', - 'Chizuko', - 'Aneesah', - 'Helmi', - 'Katrena', - 'Shyanna', - 'Zeola', - 'Lempi', - 'Arliss', - 'Madgie', - 'Verlie', - 'Ardys', - 'Twanda', - 'Kareemah', - 'Chardae', - 'Arlinda', - 'Darlena', - 'Karee', - 'Lorry', - 'Rolande', - 'Marlane', - 'Lelah', - 'Zahria', - 'Michalene', - 'Nayelis', - 'Abbigale', - 'Lorretta', - 'Sheril', - 'Priscille', - 'Cleda', - 'Kerrigan', - 'Wanita', - 'Ambria', - 'Wanetta', - 'Ebone', - 'Georgianne', - 'Karleen', - 'Laural', - 'Jonette', - 'Sharie', - 'Francina', - 'Yarelis', - 'Tempestt', - 'Kamie', - 'Julene', - 'Londa', - 'Haniya', - 'Kristeen', - 'Classie', - 'Nakiyah', - 'Valinda', - 'Kamree', - 'Micheline', - 'Mckaylee', - 'Prescilla', - 'Shaylynn', - 'Donelda', - 'Fayetta', - 'Terrye', - 'Dorthey', - 'Azilee', - 'Juanda', - 'Eustolia', - 'Nakeisha', - 'Hira', - 'Tarrah', - 'Jamyra', - 'Azaleah', - 'Aveline', - 'Chanae', - 'Andreana', - 'Banesa', - 'Berenis', - 'Brittini', - 'Orianna', - 'Reet', - 'Rayah', - 'Sofi', - 'Japji', - 'Kensie', - 'Roshonda', - 'Agripina', - 'Blasa', - 'Anevay', - 'Akari', - 'Krissi', - 'Maily', - 'Kitzia', - 'Keilly', - 'Raveen', - 'Kaiah', - 'Juliett', - 'Jocelynne', - 'Eowyn', - 'Calie', - 'Ebonee', - 'Chelcie', - 'Kayci', - 'Lauralee', - 'Trenity', - 'Deborrah', - 'Imagene', - 'Akasha', - 'Analaura', - 'Liani', - 'Lizania', - 'Lucina', - 'Melaine', - 'Sanah', - 'Stepanie', - 'Zabrina', - 'Janaye', - 'Jelena', - 'Kaylina', - 'Diavian', - 'Tasnia', - 'Nusrat', - 'Ashleymarie', - 'Maheen', - 'Ndeye', - 'Yumi', - 'Vittoria', - 'Amyra', - 'Yakelin', - 'Yudith', - 'Yumalay', - 'Juliza', - 'Daila', - 'Daenerys', - 'Calissa', - 'Tahirah', - 'Laquasia', - 'Jenay', - 'Crystina', - 'Eleonore', - 'Inessa', - 'Irine', - 'Vennie', - 'Oda', - 'Laurine', - 'Lavera', - 'Saraya', - 'Kerin', - 'Itzia', - 'Jennessa', - 'Katerine', - 'Rosselyn', - 'Leidy', - 'Adamariz', - 'Adylene', - 'Aylen', - 'Aniela', - 'Aleesha', - 'Alyssamarie', - 'Ainara', - 'Emalie', - 'Darlin', - 'Inna', - 'Emmely', - 'Eriana', - 'Esbeidy', - 'Chenelle', - 'Janise', - 'Sherrell', - 'Basilia', - 'Malayna', - 'Hilinai', - 'Mardell', - 'Romi', - 'Rosena', - 'Violett', - 'Zaylah', - 'Taia', - 'Anisah', - 'Esli', - 'Cleopatra', - 'Carisma', - 'Dezaray', - 'Swayze', - 'Raeven', - 'Neiva', - 'Myeisha', - 'Shelsea', - 'Yissel', - 'Velinda', - 'Josseline', - 'Denasia', - 'Digna', - 'Keiana', - 'Clytee', - 'Vernette', - 'Cheyene', - 'Roshunda', - 'Telisha', - 'Nilah', - 'Ayda', - 'Zykia', - 'Isabellamarie', - 'Melanee', - 'Laylanie', - 'Ajah', - 'Guiliana', - 'Oliva', - 'Mikela', - 'Mirabelle', - 'Nabiha', - 'Jasmina', - 'Hendy', - 'Ita', - 'Elif', - 'Reola', - 'Jamyah', - 'Tempest', - 'Arletta', - 'Keaira', - 'Ibeth', - 'Jerolyn', - 'Nelta', - 'Alishba', - 'Crisol', - 'Sabreena', - 'Silver', - 'Toba', - 'Yunuen', - 'Rishika', - 'Naomie', - 'Brittanya', - 'Annasophia', - 'Ayumi', - 'Jayleene', - 'Emmily', - 'Lyssa', - 'Natoya', - 'Vallerie', - 'Andee', - 'Annastasia', - 'Mazzy', - 'Zinnia', - 'Sheran', - 'Sumaiya', - 'Tasneem', - 'Aniylah', - 'Dua', - 'Tausha', - 'Jabria', - 'Lanora', - 'Janeli', - 'Mileydi', - 'Mikaella', - 'Ryah', - 'Rolonda', - 'Ajanae', - 'Ianna', - 'Xaria', - 'Winni', - 'Marializ', - 'Aidel', - 'Jonae', - 'Sanam', - 'Mao', - 'Tesia', - 'Yanina', - 'Brieana', - 'Genova', - 'Lashanae', - 'Anneke', - 'Siarra', - 'Sharhonda', - 'Zeldy', - 'Saron', - 'Johnisha', - 'Katelynne', - 'Janneth', - 'Corayma', - 'Helvi', - 'Asucena', - 'Lachelle', - 'Solmayra', - 'Tavia', - 'Marlina', - 'Rachal', - 'Sunni', - 'Nycole', - 'Aliannah', - 'Nafisa', - 'Simi', - 'Suki', - 'Jadalynn', - 'Kezia', - 'Athziri', - 'Huda', - 'Evy', - 'Jailah', - 'Jaselle', - 'Jaslyne', - 'Dalyla', - 'Emeraude', - 'Mahika', - 'Yoanna', - 'Fraida', - 'Tannia', - 'Selenne', - 'Analiz', - 'Angelene', - 'Anacristina', - 'Kylea', - 'Naydelyn', - 'Lecia', - 'Gitel', - 'Shareese', - 'Cassady', - 'Diem', - 'Perlita', - 'Monigue', - 'Marisha', - 'Emillee', - 'Kareli', - 'Shandreka', - 'Kerrin', - 'Tram', - 'Nohelani', - 'Monic', - 'Brandice', - 'Johnetta', - 'Evangelia', - 'Shakina', - 'Shunda', - 'Robbi', - 'Ariatna', - 'Shantae', - 'Sorangel', - 'Valene', - 'Aletta', - 'Libbie', - 'Marifer', - 'Deitra', - 'Despina', - 'Hayle', - 'Kassidi', - 'Dayrin', - 'Anjelina', - 'Gimena', - 'Llesenia', - 'Rainbow', - 'Muskaan', - 'Judit', - 'Kyley', - 'Tanna', - 'Luci', - 'Altagracia', - 'Kilee', - 'Kamry', - 'Kalyssa', - 'Jadeyn', - 'Virgen', - 'Damita', - 'Leinaala', - 'Illeana', - 'Nneka', - 'Onika', - 'Aralyn', - 'Mahalia', - 'Marelyn', - 'Jalene', - 'Bobbiejo', - 'Apollonia', - 'Anjuli', - 'Ricarda', - 'Fusako', - 'Michie', - 'Janira', - 'Citlalic', - 'Jannelle', - 'Tiffini', - 'Elisia', - 'Racine', - 'Marybel', - 'Xitlally', - 'Tynesha', - 'Sharay', - 'Shamara', - 'Aleene', - 'Rayssa', - 'Carlyn', - 'Falisha', - 'Lasandra', - 'Trinh', - 'Seema', - 'Tonianne', - 'Destani', - 'Nairobi', - 'Tomica', - 'Raena', - 'Ivania', - 'Odaliz', - 'Lilybeth', - 'Sheyenne', - 'Tereza', - 'Yuka', - 'Baleria', - 'Ayiana', - 'Floree', - 'Jhoanna', - 'Shakila', - 'Meleah', - 'Monserath', - 'Lelani', - 'Conception', - 'Zowie', - 'Teah', - 'Takayla', - 'Teaira', - 'Karyssa', - 'Delina', - 'Kamaile', - 'Rut', - 'Reanne', - 'Zamantha', - 'Ellyse', - 'Jisela', - 'Latonja', - 'Eiko', - 'Aylene', - 'Atziry', - 'Avila', - 'Andreya', - 'Delyla', - 'Aashna', - 'Dacia', - 'Shavonda', - 'Desirey', - 'Matea', - 'Makailah', - 'Henessy', - 'Naliyah', - 'Charlise', - 'Keirsten', - 'Ressie', - 'Halia', - 'Gweneth', - 'Manda', - 'Lilinoe', - 'Mariselda', - 'Tajuana', - 'Mahima', - 'Noeli', - 'Yanelli', - 'Sole', - 'Saloni', - 'Annistyn', - 'Marcille', - 'Thresa', - 'Cerenity', - 'Samnatha', - 'Alexah', - 'Analie', - 'Aryah', - 'Jazline', - 'Evony', - 'Erandy', - 'Jezelle', - 'Kamara', - 'Emelina', - 'Kadance', - 'Masae', - 'Davonna', - 'Shamaya', - 'Shalynn', - 'Rima', - 'Toria', - 'Zamira', - 'Cerina', - 'Fujiko', - 'Armine', - 'Morganne', - 'Gicela', - 'Desree', - 'Khaila', - 'Nikayla', - 'Kennedie', - 'Marylu', - 'Ilyssa', - 'Jatziri', - 'Shianna', - 'Dharma', - 'Resa', - 'Abra', - 'Neely', - 'Imo', - 'Betzabeth', - 'Briceyda', - 'Karenna', - 'Jakhia', - 'Ramiyah', - 'Khaliyah', - 'Tocarra', - 'Milee', - 'Athina', - 'Maleigha', - 'Shalyn', - 'Syliva', - 'Roseline', - 'Claira', - 'Jisselle', - 'Kiely', - 'Marisabel', - 'Maryanna', - 'Melena', - 'Mylene', - 'Mariangela', - 'Mailey', - 'Sonora', - 'Siana', - 'Shreeya', - 'Sevana', - 'Samhita', - 'Jackelyne', - 'Kyrstin', - 'Anslie', - 'Samella', - 'Jewelia', - 'Sammye', - 'Ayline', - 'Navneet', - 'Charlesetta', - 'Raye', - 'Yulonda', - 'Esmerelda', - 'Gianina', - 'Danessa', - 'Calia', - 'Everlena', - 'Sadaf', - 'Analucia', - 'Meriah', - 'Gwendalyn', - 'Disha', - 'Katana', - 'Kalaya', - 'Kaeley', - 'Tyonna', - 'Rozella', - 'Marjean', - 'Conchita', - 'Kylynn', - 'Aasiyah', - 'Maelynn', - 'Kahla', - 'Prachi', - 'Tajanae', - 'Megumi', - 'Micheala', - 'Yanitza', - 'Geselle', - 'Reather', - 'Annalicia', - 'Bonna', - 'Lilliann', - 'Callia', - 'Brigit', - 'Quintina', - 'Fujie', - 'Jolanda', - 'Nanami', - 'Yosselin', - 'Jakelyn', - 'Kadeja', - 'Eveny', - 'Emaly', - 'Ciena', - 'Julliana', - 'Jareli', - 'Jaretzi', - 'Kailin', - 'Kimiye', - 'Ammie', - 'Kiona', - 'Sumayyah', - 'Terre', - 'Laryssa', - 'Marleni', - 'Kamira', - 'Yulanda', - 'Jonda', - 'Lania', - 'Pippa', - 'Jazariah', - 'Takeya', - 'Shatima', - 'Ysenia', - 'Mikki', - 'Necole', - 'Etha', - 'Williemae', - 'Margurite', - 'Leonarda', - 'Inocencia', - 'Dominika', - 'Laisa', - 'Haylea', - 'Annamay', - 'Azia', - 'Mckynlee', - 'Maddilyn', - 'Scotlyn', - 'Lillith', - 'Mertie', - 'Kynzee', - 'Joshlynn', - 'Maelee', - 'Daleiza', - 'Xyla', - 'Royalty', - 'Railynn', - 'Patrycja', - 'Dotty', - 'Leda', - 'Toshiba', - 'Nelma', - 'Yeni', - 'Ottilie', - 'Lyna', - 'Leslieann', - 'Onita', - 'Darcey', - 'Marya', - 'Africa', - 'Seferina', - 'Theola', - 'Ysidra', - 'Zita', - 'Cing', - 'Zailynn', - 'Jennilee', - 'Sharmon', - 'Tyechia', - 'Irmgard', - 'Shameika', - 'Jemima', - 'Jazzelle', - 'Adlee', - 'Aliyanna', - 'Acelyn', - 'Catalaya', - 'Brileigh', - 'Braylie', - 'Angelin', - 'Arianni', - 'Ariani', - 'Kennya', - 'Maelyn', - 'Lillee', - 'Maripaz', - 'Laikyn', - 'Kenslee', - 'Ileane', - 'Puja', - 'Oanh', - 'Jakara', - 'Shawntay', - 'Cendy', - 'Erianna', - 'Chloie', - 'Birtie', - 'Korin', - 'Jannett', - 'Shawntel', - 'Markisha', - 'Nastassja', - 'Shalene', - 'Alexya', - 'Cloie', - 'Exa', - 'Jentri', - 'Modena', - 'Veronique', - 'Daina', - 'Mechele', - 'Lakesia', - 'Kawanna', - 'Clotilde', - 'Diamonique', - 'Teyana', - 'Rheagan', - 'Shanece', - 'Yanique', - 'Taysha', - 'Ulyssa', - 'Jadzia', - 'Kadija', - 'Towanna', - 'Lurlene', - 'Sharri', - 'Rosenda', - 'Daphna', - 'Hermina', - 'Shaquanda', - 'Saachi', - 'Sena', - 'Yazaira', - 'Yatzil', - 'Anam', - 'Sparrow', - 'Anetra', - 'Nalayah', - 'Jaylenne', - 'Joya', - 'Kensi', - 'Khylee', - 'Lilyrose', - 'Iasia', - 'Jaliah', - 'Melda', - 'Armella', - 'Zyasia', - 'Nazia', - 'Shanasia', - 'Krystie', - 'Dorothe', - 'Thora', - 'Adelene', - 'Avaya', - 'Aurielle', - 'Ailany', - 'Andromeda', - 'Loa', - 'Cleora', - 'Darling', - 'Caliana', - 'Keniyah', - 'Crystel', - 'Dimitra', - 'Renate', - 'Zyriah', - 'Taegan', - 'Marygrace', - 'Mckinzie', - 'Nivea', - 'Rhian', - 'Amarissa', - 'Kadee', - 'Devani', - 'Khara', - 'Aishia', - 'Annell', - 'Jaslin', - 'Jaide', - 'Briahna', - 'Merary', - 'Lauraine', - 'Tywana', - 'Athanasia', - 'Chantay', - 'Loretha', - 'Anyiah', - 'Marvine', - 'Jennelle', - 'Hiedi', - 'Sunnie', - 'Panagiota', - 'Lanesha', - 'Amity', - 'Denyse', - 'Nataleigh', - 'Amyia', - 'Avrie', - 'Analysa', - 'Ameris', - 'Ambrielle', - 'Kynnedy', - 'Gracy', - 'Kaelie', - 'Heydi', - 'Latrese', - 'Lavonia', - 'Latrelle', - 'Lynetta', - 'Graceann', - 'Susette', - 'Sarabeth', - 'Arnetta', - 'Shelonda', - 'Myiesha', - 'Shila', - 'Pascale', - 'Zenja', - 'Madelene', - 'Lalena', - 'Doria', - 'Dagmar', - 'Griselle', - 'Nitza', - 'Moraima', - 'Miguelina', - 'Brittania', - 'Emmalin', - 'Novie', - 'Chavonne', - 'Lashana', - 'Quyen', - 'Gennifer', - 'Zaryah', - 'Paytin', - 'Keeli', - 'Kolbi', - 'Maddyson', - 'Jackqueline', - 'Arnita', - 'Brynnley', - 'Edelyn', - 'Arial', - 'Yaneliz', - 'Ena', - 'Barbaraann', - 'Glendora', - 'Heavyn', - 'Neomi', - 'Rebbecca', - 'Laketa', - 'Renetta', - 'Carline', - 'Nezzie', - 'Shaneeka', - 'Desaray', - 'Hiromy', - 'Hallee', - 'Halli', - 'Sheba', - 'Tahisha', - 'Paetyn', - 'Katisha', - 'Joyell', - 'Joyel', - 'Zoei', - 'Zamiya', - 'Raygan', - 'Clydie', - 'Missouri', - 'Debany', - 'Kalisha', - 'Niurka', - 'Beverlyn', - 'Bell', - 'Zuly', - 'Lakayla', - 'Lainee', - 'Kynli', - 'Lundyn', - 'Erynn', - 'Braleigh', - 'Allena', - 'Lashanna', - 'Shaunya', - 'Tykia', - 'Leeba', - 'Bassheva', - 'Kandra', - 'Breyana', - 'Geovana', - 'Joandra', - 'Jessyka', - 'Analilia', - 'Charna', - 'Josefita', - 'Laurin', - 'Casi', - 'Jeniah', - 'Koraima', - 'Vivi', - 'Merlina', - 'Marinna', - 'Soriya', - 'Sarayu', - 'Ma', - 'Adali', - 'Abbygale', - 'Avonlea', - 'Bellah', - 'Makeyla', - 'Maanya', - 'Hania', - 'Ellah', - 'Esmee', - 'Jaylean', - 'Verlene', - 'Kendria', - 'Kasondra', - 'Kadesha', - 'Kadedra', - 'Reizel', - 'Reizy', - 'Sheryle', - 'Elka', - 'Caileigh', - 'Meya', - 'Rondi', - 'Janetta', - 'Dwana', - 'Yakira', - 'Donetta', - 'Laurissa', - 'Jordann', - 'Jenice', - 'Hasmik', - 'Mychelle', - 'Shabnam', - 'Sarahann', - 'Shaylene', - 'Zuleica', - 'Verenise', - 'Dejanee', - 'Alyx', - 'Breyanna', - 'Anum', - 'Jamesia', - 'Asheley', - 'Keya', - 'Lyzette', - 'Rossy', - 'Terilyn', - 'Rahaf', - 'Anabia', - 'Neala', - 'Payal', - 'Taheera', - 'Nakhia', - 'Shaela', - 'Krupa', - 'Suriya', - 'Victory', - 'Viviane', - 'Habiba', - 'Fortune', - 'Farida', - 'Erina', - 'Ranya', - 'Tifani', - 'Surie', - 'Aastha', - 'Joella', - 'Sherida', - 'Vonnie', - 'Bluma', - 'Gianny', - 'Naziyah', - 'Taylie', - 'Jakia', - 'Timia', - 'Farren', - 'Skylin', - 'Sabiha', - 'Nashley', - 'Blimi', - 'Annita', - 'Kristianna', - 'Delena', - 'Dalina', - 'Kyasia', - 'Cathlene', - 'Karalee', - 'Merilee', - 'Monette', - 'Asharia', - 'Jacquelina', - 'Nishat', - 'Charlcie', - 'Sukanya', - 'Celines', - 'Rashell', - 'Nadja', - 'Lamiyah', - 'Najae', - 'Zipporah', - 'Rawan', - 'Tailor', - 'Denesha', - 'Masiel', - 'Nida', - 'Assata', - 'Infiniti', - 'Cresencia', - 'Omega', - 'Meher', - 'Maneh', - 'Noura', - 'Yanine', - 'Maral', - 'Malori', - 'Safia', - 'Saori', - 'Vesper', - 'Audrinna', - 'Dea', - 'Kahlia', - 'Eliora', - 'Isley', - 'Laurinda', - 'Mignon', - 'Debie', - 'Denette', - 'Jolyn', - 'Casondra', - 'Donnisha', - 'Elysse', - 'Lazaria', - 'Aleia', - 'Shelbee', - 'Ivone', - 'Mazal', - 'Sherley', - 'Shantia', - 'Christelle', - 'Tatjana', - 'Roselia', - 'Pebbles', - 'Cleotilde', - 'Erendida', - 'Chardonnay', - 'Brittiny', - 'Brittanny', - 'Scarleth', - 'Mehar', - 'Neila', - 'Sofiya', - 'Lakshmi', - 'Lilianne', - 'Akeiba', - 'Shabreka', - 'Joannie', - 'Samiha', - 'Fatma', - 'Itzell', - 'Envy', - 'Maybelline', - 'Nashly', - 'Rya', - 'Kaelani', - 'Kailana', - 'Aylah', - 'Bellamarie', - 'Marizol', - 'Malyssa', - 'Madai', - 'Neelam', - 'Ysamar', - 'Sulma', - 'Sueling', - 'Song', - 'Sharayah', - 'Melisha', - 'Ashliegh', - 'Melodi', - 'Belem', - 'Chrystina', - 'Tonantzin', - 'Setareh', - 'Valeri', - 'Yaffa', - 'Niara', - 'Mame', - 'Janasia', - 'Flo', - 'Gustavia', - 'Lanya', - 'Nanie', - 'Velta', - 'Dot', - 'Luberta', - 'Ledora', - 'Olean', - 'Abbigayle', - 'Hadeel', - 'Rayma', - 'Mayola', - 'Nonnie', - 'Voncille', - 'Heloise', - 'Nolia', - 'Victorine', - 'Yola', - 'Vella', - 'Terrilyn', - 'Noelie', - 'Alean', - 'Allean', - 'Lorean', - 'Josiephine', - 'Heba', - 'Kerrianne', - 'Odeal', - 'Aigner', - 'Anaclara', - 'Gudrun', - 'Valborg', - 'Trenice', - 'Ardath', - 'Aune', - 'Teresia', - 'Lesha', - 'Dewanna', - 'Arlyce', - 'Jayliana', - 'Orene', - 'Paralee', - 'Jamyia', - 'Kemiyah', - 'Fredia', - 'Amyiah', - 'Doreatha', - 'Lashanta', - 'Cerissa', - 'Kawana', - 'Arizona', - 'Shanetta', - 'Jalesa', - 'Asmaa', - 'Garnette', - 'Clella', - 'Artemisa', - 'Liliya', - 'Oretha', - 'Adna', - 'Amyri', - 'Tyshae', - 'Maryan', - 'Santanna', - 'Bushra', - 'Jamyla', - 'Earma', - 'Delsie', - 'Verlean', - 'Sherena', - 'Carmelite', - 'Chari', - 'Darlean', - 'Shamia', - 'Audryna', - 'Genevia', - 'Avie', - 'Tamora', - 'Lavonna', - 'September', - 'Sharolyn', - 'Athziry', - 'Alyiah', - 'Aleina', - 'Alesandra', - 'Amoreena', - 'Nykia', - 'Drea', - 'Galilee', - 'Ainslie', - 'Ishita', - 'Jenavie', - 'Jezabel', - 'Erandi', - 'Evana', - 'Jiana', - 'Laniah', - 'Britanny', - 'Sanika', - 'Solash', - 'Laasya', - 'Nairi', - 'Leighla', - 'Kaiyah', - 'Suhana', - 'Taliya', - 'Maleia', - 'Candee', - 'Ninette', - 'Eugena', - 'Lateisha', - 'Salvatrice', - 'Quaneisha', - 'Mertis', - 'Bebe', - 'Rida', - 'Takyra', - 'Floye', - 'Christell', - 'Ozelle', - 'Juanice', - 'Genia', - 'Shaundra', - 'Shanin', - 'Wendee', - 'Cynde', - 'Adalynne', - 'Adelin', - 'Hayven', - 'Ayra', - 'Chimamanda', - 'Kenzlie', - 'Taylynn', - 'Zerenity', - 'Kynsleigh', - 'Dorthea', - 'Alley', - 'Melrose', - 'Keyondra', - 'Anglia', - 'Lynnea', - 'Tamira', - 'Terisa', - 'Tona', - 'Isaly', - 'Jeimy', - 'Giannah', - 'Leilanni', - 'Leya', - 'Quetzali', - 'Naylene', - 'Misaki', - 'Amely', - 'Donette', - 'Charlayne', - 'Selia', - 'Kittie', - 'Tamaya', - 'Lenna', - 'Zykerria', - 'Teisha', - 'Terrea', - 'Alita', - 'Bunny', - 'Deniece', - 'Inge', - 'Takira', - 'Monesha', - 'Mahala', - 'Donica', - 'Fortunata', - 'Valrie', - 'Zayah', - 'Ziyah', - 'Vela', - 'Vassie', - 'Omie', - 'Nadean', - 'Annalynn', - 'Adah', - 'Edmae', - 'Aalayah', - 'Yuritzy', - 'Ytzel', - 'Svetlana', - 'Soha', - 'Alfredia', - 'Kylei', - 'Landrey', - 'Lariyah', - 'Rozlyn', - 'Sakina', - 'Greer', - 'Bula', - 'Eura', - 'Harmonee', - 'Pecola', - 'Noreta', - 'Laveda', - 'Retta', - 'Rozlynn', - 'Skarlet', - 'Snow', - 'Zoha', - 'Sophiarose', - 'Anglea', - 'Itzabella', - 'Elanie', - 'Calirose', - 'Adhya', - 'Amaiyah', - 'Lavender', - 'Leylanie', - 'Kaliana', - 'Quetzaly', - 'Helon', - 'Nalia', - 'Cipriana', - 'Martyna', - 'Pola', - 'Dierra', - 'Maximina', - 'Sherica', - 'Murlene', - 'Berna', - 'Bernarda', - 'Ettie', - 'Laiken', - 'Hensley', - 'Fontella', - 'Modelle', - 'Timotea', - 'Venora', - 'Lakelyn', - 'Licia', - 'Laury', - 'Loralee', - 'Kamyah', - 'Verba', - 'Angelee', - 'Adalind', - 'Adaliz', - 'Ailynn', - 'Airi', - 'Alany', - 'Avika', - 'Avleen', - 'Leoni', - 'Saisha', - 'Savvy', - 'Philippa', - 'Jasneet', - 'Izabellah', - 'Elienai', - 'Kalayah', - 'Eureka', - 'Dionicia', - 'Zylah', - 'Zosia', - 'Yetzali', - 'Tigerlily', - 'Dorena', - 'Nakesha', - 'Lakenya', - 'Margarete', - 'Margarite', - 'Cloteal', - 'Adline', - 'Willadeen', - 'Anselma', - 'Marcheta', - 'Havyn', - 'Ilyanna', - 'Idalie', - 'Fallyn', - 'Emori', - 'Anzal', - 'Kalila', - 'Ellisyn', - 'Maddalyn', - 'Roslynn', - 'Hodan', - 'Emalynn', - 'Addy', - 'Adelyne', - 'Aizah', - 'Dalayza', - 'Cambri', - 'Annali', - 'Angelynn', - 'Caidence', - 'Auriana', - 'Azlynn', - 'Blakelee', - 'Brenleigh', - 'Tailynn', - 'Zyla', - 'Verline', - 'Pierina', - 'Panhia', - 'Valda', - 'Shela', - 'Uldine', - 'Vibha', - 'Wednesday', - 'Porshia', - 'Shabria', - 'Palmina', - 'Khristine', - 'Lannette', - 'Sandhya', - 'Janalyn', - 'Floreine', - 'Marchelle', - 'Minette', - 'Tawnia', - 'Wynne', - 'Sada', - 'Windi', - 'Clydene', - 'Shundra', - 'Joycie', - 'Delories', - 'Alvena', - 'Edmonia', - 'Denean', - 'Dhana', - 'Marjie', - 'Alicja', - 'Cammy', - 'Aryam', - 'Leonie', - 'Adrielle', - 'Felisita', - 'Tinnie', - 'Marinda', - 'Lamia', - 'Conchetta', - 'Naylah', - 'Sarayah', - 'Nataliya', - 'Delani', - 'Eknoor', - 'Ellee', - 'Maiah', - 'Mayumi', - 'Meara', - 'Kalliope', - 'Jewels', - 'Lanaya', - 'Yui', - 'Maxcine', - 'Yaqueline', - 'Yoceline', - 'Marilynne', - 'Maple', - 'Ronesha', - 'Marili', - 'Reema', - 'Rayana', - 'Aggie', - 'Talina', - 'Doristine', - 'Romelle', - 'Shaqueena', - 'Sharelle', - 'Caira', - 'Gelsey', - 'Tashawna', - 'Takeisha', - 'Jerlean', - 'Sunita', - 'Shalini', - 'Michaeline', - 'Audria', - 'Ronnisha', - 'Leonia', - 'Monna', - 'Ambra', - 'Corena', - 'Taren', - 'Alexiss', - 'Kajal', - 'Jordanne', - 'Kasia', - 'Brienna', - 'Gayane', - 'Deija', - 'Cidney', - 'Tabytha', - 'Raeleen', - 'Mkayla', - 'Harli', - 'Jassmin', - 'Ilo', - 'Lasheena', - 'Keianna', - 'Kally', - 'Makenzy', - 'Angelea', - 'Natasia', - 'Shaneequa', - 'Monay', - 'Moet', - 'Marcelline', - 'Shatia', - 'Sarafina', - 'Kaisha', - 'Tiffney', - 'Shenequa', - 'Sheretta', - 'Floria', - 'Alacia', - 'Kavita', - 'Kerianne', - 'Tameshia', - 'Jamye', - 'Shanese', - 'Latiqua', - 'Jesscia', - 'Johanny', - 'Daniqua', - 'Geneviev', - 'Bernadet', - 'Annice', - 'Megann', - 'Katee', - 'Nikeya', - 'Stavroula', - 'Tawna', - 'Sindia', - 'Marlaina', - 'Jury', - 'Tovah', - 'Shivonne', - 'Nekia', - 'Yvonnie', - 'Kyna', - 'Railey', - 'Xandria', - 'Genine', - 'Tashima', - 'Marycarmen', - 'Kiahna', - 'Jadynn', - 'Akua', - 'Eather', - 'Fatema', - 'Aiysha', - 'Allisa', - 'Ashleynicole', - 'Bobette', - 'Shandrika', - 'Hollace', - 'Chandni', - 'Cayley', - 'Brenae', - 'Areisy', - 'Annahi', - 'Anallely', - 'Klarisa', - 'Ayssa', - 'Jatavia', - 'Nohemy', - 'Mikyla', - 'Mariadelosang', - 'Shatina', - 'Kazandra', - 'Elsi', - 'Teryl', - 'Yennifer', - 'Destyni', - 'Damariz', - 'Areanna', - 'Everlean', - 'Lesslie', - 'Margrette', - 'Tuyet', - 'Jacquelene', - 'Grissel', - 'Walterine', - 'Shterna', - 'Gila', - 'Nabila', - 'Liel', - 'Sani', - 'Djeneba', - 'Angeliz', - 'Anari', - 'Amyrie', - 'Aissa', - 'Tichina', - 'Amariana', - 'Xiara', - 'Yamiles', - 'Isatou', - 'Airiana', - 'Carrigan', - 'Aldea', - 'Aarika', - 'Bryanne', - 'Alegandra', - 'Carrisa', - 'Andrina', - 'Casaundra', - 'Breanda', - 'Biviana', - 'Irena', - 'Denielle', - 'Lizzett', - 'Shaunice', - 'Sigourney', - 'Sona', - 'Paradise', - 'Lashanique', - 'Melaina', - 'Zoua', - 'Vaneza', - 'Tyresha', - 'Shyasia', - 'Tiyana', - 'Youa', - 'Zaneta', - 'Muskan', - 'Talissa', - 'Kennisha', - 'Lizandra', - 'Akosua', - 'Jaymi', - 'Chelby', - 'Chelci', - 'Aeriel', - 'Isamara', - 'Payge', - 'Hadja', - 'Fruma', - 'Fiza', - 'Fatumata', - 'Kabrina', - 'Feigy', - 'Zanaya', - 'Yanette', - 'Teairra', - 'Talor', - 'Kathrina', - 'Justeen', - 'Maryelizabeth', - 'Jannete', - 'Chantalle', - 'Haide', - 'Genelle', - 'Esthela', - 'Emilse', - 'Maegen', - 'Lyndsi', - 'Cristiana', - 'Clio', - 'Breindel', - 'Briyana', - 'Jamyria', - 'Jameshia', - 'Kadeshia', - 'Jamisha', - 'Faige', - 'Aishah', - 'Lorette', - 'Nandi', - 'Nastasia', - 'Shada', - 'Shakeia', - 'Shaneice', - 'Yanel', - 'Teryn', - 'Shaylyn', - 'Karimah', - 'Fabienne', - 'Shaianne', - 'Saleena', - 'Raychelle', - 'Pahoua', - 'Justyne', - 'Fransheska', - 'Katilyn', - 'Shadaya', - 'Quanasia', - 'Shantasia', - 'Nyasha', - 'Minahil', - 'Shahd', - 'Chani', - 'Bassy', - 'Zunairah', - 'Lynsie', - 'Charnelle', - 'Jaquana', - 'Taquana', - 'Shaasia', - 'Idelle', - 'Rogene', - 'Udy', - 'Devory', - 'Evanna', - 'Keisy', - 'Hadiya', - 'Brittainy', - 'Cortni', - 'Erikka', - 'Lindsie', - 'Mayraalejandra', - 'Topacio', - 'Elky', - 'Yita', - 'Sura', - 'Tiani', - 'Sadiya', - 'Kaitlen', - 'Jessicca', - 'Linna', - 'Stephy', - 'Hadia', - 'Jaiyana', - 'Aldina', - 'Frimy', - 'Tywanda', - 'Renarda', - 'Mardelle', - 'Alaijah', - 'Antoinetta', - 'Amyria', - 'Sheyanne', - 'Jackee', - 'Bina', - 'Khole', - 'Selenia', - 'Seidy', - 'Albertina', - 'Yoandra', - 'Yarelyn', - 'Kassaundra', - 'Lynzee', - 'Haneen', - 'Marshay', - 'Sharona', - 'Shanygne', - 'Nigeria', - 'Nechy', - 'Jhane', - 'Chrisette', - 'Gypsy', - 'Drusilla', - 'Milta', - 'Ranee', - 'Yvett', - 'Mykenzie', - 'Aracelia', - 'Vernessa', - 'Chekesha', - 'Cadance', - 'Moria', - 'Tsurue', - 'Yarisbel', - 'Verena', - 'Tomoe', - 'Breezy', - 'Swannie', - 'Tsuyuko', - 'Hisayo', - 'Gerianne', - 'Cailynn', - 'Adrionna', - 'Lillianne', - 'Eduarda', - 'Melinna', - 'Sanaiya', - 'Nohelia', - 'Zarela', - 'Yarethzy', - 'Sruthi', - 'Josefine', - 'Kiela', - 'Kersten', - 'Syriah', - 'Emaleigh', - 'Jazlynne', - 'Aeryn', - 'Danelly', - 'Dalylah', - 'Lexa', - 'Kherington', - 'Nivia', - 'Carolanne', - 'Sharlotte', - 'Vanda', - 'Deirdra', - 'Ilyse', - 'Judyann', - 'Venezia', - 'Mailee', - 'Latishia', - 'Ajla', - 'Lucine', - 'Shontell', - 'Rosiland', - 'Celinda', - 'Aanika', - 'Felicidad', - 'Denia', - 'Natsuko', - 'Analyse', - 'Angellina', - 'Brizeida', - 'Jazira', - 'Terah', - 'Reana', - 'Jennalyn', - 'Jenaya', - 'Kelani', - 'Miyuki', - 'Aracelie', - 'Dannika', - 'Danity', - 'Cadie', - 'Breelyn', - 'Kayra', - 'Mayli', - 'Malarie', - 'Tequilla', - 'Gerilyn', - 'Mieko', - 'Belynda', - 'Shamiyah', - 'Reaghan', - 'Ziya', - 'Rozanne', - 'Joyanne', - 'Zamaria', - 'Luiza', - 'Tamanika', - 'Kimya', - 'Patriciaann', - 'Eilene', - 'Bryna', - 'Yena', - 'Yarelly', - 'Maddyn', - 'Khylie', - 'Khyla', - 'Margueritte', - 'Ramya', - 'Jenea', - 'Jennavie', - 'Jazzlene', - 'Marelly', - 'Manya', - 'Lillyanne', - 'Gyselle', - 'Niyati', - 'Moana', - 'Kenosha', - 'Ezmeralda', - 'Anvitha', - 'Avelyn', - 'Dahlila', - 'Emmaly', - 'Dayamy', - 'Anajulia', - 'Mandee', - 'Valli', - 'Sharan', - 'Leasia', - 'Shiquita', - 'Malana', - 'Nadeen', - 'Parneet', - 'Lynna', - 'Saskia', - 'Samaiya', - 'Saffron', - 'Vianka', - 'Evey', - 'Ebelin', - 'Anishka', - 'Aneth', - 'Addelynn', - 'Kayly', - 'Alyzae', - 'Anniyah', - 'Ayme', - 'Alexsa', - 'Aidsa', - 'Elyn', - 'Illianna', - 'Greenlee', - 'Tinesha', - 'Sherline', - 'Yvanna', - 'Joslin', - 'Estee', - 'Lusia', - 'Nhung', - 'Janielle', - 'Smithie', - 'Yohanna', - 'Shanette', - 'Marilena', - 'Blannie', - 'Meleana', - 'Malie', - 'Jannine', - 'Kuulei', - 'Kawehi', - 'Velna', - 'Kuuipo', - 'Keani', - 'Tiffeny', - 'Billi', - 'Conni', - 'Elexia', - 'Sheily', - 'Mehak', - 'Ardelia', - 'Phung', - 'Aleasha', - 'Toyia', - 'Kalliopi', - 'Carrieann', - 'Shayal', - 'Brandye', - 'Shatisha', - 'Neola', - 'Pallavi', - 'Symantha', - 'Mackenzee', - 'Shalawn', - 'Krimson', - 'Jaquelinne', - 'Sonal', - 'Calysta', - 'Kaylamarie', - 'Kirah', - 'Belicia', - 'Anicia', - 'Aerin', - 'Marisel', - 'Priscella', - 'Lei', - 'Imaan', - 'Haruka', - 'Kila', - 'Jerusha', - 'Deva', - 'Charon', - 'Leida', - 'Deadra', - 'Areana', - 'Iriana', - 'Drenda', - 'Saadia', - 'Danne', - 'Jossalyn', - 'Kennadie', - 'Makaya', - 'Daelynn', - 'Daffne', - 'Galia', - 'Naida', - 'Yaira', - 'Latania', - 'Damarys', - 'Mireille', - 'Maribell', - 'Luzelena', - 'Anacani', - 'Sahira', - 'Shaylin', - 'Sejal', - 'Subrina', - 'Julaine', - 'Saby', - 'Zoraya', - 'Atalie', - 'Deseray', - 'Nacole', - 'Jennell', - 'Laneisha', - 'Ivie', - 'Darnella', - 'Lashone', - 'Lekeisha', - 'Puanani', - 'Uilani', - 'Donyale', - 'Terriann', - 'Marianela', - 'Josalynn', - 'Avari', - 'Blonnie', - 'Makya', - 'Seriah', - 'Nori', - 'Roselee', - 'Verbie', - 'Borghild', - 'Marcene', - 'Syretta', - 'Bama', - 'Eulene', - 'Chantale', - 'Shontae', - 'Mabell', - 'Hellon', - 'Shantanique', - 'Janki', - 'Dhara', - 'Buna', - 'Naeemah', - 'Tacara', - 'Shirleyann', - 'Tshwanda', - 'Nadege', - 'Georganne', - 'Leondra', - 'Fredricka', - 'Margaree', - 'Quincee', - 'Oaklynn', - 'Arlean', - 'Judee', - 'Nyoka', - 'Khia', - 'Kendia', - 'Mahek', - 'Anasia', - 'Jenin', - 'Gerline', - 'Elwillie', - 'Annsley', - 'Juhi', - 'Zettie', - 'Shacara', - 'Shantique', - 'Marijo', - 'Shakara', - 'Ersie', - 'Bionca', - 'Kolleen', - 'Ertha', - 'Chioma', - 'Roneisha', - 'Courtenay', - 'Altie', - 'Arla', - 'Delainey', - 'Rainelle', - 'Lockie', - 'Rayonna', - 'Nasiyah', - 'Zori', - 'Carollee', - 'Mima', - 'Irja', - 'Willadean', - 'Sigrid', - 'Myong', - 'Khaliah', - 'Sakeenah', - 'Saleemah', - 'Emmersyn', - 'Miyeko', - 'Brooksie', - 'Brailynn', - 'Raghad', - 'Nadira', - 'Hassana', - 'Toshiye', - 'Fumiye', - 'Kelise', - 'Angelis', - 'Earla', - 'Dilia', - 'Arwa', - 'Shaylie', - 'Synai', - 'Tanijah', - 'Jalaysia', - 'Charnita', - 'Marit', - 'Gaelle', - 'Shandiin', - 'Janelis', - 'Gatha', - 'Alahna', - 'Aniyla', - 'Mikelle', - 'Skai', - 'Merlinda', - 'Tariyah', - 'Arietta', - 'Terrika', - 'Elenor', - 'Ruthanna', - 'Evaline', - 'Abigaelle', - 'Alayjah', - 'Naysa', - 'Camya', - 'Pachia', - 'Kamia', - 'Sylvania', - 'Ambree', - 'Oakleigh', - 'Zania', - 'Murielle', - 'Charlyn', - 'Zykira', - 'Jestine', - 'Simonne', - 'Willodene', - 'Lyndee', - 'Sophonie', - 'Saddie', - 'Darlis', - 'Lynnda', - 'Marysa', - 'Seleena', - 'Raevyn', - 'Lilikoi', - 'Maiyer', - 'Kymberli', - 'Shayda', - 'Cassidee', - 'Jadira', - 'Delora', - 'Afsheen', - 'Adira', - 'Amena', - 'Canary', - 'Humaira', - 'Derricka', - 'Fatiha', - 'Xia', - 'Jaquelyne', - 'Aurianna', - 'Sarahjane', - 'Sanaz', - 'Taleen', - 'Teara', - 'Taiz', - 'Sharai', - 'Magally', - 'Manon', - 'Maizie', - 'Manisha', - 'Marisleysis', - 'Anjela', - 'Youlanda', - 'Jermani', - 'Elysha', - 'Claritza', - 'Gissela', - 'Icela', - 'Alixandria', - 'Asley', - 'Analuisa', - 'Maddalena', - 'Cortnee', - 'Coretha', - 'Audreanna', - 'Manal', - 'Kadijatou', - 'Pollie', - 'Mysti', - 'Tiffiany', - 'Corean', - 'Amiree', - 'Anner', - 'Cleone', - 'Lavone', - 'Fredna', - 'Konnie', - 'Robbyn', - 'Alica', - 'Bessy', - 'Aleesa', - 'Analleli', - 'Mischelle', - 'Bethani', - 'Baillie', - 'Odessie', - 'Erlene', - 'Marcile', - 'Edona', - 'Tylah', - 'Tyrah', - 'Rainell', - 'Precilla', - 'Genever', - 'Ajanee', - 'Chera', - 'Amye', - 'Monserratt', - 'Moorea', - 'Richa', - 'Willetta', - 'Shawne', - 'Trisa', - 'Lasonia', - 'Cleona', - 'Alizea', - 'Anayely', - 'Emelly', - 'Fionna', - 'Cerena', - 'Julyana', - 'Kaile', - 'Jacklin', - 'Brianca', - 'Ashleyann', - 'Richardine', - 'Kelcee', - 'Keyaira', - 'Mabelle', - 'Brecklyn', - 'Samyah', - 'Ayonna', - 'Mesha', - 'Tyeshia', - 'Tiffiney', - 'Tyara', - 'Azuri', - 'Merideth', - 'Hermie', - 'Leaner', - 'Mendi', - 'Kanoelani', - 'Kadeidra', - 'Akeela', - 'Lin', - 'Mindel', - 'Lashell', - 'Meegan', - 'Ia', - 'Ellamae', - 'Jasmen', - 'Nechuma', - 'Romilda', - 'Hiilei', - 'Osmara', - 'Keidy', - 'Rianne', - 'Afia', - 'Teylor', - 'Raquelle', - 'Grizelda', - 'Tasfia', - 'Laquasha', - 'Tandra', - 'Maeghan', - 'Kameshia', - 'Alara', - 'Emina', - 'Delaina', - 'Jacquetta', - 'Christena', - 'Topanga', - 'Viviann', - 'Eboney', - 'Kasha', - 'Sativa', - 'Secilia', - 'Niomi', - 'Neena', - 'Tanji', - 'Shandy', - 'Corryn', - 'Esly', - 'Silka', - 'Sanaii', - 'Annais', - 'Kaitlynne', - 'Epiphany', - 'Maniya', - 'Mali', - 'Madigan', - 'Sanii', - 'Jaeleen', - 'Faria', - 'Maralyn', - 'Johnae', - 'Lekesha', - 'Sharry', - 'Latecia', - 'Kimberl', - 'Charita', - 'Modean', - 'Marrie', - 'Lielle', - 'Zeina', - 'Pessel', - 'Sameera', - 'Eleonora', - 'Jannatul', - 'Coryn', - 'Dustie', - 'Demitria', - 'Jacqlyn', - 'Nekisha', - 'Latrecia', - 'Rabecca', - 'Malaysha', - 'Lugenia', - 'Elese', - 'Myrissa', - 'Lucrecia', - 'Lysandra', - 'Tarryn', - 'Tammey', - 'Bonnita', - 'Shiffy', - 'Shirel', - 'Clariza', - 'Analis', - 'Rechy', - 'Nusaiba', - 'Manahil', - 'Chamisa', - 'Almetta', - 'Moncia', - 'Leba', - 'Jeilyn', - 'Earnesteen', - 'Mennie', - 'Kieara', - 'Sheina', - 'Yo', - 'Sharnice', - 'Ravin', - 'Daisi', - 'Britini', - 'Carlina', - 'Arisa', - 'Margy', - 'Whitnee', - 'Krysti', - 'Odean', - 'Darlys', - 'Janita', - 'Donnetta', - 'Guynell', - 'Neomia', - 'Loyalty', - 'Serra', - 'Kaysie', - 'Preciosa', - 'Earleen', - 'Shatoria', - 'Kourtnie', - 'Kana', - 'Jahnavi', - 'Kyarra', - 'Licet', - 'Railyn', - 'Delisha', - 'Flordia', - 'Arsema', - 'Kena', - 'Kaelah', - 'Kashia', - 'Emonie', - 'Izola', - 'Linsay', - 'Naibe', - 'Natallie', - 'Rosi', - 'Taline', - 'Cortina', - 'Annett', - 'Kadi', - 'Lindsi', - 'Lasasha', - 'Tamre', - 'Yenny', - 'Yasaman', - 'Shawnice', - 'Thi', - 'Jannel', - 'Kaleen', - 'Demitra', - 'Meisha', - 'Mahira', - 'Emmanuela', - 'Janaiya', - 'Rechel', - 'Nazifa', - 'Zeynep', - 'Shalena', - 'Hila', - 'Ailish', - 'Altovise', - 'Anabeth', - 'Anavictoria', - 'Averey', - 'Berlynn', - 'Alitza', - 'Adelynne', - 'Aiva', - 'Alenna', - 'Harlowe', - 'Camrynn', - 'Daphnie', - 'Ezri', - 'Lanna', - 'Lua', - 'Maddilynn', - 'Maeva', - 'Maytte', - 'Jovi', - 'Karalyn', - 'Kataleah', - 'Kaylana', - 'Milliana', - 'Surveen', - 'Veera', - 'Nimrat', - 'Nimrit', - 'Radha', - 'Roisin', - 'Senna', - 'Ruhi', - 'Saja', - 'Glenice', - 'Damiana', - 'Mikeria', - 'Lakeria', - 'Yulia', - 'Zanna', - 'Lynnae', - 'Illa', - 'Buelah', - 'Novis', - 'Johnye', - 'Valree', - 'Santiaga', - 'Modell', - 'Maydell', - 'Elfida', - 'Charlyne', - 'Argentina', - 'Terica', - 'Kiandra', - 'Tangi', - 'Pascuala', - 'Narcisa', - 'Macaria', - 'Thomasa', - 'Verta', - 'Eulogia', - 'Trellis', - 'Tavaria', - 'Dakayla', - 'Oneita', - 'Kimberlynn', - 'Aslee', - 'Jenascia', - 'Shamaria', - 'Lakely', - 'Etna', - 'Gilberte', - 'Glena', - 'Delorse', - 'Margrett', - 'Endia', - 'Buena', - 'Alvilda', - 'Domitila', - 'Jasmaine', - 'Jaquita', - 'Shontavia', - 'Roneshia', - 'Leasa', - 'Feliciana', - 'Allyana', - 'Anaia', - 'Annalyn', - 'Ayane', - 'Belladonna', - 'Adanely', - 'Akshaya', - 'Aleiyah', - 'Tereasa', - 'Antonisha', - 'Darlah', - 'Dhalia', - 'Dianelly', - 'Elika', - 'Camillia', - 'Leonila', - 'Manreet', - 'Jazzlin', - 'Kaiulani', - 'Kashvi', - 'Talayah', - 'Viana', - 'Ximenna', - 'Shaylah', - 'Quorra', - 'Anagha', - 'Annalea', - 'Jaleyah', - 'Bethanny', - 'Zophia', - 'Alegria', - 'Advika', - 'Taneika', - 'Marye', - 'Latorya', - 'Sayler', - 'Nara', - 'Nithya', - 'Phoenyx', - 'Saiya', - 'Mellany', - 'Yazlin', - 'Adalena', - 'Adya', - 'Aliviah', - 'Aalia', - 'Rickia', - 'Eliyana', - 'Arella', - 'Audris', - 'Auria', - 'Avantika', - 'Aylani', - 'Beya', - 'Camilah', - 'Kaede', - 'Laylonie', - 'Jayani', - 'Katara', - 'Hera', - 'Audrea', - 'Nataley', - 'Nazli', - 'Neyla', - 'Noya', - 'Srinidhi', - 'Pranavi', - 'Sareen', - 'Satya', - 'Terika', - 'Zamora', - 'Jimmye', - 'Brigida', - 'Shereka', - 'Widline', - 'Natori', - 'Dorthie', - 'Berit', - 'Aretta', - 'Svea', - 'Wenona', - 'Amera', - 'Nayah', - 'Lollie', - 'Genice', - 'Fabianna', - 'Nazaria', - 'Edra', - 'Jamariah', - 'Willine', - 'Madolyn', - 'Wanell', - 'Lucetta', - 'Eudora', - 'Adda', - 'Shariah', - 'Jaelle', - 'Jalena', - 'Annelle', - 'Solveig', - 'Autherine', - 'Nobie', - 'Izora', - 'Eudell', - 'Wyolene', - 'Mariangel', - 'Mayar', - 'Luevenia', - 'Eniyah', - 'Lilie', - 'Eliany', - 'Ivyonna', - 'Beadie', - 'Zeta', - 'Merita', - 'Valjean', - 'Delbra', - 'Alanys', - 'Camiyah', - 'Edyth', - 'Kanya', - 'Perina', - 'Catelynn', - 'Angelisse', - 'Relda', - 'Eathel', - 'Kerrington', - 'Lyriq', - 'Brita', - 'Meda', - 'Zanya', - 'Emileigh', - 'Aracelys', - 'Lisania', - 'Evalena', - 'Traniya', - 'Janiyla', - 'Syesha', - 'Ahmya', - 'Camora', - 'Armonie', - 'Beula', - 'Veva', - 'Kateria', - 'Harumi', - 'Kimiyo', - 'Tangie', - 'Amayrany', - 'Alexiah', - 'Alyn', - 'Tokie', - 'Masayo', - 'Makenzee', - 'Arieana', - 'Asayo', - 'Seirra', - 'Elfrida', - 'Ariona', - 'Masue', - 'Mizuki', - 'Liliane', - 'Malanie', - 'Sabreen', - 'Yuritza', - 'Shanautica', - 'Kateleen', - 'Montanna', - 'Tiona', - 'Theresia', - 'Vernia', - 'Mahayla', - 'Glynna', - 'Shaelynn', - 'Isabelly', - 'Aileth', - 'Ailie', - 'Melvia', - 'Sherrel', - 'Ivah', - 'Himani', - 'Marayah', - 'Melane', - 'Evanie', - 'Atalia', - 'Athalia', - 'Bethsy', - 'Betzi', - 'California', - 'Bryonna', - 'Yaretsy', - 'Zamara', - 'Sanyah', - 'Gaylynn', - 'Vitoria', - 'Yoshino', - 'Hatsumi', - 'Tatsuko', - 'Samika', - 'Maili', - 'Charnae', - 'Jamilla', - 'Vieno', - 'Rylei', - 'Vanita', - 'Hydia', - 'Carmyn', - 'Kenslie', - 'Maryhelen', - 'Lamees', - 'Lilley', - 'Haunani', - 'Pualani', - 'Mikiyah', - 'Lovina', - 'Janith', - 'Kanoe', - 'Anouk', - 'Mayerly', - 'Kiele', - 'Lexia', - 'Janani', - 'Berlinda', - 'Belma', - 'Inayah', - 'Saloma', - 'Anely', - 'Anjolina', - 'Devonna', - 'Nikhita', - 'Nayana', - 'Naidely', - 'Hina', - 'Ismerai', - 'Daisie', - 'Sitlaly', - 'Yahayra', - 'Trinidy', - 'Vallery', - 'Ceaira', - 'Floretta', - 'Lavena', - 'Shawntavia', - 'Dessa', - 'Tareva', - 'Iyanla', - 'Kania', - 'Shakiya', - 'Latora', - 'Hermila', - 'Clora', - 'Tiyanna', - 'Saydie', - 'Sherlene', - 'Trixie', - 'Nadiyah', - 'Zarria', - 'Saidy', - 'Sabriya', - 'Keirra', - 'Leeana', - 'Leianna', - 'Jaia', - 'Ishanvi', - 'Ailed', - 'Fathima', - 'Hansika', - 'Delailah', - 'Caliah', - 'Dayleen', - 'Jolisa', - 'Sallye', - 'Levonia', - 'Tula', - 'Kristene', - 'Alanni', - 'Aleiah', - 'Aeva', - 'Ilean', - 'Annet', - 'Lateshia', - 'Markesha', - 'Nikol', - 'Nadolyn', - 'Kimyatta', - 'Ercilia', - 'Sheliah', - 'Heiley', - 'Metztli', - 'Teyla', - 'Saranya', - 'Tanishka', - 'Kayana', - 'Donnamae', - 'Lajoyce', - 'Kemya', - 'Kemora', - 'Jozelyn', - 'Keili', - 'Jaydy', - 'Linzy', - 'Marelin', - 'Melaney', - 'Aleksa', - 'Alynah', - 'Elyza', - 'Emmery', - 'Angeleen', - 'Annica', - 'Bindi', - 'Demya', - 'Nayleen', - 'Sadee', - 'Samah', - 'Shylee', - 'Talula', - 'Vannia', - 'Yarelli', - 'Zohar', - 'Miangel', - 'Orla', - 'Sundra', - 'Korinne', - 'Taniesha', - 'Zaliyah', - 'Zionna', - 'Amariyah', - 'Loris', - 'Cruzita', - 'Landa', - 'Eduvina', - 'Ileanna', - 'Ileene', - 'Jesselle', - 'Daviana', - 'Eleny', - 'Marijane', - 'Okla', - 'Violanda', - 'Dorma', - 'Leoma', - 'Esperansa', - 'Shanreka', - 'Baudelia', - 'Teasia', - 'Aubrei', - 'Jeree', - 'Ortencia', - 'Melida', - 'Pernie', - 'Sweetie', - 'Arelly', - 'Ariday', - 'Bhavya', - 'Aiyanah', - 'Akshita', - 'Ginette', - 'Docia', - 'Pegeen', - 'Alaynah', - 'Allanah', - 'Daniah', - 'Loriana', - 'Kenly', - 'Kenli', - 'Kendahl', - 'Kenady', - 'Senora', - 'Hetal', - 'Aloha', - 'Barri', - 'Shaniquah', - 'Feather', - 'Rica', - 'Adriann', - 'Fleta', - 'Shontel', - 'Kynisha', - 'Nahima', - 'Myracle', - 'Syniah', - 'Jomarie', - 'Leeandra', - 'Maylie', - 'Marijose', - 'Jaley', - 'Sydnei', - 'Amariya', - 'Alysandra', - 'Damia', - 'Laurieann', - 'Lucecita', - 'Miosotis', - 'Shelvy', - 'Bernina', - 'Darice', - 'Dorrie', - 'Myrta', - 'Yoko', - 'Vara', - 'Joanmarie', - 'Kerryann', - 'Carmesa', - 'Kenzington', - 'Oaklyn', - 'Shelbia', - 'Arhianna', - 'Ardyn', - 'Amarachi', - 'Cydnee', - 'Chloey', - 'Brailee', - 'Aily', - 'Rosette', - 'Geryl', - 'Luba', - 'Marguerita', - 'Ayannah', - 'Deziyah', - 'Lurdes', - 'Dawnelle', - 'Reiko', - 'Brynli', - 'Tenlee', - 'Kynadee', - 'Emersen', - 'Josilyn', - 'Jazalyn', - 'Maleyah', - 'Cozette', - 'Xoe', - 'Syria', - 'Charyl', - 'Gita', - 'Aniaya', - 'Yulemni', - 'Joleigh', - 'Kenzy', - 'Logann', - 'Genesys', - 'Cherita', - 'Trenise', - 'Stpehanie', - 'Riann', - 'Matilyn', - 'Akisha', - 'Coralee', - 'Presli', - 'Yariana', - 'Edda', - 'Lisabeth', - 'Farm', - 'Dennice', - 'Deepa', - 'Chiffon', - 'Alyzea', - 'Alexas', - 'Emylee', - 'Joellyn', - 'Zo', - 'Marybell', - 'Sapna', - 'Khristina', - 'Kellyanne', - 'Chrystie', - 'Damary', - 'Graziella', - 'Tene', - 'Shakisha', - 'Shirelle', - 'Gwynne', - 'Insha', - 'Lydiann', - 'Cuba', - 'Cortnie', - 'Denelle', - 'Huyen', - 'Brieann', - 'Cindia', - 'Shalina', - 'Linnette', - 'Kiamesha', - 'Anecia', - 'Brinna', - 'Kewanna', - 'Malke', - 'Yira', - 'Rashidah', - 'Karicia', - 'Chrislyn', - 'Idali', - 'Zandria', - 'Ruta', - 'Toshi', - 'Daena', - 'Aneliz', - 'Cherese', - 'Brandalyn', - 'Brieanne', - 'Chistina', - 'Denys', - 'Nyisha', - 'Lissie', - 'Sherine', - 'Marisal', - 'Tuwana', - 'Zyonna', - 'Shady', - 'Patrisha', - 'Laniece', - 'Jessamyn', - 'Letticia', - 'Shirlie', - 'Miyo', - 'Marilouise', - 'Yukiye', - 'Ltanya', - 'Geralynn', - 'Anastazia', - 'Mitzie', - 'Lluliana', - 'Rozanna', - 'Magalie', - 'Salima', - 'Bevin', - 'Gaudy', - 'Ieasha', - 'Makia', - 'Sacheen', - 'Sherene', - 'Mataya', - 'Hatsuye', - 'Chiyeko', - 'Devanny', - 'Nasya', - 'Odyssey', - 'Tunisia', - 'Caldonia', - 'Marsi', - 'Mindee', - 'Tamy', - 'Sherill', - 'Tsitsiki', - 'Arva', - 'Gayleen', - 'Kimmy', - 'Lenette', - 'Roxan', - 'Leanora', - 'Charlena', - 'Claudina', - 'Danise', - 'Denell', - 'Eydie', - 'Irish', - 'Hydeia', - 'Nichele', - 'Ronica', - 'Temre', - 'Cindra', - 'Vincenta', - 'Zyra', - 'Larita', - 'Jodine', - 'Ewelina', - 'Madylin', - 'Kinzleigh', - 'Malone', - 'Layken', - 'Verity', - 'Tinleigh', - 'Sophi', - 'Skyleigh', - 'Stanislawa', - 'Rylinn', - 'Natalynn', - 'Marlei', - 'Rhylie', - 'Payslee', - 'Paxtyn', - 'Brittyn', - 'Alaynna', - 'Avory', - 'Aubriee', - 'Jacqui', - 'Aseel', - 'Jannell', - 'Simra', - 'Raneem', - 'Kellene', - 'Shellee', - 'Tish', - 'Lashauna', - 'Ashira', - 'Sharrie', - 'Donnette', - 'Milarain', - 'Toshia', - 'Shariyah', - 'Dariah', - 'Gustava', - 'Leotha', - 'Sherelle', - 'Lindi', - 'Luanna', - 'Shanan', - 'Arelys', - 'Nyema', - 'Errin', - 'Fredrica', - 'Dhriti', - 'Yashvi', - 'Gaile', - 'Ermalinda', - 'Gregorita', - 'Klynn', - 'Kaedence', - 'Zaila', - 'Yaritzi', - 'Taylyn', - 'Tailyn', - 'Milka', - 'Maesyn', - 'Macyn', - 'Riyah', - 'Alleigh', - 'Aracelli', - 'Hadlie', - 'Iza', - 'Riddhi', - 'Kathleene', - 'Darely', - 'Eleyna', - 'Analiya', - 'Fanchon', - 'Allyce', - 'Jasma', - 'Porschia', - 'Deberah', - 'Zoi', - 'Sherlyne', - 'Favour', - 'Shakari', - 'Mckenzy', - 'Makinzie', - 'Maahi', - 'Jacqualine', - 'Nancyann', - 'Ronne', - 'Charmane', - 'Martie', - 'Leane', - 'Kama', - 'Corrinne', - 'Vangie', - 'Jonni', - 'Michon', - 'Sharise', - 'Shawnie', - 'Joane', - 'Rosary', - 'Noretta', - 'Zaylynn', - 'Paislie', - 'Infinity', - 'Amaryllis', - 'Altair', - 'Cookie', - 'Danyella', - 'Collyns', - 'Chrislynn', - 'Bryley', - 'Brelynn', - 'Finleigh', - 'Evianna', - 'Flavia', - 'Wilhemina', - 'Jaeliana', - 'Taija', - 'Naiomi', - 'Jennika', - 'Jenika', - 'Jaicee', - 'Laurice', - 'Ashaunti', - 'Alyxandria', - 'Delfinia', - 'Tyiesha', - 'Petrita', - 'Fedelina', - 'Eufelia', - 'Marshae', - 'Marquesha', - 'Feloniz', - 'Tyliyah', - 'Nadene', - 'Natascha', - 'Shawnette', - 'Jamese', - 'Tashay', - 'Mckenzee', - 'Mckinsey', - 'Langley', - 'Kensleigh', - 'Karolyna', - 'Coralyn', - 'Grethel', - 'Baylei', - 'Ariany', - 'Mekenzie', - 'Whitlee', - 'Sayde', - 'Willena', - 'Tzipporah', - 'Afsana', - 'Kearra', - 'Marialy', - 'Quiara', - 'Jing', - 'Dorathea', - 'Rachelann', - 'Melissaann', - 'Jeanett', - 'Jensine', - 'Jessicaann', - 'Ellesse', - 'Kaula', - 'Calley', - 'Malkie', - 'Shenelle', - 'Sheela', - 'Steffi', - 'Shadia', - 'Marielis', - 'Saima', - 'Tiarah', - 'Reginia', - 'Shaquala', - 'Shadiamond', - 'Kallista', - 'Allee', - 'Allexis', - 'Nakeya', - 'Reshma', - 'Sosha', - 'Kendrea', - 'Imalay', - 'Kyong', - 'Sharmin', - 'Sorah', - 'Alayshia', - 'Katja', - 'Chavie', - 'Farzana', - 'Lanasia', - 'Khayla', - 'Jamella', - 'Diva', - 'Ericca', - 'Brettany', - 'Imunique', - 'Tiasia', - 'Tajae', - 'Sidra', - 'Chelbi', - 'Kourtni', - 'Lamisha', - 'Krystyn', - 'Maly', - 'Mirtha', - 'Nary', - 'Nuria', - 'Falicia', - 'Zilpha', - 'Keyasia', - 'Ranisha', - 'Garnetta', - 'Alexxus', - 'Hae', - 'Herma', - 'Tasheena', - 'Philicia', - 'Fotini', - 'Avanell', - 'Czarina', - 'Kindle', - 'Antoinet', - 'Constanc', - 'Cassondr', - 'Destanee', - 'Christinia', - 'Shalisa', - 'Stepahnie', - 'Sopheap', - 'Somaly', - 'Shalane', - 'Saran', - 'Alaycia', - 'Carolynne', - 'Nikolette', - 'Saphire', - 'Dominigue', - 'Channa', - 'Leva', - 'Starquasia', - 'Shyan', - 'Sabah', - 'Shakiera', - 'Nagely', - 'Hajar', - 'Keniya', - 'Anhthu', - 'Ashle', - 'Taira', - 'Meline', - 'Rebeckah', - 'Daritza', - 'Kaysha', - 'Kathrin', - 'Edit', - 'Jennae', - 'Kaja', - 'Molli', - 'Hildreth', - 'Elyssia', - 'Keandrea', - 'Courtlyn', - 'Cova', - 'Kyndle', - 'Kadisha', - 'Mitchelle', - 'Chabeli', - 'Ashlen', - 'Feiga', - 'Shakena', - 'Lakeia', - 'Jehan', - 'Karianne', - 'Renisha', - 'Crystalyn', - 'Blia', - 'Amanada', - 'Neiba', - 'Oyuki', - 'Lianet', - 'Javaria', - 'Praise', - 'Sagal', - 'Avaleigh', - 'Amoni', - 'Fadumo', - 'Debhora', - 'Sharol', - 'Sahalie', - 'Aleana', - 'Dezire', - 'Catalia', - 'Barbarann', - 'Raelin', - 'Reniyah', - 'Jeniyah', - 'Jaziya', - 'Wilhemenia', - 'Wavie', - 'Modestine', - 'Tariah', - 'Cathern', - 'Asenath', - 'Nakya', - 'Reeva', - 'Tkai', - 'Orva', - 'Theora', - 'Brookie', - 'Breyonna', - 'Ellagrace', - 'Kaliya', - 'Jemimah', - 'Ahna', - 'Zetta', - 'Tanyia', - 'Dicie', - 'Malasia', - 'Janvi', - 'Talaysia', - 'Kaybree', - 'Teia', - 'Robertha', - 'Tilda', - 'Marykatherine', - 'Gusta', - 'Gola', - 'Malta', - 'Nija', - 'Kaija', - 'Tamaria', - 'Chyann', - 'Davianna', - 'Gae', - 'Ruther', - 'Kennadee', - 'Arvella', - 'Ashonti', - 'Euphemia', - 'Teyanna', - 'Jahnya', - 'Jamariya', - 'Ceanna', - 'Francenia', - 'Charletta', - 'Catheryn', - 'Theodosia', - 'Magdaline', - 'Samariah', - 'Jamara', - 'Nehemie', - 'Mikenzie', - 'Marielys', - 'Keilany', - 'Bernardita', - 'Marketa', - 'Takya', - 'Frona', - 'Draxie', - 'Genell', - 'Celesta', - 'Deloria', - 'Sister', - 'Icy', - 'Mardi', - 'Florance', - 'Azari', - 'Ahmiyah', - 'Chaniya', - 'Rheda', - 'Kateland', - 'Rielle', - 'Kjersten', - 'Olivette', - 'Tita', - 'Tharon', - 'Briasia', - 'Pakou', - 'Raniah', - 'Janaria', - 'Jaliya', - 'Alexiana', - 'Alayja', - 'Ailea', - 'Camiya', - 'Versa', - 'Vertell', - 'Loyola', - 'Mckelle', - 'Ebonique', - 'Jaynie', - 'Shamiah', - 'Keela', - 'Laterrica', - 'Fidelia', - 'Annia', - 'Rosslyn', - 'Robynn', - 'Darlynn', - 'Shakiara', - 'Shakeira', - 'Olinda', - 'Kionna', - 'Annslee', - 'Rudine', - 'Teonna', - 'Rudene', - 'Latrece', - 'Wynette', - 'Damiya', - 'Zonnie', - 'Jenne', - 'Deeanne', - 'Doree', - 'Jennilyn', - 'Lari', - 'Lourie', - 'Tedi', - 'Deaira', - 'Deairra', - 'Fatuma', - 'Gearldean', - 'Genise', - 'Karlyn', - 'Arleta', - 'Alla', - 'Donie', - 'Lady', - 'Rheba', - 'Nuha', - 'Olita', - 'Elzina', - 'Lutricia', - 'Tauna', - 'Teasha', - 'Elberta', - 'Jeralyn', - 'Shaketa', - 'Elonda', - 'Lafondra', - 'Shelle', - 'Lamiya', - 'Lejla', - 'Labria', - 'Wessie', - 'Cleola', - 'Suad', - 'Andretta', - 'Piccola', - 'Jadalee', - 'Louanna', - 'Donabelle', - 'Shauntel', - 'Vannie', - 'Naomia', - 'Ludell', - 'Ikram', - 'Ariyonna', - 'Anaelle', - 'Pamila', - 'Scheryl', - 'Kandee', - 'Donella', - 'Vicie', - 'Tajah', - 'Jodeen', - 'Debborah', - 'Varvara', - 'Jalisha', - 'Paw', - 'Tranette', - 'Ruwayda', - 'Jeanice', - 'Lowana', - 'Curlie', - 'Viveca', - 'Tommi', - 'Lynnel', - 'Shawneen', - 'Tora', - 'Ikhlas', - 'Delene', - 'Jillyn', - 'Abria', - 'Blondine', - 'Katharyn', - 'Gini', - 'Lynnell', - 'Laurey', - 'Ikran', - 'Madell', - 'Dura', - 'Trenia', - 'Arsie', - 'Runell', - 'Lawan', - 'Georgeanna', - 'Nashay', - 'Lasha', - 'Michi', - 'Arloa', - 'Kazuye', - 'Arnette', - 'Morghan', - 'Allure', - 'Kiyo', - 'Fusaye', - 'Sebrena', - 'Kikuye', - 'Mykia', - 'Soon', - 'Kyung', - 'Maysa', - 'Manessa', - 'Ople', - 'Amyre', - 'Katera', - 'Danaya', - 'Dorothey', - 'Shahidah', - 'Soliana', - 'Concettina', - 'Delphie', - 'Aqueelah', - 'Cassadee', - 'Larayne', - 'Burnette', - 'Diona', - 'Stasha', - 'Sheria', - 'Luciel', - 'Anise', - 'Cumi', - 'Marillyn', - 'Domenique', - 'Sumiye', - 'Masaye', - 'Imojean', - 'Louetta', - 'Taimi', - 'Berdie', - 'Jyl', - 'Cyrilla', - 'Kearstin', - 'Tosca', - 'Billee', - 'Milda', - 'Rema', - 'Tyne', - 'Altamease', - 'Aleaha', - 'Malaina', - 'Jersie', - 'Nadyne', - 'Suhailah', - 'Reghan', - 'Burma', - 'Kamyra', - 'Geraldean', - 'Ivalee', - 'Waunita', - 'Aritza', - 'Madalynne', - 'Talaya', - 'Azura', - 'Aldonia', - 'Robinette', - 'Ameenah', - 'Abeer', - 'Yamilette', - 'Tanae', - 'Mertha', - 'Jamirah', - 'Chun', - 'Avayah', - 'Janayah', - 'Bena', - 'Mahiyah', - 'Karn', - 'Kristien', - 'Mikesha', - 'Eriel', - 'Kemoni', - 'Aziya', - 'Raigan', - 'Rissie', - 'Tenna', - 'Tambria', - 'Birdell', - 'Almena', - 'Jonisha', - 'Marcey', - 'Rosebud', - 'Lakevia', - 'Shateria', - 'Nelia', - 'Rilda', - 'Doshie', - 'Onzell', - 'Safiyyah', - 'Lorilee', - 'Shiane', - 'Gauri', - 'Ashiya', - 'Yaileen', - 'Vendetta', - 'Margaretmary', - 'Telisa', - 'Imogean', - 'Sheryn', - 'Nance', - 'Mariette', - 'Keerthana', - 'Rosellen', - 'Michelene', - 'Kamrie', - 'Mayci', - 'Jerzi', - 'Vermelle', - 'Tondra', - 'Dorethea', - 'Wannetta', - 'Tilly', - 'Brightyn', - 'Patt', - 'Lynae', - 'Willo', - 'Cloma', - 'Yailyn', - 'Takeria', - 'Janyiah', - 'Rasheema', - 'Nafeesa', - 'Rosene', - 'Kellianne', - 'Taccara', - 'Quanda', - 'Patsie', - 'Chaquita', - 'Shakelia', - 'Guerline', - 'Tashika', - 'Taneesha', - 'Fatme', - 'Marliss', - 'Hye', - 'Marjo', - 'Meggie', - 'Maye', - 'Walline', - 'Dodi', - 'Kristyna', - 'Aliyyah', - 'Latravia', - 'Diania', - 'Elta', - 'Oralee', - 'Nikkita', - 'Rasha', - 'Sharena', - 'Tecora', - 'Pluma', - 'Ovell', - 'Keeya', - 'Dayja', - 'Sherrian', - 'Jinnie', - 'Ekta', - 'Javonda', - 'Shantrice', - 'Dava', - 'Kimbley', - 'Lafonda', - 'Lasonja', - 'Hiilani', - 'Danay', - 'Avree', - 'Kelliann', - 'Keasha', - 'Kimmarie', - 'Jannely', - 'Manasi', - 'Moncerat', - 'Miyu', - 'Jullianna', - 'Joelene', - 'Ynez', - 'Yazmeen', - 'Yasamin', - 'Syann', - 'Surena', - 'Tresia', - 'Trecia', - 'Sonjia', - 'Hokulani', - 'Amarilys', - 'Bethzaida', - 'Noraida', - 'Dietra', - 'Nealie', - 'Charice', - 'Alicea', - 'Jozie', - 'Delzora', - 'Jordis', - 'Jolett', - 'Kahlen', - 'Kallee', - 'Natilee', - 'Pecolia', - 'Iyari', - 'Shandrell', - 'Quintella', - 'Monchel', - 'Tysha', - 'Vanetta', - 'Shawneequa', - 'Odesser', - 'Lareina', - 'Jannifer', - 'Kinya', - 'Lateesha', - 'Dvora', - 'Katrin', - 'Denene', - 'Diondra', - 'Ciclali', - 'Sula', - 'Talena', - 'Afrika', - 'Cheron', - 'Emireth', - 'Cadee', - 'Jlyn', - 'Jermya', - 'Alyia', - 'Sitlali', - 'Sissy', - 'Felita', - 'Kerith', - 'Wendolyn', - 'Chaundra', - 'Angle', - 'Gladies', - 'Meygan', - 'Sereniti', - 'Saryn', - 'Vielka', - 'Tirzah', - 'Lynnmarie', - 'Lisanne', - 'Yliana', - 'Yamilett', - 'Keyoka', - 'Laquanta', - 'Teneshia', - 'Trenna', - 'Veronda', - 'Fronie', - 'Carlette', - 'Lanetta', - 'Raynelle', - 'Tianne', - 'Siria', - 'Mayda', - 'Lorien', - 'Celica', - 'Tabbitha', - 'Kayanna', - 'Julitza', - 'Kylia', - 'Heavenlee', - 'Nikka', - 'Rachana', - 'Mekenna', - 'Maritere', - 'Ai', - 'Angelisa', - 'Anysa', - 'Basia', - 'Ilka', - 'Geanine', - 'Kedra', - 'Caila', - 'Deysy', - 'Emilyann', - 'Samera', - 'Mackinzie', - 'Lynzie', - 'Akela', - 'Navpreet', - 'Reylene', - 'Reyanna', - 'Kathlynn', - 'Kiaira', - 'Guiselle', - 'Brinn', - 'Jerelyn', - 'Lorel', - 'Alandra', - 'Ardyth', - 'Kloee', - 'Mellody', - 'Carlisa', - 'Martinique', - 'Damali', - 'Cassandre', - 'Ivanelle', - 'Janaan', - 'Shontay', - 'Tamieka', - 'Tashema', - 'Irmalinda', - 'Tayna', - 'Berdena', - 'Janika', - 'Shauntay', - 'Nikea', - 'Ekaterini', - 'Glendaly', - 'Vernee', - 'Kang', - 'Candise', - 'Jamica', - 'Andera', - 'Katheleen', - 'Annagrace', - 'Bradleigh', - 'Kissy', - 'Lachandra', - 'Tamikia', - 'Shevon', - 'Wardean', - 'Betina', - 'Marcee', - 'Evia', - 'Carry', - 'Marica', - 'Tiwana', - 'Stacye', - 'Theressa', - 'Torsha', - 'Allayna', - 'Betania', - 'Berania', - 'Claryssa', - 'Clarise', - 'Cassidi', - 'Mehana', - 'Janella', - 'Mackenzy', - 'Kaeleigh', - 'Sanoe', - 'Neysa', - 'Shawntee', - 'Shannah', - 'Tihani', - 'Willye', - 'Zalma', - 'Serrina', - 'Shealyn', - 'Hiiaka', - 'Jeselle', - 'Mitsy', - 'Kela', - 'Aquila', - 'Marikay', - 'Christella', - 'Tameria', - 'Ebelina', - 'Maricar', - 'Shalimar', - 'Yanin', - 'Xuan', - 'Tifany', - 'Thy', - 'Quynh', - 'Shronda', - 'Kysha', - 'Lular', - 'Danee', - 'Christyna', - 'Antonieta', - 'Chara', - 'Bich', - 'Tishana', - 'Sophy', - 'Shoshanna', - 'Adrea', - 'Lavaun', - 'Keryn', - 'Okema', - 'Njeri', - 'Ashaki', - 'Alegra', - 'Anapatricia', - 'Terena', - 'Tuere', - 'Ensley', - 'Geraline', - 'Corrinna', - 'Carlye', - 'Dawnielle', - 'Fancy', - 'Akiba', - 'Korrie', - 'Lavita', - 'Chisa', - 'Lakishia', - 'Mandisa', - 'Lalita', - 'Sakeena', - 'Noami', - 'Olivea', - 'Lucilla', - 'Marialuiza', - 'Radonna', - 'Magaline', - 'Minda', - 'Annah', - 'Mitsuyo', - 'Kameko', - 'Miyako', - 'Satsuki', - 'Hatsuyo', - 'Aimie', - 'Jalexis', - 'Haruyo', - 'Tokiko', - 'Matsuyo', - 'Myiah', - 'Natalye', - 'Priseis', - 'Yeraldi', - 'Natsue', - 'Nobue', - 'Zyria', - 'Tierany', - 'Samyia', - 'Rhema', - 'Chiyo', - 'Lailoni', - 'Momoka', - 'Miku', - 'Havanna', - 'Izela', - 'Kendy', - 'Rashanda', - 'Aleysha', - 'Sherlita', - 'Tamana', - 'Kikuyo', - 'Tapanga', - 'Shauntell', - 'Adithi', - 'Chiamaka', - 'Devika', - 'Angy', - 'Arwyn', - 'Aparna', - 'Anneka', - 'Betzayra', - 'Analuiza', - 'Blondie', - 'October', - 'Yarexi', - 'Yarethzi', - 'Annaclaire', - 'Rosabel', - 'Jerlene', - 'Clelia', - 'Jatara', - 'Anzley', - 'Zamaya', - 'Venera', - 'Kalleigh', - 'Jaylynne', - 'Kaylor', - 'Milli', - 'Nelsy', - 'Laycee', - 'Arayah', - 'Betzabe', - 'Bethzi', - 'Haidy', - 'Chayla', - 'Elizah', - 'Evoleth', - 'Edyn', - 'Cyniah', - 'December', - 'Amerika', - 'Analea', - 'Ayshia', - 'Alauna', - 'Shamica', - 'Peaches', - 'Shenee', - 'Letecia', - 'Arminda', - 'Yolander', - 'Amariona', - 'Kaithlyn', - 'Jasiya', - 'Niharika', - 'Sareena', - 'Maryana', - 'Melanye', - 'Solei', - 'Suhey', - 'Soyla', - 'Koral', - 'Lilee', - 'Mercede', - 'Pennye', - 'Yumeka', - 'Mazel', - 'Vani', - 'Pattiann', - 'Shirell', - 'Carmencita', - 'Delayla', - 'Hailyn', - 'Brena', - 'Daana', - 'Lenise', - 'Ryhanna', - 'Lorely', - 'Tiannah', - 'Zabdi', - 'Kammy', - 'Josslynn', - 'Keilee', - 'Kamrynn', - 'Itza', - 'Jaidy', - 'Cherly', - 'Ladeana', - 'Memory', - 'Maresa', - 'Shauntae', - 'Risha', - 'Ilisa', - 'Debraann', - 'Gavriela', - 'Jenai', - 'Suzzette', - 'Mailani', - 'Leiloni', - 'Manasa', - 'Malin', - 'Faythe', - 'Haylei', - 'Haili', - 'Gwenivere', - 'Jamilette', - 'Naydeline', - 'Sakshi', - 'Nayda', - 'Nuala', - 'Chelsae', - 'Berenize', - 'Bahar', - 'Arpi', - 'Tearra', - 'Metta', - 'Lethia', - 'Akanksha', - 'Danine', - 'Alayne', - 'Jeanann', - 'Loyda', - 'Yamna', - 'Marsela', - 'Jolinda', - 'Leina', - 'Mariane', - 'Kaydince', - 'Etsuko', - 'Tinika', - 'Lashona', - 'Chidinma', - 'Jazell', - 'Derenda', - 'Cylinda', - 'Amaiah', - 'Alyzza', - 'Abbygayle', - 'Tashae', - 'Tesa', - 'Sarra', - 'Tanasha', - 'Latoy', - 'Dawnell', - 'Corinn', - 'Charmain', - 'Odetta', - 'Kimiya', - 'Kiaya', - 'Mairin', - 'Maelani', - 'Halena', - 'Dorianne', - 'Ilia', - 'Cheyenna', - 'Noora', - 'Nareh', - 'Namrata', - 'Sholanda', - 'Sita', - 'Dunia', - 'Betzayda', - 'Analissa', - 'Amulya', - 'Annaka', - 'Anneth', - 'Anaalicia', - 'Noemie', - 'Leni', - 'Robyne', - 'Skyleen', - 'Tiphanie', - 'Belmira', - 'Francelina', - 'Kreindy', - 'Kiri', - 'Kristena', - 'Lawren', - 'Christyn', - 'Deicy', - 'Hollyann', - 'Jamela', - 'Eriko', - 'Sotheary', - 'Lekeshia', - 'Onica', - 'Micole', - 'Marlisa', - 'Aqsa', - 'Bayla', - 'Abigal', - 'Charny', - 'Shaquira', - 'Rabab', - 'Yasemin', - 'Keishla', - 'Donasia', - 'Ellamarie', - 'Darianny', - 'Dahiana', - 'Areeba', - 'Shaquasha', - 'Oneisha', - 'Daicy', - 'Karem', - 'Kymberlee', - 'Kayleena', - 'Katryna', - 'Jessicamae', - 'Gessica', - 'Jameela', - 'Janele', - 'Naylani', - 'Anagabriela', - 'Andraya', - 'Andreanna', - 'Artavia', - 'Alexanderia', - 'Laporche', - 'Laporsche', - 'Folasade', - 'Kirandeep', - 'Davia', - 'Davona', - 'Darbi', - 'Baylea', - 'Sylwia', - 'Glendy', - 'Ivet', - 'Fritzi', - 'Lusero', - 'Marlayna', - 'Marlissa', - 'Leanny', - 'Duaa', - 'Ruchama', - 'Orli', - 'Nabeeha', - 'Maurissa', - 'Shevawn', - 'Shauni', - 'Shellby', - 'Sindi', - 'Taralyn', - 'Tanzania', - 'Sinthia', - 'Ondrea', - 'Nhu', - 'Narine', - 'Naly', - 'Yanett', - 'Temmy', - 'Manar', - 'Maimuna', - 'Arielys', - 'Dalya', - 'Allyse', - 'Mariateresa', - 'Mariade', - 'Lashea', - 'Kimberlyann', - 'Cyntia', - 'Cystal', - 'Elisse', - 'Tonimarie', - 'Nashalie', - 'Shatasia', - 'Teigan', - 'Muntaha', - 'Zlata', - 'Zehra', - 'Shaterra', - 'Leeya', - 'Keysi', - 'Christabel', - 'Alfrieda', - 'Mehgan', - 'Hyacinth', - 'Shley', - 'Caterin', - 'Darnesha', - 'Amaranta', - 'Jazzmen', - 'Kelia', - 'Kassy', - 'Grasiela', - 'Sheindy', - 'Yenty', - 'Tahani', - 'Umme', - 'Mayla', - 'Maryon', - 'Kiyanna', - 'Dezeray', - 'Macaela', - 'Nalley', - 'Mikeisha', - 'Sylvana', - 'Smantha', - 'Virdiana', - 'Afiya', - 'Chanise', - 'Glorimar', - 'Hui', - 'Hendel', - 'Junia', - 'Gioia', - 'Elene', - 'Dorothie', - 'Elynor', - 'Mercades', - 'Arfa', - 'Abiha', - 'Aayat', - 'Amarianna', - 'Raynisha', - 'Pahola', - 'Sarin', - 'Marixa', - 'Shavonna', - 'Tannya', - 'Tijera', - 'Girtha', - 'Tameko', - 'Caresse', - 'Bernyce', - 'Allisha', - 'Branda', - 'Jahmya', - 'Haleema', - 'Hodaya', - 'Samina', - 'Sheva', - 'Theadora', - 'Skylyn', - 'Razan', - 'Somalia', - 'Thalya', - 'Quadasia', - 'Yanil', - 'Arabia', - 'Edina', - 'Briyanna', - 'Verdia', - 'Sehar', - 'Naama', - 'Timberly', - 'Reann', - 'Narissa', - 'Maggy', - 'Marriah', - 'Joua', - 'Kellsie', - 'Kelcy', - 'Evonna', - 'Jacqueleen', - 'Xee', - 'Zaynah', - 'Janique', - 'Jailin', - 'Aniqa', - 'Melana', - 'Mariame', - 'Aundria', - 'Anacaren', - 'Anahid', - 'Jassmine', - 'Keoshia', - 'Keyera', - 'Delmi', - 'Briselda', - 'Carlisha', - 'Brittnei', - 'Clarrisa', - 'Dezerae', - 'Banessa', - 'Ariele', - 'Cherrell', - 'Daissy', - 'Cecila', - 'Jady', - 'Kristelle', - 'Kristinamarie', - 'Korinna', - 'Kortnee', - 'Jasimine', - 'Jahnay', - 'Farhana', - 'Shaliyah', - 'Nemesis', - 'Shakerria', - 'Phoua', - 'Carylon', - 'Ironesha', - 'Lariza', - 'Anesa', - 'Elantra', - 'Deandria', - 'Denecia', - 'Chelsia', - 'Teighlor', - 'Suzannah', - 'Zelene', - 'Zeena', - 'Catriona', - 'Tamarra', - 'Tannaz', - 'Titiana', - 'Briany', - 'Lyana', - 'Maytal', - 'Antanasia', - 'Kierston', - 'Dashia', - 'Ismenia', - 'Annessa', - 'Carolena', - 'Miasia', - 'Mikhaila', - 'Lamiracle', - 'Kassey', - 'Markeshia', - 'Hilarie', - 'Necha', - 'Ziara', - 'Jahniyah', - 'Safiyah', - 'Tanaisha', - 'Shamyra', - 'Laportia', - 'Shavy', - 'Viktoriya', - 'Khrystyne', - 'Kristyne', - 'Juanisha', - 'Jerrika', - 'Channelle', - 'Jacquiline', - 'Rakia', - 'Tamarah', - 'Sarha', - 'Mishelle', - 'Nastasha', - 'Acadia', - 'Brittiney', - 'Mickaela', - 'Natavia', - 'Seryna', - 'Ardene', - 'Special', - 'Simranjit', - 'Marivi', - 'Natassja', - 'Neira', - 'Nikkie', - 'Asiana', - 'Dazhane', - 'Channell', - 'Adryana', - 'Mariluz', - 'Dajia', - 'Breigh', - 'Zelpha', - 'Lataya', - 'Glenny', - 'Sharene', - 'Shaguana', - 'Henrine', - 'Camesha', - 'Birdia', - 'Dynisha', - 'Sherina', - 'Ayde', - 'Danille', - 'Charday', - 'Almadelia', - 'Larena', - 'Charlestine', - 'Suellyn', - 'Marry', - 'Constantina', - 'Tandi', - 'Lacretia', - 'Noralba', - 'Latresha', - 'Latacha', - 'Talynn', - 'Rox', - 'Chasey', - 'Nyia', - 'Alyissa', - 'Karilyn', - 'Shevonne', - 'Genny', - 'Tamicka', - 'Doneisha', - 'Cyrena', - 'Daisia', - 'Ravina', - 'Berdia', - 'Aneesha', - 'Vashti', - 'Latrica', - 'Kennetha', - 'Aarti', - 'Raiza', - 'Elspeth', - 'Kyleen', - 'Ronika', - 'Lyndsy', - 'Jone', - 'Chanta', - 'Serita', - 'Margree', - 'Ruthel', - 'Ruthella', - 'Breunna', - 'Cyann', - 'Atlanta', - 'Danniela', - 'Junita', - 'Floella', - 'Brittane', - 'Avanelle', - 'Priscill', - 'Luvina', - 'Jeneva', - 'Teretha', - 'Clarita', - 'Ilce', - 'Jacqualyn', - 'Justene', - 'Daysia', - 'Taylore', - 'Sadi', - 'Verenis', - 'Shyenne', - 'Toriana', - 'Alvira', - 'Kalah', - 'Rajanee', - 'Reonna', - 'Mariadelaluz', - 'Mychaela', - 'Charnele', - 'Aeisha', - 'Shaquaya', - 'Shaakira', - 'Tayana', - 'Cozetta', - 'Kensey', - 'Jazsmin', - 'Kaitlyne', - 'Hollye', - 'Lavren', - 'Sarit', - 'Shanieka', - 'Margorie', - 'Virgene', - 'Dannia', - 'Clorissa', - 'Breahna', - 'Rayla', - 'Dellanira', - 'Megen', - 'Matalie', - 'Taraneh', - 'Teila', - 'Etter', - 'Cheetara', - 'Shetara', - 'Jamielee', - 'Kariann', - 'Karess', - 'Bea', - 'Leyda', - 'Misa', - 'Mareena', - 'Maisee', - 'Yvonna', - 'Yocelyne', - 'Yilda', - 'Sabrinna', - 'Sirenia', - 'Tyriel', - 'Darrielle', - 'Siedah', - 'Yuko', - 'Stevee', - 'Chrystle', - 'Shaterrica', - 'Janyll', - 'Evelisse', - 'Belkis', - 'Renesmae', - 'Sahily', - 'Zurie', - 'Edelia', - 'Sequoya', - 'Waldine', - 'Marinell', - 'Moya', - 'Lavenia', - 'Liboria', - 'Meliah', - 'Meliyah', - 'Mio', - 'Xitllali', - 'Nare', - 'Oliviah', - 'Mayrani', - 'Sravya', - 'Valeska', - 'Riona', - 'Lashaundra', - 'Phebe', - 'Yeira', - 'Zarai', - 'Ayanah', - 'Kriti', - 'Kaileah', - 'Donata', - 'Jenavee', - 'Daphnee', - 'Gurneet', - 'Emmalie', - 'Rowrenia', - 'Haisley', - 'Harbor', - 'Arilyn', - 'Aubrii', - 'Avielle', - 'Avyn', - 'Bethenny', - 'Arienne', - 'Anyeli', - 'Brilyn', - 'Cataleyah', - 'Chisom', - 'Dalis', - 'Malaiya', - 'Meela', - 'Karsynn', - 'Kaselyn', - 'Kashlyn', - 'Amorette', - 'Lenita', - 'Adabelle', - 'Allisyn', - 'Alyzah', - 'Aaralynn', - 'Avyanna', - 'Aylinn', - 'Bexley', - 'Blakeleigh', - 'Caeli', - 'Chizaram', - 'Avriana', - 'Clarity', - 'Juanelle', - 'Jerelene', - 'Eluteria', - 'Lamerle', - 'Aletheia', - 'Abrie', - 'Adelie', - 'Elleigh', - 'Emmelyn', - 'Emsley', - 'Everlynn', - 'Galileah', - 'Derrica', - 'Keondria', - 'Keneshia', - 'Amberley', - 'Valkyrie', - 'Yazleemar', - 'Maybree', - 'Shloka', - 'Neah', - 'Oluwatomisin', - 'Saydi', - 'Jessalynn', - 'Katalaya', - 'Katniss', - 'Kendalynn', - 'Davionna', - 'Mercie', - 'Danett', - 'Deetya', - 'Dilynn', - 'Dunya', - 'Camyla', - 'Elliotte', - 'Ivee', - 'Jadie', - 'Kyleah', - 'Laelani', - 'Mileah', - 'Nalanie', - 'Nixie', - 'Oviya', - 'Lakecia', - 'Sharnae', - 'Abbagail', - 'Derica', - 'Truly', - 'Tvisha', - 'Vedika', - 'Xiclaly', - 'Syra', - 'Idamae', - 'Dashanti', - 'Neita', - 'Siona', - 'Jourdyn', - 'Analyn', - 'Shamiracle', - 'Daylene', - 'Kadeesha', - 'Malgorzata', - 'Dashay', - 'Else', - 'Pixie', - 'Myleah', - 'Myleen', - 'Nadiah', - 'Sadhana', - 'Samai', - 'Seraphine', - 'Sereen', - 'Sharanya', - 'Simar', - 'Mahlia', - 'Inika', - 'Jennavieve', - 'Genevy', - 'Harshita', - 'Hennessey', - 'Zari', - 'Jamiracle', - 'Loveta', - 'Coleta', - 'Adabella', - 'Alesana', - 'Brinleigh', - 'Azlyn', - 'Braelee', - 'Shaquila', - 'Shanyia', - 'Jamilia', - 'Corlis', - 'Dulcie', - 'Desha', - 'Timya', - 'Rakiya', - 'Tyliah', - 'Taura', - 'Terasha', - 'Gaynel', - 'Roylene', - 'Janecia', - 'Alonda', - 'Tyneisha', - 'Fleurette', - 'Mayleigh', - 'Meklit', - 'Sarenity', - 'Gulianna', - 'Itzayanna', - 'Ivyana', - 'Jazmynn', - 'Esmie', - 'Favor', - 'Kimbella', - 'Shanavia', - 'Yaritzel', - 'Daun', - 'Tykerria', - 'Antoria', - 'Shykemmia', - 'Remona', - 'Lucrezia', - 'Cicily', - 'Aradhya', - 'Esmae', - 'Evah', - 'Jhene', - 'Katalia', - 'Cyrine', - 'Delayza', - 'Eleonor', - 'Arohi', - 'Aseneth', - 'Avarose', - 'Caia', - 'Hulene', - 'Valera', - 'Nasaria', - 'Makesha', - 'Zera', - 'Aahna', - 'Aariyah', - 'Aashvi', - 'Adalene', - 'Annaliyah', - 'Aira', - 'Alaska', - 'Amila', - 'Amour', - 'Kaylinn', - 'Isidora', - 'Marija', - 'Suha', - 'Marigold', - 'Mayzie', - 'Liesel', - 'Darielle', - 'Sapphira', - 'Scotland', - 'Serah', - 'Srinika', - 'Novah', - 'Primrose', - 'Latresa', - 'Theia', - 'Alleen', - 'Agness', - 'Estanislada', - 'Ellouise', - 'Emilija', - 'Glynnis', - 'Paulene', - 'Wilna', - 'Maedell', - 'Lometa', - 'Cressie', - 'Allyne', - 'Calleen', - 'Joaquina', - 'Lashelle', - 'Modene', - 'Jonie', - 'Minta', - 'Milady', - 'Jearlene', - 'Rithika', - 'Simrat', - 'Vonzella', - 'Venna', - 'Pabla', - 'Benilde', - 'Eniya', - 'Shakendra', - 'Ailen', - 'Aina', - 'Marionna', - 'Millette', - 'Emiyah', - 'Kayloni', - 'Keerat', - 'Keeva', - 'Lailany', - 'Mishka', - 'Naevia', - 'Nathania', - 'Nyari', - 'Jayah', - 'Kaavya', - 'Frankee', - 'Anahita', - 'Anella', - 'Elizabella', - 'Damara', - 'Juaquina', - 'Gracia', - 'Rozalyn', - 'Ruhani', - 'Novalie', - 'Mialani', - 'Minka', - 'Nessa', - 'Sissi', - 'Sitara', - 'Jaynee', - 'Jeyla', - 'Gizzelle', - 'Maila', - 'Maizy', - 'Lamaya', - 'Katalea', - 'Khamila', - 'Shekita', - 'Chinita', - 'Anshika', - 'Aerabella', - 'Azelia', - 'Cici', - 'Daleyssa', - 'Divinity', - 'Fermina', - 'Murline', - 'Mattye', - 'Devra', - 'Jakya', - 'Santresa', - 'Larene', - 'Deola', - 'Liliann', - 'Lexxi', - 'Kamori', - 'Myonna', - 'Yitzel', - 'Lindalee', - 'Tira', - 'Mairyn', - 'Riyana', - 'Shaleen', - 'Rhyleigh', - 'Fleeta', - 'Gabrielly', - 'Deajah', - 'Yarielis', - 'Arelie', - 'Amore', - 'Sacoria', - 'Hedda', - 'Wanza', - 'Janyth', - 'Yaslin', - 'Brianah', - 'Anyelin', - 'Shayleigh', - 'Lace', - 'Kurstin', - 'Zakhia', - 'Charvi', - 'Raylie', - 'Nyellie', - 'Natalyn', - 'Libra', - 'Khianna', - 'Jolena', - 'Genevive', - 'Jadine', - 'Deniya', - 'Madysin', - 'Porchia', - 'Layleen', - 'Kemiya', - 'Donesha', - 'Jewelene', - 'Sakari', - 'Narely', - 'Maylyn', - 'Halina', - 'Nelli', - 'Myangel', - 'British', - 'Adore', - 'Alainah', - 'Shadonna', - 'Aminta', - 'Marolyn', - 'Jalea', - 'Breelynn', - 'Carah', - 'Sagrario', - 'Akyra', - 'Kailei', - 'Kenza', - 'Renette', - 'Joanann', - 'Solimar', - 'Semira', - 'Harneet', - 'Jahayra', - 'Evanny', - 'Gyzelle', - 'Nathalee', - 'Dalphine', - 'Mane', - 'Merelyn', - 'Kayliana', - 'Aubryn', - 'Brooklyne', - 'Kimari', - 'Dandra', - 'Cilia', - 'Laren', - 'Denetra', - 'Kandise', - 'Makynli', - 'Janan', - 'Rosalea', - 'Ludean', - 'Syndey', - 'Shaney', - 'Vannary', - 'Reynalda', - 'Rainee', - 'Trishia', - 'Kirbie', - 'Kristyl', - 'Lynzi', - 'Shardai', - 'Yaricza', - 'Tarina', - 'Lynley', - 'Maniah', - 'Arcilia', - 'Keaundra', - 'Karrigan', - 'Madeliene', - 'Lessley', - 'Laurynn', - 'Ragen', - 'Essance', - 'Celsey', - 'Caitlen', - 'Dulse', - 'Sulamita', - 'Evlyn', - 'Dorace', - 'Marciana', - 'Tenecia', - 'Natarsha', - 'Analiza', - 'Ladene', - 'Tatumn', - 'Maricsa', - 'Lysa', - 'Leydi', - 'Limayri', - 'Rebbeca', - 'Amreen', - 'Saina', - 'Remedy', - 'Rael', - 'Nami', - 'Nalini', - 'Naiyah', - 'Moxie', - 'Olina', - 'Whitni', - 'Dayannara', - 'Diara', - 'Arma', - 'Giorgia', - 'Evee', - 'Bricia', - 'Brizeyda', - 'Chihiro', - 'Ayram', - 'Ayushi', - 'Isolde', - 'Husna', - 'Khrystal', - 'Kriston', - 'Raylena', - 'Porschea', - 'Samanthia', - 'Mylinda', - 'Ginelle', - 'Coreena', - 'Aryel', - 'Mallary', - 'Maciel', - 'Kursten', - 'Leandrea', - 'Mackensie', - 'Camri', - 'Itzamara', - 'Aryiah', - 'Alayssa', - 'Andreah', - 'Anberlin', - 'Amrie', - 'Breah', - 'Ryane', - 'Tonna', - 'Valisa', - 'Adryanna', - 'Ajia', - 'Robynne', - 'Brystal', - 'Brylynn', - 'Kaleigha', - 'Danyka', - 'Dannica', - 'Caylen', - 'Jonier', - 'Ruthy', - 'Mada', - 'Vaida', - 'Yeila', - 'Zoelle', - 'Elzora', - 'Samreen', - 'Seylah', - 'Sayla', - 'Allina', - 'Stellarose', - 'Starlett', - 'Simrit', - 'Shina', - 'Bernestine', - 'Tranisha', - 'Tiffanyann', - 'Adamarys', - 'Tylyn', - 'Shahrzad', - 'Addisson', - 'Aeriana', - 'Alaiya', - 'Anni', - 'Ariely', - 'Anvika', - 'Aneya', - 'Bani', - 'Ayame', - 'Ayaka', - 'Aviella', - 'Alabama', - 'Adalyne', - 'Teresea', - 'Ishana', - 'Hargun', - 'Jasnoor', - 'Deby', - 'Dannelle', - 'Swetha', - 'Catherina', - 'Bridgitt', - 'Birgit', - 'Calisi', - 'Defne', - 'Delsa', - 'Demiyah', - 'Cataleah', - 'Icel', - 'Ixel', - 'Jazman', - 'Jessicamarie', - 'Desaree', - 'Chika', - 'Estephani', - 'Dilcia', - 'Dartha', - 'Lesieli', - 'Breyona', - 'Waynette', - 'Verma', - 'Calletana', - 'Cherisa', - 'Casara', - 'Jil', - 'Shella', - 'Renell', - 'Venise', - 'Loura', - 'Kaylia', - 'Leileen', - 'Jessel', - 'Janesa', - 'Kaelly', - 'Julina', - 'Joselinne', - 'Juna', - 'Hazelle', - 'Mauricia', - 'Octaviana', - 'Rumalda', - 'Kataleyah', - 'Kimela', - 'Mosella', - 'Delone', - 'Shemekia', - 'Balinda', - 'Hazell', - 'Deboraha', - 'Gizell', - 'Camilia', - 'Avalina', - 'Audreyana', - 'Baran', - 'Genesee', - 'Elyzabeth', - 'Eliya', - 'Kathyleen', - 'Deeksha', - 'Scherry', - 'Angelyne', - 'Amiliana', - 'Amaira', - 'Jeani', - 'Alysen', - 'Alania', - 'Adiana', - 'Chinyere', - 'Lamesha', - 'Keiley', - 'Lanea', - 'Rosely', - 'Surabhi', - 'Dyanne', - 'Mallika', - 'Tabbatha', - 'Shilpa', - 'Morgyn', - 'Narali', - 'Jenevie', - 'Lovette', - 'Nayleah', - 'Navi', - 'Meili', - 'Nazly', - 'Nethra', - 'Earlee', - 'Layloni', - 'Kiannah', - 'Lilyanah', - 'Liannah', - 'Jaylenn', - 'Jiayi', - 'Kattleya', - 'Kanna', - 'Jimin', - 'Kaleesi', - 'Kailia', - 'Itzy', - 'Itzela', - 'Jasminemarie', - 'Malynda', - 'Jeweline', - 'Eloiza', - 'Carolin', - 'Helma', - 'Arlyle', - 'Giannina', - 'Constancia', - 'Elyce', - 'Montoya', - 'Marline', - 'Krystale', - 'Maghan', - 'Laquitta', - 'Elishia', - 'Aliciana', - 'Maralee', - 'Brunetta', - 'Cybil', - 'Dannell', - 'Cherene', - 'Agueda', - 'Guillerma', - 'Haillie', - 'Bobbe', - 'Gesselle', - 'Esthefany', - 'Sian', - 'Ouita', - 'Sasheen', - 'Abigaile', - 'Demarie', - 'Edwena', - 'Aamiyah', - 'Breaunna', - 'Bryssa', - 'Catlyn', - 'Xaviera', - 'Sierria', - 'Skyelar', - 'Aujanae', - 'Rika', - 'Roshelle', - 'Roxsana', - 'Zonia', - 'Tifanie', - 'Thavy', - 'Teala', - 'Tanea', - 'Loukisha', - 'Melita', - 'Keiona', - 'Maryfer', - 'Delcenia', - 'Akila', - 'Gwenevere', - 'Obdulia', - 'Texana', - 'Licette', - 'Larina', - 'Lany', - 'Yailine', - 'Yomara', - 'Zavia', - 'Sydne', - 'Mariadelourdes', - 'Margeaux', - 'Daneille', - 'Doni', - 'Donalee', - 'Darilyn', - 'Jennfier', - 'Jeanny', - 'Haliegh', - 'Dymon', - 'Callee', - 'Cydni', - 'Daesha', - 'Tamila', - 'Tresha', - 'Mckennah', - 'Shouana', - 'Xcaret', - 'Yeneisy', - 'Yumalai', - 'Ziana', - 'Hanny', - 'Shanisha', - 'Nissi', - 'Mirabel', - 'Miarose', - 'Valerya', - 'Rosalin', - 'Saliha', - 'Samayah', - 'Smriti', - 'Jozette', - 'Gari', - 'Jeanell', - 'Dyann', - 'Vonna', - 'Velina', - 'Salli', - 'Nonie', - 'Olena', - 'Camela', - 'Eufracia', - 'Ethelyne', - 'Yuhan', - 'Silveria', - 'Silvestra', - 'Thressa', - 'Tiahna', - 'Vasti', - 'Calee', - 'Florentine', - 'Sherre', - 'Almira', - 'Zitlalli', - 'Vianne', - 'Yaribeth', - 'Yarelie', - 'Robbye', - 'Jasminne', - 'Sophiah', - 'Saryah', - 'Hermalinda', - 'Sinclaire', - 'Korissa', - 'Lanee', - 'Keeana', - 'Parlee', - 'Luceal', - 'Jetta', - 'Mairani', - 'Tameisha', - 'Haruna', - 'Chasiti', - 'Leighanne', - 'Anaisabel', - 'Aanchal', - 'Alesa', - 'Annisa', - 'Brigitta', - 'Elideth', - 'Chua', - 'Cherrish', - 'Aleece', - 'Maizee', - 'Navie', - 'Philomene', - 'Jilian', - 'Jesi', - 'Kortnie', - 'Beija', - 'Delissa', - 'Shiree', - 'Silbia', - 'Tamura', - 'Aerianna', - 'Abegail', - 'Braniya', - 'Calyn', - 'Carlynn', - 'Anjana', - 'Angelik', - 'Alyzabeth', - 'Amorie', - 'Joannamarie', - 'Kerissa', - 'Kennesha', - 'Laruen', - 'Korrina', - 'Felisitas', - 'Gilma', - 'Essica', - 'Gerarda', - 'Petronila', - 'Dorotea', - 'Maguadalupe', - 'Najla', - 'Loana', - 'Illyana', - 'Amunique', - 'Antwanette', - 'Krystan', - 'Shaniquia', - 'Shanequia', - 'Rainy', - 'Raynesha', - 'Shayleen', - 'Stephanee', - 'Sharaya', - 'Nikkole', - 'Cecille', - 'Christyne', - 'Auriel', - 'Franki', - 'Zelina', - 'Deshanae', - 'Deshawna', - 'Tyneshia', - 'Tyrisha', - 'Deangela', - 'Dynasia', - 'Maigan', - 'Jericka', - 'Jackalyn', - 'Kayln', - 'Ceslie', - 'Bethaney', - 'Samanvi', - 'Saidee', - 'Rosibel', - 'Spirit', - 'Srishti', - 'Varnika', - 'Vanshika', - 'Rosha', - 'Rheya', - 'Yoyo', - 'Veyda', - 'Weslyn', - 'Palak', - 'Sieanna', - 'Riannah', - 'Lovetta', - 'Lota', - 'Florice', - 'Hortence', - 'Zuley', - 'Zoejane', - 'Zemira', - 'Mineola', - 'Senona', - 'Concepsion', - 'Conrada', - 'Dardanella', - 'Rhina', - 'Rubicela', - 'Raissa', - 'Porchea', - 'Latiana', - 'Landy', - 'Monee', - 'Maritssa', - 'Marjani', - 'Meosha', - 'Cecilie', - 'Britanie', - 'Brandilyn', - 'Khrystina', - 'Atenas', - 'Kristeena', - 'Kristell', - 'Kristianne', - 'Angelicia', - 'Alexandera', - 'Jaimy', - 'Jeneffer', - 'Hayde', - 'Vickye', - 'Suzzanne', - 'Susi', - 'Sherrilyn', - 'Sanda', - 'Janeal', - 'Stephnie', - 'Luwana', - 'Shenae', - 'Yaris', - 'Marzell', - 'Lashane', - 'Liandra', - 'Keionna', - 'Korri', - 'Marlet', - 'Marytza', - 'Lorraina', - 'Deepika', - 'Devi', - 'Fion', - 'Darrah', - 'Dalisha', - 'Karessa', - 'Karrisa', - 'Kasara', - 'Ismar', - 'Jacquilyn', - 'Janica', - 'Jeannett', - 'Samanatha', - 'Samra', - 'Sayda', - 'Breklyn', - 'Ashika', - 'Bita', - 'Allysha', - 'Areil', - 'Arlenne', - 'Artelia', - 'Janicia', - 'Corinthia', - 'Angellica', - 'Maygen', - 'Maygan', - 'Odelle', - 'Wenonah', - 'Perfecta', - 'Anjelika', - 'Solmaira', - 'Fredonia', - 'Burgandy', - 'Chelcee', - 'Kellsey', - 'Lyann', - 'Jazmon', - 'Ardie', - 'Latunya', - 'Benetta', - 'Delphina', - 'Ortensia', - 'Obelia', - 'Lurene', - 'Refujia', - 'Noriko', - 'Ladelle', - 'Lella', - 'Shanie', - 'Shawndra', - 'Zell', - 'Zela', - 'Wenda', - 'Troylene', - 'Merrilyn', - 'Kapri', - 'Timesha', - 'Gwendlyn', - 'Jenean', - 'Lamona', - 'Ladana', - 'Cina', - 'Cybele', - 'Eugina', - 'Anjeanette', - 'Vana', - 'Jeneal', - 'Cherlene', - 'Railee', - 'Palin', - 'Yuliet', - 'Rechelle', - 'Sherisse', - 'Pollyanna', - 'Tiphani', - 'Tiffanee', - 'Vanisha', - 'Yurico', - 'Junko', - 'Shannell', - 'Shalise', - 'Kimberlina', - 'Kerra', - 'Shantee', - 'Emmelia', - 'Micala', - 'Lexxus', - 'Candiss', - 'Chauntel', - 'Alese', - 'Margit', - 'Any', - 'Ambur', - 'Chrysta', - 'Janese', - 'Jinny', - 'Zaydee', - 'Makisha', - 'Carola', - 'Marjan', - 'Samanth', - 'Shaquinta', - 'Polette', - 'Riane', - 'Nitasha', - 'Kasarah', - 'Jillianne', - 'Keidra', - 'Karrah', - 'Kaytie', - 'Sondi', - 'Swayzie', - 'Laporcha', - 'Bridgit', - 'Chanika', - 'Antoniette', - 'Jessicia', - 'Francies', - 'Kaizley', - 'Negin', - 'Mistica', - 'Lorenia', - 'Kalise', - 'Kynslie', - 'Dene', - 'Jizel', - 'Jinger', - 'Jayli', - 'Jariya', - 'Joelynn', - 'Haylin', - 'Isabellah', - 'Ciria', - 'Dealva', - 'Barbarita', - 'Prudencia', - 'Wanna', - 'Marieli', - 'Madisynn', - 'Madalyne', - 'Artisha', - 'Everlyn', - 'Cyerra', - 'Liezl', - 'Kabao', - 'Karmina', - 'Kashmir', - 'Nani', - 'Mithra', - 'Mishika', - 'Milynn', - 'Mehr', - 'Marybella', - 'Maisey', - 'Maddy', - 'Lyah', - 'Marnee', - 'Machele', - 'Ladona', - 'Lorilei', - 'Liara', - 'Alahni', - 'Analaya', - 'Amalya', - 'Alyannah', - 'Aayla', - 'Aarini', - 'Arliz', - 'Cyra', - 'Asenet', - 'Avy', - 'Avaree', - 'Ciela', - 'Evangelyn', - 'Kaidynce', - 'Isella', - 'Ilaria', - 'Kattaleya', - 'Laveah', - 'Lareen', - 'Lanah', - 'Deema', - 'Hannaley', - 'Fiora', - 'Eviana', - 'Ellieana', - 'Elisabetta', - 'Dejanira', - 'Manaia', - 'Malibu', - 'Charlsey', - 'Kaytee', - 'Kinberly', - 'Cinderella', - 'Miana', - 'Kimm', - 'Koni', - 'Eraina', - 'Dory', - 'Deette', - 'Nysa', - 'Nyima', - 'Nikitha', - 'Anasophia', - 'Alissandra', - 'Alisi', - 'Corynn', - 'Aubreyana', - 'Anjani', - 'Oliana', - 'Nura', - 'Nihira', - 'Loveda', - 'Gayathri', - 'Kleigh', - 'Ladaisha', - 'Ilette', - 'Jillene', - 'Jalina', - 'Izellah', - 'Tiaira', - 'Mickala', - 'Macarena', - 'Rubina', - 'Shadow', - 'Emillie', - 'Morine', - 'Novell', - 'Oletta', - 'Pura', - 'Winna', - 'Synia', - 'Shyloh', - 'Kaizlee', - 'Raley', - 'Merly', - 'Na', - 'Yenia', - 'Shayanne', - 'Raeana', - 'Tiauna', - 'Tanairy', - 'Georganna', - 'Mahsa', - 'Maiquel', - 'Korena', - 'Yamel', - 'Shamonica', - 'Romesha', - 'Terrisha', - 'Hannan', - 'Hillarie', - 'Feliza', - 'Courtny', - 'Lyndsee', - 'Katelan', - 'Lakedra', - 'Elisabel', - 'Cynthya', - 'Dannah', - 'Darienne', - 'Dejanique', - 'Madalin', - 'Makynzi', - 'Gwendolynn', - 'Alaine', - 'Bridney', - 'Kimorah', - 'Klee', - 'Kynedi', - 'Loreley', - 'Parthenia', - 'Aubryana', - 'Aryannah', - 'Edeline', - 'Elen', - 'Raguel', - 'Marizela', - 'Michella', - 'Haasini', - 'Tristine', - 'Elis', - 'Pattye', - 'Tanishia', - 'Jenel', - 'Jurea', - 'Laini', - 'Britania', - 'Christabelle', - 'Dafney', - 'Laterica', - 'Angelmarie', - 'Asuzena', - 'Aleea', - 'Teneka', - 'Yicel', - 'Malisha', - 'Prairie', - 'Makelle', - 'Shaelee', - 'Dafina', - 'Hisaye', - 'Adayah', - 'Alexsia', - 'Allysen', - 'Takako', - 'Thamara', - 'Trinitie', - 'Shaneen', - 'Sueellen', - 'Telma', - 'Meyah', - 'Rorie', - 'Preslea', - 'Elbia', - 'Ginna', - 'Marja', - 'Marites', - 'Neisha', - 'Shir', - 'Shastelyn', - 'Saraih', - 'Unity', - 'Makinna', - 'Franchelle', - 'Azadeh', - 'Charito', - 'Joli', - 'Amyrah', - 'Sharlee', - 'Jasey', - 'Kortlynn', - 'Kiari', - 'Kyria', - 'Eleina', - 'Elany', - 'Daleah', - 'Sumi', - 'Kileigh', - 'Lorianna', - 'Macady', - 'Naviah', - 'Mattilyn', - 'Raylyn', - 'Bridgitte', - 'Hasina', - 'Johnelle', - 'Gwendlyon', - 'Itxel', - 'Iyanah', - 'Jeidy', - 'Jaidynn', - 'Jaslynne', - 'Zoii', - 'Tensley', - 'Yolando', - 'Keyarah', - 'Keyri', - 'Katherinne', - 'Thersa', - 'Sinahi', - 'Secret', - 'Vivika', - 'Yobana', - 'Hailley', - 'Haliey', - 'Isys', - 'Deyla', - 'Kassidee', - 'Jalie', - 'Florestela', - 'Cyla', - 'Samyuktha', - 'Libni', - 'Laritza', - 'Breannah', - 'Breya', - 'Keelin', - 'Jarelly', - 'Jenyfer', - 'Julyanna', - 'Kaetlyn', - 'Mixtli', - 'Mykaila', - 'Nasia', - 'Judieth', - 'Misako', - 'Bre', - 'Shaley', - 'Gelila', - 'Aariana', - 'Laquetta', - 'Shizu', - 'Annay', - 'Annai', - 'Breeze', - 'Mahum', - 'Harsimran', - 'Helaina', - 'Alexza', - 'Tangelia', - 'Shellye', - 'Blondena', - 'Keva', - 'Suzzane', - 'Vallorie', - 'Absidy', - 'Alis', - 'Alexxia', - 'Allura', - 'Ariba', - 'Annete', - 'Anett', - 'Deyanara', - 'Ellise', - 'Majorie', - 'Hibah', - 'Chaselyn', - 'Hennesy', - 'Gayatri', - 'Kathelyn', - 'Caylah', - 'Athyna', - 'Arpita', - 'Ciclaly', - 'Emmamarie', - 'Virjinia', - 'Tyna', - 'Cyd', - 'Glennda', - 'Littie', - 'Orlean', - 'Derinda', - 'Hether', - 'Clata', - 'Pleshette', - 'Maricelda', - 'Charmin', - 'Matsuye', - 'Tamitha', - 'Armanda', - 'Sayaka', - 'Lacresia', - 'Demonica', - 'Skie', - 'Trynity', - 'Sereena', - 'Shefali', - 'Rewa', - 'Reshonda', - 'Yalanda', - 'Anissia', - 'Layni', - 'Paolina', - 'Manaal', - 'Mariali', - 'Merina', - 'Milenia', - 'Millenia', - 'Moncerrath', - 'Monzerrath', - 'Kaydie', - 'Adianna', - 'Toluwalase', - 'Trysta', - 'Ainsleigh', - 'Alianah', - 'Meuy', - 'Meloney', - 'Talea', - 'Sheetal', - 'Shalana', - 'Venesa', - 'Teana', - 'Kiki', - 'Imee', - 'Aubryanna', - 'Allyanna', - 'Ambrie', - 'Amory', - 'Aniyha', - 'Caelynn', - 'Reita', - 'Rylann', - 'Aijah', - 'Aaliyha', - 'Alezandra', - 'Yeraldine', - 'Forestine', - 'Sameeha', - 'Caeley', - 'Britzy', - 'Blessin', - 'Armilda', - 'Birda', - 'Lorrine', - 'Krisalyn', - 'Linell', - 'Maryl', - 'Karole', - 'Maryela', - 'Mckinzy', - 'Madailein', - 'Kendi', - 'Kayda', - 'Jenasis', - 'Madelis', - 'Jamyiah', - 'Gabryela', - 'Catie', - 'Genessa', - 'Jamelia', - 'Jenene', - 'Nicholl', - 'Saralyn', - 'Taylah', - 'Xandra', - 'Jezlyn', - 'Zakayla', - 'Jaira', - 'Veena', - 'Shaden', - 'Sahiti', - 'Sahian', - 'Shelsey', - 'Sreya', - 'Zianna', - 'Angeleah', - 'Camily', - 'Lesvia', - 'Sonda', - 'Franceska', - 'Cytlaly', - 'Ylonda', - 'Issis', - 'Moon', - 'Joei', - 'Mariposa', - 'Ramandeep', - 'Preeti', - 'Niobe', - 'Sherran', - 'Nichola', - 'Letrice', - 'Waneda', - 'Meka', - 'Takeshia', - 'Leaann', - 'Girlie', - 'Olar', - 'Pearlena', - 'Carlean', - 'Dhanya', - 'Chastelin', - 'Aryanah', - 'Brihana', - 'Bijou', - 'Haifa', - 'Genesiss', - 'Genavie', - 'Enna', - 'Jazzel', - 'Japleen', - 'Iana', - 'Rahel', - 'Rylyn', - 'Pragya', - 'Yosselyn', - 'Yarelin', - 'Ellasyn', - 'Charlaine', - 'Zayli', - 'Taide', - 'Jodean', - 'Emilynn', - 'Channon', - 'Carinne', - 'Anaira', - 'Amisadai', - 'Caraline', - 'Danella', - 'Debanhy', - 'Devanee', - 'Koneta', - 'Jenie', - 'Hollee', - 'Marelie', - 'Mahathi', - 'Madilynne', - 'Lylia', - 'Loreli', - 'Lolah', - 'Lexine', - 'Maylynn', - 'Clarinda', - 'Marlynn', - 'Netra', - 'Makaylin', - 'Naira', - 'Naleah', - 'Mishel', - 'Myli', - 'Charlotta', - 'Arlisa', - 'Kaylynne', - 'Kamillah', - 'Ksenia', - 'Briseidy', - 'Aysel', - 'Anaily', - 'Eulean', - 'Adilee', - 'Abri', - 'Aidynn', - 'Alisyn', - 'Alicen', - 'Marveline', - 'Lupie', - 'Mariabelen', - 'Makenah', - 'Kyliegh', - 'Foye', - 'Yajahira', - 'Trenda', - 'Tya', - 'Nattaly', - 'Netanya', - 'Supriya', - 'Teja', - 'Srija', - 'Sherra', - 'Janissa', - 'Mysha', - 'Essfa', - 'Alexandrya', - 'Abi', - 'Takhia', - 'Jaeli', - 'Jaelynne', - 'Dianey', - 'Denisa', - 'Aleli', - 'Akina', - 'Aayushi', - 'Adanna', - 'Aunika', - 'Ithzel', - 'Caricia', - 'Kallyn', - 'Karmin', - 'Kindall', - 'Gredmarie', - 'Peace', - 'Jennalee', - 'Yaindhi', - 'Arcola', - 'Trannie', - 'Lyza', - 'Mackynzie', - 'Peggye', - 'Zenab', - 'Megyn', - 'Navina', - 'Naileah', - 'Maddelyn', - 'Luxe', - 'Arkie', - 'Belvia', - 'Edilia', - 'Monda', - 'Ridhi', - 'Peyten', - 'Sorayah', - 'Syrena', - 'Amberle', - 'Johnita', - 'Jerrye', - 'Alfa', - 'Jonita', - 'Lakie', - 'Jenalee', - 'Minami', - 'Morena', - 'Elsbeth', - 'Sylia', - 'Eunique', - 'Ellisa', - 'Lanai', - 'Jesselyn', - 'Jolissa', - 'Julizza', - 'Laquitha', - 'Jobina', - 'Wyvonne', - 'Shalese', - 'Deshannon', - 'Almendra', - 'Alisandra', - 'Geraldene', - 'Abygale', - 'Katelyne', - 'Kennede', - 'Karisia', - 'Lindzy', - 'Keyhla', - 'Emilea', - 'Dacey', - 'Jalah', - 'Adrienna', - 'Aisa', - 'Alaisha', - 'Brithney', - 'Calynn', - 'Cassity', - 'Brendy', - 'Reagen', - 'Myrah', - 'Montserrath', - 'Pheobe', - 'Nyeli', - 'Jocell', - 'Serenidy', - 'Issabela', - 'Hanalei', - 'Laelah', - 'Emmylou', - 'Geraldy', - 'Ovetta', - 'Analena', - 'Allyna', - 'Aliyanah', - 'Magdalyn', - 'Suann', - 'Ronee', - 'Amey', - 'Chirstina', - 'Trude', - 'Jearldine', - 'Maeleigh', - 'Lizzy', - 'Liviana', - 'Eithel', - 'Meryem', - 'Yaneisy', - 'Shatika', - 'Zeniyah', - 'Xaylee', - 'Pennelope', - 'Xochilth', - 'Jullie', - 'Saki', - 'Shaiann', - 'Haille', - 'Dannya', - 'Kerie', - 'Chianti', - 'Leza', - 'Koreen', - 'Letricia', - 'Lamanda', - 'Kinza', - 'Marisella', - 'Joelyn', - 'Cinde', - 'Chyrl', - 'Cece', - 'Boni', - 'Felecity', - 'Faithe', - 'Delayna', - 'Diamon', - 'Daley', - 'Darah', - 'France', - 'Kolina', - 'Kieu', - 'Grizel', - 'Shaleigh', - 'Shaylea', - 'Anitza', - 'Carrolyn', - 'Olimpia', - 'Jeannene', - 'Victoriana', - 'Azara', - 'Avelynn', - 'Aveah', - 'Ariam', - 'Devanie', - 'Daleisa', - 'Karelly', - 'Karalynn', - 'Keyleen', - 'Kendallyn', - 'Graceyn', - 'Falynn', - 'Evoleht', - 'Everlie', - 'Emri', - 'Hartlee', - 'Eleena', - 'Jailee', - 'Insiya', - 'Analysia', - 'Chalee', - 'Amzie', - 'Amilya', - 'Celisa', - 'Airabella', - 'Laketha', - 'Kyoko', - 'Saria', - 'Neli', - 'Melonee', - 'Neidy', - 'Nyanza', - 'Aizlynn', - 'Arthurine', - 'Mikhaela', - 'Adalae', - 'Parveen', - 'Lotoya', - 'Evanjelina', - 'Deborra', - 'Lunna', - 'Makylah', - 'Mckinleigh', - 'Mayalen', - 'Ladasia', - 'Javia', - 'Evian', - 'Jaelee', - 'Oluwatamilore', - 'Payzlee', - 'Reiley', - 'Samarra', - 'Chyler', - 'Areona', - 'Vanesha', - 'Tomisha', - 'Betzaira', - 'Dalana', - 'Destenie', - 'Brennah', - 'Cassidie', - 'Deziray', - 'Dimond', - 'Braeleigh', - 'Aylee', - 'Anastyn', - 'Amillia', - 'Jailyne', - 'Jissell', - 'Jailenne', - 'Inioluwa', - 'Jensyn', - 'Allia', - 'Evolett', - 'Emmalynne', - 'Emberlee', - 'Emaline', - 'Ellayna', - 'Kollins', - 'Keyly', - 'Livi', - 'Judeen', - 'Eleah', - 'Vonceil', - 'Kaaliyah', - 'Girtie', - 'Gianelle', - 'Iniya', - 'Harlynn', - 'Greidy', - 'Shayli', - 'Belina', - 'Auri', - 'Avangeline', - 'Alizey', - 'Arlynn', - 'Anelise', - 'Aneli', - 'Delmira', - 'Vanassa', - 'Ceana', - 'Ambre', - 'Florita', - 'Balbina', - 'Clova', - 'Danice', - 'Aydee', - 'Carlena', - 'Benicia', - 'Soumya', - 'Lissandra', - 'Ling', - 'Liahna', - 'Leonna', - 'Leilana', - 'Reeya', - 'Krisinda', - 'Maleiah', - 'Maiyah', - 'Mailin', - 'Lucciana', - 'Naydeen', - 'Nailani', - 'Miette', - 'Yeva', - 'Suley', - 'Shravya', - 'Kyia', - 'Shree', - 'Cerise', - 'Katriana', - 'Jaskiran', - 'Mone', - 'Latijera', - 'Rosicela', - 'Sidnee', - 'Rosisela', - 'Troi', - 'Victorya', - 'Creasie', - 'Latorsha', - 'Erienne', - 'Jovonna', - 'Jessia', - 'Jeny', - 'Dejia', - 'Destynie', - 'Barbi', - 'Marlinda', - 'Shakeitha', - 'Mistelle', - 'Ziona', - 'Zarahi', - 'Xiadani', - 'Zyrah', - 'Zoriah', - 'Pamla', - 'Cinamon', - 'Bernardette', - 'Makensie', - 'Lexani', - 'Miyana', - 'Costella', - 'Cliffie', - 'Lashune', - 'Windie', - 'Rhondalyn', - 'Avonelle', - 'Marcine', - 'Berneda', - 'Rosabelle', - 'Huldah', - 'Emagene', - 'Clarabell', - 'Marceil', - 'Ula', - 'Renika', - 'Shaterica', - 'Labrittany', - 'Zelia', - 'Aidy', - 'Abeeha', - 'Maebelle', - 'Farzona', - 'Bryelle', - 'Aphrodite', - 'Diyora', - 'Zilphia', - 'Ercell', - 'Starlynn', - 'Renad', - 'Reham', - 'Marwah', - 'Raaina', - 'Mehreen', - 'Chermaine', - 'Ameliah', - 'Hajra', - 'Anamika', - 'Caoimhe', - 'Tasheka', - 'Cladie', - 'Claretta', - 'Ratzy', - 'Parizoda', - 'Tzurty', - 'Simrah', - 'Miamor', - 'Mala', - 'Yittel', - 'Ranata', - 'Clellie', - 'Dewana', - 'Kenyada', - 'Sennie', - 'Estie', - 'Oprah', - 'Chessie', - 'Rumaisa', - 'Rosmery', - 'Shenell', - 'Cosima', - 'Ellyanna', - 'Hebe', - 'Aamira', - 'Beily', - 'Areesha', - 'Amilah', - 'Mahdiya', - 'Ramata', - 'Naava', - 'Cannie', - 'Dorraine', - 'Verlee', - 'Anija', - 'Garnita', - 'Lorenda', - 'Mikia', - 'Marvella', - 'Sharma', - 'Pamula', - 'Anmarie', - 'Valicia', - 'Collene', - 'Ronetta', - 'Floris', - 'Andora', - 'Berdina', - 'Ivadell', - 'Lorain', - 'Kevinisha', - 'Corielle', - 'Rinda', - 'Jodelle', - 'Arta', - 'Kalima', - 'Kalifa', - 'Liat', - 'Dashawna', - 'Jahnae', - 'Eylin', - 'Tahmina', - 'Sherin', - 'Niambi', - 'Tonjua', - 'Hanifah', - 'Maham', - 'Sokhna', - 'Carliss', - 'Nimra', - 'Quianna', - 'Shadai', - 'Renella', - 'Eliska', - 'Alima', - 'Agata', - 'Adenike', - 'Charizma', - 'Shirlean', - 'Joycelin', - 'Cyanne', - 'Ambika', - 'Albana', - 'Noshin', - 'Merve', - 'Sanjida', - 'Khiabet', - 'Maudrey', - 'Manuella', - 'Linder', - 'Bisma', - 'Shataya', - 'Shandel', - 'Samanthamarie', - 'Liron', - 'Liann', - 'Merdis', - 'Daquana', - 'Chanee', - 'Ezora', - 'Janiqua', - 'Jamielyn', - 'Kyesha', - 'Eulalie', - 'Montressa', - 'Alzina', - 'Monez', - 'Casmira', - 'Eileene', - 'Ethelmae', - 'Veneta', - 'Madiha', - 'Akeema', - 'Daneisha', - 'Cecely', - 'Gwendola', - 'Javonna', - 'Teshia', - 'Yaniris', - 'Valbona', - 'Corita', - 'Deshanna', - 'Kameka', - 'Armina', - 'Georgian', - 'Shakeera', - 'Saudia', - 'Stacyann', - 'Shenique', - 'Ura', - 'Felicie', - 'Ezola', - 'Janeece', - 'Chavely', - 'Ashling', - 'Nakea', - 'Shiana', - 'Shadasia', - 'Petronella', - 'Virgin', - 'Gunhild', - 'Brianni', - 'Grainne', - 'Aneisha', - 'Chaniece', - 'Zalika', - 'Tynasia', - 'Tashauna', - 'Shazia', - 'Shatiqua', - 'Sharissa', - 'Shanyce', - 'Shandell', - 'Shakeyla', - 'Vergia', - 'Geraldyne', - 'Dorita', - 'Nathasha', - 'Samanthajo', - 'Amela', - 'Afnan', - 'Halimah', - 'Dayatra', - 'Shontrell', - 'Tziry', - 'Shanyah', - 'Shawntell', - 'Schwanda', - 'Magalene', - 'Si', - 'Ramisa', - 'Ioanna', - 'Imane', - 'Hadar', - 'Ettel', - 'Coumba', - 'Chumy', - 'Shiran', - 'Lianny', - 'Kimara', - 'Nicha', - 'Chestine', - 'Fatmata', - 'Chedva', - 'Shaima', - 'Shailyn', - 'Zarin', - 'Zahrah', - 'Wania', - 'Tsering', - 'Syrai', - 'Suriyah', - 'No', - 'Niylah', - 'Meerab', - 'Emanuela', - 'Draizy', - 'Giabella', - 'Jeily', - 'Sofya', - 'Shantrelle', - 'Analisse', - 'Ramatoulaye', - 'Raima', - 'Sumaiyah', - 'Stori', - 'Tremeka', - 'Beila', - 'Clodagh', - 'Lyniah', - 'Giavana', - 'Tikisha', - 'Kesia', - 'Shawan', - 'Mazelle', - 'Lear', - 'Rosilyn', - 'Jnaya', - 'Jahnia', - 'Shi', - 'Henya', - 'Jhoselyn', - 'Doha', - 'Dilara', - 'Adelisa', - 'Dedria', - 'Troylynn', - 'Basha', - 'Fatimata', - 'Ama', - 'Ashantee', - 'Chania', - 'Donzella', - 'Ya', - 'Fahmida', - 'Iysis', - 'Neviah', - 'Anastasiya', - 'Brandel', - 'Afra', - 'Lendora', - 'Zisel', - 'Dwanda', - 'Ciarah', - 'Brighid', - 'Rafia', - 'Keamber', - 'Virdie', - 'Girtrude', - 'Nakaya', - 'Donis', - 'Anslei', - 'Alyene', - 'Audell', - 'Nahriah', - 'Zakeria', - 'Zoria', - 'Nikeria', - 'Kynley', - 'Karaline', - 'Jacquita', - 'Shonteria', - 'Carlyon', - 'Tykira', - 'Nykerria', - 'Lema', - 'Destyne', - 'Kansas', - 'Aryonna', - 'Iyannah', - 'Jamayah', - 'Serenitee', - 'Jood', - 'Willean', - 'Makyah', - 'Kameria', - 'Shelagh', - 'Zarriah', - 'Avionna', - 'Arilynn', - 'Vira', - 'Lelar', - 'Miyonna', - 'Jaionna', - 'Nakiah', - 'Rubby', - 'Henrene', - 'Perlie', - 'Tanyah', - 'Luretha', - 'Fannye', - 'Arquilla', - 'Albirta', - 'Annakate', - 'Akeria', - 'Teola', - 'Darthy', - 'Amberleigh', - 'Floriene', - 'Alleyne', - 'Karra', - 'Shaneika', - 'Nekita', - 'Niketa', - 'Kiaraliz', - 'Anacarolina', - 'Sharonica', - 'Renota', - 'Shambrica', - 'Mylea', - 'Jalicia', - 'Shantavious', - 'Antania', - 'Derika', - 'Rashunda', - 'Shandrea', - 'Teneisha', - 'Wachovia', - 'Jalecia', - 'Leimomi', - 'Lasondra', - 'Tela', - 'Caleah', - 'Iwalani', - 'Jamyri', - 'Azyria', - 'Napua', - 'Lahela', - 'Lehuanani', - 'Lameka', - 'Davelyn', - 'Filippa', - 'Tywanna', - 'Toini', - 'Pota', - 'Berthe', - 'Aliesha', - 'Iolanda', - 'Seaira', - 'Kealohilani', - 'Leialoha', - 'Chastidy', - 'Taimane', - 'Taylorann', - 'Briunna', - 'Tyrielle', - 'Alohilani', - 'Jakala', - 'Lakendria', - 'Tiffinie', - 'Laprecious', - 'Kaylaann', - 'Marigny', - 'Roise', - 'Kaidance', - 'Niyla', - 'Mahari', - 'Zya', - 'Ruthia', - 'Timara', - 'Caniya', - 'Keirah', - 'Arieonna', - 'Alydia', - 'Alivea', - 'Ahmani', - 'Elynn', - 'Earnstine', - 'Ramiya', - 'Morrigan', - 'Masiyah', - 'Harmoney', - 'Pearley', - 'Jearlean', - 'Korrine', - 'Chyanna', - 'Catena', - 'Pacita', - 'Kalle', - 'Alzira', - 'Tashayla', - 'Tsugie', - 'Yachiyo', - 'Shellia', - 'Sueno', - 'Kazuyo', - 'Kikumi', - 'Shizuka', - 'Chiyono', - 'Shigeno', - 'Tatsue', - 'Fumiyo', - 'Misayo', - 'Momoyo', - 'Hanayo', - 'Misae', - 'Dalaney', - 'Dewanda', - 'Itsuko', - 'Nyamal', - 'Claris', - 'Virlee', - 'Lulabelle', - 'Valada', - 'Neleigh', - 'Rafelita', - 'Placida', - 'Dulcinea', - 'Pita', - 'Heer', - 'Beren', - 'Ramoncita', - 'Orlinda', - 'Florette', - 'Deluvina', - 'Lugarda', - 'Crucita', - 'Rafaelita', - 'Pablita', - 'Lamaria', - 'Terriana', - 'Terrianna', - 'Dariyah', - 'Carmie', - 'Clotine', - 'Antha', - 'Takyla', - 'Peachie', - 'Akirah', - 'Captola', - 'Sadeel', - 'Dosha', - 'Miquela', - 'Anilah', - 'Erielle', - 'Janiylah', - 'Aubriel', - 'Priti', - 'Purvi', - 'Shakeemah', - 'Anjail', - 'Shaheerah', - 'Amneris', - 'Melverine', - 'Twilla', - 'Kruti', - 'Jalee', - 'Shareefah', - 'Muslimah', - 'Tauheedah', - 'Anabela', - 'Yakima', - 'Lyllian', - 'Tanajah', - 'Sakiyah', - 'Eun', - 'Yashika', - 'Ji', - 'Demiana', - 'Mariaeduard', - 'Snigdha', - 'Dala', - 'Kum', - 'Myung', - 'Hadiyah', - 'Gopi', - 'Cresta', - 'In', - 'Davita', - 'Talayeh', - 'Tracyann', - 'Petula', - 'Nerida', - 'Jeaneen', - 'Ilissa', - 'Letta', - 'Kishia', - 'Gesenia', - 'Bethsaida', - 'Tanija', - 'Ivelise', - 'Marines', - 'Angenette', - 'Alanda', - 'Lauraann', - 'Darnetta', - 'Alisande', - 'Jeniya', - 'Patria', - 'Tieysha', - 'Tasheen', - 'Ife', - 'Loredana', - 'Amyjo', - 'Chane', - 'Nilka', - 'Sharema', - 'Grazia', - 'Renna', - 'Tahesha', - 'Tarita', - 'Jannis', - 'Geriann', - 'Areatha', - 'Rosangel', - 'Kemba', - 'Noni', - 'Margaretann', - 'Kimberleigh', - 'Latisa', - 'Kiriaki', - 'Bobbyjo', - 'Walida', - 'Lynanne', - 'Niyanna', - 'Daziah', - 'Kharma', - 'Pier', - 'Marymargaret', - 'Lorrain', - 'Ketty', - 'Helane', - 'Tarnisha', - 'Sherrice', - 'Swati', - 'Donnajean', - 'Tunya', - 'Annmargaret', - 'Raffaella', - 'Pina', - 'Deneene', - 'Lorriane', - 'Shenise', - 'Ziyonna', - 'Evagelia', - 'Chantae', - 'Tasheema', - 'Meaghen', - 'Shanikqua', - 'Lynnox', - 'Taiesha', - 'Sharima', - 'Shantai', - 'Shaena', - 'Jamine', - 'Rasheena', - 'Tashi', - 'Magdala', - 'Edia', - 'Lasheka', - 'Tiasha', - 'Quanita', - 'Jomayra', - 'Nairoby', - 'Danamarie', - 'Roena', - 'Zasha', - 'Shatema', - 'Orissa', - 'Elvire', - 'Louisiana', - 'Hoda', - 'Kashana', - 'Jaquanna', - 'Jacqulin', - 'Annamari', - 'Marquia', - 'Elmire', - 'Viney', - 'Sonna', - 'Yokasta', - 'Esma', - 'Rella', - 'Deloras', - 'Janill', - 'Samanthan', - 'Ketsia', - 'Chaunte', - 'Aderonke', - 'Sheindel', - 'Shameen', - 'Karema', - 'Amalin', - 'Glendaliz', - 'Finesse', - 'Talibah', - 'Lakima', - 'Geeta', - 'Suehay', - 'Dorice', - 'Aesha', - 'Lateasha', - 'Kimitra', - 'Omolola', - 'Bobbette', - 'Deliah', - 'Carianne', - 'Chanah', - 'Laquandra', - 'Laquanna', - 'Yanick', - 'Nathifa', - 'Nakima', - 'Gayl', - 'Shamaine', - 'Saquana', - 'Nixzaliz', - 'Chaye', - 'Maleka', - 'Latima', - 'Yamira', - 'Tashanna', - 'Kathiria', - 'Jameika', - 'Jamesetta', - 'Moniqua', - 'Yamaris', - 'Tasheba', - 'Virgina', - 'Aviance', - 'Calogera', - 'Candita', - 'Kinga', - 'Alissia', - 'Onnolee', - 'Johnda', - 'Sebastiana', - 'Michelena', - 'Tecla', - 'Mirriam', - 'Sydel', - 'Glema', - 'Tatiyanna', - 'Patrycia', - 'Fortuna', - 'Ebba', - 'Carmelia', - 'Liddie', - 'Genella', - 'Detta', - 'Malvery', - 'Evelene', - 'Loretto', - 'Nunziata', - 'Jenan', - 'Keshawna', - 'Kinisha', - 'Tikia', - 'Sueanne', - 'Cira', - 'Charda', - 'Midge', - 'Annina', - 'Delcina', - 'Barbette', - 'Danah', - 'Isolina', - 'Tanita', - 'Gracemarie', - 'Halleigh', - 'Julita', - 'Kaprice', - 'Dorothyann', - 'Binnie', - 'Bettyjean', - 'Frayda', - 'Tashiana', - 'Breshey', - 'Charnise', - 'Tashena', - 'Meribeth', - 'Sandralee', - 'Heena', - 'Walda', - 'Latika', - 'Rashaunda', - 'Linde', - 'Rosaleen', - 'Illona', - 'Clydette', - 'Benay', - 'Damonica', - 'Anajah', - 'Louelle', - 'Lunette', - 'Faduma', - 'Nadeige', - 'Meylin', - 'Elverna', - 'Etrulia', - 'Ellaree', - 'Rushie', - 'Jayona', - 'Mauri', - 'Radiah', - 'Runette', - 'Terrah', - 'Joia', - 'Ezma', - 'Glenys', - 'Ramla', - 'Shatasha', - 'Berma', - 'Chanteria', - 'Chantrell', - 'Elvi', - 'Sharnell', - 'Rether', - 'Keshana', - 'Ranesha', - 'Earther', - 'Zahirah', - 'Anye', - 'Khori', - 'Saniyyah', - 'Teniola', - 'Anniemae', - 'Oluwadamilola', - 'Aldene', - 'Amellia', - 'Junice', - 'Carolene', - 'Ireoluwa', - 'Nasra', - 'Vernease', - 'Delrose', - 'Marysue', - 'Mirlande', - 'Lashannon', - 'Taijah', - 'Markiesha', - 'Syanne', - 'Jahiya', - 'Vyonne', - 'Reniya', - 'Ryana', - 'Idonia', - 'Loette', - 'Etheleen', - 'Ariyon', - 'Jeneane', - 'Jamea', - 'Airyana', - 'Natesha', - 'Bonnell', - 'Savilla', - 'Daneshia', - 'Deneshia', - 'Alexzandrea', - 'Martharee', - 'Elfreda', - 'Danyla', - 'Retaj', - 'Childnotnamed', - 'Kariana', - 'Ladeja', - 'Johnesha', - 'Nariya', - 'Zamariah', - 'Shanyla', - 'Zykiria', - 'Micaella', - 'Angeliyah', - 'Camara', - 'Kenniyah', - 'Keyani', - 'Renie', - 'Aldena', - 'Paytyn', - 'Perma', - 'Annamary', - 'Roniyah', - 'Zeniya', - 'Capitola', - 'Jaiana', - 'Lakiya', - 'Reida', - 'Ahniya', - 'Elanor', - 'Dorothee', - 'Joud', - 'Ludmilla', - 'Traniyah', - 'Kjerstin', - 'Jeylin', - 'Teona', - 'Marypat', - 'Jacquelynne', - 'Harmonii', - 'Kenyah', - 'Anora', - 'Deniyah', - 'Tyleah', - 'Samora', - 'Almeter', - 'Floride', - 'Lether', - 'Aviah', - 'Livie', - 'Federica', - 'Khalani', - 'Dericka', - 'Ronisue', - 'Raziah', - 'Emaya', - 'Christyana', - 'Rasheka', - 'Jahira', - 'Jalana', - 'Lateria', - 'Baneen', - 'Davisha', - 'Joyanna', - 'Janelys', - 'Raneisha', - 'Israa', - 'Shauntavia', - 'Shericka', - 'Deloma', - 'Maryetta', - 'Jeannetta', - 'Tymber', - 'Charmon', - 'Lanise', - 'Charlisa', - 'Bloneva', - 'Andrena', - 'Katena', - 'Latorria', - 'Letoya', - 'Quovadis', - 'Lakeisa', - 'Sihaam', - 'Charo', - 'Annaclara', - 'Margretta', - 'Nataki', - 'Tyjae', - 'Bahja', - 'Shequila', - 'Quadira', - 'Toinette', - 'Sumeya', - 'Takita', - 'Sherlonda', - 'Daejah', - 'Zyanna', - 'Antonique', - 'Linnae', - 'Georgean', - 'Charlane', - 'Jakerria', - 'Nimo', - 'Saprina', - 'Detrice', - 'Nicolly', - 'Nayara', - 'Seandra', - 'Demetrica', - 'Kayton', - 'Jalayna', - 'Emanuelly', - 'Dondra', - 'Michaeleen', - 'Aquinnah', - 'Lakrisha', - 'Latoia', - 'Bernessia', - 'Jaydaliz', - 'Deona', - 'Donyelle', - 'Kearsten', - 'Tashira', - 'Kaisa', - 'Korrin', - 'Onelia', - 'Shawntia', - 'Faylene', - 'Nafeesah', - 'Synetta', - 'Robertine', - 'Krystn', - 'Nyjae', - 'Nijae', - 'Cieara', - 'Ellerie', - 'Thomasenia', - 'Tiki', - 'Lougenia', - 'Joeann', - 'Marlyss', - 'Saralee', - 'Dayona', - 'Alainna', - 'Gennell', - 'Berline', - 'Latoiya', - 'Eyvonne', - 'Cherline', - 'Tequesta', - 'Loann', - 'Kerstyn', - 'Najmo', - 'Shanitra', - 'Marnice', - 'Tamyah', - 'Ave', - 'Cierrah', - 'Deborahann', - 'Davette', - 'Kennidy', - 'Breelle', - 'Lundon', - 'Imoni', - 'Shamyah', - 'Lindia', - 'Caylyn', - 'Ghadeer', - 'Amirrah', - 'Arlayne', - 'Norrine', - 'Vondell', - 'Ruqaya', - 'Azariya', - 'Narice', - 'Glenadine', - 'Lallie', - 'Conola', - 'Airlie', - 'Lorelie', - 'Levis', - 'Sanyia', - 'Mckaela', - 'Arlina', - 'Dellar', - 'Zorianna', - 'Zanyiah', - 'Maleya', - 'Niyana', - 'Amonie', - 'Aryia', - 'Autie', - 'Keileigh', - 'Kyndel', - 'Saliyah', - 'Naziah', - 'Bernette', - 'Vona', - 'Venie', - 'Tyashia', - 'Khaliya', - 'Mckensie', - 'Kerigan', - 'Kaniah', - 'Eria', - 'Maziyah', - 'Kiasia', - 'Anice', - 'Dera', - 'Georgena', - 'Ezelle', - 'Eavan', - 'Marlyne', - 'Lovella', - 'Westonia', - 'Keniah', - 'Janiaya', - 'Mertice', - 'Marget', - 'Zyeria', - 'Marquerite', - 'Minha', - 'Redonna', - 'Deetta', - 'Aiyla', - 'Majel', - 'Elnor', - 'Deronda', - 'Viona', - 'Rosaleigh', - 'Virgiline', - 'Reeda', - 'Minnah', - 'Keerthi', - 'Kaleyah', - 'Myanna', - 'Remas', - 'Noralee', - 'Idabelle', - 'Albena', - 'Ellory', - 'Areej', - 'Zariel', - 'Laverle', - 'Hjordis', - 'Hilja', - 'Ragna', - 'Cordella', - 'Irean', - 'Ottilia', - 'Gerane', - 'Locklyn', - 'Equilla', - 'Dellie', - 'Aarvi', - 'Mardella', - 'Leighanna', - 'Theone', - 'Ordella', - 'Lidwina', - 'Alyda', - 'Arlyss', - 'Evangelita', - 'Hee', - 'Cherell', - 'Charelle', - 'Shealynn', - 'Anesha', - 'Jasman', - 'Stephie', - 'Ok', - 'Tacarra', - 'Sharnita', - 'Jessic', - 'Dulcey', - 'Natina', - 'Sharvae', - 'Nachelle', - 'Jillane', - 'Tarri', - 'Ajena', - 'Allexus', - 'Labrenda', - 'Pammy', - 'Shemeika', - 'Ysela', - 'Meghin', - 'Marketta', - 'Porshe', - 'Kayti', - 'Taylour', - 'Shavonte', - 'Aivah', - 'Khloi', - 'Jerzie', - 'Nikesha', - 'Cherron', - 'Coralynn', - 'Alvita', - 'Carlita', - 'Albany', - 'Deshawnda', - 'Lacole', - 'Lameeka', - 'Mashawn', - 'Kimyata', - 'Keenya', - 'Baya', - 'Kiva', - 'Samona', - 'Meggin', - 'Chanita', - 'Danissa', - 'Lileigh', - 'Addeline', - 'Shemeeka', - 'Aprille', - 'Donice', - 'Tannisha', - 'Angelette', - 'Lakeita', - 'Marcelyn', - 'Lesta', - 'Claudene', - 'Marney', - 'Tonyia', - 'Nellora', - 'Kimyetta', - 'Ameliana', - 'Electa', - 'Sherl', - 'Jeniece', - 'Jawana', - 'Errica', - 'Braya', - 'Titania', - 'Guydra', - 'Valeta', - 'Danetta', - 'Sharia', - 'Hawraa', - 'Danaja', - 'Makalynn', - 'Tayonna', - 'Kyrene', - 'Arieona', - 'Dallie', - 'Ruie', - 'Ophia', - 'Odella', - 'Vessie', - 'Offie', - 'Evadean', - 'Ample', - 'Aleecia', - 'Shakyla', - 'Makynna', - 'Lakyra', - 'Korryn', - 'Araina', - 'Semiyah', - 'Ndea', - 'Areonna', - 'Jasia', - 'Xavia', - 'Merikay', - 'Keshara', - 'Jennetta', - 'Vergene', - 'Wilodean', - 'Wyona', - 'Avonell', - 'Datha', - 'Ellar', - 'Morene', - 'Laverda', - 'Loetta', - 'Emmogene', - 'Arbadella', - 'Camaria', - 'Rochella', - 'Indiya', - 'Shayma', - 'Orneta', - 'Clotene', - 'Genoa', - 'Lanyah', - 'Oneda', - 'Glendola', - 'Rosala', - 'Zelphia', - 'Suda', - 'Jerrilynn', - 'Orlena', - 'Lorella', - 'Bernadean', - 'Novice', - 'Pheba', - 'Rukaya', - 'Gathel', - 'Meron', - 'Asianae', - 'Arriel', - 'Whisper', - 'Talesha', - 'Morgann', - 'Madissen', - 'Dajanay', - 'Karil', - 'Sherrita', - 'Chery', - 'Lezlee', - 'Daytona', - 'Raegen', - 'Dalal', - 'Majerle', - 'Lama', - 'Daijanae', - 'Celicia', - 'Cheril', - 'Cornesha', - 'Aniza', - 'Clytie', - 'Persis', - 'Aino', - 'Lawandra', - 'Deshonda', - 'Catrena', - 'Temekia', - 'Camella', - 'Arnetra', - 'Latoyna', - 'Tekisha', - 'Nalee', - 'Jennife', - 'Daphanie', - 'Shewanda', - 'Cheronda', - 'Latayna', - 'Almerinda', - 'Danene', - 'Jadwiga', - 'Ellora', - 'Tanga', - 'Tamekka', - 'Lashond', - 'Shinika', - 'Khyleigh', - 'Baelyn', - 'Clarene', - 'Monyette', - 'Lakisa', - 'Audreyanna', - 'Malayjah', - 'Keia', - 'Lajessica', - 'Marquite', - 'Odessia', - 'Marketia', - 'Malayshia', - 'Laconya', - 'Brayla', - 'Germani', - 'Luberdie', - 'Angla', - 'Cona', - 'Katrinia', - 'Shaletha', - 'Eutha', - 'Elmyra', - 'Cleva', - 'Elnore', - 'Vila', - 'Evone', - 'Margert', - 'Pairlee', - 'Bernelle', - 'Diannie', - 'Alinda', - 'Emerine', - 'Rogena', - 'Genette', - 'Jearline', - 'Estalee', - 'Bertina', - 'Cassand', - 'Kisa', - 'Veronic', - 'Idalina', - 'Walsie', - 'Gwendol', - 'Orvilla', - 'Latonga', - 'Elizabe', - 'Bernece', - 'Charlen', - 'Dola', - 'Alaija', - 'Martia', - 'Shanica', - 'Shariya', - 'Yuliya', - 'Atleigh', - 'Flannery', - 'Loeta', - 'Zakiah', - 'Alayia', - 'Glee', - 'Embree', - 'Kasidy', - 'Zacaria', - 'Derriona', - 'Jakyria', - 'Kiauna', - 'Garnelle', - 'Tyriana', - 'Juliya', - 'Maddisen', - 'Auna', - 'Jameisha', - 'Lurleen', - 'Kourtlyn', - 'Chelan', - 'Verlinda', - 'Sherria', - 'Alzada', - 'Ketara', - 'Anaka', - 'Breion', - 'Shadestiny', - 'Shanterica', - 'Tenia', - 'Keiosha', - 'Jamyriah', - 'Jamyrie', - 'Jalacia', - 'Ronita', - 'Maryln', - 'Earsie', - 'Kyri', - 'Markiyah', - 'Malajah', - 'Alandria', - 'Shaquitta', - 'Raymona', - 'Paeton', - 'Yaritzy', - 'Jonesha', - 'Anda', - 'Khadjah', - 'Amyree', - 'Vernestine', - 'Lavetta', - 'Jniya', - 'Shakiyah', - 'Aasia', - 'Roniya', - 'Keleigh', - 'Makalyn', - 'Kadasia', - 'Johneisha', - 'Jakaya', - 'Kinzey', - 'Wendelyn', - 'Darielys', - 'Wyteria', - 'Yarieliz', - 'Taysia', - 'Carmya', - 'Erionna', - 'Shameria', - 'Kearia', - 'Graycie', - 'Jurnie', - 'Calypso', - 'Finlee', - 'Fynlee', - 'Sophee', - 'Lorali', - 'Shacoria', - 'Kadeejah', - 'Lakira', - 'Kelsay', - 'Angelys', - 'Moeshia', - 'Keundra', - 'Mayara', - 'Josi', - 'Annaluiza', - 'Jacquese', - 'Jillaine', - 'Annajulia', - 'Nayeliz', - 'Maire', - 'Jamonica', - 'Jadalys', - 'Missie', - 'Machell', - 'Liisa', - 'Jalaine', - 'Odester', - 'Veria', - 'Virda', - 'Arleene', - 'Cigi', - 'Eloda', - 'Kacelyn', - 'Cidalia', - 'Vadie', - 'Wydell', - 'Donnita', - 'Lousie', - 'Oreatha', - 'Berdine', - 'Cielita', - 'Lilas', - 'Verneda', - 'Armelia', - 'Glender', - 'Elizbeth', - 'Vanella', - 'Florean', - 'Vyolet', - 'Albertia', - 'Albirda', - 'Sylva', - 'Lakresha', - 'Matha', - 'Nerine', - 'Dezzie', - 'Lodell', - 'Rosielee', - 'Julane', - 'Lodena', - 'Brookley', - 'Kynadi', - 'Krymson', - 'Etoile', - 'Meighan', - 'Izella', - 'Jakaria', - 'Jaleria', - 'Clister', - 'Alberdia', - 'Zykeriah', - 'Mileigh', - 'Isola', - 'Mamye', - 'Eller', - 'Kamoria', - 'Lakelynn', - 'Aslean', - 'Bular', - 'Emmaclaire', - 'Dasie', - 'Denotra', - 'Everlene', - 'Lynleigh', - 'Iantha', - 'Quinetta', - 'Lillion', - 'Sophronia', - 'Japonica', - 'Beauty', - 'Pearlina', - 'Evella', - 'Jatana', - 'Kechia', - 'Conswella', - 'Malissia', - 'Alexina', - 'Demeka', - 'Muguette', - 'Vaudine', - 'Aprill', - 'Villa', - 'Florece', - 'Tonjia', - 'Bethania', - 'Makinlee', - 'Latondra', - 'Audery', - 'Ericia', - 'Miyoshi', - 'Betti', - 'Harlym', - 'Novelle', - 'Liller', - 'Pinkey', - 'Narcille', - 'Lasheika', - 'Leonise', - 'Lydie', - 'Olla', - 'Rejeanne', - 'Athelene', - 'Eloyse', - 'Edolia', - 'Clotile', - 'Ethelrine', - 'Devonda', - 'Nakeshia', - 'Tomesha', - 'Orena', - 'Karlyne', - 'Enolia', - 'Faynell', - 'Margia', - 'Marvelene', - 'Justilia', - 'Iceola', - 'Shantina', - 'Shinita', - 'Loula', - 'Ireta', - 'Vanessia', - 'Ramonia', - 'Monita', - 'Shalva', - 'Ong', - 'Remonia', - 'Sheral', - 'Angelean', - 'Phyllistine', - 'Brenetta', - 'Madgeline', - 'Zyairah', - 'Anjolaoluwa', - 'Clotiel', - 'Eldine', - 'Tylia', - 'Ifeoluwa', - 'Florestine', - 'Althia', - 'Ravonda', - 'Tsion', - 'Zyaira', - 'Wylodene', - 'Janesha', - 'Vonciel', - 'Ruthey', - 'Khiana', - 'Kadesia', - 'Murdis', - 'Zhana', - 'Jillayne', - 'Quatisha', - 'Jaquasia', - 'Michaila', - 'Mashayla', - 'Travia', - 'Tyrika', - 'Aldah', - 'Makaiya', - 'Maridee', - 'Kyndell', - 'Nykira', - 'Mazell', - 'Luecile', - 'Quatasia', - 'Khala', - 'Sible', - 'Jakera', - 'Ovella', - 'Lealer', - 'Juleen', - 'Rinette', - 'Laykin', - 'Ozite', - 'Shaquanta', - 'Quanetta', - 'Shannyn', - 'Lacrystal', - 'Everline', - 'Editha', - 'Toneka', - 'Reinette', - 'Maclovia', - 'Ledia', - 'Shakeeka', - 'Shakeeta', - 'Taquanna', - 'Miyisha', - 'Patrecia', - 'Wylodean', - 'Solita', - 'Dalisa', - 'Jatoya', - 'Texanna', - 'Yvetta', - 'Lectoria', - 'Cyntrell', - 'Monyae', - 'Ibtisam', - 'Miski', - 'Renesha', - 'Maelle', - 'Azhar', - 'Zamzam', - 'Jamera', - 'Tyranika', - 'Ladan', - 'Ruweyda', - 'Jabrea', - 'Sherrica', - 'Clyda', - 'Treniece', - 'Fonnie', - 'Bedie', - 'Kewanda', - 'Mozel', - 'Tramika', - 'Quessie', - 'Tyshay', - 'Ladasha', - 'Kaarin', - 'Mazzie', - 'Genora', - 'Monie', - 'Muntas', - 'Hayat', - 'Jovanda', - 'Appolonia', - 'Cuma', - 'Briante', - 'Reneisha', - 'Zenovia', - 'Allysia', - 'Aliene', - 'Raini', - 'Tyja', - 'Iriel', - 'Deshante', - 'Shatira', - 'Demri', - 'Ajaysia', - 'Ireon', - 'Idil', - 'Nawaal', - 'Riham', - 'Nyeisha', - 'Jonique', - 'Keneisha', - 'Ravan', - 'Khadra', - 'Dawanna', - 'Gavriella', - 'Myrene', - 'Jasamine', - 'Brione', - 'Earlisha', - 'Dazia', - 'Jalesia', - 'Cabrina', - 'Marieme', - 'Gloristine', - 'Cattie', - 'Damilola', - 'Evora', - 'Almarie', - 'Vauda', - 'Tanzie', - 'Truby', - 'Tayona', - 'Francelia', - 'Brona', - 'Jannice', - 'Weltha', - 'Phylliss', - 'Vieva', - 'Danera', - 'Saratha', - 'Colinda', - 'Suzonne', - 'Shelene', - 'Shelda', - 'Annye', - 'Kaola', - 'Modine', - 'Velvie', - 'Vetra', - 'Tyrhonda', - 'Malissie', - 'Shemica', - 'Rockell', - 'Adgie', - 'Lachanda', - 'Kwanza', - 'Keyanta', - 'Hazeleen', - 'Yarnell', - 'Mettie', - 'Kissie', - 'Jawanna', - 'Ilham', - 'Enchantra', - 'Lucielle', - 'Salmo', - 'Sabrin', - 'Nicy', - 'Rubell', - 'Willet', - 'Ronata', - 'Semiko', - 'Idman', - 'Meoshia', - 'Maie', - 'Eulala', - 'Tiyonna', - 'Sabarin', - 'Merlie', - 'Oneka', - 'Khiya', - 'Geralene', - 'Hubbie', - 'Patches', - 'Robenia', - 'Carita', - 'Veleka', - 'Tamla', - 'Zondra', - 'Cheramie', - 'Nimco', - 'Chauntelle', - 'Calonia', - 'Mulki', - 'Clydia', - 'Glida', - 'Fartun', - 'Fardowsa', - 'Iyona', - 'Dwanna', - 'Angila', - 'Carletha', - 'Blakley', - 'Valecia', - 'Songa', - 'Shya', - 'Kamber', - 'Siah', - 'Sloka', - 'Sophiagrace', - 'Sophiamarie', - 'Setayesh', - 'Roselie', - 'Samhitha', - 'Savreen', - 'Zanayah', - 'Yilia', - 'Zareena', - 'Yeilin', - 'Ulyana', - 'Tylie', - 'Vaani', - 'Vasilisa', - 'Videl', - 'Xylia', - 'Rubylee', - 'Jessye', - 'Itasca', - 'Bonifacia', - 'Bennye', - 'Estellene', - 'Daycee', - 'Vung', - 'Babe', - 'Lucyle', - 'Laurencia', - 'Frankye', - 'Clariece', - 'Alsace', - 'Ernesteen', - 'Zuma', - 'Loleta', - 'Matiana', - 'Thyra', - 'Thekla', - 'Miladie', - 'Moselle', - 'Waldene', - 'Thula', - 'Ethelda', - 'Elbira', - 'Eddye', - 'Lafaye', - 'Beryle', - 'Beanna', - 'Basilisa', - 'Bernardina', - 'Vontressa', - 'Elner', - 'Gladine', - 'Saketha', - 'Nellene', - 'Margurette', - 'Levada', - 'Alcie', - 'Beuna', - 'Miaa', - 'Miia', - 'Miral', - 'Lunabella', - 'Manvi', - 'Nahlia', - 'Quetzal', - 'Preet', - 'Navreet', - 'Prajna', - 'Analayah', - 'Aalaya', - 'Aaleah', - 'Aaria', - 'Aby', - 'Adeena', - 'Adelaine', - 'Adhara', - 'Alekhya', - 'Avaline', - 'Avina', - 'Azaliah', - 'Azayla', - 'Anwita', - 'Arna', - 'Asmi', - 'Cutina', - 'Jaydalynn', - 'Jerusalem', - 'Hiyab', - 'Icey', - 'Jaanvi', - 'Khalessi', - 'Khiara', - 'Leelah', - 'Ketzaly', - 'Kaliyanei', - 'Karolynn', - 'Kaylonnie', - 'Harveen', - 'Danilynn', - 'Decklyn', - 'Deleyza', - 'Charm', - 'Calina', - 'Cathaleya', - 'Dailynn', - 'Corra', - 'Cyrene', - 'Eveleen', - 'Fia', - 'Galina', - 'Gohar', - 'Gursirat', - 'Harleyquinn', - 'Evalin', - 'Eevee', - 'Eira', - 'Elara', - 'Ellaina', - 'Ellarose', - 'Erabella', - 'Teofila', - 'Calamity', - 'Sherion', - 'Niang', - 'Oreta', - 'Leita', - 'Maedelle', - 'Othello', - 'Meshell', - 'Alfreida', - 'Detria', - 'Cloda', - 'Ermine', - 'Gertrudes', - 'Zudora', - 'Benigna', - 'Dolorez', - 'Narcissa', - 'Eduviges', - 'Dionisia', - 'Crisanta', - 'Adreena', - 'Aivy', - 'Sharanda', - 'Amma', - 'Danitra', - 'Lashuna', - 'Yasheka', - 'Sheronica', - 'Ameliya', - 'Cayetana', - 'Benancia', - 'Tiya', - 'Umaiza', - 'Vicktoria', - 'Vidushi', - 'Yaretzie', - 'Siennah', - 'Sofiah', - 'Stuti', - 'Taitum', - 'Yuli', - 'Zarya', - 'Zeriah', - 'Sadiee', - 'Rubee', - 'Ryenn', - 'Sayana', - 'Ezabella', - 'Galya', - 'Hayzel', - 'Evalette', - 'Eleanna', - 'Elize', - 'Elleana', - 'Hiya', - 'Jezabelle', - 'Jazzy', - 'Jeraldin', - 'Jocabed', - 'Kaloni', - 'Jazmeen', - 'Jasmarie', - 'Ilani', - 'Ilany', - 'Ariannie', - 'Angelinne', - 'Delaynie', - 'Calise', - 'Bethlehem', - 'Cateleya', - 'Paitynn', - 'Peytin', - 'Rainie', - 'Rhylin', - 'Rosaly', - 'Nomi', - 'Mirai', - 'Moksha', - 'Mylin', - 'Nazeli', - 'Nilani', - 'Marcelene', - 'Victorina', - 'Laiah', - 'Leeyah', - 'Miaisabella', - 'Ravleen', - 'Lazara', - 'Zuleidy', - 'Shraddha', - 'Simarpreet', - 'Rinoa', - 'Ridhima', - 'Ryla', - 'Ryleeann', - 'Ryli', - 'Sahori', - 'Smrithi', - 'Yeslin', - 'Yanessa', - 'Zeltzin', - 'Sonakshi', - 'Sophea', - 'Carlissa', - 'Bryttani', - 'Albesa', - 'Bonnye', - 'Daksha', - 'Terria', - 'Davinah', - 'Enalina', - 'Evolette', - 'Dhwani', - 'Eleora', - 'Leea', - 'Lexii', - 'Meilyn', - 'Nevah', - 'Noga', - 'Prabhleen', - 'Quinley', - 'Mursal', - 'Naiara', - 'Navah', - 'Izumi', - 'Janelli', - 'Jniyah', - 'Klaryssa', - 'Kritika', - 'Laksmi', - 'Lalani', - 'Joselle', - 'Kashish', - 'Kenyana', - 'Laquishia', - 'Deshonna', - 'Sentoria', - 'Ernestene', - 'Maxima', - 'Senovia', - 'Nestora', - 'Valta', - 'Casady', - 'Daphene', - 'Chonita', - 'Omelia', - 'Odena', - 'Melchora', - 'Quetzally', - 'Thera', - 'Gabina', - 'Donaciana', - 'Riddhima', - 'Lakessa', - 'Lakeeta', - 'Katasha', - 'Chaitra', - 'Chizara', - 'Aveyah', - 'Elah', - 'Eliannah', - 'Ellanore', - 'Emmalia', - 'Dalexa', - 'Delara', - 'Donatella', - 'Aubreanna', - 'Aberdeen', - 'Aerilyn', - 'Aleksia', - 'Annarose', - 'Anthea', - 'Aoi', - 'Amberrose', - 'Anaeli', - 'Lilou', - 'Lumen', - 'Manasvi', - 'Lillybeth', - 'Keylani', - 'Lenya', - 'Lidya', - 'Mulan', - 'Nirvi', - 'Ondine', - 'Meenakshi', - 'Mathea', - 'Melyna', - 'Io', - 'Izelle', - 'Jailia', - 'Eztli', - 'Gali', - 'Hade', - 'Hafsah', - 'Hannahgrace', - 'Kayleah', - 'Kayleeann', - 'Kemily', - 'Jeylah', - 'Jiaqi', - 'Sherrika', - 'Daffney', - 'Solstice', - 'Soriah', - 'Sumayya', - 'Saory', - 'Shaily', - 'Shanzay', - 'Sharvi', - 'Xylina', - 'Yeimy', - 'Yizel', - 'Zaidee', - 'Ziah', - 'Jesucita', - 'Madalena', - 'Vontresa', - 'Tangee', - 'Shekina', - 'Sista', - 'Norvis', - 'Winnell', - 'Yoshida', - 'Nikiya', - 'Vidala', - 'Shandria', - 'Rozelle', - 'Maragret', - 'Sixta', - 'Theta', - 'Wylma', - 'Jobita', - 'Gaudalupe', - 'Lurlean', - 'Oveta', - 'Heriberta', - 'Bacilia', - 'Senorina', - 'Denika', - 'Akeisha', - 'Tamecia', - 'Jera', - 'Crestina', - 'Shwanda', - 'Kelbie', - 'Sanayah', - 'Zaliah', - 'Nadezhda', - 'Maaliyah', - 'Mahaley', - 'Raziyah', - 'Saraiya', - 'Cyriah', - 'Chaniyah', - 'Emmarae', - 'Eleen', - 'Ashland', - 'Briniyah', - 'Ainhoa', - 'Aviyah', - 'Atarah', - 'Lutrelle', - 'Clevie', - 'Blossie', - 'Cola', - 'Para', - 'Verdelle', - 'Beddie', - 'Lilliemae', - 'Jurell', - 'Bertice', - 'Fozie', - 'Oppie', - 'Rozia', - 'Rozie', - 'Epsie', - 'Karman', - 'Estoria', - 'Dynesha', - 'Sarae', - 'Xolani', - 'Talyah', - 'Zanaria', - 'Zamiah', - 'Starkeisha', - 'Alys', - 'Izaria', - 'Cayenne', - 'Damiah', - 'Alwilda', - 'Leoda', - 'Yariah', - 'Tuleen', - 'Rhelda', - 'Carlesha', - 'Alfretta', - 'Orma', - 'Ornella', - 'Nazyia', - 'Samorah', - 'Keyonni', - 'Jeriyah', - 'Jazariyah', - 'Demaria', - 'Mikeyla', - 'Malania', - 'Miyanna', - 'Neriyah', - 'Naelle', - 'Lazariah', - 'Rea', - 'Annaya', - 'Aleanna', - 'Baylin', - 'Aela', - 'Emmilyn', - 'Anila', - 'Rodnesha', - 'Janeliz', - 'Kseniya', - 'Nyana', - 'Zemirah', - 'Somya', - 'Yanna', - 'Terryn', - 'Naika', - 'Laiyla', - 'Lyrica', - 'Loralie', - 'Lilya', - 'Wonnie', - 'Runelle', - 'Tynleigh', - 'Loralye', - 'Arynn', - 'Melvis', - 'Akiyah', - 'Matline', - 'Ellean', - 'Wylean', - 'Marfa', - 'Elliemae', - 'Nancey', - 'Waltina', - 'Ommie', - 'Lonia', - 'Reaver', - 'Virdell', - 'Rosabell', - 'Sarahgrace', - 'Faustine', - 'Euretha', - 'Sussie', - 'Rebie', - 'Oveline', - 'Reathel', - 'Algia', - 'Mylissa', - 'Rethel', - 'Nakyla', - 'Necia', - 'Deanie', - 'Beckey', - 'Yasmen', - 'Yukari', - 'Zamyra', - 'Roselinda', - 'Takeko', - 'Vicke', - 'Mckala', - 'Hanae', - 'Elley', - 'Ellyssa', - 'Geanna', - 'Geetika', - 'Elenoa', - 'Elane', - 'Deeya', - 'Deviny', - 'Genecis', - 'Jasminerose', - 'Ireri', - 'Hailei', - 'Hannya', - 'Harshini', - 'Holiday', - 'Arista', - 'Dannae', - 'Melayna', - 'Meleni', - 'Mystique', - 'Nathalya', - 'Natsumi', - 'Sharlize', - 'Shine', - 'Sindhu', - 'Starlyn', - 'Sarika', - 'Sarine', - 'Seleen', - 'Khalea', - 'Kirti', - 'Jocilyn', - 'Maille', - 'Mariaceleste', - 'Leelee', - 'Leidi', - 'Libertad', - 'Lizvet', - 'Kierstan', - 'Adja', - 'Debbye', - 'Dorenda', - 'Kiyono', - 'Katsuko', - 'Katsue', - 'Misue', - 'Umeno', - 'Rayvin', - 'Sachie', - 'Kinue', - 'Danajah', - 'Denay', - 'Tsuneko', - 'Tamae', - 'Saeko', - 'Tsutako', - 'Sumako', - 'Momoe', - 'Tomoko', - 'Asae', - 'Nautika', - 'Kourtnee', - 'Keauna', - 'Maydeen', - 'Chianne', - 'Macala', - 'Briaunna', - 'Ceirra', - 'Kimberlea', - 'Normalinda', - 'Milinda', - 'Jonetta', - 'Seleta', - 'Chryl', - 'Aaminah', - 'Mersades', - 'Mickenzie', - 'Tahlor', - 'Kimetha', - 'Hopie', - 'Guadulupe', - 'Blakelynn', - 'Orfelinda', - 'Aubre', - 'Ajayla', - 'Makenlee', - 'Journii', - 'Janayla', - 'Talulah', - 'Siddhi', - 'Shaira', - 'Yuridiana', - 'Yulitza', - 'Tulsi', - 'Yatana', - 'Jaleya', - 'Ayrianna', - 'Damaya', - 'Myana', - 'Lanyiah', - 'Kadince', - 'Aunna', - 'Avrielle', - 'Khyli', - 'Kariyah', - 'Bralynn', - 'Derrianna', - 'Maryella', - 'Charlynn', - 'Ilma', - 'Tresea', - 'Mersadies', - 'Macenzie', - 'Terriona', - 'Telia', - 'Tamryn', - 'Tahari', - 'Solyana', - 'Lyrical', - 'Akie', - 'Teruyo', - 'Shizuyo', - 'Tsuruyo', - 'Daviona', - 'Marshelia', - 'Connye', - 'Marka', - 'Adelmira', - 'Dorelia', - 'Nirel', - 'Oceanna', - 'Neeka', - 'Sherolyn', - 'Sheralyn', - 'Sharlet', - 'Milenka', - 'Astha', - 'Angeleena', - 'Anysia', - 'Apoorva', - 'Bryanah', - 'Carolyna', - 'Cecy', - 'Anadalay', - 'Akaylah', - 'Aika', - 'Aasha', - 'Ahniah', - 'Adelayda', - 'Kyaira', - 'Manmeet', - 'Linsy', - 'Malini', - 'Mairany', - 'Haeley', - 'Evelen', - 'Jezel', - 'Jinelle', - 'Joleena', - 'Hikari', - 'Inari', - 'Itcel', - 'Lokelani', - 'Keikilani', - 'Sherilynn', - 'Jamieann', - 'Lajuanna', - 'Roselind', - 'Rhetta', - 'Alysah', - 'Ameyalli', - 'Abigayl', - 'Aizza', - 'Alaiza', - 'Aslyn', - 'Anjalee', - 'Annaliza', - 'Antara', - 'Areen', - 'Carra', - 'Katieann', - 'Kimla', - 'Xan', - 'Mikiala', - 'Chrissa', - 'Belanna', - 'Ankitha', - 'Celestial', - 'Chiana', - 'Akhila', - 'Alique', - 'Alyssamae', - 'Betheny', - 'Stepheny', - 'Brittanyann', - 'Adonna', - 'Barbarella', - 'Shalamar', - 'Flecia', - 'Dlisa', - 'Anabelia', - 'Velen', - 'Xotchil', - 'Yairis', - 'Lytzy', - 'Faizah', - 'Eilleen', - 'Elona', - 'Esteffany', - 'Jesyka', - 'Jhovana', - 'Jisell', - 'Joclyn', - 'Teel', - 'Sundee', - 'Mechell', - 'Lisia', - 'Nandita', - 'Natalina', - 'Nattalie', - 'Rosaelena', - 'Siclali', - 'Skyllar', - 'Taeya', - 'Sadey', - 'Sadira', - 'Sanae', - 'Serenah', - 'Shamila', - 'Brizza', - 'Chalisa', - 'Shakeela', - 'Gordean', - 'Akane', - 'Akansha', - 'Angeni', - 'Annalina', - 'Anushree', - 'Allexa', - 'Katelynd', - 'Raenette', - 'Airiel', - 'Matina', - 'Teira', - 'Deatra', - 'Darolyn', - 'Hilliary', - 'Roanna', - 'Prissy', - 'Monya', - 'Armelinda', - 'Ginnie', - 'Darenda', - 'Leslea', - 'Marcedes', - 'Jeweliana', - 'Jewelissa', - 'Josselyne', - 'Lavanya', - 'Koryn', - 'Khushpreet', - 'Kierah', - 'Cyana', - 'Deeana', - 'Bibianna', - 'Bryannah', - 'Heidie', - 'Desteni', - 'Elleanna', - 'Sierah', - 'Sumedha', - 'Shantall', - 'Yarissa', - 'Yerania', - 'Tifanny', - 'Mehek', - 'Mirely', - 'Mitra', - 'Mar', - 'Rohini', - 'Prerana', - 'Naizeth', - 'Naydeli', - 'Melveen', - 'Moani', - 'Endora', - 'Jackquline', - 'Stefanny', - 'Tamanna', - 'Sofija', - 'Zitlalic', - 'Ymani', - 'Jumana', - 'Kailene', - 'Josephyne', - 'Leiya', - 'Letzy', - 'Litsy', - 'Lizbett', - 'Lizveth', - 'Jaiya', - 'Dreanna', - 'Celestia', - 'Electra', - 'Sevanna', - 'Sidnie', - 'Semone', - 'Sharra', - 'Sharlette', - 'Selinda', - 'Saumya', - 'Meilan', - 'Melea', - 'Maleeha', - 'Mitali', - 'Rheana', - 'Ruchi', - 'Oasis', - 'Preethi', - 'Aungelique', - 'Kristl', - 'Tashala', - 'Darcell', - 'Rolinda', - 'Toye', - 'Shirlyn', - 'Yvonda', - 'Tymia', - 'Oteka', - 'Ladora', - 'Deashia', - 'Janautica', - 'Sonnet', - 'Sucely', - 'Suriah', - 'Tallula', - 'Sanna', - 'Seniyah', - 'Seri', - 'Yexalen', - 'Yumiko', - 'Zayana', - 'Zohal', - 'Valerye', - 'Yarisbeth', - 'Vivyana', - 'Xela', - 'Brithanny', - 'Jasira', - 'Jenessy', - 'Jezebelle', - 'Leahna', - 'Leilanee', - 'Leily', - 'Kohana', - 'Dorsa', - 'Elanna', - 'Caralyn', - 'Erilyn', - 'Halyn', - 'Helayna', - 'Lionor', - 'Maela', - 'Masha', - 'Myley', - 'Malaak', - 'Malai', - 'Mariapaula', - 'Nathalye', - 'Remie', - 'Parnika', - 'Neveen', - 'Cherith', - 'Orvella', - 'Aurion', - 'Shonterria', - 'Natoria', - 'Shaterria', - 'Clo', - 'Donnia', - 'Cana', - 'Niaya', - 'Brelyn', - 'Aalliyah', - 'Shaaron', - 'Doylene', - 'Lowanda', - 'Henryetta', - 'Obera', - 'Marykathryn', - 'Dema', - 'Arcadia', - 'Lodema', - 'Aloni', - 'Analya', - 'Aashritha', - 'Ayani', - 'Audreena', - 'Audrena', - 'Ariahna', - 'Antonela', - 'Atzi', - 'Amunet', - 'Jaala', - 'Keambria', - 'Kanaya', - 'Emya', - 'Deijah', - 'Dayjah', - 'Tiye', - 'Nyja', - 'Markesia', - 'Valla', - 'Cesaria', - 'Eusevia', - 'Elpidia', - 'Jaquisha', - 'Romanita', - 'Shauntia', - 'Chasmine', - 'Deneisha', - 'Quatesha', - 'Nicosha', - 'Shandricka', - 'Shambria', - 'Shakerra', - 'Santrice', - 'Quinesha', - 'Shantika', - 'Roderica', - 'Whitnie', - 'Piedad', - 'Koleta', - 'Brazil', - 'Aamina', - 'Adaleen', - 'Adyline', - 'Bricola', - 'Analeigha', - 'Anara', - 'Ladawna', - 'Ruperta', - 'Deaundra', - 'Jaleisa', - 'Keria', - 'Sharaine', - 'Shanekqua', - 'Shanekia', - 'Kenyanna', - 'Jacoria', - 'Airianna', - 'Amana', - 'Amariz', - 'Ammi', - 'Miaya', - 'Aaniya', - 'Anaisha', - 'Bellina', - 'Annasofia', - 'Archita', - 'Arianie', - 'Shaquandra', - 'Shakeyra', - 'Tiandra', - 'Soveida', - 'Gonzala', - 'Gaylia', - 'Freddye', - 'Roxi', - 'Neya', - 'Nitika', - 'Noriah', - 'Raha', - 'Briah', - 'Syrah', - 'Talise', - 'Tarynn', - 'Tianah', - 'Solay', - 'Saraiah', - 'Sherlynn', - 'Leylany', - 'Lilu', - 'Maelie', - 'Lexxie', - 'Monzeratt', - 'Nari', - 'Naveyah', - 'Mianna', - 'Maylea', - 'Mery', - 'Marene', - 'Zeba', - 'Xymena', - 'Yaremi', - 'Yari', - 'Yulie', - 'Lile', - 'Dafnee', - 'Indra', - 'Itzelle', - 'Evangaline', - 'Evelett', - 'Evely', - 'Ghazal', - 'Arnisha', - 'Kassia', - 'Kayah', - 'Kalliyan', - 'Diannia', - 'Damyah', - 'Torianna', - 'Talasia', - 'Zakira', - 'Zyah', - 'Masiya', - 'Rhyanna', - 'Kemaya', - 'Jadasia', - 'Kanijah', - 'Henleigh', - 'Ciella', - 'Dayanne', - 'Ivannia', - 'Heydy', - 'Fergie', - 'Fianna', - 'Goretti', - 'Gwynneth', - 'Gyanna', - 'Haidi', - 'Christabella', - 'Angelinah', - 'Anina', - 'Annya', - 'Alejah', - 'Bradie', - 'Breanah', - 'Arihana', - 'Aryona', - 'Ashwika', - 'Aylet', - 'Ayleth', - 'Meleena', - 'Micel', - 'Misel', - 'Naiema', - 'Meiling', - 'Malaia', - 'Rehanna', - 'Raengel', - 'Padma', - 'Majestic', - 'Katelen', - 'Jenaveve', - 'Jennessy', - 'Jewelisa', - 'Joelie', - 'Lyliana', - 'Mahati', - 'Sherral', - 'Kamariah', - 'Larsen', - 'Khaniya', - 'Jakiah', - 'Darionna', - 'Bristal', - 'Ahlana', - 'Aireanna', - 'Alaila', - 'Jarethzy', - 'Orfalinda', - 'Nataliah', - 'Nayra', - 'Nishika', - 'Meeya', - 'Sanaia', - 'Sensi', - 'Percilla', - 'Pranathi', - 'Kathrynn', - 'Katriel', - 'Jordanna', - 'Jessilyn', - 'Jilliana', - 'Madeira', - 'Laia', - 'Leala', - 'Courtlynn', - 'Ahriana', - 'Aliena', - 'Adalay', - 'Nakyia', - 'Niema', - 'Leeasia', - 'Evenny', - 'Dorismar', - 'Dyanara', - 'Elonna', - 'Estreya', - 'Ashmita', - 'Anureet', - 'Angeliah', - 'Annaliz', - 'Dallanara', - 'Danaly', - 'Carely', - 'Sevilla', - 'Aleigh', - 'Allianna', - 'Alamar', - 'Jaiah', - 'Shellsea', - 'Sheylin', - 'Sonoma', - 'Hayla', - 'Yoali', - 'Yzabel', - 'Zeenat', - 'Zienna', - 'Shirlynn', - 'Shilynn', - 'Raphaella', - 'Makyia', - 'Inola', - 'Omaria', - 'Michiah', - 'Anareli', - 'Anacamila', - 'Anahis', - 'Anapaola', - 'Clowie', - 'Brizia', - 'Alexssa', - 'Ailanie', - 'Aileene', - 'Francille', - 'Jatoria', - 'Jaquitta', - 'Sybol', - 'Landra', - 'Danyela', - 'Cubia', - 'Arabela', - 'Adelfina', - 'Quaniya', - 'Paulyne', - 'Vanteen', - 'Treba', - 'Kaylena', - 'Kaelynne', - 'Kalanie', - 'Lezli', - 'Lithzy', - 'Lanessa', - 'Laylene', - 'Leilaney', - 'Emmajean', - 'Francella', - 'Eiliyah', - 'Jadey', - 'Jamilett', - 'Ingris', - 'Tayanna', - 'Skarlette', - 'Sady', - 'Senia', - 'Yakeline', - 'Yenna', - 'Yesmin', - 'Meily', - 'Mikeila', - 'Miu', - 'Rakel', - 'Niveah', - 'Nyemah', - 'Gorgeous', - 'Zaraya', - 'Lavaeh', - 'Meila', - 'Labella', - 'Lilyona', - 'Zykierra', - 'Orfa', - 'Seriyah', - 'Shivali', - 'Sibylla', - 'Sua', - 'Ulani', - 'Vianet', - 'Yanell', - 'Yolette', - 'Yudany', - 'Suheidy', - 'Sukhpreet', - 'Syanna', - 'Tatevik', - 'Tayde', - 'Sameria', - 'Mikiya', - 'Claramae', - 'Audine', - 'Francile', - 'Tynia', - 'Goddess', - 'Samoria', - 'Llana', - 'Oveda', - 'Amelya', - 'Auda', - 'Disaya', - 'Zanyah', - 'Samiyyah', - 'Jaianna', - 'Ruqayyah', - 'Nakira', - 'Shamirah', - 'Ta', - 'Giani', - 'Brya', - 'Cyani', - 'Ashiyah', - 'Kahli', - 'Beauton', - 'Kashay', - 'Sadiyah', - 'Mikaya', - 'Nasira', - 'Nasirah', - 'Ariauna', - 'Yasirah', - 'Skyelynn', - 'Naailah', - 'Nyelle', - 'Adessa', - 'Ayriana', - 'Mirielle', - 'Munirah', - 'Layani', - 'Haniyah', - 'Ovida', - 'Haniyyah', - 'Layonna', - 'Jazmarie', - 'Wicahpi', - 'Cante', - 'Zamyah', - 'Tanyiah', - 'Shalita', - 'Salley', - 'Jnya', - 'Santasia', - 'Shaneque', - 'Quantina', - 'Temeika', - 'Narvis', - 'Pearlee', - 'Nykesha', - 'Orrie', - 'Mozter', - 'Earthalee', - 'Rozena', - 'Anniebell', - 'Hannie', - 'Pretto', - 'Caro', - 'Everlina', - 'Arnetha', - 'Glenora', - 'Asalee', - 'Parniece', - 'Rubena', - 'Wilhemena', - 'Perline', - 'Elloree', - 'Clorine', - 'Richardean', - 'Rovena', - 'Arthuree', - 'Mikea', - 'Charnice', - 'Tylashia', - 'Rebacca', - 'Caretha', - 'Dynasti', - 'Marvie', - 'Hermenia', - 'Tekela', - 'Trenace', - 'Valetta', - 'Topaz', - 'Debara', - 'Jaquasha', - 'Markeria', - 'Alkeria', - 'Salwa', - 'Tatayana', - 'Dianelys', - 'Beyounce', - 'Drena', - 'Julysa', - 'Shuntel', - 'Antasia', - 'Alyze', - 'Marytheresa', - 'Raechelle', - 'Trevia', - 'Tomara', - 'Jermeka', - 'Curtisha', - 'Kebrina', - 'Kayte', - 'Shakeila', - 'Ronnesha', - 'Shavontae', - 'Taquila', - 'Shaquia', - 'Lynnann', - 'Markevia', - 'Terrilynn', - 'Carime', - 'Quaneshia', - 'Shaylen', - 'Corneisha', - 'Rodneshia', - 'Nateria', - 'Marycatherine', - 'Ashlyne', - 'Reyne', - 'Natia', - 'Taquisha', - 'Mikeshia', - 'Khadeja', - 'Lismary', - 'Prisca', - 'Antwonette', - 'Anesia', - 'Clotilda', - 'Willavene', - 'Lovey', - 'Aleda', - 'Karita', - 'Rakiyah', - 'Nyasiah', - 'Timaya', - 'Gabryelle', - 'Caniyah', - 'Ethelreda', - 'Aryelle', - 'Trianna', - 'Yesli', - 'Yareliz', - 'Tanyla', - 'Keyshia', - 'Makinsey', - 'Daily', - 'Caylynn', - 'Kalyse', - 'Sarabelle', - 'Araminta', - 'Magdelene', - 'Kristalyn', - 'Lianni', - 'Layana', - 'Haedyn', - 'Teyona', - 'Taziyah', - 'Ranijah', - 'Darneisha', - 'Jahzaria', - 'Palmyra', - 'Altheda', - 'Armanii', - 'Blodwyn', - 'Colletta', - 'Yelenis', - 'Yazlyn', - 'Leira', - 'Anaysia', - 'Anayiah', - 'Valia', - 'Bambina', - 'Burnetta', - 'Clarabel', - 'Philomenia', - 'Lorma', - 'Janeka', - 'Danaisha', - 'Cayci', - 'Jermia', - 'Idalys', - 'Sarajane', - 'Shakenya', - 'Kashanti', - 'Lanika', - 'Ceira', - 'Deshanti', - 'Adianez', - 'Alannis', - 'Lubov', - 'Aylana', - 'Nephtalie', - 'Harlean', - 'Shelvey', - 'Yalissa', - 'Asianna', - 'Jahnyah', - 'Jahliyah', - 'Ellissa', - 'Gabrianna', - 'Katonya', - 'Elsia', - 'Ketina', - 'Kateena', - 'Claudean', - 'Chenita', - 'Belkys', - 'Kerryn', - 'Teria', - 'Charron', - 'Charnissa', - 'Alura', - 'Bashirah', - 'Gerldine', - 'Katilynn', - 'Trellany', - 'Lacheryl', - 'Twalla', - 'Sharnise', - 'Yoland', - 'Shanai', - 'Ikia', - 'Aquilla', - 'Shalandra', - 'Nekesha', - 'Sonni', - 'Kutana', - 'Sharnay', - 'Timitra', - 'Shareena', - 'Tyeesha', - 'Natara', - 'Amatullah', - 'Nydirah', - 'Shahadah', - 'Inetha', - 'Clatie', - 'Ladye', - 'Makalia', - 'Sabriyah', - 'Graple', - 'Lorell', - 'Vercie', - 'Rayona', - 'Dayshia', - 'Nakirah', - 'Mcneva', - 'Bunia', - 'Brooxie', - 'Delcia', - 'Naje', - 'Eilish', - 'Lashara', - 'Crystall', - 'Shearon', - 'Kafi', - 'Kea', - 'Shantrel', - 'Jeanni', - 'Andreia', - 'Myrlande', - 'Jennifier', - 'Damika', - 'Carloyn', - 'Lashera', - 'Kamika', - 'Chrisann', - 'Lashavia', - 'Ivis', - 'Quinisha', - 'Yanelys', - 'Taralee', - 'Ibis', - 'Jazma', - 'Shakevia', - 'Deneane', - 'Kimala', - 'Casee', - 'Audreana', - 'Shahida', - 'Latangela', - 'Lashira', - 'Lashawndra', - 'Sherrina', - 'Shawntrell', - 'Latronda', - 'Meghaan', - 'Ayasha', - 'Raushanah', - 'Serrita', - 'Tennile', - 'Keyonda', - 'Idalmis', - 'Telicia', - 'Takeia', - 'Aristea', - 'Letesha', - 'Badia', - 'Nykea', - 'Bilan', - 'Ieva', - 'Kimmi', - 'Geniel', - 'Tamberly', - 'Tammee', - 'Sherma', - 'Emira', - 'Agena', - 'Carrin', - 'Ladean', - 'Caera', - 'Shatha', - 'Utahna', - 'Lujean', - 'Joylyn', - 'Kathren', - 'Kristiane', - 'Lenee', - 'Angi', - 'Vichelle', - 'Rochele', - 'Shonnie', - 'Anastasija', - 'Clea', - 'Myrlene', - 'Dniyah', - 'Tashanti', - 'Sireen', - 'Vincie', - 'Wreatha', - 'Josphine', - 'Casimera', - 'Hildagarde', - 'Margeret', - 'Grettell', - 'Greenley', - 'Gloriana', - 'Eyleen', - 'Evaleigh', - 'Davanee', - 'Corley', - 'Liliah', - 'Leanah', - 'Kynzlie', - 'Kynzleigh', - 'Kolette', - 'Lively', - 'Makenlie', - 'Lochlyn', - 'Kinslie', - 'Jleigh', - 'Jeslynn', - 'Jenisis', - 'Jenisha', - 'Kensli', - 'Addalie', - 'Demia', - 'Cele', - 'Aderinsola', - 'Auriella', - 'Blyss', - 'Cashlynn', - 'Callyn', - 'Allyzon', - 'Aleiya', - 'Alazne', - 'Alayzia', - 'Ailah', - 'Annora', - 'Analynn', - 'Leonilda', - 'Minnette', - 'Onolee', - 'Michaelina', - 'Rosemond', - 'Milica', - 'Ednamae', - 'Floribel', - 'Nur', - 'Ndia', - 'Thecla', - 'Immaculate', - 'Mayfred', - 'Selda', - 'Vincenzia', - 'Vitina', - 'Tammatha', - 'Joley', - 'Kelene', - 'Kriste', - 'Liese', - 'Mariaemilia', - 'Lasaundra', - 'Letica', - 'Karene', - 'Devera', - 'Denyce', - 'Dawnn', - 'Maryum', - 'Giovannina', - 'Roze', - 'Reygan', - 'Quinlyn', - 'Stassi', - 'Meelah', - 'Novaleigh', - 'Navey', - 'Mirakle', - 'Naiovy', - 'Munachiso', - 'Montzerrat', - 'Misk', - 'Mireyah', - 'Temiloluwa', - 'Zaiya', - 'Varshini', - 'Tiwatope', - 'Tinlee', - 'Geneve', - 'Kotryna', - 'Janila', - 'Janeah', - 'Mollye', - 'Dody', - 'Doreena', - 'Chelle', - 'Javaeh', - 'Dim', - 'Jamylah', - 'Kamyia', - 'Ramie', - 'Kandie', - 'Kitt', - 'Gaylyn', - 'Marji', - 'Laurena', - 'Lorre', - 'Ronelle', - 'Kresta', - 'Jonylah', - 'Kornelia', - 'Mindie', - 'Kendis', - 'Dorri', - 'Seaneen', - 'Lorilyn', - 'Lolly', - 'Pati', - 'Shalayne', - 'Dorise', - 'Joani', - 'Yailene', - 'Batool', - 'Cyntha', - 'Coni', - 'Kae', - 'Cynia', - 'Rhonna', - 'Lynnetta', - 'Terrisa', - 'Nishi', - 'Delise', - 'Ladena', - 'Bronwen', - 'Tere', - 'Tippi', - 'Peggi', - 'Portland', - 'Sherrin', - 'Tacy', - 'Terie', - 'Dore', - 'Daphane', - 'Juliene', - 'Kamile', - 'Janeil', - 'Megin', - 'Shenandoah', - 'Rashada', - 'Disa', - 'Elita', - 'Kelee', - 'Genee', - 'Taneya', - 'Storie', - 'Sheza', - 'Rielyn', - 'Venicia', - 'Zamyria', - 'Yisell', - 'Appollonia', - 'Meryle', - 'Frann', - 'Lucyann', - 'Clarivel', - 'Marguarite', - 'Nelsa', - 'Reanetta', - 'Roshaunda', - 'Channie', - 'Bathsheba', - 'Jannessa', - 'Jakaylah', - 'Jesalyn', - 'Ellyson', - 'Hally', - 'Haelyn', - 'Gabbie', - 'Emmerie', - 'Makailyn', - 'Maddi', - 'Lirio', - 'Lexee', - 'Matalyn', - 'Kenzee', - 'Kenlei', - 'Kaydi', - 'Kynlei', - 'Krissa', - 'Adalin', - 'Alayiah', - 'Ellice', - 'Caydee', - 'Annalysa', - 'Anisty', - 'Abeni', - 'Aliha', - 'Aerith', - 'Adrie', - 'Peggyann', - 'Pietrina', - 'Amberlie', - 'Dabria', - 'Cylee', - 'Amyriah', - 'Ambry', - 'Berkleigh', - 'Azula', - 'Zaryiah', - 'Zanyia', - 'Gerardine', - 'Joycelynn', - 'Jeslin', - 'Kenzli', - 'Keisi', - 'Kayelynn', - 'Jaselyn', - 'Mckinnley', - 'Maryse', - 'Peightyn', - 'Latausha', - 'Lety', - 'Tekia', - 'Arasely', - 'Arlynne', - 'Noell', - 'Patrcia', - 'Morning', - 'Meika', - 'Tanda', - 'Terasa', - 'Tika', - 'Roshon', - 'Marlaine', - 'Stephaie', - 'Franne', - 'Ewa', - 'Tomeca', - 'Chequita', - 'Dierdra', - 'Doriann', - 'Tammika', - 'Jeananne', - 'Cythia', - 'Laconda', - 'Catiria', - 'Migna', - 'Latiesha', - 'Sharin', - 'Tekesha', - 'Elga', - 'Barbarajean', - 'Ilena', - 'Evett', - 'Timiko', - 'Kachina', - 'Desere', - 'Galadriel', - 'Lynea', - 'Laurajean', - 'Rukiya', - 'Sakara', - 'Snezana', - 'Tashonda', - 'Orquidea', - 'Myshia', - 'Latrease', - 'Monquie', - 'Robina', - 'Vesna', - 'Faline', - 'Glori', - 'Jennel', - 'Keyatta', - 'Dimitria', - 'Uzma', - 'Lalia', - 'Krystiana', - 'Kaedynce', - 'Juany', - 'Kesley', - 'Kennedee', - 'Keeleigh', - 'Paiten', - 'Neelah', - 'Naylee', - 'Sairy', - 'Rocsi', - 'Mckenzey', - 'Modesty', - 'Abbiegail', - 'Jasalyn', - 'Genises', - 'Emmory', - 'Elisea', - 'Dlaney', - 'Haelee', - 'Jadence', - 'Audryana', - 'Carizma', - 'Josanne', - 'Nashira', - 'Meesha', - 'Taneil', - 'Sobeida', - 'Zakyra', - 'Syndee', - 'Zipora', - 'Amita', - 'Bridie', - 'Hilde', - 'Aspasia', - 'Yalexi', - 'Tenleigh', - 'Anjannette', - 'Zniyah', - 'Zayley', - 'Kyerra', - 'Lynnsey', - 'Dashae', - 'Jasha', - 'Anjenette', - 'Lelania', - 'Mija', - 'Lorrene', - 'Shanyn', - 'Shindana', - 'Shamra', - 'Dove', - 'Drina', - 'Caralee', - 'Charmian', - 'Katrine', - 'Lagina', - 'Jahna', - 'Nesita', - 'Teriana', - 'Dajae', - 'Kyiah', - 'Keslyn', - 'Kayelee', - 'Kamberlyn', - 'Raygen', - 'Orchid', - 'Maleigh', - 'Mairim', - 'Amily', - 'Ameli', - 'Alie', - 'Adelai', - 'Eniola', - 'Enaya', - 'Brealynn', - 'Blakleigh', - 'Ayelene', - 'Camrie', - 'Dianely', - 'Delayne', - 'Cortlyn', - 'Jaylei', - 'Jaycelynn', - 'Jaleigha', - 'Iviana', - 'Kaedance', - 'Jewelz', - 'Jillianna', - 'Faithlyn', - 'Isabeau', - 'Irany', - 'Galiana', - 'Makynzee', - 'Maebry', - 'Merit', - 'Mckinzee', - 'Kinzee', - 'Kendrah', - 'Laityn', - 'Amberlin', - 'Ahliyah', - 'Raphaela', - 'Ameri', - 'Brecklynn', - 'Cristabel', - 'Annalucia', - 'Avri', - 'Averly', - 'Shalia', - 'Sheilla', - 'Dejana', - 'Tonnette', - 'Tracia', - 'Trese', - 'Lalanya', - 'Kristiann', - 'Zunaira', - 'Zinachidi', - 'Xayla', - 'Zaybree', - 'Zanae', - 'Xoey', - 'Sirenity', - 'Renesme', - 'Raeley', - 'Preslyn', - 'Nyx', - 'Nyelli', - 'Rozalynn', - 'Safaa', - 'Abaigeal', - 'Perle', - 'Ersilia', - 'Ethlyn', - 'Dashanae', - 'Dajana', - 'Tahja', - 'Shavona', - 'Vernisha', - 'Sunya', - 'Zenorah', - 'Dorota', - 'Ramsha', - 'Nirali', - 'Najia', - 'Maryclaire', - 'Ismay', - 'Alfonsina', - 'Letizia', - 'Lotta', - 'Honore', - 'Jamille', - 'Kashe', - 'Bonnielee', - 'Lorelle', - 'Gloriajean', - 'Trenae', - 'Tonesha', - 'Maxene', - 'Aliz', - 'Annelyse', - 'Avagrace', - 'Adanelly', - 'Dariella', - 'Colbi', - 'Tema', - 'Marlea', - 'Elleen', - 'Veroncia', - 'Shelina', - 'Sundae', - 'Jericca', - 'Liduvina', - 'Jenney', - 'Pascha', - 'Roshell', - 'Marlies', - 'Marny', - 'Judithann', - 'Nancylee', - 'Freyda', - 'Joyceann', - 'Caroleann', - 'Desirie', - 'Christol', - 'Shulamith', - 'Marlise', - 'Rocquel', - 'Tamsen', - 'Sukari', - 'Tinna', - 'Magdelena', - 'Ruba', - 'Patra', - 'Erryn', - 'Buffi', - 'Chantil', - 'Kerensa', - 'Annastacia', - 'Zailee', - 'Lamika', - 'Kashlynn', - 'Jaedynn', - 'Kaly', - 'Paisyn', - 'Seraiah', - 'Mckenzye', - 'Nhyla', - 'Chandrika', - 'Dawana', - 'Elesha', - 'Caryle', - 'Karrin', - 'Valency', - 'Kianga', - 'Shawndee', - 'Tamasha', - 'Rhodora', - 'Shivangi', - 'Vermont', - 'Diasia', - 'Aniyyah', - 'Azhane', - 'Katleyn', - 'Tynetta', - 'Negan', - 'Marilyne', - 'Leronia', - 'Charmie', - 'Lateefa', - 'Hassanah', - 'Louvinia', - 'Shirly', - 'Sanjna', - 'Andelyn', - 'Jaima', - 'Aftyn', - 'Atira', - 'Weslie', - 'Tayzlee', - 'Rossi', - 'Nayvie', - 'Livvy', - 'Brinklee', - 'Drinda', - 'Nazirah', - 'Krithika', - 'Taisley', - 'Starlee', - 'Bijal', - 'Hiral', - 'Gwynn', - 'Orlene', - 'Maurene', - 'Sweta', - 'Naasia', - 'Luvinia', - 'Sayoko', - 'Geannie', - 'Rupal', - 'Zerlina', - 'Nobu', - 'Taeko', - 'Miye', - 'Carnation', - 'Joplin', - 'Yayeko', - 'Sakaye', - 'Ernell', - 'Tazuko', - 'Bayyinah', - 'Konstantina', - 'Danuta', - 'Cariann', - 'Charnette', - 'Michiye', - 'Tejal', - 'Shaheedah', - 'Zakkiyya', - 'Latoyah', - 'Audre', - 'Tayeko', - 'Qadriyyah', - 'Nikema', - 'Wadeeah', - 'Quanika', - 'Fareeda', - 'Ivelis', - 'Karigan', - 'Yayoi', - 'Tauni', - 'Shailee', - 'Ronnah', - 'Roseana', - 'Rosalita', - 'Orlidia', - 'Mckall', - 'Seattle', - 'Lauree', - 'Georgi', - 'Jacolyn', - 'Meichele', - 'Starlet', - 'Shandee', - 'Miquelle', - 'Cathe', - 'Nondas', - 'Roben', - 'Manette', - 'Monzelle', - 'Genieve', - 'Rumaysa', - 'Dariya', - 'Brynnleigh', - 'Vicci', - 'Sharli', - 'Chandi', - 'Guadelupe', - 'Jamilyn', - 'Willadene', - 'Centhia', - 'Cheryal', - 'Normalee', - 'Wilmajean', - 'Roanne', - 'Dyane', - 'Jinx', - 'Jorene', - 'Ceceilia', - 'Arikka', - 'Latanza', - 'Lacinda', - 'Rus', - 'Sangeeta', - 'Demita', - 'Jerene', - 'Marcellina', - 'Zani', - 'Izzabelle', - 'Graycee', - 'Sajada', - 'Quinlee', - 'Brooklee', - 'Shulamis', - 'Bunnie', - 'Michaelyn', - 'Dhruvi', - 'Sreeja', - 'Tzipa', - 'Doreene', - 'Bedelia', - 'Eutimia', - 'Tomacita', - 'Jerra', - 'Rosela', - 'Ignacita', - 'Conferina', - 'Andreita', - 'Lugardita', - 'Estefanita', - 'Suetta', - 'Debbe', - 'Amadita', - 'Mardel', - 'Mliss', - 'Korla', - 'Felipita', - 'Erminda', - 'Chrys', - 'Karthika', - 'Guilianna', - 'Chasya', - 'Bryndee', - 'Taeler', - 'Sinforosa', - 'Brinnley', - 'Aviya', - 'Jayma', - 'Zimal', - 'Vivia', - 'Arielis', - 'Arshiya', - 'Adiba', - 'Afreen', - 'Ajooni', - 'Alianny', - 'Fariza', - 'Breina', - 'Sila', - 'Aaima', - 'Amesha', - 'Antigone', - 'Kayse', - 'Aurelie', - 'Marianny', - 'Naba', - 'Salimata', - 'Retal', - 'Pema', - 'Pesha', - 'Reemas', - 'Emunah', - 'Farzeen', - 'Safina', - 'Sema', - 'Seynabou', - 'Roza', - 'Romaisa', - 'Yehudit', - 'Tzivi', - 'Tzivy', - 'Zahro', - 'Jeylen', - 'Klea', - 'Namirah', - 'Lamiah', - 'Mahjabeen', - 'Daielle', - 'Ogechi', - 'Laresha', - 'Laqueta', - 'Anayla', - 'Bashy', - 'Naeema', - 'Sarrinah', - 'Sevinch', - 'Frimmy', - 'Hibba', - 'Fajr', - 'Rayhona', - 'Rokia', - 'Wafa', - 'Britne', - 'Crystalann', - 'Reah', - 'Maggi', - 'Lenae', - 'Kambra', - 'Tabita', - 'Tamlyn', - 'Thuytien', - 'Titianna', - 'Trenisha', - 'Yuan', - 'Yarithza', - 'Yarixa', - 'Satin', - 'Elizeth', - 'Gabiela', - 'Jackline', - 'Janisa', - 'Graviela', - 'Gudalupe', - 'Hena', - 'Bryanda', - 'Avilene', - 'Ayerim', - 'Breiana', - 'Nicoleanne', - 'Merisa', - 'Relina', - 'Rebecah', - 'Rachyl', - 'Kasaundra', - 'Katryn', - 'Jeaneth', - 'Jenah', - 'Jocely', - 'Jorgina', - 'Lindsee', - 'Lizvette', - 'Oleen', - 'Waveline', - 'Laurabelle', - 'Charma', - 'Gleneva', - 'Yesika', - 'Felina', - 'Nguyet', - 'Krissie', - 'Silvina', - 'Stephanny', - 'Teera', - 'Kristol', - 'Karisha', - 'Lorisa', - 'Iracema', - 'Temesha', - 'Tamber', - 'Shelisa', - 'Roshana', - 'Rheannon', - 'Amala', - 'Anabelen', - 'Daizhane', - 'Darbie', - 'Dezaree', - 'Dezhane', - 'Carrina', - 'Chessa', - 'Christinejoy', - 'Aliea', - 'Adalhi', - 'Alexandrina', - 'Abrina', - 'Madaleine', - 'Maressa', - 'Marki', - 'Koryna', - 'Lilibet', - 'Mystic', - 'Neyra', - 'Ivonna', - 'Jenalyn', - 'Truc', - 'Berneta', - 'Quinci', - 'Rachelanne', - 'Raylina', - 'Nykole', - 'Stephaney', - 'Seleni', - 'Marvene', - 'Melizza', - 'Aimme', - 'Anaissa', - 'Anhelica', - 'Celyna', - 'Azalie', - 'Bereniz', - 'Meliss', - 'Leanza', - 'Lenina', - 'Karrina', - 'Kalynne', - 'Kanwal', - 'Kazzandra', - 'Mandalyn', - 'Limairy', - 'Lizzete', - 'Lyly', - 'Coua', - 'Icsel', - 'Izamary', - 'Lakindra', - 'Rosezella', - 'Wilhelmine', - 'Clela', - 'Marvelle', - 'Jenafer', - 'Katye', - 'Eliabeth', - 'Angelicamaria', - 'Adrieanna', - 'Caludia', - 'Caycee', - 'Chenay', - 'Cherika', - 'Arpine', - 'Kimberlyanne', - 'Jully', - 'Jyoti', - 'Mariha', - 'Meganelizabeth', - 'Melysa', - 'Lashanay', - 'Jericha', - 'Eliset', - 'Esmirna', - 'Clarie', - 'Conny', - 'Derrisha', - 'Frania', - 'Jeena', - 'Gresia', - 'Hlee', - 'Emanie', - 'Liany', - 'Aisatou', - 'Ashya', - 'Nefertari', - 'Nyanna', - 'Mariem', - 'Michellee', - 'Amenda', - 'Markella', - 'Kiyara', - 'Issamar', - 'Cecilee', - 'Rehana', - 'Nube', - 'Simy', - 'Laneshia', - 'Vasthi', - 'Treanna', - 'Tria', - 'Tuongvi', - 'Brany', - 'Niza', - 'Shandale', - 'Shanley', - 'Shastina', - 'Sheyna', - 'Ronniesha', - 'Rubit', - 'Ruvi', - 'Siobhain', - 'Shauntal', - 'Linzie', - 'Linzi', - 'Fatimatou', - 'Efrat', - 'Jasmely', - 'Kadidia', - 'Kamily', - 'Meirav', - 'Areebah', - 'Fatim', - 'Nuzhat', - 'Saribel', - 'Zorah', - 'Ting', - 'Laporscha', - 'Mieshia', - 'Vanecia', - 'Brittne', - 'Denetria', - 'Deamber', - 'Cymone', - 'Arieal', - 'Araly', - 'Shamieka', - 'Deshay', - 'Britainy', - 'Matraca', - 'Krystyne', - 'Kristela', - 'Kindell', - 'Ceyda', - 'Jahnasia', - 'Halimatou', - 'Graciana', - 'Haja', - 'Safiatou', - 'Su', - 'Zaineb', - 'Yianna', - 'Shilat', - 'Zanai', - 'Zeinabou', - 'Jalysa', - 'Garcia', - 'Jinna', - 'Brytni', - 'Crystalmarie', - 'Kyrstie', - 'Labrea', - 'Laurita', - 'Kathleena', - 'Salimatou', - 'Martisha', - 'Damisha', - 'Londin', - 'Toree', - 'Yadria', - 'Yaminah', - 'Nili', - 'Pella', - 'Menna', - 'Minah', - 'Porshay', - 'Rahwa', - 'Parissa', - 'Nury', - 'Sheeva', - 'Sendi', - 'Aroush', - 'Jerlyn', - 'Momina', - 'Nylia', - 'Mahreen', - 'Mattingly', - 'Emanuella', - 'Ceylin', - 'Biana', - 'Ishrat', - 'Genendy', - 'Hindel', - 'Chavi', - 'Freidy', - 'Rouguiatou', - 'Osnas', - 'Yagmur', - 'Yitel', - 'Hudy', - 'Jamielynn', - 'Valyncia', - 'Cheyla', - 'Assa', - 'Tasmia', - 'Yaslene', - 'Zaima', - 'Jenisse', - 'Juliannah', - 'Reveca', - 'Amra', - 'Anaria', - 'Arlenis', - 'Anastassia', - 'Anique', - 'Arilene', - 'Adileni', - 'Chelcy', - 'Chelesa', - 'Columba', - 'Corri', - 'Briane', - 'Carine', - 'Deziah', - 'Jojo', - 'Jaidalyn', - 'Cecelie', - 'Meagon', - 'Raysha', - 'Mylinh', - 'Madelena', - 'Saniyya', - 'Shama', - 'Shifa', - 'Nyala', - 'Lafaun', - 'Ronnetta', - 'Rondia', - 'Christe', - 'Tynnetta', - 'Ethyle', - 'Bobi', - 'Rayetta', - 'Wilmina', - 'Tangala', - 'Chloris', - 'Marvyl', - 'Larinda', - 'Narcedalia', - 'Tiaa', - 'Terressa', - 'Missi', - 'Ardythe', - 'Briget', - 'Julya', - 'Emilyanne', - 'Ayano', - 'Eliane', - 'Tatem', - 'Roselani', - 'Zareen', - 'Yaxeni', - 'Marleena', - 'Nicolemarie', - 'Patzy', - 'Morgana', - 'Mirca', - 'Mystica', - 'Rosaicela', - 'Rosaysela', - 'Serrena', - 'Shiori', - 'Yannely', - 'Threasa', - 'Zohra', - 'Lanitra', - 'Laquinthia', - 'Deshundra', - 'Mirasol', - 'Lladira', - 'Tejuana', - 'Michaelann', - 'Normajean', - 'Leasha', - 'Kajuana', - 'Xianna', - 'Yaquelyn', - 'Marcea', - 'Mohini', - 'Jaysha', - 'Saysha', - 'Makamae', - 'Lynnett', - 'Mistee', - 'Kaysee', - 'Lizel', - 'Kiora', - 'Kla', - 'Lanay', - 'Kainani', - 'Pomaikai', - 'Piilani', - 'Aulii', - 'Khristi', - 'Delfa', - 'Toka', - 'Satonya', - 'Jammi', - 'Iolani', - 'Hinaea', - 'Ilihia', - 'Kulia', - 'Darcus', - 'Raejean', - 'Brisamar', - 'Francessca', - 'Dhamar', - 'Lehiwa', - 'Ajane', - 'Alexsys', - 'Jema', - 'Imara', - 'Itzanami', - 'Ivori', - 'Tabby', - 'Charnell', - 'Vanessamarie', - 'Vibiana', - 'Kameisha', - 'Edica', - 'Shanetra', - 'Shametria', - 'Quinette', - 'Abreanna', - 'Corazon', - 'Correna', - 'Lilac', - 'Najwa', - 'Moranda', - 'Monik', - 'Deise', - 'Edid', - 'Karinne', - 'Ilsa', - 'Irazema', - 'Pegge', - 'Chenique', - 'Temisha', - 'Cristella', - 'Christle', - 'Falan', - 'Mekesha', - 'Jonquil', - 'Latarya', - 'Maretta', - 'Sonceria', - 'Latamara', - 'Ladina', - 'Rozann', - 'Suz', - 'Aleja', - 'Wray', - 'Indica', - 'Harkiran', - 'Gemini', - 'Erikah', - 'Fey', - 'Gudelia', - 'Komalpreet', - 'Anah', - 'Angelicamarie', - 'Cammi', - 'Dejane', - 'Dejanay', - 'Cilicia', - 'Merla', - 'Janann', - 'Maurita', - 'Aireana', - 'Shuronda', - 'Shunte', - 'Lacrisha', - 'Kwana', - 'Krisi', - 'Kaysi', - 'Latressa', - 'Tyronza', - 'Debralee', - 'Crissie', - 'Crissa', - 'Jameca', - 'Alicha', - 'Ketra', - 'Chrisie', - 'Delecia', - 'Rokisha', - 'Natoshia', - 'Shajuana', - 'Jenipher', - 'Jenefer', - 'Anjanae', - 'Azita', - 'Clairissa', - 'Brezhane', - 'Keera', - 'Siarah', - 'Smita', - 'Savonna', - 'Raquelin', - 'Lorren', - 'Omunique', - 'Molina', - 'Nixaliz', - 'Melitza', - 'Shylo', - 'Teniqua', - 'Charmine', - 'Deonne', - 'Kima', - 'Galit', - 'Ikesha', - 'Jamala', - 'Cherl', - 'Ageliki', - 'Ydania', - 'Kortlyn', - 'Lisvet', - 'Khya', - 'Kearstyn', - 'Seline', - 'Stormey', - 'Rehma', - 'Mckynna', - 'Brynnan', - 'Abiola', - 'Ambriel', - 'Akaysha', - 'Hailea', - 'Fryda', - 'Fedra', - 'Dacie', - 'Deissy', - 'Deyna', - 'Mayling', - 'Tessy', - 'Yaa', - 'Shameca', - 'Shivon', - 'Taesha', - 'Dinamarie', - 'Ifeoma', - 'Ashlye', - 'Patriciajo', - 'Danute', - 'Amalyn', - 'Nakeia', - 'Takima', - 'Shavonn', - 'Katira', - 'Lakema', - 'Jahaida', - 'Marshelle', - 'Angeliki', - 'Carrianne', - 'Carrieanne', - 'Tarika', - 'Sherece', - 'Kalimah', - 'Kinda', - 'Sadiga', - 'Paraskevi', - 'Ayianna', - 'Alezay', - 'Cadynce', - 'Haely', - 'Heavenleigh', - 'Dajanique', - 'Lasharn', - 'Drita', - 'Genene', - 'Gittle', - 'Carriann', - 'Emerita', - 'Jenniferann', - 'Kammie', - 'Bryony', - 'Rupinder', - 'Tenise', - 'Yazmyn', - 'Maricris', - 'Rhianon', - 'Nicolet', - 'Mui', - 'Nacy', - 'Naoko', - 'Gaila', - 'Charene', - 'Bas', - 'Geni', - 'Lorez', - 'Taneeka', - 'Tanikqua', - 'Tulani', - 'Sotiria', - 'Sheeba', - 'Katiuscia', - 'Eleftheria', - 'Ghislaine', - 'Jamiylah', - 'Omotayo', - 'Yuleidy', - 'Tylene', - 'Zanetta', - 'Yizza', - 'Ngan', - 'Natassha', - 'Sophear', - 'Starkisha', - 'Stehanie', - 'Jasie', - 'Aprile', - 'Billiejean', - 'Wilnelia', - 'Yaasmiyn', - 'Ednita', - 'Engracia', - 'Grisell', - 'Christinamarie', - 'Eftihia', - 'Jenniefer', - 'Chantee', - 'Afua', - 'Shamea', - 'Shamina', - 'Vickiana', - 'Sharoya', - 'Shateema', - 'Aubrea', - 'Alexcis', - 'Wallis', - 'Jalyne', - 'Harlea', - 'Carisia', - 'Cheynne', - 'Daylee', - 'Kyera', - 'Latayvia', - 'Raashida', - 'Saajida', - 'Nakema', - 'Annalyssa', - 'Chivonne', - 'Lyndie', - 'Sabrian', - 'Rahcel', - 'Hoai', - 'Krisann', - 'Jilliane', - 'Saide', - 'Matti', - 'Raigen', - 'Tenea', - 'Staphanie', - 'Zitlally', - 'Yudelca', - 'Raysa', - 'Monea', - 'Shanigua', - 'Shirah', - 'Chemise', - 'Jajaira', - 'Tunisha', - 'Yelissa', - 'Yudelka', - 'Taria', - 'Taralynn', - 'Condol', - 'Nikima', - 'Syrianna', - 'Anndrea', - 'Charae', - 'Ebelia', - 'Comfort', - 'Denishia', - 'Lanyia', - 'Lahna', - 'Iraima', - 'Josaline', - 'Onyinyechi', - 'Mykalah', - 'Shamyia', - 'Sarely', - 'Makaylie', - 'Madasyn', - 'Carron', - 'Shawnetta', - 'Dorca', - 'Subrena', - 'Romanda', - 'Sallyanne', - 'Ahniyah', - 'Annalissa', - 'Anikah', - 'Anet', - 'Emelee', - 'Branae', - 'Rosemaria', - 'Kimerly', - 'Lorra', - 'Breda', - 'Graceanne', - 'Kathyann', - 'Letetia', - 'Allaina', - 'Anaceli', - 'Brendalee', - 'Aidaly', - 'Arlana', - 'Trinetta', - 'Tennesha', - 'Talonda', - 'Sherrilynn', - 'Maloree', - 'Laiya', - 'Kynlea', - 'Ludwika', - 'Raeli', - 'Yadirah', - 'Yveth', - 'Sabrie', - 'Dannielynn', - 'Breely', - 'Jozlin', - 'Jewelyssa', - 'Keylie', - 'Jazzalyn', - 'Ijeoma', - 'Jaydie', - 'Irianna', - 'Ronya', - 'Lynee', - 'Myrian', - 'Cristalle', - 'Delinah', - 'Arnetia', - 'Guisela', - 'Orna', - 'Samehesha', - 'Scherrie', - 'Marylynne', - 'Judianne', - 'Tomasina', - 'Sanora', - 'Cheray', - 'Gordana', - 'Torina', - 'Yolandra', - 'Tyese', - 'Sharine', - 'Marea', - 'Areti', - 'Sharmila', - 'Charrise', - 'Cyndia', - 'Cinzia', - 'Gecenia', - 'Tarshia', - 'Luwanda', - 'Negar', - 'Sharah', - 'Sherah', - 'Sokha', - 'Marium', - 'Taslin', - 'Taleyah', - 'Parys', - 'Odeth', - 'Mirabai', - 'Myree', - 'Tyhesha', - 'Soyini', - 'Liria', - 'Jenille', - 'Marivic', - 'Mey', - 'Adrena', - 'Cristyn', - 'Jodette', - 'Ilea', - 'Jennett', - 'Latoi', - 'Charrisse', - 'Correne', - 'Reannon', - 'Shanah', - 'Shavaun', - 'Shelena', - 'Macrina', - 'Lashonna', - 'Tecia', - 'Zobeida', - 'Casilda', - 'Ketsy', - 'Lizza', - 'Lucesita', - 'Anelis', - 'Amori', - 'Atlantis', - 'Aslynn', - 'Kimbery', - 'Yolunda', - 'Pasqua', - 'Magalis', - 'Yanellie', - 'Tryniti', - 'Tniya', - 'Ziza', - 'Nadina', - 'Lloana', - 'Shoshannah', - 'Tamarie', - 'Ronique', - 'Keatyn', - 'Matison', - 'Micalah', - 'Nataya', - 'Mama', - 'Bailea', - 'Sidrah', - 'Jazzman', - 'Deanndra', - 'Shawniece', - 'Polett', - 'Rathana', - 'Timisha', - 'Tristina', - 'Vanezza', - 'Shiri', - 'Stephanieann', - 'Genessy', - 'Hema', - 'Huma', - 'Alessandria', - 'Yarisa', - 'Oyindamola', - 'Tianni', - 'Monasia', - 'Kely', - 'Khady', - 'Pegah', - 'Casarah', - 'Cassara', - 'Chalise', - 'Arti', - 'Natanya', - 'Masuma', - 'Shellyann', - 'Taje', - 'Saher', - 'Kelsye', - 'Odaly', - 'Talicia', - 'Mollee', - 'Tashea', - 'Shima', - 'Janaia', - 'Jenia', - 'Jharline', - 'Chabely', - 'Chalon', - 'Charnesha', - 'Christna', - 'Melika', - 'Melis', - 'Lesleyann', - 'Maleeka', - 'Krystalyn', - 'Krystalynn', - 'Marnisha', - 'Mariele', - 'Michelleann', - 'Melessa', - 'Diasy', - 'Dioselina', - 'Jenita', - 'Jaynae', - 'Jeanae', - 'Hripsime', - 'Janete', - 'Lanique', - 'Ashlon', - 'Aroosa', - 'Enisa', - 'Danaysha', - 'Briani', - 'Arjeta', - 'Sapir', - 'Naysha', - 'Kharisma', - 'Laterra', - 'Yannet', - 'Aruna', - 'Anaja', - 'Fahima', - 'Dasmine', - 'Amberlea', - 'Latiera', - 'Kimanh', - 'Mayuri', - 'Meshelle', - 'Morgane', - 'Nahal', - 'Mariacristina', - 'Marlisha', - 'Elaura', - 'Kacia', - 'Neesha', - 'Tila', - 'Waynisha', - 'Witney', - 'Niloofar', - 'Solina', - 'Soo', - 'Stphanie', - 'Shanesha', - 'Sharrell', - 'Nene', - 'Bleona', - 'Hudes', - 'Isatu', - 'Aylssa', - 'Camerina', - 'Arrielle', - 'Allycia', - 'Anacecilia', - 'Anairis', - 'Courney', - 'Dashanique', - 'Cedrina', - 'Celida', - 'Taaliyah', - 'Clarrissa', - 'Egla', - 'Duyen', - 'Kendle', - 'Janil', - 'Adeola', - 'Jazmene', - 'Leesha', - 'Lyzeth', - 'Madeley', - 'Khrystyna', - 'Charisa', - 'Crystelle', - 'Carinna', - 'Channy', - 'Flory', - 'Glenisha', - 'Sheida', - 'Naara', - 'Nassim', - 'Ngozi', - 'Nidya', - 'Marche', - 'Mariaesther', - 'Shaleena', - 'Kioni', - 'Nayab', - 'Nzinga', - 'Fizza', - 'Diavion', - 'Zanib', - 'Tionni', - 'Temitope', - 'Nasreen', - 'Melaysia', - 'Maame', - 'Sameen', - 'Azka', - 'Basma', - 'Virjean', - 'Jarmila', - 'Louren', - 'Mckenize', - 'Malyn', - 'Mercadies', - 'Vika', - 'Suong', - 'Mariadel', - 'Mariatheresa', - 'Marison', - 'Meleane', - 'Shabana', - 'Salote', - 'Raquell', - 'Rekha', - 'Sibel', - 'Shavaughn', - 'Shaquoia', - 'Shatera', - 'Fatina', - 'Jestina', - 'Latasia', - 'Geraldin', - 'Shirleymae', - 'Lubna', - 'Maxiel', - 'Naquasha', - 'Dalissa', - 'Chaniqua', - 'Chanele', - 'Jahlisa', - 'Faatimah', - 'Abagayle', - 'Adwoa', - 'Angeliqu', - 'Gelisa', - 'Bradi', - 'Shantice', - 'Sharece', - 'Nyiesha', - 'Yanill', - 'Yocasta', - 'Stepheni', - 'Suleika', - 'Takeema', - 'Kerrilyn', - 'Jamiyla', - 'Josephin', - 'Margarit', - 'Ilaisaane', - 'Jamilee', - 'Corvette', - 'Janitza', - 'Lexey', - 'Jazzmyne', - 'Kirstan', - 'Kattia', - 'Yatzary', - 'Pricsilla', - 'Gisette', - 'Panayiota', - 'Pinar', - 'Rasheida', - 'Tiffay', - 'Venisha', - 'Jennier', - 'Margulia', - 'Katima', - 'Anjoli', - 'Evelise', - 'Chetara', - 'Jaquelynn', - 'Pessie', - 'Quintessa', - 'Orit', - 'Nelissa', - 'Shekia', - 'Sherrise', - 'Abbye', - 'Imagine', - 'Britlyn', - 'Baley', - 'Tanequa', - 'Tanique', - 'Nocole', - 'Sokhom', - 'Krystelle', - 'Marqui', - 'Mariaangelica', - 'Raiven', - 'Nini', - 'Lesliee', - 'Crystalee', - 'Amadi', - 'Suzett', - 'Thelda', - 'Wladyslawa', - 'Shaqueen', - 'Shayra', - 'Domingue', - 'Garine', - 'Johnanna', - 'Karia', - 'Jany', - 'Ardele', - 'Bilma', - 'Lindita', - 'Lisbel', - 'Lyasia', - 'Kianie', - 'Saidah', - 'Niasha', - 'Chantele', - 'Brette', - 'Cydnie', - 'Chealsea', - 'Jaritsa', - 'Hanaa', - 'Jordain', - 'Kerria', - 'Shannara', - 'Shaquna', - 'Sultana', - 'Tajana', - 'Taquasha', - 'Queenasia', - 'Wandalee', - 'Mikalyn', - 'Jossette', - 'Jazsmine', - 'Keairra', - 'Arleny', - 'Selest', - 'Sabryn', - 'Jilliann', - 'Janin', - 'Kayliegh', - 'Alyss', - 'Asuka', - 'Chenin', - 'Eiliana', - 'Fahm', - 'Cyndle', - 'Daniesha', - 'Saranda', - 'Shany', - 'Veridiana', - 'Yanai', - 'Melanieann', - 'Mishell', - 'Mariadelosangel', - 'Rupa', - 'Orabelle', - 'Taquasia', - 'Tyquasia', - 'Cecillia', - 'Jeanet', - 'Lucely', - 'Kar', - 'Niaja', - 'Naquana', - 'Joanny', - 'Anjelique', - 'Aquasia', - 'Ardita', - 'Jatasia', - 'Donika', - 'Fantasha', - 'Dominiqua', - 'Elecia', - 'Deyra', - 'Erial', - 'Bayle', - 'Ninoska', - 'Jonee', - 'Jullisa', - 'Lavasia', - 'Laniqua', -]; diff --git a/integration-tests/tests/seeder/lastNames.ts b/integration-tests/tests/seeder/lastNames.ts deleted file mode 100644 index f69f2c629..000000000 --- a/integration-tests/tests/seeder/lastNames.ts +++ /dev/null @@ -1,50000 +0,0 @@ -export default [ - 'Smith', - 'Johnson', - 'Williams', - 'Brown', - 'Jones', - 'Miller', - 'Davis', - 'Garcia', - 'Rodriguez', - 'Wilson', - 'Martinez', - 'Anderson', - 'Taylor', - 'Thomas', - 'Hernandez', - 'Moore', - 'Martin', - 'Jackson', - 'Thompson', - 'White', - 'Lopez', - 'Lee', - 'Gonzalez', - 'Harris', - 'Clark', - 'Lewis', - 'Robinson', - 'Walker', - 'Perez', - 'Hall', - 'Young', - 'Allen', - 'Sanchez', - 'Wright', - 'King', - 'Scott', - 'Green', - 'Baker', - 'Adams', - 'Nelson', - 'Hill', - 'Ramirez', - 'Campbell', - 'Mitchell', - 'Roberts', - 'Carter', - 'Phillips', - 'Evans', - 'Turner', - 'Torres', - 'Parker', - 'Collins', - 'Edwards', - 'Stewart', - 'Flores', - 'Morris', - 'Nguyen', - 'Murphy', - 'Rivera', - 'Cook', - 'Rogers', - 'Morgan', - 'Peterson', - 'Cooper', - 'Reed', - 'Bailey', - 'Bell', - 'Gomez', - 'Kelly', - 'Howard', - 'Ward', - 'Cox', - 'Diaz', - 'Richardson', - 'Wood', - 'Watson', - 'Brooks', - 'Bennett', - 'Gray', - 'James', - 'Reyes', - 'Cruz', - 'Hughes', - 'Price', - 'Myers', - 'Long', - 'Foster', - 'Sanders', - 'Ross', - 'Morales', - 'Powell', - 'Sullivan', - 'Russell', - 'Ortiz', - 'Jenkins', - 'Gutierrez', - 'Perry', - 'Butler', - 'Barnes', - 'Fisher', - 'Henderson', - 'Coleman', - 'Simmons', - 'Patterson', - 'Jordan', - 'Reynolds', - 'Hamilton', - 'Graham', - 'Kim', - 'Gonzales', - 'Alexander', - 'Ramos', - 'Wallace', - 'Griffin', - 'West', - 'Cole', - 'Hayes', - 'Chavez', - 'Gibson', - 'Bryant', - 'Ellis', - 'Stevens', - 'Murray', - 'Ford', - 'Marshall', - 'Owens', - 'Mcdonald', - 'Harrison', - 'Ruiz', - 'Kennedy', - 'Wells', - 'Alvarez', - 'Woods', - 'Mendoza', - 'Castillo', - 'Olson', - 'Webb', - 'Washington', - 'Tucker', - 'Freeman', - 'Burns', - 'Henry', - 'Vasquez', - 'Snyder', - 'Simpson', - 'Crawford', - 'Jimenez', - 'Porter', - 'Mason', - 'Shaw', - 'Gordon', - 'Wagner', - 'Hunter', - 'Romero', - 'Hicks', - 'Dixon', - 'Hunt', - 'Palmer', - 'Robertson', - 'Black', - 'Holmes', - 'Stone', - 'Meyer', - 'Boyd', - 'Mills', - 'Warren', - 'Fox', - 'Rose', - 'Rice', - 'Moreno', - 'Schmidt', - 'Patel', - 'Ferguson', - 'Nichols', - 'Herrera', - 'Medina', - 'Ryan', - 'Fernandez', - 'Weaver', - 'Daniels', - 'Stephens', - 'Gardner', - 'Payne', - 'Kelley', - 'Dunn', - 'Pierce', - 'Arnold', - 'Tran', - 'Spencer', - 'Peters', - 'Hawkins', - 'Grant', - 'Hansen', - 'Castro', - 'Hoffman', - 'Hart', - 'Elliott', - 'Cunningham', - 'Knight', - 'Bradley', - 'Carroll', - 'Hudson', - 'Duncan', - 'Armstrong', - 'Berry', - 'Andrews', - 'Johnston', - 'Ray', - 'Lane', - 'Riley', - 'Carpenter', - 'Perkins', - 'Aguilar', - 'Silva', - 'Richards', - 'Willis', - 'Matthews', - 'Chapman', - 'Lawrence', - 'Garza', - 'Vargas', - 'Watkins', - 'Wheeler', - 'Larson', - 'Carlson', - 'Harper', - 'George', - 'Greene', - 'Burke', - 'Guzman', - 'Morrison', - 'Munoz', - 'Jacobs', - 'Obrien', - 'Lawson', - 'Franklin', - 'Lynch', - 'Bishop', - 'Carr', - 'Salazar', - 'Austin', - 'Mendez', - 'Gilbert', - 'Jensen', - 'Williamson', - 'Montgomery', - 'Harvey', - 'Oliver', - 'Howell', - 'Dean', - 'Hanson', - 'Weber', - 'Garrett', - 'Sims', - 'Burton', - 'Fuller', - 'Soto', - 'Mccoy', - 'Welch', - 'Chen', - 'Schultz', - 'Walters', - 'Reid', - 'Fields', - 'Walsh', - 'Little', - 'Fowler', - 'Bowman', - 'Davidson', - 'May', - 'Day', - 'Schneider', - 'Newman', - 'Brewer', - 'Lucas', - 'Holland', - 'Wong', - 'Banks', - 'Santos', - 'Curtis', - 'Pearson', - 'Delgado', - 'Valdez', - 'Pena', - 'Rios', - 'Douglas', - 'Sandoval', - 'Barrett', - 'Hopkins', - 'Keller', - 'Guerrero', - 'Stanley', - 'Bates', - 'Alvarado', - 'Beck', - 'Ortega', - 'Wade', - 'Estrada', - 'Contreras', - 'Barnett', - 'Caldwell', - 'Santiago', - 'Lambert', - 'Powers', - 'Chambers', - 'Nunez', - 'Craig', - 'Leonard', - 'Lowe', - 'Rhodes', - 'Byrd', - 'Gregory', - 'Shelton', - 'Frazier', - 'Becker', - 'Maldonado', - 'Fleming', - 'Vega', - 'Sutton', - 'Cohen', - 'Jennings', - 'Parks', - 'Mcdaniel', - 'Watts', - 'Barker', - 'Norris', - 'Vaughn', - 'Vazquez', - 'Holt', - 'Schwartz', - 'Steele', - 'Benson', - 'Neal', - 'Dominguez', - 'Horton', - 'Terry', - 'Wolfe', - 'Hale', - 'Lyons', - 'Graves', - 'Haynes', - 'Miles', - 'Park', - 'Warner', - 'Padilla', - 'Bush', - 'Thornton', - 'Mccarthy', - 'Mann', - 'Zimmerman', - 'Erickson', - 'Fletcher', - 'Mckinney', - 'Page', - 'Dawson', - 'Joseph', - 'Marquez', - 'Reeves', - 'Klein', - 'Espinoza', - 'Baldwin', - 'Moran', - 'Love', - 'Robbins', - 'Higgins', - 'Ball', - 'Cortez', - 'Le', - 'Griffith', - 'Bowen', - 'Sharp', - 'Cummings', - 'Ramsey', - 'Hardy', - 'Swanson', - 'Barber', - 'Acosta', - 'Luna', - 'Chandler', - 'Blair', - 'Daniel', - 'Cross', - 'Simon', - 'Dennis', - 'Oconnor', - 'Quinn', - 'Gross', - 'Navarro', - 'Moss', - 'Fitzgerald', - 'Doyle', - 'Mclaughlin', - 'Rojas', - 'Rodgers', - 'Stevenson', - 'Singh', - 'Yang', - 'Figueroa', - 'Harmon', - 'Newton', - 'Paul', - 'Manning', - 'Garner', - 'Mcgee', - 'Reese', - 'Francis', - 'Burgess', - 'Adkins', - 'Goodman', - 'Curry', - 'Brady', - 'Christensen', - 'Potter', - 'Walton', - 'Goodwin', - 'Mullins', - 'Molina', - 'Webster', - 'Fischer', - 'Campos', - 'Avila', - 'Sherman', - 'Todd', - 'Chang', - 'Blake', - 'Malone', - 'Wolf', - 'Hodges', - 'Juarez', - 'Gill', - 'Farmer', - 'Hines', - 'Gallagher', - 'Duran', - 'Hubbard', - 'Cannon', - 'Miranda', - 'Wang', - 'Saunders', - 'Tate', - 'Mack', - 'Hammond', - 'Carrillo', - 'Townsend', - 'Wise', - 'Ingram', - 'Barton', - 'Mejia', - 'Ayala', - 'Schroeder', - 'Hampton', - 'Rowe', - 'Parsons', - 'Frank', - 'Waters', - 'Strickland', - 'Osborne', - 'Maxwell', - 'Chan', - 'Deleon', - 'Norman', - 'Harrington', - 'Casey', - 'Patton', - 'Logan', - 'Bowers', - 'Mueller', - 'Glover', - 'Floyd', - 'Hartman', - 'Buchanan', - 'Cobb', - 'French', - 'Kramer', - 'Mccormick', - 'Clarke', - 'Tyler', - 'Gibbs', - 'Moody', - 'Conner', - 'Sparks', - 'Mcguire', - 'Leon', - 'Bauer', - 'Norton', - 'Pope', - 'Flynn', - 'Hogan', - 'Robles', - 'Salinas', - 'Yates', - 'Lindsey', - 'Lloyd', - 'Marsh', - 'Mcbride', - 'Owen', - 'Solis', - 'Pham', - 'Lang', - 'Pratt', - 'Lara', - 'Brock', - 'Ballard', - 'Trujillo', - 'Shaffer', - 'Drake', - 'Roman', - 'Aguirre', - 'Morton', - 'Stokes', - 'Lamb', - 'Pacheco', - 'Patrick', - 'Cochran', - 'Shepherd', - 'Cain', - 'Burnett', - 'Hess', - 'Li', - 'Cervantes', - 'Olsen', - 'Briggs', - 'Ochoa', - 'Cabrera', - 'Velasquez', - 'Montoya', - 'Roth', - 'Meyers', - 'Cardenas', - 'Fuentes', - 'Weiss', - 'Hoover', - 'Wilkins', - 'Nicholson', - 'Underwood', - 'Short', - 'Carson', - 'Morrow', - 'Colon', - 'Holloway', - 'Summers', - 'Bryan', - 'Petersen', - 'Mckenzie', - 'Serrano', - 'Wilcox', - 'Carey', - 'Clayton', - 'Poole', - 'Calderon', - 'Gallegos', - 'Greer', - 'Rivas', - 'Guerra', - 'Decker', - 'Collier', - 'Wall', - 'Whitaker', - 'Bass', - 'Flowers', - 'Davenport', - 'Conley', - 'Houston', - 'Huff', - 'Copeland', - 'Hood', - 'Monroe', - 'Massey', - 'Roberson', - 'Combs', - 'Franco', - 'Larsen', - 'Pittman', - 'Randall', - 'Skinner', - 'Wilkinson', - 'Kirby', - 'Cameron', - 'Bridges', - 'Anthony', - 'Richard', - 'Kirk', - 'Bruce', - 'Singleton', - 'Mathis', - 'Bradford', - 'Boone', - 'Abbott', - 'Charles', - 'Allison', - 'Sweeney', - 'Atkinson', - 'Horn', - 'Jefferson', - 'Rosales', - 'York', - 'Christian', - 'Phelps', - 'Farrell', - 'Castaneda', - 'Nash', - 'Dickerson', - 'Bond', - 'Wyatt', - 'Foley', - 'Chase', - 'Gates', - 'Vincent', - 'Mathews', - 'Hodge', - 'Garrison', - 'Trevino', - 'Villarreal', - 'Heath', - 'Dalton', - 'Valencia', - 'Callahan', - 'Hensley', - 'Atkins', - 'Huffman', - 'Roy', - 'Boyer', - 'Shields', - 'Lin', - 'Hancock', - 'Grimes', - 'Glenn', - 'Cline', - 'Delacruz', - 'Camacho', - 'Dillon', - 'Parrish', - 'Oneill', - 'Melton', - 'Booth', - 'Kane', - 'Berg', - 'Harrell', - 'Pitts', - 'Savage', - 'Wiggins', - 'Brennan', - 'Salas', - 'Marks', - 'Russo', - 'Sawyer', - 'Baxter', - 'Golden', - 'Hutchinson', - 'Liu', - 'Walter', - 'Mcdowell', - 'Wiley', - 'Rich', - 'Humphrey', - 'Johns', - 'Koch', - 'Suarez', - 'Hobbs', - 'Beard', - 'Gilmore', - 'Ibarra', - 'Keith', - 'Macias', - 'Khan', - 'Andrade', - 'Ware', - 'Stephenson', - 'Henson', - 'Wilkerson', - 'Dyer', - 'Mcclure', - 'Blackwell', - 'Mercado', - 'Tanner', - 'Eaton', - 'Clay', - 'Barron', - 'Beasley', - 'Oneal', - 'Preston', - 'Small', - 'Wu', - 'Zamora', - 'Macdonald', - 'Vance', - 'Snow', - 'Mcclain', - 'Stafford', - 'Orozco', - 'Barry', - 'English', - 'Shannon', - 'Kline', - 'Jacobson', - 'Woodard', - 'Huang', - 'Kemp', - 'Mosley', - 'Prince', - 'Merritt', - 'Hurst', - 'Villanueva', - 'Roach', - 'Nolan', - 'Lam', - 'Yoder', - 'Mccullough', - 'Lester', - 'Santana', - 'Valenzuela', - 'Winters', - 'Barrera', - 'Leach', - 'Orr', - 'Berger', - 'Mckee', - 'Strong', - 'Conway', - 'Stein', - 'Whitehead', - 'Bullock', - 'Escobar', - 'Knox', - 'Meadows', - 'Solomon', - 'Velez', - 'Odonnell', - 'Kerr', - 'Stout', - 'Blankenship', - 'Browning', - 'Kent', - 'Lozano', - 'Bartlett', - 'Pruitt', - 'Buck', - 'Barr', - 'Gaines', - 'Durham', - 'Gentry', - 'Mcintyre', - 'Sloan', - 'Rocha', - 'Melendez', - 'Herman', - 'Sexton', - 'Moon', - 'Hendricks', - 'Rangel', - 'Stark', - 'Lowery', - 'Hardin', - 'Hull', - 'Sellers', - 'Ellison', - 'Calhoun', - 'Gillespie', - 'Mora', - 'Knapp', - 'Mccall', - 'Morse', - 'Dorsey', - 'Weeks', - 'Nielsen', - 'Livingston', - 'Leblanc', - 'Mclean', - 'Bradshaw', - 'Glass', - 'Middleton', - 'Buckley', - 'Schaefer', - 'Frost', - 'Howe', - 'House', - 'Mcintosh', - 'Ho', - 'Pennington', - 'Reilly', - 'Hebert', - 'Mcfarland', - 'Hickman', - 'Noble', - 'Spears', - 'Conrad', - 'Arias', - 'Galvan', - 'Velazquez', - 'Huynh', - 'Frederick', - 'Randolph', - 'Cantu', - 'Fitzpatrick', - 'Mahoney', - 'Peck', - 'Villa', - 'Michael', - 'Donovan', - 'Mcconnell', - 'Walls', - 'Boyle', - 'Mayer', - 'Zuniga', - 'Giles', - 'Pineda', - 'Pace', - 'Hurley', - 'Mays', - 'Mcmillan', - 'Crosby', - 'Ayers', - 'Case', - 'Bentley', - 'Shepard', - 'Everett', - 'Pugh', - 'David', - 'Mcmahon', - 'Dunlap', - 'Bender', - 'Hahn', - 'Harding', - 'Acevedo', - 'Raymond', - 'Blackburn', - 'Duffy', - 'Landry', - 'Dougherty', - 'Bautista', - 'Shah', - 'Potts', - 'Arroyo', - 'Valentine', - 'Meza', - 'Gould', - 'Vaughan', - 'Fry', - 'Rush', - 'Avery', - 'Herring', - 'Dodson', - 'Clements', - 'Sampson', - 'Tapia', - 'Bean', - 'Lynn', - 'Crane', - 'Farley', - 'Cisneros', - 'Benton', - 'Ashley', - 'Mckay', - 'Finley', - 'Best', - 'Blevins', - 'Friedman', - 'Moses', - 'Sosa', - 'Blanchard', - 'Huber', - 'Frye', - 'Krueger', - 'Bernard', - 'Rosario', - 'Rubio', - 'Mullen', - 'Benjamin', - 'Haley', - 'Chung', - 'Moyer', - 'Choi', - 'Horne', - 'Yu', - 'Woodward', - 'Ali', - 'Nixon', - 'Hayden', - 'Rivers', - 'Estes', - 'Mccarty', - 'Richmond', - 'Stuart', - 'Maynard', - 'Brandt', - 'Oconnell', - 'Hanna', - 'Sanford', - 'Sheppard', - 'Church', - 'Burch', - 'Levy', - 'Rasmussen', - 'Coffey', - 'Ponce', - 'Faulkner', - 'Donaldson', - 'Schmitt', - 'Novak', - 'Costa', - 'Montes', - 'Booker', - 'Cordova', - 'Waller', - 'Arellano', - 'Maddox', - 'Mata', - 'Bonilla', - 'Stanton', - 'Compton', - 'Kaufman', - 'Dudley', - 'Mcpherson', - 'Beltran', - 'Dickson', - 'Mccann', - 'Villegas', - 'Proctor', - 'Hester', - 'Cantrell', - 'Daugherty', - 'Cherry', - 'Bray', - 'Davila', - 'Rowland', - 'Levine', - 'Madden', - 'Spence', - 'Good', - 'Irwin', - 'Werner', - 'Krause', - 'Petty', - 'Whitney', - 'Baird', - 'Hooper', - 'Pollard', - 'Zavala', - 'Jarvis', - 'Holden', - 'Haas', - 'Hendrix', - 'Mcgrath', - 'Bird', - 'Lucero', - 'Terrell', - 'Riggs', - 'Joyce', - 'Mercer', - 'Rollins', - 'Galloway', - 'Duke', - 'Odom', - 'Andersen', - 'Downs', - 'Hatfield', - 'Benitez', - 'Archer', - 'Huerta', - 'Travis', - 'Mcneil', - 'Hinton', - 'Zhang', - 'Hays', - 'Mayo', - 'Fritz', - 'Branch', - 'Mooney', - 'Ewing', - 'Ritter', - 'Esparza', - 'Frey', - 'Braun', - 'Gay', - 'Riddle', - 'Haney', - 'Kaiser', - 'Holder', - 'Chaney', - 'Mcknight', - 'Gamble', - 'Vang', - 'Cooley', - 'Carney', - 'Cowan', - 'Forbes', - 'Ferrell', - 'Davies', - 'Barajas', - 'Shea', - 'Osborn', - 'Bright', - 'Cuevas', - 'Bolton', - 'Murillo', - 'Lutz', - 'Duarte', - 'Kidd', - 'Key', - 'Cooke', - 'Goff', - 'Dejesus', - 'Marin', - 'Dotson', - 'Bonner', - 'Cotton', - 'Merrill', - 'Lindsay', - 'Lancaster', - 'Mcgowan', - 'Felix', - 'Salgado', - 'Slater', - 'Carver', - 'Guthrie', - 'Holman', - 'Fulton', - 'Snider', - 'Sears', - 'Witt', - 'Newell', - 'Byers', - 'Lehman', - 'Gorman', - 'Costello', - 'Donahue', - 'Delaney', - 'Albert', - 'Workman', - 'Rosas', - 'Springer', - 'Kinney', - 'Justice', - 'Odell', - 'Lake', - 'Donnelly', - 'Law', - 'Dailey', - 'Guevara', - 'Shoemaker', - 'Barlow', - 'Marino', - 'Winter', - 'Craft', - 'Katz', - 'Pickett', - 'Espinosa', - 'Maloney', - 'Daly', - 'Goldstein', - 'Crowley', - 'Vogel', - 'Kuhn', - 'Pearce', - 'Hartley', - 'Cleveland', - 'Palacios', - 'Mcfadden', - 'Britt', - 'Wooten', - 'Cortes', - 'Dillard', - 'Childers', - 'Alford', - 'Dodd', - 'Emerson', - 'Wilder', - 'Lange', - 'Goldberg', - 'Quintero', - 'Beach', - 'Enriquez', - 'Quintana', - 'Helms', - 'Mackey', - 'Finch', - 'Cramer', - 'Minor', - 'Flanagan', - 'Franks', - 'Corona', - 'Kendall', - 'Mccabe', - 'Hendrickson', - 'Moser', - 'Mcdermott', - 'Camp', - 'Mcleod', - 'Bernal', - 'Kaplan', - 'Medrano', - 'Lugo', - 'Tracy', - 'Bacon', - 'Crowe', - 'Richter', - 'Welsh', - 'Holley', - 'Ratliff', - 'Mayfield', - 'Talley', - 'Haines', - 'Dale', - 'Gibbons', - 'Hickey', - 'Byrne', - 'Kirkland', - 'Farris', - 'Correa', - 'Tillman', - 'Sweet', - 'Kessler', - 'England', - 'Hewitt', - 'Blanco', - 'Connolly', - 'Pate', - 'Elder', - 'Bruno', - 'Holcomb', - 'Hyde', - 'Mcallister', - 'Cash', - 'Christopher', - 'Whitfield', - 'Meeks', - 'Hatcher', - 'Fink', - 'Sutherland', - 'Noel', - 'Ritchie', - 'Rosa', - 'Leal', - 'Joyner', - 'Starr', - 'Morin', - 'Delarosa', - 'Connor', - 'Hilton', - 'Alston', - 'Gilliam', - 'Wynn', - 'Wills', - 'Jaramillo', - 'Oneil', - 'Nieves', - 'Britton', - 'Rankin', - 'Belcher', - 'Guy', - 'Chamberlain', - 'Tyson', - 'Puckett', - 'Downing', - 'Sharpe', - 'Boggs', - 'Truong', - 'Pierson', - 'Godfrey', - 'Mobley', - 'John', - 'Kern', - 'Dye', - 'Hollis', - 'Bravo', - 'Magana', - 'Rutherford', - 'Ng', - 'Tuttle', - 'Lim', - 'Romano', - 'Trejo', - 'Arthur', - 'Knowles', - 'Lyon', - 'Shirley', - 'Quinones', - 'Childs', - 'Dolan', - 'Head', - 'Reyna', - 'Saenz', - 'Hastings', - 'Kenney', - 'Cano', - 'Foreman', - 'Denton', - 'Villalobos', - 'Pryor', - 'Sargent', - 'Doherty', - 'Hopper', - 'Phan', - 'Womack', - 'Lockhart', - 'Ventura', - 'Dwyer', - 'Muller', - 'Galindo', - 'Grace', - 'Sorensen', - 'Courtney', - 'Parra', - 'Rodrigues', - 'Nicholas', - 'Ahmed', - 'Mcginnis', - 'Langley', - 'Madison', - 'Locke', - 'Jamison', - 'Nava', - 'Gustafson', - 'Sykes', - 'Dempsey', - 'Hamm', - 'Rodriquez', - 'Mcgill', - 'Xiong', - 'Esquivel', - 'Simms', - 'Kendrick', - 'Boyce', - 'Vigil', - 'Downey', - 'Mckenna', - 'Sierra', - 'Webber', - 'Kirkpatrick', - 'Dickinson', - 'Couch', - 'Burks', - 'Sheehan', - 'Slaughter', - 'Pike', - 'Whitley', - 'Magee', - 'Cheng', - 'Sinclair', - 'Cassidy', - 'Rutledge', - 'Burris', - 'Bowling', - 'Crabtree', - 'Mcnamara', - 'Avalos', - 'Vu', - 'Herron', - 'Broussard', - 'Abraham', - 'Garland', - 'Corbett', - 'Corbin', - 'Stinson', - 'Chin', - 'Burt', - 'Hutchins', - 'Woodruff', - 'Lau', - 'Brandon', - 'Singer', - 'Hatch', - 'Rossi', - 'Shafer', - 'Ott', - 'Goss', - 'Gregg', - 'Dewitt', - 'Tang', - 'Polk', - 'Worley', - 'Covington', - 'Saldana', - 'Heller', - 'Emery', - 'Swartz', - 'Cho', - 'Mccray', - 'Elmore', - 'Rosenberg', - 'Simons', - 'Clemons', - 'Beatty', - 'Harden', - 'Herbert', - 'Bland', - 'Rucker', - 'Manley', - 'Ziegler', - 'Grady', - 'Lott', - 'Rouse', - 'Gleason', - 'Mcclellan', - 'Abrams', - 'Vo', - 'Albright', - 'Meier', - 'Dunbar', - 'Ackerman', - 'Padgett', - 'Mayes', - 'Tipton', - 'Coffman', - 'Peralta', - 'Shapiro', - 'Roe', - 'Weston', - 'Plummer', - 'Helton', - 'Stern', - 'Fraser', - 'Stover', - 'Fish', - 'Schumacher', - 'Baca', - 'Curran', - 'Vinson', - 'Vera', - 'Clifton', - 'Ervin', - 'Eldridge', - 'Lowry', - 'Childress', - 'Becerra', - 'Gore', - 'Seymour', - 'Chu', - 'Field', - 'Akers', - 'Carrasco', - 'Bingham', - 'Sterling', - 'Greenwood', - 'Leslie', - 'Groves', - 'Manuel', - 'Swain', - 'Edmonds', - 'Muniz', - 'Thomson', - 'Crouch', - 'Walden', - 'Smart', - 'Tomlinson', - 'Alfaro', - 'Quick', - 'Goldman', - 'Mcelroy', - 'Yarbrough', - 'Funk', - 'Hong', - 'Portillo', - 'Lund', - 'Ngo', - 'Elkins', - 'Stroud', - 'Meredith', - 'Battle', - 'Mccauley', - 'Zapata', - 'Bloom', - 'Gee', - 'Givens', - 'Cardona', - 'Schafer', - 'Robison', - 'Gunter', - 'Griggs', - 'Tovar', - 'Teague', - 'Swift', - 'Bowden', - 'Schulz', - 'Blanton', - 'Buckner', - 'Whalen', - 'Pritchard', - 'Pierre', - 'Kang', - 'Metcalf', - 'Butts', - 'Kurtz', - 'Sanderson', - 'Tompkins', - 'Inman', - 'Crowder', - 'Dickey', - 'Hutchison', - 'Conklin', - 'Hoskins', - 'Holbrook', - 'Horner', - 'Neely', - 'Tatum', - 'Hollingsworth', - 'Draper', - 'Clement', - 'Lord', - 'Reece', - 'Feldman', - 'Kay', - 'Hagen', - 'Crews', - 'Bowles', - 'Post', - 'Jewell', - 'Daley', - 'Cordero', - 'Mckinley', - 'Velasco', - 'Masters', - 'Driscoll', - 'Burrell', - 'Valle', - 'Crow', - 'Devine', - 'Larkin', - 'Chappell', - 'Pollock', - 'Ly', - 'Kimball', - 'Schmitz', - 'Lu', - 'Rubin', - 'Self', - 'Barrios', - 'Pereira', - 'Phipps', - 'Mcmanus', - 'Nance', - 'Steiner', - 'Poe', - 'Crockett', - 'Jeffries', - 'Amos', - 'Nix', - 'Newsome', - 'Dooley', - 'Payton', - 'Rosen', - 'Swenson', - 'Connelly', - 'Tolbert', - 'Segura', - 'Esposito', - 'Coker', - 'Biggs', - 'Hinkle', - 'Thurman', - 'Drew', - 'Ivey', - 'Bullard', - 'Baez', - 'Neff', - 'Maher', - 'Stratton', - 'Egan', - 'Dubois', - 'Gallardo', - 'Blue', - 'Rainey', - 'Yeager', - 'Saucedo', - 'Ferreira', - 'Sprague', - 'Lacy', - 'Hurtado', - 'Heard', - 'Connell', - 'Stahl', - 'Aldridge', - 'Amaya', - 'Forrest', - 'Erwin', - 'Gunn', - 'Swan', - 'Butcher', - 'Rosado', - 'Godwin', - 'Hand', - 'Gabriel', - 'Otto', - 'Whaley', - 'Ludwig', - 'Clifford', - 'Grove', - 'Beaver', - 'Silver', - 'Dang', - 'Hammer', - 'Dick', - 'Boswell', - 'Mead', - 'Colvin', - 'Oleary', - 'Milligan', - 'Goins', - 'Ames', - 'Dodge', - 'Kaur', - 'Escobedo', - 'Arredondo', - 'Geiger', - 'Winkler', - 'Dunham', - 'Temple', - 'Babcock', - 'Billings', - 'Grimm', - 'Lilly', - 'Wesley', - 'Mcghee', - 'Siegel', - 'Painter', - 'Bower', - 'Purcell', - 'Block', - 'Aguilera', - 'Norwood', - 'Sheridan', - 'Cartwright', - 'Coates', - 'Davison', - 'Regan', - 'Ramey', - 'Koenig', - 'Kraft', - 'Bunch', - 'Engel', - 'Tan', - 'Winn', - 'Steward', - 'Link', - 'Vickers', - 'Bragg', - 'Piper', - 'Huggins', - 'Michel', - 'Healy', - 'Jacob', - 'Mcdonough', - 'Wolff', - 'Colbert', - 'Zepeda', - 'Hoang', - 'Dugan', - 'Meade', - 'Kilgore', - 'Guillen', - 'Do', - 'Hinojosa', - 'Goode', - 'Arrington', - 'Gary', - 'Snell', - 'Willard', - 'Renteria', - 'Chacon', - 'Gallo', - 'Hankins', - 'Montano', - 'Browne', - 'Peacock', - 'Ohara', - 'Cornell', - 'Sherwood', - 'Castellanos', - 'Thorpe', - 'Stiles', - 'Sadler', - 'Latham', - 'Redmond', - 'Greenberg', - 'Cote', - 'Waddell', - 'Dukes', - 'Diamond', - 'Bui', - 'Madrid', - 'Alonso', - 'Sheets', - 'Irvin', - 'Hurt', - 'Ferris', - 'Sewell', - 'Carlton', - 'Aragon', - 'Blackmon', - 'Hadley', - 'Hoyt', - 'Mcgraw', - 'Pagan', - 'Land', - 'Tidwell', - 'Lovell', - 'Miner', - 'Doss', - 'Dahl', - 'Delatorre', - 'Stanford', - 'Kauffman', - 'Vela', - 'Gagnon', - 'Winston', - 'Gomes', - 'Thacker', - 'Coronado', - 'Ash', - 'Jarrett', - 'Hager', - 'Samuels', - 'Metzger', - 'Raines', - 'Spivey', - 'Maurer', - 'Han', - 'Voss', - 'Henley', - 'Caballero', - 'Caruso', - 'Coulter', - 'North', - 'Finn', - 'Cahill', - 'Lanier', - 'Souza', - 'Mcwilliams', - 'Deal', - 'Urban', - 'Schaffer', - 'Houser', - 'Cummins', - 'Romo', - 'Crocker', - 'Bassett', - 'Kruse', - 'Bolden', - 'Ybarra', - 'Metz', - 'Root', - 'Mcmullen', - 'Hagan', - 'Crump', - 'Guidry', - 'Brantley', - 'Kearney', - 'Beal', - 'Toth', - 'Jorgensen', - 'Timmons', - 'Milton', - 'Tripp', - 'Hurd', - 'Sapp', - 'Whitman', - 'Messer', - 'Burgos', - 'Major', - 'Westbrook', - 'Castle', - 'Serna', - 'Carlisle', - 'Varela', - 'Cullen', - 'Wilhelm', - 'Bergeron', - 'Burger', - 'Posey', - 'Barnhart', - 'Hackett', - 'Madrigal', - 'Eubanks', - 'Sizemore', - 'Hilliard', - 'Hargrove', - 'Boucher', - 'Thomason', - 'Melvin', - 'Roper', - 'Barnard', - 'Fonseca', - 'Pedersen', - 'Quiroz', - 'Washburn', - 'Holliday', - 'Yee', - 'Rudolph', - 'Bermudez', - 'Coyle', - 'Gil', - 'Pina', - 'Goodrich', - 'Elias', - 'Lockwood', - 'Cabral', - 'Carranza', - 'Duvall', - 'Cornelius', - 'Mccollum', - 'Street', - 'Mcneal', - 'Connors', - 'Angel', - 'Paulson', - 'Hinson', - 'Keenan', - 'Sheldon', - 'Farr', - 'Eddy', - 'Samuel', - 'Ring', - 'Ledbetter', - 'Betts', - 'Fontenot', - 'Gifford', - 'Hannah', - 'Hanley', - 'Person', - 'Fountain', - 'Levin', - 'Stubbs', - 'Hightower', - 'Murdock', - 'Koehler', - 'Ma', - 'Engle', - 'Smiley', - 'Carmichael', - 'Sheffield', - 'Langston', - 'Mccracken', - 'Yost', - 'Trotter', - 'Story', - 'Starks', - 'Lujan', - 'Blount', - 'Cody', - 'Rushing', - 'Benoit', - 'Herndon', - 'Jacobsen', - 'Nieto', - 'Wiseman', - 'Layton', - 'Epps', - 'Shipley', - 'Leyva', - 'Reeder', - 'Brand', - 'Roland', - 'Fitch', - 'Rico', - 'Napier', - 'Cronin', - 'Mcqueen', - 'Paredes', - 'Trent', - 'Christiansen', - 'Spangler', - 'Pettit', - 'Langford', - 'Benavides', - 'Penn', - 'Paige', - 'Weir', - 'Dietz', - 'Prater', - 'Brewster', - 'Louis', - 'Diehl', - 'Pack', - 'Spaulding', - 'Ernst', - 'Aviles', - 'Nowak', - 'Olvera', - 'Rock', - 'Mansfield', - 'Aquino', - 'Ogden', - 'Stacy', - 'Rizzo', - 'Sylvester', - 'Gillis', - 'Sands', - 'Machado', - 'Lovett', - 'Duong', - 'Hyatt', - 'Landis', - 'Platt', - 'Bustamante', - 'Hedrick', - 'Pritchett', - 'Gaston', - 'Dobson', - 'Caudill', - 'Tackett', - 'Bateman', - 'Landers', - 'Carmona', - 'Gipson', - 'Uribe', - 'Mcneill', - 'Ledford', - 'Mims', - 'Abel', - 'Gold', - 'Smallwood', - 'Thorne', - 'Mchugh', - 'Dickens', - 'Leung', - 'Tobin', - 'Kowalski', - 'Medeiros', - 'Cope', - 'Quezada', - 'Kraus', - 'Overton', - 'Montalvo', - 'Staley', - 'Woody', - 'Hathaway', - 'Osorio', - 'Laird', - 'Dobbs', - 'Capps', - 'Putnam', - 'Lay', - 'Francisco', - 'Bernstein', - 'Adair', - 'Hutton', - 'Burkett', - 'Rhoades', - 'Yanez', - 'Richey', - 'Bledsoe', - 'Mccain', - 'Beyer', - 'Cates', - 'Roche', - 'Spicer', - 'Queen', - 'Doty', - 'Darling', - 'Darby', - 'Sumner', - 'Kincaid', - 'Hay', - 'Grossman', - 'Lacey', - 'Wilkes', - 'Humphries', - 'Paz', - 'Darnell', - 'Keys', - 'Kyle', - 'Lackey', - 'Vogt', - 'Locklear', - 'Kiser', - 'Presley', - 'Bryson', - 'Bergman', - 'Peoples', - 'Fair', - 'Mcclendon', - 'Corley', - 'Prado', - 'Christie', - 'Delong', - 'Skaggs', - 'Dill', - 'Shearer', - 'Judd', - 'Stapleton', - 'Flaherty', - 'Casillas', - 'Pinto', - 'Youngblood', - 'Haywood', - 'Toney', - 'Ricks', - 'Granados', - 'Crum', - 'Triplett', - 'Soriano', - 'Waite', - 'Hoff', - 'Anaya', - 'Crenshaw', - 'Jung', - 'Canales', - 'Cagle', - 'Denny', - 'Marcus', - 'Berman', - 'Munson', - 'Ocampo', - 'Bauman', - 'Corcoran', - 'Keen', - 'Zimmer', - 'Friend', - 'Ornelas', - 'Varner', - 'Pelletier', - 'Vernon', - 'Blum', - 'Albrecht', - 'Culver', - 'Schuster', - 'Cuellar', - 'Mccord', - 'Shultz', - 'Mcrae', - 'Moreland', - 'Calvert', - 'William', - 'Whittington', - 'Eckert', - 'Keene', - 'Mohr', - 'Hanks', - 'Kimble', - 'Cavanaugh', - 'Crowell', - 'Russ', - 'Feliciano', - 'Crain', - 'Busch', - 'Mccormack', - 'Drummond', - 'Omalley', - 'Aldrich', - 'Luke', - 'Greco', - 'Mott', - 'Oakes', - 'Mallory', - 'Mclain', - 'Burrows', - 'Otero', - 'Allred', - 'Eason', - 'Finney', - 'Weller', - 'Waldron', - 'Champion', - 'Jeffers', - 'Coon', - 'Rosenthal', - 'Huddleston', - 'Solano', - 'Hirsch', - 'Akins', - 'Olivares', - 'Song', - 'Sneed', - 'Benedict', - 'Bain', - 'Okeefe', - 'Hidalgo', - 'Matos', - 'Stallings', - 'Paris', - 'Gamez', - 'Kenny', - 'Quigley', - 'Marrero', - 'Fagan', - 'Dutton', - 'Pappas', - 'Atwood', - 'Mcgovern', - 'Bagley', - 'Read', - 'Lunsford', - 'Moseley', - 'Oakley', - 'Ashby', - 'Granger', - 'Shaver', - 'Hope', - 'Coe', - 'Burroughs', - 'Helm', - 'Neumann', - 'Ambrose', - 'Michaels', - 'Prescott', - 'Light', - 'Dumas', - 'Flood', - 'Stringer', - 'Currie', - 'Comer', - 'Fong', - 'Whitlock', - 'Lemus', - 'Hawley', - 'Ulrich', - 'Staples', - 'Boykin', - 'Knutson', - 'Grover', - 'Hobson', - 'Cormier', - 'Doran', - 'Thayer', - 'Woodson', - 'Whitt', - 'Hooker', - 'Kohler', - 'Vandyke', - 'Addison', - 'Schrader', - 'Haskins', - 'Whittaker', - 'Madsen', - 'Gauthier', - 'Burnette', - 'Keating', - 'Purvis', - 'Aleman', - 'Huston', - 'Pimentel', - 'Hamlin', - 'Gerber', - 'Hooks', - 'Schwab', - 'Honeycutt', - 'Schulte', - 'Alonzo', - 'Isaac', - 'Conroy', - 'Adler', - 'Eastman', - 'Cottrell', - 'Orourke', - 'Hawk', - 'Goldsmith', - 'Rader', - 'Crandall', - 'Reynoso', - 'Shook', - 'Abernathy', - 'Baer', - 'Olivas', - 'Grayson', - 'Bartley', - 'Henning', - 'Parr', - 'Duff', - 'Brunson', - 'Baum', - 'Ennis', - 'Laughlin', - 'Foote', - 'Valadez', - 'Adamson', - 'Begay', - 'Stovall', - 'Lincoln', - 'Cheung', - 'Malloy', - 'Rider', - 'Giordano', - 'Jansen', - 'Lopes', - 'Arnett', - 'Pendleton', - 'Gage', - 'Barragan', - 'Keyes', - 'Navarrete', - 'Amador', - 'Hoffmann', - 'Schilling', - 'Hawthorne', - 'Perdue', - 'Schreiber', - 'Arevalo', - 'Naylor', - 'Deluca', - 'Marcum', - 'Altman', - 'Mark', - 'Chadwick', - 'Doan', - 'Easley', - 'Ladd', - 'Woodall', - 'Betancourt', - 'Shin', - 'Maguire', - 'Bellamy', - 'Quintanilla', - 'Ham', - 'Sorenson', - 'Mattson', - 'Brenner', - 'Means', - 'Faust', - 'Calloway', - 'Ojeda', - 'Mcnally', - 'Dietrich', - 'Ransom', - 'Hare', - 'Felton', - 'Whiting', - 'Burkhart', - 'Clinton', - 'Schwarz', - 'Cleary', - 'Wetzel', - 'Reagan', - 'Stjohn', - 'Chow', - 'Hauser', - 'Dupree', - 'Brannon', - 'Lyles', - 'Prather', - 'Willoughby', - 'Sepulveda', - 'Nugent', - 'Pickens', - 'Mosher', - 'Joiner', - 'Stoner', - 'Dowling', - 'Trimble', - 'Valdes', - 'Cheek', - 'Scruggs', - 'Coy', - 'Tilley', - 'Barney', - 'Saylor', - 'Nagy', - 'Horvath', - 'Lai', - 'Corey', - 'Ruth', - 'Sauer', - 'Baron', - 'Thao', - 'Rowell', - 'Grubbs', - 'Schaeffer', - 'Hillman', - 'Sams', - 'Hogue', - 'Hutson', - 'Busby', - 'Nickerson', - 'Bruner', - 'Parham', - 'Rendon', - 'Anders', - 'Lombardo', - 'Iverson', - 'Kinsey', - 'Earl', - 'Borden', - 'Titus', - 'Jean', - 'Tellez', - 'Beavers', - 'Cornett', - 'Sotelo', - 'Kellogg', - 'Silverman', - 'Burnham', - 'Mcnair', - 'Jernigan', - 'Escamilla', - 'Barrow', - 'Coats', - 'London', - 'Redding', - 'Ruffin', - 'Yi', - 'Boudreaux', - 'Goodson', - 'Dowell', - 'Fenton', - 'Mock', - 'Dozier', - 'Bynum', - 'Gale', - 'Jolly', - 'Beckman', - 'Goddard', - 'Craven', - 'Whitmore', - 'Leary', - 'Mccloud', - 'Gamboa', - 'Kerns', - 'Brunner', - 'Negron', - 'Hough', - 'Cutler', - 'Ledesma', - 'Pyle', - 'Monahan', - 'Tabor', - 'Burk', - 'Leone', - 'Stauffer', - 'Hayward', - 'Driver', - 'Ruff', - 'Talbot', - 'Seals', - 'Boston', - 'Carbajal', - 'Fay', - 'Purdy', - 'Mcgregor', - 'Sun', - 'Orellana', - 'Gentile', - 'Mahan', - 'Brower', - 'Patino', - 'Thurston', - 'Shipman', - 'Torrez', - 'Aaron', - 'Weiner', - 'Call', - 'Wilburn', - 'Oliva', - 'Hairston', - 'Coley', - 'Hummel', - 'Arreola', - 'Watt', - 'Sharma', - 'Lentz', - 'Arce', - 'Power', - 'Longoria', - 'Wagoner', - 'Burr', - 'Hsu', - 'Tinsley', - 'Beebe', - 'Wray', - 'Nunn', - 'Prieto', - 'German', - 'Rowley', - 'Grubb', - 'Brito', - 'Royal', - 'Valentin', - 'Bartholomew', - 'Schuler', - 'Aranda', - 'Flint', - 'Hearn', - 'Venegas', - 'Unger', - 'Mattingly', - 'Boles', - 'Casas', - 'Barger', - 'Julian', - 'Dow', - 'Dobbins', - 'Vann', - 'Chester', - 'Strange', - 'Lemon', - 'Kahn', - 'Mckinnon', - 'Gannon', - 'Waggoner', - 'Conn', - 'Meek', - 'Cavazos', - 'Skelton', - 'Lo', - 'Kumar', - 'Toledo', - 'Lorenz', - 'Vallejo', - 'Starkey', - 'Kitchen', - 'Reaves', - 'Demarco', - 'Farrar', - 'Stearns', - 'Michaud', - 'Higginbotham', - 'Fernandes', - 'Isaacs', - 'Marion', - 'Guillory', - 'Priest', - 'Meehan', - 'Oliveira', - 'Palma', - 'Oswald', - 'Loomis', - 'Galvez', - 'Lind', - 'Mena', - 'Stclair', - 'Hinds', - 'Reardon', - 'Alley', - 'Barth', - 'Crook', - 'Bliss', - 'Nagel', - 'Banuelos', - 'Parish', - 'Harman', - 'Douglass', - 'Kearns', - 'Newcomb', - 'Mulligan', - 'Coughlin', - 'Way', - 'Fournier', - 'Lawler', - 'Kaminski', - 'Barbour', - 'Sousa', - 'Stump', - 'Alaniz', - 'Ireland', - 'Rudd', - 'Carnes', - 'Lundy', - 'Godinez', - 'Pulido', - 'Dennison', - 'Burdick', - 'Baumann', - 'Dove', - 'Stoddard', - 'Liang', - 'Dent', - 'Roark', - 'Mcmahan', - 'Bowser', - 'Parnell', - 'Mayberry', - 'Wakefield', - 'Arndt', - 'Ogle', - 'Worthington', - 'Durbin', - 'Escalante', - 'Pederson', - 'Weldon', - 'Vick', - 'Knott', - 'Ryder', - 'Zarate', - 'Irving', - 'Clemens', - 'Shelley', - 'Salter', - 'Jack', - 'Cloud', - 'Dasilva', - 'Muhammad', - 'Squires', - 'Rapp', - 'Dawkins', - 'Polanco', - 'Chatman', - 'Maier', - 'Yazzie', - 'Gruber', - 'Staton', - 'Blackman', - 'Mcdonnell', - 'Dykes', - 'Laws', - 'Whitten', - 'Pfeiffer', - 'Vidal', - 'Early', - 'Kelsey', - 'Baughman', - 'Dias', - 'Starnes', - 'Crespo', - 'Lombardi', - 'Kilpatrick', - 'Deaton', - 'Satterfield', - 'Wiles', - 'Weinstein', - 'Rowan', - 'Delossantos', - 'Hamby', - 'Estep', - 'Daigle', - 'Elam', - 'Creech', - 'Heck', - 'Chavis', - 'Echols', - 'Foss', - 'Trahan', - 'Strauss', - 'Vanhorn', - 'Winslow', - 'Rea', - 'Heaton', - 'Fairchild', - 'Minton', - 'Hitchcock', - 'Linton', - 'Handy', - 'Crouse', - 'Coles', - 'Upton', - 'Foy', - 'Herrington', - 'Mcclelland', - 'Hwang', - 'Rector', - 'Luther', - 'Kruger', - 'Salcedo', - 'Chance', - 'Gunderson', - 'Tharp', - 'Griffiths', - 'Graf', - 'Branham', - 'Humphreys', - 'Renner', - 'Lima', - 'Rooney', - 'Moya', - 'Almeida', - 'Gavin', - 'Coburn', - 'Ouellette', - 'Goetz', - 'Seay', - 'Parrott', - 'Harms', - 'Robb', - 'Storey', - 'Barbosa', - 'Barraza', - 'Loyd', - 'Merchant', - 'Donohue', - 'Carrier', - 'Diggs', - 'Chastain', - 'Sherrill', - 'Whipple', - 'Braswell', - 'Weathers', - 'Linder', - 'Chapa', - 'Bock', - 'Oh', - 'Lovelace', - 'Saavedra', - 'Ferrara', - 'Callaway', - 'Salmon', - 'Templeton', - 'Christy', - 'Harp', - 'Dowd', - 'Forrester', - 'Lawton', - 'Epstein', - 'Gant', - 'Tierney', - 'Seaman', - 'Corral', - 'Dowdy', - 'Zaragoza', - 'Morrissey', - 'Eller', - 'Chau', - 'Breen', - 'High', - 'Newberry', - 'Beam', - 'Yancey', - 'Jarrell', - 'Cerda', - 'Ellsworth', - 'Lofton', - 'Thibodeaux', - 'Pool', - 'Rinehart', - 'Arteaga', - 'Marlow', - 'Hacker', - 'Will', - 'Mackenzie', - 'Hook', - 'Gilliland', - 'Emmons', - 'Pickering', - 'Medley', - 'Willey', - 'Andrew', - 'Shell', - 'Randle', - 'Brinkley', - 'Pruett', - 'Tobias', - 'Edmondson', - 'Grier', - 'Saldivar', - 'Batista', - 'Askew', - 'Moeller', - 'Chavarria', - 'Augustine', - 'Troyer', - 'Layne', - 'Mcnulty', - 'Shank', - 'Desai', - 'Herrmann', - 'Hemphill', - 'Bearden', - 'Spear', - 'Keener', - 'Holguin', - 'Culp', - 'Braden', - 'Briscoe', - 'Bales', - 'Garvin', - 'Stockton', - 'Abreu', - 'Suggs', - 'Mccartney', - 'Ferrer', - 'Rhoads', - 'Ha', - 'Nevarez', - 'Singletary', - 'Chong', - 'Alcala', - 'Cheney', - 'Westfall', - 'Damico', - 'Snodgrass', - 'Devries', - 'Looney', - 'Hein', - 'Lyle', - 'Lockett', - 'Jacques', - 'Barkley', - 'Wahl', - 'Aponte', - 'Myrick', - 'Bolin', - 'Holm', - 'Slack', - 'Scherer', - 'Martino', - 'Bachman', - 'Ely', - 'Nesbitt', - 'Marroquin', - 'Bouchard', - 'Mast', - 'Jameson', - 'Hills', - 'Mireles', - 'Bueno', - 'Pease', - 'Vitale', - 'Alarcon', - 'Linares', - 'Schell', - 'Lipscomb', - 'Arriaga', - 'Bourgeois', - 'Markham', - 'Bonds', - 'Wisniewski', - 'Ivy', - 'Oldham', - 'Wendt', - 'Fallon', - 'Joy', - 'Stamper', - 'Babb', - 'Steinberg', - 'Asher', - 'Fuchs', - 'Blank', - 'Willett', - 'Heredia', - 'Croft', - 'Lytle', - 'Lance', - 'Lassiter', - 'Barrientos', - 'Condon', - 'Barfield', - 'Darden', - 'Araujo', - 'Noonan', - 'Guinn', - 'Burleson', - 'Belanger', - 'Main', - 'Traylor', - 'Messina', - 'Zeigler', - 'Danielson', - 'Millard', - 'Kenyon', - 'Radford', - 'Graff', - 'Beaty', - 'Baggett', - 'Salisbury', - 'Crisp', - 'Trout', - 'Lorenzo', - 'Parson', - 'Gann', - 'Garber', - 'Adcock', - 'Covarrubias', - 'Scales', - 'Acuna', - 'Thrasher', - 'Card', - 'Van', - 'Mabry', - 'Mohamed', - 'Montanez', - 'Stock', - 'Redd', - 'Willingham', - 'Redman', - 'Zambrano', - 'Gaffney', - 'Herr', - 'Schubert', - 'Devlin', - 'Pringle', - 'Houck', - 'Casper', - 'Rees', - 'Wing', - 'Ebert', - 'Jeter', - 'Cornejo', - 'Gillette', - 'Shockley', - 'Amato', - 'Girard', - 'Leggett', - 'Cheatham', - 'Bustos', - 'Epperson', - 'Dubose', - 'Seitz', - 'Frias', - 'East', - 'Schofield', - 'Steen', - 'Orlando', - 'Myles', - 'Caron', - 'Grey', - 'Denney', - 'Ontiveros', - 'Burden', - 'Jaeger', - 'Reich', - 'Witherspoon', - 'Najera', - 'Frantz', - 'Hammonds', - 'Xu', - 'Leavitt', - 'Gilchrist', - 'Adam', - 'Barone', - 'Forman', - 'Ceja', - 'Ragsdale', - 'Sisk', - 'Tubbs', - 'Elizondo', - 'Pressley', - 'Bollinger', - 'Linn', - 'Huntley', - 'Dewey', - 'Geary', - 'Carlos', - 'Ragland', - 'Mixon', - 'Mcarthur', - 'Baugh', - 'Tam', - 'Nobles', - 'Clevenger', - 'Lusk', - 'Foust', - 'Cooney', - 'Tamayo', - 'Robert', - 'Longo', - 'Overstreet', - 'Oglesby', - 'Mace', - 'Churchill', - 'Matson', - 'Hamrick', - 'Rockwell', - 'Trammell', - 'Wheatley', - 'Carrington', - 'Ferraro', - 'Ralston', - 'Clancy', - 'Mondragon', - 'Carl', - 'Hu', - 'Hopson', - 'Breaux', - 'Mccurdy', - 'Mares', - 'Mai', - 'Chisholm', - 'Matlock', - 'Aiken', - 'Cary', - 'Lemons', - 'Anguiano', - 'Herrick', - 'Crawley', - 'Montero', - 'Hassan', - 'Archuleta', - 'Farias', - 'Cotter', - 'Parris', - 'Felder', - 'Luu', - 'Pence', - 'Gilman', - 'Killian', - 'Naranjo', - 'Duggan', - 'Scarborough', - 'Swann', - 'Easter', - 'Ricketts', - 'France', - 'Bello', - 'Nadeau', - 'Still', - 'Rincon', - 'Cornwell', - 'Slade', - 'Fierro', - 'Mize', - 'Christianson', - 'Greenfield', - 'Mcafee', - 'Landrum', - 'Adame', - 'Dinh', - 'Lankford', - 'Lewandowski', - 'Rust', - 'Bundy', - 'Waterman', - 'Milner', - 'Mccrary', - 'Hite', - 'Curley', - 'Donald', - 'Duckworth', - 'Cecil', - 'Carrera', - 'Speer', - 'Birch', - 'Denson', - 'Beckwith', - 'Stack', - 'Durant', - 'Lantz', - 'Dorman', - 'Christman', - 'Spann', - 'Masterson', - 'Hostetler', - 'Kolb', - 'Brink', - 'Scanlon', - 'Nye', - 'Wylie', - 'Beverly', - 'Woo', - 'Spurlock', - 'Sommer', - 'Shelby', - 'Reinhardt', - 'Robledo', - 'Bertrand', - 'Ashton', - 'Cyr', - 'Edgar', - 'Doe', - 'Harkins', - 'Brubaker', - 'Stoll', - 'Dangelo', - 'Zhou', - 'Moulton', - 'Hannon', - 'Falk', - 'Rains', - 'Broughton', - 'Applegate', - 'Hudgins', - 'Slone', - 'Yoon', - 'Farnsworth', - 'Perales', - 'Reedy', - 'Milam', - 'Franz', - 'Ponder', - 'Ricci', - 'Fontaine', - 'Irizarry', - 'Puente', - 'New', - 'Selby', - 'Cazares', - 'Doughty', - 'Moffett', - 'Balderas', - 'Fine', - 'Smalley', - 'Carlin', - 'Trinh', - 'Dyson', - 'Galvin', - 'Valdivia', - 'Benner', - 'Low', - 'Turpin', - 'Lyman', - 'Billingsley', - 'Mcadams', - 'Cardwell', - 'Fraley', - 'Patten', - 'Holton', - 'Shanks', - 'Mcalister', - 'Canfield', - 'Sample', - 'Harley', - 'Cason', - 'Tomlin', - 'Ahmad', - 'Coyne', - 'Forte', - 'Riggins', - 'Littlejohn', - 'Forsythe', - 'Brinson', - 'Halverson', - 'Bach', - 'Stuckey', - 'Falcon', - 'Wenzel', - 'Talbert', - 'Champagne', - 'Mchenry', - 'Vest', - 'Shackelford', - 'Ordonez', - 'Collazo', - 'Boland', - 'Sisson', - 'Bigelow', - 'Wharton', - 'Hyman', - 'Brumfield', - 'Oates', - 'Mesa', - 'Morrell', - 'Beckett', - 'Reis', - 'Alves', - 'Chiu', - 'Larue', - 'Streeter', - 'Grogan', - 'Blakely', - 'Brothers', - 'Hatton', - 'Kimbrough', - 'Lauer', - 'Wallis', - 'Jett', - 'Pepper', - 'Hildebrand', - 'Rawls', - 'Mello', - 'Neville', - 'Bull', - 'Steffen', - 'Braxton', - 'Cowart', - 'Simpkins', - 'Mcneely', - 'Blalock', - 'Spain', - 'Shipp', - 'Lindquist', - 'Oreilly', - 'Butterfield', - 'Perrin', - 'Qualls', - 'Edge', - 'Havens', - 'Luong', - 'Switzer', - 'Troutman', - 'Fortner', - 'Tolliver', - 'Monk', - 'Poindexter', - 'Rupp', - 'Ferry', - 'Negrete', - 'Muse', - 'Gresham', - 'Beauchamp', - 'Schmid', - 'Barclay', - 'Chun', - 'Brice', - 'Faulk', - 'Watters', - 'Briones', - 'Guajardo', - 'Harwood', - 'Grissom', - 'Harlow', - 'Whelan', - 'Burdette', - 'Palumbo', - 'Paulsen', - 'Corrigan', - 'Garvey', - 'Levesque', - 'Dockery', - 'Delgadillo', - 'Gooch', - 'Cao', - 'Mullin', - 'Ridley', - 'Stanfield', - 'Noriega', - 'Dial', - 'Ceballos', - 'Nunes', - 'Newby', - 'Baumgartner', - 'Hussain', - 'Wyman', - 'Causey', - 'Gossett', - 'Ness', - 'Waugh', - 'Choate', - 'Carman', - 'Daily', - 'Kong', - 'Devore', - 'Irby', - 'Breeden', - 'Whatley', - 'Ellington', - 'Lamar', - 'Fultz', - 'Bair', - 'Zielinski', - 'Colby', - 'Houghton', - 'Grigsby', - 'Fortune', - 'Paxton', - 'Mcmillian', - 'Hammons', - 'Bronson', - 'Keck', - 'Wellman', - 'Ayres', - 'Whiteside', - 'Menard', - 'Roush', - 'Warden', - 'Espino', - 'Strand', - 'Haggerty', - 'Banda', - 'Krebs', - 'Fabian', - 'Bowie', - 'Branson', - 'Lenz', - 'Benavidez', - 'Keeler', - 'Newsom', - 'Ezell', - 'Jeffrey', - 'Pulliam', - 'Clary', - 'Byrnes', - 'Kopp', - 'Beers', - 'Smalls', - 'Sommers', - 'Gardiner', - 'Fennell', - 'Mancini', - 'Osullivan', - 'Sebastian', - 'Bruns', - 'Giron', - 'Parent', - 'Boyles', - 'Keefe', - 'Muir', - 'Wheat', - 'Vergara', - 'Shuler', - 'Pemberton', - 'South', - 'Brownlee', - 'Brockman', - 'Royer', - 'Fanning', - 'Herzog', - 'Morley', - 'Bethea', - 'Tong', - 'Needham', - 'Roque', - 'Mojica', - 'Bunn', - 'Francois', - 'Noe', - 'Kuntz', - 'Snowden', - 'Withers', - 'Harlan', - 'Seibert', - 'Limon', - 'Kiefer', - 'Bone', - 'Sell', - 'Allan', - 'Skidmore', - 'Wren', - 'Dunaway', - 'Finnegan', - 'Moe', - 'Wolford', - 'Seeley', - 'Kroll', - 'Lively', - 'Janssen', - 'Montague', - 'Rahman', - 'Boehm', - 'Nettles', - 'Dees', - 'Krieger', - 'Peek', - 'Hershberger', - 'Sage', - 'Custer', - 'Zheng', - 'Otoole', - 'Jaimes', - 'Elrod', - 'Somers', - 'Lira', - 'Nagle', - 'Grooms', - 'Soria', - 'Drury', - 'Keane', - 'Bostic', - 'Hartmann', - 'Pauley', - 'Murrell', - 'Manzo', - 'Morey', - 'Agee', - 'Hamel', - 'Tavares', - 'Dunning', - 'Mccloskey', - 'Plunkett', - 'Maples', - 'March', - 'Armenta', - 'Waldrop', - 'Espinal', - 'Fajardo', - 'Christenson', - 'Robins', - 'Bagwell', - 'Massie', - 'Leahy', - 'Urbina', - 'Medlin', - 'Zhu', - 'Pantoja', - 'Barbee', - 'Clawson', - 'Reiter', - 'Ko', - 'Crider', - 'Maxey', - 'Worrell', - 'Brackett', - 'Mclemore', - 'Younger', - 'Her', - 'Hardesty', - 'Danner', - 'Ragan', - 'Almanza', - 'Nielson', - 'Graber', - 'Mcintire', - 'Tirado', - 'Griswold', - 'Seifert', - 'Valles', - 'Laney', - 'Gupta', - 'Malik', - 'Libby', - 'Marvin', - 'Koontz', - 'Marr', - 'Kozlowski', - 'Lemke', - 'Brant', - 'Phelan', - 'Kemper', - 'Gooden', - 'Beaulieu', - 'Cardoza', - 'Healey', - 'Zhao', - 'Hardwick', - 'Kitchens', - 'Box', - 'Stepp', - 'Comstock', - 'Poston', - 'Sager', - 'Conti', - 'Borges', - 'Farrow', - 'Acker', - 'Glaser', - 'Antonio', - 'Lennon', - 'Gaither', - 'Freitas', - 'Alicea', - 'Mcmillen', - 'Chapin', - 'Ratcliff', - 'Lerma', - 'Severson', - 'Wilde', - 'Mortensen', - 'Winchester', - 'Flannery', - 'Villasenor', - 'Centeno', - 'Burkholder', - 'Horan', - 'Meador', - 'Ingle', - 'Roldan', - 'Estrella', - 'Pullen', - 'Newkirk', - 'Gaytan', - 'Lindberg', - 'Windham', - 'Gatlin', - 'Stoltzfus', - 'Behrens', - 'Cintron', - 'Broderick', - 'Solorzano', - 'Jaime', - 'Venable', - 'Culbertson', - 'Garay', - 'Caputo', - 'Grantham', - 'Hanlon', - 'Parry', - 'Crist', - 'Cosby', - 'Shore', - 'Everhart', - 'Dorn', - 'Turley', - 'Eng', - 'Valerio', - 'Rand', - 'Hiatt', - 'Mota', - 'Judge', - 'Kinder', - 'Colwell', - 'Ashworth', - 'Tejeda', - 'Sikes', - 'Oshea', - 'Westmoreland', - 'Faber', - 'Culpepper', - 'Logsdon', - 'Fugate', - 'Apodaca', - 'Lindley', - 'Samson', - 'Liles', - 'Mcclanahan', - 'Burge', - 'Vail', - 'Etheridge', - 'Boudreau', - 'Andres', - 'Noll', - 'Higgs', - 'Snead', - 'Layman', - 'Turk', - 'Nolen', - 'Wayne', - 'Betz', - 'Victor', - 'Lafferty', - 'Carbone', - 'Skipper', - 'Zeller', - 'Kasper', - 'Desantis', - 'Fogle', - 'Gandy', - 'Mendenhall', - 'Seward', - 'Schweitzer', - 'Gulley', - 'Stine', - 'Sowers', - 'Duenas', - 'Monson', - 'Brinkman', - 'Hubert', - 'Motley', - 'Pfeifer', - 'Weinberg', - 'Eggleston', - 'Isom', - 'Quinlan', - 'Gilley', - 'Jasso', - 'Loya', - 'Mull', - 'Reichert', - 'Wirth', - 'Reddy', - 'Hodgson', - 'Stowe', - 'Mccallum', - 'Ahrens', - 'Huey', - 'Mattox', - 'Dupont', - 'Aguayo', - 'Pak', - 'Tice', - 'Alba', - 'Colburn', - 'Currier', - 'Gaskins', - 'Harder', - 'Cohn', - 'Yoo', - 'Garnett', - 'Harter', - 'Wenger', - 'Charlton', - 'Littleton', - 'Minter', - 'Henriquez', - 'Cone', - 'Vines', - 'Kimmel', - 'Crooks', - 'Caraballo', - 'Searcy', - 'Peyton', - 'Renfro', - 'Groff', - 'Thorn', - 'Moua', - 'Jay', - 'Leigh', - 'Sanborn', - 'Wicker', - 'Martens', - 'Broome', - 'Abney', - 'Fisk', - 'Argueta', - 'Upchurch', - 'Alderman', - 'Tisdale', - 'Castellano', - 'Legg', - 'Wilbur', - 'Bills', - 'Dix', - 'Mauldin', - 'Isbell', - 'Mears', - 'Latimer', - 'Ashcraft', - 'Earley', - 'Tejada', - 'Partridge', - 'Anglin', - 'Caswell', - 'Easton', - 'Kirchner', - 'Mehta', - 'Lanham', - 'Blaylock', - 'Binder', - 'Catalano', - 'Handley', - 'Storm', - 'Albertson', - 'Free', - 'Tuck', - 'Keegan', - 'Moriarty', - 'Dexter', - 'Mancuso', - 'Allard', - 'Pino', - 'Chamberlin', - 'Moffitt', - 'Haag', - 'Schott', - 'Agnew', - 'Malcolm', - 'Hallman', - 'Heckman', - 'Karr', - 'Soares', - 'Alfonso', - 'Tom', - 'Wadsworth', - 'Schindler', - 'Garibay', - 'Kuykendall', - 'Penny', - 'Littlefield', - 'Mcnabb', - 'Sam', - 'Lea', - 'Berrios', - 'Murry', - 'Regalado', - 'Dehart', - 'Mohammed', - 'Counts', - 'Solorio', - 'Preciado', - 'Armendariz', - 'Martell', - 'Barksdale', - 'Frick', - 'Haller', - 'Broyles', - 'Doll', - 'Cable', - 'Delvalle', - 'Weems', - 'Kelleher', - 'Gagne', - 'Albers', - 'Kunz', - 'Hoy', - 'Hawes', - 'Guenther', - 'Johansen', - 'Chaffin', - 'Whitworth', - 'Wynne', - 'Mcmurray', - 'Luce', - 'Fiore', - 'Straub', - 'Majors', - 'Mcduffie', - 'Bohannon', - 'Rawlings', - 'Freed', - 'Sutter', - 'Lindstrom', - 'Buss', - 'Loera', - 'Hoyle', - 'Witte', - 'Tyree', - 'Luttrell', - 'Andrus', - 'Steed', - 'Thiel', - 'Cranford', - 'Fulmer', - 'Gable', - 'Porras', - 'Weis', - 'Maas', - 'Packard', - 'Noyes', - 'Kwon', - 'Knoll', - 'Marx', - 'Feeney', - 'Israel', - 'Bohn', - 'Cockrell', - 'Glick', - 'Cosgrove', - 'Keefer', - 'Mundy', - 'Batchelor', - 'Loveless', - 'Horowitz', - 'Haskell', - 'Kunkel', - 'Colson', - 'Hedges', - 'Staggs', - 'Swisher', - 'Lomeli', - 'Padron', - 'Cota', - 'Homan', - 'Musser', - 'Curtin', - 'Salerno', - 'Segovia', - 'Keeton', - 'Brandenburg', - 'Starling', - 'Tsai', - 'Mahon', - 'Klinger', - 'Paquette', - 'Haddad', - 'Mccune', - 'Mathew', - 'Shull', - 'Higdon', - 'Guest', - 'Shay', - 'Swafford', - 'Angulo', - 'Hackney', - 'Evers', - 'Sibley', - 'Woodworth', - 'Ostrander', - 'Mangum', - 'Smyth', - 'Quarles', - 'Mccarter', - 'Close', - 'Truitt', - 'Stpierre', - 'Mackay', - 'Bayer', - 'Timm', - 'Thatcher', - 'Bess', - 'Trinidad', - 'Jacoby', - 'Proffitt', - 'Concepcion', - 'Parkinson', - 'Carreon', - 'Ramon', - 'Monroy', - 'Leger', - 'Jauregui', - 'Glynn', - 'Taggart', - 'Neil', - 'Reddick', - 'Wiese', - 'Dover', - 'Wicks', - 'Hennessy', - 'Bittner', - 'Mcclung', - 'Mcwhorter', - 'Derrick', - 'Strom', - 'Beckham', - 'Kee', - 'Coombs', - 'Schrock', - 'Holtz', - 'Maki', - 'Willson', - 'Hulsey', - 'Whitson', - 'Haugen', - 'Lumpkin', - 'Scholl', - 'Gall', - 'Carvalho', - 'Kovach', - 'Vieira', - 'Millan', - 'Irvine', - 'Held', - 'Jolley', - 'Jasper', - 'Cadena', - 'Runyon', - 'Lomax', - 'Fahey', - 'Hoppe', - 'Bivens', - 'Ruggiero', - 'Hussey', - 'Ainsworth', - 'Hardman', - 'Ulloa', - 'Dugger', - 'Fitzsimmons', - 'Scroggins', - 'Sowell', - 'Toler', - 'Barba', - 'Biddle', - 'Rafferty', - 'Trapp', - 'Byler', - 'Brill', - 'Delagarza', - 'Thigpen', - 'Hiller', - 'Martins', - 'Jankowski', - 'Findley', - 'Hollins', - 'Stull', - 'Pollack', - 'Poirier', - 'Reno', - 'Bratton', - 'Jeffery', - 'Menendez', - 'Mcnutt', - 'Kohl', - 'Forster', - 'Clough', - 'Deloach', - 'Bader', - 'Hanes', - 'Sturm', - 'Tafoya', - 'Beall', - 'Coble', - 'Demers', - 'Kohn', - 'Santamaria', - 'Vaught', - 'Correia', - 'Mcgrew', - 'Sarmiento', - 'Roby', - 'Reinhart', - 'Rosenbaum', - 'Bernier', - 'Schiller', - 'Furman', - 'Grabowski', - 'Perryman', - 'Kidwell', - 'Sabo', - 'Saxton', - 'Noland', - 'Seaton', - 'Packer', - 'Seal', - 'Ruby', - 'Smoot', - 'Lavoie', - 'Putman', - 'Fairbanks', - 'Neill', - 'Florence', - 'Beattie', - 'Tarver', - 'Stephen', - 'Bolen', - 'Mccombs', - 'Freedman', - 'Barnhill', - 'Gaddis', - 'Goad', - 'Worden', - 'Canada', - 'Vickery', - 'Calvin', - 'Mcclintock', - 'Slocum', - 'Clausen', - 'Mccutcheon', - 'Ripley', - 'Razo', - 'Southard', - 'Bourne', - 'Aiello', - 'Knudsen', - 'Angeles', - 'Keeney', - 'Stacey', - 'Neeley', - 'Holly', - 'Gallant', - 'Eads', - 'Lafleur', - 'Fredrickson', - 'Popp', - 'Bobo', - 'Pardo', - 'Artis', - 'Lawless', - 'Shen', - 'Headley', - 'Pedraza', - 'Pickard', - 'Salvador', - 'Hofmann', - 'Davey', - 'Szymanski', - 'Dallas', - 'Erb', - 'Perea', - 'Alcantar', - 'Ashford', - 'Harry', - 'Crutchfield', - 'Goebel', - 'Ridgeway', - 'Mcvey', - 'Cordell', - 'Kovacs', - 'Florez', - 'Calkins', - 'Redden', - 'Ricker', - 'Salcido', - 'Farrington', - 'Reimer', - 'Mullis', - 'Mayhew', - 'Register', - 'Kaye', - 'Blocker', - 'Buford', - 'Munguia', - 'Cady', - 'Burley', - 'Sander', - 'Robinette', - 'Stubblefield', - 'Shuman', - 'Santillan', - 'Loy', - 'Deutsch', - 'Sales', - 'Langdon', - 'Mazur', - 'Clapp', - 'Teal', - 'Buffington', - 'Elliot', - 'Halstead', - 'Sturgeon', - 'Colley', - 'Koehn', - 'Bergstrom', - 'Dunne', - 'Pond', - 'Gantt', - 'Cousins', - 'Viera', - 'Wilks', - 'Haase', - 'Sweat', - 'Simonson', - 'Breedlove', - 'Munn', - 'Pitt', - 'Faircloth', - 'Peter', - 'Wheaton', - 'Howland', - 'Merriman', - 'Fusco', - 'Burney', - 'Bedford', - 'Baltazar', - 'Persaud', - 'Gerard', - 'Bourque', - 'Chao', - 'Slagle', - 'Kirsch', - 'Volk', - 'Heim', - 'Glasgow', - 'Borders', - 'Rauch', - 'Goforth', - 'Batson', - 'Basham', - 'Mount', - 'Peace', - 'Lazo', - 'Samples', - 'Amaro', - 'Slattery', - 'Ibrahim', - 'Weatherford', - 'Taft', - 'Santoro', - 'Aparicio', - 'Jiang', - 'Ritchey', - 'Goble', - 'Spring', - 'Strain', - 'Scully', - 'Villareal', - 'Toro', - 'Duval', - 'Jonas', - 'Neuman', - 'Wozniak', - 'Varney', - 'Dell', - 'Conover', - 'Landon', - 'Sigler', - 'Galbraith', - 'Boss', - 'Cepeda', - 'Back', - 'Mateo', - 'Peebles', - 'Arsenault', - 'Cathey', - 'Calabrese', - 'Dodds', - 'Gilbertson', - 'Hoke', - 'Greenlee', - 'Sauceda', - 'Vue', - 'Lehmann', - 'Zink', - 'Lapointe', - 'Laster', - 'Moy', - 'Ammons', - 'Llamas', - 'Foltz', - 'Fleck', - 'Chew', - 'Amaral', - 'Geer', - 'Su', - 'Carden', - 'Nunley', - 'Creel', - 'Clarkson', - 'Provost', - 'Covey', - 'Paine', - 'Wofford', - 'Frame', - 'Dube', - 'Grice', - 'Tully', - 'Molnar', - 'Luciano', - 'Bartels', - 'Winstead', - 'Canady', - 'Moreau', - 'Burnside', - 'Bratcher', - 'Infante', - 'Peterman', - 'Swope', - 'Freeland', - 'Vetter', - 'Lanning', - 'Marquis', - 'Schulze', - 'Thai', - 'Coppola', - 'Rayburn', - 'Conte', - 'Martz', - 'Showalter', - 'Quinonez', - 'Bandy', - 'Rao', - 'Bunting', - 'Belt', - 'Cruse', - 'Hamblin', - 'Himes', - 'Raney', - 'Merrell', - 'See', - 'Gough', - 'Maciel', - 'Wimberly', - 'Craddock', - 'Marquardt', - 'Wentz', - 'Meeker', - 'Sandberg', - 'Mosier', - 'Wasson', - 'Hundley', - 'Joe', - 'Shumaker', - 'Fortin', - 'Embry', - 'Olivarez', - 'Akin', - 'Seidel', - 'Coons', - 'Corrales', - 'Earle', - 'Matheny', - 'Kish', - 'Outlaw', - 'Lieberman', - 'Spalding', - 'Barnette', - 'Martel', - 'Hargis', - 'Kelso', - 'Merrick', - 'Fullerton', - 'Fries', - 'Doucette', - 'Clouse', - 'Prewitt', - 'Hawks', - 'Keaton', - 'Worthy', - 'Zook', - 'Montez', - 'Poore', - 'Autry', - 'Lemay', - 'Shifflett', - 'Forsyth', - 'Briseno', - 'Piazza', - 'Welker', - 'Tennant', - 'Heinz', - 'Haggard', - 'Leighton', - 'Brittain', - 'Begley', - 'Flanders', - 'Hermann', - 'Botello', - 'Mathias', - 'Hofer', - 'Hutto', - 'Godoy', - 'Cave', - 'Pagano', - 'Asbury', - 'Bowens', - 'Withrow', - 'Olivo', - 'Harbin', - 'Andre', - 'Sandlin', - 'Wertz', - 'Desimone', - 'Greiner', - 'Heinrich', - 'Whitcomb', - 'Dayton', - 'Petrie', - 'Hair', - 'Ketchum', - 'Shanahan', - 'Bianco', - 'Heil', - 'Cochrane', - 'Wegner', - 'Dagostino', - 'Couture', - 'Ling', - 'Wingate', - 'Arenas', - 'Keel', - 'Casteel', - 'Boothe', - 'Derosa', - 'Horst', - 'Rau', - 'Palermo', - 'Mccorkle', - 'Altamirano', - 'Nall', - 'Shumate', - 'Lightfoot', - 'Creamer', - 'Romeo', - 'Coffin', - 'Hutchings', - 'Jerome', - 'Hutcheson', - 'Damron', - 'Sorrell', - 'Nickel', - 'Sells', - 'Pinkerton', - 'Dao', - 'Dion', - 'Mcfarlane', - 'Ridenour', - 'Atwell', - 'Sturgill', - 'Schoen', - 'Partin', - 'Nemeth', - 'Almonte', - 'Pan', - 'Rickard', - 'Wentworth', - 'Sammons', - 'Sayre', - 'Southerland', - 'Parisi', - 'Ahn', - 'Carrion', - 'Testa', - 'Shorter', - 'Covert', - 'Gorham', - 'Alcantara', - 'Belton', - 'Bannister', - 'Sharkey', - 'Mccreary', - 'Pannell', - 'Scarbrough', - 'Keeling', - 'Gainey', - 'Mill', - 'Camarena', - 'Herbst', - 'Roller', - 'Wild', - 'Dellinger', - 'Lovejoy', - 'Manson', - 'Dupuis', - 'Clem', - 'Resendez', - 'Burkhardt', - 'Williford', - 'Mclendon', - 'Mazza', - 'Mccaffrey', - 'Lum', - 'Settle', - 'Hefner', - 'Dupre', - 'Louie', - 'Gunther', - 'Weimer', - 'Turnbull', - 'Bradbury', - 'Maness', - 'Urena', - 'Lor', - 'Sides', - 'Wick', - 'Monaco', - 'Gillen', - 'Ives', - 'Battaglia', - 'Ulmer', - 'Schreiner', - 'Caceres', - 'Sprouse', - 'Scoggins', - 'Ahern', - 'Tracey', - 'Terrazas', - 'Bracken', - 'Gurley', - 'Soliz', - 'Alcaraz', - 'Martines', - 'Weidner', - 'Criswell', - 'Wilbanks', - 'Hennessey', - 'Mendes', - 'Peak', - 'Ruelas', - 'Caudle', - 'Fuqua', - 'Jewett', - 'Chism', - 'Volpe', - 'Nino', - 'Logue', - 'Mcculloch', - 'Furr', - 'Kersey', - 'Shinn', - 'Yan', - 'Rausch', - 'Stinnett', - 'Mowery', - 'Rivero', - 'Weed', - 'Bertram', - 'Durand', - 'Gatewood', - 'Tilton', - 'Mahaffey', - 'Niles', - 'Mccue', - 'Vargo', - 'Holcombe', - 'Ralph', - 'Castleberry', - 'Snipes', - 'Wilt', - 'Vanmeter', - 'Nutter', - 'Mendiola', - 'Burchett', - 'Enos', - 'Jobe', - 'Kirkwood', - 'Pedroza', - 'Iglesias', - 'Leong', - 'Cromer', - 'Trice', - 'Magnuson', - 'Eagle', - 'Montenegro', - 'Troy', - 'Cato', - 'Edmond', - 'Hendrick', - 'Lebron', - 'Lathrop', - 'Budd', - 'Appel', - 'Knowlton', - 'Bianchi', - 'Camarillo', - 'Ginn', - 'Pulley', - 'True', - 'Gaddy', - 'Domingo', - 'Kingsley', - 'Loftus', - 'Denham', - 'Sifuentes', - 'Siler', - 'Hardison', - 'Kwan', - 'Pendergrass', - 'Frasier', - 'Hutchens', - 'Fort', - 'Montiel', - 'Fincher', - 'Eggers', - 'Moen', - 'Griffis', - 'Hauck', - 'Lister', - 'Lundberg', - 'Tanaka', - 'Cornish', - 'Whitlow', - 'Chou', - 'Griego', - 'Robson', - 'Prosser', - 'Ballinger', - 'Fogarty', - 'Allman', - 'Atchison', - 'Conaway', - 'Riddick', - 'Rupert', - 'Krug', - 'Pinkston', - 'Coggins', - 'Narvaez', - 'Earnest', - 'Fain', - 'Rash', - 'Olmstead', - 'Sherrod', - 'Beeler', - 'Spearman', - 'Poland', - 'Rousseau', - 'Hyland', - 'Rhea', - 'Son', - 'Redmon', - 'Wilke', - 'Valenti', - 'Paulino', - 'Geyer', - 'Blackwood', - 'Leclair', - 'Olguin', - 'Maestas', - 'Buckingham', - 'Blythe', - 'Samuelson', - 'Bounds', - 'Nakamura', - 'Batts', - 'Galarza', - 'Sisco', - 'Mcvay', - 'Hynes', - 'Mertz', - 'Tremblay', - 'Orosco', - 'Prentice', - 'Wilhite', - 'Seiler', - 'Archibald', - 'Wooldridge', - 'Winfield', - 'Oden', - 'Zelaya', - 'Chestnut', - 'Guardado', - 'Mccallister', - 'Canty', - 'Grasso', - 'Collett', - 'Hylton', - 'Easterling', - 'Deangelis', - 'Treadway', - 'Ferrari', - 'Ethridge', - 'Milburn', - 'Mercier', - 'Bickford', - 'Thibodeau', - 'Bolanos', - 'Fellows', - 'Hales', - 'Greathouse', - 'Buchholz', - 'Strunk', - 'Faison', - 'Purnell', - 'Clegg', - 'Steinmetz', - 'Wojcik', - 'Alcorn', - 'Ballesteros', - 'Basile', - 'Paez', - 'Armour', - 'Devito', - 'Tello', - 'Flick', - 'Yount', - 'Estevez', - 'Hitt', - 'Houle', - 'Cha', - 'Travers', - 'Cass', - 'Loper', - 'Getz', - 'Cade', - 'Gonsalves', - 'Lear', - 'Cromwell', - 'Stephan', - 'Ocasio', - 'Deluna', - 'Tolentino', - 'Picard', - 'Eaves', - 'Toscano', - 'Ault', - 'Osburn', - 'Ruvalcaba', - 'Szabo', - 'Kozak', - 'Bear', - 'Eck', - 'Deyoung', - 'Morehead', - 'Herrin', - 'Tillery', - 'Royster', - 'Kehoe', - 'Swank', - 'Yamamoto', - 'Schoonover', - 'Clanton', - 'Stutzman', - 'Swearingen', - 'Martinson', - 'Harrelson', - 'Leo', - 'Keyser', - 'Guyton', - 'Lucio', - 'Veal', - 'Vanwinkle', - 'Angelo', - 'Zamudio', - 'Haddock', - 'Quach', - 'Thomsen', - 'Curiel', - 'Badger', - 'Teel', - 'Hibbard', - 'Dvorak', - 'Ballew', - 'Falls', - 'Bostick', - 'Monaghan', - 'Segal', - 'Denning', - 'Bahr', - 'Serrato', - 'Toomey', - 'Lacroix', - 'Antoine', - 'Resendiz', - 'Sperry', - 'Rosser', - 'Bogan', - 'Gaspar', - 'Amin', - 'Schramm', - 'Lemaster', - 'Echevarria', - 'Lilley', - 'Poling', - 'Villagomez', - 'Conde', - 'Delrio', - 'Lerner', - 'Leroy', - 'Otis', - 'Durkin', - 'Lavender', - 'Schenk', - 'Ong', - 'Guess', - 'Alanis', - 'Jacobo', - 'Ramsay', - 'Henke', - 'Sledge', - 'Whited', - 'Frazer', - 'Fortier', - 'Macleod', - 'Pascual', - 'Casanova', - 'Olds', - 'Jenson', - 'Tijerina', - 'Flora', - 'Casto', - 'Rinaldi', - 'Blunt', - 'Fontana', - 'Minnick', - 'Larios', - 'Raynor', - 'Fung', - 'Marek', - 'Valladares', - 'Clemmons', - 'Gracia', - 'Rohrer', - 'Fryer', - 'Folsom', - 'Gearhart', - 'Sumpter', - 'Kraemer', - 'Aceves', - 'Pettigrew', - 'Mclaurin', - 'Southern', - 'Barrows', - 'Landeros', - 'Janes', - 'Deguzman', - 'Mcfall', - 'Fredericks', - 'Ashe', - 'Mauro', - 'Merino', - 'Windsor', - 'Taber', - 'Armijo', - 'Bricker', - 'Pitman', - 'Morrill', - 'Sanches', - 'Deboer', - 'Conlon', - 'Reuter', - 'Stegall', - 'Clemente', - 'Romine', - 'Dykstra', - 'Ehlers', - 'Tallman', - 'Lovato', - 'Brent', - 'Pearl', - 'Pyles', - 'Cloutier', - 'Mccurry', - 'Mckeever', - 'Graziano', - 'Heflin', - 'Garman', - 'Isaacson', - 'Mcreynolds', - 'Meister', - 'Stroup', - 'Everson', - 'Halsey', - 'Mcewen', - 'Sparkman', - 'Yager', - 'Bucher', - 'Berryman', - 'Derr', - 'Jester', - 'Mickelson', - 'Sayers', - 'Whiteman', - 'Riordan', - 'Mcinnis', - 'Jose', - 'Goolsby', - 'Stidham', - 'Donley', - 'Johnsen', - 'Stallworth', - 'Franke', - 'Silvers', - 'Reitz', - 'Nathan', - 'Brogan', - 'Cardoso', - 'Linville', - 'Baptiste', - 'Gorski', - 'Rey', - 'Hazen', - 'Damon', - 'Shores', - 'Boling', - 'Jablonski', - 'Lemieux', - 'Hecht', - 'Dong', - 'Langlois', - 'Burrow', - 'Hernandes', - 'Mcdevitt', - 'Pichardo', - 'Lew', - 'Stillwell', - 'Savoy', - 'Teixeira', - 'Matheson', - 'Hildreth', - 'Warfield', - 'Hogg', - 'Tiller', - 'Unruh', - 'Rudy', - 'Bristol', - 'Matias', - 'Buxton', - 'Ambriz', - 'Chiang', - 'Pomeroy', - 'Pogue', - 'Hammock', - 'Bethel', - 'Miguel', - 'Cassell', - 'Towns', - 'Bunker', - 'Mcmichael', - 'Kress', - 'Newland', - 'Whitehurst', - 'Fazio', - 'Batten', - 'Calvillo', - 'Wallen', - 'Lung', - 'Turney', - 'Sparrow', - 'Steadman', - 'Battles', - 'Berlin', - 'Lindgren', - 'Mckeon', - 'Luckett', - 'Spradlin', - 'Sherry', - 'Timmerman', - 'Utley', - 'Beale', - 'Driggers', - 'Hintz', - 'Pellegrino', - 'Hazel', - 'Grim', - 'Desmond', - 'Spellman', - 'Boren', - 'Staten', - 'Schlegel', - 'Maya', - 'Johnstone', - 'Harwell', - 'Pinson', - 'Barreto', - 'Spooner', - 'Candelaria', - 'Hammett', - 'Sessions', - 'Mckeown', - 'Mccool', - 'Gilson', - 'Knudson', - 'Irish', - 'Spruill', - 'Kling', - 'Gerlach', - 'Carnahan', - 'Markley', - 'Laporte', - 'Flanigan', - 'Spires', - 'Cushman', - 'Plante', - 'Schlosser', - 'Sachs', - 'Jamieson', - 'Hornsby', - 'Armstead', - 'Kremer', - 'Madera', - 'Thornburg', - 'Briley', - 'Garris', - 'Jorgenson', - 'Moorman', - 'Vuong', - 'Ard', - 'Irons', - 'Fiedler', - 'Jackman', - 'Kuehn', - 'Jenks', - 'Bristow', - 'Mosby', - 'Aldana', - 'Maclean', - 'Freund', - 'Creighton', - 'Smothers', - 'Melson', - 'Lundgren', - 'Donato', - 'Usher', - 'Thornhill', - 'Lowman', - 'Mariano', - 'Button', - 'Mcbee', - 'Cupp', - 'Wickham', - 'Destefano', - 'Nutt', - 'Rambo', - 'Voigt', - 'Talbott', - 'Saxon', - 'Cedillo', - 'Mattison', - 'Speed', - 'Reiss', - 'Nan', - 'Westphal', - 'Whittle', - 'Bernhardt', - 'Boatwright', - 'Bussey', - 'Rojo', - 'Eden', - 'Crites', - 'Place', - 'He', - 'Chaves', - 'Larose', - 'Thames', - 'Hoch', - 'Knotts', - 'Simone', - 'Binkley', - 'Koester', - 'Pettis', - 'Moye', - 'Napolitano', - 'Heffner', - 'Sasser', - 'Jessup', - 'Aguiar', - 'Ogrady', - 'Pippin', - 'Worth', - 'Shively', - 'Whitmire', - 'Rutter', - 'Cedeno', - 'Welborn', - 'Mcdougal', - 'Angell', - 'Sacco', - 'Hailey', - 'Neel', - 'Paniagua', - 'Pointer', - 'Rohde', - 'Holloman', - 'Strother', - 'Guffey', - 'Fenner', - 'Huntington', - 'Shane', - 'Yuen', - 'Gosnell', - 'Martini', - 'Loving', - 'Molloy', - 'Olmos', - 'Christ', - 'Oaks', - 'Ostrowski', - 'Badillo', - 'To', - 'Laplante', - 'Martindale', - 'Richie', - 'Pleasant', - 'Palomino', - 'Rodarte', - 'Stamps', - 'Peeples', - 'Ries', - 'Brownell', - 'Walz', - 'Arana', - 'Tenney', - 'Roddy', - 'Lindner', - 'Bolt', - 'Rigsby', - 'Matteson', - 'Fielder', - 'Randazzo', - 'Deanda', - 'Drayton', - 'Ridge', - 'Tarr', - 'Shade', - 'Upshaw', - 'Woodcock', - 'Miley', - 'Hargrave', - 'Langer', - 'Yun', - 'Wilkie', - 'Choe', - 'Ching', - 'Dugas', - 'Saul', - 'Corder', - 'Bobbitt', - 'Spurgeon', - 'Gladden', - 'Woodbury', - 'Tibbs', - 'Mcgarry', - 'Mcdaniels', - 'Weigel', - 'Bickel', - 'Michels', - 'Hughey', - 'Apple', - 'Bosley', - 'Nesmith', - 'Farber', - 'Ackley', - 'Goodin', - 'Almond', - 'Garrity', - 'Bettencourt', - 'Koss', - 'Falcone', - 'Lavigne', - 'Rainwater', - 'Nation', - 'Blodgett', - 'Dabney', - 'Mabe', - 'Trowbridge', - 'Lundquist', - 'Rosenberger', - 'Dombrowski', - 'Ferro', - 'Evangelista', - 'Bowlin', - 'Mckelvey', - 'Roderick', - 'Michalski', - 'Berkowitz', - 'Sato', - 'Mayorga', - 'Corwin', - 'Mckenney', - 'Salyer', - 'Walling', - 'Abell', - 'Palacio', - 'Lash', - 'Collado', - 'Gass', - 'Luis', - 'Cooksey', - 'Moll', - 'Miramontes', - 'Luster', - 'Shrader', - 'Toliver', - 'Hard', - 'Tu', - 'Sena', - 'Mckoy', - 'Wainwright', - 'Barela', - 'Keiser', - 'Hoag', - 'Backus', - 'Huskey', - 'Brannan', - 'Brumley', - 'Palm', - 'Boynton', - 'Krauss', - 'Steel', - 'Jurado', - 'Mulder', - 'Paterson', - 'Woolsey', - 'Smithson', - 'Joslin', - 'Richman', - 'Partida', - 'Grisham', - 'Wooden', - 'Gooding', - 'Fang', - 'Mcdade', - 'Spriggs', - 'Fishman', - 'Gabel', - 'Rutkowski', - 'Pride', - 'Beals', - 'Gaskin', - 'Friday', - 'Underhill', - 'Rodas', - 'Melo', - 'Sipes', - 'Zimmermann', - 'Mosqueda', - 'Haight', - 'Beeson', - 'Judy', - 'Bankston', - 'Pieper', - 'Siebert', - 'Horning', - 'Butt', - 'Bice', - 'Sills', - 'Philips', - 'Eisenberg', - 'Schumann', - 'Conger', - 'Bare', - 'Hume', - 'Nolasco', - 'Trainor', - 'Weatherly', - 'Huebner', - 'Bosch', - 'Gayle', - 'Kuhns', - 'Byron', - 'Glaze', - 'Poulin', - 'Enright', - 'Large', - 'Comeaux', - 'Rountree', - 'Tavarez', - 'Beardsley', - 'Rubino', - 'Fee', - 'Grider', - 'Bechtel', - 'Gaona', - 'Wallin', - 'Mashburn', - 'Dalrymple', - 'Gingerich', - 'Vaccaro', - 'Hass', - 'Manzano', - 'Tyner', - 'Loza', - 'Lowell', - 'Kaufmann', - 'Bischoff', - 'Doolittle', - 'Shivers', - 'Valente', - 'Bozeman', - 'Howes', - 'Felts', - 'Feller', - 'Justus', - 'Schnell', - 'Boettcher', - 'Ivory', - 'Thorson', - 'Corn', - 'Snook', - 'Heilman', - 'Baxley', - 'Hasty', - 'Wasserman', - 'Barringer', - 'Frankel', - 'Peltier', - 'Guarino', - 'Avina', - 'Sturdivant', - 'Lien', - 'Montemayor', - 'Giddens', - 'Valverde', - 'Burchfield', - 'Pang', - 'Holbert', - 'Rooks', - 'Erdman', - 'Mcmaster', - 'Iniguez', - 'Hartwell', - 'Menchaca', - 'Bordelon', - 'Farkas', - 'Chrisman', - 'Metzler', - 'Fredrick', - 'Porterfield', - 'Slayton', - 'Quesada', - 'Hembree', - 'Peel', - 'Woodley', - 'Mather', - 'Waltz', - 'Totten', - 'Forney', - 'Woolley', - 'Trombley', - 'Yarborough', - 'Javier', - 'Durr', - 'Macklin', - 'Macon', - 'Novotny', - 'Amundson', - 'Kidder', - 'Flagg', - 'Oxendine', - 'Arguello', - 'Marler', - 'Penrod', - 'Mallett', - 'Council', - 'Kinard', - 'Bremer', - 'Towne', - 'Harless', - 'Merkel', - 'Giese', - 'Fife', - 'Byars', - 'Grande', - 'Kuo', - 'Levi', - 'Darr', - 'Sanabria', - 'Pounds', - 'Roeder', - 'Keim', - 'Brush', - 'Dreyer', - 'Taveras', - 'Furlong', - 'Dorris', - 'Prior', - 'Musgrove', - 'Weiler', - 'Munro', - 'Leake', - 'Vollmer', - 'Musick', - 'Hetrick', - 'Perdomo', - 'Kester', - 'Lock', - 'Pine', - 'Baskin', - 'Bonham', - 'Heffernan', - 'Mandel', - 'Sarver', - 'Hamer', - 'Duckett', - 'Lozada', - 'Stocker', - 'Fulcher', - 'Damato', - 'Camargo', - 'Shephard', - 'Loftis', - 'Winfrey', - 'Rueda', - 'Ledezma', - 'Gottlieb', - 'Lamont', - 'Mackie', - 'Bowe', - 'Stockwell', - 'Groth', - 'Chavira', - 'Lohr', - 'Loftin', - 'Gilmer', - 'Cushing', - 'Brody', - 'Nowlin', - 'Holiday', - 'Shirk', - 'Archie', - 'Howerton', - 'Matthew', - 'Copley', - 'Marchese', - 'Echeverria', - 'Soper', - 'Cantwell', - 'Nelms', - 'Tuggle', - 'Dumont', - 'Bard', - 'Gower', - 'Mathes', - 'Yeung', - 'Buell', - 'Bastian', - 'Burd', - 'Broadway', - 'Peng', - 'Greenwell', - 'Vanover', - 'Correll', - 'Tindall', - 'Bill', - 'Mulcahy', - 'Dionne', - 'Rathbun', - 'Baeza', - 'Booher', - 'Fried', - 'Mcginley', - 'Lavin', - 'Atherton', - 'Donnell', - 'Bays', - 'Riedel', - 'Grenier', - 'Zachary', - 'Harold', - 'Styles', - 'Wisdom', - 'Raley', - 'Tamez', - 'Arena', - 'Morelli', - 'Hazelwood', - 'Somerville', - 'Lapp', - 'Rood', - 'Salem', - 'Pape', - 'Olivera', - 'Albritton', - 'Carvajal', - 'Zayas', - 'Myer', - 'Pohl', - 'Haynie', - 'Mariscal', - 'Wampler', - 'Rife', - 'Leeper', - 'Newhouse', - 'Rodney', - 'Vandenberg', - 'Spitzer', - 'Kingston', - 'Wessel', - 'Hartzell', - 'Durden', - 'Marques', - 'Born', - 'Scribner', - 'Rocco', - 'Germain', - 'Tinoco', - 'Valdovinos', - 'Musselman', - 'Vicente', - 'Parsley', - 'Crittenden', - 'Tibbetts', - 'Hulse', - 'Mccleary', - 'Barboza', - 'Velarde', - 'Brodie', - 'Beaudoin', - 'Moreira', - 'Maggard', - 'Jara', - 'Ferrante', - 'Overby', - 'Friesen', - 'Viola', - 'Nelsen', - 'Hash', - 'Doane', - 'Deese', - 'Messick', - 'Bay', - 'Anton', - 'Ingersoll', - 'Saucier', - 'Kwiatkowski', - 'Rawson', - 'Brophy', - 'Ladner', - 'Lehr', - 'Weil', - 'Yocum', - 'Brasher', - 'Denison', - 'Hutcherson', - 'Stowers', - 'Geller', - 'Fortenberry', - 'Stebbins', - 'Conyers', - 'Toole', - 'Stoker', - 'Roden', - 'Chitwood', - 'Beeman', - 'Fannin', - 'Strait', - 'Marlowe', - 'Greenwald', - 'Hann', - 'Stumpf', - 'Samaniego', - 'Colton', - 'Bogart', - 'Morel', - 'Montelongo', - 'Boylan', - 'Guido', - 'Wyrick', - 'Horsley', - 'Tenorio', - 'Sallee', - 'Morehouse', - 'Whyte', - 'Neilson', - 'Watanabe', - 'Magallanes', - 'Mudd', - 'Kieffer', - 'Brigham', - 'Dollar', - 'Huss', - 'Albanese', - 'Spiegel', - 'Hixson', - 'Rounds', - 'Orth', - 'Blanchette', - 'Vanderpool', - 'Pfaff', - 'Speck', - 'Shreve', - 'Sevilla', - 'Neri', - 'Rohr', - 'Ruble', - 'Vanpelt', - 'Rickman', - 'Caraway', - 'Berndt', - 'Mchale', - 'Ingalls', - 'Roybal', - 'Money', - 'Mcdougall', - 'Melancon', - 'Wellington', - 'Ingraham', - 'Ritz', - 'Lashley', - 'Marchand', - 'Schatz', - 'Heiser', - 'Eby', - 'Wimmer', - 'Orton', - 'Atchley', - 'Mumford', - 'Bahena', - 'Gammon', - 'Buehler', - 'Fike', - 'Plank', - 'Carrigan', - 'Kempf', - 'Cundiff', - 'So', - 'Sauls', - 'Mohler', - 'Grillo', - 'Prichard', - 'Pastor', - 'Prasad', - 'Babin', - 'Bontrager', - 'Weddle', - 'Alberts', - 'Theis', - 'Lemoine', - 'Hartnett', - 'Kingsbury', - 'Baran', - 'Birmingham', - 'Gault', - 'Thorp', - 'Wyant', - 'Obryan', - 'Santacruz', - 'Camara', - 'Whitehouse', - 'Evenson', - 'Halvorson', - 'Palmieri', - 'Hannan', - 'Dew', - 'Au', - 'Nolte', - 'Click', - 'Wooley', - 'Hung', - 'Eberhardt', - 'Rawlins', - 'Sadowski', - 'Sarabia', - 'Soule', - 'Millar', - 'Engstrom', - 'Cowles', - 'Runyan', - 'Mitchel', - 'Torrence', - 'Silverstein', - 'Hewett', - 'Pilgrim', - 'Yeh', - 'Rosenfeld', - 'Mulholland', - 'Hatley', - 'Fawcett', - 'Delrosario', - 'Chinn', - 'Bayless', - 'Dee', - 'Deane', - 'Arriola', - 'Duda', - 'Koster', - 'Rath', - 'Karl', - 'Weiland', - 'Lemmon', - 'Blaine', - 'Scofield', - 'Marston', - 'Gist', - 'Pinckney', - 'Moritz', - 'Mclellan', - 'Fulkerson', - 'Gaynor', - 'Pitre', - 'Warrick', - 'Cobbs', - 'Meacham', - 'Guerin', - 'Tedesco', - 'Passmore', - 'Northcutt', - 'Ison', - 'Cowell', - 'Ream', - 'Walther', - 'Meraz', - 'Tribble', - 'Bumgarner', - 'Gabbard', - 'Dawes', - 'Moncada', - 'Chilton', - 'Deweese', - 'Rigby', - 'Marte', - 'Baylor', - 'Valentino', - 'Shine', - 'August', - 'Billups', - 'Jarman', - 'Jacks', - 'Coffee', - 'Friedrich', - 'Marley', - 'Hasan', - 'Pennell', - 'Abercrombie', - 'Bazan', - 'Strickler', - 'Bruton', - 'Lamm', - 'Pender', - 'Wingfield', - 'Hoffer', - 'Zahn', - 'Chaplin', - 'Reinke', - 'Larosa', - 'Maupin', - 'Bunnell', - 'Hassell', - 'Guo', - 'Galan', - 'Paschal', - 'Browder', - 'Krantz', - 'Milne', - 'Pelayo', - 'Emanuel', - 'Mccluskey', - 'Edens', - 'Radtke', - 'Alger', - 'Duhon', - 'Probst', - 'Witmer', - 'Hoagland', - 'Saechao', - 'Pitcher', - 'Villalpando', - 'Carswell', - 'Roundtree', - 'Kuhlman', - 'Tait', - 'Shaughnessy', - 'Wei', - 'Cravens', - 'Sipe', - 'Islas', - 'Hollenbeck', - 'Lockard', - 'Perrone', - 'Tapp', - 'Santoyo', - 'Jaffe', - 'Klotz', - 'Gilpin', - 'Ehrlich', - 'Klug', - 'Stowell', - 'Ibanez', - 'Lazar', - 'Osman', - 'Larkins', - 'Donofrio', - 'Ericson', - 'Schenck', - 'Mouton', - 'Medlock', - 'Hubbell', - 'Bixler', - 'Nowicki', - 'Muro', - 'Homer', - 'Grijalva', - 'Ashmore', - 'Harbison', - 'Duffey', - 'Osgood', - 'Hardee', - 'Jain', - 'Wilber', - 'Bolling', - 'Lett', - 'Phillip', - 'Dipietro', - 'Lefebvre', - 'Batiste', - 'Mcswain', - 'Distefano', - 'Hack', - 'Strobel', - 'Kipp', - 'Doerr', - 'Radcliffe', - 'Cartagena', - 'Paradis', - 'Stilwell', - 'Mccrea', - 'Searles', - 'Frausto', - 'Hendershot', - 'Gosselin', - 'Islam', - 'Freese', - 'Stockman', - 'Burwell', - 'Vandiver', - 'Engler', - 'Geisler', - 'Barham', - 'Wiegand', - 'Goncalves', - 'Theriot', - 'Doucet', - 'Bridge', - 'Catron', - 'Blanks', - 'Rahn', - 'Schaub', - 'Hershey', - 'Strader', - 'Buckman', - 'Hartwig', - 'Campo', - 'Tsang', - 'Luck', - 'Bernardo', - 'Marker', - 'Pinkney', - 'Benefield', - 'Mcginty', - 'Bode', - 'Linden', - 'Manriquez', - 'Jaquez', - 'Bedard', - 'Flack', - 'Hesse', - 'Costanzo', - 'Boardman', - 'Carper', - 'Word', - 'Miracle', - 'Edmunds', - 'Bott', - 'Flemming', - 'Manns', - 'Kesler', - 'Piatt', - 'Tankersley', - 'Eberle', - 'Roney', - 'Belk', - 'Vansickle', - 'Varga', - 'Hillard', - 'Neubauer', - 'Quirk', - 'Chevalier', - 'Mintz', - 'Kocher', - 'Casarez', - 'Tinker', - 'Elmer', - 'Decarlo', - 'Cordes', - 'Berube', - 'Kimbrell', - 'Schick', - 'Papa', - 'Alderson', - 'Callaghan', - 'Renaud', - 'Pardue', - 'Krohn', - 'Bloomfield', - 'Coward', - 'Ligon', - 'Trask', - 'Wingo', - 'Book', - 'Crutcher', - 'Canter', - 'Teran', - 'Denman', - 'Stackhouse', - 'Chambliss', - 'Gourley', - 'Earls', - 'Frizzell', - 'Bergen', - 'Abdullah', - 'Sprinkle', - 'Fancher', - 'Urias', - 'Lavelle', - 'Baumgardner', - 'Kahler', - 'Baldridge', - 'Alejandro', - 'Plascencia', - 'Hix', - 'Rule', - 'Mix', - 'Petro', - 'Hadden', - 'Fore', - 'Humes', - 'Barnum', - 'Laing', - 'Maggio', - 'Sylvia', - 'Malinowski', - 'Fell', - 'Durst', - 'Plant', - 'Vaca', - 'Abarca', - 'Shirey', - 'Parton', - 'Ta', - 'Ramires', - 'Ochs', - 'Gaitan', - 'Ledoux', - 'Darrow', - 'Messenger', - 'Chalmers', - 'Schaller', - 'Derby', - 'Coakley', - 'Saleh', - 'Kirkman', - 'Orta', - 'Crabb', - 'Spinks', - 'Dinkins', - 'Harrigan', - 'Koller', - 'Dorr', - 'Carty', - 'Sturgis', - 'Shriver', - 'Macedo', - 'Feng', - 'Bentz', - 'Bedell', - 'Osuna', - 'Dibble', - 'Dejong', - 'Fender', - 'Parada', - 'Vanburen', - 'Chaffee', - 'Stott', - 'Sigmon', - 'Nicolas', - 'Salyers', - 'Magdaleno', - 'Deering', - 'Puentes', - 'Funderburk', - 'Jang', - 'Christopherson', - 'Sellars', - 'Marcotte', - 'Oster', - 'Liao', - 'Tudor', - 'Specht', - 'Chowdhury', - 'Landa', - 'Monge', - 'Brake', - 'Behnke', - 'Llewellyn', - 'Labelle', - 'Mangan', - 'Godsey', - 'Truax', - 'Lombard', - 'Thurmond', - 'Emerick', - 'Blume', - 'Mcginn', - 'Beer', - 'Marrs', - 'Zinn', - 'Rieger', - 'Dilley', - 'Thibault', - 'Witkowski', - 'Chi', - 'Fielding', - 'Tyrrell', - 'Peeler', - 'Northrup', - 'Augustin', - 'Toy', - 'Geist', - 'Schuman', - 'Fairley', - 'Duque', - 'Villatoro', - 'Dudek', - 'Sonnier', - 'Fritts', - 'Worsham', - 'Herold', - 'Mcgehee', - 'Caskey', - 'Boatright', - 'Lazaro', - 'Deck', - 'Palomo', - 'Cory', - 'Olivier', - 'Baines', - 'Fan', - 'Futrell', - 'Halpin', - 'Garrido', - 'Koonce', - 'Fogg', - 'Meneses', - 'Mulkey', - 'Restrepo', - 'Ducharme', - 'Slate', - 'Toussaint', - 'Sorrells', - 'Fitts', - 'Dickman', - 'Alfred', - 'Grimsley', - 'Settles', - 'Etienne', - 'Eggert', - 'Hague', - 'Caldera', - 'Hillis', - 'Hollander', - 'Haire', - 'Theriault', - 'Madigan', - 'Kiernan', - 'Parkhurst', - 'Lippert', - 'Jaynes', - 'Moniz', - 'Bost', - 'Bettis', - 'Sandy', - 'Kuhl', - 'Wilk', - 'Borrego', - 'Koon', - 'Penney', - 'Pizarro', - 'Stitt', - 'Koski', - 'Galicia', - 'Quiles', - 'Real', - 'Massa', - 'Crone', - 'Teeter', - 'Voorhees', - 'Hilbert', - 'Nabors', - 'Shupe', - 'Blood', - 'Mcauliffe', - 'Waits', - 'Blakley', - 'Stoltz', - 'Maes', - 'Munroe', - 'Rhoden', - 'Abeyta', - 'Milliken', - 'Harkness', - 'Almaraz', - 'Remington', - 'Raya', - 'Frierson', - 'Olszewski', - 'Quillen', - 'Westcott', - 'Fu', - 'Tolley', - 'Olive', - 'Mcclary', - 'Corbitt', - 'Lui', - 'Lachance', - 'Meagher', - 'Cowley', - 'Hudak', - 'Cress', - 'Mccrory', - 'Talavera', - 'Mclaren', - 'Laurent', - 'Bias', - 'Whetstone', - 'Hollister', - 'Quevedo', - 'Byerly', - 'Berryhill', - 'Folk', - 'Conners', - 'Kellum', - 'Haro', - 'Mallard', - 'Mccants', - 'Risner', - 'Barros', - 'Downes', - 'Mayers', - 'Loeffler', - 'Mink', - 'Hotchkiss', - 'Bartz', - 'Alt', - 'Hindman', - 'Bayne', - 'Bagby', - 'Colin', - 'Treadwell', - 'Hemingway', - 'Bane', - 'Heintz', - 'Fite', - 'Mccomb', - 'Carmody', - 'Kistler', - 'Olinger', - 'Vestal', - 'Byrum', - 'Seale', - 'Turnage', - 'Raber', - 'Prendergast', - 'Koons', - 'Nickell', - 'Benz', - 'Mcculley', - 'Lightner', - 'Hamill', - 'Castellon', - 'Chesser', - 'Moats', - 'Buie', - 'Svoboda', - 'Wold', - 'Macmillan', - 'Boring', - 'Terrill', - 'Loveland', - 'Gaskill', - 'Verdugo', - 'Yip', - 'Oviedo', - 'Hight', - 'Carmack', - 'Scheer', - 'Dreher', - 'Appleby', - 'Lally', - 'Kibler', - 'Marra', - 'Mcnamee', - 'Cooks', - 'Kavanaugh', - 'Carrico', - 'Alden', - 'Dillman', - 'Zamarripa', - 'Serra', - 'Gilligan', - 'Nester', - 'Sokol', - 'Latta', - 'Hanrahan', - 'Ballou', - 'Hollinger', - 'Lux', - 'Caton', - 'Hamann', - 'Sackett', - 'Leiva', - 'Emory', - 'Barden', - 'Houk', - 'Lees', - 'Deltoro', - 'Lowrey', - 'Mcevoy', - 'Hibbs', - 'Crossley', - 'Rego', - 'Melchor', - 'Tull', - 'Bramlett', - 'Hsieh', - 'Warwick', - 'Sayles', - 'Mapes', - 'Pabon', - 'Dearing', - 'Stamm', - 'Joshi', - 'Quan', - 'Larry', - 'Nordstrom', - 'Heisler', - 'Bigham', - 'Walston', - 'Solberg', - 'Bodnar', - 'Posada', - 'Mancilla', - 'Ovalle', - 'Harr', - 'Mccaskill', - 'Bromley', - 'Koerner', - 'Macpherson', - 'Trudeau', - 'Blais', - 'Kiley', - 'Lawlor', - 'Suter', - 'Rothman', - 'Oberg', - 'Seely', - 'Maxfield', - 'Truman', - 'Salvatore', - 'Fouts', - 'Goulet', - 'Munger', - 'Sikora', - 'Comeau', - 'Oliphant', - 'Baber', - 'Hensel', - 'Edelman', - 'Farina', - 'Albano', - 'Aycock', - 'Sung', - 'Deckard', - 'Steinke', - 'Silveira', - 'Servin', - 'Rex', - 'Franzen', - 'Hecker', - 'Gragg', - 'Mcgriff', - 'Ellingson', - 'Kerrigan', - 'An', - 'Bartel', - 'Priddy', - 'Hodson', - 'Tse', - 'Arbogast', - 'Arceneaux', - 'Leatherman', - 'Federico', - 'Pridgen', - 'Yim', - 'Kowalczyk', - 'Deberry', - 'Lejeune', - 'Elston', - 'Mielke', - 'Shelly', - 'Stambaugh', - 'Eagan', - 'Rivard', - 'Silvia', - 'Lawhorn', - 'Denis', - 'Hendry', - 'Wieland', - 'Levinson', - 'Marlin', - 'Gerdes', - 'Pfister', - 'Carder', - 'Pipkin', - 'Angle', - 'Hang', - 'Hagerty', - 'Rhinehart', - 'Gao', - 'Petit', - 'Mccraw', - 'Markle', - 'Lupo', - 'Busse', - 'Marble', - 'Bivins', - 'Storms', - 'Yuan', - 'Waldman', - 'Suh', - 'Wyckoff', - 'Stillman', - 'Piotrowski', - 'Abrego', - 'Gregoire', - 'Bogle', - 'Wortham', - 'Phung', - 'Brister', - 'Karnes', - 'Deming', - 'Ley', - 'Carrasquillo', - 'Curtiss', - 'Appleton', - 'Salley', - 'Borja', - 'Begum', - 'Phifer', - 'Shoup', - 'Cawley', - 'Deason', - 'Castanon', - 'Loucks', - 'Hagler', - 'Mcclinton', - 'Dulaney', - 'Hargett', - 'Mcardle', - 'Burcham', - 'Philpot', - 'Laroche', - 'Breland', - 'Hatten', - 'Karp', - 'Brummett', - 'Boatman', - 'Natale', - 'Pepe', - 'Mortimer', - 'Sink', - 'Voyles', - 'Reeve', - 'Honaker', - 'Loredo', - 'Ridgway', - 'Donner', - 'Lessard', - 'Dever', - 'Salomon', - 'Hickson', - 'Nicholls', - 'Bushey', - 'Osteen', - 'Reavis', - 'Rodman', - 'Barahona', - 'Knecht', - 'Hinman', - 'Faria', - 'Dana', - 'Bancroft', - 'Hatchett', - 'Hageman', - 'Klaus', - 'Castor', - 'Lampkin', - 'Dalessandro', - 'Riffle', - 'Korn', - 'Savoie', - 'Sandifer', - 'Mciver', - 'Magill', - 'Delafuente', - 'Widener', - 'Vermillion', - 'Dandrea', - 'Mader', - 'Woodman', - 'Milan', - 'Hollowell', - 'Schaaf', - 'Kao', - 'Nail', - 'Beaman', - 'Hawkes', - 'Mclane', - 'Marchant', - 'Scanlan', - 'Syed', - 'Peabody', - 'Uhl', - 'Schauer', - 'Azevedo', - 'Wolcott', - 'Mick', - 'Melgar', - 'Pilcher', - 'Burgin', - 'Weiser', - 'Daughtry', - 'Theisen', - 'Babbitt', - 'Petry', - 'Cotten', - 'Fick', - 'Eubank', - 'Tolson', - 'Judkins', - 'Cronk', - 'Wendel', - 'Monteiro', - 'Kissinger', - 'Banta', - 'Senn', - 'Fix', - 'Brehm', - 'Rittenhouse', - 'Banner', - 'Elwell', - 'Herd', - 'Araiza', - 'Hui', - 'Nowell', - 'Brett', - 'Hua', - 'Breeding', - 'Pawlowski', - 'Thompkins', - 'Bocanegra', - 'Bosworth', - 'Dutcher', - 'Cotto', - 'Beecher', - 'Callender', - 'Hamlett', - 'Benfield', - 'Claudio', - 'Reel', - 'Brookshire', - 'Helmick', - 'Ryals', - 'Winder', - 'Thom', - 'Robin', - 'Overman', - 'Furtado', - 'Dacosta', - 'Paddock', - 'Dancy', - 'Carpio', - 'Manzanares', - 'Zito', - 'Favela', - 'Beckley', - 'Adrian', - 'Flory', - 'Nestor', - 'Spell', - 'Speight', - 'Strawn', - 'Beckner', - 'Gause', - 'Berglund', - 'Ruppert', - 'Mincey', - 'Spinelli', - 'Suzuki', - 'Mizell', - 'Kirksey', - 'Bolduc', - 'Kilmer', - 'Wesson', - 'Brinker', - 'Urrutia', - 'Markey', - 'Brenneman', - 'Haupt', - 'Sievers', - 'Puga', - 'Halloran', - 'Birdsong', - 'Stancil', - 'Wiener', - 'Calvo', - 'Macy', - 'Cairns', - 'Kahl', - 'Vice', - 'Ordaz', - 'Grow', - 'Lafrance', - 'Dryden', - 'Studer', - 'Matney', - 'Edward', - 'Rackley', - 'Gurrola', - 'Demoss', - 'Woolard', - 'Oquinn', - 'Hambrick', - 'Christmas', - 'Robey', - 'Crayton', - 'Haber', - 'Arango', - 'Newcomer', - 'Groom', - 'Corson', - 'Harness', - 'Rossman', - 'Slaton', - 'Schutz', - 'Conant', - 'Tedder', - 'Sabin', - 'Lowder', - 'Womble', - 'Jin', - 'Monday', - 'Garmon', - 'Aronson', - 'Skeen', - 'Headrick', - 'Lefevre', - 'Whittemore', - 'Pelton', - 'Barner', - 'Hildebrandt', - 'Rick', - 'Helmer', - 'Grose', - 'Zak', - 'Schroder', - 'Mahler', - 'Keeley', - 'Flinn', - 'Jordon', - 'Ozuna', - 'Sand', - 'Henkel', - 'Turcotte', - 'Vining', - 'Bellinger', - 'Neese', - 'Hagerman', - 'Mcmillin', - 'Gaylord', - 'Harney', - 'Milano', - 'Carothers', - 'Depew', - 'Bucci', - 'Pirtle', - 'Hafner', - 'Dimas', - 'Howlett', - 'Reber', - 'Abram', - 'Davalos', - 'Zajac', - 'Pedro', - 'Goodall', - 'Kaylor', - 'Wrenn', - 'Gartner', - 'Kell', - 'Curl', - 'Leathers', - 'Spiller', - 'Beason', - 'Shattuck', - 'Brewington', - 'Pinon', - 'Nazario', - 'Wash', - 'Ruggles', - 'Matz', - 'Capers', - 'Dorsett', - 'Wilmoth', - 'Bracey', - 'Lenhart', - 'Devoe', - 'Choy', - 'Oswalt', - 'Capone', - 'Wayman', - 'Parikh', - 'Eastwood', - 'Cofield', - 'Rickert', - 'Mccandless', - 'Greenway', - 'Majewski', - 'Rigdon', - 'Armbruster', - 'Royce', - 'Sterner', - 'Swaim', - 'Flournoy', - 'Amezcua', - 'Delano', - 'Westerman', - 'Grau', - 'Claxton', - 'Veliz', - 'Haun', - 'Roscoe', - 'Mccafferty', - 'Ringer', - 'Volz', - 'Blessing', - 'Mcphail', - 'Thelen', - 'Gagliardi', - 'Scholz', - 'Genovese', - 'Boyette', - 'Squire', - 'Naughton', - 'Levitt', - 'Erskine', - 'Leffler', - 'Manchester', - 'Hallett', - 'Whitmer', - 'Gillett', - 'Groce', - 'Roos', - 'Bejarano', - 'Moskowitz', - 'Constantine', - 'Fidler', - 'Roll', - 'Schutte', - 'Ohare', - 'Warnock', - 'Wester', - 'Macgregor', - 'Golding', - 'Abner', - 'Burgett', - 'Bushnell', - 'Brazil', - 'Ascencio', - 'Hock', - 'Legrand', - 'Eversole', - 'Rome', - 'Radcliff', - 'Fuhrman', - 'Schmit', - 'Tew', - 'Caro', - 'Cowen', - 'Marriott', - 'Kephart', - 'Hartung', - 'Keil', - 'Benally', - 'Hazlett', - 'Avant', - 'Desrosiers', - 'Kwong', - 'Guyer', - 'Penner', - 'Avelar', - 'Cashman', - 'Stith', - 'Orona', - 'Rager', - 'Johanson', - 'Lanza', - 'Min', - 'Cool', - 'Heine', - 'Nissen', - 'Buenrostro', - 'Mcmullin', - 'Oropeza', - 'Hom', - 'Degroot', - 'Wescott', - 'Hulbert', - 'Shrum', - 'Muncy', - 'Littrell', - 'Forest', - 'Dyke', - 'Garces', - 'Cimino', - 'Gebhardt', - 'Hickerson', - 'Satterwhite', - 'Radke', - 'Luckey', - 'Coronel', - 'Pugliese', - 'Frazee', - 'Siddiqui', - 'Flatt', - 'Abbey', - 'Gerald', - 'Bodine', - 'Lora', - 'Youngs', - 'Catlett', - 'Alexis', - 'Luo', - 'Youmans', - 'Sherlock', - 'Kinser', - 'Wales', - 'Dinsmore', - 'Abramson', - 'Stricker', - 'Rumsey', - 'Showers', - 'Mickens', - 'Tallent', - 'Setzer', - 'Etter', - 'Allgood', - 'Pagel', - 'Jefferies', - 'Bissell', - 'Colombo', - 'Musgrave', - 'Kuehl', - 'Raab', - 'Kavanagh', - 'Beane', - 'Witcher', - 'Pattison', - 'Paulus', - 'Gong', - 'Mcgough', - 'Burkhalter', - 'Vanbuskirk', - 'Kite', - 'Sass', - 'Lalonde', - 'Gormley', - 'Baier', - 'Brauer', - 'Stricklin', - 'Napoli', - 'Brotherton', - 'Stansbury', - 'Loggins', - 'Sorrentino', - 'Poff', - 'Nieman', - 'Roebuck', - 'Reiner', - 'Hovey', - 'Walley', - 'Leech', - 'Gambino', - 'Hammack', - 'Burson', - 'Tatro', - 'Perrine', - 'Carley', - 'Stadler', - 'Nason', - 'Peckham', - 'Gervais', - 'Ables', - 'Turman', - 'Dore', - 'Peavy', - 'Addington', - 'Tobar', - 'Gilstrap', - 'Brumbaugh', - 'Gerhardt', - 'Slusher', - 'Nevins', - 'Garofalo', - 'Amick', - 'Barrick', - 'Race', - 'Daggett', - 'Manion', - 'Noah', - 'Kranz', - 'Runge', - 'Wysocki', - 'Gillum', - 'Verduzco', - 'Alvey', - 'Pettus', - 'Sim', - 'Cage', - 'Mckean', - 'Harrod', - 'Weatherspoon', - 'Takahashi', - 'Wingard', - 'Endres', - 'Skiles', - 'Wald', - 'Finger', - 'Reams', - 'Ussery', - 'Fricke', - 'Jaworski', - 'Cusick', - 'Stanek', - 'Shaner', - 'Massaro', - 'Ribeiro', - 'Eades', - 'Rue', - 'Scharf', - 'Standridge', - 'Wojciechowski', - 'Victoria', - 'Galbreath', - 'Lander', - 'Martinelli', - 'Raper', - 'Karas', - 'Tomas', - 'La', - 'Kizer', - 'Gastelum', - 'Delp', - 'Sansone', - 'Therrien', - 'Brookins', - 'Shi', - 'Hammel', - 'Polley', - 'Riddell', - 'Claiborne', - 'Lampe', - 'Benham', - 'Braddock', - 'Elwood', - 'Mcminn', - 'Amerson', - 'Leija', - 'Gambrell', - 'Nuno', - 'Mallon', - 'Gard', - 'Burford', - 'Halley', - 'Maley', - 'Eicher', - 'Caban', - 'Rubenstein', - 'Tighe', - 'Harbaugh', - 'Bergmann', - 'Runnels', - 'Carrizales', - 'Gustin', - 'Wight', - 'Dominick', - 'Cannady', - 'Brace', - 'Beauregard', - 'Weitzel', - 'Orcutt', - 'Abrahamson', - 'Jorge', - 'Mccown', - 'Harriman', - 'Nicol', - 'Gott', - 'Andino', - 'Tsosie', - 'Shumway', - 'Aucoin', - 'Bowes', - 'Hixon', - 'Broom', - 'Cate', - 'Desantiago', - 'Haug', - 'Pinedo', - 'Mowry', - 'Moyers', - 'Deangelo', - 'Mcshane', - 'Boley', - 'Tiffany', - 'Steger', - 'Woodford', - 'Whitford', - 'Collette', - 'Muth', - 'Mansour', - 'Schuh', - 'Fortney', - 'Khoury', - 'Livengood', - 'Haworth', - 'Rusk', - 'Mathieu', - 'Peppers', - 'Gehring', - 'Faris', - 'Diep', - 'Rae', - 'Hupp', - 'Escalera', - 'Gwin', - 'Engelhardt', - 'Bannon', - 'Menjivar', - 'Eberhart', - 'Kershaw', - 'Cottle', - 'Palomares', - 'Carrell', - 'Galaviz', - 'Willie', - 'Troxell', - 'Visser', - 'Xie', - 'Juan', - 'Spector', - 'Izzo', - 'Woodring', - 'Gilbreath', - 'Bey', - 'Giraldo', - 'Neary', - 'Ready', - 'Toland', - 'Benge', - 'Thrower', - 'Bemis', - 'Hostetter', - 'Dull', - 'Poulos', - 'Vanegas', - 'Abad', - 'Harker', - 'Mei', - 'Nigro', - 'Messner', - 'Peres', - 'Hardaway', - 'Crumpton', - 'Dingman', - 'Hipp', - 'Lemley', - 'Maloy', - 'Ye', - 'Neighbors', - 'Proulx', - 'Jamerson', - 'Finkelstein', - 'Payan', - 'Holler', - 'Simonds', - 'Toms', - 'Schulman', - 'Aguero', - 'Hinrichs', - 'Steffens', - 'Clapper', - 'Delao', - 'Knighton', - 'Jahn', - 'Mach', - 'Heal', - 'Detwiler', - 'Corso', - 'Toner', - 'Rook', - 'Brockway', - 'Coulson', - 'Delia', - 'Giddings', - 'Hermosillo', - 'Ballenger', - 'Persinger', - 'Delk', - 'Pedigo', - 'Burg', - 'Voelker', - 'Ecker', - 'Kile', - 'Propst', - 'Rascon', - 'Stultz', - 'Swindle', - 'Swindell', - 'Deaver', - 'Welty', - 'Sussman', - 'Southworth', - 'Child', - 'Coston', - 'Lei', - 'Spillman', - 'Hochstetler', - 'Veach', - 'Melcher', - 'Chipman', - 'Lebeau', - 'Summerville', - 'Peden', - 'Lizarraga', - 'Kingery', - 'Leos', - 'Fogel', - 'Eckman', - 'Burbank', - 'Castano', - 'Chartier', - 'Medellin', - 'Torrey', - 'Peake', - 'Swinney', - 'Aziz', - 'Reinert', - 'Borg', - 'Pires', - 'Brooke', - 'Forester', - 'Greaves', - 'Delapaz', - 'Hunnicutt', - 'Bierman', - 'Stringfellow', - 'Lavallee', - 'Farnham', - 'Gadson', - 'Gainer', - 'Kulp', - 'Liston', - 'Brooker', - 'Loudermilk', - 'Reza', - 'Henshaw', - 'Hinz', - 'Brammer', - 'Frisch', - 'Toombs', - 'Esquibel', - 'Feinberg', - 'Plaza', - 'Bly', - 'Encarnacion', - 'Cockerham', - 'Shealy', - 'Haile', - 'Nave', - 'Chenoweth', - 'Goto', - 'Ernest', - 'Staub', - 'Marty', - 'Huizar', - 'Lammers', - 'Mcavoy', - 'Dishman', - 'Giroux', - 'Dowdell', - 'Via', - 'Fenn', - 'Kain', - 'Breckenridge', - 'Egbert', - 'Steelman', - 'Gasper', - 'Riojas', - 'Parmer', - 'Creed', - 'Gillispie', - 'Edgerton', - 'Yen', - 'Calder', - 'Holmberg', - 'Kreider', - 'Landau', - 'Eley', - 'Lewallen', - 'Quimby', - 'Holladay', - 'Du', - 'Leland', - 'Hyder', - 'Omeara', - 'Acton', - 'Gaspard', - 'Kennard', - 'Renfroe', - 'Hayman', - 'Gladney', - 'Glidden', - 'Wilmot', - 'Pearsall', - 'Cahoon', - 'Hallock', - 'Grigg', - 'Boggess', - 'Lewin', - 'Doering', - 'Thach', - 'Mcatee', - 'Paulk', - 'Rusch', - 'Harrold', - 'Suttles', - 'Chiles', - 'Sawyers', - 'Roger', - 'Kwok', - 'Luevano', - 'Coelho', - 'Waldo', - 'Ewell', - 'Lagunas', - 'Rude', - 'Barrington', - 'Mccomas', - 'Whiteley', - 'Jeanbaptiste', - 'Darcy', - 'Lussier', - 'Kerley', - 'Fordham', - 'Moorehead', - 'Welton', - 'Nicely', - 'Constantino', - 'Townes', - 'Giglio', - 'Damian', - 'Mckibben', - 'Resnick', - 'Endicott', - 'Lindeman', - 'Killion', - 'Gwinn', - 'Beaumont', - 'Nord', - 'Miceli', - 'Fast', - 'Bidwell', - 'Sites', - 'Drum', - 'Maze', - 'Abshire', - 'Berner', - 'Rhyne', - 'Juliano', - 'Wortman', - 'Beggs', - 'Winchell', - 'Summerlin', - 'Thrash', - 'Biggers', - 'Buckles', - 'Barnwell', - 'Thomasson', - 'Wan', - 'Arneson', - 'Rodrigue', - 'Wroblewski', - 'Quiroga', - 'Fulk', - 'Dillingham', - 'Rone', - 'Mapp', - 'Sattler', - 'Letourneau', - 'Gaudet', - 'Mccaslin', - 'Gurule', - 'Huck', - 'Hudspeth', - 'Welter', - 'Wittman', - 'Hileman', - 'Ewald', - 'Yao', - 'Kindred', - 'Kato', - 'Nickels', - 'Tyndall', - 'Sanmiguel', - 'Mayle', - 'Alfano', - 'Eichelberger', - 'Bee', - 'Sheehy', - 'Rogan', - 'Philip', - 'Dilworth', - 'Midkiff', - 'Hudgens', - 'Killingsworth', - 'Russel', - 'Criss', - 'Liddell', - 'Eberly', - 'Khalil', - 'Lattimore', - 'Koval', - 'Maxson', - 'Schram', - 'Goodell', - 'Catlin', - 'Cofer', - 'Alva', - 'Sandler', - 'Kunkle', - 'Perron', - 'Bushman', - 'Edmonson', - 'Roa', - 'Nesbit', - 'Ahearn', - 'Garver', - 'Bible', - 'Barley', - 'Struble', - 'Oxford', - 'Wulf', - 'Marron', - 'Haught', - 'Bonnell', - 'Pigg', - 'Friel', - 'Almaguer', - 'Bowler', - 'Mitchem', - 'Fussell', - 'Lemos', - 'Savino', - 'Boisvert', - 'Torgerson', - 'Annis', - 'Dicks', - 'Ruhl', - 'Pepin', - 'Wildman', - 'Gendron', - 'Melanson', - 'Sherer', - 'Duty', - 'Cassel', - 'Croteau', - 'Rolon', - 'Staats', - 'Pass', - 'Larocca', - 'Sauter', - 'Sacks', - 'Boutwell', - 'Hunsaker', - 'Omara', - 'Mcbroom', - 'Lohman', - 'Treat', - 'Dufour', - 'Brashear', - 'Yepez', - 'Lao', - 'Telles', - 'Manis', - 'Mars', - 'Shilling', - 'Tingle', - 'Macaluso', - 'Rigney', - 'Clair', - 'Matsumoto', - 'Agosto', - 'Halbert', - 'Dabbs', - 'Eckstein', - 'Mercurio', - 'Berkley', - 'Wachter', - 'Langan', - 'Peach', - 'Carreno', - 'Lepore', - 'Howie', - 'Thaxton', - 'Arrowood', - 'Weinberger', - 'Eldred', - 'Hooten', - 'Raymer', - 'Feaster', - 'Bosco', - 'Cataldo', - 'Fears', - 'Eckhardt', - 'Mullinax', - 'Spratt', - 'Laboy', - 'Marsden', - 'Carlile', - 'Bustillos', - 'Crim', - 'Surratt', - 'Kurth', - 'Gaul', - 'Machuca', - 'Rolfe', - 'Lower', - 'Edmiston', - 'Millsap', - 'Dehaven', - 'Racine', - 'Coney', - 'Rinker', - 'Maddux', - 'Burmeister', - 'Fenwick', - 'Stocks', - 'Forde', - 'Pettway', - 'Balderrama', - 'Westover', - 'Bloch', - 'Burress', - 'Hunley', - 'Futch', - 'Chee', - 'Alvarenga', - 'Bostwick', - 'Cleaver', - 'Pelkey', - 'Bryce', - 'Pisano', - 'Qureshi', - 'Varghese', - 'Cunha', - 'Hellman', - 'Grass', - 'Luker', - 'Hazelton', - 'Cathcart', - 'Yamada', - 'Gallego', - 'Menke', - 'Yingling', - 'Merriweather', - 'Fleury', - 'Salmeron', - 'Metcalfe', - 'Brook', - 'Freitag', - 'Malek', - 'Obregon', - 'Blain', - 'Mellott', - 'Alam', - 'Bessette', - 'Moncrief', - 'Arvizu', - 'Botts', - 'Moorer', - 'Landreth', - 'Hulett', - 'Marinelli', - 'Falco', - 'Silvestri', - 'Gottschalk', - 'Thiele', - 'Kight', - 'Warrington', - 'Huckaby', - 'Ledet', - 'Charbonneau', - 'Crozier', - 'Mohan', - 'Stroh', - 'Bolinger', - 'Delvecchio', - 'Macfarlane', - 'Cribbs', - 'Mcloughlin', - 'Maynor', - 'Ming', - 'Digiovanni', - 'Truesdale', - 'Pfeffer', - 'Benn', - 'Chaparro', - 'Englert', - 'Spano', - 'Ogletree', - 'Yancy', - 'Swick', - 'Hallmark', - 'Mattern', - 'Tryon', - 'Plumb', - 'Martineau', - 'Man', - 'Grube', - 'Holst', - 'Nez', - 'Belden', - 'Aikens', - 'Litton', - 'Moorhead', - 'Dufresne', - 'Bonney', - 'Heyward', - 'Halliday', - 'Ito', - 'Crossman', - 'Gast', - 'Levan', - 'Wine', - 'Desouza', - 'Kornegay', - 'Nam', - 'Keough', - 'Stotts', - 'Dickenson', - 'Ousley', - 'Leduc', - 'Revels', - 'Dizon', - 'Arreguin', - 'Shockey', - 'Alegria', - 'Blades', - 'Ignacio', - 'Mellon', - 'Ebersole', - 'Sain', - 'Weissman', - 'Wargo', - 'Claypool', - 'Zorn', - 'Julien', - 'Hinshaw', - 'Alberto', - 'Garduno', - 'Kellar', - 'Rizo', - 'Labonte', - 'Humble', - 'Downer', - 'Lykins', - 'Tower', - 'Vanhouten', - 'Chairez', - 'Campa', - 'Blizzard', - 'Standley', - 'Reiser', - 'Whitener', - 'Menefee', - 'Nalley', - 'Lasher', - 'Strang', - 'Smock', - 'Moralez', - 'Kiel', - 'Moffatt', - 'Behm', - 'Hackworth', - 'Dirks', - 'Kratz', - 'Guillot', - 'Tittle', - 'Stlouis', - 'Seymore', - 'Searle', - 'Utter', - 'Wilborn', - 'Dortch', - 'Duron', - 'Cardinal', - 'Spikes', - 'Arambula', - 'Cutter', - 'Dibenedetto', - 'Botelho', - 'Bedwell', - 'Kilby', - 'Bottoms', - 'Cassady', - 'Rothwell', - 'Bilodeau', - 'Markowitz', - 'Baucom', - 'Valley', - 'Esqueda', - 'Depalma', - 'Laskowski', - 'Hopp', - 'Casale', - 'Perreault', - 'Shuster', - 'Wolter', - 'Raby', - 'Cyrus', - 'Tseng', - 'Georges', - 'Das', - 'Wilfong', - 'Schlueter', - 'Woolf', - 'Stickney', - 'Mcinerney', - 'Curcio', - 'Fowlkes', - 'Boldt', - 'Zander', - 'Shropshire', - 'Antonelli', - 'Froehlich', - 'Butterworth', - 'Stedman', - 'Broadnax', - 'Kroeger', - 'Kellner', - 'Monreal', - 'Armas', - 'Mcguinness', - 'Canterbury', - 'Weisman', - 'Hilburn', - 'Carruthers', - 'Pell', - 'Peele', - 'Devaney', - 'Owings', - 'Mar', - 'Liggett', - 'Breslin', - 'Soucy', - 'Aguila', - 'Weidman', - 'Mingo', - 'Tarango', - 'Winger', - 'Poteet', - 'Acree', - 'Mcnew', - 'Leatherwood', - 'Aubrey', - 'Waring', - 'Soler', - 'Roof', - 'Sunderland', - 'Blackford', - 'Rabe', - 'Hepler', - 'Leonardo', - 'Spina', - 'Smythe', - 'Alex', - 'Barta', - 'Bybee', - 'Campagna', - 'Pete', - 'Batchelder', - 'Gurney', - 'Wyche', - 'Schutt', - 'Rashid', - 'Almazan', - 'Pahl', - 'Perri', - 'Viramontes', - 'Cavender', - 'Snapp', - 'Newson', - 'Sandhu', - 'Fernando', - 'Stockdale', - 'Garfield', - 'Ealy', - 'Mcfarlin', - 'Bieber', - 'Callan', - 'Arruda', - 'Oquendo', - 'Levasseur', - 'Maple', - 'Kowal', - 'Kushner', - 'Naquin', - 'Shouse', - 'Mcquade', - 'Cai', - 'Smedley', - 'Gober', - 'Saiz', - 'Brunelle', - 'Arbuckle', - 'Landes', - 'Mak', - 'Korte', - 'Oxley', - 'Boger', - 'Mickey', - 'Lent', - 'Cureton', - 'Husted', - 'Eidson', - 'Boyett', - 'Kitts', - 'Shope', - 'Hance', - 'Jessen', - 'Litchfield', - 'Torre', - 'Cargill', - 'Herren', - 'Straight', - 'Merz', - 'Weese', - 'Sperling', - 'Lapierre', - 'Yung', - 'Doggett', - 'Cauley', - 'Hardeman', - 'Margolis', - 'Watford', - 'Seltzer', - 'Fullmer', - 'Timberlake', - 'Butz', - 'Duquette', - 'Olin', - 'Leverett', - 'Hartford', - 'Otte', - 'Beaton', - 'Grimaldi', - 'Marotta', - 'Carlsen', - 'Cullum', - 'Monte', - 'Haygood', - 'Middlebrooks', - 'Lazarus', - 'Shiver', - 'Ivie', - 'Niemi', - 'Lacombe', - 'Judson', - 'Ginsberg', - 'Firestone', - 'Izquierdo', - 'Deel', - 'Jacinto', - 'Towers', - 'Fritsch', - 'Albin', - 'Kaminsky', - 'Yin', - 'Wrobel', - 'Birdwell', - 'Krieg', - 'Danforth', - 'Florio', - 'Saito', - 'Clift', - 'Duck', - 'Matt', - 'Moxley', - 'Barbieri', - 'Klatt', - 'Saltzman', - 'Chesney', - 'Bojorquez', - 'Cosentino', - 'Lodge', - 'Converse', - 'Decastro', - 'Gerhart', - 'Music', - 'Danley', - 'Santangelo', - 'Bevins', - 'Coen', - 'Seibel', - 'Lindemann', - 'Dressler', - 'Newport', - 'Bedolla', - 'Lillie', - 'Rhone', - 'Penaloza', - 'Swart', - 'Niemeyer', - 'Pilkington', - 'Matta', - 'Hollifield', - 'Gillman', - 'Montana', - 'Maroney', - 'Stenger', - 'Loos', - 'Wert', - 'Brogdon', - 'Gandhi', - 'Bent', - 'Tabb', - 'Sikorski', - 'Hagedorn', - 'Hannigan', - 'Hoss', - 'Conlin', - 'Trott', - 'Fall', - 'Granado', - 'Bartell', - 'Rubalcava', - 'Neves', - 'Poynter', - 'Alton', - 'Paschall', - 'Waltman', - 'Parke', - 'Kittle', - 'Czarnecki', - 'Bloodworth', - 'Knorr', - 'Timms', - 'Derry', - 'Messier', - 'Saad', - 'Cozart', - 'Sutphin', - 'Puryear', - 'Gatto', - 'Whitacre', - 'Verdin', - 'Bloomer', - 'Brundage', - 'Brian', - 'Seger', - 'Clare', - 'Balch', - 'Tharpe', - 'Rayford', - 'Halter', - 'Barefoot', - 'Gonsalez', - 'Lomas', - 'Monzon', - 'Howarth', - 'Mccready', - 'Gudino', - 'Serafin', - 'Sanfilippo', - 'Minnich', - 'Eldredge', - 'Malave', - 'Greeley', - 'Sisneros', - 'Kangas', - 'Peery', - 'Lunn', - 'Lukas', - 'Bunce', - 'Riccio', - 'Thies', - 'Stivers', - 'Conard', - 'Mullaney', - 'Catalan', - 'Omar', - 'Theobald', - 'Jeffcoat', - 'Kucera', - 'Borkowski', - 'Coomer', - 'Mathison', - 'Croom', - 'Rushton', - 'Stites', - 'Pendley', - 'Till', - 'Oconner', - 'Forsberg', - 'Wages', - 'Fillmore', - 'Barcenas', - 'Gillard', - 'Leak', - 'Towle', - 'Esser', - 'Dunlop', - 'Quackenbush', - 'Archambault', - 'Buller', - 'Newlin', - 'Urquhart', - 'Shanley', - 'Mote', - 'Ippolito', - 'Rozier', - 'Reidy', - 'Gregor', - 'Swaney', - 'Bradfield', - 'Fudge', - 'More', - 'Tester', - 'Higley', - 'Dambrosio', - 'Bullington', - 'Highsmith', - 'Silas', - 'Felker', - 'Sawicki', - 'Beltz', - 'Albarran', - 'Aitken', - 'Findlay', - 'Looper', - 'Tooley', - 'Lasley', - 'Moynihan', - 'Ratcliffe', - 'Grizzle', - 'Souders', - 'Nussbaum', - 'Suber', - 'Macdougall', - 'Waddle', - 'Brawner', - 'Tucci', - 'Cosme', - 'Walk', - 'Gordy', - 'Tarrant', - 'Rosenblum', - 'Huth', - 'Bridgeman', - 'Hinkley', - 'Gehrke', - 'Boden', - 'Suazo', - 'Gambill', - 'Widner', - 'Chick', - 'Mccollough', - 'Hassler', - 'Odum', - 'Pawlak', - 'Prevost', - 'Slavin', - 'Fetters', - 'Beamon', - 'Renshaw', - 'Deng', - 'Plourde', - 'Holstein', - 'Rye', - 'Holliman', - 'Melville', - 'Messinger', - 'Turcios', - 'Garnica', - 'Feeley', - 'Mariani', - 'Otten', - 'Dorado', - 'Mortenson', - 'Meissner', - 'Scarlett', - 'Sweitzer', - 'Glisson', - 'Desjardins', - 'Penland', - 'Elledge', - 'Crumley', - 'Deen', - 'Shih', - 'Heuer', - 'Gloria', - 'Lail', - 'Mcandrew', - 'Mcnaughton', - 'Cortese', - 'Stgermain', - 'Hammon', - 'Leininger', - 'Flickinger', - 'Dement', - 'Bumgardner', - 'Tessier', - 'Fulford', - 'Cervantez', - 'Wisner', - 'Shulman', - 'Sabol', - 'Papp', - 'Strasser', - 'Sartin', - 'Rothstein', - 'Grote', - 'Beaudry', - 'Deville', - 'Roop', - 'Villar', - 'Bussell', - 'Bowyer', - 'Yoshida', - 'Hertz', - 'Countryman', - 'Hoey', - 'Roseberry', - 'Schock', - 'Boozer', - 'Mccowan', - 'Kirschner', - 'Lechner', - 'Winkelman', - 'Witham', - 'Thurber', - 'Depriest', - 'Chenault', - 'Moten', - 'Tillotson', - 'Guan', - 'Ketcham', - 'Jiles', - 'Grosso', - 'Nottingham', - 'Kellam', - 'Alejo', - 'Thoma', - 'Marchetti', - 'Holifield', - 'Fortson', - 'Leasure', - 'Mceachern', - 'Oceguera', - 'Carleton', - 'Weekley', - 'Kinsella', - 'Harvell', - 'Waldon', - 'Kean', - 'Chancellor', - 'Blosser', - 'Detweiler', - 'Presnell', - 'Beachy', - 'Lingle', - 'Plumley', - 'Knopp', - 'Gamache', - 'Atwater', - 'Caine', - 'Woodland', - 'Terwilliger', - 'Moller', - 'Cleland', - 'Cottingham', - 'Janke', - 'Willman', - 'Dann', - 'Mangrum', - 'Shuck', - 'Paden', - 'Adelman', - 'Brim', - 'Tullis', - 'Hertel', - 'Gallaher', - 'Leopold', - 'Donegan', - 'Popovich', - 'Gusman', - 'Chatham', - 'Schooley', - 'Pinder', - 'Heise', - 'Maines', - 'Nystrom', - 'Jahnke', - 'Poon', - 'Murphree', - 'Pelaez', - 'Risley', - 'Sohn', - 'Shim', - 'Armentrout', - 'Kastner', - 'Philpott', - 'Mao', - 'Pursley', - 'Mangold', - 'Mccourt', - 'Hollar', - 'Desmarais', - 'Debord', - 'Gullett', - 'Gaeta', - 'Bae', - 'Houlihan', - 'Gorton', - 'Steinman', - 'Santo', - 'Snelling', - 'Corpuz', - 'Look', - 'Scudder', - 'Treece', - 'Binns', - 'Sokolowski', - 'Harner', - 'Gallup', - 'Marti', - 'Teasley', - 'Markel', - 'Casiano', - 'Nicks', - 'Recinos', - 'Paradise', - 'Colman', - 'Orange', - 'Mele', - 'Medford', - 'Templin', - 'Zuber', - 'Mackin', - 'Brodsky', - 'Householder', - 'Wirtz', - 'Hackman', - 'Tippett', - 'Polson', - 'Colston', - 'Cerna', - 'Herald', - 'Shults', - 'Shubert', - 'Mertens', - 'Dave', - 'Duffield', - 'Vanness', - 'Mayne', - 'Driskell', - 'Percy', - 'Lauderdale', - 'Cipriano', - 'Theodore', - 'Colella', - 'Kiger', - 'Brownfield', - 'Stella', - 'Wideman', - 'Maye', - 'Chisolm', - 'Muldoon', - 'Fitzwater', - 'Harville', - 'Dixson', - 'Burkey', - 'Hartsfield', - 'Schade', - 'Brawley', - 'Pelfrey', - 'Tennyson', - 'Whitted', - 'Silvas', - 'Harbour', - 'Krupa', - 'Peraza', - 'Erdmann', - 'Halpern', - 'Finnerty', - 'Mackinnon', - 'Humbert', - 'Mccarley', - 'Doster', - 'Kugler', - 'Livesay', - 'Force', - 'Haberman', - 'Lamp', - 'Hector', - 'Charron', - 'Woosley', - 'Rein', - 'Ashburn', - 'Greenleaf', - 'Niemann', - 'Carillo', - 'Skelly', - 'Nunnally', - 'Renfrow', - 'Prickett', - 'Angus', - 'Bednar', - 'Nightingale', - 'Steinbach', - 'Warnick', - 'Jason', - 'Hans', - 'Lydon', - 'Rutland', - 'Alleman', - 'Hawn', - 'Malin', - 'Beech', - 'Auger', - 'Desilva', - 'Izaguirre', - 'Isham', - 'Mandujano', - 'Glasser', - 'Dimarco', - 'Berumen', - 'Nipper', - 'Pegram', - 'Sundberg', - 'Labbe', - 'Mcphee', - 'Crafton', - 'Agustin', - 'Cantor', - 'Beller', - 'Bang', - 'Lawyer', - 'Croy', - 'Kyles', - 'Winans', - 'Battista', - 'Jost', - 'Bakken', - 'Dandridge', - 'Mustafa', - 'Ice', - 'Eklund', - 'Montesdeoca', - 'Hermes', - 'Grimaldo', - 'Vannoy', - 'Grainger', - 'Lamas', - 'Tarantino', - 'Witter', - 'Worthen', - 'Basinger', - 'Cowden', - 'Hiles', - 'Mcanally', - 'Felipe', - 'Gallimore', - 'Kapp', - 'Makowski', - 'Copenhaver', - 'Ramer', - 'Gideon', - 'Bowker', - 'Wilkens', - 'Seeger', - 'Huntsman', - 'Palladino', - 'Jessee', - 'Kittrell', - 'Rolle', - 'Ciccone', - 'Kolar', - 'Brannen', - 'Bixby', - 'Pohlman', - 'Strachan', - 'Lesher', - 'Fleischer', - 'Umana', - 'Murphey', - 'Mcentire', - 'Rabon', - 'Mcauley', - 'Bunton', - 'Soileau', - 'Sheriff', - 'Borowski', - 'Mullens', - 'Larrabee', - 'Prouty', - 'Malley', - 'Sumrall', - 'Reisinger', - 'Surber', - 'Kasten', - 'Shoemake', - 'Yowell', - 'Bonin', - 'Bevan', - 'Bove', - 'Boe', - 'Hazard', - 'Slay', - 'Carraway', - 'Kaczmarek', - 'Armitage', - 'Lowther', - 'Sheaffer', - 'Farah', - 'Atencio', - 'Ung', - 'Kirkham', - 'Cavanagh', - 'Mccutchen', - 'Shoop', - 'Nickles', - 'Borchardt', - 'Durkee', - 'Maus', - 'Shedd', - 'Petrillo', - 'Brainard', - 'Eddings', - 'Fanelli', - 'Seo', - 'Heaney', - 'Drennan', - 'Mcgarvey', - 'Saddler', - 'Lucia', - 'Higa', - 'Gailey', - 'Groh', - 'Hinckley', - 'Griner', - 'Norfleet', - 'Caplan', - 'Rademacher', - 'Souder', - 'Autrey', - 'Eskridge', - 'Drumm', - 'Fiske', - 'Giffin', - 'Townley', - 'Derose', - 'Burrus', - 'Castrejon', - 'Emmert', - 'Cothran', - 'Hartsell', - 'Kilburn', - 'Riggle', - 'Trussell', - 'Mulvey', - 'Barto', - 'Crank', - 'Lovely', - 'Woodhouse', - 'Powe', - 'Pablo', - 'Zack', - 'Murchison', - 'Dicarlo', - 'Kessel', - 'Hagood', - 'Rost', - 'Edson', - 'Blakeney', - 'Fant', - 'Brodeur', - 'Jump', - 'Spry', - 'Laguna', - 'Lotz', - 'Bergquist', - 'Collard', - 'Mash', - 'Rideout', - 'Bilbrey', - 'Selman', - 'Fortunato', - 'Holzer', - 'Pifer', - 'Mcabee', - 'Talamantes', - 'Tollefson', - 'Pastore', - 'Crew', - 'Wilcher', - 'Kutz', - 'Stallard', - 'Ressler', - 'Fehr', - 'Piercy', - 'Lafond', - 'Digiacomo', - 'Schuck', - 'Winkle', - 'Graybill', - 'Plata', - 'Gribble', - 'Odle', - 'Fraga', - 'Bressler', - 'Moultrie', - 'Tung', - 'Charette', - 'Marvel', - 'Kerby', - 'Mori', - 'Hamman', - 'Favors', - 'Freeze', - 'Delisle', - 'Straw', - 'Dingle', - 'Elizalde', - 'Cabello', - 'Zalewski', - 'Funkhouser', - 'Abate', - 'Nero', - 'Holston', - 'Josey', - 'Schreck', - 'Shroyer', - 'Paquin', - 'Bing', - 'Chauvin', - 'Maria', - 'Melgoza', - 'Arms', - 'Caddell', - 'Pitchford', - 'Sternberg', - 'Rana', - 'Lovelady', - 'Strouse', - 'Macarthur', - 'Lechuga', - 'Wolfson', - 'Mcglynn', - 'Koo', - 'Stoops', - 'Tetreault', - 'Lepage', - 'Duren', - 'Hartz', - 'Kissel', - 'Gish', - 'Largent', - 'Henninger', - 'Janson', - 'Carrick', - 'Kenner', - 'Haack', - 'Diego', - 'Wacker', - 'Wardell', - 'Ballentine', - 'Smeltzer', - 'Bibb', - 'Winton', - 'Bibbs', - 'Reinhard', - 'Nilsen', - 'Edison', - 'Kalinowski', - 'June', - 'Hewlett', - 'Blaisdell', - 'Zeman', - 'Chon', - 'Board', - 'Nealy', - 'Moretti', - 'Wanner', - 'Bonnett', - 'Hardie', - 'Mains', - 'Cordeiro', - 'Karim', - 'Kautz', - 'Craver', - 'Colucci', - 'Congdon', - 'Mounts', - 'Kurz', - 'Eder', - 'Merryman', - 'Soles', - 'Dulin', - 'Lubin', - 'Mcgowen', - 'Hockenberry', - 'Work', - 'Mazzola', - 'Crandell', - 'Mcgrady', - 'Caruthers', - 'Govea', - 'Meng', - 'Fetter', - 'Trusty', - 'Weintraub', - 'Hurlburt', - 'Reiff', - 'Nowakowski', - 'Hoard', - 'Densmore', - 'Blumenthal', - 'Neale', - 'Schiff', - 'Raleigh', - 'Steiger', - 'Marmolejo', - 'Jessie', - 'Palafox', - 'Tutt', - 'Keister', - 'Core', - 'Im', - 'Wendell', - 'Bennet', - 'Canning', - 'Krull', - 'Patti', - 'Zucker', - 'Schlesinger', - 'Wiser', - 'Dunson', - 'Olmedo', - 'Hake', - 'Champlin', - 'Braley', - 'Wheelock', - 'Geier', - 'Janis', - 'Turek', - 'Grindstaff', - 'Schaffner', - 'Deas', - 'Sirois', - 'Polito', - 'Bergin', - 'Schall', - 'Vineyard', - 'Pellegrini', - 'Corrado', - 'Oleson', - 'List', - 'Dameron', - 'Parkin', - 'Flake', - 'Hollingshead', - 'Chancey', - 'Hufford', - 'Morell', - 'Kantor', - 'Chasteen', - 'Laborde', - 'Sessoms', - 'Hermanson', - 'Burnell', - 'Dewberry', - 'Tolman', - 'Glasscock', - 'Durfee', - 'Gilroy', - 'Wilkey', - 'Dungan', - 'Saravia', - 'Weigand', - 'Bigler', - 'Vancleave', - 'Burlingame', - 'Roseman', - 'Stiffler', - 'Gagliano', - 'Kates', - 'Awad', - 'Knepp', - 'Rondeau', - 'Bertsch', - 'Wolverton', - 'Walcott', - 'Poss', - 'Frisby', - 'Wexler', - 'Reinhold', - 'Krol', - 'Stuck', - 'Ricciardi', - 'Ardoin', - 'Michaelson', - 'Lillard', - 'Burciaga', - 'Birchfield', - 'Patch', - 'Silvey', - 'Simmonds', - 'Siu', - 'Press', - 'Deans', - 'Riegel', - 'Ismail', - 'Magallon', - 'Diller', - 'Hine', - 'Michalak', - 'Dones', - 'Deitz', - 'Gulledge', - 'Stroman', - 'Kobayashi', - 'Hafer', - 'Berk', - 'Landin', - 'Gilles', - 'Obryant', - 'Cheeks', - 'Gress', - 'Lutes', - 'Raphael', - 'Pizano', - 'Bachmann', - 'Cifuentes', - 'Earp', - 'Gilreath', - 'Peluso', - 'Hubbs', - 'Alvis', - 'Peer', - 'Dutra', - 'Stetson', - 'Constant', - 'Benford', - 'Sorto', - 'Cater', - 'Rosier', - 'Isenberg', - 'Shanklin', - 'Veloz', - 'Ramage', - 'Dunford', - 'Ku', - 'Hames', - 'Eddins', - 'Ruano', - 'Frink', - 'Flower', - 'Beadle', - 'Rochester', - 'Fontes', - 'Mefford', - 'Barwick', - 'Millen', - 'Stelly', - 'Cann', - 'Rayner', - 'Carruth', - 'Wendling', - 'Shutt', - 'Hazzard', - 'Maravilla', - 'Gregorio', - 'Pavlik', - 'Hudnall', - 'Aston', - 'Mcglothlin', - 'Weise', - 'Devereaux', - 'Belle', - 'Borst', - 'Burdett', - 'Frisbie', - 'Rummel', - 'Rentz', - 'Cobos', - 'Kimura', - 'Neu', - 'Winner', - 'Candelario', - 'Callis', - 'Basso', - 'Mckim', - 'Tai', - 'Eskew', - 'Lair', - 'Pye', - 'Knuth', - 'Scarberry', - 'Alter', - 'Mcgann', - 'Anson', - 'Drews', - 'Zuckerman', - 'Petrone', - 'Ludlow', - 'Bechtold', - 'Nair', - 'Rennie', - 'Rhine', - 'Fleetwood', - 'Sudduth', - 'Leftwich', - 'Hardiman', - 'Northrop', - 'Banker', - 'Killen', - 'Mastin', - 'Mcmurry', - 'Jasinski', - 'Taliaferro', - 'Mathers', - 'Sheikh', - 'Nuss', - 'Jesse', - 'Zabel', - 'Crotty', - 'Kamp', - 'Fleenor', - 'Halcomb', - 'Eady', - 'Vella', - 'Demars', - 'Ensley', - 'Delosreyes', - 'Zendejas', - 'Leeds', - 'Just', - 'Oday', - 'Dills', - 'Zeng', - 'Barriga', - 'Millican', - 'Cascio', - 'Eakin', - 'Argo', - 'Borland', - 'Cover', - 'Diorio', - 'Coria', - 'Lease', - 'Pinkham', - 'Reichard', - 'Guadalupe', - 'Hansel', - 'Bye', - 'Westerfield', - 'Gales', - 'Mickle', - 'Licata', - 'Cram', - 'Bracy', - 'Motta', - 'Imhoff', - 'Siegfried', - 'Merry', - 'Swiger', - 'Ton', - 'Hersey', - 'Marrone', - 'Ginter', - 'Miele', - 'Breton', - 'Scheffler', - 'Pray', - 'Stapp', - 'Bogard', - 'Towner', - 'Mcelhaney', - 'Bridgewater', - 'Waldner', - 'Quijano', - 'Galante', - 'Quesenberry', - 'Rourke', - 'Harshman', - 'Traver', - 'Alvares', - 'Mcgaha', - 'Nyberg', - 'Pharr', - 'Lerch', - 'Sok', - 'Rosson', - 'Wiggs', - 'Mcelveen', - 'Dimaggio', - 'Rettig', - 'Ahumada', - 'Hetzel', - 'Welling', - 'Chadwell', - 'Swink', - 'Mckinzie', - 'Kwak', - 'Chabot', - 'Tomaszewski', - 'Bonanno', - 'Lesko', - 'Teter', - 'Stalnaker', - 'Ober', - 'Hovis', - 'Hosey', - 'Chaudhry', - 'Fey', - 'Vital', - 'Earhart', - 'Heins', - 'Crowther', - 'Hanner', - 'Behr', - 'Billington', - 'Vogler', - 'Hersh', - 'Perlman', - 'Given', - 'Files', - 'Partain', - 'Coddington', - 'Jardine', - 'Grimmett', - 'Springs', - 'Macomber', - 'Horgan', - 'Arrieta', - 'Charley', - 'Josephson', - 'Tupper', - 'Provenzano', - 'Celaya', - 'Mcvicker', - 'Sigala', - 'Wimer', - 'Ayon', - 'Dossantos', - 'Norvell', - 'Lorenzen', - 'Pasquale', - 'Lambright', - 'Goings', - 'Defelice', - 'Wen', - 'Sigman', - 'Gaylor', - 'Rehm', - 'Carino', - 'Werth', - 'Forehand', - 'Hanke', - 'Lasalle', - 'Mitchum', - 'Priester', - 'Lefler', - 'Celis', - 'Lesser', - 'Fitz', - 'Wentzel', - 'Lavery', - 'Klassen', - 'Shiflett', - 'Hedden', - 'Henn', - 'Coursey', - 'Drain', - 'Delorenzo', - 'Haws', - 'Stansberry', - 'Trump', - 'Dantzler', - 'Chaidez', - 'Mcsweeney', - 'Griffen', - 'Trail', - 'Gandara', - 'Brunk', - 'Kennon', - 'Coss', - 'Blackmore', - 'Metts', - 'Gluck', - 'Blackshear', - 'Cogan', - 'Boney', - 'Encinas', - 'Adamski', - 'Roberge', - 'Schuette', - 'Valero', - 'Barroso', - 'Antunez', - 'Mohammad', - 'Housley', - 'Escoto', - 'Ullrich', - 'Helman', - 'Trost', - 'Lafave', - 'Faith', - 'Blaney', - 'Kershner', - 'Hoehn', - 'Roemer', - 'Isley', - 'Lipinski', - 'Claus', - 'Caulfield', - 'Paiz', - 'Leyba', - 'Robinett', - 'Lambeth', - 'Tarpley', - 'Essex', - 'Eilers', - 'Epley', - 'Murdoch', - 'Sandstrom', - 'Laux', - 'Domingue', - 'Grundy', - 'Bellows', - 'Spindler', - 'Boos', - 'Bhatt', - 'Tye', - 'Salamone', - 'Cirillo', - 'Troup', - 'Jemison', - 'Calzada', - 'Dowden', - 'Geraci', - 'Dunphy', - 'Sack', - 'Sloane', - 'Hathcock', - 'Yap', - 'Ronquillo', - 'Willette', - 'Partlow', - 'Dear', - 'Tunstall', - 'Kiss', - 'Huhn', - 'Seabolt', - 'Beene', - 'Sather', - 'Lockridge', - 'Despain', - 'Wines', - 'Mcalpine', - 'Wadley', - 'Dey', - 'Loring', - 'Meadors', - 'Buettner', - 'Lavalley', - 'Bugg', - 'Creek', - 'Millett', - 'Pumphrey', - 'Fregoso', - 'Merkle', - 'Sheffer', - 'Glassman', - 'Groover', - 'Sweatt', - 'Colunga', - 'Boykins', - 'Seng', - 'Stutz', - 'Brann', - 'Blakey', - 'Munos', - 'Geddes', - 'Avendano', - 'Molitor', - 'Diedrich', - 'Langham', - 'Kindle', - 'Lacour', - 'Buckler', - 'Corum', - 'Bakke', - 'Godin', - 'Kerner', - 'Tobey', - 'Kubiak', - 'Hoyer', - 'Hedge', - 'Priebe', - 'Callison', - 'Lahr', - 'Shears', - 'Snavely', - 'Blatt', - 'Mcpeak', - 'Tinney', - 'Sullins', - 'Bernhard', - 'Gibb', - 'Vaillancourt', - 'Paugh', - 'Funes', - 'Romans', - 'Maurice', - 'Lough', - 'Kerwin', - 'Sanger', - 'Vierra', - 'Markus', - 'Comfort', - 'Krall', - 'Spies', - 'Malcom', - 'Vizcarra', - 'Beamer', - 'Kellerman', - 'Mcroberts', - 'Waterhouse', - 'Stromberg', - 'Persons', - 'Whitesell', - 'Harty', - 'Rosenblatt', - 'Broadwater', - 'Clardy', - 'Shackleford', - 'Jacquez', - 'Brittingham', - 'Lindahl', - 'Feliz', - 'Danna', - 'Garwood', - 'Heron', - 'Southwick', - 'Dehoyos', - 'Cottrill', - 'Mellor', - 'Goldfarb', - 'Grieco', - 'Helgeson', - 'Vandusen', - 'Heinen', - 'Batt', - 'Ruch', - 'Garretson', - 'Pankey', - 'Caudillo', - 'Jakubowski', - 'Plowman', - 'Starcher', - 'Wessels', - 'Moose', - 'Rosner', - 'Louden', - 'Walczak', - 'Poulsen', - 'Mcchesney', - 'Karns', - 'Casares', - 'Cusack', - 'Cespedes', - 'Cornelison', - 'Crossland', - 'Hirst', - 'Mier', - 'Roberto', - 'Canchola', - 'Bosse', - 'Shetler', - 'Melendrez', - 'Giannini', - 'Six', - 'Traynor', - 'Knepper', - 'Lonergan', - 'Kessinger', - 'Hollon', - 'Weathersby', - 'Stouffer', - 'Gingrich', - 'Breault', - 'Pompa', - 'Vanhoose', - 'Burdine', - 'Lark', - 'Stiltner', - 'Wunderlich', - 'Yong', - 'Merrifield', - 'Willhite', - 'Geiser', - 'Lambrecht', - 'Keffer', - 'Carlo', - 'Germany', - 'Turgeon', - 'Dame', - 'Tristan', - 'Bova', - 'Doak', - 'Mannino', - 'Shotwell', - 'Bash', - 'Coots', - 'Feist', - 'Mahmood', - 'Schlabach', - 'Salzman', - 'Kass', - 'Bresnahan', - 'Stonge', - 'Tesch', - 'Grajeda', - 'Mccarron', - 'Mcelwee', - 'Spradling', - 'Mckown', - 'Colgan', - 'Piedra', - 'Collum', - 'Stoffel', - 'Won', - 'Gulick', - 'Devault', - 'Enders', - 'Yanes', - 'Lansing', - 'Ebner', - 'Deegan', - 'Boutin', - 'Fetzer', - 'Andresen', - 'Trigg', - 'Sale', - 'Polite', - 'Hummer', - 'Wille', - 'Bowerman', - 'Routh', - 'Iqbal', - 'Lakey', - 'Mcadoo', - 'Laflamme', - 'Boulware', - 'Guadarrama', - 'Campana', - 'Strayer', - 'Aho', - 'Emmett', - 'Wolters', - 'Bos', - 'Knighten', - 'Averill', - 'Bhakta', - 'Schumaker', - 'Stutts', - 'Mejias', - 'Byer', - 'Mahone', - 'Staab', - 'Riehl', - 'Briceno', - 'Zabala', - 'Lafountain', - 'Clemmer', - 'Mansell', - 'Rossetti', - 'Lafontaine', - 'Mager', - 'Adamo', - 'Bogue', - 'Northern', - 'Disney', - 'Masse', - 'Senter', - 'Yaeger', - 'Dahlberg', - 'Bisson', - 'Leitner', - 'Bolding', - 'Ormsby', - 'Berard', - 'Brazell', - 'Pickle', - 'Hord', - 'Mcguigan', - 'Glennon', - 'Aman', - 'Dearman', - 'Cauthen', - 'Rembert', - 'Delucia', - 'Enciso', - 'Slusser', - 'Kratzer', - 'Schoenfeld', - 'Gillam', - 'Rael', - 'Rhode', - 'Moton', - 'Eide', - 'Eliason', - 'Helfrich', - 'Bish', - 'Goodnight', - 'Campion', - 'Blow', - 'Gerken', - 'Goldenberg', - 'Mellinger', - 'Nations', - 'Maiden', - 'Anzalone', - 'Wagers', - 'Arguelles', - 'Christen', - 'Guth', - 'Stamey', - 'Bozarth', - 'Balogh', - 'Grammer', - 'Chafin', - 'Prine', - 'Freer', - 'Alder', - 'Latorre', - 'Zaleski', - 'Lindholm', - 'Belisle', - 'Zacharias', - 'Swinson', - 'Bazemore', - 'Glazer', - 'Acord', - 'Said', - 'Liggins', - 'Lueck', - 'Luedtke', - 'Blackstone', - 'Copper', - 'Riker', - 'Braud', - 'Demello', - 'Rode', - 'Haven', - 'Rhee', - 'Galligan', - 'Record', - 'Nilson', - 'Ansley', - 'Pera', - 'Gilliard', - 'Copp', - 'Haugh', - 'Dunigan', - 'Grinnell', - 'Garr', - 'Leonhardt', - 'Elswick', - 'Shahan', - 'Mike', - 'Boddie', - 'Casella', - 'Mauricio', - 'Millet', - 'Daye', - 'Claussen', - 'Pierrelouis', - 'Fleischman', - 'Embrey', - 'Durso', - 'Whisenant', - 'Rankins', - 'Lasky', - 'Askins', - 'Rupe', - 'Rochelle', - 'Burkes', - 'Kreger', - 'Mishler', - 'Heald', - 'Jager', - 'Player', - 'Linehan', - 'Horwitz', - 'Jacobi', - 'Maine', - 'Wiest', - 'Ostrom', - 'Sealy', - 'Jimerson', - 'Alverson', - 'Senior', - 'Hassett', - 'Colter', - 'Schleicher', - 'Marini', - 'Mcbrayer', - 'Arzola', - 'Sobel', - 'Frederickson', - 'Confer', - 'Tadlock', - 'Belmonte', - 'Lebrun', - 'Clyde', - 'Alleyne', - 'Lozoya', - 'Teller', - 'Husband', - 'Brigman', - 'Secrest', - 'Krajewski', - 'Neiman', - 'Trull', - 'Watterson', - 'Vanhook', - 'Sotomayor', - 'Woodrum', - 'Baskerville', - 'Finke', - 'Hohman', - 'Arp', - 'Hearne', - 'Mauk', - 'Danko', - 'Laurie', - 'Linderman', - 'Hutt', - 'Springfield', - 'Chmielewski', - 'Klimek', - 'Phinney', - 'Leboeuf', - 'Mcglone', - 'Holmquist', - 'Cogswell', - 'Nichol', - 'Klink', - 'Dunston', - 'Krawczyk', - 'Dart', - 'Woodside', - 'Smitherman', - 'Gasca', - 'Sala', - 'Foxworth', - 'Kammerer', - 'Auer', - 'Pegues', - 'Bukowski', - 'Koger', - 'Spitz', - 'Blomquist', - 'Creasy', - 'Bomar', - 'Holub', - 'Loney', - 'Garry', - 'Habib', - 'Chea', - 'Dupuy', - 'Seaver', - 'Sowards', - 'Julius', - 'Fulks', - 'Braithwaite', - 'Bretz', - 'Mccammon', - 'Sedillo', - 'Chiasson', - 'Oney', - 'Horstman', - 'Waites', - 'Mccusker', - 'Fenske', - 'Conwell', - 'Brokaw', - 'Cloyd', - 'Biles', - 'Aguinaga', - 'Astorga', - 'Demaio', - 'Liberty', - 'Kayser', - 'Ney', - 'Barthel', - 'Lennox', - 'Trautman', - 'Purser', - 'Pitzer', - 'Mattos', - 'Liss', - 'Clack', - 'Sias', - 'Bobb', - 'Stoller', - 'Robillard', - 'Almodovar', - 'Cribb', - 'Ebel', - 'Oyler', - 'Dail', - 'Ericksen', - 'Geis', - 'Everitt', - 'Cropper', - 'Meisner', - 'Skeens', - 'Frith', - 'Privett', - 'Braddy', - 'Bolick', - 'Severance', - 'Jeffreys', - 'Bethune', - 'Delcid', - 'Buzzard', - 'Broadbent', - 'Bono', - 'Addis', - 'Johannes', - 'Tims', - 'Castorena', - 'Simonsen', - 'Glidewell', - 'Mui', - 'Ogilvie', - 'Soukup', - 'Sunday', - 'Redwine', - 'Borton', - 'Schuyler', - 'Rudisill', - 'Beckford', - 'Pascua', - 'Garton', - 'Gilkey', - 'Applewhite', - 'Halterman', - 'Alsup', - 'Delreal', - 'Hubble', - 'Quijada', - 'Kropp', - 'Dunkle', - 'Lemire', - 'Lamontagne', - 'Dunkin', - 'Paulin', - 'Attaway', - 'Baugher', - 'Hornbeck', - 'Niehaus', - 'Nice', - 'Trimmer', - 'Canaday', - 'Maney', - 'Trexler', - 'Schmucker', - 'Edinger', - 'Massengill', - 'Rowlett', - 'Caviness', - 'Kam', - 'Chesnut', - 'Giardina', - 'Spaeth', - 'Gebhart', - 'Morano', - 'Salguero', - 'Buckland', - 'Reina', - 'Jumper', - 'Navas', - 'Thrift', - 'Spradley', - 'Bitner', - 'Ayer', - 'Harber', - 'Landaverde', - 'Mcmillion', - 'Naugle', - 'Dole', - 'Seagraves', - 'Smithers', - 'Frechette', - 'Weeden', - 'Caston', - 'Cavallaro', - 'Laureano', - 'Mandell', - 'Lowrance', - 'Baty', - 'Ronan', - 'Gigliotti', - 'Rossiter', - 'Mines', - 'Alatorre', - 'Markowski', - 'Berge', - 'Hatter', - 'Weakley', - 'Borrero', - 'Glazier', - 'Lavergne', - 'Sines', - 'Ingham', - 'Meltzer', - 'Rabinowitz', - 'Siciliano', - 'Canas', - 'Perna', - 'Struck', - 'Dare', - 'Nay', - 'Severino', - 'Mathewson', - 'Bouldin', - 'Topete', - 'Brunette', - 'Sin', - 'Hendren', - 'Brickey', - 'Ferrier', - 'Alessi', - 'Scheel', - 'Storer', - 'Matherne', - 'Mecham', - 'Spiker', - 'Hibbert', - 'Klingensmith', - 'Lefever', - 'Banning', - 'Bankhead', - 'Roan', - 'Brack', - 'Pascoe', - 'Davie', - 'Scheid', - 'Jim', - 'Tweedy', - 'Strahan', - 'Revis', - 'Fermin', - 'Obrian', - 'Motes', - 'Lobo', - 'Palmisano', - 'Faught', - 'Byington', - 'Garren', - 'Hungerford', - 'Vanzandt', - 'Gust', - 'Heater', - 'Klingler', - 'Delay', - 'Wear', - 'Hendley', - 'Threatt', - 'Gaughan', - 'Kunze', - 'Hessler', - 'Lindell', - 'Monteleone', - 'Palazzolo', - 'Shear', - 'Phares', - 'Cavalier', - 'Benning', - 'Urbanski', - 'Darrah', - 'Wager', - 'Mohn', - 'Vereen', - 'Beiler', - 'Hedlund', - 'Quade', - 'Wieczorek', - 'Cicero', - 'Hoekstra', - 'Scalf', - 'Ducote', - 'Havard', - 'Espiritu', - 'Beacham', - 'Bolger', - 'Schuller', - 'Sill', - 'Dice', - 'Lemmons', - 'Orlowski', - 'Lundeen', - 'Steck', - 'Stanfill', - 'Rakes', - 'Laine', - 'Haviland', - 'Durrett', - 'Naumann', - 'Donahoe', - 'Reif', - 'Franck', - 'Amoroso', - 'Belknap', - 'Tolle', - 'Perrotta', - 'Heyer', - 'Dougan', - 'Frakes', - 'Leath', - 'Poteat', - 'Violette', - 'Marine', - 'Zellner', - 'Granillo', - 'Fontanez', - 'Didonato', - 'Bradberry', - 'Morman', - 'Mentzer', - 'Lamoureux', - 'Sabatino', - 'Catania', - 'Wenner', - 'Pastrana', - 'Shenk', - 'Losey', - 'Hepburn', - 'Antonucci', - 'Egger', - 'Higbee', - 'Adames', - 'Reep', - 'Cavallo', - 'Bridwell', - 'Villalba', - 'Poor', - 'Peet', - 'Everette', - 'Arney', - 'Towery', - 'Sharon', - 'Trainer', - 'Marrow', - 'Cumming', - 'Rimmer', - 'Stanger', - 'Pinter', - 'Felt', - 'Parrett', - 'Garrard', - 'Benedetto', - 'Lingenfelter', - 'Resch', - 'Billy', - 'Mikesell', - 'Osterman', - 'Trueblood', - 'Redfern', - 'Calderone', - 'Placencia', - 'Wamsley', - 'Warr', - 'Varnado', - 'Harshbarger', - 'Topping', - 'Feltner', - 'Decosta', - 'Tart', - 'Blumberg', - 'Shaikh', - 'Culley', - 'Bork', - 'Thibeault', - 'Stolz', - 'Ramsdell', - 'Tedford', - 'Noto', - 'Poulson', - 'Daves', - 'Altieri', - 'Mendosa', - 'Kisner', - 'Grafton', - 'Remy', - 'Hartline', - 'Cripe', - 'Sher', - 'Mulvaney', - 'Ansari', - 'Hartfield', - 'Whitton', - 'Wathen', - 'Eisele', - 'Hinojos', - 'Backer', - 'Speaks', - 'Schuetz', - 'Novoa', - 'Marcos', - 'Mask', - 'Oboyle', - 'Kircher', - 'Stang', - 'Sibert', - 'Scala', - 'Zacarias', - 'Hendon', - 'Halvorsen', - 'Montalbano', - 'Zermeno', - 'Vancamp', - 'Grams', - 'Hornberger', - 'Binion', - 'Dewald', - 'Rives', - 'Sankey', - 'Kleinman', - 'Falconer', - 'Rumph', - 'Matus', - 'Swett', - 'Spinner', - 'Depasquale', - 'Gamino', - 'Olmsted', - 'Absher', - 'Culler', - 'Fryman', - 'Lampert', - 'Carlyle', - 'Terranova', - 'Dunagan', - 'Chouinard', - 'Wesolowski', - 'Hetherington', - 'Scalise', - 'Pendergast', - 'Marcano', - 'Joubert', - 'Scheller', - 'Whisenhunt', - 'Lenoir', - 'Mahar', - 'Vanlandingham', - 'Pecoraro', - 'You', - 'Natividad', - 'Daum', - 'Penick', - 'Eddington', - 'Deleo', - 'Soltis', - 'Santucci', - 'Costanza', - 'Hiner', - 'Farlow', - 'Hartsock', - 'Duprey', - 'Fann', - 'Safford', - 'Murtha', - 'Fessler', - 'Chien', - 'Paynter', - 'Devera', - 'Hoelscher', - 'Boltz', - 'Deacon', - 'Loo', - 'Enoch', - 'Dilorenzo', - 'Saville', - 'Mirza', - 'Takacs', - 'Drexler', - 'Lakin', - 'Geraghty', - 'Widmer', - 'Esteves', - 'Llanes', - 'Cerny', - 'Quist', - 'Hargraves', - 'Toma', - 'Tarter', - 'Chapple', - 'Alderete', - 'Michelson', - 'Clymer', - 'Batey', - 'Sealey', - 'Loughlin', - 'Preece', - 'Zurita', - 'Courville', - 'Desousa', - 'Shamblin', - 'Tingley', - 'Noles', - 'Misner', - 'Standifer', - 'Dinardo', - 'Dillow', - 'Bullis', - 'Carballo', - 'Everly', - 'Mulvihill', - 'Tincher', - 'Carle', - 'Lundin', - 'Birdsall', - 'Bainbridge', - 'Suttle', - 'Wightman', - 'Mower', - 'Mountain', - 'Bickham', - 'Durante', - 'Viveros', - 'Swinford', - 'Mcgruder', - 'Tapley', - 'Grable', - 'Gwynn', - 'Wiebe', - 'Stagg', - 'Dash', - 'Heitman', - 'Cluff', - 'Huertas', - 'Fortuna', - 'Lines', - 'Sly', - 'Halford', - 'Helsel', - 'Bicknell', - 'Blakeman', - 'Colangelo', - 'Olney', - 'Quinton', - 'Rothrock', - 'Renz', - 'Hone', - 'Prejean', - 'Oshiro', - 'Serio', - 'Latour', - 'Newbold', - 'Fitzhugh', - 'Songer', - 'Cardin', - 'Geter', - 'Barbera', - 'Abbas', - 'Caesar', - 'Blakeslee', - 'Camper', - 'Mcclurg', - 'Driskill', - 'Cancel', - 'Donelson', - 'Borrelli', - 'Donoghue', - 'Shoaf', - 'Tinajero', - 'Arzate', - 'Keesee', - 'Pasley', - 'Strode', - 'Morello', - 'Trantham', - 'Ackerson', - 'Jowers', - 'Brockington', - 'Barcia', - 'Lipp', - 'Dinger', - 'Ridings', - 'Canavan', - 'Rank', - 'Hagans', - 'Lampley', - 'Beckmann', - 'Bjork', - 'Raygoza', - 'Schirmer', - 'Longmire', - 'Schiavone', - 'Breuer', - 'Lore', - 'Stenson', - 'Koziol', - 'Channell', - 'Cale', - 'Trader', - 'Culberson', - 'Mundt', - 'Sickles', - 'Nemec', - 'Holl', - 'Stribling', - 'Berens', - 'Nauman', - 'Lehner', - 'Deem', - 'Castelli', - 'Billman', - 'Orndorff', - 'Gumm', - 'Davy', - 'Pelham', - 'Spotts', - 'Jurgens', - 'Sword', - 'Adorno', - 'Gorrell', - 'Boughton', - 'Bobadilla', - 'Mauer', - 'Moline', - 'Guay', - 'Holsinger', - 'Baranowski', - 'Gutierres', - 'Beveridge', - 'Marable', - 'Berkey', - 'Lamothe', - 'Spitler', - 'Carbaugh', - 'Hoopes', - 'Wilken', - 'Milford', - 'Bingaman', - 'Crippen', - 'Shock', - 'Yarnell', - 'Oman', - 'Wethington', - 'Kost', - 'Gaudette', - 'Spielman', - 'Foran', - 'Starke', - 'Eugene', - 'Birnbaum', - 'Navarrette', - 'Hussein', - 'Ranson', - 'Hedgepeth', - 'Doctor', - 'Higuera', - 'Brough', - 'Cookson', - 'Provencher', - 'Mendonca', - 'Gowen', - 'Summer', - 'Rutz', - 'Reader', - 'Doud', - 'Raven', - 'Toribio', - 'Peachey', - 'Gunning', - 'Bittle', - 'Vale', - 'Harnish', - 'Marano', - 'Aker', - 'Damore', - 'Utz', - 'Throckmorton', - 'Bulger', - 'Vanzant', - 'Pasillas', - 'Holmgren', - 'Corpus', - 'Longley', - 'Wetmore', - 'Carstens', - 'Line', - 'Percival', - 'Ayotte', - 'Batres', - 'Pipes', - 'Ludwick', - 'Alpert', - 'Pick', - 'Carlock', - 'Edmundson', - 'Feinstein', - 'Krouse', - 'Dahlgren', - 'Sasaki', - 'Lieb', - 'Londono', - 'Oloughlin', - 'Wardlaw', - 'Lineberry', - 'Castello', - 'Milstead', - 'Parmenter', - 'Riffe', - 'Pare', - 'Sitton', - 'Tarin', - 'Delcastillo', - 'Manor', - 'Calabro', - 'Elkin', - 'Grill', - 'Boaz', - 'Coco', - 'Chamblee', - 'Celestine', - 'Nick', - 'Stork', - 'Meekins', - 'Moise', - 'Devers', - 'Jun', - 'Kegley', - 'Brick', - 'Lobato', - 'Biggerstaff', - 'Kersten', - 'Jayne', - 'Nasser', - 'Southall', - 'Kempton', - 'Eaddy', - 'Paladino', - 'Berardi', - 'Pizzo', - 'Pulver', - 'Ohalloran', - 'Fromm', - 'Cranston', - 'Rowden', - 'Capobianco', - 'Kahle', - 'Thiessen', - 'Malott', - 'Houseman', - 'Maul', - 'Gallion', - 'Tressler', - 'Pauly', - 'Pellerin', - 'Sainz', - 'Firth', - 'Cryer', - 'Jeanlouis', - 'Mong', - 'Trawick', - 'Chronister', - 'Hayashi', - 'Posner', - 'Cueva', - 'Sherwin', - 'Lacasse', - 'Gorden', - 'Bohl', - 'Twigg', - 'Coan', - 'Hocker', - 'Goodale', - 'Urbano', - 'Loeb', - 'Perrault', - 'Frawley', - 'Carcamo', - 'Richburg', - 'Moffat', - 'Hennings', - 'Weyer', - 'Myatt', - 'Ullman', - 'Tunnell', - 'Hern', - 'Lopresti', - 'Sonnenberg', - 'Knisley', - 'Twomey', - 'Jaggers', - 'Tanksley', - 'Rachal', - 'Poppe', - 'Vos', - 'Kania', - 'Speakman', - 'Peirce', - 'Pound', - 'Romer', - 'Patty', - 'Millsaps', - 'Kyser', - 'Telford', - 'Hegarty', - 'Kellett', - 'Michaelis', - 'Halligan', - 'Maughan', - 'Herb', - 'Rainer', - 'Robichaud', - 'Fiscus', - 'Sickler', - 'Blom', - 'Lavine', - 'Medel', - 'Bolyard', - 'Secor', - 'Creekmore', - 'Magruder', - 'Haskin', - 'Laliberte', - 'Drago', - 'Bernabe', - 'Leader', - 'Cavin', - 'Lukens', - 'Vassallo', - 'Pletcher', - 'Fuson', - 'Hasson', - 'Huckabee', - 'Edington', - 'Eichler', - 'Hering', - 'Vong', - 'Mardis', - 'Gu', - 'Segarra', - 'Bilyeu', - 'Runion', - 'Fragoso', - 'Gama', - 'Dunton', - 'Frady', - 'Lewellen', - 'Crumpler', - 'Jeske', - 'Furlow', - 'Delapena', - 'Kale', - 'Massengale', - 'Hamlet', - 'Galli', - 'Esteban', - 'Greeson', - 'Shue', - 'Pollak', - 'Pinney', - 'Ruffner', - 'Maitland', - 'Steven', - 'Hockett', - 'Fraire', - 'Mulhern', - 'Elbert', - 'Hoggard', - 'Labarge', - 'Silcox', - 'Saez', - 'Sluder', - 'Stamp', - 'Darlington', - 'Mccarroll', - 'Pillow', - 'Palazzo', - 'Blaha', - 'Demaria', - 'Swanger', - 'Winningham', - 'Lippincott', - 'Dake', - 'Goldsberry', - 'Seidl', - 'Woolfolk', - 'Murawski', - 'Hobart', - 'Kimber', - 'Nilsson', - 'Stough', - 'Almendarez', - 'Nevels', - 'Fasano', - 'Salmons', - 'Denmark', - 'Lathan', - 'Mosely', - 'Stengel', - 'Mendieta', - 'Felice', - 'Drown', - 'Vidrine', - 'Callihan', - 'Polston', - 'Howze', - 'Eakins', - 'Leek', - 'Featherstone', - 'Lajoie', - 'Athey', - 'Asuncion', - 'Ashbaugh', - 'Orman', - 'Morrissette', - 'Peart', - 'Hamner', - 'Zell', - 'Dry', - 'Dieter', - 'Terrones', - 'Campuzano', - 'Reveles', - 'Bakker', - 'Banister', - 'Arceo', - 'Dhillon', - 'Normand', - 'Shavers', - 'Ginsburg', - 'Go', - 'Rubinstein', - 'Arens', - 'Clutter', - 'Jaques', - 'Traxler', - 'Hackler', - 'Cisco', - 'Starrett', - 'Ceron', - 'Gillenwater', - 'Ottinger', - 'Caster', - 'Blakemore', - 'Thorsen', - 'Molinar', - 'Baur', - 'Hower', - 'Haldeman', - 'Oliveri', - 'Mcalpin', - 'Standish', - 'Bengtson', - 'Strack', - 'Cordoba', - 'Blackstock', - 'Barna', - 'Schantz', - 'Hawkinson', - 'Breese', - 'Saba', - 'Camden', - 'Gwaltney', - 'Corliss', - 'Smit', - 'Cruise', - 'Mcneese', - 'Duggins', - 'Laub', - 'Burman', - 'Kenworthy', - 'Spohn', - 'Santini', - 'Nuttall', - 'Willison', - 'Stjean', - 'Shabazz', - 'Manes', - 'Gerry', - 'Mclamb', - 'Koepke', - 'Reeser', - 'Ogburn', - 'Wegener', - 'Risinger', - 'Carrero', - 'Livermore', - 'Brewton', - 'Harsh', - 'Utterback', - 'Lecompte', - 'Schnabel', - 'Ting', - 'Honea', - 'Stryker', - 'Foshee', - 'Baptista', - 'Gravely', - 'Courson', - 'Goyette', - 'Leitch', - 'Tasker', - 'Laurence', - 'Reneau', - 'Voight', - 'Tilson', - 'Range', - 'Hallam', - 'Dufrene', - 'Boice', - 'Shrewsbury', - 'Sturges', - 'Lenard', - 'Sistrunk', - 'Weitz', - 'Carnevale', - 'Hepner', - 'Wehner', - 'Callen', - 'Oshaughnessy', - 'Wingert', - 'Mouser', - 'Palmore', - 'Rugg', - 'Elia', - 'Alcazar', - 'Avitia', - 'Penton', - 'Brisco', - 'Ambrosio', - 'Wardlow', - 'Leaf', - 'Rowles', - 'Buggs', - 'Dittmer', - 'Schweizer', - 'Puleo', - 'Vaden', - 'Haughton', - 'Cardinale', - 'Seguin', - 'Ruddy', - 'Minard', - 'Stalker', - 'Bennington', - 'Hilt', - 'Works', - 'Broadus', - 'Engels', - 'Haddix', - 'Buster', - 'Recker', - 'Bopp', - 'Wilton', - 'Costantino', - 'Boots', - 'Falkner', - 'Tennison', - 'Mcgary', - 'Holz', - 'Lofgren', - 'Putney', - 'Christner', - 'Fruge', - 'Vassar', - 'Vankirk', - 'Spoon', - 'Pearlman', - 'Guertin', - 'Meece', - 'Sartain', - 'Petterson', - 'Primm', - 'Cardillo', - 'Dryer', - 'Hartshorn', - 'Dane', - 'Chaisson', - 'Espitia', - 'Creager', - 'Disalvo', - 'Janik', - 'Parente', - 'Paiva', - 'Slaven', - 'Tague', - 'Kujawa', - 'Gruver', - 'Foor', - 'Frampton', - 'Prokop', - 'Mettler', - 'Collis', - 'Lamkin', - 'Shuey', - 'Tepper', - 'Colyer', - 'Masi', - 'Trumble', - 'Guice', - 'Hurwitz', - 'Windle', - 'Mccully', - 'Cutting', - 'Stotler', - 'Grullon', - 'Wagstaff', - 'Morfin', - 'Dehaan', - 'Noon', - 'Flesher', - 'Ferri', - 'Covell', - 'Coll', - 'Lucy', - 'Albaugh', - 'Testerman', - 'Gordillo', - 'Jepson', - 'Brinkerhoff', - 'Calle', - 'Crowl', - 'Mcelwain', - 'Chumley', - 'Brockett', - 'Thoms', - 'Revell', - 'Garzon', - 'Polak', - 'Rothenberg', - 'Socha', - 'Vallejos', - 'Felty', - 'Peguero', - 'Ping', - 'Tso', - 'Charleston', - 'Fedor', - 'Haider', - 'Abe', - 'Enlow', - 'Fifer', - 'Bumpus', - 'Keele', - 'Mcdavid', - 'Panek', - 'Scholten', - 'Dyess', - 'Heatherly', - 'Donohoe', - 'Hoban', - 'Griffey', - 'Corry', - 'Mcclean', - 'Plyler', - 'Feathers', - 'Adkison', - 'Killeen', - 'Hoeft', - 'Myhre', - 'Fiorentino', - 'Mcbeth', - 'Erazo', - 'Madson', - 'Fulbright', - 'Wilds', - 'Petrucci', - 'Mcgaughey', - 'Monteith', - 'Murguia', - 'Hausman', - 'Zukowski', - 'Shute', - 'Brisson', - 'Lain', - 'Runkle', - 'Hickok', - 'Caffrey', - 'Million', - 'Elson', - 'Peay', - 'Haga', - 'Ancheta', - 'Cordle', - 'Blas', - 'Carmen', - 'Pettiford', - 'Dimartino', - 'Spahr', - 'Mozingo', - 'Backman', - 'Stgeorge', - 'Konrad', - 'Buhler', - 'Mcelrath', - 'Oliveros', - 'Edelstein', - 'Cadet', - 'Gilmartin', - 'Munday', - 'Roane', - 'Desalvo', - 'Lepe', - 'Symons', - 'Shearin', - 'Linkous', - 'Cheshire', - 'Klemm', - 'Beagle', - 'Pooler', - 'Dewalt', - 'Esch', - 'Finnell', - 'Sinnott', - 'Kepler', - 'Toups', - 'Riccardi', - 'Caylor', - 'Tillis', - 'Messmer', - 'Rothschild', - 'Boutte', - 'Zumwalt', - 'Bohrer', - 'Elgin', - 'Kinley', - 'Schechter', - 'Gowan', - 'Pyne', - 'Cousin', - 'Hunsinger', - 'Fishel', - 'Edenfield', - 'Nadler', - 'Warman', - 'Bruhn', - 'Swint', - 'Lizotte', - 'Nardone', - 'Troxel', - 'Grindle', - 'Labrie', - 'Tao', - 'Olea', - 'Schermerhorn', - 'Stier', - 'Hettinger', - 'Farthing', - 'Roux', - 'Max', - 'Amburgey', - 'Auerbach', - 'Janzen', - 'Ortez', - 'Alejandre', - 'Peiffer', - 'Molinaro', - 'Burleigh', - 'Benites', - 'Ringler', - 'Hou', - 'Haffner', - 'Nace', - 'Crosson', - 'Karcher', - 'Neufeld', - 'Bayles', - 'Riemer', - 'Amezquita', - 'Cadwell', - 'Petrosky', - 'Swallow', - 'Minnis', - 'Krupp', - 'Nardi', - 'Orsini', - 'Diez', - 'Updike', - 'Gasser', - 'Rogerson', - 'Speicher', - 'Dubay', - 'Hollaway', - 'Teets', - 'Keown', - 'Center', - 'Blanding', - 'Whisler', - 'Spurlin', - 'Collin', - 'Greenawalt', - 'Tomes', - 'Leister', - 'Chatfield', - 'Helwig', - 'Reimers', - 'Andress', - 'Norcross', - 'Melnick', - 'Yearwood', - 'Defazio', - 'Kubik', - 'Bhatia', - 'Uddin', - 'Belmont', - 'Haden', - 'Bench', - 'Chilson', - 'Pegg', - 'Cane', - 'Goehring', - 'Lino', - 'Tyus', - 'Furey', - 'Castleman', - 'Heywood', - 'Leedy', - 'Holleman', - 'Villeda', - 'Mcveigh', - 'Carreiro', - 'Hocking', - 'Azar', - 'Blough', - 'Lieu', - 'Marcial', - 'Coblentz', - 'Hossain', - 'Weisberg', - 'Gardea', - 'Hoyos', - 'Lipsey', - 'Reger', - 'Clouser', - 'Bewley', - 'Magness', - 'Goines', - 'Thome', - 'Odea', - 'Mannion', - 'Dansby', - 'Dipasquale', - 'Constable', - 'Truelove', - 'Hubler', - 'Ulibarri', - 'Wymer', - 'Cron', - 'Hugo', - 'Hilderbrand', - 'Milazzo', - 'Vasques', - 'Sproul', - 'Shuford', - 'Chavers', - 'Kral', - 'Vecchio', - 'Mehl', - 'Rymer', - 'Henriksen', - 'Taulbee', - 'Hagy', - 'Ammerman', - 'Kagan', - 'Galdamez', - 'Krick', - 'Owsley', - 'Mullikin', - 'Beery', - 'Eccles', - 'Kleinschmidt', - 'Kloss', - 'Oldenburg', - 'Ospina', - 'Harbert', - 'Andujar', - 'Florian', - 'Antone', - 'Mcmillon', - 'Ceniceros', - 'Rippy', - 'Adkisson', - 'Stange', - 'Balmer', - 'Mazurek', - 'Dahlke', - 'Girouard', - 'Nickelson', - 'Perera', - 'Tullos', - 'Cioffi', - 'Bogdan', - 'Olivieri', - 'Petree', - 'Speights', - 'Jantz', - 'Collings', - 'Zellers', - 'Yarber', - 'Lafollette', - 'Rink', - 'Currin', - 'Chua', - 'Hartle', - 'Larocque', - 'Cuthbertson', - 'Ehrhardt', - 'Mara', - 'Rieck', - 'Lumley', - 'Anderton', - 'Hennigan', - 'Fabrizio', - 'Hutter', - 'Bruning', - 'Korman', - 'Haring', - 'Monette', - 'Woodyard', - 'Goggins', - 'Balzer', - 'Philbrick', - 'Bruder', - 'Hansford', - 'Averett', - 'Teske', - 'Mauck', - 'Billiot', - 'Collie', - 'Caffey', - 'Manos', - 'Buchan', - 'Birk', - 'Abdallah', - 'Featherston', - 'Koh', - 'Valera', - 'Deyo', - 'Buono', - 'Aubin', - 'Doody', - 'Pigott', - 'Peloquin', - 'Maniscalco', - 'Eisenhauer', - 'Biller', - 'Farwell', - 'Hartzog', - 'Brazier', - 'Talton', - 'Mcdougald', - 'Midgett', - 'Strout', - 'Spiers', - 'Eiland', - 'Garth', - 'Sequeira', - 'Noyola', - 'Petri', - 'Goodyear', - 'Dineen', - 'Bernardi', - 'Berns', - 'Coolidge', - 'Dorfman', - 'Dittman', - 'Zeno', - 'Hauer', - 'Finlay', - 'Ziemba', - 'Spillane', - 'Kays', - 'Ekstrom', - 'Hile', - 'Mckinstry', - 'Lesley', - 'Courtright', - 'Kuhlmann', - 'Verma', - 'Cripps', - 'Wigley', - 'Nickens', - 'Petrick', - 'Delozier', - 'Hardcastle', - 'Yamaguchi', - 'Romig', - 'Venezia', - 'Reading', - 'Redford', - 'Heng', - 'Anselmo', - 'Getty', - 'Marten', - 'Badgett', - 'Eisner', - 'Holtzman', - 'Stell', - 'Hiser', - 'Dustin', - 'Bordeaux', - 'Debolt', - 'Trevizo', - 'Eckard', - 'Follett', - 'Lal', - 'Dark', - 'Buskirk', - 'Roca', - 'Todaro', - 'Campanella', - 'Lindsley', - 'Wickman', - 'Pritt', - 'Cutlip', - 'Pokorny', - 'Friedlander', - 'Saari', - 'Casias', - 'Macneil', - 'Clyburn', - 'Kravitz', - 'Edgington', - 'Portis', - 'Culbreth', - 'Cuff', - 'Brouillette', - 'Artz', - 'Trudell', - 'Pledger', - 'Markovich', - 'Pisani', - 'Faller', - 'Sergent', - 'Hail', - 'Stabile', - 'Wait', - 'Mcilwain', - 'Eriksen', - 'Nee', - 'Boll', - 'Catanzaro', - 'Giuliano', - 'Oldfield', - 'Banas', - 'Ickes', - 'Vachon', - 'Gleeson', - 'Bailes', - 'Biehl', - 'Woodham', - 'Troupe', - 'Mcgoldrick', - 'Cappello', - 'Kirkendall', - 'Baisden', - 'Joshua', - 'Nicoletti', - 'Roesch', - 'Deatherage', - 'Matter', - 'Sheth', - 'Tynes', - 'Shaheen', - 'Wilbert', - 'Toles', - 'Sanner', - 'Bury', - 'Boman', - 'Bose', - 'Millner', - 'Eisen', - 'Couto', - 'Ide', - 'Howells', - 'Jiminez', - 'Crampton', - 'Monti', - 'Jelinek', - 'Morford', - 'Yeomans', - 'Turnbow', - 'Rolland', - 'Scheetz', - 'Arends', - 'Repp', - 'Hohn', - 'Paton', - 'Govan', - 'Fabela', - 'Mroz', - 'Bourassa', - 'Rizzi', - 'Froelich', - 'Molinari', - 'Lunde', - 'Navarre', - 'Alexandre', - 'Dearborn', - 'Lakes', - 'Foxx', - 'Jerez', - 'Lamanna', - 'Talarico', - 'Butera', - 'Riner', - 'Gros', - 'Champ', - 'Phoenix', - 'Vandeventer', - 'Samora', - 'Behling', - 'Karpinski', - 'Hosier', - 'Tufts', - 'Hobby', - 'Rohrbach', - 'Youngman', - 'Yeary', - 'Paisley', - 'Ben', - 'Villalta', - 'Hempel', - 'Giblin', - 'Lunt', - 'Hagar', - 'Lapoint', - 'Singley', - 'Shows', - 'Kesterson', - 'Bollman', - 'Stansell', - 'Yon', - 'Gabaldon', - 'Simental', - 'Zastrow', - 'Enloe', - 'Sasso', - 'Harkey', - 'Sansom', - 'Twyman', - 'Haslam', - 'Sowa', - 'Hunsberger', - 'Norberg', - 'Hornback', - 'Hanshaw', - 'Axtell', - 'Hoge', - 'Gantz', - 'Mccullum', - 'Blazek', - 'Scher', - 'Carlucci', - 'Jeong', - 'Tillett', - 'Woolridge', - 'Carberry', - 'Reck', - 'Nevin', - 'Armes', - 'Sidhu', - 'Wiesner', - 'Auman', - 'Teeters', - 'Rigg', - 'Moloney', - 'Feld', - 'Lucier', - 'Cardone', - 'Kilian', - 'Conder', - 'Horta', - 'Murakami', - 'Schaff', - 'Dresser', - 'Spray', - 'Hott', - 'Capuano', - 'Englund', - 'Rothe', - 'Ferree', - 'Nolt', - 'Triana', - 'Sanjuan', - 'Oller', - 'Brathwaite', - 'Richert', - 'Holdren', - 'Goree', - 'Branstetter', - 'Schimmel', - 'Jessop', - 'Nellis', - 'Sevier', - 'Rabb', - 'Mcmorris', - 'Lindo', - 'Littles', - 'Polzin', - 'Ranieri', - 'Reale', - 'Sturtevant', - 'Arnone', - 'Zamorano', - 'Keever', - 'Clow', - 'Corr', - 'Blaser', - 'Sheetz', - 'Llanos', - 'Belew', - 'Rusnak', - 'Brandes', - 'Eichhorn', - 'Guida', - 'Pucci', - 'Streit', - 'Renn', - 'Partee', - 'Rappaport', - 'Rosso', - 'Defeo', - 'Greve', - 'Schoch', - 'Langevin', - 'Manna', - 'Towe', - 'Scoville', - 'Marco', - 'Gove', - 'Mckissick', - 'Dangerfield', - 'Mcwhirter', - 'Port', - 'Marrufo', - 'Nicosia', - 'Farren', - 'Kinsley', - 'Pearman', - 'Porch', - 'Mooneyham', - 'Buff', - 'Ruben', - 'Blanc', - 'Mellen', - 'Heiman', - 'Novack', - 'Heston', - 'Huie', - 'Justin', - 'Kincade', - 'Laverty', - 'Villavicencio', - 'Burkart', - 'Offutt', - 'Halliburton', - 'Polo', - 'Barbara', - 'Trammel', - 'Rosati', - 'Sakamoto', - 'Salo', - 'Heyman', - 'Rooker', - 'Sarno', - 'Leroux', - 'Virgen', - 'Collison', - 'Branum', - 'Mcmasters', - 'Divine', - 'Mcnatt', - 'Threadgill', - 'Desir', - 'Borchers', - 'Walkup', - 'Sy', - 'Greenbaum', - 'Vidales', - 'Mercedes', - 'Selph', - 'Bardwell', - 'Whorton', - 'Demartino', - 'Endsley', - 'Verner', - 'Hillier', - 'Mancha', - 'Ricard', - 'Postell', - 'Kummer', - 'Welsch', - 'Almanzar', - 'Brunet', - 'Deeds', - 'Romanowski', - 'Ocallaghan', - 'Cueto', - 'Terhune', - 'Truesdell', - 'Whisnant', - 'Lingo', - 'Aden', - 'Labrecque', - 'Braga', - 'Iles', - 'Garrick', - 'Knickerbocker', - 'Rasberry', - 'Hervey', - 'Schill', - 'Kiely', - 'Liddle', - 'Blakeley', - 'Marez', - 'Schoonmaker', - 'Swinton', - 'Fryar', - 'Exum', - 'Gouge', - 'Hoskinson', - 'Lupton', - 'Guild', - 'Davisson', - 'Chidester', - 'Gravitt', - 'Lenox', - 'Pyatt', - 'Moberg', - 'Overholt', - 'Whiddon', - 'Foti', - 'Lipps', - 'Shankle', - 'Xiao', - 'Balentine', - 'Cesar', - 'Barreras', - 'Schroer', - 'Ram', - 'Eames', - 'Gutman', - 'Pardee', - 'Damiano', - 'Houchin', - 'Porto', - 'Leclerc', - 'Mahaney', - 'Deardorff', - 'Garey', - 'Trotta', - 'Lachapelle', - 'Suiter', - 'Ewert', - 'Costner', - 'Bever', - 'Charpentier', - 'Milewski', - 'Coffelt', - 'Schorr', - 'Leis', - 'Dasher', - 'Cullins', - 'Eveland', - 'Hornung', - 'Swingle', - 'Eudy', - 'Motter', - 'Silk', - 'Gadd', - 'Sidwell', - 'Sandusky', - 'Auld', - 'Mazariegos', - 'Hirt', - 'Zane', - 'Rickett', - 'Ritenour', - 'Goin', - 'Dipaolo', - 'Wolfgang', - 'Inouye', - 'Branton', - 'Rakestraw', - 'Kimbro', - 'Craighead', - 'Sandefur', - 'Foerster', - 'Wipf', - 'Wilkin', - 'Shoffner', - 'Overcash', - 'Simonetti', - 'Toomer', - 'Albino', - 'Eshelman', - 'Rockwood', - 'Pineiro', - 'Reames', - 'Cray', - 'Wulff', - 'Heider', - 'Bath', - 'Colletti', - 'Fiala', - 'Greenstein', - 'Moles', - 'Bashaw', - 'Adamczyk', - 'Finkel', - 'Kistner', - 'Manzi', - 'Ferretti', - 'Demarest', - 'Ahlers', - 'Lack', - 'Wedel', - 'Kinzer', - 'Sechrist', - 'Stickler', - 'Easterday', - 'Mallette', - 'Loehr', - 'Gessner', - 'Croce', - 'Stanko', - 'Innes', - 'Farfan', - 'Heady', - 'Chambless', - 'Balbuena', - 'Decicco', - 'Winsor', - 'Pereyra', - 'Zoller', - 'Ingles', - 'Churchwell', - 'Westlake', - 'Villagran', - 'Soderberg', - 'Thill', - 'Timmer', - 'Mccaleb', - 'Mckernan', - 'Vandergriff', - 'Yoho', - 'Crispin', - 'Dorton', - 'Fults', - 'Borne', - 'Maxie', - 'Bloomquist', - 'Kung', - 'Budde', - 'Weinstock', - 'Honey', - 'Diener', - 'Horak', - 'Tsui', - 'Zirkle', - 'Plum', - 'Heitz', - 'Manrique', - 'Balcom', - 'Napper', - 'Boese', - 'Stefan', - 'Kime', - 'Gautreaux', - 'Leverette', - 'Lemaire', - 'Danford', - 'Hollman', - 'Kuzma', - 'Swinehart', - 'Merriam', - 'Novick', - 'Stankiewicz', - 'Parkes', - 'Englehart', - 'Polansky', - 'Leclaire', - 'Magner', - 'Masson', - 'Mass', - 'Coogan', - 'Jepsen', - 'Pittenger', - 'Bump', - 'Hain', - 'Burchell', - 'Chesley', - 'Cawthon', - 'Dance', - 'Piccolo', - 'Lucey', - 'Ordway', - 'Recio', - 'Ginther', - 'Hauge', - 'Lesperance', - 'Suhr', - 'Ding', - 'Ogg', - 'Skiba', - 'Scannell', - 'Gillies', - 'Brame', - 'Schipper', - 'Brune', - 'Stuber', - 'Pesce', - 'Stead', - 'Bushong', - 'Juneau', - 'Mccalla', - 'Feder', - 'Plaisance', - 'Tweed', - 'Hashimoto', - 'Mounce', - 'Diana', - 'Savala', - 'Vanek', - 'Lamson', - 'Dubin', - 'Killebrew', - 'Kan', - 'Nault', - 'Mulford', - 'Salamanca', - 'Linker', - 'Penrose', - 'Kowalewski', - 'Platz', - 'Kogan', - 'Martucci', - 'Gutowski', - 'Mattes', - 'Haigh', - 'Merida', - 'Ashman', - 'Batton', - 'Biondo', - 'Sweigart', - 'Sorg', - 'Barrier', - 'Gatling', - 'Geib', - 'Henrich', - 'Dabrowski', - 'Vara', - 'Weikel', - 'Jarosz', - 'Mummert', - 'Uriarte', - 'Fifield', - 'Locker', - 'Merlo', - 'Lasater', - 'Ripple', - 'Hopwood', - 'Sherrell', - 'Ruark', - 'Litz', - 'Kinkade', - 'Simkins', - 'Grandy', - 'Lemasters', - 'Wehr', - 'Jinks', - 'Alas', - 'Bale', - 'Stimpson', - 'Glickman', - 'Hage', - 'Seabrook', - 'Stirling', - 'Rozell', - 'Woodburn', - 'Braaten', - 'Sugg', - 'Linde', - 'Castille', - 'Grewal', - 'Blackwelder', - 'Hover', - 'Spurling', - 'Mckellar', - 'Muench', - 'Bovee', - 'Amado', - 'Yau', - 'Harger', - 'Lederer', - 'Seda', - 'Doney', - 'Kimes', - 'Western', - 'Foret', - 'Luera', - 'Warnke', - 'Bussard', - 'Cartier', - 'Andreasen', - 'Lagasse', - 'Topper', - 'Nyman', - 'Hallberg', - 'Whisman', - 'Cremeans', - 'Dewar', - 'Garrow', - 'Odaniel', - 'Stabler', - 'Bourg', - 'Appling', - 'Dahlstrom', - 'Fujimoto', - 'Prudhomme', - 'Gum', - 'Nau', - 'Hiers', - 'Rockett', - 'Sobczak', - 'Traub', - 'Bevis', - 'Tilghman', - 'Plasencia', - 'Sison', - 'Blau', - 'Abbate', - 'Sisler', - 'Rudder', - 'Trotman', - 'Brust', - 'Lederman', - 'Frahm', - 'Fredette', - 'Parise', - 'Urso', - 'Amann', - 'Kaul', - 'Woolery', - 'Thielen', - 'Symonds', - 'Marcy', - 'Wiltshire', - 'Sustaita', - 'Botkin', - 'Kernan', - 'Doolin', - 'Babineaux', - 'Greenspan', - 'Delacerda', - 'Kinnard', - 'Twitty', - 'Augustus', - 'Corriveau', - 'Stults', - 'Toman', - 'Sklar', - 'Leber', - 'Considine', - 'Ohearn', - 'Deforest', - 'Mcmann', - 'Farquhar', - 'Ferrel', - 'Bickley', - 'Manno', - 'Vreeland', - 'Berthiaume', - 'Mcentee', - 'Summerfield', - 'Woodrow', - 'Reynaga', - 'Soltero', - 'Tomko', - 'Jarboe', - 'Allmon', - 'Duplessis', - 'Sydnor', - 'Diallo', - 'Cogar', - 'Mandeville', - 'Shimizu', - 'Aubuchon', - 'Gabbert', - 'Ashlock', - 'Macri', - 'Weng', - 'Walser', - 'Teng', - 'Bailon', - 'Steeves', - 'Perillo', - 'Quattlebaum', - 'Knipp', - 'Delavega', - 'Kirtley', - 'Bramble', - 'Sublett', - 'Borchert', - 'Doria', - 'Session', - 'Merced', - 'Lundstrom', - 'Bluhm', - 'Cortinas', - 'Proper', - 'Sieber', - 'Mccay', - 'Wilford', - 'Asberry', - 'Muldrow', - 'Berning', - 'Hemenway', - 'Millman', - 'Ewers', - 'Timko', - 'Reding', - 'Sayer', - 'Pickel', - 'Cogburn', - 'Chappel', - 'Custodio', - 'Reichel', - 'Robeson', - 'Waid', - 'Wagler', - 'Sappington', - 'Bart', - 'Zazueta', - 'Najar', - 'Marko', - 'Nally', - 'States', - 'Bellard', - 'Marciano', - 'Killough', - 'Cosper', - 'Sangster', - 'Heinze', - 'Bortz', - 'Matamoros', - 'Nuckols', - 'Townsley', - 'Bak', - 'Ralls', - 'Ferrin', - 'Villela', - 'Siegrist', - 'Arora', - 'Collinsworth', - 'Masten', - 'Deer', - 'Balog', - 'Buchman', - 'Scaggs', - 'Holeman', - 'Lefkowitz', - 'Santora', - 'Funke', - 'Redfield', - 'Douthit', - 'Marciniak', - 'Twitchell', - 'Sheahan', - 'Dai', - 'Demuth', - 'Ganz', - 'Bruckner', - 'Wier', - 'Alamo', - 'Aultman', - 'Chubb', - 'Branco', - 'Courter', - 'Vivian', - 'Guin', - 'Witten', - 'Glen', - 'Hyer', - 'Crowson', - 'Arendt', - 'Cipolla', - 'Prochaska', - 'Schober', - 'Harte', - 'Arciniega', - 'Beier', - 'Middlebrook', - 'Dennard', - 'Vantassel', - 'Weekes', - 'Penley', - 'Lozier', - 'Lamberson', - 'Broomfield', - 'Nygaard', - 'Pascale', - 'Hyden', - 'Mundell', - 'Kamara', - 'Ehlert', - 'Mangus', - 'Bornstein', - 'Benedetti', - 'Erikson', - 'Quint', - 'Westman', - 'Basler', - 'Smoak', - 'Leavell', - 'Kerber', - 'Kopec', - 'Emrick', - 'Mattice', - 'Render', - 'Mccree', - 'Feldmann', - 'Cutright', - 'Randell', - 'Drucker', - 'Gilmour', - 'Marconi', - 'Stripling', - 'Mucha', - 'Shipe', - 'Chalk', - 'Martone', - 'Lema', - 'Ricardo', - 'Cobian', - 'Laufer', - 'Mistretta', - 'Shortt', - 'Menzel', - 'Wickline', - 'Oddo', - 'Chai', - 'Rabideau', - 'Stogner', - 'Mckie', - 'Luongo', - 'Trieu', - 'Breshears', - 'Sturdevant', - 'Abernethy', - 'Rohan', - 'Bonnette', - 'Steffes', - 'Straka', - 'Lawhon', - 'Shawver', - 'Guilford', - 'Wiltz', - 'Digregorio', - 'Warburton', - 'Fleshman', - 'Kerstetter', - 'Byram', - 'Obannon', - 'Dalessio', - 'Gatti', - 'Kalb', - 'Boris', - 'Graver', - 'Parkins', - 'Kollar', - 'Crothers', - 'Patin', - 'Cutshall', - 'Fern', - 'Derosier', - 'Goodrum', - 'Kaelin', - 'Baynes', - 'Beesley', - 'Macintyre', - 'Butters', - 'Kinsman', - 'Huffer', - 'Eslinger', - 'Prunty', - 'Boehmer', - 'Nusbaum', - 'Gouveia', - 'Mire', - 'Mccary', - 'Mikell', - 'Petrovich', - 'Melillo', - 'Kennelly', - 'Howley', - 'Merwin', - 'Cotner', - 'Kanter', - 'Sahagun', - 'Bodden', - 'Mcconville', - 'Leddy', - 'Auten', - 'Downie', - 'Armistead', - 'Goudy', - 'Gerhard', - 'Theiss', - 'Lauria', - 'Tuthill', - 'Ammon', - 'Ikeda', - 'Schultheis', - 'Zhong', - 'Pearcy', - 'Vass', - 'Essary', - 'Wendland', - 'Zehr', - 'Hartigan', - 'Ugalde', - 'Mossman', - 'Hartwick', - 'Joaquin', - 'Andreas', - 'Bartee', - 'Gajewski', - 'Gallaway', - 'Comerford', - 'Lieber', - 'Wireman', - 'Damm', - 'Yousif', - 'Kosinski', - 'Kelm', - 'Durrant', - 'Derouen', - 'Bonk', - 'Rubalcaba', - 'Opperman', - 'Decamp', - 'Fairfield', - 'Pauls', - 'Dicicco', - 'Northup', - 'Woerner', - 'Stegman', - 'Ritch', - 'Bedoya', - 'Jeanpierre', - 'Rioux', - 'Strohl', - 'Herrell', - 'Simonton', - 'Carriere', - 'Pridemore', - 'Karam', - 'Marple', - 'Topp', - 'Heiden', - 'Leibowitz', - 'Morabito', - 'Junker', - 'Calixto', - 'Hardt', - 'Silverio', - 'Swords', - 'Rickey', - 'Roussel', - 'Earles', - 'Bastien', - 'Defilippo', - 'Bigley', - 'Mosteller', - 'Issa', - 'Prout', - 'Grossi', - 'Bartos', - 'Lipman', - 'Colegrove', - 'Stpeter', - 'Vanfleet', - 'Fordyce', - 'Risher', - 'Royston', - 'Shoulders', - 'Mendel', - 'Statler', - 'Dantonio', - 'Inglis', - 'Fogleman', - 'Loveday', - 'Straus', - 'Luft', - 'Dam', - 'Chewning', - 'Winkel', - 'Bousquet', - 'Eckhart', - 'Dillinger', - 'Locascio', - 'Shellenberger', - 'Duerr', - 'Alcocer', - 'Licht', - 'Gingras', - 'Grassi', - 'Gately', - 'Padula', - 'Brien', - 'Nimmo', - 'Nell', - 'Bondurant', - 'Hughley', - 'Schalk', - 'Cabrales', - 'Heinemann', - 'Meunier', - 'Maddock', - 'Noone', - 'Brackin', - 'Dunnigan', - 'Sargeant', - 'Kinchen', - 'Veras', - 'Gile', - 'Bacchus', - 'Ang', - 'Cowgill', - 'Currey', - 'Garlick', - 'Manus', - 'Ballance', - 'Robitaille', - 'Begin', - 'Mijares', - 'Keogh', - 'Wicklund', - 'Mccurley', - 'Truett', - 'Pullin', - 'Alkire', - 'Loughran', - 'Mort', - 'Tatman', - 'Wanamaker', - 'Haralson', - 'Harrah', - 'Stucker', - 'Reda', - 'Pascal', - 'Holter', - 'Solares', - 'Bruck', - 'Mah', - 'Didomenico', - 'Korth', - 'Virgil', - 'Nishimura', - 'Vacca', - 'Stenberg', - 'Tomczak', - 'Sayler', - 'Chasse', - 'Blazer', - 'Sleeper', - 'Doiron', - 'Nunnery', - 'Ortman', - 'Maag', - 'Cali', - 'Ferrera', - 'Hotaling', - 'Festa', - 'Murr', - 'Sterrett', - 'Cuthbert', - 'Clayborn', - 'Pendergraft', - 'Yoakum', - 'Baily', - 'Overbey', - 'Warne', - 'Hokanson', - 'Tafolla', - 'Puglisi', - 'Wooster', - 'Nassar', - 'Lesniak', - 'Noack', - 'Beres', - 'Liberatore', - 'Guyette', - 'Duffin', - 'Ishmael', - 'Dolezal', - 'Larimer', - 'Musso', - 'Borman', - 'Deemer', - 'Hobgood', - 'Triggs', - 'Mau', - 'Wainscott', - 'Seth', - 'Hodnett', - 'Mckeehan', - 'Toon', - 'Evens', - 'Drost', - 'Roehl', - 'Trapani', - 'Bains', - 'Modica', - 'Arcos', - 'Knopf', - 'Salvo', - 'Garlock', - 'Lounsbury', - 'Hennen', - 'Drescher', - 'Morgenstern', - 'Studebaker', - 'Nordin', - 'Madore', - 'Joslyn', - 'Brousseau', - 'Addy', - 'Audette', - 'Santibanez', - 'Sauers', - 'Engelman', - 'Mauney', - 'Arechiga', - 'Eckel', - 'Jerry', - 'Pernell', - 'Sedlacek', - 'Mcnary', - 'Loewen', - 'Eyler', - 'Feather', - 'Mckinnie', - 'Bowersox', - 'Laclair', - 'Melby', - 'Thoman', - 'Hose', - 'Carmon', - 'Bartram', - 'Berggren', - 'Rogge', - 'Seto', - 'Court', - 'Deskins', - 'Barcus', - 'Putt', - 'Minick', - 'Durgin', - 'Hockman', - 'Keltner', - 'Legaspi', - 'Wallach', - 'Ranney', - 'Borger', - 'Wakeman', - 'Schoolcraft', - 'Souther', - 'Villani', - 'Sauder', - 'Chupp', - 'Slover', - 'Faul', - 'Degroat', - 'Hakim', - 'Brucker', - 'Moylan', - 'Castilleja', - 'Whetzel', - 'Eanes', - 'Brouwer', - 'Okelley', - 'Crimmins', - 'Bargas', - 'Jo', - 'Clover', - 'Adan', - 'Domingues', - 'Yelton', - 'Lobdell', - 'Mattis', - 'Escudero', - 'Pentecost', - 'Riser', - 'Lorentz', - 'Neace', - 'Caplinger', - 'Lipe', - 'Satterlee', - 'Labarbera', - 'Cullison', - 'Goggin', - 'Coke', - 'Keo', - 'Buckmaster', - 'Holtzclaw', - 'Lustig', - 'Ellinger', - 'Lollar', - 'Cork', - 'Mccrae', - 'Hilario', - 'Yawn', - 'Arnette', - 'Yuhas', - 'Wardle', - 'Pixley', - 'Leflore', - 'Fluker', - 'Krier', - 'Wind', - 'Ditto', - 'Rorie', - 'Ensminger', - 'Hunsucker', - 'Levenson', - 'Millington', - 'Gorsuch', - 'Willems', - 'Fredricks', - 'Agarwal', - 'Lariviere', - 'Don', - 'Chery', - 'Pfeil', - 'Wurtz', - 'Remillard', - 'Cozad', - 'Hodgkins', - 'Cohan', - 'Nurse', - 'Espana', - 'Giguere', - 'Hoskin', - 'Pettaway', - 'Keifer', - 'Yandell', - 'Frandsen', - 'Nawrocki', - 'Vila', - 'Pouliot', - 'Boulanger', - 'Pruden', - 'Strauch', - 'Lua', - 'Rohn', - 'Greig', - 'Lightsey', - 'Etheredge', - 'Hara', - 'Ensign', - 'Ruckman', - 'Senecal', - 'Sedgwick', - 'Maciejewski', - 'Morningstar', - 'Creswell', - 'Britten', - 'Godley', - 'Laubach', - 'Schwenk', - 'Hayhurst', - 'Cammarata', - 'Paxson', - 'Mcmurtry', - 'Marasco', - 'Weatherby', - 'Fales', - 'Fondren', - 'Deherrera', - 'Gaydos', - 'Defranco', - 'Bjorklund', - 'Silberman', - 'Maxon', - 'Rockey', - 'Brass', - 'Marcoux', - 'Marquette', - 'Marcello', - 'Veit', - 'Debose', - 'Cloninger', - 'Puccio', - 'Greenman', - 'Bross', - 'Lile', - 'Behan', - 'Plumlee', - 'Hampson', - 'Steverson', - 'Wininger', - 'Mcmullan', - 'Jude', - 'Sharif', - 'Rothermel', - 'Becher', - 'Keithley', - 'Gargano', - 'Morillo', - 'Dumond', - 'Johannsen', - 'Baney', - 'Lipton', - 'Railey', - 'Clowers', - 'Rotondo', - 'Simeone', - 'Hatt', - 'Schexnayder', - 'Snoddy', - 'Gelinas', - 'Mendelson', - 'Matherly', - 'Klock', - 'Clubb', - 'Dunkley', - 'Rosenzweig', - 'Chuang', - 'Gines', - 'Galasso', - 'Helland', - 'Rohrbaugh', - 'Avilez', - 'Czajkowski', - 'Olsson', - 'Lumsden', - 'Birt', - 'Ortego', - 'Acuff', - 'Yetter', - 'Tichenor', - 'Mork', - 'Skillman', - 'Row', - 'Lollis', - 'Wolk', - 'Demott', - 'Lazenby', - 'Bellew', - 'Brickner', - 'Ragusa', - 'Stice', - 'Herlihy', - 'Guillermo', - 'Estabrook', - 'Montijo', - 'Jenner', - 'Rayfield', - 'Donlon', - 'Greenhalgh', - 'Alberti', - 'Rix', - 'Holthaus', - 'Mistry', - 'Ruzicka', - 'Sievert', - 'Koopman', - 'Kalish', - 'Kehl', - 'Ponte', - 'Varnell', - 'Guss', - 'Kovac', - 'Hosmer', - 'Scrivner', - 'Tomblin', - 'Villafuerte', - 'Branscum', - 'Nitz', - 'Reider', - 'Gaunt', - 'Richerson', - 'Hemmer', - 'Vinyard', - 'Barrie', - 'Manalo', - 'Flynt', - 'Cadle', - 'Hau', - 'Uy', - 'Manfredi', - 'Deeter', - 'Resto', - 'Carnell', - 'Drane', - 'Cusumano', - 'Fein', - 'Schneck', - 'Stucky', - 'Heid', - 'Bruggeman', - 'Schweiger', - 'Vanetten', - 'Munsey', - 'Kiker', - 'Whittier', - 'Seeman', - 'Zerbe', - 'Hillyer', - 'Burkhead', - 'Gafford', - 'Gephart', - 'Braman', - 'Plott', - 'Henriques', - 'Coppock', - 'Mcandrews', - 'Valtierra', - 'Dileo', - 'Stiner', - 'Mikel', - 'Owensby', - 'Gupton', - 'Scurlock', - 'Gittens', - 'Degnan', - 'Guillaume', - 'Helmuth', - 'Nolin', - 'Mair', - 'Bergeson', - 'Paik', - 'Kinne', - 'Goodloe', - 'Nakagawa', - 'Raposo', - 'Defreitas', - 'Korb', - 'Hinkel', - 'Magers', - 'Althoff', - 'Rafael', - 'Akhtar', - 'Cashion', - 'Mcquillan', - 'Patricio', - 'Sweeny', - 'Meaux', - 'Tyre', - 'Demeo', - 'Trivedi', - 'Goodfellow', - 'Dunleavy', - 'Middaugh', - 'Barbato', - 'Pasco', - 'Harland', - 'Shorts', - 'Mowrey', - 'Dempster', - 'Knuckles', - 'Luebke', - 'Petrella', - 'Retana', - 'Licea', - 'Rundle', - 'Cape', - 'Lou', - 'Mcconkey', - 'Leeman', - 'Cabe', - 'Timothy', - 'Crochet', - 'Fulgham', - 'Glasco', - 'Backes', - 'Konopka', - 'Mcquaid', - 'Schley', - 'Abrahams', - 'Dahlin', - 'Iversen', - 'Chico', - 'Huffaker', - 'Modlin', - 'Laduke', - 'Marquart', - 'Motz', - 'Keech', - 'Louviere', - 'Como', - 'Fye', - 'Brightwell', - 'Yamashita', - 'Desrochers', - 'Richer', - 'Bourke', - 'Broadhead', - 'Pink', - 'Okamoto', - 'Chicas', - 'Vanatta', - 'Shick', - 'Furst', - 'Layfield', - 'Mcewan', - 'Baumgart', - 'Kappel', - 'Kucharski', - 'Quam', - 'Taub', - 'Houghtaling', - 'Sundquist', - 'Monks', - 'Wake', - 'Quiros', - 'Pursell', - 'Johansson', - 'Talkington', - 'Bast', - 'Stimson', - 'Hakes', - 'Loe', - 'Caggiano', - 'Schaper', - 'Chandra', - 'Tuma', - 'Arledge', - 'Romain', - 'Hornick', - 'Bridgman', - 'Livingstone', - 'Potvin', - 'Sparling', - 'Hause', - 'Trosclair', - 'Pless', - 'Szeto', - 'Clontz', - 'Lauber', - 'Detrick', - 'Dominique', - 'Mosser', - 'Degraff', - 'Liner', - 'Fleet', - 'Czerwinski', - 'Kopf', - 'Kovar', - 'Sheedy', - 'Zaremba', - 'Mina', - 'Sweeten', - 'Ou', - 'Musto', - 'Hennig', - 'Bangs', - 'Pasternak', - 'Berrier', - 'Smidt', - 'Brayton', - 'Claytor', - 'Ellerbe', - 'Reiman', - 'Larimore', - 'Ratzlaff', - 'Mudge', - 'Ni', - 'Spillers', - 'Cuomo', - 'Gerke', - 'Polizzi', - 'Harmer', - 'Apperson', - 'Regis', - 'Ugarte', - 'Paull', - 'Lagrange', - 'Dinwiddie', - 'Becton', - 'Gadsden', - 'Conforti', - 'Desoto', - 'Orme', - 'Filer', - 'Viers', - 'Lares', - 'Stair', - 'Hipps', - 'Kaneshiro', - 'Ladson', - 'Altizer', - 'Montejano', - 'Scalzo', - 'Sowder', - 'Ebeling', - 'Faucher', - 'Dicken', - 'Sartor', - 'Mcnerney', - 'Stage', - 'Mika', - 'Hice', - 'Grinstead', - 'Bartsch', - 'Mccumber', - 'Lenahan', - 'Liska', - 'Tietz', - 'Gauna', - 'Janda', - 'Bellis', - 'Shew', - 'Kelton', - 'Doby', - 'Golson', - 'Plaster', - 'Gonsales', - 'Krone', - 'Lape', - 'Lowrie', - 'Polly', - 'Gerardi', - 'Lamoreaux', - 'Bhatti', - 'Kimsey', - 'Buhl', - 'Arvin', - 'Gillian', - 'Benbow', - 'Roesler', - 'Stlaurent', - 'Canon', - 'Swihart', - 'Corea', - 'Petitt', - 'Spates', - 'Nappi', - 'Sebring', - 'Smelser', - 'Eckenrode', - 'Palos', - 'Disanto', - 'Tabares', - 'Okane', - 'Easterly', - 'Dendy', - 'Whigham', - 'Bednarz', - 'Wedge', - 'Edelen', - 'Stiff', - 'Borjas', - 'Obando', - 'Mcspadden', - 'Breed', - 'Dismuke', - 'Jarmon', - 'Serpa', - 'Lucky', - 'Cournoyer', - 'Hedberg', - 'Martine', - 'Michell', - 'Wittig', - 'Clodfelter', - 'Davids', - 'Gattis', - 'Kull', - 'Mascorro', - 'Schad', - 'Rine', - 'Bradburn', - 'Marie', - 'Czech', - 'Sunderman', - 'Wickersham', - 'Toohey', - 'Capozzi', - 'Poplin', - 'Markland', - 'Brosnan', - 'Fetterman', - 'Heiss', - 'Haglund', - 'Jourdan', - 'Turnipseed', - 'Tiernan', - 'Horrocks', - 'Barnhardt', - 'Sing', - 'Belford', - 'Baumgarten', - 'Klee', - 'Degeorge', - 'Caulder', - 'Gladstone', - 'Dancer', - 'Satchell', - 'Vento', - 'Larock', - 'Kimberly', - 'Hunn', - 'Harvin', - 'Krahn', - 'Ogorman', - 'Storch', - 'Coomes', - 'Bevilacqua', - 'Crotts', - 'Schillinger', - 'Morelock', - 'Hayworth', - 'Avis', - 'Cranmer', - 'Getchell', - 'Tena', - 'Buzzell', - 'Widman', - 'Barter', - 'Lafayette', - 'Asencio', - 'Embree', - 'Krell', - 'Siders', - 'Fuselier', - 'Whitby', - 'Elsner', - 'Pando', - 'Surface', - 'Rolf', - 'Highland', - 'Bufford', - 'Scheidt', - 'Defrancesco', - 'Fellers', - 'Carrol', - 'Germano', - 'Licon', - 'Hilty', - 'Ringo', - 'Dowler', - 'Glowacki', - 'Slabaugh', - 'Tomasello', - 'Messing', - 'Lavalle', - 'Milo', - 'Frerichs', - 'Plotkin', - 'Ziolkowski', - 'Gentle', - 'Knobloch', - 'Larochelle', - 'Duell', - 'Hurdle', - 'Speller', - 'Ceasar', - 'Vinci', - 'Mosquera', - 'Wyse', - 'Towler', - 'Ayoub', - 'Gullickson', - 'Spade', - 'Forshee', - 'Cliff', - 'Gholson', - 'Reichenbach', - 'Lockman', - 'Morones', - 'Storie', - 'Bissett', - 'Janney', - 'Durocher', - 'Fentress', - 'Troiano', - 'Boes', - 'Rouleau', - 'Rall', - 'Sultan', - 'Braggs', - 'Bethke', - 'Schacht', - 'Straley', - 'Mcfalls', - 'Fahy', - 'Winegar', - 'Gorecki', - 'Rudnick', - 'Wigginton', - 'Dedrick', - 'Sthilaire', - 'Lovette', - 'Hanneman', - 'Loch', - 'Moores', - 'Polen', - 'Anchondo', - 'Rosato', - 'Tindell', - 'Hunsicker', - 'Penna', - 'Privette', - 'Gayton', - 'Sliger', - 'Wink', - 'Brummer', - 'Crown', - 'Sommerville', - 'Mastrangelo', - 'Latimore', - 'Merlino', - 'Thoreson', - 'Kleiner', - 'Able', - 'Boose', - 'Loyola', - 'Jimenes', - 'Lapham', - 'Srinivasan', - 'Hammers', - 'Mo', - 'Evert', - 'Vanslyke', - 'Caywood', - 'Gremillion', - 'Rauscher', - 'Eckhoff', - 'Dearth', - 'Sinha', - 'Becerril', - 'Tuten', - 'Greenwalt', - 'Curlee', - 'Burgan', - 'Feagin', - 'Gallman', - 'Germann', - 'Swensen', - 'Vanallen', - 'Bissonnette', - 'Stoudt', - 'Handler', - 'Tanguay', - 'Lovins', - 'Smotherman', - 'Cutts', - 'Herod', - 'Maclin', - 'Arcuri', - 'Hackbarth', - 'Breazeale', - 'Rainville', - 'Crick', - 'Macintosh', - 'Bloss', - 'Fridley', - 'Stefanski', - 'Beauvais', - 'Koop', - 'Andes', - 'Blomberg', - 'Vallee', - 'Lanigan', - 'Blouin', - 'Rochon', - 'Dorazio', - 'Drouin', - 'Lamonica', - 'Wilbourn', - 'Spraggins', - 'Rieder', - 'Shugart', - 'Chacko', - 'Rutan', - 'Nutting', - 'Lawley', - 'Landy', - 'January', - 'Blowers', - 'Handel', - 'Doman', - 'Swiney', - 'Ettinger', - 'Jellison', - 'Veilleux', - 'Wiens', - 'Raimondi', - 'Spink', - 'Emond', - 'Yale', - 'Rachel', - 'Alldredge', - 'Lach', - 'Morlan', - 'Wayland', - 'Colquitt', - 'Gabrielson', - 'Mccarver', - 'Frances', - 'Granville', - 'Costigan', - 'Preuss', - 'Lentini', - 'Vansant', - 'Mosca', - 'Connally', - 'Frei', - 'Laplant', - 'Lago', - 'Leiter', - 'Trumbull', - 'Shaeffer', - 'Gongora', - 'Coady', - 'Fyffe', - 'Mance', - 'Worcester', - 'Zehner', - 'Bodie', - 'Burnes', - 'Pompey', - 'Teitelbaum', - 'Beaupre', - 'Visconti', - 'Mumma', - 'Markiewicz', - 'Piscitelli', - 'Moak', - 'Bourland', - 'Pennock', - 'Hannum', - 'Robichaux', - 'Folks', - 'Coppage', - 'Heffron', - 'Mullet', - 'Kimberlin', - 'Breneman', - 'Blandford', - 'Matthias', - 'Engebretson', - 'Roessler', - 'Allee', - 'Parkman', - 'Barge', - 'Ren', - 'Backstrom', - 'Bullen', - 'Lampman', - 'Loesch', - 'Echavarria', - 'Haman', - 'Cortina', - 'Elms', - 'Gordan', - 'Pabst', - 'Snelson', - 'Vanarsdale', - 'Pecora', - 'Rabago', - 'Enger', - 'Senger', - 'Dewees', - 'Semple', - 'Howey', - 'Westlund', - 'Daw', - 'Hagemann', - 'Mcpeek', - 'Vanderhoof', - 'Ohler', - 'Bohm', - 'Mazzone', - 'Arnott', - 'Bouton', - 'Fackler', - 'Giunta', - 'Stagner', - 'Tavera', - 'Poorman', - 'Buch', - 'Mangano', - 'Bonar', - 'Gerson', - 'Ranger', - 'Mccullar', - 'Wunder', - 'Bade', - 'Armand', - 'Chalfant', - 'Lichtenstein', - 'Turco', - 'Degraw', - 'Few', - 'Haigler', - 'Lis', - 'Bittinger', - 'Morrone', - 'Hodgdon', - 'Wittenberg', - 'Imes', - 'Dreiling', - 'Landwehr', - 'Maly', - 'Warlick', - 'Terpstra', - 'Bolte', - 'Stiller', - 'Stmartin', - 'Pankratz', - 'Albee', - 'Victory', - 'Lezama', - 'Brecht', - 'Monarrez', - 'Thurlow', - 'Laskey', - 'Bothwell', - 'Candler', - 'Esh', - 'Kalman', - 'Samano', - 'Yohe', - 'Regnier', - 'Leite', - 'Ballantyne', - 'Dan', - 'Fikes', - 'Cendejas', - 'Mikula', - 'Fairman', - 'Dragon', - 'Manzella', - 'Renninger', - 'Leaman', - 'Godbey', - 'Current', - 'Mirabal', - 'Boerner', - 'Depaz', - 'Birge', - 'Westberry', - 'Severin', - 'Weddington', - 'Longenecker', - 'Mccreery', - 'Lebel', - 'Nader', - 'Gan', - 'Auguste', - 'Colonna', - 'Paramo', - 'Minyard', - 'Duley', - 'Beil', - 'Salters', - 'Brindley', - 'Simmers', - 'Lumpkins', - 'Crisman', - 'Raulerson', - 'Lanz', - 'Deroche', - 'Kemmerer', - 'Bogner', - 'Mahn', - 'Willer', - 'Gunnels', - 'Warford', - 'Reason', - 'Scherr', - 'Digirolamo', - 'Hallowell', - 'Wilcoxson', - 'Gaillard', - 'Deshields', - 'Hively', - 'Sakai', - 'Creason', - 'Jaber', - 'Lapinski', - 'Bolivar', - 'Millwood', - 'Shumpert', - 'Fujii', - 'Plemmons', - 'Lamere', - 'Cleghorn', - 'Mccaw', - 'Seavey', - 'Zwick', - 'Hosler', - 'Lepley', - 'Marden', - 'Cornwall', - 'Gauger', - 'Hofmeister', - 'Bugarin', - 'Loose', - 'Guardiola', - 'Hertzog', - 'Bigger', - 'Heineman', - 'Retzlaff', - 'Rizzuto', - 'Flannigan', - 'Rathburn', - 'Moulder', - 'Town', - 'Gautier', - 'Hamid', - 'Torrance', - 'Walthall', - 'Windom', - 'Kleckner', - 'Kirwan', - 'Gasaway', - 'Pinkard', - 'Concannon', - 'Mcquiston', - 'Yow', - 'Eshleman', - 'Riggleman', - 'Foulk', - 'Bolles', - 'Craine', - 'Hinnant', - 'Gholston', - 'Lebo', - 'Torkelson', - 'Mancia', - 'Canale', - 'Celestin', - 'Neubert', - 'Schmaltz', - 'Highfill', - 'Fisch', - 'Matte', - 'Hoefer', - 'Flippin', - 'Mclin', - 'Mikkelson', - 'Gump', - 'Kilroy', - 'Ensor', - 'Klosterman', - 'Ruppel', - 'Steffey', - 'Sauve', - 'Cessna', - 'Apgar', - 'Jacobus', - 'Pettyjohn', - 'Northington', - 'Smithey', - 'Moro', - 'Dossett', - 'Mccroskey', - 'Yelverton', - 'Mascarenas', - 'Hebb', - 'Quinteros', - 'Giang', - 'Pontius', - 'Sipple', - 'Atkin', - 'Howington', - 'Hiebert', - 'Lingerfelt', - 'Schueler', - 'Sailer', - 'Smits', - 'Keeter', - 'Macrae', - 'Mease', - 'Shortridge', - 'Scates', - 'Amstutz', - 'Kuebler', - 'Cambron', - 'Eaker', - 'Finlayson', - 'Bookout', - 'Mullett', - 'Bank', - 'Schlenker', - 'Morlock', - 'Haskett', - 'Dade', - 'Gallucci', - 'Lahey', - 'Ryerson', - 'Crownover', - 'Banfield', - 'Mcclay', - 'Diggins', - 'Conerly', - 'Primus', - 'Syverson', - 'Prindle', - 'Blasingame', - 'Deford', - 'Garnes', - 'Hoisington', - 'Glasper', - 'Lorusso', - 'Hesson', - 'Youssef', - 'Threlkeld', - 'Talmadge', - 'Winfree', - 'Heacock', - 'Rawlinson', - 'Burse', - 'Diederich', - 'Niemiec', - 'Norby', - 'Bauder', - 'Scranton', - 'Prentiss', - 'Towles', - 'Henton', - 'Purifoy', - 'Pinzon', - 'Edler', - 'Ragin', - 'Albarado', - 'Cuadra', - 'Hoadley', - 'Devita', - 'Pavon', - 'Alday', - 'Goulding', - 'Millis', - 'Dalley', - 'Kolodziej', - 'Kropf', - 'Kuiper', - 'Crespin', - 'Xavier', - 'Sailor', - 'Lagrone', - 'Boehme', - 'Tidd', - 'Wilmore', - 'Ziemer', - 'Ropp', - 'Kettler', - 'Pilon', - 'Miron', - 'Salsbury', - 'Job', - 'Sensenig', - 'Cayton', - 'Nanney', - 'Rasch', - 'Silvestre', - 'Ladue', - 'Dampier', - 'Ackermann', - 'Friedel', - 'Kleiman', - 'Geronimo', - 'Ezzell', - 'Duclos', - 'Moor', - 'Neuhaus', - 'Lan', - 'Allender', - 'Tedeschi', - 'Langton', - 'Dawley', - 'Kearse', - 'Godina', - 'Guernsey', - 'Kober', - 'Bisbee', - 'Lamphere', - 'Kinman', - 'Wesner', - 'Malo', - 'Stroupe', - 'Millette', - 'Yeoman', - 'Baig', - 'Kirchoff', - 'Tsao', - 'Cristobal', - 'Mucci', - 'Pair', - 'Barefield', - 'Dewolf', - 'Fitzmaurice', - 'Mcaleer', - 'Natal', - 'Bara', - 'Macey', - 'Mclennan', - 'Fabre', - 'Vieyra', - 'Magno', - 'Eyre', - 'Chatterton', - 'Gilland', - 'Hurlbut', - 'Umberger', - 'Roloff', - 'Brambila', - 'Mazzeo', - 'Letson', - 'Norsworthy', - 'Bier', - 'Gioia', - 'Kapoor', - 'Marlatt', - 'Flippo', - 'Houde', - 'Baughn', - 'Blackledge', - 'Fly', - 'Dinkel', - 'Rathbone', - 'Bober', - 'Boydston', - 'Ferdinand', - 'Coletti', - 'Cuenca', - 'Deters', - 'Blagg', - 'Timmins', - 'Boyden', - 'Meads', - 'Narcisse', - 'Saelee', - 'Cosner', - 'Strawser', - 'Amico', - 'Dowdle', - 'Golub', - 'Silverberg', - 'Riles', - 'Balk', - 'Buhr', - 'Feltman', - 'Stickel', - 'Zapien', - 'Cargile', - 'Kulik', - 'Lazzaro', - 'Oberle', - 'Wickstrom', - 'Maeda', - 'Cockrum', - 'Boulton', - 'Sandford', - 'Culbert', - 'Dula', - 'Ament', - 'Chunn', - 'Owenby', - 'Wasilewski', - 'Wichman', - 'Oestreich', - 'Klos', - 'Orchard', - 'Hogge', - 'Presson', - 'Cordon', - 'Gans', - 'Leonardi', - 'Manjarrez', - 'Olander', - 'Drennen', - 'Wirt', - 'Tiger', - 'Dolce', - 'Hagstrom', - 'Hirsh', - 'Tally', - 'Crumbley', - 'Mcgreevy', - 'Amidon', - 'Olague', - 'Lint', - 'Poche', - 'Lipford', - 'Engen', - 'Mcelfresh', - 'Cuneo', - 'Krumm', - 'Haak', - 'Arocho', - 'Longworth', - 'Seamon', - 'Bronner', - 'Swartzentruber', - 'Chand', - 'Wilhoit', - 'Chapel', - 'Hitchens', - 'Brzezinski', - 'Heidenreich', - 'Ellenberger', - 'Gamblin', - 'Ormond', - 'Burchard', - 'Dibella', - 'Nicoll', - 'Simcox', - 'Strohm', - 'Dittmar', - 'Wycoff', - 'Grays', - 'Spero', - 'Vess', - 'Picone', - 'Greening', - 'Maynes', - 'Knauss', - 'Wojtowicz', - 'Chaput', - 'Soliman', - 'Ponton', - 'Carlino', - 'Kestner', - 'Kelch', - 'Dimauro', - 'Iorio', - 'Parenteau', - 'Pesina', - 'Clauson', - 'Stigall', - 'Keels', - 'Waldrep', - 'Wix', - 'Draeger', - 'Ertel', - 'Starner', - 'Charest', - 'Simoneaux', - 'Ivanov', - 'Thor', - 'Gravel', - 'Trottier', - 'Clendenin', - 'Kromer', - 'Benda', - 'Touchet', - 'Hornbuckle', - 'Avent', - 'Dombroski', - 'Friedland', - 'Radabaugh', - 'Vesely', - 'Wike', - 'Lax', - 'Messersmith', - 'Deoliveira', - 'Brey', - 'Cogdill', - 'Overturf', - 'Sova', - 'Pero', - 'Beaird', - 'Cevallos', - 'Defalco', - 'Taormina', - 'Thornberry', - 'Westervelt', - 'Macaulay', - 'Hajek', - 'Brugger', - 'Leff', - 'Ketterer', - 'Ono', - 'Mullenix', - 'Frison', - 'Gullo', - 'Calhoon', - 'Summey', - 'Hockaday', - 'Dimatteo', - 'Agan', - 'Patenaude', - 'Mary', - 'Tanis', - 'Obert', - 'Elton', - 'Randles', - 'Migliore', - 'Schmalz', - 'Vanvalkenburg', - 'Quinto', - 'Palmquist', - 'Hoops', - 'Naples', - 'Orear', - 'Eberhard', - 'Fitzgibbons', - 'Adkinson', - 'Gerace', - 'Elie', - 'Dressel', - 'Silber', - 'Otey', - 'Hsiao', - 'Kreutzer', - 'Tutor', - 'Roundy', - 'Haddox', - 'Bridgers', - 'Leto', - 'Daniell', - 'Pollitt', - 'Freda', - 'Mraz', - 'Engelbrecht', - 'Ariza', - 'Grand', - 'Pavone', - 'Everts', - 'Benes', - 'Reamer', - 'Faucett', - 'Eatmon', - 'Raymundo', - 'Zaman', - 'Devitt', - 'Master', - 'Carron', - 'Hoffner', - 'Sciortino', - 'Stringham', - 'Bookman', - 'Westberg', - 'Spahn', - 'Hise', - 'Waterbury', - 'Buckwalter', - 'Hug', - 'Overly', - 'Dingus', - 'Ince', - 'Haar', - 'Shain', - 'Heaps', - 'Oppenheimer', - 'Miyamoto', - 'Schreier', - 'Martello', - 'Atteberry', - 'Folger', - 'Macke', - 'Pal', - 'Lucchesi', - 'Osterhout', - 'Liriano', - 'Legge', - 'Barra', - 'Crumb', - 'Gwyn', - 'Forst', - 'Axelrod', - 'Samayoa', - 'Edgell', - 'Purkey', - 'Lannon', - 'Branam', - 'Yeo', - 'Hatmaker', - 'Borum', - 'Villagrana', - 'Lawing', - 'Bark', - 'Muirhead', - 'Eckles', - 'Weight', - 'Surles', - 'Cullinan', - 'Lagos', - 'Naber', - 'Sloat', - 'Foos', - 'Vine', - 'Milliner', - 'Reliford', - 'Dahlquist', - 'Gibney', - 'Moroney', - 'Stecker', - 'Bella', - 'Brickhouse', - 'Canela', - 'Kula', - 'Tartaglia', - 'Siewert', - 'Hitch', - 'Brickman', - 'Cheeseman', - 'Carollo', - 'Geissler', - 'Jiron', - 'Cossey', - 'Sroka', - 'Border', - 'Brownlow', - 'Ellenburg', - 'Cella', - 'Brinton', - 'Scurry', - 'Behrendt', - 'Carstensen', - 'Schendel', - 'Bodner', - 'Eddleman', - 'Stec', - 'Capasso', - 'Leu', - 'Kennett', - 'Ruane', - 'Critchfield', - 'Carbonell', - 'Mitcham', - 'Troncoso', - 'Mckeen', - 'Cammack', - 'Broach', - 'Culbreath', - 'Callejas', - 'Wurst', - 'Brookman', - 'Guerrier', - 'Seese', - 'Kitzmiller', - 'Graybeal', - 'Yardley', - 'Cheever', - 'Virgin', - 'Brimmer', - 'Swoboda', - 'Pandya', - 'Canton', - 'Magnus', - 'Draughn', - 'Dilts', - 'Tauber', - 'Vandegrift', - 'Rene', - 'Cousineau', - 'Joo', - 'Pimental', - 'Carpentier', - 'Eager', - 'Cumberland', - 'Eastridge', - 'Moberly', - 'Erhardt', - 'Meldrum', - 'Degennaro', - 'Desanto', - 'Manahan', - 'Gowdy', - 'Popham', - 'Mee', - 'Kinslow', - 'Harned', - 'Cartee', - 'Raiford', - 'Henrichs', - 'Maffei', - 'Seamans', - 'Heckel', - 'Toll', - 'Milian', - 'Mabrey', - 'Dall', - 'Lanford', - 'Carew', - 'Bascom', - 'Christofferson', - 'Hadfield', - 'Ferber', - 'Mestas', - 'Leith', - 'Abston', - 'Cuddy', - 'Svendsen', - 'Cowling', - 'Segars', - 'Nalls', - 'Hofstetter', - 'Badgley', - 'Mccaffery', - 'Burner', - 'Laymon', - 'Pinion', - 'Schooler', - 'Brun', - 'Aldaco', - 'Savarese', - 'Gravelle', - 'Belvin', - 'Brekke', - 'Dekker', - 'Ellefson', - 'Lurie', - 'Cassity', - 'Epperly', - 'Genova', - 'Dehn', - 'Fargo', - 'Vanderford', - 'Sine', - 'Horrell', - 'Napoleon', - 'Kamm', - 'Riel', - 'Gerena', - 'Check', - 'Devane', - 'Grissett', - 'Brendel', - 'Weyant', - 'Basurto', - 'Coppinger', - 'Grosse', - 'Saeed', - 'Lunceford', - 'Washam', - 'Benard', - 'Eastham', - 'Holleran', - 'Kiesel', - 'Risch', - 'Mccullen', - 'Vizcaino', - 'Fullen', - 'Westbrooks', - 'Babich', - 'Mauch', - 'Hensler', - 'Bryner', - 'Phillippi', - 'Santistevan', - 'Jalbert', - 'Vanorden', - 'Brantner', - 'Mcgrail', - 'Rustin', - 'Lebaron', - 'Genao', - 'Quast', - 'Hamburg', - 'Mensah', - 'Heckler', - 'Popa', - 'Mantooth', - 'Hargreaves', - 'Jury', - 'Seiber', - 'Calton', - 'Lafreniere', - 'Starbuck', - 'Gow', - 'Veazey', - 'Kneeland', - 'Woodberry', - 'Vallone', - 'Sutcliffe', - 'Loh', - 'Wiltse', - 'Choudhury', - 'Rollo', - 'Bjerke', - 'Huffstetler', - 'Ogren', - 'Legere', - 'Wilmer', - 'Conboy', - 'Pressler', - 'Hon', - 'Monger', - 'Devos', - 'Houtz', - 'Shurtleff', - 'Sedlak', - 'Carolan', - 'Luc', - 'Immel', - 'Guizar', - 'Kron', - 'Lusby', - 'Whitsett', - 'Pryce', - 'Mengel', - 'Youngberg', - 'Kluge', - 'Thrush', - 'Wilsey', - 'Santee', - 'Braham', - 'Palmeri', - 'Cousino', - 'Willits', - 'Gram', - 'Dearmond', - 'Fonville', - 'Sabatini', - 'Nehring', - 'Henne', - 'Prager', - 'Mederos', - 'Schuldt', - 'Weisz', - 'Mccart', - 'Warriner', - 'Bartelt', - 'Dimond', - 'Mccubbin', - 'Say', - 'Mickel', - 'Bracamonte', - 'Volkman', - 'Brindle', - 'Bitter', - 'Dickie', - 'Inge', - 'Brinegar', - 'Lerman', - 'Bohan', - 'Rondon', - 'Dilbeck', - 'Rumbaugh', - 'Simard', - 'Berke', - 'Ealey', - 'Knauer', - 'Michalek', - 'Smolinski', - 'Wurster', - 'Zullo', - 'Nott', - 'Claar', - 'Mayor', - 'Moir', - 'Hubbert', - 'Hankerson', - 'Mok', - 'Simko', - 'Mumm', - 'Sheely', - 'Abramowitz', - 'Pusateri', - 'Boomer', - 'Chappelle', - 'Demery', - 'Coniglio', - 'Asay', - 'Nova', - 'Biel', - 'Delancey', - 'Tocco', - 'Tant', - 'Melin', - 'Lacoste', - 'Derrico', - 'Stacks', - 'Watley', - 'Stoneking', - 'Westrick', - 'Pons', - 'Malm', - 'Parekh', - 'Loop', - 'Kitt', - 'Crisostomo', - 'Ecklund', - 'Tollison', - 'Dziedzic', - 'Pillsbury', - 'Baumer', - 'Matsuda', - 'Jeon', - 'Foye', - 'Peltz', - 'Candela', - 'Levey', - 'Organ', - 'Hathorn', - 'Galeano', - 'Nies', - 'Cabezas', - 'Barras', - 'Pier', - 'Truss', - 'Leist', - 'Lheureux', - 'Nakano', - 'Ladwig', - 'Grunwald', - 'Centers', - 'Sherrard', - 'Morais', - 'Juhl', - 'Ivers', - 'Dunfee', - 'Jolliff', - 'Breeze', - 'Tapper', - 'Goodridge', - 'Kelliher', - 'Finck', - 'Roose', - 'Gauvin', - 'Coil', - 'Pounders', - 'Lobb', - 'Stalcup', - 'Swanner', - 'Boivin', - 'Neer', - 'Laxton', - 'Pai', - 'Postma', - 'Janus', - 'Didier', - 'Engleman', - 'League', - 'Fray', - 'Aguillon', - 'Richins', - 'Tolar', - 'Criner', - 'Rowlands', - 'Verdi', - 'Utt', - 'Winders', - 'Turbeville', - 'Rada', - 'Mcnichols', - 'Boddy', - 'Binford', - 'Amey', - 'Schultze', - 'Sontag', - 'Saleem', - 'Przybylski', - 'Vanderlinden', - 'Vanfossen', - 'Longacre', - 'Heasley', - 'Southwell', - 'Decesare', - 'Munch', - 'Minix', - 'Hymes', - 'Klopp', - 'Militello', - 'Schuessler', - 'Velazco', - 'Jurek', - 'Claycomb', - 'Diemer', - 'Roser', - 'Huse', - 'Perkinson', - 'Musa', - 'Leavy', - 'Seidman', - 'Vroman', - 'Stalter', - 'Grieve', - 'Aron', - 'Purdie', - 'Dusek', - 'Rago', - 'Shepler', - 'Leopard', - 'Araya', - 'Rutt', - 'Voth', - 'Hittle', - 'Husain', - 'Gratton', - 'Seigler', - 'Coppedge', - 'Nicastro', - 'Fitzgibbon', - 'Sosebee', - 'Tank', - 'Troche', - 'Delph', - 'Ryland', - 'Mazzella', - 'Rai', - 'Strecker', - 'Epp', - 'Clower', - 'Porche', - 'Gelman', - 'Herrman', - 'Balser', - 'Tosh', - 'Bonn', - 'Cerrato', - 'Varley', - 'Dingess', - 'Goodspeed', - 'Boller', - 'Heimann', - 'Gottfried', - 'Super', - 'Falzone', - 'Bizzell', - 'Litwin', - 'Ji', - 'Rogowski', - 'Tindle', - 'Hoye', - 'Balfour', - 'Focht', - 'Manz', - 'Stender', - 'Sutterfield', - 'Bayes', - 'Mullings', - 'Dockter', - 'Figueiredo', - 'Kepner', - 'Posadas', - 'Nettleton', - 'Ruder', - 'Younce', - 'Flanary', - 'Scotti', - 'Bayliss', - 'Tandy', - 'Henrickson', - 'Volker', - 'Letts', - 'Joines', - 'Fewell', - 'Wherry', - 'Stelzer', - 'Stever', - 'Viator', - 'Catt', - 'Jeffords', - 'Guerriero', - 'Milby', - 'Jozwiak', - 'Slawson', - 'Portwood', - 'Billie', - 'Borunda', - 'Chinchilla', - 'Papadopoulos', - 'Lohse', - 'Mantz', - 'Gabriele', - 'Hosford', - 'Kohut', - 'Tardiff', - 'Puma', - 'Bodin', - 'Hodgins', - 'Boon', - 'Golightly', - 'Bogert', - 'Abdi', - 'Wigfall', - 'Fleischmann', - 'Nease', - 'Rayborn', - 'Zigler', - 'Reimann', - 'Malagon', - 'Puls', - 'Grogg', - 'Drinkwater', - 'Dacus', - 'Mcfee', - 'Domino', - 'Harjo', - 'Pascarella', - 'Spengler', - 'Copple', - 'Rollings', - 'Brew', - 'Brabham', - 'Nordquist', - 'Emig', - 'Riggio', - 'Sanson', - 'Gerardo', - 'Pereda', - 'Renken', - 'Stickley', - 'Milliron', - 'Rolling', - 'Hollie', - 'Biondi', - 'Fluharty', - 'Magyar', - 'Balsamo', - 'Imler', - 'Hanlin', - 'Dycus', - 'Kirkley', - 'Wimberley', - 'Finan', - 'Kulkarni', - 'Morreale', - 'Briner', - 'Pelzer', - 'Bouie', - 'Fenstermaker', - 'Gimenez', - 'Labella', - 'Scherrer', - 'Holzman', - 'Winer', - 'Wrigley', - 'Leighty', - 'Liptak', - 'Chamness', - 'Franko', - 'Arwood', - 'Tiner', - 'Schoenberger', - 'Gear', - 'Hereford', - 'Slezak', - 'Longfellow', - 'Cull', - 'Brashears', - 'Clear', - 'Zielke', - 'Arden', - 'Bonneau', - 'Muck', - 'Tarvin', - 'Beran', - 'Coulombe', - 'Toothman', - 'Ghosh', - 'Mcguirk', - 'Pinero', - 'Ruan', - 'Gartman', - 'Peed', - 'Cassano', - 'Forcier', - 'Haque', - 'Veatch', - 'Fodor', - 'Wetherington', - 'Barrette', - 'Bottorff', - 'Holmstrom', - 'Honda', - 'Kopecky', - 'Loaiza', - 'Castelan', - 'Haydon', - 'Lamotte', - 'Mutchler', - 'Mahmoud', - 'Gleaton', - 'Rebollar', - 'Moctezuma', - 'Tannehill', - 'Bernardino', - 'Walrath', - 'Adcox', - 'Heidt', - 'Rakowski', - 'Soza', - 'Limas', - 'Wysong', - 'Mannix', - 'Pattillo', - 'Corner', - 'Kuang', - 'Loflin', - 'Ledger', - 'Ivery', - 'Likens', - 'Mctaggart', - 'Hartin', - 'Prange', - 'Stenzel', - 'Shadle', - 'Karn', - 'Duplantis', - 'Garibaldi', - 'Batty', - 'Goulart', - 'Ranck', - 'Beekman', - 'Nicolosi', - 'Arizmendi', - 'Donoho', - 'Drewry', - 'Lenihan', - 'Spatz', - 'Wible', - 'Dimmick', - 'Stelter', - 'Seyler', - 'Stringfield', - 'Bonaparte', - 'Dematteo', - 'Petrey', - 'Bellino', - 'Cavaliere', - 'Thaler', - 'Heiner', - 'Lillis', - 'Hammes', - 'Rainbolt', - 'Hillyard', - 'Farnum', - 'Overmyer', - 'Replogle', - 'Sclafani', - 'Audet', - 'Santa', - 'Hollen', - 'Lineberger', - 'Bonnet', - 'Caples', - 'Dahlen', - 'Ruggieri', - 'Keppler', - 'Ryman', - 'Copas', - 'Lyda', - 'Pusey', - 'Bostrom', - 'Patnode', - 'Richeson', - 'Hamil', - 'Wyss', - 'Mcadam', - 'Dennett', - 'Lever', - 'Drinkard', - 'Ohl', - 'Restivo', - 'Vyas', - 'Moyle', - 'Blauvelt', - 'Gregson', - 'Scull', - 'Verret', - 'Stines', - 'Forsman', - 'Gehman', - 'Watrous', - 'Gunnell', - 'Choice', - 'Castaldo', - 'Pietrzak', - 'Goodsell', - 'Klima', - 'Stratman', - 'Foutz', - 'Massingill', - 'Huneycutt', - 'Zellmer', - 'Tefft', - 'Hamblen', - 'Baggs', - 'Mcgarity', - 'Alfieri', - 'Stetler', - 'Hershman', - 'Fuerst', - 'Granda', - 'Villafane', - 'Stocking', - 'Laguerre', - 'Salvato', - 'Mcniel', - 'Trim', - 'Goldston', - 'Tannenbaum', - 'Laforge', - 'Hawker', - 'Innis', - 'Rasheed', - 'Marbury', - 'Jules', - 'Harpster', - 'Hruska', - 'Mancillas', - 'Ruck', - 'Schloss', - 'Shy', - 'Leming', - 'Eich', - 'Allain', - 'Premo', - 'Goodner', - 'Karlin', - 'Natoli', - 'Sinn', - 'Althouse', - 'Bodiford', - 'Krishnan', - 'Snedeker', - 'Weigle', - 'Blohm', - 'Renwick', - 'Menzies', - 'Stonebraker', - 'Brunetti', - 'Crompton', - 'Hucks', - 'Maharaj', - 'Bangert', - 'Hepp', - 'Kammer', - 'Sutliff', - 'Doyon', - 'Hutsell', - 'Cumbie', - 'Dibiase', - 'Linke', - 'Sapienza', - 'Sprayberry', - 'Sundstrom', - 'Vanbeek', - 'Ewart', - 'Erlandson', - 'Knutsen', - 'Nicolai', - 'Oros', - 'Almquist', - 'Tedrow', - 'Diebold', - 'Bellman', - 'Sherrer', - 'Ehret', - 'Ota', - 'Seman', - 'Folse', - 'Amy', - 'Mcateer', - 'Steinhauer', - 'Vannatta', - 'Holle', - 'Carreras', - 'Anger', - 'Clinkscales', - 'Castiglione', - 'Zakrzewski', - 'Principe', - 'Artman', - 'Waiters', - 'Tarbox', - 'Sippel', - 'Belz', - 'Joachim', - 'Pipkins', - 'Peterkin', - 'Abalos', - 'Flock', - 'Brochu', - 'Tobler', - 'Mckinnis', - 'Gatson', - 'Cronan', - 'Manthey', - 'Oberholtzer', - 'Schiltz', - 'Skowronski', - 'Matute', - 'Castonguay', - 'Bechard', - 'Drees', - 'Carte', - 'Baysinger', - 'Kees', - 'Steve', - 'Ratchford', - 'Clopton', - 'Heimbach', - 'Selig', - 'Peavey', - 'Sidney', - 'Hilliker', - 'Oehler', - 'Essig', - 'Ownby', - 'Huling', - 'Aylward', - 'Matzke', - 'Mikkelsen', - 'Vandam', - 'Rodden', - 'Plunk', - 'Mcdonell', - 'Buechler', - 'Dahm', - 'Tarlton', - 'Funches', - 'Alvidrez', - 'Padua', - 'Pingel', - 'Cid', - 'Mcburney', - 'Brunton', - 'Dwight', - 'Bucio', - 'Schiffer', - 'Dyal', - 'Cyphers', - 'Gildea', - 'Wengerd', - 'Lappin', - 'Longwell', - 'Basil', - 'Acklin', - 'Cancino', - 'Kalina', - 'Tynan', - 'Raasch', - 'Fleener', - 'Dunmire', - 'Gent', - 'Cruickshank', - 'Baltimore', - 'Shum', - 'Vanpatten', - 'Costilla', - 'Grimshaw', - 'Loar', - 'Royse', - 'Amon', - 'Amendola', - 'Mcgonagle', - 'Alm', - 'Hausmann', - 'Heitzman', - 'Mailloux', - 'Brault', - 'Capra', - 'Levis', - 'Barillas', - 'Quandt', - 'Fedele', - 'Chittenden', - 'Cheesman', - 'Wildes', - 'Bolan', - 'Metoyer', - 'Ciccarelli', - 'Melara', - 'Gano', - 'Janowski', - 'Magoon', - 'Kuster', - 'Ofarrell', - 'Joplin', - 'Cannella', - 'Middendorf', - 'Putz', - 'Saephan', - 'Sieg', - 'Lainez', - 'Roten', - 'Buras', - 'Nock', - 'Manke', - 'Hymel', - 'Devaughn', - 'Braverman', - 'Fleisher', - 'Persson', - 'Sandidge', - 'Corsi', - 'Torok', - 'Steinhoff', - 'Corby', - 'Shorey', - 'Wooton', - 'Estell', - 'Bolander', - 'Vivar', - 'Cuesta', - 'Renick', - 'Isler', - 'Caprio', - 'Crissman', - 'Wann', - 'Matchett', - 'Calahan', - 'Escareno', - 'Liguori', - 'Helt', - 'Boner', - 'Luper', - 'Hoppes', - 'Ingold', - 'Gilleland', - 'Saathoff', - 'Szczepanski', - 'Yockey', - 'Veith', - 'Wasser', - 'Denniston', - 'Fretwell', - 'Goetsch', - 'Havel', - 'Banach', - 'Schaal', - 'Nisbet', - 'Depaul', - 'Escalona', - 'Gammons', - 'Schmelzer', - 'Wehrle', - 'Guglielmo', - 'Oberlander', - 'Wolski', - 'Dimick', - 'Rebello', - 'Braunstein', - 'Vanderveen', - 'Saini', - 'Meiners', - 'Metheny', - 'Schommer', - 'Kissell', - 'Burgoyne', - 'Walmsley', - 'Parmley', - 'Arthurs', - 'Worsley', - 'Hulme', - 'Campisi', - 'Parvin', - 'Ogawa', - 'Coder', - 'Gardener', - 'Taplin', - 'Nuzzo', - 'Linthicum', - 'Rosenstein', - 'Simoneau', - 'Preble', - 'Chae', - 'Nealon', - 'Stonecipher', - 'Medders', - 'Bencomo', - 'Durazo', - 'Scotto', - 'Klem', - 'Corman', - 'Byard', - 'Evan', - 'Dengler', - 'Kohls', - 'Seidler', - 'Clute', - 'Nebel', - 'Hohl', - 'Younker', - 'Parkerson', - 'Pullins', - 'Sweeting', - 'Wiersma', - 'Callanan', - 'Lisk', - 'Fassett', - 'Alloway', - 'Lafever', - 'Ollis', - 'Gracey', - 'Tune', - 'Ester', - 'Weingarten', - 'Swigart', - 'Frew', - 'Conkle', - 'Mendelsohn', - 'Belliveau', - 'Bacher', - 'Coto', - 'Ro', - 'Lipson', - 'Standard', - 'Hoerner', - 'Moldenhauer', - 'Trivette', - 'Colligan', - 'Cacho', - 'Emrich', - 'Condit', - 'Styer', - 'Paramore', - 'Cheramie', - 'Sprenger', - 'Kreps', - 'Curd', - 'Josephs', - 'Bruch', - 'Villano', - 'Banh', - 'Kennison', - 'Hilson', - 'Gathers', - 'Weinman', - 'Brickley', - 'Jetton', - 'Munford', - 'Charboneau', - 'Dittrich', - 'Boysen', - 'Newbury', - 'Hayner', - 'Pfau', - 'Wegman', - 'Eure', - 'Heinrichs', - 'Kresge', - 'Klepper', - 'Yohn', - 'Bergan', - 'Spells', - 'Reisman', - 'Schiffman', - 'Napoles', - 'Banegas', - 'Landman', - 'Hallenbeck', - 'Sever', - 'Hole', - 'Bown', - 'Barnaby', - 'Junior', - 'Deloatch', - 'Secrist', - 'Steigerwald', - 'Kallas', - 'Littell', - 'Clinger', - 'Rehman', - 'Cothern', - 'Class', - 'Sabino', - 'Mckain', - 'Werts', - 'Asmus', - 'Fierros', - 'Heffelfinger', - 'Henthorn', - 'Weirich', - 'Ashbrook', - 'Alber', - 'Calles', - 'Bragdon', - 'Gerow', - 'Hanger', - 'Machen', - 'Patt', - 'Harada', - 'Parmelee', - 'Decaro', - 'Sons', - 'Tindal', - 'Lubbers', - 'Ferland', - 'Bruni', - 'Boyes', - 'Danis', - 'Tigner', - 'Anzaldua', - 'Gaxiola', - 'Iacono', - 'Lizama', - 'Forbis', - 'Mcguffin', - 'Greenhill', - 'Baity', - 'Welcome', - 'Lauzon', - 'Nicodemus', - 'Rabin', - 'Teegarden', - 'Yunker', - 'Salim', - 'Dews', - 'Schueller', - 'Stogsdill', - 'Minch', - 'Ellett', - 'Villafana', - 'Shan', - 'Boler', - 'Kast', - 'Shrout', - 'Taff', - 'Willcox', - 'Kahan', - 'Gerth', - 'Sabella', - 'Procopio', - 'Vedder', - 'Heeter', - 'Banes', - 'Alaimo', - 'Raza', - 'Starkweather', - 'Mutter', - 'Manners', - 'Bohanan', - 'Virden', - 'Booze', - 'Wimbush', - 'Eickhoff', - 'Hankinson', - 'Swilley', - 'Killinger', - 'Labar', - 'Tallant', - 'Rosin', - 'Hillhouse', - 'Labarre', - 'Ryans', - 'Heintzelman', - 'Cottone', - 'Bickerstaff', - 'Westley', - 'Rotter', - 'Hey', - 'Dinapoli', - 'Lohmann', - 'Reetz', - 'Vences', - 'Mckiernan', - 'Thornsberry', - 'Hofman', - 'Murrieta', - 'Vanwormer', - 'Sen', - 'Pinheiro', - 'Jaco', - 'Maner', - 'Crosley', - 'Rogalski', - 'Hollandsworth', - 'Hinze', - 'Seawright', - 'Brosius', - 'Keehn', - 'Sweetman', - 'Vicknair', - 'Casler', - 'Hagopian', - 'Westhoff', - 'Lipari', - 'Poll', - 'Lintz', - 'Rosinski', - 'Henrie', - 'Crystal', - 'Wroten', - 'Perla', - 'Zawacki', - 'Mckillip', - 'Dorantes', - 'Wallick', - 'Hoots', - 'Witty', - 'Granata', - 'Janicki', - 'Petroff', - 'Emert', - 'Raskin', - 'Picou', - 'Caple', - 'Mcelyea', - 'Blackmer', - 'Busbee', - 'Pettengill', - 'Newberg', - 'Nickle', - 'Hedman', - 'Flavin', - 'Forgione', - 'Wachtel', - 'Meader', - 'Nale', - 'Westby', - 'Pulaski', - 'Schupp', - 'Troutt', - 'Fishburn', - 'Laprade', - 'Dealba', - 'Waymire', - 'Stiefel', - 'Carner', - 'Fallin', - 'Belin', - 'Anand', - 'Lesh', - 'Okada', - 'Whipkey', - 'Mang', - 'Harvill', - 'Caver', - 'Moskal', - 'Schaible', - 'Vandeusen', - 'Boyko', - 'Matteo', - 'Crisler', - 'Capehart', - 'Heide', - 'Holdsworth', - 'Mcdonagh', - 'Burlison', - 'Beshears', - 'Gills', - 'Cowger', - 'Gendreau', - 'Goering', - 'Hewes', - 'Whelchel', - 'Kier', - 'Tramel', - 'Mcsherry', - 'Morita', - 'Cissell', - 'Knaus', - 'Vangilder', - 'Karsten', - 'Linscott', - 'Ratner', - 'Catoe', - 'Scriven', - 'Gerstner', - 'Brobst', - 'Normandin', - 'Piasecki', - 'Tamura', - 'Balboa', - 'Nathanson', - 'Huizenga', - 'Renard', - 'Deshazo', - 'Ethier', - 'Fabiano', - 'Quisenberry', - 'Mcbryde', - 'Palencia', - 'Scaglione', - 'Friese', - 'Laughter', - 'Houchins', - 'Loman', - 'Garden', - 'Cromartie', - 'Borgman', - 'Hoffpauir', - 'Choquette', - 'Jarrard', - 'Fernald', - 'Barranco', - 'Levering', - 'Ansell', - 'Perl', - 'Caudell', - 'Ewen', - 'Ohanlon', - 'Swofford', - 'Reasoner', - 'Grout', - 'Rising', - 'Buttram', - 'Vandenheuvel', - 'Imel', - 'Rearick', - 'Harn', - 'Sorrels', - 'Biggins', - 'Renda', - 'Norden', - 'Matula', - 'Walch', - 'Broad', - 'Stokley', - 'Gully', - 'Barrientes', - 'Chilcote', - 'Freel', - 'Lage', - 'Farner', - 'Rubel', - 'Demko', - 'Shao', - 'Cupples', - 'Holderman', - 'Dunnam', - 'Hughs', - 'Foskey', - 'Darst', - 'Greenblatt', - 'Shiner', - 'Brasfield', - 'Simeon', - 'Maser', - 'Lacayo', - 'Priestley', - 'Pleasants', - 'Howse', - 'Iyer', - 'Perreira', - 'Baillargeon', - 'Revilla', - 'Yarger', - 'Gries', - 'Sheeley', - 'Prim', - 'Picazo', - 'Heinlein', - 'Merola', - 'Malhotra', - 'Wein', - 'Mchone', - 'Valliere', - 'Minner', - 'Blumer', - 'Hasse', - 'Kuester', - 'Landi', - 'Suits', - 'Primeaux', - 'Jarnagin', - 'Galle', - 'Greenlaw', - 'Qiu', - 'Lamarche', - 'Acheson', - 'Gothard', - 'Mendivil', - 'Bombard', - 'Mcquillen', - 'Munden', - 'Herzberg', - 'Ros', - 'Umstead', - 'Levins', - 'Pellegrin', - 'Castagna', - 'Alvord', - 'Huckins', - 'Wagnon', - 'Plemons', - 'Dolin', - 'Garica', - 'Lyttle', - 'Bazile', - 'Astudillo', - 'Gover', - 'Galati', - 'Seager', - 'Girardi', - 'Freels', - 'Bramblett', - 'Brancato', - 'Reppert', - 'Saetern', - 'Puig', - 'Prettyman', - 'Chagnon', - 'Heavner', - 'Schlichting', - 'Saladino', - 'Stall', - 'Loiselle', - 'Sedano', - 'Panos', - 'Heilig', - 'Ridgley', - 'Basilio', - 'Rapoza', - 'Furrow', - 'Oliveras', - 'Cordray', - 'Strausbaugh', - 'Culhane', - 'Iraheta', - 'Lamantia', - 'Shires', - 'Wilding', - 'Obanion', - 'Easterwood', - 'Hearns', - 'Manske', - 'Spiess', - 'Eckley', - 'Wootton', - 'Enochs', - 'Cheatwood', - 'Woodfin', - 'Akridge', - 'Mattocks', - 'Mcdougle', - 'Legette', - 'Neher', - 'Rhoton', - 'Vartanian', - 'Dunkel', - 'Wehmeyer', - 'Foutch', - 'Dille', - 'Halle', - 'Lowden', - 'Olesen', - 'Chace', - 'Hasbrouck', - 'Lesage', - 'Pappalardo', - 'Shinkle', - 'Ishii', - 'Peralez', - 'Gabler', - 'Fichter', - 'Mcnicholas', - 'Moshier', - 'Barbeau', - 'Bossert', - 'Trivett', - 'Bamford', - 'Lauterbach', - 'Gossman', - 'Epling', - 'Welk', - 'Daub', - 'Squier', - 'Dicus', - 'Siller', - 'Romaine', - 'Meriwether', - 'Bordner', - 'Baden', - 'Hagins', - 'Sica', - 'Mullane', - 'Jurgensen', - 'Tien', - 'Gertz', - 'Touchstone', - 'Bones', - 'Kimmons', - 'Prisco', - 'Kaser', - 'Drysdale', - 'Jelks', - 'Cerrone', - 'Wolfenbarger', - 'Deckert', - 'Ganley', - 'Fleeman', - 'Cubbage', - 'Woodie', - 'Schwan', - 'Siefert', - 'Rizvi', - 'Heier', - 'Khanna', - 'Leet', - 'Gratz', - 'Mullan', - 'Moorefield', - 'Fishback', - 'Whittenburg', - 'Casson', - 'Statham', - 'Red', - 'Coldiron', - 'Keplinger', - 'Reichman', - 'Brier', - 'Vavra', - 'Housman', - 'Kitson', - 'Fekete', - 'Rotella', - 'Onofre', - 'Orvis', - 'Beutler', - 'Cadwallader', - 'Gabor', - 'Emmanuel', - 'Moretz', - 'Suniga', - 'Mcmath', - 'Kinlaw', - 'Beringer', - 'Gaudreau', - 'Lirette', - 'Drye', - 'Oubre', - 'Gardella', - 'Reigle', - 'Zubia', - 'Mccardle', - 'Ambler', - 'Lucius', - 'Fizer', - 'Hilley', - 'Fischbach', - 'Borelli', - 'Gies', - 'Barks', - 'Sheard', - 'Hammontree', - 'Hogle', - 'Fagg', - 'Buitron', - 'Eiler', - 'Grandstaff', - 'Hank', - 'Wark', - 'Decoteau', - 'Depina', - 'Clabaugh', - 'Desiderio', - 'Kuchta', - 'Trang', - 'Abril', - 'Smathers', - 'Kaspar', - 'Melia', - 'Sandman', - 'Maltese', - 'Mccasland', - 'Rayl', - 'Meche', - 'Wiggin', - 'Saint', - 'Dorner', - 'Columbus', - 'Boatner', - 'Fresquez', - 'Sykora', - 'Shriner', - 'Drumheller', - 'Mahony', - 'Redinger', - 'Radloff', - 'Mitts', - 'Casperson', - 'Gammill', - 'Moraga', - 'Baratta', - 'Tow', - 'Ocon', - 'Cruce', - 'Bohannan', - 'Hurtt', - 'Mose', - 'Caines', - 'Heisey', - 'Pitcock', - 'Swiderski', - 'Shu', - 'Buda', - 'Whidden', - 'Busick', - 'Simas', - 'Croley', - 'Morrisey', - 'Saulsberry', - 'Crudup', - 'Bongiorno', - 'Beem', - 'Bunner', - 'Rosemond', - 'Freire', - 'Casado', - 'Merideth', - 'Selden', - 'Lamarre', - 'Fullwood', - 'Hartig', - 'Kerlin', - 'Lebowitz', - 'Kibbe', - 'Fannon', - 'Hotz', - 'Yerkes', - 'Re', - 'Waddington', - 'Akbar', - 'Baek', - 'Closson', - 'Miers', - 'Bonomo', - 'Wetherbee', - 'Taranto', - 'Henslee', - 'Bartle', - 'Hilger', - 'Asaro', - 'Mahr', - 'Strozier', - 'Agudelo', - 'Kulick', - 'Skoglund', - 'Yamasaki', - 'Schlemmer', - 'Hefley', - 'Waxman', - 'Radley', - 'Sanderlin', - 'Arispe', - 'Galang', - 'Morejon', - 'Stich', - 'Cesario', - 'Silvis', - 'Gurganus', - 'Shofner', - 'Funderburg', - 'Reddish', - 'Rybak', - 'Dingler', - 'Mankin', - 'Renna', - 'Alban', - 'Mckittrick', - 'Lippman', - 'Brenton', - 'Liebman', - 'Santillo', - 'Crigger', - 'Riney', - 'Mccraney', - 'Kluck', - 'Sosnowski', - 'Anspach', - 'Bourdon', - 'Modi', - 'Heer', - 'Mastroianni', - 'Musial', - 'Whiteaker', - 'Summa', - 'Herber', - 'Roselli', - 'Orris', - 'Bert', - 'Dedmon', - 'Kelson', - 'Paone', - 'Barstow', - 'Gerst', - 'Bettinger', - 'Castner', - 'Penman', - 'Broaddus', - 'Ohman', - 'Villalon', - 'Carwile', - 'Fluellen', - 'Ort', - 'Bommarito', - 'Shuff', - 'Cannata', - 'Westgate', - 'Bien', - 'Driggs', - 'Maisonet', - 'Costin', - 'Raine', - 'Banton', - 'Buterbaugh', - 'Katzman', - 'Coreas', - 'Rosalez', - 'Gose', - 'Robie', - 'Winburn', - 'Glancy', - 'Hild', - 'Strock', - 'Umanzor', - 'Hoglund', - 'Kesner', - 'Lynam', - 'Swayze', - 'Grizzard', - 'Fettig', - 'Macko', - 'Schrum', - 'Sours', - 'Yonker', - 'Ebanks', - 'Chiodo', - 'Meaney', - 'Paras', - 'Struthers', - 'Sicard', - 'Leveille', - 'Beckstead', - 'Calero', - 'Fuhrmann', - 'Lybarger', - 'Capo', - 'Adolph', - 'Raabe', - 'Gran', - 'Borel', - 'Ary', - 'Charland', - 'Huh', - 'Steinert', - 'Stemple', - 'Groat', - 'Zang', - 'Nath', - 'Ogara', - 'Pecina', - 'Simoes', - 'Breece', - 'Nascimento', - 'Usry', - 'Gain', - 'Brassfield', - 'Lochner', - 'Pietsch', - 'Wechsler', - 'Sum', - 'Teneyck', - 'Pelt', - 'Burnley', - 'Renzi', - 'Mujica', - 'Profitt', - 'Body', - 'Debusk', - 'Robidoux', - 'Pruneda', - 'Pomerantz', - 'Gonyea', - 'Crosier', - 'Currence', - 'Newborn', - 'Tolleson', - 'Conlan', - 'Dunsmore', - 'Tansey', - 'Clinard', - 'Staudt', - 'Oppenheim', - 'Gossard', - 'Osbourne', - 'Gilyard', - 'Lucido', - 'Tonkin', - 'Mitzel', - 'Sola', - 'Palombo', - 'Duane', - 'Mac', - 'Kerry', - 'Stills', - 'Viveiros', - 'Stallman', - 'Moos', - 'Follis', - 'Maris', - 'Hollier', - 'Gundlach', - 'Moler', - 'Schweigert', - 'Chartrand', - 'Finkle', - 'Meese', - 'Nigh', - 'Amundsen', - 'Brocato', - 'Dreier', - 'Glessner', - 'Weibel', - 'Fritch', - 'Retherford', - 'Rahim', - 'Markert', - 'Ronk', - 'Olmeda', - 'Gosney', - 'Keathley', - 'Luby', - 'Harrill', - 'Dinges', - 'Rocheleau', - 'Meisel', - 'Farrer', - 'Lute', - 'Apel', - 'Pincus', - 'Maida', - 'Jimmerson', - 'Baltz', - 'Cuccia', - 'Heenan', - 'Thieme', - 'Zoeller', - 'Larocco', - 'Abdalla', - 'Classen', - 'Hassinger', - 'Filler', - 'Pidgeon', - 'Hanford', - 'Espy', - 'Goodlett', - 'Jone', - 'Ruggeri', - 'Lisi', - 'Spada', - 'Gerrard', - 'Allbritton', - 'Brazelton', - 'Boggan', - 'Dufault', - 'Espejo', - 'Bodkin', - 'Penix', - 'Dockins', - 'Rascoe', - 'Swarthout', - 'Tritt', - 'Gouin', - 'Lamberth', - 'Bourn', - 'Barnhouse', - 'Guzzo', - 'Netherton', - 'Zamarron', - 'Rosenberry', - 'Dahms', - 'Anwar', - 'Whitesides', - 'Tidmore', - 'Longstreet', - 'Claunch', - 'Ehrhart', - 'Hullinger', - 'Xia', - 'Heideman', - 'Nicklas', - 'Prins', - 'Soni', - 'Dominquez', - 'Vogelsang', - 'Pew', - 'Chess', - 'Simmerman', - 'Brunell', - 'Matthes', - 'Kinnison', - 'Cansler', - 'Weekly', - 'Eger', - 'Garabedian', - 'Milliman', - 'Severns', - 'Magnusson', - 'Fossum', - 'Salamon', - 'Vandoren', - 'Gillingham', - 'Charney', - 'Nokes', - 'Lamon', - 'Irick', - 'Okeeffe', - 'Zou', - 'Kott', - 'Quillin', - 'Friar', - 'Drummer', - 'Catchings', - 'Hamada', - 'Scheck', - 'Setser', - 'Gobble', - 'Condra', - 'Bowley', - 'Deschamps', - 'Sylva', - 'Bartolome', - 'Warfel', - 'Veltri', - 'Speers', - 'Butner', - 'Delorme', - 'Giesler', - 'Sonntag', - 'Wetherell', - 'Ohagan', - 'Torbert', - 'Grandberry', - 'Ronning', - 'Howser', - 'Soden', - 'Rasco', - 'Clauss', - 'Beland', - 'Nicola', - 'Justiniano', - 'Varnum', - 'Fergus', - 'Lazcano', - 'Sartori', - 'Carnley', - 'Lucarelli', - 'Bergh', - 'Wellborn', - 'Bow', - 'Longshore', - 'Marcel', - 'Sumlin', - 'Atilano', - 'Dostal', - 'Westendorf', - 'Stiver', - 'Morency', - 'Herrod', - 'Bologna', - 'Valiente', - 'Weinert', - 'Gaertner', - 'Prock', - 'Spangenberg', - 'Tineo', - 'Cosio', - 'Maass', - 'Rist', - 'Oatman', - 'Waguespack', - 'Cardiel', - 'Grate', - 'Behrends', - 'Linger', - 'Pozo', - 'Scoggin', - 'Jenkinson', - 'Ake', - 'Redick', - 'Bonacci', - 'Rivet', - 'Declue', - 'Swing', - 'Chopra', - 'Leib', - 'Wallner', - 'Grimmer', - 'Wilmes', - 'Pirkle', - 'Stanhope', - 'Knop', - 'Culotta', - 'Dipaola', - 'Hipolito', - 'Gerling', - 'Sennett', - 'Fulghum', - 'Grothe', - 'Krout', - 'Onorato', - 'Donis', - 'Winbush', - 'Aoki', - 'Buscher', - 'Jarquin', - 'Lemanski', - 'Mcgrane', - 'Tardif', - 'Segundo', - 'Caba', - 'Sease', - 'Blinn', - 'Losee', - 'Kirschbaum', - 'Baskett', - 'Knights', - 'Goudeau', - 'Grondin', - 'Harting', - 'Szewczyk', - 'Wieder', - 'Conatser', - 'Romanelli', - 'Freshour', - 'Brizendine', - 'Rolen', - 'Guynn', - 'Laforest', - 'Doris', - 'Sandridge', - 'Dublin', - 'Blancas', - 'Duryea', - 'Naik', - 'Paradiso', - 'Scheele', - 'Westra', - 'Hassel', - 'Bertucci', - 'Fansler', - 'Flohr', - 'Solt', - 'Suess', - 'Keiper', - 'Downard', - 'Ivester', - 'Darley', - 'Seales', - 'Kolesar', - 'Overbeck', - 'Subramanian', - 'Panter', - 'Parshall', - 'Stannard', - 'Gravley', - 'Dhaliwal', - 'Shippy', - 'Dolphin', - 'Lepper', - 'Gorby', - 'Delmonte', - 'Piccirillo', - 'Besaw', - 'Alligood', - 'Rhymes', - 'Eisenman', - 'Deveau', - 'Tilden', - 'Girton', - 'Buser', - 'Rentschler', - 'Sopko', - 'Uriostegui', - 'Wasko', - 'Noffsinger', - 'Barkman', - 'Dyck', - 'Ferrero', - 'Kiehl', - 'Leffel', - 'Rybicki', - 'Hedstrom', - 'Bracamontes', - 'Zebrowski', - 'Blundell', - 'Brightman', - 'Hegwood', - 'Beecham', - 'Kolbe', - 'Bucy', - 'Bondi', - 'Borgen', - 'Gibbens', - 'Pullman', - 'Letcher', - 'Ferebee', - 'Kitterman', - 'Seefeldt', - 'Upham', - 'Thiede', - 'Bolster', - 'Bastin', - 'Bondy', - 'Mershon', - 'Nickson', - 'Drozd', - 'Schroyer', - 'Mcmenamin', - 'Reith', - 'Lovin', - 'San', - 'Henegar', - 'Haislip', - 'Barco', - 'Arter', - 'Malecki', - 'Teeple', - 'Walpole', - 'Feil', - 'Neitzel', - 'Ostler', - 'Parmar', - 'Vinton', - 'Jan', - 'Weldy', - 'Etherton', - 'Joya', - 'Saliba', - 'Schnur', - 'Belles', - 'Mcgeorge', - 'Olden', - 'Rarick', - 'Worrall', - 'Degen', - 'Froman', - 'Odowd', - 'Einhorn', - 'Fimbres', - 'Maresca', - 'Rocker', - 'Arend', - 'Biermann', - 'Guimond', - 'Mcgurk', - 'Goll', - 'Santilli', - 'Hadlock', - 'Teer', - 'Dillion', - 'Jorden', - 'Honore', - 'Bromberg', - 'Stoneman', - 'Blossom', - 'Guzik', - 'Stockstill', - 'Wax', - 'Anello', - 'Blasko', - 'Frese', - 'Berthold', - 'Morefield', - 'Baptist', - 'Legault', - 'Bouffard', - 'Bebout', - 'Darnall', - 'Buscemi', - 'Buentello', - 'Scroggs', - 'Gatton', - 'Turnquist', - 'Lucht', - 'Remick', - 'Godlewski', - 'Bradt', - 'Waldorf', - 'Zeringue', - 'Rowen', - 'Mowbray', - 'Parkey', - 'Engram', - 'Mazzarella', - 'Kirkbride', - 'Gridley', - 'Kaster', - 'Lorenzana', - 'Wareham', - 'Star', - 'Marshburn', - 'Everman', - 'Wolfram', - 'Zick', - 'Hyun', - 'Yerger', - 'Baham', - 'Gebhard', - 'Ruf', - 'Suchy', - 'Tieman', - 'Wenz', - 'Schiro', - 'Fout', - 'Abdo', - 'Hayter', - 'Cleaves', - 'Fritsche', - 'Meurer', - 'Riendeau', - 'Ventimiglia', - 'Cervera', - 'Mallow', - 'Allie', - 'Hanscom', - 'Viloria', - 'Dubon', - 'Leeson', - 'Ruffing', - 'Jonson', - 'Fenimore', - 'Gonzaga', - 'Schriver', - 'Traina', - 'Mecca', - 'Lantigua', - 'Baril', - 'Harford', - 'Bartow', - 'Asbell', - 'Rumley', - 'Brogden', - 'Derryberry', - 'Ketner', - 'Dakin', - 'Wass', - 'Fallis', - 'Wada', - 'Studdard', - 'Lecroy', - 'Fetty', - 'Nass', - 'Chute', - 'Parman', - 'Bevans', - 'Headen', - 'Hysell', - 'Merten', - 'Most', - 'Fuss', - 'Schrank', - 'Last', - 'Even', - 'Vaz', - 'Sifford', - 'Streets', - 'Claude', - 'Bronstein', - 'Sherburne', - 'Wadkins', - 'Gascon', - 'Seiter', - 'Steffan', - 'Cardozo', - 'Henricks', - 'Claflin', - 'Etzel', - 'Kulas', - 'Trinkle', - 'Ortegon', - 'Phaneuf', - 'Langworthy', - 'Barb', - 'Mazon', - 'Veney', - 'Redondo', - 'Tieu', - 'Laursen', - 'Nanez', - 'Votaw', - 'Walraven', - 'Abella', - 'Dsouza', - 'Bayley', - 'Townson', - 'Applebaum', - 'Mazzei', - 'Piche', - 'Rivenbark', - 'Urrea', - 'Dolph', - 'Bonifacio', - 'Shehan', - 'Glascock', - 'Verde', - 'Gadberry', - 'Trimm', - 'Dowe', - 'Khang', - 'Mulhall', - 'Selzer', - 'Raub', - 'Ore', - 'Copes', - 'Masuda', - 'Moscoso', - 'Zeitler', - 'Mollica', - 'Iler', - 'Leventhal', - 'Manders', - 'Prue', - 'Fergerson', - 'Brose', - 'Phu', - 'Debellis', - 'Haan', - 'Schoening', - 'Stager', - 'Demos', - 'Rumble', - 'Brunt', - 'Nivens', - 'Manigault', - 'Buendia', - 'Deschenes', - 'Wittmer', - 'Hamon', - 'Hentz', - 'Loud', - 'Oseguera', - 'Rayo', - 'Macfarland', - 'Mimms', - 'Grunewald', - 'Hartness', - 'Wynkoop', - 'Wallingford', - 'Juergens', - 'Meszaros', - 'Riehle', - 'Trego', - 'Neece', - 'Coggin', - 'Burrill', - 'Laurel', - 'Routt', - 'Rodger', - 'Krum', - 'Faulkenberry', - 'Labadie', - 'Hemming', - 'Fulp', - 'Jamal', - 'Deloney', - 'Fells', - 'Bohnert', - 'Kapadia', - 'Guill', - 'Coop', - 'Broadhurst', - 'Mccrimmon', - 'Bonfiglio', - 'Capetillo', - 'Chamorro', - 'Gargiulo', - 'Stoehr', - 'Schlecht', - 'Karlson', - 'Garten', - 'Remer', - 'Mebane', - 'Finnigan', - 'Bourdeau', - 'Espindola', - 'Shukla', - 'Petras', - 'Steinberger', - 'Casner', - 'Carico', - 'Seevers', - 'Westwood', - 'Hosea', - 'Mcphillips', - 'Nygren', - 'Wagaman', - 'Coghlan', - 'Sutherlin', - 'Sellman', - 'Bashore', - 'Mullican', - 'Stoneburner', - 'Montag', - 'Karst', - 'Murch', - 'Puffer', - 'Sabala', - 'Pauli', - 'Odonoghue', - 'Lassen', - 'Mattera', - 'Mcaninch', - 'Portugal', - 'Clingan', - 'Michener', - 'Munsell', - 'Streetman', - 'Harton', - 'Swarts', - 'Honig', - 'Jesus', - 'Rentas', - 'Trosper', - 'Coffield', - 'Burket', - 'Donaghy', - 'Byun', - 'Riess', - 'Mcqueary', - 'Stayton', - 'Ferron', - 'Wedding', - 'Tibbitts', - 'Frisbee', - 'Reinoso', - 'Lama', - 'Allyn', - 'Sheen', - 'Tyra', - 'Golder', - 'Veasey', - 'Schroth', - 'Kukla', - 'Narayan', - 'Vandemark', - 'Horace', - 'Kadlec', - 'Portnoy', - 'Reynosa', - 'Surprenant', - 'Savell', - 'Seagle', - 'Vandervort', - 'Eye', - 'Eccleston', - 'Blaise', - 'Glaspie', - 'Cressman', - 'Lahti', - 'Yocom', - 'Leppert', - 'Brendle', - 'Greenough', - 'Relyea', - 'Marinez', - 'Bouley', - 'Fincham', - 'Highley', - 'Goza', - 'Norrell', - 'Yusuf', - 'Ohm', - 'Thakkar', - 'Cosenza', - 'Efird', - 'Heger', - 'Dysart', - 'Mango', - 'Fitchett', - 'Kring', - 'Paolucci', - 'Menges', - 'Layden', - 'Mccleery', - 'Benko', - 'Sandor', - 'Blakney', - 'Zanders', - 'Gengler', - 'Fujita', - 'Huls', - 'Basquez', - 'Trepanier', - 'Spadaro', - 'Ankney', - 'Damiani', - 'Games', - 'Cherney', - 'Fitzsimons', - 'Dearmas', - 'Bonet', - 'Diem', - 'Shimp', - 'Agrawal', - 'Gaw', - 'Gahagan', - 'Fossett', - 'Kafka', - 'Dedios', - 'Coryell', - 'Bahe', - 'Wurm', - 'Wishart', - 'Dray', - 'Armer', - 'Khalid', - 'Gassaway', - 'Vawter', - 'Loew', - 'Coello', - 'Curren', - 'Gilder', - 'Letendre', - 'Sprecher', - 'Rexrode', - 'Minich', - 'Koepp', - 'Mulloy', - 'Bohman', - 'Gambrel', - 'Hackley', - 'Demasi', - 'Hoffert', - 'Kittredge', - 'Maltby', - 'Nyquist', - 'Schieber', - 'Kennell', - 'Calderwood', - 'Compean', - 'Romines', - 'Simonelli', - 'Pico', - 'Oda', - 'Holte', - 'Bate', - 'Learn', - 'Lowenstein', - 'Holtman', - 'Mingus', - 'Sessa', - 'Legendre', - 'Gerrish', - 'Schoenberg', - 'Liberman', - 'Mclachlan', - 'Higginson', - 'Vince', - 'Mallery', - 'Delamora', - 'Difranco', - 'Lein', - 'Haltom', - 'Dority', - 'Marcellus', - 'Heskett', - 'Harward', - 'Spinney', - 'Darwin', - 'Baylis', - 'Amodeo', - 'Schwandt', - 'Mcmorrow', - 'Foraker', - 'Fyfe', - 'Shingleton', - 'Blandon', - 'Waddy', - 'Ricca', - 'Scheffer', - 'Balliet', - 'Philipp', - 'Rish', - 'Hattaway', - 'Krejci', - 'Orduno', - 'Passarelli', - 'Skala', - 'Oram', - 'Raynes', - 'Hiett', - 'Tolan', - 'Kimbell', - 'Delara', - 'Farhat', - 'Kamps', - 'Mohney', - 'Escarcega', - 'Mell', - 'Mcquay', - 'Cannizzaro', - 'Deuel', - 'Losoya', - 'Goldin', - 'Zaidi', - 'Gillmore', - 'Buelow', - 'Maust', - 'Guerrera', - 'Bouck', - 'Bick', - 'Kelty', - 'Pines', - 'Braziel', - 'Bruening', - 'Frenzel', - 'Kenna', - 'Loria', - 'Koren', - 'Cornelio', - 'Poisson', - 'Raker', - 'Ptak', - 'Bohr', - 'Coury', - 'Failla', - 'Cipriani', - 'Delany', - 'Marmon', - 'Kinch', - 'Figgins', - 'Delfino', - 'Risser', - 'Hickox', - 'Fager', - 'Turpen', - 'Dalzell', - 'Falvey', - 'Leiker', - 'Mcgonigal', - 'Vaquera', - 'Weisser', - 'Viviano', - 'Shrock', - 'Minaya', - 'Chitty', - 'Costley', - 'Granberry', - 'Dimaria', - 'Roma', - 'Ortis', - 'Burnam', - 'Burruss', - 'Stoughton', - 'Cales', - 'Burrage', - 'Vanwagner', - 'Espada', - 'Mccuen', - 'Baize', - 'Pullum', - 'Gerrity', - 'Vicari', - 'Heuser', - 'Semler', - 'Fear', - 'Havener', - 'Kash', - 'Thibodaux', - 'Hadaway', - 'Smithwick', - 'Eisenhart', - 'Hodgin', - 'Cluck', - 'Godby', - 'Belli', - 'Demaree', - 'Beyers', - 'Jared', - 'Mall', - 'Defoe', - 'Chmura', - 'Hepworth', - 'Hintze', - 'Luk', - 'Vanriper', - 'Solari', - 'Atlas', - 'Outland', - 'Hanselman', - 'Scharff', - 'Rhein', - 'Milone', - 'Rochford', - 'Mynatt', - 'Lambdin', - 'Sandell', - 'Grounds', - 'Tabler', - 'Smartt', - 'Dejean', - 'Clayborne', - 'Vangorder', - 'Eastin', - 'Hiler', - 'Lisle', - 'Gramling', - 'Degarmo', - 'Malec', - 'Tinkham', - 'Vanauken', - 'Andrzejewski', - 'Rundell', - 'Happel', - 'Strine', - 'Koerber', - 'Haner', - 'Ashcroft', - 'Hille', - 'Cairo', - 'Upson', - 'Mooring', - 'Koury', - 'Vito', - 'Oberlin', - 'Christiano', - 'Redfearn', - 'Trower', - 'Hibbler', - 'Sumter', - 'Raftery', - 'Geise', - 'Wohl', - 'Gorney', - 'Peasley', - 'Heap', - 'Brazeal', - 'Mccleskey', - 'Yard', - 'Mcroy', - 'Amend', - 'Cutshaw', - 'Kazmierczak', - 'Strandberg', - 'Lasko', - 'Newlon', - 'File', - 'Bevill', - 'Silvera', - 'Arakaki', - 'Kelsch', - 'Ostendorf', - 'Cowie', - 'Hove', - 'Doles', - 'Bouvier', - 'Fecteau', - 'Hasegawa', - 'Paschke', - 'Taing', - 'Heldt', - 'Allaire', - 'Ochsner', - 'Giusti', - 'Reisner', - 'Swim', - 'Laidlaw', - 'Vanderbilt', - 'Atterberry', - 'Barthelemy', - 'Chalker', - 'Degregorio', - 'Mastro', - 'Patlan', - 'Gipe', - 'Roosa', - 'Filkins', - 'Styron', - 'Bryer', - 'Blackston', - 'Hagel', - 'Fralick', - 'Linhart', - 'Moura', - 'Pavia', - 'Pavao', - 'Furry', - 'Petrus', - 'Fairweather', - 'Blystone', - 'Co', - 'Divito', - 'Villicana', - 'Winch', - 'Tome', - 'Lanoue', - 'Biron', - 'Noell', - 'Mckeel', - 'Worthey', - 'Aten', - 'Eyer', - 'Zhen', - 'Tischler', - 'Luoma', - 'Opp', - 'Riggin', - 'Furness', - 'Wolbert', - 'Penning', - 'Draves', - 'Whitehill', - 'Dudgeon', - 'Kinkead', - 'Luca', - 'Rosell', - 'Macauley', - 'Goldner', - 'Ishikawa', - 'Kirchhoff', - 'Lamarca', - 'Miyashiro', - 'Weger', - 'Wuest', - 'Kreis', - 'Urbanek', - 'Palko', - 'Victorino', - 'Morado', - 'Burchette', - 'Holyfield', - 'Tulloch', - 'Twombly', - 'Munk', - 'Woolford', - 'Knisely', - 'Locher', - 'Eckart', - 'Rancourt', - 'Pyron', - 'Edney', - 'Besser', - 'Truex', - 'Monterroso', - 'Bruneau', - 'Province', - 'Permenter', - 'Nims', - 'Rollison', - 'Cabell', - 'Sylvain', - 'Salman', - 'Signorelli', - 'Vegas', - 'Maddy', - 'Bachelder', - 'Sevigny', - 'Stolte', - 'Chavarin', - 'Lukes', - 'Rather', - 'Gartland', - 'Kurek', - 'Nantz', - 'Savard', - 'Finegan', - 'No', - 'Chichester', - 'Newbill', - 'Mahnke', - 'Sax', - 'Sowinski', - 'Wendler', - 'Cadiz', - 'Male', - 'Mealey', - 'Brookes', - 'Enderle', - 'Valenta', - 'Tooker', - 'Whitbeck', - 'Threet', - 'Cavitt', - 'Murtagh', - 'Phalen', - 'Errico', - 'Merkley', - 'Ju', - 'Zachery', - 'Bramer', - 'Henline', - 'Noga', - 'Woelfel', - 'Deras', - 'Amen', - 'Aldape', - 'Bartling', - 'Claros', - 'Spurrier', - 'Ginder', - 'Fred', - 'Giberson', - 'Ryba', - 'Sommerfeld', - 'Dahle', - 'Endo', - 'Haddon', - 'Bowlby', - 'Wagener', - 'Ketter', - 'Balint', - 'Goheen', - 'Motsinger', - 'Celentano', - 'Drawdy', - 'Dennehy', - 'Mcelligott', - 'Nakamoto', - 'Deines', - 'Goldsby', - 'Drakeford', - 'Steffy', - 'Streich', - 'Villasana', - 'Cermak', - 'Prill', - 'Ellzey', - 'Gartrell', - 'Duffie', - 'Rother', - 'Buse', - 'Luz', - 'Groen', - 'Laviolette', - 'Roles', - 'Days', - 'Eash', - 'Haefner', - 'Font', - 'Mcree', - 'Bustillo', - 'Coughlan', - 'Bax', - 'Hoxie', - 'Barre', - 'Scaife', - 'Nowacki', - 'Reichardt', - 'Rogel', - 'Ivins', - 'Vanderburg', - 'Etchison', - 'Chesson', - 'Molden', - 'Giuliani', - 'Goodpaster', - 'Kriner', - 'Sturtz', - 'Tschida', - 'Henschel', - 'Asselin', - 'Kocsis', - 'Kroger', - 'Swayne', - 'Gallop', - 'Fraker', - 'Lauro', - 'Tuohy', - 'Scholes', - 'Croxton', - 'Fertig', - 'Gregerson', - 'Gundersen', - 'Lehrer', - 'Monsivais', - 'Pilla', - 'Weishaar', - 'Gutshall', - 'Winget', - 'Human', - 'Oberry', - 'Learned', - 'Marburger', - 'Teed', - 'Parrilla', - 'Due', - 'Hartzler', - 'Cieslak', - 'Feltz', - 'Geren', - 'Wile', - 'Waldrip', - 'Clore', - 'Stutler', - 'Feehan', - 'Lacher', - 'Felter', - 'Barakat', - 'Flippen', - 'Holsey', - 'Finkbeiner', - 'Istre', - 'Lengyel', - 'Lupercio', - 'Beegle', - 'Habel', - 'Hammill', - 'Kifer', - 'Buswell', - 'Deboard', - 'Guilliams', - 'Ahlstrom', - 'Beliveau', - 'Sasse', - 'Delker', - 'Letterman', - 'Avey', - 'Bohlen', - 'Piner', - 'Folmar', - 'Barile', - 'Komar', - 'Bonelli', - 'Lamay', - 'Cora', - 'Deere', - 'Sanon', - 'Deppe', - 'Emmerich', - 'Giannone', - 'Navarra', - 'Hudock', - 'Seaborn', - 'Burda', - 'Faz', - 'Stefani', - 'Beemer', - 'Vose', - 'Calandra', - 'Eno', - 'Figueredo', - 'Lauck', - 'Schwindt', - 'Dumais', - 'Hedger', - 'Capp', - 'Barreiro', - 'Buker', - 'Spruell', - 'Bertolini', - 'Hoar', - 'Tiemann', - 'Vandenbosch', - 'Winebrenner', - 'Maio', - 'Winship', - 'Brissette', - 'Hansell', - 'Elsey', - 'Hansard', - 'Gildersleeve', - 'Hambright', - 'Borba', - 'Konieczny', - 'Lundell', - 'Tiedemann', - 'Siegler', - 'Ying', - 'Mckinsey', - 'Olah', - 'Boersma', - 'Younkin', - 'Evanoff', - 'Nakashima', - 'Scalia', - 'Piro', - 'Colorado', - 'Felan', - 'Fuentez', - 'Blea', - 'Gowin', - 'Hanning', - 'Byrom', - 'Morant', - 'Bachand', - 'Mcsorley', - 'Peaslee', - 'Bardsley', - 'Stilson', - 'Severs', - 'Kincheloe', - 'Kyler', - 'Aurand', - 'Bento', - 'Hoeppner', - 'Mertes', - 'Pickrell', - 'Rustad', - 'Millikan', - 'Celestino', - 'Hovland', - 'Kurowski', - 'Zollinger', - 'Tallon', - 'Junkins', - 'Mizrahi', - 'Bomberger', - 'Farrand', - 'Curto', - 'Bona', - 'Donatelli', - 'Eppley', - 'Schurman', - 'Henao', - 'Tomberlin', - 'Provencio', - 'Speidel', - 'Cree', - 'Inskeep', - 'Yeates', - 'Hoggatt', - 'Hinkson', - 'Ficklin', - 'Mcnealy', - 'Cabanas', - 'Laycock', - 'Theroux', - 'Weymouth', - 'Mabie', - 'Hatchell', - 'Bohanon', - 'Bilger', - 'Nazarian', - 'Weist', - 'Depue', - 'Mangini', - 'Gelb', - 'Luman', - 'Blass', - 'Desroches', - 'Hearon', - 'Mcmiller', - 'Stoltenberg', - 'Parenti', - 'Daulton', - 'Smail', - 'Chisum', - 'Benefiel', - 'Tetrault', - 'Foland', - 'Reddington', - 'Mattei', - 'Custis', - 'Fransen', - 'Zylstra', - 'Salvaggio', - 'Factor', - 'Deshong', - 'Biederman', - 'Sirianni', - 'Steckler', - 'Thrall', - 'Dorsch', - 'Harpe', - 'Tell', - 'Galusha', - 'Guttman', - 'Raposa', - 'Jaros', - 'Lipka', - 'Shive', - 'Shand', - 'Brizuela', - 'Horvat', - 'Pisciotta', - 'Sorge', - 'Riebe', - 'Vanderlaan', - 'Isenhour', - 'Franson', - 'Goslin', - 'Amore', - 'Leachman', - 'Foulks', - 'Alamillo', - 'Scarpa', - 'Tickle', - 'Pettitt', - 'Orrell', - 'Fleckenstein', - 'Sapien', - 'Roye', - 'Mcmeans', - 'Sligh', - 'Landgraf', - 'Cecere', - 'Aune', - 'Ketron', - 'Welcher', - 'Tilford', - 'Maston', - 'Overall', - 'Fails', - 'Bah', - 'Ketterman', - 'Lindauer', - 'Saxe', - 'Majka', - 'Goodenough', - 'Panella', - 'Ramm', - 'Caley', - 'Christine', - 'Kinsler', - 'Pippen', - 'Murph', - 'Ammann', - 'Falkowski', - 'Madonna', - 'Seligman', - 'Rommel', - 'Lareau', - 'Melone', - 'Frasure', - 'Joyal', - 'Piekarski', - 'Porcelli', - 'Kennington', - 'Pica', - 'Ankrom', - 'Capron', - 'Chatmon', - 'Horrigan', - 'Morelos', - 'Noren', - 'Paolini', - 'Wildermuth', - 'Rossow', - 'Dorgan', - 'Pawlik', - 'Reiber', - 'Rothenberger', - 'Mcgonigle', - 'Oren', - 'Jeans', - 'Vivas', - 'Gerner', - 'Brzozowski', - 'Croyle', - 'Klick', - 'Vidaurri', - 'Wollman', - 'Brouillard', - 'Dejohn', - 'Meikle', - 'Grochowski', - 'Kaczor', - 'Philbin', - 'Sperber', - 'Vancil', - 'Zornes', - 'Strope', - 'Housel', - 'Minks', - 'Dike', - 'Jasmin', - 'Denicola', - 'Gokey', - 'Dominy', - 'Gillham', - 'Viray', - 'Herz', - 'Hursh', - 'Koeller', - 'Caicedo', - 'Near', - 'Harrel', - 'Veale', - 'Gustavson', - 'Lopiccolo', - 'Goldschmidt', - 'Loder', - 'Vannorman', - 'Maske', - 'Randel', - 'Pinner', - 'Buntin', - 'Roache', - 'Pinnock', - 'Dimaio', - 'Heckert', - 'Perrigo', - 'Schank', - 'Lisowski', - 'Brownstein', - 'Sharer', - 'Hambleton', - 'Maker', - 'Hursey', - 'Aguado', - 'Tian', - 'Rheaume', - 'Becraft', - 'Sowders', - 'Bratt', - 'Tebo', - 'Eid', - 'Reinecke', - 'Storck', - 'Pech', - 'Alspaugh', - 'Grell', - 'Purdue', - 'Jennette', - 'Pauling', - 'Wint', - 'Knupp', - 'Madewell', - 'Schwanke', - 'Tellier', - 'Washer', - 'Staff', - 'Keely', - 'Lisenby', - 'Walder', - 'Kennerly', - 'Ip', - 'Michalik', - 'Eichner', - 'Disbrow', - 'Bellomy', - 'Boesch', - 'Chirico', - 'Lietz', - 'Ploof', - 'Dyar', - 'Bai', - 'Lary', - 'Corbo', - 'Danaher', - 'Schiavo', - 'Giacalone', - 'Pentz', - 'Studley', - 'Doyal', - 'Edie', - 'Nathaniel', - 'Cambra', - 'Fenstermacher', - 'Garst', - 'Gaudio', - 'Zavaleta', - 'Castilla', - 'Griffeth', - 'Warthen', - 'Derringer', - 'Samsel', - 'Mattia', - 'Boelter', - 'Mathieson', - 'Estelle', - 'Frisk', - 'Hipple', - 'Garceau', - 'Ehrman', - 'Buchner', - 'Frailey', - 'Ganey', - 'Belser', - 'Leiby', - 'Schwind', - 'Hagberg', - 'Hooley', - 'Rafter', - 'Hasting', - 'Mcnab', - 'Piggott', - 'Millhouse', - 'Brescia', - 'Giancola', - 'Grob', - 'Uresti', - 'Tawney', - 'Huot', - 'Mizer', - 'Storrs', - 'Shobe', - 'Blade', - 'Baumbach', - 'Eppler', - 'Henningsen', - 'Kmetz', - 'Sepeda', - 'Pangburn', - 'Falgout', - 'Hurn', - 'Sholar', - 'Kendricks', - 'Brimhall', - 'Bucklin', - 'Hruby', - 'Hunziker', - 'Krenz', - 'Schwager', - 'Murley', - 'Crittendon', - 'Broady', - 'Kintz', - 'Entrekin', - 'Estey', - 'Sharrow', - 'Quarterman', - 'Gumbs', - 'Steely', - 'Machin', - 'Difiore', - 'Desch', - 'Wiedemann', - 'Tonn', - 'Villines', - 'Mcdole', - 'Bashir', - 'Beauford', - 'Crary', - 'Gallina', - 'Wolak', - 'Aburto', - 'Hasler', - 'Gullion', - 'Bracewell', - 'Rusher', - 'Sarvis', - 'Dargan', - 'Garbarino', - 'Pigeon', - 'Blasi', - 'Viens', - 'Reising', - 'Vosburgh', - 'Canipe', - 'Mcnett', - 'Bruss', - 'Shiflet', - 'Pinard', - 'Lattin', - 'Armbrust', - 'Peffer', - 'Shotts', - 'Arbaugh', - 'Hux', - 'First', - 'Bolds', - 'Ceaser', - 'Cephas', - 'Bormann', - 'Broadwell', - 'Qian', - 'Talamantez', - 'Vandermolen', - 'Maza', - 'Kinnear', - 'Bullins', - 'Arant', - 'Brodbeck', - 'Rolfes', - 'Wisneski', - 'Dague', - 'Dudas', - 'Greener', - 'Noguera', - 'Greeno', - 'Daddario', - 'Giambrone', - 'Menon', - 'Sherrick', - 'Spier', - 'Semon', - 'Fendley', - 'Crichton', - 'Moree', - 'Stratford', - 'Zobel', - 'Halladay', - 'Keesler', - 'Prewett', - 'Deavers', - 'Kamal', - 'Bottom', - 'Caves', - 'Harshaw', - 'Fretz', - 'Secord', - 'Seibold', - 'Pantaleon', - 'Greek', - 'Baumeister', - 'Kleven', - 'Kos', - 'Orban', - 'Papke', - 'Shatto', - 'Cui', - 'Boan', - 'Nevitt', - 'Hultgren', - 'Kreiser', - 'Veres', - 'Jent', - 'Merck', - 'Gibby', - 'Hosch', - 'Mallet', - 'Dock', - 'Dallman', - 'Loiacono', - 'Tetzlaff', - 'Arboleda', - 'Mclelland', - 'Willing', - 'Coonrod', - 'Cappiello', - 'Courtemanche', - 'Halperin', - 'Odegard', - 'Hornyak', - 'Stem', - 'Doner', - 'Saffold', - 'Hochman', - 'Ing', - 'Knudtson', - 'Laabs', - 'Selleck', - 'Bassler', - 'Kamin', - 'Hur', - 'Forward', - 'Finnie', - 'Blubaugh', - 'Hitz', - 'Litteral', - 'Mansur', - 'Rosenow', - 'Vermeulen', - 'Markarian', - 'Marceau', - 'Weisner', - 'Sharpless', - 'Cunniff', - 'Guilfoyle', - 'Lauver', - 'Lukasik', - 'Ripp', - 'Wierzbicki', - 'Wunsch', - 'Boothby', - 'Selfridge', - 'Mckey', - 'Vandermeer', - 'Vanhoy', - 'Edlund', - 'Eggen', - 'Bickett', - 'Hallum', - 'Brow', - 'Rhymer', - 'Buckalew', - 'Haughey', - 'Hentges', - 'Matthies', - 'Mccloy', - 'Simmon', - 'Concha', - 'Feingold', - 'Maglio', - 'Olaughlin', - 'Tassone', - 'Abbasi', - 'Oyola', - 'Mook', - 'Makin', - 'Carnegie', - 'Yue', - 'Sethi', - 'Duchene', - 'Mcnear', - 'Bartolo', - 'Hegedus', - 'Knoblauch', - 'Orner', - 'Hottinger', - 'Lovitt', - 'Harkless', - 'Anastasio', - 'Hohmann', - 'Mangione', - 'Dalby', - 'Urich', - 'Shuttleworth', - 'Guilbeau', - 'Bausch', - 'Demartini', - 'Difrancesco', - 'Schwalm', - 'Steere', - 'Guel', - 'Blanford', - 'Flax', - 'Fearon', - 'Severe', - 'Canto', - 'Krogh', - 'Meola', - 'Dykema', - 'Angelini', - 'Pooley', - 'Raff', - 'Rister', - 'Baehr', - 'Daubert', - 'Dechant', - 'Kliewer', - 'Hamdan', - 'Gaiser', - 'Lichty', - 'Pomerleau', - 'Uhler', - 'Membreno', - 'Printz', - 'Worman', - 'Thornley', - 'Burbridge', - 'Burdge', - 'Schnitzer', - 'Swanberg', - 'Steinkamp', - 'Heidel', - 'Karch', - 'Igo', - 'Mccausland', - 'Huskins', - 'Kuss', - 'Newbern', - 'Peete', - 'Godbolt', - 'Climer', - 'Neuenschwander', - 'Then', - 'Tietjen', - 'Trombetta', - 'Hawke', - 'Hazlewood', - 'Mayse', - 'Patillo', - 'Banos', - 'Kuck', - 'Lashbrook', - 'Sarkisian', - 'Goldberger', - 'Moravec', - 'Arey', - 'Crosswhite', - 'Elders', - 'Fricks', - 'Hercules', - 'Bester', - 'Erhart', - 'Kuper', - 'Sickels', - 'Mun', - 'Beddingfield', - 'Panetta', - 'Poplawski', - 'Lansford', - 'Negri', - 'Dawe', - 'Belair', - 'Lattimer', - 'Betty', - 'Raye', - 'Gobert', - 'Dragoo', - 'Horney', - 'Strawbridge', - 'Howery', - 'Bosarge', - 'Panzer', - 'Labrador', - 'Ransdell', - 'Trumbo', - 'Aubry', - 'Fenderson', - 'Fukuda', - 'Grosz', - 'Jacome', - 'Slick', - 'Kogut', - 'Haig', - 'Fouse', - 'Hufnagel', - 'Kehr', - 'Musselwhite', - 'Otwell', - 'Raddatz', - 'Oliverio', - 'Sluss', - 'Crossen', - 'Guidroz', - 'Mollett', - 'Sumler', - 'Chmiel', - 'Guinan', - 'Vita', - 'Wieser', - 'Ohlson', - 'Bubb', - 'Stennett', - 'Bugbee', - 'Minchew', - 'Grado', - 'Calcagno', - 'Losh', - 'Witzel', - 'Brandl', - 'Geoghegan', - 'Vanbrunt', - 'Smalling', - 'Carignan', - 'Schuelke', - 'Sienkiewicz', - 'Sollars', - 'Dames', - 'Malkin', - 'Rodriges', - 'Rozanski', - 'Tews', - 'Aust', - 'Bardin', - 'Voorhies', - 'Rines', - 'Courts', - 'Bannerman', - 'Martinsen', - 'Malick', - 'Collar', - 'Twilley', - 'Freiberg', - 'Latiolais', - 'Zehnder', - 'Mannon', - 'Becnel', - 'Cowans', - 'Arrigo', - 'Crago', - 'Curtsinger', - 'Gassman', - 'Marcelo', - 'Rosendahl', - 'Benito', - 'Cortright', - 'Carlon', - 'Kenton', - 'Hemminger', - 'Martinek', - 'Galeana', - 'Cobble', - 'Ruffino', - 'Wittrock', - 'Aberle', - 'Catanese', - 'Huezo', - 'Soules', - 'Ashraf', - 'Mera', - 'Gash', - 'Agnello', - 'Hauk', - 'Hayek', - 'Rahm', - 'Higham', - 'Kondo', - 'Almon', - 'Earwood', - 'Kriebel', - 'Philbrook', - 'Rimer', - 'Cuffee', - 'Wolfgram', - 'Wardwell', - 'Ridder', - 'Runner', - 'Houchens', - 'Vasser', - 'Charlesworth', - 'Dierks', - 'Molter', - 'Orosz', - 'Roudebush', - 'Coca', - 'Brost', - 'Lovern', - 'Brott', - 'Baudoin', - 'Prophet', - 'Bermea', - 'Ulm', - 'Bahl', - 'Ulery', - 'Caraveo', - 'Maez', - 'Corchado', - 'Baillie', - 'Colmenero', - 'Rebolledo', - 'Shevlin', - 'Mehaffey', - 'Hedin', - 'Pickell', - 'Spiro', - 'Coatney', - 'Gentner', - 'Fuhr', - 'Zeh', - 'Fuerte', - 'Knerr', - 'Nakata', - 'Voll', - 'Zach', - 'Gatica', - 'Rabalais', - 'Macek', - 'Petti', - 'Dickison', - 'Sheley', - 'Kinner', - 'Effinger', - 'Axelson', - 'Overbay', - 'Vancleve', - 'Speegle', - 'Muntz', - 'Sang', - 'Mcleroy', - 'Aleshire', - 'Holdridge', - 'Knouse', - 'Saling', - 'Zacher', - 'Zambrana', - 'Neblett', - 'Cichon', - 'Herdman', - 'Poli', - 'Schisler', - 'Antrim', - 'Babineau', - 'Coplin', - 'Straughn', - 'Watlington', - 'Burbach', - 'Campanelli', - 'Coletta', - 'Tennis', - 'Dymond', - 'Darosa', - 'Chard', - 'Delcampo', - 'Lyden', - 'Piland', - 'Eslick', - 'Beets', - 'Ransome', - 'Schuett', - 'Styers', - 'Fegley', - 'Corning', - 'Crume', - 'Villeneuve', - 'Schmeling', - 'Zeiger', - 'Blaker', - 'Ramsden', - 'Carol', - 'Roseboro', - 'Egner', - 'Filip', - 'Poitras', - 'Flanery', - 'Cothren', - 'Bridger', - 'Hoose', - 'Demas', - 'Kozel', - 'Marzano', - 'Penwell', - 'Rast', - 'Whicker', - 'Haslett', - 'Bibby', - 'Keese', - 'Montilla', - 'Sultana', - 'Resendes', - 'Vanscoy', - 'Dinan', - 'Bala', - 'Dirksen', - 'Ek', - 'Shimer', - 'Doshi', - 'Mayeux', - 'Streater', - 'Dattilo', - 'Marlar', - 'Senft', - 'Vanalstine', - 'Rehberg', - 'Vanderhoff', - 'Brenes', - 'Motto', - 'Sproles', - 'Toone', - 'Royall', - 'Beaudette', - 'Belding', - 'Berta', - 'Carmean', - 'Simonian', - 'Avera', - 'Martina', - 'Kind', - 'Buchheit', - 'Corrao', - 'Crumrine', - 'Wertman', - 'Lininger', - 'Pressman', - 'Slane', - 'Manges', - 'Theus', - 'Canizales', - 'Eugenio', - 'Ferrigno', - 'Ellard', - 'Stilley', - 'Crabbe', - 'Procter', - 'Baccus', - 'Hellmann', - 'Risk', - 'Schild', - 'Tostado', - 'Fessenden', - 'Glines', - 'Perone', - 'Carns', - 'Belote', - 'Deshotel', - 'Bottomley', - 'Delbosque', - 'Dubinsky', - 'Flinchum', - 'Berlanga', - 'Darland', - 'Daniele', - 'Jess', - 'Mungia', - 'Harlin', - 'Rocca', - 'Saltsman', - 'Trovato', - 'Dionisio', - 'Erbe', - 'Dauzat', - 'Laferriere', - 'Kear', - 'Brannigan', - 'Guard', - 'Roquemore', - 'Brehmer', - 'Kappes', - 'Kepley', - 'Labounty', - 'Sudol', - 'Walburn', - 'Bibeau', - 'Euler', - 'Brawn', - 'Pilot', - 'Bunger', - 'Earnhardt', - 'Fischetti', - 'Buitrago', - 'Calo', - 'Surette', - 'Martyn', - 'Tollett', - 'Tuller', - 'Noakes', - 'Marson', - 'Bongiovanni', - 'Novello', - 'Werling', - 'Wyland', - 'Palen', - 'Sigmund', - 'Salzer', - 'Abels', - 'Penson', - 'Cazarez', - 'Diblasi', - 'Jantzen', - 'Kittleson', - 'Hurlbert', - 'Shepardson', - 'Munz', - 'Bozek', - 'Woll', - 'Forth', - 'Colvard', - 'Baginski', - 'Beirne', - 'Lemmer', - 'Shover', - 'Lucci', - 'Hockensmith', - 'Mayhall', - 'Faucette', - 'Soloman', - 'Lembo', - 'Tarnowski', - 'Westerlund', - 'Gossage', - 'Bold', - 'Davi', - 'Crater', - 'Saia', - 'Spisak', - 'Zerr', - 'Penate', - 'Piel', - 'Raja', - 'Farney', - 'Cutrer', - 'Liverman', - 'Brar', - 'Nocera', - 'Coutu', - 'Rishel', - 'Spurr', - 'Kail', - 'Molino', - 'Favreau', - 'Mullinix', - 'Pospisil', - 'Rohloff', - 'Slavens', - 'Stumbo', - 'Ahl', - 'Hosking', - 'Speaker', - 'Tarkington', - 'Majeski', - 'Skoog', - 'Kirch', - 'Vannostrand', - 'Olmo', - 'Dorrell', - 'Newcombe', - 'Halls', - 'Riffel', - 'Luque', - 'Rolston', - 'Lokey', - 'Nicholes', - 'Gula', - 'Schrage', - 'Goshorn', - 'Woodell', - 'Ahmadi', - 'Austria', - 'Shaul', - 'Berwick', - 'Graczyk', - 'Lacourse', - 'Porcaro', - 'Rexroad', - 'Chrzanowski', - 'Abele', - 'Woodin', - 'Gillan', - 'Lone', - 'Orzechowski', - 'Fader', - 'Regina', - 'Ban', - 'Morriss', - 'Rickards', - 'Gannaway', - 'Tassin', - 'Accardi', - 'Engelke', - 'Kruk', - 'Mantilla', - 'Soderstrom', - 'Kriz', - 'Cantley', - 'Cangelosi', - 'Kalin', - 'Sobolewski', - 'Prinz', - 'Bessey', - 'Chittum', - 'Marcucci', - 'Annunziata', - 'Hegg', - 'Mishra', - 'Heppner', - 'Benningfield', - 'Rhoten', - 'Smolen', - 'Lewellyn', - 'Tall', - 'Comiskey', - 'Gobel', - 'Klump', - 'Stauber', - 'Tocci', - 'Gosser', - 'Tussey', - 'Summitt', - 'Ottman', - 'Vester', - 'Pasko', - 'Latshaw', - 'Kies', - 'Valderrama', - 'Leese', - 'Orduna', - 'Gilcrease', - 'Alli', - 'Berberich', - 'Delariva', - 'Harb', - 'Schmuck', - 'Spang', - 'Uecker', - 'Garfinkel', - 'Mcalexander', - 'Monty', - 'Leonetti', - 'Knipe', - 'Loudon', - 'Leisure', - 'Swearengin', - 'Tinnin', - 'Engelmann', - 'Noblitt', - 'Ruhland', - 'Shewmaker', - 'Smetana', - 'Vangundy', - 'Yzaguirre', - 'Nehls', - 'Sullens', - 'Mahurin', - 'Ferman', - 'Lenhardt', - 'Littman', - 'Udell', - 'Coutts', - 'Mcginness', - 'Nakayama', - 'Goguen', - 'Lass', - 'Tibbits', - 'Pafford', - 'Fett', - 'Ruis', - 'Trogdon', - 'Tarleton', - 'Isabell', - 'Paylor', - 'Grandison', - 'Bejar', - 'Highfield', - 'Peplinski', - 'Hammitt', - 'Mitton', - 'Dashiell', - 'Turrentine', - 'Rusin', - 'Sheeran', - 'Barrs', - 'Grund', - 'Kowalsky', - 'Mccaughey', - 'Orantes', - 'Oshields', - 'Tourville', - 'Szymczak', - 'Gagner', - 'Kemble', - 'Delangel', - 'Kaler', - 'Treanor', - 'Deems', - 'Ours', - 'Loss', - 'Remley', - 'Welles', - 'Bogardus', - 'Feher', - 'Grzybowski', - 'Meinert', - 'Mickelsen', - 'Opitz', - 'Osowski', - 'Paglia', - 'Srivastava', - 'Hirata', - 'Vandermark', - 'Maggi', - 'Gautreau', - 'Fonte', - 'Meck', - 'Mcquinn', - 'Criddle', - 'Hulin', - 'Fulmore', - 'Baldino', - 'Neugebauer', - 'Sletten', - 'Talcott', - 'Tessmer', - 'Vrooman', - 'Whitlatch', - 'Miano', - 'Arauz', - 'Lafon', - 'Cashin', - 'Carrow', - 'Feely', - 'Provo', - 'Botsford', - 'Chojnacki', - 'Pritts', - 'Duby', - 'Danos', - 'Mundo', - 'Strum', - 'Bealer', - 'Barmore', - 'Birkholz', - 'Hedgecock', - 'Vides', - 'Mcjunkin', - 'Paley', - 'Dennie', - 'Cosey', - 'Trombly', - 'Wagar', - 'Tope', - 'Venters', - 'Neptune', - 'Allshouse', - 'Kuczynski', - 'Beams', - 'Kilbourne', - 'Troxler', - 'Mcgahee', - 'Latson', - 'Miraglia', - 'Suda', - 'Prall', - 'Searls', - 'Tevis', - 'Vales', - 'Coberly', - 'Eichman', - 'Hiltz', - 'Mancera', - 'Mrozek', - 'Obermeyer', - 'Wiedeman', - 'Yoshimura', - 'Pascucci', - 'Denk', - 'Pita', - 'Abdul', - 'Schurr', - 'Huntoon', - 'Sund', - 'Blose', - 'Agostini', - 'Cogdell', - 'Hamburger', - 'Orwig', - 'Pelley', - 'Mcnelly', - 'Litten', - 'Osterberg', - 'Zepp', - 'Mathur', - 'Ardon', - 'Petre', - 'Schroeter', - 'Christoff', - 'Ridenhour', - 'Hibler', - 'Coachman', - 'Tadeo', - 'Vanderploeg', - 'Ference', - 'Connery', - 'Albro', - 'Bublitz', - 'Fagundes', - 'Purpura', - 'Deeb', - 'Melzer', - 'Haus', - 'Huffine', - 'Groner', - 'Laforce', - 'Burriss', - 'Longino', - 'Seldon', - 'Chicoine', - 'Neira', - 'Pintor', - 'Trager', - 'Garg', - 'Camilleri', - 'Limbaugh', - 'Marinello', - 'Sanz', - 'Hankey', - 'Aylor', - 'Homes', - 'Marro', - 'Stalder', - 'Creasey', - 'Blankinship', - 'Waldrup', - 'Aubert', - 'Quintanar', - 'Tarbell', - 'Mayton', - 'Baba', - 'Voltz', - 'Cuba', - 'Bracco', - 'Dimeo', - 'Cauble', - 'Rodela', - 'Sambrano', - 'Doten', - 'Jobes', - 'Laura', - 'Farrier', - 'Mixson', - 'Bassi', - 'Kroening', - 'Papineau', - 'Scheuerman', - 'Zertuche', - 'Cardella', - 'Taube', - 'Bazzi', - 'Sautter', - 'Tobon', - 'Venditti', - 'Nordman', - 'Loken', - 'Fortino', - 'Godbout', - 'Knaub', - 'Larabee', - 'Meserve', - 'Slama', - 'Junge', - 'Stamand', - 'Daigneault', - 'Fredericksen', - 'Loveall', - 'Clothier', - 'Kuehne', - 'Delahoussaye', - 'Bosquez', - 'Hildenbrand', - 'Muto', - 'Vanvliet', - 'Frederiksen', - 'Mero', - 'Rapier', - 'Feldt', - 'Mcpartland', - 'Stegner', - 'Veenstra', - 'Yeater', - 'Yeatts', - 'Rosenbloom', - 'Shepperd', - 'Marchbanks', - 'Tapscott', - 'Baynard', - 'Osby', - 'Cumberbatch', - 'Brassard', - 'Dahlman', - 'Doi', - 'Katona', - 'Niesen', - 'Slavik', - 'Macneill', - 'Marsala', - 'Fazekas', - 'Cudd', - 'Ocana', - 'Brimer', - 'Lachman', - 'Balla', - 'Shahid', - 'Gammage', - 'Canez', - 'Fickes', - 'Goldblatt', - 'Mcgeehan', - 'Westerberg', - 'Legler', - 'Stanberry', - 'Hillery', - 'Colosimo', - 'Florek', - 'Heckathorn', - 'Lenart', - 'Mcneilly', - 'Viles', - 'Davin', - 'Pierro', - 'Edman', - 'Patron', - 'Tipps', - 'Ardis', - 'Hassen', - 'Crase', - 'Gebert', - 'Predmore', - 'Entwistle', - 'Lourenco', - 'Snively', - 'Chivers', - 'Byas', - 'Edsall', - 'Sneddon', - 'Kloster', - 'Luedke', - 'Barcelo', - 'Corns', - 'Paula', - 'Tacker', - 'Marton', - 'Lyke', - 'Huitt', - 'Tinch', - 'Tagle', - 'Linnell', - 'Loden', - 'Witman', - 'Condrey', - 'Swindler', - 'Denby', - 'Mcdow', - 'Bennion', - 'Berkman', - 'Esguerra', - 'Kohli', - 'Leicht', - 'Platero', - 'Purtell', - 'Sarro', - 'Spera', - 'Wasielewski', - 'Nold', - 'Gander', - 'Coster', - 'Burn', - 'Sindelar', - 'Spivak', - 'Stangl', - 'Eakes', - 'Host', - 'Raybon', - 'Stickle', - 'Vitiello', - 'Borntrager', - 'Glorioso', - 'Winnie', - 'Blocher', - 'Che', - 'Godbold', - 'Blumenfeld', - 'Hallford', - 'Nuckolls', - 'Rasor', - 'Tardy', - 'Hayslett', - 'Kivett', - 'Pettry', - 'Klopfenstein', - 'Martelli', - 'Dunker', - 'Klass', - 'Denn', - 'Vessels', - 'Stukes', - 'Iannone', - 'Kovarik', - 'Perlmutter', - 'Som', - 'Kump', - 'Tack', - 'Warf', - 'Coffer', - 'Baas', - 'Balli', - 'Fleishman', - 'Lyall', - 'Meli', - 'Petrovic', - 'Sego', - 'Tignor', - 'Maule', - 'Stinchcomb', - 'Doxey', - 'Garbutt', - 'Drewes', - 'Prestridge', - 'Vivanco', - 'Weinmann', - 'Amrhein', - 'Schluter', - 'Cleek', - 'Rossignol', - 'Rezendes', - 'Marone', - 'Sloss', - 'Weary', - 'Leishman', - 'Searfoss', - 'Springman', - 'Wolfer', - 'Hires', - 'Mccampbell', - 'Casselman', - 'Frasca', - 'Lintner', - 'Preiss', - 'Neilsen', - 'Twiss', - 'Boughner', - 'Donnellan', - 'Rech', - 'Mccaulley', - 'Massenburg', - 'Dermody', - 'Neuberger', - 'Rifkin', - 'Ullom', - 'Marth', - 'Blacker', - 'Kase', - 'Garon', - 'Calaway', - 'Grange', - 'Yopp', - 'Service', - 'Blassingame', - 'Lockley', - 'Straughter', - 'Porath', - 'Situ', - 'Stansfield', - 'Eves', - 'Cianci', - 'Colindres', - 'Killam', - 'Luiz', - 'Stahlman', - 'Silvernail', - 'Moorhouse', - 'Langner', - 'Soucie', - 'Lucke', - 'Manly', - 'Huggard', - 'Higareda', - 'Matarazzo', - 'Jusino', - 'Winnett', - 'Matheney', - 'Bufkin', - 'Bilbo', - 'Levingston', - 'Auxier', - 'Guevarra', - 'Triolo', - 'Roder', - 'Clever', - 'Moodie', - 'Cabana', - 'Kiesling', - 'Lindblom', - 'Reuther', - 'Rubi', - 'Brinkmann', - 'Donati', - 'Cresswell', - 'Fortes', - 'Bayard', - 'Grayer', - 'Malveaux', - 'Hauger', - 'Hirschman', - 'Soroka', - 'Witek', - 'Pugsley', - 'Eoff', - 'Alewine', - 'Hastie', - 'Budzinski', - 'Burgard', - 'Hebel', - 'Kleist', - 'Lawhead', - 'Saporito', - 'Sugarman', - 'Sechler', - 'Cohoon', - 'Treadaway', - 'Silliman', - 'Horsey', - 'Chauhan', - 'Jovel', - 'Giorgio', - 'Waltrip', - 'Templeman', - 'Morning', - 'Fava', - 'Mcinturff', - 'Migliaccio', - 'Moncayo', - 'Pesek', - 'Olivero', - 'Devall', - 'Dauphin', - 'Banerjee', - 'Benway', - 'Bermejo', - 'Dacey', - 'Pilarski', - 'Pinnell', - 'Chia', - 'Pung', - 'Rahe', - 'Greenhaw', - 'Byrns', - 'Ancona', - 'Granato', - 'Luciani', - 'Shryock', - 'Sloop', - 'Murcia', - 'Croll', - 'Congleton', - 'Okelly', - 'Norville', - 'Flesch', - 'Murad', - 'Seddon', - 'Waybright', - 'Cremer', - 'Hagman', - 'Largo', - 'Solar', - 'Costales', - 'Gier', - 'Tober', - 'Reeb', - 'Lands', - 'Hoback', - 'Ingrassia', - 'Youngquist', - 'Tyrell', - 'Profit', - 'Collura', - 'Oldaker', - 'Vogl', - 'Spafford', - 'Laughman', - 'Goris', - 'Coghill', - 'Sweatman', - 'Rozelle', - 'Chatelain', - 'Fouch', - 'Legros', - 'Koza', - 'Vialpando', - 'Subia', - 'Danz', - 'Dosch', - 'Debruin', - 'Stefanik', - 'Gamber', - 'Saylors', - 'Cost', - 'Bernat', - 'Eastburn', - 'Getman', - 'Maillet', - 'Dogan', - 'Finklea', - 'Alongi', - 'Ballas', - 'Konkel', - 'Ryu', - 'Scoles', - 'Oles', - 'Algarin', - 'Seago', - 'Delaune', - 'Pettey', - 'Gettys', - 'Blanch', - 'Kea', - 'Cambridge', - 'Ciesielski', - 'Pribble', - 'Mayhugh', - 'Dery', - 'Allsup', - 'Hauptman', - 'Shoff', - 'Spath', - 'Lipsky', - 'Lakhani', - 'Lona', - 'Andrea', - 'Heist', - 'Herzig', - 'Insley', - 'Frasher', - 'Muise', - 'Kettle', - 'Catano', - 'Harkleroad', - 'Rominger', - 'Schreffler', - 'Bielecki', - 'Knarr', - 'Arvidson', - 'Harnden', - 'Galyon', - 'Rando', - 'Delima', - 'Constance', - 'Bosman', - 'Meinke', - 'Rosenquist', - 'Stickles', - 'Batz', - 'Eitel', - 'Kouba', - 'Marmol', - 'Rini', - 'Kinyon', - 'Munns', - 'Hilts', - 'Verrett', - 'Shead', - 'Staggers', - 'Naccarato', - 'Shupp', - 'Willeford', - 'Gayer', - 'Bran', - 'Krider', - 'Cue', - 'Dubiel', - 'Kawamoto', - 'Quayle', - 'Meckley', - 'Weingart', - 'Ivan', - 'Aller', - 'Pattee', - 'Pile', - 'Shinault', - 'Alzate', - 'Goudreau', - 'Weitzman', - 'Zurek', - 'Portman', - 'Tellis', - 'Achenbach', - 'Cranfill', - 'Scheib', - 'Rud', - 'Forgey', - 'Sardina', - 'Hayslip', - 'Fadden', - 'Ethington', - 'Jette', - 'Maberry', - 'Stecher', - 'Mcgahan', - 'Buffa', - 'Lehto', - 'Lesch', - 'Minier', - 'Niblett', - 'Behar', - 'Gochenour', - 'Thole', - 'Woodmansee', - 'Guse', - 'Breunig', - 'Deibert', - 'Levario', - 'Liming', - 'Oltman', - 'Vought', - 'Higby', - 'Lummus', - 'Casimir', - 'Grabow', - 'Helzer', - 'Madero', - 'Panico', - 'Ruud', - 'Beas', - 'Knebel', - 'Lorence', - 'Sizer', - 'Goodwill', - 'Darrell', - 'Dismukes', - 'Wimbish', - 'Kleine', - 'Prohaska', - 'Freeborn', - 'Caso', - 'Meis', - 'Bise', - 'Maxim', - 'Chumbley', - 'Eaglin', - 'Bergey', - 'Hillenbrand', - 'Pacifico', - 'Plath', - 'Rio', - 'Ristau', - 'Zych', - 'Whang', - 'Fister', - 'Forbush', - 'Lagarde', - 'Atha', - 'Hallinan', - 'Hesser', - 'Hoak', - 'Kohr', - 'Longnecker', - 'Nomura', - 'Raia', - 'Seybold', - 'Spagnola', - 'Majano', - 'Sanmartin', - 'Mangual', - 'Stanback', - 'Gangi', - 'Lauritzen', - 'Seeber', - 'Disla', - 'Frain', - 'Besse', - 'Makris', - 'Ducker', - 'Demps', - 'Laporta', - 'Pavey', - 'Reineke', - 'Najjar', - 'Mcclaskey', - 'Luff', - 'Vanderveer', - 'Mccoll', - 'Leamon', - 'Meinhardt', - 'Dinatale', - 'Laffoon', - 'Jenny', - 'Skipworth', - 'Folds', - 'Burstein', - 'Freas', - 'Lizardo', - 'Selle', - 'Vrabel', - 'Beranek', - 'Hakala', - 'Spataro', - 'Prahl', - 'Meas', - 'Haston', - 'Croker', - 'Carmouche', - 'Doolan', - 'Guerrieri', - 'Poulton', - 'Mauger', - 'Klose', - 'Husk', - 'Pharis', - 'Dipalma', - 'Hamaker', - 'Simek', - 'Strube', - 'Corl', - 'Bence', - 'Meigs', - 'Gillaspie', - 'Moring', - 'Eli', - 'Mccullers', - 'Erving', - 'Dopp', - 'Falbo', - 'Gensler', - 'Heroux', - 'Hertzler', - 'Muscarella', - 'Wittmann', - 'Willner', - 'Howton', - 'Brummitt', - 'Demar', - 'Hardrick', - 'Benavente', - 'Choo', - 'Tiscareno', - 'Bunge', - 'Helle', - 'Ogan', - 'Allbright', - 'Jervis', - 'Tompson', - 'Sheats', - 'Hebron', - 'Esters', - 'Fiorillo', - 'Narciso', - 'Slowik', - 'Kush', - 'Sole', - 'Bitting', - 'Bradham', - 'Goggans', - 'Rushin', - 'Huguley', - 'Kittelson', - 'Nadel', - 'Noggle', - 'Xue', - 'Alameda', - 'Hege', - 'Liberto', - 'Maron', - 'Aber', - 'Brodersen', - 'Clasen', - 'Couturier', - 'Godines', - 'Ozment', - 'Parga', - 'Rohm', - 'Voris', - 'Leaver', - 'Newhart', - 'Sabourin', - 'Kelling', - 'Repass', - 'Wigington', - 'Prioleau', - 'Antle', - 'Goucher', - 'Kreitzer', - 'Reuss', - 'Rosenfield', - 'Sliva', - 'Nolting', - 'Radel', - 'Quintal', - 'Lisa', - 'Temples', - 'Cavins', - 'Gazaway', - 'Hopewell', - 'Albury', - 'Broberg', - 'Khuu', - 'Zelinski', - 'Kurian', - 'Treacy', - 'Rake', - 'Tirrell', - 'Macdowell', - 'Smead', - 'Edgerly', - 'Fowles', - 'Yorke', - 'Goodwyn', - 'Sciacca', - 'Breitenbach', - 'Charity', - 'Greenidge', - 'Kendig', - 'Navarette', - 'Doremus', - 'Marcelino', - 'Ribera', - 'Luse', - 'Hasley', - 'Halton', - 'Jakes', - 'Balas', - 'Cheema', - 'Dettman', - 'Schachter', - 'Weisenberger', - 'Lehn', - 'Sailors', - 'Alcott', - 'Mancino', - 'Mineo', - 'Montz', - 'Stettler', - 'Brannock', - 'Shumake', - 'Blunk', - 'Feuerstein', - 'Mangino', - 'Bitzer', - 'Padden', - 'Wetter', - 'Blase', - 'Helvey', - 'Sabia', - 'Folden', - 'Wyllie', - 'Hoosier', - 'Gehringer', - 'Peifer', - 'Schneiderman', - 'Raj', - 'Gift', - 'Sue', - 'Wedgeworth', - 'Bischof', - 'Coviello', - 'Flor', - 'Barrentine', - 'Ells', - 'Dundas', - 'Baine', - 'Bouknight', - 'Koning', - 'Mallari', - 'Monje', - 'Wingler', - 'Stainbrook', - 'Mari', - 'Hemby', - 'Boateng', - 'Enfinger', - 'Esquer', - 'Salvatierra', - 'Tercero', - 'Porta', - 'Speth', - 'Plate', - 'Rockhold', - 'Hampshire', - 'Stipe', - 'Buescher', - 'Denault', - 'Fahnestock', - 'Vandehey', - 'Brouse', - 'Ciaccio', - 'Hund', - 'Wire', - 'Sherron', - 'Fairfax', - 'Owusu', - 'Cuervo', - 'Minjarez', - 'Zarco', - 'Vandyne', - 'Gedeon', - 'Kegler', - 'Ebron', - 'Murtaugh', - 'Pariseau', - 'Morvant', - 'Ellwood', - 'Beazley', - 'Farrelly', - 'Mccollom', - 'Alegre', - 'Dussault', - 'Goulette', - 'Hession', - 'Regier', - 'Speranza', - 'Spinella', - 'Maloof', - 'Nogueira', - 'Beaudin', - 'Sable', - 'Samford', - 'Marchan', - 'Rodriques', - 'Rhines', - 'Aldrete', - 'Creedon', - 'Laberge', - 'Sandel', - 'Spady', - 'Horsman', - 'Schimpf', - 'Sottile', - 'Than', - 'Ybanez', - 'Sagastume', - 'Vosburg', - 'Langlais', - 'Windley', - 'Bielski', - 'Meyerson', - 'Rizk', - 'Sparacino', - 'Winebarger', - 'Helsley', - 'Alward', - 'Wilker', - 'Clyne', - 'Bergren', - 'Gin', - 'Heberling', - 'Noh', - 'Rotz', - 'Laffey', - 'Zurawski', - 'Aliff', - 'Coover', - 'Steves', - 'Brain', - 'Greggs', - 'Burts', - 'Culwell', - 'Halbrook', - 'Marcantel', - 'Alsip', - 'Esslinger', - 'Kinnaird', - 'Rew', - 'Wimbley', - 'Dalal', - 'Litke', - 'Ostlund', - 'Petersheim', - 'Vezina', - 'Vickrey', - 'Vida', - 'Stachowiak', - 'Santizo', - 'Stow', - 'Hoel', - 'Parrino', - 'Elsberry', - 'Pharris', - 'Chiarello', - 'Konen', - 'Ogata', - 'Tousignant', - 'Turano', - 'Zoll', - 'Reser', - 'Ribble', - 'Dally', - 'Kersh', - 'Crivello', - 'Glantz', - 'Vanvleet', - 'Dy', - 'Woolwine', - 'Ager', - 'Romney', - 'Dedeaux', - 'Ringgold', - 'Mir', - 'Rexford', - 'Whitehair', - 'Wilczynski', - 'Kleinsasser', - 'Siemens', - 'Kindig', - 'Kemmer', - 'Fonda', - 'Litt', - 'Mcferrin', - 'Riche', - 'Beaudet', - 'Lasala', - 'Maglione', - 'Milani', - 'Moscato', - 'Pangilinan', - 'Haycraft', - 'Camilo', - 'Trafton', - 'Stroble', - 'Dollard', - 'Consiglio', - 'Kinnaman', - 'Mumaw', - 'Mustard', - 'Nees', - 'Rupprecht', - 'Gimbel', - 'Chamberland', - 'Lish', - 'Beedle', - 'Minder', - 'Broxton', - 'Cocco', - 'Vore', - 'Slough', - 'Pehrson', - 'Graney', - 'Reade', - 'Cozzi', - 'Mowrer', - 'Necaise', - 'Notaro', - 'Vanderwall', - 'Jeffs', - 'Lynd', - 'Perino', - 'Poyner', - 'Oscar', - 'Mihalik', - 'Coscia', - 'Zoellner', - 'Shippee', - 'Casimiro', - 'Phillippe', - 'Bartolotta', - 'Graciano', - 'Schnoor', - 'Aube', - 'Duguay', - 'Dickerman', - 'Santi', - 'Cude', - 'Haver', - 'Heidelberg', - 'Farquharson', - 'Bianchini', - 'Kasprzak', - 'Pizzi', - 'Urquiza', - 'Knee', - 'Lust', - 'Strayhorn', - 'Ader', - 'Canup', - 'Mira', - 'Saulnier', - 'Stalvey', - 'Takeuchi', - 'Updegraff', - 'Barletta', - 'Mikhail', - 'Abadie', - 'Cohee', - 'Sones', - 'Hird', - 'Mizelle', - 'Graddy', - 'Demay', - 'Escandon', - 'Kozar', - 'Lecuyer', - 'Tredway', - 'Danks', - 'Pry', - 'Mathena', - 'Gomer', - 'Moussa', - 'Journey', - 'Brison', - 'Denardo', - 'Digiorgio', - 'Worster', - 'Kottke', - 'Sayegh', - 'Aday', - 'Chain', - 'Digby', - 'Beeks', - 'Malpass', - 'Toft', - 'Fucci', - 'Stam', - 'Smoker', - 'Willms', - 'Bohner', - 'Sugar', - 'Tay', - 'Faye', - 'Melnik', - 'Pankow', - 'Stehle', - 'Vecchione', - 'Weatherwax', - 'Monterrosa', - 'Bodily', - 'Serino', - 'Jerkins', - 'Bosma', - 'Luczak', - 'Serafini', - 'Baze', - 'Hemmings', - 'Darrington', - 'Fraizer', - 'Henrikson', - 'Kok', - 'Larrison', - 'Mirabella', - 'Newhall', - 'Hollenbach', - 'Formica', - 'Haake', - 'Seim', - 'Zeledon', - 'Crabill', - 'Mensch', - 'Prevatt', - 'Riggan', - 'Gallien', - 'Erby', - 'Running', - 'Shisler', - 'Sidebottom', - 'Sladek', - 'Alejos', - 'Momin', - 'Bickers', - 'Smither', - 'Ahart', - 'Huseman', - 'Cantero', - 'Reiley', - 'Mcneeley', - 'Quill', - 'Binger', - 'Ellerbee', - 'Cearley', - 'Guilmette', - 'Helbig', - 'Nuzum', - 'Gravatt', - 'Turlington', - 'Deramus', - 'Casados', - 'Harrop', - 'Kardos', - 'Krehbiel', - 'Homa', - 'Agostino', - 'Candia', - 'Byerley', - 'Kincer', - 'Vitello', - 'Backhaus', - 'Burzynski', - 'Zaborowski', - 'Puebla', - 'Pedrick', - 'Hyson', - 'Mazyck', - 'Deno', - 'Yutzy', - 'Dubbs', - 'Shimek', - 'Saha', - 'Philipps', - 'Chretien', - 'Bramwell', - 'Mccalister', - 'Ebright', - 'Parkhill', - 'Rieke', - 'Karras', - 'Mcbain', - 'Gibbon', - 'Beckler', - 'Nordby', - 'Sipos', - 'Swider', - 'Treiber', - 'Weakland', - 'Zagorski', - 'Peavler', - 'Cirino', - 'Corzine', - 'Barbier', - 'Dolby', - 'Sheperd', - 'Vanderhorst', - 'Cornman', - 'Dippel', - 'Gramlich', - 'Hoffmeister', - 'Markwell', - 'Milks', - 'Schriner', - 'Cusimano', - 'Emberton', - 'Kimbler', - 'Merrow', - 'Huard', - 'Paulo', - 'Durrance', - 'Faherty', - 'Palmatier', - 'Rezac', - 'Speir', - 'Streicher', - 'Ackman', - 'Veitch', - 'Bedgood', - 'Pantano', - 'Raman', - 'Eusebio', - 'Coldwell', - 'Omer', - 'Swanigan', - 'Stepney', - 'Breiner', - 'Casebolt', - 'Deblasio', - 'Mascaro', - 'Maselli', - 'Overfield', - 'Enyart', - 'Litman', - 'Borer', - 'Dudash', - 'Mcniff', - 'Cherian', - 'Scearce', - 'Brakefield', - 'Hamed', - 'Cooperman', - 'Kinzel', - 'Mchargue', - 'Schiefelbein', - 'Varughese', - 'Brumm', - 'Novy', - 'Vicars', - 'Barratt', - 'Titsworth', - 'Mole', - 'Crisafulli', - 'Deitch', - 'Slager', - 'Tokarz', - 'Speelman', - 'Tunney', - 'Peal', - 'Chenevert', - 'Haggins', - 'Heitmann', - 'Scheuer', - 'Stuhr', - 'Zenner', - 'Wishon', - 'Arno', - 'Lauder', - 'Goertz', - 'Jew', - 'Knapik', - 'Lococo', - 'Murnane', - 'Pawloski', - 'Contino', - 'Holbrooks', - 'Carlstrom', - 'Heitkamp', - 'Muszynski', - 'Shelnutt', - 'Tortora', - 'Dietrick', - 'Kyzer', - 'Colt', - 'Propes', - 'Caffee', - 'Fankhauser', - 'Liotta', - 'Patil', - 'Broder', - 'Disher', - 'Telfer', - 'Lampkins', - 'Bartman', - 'Beauchemin', - 'Gatz', - 'Pedrosa', - 'Schuch', - 'Zorrilla', - 'Capote', - 'Vanderslice', - 'Boulden', - 'Kirkendoll', - 'Fausto', - 'Krom', - 'Ngai', - 'Sepe', - 'Domenech', - 'Dines', - 'Aschenbrenner', - 'Carias', - 'Inoue', - 'Montagna', - 'Pulsifer', - 'Rieman', - 'Seelye', - 'Yochum', - 'Defilippis', - 'Lacross', - 'Betances', - 'Jenne', - 'Rousey', - 'Brunswick', - 'Wadlington', - 'Brainerd', - 'Dauria', - 'Dinicola', - 'Fath', - 'Gemmell', - 'Rudman', - 'Urbaniak', - 'Fillion', - 'Brandel', - 'Devin', - 'Derrickson', - 'Jenkin', - 'Ebling', - 'Ferranti', - 'Lueders', - 'Alvear', - 'Gero', - 'Maury', - 'Estill', - 'Beadles', - 'Philyaw', - 'Tann', - 'Bednarski', - 'Nagata', - 'Partington', - 'Sobol', - 'Soohoo', - 'Welliver', - 'Yam', - 'Popejoy', - 'Berthelot', - 'Manwaring', - 'Cahn', - 'Layer', - 'Poarch', - 'Tee', - 'Arellanes', - 'Ehler', - 'Montalto', - 'Pavlick', - 'Rauh', - 'Mcnees', - 'Balke', - 'Alles', - 'Caperton', - 'Frier', - 'Thweatt', - 'Whitely', - 'Demby', - 'Kowalik', - 'Loffredo', - 'Solem', - 'Clampitt', - 'Dossey', - 'Fauver', - 'Toto', - 'Corlett', - 'Nickols', - 'Golston', - 'Graef', - 'Salsman', - 'Hartl', - 'Towell', - 'Lasseter', - 'Arata', - 'Diver', - 'Malan', - 'Lanter', - 'Justis', - 'Prime', - 'Ditzler', - 'Engelhart', - 'Plouffe', - 'Zaldivar', - 'Elser', - 'Witherow', - 'Mateer', - 'Rikard', - 'Dolson', - 'Mariner', - 'Amis', - 'Toby', - 'Evins', - 'Midgette', - 'Pinnix', - 'Blackard', - 'Huisman', - 'Lager', - 'Deloera', - 'Dutt', - 'Goodrow', - 'Morphis', - 'Quin', - 'Frankenfield', - 'Craycraft', - 'Mazer', - 'Meloy', - 'Lebouef', - 'Beresford', - 'Spiva', - 'Michie', - 'Jarreau', - 'Vallier', - 'Dunmore', - 'Cerra', - 'Ciulla', - 'Dauer', - 'Helling', - 'Jackowski', - 'Taboada', - 'Balistreri', - 'Blattner', - 'Cabot', - 'Lawver', - 'Cornette', - 'Arline', - 'Amsden', - 'Degner', - 'Ungar', - 'Birney', - 'Goldie', - 'Croston', - 'Wixon', - 'Alan', - 'Garneau', - 'Kolakowski', - 'Vitek', - 'Witherell', - 'Licari', - 'Badeaux', - 'Sammon', - 'Greenland', - 'Corlew', - 'Cashwell', - 'Aldinger', - 'Bilderback', - 'Kleeman', - 'Sisto', - 'Menz', - 'Bakos', - 'Ebbert', - 'Berliner', - 'Kin', - 'Cabaniss', - 'Ouzts', - 'Mccook', - 'Campfield', - 'Gulino', - 'Odriscoll', - 'Weyand', - 'Mcguckin', - 'Crean', - 'Boyington', - 'Bracero', - 'Carini', - 'Chawla', - 'Chaudhary', - 'Koehl', - 'Wahlstrom', - 'Francoeur', - 'Leveque', - 'Ledgerwood', - 'Paluch', - 'Wyble', - 'Latif', - 'Koen', - 'Eddie', - 'Mcgirt', - 'Boxley', - 'Exline', - 'Lujano', - 'Michalowski', - 'Rottman', - 'Throop', - 'Zech', - 'Baros', - 'Bohne', - 'Mule', - 'Monica', - 'Lasiter', - 'Alsop', - 'Pittard', - 'Whitefield', - 'Mccaskey', - 'Paek', - 'Reilley', - 'Wasik', - 'Bouma', - 'Garrigan', - 'Nett', - 'Mclarty', - 'Flemings', - 'Alcorta', - 'Spoor', - 'Mccranie', - 'Coverdale', - 'Guaman', - 'Jenness', - 'Knoop', - 'Scarpelli', - 'Schrecengost', - 'Toews', - 'Caughey', - 'Laska', - 'Helfer', - 'Bevers', - 'Forbus', - 'Mccrady', - 'Reasor', - 'Aggarwal', - 'Locicero', - 'Uber', - 'Vadnais', - 'Budnick', - 'Duhamel', - 'Stelling', - 'Kicklighter', - 'Basco', - 'Otts', - 'Tippins', - 'Bliven', - 'Gayheart', - 'Knauf', - 'Lalli', - 'Quigg', - 'Kingman', - 'Boros', - 'Henneman', - 'Lofland', - 'Pendarvis', - 'Keitt', - 'Gelfand', - 'Greaney', - 'Kindt', - 'Stimac', - 'Kirn', - 'Tokar', - 'Miura', - 'Wendorf', - 'Vigue', - 'Dorey', - 'Fegan', - 'Meares', - 'Thierry', - 'Ambrosino', - 'Coenen', - 'Kersting', - 'Leas', - 'Millward', - 'Petzold', - 'Morphew', - 'Filippone', - 'Stoffer', - 'Mani', - 'Clairmont', - 'Mccreight', - 'Cully', - 'Bissonette', - 'Kochan', - 'Linneman', - 'Parlier', - 'Bergner', - 'Sterns', - 'Steveson', - 'Clingerman', - 'Karg', - 'Medved', - 'Prakash', - 'Ulman', - 'Petroski', - 'Hagaman', - 'Huddle', - 'Auclair', - 'Shives', - 'Dunavant', - 'Glade', - 'Chauncey', - 'Pough', - 'Burgoon', - 'Pluta', - 'Couey', - 'Punch', - 'Colmenares', - 'Fosdick', - 'Henze', - 'Kaczynski', - 'Lomonaco', - 'Roepke', - 'Schenkel', - 'Schlatter', - 'Schoenherr', - 'Tripodi', - 'Zeiler', - 'Bunt', - 'Dolly', - 'Boyland', - 'Bickle', - 'Cincotta', - 'Crull', - 'Enfield', - 'Saltz', - 'Skelley', - 'Younts', - 'Bussiere', - 'Latona', - 'Sensabaugh', - 'Grosvenor', - 'Woolbright', - 'Shorty', - 'Brungardt', - 'Cardon', - 'Carlberg', - 'Clevinger', - 'Rucinski', - 'Vanhooser', - 'Westling', - 'Imperial', - 'Tyer', - 'Elzey', - 'Aslam', - 'Fesler', - 'Leiser', - 'Smitley', - 'Orgeron', - 'Scuderi', - 'Flatley', - 'Whiteford', - 'Tison', - 'Laurin', - 'Fortman', - 'Whitty', - 'Kirton', - 'Cassella', - 'Flom', - 'Seigel', - 'Cossette', - 'Bryden', - 'Gobin', - 'Hieb', - 'Marzullo', - 'Matuszak', - 'Rolph', - 'Spilman', - 'Vanvoorhis', - 'Sande', - 'Suydam', - 'Gledhill', - 'Krill', - 'Mackiewicz', - 'Templet', - 'Friedrichs', - 'Ruddell', - 'Kats', - 'Nourse', - 'Millender', - 'Wafer', - 'Fauntleroy', - 'Archibeque', - 'Maslowski', - 'Metzgar', - 'Pizana', - 'Mcguffey', - 'Estridge', - 'Vanalstyne', - 'Decuir', - 'Mcbean', - 'Hardnett', - 'Avilla', - 'Spadafora', - 'Weisel', - 'Kann', - 'Leyden', - 'Purdom', - 'Tappan', - 'Gunnells', - 'Slaten', - 'Hansley', - 'Chiappetta', - 'Rozek', - 'Tiede', - 'Winland', - 'Dubuque', - 'Heslin', - 'Bradway', - 'Eckels', - 'Saffell', - 'Germaine', - 'Apolinar', - 'Coloma', - 'Gawlik', - 'Chipps', - 'Hicklin', - 'Glanton', - 'Dalke', - 'Denlinger', - 'Kuipers', - 'Houpt', - 'Parcell', - 'Claeys', - 'Ferreri', - 'Greif', - 'Lucente', - 'Siems', - 'Yousef', - 'Llerena', - 'Rote', - 'Suero', - 'Malmberg', - 'Touchette', - 'Luton', - 'Wess', - 'Height', - 'Stampley', - 'Anastasi', - 'Bulman', - 'Deharo', - 'Laube', - 'Severt', - 'Midgley', - 'Colling', - 'Ell', - 'Burbage', - 'Commander', - 'Hubner', - 'Zurcher', - 'Arocha', - 'Nobile', - 'Tingler', - 'Ellman', - 'Lolley', - 'Pewitt', - 'Mcduff', - 'Hyler', - 'Goltz', - 'Kubota', - 'Lamberti', - 'Ohern', - 'Uhrig', - 'Dummer', - 'Keesling', - 'Litzinger', - 'Moriarity', - 'Servantes', - 'Rohe', - 'Stokely', - 'Weedon', - 'Pippins', - 'Dehner', - 'Krogman', - 'Luecke', - 'Rosete', - 'Zona', - 'Lowy', - 'Applebee', - 'Heather', - 'Cruikshank', - 'Linson', - 'Brandy', - 'Koser', - 'Ruel', - 'Ruppe', - 'Saeteurn', - 'Dewolfe', - 'Sawtelle', - 'Rudin', - 'Raver', - 'Bassham', - 'Yaw', - 'Segrest', - 'Belfiore', - 'Heeren', - 'Kotowski', - 'Luken', - 'Makela', - 'Ranallo', - 'Schug', - 'Seery', - 'Payson', - 'Caufield', - 'Lacefield', - 'Bratten', - 'Jr', - 'Buske', - 'Ternes', - 'Bivona', - 'Felber', - 'Rott', - 'Pitkin', - 'Pridmore', - 'Oyer', - 'Astle', - 'Jeppesen', - 'Shimabukuro', - 'Soltys', - 'Vieth', - 'Rasnick', - 'Calfee', - 'Brignac', - 'Lamy', - 'Facey', - 'Alper', - 'Borquez', - 'Cavalieri', - 'Niswonger', - 'Pajak', - 'Schwabe', - 'Ringel', - 'Abbe', - 'Fenley', - 'Churchman', - 'Haydel', - 'Stockard', - 'Adamek', - 'Ellerman', - 'Torpey', - 'Waldroup', - 'Hunte', - 'Bienaime', - 'Lazzara', - 'Nemitz', - 'Wingerter', - 'Boer', - 'Franken', - 'Lebow', - 'Manger', - 'Baisley', - 'Pane', - 'Gayden', - 'Bertelsen', - 'Curfman', - 'Leanos', - 'Nissley', - 'Odwyer', - 'Manzer', - 'Kollman', - 'Quon', - 'Holgate', - 'Cola', - 'Mckissack', - 'Cousar', - 'Bilski', - 'Boehler', - 'Kawamura', - 'April', - 'Mckelvy', - 'Lanni', - 'Roehm', - 'Salva', - 'Stackpole', - 'Stracener', - 'Masiello', - 'Barrus', - 'Tubb', - 'Brummel', - 'Devereux', - 'Foushee', - 'Corado', - 'Gladfelter', - 'Grewe', - 'Hodapp', - 'Swartwood', - 'Vacek', - 'Wrona', - 'Shaffner', - 'Ullah', - 'Heslop', - 'Mungo', - 'Haymon', - 'Behrend', - 'Falter', - 'Feola', - 'Gruner', - 'Picklesimer', - 'Riedl', - 'Stegeman', - 'Harpole', - 'Moyes', - 'Boulay', - 'Brighton', - 'Guise', - 'Laury', - 'Badilla', - 'Cypher', - 'Houdek', - 'Juhasz', - 'Klingbeil', - 'Pinales', - 'Fellman', - 'Daher', - 'Allmond', - 'Bal', - 'Crager', - 'Hillebrand', - 'Menezes', - 'Serpas', - 'Zager', - 'Alvardo', - 'Summerford', - 'Stillings', - 'Vandergrift', - 'Hanchett', - 'Minto', - 'Daughtery', - 'Gillon', - 'Rajan', - 'Vasko', - 'Wirick', - 'Woolever', - 'Caserta', - 'Welle', - 'Kimbrel', - 'Traywick', - 'Hands', - 'Spratley', - 'Iannuzzi', - 'Krikorian', - 'Runk', - 'Sood', - 'Riese', - 'Antunes', - 'Winsett', - 'Mans', - 'Capel', - 'Condron', - 'Nilles', - 'Petz', - 'Salemi', - 'Bainter', - 'Patchett', - 'Hirschfeld', - 'Murrin', - 'Lamey', - 'Mcglothin', - 'Hodo', - 'Hirth', - 'Kaltenbach', - 'Kensinger', - 'Leidy', - 'Shurtz', - 'Braatz', - 'Brafford', - 'Willet', - 'Clendening', - 'Basch', - 'Brockwell', - 'Oberman', - 'Palmateer', - 'Osornio', - 'Gehl', - 'Staker', - 'Mattila', - 'Dawn', - 'Cowherd', - 'Appleman', - 'Carbonaro', - 'Castruita', - 'Pilling', - 'Wenrich', - 'Christoffersen', - 'Hinzman', - 'Kaup', - 'Pettersen', - 'Jue', - 'Khalsa', - 'Mutz', - 'Remus', - 'Arch', - 'Shands', - 'Borek', - 'Buresh', - 'Egli', - 'Feldkamp', - 'Hampel', - 'Lichtenberg', - 'Morimoto', - 'Brasel', - 'Demelo', - 'Royalty', - 'Averitt', - 'Metivier', - 'Bradsher', - 'Avallone', - 'Demeter', - 'Masucci', - 'Musil', - 'Wichmann', - 'Broman', - 'Taunton', - 'Blewett', - 'Duhart', - 'Goo', - 'Hanus', - 'Mathai', - 'Shutts', - 'Taniguchi', - 'Vanleeuwen', - 'Delvillar', - 'Hane', - 'Givan', - 'Croskey', - 'Elamin', - 'Deffenbaugh', - 'Miklos', - 'Passalacqua', - 'Woessner', - 'Lapan', - 'Miah', - 'Coty', - 'Baksh', - 'Beehler', - 'Goel', - 'Wolfinger', - 'Goodhue', - 'Toal', - 'Mattoon', - 'Haq', - 'Nida', - 'Dant', - 'Varnadore', - 'Tippit', - 'Every', - 'Bohling', - 'Lichtenberger', - 'Louk', - 'Soderquist', - 'Werkheiser', - 'Willbanks', - 'Whitis', - 'Millikin', - 'Dietzel', - 'Frase', - 'Ishida', - 'Pilger', - 'Grajales', - 'Kole', - 'Roff', - 'Ballantine', - 'Basden', - 'Cadenas', - 'Caliendo', - 'Hotard', - 'Vidrio', - 'Lichtman', - 'Devinney', - 'Fugitt', - 'Proud', - 'Hults', - 'Galey', - 'Verna', - 'Newburn', - 'Lafortune', - 'Fobbs', - 'Azure', - 'Cheong', - 'Heft', - 'Aispuro', - 'Longstreth', - 'Lajeunesse', - 'Howle', - 'Galley', - 'Lovan', - 'Convery', - 'Malatesta', - 'Warnecke', - 'Glavin', - 'Reil', - 'Filson', - 'Poage', - 'Fountaine', - 'Nolley', - 'Raglin', - 'Backlund', - 'Doerfler', - 'Faunce', - 'Hooton', - 'Lightcap', - 'Stepanek', - 'Grosser', - 'Weld', - 'Filippi', - 'Youn', - 'Matis', - 'Harnett', - 'Ferrill', - 'Segers', - 'Ponds', - 'Cuyler', - 'Faile', - 'Flaugher', - 'Kuehner', - 'Giorgi', - 'Eckler', - 'Sergeant', - 'Twiggs', - 'Boeck', - 'Flach', - 'Iliff', - 'Mcmurtrey', - 'Mcnelis', - 'Steckel', - 'Rouillard', - 'Folkerts', - 'Mechling', - 'Whitcher', - 'Daws', - 'Joly', - 'Abt', - 'Eells', - 'Niccum', - 'Twining', - 'Grinder', - 'Melrose', - 'Yarbro', - 'Degenhardt', - 'Dimeglio', - 'Okamura', - 'Kriss', - 'Payette', - 'Chui', - 'Mowers', - 'Foose', - 'Kinzie', - 'Blick', - 'Rizer', - 'Alcock', - 'Sirmans', - 'Behrman', - 'Carsten', - 'Kopacz', - 'Randhawa', - 'Schwing', - 'Burkhard', - 'Cunanan', - 'Exley', - 'Balducci', - 'Leman', - 'Hyslop', - 'Burtch', - 'Hadnot', - 'Lanphear', - 'Finchum', - 'Voit', - 'Jock', - 'Wilhoite', - 'Officer', - 'Mayweather', - 'Ravenell', - 'Arehart', - 'Bonetti', - 'Cloer', - 'Galliher', - 'Niven', - 'Uyeda', - 'Coughenour', - 'Siddiqi', - 'Karimi', - 'Cupit', - 'Loupe', - 'Hammell', - 'Antley', - 'Ally', - 'Southers', - 'Haymond', - 'Hosley', - 'Broz', - 'Kinoshita', - 'Kohout', - 'Lipke', - 'Ostrow', - 'Teves', - 'Gaus', - 'Meiser', - 'Cravey', - 'Noss', - 'Drayer', - 'Crooms', - 'Carrano', - 'Mckechnie', - 'Uhrich', - 'Villalva', - 'Wilkening', - 'Benevides', - 'Kepple', - 'Pon', - 'Randol', - 'Leadbetter', - 'Russom', - 'Locklin', - 'Battiste', - 'Abundis', - 'Agosta', - 'Bartek', - 'Brillhart', - 'Hoffmaster', - 'Mehr', - 'Spanos', - 'Denker', - 'Kimberling', - 'Schon', - 'Felten', - 'Lightle', - 'Ramseur', - 'Branning', - 'Deblois', - 'Inocencio', - 'Maricle', - 'Nishimoto', - 'Oviatt', - 'Shunk', - 'Taddeo', - 'Villarruel', - 'Otterson', - 'Clune', - 'Seamster', - 'Dandy', - 'Cybulski', - 'Daza', - 'Eastep', - 'Faulhaber', - 'Friedberg', - 'Gentz', - 'Scola', - 'Sebesta', - 'Glinski', - 'Schoon', - 'Graeber', - 'Sinks', - 'Wee', - 'Summerall', - 'Deets', - 'Furnish', - 'Kelemen', - 'Maiorano', - 'Teachout', - 'Paquet', - 'Mcgahey', - 'Kill', - 'Horman', - 'Selders', - 'Cottman', - 'Delfin', - 'Fronk', - 'Seelig', - 'Visco', - 'Briles', - 'Castillon', - 'Suire', - 'Havey', - 'Arner', - 'Farver', - 'Marts', - 'Gean', - 'Hugh', - 'Stoney', - 'Townsel', - 'Sandquist', - 'Neidig', - 'Miser', - 'Leeth', - 'Hocutt', - 'Balcazar', - 'Caporale', - 'Guymon', - 'Horstmann', - 'Miedema', - 'Zickefoose', - 'Casterline', - 'Pfannenstiel', - 'Becht', - 'Myres', - 'Ried', - 'Vallery', - 'Bator', - 'Calise', - 'Cotterman', - 'Desautels', - 'Hinchey', - 'Kostka', - 'Orenstein', - 'Rosenau', - 'Skow', - 'Cuello', - 'Herder', - 'Cure', - 'Eadie', - 'Claggett', - 'Batie', - 'Kirwin', - 'Troia', - 'Sinnett', - 'Books', - 'Maize', - 'Tremble', - 'Sinkler', - 'Gallon', - 'Winkles', - 'Zion', - 'Walt', - 'Pearse', - 'Gathright', - 'Isakson', - 'Saeger', - 'Siegle', - 'Wittwer', - 'Modesto', - 'Bensen', - 'Royals', - 'Mccane', - 'Begaye', - 'Matuszewski', - 'Schrier', - 'Shimko', - 'Torchia', - 'Ausmus', - 'Casazza', - 'Mealer', - 'Yant', - 'Amar', - 'Callas', - 'Depaola', - 'Kintner', - 'Lech', - 'Marsico', - 'Boerger', - 'Rak', - 'Kellen', - 'Kennemer', - 'Carbo', - 'Rennick', - 'Brennen', - 'Dorrough', - 'Shealey', - 'Breyer', - 'Dilks', - 'Geske', - 'Hundt', - 'Occhipinti', - 'Strauser', - 'Schult', - 'Transue', - 'Holding', - 'Vanhorne', - 'Critchlow', - 'Steptoe', - 'Buerger', - 'Claassen', - 'Farinas', - 'Ruland', - 'Holsapple', - 'Mcclintic', - 'Bendel', - 'Muriel', - 'Mckeithan', - 'Shellman', - 'Balzano', - 'Bement', - 'Montesinos', - 'Ringle', - 'Sobotka', - 'Donahoo', - 'Dicker', - 'Harling', - 'Burkley', - 'Browner', - 'Iovino', - 'Kubala', - 'Labriola', - 'Morra', - 'Orloff', - 'Patchen', - 'Recchia', - 'Budge', - 'Glendenning', - 'Nethery', - 'Scholtz', - 'Aybar', - 'Buis', - 'Mattie', - 'Bonsall', - 'Conine', - 'Dettmer', - 'Gerding', - 'Plantz', - 'Vandorn', - 'Tremaine', - 'Ruddick', - 'Murrow', - 'Mceachin', - 'Bridgeforth', - 'Docherty', - 'Hultman', - 'Liechty', - 'Touchton', - 'Yokoyama', - 'Borth', - 'Daoud', - 'Mealy', - 'Hearst', - 'Stalling', - 'Drapeau', - 'Hellwig', - 'Longtin', - 'Rappa', - 'Tormey', - 'Vanantwerp', - 'Sabel', - 'Neagle', - 'Duet', - 'Liebert', - 'Lush', - 'Aly', - 'Behn', - 'Brereton', - 'Atienza', - 'Dubey', - 'Gennaro', - 'Miltenberger', - 'Nitschke', - 'Ragle', - 'Schumm', - 'Tangen', - 'Waibel', - 'Whitham', - 'Stallone', - 'Perritt', - 'Coody', - 'Hinch', - 'Depuy', - 'Dunkelberger', - 'Texeira', - 'Tomita', - 'Diers', - 'Elsasser', - 'Neve', - 'Clendenen', - 'Pettibone', - 'Dobyns', - 'Ciotti', - 'Dodrill', - 'Fridman', - 'Lepine', - 'Nygard', - 'Shreves', - 'Sollenberger', - 'Leinbach', - 'Diazdeleon', - 'Bourget', - 'Ramadan', - 'Allensworth', - 'Scarboro', - 'Prowell', - 'Ghee', - 'Edouard', - 'Duca', - 'Ziebell', - 'Kercher', - 'Greger', - 'Mas', - 'Shier', - 'Branca', - 'Melchior', - 'Cast', - 'Saner', - 'Beswick', - 'Carone', - 'Sobieski', - 'Zweifel', - 'Beahm', - 'Defrank', - 'Krebsbach', - 'Mericle', - 'Mcinnes', - 'Lown', - 'Brumback', - 'Clause', - 'Claborn', - 'Rollin', - 'Montford', - 'Beckles', - 'Grebe', - 'Groesbeck', - 'Guidi', - 'Mathisen', - 'Mukherjee', - 'Rotolo', - 'Seybert', - 'Odegaard', - 'Mackley', - 'Glatt', - 'Going', - 'Perks', - 'Sansbury', - 'Prude', - 'Bequette', - 'Difilippo', - 'Dodgen', - 'Terpening', - 'Vanepps', - 'Poncedeleon', - 'Qu', - 'Ullery', - 'Wisener', - 'Lok', - 'Lutton', - 'Bellah', - 'Kinsel', - 'Tone', - 'Carabajal', - 'Koll', - 'Shankar', - 'Edick', - 'Donathan', - 'Andree', - 'Perrino', - 'Moffit', - 'Gaddie', - 'Breidenbach', - 'Jespersen', - 'Larrick', - 'Mauriello', - 'Morgado', - 'Roh', - 'Svec', - 'Tebbe', - 'Thieman', - 'Cerezo', - 'Perkowski', - 'Colville', - 'Yarnall', - 'Chason', - 'Brach', - 'Meller', - 'Brayboy', - 'Salaam', - 'Keleher', - 'Kilbourn', - 'Lowenthal', - 'Rispoli', - 'Vanzee', - 'Vlahos', - 'Trojan', - 'Birdsell', - 'Defoor', - 'Mcclusky', - 'Barret', - 'Smoke', - 'Berkeley', - 'Cuadrado', - 'Galyean', - 'Gruen', - 'Gualtieri', - 'Kurland', - 'Sposato', - 'Stieber', - 'Weatherman', - 'Strausser', - 'Miera', - 'Edlin', - 'Gilford', - 'Mouzon', - 'Buczek', - 'Krapf', - 'Lucatero', - 'Amburn', - 'Peddicord', - 'Forero', - 'Domer', - 'Farish', - 'Segraves', - 'Sant', - 'Engles', - 'Douthitt', - 'Lall', - 'Wormley', - 'Geisel', - 'Hao', - 'Polhemus', - 'Slifer', - 'Mowen', - 'Markin', - 'Rape', - 'Bollin', - 'Bulloch', - 'Pouncey', - 'Rufus', - 'Goodlow', - 'Dammann', - 'Delgrosso', - 'Gadbois', - 'Leap', - 'Lorentzen', - 'Sprankle', - 'Stucki', - 'Vitela', - 'Walck', - 'Winkelmann', - 'Mund', - 'Bley', - 'Channel', - 'Griebel', - 'Nordberg', - 'Slinkard', - 'Orrick', - 'Crooker', - 'Groll', - 'Maradiaga', - 'Jolin', - 'Boni', - 'Prom', - 'Reder', - 'Easler', - 'Totty', - 'Arnaud', - 'Bohler', - 'Heikkila', - 'Kehler', - 'Klingenberg', - 'Matera', - 'Striegel', - 'Urzua', - 'Baldi', - 'Burling', - 'Osmond', - 'Rucks', - 'Diel', - 'Kassel', - 'Schewe', - 'Conkling', - 'Ricke', - 'Schack', - 'Shirah', - 'Brauner', - 'Carriker', - 'Mcduffy', - 'Bieker', - 'Credeur', - 'Fabry', - 'Holdeman', - 'Jeansonne', - 'Klett', - 'Kolstad', - 'Mustain', - 'Strub', - 'Ricketson', - 'Fairbairn', - 'Langel', - 'Fenster', - 'Slatton', - 'Ehrenberg', - 'Espinola', - 'Hannaford', - 'Hinderliter', - 'Siqueiros', - 'Ange', - 'Gillin', - 'Battin', - 'Belue', - 'Spigner', - 'Simien', - 'Gervasi', - 'Pallares', - 'Plotner', - 'Puri', - 'Swiatek', - 'Vanmatre', - 'Corp', - 'Devillier', - 'Bucholtz', - 'Bremner', - 'Jen', - 'Evanson', - 'Ghent', - 'Eastland', - 'Kappler', - 'Grahn', - 'Shadrick', - 'Kibby', - 'Chaires', - 'Kontos', - 'Petrov', - 'Pillai', - 'Chadbourne', - 'Sotolongo', - 'Allende', - 'Kells', - 'Hayford', - 'Hempstead', - 'Livers', - 'Farrior', - 'Authement', - 'Bitz', - 'Corkery', - 'Klawitter', - 'Mongold', - 'Somma', - 'Topham', - 'Defrancisco', - 'Noda', - 'Breon', - 'Thetford', - 'Rod', - 'Kisling', - 'Drouillard', - 'Dotts', - 'Gramajo', - 'Masek', - 'Volkert', - 'Vora', - 'Pietras', - 'Sheffler', - 'Shrestha', - 'Kono', - 'Panza', - 'Brunn', - 'Tatom', - 'Nasir', - 'Barris', - 'Bursey', - 'Elsea', - 'Kettner', - 'Martorana', - 'Lindow', - 'Chevez', - 'Pater', - 'Hennis', - 'Iman', - 'Stembridge', - 'Satcher', - 'Britz', - 'Hommel', - 'Llanas', - 'Pathak', - 'Schwartzman', - 'Janz', - 'Hickle', - 'Deakins', - 'Mantle', - 'Billing', - 'Veiga', - 'Darbonne', - 'Angelle', - 'Granderson', - 'Odoms', - 'Mondesir', - 'Ducksworth', - 'Anker', - 'Deneen', - 'Follmer', - 'Norred', - 'Whitecotton', - 'Halsted', - 'Schiele', - 'Reddin', - 'Pichon', - 'Eustice', - 'Finelli', - 'Kawasaki', - 'Kerekes', - 'Surrett', - 'Divers', - 'Kerney', - 'Bohlman', - 'Oberst', - 'Prough', - 'Tarwater', - 'Wangler', - 'Piceno', - 'Persico', - 'Lastra', - 'Fillman', - 'Barlett', - 'Cort', - 'Kuchar', - 'Plaisted', - 'Rufo', - 'Whitmarsh', - 'Fusaro', - 'Bajwa', - 'Belter', - 'Aldama', - 'Conlee', - 'Tweedie', - 'Greear', - 'Riviera', - 'Stormer', - 'Flannagan', - 'Heatley', - 'Feazell', - 'Bastidas', - 'Benninger', - 'Canseco', - 'Hanners', - 'Kreiner', - 'Pestana', - 'Simerly', - 'Such', - 'Tiedeman', - 'Weible', - 'Zawadzki', - 'Rayman', - 'Crose', - 'Sheeler', - 'Kirven', - 'Winford', - 'Mackall', - 'Balderson', - 'Calleja', - 'Klinefelter', - 'Lauffer', - 'Probert', - 'Melero', - 'Ravelo', - 'Degroff', - 'Pylant', - 'Ricco', - 'Varona', - 'Pickney', - 'Bachmeier', - 'Dulay', - 'Hanover', - 'Virgilio', - 'Spino', - 'Bohon', - 'Cantin', - 'Pettijohn', - 'Branigan', - 'Duhe', - 'Perine', - 'Thedford', - 'Shamburger', - 'Guarnieri', - 'Guptill', - 'Nyland', - 'Setliff', - 'Shreffler', - 'Viggiano', - 'Pries', - 'Sunde', - 'Bulmer', - 'Platts', - 'Jeremiah', - 'Fawley', - 'Jansson', - 'Rebelo', - 'Prochnow', - 'Waldeck', - 'Citron', - 'Roughton', - 'Ryckman', - 'Molano', - 'Cannaday', - 'Ned', - 'Beckerman', - 'Galaz', - 'Graziani', - 'Kawakami', - 'Limones', - 'Mousseau', - 'Riha', - 'Huser', - 'Casady', - 'Kirker', - 'Benish', - 'Tomczyk', - 'Hallahan', - 'Kue', - 'Siple', - 'Kandel', - 'Maring', - 'Bosak', - 'Gandolfo', - 'Reichart', - 'Robarge', - 'Shufelt', - 'Forry', - 'Richart', - 'Shireman', - 'Tozzi', - 'Trudel', - 'Tat', - 'Maday', - 'Faw', - 'Lawrie', - 'Mingle', - 'Yasin', - 'Cutrone', - 'Fairbrother', - 'Ficken', - 'Kluesner', - 'Lagana', - 'Schoenborn', - 'Greb', - 'Stromain', - 'Mcpeters', - 'Toepfer', - 'Wehrman', - 'Kozma', - 'Rohner', - 'Kittel', - 'Louderback', - 'Daughtrey', - 'Philippe', - 'Bargo', - 'Cullinane', - 'Fama', - 'Fredenburg', - 'Pedone', - 'Santillanes', - 'Zahner', - 'Zupan', - 'Dundon', - 'Gilfillan', - 'Grego', - 'Otter', - 'Jamil', - 'Beaubien', - 'Collingwood', - 'Quinney', - 'Botero', - 'Edstrom', - 'Flink', - 'Ortner', - 'Schmidtke', - 'Reichle', - 'Leder', - 'Pelosi', - 'Fiorito', - 'Berber', - 'Hislop', - 'Dunstan', - 'Favorite', - 'Wooding', - 'Gariepy', - 'Gottesman', - 'Guercio', - 'Konz', - 'Kothari', - 'Laguardia', - 'Lamphier', - 'Puetz', - 'Casagrande', - 'Quay', - 'Rieth', - 'Vowell', - 'Mcanulty', - 'Mian', - 'Lucus', - 'Alvizo', - 'Domanski', - 'Elling', - 'Maniaci', - 'Neumeyer', - 'Piraino', - 'Schroll', - 'Willsey', - 'Avellaneda', - 'Wilcoxen', - 'Murrey', - 'Bennette', - 'Boyajian', - 'Distler', - 'Lindamood', - 'Maclaren', - 'Onken', - 'Stefano', - 'Uselton', - 'Wilgus', - 'Rardin', - 'Boen', - 'Stillwagon', - 'Satter', - 'Allis', - 'Capell', - 'Nedd', - 'Arcand', - 'Breit', - 'Horwath', - 'Lakatos', - 'Roling', - 'Hessel', - 'Cusson', - 'Rockefeller', - 'Shiffer', - 'Briney', - 'Celeste', - 'Sayed', - 'Revelle', - 'Corker', - 'Baldonado', - 'Lokken', - 'Plymale', - 'Sugden', - 'Twist', - 'Parten', - 'Geil', - 'Sime', - 'Grisby', - 'Jeanty', - 'Baroni', - 'Ditullio', - 'Domenico', - 'Geiss', - 'Gemmill', - 'Leng', - 'Lewicki', - 'Weyandt', - 'Haycock', - 'Coonce', - 'Pillar', - 'Medcalf', - 'Sall', - 'Goldsborough', - 'Bergerson', - 'Daffron', - 'Hinchman', - 'Leibold', - 'Sarkissian', - 'Serratos', - 'Uhlig', - 'Wurth', - 'Ost', - 'Steinmann', - 'Saum', - 'Bullion', - 'Dejonge', - 'Assad', - 'Adelson', - 'Sholes', - 'Clermont', - 'Tabron', - 'Kilduff', - 'Millspaugh', - 'Partyka', - 'Santore', - 'Wensel', - 'Zima', - 'Raschke', - 'Simonis', - 'Tuell', - 'Obriant', - 'Lewter', - 'Nealey', - 'Baranski', - 'Bloomberg', - 'Franchi', - 'Klemme', - 'Raborn', - 'Wohlgemuth', - 'Basta', - 'Bernardini', - 'Canlas', - 'Yeargin', - 'Stingley', - 'Crosland', - 'Bob', - 'Ascher', - 'Dibona', - 'Farabaugh', - 'Kilcoyne', - 'Poblete', - 'Beato', - 'Teasdale', - 'Rossell', - 'Lawhorne', - 'Jama', - 'Behringer', - 'Hallstrom', - 'Kitzman', - 'Klenk', - 'Mctigue', - 'Onate', - 'Rodda', - 'Siegal', - 'Pepple', - 'Tash', - 'Gager', - 'Hing', - 'Yokley', - 'Epting', - 'Mangham', - 'Zackery', - 'Blackerby', - 'Canedo', - 'Glatz', - 'Hilker', - 'Hummell', - 'Mangels', - 'Gamel', - 'Gang', - 'Hooser', - 'Moates', - 'Mutch', - 'Lyerly', - 'Vesey', - 'Satterthwaite', - 'Calcote', - 'Saulsbury', - 'Averette', - 'Ates', - 'Rita', - 'Vicencio', - 'Wismer', - 'Mayoral', - 'Crader', - 'Levens', - 'Joel', - 'Haye', - 'Drager', - 'Eiden', - 'Escutia', - 'Inzunza', - 'Moroz', - 'Sepulvado', - 'Tomaselli', - 'Zartman', - 'Isaak', - 'Philippi', - 'Mcgeary', - 'Taha', - 'Buttler', - 'Crisci', - 'Kot', - 'Micek', - 'Mondello', - 'Petrarca', - 'Rossini', - 'Villalvazo', - 'Weedman', - 'Mitten', - 'Favre', - 'Varnes', - 'Betancur', - 'Bevington', - 'Bockman', - 'Feldstein', - 'Kujawski', - 'Siemer', - 'Soderlund', - 'Fricker', - 'Gerstein', - 'Kick', - 'Haff', - 'Brackman', - 'Hulen', - 'Nephew', - 'Birkett', - 'Gardenhire', - 'Garn', - 'Kellenberger', - 'Mogensen', - 'Murata', - 'Weisbrod', - 'Vilchis', - 'Meder', - 'Akey', - 'Mcmanis', - 'Delatte', - 'Guiles', - 'Turnbough', - 'Murrah', - 'Kilgo', - 'Marcelin', - 'Cecchini', - 'Chrysler', - 'Eick', - 'Fletes', - 'Luevanos', - 'Kurt', - 'Firman', - 'Hensen', - 'Champine', - 'Holford', - 'Appelbaum', - 'Ciampa', - 'Florentino', - 'Lorton', - 'Lubinski', - 'Moquin', - 'Welke', - 'Grinberg', - 'Bolstad', - 'Ade', - 'Outten', - 'Grear', - 'Haith', - 'Borntreger', - 'Steinhauser', - 'Facio', - 'Preslar', - 'Speirs', - 'Grasser', - 'Zuck', - 'Deslauriers', - 'Frates', - 'Mayville', - 'Suddeth', - 'Littlepage', - 'Aversa', - 'Chagolla', - 'Godshall', - 'Jordahl', - 'Oakland', - 'Monsen', - 'Rudolf', - 'Mccollister', - 'Mickles', - 'Flaig', - 'Friberg', - 'Grubaugh', - 'Sliwinski', - 'Stach', - 'Bechtol', - 'Pasch', - 'Keebler', - 'Fagin', - 'Mister', - 'Wynter', - 'Bednarek', - 'Blansett', - 'Crossett', - 'Kettering', - 'Lafata', - 'Raffa', - 'Roig', - 'Schopp', - 'Voegele', - 'Waldschmidt', - 'Clatterbuck', - 'Amer', - 'Kraut', - 'Furniss', - 'Edgecomb', - 'Aspinwall', - 'Buckelew', - 'Loranger', - 'Koppel', - 'Vernier', - 'Latino', - 'Hayton', - 'Girod', - 'Primrose', - 'Jetter', - 'Hyche', - 'Ottley', - 'Isidro', - 'Kort', - 'Mulroy', - 'Reznik', - 'Tozer', - 'Vanderheyden', - 'Kassab', - 'Paro', - 'Belen', - 'Vandever', - 'Harsch', - 'Rawley', - 'Gonder', - 'Delbridge', - 'Alumbaugh', - 'Basulto', - 'Hoehne', - 'Mccaig', - 'Qin', - 'Rasnake', - 'Tewksbury', - 'Ratajczak', - 'Reinbold', - 'Mcgillivray', - 'Nuccio', - 'Steinbeck', - 'Deland', - 'Callow', - 'Wootten', - 'Lytton', - 'Calix', - 'Stinger', - 'Slider', - 'Cadman', - 'Faulconer', - 'Higashi', - 'Lamping', - 'Sellner', - 'Walko', - 'Kilkenny', - 'Charter', - 'Gauntt', - 'Bronk', - 'Legare', - 'Hukill', - 'Kulikowski', - 'Kunde', - 'Michelsen', - 'Mottola', - 'Pasion', - 'Stimmel', - 'Deavila', - 'Lian', - 'Koga', - 'Kitchin', - 'Whitner', - 'Bucholz', - 'Kilbride', - 'Klumpp', - 'Osinski', - 'Petrich', - 'Saar', - 'Robards', - 'Flakes', - 'Accardo', - 'Gebauer', - 'Matyas', - 'Montesano', - 'Schiefer', - 'Zuehlke', - 'Swartout', - 'Gidley', - 'Burghardt', - 'Delcambre', - 'Jerman', - 'Laufenberg', - 'Paterno', - 'Piccione', - 'Wenning', - 'Wilhelmi', - 'Rathjen', - 'Bauch', - 'Hiott', - 'Bagnall', - 'Miskell', - 'Snellings', - 'Sally', - 'Bjornson', - 'Din', - 'Kroeker', - 'Mitra', - 'Saxena', - 'Hausler', - 'Scogin', - 'Jeronimo', - 'Holderfield', - 'Cruze', - 'Christina', - 'Beville', - 'Whitehorn', - 'Bembry', - 'Fludd', - 'Abboud', - 'Blomgren', - 'Friddle', - 'Jarvi', - 'Nastasi', - 'Tomich', - 'Peinado', - 'Rinaldo', - 'Proudfoot', - 'Down', - 'Lawry', - 'Noor', - 'Bachelor', - 'Mullenax', - 'Pocock', - 'Resler', - 'Sprunger', - 'Wiegel', - 'Wohlers', - 'Niedzwiecki', - 'Bourgoin', - 'Grist', - 'Nora', - 'Gude', - 'Mcgaughy', - 'Borror', - 'Bushee', - 'Crego', - 'Engberg', - 'Karle', - 'Raso', - 'Rayas', - 'Roehrig', - 'Villamil', - 'Croucher', - 'Candido', - 'Rockhill', - 'Dahn', - 'Philp', - 'Grasty', - 'Basnight', - 'Cacioppo', - 'Heavener', - 'Hoenig', - 'Janisch', - 'Labombard', - 'Sheng', - 'Wettstein', - 'Wymore', - 'Zuluaga', - 'Canova', - 'Maclennan', - 'Tuley', - 'Geddings', - 'Cayetano', - 'Bogar', - 'Malbrough', - 'Bradish', - 'Chiaramonte', - 'Eguia', - 'Loux', - 'Nemecek', - 'Ouimet', - 'Roxas', - 'Yoshioka', - 'Cossio', - 'Sleight', - 'Walla', - 'Younan', - 'Hee', - 'Bartlow', - 'Parchman', - 'Leaks', - 'Folz', - 'Knittel', - 'Lovvorn', - 'Melick', - 'Weingartner', - 'Eustace', - 'Robbs', - 'Jacquet', - 'Direnzo', - 'Domke', - 'Kestler', - 'Pavelka', - 'Pileggi', - 'Silvestro', - 'Leedom', - 'Kyte', - 'Espey', - 'Kincannon', - 'Robicheaux', - 'Lard', - 'Falkenstein', - 'Fino', - 'Kotz', - 'Lammert', - 'Markovic', - 'Mcwaters', - 'Shibata', - 'Garoutte', - 'Brum', - 'Hora', - 'Gundrum', - 'Leer', - 'Coller', - 'Delsignore', - 'Ebarb', - 'Heras', - 'Skolnick', - 'Sponseller', - 'Baltes', - 'Rabinovich', - 'Welden', - 'Papas', - 'Bingman', - 'Neto', - 'Burrough', - 'Ollie', - 'Deitrick', - 'Hermansen', - 'Datta', - 'Gebo', - 'Bulla', - 'Rippey', - 'Solon', - 'Draughon', - 'Sylvestre', - 'Outen', - 'Westfield', - 'Daoust', - 'Kuan', - 'Kubat', - 'Labuda', - 'Olejniczak', - 'Radomski', - 'Scheuermann', - 'Schunk', - 'Tuazon', - 'Wineland', - 'Gizzi', - 'Millay', - 'Hamp', - 'Murdaugh', - 'Hayles', - 'Plowden', - 'Lesure', - 'Artrip', - 'Kenneally', - 'Piehl', - 'Vandermeulen', - 'Camberos', - 'Hochberg', - 'Sinner', - 'Crass', - 'Gade', - 'Tedrick', - 'Nicholl', - 'Speece', - 'Chatterjee', - 'Gillihan', - 'Luzzi', - 'Obyrne', - 'Uchida', - 'Kidney', - 'Dorough', - 'Dangler', - 'Mcneel', - 'Ruley', - 'Mcloud', - 'Smarr', - 'Gayles', - 'Janiszewski', - 'Kubo', - 'Mckibbin', - 'Szatkowski', - 'Lehnert', - 'Mcilvain', - 'Mcclish', - 'Mcentyre', - 'Strawder', - 'Briere', - 'Headlee', - 'Leszczynski', - 'Mauser', - 'Rask', - 'Wisler', - 'Burba', - 'Shaulis', - 'Showman', - 'Proto', - 'Creasman', - 'Slye', - 'Dunwoody', - 'Ellingsworth', - 'Linebaugh', - 'Riva', - 'Um', - 'Muldowney', - 'Burlew', - 'Gettings', - 'Clingman', - 'Shield', - 'Trollinger', - 'Stiger', - 'Kellman', - 'Arviso', - 'Boettger', - 'Deak', - 'Deiter', - 'Hackenberg', - 'Langone', - 'Lichter', - 'Siano', - 'Wrinkle', - 'Dickert', - 'Boor', - 'Ludington', - 'Griffing', - 'Perin', - 'Woodby', - 'Quail', - 'Harriss', - 'Bilotta', - 'Chino', - 'Cocke', - 'Corbell', - 'Dearden', - 'Facundo', - 'Gaskell', - 'Grieser', - 'Houts', - 'Zuk', - 'Yamauchi', - 'Caouette', - 'Perham', - 'Hewson', - 'Keppel', - 'Artiaga', - 'Sa', - 'Ginger', - 'Goosby', - 'Bollig', - 'Grippo', - 'Hoffmeyer', - 'Klaas', - 'Rohlfing', - 'Stolp', - 'Vielma', - 'Gresh', - 'Mignone', - 'Parsell', - 'Sprout', - 'Hase', - 'Nadal', - 'Joye', - 'Butkus', - 'Donlan', - 'Fuhrer', - 'Grobe', - 'Haverkamp', - 'Janecek', - 'Pancoast', - 'Rathke', - 'Scheibe', - 'Schneller', - 'Scally', - 'Valeriano', - 'Fail', - 'Everage', - 'Murff', - 'Demayo', - 'Dieterich', - 'Kramp', - 'Macchia', - 'Ruyle', - 'Zuidema', - 'Tischer', - 'Palo', - 'Bahn', - 'Hartson', - 'Rosborough', - 'Hartke', - 'Hixenbaugh', - 'Matlack', - 'Hoefler', - 'Hsia', - 'Cech', - 'Donham', - 'Szafranski', - 'Jennison', - 'Emmer', - 'Christians', - 'Swigert', - 'Mclawhorn', - 'Costas', - 'Culligan', - 'Eisenstein', - 'Joos', - 'Villacorta', - 'Majerus', - 'Lukowski', - 'Byford', - 'Canepa', - 'Jeppson', - 'Larison', - 'Waechter', - 'Bleich', - 'Trigo', - 'Lill', - 'Mcisaac', - 'Oflaherty', - 'Dedman', - 'Lynes', - 'Everidge', - 'Armfield', - 'Cadieux', - 'Dembowski', - 'Flewelling', - 'Guadagno', - 'Lamendola', - 'Meidinger', - 'Muzzy', - 'Pacelli', - 'Pangle', - 'Denzer', - 'Sharman', - 'Venzor', - 'Shadwick', - 'Saine', - 'Lighty', - 'Twine', - 'Buehner', - 'Caruana', - 'Filipiak', - 'Fiori', - 'Kellison', - 'Odonovan', - 'Ragone', - 'Enyeart', - 'Coale', - 'Coombes', - 'Yarrington', - 'Leno', - 'Coad', - 'Well', - 'Labranche', - 'Banaszak', - 'Jovanovic', - 'Junk', - 'Kratochvil', - 'Marchi', - 'Mcnitt', - 'Monnin', - 'Portales', - 'Nazzaro', - 'Laramie', - 'Kohlman', - 'Pinette', - 'Craw', - 'Aldred', - 'Jolicoeur', - 'Nevers', - 'Boseman', - 'Apostol', - 'Barbaro', - 'Dirienzo', - 'Kimrey', - 'Knaack', - 'Marenco', - 'Meixner', - 'Placek', - 'Prigge', - 'Sablan', - 'Stoecker', - 'Ulrey', - 'Madonia', - 'Mariotti', - 'Hypes', - 'Teti', - 'Pothier', - 'Duer', - 'Reay', - 'Charlie', - 'Alix', - 'Cropp', - 'Wellons', - 'Haugland', - 'Malkowski', - 'Powley', - 'Query', - 'Stolle', - 'Twedt', - 'Grech', - 'Musson', - 'Larrimore', - 'Esper', - 'Suleiman', - 'Gillie', - 'Aaronson', - 'Brueggeman', - 'Kupfer', - 'Orf', - 'Pozzi', - 'Rayos', - 'Scheiner', - 'Schmoll', - 'Sirota', - 'Trickey', - 'Ahuja', - 'Halm', - 'Jaycox', - 'Carithers', - 'Bjorkman', - 'Klar', - 'Lembke', - 'Nordyke', - 'Primeau', - 'Wachs', - 'Wissinger', - 'Doonan', - 'Mikulski', - 'Murthy', - 'Raju', - 'Thrailkill', - 'Splawn', - 'Lockamy', - 'Brassell', - 'Mcshan', - 'Hawbaker', - 'Kracht', - 'Lahman', - 'Lauritsen', - 'Metzner', - 'Presser', - 'Rapoport', - 'Romani', - 'Wolken', - 'Bertone', - 'Bhat', - 'Lenzi', - 'Lefort', - 'Makar', - 'Melnyk', - 'Siguenza', - 'Ristow', - 'Piller', - 'Mcgaugh', - 'Lampton', - 'Delva', - 'Gethers', - 'Leday', - 'Bateson', - 'Beckstrom', - 'Bedsole', - 'Hauber', - 'Hodgkinson', - 'Croghan', - 'Glanz', - 'Gaver', - 'Pinkley', - 'Traynham', - 'Heffley', - 'Indelicato', - 'Lindblad', - 'Petrik', - 'Ptacek', - 'Capen', - 'Carrara', - 'Ortuno', - 'Lobue', - 'Corella', - 'Lybrand', - 'Myler', - 'Steer', - 'Mckamey', - 'Coman', - 'Auker', - 'Escue', - 'Knell', - 'Mahood', - 'Tillinghast', - 'Deremer', - 'Janak', - 'Naegele', - 'Patnaude', - 'Leahey', - 'Pupo', - 'Bouse', - 'Bradstreet', - 'Symes', - 'Callies', - 'Duncanson', - 'Blanche', - 'Span', - 'Shakir', - 'Finneran', - 'Lenker', - 'Mendola', - 'Navin', - 'Palka', - 'Spanier', - 'Stahler', - 'Vannatter', - 'Botta', - 'Gonser', - 'Edelson', - 'Brashier', - 'Golla', - 'Parramore', - 'Bigby', - 'El', - 'Habeck', - 'Kleinhans', - 'Knobel', - 'Pekar', - 'Remmers', - 'Dea', - 'Foo', - 'Plumer', - 'Combest', - 'Godbee', - 'Hilaire', - 'Lepak', - 'Sgro', - 'Vierling', - 'Harm', - 'Holtsclaw', - 'Gaetano', - 'Kindler', - 'Sabbagh', - 'Politte', - 'Amor', - 'Tilly', - 'Trone', - 'Callaham', - 'Roussell', - 'Asplund', - 'Cacciatore', - 'Dries', - 'Friedl', - 'Hartranft', - 'Kimmell', - 'Lengacher', - 'Scardino', - 'Werley', - 'Zappa', - 'Hust', - 'Seiden', - 'Bultman', - 'Withey', - 'Brandow', - 'Oler', - 'Ladouceur', - 'Celli', - 'Condie', - 'Egge', - 'Kleman', - 'Krafft', - 'Margulies', - 'Weier', - 'Mikels', - 'Pavel', - 'Sigel', - 'Foulke', - 'Kluttz', - 'Mcgown', - 'Acero', - 'Gering', - 'Knauff', - 'Ruesch', - 'Rydberg', - 'Shonk', - 'Weisgerber', - 'Wieber', - 'Zinser', - 'Lilienthal', - 'Crosbie', - 'Luckie', - 'Chenier', - 'Aceto', - 'Atnip', - 'Hisey', - 'Imhof', - 'Klocke', - 'Renderos', - 'Schaad', - 'Shoults', - 'Slevin', - 'Tenenbaum', - 'Vrana', - 'Dicesare', - 'Colarusso', - 'Killgore', - 'Courtois', - 'Tysinger', - 'Agard', - 'Brutus', - 'Woodfork', - 'Boeckman', - 'Breitenstein', - 'Downen', - 'Franzese', - 'Garbe', - 'Iannucci', - 'Kist', - 'Mccolgan', - 'Seib', - 'Sereno', - 'Varma', - 'Fought', - 'Barcomb', - 'Happ', - 'Yeaton', - 'Sharples', - 'Huson', - 'Askin', - 'Elliston', - 'Birks', - 'Allums', - 'Richarson', - 'Arterburn', - 'Auyeung', - 'Engman', - 'Segall', - 'Sjoberg', - 'Sturman', - 'Buys', - 'Basford', - 'Gaut', - 'Hollomon', - 'Antal', - 'Groseclose', - 'Motyka', - 'Reddell', - 'Ansel', - 'Fausett', - 'Girgis', - 'Brownson', - 'Pouncy', - 'Behler', - 'Ciesla', - 'Dewall', - 'Helmers', - 'Pizzuto', - 'Sao', - 'Hourigan', - 'Novelli', - 'Kuta', - 'Gau', - 'Verville', - 'Parkison', - 'Souter', - 'Whitelaw', - 'Vercher', - 'Coger', - 'Issac', - 'Cardamone', - 'Heneghan', - 'Herrero', - 'Plancarte', - 'Reach', - 'Sarinana', - 'Zweig', - 'Berkheimer', - 'Brosseau', - 'Angstadt', - 'Popoca', - 'Brode', - 'Presswood', - 'Hannibal', - 'Pigford', - 'Argento', - 'Dieringer', - 'Kinnett', - 'Maclachlan', - 'Perko', - 'Rosenkranz', - 'Kobus', - 'Merk', - 'Prevatte', - 'Kaya', - 'Didio', - 'Thong', - 'Cowin', - 'Tumlin', - 'Lopp', - 'Callier', - 'Sesay', - 'Beerman', - 'Creger', - 'Eyster', - 'Libbey', - 'Minear', - 'Pontious', - 'Stemen', - 'Strahl', - 'Trillo', - 'Dively', - 'Lackner', - 'Welte', - 'Likes', - 'Mazzoni', - 'Resh', - 'Oser', - 'Dilday', - 'Requena', - 'Bail', - 'Ellen', - 'Buchanon', - 'Almeda', - 'Dimino', - 'Griess', - 'Wetzler', - 'Kriegel', - 'Attanasio', - 'Reighard', - 'Alling', - 'Wiginton', - 'Penfield', - 'Barbe', - 'Alred', - 'Ridout', - 'Lucien', - 'Cerullo', - 'Esterline', - 'Garriott', - 'Hendershott', - 'Kaczmarczyk', - 'Pazos', - 'Racicot', - 'Kowaleski', - 'Lippold', - 'Bankert', - 'Emigh', - 'Cupps', - 'Jagger', - 'Leavens', - 'Lies', - 'Ater', - 'Bleau', - 'Pellot', - 'Crosslin', - 'Faulks', - 'Antwine', - 'Calixte', - 'Brod', - 'Hamad', - 'Junkin', - 'Koeppel', - 'Leifer', - 'Vannest', - 'Olcott', - 'Delange', - 'Hillen', - 'Merlin', - 'Gundy', - 'Hogans', - 'Arseneau', - 'Buzard', - 'Ewalt', - 'Persing', - 'Pursel', - 'Rohrs', - 'Sisemore', - 'Vilchez', - 'Bernath', - 'Rosenbalm', - 'Woolverton', - 'Gibbins', - 'Like', - 'Larsson', - 'Savidge', - 'Strohmeyer', - 'Trentham', - 'Wotring', - 'Boster', - 'Sewall', - 'Glore', - 'Burtis', - 'Marchman', - 'Fouche', - 'Okafor', - 'Khatri', - 'Lengel', - 'Pribyl', - 'Rodewald', - 'Cafaro', - 'Mattix', - 'Shingler', - 'Seawell', - 'Square', - 'Belnap', - 'Heidemann', - 'Kretz', - 'Nebeker', - 'Zemke', - 'Reiners', - 'Cassels', - 'Hout', - 'Favor', - 'Rattray', - 'Custard', - 'Bellucci', - 'Bucklew', - 'Casavant', - 'Davanzo', - 'Kleber', - 'Koeppen', - 'Kulpa', - 'Ledonne', - 'Scarano', - 'Schaar', - 'Staiger', - 'Trigueros', - 'Trobaugh', - 'Tufano', - 'Tschetter', - 'Labra', - 'Beverage', - 'Hulet', - 'Stairs', - 'Waggener', - 'Candy', - 'Kaba', - 'Feiner', - 'Ipock', - 'Nelligan', - 'Pottorff', - 'Beno', - 'Beausoleil', - 'Mayen', - 'Kalil', - 'Deller', - 'Cormack', - 'Hayne', - 'Below', - 'Bundick', - 'Avakian', - 'Desmet', - 'Dobler', - 'Dykeman', - 'Eckstrom', - 'Mahle', - 'Meers', - 'Bortner', - 'Kroon', - 'Lindenmuth', - 'Mcnichol', - 'Sechrest', - 'Abdulla', - 'Gaudin', - 'Lamers', - 'Luffman', - 'Marchione', - 'Paredez', - 'Polster', - 'Maresh', - 'Kristoff', - 'Rickel', - 'Frary', - 'Lorance', - 'Round', - 'Toye', - 'Claybrook', - 'Senegal', - 'Gayhart', - 'Mcmackin', - 'Sagan', - 'Sarkar', - 'Whistler', - 'Stutsman', - 'Alderfer', - 'Spainhour', - 'Karol', - 'Ke', - 'Mifflin', - 'Salah', - 'Alberty', - 'Hynson', - 'Beisel', - 'Castelo', - 'Dau', - 'Diliberto', - 'Dollins', - 'Fiorini', - 'Fritzler', - 'Hanan', - 'Hauschild', - 'Overholser', - 'Wrobleski', - 'Peil', - 'Bellon', - 'Buice', - 'Rolls', - 'Shack', - 'Arakelian', - 'Carpino', - 'Liou', - 'Lydick', - 'Supple', - 'Tammaro', - 'Walbridge', - 'Jandreau', - 'Riter', - 'Roeser', - 'Merson', - 'Bole', - 'Franey', - 'Berrett', - 'Carton', - 'Mcnish', - 'Earnhart', - 'Lehrman', - 'Lipski', - 'Mandelbaum', - 'Tanabe', - 'Mirabile', - 'Ocegueda', - 'Clementi', - 'Shake', - 'Buckle', - 'Rowsey', - 'Eifert', - 'Giesen', - 'Standiford', - 'Vallecillo', - 'Walworth', - 'Berkshire', - 'Feit', - 'Lande', - 'Fiddler', - 'Deputy', - 'Feemster', - 'Evelyn', - 'Bocchino', - 'Cozza', - 'Dirocco', - 'Kock', - 'Luisi', - 'Marcantonio', - 'Presti', - 'Rahimi', - 'Ridinger', - 'Sergi', - 'Viana', - 'Kabat', - 'Suriel', - 'Mester', - 'Bozman', - 'Huffines', - 'Linck', - 'Lodato', - 'Ownbey', - 'Pietz', - 'Rudnicki', - 'Schoener', - 'Schrag', - 'Spicher', - 'Sze', - 'Villella', - 'Steinle', - 'Seaberg', - 'Derks', - 'Mavis', - 'Luellen', - 'Garlington', - 'Nimmons', - 'Brevard', - 'Seabrooks', - 'Ahlquist', - 'Golembiewski', - 'Kochis', - 'Popov', - 'Poulter', - 'Redington', - 'Wingrove', - 'Krepps', - 'Viars', - 'Gallatin', - 'Gilham', - 'Jimison', - 'Glosson', - 'Campeau', - 'Goodhart', - 'Koth', - 'Lettieri', - 'Siragusa', - 'Sojka', - 'Tichy', - 'Viar', - 'Carrozza', - 'Chaffins', - 'Eagleson', - 'Prestwood', - 'Deshazer', - 'Ike', - 'Kubacki', - 'Minogue', - 'Sunseri', - 'Turnbaugh', - 'Heminger', - 'Delira', - 'Jani', - 'Platte', - 'Waterson', - 'Keeble', - 'Kiper', - 'Crigler', - 'Swaby', - 'Brisbin', - 'Galiano', - 'Negley', - 'Regal', - 'Stottlemyer', - 'Volkmann', - 'Herrold', - 'Cypert', - 'Markman', - 'Laman', - 'Williard', - 'Terrio', - 'Raulston', - 'Harrow', - 'Humiston', - 'Kantner', - 'Mcmonagle', - 'Polasek', - 'Ruocco', - 'Schelling', - 'Seip', - 'Woller', - 'Despres', - 'Melius', - 'Keiffer', - 'Voges', - 'Figg', - 'Judice', - 'Henery', - 'Dejarnette', - 'Prosper', - 'Duenez', - 'Frenette', - 'Jaimez', - 'Krist', - 'Kuch', - 'Schlachter', - 'Traeger', - 'Mrozinski', - 'Colberg', - 'Lade', - 'Been', - 'Revere', - 'Greely', - 'Belizaire', - 'Amberg', - 'Cerniglia', - 'Lattanzio', - 'Leitz', - 'Ocker', - 'Ratto', - 'Thornburgh', - 'Yule', - 'Hibner', - 'Puerto', - 'Shoultz', - 'Baley', - 'Linley', - 'Alfrey', - 'Bazaldua', - 'Deniz', - 'Lohnes', - 'Marder', - 'Pelland', - 'Urick', - 'Loberg', - 'Rempel', - 'Faux', - 'Tomkins', - 'Gail', - 'Mccardell', - 'Reuben', - 'Brabant', - 'Hutzler', - 'Liedtke', - 'Nowack', - 'Pittsley', - 'Pelc', - 'Darragh', - 'Pae', - 'Blanke', - 'Brinks', - 'Delap', - 'Brea', - 'Milsap', - 'Borneman', - 'Crofts', - 'Nakai', - 'Silguero', - 'Speciale', - 'Martindelcampo', - 'Vandenburg', - 'Wimsatt', - 'Harbor', - 'Mccorvey', - 'Bensinger', - 'Carhart', - 'Condo', - 'Lemen', - 'Malchow', - 'Vandewater', - 'Ventresca', - 'Morena', - 'Mendell', - 'Faustino', - 'Kleiber', - 'Alberson', - 'Lamonte', - 'Kiner', - 'Belgrave', - 'Blitz', - 'Dildine', - 'Gosch', - 'Grabill', - 'Klemp', - 'Larrea', - 'Pallas', - 'Leonhard', - 'Littler', - 'Dilling', - 'Weatherbee', - 'Robnett', - 'Lacount', - 'Brackins', - 'Counterman', - 'Divincenzo', - 'Dobrowolski', - 'Eppard', - 'Estepp', - 'Gahan', - 'Steininger', - 'Tancredi', - 'Wixom', - 'Combes', - 'Dena', - 'Warn', - 'Teems', - 'Askey', - 'Delmar', - 'Ogles', - 'Herriott', - 'Aguinaldo', - 'In', - 'Kinter', - 'Moul', - 'Santaniello', - 'Tringali', - 'Vanasse', - 'Vanwagoner', - 'Whitesel', - 'Vanderwal', - 'Friedmann', - 'Kalis', - 'Cayer', - 'Para', - 'Wander', - 'Cothron', - 'Betters', - 'Cloward', - 'Cusano', - 'Encinias', - 'Imai', - 'Lalone', - 'Saks', - 'Nosal', - 'Crossan', - 'Caverly', - 'Tewell', - 'Lowney', - 'Merle', - 'Meighan', - 'Labat', - 'Pou', - 'Linsey', - 'Gaviria', - 'Manthei', - 'Marquina', - 'Siegert', - 'Blondin', - 'Maskell', - 'Kimpel', - 'Cappel', - 'Tootle', - 'Folkes', - 'Mainor', - 'Offord', - 'Clagg', - 'Minshew', - 'Niebuhr', - 'Schanz', - 'Stotz', - 'Takeda', - 'Huelsman', - 'Madril', - 'Monico', - 'Stradley', - 'Thein', - 'Cannell', - 'Malson', - 'Ludden', - 'Couts', - 'Mishoe', - 'Dales', - 'Slemp', - 'Stueve', - 'Ziemann', - 'Fluke', - 'Vitali', - 'Monn', - 'Dooling', - 'Lambe', - 'Cail', - 'Louder', - 'Lotts', - 'Augusta', - 'Ando', - 'Depaolo', - 'Egolf', - 'Hibdon', - 'Marzan', - 'Mccawley', - 'Mcgivern', - 'Minjares', - 'Mullally', - 'Portner', - 'Vinciguerra', - 'Wolpert', - 'Yingst', - 'Checo', - 'Starck', - 'Ra', - 'Credle', - 'Baldauf', - 'Bamberger', - 'Besch', - 'Caulkins', - 'Huyck', - 'Portela', - 'Walberg', - 'Kutcher', - 'Hunger', - 'Trant', - 'Cumbee', - 'Cheadle', - 'Drewery', - 'Andrada', - 'Dollinger', - 'Dondero', - 'Salvati', - 'Sefton', - 'Siemers', - 'Sitz', - 'Smale', - 'Wenk', - 'Reschke', - 'Puglia', - 'Koob', - 'Overland', - 'Furrer', - 'Gohl', - 'Hegge', - 'Hentschel', - 'Huberty', - 'Krise', - 'Stasiak', - 'Tripoli', - 'Palomera', - 'Norling', - 'Smucker', - 'Hennes', - 'Metro', - 'Himmel', - 'Paolino', - 'Prato', - 'Wommack', - 'Mcpheeters', - 'Ronald', - 'Eppinger', - 'Cantey', - 'Appell', - 'Capellan', - 'Fielden', - 'Garfias', - 'Heit', - 'Janusz', - 'Pagliaro', - 'Pitz', - 'Winegardner', - 'Gregorich', - 'Schlager', - 'Selvidge', - 'Shultis', - 'Severn', - 'Buffum', - 'Crafts', - 'Antony', - 'Timpson', - 'Deveaux', - 'Maese', - 'Merlos', - 'Mojarro', - 'Policastro', - 'Tawil', - 'Flamm', - 'Aasen', - 'Lipkin', - 'Dyches', - 'Caulk', - 'Rampersad', - 'Pettie', - 'Hagwood', - 'Jedlicka', - 'Paoli', - 'Perkey', - 'Shaub', - 'Vires', - 'Glad', - 'Mandrell', - 'Angeli', - 'Antuna', - 'Bessler', - 'Cebula', - 'Heagy', - 'Mankowski', - 'Sitler', - 'Vanleuven', - 'Blanck', - 'Dannenberg', - 'Moren', - 'Hites', - 'Leckie', - 'Tham', - 'Dower', - 'Beans', - 'Alls', - 'Sipp', - 'Dygert', - 'Kubicek', - 'Matsumura', - 'Shiroma', - 'Smiddy', - 'Szilagyi', - 'Winkleman', - 'Zentz', - 'Niehoff', - 'Boedeker', - 'Dimmitt', - 'Trew', - 'Wilner', - 'Traughber', - 'Bardales', - 'Borbon', - 'Bramhall', - 'Crofoot', - 'Desilets', - 'Disch', - 'Kehrer', - 'Leffingwell', - 'Olalde', - 'Wawrzyniak', - 'Jagodzinski', - 'Schwerin', - 'Heiney', - 'Hirano', - 'Rueter', - 'Sarris', - 'Magnan', - 'Rigsbee', - 'Blay', - 'Edgeworth', - 'Hafford', - 'Legrande', - 'Netter', - 'Dulac', - 'Etherington', - 'Gaede', - 'Matranga', - 'Misch', - 'Gryder', - 'Kolman', - 'Reyer', - 'Landsman', - 'Huppert', - 'Steagall', - 'Heims', - 'Baldini', - 'Breithaupt', - 'Claypoole', - 'Feuer', - 'Heishman', - 'Pallotta', - 'Sponaugle', - 'Pershing', - 'Spaid', - 'Salt', - 'Giger', - 'Whetsel', - 'Balaban', - 'Baus', - 'Croke', - 'Heimer', - 'Milnes', - 'Onstott', - 'Wagman', - 'Magro', - 'Havlik', - 'Menge', - 'Talmage', - 'Aungst', - 'Dichiara', - 'Kuhr', - 'Milstein', - 'Sinatra', - 'Speiser', - 'Vise', - 'Panther', - 'Phair', - 'Commons', - 'Mincy', - 'Ashline', - 'Eagen', - 'Enns', - 'Epler', - 'Giltner', - 'Rexroat', - 'Schein', - 'Wellner', - 'Wickert', - 'Ardito', - 'Ihrig', - 'Schuerman', - 'Wentland', - 'Wohlford', - 'Stoy', - 'Kohan', - 'Ratley', - 'Hazell', - 'Coppin', - 'Blackshire', - 'Coolbaugh', - 'Essman', - 'Gandee', - 'Moccia', - 'Mullarkey', - 'Sugrue', - 'Woomer', - 'Arriaza', - 'Pipitone', - 'Heart', - 'Prothro', - 'Connaughton', - 'Covelli', - 'Lunger', - 'Mcilroy', - 'Morataya', - 'Swedberg', - 'Trembley', - 'Wiederhold', - 'Zappia', - 'Perret', - 'Glander', - 'Snedden', - 'Stonestreet', - 'Archey', - 'Arbour', - 'Cordaro', - 'Diskin', - 'Dumlao', - 'Fravel', - 'Spagnuolo', - 'Derossett', - 'Grigorian', - 'Mercadante', - 'Harcourt', - 'Norgaard', - 'Terhaar', - 'Touch', - 'Mccubbins', - 'Tadros', - 'Zabriskie', - 'Fontanilla', - 'Ruse', - 'Springsteen', - 'Getter', - 'Berrian', - 'Louissaint', - 'Cobbins', - 'Dorney', - 'Kugel', - 'Luth', - 'Poffenberger', - 'Sidoti', - 'Steinfeld', - 'Poley', - 'Dreger', - 'Ertl', - 'Capper', - 'Laswell', - 'Spragg', - 'Coltrane', - 'Winborne', - 'Langhorne', - 'Fambro', - 'Berkebile', - 'Bosserman', - 'Cygan', - 'Debonis', - 'Munsch', - 'Pflug', - 'Skowron', - 'Ediger', - 'Bosler', - 'Morden', - 'Virtue', - 'Orso', - 'Claire', - 'Damas', - 'Eichenlaub', - 'Gatchell', - 'Mikus', - 'Tjaden', - 'Tremper', - 'Tusing', - 'Longest', - 'Baires', - 'Dobos', - 'Deforge', - 'Kawa', - 'Hodder', - 'Thornell', - 'Mcgarrity', - 'Gotcher', - 'Judah', - 'Busey', - 'Perrier', - 'Hawthorn', - 'Captain', - 'Costlow', - 'Frohlich', - 'Gulla', - 'Hildebrant', - 'Hilgendorf', - 'Ramachandran', - 'Reaume', - 'Vollrath', - 'Lambertson', - 'Wyer', - 'Coit', - 'Dietsch', - 'Struve', - 'Vicario', - 'Ahlberg', - 'Warshaw', - 'Ryon', - 'Evatt', - 'Mobbs', - 'Gartin', - 'Kenley', - 'Marcell', - 'Bumpers', - 'Jans', - 'Karczewski', - 'Mazurkiewicz', - 'Nadolny', - 'Verrill', - 'Sitter', - 'Freyer', - 'Hindle', - 'Hergert', - 'Inda', - 'Magwood', - 'Basa', - 'Covello', - 'Pacini', - 'Ruoff', - 'Schenker', - 'Zwicker', - 'Popovic', - 'Augustyn', - 'Sutera', - 'Almy', - 'Keisler', - 'Vowels', - 'Lemond', - 'Abila', - 'Beardslee', - 'Benvenuto', - 'Deschaine', - 'Hodel', - 'Turbyfill', - 'Vejar', - 'Iddings', - 'Labrada', - 'Bowne', - 'Seel', - 'Stretch', - 'Haswell', - 'Rickerson', - 'Speas', - 'Southward', - 'Tony', - 'Burrier', - 'Casco', - 'Lorch', - 'Pietrowski', - 'Rabbitt', - 'Sefcik', - 'Trenary', - 'Trisler', - 'Zarazua', - 'Kube', - 'Riera', - 'Stmarie', - 'Starns', - 'Carmel', - 'Shire', - 'Britto', - 'Lacks', - 'Cifelli', - 'Dusenberry', - 'Lusher', - 'Mattioli', - 'Quiring', - 'Regner', - 'Shetty', - 'Stober', - 'Winemiller', - 'Zinke', - 'Heffington', - 'Santelli', - 'Figeroa', - 'Dishon', - 'Doble', - 'Canino', - 'Tahir', - 'Stamant', - 'Sharpton', - 'Sancho', - 'Linzy', - 'Ba', - 'Bonebrake', - 'Frenkel', - 'Irion', - 'Marines', - 'Lacava', - 'Drennon', - 'Fallen', - 'Whiten', - 'Bielawski', - 'Brasch', - 'Eichorn', - 'Gattuso', - 'Neis', - 'Tkach', - 'Usrey', - 'Walkowiak', - 'Dorame', - 'Orem', - 'Crombie', - 'Lowes', - 'Truscott', - 'Marlette', - 'Bushell', - 'Gosa', - 'Hillary', - 'Byfield', - 'Engdahl', - 'Ganser', - 'Hollars', - 'Lambros', - 'Matzen', - 'Moldovan', - 'Najarian', - 'Schoff', - 'Soo', - 'Spargo', - 'Wierenga', - 'Maysonet', - 'Dewan', - 'Bardo', - 'Figgs', - 'Bostian', - 'Graser', - 'Pecor', - 'Rodrigo', - 'Spilker', - 'Suen', - 'Nafziger', - 'Khouri', - 'Milling', - 'Benke', - 'Chapdelaine', - 'Darwish', - 'Merrigan', - 'Narayanan', - 'Neuner', - 'Wallman', - 'Caracciolo', - 'Uren', - 'Borge', - 'Garside', - 'Veasley', - 'Arquette', - 'Gastineau', - 'Helbling', - 'Maggiore', - 'Prell', - 'Vangelder', - 'Giaquinto', - 'Macha', - 'Jonsson', - 'Febus', - 'Lady', - 'Hughson', - 'Wickliffe', - 'Archila', - 'Bearce', - 'Harstad', - 'Krein', - 'Kulesza', - 'Levitan', - 'Nakasone', - 'Saraceno', - 'Stankus', - 'Shelden', - 'Hopping', - 'Diab', - 'Agar', - 'Mcpike', - 'Betterton', - 'Buzbee', - 'Dieguez', - 'Lins', - 'Phuong', - 'Pinegar', - 'Postel', - 'Beatrice', - 'Biddy', - 'Over', - 'Riding', - 'Rials', - 'Rance', - 'Simington', - 'Degraffenreid', - 'Sherard', - 'Clum', - 'Harkin', - 'Mallen', - 'Messerschmidt', - 'Patz', - 'Shatzer', - 'Stetz', - 'Beckert', - 'Worm', - 'Belmontes', - 'Narron', - 'Lyne', - 'Mckendrick', - 'Rester', - 'Archbold', - 'Whorley', - 'Monts', - 'Crapo', - 'Gribbin', - 'Lamborn', - 'Leverenz', - 'Mccarville', - 'Nishida', - 'Ryberg', - 'Smeal', - 'Piontek', - 'Routhier', - 'Willmon', - 'Proffit', - 'Sharrock', - 'Gasque', - 'Minott', - 'Corpening', - 'Capizzi', - 'Dubuc', - 'Gurevich', - 'Hohenstein', - 'Kotch', - 'Peper', - 'Rehbein', - 'Stortz', - 'Corvin', - 'Savant', - 'Ryle', - 'Madere', - 'Firmin', - 'Bitterman', - 'Bruso', - 'Guzzi', - 'Hefty', - 'Almada', - 'Mcninch', - 'Mangin', - 'On', - 'Hardage', - 'Garson', - 'Hisle', - 'Dease', - 'Critelli', - 'Digennaro', - 'Ehle', - 'Freestone', - 'Grieb', - 'Haubert', - 'Kelsay', - 'Loughman', - 'Neth', - 'Pen', - 'Ranta', - 'Sater', - 'Tomei', - 'Castiglia', - 'Kosek', - 'Zentner', - 'Nowland', - 'Klinedinst', - 'Karls', - 'Charon', - 'Cart', - 'Umphrey', - 'Laramore', - 'Mckenny', - 'Hamler', - 'Stoudemire', - 'Diercks', - 'Hodzic', - 'Huntzinger', - 'Runde', - 'Scavone', - 'Halbach', - 'Banales', - 'Thiry', - 'Waterfield', - 'Bebee', - 'Dass', - 'Caughman', - 'Admire', - 'Attebery', - 'Faubion', - 'Friess', - 'Goldsworthy', - 'Raburn', - 'Vantine', - 'Newswanger', - 'Manhart', - 'Grecco', - 'Meany', - 'Rumpf', - 'Dunlevy', - 'Franceschi', - 'Romanski', - 'Alwine', - 'Cahall', - 'Czaja', - 'Krawiec', - 'Mikolajczyk', - 'Neyman', - 'Perrotti', - 'Weideman', - 'Coppa', - 'Ingerson', - 'Avena', - 'Crunk', - 'Cadenhead', - 'Gittings', - 'Gloss', - 'Trowell', - 'Denard', - 'Funchess', - 'Kinnamon', - 'Mailhot', - 'Mollohan', - 'Polacek', - 'Pozos', - 'Rempe', - 'Schutter', - 'Shimkus', - 'Bedrosian', - 'Beede', - 'Conry', - 'Legan', - 'Pickford', - 'Chamblin', - 'Depinto', - 'Geibel', - 'Gilpatrick', - 'Hashmi', - 'Hermsen', - 'Petruzzi', - 'Robben', - 'Sorkin', - 'Gambardella', - 'Podgorski', - 'Langenfeld', - 'Yanke', - 'Zipperer', - 'Tillson', - 'Ariola', - 'Kelman', - 'Hert', - 'Fearn', - 'Goods', - 'Cervenka', - 'Kreft', - 'Kreidler', - 'Kuhar', - 'Leffew', - 'Maziarz', - 'Vollmar', - 'Zmuda', - 'Eisenhower', - 'Yelle', - 'Bhagat', - 'Kirst', - 'Gilkerson', - 'Kindel', - 'Argyle', - 'Bedingfield', - 'Manney', - 'Guion', - 'Rencher', - 'Plater', - 'Beitzel', - 'Camero', - 'Delaluz', - 'Fennelly', - 'Keenum', - 'Kingrey', - 'Mckillop', - 'Munyon', - 'Rorick', - 'Schrimsher', - 'Sohl', - 'Torbett', - 'Lynde', - 'Reiland', - 'Shepley', - 'Cudney', - 'Cather', - 'Abed', - 'Holen', - 'Jobson', - 'Husbands', - 'Marc', - 'Blatz', - 'Feucht', - 'Gunkel', - 'Margolin', - 'Messerly', - 'Womer', - 'Teston', - 'Ditch', - 'Marta', - 'Osier', - 'Awan', - 'Marcella', - 'Silvester', - 'Baugus', - 'Wilcoxon', - 'Nowling', - 'Torain', - 'Badalamenti', - 'Bartosh', - 'Czajka', - 'Savedra', - 'Shaker', - 'Shambaugh', - 'Stapley', - 'Goeke', - 'Schepers', - 'Tyo', - 'Rhodus', - 'Arencibia', - 'Kara', - 'Aitchison', - 'Parlin', - 'Benny', - 'Shakespeare', - 'Altomare', - 'Axe', - 'Bednarczyk', - 'Feasel', - 'Heikkinen', - 'Heyl', - 'Konecny', - 'Montalbo', - 'Semones', - 'Zuercher', - 'Dorrance', - 'Gehrig', - 'Kretzer', - 'Puchalski', - 'Asche', - 'Astacio', - 'Steers', - 'Jeanes', - 'Bamberg', - 'Matthis', - 'Maultsby', - 'Bunkley', - 'Afonso', - 'Danielsen', - 'Freier', - 'Graeff', - 'Gutknecht', - 'Jansky', - 'Lindenberg', - 'Macphee', - 'Pequeno', - 'Petrocelli', - 'Petrowski', - 'Prete', - 'Igoe', - 'Demonte', - 'Khatib', - 'Agin', - 'Siddall', - 'Mcdill', - 'Higginbottom', - 'Gallow', - 'Inniss', - 'Ballman', - 'Bieniek', - 'Casino', - 'Garringer', - 'Griese', - 'Heritage', - 'Zeitz', - 'Montanaro', - 'Qi', - 'Belcastro', - 'Brautigam', - 'Wakeland', - 'Keasler', - 'Oglesbee', - 'Saye', - 'Steppe', - 'Cichocki', - 'Melgarejo', - 'Primavera', - 'Rippe', - 'Sieger', - 'Stutes', - 'Tustin', - 'Vanloon', - 'Konkol', - 'Altmann', - 'Anderegg', - 'Bun', - 'Mcduffee', - 'Deo', - 'Persad', - 'Kindell', - 'Antillon', - 'Ast', - 'Kumm', - 'Lauricella', - 'Minkler', - 'Pilch', - 'Porreca', - 'Shoopman', - 'Skeels', - 'Chanthavong', - 'Hounshell', - 'Pitner', - 'Space', - 'Blackley', - 'Groomes', - 'Bleeker', - 'Duddy', - 'Inlow', - 'Knabe', - 'Lehmkuhl', - 'Salais', - 'Statz', - 'Sundin', - 'Woolston', - 'Hojnacki', - 'Drolet', - 'Gallivan', - 'Viner', - 'Hafley', - 'Hollan', - 'Phillis', - 'Montrose', - 'Colclough', - 'Coaxum', - 'Basel', - 'Campoverde', - 'Cirelli', - 'Delmonico', - 'Goh', - 'Goyal', - 'Hungate', - 'Lufkin', - 'Passaro', - 'Penta', - 'Quispe', - 'Ovalles', - 'Bulkley', - 'Show', - 'Purington', - 'Sockwell', - 'Mccluney', - 'Asato', - 'Buchta', - 'Cassara', - 'Cesena', - 'Empey', - 'Fass', - 'Gazda', - 'Giannetti', - 'Giuffre', - 'Jahns', - 'Jong', - 'Ruh', - 'Schmieder', - 'Sheerin', - 'Weinheimer', - 'Iwamoto', - 'Ouyang', - 'Uranga', - 'Ranalli', - 'Woolum', - 'Calabria', - 'Arrowsmith', - 'Cashen', - 'Vogan', - 'Giffen', - 'Sherk', - 'Denner', - 'Lanclos', - 'Whittlesey', - 'Dora', - 'Plain', - 'Bransford', - 'Bradwell', - 'Davitt', - 'Dehoff', - 'Lotito', - 'Roell', - 'Satterly', - 'Stahr', - 'Thiem', - 'Helberg', - 'Vause', - 'Willmore', - 'Seid', - 'Linebarger', - 'Geddis', - 'Bringhurst', - 'Damelio', - 'Fetterolf', - 'Galban', - 'Henkle', - 'Kamen', - 'Kaneko', - 'Kissane', - 'Rua', - 'Tehrani', - 'Tingey', - 'Lizardi', - 'Strick', - 'Halper', - 'Striker', - 'Amason', - 'Lesueur', - 'Tatem', - 'Bulluck', - 'Hobdy', - 'Flythe', - 'Brookover', - 'Fishbein', - 'Hartless', - 'Snelgrove', - 'Weikert', - 'Wissman', - 'Bourbeau', - 'Colclasure', - 'Sampley', - 'Shubin', - 'Rhoda', - 'Mcclane', - 'Meals', - 'Peets', - 'Anding', - 'Clewis', - 'Gaymon', - 'Bierly', - 'Brockmeyer', - 'Burnworth', - 'Dierking', - 'Patzer', - 'Seipel', - 'Shieh', - 'Pazmino', - 'Bailie', - 'Ducey', - 'Sessler', - 'Hornaday', - 'Andry', - 'Mowatt', - 'Charlot', - 'Buchholtz', - 'Gaulke', - 'Gondek', - 'Grossmann', - 'Hammerschmidt', - 'Heinle', - 'Huckabay', - 'Neathery', - 'Vanzile', - 'Vossler', - 'Schillaci', - 'Lem', - 'Paff', - 'Oja', - 'Broker', - 'Marlett', - 'Innocent', - 'Adsit', - 'Begg', - 'Kocian', - 'Maddalena', - 'Melamed', - 'Mikos', - 'Pio', - 'Poth', - 'Richwine', - 'Ruda', - 'Sackman', - 'Querry', - 'Padro', - 'Sober', - 'Ayscue', - 'Puff', - 'Hunton', - 'Woltz', - 'Alsobrook', - 'Baskins', - 'Daggs', - 'Brands', - 'Buechel', - 'Gonda', - 'Haberkorn', - 'Hartel', - 'Hazeltine', - 'Lantrip', - 'Leoni', - 'Licona', - 'Stanke', - 'Zwart', - 'Aplin', - 'Leatham', - 'Ace', - 'Ganter', - 'Bartolomeo', - 'Colgrove', - 'Halling', - 'Hesler', - 'Hainline', - 'Susi', - 'Kroner', - 'Sanden', - 'Rylander', - 'Basaldua', - 'Fujiwara', - 'Hengst', - 'Kapur', - 'Kienzle', - 'Miao', - 'Mutschler', - 'Orsi', - 'Pais', - 'Termini', - 'Yamane', - 'Zipp', - 'Wildey', - 'Bauerle', - 'Rehn', - 'Hipsher', - 'Staubin', - 'Esquilin', - 'Goley', - 'Buenaventura', - 'Frutos', - 'Gaugler', - 'Maclellan', - 'Mehring', - 'Stiers', - 'Gearheart', - 'Bong', - 'Maddocks', - 'Canary', - 'Urie', - 'Skillings', - 'Amir', - 'Bogus', - 'Oakman', - 'Barresi', - 'Cappelli', - 'Clausing', - 'Genest', - 'Grella', - 'Mulherin', - 'Roettger', - 'Corle', - 'Mantel', - 'Mody', - 'Delapp', - 'Dunnington', - 'Harvard', - 'Berquist', - 'Foglia', - 'Gilbride', - 'Krenek', - 'Gagnier', - 'Berney', - 'Bazzell', - 'Selvage', - 'Gullette', - 'Lavan', - 'Gunderman', - 'Holaday', - 'Horine', - 'Salata', - 'Slaybaugh', - 'Tobia', - 'Knick', - 'Tinkle', - 'Calcaterra', - 'Fauth', - 'Helmke', - 'Margiotta', - 'Mejorado', - 'Salomone', - 'Sevy', - 'Suri', - 'Vasconcellos', - 'Vetrano', - 'Flaten', - 'Sweetser', - 'Logston', - 'Varon', - 'Allsop', - 'Mickler', - 'Swails', - 'Conejo', - 'Derosia', - 'Hamre', - 'Hanvey', - 'Holscher', - 'Interiano', - 'Kleinberg', - 'Kravetz', - 'Reinking', - 'Schow', - 'Schur', - 'Vanbrocklin', - 'Yinger', - 'Zelenka', - 'Chagoya', - 'Sieben', - 'Devora', - 'Archambeau', - 'Burpee', - 'Shamp', - 'Stander', - 'Weaks', - 'Viney', - 'Halloway', - 'Artiga', - 'Clinkenbeard', - 'Kenison', - 'Loeza', - 'Schaap', - 'Simoni', - 'Frock', - 'Galea', - 'Graven', - 'Brookhart', - 'Gurr', - 'Mackintosh', - 'Arjona', - 'Busche', - 'Salvi', - 'Bedenbaugh', - 'Duan', - 'Clara', - 'Brundidge', - 'Akhter', - 'Amsler', - 'Bolz', - 'Bonura', - 'Brumbelow', - 'Droste', - 'Lohmeyer', - 'Lorah', - 'Louthan', - 'Botti', - 'Feigenbaum', - 'Thon', - 'Osbourn', - 'Peugh', - 'Viau', - 'Elsayed', - 'Hilyard', - 'Coram', - 'Alvin', - 'Milbourne', - 'Hickmon', - 'Basu', - 'Fasnacht', - 'Heathcock', - 'Matsui', - 'Oyama', - 'Stransky', - 'Blakesley', - 'Antes', - 'Flury', - 'Lacrosse', - 'Lull', - 'Clelland', - 'Rugh', - 'Hamelin', - 'Reta', - 'Barnet', - 'Ballow', - 'Pyburn', - 'Slayden', - 'Freshwater', - 'Fomby', - 'Bourquin', - 'Bowersock', - 'Calleros', - 'Dallmann', - 'Gootee', - 'Koelling', - 'Parfitt', - 'Pruss', - 'Tretter', - 'Bellini', - 'Gulden', - 'Pett', - 'Mcglasson', - 'Yerby', - 'Buth', - 'Curnow', - 'Goller', - 'Halderman', - 'Kulig', - 'Laue', - 'Roesner', - 'Samra', - 'Sorrow', - 'Vanbibber', - 'Mellin', - 'Villacis', - 'Hilborn', - 'Ditty', - 'Vasey', - 'Crall', - 'Sera', - 'Honeywell', - 'Blanchet', - 'Halim', - 'Nevius', - 'Ines', - 'Stuard', - 'Birr', - 'Curnutt', - 'Deibler', - 'Jaster', - 'Ouk', - 'Poppell', - 'Provence', - 'Rebman', - 'Schmick', - 'Terra', - 'Zea', - 'Hoven', - 'Loth', - 'Arreaga', - 'Cambre', - 'Roots', - 'Gains', - 'Jeancharles', - 'Cerritos', - 'Ihle', - 'Zambito', - 'Brueggemann', - 'Kluth', - 'Schwartzkopf', - 'Shott', - 'Mcglaughlin', - 'Decoster', - 'Northam', - 'Esau', - 'Fling', - 'Castile', - 'Milledge', - 'Desjarlais', - 'Laframboise', - 'Remigio', - 'Rudloff', - 'Utecht', - 'Enrique', - 'Wygant', - 'Fairbank', - 'Behl', - 'Meuse', - 'Pyke', - 'Fury', - 'Chowning', - 'Hyndman', - 'Donat', - 'Nuckles', - 'Cartledge', - 'Bilal', - 'Antonacci', - 'Huether', - 'Kha', - 'Mascia', - 'Rothberg', - 'Sieck', - 'Younes', - 'Sassaman', - 'Amparan', - 'Benesh', - 'Faraci', - 'Gaber', - 'Lehew', - 'Belzer', - 'Segoviano', - 'Teagle', - 'Burian', - 'Menne', - 'Niemeier', - 'Old', - 'Olenick', - 'Takemoto', - 'Tepe', - 'Test', - 'Zahler', - 'Matsuoka', - 'Hopf', - 'Misenheimer', - 'Mings', - 'Hullett', - 'Beutel', - 'Criscuolo', - 'Fedak', - 'Holtkamp', - 'Kretschmer', - 'Mongillo', - 'Mulrooney', - 'Panganiban', - 'Pollick', - 'Sgroi', - 'Shirkey', - 'Stodola', - 'Tozier', - 'Weidler', - 'Puskar', - 'Fiorello', - 'Stille', - 'Pomales', - 'Gladding', - 'Griffie', - 'Warmack', - 'Uzzell', - 'Stennis', - 'Buttrey', - 'Ekberg', - 'Harmsen', - 'Lieske', - 'Madriz', - 'Mohs', - 'Reininger', - 'Edgin', - 'Galla', - 'Chattin', - 'Frayer', - 'Brents', - 'Lasker', - 'Angelone', - 'Boulter', - 'Burritt', - 'Choudhry', - 'Claffey', - 'Elizarraras', - 'Gaumer', - 'Gawronski', - 'Henwood', - 'Lapine', - 'Bitar', - 'Himel', - 'Almand', - 'Brase', - 'Lala', - 'Salama', - 'Essick', - 'Longman', - 'Mone', - 'Reynard', - 'Brackney', - 'Cottam', - 'Donadio', - 'Geesey', - 'Laudenslager', - 'Mcgilvray', - 'Yano', - 'Bueche', - 'Irey', - 'Carneal', - 'Tinder', - 'Walke', - 'Baston', - 'Segar', - 'Brisbane', - 'Venson', - 'Arguijo', - 'Beitler', - 'Burek', - 'Burgener', - 'Collyer', - 'Donlin', - 'Duhaime', - 'Dworak', - 'Frech', - 'Kozik', - 'Montejo', - 'Nhan', - 'Quirarte', - 'Tram', - 'Deshpande', - 'Silverthorn', - 'Leard', - 'Sheller', - 'Alphin', - 'Boxer', - 'Shawn', - 'Pinnick', - 'Stigler', - 'Arpin', - 'Falkenberg', - 'Gerig', - 'Lemonds', - 'Salm', - 'Sarkis', - 'Paprocki', - 'Probasco', - 'Haithcock', - 'Carn', - 'Farrish', - 'Haliburton', - 'Copen', - 'Pieri', - 'Slaymaker', - 'Cardarelli', - 'Veneziano', - 'Melfi', - 'Solley', - 'Hymer', - 'Pleitez', - 'Hinsley', - 'Bruen', - 'Arita', - 'Dreisbach', - 'Fichtner', - 'Keckler', - 'Slaby', - 'Tanguma', - 'Wiberg', - 'Ferrucci', - 'Lick', - 'Maginnis', - 'Quaranta', - 'Bera', - 'Maybee', - 'Hennessee', - 'Kerrick', - 'Kabir', - 'Branscome', - 'Fullington', - 'Menser', - 'Brooking', - 'Patridge', - 'Gue', - 'Gowens', - 'Redus', - 'Ector', - 'Distasio', - 'Kissner', - 'Prada', - 'Sponsler', - 'Tempel', - 'Wedemeyer', - 'Degler', - 'Bodenhamer', - 'Sherbert', - 'Jefferis', - 'Belgarde', - 'Bevel', - 'Figaro', - 'Bertino', - 'Fabbri', - 'Kovacevic', - 'Kunst', - 'Leja', - 'Ruffo', - 'Stearman', - 'Trickett', - 'Zafar', - 'Valdivieso', - 'Curbelo', - 'Mabee', - 'Emma', - 'Arman', - 'Swasey', - 'Lyday', - 'Muff', - 'Rideaux', - 'Ahlgren', - 'Cobo', - 'Hanratty', - 'Litwiller', - 'Mallonee', - 'Glunt', - 'Moudy', - 'Hickam', - 'Mahmud', - 'Fate', - 'Hemsley', - 'Biery', - 'Buechner', - 'Fragale', - 'Hornbaker', - 'Lacorte', - 'Mateos', - 'Mickley', - 'Reusch', - 'Sabado', - 'Schnurr', - 'Gasior', - 'Konkle', - 'Okazaki', - 'Doubleday', - 'Couvillion', - 'Lupien', - 'Oder', - 'Ohair', - 'Win', - 'Quaintance', - 'Diltz', - 'Poythress', - 'Percell', - 'Weatherall', - 'Ainslie', - 'Brandner', - 'Byrge', - 'Cawood', - 'Heatwole', - 'Kerschner', - 'Looker', - 'Racz', - 'Skirvin', - 'Steitz', - 'Svenson', - 'Vermette', - 'Zupancic', - 'Monnier', - 'Scafidi', - 'Trousdale', - 'Bares', - 'Costantini', - 'Frees', - 'Kallio', - 'Methvin', - 'Prudencio', - 'Hayse', - 'Mahabir', - 'Wafford', - 'Borgmann', - 'Cogley', - 'Gigante', - 'Kurkowski', - 'Lavoy', - 'Wertheimer', - 'Wienke', - 'Goodling', - 'Danek', - 'Brinley', - 'Charlson', - 'Whitsell', - 'Lowen', - 'Minnix', - 'Lowers', - 'Palin', - 'Burgher', - 'Lorick', - 'Sobers', - 'Gavigan', - 'Italiano', - 'Liebl', - 'Prevette', - 'Wehunt', - 'Radin', - 'Guillotte', - 'Mode', - 'Halfacre', - 'Stjames', - 'Isabelle', - 'Meggs', - 'Burkard', - 'Giannotti', - 'Justo', - 'Kasprzyk', - 'Kuba', - 'Mino', - 'Morganti', - 'Schnelle', - 'Serfass', - 'Yacoub', - 'Thode', - 'Wykoff', - 'Macbeth', - 'Oxner', - 'Mayhue', - 'Saulter', - 'Budnik', - 'Gandarilla', - 'Michalec', - 'Eisel', - 'Newmark', - 'Placido', - 'Bellar', - 'Dollarhide', - 'Huett', - 'Copher', - 'Lacaze', - 'Dominic', - 'Bibler', - 'Boydstun', - 'Faas', - 'Grana', - 'Guardino', - 'Illig', - 'Luebbert', - 'Lyford', - 'Mcgettigan', - 'Repko', - 'Widmann', - 'Trevathan', - 'Ewan', - 'Mcray', - 'Footman', - 'Kerchner', - 'Leggio', - 'Bullinger', - 'Rushford', - 'Edel', - 'Leandro', - 'Burkman', - 'Grattan', - 'Tench', - 'Dartez', - 'Lemar', - 'Fane', - 'Zenon', - 'Sabb', - 'Blatchford', - 'Chilcoat', - 'Hahne', - 'Hanssen', - 'Mawhinney', - 'Pflueger', - 'Pol', - 'Vitelli', - 'Brierley', - 'Zundel', - 'Mcgillicuddy', - 'Adriano', - 'Mate', - 'Wilkison', - 'Ramnarine', - 'Peaks', - 'Bacote', - 'Barretto', - 'Benevento', - 'Gubler', - 'Koelsch', - 'Naas', - 'Patane', - 'Schnitzler', - 'Sprenkle', - 'Ulbrich', - 'Violante', - 'Rench', - 'Najarro', - 'Kristensen', - 'Poma', - 'Sara', - 'Jerrell', - 'Sarratt', - 'Mondy', - 'Antill', - 'Belleville', - 'Dworkin', - 'Holdaway', - 'Lenderman', - 'Murga', - 'Reiling', - 'Stasko', - 'Topel', - 'Verity', - 'Vinas', - 'Ziebarth', - 'Vanguilder', - 'Stoots', - 'Yantis', - 'Faries', - 'Tulley', - 'Baucum', - 'Fugett', - 'Harring', - 'Semien', - 'Dauphinais', - 'Furukawa', - 'Grilli', - 'Ohanian', - 'Ormiston', - 'Osegueda', - 'Wiegert', - 'Zier', - 'Chiesa', - 'Radecki', - 'Mongeon', - 'Stake', - 'Sweetland', - 'Shearon', - 'Lamore', - 'Mccuiston', - 'Minson', - 'Burditt', - 'Mcferren', - 'Covin', - 'Straker', - 'Elzy', - 'Althaus', - 'Anzures', - 'Glaeser', - 'Huseby', - 'Nitta', - 'Ribaudo', - 'Sobota', - 'Spieker', - 'Stefaniak', - 'Valois', - 'Vanwie', - 'Venturini', - 'Beltre', - 'Ewer', - 'Hartt', - 'Keaney', - 'Throne', - 'Edrington', - 'Inmon', - 'Isabel', - 'Brayman', - 'Devilbiss', - 'Krasner', - 'Malak', - 'Tito', - 'Vermeer', - 'Benigno', - 'Bosque', - 'Berridge', - 'Clines', - 'Brite', - 'Mcbeath', - 'Gleaves', - 'Koenen', - 'Kubicki', - 'Kudla', - 'Seiple', - 'Warkentin', - 'Choiniere', - 'Nassif', - 'Banko', - 'Muncie', - 'Garling', - 'Causby', - 'Mcgaw', - 'Burkeen', - 'Balan', - 'Georgia', - 'Hick', - 'Tumblin', - 'Badon', - 'Warrior', - 'Yearby', - 'Hiestand', - 'Hughart', - 'Proffer', - 'Sult', - 'Yepes', - 'Zachman', - 'Beddow', - 'Molyneux', - 'Camejo', - 'Stephany', - 'Cadogan', - 'Gosha', - 'Goodwine', - 'Harewood', - 'Burnsed', - 'Frappier', - 'Minardi', - 'Rieser', - 'Tabbert', - 'Marietta', - 'Butch', - 'Steil', - 'Canal', - 'Brundige', - 'Comas', - 'Hopkinson', - 'Shomo', - 'Kendle', - 'Bowsher', - 'Illingworth', - 'Kampa', - 'Manasco', - 'Mcdorman', - 'Theurer', - 'Widger', - 'Carbonneau', - 'Stachura', - 'Eriksson', - 'Trostle', - 'Foxworthy', - 'Lex', - 'Belman', - 'Isola', - 'Mckane', - 'Gearing', - 'Rimes', - 'Couillard', - 'Emanuele', - 'Pho', - 'Scimeca', - 'Skaar', - 'Vibbert', - 'Bilby', - 'Hink', - 'Gohn', - 'Nguy', - 'Perrett', - 'Bowland', - 'Comes', - 'Moffet', - 'Pauline', - 'Donalson', - 'Tilman', - 'Hansberry', - 'Acedo', - 'Camarda', - 'Devivo', - 'Eurich', - 'Jojola', - 'Railsback', - 'Rumfelt', - 'Stastny', - 'Strittmatter', - 'Houseknecht', - 'Rynearson', - 'Weinrich', - 'Kinghorn', - 'Astin', - 'Aguillard', - 'Hameed', - 'Drone', - 'Lonon', - 'Burgio', - 'Klimas', - 'Riegler', - 'Schiano', - 'Slonaker', - 'Deery', - 'Weissinger', - 'Cea', - 'Grenz', - 'Arent', - 'Sopher', - 'Jarratt', - 'Mitchener', - 'Conigliaro', - 'Dohm', - 'Feenstra', - 'Meiers', - 'Hetland', - 'Kinsinger', - 'Kmiec', - 'Teich', - 'Fukushima', - 'Kerins', - 'Cienfuegos', - 'Orlandi', - 'Bonser', - 'Okun', - 'Coate', - 'Rittenberry', - 'Mcclaine', - 'Dunklin', - 'Citizen', - 'Danzy', - 'Geers', - 'Georgeson', - 'Kikuchi', - 'Macinnis', - 'Malizia', - 'Mukai', - 'Plants', - 'Ehmann', - 'Haren', - 'Lachney', - 'Duchesne', - 'Collinson', - 'Connett', - 'Hostler', - 'Farnell', - 'Osler', - 'Triche', - 'Ballweg', - 'Bansal', - 'Galo', - 'Hollabaugh', - 'Hultquist', - 'Mcbrien', - 'Pelz', - 'Picciano', - 'Tashjian', - 'Thresher', - 'Uphoff', - 'Shawley', - 'Tomasek', - 'Aldaz', - 'Harig', - 'Kullman', - 'Vaness', - 'Isabella', - 'Munley', - 'Bissette', - 'Thackston', - 'Borgia', - 'Camire', - 'Charters', - 'Feiler', - 'Geisinger', - 'Racca', - 'Rasmusson', - 'Stonesifer', - 'Vidmar', - 'Arciga', - 'Bialek', - 'Baruch', - 'Kornfeld', - 'Harmeyer', - 'Picon', - 'Suppa', - 'Strate', - 'Hyre', - 'Verdon', - 'Reily', - 'Castell', - 'Foard', - 'Exner', - 'Furnari', - 'Guereca', - 'Hallgren', - 'Holsclaw', - 'Ketelsen', - 'Magnani', - 'Mehling', - 'Naser', - 'Seder', - 'Sparr', - 'Strnad', - 'Tatar', - 'Crecelius', - 'Knicely', - 'Vantassell', - 'Balsley', - 'Babbs', - 'Gowans', - 'Mcclam', - 'Batdorf', - 'Belsky', - 'Gull', - 'Letizia', - 'Ludlum', - 'Mascari', - 'Scheffel', - 'Spurgin', - 'Dignan', - 'Steffensen', - 'Freeberg', - 'Honan', - 'Hamric', - 'Woolman', - 'Valeri', - 'Saab', - 'Boyers', - 'Pardon', - 'Deasy', - 'Forshey', - 'Juntunen', - 'Kamel', - 'Macisaac', - 'Marinaro', - 'Milroy', - 'Parillo', - 'Rappold', - 'Schippers', - 'Smola', - 'Staniszewski', - 'Strasburg', - 'Epple', - 'Dewitte', - 'Hubley', - 'Queener', - 'Stoddart', - 'Briant', - 'Mcclurkin', - 'Binkowski', - 'Eberts', - 'Kilbane', - 'Kiraly', - 'Monsalve', - 'Othman', - 'Pasek', - 'Rinke', - 'Steinbrecher', - 'Trees', - 'Winther', - 'Boal', - 'Eber', - 'Funez', - 'Harryman', - 'Boyter', - 'Rill', - 'Jolliffe', - 'Dorian', - 'Demore', - 'Sebree', - 'Jeff', - 'Jolivette', - 'Elko', - 'Jividen', - 'Lenzen', - 'Marsee', - 'Milbrandt', - 'Orihuela', - 'Osterhoudt', - 'Parras', - 'Schnepp', - 'Tenaglia', - 'Thoren', - 'Diosdado', - 'Pingree', - 'Rutigliano', - 'Filbert', - 'Babel', - 'Stollings', - 'Hopes', - 'Bynes', - 'Brockmann', - 'Carta', - 'Deleeuw', - 'Demo', - 'Margeson', - 'Mckitrick', - 'Reyez', - 'Sidor', - 'Strehlow', - 'Timlin', - 'Wegrzyn', - 'Burgdorf', - 'Benzing', - 'Bonneville', - 'Clonts', - 'Camps', - 'Graydon', - 'Pasha', - 'Andreoli', - 'Cockerill', - 'Covino', - 'Hajjar', - 'Korpi', - 'Pohlmann', - 'Wente', - 'Wickwire', - 'Schaber', - 'Vonderhaar', - 'Manser', - 'Fitton', - 'Galindez', - 'Ares', - 'Longmore', - 'Buchert', - 'Delisi', - 'Gaulin', - 'Genco', - 'Helgerson', - 'Khawaja', - 'Radosevich', - 'Sannicolas', - 'Sterk', - 'Theberge', - 'Voiles', - 'Warchol', - 'Potthoff', - 'Runkel', - 'Stachowski', - 'Snay', - 'Share', - 'Conkey', - 'Pontes', - 'Mathies', - 'Brittian', - 'Allgeier', - 'Daughenbaugh', - 'Glock', - 'Meisinger', - 'Pantaleo', - 'Saitta', - 'Weick', - 'Burak', - 'Borda', - 'Rim', - 'Bunyard', - 'Neaves', - 'Mcilvaine', - 'Zee', - 'Buskey', - 'Roseborough', - 'Bellin', - 'Fasulo', - 'Grab', - 'Jia', - 'Knab', - 'Skalski', - 'Stensland', - 'Zajicek', - 'Echeverry', - 'Kolenda', - 'Cadden', - 'Delawder', - 'Propp', - 'Scheeler', - 'Clukey', - 'Loven', - 'Bogen', - 'Whittingham', - 'Barcelona', - 'Braasch', - 'Haubrich', - 'Kolberg', - 'Vendetti', - 'Sheesley', - 'Bartoli', - 'Knierim', - 'Amparo', - 'Lauth', - 'Rosero', - 'Burry', - 'Guynes', - 'Cumbo', - 'Pridgeon', - 'Aarons', - 'Alarid', - 'Arakawa', - 'Benzel', - 'Bywater', - 'Grosch', - 'Heth', - 'Logiudice', - 'Maisel', - 'Morquecho', - 'Wahlberg', - 'Teigen', - 'Bockelman', - 'Rehak', - 'Bitler', - 'Brion', - 'Niece', - 'Selvey', - 'Sudderth', - 'Ruddock', - 'Sandiford', - 'Aguas', - 'Folan', - 'Herwig', - 'Krupinski', - 'Mccarrick', - 'Mudgett', - 'Pancake', - 'Redner', - 'Wentzell', - 'Soliday', - 'Marschall', - 'Krakowski', - 'Rebholz', - 'Dold', - 'Giller', - 'Gassett', - 'Brazzell', - 'Bellow', - 'Tolen', - 'Gloster', - 'Gagliardo', - 'Harbuck', - 'Lorber', - 'Natarajan', - 'Sarna', - 'Schrack', - 'Vena', - 'Witzke', - 'Minassian', - 'Loi', - 'Rogue', - 'Trace', - 'Bomba', - 'Cozzens', - 'Evett', - 'Boze', - 'Petros', - 'Cotta', - 'Eisenmann', - 'Florea', - 'Hammersley', - 'Keohane', - 'Necessary', - 'Nodine', - 'Pekarek', - 'Sjogren', - 'Ruybal', - 'Arabie', - 'Huntsinger', - 'Eiseman', - 'Mehler', - 'Craner', - 'Vandine', - 'Gaffey', - 'Menna', - 'Royle', - 'Cordrey', - 'Gala', - 'Gauss', - 'Dacruz', - 'Cardell', - 'Devan', - 'Calmes', - 'Humber', - 'Stoute', - 'Balko', - 'Cera', - 'Griesbach', - 'Kissick', - 'Kloos', - 'Oertel', - 'Sedlock', - 'Stellato', - 'Tuite', - 'Bero', - 'Rinard', - 'Dambra', - 'Cinelli', - 'Tea', - 'Hicken', - 'Linch', - 'Dials', - 'Bennefield', - 'Hillsman', - 'Flemister', - 'Alvaro', - 'Goranson', - 'Henk', - 'Ryden', - 'Verhagen', - 'Wessling', - 'Willetts', - 'Neidlinger', - 'Pereida', - 'Lainhart', - 'Nemes', - 'Rudzinski', - 'Sward', - 'Rom', - 'Rosko', - 'Runions', - 'Henney', - 'Ridgely', - 'Tomson', - 'Arballo', - 'Bohorquez', - 'Brixey', - 'Durling', - 'Espina', - 'Esquivias', - 'Nungaray', - 'Ovando', - 'Zapf', - 'Pizza', - 'Arel', - 'Ballin', - 'Heathman', - 'Morison', - 'Troop', - 'Monfort', - 'Copland', - 'Harriott', - 'Mcwhite', - 'Amini', - 'Cirilo', - 'Gassner', - 'Gulbranson', - 'Kovatch', - 'Venne', - 'Terriquez', - 'Savin', - 'Amo', - 'Moris', - 'Crable', - 'Delaughter', - 'Greenhouse', - 'Eckardt', - 'Hendrixson', - 'Manansala', - 'Mongeau', - 'Panko', - 'Pichette', - 'Sliwa', - 'Tabak', - 'Determan', - 'Freeburg', - 'Portell', - 'Steller', - 'Buffkin', - 'Righter', - 'Mcguinn', - 'Corrie', - 'Tatham', - 'Smelley', - 'Terrel', - 'Selmon', - 'Blecha', - 'Eisler', - 'Engelking', - 'Goen', - 'Krey', - 'Mceldowney', - 'Plamondon', - 'Slovak', - 'Sorce', - 'Spagnolo', - 'Wambold', - 'Colborn', - 'Englander', - 'Monsour', - 'Pait', - 'Perricone', - 'Loveridge', - 'Cragg', - 'Dies', - 'Holsten', - 'Dagley', - 'Beverley', - 'Bayona', - 'Cam', - 'Chock', - 'Coppersmith', - 'Donath', - 'Guillemette', - 'Iannelli', - 'Potratz', - 'Selander', - 'Suk', - 'Waldvogel', - 'Olberding', - 'Giaimo', - 'Spoto', - 'Crocco', - 'Waskiewicz', - 'Krizan', - 'Vigo', - 'Boarman', - 'Ron', - 'Facer', - 'Garlow', - 'Filsaime', - 'Andersson', - 'Demski', - 'Derouin', - 'Diegel', - 'Feria', - 'Foth', - 'Hertzberg', - 'Jillson', - 'Kram', - 'Mammen', - 'Melhorn', - 'Monjaras', - 'Oslund', - 'Petrin', - 'Pinho', - 'Scheerer', - 'Shadden', - 'Sitzman', - 'Stumbaugh', - 'Wengert', - 'Gershon', - 'Mcelhinney', - 'Batterson', - 'Macqueen', - 'Janas', - 'Gladson', - 'Aull', - 'Wasinger', - 'Shemwell', - 'Seats', - 'Colas', - 'Allbee', - 'Fithian', - 'Fonner', - 'Gergen', - 'Lubrano', - 'Mannarino', - 'Piscopo', - 'Sydow', - 'Werle', - 'Aumiller', - 'Coplen', - 'Dardar', - 'Morrisette', - 'Mchaney', - 'Simes', - 'Gillison', - 'Emmel', - 'Klunk', - 'Luber', - 'Madeira', - 'Schlicht', - 'Tremain', - 'Cleaveland', - 'Boulet', - 'Golladay', - 'Enck', - 'Fera', - 'Hammar', - 'Hebner', - 'Ishee', - 'Nanni', - 'Palomar', - 'Pangborn', - 'Rogala', - 'Rushlow', - 'Wiedman', - 'Laber', - 'Schoenfelder', - 'Sonner', - 'Duffer', - 'Granier', - 'Sawin', - 'Dwiggins', - 'Jaso', - 'Popplewell', - 'Loren', - 'Ord', - 'Dearmon', - 'Hammen', - 'Misra', - 'Reindl', - 'Siordia', - 'Woodhead', - 'Yasuda', - 'Dockstader', - 'Kobs', - 'Tokarski', - 'Villers', - 'Mase', - 'Arrant', - 'Hedgpeth', - 'Eggleton', - 'Frederic', - 'Victorian', - 'Akerman', - 'Balazs', - 'Brandau', - 'Depietro', - 'Dillenbeck', - 'Goodnow', - 'Larner', - 'Mcmurtrie', - 'Salameh', - 'Swicegood', - 'Koshy', - 'Stdenis', - 'Deakin', - 'Izzi', - 'Teater', - 'Gramm', - 'Doig', - 'Blacklock', - 'Haymore', - 'Heggie', - 'Kirklin', - 'Kassa', - 'Ryles', - 'Tenner', - 'Ndiaye', - 'Burrola', - 'Faires', - 'Grega', - 'Krentz', - 'Needles', - 'Portz', - 'Ruedas', - 'Sitko', - 'Viernes', - 'Setter', - 'Tricarico', - 'Prest', - 'Olivar', - 'Whitsitt', - 'Labossiere', - 'Bellomo', - 'Burgeson', - 'Capriotti', - 'Drinnon', - 'Gulati', - 'Haffey', - 'Lasota', - 'Laughery', - 'Mees', - 'Melander', - 'Paoletti', - 'Petermann', - 'Zerby', - 'Burhans', - 'Lasseigne', - 'Vannote', - 'Wai', - 'Berson', - 'Gritton', - 'Searl', - 'Toller', - 'Brackeen', - 'Screws', - 'Hagens', - 'Billingslea', - 'Hyppolite', - 'Asmussen', - 'Bitton', - 'Diiorio', - 'Grigoryan', - 'Hauenstein', - 'Krukowski', - 'Mulcahey', - 'Perras', - 'Prak', - 'Reitzel', - 'Spackman', - 'Valenciano', - 'Wieck', - 'Yeagley', - 'Zanetti', - 'Goeller', - 'Azizi', - 'Grise', - 'Mogan', - 'Traverso', - 'Nangle', - 'Saladin', - 'Hardgrove', - 'Osei', - 'Fehrenbach', - 'Giesbrecht', - 'Halas', - 'Hetzler', - 'Orsak', - 'Salaz', - 'Surace', - 'Whipp', - 'Charlebois', - 'Stayer', - 'Stelmach', - 'Hitchings', - 'Senters', - 'Mcnaught', - 'Cordier', - 'Dawsey', - 'Barhorst', - 'Clauser', - 'Dibernardo', - 'Hawkey', - 'Hritz', - 'Patchin', - 'Raatz', - 'Seubert', - 'Slingerland', - 'Vanderwoude', - 'Aquilino', - 'Goertzen', - 'Navratil', - 'Mccuistion', - 'Vallin', - 'Moors', - 'Connely', - 'Fedrick', - 'Bontempo', - 'Dishong', - 'Felch', - 'Laino', - 'Minshall', - 'Montroy', - 'Plotts', - 'Radice', - 'Sachse', - 'Safran', - 'Schecter', - 'Traut', - 'Vasile', - 'Yadon', - 'Gorka', - 'Roelofs', - 'Suit', - 'Asbill', - 'Torrens', - 'Kimmey', - 'Ruger', - 'Vinzant', - 'Watkin', - 'Rawles', - 'Cubero', - 'Duch', - 'Endress', - 'Fangman', - 'Holben', - 'Holzapfel', - 'Karner', - 'Otteson', - 'Stangel', - 'Terrebonne', - 'Wagley', - 'Wisecup', - 'Bengston', - 'Leck', - 'Coalson', - 'Farooq', - 'Safi', - 'Smyers', - 'All', - 'Else', - 'Wason', - 'Nairn', - 'Panton', - 'Ahrendt', - 'Arvizo', - 'Klahn', - 'Robak', - 'Schier', - 'Start', - 'Tiano', - 'Kraatz', - 'Corzo', - 'Maranto', - 'Elm', - 'Eagles', - 'Acres', - 'Schoolfield', - 'Ancrum', - 'Ahner', - 'Augsburger', - 'Berna', - 'Danh', - 'Fruth', - 'Galluzzo', - 'Racette', - 'Selva', - 'Szekely', - 'Zirbel', - 'Hauff', - 'Markgraf', - 'Wonderly', - 'Rydell', - 'Julia', - 'Chris', - 'Simson', - 'Bridgeford', - 'Jeffress', - 'Brailsford', - 'Bluford', - 'Boser', - 'Fichera', - 'Meininger', - 'Meyerhoff', - 'Modzelewski', - 'Niese', - 'Pavlovich', - 'Radovich', - 'Ratz', - 'Frankowski', - 'Berti', - 'Geno', - 'Fares', - 'Marney', - 'Harwick', - 'Tata', - 'Bobby', - 'Dobbin', - 'Roosevelt', - 'Greenaway', - 'Janvier', - 'Oatis', - 'Beilke', - 'Brelsford', - 'Dowty', - 'Giudice', - 'Hetzer', - 'Imboden', - 'Irelan', - 'Nie', - 'Ramberg', - 'Rega', - 'Sproat', - 'Sytsma', - 'Unrein', - 'Davignon', - 'Ganoe', - 'Leinweber', - 'Mantell', - 'Troisi', - 'Sahr', - 'Esperanza', - 'Asper', - 'Lathem', - 'Eagleton', - 'Lamons', - 'Gaulden', - 'Bloodgood', - 'Cerone', - 'Claro', - 'Durfey', - 'Enamorado', - 'Herrada', - 'Maw', - 'Schlagel', - 'Signor', - 'Reisch', - 'Gruenwald', - 'Helbert', - 'Lorenzi', - 'Woodlief', - 'Huval', - 'Batman', - 'Meadow', - 'Croswell', - 'Bordonaro', - 'Earnshaw', - 'Freiburger', - 'Gunnoe', - 'Lamberton', - 'Martella', - 'Mischke', - 'Shelor', - 'Venuti', - 'Bilek', - 'Mcmains', - 'Balding', - 'Mestre', - 'Mcconnaughey', - 'Manso', - 'Decoste', - 'Egerton', - 'Alvino', - 'Arizpe', - 'Blaschke', - 'Foglesong', - 'Heyn', - 'Irigoyen', - 'Komorowski', - 'Lesinski', - 'Nghiem', - 'Rund', - 'Santiesteban', - 'Strahm', - 'Hendel', - 'Capes', - 'Carls', - 'Bon', - 'Sires', - 'Nichelson', - 'Brimm', - 'Aikins', - 'Berra', - 'Brazee', - 'Burkert', - 'Capalbo', - 'Criscione', - 'Feddersen', - 'Hofbauer', - 'Jacobowitz', - 'Mackowiak', - 'Mcenroe', - 'Philbeck', - 'Shimada', - 'Ticknor', - 'Wozny', - 'Biernacki', - 'Hirschi', - 'Polich', - 'Sokoloski', - 'Dolores', - 'Knoch', - 'Ge', - 'Groome', - 'Markell', - 'Fearing', - 'Mcclaren', - 'Hadsell', - 'Rumple', - 'Samudio', - 'Scardina', - 'Spinosa', - 'Abramov', - 'Siracusa', - 'Goren', - 'Rocchio', - 'Bibi', - 'Lamer', - 'Liddy', - 'Anna', - 'Coxe', - 'De', - 'Rodes', - 'Cheshier', - 'Coulon', - 'Closs', - 'Tigue', - 'Seville', - 'Hopkin', - 'Rodwell', - 'Bibbins', - 'Baldree', - 'Bawden', - 'Bishoff', - 'Costabile', - 'Dec', - 'Hillegass', - 'Infantino', - 'Mantia', - 'Mcamis', - 'Northcott', - 'Ruprecht', - 'Sanpedro', - 'Campione', - 'Muchow', - 'Ostby', - 'Mohl', - 'Pulice', - 'Vigna', - 'Thomann', - 'Lillibridge', - 'Manville', - 'Vives', - 'Bellanger', - 'Desormeaux', - 'Lovingood', - 'Stjulien', - 'Echeverri', - 'Florey', - 'Gieseke', - 'Maeder', - 'Marcinko', - 'Nuncio', - 'Quirino', - 'Versteeg', - 'Voelkel', - 'Wanless', - 'Morocho', - 'Monteagudo', - 'Aikin', - 'Bramley', - 'Bartleson', - 'Skeete', - 'Batra', - 'Dolloff', - 'Gehr', - 'Hellyer', - 'Hersch', - 'Hier', - 'Lannan', - 'Reffitt', - 'Carboni', - 'Schouten', - 'Burkle', - 'Riches', - 'Busa', - 'Rademaker', - 'Hult', - 'Synder', - 'Bossard', - 'Tunis', - 'Pamplin', - 'Oats', - 'Mcphaul', - 'Baik', - 'Kieser', - 'Pareja', - 'Raffaele', - 'Erhard', - 'Iwasaki', - 'Tonelli', - 'Mabey', - 'Debruyn', - 'Carrel', - 'Myron', - 'Arai', - 'Vallo', - 'Points', - 'Buteau', - 'Becknell', - 'Lue', - 'Antos', - 'Folkers', - 'Galletta', - 'Hissong', - 'Knoche', - 'Kundert', - 'Larussa', - 'Lobos', - 'Poitra', - 'Rinn', - 'Seamons', - 'Senko', - 'Villaverde', - 'Weatherholt', - 'Maliszewski', - 'Jurkowski', - 'Scism', - 'Hallas', - 'Collet', - 'Capello', - 'Lena', - 'Popper', - 'Aikman', - 'Blakes', - 'Cadigan', - 'Dupler', - 'Kazi', - 'Masri', - 'Matejka', - 'Mcgirr', - 'Pistone', - 'Prenger', - 'Ranes', - 'Thiemann', - 'Voeller', - 'Cockman', - 'Burtt', - 'Looby', - 'Bonnie', - 'Mcclenny', - 'Ridgell', - 'Nails', - 'Lesane', - 'Bertolino', - 'Doheny', - 'Fechter', - 'Holshouser', - 'Kierstead', - 'Krewson', - 'Lanahan', - 'Vig', - 'Wiswell', - 'Freytag', - 'Haselden', - 'Kuras', - 'Navar', - 'Raisor', - 'Finamore', - 'Kipper', - 'Morissette', - 'Laughton', - 'Awe', - 'Manier', - 'Cumby', - 'Cabada', - 'Hafen', - 'Kojima', - 'Massari', - 'Mctague', - 'Stehr', - 'Vandevelde', - 'Voong', - 'Wisely', - 'Girardin', - 'Bies', - 'Demaris', - 'Galles', - 'Goldstone', - 'Kai', - 'Cord', - 'Brigance', - 'Gomillion', - 'Drakes', - 'Bartkowiak', - 'Chica', - 'Draheim', - 'Honeyman', - 'Klapper', - 'Kniffen', - 'Knoblock', - 'Scherzer', - 'Tougas', - 'Toyama', - 'Urbach', - 'Walia', - 'Wattenbarger', - 'Marz', - 'Cesare', - 'Miro', - 'Kervin', - 'Godard', - 'Beiter', - 'Betcher', - 'Evarts', - 'Evensen', - 'Gaff', - 'Griffitts', - 'Grunden', - 'Hoffart', - 'Kroupa', - 'Maiers', - 'Mckendry', - 'Puett', - 'Shoe', - 'Stermer', - 'Wineinger', - 'Brocious', - 'Chudy', - 'Spofford', - 'Wessinger', - 'Weich', - 'Croff', - 'Ephraim', - 'Sallis', - 'Blasco', - 'Burningham', - 'Buschmann', - 'Forget', - 'Kulak', - 'Panozzo', - 'Pierpont', - 'Priolo', - 'Puhl', - 'Ruffolo', - 'Voisine', - 'Mancinelli', - 'Santacroce', - 'Vanvalkenburgh', - 'Veverka', - 'Desena', - 'Agner', - 'Boron', - 'Wheeling', - 'Plato', - 'Tonge', - 'Deibel', - 'Herriman', - 'Holroyd', - 'Huitron', - 'Hum', - 'Kreamer', - 'Lada', - 'Lucena', - 'Pao', - 'Planck', - 'Vanroekel', - 'Bodell', - 'Francia', - 'Anastasia', - 'Haxton', - 'Maile', - 'Warning', - 'Labeau', - 'Pujol', - 'Done', - 'Minney', - 'Hogsett', - 'Tayler', - 'Delancy', - 'Philson', - 'Allemand', - 'Buhrman', - 'Diefenbach', - 'Gawel', - 'Kovacic', - 'Kralik', - 'Lazor', - 'Mcnemar', - 'Warth', - 'Glanzer', - 'Keep', - 'Hochstein', - 'Febles', - 'Morneau', - 'Agostinelli', - 'Galeas', - 'Landen', - 'Lion', - 'Attwood', - 'Capshaw', - 'Willy', - 'Dekle', - 'Murrill', - 'Coby', - 'Falvo', - 'Kanagy', - 'Mihalko', - 'Schellenberg', - 'Sugimoto', - 'Lippard', - 'Sardo', - 'Suckow', - 'Demichele', - 'Kath', - 'Lappe', - 'Lego', - 'Schleifer', - 'Vold', - 'Kingsland', - 'Mitch', - 'Manlove', - 'Cuozzo', - 'Dauber', - 'Deininger', - 'Goldbach', - 'Halfmann', - 'Kazarian', - 'Marksberry', - 'Marzec', - 'Mcmurphy', - 'Oregan', - 'Paczkowski', - 'Pinsky', - 'Poynor', - 'Schertz', - 'Tetrick', - 'Umali', - 'Valenza', - 'Witherington', - 'Kesselring', - 'Nylund', - 'Cinnamon', - 'Rielly', - 'Surman', - 'Fowle', - 'Hains', - 'Sharlow', - 'Lones', - 'Durgan', - 'Savory', - 'Minger', - 'Okon', - 'Berends', - 'Binning', - 'Malina', - 'Loeser', - 'Marthaler', - 'Pacella', - 'Vasta', - 'Hinerman', - 'Goodchild', - 'Chuck', - 'Linney', - 'Beckworth', - 'Carrie', - 'Lovings', - 'Ginyard', - 'Bredeson', - 'Debiase', - 'Gorder', - 'Noce', - 'Redlin', - 'Schwinn', - 'Zins', - 'Burtner', - 'Kosakowski', - 'Erler', - 'Altom', - 'Husman', - 'Markos', - 'Thorman', - 'Fagen', - 'Voisin', - 'Gauldin', - 'Pressey', - 'Calbert', - 'Holness', - 'Alspach', - 'Broeker', - 'Danziger', - 'Klenke', - 'Popescu', - 'Schoenrock', - 'Schreckengost', - 'Syme', - 'Trick', - 'Plautz', - 'Beckel', - 'Dealmeida', - 'Winne', - 'Moron', - 'Seed', - 'Capozzoli', - 'Gawron', - 'Kobel', - 'Kouns', - 'Nunemaker', - 'Steinbacher', - 'Stookey', - 'Vidana', - 'Zoch', - 'Ohlinger', - 'Hudkins', - 'Ferren', - 'Gille', - 'Sheckler', - 'Kittell', - 'Roath', - 'Ziglar', - 'Brecher', - 'Coldren', - 'Degraaf', - 'Eddinger', - 'Joffe', - 'Luthy', - 'Metzinger', - 'Nayak', - 'Paule', - 'Prudente', - 'Wooddell', - 'Zuccaro', - 'Rineer', - 'Soos', - 'Manka', - 'Vandervoort', - 'Kitchell', - 'Casserly', - 'Watchman', - 'Poteete', - 'Dopson', - 'Mathurin', - 'Cataldi', - 'Crepeau', - 'Fackrell', - 'Goben', - 'Macinnes', - 'Scherf', - 'Shaddix', - 'Sorber', - 'Teichman', - 'Wydra', - 'Holzworth', - 'Baade', - 'Tinnell', - 'Tinkler', - 'Mauzy', - 'Alphonse', - 'Fullard', - 'Adger', - 'Akiyama', - 'Bloxham', - 'Coultas', - 'Esler', - 'Giebel', - 'Goswick', - 'Heikes', - 'Javed', - 'Linan', - 'Mooers', - 'Nemetz', - 'Pradhan', - 'Rainone', - 'Romito', - 'Treichel', - 'Vohs', - 'Grosskopf', - 'Weisinger', - 'Ruple', - 'Naff', - 'Meaders', - 'Lamarr', - 'Toppin', - 'Apicella', - 'Beecroft', - 'Boshears', - 'Breier', - 'Cuadros', - 'Umbarger', - 'Alioto', - 'Ravenscroft', - 'Vesper', - 'Oak', - 'Tigges', - 'Simmer', - 'Hanby', - 'Webre', - 'Lenk', - 'Mcelvain', - 'Boy', - 'Debarros', - 'Hickenbottom', - 'Quincy', - 'Billips', - 'Ollison', - 'Barbuto', - 'Clearwater', - 'Cronkhite', - 'Groleau', - 'Mehra', - 'Tessler', - 'Kegel', - 'Borenstein', - 'Newnam', - 'Crofton', - 'Phenix', - 'Dankert', - 'Hymas', - 'Lobel', - 'Marszalek', - 'Moceri', - 'Ottaviano', - 'Papazian', - 'Roedel', - 'Jochum', - 'Urquidez', - 'Lapin', - 'Garro', - 'Lamond', - 'Sessums', - 'Tooke', - 'Steadham', - 'Azam', - 'Bleier', - 'Buelna', - 'Bupp', - 'Burridge', - 'Derderian', - 'Derstine', - 'Halberg', - 'Katzer', - 'Meegan', - 'Ortmann', - 'Herschberger', - 'Sanroman', - 'Winiarski', - 'Alcon', - 'Picker', - 'Demille', - 'Huron', - 'Hankin', - 'Dahmen', - 'Fronczak', - 'Klingman', - 'Perugini', - 'Pettinato', - 'Powelson', - 'Saffer', - 'Schwenke', - 'Pals', - 'Estremera', - 'Sofia', - 'Arvelo', - 'Terrero', - 'Bankes', - 'Sais', - 'Netherland', - 'Odeh', - 'Sutphen', - 'Caddy', - 'Dorval', - 'Glaude', - 'Mcadory', - 'Eichinger', - 'Lesniewski', - 'Petito', - 'Pfohl', - 'Presler', - 'Rys', - 'Sano', - 'Willenborg', - 'Seppala', - 'Shibley', - 'Cajigas', - 'Gal', - 'Farag', - 'Pickles', - 'Rump', - 'Grills', - 'Mikes', - 'Adderley', - 'Altland', - 'Araki', - 'Beitz', - 'Brotzman', - 'Buonocore', - 'Fayard', - 'Gelber', - 'Jurewicz', - 'Lezcano', - 'Marsteller', - 'Minarik', - 'Opsahl', - 'Pranger', - 'Tiburcio', - 'Zollo', - 'Engh', - 'Henault', - 'Barrineau', - 'Pilkinton', - 'Pratte', - 'Niland', - 'Warda', - 'Southwood', - 'Clinch', - 'Halsell', - 'Mccaa', - 'Isreal', - 'Pinkett', - 'Asch', - 'Beauchesne', - 'Bruemmer', - 'Doebler', - 'Ehlinger', - 'Goelz', - 'Hashemi', - 'Karel', - 'Magiera', - 'Martorano', - 'Mooneyhan', - 'Cibrian', - 'Cavey', - 'Kosko', - 'Christo', - 'Cockrill', - 'Mansker', - 'Balls', - 'Degree', - 'Tiggs', - 'Alberico', - 'Clugston', - 'Elman', - 'Frueh', - 'Kampf', - 'Kochanski', - 'Leider', - 'Marsella', - 'Mckendree', - 'Moffa', - 'Quattrocchi', - 'Raval', - 'Snoke', - 'Akopyan', - 'Barrilleaux', - 'Cambria', - 'Kawaguchi', - 'Bonde', - 'Dawdy', - 'Willig', - 'Kazee', - 'Debow', - 'Beachum', - 'Vicks', - 'Aurelio', - 'Barocio', - 'Bonesteel', - 'Ezzo', - 'Gesell', - 'Krzeminski', - 'Madan', - 'Magda', - 'Manring', - 'Mcfaul', - 'Morera', - 'Purinton', - 'Retzer', - 'Schonfeld', - 'Staszak', - 'Stubbe', - 'Talerico', - 'Wikoff', - 'Zia', - 'Seyfried', - 'Diangelo', - 'Keach', - 'Shipton', - 'Shewmake', - 'Behrmann', - 'Hopps', - 'Paster', - 'Augenstein', - 'Castaldi', - 'Ferrufino', - 'Gregersen', - 'Hosseini', - 'Keniston', - 'Nadolski', - 'Ouimette', - 'Pellett', - 'Riebel', - 'Schwark', - 'Spelman', - 'Tesar', - 'Yahn', - 'Grossnickle', - 'Rosillo', - 'Dostie', - 'Noa', - 'Khalaf', - 'Cardosa', - 'Afzal', - 'Mercure', - 'Wheless', - 'Tailor', - 'Mcgarrah', - 'Miler', - 'Norfolk', - 'Crapps', - 'Dansereau', - 'Jenney', - 'Keast', - 'Lieser', - 'Mihm', - 'Porco', - 'Zelinsky', - 'Sleeth', - 'Mcelreath', - 'Hemann', - 'Capaldi', - 'Huggett', - 'Reagle', - 'Mayotte', - 'Liller', - 'Leen', - 'Demmer', - 'Tunison', - 'Woodbridge', - 'Haymes', - 'Cunning', - 'Blaze', - 'Eatman', - 'Ulysse', - 'Bagshaw', - 'Buczkowski', - 'Cardello', - 'Decola', - 'Diloreto', - 'Evola', - 'Glassburn', - 'Hazelbaker', - 'Holycross', - 'Minasian', - 'Regula', - 'Ruge', - 'Uhlman', - 'Lamprecht', - 'Shifflet', - 'Weikle', - 'Coupe', - 'Isherwood', - 'Dimon', - 'Pop', - 'Willhoite', - 'Bari', - 'Boise', - 'Doom', - 'Mccolley', - 'Bircher', - 'Wannamaker', - 'Eppes', - 'Pea', - 'Okeke', - 'Alpizar', - 'Arista', - 'Barbagallo', - 'Baumert', - 'Bhattacharya', - 'Gheen', - 'Hutchcraft', - 'Karlen', - 'Klier', - 'Ladnier', - 'Marrujo', - 'Reister', - 'Rorrer', - 'Tarpey', - 'Wisecarver', - 'Beydoun', - 'Fillinger', - 'Kemnitz', - 'Takata', - 'Leight', - 'Kross', - 'Junco', - 'Holmer', - 'Sando', - 'Biddix', - 'Dawood', - 'Frisco', - 'Flagler', - 'Arntz', - 'Bache', - 'Bundrick', - 'Glasson', - 'Los', - 'Scheiber', - 'Shellenbarger', - 'Steinmeyer', - 'Sura', - 'Tanski', - 'Teodoro', - 'Vanaken', - 'Jodoin', - 'Klinker', - 'Szydlowski', - 'Yamashiro', - 'Kutch', - 'Hoth', - 'Edwardson', - 'Gess', - 'Mohamad', - 'Goodine', - 'Carolina', - 'Blauser', - 'Emerich', - 'Flook', - 'Graul', - 'Gribben', - 'Herbold', - 'Kreutz', - 'Lavey', - 'Lukacs', - 'Maiorana', - 'Openshaw', - 'Plattner', - 'Sauro', - 'Schardt', - 'Tortorici', - 'Wendlandt', - 'Danowski', - 'Mcnellis', - 'Pinkowski', - 'Linz', - 'Virga', - 'Jardin', - 'Maclaughlin', - 'Rama', - 'Deline', - 'Kimbel', - 'Hagin', - 'Pottinger', - 'Detmer', - 'Ferrone', - 'Matthiesen', - 'Melchert', - 'Ruehl', - 'Takach', - 'Briese', - 'Elmendorf', - 'Valentini', - 'Hersom', - 'Bordeau', - 'Linsley', - 'Keatts', - 'Dina', - 'Boye', - 'Riviere', - 'Stodghill', - 'Madry', - 'Angelos', - 'Bou', - 'Ketterling', - 'Niemczyk', - 'Pardini', - 'Rippel', - 'Schieffer', - 'Schnee', - 'Shogren', - 'Sholl', - 'Ullmann', - 'Ure', - 'Curless', - 'Gonnella', - 'Tholen', - 'Valladolid', - 'Silbernagel', - 'Cohrs', - 'Shahin', - 'Beth', - 'Holmen', - 'Tippie', - 'Opie', - 'Sprowl', - 'Byam', - 'Bethany', - 'Saintil', - 'Auriemma', - 'Blust', - 'Dibello', - 'Digangi', - 'Farnam', - 'Farnan', - 'Linford', - 'Mcgroarty', - 'Meisenheimer', - 'Pagels', - 'Sauber', - 'Schwalbe', - 'Seemann', - 'Slivka', - 'Twardowski', - 'Wickey', - 'Zettler', - 'Zuchowski', - 'Feldhaus', - 'Baldock', - 'Cowman', - 'Carp', - 'Camera', - 'Balon', - 'Neveu', - 'Caminiti', - 'Carreira', - 'Gura', - 'Hershkowitz', - 'Killoran', - 'Narducci', - 'Reigel', - 'Saccone', - 'Tomasi', - 'Wieneke', - 'Sibrian', - 'Hashem', - 'Kellems', - 'Stouder', - 'Villamar', - 'Piette', - 'Wand', - 'Battey', - 'Staunton', - 'Bedore', - 'Hanel', - 'Jutras', - 'Kanner', - 'Mathiesen', - 'Northway', - 'Privitera', - 'Reichelt', - 'Zucco', - 'Roys', - 'Aderholt', - 'Lampson', - 'Olen', - 'Mcgarr', - 'Schools', - 'Leaphart', - 'Lykes', - 'Brightbill', - 'Koos', - 'Lahue', - 'Laplaca', - 'Naqvi', - 'Novo', - 'Puerta', - 'Siers', - 'Strutz', - 'Trimboli', - 'Waldie', - 'Goold', - 'Falke', - 'Corter', - 'Cartmell', - 'Brazel', - 'Farabee', - 'Majeed', - 'Hilden', - 'Kealoha', - 'Neider', - 'Parodi', - 'Rizza', - 'Rong', - 'Silberstein', - 'Snellgrove', - 'Trojanowski', - 'Warneke', - 'Wissler', - 'Yiu', - 'Grein', - 'Sak', - 'Daines', - 'Monzo', - 'Emmerson', - 'Lorraine', - 'Samaroo', - 'Edmund', - 'Cacace', - 'Dornan', - 'Eyman', - 'Hovanec', - 'Jeschke', - 'Limberg', - 'Maturo', - 'Pandey', - 'Somoza', - 'Streiff', - 'Wiemer', - 'Zablocki', - 'Crace', - 'Leinen', - 'Rucci', - 'Blyth', - 'Clemans', - 'Magid', - 'Ferrick', - 'Garriga', - 'Martir', - 'Tanton', - 'Hoon', - 'Echard', - 'Borrell', - 'Howden', - 'Gravett', - 'Lando', - 'Amacher', - 'Dalman', - 'Hollenbaugh', - 'Sigrist', - 'Tamashiro', - 'Therriault', - 'Villafranca', - 'Matthys', - 'Salois', - 'Sforza', - 'Swager', - 'Borah', - 'Sentell', - 'Besson', - 'Ghani', - 'Bilinski', - 'Holzinger', - 'Kus', - 'Lobianco', - 'Morawski', - 'Perz', - 'Sada', - 'Wollenberg', - 'Yusko', - 'Caughron', - 'Diffenderfer', - 'Slowinski', - 'Skiver', - 'Galland', - 'Hodes', - 'Boyne', - 'Towry', - 'Alers', - 'Hellums', - 'Certain', - 'Megginson', - 'Creer', - 'Coutee', - 'Strothers', - 'Stfleur', - 'Barga', - 'Bina', - 'Cellini', - 'Digiulio', - 'Douma', - 'Klement', - 'Mccambridge', - 'Parmeter', - 'Presto', - 'Salmi', - 'Seabaugh', - 'Barreda', - 'Nepomuceno', - 'Zent', - 'Yonce', - 'Loreto', - 'Honer', - 'Conquest', - 'Gathings', - 'Wims', - 'Upshur', - 'Aeschliman', - 'Casaus', - 'Dumke', - 'Earlywine', - 'Ferreyra', - 'Heyne', - 'Hudon', - 'Kuder', - 'Malia', - 'Brueckner', - 'Luchsinger', - 'Ornellas', - 'Ramseyer', - 'Weidemann', - 'Walbert', - 'Zola', - 'Linquist', - 'Storts', - 'Dente', - 'Lebleu', - 'Stockham', - 'Rollinson', - 'Auzenne', - 'Abebe', - 'Bartol', - 'Cozzolino', - 'Der', - 'Fata', - 'Gorr', - 'Janousek', - 'Moschella', - 'Riedy', - 'Dust', - 'Malmgren', - 'Puterbaugh', - 'Sacchetti', - 'Lascano', - 'Begnaud', - 'Duling', - 'Porteous', - 'Debnam', - 'Abron', - 'Delehanty', - 'Fazenbaker', - 'Flener', - 'Gora', - 'Herter', - 'Johann', - 'Keiter', - 'Lucca', - 'Passman', - 'Saindon', - 'Schoppe', - 'Skibinski', - 'Stueber', - 'Tegeler', - 'Jochim', - 'Buttner', - 'Crilly', - 'Swanton', - 'Muncey', - 'Negrin', - 'Thorburn', - 'Delpino', - 'Kinn', - 'Gaiter', - 'Obi', - 'Hohensee', - 'Rollman', - 'Scheff', - 'Shor', - 'Tumbleson', - 'Mccrum', - 'Knack', - 'Llano', - 'Saber', - 'Rosman', - 'Bankson', - 'Atkisson', - 'Kennel', - 'Cammon', - 'Bangura', - 'Cichy', - 'Gillikin', - 'Hiltner', - 'Lubben', - 'Mcqueeney', - 'Nasca', - 'Nordgren', - 'Ostermann', - 'Quito', - 'Sakowski', - 'Schut', - 'Stobaugh', - 'Alessio', - 'Gorelik', - 'Heinzman', - 'Westrich', - 'Nardella', - 'Cruzado', - 'Lansberry', - 'Dubreuil', - 'Nylander', - 'Rabel', - 'Moret', - 'Crout', - 'Ardrey', - 'Rolley', - 'Finks', - 'Cliett', - 'Caito', - 'Clingenpeel', - 'Delprete', - 'Dolen', - 'Heidrich', - 'Hinrichsen', - 'Jindra', - 'Madej', - 'Panzarella', - 'Sandin', - 'Seekins', - 'Shilts', - 'Sokoloff', - 'Maggart', - 'Pigman', - 'Travieso', - 'Denbow', - 'Dollison', - 'Gaye', - 'Binette', - 'Dutta', - 'Grandinetti', - 'Kitch', - 'Tangeman', - 'Finstad', - 'Rodkey', - 'Servis', - 'Tiwari', - 'Rodd', - 'Parfait', - 'Seck', - 'Delaurentis', - 'Dragan', - 'Fleig', - 'Giacobbe', - 'Hilligoss', - 'Kroh', - 'Lippe', - 'Maleski', - 'Perini', - 'Rutten', - 'Stauss', - 'Yoshikawa', - 'Dibattista', - 'Gilsdorf', - 'Riemenschneider', - 'Streck', - 'Gessler', - 'Springstead', - 'Zaki', - 'Lambie', - 'Barczak', - 'Ellerbrock', - 'Foresman', - 'Holstine', - 'Lemm', - 'Santillana', - 'Trautwein', - 'Unsworth', - 'Valderas', - 'Vaquero', - 'Vetsch', - 'Wadleigh', - 'Yonts', - 'Mcguiness', - 'Auvil', - 'Leeder', - 'Sprowls', - 'Cala', - 'Portalatin', - 'Casso', - 'Chirinos', - 'Less', - 'Baltzell', - 'Bo', - 'Whetsell', - 'Ledlow', - 'Fullbright', - 'Arnell', - 'Stainback', - 'Mcleish', - 'Lyn', - 'Bermeo', - 'Billet', - 'Craun', - 'Gladwell', - 'Goral', - 'Herbig', - 'Kluver', - 'Mermelstein', - 'Odette', - 'Poggi', - 'Schacher', - 'Thielman', - 'Cianciolo', - 'Ferrie', - 'Kapusta', - 'Kreager', - 'Messineo', - 'Rovira', - 'Stricklen', - 'Wansley', - 'Amell', - 'Baena', - 'Depaula', - 'Fickett', - 'Housewright', - 'Kreiger', - 'Legate', - 'Lutterman', - 'Men', - 'Pautz', - 'Swecker', - 'Tantillo', - 'Dudeck', - 'Bellas', - 'Marian', - 'Bienvenu', - 'Riden', - 'Hosein', - 'Couser', - 'Batterton', - 'Desantos', - 'Dieterle', - 'Drabek', - 'Grennan', - 'Greulich', - 'Ludlam', - 'Maltos', - 'Marcin', - 'Ostertag', - 'Rednour', - 'Tippetts', - 'Updyke', - 'Ormsbee', - 'Reutter', - 'Uyehara', - 'Musumeci', - 'Antonini', - 'Thistle', - 'Marcia', - 'Renne', - 'Jines', - 'Dorothy', - 'Menter', - 'Crosser', - 'Ditommaso', - 'Glueck', - 'Malta', - 'Mcgranahan', - 'Mensing', - 'Ostroff', - 'Rota', - 'Rothfuss', - 'Borcherding', - 'Haveman', - 'Swallows', - 'Heltzel', - 'Aloi', - 'Stipp', - 'Broda', - 'Darter', - 'Gressett', - 'Brasier', - 'Lana', - 'Crooke', - 'Seegers', - 'Sirmons', - 'Berberian', - 'Goers', - 'Losch', - 'Memon', - 'Paternoster', - 'Rierson', - 'Miyake', - 'Barndt', - 'Kirstein', - 'Azua', - 'Zeck', - 'Britain', - 'Lanman', - 'Gorges', - 'Clock', - 'Alman', - 'Callicutt', - 'Walford', - 'Searight', - 'Eakle', - 'Federici', - 'Hosack', - 'Jarecki', - 'Kauffmann', - 'Maras', - 'Nisley', - 'Sandahl', - 'Shidler', - 'Wnek', - 'Moneymaker', - 'Santander', - 'Schneeberger', - 'Luviano', - 'Gorin', - 'Negus', - 'Coulston', - 'Polin', - 'Winslett', - 'Anstett', - 'Cowsert', - 'Dipiazza', - 'Fitting', - 'Forslund', - 'Poquette', - 'Tibbets', - 'Tomasini', - 'Toor', - 'Starry', - 'Venema', - 'Cedano', - 'Carro', - 'Samons', - 'Matty', - 'Ellenwood', - 'Kilcrease', - 'Noblin', - 'Decatur', - 'Heckard', - 'Nard', - 'Beighley', - 'Delamater', - 'Eblen', - 'Heninger', - 'Kehn', - 'Rotunno', - 'Uppal', - 'Hynek', - 'Zenk', - 'Brasil', - 'Mu', - 'Julio', - 'Cassar', - 'Crisco', - 'Oriley', - 'Turton', - 'Goens', - 'Cargo', - 'Toure', - 'Breitbach', - 'Cahalan', - 'Chadha', - 'Kittinger', - 'Marnell', - 'Masias', - 'Matousek', - 'Mittal', - 'Nieblas', - 'Onan', - 'Purdum', - 'Tursi', - 'Esplin', - 'Etsitty', - 'Fratto', - 'Przybyla', - 'Cassin', - 'Nitti', - 'Arshad', - 'Sandoz', - 'Walzer', - 'Everton', - 'Russum', - 'Morland', - 'Fennel', - 'Viel', - 'Jarrells', - 'Vassell', - 'Frigo', - 'Kodama', - 'Naron', - 'Oelke', - 'Remaley', - 'Shean', - 'Cloonan', - 'Clayman', - 'Lasch', - 'Lepard', - 'Rewis', - 'Vankeuren', - 'Lightbody', - 'Houseworth', - 'Caison', - 'Denmon', - 'Rauls', - 'Sallie', - 'Humphery', - 'Showell', - 'Raysor', - 'Angotti', - 'Barbero', - 'Buxbaum', - 'Capella', - 'Horsch', - 'Kunselman', - 'Nishikawa', - 'Perotti', - 'Sprung', - 'Szucs', - 'Emch', - 'Kotula', - 'Mendizabal', - 'Yeaman', - 'Beste', - 'Kader', - 'Forker', - 'Wiggers', - 'Cotham', - 'Primo', - 'Fetterhoff', - 'Giarrusso', - 'Glosser', - 'Lumbreras', - 'Rosano', - 'Strohecker', - 'Wanek', - 'Waycaster', - 'Worthley', - 'Salasar', - 'Boulos', - 'Pulsipher', - 'Scheider', - 'Lorimer', - 'Alamilla', - 'Zapp', - 'Deis', - 'Tariq', - 'Kasey', - 'Famiglietti', - 'Flansburg', - 'Georgiou', - 'Groft', - 'Heistand', - 'Merker', - 'Stoeckel', - 'Tackitt', - 'Verbeck', - 'Weyers', - 'Wiltrout', - 'Brabec', - 'Caligiuri', - 'Dudzinski', - 'Grieger', - 'Benfer', - 'Pesta', - 'Wool', - 'Sunshine', - 'Oka', - 'Stamour', - 'Barrio', - 'Mathe', - 'Vanduyne', - 'Brager', - 'Mcphatter', - 'Ahluwalia', - 'Borys', - 'Dreibelbis', - 'Kalmbach', - 'Karwoski', - 'Moomaw', - 'Youngren', - 'Offerman', - 'Nine', - 'Symington', - 'Branan', - 'Turberville', - 'Heber', - 'Loughridge', - 'Vanderberg', - 'Mccannon', - 'Linda', - 'Dupee', - 'Cottom', - 'Mcphearson', - 'Razor', - 'Buchwald', - 'Fraze', - 'Grannis', - 'Krolikowski', - 'Lapidus', - 'Madruga', - 'Mcmartin', - 'Quinlivan', - 'Riaz', - 'Spittler', - 'Zahm', - 'Zender', - 'Eisman', - 'Hourihan', - 'Shirazi', - 'Herendeen', - 'Perdew', - 'Pendell', - 'Chernoff', - 'Lyell', - 'Clarey', - 'Macken', - 'Guthridge', - 'Redditt', - 'Bedi', - 'Debenedictis', - 'Distel', - 'Gapinski', - 'Iwanski', - 'Medici', - 'Schmutz', - 'Tuel', - 'Verburg', - 'Galgano', - 'Skogen', - 'Aymond', - 'Raymo', - 'Croney', - 'Carry', - 'Rhynes', - 'Lamour', - 'Shedrick', - 'Tookes', - 'Baltierra', - 'Leitzel', - 'Letchworth', - 'Montesino', - 'Preis', - 'Sanzone', - 'Shantz', - 'Teo', - 'Twohig', - 'Wajda', - 'Windisch', - 'Zinck', - 'Fiero', - 'Hornby', - 'Paget', - 'Serano', - 'Rodrick', - 'Lewison', - 'Dyas', - 'Delcarmen', - 'Garske', - 'Hontz', - 'Mcquown', - 'Melling', - 'Rolando', - 'Rosencrans', - 'Steichen', - 'Teeples', - 'Forseth', - 'Quijas', - 'Schraeder', - 'Vaidya', - 'Ventre', - 'Mountjoy', - 'Morr', - 'Leviner', - 'Paulette', - 'Dobie', - 'Brue', - 'Prier', - 'Biffle', - 'Neyland', - 'Valcourt', - 'Mckeithen', - 'Lemelle', - 'Alviar', - 'Auth', - 'Bahm', - 'Bierbaum', - 'Cazier', - 'Eschbach', - 'Etzler', - 'Nowlan', - 'Sahota', - 'Vanaman', - 'Zaugg', - 'Hogeland', - 'Choat', - 'Walmer', - 'Cepero', - 'Michal', - 'Foxwell', - 'Decoursey', - 'Molyneaux', - 'Peat', - 'Jeanfrancois', - 'Arevalos', - 'Bachert', - 'Beachler', - 'Berrones', - 'Clavijo', - 'Elsen', - 'Fuhs', - 'Hooven', - 'Johannessen', - 'Klausner', - 'Masso', - 'Puzio', - 'Sekula', - 'Smyser', - 'Stepanian', - 'Barg', - 'Trueman', - 'Constante', - 'Cubas', - 'Dowers', - 'Pratts', - 'Cockburn', - 'Counce', - 'Nappier', - 'Lindon', - 'Burrowes', - 'Cokley', - 'Tillmon', - 'Bao', - 'Inks', - 'Liberato', - 'Moehring', - 'Ryker', - 'Sar', - 'Swartzendruber', - 'Torgersen', - 'Treto', - 'Tungate', - 'Ricotta', - 'Weesner', - 'Willyard', - 'Callicoat', - 'Hoque', - 'Atkison', - 'Mcwherter', - 'Dubuisson', - 'Wanzer', - 'Stradford', - 'Abruzzo', - 'Amerman', - 'Bame', - 'Bantz', - 'Bleakley', - 'Galt', - 'Hoobler', - 'Jaquith', - 'Lessman', - 'Polinski', - 'Rasche', - 'Roeber', - 'Rubright', - 'Sarnowski', - 'Signore', - 'Solum', - 'Vankampen', - 'Vath', - 'Malmquist', - 'Mittelstadt', - 'Belyea', - 'Haverty', - 'Wickett', - 'Sansing', - 'Yeatman', - 'Brocker', - 'Wonders', - 'Both', - 'Rabun', - 'Rocke', - 'Meachum', - 'Blane', - 'Lapsley', - 'Biswas', - 'Derocher', - 'Haran', - 'Hehn', - 'Keshishian', - 'Kniffin', - 'Lacina', - 'Skolnik', - 'Spiewak', - 'Wileman', - 'Eble', - 'Kraynak', - 'Wiesen', - 'Micheli', - 'Scroggin', - 'Roch', - 'Denise', - 'Altenburg', - 'Hornstein', - 'Netto', - 'Opel', - 'Passey', - 'Roeske', - 'Schrantz', - 'Abrahamsen', - 'Powless', - 'Callais', - 'Desjardin', - 'Pirro', - 'Yonkers', - 'Macallister', - 'Dady', - 'Ruskin', - 'Escott', - 'Abbot', - 'Sankar', - 'Bolar', - 'Angelucci', - 'Biegel', - 'Cirone', - 'Damewood', - 'Flett', - 'Kronenberg', - 'Ky', - 'Nagler', - 'Perlstein', - 'Saperstein', - 'Tenbrink', - 'Vana', - 'Wnuk', - 'Bonnema', - 'Schoenecker', - 'Pichler', - 'Armendarez', - 'Oiler', - 'Rouch', - 'Boas', - 'Laracuente', - 'Milbourn', - 'Summy', - 'Counter', - 'Gracie', - 'Belfield', - 'Bynoe', - 'Jalloh', - 'Blazier', - 'Bochenek', - 'Broughman', - 'Chuong', - 'Cregger', - 'Estacio', - 'Kaleta', - 'Lanctot', - 'Mish', - 'Novosel', - 'Passero', - 'Ripplinger', - 'Vitt', - 'Walborn', - 'Friscia', - 'Memmott', - 'Tripi', - 'Weinhold', - 'Honn', - 'Gianni', - 'Poch', - 'Sagar', - 'Markum', - 'Primmer', - 'Belmore', - 'Rain', - 'Bevard', - 'Skyles', - 'Farland', - 'Mccleese', - 'Teachey', - 'Moulden', - 'Antolin', - 'Augello', - 'Borrayo', - 'Effler', - 'Hornak', - 'Hosman', - 'Leingang', - 'Limbach', - 'Oregel', - 'Ritzman', - 'Rochefort', - 'Schimke', - 'Stefanelli', - 'Vien', - 'Zurn', - 'Badolato', - 'Bieri', - 'Clarkin', - 'Folino', - 'Kelchner', - 'Pote', - 'Brahm', - 'Hoop', - 'Macbride', - 'Hunting', - 'Brule', - 'Wainright', - 'Rolison', - 'Bennie', - 'Banghart', - 'Bertke', - 'Bozzo', - 'Gadomski', - 'Granberg', - 'Kostecki', - 'Lemelin', - 'Levengood', - 'Puskas', - 'Swanstrom', - 'Willcutt', - 'Deitrich', - 'Grieves', - 'Ferran', - 'Boileau', - 'Kendra', - 'Trippe', - 'Mcconnel', - 'Cara', - 'Stephans', - 'Bachus', - 'Applin', - 'Utsey', - 'Auston', - 'Arras', - 'Bencosme', - 'Berntsen', - 'Decarolis', - 'Dettloff', - 'Duerksen', - 'Pavlovic', - 'Schwantes', - 'Sjostrom', - 'Sugiyama', - 'Sulak', - 'Virani', - 'Winberg', - 'Yoshimoto', - 'Comito', - 'Pandolfo', - 'Cathers', - 'Hardisty', - 'Collom', - 'Wain', - 'Worthing', - 'Leep', - 'Simo', - 'Boom', - 'Bald', - 'Applegarth', - 'Gilbreth', - 'Griest', - 'Jobin', - 'Matsuura', - 'Misko', - 'Scerbo', - 'Scheidler', - 'Sterba', - 'Tomaino', - 'Wixson', - 'Yadao', - 'Hietpas', - 'Gruss', - 'Fors', - 'Gosse', - 'Katt', - 'Virk', - 'Quebedeaux', - 'Barkey', - 'Salam', - 'Willford', - 'Tarry', - 'Chancy', - 'Beynon', - 'Eckes', - 'Eischen', - 'Felger', - 'Kimm', - 'Labate', - 'Mehan', - 'Netzer', - 'Strosnider', - 'Trezza', - 'Vial', - 'Waugaman', - 'Zieman', - 'Ankeny', - 'Digman', - 'Farino', - 'Faro', - 'Vasconcelos', - 'Nevill', - 'Rave', - 'Sabine', - 'Hagg', - 'Weightman', - 'Berton', - 'Fipps', - 'Knapper', - 'Camel', - 'Gilkes', - 'Aldous', - 'Delucca', - 'Dicke', - 'Evitts', - 'Hachey', - 'Rinck', - 'Treese', - 'Uher', - 'Victorio', - 'Vignola', - 'Willert', - 'Baun', - 'Wever', - 'Varn', - 'Yokum', - 'Dunk', - 'Maben', - 'Arzu', - 'Guider', - 'Bonhomme', - 'Majette', - 'Crislip', - 'Gresko', - 'Luppino', - 'Posch', - 'Potenza', - 'Rial', - 'Ruderman', - 'Shaff', - 'Balboni', - 'Solheim', - 'Mey', - 'Sittig', - 'Perman', - 'Sumners', - 'Deaner', - 'Keizer', - 'Reves', - 'Glanville', - 'Menzie', - 'Mccowen', - 'Steib', - 'Portee', - 'Azad', - 'Dallaire', - 'Denno', - 'Deptula', - 'Fischman', - 'Guilbault', - 'Imperato', - 'Koehne', - 'Menning', - 'Mirelez', - 'Stanislawski', - 'Streb', - 'Sumida', - 'Wolke', - 'Kerfoot', - 'Pirie', - 'Saracino', - 'Maslanka', - 'Slominski', - 'Nienaber', - 'Serena', - 'Kamper', - 'Matheis', - 'Westin', - 'Ishman', - 'Biagi', - 'Chiou', - 'Dieckmann', - 'Frieden', - 'Huestis', - 'Presutti', - 'Ribas', - 'Siedlecki', - 'Steege', - 'Uehara', - 'Petrosyan', - 'Siebold', - 'Turi', - 'Rady', - 'Vanorman', - 'Arif', - 'Hiland', - 'Naidu', - 'Clagett', - 'Ludy', - 'Bodley', - 'Avelino', - 'Citro', - 'Cuda', - 'Derbyshire', - 'Kruszewski', - 'Kupper', - 'Mahl', - 'Muratore', - 'Noecker', - 'Osmer', - 'Pasquariello', - 'Schlick', - 'Snover', - 'Strzelecki', - 'Studt', - 'Sunga', - 'Belmares', - 'Seifried', - 'Urioste', - 'Housh', - 'Babu', - 'Bures', - 'Augusto', - 'Faddis', - 'Pun', - 'Chopp', - 'Tullock', - 'Sea', - 'Boisseau', - 'Herbin', - 'Balcer', - 'Copus', - 'Eichenberger', - 'Enterline', - 'Gamarra', - 'Gursky', - 'Hovsepian', - 'Laffin', - 'Melena', - 'Rappe', - 'Soma', - 'Spira', - 'Spraker', - 'Teuscher', - 'Hochhalter', - 'Brenden', - 'Snee', - 'Polan', - 'Hataway', - 'Tirey', - 'Cobler', - 'Marren', - 'Ress', - 'Bennis', - 'Busha', - 'Galler', - 'Orea', - 'Nailor', - 'Magby', - 'Bridgett', - 'Island', - 'Camino', - 'Coderre', - 'Gangloff', - 'Gillilan', - 'Goergen', - 'Henthorne', - 'Heverly', - 'Loughry', - 'Records', - 'Schweikert', - 'Seeds', - 'Vanderwerf', - 'Westall', - 'Cristiano', - 'Biser', - 'Cartmill', - 'Greenly', - 'Kountz', - 'Craney', - 'Sheffey', - 'Gelin', - 'Gourdine', - 'Canham', - 'Edgmon', - 'Enz', - 'Feldpausch', - 'Hestand', - 'Kaus', - 'Kostelnik', - 'Ocanas', - 'Riggi', - 'Rohl', - 'Scheurer', - 'Sleeman', - 'Tosi', - 'Phegley', - 'Abelson', - 'Mclees', - 'Sinor', - 'Babson', - 'Whalley', - 'Manton', - 'Patteson', - 'Doyen', - 'Asad', - 'Thurmon', - 'Cassese', - 'Ditmore', - 'Duva', - 'Pilato', - 'Polaski', - 'Rzepka', - 'Sevin', - 'Sivak', - 'Speckman', - 'Stepien', - 'Switalski', - 'Valletta', - 'Knoth', - 'Niver', - 'Ciancio', - 'Giza', - 'Liebowitz', - 'Orengo', - 'Rothgeb', - 'Witz', - 'Airhart', - 'Gayman', - 'Belland', - 'Eury', - 'Randal', - 'Mcghie', - 'Briganti', - 'Hoopingarner', - 'Lugar', - 'Manfre', - 'Mongelli', - 'Squibb', - 'Vasil', - 'Cap', - 'Veillon', - 'Ege', - 'Spice', - 'Nevel', - 'Vanleer', - 'Petway', - 'Petitfrere', - 'Barcena', - 'Belville', - 'Brezina', - 'Ketcherside', - 'Knodel', - 'Krinsky', - 'Lundahl', - 'Mescher', - 'Pilat', - 'Sneller', - 'Staller', - 'Steinhaus', - 'Stensrud', - 'Szalay', - 'Tani', - 'Saviano', - 'Genna', - 'Emry', - 'Allin', - 'Harvel', - 'Harth', - 'Pay', - 'Harries', - 'Brannum', - 'Elijah', - 'Hoyte', - 'Bazinet', - 'Bhandari', - 'Brozek', - 'Cava', - 'Dalbey', - 'Delgiudice', - 'Klages', - 'Riffey', - 'Straube', - 'Zagar', - 'Zientek', - 'Dilger', - 'Hof', - 'Karwowski', - 'Rybarczyk', - 'Spiering', - 'Stamos', - 'Gangemi', - 'Olavarria', - 'Sardinas', - 'Magin', - 'Payano', - 'Deady', - 'Henricksen', - 'Kary', - 'Garnier', - 'Babic', - 'Behymer', - 'Billig', - 'Huegel', - 'Ishihara', - 'Mcglinchey', - 'Misuraca', - 'Petrosino', - 'Zizzo', - 'Reierson', - 'Wadman', - 'Brander', - 'Risko', - 'Basye', - 'Mcmakin', - 'Straughan', - 'Chesnutt', - 'Sima', - 'Ree', - 'Mankins', - 'Soberanis', - 'Greenup', - 'Commodore', - 'Carucci', - 'Defibaugh', - 'Finfrock', - 'Funston', - 'Grantz', - 'Guiney', - 'Ohrt', - 'Tinsman', - 'Godek', - 'Mcgrory', - 'Mikeska', - 'Kamer', - 'Lovas', - 'Kirshner', - 'Bevacqua', - 'Franqui', - 'Walts', - 'Doke', - 'Orsborn', - 'Tavernier', - 'Kibble', - 'Scipio', - 'Diop', - 'Antczak', - 'Bastida', - 'Callister', - 'Dusseau', - 'Ficarra', - 'Garcilazo', - 'Hughett', - 'Liebel', - 'Rodenbaugh', - 'Rosselli', - 'Teresi', - 'Bohnsack', - 'Steidl', - 'Vanderheiden', - 'Demma', - 'Dutson', - 'Mcmeekin', - 'Glassford', - 'Serrao', - 'Marriner', - 'Mcchristian', - 'Lias', - 'Blahnik', - 'Brunke', - 'Daleo', - 'Fullam', - 'Goetzinger', - 'Leva', - 'Rehder', - 'Ripperger', - 'Shindler', - 'Tussing', - 'Mayr', - 'Rozzi', - 'Bonsignore', - 'Te', - 'Graft', - 'Ok', - 'Clink', - 'Mccamey', - 'Goldring', - 'Tartt', - 'Fullilove', - 'Amodio', - 'Arkin', - 'Dettmann', - 'Ellingwood', - 'Figura', - 'Fritzinger', - 'Heilmann', - 'Hillstrom', - 'Marasigan', - 'Pavlov', - 'Totman', - 'Dokken', - 'Serpico', - 'Shumard', - 'Rathman', - 'Siegmund', - 'Woodhull', - 'Oregon', - 'Roselle', - 'Taul', - 'Maddix', - 'Nwosu', - 'Bavaro', - 'Carella', - 'Cowdrey', - 'Goodnough', - 'Koffler', - 'Mahajan', - 'Montalvan', - 'Morga', - 'Parrella', - 'Quiggle', - 'Rehrig', - 'Rotondi', - 'Tavenner', - 'Wigger', - 'Yax', - 'Bartko', - 'Netzel', - 'Zechman', - 'Socia', - 'Vea', - 'Wemple', - 'Matti', - 'Striplin', - 'Hollin', - 'Geddie', - 'Nolden', - 'Freeney', - 'Jeanjacques', - 'Bermudes', - 'Castrellon', - 'Catino', - 'Feeser', - 'Kreitz', - 'Maisano', - 'Melkonian', - 'Toste', - 'Vancura', - 'Bylsma', - 'Wiant', - 'Mcpheron', - 'Gere', - 'Geoffroy', - 'Fuston', - 'Petteway', - 'Barsky', - 'Bovard', - 'Buttars', - 'Christophersen', - 'Dudzik', - 'Ganger', - 'Hilgers', - 'Holzhauer', - 'Minervini', - 'Pong', - 'Rozycki', - 'Sulzer', - 'Tauscher', - 'Upright', - 'Verastegui', - 'Lobello', - 'Sandt', - 'Timbrook', - 'Yniguez', - 'Nuzzi', - 'Sakata', - 'Koran', - 'Veloso', - 'Cullers', - 'Culton', - 'Reynold', - 'Feagins', - 'Amaker', - 'Cafferty', - 'Coontz', - 'Iden', - 'Mazzotta', - 'Montanye', - 'Wandell', - 'Weiman', - 'Vik', - 'Staib', - 'Lasso', - 'Waynick', - 'Boniface', - 'Massingale', - 'Gainous', - 'Sharper', - 'Columbia', - 'Felkins', - 'Gatzke', - 'Heindel', - 'Ludeman', - 'Mcmunn', - 'Mogavero', - 'Ratti', - 'Rickabaugh', - 'Ripper', - 'Tessman', - 'Triano', - 'Vanderpol', - 'Langille', - 'Holten', - 'Steeley', - 'Solan', - 'Devaul', - 'Lindler', - 'Armor', - 'Fambrough', - 'Golliday', - 'Bognar', - 'Gamba', - 'Gettinger', - 'Hanzel', - 'Krumwiede', - 'Marcinkowski', - 'Nicolay', - 'Peppard', - 'Sisti', - 'Sundeen', - 'Senatore', - 'Diebel', - 'Demarais', - 'Letellier', - 'Goon', - 'Texidor', - 'Baughan', - 'Gunder', - 'Lalor', - 'Wigglesworth', - 'Aird', - 'Basey', - 'Afshar', - 'Anhalt', - 'Bondoc', - 'Bunten', - 'Daniello', - 'Kazmierski', - 'Marcott', - 'Petruska', - 'Trejos', - 'Droege', - 'Fukumoto', - 'Harju', - 'Hauf', - 'Yagi', - 'Mccallie', - 'Moulds', - 'Singleterry', - 'Ramkissoon', - 'Sanks', - 'Siggers', - 'Myrie', - 'Conteh', - 'Biss', - 'Brees', - 'Collopy', - 'Dashner', - 'Dehaas', - 'Delzer', - 'Fees', - 'Finocchiaro', - 'Forsgren', - 'Giampietro', - 'Levandowski', - 'Mallick', - 'Maudlin', - 'Micheletti', - 'Newhard', - 'Parmentier', - 'Pintado', - 'Pliego', - 'Radigan', - 'Selke', - 'Uptain', - 'Wigton', - 'Zabinski', - 'Becenti', - 'Guthmiller', - 'Malecha', - 'Eardley', - 'Muscat', - 'Ruhe', - 'Battersby', - 'Lamie', - 'Stan', - 'Dutch', - 'Duplechain', - 'Dildy', - 'Auch', - 'Baltzer', - 'Degaetano', - 'Mileski', - 'Parrillo', - 'Schoof', - 'Stires', - 'Villescas', - 'Knittle', - 'Degrave', - 'Deihl', - 'Moseman', - 'Prillaman', - 'Wakeley', - 'Jake', - 'Murden', - 'Shareef', - 'Yarbough', - 'Bothe', - 'Boutilier', - 'Breck', - 'Buschman', - 'Coccia', - 'Eberlein', - 'Harriger', - 'Neas', - 'Sullenger', - 'Walp', - 'Yaple', - 'Zinger', - 'Zufelt', - 'Marinaccio', - 'Viele', - 'Markee', - 'Melody', - 'Rooke', - 'Ales', - 'Mumphrey', - 'Bessinger', - 'Bialas', - 'Brugh', - 'Chum', - 'Diehm', - 'Frieze', - 'Hieber', - 'Malouf', - 'Maltz', - 'Mcmanaway', - 'Musante', - 'Pester', - 'Roda', - 'Snarr', - 'Tovey', - 'Buchmann', - 'Fluck', - 'Sadowsky', - 'Viteri', - 'Loewe', - 'Mullaly', - 'Lamboy', - 'Bouman', - 'Provencal', - 'Siddons', - 'Chelette', - 'Rachels', - 'Dynes', - 'Nobel', - 'Desselle', - 'Tillison', - 'Bajaj', - 'Bresee', - 'Hisel', - 'Mallo', - 'Meints', - 'Potocki', - 'Spore', - 'Steier', - 'Toothaker', - 'Wildt', - 'Darcangelo', - 'Karbowski', - 'Scaccia', - 'Lascola', - 'Duman', - 'Mccaul', - 'Rowton', - 'Setters', - 'Hendryx', - 'Belson', - 'Manny', - 'Winckler', - 'Longe', - 'Mclucas', - 'Lenon', - 'Linen', - 'Anstine', - 'Belkin', - 'Drozdowski', - 'Ender', - 'Ferra', - 'Lessig', - 'Marucci', - 'Nardo', - 'Nipp', - 'Passarella', - 'Roecker', - 'Siddique', - 'Stanczak', - 'Stavros', - 'Tomasetti', - 'Lagreca', - 'Seegmiller', - 'Keena', - 'Suddarth', - 'Wayt', - 'Matas', - 'Ryer', - 'Mortimore', - 'Durnell', - 'Pieters', - 'Slocumb', - 'Andaya', - 'Brymer', - 'Dufek', - 'Ekman', - 'Espericueta', - 'Feltes', - 'Hammann', - 'Heydt', - 'Inthavong', - 'Jagielski', - 'Nast', - 'Petrucelli', - 'Phippen', - 'Vanderzanden', - 'Whinery', - 'Zatarain', - 'Zelenak', - 'Aquilina', - 'Hougland', - 'Isais', - 'Canney', - 'Flath', - 'Ragon', - 'Len', - 'Violet', - 'Carra', - 'Everetts', - 'Lockey', - 'Dahmer', - 'Fuquay', - 'Alpers', - 'Borromeo', - 'Bringas', - 'Brumit', - 'Campanile', - 'Folts', - 'Hirai', - 'Kiessling', - 'Krogstad', - 'Ovitt', - 'Bhardwaj', - 'Hlavaty', - 'Monceaux', - 'Spatola', - 'Trunzo', - 'Girvin', - 'Shady', - 'Grimley', - 'Tagg', - 'Weddell', - 'Mcfadyen', - 'Reagin', - 'Philo', - 'Emily', - 'Codd', - 'Cherrington', - 'Skates', - 'Deary', - 'Ballester', - 'Barilla', - 'Cicchetti', - 'Dyche', - 'Goossen', - 'Graveline', - 'Hajduk', - 'Halliwell', - 'Kohnen', - 'Kupiec', - 'Machacek', - 'Manship', - 'Slinker', - 'Mallozzi', - 'Dotter', - 'Brazeau', - 'Manon', - 'Crofford', - 'Gauthreaux', - 'Petillo', - 'Bailor', - 'Ganesh', - 'Reaser', - 'Barren', - 'Adachi', - 'Aguiniga', - 'Cartrette', - 'Crady', - 'Hegland', - 'Isner', - 'Karasek', - 'Labrum', - 'Maroon', - 'Rullo', - 'Schull', - 'Stawicki', - 'Withee', - 'Penfold', - 'Foronda', - 'Claridge', - 'Coiner', - 'Guimaraes', - 'Mawyer', - 'Rivkin', - 'Kiggins', - 'Hackel', - 'Wey', - 'Fairhurst', - 'Albertini', - 'Gaal', - 'Flurry', - 'Patricia', - 'Savery', - 'Colen', - 'Cuthrell', - 'Maffett', - 'Dungey', - 'Luter', - 'Hurston', - 'Ahles', - 'Czapla', - 'Gallas', - 'Kotecki', - 'Lazzari', - 'Marcellino', - 'Valvo', - 'Vukovich', - 'Wisor', - 'Agler', - 'Wease', - 'Gallentine', - 'Christoph', - 'Poyer', - 'Norment', - 'Rhett', - 'Amabile', - 'Barish', - 'Heifner', - 'Kolarik', - 'Mcquarrie', - 'Morua', - 'Nahas', - 'Razzano', - 'Riegle', - 'Torralba', - 'Perfetti', - 'Stalzer', - 'Killman', - 'Lenning', - 'Wyler', - 'Soward', - 'Releford', - 'Battisti', - 'Bergum', - 'Catapano', - 'Doerner', - 'Ehlen', - 'Finken', - 'Genereux', - 'Hillegas', - 'Hopple', - 'Kaatz', - 'Lacson', - 'Macario', - 'Marzolf', - 'Muha', - 'Picha', - 'Springston', - 'Stooksbury', - 'Weide', - 'Glodowski', - 'Lueth', - 'Assaf', - 'Robuck', - 'Lamaster', - 'Foulkes', - 'Swopes', - 'Winkfield', - 'Aristizabal', - 'Aylesworth', - 'Bellotti', - 'Bittick', - 'Capistran', - 'Cizek', - 'Dinneen', - 'Ellender', - 'Friske', - 'Hoffa', - 'Klinge', - 'Kuklinski', - 'Luzier', - 'Martensen', - 'Rolin', - 'Shankles', - 'Siska', - 'Wiegman', - 'Winterbottom', - 'Crookston', - 'Gorospe', - 'Curci', - 'Lamberty', - 'Antonetti', - 'Sheer', - 'Durning', - 'Hootman', - 'Doub', - 'Klaiber', - 'Mayeaux', - 'Domingos', - 'Wheeless', - 'Vantrease', - 'Summerhill', - 'Agresta', - 'Annas', - 'Aquilar', - 'Crea', - 'Froese', - 'Medlen', - 'Peeters', - 'Rhudy', - 'Risse', - 'Schor', - 'Zimmerer', - 'Bombardier', - 'Halfhill', - 'Koppenhaver', - 'Kruckenberg', - 'Boccia', - 'Rella', - 'Carelli', - 'Overson', - 'Tamburro', - 'Rosamond', - 'Lie', - 'Mesquita', - 'Jennett', - 'Jewel', - 'Waye', - 'Bogucki', - 'Colpitts', - 'Galpin', - 'Hrdlicka', - 'Kading', - 'Kushnir', - 'Leano', - 'Liebig', - 'Mceuen', - 'Nestler', - 'Payer', - 'Santarelli', - 'Schrupp', - 'Schwarze', - 'Semrau', - 'Solanki', - 'Terzian', - 'Treloar', - 'Ureno', - 'Vohra', - 'Voshell', - 'Nakanishi', - 'Senese', - 'Dierker', - 'Quinley', - 'Monier', - 'Rounsaville', - 'Mcfaddin', - 'Defrance', - 'Joynes', - 'Levert', - 'Adragna', - 'Buczynski', - 'Cranor', - 'Englebert', - 'Furney', - 'Gorny', - 'Mockler', - 'Pavlicek', - 'Petrini', - 'Schadt', - 'Slagel', - 'Cumpston', - 'Priore', - 'Paonessa', - 'Carling', - 'Espaillat', - 'Hem', - 'Griffo', - 'Tomer', - 'Venn', - 'Giraud', - 'Becks', - 'Mungin', - 'Attard', - 'Brucato', - 'Dreyfus', - 'Droz', - 'Falck', - 'Firebaugh', - 'Fiser', - 'Hemmelgarn', - 'Hofacker', - 'Kreeger', - 'Rippee', - 'Ruehle', - 'Saputo', - 'Scovill', - 'Silbaugh', - 'Smolenski', - 'Spickler', - 'Swango', - 'Kaehler', - 'Mootz', - 'Noblett', - 'Zarcone', - 'Katzenberger', - 'Kita', - 'Brezinski', - 'Castles', - 'Padin', - 'Hinde', - 'Barretta', - 'Amiri', - 'Shelburne', - 'Mccoin', - 'Heaston', - 'Aldredge', - 'Milhouse', - 'Wilbon', - 'Cephus', - 'Barsness', - 'Belch', - 'Blatter', - 'Boyum', - 'Corvino', - 'Dagenais', - 'Doscher', - 'Elizarraraz', - 'Gierke', - 'Habegger', - 'Ketcher', - 'Kristiansen', - 'Oldroyd', - 'Sandage', - 'Tesoriero', - 'Unzueta', - 'Wollam', - 'Cefalu', - 'Achey', - 'Wegmann', - 'Lessner', - 'Bunk', - 'Mallin', - 'Polis', - 'Aronoff', - 'Portal', - 'Crock', - 'Escher', - 'Medler', - 'Pretty', - 'Younge', - 'Agbayani', - 'Brinkmeyer', - 'Castrillon', - 'Feick', - 'Gutmann', - 'Hagenbuch', - 'Hesseltine', - 'Houska', - 'Kimzey', - 'Kolasa', - 'Lentine', - 'Lobaugh', - 'Maimone', - 'Meshell', - 'Nardini', - 'Rosetti', - 'Siefker', - 'Sileo', - 'Silveria', - 'Argumedo', - 'Lesmeister', - 'Donnan', - 'Hermans', - 'Raggio', - 'Dupras', - 'Empson', - 'Bevier', - 'Tumey', - 'Donn', - 'Darville', - 'Douse', - 'Cheyne', - 'Dewing', - 'Jansma', - 'Mayeda', - 'Nield', - 'Obermiller', - 'Opfer', - 'Surma', - 'Tiffin', - 'Tirpak', - 'Wassel', - 'Blickenstaff', - 'Dorland', - 'Kulhanek', - 'Andras', - 'Estupinan', - 'Gonce', - 'Weast', - 'Souto', - 'Guirguis', - 'Glazebrook', - 'Dain', - 'Loyer', - 'Bensley', - 'Verge', - 'Tubman', - 'Onley', - 'Dais', - 'Barash', - 'Bullman', - 'Crispino', - 'Davino', - 'Isenhart', - 'Kneller', - 'Loschiavo', - 'Opper', - 'Pfleger', - 'Wahler', - 'Zelasko', - 'Havrilla', - 'Mintzer', - 'Devoll', - 'Giannelli', - 'Sees', - 'Barritt', - 'Mesta', - 'Sostre', - 'Rohman', - 'Padget', - 'Edds', - 'Slinger', - 'Borowicz', - 'Bregman', - 'Bubar', - 'Debartolo', - 'Desposito', - 'Grieshaber', - 'Ludtke', - 'Pagani', - 'Quiambao', - 'Schapiro', - 'Winward', - 'Bouska', - 'Olstad', - 'Rough', - 'Genz', - 'Husby', - 'Nealis', - 'Hyams', - 'Andrades', - 'Mcgibbon', - 'Edwin', - 'Buckhalter', - 'Baylon', - 'Fiene', - 'Fillingim', - 'Fiorenza', - 'Greenstreet', - 'Krager', - 'Laxson', - 'Noreen', - 'Roberds', - 'Rundquist', - 'Smelcer', - 'Tabone', - 'Train', - 'Zeoli', - 'Defries', - 'Kolp', - 'Maahs', - 'Mcnall', - 'Ehman', - 'Keeth', - 'Shackleton', - 'Hogarth', - 'Westbury', - 'Gulliver', - 'Oquin', - 'Holiman', - 'Saintlouis', - 'Vaughns', - 'Aichele', - 'Arbelaez', - 'Bathurst', - 'Bresler', - 'Cecena', - 'Drollinger', - 'Fellner', - 'Griesemer', - 'Harnois', - 'Hire', - 'Kraker', - 'Roylance', - 'Zaccaria', - 'Dinunzio', - 'Foisy', - 'Nordlund', - 'Peppler', - 'Kishbaugh', - 'Marcil', - 'Mcfarren', - 'Puello', - 'Supplee', - 'Boyea', - 'Depp', - 'Tift', - 'Wince', - 'Pam', - 'Ifill', - 'Brodt', - 'Caamano', - 'Gibler', - 'Litherland', - 'Miesner', - 'Pixler', - 'Schwimmer', - 'Suriano', - 'Abendroth', - 'Gillaspy', - 'Kumpf', - 'Schroepfer', - 'Boals', - 'Seneca', - 'Sasson', - 'Hindes', - 'Posten', - 'Lann', - 'Anctil', - 'Arebalo', - 'Beacom', - 'Boberg', - 'Coufal', - 'Didion', - 'Fromme', - 'Greenan', - 'Guerrette', - 'Hudec', - 'Kazmi', - 'Lucchese', - 'Mouw', - 'Savastano', - 'Schomer', - 'Shorb', - 'Storz', - 'Finazzo', - 'Knigge', - 'Pawlikowski', - 'Cercone', - 'Sutfin', - 'Valdespino', - 'Mccartin', - 'Yurko', - 'Treaster', - 'Peaden', - 'Russin', - 'Dibartolo', - 'Dona', - 'Skillern', - 'Brackens', - 'Amyx', - 'Bornemann', - 'Comtois', - 'Kaestner', - 'Kallenbach', - 'Krupka', - 'Lineback', - 'Lopata', - 'Mcclenahan', - 'Monteverde', - 'Otani', - 'Panchal', - 'Pawlicki', - 'Suman', - 'Vallance', - 'Zammit', - 'Liszewski', - 'Trunk', - 'Sharifi', - 'Lents', - 'Watkinson', - 'Willow', - 'Flaming', - 'Sol', - 'Dory', - 'Purchase', - 'Haris', - 'Bigsby', - 'Boonstra', - 'Emge', - 'Goodpasture', - 'Iwata', - 'Kau', - 'Syring', - 'Vlach', - 'Klaassen', - 'Vicuna', - 'Wasden', - 'Cattell', - 'Ridlon', - 'Fassler', - 'Scullion', - 'Hibbitts', - 'Mcgillis', - 'Pla', - 'Mustin', - 'Darty', - 'Minniefield', - 'Bloyd', - 'Calnan', - 'Casal', - 'Fickel', - 'Gamero', - 'Higuchi', - 'Huante', - 'Knies', - 'Letner', - 'Quang', - 'Teufel', - 'Topolski', - 'Tumminello', - 'Vanorder', - 'Slawinski', - 'Nyce', - 'Asmar', - 'Loudin', - 'Karen', - 'Budden', - 'Mothershed', - 'Fenelon', - 'Mccrorey', - 'Ashenfelter', - 'Auge', - 'Christison', - 'Cilley', - 'Corsetti', - 'Coxwell', - 'Critchley', - 'Griep', - 'Hausner', - 'Hiemstra', - 'Koprowski', - 'Kozicki', - 'Marling', - 'Marmo', - 'Noller', - 'Pich', - 'Recendez', - 'Renegar', - 'Rinne', - 'Zeis', - 'Buzzelli', - 'Lipham', - 'Schaner', - 'Kartchner', - 'Kealy', - 'Sinopoli', - 'Krishna', - 'Brinn', - 'Zachry', - 'Barbre', - 'Sharber', - 'Fritze', - 'Hanshew', - 'Lemere', - 'Maruyama', - 'Masker', - 'Melendy', - 'Pelto', - 'Rigo', - 'Rohling', - 'Scobee', - 'Sundell', - 'Tranter', - 'Vancuren', - 'Augustyniak', - 'Mehringer', - 'Sulkowski', - 'Gittins', - 'Twiford', - 'Dumm', - 'Jacklin', - 'Mcquaig', - 'Richison', - 'Jex', - 'Meritt', - 'Hegler', - 'Duboise', - 'Houze', - 'Akana', - 'Corsaro', - 'Delosangeles', - 'Guidice', - 'Maccallum', - 'Moes', - 'Steinhardt', - 'Stirewalt', - 'Wooters', - 'Schissler', - 'Sobeck', - 'Boyte', - 'Jilek', - 'Suder', - 'Kellis', - 'Blankenbaker', - 'Lank', - 'Mandigo', - 'Fremont', - 'Rideau', - 'Beidler', - 'Boda', - 'Gulotta', - 'Havelka', - 'Herberger', - 'Isenhower', - 'Lattanzi', - 'Pandolfi', - 'Shearman', - 'Wilmarth', - 'Dutkiewicz', - 'Mazzuca', - 'Tabarez', - 'Vermilyea', - 'Kray', - 'Vitti', - 'Packwood', - 'Paulos', - 'Howson', - 'Collman', - 'Ameen', - 'Berisha', - 'Capece', - 'Fantasia', - 'Galas', - 'Laszlo', - 'Luthi', - 'Maietta', - 'Mcconaghy', - 'Naab', - 'Nerio', - 'Pineau', - 'Rossbach', - 'Senne', - 'Unangst', - 'Kautzman', - 'Muhs', - 'Ripka', - 'Wehling', - 'Hoot', - 'Jee', - 'Megna', - 'Tirone', - 'Walle', - 'Brandi', - 'Lutter', - 'Mona', - 'Roley', - 'Mcfann', - 'Swader', - 'Cavett', - 'Delmore', - 'Walthour', - 'Goldson', - 'Biddinger', - 'Bjornstad', - 'Buesing', - 'Cerino', - 'Diede', - 'Hagle', - 'Hodgman', - 'Killmer', - 'Loa', - 'Matsunaga', - 'Micciche', - 'Newquist', - 'Poppen', - 'Shellhammer', - 'Tienda', - 'Tino', - 'Mihelich', - 'Garsia', - 'Orzel', - 'Ericsson', - 'Dose', - 'Kotter', - 'Amante', - 'Hanif', - 'Huckleberry', - 'Blandin', - 'Carvin', - 'Axton', - 'Delosrios', - 'Diekmann', - 'Failing', - 'Filipek', - 'Otting', - 'Rozman', - 'Sadeghi', - 'Slutsky', - 'Speake', - 'Szostak', - 'Tacy', - 'Kmiecik', - 'Macgillivray', - 'Yeakel', - 'Dykman', - 'Gorey', - 'Dowding', - 'Revel', - 'Geathers', - 'Cappa', - 'Davidoff', - 'Lukehart', - 'Mccutchan', - 'Neeb', - 'Nikolic', - 'Piorkowski', - 'Sandvig', - 'Schmidgall', - 'Stockbridge', - 'Thornock', - 'Valk', - 'Wiechmann', - 'Chait', - 'Gacek', - 'Schupbach', - 'Gemma', - 'Rus', - 'Barch', - 'Wyles', - 'Scrivener', - 'Salls', - 'Akram', - 'Mcclatchey', - 'Bromfield', - 'Burl', - 'Redwood', - 'Starkes', - 'Beaston', - 'Boggio', - 'Cantillo', - 'Cina', - 'Cryan', - 'Dubs', - 'Edmisten', - 'Fitzer', - 'Fugere', - 'Fundora', - 'Galvis', - 'Jafri', - 'Nalepa', - 'Peri', - 'Pippenger', - 'Rheault', - 'Rohrbacher', - 'Romberg', - 'Samek', - 'Stehlik', - 'Stepan', - 'Torrisi', - 'Wessner', - 'Zappala', - 'Bangerter', - 'Czerniak', - 'Mcshea', - 'Raczkowski', - 'Rohwer', - 'Spehar', - 'Lague', - 'Messman', - 'Angst', - 'Temme', - 'Tolles', - 'Lawn', - 'Ayars', - 'Austen', - 'Stansel', - 'Fairclough', - 'Tribbett', - 'Peevy', - 'Fraiser', - 'Caradine', - 'Fiegel', - 'Gignac', - 'Halpert', - 'Karels', - 'Knappenberger', - 'Prezioso', - 'Rohlfs', - 'Szot', - 'Varano', - 'Weinreich', - 'Butterbaugh', - 'Heying', - 'Vandewalle', - 'Yandle', - 'Thede', - 'Astor', - 'Blanchfield', - 'Hegeman', - 'Fels', - 'Miniard', - 'Lorio', - 'Muhammed', - 'Lazard', - 'Ehmke', - 'Hulst', - 'Imlay', - 'Kinzler', - 'Knaak', - 'Poehler', - 'Prusak', - 'Rakow', - 'Raupp', - 'Sucher', - 'Tanenbaum', - 'Burich', - 'Macmaster', - 'Shapley', - 'Thurgood', - 'Mires', - 'Gotay', - 'Attia', - 'Martis', - 'Greenley', - 'Fothergill', - 'Bonvillain', - 'Buffalo', - 'Dues', - 'Crute', - 'Cantone', - 'Dewit', - 'Dovel', - 'Klopfer', - 'Philhower', - 'Piatek', - 'Pion', - 'Rapaport', - 'Vanwert', - 'Wikstrom', - 'Graffeo', - 'Kissling', - 'Niday', - 'Soong', - 'Adami', - 'Hammersmith', - 'Keir', - 'Yo', - 'Grizzell', - 'Stclaire', - 'Swales', - 'Nole', - 'Pole', - 'Hartgrove', - 'Carrothers', - 'Carlone', - 'Ciano', - 'Finucane', - 'Fitterer', - 'Gellman', - 'Hakimi', - 'Janos', - 'Krings', - 'Malmstrom', - 'Markwardt', - 'Rodin', - 'Schau', - 'Scheible', - 'Orick', - 'Dine', - 'Tremmel', - 'Shon', - 'Wilms', - 'Bren', - 'Bertin', - 'Poster', - 'Jeng', - 'Stcharles', - 'Jenning', - 'Eutsey', - 'Fayne', - 'Gustave', - 'Mccargo', - 'Boruff', - 'Boschert', - 'Burmester', - 'Colello', - 'Conchas', - 'Devi', - 'Dishaw', - 'Funaro', - 'Gallen', - 'Hsueh', - 'Lanser', - 'Macaraeg', - 'Munster', - 'Petsch', - 'Routon', - 'Werkmeister', - 'Woznicki', - 'Boroff', - 'Cochenour', - 'Dibartolomeo', - 'Elzinga', - 'Heyen', - 'Lapaglia', - 'Schiel', - 'Rauda', - 'Woltman', - 'Carll', - 'Kanda', - 'Runnells', - 'Hazelett', - 'Arnwine', - 'Sherfield', - 'Borthwick', - 'Coyner', - 'Ensey', - 'Feinman', - 'Leyendecker', - 'Lickteig', - 'Lubeck', - 'Maccarone', - 'Minahan', - 'Plew', - 'Saur', - 'Schleich', - 'Sixtos', - 'Soller', - 'Valek', - 'Umland', - 'Swogger', - 'Iannacone', - 'Tomey', - 'Venuto', - 'Peru', - 'Adolf', - 'Lemme', - 'Bureau', - 'River', - 'Buffaloe', - 'Leacock', - 'Threat', - 'Boza', - 'Constancio', - 'Dandurand', - 'Hiscock', - 'Kaley', - 'Michaelsen', - 'Roberti', - 'Sicilia', - 'Sliker', - 'Sooter', - 'Steyer', - 'Tabora', - 'Vanderbeek', - 'Vanscyoc', - 'Piercey', - 'Sabater', - 'Bride', - 'Tippens', - 'Acquaviva', - 'Baublitz', - 'Mccanna', - 'Mckaig', - 'Merenda', - 'Obermeier', - 'Pechacek', - 'Pugmire', - 'Shaneyfelt', - 'Steuer', - 'Zeidler', - 'Bodenheimer', - 'Gaglio', - 'Maceachern', - 'Munsterman', - 'Rayle', - 'Wisnewski', - 'Baar', - 'Thi', - 'Foulds', - 'Rufino', - 'Chrisco', - 'Barrientez', - 'Lare', - 'Munnerlyn', - 'Pitter', - 'Koroma', - 'Caisse', - 'Espe', - 'Kerin', - 'Melchiorre', - 'Mentz', - 'Paasch', - 'Parrales', - 'Rhew', - 'Sigley', - 'Skiff', - 'Stockert', - 'Viglione', - 'Kraska', - 'Botto', - 'Ponzio', - 'Wolfley', - 'Wack', - 'Kilborn', - 'Dunnavant', - 'Pitney', - 'Dolman', - 'Biscoe', - 'Michelle', - 'Azcona', - 'Brasington', - 'Fazzino', - 'Hoefs', - 'Kohlmeyer', - 'Laser', - 'Morea', - 'Morrin', - 'Neuwirth', - 'Nicklaus', - 'Pennypacker', - 'Rueckert', - 'Schriefer', - 'Scovel', - 'Swyers', - 'Thebeau', - 'Mijangos', - 'Douville', - 'Tidball', - 'Smullen', - 'Lecount', - 'Pruiett', - 'Branche', - 'Arment', - 'Babiarz', - 'Char', - 'Granlund', - 'Hillock', - 'Kahrs', - 'Khong', - 'Lalley', - 'Laspina', - 'Pietila', - 'Ponciano', - 'Rosengren', - 'Slee', - 'Snowberger', - 'Weglarz', - 'Camarata', - 'Villalovos', - 'Buza', - 'Kenning', - 'Rohrig', - 'Sedor', - 'Perretta', - 'Hamberg', - 'Mongan', - 'Formby', - 'Portier', - 'Silcott', - 'Levell', - 'Barrantes', - 'Bellefeuille', - 'Beneke', - 'Bilbao', - 'Danahy', - 'Delahanty', - 'Deppen', - 'Dicostanzo', - 'Dudding', - 'Elmquist', - 'Handa', - 'Hatem', - 'Loverde', - 'Mesick', - 'Onofrio', - 'Ramesh', - 'Tiberio', - 'Trachtenberg', - 'Vanwagenen', - 'Cassada', - 'Pepitone', - 'Stillson', - 'Pfarr', - 'Radle', - 'Scallan', - 'Carlen', - 'Bermingham', - 'Sagers', - 'Llorens', - 'Turay', - 'Beamish', - 'Carlini', - 'Galipeau', - 'Heavey', - 'Kempker', - 'Masser', - 'Montellano', - 'Peine', - 'Pietro', - 'Plitt', - 'Pollman', - 'Rike', - 'Spees', - 'Vandervelde', - 'Vanwey', - 'Grundman', - 'Marinucci', - 'Molenda', - 'Shideler', - 'Turrubiartes', - 'Schaer', - 'Firkins', - 'Haid', - 'Parnes', - 'Pulse', - 'Masone', - 'Burpo', - 'Tharrington', - 'Winborn', - 'Petite', - 'Buttry', - 'Clason', - 'Eutsler', - 'Haberer', - 'Haft', - 'Kotler', - 'Meloche', - 'Raether', - 'Rengifo', - 'Roback', - 'Stangle', - 'Wilderman', - 'Chickering', - 'Gervacio', - 'Penaranda', - 'Schnieders', - 'Coyer', - 'Laramee', - 'Curts', - 'Bailiff', - 'Truby', - 'Molder', - 'Hedley', - 'Carbon', - 'Gudger', - 'Fontenette', - 'Askren', - 'Deshane', - 'Enriques', - 'Fake', - 'Jungers', - 'Krech', - 'Niemela', - 'Perfetto', - 'Ritt', - 'Soldano', - 'Stanish', - 'Strege', - 'Wichert', - 'Wolz', - 'Zimbelman', - 'Abplanalp', - 'Nikkel', - 'Oravec', - 'Coile', - 'Mizuno', - 'Fenlon', - 'Vanloo', - 'Callery', - 'Hortman', - 'Hashim', - 'Sorey', - 'Ajayi', - 'Alesi', - 'Alessandro', - 'Avants', - 'Bachtel', - 'Bonine', - 'Butkovich', - 'Cerros', - 'Colina', - 'Dayhoff', - 'Favata', - 'Haning', - 'Kamath', - 'Kosik', - 'Loughrey', - 'Mollo', - 'Nagi', - 'Nesler', - 'Nosek', - 'Ordoyne', - 'Politis', - 'Zwolinski', - 'Yaffe', - 'Sigal', - 'Burow', - 'Scarbro', - 'Buckel', - 'Broxson', - 'Goyer', - 'Goding', - 'Delee', - 'Jefferys', - 'Blissett', - 'Balian', - 'Brader', - 'Curreri', - 'Dickmann', - 'Eckerle', - 'Erives', - 'Fedewa', - 'Frisina', - 'Gropp', - 'Hinck', - 'Lamorte', - 'Litzenberger', - 'Proehl', - 'Struss', - 'Tamburello', - 'Digioia', - 'Galarneau', - 'Jurkiewicz', - 'Macnaughton', - 'Talsma', - 'Vlasak', - 'Weyrauch', - 'Yontz', - 'Kho', - 'Stgermaine', - 'Grauer', - 'Benware', - 'Rearden', - 'Molin', - 'Pendergrast', - 'Sivils', - 'Ellery', - 'Ikner', - 'Metayer', - 'Toran', - 'Seaberry', - 'Banderas', - 'Bannan', - 'Critzer', - 'Doescher', - 'Haakenson', - 'Hignite', - 'Hoeksema', - 'Inserra', - 'Korbel', - 'Kruzel', - 'Langen', - 'Mittelstaedt', - 'Popkin', - 'Schwarting', - 'Toral', - 'Ilagan', - 'Lamica', - 'Lierman', - 'Zimmerly', - 'Fosse', - 'Pagnotta', - 'Trenholm', - 'Clayson', - 'Cerutti', - 'Wollard', - 'Mcburnett', - 'Stallcup', - 'Magan', - 'Wonder', - 'Gillock', - 'Ellisor', - 'Clayburn', - 'Mabery', - 'Cariaga', - 'Crail', - 'Dieckman', - 'Joynt', - 'Kleinert', - 'Kutner', - 'Milla', - 'Nauta', - 'Rende', - 'Robare', - 'Santella', - 'Scianna', - 'Sevcik', - 'Smolik', - 'Staudinger', - 'Cedillos', - 'Shroff', - 'Ueda', - 'Yearout', - 'Zuno', - 'Pottle', - 'Klabunde', - 'Tusa', - 'Schomburg', - 'Alto', - 'Packett', - 'Muns', - 'Dante', - 'Jarnigan', - 'Londo', - 'Bigbee', - 'Isles', - 'Nembhard', - 'Appiah', - 'Hypolite', - 'Acebedo', - 'Arlt', - 'Champney', - 'Kawahara', - 'Lehan', - 'Pavlak', - 'Ritacco', - 'Seckinger', - 'Turvey', - 'Vanevery', - 'Wronski', - 'Bahnsen', - 'Clites', - 'Ellwanger', - 'Husak', - 'Lydic', - 'Zubiate', - 'Muehlbauer', - 'Neumeister', - 'Wellnitz', - 'Langstaff', - 'Gort', - 'Eve', - 'Stones', - 'Stanard', - 'Whichard', - 'Cheers', - 'Baldus', - 'Bertoni', - 'Chesebro', - 'Dino', - 'Dubray', - 'Icenhour', - 'Marquard', - 'Mette', - 'Potash', - 'Winterhalter', - 'Crupi', - 'Lascala', - 'Tauer', - 'Vandenburgh', - 'Mende', - 'Swarey', - 'Sarles', - 'Platter', - 'Dekeyser', - 'Jaye', - 'Pelle', - 'Caroll', - 'Rosette', - 'Shepperson', - 'Fooks', - 'Kennerson', - 'Bolser', - 'Chim', - 'Diefenderfer', - 'Frosch', - 'Holzwarth', - 'Kjos', - 'Langland', - 'Meland', - 'Stufflebeam', - 'Worland', - 'Barrales', - 'Chhay', - 'Corkern', - 'Creegan', - 'Golan', - 'Marceaux', - 'Matsuo', - 'Micallef', - 'Otsuka', - 'Rinella', - 'Creveling', - 'Krane', - 'Mcnay', - 'Detter', - 'Drexel', - 'Kibodeaux', - 'Shippey', - 'Medearis', - 'Samms', - 'Drzewiecki', - 'Fariss', - 'Glandon', - 'Heinecke', - 'Hendler', - 'Jungwirth', - 'Panepinto', - 'Rohleder', - 'Saragosa', - 'Stuller', - 'Wissel', - 'Atwal', - 'Tisch', - 'Esterly', - 'Mourad', - 'Brickell', - 'Bough', - 'Rubens', - 'Angevine', - 'Tolin', - 'Sago', - 'Apfel', - 'Ashdown', - 'Derusha', - 'Fiorino', - 'Koyama', - 'Matteucci', - 'Newbrough', - 'Seufert', - 'Stahley', - 'Tyburski', - 'Zaino', - 'Cdebaca', - 'Hormann', - 'Wangen', - 'Winterton', - 'Beagley', - 'Sowden', - 'Daul', - 'Errington', - 'Steber', - 'Emfinger', - 'Olan', - 'Fiveash', - 'Carriger', - 'Breakfield', - 'Ezekiel', - 'Wallington', - 'Hollimon', - 'Izzard', - 'Lyde', - 'Bellmore', - 'Benkert', - 'Bhargava', - 'Dacanay', - 'Dano', - 'Diprima', - 'Garlitz', - 'Hannemann', - 'Janiak', - 'Klann', - 'Kunce', - 'Malicki', - 'Mcgivney', - 'Nordeen', - 'Procell', - 'Rands', - 'Smeltz', - 'Sutch', - 'Wach', - 'Wentling', - 'Karapetyan', - 'Mcvicar', - 'Pennisi', - 'Perley', - 'Graner', - 'Hartney', - 'Shadley', - 'Pennebaker', - 'Cayce', - 'Marris', - 'Burges', - 'Odem', - 'Charvat', - 'Delgreco', - 'Diven', - 'Latu', - 'Mccallion', - 'Mcfeely', - 'Mon', - 'Nagai', - 'Obrecht', - 'Opdyke', - 'Pearlstein', - 'Pomroy', - 'Prothero', - 'Rado', - 'Roehr', - 'Seiffert', - 'Spake', - 'Stech', - 'Thakur', - 'Trzcinski', - 'Uvalle', - 'Vazques', - 'Anschutz', - 'Boecker', - 'Descoteaux', - 'Idol', - 'Stanzione', - 'Welp', - 'Schumer', - 'Ridner', - 'Kasner', - 'Auton', - 'Barca', - 'Ocheltree', - 'Biernat', - 'Mercuri', - 'Truslow', - 'Witters', - 'Mcelhannon', - 'Mccrackin', - 'Brabson', - 'Baumberger', - 'Double', - 'Garis', - 'Kasparian', - 'Kooistra', - 'Loser', - 'Mangone', - 'Massman', - 'Raimondo', - 'Sparacio', - 'Valli', - 'Viets', - 'Wessell', - 'Kieu', - 'Vonderheide', - 'Wojnar', - 'Furbee', - 'Heyden', - 'Lackie', - 'Ehrich', - 'Roupe', - 'Holy', - 'Care', - 'Isa', - 'Samad', - 'Rougeau', - 'Chavous', - 'Rattler', - 'Wedderburn', - 'President', - 'Blackham', - 'Bobak', - 'Crimi', - 'Durland', - 'Gargus', - 'Gitlin', - 'Levandoski', - 'Niu', - 'Piccirilli', - 'Sauvageau', - 'Schweers', - 'Talty', - 'Uthe', - 'Verga', - 'Warzecha', - 'Erisman', - 'Gallacher', - 'Shanholtz', - 'Fulgencio', - 'Migues', - 'Garin', - 'Heisel', - 'Stong', - 'Christiana', - 'Bonenfant', - 'Clancey', - 'Kindley', - 'Nill', - 'Mood', - 'Atterbury', - 'Tobe', - 'Eisenhardt', - 'Franceschini', - 'Heiland', - 'Kreuzer', - 'Lockaby', - 'Scarola', - 'Tessitore', - 'Warehime', - 'Kukowski', - 'Ruhlman', - 'Frymire', - 'Bartone', - 'Wrightson', - 'Langlinais', - 'Planas', - 'Darsey', - 'Darin', - 'Gammel', - 'Giroir', - 'Aspinall', - 'Hollywood', - 'Childres', - 'Copelin', - 'Teamer', - 'Okoro', - 'Abshier', - 'Arizaga', - 'Berenson', - 'Biegler', - 'Dugdale', - 'Erlich', - 'Gavino', - 'Haaland', - 'Lautenschlager', - 'Lilja', - 'Livingood', - 'Lockner', - 'Pyeatt', - 'Reist', - 'Rummell', - 'Schadler', - 'Snare', - 'Zawada', - 'Dumler', - 'Moncivais', - 'Sammarco', - 'Laraway', - 'Voorhis', - 'Detty', - 'Manko', - 'Zale', - 'Autin', - 'Quaid', - 'Denver', - 'Demario', - 'Nearing', - 'Amerine', - 'Bea', - 'Carraher', - 'Dierkes', - 'Dutko', - 'Hosek', - 'Kassner', - 'Meo', - 'Mesler', - 'Norquist', - 'Pacetti', - 'Pellerito', - 'Ryser', - 'Turnmire', - 'Caniglia', - 'Zollman', - 'Gerwig', - 'Denslow', - 'Stapler', - 'Majid', - 'Prestage', - 'Eargle', - 'Spight', - 'Argabright', - 'Borgeson', - 'Cipollone', - 'Dippold', - 'Korf', - 'Milhoan', - 'Pinelli', - 'Roblero', - 'Scolaro', - 'Sperl', - 'Svensson', - 'Bauguess', - 'Freimuth', - 'Luquin', - 'Barman', - 'Solivan', - 'Buel', - 'Birkeland', - 'Cafiero', - 'Degollado', - 'Demeyer', - 'Hoberg', - 'Homola', - 'Kadel', - 'Koslowski', - 'Lefrancois', - 'Macconnell', - 'Madill', - 'Nudelman', - 'Raucci', - 'Reidenbach', - 'Schermer', - 'Sergio', - 'Bucko', - 'Haegele', - 'Nibert', - 'Sidell', - 'Slape', - 'Hellard', - 'Russi', - 'Wilcock', - 'Verdejo', - 'Lessley', - 'Camille', - 'Topps', - 'Acampora', - 'Blacketer', - 'Clapham', - 'Efaw', - 'Louks', - 'Mersch', - 'Odden', - 'Schettler', - 'Schnarr', - 'Sieracki', - 'Skog', - 'Zobrist', - 'Corless', - 'Zunker', - 'Bega', - 'Victoriano', - 'Singler', - 'Keltz', - 'Valcarcel', - 'Curet', - 'Harvison', - 'Mccullah', - 'Cranfield', - 'Gardin', - 'Mewborn', - 'Bisel', - 'Carfagno', - 'Carli', - 'Chirino', - 'Fairless', - 'Gaboury', - 'Goetze', - 'Guitron', - 'Haut', - 'Krupski', - 'Lata', - 'Misiak', - 'Sawaya', - 'Schomaker', - 'Schulke', - 'Tin', - 'Dewhurst', - 'Krummel', - 'Hannahs', - 'Carlow', - 'Hemp', - 'Bowdoin', - 'Breda', - 'Chriss', - 'Kebede', - 'Binney', - 'Brasseaux', - 'Cunliffe', - 'Gantner', - 'Gillick', - 'Hottle', - 'Hren', - 'Irani', - 'Klitzke', - 'Luhrs', - 'Micale', - 'Oien', - 'Oppelt', - 'Rallo', - 'Ringwald', - 'Stonerock', - 'Strebel', - 'Tiberi', - 'Volner', - 'Whetstine', - 'Wrubel', - 'Brakebill', - 'Fechner', - 'Geurts', - 'Hoefling', - 'Misener', - 'Andros', - 'Dimock', - 'Rosendo', - 'Megill', - 'Gloyd', - 'Garney', - 'Andries', - 'Esco', - 'Rhames', - 'Draine', - 'Plair', - 'Jiggetts', - 'Atcheson', - 'Brienza', - 'Cerveny', - 'Depaoli', - 'Deroo', - 'Dorf', - 'Guidotti', - 'Heimlich', - 'Insalaco', - 'Kaczorowski', - 'Kinnunen', - 'Loureiro', - 'Lyster', - 'Pia', - 'Piccoli', - 'Quale', - 'Sadek', - 'Stenstrom', - 'Strause', - 'Tortorella', - 'Traweek', - 'Vanderwerff', - 'Varian', - 'Vink', - 'Waxler', - 'Wynia', - 'Annese', - 'Economou', - 'Whitsel', - 'Dougher', - 'Schnieder', - 'Cosman', - 'Farra', - 'Osmon', - 'Bardon', - 'Rampersaud', - 'Jane', - 'Kirts', - 'Chennault', - 'Thomison', - 'Graig', - 'Narine', - 'Gunner', - 'Aamodt', - 'Adinolfi', - 'Adolphson', - 'Aki', - 'Alderton', - 'Aloisio', - 'Bellavia', - 'Clutts', - 'Coughran', - 'Frasco', - 'Guinta', - 'Hatala', - 'Ibach', - 'Mecum', - 'Medero', - 'Neria', - 'Nery', - 'Pignataro', - 'Podesta', - 'Statzer', - 'Stombaugh', - 'Szczesny', - 'Kovaleski', - 'Ades', - 'Bauers', - 'Bern', - 'Horsfall', - 'Masood', - 'Cinque', - 'Stay', - 'Beare', - 'Donavan', - 'Ikerd', - 'Seney', - 'Layson', - 'Coler', - 'Tuft', - 'Tamplin', - 'Billinger', - 'Scrivens', - 'Bartolomei', - 'Baza', - 'Dimattia', - 'Dotterer', - 'Dushane', - 'Fulop', - 'Iacovelli', - 'Macnamara', - 'Mahlum', - 'Noteboom', - 'Rebstock', - 'Drechsler', - 'Itzkowitz', - 'Rigler', - 'Schrom', - 'Pirozzi', - 'Ferre', - 'Shiley', - 'Villanova', - 'Barona', - 'Farrel', - 'Shelman', - 'Nute', - 'Rowlette', - 'Tarrance', - 'Cadorette', - 'Christenberry', - 'Deocampo', - 'Farace', - 'Fesmire', - 'Kallman', - 'Koogler', - 'Pitsch', - 'Salce', - 'Schnepf', - 'Totaro', - 'Towey', - 'Urdiales', - 'Gotschall', - 'Brunett', - 'Dier', - 'Hainsworth', - 'Seabury', - 'Cornelious', - 'Altobelli', - 'Andreozzi', - 'Bohlmann', - 'Carranco', - 'Daubenspeck', - 'Delagrange', - 'Delo', - 'Faler', - 'Ficke', - 'Hellinger', - 'Hudman', - 'Ihde', - 'Landolfi', - 'Leiner', - 'Mosman', - 'Rang', - 'Tarbet', - 'Wineman', - 'Fehrman', - 'Guinto', - 'Icenogle', - 'Tomasik', - 'Looman', - 'Iriarte', - 'Denaro', - 'Montross', - 'Piersall', - 'Lauren', - 'Lablanc', - 'Kindrick', - 'Deriso', - 'Manker', - 'Maycock', - 'Cullens', - 'Frieson', - 'Clippinger', - 'Colavito', - 'Fassbender', - 'Fennessy', - 'Granada', - 'Gugliotta', - 'Guiliano', - 'Hirschberg', - 'Kerbs', - 'Kusch', - 'Limmer', - 'Malpica', - 'Mcaloon', - 'Morken', - 'Pytel', - 'Resnik', - 'Spangle', - 'Worstell', - 'Kerkhoff', - 'Kupka', - 'Stanczyk', - 'Storlie', - 'Thurow', - 'Caetano', - 'Ernandez', - 'Males', - 'Coopersmith', - 'Everest', - 'Leander', - 'Demeritt', - 'Thomes', - 'Codner', - 'Livsey', - 'Alcoser', - 'Arico', - 'Balestrieri', - 'Cavalli', - 'Florendo', - 'Gottshall', - 'Hinesley', - 'Lafuente', - 'Landess', - 'Ornstein', - 'Pettingill', - 'Romesburg', - 'Tokunaga', - 'Wiersema', - 'Janeway', - 'Pecha', - 'Steimel', - 'Sproule', - 'Sommerfield', - 'Mirsky', - 'Staines', - 'Pu', - 'Corbit', - 'Mcelmurry', - 'Wickes', - 'Yell', - 'Mordecai', - 'Aye', - 'Boldin', - 'China', - 'Fason', - 'Thibeaux', - 'Nesby', - 'Bergevin', - 'Besecker', - 'Dohrmann', - 'Fujioka', - 'Fyock', - 'Goralski', - 'Kirschenbaum', - 'Knipper', - 'Menor', - 'Mischler', - 'Nolder', - 'Odoherty', - 'Pickerill', - 'Poremba', - 'Swantek', - 'Difabio', - 'Kulka', - 'Servais', - 'Wickizer', - 'Melecio', - 'Zeek', - 'Fruit', - 'Agnes', - 'Bar', - 'Mccarrell', - 'Hopgood', - 'Califano', - 'Cratty', - 'Dishner', - 'Gabrielli', - 'Hamacher', - 'Hinote', - 'Jakob', - 'Klinkhammer', - 'Krasinski', - 'Krysiak', - 'Pardi', - 'Petrilli', - 'Razon', - 'Reifsnyder', - 'Reisig', - 'Reller', - 'Sassano', - 'Steinhart', - 'Wrede', - 'Zevallos', - 'Coombe', - 'Quesnel', - 'Rebuck', - 'Wantz', - 'Bendele', - 'Lacomb', - 'Hagge', - 'Donelan', - 'Kempe', - 'Po', - 'Varnadoe', - 'Constantin', - 'Deon', - 'Motte', - 'Beckum', - 'Parchment', - 'Meriweather', - 'Borucki', - 'Fatima', - 'Gerkin', - 'Guglielmi', - 'Hettich', - 'Hoerr', - 'Karlsson', - 'Kenealy', - 'Paolillo', - 'Pfenning', - 'Rueger', - 'Schildt', - 'Sem', - 'Vilches', - 'Dornbusch', - 'Erdahl', - 'Kleinhenz', - 'Moneypenny', - 'Tomasko', - 'Vandevender', - 'Cromley', - 'Tun', - 'Velasques', - 'Roble', - 'Burgo', - 'Waples', - 'Mabon', - 'Benincasa', - 'Buttermore', - 'Dalbec', - 'Eikenberry', - 'Fuehrer', - 'Hossler', - 'Lepp', - 'Opheim', - 'Sarsfield', - 'Strobl', - 'Strouth', - 'Tousley', - 'Wilczek', - 'Kleppe', - 'Muraoka', - 'Wiencek', - 'Pinckard', - 'Ahsan', - 'Welder', - 'Forton', - 'Lorden', - 'Stlawrence', - 'Marina', - 'Mcquire', - 'Randleman', - 'Pates', - 'Fluitt', - 'Scotland', - 'Clerk', - 'Townsell', - 'Arrasmith', - 'Baisch', - 'Berling', - 'Busler', - 'Curtice', - 'Ebinger', - 'Fleeger', - 'Geng', - 'Goettsch', - 'Henneberry', - 'Johannesen', - 'Mcilrath', - 'Perigo', - 'Phibbs', - 'Riske', - 'Scarcella', - 'Vandyken', - 'Barstad', - 'Dicamillo', - 'Ernsberger', - 'Guebara', - 'Peetz', - 'Newcome', - 'Alterman', - 'Weik', - 'Trier', - 'Yeats', - 'Hugg', - 'Crayne', - 'Ige', - 'Coach', - 'Archuletta', - 'Bodi', - 'Cadavid', - 'Ceccarelli', - 'Derksen', - 'Deutscher', - 'Genter', - 'Gogel', - 'Gorczyca', - 'Grohs', - 'Koplin', - 'Kozloski', - 'Lillo', - 'Oplinger', - 'Pulis', - 'Renk', - 'Repka', - 'Scavo', - 'Vitagliano', - 'Weinkauf', - 'Yellin', - 'Boehlke', - 'Montecalvo', - 'Castrillo', - 'Grenon', - 'Wellen', - 'Keelan', - 'Coville', - 'Rison', - 'Jourdain', - 'Chestnutt', - 'Sharpley', - 'Acharya', - 'Bartles', - 'Burruel', - 'Capelle', - 'Contos', - 'Friedrichsen', - 'Heaberlin', - 'Hermiz', - 'Iracheta', - 'Klutts', - 'Koziel', - 'Salto', - 'Scaturro', - 'Stasik', - 'Stitzel', - 'Wiseley', - 'Paccione', - 'Squyres', - 'Leverich', - 'Holderness', - 'Elvin', - 'Morand', - 'Lizana', - 'Woolen', - 'Amarante', - 'Arn', - 'Biedermann', - 'Daddio', - 'Davilla', - 'Forti', - 'Gripp', - 'Hanzlik', - 'Iannotti', - 'Larin', - 'Nakajima', - 'Novacek', - 'Pesch', - 'Regino', - 'Rosengarten', - 'Schleif', - 'Searing', - 'Sikkema', - 'Walstrom', - 'Guastella', - 'Hemstreet', - 'Rorabaugh', - 'Weisenburger', - 'Cannan', - 'Band', - 'Fowkes', - 'Bennetts', - 'Purviance', - 'Tippin', - 'Brossard', - 'Seigle', - 'Babyak', - 'Billiter', - 'Cartner', - 'Deetz', - 'Dorow', - 'Laur', - 'Leblond', - 'Lecomte', - 'Morando', - 'Reitman', - 'Sarria', - 'Scheu', - 'Timmermann', - 'Vaneck', - 'Vangorp', - 'Windhorst', - 'Kaeser', - 'Kosloski', - 'Cappuccio', - 'Knitter', - 'Evon', - 'Garbett', - 'Wickens', - 'Ruston', - 'Fregia', - 'Ashurst', - 'Ede', - 'Strider', - 'Reaux', - 'Castellani', - 'Debus', - 'Degracia', - 'Hineman', - 'Laning', - 'Litts', - 'Losito', - 'Massi', - 'Mazzara', - 'Schriber', - 'Seyfert', - 'Strength', - 'Treptow', - 'Yuhasz', - 'Kamrath', - 'Krigbaum', - 'Marrocco', - 'Wanta', - 'Yakubov', - 'Hy', - 'Sabedra', - 'Belling', - 'Deats', - 'Mahaffy', - 'Brodrick', - 'Mcneece', - 'Madding', - 'Mottley', - 'Asp', - 'Borgerding', - 'Conrady', - 'Dagenhart', - 'Defusco', - 'Duensing', - 'Ensz', - 'Fockler', - 'Gajda', - 'Masino', - 'Minster', - 'Naso', - 'Nifong', - 'Ohlsen', - 'Prairie', - 'Rosendale', - 'Rotman', - 'Salzano', - 'Samet', - 'Takagi', - 'Vandagriff', - 'Vespa', - 'Zaragosa', - 'Howdyshell', - 'Kilburg', - 'Mellado', - 'Mollet', - 'Varone', - 'Benne', - 'Dillehay', - 'Ruther', - 'Gullick', - 'Lasure', - 'Wilkenson', - 'Lawrance', - 'Amacker', - 'Wisher', - 'Pryer', - 'Torian', - 'Aragona', - 'Dains', - 'Darrigo', - 'Escajeda', - 'Fertitta', - 'Futral', - 'Kielty', - 'Kightlinger', - 'Lanuza', - 'Marich', - 'Mcenaney', - 'Mohrman', - 'Pressnell', - 'Prestia', - 'Scullin', - 'Seidner', - 'Steigerwalt', - 'Wassell', - 'Bonavita', - 'Bourgault', - 'Sentz', - 'Viswanathan', - 'Hanchey', - 'Volpi', - 'Wilensky', - 'Mathey', - 'Mages', - 'Raimo', - 'Cozine', - 'Sprow', - 'Petties', - 'Bracht', - 'Cayabyab', - 'Comp', - 'Flamenco', - 'Friederich', - 'Hori', - 'Husmann', - 'Isidoro', - 'Ketchem', - 'Krishnamurthy', - 'Kucinski', - 'Lalani', - 'Lamacchia', - 'Lecher', - 'Morante', - 'Schrieber', - 'Sciarra', - 'Vandamme', - 'Welz', - 'Bozich', - 'Cancilla', - 'Panduro', - 'Mcglade', - 'Wasmund', - 'Riso', - 'Moronta', - 'Kemple', - 'Rocks', - 'Sainsbury', - 'Solo', - 'Harnage', - 'Sturkie', - 'Hollingworth', - 'Denley', - 'Bumpass', - 'Lovick', - 'Bribiesca', - 'Dewilde', - 'Drohan', - 'Geringer', - 'Kokoszka', - 'Kronberg', - 'Lewinski', - 'Lunney', - 'Morehart', - 'Ty', - 'Vasseur', - 'Vona', - 'Wriston', - 'Casarrubias', - 'Copsey', - 'Rochette', - 'Macwilliams', - 'Natali', - 'Milanes', - 'Rux', - 'Woodcox', - 'Bernett', - 'Bronaugh', - 'Fulwood', - 'Bhalla', - 'Depalo', - 'Hench', - 'Huckeba', - 'Kasch', - 'Kisor', - 'Marinos', - 'Nakahara', - 'Parrent', - 'Rantz', - 'Schoenbeck', - 'Schwieterman', - 'Selk', - 'Swonger', - 'Walding', - 'Nunamaker', - 'Schuchardt', - 'Leverton', - 'Fiallo', - 'Viruet', - 'Fadel', - 'Robel', - 'Calley', - 'Renton', - 'Rack', - 'Brin', - 'Cocks', - 'Mcivor', - 'Bois', - 'Demary', - 'Bason', - 'Dowlen', - 'Prophete', - 'Collymore', - 'Beisner', - 'Briand', - 'Cumberledge', - 'Curro', - 'Cutcher', - 'Daponte', - 'Eckroth', - 'Edgemon', - 'Farinella', - 'Kobe', - 'Muilenburg', - 'Osiecki', - 'Cutsinger', - 'Biggar', - 'Maciver', - 'Quesinberry', - 'Rippetoe', - 'Baswell', - 'Caven', - 'Mimbs', - 'Hurlock', - 'Cham', - 'Cypress', - 'Emile', - 'Beitel', - 'Bellavance', - 'Casada', - 'Fandel', - 'Gillentine', - 'Gorelick', - 'Kassis', - 'Klim', - 'Kohnke', - 'Lutgen', - 'Nalbandian', - 'Schepis', - 'Troester', - 'Hartje', - 'Hippensteel', - 'Kiehn', - 'Kuenzi', - 'Greenburg', - 'Boroughs', - 'Catton', - 'Adney', - 'Olivencia', - 'Mcdermitt', - 'Ashwell', - 'Leazer', - 'Poag', - 'Prevo', - 'Porcher', - 'Hugley', - 'Salone', - 'Jupiter', - 'Bratz', - 'Ehresman', - 'Fauber', - 'Filippelli', - 'Kesling', - 'Kronk', - 'Mcelhiney', - 'Mcgreal', - 'Miyasato', - 'Moomey', - 'Nicolini', - 'Osberg', - 'Ostroski', - 'Sanzo', - 'Sybert', - 'Dimichele', - 'Gerrits', - 'Shatley', - 'Weider', - 'Faraj', - 'Paules', - 'Yarberry', - 'Lege', - 'Pembroke', - 'Clipper', - 'Filmore', - 'Crichlow', - 'Blaustein', - 'Boak', - 'Canzoneri', - 'Crescenzo', - 'Ebaugh', - 'Feig', - 'Jens', - 'Knoebel', - 'Mohammadi', - 'Montour', - 'Norgren', - 'Pasquini', - 'Prost', - 'Reh', - 'Rosal', - 'Thesing', - 'Titcomb', - 'Wolinski', - 'Zeitlin', - 'Depoy', - 'Guccione', - 'Ritsema', - 'Valent', - 'Drey', - 'Govoni', - 'Lonsdale', - 'Hultz', - 'Harvie', - 'Levison', - 'Colomb', - 'Dace', - 'Cleckley', - 'Godette', - 'Brentlinger', - 'Fetrow', - 'Giuffrida', - 'Kopka', - 'Kurtzman', - 'Panameno', - 'Pannone', - 'Parzych', - 'Seipp', - 'Stobbe', - 'Thulin', - 'Torosian', - 'Trani', - 'Zietlow', - 'Montufar', - 'Stohr', - 'Woloszyn', - 'Cimini', - 'Angles', - 'Nicasio', - 'Vi', - 'Em', - 'Couchman', - 'Hobbie', - 'Bluestein', - 'Phillipson', - 'Shiels', - 'Altice', - 'Williston', - 'Kone', - 'Tadesse', - 'Abbruzzese', - 'Badders', - 'Duxbury', - 'Egeland', - 'Freyre', - 'Haen', - 'Hineline', - 'Kniss', - 'Kothe', - 'Kyker', - 'Popelka', - 'Sanjose', - 'Slaugh', - 'Wecker', - 'Wiechman', - 'Bilello', - 'Keezer', - 'Knode', - 'Longhurst', - 'Wisser', - 'Cease', - 'Contrera', - 'Berroa', - 'Aguon', - 'Pott', - 'Blitch', - 'Suares', - 'Bein', - 'Acre', - 'Ailes', - 'Tutwiler', - 'Porte', - 'Ashwood', - 'Blackson', - 'Viverette', - 'Balthazar', - 'Kidane', - 'Allegretti', - 'Corbeil', - 'Crossno', - 'Cudworth', - 'Federspiel', - 'Hamstra', - 'Kibbey', - 'Lefevers', - 'Loomer', - 'Losada', - 'Medema', - 'Palmerin', - 'Peregoy', - 'Previte', - 'Riedinger', - 'Schlossberg', - 'Wilemon', - 'Lepkowski', - 'Mcdanel', - 'Commisso', - 'Baiza', - 'Fones', - 'Divis', - 'Diedrick', - 'Grave', - 'Bonkowski', - 'Cerami', - 'Drinkwine', - 'Hauke', - 'Heun', - 'Keilman', - 'Klemmer', - 'Mella', - 'Olarte', - 'Ryall', - 'Veltman', - 'Wlodarczyk', - 'Bashor', - 'Kubinski', - 'Vanacker', - 'Prouse', - 'Perrott', - 'Berrio', - 'Mccarney', - 'Seiders', - 'Jafari', - 'Louque', - 'Melder', - 'Grazier', - 'Gabay', - 'Hardway', - 'Sadiq', - 'Sully', - 'Durrell', - 'Barno', - 'Maybin', - 'Brazile', - 'Asante', - 'Awalt', - 'Badal', - 'Cucinotta', - 'Grenfell', - 'Hartis', - 'Herbster', - 'Hesch', - 'Klosowski', - 'Overfelt', - 'Pangelinan', - 'Pflum', - 'Rozema', - 'Spivack', - 'Vallez', - 'Vetere', - 'Villamor', - 'Wedekind', - 'Bobrowski', - 'Nguyenthi', - 'Nowaczyk', - 'Vis', - 'Pownall', - 'Susan', - 'Yanni', - 'Gest', - 'Balthrop', - 'Treasure', - 'Harston', - 'Frett', - 'Buttery', - 'Chiarelli', - 'Colledge', - 'Czaplicki', - 'Fahringer', - 'Fedder', - 'Gerstenberger', - 'Gretz', - 'Hallquist', - 'Hemme', - 'Kolling', - 'Krauth', - 'Liquori', - 'Podolsky', - 'Scheirer', - 'Sehgal', - 'Selinger', - 'Wintermute', - 'Chokshi', - 'Dimarzio', - 'Santoni', - 'Wetherby', - 'Flis', - 'Comley', - 'Boyt', - 'Farrah', - 'Mario', - 'Mcquilkin', - 'Tim', - 'Cusic', - 'Enge', - 'Millage', - 'Waheed', - 'Kenan', - 'Silmon', - 'Mcconico', - 'Bougher', - 'Braly', - 'Coriell', - 'Daignault', - 'Henschen', - 'Holsomback', - 'Johal', - 'Kellams', - 'Schaumburg', - 'Stockinger', - 'Urquidi', - 'Cabanillas', - 'Lindbloom', - 'Willinger', - 'Redpath', - 'Baller', - 'Juarbe', - 'Badia', - 'Elderkin', - 'Dessert', - 'Retter', - 'Mccollam', - 'Rivette', - 'Devins', - 'Hewell', - 'Penniman', - 'Arbuthnot', - 'Cotman', - 'Tezeno', - 'Albo', - 'Beezley', - 'Can', - 'Chesler', - 'Dehne', - 'Demchak', - 'Edberg', - 'Gotham', - 'Ingels', - 'Kaercher', - 'Kwiecinski', - 'Landolt', - 'Macdonnell', - 'Malicoat', - 'Meinen', - 'Niswander', - 'Pandit', - 'Pettet', - 'Pliska', - 'Ploch', - 'Ratigan', - 'Sampsel', - 'Sick', - 'Ciampi', - 'Mctighe', - 'Riester', - 'Salvucci', - 'Tornow', - 'Vencill', - 'Racey', - 'Haroldson', - 'Finder', - 'Dennen', - 'Stano', - 'Boys', - 'Camillo', - 'Woodfield', - 'Turrell', - 'Sami', - 'Annan', - 'Yeldell', - 'Madlock', - 'Manigo', - 'Arcila', - 'Bauza', - 'Bisceglia', - 'Crouthamel', - 'Debenedetto', - 'Delude', - 'Dorta', - 'Fairburn', - 'Garciagarcia', - 'Geeslin', - 'Kazanjian', - 'Loescher', - 'Mccarl', - 'Mulqueen', - 'Pultz', - 'Shutter', - 'Spacek', - 'Yamanaka', - 'Borkholder', - 'Halko', - 'Pieroni', - 'Proano', - 'Sarkisyan', - 'Riopelle', - 'Routson', - 'Fogelman', - 'Sou', - 'Tress', - 'Altemus', - 'Bosh', - 'Laroque', - 'Hueston', - 'Latin', - 'Taitt', - 'Lymon', - 'Chadd', - 'Challis', - 'Comella', - 'Drabik', - 'Entz', - 'Hagner', - 'Knobbe', - 'Luckenbill', - 'Macphail', - 'Mogg', - 'Paustian', - 'Rimel', - 'Schilke', - 'Folkman', - 'Lemery', - 'Quinby', - 'Cliburn', - 'Rowand', - 'Wambach', - 'Gammell', - 'Nobrega', - 'Hoggan', - 'Nightengale', - 'Alison', - 'Batte', - 'Borner', - 'Hudnell', - 'Casseus', - 'Boteler', - 'Cantos', - 'Contois', - 'Coventry', - 'Dezarn', - 'Eisenbarth', - 'Hegel', - 'Jahr', - 'Joss', - 'Lober', - 'Marcks', - 'Portilla', - 'Reinders', - 'Scouten', - 'Siri', - 'Sobocinski', - 'Tesh', - 'Veno', - 'Wheeldon', - 'Yankee', - 'Wanke', - 'Wollin', - 'Longobardi', - 'Mccarson', - 'Sampsell', - 'Harrer', - 'Bakewell', - 'Mcgalliard', - 'Truluck', - 'Bremmer', - 'Lois', - 'Goody', - 'Kassim', - 'Conniff', - 'Elenes', - 'Esker', - 'Groshong', - 'Hallisey', - 'Loree', - 'Marken', - 'Molle', - 'Muntean', - 'Ozaki', - 'Roen', - 'Rumer', - 'Shorr', - 'Tanzer', - 'Varady', - 'Hillmer', - 'Macari', - 'Schuld', - 'Swartzlander', - 'Tsuji', - 'Holahan', - 'Abee', - 'Rowse', - 'Pawley', - 'Samp', - 'Shad', - 'Wintz', - 'Rainford', - 'Cellucci', - 'Cumpton', - 'Dando', - 'Dress', - 'Funari', - 'Gouker', - 'Hemberger', - 'Latz', - 'Meckes', - 'Parrinello', - 'Picardi', - 'Pilz', - 'Pretzer', - 'Schriever', - 'Sodano', - 'Stetter', - 'Storti', - 'Tiu', - 'Zimmerle', - 'Dragone', - 'Engert', - 'Fullenkamp', - 'Rockafellow', - 'Siwek', - 'Zillmer', - 'Devol', - 'Milke', - 'Taira', - 'Richner', - 'Aros', - 'Mancil', - 'Yetman', - 'Hanney', - 'Kinion', - 'Ferrand', - 'Conyer', - 'Chahal', - 'Fulfer', - 'Gurski', - 'Horseman', - 'Liebe', - 'Nyhus', - 'Pernice', - 'Pesqueira', - 'Rieker', - 'Trautmann', - 'Yellowhair', - 'Schwanz', - 'Salinger', - 'Carvell', - 'Heymann', - 'Grad', - 'Pharo', - 'Pipher', - 'Magalhaes', - 'Kissee', - 'Winthrop', - 'Leid', - 'Sledd', - 'Bladen', - 'Rahaman', - 'Holdman', - 'Goldwire', - 'Lawal', - 'Sinkfield', - 'Bryk', - 'Butkiewicz', - 'Gagen', - 'Gettle', - 'Goede', - 'Hardenbrook', - 'Heinsohn', - 'Kovalcik', - 'Needleman', - 'Obeso', - 'Parziale', - 'Schaus', - 'Wadlow', - 'Haluska', - 'Stiteler', - 'Zaruba', - 'Tschirhart', - 'Biscardi', - 'Gopal', - 'Avella', - 'Ponto', - 'Levit', - 'Trevor', - 'Pimienta', - 'Plass', - 'Guthery', - 'Cordy', - 'Tuff', - 'Zellars', - 'Altier', - 'Berges', - 'Connick', - 'Deruyter', - 'Divita', - 'Frankovich', - 'Ingenito', - 'Kosman', - 'Lantis', - 'Lovering', - 'Sortino', - 'Waage', - 'Wildrick', - 'Barberio', - 'Domin', - 'Meisels', - 'Sender', - 'Giovanni', - 'Sanguinetti', - 'Beary', - 'Helmstetter', - 'Joens', - 'Beaven', - 'Kines', - 'Surrency', - 'Sheilds', - 'Chamber', - 'Albarez', - 'Ambrocio', - 'Arrellano', - 'Berrigan', - 'Bookwalter', - 'Caravella', - 'Higbie', - 'Lotter', - 'Lougee', - 'Manganiello', - 'Nobriga', - 'Roorda', - 'Serr', - 'Squillace', - 'Tejera', - 'Tipping', - 'Wohler', - 'Carreto', - 'Deignan', - 'Luebbers', - 'Engelhard', - 'Hollenback', - 'Baldo', - 'Gearin', - 'Bia', - 'Figueras', - 'Lule', - 'Libert', - 'Florida', - 'Wyne', - 'Mccright', - 'Jacko', - 'Cawthorne', - 'Rhue', - 'Betton', - 'Cisse', - 'Arth', - 'Bendickson', - 'Cangialosi', - 'Coltharp', - 'Cubias', - 'Czarnik', - 'Erpelding', - 'Erway', - 'Heister', - 'Mergen', - 'Murrietta', - 'Nachman', - 'Nusser', - 'Ostrem', - 'Pei', - 'Pescatore', - 'Reim', - 'Shaull', - 'Spranger', - 'Uphold', - 'Yslas', - 'Heinold', - 'Lindemuth', - 'Redeker', - 'Rochin', - 'Wisehart', - 'Carsey', - 'Nocella', - 'Combe', - 'Thacher', - 'Hammad', - 'Bene', - 'Yelvington', - 'Mccrone', - 'Driessen', - 'Saxby', - 'Maull', - 'Jeune', - 'Amorim', - 'Degrazia', - 'Doege', - 'Flinchbaugh', - 'Goodreau', - 'Hanisch', - 'Hoaglund', - 'Imamura', - 'Lafler', - 'Linne', - 'Profeta', - 'Reifschneider', - 'Santaana', - 'Scaffidi', - 'Shreeve', - 'Stadelman', - 'Dippolito', - 'Pizzuti', - 'Rodenberg', - 'Schartz', - 'Reiger', - 'Solie', - 'Willen', - 'Atallah', - 'Wyers', - 'Harpel', - 'Cleckler', - 'Fobes', - 'Sniffen', - 'Pedroso', - 'Samara', - 'Malcomb', - 'Penry', - 'Stearn', - 'Seller', - 'Abeita', - 'Bilotti', - 'Brosky', - 'Clewell', - 'Fraijo', - 'Gaskey', - 'Goodfriend', - 'Mesaros', - 'Musch', - 'Nulph', - 'Obarr', - 'Roat', - 'Sabato', - 'Sauerwein', - 'Schum', - 'Silsby', - 'Weyenberg', - 'Corrente', - 'Egloff', - 'Kohrs', - 'Sammartino', - 'Thoennes', - 'Carmer', - 'Madura', - 'Shang', - 'Faxon', - 'Monell', - 'Laden', - 'Yousuf', - 'Mcgauley', - 'Salmond', - 'Berhane', - 'Abood', - 'Bondar', - 'Buehrer', - 'Capelli', - 'Gersten', - 'Hambly', - 'Haymaker', - 'Kosar', - 'Lahaie', - 'Lecrone', - 'Lippy', - 'Pohle', - 'Shimmel', - 'Viall', - 'Yother', - 'Deviney', - 'Kosiba', - 'Wiederholt', - 'Sivley', - 'Wheelis', - 'Kanipe', - 'Braz', - 'Peacher', - 'Quadri', - 'Hancox', - 'Paye', - 'Curlin', - 'Broden', - 'Mckeller', - 'Baltodano', - 'Baquero', - 'Bolek', - 'Brede', - 'Bulson', - 'Christmann', - 'Cisler', - 'Delio', - 'Duffee', - 'Duzan', - 'Kuschel', - 'Mohon', - 'Nedrow', - 'Sengupta', - 'Timpe', - 'Veeder', - 'Zollner', - 'Zummo', - 'Hribar', - 'Laredo', - 'Mcdivitt', - 'Nazari', - 'Davern', - 'Heizer', - 'Orejel', - 'Haggett', - 'Flore', - 'Soley', - 'Bardell', - 'Comegys', - 'Bessent', - 'Shaheed', - 'Brugman', - 'Choudhary', - 'Fehl', - 'Fogt', - 'Heckmann', - 'Iacobucci', - 'Klaver', - 'Lumbert', - 'Mussman', - 'Pierotti', - 'Pihl', - 'Sandrock', - 'Scritchfield', - 'Siefken', - 'Stavropoulos', - 'Thomley', - 'Zenker', - 'Enke', - 'Knoke', - 'Rung', - 'Mikita', - 'Kunkler', - 'Deskin', - 'Egnor', - 'Vader', - 'Allers', - 'Pi', - 'Sproull', - 'Peller', - 'Kendell', - 'Jinkins', - 'Iglehart', - 'Brookens', - 'Darrough', - 'Winzer', - 'Amenta', - 'Aughenbaugh', - 'Barnick', - 'Conaty', - 'Eichmann', - 'Gilday', - 'Guhl', - 'Koskela', - 'Makuch', - 'Osoria', - 'Pujols', - 'Reinsch', - 'Reiswig', - 'Rosebrock', - 'Sahli', - 'Seitzinger', - 'Shermer', - 'Vasbinder', - 'Zanghi', - 'Flahive', - 'Mieczkowski', - 'Osmundson', - 'Willmann', - 'Agramonte', - 'Aven', - 'Vanderzee', - 'Fraher', - 'Kannan', - 'Shira', - 'Zetina', - 'Gilden', - 'Hingle', - 'Boutros', - 'Scutt', - 'Foree', - 'Gillins', - 'Screen', - 'Birden', - 'Guinyard', - 'Berreth', - 'Bertini', - 'Bousman', - 'Butchko', - 'Caras', - 'Donoso', - 'Gavilanes', - 'Karow', - 'Kouri', - 'Rediger', - 'Rininger', - 'Rosecrans', - 'Toops', - 'Vigliotti', - 'Cancio', - 'Karger', - 'Milholland', - 'Thielke', - 'Amster', - 'Rosch', - 'Elks', - 'Vasco', - 'Doshier', - 'Belasco', - 'Lean', - 'Dickason', - 'Suitt', - 'Tipler', - 'Obey', - 'Crear', - 'Redic', - 'Agredano', - 'Amarillas', - 'Arnesen', - 'Celedon', - 'Clapsaddle', - 'Coveney', - 'Demorest', - 'Gleich', - 'Guenthner', - 'Haverland', - 'Jaffee', - 'Kusek', - 'Manni', - 'Mysliwiec', - 'Nakama', - 'Ngan', - 'Ohmer', - 'Romanoff', - 'Salaiz', - 'Zeiders', - 'Bartholow', - 'Budke', - 'Centanni', - 'Koppelman', - 'Liberti', - 'Gatta', - 'Lovegrove', - 'Maggs', - 'Malay', - 'Blind', - 'Kerman', - 'Frans', - 'Rendleman', - 'Tyrone', - 'Ambers', - 'Rambert', - 'Killings', - 'Balicki', - 'Bohac', - 'Brisbois', - 'Cervone', - 'Curtner', - 'Ertle', - 'Fantozzi', - 'Feger', - 'Fineman', - 'Garate', - 'Goldy', - 'Gudmundson', - 'Harcrow', - 'Herdt', - 'Klapp', - 'Mirra', - 'Radu', - 'Saiki', - 'Unser', - 'Valko', - 'Verhoff', - 'Candelas', - 'Ireton', - 'Vanhuss', - 'Wierman', - 'Zawistowski', - 'Geiman', - 'Mess', - 'Full', - 'Fuertes', - 'Derickson', - 'Mccole', - 'Godden', - 'Mizzell', - 'Sane', - 'Shirer', - 'Fickling', - 'Marcelle', - 'Tramble', - 'Cappelletti', - 'Catterton', - 'Champeau', - 'Czyzewski', - 'Dirusso', - 'Herget', - 'Heupel', - 'Hinchliffe', - 'Levitsky', - 'Maheu', - 'Nakao', - 'Petsche', - 'Pilkenton', - 'Raska', - 'Rief', - 'Scheidegger', - 'Schmeltzer', - 'Sherlin', - 'Skarda', - 'Strassburg', - 'Sundaram', - 'Wuertz', - 'Bonanni', - 'Montante', - 'Ottesen', - 'Nading', - 'Bram', - 'Debell', - 'Sia', - 'Latch', - 'Largen', - 'Nack', - 'Smillie', - 'Debold', - 'Bruer', - 'Steedley', - 'Mckinny', - 'Radney', - 'Amadio', - 'Bearman', - 'Canny', - 'Cansino', - 'Cupo', - 'Ekstrand', - 'Forrer', - 'Imm', - 'Kawano', - 'Klingaman', - 'Kovacevich', - 'Lukasiewicz', - 'Mcdermid', - 'Michon', - 'Mincks', - 'Piano', - 'Ronayne', - 'Schaum', - 'Sciandra', - 'Villafan', - 'Wolin', - 'Schrager', - 'Strawderman', - 'Hable', - 'Skees', - 'Persky', - 'Defore', - 'Edmonston', - 'Base', - 'Barrell', - 'Cressey', - 'Husser', - 'Matin', - 'Mckennon', - 'Barak', - 'Buffone', - 'Clemence', - 'Delaguila', - 'Eberwein', - 'Eichholz', - 'Faraone', - 'Herington', - 'Kempa', - 'Kenefick', - 'Lahaye', - 'Larusso', - 'Osterloh', - 'Pfluger', - 'Pomponio', - 'Shiu', - 'Stokke', - 'Trembly', - 'Weck', - 'Alire', - 'Babayan', - 'Hustad', - 'Stumph', - 'Zwiebel', - 'Wicke', - 'Brauch', - 'Milos', - 'Haggart', - 'Mento', - 'Kennamer', - 'Thibeau', - 'Winge', - 'Lords', - 'Debaun', - 'Haw', - 'Mould', - 'Elison', - 'Etling', - 'Froemming', - 'Ghazarian', - 'Justesen', - 'Kawai', - 'Lensing', - 'Lindhorst', - 'Poveda', - 'Rabadan', - 'Vigeant', - 'Warnken', - 'Bermel', - 'Manry', - 'Suppes', - 'Stauder', - 'Dayley', - 'Lose', - 'Tappe', - 'Harle', - 'Mcquain', - 'Bettes', - 'Carline', - 'Cordner', - 'Habeeb', - 'Sisney', - 'Kyer', - 'Bruins', - 'Prosise', - 'Molton', - 'Blye', - 'Mccuin', - 'Babler', - 'Caiazzo', - 'Cereceres', - 'Ciaramitaro', - 'Corkran', - 'Crawshaw', - 'Degan', - 'Dunlavy', - 'Gronewold', - 'Hartner', - 'Kornacki', - 'Lapolla', - 'Mountz', - 'Mumpower', - 'Orefice', - 'Prats', - 'Repasky', - 'Schlee', - 'Sekhon', - 'Stanich', - 'Yilmaz', - 'Desisto', - 'Hanko', - 'Nichter', - 'Risenhoover', - 'Tomasso', - 'Blome', - 'Carda', - 'Ebrahimi', - 'Devor', - 'Pappa', - 'Caravello', - 'Lunday', - 'Slim', - 'Praytor', - 'Pickerel', - 'Wahab', - 'Breeland', - 'Flowe', - 'Brodnax', - 'Monds', - 'Sylla', - 'Bekele', - 'Mozee', - 'Beechy', - 'Birky', - 'Dellavalle', - 'Delmastro', - 'Dematteis', - 'Eckberg', - 'Eisenbraun', - 'Englehardt', - 'Fazzio', - 'Gedney', - 'Hana', - 'Keeran', - 'Lallier', - 'Martenson', - 'Mcelheny', - 'Paar', - 'Suski', - 'Vossen', - 'Westergaard', - 'Westermann', - 'Wiemann', - 'Golz', - 'Lofquist', - 'Pracht', - 'Tifft', - 'Ruhnke', - 'Schnider', - 'How', - 'Knaggs', - 'Bleck', - 'Whitelock', - 'Berringer', - 'Clepper', - 'Birkhead', - 'Pilson', - 'Inabinet', - 'Gentles', - 'Respress', - 'Crumble', - 'Bandera', - 'Bartunek', - 'Buerkle', - 'Dulong', - 'Eisinger', - 'Favero', - 'Giusto', - 'Guisinger', - 'Kiddy', - 'Krisher', - 'Lounsberry', - 'Morikawa', - 'Mowdy', - 'Penaflor', - 'Picariello', - 'Quirion', - 'Scali', - 'Scheibel', - 'Schlitt', - 'Sermeno', - 'Thalman', - 'Barraclough', - 'Boshart', - 'Glatfelter', - 'Hjelm', - 'Horlacher', - 'Muratalla', - 'Schepp', - 'Fogerty', - 'Mulero', - 'Manner', - 'Creecy', - 'Leftridge', - 'Ancira', - 'Anselmi', - 'Blew', - 'Coykendall', - 'Dembinski', - 'Emmerling', - 'Fawver', - 'Giard', - 'Heinzen', - 'Kasson', - 'Linam', - 'Lofaro', - 'Magnotta', - 'Pitzen', - 'Ripa', - 'Skowronek', - 'Sliter', - 'Stauch', - 'Szczepaniak', - 'Yerian', - 'Baccam', - 'Berres', - 'Helstrom', - 'Kocurek', - 'Kostelecky', - 'Corkins', - 'Fesperman', - 'Gibble', - 'Liranzo', - 'Karan', - 'Lavely', - 'Yorks', - 'Lisenbee', - 'Jerger', - 'Cockroft', - 'Brodhead', - 'Weathersbee', - 'Salih', - 'Pore', - 'Melbourne', - 'Code', - 'Scotton', - 'Addie', - 'Snipe', - 'Cuffie', - 'Haynesworth', - 'Borawski', - 'Borchard', - 'Cacciola', - 'Dedic', - 'Grzyb', - 'Hecox', - 'Horacek', - 'Nierman', - 'Nofziger', - 'Raup', - 'Rissler', - 'Segler', - 'Serviss', - 'Soon', - 'Tesmer', - 'Campanaro', - 'Curnutte', - 'Rabold', - 'Schreyer', - 'Siebenaler', - 'Zenteno', - 'Deveney', - 'Kuchera', - 'Ruden', - 'Skaff', - 'Sciulli', - 'Howeth', - 'Hanly', - 'Gola', - 'Forkner', - 'Rosene', - 'Beeker', - 'Mazo', - 'Lambson', - 'Younis', - 'Batch', - 'Ayo', - 'Ackles', - 'Hansbrough', - 'Terrance', - 'Bacani', - 'Cracraft', - 'Ebben', - 'Falzarano', - 'Ferreras', - 'Hovatter', - 'Jaskiewicz', - 'Killpack', - 'Kwasniewski', - 'Mahnken', - 'Natera', - 'Noboa', - 'Rapson', - 'Raybuck', - 'Shima', - 'Vahle', - 'Sheeks', - 'Laker', - 'Krok', - 'Debo', - 'Oberly', - 'Chelf', - 'Catala', - 'Airey', - 'Osten', - 'Golay', - 'Eliot', - 'Lebert', - 'Swaggerty', - 'Hue', - 'Seavers', - 'Bomer', - 'Bouyer', - 'Andazola', - 'Blancarte', - 'Brierly', - 'Centofanti', - 'Dalesandro', - 'Dickstein', - 'Kalas', - 'Langman', - 'Mouradian', - 'Okubo', - 'Overbaugh', - 'Popek', - 'Runnion', - 'Sannes', - 'Schamber', - 'Silfies', - 'Sinko', - 'Sit', - 'Cerrillo', - 'Gayler', - 'Kauth', - 'Culkin', - 'Peers', - 'Spidle', - 'Ballon', - 'Rasmus', - 'Queenan', - 'Reynaud', - 'Ambroise', - 'Mcclenton', - 'Adelmann', - 'Avellino', - 'Fickle', - 'Humm', - 'Hussong', - 'Iturralde', - 'Kritzer', - 'Lautzenheiser', - 'Linsky', - 'Malarkey', - 'Mallia', - 'Marban', - 'Mccance', - 'Nawaz', - 'Pallone', - 'Rindfleisch', - 'Schmall', - 'Sowle', - 'Stanco', - 'Whelpley', - 'Winning', - 'Kopczynski', - 'Pickup', - 'Tsou', - 'Phebus', - 'Munter', - 'Sisko', - 'Fico', - 'Mosco', - 'Rani', - 'Kon', - 'Baggott', - 'Brom', - 'Valerius', - 'Fines', - 'Megee', - 'Salsberry', - 'Sheff', - 'Mourning', - 'Archambeault', - 'Bhatnagar', - 'Budreau', - 'Dieffenbach', - 'Gildner', - 'Hevener', - 'Hippler', - 'Jonker', - 'Keef', - 'Kirlin', - 'Litvak', - 'Liz', - 'Mulhearn', - 'Popal', - 'Samaha', - 'Schwartzberg', - 'Sotello', - 'Weiskopf', - 'Neitzke', - 'Strelow', - 'Nitsch', - 'Lynne', - 'Olver', - 'Bange', - 'Boot', - 'Carmine', - 'Bellville', - 'Lafitte', - 'Condry', - 'Mccotter', - 'Spruiell', - 'Moman', - 'Legree', - 'Bongard', - 'Deiss', - 'Devoy', - 'Gusler', - 'Ianni', - 'Kolker', - 'Lagomarsino', - 'Leier', - 'Marbut', - 'Minsky', - 'Okumura', - 'Roza', - 'Siemon', - 'Vescio', - 'Wirkus', - 'Huizinga', - 'Lazalde', - 'Morici', - 'Ungaro', - 'Detamore', - 'Meer', - 'Erman', - 'Sherrow', - 'Laforte', - 'Pellman', - 'Bostock', - 'Lender', - 'Peagler', - 'Rhem', - 'Brisbon', - 'Angers', - 'Azbill', - 'Busto', - 'Coggeshall', - 'Cucci', - 'Defino', - 'Duey', - 'Fecht', - 'Grudzinski', - 'Guarneri', - 'Huesca', - 'Kolbeck', - 'Mennella', - 'Nishi', - 'Ohaver', - 'Porth', - 'Romanello', - 'Serrata', - 'Thoele', - 'Thornsbury', - 'Ulsh', - 'Vanderlinde', - 'Weninger', - 'Bonaventura', - 'Cura', - 'Filley', - 'Grabinski', - 'Kloc', - 'Kulinski', - 'Maruca', - 'Dantoni', - 'Grohman', - 'Starbird', - 'Rach', - 'Asman', - 'Mosso', - 'Slaney', - 'Kall', - 'Nevil', - 'Blann', - 'Frear', - 'Mosey', - 'Wrench', - 'Balkcom', - 'Liburd', - 'Yeboah', - 'Abbatiello', - 'Creviston', - 'Dunivan', - 'Durnin', - 'Eckerman', - 'Fennimore', - 'Gohlke', - 'Holtan', - 'Kochevar', - 'Kraushaar', - 'Landino', - 'Maack', - 'Montefusco', - 'Noguchi', - 'Norgard', - 'Olafson', - 'Paulick', - 'Petropoulos', - 'Principato', - 'Qazi', - 'Sammis', - 'Sida', - 'Sorum', - 'Vandal', - 'Vertrees', - 'Votta', - 'Wiesman', - 'Fleagle', - 'Panaro', - 'Stolarski', - 'Ogborn', - 'Petta', - 'Annett', - 'Campas', - 'Xing', - 'Lorey', - 'Restaino', - 'Forgue', - 'Rourk', - 'Modisette', - 'Aris', - 'Vandunk', - 'Dia', - 'Alverio', - 'Ancell', - 'Bieler', - 'Bouwman', - 'Campillo', - 'Cebreros', - 'Chant', - 'Cira', - 'Cragun', - 'Geppert', - 'Hemmert', - 'Kister', - 'Luger', - 'Ojala', - 'Pfeifle', - 'Piechocki', - 'Saldarriaga', - 'Skoda', - 'Vangorden', - 'Winberry', - 'Zeeb', - 'Gehm', - 'Oshima', - 'Tofte', - 'Tsoi', - 'Delman', - 'Harsha', - 'Finton', - 'Triola', - 'Bingle', - 'Delise', - 'Westergard', - 'Aul', - 'Celia', - 'Headings', - 'Mates', - 'Coste', - 'Venus', - 'Shearn', - 'Adell', - 'Minnifield', - 'Baxa', - 'Cieri', - 'Coppens', - 'Delahoz', - 'Fratus', - 'Gribbins', - 'Homann', - 'Ilg', - 'Majchrzak', - 'Mcclard', - 'Podolak', - 'Pollan', - 'Savio', - 'Schloemer', - 'Sesma', - 'Tilbury', - 'Torrico', - 'Vanduyn', - 'Eisert', - 'Levalley', - 'Silversmith', - 'Zanoni', - 'Grupe', - 'Marmolejos', - 'Marsch', - 'Martes', - 'Gorley', - 'Furbush', - 'Hughlett', - 'Stcyr', - 'Faustin', - 'Bushaw', - 'Cerbone', - 'Equihua', - 'Fiorella', - 'Ganzer', - 'Gugel', - 'Hladik', - 'Kalra', - 'Leuenberger', - 'Lusardi', - 'Nogales', - 'Schifano', - 'Swalley', - 'Tangney', - 'Zakarian', - 'Arenz', - 'Bottcher', - 'Gervasio', - 'Peschel', - 'Potteiger', - 'Teruya', - 'Tullier', - 'Lenhard', - 'Brusseau', - 'Streett', - 'Loan', - 'Fahmy', - 'Broadfoot', - 'Shugars', - 'Wilshire', - 'Mohabir', - 'Baye', - 'Sean', - 'Caruth', - 'Arroyos', - 'Campise', - 'Capparelli', - 'Desanti', - 'Dunsworth', - 'Fasching', - 'Heldman', - 'Keagle', - 'Kulesa', - 'Lawrenz', - 'Monhollen', - 'Niekamp', - 'Nucci', - 'Ostman', - 'Salzmann', - 'Schemmel', - 'Selin', - 'Stencel', - 'Zilka', - 'Friesner', - 'Onstad', - 'Poovey', - 'Squillante', - 'Tullo', - 'Uriegas', - 'Vigilante', - 'Lasswell', - 'Navedo', - 'Dunnagan', - 'Pevey', - 'Santino', - 'Waldren', - 'Leven', - 'Stinnette', - 'Eleazer', - 'Ragas', - 'Cockfield', - 'Lafontant', - 'Babinski', - 'Balash', - 'Hadler', - 'Kantz', - 'Latini', - 'Lavy', - 'Mally', - 'Maurin', - 'Mifsud', - 'Miguez', - 'Muma', - 'Needle', - 'Orrico', - 'Zalazar', - 'Chinen', - 'Coluccio', - 'Gibboney', - 'Knapke', - 'Moczygemba', - 'Leonguerrero', - 'Punzalan', - 'Lortz', - 'Rosel', - 'Mcclaran', - 'Weatherhead', - 'Mcgurn', - 'Sanville', - 'Goe', - 'Phang', - 'Briskey', - 'Bluitt', - 'Hapner', - 'Lamadrid', - 'Leuthold', - 'Litchford', - 'Scaduto', - 'Smoyer', - 'Stonehouse', - 'Streng', - 'Susman', - 'Swoyer', - 'Tempesta', - 'Tiedt', - 'Politi', - 'Ruotolo', - 'Schwendeman', - 'Siegenthaler', - 'Streff', - 'Strite', - 'Kroft', - 'Lewey', - 'Silbert', - 'Frie', - 'Bentson', - 'Coin', - 'Lupe', - 'Mousa', - 'Syler', - 'Fester', - 'Tenny', - 'Surgeon', - 'Blowe', - 'Metellus', - 'Borboa', - 'Danker', - 'Ferch', - 'Fritzsche', - 'Gudiel', - 'Kilmartin', - 'Nieland', - 'Soffer', - 'Yescas', - 'Chappelear', - 'Hincapie', - 'Landowski', - 'Barfoot', - 'Hesketh', - 'Mittelman', - 'Escorcia', - 'Meetze', - 'Coral', - 'Huddleson', - 'Hoo', - 'Googe', - 'Munir', - 'Reine', - 'Studstill', - 'Swims', - 'Ganaway', - 'Daise', - 'Blando', - 'Bream', - 'Cangemi', - 'Dicola', - 'Difalco', - 'Gleim', - 'Goerke', - 'Jauch', - 'Lashway', - 'Mckinlay', - 'Mura', - 'Polsky', - 'Roehrich', - 'Schwalbach', - 'Tegtmeier', - 'Theel', - 'Wuthrich', - 'Yabut', - 'Zara', - 'Ardizzone', - 'Blasius', - 'Deramo', - 'Heffern', - 'Rickels', - 'Wojtas', - 'Bue', - 'Garant', - 'Kitagawa', - 'Vorhees', - 'Randa', - 'Seider', - 'Bi', - 'Womac', - 'Santerre', - 'Mesmer', - 'Bailly', - 'Argue', - 'Spidell', - 'Manu', - 'General', - 'Exantus', - 'Neloms', - 'Piggee', - 'Agcaoili', - 'Ambrosini', - 'Balleza', - 'Bhavsar', - 'Brandstetter', - 'Cascone', - 'Deyton', - 'Fette', - 'Gershman', - 'Hanni', - 'Hitchner', - 'Manthe', - 'Marengo', - 'Ockerman', - 'Pergola', - 'Ratterree', - 'Shober', - 'Swezey', - 'Vadala', - 'Waszak', - 'Wishard', - 'Zhuang', - 'Bobst', - 'Filippini', - 'Giardino', - 'Johanning', - 'Kloepfer', - 'Dahan', - 'Rahmani', - 'Hett', - 'Sha', - 'Spaugh', - 'Darner', - 'Dagen', - 'Gaier', - 'Musco', - 'Holling', - 'Keahey', - 'Merricks', - 'Nur', - 'Andrick', - 'Demauro', - 'Haury', - 'Hsiung', - 'Kotarski', - 'Kriesel', - 'Leleux', - 'Nazar', - 'Oganesyan', - 'Polivka', - 'Sansoucie', - 'Serafino', - 'Stammer', - 'Tamm', - 'Wachowiak', - 'Zinda', - 'Goedde', - 'Pedregon', - 'Snader', - 'Witczak', - 'Kem', - 'Prabhu', - 'Purtle', - 'Nola', - 'Om', - 'Finster', - 'Bryans', - 'Mateus', - 'Bour', - 'Santy', - 'Mola', - 'Guile', - 'Denne', - 'Bol', - 'Mont', - 'Perro', - 'Haji', - 'Swinger', - 'Mitchelle', - 'Creary', - 'Leeks', - 'Barsotti', - 'Bolender', - 'Dohner', - 'Federman', - 'Lancour', - 'Lueken', - 'Pettinger', - 'Rathmann', - 'Schiess', - 'Schulenberg', - 'Troyan', - 'Dafoe', - 'Delahunt', - 'Domagala', - 'Ganske', - 'Grasmick', - 'Guinther', - 'Hlavac', - 'Klumb', - 'Susko', - 'Vanhandel', - 'Burget', - 'Thaker', - 'Winker', - 'Castellucci', - 'Guerette', - 'Garde', - 'Busher', - 'Usery', - 'Braker', - 'Blan', - 'Goar', - 'Loiseau', - 'Anderberg', - 'Bamber', - 'Biagini', - 'Dack', - 'Groeneveld', - 'Habig', - 'Howk', - 'Kutsch', - 'Mcgloin', - 'Nevares', - 'Piedrahita', - 'Puffenbarger', - 'Racer', - 'Stanaland', - 'Turck', - 'Vanvleck', - 'Velardi', - 'Verhoeven', - 'Wernick', - 'Wherley', - 'Zamzow', - 'Binegar', - 'Kaluza', - 'Kudrna', - 'Marbach', - 'Schwichtenberg', - 'Chay', - 'Lanthier', - 'Balling', - 'Parcher', - 'Venner', - 'Nolette', - 'Quant', - 'Grierson', - 'Quest', - 'Level', - 'Birkner', - 'Evancho', - 'Grinde', - 'Horiuchi', - 'Hoselton', - 'Kuk', - 'Maiello', - 'Matuska', - 'Melito', - 'Northey', - 'Pallante', - 'Porzio', - 'Rad', - 'Rizzolo', - 'Thull', - 'Urenda', - 'Dalfonso', - 'Harbold', - 'Kemerer', - 'Knapton', - 'Meeder', - 'Ruckle', - 'Segui', - 'Behne', - 'Bamburg', - 'Galen', - 'Hallen', - 'Herandez', - 'Chittick', - 'Deshon', - 'Verrier', - 'Sorel', - 'Neylon', - 'Thatch', - 'Bayly', - 'Beever', - 'Galka', - 'Gruhn', - 'Gsell', - 'Happe', - 'Hovan', - 'Marter', - 'Matarese', - 'Mellema', - 'Ollila', - 'Schempp', - 'Serda', - 'Skenandore', - 'Stemper', - 'Toupin', - 'Vandeven', - 'Yauger', - 'Koenigs', - 'Mullendore', - 'Ouellet', - 'Sullenberger', - 'Julson', - 'Pelot', - 'Clamp', - 'Berte', - 'Beese', - 'Matkin', - 'Erie', - 'Rosenburg', - 'Reap', - 'Stelle', - 'Rayon', - 'Hoit', - 'Hollyfield', - 'Kindall', - 'Agent', - 'Glascoe', - 'Holts', - 'Wynder', - 'Balderston', - 'Bernardy', - 'Blehm', - 'Casebeer', - 'Emler', - 'Farrugia', - 'Guzzardo', - 'Johnsrud', - 'Maffeo', - 'Mccartan', - 'Redburn', - 'Reesman', - 'Savas', - 'Shamoon', - 'Shown', - 'Spinale', - 'Tabaka', - 'Wedell', - 'Armato', - 'Bassford', - 'Bungard', - 'Faerber', - 'Freet', - 'Oesterle', - 'Vandeberg', - 'Bacha', - 'Stemm', - 'Edgett', - 'Karrick', - 'Girten', - 'Orgill', - 'Meridith', - 'Cullom', - 'Hennington', - 'Minns', - 'Appleberry', - 'Abare', - 'Annen', - 'Beierle', - 'Berish', - 'Cracchiolo', - 'Dilullo', - 'Kehm', - 'Kuhne', - 'Modglin', - 'Norland', - 'Petruzzelli', - 'Schabel', - 'Stauffacher', - 'Villena', - 'Wageman', - 'Willden', - 'Faiella', - 'Mangiaracina', - 'Petralia', - 'Witwer', - 'Tropp', - 'Bores', - 'Burkel', - 'Stanifer', - 'Teele', - 'Cornick', - 'Credit', - 'Dorvil', - 'Bonillas', - 'Callinan', - 'Colleran', - 'Finer', - 'Krach', - 'Lubas', - 'Lutman', - 'Marien', - 'Mccort', - 'Merica', - 'Mies', - 'Nicotra', - 'Novosad', - 'Priem', - 'Ramakrishnan', - 'Zolman', - 'Deitsch', - 'Georgi', - 'Haberstroh', - 'Kofoed', - 'Kreischer', - 'Nazareno', - 'Norkus', - 'Steimle', - 'Fellin', - 'Ghanem', - 'Kosch', - 'Pages', - 'Balthazor', - 'Corte', - 'Hoh', - 'Shrewsberry', - 'Beharry', - 'Waight', - 'Leconte', - 'Clowney', - 'Tesfaye', - 'Andis', - 'Brosch', - 'Bruckman', - 'Carducci', - 'Erbes', - 'Ferreiro', - 'Gatten', - 'Heggen', - 'Kackley', - 'Klamm', - 'Korff', - 'Lehane', - 'Mech', - 'Montanari', - 'Pousson', - 'Soderholm', - 'Strey', - 'Upp', - 'Wahlen', - 'Cedrone', - 'Steuber', - 'Vonfeldt', - 'Deridder', - 'Shams', - 'Barnas', - 'Bake', - 'Brownrigg', - 'Donohoo', - 'Mccorry', - 'Spruce', - 'Masden', - 'Porchia', - 'Fofana', - 'Bless', - 'Caler', - 'Calva', - 'Carnero', - 'Chakraborty', - 'Clenney', - 'Dockendorf', - 'Dziak', - 'Errickson', - 'Ewoldt', - 'Klippel', - 'Krass', - 'Luebbe', - 'Parlett', - 'Paternostro', - 'Peterka', - 'Petitti', - 'Puthoff', - 'Wessman', - 'Brossman', - 'Glotfelty', - 'Grabau', - 'Kortz', - 'Sienko', - 'Yonan', - 'Fakhoury', - 'Bunney', - 'Sillas', - 'Guerry', - 'Sedwick', - 'Okey', - 'Virgo', - 'Babers', - 'Casali', - 'Chiquito', - 'Correnti', - 'Doverspike', - 'Fryberger', - 'Golas', - 'Golob', - 'Hufstetler', - 'Inoa', - 'Lasser', - 'Nesheim', - 'Peveto', - 'Reckner', - 'Rydzewski', - 'Shartzer', - 'Smouse', - 'Tipple', - 'Wantland', - 'Wolfert', - 'Yordy', - 'Zuleta', - 'Heimerl', - 'Mccarren', - 'Cabeza', - 'Neice', - 'Kassem', - 'Hodgen', - 'Charrier', - 'Duggar', - 'Blacksmith', - 'Cush', - 'Trunnell', - 'Laventure', - 'Salahuddin', - 'Batalla', - 'Brahmbhatt', - 'Breslow', - 'Cua', - 'Deatley', - 'Digrazia', - 'Divirgilio', - 'Falin', - 'Freiberger', - 'Gladish', - 'Holyoak', - 'Lazos', - 'Loader', - 'Mcclafferty', - 'Meloni', - 'Muhr', - 'Salzwedel', - 'Schaab', - 'Shehadeh', - 'Suresh', - 'Verdusco', - 'Younglove', - 'Damman', - 'Fulco', - 'Neikirk', - 'Laver', - 'Biro', - 'Shill', - 'Labarr', - 'Kari', - 'Mcclory', - 'Torelli', - 'Knock', - 'Dormer', - 'Papin', - 'Stoneham', - 'Weathington', - 'Albus', - 'Andel', - 'Banville', - 'Cassens', - 'Chalifoux', - 'Dellaquila', - 'Depauw', - 'Deschene', - 'Genung', - 'Greider', - 'Luhman', - 'Mastropietro', - 'Mignogna', - 'Pisarski', - 'Terrien', - 'Thomure', - 'Tornabene', - 'Beheler', - 'Chimento', - 'Engelbert', - 'Gambone', - 'Goettl', - 'Jasperson', - 'Kovalenko', - 'Infinger', - 'Timbs', - 'Dasgupta', - 'Purdon', - 'Velie', - 'Eland', - 'Ankrum', - 'Narain', - 'Mcfarling', - 'Creagh', - 'Bunyan', - 'Rattigan', - 'Reddix', - 'Aumann', - 'Beilfuss', - 'Bogosian', - 'Bramel', - 'Burlingham', - 'Cruzan', - 'Demel', - 'Dorff', - 'Figley', - 'Friesz', - 'Huffstutler', - 'Mcdaris', - 'Meinecke', - 'Moench', - 'Newville', - 'Normile', - 'Pfund', - 'Pilar', - 'Seckman', - 'Szoke', - 'Zyla', - 'Freilich', - 'Hammerle', - 'Kopel', - 'Liskey', - 'Mesina', - 'Schlicher', - 'Dalen', - 'Bettin', - 'Malanga', - 'Dern', - 'Tuckey', - 'Warder', - 'Harren', - 'Siner', - 'Mahdi', - 'Ahmann', - 'Allor', - 'Claywell', - 'Corkill', - 'Follansbee', - 'Iseman', - 'Lawter', - 'Myslinski', - 'Sauser', - 'Tornatore', - 'Bhasin', - 'Governale', - 'Karstens', - 'Klocek', - 'Stempien', - 'Petrino', - 'Kohlmeier', - 'Igou', - 'Sari', - 'Mareno', - 'Bouche', - 'Romas', - 'Urey', - 'Sprott', - 'Ponzo', - 'Nevills', - 'Affolter', - 'Alleva', - 'Allgaier', - 'Azbell', - 'Branagan', - 'Fiebig', - 'Geremia', - 'Grabert', - 'Grahl', - 'Gruwell', - 'Koebel', - 'Krauter', - 'Kuhnert', - 'Kuperman', - 'Laverdiere', - 'Leuck', - 'Masella', - 'Mierzejewski', - 'Platek', - 'Samaan', - 'Selsor', - 'Vickroy', - 'Whitenack', - 'Zanella', - 'Cavagnaro', - 'Galioto', - 'Schoeneman', - 'Zanotti', - 'Bort', - 'Alpaugh', - 'Culverhouse', - 'Perona', - 'Wheelwright', - 'Amber', - 'Bradner', - 'Sedberry', - 'Goethe', - 'Swygert', - 'Nisbett', - 'Harts', - 'Pendelton', - 'Keita', - 'Addair', - 'Anania', - 'Armagost', - 'Brumett', - 'Butala', - 'Celmer', - 'Forquer', - 'Hagadorn', - 'Jalomo', - 'Koranda', - 'Lemmond', - 'Liske', - 'Mcglamery', - 'Ramiro', - 'Tickner', - 'Toso', - 'Tosti', - 'Beerbower', - 'Bichler', - 'Buege', - 'Cadotte', - 'Chiong', - 'Romberger', - 'Mandarino', - 'Deter', - 'Wallack', - 'Bligh', - 'Harer', - 'Terral', - 'Hobert', - 'Doren', - 'Affleck', - 'Marquess', - 'Lewton', - 'Covel', - 'Reff', - 'Gowins', - 'Claybrooks', - 'Artiles', - 'Brunelli', - 'Campusano', - 'Deshaies', - 'Elpers', - 'Fait', - 'Heathcote', - 'Katayama', - 'Landreneau', - 'Nardelli', - 'Padovano', - 'Pendry', - 'Santillano', - 'Ubaldo', - 'Wurz', - 'Bathke', - 'Fillers', - 'Reitano', - 'Patrone', - 'Mountford', - 'Farran', - 'Burdo', - 'Danish', - 'Windell', - 'Amrine', - 'Pilgreen', - 'Pross', - 'Bowery', - 'Girdner', - 'Stockley', - 'Chisom', - 'Bigos', - 'Cavallero', - 'Choma', - 'Chorba', - 'Doubek', - 'Eynon', - 'Fitzmorris', - 'Gergely', - 'Hilsabeck', - 'Hime', - 'Kafer', - 'Kilday', - 'Lairson', - 'Mccanless', - 'Meenan', - 'Mossburg', - 'Muscato', - 'Raap', - 'Ramp', - 'Reali', - 'Reinard', - 'Rivadeneira', - 'Schwenn', - 'Serbin', - 'Soeder', - 'Wagle', - 'Jablonowski', - 'Vanni', - 'Grapes', - 'Hilleary', - 'Mondor', - 'Natalie', - 'Seat', - 'Heming', - 'Waide', - 'Haverly', - 'Eva', - 'Marshman', - 'Mais', - 'Portlock', - 'Scoby', - 'Sharps', - 'Buday', - 'Bumbalough', - 'Burback', - 'Carano', - 'Eustis', - 'Flaim', - 'Fraticelli', - 'Grimme', - 'Heape', - 'Hoaglin', - 'Kreuser', - 'Odgers', - 'Pastorius', - 'Pavek', - 'Rogoff', - 'Skorupski', - 'Stene', - 'Tomasino', - 'Varble', - 'Vasek', - 'Woolums', - 'Arcaro', - 'Graley', - 'Larkey', - 'Ortlieb', - 'Piccone', - 'Verhey', - 'Inch', - 'Laroe', - 'Brockmeier', - 'Familia', - 'Soll', - 'Duplechin', - 'Blevens', - 'Gell', - 'Hipkins', - 'Kleinpeter', - 'Swindall', - 'Sabir', - 'Kinloch', - 'Muldrew', - 'Clausell', - 'Bouch', - 'Casciano', - 'Dewhirst', - 'Draney', - 'Fourman', - 'Fuente', - 'Ganci', - 'Gentzler', - 'Gerhold', - 'Ingoglia', - 'Jerabek', - 'Keisling', - 'Larivee', - 'Negro', - 'Pelchat', - 'Quilty', - 'Reinig', - 'Rubeck', - 'Rudick', - 'Rulli', - 'Spagnoli', - 'Wiltsie', - 'Vitolo', - 'Neuhauser', - 'Khurana', - 'Vint', - 'Kant', - 'Nead', - 'Deroy', - 'Ransford', - 'Stromer', - 'Buley', - 'Bloxom', - 'Rieves', - 'Bastos', - 'Deckman', - 'Duenes', - 'Hessling', - 'Kresse', - 'Langdale', - 'Penberthy', - 'Polyak', - 'Sagun', - 'Salehi', - 'Sas', - 'Soja', - 'Spieth', - 'Verhulst', - 'Walen', - 'Woodling', - 'Acierno', - 'Bergsma', - 'Biskup', - 'Buonomo', - 'Gores', - 'Koffman', - 'Redder', - 'Ishak', - 'Billow', - 'Ratledge', - 'Widder', - 'Margerum', - 'Bussing', - 'Caccamo', - 'Carozza', - 'Cwik', - 'Forner', - 'Goeden', - 'Greninger', - 'Hartenstein', - 'Hermida', - 'Krutz', - 'Kubes', - 'Kulow', - 'Lynott', - 'Mank', - 'Meinders', - 'Mikrut', - 'Moots', - 'Patek', - 'Pogorzelski', - 'Reinstein', - 'Ruiter', - 'Rupard', - 'Salvia', - 'Sissom', - 'Sligar', - 'Spendlove', - 'Vian', - 'Wissing', - 'Witucki', - 'Brossart', - 'Warhurst', - 'Staron', - 'Gilly', - 'Borck', - 'Mccarn', - 'Stanbery', - 'Aydelotte', - 'Etters', - 'Rho', - 'Menzer', - 'Knoble', - 'Luallen', - 'Meda', - 'Myre', - 'Nevils', - 'Seide', - 'Rouser', - 'Bernas', - 'Bressette', - 'Dohn', - 'Domina', - 'Filion', - 'Fossen', - 'Grunder', - 'Hofland', - 'Larranaga', - 'Launius', - 'Lento', - 'Mohrmann', - 'Papenfuss', - 'Polcyn', - 'Pollina', - 'Reinheimer', - 'Rueb', - 'Sacher', - 'Sauseda', - 'Whitwell', - 'Caspers', - 'Dejager', - 'Kastelic', - 'Kildow', - 'Sappenfield', - 'Schultes', - 'Tucciarone', - 'Gogan', - 'Sarti', - 'Percle', - 'Cagney', - 'Wasley', - 'Getts', - 'Sahm', - 'Brandle', - 'Osbon', - 'Febres', - 'Billett', - 'Pall', - 'Spearing', - 'Thursby', - 'Junious', - 'Allenbaugh', - 'Calamia', - 'Cregan', - 'Hostettler', - 'Leete', - 'Pirrone', - 'Ploeger', - 'Revak', - 'Sarlo', - 'Sayavong', - 'Schlichter', - 'Shonkwiler', - 'Soots', - 'Spak', - 'Thien', - 'Torgeson', - 'Urbanczyk', - 'Vredenburg', - 'Wormuth', - 'Yankovich', - 'Badertscher', - 'Holewinski', - 'Kalinoski', - 'Kwasny', - 'Neidert', - 'Remmel', - 'Uram', - 'Zettlemoyer', - 'Sanna', - 'Walthers', - 'Kinkaid', - 'Rummage', - 'Vane', - 'Morgen', - 'Stum', - 'Ainsley', - 'Mckelvie', - 'Barbin', - 'Shariff', - 'Blanchett', - 'Mayon', - 'Broadie', - 'Millien', - 'Azzarello', - 'Bocock', - 'Bohlander', - 'Brennecke', - 'Daman', - 'Dixit', - 'Goth', - 'Kocur', - 'Koslow', - 'Loncar', - 'Narez', - 'Oleksy', - 'Ouderkirk', - 'Rathe', - 'Sandmann', - 'Scarpino', - 'Siegman', - 'Soloway', - 'Tomeo', - 'Vantuyl', - 'Benesch', - 'Doornbos', - 'Gisler', - 'Nistler', - 'Pelzel', - 'Piecuch', - 'Schweiss', - 'Zieba', - 'Domangue', - 'Curti', - 'Iams', - 'Viger', - 'Sandefer', - 'Maybury', - 'Haneline', - 'Shappell', - 'Charlier', - 'Belardo', - 'Lynk', - 'Ocain', - 'Ismael', - 'Blacksher', - 'Lesesne', - 'Blash', - 'Fantroy', - 'Bucciarelli', - 'Deruiter', - 'Fetner', - 'Filla', - 'Frontera', - 'Furlan', - 'Goepfert', - 'Gorsline', - 'Gugino', - 'Kleis', - 'Kriger', - 'Lebarron', - 'Lesnick', - 'Losano', - 'Macquarrie', - 'Marczak', - 'Mazariego', - 'Moraes', - 'Murano', - 'Myint', - 'Philley', - 'Ruffalo', - 'Salyards', - 'Swab', - 'Trester', - 'Vlcek', - 'Abramo', - 'Kaczmarski', - 'Mastronardi', - 'Lafont', - 'Tomerlin', - 'Mchan', - 'Blanda', - 'Deandrade', - 'Klien', - 'Meno', - 'Maia', - 'Durall', - 'Lansdowne', - 'Cones', - 'Adley', - 'Taffe', - 'Ikard', - 'Sylve', - 'Bartok', - 'Farler', - 'Farnworth', - 'Gookin', - 'Guijarro', - 'Hazan', - 'Hosterman', - 'Klees', - 'Knust', - 'Leadingham', - 'Lefeber', - 'Maisch', - 'Muchmore', - 'Pini', - 'Polinsky', - 'Quakenbush', - 'Rought', - 'Ruta', - 'Tingen', - 'Urness', - 'Valade', - 'Wadle', - 'Hietala', - 'Hockenbury', - 'Ivanoff', - 'Mcevers', - 'Miyazaki', - 'Druckenmiller', - 'Neisler', - 'Vroom', - 'Berland', - 'Rizor', - 'Caris', - 'Jenison', - 'Folmer', - 'Si', - 'Pulling', - 'Houge', - 'Snuggs', - 'Enis', - 'Peeks', - 'Stacker', - 'Destin', - 'Ojo', - 'Barraco', - 'Childree', - 'Ciszewski', - 'Dicenzo', - 'Gowing', - 'Granquist', - 'Kapinos', - 'Khalili', - 'Kienitz', - 'Konrath', - 'Kosa', - 'Schilz', - 'Sealock', - 'Soucek', - 'Stefanko', - 'Trow', - 'Udy', - 'Fricano', - 'Hunnewell', - 'Sieler', - 'Stranahan', - 'Thammavongsa', - 'Zettel', - 'Cutrell', - 'Balter', - 'Clavel', - 'Thibert', - 'Ondo', - 'Senna', - 'Kun', - 'Maximo', - 'Wares', - 'Caldeira', - 'Furgerson', - 'Franklyn', - 'Christophe', - 'Bady', - 'Blanken', - 'Boike', - 'Cuen', - 'Davidian', - 'Glauser', - 'Gleave', - 'Guzy', - 'Halleck', - 'Kempfer', - 'Kenkel', - 'Kloth', - 'Knable', - 'Mcenery', - 'Pizzolato', - 'Schryver', - 'Seminara', - 'Shenoy', - 'Somera', - 'Stroop', - 'Weirick', - 'Yatsko', - 'Evanko', - 'Koegel', - 'Lastinger', - 'Schrenk', - 'Vitullo', - 'Holste', - 'Susa', - 'Pedley', - 'Cove', - 'Levett', - 'Gillyard', - 'Boeding', - 'Delpozo', - 'Denoyer', - 'Farese', - 'Floro', - 'Gavina', - 'Hargus', - 'Kisiel', - 'Konig', - 'Krotz', - 'Lundblad', - 'Masoner', - 'Mumper', - 'Nolf', - 'Sandgren', - 'Schussler', - 'Shallcross', - 'Singhal', - 'Standen', - 'Teta', - 'Vacanti', - 'Yokota', - 'Borski', - 'Filice', - 'Frankum', - 'Kleinsmith', - 'Plauche', - 'Spohr', - 'Goya', - 'Rosensteel', - 'Srey', - 'Touhey', - 'Launer', - 'Dome', - 'Mossey', - 'Mclay', - 'Sturgess', - 'Demond', - 'Buren', - 'Millin', - 'Riddles', - 'Arps', - 'Dugar', - 'Carradine', - 'Brasseur', - 'Burchill', - 'Champoux', - 'Chojnowski', - 'Cyphert', - 'Devincentis', - 'Donze', - 'Gaspari', - 'Harshberger', - 'Merchan', - 'Mulgrew', - 'Parma', - 'Pasqua', - 'Pierpoint', - 'Rozeboom', - 'Rumery', - 'Stahle', - 'Stierwalt', - 'Swander', - 'Tiegs', - 'Trabucco', - 'Withington', - 'Frericks', - 'Kilman', - 'Locastro', - 'Samonte', - 'Sanko', - 'Wisman', - 'Flecha', - 'Coplan', - 'Zafra', - 'Art', - 'Maxam', - 'Cavaness', - 'Willi', - 'Vanliew', - 'Fresh', - 'Bauserman', - 'Bergemann', - 'Buchler', - 'Curbow', - 'Dimascio', - 'Einstein', - 'Favila', - 'Galeno', - 'Granat', - 'Halteman', - 'Janczak', - 'Janicek', - 'Jundt', - 'Karren', - 'Modesitt', - 'Provance', - 'Reasons', - 'Riveron', - 'Salts', - 'Salvino', - 'Sawhney', - 'Shallenberger', - 'Sirk', - 'Tylka', - 'Baumler', - 'Mcmenamy', - 'Territo', - 'Thackeray', - 'Much', - 'Papageorge', - 'Rynders', - 'Bacigalupo', - 'Fulwider', - 'Hendricksen', - 'Lepre', - 'Mangel', - 'Dering', - 'Soda', - 'Bazar', - 'Dinning', - 'Portera', - 'Schatzman', - 'Kernodle', - 'Bashford', - 'Ferrebee', - 'Cortner', - 'Sanker', - 'Livings', - 'Jemmott', - 'Arzaga', - 'Cihak', - 'Cobarrubias', - 'Coey', - 'Coutinho', - 'Deneau', - 'Droll', - 'Hickel', - 'Hillmann', - 'Kitto', - 'Lefebre', - 'Lev', - 'Mato', - 'Mcomber', - 'Norlin', - 'Renstrom', - 'Rhyner', - 'Sacca', - 'Sangha', - 'Sutor', - 'Dwire', - 'Huyser', - 'Kressin', - 'Moilanen', - 'Picado', - 'Schmidlin', - 'Albor', - 'Zaldana', - 'Failor', - 'Dubberly', - 'Youse', - 'Mohiuddin', - 'Shiel', - 'Loran', - 'Hamme', - 'Castine', - 'Lanum', - 'Mcelderry', - 'Riggsbee', - 'Madkins', - 'Abts', - 'Bekker', - 'Boccio', - 'Florin', - 'Lienemann', - 'Madara', - 'Manganello', - 'Mcfetridge', - 'Medsker', - 'Minish', - 'Roberg', - 'Sajdak', - 'Schwall', - 'Sedivy', - 'Suto', - 'Wieberg', - 'Catherman', - 'Ficker', - 'Leckrone', - 'Lieder', - 'Rodak', - 'Tomek', - 'Everard', - 'Spong', - 'Glacken', - 'Polka', - 'Aley', - 'Farro', - 'Stanwood', - 'Petter', - 'Desrosier', - 'Kerl', - 'Goslee', - 'Burston', - 'Pennywell', - 'Birchard', - 'Federer', - 'Flicker', - 'Frangos', - 'Korhonen', - 'Kozikowski', - 'Kyger', - 'Mccoskey', - 'Standing', - 'Terada', - 'Trierweiler', - 'Trupiano', - 'Urbanowicz', - 'Viegas', - 'Ybarbo', - 'Brinlee', - 'Daddona', - 'Deisher', - 'Schwieger', - 'Farless', - 'Slaght', - 'Jarvie', - 'Hunkins', - 'Barrack', - 'Bisset', - 'Bruley', - 'Molen', - 'Milas', - 'Matts', - 'Wickware', - 'Timbers', - 'Minus', - 'Kennebrew', - 'Boorman', - 'Faughn', - 'Feight', - 'Githens', - 'Hazelrigg', - 'Hutzell', - 'Klang', - 'Kogler', - 'Lechtenberg', - 'Malachowski', - 'Orsburn', - 'Retz', - 'Saban', - 'Tak', - 'Underdahl', - 'Veldman', - 'Virnig', - 'Wanat', - 'Achord', - 'Drenth', - 'Heibel', - 'Hendee', - 'Raiche', - 'Saunier', - 'Wertheim', - 'Forand', - 'Stathis', - 'Raider', - 'Cassaro', - 'Cly', - 'Hagey', - 'Moad', - 'Rhody', - 'Fogler', - 'Hellen', - 'Sweezy', - 'Farid', - 'Suddreth', - 'Kenneth', - 'Pindell', - 'Corney', - 'Monsanto', - 'Laye', - 'Lingard', - 'Armwood', - 'Asif', - 'Axley', - 'Barkan', - 'Bittel', - 'Boesen', - 'Camilli', - 'Champa', - 'Dauenhauer', - 'Ehrmann', - 'Gangl', - 'Gatrell', - 'Gehret', - 'Hankel', - 'Kalbach', - 'Kessell', - 'Khatoon', - 'Lanese', - 'Manco', - 'Masteller', - 'Pruner', - 'Remmert', - 'Valasek', - 'Vater', - 'Yurick', - 'Zavalza', - 'Biesecker', - 'Frankenberg', - 'Hovorka', - 'Poissant', - 'Neises', - 'Moog', - 'Hadad', - 'Wittenburg', - 'Devere', - 'Hynds', - 'Sparkes', - 'Brailey', - 'Addo', - 'Accetta', - 'Altschuler', - 'Amescua', - 'Corredor', - 'Didonna', - 'Jencks', - 'Keady', - 'Keidel', - 'Mancebo', - 'Matusiak', - 'Rakoczy', - 'Reamy', - 'Sardella', - 'Slotnick', - 'Fotheringham', - 'Gettman', - 'Kunzler', - 'Manganaro', - 'Manygoats', - 'Huelskamp', - 'Newsham', - 'Kohen', - 'Cong', - 'Goulden', - 'Timmers', - 'Aderhold', - 'Shinall', - 'Cowser', - 'Uzzle', - 'Harps', - 'Balster', - 'Baringer', - 'Bechler', - 'Billick', - 'Chenard', - 'Ditta', - 'Fiallos', - 'Kampe', - 'Kretzschmar', - 'Manukyan', - 'Mcbreen', - 'Mcmanigal', - 'Miko', - 'Mol', - 'Orrego', - 'Penalosa', - 'Ronco', - 'Thum', - 'Tupa', - 'Vittitow', - 'Wierzba', - 'Gavitt', - 'Hampe', - 'Kowalkowski', - 'Neuroth', - 'Sterkel', - 'Herling', - 'Boldman', - 'Camus', - 'Drier', - 'Arcia', - 'Feagans', - 'Thompsen', - 'Maka', - 'Villalona', - 'Bonito', - 'Buist', - 'Dato', - 'Yankey', - 'Daluz', - 'Hollands', - 'Durio', - 'Bradly', - 'Daffin', - 'Chhabra', - 'Dettling', - 'Dolinger', - 'Flenniken', - 'Henrichsen', - 'Laduca', - 'Lashomb', - 'Leick', - 'Luchini', - 'Mcmanaman', - 'Minkoff', - 'Nobbe', - 'Oyster', - 'Quintela', - 'Robar', - 'Sakurai', - 'Solak', - 'Stolt', - 'Taddei', - 'Puopolo', - 'Schwarzkopf', - 'Stango', - 'Mcparland', - 'Schembri', - 'Standefer', - 'Dayan', - 'Sculley', - 'Bhuiyan', - 'Delauder', - 'Harrity', - 'Bree', - 'Haste', - 'Mcbay', - 'Garmany', - 'Maison', - 'Common', - 'Hanton', - 'Aigner', - 'Aliaga', - 'Boeve', - 'Cromie', - 'Demick', - 'Filipowicz', - 'Frickey', - 'Garrigus', - 'Heindl', - 'Hilmer', - 'Homeyer', - 'Lanterman', - 'Larch', - 'Masci', - 'Minami', - 'Palmiter', - 'Rufener', - 'Saal', - 'Sarmento', - 'Seewald', - 'Sestito', - 'Somarriba', - 'Sparano', - 'Vorce', - 'Wombles', - 'Zarr', - 'Antonson', - 'Bruzzese', - 'Chillemi', - 'Dannunzio', - 'Hogrefe', - 'Mastandrea', - 'Moynahan', - 'Wangerin', - 'Wedeking', - 'Ziobro', - 'Flegel', - 'Axsom', - 'Buzby', - 'Slowey', - 'Cuebas', - 'App', - 'Dar', - 'Robers', - 'Elting', - 'Demus', - 'Finkley', - 'Taborn', - 'Balogun', - 'Binstock', - 'Gebel', - 'Hinnenkamp', - 'Kosta', - 'Lamphear', - 'Linhares', - 'Luzader', - 'Mcconathy', - 'Motl', - 'Mroczkowski', - 'Reznicek', - 'Rieken', - 'Sadlowski', - 'Schlink', - 'Snuffer', - 'Tep', - 'Vaske', - 'Whisner', - 'Amesquita', - 'Demler', - 'Macdonell', - 'Rajala', - 'Sandate', - 'Kolk', - 'Bickerton', - 'Dugal', - 'Kirtland', - 'Neilan', - 'Doughman', - 'Crye', - 'Depena', - 'Quire', - 'Hafeez', - 'Rosse', - 'Devon', - 'Deboe', - 'Kitchings', - 'Blackett', - 'Acey', - 'Mcculler', - 'Obie', - 'Pleas', - 'Lurry', - 'Abid', - 'Bierlein', - 'Boisclair', - 'Cabanilla', - 'Celano', - 'Conrow', - 'Deeley', - 'Frankhouser', - 'Janowiak', - 'Jarchow', - 'Mcnicol', - 'Peixoto', - 'Pompeo', - 'Reitmeyer', - 'Scalera', - 'Schnorr', - 'Sideris', - 'Solesbee', - 'Stejskal', - 'Strole', - 'Tosto', - 'Wenke', - 'Dombek', - 'Gottschall', - 'Halbur', - 'Kuchler', - 'Kuyper', - 'Wruck', - 'Lorenc', - 'Search', - 'Chohan', - 'Monda', - 'Clowes', - 'Farson', - 'Rhoad', - 'Clavin', - 'Ramus', - 'Hayley', - 'Dolley', - 'Menton', - 'Dejarnett', - 'Challenger', - 'Branner', - 'Shed', - 'Dada', - 'Flewellen', - 'Volcy', - 'Allphin', - 'Barberena', - 'Bencivenga', - 'Bienkowski', - 'Bossi', - 'Corsini', - 'Dardis', - 'Falconi', - 'Fitzhenry', - 'Gaglione', - 'Handlin', - 'Kainz', - 'Lorge', - 'Nase', - 'Pavich', - 'Perelman', - 'Shanafelt', - 'Towsley', - 'Weill', - 'Zollars', - 'Appelt', - 'Cannizzo', - 'Carrubba', - 'Detar', - 'Dobrzynski', - 'Hashman', - 'Maassen', - 'Mccullagh', - 'Rettinger', - 'Roediger', - 'Rybolt', - 'Savoca', - 'Wortmann', - 'Boria', - 'Mairs', - 'Stream', - 'Larmore', - 'Sama', - 'Graden', - 'Hollinshead', - 'Mandy', - 'Gidney', - 'Demming', - 'Alexandra', - 'Caleb', - 'Abdullahi', - 'Cabal', - 'Dikeman', - 'Ellenbecker', - 'Fosnaugh', - 'Funck', - 'Heidorn', - 'Housden', - 'Ilic', - 'Illescas', - 'Kohlmann', - 'Lagman', - 'Larez', - 'Penafiel', - 'Pense', - 'Ragonese', - 'Reitan', - 'Shetterly', - 'Trapasso', - 'Zank', - 'Zecca', - 'Grisanti', - 'Hemker', - 'Mascolo', - 'Muhlenkamp', - 'Riemann', - 'Schindel', - 'Uncapher', - 'Zelman', - 'Koper', - 'Byrn', - 'Calzadilla', - 'Dilly', - 'Beiser', - 'Maller', - 'Bagg', - 'Winnick', - 'Sillman', - 'Bilton', - 'Esmond', - 'Sconyers', - 'Lemma', - 'Geralds', - 'Lazare', - 'Threats', - 'Accurso', - 'Boitnott', - 'Calcagni', - 'Chavera', - 'Corda', - 'Delisio', - 'Demont', - 'Eichel', - 'Faulds', - 'Ficek', - 'Gappa', - 'Graci', - 'Hammaker', - 'Heino', - 'Katcher', - 'Keslar', - 'Larsh', - 'Lashua', - 'Leising', - 'Magri', - 'Manbeck', - 'Mcwatters', - 'Mixer', - 'Moder', - 'Noori', - 'Pallo', - 'Pfingsten', - 'Plett', - 'Prehn', - 'Reyburn', - 'Savini', - 'Sebek', - 'Thang', - 'Lemberg', - 'Xiang', - 'Stiegler', - 'Groman', - 'Bowlen', - 'Grignon', - 'Morren', - 'Dini', - 'Mcaulay', - 'Ngu', - 'Bethell', - 'Warring', - 'Belyeu', - 'Ramcharan', - 'Mcjunkins', - 'Alms', - 'Ayub', - 'Brem', - 'Dresen', - 'Flori', - 'Geesaman', - 'Haugan', - 'Heppler', - 'Hermance', - 'Korinek', - 'Lograsso', - 'Madriaga', - 'Milbrath', - 'Radwan', - 'Riemersma', - 'Rivett', - 'Roggenbuck', - 'Stefanick', - 'Storment', - 'Ziegenfuss', - 'Blackhurst', - 'Daquila', - 'Maruska', - 'Rybka', - 'Schweer', - 'Tandon', - 'Hersman', - 'Galster', - 'Lemp', - 'Hantz', - 'Enderson', - 'Marchal', - 'Conly', - 'Bali', - 'Canaan', - 'Anstead', - 'Savary', - 'Andy', - 'Tisdell', - 'Livas', - 'Grinage', - 'Afanador', - 'Alviso', - 'Aracena', - 'Denio', - 'Dentremont', - 'Eldreth', - 'Gravois', - 'Huebsch', - 'Kalbfleisch', - 'Labree', - 'Mones', - 'Reitsma', - 'Schnapp', - 'Seek', - 'Shuping', - 'Tortorice', - 'Viscarra', - 'Wahlers', - 'Wittner', - 'Yake', - 'Zamani', - 'Carriveau', - 'Delage', - 'Gargan', - 'Goldade', - 'Golec', - 'Lapage', - 'Meinhart', - 'Mierzwa', - 'Riggenbach', - 'Schloesser', - 'Sedam', - 'Winkels', - 'Woldt', - 'Beckers', - 'Teach', - 'Feagan', - 'Booe', - 'Slates', - 'Bears', - 'Market', - 'Moone', - 'Verdun', - 'Ibe', - 'Jeudy', - 'Agudo', - 'Brisendine', - 'Casillo', - 'Chalupa', - 'Daversa', - 'Fissel', - 'Fleites', - 'Giarratano', - 'Glackin', - 'Granzow', - 'Hawver', - 'Hayashida', - 'Hovermale', - 'Huaman', - 'Jezek', - 'Lansdell', - 'Loughery', - 'Niedzielski', - 'Orellano', - 'Pebley', - 'Rojek', - 'Tomic', - 'Yellen', - 'Zerkle', - 'Boettner', - 'Decook', - 'Digilio', - 'Dinsdale', - 'Germer', - 'Kleve', - 'Marcinek', - 'Mendicino', - 'Pehl', - 'Revoir', - 'Osmun', - 'Bahner', - 'Shone', - 'Howald', - 'Kanode', - 'Amari', - 'Enix', - 'Levene', - 'Joffrion', - 'Lenis', - 'Carmicheal', - 'Njoku', - 'Coffel', - 'Ditter', - 'Grupp', - 'Kabel', - 'Kanzler', - 'Konop', - 'Lupi', - 'Mautz', - 'Mccahill', - 'Perella', - 'Perich', - 'Rion', - 'Ruvolo', - 'Torio', - 'Vipperman', - 'Bentivegna', - 'Formanek', - 'Smet', - 'Tarquinio', - 'Wesche', - 'Dearinger', - 'Makara', - 'Duba', - 'Iser', - 'Nicklow', - 'Wignall', - 'Wanger', - 'Goda', - 'Huckstep', - 'Basse', - 'Debruhl', - 'Hainey', - 'Damour', - 'Ebbs', - 'Armond', - 'Ewings', - 'Rease', - 'Okoye', - 'Arentz', - 'Baack', - 'Bellantoni', - 'Buckholz', - 'Cirigliano', - 'Colletta', - 'Dutka', - 'Everingham', - 'Gilardi', - 'Hudelson', - 'Klimczak', - 'Kneip', - 'Papaleo', - 'Peregrino', - 'Piechowski', - 'Prucha', - 'Ryburn', - 'Scholle', - 'Scholtes', - 'Socarras', - 'Wrightsman', - 'Yum', - 'Campau', - 'Dwinell', - 'Haupert', - 'Lotspeich', - 'Madar', - 'Casa', - 'Michals', - 'Rainier', - 'Tenpenny', - 'Lakeman', - 'Spadoni', - 'Cantrelle', - 'Mangal', - 'Chachere', - 'Swoope', - 'Carwell', - 'Voltaire', - 'Durrah', - 'Roulhac', - 'Aboytes', - 'Apuzzo', - 'Bielinski', - 'Bollenbacher', - 'Borjon', - 'Croak', - 'Dansie', - 'Espin', - 'Euceda', - 'Garone', - 'Garthwaite', - 'Hata', - 'Heu', - 'Hogenson', - 'Jahner', - 'Keesey', - 'Kotas', - 'Labrake', - 'Laitinen', - 'Laumann', - 'Miske', - 'Nickless', - 'Onishi', - 'Setty', - 'Shinnick', - 'Takayama', - 'Tassinari', - 'Tribe', - 'Bowdish', - 'Friesenhahn', - 'Hoffarth', - 'Wachowski', - 'Gudgel', - 'Gautney', - 'Matar', - 'Ellenberg', - 'Inghram', - 'Bevil', - 'Rasul', - 'Niblack', - 'Perkin', - 'Goring', - 'Potier', - 'Bachrach', - 'Bozza', - 'Budz', - 'Devens', - 'Ditzel', - 'Drahos', - 'Ducat', - 'Fahrner', - 'Friedline', - 'Geurin', - 'Goodenow', - 'Greenfeld', - 'Grunow', - 'Ingber', - 'Kashani', - 'Kochman', - 'Kozub', - 'Kukuk', - 'Leppo', - 'Liew', - 'Metheney', - 'Molony', - 'Montemurro', - 'Neiss', - 'Postlethwait', - 'Quaglia', - 'Ruszkowski', - 'Shertzer', - 'Titone', - 'Waldmann', - 'Wenninger', - 'Wheeland', - 'Zorich', - 'Mervine', - 'Weatherholtz', - 'Brotman', - 'Malenfant', - 'Nong', - 'Rogness', - 'Dibert', - 'Gallahan', - 'Gange', - 'Chilcott', - 'Axt', - 'Wiler', - 'Jacot', - 'Ory', - 'Abdon', - 'Fenter', - 'Bryars', - 'Ramroop', - 'Jacox', - 'Mainer', - 'Figures', - 'Alig', - 'Bires', - 'Cassata', - 'Cholewa', - 'Dispenza', - 'Eckmann', - 'Gauer', - 'Gloor', - 'Hattori', - 'Huster', - 'Kopplin', - 'Krugman', - 'Lancon', - 'Ledin', - 'Limb', - 'Marentes', - 'Minges', - 'Monacelli', - 'Monteon', - 'Naslund', - 'Nitsche', - 'Rapozo', - 'Rimkus', - 'Schwerdtfeger', - 'Vandenbos', - 'Balandran', - 'Biehn', - 'Briody', - 'Hackmann', - 'Kalka', - 'Keranen', - 'Lortie', - 'Mannella', - 'Shiffler', - 'Stempel', - 'Takaki', - 'Tomassi', - 'Reidel', - 'Ciprian', - 'Penza', - 'Vite', - 'Cormany', - 'Derousse', - 'Beus', - 'Shurley', - 'Courtwright', - 'Donna', - 'Karney', - 'Keats', - 'Harron', - 'Stjacques', - 'Regester', - 'Stoke', - 'Garron', - 'Sulaiman', - 'Fusilier', - 'Hence', - 'Altidor', - 'Rollerson', - 'Anfinson', - 'Badua', - 'Balmaceda', - 'Bringman', - 'Bystrom', - 'Goffinet', - 'Guindon', - 'Hilling', - 'Makepeace', - 'Mooradian', - 'Muzquiz', - 'Newcom', - 'Perrella', - 'Postlewait', - 'Raetz', - 'Riveros', - 'Saephanh', - 'Scharer', - 'Sheeder', - 'Sitar', - 'Umlauf', - 'Voegeli', - 'Yurkovich', - 'Chaudhari', - 'Chianese', - 'Clonch', - 'Gasparini', - 'Giambalvo', - 'Gindlesperger', - 'Rauen', - 'Riegert', - 'Collingsworth', - 'Stief', - 'Zeisler', - 'Kirsten', - 'Vessey', - 'Scherman', - 'Ledwith', - 'Goudie', - 'Ayre', - 'Salome', - 'Knoles', - 'Munyan', - 'Corbet', - 'Hagewood', - 'Humphry', - 'Bernardez', - 'Drummonds', - 'Lide', - 'Veals', - 'Andolina', - 'Anzaldo', - 'Aufiero', - 'Bakshi', - 'Berdan', - 'Birrell', - 'Colcord', - 'Dutro', - 'Eisenhour', - 'Falgoust', - 'Foertsch', - 'Forlenza', - 'Harroun', - 'Kurtenbach', - 'Livesey', - 'Luka', - 'Manseau', - 'Mcdaid', - 'Miska', - 'Overley', - 'Panzica', - 'Reish', - 'Riolo', - 'Roseland', - 'Shenberger', - 'Splinter', - 'Strupp', - 'Sturgell', - 'Swatzell', - 'Totherow', - 'Villarroel', - 'Wenig', - 'Zimny', - 'Brunetto', - 'Hiester', - 'Kasinger', - 'Laverde', - 'Mihalek', - 'Aquila', - 'Moreton', - 'Collums', - 'Ergle', - 'Keziah', - 'Bourbon', - 'Scaff', - 'Leamy', - 'Sublette', - 'Winkley', - 'Arlington', - 'Cuffe', - 'Guity', - 'Mcmickle', - 'Summerour', - 'Baggerly', - 'Biltz', - 'Calma', - 'Dephillips', - 'Graffam', - 'Holsopple', - 'Izumi', - 'Joerger', - 'Kesselman', - 'Kingdon', - 'Kinkel', - 'Knezevich', - 'Liebler', - 'Maceda', - 'Qualey', - 'Robeck', - 'Sciarrino', - 'Sooy', - 'Stahly', - 'Stieglitz', - 'Strike', - 'Unwin', - 'Urizar', - 'Volmer', - 'Winterstein', - 'Aronov', - 'Czyz', - 'Marrazzo', - 'Seagren', - 'Wiegmann', - 'Yearsley', - 'Brommer', - 'Sterne', - 'Armel', - 'Kryger', - 'Barten', - 'Bodwell', - 'Hollett', - 'Sharron', - 'Scobey', - 'Croson', - 'Gainor', - 'Axel', - 'Basore', - 'Bengel', - 'Chiem', - 'Desanctis', - 'Gillooly', - 'Groulx', - 'Hulings', - 'Koenigsberg', - 'Kuchinski', - 'Pagaduan', - 'Pataky', - 'Rietz', - 'Robello', - 'Schuchman', - 'Shek', - 'Brattain', - 'Gottwald', - 'Klapperich', - 'Kosky', - 'Ruegg', - 'Smid', - 'Taillon', - 'Klonowski', - 'Attar', - 'Mansoor', - 'Daus', - 'Falla', - 'Guyot', - 'Hasten', - 'Mcdowall', - 'Tugwell', - 'Remo', - 'Dishmon', - 'Leggette', - 'Sudler', - 'Prescod', - 'Benvenuti', - 'Bittenbender', - 'Burkland', - 'Crehan', - 'Donjuan', - 'Ewbank', - 'Fluegel', - 'Freiman', - 'Fuelling', - 'Grabner', - 'Gras', - 'Horr', - 'Jurich', - 'Kentner', - 'Laski', - 'Minero', - 'Olivos', - 'Porro', - 'Purves', - 'Smethers', - 'Spallone', - 'Stangler', - 'Gebbia', - 'Fowers', - 'Gaster', - 'Fero', - 'Gamon', - 'Wiss', - 'Strassner', - 'Cott', - 'Houp', - 'Fidel', - 'Parisien', - 'Daisy', - 'Calais', - 'Boers', - 'Bolle', - 'Caccavale', - 'Colantonio', - 'Columbo', - 'Goswami', - 'Hakanson', - 'Jelley', - 'Kahlon', - 'Lopezgarcia', - 'Marier', - 'Mesko', - 'Monter', - 'Mowell', - 'Piech', - 'Shortell', - 'Slechta', - 'Starman', - 'Tiemeyer', - 'Troutner', - 'Vandeveer', - 'Voorheis', - 'Woodhams', - 'Helget', - 'Kalk', - 'Kiester', - 'Lagace', - 'Obst', - 'Parrack', - 'Rennert', - 'Rodeheaver', - 'Schuermann', - 'Warmuth', - 'Wisnieski', - 'Yahnke', - 'Yurek', - 'Faver', - 'Belleau', - 'Moan', - 'Remsen', - 'Bonano', - 'Genson', - 'Genis', - 'Risen', - 'Franze', - 'Lauderback', - 'Ferns', - 'Cooler', - 'Mcwilliam', - 'Micheals', - 'Gotch', - 'Teat', - 'Bacus', - 'Banik', - 'Bernhart', - 'Doell', - 'Francese', - 'Gasbarro', - 'Gietzen', - 'Gossen', - 'Haberle', - 'Havlicek', - 'Henion', - 'Kevorkian', - 'Liem', - 'Loor', - 'Moede', - 'Mostafa', - 'Mottern', - 'Naito', - 'Nofsinger', - 'Omelia', - 'Pirog', - 'Pirone', - 'Plucinski', - 'Raghavan', - 'Robaina', - 'Seliga', - 'Stade', - 'Steinhilber', - 'Wedin', - 'Wieman', - 'Zemaitis', - 'Creps', - 'Gumina', - 'Inglett', - 'Jhaveri', - 'Kolasinski', - 'Salvesen', - 'Vallely', - 'Weseman', - 'Zysk', - 'Gourlay', - 'Zanger', - 'Delorey', - 'Sneider', - 'Tacey', - 'Valls', - 'Ossman', - 'Watton', - 'Breau', - 'Burell', - 'Villard', - 'Janice', - 'Honor', - 'Arterberry', - 'Sow', - 'Cucchiara', - 'Diemert', - 'Fluty', - 'Guadiana', - 'Ionescu', - 'Kearley', - 'Krzyzanowski', - 'Lavecchia', - 'Lundmark', - 'Melichar', - 'Mulkern', - 'Odonohue', - 'Payment', - 'Pinnow', - 'Popoff', - 'Prus', - 'Reinoehl', - 'Scarlata', - 'Schamp', - 'Schowalter', - 'Scinto', - 'Semmler', - 'Sheline', - 'Sigg', - 'Trauger', - 'Bleiler', - 'Carrino', - 'Hauth', - 'Kunsman', - 'Reicks', - 'Rotenberg', - 'Soltesz', - 'Wascher', - 'Mattina', - 'Tamblyn', - 'Bellanca', - 'Heward', - 'Seif', - 'Agha', - 'Gosling', - 'Defreese', - 'Lyvers', - 'Robley', - 'Hadi', - 'Ledyard', - 'Mitchner', - 'Berrien', - 'Clinkscale', - 'Affeldt', - 'Aung', - 'Azpeitia', - 'Boehnlein', - 'Cavan', - 'Ekdahl', - 'Ellyson', - 'Fahl', - 'Herrig', - 'Hulick', - 'Ihrke', - 'Kaeding', - 'Keagy', - 'Mehlman', - 'Minniear', - 'Paniccia', - 'Pleva', - 'Prestidge', - 'Pulford', - 'Quattrone', - 'Riquelme', - 'Rombach', - 'Sarwar', - 'Sivertsen', - 'Sprang', - 'Wardrop', - 'Anglemyer', - 'Bobek', - 'Scronce', - 'Snethen', - 'Stancliff', - 'Booton', - 'Pinal', - 'Weihe', - 'Bria', - 'Lopresto', - 'Awbrey', - 'Fogal', - 'Ning', - 'Hydrick', - 'Lumb', - 'Pommier', - 'Hendy', - 'Armon', - 'Spenser', - 'Beachem', - 'Decrescenzo', - 'Heaphy', - 'Kalata', - 'Kastl', - 'Kosel', - 'Kunert', - 'Laatsch', - 'Lanpher', - 'Malinski', - 'Mazzie', - 'Neuendorf', - 'Salloum', - 'Tays', - 'Yackel', - 'Calvario', - 'Feese', - 'Feldner', - 'Kness', - 'Kozuch', - 'Magat', - 'Pantalone', - 'Rilling', - 'Teska', - 'Fantauzzi', - 'Wartman', - 'Stansbery', - 'Sox', - 'Napp', - 'Schauf', - 'Cumings', - 'Coxon', - 'Labor', - 'Brash', - 'Egleston', - 'Quintin', - 'Oki', - 'Date', - 'Tuckett', - 'Devaux', - 'Hewins', - 'Abdelrahman', - 'Schumpert', - 'Dort', - 'Limbrick', - 'Linwood', - 'Delaine', - 'Liverpool', - 'Azimi', - 'Biever', - 'Craigo', - 'Eschete', - 'Fortini', - 'Francom', - 'Giacomini', - 'Girdler', - 'Halasz', - 'Hillin', - 'Inglese', - 'Isaza', - 'Lewman', - 'Ploetz', - 'Rampley', - 'Reifsteck', - 'Rossano', - 'Sanagustin', - 'Sotak', - 'Spainhower', - 'Stecklein', - 'Stolberg', - 'Teschner', - 'Thew', - 'Blaszczyk', - 'Caradonna', - 'Cillo', - 'Diluzio', - 'Hagemeyer', - 'Holstrom', - 'Jewkes', - 'Mcquaide', - 'Osterhaus', - 'Twaddle', - 'Wenck', - 'Yakel', - 'Zeiner', - 'Zulauf', - 'Mirabelli', - 'Gerold', - 'Sherr', - 'Ogando', - 'Achilles', - 'Woodlee', - 'Underdown', - 'Peirson', - 'Abdelaziz', - 'Bently', - 'Junes', - 'Furtick', - 'Muckle', - 'Freemon', - 'Jamar', - 'Scriber', - 'Michaux', - 'Cheatum', - 'Hollings', - 'Telfair', - 'Amadeo', - 'Bargar', - 'Berchtold', - 'Boomhower', - 'Camba', - 'Compo', - 'Dellavecchia', - 'Doring', - 'Doyel', - 'Geck', - 'Giovannini', - 'Herda', - 'Kopko', - 'Kuns', - 'Maciag', - 'Neenan', - 'Neglia', - 'Nienhuis', - 'Niznik', - 'Pieczynski', - 'Quintos', - 'Quirin', - 'Ravi', - 'Teaster', - 'Tipsword', - 'Troiani', - 'Consuegra', - 'Damaso', - 'Garavaglia', - 'Pischke', - 'Prowse', - 'Rumore', - 'Simcoe', - 'Slentz', - 'Sposito', - 'Sulser', - 'Weichel', - 'Sandobal', - 'Siver', - 'Vickerman', - 'Sham', - 'Gutridge', - 'Gracy', - 'Weatherington', - 'Benett', - 'Nottage', - 'Myricks', - 'Tukes', - 'Alcaide', - 'Curatolo', - 'Dalziel', - 'Fandrich', - 'Fisette', - 'Gianino', - 'Grether', - 'Hari', - 'Ichikawa', - 'Lantzy', - 'Monteforte', - 'Moskovitz', - 'Porritt', - 'Raz', - 'Rodenbeck', - 'Ryczek', - 'Strehle', - 'Vanduzer', - 'Voge', - 'Wiker', - 'Yanik', - 'Zangari', - 'Cahue', - 'Dellapenna', - 'Gohr', - 'Gurka', - 'Imburgia', - 'Langenberg', - 'Kivi', - 'Pikul', - 'Sexson', - 'Sharrer', - 'Aramburo', - 'Kadar', - 'Casasola', - 'Nina', - 'Borras', - 'Toledano', - 'Wykle', - 'Naeem', - 'Bailer', - 'Lalla', - 'Booty', - 'Turenne', - 'Merrit', - 'Duffus', - 'Hemmingway', - 'Asare', - 'Ahlborn', - 'Arroyave', - 'Brandenberger', - 'Carolus', - 'Coonan', - 'Dacunha', - 'Dost', - 'Filter', - 'Freudenberg', - 'Grabski', - 'Hengel', - 'Holohan', - 'Kohne', - 'Kollmann', - 'Levick', - 'Lupinacci', - 'Meservey', - 'Reisdorf', - 'Rodabaugh', - 'Shimon', - 'Soth', - 'Spall', - 'Tener', - 'Thier', - 'Welshans', - 'Chermak', - 'Ciolino', - 'Frantzen', - 'Grassman', - 'Okuda', - 'Passantino', - 'Schellinger', - 'Sneath', - 'Bolla', - 'Bobe', - 'Maves', - 'Matey', - 'Shafi', - 'Rothchild', - 'Ker', - 'Verrette', - 'Thorington', - 'Lathers', - 'Merriwether', - 'Bendall', - 'Bercier', - 'Botz', - 'Claybaugh', - 'Creson', - 'Dilone', - 'Gabehart', - 'Gencarelli', - 'Ghormley', - 'Hacking', - 'Haefele', - 'Haros', - 'Holderby', - 'Krotzer', - 'Nanda', - 'Oltmanns', - 'Orndoff', - 'Poniatowski', - 'Rosol', - 'Sheneman', - 'Shifrin', - 'Smay', - 'Swickard', - 'Thayne', - 'Tripathi', - 'Vonbehren', - 'Pummill', - 'Schnitker', - 'Steines', - 'Beechler', - 'Faron', - 'Villari', - 'Spickard', - 'Levings', - 'Polack', - 'Standre', - 'Castel', - 'Louise', - 'Janey', - 'Lindor', - 'Bulthuis', - 'Cantrall', - 'Cisnero', - 'Dangel', - 'Deborde', - 'Decena', - 'Grandon', - 'Gritz', - 'Heberlein', - 'Kestenbaum', - 'Kubitz', - 'Luers', - 'Naiman', - 'Ramaswamy', - 'Sek', - 'Slauson', - 'Walsworth', - 'Biehler', - 'Capano', - 'Casstevens', - 'Forgette', - 'Furnas', - 'Gilkison', - 'Janoski', - 'Jerde', - 'Mcclimans', - 'Rohlf', - 'Vliet', - 'Heeney', - 'Zapanta', - 'Lighthall', - 'Shallow', - 'Neils', - 'Raikes', - 'Clarkston', - 'Claud', - 'Guilbeaux', - 'Pennie', - 'Arizola', - 'Aud', - 'Checketts', - 'Corvera', - 'Easterbrook', - 'Gamm', - 'Grassel', - 'Guarin', - 'Hanf', - 'Hitsman', - 'Lackman', - 'Lubitz', - 'Lupian', - 'Olexa', - 'Omori', - 'Oscarson', - 'Picasso', - 'Plewa', - 'Schmahl', - 'Stolze', - 'Todisco', - 'Zarzycki', - 'Baluyot', - 'Cerrito', - 'Elenbaas', - 'Gavidia', - 'Heisner', - 'Karpowicz', - 'Neidhardt', - 'Silkwood', - 'Taras', - 'Dobias', - 'Widen', - 'Blandino', - 'Fanguy', - 'Probus', - 'Guilbert', - 'Shadowens', - 'Keepers', - 'Bruin', - 'Hitson', - 'Crymes', - 'Roston', - 'Beaubrun', - 'Arrambide', - 'Betti', - 'Brockhaus', - 'Bumanglag', - 'Cabreja', - 'Dicenso', - 'Hartlaub', - 'Hertlein', - 'Lapenna', - 'Rathje', - 'Rotert', - 'Salzberg', - 'Siniard', - 'Tomsic', - 'Wondra', - 'Zenger', - 'Norrod', - 'Opalka', - 'Osment', - 'Zhan', - 'Lemcke', - 'Meranda', - 'Joles', - 'Labay', - 'Monserrate', - 'Grime', - 'Martha', - 'Coltrain', - 'Vardaman', - 'Wragg', - 'Frater', - 'Offer', - 'Elcock', - 'Auble', - 'Bistline', - 'Chorney', - 'Colgate', - 'Dadamo', - 'Deol', - 'Discher', - 'Ertz', - 'Fletchall', - 'Galletti', - 'Geffre', - 'Grall', - 'Hoos', - 'Iezzi', - 'Kawecki', - 'Madamba', - 'Margolies', - 'Mccreedy', - 'Okimoto', - 'Oum', - 'Pangan', - 'Pasternack', - 'Plazola', - 'Prochazka', - 'Tewes', - 'Tramontana', - 'Yauch', - 'Zarling', - 'Zemanek', - 'Altshuler', - 'Bartkowski', - 'Cuoco', - 'Garcialopez', - 'Kauzlarich', - 'Shishido', - 'Zaun', - 'Hallin', - 'Starliper', - 'Belflower', - 'Kneece', - 'Genet', - 'Palmero', - 'Willmott', - 'Riek', - 'Belger', - 'Abbitt', - 'Statum', - 'Jacque', - 'Chisley', - 'Habersham', - 'Berardinelli', - 'Bodle', - 'Deshaw', - 'Ingalsbe', - 'Kirchgessner', - 'Kuna', - 'Pellow', - 'Pickler', - 'Pistole', - 'Rosenstock', - 'Salceda', - 'Sawatzky', - 'Schappell', - 'Scholer', - 'Shellabarger', - 'Spader', - 'Swadley', - 'Travelstead', - 'Varin', - 'Villwock', - 'Wiemers', - 'Bedoy', - 'Borowiak', - 'Celio', - 'Dornfeld', - 'Juhnke', - 'Livernois', - 'Sakaguchi', - 'Sandall', - 'Sivertson', - 'Whitcraft', - 'Anda', - 'Aprile', - 'Kritz', - 'Speier', - 'Karman', - 'Kise', - 'Madia', - 'Bodo', - 'Madole', - 'Harl', - 'Gach', - 'Stalls', - 'Holme', - 'Lomba', - 'Tutton', - 'Windon', - 'Bines', - 'Benoist', - 'Cirrincione', - 'Coday', - 'Delrosso', - 'Dlouhy', - 'Domenick', - 'Edelmann', - 'Goos', - 'Hamling', - 'Huda', - 'Hutzel', - 'Lanasa', - 'Loudenslager', - 'Lueras', - 'Magnussen', - 'Mcferran', - 'Nowinski', - 'Pikula', - 'Precht', - 'Quilici', - 'Robling', - 'Rusche', - 'Schettino', - 'Scibelli', - 'Soderman', - 'Spirito', - 'Teaford', - 'Updegrove', - 'Weygandt', - 'Zervos', - 'Brunker', - 'Demuro', - 'Eckenrod', - 'Emley', - 'Franek', - 'Frankenberger', - 'Longbrake', - 'Magallanez', - 'Stofko', - 'Zenz', - 'Galik', - 'Crevier', - 'Fina', - 'Harari', - 'Dudney', - 'Inga', - 'Sowles', - 'Folker', - 'Cressy', - 'Eckerson', - 'Gerringer', - 'Capito', - 'Huxtable', - 'Arcement', - 'Lansdown', - 'Amara', - 'Brazill', - 'Flye', - 'Currington', - 'Buffin', - 'Desta', - 'Cheuvront', - 'Fuoco', - 'Gerbino', - 'Hilyer', - 'Hogsed', - 'Kubis', - 'Lautner', - 'Loeber', - 'Meyn', - 'Mortell', - 'Nunziato', - 'Opdahl', - 'Panebianco', - 'Reffner', - 'Repsher', - 'Riccobono', - 'Wik', - 'Circle', - 'Hovde', - 'Keaveney', - 'Landsberg', - 'Pesavento', - 'Bedel', - 'Glas', - 'Thurn', - 'Jaffer', - 'Dantin', - 'Risi', - 'Many', - 'Egler', - 'Craghead', - 'Ann', - 'Turnbo', - 'Crumby', - 'Faciane', - 'Brummell', - 'Bujak', - 'Chaddock', - 'Cullop', - 'Eberling', - 'Ennen', - 'Frum', - 'Gassert', - 'Grothaus', - 'Hucke', - 'Lanphere', - 'Lozon', - 'Macadam', - 'Mezo', - 'Peretti', - 'Perlin', - 'Prestwich', - 'Redmann', - 'Ringley', - 'Rivenburg', - 'Sandow', - 'Spreitzer', - 'Stachnik', - 'Szczesniak', - 'Tworek', - 'Wogan', - 'Zygmunt', - 'Austad', - 'Chiappone', - 'Gelineau', - 'Lannom', - 'Livezey', - 'Monrroy', - 'Norem', - 'Oetting', - 'Ostberg', - 'Takeshita', - 'Gorsky', - 'Allcorn', - 'Pemble', - 'Josselyn', - 'Lanzo', - 'Hoare', - 'Ticer', - 'Netterville', - 'Lawes', - 'Lenton', - 'Garraway', - 'Cyprian', - 'Alferez', - 'Allocco', - 'Aslanian', - 'Brenna', - 'Carachure', - 'Devoss', - 'Dubas', - 'Garrabrant', - 'Gerloff', - 'Gerritsen', - 'Hobaugh', - 'Jasek', - 'Kulis', - 'Lenehan', - 'Lodes', - 'Mandich', - 'Manter', - 'Mcfatridge', - 'Mikolajczak', - 'Netz', - 'Perrelli', - 'Ribar', - 'Sekerak', - 'Shingledecker', - 'Talamante', - 'Taverna', - 'Thoresen', - 'Throneberry', - 'Vanacore', - 'Vieau', - 'Wermuth', - 'Zeidan', - 'Counihan', - 'Dircks', - 'Markovitz', - 'Panas', - 'Steffel', - 'Bergstedt', - 'Mohar', - 'Sonne', - 'Mitsch', - 'Aceituno', - 'Loker', - 'Treen', - 'Prunier', - 'Amberson', - 'Allington', - 'Artley', - 'Caffery', - 'Rhoney', - 'Nimmer', - 'Ledwell', - 'Barkus', - 'Fralin', - 'Locks', - 'Azzara', - 'Bartosik', - 'Bertelson', - 'Birman', - 'Brogna', - 'Cachola', - 'Dennington', - 'Enea', - 'Gallogly', - 'Grafe', - 'Jankowiak', - 'Kaas', - 'Karis', - 'Kostick', - 'Lentsch', - 'Locken', - 'Mathys', - 'Maxcy', - 'Monegro', - 'Olano', - 'Paske', - 'Raible', - 'Rowbotham', - 'Vanderbeck', - 'Vanosdol', - 'Wenzler', - 'Yglesias', - 'Eisenberger', - 'Grzelak', - 'Hamidi', - 'Hottel', - 'Markoff', - 'Santagata', - 'Seefeld', - 'Stachowicz', - 'Stiehl', - 'Staver', - 'Raad', - 'Sarber', - 'Rudge', - 'Connelley', - 'Danser', - 'Chumney', - 'Hind', - 'Desper', - 'Fergusson', - 'Ringwood', - 'Byles', - 'Alyea', - 'Benzinger', - 'Betzer', - 'Brix', - 'Chiarella', - 'Chiriboga', - 'Cicala', - 'Cohick', - 'Creeden', - 'Delligatti', - 'Garbacz', - 'Grossberg', - 'Habecker', - 'Inscoe', - 'Irias', - 'Karlsen', - 'Kilts', - 'Koetter', - 'Laflin', - 'Laperle', - 'Mizner', - 'Navia', - 'Nolet', - 'Procaccini', - 'Pula', - 'Scarfo', - 'Schmelz', - 'Taaffe', - 'Troth', - 'Vanlaningham', - 'Vosberg', - 'Whitchurch', - 'Benak', - 'Hanawalt', - 'Lindman', - 'Moschetti', - 'Rozas', - 'Sporleder', - 'Stopka', - 'Turowski', - 'Wahlgren', - 'Youngstrom', - 'Jabbour', - 'Myerson', - 'Perlow', - 'Cannone', - 'Kil', - 'Stiverson', - 'Cedar', - 'Sweeden', - 'Pourciau', - 'Salina', - 'Delmoral', - 'Balle', - 'Cohea', - 'Bute', - 'Rayne', - 'Cawthorn', - 'Conely', - 'Cartlidge', - 'Powel', - 'Nwankwo', - 'Centrella', - 'Delaura', - 'Deprey', - 'Dulude', - 'Garrod', - 'Gassen', - 'Greenberger', - 'Huneke', - 'Kunzman', - 'Laakso', - 'Oppermann', - 'Radich', - 'Rozen', - 'Schoffstall', - 'Swetnam', - 'Vitrano', - 'Wolber', - 'Amirault', - 'Przybysz', - 'Trzeciak', - 'Fontan', - 'Mathie', - 'Roswell', - 'Mcquitty', - 'Kye', - 'Lucious', - 'Chilcutt', - 'Difazio', - 'Diperna', - 'Gashi', - 'Goodstein', - 'Gruetzmacher', - 'Imus', - 'Krumholz', - 'Lanzetta', - 'Leaming', - 'Lehigh', - 'Lobosco', - 'Pardoe', - 'Pellicano', - 'Purtee', - 'Ramanathan', - 'Roszkowski', - 'Satre', - 'Steinborn', - 'Stinebaugh', - 'Thiesen', - 'Tierno', - 'Wrisley', - 'Yazdani', - 'Zwilling', - 'Berntson', - 'Gisclair', - 'Golliher', - 'Neumeier', - 'Stohl', - 'Swartley', - 'Wannemacher', - 'Wickard', - 'Duford', - 'Rosello', - 'Merfeld', - 'Arko', - 'Cotney', - 'Hai', - 'Milley', - 'Figueira', - 'Willes', - 'Helmes', - 'Abair', - 'Life', - 'Izard', - 'Duskin', - 'Moland', - 'Primer', - 'Hagos', - 'Anyanwu', - 'Balasubramanian', - 'Bluth', - 'Calk', - 'Chrzan', - 'Constanza', - 'Durney', - 'Ekholm', - 'Erny', - 'Ferrando', - 'Froberg', - 'Gonyer', - 'Guagliardo', - 'Hreha', - 'Kobza', - 'Kuruvilla', - 'Preziosi', - 'Ricciuti', - 'Rosiles', - 'Schiesser', - 'Schmoyer', - 'Slota', - 'Szeliga', - 'Verba', - 'Widjaja', - 'Wrzesinski', - 'Zufall', - 'Bumstead', - 'Dohrman', - 'Dommer', - 'Eisenmenger', - 'Glogowski', - 'Kaufhold', - 'Kuiken', - 'Ricklefs', - 'Sinyard', - 'Steenbergen', - 'Schweppe', - 'Chatwin', - 'Dingee', - 'Mittleman', - 'Menear', - 'Milot', - 'Riccardo', - 'Clemenson', - 'Mellow', - 'Gabe', - 'Rolla', - 'Vander', - 'Casselberry', - 'Hubbart', - 'Colvert', - 'Billingsly', - 'Burgman', - 'Cattaneo', - 'Duthie', - 'Hedtke', - 'Heidler', - 'Hertenstein', - 'Hudler', - 'Hustead', - 'Ibsen', - 'Krutsinger', - 'Mauceri', - 'Mersereau', - 'Morad', - 'Rentfro', - 'Rumrill', - 'Shedlock', - 'Sindt', - 'Soulier', - 'Squitieri', - 'Trageser', - 'Vatter', - 'Vollman', - 'Wagster', - 'Caselli', - 'Dibacco', - 'Gick', - 'Kachel', - 'Lukaszewski', - 'Minniti', - 'Neeld', - 'Zarrella', - 'Hedglin', - 'Jahan', - 'Nathe', - 'Starn', - 'Kana', - 'Bernet', - 'Rossa', - 'Barro', - 'Smylie', - 'Bowlds', - 'Mccalley', - 'Oniel', - 'Thaggard', - 'Cayson', - 'Sinegal', - 'Bergfeld', - 'Bickmore', - 'Boch', - 'Bushway', - 'Carneiro', - 'Cerio', - 'Colbath', - 'Eade', - 'Eavenson', - 'Epping', - 'Fredricksen', - 'Gramer', - 'Hassman', - 'Hinderer', - 'Kantrowitz', - 'Kaplowitz', - 'Kelner', - 'Lecates', - 'Lothrop', - 'Lupica', - 'Masterman', - 'Meeler', - 'Neumiller', - 'Newbauer', - 'Noyce', - 'Nulty', - 'Shanker', - 'Taheri', - 'Timblin', - 'Vitucci', - 'Zappone', - 'Femia', - 'Hejl', - 'Helmbrecht', - 'Kiesow', - 'Maschino', - 'Brougher', - 'Koff', - 'Reffett', - 'Langhoff', - 'Milman', - 'Sidener', - 'Levie', - 'Chaudry', - 'Rattan', - 'Finkler', - 'Bollen', - 'Booz', - 'Shipps', - 'Theall', - 'Scallion', - 'Furlough', - 'Landfair', - 'Albuquerque', - 'Beckstrand', - 'Colglazier', - 'Darcey', - 'Fahr', - 'Gabert', - 'Gertner', - 'Gettler', - 'Giovannetti', - 'Hulvey', - 'Juenger', - 'Kantola', - 'Kemmerling', - 'Leclere', - 'Liberati', - 'Lopezlopez', - 'Minerva', - 'Redlich', - 'Shoun', - 'Sickinger', - 'Vivier', - 'Yerdon', - 'Ziomek', - 'Dechert', - 'Delbene', - 'Galassi', - 'Rawdon', - 'Wesenberg', - 'Laurino', - 'Grosjean', - 'Levay', - 'Zike', - 'Stukey', - 'Loft', - 'Kool', - 'Hatchel', - 'Mainville', - 'Salis', - 'Greenslade', - 'Mantey', - 'Spratlin', - 'Fayette', - 'Marner', - 'Rolan', - 'Pain', - 'Colquhoun', - 'Brave', - 'Locust', - 'Sconiers', - 'Bahler', - 'Barrero', - 'Bartha', - 'Basnett', - 'Berghoff', - 'Bomgardner', - 'Brindisi', - 'Campoli', - 'Carawan', - 'Chhim', - 'Corro', - 'Crissey', - 'Deterding', - 'Dileonardo', - 'Dowis', - 'Hagemeier', - 'Heichel', - 'Kipfer', - 'Lemberger', - 'Maestri', - 'Mauri', - 'Nakatani', - 'Notestine', - 'Polakowski', - 'Schlobohm', - 'Segel', - 'Socci', - 'Stieg', - 'Thorstad', - 'Trausch', - 'Whitledge', - 'Wilkowski', - 'Barkdull', - 'Dubeau', - 'Ellingsen', - 'Hayduk', - 'Lauter', - 'Lizak', - 'Machamer', - 'Makarewicz', - 'Shuffield', - 'Heiserman', - 'Sandeen', - 'Plough', - 'Stemler', - 'Bossler', - 'Catalina', - 'Betley', - 'Bonello', - 'Pryde', - 'Nickey', - 'Schanck', - 'Single', - 'Mulberry', - 'Point', - 'Danson', - 'Flemmings', - 'Behnken', - 'Catone', - 'Cummiskey', - 'Currens', - 'Gersch', - 'Kitamura', - 'Meddaugh', - 'Montagne', - 'Nouri', - 'Olejnik', - 'Pintar', - 'Placke', - 'Quinter', - 'Rakers', - 'Stuteville', - 'Sullo', - 'Voelz', - 'Barabas', - 'Estock', - 'Hultberg', - 'Savitz', - 'Treml', - 'Vigneault', - 'Jezierski', - 'Zayed', - 'Dewell', - 'Yanko', - 'Moulin', - 'Whalin', - 'Elsworth', - 'Summit', - 'Esty', - 'Mahadeo', - 'Shular', - 'Amedee', - 'Bellerose', - 'Bendixen', - 'Briski', - 'Buysse', - 'Desa', - 'Dobry', - 'Dufner', - 'Fetterly', - 'Finau', - 'Gaudioso', - 'Giangrande', - 'Heuring', - 'Kitchel', - 'Latulippe', - 'Pombo', - 'Vancott', - 'Woofter', - 'Bojarski', - 'Cretella', - 'Heumann', - 'Limpert', - 'Mcneff', - 'Pluff', - 'Tumlinson', - 'Widick', - 'Yeargan', - 'Hanft', - 'Novinger', - 'Ruddle', - 'Wrye', - 'Felde', - 'Basic', - 'Babington', - 'Karson', - 'Forgy', - 'Rendall', - 'Icard', - 'Jann', - 'Ady', - 'Therrell', - 'Sroufe', - 'Maden', - 'Ganus', - 'Preddy', - 'Marberry', - 'Fonder', - 'Latty', - 'Leatherbury', - 'Mentor', - 'Brissett', - 'Mcglory', - 'Readus', - 'Akau', - 'Bellone', - 'Berendt', - 'Bok', - 'Broten', - 'Colosi', - 'Corio', - 'Gilani', - 'Huffmaster', - 'Kieler', - 'Leonor', - 'Lips', - 'Madron', - 'Missey', - 'Nabozny', - 'Panning', - 'Reinwald', - 'Ridener', - 'Silvio', - 'Soder', - 'Spieler', - 'Vaeth', - 'Vincenti', - 'Walczyk', - 'Washko', - 'Wiater', - 'Wilen', - 'Windish', - 'Consalvo', - 'Fioravanti', - 'Hinners', - 'Paduano', - 'Ranum', - 'Parlato', - 'Dweck', - 'Matern', - 'Cryder', - 'Rubert', - 'Furgason', - 'Virella', - 'Boylen', - 'Devenport', - 'Perrodin', - 'Hollingshed', - 'Pennix', - 'Bogdanski', - 'Carretero', - 'Cubillos', - 'Deponte', - 'Forrey', - 'Gatchalian', - 'Geisen', - 'Gombos', - 'Hartlage', - 'Huddy', - 'Kou', - 'Matsko', - 'Muffley', - 'Niazi', - 'Nodarse', - 'Pawelek', - 'Pyper', - 'Stahnke', - 'Udall', - 'Baldyga', - 'Chrostowski', - 'Frable', - 'Handshoe', - 'Helderman', - 'Lambing', - 'Marolf', - 'Maynez', - 'Bunde', - 'Coia', - 'Piersol', - 'Agne', - 'Manwarren', - 'Bolter', - 'Kirsh', - 'Limerick', - 'Degray', - 'Bossie', - 'Frizell', - 'Saulters', - 'Staple', - 'Raspberry', - 'Arvie', - 'Abler', - 'Caya', - 'Ceci', - 'Dado', - 'Dewoody', - 'Hartzel', - 'Haverstick', - 'Kagel', - 'Kinnan', - 'Krock', - 'Kubica', - 'Laun', - 'Leimbach', - 'Mecklenburg', - 'Messmore', - 'Milich', - 'Mor', - 'Nachreiner', - 'Novelo', - 'Poer', - 'Vaupel', - 'Wery', - 'Breisch', - 'Cashdollar', - 'Corbridge', - 'Craker', - 'Heiberger', - 'Landress', - 'Leichty', - 'Wiedmann', - 'Yankowski', - 'Rigel', - 'Eary', - 'Riggen', - 'Nazir', - 'Shambo', - 'Gingery', - 'Guyon', - 'Bogie', - 'Kar', - 'Manifold', - 'Lafavor', - 'Montas', - 'Yeadon', - 'Cutchin', - 'Burkins', - 'Achille', - 'Bulls', - 'Torry', - 'Bartkus', - 'Beshara', - 'Busalacchi', - 'Calkin', - 'Corkum', - 'Crilley', - 'Cuny', - 'Delgaudio', - 'Devenney', - 'Emanuelson', - 'Fiel', - 'Galanti', - 'Gravina', - 'Herzing', - 'Huckaba', - 'Jaquish', - 'Kellermann', - 'Ketola', - 'Klunder', - 'Kolinski', - 'Kosak', - 'Loscalzo', - 'Moehle', - 'Ressel', - 'Skora', - 'Steakley', - 'Traugott', - 'Volden', - 'Berrong', - 'Kehres', - 'Loeffelholz', - 'Mensinger', - 'Nudo', - 'Pargas', - 'Endy', - 'Corniel', - 'Azzam', - 'Soard', - 'Flud', - 'Shuffler', - 'Hiley', - 'Logwood', - 'Ducre', - 'Aikey', - 'Ardolino', - 'Bergstresser', - 'Cen', - 'Delpriore', - 'Divelbiss', - 'Fishkin', - 'Gaucin', - 'Hemmingsen', - 'Inscore', - 'Kathman', - 'Kempen', - 'Koble', - 'Maestre', - 'Mcmonigle', - 'Merendino', - 'Meske', - 'Pietrzyk', - 'Renfrew', - 'Shevchenko', - 'Wied', - 'Digeronimo', - 'Heberer', - 'Himmelberger', - 'Nordmeyer', - 'Pocius', - 'Sigurdson', - 'Simic', - 'Steury', - 'Kealey', - 'Sabat', - 'Verstraete', - 'Patchell', - 'Finigan', - 'Critz', - 'Janelle', - 'Cima', - 'Zachariah', - 'Lebon', - 'Kellough', - 'Whitehall', - 'Jaudon', - 'Civil', - 'Dokes', - 'Slappy', - 'Bernacki', - 'Castronovo', - 'Douty', - 'Formoso', - 'Handelman', - 'Hauswirth', - 'Janowicz', - 'Klostermann', - 'Lochridge', - 'Mcdiarmid', - 'Schmale', - 'Shaddox', - 'Sitzes', - 'Spaw', - 'Urbanik', - 'Voller', - 'Fujikawa', - 'Kimmet', - 'Klingel', - 'Stoffregen', - 'Thammavong', - 'Varelas', - 'Whobrey', - 'Mandella', - 'Montuori', - 'Safrit', - 'Turan', - 'Khokhar', - 'Sircy', - 'Sabio', - 'Fill', - 'Brandao', - 'Avans', - 'Mencer', - 'Sherley', - 'Mccadden', - 'Sydney', - 'Smack', - 'Lastrapes', - 'Rowser', - 'Moultry', - 'Faulcon', - 'Arnall', - 'Babiak', - 'Balsam', - 'Bezanson', - 'Bocook', - 'Bohall', - 'Celi', - 'Costillo', - 'Crom', - 'Crusan', - 'Dibari', - 'Donaho', - 'Followell', - 'Gaudino', - 'Gericke', - 'Gori', - 'Hurrell', - 'Jakubiak', - 'Kazemi', - 'Koslosky', - 'Massoud', - 'Niebla', - 'Noffke', - 'Panjwani', - 'Papandrea', - 'Patella', - 'Plambeck', - 'Plichta', - 'Prinkey', - 'Raptis', - 'Ruffini', - 'Shoen', - 'Temkin', - 'Thul', - 'Vandall', - 'Wyeth', - 'Zalenski', - 'Consoli', - 'Gumbert', - 'Milanowski', - 'Musolf', - 'Naeger', - 'Okonski', - 'Orrison', - 'Solache', - 'Verdone', - 'Woehler', - 'Yonke', - 'Risdon', - 'Orzech', - 'Bergland', - 'Collen', - 'Bloodsworth', - 'Furgeson', - 'Moch', - 'Callegari', - 'Alphonso', - 'Ozier', - 'Paulding', - 'Ringold', - 'Yarde', - 'Abbett', - 'Axford', - 'Capwell', - 'Datz', - 'Delillo', - 'Delisa', - 'Dicaprio', - 'Dimare', - 'Faughnan', - 'Fehrenbacher', - 'Gellert', - 'Ging', - 'Gladhill', - 'Goates', - 'Hammerstrom', - 'Hilbun', - 'Iodice', - 'Kadish', - 'Kilker', - 'Lurvey', - 'Maue', - 'Michna', - 'Parslow', - 'Pawelski', - 'Quenzer', - 'Raboin', - 'Sader', - 'Sawka', - 'Velis', - 'Wilczewski', - 'Willemsen', - 'Zebley', - 'Benscoter', - 'Denhartog', - 'Dolinsky', - 'Malacara', - 'Mccosh', - 'Modugno', - 'Tsay', - 'Vanvoorst', - 'Mincher', - 'Nickol', - 'Elster', - 'Kerce', - 'Brittan', - 'Quilter', - 'Spike', - 'Mcintee', - 'Boldon', - 'Balderama', - 'Cauffman', - 'Chovanec', - 'Difonzo', - 'Fagerstrom', - 'Galanis', - 'Jeziorski', - 'Krasowski', - 'Lansdale', - 'Laven', - 'Magallan', - 'Mahal', - 'Mehrer', - 'Naus', - 'Peltzer', - 'Petraitis', - 'Pritz', - 'Salway', - 'Savich', - 'Schmehl', - 'Teniente', - 'Tuccillo', - 'Wahlquist', - 'Wetz', - 'Brozovich', - 'Catalfamo', - 'Dioguardi', - 'Guzzetta', - 'Hanak', - 'Lipschutz', - 'Sholtis', - 'Bleecker', - 'Sattar', - 'Thivierge', - 'Camfield', - 'Heslep', - 'Tree', - 'Calvey', - 'Mcgowin', - 'Strickling', - 'Manderson', - 'Dieudonne', - 'Bonini', - 'Bruinsma', - 'Burgueno', - 'Cotugno', - 'Fukunaga', - 'Krog', - 'Lacerda', - 'Larrivee', - 'Lepera', - 'Pinilla', - 'Reichenberger', - 'Rovner', - 'Rubiano', - 'Saraiva', - 'Smolka', - 'Soboleski', - 'Tallmadge', - 'Wigand', - 'Wikle', - 'Bentsen', - 'Bierer', - 'Cohenour', - 'Dobberstein', - 'Holderbaum', - 'Polhamus', - 'Skousen', - 'Theiler', - 'Fornes', - 'Sisley', - 'Zingale', - 'Nimtz', - 'Prieur', - 'Mccaughan', - 'Fawaz', - 'Hobbins', - 'Killingbeck', - 'Roads', - 'Nicolson', - 'Mcculloh', - 'Verges', - 'Badley', - 'Shorten', - 'Litaker', - 'Laseter', - 'Stthomas', - 'Mcguffie', - 'Depass', - 'Flemons', - 'Ahola', - 'Armacost', - 'Bearse', - 'Downum', - 'Drechsel', - 'Farooqi', - 'Filosa', - 'Francesconi', - 'Kielbasa', - 'Latella', - 'Monarch', - 'Ozawa', - 'Papadakis', - 'Politano', - 'Poucher', - 'Roussin', - 'Safley', - 'Schwer', - 'Tesoro', - 'Tsan', - 'Wintersteen', - 'Zanni', - 'Barlage', - 'Brancheau', - 'Buening', - 'Dahlem', - 'Forni', - 'Gerety', - 'Gutekunst', - 'Leamer', - 'Liwanag', - 'Meech', - 'Wigal', - 'Bonta', - 'Cheetham', - 'Crespi', - 'Fahs', - 'Prow', - 'Postle', - 'Delacy', - 'Dufort', - 'Gallery', - 'Romey', - 'Aime', - 'Molock', - 'Dixion', - 'Carstarphen', - 'Appleyard', - 'Aylsworth', - 'Barberi', - 'Contini', - 'Cugini', - 'Eiben', - 'Faso', - 'Hartog', - 'Jelen', - 'Loayza', - 'Maugeri', - 'Mcgannon', - 'Osorno', - 'Paratore', - 'Sahagian', - 'Sarracino', - 'Scallon', - 'Sypniewski', - 'Teters', - 'Throgmorton', - 'Vogelpohl', - 'Walkowski', - 'Winchel', - 'Niedermeyer', - 'Jayroe', - 'Montello', - 'Neyer', - 'Milder', - 'Obar', - 'Stanis', - 'Pro', - 'Pin', - 'Fatheree', - 'Cotterell', - 'Reeds', - 'Comrie', - 'Zamor', - 'Gradney', - 'Poullard', - 'Betker', - 'Bondarenko', - 'Buchko', - 'Eischens', - 'Glavan', - 'Hannold', - 'Heafner', - 'Karaffa', - 'Krabbe', - 'Meinzer', - 'Olgin', - 'Raeder', - 'Sarff', - 'Senechal', - 'Sette', - 'Shovlin', - 'Slife', - 'Tallarico', - 'Trivino', - 'Wyszynski', - 'Audia', - 'Facemire', - 'Januszewski', - 'Klebba', - 'Kovacik', - 'Moroni', - 'Nieder', - 'Schorn', - 'Sundby', - 'Tehan', - 'Trias', - 'Kissler', - 'Margo', - 'Jefcoat', - 'Bulow', - 'Maire', - 'Vizcarrondo', - 'Ki', - 'Ayuso', - 'Mayhan', - 'Usman', - 'Blincoe', - 'Whidby', - 'Tinson', - 'Calarco', - 'Cena', - 'Ciccarello', - 'Cloe', - 'Consolo', - 'Davydov', - 'Decristofaro', - 'Delmundo', - 'Dubrow', - 'Ellinwood', - 'Gehling', - 'Halberstadt', - 'Hascall', - 'Hoeffner', - 'Huettl', - 'Iafrate', - 'Imig', - 'Khoo', - 'Krausz', - 'Kuether', - 'Kulla', - 'Marchesani', - 'Ormonde', - 'Platzer', - 'Preusser', - 'Rebel', - 'Reidhead', - 'Riehm', - 'Robertshaw', - 'Runco', - 'Sandino', - 'Spare', - 'Trefethen', - 'Tribby', - 'Yamazaki', - 'Ziesmer', - 'Calamari', - 'Deyoe', - 'Marullo', - 'Neidigh', - 'Salveson', - 'Senesac', - 'Ausburn', - 'Herner', - 'Seagrave', - 'Lormand', - 'Niblock', - 'Somes', - 'Naim', - 'Murren', - 'Callander', - 'Glassco', - 'Henri', - 'Jabbar', - 'Bordes', - 'Altemose', - 'Bagnell', - 'Belloso', - 'Beougher', - 'Birchall', - 'Cantara', - 'Demetriou', - 'Galford', - 'Hast', - 'Heiny', - 'Hieronymus', - 'Jehle', - 'Khachatryan', - 'Kristof', - 'Kubas', - 'Mano', - 'Munar', - 'Ogas', - 'Riccitelli', - 'Sidman', - 'Suchocki', - 'Tortorello', - 'Trombino', - 'Vullo', - 'Badura', - 'Clerkin', - 'Criollo', - 'Dashnaw', - 'Mednick', - 'Pickrel', - 'Mawson', - 'Hockey', - 'Alo', - 'Frankland', - 'Gaby', - 'Hoda', - 'Marchena', - 'Fawbush', - 'Cowing', - 'Aydelott', - 'Dieu', - 'Rise', - 'Morten', - 'Gunby', - 'Modeste', - 'Balcerzak', - 'Cutbirth', - 'Dejoseph', - 'Desaulniers', - 'Dimperio', - 'Dubord', - 'Gruszka', - 'Haske', - 'Hehr', - 'Kolander', - 'Kusiak', - 'Lampron', - 'Mapel', - 'Montie', - 'Mumme', - 'Naramore', - 'Raffel', - 'Ruter', - 'Sawa', - 'Sencion', - 'Somogyi', - 'Ventola', - 'Zabawa', - 'Alagna', - 'Burmaster', - 'Chirco', - 'Gjerde', - 'Hilgenberg', - 'Huntress', - 'Kochel', - 'Nist', - 'Schena', - 'Toolan', - 'Wurzer', - 'Masih', - 'Ritts', - 'Rousse', - 'Buckey', - 'Sausedo', - 'Dolle', - 'Bena', - 'Franca', - 'Commins', - 'Gago', - 'Pattie', - 'Brener', - 'Verley', - 'Griffy', - 'Heiskell', - 'Osley', - 'Babula', - 'Barbone', - 'Berzins', - 'Demirjian', - 'Dietze', - 'Haseltine', - 'Heinbaugh', - 'Henneke', - 'Korba', - 'Levitz', - 'Lorenzini', - 'Mansilla', - 'Peffley', - 'Poletti', - 'Portelli', - 'Rottinghaus', - 'Scifres', - 'Stadel', - 'Stettner', - 'Swauger', - 'Vanwart', - 'Vorhies', - 'Worst', - 'Yadav', - 'Yebra', - 'Kreiter', - 'Mroczek', - 'Pennella', - 'Stangelo', - 'Suchan', - 'Weiand', - 'Widhalm', - 'Wojcicki', - 'Gutzman', - 'Griffee', - 'Konicki', - 'Moorehouse', - 'Neighbor', - 'Butte', - 'Cooter', - 'Humpherys', - 'Morrish', - 'Stockhausen', - 'Slatter', - 'Cheely', - 'Yassin', - 'Bazil', - 'Mcsween', - 'Anastos', - 'Annunziato', - 'Bora', - 'Burkitt', - 'Cino', - 'Codding', - 'Criado', - 'Firestine', - 'Goecke', - 'Golda', - 'Holloran', - 'Homen', - 'Laubscher', - 'Memmer', - 'Navejar', - 'Peraino', - 'Petrizzo', - 'Pflieger', - 'Pint', - 'Porcello', - 'Raffety', - 'Riedesel', - 'Salado', - 'Scaletta', - 'Schuring', - 'Slaydon', - 'Solecki', - 'Spomer', - 'Waldridge', - 'Zawislak', - 'Bottone', - 'Helgesen', - 'Knippel', - 'Loutzenhiser', - 'Mallinson', - 'Malnar', - 'Pethtel', - 'Sissel', - 'Thorstenson', - 'Winokur', - 'Dittmann', - 'Fencl', - 'Kernen', - 'Gath', - 'Hiney', - 'Godman', - 'Hopton', - 'Tinley', - 'Wamble', - 'Greg', - 'Garrette', - 'Acoff', - 'Ausman', - 'Burggraf', - 'Colliver', - 'Dejulio', - 'Fedorchak', - 'Finocchio', - 'Grasse', - 'Harpold', - 'Hopman', - 'Kilzer', - 'Losasso', - 'Lovallo', - 'Neumayer', - 'Purohit', - 'Reddinger', - 'Scheper', - 'Valbuena', - 'Wenzl', - 'Eilerman', - 'Galbo', - 'Haydu', - 'Vipond', - 'Wesselman', - 'Yeagle', - 'Boutelle', - 'Odonnel', - 'Morocco', - 'Speak', - 'Ruckel', - 'Cornier', - 'Burbidge', - 'Esselman', - 'Daisey', - 'Juran', - 'Henard', - 'Trench', - 'Hurry', - 'Estis', - 'Allport', - 'Beedy', - 'Blower', - 'Bogacz', - 'Caldas', - 'Carriero', - 'Garand', - 'Gonterman', - 'Harbeck', - 'Husar', - 'Lizcano', - 'Lonardo', - 'Meneely', - 'Misiewicz', - 'Pagliuca', - 'Pember', - 'Rybacki', - 'Safar', - 'Seeberger', - 'Siharath', - 'Spoerl', - 'Tattersall', - 'Birchmeier', - 'Denunzio', - 'Dustman', - 'Franchini', - 'Gettel', - 'Goldrick', - 'Goodheart', - 'Keshishyan', - 'Mcgrogan', - 'Newingham', - 'Scheier', - 'Skorupa', - 'Utech', - 'Weidenbach', - 'Chaloupka', - 'Grater', - 'Libman', - 'Recore', - 'Savona', - 'Verbeke', - 'Lunetta', - 'Schlater', - 'Staffieri', - 'Troll', - 'Leyton', - 'Peto', - 'Trella', - 'Follin', - 'Morro', - 'Woodhall', - 'Krauser', - 'Salles', - 'Brunty', - 'Wadford', - 'Shaddock', - 'Minnie', - 'Mountcastle', - 'Butter', - 'Galentine', - 'Longsworth', - 'Edgecombe', - 'Babino', - 'Printup', - 'Humbles', - 'Vessel', - 'Relford', - 'Taite', - 'Aliberti', - 'Brostrom', - 'Budlong', - 'Bykowski', - 'Coursen', - 'Darga', - 'Doutt', - 'Gomberg', - 'Greaser', - 'Hilde', - 'Hirschy', - 'Mayorquin', - 'Mcartor', - 'Mechler', - 'Mein', - 'Montville', - 'Peskin', - 'Popiel', - 'Ricciardelli', - 'Terrana', - 'Urton', - 'Cardiff', - 'Foiles', - 'Humann', - 'Pokorney', - 'Seehafer', - 'Sporer', - 'Timme', - 'Tweten', - 'Widrick', - 'Harnack', - 'Chamlee', - 'Lafountaine', - 'Lowdermilk', - 'Akel', - 'Maulden', - 'Sloman', - 'Odonald', - 'Hitchman', - 'Pendergraph', - 'Klugh', - 'Mctier', - 'Stargell', - 'Hailu', - 'Kanu', - 'Abrahamian', - 'Ackerly', - 'Belongia', - 'Cudmore', - 'Jaskolski', - 'Kedzierski', - 'Licciardi', - 'Lowenberg', - 'Meitzler', - 'Metzer', - 'Mitcheltree', - 'Nishioka', - 'Pascuzzi', - 'Pelphrey', - 'Ramones', - 'Schuchard', - 'Smithee', - 'Bignell', - 'Blaszak', - 'Borello', - 'Fiacco', - 'Garrelts', - 'Guzowski', - 'Rychlik', - 'Siebers', - 'Speziale', - 'Zauner', - 'Corell', - 'Welt', - 'Koby', - 'Auletta', - 'Bursch', - 'Luckman', - 'Vanhoesen', - 'Russian', - 'Statton', - 'Yahya', - 'Boxx', - 'Haltiwanger', - 'Redhead', - 'Mcgregory', - 'Baccari', - 'Berrey', - 'Bogden', - 'Braniff', - 'Cafarelli', - 'Clavette', - 'Corallo', - 'Dealy', - 'Gilger', - 'Gitter', - 'Goldwasser', - 'Hillesheim', - 'Hulsizer', - 'Jankovic', - 'Limburg', - 'Lopera', - 'Mcaleese', - 'Mcclintick', - 'Montealegre', - 'Mosko', - 'Nogle', - 'Ordones', - 'Papesh', - 'Peragine', - 'Picco', - 'Podraza', - 'Ras', - 'Rezek', - 'Rork', - 'Schraufnagel', - 'Scipione', - 'Terlizzi', - 'Vanblarcom', - 'Yoshino', - 'Beaverson', - 'Behunin', - 'Isch', - 'Janiga', - 'Koeppe', - 'Laurich', - 'Vondrak', - 'Walkley', - 'Hottenstein', - 'Garms', - 'Macknight', - 'Seagroves', - 'Shehata', - 'Arons', - 'Liley', - 'Pressly', - 'Cowper', - 'Branon', - 'Abdella', - 'Milord', - 'Appenzeller', - 'Ardila', - 'Belgard', - 'Boop', - 'Burbano', - 'Capitano', - 'Carrig', - 'Conrey', - 'Donica', - 'Fineberg', - 'Gemberling', - 'Harrier', - 'Hufnagle', - 'Kitner', - 'Lessing', - 'Manoukian', - 'Menk', - 'Repetto', - 'Rhinesmith', - 'Stechschulte', - 'Yep', - 'Zuhlke', - 'Abundiz', - 'Buccellato', - 'Closser', - 'Gielow', - 'Nurmi', - 'Pelka', - 'Piscitello', - 'Shoaff', - 'Champlain', - 'Conran', - 'Leidig', - 'Carel', - 'Zahid', - 'Dimitri', - 'Sapia', - 'Labauve', - 'Khalifa', - 'Gonsoulin', - 'Parrot', - 'Propps', - 'Dunnaway', - 'Cayo', - 'Mccleod', - 'Bonifas', - 'Dirkes', - 'Farruggia', - 'Gut', - 'Heacox', - 'Herrejon', - 'Ipina', - 'Keatley', - 'Kowitz', - 'Kratky', - 'Langseth', - 'Nidiffer', - 'Plimpton', - 'Riesenberg', - 'Sulewski', - 'Tabar', - 'Takara', - 'Tomassetti', - 'Tweet', - 'Weltz', - 'Youtsey', - 'Franckowiak', - 'Geffert', - 'Glawe', - 'Hillestad', - 'Ladewig', - 'Luckow', - 'Radebaugh', - 'Ransbottom', - 'Stordahl', - 'Weimar', - 'Wiegers', - 'Jowett', - 'Tomb', - 'Waitt', - 'Beaudreau', - 'Notter', - 'Rijo', - 'Denike', - 'Mam', - 'Vent', - 'Gamage', - 'Carre', - 'Childrey', - 'Heaven', - 'Forge', - 'Beckom', - 'Collick', - 'Bovell', - 'Hardimon', - 'Shells', - 'Bolf', - 'Canete', - 'Cozby', - 'Dunlavey', - 'Febo', - 'Lamke', - 'Lant', - 'Larned', - 'Leiss', - 'Lofthouse', - 'Marohn', - 'Stradling', - 'Subramaniam', - 'Vitug', - 'Ziccardi', - 'Akamine', - 'Bellissimo', - 'Bottini', - 'Braund', - 'Cavasos', - 'Heltsley', - 'Landstrom', - 'Lisiecki', - 'Navejas', - 'Sobczyk', - 'Trela', - 'Yablonski', - 'Yocham', - 'Fier', - 'Laiche', - 'Zenor', - 'Grew', - 'Naval', - 'Garratt', - 'Sako', - 'Zollicoffer', - 'Momon', - 'Bensman', - 'Cirincione', - 'Dimitrov', - 'Domeier', - 'Gaska', - 'Gensel', - 'Gernert', - 'Groot', - 'Guarisco', - 'Llorente', - 'Ludemann', - 'Moisan', - 'Muzio', - 'Neiswender', - 'Ottaway', - 'Paslay', - 'Readinger', - 'Skok', - 'Spittle', - 'Sweany', - 'Tanzi', - 'Upadhyay', - 'Valone', - 'Varas', - 'Benecke', - 'Faulstich', - 'Hebda', - 'Jobst', - 'Schleis', - 'Shuart', - 'Treinen', - 'Fok', - 'Dentler', - 'Ginty', - 'Ronda', - 'Tess', - 'Scantlin', - 'Kham', - 'Murin', - 'Faubert', - 'Ocarroll', - 'Maranda', - 'Gadsby', - 'Mouse', - 'Lunden', - 'Asquith', - 'Batley', - 'Bazzle', - 'Hooke', - 'Macneal', - 'Desnoyers', - 'Verdier', - 'Biglow', - 'Leverson', - 'Becherer', - 'Cecilio', - 'Correale', - 'Ehinger', - 'Erney', - 'Fassnacht', - 'Humpal', - 'Korpela', - 'Kratt', - 'Kunes', - 'Lockyer', - 'Macho', - 'Manfredo', - 'Maturino', - 'Raineri', - 'Seiger', - 'Stant', - 'Tecson', - 'Tempest', - 'Traverse', - 'Vonk', - 'Wormington', - 'Yeske', - 'Erichsen', - 'Fiorelli', - 'Fouty', - 'Hodgkiss', - 'Lindenbaum', - 'Matusik', - 'Mazzocco', - 'Oldani', - 'Ronca', - 'Amero', - 'Ormand', - 'Cagley', - 'Teutsch', - 'Likins', - 'Blurton', - 'Lapier', - 'Rensch', - 'Howitt', - 'Kady', - 'Broce', - 'Gaba', - 'Summerson', - 'Faure', - 'Densley', - 'Matkins', - 'Boleware', - 'Rahming', - 'Degrate', - 'Broaden', - 'Barbian', - 'Brancaccio', - 'Dimiceli', - 'Doukas', - 'Fredell', - 'Fritchman', - 'Gahr', - 'Geerdes', - 'Heidrick', - 'Hernon', - 'Ipsen', - 'Koci', - 'Lato', - 'Lyng', - 'Montella', - 'Petraglia', - 'Redlinger', - 'Riedlinger', - 'Rodier', - 'Shenton', - 'Smigiel', - 'Spanbauer', - 'Swetland', - 'Sypolt', - 'Taubert', - 'Wallander', - 'Willers', - 'Ziller', - 'Bielak', - 'Careaga', - 'Droddy', - 'Girardot', - 'Kanouse', - 'Perusse', - 'Schwier', - 'Velo', - 'Westrum', - 'Bouza', - 'Calverley', - 'Shupert', - 'Simi', - 'Zieger', - 'Nicole', - 'Fergeson', - 'Guerrant', - 'Tongue', - 'Amison', - 'Darius', - 'Banasiak', - 'Cocca', - 'Dannemiller', - 'Frommer', - 'Guardia', - 'Herl', - 'Lippa', - 'Nappo', - 'Olaya', - 'Ozburn', - 'Patry', - 'Pontiff', - 'Rauth', - 'Reier', - 'Rolfs', - 'Sassone', - 'Servidio', - 'Shough', - 'Tencza', - 'Ernster', - 'Helminiak', - 'Mcmanamon', - 'Ottens', - 'Vinh', - 'Bula', - 'Elza', - 'Serres', - 'Holan', - 'Wetherill', - 'Balis', - 'Schexnider', - 'Harral', - 'Dulany', - 'Webley', - 'Addleman', - 'Antonopoulos', - 'Badman', - 'Czerwonka', - 'Deweerd', - 'Donaghey', - 'Duszynski', - 'Firkus', - 'Foell', - 'Goyne', - 'Hattabaugh', - 'Herbel', - 'Liebelt', - 'Lovera', - 'Quenneville', - 'Ramic', - 'Rissmiller', - 'Schlag', - 'Selover', - 'Seyer', - 'Stangeland', - 'Stutesman', - 'Suminski', - 'Sweger', - 'Tetlow', - 'Thornbury', - 'Votava', - 'Weberg', - 'Canniff', - 'Evetts', - 'Gutterman', - 'Kasparek', - 'Krenzer', - 'Luckenbaugh', - 'Mainwaring', - 'Vanderweide', - 'Balladares', - 'Riesterer', - 'Salmen', - 'Mirando', - 'Rockman', - 'Warnes', - 'Crispell', - 'Corban', - 'Chrystal', - 'Barlowe', - 'Perot', - 'Ka', - 'Stockett', - 'Montfort', - 'Reagor', - 'Coote', - 'Christon', - 'Dor', - 'Apt', - 'Bandel', - 'Bibbee', - 'Brunkhorst', - 'Dexheimer', - 'Disharoon', - 'Engelstad', - 'Glaza', - 'Locey', - 'Loughney', - 'Minotti', - 'Posa', - 'Renzulli', - 'Schlauch', - 'Shadix', - 'Sloboda', - 'Topor', - 'Vacha', - 'Cerulli', - 'Ciaravino', - 'Cisek', - 'Congrove', - 'Domzalski', - 'Fleitas', - 'Helfand', - 'Lehnen', - 'Moleski', - 'Walski', - 'Dazey', - 'Mckellips', - 'Kanne', - 'Deguire', - 'Macmurray', - 'Marcelli', - 'Creach', - 'Antrobus', - 'Hykes', - 'Barriere', - 'Avinger', - 'Handford', - 'Beaufort', - 'Abend', - 'Bozzi', - 'Burnsworth', - 'Crosthwaite', - 'Eilert', - 'Frigon', - 'Hanbury', - 'Hoilman', - 'Isaksen', - 'Juday', - 'Legarda', - 'Mcgourty', - 'Mittler', - 'Olkowski', - 'Pau', - 'Pescador', - 'Pinkerman', - 'Renno', - 'Rescigno', - 'Salsgiver', - 'Schlanger', - 'Sobek', - 'Stasi', - 'Talaga', - 'Tish', - 'Tropea', - 'Umphress', - 'Weisheit', - 'Bartolini', - 'Dassow', - 'Ferullo', - 'Fetherolf', - 'Kimery', - 'Kurihara', - 'Schneiter', - 'Sramek', - 'Swier', - 'Weinzierl', - 'Karrer', - 'Hurta', - 'Lodico', - 'Conkright', - 'Sandvik', - 'Pash', - 'Pinell', - 'Dougal', - 'Burnet', - 'Hoe', - 'Rann', - 'Curvin', - 'Route', - 'Outler', - 'Corprew', - 'Berhe', - 'Eleby', - 'Acoba', - 'Ante', - 'Baio', - 'Befort', - 'Brueck', - 'Chevere', - 'Ciani', - 'Farnes', - 'Hamar', - 'Hirschhorn', - 'Imbrogno', - 'Kegg', - 'Leever', - 'Mesker', - 'Nodal', - 'Olveda', - 'Paletta', - 'Pilant', - 'Rissman', - 'Sebold', - 'Siebel', - 'Smejkal', - 'Stai', - 'Vanderkolk', - 'Allday', - 'Canupp', - 'Dieck', - 'Hinders', - 'Karcz', - 'Shomaker', - 'Tuinstra', - 'Urquizo', - 'Wiltgen', - 'Withem', - 'Yanda', - 'Blizard', - 'Christenbury', - 'Helser', - 'Jing', - 'Stave', - 'Waddill', - 'Mairena', - 'Rebert', - 'Gara', - 'Shipes', - 'Hartsoe', - 'Bargeron', - 'Arne', - 'Ebrahim', - 'Basha', - 'Rozar', - 'Venter', - 'Mounger', - 'Marsalis', - 'Gildon', - 'Antkowiak', - 'Brus', - 'Cicalese', - 'Einspahr', - 'Faucheux', - 'Frix', - 'Gateley', - 'Hamberger', - 'Holdorf', - 'Hollibaugh', - 'Junod', - 'Keaveny', - 'Knechtel', - 'Kuffel', - 'Mcwhirt', - 'Navis', - 'Neave', - 'Rackers', - 'Romagnoli', - 'Shawhan', - 'Valvano', - 'Vina', - 'Wielgus', - 'Wojtaszek', - 'Bartnik', - 'Fiebelkorn', - 'Gertsch', - 'Morgenthaler', - 'Nambo', - 'Nemmers', - 'Nihart', - 'Nilges', - 'Pulgarin', - 'Recktenwald', - 'Vandenbrink', - 'Wion', - 'Cundy', - 'Burby', - 'Cu', - 'Vansciver', - 'Herne', - 'Doughtie', - 'Cowdery', - 'Woodle', - 'Lafosse', - 'Hodgens', - 'Mckune', - 'Car', - 'Callens', - 'Corsey', - 'Brimage', - 'Westry', - 'Arismendez', - 'Benenati', - 'Brine', - 'Brookbank', - 'Burfield', - 'Charnock', - 'Copado', - 'Demilio', - 'Elvira', - 'Fantini', - 'Ferko', - 'Flanagin', - 'Gotto', - 'Hartsough', - 'Heckart', - 'Herskowitz', - 'Hoene', - 'Ishibashi', - 'Kysar', - 'Leaverton', - 'Longfield', - 'Mischel', - 'Musleh', - 'Neyra', - 'Obeirne', - 'Ostrum', - 'Pedretti', - 'Pilkerton', - 'Plasse', - 'Reesor', - 'Roznowski', - 'Rusinko', - 'Sickle', - 'Spiteri', - 'Stash', - 'Syracuse', - 'Trachsel', - 'Weinand', - 'Gruenberg', - 'Gutkowski', - 'Morella', - 'Morneault', - 'Slivinski', - 'Blessinger', - 'Taketa', - 'Hussaini', - 'Obeid', - 'Seebeck', - 'Spayd', - 'Keasling', - 'Famularo', - 'Carne', - 'Lacosse', - 'Morino', - 'Gutzmer', - 'Spinola', - 'Deahl', - 'Crumm', - 'Folley', - 'Lennard', - 'Rowson', - 'Pickron', - 'Union', - 'Abraha', - 'Yohannes', - 'Whidbee', - 'Mccaster', - 'Batzel', - 'Borowy', - 'Disanti', - 'Druck', - 'Elsbury', - 'Eschmann', - 'Fehn', - 'Flesner', - 'Grawe', - 'Haapala', - 'Helvie', - 'Hudy', - 'Joswick', - 'Kilcullen', - 'Mabus', - 'Marzo', - 'Obradovich', - 'Oriordan', - 'Phy', - 'Scarff', - 'Schappert', - 'Scire', - 'Vandevander', - 'Weyland', - 'Anstey', - 'Feeback', - 'Komarek', - 'Kyllo', - 'Manivong', - 'Timberman', - 'Tinkey', - 'Zempel', - 'Haselhorst', - 'Herberg', - 'Laris', - 'Morter', - 'Fredman', - 'Reny', - 'Ferrall', - 'Silverthorne', - 'Shuttlesworth', - 'Stigers', - 'Koker', - 'Mollette', - 'Mansel', - 'Chrisp', - 'Glymph', - 'Preyer', - 'Worlds', - 'Arutyunyan', - 'Carrizosa', - 'Dambrosia', - 'Dantuono', - 'Delduca', - 'Florencio', - 'Garafola', - 'Habermehl', - 'Hanaway', - 'Harmes', - 'Heinonen', - 'Hellstrom', - 'Herzer', - 'Klahr', - 'Kobler', - 'Korner', - 'Lancia', - 'Leask', - 'Ledo', - 'Manzanarez', - 'Myung', - 'Prestigiacomo', - 'Serpe', - 'Tonche', - 'Ventrella', - 'Walrod', - 'Warga', - 'Wasmer', - 'Weins', - 'Zaccaro', - 'Bartus', - 'Fiumara', - 'Incorvaia', - 'Khatun', - 'Kisamore', - 'Riesen', - 'Santry', - 'Schmierer', - 'Talamo', - 'Zaccone', - 'Liddick', - 'Mcclune', - 'Hade', - 'Calcutt', - 'Gillet', - 'Husein', - 'Be', - 'Lavell', - 'Veley', - 'Buckholtz', - 'Naves', - 'Debrosse', - 'Palms', - 'Lacewell', - 'Tates', - 'Tekle', - 'Golphin', - 'Asleson', - 'Bartlebaugh', - 'Benter', - 'Bielefeld', - 'Cappetta', - 'Hanback', - 'Heeg', - 'Helf', - 'Hibberd', - 'Holsworth', - 'Kowalchuk', - 'Kruczek', - 'Lieurance', - 'Markwood', - 'Muckey', - 'Rasey', - 'Rautio', - 'Salek', - 'Schwaller', - 'Scibilia', - 'Speltz', - 'Stopper', - 'Struckman', - 'Surowiec', - 'Texter', - 'Venturi', - 'Wolfenden', - 'Zortman', - 'Dehler', - 'Gillogly', - 'Hoelzel', - 'Iida', - 'Paparella', - 'Petrea', - 'Pflaum', - 'Spampinato', - 'Spaur', - 'Umbaugh', - 'Cerney', - 'Athens', - 'Salvas', - 'Gardinier', - 'Ammar', - 'Arns', - 'Calvi', - 'Palazzola', - 'Starlin', - 'Quave', - 'Rhame', - 'Gulliford', - 'Nettle', - 'Picken', - 'Warde', - 'Pelissier', - 'Mcteer', - 'Freeny', - 'Tappin', - 'Bromell', - 'People', - 'Carthen', - 'Battenfield', - 'Bunte', - 'Estrin', - 'Fitzner', - 'Flattery', - 'Hlavacek', - 'Holecek', - 'Jorstad', - 'Jurczak', - 'Kraszewski', - 'Lencioni', - 'Mamula', - 'Mater', - 'Petrakis', - 'Safranek', - 'Santorelli', - 'Speyer', - 'Waterworth', - 'Worner', - 'Antonellis', - 'Codispoti', - 'Docken', - 'Economos', - 'Petrilla', - 'Puccinelli', - 'Rondinelli', - 'Leibel', - 'Santoya', - 'Hader', - 'Yeakley', - 'Dowse', - 'Hattan', - 'Lia', - 'Emel', - 'Corse', - 'Danes', - 'Rambin', - 'Dura', - 'Kyne', - 'Sanderford', - 'Mincer', - 'Rawl', - 'Staves', - 'Mccleave', - 'Faniel', - 'Abeln', - 'Asta', - 'Beymer', - 'Cresap', - 'Cryderman', - 'Gutwein', - 'Kaszuba', - 'Maland', - 'Marella', - 'Mcmannis', - 'Molenaar', - 'Olivarria', - 'Panfil', - 'Pieratt', - 'Ramthun', - 'Resurreccion', - 'Rosander', - 'Rostad', - 'Sallas', - 'Santone', - 'Schey', - 'Shasteen', - 'Spalla', - 'Sui', - 'Tannous', - 'Tarman', - 'Trayer', - 'Wolman', - 'Chausse', - 'Debacker', - 'Dozal', - 'Hach', - 'Klossner', - 'Kruchten', - 'Mahowald', - 'Rosenlund', - 'Steffenhagen', - 'Vanmaanen', - 'Wildasin', - 'Winiecki', - 'Dilauro', - 'Wygal', - 'Cadmus', - 'Smallman', - 'Sear', - 'Berch', - 'Nabor', - 'Bro', - 'Storr', - 'Goynes', - 'Chestang', - 'Alvillar', - 'Arya', - 'Aton', - 'Bors', - 'Brydon', - 'Castagno', - 'Catena', - 'Catterson', - 'Chhun', - 'Delrossi', - 'Garnsey', - 'Harbeson', - 'Holum', - 'Iglesia', - 'Kleen', - 'Lavallie', - 'Lossing', - 'Miyata', - 'Myszka', - 'Peth', - 'Pyka', - 'Radler', - 'Roggenkamp', - 'Sarra', - 'Schmeltz', - 'Schreifels', - 'Schrimpf', - 'Scrogham', - 'Sieminski', - 'Singson', - 'Stichter', - 'Vajda', - 'Vilardo', - 'Ziff', - 'Cegielski', - 'Fanara', - 'Mefferd', - 'Polanski', - 'Reining', - 'Roggow', - 'Sassi', - 'Wagenknecht', - 'Roadcap', - 'Tuman', - 'Demesa', - 'Surita', - 'Armando', - 'Macks', - 'Megan', - 'Angello', - 'Bosher', - 'Neugent', - 'Croslin', - 'Bumpas', - 'Gladman', - 'Demmons', - 'Mcnairy', - 'Sermons', - 'Okonkwo', - 'Alvira', - 'Barfuss', - 'Bersch', - 'Bustin', - 'Ciriello', - 'Cords', - 'Cuddeback', - 'Debono', - 'Delosh', - 'Haeger', - 'Ida', - 'Kneer', - 'Koppen', - 'Kottwitz', - 'Laib', - 'Matsushita', - 'Mckone', - 'Meester', - 'Ohashi', - 'Pickert', - 'Risso', - 'Vannice', - 'Vargason', - 'Vorpahl', - 'Gluth', - 'Goossens', - 'Kloeppel', - 'Krolczyk', - 'Lequire', - 'Nila', - 'Savoia', - 'Wassmer', - 'Bianca', - 'Rousselle', - 'Wittler', - 'Gillean', - 'Cervi', - 'Fremin', - 'Vanzanten', - 'Varvel', - 'Sween', - 'Peron', - 'Trudo', - 'Welford', - 'Scovil', - 'Beazer', - 'Cohill', - 'Estime', - 'Alcalde', - 'Bugay', - 'Bushard', - 'Dethloff', - 'Gahn', - 'Gronau', - 'Hogston', - 'Kleinfelter', - 'Ksiazek', - 'Lyness', - 'Marak', - 'Munafo', - 'Noorani', - 'Plonski', - 'Pontarelli', - 'Presas', - 'Ringenberg', - 'Sabillon', - 'Schaut', - 'Shankland', - 'Sheil', - 'Shugrue', - 'Soter', - 'Stankovich', - 'Arrants', - 'Boeckmann', - 'Boothroyd', - 'Dysinger', - 'Gersh', - 'Monnig', - 'Scheiderer', - 'Slifka', - 'Vilardi', - 'Podell', - 'Tarallo', - 'Goodroe', - 'Sardinha', - 'Blish', - 'Califf', - 'Dorion', - 'Dougall', - 'Hamza', - 'Boggus', - 'Mccan', - 'Branscomb', - 'Baatz', - 'Bendix', - 'Hartstein', - 'Hechler', - 'Komatsu', - 'Kooiman', - 'Loghry', - 'Lorson', - 'Mcgoff', - 'Moga', - 'Monsees', - 'Nigg', - 'Pacitti', - 'Shiffman', - 'Shoupe', - 'Snarski', - 'Vrba', - 'Wilmeth', - 'Yurchak', - 'Budney', - 'Estok', - 'Knipple', - 'Krzywicki', - 'Librizzi', - 'Obringer', - 'Poliquin', - 'Severtson', - 'Vecchiarelli', - 'Zelazny', - 'Eis', - 'Wildeman', - 'Gatt', - 'Gordin', - 'Dusenbury', - 'Prew', - 'Mander', - 'Tine', - 'Debarr', - 'Bann', - 'Mcguirt', - 'Vanloan', - 'Basdeo', - 'Kosh', - 'Bertha', - 'Mcglothen', - 'Youman', - 'Hallums', - 'Mcfield', - 'Asano', - 'Barbo', - 'Braver', - 'Bua', - 'Buetow', - 'Buttke', - 'Estela', - 'Kauk', - 'Kosmicki', - 'Kuecker', - 'Lahm', - 'Lienhard', - 'Lombera', - 'Menken', - 'Niederhauser', - 'Norcia', - 'Petrelli', - 'Phong', - 'Piontkowski', - 'Prihoda', - 'Raffo', - 'Sherpa', - 'Shinsky', - 'Skoczylas', - 'Sosinski', - 'Sua', - 'Sur', - 'Thorndike', - 'Trease', - 'Wessler', - 'Witting', - 'Ackroyd', - 'Bartnick', - 'Dziuba', - 'Lisko', - 'Muradyan', - 'Pistilli', - 'Riechers', - 'Saxman', - 'Rodi', - 'Venables', - 'Holway', - 'Vargus', - 'Oley', - 'Delmont', - 'Fuster', - 'Wyndham', - 'Whittenberg', - 'Chustz', - 'Swilling', - 'Moncure', - 'Housey', - 'Mckiver', - 'Shelvin', - 'Aslin', - 'Begeman', - 'Capek', - 'Christlieb', - 'Colasanti', - 'Daidone', - 'Detlefsen', - 'Elsass', - 'Faus', - 'Francke', - 'Hensarling', - 'Hollmann', - 'Isaacks', - 'Kocis', - 'Kofman', - 'Kwiatek', - 'Osterkamp', - 'Pickar', - 'Prellwitz', - 'Ramo', - 'Steenson', - 'Tomasulo', - 'Weinreb', - 'Wiard', - 'Ambs', - 'Baglio', - 'Frayre', - 'Hisaw', - 'Justman', - 'Morrical', - 'Sherfey', - 'Gera', - 'Ilgenfritz', - 'Silos', - 'Boge', - 'Darocha', - 'Hennon', - 'Hendriks', - 'Purrington', - 'Eunice', - 'Kirks', - 'Barbar', - 'Guichard', - 'Bonny', - 'Lobban', - 'Winrow', - 'Alavi', - 'Binner', - 'Canan', - 'Ciullo', - 'Cyran', - 'Doolen', - 'Enquist', - 'Fatzinger', - 'Forsell', - 'Harnisch', - 'Hirose', - 'Lunz', - 'Mcbrearty', - 'Mcgavin', - 'Minkin', - 'Ralphs', - 'Ruegsegger', - 'Shetter', - 'Slagter', - 'Tyminski', - 'Ubben', - 'Vanderschaaf', - 'Wigfield', - 'Zellman', - 'Bettenhausen', - 'Busker', - 'Jabs', - 'Mishkin', - 'Sturdy', - 'Vanstone', - 'Tierce', - 'Cormican', - 'Mazzucco', - 'Buenger', - 'Gallier', - 'Duma', - 'Rainbow', - 'Herlong', - 'Chriswell', - 'Litsey', - 'Wyke', - 'Kissoon', - 'Sesler', - 'Farve', - 'Lalanne', - 'Myhand', - 'Heggs', - 'Andujo', - 'Arcilla', - 'Bult', - 'Caponigro', - 'Commerford', - 'Ditmars', - 'Dressen', - 'Eggemeyer', - 'Forstner', - 'From', - 'Heldreth', - 'Hevia', - 'Leiphart', - 'Mastrocola', - 'Mcanelly', - 'Mccrillis', - 'Mellick', - 'Mogle', - 'Mummey', - 'Nishiyama', - 'Nordine', - 'Picinich', - 'Rafiq', - 'Savo', - 'Selvig', - 'Sestak', - 'Shafran', - 'Smithhart', - 'Soltani', - 'Stillion', - 'Szuch', - 'Tigert', - 'Trine', - 'Un', - 'Brest', - 'Callari', - 'Jaskowiak', - 'Maneval', - 'Sarchet', - 'Szuba', - 'Taubman', - 'Wandel', - 'Blok', - 'Pasquarello', - 'Sava', - 'Diekman', - 'Blight', - 'Lovgren', - 'Clemson', - 'Lince', - 'Kanady', - 'Whipps', - 'Coren', - 'Coye', - 'Patman', - 'Souffrant', - 'Bloodsaw', - 'Amano', - 'Cassaday', - 'Cutillo', - 'Dayrit', - 'Deringer', - 'Duwe', - 'Favazza', - 'Fennema', - 'Hackleman', - 'Harders', - 'Imperiale', - 'Kano', - 'Kingma', - 'Meuser', - 'Neiger', - 'Neitz', - 'Nied', - 'Prows', - 'Riss', - 'Rotundo', - 'Scheurich', - 'Stopa', - 'Tonks', - 'Veen', - 'Volante', - 'Maerz', - 'Nunnelley', - 'Sommerfeldt', - 'Spoonemore', - 'Wechter', - 'Wehrli', - 'Ackert', - 'Begun', - 'Dreyfuss', - 'Frezza', - 'Mako', - 'Nagao', - 'Lassetter', - 'Linse', - 'Raum', - 'Graca', - 'Enslow', - 'Bruff', - 'Hodgkin', - 'Coone', - 'Trippett', - 'Tippitt', - 'Sumerlin', - 'Carelock', - 'Whitelow', - 'Beightol', - 'Cappadona', - 'Carrizal', - 'Clendaniel', - 'Cresci', - 'Dietzman', - 'Figge', - 'Heyde', - 'Jarema', - 'Kyllonen', - 'Laminack', - 'Luddy', - 'Monical', - 'Mula', - 'Picotte', - 'Sandiego', - 'Seki', - 'Senner', - 'Starkman', - 'Stassi', - 'Stuckert', - 'Wiers', - 'Wieting', - 'Ziska', - 'Ardelean', - 'Hulslander', - 'Loewenstein', - 'Mearns', - 'Roese', - 'Sweaney', - 'Winick', - 'Zaring', - 'Farry', - 'Dulle', - 'Gunnerson', - 'Duden', - 'Arts', - 'Lame', - 'Mcquerry', - 'Smiles', - 'Pennick', - 'Adderly', - 'Becka', - 'Bluemel', - 'Bocek', - 'Bouwens', - 'Deren', - 'Dewitz', - 'Doland', - 'Ewton', - 'Funnell', - 'Gavel', - 'Haidar', - 'Kalkbrenner', - 'Kawashima', - 'Kueker', - 'Lutze', - 'Macareno', - 'Nenninger', - 'Schone', - 'Seever', - 'Sexauer', - 'Sibilia', - 'Sperrazza', - 'Vanderhoef', - 'Vanoss', - 'Werre', - 'Wotton', - 'Behney', - 'Bossart', - 'Ellithorpe', - 'Eyrich', - 'Fosco', - 'Fulginiti', - 'Grumbles', - 'Hoeger', - 'Kizziah', - 'Kloiber', - 'Kudo', - 'Majcher', - 'Stickels', - 'Stoler', - 'Umholtz', - 'Vasallo', - 'Wenker', - 'Wittmeyer', - 'Telesco', - 'Jha', - 'Maulding', - 'Campton', - 'Verble', - 'Mclure', - 'Bernardin', - 'Eison', - 'Coffie', - 'Ceesay', - 'Balakrishnan', - 'Barich', - 'Bigman', - 'Blumenstein', - 'Bonafede', - 'Cebulski', - 'Chesbro', - 'Cuaresma', - 'Demarino', - 'Derienzo', - 'Donmoyer', - 'Fairall', - 'Gelpi', - 'Giambra', - 'Hasselman', - 'Highlander', - 'Hunker', - 'Iyengar', - 'Kulaga', - 'Kuznicki', - 'Labus', - 'Limbert', - 'Molchan', - 'Neuharth', - 'Overgaard', - 'Paszkiewicz', - 'Plescia', - 'Redcay', - 'Ritzer', - 'Smirnov', - 'Valiquette', - 'Vannortwick', - 'Warstler', - 'Yantz', - 'Beardall', - 'Cimmino', - 'Crnkovich', - 'Konishi', - 'Kosowski', - 'Ragen', - 'Sebert', - 'Valla', - 'Venancio', - 'Maltez', - 'Skehan', - 'Abrantes', - 'Colfer', - 'Beman', - 'Wilhelmsen', - 'Wilking', - 'Rorer', - 'Shutes', - 'Albany', - 'Wearing', - 'Assefa', - 'Angeloni', - 'Bisher', - 'Blancett', - 'Briel', - 'Chiara', - 'Clearman', - 'Dengel', - 'Detert', - 'Fadely', - 'Flinders', - 'Garguilo', - 'Goes', - 'Hakimian', - 'Henehan', - 'Homewood', - 'Kalla', - 'Keirn', - 'Kerwood', - 'Laflam', - 'Lynskey', - 'Minhas', - 'Mow', - 'Olk', - 'Ostergaard', - 'Palecek', - 'Poirrier', - 'Raudenbush', - 'Schlottman', - 'Shatz', - 'Sieloff', - 'Stikeleather', - 'Swavely', - 'Tapanes', - 'Teehan', - 'Wendorff', - 'Wollner', - 'Bichsel', - 'Brandenburger', - 'Demattia', - 'Eggebrecht', - 'Koelzer', - 'Landrigan', - 'Morsch', - 'Pittinger', - 'Rewerts', - 'Schopf', - 'Tetro', - 'Westenberger', - 'Kieft', - 'Overy', - 'Cutrona', - 'Misa', - 'Erich', - 'Swapp', - 'Welchel', - 'Messa', - 'Ala', - 'Witbeck', - 'Mothershead', - 'Stofer', - 'Mcneice', - 'Ayling', - 'Zakaria', - 'Bu', - 'Rauf', - 'Richbourg', - 'Fristoe', - 'Dorch', - 'Mcclarin', - 'Privott', - 'Bonsu', - 'Ayson', - 'Bifulco', - 'Brungard', - 'Bub', - 'Budzynski', - 'Chizmar', - 'Coriz', - 'Corser', - 'Daughdrill', - 'Delre', - 'Elfers', - 'Fabrizi', - 'Gunawan', - 'Haecker', - 'Hammac', - 'Handwerk', - 'Larcom', - 'Liera', - 'Littlewood', - 'Luikart', - 'Pasquarella', - 'Radman', - 'Ranft', - 'Rigas', - 'Santin', - 'Sorbello', - 'Tayag', - 'Ureste', - 'Weidinger', - 'Yerena', - 'Aase', - 'Galyen', - 'Halferty', - 'Hindley', - 'Kunath', - 'Laprairie', - 'Oza', - 'Stohler', - 'Tokarczyk', - 'Yusupov', - 'Nogueras', - 'Jersey', - 'Eastes', - 'Agron', - 'Boso', - 'Kender', - 'Couse', - 'Moreta', - 'Larrow', - 'Degrace', - 'Sonier', - 'Tisdel', - 'Creque', - 'Esther', - 'Girtman', - 'Seraphin', - 'Wesby', - 'Kargbo', - 'Adjei', - 'Angeline', - 'Biby', - 'Brucks', - 'Bucaro', - 'Farman', - 'Gerdeman', - 'Hodsdon', - 'Hoying', - 'Kasperek', - 'Keinath', - 'Kidman', - 'Kleier', - 'Kuban', - 'Lacko', - 'Latourette', - 'Leffert', - 'Leonhart', - 'Mathern', - 'Ploss', - 'Poblano', - 'Raigoza', - 'Santor', - 'Schmitzer', - 'Sirico', - 'Skalsky', - 'Spreen', - 'Standlee', - 'Vonbargen', - 'Cederberg', - 'Cornforth', - 'Dercole', - 'Diblasio', - 'Fleer', - 'Fredlund', - 'Gehris', - 'Guck', - 'Lannen', - 'Lurz', - 'Mazzaferro', - 'Neukam', - 'Rookstool', - 'Scharrer', - 'Sevey', - 'Sicairos', - 'Skrocki', - 'Sneeringer', - 'Stefanowicz', - 'Zuleger', - 'Harmel', - 'Sendejo', - 'Bearer', - 'Shur', - 'Weers', - 'Norell', - 'Plotnick', - 'Cecchi', - 'Gandia', - 'Bastone', - 'Tole', - 'Tramell', - 'Willock', - 'Rhome', - 'Curington', - 'Rapley', - 'Hazley', - 'Todman', - 'Lathon', - 'Alperin', - 'Axtman', - 'Boeke', - 'Butson', - 'Cestaro', - 'Cosgriff', - 'Docter', - 'Eblin', - 'Filsinger', - 'Franzone', - 'Gareau', - 'Garfinkle', - 'Gatch', - 'Germosen', - 'Grzywacz', - 'Huesman', - 'Kasel', - 'Kazan', - 'Manalang', - 'Marando', - 'Marchio', - 'Massimino', - 'Mcneer', - 'Menger', - 'Milanese', - 'Monrreal', - 'Moretto', - 'Mulvany', - 'Petkus', - 'Rehling', - 'Rubbo', - 'Rudnik', - 'Settlemire', - 'Treon', - 'Yaklin', - 'Zittel', - 'Betzold', - 'Bohlin', - 'Churilla', - 'Conrath', - 'Ozbun', - 'Sciuto', - 'Stitz', - 'Sweigert', - 'Tamanaha', - 'Wallgren', - 'Eplin', - 'Ion', - 'Liford', - 'Orendorff', - 'Wootan', - 'Carmical', - 'Mince', - 'Stormes', - 'Lantry', - 'Sportsman', - 'Corron', - 'Padia', - 'Cunnington', - 'Pitta', - 'Ori', - 'Obara', - 'Gaultney', - 'Vanlue', - 'Emmitt', - 'Roddey', - 'Payen', - 'Elmi', - 'Culmer', - 'Mealing', - 'Allegra', - 'Bano', - 'Batterman', - 'Bickell', - 'Dager', - 'Drach', - 'Duchesneau', - 'Erdos', - 'Fedorko', - 'Fluhr', - 'Gassmann', - 'Gillig', - 'Goedert', - 'Golomb', - 'Hatler', - 'Jalali', - 'Joosten', - 'Koke', - 'Lausch', - 'Leisner', - 'Mallinger', - 'Marsolek', - 'Mashek', - 'Ognibene', - 'Oishi', - 'Outman', - 'Paganelli', - 'Passino', - 'Petrak', - 'Rosenwald', - 'Schroader', - 'Stehman', - 'Tenuta', - 'Todt', - 'Tritz', - 'Boerman', - 'Doeden', - 'Etcheverry', - 'Grissinger', - 'Gruenewald', - 'Lijewski', - 'Marcom', - 'Niebauer', - 'Rukavina', - 'Sakuma', - 'Woehrle', - 'Amores', - 'Krammes', - 'Shontz', - 'Bunning', - 'Widdowson', - 'Blankenburg', - 'Goans', - 'Longan', - 'Aboud', - 'Michelli', - 'Rivere', - 'Colla', - 'Lory', - 'Lougheed', - 'Wadel', - 'Chalkley', - 'Gaubert', - 'Goodlin', - 'Bommer', - 'Abbs', - 'Rashad', - 'Malachi', - 'Abrigo', - 'Akre', - 'Antolik', - 'Bachner', - 'Blegen', - 'Cona', - 'Diantonio', - 'Emde', - 'Enrico', - 'Follette', - 'Hagarty', - 'Hanser', - 'Hulsman', - 'Jelinski', - 'Kalisz', - 'Kolek', - 'Kough', - 'Ninneman', - 'Offield', - 'Perezgarcia', - 'Plude', - 'Printy', - 'Rosengrant', - 'Salminen', - 'Schamberger', - 'Teall', - 'Zipfel', - 'Bickler', - 'Casanas', - 'Holtzapple', - 'Sachdeva', - 'Scharnhorst', - 'Schnack', - 'Grode', - 'Strough', - 'Teare', - 'Korona', - 'Creelman', - 'Simper', - 'Marett', - 'Nadeem', - 'Pollet', - 'Eduardo', - 'Chipley', - 'Vanrossum', - 'Fabio', - 'Colona', - 'Whirley', - 'Hider', - 'Plaskett', - 'Trabue', - 'Gibert', - 'Cabiness', - 'Loyal', - 'Rayson', - 'Aloia', - 'Aukerman', - 'Broxterman', - 'Cada', - 'Catalanotto', - 'Condos', - 'Corriher', - 'Eliopoulos', - 'Furia', - 'Girolamo', - 'Haese', - 'Israelson', - 'Jaworowski', - 'Jirik', - 'Kalmar', - 'Leipold', - 'Lemmo', - 'Loja', - 'Loughmiller', - 'Matelski', - 'Mcrorie', - 'Moeckel', - 'Naill', - 'Raczka', - 'Rathgeber', - 'Shamoun', - 'Shannahan', - 'Simler', - 'Stamer', - 'Stonehocker', - 'Twersky', - 'Voeltz', - 'Willets', - 'Wolgamott', - 'Yamin', - 'Acri', - 'Dalgleish', - 'Ehrenreich', - 'Huish', - 'Huxley', - 'Pinkstaff', - 'Rincones', - 'Saric', - 'Shreiner', - 'Stitely', - 'Tippets', - 'Vanamburg', - 'Zbikowski', - 'Sharrett', - 'Suther', - 'Renta', - 'Balles', - 'Florentine', - 'Chrisley', - 'Offner', - 'Matheus', - 'Akens', - 'Dugue', - 'Rigaud', - 'Mohamud', - 'Magloire', - 'Stigger', - 'Andrist', - 'Chaudoin', - 'Clos', - 'Cragin', - 'Dinius', - 'Duignan', - 'Elk', - 'Frenz', - 'Frogge', - 'Giammarino', - 'Hackl', - 'Jaeckel', - 'Knieriem', - 'Lajara', - 'Lisak', - 'Luxton', - 'Merriott', - 'Montini', - 'Olender', - 'Orebaugh', - 'Orren', - 'Osika', - 'Sciascia', - 'Selvaggio', - 'Stoneback', - 'Sweis', - 'Torosyan', - 'Trupp', - 'Wardrip', - 'Wigle', - 'Beissel', - 'Brakke', - 'Carosella', - 'Dobek', - 'Eidem', - 'Homolka', - 'Kemery', - 'Kinderman', - 'Palla', - 'Puccini', - 'Szarek', - 'Vandehei', - 'Arca', - 'Jou', - 'Needs', - 'Habermann', - 'Hyle', - 'Jagoda', - 'Smigielski', - 'Guttierrez', - 'Awwad', - 'Maccormack', - 'Bassin', - 'Achee', - 'Demark', - 'Jardon', - 'Kelsoe', - 'Olear', - 'Comacho', - 'Rosetta', - 'Peddie', - 'Delsol', - 'Nwachukwu', - 'Bagdasarian', - 'Boehringer', - 'Bunke', - 'Burkhammer', - 'Delahoya', - 'Dietzen', - 'Ditmer', - 'Duchaine', - 'Felske', - 'Gumpert', - 'Hansson', - 'Hedeen', - 'Jalil', - 'Kalal', - 'Kanan', - 'Kaska', - 'Kaufer', - 'Knoff', - 'Kornblum', - 'Lanzi', - 'Obenchain', - 'Piatkowski', - 'Prugh', - 'Rima', - 'Shadduck', - 'Sodergren', - 'Spitzley', - 'Tauzin', - 'Weigelt', - 'Baldassarre', - 'Biglin', - 'Fuhriman', - 'Gaumond', - 'Ledvina', - 'Meckler', - 'Minteer', - 'Nesser', - 'Riederer', - 'Ruelle', - 'Turchi', - 'Alberg', - 'Vanderlip', - 'Halder', - 'Hop', - 'Larmon', - 'Bonfield', - 'Ketch', - 'Mannis', - 'Mcallen', - 'Alfonzo', - 'Sampey', - 'Guillet', - 'Madaris', - 'Lisby', - 'Crowner', - 'Frager', - 'Coar', - 'Crewe', - 'Levier', - 'Ligons', - 'Abello', - 'Brinsfield', - 'Buccieri', - 'Cantera', - 'Cieslinski', - 'Cragle', - 'Flater', - 'Grunert', - 'Higinbotham', - 'Janish', - 'Kuennen', - 'Lanners', - 'Lesiak', - 'Litvin', - 'Madueno', - 'Maffia', - 'Manetta', - 'Marschke', - 'Mourer', - 'Nordahl', - 'Nordan', - 'Pankowski', - 'Petron', - 'Qualley', - 'Recht', - 'Rosenbach', - 'Ruttenberg', - 'Saam', - 'Savarino', - 'Solana', - 'Stumpff', - 'Tsukamoto', - 'Vanlanen', - 'Wainer', - 'Kasza', - 'Kuehler', - 'Landgren', - 'Omahony', - 'Paullin', - 'Ramales', - 'Schmelzle', - 'Schnakenberg', - 'Touma', - 'Urgiles', - 'Vorndran', - 'Corne', - 'Higman', - 'Dutil', - 'Reef', - 'Racanelli', - 'Gladwin', - 'Jaspers', - 'Crutchley', - 'Homme', - 'Hughbanks', - 'Crismon', - 'Burdin', - 'Dise', - 'Enzor', - 'Hally', - 'Mccone', - 'Mckell', - 'Belo', - 'Moat', - 'Ijames', - 'Bussie', - 'Papillion', - 'Pratcher', - 'Baranek', - 'Bidlack', - 'Boyadjian', - 'Chern', - 'Conahan', - 'Dimuzio', - 'Erker', - 'Fregeau', - 'Gelsinger', - 'Gonzalo', - 'Heo', - 'Hoog', - 'Jovanovich', - 'Kaschak', - 'Kasik', - 'Katich', - 'Laible', - 'Mastel', - 'Muellner', - 'Pingleton', - 'Rexroth', - 'Schmitter', - 'Stick', - 'Strollo', - 'Traficante', - 'Veteto', - 'Wampole', - 'Winings', - 'Amalfitano', - 'Amiot', - 'Camaj', - 'Cuartas', - 'Drotar', - 'Eatherton', - 'Fioretti', - 'Fudala', - 'Gehrman', - 'Gittleman', - 'Heppe', - 'Maffucci', - 'Tammen', - 'Chovan', - 'Ginley', - 'Stipes', - 'Antigua', - 'Ironside', - 'Kuroda', - 'Lebar', - 'Laske', - 'Salay', - 'Gisi', - 'Mccormic', - 'Veron', - 'Robbin', - 'Morain', - 'Mayden', - 'Vanputten', - 'Triplet', - 'Ravenel', - 'Moragne', - 'Bowdry', - 'Agundez', - 'Allinson', - 'Bosko', - 'Buehrle', - 'Devey', - 'Gasiorowski', - 'Goettel', - 'Halleran', - 'Innocenti', - 'Orser', - 'Scarpati', - 'Scherff', - 'Schlott', - 'Skilling', - 'Speedy', - 'Staal', - 'Szafran', - 'Szczech', - 'Szczepanik', - 'Venturella', - 'Vert', - 'Vogelgesang', - 'Vollbrecht', - 'Wiehe', - 'Achterberg', - 'Fadness', - 'Groene', - 'Halbrooks', - 'Leavenworth', - 'Pruski', - 'Redifer', - 'Schmiesing', - 'Stanforth', - 'Stepanski', - 'Ziel', - 'Hefter', - 'Urman', - 'Muela', - 'Simpler', - 'Elick', - 'Shalabi', - 'Cooner', - 'Ferriera', - 'Templer', - 'Prashad', - 'Gorum', - 'Wheller', - 'Spratling', - 'Gutter', - 'Eke', - 'Rias', - 'Belcourt', - 'Bernards', - 'Camburn', - 'Cerqueira', - 'Conkel', - 'Deist', - 'Derobertis', - 'Desio', - 'Eimer', - 'Fayad', - 'Frommelt', - 'Guariglia', - 'Laba', - 'Labine', - 'Lanius', - 'Loconte', - 'Nop', - 'Omary', - 'Penninger', - 'Pentland', - 'Pinkus', - 'Richoux', - 'Sturrock', - 'Theil', - 'Vanvranken', - 'Bartoszek', - 'Bruski', - 'Engelken', - 'Kranich', - 'Mrazek', - 'Muralles', - 'Pienta', - 'Salido', - 'Sridhar', - 'Turkington', - 'Vellucci', - 'Verhage', - 'Derenzo', - 'Lucker', - 'Wands', - 'Parrow', - 'Branyon', - 'Houff', - 'Bossier', - 'Reels', - 'Rockmore', - 'Altmeyer', - 'Anacker', - 'Antoniou', - 'Berlinger', - 'Busser', - 'Caracci', - 'Caseres', - 'Corcino', - 'Demint', - 'Dhanani', - 'Erekson', - 'Farinacci', - 'Ganesan', - 'Gornick', - 'Gresser', - 'Kremers', - 'Kreuter', - 'Lesieur', - 'Linarez', - 'Mccrystal', - 'Morang', - 'Pucillo', - 'Spicuzza', - 'Tranchina', - 'Tullar', - 'Vantilburg', - 'Yeck', - 'Zandstra', - 'Zeleny', - 'Bearss', - 'Burgner', - 'Delich', - 'Fetsch', - 'Grom', - 'Kreisel', - 'Laprise', - 'Legarreta', - 'Musacchio', - 'Rembold', - 'Sjoblom', - 'Skalicky', - 'Sokolov', - 'Tuminello', - 'Vanskiver', - 'Zidek', - 'Severa', - 'Stables', - 'Guffy', - 'Lebeck', - 'Barradas', - 'Chanley', - 'Dayal', - 'Villafranco', - 'Droke', - 'Popwell', - 'Renier', - 'Bolten', - 'Mille', - 'Swagerty', - 'Grismore', - 'Brantly', - 'Divens', - 'Ottey', - 'Hagger', - 'Advincula', - 'Boschee', - 'Buckbee', - 'Carlan', - 'Casciato', - 'Cregar', - 'Fehring', - 'Ianniello', - 'Interrante', - 'Juedes', - 'Kosier', - 'Lizaola', - 'Lorenzetti', - 'Mccauslin', - 'Older', - 'Osuch', - 'Ramstad', - 'Sare', - 'Stavinoha', - 'Taborda', - 'Warmoth', - 'Weissmann', - 'Winograd', - 'Woeste', - 'Zywicki', - 'Blalack', - 'Chavoya', - 'Clickner', - 'Daigrepont', - 'Dissinger', - 'Kovalik', - 'Lemler', - 'Shortall', - 'Tucholski', - 'Vanmetre', - 'Zetino', - 'Niezgoda', - 'Recupero', - 'Booms', - 'Ramsburg', - 'Berka', - 'Mininger', - 'Tamer', - 'Baka', - 'Jago', - 'Bucks', - 'Laude', - 'Andrepont', - 'Gair', - 'Hayer', - 'Kitching', - 'Towson', - 'Slappey', - 'Syms', - 'Derico', - 'Badie', - 'Kenon', - 'Goffney', - 'Amigon', - 'Belsito', - 'Bergamo', - 'Caputi', - 'Delpilar', - 'Entsminger', - 'Gehres', - 'Geimer', - 'Hada', - 'Krolak', - 'Kruer', - 'Malaney', - 'Mancias', - 'Misiaszek', - 'Pring', - 'Salonga', - 'Schaefers', - 'Schmied', - 'Schwertfeger', - 'Scialabba', - 'Stemmer', - 'Stifter', - 'Suon', - 'Szczygiel', - 'Weisse', - 'Yackley', - 'Decasas', - 'Donado', - 'Drenning', - 'Eppich', - 'Kertesz', - 'Mihal', - 'Mochizuki', - 'Schiebel', - 'Schlageter', - 'Scruton', - 'Weckerly', - 'Wemhoff', - 'Wernette', - 'Zietz', - 'Iwanicki', - 'Ara', - 'Barson', - 'Resor', - 'Rampy', - 'Iskander', - 'Oharra', - 'Kope', - 'Soli', - 'Bodkins', - 'Bussa', - 'Maletta', - 'Clemen', - 'Vaneaton', - 'Berkel', - 'Salvage', - 'Gilchrest', - 'Whitter', - 'Bruster', - 'Mccowin', - 'Gullatt', - 'Cherubin', - 'Flamer', - 'Gueye', - 'Angerer', - 'Baray', - 'Barreca', - 'Bresson', - 'Brougham', - 'Buscaglia', - 'Candee', - 'Decelles', - 'Durflinger', - 'Dusenbery', - 'Enomoto', - 'Galliano', - 'Klooster', - 'Lowrimore', - 'Manda', - 'Morace', - 'Raisanen', - 'Ravenscraft', - 'Rutman', - 'Schmieg', - 'Schorsch', - 'Selim', - 'Stanchfield', - 'Stankowski', - 'Tolosa', - 'Uyeno', - 'Vancleef', - 'Kamdar', - 'Kazlauskas', - 'Kwasnik', - 'Pivonka', - 'Shrode', - 'Sellinger', - 'Deliz', - 'Longerbeam', - 'Schobert', - 'Shader', - 'Collister', - 'Curtright', - 'Franc', - 'Wakely', - 'Duree', - 'Laban', - 'Gascoigne', - 'Noy', - 'Hulon', - 'Michele', - 'Crowden', - 'Dolton', - 'Ryner', - 'Gene', - 'Tetterton', - 'Laffitte', - 'Laidler', - 'Hoston', - 'Akter', - 'Biebel', - 'Bohnenkamp', - 'Bottger', - 'Brecheisen', - 'Bumbarger', - 'Burgert', - 'Burtnett', - 'Coffing', - 'Corigliano', - 'Dault', - 'Dettinger', - 'Fenech', - 'Golaszewski', - 'Hernando', - 'Hoppel', - 'Kadrmas', - 'Khim', - 'Labrado', - 'Leh', - 'Michiels', - 'Milkovich', - 'Mosel', - 'Nestle', - 'Nunan', - 'Palomarez', - 'Peretz', - 'Perno', - 'Popowski', - 'Pottebaum', - 'Rallis', - 'Rase', - 'Rotramel', - 'Sokolik', - 'Sparlin', - 'Zipf', - 'Abruzzese', - 'Branin', - 'Cheslock', - 'Chimenti', - 'Czechowski', - 'Diveley', - 'Eisenbeis', - 'Eisenhut', - 'Friedt', - 'Gehlhausen', - 'Kamphaus', - 'Mctiernan', - 'Monnett', - 'Schue', - 'Steffensmeier', - 'Gens', - 'Schlotterbeck', - 'Ask', - 'Leser', - 'Renville', - 'Wisenbaker', - 'Kellow', - 'Mounsey', - 'Dupin', - 'Causer', - 'Yapp', - 'Stmary', - 'Bowditch', - 'Nickolson', - 'Molla', - 'Larke', - 'Kamau', - 'Cardinali', - 'Deely', - 'Deep', - 'Dietel', - 'Ferraris', - 'Fons', - 'Hahm', - 'Huy', - 'Imber', - 'Leichliter', - 'Longanecker', - 'Lordi', - 'Ludewig', - 'Maiolo', - 'Mckern', - 'Meyering', - 'Muhl', - 'Nylen', - 'Ohlendorf', - 'Palmgren', - 'Raffield', - 'Reusser', - 'Revette', - 'Ridolfi', - 'Rosemeyer', - 'Seber', - 'Silberberg', - 'Sitzmann', - 'Tayman', - 'Tygart', - 'Vertz', - 'Volkmer', - 'Bellemare', - 'Benanti', - 'Bialecki', - 'Biber', - 'Dipierro', - 'Dornbush', - 'Eichhorst', - 'Messana', - 'Neisen', - 'Ottoson', - 'Salmonson', - 'Turcott', - 'Vlachos', - 'Wojdyla', - 'Dagg', - 'Hernan', - 'Mannes', - 'Fent', - 'Tappen', - 'Hyers', - 'Gery', - 'Deam', - 'Channing', - 'Gesner', - 'Swaringen', - 'Lakins', - 'Cogbill', - 'Allsbrook', - 'Kennemore', - 'Sumrell', - 'Luma', - 'Rookard', - 'Shakoor', - 'Philbert', - 'Maragh', - 'Wordlaw', - 'Ofori', - 'Arseneault', - 'Arslanian', - 'Aydin', - 'Balthaser', - 'Bensch', - 'Boord', - 'Botting', - 'Brummet', - 'Cassiday', - 'Chubbuck', - 'Crance', - 'Dobis', - 'Dymek', - 'Kakar', - 'Kipnis', - 'Kooi', - 'Kovack', - 'Malzahn', - 'Melendes', - 'Micucci', - 'Miklas', - 'Molander', - 'Nungesser', - 'Razavi', - 'Reppond', - 'Reznick', - 'Rosten', - 'Schwegler', - 'Sielaff', - 'Sincavage', - 'Soave', - 'Socorro', - 'Tausch', - 'Tracz', - 'Vey', - 'Weltman', - 'Wittich', - 'Emswiler', - 'Etzkorn', - 'Kuchenbecker', - 'Lampi', - 'Pfahler', - 'Thronson', - 'Trefz', - 'Pont', - 'Hendrie', - 'Russon', - 'Coleson', - 'Gregori', - 'Herzfeld', - 'Tamas', - 'Oslin', - 'Warrell', - 'Basher', - 'Elizabeth', - 'Nickolas', - 'Prigmore', - 'Okray', - 'Cannedy', - 'Mercy', - 'Daigre', - 'Leggins', - 'Savannah', - 'Russaw', - 'Opoku', - 'Angier', - 'Behrle', - 'Budny', - 'Cislo', - 'Covalt', - 'Dershem', - 'Devincent', - 'Dhar', - 'Dombrosky', - 'Dragovich', - 'Drobny', - 'Fess', - 'Genthner', - 'Gierhart', - 'Hadzic', - 'Hehir', - 'Henle', - 'Heyd', - 'Hudlow', - 'Janko', - 'Kapral', - 'Kietzman', - 'Malburg', - 'Maret', - 'Mcever', - 'Sann', - 'Scheidel', - 'Schultheiss', - 'Sedita', - 'Sigl', - 'Starace', - 'Stoklosa', - 'Tainter', - 'Tamburrino', - 'Vankleeck', - 'Vannucci', - 'Wernecke', - 'Widmayer', - 'Agresti', - 'Boshell', - 'Dartt', - 'Dobkin', - 'Effertz', - 'Gaydosh', - 'Hocevar', - 'Kluger', - 'Mcguffee', - 'Pekala', - 'Tuchman', - 'Keylon', - 'Pletz', - 'Germond', - 'Keedy', - 'Meir', - 'Tromp', - 'Solly', - 'Baerga', - 'Jawad', - 'Chanda', - 'Scobie', - 'Snowball', - 'Pricer', - 'Graper', - 'Bally', - 'Mcfarlan', - 'Duncombe', - 'Mccory', - 'Costen', - 'Poplar', - 'Denkins', - 'Padmore', - 'Waithe', - 'Adduci', - 'Aldaba', - 'Berhow', - 'Cocuzza', - 'Dubroc', - 'Earnheart', - 'Eickholt', - 'Gutzwiller', - 'Heavin', - 'Himebaugh', - 'Jakubik', - 'Kiang', - 'Klusman', - 'Knueppel', - 'Neddo', - 'Oakey', - 'Rachlin', - 'Spegal', - 'Spizzirri', - 'Stavola', - 'Zika', - 'Beverlin', - 'Boehle', - 'Caltagirone', - 'Chernick', - 'Ciaccia', - 'Courchaine', - 'Covault', - 'Crihfield', - 'Fojtik', - 'Gronski', - 'Huwe', - 'Ostrovsky', - 'Quraishi', - 'Rauber', - 'Scalici', - 'Schuetze', - 'Advani', - 'Galer', - 'Rog', - 'Husson', - 'Karpen', - 'Ess', - 'Henman', - 'Slatten', - 'Bango', - 'Barkin', - 'Vessell', - 'Mayson', - 'Kittles', - 'Quince', - 'Beardmore', - 'Breceda', - 'Carmony', - 'Ciliberto', - 'Cotroneo', - 'Dimitroff', - 'Granahan', - 'Haacke', - 'Huska', - 'Jankiewicz', - 'Klipp', - 'Kostic', - 'Langarica', - 'Lanphier', - 'Maran', - 'Marmion', - 'Mclinden', - 'Mcpeake', - 'Minkel', - 'Nicolo', - 'Quihuis', - 'Siemsen', - 'Somero', - 'Spuhler', - 'Spychalski', - 'Stary', - 'Stitzer', - 'Stucke', - 'Tango', - 'Ticas', - 'Vivero', - 'Campen', - 'Fei', - 'Ganas', - 'Klipfel', - 'Vodicka', - 'Zajdel', - 'Ulin', - 'Bodey', - 'Moral', - 'Fellenz', - 'Charo', - 'Cliver', - 'Clasby', - 'Neeson', - 'Durell', - 'Hew', - 'Mcgray', - 'Breaker', - 'Haslem', - 'Verser', - 'Broner', - 'Mannings', - 'Darensbourg', - 'Petithomme', - 'Akbari', - 'Amdahl', - 'Boeger', - 'Bougie', - 'Buffo', - 'Cisar', - 'Deleonardis', - 'Diffee', - 'Dillen', - 'Dingley', - 'Dugo', - 'Fedora', - 'Habibi', - 'Hartland', - 'Hennelly', - 'Kachmar', - 'Louth', - 'Mughal', - 'Muska', - 'Narang', - 'Pontillo', - 'Roel', - 'Shehorn', - 'Smick', - 'Soliven', - 'Starzyk', - 'Swaminathan', - 'Teagarden', - 'Thune', - 'Vokes', - 'Volkov', - 'Weckesser', - 'Wigen', - 'Donaghue', - 'Ederer', - 'Glaus', - 'Gwozdz', - 'Kimler', - 'Kocak', - 'Lagerquist', - 'Pellecchia', - 'Ruminski', - 'Scholler', - 'Steurer', - 'Tlatelpa', - 'Zegarra', - 'Janssens', - 'Jass', - 'Ciriaco', - 'Kessner', - 'Georg', - 'Harre', - 'Brannam', - 'Beel', - 'Kaine', - 'Roher', - 'Evora', - 'Rittman', - 'Sion', - 'Millon', - 'Morre', - 'Bouler', - 'Seegars', - 'Jenifer', - 'Bernd', - 'Chahine', - 'Crisanto', - 'Desautel', - 'Dirosa', - 'Fehringer', - 'Fukui', - 'Hetz', - 'Hueber', - 'Ivanova', - 'Klecker', - 'Kulzer', - 'Machi', - 'Menn', - 'Mudry', - 'Niro', - 'Nyenhuis', - 'Pressel', - 'Prusinski', - 'Roske', - 'Shaefer', - 'Stear', - 'Stumpo', - 'Teas', - 'Tolsma', - 'Troha', - 'Vanveen', - 'Waltermire', - 'Zaretsky', - 'Zingg', - 'Arntson', - 'Dizdarevic', - 'Kassebaum', - 'Natzke', - 'Passanisi', - 'Rodebaugh', - 'Skonieczny', - 'Vanhoozer', - 'Wiechert', - 'Golonka', - 'Roycroft', - 'Robl', - 'Lisboa', - 'Brandis', - 'Symmes', - 'Nou', - 'Pawson', - 'Comins', - 'Ranker', - 'Silman', - 'Lonas', - 'Goldthwaite', - 'Aries', - 'Leckey', - 'Conolly', - 'Ezelle', - 'Degrasse', - 'Tarte', - 'Bonaventure', - 'Rambeau', - 'Alsobrooks', - 'Blumenberg', - 'Snape', - 'Delane', - 'Sarr', - 'Rankine', - 'Mcclarty', - 'Skipwith', - 'Mapps', - 'Poke', - 'Ahlman', - 'Brunkow', - 'Crissinger', - 'Critcher', - 'Cronce', - 'Earney', - 'Fischler', - 'Franta', - 'Haist', - 'Hirschfield', - 'Jacobe', - 'Karraker', - 'Kronenberger', - 'Layland', - 'Liscano', - 'Lohrman', - 'Luy', - 'Macik', - 'Makinen', - 'Mis', - 'Musarra', - 'Orbe', - 'Ortloff', - 'Potempa', - 'Presta', - 'Rebollo', - 'Rudden', - 'Schab', - 'Settlemyre', - 'Shaban', - 'Shiraishi', - 'Shrake', - 'Suba', - 'Tornquist', - 'Treglia', - 'Vanschaick', - 'Velten', - 'Waln', - 'Addeo', - 'Dacquisto', - 'Fenno', - 'Gilberg', - 'Halberstam', - 'Holck', - 'Landgrebe', - 'Lipa', - 'Luehrs', - 'Mkrtchyan', - 'Proscia', - 'Schucker', - 'Selner', - 'Sinisi', - 'Wandersee', - 'Weigold', - 'Winterrowd', - 'Stoutenburg', - 'Medinger', - 'Bittman', - 'Gerges', - 'Langelier', - 'Berdine', - 'Hartshorne', - 'Matters', - 'Lavere', - 'Delauter', - 'Caillouet', - 'Elford', - 'Derrington', - 'Mollison', - 'Erskin', - 'Doswell', - 'Loadholt', - 'Stepter', - 'Contee', - 'Adwell', - 'Banez', - 'Birchler', - 'Bodman', - 'Bransfield', - 'Butzer', - 'Cenci', - 'Fabro', - 'Fila', - 'Follman', - 'Geoffrion', - 'Hardegree', - 'Klindt', - 'Kuzniar', - 'Lapenta', - 'Lasorsa', - 'Lykens', - 'Madariaga', - 'Mcginnity', - 'Mezger', - 'Milleson', - 'Nisly', - 'Palau', - 'Salz', - 'Sholly', - 'Spartz', - 'Spevak', - 'Svehla', - 'Trafford', - 'Treu', - 'Winski', - 'Zervas', - 'Bautch', - 'Dybas', - 'Hillenburg', - 'Krahl', - 'Loretto', - 'Mcanany', - 'Meschke', - 'Panuco', - 'Pezzullo', - 'Pokorski', - 'Reinertson', - 'Spoden', - 'Steinbrenner', - 'Wedig', - 'Mom', - 'Furner', - 'Harpin', - 'Carlston', - 'Oo', - 'Betten', - 'Duro', - 'Veronica', - 'Klutz', - 'Coven', - 'Siles', - 'Carby', - 'Duvernay', - 'Gory', - 'Adamczak', - 'Adee', - 'Agius', - 'Bachicha', - 'Belka', - 'Bridenstine', - 'Cappella', - 'Chiao', - 'Georgiadis', - 'Hansmann', - 'Kettlewell', - 'Klemann', - 'Kracke', - 'Legacy', - 'Mateja', - 'Mcgarrigle', - 'Peitz', - 'Pergande', - 'Proia', - 'Reicher', - 'Rentfrow', - 'Rudkin', - 'Sahni', - 'Santopietro', - 'Sarin', - 'Schear', - 'Seckel', - 'Sopp', - 'Sorci', - 'Terbush', - 'Uplinger', - 'Vantol', - 'Zaro', - 'Cuppett', - 'Depetro', - 'Hofferber', - 'Kreifels', - 'Kuznetsov', - 'Matassa', - 'Mazanec', - 'Naegle', - 'Sphar', - 'Villaneda', - 'Wachholz', - 'Pastrano', - 'Pilotte', - 'Shedden', - 'Molt', - 'Dalia', - 'Bishara', - 'Dumoulin', - 'Dehnert', - 'Dilmore', - 'Termine', - 'Bracher', - 'Laplace', - 'Sherin', - 'Morine', - 'Garrott', - 'Banford', - 'Drumwright', - 'Linnen', - 'Belay', - 'Juste', - 'Moment', - 'Adamec', - 'Alessandrini', - 'Bolda', - 'Buonanno', - 'Corrow', - 'Couvillon', - 'Dahnke', - 'Durrani', - 'Errett', - 'Fingerhut', - 'Ittner', - 'Kandler', - 'Khosla', - 'Mascio', - 'Mesch', - 'Napolitan', - 'Packman', - 'Parady', - 'Saline', - 'Spatafore', - 'Squiers', - 'Stailey', - 'Stolar', - 'Strommen', - 'Vahey', - 'Vanbebber', - 'Wimpee', - 'Wolinsky', - 'Yambao', - 'Ciocca', - 'Fornwalt', - 'Giannattasio', - 'Herbers', - 'Korol', - 'Lindenberger', - 'Lysne', - 'Piacentini', - 'Vogeler', - 'Cassetta', - 'Hildebran', - 'Masoud', - 'Shiller', - 'Fisler', - 'Loll', - 'Wattles', - 'Carris', - 'Hippe', - 'Torregrossa', - 'Thain', - 'Enman', - 'Kanno', - 'Jeane', - 'Clendenning', - 'Halt', - 'Dorin', - 'Carnathan', - 'Bisch', - 'Simm', - 'Goatley', - 'July', - 'Oke', - 'Basley', - 'Dillahunt', - 'Times', - 'Mcglown', - 'Cohens', - 'Jeanphilippe', - 'Benshoof', - 'Bensing', - 'Bir', - 'Birnie', - 'Burklow', - 'Capili', - 'Cordts', - 'Falanga', - 'Farooqui', - 'Furber', - 'Godino', - 'Gollnick', - 'Harmening', - 'Hilpert', - 'Hrivnak', - 'Iribe', - 'Krienke', - 'Kuntzman', - 'Laslo', - 'Loso', - 'Omohundro', - 'Rabadi', - 'Reisenauer', - 'Rohrich', - 'Salak', - 'Schuckman', - 'Semmel', - 'Sendelbach', - 'Sidler', - 'Stegmann', - 'Sudbeck', - 'Tara', - 'Walcher', - 'Walkenhorst', - 'Wellbrock', - 'Capaldo', - 'Cotnoir', - 'Durrence', - 'Fralix', - 'Leibfried', - 'Schlarb', - 'Whitenight', - 'Grannan', - 'Mugford', - 'Filo', - 'Soh', - 'Deprez', - 'Semidey', - 'Vandivier', - 'Shawl', - 'Happy', - 'Gartley', - 'Jonathan', - 'Bouquet', - 'Warsaw', - 'Verne', - 'Furse', - 'Holms', - 'Bassette', - 'Fishburne', - 'Ambrosius', - 'Amrein', - 'Astorino', - 'Bedonie', - 'Bibee', - 'Brearley', - 'Chesher', - 'Colasurdo', - 'Deike', - 'Dimarino', - 'Felling', - 'Freid', - 'Gad', - 'Gambale', - 'Gieser', - 'Greff', - 'Halseth', - 'Hamor', - 'Hargens', - 'Hohenberger', - 'Hohler', - 'Illes', - 'Koscielniak', - 'Kotara', - 'Krygier', - 'Lopinto', - 'Mangas', - 'Mantione', - 'Mcendree', - 'Musich', - 'Nordling', - 'Panagopoulos', - 'Pollio', - 'Score', - 'Semaan', - 'Tortorelli', - 'Trabert', - 'Troung', - 'Vittorio', - 'Barkdoll', - 'Dombeck', - 'Ferriter', - 'Gancarz', - 'Gubbels', - 'Kertz', - 'Langenderfer', - 'Roppolo', - 'Siglin', - 'Trnka', - 'Vanderkooi', - 'Yaun', - 'Witkin', - 'Caryl', - 'Boies', - 'Carattini', - 'Hannes', - 'Harmison', - 'Mctavish', - 'Bille', - 'Sullivant', - 'Yeakey', - 'Respess', - 'Gooley', - 'Maura', - 'Jukes', - 'Oguin', - 'Demory', - 'Morson', - 'Hathorne', - 'Anklam', - 'Antaya', - 'Bentler', - 'Bettcher', - 'Bresette', - 'Broadrick', - 'Degante', - 'Demaray', - 'Dipinto', - 'Doberstein', - 'Dorminey', - 'Dorwart', - 'Gugliuzza', - 'Jesser', - 'Kjar', - 'Kujala', - 'Lemarr', - 'Lynds', - 'Novitsky', - 'Oropesa', - 'Scarpulla', - 'Schave', - 'Siravo', - 'Torma', - 'Uva', - 'Winkowski', - 'Boscia', - 'Buikema', - 'Byland', - 'Enneking', - 'Enstrom', - 'Gotsch', - 'Kulakowski', - 'Mattheis', - 'Niemuth', - 'Oberdorf', - 'Rabuck', - 'Shinners', - 'Struebing', - 'Dickes', - 'Hettrick', - 'Pille', - 'Vilar', - 'Blewitt', - 'Gutt', - 'Haseley', - 'Pennel', - 'Figuereo', - 'Lassalle', - 'Tannahill', - 'Teats', - 'Mumby', - 'Cheves', - 'Spark', - 'Ale', - 'Wally', - 'Lowndes', - 'Ballo', - 'Couper', - 'Alberta', - 'Puller', - 'Rochell', - 'Bachar', - 'Ballengee', - 'Bellizzi', - 'Boback', - 'Cammarano', - 'Dirr', - 'Findling', - 'Fruin', - 'Ghattas', - 'Kaliszewski', - 'Kammeyer', - 'Kwiecien', - 'Lamora', - 'Lehrke', - 'Macewen', - 'Nasta', - 'Neibert', - 'Ogaz', - 'Olesky', - 'Otano', - 'Prescher', - 'Romick', - 'Scibetta', - 'Slicker', - 'Ungerer', - 'Vanheel', - 'Wadas', - 'Weissert', - 'Armiger', - 'Brusca', - 'Christeson', - 'Crookshanks', - 'Demarinis', - 'Fahrney', - 'Heiple', - 'Howat', - 'Knoedler', - 'Kuske', - 'Leifheit', - 'Lukach', - 'Nauert', - 'Obremski', - 'Seidenberg', - 'Smigelski', - 'Visscher', - 'Wauneka', - 'Whitmoyer', - 'Wyand', - 'Ilardi', - 'Jackel', - 'Rackham', - 'Macgowan', - 'Braid', - 'Bringle', - 'Dirk', - 'Paci', - 'Wears', - 'Vanbergen', - 'Sidle', - 'Mellish', - 'Paino', - 'State', - 'Cargle', - 'Harcum', - 'Beyene', - 'Mwangi', - 'Anderle', - 'Cancienne', - 'Compeau', - 'Egle', - 'Farone', - 'Harke', - 'Hollopeter', - 'Jambor', - 'Jermyn', - 'Kadakia', - 'Kerker', - 'Langowski', - 'Lechman', - 'Nagengast', - 'Narvaiz', - 'Paola', - 'Partch', - 'Plucker', - 'Rawe', - 'Rohland', - 'Rosebrook', - 'Stanphill', - 'Stoltman', - 'Volkers', - 'Balingit', - 'Bausman', - 'Besler', - 'Dalto', - 'Edgren', - 'Hairfield', - 'Janek', - 'Kenoyer', - 'Koska', - 'Mihok', - 'Monjaraz', - 'Reisz', - 'Snedegar', - 'Vandezande', - 'Viscomi', - 'Kiene', - 'Dib', - 'Kuc', - 'Magley', - 'Swearingin', - 'Culliton', - 'Roome', - 'Fendrick', - 'Trindade', - 'Whaling', - 'Tarbutton', - 'Sider', - 'Swingler', - 'Lover', - 'Clarida', - 'Jocelyn', - 'Mervin', - 'Blaize', - 'Semper', - 'Bagsby', - 'Pree', - 'Dieujuste', - 'Anacleto', - 'Annable', - 'Bacci', - 'Bottari', - 'Cinco', - 'Delzell', - 'Dowless', - 'Drilling', - 'Egert', - 'Fanton', - 'Geerts', - 'Ghaffari', - 'Guggenheim', - 'Hankes', - 'Hediger', - 'Hornig', - 'Kauer', - 'Kossman', - 'Krasnow', - 'Lauman', - 'Lebsack', - 'Liendo', - 'Marhefka', - 'Noguez', - 'Oxman', - 'Pa', - 'Pella', - 'Pongratz', - 'Prisk', - 'Rajagopalan', - 'Rozo', - 'Vanvorst', - 'Wachob', - 'Avolio', - 'Banet', - 'Boissonneault', - 'Coglianese', - 'Crudele', - 'Dobratz', - 'Gerdts', - 'Koors', - 'Mazzanti', - 'Ozimek', - 'Vanhove', - 'Zern', - 'Kalama', - 'Mikelson', - 'Renehan', - 'Blecher', - 'Meath', - 'Bonus', - 'Wesch', - 'Kirkey', - 'Goldbeck', - 'Hun', - 'Morgans', - 'Strohman', - 'Lanagan', - 'Wyly', - 'Syers', - 'Berne', - 'Tondreau', - 'Witts', - 'Budhu', - 'Flott', - 'Alsbrooks', - 'Mabin', - 'Kingsberry', - 'Berend', - 'Brandeberry', - 'Carandang', - 'Ciavarella', - 'Foil', - 'Galano', - 'Garzia', - 'Golembeski', - 'Kossow', - 'Kren', - 'Lefave', - 'Macmahon', - 'Nilan', - 'Peregrina', - 'Pralle', - 'Sahakian', - 'Sarate', - 'Scalzi', - 'Soulliere', - 'Srock', - 'Stammen', - 'Sterry', - 'Tadych', - 'Trembath', - 'Watwood', - 'Wolske', - 'Woolson', - 'Aversano', - 'Chavana', - 'Digiuseppe', - 'Escano', - 'Harkrider', - 'Liebmann', - 'Soldan', - 'Swiatkowski', - 'Tomala', - 'Keay', - 'Lindstedt', - 'Maille', - 'Thurner', - 'Favia', - 'Guedes', - 'Simao', - 'Rambow', - 'Chriscoe', - 'Hiss', - 'Mcraney', - 'Barke', - 'Hobday', - 'Buri', - 'Sigle', - 'Bawa', - 'Lalande', - 'Bordon', - 'Friley', - 'Feild', - 'Arington', - 'Jons', - 'Funderburke', - 'Mccommons', - 'Troublefield', - 'Mable', - 'Hullum', - 'Wrice', - 'Cager', - 'Barse', - 'Braunschweig', - 'Dasch', - 'Fraioli', - 'Giefer', - 'Giovanniello', - 'Glahn', - 'Hatheway', - 'Holtrop', - 'Katsaros', - 'Koetting', - 'Malinoski', - 'Markov', - 'Mcclosky', - 'Mccormac', - 'Mertins', - 'Milito', - 'Mroczka', - 'Overdorf', - 'Palombi', - 'Peninger', - 'Provenza', - 'Quinnell', - 'Roady', - 'Ruthven', - 'Savitsky', - 'Shenefield', - 'Stapel', - 'Venkataraman', - 'Zachow', - 'Aaberg', - 'Bajorek', - 'Bankowski', - 'Barquero', - 'Delcamp', - 'Deshler', - 'Halili', - 'Hebenstreit', - 'Hirota', - 'Hladky', - 'Kliethermes', - 'Koestner', - 'Kroes', - 'Luepke', - 'Mckeough', - 'Mielcarek', - 'Nobis', - 'Olenik', - 'Plessinger', - 'Shillingburg', - 'Spadaccini', - 'Springborn', - 'Werden', - 'Willenbring', - 'Zyskowski', - 'Paucar', - 'Werst', - 'Wohlwend', - 'Nauss', - 'Alma', - 'Tebeau', - 'Paskett', - 'Spindle', - 'Twiddy', - 'Alomar', - 'Mi', - 'Billard', - 'Bails', - 'Channer', - 'Fripp', - 'Abreo', - 'Adamowicz', - 'Bocian', - 'Breden', - 'Breitkreutz', - 'Celona', - 'Chizek', - 'Chrestman', - 'Ciaramella', - 'Compher', - 'Crannell', - 'Dermer', - 'Duryee', - 'Feuerborn', - 'Garrels', - 'Gausman', - 'Grippi', - 'Guadamuz', - 'Hatlestad', - 'Heon', - 'Hokenson', - 'Kaden', - 'Kluever', - 'Lagares', - 'Mamone', - 'Mascola', - 'Matich', - 'Messimer', - 'Mezera', - 'Mongiello', - 'Moradi', - 'Nessler', - 'Nijjar', - 'Nin', - 'Pasquarelli', - 'Pawlowicz', - 'Petitto', - 'Petruccelli', - 'Pullano', - 'Rebar', - 'Romack', - 'Rosener', - 'Soland', - 'Solow', - 'Vandervelden', - 'Vazguez', - 'Vonruden', - 'Balmes', - 'Berninger', - 'Broecker', - 'Clogston', - 'Fontanella', - 'Gubbins', - 'Kampen', - 'Levenhagen', - 'Lyter', - 'Nagamine', - 'Regas', - 'Riecke', - 'Veltre', - 'Wojahn', - 'Angelino', - 'Mccomber', - 'Grisso', - 'Saran', - 'Pecore', - 'Sorter', - 'Encalada', - 'Robart', - 'Deerman', - 'Lori', - 'Mcnee', - 'Dagher', - 'Villars', - 'Chaplain', - 'Houtman', - 'Dingwall', - 'Akerson', - 'Donaway', - 'Dimmer', - 'Mittman', - 'Camm', - 'Kenedy', - 'Bilbro', - 'Brocks', - 'Mansaray', - 'Acebo', - 'Ahr', - 'Alayon', - 'Benyo', - 'Blatnik', - 'Degidio', - 'Dumire', - 'Elefante', - 'Gase', - 'Gilboy', - 'Gradillas', - 'Haverstock', - 'Heberle', - 'Hilmes', - 'Hjort', - 'Johnsey', - 'Lambiase', - 'Marland', - 'Mcevilly', - 'Mergenthaler', - 'Mini', - 'Noska', - 'Patrie', - 'Rohrback', - 'Seelbach', - 'Stopher', - 'Trzaska', - 'Vanessen', - 'Veillette', - 'Walizer', - 'Zapalac', - 'Andalon', - 'Beukema', - 'Cieslik', - 'Dukart', - 'Gerads', - 'Gilhooly', - 'Hinebaugh', - 'Jumonville', - 'Macchi', - 'Oldenkamp', - 'Plotz', - 'Robideau', - 'Streed', - 'Trochez', - 'Grames', - 'Beltram', - 'Fishbaugh', - 'Lais', - 'Ossa', - 'Wilden', - 'Erick', - 'Dosier', - 'Trust', - 'Swaine', - 'Darity', - 'Mccroy', - 'Yuille', - 'Cantave', - 'Barsanti', - 'Carbonara', - 'Cavanah', - 'Chrismer', - 'Cuestas', - 'Czaplewski', - 'Denes', - 'Dorio', - 'Geraldo', - 'Giebler', - 'Goewey', - 'Gorniak', - 'Grabe', - 'Guidera', - 'Hannig', - 'Herin', - 'Kadow', - 'Klauer', - 'Kleppinger', - 'Lerro', - 'Manoogian', - 'Mentzel', - 'Muramoto', - 'Ollinger', - 'Pacey', - 'Pufahl', - 'Quero', - 'Revuelta', - 'Rickles', - 'Rudie', - 'Ruggerio', - 'Salberg', - 'Schwoerer', - 'Stephani', - 'Stevick', - 'Strada', - 'Thorley', - 'Thrun', - 'Virts', - 'Wingett', - 'Balfe', - 'Branaman', - 'Brookshier', - 'Carlsson', - 'Chismar', - 'Habben', - 'Migdal', - 'Ozga', - 'Rivest', - 'Russman', - 'Schellhorn', - 'Staup', - 'Pietri', - 'Welby', - 'Cisney', - 'Hijazi', - 'Brines', - 'Calderin', - 'Mudrick', - 'Domine', - 'Parlow', - 'Ervine', - 'Banis', - 'Mathenia', - 'Carbin', - 'Rashed', - 'Mcgilvery', - 'Prichett', - 'Feimster', - 'Smoots', - 'Persley', - 'Desire', - 'Abadi', - 'Bercaw', - 'Bertz', - 'Bibian', - 'Brosious', - 'Brunken', - 'Calvano', - 'Chenette', - 'Chiusano', - 'Dendinger', - 'Diffley', - 'Eichenberg', - 'Gawne', - 'Gelardi', - 'Gottman', - 'Gulyas', - 'Hak', - 'Haydock', - 'Hettler', - 'Hinsch', - 'Kozlik', - 'Krebbs', - 'Krichbaum', - 'Loges', - 'Lyssy', - 'Mitnick', - 'Podolski', - 'Priego', - 'Radhakrishnan', - 'Reineck', - 'Ruggirello', - 'Samborski', - 'Schwalb', - 'Sitek', - 'Sprinkel', - 'Tkachuk', - 'Viscuso', - 'Working', - 'Zinner', - 'Anspaugh', - 'Anthes', - 'Bratsch', - 'Breining', - 'Cejka', - 'Delbuono', - 'Hugill', - 'Huyett', - 'Irlbeck', - 'Kilgus', - 'Langwell', - 'Margulis', - 'Meara', - 'Napierala', - 'Stanaway', - 'Worton', - 'Gaucher', - 'Bakeman', - 'Pasos', - 'Feazel', - 'Evitt', - 'Marrin', - 'Baskette', - 'Orne', - 'Ivens', - 'Burnstein', - 'Rodell', - 'Bowell', - 'Maraj', - 'Lango', - 'Boudoin', - 'Wider', - 'Walkins', - 'Raheem', - 'Talford', - 'Jeanmarie', - 'Drumgoole', - 'Arnot', - 'Bennick', - 'Buchinger', - 'Cleven', - 'Corsello', - 'Delucchi', - 'Dicocco', - 'Eachus', - 'Eilts', - 'Fandino', - 'Fyke', - 'Giammarco', - 'Gwartney', - 'Hawken', - 'Henkelman', - 'Jaggi', - 'Jurczyk', - 'Kamman', - 'Kattner', - 'Keator', - 'Klus', - 'Leidner', - 'Ligas', - 'Martus', - 'Maslow', - 'Piccinini', - 'Pysher', - 'Riga', - 'Siek', - 'Sizelove', - 'Vanostrand', - 'Vastine', - 'Viviani', - 'Youngerman', - 'Zahniser', - 'Brigante', - 'Burklund', - 'Cajina', - 'Coppolino', - 'Goytia', - 'Icenhower', - 'Ihnen', - 'Jablonsky', - 'Koepsell', - 'Mennenga', - 'Redenius', - 'Tengan', - 'Weishaupt', - 'Dorst', - 'Kief', - 'Busk', - 'Luba', - 'Quine', - 'Deshotels', - 'Roulston', - 'Diniz', - 'Chandley', - 'Saleeby', - 'Maro', - 'Faidley', - 'Burrous', - 'Ilyas', - 'Roster', - 'Clovis', - 'Bacot', - 'Pembleton', - 'Bellot', - 'Entzminger', - 'Ryce', - 'Posley', - 'Alvi', - 'Audino', - 'Bitters', - 'Boomershine', - 'Boyack', - 'Branda', - 'Bresnan', - 'Brusco', - 'Bunda', - 'Catanzarite', - 'Dohmen', - 'Elbaum', - 'Farago', - 'Ferrentino', - 'Gimpel', - 'Grzeskowiak', - 'Gutting', - 'Henandez', - 'Herbeck', - 'Hoben', - 'Hunnell', - 'Ibbotson', - 'Kida', - 'Kirchman', - 'Kubin', - 'Laplume', - 'Laskin', - 'Lefferts', - 'Leimer', - 'Locatelli', - 'Pitsenbarger', - 'Reum', - 'Rittgers', - 'Scadden', - 'Shammas', - 'Tatge', - 'Tiongson', - 'Wengler', - 'Wenrick', - 'Wortley', - 'Bretado', - 'Detloff', - 'Dlugosz', - 'Eisemann', - 'Embler', - 'Graffius', - 'Kienast', - 'Kucher', - 'Larew', - 'Lemmerman', - 'Maners', - 'Peckinpaugh', - 'Rupnow', - 'Schubring', - 'Staheli', - 'Stege', - 'Talwar', - 'Truszkowski', - 'Coda', - 'Comunale', - 'Holtry', - 'Newfield', - 'Blankley', - 'Devino', - 'Wahba', - 'Cathell', - 'Timson', - 'Setzler', - 'Shacklett', - 'Nicols', - 'Rocque', - 'Nest', - 'Freelove', - 'Neat', - 'Kina', - 'Caslin', - 'Creal', - 'Wyre', - 'Compere', - 'Brisker', - 'Givhan', - 'Menifee', - 'Hymon', - 'Boakye', - 'Aguillar', - 'Alpern', - 'Antico', - 'Attridge', - 'Bjorge', - 'Bordwell', - 'Brumbach', - 'Castronova', - 'Cowher', - 'Fakhouri', - 'Hanigan', - 'Heidecker', - 'Hosick', - 'Lorang', - 'Magadan', - 'Marovich', - 'Masur', - 'Nienow', - 'Passow', - 'Priola', - 'Prose', - 'Radillo', - 'Saracco', - 'Schlender', - 'Sellards', - 'Stirn', - 'Strathman', - 'Supan', - 'Taguchi', - 'Tufte', - 'Vanderleest', - 'Vanderpoel', - 'Vondra', - 'Wayment', - 'Wisinski', - 'Brodowski', - 'Cichowski', - 'Delarocha', - 'Demyan', - 'Dobies', - 'Hegner', - 'Karapetian', - 'Konieczka', - 'Lazarz', - 'Loughner', - 'Portanova', - 'Rosentreter', - 'Rothlisberger', - 'Schropp', - 'Trenkamp', - 'Flaharty', - 'Murfin', - 'Waner', - 'Baiz', - 'Dunegan', - 'Gillson', - 'Erne', - 'Mahin', - 'Hardgrave', - 'Felps', - 'Bevens', - 'Abdou', - 'Songy', - 'Boule', - 'Wisham', - 'Devonshire', - 'Havis', - 'Relf', - 'Pean', - 'Manago', - 'Brazzle', - 'Mckelvin', - 'Goulbourne', - 'Pinkins', - 'Yelder', - 'Akina', - 'Allerton', - 'Aminov', - 'Barsamian', - 'Biondolillo', - 'Bouchillon', - 'Bustle', - 'Dolney', - 'Dunkerley', - 'Farha', - 'Floor', - 'Gaustad', - 'Gilberti', - 'Helder', - 'Kolber', - 'Kuznia', - 'Longhi', - 'Mamaril', - 'Milhorn', - 'Mozo', - 'Norbury', - 'Okano', - 'Perkovich', - 'Rafanan', - 'Rulo', - 'Ruperto', - 'Scow', - 'Shadoan', - 'Smisek', - 'Steinfeldt', - 'Thobe', - 'Venturino', - 'Widell', - 'Broccoli', - 'Helmig', - 'Koegler', - 'Lewandoski', - 'Pequignot', - 'Radermacher', - 'Resetar', - 'Rostro', - 'Sebald', - 'Walgren', - 'Lottes', - 'Capraro', - 'Grine', - 'Gordner', - 'Crus', - 'Easom', - 'Bayle', - 'Barts', - 'Duguid', - 'Estel', - 'Peggs', - 'Cheaney', - 'Rossin', - 'Mackel', - 'Vassel', - 'Fils', - 'Senat', - 'Alarie', - 'Allar', - 'Brownlie', - 'Bumbaugh', - 'Caissie', - 'Cordone', - 'Critser', - 'Delconte', - 'Falzon', - 'Formosa', - 'Frerking', - 'Gadea', - 'Ganem', - 'Guzek', - 'Hauch', - 'Heese', - 'Hemmen', - 'Holzschuh', - 'Impson', - 'Jablon', - 'Kiedrowski', - 'Krob', - 'Kuhnle', - 'Laake', - 'Larouche', - 'Leaton', - 'Leyland', - 'Lorenson', - 'Macduff', - 'Maready', - 'Newberger', - 'Ohnstad', - 'Pinela', - 'Polino', - 'Postema', - 'Pyon', - 'Radziewicz', - 'Rathod', - 'Salopek', - 'Salvadore', - 'Sawchuk', - 'Trotto', - 'Vereb', - 'Auslander', - 'Beninati', - 'Blunck', - 'Decandia', - 'Deeney', - 'Escatel', - 'Foskett', - 'Hagmann', - 'Hussar', - 'Jakubek', - 'Kluender', - 'Mcelhinny', - 'Salatino', - 'Sangalang', - 'Schoenfeldt', - 'Stogdill', - 'Svitak', - 'Taravella', - 'Tezak', - 'Wieseler', - 'Komperda', - 'Reinitz', - 'Malis', - 'Duce', - 'Salib', - 'Keelin', - 'Labell', - 'Symmonds', - 'Gwynne', - 'Byus', - 'Burgy', - 'Delfosse', - 'Benskin', - 'Hedgepath', - 'Ursin', - 'Kinnebrew', - 'Tinnon', - 'Callum', - 'Allah', - 'Arduini', - 'Azucena', - 'Birkel', - 'Bowermaster', - 'Caires', - 'Chrobak', - 'Cottier', - 'Cropley', - 'Crotteau', - 'Dutan', - 'Ezernack', - 'Fabiani', - 'Fauser', - 'Feeny', - 'Ferdig', - 'Fliss', - 'Gallus', - 'Harlacher', - 'Hasselbach', - 'Honsinger', - 'Landberg', - 'Lohn', - 'Losinski', - 'Maung', - 'Melikian', - 'Nooney', - 'Oyervides', - 'Prum', - 'Riepe', - 'Seebach', - 'Sendejas', - 'Sprick', - 'Torino', - 'Weida', - 'Geschke', - 'Girgenti', - 'Klever', - 'Rathert', - 'Roszell', - 'Sarich', - 'Shimmin', - 'Trimpe', - 'Turrubiates', - 'Zelada', - 'Danzig', - 'Diamant', - 'Hannen', - 'Odland', - 'Puzzo', - 'Slyter', - 'Smaldone', - 'Ebey', - 'Beg', - 'Magel', - 'Tebbs', - 'Gali', - 'Winney', - 'Juba', - 'Stargel', - 'Waren', - 'Stann', - 'Ducasse', - 'Vaugh', - 'Lewers', - 'Stjuste', - 'Heckstall', - 'Bokhari', - 'Bonino', - 'Brummond', - 'Caterino', - 'Deatrick', - 'Decorte', - 'Demara', - 'Dubree', - 'Dulski', - 'Feck', - 'Foglio', - 'Heinzelman', - 'Jory', - 'Knoell', - 'Kronick', - 'Maclay', - 'Mastrogiovanni', - 'Reichling', - 'Rueff', - 'Sellitto', - 'Sensing', - 'Sheu', - 'Soberanes', - 'Stahlecker', - 'Wholey', - 'Yochim', - 'Zeiss', - 'Bojanowski', - 'Bonawitz', - 'Caporaso', - 'Dalesio', - 'Exposito', - 'Giovinazzo', - 'Palardy', - 'Rastogi', - 'Saenger', - 'Sirek', - 'Sonoda', - 'Sovereign', - 'Weimann', - 'Wirtanen', - 'Enerson', - 'Olliff', - 'Kallam', - 'Leggitt', - 'Goude', - 'Rampey', - 'Letsinger', - 'Walles', - 'Kater', - 'Betsill', - 'Creese', - 'Lisbon', - 'Abitz', - 'Bednarik', - 'Bendorf', - 'Berkovich', - 'Brevik', - 'Cassatt', - 'Ciarlo', - 'Cookman', - 'Cosma', - 'Defee', - 'Essner', - 'Fallas', - 'Holda', - 'Kemler', - 'Kovich', - 'Krimmel', - 'Landauer', - 'Meharg', - 'Moncus', - 'Nabi', - 'Redenbaugh', - 'Ruwe', - 'Scalisi', - 'Shughart', - 'Sloma', - 'Sovine', - 'Tomaso', - 'Trueba', - 'Urista', - 'Vanyo', - 'Wolanski', - 'Zettle', - 'Arvanitis', - 'Baeten', - 'Caponi', - 'Carrazco', - 'Galambos', - 'Hartsook', - 'Helseth', - 'Kobylarz', - 'Krugh', - 'Meckel', - 'Ohnemus', - 'Voytek', - 'Winegarden', - 'Zuba', - 'Piloto', - 'Shames', - 'Debella', - 'Keddy', - 'Perra', - 'Winks', - 'Hemrick', - 'Snowdon', - 'Cleere', - 'Leavey', - 'Courington', - 'Herson', - 'Nelon', - 'Bloise', - 'Mcphie', - 'Catledge', - 'Mcneary', - 'Hoffler', - 'Suell', - 'Coard', - 'Woolfork', - 'Biros', - 'Brouhard', - 'Dinovo', - 'Disano', - 'Emami', - 'Flegal', - 'Hardebeck', - 'Hobin', - 'Huttner', - 'Kloosterman', - 'Knutzen', - 'Kopinski', - 'Mailman', - 'Mankey', - 'Mccamish', - 'Mccorquodale', - 'Minichiello', - 'Miyasaki', - 'Osher', - 'Prutzman', - 'Sagen', - 'Shawgo', - 'Sokolow', - 'Southam', - 'Sulik', - 'Wiedel', - 'Wollschlager', - 'Cantalupo', - 'Cruser', - 'Denomme', - 'Dinardi', - 'Donahey', - 'Havlin', - 'Lasecki', - 'Margraf', - 'Mchaffie', - 'Mihaly', - 'Omlor', - 'Roope', - 'Schremp', - 'Vanhecke', - 'Washabaugh', - 'Zaunbrecher', - 'Joost', - 'Pensinger', - 'Kraner', - 'Mikles', - 'Delair', - 'Bukhari', - 'Earll', - 'Sans', - 'Gatliff', - 'Casteneda', - 'Shalom', - 'Fidalgo', - 'Leitao', - 'Degrange', - 'Fruits', - 'Kercheval', - 'Mew', - 'Chopin', - 'Seawood', - 'Agro', - 'Aliano', - 'Badour', - 'Betsch', - 'Buchbinder', - 'Cleavenger', - 'Collazos', - 'Cusmano', - 'Dienes', - 'Dittus', - 'Eggenberger', - 'Fierst', - 'Gingell', - 'Greever', - 'Grisales', - 'Hegstrom', - 'Justen', - 'Kalt', - 'Kirkhart', - 'Krage', - 'Kyzar', - 'Livolsi', - 'Neyhart', - 'Nunziata', - 'Orlich', - 'Parcel', - 'Peshlakai', - 'Schemm', - 'Segner', - 'Urieta', - 'Wolfman', - 'Coonradt', - 'Disilvestro', - 'Dobrowski', - 'Gramza', - 'Kotlyar', - 'Micka', - 'Miksch', - 'Mione', - 'Montone', - 'Palmerton', - 'Parrill', - 'Passafiume', - 'Rosoff', - 'Spaziani', - 'Venditto', - 'Wisch', - 'Fini', - 'Horky', - 'Perel', - 'Arzuaga', - 'Nasworthy', - 'Carland', - 'Elden', - 'Moises', - 'Maione', - 'Glace', - 'Laverdure', - 'Sieh', - 'Toulouse', - 'Hannam', - 'Cumber', - 'Rendell', - 'Hardey', - 'Maddison', - 'Brittle', - 'Helen', - 'Aina', - 'Allwood', - 'Fenty', - 'Herard', - 'Traore', - 'Ator', - 'Bedsaul', - 'Bickert', - 'Brendlinger', - 'Camuso', - 'Dutter', - 'Eastlick', - 'Fernholz', - 'Guza', - 'Heitzenrater', - 'Huo', - 'Isbill', - 'Katzenstein', - 'Keigley', - 'Kelnhofer', - 'Klarich', - 'Mangat', - 'Mathiason', - 'Murzyn', - 'Odenthal', - 'Pascarelli', - 'Passwaters', - 'Rotunda', - 'Schons', - 'Sein', - 'Sobon', - 'Stayner', - 'Tri', - 'Uhlir', - 'Viscusi', - 'Winstanley', - 'Xi', - 'Yodice', - 'Aerts', - 'Antosh', - 'Baldinger', - 'Brislin', - 'Christopoulos', - 'Faurot', - 'Fusselman', - 'Hamsher', - 'Henckel', - 'Macht', - 'Moellering', - 'Oclair', - 'Pavelko', - 'Poehlman', - 'Rajewski', - 'Richcreek', - 'Schmeichel', - 'Venkatesh', - 'Zemba', - 'Zuelke', - 'Dechellis', - 'Reddig', - 'Splain', - 'Claw', - 'Mottram', - 'Crise', - 'Villaflor', - 'Allocca', - 'Buttrum', - 'Cocking', - 'Mundie', - 'Tavis', - 'Saidi', - 'Latter', - 'Tuberville', - 'Spease', - 'Leatherberry', - 'Peatross', - 'Claridy', - 'Duerson', - 'Durley', - 'Mekonnen', - 'Thiam', - 'Aderman', - 'Al', - 'Andreu', - 'Beine', - 'Bowron', - 'Campi', - 'Chura', - 'Ciraulo', - 'Daywalt', - 'Fleek', - 'Friant', - 'Gahm', - 'Gongaware', - 'Grosh', - 'Heaslip', - 'Knape', - 'Kravets', - 'Kritikos', - 'Kumagai', - 'Kustra', - 'Madani', - 'Mich', - 'Norlander', - 'Paulhus', - 'Rabanal', - 'Saker', - 'Stupak', - 'Suchomel', - 'Vandenberghe', - 'Wehrenberg', - 'Zaccardi', - 'Davlin', - 'Dykhouse', - 'Grandfield', - 'Hullender', - 'Kallis', - 'Livshits', - 'Rihn', - 'Criger', - 'Michl', - 'Tutino', - 'Zulueta', - 'Cristo', - 'Meline', - 'Fetch', - 'Dung', - 'Shami', - 'Teale', - 'Cocker', - 'Eshbach', - 'Phagan', - 'Millea', - 'Tayloe', - 'Olivia', - 'Houchen', - 'Peddy', - 'Ferryman', - 'Boodram', - 'Maduro', - 'Fullman', - 'Landingham', - 'Pee', - 'Argenbright', - 'Aronowitz', - 'Baldenegro', - 'Barentine', - 'Bernasconi', - 'Bicking', - 'Bohle', - 'Camerer', - 'Dufford', - 'Ende', - 'Gessel', - 'Grauman', - 'Jaqua', - 'Kagawa', - 'Kalinski', - 'Kanz', - 'Klasen', - 'Koloski', - 'Kriete', - 'Litalien', - 'Maish', - 'Massar', - 'Muraski', - 'Pickelsimer', - 'Sagraves', - 'Servellon', - 'Shellito', - 'Shiveley', - 'Stanislaw', - 'Volland', - 'Biehle', - 'Cruey', - 'Eagar', - 'Ermis', - 'Goracke', - 'Mackert', - 'Malloch', - 'Merillat', - 'Rylee', - 'Schelin', - 'Tibbals', - 'Zandi', - 'Golde', - 'Steuart', - 'Jamie', - 'Lavis', - 'Bromwell', - 'Tregre', - 'Alkhatib', - 'Carvey', - 'Essa', - 'Wale', - 'Mccarey', - 'Brandley', - 'Hermon', - 'Stenhouse', - 'Oguinn', - 'Barclift', - 'Sylvan', - 'Smyre', - 'Ellerby', - 'Alemany', - 'Beyl', - 'Boven', - 'Bultema', - 'Buzan', - 'Cappo', - 'Cottongim', - 'Detore', - 'Dierolf', - 'Dueck', - 'Egelston', - 'Emard', - 'Eveleth', - 'Ferrini', - 'Fodera', - 'Hidy', - 'Kahley', - 'Karasik', - 'Klare', - 'Koudelka', - 'Lafleche', - 'Minturn', - 'Montemarano', - 'Plock', - 'Ratterman', - 'Reingold', - 'Rieber', - 'Schnackenberg', - 'Schrade', - 'Steffek', - 'Stehling', - 'Sticha', - 'Velaquez', - 'Weissberg', - 'Allnutt', - 'Barkhurst', - 'Bettendorf', - 'Canonico', - 'Deshmukh', - 'Dobosz', - 'Glab', - 'Kirkeby', - 'Menapace', - 'Parizek', - 'Pursifull', - 'Ragucci', - 'Raisch', - 'Schronce', - 'Tuason', - 'Duross', - 'Hainer', - 'Kinnick', - 'Rens', - 'Williamsen', - 'Hilke', - 'Hark', - 'Mellett', - 'Decarvalho', - 'Filyaw', - 'Sian', - 'Mccard', - 'Symon', - 'Grade', - 'Giboney', - 'Sadik', - 'Caul', - 'Gater', - 'Sulton', - 'Dungee', - 'Adriance', - 'Almas', - 'Andler', - 'Bellina', - 'Belshe', - 'Blouch', - 'Bradeen', - 'Brandwein', - 'Buechele', - 'Cristina', - 'Davidov', - 'Defiore', - 'Defrain', - 'Derasmo', - 'Dober', - 'Grosshans', - 'Hoek', - 'Hofstad', - 'Ingman', - 'Kille', - 'Langill', - 'Matic', - 'Niederer', - 'Novella', - 'Oelkers', - 'Percifield', - 'Phariss', - 'Pola', - 'Pompei', - 'Potthast', - 'Raden', - 'Radick', - 'Rendina', - 'Sicotte', - 'Sleep', - 'Wadhwa', - 'Buccheri', - 'Calogero', - 'Catrett', - 'Flemmer', - 'Mancinas', - 'Mcmichen', - 'Measel', - 'Pudlo', - 'Ruether', - 'Shusterman', - 'Stabley', - 'Teffeteller', - 'Waisanen', - 'Zappulla', - 'Symanski', - 'Mckenrick', - 'Moger', - 'Obispo', - 'Armenteros', - 'Roses', - 'Makki', - 'Faley', - 'Rumford', - 'Schonberg', - 'Hizer', - 'Blaydes', - 'Coor', - 'Mccalip', - 'Stancill', - 'Cal', - 'Murat', - 'Amie', - 'Placide', - 'Akpan', - 'Bembenek', - 'Bilyk', - 'Bizzarro', - 'Bugge', - 'Cunnane', - 'Degenhart', - 'Doehring', - 'Flammia', - 'Fritcher', - 'Godinho', - 'Gouger', - 'Heyboer', - 'Humenik', - 'Iannaccone', - 'Lacivita', - 'Lagunes', - 'Leitzke', - 'Luty', - 'Maute', - 'Micke', - 'Midura', - 'Nydam', - 'Rasp', - 'Rediker', - 'Requejo', - 'Roskos', - 'Ruckert', - 'Saldierna', - 'Salemme', - 'Tsuchiya', - 'Vallas', - 'Werder', - 'Arenivas', - 'Bartholomay', - 'Brozowski', - 'Dusza', - 'Frevert', - 'Giannopoulos', - 'Kormos', - 'Martos', - 'Mollenhauer', - 'Romanek', - 'Solinger', - 'Tomaro', - 'Zangara', - 'Buttrick', - 'Pardy', - 'Alvelo', - 'Breth', - 'Hemond', - 'Kayes', - 'Manne', - 'Grandchamp', - 'Gilbo', - 'Calame', - 'Clippard', - 'Gieger', - 'Penalver', - 'Ecton', - 'Totton', - 'Poyser', - 'Kettles', - 'Hosang', - 'Waker', - 'Maryland', - 'Girma', - 'Baribeau', - 'Boehnke', - 'Brunick', - 'Buhrow', - 'Cerreta', - 'Dascoli', - 'Eroh', - 'Fallert', - 'Fotopoulos', - 'Granholm', - 'Hebdon', - 'Hoelzer', - 'Hyser', - 'Lisanti', - 'Mastrianni', - 'Mewes', - 'Mulanax', - 'Nikolai', - 'Odekirk', - 'Ofallon', - 'Onnen', - 'Or', - 'Osso', - 'Ridpath', - 'Schara', - 'Schnipke', - 'Slayter', - 'Sodhi', - 'Steffler', - 'Stegemann', - 'Weisensel', - 'Bertling', - 'Dueitt', - 'Keehner', - 'Khaimov', - 'Kramlich', - 'Salkeld', - 'Ulbricht', - 'Vultaggio', - 'Dennin', - 'Mondo', - 'Kett', - 'Dom', - 'Kalan', - 'Yaney', - 'Nicley', - 'Carabello', - 'Ellegood', - 'Mcglocklin', - 'Figuero', - 'Pillard', - 'Wolfrey', - 'Leys', - 'Cobert', - 'Wahid', - 'Fede', - 'Ausbrooks', - 'Gums', - 'Gillion', - 'Mcgeachy', - 'Parran', - 'Likely', - 'Marbley', - 'Argote', - 'Bhullar', - 'Botros', - 'Brethauer', - 'Chell', - 'Conradi', - 'Covill', - 'Crays', - 'Crysler', - 'Handke', - 'Hanneken', - 'Hidrogo', - 'Hirayama', - 'Huebert', - 'Hurford', - 'Iskra', - 'Malczewski', - 'Menees', - 'Monforte', - 'Murdick', - 'Naclerio', - 'Nohr', - 'Pangallo', - 'Payeur', - 'Pozniak', - 'Rammel', - 'Schield', - 'Schrick', - 'Seifer', - 'Sperduto', - 'Stagliano', - 'Staubs', - 'Stromme', - 'Tourigny', - 'Traister', - 'Vandecar', - 'Wilhelms', - 'Wilinski', - 'Wittke', - 'Clougherty', - 'Crotwell', - 'Hannula', - 'Heavrin', - 'Heidinger', - 'Keehan', - 'Ortwein', - 'Palinkas', - 'Seivert', - 'Sloniker', - 'Yielding', - 'Lac', - 'Shove', - 'Venard', - 'Violett', - 'Foresta', - 'Gapp', - 'Dejongh', - 'Ambrosia', - 'Simkin', - 'Sastre', - 'Mcarthy', - 'Bering', - 'Sarah', - 'Hickling', - 'Sookdeo', - 'Val', - 'Colden', - 'Feltus', - 'Hailes', - 'Canizalez', - 'Cloke', - 'Connole', - 'Dancel', - 'Demmon', - 'Ehrler', - 'Fruchey', - 'Helinski', - 'Hepfer', - 'Katzen', - 'Kressler', - 'Lagrow', - 'Nethercutt', - 'Novitski', - 'Papale', - 'Pesola', - 'Petrosian', - 'Pies', - 'Prazak', - 'Preza', - 'Reiche', - 'Salle', - 'Savic', - 'Servello', - 'Sherbondy', - 'Solazzo', - 'Stabenow', - 'Walstad', - 'Yaden', - 'Zagal', - 'Zani', - 'Dimambro', - 'Engquist', - 'Fochtman', - 'Frasch', - 'Fuerstenberg', - 'Galus', - 'Gronowski', - 'Grossenbacher', - 'Hahs', - 'Iavarone', - 'Kerper', - 'Kravchenko', - 'Kwolek', - 'Lusignan', - 'Lybbert', - 'Maertens', - 'Mahany', - 'Medico', - 'Orrantia', - 'Reitmeier', - 'Sieve', - 'Sterbenz', - 'Tenpas', - 'Wischmeyer', - 'Zajkowski', - 'Cregg', - 'Shetley', - 'Tisher', - 'Coup', - 'Murdy', - 'Lysaght', - 'Sesco', - 'Koy', - 'Wakley', - 'Bertholf', - 'Swaner', - 'Stakes', - 'Gren', - 'Elahi', - 'Torney', - 'Gopaul', - 'Egland', - 'Gingles', - 'Aurich', - 'Biela', - 'Binz', - 'Blumenstock', - 'Boardwine', - 'Boehner', - 'Boening', - 'Crankshaw', - 'Decarli', - 'Fauble', - 'Georgopoulos', - 'Gieske', - 'Hasselbring', - 'Heeb', - 'Janosik', - 'Kalafut', - 'Karpf', - 'Kramm', - 'Lanyon', - 'Lewelling', - 'Lilla', - 'Marik', - 'Moyano', - 'Oppel', - 'Panagos', - 'Renovato', - 'Rohlman', - 'Rostron', - 'Todhunter', - 'Torello', - 'Umfleet', - 'Wien', - 'Youker', - 'Ytuarte', - 'Zavada', - 'Altvater', - 'Arnzen', - 'Blixt', - 'Elek', - 'Geiselman', - 'Hiltunen', - 'Jachim', - 'Kolenovic', - 'Kooyman', - 'Muecke', - 'Pierron', - 'Preisler', - 'Rogus', - 'Schoeller', - 'Solimine', - 'Speagle', - 'Courser', - 'Mascarenhas', - 'Dorer', - 'Scotten', - 'Goy', - 'Avers', - 'Blanca', - 'Choung', - 'Goleman', - 'Nanna', - 'Lave', - 'Seley', - 'Meggison', - 'Ripoll', - 'Mannan', - 'Bihm', - 'Tribbey', - 'Ports', - 'Asby', - 'Philibert', - 'Furby', - 'Keal', - 'Louallen', - 'Idris', - 'Artist', - 'Branford', - 'Sabree', - 'Ainley', - 'Amezola', - 'Andreason', - 'Athans', - 'Batiz', - 'Bostelman', - 'Bozic', - 'Butman', - 'Coiro', - 'Defina', - 'Garbo', - 'Gewirtz', - 'Hathcoat', - 'Heebner', - 'Helbing', - 'Kasler', - 'Kastler', - 'Kearby', - 'Krus', - 'Lezotte', - 'Lithgow', - 'Mealor', - 'Moltz', - 'Morcom', - 'Norbeck', - 'Novicki', - 'Osmani', - 'Posluszny', - 'Quiroa', - 'Rahal', - 'Roddenberry', - 'Rodino', - 'Sallade', - 'Saraceni', - 'Schmaus', - 'Stathopoulos', - 'Swatek', - 'Tupy', - 'Vonseggern', - 'Zens', - 'Ahonen', - 'Arrazola', - 'Avedisian', - 'Bachtell', - 'Bastarache', - 'Chavero', - 'Darienzo', - 'Giampa', - 'Gillott', - 'Hierholzer', - 'Kruckeberg', - 'Lafrenz', - 'Milkowski', - 'Missildine', - 'Passaretti', - 'Rogstad', - 'Saadeh', - 'Sielski', - 'Slavick', - 'Tieken', - 'Wittenmyer', - 'Yepiz', - 'Zimdars', - 'Rail', - 'Kook', - 'Jian', - 'Piet', - 'Sanjurjo', - 'Shampine', - 'Christel', - 'Hechavarria', - 'Blucher', - 'Crimm', - 'Lebreton', - 'Charbonnet', - 'Bolls', - 'Stroder', - 'Baise', - 'Mcnease', - 'Alen', - 'Priestly', - 'Mannie', - 'Doleman', - 'Areas', - 'Atayde', - 'Berent', - 'Bodmer', - 'Brodin', - 'Buntrock', - 'Eckrich', - 'Emberson', - 'Hilgert', - 'Hirn', - 'Holihan', - 'Hoshino', - 'Jeung', - 'Leece', - 'Leonardis', - 'Macera', - 'Mcferron', - 'Muster', - 'Naef', - 'Pecka', - 'Peloso', - 'Pensyl', - 'Reaney', - 'Reidinger', - 'Rockholt', - 'Tabrizi', - 'Trauth', - 'Trulock', - 'Tupou', - 'Asbridge', - 'Franzel', - 'Gesualdi', - 'Grimwood', - 'Hardinger', - 'Kondrat', - 'Koskinen', - 'Ludolph', - 'Marchesi', - 'Mehrtens', - 'Racioppi', - 'Sabey', - 'Stroebel', - 'Swendsen', - 'Vandewalker', - 'Korber', - 'Messler', - 'Mowat', - 'Kor', - 'Pua', - 'Sarazin', - 'Wayson', - 'Oland', - 'Bandi', - 'Fabel', - 'Frankl', - 'Rane', - 'Mozer', - 'Weaber', - 'Moustafa', - 'Robe', - 'Lindy', - 'Medaris', - 'Derden', - 'Benthall', - 'Ayler', - 'Osias', - 'Choyce', - 'Scantlebury', - 'Patmon', - 'Ahlgrim', - 'Boffa', - 'Brideau', - 'Bubeck', - 'Bubel', - 'Casio', - 'Casique', - 'Casten', - 'Colebank', - 'Demoura', - 'Devincenzo', - 'Elsesser', - 'Fauci', - 'Frentz', - 'Hemler', - 'Keitel', - 'Luan', - 'Luhn', - 'Luquette', - 'Mazurowski', - 'Mendibles', - 'Mickiewicz', - 'Minelli', - 'Mistler', - 'Nemer', - 'Nikolaus', - 'Offill', - 'Pezza', - 'Ruzich', - 'Skrzypek', - 'Swimmer', - 'Trucks', - 'Vaccarella', - 'Zeidman', - 'Brattin', - 'Deblock', - 'Dufrane', - 'Gural', - 'Hufstedler', - 'Kapuscinski', - 'Lyerla', - 'Musolino', - 'Neubecker', - 'Polus', - 'Protzman', - 'Retzloff', - 'Sachdev', - 'Sazama', - 'Shrider', - 'Tobolski', - 'Mcbane', - 'Clabo', - 'Fredrich', - 'Lace', - 'Bertran', - 'Kama', - 'Simonet', - 'Lippitt', - 'Thomlinson', - 'Vallot', - 'Dede', - 'Brimley', - 'Parler', - 'Standfield', - 'Goodie', - 'Isidore', - 'Philogene', - 'Abramczyk', - 'Andert', - 'Besancon', - 'Bieda', - 'Birkey', - 'Boquet', - 'Borak', - 'Bottino', - 'Breyfogle', - 'Crill', - 'Daffern', - 'Derrig', - 'Dimalanta', - 'Dresch', - 'Feulner', - 'Friede', - 'Furth', - 'Gamet', - 'Garramone', - 'Gaunce', - 'Gitto', - 'Guandique', - 'Hoxworth', - 'Hubers', - 'Ingwersen', - 'Junio', - 'Kassing', - 'Magrath', - 'Martelle', - 'Mcweeney', - 'Neris', - 'Nesheiwat', - 'Remlinger', - 'Rentmeester', - 'Schlein', - 'Schoneman', - 'Sterr', - 'Streib', - 'Szymanowski', - 'Trompeter', - 'Tullius', - 'Cherico', - 'Cremin', - 'Dominey', - 'Gotthardt', - 'Kowalke', - 'Onderdonk', - 'Pirrello', - 'Rumberger', - 'Schreur', - 'Westerhoff', - 'Maroni', - 'Dire', - 'Menta', - 'Hoeg', - 'Meise', - 'Standerfer', - 'Roam', - 'Tibbett', - 'Beevers', - 'Evrard', - 'Locklair', - 'Brester', - 'Sirmon', - 'Woodbeck', - 'Wires', - 'Durette', - 'Raul', - 'Stephanie', - 'Mcwain', - 'Skeeters', - 'Wilbourne', - 'Debroux', - 'Keyton', - 'Noris', - 'Fanta', - 'Goshen', - 'Kithcart', - 'Shepheard', - 'Sherod', - 'Buntyn', - 'Gissendanner', - 'Goodley', - 'Mckissic', - 'Bissinger', - 'Biswell', - 'Borruso', - 'Danese', - 'Eslava', - 'Gehle', - 'Gibeau', - 'Gionet', - 'Greth', - 'Gul', - 'Hambley', - 'Harshfield', - 'Helin', - 'Henken', - 'Hogland', - 'Hoxha', - 'Hurlbutt', - 'Kaminer', - 'Kien', - 'Kliebert', - 'Koivisto', - 'Kooken', - 'Laconte', - 'Lovo', - 'Manninen', - 'Maxham', - 'Mcleland', - 'Mclerran', - 'Milici', - 'Negrette', - 'Nicotera', - 'Nissan', - 'Philipson', - 'Pimenta', - 'Pinch', - 'Rietveld', - 'Seyller', - 'Shollenberger', - 'Sochacki', - 'Telleria', - 'Toda', - 'Unrue', - 'Vanbenschoten', - 'Versace', - 'Villada', - 'Watry', - 'Wirsing', - 'Zeimet', - 'Zynda', - 'Angelillo', - 'Fleissner', - 'Freehling', - 'Grewell', - 'Heick', - 'Kartes', - 'Kishi', - 'Kopke', - 'Laubenstein', - 'Leske', - 'Lohmeier', - 'Marotz', - 'Moccio', - 'Mullineaux', - 'Muzyka', - 'Ostermiller', - 'Penuelas', - 'Plagge', - 'Stolarz', - 'Wertenberger', - 'Sella', - 'Allinger', - 'Betzler', - 'Rosenkrantz', - 'Trimarchi', - 'Dionicio', - 'Frohman', - 'Landenberger', - 'Shillings', - 'Chill', - 'Leather', - 'Sonn', - 'Connel', - 'Fougere', - 'Alia', - 'Wisby', - 'Haisley', - 'Minion', - 'Mccathern', - 'Rozzell', - 'Armbrister', - 'Ryant', - 'Almeyda', - 'Bonjour', - 'Bordas', - 'Bozard', - 'Buccola', - 'Cihlar', - 'Dargis', - 'Faivre', - 'Fejes', - 'Grulke', - 'Harken', - 'Heimberger', - 'Hochmuth', - 'Keadle', - 'Kedrowski', - 'Kortman', - 'Krahenbuhl', - 'Krasniqi', - 'Kundrat', - 'Leistner', - 'Loguidice', - 'Mcauliff', - 'Mchatton', - 'Minella', - 'Muccio', - 'Normington', - 'Nuttle', - 'Orsino', - 'Reker', - 'Respicio', - 'Shein', - 'Teichert', - 'Varisco', - 'Accomando', - 'Amelio', - 'Burckhard', - 'Fleischhacker', - 'Hagglund', - 'Kessenich', - 'Langrehr', - 'Lauderbaugh', - 'Misquez', - 'Muneton', - 'Ourada', - 'Rulon', - 'Scholze', - 'Stellmach', - 'Sudano', - 'Thelander', - 'Yeckley', - 'Corsino', - 'Grage', - 'Isla', - 'Narramore', - 'Coolman', - 'Heatherington', - 'Newey', - 'Kunda', - 'Motts', - 'Tawfik', - 'Tindel', - 'Passon', - 'Sypher', - 'Conceicao', - 'Haraway', - 'Deamer', - 'Nored', - 'Mamo', - 'Mcgilberry', - 'Akerley', - 'Andreatta', - 'Aronhalt', - 'Barz', - 'Bebber', - 'Brubacher', - 'Cabriales', - 'Dyckman', - 'Ellers', - 'Finerty', - 'Hargan', - 'Haselton', - 'Hellmuth', - 'Hoffmeier', - 'Homrich', - 'Hrabak', - 'Intrieri', - 'Lebeda', - 'Lutzke', - 'Malka', - 'Mcglinn', - 'Nicklin', - 'Nusz', - 'Pennings', - 'Rebmann', - 'Rodocker', - 'Sacra', - 'Saksa', - 'Shehane', - 'Siever', - 'Snide', - 'Sotero', - 'Sponsel', - 'Therien', - 'Viti', - 'Wubben', - 'Zieske', - 'Billingham', - 'Bruschi', - 'Cullipher', - 'Eppolito', - 'Greuel', - 'Huq', - 'Matott', - 'Mohlman', - 'Monterroza', - 'Risberg', - 'Shvartsman', - 'Sigafoos', - 'Zehring', - 'Manuele', - 'Asghar', - 'Shelp', - 'Grieder', - 'Hippert', - 'Dani', - 'Beserra', - 'Kennan', - 'Scholfield', - 'Joh', - 'Swailes', - 'Pear', - 'Hell', - 'Kittler', - 'Pickeral', - 'Somerset', - 'Streat', - 'Tinner', - 'Landor', - 'Pretlow', - 'Tensley', - 'Abela', - 'Abramovich', - 'Acocella', - 'Avino', - 'Bacchi', - 'Bayliff', - 'Beganovic', - 'Belinsky', - 'Bilicki', - 'Borowiec', - 'Bucknam', - 'Calandro', - 'Ciszek', - 'Cooling', - 'Cundari', - 'Derk', - 'Ekern', - 'Engelson', - 'Fennessey', - 'Ferencz', - 'Filipkowski', - 'Frescas', - 'Frisinger', - 'Gegg', - 'Hanken', - 'Harbach', - 'Jipson', - 'Kasal', - 'Kinstler', - 'Langenbach', - 'Leccese', - 'Maalouf', - 'Mcinerny', - 'Mcpartlin', - 'Meth', - 'Mitzner', - 'Riano', - 'Saggese', - 'Schroff', - 'Skibicki', - 'Textor', - 'Vancampen', - 'Vukelich', - 'Wascom', - 'Workinger', - 'Xin', - 'Bronkema', - 'Gerstel', - 'Geving', - 'Gravlin', - 'Hannay', - 'Haughn', - 'Lippi', - 'Lonsway', - 'Paradowski', - 'Poust', - 'Thinnes', - 'Wassenaar', - 'Hemm', - 'Isip', - 'Pastorino', - 'Barkett', - 'Montalban', - 'Ballestero', - 'Floren', - 'Rossen', - 'Chuba', - 'Burrington', - 'Derman', - 'Wickland', - 'Dunman', - 'Beek', - 'Petitjean', - 'Michelin', - 'Chapell', - 'Pullam', - 'Adamcik', - 'Albarracin', - 'Batrez', - 'Berghuis', - 'Birkland', - 'Boulier', - 'Broderson', - 'Bruun', - 'Cicio', - 'Davidow', - 'Denova', - 'Dooner', - 'Espeland', - 'Fifita', - 'Guidone', - 'Hartnell', - 'Havranek', - 'Janca', - 'Klepac', - 'Langhorst', - 'Lippmann', - 'Merrihew', - 'Mondelli', - 'Monterosso', - 'Moster', - 'Noxon', - 'Poznanski', - 'Reents', - 'Samaras', - 'Silvius', - 'Srour', - 'Stasio', - 'Steffe', - 'Steimer', - 'Stracke', - 'Taney', - 'Theodorou', - 'Trickel', - 'Tunks', - 'Vavrek', - 'Whitfill', - 'Wohlfeil', - 'Zirkelbach', - 'Brissey', - 'Busboom', - 'Collignon', - 'Emling', - 'Fratzke', - 'Genrich', - 'Giglia', - 'Hayakawa', - 'Lupinski', - 'Pulvermacher', - 'Steinbrink', - 'Xayavong', - 'Yerkey', - 'Arlotta', - 'Calia', - 'Pfiffner', - 'Gostomski', - 'Declerck', - 'Demedeiros', - 'Dirickson', - 'Wo', - 'Hosie', - 'Chad', - 'Herbison', - 'Fleece', - 'Connon', - 'Dun', - 'Gaffin', - 'Plush', - 'Gravette', - 'Houseal', - 'Seaward', - 'Esson', - 'Mayhorn', - 'Surrell', - 'Horsford', - 'Mcduffey', - 'Huger', - 'Alexie', - 'Apsey', - 'Belke', - 'Bourcier', - 'Cardena', - 'Daun', - 'Dunworth', - 'Ehrsam', - 'Elizardo', - 'Elkhatib', - 'Emick', - 'Fernau', - 'Finnan', - 'Hitzeman', - 'Housand', - 'Kallstrom', - 'Katen', - 'Kerstein', - 'Kiracofe', - 'Klammer', - 'Largaespada', - 'Limoges', - 'Lodwick', - 'Lozito', - 'Madl', - 'Mauthe', - 'Mogel', - 'Newstrom', - 'Ninh', - 'Obrochta', - 'Opsal', - 'Ordiway', - 'Osentoski', - 'Paxman', - 'Plume', - 'Rickenbach', - 'Rinks', - 'Saltmarsh', - 'Scheuring', - 'Schwegel', - 'Skov', - 'Woodrome', - 'Zdanowicz', - 'Zera', - 'Basgall', - 'Bornhorst', - 'Clotfelter', - 'Coulthard', - 'Dresner', - 'Fischl', - 'Grahek', - 'Grefe', - 'Knightly', - 'Kuenzel', - 'Mccumbers', - 'Millstein', - 'Mulnix', - 'Weiher', - 'Yust', - 'Metter', - 'Polio', - 'Ayad', - 'Banke', - 'Lawlis', - 'Coba', - 'Twyford', - 'Burck', - 'Barthold', - 'Sames', - 'Jacquot', - 'Allsopp', - 'Mcglaun', - 'Hollinsworth', - 'Gillings', - 'Buchannon', - 'Bas', - 'Beaber', - 'Berto', - 'Bobrow', - 'Bochicchio', - 'Bohland', - 'Burghart', - 'Chaloux', - 'Costella', - 'Depace', - 'Dils', - 'Diviney', - 'Ehly', - 'Ermer', - 'Fussner', - 'Gunia', - 'Guterrez', - 'Holik', - 'Holster', - 'Kasperski', - 'Koscinski', - 'Lamoureaux', - 'Marotti', - 'Masullo', - 'Mcconahy', - 'Mehlhaff', - 'Mocarski', - 'Moosman', - 'Pavlich', - 'Pfisterer', - 'Ruacho', - 'Semrad', - 'Slemmer', - 'Stineman', - 'Toelle', - 'Vanderstelt', - 'Wagy', - 'Wuensch', - 'Wykes', - 'Zar', - 'Bouchie', - 'Friis', - 'Gehrt', - 'Hempfling', - 'Henkes', - 'Huggler', - 'Kelbaugh', - 'Petrenko', - 'Pfost', - 'Rubendall', - 'Shimel', - 'Stapf', - 'Sweeton', - 'Tsuda', - 'Vitanza', - 'Voytko', - 'Bibbo', - 'Hagee', - 'Majer', - 'Mangieri', - 'Pala', - 'Volle', - 'Cabassa', - 'Lipsett', - 'Macdougal', - 'Minar', - 'Eline', - 'Eskin', - 'Angeletti', - 'Lattner', - 'Kimple', - 'Marsan', - 'Tornes', - 'Moncur', - 'Sanderfer', - 'Crite', - 'Levels', - 'Valcin', - 'Motton', - 'Foggie', - 'Battistoni', - 'Bedient', - 'Bendt', - 'Bennison', - 'Bonnin', - 'Caridi', - 'Cedotal', - 'Choinski', - 'Cossin', - 'Devargas', - 'Deveny', - 'Dosher', - 'Dredge', - 'Fittro', - 'Gorgone', - 'Gourd', - 'Herra', - 'Holwerda', - 'Iannello', - 'Klintworth', - 'Kubena', - 'Leyvas', - 'Magowan', - 'Mendolia', - 'Nehme', - 'Pelikan', - 'Pfalzgraf', - 'Raith', - 'Reichenberg', - 'Reinertsen', - 'Sens', - 'Simer', - 'Spektor', - 'Sweda', - 'Wordell', - 'Blasing', - 'Dinoto', - 'Goblirsch', - 'Helming', - 'Hibshman', - 'Lamountain', - 'Latka', - 'Licausi', - 'Malerba', - 'Mentink', - 'Meskill', - 'Moening', - 'Montminy', - 'Ryno', - 'Sluka', - 'Solarz', - 'Swainston', - 'Tagliaferri', - 'Twichell', - 'Vertucci', - 'Voland', - 'Wolgast', - 'Bissen', - 'Duray', - 'Flaum', - 'Taves', - 'Caplin', - 'Hayat', - 'Pollett', - 'Baris', - 'Taher', - 'Anes', - 'Beza', - 'Pere', - 'Tipper', - 'Farrey', - 'Slott', - 'Sinquefield', - 'Bobbett', - 'Calico', - 'Eigner', - 'Gambrill', - 'Donigan', - 'Daney', - 'Natt', - 'Gettis', - 'Kincy', - 'Dolberry', - 'Curenton', - 'Elzie', - 'Beretta', - 'Carbine', - 'Carpenito', - 'Clarin', - 'Conrado', - 'Conradt', - 'Courteau', - 'Daft', - 'Debruler', - 'Delahunty', - 'Duerst', - 'Dzik', - 'Ellner', - 'Faeth', - 'Fournet', - 'Galinski', - 'Goldenstein', - 'Hanauer', - 'Higgason', - 'Hoeper', - 'Hollo', - 'Ildefonso', - 'Jocson', - 'Kasprowicz', - 'Kochanowski', - 'Labrosse', - 'Lazaroff', - 'Leino', - 'Levinsky', - 'Lopezhernandez', - 'Mckeague', - 'Otremba', - 'Paluzzi', - 'Pevehouse', - 'Polgar', - 'Raneri', - 'Rumler', - 'Sanantonio', - 'Schissel', - 'Senteno', - 'Sieling', - 'Smee', - 'Swiggum', - 'Tarnow', - 'Tavakoli', - 'Tholl', - 'Valdiviezo', - 'Willadsen', - 'Wilmouth', - 'Dudziak', - 'Eskenazi', - 'Garity', - 'Gravino', - 'Impastato', - 'Kuhner', - 'Mcclaflin', - 'Nein', - 'Precourt', - 'Rotenberry', - 'Sciara', - 'Arenson', - 'Coupland', - 'Sedler', - 'Pizer', - 'Him', - 'Combee', - 'Rhorer', - 'Gelles', - 'Baroody', - 'Basten', - 'Sprinkles', - 'Vanier', - 'Clementson', - 'Robberson', - 'Harten', - 'Kade', - 'Bhola', - 'Bahar', - 'Pellum', - 'Isadore', - 'Dixie', - 'Axline', - 'Backs', - 'Berdahl', - 'Billeter', - 'Bily', - 'Broerman', - 'Declercq', - 'Derleth', - 'Fanucchi', - 'Forkey', - 'Gallinger', - 'Gionfriddo', - 'Gretzinger', - 'Grima', - 'Helgren', - 'Hoelting', - 'Hundertmark', - 'Inscho', - 'Jernberg', - 'Kamiya', - 'Lekas', - 'Marchini', - 'Markuson', - 'Matsushima', - 'Meineke', - 'Mizrachi', - 'Moglia', - 'Nagele', - 'Naro', - 'Padillo', - 'Palleschi', - 'Palomba', - 'Purgason', - 'Qadri', - 'Recalde', - 'Rosiak', - 'Rumney', - 'Savitt', - 'Shibuya', - 'Szalkowski', - 'Wagg', - 'Wolsey', - 'Zumpano', - 'Benbrook', - 'Blasdel', - 'Carusone', - 'Karalis', - 'Koep', - 'Kohles', - 'Rumbo', - 'Siggins', - 'Unverzagt', - 'Eatherly', - 'Kapper', - 'Salser', - 'Wege', - 'Zinsmeister', - 'Alf', - 'Wish', - 'Falero', - 'Bur', - 'Imam', - 'Biven', - 'Merritts', - 'Kaigler', - 'Verdell', - 'Feggins', - 'Acerra', - 'Antenucci', - 'Benegas', - 'Bisesi', - 'Boshers', - 'Chap', - 'Clouatre', - 'Doxtater', - 'Dullea', - 'Eischeid', - 'Gundry', - 'Hinger', - 'Hodak', - 'Iseminger', - 'Juris', - 'Kirchen', - 'Knezevic', - 'Kobrin', - 'Krizek', - 'Leza', - 'Lusty', - 'Luttrull', - 'Mattke', - 'Mossbarger', - 'Narro', - 'Osland', - 'Ostwald', - 'Pepperman', - 'Pritzl', - 'Reasner', - 'Schimming', - 'Schulenburg', - 'Trefry', - 'Vigorito', - 'Bayardo', - 'Bieser', - 'Brinkmeier', - 'Camposano', - 'Cremeens', - 'Delgrande', - 'Demopoulos', - 'Deyarmin', - 'Grismer', - 'Jubb', - 'Kinker', - 'Lauf', - 'Mabile', - 'Muehl', - 'Orlick', - 'Pillado', - 'Pizzano', - 'Poppleton', - 'Quickel', - 'Stoneberg', - 'Szwed', - 'Zadrozny', - 'Ziemke', - 'Zupko', - 'Diesel', - 'Hornbrook', - 'Pillion', - 'Holaway', - 'Massad', - 'Rossmiller', - 'Parriott', - 'Toya', - 'Dross', - 'Burwick', - 'Kaman', - 'Bruna', - 'Milles', - 'Acrey', - 'Toogood', - 'Austell', - 'Chastang', - 'Jasmine', - 'Eckford', - 'Stiggers', - 'Saintvil', - 'Adeyemi', - 'Basto', - 'Bolon', - 'Brilliant', - 'Brockhoff', - 'Colao', - 'Emens', - 'Endler', - 'Fabris', - 'Falletta', - 'Felver', - 'Ferdon', - 'Golinski', - 'Gosdin', - 'Gronlund', - 'Guijosa', - 'Hainley', - 'Halama', - 'Heinicke', - 'Heldenbrand', - 'Helmkamp', - 'Hoctor', - 'Hoeck', - 'Kroboth', - 'Lamagna', - 'Lingg', - 'Locurto', - 'Marchewka', - 'Micco', - 'Mormino', - 'Newmeyer', - 'Ostrosky', - 'Redel', - 'Saccoccio', - 'Stavely', - 'Stidd', - 'Tonne', - 'Tonnesen', - 'Umbach', - 'Vardanyan', - 'Wank', - 'Wolven', - 'Cilento', - 'Delmonaco', - 'Denigris', - 'Gerbig', - 'Gradilla', - 'Grebner', - 'Landini', - 'Marohl', - 'Muenchow', - 'Niedermeier', - 'Nussbaumer', - 'Nycz', - 'Pizzino', - 'Schader', - 'Schuneman', - 'Takano', - 'Ureta', - 'Vanderloop', - 'Windholz', - 'Wombacher', - 'Woulfe', - 'Hamley', - 'Schickel', - 'Yuill', - 'Batta', - 'Galant', - 'Mofield', - 'Kint', - 'Barnell', - 'Ashmead', - 'Crossin', - 'Lasco', - 'Chasen', - 'Swire', - 'Gleghorn', - 'Bearfield', - 'Goodgame', - 'Daris', - 'Plump', - 'Derricott', - 'Burno', - 'Baylock', - 'Vanterpool', - 'Judon', - 'Mells', - 'Proby', - 'Bagan', - 'Batcheller', - 'Bjelland', - 'Boline', - 'Boullion', - 'Broomall', - 'Carcia', - 'Cassinelli', - 'Cerro', - 'Colantuono', - 'Dembeck', - 'Doto', - 'Eckersley', - 'Edell', - 'Ewy', - 'Goodness', - 'Huhta', - 'Kallen', - 'Keimig', - 'Kemppainen', - 'Koopmann', - 'Lacap', - 'Lehtinen', - 'Maciolek', - 'Marchuk', - 'Mcfate', - 'Mentel', - 'Minihan', - 'Mohsin', - 'Oppedisano', - 'Patriarca', - 'Raske', - 'Schueneman', - 'Shostak', - 'Sibal', - 'Spadafore', - 'Suitor', - 'Tavella', - 'Vy', - 'Wies', - 'Beadnell', - 'Bogusz', - 'Cleverly', - 'Dellorusso', - 'Dudenhoeffer', - 'Glendinning', - 'Glomb', - 'Heinkel', - 'Jiwani', - 'Lonigro', - 'Machala', - 'Marsicano', - 'Neuenfeldt', - 'Overlock', - 'Popko', - 'Russomanno', - 'Saxer', - 'Scicchitano', - 'Spiegelberg', - 'Spindel', - 'Timpone', - 'Vincelette', - 'Waidelich', - 'Wissink', - 'Woolstenhulme', - 'Danza', - 'Sleasman', - 'Frometa', - 'Savinon', - 'Higgerson', - 'Helmich', - 'Nahar', - 'Campus', - 'Hassey', - 'Mccorkel', - 'Tola', - 'Ferrington', - 'Nicolls', - 'Markes', - 'Edgley', - 'Dupriest', - 'Wah', - 'Mclester', - 'Scantling', - 'Goffe', - 'Battie', - 'Battershell', - 'Bearup', - 'Bisig', - 'Brouillet', - 'Canby', - 'Chaussee', - 'Colandrea', - 'Colocho', - 'Daube', - 'Dobransky', - 'Dolbow', - 'Dyk', - 'Elfrink', - 'Figel', - 'Hauter', - 'Henkels', - 'Keillor', - 'Kollasch', - 'Krabill', - 'Kubly', - 'Kvasnicka', - 'Leise', - 'Martirosyan', - 'Mihalic', - 'Montecinos', - 'Myren', - 'Okerlund', - 'Ozer', - 'Rajput', - 'Reihl', - 'Rimando', - 'Saffle', - 'Schmelter', - 'Tellado', - 'Wachsmuth', - 'Wussow', - 'Zylka', - 'Caiola', - 'Certo', - 'Disabatino', - 'Ehrke', - 'Lahmann', - 'Lamartina', - 'Manheim', - 'Mckevitt', - 'Nardozzi', - 'Neuzil', - 'Novotney', - 'Oldfather', - 'Sietsema', - 'Stemmler', - 'Stumm', - 'Ueno', - 'Weckwerth', - 'Berrocal', - 'Nolde', - 'Alava', - 'Revier', - 'Sester', - 'Saller', - 'Tonga', - 'Kala', - 'Reveron', - 'Homesley', - 'Pagett', - 'Blackie', - 'Raimer', - 'Fitt', - 'Kimbley', - 'Amory', - 'Cabler', - 'Juett', - 'Crate', - 'Burres', - 'Siddle', - 'Barnfield', - 'Bordenave', - 'Cubit', - 'Elem', - 'Hardmon', - 'Augspurger', - 'Barriger', - 'Bau', - 'Bloomingdale', - 'Busta', - 'Canoy', - 'Carapia', - 'Cavenaugh', - 'Conkin', - 'Coppernoll', - 'Daloia', - 'Debruyne', - 'Egly', - 'Esmail', - 'Estorga', - 'Gladu', - 'Gladue', - 'Harvath', - 'Hirschmann', - 'Juel', - 'Kappus', - 'Kopriva', - 'Krul', - 'Lavorgna', - 'Maginn', - 'Malphrus', - 'Mcilhenny', - 'Perazzo', - 'Peredo', - 'Pineo', - 'Rigoni', - 'Robleto', - 'Schoene', - 'Sevillano', - 'Stears', - 'Stoltzfoos', - 'Sutley', - 'Terracciano', - 'Villacres', - 'Yoak', - 'Brensinger', - 'Brodzinski', - 'Cordial', - 'Cornacchia', - 'Corralejo', - 'Demarchi', - 'Dziuk', - 'Hirzel', - 'Keirns', - 'Kocourek', - 'Kupec', - 'Nazaryan', - 'Oftedahl', - 'Pignatelli', - 'Pundt', - 'Repinski', - 'Ryther', - 'Sampedro', - 'Shemanski', - 'Siess', - 'Trettel', - 'Urquilla', - 'Vantil', - 'Vicens', - 'Dunahoo', - 'Safer', - 'Romaniello', - 'Tallo', - 'Cavell', - 'Cobern', - 'Yarrow', - 'Serge', - 'Adel', - 'Allum', - 'Pruit', - 'Wali', - 'Forson', - 'Bells', - 'Blyden', - 'Andreotti', - 'Bagnato', - 'Beauchaine', - 'Biedrzycki', - 'Brabo', - 'Brodman', - 'Bruyere', - 'Canizares', - 'Chio', - 'Coudriet', - 'Dara', - 'Dhawan', - 'Diclemente', - 'Doro', - 'Elvir', - 'Fivecoat', - 'Frate', - 'Furuya', - 'Greis', - 'Halbleib', - 'Heuerman', - 'Hoener', - 'Holberg', - 'Hoogendoorn', - 'Inclan', - 'Jokinen', - 'Kretchmer', - 'Lafromboise', - 'Mccomsey', - 'Mckiddy', - 'Pelky', - 'Plaia', - 'Ponti', - 'Reichl', - 'Schicker', - 'Sotto', - 'Staehle', - 'Thau', - 'Turchin', - 'Zill', - 'Aicher', - 'Arrigoni', - 'Bertagnolli', - 'Binetti', - 'Dahlheimer', - 'Delashmit', - 'Disque', - 'Hemmerling', - 'Hovater', - 'Kachur', - 'Massmann', - 'Schlup', - 'Turkovich', - 'Underberg', - 'Wambolt', - 'Vassey', - 'Larney', - 'Brisky', - 'Minas', - 'Kata', - 'Magar', - 'Arlen', - 'Corporan', - 'Westland', - 'Detherage', - 'Reen', - 'Morale', - 'Hoes', - 'Baynham', - 'Norrington', - 'Lartigue', - 'Hakeem', - 'Kendrix', - 'Cazeau', - 'Amadi', - 'Mczeal', - 'Alwin', - 'Barcellos', - 'Bastedo', - 'Bintz', - 'Brackenbury', - 'Brockel', - 'Bucek', - 'Cecala', - 'Dapper', - 'Dettore', - 'Dowdall', - 'Dralle', - 'Essenmacher', - 'Evaristo', - 'Fecher', - 'Feldmeier', - 'Fetherston', - 'Futterman', - 'Garlinghouse', - 'Germani', - 'Gotz', - 'Hoen', - 'Janikowski', - 'Kiess', - 'Lagerstrom', - 'Lozinski', - 'Magnone', - 'Markow', - 'Mayall', - 'Mehdi', - 'Mineau', - 'Morgenroth', - 'Nitzsche', - 'Nordell', - 'Pavlock', - 'Peruzzi', - 'Pettine', - 'Pinos', - 'Polidoro', - 'Rahl', - 'Rudis', - 'Ryback', - 'Santellan', - 'Scharfenberg', - 'Schnake', - 'Schwake', - 'Seeling', - 'Senk', - 'Siron', - 'Speich', - 'Summerhays', - 'Torno', - 'Vangieson', - 'Wiacek', - 'Begnoche', - 'Carrejo', - 'Chervenak', - 'Edminster', - 'Halonen', - 'Macumber', - 'Mazeika', - 'Mikami', - 'Minetti', - 'Mosbrucker', - 'Mundis', - 'Onder', - 'Prowant', - 'Pyo', - 'Sedlack', - 'Stanbro', - 'Woehl', - 'Wrage', - 'Carpentieri', - 'Guedry', - 'Hodde', - 'Waggy', - 'Weitman', - 'Handal', - 'Gosman', - 'Mckeone', - 'Oliveria', - 'Soutar', - 'Glance', - 'Surprise', - 'Milius', - 'Crammer', - 'Mclear', - 'Borris', - 'Malon', - 'Mane', - 'Arrick', - 'Brazzel', - 'Matthewson', - 'Philemon', - 'Selvy', - 'Lites', - 'Deadwyler', - 'Marzette', - 'Alipio', - 'Arancibia', - 'Arrona', - 'Basista', - 'Blethen', - 'Brull', - 'Colaianni', - 'Dreese', - 'Giammona', - 'Giovanetti', - 'Grandmaison', - 'Grondahl', - 'Gulli', - 'Hellenbrand', - 'Iturbe', - 'Koesters', - 'Kondracki', - 'Konitzer', - 'Kubic', - 'Lauerman', - 'Mcfadin', - 'Musquiz', - 'Papalia', - 'Porrazzo', - 'Prien', - 'Reichley', - 'Treichler', - 'Ursua', - 'Vanblaricom', - 'Wich', - 'Windler', - 'Wos', - 'Zampino', - 'Alexopoulos', - 'Bambrick', - 'Beabout', - 'Brechtel', - 'Buroker', - 'Dahler', - 'Everding', - 'Furno', - 'Gikas', - 'Gilkeson', - 'Hubka', - 'Konwinski', - 'Krisko', - 'Kuligowski', - 'Maltbie', - 'Molstad', - 'Nonnemacher', - 'Nowotny', - 'Odisho', - 'Remsburg', - 'Rollyson', - 'Siegmann', - 'Slaubaugh', - 'Wasco', - 'Carlyon', - 'Chanin', - 'Cominsky', - 'Karber', - 'Aynes', - 'Swamy', - 'Kolden', - 'Rochel', - 'Julin', - 'Demarcus', - 'Malena', - 'Morice', - 'Burst', - 'Sukhu', - 'Mccravy', - 'Rinehardt', - 'Veazie', - 'Isaiah', - 'Bradby', - 'Poellnitz', - 'Agyemang', - 'Agate', - 'Aschoff', - 'Beenken', - 'Bogenschutz', - 'Casamento', - 'Correira', - 'Ebers', - 'Ellertson', - 'Forcum', - 'Gortney', - 'Jarriel', - 'Jasmer', - 'Kennebeck', - 'Kimpton', - 'Lad', - 'Lasek', - 'Licavoli', - 'Lipper', - 'Luedecke', - 'Maqueda', - 'Matsen', - 'Mest', - 'Neang', - 'Neault', - 'Newlun', - 'Oetken', - 'Rodick', - 'Rollinger', - 'Sabins', - 'Schalow', - 'Sheils', - 'Spilde', - 'Virzi', - 'Watz', - 'Wehrly', - 'Boscarino', - 'Chavolla', - 'Dasaro', - 'Eisenbach', - 'Ignatowski', - 'Kievit', - 'Kuzminski', - 'Lickliter', - 'Moravek', - 'Pawling', - 'Prause', - 'Redler', - 'Wunschel', - 'Suchanek', - 'Eyring', - 'Loge', - 'Tout', - 'Fross', - 'Swiss', - 'Deforrest', - 'Umphlett', - 'Herran', - 'Matton', - 'Passe', - 'Ode', - 'Della', - 'Caillier', - 'Baten', - 'Chesterfield', - 'Odneal', - 'Azeez', - 'Salami', - 'Ramson', - 'Mcvea', - 'Pittmon', - 'Cheatom', - 'Dorsainvil', - 'Cheeseboro', - 'Lavalais', - 'Allegro', - 'Bressi', - 'Brocklehurst', - 'Cassarino', - 'Dario', - 'Gazzola', - 'Glinka', - 'Goffredo', - 'Halabi', - 'Kroeze', - 'Lenig', - 'Marciel', - 'Marcussen', - 'Massoni', - 'Mayernik', - 'Nawrot', - 'Palazzi', - 'Pfefferkorn', - 'Placeres', - 'Polimeni', - 'Recendiz', - 'Sawdey', - 'Seidell', - 'Suchecki', - 'Titzer', - 'Virag', - 'Vitulli', - 'Wiltfong', - 'Wolden', - 'Woolworth', - 'Yandow', - 'Zeiter', - 'Zogg', - 'Brosh', - 'Dunsmoor', - 'Gucciardo', - 'Gumz', - 'Luginbill', - 'Mathwig', - 'Pannullo', - 'Raitt', - 'Reutzel', - 'Sonnen', - 'Bahri', - 'Guiffre', - 'Hons', - 'Platner', - 'Balaguer', - 'Lapre', - 'Rabbani', - 'Talent', - 'Hoster', - 'Thal', - 'Apo', - 'Duggin', - 'Kirley', - 'Burnard', - 'Lourie', - 'Wilham', - 'Craton', - 'Griff', - 'Falwell', - 'Upperman', - 'Laverne', - 'Wi', - 'Foucher', - 'Sudberry', - 'Oriol', - 'Cowens', - 'Marshell', - 'Chargois', - 'Bordley', - 'Artale', - 'Boeker', - 'Cookston', - 'Dattilio', - 'Dewinter', - 'Ditton', - 'Droessler', - 'Dusch', - 'Eltringham', - 'Feige', - 'Giel', - 'Grigas', - 'Hannagan', - 'Haubner', - 'Henzler', - 'Kippes', - 'Kneebone', - 'Lozeau', - 'Mallek', - 'Mandato', - 'Mangiapane', - 'Matusek', - 'Newgard', - 'Notte', - 'Purdin', - 'Ramaker', - 'Reddoch', - 'Rensing', - 'Rohrman', - 'Romm', - 'Rudiger', - 'Torti', - 'Travaglini', - 'Uno', - 'Wojciak', - 'Yannuzzi', - 'Zeien', - 'Arpino', - 'Borgstrom', - 'Burkemper', - 'Cristino', - 'Detjen', - 'Gienger', - 'Glockner', - 'Grillot', - 'Jentz', - 'Kendzierski', - 'Klebe', - 'Knippenberg', - 'Kusler', - 'Olofson', - 'Orlov', - 'Rindt', - 'Stallbaumer', - 'Troost', - 'Turri', - 'Uzelac', - 'Weichert', - 'Sweazy', - 'Alcivar', - 'Canner', - 'Lottman', - 'Salame', - 'Berkes', - 'Pickren', - 'Ganson', - 'Odonell', - 'Geron', - 'Kasa', - 'Banbury', - 'Tinnel', - 'Umble', - 'Flow', - 'Kirt', - 'Rhule', - 'Diles', - 'Seeney', - 'Givans', - 'Mckethan', - 'Crusoe', - 'Darko', - 'Mucker', - 'Kizzee', - 'Daniely', - 'Nutall', - 'Angove', - 'Appelhans', - 'Balder', - 'Blatchley', - 'Botkins', - 'Brisk', - 'Burandt', - 'Clowdus', - 'Debauche', - 'Deily', - 'Group', - 'Hoecker', - 'Holsonback', - 'Humpert', - 'Jacquin', - 'Jurica', - 'Karnik', - 'Krontz', - 'Lapiana', - 'Lenzo', - 'Luscombe', - 'Madey', - 'Mirabito', - 'Neifert', - 'Pennino', - 'Piechota', - 'Pizzimenti', - 'Reeg', - 'Roarty', - 'Routzahn', - 'Salsedo', - 'Schuff', - 'Silveri', - 'Steckman', - 'Supak', - 'Swackhamer', - 'Trusler', - 'Vizzini', - 'Wences', - 'Whelton', - 'Zachar', - 'Albertsen', - 'Bischel', - 'Brigandi', - 'Campoy', - 'Castagnola', - 'Doenges', - 'Flessner', - 'Garbers', - 'Jezewski', - 'Kozlov', - 'Niedbalski', - 'Schillo', - 'Schoepke', - 'Schranz', - 'Trulson', - 'Vanwyhe', - 'Versluis', - 'Zavadil', - 'Brau', - 'Rudell', - 'Golen', - 'Meter', - 'Sherrin', - 'Tolly', - 'Mandala', - 'Calcano', - 'Lewing', - 'Sedeno', - 'Ramalho', - 'Haggar', - 'Borns', - 'Matherson', - 'Cobin', - 'Turnley', - 'Pone', - 'Tuner', - 'Crandle', - 'Sturkey', - 'Heggins', - 'Tisby', - 'Allbaugh', - 'Baars', - 'Bethard', - 'Brenizer', - 'Bussman', - 'Casebier', - 'Castanos', - 'Climaco', - 'Dux', - 'Farrens', - 'Frediani', - 'Gaccione', - 'Garciaperez', - 'Hoppa', - 'Juckett', - 'Klinkner', - 'Kooy', - 'Krinke', - 'Locy', - 'Lovecchio', - 'Lukin', - 'Machia', - 'Mand', - 'Maslin', - 'Mehrotra', - 'Nicolet', - 'Peyser', - 'Reckart', - 'Roanhorse', - 'Rokicki', - 'Sargis', - 'Sciullo', - 'Shevchuk', - 'Sindoni', - 'Slankard', - 'Sobiech', - 'Stoneberger', - 'Stys', - 'Tuzzolino', - 'Waligora', - 'Wiland', - 'Clabough', - 'Drawbaugh', - 'Figurski', - 'Gibeault', - 'Gojcaj', - 'Hartfiel', - 'Inbody', - 'Konarski', - 'Kruszka', - 'Letarte', - 'Lillich', - 'Mccandlish', - 'Mollenkopf', - 'Oltmann', - 'Pfenninger', - 'Ruediger', - 'Schaben', - 'Shauger', - 'Wilczak', - 'Wolanin', - 'Ziehm', - 'Bassinger', - 'Brannick', - 'Schlereth', - 'Capri', - 'Roscher', - 'Pasqual', - 'Lallo', - 'Sweney', - 'Rozario', - 'Hamblet', - 'Muckleroy', - 'Frankson', - 'Moure', - 'Shrieves', - 'Bosket', - 'Strowbridge', - 'Hawkin', - 'Cooperwood', - 'Agena', - 'Barrowman', - 'Belko', - 'Blasdell', - 'Brobeck', - 'Chieffo', - 'Cooperrider', - 'Dickard', - 'Erion', - 'Fradkin', - 'Hattery', - 'Hefferon', - 'Hofstra', - 'Hoiland', - 'Jirak', - 'Klugman', - 'Klundt', - 'Knope', - 'Lawniczak', - 'Luckenbach', - 'Manzione', - 'Mccombie', - 'Minden', - 'Mousel', - 'Ridling', - 'Rightmire', - 'Ritzel', - 'Santori', - 'Semmens', - 'Snyders', - 'Spargur', - 'Staszewski', - 'Swiech', - 'Tasso', - 'Veldhuizen', - 'Vuolo', - 'Wojnarowski', - 'Yoe', - 'Bachler', - 'Cimo', - 'Hippen', - 'Klimaszewski', - 'Kohlhepp', - 'Kovacich', - 'Kretsch', - 'Lacoursiere', - 'Lopezmartinez', - 'Marsiglia', - 'Metzker', - 'Murchie', - 'Paradee', - 'Pfefferle', - 'Rothert', - 'Skellenger', - 'Tourangeau', - 'Beumer', - 'Thunder', - 'Uden', - 'Broe', - 'Moxon', - 'Kassin', - 'Murton', - 'Hockley', - 'Vinet', - 'Suthers', - 'Bayman', - 'Cokeley', - 'Ailey', - 'Crossfield', - 'Desha', - 'Dowson', - 'Acheampong', - 'Boomsma', - 'Buer', - 'Caratachea', - 'Dascenzo', - 'Debes', - 'Degroote', - 'Dillie', - 'Dorsi', - 'Dorward', - 'Eyestone', - 'Geister', - 'Gonia', - 'Heiler', - 'Hin', - 'Hoheisel', - 'Horger', - 'Hulce', - 'Kainer', - 'Kerkman', - 'Kloehn', - 'Krempasky', - 'Kuehnel', - 'Leetch', - 'Lio', - 'Lohrey', - 'Lucchetti', - 'Machnik', - 'Majeske', - 'Martire', - 'Mores', - 'Oyen', - 'Pappert', - 'Platas', - 'Podany', - 'Prata', - 'Radoncic', - 'Sainato', - 'Salada', - 'Serota', - 'Tatsch', - 'Torbeck', - 'Vilhauer', - 'Waltner', - 'Wauters', - 'Welge', - 'Yoss', - 'Bigwood', - 'Brunsman', - 'Civitello', - 'Compston', - 'Cuccaro', - 'Denholm', - 'Emmick', - 'Gadzinski', - 'Goedken', - 'Graumann', - 'Hackert', - 'Hardacre', - 'Hehl', - 'Magliocco', - 'Marotto', - 'Ozanich', - 'Pidcock', - 'Schlangen', - 'Scoma', - 'Sobecki', - 'Spreng', - 'Thalmann', - 'Wolfrum', - 'Groninger', - 'Howatt', - 'Kindy', - 'Swor', - 'Ledden', - 'Voyer', - 'Colli', - 'Andrae', - 'Duchemin', - 'Boker', - 'Malter', - 'Snooks', - 'Morss', - 'Haylett', - 'Mitter', - 'Fairey', - 'Kenerson', - 'Albea', - 'Ellerson', - 'Alcindor', - 'Gadison', - 'Arabia', - 'Bundren', - 'Calica', - 'Cartaya', - 'Cielo', - 'Ebbers', - 'Entler', - 'Friedly', - 'Granja', - 'Landt', - 'Lorensen', - 'Michelini', - 'Oliveto', - 'Piela', - 'Reust', - 'Roussos', - 'Sanluis', - 'Seier', - 'Sobolik', - 'Stader', - 'Stetzer', - 'Tetley', - 'Zirbes', - 'Bridenbaugh', - 'Chinnici', - 'Crabbs', - 'Evilsizer', - 'Favaloro', - 'Haeberle', - 'Hopfensperger', - 'Kijowski', - 'Kingbird', - 'Leikam', - 'Montavon', - 'Petrossian', - 'Quizhpi', - 'Spoelstra', - 'Testani', - 'Plaut', - 'Windt', - 'Dubie', - 'Kozinski', - 'Sorell', - 'Nish', - 'Katon', - 'Soy', - 'Pelcher', - 'Sayres', - 'Waitman', - 'Relph', - 'Hearld', - 'Farewell', - 'Giordani', - 'Canida', - 'Martian', - 'Suliman', - 'Mckesson', - 'Randon', - 'Eastmond', - 'Willaims', - 'Collington', - 'Hardge', - 'Asevedo', - 'Beauchene', - 'Bebeau', - 'Bobick', - 'Bogacki', - 'Bolich', - 'Bonadonna', - 'Butsch', - 'Coltrin', - 'Corbello', - 'Dastrup', - 'Dunshee', - 'Firpo', - 'Foister', - 'Franssen', - 'Fredriksen', - 'Gfeller', - 'Glassner', - 'Johanns', - 'Korson', - 'Langsam', - 'Linstrom', - 'Longstaff', - 'Lukic', - 'Maler', - 'Marteney', - 'Milardo', - 'Rhatigan', - 'Ruetz', - 'Semel', - 'Senske', - 'Shatswell', - 'Simmering', - 'Tasch', - 'Vanskike', - 'Verano', - 'Viscardi', - 'Weidmann', - 'Doubet', - 'Farraj', - 'Fritter', - 'Griesinger', - 'Horkey', - 'Hornik', - 'Izatt', - 'Klayman', - 'Mantei', - 'Notz', - 'Oberholzer', - 'Petko', - 'Rueth', - 'Rygiel', - 'Tumolo', - 'Unterreiner', - 'Urgo', - 'Weisbecker', - 'Weniger', - 'Zarro', - 'Zunino', - 'Goldmann', - 'Verderber', - 'Glennie', - 'Shere', - 'Lamos', - 'Face', - 'Sparger', - 'Donnay', - 'Kage', - 'Leason', - 'Mcgue', - 'Brickle', - 'Mae', - 'Thomaston', - 'Dunnell', - 'Tillie', - 'Miggins', - 'Geffrard', - 'Aubel', - 'Backe', - 'Beaumier', - 'Bloor', - 'Brackbill', - 'Brandvold', - 'Bylund', - 'Carbary', - 'Catrambone', - 'Dapolito', - 'Dillenburg', - 'Elliff', - 'Fehnel', - 'Ferriss', - 'Gellner', - 'Graw', - 'Guilbeault', - 'Hautala', - 'Hollenberg', - 'Imparato', - 'Kaner', - 'Kley', - 'Lanzer', - 'Laterza', - 'Legner', - 'Lombardozzi', - 'Mcerlean', - 'Mcgilton', - 'Mohring', - 'Neeper', - 'Pollinger', - 'Pullara', - 'Sagona', - 'Scripter', - 'Skillen', - 'Streeper', - 'Tritch', - 'Vayda', - 'Verbeek', - 'Wenberg', - 'Youngers', - 'Bayus', - 'Cobaugh', - 'Dolak', - 'Forys', - 'Genther', - 'Jankovich', - 'Kneale', - 'Komp', - 'Kreher', - 'Kuwahara', - 'Mclouth', - 'Melland', - 'Molesky', - 'Neustadt', - 'Oesterling', - 'Quirke', - 'Roeper', - 'Stantz', - 'Vandenboom', - 'Venhuizen', - 'Westermeyer', - 'Embury', - 'Cozort', - 'Crispo', - 'Woollard', - 'Thiery', - 'Lecy', - 'Terris', - 'Stencil', - 'Yero', - 'Bollard', - 'Chander', - 'Shepp', - 'Younkins', - 'Jon', - 'Anselm', - 'Deveraux', - 'Better', - 'Birth', - 'Hoskie', - 'Kirtz', - 'Encalade', - 'Aprea', - 'Bernick', - 'Bialy', - 'Bolenbaugh', - 'Chinea', - 'Cwiklinski', - 'Dunavan', - 'Dunckel', - 'Essen', - 'Ferner', - 'Gallick', - 'Gruba', - 'Hauss', - 'Intriago', - 'Javaid', - 'Kaney', - 'Klemens', - 'Kuriakose', - 'Leyda', - 'Losurdo', - 'Mcelhone', - 'Methot', - 'Morioka', - 'Mundorf', - 'Nocito', - 'Nordmann', - 'Oommen', - 'Pfahl', - 'Piquette', - 'Prinsen', - 'Sacramento', - 'Shenker', - 'Skidgel', - 'Sobalvarro', - 'Soldo', - 'Synan', - 'Tostenson', - 'Trotti', - 'Vienneau', - 'Vigneau', - 'Waitkus', - 'Wiess', - 'Bartmess', - 'Comparan', - 'Dalonzo', - 'Dutrow', - 'Fleegle', - 'Fronek', - 'Handrich', - 'Hazelip', - 'Heinig', - 'Macapagal', - 'Masciarelli', - 'Pitstick', - 'Radakovich', - 'Ripberger', - 'Schwebel', - 'Slomski', - 'Stinchfield', - 'Zegers', - 'Zeiser', - 'Kimmer', - 'Rippon', - 'Satz', - 'Bosques', - 'Mcnickle', - 'Yarwood', - 'Babar', - 'Ghazi', - 'Mcquary', - 'Africa', - 'Sofer', - 'Marsland', - 'Curby', - 'Odor', - 'Gillem', - 'Selmer', - 'Delmas', - 'Lamison', - 'Lanes', - 'Shadd', - 'Goard', - 'Haylock', - 'Sermon', - 'Meachem', - 'Vernet', - 'Akiona', - 'Avitabile', - 'Berkson', - 'Bisono', - 'Busic', - 'Caroselli', - 'Corradi', - 'Delval', - 'Egley', - 'Elkind', - 'Everling', - 'Ferrario', - 'Frumkin', - 'Gelder', - 'Gironda', - 'Glasheen', - 'Goette', - 'Gotts', - 'Haub', - 'Herro', - 'Hudzik', - 'Hula', - 'Inboden', - 'Isensee', - 'Kiesewetter', - 'Koetje', - 'Laughridge', - 'Lovewell', - 'Meeuwsen', - 'Mokry', - 'Navarez', - 'Plake', - 'Quain', - 'Reppucci', - 'Sorn', - 'Tallerico', - 'Uselman', - 'Verrastro', - 'Wineberg', - 'Blazina', - 'Falardeau', - 'Garavito', - 'Gellerman', - 'Havins', - 'Kurdziel', - 'Liedel', - 'Lofstrom', - 'Pakula', - 'Presby', - 'Ringstad', - 'Rokosz', - 'Schuchart', - 'Seckler', - 'Verderame', - 'Veselka', - 'Asfour', - 'Delanoy', - 'Fromer', - 'Koba', - 'Kostrzewa', - 'Melle', - 'Merkey', - 'Scalese', - 'Oritz', - 'Kilgour', - 'Piker', - 'Janet', - 'Huge', - 'Hails', - 'Dobey', - 'Escoe', - 'Rasool', - 'Gilcrest', - 'Codrington', - 'Jeangilles', - 'Outley', - 'Bambach', - 'Beaulac', - 'Begue', - 'Bobeck', - 'Buccino', - 'Carrigg', - 'Cranney', - 'Denninger', - 'Dicioccio', - 'Eapen', - 'Fargnoli', - 'Fatica', - 'Fernicola', - 'Forse', - 'Freck', - 'Gardipee', - 'Gibas', - 'Goeman', - 'Guadian', - 'Hlad', - 'Jakab', - 'Kishimoto', - 'Krenn', - 'Lagesse', - 'Lhommedieu', - 'Lusch', - 'Mausolf', - 'Mazzocchi', - 'Mcdavitt', - 'Noseworthy', - 'Passante', - 'Placzek', - 'Quamme', - 'Ringgenberg', - 'Spiegelman', - 'Vinluan', - 'Wachsman', - 'Bacigalupi', - 'Baechle', - 'Baetz', - 'Barsch', - 'Colbaugh', - 'Devoto', - 'Dimercurio', - 'Dosanjh', - 'Dukeman', - 'Ferger', - 'Garinger', - 'Grelle', - 'Guyett', - 'Harpenau', - 'Hundal', - 'Kamerer', - 'Klomp', - 'Licklider', - 'Martinec', - 'Matzek', - 'Nixdorf', - 'Pankonin', - 'Pogosyan', - 'Schweickert', - 'Smethurst', - 'Stroope', - 'Zwack', - 'Tebbetts', - 'Stains', - 'Tosado', - 'Carles', - 'Rings', - 'Hebard', - 'Choplin', - 'Townshend', - 'Doorn', - 'Aja', - 'Picking', - 'Oneall', - 'Logie', - 'Aro', - 'Dua', - 'Heney', - 'Manard', - 'Atchinson', - 'Breech', - 'Brashers', - 'Addams', - 'Nooner', - 'Barsh', - 'Orum', - 'Dancey', - 'Bamba', - 'Kareem', - 'Theard', - 'Marseille', - 'Molette', - 'Getachew', - 'Saintfleur', - 'Frimpong', - 'Anglada', - 'Attardo', - 'Barreira', - 'Bleicher', - 'Bonecutter', - 'Bricco', - 'Compian', - 'Creppel', - 'Cuadras', - 'Cuccio', - 'Cutsforth', - 'Dinino', - 'Eskelson', - 'Freemyer', - 'Friedhoff', - 'Grandt', - 'Holzmann', - 'Hoverson', - 'Hurteau', - 'Iacona', - 'Jergens', - 'Kingham', - 'Leiterman', - 'Leugers', - 'Leyh', - 'Lotti', - 'Majkowski', - 'Mossberg', - 'Nuffer', - 'Oaxaca', - 'Pagenkopf', - 'Paille', - 'Petzoldt', - 'Rogalla', - 'Siddens', - 'Siddoway', - 'Spatafora', - 'Tufo', - 'Weismann', - 'Werntz', - 'Wilz', - 'Ammirati', - 'Benninghoff', - 'Escarsega', - 'Fessel', - 'Hurless', - 'Jastrzebski', - 'Klingerman', - 'Kurilla', - 'Kuzmin', - 'Meserole', - 'Politz', - 'Pollino', - 'Rettke', - 'Sinay', - 'Strebeck', - 'Strycharz', - 'Suhre', - 'Thumm', - 'Trybus', - 'Uhrin', - 'Weisberger', - 'Zeger', - 'Carringer', - 'Sitts', - 'Lungren', - 'Iiams', - 'Sudbury', - 'Surrette', - 'Chellis', - 'Yore', - 'Joice', - 'Foot', - 'Ausley', - 'Scioneaux', - 'Mcaffee', - 'Pinn', - 'Maina', - 'Dorce', - 'Agrusa', - 'Albornoz', - 'Arave', - 'Bacallao', - 'Bendavid', - 'Bochner', - 'Bortle', - 'Carragher', - 'Chalfin', - 'Courtade', - 'Dagle', - 'Debuhr', - 'Fowble', - 'Galinsky', - 'Hardigree', - 'Haulk', - 'Hendron', - 'Herringshaw', - 'Jayaraman', - 'Koestler', - 'Konicek', - 'Kutscher', - 'Lachowicz', - 'Lafauci', - 'Lansky', - 'Lazarski', - 'Lolli', - 'Ludvigsen', - 'Manternach', - 'Martorelli', - 'Mcquillin', - 'Mikaelian', - 'Northcraft', - 'Nyborg', - 'Palone', - 'Peckman', - 'Schwebach', - 'Simbeck', - 'Sittler', - 'Udovich', - 'Viesca', - 'Yazell', - 'Zimmers', - 'Bielen', - 'Cohron', - 'Dearcos', - 'Feezor', - 'Hilgart', - 'Karriker', - 'Klingberg', - 'Leisenring', - 'Napora', - 'Nedved', - 'Okeson', - 'Seratt', - 'Trautner', - 'Trimarco', - 'Turkel', - 'Bronder', - 'Itani', - 'Verona', - 'Blackbird', - 'Laque', - 'Karpel', - 'Louro', - 'Hamson', - 'Ashland', - 'Gruel', - 'Breer', - 'Wesely', - 'Bebo', - 'Conery', - 'Mccarry', - 'Cradic', - 'Aytes', - 'Dikes', - 'Soltau', - 'Debois', - 'Berko', - 'Callins', - 'Anastacio', - 'Balbi', - 'Bata', - 'Bechel', - 'Borsuk', - 'Chihuahua', - 'Cindric', - 'Denapoli', - 'Dotzler', - 'Dusing', - 'Dziekan', - 'Eifler', - 'Franchino', - 'Garritano', - 'Herrarte', - 'Jaskot', - 'Kettell', - 'Kingsford', - 'Marsters', - 'Oshel', - 'Overacker', - 'Pagliarulo', - 'Pannier', - 'Pyun', - 'Rardon', - 'Reville', - 'Rogozinski', - 'Scatena', - 'Schoeppner', - 'Senkbeil', - 'Silkey', - 'Takhar', - 'Whitebread', - 'Wiech', - 'Adelsberger', - 'Aslinger', - 'Bhattacharyya', - 'Brege', - 'Burright', - 'Cafarella', - 'Chlebowski', - 'Decaprio', - 'Dilello', - 'Dresher', - 'Finkbiner', - 'Gerlich', - 'Ignasiak', - 'Kataoka', - 'Kearl', - 'Pingitore', - 'Sellick', - 'Sinning', - 'Stojanovic', - 'Vanasten', - 'Vanluven', - 'Westerfeld', - 'Mahala', - 'Biancardi', - 'Velardo', - 'Payes', - 'Debello', - 'Kyes', - 'Reever', - 'Joung', - 'Coran', - 'Perrow', - 'Linzer', - 'Birchett', - 'Poles', - 'Cajuste', - 'Albergo', - 'Andal', - 'Belaire', - 'Borell', - 'Bruehl', - 'Celani', - 'Cerruti', - 'Crellin', - 'Delcarlo', - 'Dubach', - 'Elicker', - 'Fialkowski', - 'Ganim', - 'Gladieux', - 'Glendening', - 'Glomski', - 'Kalp', - 'Kavan', - 'Kawabata', - 'Kever', - 'Kisch', - 'Maiorino', - 'Masaki', - 'Mcgeough', - 'Miyoshi', - 'Nand', - 'Nitka', - 'Novakovich', - 'Penagos', - 'Pierini', - 'Rassi', - 'Rorke', - 'Rosenboom', - 'Rossmann', - 'Scarfone', - 'Scarsella', - 'Siedschlag', - 'Sobotta', - 'Studnicka', - 'Teeling', - 'Tegtmeyer', - 'Woznick', - 'Beske', - 'Dersch', - 'Deschepper', - 'Duffner', - 'Geroux', - 'Lindvall', - 'Linnemann', - 'Roethler', - 'Scanlin', - 'Schaecher', - 'Schmude', - 'Schwertner', - 'Shimamoto', - 'Stratmann', - 'Stufflebean', - 'Ulatowski', - 'Witkop', - 'Landrus', - 'Sahin', - 'Araque', - 'Massett', - 'Meanor', - 'Sebo', - 'Delic', - 'Bryand', - 'Frederico', - 'Portuondo', - 'Verry', - 'Browe', - 'Winecoff', - 'Gipp', - 'Khamis', - 'Ingrum', - 'Gilliand', - 'Poinsett', - 'Hagley', - 'Valliant', - 'Henly', - 'Bingley', - 'Romulus', - 'Moyd', - 'Abascal', - 'Adelstein', - 'Arabian', - 'Barcelos', - 'Barot', - 'Cabacungan', - 'Darco', - 'Dickmeyer', - 'Gindi', - 'Grone', - 'Haberland', - 'Hachem', - 'Humbarger', - 'Insco', - 'Kravchuk', - 'Mackowski', - 'Madrazo', - 'Malesky', - 'Markowicz', - 'Mcconnon', - 'Meiring', - 'Micalizzi', - 'Moeser', - 'Mortier', - 'Muegge', - 'Ollar', - 'Pamperin', - 'Pusch', - 'Remache', - 'Roginski', - 'Rothbauer', - 'Sellin', - 'Stachurski', - 'Stelmack', - 'Suprenant', - 'Totzke', - 'Uemura', - 'Vandercook', - 'Yott', - 'Zaher', - 'Autio', - 'Barnhard', - 'Brys', - 'Chisenhall', - 'Deiters', - 'Fetsko', - 'Finzel', - 'Gangwer', - 'Grygiel', - 'Heidelberger', - 'Kommer', - 'Latchford', - 'Liszka', - 'Mcconaha', - 'Miazga', - 'Nettesheim', - 'Oelschlager', - 'Rafuse', - 'Reichow', - 'Santosuosso', - 'Sebastiani', - 'Serratore', - 'Spenner', - 'Steffenson', - 'Strehl', - 'Tropeano', - 'Vanstraten', - 'Vegh', - 'Virrueta', - 'Wilhide', - 'Prey', - 'Ullmer', - 'Ferraz', - 'Mazor', - 'Vinje', - 'Mory', - 'Rody', - 'Dowen', - 'Bord', - 'Rajkumar', - 'Qadir', - 'Turbin', - 'Rorex', - 'Wilmott', - 'Grandpre', - 'Bucker', - 'Reasonover', - 'Holoman', - 'Mustapha', - 'Warsame', - 'Laday', - 'Whack', - 'Blahut', - 'Boxell', - 'Britnell', - 'Buehl', - 'Burri', - 'Cesaro', - 'Degrand', - 'Demetro', - 'Fadeley', - 'Fischel', - 'Florer', - 'Givler', - 'Gockley', - 'Iuliano', - 'Koral', - 'Kotlarz', - 'Kraai', - 'Kvamme', - 'Latchaw', - 'Lopeman', - 'Manocchio', - 'Martinezgarcia', - 'Minehart', - 'Narasimhan', - 'Nier', - 'Niziolek', - 'Oliff', - 'Piascik', - 'Pitera', - 'Pronovost', - 'Roseboom', - 'Rosevear', - 'Runkles', - 'Santmyer', - 'Skillin', - 'Stamas', - 'Storbeck', - 'Teicher', - 'Titterington', - 'Tomkinson', - 'Tzeng', - 'Vukovic', - 'Wescoat', - 'Algeo', - 'Aronow', - 'Balbach', - 'Brockbank', - 'Caloca', - 'Caughlin', - 'Devincenzi', - 'Doetsch', - 'Filby', - 'Godar', - 'Keeven', - 'Marchetta', - 'Quiram', - 'Rudeen', - 'Siemen', - 'Suderman', - 'Tacke', - 'Walby', - 'Fram', - 'Maccarthy', - 'Fana', - 'Kimberley', - 'Richens', - 'Doser', - 'Bigford', - 'Brazie', - 'Haroon', - 'Mcginniss', - 'Knipfer', - 'Seltz', - 'Laton', - 'Balow', - 'Cramp', - 'Edger', - 'Alonge', - 'Beagles', - 'Ken', - 'Peary', - 'Lifsey', - 'Acy', - 'Lightbourne', - 'Antwi', - 'Arntzen', - 'Bracknell', - 'Brewbaker', - 'Carville', - 'Cinquemani', - 'Corales', - 'Corgan', - 'Craze', - 'Dechristopher', - 'Eltzroth', - 'Fjelstad', - 'Forinash', - 'Gudenkauf', - 'Hapeman', - 'Hassing', - 'Hurm', - 'Jaurigue', - 'Kneisel', - 'Kulwicki', - 'Lookingbill', - 'Moist', - 'Naderi', - 'Nicoli', - 'Nicoson', - 'Olvey', - 'Remaly', - 'Stare', - 'Steinruck', - 'Switala', - 'Tada', - 'Toves', - 'Traber', - 'Tuohey', - 'Venti', - 'Vinal', - 'Wahle', - 'Yarosh', - 'Balinski', - 'Bauknecht', - 'Bernauer', - 'Bink', - 'Chudzik', - 'Coppess', - 'Corrick', - 'Gruener', - 'Kutter', - 'Malkiewicz', - 'Marking', - 'Mcgrain', - 'Melberg', - 'Ohmann', - 'Pellicane', - 'Regehr', - 'Schmoldt', - 'Schmuhl', - 'Starmer', - 'Stiens', - 'Whilden', - 'Yearick', - 'Desmith', - 'Habiger', - 'Papay', - 'Study', - 'Toot', - 'Franzoni', - 'Neuhoff', - 'Boreman', - 'Sayas', - 'Hinks', - 'Dax', - 'Sasnett', - 'Hannis', - 'Rotan', - 'Haze', - 'Jennifer', - 'Barganier', - 'Milson', - 'Kinnie', - 'Boyde', - 'Dyce', - 'Cuttino', - 'Neals', - 'Mccovery', - 'Abaya', - 'Balz', - 'Bezold', - 'Breighner', - 'Buttacavoli', - 'Cattani', - 'Detzel', - 'Douthat', - 'Dunay', - 'Eicholtz', - 'Eirich', - 'Felkner', - 'Friedenberg', - 'Haskew', - 'Henes', - 'Jamroz', - 'Kelter', - 'Kutzer', - 'Laughner', - 'Livoti', - 'Magistro', - 'Makinson', - 'Manwell', - 'Mckimmy', - 'Mcwethy', - 'Pacholski', - 'Pankau', - 'Poh', - 'Purewal', - 'Remedios', - 'Ringuette', - 'Rocchi', - 'Rojero', - 'Sabina', - 'Schiffner', - 'Sellen', - 'Setaro', - 'Soledad', - 'Stoermer', - 'Tal', - 'Vanwyk', - 'Waack', - 'Xenos', - 'Yoakam', - 'Zweber', - 'Apachito', - 'Belluomini', - 'Cancelliere', - 'Cervini', - 'Davidovich', - 'Deguia', - 'Doxtator', - 'Errera', - 'Eshbaugh', - 'Mandt', - 'Pautler', - 'Raczynski', - 'Roemmich', - 'Rosamilia', - 'Shelhamer', - 'Vandevoorde', - 'Vanengen', - 'Vindiola', - 'Weyman', - 'Dufur', - 'Reaver', - 'Bugh', - 'Starley', - 'Macmullen', - 'Mataya', - 'Bucknell', - 'Taitano', - 'Coole', - 'Huguet', - 'Top', - 'Rockford', - 'Carrithers', - 'Garrell', - 'Toppins', - 'Mayner', - 'Dantes', - 'Tones', - 'Dauphine', - 'Shillingford', - 'Massiah', - 'Angermeier', - 'Arrizon', - 'Azer', - 'Badami', - 'Beeck', - 'Buddenhagen', - 'Cheyney', - 'Danielski', - 'Delgiorno', - 'Enslin', - 'Erber', - 'Fluegge', - 'Fresco', - 'Frishman', - 'Geigle', - 'Gervase', - 'Giangregorio', - 'Glauber', - 'Hedding', - 'Janota', - 'Labore', - 'Ladley', - 'Levee', - 'Lipuma', - 'Lomanto', - 'Magos', - 'Mangen', - 'Miltner', - 'Mitschke', - 'Pingley', - 'Puertas', - 'Schwed', - 'Seminario', - 'Sinsel', - 'Sliney', - 'Spielmann', - 'Standage', - 'Waas', - 'Cooprider', - 'Delguercio', - 'Dockham', - 'Dohse', - 'Doubrava', - 'Emerine', - 'Frazzini', - 'Godown', - 'Heidbreder', - 'Ladow', - 'Lariccia', - 'Molzahn', - 'Opiela', - 'Ordorica', - 'Otterness', - 'Owczarzak', - 'Rafalski', - 'Smigel', - 'Urbas', - 'Andon', - 'Kota', - 'Ruzzo', - 'Pheasant', - 'Proch', - 'Sullinger', - 'Ezra', - 'Portes', - 'Mynhier', - 'Depree', - 'Slight', - 'Selley', - 'Daughety', - 'Shamel', - 'Glasby', - 'Casher', - 'Brisby', - 'Whittley', - 'Brye', - 'Mackins', - 'Allam', - 'Berwanger', - 'Borgmeyer', - 'Brumlow', - 'Cashmore', - 'Clementz', - 'Coopman', - 'Corti', - 'Danzer', - 'Deater', - 'Delprado', - 'Dibuono', - 'Dwan', - 'Edling', - 'Ekins', - 'Feighner', - 'Galica', - 'Gasparro', - 'Geisert', - 'Gilvin', - 'Glotzbach', - 'Goostree', - 'Hollenkamp', - 'Hronek', - 'Kamins', - 'Khun', - 'Klimowicz', - 'Langella', - 'Letz', - 'Lindh', - 'Lycan', - 'Magouirk', - 'Mcbryar', - 'Milonas', - 'Patalano', - 'Petrides', - 'Plocher', - 'Signer', - 'Sinagra', - 'Taibi', - 'Thissen', - 'Thueson', - 'Tietje', - 'Trebilcock', - 'Zelek', - 'Alavez', - 'Beyersdorf', - 'Ferraiolo', - 'Flodin', - 'Fulwiler', - 'Gieselman', - 'Heisinger', - 'Hutmacher', - 'Laraia', - 'Lempke', - 'Marchiano', - 'Mendia', - 'Milberger', - 'Murri', - 'Willhelm', - 'Yannone', - 'Diss', - 'Golab', - 'Meuth', - 'Strebe', - 'Berenguer', - 'Cunard', - 'Girvan', - 'Pacer', - 'Nate', - 'Weare', - 'Dile', - 'Donate', - 'Pamer', - 'Charlet', - 'Roades', - 'Krah', - 'Merton', - 'Debrito', - 'Montel', - 'Guimont', - 'Caire', - 'Olley', - 'Ausborn', - 'Ramdass', - 'Stores', - 'Hush', - 'Watler', - 'Robotham', - 'Stanislaus', - 'Bellevue', - 'Almeter', - 'Bartold', - 'Bathgate', - 'Bollier', - 'Boundy', - 'Bushart', - 'Buzek', - 'Cauthon', - 'Daudelin', - 'Delguidice', - 'Depaolis', - 'Dysert', - 'Forsee', - 'Goglia', - 'Gruenhagen', - 'Guilfoil', - 'Guldin', - 'Gurnee', - 'Henzel', - 'Jurney', - 'Kable', - 'Korenek', - 'Kussman', - 'Liese', - 'Mauss', - 'Mexicano', - 'Morini', - 'Oathout', - 'Paragas', - 'Phommachanh', - 'Pixton', - 'Pucciarelli', - 'Rabine', - 'Ramlow', - 'Ravert', - 'Redhouse', - 'Renault', - 'Rybinski', - 'Sahlin', - 'Scherger', - 'Schoeffler', - 'Smolinsky', - 'Stadnik', - 'Stallsmith', - 'Timoney', - 'Whiteeagle', - 'Woodsmall', - 'Zinter', - 'Bargmann', - 'Basich', - 'Bossio', - 'Coutant', - 'Curcuru', - 'Duitsman', - 'Hunkele', - 'Kingry', - 'Kotek', - 'Mancusi', - 'Orama', - 'Paszek', - 'Schrodt', - 'Schuknecht', - 'Torsiello', - 'Troise', - 'Wernimont', - 'Wipperfurth', - 'Wissner', - 'Zahradnik', - 'Deasis', - 'Pac', - 'Vowles', - 'Montesi', - 'Carie', - 'Name', - 'Broy', - 'Hillson', - 'Exton', - 'Skerritt', - 'Ude', - 'Allston', - 'Cliatt', - 'Chevis', - 'Poitier', - 'Barrasso', - 'Bartnicki', - 'Broski', - 'Cobleigh', - 'Crickenberger', - 'Cruces', - 'Cumba', - 'Diodato', - 'Dipietrantonio', - 'Eyerly', - 'Fedler', - 'Fetting', - 'Francavilla', - 'Frein', - 'Gasparyan', - 'Gingold', - 'Gunnarson', - 'Houy', - 'Huelsmann', - 'Jeppsen', - 'Labreck', - 'Lefton', - 'Maenza', - 'Mauritz', - 'Mingione', - 'Mullany', - 'Mussell', - 'Muston', - 'Paraiso', - 'Peelman', - 'Penuel', - 'Piccola', - 'Punt', - 'Ramella', - 'Rauser', - 'Reas', - 'Reino', - 'Schlack', - 'Sebastiano', - 'Sgambati', - 'Shackett', - 'Szpak', - 'Thalacker', - 'Theissen', - 'Tutko', - 'Astarita', - 'Blazejewski', - 'Dejaynes', - 'Djordjevic', - 'Eckenroth', - 'Estala', - 'Giacomo', - 'Glaub', - 'Golubski', - 'Guerreiro', - 'Housholder', - 'Kashuba', - 'Klute', - 'Lennartz', - 'Messamore', - 'Rovito', - 'Schreurs', - 'Starcevich', - 'Starkel', - 'Szczerba', - 'Thomassen', - 'Varkey', - 'Yorio', - 'Guba', - 'Unzicker', - 'Howry', - 'Bido', - 'Farella', - 'Frane', - 'Werry', - 'Cornia', - 'Postal', - 'Humphres', - 'Ran', - 'Macnair', - 'Duston', - 'Aveni', - 'Mcconn', - 'Sistare', - 'Wadell', - 'Naraine', - 'Mubarak', - 'Lonzo', - 'Shyne', - 'Tilmon', - 'Symonette', - 'Shinholster', - 'Oree', - 'Ogarro', - 'Quashie', - 'Almario', - 'Antonsen', - 'Armetta', - 'Avetisyan', - 'Bania', - 'Barricklow', - 'Bloemker', - 'Cannavo', - 'Dolliver', - 'Espenshade', - 'Falor', - 'Fukuhara', - 'Gemme', - 'Goldfinger', - 'Gonya', - 'Hamamoto', - 'Hindi', - 'Hiraldo', - 'Holquin', - 'Janco', - 'Janow', - 'Lemming', - 'Macchio', - 'Mago', - 'Mavity', - 'Mcnamer', - 'Mushrush', - 'Niskanen', - 'Ohms', - 'Pawluk', - 'Popple', - 'Poser', - 'Schiavi', - 'Stram', - 'Streight', - 'Stueck', - 'Vansandt', - 'Vivona', - 'Vongphakdy', - 'Zalar', - 'Zipper', - 'Altic', - 'Billmeyer', - 'Boghosian', - 'Bohlke', - 'Cisewski', - 'Gabrielsen', - 'Gianotti', - 'Heffler', - 'Holian', - 'Kannenberg', - 'Lenius', - 'Manuelito', - 'Mugavero', - 'Reinier', - 'Rekowski', - 'Sadlier', - 'Scialdone', - 'Stromquist', - 'Vittetoe', - 'Vorwald', - 'Widrig', - 'Audi', - 'Peral', - 'Devery', - 'Gato', - 'Sower', - 'Vanes', - 'Bonnes', - 'Hense', - 'Counsell', - 'Frankie', - 'Colford', - 'Wanser', - 'Mickels', - 'Briddell', - 'Washinton', - 'Antilla', - 'Baxendale', - 'Beining', - 'Belveal', - 'Boedecker', - 'Bottenfield', - 'Bufano', - 'Castellana', - 'Chaikin', - 'Cherne', - 'Costilow', - 'Dzialo', - 'Goeken', - 'Gombert', - 'Hammerman', - 'Hansman', - 'Hartling', - 'Kalani', - 'Klich', - 'Kolodziejski', - 'Kramar', - 'Lapinsky', - 'Latterell', - 'Lipsitz', - 'Loma', - 'Lukenbill', - 'Marxen', - 'Metallo', - 'Molner', - 'Niquette', - 'Ostrand', - 'Pelster', - 'Previti', - 'Rennaker', - 'Roering', - 'Roode', - 'Saltos', - 'Sangiovanni', - 'Schiraldi', - 'Schlafer', - 'Schwering', - 'Seedorf', - 'Sklenar', - 'Spinello', - 'Steinhorst', - 'Urueta', - 'Vonstein', - 'Bonczek', - 'Casalino', - 'Chiaro', - 'Doffing', - 'Downham', - 'Gillotti', - 'Hearl', - 'Karges', - 'Kunesh', - 'Langeland', - 'Maertz', - 'Mattinson', - 'Mignano', - 'Pasquinelli', - 'Petracca', - 'Pherigo', - 'Pikus', - 'Reichmuth', - 'Schwegman', - 'Schwerdt', - 'Seelman', - 'Winquist', - 'Wyka', - 'Yahr', - 'Bunkers', - 'Delnegro', - 'Norder', - 'Manas', - 'Polites', - 'Grape', - 'Jares', - 'Surges', - 'Asa', - 'Copeman', - 'Askar', - 'Goman', - 'Whitmyer', - 'Cohran', - 'Imbert', - 'Beaner', - 'Hugger', - 'Petion', - 'Lauture', - 'Andringa', - 'Athanas', - 'Butrick', - 'Caronna', - 'Dedominicis', - 'Eligio', - 'Fasick', - 'Hilinski', - 'Hinely', - 'Idler', - 'Janosko', - 'Kempner', - 'Klosinski', - 'Lapeyrouse', - 'Lindroth', - 'Marcon', - 'Meding', - 'Peppin', - 'Quizon', - 'Rectenwald', - 'Roessner', - 'Roets', - 'Schonberger', - 'Szostek', - 'Wassink', - 'Whan', - 'Yeakle', - 'Alguire', - 'Bielenberg', - 'Bisaillon', - 'Bonenberger', - 'Centola', - 'Colaizzi', - 'Deroos', - 'Eberlin', - 'Ehrig', - 'Ferenc', - 'Freiermuth', - 'Fruchter', - 'Garnto', - 'Huxford', - 'Knous', - 'Luttman', - 'Mulry', - 'Schirm', - 'Stankovic', - 'Authier', - 'Derise', - 'Doo', - 'Kessen', - 'Maline', - 'Porada', - 'Vasconez', - 'Haseman', - 'Tonner', - 'Woodroof', - 'Bedrossian', - 'Cranmore', - 'Dodaro', - 'Hommes', - 'Harmony', - 'Peno', - 'Mccommon', - 'Colver', - 'Olinde', - 'Oba', - 'Colone', - 'Warbington', - 'Monie', - 'Whitmill', - 'Moxey', - 'Canion', - 'Mcclenney', - 'Hallmon', - 'Austill', - 'Berni', - 'Boehning', - 'Bueso', - 'Cefalo', - 'Conneely', - 'Demicco', - 'Dieppa', - 'Duris', - 'Durnil', - 'Erxleben', - 'Hashimi', - 'Hedquist', - 'Koc', - 'Lamattina', - 'Lassman', - 'Ligman', - 'Lukins', - 'Mackler', - 'Manolis', - 'Mou', - 'Oblak', - 'Omahoney', - 'Paolo', - 'Pollok', - 'Priess', - 'Reeh', - 'Rempfer', - 'Rickerd', - 'Schoettle', - 'Serritella', - 'Steedman', - 'Suss', - 'Tanimoto', - 'Thaden', - 'Thelin', - 'Vanwingerden', - 'Wacha', - 'Weldin', - 'Youkhana', - 'Bazzano', - 'Behring', - 'Caliri', - 'Cocchi', - 'Croissant', - 'Dibbern', - 'Figiel', - 'Flygare', - 'Grieshop', - 'Iten', - 'Kaupp', - 'Linnane', - 'Plybon', - 'Rappleye', - 'Romanik', - 'Saefong', - 'Schetter', - 'Schryer', - 'Siwik', - 'Snitker', - 'Tomasic', - 'Wavra', - 'Auen', - 'Thone', - 'Marso', - 'Shadid', - 'Cake', - 'Louvier', - 'Macia', - 'Areola', - 'Kardell', - 'Strome', - 'Coogle', - 'Delis', - 'Pistorius', - 'Raybourn', - 'Sula', - 'Math', - 'Sanda', - 'Renaldo', - 'Pat', - 'Florance', - 'Brank', - 'Alice', - 'Rosebrough', - 'Quiett', - 'Henigan', - 'Mcclees', - 'Dase', - 'Bagot', - 'Kings', - 'Lanehart', - 'Barbary', - 'Stitts', - 'Aurora', - 'Baldoni', - 'Barkalow', - 'Bohnet', - 'Bosshart', - 'Decapua', - 'Denbo', - 'Deneault', - 'Dinse', - 'Dul', - 'Estle', - 'Filipski', - 'Fishell', - 'Fluckiger', - 'Glassberg', - 'Janick', - 'Juda', - 'Kibbee', - 'Kreisler', - 'Lawther', - 'Levangie', - 'Lichtenwalner', - 'Lucking', - 'Meiner', - 'Mileham', - 'Milz', - 'Reposa', - 'Rinehimer', - 'Rupley', - 'Sandez', - 'Schinke', - 'Sharpnack', - 'Sineath', - 'Tax', - 'Thumma', - 'Urda', - 'Widdison', - 'Bergdoll', - 'Bruhl', - 'Chesmore', - 'Delfavero', - 'Ferderer', - 'Haueter', - 'Hirshberg', - 'Hollobaugh', - 'Lalama', - 'Mckeag', - 'Mehlhoff', - 'Mirchandani', - 'Orwick', - 'Puskarich', - 'Schlotzhauer', - 'Stoiber', - 'Swetz', - 'Basara', - 'Magaw', - 'Amble', - 'Hawe', - 'Toren', - 'Parilla', - 'Gowell', - 'Selkirk', - 'Edris', - 'Ariel', - 'Kihara', - 'Dunkerson', - 'Halk', - 'Mooty', - 'Tippen', - 'Fullenwider', - 'Herford', - 'Salton', - 'Feider', - 'Buckhannon', - 'Mckneely', - 'Milon', - 'Whiters', - 'Barasch', - 'Baria', - 'Basques', - 'Beavin', - 'Borre', - 'Branz', - 'Broers', - 'Conca', - 'Cortopassi', - 'Courchesne', - 'Crisanti', - 'Cumpian', - 'Dagan', - 'Dekay', - 'Demartin', - 'Dewaard', - 'Dowland', - 'Duffell', - 'Ebersol', - 'Faiola', - 'Frontz', - 'Fryling', - 'Garczynski', - 'Hanway', - 'Huettner', - 'Janovsky', - 'Johndrow', - 'Kahana', - 'Kaniewski', - 'Kulish', - 'Lich', - 'Lincks', - 'Loppnow', - 'Macnab', - 'Mcconaughy', - 'Melroy', - 'Noviello', - 'Orn', - 'Pacas', - 'Peppel', - 'Polidori', - 'Radi', - 'Riesgo', - 'Romanoski', - 'Sagrero', - 'Schirripa', - 'Spack', - 'Sternhagen', - 'Tamburri', - 'Traczyk', - 'Uballe', - 'Vandruff', - 'Voght', - 'Weant', - 'Weinel', - 'Angerman', - 'Boultinghouse', - 'Dolinar', - 'Dripps', - 'Dubow', - 'Ehrhard', - 'Janvrin', - 'Lazear', - 'Liddiard', - 'Madayag', - 'Mirkin', - 'Monticello', - 'Mulka', - 'Oliger', - 'Pierceall', - 'Pittner', - 'Polkowski', - 'Prindiville', - 'Rasnic', - 'Tellefsen', - 'Uffelman', - 'Vandenbergh', - 'Weisenbach', - 'Wiedmeyer', - 'Wintle', - 'Wisz', - 'Yorba', - 'Holtmeyer', - 'Tabet', - 'Laham', - 'Barsoum', - 'Henner', - 'Idle', - 'Shaft', - 'Rennels', - 'Swarm', - 'Forgie', - 'Khaled', - 'Avon', - 'Hewey', - 'Grober', - 'Pipe', - 'Macfadden', - 'Keath', - 'Fergason', - 'Polland', - 'Brownley', - 'Haslip', - 'Crocket', - 'Tines', - 'Juniel', - 'Opara', - 'Bethley', - 'Ambuehl', - 'Bagheri', - 'Baquera', - 'Bertoli', - 'Bisek', - 'Borroto', - 'Botten', - 'Bovenzi', - 'Bruntz', - 'Buehring', - 'Canche', - 'Cicco', - 'Dambach', - 'Delellis', - 'Deniston', - 'Dirico', - 'Feagle', - 'Frayne', - 'Haagenson', - 'Janicke', - 'Kashyap', - 'Kastel', - 'Kruck', - 'Langi', - 'Lapka', - 'Marschner', - 'Megia', - 'Nesta', - 'Nevala', - 'Oblinger', - 'Picchi', - 'Rodeffer', - 'Salkin', - 'Scavuzzo', - 'Sladky', - 'Soyars', - 'Suchil', - 'Thielbar', - 'Timoteo', - 'Vanhise', - 'Varden', - 'Waldoch', - 'Watling', - 'Werk', - 'Becvar', - 'Betteridge', - 'Bolliger', - 'Bonifield', - 'Buchberger', - 'Caprara', - 'Castrogiovanni', - 'Fallaw', - 'Geeting', - 'Hiegel', - 'Hulgan', - 'Kokesh', - 'Lanting', - 'Mcphetridge', - 'Nuxoll', - 'Soun', - 'Strothman', - 'Triska', - 'Vensel', - 'Wesolek', - 'Wixted', - 'Wolgemuth', - 'Yedinak', - 'Anthis', - 'Manfred', - 'Agans', - 'Lafoe', - 'Mcginnes', - 'Folwell', - 'Galvao', - 'Carmo', - 'Valin', - 'Woon', - 'Degregory', - 'Evangelist', - 'Coast', - 'Strater', - 'Decou', - 'Pears', - 'Nellums', - 'Kynard', - 'Boursiquot', - 'Ruffins', - 'Akhavan', - 'Baloga', - 'Barany', - 'Buche', - 'Davoli', - 'Fennewald', - 'Figler', - 'Frede', - 'Gannett', - 'Ghannam', - 'Handlon', - 'Herridge', - 'Jakel', - 'Kamphuis', - 'Kattan', - 'Kemplin', - 'Klecka', - 'Korver', - 'Kozakiewicz', - 'Linenberger', - 'Lofaso', - 'Lorman', - 'Lueder', - 'Mcconahay', - 'Mcternan', - 'Mench', - 'Norenberg', - 'Oro', - 'Ostenson', - 'Pant', - 'Peardon', - 'Pertuit', - 'Ritzert', - 'Salvetti', - 'Sandner', - 'Sheek', - 'Sniegowski', - 'Sorbo', - 'Sperbeck', - 'Sump', - 'Supinski', - 'Sweetin', - 'Toenjes', - 'Velotta', - 'Venier', - 'Veracruz', - 'Wender', - 'Yamagata', - 'Arostegui', - 'Balestra', - 'Blumstein', - 'Carras', - 'Grauberger', - 'Howdeshell', - 'Murayama', - 'Nippert', - 'Notch', - 'Reisert', - 'Sebren', - 'Tetzloff', - 'Venneman', - 'Douds', - 'Lineman', - 'Powles', - 'Huet', - 'Matto', - 'Roes', - 'Dillin', - 'Lagan', - 'Bakes', - 'Yann', - 'Canterberry', - 'Milum', - 'Hinderman', - 'Linzey', - 'Ballen', - 'Ventress', - 'Prysock', - 'Bangle', - 'Blinder', - 'Bugaj', - 'Carlisi', - 'Dimario', - 'Dzikowski', - 'Gaetz', - 'Galves', - 'Ghazal', - 'Golebiewski', - 'Hadsall', - 'Hogberg', - 'Krammer', - 'Kreisher', - 'Lamia', - 'Luhmann', - 'Lupa', - 'Michelotti', - 'Nesci', - 'Paape', - 'Posthumus', - 'Reth', - 'Sassman', - 'Schlechter', - 'Schlie', - 'Schumacker', - 'Seliger', - 'Shanholtzer', - 'Strojny', - 'Taglieri', - 'Tibbles', - 'Tregoning', - 'Valine', - 'Zeiset', - 'Antu', - 'Bierwirth', - 'Birenbaum', - 'Boeder', - 'Dobkins', - 'Fenoglio', - 'Jentsch', - 'Marcinkiewicz', - 'Mruk', - 'Muhlbauer', - 'Namba', - 'Oettinger', - 'Rigor', - 'Rothweiler', - 'Schmader', - 'Schork', - 'Vandevoort', - 'Brenny', - 'Neels', - 'Fodge', - 'Que', - 'Dalpe', - 'Guerard', - 'Lammey', - 'Alfredo', - 'Corrin', - 'Quarry', - 'Reise', - 'Derrow', - 'Worrel', - 'Tennent', - 'Cassis', - 'Winson', - 'Cornet', - 'Garlin', - 'Saucer', - 'Ursery', - 'Saffo', - 'Battee', - 'Ackerley', - 'Ackland', - 'Allmendinger', - 'Altamura', - 'Anastas', - 'Artola', - 'Baldassari', - 'Bayron', - 'Bouwkamp', - 'Buonopane', - 'Chronis', - 'Coffaro', - 'Dech', - 'Delfierro', - 'Depaulo', - 'Digges', - 'Dowda', - 'Drab', - 'Feijoo', - 'Formato', - 'Friedli', - 'Hanahan', - 'Hegna', - 'Igarashi', - 'Kamai', - 'Kory', - 'Kuzel', - 'Lewkowicz', - 'Lumbra', - 'Mccreadie', - 'Meisch', - 'Montoro', - 'Pamintuan', - 'Petrow', - 'Pulcini', - 'Shewell', - 'Spitznagel', - 'Swedlund', - 'Terhorst', - 'Wilberg', - 'Willwerth', - 'Affinito', - 'Baune', - 'Beichner', - 'Boutell', - 'Challender', - 'Ellestad', - 'Gomm', - 'Hochstatter', - 'Jasko', - 'Kielar', - 'Kimmerle', - 'Kirshenbaum', - 'Kotila', - 'Lecker', - 'Manross', - 'Mcnevin', - 'Neuburger', - 'Verderosa', - 'Wiltsey', - 'Caminero', - 'Gianfrancesco', - 'Shiverdecker', - 'Amman', - 'Flavell', - 'Oconor', - 'Shure', - 'Hanagan', - 'Bokor', - 'Mashaw', - 'Ground', - 'Brittenham', - 'Pinera', - 'Smaltz', - 'Hold', - 'Gallamore', - 'Delon', - 'Hearing', - 'Rynes', - 'Cocklin', - 'Cassie', - 'Calligan', - 'Josue', - 'Congo', - 'Tennell', - 'Blyther', - 'Azarian', - 'Bauernfeind', - 'Beeghly', - 'Berget', - 'Brayfield', - 'Cerasoli', - 'Dedecker', - 'Gloeckner', - 'Herriges', - 'Hoganson', - 'Ivancic', - 'Jakeway', - 'Kayne', - 'Kitko', - 'Kohlbeck', - 'Krabbenhoft', - 'Kumari', - 'Lauri', - 'Leiber', - 'Minke', - 'Montecino', - 'Moutray', - 'Munshi', - 'Ohlin', - 'Portocarrero', - 'Rados', - 'Roedl', - 'Rossing', - 'Schake', - 'Simonin', - 'Staffa', - 'Stroschein', - 'Titman', - 'Treder', - 'Vonada', - 'Xenakis', - 'Aulds', - 'Benedick', - 'Boulais', - 'Butikofer', - 'Butorac', - 'Contento', - 'Goetting', - 'Goldammer', - 'Hopke', - 'Koppes', - 'Phetteplace', - 'Roehrs', - 'Schul', - 'Slabach', - 'Steinmiller', - 'Sucharski', - 'Vorwerk', - 'Wahlert', - 'Wheatcraft', - 'Abellera', - 'Jutte', - 'Baumgarner', - 'Tijerino', - 'Awadallah', - 'Horen', - 'Lina', - 'Stanbrough', - 'College', - 'Jarry', - 'Keas', - 'Mordan', - 'Ramnauth', - 'Rena', - 'Wa', - 'Petters', - 'Ramnath', - 'Hellams', - 'Mamon', - 'Cheese', - 'Meggett', - 'Anttila', - 'Beilman', - 'Binsfeld', - 'Brining', - 'Brubeck', - 'Carcione', - 'Chandran', - 'Chaudhuri', - 'Cogliano', - 'Dimaano', - 'Dols', - 'Doughten', - 'Ehrenfeld', - 'Elena', - 'Fausnaugh', - 'Fetz', - 'Fogelson', - 'Fraleigh', - 'Gaza', - 'Giesey', - 'Gockel', - 'Gougeon', - 'Granito', - 'Grassia', - 'Hauserman', - 'Idrovo', - 'Iwan', - 'Janning', - 'Kaffenberger', - 'Kichline', - 'Kimoto', - 'Kolodny', - 'Kortum', - 'Lafevers', - 'Lodi', - 'Longton', - 'Ludke', - 'Manganelli', - 'Mccuan', - 'Merryfield', - 'Mezquita', - 'Morandi', - 'Neibauer', - 'Oran', - 'Ozaeta', - 'Pacha', - 'Palese', - 'Perala', - 'Pisarcik', - 'Pobanz', - 'Pommer', - 'Pontrelli', - 'Prabhakar', - 'Rehmann', - 'Scheunemann', - 'Severini', - 'Skalla', - 'Srinivas', - 'Stadtmiller', - 'Trentman', - 'Trinka', - 'Tutterow', - 'Vari', - 'Wence', - 'Zeff', - 'Anagnos', - 'Arvayo', - 'Bihl', - 'Darbyshire', - 'Deeg', - 'Domagalski', - 'Estenson', - 'Finkenbinder', - 'Gaboriault', - 'Kastens', - 'Lacek', - 'Merkin', - 'Mersman', - 'Nicolaus', - 'Offerdahl', - 'Pallett', - 'Platten', - 'Quesnell', - 'Skene', - 'Sondag', - 'Wolfrom', - 'Mineer', - 'Sor', - 'Canard', - 'Mcmeen', - 'Tur', - 'Giner', - 'Mackrell', - 'Alic', - 'Sampath', - 'Baby', - 'Beales', - 'Kadri', - 'Minot', - 'Bienvenue', - 'Millirons', - 'Woodstock', - 'Landing', - 'Limehouse', - 'Andonian', - 'Armentor', - 'Asai', - 'Cutaia', - 'Darji', - 'Delsanto', - 'Deutch', - 'Droge', - 'Emme', - 'Flenner', - 'Gaida', - 'Gladd', - 'Guettler', - 'Guggisberg', - 'Guier', - 'Habenicht', - 'Heininger', - 'Helfman', - 'Hiscox', - 'Holtorf', - 'Hovious', - 'Juul', - 'Lacock', - 'Lepisto', - 'Malanowski', - 'Marineau', - 'Matza', - 'Meffert', - 'Nuon', - 'Oneto', - 'Padmanabhan', - 'Pantuso', - 'Pesci', - 'Rosenbluth', - 'Rubano', - 'Sedlar', - 'Sferrazza', - 'Sifuentez', - 'Simione', - 'Torossian', - 'Vaux', - 'Weilbacher', - 'Wiatrek', - 'Brzoska', - 'Caltabiano', - 'Csaszar', - 'Eyerman', - 'Geissinger', - 'Gioffre', - 'Grilliot', - 'Grotz', - 'Harrower', - 'Jaroszewski', - 'Jokerst', - 'Kamali', - 'Kampmann', - 'Klemz', - 'Koike', - 'Lista', - 'Mcconkie', - 'Mencia', - 'Missler', - 'Olshefski', - 'Omdahl', - 'Penunuri', - 'Scheckel', - 'Schreiter', - 'Swackhammer', - 'Taflinger', - 'Tegethoff', - 'Ummel', - 'Wetsel', - 'Wissmann', - 'Porr', - 'Ramser', - 'Russett', - 'Clucas', - 'Matlin', - 'Noblet', - 'Boyan', - 'Koman', - 'Lope', - 'Deman', - 'Latendresse', - 'Bound', - 'Rijos', - 'Bouillon', - 'Crunkleton', - 'Jayson', - 'Anne', - 'Staude', - 'Sturn', - 'Burdell', - 'Arther', - 'Yett', - 'Woolcock', - 'Clemon', - 'Saintjean', - 'Sainvil', - 'Coverson', - 'Barroga', - 'Benedicto', - 'Borin', - 'Budrow', - 'Cuddihy', - 'Forness', - 'Gohman', - 'Hepker', - 'Hilscher', - 'Holien', - 'Holstad', - 'Hopfer', - 'Hulburt', - 'Kalter', - 'Kuehnle', - 'Lachica', - 'Macioce', - 'Massimo', - 'Matsubara', - 'Meaker', - 'Mehmedovic', - 'Minckler', - 'Miralles', - 'Mostek', - 'Oshita', - 'Parthasarathy', - 'Roszak', - 'Rottenberg', - 'Rydman', - 'Shankman', - 'Sprong', - 'Stenerson', - 'Strubel', - 'Tavano', - 'Thornberg', - 'Trumpower', - 'Whittinghill', - 'Altenhofen', - 'Bartolucci', - 'Debski', - 'Dekoning', - 'Dottavio', - 'Emminger', - 'Hodkinson', - 'Hurtubise', - 'Lauridsen', - 'Leinberger', - 'Luskin', - 'Pask', - 'Rehfeld', - 'Spagna', - 'Szumski', - 'Szymborski', - 'Teem', - 'Tritschler', - 'Tschantz', - 'Tsutsui', - 'Vanecek', - 'Haddaway', - 'Colombe', - 'Mayol', - 'Shivley', - 'Maturin', - 'Babe', - 'Bovey', - 'Bathe', - 'Belliard', - 'Loner', - 'Arrow', - 'Billa', - 'Mcneish', - 'Kinton', - 'Scarber', - 'Donson', - 'Atherley', - 'Abdulaziz', - 'Age', - 'Carreker', - 'Tory', - 'Leduff', - 'Wattley', - 'Altergott', - 'Belitz', - 'Bidinger', - 'Blauch', - 'Cariker', - 'Condren', - 'Curiale', - 'Dronet', - 'Elstad', - 'Esquerra', - 'Fread', - 'Gilb', - 'Goga', - 'Gonyo', - 'Grudzien', - 'Hino', - 'Ishler', - 'Jacober', - 'Kilty', - 'Kuhrt', - 'Lairmore', - 'Lamba', - 'Lorek', - 'Lucich', - 'Marcou', - 'Mcgath', - 'Menze', - 'Mindel', - 'Nabb', - 'Ottosen', - 'Pann', - 'Ratkowski', - 'Saurer', - 'Sedore', - 'Shonka', - 'Soberano', - 'Sossamon', - 'Stdennis', - 'Stillinger', - 'Tager', - 'Tersigni', - 'Tissue', - 'Trampe', - 'Twite', - 'Whitling', - 'Wiebusch', - 'Abundez', - 'Bisping', - 'Candella', - 'Dahill', - 'Groebner', - 'Gulbrandsen', - 'Hasenauer', - 'Heesch', - 'Hipwell', - 'Kamrowski', - 'Keyworth', - 'Kleinschmit', - 'Legorreta', - 'Minium', - 'Mixter', - 'Neiswonger', - 'Purk', - 'Rinkenberger', - 'Rosenkrans', - 'Rozenberg', - 'Simenson', - 'Soltes', - 'Storino', - 'Viereck', - 'Schaafsma', - 'Craigie', - 'Amorin', - 'Latner', - 'Bowmer', - 'Nasby', - 'Bada', - 'Rami', - 'Mcglashan', - 'Reede', - 'Police', - 'Cobey', - 'Dahir', - 'Dirden', - 'Destine', - 'Akkerman', - 'Azzopardi', - 'Blankenhorn', - 'Bolio', - 'Brandhorst', - 'Buchter', - 'Canul', - 'Cocozza', - 'Collantes', - 'Cronic', - 'Cullifer', - 'Delpizzo', - 'Demoranville', - 'Dolder', - 'Dvorsky', - 'Eggett', - 'Elgersma', - 'Episcopo', - 'Esses', - 'Fehlman', - 'Gansen', - 'Garciamartinez', - 'Goldwater', - 'Gushue', - 'Hittner', - 'Igel', - 'Jupin', - 'Kostoff', - 'Kruschke', - 'Kuechler', - 'Labs', - 'Lacerte', - 'Lagle', - 'Leischner', - 'Linders', - 'Marulanda', - 'Meindl', - 'Melman', - 'Menden', - 'Orbach', - 'Patak', - 'Patras', - 'Petroni', - 'Rabenold', - 'Rapisarda', - 'Rodenburg', - 'Roelle', - 'Schar', - 'Scherbarth', - 'Simar', - 'Thoen', - 'Trana', - 'Tuch', - 'Turko', - 'Wamser', - 'Weinfeld', - 'Wirz', - 'Zatorski', - 'Zbinden', - 'Aksamit', - 'Asebedo', - 'Biello', - 'Bouchey', - 'Callejo', - 'Espanol', - 'Flathers', - 'Kunka', - 'Liaw', - 'Mckowen', - 'Mitrano', - 'Needler', - 'Och', - 'Paolella', - 'Patricelli', - 'Recine', - 'Rengel', - 'Spinler', - 'Wagenaar', - 'Winnicki', - 'Eichert', - 'Dabb', - 'Imrie', - 'Antoni', - 'Lardner', - 'Maund', - 'Schou', - 'Brittin', - 'Anthon', - 'Was', - 'Nevis', - 'Delamar', - 'Mcnorton', - 'Tankard', - 'Boardley', - 'Garcon', - 'Wimes', - 'Antell', - 'Belmarez', - 'Boff', - 'Boughan', - 'Cando', - 'Carrender', - 'Carrieri', - 'Charnley', - 'Cittadino', - 'Cwynar', - 'Deupree', - 'Doepke', - 'Fasone', - 'Fauteux', - 'Foody', - 'Fornal', - 'Fust', - 'Gasner', - 'Gloe', - 'Gorter', - 'Grumbine', - 'Hancher', - 'Hapke', - 'Heckendorn', - 'Heinlen', - 'Hilgeman', - 'Kahre', - 'Kakos', - 'Kops', - 'Lahn', - 'Leiferman', - 'Lothamer', - 'Mallis', - 'Napierkowski', - 'Orbin', - 'Panno', - 'Piacente', - 'Posas', - 'Ragasa', - 'Sonora', - 'Stupka', - 'Tio', - 'Valido', - 'Weyrick', - 'Argall', - 'Arrighi', - 'Bohlken', - 'Desrocher', - 'Distad', - 'Erkkila', - 'Gherardi', - 'Goughnour', - 'Koltz', - 'Koperski', - 'Lafalce', - 'Lucken', - 'Meleski', - 'Mortellaro', - 'Nagorski', - 'Pedrotti', - 'Pruyn', - 'Revard', - 'Saffran', - 'Schnoebelen', - 'Sermersheim', - 'Skroch', - 'Vandervliet', - 'Alwood', - 'Bosso', - 'Hor', - 'Licerio', - 'Septer', - 'Labo', - 'Lessa', - 'Ooley', - 'Gorgas', - 'Medal', - 'Coull', - 'Creely', - 'Bolland', - 'Ishaq', - 'Legore', - 'Alicia', - 'Fillingame', - 'Levers', - 'Flight', - 'Woodrick', - 'Berrie', - 'Buckels', - 'Pigue', - 'Crosse', - 'Speakes', - 'Wynes', - 'Mussa', - 'Highbaugh', - 'Venning', - 'Dupas', - 'Mccastle', - 'Andreoni', - 'Bakula', - 'Besemer', - 'Blier', - 'Braaksma', - 'Brocco', - 'Cajas', - 'Campano', - 'Crapser', - 'Dentinger', - 'Deziel', - 'Dragos', - 'Ekblad', - 'Gargis', - 'Gilberto', - 'Guadron', - 'Hollern', - 'Leibensperger', - 'Lindaman', - 'Lumadue', - 'Mault', - 'Mieses', - 'Nanninga', - 'Nudd', - 'Ouch', - 'Ramin', - 'Reggio', - 'Ruttan', - 'Saccomanno', - 'Scheaffer', - 'Sohm', - 'Spaniol', - 'Stenner', - 'Strieter', - 'Takashima', - 'Vaid', - 'Venzke', - 'Wallwork', - 'Zaffuto', - 'Zaucha', - 'Zemel', - 'Zinni', - 'Alltop', - 'Ciolek', - 'Empie', - 'Flitton', - 'Gullikson', - 'Hassebrock', - 'Kanitz', - 'Kirschenmann', - 'Krivanek', - 'Loseke', - 'Mckercher', - 'Melching', - 'Nham', - 'Ormerod', - 'Randlett', - 'Reifel', - 'Sawada', - 'Sofranko', - 'Stoia', - 'Umeda', - 'Eagon', - 'Hucker', - 'Kenniston', - 'Salus', - 'Ayyad', - 'Camey', - 'Dacy', - 'Joa', - 'Peerson', - 'Rossy', - 'Aure', - 'Keetch', - 'Sprigg', - 'Southgate', - 'Parden', - 'Andris', - 'Bossman', - 'Blondell', - 'Carmickle', - 'Pelly', - 'Mceachron', - 'Marry', - 'Burel', - 'Shark', - 'Flash', - 'Rickenbacker', - 'Foots', - 'Sillah', - 'Almgren', - 'Awtrey', - 'Berganza', - 'Boehne', - 'Bralley', - 'Brosnahan', - 'Caddick', - 'Chandonnet', - 'Cullimore', - 'Darroch', - 'Eimers', - 'Flam', - 'Howerter', - 'Jerzak', - 'Kabler', - 'Kirkes', - 'Kopper', - 'Krakow', - 'Linskey', - 'Lizzi', - 'Luria', - 'Marcrum', - 'Mathy', - 'Matulich', - 'Miskin', - 'Moghadam', - 'Nagarajan', - 'Packham', - 'Papania', - 'Paup', - 'Rippeon', - 'Rolli', - 'Rubey', - 'Scherzinger', - 'Scrima', - 'Sharar', - 'Shoberg', - 'Stupar', - 'Tendler', - 'Tobiason', - 'Vanvooren', - 'Zisa', - 'Bindel', - 'Flasch', - 'Graetz', - 'Heintzman', - 'Kosanke', - 'Longden', - 'Mahfouz', - 'Mormile', - 'Nannini', - 'Olaes', - 'Panik', - 'Putzier', - 'Radilla', - 'Schaedler', - 'Schoepf', - 'Sianez', - 'Taucher', - 'Wiebelhaus', - 'Banka', - 'Console', - 'Derego', - 'Vile', - 'Colgin', - 'Drage', - 'Josten', - 'Luckadoo', - 'Ryen', - 'Bako', - 'Ow', - 'Patient', - 'Elmes', - 'Mossa', - 'Colee', - 'Comber', - 'Tippy', - 'Perrell', - 'Axon', - 'Rickson', - 'Postlewaite', - 'Lafargue', - 'Guffin', - 'Cains', - 'Dewindt', - 'Cathy', - 'Tallie', - 'Ausby', - 'Alires', - 'Baz', - 'Bergeman', - 'Bodensteiner', - 'Borghi', - 'Dematos', - 'Denzler', - 'Dorko', - 'Duffett', - 'Dykas', - 'Emerton', - 'Fenger', - 'Fosberg', - 'Gwinner', - 'Kniess', - 'Lerew', - 'Lohner', - 'Lun', - 'Maita', - 'Mandler', - 'Marcoe', - 'Nikolov', - 'Paschen', - 'Paver', - 'Prosperi', - 'Rackliff', - 'Roever', - 'Ruberg', - 'Ruest', - 'Schnick', - 'Schuur', - 'Sowash', - 'Zanca', - 'Brecheen', - 'Brusky', - 'Chauca', - 'Debernardi', - 'Froio', - 'Gadway', - 'Karoly', - 'Kintzel', - 'Kneisley', - 'Kruser', - 'Lindfors', - 'Lwin', - 'Oursler', - 'Peruski', - 'Petteys', - 'Rottmann', - 'Schroeck', - 'Stenglein', - 'Vigen', - 'Wempe', - 'Zehren', - 'Wollen', - 'Dismore', - 'Santalucia', - 'Laza', - 'Pesnell', - 'Litle', - 'Markson', - 'Piercefield', - 'Jerrett', - 'Virginia', - 'Demonbreun', - 'Tugman', - 'Ramoutar', - 'Bazin', - 'Ola', - 'Alamin', - 'Adebayo', - 'Berkland', - 'Bernt', - 'Briguglio', - 'Bulnes', - 'Burack', - 'Cantoran', - 'Giardini', - 'Goetzke', - 'Graziosi', - 'Guberman', - 'Kamaka', - 'Karvonen', - 'Kitz', - 'Kopera', - 'Krempa', - 'Linkenhoker', - 'Mascioli', - 'Matlick', - 'Mcmahill', - 'Medaglia', - 'Mirarchi', - 'Mondry', - 'Muhlestein', - 'Murty', - 'Orender', - 'Pesantez', - 'Postiglione', - 'Reisen', - 'Riff', - 'Scarantino', - 'Seelinger', - 'Seher', - 'Sharum', - 'Sorice', - 'Staebler', - 'Tanney', - 'Tech', - 'Tramontano', - 'Trude', - 'Vasudevan', - 'Wareing', - 'Westerhold', - 'Wohlfarth', - 'Achorn', - 'Boesel', - 'Calabaza', - 'Dunkleberger', - 'Erck', - 'Fanger', - 'Felmlee', - 'Friebel', - 'Gabrys', - 'Godsil', - 'Goldhammer', - 'Gourneau', - 'Kaseman', - 'Keysor', - 'Mccargar', - 'Mittag', - 'Narum', - 'Schoeneck', - 'Stenquist', - 'Sunderlin', - 'Tarazon', - 'Tietze', - 'Wemmer', - 'Witthuhn', - 'Durango', - 'Simerson', - 'Beber', - 'Bjorn', - 'Neuville', - 'Preas', - 'Reitter', - 'Senf', - 'Mcclatchy', - 'Sanor', - 'Benney', - 'Sarrazin', - 'Woodliff', - 'Bramlet', - 'Cullin', - 'Wessells', - 'Higgens', - 'Rout', - 'Craigen', - 'Ackers', - 'Wickliff', - 'Hofler', - 'Pilgram', - 'Mcfayden', - 'Dillworth', - 'Robenson', - 'Mateen', - 'Ambrogio', - 'Aoun', - 'Aranas', - 'Balsiger', - 'Bonzo', - 'Busam', - 'Casassa', - 'Ciborowski', - 'Cotterill', - 'Cressler', - 'Cristales', - 'Crumpacker', - 'Daloisio', - 'Damasco', - 'Depolo', - 'Diguglielmo', - 'Dominik', - 'Esbenshade', - 'Fineran', - 'Formisano', - 'Gandolfi', - 'Geidel', - 'Gerwitz', - 'Grammatico', - 'Idleman', - 'Iwinski', - 'Kerth', - 'Lacouture', - 'Lafoy', - 'Lapid', - 'Lardizabal', - 'Lembcke', - 'Maga', - 'Mahrt', - 'Maniatis', - 'Martinezlopez', - 'Martinovich', - 'Milham', - 'Muscatello', - 'Perezperez', - 'Quiocho', - 'Rickner', - 'Sackrider', - 'Schwarm', - 'Schwebke', - 'Scollard', - 'Seader', - 'Shutters', - 'Skare', - 'Slothower', - 'Steeber', - 'Want', - 'Cherubini', - 'Coslett', - 'Degener', - 'Dulak', - 'Faull', - 'Freyman', - 'Gatchel', - 'Ginzburg', - 'Gronberg', - 'Landeck', - 'Lehenbauer', - 'Lubke', - 'Mcconaughey', - 'Mendonsa', - 'Minnehan', - 'Palaguachi', - 'Peedin', - 'Raithel', - 'Rezabek', - 'Rolfson', - 'Schuitema', - 'Sjodin', - 'Underkoffler', - 'Verrilli', - 'Yogi', - 'Zimpfer', - 'Zingaro', - 'Butrum', - 'Ritson', - 'Martinka', - 'Cashatt', - 'Kearn', - 'Sawtell', - 'Boyster', - 'Broyhill', - 'Cockerell', - 'Thane', - 'Resende', - 'Pealer', - 'Perrot', - 'Everhardt', - 'Breach', - 'Bry', - 'Juma', - 'Mclaine', - 'Paddy', - 'Hennesy', - 'Ledee', - 'Web', - 'Delone', - 'Louison', - 'Hamiel', - 'Tutson', - 'Bellingham', - 'Brenn', - 'Bussen', - 'Charrette', - 'Denenberg', - 'Depascale', - 'Derner', - 'Dondlinger', - 'Favro', - 'Frana', - 'Goeser', - 'Guerrini', - 'Hamideh', - 'Hetu', - 'Hnat', - 'Hollerbach', - 'Kenagy', - 'Kregel', - 'Lammi', - 'Laubacher', - 'Madarang', - 'Mangine', - 'Marut', - 'Mcmahen', - 'Memoli', - 'Milko', - 'Morash', - 'Mulvehill', - 'Nelles', - 'Perfecto', - 'Perkes', - 'Pesantes', - 'Peschke', - 'Polyakov', - 'Preheim', - 'Prust', - 'Reha', - 'Richardt', - 'Rockers', - 'Sartwell', - 'Schedler', - 'Scheler', - 'Skop', - 'Stefko', - 'Tatlock', - 'Tiley', - 'Waldecker', - 'Weinbaum', - 'Aguallo', - 'Benassi', - 'Bezio', - 'Bockover', - 'Dobesh', - 'Encina', - 'Eversman', - 'Haverfield', - 'Heigl', - 'Holzhauser', - 'Liebenow', - 'Mesenbrink', - 'Mittendorf', - 'Normoyle', - 'Pickart', - 'Rosselot', - 'Shigley', - 'Skufca', - 'Stroot', - 'Walth', - 'Wernert', - 'Lahood', - 'Ragain', - 'Stumpe', - 'Kolle', - 'Minerd', - 'Dickeson', - 'Koone', - 'Stoessel', - 'Kington', - 'Soe', - 'Wailes', - 'Monet', - 'Mccullars', - 'Huguenin', - 'Warnell', - 'Calip', - 'Sandles', - 'Fayson', - 'Balik', - 'Bauermeister', - 'Bianculli', - 'Bin', - 'Bring', - 'Busenbark', - 'Canevari', - 'Crile', - 'Dyment', - 'Egelhoff', - 'Elbe', - 'Estudillo', - 'Feigel', - 'Flammer', - 'Folta', - 'Ghuman', - 'Hefferan', - 'Hennick', - 'Hosner', - 'Kilner', - 'Liuzzi', - 'Maj', - 'Massing', - 'Nicolaisen', - 'Ohlrich', - 'Ozdemir', - 'Piccininni', - 'Prem', - 'Primiano', - 'Reek', - 'Riling', - 'Rohweder', - 'Rosasco', - 'Sandau', - 'Santarsiero', - 'Schuhmacher', - 'Stenseth', - 'Stilts', - 'Strohmeier', - 'Thorell', - 'Torr', - 'Vaswani', - 'Yono', - 'Amadon', - 'Ballowe', - 'Betke', - 'Borgwardt', - 'Decelle', - 'Dibiasio', - 'Fieldhouse', - 'Hegyi', - 'Heuberger', - 'Kreiling', - 'Montney', - 'Sammut', - 'Senseney', - 'Takenaka', - 'Tramonte', - 'Zalesky', - 'Zumstein', - 'Bents', - 'Vandersluis', - 'Wieringa', - 'Houlton', - 'Lippens', - 'Maino', - 'Keeny', - 'Bethards', - 'Guillette', - 'Lenn', - 'Minge', - 'Masley', - 'Christley', - 'Gabrielle', - 'Bruington', - 'Perren', - 'Ander', - 'Leeb', - 'Callicott', - 'Peaster', - 'Hardister', - 'Daughtridge', - 'Mclauchlin', - 'Culliver', - 'Missouri', - 'Aloisi', - 'Barua', - 'Bezek', - 'Broshears', - 'Busbin', - 'Cajamarca', - 'Dellarocco', - 'Dezeeuw', - 'Ferrelli', - 'Fieber', - 'Fredin', - 'Giovannoni', - 'Glasner', - 'Grenda', - 'Haberl', - 'Heimsoth', - 'Heinl', - 'Hellickson', - 'Hernandezlopez', - 'Huckeby', - 'Jungman', - 'Langhans', - 'Lingelbach', - 'Manera', - 'Maneri', - 'Marzella', - 'Mennen', - 'Molesworth', - 'Nagano', - 'Narula', - 'Niner', - 'Nordhoff', - 'Olazabal', - 'Perfect', - 'Plonka', - 'Pund', - 'Reincke', - 'Schimek', - 'Seegert', - 'Summar', - 'Tanori', - 'Trethewey', - 'Wehler', - 'Wirthlin', - 'Wolaver', - 'Zuver', - 'Bendure', - 'Bither', - 'Bungert', - 'Chaviano', - 'Derhammer', - 'Disbro', - 'Facchini', - 'Hoefle', - 'Hoepner', - 'Kimmes', - 'Korus', - 'Manfredonia', - 'Neuser', - 'Samarin', - 'Sanghera', - 'Sherburn', - 'Shiplett', - 'Steckelberg', - 'Faist', - 'Cardy', - 'Colan', - 'Goodbar', - 'Boro', - 'Moden', - 'Hardick', - 'Esteve', - 'Rawling', - 'Benet', - 'Nabers', - 'Atkerson', - 'Countess', - 'Thwaites', - 'Caroline', - 'Whisonant', - 'Alridge', - 'Pamphile', - 'Abdelnour', - 'Allebach', - 'Armenti', - 'Baudendistel', - 'Biers', - 'Bockrath', - 'Borgert', - 'Bovino', - 'Burgamy', - 'Cadiente', - 'Calabretta', - 'Cariveau', - 'Christoffel', - 'Daigler', - 'Dannels', - 'Darnold', - 'Decock', - 'Dominski', - 'Fest', - 'Forren', - 'Freise', - 'Galperin', - 'Hackbart', - 'Holtzer', - 'Idell', - 'Kapala', - 'Kohlenberg', - 'Kolton', - 'Lemburg', - 'Lievanos', - 'Maranan', - 'Marchitto', - 'Masini', - 'Mayabb', - 'Mccrossen', - 'Metrick', - 'Molinelli', - 'Oehlert', - 'Parlee', - 'Pizzini', - 'Polachek', - 'Salmans', - 'Selbe', - 'Sickman', - 'Stegmaier', - 'Sulek', - 'Thall', - 'Tiznado', - 'Tonini', - 'Trostel', - 'Warshawsky', - 'Aument', - 'Byrer', - 'Dechaine', - 'Fearnow', - 'Gallicchio', - 'Gertler', - 'Greubel', - 'Hironaka', - 'Kashner', - 'Kleffner', - 'Korthals', - 'Kundinger', - 'Lenger', - 'Lingafelter', - 'Luczynski', - 'Ostermeier', - 'Petrasek', - 'Righetti', - 'Tvedt', - 'Weindel', - 'Wurtzel', - 'Zumbro', - 'Wikel', - 'Burdi', - 'Ozturk', - 'Parmele', - 'Oteri', - 'Alexa', - 'Erven', - 'Keng', - 'Fare', - 'Sade', - 'Saw', - 'Jaquay', - 'Pillay', - 'Kearsley', - 'Kirkby', - 'Game', - 'Herst', - 'Vallie', - 'Bayon', - 'Whitler', - 'Pe', - 'Lockerman', - 'Cogle', - 'Rouzer', - 'Curling', - 'Mandley', - 'Kleckley', - 'Buckson', - 'Risby', - 'Averhart', - 'Almendariz', - 'Angelopoulos', - 'Brallier', - 'Decaire', - 'Deloria', - 'Derham', - 'Drudge', - 'Eckelberry', - 'Ehling', - 'Engebretsen', - 'Ercole', - 'Fiscal', - 'Gabino', - 'Gelvin', - 'Giannetto', - 'Godeaux', - 'Goshert', - 'Hedrich', - 'Ioannou', - 'Jungbluth', - 'Kia', - 'Krusemark', - 'Lader', - 'Lythgoe', - 'Malinak', - 'Mcinvale', - 'Melis', - 'Metsker', - 'Minasyan', - 'Nuhfer', - 'Omana', - 'Parco', - 'Pha', - 'Phanthavong', - 'Proa', - 'Sarli', - 'Schirtzinger', - 'Schlotter', - 'Sharrar', - 'Spielberg', - 'Stelzner', - 'Tschudy', - 'Utke', - 'Weipert', - 'Yera', - 'Berkemeier', - 'Bothun', - 'Dalporto', - 'Deschler', - 'Dragonetti', - 'Hasz', - 'Holtzinger', - 'Kallal', - 'Kesinger', - 'Kilfoyle', - 'Kobylinski', - 'Kramme', - 'Kreh', - 'Lindseth', - 'Plaugher', - 'Rehfeldt', - 'Repine', - 'Roudabush', - 'Swoveland', - 'Teper', - 'Tucek', - 'Wadding', - 'Wenzlick', - 'Ghobrial', - 'Golberg', - 'Soyka', - 'Matura', - 'Moras', - 'Natter', - 'Apps', - 'Imran', - 'Rossel', - 'Harne', - 'Les', - 'Silla', - 'Deblanc', - 'Rhinehardt', - 'Delaware', - 'Alkins', - 'Laidley', - 'Maree', - 'Cassells', - 'Abdulrahman', - 'Cange', - 'Devone', - 'Eustache', - 'Negash', - 'Tanks', - 'Sivels', - 'Cabbagestalk', - 'Ahlin', - 'Akard', - 'Barbaree', - 'Bielat', - 'Bressman', - 'Capurro', - 'Cortazar', - 'Dauphinee', - 'Dornak', - 'Eckl', - 'Eisenhuth', - 'Fazzini', - 'Fraim', - 'Glaab', - 'Glod', - 'Guedea', - 'Hearty', - 'Hinostroza', - 'Honold', - 'Jostes', - 'Korzeniewski', - 'Lobell', - 'Lopardo', - 'Middlekauff', - 'Monfils', - 'Oshana', - 'Schiappa', - 'Schubach', - 'Servantez', - 'Shaler', - 'Siverson', - 'Slimp', - 'Slovacek', - 'Staat', - 'Strassman', - 'Waffle', - 'Wuebker', - 'Beigel', - 'Berardo', - 'Berkery', - 'Bloyer', - 'Cronkright', - 'Cuautle', - 'Devenny', - 'Ghrist', - 'Gipple', - 'Gwilliam', - 'Hunzeker', - 'Ierardi', - 'Kathol', - 'Kienle', - 'Krack', - 'Loeper', - 'Minchey', - 'Pecht', - 'Schaberg', - 'Schollmeyer', - 'Siniscalchi', - 'Toback', - 'Tramp', - 'Vandaele', - 'Witzig', - 'Wivell', - 'Moros', - 'Saso', - 'Gares', - 'Heagle', - 'Murrillo', - 'Stankey', - 'Shamon', - 'Avram', - 'Achor', - 'Ovens', - 'Rames', - 'Perris', - 'Kernes', - 'Semmes', - 'Thaw', - 'Stevison', - 'Clemetson', - 'Belmar', - 'Guster', - 'Bascomb', - 'Adrien', - 'Jeanpaul', - 'Alabi', - 'Jallow', - 'Atamian', - 'Basque', - 'Bubier', - 'Casad', - 'Czekaj', - 'Dejoy', - 'Dulworth', - 'Fatula', - 'Favale', - 'Feutz', - 'Freundlich', - 'Frid', - 'Gagan', - 'Gaughran', - 'Guderian', - 'Hagemeister', - 'Haser', - 'Leibman', - 'Meddings', - 'Narlock', - 'Offenberger', - 'Pesa', - 'Poupard', - 'Raus', - 'Repetti', - 'Revello', - 'Robarts', - 'Rowin', - 'Saltarelli', - 'Sanghvi', - 'Schleyer', - 'Silba', - 'Steuck', - 'Stoffers', - 'Tangredi', - 'Taussig', - 'Tiso', - 'Wehmeier', - 'Zwiefelhofer', - 'Bartelson', - 'Brabender', - 'Cornfield', - 'Davtyan', - 'Delnero', - 'Frontino', - 'Gathman', - 'Graessle', - 'Hinchcliff', - 'Houdeshell', - 'Kapler', - 'Karabin', - 'Kerestes', - 'Lemmen', - 'Merkt', - 'Mitro', - 'Nahm', - 'Nancarrow', - 'Novakowski', - 'Parraz', - 'Revolorio', - 'Schamel', - 'Scowden', - 'Steever', - 'Suastegui', - 'Villarin', - 'Wuellner', - 'Dooly', - 'Erno', - 'Arbelo', - 'Groshek', - 'Boliver', - 'Gane', - 'Bees', - 'Dowds', - 'Newmann', - 'Kewley', - 'Stile', - 'Lobe', - 'Skeet', - 'Burgen', - 'Mckamie', - 'Hubanks', - 'Suleman', - 'Billey', - 'Efferson', - 'Mcleary', - 'Housen', - 'Shambley', - 'Fanfan', - 'Bacca', - 'Battaglini', - 'Bonfanti', - 'Bongers', - 'Butzin', - 'Caira', - 'Councilman', - 'Crounse', - 'Dadisman', - 'Donais', - 'Estabrooks', - 'Fornoff', - 'Froh', - 'Gaige', - 'Garofolo', - 'Grivas', - 'Jacuinde', - 'Kalmus', - 'Kientz', - 'Kostenko', - 'Kras', - 'Lagoy', - 'Larzelere', - 'Lizer', - 'Maric', - 'Mayette', - 'Mcfeeters', - 'Meadowcroft', - 'Newgent', - 'Parpart', - 'Pauwels', - 'Perriello', - 'Persichetti', - 'Proietti', - 'Siefring', - 'Simones', - 'Taliercio', - 'Thilges', - 'Thumann', - 'Thun', - 'Tuomi', - 'Uhde', - 'Umscheid', - 'Uran', - 'Velador', - 'Veltkamp', - 'Waddoups', - 'Yeley', - 'Bihn', - 'Bladow', - 'Boeh', - 'Chadderdon', - 'Ensing', - 'Fasbender', - 'Folkert', - 'Goellner', - 'Heitmeyer', - 'Iovine', - 'Klinke', - 'Nessel', - 'Perleberg', - 'Rajagopal', - 'Sackmann', - 'Sapio', - 'Schickling', - 'Schliep', - 'Siminski', - 'Sirrine', - 'Sporn', - 'Stockburger', - 'Tangonan', - 'Tarkowski', - 'Tartaglione', - 'Traum', - 'Vanoverbeke', - 'Weirauch', - 'Wellendorf', - 'Wonnacott', - 'Camplin', - 'Leth', - 'Meltz', - 'Cavero', - 'Florido', - 'Tremont', - 'Riviello', - 'Piotter', - 'Munce', - 'Trescott', - 'Eben', - 'Vaillant', - 'Furches', - 'Bazen', - 'Esse', - 'Losier', - 'Zahir', - 'Lazier', - 'Lightell', - 'Christal', - 'Behe', - 'Blayney', - 'Buchalter', - 'Demarsh', - 'Dhondt', - 'Diefendorf', - 'Dillavou', - 'Dombkowski', - 'Duchow', - 'Fettes', - 'Gallaga', - 'Gallet', - 'Haaf', - 'Hartinger', - 'Jech', - 'Klas', - 'Kostal', - 'Kubler', - 'Leisey', - 'Leisinger', - 'Marinas', - 'Mcpeck', - 'Miccio', - 'Mikkola', - 'Morath', - 'Olthoff', - 'Pacific', - 'Penado', - 'Petronio', - 'Pirani', - 'Pitones', - 'Pociask', - 'Ratay', - 'Riesberg', - 'Ruberto', - 'Sabet', - 'Sabic', - 'Simonich', - 'Skains', - 'Skarzynski', - 'Spreeman', - 'Steig', - 'Struckhoff', - 'Trolinger', - 'Uliano', - 'Vaquerano', - 'Zukas', - 'Zwahlen', - 'Amborn', - 'Amspacher', - 'Azzaro', - 'Bartoletti', - 'Berkstresser', - 'Buboltz', - 'Ekstein', - 'Fohl', - 'Heinzel', - 'Hellmer', - 'Kapfer', - 'Kurka', - 'Mccreless', - 'Miyahira', - 'Nebergall', - 'Orlosky', - 'Pajor', - 'Quartararo', - 'Rahilly', - 'Rzasa', - 'Sabas', - 'Slutz', - 'Speros', - 'Stumpp', - 'Tamburo', - 'Tesler', - 'Tonkovich', - 'Urbieta', - 'Vallandingham', - 'Youngdahl', - 'Juliana', - 'Rienstra', - 'Prideaux', - 'Coval', - 'Hausen', - 'Seith', - 'Ny', - 'Bian', - 'Gressman', - 'Yanick', - 'Mannina', - 'Nater', - 'Gurry', - 'Vaile', - 'Sortor', - 'Woodington', - 'Apollo', - 'Mozley', - 'Patience', - 'Hearron', - 'Milloy', - 'Huntsberry', - 'Polidore', - 'Ridges', - 'Bonton', - 'Mercadel', - 'Alikhan', - 'Antis', - 'Bartosiewicz', - 'Brems', - 'Clopper', - 'Colato', - 'Collver', - 'Daino', - 'Degrande', - 'Dellis', - 'Depner', - 'Disantis', - 'Dolecki', - 'Dollens', - 'Eliasen', - 'Fasig', - 'Favinger', - 'Furuta', - 'Gharibian', - 'Gombar', - 'Gordo', - 'Gornik', - 'Gulas', - 'Khoshaba', - 'Laurita', - 'Liby', - 'Linhardt', - 'Lookabaugh', - 'Lorincz', - 'Mautner', - 'Mcquigg', - 'Meine', - 'Melaragno', - 'Meroney', - 'Mikesh', - 'Miu', - 'Monasterio', - 'Navarete', - 'Orendain', - 'Puricelli', - 'Riede', - 'Rubis', - 'Sandness', - 'Schellhase', - 'Stehlin', - 'Sunder', - 'Teaney', - 'Terman', - 'Tith', - 'Totino', - 'Tudisco', - 'Urwin', - 'Vandrunen', - 'Vasicek', - 'Youtz', - 'Berwald', - 'Bilow', - 'Bubolz', - 'Cieslewicz', - 'Denbleyker', - 'Ensinger', - 'Gantenbein', - 'Gurnsey', - 'Herceg', - 'Kless', - 'Kollias', - 'Leppek', - 'Naeve', - 'Oncale', - 'Pastran', - 'Pinyan', - 'Porrata', - 'Pustejovsky', - 'Renko', - 'Scioli', - 'Sinkhorn', - 'Sporrer', - 'Tomkiewicz', - 'Weisbeck', - 'Gautam', - 'Gleed', - 'Shave', - 'Crotzer', - 'Demarr', - 'Reckard', - 'Coyt', - 'Norberto', - 'Ury', - 'Crispen', - 'Parcells', - 'Meiklejohn', - 'Risden', - 'Bracker', - 'Askari', - 'Hyneman', - 'Auberry', - 'Bruney', - 'Weakly', - 'Ysaguirre', - 'Calender', - 'Benison', - 'Nazaire', - 'Pondexter', - 'Fryson', - 'Aguino', - 'Antonino', - 'Babilonia', - 'Banfill', - 'Beger', - 'Berardino', - 'Bizub', - 'Contractor', - 'Convey', - 'Cossairt', - 'Cruzen', - 'Dible', - 'Dorning', - 'Ellena', - 'Fafard', - 'Fano', - 'Favaro', - 'Feeler', - 'Foulger', - 'Gulbrandson', - 'Heckaman', - 'Heimerman', - 'Herms', - 'Hotchkin', - 'Jinright', - 'Kisler', - 'Kontz', - 'Kryder', - 'Lopezperez', - 'Lumm', - 'Mcelravy', - 'Meditz', - 'Melucci', - 'Meras', - 'Miyahara', - 'Musella', - 'Nelis', - 'Nhem', - 'Olivan', - 'Popson', - 'Presgraves', - 'Reindel', - 'Riege', - 'Rivenburgh', - 'Sahl', - 'Selberg', - 'Tashiro', - 'Todorov', - 'Toutant', - 'Turski', - 'Vankuren', - 'Westrup', - 'Beeney', - 'Bickhart', - 'Borkenhagen', - 'Bukoski', - 'Citrin', - 'Civello', - 'Forstrom', - 'Froning', - 'Geiler', - 'Hargadon', - 'Hemric', - 'Jeffus', - 'Klingele', - 'Kooiker', - 'Lizalde', - 'Nardiello', - 'Pestka', - 'Pignato', - 'Pudwill', - 'Rabelo', - 'Remund', - 'Skluzacek', - 'Stegenga', - 'Steidle', - 'Stenz', - 'Terlecki', - 'Vanselow', - 'Waskey', - 'Azhar', - 'Wroe', - 'Tool', - 'Leibert', - 'Vary', - 'Scovell', - 'Derick', - 'Arrey', - 'Cavness', - 'Garley', - 'Sholtz', - 'Legard', - 'Heyliger', - 'Thorns', - 'Sowells', - 'Alemu', - 'Aragones', - 'Ayllon', - 'Baab', - 'Blankenbeckler', - 'Brengle', - 'Burick', - 'Deuser', - 'Disabato', - 'Doddridge', - 'Dolinski', - 'Economy', - 'Ems', - 'Hagenow', - 'Iwen', - 'Kiesler', - 'Lehrmann', - 'Loisel', - 'Mallicoat', - 'Mansouri', - 'Marse', - 'Mccartt', - 'Menninger', - 'Montee', - 'Nappa', - 'Ohanesian', - 'Podgurski', - 'Prosch', - 'Puder', - 'Ritthaler', - 'Rodelo', - 'Shipper', - 'Shorkey', - 'Sirna', - 'Smedberg', - 'Smink', - 'Strahle', - 'Troeger', - 'Twaddell', - 'Vandyk', - 'Wandrey', - 'Yaworski', - 'Zagami', - 'Duecker', - 'Finlinson', - 'Frysinger', - 'Grush', - 'Knackstedt', - 'Morozov', - 'Murgia', - 'Naffziger', - 'Ontko', - 'Piltz', - 'Roskelley', - 'Sonderman', - 'Garrand', - 'Kopack', - 'Theys', - 'Sanseverino', - 'Budai', - 'Selwyn', - 'Assante', - 'Nary', - 'Fildes', - 'Tano', - 'Hogen', - 'Gennett', - 'Melka', - 'Thorner', - 'Grandjean', - 'Dury', - 'Gerrald', - 'Quilling', - 'Mccallon', - 'Preister', - 'Kydd', - 'Cranshaw', - 'Folson', - 'Roker', - 'Dockett', - 'Stfort', - 'Haymer', - 'Njie', - 'Adamik', - 'Aredondo', - 'Bathrick', - 'Beldin', - 'Blackwater', - 'Branscom', - 'Cappucci', - 'Cartelli', - 'Carullo', - 'Cunneen', - 'Davee', - 'Deboy', - 'Defrates', - 'Esham', - 'Furio', - 'Garverick', - 'Gimlin', - 'Gosline', - 'Gromer', - 'Halbig', - 'Hasbrook', - 'Holgerson', - 'Hupfer', - 'Jochem', - 'Kihn', - 'Klotzbach', - 'Lantagne', - 'Leichter', - 'Lerette', - 'Lupu', - 'Machorro', - 'Mieles', - 'Mikulec', - 'Mirante', - 'Nasrallah', - 'Piccini', - 'Pinkhasov', - 'Poplaski', - 'Pottenger', - 'Rahrig', - 'Ranganathan', - 'Ravan', - 'Righi', - 'Rogacki', - 'Sadlon', - 'Salafia', - 'Schlitz', - 'Slayback', - 'Stetzel', - 'Tamargo', - 'Tenore', - 'Verkuilen', - 'Vuncannon', - 'Waggle', - 'Bacorn', - 'Boerema', - 'Cimorelli', - 'Ciresi', - 'Dethlefs', - 'Dimarzo', - 'Ficco', - 'Floresca', - 'Gnau', - 'Hefel', - 'Holbein', - 'Klepacki', - 'Konigsberg', - 'Lienau', - 'Malsam', - 'Meidl', - 'Nawabi', - 'Netzley', - 'Renbarger', - 'Rumbold', - 'Sarafian', - 'Sonnenfeld', - 'Tindol', - 'Trettin', - 'Tuckerman', - 'Vanderweele', - 'Weppler', - 'Westbay', - 'Zaveri', - 'Boran', - 'Deighan', - 'Rothery', - 'Yom', - 'Gatley', - 'Caldron', - 'Lucado', - 'Dromgoole', - 'Novell', - 'Sherriff', - 'Gerrick', - 'Balgobin', - 'Danger', - 'Sookram', - 'Daron', - 'Knibbs', - 'Faggart', - 'Beidleman', - 'Russey', - 'Lagrand', - 'Bluett', - 'Glaspy', - 'Baldon', - 'Trueheart', - 'Cradle', - 'Asfaw', - 'Ballinas', - 'Bogdon', - 'Brizzi', - 'Carrio', - 'Cherny', - 'Crogan', - 'Depierro', - 'Dhami', - 'Dresden', - 'Finnicum', - 'Geltz', - 'Granade', - 'Granieri', - 'Guia', - 'Hashagen', - 'Hollick', - 'Jicha', - 'Jollie', - 'Kathan', - 'Malara', - 'Manabat', - 'Mehall', - 'Midcap', - 'Mitre', - 'Newburg', - 'Parveen', - 'Pianka', - 'Plouff', - 'Posillico', - 'Ransier', - 'Reano', - 'Roskam', - 'Rufer', - 'Schnetzer', - 'Scorsone', - 'Sitterly', - 'Skilton', - 'Sohail', - 'Starin', - 'Stavish', - 'Tufaro', - 'Vano', - 'Vinsant', - 'Vlahakis', - 'Vondrasek', - 'Waldroop', - 'Wamboldt', - 'Achatz', - 'Bomkamp', - 'Fetzner', - 'Gemmer', - 'Haroutunian', - 'Hurtig', - 'Juncaj', - 'Kleban', - 'Knier', - 'Kopischke', - 'Kugelman', - 'Lacoss', - 'Meulemans', - 'Neyens', - 'Niccoli', - 'Oberhaus', - 'Penkala', - 'Podoll', - 'Roupp', - 'Scozzari', - 'Siverling', - 'Uhls', - 'Werber', - 'Grealish', - 'Montieth', - 'Haik', - 'Kuri', - 'Kanaan', - 'Prenatt', - 'Dingledine', - 'Mccamy', - 'Balin', - 'Droney', - 'Clyatt', - 'Ramone', - 'Anglen', - 'Mathus', - 'Bagent', - 'Lamarque', - 'Arscott', - 'Romes', - 'Speigner', - 'Latouche', - 'Tripplett', - 'Eversley', - 'Aquirre', - 'Bernales', - 'Bouthillier', - 'Cavendish', - 'Detienne', - 'Dewbre', - 'Dimuro', - 'Dosh', - 'Dunklee', - 'Duyck', - 'Emilio', - 'Ence', - 'Garofano', - 'Gellis', - 'Haertel', - 'Handyside', - 'Hornburg', - 'Jenniges', - 'Kallhoff', - 'Klontz', - 'Langsdorf', - 'Leabo', - 'Lorette', - 'Maracle', - 'Merta', - 'Muoio', - 'Nierenberg', - 'Oborn', - 'Osorto', - 'Ruscitti', - 'Santaella', - 'Spinnato', - 'Stentz', - 'Stocke', - 'Sundt', - 'Thorup', - 'Tresch', - 'Urdaneta', - 'Uttech', - 'Vosler', - 'Wieand', - 'Zacharia', - 'Zeleznik', - 'Zoucha', - 'Zuch', - 'Abrell', - 'Atiyeh', - 'Aydt', - 'Cleeton', - 'Crisan', - 'Cwikla', - 'Denz', - 'Diesing', - 'Emmi', - 'Fringer', - 'Gibbard', - 'Graunke', - 'Gschwind', - 'Hafele', - 'Hoogland', - 'Howsare', - 'Kesecker', - 'Kilgallon', - 'Kleyman', - 'Kufahl', - 'Laut', - 'Malstrom', - 'Michetti', - 'Nosbisch', - 'Rasner', - 'Rosekrans', - 'Schnebly', - 'Staebell', - 'Theilen', - 'Tieszen', - 'Mellone', - 'Burcher', - 'Feister', - 'Hoage', - 'Irmen', - 'Derwin', - 'Dien', - 'Markins', - 'Egnew', - 'Dunlow', - 'Brickel', - 'Curt', - 'Smyly', - 'Whedbee', - 'Larman', - 'Boisselle', - 'Jaquess', - 'Bowns', - 'Nile', - 'Boyson', - 'Phillipps', - 'Weech', - 'Pillars', - 'Cauldwell', - 'Wynns', - 'Toca', - 'Scorza', - 'Ramsaran', - 'Arkwright', - 'Gurganious', - 'Jubert', - 'Beed', - 'Kellem', - 'Gervin', - 'Yarn', - 'Bookhart', - 'Sullen', - 'Moncrieffe', - 'Eze', - 'Agyeman', - 'Aldea', - 'Amodei', - 'Attig', - 'Bergthold', - 'Blaskowski', - 'Blitzer', - 'Bowring', - 'Brenning', - 'Chappuis', - 'Cordasco', - 'Cosens', - 'Denoble', - 'Dochterman', - 'Domek', - 'Embleton', - 'Georgiades', - 'Gintz', - 'Grooters', - 'Hoell', - 'Honse', - 'Jagiello', - 'Jaskulski', - 'Kaluzny', - 'Keske', - 'Khiev', - 'Koeneman', - 'Majestic', - 'Mandile', - 'Marandola', - 'Mcinroy', - 'Nienhaus', - 'Peckenpaugh', - 'Raquel', - 'Rossler', - 'Rusconi', - 'Schaffert', - 'Schipani', - 'Sittner', - 'Sweezey', - 'Swenor', - 'Tagliaferro', - 'Tubby', - 'Ulep', - 'Vallette', - 'Westergren', - 'Yaros', - 'Yasui', - 'Anway', - 'Bannick', - 'Biasi', - 'Breitling', - 'Catarino', - 'Dunaj', - 'Giovanelli', - 'Hemmerich', - 'Iott', - 'Knotek', - 'Kraeger', - 'Laskaris', - 'Lomboy', - 'Oleski', - 'Reibel', - 'Rightmyer', - 'Salmela', - 'Salow', - 'Siebels', - 'Spielvogel', - 'Streitmatter', - 'Ucci', - 'Windmiller', - 'Wojtkiewicz', - 'Zirkel', - 'Markie', - 'Nedeau', - 'Froehle', - 'Jesson', - 'Regala', - 'Boody', - 'Hayen', - 'Ose', - 'Loewy', - 'Radliff', - 'Davia', - 'Sky', - 'Halker', - 'Alu', - 'Ey', - 'Badawi', - 'Yeargain', - 'Jeanette', - 'Doublin', - 'Nolton', - 'Streety', - 'Blueford', - 'Abeles', - 'Aldava', - 'Alsteen', - 'Altadonna', - 'Apa', - 'Behlke', - 'Bellisario', - 'Bienstock', - 'Brenan', - 'Capley', - 'Castoro', - 'Demir', - 'Evinger', - 'Gartside', - 'Gellatly', - 'Goldinger', - 'Grabel', - 'Henkin', - 'Herrle', - 'Honegger', - 'Kunin', - 'Larmer', - 'Lizano', - 'Lorino', - 'Malcomson', - 'Matesic', - 'Mathiasen', - 'Mccolm', - 'Meenach', - 'Mullady', - 'Neiderer', - 'Ogier', - 'Omura', - 'Plog', - 'Pomplun', - 'Procida', - 'Raisbeck', - 'Rastetter', - 'Reither', - 'Rettberg', - 'Roblee', - 'Rossitto', - 'Scahill', - 'Schmoker', - 'Segreto', - 'Shelstad', - 'Shwartz', - 'Sondgeroth', - 'Supnet', - 'Swartzbaugh', - 'Tkachenko', - 'Urbani', - 'Vanslooten', - 'Varricchio', - 'Villarino', - 'Whiston', - 'Wyffels', - 'Yehle', - 'Basinski', - 'Belvedere', - 'Bernabei', - 'Bolotin', - 'Bresett', - 'Dabkowski', - 'Dalsanto', - 'Gotwalt', - 'Hellberg', - 'Hunke', - 'Kroenke', - 'Leppla', - 'Luginbuhl', - 'Mimnaugh', - 'Mullenbach', - 'Nearhood', - 'Raser', - 'Resendis', - 'Seydel', - 'Sozio', - 'Stillions', - 'Stormont', - 'Strimple', - 'Toruno', - 'Trouten', - 'Tryba', - 'Vandalen', - 'Wilhelmy', - 'Orland', - 'Loui', - 'Morcos', - 'Radell', - 'Artus', - 'Truxillo', - 'Copelan', - 'Bress', - 'Unthank', - 'Sudlow', - 'Branden', - 'Rowzee', - 'Montreuil', - 'Sollers', - 'Umar', - 'Coulibaly', - 'Allegretto', - 'Andreen', - 'Bielicki', - 'Bustard', - 'Cardosi', - 'Carkhuff', - 'Cetina', - 'Clouthier', - 'Dolata', - 'Fiola', - 'Fjeld', - 'Gawthrop', - 'Glastetter', - 'Hamlyn', - 'Hanten', - 'Huerter', - 'Kreiss', - 'Lestrange', - 'Litzau', - 'Luberto', - 'Menconi', - 'Milosevic', - 'Munera', - 'Nachtigal', - 'Nethers', - 'Nicolaou', - 'Olund', - 'Paddack', - 'Pfiester', - 'Pilley', - 'Polendo', - 'Porcayo', - 'Preast', - 'Runquist', - 'Saccente', - 'Santoli', - 'Saragoza', - 'Selway', - 'Smestad', - 'Stebner', - 'Toben', - 'Trapnell', - 'Urschel', - 'Verno', - 'Vidovich', - 'Walterscheid', - 'Yoh', - 'Zmijewski', - 'Allwein', - 'Bessire', - 'Broering', - 'Budzik', - 'Denherder', - 'Goerner', - 'Goldbaum', - 'Grussing', - 'Huaracha', - 'Ippoliti', - 'Kanak', - 'Kaucher', - 'Kious', - 'Kirkner', - 'Kratzke', - 'Kubisiak', - 'Kueny', - 'Mazzilli', - 'Mazzo', - 'Mcclenathan', - 'Mehlberg', - 'Miotke', - 'Nihiser', - 'Olheiser', - 'Oravetz', - 'Radwanski', - 'Shinsato', - 'Vandekamp', - 'Zagata', - 'Abert', - 'Llera', - 'Thommen', - 'Wirkkala', - 'Brasuell', - 'Shawler', - 'Mourey', - 'Gavia', - 'Morgano', - 'Newill', - 'Rathel', - 'Wist', - 'Braner', - 'Soman', - 'Koskey', - 'Searson', - 'Brocksmith', - 'Peale', - 'Couzens', - 'Shall', - 'Anis', - 'Stanly', - 'Cauthorn', - 'Kinkle', - 'Laughinghouse', - 'Mellette', - 'Rox', - 'Demetrius', - 'Cullars', - 'Summons', - 'Banwart', - 'Bartl', - 'Bebb', - 'Bobier', - 'Bogdanoff', - 'Bollmann', - 'Borrowman', - 'Borseth', - 'Buttitta', - 'Canelo', - 'Cassedy', - 'Cata', - 'Crivelli', - 'Daane', - 'Dhingra', - 'Dipple', - 'Dovidio', - 'Duesler', - 'Eissler', - 'Ent', - 'Falotico', - 'Goodrick', - 'Goupil', - 'Huels', - 'Keithly', - 'Killilea', - 'Klausing', - 'Kludt', - 'Licitra', - 'Llerenas', - 'Merolla', - 'Oatley', - 'Osmanovic', - 'Poudrier', - 'Raben', - 'Realmuto', - 'Reczek', - 'Ricchio', - 'Rossner', - 'Rozak', - 'Sandora', - 'Schuenemann', - 'Seres', - 'Shoptaw', - 'Splitt', - 'Tonkinson', - 'Willardson', - 'Winterberg', - 'Zayac', - 'Bobzien', - 'Buhman', - 'Carotenuto', - 'Chynoweth', - 'Defenbaugh', - 'Dipiero', - 'Duve', - 'Goonan', - 'Gragert', - 'Hangartner', - 'Heemstra', - 'Hensch', - 'Hollatz', - 'Jakubowicz', - 'Kapaun', - 'Kiener', - 'Landesman', - 'Lenzini', - 'Longbottom', - 'Parde', - 'Pincock', - 'Schlicker', - 'Shankel', - 'Vidas', - 'Waisner', - 'Zilberman', - 'Allcock', - 'Durban', - 'Javid', - 'Shoda', - 'Edes', - 'Boxwell', - 'Dezern', - 'Rubley', - 'Angelica', - 'Jeannette', - 'Planer', - 'Pata', - 'Lothridge', - 'Lucks', - 'Bais', - 'Sandra', - 'Enwright', - 'Maxton', - 'Radway', - 'Hoof', - 'Morisset', - 'Danzey', - 'Ancar', - 'Mcwright', - 'Leggs', - 'Monestime', - 'Massaquoi', - 'Barkow', - 'Bastyr', - 'Bautz', - 'Behanna', - 'Bewick', - 'Bezdek', - 'Bielby', - 'Bretschneider', - 'Bugher', - 'Carchi', - 'Chapp', - 'Conser', - 'Crete', - 'Derflinger', - 'Elsbernd', - 'Freimark', - 'Gerwin', - 'Grunfeld', - 'Harpham', - 'Hoeschen', - 'Holmlund', - 'Horch', - 'Hulsebus', - 'Kassabian', - 'Konczal', - 'Korell', - 'Lacuesta', - 'Lantier', - 'Larowe', - 'Lietzke', - 'Lunny', - 'Masin', - 'Massicotte', - 'Michalsky', - 'Notarianni', - 'Pautsch', - 'Poppy', - 'Sukup', - 'Suleski', - 'Tafel', - 'Wanninger', - 'Zaffino', - 'Zody', - 'Arganbright', - 'Bohmer', - 'Cintora', - 'Connatser', - 'Dlugos', - 'Fariello', - 'Fedie', - 'Felicetti', - 'Garno', - 'Gottsch', - 'Gratzer', - 'Gubser', - 'Kappelman', - 'Kuechle', - 'Laningham', - 'Latsch', - 'Longie', - 'Luscher', - 'Lybeck', - 'Rhude', - 'Setterlund', - 'Sobh', - 'Sonneborn', - 'Villamizar', - 'Wolstenholme', - 'Zacek', - 'Leppanen', - 'Casdorph', - 'Pinsker', - 'Reutov', - 'Rede', - 'Sheck', - 'Bakley', - 'Radde', - 'Moher', - 'Khader', - 'Rossie', - 'Scriver', - 'Provine', - 'Debarge', - 'Darke', - 'Griswell', - 'Naji', - 'Frere', - 'Cheevers', - 'Schnyder', - 'Curb', - 'Luten', - 'Cashaw', - 'Agerton', - 'Barnier', - 'Bluestone', - 'Boward', - 'Boyar', - 'Briano', - 'Bryngelson', - 'Calef', - 'Caraher', - 'Castelluccio', - 'Conk', - 'Crewse', - 'Demarzo', - 'Deutschman', - 'Eckrote', - 'Edmister', - 'Ferg', - 'Ghan', - 'Giampaolo', - 'Goedecke', - 'Gonet', - 'Gradel', - 'Gregston', - 'Grzesiak', - 'Guallpa', - 'Hanline', - 'Hardyman', - 'Hogate', - 'Houg', - 'Justiss', - 'Kaps', - 'Klopf', - 'Kniskern', - 'Laneve', - 'Lenhoff', - 'Lojewski', - 'Melott', - 'Milillo', - 'Passage', - 'Pereyda', - 'Plack', - 'Poet', - 'Prospero', - 'Quadros', - 'Revelo', - 'Rogier', - 'Sanabia', - 'Tragesser', - 'Vanarsdall', - 'Vanausdal', - 'Verbrugge', - 'Wandler', - 'Zoss', - 'Balzarini', - 'Brotz', - 'Bulin', - 'Bumann', - 'Cancro', - 'Centner', - 'Deblasi', - 'Duesing', - 'Friedley', - 'Frieling', - 'Heinke', - 'Holzheimer', - 'Klinck', - 'Knouff', - 'Kuczek', - 'Leible', - 'Lerum', - 'Liddicoat', - 'Mikowski', - 'Nonaka', - 'Ohlman', - 'Picaso', - 'Plamann', - 'Porretta', - 'Prajapati', - 'Rancour', - 'Stepka', - 'Studzinski', - 'Vaysman', - 'Wallenstein', - 'Wunderlin', - 'Pattinson', - 'Siskind', - 'Sitzer', - 'Thuman', - 'Barella', - 'Brillon', - 'Arnholt', - 'Karge', - 'Dohman', - 'Morone', - 'Macie', - 'Aken', - 'Lye', - 'Student', - 'Westen', - 'Bonsell', - 'Komara', - 'Hafiz', - 'Stickland', - 'Morina', - 'Creekmur', - 'Hussien', - 'Walrond', - 'Louischarles', - 'Alkema', - 'Angert', - 'Arcidiacono', - 'Ashkar', - 'Bookbinder', - 'Bootz', - 'Cilia', - 'Devilla', - 'Difatta', - 'Enberg', - 'Enderby', - 'Forbess', - 'Frutiger', - 'Graefe', - 'Guenette', - 'Hauschildt', - 'Keirsey', - 'Kolka', - 'Kopelman', - 'Lewan', - 'Mcluckie', - 'Mia', - 'Moebius', - 'Oestreicher', - 'Oprea', - 'Ortolano', - 'Padovani', - 'Pensabene', - 'Phimmasone', - 'Pointon', - 'Punches', - 'Schertzer', - 'Seoane', - 'Skramstad', - 'Sorlie', - 'Syfert', - 'Tasca', - 'Townzen', - 'Wernli', - 'Wurzel', - 'Yazdi', - 'Devendorf', - 'Featherly', - 'Frush', - 'Heringer', - 'Iwai', - 'Kallenberger', - 'Kobashigawa', - 'Langbehn', - 'Livecchi', - 'Middlesworth', - 'Niess', - 'Osterlund', - 'Ruz', - 'Seiwert', - 'Vanwieren', - 'Wernet', - 'Grabbe', - 'Gaugh', - 'Mcclarren', - 'Raudales', - 'Urry', - 'Clere', - 'Lacer', - 'Mathia', - 'Mccrumb', - 'Cotrell', - 'Mannor', - 'Medine', - 'Tittsworth', - 'Hughston', - 'Buick', - 'Limes', - 'Hams', - 'Thagard', - 'Leavelle', -]; diff --git a/integration-tests/tests/seeder/pg.test.ts b/integration-tests/tests/seeder/pg.test.ts index 8d074e747..33cd06f7e 100644 --- a/integration-tests/tests/seeder/pg.test.ts +++ b/integration-tests/tests/seeder/pg.test.ts @@ -2,10 +2,8 @@ import { PGlite } from '@electric-sql/pglite'; import { sql } from 'drizzle-orm'; import type { PgliteDatabase } from 'drizzle-orm/pglite'; import { drizzle } from 'drizzle-orm/pglite'; -import { reset, seed } from 'drizzle-seed'; +import { firstNames, lastNames, reset, seed } from 'drizzle-seed'; import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; -import firstNames from './firstNames.ts'; -import lastNames from './lastNames.ts'; import * as schema from './pgSchema.ts'; let client: PGlite; From 8b3dce38f039ef6e4a6e5c9e98dec617c9d035b9 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 21 Nov 2024 14:54:20 +0200 Subject: [PATCH 376/492] Add credits for all datasets --- drizzle-seed/src/datasets/adjectives.ts | 3 +++ drizzle-seed/src/datasets/cityNames.ts | 4 ++++ drizzle-seed/src/datasets/countries.ts | 4 ++++ drizzle-seed/src/datasets/firstNames.ts | 3 +++ drizzle-seed/src/datasets/jobsTitles.ts | 3 +++ drizzle-seed/src/datasets/lastNames.ts | 3 +++ drizzle-seed/src/datasets/loremIpsumSentences.ts | 3 +++ drizzle-seed/src/datasets/phonesInfo.ts | 6 +++++- drizzle-seed/src/datasets/streetSuffix.ts | 3 +++ 9 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drizzle-seed/src/datasets/adjectives.ts b/drizzle-seed/src/datasets/adjectives.ts index 256ed1cc1..c2b152af0 100644 --- a/drizzle-seed/src/datasets/adjectives.ts +++ b/drizzle-seed/src/datasets/adjectives.ts @@ -1,3 +1,6 @@ +/** + * The original source for the Adjectives data was taken from https://www.kaggle.com/datasets/jordansiem/adjectives-list + */ export default [ 'abandoned', 'abdominal', diff --git a/drizzle-seed/src/datasets/cityNames.ts b/drizzle-seed/src/datasets/cityNames.ts index e358a0b31..780b55213 100644 --- a/drizzle-seed/src/datasets/cityNames.ts +++ b/drizzle-seed/src/datasets/cityNames.ts @@ -1,3 +1,7 @@ +/** + * The original source for cities names data was taken from https://www.kaggle.com/datasets/juanmah/world-cities + * We've excluded a few countries and their cities from this list because we don't think they should ever appear in any list + */ export default [ 'Humpata', 'Qunghirot', diff --git a/drizzle-seed/src/datasets/countries.ts b/drizzle-seed/src/datasets/countries.ts index 11bc64e91..4808fc5e5 100644 --- a/drizzle-seed/src/datasets/countries.ts +++ b/drizzle-seed/src/datasets/countries.ts @@ -1,3 +1,7 @@ +/** + * The original source for countries data was taken from https://www.kaggle.com/datasets/manusmitajha/countrydatacsv + * We've excluded a few countries and their cities from this list because we don't think they should ever appear in any list + */ export default [ 'Afghanistan', 'Albania', diff --git a/drizzle-seed/src/datasets/firstNames.ts b/drizzle-seed/src/datasets/firstNames.ts index ac6e1b74a..7ca0ff928 100644 --- a/drizzle-seed/src/datasets/firstNames.ts +++ b/drizzle-seed/src/datasets/firstNames.ts @@ -1,3 +1,6 @@ +/** + * The original source for first names data was taken from https://www.kaggle.com/datasets/kaggle/us-baby-names?select=StateNames.csv + */ export default [ 'Robert', 'John', diff --git a/drizzle-seed/src/datasets/jobsTitles.ts b/drizzle-seed/src/datasets/jobsTitles.ts index 74ef3146a..3a38e3244 100644 --- a/drizzle-seed/src/datasets/jobsTitles.ts +++ b/drizzle-seed/src/datasets/jobsTitles.ts @@ -1,3 +1,6 @@ +/** + * The original source for the job titles data was taken from https://www.kaggle.com/datasets/ravindrasinghrana/job-description-dataset + */ export default [ 'Digital marketing specialist', 'Web developer', diff --git a/drizzle-seed/src/datasets/lastNames.ts b/drizzle-seed/src/datasets/lastNames.ts index f69f2c629..117c5fe28 100644 --- a/drizzle-seed/src/datasets/lastNames.ts +++ b/drizzle-seed/src/datasets/lastNames.ts @@ -1,3 +1,6 @@ +/** + * The original source for last names data was taken from https://www.kaggle.com/datasets/fivethirtyeight/fivethirtyeight-most-common-name-dataset?resource=download&select=surnames.csv + */ export default [ 'Smith', 'Johnson', diff --git a/drizzle-seed/src/datasets/loremIpsumSentences.ts b/drizzle-seed/src/datasets/loremIpsumSentences.ts index aabd5f771..f03277d86 100644 --- a/drizzle-seed/src/datasets/loremIpsumSentences.ts +++ b/drizzle-seed/src/datasets/loremIpsumSentences.ts @@ -1,3 +1,6 @@ +/** + * Data was generated, using https://www.lipsum.com/ + */ export default [ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 'Nam porta quis ex a blandit.', diff --git a/drizzle-seed/src/datasets/phonesInfo.ts b/drizzle-seed/src/datasets/phonesInfo.ts index d3ed9663f..3412857ed 100644 --- a/drizzle-seed/src/datasets/phonesInfo.ts +++ b/drizzle-seed/src/datasets/phonesInfo.ts @@ -1,4 +1,8 @@ -// ["country prefix, operator prefix, number length including operator prefix and excluding country prefix", ] +/** + * The original source for the phones info data was taken from https://www.kaggle.com/datasets/leighplt/country-code?select=mobile_telephone_prefixes_by_country.csv + * + * Data format is: ["country prefix, operator prefix, number length including operator prefix and excluding country prefix"] + */ export default [ '93,70,9', '93,71,9', diff --git a/drizzle-seed/src/datasets/streetSuffix.ts b/drizzle-seed/src/datasets/streetSuffix.ts index e6e02d505..e9b20c392 100644 --- a/drizzle-seed/src/datasets/streetSuffix.ts +++ b/drizzle-seed/src/datasets/streetSuffix.ts @@ -1,3 +1,6 @@ +/** + * The original data was taken from the сopycat library: https://github.com/supabase-community/copycat/blob/main/src/locales/en/address/street_suffix.ts + */ export default [ 'Alley', 'Avenue', From 236368ef5ef624950a9ebfbee781fe2a35779153 Mon Sep 17 00:00:00 2001 From: Andrii Sherman Date: Thu, 21 Nov 2024 15:28:56 +0200 Subject: [PATCH 377/492] drizzle-seed (#3587) drizzle-seed package release --------- Co-authored-by: OleksiiKH0240 --- .github/workflows/release-feature-branch.yaml | 1 + .github/workflows/release-latest.yaml | 1 + .gitignore | 2 + drizzle-orm/package.json | 4 +- drizzle-orm/src/column-builder.ts | 7 +- drizzle-orm/src/column.ts | 1 + drizzle-orm/src/operations.ts | 10 +- drizzle-orm/src/pg-core/columns/common.ts | 2 - drizzle-orm/src/pg-core/columns/int.common.ts | 15 +- drizzle-orm/src/pg-core/dialect.ts | 12 +- .../src/pg-core/query-builders/insert.ts | 44 +- drizzle-orm/src/table.ts | 7 +- drizzle-orm/type-tests/mysql/tables.ts | 16 + drizzle-orm/type-tests/pg/array.ts | 1 + drizzle-orm/type-tests/pg/insert.ts | 22 +- drizzle-orm/type-tests/pg/tables.ts | 57 +- drizzle-orm/type-tests/sqlite/tables.ts | 6 + drizzle-seed/README.md | 1143 + drizzle-seed/package.json | 103 + drizzle-seed/rollup.config.ts | 32 + drizzle-seed/scripts/build.ts | 15 + drizzle-seed/src/datasets/adjectives.ts | 4846 ++ drizzle-seed/src/datasets/cityNames.ts | 42859 +++++++++++++ .../src/datasets/companyNameSuffixes.ts | 27 + drizzle-seed/src/datasets/countries.ts | 171 + drizzle-seed/src/datasets/emailDomains.ts | 24 + drizzle-seed/src/datasets/firstNames.ts | 30279 ++++++++++ drizzle-seed/src/datasets/jobsTitles.ts | 152 + drizzle-seed/src/datasets/lastNames.ts | 50003 ++++++++++++++++ .../src/datasets/loremIpsumSentences.ts | 1639 + drizzle-seed/src/datasets/phonesInfo.ts | 851 + drizzle-seed/src/datasets/states.ts | 52 + drizzle-seed/src/datasets/streetSuffix.ts | 200 + drizzle-seed/src/index.ts | 873 + .../src/services/GeneratorsWrappers.ts | 3405 ++ drizzle-seed/src/services/SeedService.ts | 1160 + drizzle-seed/src/services/utils.ts | 83 + .../tests/benchmarks/generatorsBenchmark.ts | 131 + .../mysql/allDataTypesTest/drizzle.config.ts | 7 + .../mysql/allDataTypesTest/mysqlSchema.ts | 56 + .../mysql_all_data_types.test.ts | 121 + .../src/tests/mysql/drizzle.config.ts | 7 + .../mysql/generatorsTest/drizzle.config.ts | 7 + .../mysql/generatorsTest/generators.test.ts | 128 + .../tests/mysql/generatorsTest/mysqlSchema.ts | 9 + drizzle-seed/src/tests/mysql/mysql.test.ts | 381 + drizzle-seed/src/tests/mysql/mysqlSchema.ts | 102 + .../src/tests/northwind/mysqlSchema.ts | 102 + drizzle-seed/src/tests/northwind/mysqlTest.ts | 176 + drizzle-seed/src/tests/northwind/pgSchema.ts | 104 + drizzle-seed/src/tests/northwind/pgTest.ts | 175 + .../src/tests/northwind/sqliteSchema.ts | 107 + .../src/tests/northwind/sqliteTest.ts | 162 + .../pg/allDataTypesTest/drizzle.config.ts | 7 + .../src/tests/pg/allDataTypesTest/pgSchema.ts | 62 + .../pg_all_data_types.test.ts | 78 + drizzle-seed/src/tests/pg/drizzle.config.ts | 7 + .../tests/pg/generatorsTest/drizzle.config.ts | 7 + .../pg/generatorsTest/generators.test.ts | 1372 + .../src/tests/pg/generatorsTest/pgSchema.ts | 205 + drizzle-seed/src/tests/pg/pg.test.ts | 363 + drizzle-seed/src/tests/pg/pgSchema.ts | 136 + .../sqlite/allDataTypesTest/sqliteSchema.ts | 15 + .../sqlite_all_data_types.test.ts | 53 + drizzle-seed/src/tests/sqlite/sqlite.test.ts | 290 + drizzle-seed/src/tests/sqlite/sqliteSchema.ts | 107 + drizzle-seed/src/tests/vitest.config.ts | 25 + drizzle-seed/src/types/drizzleStudio.ts | 65 + drizzle-seed/src/types/seedService.ts | 45 + drizzle-seed/src/types/tables.ts | 36 + drizzle-seed/tsconfig.build.json | 7 + drizzle-seed/tsconfig.json | 48 + integration-tests/package.json | 3 +- integration-tests/tests/pg/pg-common.ts | 56 +- integration-tests/tests/seeder/mysql.test.ts | 490 + integration-tests/tests/seeder/mysqlSchema.ts | 167 + integration-tests/tests/seeder/pg.test.ts | 1775 + integration-tests/tests/seeder/pgSchema.ts | 357 + integration-tests/tests/seeder/sqlite.test.ts | 322 + .../tests/seeder/sqliteSchema.ts | 122 + integration-tests/vitest.config.ts | 1 + pnpm-lock.yaml | 12502 ++-- pnpm-workspace.yaml | 1 + turbo.json | 28 +- 84 files changed, 151058 insertions(+), 7594 deletions(-) create mode 100644 drizzle-seed/README.md create mode 100644 drizzle-seed/package.json create mode 100644 drizzle-seed/rollup.config.ts create mode 100644 drizzle-seed/scripts/build.ts create mode 100644 drizzle-seed/src/datasets/adjectives.ts create mode 100644 drizzle-seed/src/datasets/cityNames.ts create mode 100644 drizzle-seed/src/datasets/companyNameSuffixes.ts create mode 100644 drizzle-seed/src/datasets/countries.ts create mode 100644 drizzle-seed/src/datasets/emailDomains.ts create mode 100644 drizzle-seed/src/datasets/firstNames.ts create mode 100644 drizzle-seed/src/datasets/jobsTitles.ts create mode 100644 drizzle-seed/src/datasets/lastNames.ts create mode 100644 drizzle-seed/src/datasets/loremIpsumSentences.ts create mode 100644 drizzle-seed/src/datasets/phonesInfo.ts create mode 100644 drizzle-seed/src/datasets/states.ts create mode 100644 drizzle-seed/src/datasets/streetSuffix.ts create mode 100644 drizzle-seed/src/index.ts create mode 100644 drizzle-seed/src/services/GeneratorsWrappers.ts create mode 100644 drizzle-seed/src/services/SeedService.ts create mode 100644 drizzle-seed/src/services/utils.ts create mode 100644 drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts create mode 100644 drizzle-seed/src/tests/mysql/allDataTypesTest/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/mysql/allDataTypesTest/mysqlSchema.ts create mode 100644 drizzle-seed/src/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts create mode 100644 drizzle-seed/src/tests/mysql/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/mysql/generatorsTest/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/mysql/generatorsTest/generators.test.ts create mode 100644 drizzle-seed/src/tests/mysql/generatorsTest/mysqlSchema.ts create mode 100644 drizzle-seed/src/tests/mysql/mysql.test.ts create mode 100644 drizzle-seed/src/tests/mysql/mysqlSchema.ts create mode 100644 drizzle-seed/src/tests/northwind/mysqlSchema.ts create mode 100644 drizzle-seed/src/tests/northwind/mysqlTest.ts create mode 100644 drizzle-seed/src/tests/northwind/pgSchema.ts create mode 100644 drizzle-seed/src/tests/northwind/pgTest.ts create mode 100644 drizzle-seed/src/tests/northwind/sqliteSchema.ts create mode 100644 drizzle-seed/src/tests/northwind/sqliteTest.ts create mode 100644 drizzle-seed/src/tests/pg/allDataTypesTest/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts create mode 100644 drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts create mode 100644 drizzle-seed/src/tests/pg/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/pg/generatorsTest/drizzle.config.ts create mode 100644 drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts create mode 100644 drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts create mode 100644 drizzle-seed/src/tests/pg/pg.test.ts create mode 100644 drizzle-seed/src/tests/pg/pgSchema.ts create mode 100644 drizzle-seed/src/tests/sqlite/allDataTypesTest/sqliteSchema.ts create mode 100644 drizzle-seed/src/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts create mode 100644 drizzle-seed/src/tests/sqlite/sqlite.test.ts create mode 100644 drizzle-seed/src/tests/sqlite/sqliteSchema.ts create mode 100644 drizzle-seed/src/tests/vitest.config.ts create mode 100644 drizzle-seed/src/types/drizzleStudio.ts create mode 100644 drizzle-seed/src/types/seedService.ts create mode 100644 drizzle-seed/src/types/tables.ts create mode 100644 drizzle-seed/tsconfig.build.json create mode 100644 drizzle-seed/tsconfig.json create mode 100644 integration-tests/tests/seeder/mysql.test.ts create mode 100644 integration-tests/tests/seeder/mysqlSchema.ts create mode 100644 integration-tests/tests/seeder/pg.test.ts create mode 100644 integration-tests/tests/seeder/pgSchema.ts create mode 100644 integration-tests/tests/seeder/sqlite.test.ts create mode 100644 integration-tests/tests/seeder/sqliteSchema.ts diff --git a/.github/workflows/release-feature-branch.yaml b/.github/workflows/release-feature-branch.yaml index eb360da2d..3868db792 100644 --- a/.github/workflows/release-feature-branch.yaml +++ b/.github/workflows/release-feature-branch.yaml @@ -16,6 +16,7 @@ jobs: - drizzle-orm - drizzle-kit - drizzle-zod + - drizzle-seed - drizzle-typebox - drizzle-valibot - eslint-plugin-drizzle diff --git a/.github/workflows/release-latest.yaml b/.github/workflows/release-latest.yaml index f9292b2e0..fdab8f90e 100644 --- a/.github/workflows/release-latest.yaml +++ b/.github/workflows/release-latest.yaml @@ -12,6 +12,7 @@ jobs: - drizzle-orm - drizzle-kit - drizzle-zod + - drizzle-seed - drizzle-typebox - drizzle-valibot - eslint-plugin-drizzle diff --git a/.gitignore b/.gitignore index 45788cac5..570a706f8 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ dist-dts rollup.config-*.mjs *.log .DS_Store +drizzle-seed/src/test.ts +drizzle-seed/src/schemaTest.ts \ No newline at end of file diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index e43462fb0..809a28520 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.36.3", + "version": "0.36.4", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -203,4 +203,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} \ No newline at end of file +} diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index e53e5ca0d..f621343d9 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -63,6 +63,7 @@ export type MakeColumnConfig< enumValues: T['enumValues']; baseColumn: T extends { baseBuilder: infer U extends ColumnBuilderBase } ? BuildColumn : never; + identity: T extends { identity: 'always' } ? 'always' : T extends { identity: 'byDefault' } ? 'byDefault' : undefined; generated: T extends { generated: infer G } ? unknown extends G ? undefined : G extends undefined ? undefined : G @@ -84,6 +85,7 @@ export type ColumnBuilderTypeConfig< notNull: T extends { notNull: infer U } ? U : boolean; hasDefault: T extends { hasDefault: infer U } ? U : boolean; enumValues: T['enumValues']; + identity: T extends { identity: infer U } ? U : unknown; generated: T extends { generated: infer G } ? G extends undefined ? unknown : G : unknown; } & TTypeConfig @@ -154,17 +156,16 @@ export type HasGenerated = T & { _: { notNull: true; hasDefault: true; - generated: { as: any; type: TType }; + identity: TType; }; }; - export interface ColumnBuilderBase< T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, TTypeConfig extends object = object, diff --git a/drizzle-orm/src/column.ts b/drizzle-orm/src/column.ts index 79ba17f12..1396e3a61 100644 --- a/drizzle-orm/src/column.ts +++ b/drizzle-orm/src/column.ts @@ -38,6 +38,7 @@ export type ColumnTypeConfig, enumValues: T['enumValues']; baseColumn: T extends { baseColumn: infer U } ? U : unknown; generated: GeneratedColumnConfig | undefined; + identity: undefined | 'always' | 'byDefault'; } & TTypeConfig; export type ColumnRuntimeConfig = ColumnBuilderRuntimeConfig< diff --git a/drizzle-orm/src/operations.ts b/drizzle-orm/src/operations.ts index 573e05957..5f7704fd6 100644 --- a/drizzle-orm/src/operations.ts +++ b/drizzle-orm/src/operations.ts @@ -1,5 +1,4 @@ import type { AnyColumn, Column } from './column.ts'; -import type { GeneratedColumnConfig } from './index.ts'; import type { SQL } from './sql/sql.ts'; import type { Table } from './table.ts'; @@ -12,13 +11,16 @@ export type RequiredKeyOnly = T extends A export type OptionalKeyOnly< TKey extends string, T extends Column, + OverrideT extends boolean | undefined = false, > = TKey extends RequiredKeyOnly ? never : T extends { _: { - generated: infer G; + generated: undefined; }; - } ? G extends GeneratedColumnConfig ? G['type'] extends 'always' ? never : TKey - : TKey + } ? ( + T['_']['identity'] extends 'always' ? OverrideT extends true ? TKey : never + : TKey + ) : never; // TODO: SQL -> SQLWrapper diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index de2267cf3..d9384b344 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -4,7 +4,6 @@ import type { ColumnBuilderExtraConfig, ColumnBuilderRuntimeConfig, ColumnDataType, - GeneratedColumnConfig, HasGenerated, MakeColumnConfig, } from '~/column-builder.ts'; @@ -56,7 +55,6 @@ export abstract class PgColumnBuilder< data: T['data'][]; driverParam: T['driverParam'][] | string; enumValues: T['enumValues']; - generated: GeneratedColumnConfig; } & (T extends { notNull: true } ? { notNull: true } : {}) & (T extends { hasDefault: true } ? { hasDefault: true } : {}), diff --git a/drizzle-orm/src/pg-core/columns/int.common.ts b/drizzle-orm/src/pg-core/columns/int.common.ts index c473b8d04..32d5d12cd 100644 --- a/drizzle-orm/src/pg-core/columns/int.common.ts +++ b/drizzle-orm/src/pg-core/columns/int.common.ts @@ -1,9 +1,4 @@ -import type { - ColumnBuilderBaseConfig, - ColumnDataType, - GeneratedIdentityConfig, - IsIdentityByDefault, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnDataType, GeneratedIdentityConfig, IsIdentity } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; import type { PgSequenceOptions } from '../sequence.ts'; import { PgColumnBuilder } from './common.ts'; @@ -18,7 +13,7 @@ export abstract class PgIntColumnBaseBuilder< generatedAlwaysAsIdentity( sequence?: PgSequenceOptions & { name?: string }, - ): IsIdentityByDefault { + ): IsIdentity { if (sequence) { const { name, ...options } = sequence; this.config.generatedIdentity = { @@ -35,12 +30,12 @@ export abstract class PgIntColumnBaseBuilder< this.config.hasDefault = true; this.config.notNull = true; - return this as any; + return this as IsIdentity; } generatedByDefaultAsIdentity( sequence?: PgSequenceOptions & { name?: string }, - ): IsIdentityByDefault { + ): IsIdentity { if (sequence) { const { name, ...options } = sequence; this.config.generatedIdentity = { @@ -57,6 +52,6 @@ export abstract class PgIntColumnBaseBuilder< this.config.hasDefault = true; this.config.notNull = true; - return this as any; + return this as IsIdentity; } } diff --git a/drizzle-orm/src/pg-core/dialect.ts b/drizzle-orm/src/pg-core/dialect.ts index 318ea3098..52bd10ed5 100644 --- a/drizzle-orm/src/pg-core/dialect.ts +++ b/drizzle-orm/src/pg-core/dialect.ts @@ -491,7 +491,9 @@ export class PgDialect { return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; } - buildInsertQuery({ table, values: valuesOrSelect, onConflict, returning, withList, select }: PgInsertConfig): SQL { + buildInsertQuery( + { table, values: valuesOrSelect, onConflict, returning, withList, select, overridingSystemValue_ }: PgInsertConfig, + ): SQL { const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = []; const columns: Record = table[Table.Symbol.Columns]; @@ -553,7 +555,9 @@ export class PgDialect { const onConflictSql = onConflict ? sql` on conflict ${onConflict}` : undefined; - return sql`${withSql}insert into ${table} ${insertOrder} ${valuesSql}${onConflictSql}${returningSql}`; + const overridingSql = overridingSystemValue_ === true ? sql`overriding system value ` : undefined; + + return sql`${withSql}insert into ${table} ${insertOrder} ${overridingSql}${valuesSql}${onConflictSql}${returningSql}`; } buildRefreshMaterializedViewQuery( @@ -1163,7 +1167,9 @@ export class PgDialect { })); } else { const aliasedColumns = Object.fromEntries( - Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value, tableAlias)]), + Object.entries(tableConfig.columns).map(( + [key, value], + ) => [key, aliasedTableColumn(value, tableAlias)]), ); if (config.where) { diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index e44d3fbbb..b1a39fa05 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -8,7 +8,7 @@ import type { PgSession, PreparedQueryConfig, } from '~/pg-core/session.ts'; -import type { PgTable } from '~/pg-core/table.ts'; +import type { PgTable, TableConfig } from '~/pg-core/table.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; @@ -16,6 +16,7 @@ import type { RunnableQuery } from '~/runnable-query.ts'; import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; import { Param, SQL, sql } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; +import type { InferInsertModel } from '~/table.ts'; import { Columns, Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; import { haveSameKeys, mapUpdateSet, orderSelectedFields } from '~/utils.ts'; @@ -31,11 +32,15 @@ export interface PgInsertConfig { onConflict?: SQL; returning?: SelectedFieldsOrdered; select?: boolean; + overridingSystemValue_?: boolean; } -export type PgInsertValue = +export type PgInsertValue, OverrideT extends boolean = false> = & { - [Key in keyof TTable['$inferInsert']]: TTable['$inferInsert'][Key] | SQL | Placeholder; + [Key in keyof InferInsertModel]: + | InferInsertModel[Key] + | SQL + | Placeholder; } & {}; @@ -43,7 +48,11 @@ export type PgInsertSelectQueryBuilder = TypedQueryBuild { [K in keyof TTable['$inferInsert']]: AnyPgColumn | SQL | SQL.Aliased | TTable['$inferInsert'][K] } >; -export class PgInsertBuilder { +export class PgInsertBuilder< + TTable extends PgTable, + TQueryResult extends PgQueryResultHKT, + OverrideT extends boolean = false, +> { static readonly [entityKind]: string = 'PgInsertBuilder'; constructor( @@ -51,11 +60,19 @@ export class PgInsertBuilder): PgInsertBase; - values(values: PgInsertValue[]): PgInsertBase; - values(values: PgInsertValue | PgInsertValue[]): PgInsertBase { + overridingSystemValue(): Omit, 'overridingSystemValue'> { + this.overridingSystemValue_ = true; + return this as any; + } + + values(value: PgInsertValue): PgInsertBase; + values(values: PgInsertValue[]): PgInsertBase; + values( + values: PgInsertValue | PgInsertValue[], + ): PgInsertBase { values = Array.isArray(values) ? values : [values]; if (values.length === 0) { throw new Error('values() must be called with at least one value'); @@ -70,7 +87,15 @@ export class PgInsertBuilder PgInsertSelectQueryBuilder): PgInsertBase; @@ -208,9 +233,10 @@ export class PgInsertBase< private dialect: PgDialect, withList?: Subquery[], select?: boolean, + overridingSystemValue_?: boolean, ) { super(); - this.config = { table, values: values as any, withList, select }; + this.config = { table, values: values as any, withList, select, overridingSystemValue_ }; } /** diff --git a/drizzle-orm/src/table.ts b/drizzle-orm/src/table.ts index 6bacfc207..c843fd519 100644 --- a/drizzle-orm/src/table.ts +++ b/drizzle-orm/src/table.ts @@ -156,7 +156,7 @@ export type MapColumnName, TInferMode extends 'select' | 'insert' = 'select', - TConfig extends { dbColumnNames: boolean } = { dbColumnNames: false }, + TConfig extends { dbColumnNames: boolean; override?: boolean } = { dbColumnNames: false; override: false }, > = Simplify< TInferMode extends 'insert' ? & { @@ -171,7 +171,8 @@ export type InferModelFromColumns< [ Key in keyof TColumns & string as OptionalKeyOnly< MapColumnName, - TColumns[Key] + TColumns[Key], + TConfig['override'] > ]?: GetColumnData; } @@ -201,5 +202,5 @@ export type InferSelectModel< export type InferInsertModel< TTable extends Table, - TConfig extends { dbColumnNames: boolean } = { dbColumnNames: false }, + TConfig extends { dbColumnNames: boolean; override?: boolean } = { dbColumnNames: false; override: false }, > = InferModelFromColumns; diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index adc8e8eb8..473976d1a 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -104,6 +104,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: true; hasRuntimeDefault: false; }, object>; @@ -120,6 +121,7 @@ Expect< enumValues: [string, ...string[]]; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; }, object>; @@ -136,6 +138,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; }, object>; @@ -214,6 +217,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: true; hasRuntimeDefault: false; @@ -230,6 +234,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: true; hasRuntimeDefault: false; @@ -270,6 +275,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: true; hasRuntimeDefault: false; @@ -286,6 +292,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: true; hasRuntimeDefault: false; @@ -324,6 +331,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -340,6 +348,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -378,6 +387,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -394,6 +404,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -425,6 +436,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -441,6 +453,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -472,6 +485,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -488,6 +502,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -522,6 +537,7 @@ Expect< baseColumn: never; dialect: 'mysql'; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; diff --git a/drizzle-orm/type-tests/pg/array.ts b/drizzle-orm/type-tests/pg/array.ts index 3961e92d0..586acb1c7 100644 --- a/drizzle-orm/type-tests/pg/array.ts +++ b/drizzle-orm/type-tests/pg/array.ts @@ -21,6 +21,7 @@ import { integer, pgTable } from '~/pg-core/index.ts'; enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; diff --git a/drizzle-orm/type-tests/pg/insert.ts b/drizzle-orm/type-tests/pg/insert.ts index 78d2c3197..a1722fa78 100644 --- a/drizzle-orm/type-tests/pg/insert.ts +++ b/drizzle-orm/type-tests/pg/insert.ts @@ -5,7 +5,7 @@ import { boolean, pgTable, QueryBuilder, serial, text } from '~/pg-core/index.ts import type { PgInsert } from '~/pg-core/query-builders/insert.ts'; import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; -import { users } from './tables.ts'; +import { identityColumnsTable, users } from './tables.ts'; const insert = await db .insert(users) @@ -277,3 +277,23 @@ Expect< // @ts-expect-error tables have different keys db.insert(users1).select(() => db.select().from(users2)); } + +{ + db.insert(identityColumnsTable).values([ + { byDefaultAsIdentity: 4, name: 'fdf' }, + ]); + + // @ts-expect-error + db.insert(identityColumnsTable).values([ + { alwaysAsIdentity: 2 }, + ]); + + db.insert(identityColumnsTable).overridingSystemValue().values([ + { alwaysAsIdentity: 2 }, + ]); + + // @ts-expect-error + db.insert(identityColumnsTable).values([ + { generatedCol: 2 }, + ]); +} diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index 0b139dc3a..2b07a9fcd 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -55,10 +55,35 @@ import { } from '~/pg-core/view.ts'; import { sql } from '~/sql/sql.ts'; import type { InferInsertModel, InferSelectModel } from '~/table.ts'; +import type { Simplify } from '~/utils.ts'; import { db } from './db.ts'; export const myEnum = pgEnum('my_enum', ['a', 'b', 'c']); +export const identityColumnsTable = pgTable('identity_columns_table', { + generatedCol: integer('generated_col').generatedAlwaysAs(1), + alwaysAsIdentity: integer('always_as_identity').generatedAlwaysAsIdentity(), + byDefaultAsIdentity: integer('by_default_as_identity').generatedByDefaultAsIdentity(), + name: text('name'), +}); + +Expect, typeof identityColumnsTable['$inferSelect']>>; +Expect, typeof identityColumnsTable['_']['inferSelect']>>; +Expect, typeof identityColumnsTable['$inferInsert']>>; +Expect, typeof identityColumnsTable['_']['inferInsert']>>; +Expect< + Equal< + InferInsertModel, + Simplify + > +>; +Expect< + Equal< + InferInsertModel, + Simplify + > +>; + export const users = pgTable( 'users_table', { @@ -114,9 +139,7 @@ export const smallSerialTest = pgTable('cities_table', { id: smallserial('id').primaryKey(), name: text('name').notNull(), population: integer('population').default(0), -}, (cities) => ({ - citiesNameIdx: index().on(cities.id), -})); +}); Expect< Equal<{ @@ -207,6 +230,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -223,6 +247,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -266,6 +291,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -282,6 +308,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -323,6 +350,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -339,6 +367,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -380,6 +409,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -396,6 +426,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -427,6 +458,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -443,6 +475,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -474,6 +507,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -490,6 +524,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -536,6 +571,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -552,6 +588,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -598,6 +635,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -614,6 +652,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -658,6 +697,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -674,6 +714,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -718,6 +759,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -734,6 +776,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -765,6 +808,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -781,6 +825,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -812,6 +857,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -828,6 +874,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -943,6 +990,7 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -959,6 +1007,7 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); notNull: true; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; @@ -975,6 +1024,7 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); notNull: true; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; @@ -991,6 +1041,7 @@ await db.refreshMaterializedView(newYorkers2).withNoData().concurrently(); enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; diff --git a/drizzle-orm/type-tests/sqlite/tables.ts b/drizzle-orm/type-tests/sqlite/tables.ts index 02a6e840a..358b6fea6 100644 --- a/drizzle-orm/type-tests/sqlite/tables.ts +++ b/drizzle-orm/type-tests/sqlite/tables.ts @@ -171,6 +171,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: true; @@ -187,6 +188,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: true; @@ -222,6 +224,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: false; @@ -238,6 +241,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: false; @@ -269,6 +273,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: false; @@ -285,6 +290,7 @@ Expect< enumValues: undefined; baseColumn: never; generated: undefined; + identity: undefined; isAutoincrement: false; hasRuntimeDefault: false; isPrimaryKey: false; diff --git a/drizzle-seed/README.md b/drizzle-seed/README.md new file mode 100644 index 000000000..8476e03b5 --- /dev/null +++ b/drizzle-seed/README.md @@ -0,0 +1,1143 @@ +## Overview + +drizzle-seed is a typescript library that will help you generate deterministic fake realistic data and fill your database with it. + +### Determinism + +## + +#### pseudorandom number generator(pRNG) + +It's a random number generator whose randomness you can control. +It will give you the same sequence of numbers if you initialize it with the same `seed` number. + +## + +#### How it works? + +Each column will be assigned with its generator and all random events in it will be handled by pRNG. + +Each pRNG will be initialized with `seed` which will be generated from table name and column name. + +Also, there will be cases when the randomness of generators will be affected by the number of rows you want to generate. So far this only applies to unique int and number generators. + +So as long as your schema and your seeding script remain the same, Seeder will generate the same data. + +## Getting started + +`npm install drizzle-seed` + +You have to install drizzle-orm in order to use seeder. + +`npm install drizzle-orm` + +## Usage + +### Simple usage + +#### `src/main.ts` + +```ts +(async () => { + await seed(db, schema); + // await seed(db, schema, { count: 100000 }); + // await seed(db, schema, { count: 100000, seed: 1 }); +})().then(); +``` + +From the commented part of the code above, you can see that it's possible to specify the `count` property which stands for the number of rows you want to generate + +and `seed` property which represents a custom `seed` number that will be added to the one automatically generated from the table's name and column's name and then the result of addition will be fed to pRNG. +Therefore you can manage different states of your data using the `seed` property. + +#### You also can delete all data from your tables to seed your database again using the `reset` function. + +#### `src/main.ts` + +```ts +(async () => { + await reset(db, schema); + // await seed(db, schema); +})().then(); +``` + +`If db is a PgDatabase object`, we will execute sql query and delete data from your tables the following way: + +```sql +truncate tableName1, tableName2, ... cascade; +``` + +`If db is a MySqlDatabase object`, we will execute sql queries and delete data from your tables the following way: + +```sql +SET FOREIGN_KEY_CHECKS = 0; +truncate tableName1; +truncate tableName2; +. +. +. + +SET FOREIGN_KEY_CHECKS = 1; +``` + +`If db is a BaseSQLiteDatabase object`, we will execute sql queries and delete data from your tables the following way: + +```sql +PRAGMA foreign_keys = OFF; +delete from tableName1; +delete from tableName2; +. +. +. + +PRAGMA foreign_keys = ON; +``` + +### But you still need to define database schema (`schema`) and create database connection (`db`) before using `seed` or `reset` function. + +#### You can find some examples for Postgres, Mysql and Sqlite below. + +### **Postgres** + +#### `src/schema.ts` + +```ts +import { + serial, + integer, + varchar, + pgSchema, + getTableConfig as getPgTableConfig, +} from "drizzle-orm/pg-core"; + +export const schema = pgSchema("seeder_lib_pg"); + +export const users = schema.table("users", { + id: serial("id").primaryKey(), + name: varchar("name", { length: 256 }), + email: varchar("email", { length: 256 }), + phone: varchar("phone", { length: 256 }), + password: varchar("password", { length: 256 }), +}); + +export const posts = schema.table("posts", { + id: serial("id").primaryKey(), + title: varchar("title", { length: 256 }), + content: varchar("content", { length: 256 }), + userId: integer("user_id").references(() => users.id), +}); +``` + +#### `src/main.ts` + +```ts +import Pool from "pg"; +import { drizzle } from "drizzle-orm/node-postgres"; +import * as schema from "./schema"; + +const { PG_HOST, PG_PORT, PG_DATABASE, PG_USER, PG_PASSWORD } = process.env; + +const pool = new Pool({ + host: PG_HOST, + port: Number(PG_PORT) || 5432, + database: PG_DATABASE, + user: PG_USER, + password: PG_PASSWORD, + // ssl: true +}); + +const db = drizzle(pool); +``` + +### **Mysql** + +#### `src/schema.ts` + +```ts +import { serial, int, varchar, mysqlTable } from "drizzle-orm/mysql-core"; + +export const users = mysqlTable("users", { + id: int("id").autoincrement().primaryKey(), + name: varchar("name", { length: 256 }), + email: varchar("email", { length: 256 }), + phone: varchar("phone", { length: 256 }), + password: varchar("password", { length: 256 }), +}); + +export const posts = mysqlTable("posts", { + id: int("id").autoincrement().primaryKey(), + title: varchar("title", { length: 256 }), + content: varchar("content", { length: 256 }), + userId: int("user_id").references(() => users.id), +}); +``` + +#### `src/main.ts` + +```ts +import mysql from "mysql2/promise"; +import { drizzle } from "drizzle-orm/mysql2"; +import * as schema from "./schema"; + +const { Mysql_HOST, Mysql_PORT, Mysql_DATABASE, Mysql_USER, Mysql_PASSWORD } = + process.env; + +const pool = mysql.createPool({ + host: Mysql_HOST, + port: Number(Mysql_PORT) || 3306, + database: Mysql_DATABASE, + user: Mysql_USER, + password: Mysql_PASSWORD, + // ssl: { rejectUnauthorized: false } +}); + +const db = drizzle(pool); +``` + +### **Sqlite** + +#### `src/schema.ts` + +```ts +import { integer, text, sqliteTable } from "drizzle-orm/sqlite-core"; + +export const users = sqliteTable("users", { + id: integer("id").primaryKey(), + name: text("name", { length: 256 }), + email: text("email", { length: 256 }), + phone: text("phone", { length: 256 }), + password: text("password", { length: 256 }), +}); + +export const posts = sqliteTable("posts", { + id: integer("id").primaryKey(), + title: text("title", { length: 256 }), + content: text("content", { length: 256 }), + userId: integer("user_id").references(() => users.id), +}); +``` + +#### `src/main.ts` + +```ts +import betterSqlite3 from "better-sqlite3"; +import { drizzle } from "drizzle-orm/better-sqlite3"; +import * as schema from "./schema"; + +const { Sqlite_PATH } = process.env; +const sqliteDb = betterSqlite3(Sqlite_PATH); +const db = drizzle(sqliteDb); +``` + +### More complex usage examples + +#### All of the following examples will be in the context of database schema defined above. + +## + +#### You have 30 different data generators to choose from: + +- `default` +- `valuesFromArray` +- `intPrimaryKey` +- `number` +- `int` +- `boolean` +- `date` +- `time` +- `timestamp` +- `datetime` +- `year` +- `json` +- `interval` +- `string` +- `firstName` +- `lastName` +- `fullName` +- `email` +- `phoneNumber` +- `country` +- `city` +- `streetAddress` +- `jobTitle` +- `postcode` +- `state` +- `companyName` +- `loremIpsum` +- `weightedRandom` + +#### Some of them have an option to generate unique data samples which stands for property `isUnique`. + +#### Some of them can only generate unique data like `email` or `phoneNumber` generators. + +#### `src/main.ts` + +```ts +(async () => { + await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + name: funcs.firstName({ isUnique: true }), + email: funcs.email(), + phone: funcs.phoneNumber({ template: "+380 99 ###-##-##" }), + password: funcs.string({ isUnique: true }), + }, + count: 100000, + }, + posts: { + columns: { + title: funcs.valuesFromArray({ + values: ["Title1", "Title2", "Title3", "Title4", "Title5"], + }), + content: funcs.loremIpsum({ sentencesCount: 3 }), + }, + }, + })); +})().then(); +``` + +In the example above we used
+`firstName`, `string` generators that have `isUnique` property,
+`email` and `phoneNumber` which always generates unique data,
+`loremIpsum` and `default` generators that don't have `isUnique` property,
+and `valuesFromArray` which has `isUnique` property. + +Also we specified number of rows we want to generate in `users` section using property `count`. Therefore top-level `count` which equals 1000, will be rewrote with the one from `refine` and `count` for `users` table will equal 100000. + +And since we didn't specify `count` property in `posts` section it will use top-level `count` which equals 1000 and generate 1000 rows for `posts` table. + +#### Even so `valuesFromArray` generator has `isUnique` property, there is no point using it here, since we have only 5 unique elements in `values` array and want to generate 1000 titles for `posts` table. + +## + +#### You can specify how many posts each user will have, using `with` property if there is right relation in schema. + +#### Write `with: {posts: 2}` so each user will have 2 posts related to him. + +#### `src/main.ts` + +```ts +(async () => { + await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + count: 100000, + with: { + posts: 2, + }, + }, + posts: { + count: 100, + }, + })); +})().then(); +``` + +In this example overall number of posts or in other words posts `count` will be calculated like: + +{users `count`} $\times$ 2 = 100000 $\times$ 2 = 200000 + +And this posts `count` will overwrite both top-level `count` which equals to 100000 and `count` from `posts` section which equals to 100. + +## + +#### **Weighted choice** + +#### You can specify weighted number of posts for each user to have. + +```ts +with: { + posts: [ + { weight: 0.7, count: 3 }, + { weight: 0.3, count: [4, 5] } + ] +} +``` + +#### This means that each user will have 3 posts with probability 0.7 and from 4 to 5 posts with probability 0.3 . + +Number of posts for each user will be generated using pRNG and therefore remain deterministic. + +#### There also are some generators that feature select with given probability: + +- `valuesFromArray` has option to specify weighted arrays of values, +- `weightedMix` will use generators with given probabilities. + +#### `src/main.ts` + +```ts +(async () => { + await seed(db, schema).refine((funcs) => ({ + users: { + count: 100000, + with: { + posts: [ + { weight: 0.7, count: 3 }, + { weight: 0.3, count: [4, 5] }, + ], + }, + }, + posts: { + columns: { + title: funcs.valuesFromArray({ + values: [ + { weight: 0.35, values: ["Title1", "Title2"] }, + { weight: 0.5, values: ["Title3", "Title4"] }, + { weight: 0.15, values: ["Title5"] }, + ], + }), + content: funcs.weightedRandom([ + { + weight: 0.6, + value: funcs.loremIpsum({ sentencesCount: 3 }), + }, + { + weight: 0.4, + value: funcs.default({ defaultValue: "TODO" }), + }, + ]), + }, + }, + })); +})().then(); +``` + +#### Explanations of the code block above: + +- `valuesFromArray` generator
+ with probability 0.35 will pick array `["Title1", "Title2"]`,
+ with probability 0.5 will pick array `["Title3", "Title4"]`,
+ with probability 0.15 will pick array `["Title5"]`
+ and then pick value from chosen array using uniform distribution or in other words uniformly. +- `weightedMix` generator will call `loremIpsum` generator with probability 0.6 and `default` generator with probability 0.4 . + +## + +#### And you can combine all of this in one seeding script + +#### `src/main.ts` + +```ts +(async () => { + await seed(db, schema).refine((funcs) => ({ + users: { + columns: { + name: funcs.fullName(), + email: funcs.email(), + phone: funcs.phoneNumber({ template: "+380 99 ###-##-##" }), + password: funcs.string({ isUnique: true }), + }, + count: 100000, + with: { + posts: [ + { weight: 0.7, count: 3 }, + { weight: 0.3, count: [4, 5] }, + ], + }, + }, + posts: { + columns: { + title: funcs.valuesFromArray({ + values: [ + { weight: 0.35, values: ["Title1", "Title2"] }, + { weight: 0.5, values: ["Title3", "Title4"] }, + { weight: 0.15, values: ["Title5"] }, + ], + }), + content: funcs.weightedRandom([ + { + weight: 0.6, + value: funcs.loremIpsum({ sentencesCount: 3 }), + }, + { + weight: 0.4, + value: funcs.default({ defaultValue: "TODO" }), + }, + ]), + }, + }, + })); +})().then(); +``` + +### Generators Usage Examples + +## + +#### **default** + +generates same given value each time the generator is called. + +`defaultValue` - value you want to generate + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + content: funcs.default({ defaultValue: "post content" }), + }, + }, +})); +``` + +## + +#### **valuesFromArray** + +generates values from given array + +`values` - array of values you want to generate.(can be array of weighted values) + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + title: funcs.valuesFromArray({ + values: ["Title1", "Title2", "Title3", "Title4", "Title5"], + isUnique: true, + }), + }, + }, +})); +``` + +weighted values example + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + title: funcs.valuesFromArray({ + values: [ + { weight: 0.35, values: ["Title1", "Title2"] }, + { weight: 0.5, values: ["Title3", "Title4"] }, + { weight: 0.15, values: ["Title5"] }, + ], + isUnique: false, + }), + }, + }, +})); +``` + +## + +#### **intPrimaryKey** + +generates sequential integers starting with 1. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + id: funcs.intPrimaryKey(), + }, + }, +})); +``` + +## + +#### **number** + +generates numbers with floating point in given range. + +`minValue` - lower border of range. + +`maxValue` - upper border of range. + +`precision` - precision of generated number:
+precision equals 10 means that values will be accurate to one tenth (1.2, 34.6);
+precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67). + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + products: { + columns: { + unitPrice: funcs.number({ + minValue: 10, + maxValue: 120, + precision: 100, + isUnique: false, + }), + }, + }, +})); +``` + +## + +#### **int** + +generates integers with given range. + +`minValue` - lower border of range. + +`maxValue` - upper border of range. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + products: { + columns: { + unitsInStock: funcs.int({ + minValue: 0, + maxValue: 100, + isUnique: false, + }), + }, + }, +})); +``` + +## + +#### **boolean** + +generates boolean values(true or false). + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + isAvailable: funcs.boolean(), + }, + }, +})); +``` + +## + +#### **date** + +generates date within given range. + +`minDate` - lower border of range. + +`maxDate` - upper border of range. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + birthDate: funcs.date({ minDate: "1990-01-01", maxDate: "2010-12-31" }), + }, + }, +})); +``` + +## + +#### **time** + +generates time in 24 hours style. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + birthTime: funcs.time(), + }, + }, +})); +``` + +## + +#### **timestamp** + +generates timestamps. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + orders: { + columns: { + shippedDate: funcs.timestamp(), + }, + }, +})); +``` + +## + +#### **datetime** + +generates datetime objects. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + orders: { + columns: { + shippedDate: funcs.datetime(), + }, + }, +})); +``` + +## + +#### **year** + +generates years. + +example of generated value: "2024" + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + birthYear: funcs.year(), + }, + }, +})); +``` + +## + +#### **json** + +generates json objects with fixed structure. + +json structure can equal this: + +``` +{ + email, + name, + isGraduated, + hasJob, + salary, + startedWorking, + visitedCountries, +} +``` + +or this + +``` +{ + email, + name, + isGraduated, + hasJob, + visitedCountries, +} +``` + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + metadata: funcs.json(), + }, + }, +})); +``` + +## + +#### **interval** + +generates time intervals. + +example of generated value: "1 years 12 days 5 minutes" + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + timeSpentOnWebsite: funcs.interval(), + }, + }, +})); +``` + +## + +#### **string** + +generates random strings. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + hashedPassword: funcs.string({ isUnique: false }), + }, + }, +})); +``` + +## + +#### **firstName** + +generates person's first names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + firstName: funcs.firstName({ isUnique: true }), + }, + }, +})); +``` + +## + +#### **lastName** + +generates person's last names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + lastName: funcs.lastName({ isUnique: false }), + }, + }, +})); +``` + +## + +#### **fullName** + +generates person's full names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + fullName: funcs.fullName({ isUnique: true }), + }, + }, +})); +``` + +## + +#### **email** + +generates unique emails. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + email: funcs.email(), + }, + }, +})); +``` + +## + +#### **phoneNumber** + +generates unique phone numbers. + +`template` - phone number template, where all '#' symbols will be substituted with generated digits. + +`prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property) + +`generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property) + +```ts +//generate phone number using template property +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + phoneNumber: funcs.phoneNumber({ template: "+(380) ###-####" }), + }, + }, +})); + +//generate phone number using prefixes and generatedDigitsNumbers properties +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + phoneNumber: funcs.phoneNumber({ + prefixes: ["+380 99", "+380 67"], + generatedDigitsNumbers: 7, + }), + }, + }, +})); + +//generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + phoneNumber: funcs.phoneNumber({ + prefixes: ["+380 99", "+380 67", "+1"], + generatedDigitsNumbers: [7, 7, 10], + }), + }, + }, +})); +``` + +## + +#### **country** + +generates country's names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + country: funcs.country({ isUnique: false }), + }, + }, +})); +``` + +## + +#### **city** + +generates city's names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + city: funcs.city({ isUnique: false }), + }, + }, +})); +``` + +## + +#### **streetAddress** + +generates street address. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + streetAddress: funcs.streetAddress({ isUnique: true }), + }, + }, +})); +``` + +## + +#### **jobTitle** + +generates job titles. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + jobTitle: funcs.jobTitle(), + }, + }, +})); +``` + +## + +#### **postcode** + +generates postal codes. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + postcode: funcs.postcode({ isUnique: true }), + }, + }, +})); +``` + +## + +#### **state** + +generates states of America. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + state: funcs.state(), + }, + }, +})); +``` + +## + +#### **companyName** + +generates company's names. + +`isUnique` - property that controls if generated values gonna be unique or not. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + company: funcs.companyName({ isUnique: true }), + }, + }, +})); +``` + +## + +#### **loremIpsum** + +generates 'lorem ipsum' text sentences. + +`sentencesCount` - number of sentences you want to generate as one generated value(string). + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + content: funcs.loremIpsum({ sentencesCount: 2 }), + }, + }, +})); +``` + +## + +#### **point** + +generates 2D points within specified ranges for x and y coordinates. + +`isUnique` - property that controls if generated values gonna be unique or not. + +`minXValue` - lower bound of range for x coordinate. + +`maxXValue` - upper bound of range for x coordinate. + +`minYValue` - lower bound of range for y coordinate. + +`maxYValue` - upper bound of range for y coordinate. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + triangles: { + columns: { + pointCoords: funcs.point({ + isUnique: true, + minXValue: -5, + maxXValue: 20, + minYValue: 0, + maxYValue: 30, + }), + }, + }, +})); +``` + +## + +#### **line** + +generates 2D lines within specified ranges for a, b and c parameters of line. + +``` +line equation: a*x + b*y + c = 0 +``` + +`isUnique` - property that controls if generated values gonna be unique or not. + +`minAValue` - lower bound of range for a parameter. + +`maxAValue` - upper bound of range for x parameter. + +`minBValue` - lower bound of range for y parameter. + +`maxBValue` - upper bound of range for y parameter. + +`minCValue` - lower bound of range for y parameter. + +`maxCValue` - upper bound of range for y parameter. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + lines: { + columns: { + lineParams: funcs.point({ + isUnique: true, + minAValue: -5, + maxAValue: 20, + minBValue: 0, + maxBValue: 30, + minCValue: 0, + maxCValue: 10, + }), + }, + }, +})); +``` + +## + +#### **weightedRandom** + +gives you the opportunity to call different generators with different probabilities to generate values for one column. + +params - array of generators with probabilities you would like to call them to generate values. + +```ts +await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + posts: { + columns: { + content: funcs.weightedRandom([ + { + weight: 0.6, + value: funcs.loremIpsum({ sentencesCount: 3 }), + }, + { + weight: 0.4, + value: funcs.default({ defaultValue: "TODO" }), + }, + ]), + }, + }, +})); +``` + +## + +## Limitations + +- Seeder can generate data for composite foreign keys, but it can't handle the uniqueness of composite primary keys, so using composite primary and foreign keys sometimes will end up in error for now. +- Seeder can't generate data for columns with composite unique constraint.(unique index for multiple columns) +- Not all generators have ability to generate unique data. This applies to default, date, time, timestamp, datetime, year, json, jobTitle, state, loremIpsum generators. diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json new file mode 100644 index 000000000..c529f22e8 --- /dev/null +++ b/drizzle-seed/package.json @@ -0,0 +1,103 @@ +{ + "name": "drizzle-seed", + "version": "0.1.1", + "main": "index.js", + "type": "module", + "scripts": { + "build": "tsx scripts/build.ts", + "pack": "(cd dist && npm pack --pack-destination ..) && rm -f package.tgz && mv *.tgz package.tgz", + "test": "vitest --config ./src/tests/vitest.config.ts", + "generate-for-tests:pg": "drizzle-kit generate --config=./src/tests/pg/drizzle.config.ts", + "generate-for-tests:mysql": "drizzle-kit generate --config=./src/tests/mysql/drizzle.config.ts", + "generate-for-tests:sqlite": "drizzle-kit generate --config=./src/tests/sqlite/drizzle.config.ts", + "generate": "drizzle-kit generate", + "start": "npx tsx ./src/test.ts", + "start:pg": "npx tsx ./src/tests/northwind/pgTest.ts", + "start:mysql": "npx tsx ./src/tests/northwind/mysqlTest.ts", + "start:sqlite": "npx tsx ./src/tests/northwind/sqliteTest.ts", + "benchmark": "npx tsx ./src/tests/benchmarks/generatorsBenchmark.ts" + }, + "author": "Drizzle Team", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/drizzle-team/drizzle-orm/issues" + }, + "keywords": [ + "drizzle", + "orm", + "pg", + "mysql", + "postgresql", + "postgres", + "sqlite", + "database", + "sql", + "typescript", + "ts", + "drizzle-orm", + "drizzle-seed", + "seeding", + "seed" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/drizzle-team/drizzle-orm.git" + }, + "publishConfig": { + "provenance": true + }, + "sideEffects": false, + "description": "A package to seed your database using Drizzle ORM", + "exports": { + ".": { + "import": { + "types": "./index.d.mts", + "default": "./index.mjs" + }, + "require": { + "types": "./index.d.cjs", + "default": "./index.cjs" + }, + "types": "./index.d.ts", + "default": "./index.mjs" + } + }, + "peerDependencies": { + "drizzle-orm": ">=0.36.4" + }, + "peerDependenciesMeta": { + "drizzle-orm": { + "optional": true + } + }, + "devDependencies": { + "@arethetypeswrong/cli": "^0.16.1", + "@electric-sql/pglite": "^0.2.12", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.6", + "@types/better-sqlite3": "^7.6.11", + "@types/dockerode": "^3.3.31", + "@types/node": "^22.5.4", + "@types/pg": "^8.11.6", + "@types/uuid": "^10.0.0", + "better-sqlite3": "^11.1.2", + "cpy": "^11.1.0", + "dockerode": "^4.0.2", + "dotenv": "^16.4.5", + "drizzle-kit": "workspace:./drizzle-kit/dist", + "drizzle-orm": "workspace:./drizzle-orm/dist", + "get-port": "^7.1.0", + "mysql2": "^3.3.3", + "pg": "^8.12.0", + "resolve-tspaths": "^0.8.19", + "rollup": "^4.21.2", + "tslib": "^2.7.0", + "tsx": "^4.19.0", + "uuid": "^10.0.0", + "vitest": "^2.0.5", + "zx": "^8.1.5" + }, + "dependencies": { + "pure-rand": "^6.1.0" + } +} diff --git a/drizzle-seed/rollup.config.ts b/drizzle-seed/rollup.config.ts new file mode 100644 index 000000000..229862c75 --- /dev/null +++ b/drizzle-seed/rollup.config.ts @@ -0,0 +1,32 @@ +import terser from '@rollup/plugin-terser'; +import typescript from '@rollup/plugin-typescript'; +import { defineConfig } from 'rollup'; + +export default defineConfig([ + { + input: 'src/index.ts', + output: [ + { + format: 'esm', + dir: 'dist', + entryFileNames: '[name].mjs', + chunkFileNames: '[name]-[hash].mjs', + sourcemap: true, + }, + { + format: 'cjs', + dir: 'dist', + entryFileNames: '[name].cjs', + chunkFileNames: '[name]-[hash].cjs', + sourcemap: true, + }, + ], + external: [/^drizzle-orm\/?/, 'pure-rand'], + plugins: [ + typescript({ + tsconfig: 'tsconfig.build.json', + }), + terser(), + ], + }, +]); diff --git a/drizzle-seed/scripts/build.ts b/drizzle-seed/scripts/build.ts new file mode 100644 index 000000000..1910feac6 --- /dev/null +++ b/drizzle-seed/scripts/build.ts @@ -0,0 +1,15 @@ +#!/usr/bin/env -S pnpm tsx +import 'zx/globals'; +import cpy from 'cpy'; + +await fs.remove('dist'); +await $`rollup --config rollup.config.ts --configPlugin typescript`; +await $`resolve-tspaths`; +await fs.copy('README.md', 'dist/README.md'); +await cpy('dist/**/*.d.ts', 'dist', { + rename: (basename) => basename.replace(/\.d\.ts$/, '.d.mts'), +}); +await cpy('dist/**/*.d.ts', 'dist', { + rename: (basename) => basename.replace(/\.d\.ts$/, '.d.cts'), +}); +await fs.copy('package.json', 'dist/package.json'); diff --git a/drizzle-seed/src/datasets/adjectives.ts b/drizzle-seed/src/datasets/adjectives.ts new file mode 100644 index 000000000..c2b152af0 --- /dev/null +++ b/drizzle-seed/src/datasets/adjectives.ts @@ -0,0 +1,4846 @@ +/** + * The original source for the Adjectives data was taken from https://www.kaggle.com/datasets/jordansiem/adjectives-list + */ +export default [ + 'abandoned', + 'abdominal', + 'abhorrent', + 'abiding', + 'abject', + 'able', + 'able-bodied', + 'abnormal', + 'abounding', + 'abrasive', + 'abrupt', + 'absent', + 'absentminded', + 'absolute', + 'absorbed', + 'absorbing', + 'abstracted', + 'absurd', + 'abundant', + 'abusive', + 'abysmal', + 'academic', + 'acceptable', + 'accepting', + 'accessible', + 'accidental', + 'acclaimed', + 'accommodating', + 'accompanying', + 'accountable', + 'accurate', + 'accusative', + 'accused', + 'accusing', + 'acerbic', + 'achievable', + 'aching', + 'acid', + 'acidic', + 'acknowledged', + 'acoustic', + 'acrid', + 'acrimonious', + 'acrobatic', + 'actionable', + 'active', + 'actual', + 'adhoc', + 'adamant', + 'adaptable', + 'adaptive', + 'addicted', + 'addictive', + 'additional', + 'adept', + 'adequate', + 'adhesive', + 'adjacent', + 'adjoining', + 'adjustable', + 'administrative', + 'admirable', + 'admired', + 'admiring', + 'adopted', + 'adoptive', + 'adorable', + 'adored', + 'adoring', + 'adrenalized', + 'adroit', + 'adult', + 'advanced', + 'advantageous', + 'adventurous', + 'adversarial', + 'advisable', + 'aerial', + 'affable', + 'affected', + 'affectionate', + 'affirmative', + 'affordable', + 'afraid', + 'afternoon', + 'ageless', + 'aggravated', + 'aggravating', + 'aggressive', + 'agitated', + 'agonizing', + 'agrarian', + 'agreeable', + 'aimless', + 'airline', + 'airsick', + 'ajar', + 'alarmed', + 'alarming', + 'alert', + 'algebraic', + 'alien', + 'alienated', + 'alike', + 'alive', + 'all-around', + 'alleged', + 'allowable', + 'all-purpose', + 'all-too-common', + 'alluring', + 'allusive', + 'alone', + 'aloof', + 'alterable', + 'alternating', + 'alternative', + 'amazed', + 'amazing', + 'ambiguous', + 'ambitious', + 'ambulant', + 'ambulatory', + 'amiable', + 'amicable', + 'amphibian', + 'amused', + 'amusing', + 'ancient', + 'anecdotal', + 'anemic', + 'angelic', + 'angered', + 'angry', + 'angular', + 'animal', + 'animated', + 'annoyed', + 'annoying', + 'annual', + 'anonymous', + 'another', + 'antagonistic', + 'anticipated', + 'anticlimactic', + 'anticorrosive', + 'antiquated', + 'antiseptic', + 'antisocial', + 'antsy', + 'anxious', + 'any', + 'apathetic', + 'apologetic', + 'apologizing', + 'appalling', + 'appealing', + 'appetizing', + 'applauding', + 'applicable', + 'applicative', + 'appreciative', + 'apprehensive', + 'approachable', + 'approaching', + 'appropriate', + 'approving', + 'approximate', + 'aquatic', + 'architectural', + 'ardent', + 'arduous', + 'arguable', + 'argumentative', + 'arid', + 'aristocratic', + 'aromatic', + 'arresting', + 'arrogant', + 'artful', + 'artificial', + 'artistic', + 'artless', + 'ashamed', + 'aspiring', + 'assertive', + 'assignable', + 'assorted', + 'assumable', + 'assured', + 'assuring', + 'astonished', + 'astonishing', + 'astounded', + 'astounding', + 'astringent', + 'astronomical', + 'astute', + 'asymmetrical', + 'athletic', + 'atomic', + 'atrocious', + 'attachable', + 'attainable', + 'attentive', + 'attractive', + 'attributable', + 'atypical', + 'audacious', + 'auspicious', + 'authentic', + 'authoritarian', + 'authoritative', + 'autobiographic', + 'autographed', + 'automatic', + 'autonomous', + 'available', + 'avant-garde', + 'avenging', + 'average', + 'avian', + 'avid', + 'avoidable', + 'awake', + 'awakening', + 'aware', + 'away', + 'awesome', + 'awful', + 'awkward', + 'axiomatic', + 'babbling', + 'baby', + 'background', + 'backhanded', + 'bacterial', + 'bad', + 'bad-tempered', + 'baffled', + 'baffling', + 'bald', + 'balding', + 'balmy', + 'bandaged', + 'banging', + 'bankable', + 'banned', + 'bantering', + 'barbaric', + 'barbarous', + 'barbequed', + 'barefooted', + 'barking', + 'barren', + 'bashful', + 'basic', + 'battered', + 'batty', + 'bawling', + 'beady', + 'beaming', + 'bearable', + 'beautiful', + 'beckoning', + 'bedazzled', + 'bedazzling', + 'beefy', + 'beeping', + 'befitting', + 'befuddled', + 'beginning', + 'belching', + 'believable', + 'bellicose', + 'belligerent', + 'bellowing', + 'bendable', + 'beneficial', + 'benevolent', + 'benign', + 'bent', + 'berserk', + 'best', + 'betrayed', + 'better', + 'betteroff', + 'better-late-than-never', + 'bewildered', + 'bewildering', + 'bewitched', + 'bewitching', + 'biased', + 'biblical', + 'big', + 'big-city', + 'bigger', + 'biggest', + 'big-headed', + 'bighearted', + 'bigoted', + 'bilingual', + 'billable', + 'billowy', + 'binary', + 'binding', + 'bioactive', + 'biodegradable', + 'biographical', + 'bite-sized', + 'biting', + 'bitter', + 'bizarre', + 'black', + 'black-and-blue', + 'blamable', + 'blameless', + 'bland', + 'blank', + 'blaring', + 'blasphemous', + 'blatant', + 'blazing', + 'bleached', + 'bleak', + 'bleary', + 'bleary-eyed', + 'blessed', + 'blind', + 'blindfolded', + 'blinding', + 'blissful', + 'blistering', + 'bloated', + 'blonde', + 'bloodied', + 'blood-red', + 'bloodthirsty', + 'bloody', + 'blooming', + 'blossoming', + 'blue', + 'blundering', + 'blunt', + 'blurred', + 'blurry', + 'blushing', + 'boastful', + 'bodacious', + 'bohemian', + 'boiling', + 'boisterous', + 'bold', + 'bookish', + 'booming', + 'boorish', + 'bordering', + 'bored', + 'boring', + 'born', + 'bossy', + 'both', + 'bothered', + 'bouncing', + 'bouncy', + 'boundless', + 'bountiful', + 'boyish', + 'braided', + 'brainless', + 'brainy', + 'brash', + 'brassy', + 'brave', + 'brawny', + 'brazen', + 'breakable', + 'breathable', + 'breathless', + 'breathtaking', + 'breezy', + 'bribable', + 'brick', + 'brief', + 'bright', + 'bright-eyed', + 'bright-red', + 'brilliant', + 'briny', + 'brisk', + 'bristly', + 'broad', + 'broken', + 'broken-hearted', + 'bronchial', + 'bronze', + 'bronzed', + 'brooding', + 'brown', + 'bruised', + 'brunette', + 'brutal', + 'brutish', + 'bubbly', + 'budget', + 'built-in', + 'bulky', + 'bumpy', + 'bungling', + 'buoyant', + 'bureaucratic', + 'burly', + 'burnable', + 'burning', + 'bushy', + 'busiest', + 'business', + 'bustling', + 'busy', + 'buzzing', + 'cackling', + 'caged', + 'cagey', + 'calculable', + 'calculated', + 'calculating', + 'callous', + 'calm', + 'calming', + 'camouflaged', + 'cancelled', + 'cancerous', + 'candid', + 'cantankerous', + 'capable', + 'capricious', + 'captivated', + 'captivating', + 'captive', + 'carefree', + 'careful', + 'careless', + 'caring', + 'carnivorous', + 'carpeted', + 'carsick', + 'casual', + 'catastrophic', + 'catatonic', + 'catchable', + 'caustic', + 'cautious', + 'cavalier', + 'cavernous', + 'ceaseless', + 'celebrated', + 'celestial', + 'centered', + 'central', + 'cerebral', + 'ceremonial', + 'certain', + 'certifiable', + 'certified', + 'challenged', + 'challenging', + 'chance', + 'changeable', + 'changing', + 'chanting', + 'charging', + 'charismatic', + 'charitable', + 'charmed', + 'charming', + 'chattering', + 'chatting', + 'chatty', + 'chauvinistic', + 'cheap', + 'cheapest', + 'cheeky', + 'cheerful', + 'cheering', + 'cheerless', + 'cheery', + 'chemical', + 'chewable', + 'chewy', + 'chic', + 'chicken', + 'chief', + 'childish', + 'childlike', + 'chilling', + 'chilly', + 'chivalrous', + 'choice', + 'choking', + 'choppy', + 'chronological', + 'chubby', + 'chuckling', + 'chunky', + 'cinematic', + 'circling', + 'circular', + 'circumstantial', + 'civil', + 'civilian', + 'civilized', + 'clammy', + 'clamoring', + 'clandestine', + 'clanging', + 'clapping', + 'clashing', + 'classic', + 'classical', + 'classifiable', + 'classified', + 'classy', + 'clean', + 'cleanable', + 'clear', + 'cleared', + 'clearheaded', + 'clever', + 'climatic', + 'climbable', + 'clinging', + 'clingy', + 'clinical', + 'cliquish', + 'clogged', + 'cloistered', + 'close', + 'closeable', + 'closed', + 'close-minded', + 'cloudless', + 'cloudy', + 'clownish', + 'clueless', + 'clumsy', + 'cluttered', + 'coachable', + 'coarse', + 'cockamamie', + 'cocky', + 'codified', + 'coercive', + 'cognitive', + 'coherent', + 'cohesive', + 'coincidental', + 'cold', + 'coldhearted', + 'collaborative', + 'collapsed', + 'collapsing', + 'collectable', + 'collegial', + 'colloquial', + 'colonial', + 'colorful', + 'colorless', + 'colossal', + 'combative', + 'combined', + 'comfortable', + 'comforted', + 'comforting', + 'comical', + 'commanding', + 'commemorative', + 'commendable', + 'commercial', + 'committed', + 'common', + 'communal', + 'communicable', + 'communicative', + 'communist', + 'compact', + 'comparable', + 'comparative', + 'compassionate', + 'compelling', + 'competent', + 'competitive', + 'complacent', + 'complaining', + 'complete', + 'completed', + 'complex', + 'compliant', + 'complicated', + 'complimentary', + 'compound', + 'comprehensive', + 'compulsive', + 'compulsory', + 'computer', + 'computerized', + 'concealable', + 'concealed', + 'conceited', + 'conceivable', + 'concerned', + 'concerning', + 'concerted', + 'concise', + 'concurrent', + 'condemned', + 'condensed', + 'condescending', + 'conditional', + 'confident', + 'confidential', + 'confirmable', + 'confirmed', + 'conflicted', + 'conflicting', + 'conformable', + 'confounded', + 'confused', + 'confusing', + 'congenial', + 'congested', + 'congressional', + 'congruent', + 'congruous', + 'connectable', + 'connected', + 'connecting', + 'connective', + 'conscientious', + 'conscious', + 'consecutive', + 'consensual', + 'consenting', + 'conservative', + 'considerable', + 'considerate', + 'consistent', + 'consoling', + 'conspicuous', + 'conspiratorial', + 'constant', + 'constitutional', + 'constrictive', + 'constructive', + 'consumable', + 'consummate', + 'contagious', + 'containable', + 'contemplative', + 'contemporary', + 'contemptible', + 'contemptuous', + 'content', + 'contented', + 'contentious', + 'contextual', + 'continual', + 'continuing', + 'continuous', + 'contoured', + 'contractual', + 'contradicting', + 'contradictory', + 'contrarian', + 'contrary', + 'contributive', + 'contrite', + 'controllable', + 'controlling', + 'controversial', + 'convenient', + 'conventional', + 'conversational', + 'convinced', + 'convincing', + 'convoluted', + 'convulsive', + 'cooing', + 'cooked', + 'cool', + 'coolest', + 'cooperative', + 'coordinated', + 'copious', + 'coquettish', + 'cordial', + 'corner', + 'cornered', + 'corny', + 'corporate', + 'corpulent', + 'correct', + 'correctable', + 'corrective', + 'corresponding', + 'corrosive', + 'corrupt', + 'corrupting', + 'corruptive', + 'cosmetic', + 'cosmic', + 'costly', + 'cottony', + 'coughing', + 'courageous', + 'courteous', + 'covert', + 'coveted', + 'cowardly', + 'cowering', + 'coy', + 'cozy', + 'crabby', + 'cracked', + 'crackling', + 'crafty', + 'craggy', + 'crammed', + 'cramped', + 'cranky', + 'crashing', + 'crass', + 'craven', + 'crawling', + 'crazy', + 'creaking', + 'creaky', + 'creamy', + 'creative', + 'credible', + 'creeping', + 'creepy', + 'crestfallen', + 'criminal', + 'crippled', + 'crippling', + 'crisp', + 'crispy', + 'critical', + 'crooked', + 'cropped', + 'cross', + 'crossed', + 'crotchety', + 'crowded', + 'crucial', + 'crude', + 'cruel', + 'crumbling', + 'crumbly', + 'crumply', + 'crunchable', + 'crunching', + 'crunchy', + 'crushable', + 'crushed', + 'crusty', + 'crying', + 'cryptic', + 'crystalline', + 'crystallized', + 'cuddly', + 'culpable', + 'cultural', + 'cultured', + 'cumbersome', + 'cumulative', + 'cunning', + 'curable', + 'curative', + 'curious', + 'curly', + 'current', + 'cursed', + 'curt', + 'curved', + 'curvy', + 'customary', + 'cut', + 'cute', + 'cutting', + 'cylindrical', + 'cynical', + 'daffy', + 'daft', + 'daily', + 'dainty', + 'damaged', + 'damaging', + 'damp', + 'danceable', + 'dandy', + 'dangerous', + 'dapper', + 'daring', + 'dark', + 'darkened', + 'dashing', + 'daughterly', + 'daunting', + 'dawdling', + 'day', + 'dazed', + 'dazzling', + 'dead', + 'deadly', + 'deadpan', + 'deaf', + 'deafening', + 'dear', + 'debatable', + 'debonair', + 'decadent', + 'decayed', + 'decaying', + 'deceitful', + 'deceivable', + 'deceiving', + 'decent', + 'decentralized', + 'deceptive', + 'decimated', + 'decipherable', + 'decisive', + 'declining', + 'decorative', + 'decorous', + 'decreasing', + 'decrepit', + 'dedicated', + 'deep', + 'deepening', + 'deeply', + 'defeated', + 'defective', + 'defendable', + 'defenseless', + 'defensible', + 'defensive', + 'defiant', + 'deficient', + 'definable', + 'definitive', + 'deformed', + 'degenerative', + 'degraded', + 'dehydrated', + 'dejected', + 'delectable', + 'deliberate', + 'deliberative', + 'delicate', + 'delicious', + 'delighted', + 'delightful', + 'delinquent', + 'delirious', + 'deliverable', + 'deluded', + 'demanding', + 'demented', + 'democratic', + 'demonic', + 'demonstrative', + 'demure', + 'deniable', + 'dense', + 'dependable', + 'dependent', + 'deplorable', + 'deploring', + 'depraved', + 'depressed', + 'depressing', + 'depressive', + 'deprived', + 'deranged', + 'derivative', + 'derogative', + 'derogatory', + 'descriptive', + 'deserted', + 'designer', + 'desirable', + 'desirous', + 'desolate', + 'despairing', + 'desperate', + 'despicable', + 'despised', + 'despondent', + 'destroyed', + 'destructive', + 'detachable', + 'detached', + 'detailed', + 'detectable', + 'determined', + 'detestable', + 'detrimental', + 'devastated', + 'devastating', + 'devious', + 'devoted', + 'devout', + 'dexterous', + 'diabolical', + 'diagonal', + 'didactic', + 'different', + 'difficult', + 'diffuse', + 'digestive', + 'digital', + 'dignified', + 'digressive', + 'dilapidated', + 'diligent', + 'dim', + 'diminishing', + 'diminutive', + 'dingy', + 'diplomatic', + 'dire', + 'direct', + 'direful', + 'dirty', + 'disabled', + 'disadvantaged', + 'disadvantageous', + 'disaffected', + 'disagreeable', + 'disappearing', + 'disappointed', + 'disappointing', + 'disapproving', + 'disarming', + 'disastrous', + 'discarded', + 'discernable', + 'disciplined', + 'disconnected', + 'discontented', + 'discordant', + 'discouraged', + 'discouraging', + 'discourteous', + 'discredited', + 'discreet', + 'discriminating', + 'discriminatory', + 'discussable', + 'disdainful', + 'diseased', + 'disenchanted', + 'disgraceful', + 'disgruntled', + 'disgusted', + 'disgusting', + 'disheartened', + 'disheartening', + 'dishonest', + 'dishonorable', + 'disillusioned', + 'disinclined', + 'disingenuous', + 'disinterested', + 'disjointed', + 'dislikeable', + 'disliked', + 'disloyal', + 'dismal', + 'dismissive', + 'disobedient', + 'disorderly', + 'disorganized', + 'disparaging', + 'disparate', + 'dispassionate', + 'dispensable', + 'displaced', + 'displeased', + 'displeasing', + 'disposable', + 'disproportionate', + 'disproved', + 'disputable', + 'disputatious', + 'disputed', + 'disreputable', + 'disrespectful', + 'disruptive', + 'dissatisfied', + 'dissimilar', + 'dissolvable', + 'dissolving', + 'dissonant', + 'dissuasive', + 'distant', + 'distasteful', + 'distinct', + 'distinctive', + 'distinguished', + 'distracted', + 'distracting', + 'distraught', + 'distressed', + 'distressing', + 'distrustful', + 'disturbed', + 'disturbing', + 'divergent', + 'diverging', + 'diverse', + 'diversified', + 'divided', + 'divine', + 'divisive', + 'dizzy', + 'dizzying', + 'doable', + 'documentary', + 'dogged', + 'doggish', + 'dogmatic', + 'doleful', + 'dollish', + 'domed', + 'domestic', + 'dominant', + 'domineering', + 'dorsal', + 'doting', + 'double', + 'doubtful', + 'doubting', + 'dovish', + 'dowdy', + 'down', + 'down-and-out', + 'downhearted', + 'downloadable', + 'downtown', + 'downward', + 'dozing', + 'drab', + 'drained', + 'dramatic', + 'drastic', + 'dreaded', + 'dreadful', + 'dreaming', + 'dreamy', + 'dreary', + 'drenched', + 'dress', + 'dressy', + 'dried', + 'dripping', + 'drivable', + 'driven', + 'droll', + 'drooping', + 'droopy', + 'drowsy', + 'drunk', + 'dry', + 'dual', + 'dubious', + 'due', + 'dulcet', + 'dull', + 'duplicitous', + 'durable', + 'dusty', + 'dutiful', + 'dwarfish', + 'dwindling', + 'dynamic', + 'dysfunctional', + 'each', + 'eager', + 'early', + 'earnest', + 'ear-piercing', + 'ear-splitting', + 'earthshaking', + 'earthy', + 'east', + 'eastern', + 'easy', + 'eatable', + 'eccentric', + 'echoing', + 'ecological', + 'economic', + 'economical', + 'economy', + 'ecstatic', + 'edgy', + 'editable', + 'educated', + 'educational', + 'eerie', + 'effective', + 'effervescent', + 'efficacious', + 'efficient', + 'effortless', + 'effusive', + 'egalitarian', + 'egocentric', + 'egomaniacal', + 'egotistical', + 'eight', + 'eighth', + 'either', + 'elaborate', + 'elastic', + 'elated', + 'elderly', + 'electric', + 'electrical', + 'electrifying', + 'electronic', + 'elegant', + 'elementary', + 'elevated', + 'elfish', + 'eligible', + 'elite', + 'eloquent', + 'elusive', + 'emaciated', + 'embarrassed', + 'embarrassing', + 'embattled', + 'embittered', + 'emblematic', + 'emboldened', + 'embroiled', + 'emergency', + 'eminent', + 'emotional', + 'emotionless', + 'empirical', + 'empty', + 'enamored', + 'enchanted', + 'enchanting', + 'encouraged', + 'encouraging', + 'encrusted', + 'endangered', + 'endearing', + 'endemic', + 'endless', + 'endurable', + 'enduring', + 'energetic', + 'energizing', + 'enforceable', + 'engaging', + 'engrossing', + 'enhanced', + 'enigmatic', + 'enjoyable', + 'enlarged', + 'enlightened', + 'enormous', + 'enough', + 'enraged', + 'ensuing', + 'enterprising', + 'entertained', + 'entertaining', + 'enthralled', + 'enthused', + 'enthusiastic', + 'enticing', + 'entire', + 'entranced', + 'entrepreneurial', + 'enumerable', + 'enviable', + 'envious', + 'environmental', + 'episodic', + 'equable', + 'equal', + 'equidistant', + 'equitable', + 'equivalent', + 'erasable', + 'erect', + 'eroding', + 'errant', + 'erratic', + 'erroneous', + 'eruptive', + 'escalating', + 'esoteric', + 'essential', + 'established', + 'estimated', + 'estranged', + 'eternal', + 'ethereal', + 'ethical', + 'ethnic', + 'euphemistic', + 'euphoric', + 'evasive', + 'even', + 'evenhanded', + 'evening', + 'eventful', + 'eventual', + 'everlasting', + 'every', + 'evil', + 'evocative', + 'exacerbating', + 'exact', + 'exacting', + 'exaggerated', + 'exalted', + 'exasperated', + 'exasperating', + 'excellent', + 'exceptional', + 'excessive', + 'exchangeable', + 'excitable', + 'excited', + 'exciting', + 'exclusive', + 'excruciating', + 'excusable', + 'executable', + 'exemplary', + 'exhausted', + 'exhausting', + 'exhaustive', + 'exhilarated', + 'exhilarating', + 'existing', + 'exotic', + 'expandable', + 'expanded', + 'expanding', + 'expansive', + 'expectant', + 'expected', + 'expedient', + 'expeditious', + 'expendable', + 'expensive', + 'experimental', + 'expert', + 'expired', + 'expiring', + 'explainable', + 'explicit', + 'exploding', + 'exploitative', + 'exploited', + 'explosive', + 'exponential', + 'exposed', + 'express', + 'expressionistic', + 'expressionless', + 'expressive', + 'exquisite', + 'extemporaneous', + 'extendable', + 'extended', + 'extension', + 'extensive', + 'exterior', + 'external', + 'extra', + 'extra-large', + 'extraneous', + 'extraordinary', + 'extra-small', + 'extravagant', + 'extreme', + 'exuberant', + 'eye-popping', + 'fabled', + 'fabulous', + 'facetious', + 'facial', + 'factitious', + 'factual', + 'faded', + 'fading', + 'failed', + 'faint', + 'fainthearted', + 'fair', + 'faithful', + 'faithless', + 'fallacious', + 'false', + 'falsified', + 'faltering', + 'familiar', + 'famished', + 'famous', + 'fanatical', + 'fanciful', + 'fancy', + 'fantastic', + 'far', + 'faraway', + 'farcical', + 'far-flung', + 'farsighted', + 'fascinated', + 'fascinating', + 'fascistic', + 'fashionable', + 'fast', + 'fastest', + 'fastidious', + 'fast-moving', + 'fat', + 'fatal', + 'fateful', + 'fatherly', + 'fathomable', + 'fathomless', + 'fatigued', + 'faulty', + 'favorable', + 'favorite', + 'fawning', + 'feared', + 'fearful', + 'fearless', + 'fearsome', + 'feathered', + 'feathery', + 'feckless', + 'federal', + 'feeble', + 'feebleminded', + 'feeling', + 'feigned', + 'felonious', + 'female', + 'feminine', + 'fermented', + 'ferocious', + 'fertile', + 'fervent', + 'fervid', + 'festive', + 'fetching', + 'fetid', + 'feudal', + 'feverish', + 'few,', + 'fewer', + 'fictional', + 'fictitious', + 'fidgeting', + 'fidgety', + 'fiendish', + 'fierce', + 'fiery', + 'fifth', + 'filmy', + 'filtered', + 'filthy', + 'final', + 'financial', + 'fine', + 'finicky', + 'finite', + 'fireproof', + 'firm', + 'first', + 'fiscal', + 'fishy', + 'fit', + 'fitted', + 'fitting', + 'five', + 'fixable', + 'fixed', + 'flabby', + 'flagrant', + 'flaky', + 'flamboyant', + 'flaming', + 'flammable', + 'flashy', + 'flat', + 'flattened', + 'flattered', + 'flattering', + 'flavored', + 'flavorful', + 'flavorless', + 'flawed', + 'flawless', + 'fleeting', + 'flexible', + 'flickering', + 'flimsy', + 'flippant', + 'flirtatious', + 'floating', + 'flooded', + 'floppy', + 'floral', + 'flowering', + 'flowery', + 'fluent', + 'fluffy', + 'flushed', + 'fluttering', + 'flying', + 'foamy', + 'focused', + 'foggy', + 'folded', + 'following', + 'fond', + 'foolhardy', + 'foolish', + 'forbidding', + 'forceful', + 'foreboding', + 'foregoing', + 'foreign', + 'forensic', + 'foreseeable', + 'forged', + 'forgetful', + 'forgettable', + 'forgivable', + 'forgiving', + 'forgotten', + 'forked', + 'formal', + 'formative', + 'former', + 'formidable', + 'formless', + 'formulaic', + 'forthright', + 'fortuitous', + 'fortunate', + 'forward', + 'foul', + 'foul-smelling', + 'four', + 'fourth', + 'foxy', + 'fractional', + 'fractious', + 'fragile', + 'fragmented', + 'fragrant', + 'frail', + 'frank', + 'frantic', + 'fraternal', + 'fraudulent', + 'frayed', + 'freakish', + 'freaky', + 'freckled', + 'free', + 'freezing', + 'frequent', + 'fresh', + 'fretful', + 'fried', + 'friendly', + 'frightened', + 'frightening', + 'frightful', + 'frigid', + 'frilly', + 'frisky', + 'frivolous', + 'front', + 'frosty', + 'frothy', + 'frowning', + 'frozen', + 'frugal', + 'fruitful', + 'fruitless', + 'fruity', + 'frumpy', + 'frustrated', + 'frustrating', + 'fulfilled', + 'fulfilling', + 'full', + 'fully-grown', + 'fumbling', + 'fuming', + 'fun', + 'functional', + 'fundamental', + 'fun-loving', + 'funniest', + 'funny', + 'furious', + 'furry', + 'furthest', + 'furtive', + 'fussy', + 'futile', + 'future', + 'futuristic', + 'fuzzy', + 'gabby', + 'gainful', + 'gallant', + 'galling', + 'game', + 'gangly', + 'gaping', + 'garbled', + 'gargantuan', + 'garish', + 'garrulous', + 'gaseous', + 'gasping', + 'gaudy', + 'gaunt', + 'gauzy', + 'gawky', + 'general', + 'generative', + 'generic', + 'generous', + 'genial', + 'gentle', + 'genuine', + 'geographic', + 'geologic', + 'geometric', + 'geriatric', + 'ghastly', + 'ghostly', + 'ghoulish', + 'giant', + 'giddy', + 'gifted', + 'gigantic', + 'giggling', + 'gilded', + 'giving', + 'glad', + 'glamorous', + 'glaring', + 'glass', + 'glassy', + 'gleaming', + 'glib', + 'glistening', + 'glittering', + 'global', + 'globular', + 'gloomy', + 'glorious', + 'glossy', + 'glowing', + 'gluey', + 'glum', + 'gluttonous', + 'gnarly', + 'gold', + 'golden', + 'good', + 'good-looking', + 'good-natured', + 'gooey', + 'goofy', + 'gorgeous', + 'graceful', + 'gracious', + 'gradual', + 'grainy', + 'grand', + 'grandiose', + 'graphic', + 'grateful', + 'gratified', + 'gratifying', + 'grating', + 'gratis', + 'gratuitous', + 'grave', + 'gray', + 'greasy', + 'great', + 'greatest', + 'greedy', + 'green', + 'gregarious', + 'grey', + 'grieving', + 'grim', + 'grimacing', + 'grimy', + 'grinding', + 'grinning', + 'gripping', + 'gritty', + 'grizzled', + 'groaning', + 'groggy', + 'groomed', + 'groovy', + 'gross', + 'grotesque', + 'grouchy', + 'growling', + 'grown-up', + 'grubby', + 'grueling', + 'gruesome', + 'gruff', + 'grumbling', + 'grumpy', + 'guaranteed', + 'guarded', + 'guiltless', + 'guilt-ridden', + 'guilty', + 'gullible', + 'gurgling', + 'gushing', + 'gushy', + 'gusty', + 'gutsy', + 'habitable', + 'habitual', + 'haggard', + 'hairless', + 'hairy', + 'half', + 'halfhearted', + 'hallowed', + 'halting', + 'handsome', + 'handy', + 'hanging', + 'haphazard', + 'hapless', + 'happy', + 'hard', + 'hard-to-find', + 'hardworking', + 'hardy', + 'harebrained', + 'harmful', + 'harmless', + 'harmonic', + 'harmonious', + 'harried', + 'harsh', + 'hasty', + 'hated', + 'hateful', + 'haughty', + 'haunting', + 'hawkish', + 'hazardous', + 'hazy', + 'head', + 'heady', + 'healthy', + 'heartbreaking', + 'heartbroken', + 'heartless', + 'heartrending', + 'hearty', + 'heated', + 'heavenly', + 'heavy', + 'hectic', + 'hefty', + 'heinous', + 'helpful', + 'helpless', + 'her', + 'heroic', + 'hesitant', + 'hideous', + 'high', + 'highest', + 'highfalutin', + 'high-functioning', + 'high-maintenance', + 'high-pitched', + 'high-risk', + 'hilarious', + 'his', + 'hissing', + 'historical', + 'hoarse', + 'hoggish', + 'holiday', + 'holistic', + 'hollow', + 'home', + 'homeless', + 'homely', + 'homeopathic', + 'homey', + 'homogeneous', + 'honest', + 'honking', + 'honorable', + 'hopeful', + 'hopeless', + 'horizontal', + 'hormonal', + 'horned', + 'horrendous', + 'horrible', + 'horrid', + 'horrific', + 'horrified', + 'horrifying', + 'hospitable', + 'hostile', + 'hot', + 'hotpink', + 'hot-blooded', + 'hotheaded', + 'hot-shot', + 'hot-tempered', + 'hour-long', + 'house', + 'howling', + 'huffy', + 'huge', + 'huggable', + 'hulking', + 'human', + 'humanitarian', + 'humanlike', + 'humble', + 'humdrum', + 'humid', + 'humiliated', + 'humiliating', + 'humming', + 'humongous', + 'humorless', + 'humorous', + 'hungry', + 'hurried', + 'hurt', + 'hurtful', + 'hushed', + 'husky', + 'hydraulic', + 'hydrothermal', + 'hygienic', + 'hyper-active', + 'hyperbolic', + 'hypercritical', + 'hyperirritable', + 'hypersensitive', + 'hypertensive', + 'hypnotic', + 'hypnotizable', + 'hypothetical', + 'hysterical', + 'icky', + 'iconoclastic', + 'icy', + 'icy-cold', + 'ideal', + 'idealistic', + 'identical', + 'identifiable', + 'idiosyncratic', + 'idiotic', + 'idyllic', + 'ignorable', + 'ignorant', + 'ill', + 'illegal', + 'illegible', + 'illegitimate', + 'ill-equipped', + 'ill-fated', + 'ill-humored', + 'illicit', + 'ill-informed', + 'illiterate', + 'illogical', + 'illuminating', + 'illusive', + 'illustrious', + 'imaginable', + 'imaginary', + 'imaginative', + 'imitative', + 'immaculate', + 'immanent', + 'immature', + 'immeasurable', + 'immediate', + 'immense', + 'immensurable', + 'imminent', + 'immobile', + 'immodest', + 'immoral', + 'immortal', + 'immovable', + 'impartial', + 'impassable', + 'impassioned', + 'impatient', + 'impeccable', + 'impenetrable', + 'imperative', + 'imperceptible', + 'imperceptive', + 'imperfect', + 'imperial', + 'imperialistic', + 'impermeable', + 'impersonal', + 'impertinent', + 'impervious', + 'impetuous', + 'impish', + 'implausible', + 'implicit', + 'implosive', + 'impolite', + 'imponderable', + 'important', + 'imported', + 'imposing', + 'impossible', + 'impoverished', + 'impractical', + 'imprecise', + 'impressionable', + 'impressive', + 'improbable', + 'improper', + 'improvable', + 'improved', + 'improving', + 'imprudent', + 'impulsive', + 'impure', + 'inaccessible', + 'inaccurate', + 'inactive', + 'inadequate', + 'inadmissible', + 'inadvertent', + 'inadvisable', + 'inalienable', + 'inalterable', + 'inane', + 'inanimate', + 'inapplicable', + 'inappropriate', + 'inapt', + 'inarguable', + 'inarticulate', + 'inartistic', + 'inattentive', + 'inaudible', + 'inauspicious', + 'incalculable', + 'incandescent', + 'incapable', + 'incessant', + 'incidental', + 'inclusive', + 'incoherent', + 'incomparable', + 'incompatible', + 'incompetent', + 'incomplete', + 'incomprehensible', + 'inconceivable', + 'inconclusive', + 'incongruent', + 'incongruous', + 'inconsequential', + 'inconsiderable', + 'inconsiderate', + 'inconsistent', + 'inconsolable', + 'inconspicuous', + 'incontrovertible', + 'inconvenient', + 'incorrect', + 'incorrigible', + 'incorruptible', + 'increasing', + 'incredible', + 'incredulous', + 'incremental', + 'incurable', + 'indecent', + 'indecipherable', + 'indecisive', + 'indefensible', + 'indefinable', + 'indefinite', + 'indelible', + 'independent', + 'indescribable', + 'indestructible', + 'indeterminable', + 'indeterminate', + 'indicative', + 'indifferent', + 'indigenous', + 'indignant', + 'indirect', + 'indiscreet', + 'indiscriminate', + 'indispensable', + 'indisputable', + 'indistinct', + 'individual', + 'individualistic', + 'indivisible', + 'indomitable', + 'inductive', + 'indulgent', + 'industrial', + 'industrious', + 'ineffective', + 'ineffectual', + 'inefficient', + 'inelegant', + 'ineloquent', + 'inequitable', + 'inert', + 'inescapable', + 'inevitable', + 'inexact', + 'inexcusable', + 'inexhaustible', + 'inexpedient', + 'inexpensive', + 'inexplicable', + 'inexpressible', + 'inexpressive', + 'inextricable', + 'infallible', + 'infamous', + 'infantile', + 'infatuated', + 'infected', + 'infectious', + 'inferable', + 'inferior', + 'infernal', + 'infinite', + 'infinitesimal', + 'inflamed', + 'inflammable', + 'inflammatory', + 'inflatable', + 'inflated', + 'inflexible', + 'influential', + 'informal', + 'informative', + 'informed', + 'infrequent', + 'infuriated', + 'infuriating', + 'ingenious', + 'ingenuous', + 'inglorious', + 'ingratiating', + 'inhabitable', + 'inharmonious', + 'inherent', + 'inhibited', + 'inhospitable', + 'inhuman', + 'inhumane', + 'initial', + 'injudicious', + 'injured', + 'injurious', + 'innate', + 'inner', + 'innocent', + 'innocuous', + 'innovative', + 'innumerable', + 'inoffensive', + 'inoperable', + 'inoperative', + 'inopportune', + 'inordinate', + 'inorganic', + 'inquiring', + 'inquisitive', + 'insane', + 'insatiable', + 'inscrutable', + 'insecure', + 'insensible', + 'insensitive', + 'inseparable', + 'inside', + 'insidious', + 'insightful', + 'insignificant', + 'insincere', + 'insipid', + 'insistent', + 'insolent', + 'inspirational', + 'inspired', + 'inspiring', + 'instant', + 'instantaneous', + 'instinctive', + 'instinctual', + 'institutional', + 'instructive', + 'instrumental', + 'insubordinate', + 'insufferable', + 'insufficient', + 'insulted', + 'insulting', + 'insurable', + 'insurmountable', + 'intangible', + 'integral', + 'intellectual', + 'intelligent', + 'intelligible', + 'intended', + 'intense', + 'intensive', + 'intentional', + 'interactive', + 'interchangeable', + 'interdepartmental', + 'interdependent', + 'interested', + 'interesting', + 'interior', + 'intermediate', + 'intermittent', + 'internal', + 'international', + 'interpersonal', + 'interracial', + 'intestinal', + 'intimate', + 'intimidating', + 'intolerable', + 'intolerant', + 'intravenous', + 'intrepid', + 'intricate', + 'intrigued', + 'intriguing', + 'intrinsic', + 'introductory', + 'introspective', + 'introverted', + 'intrusive', + 'intuitive', + 'invalid', + 'invaluable', + 'invasive', + 'inventive', + 'invigorating', + 'invincible', + 'invisible', + 'invited', + 'inviting', + 'involuntary', + 'involved', + 'inward', + 'irascible', + 'irate', + 'iridescent', + 'irksome', + 'iron', + 'iron-fisted', + 'ironic', + 'irrational', + 'irreconcilable', + 'irrefutable', + 'irregular', + 'irrelative', + 'irrelevant', + 'irremovable', + 'irreparable', + 'irreplaceable', + 'irrepressible', + 'irresistible', + 'irresponsible', + 'irretrievably', + 'irreverent', + 'irreversible', + 'irrevocable', + 'irritable', + 'irritated', + 'irritating', + 'isolated', + 'itchy', + 'its', + 'itty-bitty', + 'jabbering', + 'jaded', + 'jagged', + 'jarring', + 'jaundiced', + 'jazzy', + 'jealous', + 'jeering', + 'jerky', + 'jiggling', + 'jittery', + 'jobless', + 'jocular', + 'joint', + 'jolly', + 'jovial', + 'joyful', + 'joyless', + 'joyous', + 'jubilant', + 'judgmental', + 'judicious', + 'juicy', + 'jumbled', + 'jumpy', + 'junior', + 'just', + 'justifiable', + 'juvenile', + 'kaput', + 'keen', + 'key', + 'kind', + 'kindhearted', + 'kindly', + 'kinesthetic', + 'kingly', + 'kitchen', + 'knavish', + 'knightly', + 'knobbed', + 'knobby', + 'knotty', + 'knowable', + 'knowing', + 'knowledgeable', + 'known', + 'labored', + 'laborious', + 'lackadaisical', + 'lacking', + 'lacy', + 'lame', + 'lamentable', + 'languid', + 'languishing', + 'lanky', + 'larcenous', + 'large', + 'larger', + 'largest', + 'lascivious', + 'last', + 'lasting', + 'late', + 'latent', + 'later', + 'lateral', + 'latest', + 'latter', + 'laudable', + 'laughable', + 'laughing', + 'lavish', + 'lawful', + 'lawless', + 'lax', + 'lazy', + 'lead', + 'leading', + 'lean', + 'learnable', + 'learned', + 'leased', + 'least', + 'leather', + 'leathery', + 'lecherous', + 'leering', + 'left', + 'left-handed', + 'legal', + 'legendary', + 'legible', + 'legislative', + 'legitimate', + 'lengthy', + 'lenient', + 'less', + 'lesser', + 'lesser-known', + 'less-qualified', + 'lethal', + 'lethargic', + 'level', + 'liable', + 'libelous', + 'liberal', + 'licensed', + 'life', + 'lifeless', + 'lifelike', + 'lifelong', + 'light', + 'light-blue', + 'lighthearted', + 'likable', + 'likeable', + 'likely', + 'like-minded', + 'lily-livered', + 'limber', + 'limited', + 'limitless', + 'limp', + 'limping', + 'linear', + 'lined', + 'lingering', + 'linguistic', + 'liquid', + 'listless', + 'literal', + 'literary', + 'literate', + 'lithe', + 'lithographic', + 'litigious', + 'little', + 'livable', + 'live', + 'lively', + 'livid', + 'living', + 'loathsome', + 'local', + 'locatable', + 'locked', + 'lofty', + 'logarithmic', + 'logical', + 'logistic', + 'lonely', + 'long', + 'longer', + 'longest', + 'longing', + 'long-term', + 'long-winded', + 'loose', + 'lopsided', + 'loquacious', + 'lordly', + 'lost', + 'loud', + 'lousy', + 'loutish', + 'lovable', + 'loveable', + 'lovely', + 'loving', + 'low', + 'low-calorie', + 'low-carb', + 'lower', + 'low-fat', + 'lowly', + 'low-maintenance', + 'low-ranking', + 'low-risk', + 'loyal', + 'lucent', + 'lucid', + 'lucky', + 'lucrative', + 'ludicrous', + 'lukewarm', + 'lulling', + 'luminescent', + 'luminous', + 'lumpy', + 'lurid', + 'luscious', + 'lush', + 'lustrous', + 'luxurious', + 'lying', + 'lyrical', + 'macabre', + 'Machiavellian', + 'macho', + 'mad', + 'maddening', + 'magenta', + 'magic', + 'magical', + 'magnanimous', + 'magnetic', + 'magnificent', + 'maiden', + 'main', + 'maintainable', + 'majestic', + 'major', + 'makeable', + 'makeshift', + 'maladjusted', + 'male', + 'malevolent', + 'malicious', + 'malignant', + 'malleable', + 'mammoth', + 'manageable', + 'managerial', + 'mandatory', + 'maneuverable', + 'mangy', + 'maniacal', + 'manic', + 'manicured', + 'manipulative', + 'man-made', + 'manual', + 'many,', + 'marbled', + 'marginal', + 'marked', + 'marketable', + 'married', + 'marvelous', + 'masked', + 'massive', + 'master', + 'masterful', + 'matchless', + 'material', + 'materialistic', + 'maternal', + 'mathematical', + 'matronly', + 'matted', + 'mature', + 'maximum', + 'meager', + 'mean', + 'meandering', + 'meaningful', + 'meaningless', + 'mean-spirited', + 'measly', + 'measurable', + 'meat-eating', + 'meaty', + 'mechanical', + 'medical', + 'medicinal', + 'meditative', + 'medium', + 'medium-rare', + 'meek', + 'melancholy', + 'mellow', + 'melodic', + 'melodious', + 'melodramatic', + 'melted', + 'memorable', + 'menacing', + 'menial', + 'mental', + 'merciful', + 'merciless', + 'mercurial', + 'mere', + 'merry', + 'messy', + 'metabolic', + 'metallic', + 'metaphoric', + 'meteoric', + 'meticulous', + 'microscopic', + 'microwaveable', + 'middle', + 'middle-class', + 'midweek', + 'mighty', + 'mild', + 'militant', + 'militaristic', + 'military', + 'milky', + 'mincing', + 'mind-bending', + 'mindful', + 'mindless', + 'mini', + 'miniature', + 'minimal', + 'minimum', + 'minor', + 'minute', + 'miraculous', + 'mirthful', + 'miscellaneous', + 'mischievous', + 'miscreant', + 'miserable', + 'miserly', + 'misguided', + 'misleading', + 'mission', + 'mistaken', + 'mistrustful', + 'mistrusting', + 'misty', + 'mixed', + 'mnemonic', + 'moaning', + 'mobile', + 'mocking', + 'moderate', + 'modern', + 'modest', + 'modified', + 'modular', + 'moist', + 'moldy', + 'momentary', + 'momentous', + 'monetary', + 'money-grubbing', + 'monopolistic', + 'monosyllabic', + 'monotone', + 'monotonous', + 'monstrous', + 'monumental', + 'moody', + 'moral', + 'moralistic', + 'morbid', + 'mordant', + 'more', + 'moronic', + 'morose', + 'mortal', + 'mortified', + 'most', + 'mother', + 'motherly', + 'motionless', + 'motivated', + 'motivating', + 'motivational', + 'motor', + 'mountain', + 'mountainous', + 'mournful', + 'mouthwatering', + 'movable', + 'moved', + 'moving', + 'much', + 'muddled', + 'muddy', + 'muffled', + 'muggy', + 'multicultural', + 'multifaceted', + 'multipurpose', + 'multitalented', + 'mumbled', + 'mundane', + 'municipal', + 'murky', + 'muscular', + 'mushy', + 'musical', + 'musky', + 'musty', + 'mutative', + 'mute', + 'muted', + 'mutinous', + 'muttering', + 'mutual', + 'my', + 'myopic', + 'mysterious', + 'mystic', + 'mystical', + 'mystified', + 'mystifying', + 'mythical', + 'naive', + 'nameless', + 'narcissistic', + 'narrow', + 'narrow-minded', + 'nasal', + 'nasty', + 'national', + 'native', + 'natural', + 'naughty', + 'nauseating', + 'nauseous', + 'nautical', + 'navigable', + 'navy-blue', + 'near', + 'nearby', + 'nearest', + 'nearsighted', + 'neat', + 'nebulous', + 'necessary', + 'needless', + 'needy', + 'nefarious', + 'negative', + 'neglected', + 'neglectful', + 'negligent', + 'negligible', + 'negotiable', + 'neighborly', + 'neither', + 'nerve-racking', + 'nervous', + 'neurological', + 'neurotic', + 'neutral', + 'new', + 'newest', + 'next', + 'next-door', + 'nice', + 'nifty', + 'nightmarish', + 'nimble', + 'nine', + 'ninth', + 'nippy', + 'no', + 'noble', + 'nocturnal', + 'noiseless', + 'noisy', + 'nominal', + 'nonabrasive', + 'nonaggressive', + 'nonchalant', + 'noncommittal', + 'noncompetitive', + 'nonconsecutive', + 'nondescript', + 'nondestructive', + 'nonexclusive', + 'nonnegotiable', + 'nonproductive', + 'nonrefundable', + 'nonrenewable', + 'nonresponsive', + 'nonrestrictive', + 'nonreturnable', + 'nonsensical', + 'nonspecific', + 'nonstop', + 'nontransferable', + 'nonverbal', + 'nonviolent', + 'normal', + 'north', + 'northeast', + 'northerly', + 'northwest', + 'nostalgic', + 'nosy', + 'notable', + 'noticeable', + 'notorious', + 'novel', + 'noxious', + 'null', + 'numb', + 'numberless', + 'numbing', + 'numerable', + 'numeric', + 'numerous', + 'nutritional', + 'nutritious', + 'nutty', + 'oafish', + 'obedient', + 'obeisant', + 'obese', + 'objectionable', + 'objective', + 'obligatory', + 'obliging', + 'oblique', + 'oblivious', + 'oblong', + 'obnoxious', + 'obscene', + 'obscure', + 'observable', + 'observant', + 'obsessive', + 'obsolete', + 'obstinate', + 'obstructive', + 'obtainable', + 'obtrusive', + 'obtuse', + 'obvious', + 'occasional', + 'occupational', + 'occupied', + 'oceanic', + 'odd', + 'odd-looking', + 'odiferous', + 'odious', + 'odorless', + 'odorous', + 'offbeat', + 'offensive', + 'offhanded', + 'official', + 'officious', + 'oily', + 'OK', + 'okay', + 'old', + 'older', + 'oldest', + 'old-fashioned', + 'ominous', + 'omniscient', + 'omnivorous', + 'one', + 'one-hour', + 'onerous', + 'one-sided', + 'only', + 'opaque', + 'open', + 'opened', + 'openhanded', + 'openhearted', + 'opening', + 'open-minded', + 'operable', + 'operatic', + 'operational', + 'operative', + 'opinionated', + 'opportune', + 'opportunistic', + 'opposable', + 'opposed', + 'opposing', + 'opposite', + 'oppressive', + 'optimal', + 'optimistic', + 'optional', + 'opulent', + 'oral', + 'orange', + 'ordinary', + 'organic', + 'organizational', + 'original', + 'ornamental', + 'ornate', + 'ornery', + 'orphaned', + 'orthopedic', + 'ossified', + 'ostentatious', + 'other', + 'otherwise', + 'our', + 'outer', + 'outermost', + 'outgoing', + 'outlandish', + 'outraged', + 'outrageous', + 'outside', + 'outspoken', + 'outstanding', + 'outward', + 'oval', + 'overactive', + 'overaggressive', + 'overall', + 'overambitious', + 'overassertive', + 'overbearing', + 'overcast', + 'overcautious', + 'overconfident', + 'overcritical', + 'overcrowded', + 'overemotional', + 'overenthusiastic', + 'overjoyed', + 'overoptimistic', + 'overpowering', + 'overpriced', + 'overprotective', + 'overqualified', + 'overrated', + 'oversensitive', + 'oversized', + 'overt', + 'overwhelmed', + 'overwhelming', + 'overworked', + 'overwrought', + 'overzealous', + 'own', + 'oxymoronic', + 'padded', + 'painful', + 'painless', + 'painstaking', + 'palatable', + 'palatial', + 'pale', + 'pallid', + 'palpable', + 'paltry', + 'pampered', + 'panicky', + 'panoramic', + 'paradoxical', + 'parallel', + 'paranormal', + 'parasitic', + 'parched', + 'pardonable', + 'parental', + 'parenthetic', + 'parking', + 'parsimonious', + 'partial', + 'particular', + 'partisan', + 'part-time', + 'party', + 'passing', + 'passionate', + 'passive', + 'past', + 'pastoral', + 'patched', + 'patchy', + 'patented', + 'paternal', + 'paternalistic', + 'pathetic', + 'pathological', + 'patient', + 'patriotic', + 'patronizing', + 'patterned', + 'payable', + 'peaceable', + 'peaceful', + 'peculiar', + 'pedantic', + 'pedestrian', + 'peerless', + 'peeved', + 'peevish', + 'penetrable', + 'penetrating', + 'pensive', + 'peppery', + 'perceivable', + 'perceptible', + 'perceptive', + 'perceptual', + 'peremptory', + 'perennial', + 'perfect', + 'perfumed', + 'perilous', + 'period', + 'periodic', + 'peripheral', + 'perishable', + 'perky', + 'permanent', + 'permeable', + 'permissible', + 'permissive', + 'pernicious', + 'perpendicular', + 'perpetual', + 'perplexed', + 'perplexing', + 'persevering', + 'persistent', + 'personable', + 'personal', + 'persuasive', + 'pert', + 'pertinent', + 'perturbed', + 'perturbing', + 'pervasive', + 'perverse', + 'pessimistic', + 'petite', + 'pettish', + 'petty', + 'petulant', + 'pharmaceutical', + 'phenomenal', + 'philanthropic', + 'philosophical', + 'phobic', + 'phonemic', + 'phonetic', + 'phosphorescent', + 'photographic', + 'physical', + 'physiological', + 'picturesque', + 'piercing', + 'pigheaded', + 'pink', + 'pious', + 'piquant', + 'pitch-dark', + 'pitch-perfect', + 'piteous', + 'pithy', + 'pitiful', + 'pitiless', + 'pivotal', + 'placid', + 'plaid', + 'plain', + 'plane', + 'planned', + 'plastic', + 'platonic', + 'plausible', + 'playful', + 'pleading', + 'pleasant', + 'pleased', + 'pleasing', + 'pleasurable', + 'plentiful', + 'pliable', + 'plodding', + 'plopping', + 'plucky', + 'plump', + 'pluralistic', + 'plus', + 'plush', + 'pneumatic', + 'poetic', + 'poignant', + 'pointless', + 'poised', + 'poisonous', + 'polished', + 'polite', + 'political', + 'polka-dotted', + 'polluted', + 'polyunsaturated', + 'pompous', + 'ponderous', + 'poor', + 'poorer', + 'poorest', + 'popping', + 'popular', + 'populous', + 'porous', + 'portable', + 'portly', + 'positive', + 'possessive', + 'possible', + 'posthoc', + 'posthumous', + 'postoperative', + 'potable', + 'potent', + 'potential', + 'powdery', + 'powerful', + 'powerless', + 'practical', + 'pragmatic', + 'praiseworthy', + 'precarious', + 'precious', + 'precipitous', + 'precise', + 'precocious', + 'preconceived', + 'predicative', + 'predictable', + 'predisposed', + 'predominant', + 'preeminent', + 'preemptive', + 'prefabricated', + 'preferable', + 'preferential', + 'pregnant', + 'prehistoric', + 'prejudiced', + 'prejudicial', + 'preliminary', + 'premature', + 'premeditated', + 'premium', + 'prenatal', + 'preoccupied', + 'preoperative', + 'preparative', + 'prepared', + 'preposterous', + 'prescriptive', + 'present', + 'presentable', + 'presidential', + 'pressing', + 'pressurized', + 'prestigious', + 'presumable', + 'presumptive', + 'presumptuous', + 'pretend', + 'pretentious', + 'pretty', + 'prevalent', + 'preventable', + 'preventative', + 'preventive', + 'previous', + 'priceless', + 'pricey', + 'prickly', + 'prim', + 'primary', + 'primitive', + 'primordial', + 'princely', + 'principal', + 'principled', + 'prior', + 'prissy', + 'pristine', + 'private', + 'prize', + 'prized', + 'proactive', + 'probabilistic', + 'probable', + 'problematic', + 'procedural', + 'prodigious', + 'productive', + 'profane', + 'professed', + 'professional', + 'professorial', + 'proficient', + 'profitable', + 'profound', + 'profuse', + 'programmable', + 'progressive', + 'prohibitive', + 'prolific', + 'prominent', + 'promised', + 'promising', + 'prompt', + 'pronounceable', + 'pronounced', + 'proof', + 'proper', + 'prophetic', + 'proportional', + 'proportionate', + 'proportioned', + 'prospective', + 'prosperous', + 'protective', + 'prototypical', + 'proud', + 'proverbial', + 'provisional', + 'provocative', + 'provoking', + 'proximal', + 'proximate', + 'prudent', + 'prudential', + 'prying', + 'psychedelic', + 'psychiatric', + 'psychological', + 'psychosomatic', + 'psychotic', + 'public', + 'puckish', + 'puffy', + 'pugnacious', + 'pumped', + 'punctual', + 'pungent', + 'punishable', + 'punitive', + 'puny', + 'pure', + 'purified', + 'puritanical', + 'purple', + 'purported', + 'purposeful', + 'purposeless', + 'purring', + 'pushy', + 'pusillanimous', + 'putrid', + 'puzzled', + 'puzzling', + 'pyrotechnic', + 'quackish', + 'quacky', + 'quaint', + 'qualified', + 'qualitative', + 'quality', + 'quantifiable', + 'quantitative', + 'quarrelsome', + 'queasy', + 'queenly', + 'querulous', + 'questionable', + 'quick', + 'quick-acting', + 'quick-drying', + 'quickest', + 'quick-minded', + 'quick-paced', + 'quick-tempered', + 'quick-thinking', + 'quick-witted', + 'quiet', + 'quintessential', + 'quirky', + 'quivering', + 'quizzical', + 'quotable', + 'rabid', + 'racial', + 'racist', + 'radiant', + 'radical', + 'radioactive', + 'ragged', + 'raging', + 'rainbowcolored', + 'rainy', + 'rakish', + 'rambling', + 'rambunctious', + 'rampageous', + 'rampant', + 'rancid', + 'rancorous', + 'random', + 'rank', + 'rapid', + 'rapid-fire', + 'rapturous', + 'rare', + 'rascally', + 'rash', + 'rasping', + 'raspy', + 'rational', + 'ratty', + 'ravenous', + 'raving', + 'ravishing', + 'raw', + 'razor-edged', + 'reactive', + 'ready', + 'real', + 'realistic', + 'reasonable', + 'reassured', + 'reassuring', + 'rebel', + 'rebellious', + 'receding', + 'recent', + 'receptive', + 'recessive', + 'rechargeable', + 'reciprocal', + 'reckless', + 'reclusive', + 'recognizable', + 'recognized', + 'rectangular', + 'rectifiable', + 'recurrent', + 'recyclable', + 'red', + 'red-blooded', + 'reddish', + 'redeemable', + 'redolent', + 'redundant', + 'referential', + 'refillable', + 'reflective', + 'refractive', + 'refreshing', + 'refundable', + 'refurbished', + 'refutable', + 'regal', + 'regional', + 'regretful', + 'regrettable', + 'regular', + 'reigning', + 'relatable', + 'relative', + 'relaxed', + 'relaxing', + 'relentless', + 'relevant', + 'reliable', + 'relieved', + 'religious', + 'reluctant', + 'remaining', + 'remarkable', + 'remedial', + 'reminiscent', + 'remorseful', + 'remorseless', + 'remote', + 'removable', + 'renegotiable', + 'renewable', + 'rented', + 'repairable', + 'repaired', + 'repeatable', + 'repeated', + 'repentant', + 'repetitious', + 'repetitive', + 'replaceable', + 'replicable', + 'reported', + 'reprehensible', + 'representative', + 'repressive', + 'reproachful', + 'reproductive', + 'republican', + 'repugnant', + 'repulsive', + 'reputable', + 'reputed', + 'rescued', + 'resealable', + 'resentful', + 'reserved', + 'resident', + 'residential', + 'residual', + 'resilient', + 'resolute', + 'resolvable', + 'resonant', + 'resounding', + 'resourceful', + 'respectable', + 'respectful', + 'respective', + 'responsible', + 'responsive', + 'rested', + 'restful', + 'restless', + 'restored', + 'restrained', + 'restrictive', + 'retired', + 'retroactive', + 'retrogressive', + 'retrospective', + 'reusable', + 'revamped', + 'revealing', + 'revengeful', + 'reverent', + 'reverential', + 'reverse', + 'reversible', + 'reviewable', + 'reviled', + 'revisable', + 'revised', + 'revocable', + 'revolting', + 'revolutionary', + 'rewarding', + 'rhetorical', + 'rhythmic', + 'rich', + 'richer', + 'richest', + 'ridiculing', + 'ridiculous', + 'right', + 'righteous', + 'rightful', + 'right-handed', + 'rigid', + 'rigorous', + 'ringing', + 'riotous', + 'ripe', + 'rippling', + 'risky', + 'ritualistic', + 'ritzy', + 'riveting', + 'roaring', + 'roasted', + 'robotic', + 'robust', + 'rocketing', + 'roguish', + 'romantic', + 'roomy', + 'rosy', + 'rotating', + 'rotten', + 'rotting', + 'rotund', + 'rough', + 'round', + 'roundtable', + 'rousing', + 'routine', + 'rowdy', + 'royal', + 'ruddy', + 'rude', + 'rudimentary', + 'rueful', + 'rugged', + 'ruined', + 'ruinous', + 'rumbling', + 'rumpled', + 'ruptured', + 'rural', + 'rusted', + 'rustic', + 'rustling', + 'rusty', + 'ruthless', + 'rutted', + 'saccharin', + 'sacred', + 'sacrificial', + 'sacrilegious', + 'sad', + 'saddened', + 'safe', + 'saintly', + 'salacious', + 'salient', + 'salt', + 'salted', + 'salty', + 'salvageable', + 'salvaged', + 'same', + 'sanctimonious', + 'sandy', + 'sane', + 'sanguine', + 'sanitary', + 'sappy', + 'sarcastic', + 'sardonic', + 'sassy', + 'satin', + 'satiny', + 'satiric', + 'satirical', + 'satisfactory', + 'satisfied', + 'satisfying', + 'saucy', + 'savage', + 'savory', + 'savvy', + 'scalding', + 'scaly', + 'scandalous', + 'scant', + 'scanty', + 'scarce', + 'scared', + 'scarred', + 'scary', + 'scathing', + 'scattered', + 'scenic', + 'scented', + 'scheduled', + 'schematic', + 'scholarly', + 'scholastic', + 'scientific', + 'scintillating', + 'scorching', + 'scornful', + 'scrabbled', + 'scraggly', + 'scrappy', + 'scratched', + 'scratchy', + 'scrawny', + 'screaming', + 'screeching', + 'scribbled', + 'scriptural', + 'scruffy', + 'scrumptious', + 'scrupulous', + 'sculpted', + 'sculptural', + 'scummy', + 'sea', + 'sealed', + 'seamless', + 'searching', + 'searing', + 'seasick', + 'seasonable', + 'seasonal', + 'secluded', + 'second', + 'secondary', + 'second-hand', + 'secret', + 'secretive', + 'secular', + 'secure', + 'secured', + 'sedate', + 'seditious', + 'seductive', + 'seedy', + 'seeming', + 'seemly', + 'seething', + 'seismic', + 'select', + 'selected', + 'selective', + 'self-absorbed', + 'self-aggrandizing', + 'self-assured', + 'self-centered', + 'self-confident', + 'self-directed', + 'self-disciplined', + 'self-effacing', + 'self-indulgent', + 'self-interested', + 'selfish', + 'selfless', + 'self-reliant', + 'self-respect', + 'self-satisfied', + 'sellable', + 'semiconscious', + 'semiofficial', + 'semiprecious', + 'semiprofessional', + 'senior', + 'sensational', + 'senseless', + 'sensible', + 'sensitive', + 'sensual', + 'sensuous', + 'sentimental', + 'separate', + 'sequential', + 'serendipitous', + 'serene', + 'serial', + 'serious', + 'serrated', + 'serviceable', + 'seven', + 'seventh', + 'several', + 'severe', + 'shabbiest', + 'shabby', + 'shaded', + 'shadowed', + 'shadowy', + 'shady', + 'shaggy', + 'shaky', + 'shallow', + 'shamefaced', + 'shameful', + 'shameless', + 'shapeless', + 'shapely', + 'sharp', + 'sharpened', + 'shattered', + 'shattering', + 'sheepish', + 'sheer', + 'sheltered', + 'shifty', + 'shimmering', + 'shining', + 'shiny', + 'shivering', + 'shivery', + 'shocked', + 'shocking', + 'shoddy', + 'short', + 'short-lived', + 'shortsighted', + 'short-tempered', + 'short-term', + 'showy', + 'shrewd', + 'shrieking', + 'shrill', + 'shut', + 'shy', + 'sick', + 'sickened', + 'sickening', + 'sickly', + 'side-splitting', + 'signed', + 'significant', + 'silent', + 'silky', + 'silly', + 'silver', + 'silver-tongued', + 'simian', + 'similar', + 'simple', + 'simpleminded', + 'simplified', + 'simplistic', + 'simultaneous', + 'sincere', + 'sinful', + 'single', + 'single-minded', + 'singular', + 'sinister', + 'sinuous', + 'sisterly', + 'six', + 'sixth', + 'sizable', + 'sizzling', + 'skeptical', + 'sketchy', + 'skilled', + 'skillful', + 'skimpy', + 'skin-deep', + 'skinny', + 'skittish', + 'sky-blue', + 'slanderous', + 'slanted', + 'slanting', + 'sleek', + 'sleeping', + 'sleepless', + 'sleepy', + 'slender', + 'slick', + 'slight', + 'slim', + 'slimy', + 'slippery', + 'sloped', + 'sloping', + 'sloppy', + 'slothful', + 'slow', + 'slow-moving', + 'sluggish', + 'slushy', + 'sly', + 'small', + 'smaller', + 'smallest', + 'small-minded', + 'small-scale', + 'small-time', + 'small-town', + 'smarmy', + 'smart', + 'smarter', + 'smartest', + 'smashing', + 'smeared', + 'smelly', + 'smiling', + 'smoggy', + 'smoked', + 'smoky', + 'smooth', + 'smothering', + 'smudged', + 'smug', + 'snapping', + 'snappish', + 'snappy', + 'snarling', + 'sneaky', + 'snide', + 'snippy', + 'snobbish', + 'snoopy', + 'snooty', + 'snoring', + 'snotty', + 'snow-white', + 'snug', + 'snuggly', + 'soaked', + 'soaking', + 'soakingwet', + 'soaring', + 'sober', + 'sociable', + 'social', + 'socialist', + 'sociological', + 'soft', + 'softhearted', + 'soggy', + 'solar', + 'soldierly', + 'sole', + 'solemn', + 'solicitous', + 'solid', + 'solitary', + 'somatic', + 'somber', + 'some,', + 'sonic', + 'sonly', + 'soothed', + 'soothing', + 'sophisticated', + 'sordid', + 'sore', + 'sorrowful', + 'sorry', + 'soulful', + 'soulless', + 'soundless', + 'sour', + 'south', + 'southeasterly', + 'southern', + 'southwestern', + 'spacious', + 'spare', + 'sparing', + 'sparkling', + 'sparkly', + 'sparse', + 'spasmodic', + 'spastic', + 'spatial', + 'spattered', + 'special', + 'specialist', + 'specialized', + 'specific', + 'speckled', + 'spectacular', + 'spectral', + 'speculative', + 'speechless', + 'speedy', + 'spellbinding', + 'spendthrift', + 'spherical', + 'spicy', + 'spiffy', + 'spiky', + 'spinal', + 'spineless', + 'spiral', + 'spiraled', + 'spirited', + 'spiritless', + 'spiritual', + 'spiteful', + 'splashing', + 'splashy', + 'splattered', + 'splendid', + 'splintered', + 'spoiled', + 'spoken', + 'spongy', + 'spontaneous', + 'spooky', + 'sporadic', + 'sporting', + 'sportsmanly', + 'spotless', + 'spotted', + 'spotty', + 'springy', + 'sprite', + 'spry', + 'spurious', + 'squalid', + 'squandered', + 'square', + 'squashed', + 'squashy', + 'squatting', + 'squawking', + 'squealing', + 'squeamish', + 'squeezable', + 'squiggly', + 'squirming', + 'squirrelly', + 'stable', + 'stackable', + 'stacked', + 'staggering', + 'stagnant', + 'stained', + 'stale', + 'stanch', + 'standard', + 'standing', + 'standoffish', + 'starched', + 'star-crossed', + 'stark', + 'startled', + 'startling', + 'starving', + 'stately', + 'static', + 'statistical', + 'statuesque', + 'status', + 'statutory', + 'staunch', + 'steadfast', + 'steady', + 'stealth', + 'steaming', + 'steamy', + 'steel', + 'steely', + 'steep', + 'stereophonic', + 'stereotyped', + 'stereotypical', + 'sterile', + 'stern', + 'sticky', + 'stiff', + 'stifled', + 'stifling', + 'stigmatic', + 'still', + 'stilled', + 'stilted', + 'stimulating', + 'stinging', + 'stingy', + 'stinking', + 'stinky', + 'stirring', + 'stock', + 'stodgy', + 'stoic', + 'stony', + 'stormy', + 'stout', + 'straggly', + 'straight', + 'straightforward', + 'stranded', + 'strange', + 'strategic', + 'streaked', + 'street', + 'strenuous', + 'stressful', + 'stretchy', + 'strict', + 'strident', + 'striking', + 'stringent', + 'striped', + 'strong', + 'stronger', + 'strongest', + 'structural', + 'stubborn', + 'stubby', + 'stuck-up', + 'studied', + 'studious', + 'stuffed', + 'stuffy', + 'stumbling', + 'stunned', + 'stunning', + 'stupendous', + 'sturdy', + 'stuttering', + 'stylish', + 'stylistic', + 'suave', + 'subconscious', + 'subdued', + 'subject', + 'subjective', + 'sublime', + 'subliminal', + 'submissive', + 'subordinate', + 'subsequent', + 'subservient', + 'substantial', + 'substantiated', + 'substitute', + 'subterranean', + 'subtitled', + 'subtle', + 'subversive', + 'successful', + 'successive', + 'succinct', + 'succulent', + 'such', + 'sudden', + 'suffering', + 'sufficient', + 'sugary', + 'suggestive', + 'suitable', + 'sulky', + 'sullen', + 'sumptuous', + 'sunny', + 'super', + 'superabundant', + 'superb', + 'supercilious', + 'superficial', + 'superhuman', + 'superior', + 'superlative', + 'supernatural', + 'supersensitive', + 'supersonic', + 'superstitious', + 'supple', + 'supportive', + 'supposed', + 'suppressive', + 'supreme', + 'sure', + 'sure-footed', + 'surgical', + 'surly', + 'surmountable', + 'surprised', + 'surprising', + 'surrealistic', + 'survivable', + 'susceptible', + 'suspected', + 'suspicious', + 'sustainable', + 'swaggering', + 'swanky', + 'swaying', + 'sweaty', + 'sweeping', + 'sweet', + 'sweltering', + 'swift', + 'swimming', + 'swinish', + 'swishing', + 'swollen', + 'swooping', + 'syllabic', + 'syllogistic', + 'symbiotic', + 'symbolic', + 'symmetrical', + 'sympathetic', + 'symptomatic', + 'synergistic', + 'synonymous', + 'syntactic', + 'synthetic', + 'systematic', + 'taboo', + 'tacit', + 'tacky', + 'tactful', + 'tactical', + 'tactless', + 'tactual', + 'tainted', + 'take-charge', + 'talented', + 'talkative', + 'tall', + 'taller', + 'tallest', + 'tame', + 'tamed', + 'tan', + 'tangential', + 'tangible', + 'tangled', + 'tangy', + 'tanned', + 'tantalizing', + 'tapered', + 'tardy', + 'targeted', + 'tarnished', + 'tart', + 'tasteful', + 'tasteless', + 'tasty', + 'tattered', + 'taunting', + 'taut', + 'taxing', + 'teachable', + 'tearful', + 'tearing', + 'teasing', + 'technical', + 'technological', + 'tectonic', + 'tedious', + 'teenage', + 'teensy', + 'teeny', + 'teeny-tiny', + 'telegraphic', + 'telekinetic', + 'telepathic', + 'telephonic', + 'telescopic', + 'telling', + 'temperamental', + 'temperate', + 'tempestuous', + 'temporary', + 'tempted', + 'tempting', + 'ten', + 'tenable', + 'tenacious', + 'tender', + 'tenderhearted', + 'ten-minute', + 'tense', + 'tentative', + 'tenth', + 'tenuous', + 'tepid', + 'terminal', + 'terrestrial', + 'terrible', + 'terrific', + 'terrified', + 'terrifying', + 'territorial', + 'terse', + 'tested', + 'testy', + 'tetchy', + 'textual', + 'textural', + 'thankful', + 'thankless', + 'that', + 'the', + 'theatrical', + 'their', + 'thematic', + 'theological', + 'theoretical', + 'therapeutic', + 'thermal', + 'these', + 'thick', + 'thievish', + 'thin', + 'thinkable', + 'third', + 'thirsty', + 'this', + 'thorny', + 'thorough', + 'those', + 'thoughtful', + 'thoughtless', + 'thrashed', + 'threatened', + 'threatening', + 'three', + 'thriftless', + 'thrifty', + 'thrilled', + 'thrilling', + 'throbbing', + 'thumping', + 'thundering', + 'thunderous', + 'ticking', + 'tickling', + 'ticklish', + 'tidal', + 'tidy', + 'tight', + 'tightfisted', + 'time', + 'timeless', + 'timely', + 'timid', + 'timorous', + 'tiny', + 'tipsy', + 'tired', + 'tireless', + 'tiresome', + 'tiring', + 'tolerable', + 'tolerant', + 'tonal', + 'tone-deaf', + 'toneless', + 'toothsome', + 'toothy', + 'top', + 'topical', + 'topographical', + 'tormented', + 'torpid', + 'torrential', + 'torrid', + 'torturous', + 'total', + 'touched', + 'touching', + 'touchy', + 'tough', + 'towering', + 'toxic', + 'traditional', + 'tragic', + 'trainable', + 'trained', + 'training', + 'traitorous', + 'tranquil', + 'transcendent', + 'transcendental', + 'transformational', + 'transformative', + 'transformed', + 'transient', + 'transitional', + 'transitory', + 'translucent', + 'transparent', + 'transplanted', + 'trapped', + 'trashed', + 'trashy', + 'traumatic', + 'treacherous', + 'treasonable', + 'treasonous', + 'treasured', + 'treatable', + 'tremendous', + 'tremulous', + 'trenchant', + 'trendy', + 'triangular', + 'tribal', + 'trick', + 'tricky', + 'trim', + 'tripping', + 'trite', + 'triumphant', + 'trivial', + 'tropical', + 'troubled', + 'troublesome', + 'troubling', + 'truculent', + 'true', + 'trusted', + 'trustful', + 'trusting', + 'trustworthy', + 'trusty', + 'truthful', + 'trying', + 'tumultuous', + 'tuneful', + 'tuneless', + 'turbulent', + 'twinkling', + 'twinkly', + 'twisted', + 'twitchy', + 'two', + 'typical', + 'tyrannical', + 'tyrannous', + 'ubiquitous', + 'ugly', + 'ultimate', + 'ultraconservative', + 'ultrasensitive', + 'ultrasonic', + 'ultraviolet', + 'unabashed', + 'unabated', + 'unable', + 'unacceptable', + 'unaccompanied', + 'unaccountable', + 'unaccustomed', + 'unacknowledged', + 'unadorned', + 'unadulterated', + 'unadventurous', + 'unadvised', + 'unaffected', + 'unaffordable', + 'unafraid', + 'unaggressive', + 'unaided', + 'unalienable', + 'unalterable', + 'unaltered', + 'unambiguous', + 'unanimous', + 'unannounced', + 'unanswerable', + 'unanticipated', + 'unapologetic', + 'unappealing', + 'unappetizing', + 'unappreciative', + 'unapproachable', + 'unashamed', + 'unassailable', + 'unassertive', + 'unassisted', + 'unattached', + 'unattainable', + 'unattractive', + 'unauthorized', + 'unavailable', + 'unavailing', + 'unavoidable', + 'unbalanced', + 'unbearable', + 'unbeatable', + 'unbeaten', + 'unbecoming', + 'unbelievable', + 'unbelieving', + 'unbendable', + 'unbending', + 'unbiased', + 'unblemished', + 'unblinking', + 'unblushing', + 'unbounded', + 'unbreakable', + 'unbridled', + 'uncanny', + 'uncaring', + 'unceasing', + 'unceremonious', + 'uncertain', + 'unchangeable', + 'unchanging', + 'uncharacteristic', + 'uncharitable', + 'uncharted', + 'uncivil', + 'uncivilized', + 'unclassified', + 'unclean', + 'uncluttered', + 'uncomely', + 'uncomfortable', + 'uncommitted', + 'uncommon', + 'uncommunicative', + 'uncomplaining', + 'uncomprehending', + 'uncompromising', + 'unconcerned', + 'unconditional', + 'unconfirmed', + 'unconquerable', + 'unconscionable', + 'unconscious', + 'unconstitutional', + 'unconstrained', + 'unconstructive', + 'uncontainable', + 'uncontrollable', + 'unconventional', + 'unconvinced', + 'unconvincing', + 'uncooked', + 'uncooperative', + 'uncoordinated', + 'uncouth', + 'uncovered', + 'uncreative', + 'uncritical', + 'undamaged', + 'undated', + 'undaunted', + 'undeclared', + 'undefeated', + 'undefined', + 'undemocratic', + 'undeniable', + 'undependable', + 'underdeveloped', + 'underfunded', + 'underhanded', + 'underprivileged', + 'understandable', + 'understanding', + 'understated', + 'understood', + 'undeserved', + 'undesirable', + 'undetected', + 'undeterred', + 'undeveloped', + 'undeviating', + 'undifferentiated', + 'undignified', + 'undiminished', + 'undiplomatic', + 'undisciplined', + 'undiscovered', + 'undisguised', + 'undisputed', + 'undistinguished', + 'undivided', + 'undoubted', + 'unearthly', + 'uneasy', + 'uneducated', + 'unemotional', + 'unemployed', + 'unencumbered', + 'unending', + 'unendurable', + 'unenforceable', + 'unenthusiastic', + 'unenviable', + 'unequal', + 'unequaled', + 'unequivocal', + 'unerring', + 'uneven', + 'uneventful', + 'unexceptional', + 'unexcited', + 'unexpected', + 'unexplainable', + 'unexplored', + 'unexpressive', + 'unfailing', + 'unfair', + 'unfaithful', + 'unfaltering', + 'unfamiliar', + 'unfashionable', + 'unfathomable', + 'unfavorable', + 'unfeeling', + 'unfettered', + 'unfilled', + 'unflagging', + 'unflappable', + 'unflattering', + 'unflinching', + 'unfocused', + 'unforeseeable', + 'unforgettable', + 'unforgivable', + 'unforgiving', + 'unfortunate', + 'unfriendly', + 'unfulfilled', + 'ungallant', + 'ungenerous', + 'ungentlemanly', + 'unglamorous', + 'ungraceful', + 'ungracious', + 'ungrateful', + 'unguarded', + 'unhandsome', + 'unhappy', + 'unharmed', + 'unhealthy', + 'unheated', + 'unheeded', + 'unhelpful', + 'unhesitating', + 'unhurried', + 'uniform', + 'unilateral', + 'unimaginable', + 'unimaginative', + 'unimpeachable', + 'unimpeded', + 'unimpressive', + 'unincorporated', + 'uninformed', + 'uninhabitable', + 'uninhibited', + 'uninitiated', + 'uninjured', + 'uninspired', + 'uninsurable', + 'unintelligent', + 'unintelligible', + 'unintended', + 'unintentional', + 'uninterested', + 'uninterrupted', + 'uninvited', + 'unique', + 'united', + 'universal', + 'unjust', + 'unjustifiable', + 'unkempt', + 'unkind', + 'unknowing', + 'unknown', + 'unlawful', + 'unlicensed', + 'unlikable', + 'unlikely', + 'unlivable', + 'unloved', + 'unlucky', + 'unmanageable', + 'unmanly', + 'unmanned', + 'unmarketable', + 'unmasked', + 'unmatched', + 'unmemorable', + 'unmentionable', + 'unmerciful', + 'unmistakable', + 'unmitigated', + 'unmodified', + 'unmotivated', + 'unnatural', + 'unnecessary', + 'unnerved', + 'unnerving', + 'unnoticeable', + 'unobserved', + 'unobtainable', + 'unobtrusive', + 'unofficial', + 'unopened', + 'unopposed', + 'unorthodox', + 'unostentatious', + 'unpalatable', + 'unpardonable', + 'unpersuasive', + 'unperturbed', + 'unplanned', + 'unpleasant', + 'unprecedented', + 'unpredictable', + 'unpretentious', + 'unprincipled', + 'unproductive', + 'unprofessional', + 'unprofitable', + 'unpromising', + 'unpronounceable', + 'unprovoked', + 'unqualified', + 'unquantifiable', + 'unquenchable', + 'unquestionable', + 'unquestioned', + 'unquestioning', + 'unraveled', + 'unreachable', + 'unreadable', + 'unrealistic', + 'unrealized', + 'unreasonable', + 'unreceptive', + 'unrecognizable', + 'unrecognized', + 'unredeemable', + 'unregulated', + 'unrelenting', + 'unreliable', + 'unremarkable', + 'unremitting', + 'unrepentant', + 'unrepresentative', + 'unrepresented', + 'unreserved', + 'unrespectable', + 'unresponsive', + 'unrestrained', + 'unripe', + 'unrivaled', + 'unromantic', + 'unruffled', + 'unruly', + 'unsafe', + 'unsalvageable', + 'unsatisfactory', + 'unsatisfied', + 'unscheduled', + 'unscholarly', + 'unscientific', + 'unscrupulous', + 'unseasonable', + 'unseemly', + 'unselfish', + 'unsettled', + 'unsettling', + 'unshakable', + 'unshapely', + 'unsightly', + 'unsigned', + 'unsinkable', + 'unskilled', + 'unsociable', + 'unsolicited', + 'unsolvable', + 'unsolved', + 'unsophisticated', + 'unsound', + 'unsparing', + 'unspeakable', + 'unspoiled', + 'unstable', + 'unstated', + 'unsteady', + 'unstoppable', + 'unstressed', + 'unstructured', + 'unsubstantial', + 'unsubstantiated', + 'unsuccessful', + 'unsuitable', + 'unsuited', + 'unsupervised', + 'unsupported', + 'unsure', + 'unsurpassable', + 'unsurpassed', + 'unsurprising', + 'unsuspected', + 'unsuspecting', + 'unsustainable', + 'unsympathetic', + 'unsystematic', + 'untainted', + 'untamable', + 'untamed', + 'untapped', + 'untenable', + 'untested', + 'unthinkable', + 'unthinking', + 'untidy', + 'untimely', + 'untitled', + 'untouchable', + 'untraditional', + 'untrained', + 'untried', + 'untroubled', + 'untrustworthy', + 'untruthful', + 'unused', + 'unusual', + 'unverified', + 'unwary', + 'unwashed', + 'unwatchable', + 'unwavering', + 'unwholesome', + 'unwieldy', + 'unwilling', + 'unwise', + 'unwitting', + 'unworkable', + 'unworldly', + 'unworthy', + 'unwritten', + 'unyielding', + 'upbeat', + 'upmost', + 'upper', + 'uppity', + 'upright', + 'uproarious', + 'upset', + 'upsetting', + 'upstairs', + 'uptight', + 'up-to-date', + 'up-to-the-minute', + 'upward', + 'urbane', + 'urgent', + 'usable', + 'used', + 'useful', + 'useless', + 'usual', + 'utilitarian', + 'utopian', + 'utter', + 'uttermost', + 'vacant', + 'vacillating', + 'vacuous', + 'vagabond', + 'vagrant', + 'vague', + 'vain', + 'valiant', + 'valid', + 'valorous', + 'valuable', + 'vanishing', + 'vapid', + 'vaporous', + 'variable', + 'varied', + 'various', + 'varying', + 'vast', + 'vegetable', + 'vegetarian', + 'vegetative', + 'vehement', + 'velvety', + 'venal', + 'venerable', + 'vengeful', + 'venomous', + 'venturesome', + 'venturous', + 'veracious', + 'verbal', + 'verbose', + 'verdant', + 'verifiable', + 'verified', + 'veritable', + 'vernacular', + 'versatile', + 'versed', + 'vertical', + 'very', + 'vexed', + 'vexing', + 'viable', + 'vibrant', + 'vibrating', + 'vicarious', + 'vicious', + 'victorious', + 'vigilant', + 'vigorous', + 'vile', + 'villainous', + 'vindictive', + 'vinegary', + 'violent', + 'violet', + 'viperous', + 'viral', + 'virtual', + 'virtuous', + 'virulent', + 'visceral', + 'viscous', + 'visible', + 'visionary', + 'visual', + 'vital', + 'vitriolic', + 'vivacious', + 'vivid', + 'vocal', + 'vocational', + 'voiceless', + 'volatile', + 'volcanic', + 'voluminous', + 'voluntary', + 'voluptuous', + 'voracious', + 'vulgar', + 'vulnerable', + 'wacky', + 'wailing', + 'waiting', + 'wakeful', + 'wandering', + 'wanting', + 'wanton', + 'warlike', + 'warm', + 'warmest', + 'warning', + 'warring', + 'wary', + 'waspish', + 'waste', + 'wasted', + 'wasteful', + 'watchful', + 'waterlogged', + 'waterproof', + 'watertight', + 'watery', + 'wavering', + 'wax', + 'waxen', + 'weak', + 'weakened', + 'weak-willed', + 'wealthy', + 'wearisome', + 'weary', + 'wee', + 'weedy', + 'week-long', + 'weekly', + 'weightless', + 'weighty', + 'weird', + 'welcoming', + 'well', + 'well-adjusted', + 'well-argued', + 'well-aware', + 'well-balanced', + 'well-behaved', + 'well-built', + 'well-conceived', + 'well-considered', + 'well-crafted', + 'well-deserved', + 'well-developed', + 'well-done', + 'well-dressed', + 'well-educated', + 'well-equipped', + 'well-established', + 'well-founded', + 'well-groomed', + 'well-heeled', + 'well-honed', + 'well-informed', + 'well-intentioned', + 'well-kempt', + 'well-known', + 'well-liked', + 'well-lit', + 'well-made', + 'well-maintained', + 'well-mannered', + 'well-meaning', + 'well-off', + 'well-placed', + 'well-planned', + 'well-prepared', + 'well-qualified', + 'well-read', + 'well-received', + 'well-rounded', + 'well-spoken', + 'well-suited', + 'well-thought-of', + 'well-thought-out', + 'well-to-do', + 'well-traveled', + 'well-used', + 'well-versed', + 'well-worn', + 'well-written', + 'west', + 'western', + 'wet', + 'what', + 'wheezing', + 'which', + 'whimpering', + 'whimsical', + 'whining', + 'whispering', + 'whistling', + 'white', + 'whole', + 'wholehearted', + 'wholesale', + 'wholesome', + 'whooping', + 'whopping', + 'whose', + 'wicked', + 'wide', + 'wide-eyed', + 'wide-ranging', + 'widespread', + 'wiggly', + 'wild', + 'willful', + 'willing', + 'wily', + 'windy', + 'winning', + 'winsome', + 'winter', + 'wintery', + 'wiry', + 'wise', + 'wishful', + 'wispy', + 'wistful', + 'withering', + 'witless', + 'witty', + 'wizardly', + 'wobbly', + 'woeful', + 'wolfish', + 'wonderful', + 'wondrous', + 'wonted', + 'wood', + 'wooden', + 'wooing', + 'wool', + 'woolen', + 'woozy', + 'wordless', + 'wordy', + 'work', + 'workable', + 'working', + 'work-oriented', + 'worldly', + 'worn', + 'worndown', + 'wornout', + 'worried', + 'worrisome', + 'worrying', + 'worse', + 'worshipful', + 'worst', + 'worth', + 'worthless', + 'worthwhile', + 'worthy', + 'wounding', + 'wrathful', + 'wrenching', + 'wretched', + 'wriggling', + 'wriggly', + 'wrinkled', + 'wrinkly', + 'written', + 'wrong', + 'wrongful', + 'wry', + 'yawning', + 'yearly', + 'yearning', + 'yellow', + 'yelping', + 'yielding', + 'young', + 'younger', + 'youngest', + 'youthful', + 'yummy', + 'zany', + 'zealous', + 'zestful', + 'zesty', + 'zippy', + 'zonked', + 'zoological', +]; diff --git a/drizzle-seed/src/datasets/cityNames.ts b/drizzle-seed/src/datasets/cityNames.ts new file mode 100644 index 000000000..780b55213 --- /dev/null +++ b/drizzle-seed/src/datasets/cityNames.ts @@ -0,0 +1,42859 @@ +/** + * The original source for cities names data was taken from https://www.kaggle.com/datasets/juanmah/world-cities + * We've excluded a few countries and their cities from this list because we don't think they should ever appear in any list + */ +export default [ + 'Humpata', + 'Qunghirot', + 'Erdek', + 'Asenovgrad', + 'Payyoli', + 'Pidhorodne', + 'Clawson', + 'Kala Diara', + 'Kadan', + 'Tumut', + 'Bayat', + 'Gangoli', + 'Nuqui', + 'Lochau', + 'Albignasego', + 'Narayanganj', + 'Novo Lino', + 'Regeneracao', + 'Belvedere Marittimo', + 'Santana de Parnaiba', + 'Miyako', + 'Aniche', + 'Andrijevica', + 'Buggenhout', + 'Kurikka', + 'Milanowek', + 'Liaquatpur', + 'Khamaria', + 'Jora Khurd', + 'Petal', + 'Pak Tin Pa', + 'Xiantangcun', + 'Bovingdon', + 'Lianmuqin Kancun', + 'Sainte-Maxime', + 'Campinorte', + 'Vammanal', + 'Yabelo', + 'Wani', + 'Kaita', + 'Monkey Bay', + 'Ianapera', + 'Mariestad', + 'Bukomansimbi', + 'Kavaje', + 'Amahai', + 'Luis Alves', + 'Altmunster', + 'Spring Lake', + 'Niemasson', + 'Douala', + 'Naranjos', + 'Madhubani', + 'Atotonilco el Alto', + 'Palmar de Varela', + 'Hanerik', + 'Wadhraf', + 'Terre Neuve', + 'Libungan', + 'Mattigiri', + 'Prieto Diaz', + 'Barjora', + 'Kagamino', + 'Pakokku', + 'Bol', + 'Prienai', + 'Tan Phong', + 'Kali', + 'Rauenberg', + 'Chios', + 'Jerico', + "Qal'acha", + 'Biwong', + 'Albi', + 'Plantation', + 'Nargund', + 'Yamakita', + 'Ghota Fatehgarh', + 'Vredenburg', + 'Sherman', + 'Penal', + 'Varkaus', + 'Zhongwei', + 'Miri', + 'Guarapuava', + 'Bolszewo', + 'Park Forest Village', + 'Cianjur', + 'Kempsey', + 'Guaraci', + 'Odorheiu Secuiesc', + 'Alytus', + 'Mulanje', + 'Evinayong', + 'Bukkapatnam', + 'Berd', + 'Kisaran', + 'Bitung', + 'Selcuk', + 'Xikeng', + 'Cantanhede', + 'Pasuquin', + 'Steinheim am der Murr', + 'Mahem', + 'Gloria', + 'Benbrook', + 'Beforona', + 'Borken', + 'Ouled Rahmoun', + 'Pedras de Maria da Cruz', + 'Al Fuhays', + 'Titiribi', + 'Kien Luong', + 'Shediac', + 'Villasanta', + 'Guelph', + 'Duzkoy', + 'Narkher', + 'Tateyama', + 'Penzance', + 'Pasay City', + 'San Lucas Sacatepequez', + 'Skardu', + 'Maharajapuram', + 'Al `Asharah', + 'Tanant', + 'Kawaguchi', + 'Madhuban Bediban', + 'Bridge City', + 'Greenbelt', + 'Iara', + 'Baton Rouge', + 'Yopal', + 'Moribila', + 'Ciudad-Rodrigo', + 'Madira', + 'Bobonong', + 'Fort Hood', + 'Amboasary', + 'Sostanj', + 'Fnidq', + 'Vikasnagar', + 'Yangping', + 'Arraias', + 'Goslar', + 'Shuixi', + 'Lagoa da Canoa', + 'Baiersbronn', + 'Forest', + 'Sedavi', + 'Kosonsoy', + 'Trelleborg', + 'Bucheya', + 'Kidricevo', + 'Gokulgarh', + 'Coswig', + 'Marechal Taumaturgo', + 'Sidi Akkacha', + 'Kouarfa', + 'Finspang', + 'Timberlane', + 'Colotenango', + 'Puerto Ayora', + 'Goytapa', + 'Tarlapalli', + 'Acandi', + 'General Luna', + 'Calamba', + 'Miqiao', + 'Linxia Chengguanzhen', + 'Nizamabad', + 'Doria Sonapur', + 'Chongoroi', + 'Oskaloosa', + 'Prevalje', + 'Lubang', + 'Ladispoli', + 'Coite do Noia', + 'Sarjapur', + 'Panuco', + 'Jendouba', + 'Nayakanhatti', + "'Ain Mouilah", + 'Chapeco', + 'Stanton', + 'Balve', + 'Libante', + 'Etah', + 'Yarim', + 'Litchfield Beach', + 'Tsingoni', + 'Kendall Park', + 'Karkala', + 'Vlaardingen', + 'Torrente', + 'Periyanegamam', + 'Senhor do Bonfim', + 'Fleet', + 'Geita', + 'Chettipalaiyam', + 'New Washington', + 'Vlore', + 'San Juan Ermita', + 'Lagonglong', + 'Shwebo', + 'Hattiesburg', + 'Mering', + 'Basibasy', + 'Sarahs', + 'Nadendla', + 'Palaiyam', + 'Porto de Pedras', + 'Porto Novo', + 'Westampton', + 'Oriximina', + 'Al Jaghbub', + 'Hajjah', + 'Cutler Bay', + 'Toyokawa', + 'Tehuipango', + 'Catabola', + 'Ivanic-Grad', + 'Caudete', + 'Del Rio', + 'Clarence-Rockland', + 'Morrisville', + 'Divisopolis', + 'Chigasaki', + 'West Auckland', + 'Suzu', + 'Blythe', + 'Khunti', + 'Putussibau', + 'Ourikela', + 'Ambano', + 'Calpe', + 'Ambohitralanana', + 'Longjin', + 'Sao Filipe', + 'San Jose de Gracia', + 'Bura', + 'Ziarat', + 'Termoli', + 'Vohindava', + 'Xinbu', + 'Biliaivka', + 'Sahneh', + 'Rutherglen', + 'Naolinco de Victoria', + 'Windlesham', + 'Manchester', + 'Orinda', + 'South Yarmouth', + 'Tabaco', + 'Kayseri', + 'Ibiapina', + 'Murcia', + 'Swieqi', + 'Valencia', + 'Chirala', + 'Eloxochitlan', + 'Dembeni', + 'Fardis', + 'Misaki', + 'Nagar', + 'Miyajima', + 'Brikama', + 'Umurlu', + 'Brierley Hill', + 'Khodabandeh', + 'Ozgon', + 'Reze', + 'Tinajeros', + 'Novomyrhorod', + 'Fully', + 'Biak', + 'Colider', + 'Kashiwara', + 'Sjenica', + 'Hednesford', + 'Madukkarai', + 'Villaflores', + 'Chiautla de Tapia', + 'Taormina', + 'Huwei', + 'Seiyo', + 'Washim', + 'Benton', + 'Venturina', + 'Kakalur', + 'Andamooka', + 'Anghad', + 'West Hempfield', + 'Turnhout', + 'Markkleeberg', + 'Poko', + 'Wealdstone', + 'Ban Na Pa', + 'Cerklje na Gorenjskem', + 'Bombon', + 'Arimalam', + 'Jangy-Kyshtak', + 'Isny im Allgau', + 'Braga', + 'Kawadgaon', + 'Bonate di Sopra', + 'Tonneins', + 'Munagala', + 'Chinna Mushidivada', + 'Talagutong', + 'Neihuzhai', + 'Agua de Dios', + 'Herceg Novi', + "Nerk'in Getashen", + 'Botucatu', + 'Arroio do Meio', + 'Villafranca del Panades', + 'Madikeri', + 'Serik', + 'San Sebastian Huehuetenango', + 'Kyzyl-Adyr', + 'Somarasampettai', + 'Surmene', + 'Turbana', + 'Chilas', + 'Marinette', + 'The Hammocks', + 'McPherson', + 'General MacArthur', + 'Strasbourg', + 'Tibana', + 'Polatli', + 'Sur', + 'Lye', + 'West Carson', + 'Uludere', + 'Moroni', + 'Mata de Sao Joao', + 'Pachmir', + 'Saskatoon', + 'Nina Rodrigues', + 'Chinnakkavundanur', + 'Norton Shores', + 'Abu', + 'Santo Angelo', + 'Pianezza', + 'Wythenshawe', + 'Mabeskraal', + 'Fort Drum', + 'Gobindpur', + 'Kostopil', + 'Calca', + 'Nonkon', + 'Kolno', + 'Tati', + 'Glastonbury', + 'Itakura', + 'Payyanadam', + 'Puerto Caimito', + 'Thionville', + 'Wezep', + 'Llandudno', + 'Antequera', + 'Camp Perrin', + 'Sao Luis do Paraitinga', + 'Kabatas', + 'Volta Redonda', + 'Beni Mered', + 'Kaffrine', + 'Reutlingen', + 'Fort Morgan', + 'Naucalpan de Juarez', + 'Ebo', + 'Dargaz', + 'Vina del Mar', + 'Ilam', + 'Kyzyl-Suu', + 'Perinton', + 'Nenmini', + 'La Mirada', + 'Sumbe', + 'Jicin', + 'Indian Trail', + 'Nova Bassano', + 'Batam Centre', + 'Tocache Nuevo', + 'Tambaram', + 'Kikugawa', + 'Sari', + 'Borca', + 'Beja', + 'Feltre', + 'Godo', + 'Oshawa', + 'German Flatts', + 'Schaffhausen', + 'Albino', + 'Wejherowo', + 'Plav', + 'Beccar', + 'Pitsea', + 'Lauro de Freitas', + 'Gogrial', + 'Ferros', + 'Tipp City', + 'Waynesboro', + 'Khost', + 'Golungo Alto', + 'Tamesis', + 'Almondbury', + 'Bernardo de Irigoyen', + 'Vairampatti', + 'Neiafu', + 'Everswinkel', + 'Garden Acres', + 'Yufu', + 'Coxim', + 'Dilra', + 'Guwahati', + 'Tan Phu', + "Khairpur Mir's", + 'Poza Rica de Hidalgo', + 'Trancoso', + 'Koytendag', + 'At Tafilah', + 'Ranohira', + 'Legionowo', + 'Romitan Shahri', + 'The Villages', + 'Carroll', + 'Mogi Mirim', + 'Mo i Rana', + 'San Miguel Duenas', + 'Dardoq', + 'Abaetetuba', + 'New Milford', + 'Palda', + 'Tsinjomitondraka', + 'Pisz', + 'Otaru', + 'Caldas Novas', + 'Pampanito', + 'Panuco de Coronado', + 'Lanyi', + 'Mayoyao', + 'Tlagasana', + 'Chetouane', + 'Grand-Popo', + 'Nagaoki', + 'Chong Nonsi', + 'Emmiganur', + 'Looc', + 'Vila Muriqui', + 'Frattamaggiore', + 'Ormoz', + 'Goynucek', + 'Arles', + 'Laungowal', + 'Jalhay', + 'Wan Tau Tong', + 'Villa Angela', + 'Mariyammanahalli', + 'Pivka', + 'Firmat', + 'Patsanda', + 'Colle Salvetti', + 'Gyula', + 'Valparai', + 'Issaquah', + 'Jeronimo Monteiro', + 'Bugasong', + 'Broxbourne', + 'Tsundupalle', + 'Jacupiranga', + 'San Juan Ixcoy', + 'Ambatomirahavavy', + 'Lanco', + 'Monsenhor Gil', + 'Sabaa Aiyoun', + 'Narnaul', + 'Carutapera', + 'Altay', + 'Ambodiampana', + 'Kouvola', + 'Harahan', + 'Paoskoto', + 'Vargem Grande Paulista', + 'Schwarzenbruck', + 'Bellheim', + 'Oak Ridge', + 'Chimaltenango', + 'Issaba', + 'Tiri', + 'Taroudannt', + 'Nonahi', + 'Ranquitte', + 'Tala Yfassene', + 'Meybod', + 'Muchamiel', + 'Antohobe', + 'Axochiapan', + 'Malakanagiri', + 'Whitchurch', + 'Lake in the Hills', + 'San Mateo del Mar', + 'Curuzu Cuatia', + 'Schweizer-Reineke', + 'Babusnica', + 'Montgomeryville', + 'Gundugolanu', + 'Abi al Khasib', + 'Pillanallur', + 'Soulei', + 'Ayas', + 'Azuqueca de Henares', + 'Chodov', + 'Mingjiujie', + 'Patar', + 'Porto Murtinho', + 'Jafra', + 'El Progreso', + 'Rulin', + 'Penetanguishene', + 'Ban Khek Noi', + 'Tubao', + 'Calw', + 'Gaundra', + 'Nasik', + 'Gaolingcun', + 'Kalol', + 'Meadowbrook', + 'Kidapawan', + 'Rudsar', + 'Maddaloni', + 'Kabul', + 'Karlskoga', + 'Yazd', + 'Podalakur', + 'Asakura', + 'Teranikallu', + 'Keokuk', + 'Uyuni', + 'Yorosso', + 'Pfaffikon', + 'Arniquet', + 'Kyzyl-Kyshtak', + 'Kambur', + 'Mburucuya', + 'Mingacevir', + 'Zvolen', + 'Cabaceiras do Paraguacu', + 'Tamworth', + 'Guantanamo', + 'Darregueira', + 'Ezequiel Montes', + 'Fomboni', + 'Quintanar de la Orden', + 'Siachoque', + 'Kericho', + 'Mineral de Angangueo', + 'Peka', + 'Fenglin', + 'Quetzaltenango', + 'Sevanagala', + 'Port Pirie', + 'Tengyue', + 'Novoyavorovskoye', + 'Forli', + 'Suchitoto', + 'Hosdurga', + 'Arcoverde', + 'Vale de Cambra', + 'San Pablo Atlazalpan', + 'Hockenheim', + 'Dandu Mailaram', + 'Tadjmout', + 'Port of Spain', + 'Nanaimo', + 'Colonia del Sol', + 'Primeiro de Maio', + 'Valletta', + 'Horishni Plavni', + 'Kingswood', + 'Furstenwalde', + 'Grosse Pointe Farms', + 'Bang Kruai', + 'Haiger', + 'Chansolme', + 'Xiaoganzhan', + 'Mulaikkaraippatti', + 'Nandazhang', + 'Hambuhren', + 'Medellin', + 'Canapolis', + 'Corozal', + 'Bignona', + 'Nova Vodolaha', + 'Shedbal', + 'Maojiatang', + 'Greentree', + 'Mahayag', + 'Rajendranagar', + 'Guararema', + 'Pirane', + 'Tall Dhahab', + 'Sipoo', + 'Aiquile', + 'Kish', + 'Taltal', + 'Kushmanchi', + 'Santa Genoveva de Docordo', + 'Tapiales', + 'Yunak', + 'Floirac', + 'Parbata', + 'Zhangzhengqiao', + 'Zossen', + 'Caselle Torinese', + 'Zaliohouan', + 'Waldkirchen', + 'Sao Jose da Coroa Grande', + 'Pasinler', + 'Gaspe', + 'Soubakaniedougou', + 'Nabire', + 'Sieyik', + 'Sao Jose de Piranhas', + 'Gioia del Colle', + 'Villanueva de Arosa', + 'Marihatag', + 'Daugavpils', + 'Saint Helens', + 'Jiannan', + 'Gross Kreutz', + 'Ganapathivattam', + 'Santiago de Cuba', + 'Katanning', + 'Marotolana', + 'Dingzhou', + 'Spoleto', + 'San Agustin Chahal', + 'Calheta de Sao Miguel', + 'Aragua de Barcelona', + 'Vammala', + 'Sao Goncalo do Amarante', + 'Shahba', + 'Cornedo Vicentino', + 'Kew Green', + 'Kuzuculu', + 'Tobati', + 'Currais Novos', + 'Mounds View', + 'Wetzlar', + 'Nesoddtangen', + 'Bosilovo', + 'Marolambo', + 'Horodyshche', + 'Aleksandrow Kujawski', + 'Sao Jose do Cedro', + 'Dhabauli', + 'Macka', + 'Oelsnitz', + 'Kiambu', + 'Mugutkhan Hubli', + 'Jalkaura', + "Bo'ao", + 'Emmiganuru', + 'Manglur', + 'Shenmu', + 'Kerch', + 'Paluan', + 'Jaguaribe', + 'Palmeira dos Indios', + 'Zorgo', + 'Chagne', + 'Ugrinovci', + 'Feuchtwangen', + 'Mitake', + 'Pacora', + "Rui'an", + 'West Hanover', + 'Buca', + 'Sam Son', + 'Matsuyama', + 'Gouka', + 'Tuchin', + 'Tonantins', + 'Narangba', + 'Inami', + 'Wolf Trap', + 'Kumharsan', + 'Gundi', + 'Rubiera', + 'Balia', + 'Estarreja', + 'Golkoy', + 'Nordestina', + 'Dattapulia', + 'Wapienica', + 'Unao', + 'Vasterhaninge', + 'Wenxian Chengguanzhen', + 'Hanover Park', + 'Urrugne', + 'San Antonio Ilotenango', + 'San Vicente dels Horts', + "Sao Miguel d'Oeste", + 'Caerfyrddin', + 'Sidi Rahhal', + 'Olongapo', + 'Jasol', + 'Castelnuovo Rangone', + 'Don Benito', + 'Thung Song', + 'Zhanibek', + 'Male', + 'Anpachi', + 'Buford', + 'Kwekwe', + 'Urmston', + 'Fernan-Nunez', + 'Rio das Ostras', + 'Zhmerynka', + 'Shahrud', + 'Las Lomitas', + 'Curuca', + 'Ar Ramadi', + 'Jamundi', + 'Skalica', + 'Taixing', + 'Huron', + 'Basse-Goulaine', + 'Arteche', + 'Roxbury', + 'Nawnghkio', + 'Terryville', + 'Eastlake', + 'Guarabira', + 'Zionsville', + 'Yala', + 'Os', + 'Tuquerres', + 'Zlatograd', + 'Harnai', + 'Cherukara', + 'Numancia', + 'Negotino', + 'Sparta', + 'Buzen', + 'Karuvelampatti', + 'Monte San Pietro', + 'Rosario do Catete', + 'Thamaga', + 'Johnstown', + 'Manaira', + 'Zabrat', + 'Tebourba', + 'Cornelius', + 'Al Mu`addamiyah', + 'Epinal', + 'Haria', + 'Surrey', + 'Tarapoto', + 'Morecambe', + 'Maribojoc', + 'Savda', + 'Calbiga', + 'Ayodhyapattanam', + 'Dulmen', + 'Porteirinha', + 'Armstrong', + 'Darton', + 'Poco Redondo', + 'Yoboki', + 'Maevka', + 'Pihra', + 'Nong Khae', + 'Mascoutah', + 'Ukrainka', + 'Ivrea', + 'Vadavalam', + 'Huaraz', + 'Gjakove', + 'Penablanca', + 'Lishuping', + 'Kiso', + 'Guaranda', + 'Palliman', + 'Rawtenstall', + 'Atchampeta', + 'Tarazona de Aragon', + 'Vincent', + 'Longtang', + 'Muragacha', + 'Gwadar', + 'Aguilas', + 'Karttigappalli', + 'Rahway', + 'Churi', + 'Leini', + 'Ragan Sur', + 'Hongliuwan', + 'Bayang', + 'Plattsburgh', + 'Anagni', + 'Gidan Ider', + 'Ait Bouchta', + 'Sidi Abdelkader', + 'Salaverry', + "Ma'erkang", + 'Niena', + 'Santamaguluru', + 'Buxtehude', + 'Ugep', + 'Zelezniki', + 'Emmendingen', + 'Monforte de Lemos', + 'Tourza', + 'Rivalta di Torino', + 'Orange Cove', + 'Bijbiara', + 'Jardim do Serido', + 'Kajaani', + 'Barros Cassal', + 'Shengang', + 'Candido de Abreu', + 'Ashdod', + 'Bhit Bhagwanpur', + 'Sajoszentpeter', + 'Ambolotarakely', + 'Viota', + 'Muskegon', + 'Hanau', + 'Madhupur', + 'Popesti-Leordeni', + 'Coyhaique', + 'Hojai', + 'Nehe', + 'Maddagiri', + 'Bodrum', + 'Mountain View', + 'Tash-Komur', + 'Cili', + 'Kristianstad', + 'Pehuajo', + 'Jam', + 'Frederickson', + 'Aywaille', + 'Heule', + 'Kasungu', + 'Koge', + 'Mukdahan', + 'Dialakoroba', + 'Les Sorinieres', + 'Al Kiswah', + 'Dongxiaozhai', + 'Mirandela', + 'Mochizuki', + 'Hanumantanpatti', + 'Bregenz', + 'Kongjiazhuangcun', + 'Xianxi', + 'Kovin', + 'Konan', + 'La Serena', + 'Menomonie', + 'Zemmouri', + 'Nakagusuku', + 'Gharbara', + 'Oro-Medonte', + 'Qiloane', + 'Larantuka', + 'Nonoai', + 'Silvarpatti', + 'Kharagbani', + 'Nghia Lo', + 'Kissimmee', + 'Higuey', + 'Susques', + 'Pyalakurti', + 'Sleaford', + 'Barranco de Loba', + 'Rattihalli', + 'Standish', + 'Holyoke', + 'Nettadahalli', + 'Torrejon de la Calzada', + 'Nidzica', + 'Sovata', + 'Ilha Solteira', + 'Rampur Khajuriya', + 'Pappinissheri', + 'Sint Willebrord', + 'Benito Soliven', + "Sek'ot'a", + 'Jhang City', + 'Vadakkanandal', + 'Kolo', + 'Montecorvino Rovella', + 'Mancio Lima', + 'Kashkar-Kyshtak', + 'Mohania', + 'Kochgawan', + 'Honiara', + 'Brejoes', + 'Krasnyy Yar', + 'Otrokovice', + 'Saidpur', + 'Nainijor', + 'Jhanjharpur', + 'Yarm', + 'Caransebes', + 'Santa Teresa del Tuy', + 'Banate', + 'Altadena', + 'Sihu', + 'Velten', + 'San Pablo', + 'Chbar Mon', + 'Baraderes', + 'Baraon', + 'Telsang', + 'Saint Budeaux', + 'Candelaria', + 'Silva Jardim', + 'Udburu', + 'Mastic', + 'Itapora', + 'Iklin', + 'Vlasotince', + 'Svay Pak', + 'Havelock North', + 'Kalipatnam', + 'Mozarlandia', + 'Kamarhati', + 'Strehaia', + 'Joshimath', + 'Bridgnorth', + 'Batticaloa', + 'Pallisa', + 'Coronel Dorrego', + 'Chelmek', + 'Hinthada', + 'Nola', + 'Little Rock', + 'New Braunfels', + 'Havre', + 'Lavezares', + 'Lamphun', + 'Karajgi', + 'Maheshram', + 'Rangasamudram', + 'Cuango', + 'Tonse East', + 'Morlanwelz-Mariemont', + 'Otavalo', + 'Nerkunram', + 'Jaque', + 'Okha', + 'Bhamo', + 'Gadabay', + 'Timbauba', + 'Andapafito', + 'Punta Umbria', + 'Vanj', + 'Kun Puhal', + 'Timmendorfer Strand', + 'Pau dos Ferros', + 'Matsuzaka', + 'Columbus', + 'Putina', + 'Kotdwara', + 'Tagana-an', + 'Ajdovscina', + 'Siegen', + 'Sangin', + 'Bihpuriagaon', + 'Biswanath Chariali', + 'Chiva', + 'Paszto', + 'Ban Wang Daeng', + 'Karlsfeld', + 'El Alamo', + 'Lelystad', + 'Chand Chaur', + 'Nioaque', + 'Yargatti', + 'Hilzingen', + 'Ayvacik', + 'Suceava', + 'Padova', + 'Carneys Point', + 'Winkfield', + 'Absecon', + 'Guntakal Junction', + 'Bhadwar', + 'Iwaka', + 'San Pedro de Lloc', + 'Key Largo', + 'Monterotondo', + 'Al Hillah', + 'Zaouia Ait Ishak', + 'Floriana', + 'Ubajara', + 'Ouled Fayet', + 'Novo Cruzeiro', + 'Selwyn', + 'Phitsanulok', + 'Amarzgane', + 'Punakha', + 'Liperi', + 'Biblis', + 'Pavlodar', + 'Salalah', + 'Tysvaer', + 'Yapqan', + 'Vetapalem', + 'Baisari', + 'Boryeong', + 'Dhanauli', + 'Atenco', + 'Little Chute', + 'Mimasaka', + 'Champapur', + 'Itamonte', + 'Marple', + 'El Callao', + 'Whanganui', + 'Korschenbroich', + 'Zhuqi', + 'Asfarvarin', + 'Kodayattur', + 'Yozyovon', + 'Thompson', + 'Wingles', + 'Karliova', + 'Radyvyliv', + 'Mollendo', + 'Jagdalpur', + 'Nandgaon', + 'Toyono', + 'Gryfino', + 'Ventspils', + 'Sibiti', + 'Shishi', + 'Lulhaul', + 'Bhalpatti', + 'Norman', + 'Halesowen', + 'Al Midhnab', + 'Viroflay', + 'Nether Providence', + 'Anglet', + 'Seven Corners', + 'Kurort Steinbach-Hallenberg', + 'Eden Prairie', + 'Firestone', + 'Shanywathit', + 'North Wantagh', + 'Grenzach-Wyhlen', + 'Chiari', + 'Keningau', + 'Miranda do Corvo', + 'Tenambakkam', + 'Tilburg', + 'Budipuram', + 'Nallamada', + 'San Giovanni la Punta', + 'Middle', + 'Nanzhai', + 'Castelfiorentino', + 'Mont-Royal', + 'Khasbalanda', + 'Zirara', + 'Carluke', + 'Kawatana', + 'Idangansalai', + 'Mandi', + 'Sabanitas', + 'Balangir', + 'Phillipsburg', + 'Poniatowa', + 'Jizzax', + 'Corumbaiba', + 'Sampues', + 'Muynoq', + 'Valga', + 'Daharia', + 'Mundakkal', + 'Qarqin', + 'Gandu', + 'Los Vilos', + 'Arkonam', + 'Kananya', + 'South Middleton', + 'Devsar', + 'Kamin-Kashyrskyi', + 'Hauterive', + 'Raitar', + 'Swords', + 'Elche', + 'Shakhtinsk', + 'Meadow Woods', + 'Kadiapattanam', + 'Sherrelwood', + 'Altamura', + 'Bloomingdale', + 'Hesperia', + 'Marathon', + 'Sogndal', + 'Timberlake', + 'Upper Gwynedd', + 'Saint-Andre-de-Cubzac', + 'Chelmsford', + 'Udaipur Bithwar', + 'Provins', + 'Prievidza', + 'Loiyo', + 'Dabou', + 'Kastav', + 'Vellarivalli', + 'Orchards', + 'Summerfield', + 'Ilidza', + 'Badiadka', + 'Ypsilanti', + 'Warsaw', + 'Randers', + 'Aqtobe', + 'Rosendael', + 'New Paltz', + 'Port Neches', + 'Cranford', + 'Hadamar', + 'Bergenfield', + 'Orland Park', + 'Ba Chuc', + 'Fomento', + 'Tegueste', + 'Omagh', + 'Maria Pinto', + 'Ban Suan', + 'Cuernavaca', + 'Leominster', + 'Eidsvold', + 'Sohtha', + 'Todi', + 'Choszczno', + 'Yamato', + 'Lengquancun', + 'Sultanpur Mazra', + 'Boumalne', + 'Manises', + 'Xiaoli', + 'Zolochiv', + 'Pyapon', + 'Lake Ronkonkoma', + 'Hasselt', + 'El Minie', + 'Ambinanindovoka', + 'Trittau', + 'Mulavur', + 'Loyish Shaharchasi', + 'Bembereke', + 'Antratsyt', + 'Sayalkudi', + 'Chorrocho', + 'Ipiau', + 'Pembroke Pines', + 'Palghar', + 'Frodsham', + 'Sullana', + 'Sunamganj', + 'Finike', + 'Qiryat Mozqin', + 'Correia Pinto', + 'Macheng', + 'Ban Du', + 'Agde', + 'Santa Quiteria', + 'Voyenno-Antonovka', + 'Kapellen', + 'An Chau', + 'Valera', + 'Glen Parva', + 'Mahikeng', + 'Gland', + 'Northallerton', + 'Su-ngai Kolok', + 'Ash Shaykhan', + 'Roztoky', + 'Kokomo', + 'Duren', + 'Iver', + 'Campanha', + 'Befody', + 'Vaisampakkal', + 'Ucar', + 'Janesville', + 'Aksehir', + 'Buur Gaabo', + 'Ouled Fares', + 'Eseka', + 'Cossimbazar', + 'Abingdon', + 'Andrychow', + 'Calimesa', + 'Manati', + 'Hannoversch Munden', + 'Nalakadoddi', + 'Xiaoba', + 'Suo-Oshima', + 'Beaver Dam', + 'Oulad Ouchchih', + 'Analavory', + 'Lopez Jaena', + 'Midland', + 'Zhongbu', + 'Tarrytown', + 'Brighton', + 'Vannes', + 'Rajgir', + 'Kuppam', + 'Kottakota', + 'Onesti', + 'Massa', + 'Sebastian', + 'Benahavis', + 'Gigmoto', + 'Probolinggo', + 'Valkenswaard', + 'Momostenango', + 'Det Udom', + 'Myrza-Ake', + 'Bou Saada', + 'Maur Kalan', + 'Cholargos', + 'Senglea', + 'Baranzate', + 'Point Fortin', + 'Wutiancun', + 'South Whittier', + 'Tiran', + 'Fitchburg', + 'Eyvan', + 'Burbaliq', + 'Heanor', + 'Rancharia', + 'Karumattampatti', + 'Piagapo', + 'Rishivandiyam', + 'Amposta', + 'Tultepec', + 'Cabaret', + 'Cloquet', + 'Plouzane', + 'Wilnecote', + 'Presidente Epitacio', + 'Mossaka', + 'Piano di Sorrento', + 'Colomiers', + 'Kaithal', + 'Cotoca', + 'Kofele', + 'Nangong', + 'Yhu', + 'Chepo', + 'Kyoto', + 'Sorocaba', + 'Phagwara', + 'Ludenscheid', + 'Guotang', + 'Vayakkalattu', + 'Mianeh', + 'Closepet', + 'Kronshagen', + 'Unye', + 'Vale de Cavalos', + 'Zitorada', + 'Ramnicu Valcea', + 'Samastipur', + 'West Hempstead', + 'Saunshi', + 'Atamyrat', + 'Morfelden-Walldorf', + 'Okahandja', + 'Shaoyu', + 'Mirpur Mathelo', + 'Odendaalsrus', + 'Jisrayn', + 'Elankur', + 'Facatativa', + 'Leshan', + 'Halle', + 'Paharpur', + 'Dialafara', + 'Villeneuve-Loubet', + 'Regidor', + 'Pukkulam', + 'Torre Boldone', + 'Tirukkalikkunram', + 'Xihuangcun', + 'Artemida', + 'Lorrach', + 'Governador Valadares', + 'Virton', + 'Xochiatipan de Castillo', + 'Ehingen an der Donau', + 'Carlosama', + 'Zarzal', + 'Terni', + 'Tomaszow Mazowiecki', + 'Villa Union', + 'North Lakes', + 'Lospalos', + 'Wuhan', + 'La Puebla del Rio', + 'Caraga', + 'Drolshagen', + 'Mahad', + 'Charleville', + 'Dhorimanna', + 'Hakodate', + 'Soumagne', + 'Magra', + 'Chulumani', + 'Alloa', + 'Montegranaro', + 'Singhara Buzurg', + 'Errahalli', + 'Sakleshpur', + 'Serris', + 'Zell am See', + 'Danbury', + 'Yoshioka', + 'Eruh', + 'Kinshasa', + 'Mellieha', + 'Ibadan', + 'Filottrano', + 'Dongjiangshui', + 'Mariehamn', + 'Mbalmayo', + 'Cobija', + 'Cairo', + 'Jatara', + 'Famalicao', + 'Bayonet Point', + 'Trang Bang', + 'Fandriana', + 'Copceac', + 'Nhamunda', + 'Sriperumbudur', + 'Kitamoto', + 'Le Grand-Quevilly', + 'Higuera de Zaragoza', + 'Sa Dec', + 'Plougastel-Daoulas', + 'IJsselstein', + 'Rivoli', + 'Neu Bleckede', + 'Am-Timan', + 'Jobabo', + 'Lerik', + 'Chaiyo', + 'Bergen op Zoom', + 'Niederzier', + 'Sesimbra', + 'Jagta', + 'Levis', + "Stara L'ubovna", + 'Horbury', + 'Bialy Kamien', + 'Alamo', + 'Palaio Faliro', + 'Roselle Park', + 'Rudewa', + 'Kotma', + 'Cojedes', + 'Guangming', + 'Shanwei', + 'Vanimo', + 'Alesd', + 'Sidmouth', + 'Hamah', + 'Alejandro Korn', + 'Emsworth', + 'Shenjiabang', + 'Calatayud', + 'Furano', + 'Moca', + 'Viraghattam', + 'Farshut', + 'Nachod', + 'Patzun', + 'Southborough', + 'Hopetown', + 'Regina', + 'Estavayer-le-Lac', + 'Castellammare di Stabia', + 'Marabut', + 'Wegrow', + 'Moncton', + 'Pochuta', + 'Yumbe', + 'Raynes Park', + 'Kaiserslautern', + 'Ixtahuacan', + 'Montemor-o-Novo', + 'Palanisettipatti', + 'Baaqline', + 'Pen-y-Bont ar Ogwr', + 'Altinekin', + 'Villaba', + 'Cudahy', + 'Pazhanji', + 'Icononzo', + 'Yaozhuangcun', + 'Sanson', + 'Mol', + 'Lejiangxiang', + 'Prien am Chiemsee', + 'Heerde', + 'Nabatiye', + 'Dobre Miasto', + 'Franklin', + 'Ban Khi Lek', + 'Calumpang', + 'Levelland', + 'San Jose de Bocay', + 'Xichang', + 'Uravakonda', + 'Madinat Zayid', + 'Udayagiri', + "Jeppe's Reef", + "Nek'emte", + 'Fajardo', + 'Ratodero', + 'South Elgin', + 'Gogogogo', + 'Awjilah', + 'Kantharalak', + 'La Trinidad', + 'Nakanoto', + 'Paamiut', + 'Augustdorf', + 'Ferizli', + 'Belauncha', + 'Elurupadu', + 'Abuna', + 'Kuantan', + 'Casimiro de Abreu', + 'Battle Creek', + 'Ohara', + 'Knottingley', + 'Varzedo', + 'Ouled Slama Tahta', + 'Sorrento', + 'Lalmatie', + 'Hemavati', + 'Lewisboro', + 'Gary', + 'Hartbeespoort', + 'Piriyapatna', + 'Fulacunda', + 'Coatzacoalcos', + 'Puliyara', + 'Busca', + 'Jamkhed', + 'Targu Lapus', + "Ra's al Ma`arrah", + 'Nakhtarana', + 'Monte Plata', + 'Gravenhurst', + 'Jingcheng', + 'Starnberg', + 'Sa al Hajar', + 'Whitehouse', + 'Batatais', + 'Ciempozuelos', + 'Bingmei', + 'Divinopolis', + 'Como', + 'Sirgora', + 'Ban Bang Yai', + 'Tejucuoca', + 'Soavina Antanety', + 'Grapevine', + 'Waseca', + 'Sindelfingen', + 'Ulhasnagar', + 'Tulcan', + 'Ararica', + 'Camoapa', + 'Zoubiria', + 'Dour', + 'Terku Narippaiyur', + 'Llagostera', + 'Qo`rg`ontepa', + 'San Rafael La Independencia', + 'Sandino', + 'Dasoguz', + 'Bankra', + 'Mauguio', + 'Viagrande', + 'Bay Village', + 'Galivedu', + 'Oulad Fares', + 'Patapatnam', + 'Swinoujscie', + 'Dharmkot', + 'Recklinghausen', + 'General Viamonte', + 'Cyangugu', + 'Monteux', + 'Ozalp', + 'Quintero', + 'Baocheng', + 'Marhaura', + 'La Solana', + 'Simpang Renggam', + 'Bad Durkheim', + 'Sao Bento do Sapucai', + 'Mitzic', + 'Etajima', + 'Volos', + 'Hailey', + 'Weinsberg', + 'Dahi', + 'Braselton', + 'Miro Khan', + 'Qujingpu', + 'Ince-in-Makerfield', + 'Spanish Springs', + 'Montanhas', + 'Presevo', + 'San Carlos Centro', + 'Nandnawan', + 'Nowy Sacz', + 'View Royal', + 'West Rembo', + 'Paragould', + 'Tortoli', + 'Guapiacu', + 'Gijon', + 'Ilesa', + 'Tongjiang', + 'Belakvadi', + 'Santa Sylvina', + 'Adelfia', + 'Mandya', + 'Bay City', + 'Rosny-sous-Bois', + 'Angono', + 'Uzhhorod', + 'Ap Phu Hai', + 'Bembe', + 'Palma di Montechiaro', + 'Shanhe', + 'Oued el Djemaa', + 'Atturkuppam', + 'Adwa', + 'Zabbar', + 'Bhagalpur', + 'West Valley City', + 'Ruislip', + 'Talatamaty', + 'Ban Wang Krachae', + 'Iskapalem', + 'Kashmar', + 'Bouchagroun', + 'Timissa', + 'Xizi', + 'Elmwood Park', + 'Santa Ana Huista', + 'Hickory Hills', + 'Rayong', + 'Zambrow', + 'Diamantina', + 'Carmen de Areco', + 'Kodigenahalli', + 'Jamikunta', + 'Soyaux', + 'Juraqan', + 'Burgess Hill', + 'Piskent', + 'Wloclawek', + 'Meerssen', + 'Cruz Alta', + 'Huitzilan', + 'Melo', + 'Takelsa', + 'Xiaoyi', + 'Jhabua', + 'Jagna', + 'Sondiha', + 'Sopiste', + 'Koungou', + 'Yeldurti', + 'Dois Irmaos', + 'Jaru', + 'Kulasekharapuram', + 'Shinshiro', + 'Qaanaaq', + 'Cangucu', + 'Rosas', + 'Westtown', + 'Kaka', + 'Gobardanga', + 'Fangyuan', + 'Kallupatti', + 'Raiganj', + 'Chitapur', + 'Benevides', + 'Miercurea-Ciuc', + 'Massapequa', + 'Kallakkudi', + 'Dinuba', + 'Ouagadougou', + 'Hanford', + 'Mfou', + 'Mandalapalle', + 'Alvand', + 'Fort Campbell North', + 'Kueneng', + 'Bunnik', + 'Radnor', + 'Ikoto', + 'Blankenburg', + 'Santa Marinella', + 'Snizhne', + 'Zerakpur', + 'Caetite', + 'Boechout', + 'Gulbarga', + 'Southern Pines', + 'Nanakuli', + 'Miarinarivo', + 'Lakshmeshwar', + 'Gaocheng', + 'Laheji', + 'Bagumbayan', + 'Goshen', + 'Neopolis', + 'Baohe', + 'Diss', + 'Hangu', + 'Muyinga', + 'Apahida', + 'Miagao', + 'Videm pri Ptuju', + 'Kuysinjaq', + 'Kalfou', + 'Danilovgrad', + 'Ambalatany', + 'Katkol', + 'Forio', + 'Chaohucun', + 'Manki', + 'Capulhuac', + 'White Rock', + 'Ban Pa Tueng', + 'Marahom', + 'Constanta', + 'Ntoum', + 'Los Minas', + 'Nabaruh', + 'Mahuver', + 'Crosia', + 'Bilenke', + 'Miranda de Ebro', + 'Oshakati', + 'Kochugaon', + 'Paralimni', + 'Ramon Santana', + 'Villa Bisono', + 'Ichikai', + 'Nefasit', + 'Sangmelima', + 'Jasmine Estates', + 'Marion Oaks', + 'Ahmedabad', + 'Bello', + 'Koporo-Kenie-na', + 'Attard', + 'Kamargani', + 'Greenwood Village', + 'Dubacherla', + 'Ad Dabyah', + 'Katosi', + 'Nhandeara', + 'Thap Than', + 'Andranambolava', + 'Totutla', + 'Gambettola', + 'Hatoyama', + 'Shanyincun', + 'Pinjranwan', + 'Yadiki', + 'Ceelbuur', + 'Petrovec', + 'Tighenif', + 'Berwick-Upon-Tweed', + 'Pakhtaobod', + 'Sentilj', + 'Barahra', + 'Pingdeng', + 'Zunil', + 'Darwen', + 'Trang', + 'Napier', + 'Oroshaza', + 'Sao Tiago', + 'Sipe Sipe', + 'Gera', + 'Sadhoa', + 'Sungo', + 'Papagaios', + 'Yahaba', + 'Tassera', + 'Cuyotenango', + 'Doumanaba', + 'Tortuguitas', + 'La Prairie', + 'Enfida', + 'Nafpaktos', + 'Chhapra', + 'Hoenheim', + 'Bondoufle', + 'La Virginia', + 'Guneysu', + 'Champaign', + 'Kampala', + 'Sundararaopeta', + 'Uppidamangalam', + 'Ikkadu', + 'Valjevo', + 'Xidiancun', + 'Bangkinang', + 'Ermenek', + 'Bayaguana', + 'Bitburg', + 'North Smithfield', + 'Lagunas', + 'Chuquicamata', + 'Kannamangalam', + 'Taunggyi', + 'Bibipet', + 'Fangcun', + 'Baikatpur', + 'Sultanpur', + 'Rio de Mouro', + 'Dongcun', + 'Yali', + 'Gora Kalwaria', + 'Ottawa', + 'Achankovil', + 'Przemysl', + 'Ambohinamboarina', + 'Sangalbahita', + 'Ban Pet', + 'Segaon', + 'Watertown', + 'Baghmaria', + 'Meissen', + 'Chebli', + 'Santo Antonio do Descoberto', + 'Santa Rosa de Rio Primero', + 'Gold Canyon', + 'Marburg', + 'Bhadas', + 'Arcos', + 'Kediri', + 'Kasaoka', + 'Teisendorf', + 'Tadikombu', + 'Enger', + 'Hajan', + 'Fenggeling', + 'Guroymak', + 'Kolanpak', + 'Magam', + 'Marsberg', + 'Panagar', + 'Nove Mesto nad Vahom', + 'Koluszki', + 'Tan-Tan', + 'Dehdasht', + 'Karimganj', + 'Tekman', + 'Dudelange', + 'Remscheid', + 'Xiaolongtan', + 'Srisailain', + 'Pike Road', + 'Villaquilambre', + 'Neustadt', + 'Anserma', + 'Prerov', + 'Mandleshwar', + 'Entrerrios', + 'Andranopasy', + 'Ambohibe', + 'Eagle Mountain', + 'Kadimetla', + 'Obala', + 'Nichinan', + 'Kouloum', + 'Karumba', + 'Sagamihara', + 'Multi', + 'Imabari', + 'Vizela', + 'Chiquimula', + 'Okkerneutboom', + 'Faribault', + 'Seyhan', + 'Vinces', + 'Vijayapuri North', + 'Santa Clara del Cobre', + 'Yorkville', + 'Purisima de Bustos', + 'Belhi', + 'Balarampur', + 'Buluan', + 'Jefferson Valley-Yorktown', + 'Buchs', + 'Agua Boa', + 'Karayazi', + 'Raipur Buzurg', + 'Sisa', + 'Adigala', + 'Demba', + 'Tangerhutte', + 'Sidi Moussa Ben Ali', + 'Alpharetta', + 'Shangping', + 'Sabha', + 'Iguatemi', + 'Ragampet', + 'Andranovao', + 'Chitaga', + 'Olalapadi', + 'Chenalho', + 'Kent', + 'Gorele', + 'Fiumicino', + 'Carrboro', + 'Sihanoukville', + 'Cepin', + 'Mawlaik', + 'Melmuri', + 'Mapai', + 'Ciudad Lopez Mateos', + 'Santaluz', + 'Leninskoe', + 'Esbiaat', + 'Shterpce', + 'Sidi Abdelkarim', + 'Meoqui', + 'Wajimazakimachi', + 'Sulya', + 'Kangersuatsiaq', + 'Telpur', + 'Osmanabad', + 'Diourbel', + 'Waycross', + 'Hohenmolsen', + 'Mukhtarpur Salkani', + 'Campo Grande', + 'Willebroek', + 'Bamaur', + 'Vico Equense', + 'Andipalaiyam', + 'Peraia', + 'Ashtown', + 'Biro', + 'Weddington', + 'Arboletes', + 'Tauramena', + 'Bayserke', + 'Toretsk', + 'Ha Tinh', + 'Redondela', + 'Patcham', + 'Hilden', + 'New Corella', + 'San Francisco del Rincon', + 'Tlacolulan', + 'Letlhakane', + 'Rubanda', + 'Bohechio', + 'Boujediane', + 'Hacienda Heights', + 'Alderwood Manor', + 'Hendrik-Ido-Ambacht', + 'Dhangadhi', + 'Chanute', + 'Paraippatti', + 'Senftenberg', + 'Remich', + 'Nimbahera', + 'Kadrabad', + 'Taperoa', + 'Dharan', + 'Bidar', + 'Jiaozuo', + 'Waterford', + 'Nanao', + 'Verona', + 'Bawali', + 'Vellakkovil', + 'Lakkavaram', + 'Lyss', + 'Punnavalli', + 'Martil', + 'Melut', + 'Newburgh', + 'Qaskeleng', + 'Crevillente', + 'Assemini', + 'Kilankundal', + 'Rades', + 'Beidao', + 'Leiden', + 'Phu Ly', + 'Antehiroka', + 'Ouolodo', + 'Vaddepalli', + 'Andalusia', + 'Marechal Candido Rondon', + 'Malaut', + 'Port Shepstone', + 'Julich', + 'Spitak', + 'Si Wilai', + 'Oblesevo', + 'Nantes', + 'Totana', + 'Godhavn', + 'Augusto Correa', + 'Mirchpur', + 'Yzeure', + 'Pelabuhanratu', + 'Werneuchen', + 'Dospat', + 'Ikkarai Boluvampatti', + 'Sareh Mowndeh', + 'Ramiriqui', + 'Sorriso', + 'Wasi', + 'Indi', + 'Talavera de la Reina', + 'Lichuan', + 'Cachoeiro de Itapemirim', + 'Kariba', + 'Narita', + 'Dazhou', + 'Marmeleiro', + 'Wollongong', + 'Alwaye', + 'Fazilka', + 'Tynemouth', + 'Aramari', + 'Bantay', + 'Helmond', + 'Talegaon Dabhade', + 'Dowbaran', + 'Babak', + 'Country Walk', + 'Irara', + 'Simoes', + 'Surakarta', + 'Carapegua', + 'Lal Khatanga', + 'Nowshera', + 'Sao Leopoldo', + 'Pinrang', + 'Bouchegouf', + 'Kipili', + 'Yuzhne', + 'Narasimharajapura', + 'Halls', + 'Paco', + 'Tarija', + 'Vergina', + 'Sheridan', + 'Bastrop', + 'Cota', + 'Jinghong', + 'Aylestone', + 'Tlalixcoyan', + 'Tiszakecske', + 'Blackwells Mills', + 'Serarou', + 'Kherameh', + 'Kampung Baharu Nilai', + 'Gomboussougou', + 'Mulheim-Karlich', + 'Oshnaviyeh', + 'Ocnita', + 'Thornton Heath', + 'Enfield', + 'Castricum', + 'Rio dos Cedros', + 'West Chester', + 'Beanana', + 'Wiener Neudorf', + 'Takkolam', + 'Santo Antonio de Posse', + 'Les Abricots', + 'Higashi-Matsuyama', + 'Burutu', + 'Yingtan', + 'Valkeala', + 'Council Bluffs', + 'North Decatur', + 'Gaozhou', + 'Ghabrah', + 'Barun', + 'Mugla', + 'Olgiy', + 'Pramatam', + 'Ituacu', + 'Hihya', + 'Faridkot', + 'Zarand', + 'Escada', + 'Ambaguio', + 'Sao Joao Nepomuceno', + 'Bardoli', + 'Murakami', + 'Leinefelde', + 'Zawyat an Nwacer', + 'Banjul', + 'Genthin', + 'Susono', + 'Buin', + 'Vryheid', + 'El Tocuyo', + 'Pompton Lakes', + 'Ibipitanga', + 'Magwe', + 'Ocuilan de Arteaga', + 'Solleftea', + 'Areal', + 'Casal di Principe', + 'Hyvinkaa', + 'Kukdeshwar', + 'Ludlow', + 'Klamath Falls', + 'Husnabad', + 'Belwara', + 'Tonisvorst', + 'Shekhupur', + 'Yokaichiba', + 'Amlash', + 'Usumatlan', + 'Mascota', + 'Hemau', + 'Bhawana', + 'Dongshi', + 'Siriari', + 'Gulf Hills', + 'Khromtau', + 'Jalal-Abad', + 'Ayvalik', + 'Baza', + 'Knowsley', + 'Gibsonville', + 'Tondangi', + 'Uzunkopru', + 'Pedda Penki', + 'New Rochelle', + 'Limache', + 'Nasiyanur', + 'Pansemal', + 'Ottendorf-Okrilla', + 'Karukurti', + 'Xiangjiaba', + 'Varennes', + 'Del Gallego', + 'Riviera Beach', + 'Chicacole', + 'Marignane', + 'Nova Vas', + 'Dammaj', + 'Kayunga', + 'Wallaceburg', + 'Bangkalan', + 'Kandi', + 'Corman Park No. 344', + 'Lavinia', + 'Estelle', + 'Parthenay', + 'Datiana', + 'Tamzoura', + 'Banapur', + 'Campia Turzii', + 'Pylaia', + 'Las Heras', + 'Diamantino', + 'Dachepalle', + 'Vegarai', + 'Campbell', + 'Sao Cristovao', + 'Nossa Senhora do Socorro', + 'Ocotal', + 'Del Carmen', + 'Mangalvedha', + 'Bamba', + 'Yaojia', + 'Ecully', + 'Tadjourah', + 'Flanders', + 'Nordhragota', + 'Stutterheim', + 'Sher', + 'Seferhisar', + 'Lieshout', + 'Brignoles', + 'Alcoa', + 'Senta', + 'Isola della Scala', + 'Ekchari', + 'Formello', + 'Rio Bananal', + 'Uppalapadu', + 'Apatzingan de la Constitucion', + 'Yuancun', + 'Mandi Burewala', + 'Baraka', + 'Ban Bang Khu Lat', + 'Tradate', + 'Fangliao', + 'Santa Ana de Yacuma', + 'Castel San Giovanni', + 'Aachen', + 'Ginan', + 'Riviere-du-Loup', + 'Blain', + 'Alawandi', + 'Xo`jayli Shahri', + 'Samut Prakan', + 'Ban Wang Nok Aen', + 'Triprangottur', + 'Tumbes', + 'Vandam', + 'Bistan', + 'Punnaikkayal', + 'St. Francis', + 'Garforth', + 'Sultanbeyli', + 'Jalpaiguri', + 'Nelas', + 'Embrun', + 'Karia Ba Mohamed', + 'Guasavito', + 'Chiroqchi', + 'Leander', + 'Adrano', + 'Boudjima', + 'Ostroh', + 'Kodriva', + 'Meriden', + 'Nova Laranjeiras', + 'Barnoldswick', + 'Urbiztondo', + 'Marapanim', + 'Jiangshan', + 'Jamshoro', + 'Aki', + 'Lackawanna', + 'Kafr Nubl', + 'Siroda', + 'Whittier', + 'Junqueiro', + 'Karavaram', + 'Jaguariaiva', + 'Fort Stewart', + 'Alvarado', + 'Vicopisano', + 'Raseiniai', + 'Zolotonosha', + 'Arbutus', + 'Parsahi Sirsia', + 'Alcora', + 'Canutama', + 'Edmonton', + 'Kalaa Srira', + 'Shirayamamachi', + 'Orito', + 'Mahadebnagar', + 'Wallaroo', + 'Ciampino', + 'Sirumugai', + 'Zhangshicun', + 'Fanambana', + 'Los Guayos', + 'Santa Gertrudes', + 'Godome', + 'Formby', + 'Paramankurichi', + 'Caratinga', + 'Dayalpur Sapha', + 'Mahuakheraganj', + 'Pine Hill', + 'Zhosaly', + 'Kousseri', + 'Jabalpur', + 'Bad Lauchstadt', + 'Julu', + 'Cortazar', + 'Drexel Heights', + 'Bolzano', + 'Plano', + 'Grossenhain', + 'Ventaquemada', + 'Bechem', + 'Masaki', + 'Denpasar', + 'Gaggiano', + 'Roxas', + 'Wickede', + 'Gomoh', + 'Arklow', + 'Fossano', + 'Stralsund', + 'Kresek', + 'Pohrebyshche', + 'Siruvalur', + 'Karpi', + 'Adra', + 'Rafiganj', + 'Oftringen', + 'Ilirska Bistrica', + 'Anazzou', + 'Jonnagiri', + 'Norcross', + 'Sidi Bennour', + 'Berkine', + 'Ueckermunde', + 'Walsall', + 'Dingle', + 'Raxaul', + 'Chard', + 'Cataingan', + 'Ervadi', + 'Santiago', + 'Dallgow-Doberitz', + 'Poperinge', + 'Shankarpur', + 'Felton', + 'Nesebar', + 'Junction City', + 'Socorro', + 'Horb am Neckar', + 'Slavonski Brod', + 'Samaniego', + 'Bolingbrook', + 'Sombrerete', + 'Pastrana', + 'Bertoua', + 'Zungeru', + 'Ataleia', + 'Ath Thawrah', + 'Palisades Park', + 'Biatorbagy', + 'Perches', + 'Ashqelon', + 'Janjanbureh', + 'Stendal', + 'Quixabeira', + 'San Giovanni Valdarno', + 'Madepalli', + 'Bubanza', + 'Fatehpur Shahbaz', + 'Vigonza', + 'Pallikapuzha', + 'Stepney', + 'Sibiu', + 'Bodagudipadu', + 'Isidro Casanova', + 'Chatia', + 'Angor', + 'Ouro Verde', + 'Markala', + 'Sapkyo', + 'Amarapuuram', + 'Kannadiparamba', + 'Koula', + 'Laksar', + 'Uonuma', + 'Mainpuri', + 'Liberia', + 'Zarah Sharan', + 'Alcaniz', + 'Lakhaura', + 'Bansbari', + 'Kurikuppi', + 'Muan', + 'Sandrandahy', + 'Corail', + 'Sardrud', + 'Ambositra', + 'Zhengtun', + 'Ijebu-Ode', + 'Athol', + 'Menderes', + 'Shirbadgi', + 'Oaxaca', + 'Nogales', + 'Tekkattur', + 'Mobile', + 'Pazaryeri', + 'Hirakud', + 'Oyama', + 'Anrochte', + 'Mashiko', + 'Vobkent Shahri', + 'Neumunster', + 'Lingbao Chengguanzhen', + 'Elbistan', + 'Hakka', + 'Safranbolu', + 'Goulds', + 'Kadriye', + 'Komae', + 'Mahdia', + 'Peer', + 'Mbulungu', + 'Prince George', + 'Bir Ben Laabed', + 'Manukau City', + 'Isfana', + 'Buxton', + 'Hassfurt', + 'Paro', + 'Andimeshk', + 'Mockmuhl', + 'Leonora', + 'Healdsburg', + 'Pyrgos', + 'Dardilly', + 'Richardson', + 'Espiritu', + 'Dipolog', + 'Oyodo', + 'Concord', + 'Rye Brook', + 'Komoro', + 'Liedekerke', + 'Nishon Tumani', + 'Wyke', + 'Padangsidempuan', + 'Milton', + 'Princes Town', + 'Bandar-e Deylam', + 'Perry Hall', + "Ahmer el 'Ain", + 'Kampong Cham', + 'Vijayawada', + 'Kendal', + 'Sabinas', + 'Sihanamaro', + 'Kanye', + 'George Town', + 'Piquete', + 'Mullach Ide', + 'Fukushima', + 'Hohen Neuendorf', + 'Antsahabe', + 'Navoiy', + 'Riehen', + 'Castel Bolognese', + 'Virovitica', + 'Solihull', + 'Galaat el Andeless', + 'Endwell', + 'Langeloop', + 'Tuban', + 'Quaregnon', + 'Mastchoh', + 'La Chapelle-sur-Erdre', + 'Tapes', + 'Bac Ninh', + 'Tustin', + 'Leava', + 'Nagai', + 'Huatusco', + 'Kyjov', + 'Duque Bacelar', + 'Tanbei', + 'Copiague', + 'Langenzenn', + 'Iaciara', + 'Bimbo', + 'Guri', + 'Lake Ridge', + 'Star Dojran', + 'Nivala', + 'Damme', + 'Ambohitompoina', + 'Slovenj Gradec', + 'Najibabad', + 'Ziguinchor', + 'Chatenay-Malabry', + 'Mulanay', + 'Nakasi', + 'Guadalajara', + 'Bad Hersfeld', + 'Raciborz', + 'Sesto San Giovanni', + 'Walker', + 'Nonnweiler', + 'Dujiashigou', + 'Akune', + 'Malabang', + 'Konarka', + 'Chaves', + 'Yueqing', + 'Goias', + 'Isbergues', + 'Esenler', + 'Jovellanos', + 'Hajin', + 'Forest Acres', + 'Duchcov', + 'Keza', + 'Summit View', + 'Sokotindji', + 'Chitvel', + 'Tunis', + 'Sarkoy', + 'Nerang', + 'Berlaar', + 'Lukovica', + 'Bilthoven', + 'Muddebihal', + 'Thi Tran Mau A', + 'Fano', + 'Samtse', + 'Litian Gezhuang', + 'Dundalk', + 'Silistra', + 'Jangamguda', + 'Borna', + 'Bassar', + 'Gerstungen', + 'Talevad', + 'Worksop', + 'Sidlaghatta', + 'Chapulhuacan', + 'Guasdualito', + 'Garhi', + 'Cugir', + 'Epitacio Huerta', + 'Sankhavaram', + 'Sabotsy', + 'Nausori', + 'Purnea', + 'Ponnamaravati', + 'Sarkikaraagac', + 'Bourem', + 'Quepos', + 'South San Jose Hills', + 'Changchunpu', + 'Wissen', + 'Nova Canaa', + 'Whitburn', + 'Wysokie Mazowieckie', + 'Soacha', + 'Nagathan', + 'Daly City', + 'Antanimasaka', + 'Pura', + 'Petersfield', + 'Overlea', + 'Patjirwa', + 'Weldiya', + 'Iringa', + 'Guaruja', + 'Sitges', + 'Paola', + 'West End', + 'Nasice', + 'Mullanwala', + 'Nanjangud', + 'Jozefoslaw', + 'Zalau', + 'Petorca', + 'Zandhoven', + 'Xiashi', + 'Jaspur', + 'Pasuruan', + 'Bergen', + 'Gangneung', + 'Stargard Szczecinski', + 'President Roxas', + 'El Achir', + 'Beltangadi', + 'Iida', + 'Ardooie', + 'Swallownest', + 'Bairi Chak', + 'Zhijiang', + 'Shiyan', + 'Huzurabad', + 'Kampene', + 'Norden', + 'Chumpak', + 'Kokrajhar', + 'Arbelaez', + 'Mendig', + 'Independent Hill', + 'Etimesgut', + 'White Settlement', + 'Pottanur', + 'Shisui', + 'Mukkudal', + 'Mellila', + 'Pinagkaisahan', + 'Alcorta', + 'Dhantola', + 'San Carlos de Bariloche', + 'New Kingman-Butler', + 'Lawang', + 'Taki', + 'Khanpur', + 'Pirallahi', + 'Amatlan de los Reyes', + 'Kottapuram', + 'Mount Magnet', + 'Hunedoara', + 'Urayasu', + 'Provadia', + 'Siddarampuram', + 'Warfield', + 'Lemery', + 'Lidkoping', + 'Kalikiri', + 'Cravinhos', + 'Mukkanur', + 'Lakeland Highlands', + 'Pilani', + 'Al Mayadin', + 'Port Charlotte', + 'Jinshan', + 'Zeydabad', + 'Cantonment', + 'Nakhon Thai', + 'Dingras', + 'Kirippatti', + 'Haverford', + 'Rufisque', + 'Alagarai', + 'Bang Ban', + 'Querencia do Norte', + 'Puebloviejo', + 'Helena Valley Southeast', + 'Mezitli', + 'Pryor Creek', + 'Hem', + 'Antadinga', + 'Costa de Caparica', + 'Ghardimaou', + 'Shuinancun', + 'Shelek', + 'Saldanha', + 'Maues', + 'Apaseo el Grande', + 'Gendou', + 'Conceicao da Aparecida', + 'Burtonsville', + 'Eagle Pass', + 'Babhangawan', + 'Halle-Neustadt', + "Bahla'", + 'Matelandia', + 'Muddanuru', + 'Coroaci', + 'Morro Agudo', + 'Lipjan', + 'Mizusawa', + 'Cangola', + 'Montanha', + 'Rethymno', + 'Westwood Lakes', + 'Valpovo', + 'Cayambe', + 'Itapicuru', + 'Bourdoud', + 'Polasara', + 'Beltinci', + 'Armentieres', + 'Nuriston', + 'Hattian Bala', + 'Torre del Campo', + 'Hormigueros', + 'Tan An', + 'Sao Jose dos Campos', + 'Belem de Maria', + 'Ksar Lmajaz', + 'Ossining', + 'Tikota', + 'Matsumoto', + 'Reina Mercedes Viejo', + 'New Plymouth', + 'Ocean Pointe', + 'Zogbodome', + 'Ahlaf', + 'Southfield', + 'Nijverdal', + 'Mumias', + 'Vac', + 'Hevie', + 'Malumfashi', + 'Merignac', + 'Agua Prieta', + 'Parabcan', + 'Kako', + 'Chestermere', + 'Nijar', + 'Esanboy', + 'Loango', + 'Boulder City', + 'Pedda Mupparam', + 'Bender', + 'Snellville', + 'Aibongo', + 'Geraardsbergen', + 'Skillounta', + 'Zalingei', + 'Argyroupoli', + 'Steiner Ranch', + 'Meghraj', + 'Midrand', + 'Akola', + 'Sacacoyo', + 'Osogbo', + 'Kaukhali', + 'Cotui', + 'Nzalat Laadam', + 'Bunji', + 'East Meadow', + 'Yangasso', + 'Saint-Cyprien', + 'Banda Aceh', + 'Shipley', + 'Nelamangala', + 'Sidi Redouane', + 'Mahomet', + 'El Abadia', + 'Kanagicho', + 'Port Elgin', + 'Parkway', + 'Kashiwazaki', + 'Belabo', + 'Rajauli', + 'Vlist', + 'Lucheng', + 'Chania', + 'Garching bei Munchen', + 'Taurianova', + 'Kahhale', + 'Novellara', + 'Cerejeiras', + 'Maintal', + 'Old Orchard Beach', + 'Lecco', + 'Oirase', + 'Kailahun', + 'Tres Valles', + 'Sao Jose de Ribamar', + 'Pala', + 'Galikesh', + 'Phularwan', + 'Santo Tomas de los Platanos', + 'Sher Chakla', + 'Rumia', + 'Almasi', + 'Hasanpur Juned', + 'Acambaro', + 'Market Warsop', + 'Diankabou', + 'Yelahanka', + 'Florissant', + 'Daegu', + 'Neckarsulm', + 'Suan', + 'Abadan', + 'Piritu', + 'Tulancingo', + 'Al Malikiyah', + 'Hazel Grove', + 'Zhanlicun', + 'Shoreline', + 'Sutihar', + 'Kopa', + 'Conshohocken', + 'Cuilco', + 'Budaun', + 'Makhar', + 'Kondrukota', + 'South Huron', + 'Jambukuttaippatti', + 'Plabennec', + 'Benoni', + 'Maddikera', + 'Vredendal', + 'Aci Castello', + 'Solotvyno', + 'Tarhzout', + 'Webb City', + 'Shagamu', + 'Svendborg', + 'Manokwari', + 'Lalian', + 'Kings Mountain', + 'Sambhar', + 'Kovacica', + 'Sumperk', + 'Barra Bonita', + 'Cedeno', + 'El Paraiso', + 'Zeghanghane', + 'Parihara', + 'Chosica', + 'Allur', + 'Al Qatif', + 'Wadlakonda', + 'Itoshima', + 'Huckelhoven', + 'Lempaala', + 'Fleming Island', + 'Sewai', + 'Mahesh Khunt', + 'Cranbourne', + 'Bahia Honda', + 'Sanderstead', + 'Munagapaka', + 'Kamata', + 'Arakere', + 'Nasirabad', + 'Tennala', + 'Sumbal', + 'Mandaluyong City', + 'Sunne', + 'Skierniewice', + 'Dilarpur', + 'Qujing', + 'Minneapolis', + 'Abalessa', + 'Roosevelt', + 'Balatonfured', + 'Mel Palaiyam', + 'Maitum', + 'Umm el Fahm', + 'Nanpala', + 'Isahara', + 'Qantir', + 'Boucherville', + 'Port Townsend', + 'Sassuolo', + 'Lipno', + 'Vahdat', + 'Orastie', + 'Oakland', + 'Reus', + 'Arpacay', + 'Andenne', + 'Kafr Takharim', + 'Wakasa', + 'Rutigliano', + 'Marianao', + 'Norderstedt', + 'Orobo', + 'Helsinki', + 'Bria', + 'Wehr', + 'Melsungen', + 'Saint-Basile-le-Grand', + 'Keisen', + 'Khorramshahr', + 'Brighouse', + 'Mount Dora', + 'Bogor', + 'Ayni', + 'Karoi', + 'Kujri', + 'Codo', + 'Police', + 'Ascension', + 'Chaguaramas', + 'Montauban', + 'Kukichuo', + 'Ruti', + 'Abbottabad', + 'Zgornje Jezersko', + 'Bushkill', + 'Ilobu', + 'Allison Park', + 'Abreu e Lima', + 'Magdalena', + 'Natividade do Carangola', + 'Chiclayo', + 'Hard', + 'Singrauliya', + 'Thanh Phu', + 'Kraljevo', + 'Grossos', + 'Algonquin', + 'Nowgong', + 'San Pietro in Casale', + 'Si Racha', + 'Anjoma-Ramartina', + 'Somain', + 'Ronkonkoma', + 'Draper', + 'Gudikallu', + 'Anandnagar', + 'Bouknadel', + 'Torri di Quartesolo', + 'Kaluvaya', + 'Benato-Toby', + 'Bormujos', + 'Xinzhou', + 'Qingyuan', + 'Tiruppattur', + 'Rotherham', + 'Alawalpur', + 'West Perrine', + 'Sahab', + 'Brejo do Cruz', + 'Uchiko', + 'Lichfield', + 'Schwaz', + 'Prevost', + 'Srimushnam', + 'Isalo', + 'Malinagar', + 'Tucson Estates', + 'Santiago do Cacem', + 'Neuenhaus', + 'Sa`dah', + 'Diebougou', + 'Karmah an Nuzul', + 'Muradpur', + 'Hov', + 'Duffel', + 'Ankeny', + 'Selim', + 'San Juan Bautista', + 'La Lisa', + 'Upper Arlington', + 'Chagallu', + 'West Wickham', + 'Godhra', + 'Bilaspur', + 'Bijeraghogarh', + 'Misterbianco', + 'Immingham', + 'Lawndale', + 'Ham Lake', + 'Bytow', + 'Lahnstein', + 'Illertissen', + 'Carpi', + 'Uch Sharif', + 'Pariconia', + 'Teixeira de Freitas', + 'Newstead', + 'Chegga', + 'Potsdam', + 'Korinthos', + 'Palmital', + 'Undavalli', + 'Onteniente', + 'Ayutuxtepeque', + 'Parbhani', + 'Ban Noen Kum Nueng', + 'Sucha Beskidzka', + 'Pieve di Soligo', + 'Sioux City', + 'Bni Darkoul', + 'Mae O', + 'Nova Sintra', + 'Piratininga', + 'Massantola', + 'Alice Springs', + 'Tidili Masfiywat', + 'Mahaly', + 'Baglar', + 'Heartland', + 'Kuyucak', + 'Pili', + 'Katri', + 'Saladas', + 'Samarinda', + 'Okhtyrka', + 'Sulagiri', + 'Pluzine', + 'Di Linh', + 'Kabacan', + 'Koprubasi', + 'Bayanauyl', + 'Murray Bridge', + 'Sunchales', + 'Holzminden', + 'Solon', + 'Orosi', + 'Ofaqim', + 'Vadakkangara', + 'Tooele', + '`Adra', + 'Nagercoil', + 'Berriche', + 'Hyuga', + 'Santos Reyes Nopala', + 'Sezana', + 'Halifax', + 'Ambodisakoana', + 'Booneville', + 'Kirkenes', + 'Mahmutlar', + 'Bad Mergentheim', + 'Tnine Lgharbia', + 'Tanamarina-Sakay', + 'Escaudain', + 'Paterno', + 'Lepe', + 'Marui', + 'Lalitpur', + 'Las Veredas', + 'Pocos de Caldas', + 'Guasave', + 'Canterbury', + 'Rakhwari', + 'Benbutucun', + 'Harrisburg', + 'Casalgrande', + 'Mercaderes', + 'Celorico de Basto', + 'Goiania', + 'Thiruvananthapuram', + 'Padrauna', + 'Navarro', + 'Minturno', + 'Sarari', + 'Carugate', + 'Math Lohiyar', + 'Vairichettipalaiyam', + 'Leo', + 'Saposoa', + 'Vasa', + 'Heggadadevankote', + 'Po', + 'Rock Springs', + 'Kantilo', + 'Jedeida', + 'Pignon', + 'Izunokuni', + 'Shiyeli', + 'Mandiavato', + 'San Jose del Monte', + 'Ouenou', + 'Bouabout', + 'Kangaba', + 'Ulm', + 'Gwalior', + 'Recke', + 'Puruk Cahu', + 'Leonia', + 'Zapala', + 'Ban Na San', + 'Morant Bay', + 'Teonthar', + 'Douar Bou Tlelis', + 'Gondia', + 'Pulur', + 'Andonabe', + 'Santo Antonio do Jacinto', + 'Poldokhtar', + 'Setubal', + 'Mogalturru', + 'Tlahuelilpan', + 'Strood', + 'Pirapetinga', + 'Hamina', + 'Pompeia', + 'Pistoia', + 'Varre-Sai', + 'Tonosho', + 'Cisneros', + 'Bad Sackingen', + 'Yinggen', + 'Barwa Sagar', + 'Ayorou', + 'Chandhaus', + 'Mehsari', + 'Bobrovytsia', + 'McKinney', + 'Gernsbach', + 'Huejutla de Reyes', + 'Cintalapa de Figueroa', + 'Terra Alta', + 'Isemi-Ile', + 'Nishiwaki', + 'Siruma', + 'Leinfelden-Echterdingen', + 'Bernissart', + 'Dharampur', + 'Golden', + 'Beek', + 'Noordwijk', + 'Elixku', + "Piest'any", + 'Kilvisharam', + 'Andria', + 'Nanjakkad', + 'Sankaridrug', + 'Ondorhaan', + 'Campo Novo do Parecis', + 'Castellon de la Plana', + 'Houthulst', + 'Choi Hung', + 'Zabrze', + 'Madaya', + 'Alfafar', + 'Nili', + 'Robertsonpet', + 'Yedapalli', + 'Cidade de Nacala', + 'Mathibestad', + 'Oued Tlelat', + 'Cuetzalan', + 'Juli', + 'Xixinzhuangzhen', + 'Hanwell', + 'Pomezia', + 'Lucani', + 'Fastiv', + 'Bela Palanka', + 'Kumarkhali', + 'Golubac', + 'Svencionys', + 'Sesena', + 'Savigny-sur-Orge', + 'Cal', + 'Brown Deer', + 'Thessaloniki', + 'Jiroft', + 'Taoyang', + 'Beziers', + 'Pathraha', + 'Minalabac', + 'Genova', + 'Sarea Khas', + 'Mahabe', + 'Bela Vista', + 'Zawyat Ahancal', + 'Speyer', + 'Cicekdagi', + 'Ouled Brahim', + 'Yinying', + 'Aguas Vermelhas', + 'Lille', + 'Dillingen', + 'Silang', + 'Monsey', + 'Kalakada', + 'Comarapa', + 'Tit Mellil', + 'Sergio Osmena Sr', + 'Tabapua', + 'Nata', + 'Redlands', + 'Jaggisettigudem', + 'Loma de Cabrera', + 'Kasongo', + 'Kincardine', + 'Aukstieji Paneriai', + 'Sabana Grande', + 'Barwadih', + 'Eragny', + 'Mochudi', + 'New Ulm', + 'La Chorrera', + 'Teresa', + 'Pingtan', + 'Caete', + 'Wieruszow', + 'Torrelavega', + 'Waltham Cross', + 'Yaupi', + 'Becancour', + 'Sao Fidelis', + 'Koch', + 'San Martin de Valdeiglesias', + 'Akron', + 'Cruzeiro do Sul', + 'Halabjah', + 'Channapatna', + 'Aliquippa', + 'Tilehurst', + 'Sabaoani', + 'Berck-sur-Mer', + 'Marquetalia', + 'Shepparton', + 'Stalybridge', + 'Banos', + 'Rengam', + 'Andradina', + 'Andicun', + 'Changde', + 'Vacaville', + 'Sattegalam', + 'Dadukou', + 'Machida', + 'Quisqueya', + 'Solcava', + 'Annecy', + 'Golakpur', + 'Altenburg', + 'Vahdattiyeh', + 'Damoh', + 'Mojo', + 'Vercelli', + 'Simijaca', + 'Chainpur', + 'Esopus', + 'Dimasalang', + 'Grand Rapids', + 'Bowdon', + 'Socastee', + 'Sibila', + 'Miches', + 'Kalkuni', + 'Kananga', + 'Ain Legdah', + 'Songo', + 'Huandacareo', + 'Panazol', + 'Iacu', + 'Kelandis', + 'Miragoane', + 'Pote', + 'Shimabara', + 'Mariluz', + 'Anyuan', + 'Guisborough', + 'Hashtgerd', + 'La Esperanza', + 'Gitarama', + 'San Miguel de Tucuman', + 'Hialeah', + 'Lake Wales', + 'Orihuela', + 'Lakhzazra', + 'Marivan', + 'Whitehorse', + 'Arawa', + 'Ono', + 'Sidi Bou Ali', + 'Papa', + 'Guankou', + 'Marghita', + 'Takarazuka', + 'Sao Joao do Manhuacu', + "G'ijduvon Shahri", + 'Puerto Heath', + 'San Juanito de Escobedo', + 'Mattenhof', + 'Amriswil', + 'Semara', + 'Lokeren', + 'Nevers', + 'Ken Caryl', + 'Hungen', + 'Kehl', + 'Tysmenytsia', + 'Khaur', + 'Hawsh al Bahdaliyah', + 'Palasa', + 'Vaduz', + 'Munnuru', + 'Oranjestad', + 'Tallkalakh', + 'Elwood', + 'Tocaima', + 'Ostringen', + 'Fontoura Xavier', + 'Palau', + 'Eastleigh', + 'Ferry Pass', + 'Renigunta', + 'Gig Harbor', + 'Guma', + 'Angadikkal Tekkekara', + 'Pathri', + 'Neya', + 'Santa Ana Maya', + 'Campobello di Mazara', + 'Zhongshu', + 'Lorton', + 'Wankaner', + 'Claremont', + 'Casca', + 'Izumi', + 'Lodhwe', + 'Sidi Boushab', + 'Karcag', + 'Siyabuswa', + 'Simeria', + 'Nemby', + 'Tema', + 'Komatsushimacho', + 'Canhotinho', + 'Ubstadt-Weiher', + 'Mill Hill', + 'Stange', + 'Rincon', + 'Leteri', + 'Cavite City', + 'Msaken', + 'Maputsoe', + 'Martorell', + 'Villiers-le-Bel', + 'San Esteban', + 'Fruita', + 'Sagunto', + 'Monkayo', + 'Maurepas', + 'Jianguang', + 'Zetel', + 'Dordrecht', + 'Kangbao', + 'Linkou', + 'Virginia', + 'Freital', + 'Tut', + 'Tashi', + 'Lang Son', + 'Falun', + 'Tentena', + 'Cristino Castro', + 'Langwedel', + 'Joaima', + 'Maraiyur', + 'Mata Grande', + 'Estanzuela', + 'Rosemere', + 'Kloof', + 'Or `Aqiva', + 'Cerro Grande', + 'Villa Berthet', + 'Buena Park', + 'Balkanabat', + 'Yaguate', + 'Katagon', + 'Cantaura', + 'Stung Treng', + 'Shambu', + 'Froha', + 'Anzio', + 'Trichur', + 'Bhatranha', + 'Sideropolis', + 'Herbrechtingen', + 'Gent', + 'Burhaniye', + 'Odienne', + 'Hendon', + 'Rustenburg', + 'Ninohe', + 'Godollo', + 'Muelle de los Bueyes', + 'Astorga', + 'Nowy Dwor Mazowiecki', + 'Pilibangan', + 'Rapu-Rapu', + 'Ingham', + 'Sable-sur-Sarthe', + 'Andre Fernandes', + 'Khomeyni Shahr', + 'Languyan', + 'Schwyz', + 'Terranuova Bracciolini', + 'Sangan', + 'Nirpur', + 'Palmeira', + 'Aziylal', + "Vel'ky Krtis", + 'Babhnoul', + 'Ait Yaazem', + 'Usti nad Orlici', + 'Bonham', + 'Achampet', + 'San Baudilio de Llobregat', + 'Tres Arroyos', + 'Suva', + 'Hameln', + 'Oued Taria', + 'Tamalameque', + 'Aguinaldo', + 'Kitajima', + 'Bilhorod-Dnistrovskyi', + 'Glocester', + 'Nuevo Ideal', + 'Rialma', + 'Tukums', + 'Calhoun', + 'Ambalavero', + 'Idappadi', + 'Benevento', + 'Lormont', + 'Anndevarapeta', + 'Upton', + 'Zamalka', + 'Sasaram', + 'Bucksburn', + 'Segamat', + 'Zywiec', + 'Ribnitz-Damgarten', + 'Marly', + 'Mogwase', + 'Senaki', + 'Arroio Grande', + 'Grobbendonk', + 'Clarendon Hills', + 'Vyshneve', + 'Lomas del Mirador', + 'Royal Palm Beach', + 'Koloriang', + 'Niort', + 'Tazhakara', + 'Papanasam', + 'Arroio do Tigre', + 'Los Bajos', + 'Ostuncalco', + 'Jastrzebie-Zdroj', + 'Bejucal', + 'St. Clements', + 'Itanhem', + 'Bayamo', + 'Vejle', + 'Kishanpur Ratwara', + 'Chok Chai', + 'Oberhausen-Rheinhausen', + 'Karawang', + 'Lengir', + 'Katori', + 'Karapinar', + 'Talcahuano', + 'Ciudad de Huajuapam de Leon', + 'Hindupur', + 'Keller', + 'Fagaras', + 'Wodonga', + 'Tanakkangulam', + 'Pereira', + 'Clonmel', + 'Eunice', + 'Eberswalde', + 'Tottiyam', + 'Iquira', + 'Ergani', + 'Santa Clara', + 'Jaitpur', + 'Anzin', + 'Toumodi', + 'Sitio do Mato', + 'Drabar', + 'Srikhanda', + 'Ban Mae Hia Nai', + 'Shimubi', + 'Ozd', + 'Mucur', + 'Burdeos', + 'Hawthorne', + 'El Aouana', + 'Kirkuk', + 'Mekele', + 'Barguna', + 'Brzeg Dolny', + 'Santa Maria Tonameca', + 'San Luis', + 'Les Ponts-de-Ce', + 'Helong', + 'Marneuli', + 'Anjiamangirana I', + 'Punjai Kalamangalam', + 'Phan Thiet', + 'Beni Mellal', + 'Jose Panganiban', + 'Boxley', + 'Tamalpais-Homestead Valley', + 'Raisari', + 'Calanasan', + 'Kazanlak', + 'Buved', + 'Amarpatan', + 'Quang Tri', + 'Premia de Mar', + 'Nandimandalam', + 'Leeuwarden', + 'Difficult Run', + 'Bergamo', + 'Kuwana', + 'Paignton', + 'Puduparambubhagam', + 'Tranqueras', + 'Haren', + 'Wertingen', + 'Castelar', + 'Glenrothes', + 'Bilimora', + 'Funes', + 'Longview', + 'Afdem', + 'Soyalo', + 'Nasatta', + 'Takkali', + 'Downpatrick', + 'Khotyn', + 'Sidi Brahim', + 'Halewood', + 'Lawton', + 'Surampatti', + 'Arroio dos Ratos', + 'Ain Zohra', + 'Barking', + 'Sucre', + 'Amboanjo', + 'Lubalo', + 'Chachapoyas', + 'Villa Yapacani', + 'Vettakkaranpudur', + 'Montemarciano', + 'Aracatu', + 'Avigliano', + 'Roanne', + 'Nadur', + 'Weinan', + 'Heyuan', + 'Tabontabon', + 'Peterborough', + 'Dieli', + 'El Ach', + 'Ezanville', + 'Gore', + 'Bougoula', + 'Porlamar', + 'Sedona', + 'Saint-Louis', + 'Cebazat', + 'Nueva Guinea', + 'Sao Francisco de Assis', + 'Achi', + 'Mummidivaram', + 'Antsirabe', + 'Samalapuram', + 'Chandler', + 'Shuanghe', + 'Santana do Paraiso', + 'Ampondra', + 'Delavan', + 'Cacoal', + 'Abangaritos', + 'South Londonderry', + 'Triesenberg', + 'Amantea', + 'Bou Arkoub', + 'Tamponala', + 'Sogamoso', + 'Verdun', + 'Mali Zvornik', + 'La Democracia', + 'El Prat de Llobregat', + 'Borgloon', + 'Morwa', + 'Jarville-la-Malgrange', + 'Evans', + 'Peto', + 'Forde', + 'Grants', + 'Maglie', + 'Altagracia de Orituco', + 'Budaors', + 'El Affroun', + 'Azhikkod', + 'Hiramandalam', + 'Botad', + 'Rye', + 'Broadstairs', + 'Tilmi', + 'Harleysville', + 'Moncao', + 'Usti nad Labem', + 'Maracha', + 'Gaojiayingcun', + 'Castelnuovo di Verona', + 'Versmold', + 'Luzilandia', + 'Vernier', + 'Southold', + 'Nkhata Bay', + 'Chavkandak', + 'Paniqui', + 'South Milwaukee', + 'Mauranwan', + 'Sidi Ladjel', + 'Mozirje', + 'Mthatha', + 'Novotroitske', + 'Aracinovo', + 'Fulin', + 'Tatalon', + 'Carpentersville', + 'Vaijapur', + 'Zhongcheng', + 'Glendale', + 'Saugeen Shores', + 'Saint-Paul-les-Dax', + 'Kobeliaky', + 'Pai Bigha', + 'Bay St. Louis', + 'Bluffdale', + 'Zagora', + 'Careiro', + 'Karahrud', + 'Mudakkal', + 'Amuru', + 'Ismailia', + 'Chodavaram', + 'Kiyose', + 'Cerritos', + 'Ambondrona', + 'Penn Hills', + 'Le Taillan-Medoc', + 'Girua', + 'Rio Linda', + 'Poas', + 'Lucas do Rio Verde', + 'Pratapgarh', + 'Daddi', + 'Lifford', + 'Vandikarai', + 'Westhoughton', + 'Rajepur', + 'Monreal', + 'Loviisa', + 'Juanacatlan', + 'Hankey', + 'Amboise', + 'Bozkir', + 'Ha Tien', + 'Kucukcekmece', + 'Posse', + 'Buerarema', + 'Leixlip', + 'Huanren', + 'Bawgalegyi', + 'Manage', + 'Dumanjog', + 'Mulifanua', + 'Traun', + 'Pantelho', + 'Gundur', + 'Mirialguda', + 'Russelsheim', + 'Quixelo', + 'Chipata', + 'Macaubas', + 'Fujino', + 'Craig', + 'Iskapalli', + 'Solhan', + 'Costessey', + 'La Vega', + 'Espejo', + 'Perevalsk', + 'Middle Island', + 'Zavora', + 'Lorain', + 'Leninskiy', + 'Rossdorf', + 'Pembroke', + 'Weirton', + 'Villa Gonzalez', + 'Multan', + 'Patamundai', + 'Wicklow', + 'Florence', + 'Tibati', + 'Steti', + 'Ugento', + 'Messstetten', + 'Pestel', + 'Sujangarh', + 'Camanducaia', + 'Acarau', + 'Balagam', + 'Sungal', + 'Linyi', + 'Tukuyu', + 'Faetano', + 'Batgram', + 'Saundatti', + 'Roux', + 'Hermosa Beach', + 'Mavelikara', + 'Canapi', + 'Lovendegem', + 'Busogo', + 'Villeneuve-les-Avignon', + 'Phokeng', + "Sant'Arpino", + 'Ambasamudram', + 'Gobernador Virasora', + 'Langley Park', + 'Mungo', + 'Carrick on Shannon', + 'Warangal', + 'Haan', + 'Markt Indersdorf', + 'Ngororero', + 'Pavannur', + 'Boekel', + 'Sotteville-les-Rouen', + 'Sarai Alamgir', + 'Kutiyana', + 'Great Cornard', + 'Oiapoque', + 'Diondiori', + 'Xiangshui', + 'Benesov', + 'Borja', + 'Traunstein', + 'Cardito', + 'Evreux', + 'Camponogara', + 'Kladovo', + 'Oncativo', + 'Nazret', + 'Cachoeiras de Macacu', + 'Bayport', + 'Mandaguari', + 'Katha', + 'Scarborough', + 'Hotan', + 'Dinangorou', + 'Kilimli', + 'Killamarsh', + 'Bifoun', + 'Gorom-Gorom', + 'Reddish', + 'Wildomar', + 'Tlalmanalco', + 'Grafenhainichen', + "Sama'il", + 'Touwu', + 'Castillos', + 'Sipacapa', + 'Dionisio Cerqueira', + 'Maqsuda', + 'Iranduba', + 'Bharweli', + 'Irakleio', + 'Shima', + 'Zandvoort', + 'Edremit', + 'Vitomirice', + 'Laoaoba', + 'Kocakoy', + 'Barnet', + 'Majitha', + 'Minnehaha', + 'Holbaek', + 'Panchgram', + 'San Michele al Tagliamento', + 'San Agustin de Guadalix', + 'Fanjakana', + 'Piat', + 'Marjampad', + 'River Falls', + 'Gualan', + 'Capannori', + 'Takashima', + 'Siripur', + 'Antakotako', + "Qa'en", + 'Agadir Melloul', + 'West Jordan', + 'Dipalpur', + 'Ar Rudayyif', + 'New Hyde Park', + 'Rasdhoo', + 'Amakusa', + 'Jember', + 'North Richland Hills', + 'Andrainjato', + "Bo'ness", + 'Curridabat', + 'Wangaratta', + 'Mirante', + 'Pulppatta', + 'Prestwick', + 'El Tarra', + 'Ambodimanga II', + 'Beausoleil', + 'Raisio', + 'Puttur', + 'Diriamba', + 'Davyhulme', + 'Murukondapadu', + 'North Union', + 'Guayaramerin', + 'Mingguang', + 'Milaor', + 'Dongluocun', + 'Ghuenke', + 'Market Harborough', + 'Sainte-Savine', + 'Makaha', + 'Security-Widefield', + 'Donabate', + 'Wigan', + 'Tasquillo', + 'Villasagar', + 'Buikwe', + "Ouro Preto d'Oeste", + 'Roldanillo', + "Ait I'yach", + 'Camliyayla', + 'Cinderford', + 'Maraial', + 'Santo Stefano di Magra', + 'Anaiyur', + 'Kushk', + 'Amontada', + 'Marituba', + 'Cambe', + 'Horjul', + 'Seguela', + 'Wagin', + 'Schwandorf', + 'Lawaan', + 'Kadirli', + 'Vaughan', + 'East Retford', + 'Hinatuan', + 'Shoranur', + 'Rayen', + 'Bistrica ob Sotli', + 'Acharnes', + 'Rajsamand', + 'Aipe', + 'Faxinal', + 'Ollioules', + 'Ismaning', + 'Smartno', + 'Lamhadi', + 'Lecce', + 'Bredbury', + 'Adjarra', + 'Lichana', + 'La Troncal', + 'Sao Caetano do Sul', + 'Koppal', + 'Hansa', + 'Sirinhaem', + 'Weissenfels', + 'Aloha', + 'Tailai', + 'Jucuaran', + 'Summerstrand', + 'Amnat Charoen', + 'Kornwestheim', + 'Sorum', + 'Iarpur', + 'Minquan', + 'Srivaikuntam', + 'Almunecar', + 'Ban Don Thong', + 'Targu Jiu', + 'Tamparan', + 'Oyabe', + 'Stadtlohn', + 'Hazorasp', + 'Torredembarra', + 'Kalavad', + 'Ochakiv', + 'Williamsburg', + 'North Greenbush', + 'Victor Larco Herrera', + 'Karasu', + 'Sabnima', + 'Iramala', + 'Hoa Binh', + 'Naregal', + 'Concordia Sagittaria', + 'Portishead', + 'Zhaltyr', + 'Liberty Triangle', + 'Chegurumomadi', + 'Vila Junqueiro', + 'Bitlis', + "Tajura'", + 'Ambodivoara', + 'Highbury', + 'Nizza Monferrato', + 'Kesariya', + 'Walur', + 'Turbat', + 'Kars', + 'Colorado Springs', + 'Lashkar Gah', + 'Lavaur', + 'Nova Petropolis', + 'Goalpara', + 'Padra', + 'Fallbrook', + 'Imotski', + 'Domnesti', + 'Ilami', + 'Edewecht', + 'Playas de Rosarito', + 'Palo Negro', + 'Ban Song', + 'Batna', + 'Galt', + 'Ambatolava', + 'Le Cannet', + 'Urumita', + 'Ankily', + 'Missouri City', + 'Partap Tanr', + 'Margarita', + 'Vandiperiyar', + 'Kaminokawa', + 'Goldach', + 'Viamao', + 'Nainpur', + 'Ya`bad', + 'Palhano', + 'Chhatapur', + 'Commune Sidi Youssef Ben Ahmed', + 'Jucati', + 'Con Dao', + "Al Bayda'", + 'Badhoevedorp', + 'San Rafael Oriente', + 'Ndulo', + 'Az Zulfi', + 'Ban San Pong', + 'Antioch', + 'Stoke-on-Trent', + 'Sahuli', + 'Asagi Ayibli', + 'Palukudoddi', + 'Chorfa', + 'Campos Novos', + 'Borim', + 'Hueytown', + 'Anuppur', + 'Port Lincoln', + 'Sertanopolis', + 'Cradock', + 'Winsford', + 'Bakhchysarai', + 'Spreitenbach', + 'Arese', + 'Buug', + 'Paruchuru', + 'Lower Swatara', + 'Vinica', + 'Pottsville', + 'Moncalieri', + 'Lamzoudia', + 'Crestwood', + 'Damongo', + 'Greece', + 'Utinga', + 'Niamtougou', + 'Kallayi', + 'Trogir', + 'Osmaneli', + 'Friendly', + 'Kanchanpur', + 'Hawera', + 'Carupano', + 'Nador', + 'Grand-Couronne', + 'Ogbomoso', + 'Sahagun', + 'Bridgwater', + 'Xicotepec de Juarez', + 'Durham', + 'Jerez de los Caballeros', + 'North Hykeham', + 'Stannington', + 'Ibanda', + 'Batac', + 'Logten', + 'Hoorn', + 'Roussillon', + 'Minzhu', + 'Blindio', + 'Mainz', + 'Catarman', + 'Lumberton', + 'Payabon', + 'Sangeorz-Bai', + "Pau d'Alho", + 'Honggu', + 'Sauk Rapids', + 'Ortaklar', + 'Thousand Oaks', + 'Kocani', + 'Kudangulam', + 'Chicoloapan', + 'De Meern', + 'Qiblai', + 'Montevista', + 'San Felipe Orizatlan', + 'Lakatoro', + 'Badia Polesine', + 'Bad Kissingen', + 'Bom Jesus do Itabapoana', + 'Erenler', + 'Katwijk', + 'Sao Francisco do Sul', + 'Lila', + 'Na Sceiri', + 'Perumbakkam', + 'Leling', + 'Gladstone', + 'Al `Aqabah', + 'Waregem', + 'Mulgund', + 'Ambolomadinika', + 'Osorno', + 'Gorgab', + 'Udaipur', + 'Khomam', + 'Sindalakkundu', + 'Toukountouna', + 'Chebba', + 'Pettampalaiyam', + 'Baile Atha Luain', + 'Nurobod Shahri', + 'Kropyvnytskyi', + 'Guarapari', + 'Caidat Sidi Boubker El Haj', + 'Ala-Buka', + 'Turin', + 'Bucharest', + 'Gingoog', + 'Youngsville', + 'Angwali', + 'Orikhiv', + 'Hofn', + 'Varzea da Palma', + 'Lower Makefield', + 'Chillicothe', + 'Seabrook', + 'Phetchaburi', + 'Fujisawa', + 'Matara', + 'Kepno', + 'Alden', + 'Omigawa', + 'Bayombong', + 'Toride', + 'Mirabela', + 'Tullukuttinayakkanur', + 'Ugong', + 'Zhangye', + 'Mangha', + 'Krsko', + 'Comrat', + 'Sudbury', + 'Almaty', + 'Sonamukhi', + 'Terrabona', + 'Windsor', + 'Coralville', + 'Capela', + 'Qufu', + 'Stallings', + 'Kingaroy', + 'Downham Market', + 'Calapan', + 'Aizuwakamatsu', + 'Kaintragarh', + 'Inhuma', + 'Pangururan', + 'Scotchtown', + 'La Marque', + 'Iwata', + 'Zrece', + 'Waldheim', + 'Ajmer', + 'Pamekasan', + 'Mafune', + 'Weiyuan', + 'Gunzburg', + 'Drohobych', + 'Damal', + 'Sigtuna', + 'Campulung', + 'Patancheruvu', + 'Gavardo', + 'Acushnet', + 'Poiana Mare', + 'Tarsus', + 'Betanzos', + 'Chau Doc', + 'Cacequi', + 'Lalsaraia', + 'Aweitancun', + 'Gia Rai', + 'Corat', + 'Arcos de la Frontera', + 'Akassato', + "Samch'ok", + 'Lake Tapps', + 'Aine Draham', + 'Vertou', + 'Neenah', + 'Tanhacu', + 'Shimla', + 'Keal', + 'Rani', + 'Kadaiyanallur', + 'Sefwi Wiawso', + 'Shankarpur Khawas', + 'Veliyangod', + 'Senador Guiomard', + 'Danzao', + 'Ndele', + 'Pornic', + 'Nowy Tomysl', + 'Scenic Oaks', + 'Ursulo Galvan', + 'Freudenberg', + 'Araruna', + 'Popayan', + 'Centereach', + 'Kamaishi', + 'Sainte-Marthe-sur-le-Lac', + 'Imilchil', + 'Zimapan', + 'Meschede', + 'Puthuppariyaram', + 'Paso de los Libres', + 'Longbenton', + 'Kampong Speu', + 'Novy Jicin', + 'Jinggang', + 'Asahi', + 'Khokri Kalan', + 'Kaveripatnam', + 'Lviv', + 'Bowling Green', + 'Braganca', + 'Panjgirain Kalan', + 'Emeryville', + 'Ruhango', + 'Tarim', + 'Castiglione del Lago', + 'Kyiv', + 'Mineral Wells', + 'Burnsville', + 'Franeker', + 'Teignmouth', + 'Canas', + 'Ajjampur', + 'Barhauna', + 'Zacharo', + 'Fujimi', + 'Billerica', + 'Falconara Marittima', + 'Alto Araguaia', + 'Tak Bai', + 'Bishops Cleeve', + 'Orhangazi', + 'Spokane Valley', + 'Kovel', + 'Walworth', + 'Zushi', + 'Aglasun', + 'Romainville', + 'Sorsogon', + 'Castellamonte', + 'Des Plaines', + 'Xai', + "'Ain Abid", + 'Plattekill', + 'Sinzheim', + 'Cipanas', + 'Paliaturutu', + 'Katwe', + 'Lorenskog', + 'San Tung Chung Hang', + 'Abrego', + 'Viana', + 'Ishtixon Shahri', + 'Kharika', + 'Sautron', + 'San Narciso', + 'Hilton Head Island', + 'Lingolsheim', + 'Bornheim', + 'Koregaon', + 'Matao', + 'Sumida', + 'Ketsch', + 'Gopalnagar', + 'Rodez', + 'Canelones', + 'Tolten', + 'Crawley', + 'Tillsonburg', + 'Wislane', + 'Mortsel', + 'Akitakata', + 'Halasztelek', + 'Herselt', + 'Kartal', + 'Balabac', + 'Ungaran', + 'Da', + 'Sao Joao del Rei', + 'Ghanipur Bejha', + 'Al Quway`iyah', + 'Zalaegerszeg', + 'Carquefou', + 'Huanimaro', + 'Ponte Nova', + 'Monte Azul', + 'Melito di Porto Salvo', + 'Shimenzhai', + 'Pinehurst', + "K'ebri Beyah", + 'Molsheim', + 'Konigstein im Taunus', + 'Taranagar', + 'Farciennes', + 'Bhilai', + 'Mathurapur', + 'Port-a-Piment', + 'Kyegegwa', + 'Ortakoy', + 'Antonibe', + 'Mercedes Umana', + 'Coronel', + 'Pedrinhas', + 'Suhagi', + 'Jaboatao dos Guararapes', + 'Oxon Hill', + 'Jalolquduq', + 'Morros', + 'Sumbas', + 'Chingola', + 'Rada Tilly', + 'Kolachel', + 'Bandarawela', + 'Pallattur', + 'Carauari', + 'Colares', + 'Santa Fe do Sul', + 'Musapur', + 'Arni', + 'Negage', + 'Graham', + 'Lake Grove', + 'Tolosa', + 'Marlboro', + 'Kandrawan', + 'Ponte Serrada', + 'Shanghai', + 'Ouedeme', + 'Saki', + 'Chembra', + 'Syston', + 'Palmeirais', + 'Borlange', + 'Bordj Bounaama', + 'Montceau-les-Mines', + 'Zhufeng', + 'Frei Paulo', + 'Western Springs', + 'Hemmingen', + 'Santa Cruz del Sur', + 'Pleasantville', + 'Chandla', + 'Maihma Sarja', + 'Sacaba', + 'Reynoldsburg', + 'Highland', + 'Sunyani', + 'Ajnala', + 'Ourem', + 'Zaltan', + 'Vannikkonendal', + 'Suchindram', + 'Metouia', + 'Bandar-e Lengeh', + 'Sestu', + 'Troisdorf', + 'Tibasosa', + "Villenave-d'Ornon", + 'Huseni', + 'Komorniki', + 'Ankerana', + 'Planura', + 'Saguenay', + 'Xiangping', + 'Almendralejo', + 'Slawno', + 'Bir Ghbalou', + 'Luna', + 'Tiaret', + 'Pulakurti', + 'General Santos', + 'Shibancun', + 'Lansing', + 'Lake Los Angeles', + 'Hala', + 'Port Washington', + 'Cortalim', + 'Apostoles', + 'Radnevo', + 'Reina Mercedes', + 'Tivoli', + 'Gomishan', + 'Maigh Nuad', + 'Gujiao', + 'Sorvagur', + 'Milpitas', + 'Ramnagar Bankat', + 'Longyearbyen', + 'Sarauni', + 'Angel R. Cabada', + 'Brooksville', + 'Bochaha', + 'Alguazas', + 'Tigaraksa', + 'Guiguinto', + 'Granbury', + 'Aiyetoro Gbede', + 'Zenica', + 'Itsoseng', + "Al Madrah Sama'il", + 'Murtajapur', + 'Gyongyos', + 'Kabale', + 'Armiansk', + 'Bandar-e Kong', + 'Makhambet', + 'Naval', + 'Issoudun', + 'Valmiera', + 'Virapandiyanpattanam', + 'Beirut', + 'Tagbilaran City', + 'El Factor', + 'Banikane', + 'Khartoum', + 'Jiangna', + 'Bhawanipatna', + 'Aungban', + 'Leonding', + 'Limeil-Brevannes', + 'Obernkirchen', + 'Nova Trento', + 'Zambezi', + 'Leith', + 'Gessate', + 'Huguan Nongchang', + 'Tirupati', + 'Cilimli', + 'Brie-Comte-Robert', + 'Cebu City', + 'Patti', + 'Germi', + 'Jaleshwar', + 'Piliscsaba', + 'Devipattinam', + 'Chato', + 'Khartoum North', + 'Brushy Creek', + 'Vlagtwedde', + 'Amacuzac', + 'Kosigi', + 'Aranjuez', + 'Leama', + 'Roanoke', + 'Limpio', + 'Kemalpasa', + 'Haisyn', + 'Peoria', + 'Stade', + 'In Guezzam', + 'Gashua', + 'Nerubaiske', + 'Ratlam', + 'Mahmutlu', + 'Srirampuram', + 'Veldurti', + 'Wemmel', + 'Phichit', + 'Dibaya-Lubwe', + 'Madurai', + 'Sao Goncalo do Para', + 'Vitry-le-Francois', + 'Anantarazupeta', + 'Boudinar', + 'Zschopau', + 'Quellon', + 'Longonjo', + 'Hexham', + 'Mangqu', + 'Hoxut', + 'Twickenham', + 'Gueckedou', + 'Labbaikkudikkadu', + 'Mittenwalde', + 'Hatton', + 'Feldbach', + 'Lahij', + 'Sasan', + 'Miastko', + 'Waitakere', + 'Shizuoka', + 'West Warwick', + 'Galati', + 'Biu', + 'Kudatini', + 'Viradouro', + 'Saffle', + 'Gyumai', + 'Zhongshan', + 'Picayune', + 'Antaly', + 'Anse-a-Veau', + 'Saint Peter Port', + 'Ambohitrolomahitsy', + 'Avadattur', + 'Calasiao', + 'Bambang', + 'Warder', + 'Koforidua', + 'Tangier', + 'Duggirala', + 'Glenville', + 'Bagrinagar', + 'Ingelmunster', + 'Carrigaline', + 'Ashtabula', + 'Galeras', + 'Ulchin', + 'Paarl', + 'Bandung', + 'Roxana', + 'Gulu', + 'Kesavapuram', + 'Beantake', + 'Yokoshiba', + 'Kaohsiung', + 'Piranguinho', + 'Port-de-Bouc', + 'Lakri', + 'Cadereyta Jimenez', + 'Merad', + 'Centralia', + 'Putte', + 'Baozhong', + 'Tougan', + 'Knutsford', + 'Estancia Velha', + 'Nawada', + 'Gangelt', + 'Frontignan', + 'Chiconcuac', + 'Gunnedah', + 'Lingen', + 'Bozmargi', + 'Porac', + 'St. Peter', + 'East Hempfield', + 'Tapalpa', + 'Jolfa', + 'Photharam', + '`Ajman', + 'Altunhisar', + 'Staufenberg', + 'Fgura', + 'Heist-op-den-Berg', + 'Colima', + 'Hoogstraten', + 'Oi', + 'Rustington', + 'Vandamettu', + 'Manzanares el Real', + 'Laohekou', + 'Szigethalom', + 'Colindres', + 'Harrow', + 'Kishanganj', + 'Brejo Santo', + 'Dalfsen', + 'Werdau', + 'Rijkevorsel', + 'Coondapoor', + 'Kagizman', + 'Pardi', + 'Paombong', + 'Pitseng', + 'Chikwawa', + 'Togou', + 'Akanavaritota', + 'Ojus', + 'Buhl', + 'Ganjing', + 'Sona', + 'Vayalpad', + 'Taishacho-kizukikita', + 'Ocoee', + 'Noda', + 'Nurdagi', + 'Maidan Shahr', + 'Culleredo', + 'Paravurkambolam', + 'Olintepeque', + 'Kien Giang', + 'Kunoy', + 'Zawyat Sidi al Mekki', + 'Aleksinac', + 'Mandalay', + 'La Laguna', + 'Kanabur', + 'San Miguel Panan', + 'Batumi', + 'Gambolo', + 'Cibitoke', + 'Swatara', + 'Ganga', + 'Cotorro', + 'Skofljica', + 'Piranhas', + 'Aricak', + 'Darb-e Behesht', + 'Ampana', + 'North Bellmore', + 'La Roche-sur-Yon', + 'Challapata', + 'Binghamton', + 'Hatod', + 'Gouveia', + 'Gardendale', + 'Newnan', + 'Le Haillan', + 'Lencois Paulista', + 'Dangriga', + 'Mallan', + 'Forest Park', + 'Chiyoda', + 'Pirenopolis', + 'Sao Joao do Piaui', + 'Mahavanona', + 'Hanzhong', + 'Madalag', + 'Los Osos', + 'Guatajiagua', + 'Berri', + 'Lardero', + 'El Jicaral', + 'Ter Apel', + 'Kola', + 'Vasteras', + "Al 'Attawia", + 'Pamplona', + 'Tomobe', + 'Bejaia', + 'Kullorsuaq', + 'Arganil', + 'Comapa', + 'Dehqonobod', + 'Gaoping', + 'Buntok', + 'Somerton', + 'Herstal', + 'Igualada', + 'Tumaco', + 'Saint Joseph', + 'Mandeville', + 'Monterrey', + 'Jamindan', + 'Nguti', + 'Sidi Lahssen', + 'Redruth', + 'Akcakoca', + 'Jankampet', + 'Tataouine', + 'Manizales', + 'Narasannapeta', + 'Karempudi', + 'St. Augustine', + 'Cumanayagua', + 'Montesilvano', + 'Gracias', + 'Congaz', + 'Poso', + 'Humenne', + 'Shalqar', + 'Lago Ranco', + 'Morogoro', + 'Qingan', + 'Anini-y', + 'Marche-en-Famenne', + 'Erseke', + 'Presidente Venceslau', + 'Abomey', + 'Dorohoi', + 'Talipparamba', + 'Bonito', + 'Algarrobo', + 'Yamoussoukro', + 'Lafey', + 'Kadi', + 'Beberibe', + 'Yurihama', + 'Viana do Castelo', + 'Assen', + 'Sniatyn', + 'Spanish Fort', + 'Xintianfeng', + 'Bukungu', + 'Xiaqiaotou', + 'Peshtera', + 'Hueyapan de Ocampo', + 'Marreddipalli', + 'Kaimati', + 'Isabela', + 'Selfoss', + 'Delhi', + 'Fujikawaguchiko', + 'Marutharod', + 'Bom Repouso', + 'Jagadhri', + 'El Valle', + 'Zlotoryja', + 'Grover Beach', + 'Hashtpar', + 'San Alejo', + 'Nazarje', + 'Hillcrest', + 'Sananduva', + 'Peissenberg', + 'Bada Barabil', + 'Watampone', + 'Nove Mesto nad Metuji', + 'Karankot', + 'Pucon', + 'Guangshui', + 'Falls Church', + 'Danihe', + 'Mudakkiraye', + 'Ceuti', + 'Fussen', + 'Zaghouan', + 'Yongbei', + 'Hong Ngu', + 'Conchas', + 'Manivilundan', + 'Tadhwa Nandpur', + 'Monistrol-sur-Loire', + 'Chateaubriant', + 'Sangar', + 'Fafe', + 'Shoshong', + 'Madang', + 'Marcy', + 'Puttlingen', + 'Groves', + 'Al Bahah', + 'Gorham', + 'Afogados da Ingazeira', + 'Knokke-Heist', + 'Pariyaram', + 'Zagreb', + 'Winton', + 'Les Iles-de-la-Madeleine', + 'Kusterdingen', + 'Paraguari', + 'Kuknur', + 'Black River', + 'Baishaling', + 'Sigulda', + 'Uppsala', + 'Selm', + 'Muy Muy', + 'Paracale', + 'Luleburgaz', + 'La Llagosta', + 'Demirci', + 'Kalasin', + 'Ibajay', + 'Ceska Lipa', + 'Camocim de Sao Felix', + 'Ogose', + 'Menlo Park', + 'Ouedo-Agueko', + 'Karakurisshi', + 'Franklin Lakes', + 'Ismayilli', + 'Gottingen', + 'Melmadai', + 'Meulaboh', + 'Ogre', + 'Bad Abbach', + 'Longmen', + 'Awka', + 'Braco do Norte', + 'Bigadic', + 'General Pacheco', + 'Sint-Oedenrode', + 'Annamalainagar', + 'Angamali', + 'Julio de Castilhos', + 'Capao Bonito', + 'Poynton', + 'Santa Cruz Atizapan', + 'Ekeren', + 'Gandara West', + 'Metairie', + 'Katsuren-haebaru', + 'Dupnitsa', + 'Tricase', + 'Mokpo', + 'Dassari', + 'Givatayim', + 'Jambai', + 'Hamsavaram', + 'Foggia', + 'Scott', + 'Inkhil', + 'Catamayo', + 'Nana', + 'Ntchisi', + 'Olomouc', + 'Madison Heights', + 'Genzano di Roma', + 'Vieux Fort', + 'Kagvad', + 'Motegi', + 'Breves', + 'Myitkyina', + 'Aqkol', + 'Al `Ashir min Ramadan', + 'Ariano Irpino', + 'Restrepo', + 'Jeumont', + 'Drazinda', + 'San Pedro de Ribas', + 'Chintakommadinne', + 'Tank', + 'Preili', + 'Konakli', + 'Julita', + 'Meda', + 'Ciudad Obregon', + 'Barabai', + 'Gizycko', + 'Boureit', + 'Arambagh', + 'Bonito Oriental', + 'Mbanga', + 'Chemmanam', + 'Kakira', + 'Mundka', + 'Noniya', + 'Marianske Lazne', + 'Khanaqin', + 'Pajacuaran', + 'Ain el Bya', + 'Bacliff', + 'Sewari', + 'Altusried', + 'Zinapecuaro', + 'Matsuo', + 'Vasylivka', + 'Peda-Houeyogbe', + 'Nossa Senhora dos Remedios', + 'Chaltabaria', + 'Hailakandi', + 'Poznan', + 'Taoudenni', + 'Sidhwan', + 'Guadalajara de Buga', + 'Rozhyshche', + 'Caracarai', + 'Suwannaphum', + "Bur Fu'ad", + 'Fderik', + 'Mezotur', + 'Las Vegas', + 'Limassol', + 'Jursinci', + 'Taggia', + 'Poco das Trincheiras', + 'Douar Oulad Naoual', + 'Calarca', + 'Mont-Tremblant', + 'Belterra', + 'Sheikhpura', + 'North Olmsted', + 'Ramdurg', + 'Orumanayur', + 'Villafranca de los Barros', + 'Esztergom', + 'Payakaraopeta', + 'Ramchandrapur', + 'Khajamahalpur', + 'Najafgarh', + 'Athni', + 'Mikkelin Maalaiskunta', + 'Bijnor', + 'Ighram', + 'Dragash', + 'Thargomindah', + 'Castel Maggiore', + 'Belambo', + 'Nueva Palmira', + 'Kurabur', + 'Yahsihan', + 'Chesterton', + 'Konduru', + 'Tordesillas', + 'Biala Podlaska', + 'Katsuragi', + 'South Bradenton', + 'Naranja', + 'Okhmalynka', + 'Newtownards', + 'Pimenta Bueno', + 'Naraura', + 'Craponne', + 'Auta', + 'Kumaravadi', + 'Anajas', + 'Mouiat Ouennsa', + 'Norvenich', + 'Jaruco', + 'Stockelsdorf', + 'Moron de la Frontera', + 'Dalmine', + 'Le Pont-de-Claix', + 'Ambahy', + 'Fianga', + 'Pinecrest', + 'San Bonifacio', + 'Carpinteria', + 'Stip', + 'Ergolding', + 'Lokossa', + 'Siniloan', + 'Seeheim-Jugenheim', + 'Nottingham', + 'Abrantes', + 'San Felipe Jalapa de Diaz', + 'Boninal', + 'Digor', + 'Hosur', + 'Trepuzzi', + 'Koidu', + 'Kumta', + 'Paracatu', + 'Shinkai', + 'Thuan An', + 'Pokaran', + 'Betzdorf', + 'Binde', + 'Ghazni', + 'Vembur', + 'Pontivy', + 'Juterbog', + 'Sheerness', + 'Chhindwara', + 'Alagoinhas', + 'Itabira', + 'San Jose Ojetenam', + 'Mazatenango', + 'Nabinagar', + 'Manavgat', + 'Ovenden', + 'Lagkadas', + 'Gaildorf', + 'Chirpan', + 'Vidalia', + 'Maracaju', + 'Pindwara', + 'Nova Dubnica', + 'Mokarrampur', + 'Bocaue', + 'Warsop', + 'Florida', + 'Gangajalghati', + 'Monte Alegre do Sul', + 'Kibi', + 'Pirakkad', + 'Bani `Ubayd', + 'Tiberias', + 'Palombara Sabina', + 'Rongat', + 'Wabagai', + 'Maceio', + 'Agliana', + 'Bell', + 'Yosano', + 'Potiragua', + 'Mannamangalam', + 'Yerevan', + 'Valledupar', + 'Faversham', + 'Xavantes', + 'Embrach', + 'Desanagi', + 'Ciudad de Ceuta', + 'Contagem', + 'As Sib', + 'Kulgam', + 'Kanigiri', + 'Kuljibrin', + 'Palm Beach Gardens', + 'Mugnano di Napoli', + 'Chunian', + 'Merzig', + 'Dhilwan Kalan', + 'Stainz', + 'Betera', + 'Vallur', + 'Seva', + 'Puerto Lopez', + 'Inekar', + 'Suong', + 'Tiruvottiyur', + 'Baghlan', + 'Ilo', + 'Bautzen', + 'Koutiala', + 'Allahabad', + 'Lhokseumawe', + 'San Juan del Sur', + 'Taua', + 'Sapa Sapa', + 'Otuke', + 'Sabra', + 'Kutahya', + 'Coccaglio', + 'Mamun', + 'Billerbeck', + 'Weil am Rhein', + 'Lajia', + 'Argentan', + 'Ninheira', + 'Aranya Kalan', + 'Lumding', + 'Comendador Levy Gasparian', + 'Lilongwe', + 'Cerro Largo', + 'Oosterhout', + 'Oswestry', + 'Gaspar', + 'Videle', + 'Maumelle', + 'Azezo', + 'Osuna', + 'Pulla', + 'Yangshuling', + 'Khirkiyan', + 'Hamilton', + 'Kalgoorlie', + 'Rejiche', + 'Aylesford', + 'Nagaoka', + 'Monterey Park', + 'Potavaram', + 'Jequeri', + 'Boisbriand', + 'Meliana', + 'Quilenda', + 'Santa Leopoldina', + 'Lakeland', + 'Eatontown', + 'Basilisa', + 'Wernau', + 'Sassenheim', + 'Twistringen', + 'Talitay', + 'East Wenatchee', + 'Jinbi', + '`Anbarabad', + 'Shimanto', + 'Caputira', + 'Goppingen', + 'Turuttikkara', + 'Zhongtai', + 'San Francisco Zapotitlan', + 'Hazebrouck', + 'Clemencia', + 'Surandai', + 'Khijri', + 'Jacarezinho', + 'Lunsar', + 'Ouled Sidi Brahim', + 'Chaqra', + 'Distraccion', + 'Eppelborn', + 'Vakhrusheve', + 'San Carlos del Zulia', + 'Khairpur Tamewah', + 'Shongzhy', + 'Ban Bang Kaeo', + 'Murillo', + 'Ban Mai', + 'Lakoucun', + 'Kottaikuppam', + 'Sini', + 'Karditsa', + 'Penumur', + 'Ramos', + 'Arauco', + 'Chatayamangalam', + 'Nieuw-Lekkerland', + 'Ixhuatlan del Sureste', + 'Bog Walk', + 'Daltonganj', + 'Guamo', + 'Kiklah', + 'Bongouanou', + 'Las Pinas City', + 'Narni', + 'Olesa de Montserrat', + 'Barrancabermeja', + 'Souama', + 'Sokolow Podlaski', + 'Katakwi', + 'Sunset', + 'Dilawarpur', + 'Telagh', + 'Caapiranga', + 'Pavittiram', + 'Yunzhong', + 'Paicandu', + 'Farafangana', + 'Zawyat Sidi Ben Hamdoun', + 'Bosilegrad', + 'Cabanaquinta', + 'Eaubonne', + 'El Paujil', + 'Matca', + 'Rawdon', + 'Tongoma', + 'Monsefu', + 'Itaguara', + 'Mihama', + 'Alengad', + 'Zhumadian', + 'Schlieren', + 'Murree', + 'Seto', + 'Yenipazar', + 'Kharak Kalan', + 'Ambares-et-Lagrave', + 'Kawlin', + 'Sainte-Julienne', + 'Khagaul', + 'Dyersburg', + 'Ekuvukeni', + 'Virginopolis', + 'Zhenzhou', + 'Jiashizhuangcun', + 'Changchong', + 'Notodden', + 'Stephenville', + 'Rellingen', + 'Keolari', + 'Los Alcarrizos', + 'Brake', + 'Yuzawa', + 'Cabatuan', + 'Kanegasaki', + 'Vohiposa', + 'Arequipa', + 'Antseza', + 'Puspokladany', + 'Natick', + 'Astrea', + 'Auchel', + 'Aquidauana', + 'Mohlin', + 'Redcar', + 'Brookline', + 'Jekabpils', + 'Melville', + 'Pintadas', + 'Manfalut', + 'Aasiaat', + 'Sao Borja', + 'Ransiki', + 'Ibipetuba', + 'Kuala Lumpur', + "Tong'anyi", + 'Eklahra', + 'Satara', + 'Pupri', + 'Gualcince', + 'Friedberg', + 'Sinnai', + 'Saynshand', + 'Bupoto', + 'Kalanjur', + 'Hilversum', + 'Shobara', + 'Mahaplag', + 'Puturge', + 'Oued Jdida', + 'Melnik', + 'Pointe-Noire', + 'Tipton', + 'Tekari', + 'Ounagha', + 'Cavriago', + 'Lupon', + 'Paoay', + 'Follonica', + 'Bhachhi Asli', + 'Hofheim', + 'Kasukabe', + 'Viligili', + 'Tinton Falls', + 'Limay', + 'Pauktaw', + 'Sedziszow Malopolski', + 'Citrus', + 'Chirongui', + 'Mitane', + 'Payimattam', + 'Pajaros', + 'Gelves', + 'Tupi Paulista', + 'Pokhuria', + 'Thetford Mines', + 'Iselin', + 'Bandar Murcaayo', + 'Taungoo', + 'Hikawadai', + 'Los Santos', + 'Marbella', + 'Vranje', + 'Squamish', + 'Mahthi', + 'Toura', + 'Cicciano', + 'Wernigerode', + 'Xiaobazi', + 'Reforma', + 'Ispir', + 'Ntcheu', + 'Samboan', + 'Kelamangalam', + 'Diglipur', + 'Malkhaid', + 'Tomakomai', + 'Vidhareidhi', + 'Rio Grande City', + 'Puerto Libertador', + 'Ariccia', + 'Mashhad', + 'Renkum', + 'Sakabansi', + 'Dandeli', + 'Gahanna', + 'Waupun', + 'Sonoma', + 'Kutchan', + 'Phetchabun', + 'Bischwiller', + 'Barotac Viejo', + 'Giresun', + 'Caieiras', + 'Rodeiro', + 'Guabo', + 'Kusti', + 'Ketou', + 'Oestrich-Winkel', + 'Cayce', + 'Sume', + 'Yaese', + 'Zemamra', + 'Spring Garden', + 'Sheron', + 'Karnawad', + 'Neu-Ulm', + 'Grafelfing', + 'Costa Mesa', + 'Wangjia', + 'Joaquim Gomes', + 'Al Qurnah', + 'Naivasha', + 'Borgerhout', + 'Santa Rosalia', + 'Corocoro', + 'Liskeard', + 'Kruibeke', + 'Mingaora', + 'Latauna', + 'Sepolno Krajenskie', + 'Madison', + 'Berkane', + 'San Giovanni Rotondo', + 'Siwah', + 'Aldeia de Paio Pires', + 'Krosno Odrzanskie', + 'Zriba-Village', + 'Tampico', + 'Gastre', + 'Katrineholm', + 'Joao Pinheiro', + 'Martensville', + 'Karakocan', + 'San Antero', + 'Pocinhos', + 'Erravaram', + 'Ogaki', + 'Ezzhiliga', + 'Dimmbal', + 'Torul', + 'Darlaston', + 'Itapissuma', + 'Mragowo', + 'Buton', + 'Villach', + 'Xinzhancun', + 'Rusape', + 'Ialoveni', + 'Biltine', + 'Alukkuli', + 'Panpuli', + 'Barili', + 'Kempen', + "`Alem T'ena", + 'Wustermark', + 'Murnau am Staffelsee', + 'El Ghomri', + 'Kambhaladinne', + 'Ciego de Avila', + 'Khoragachhi', + 'Tiburon', + 'Ohata', + 'San Martin Zapotitlan', + 'Priego de Cordoba', + "Mun'gyong", + 'Placetas', + 'Comodoro Rivadavia', + 'Goluwali', + 'Janglot', + 'Ammanford', + 'Juquia', + 'Parapua', + 'Mitchell', + 'Lincoln', + 'Kafr Sa`d', + 'Dhanwada', + 'Vergiate', + 'Son Servera', + 'Uto', + 'Gesuba', + 'Jamaat Shaim', + 'Basirhat', + 'Dalain Hob', + 'Bishenpur', + 'Regensburg', + 'Altensteig', + 'Kekem', + 'Sanwal', + 'Palankottai', + 'Raquira', + 'Antsahanoro', + 'Cerignola', + 'Beesel', + 'Burj al `Arab', + 'Rantepao', + 'Ankadindambo', + 'Jinotega', + 'Hechingen', + 'Ingersoll', + 'Vitoria da Conquista', + 'Parma', + 'Vaciamadrid', + 'Daita', + 'Santa Catarina Juquila', + 'Kozje', + 'Hagen', + 'Pargi', + 'Porto Nacional', + 'Krishnarajpur', + 'Huazangsi', + 'Blida', + 'Majra', + 'Sahasoa', + 'Inzai', + 'Murrysville', + 'Jalalpur', + 'Belakoba', + 'Ichalkaranji', + 'Almagro', + 'Vassouras', + 'Taubate', + 'Sarrat', + 'Jupiter', + 'Icara', + 'Avrankou', + 'Brick', + "Giv`at Shemu'el", + 'Bargarh', + 'Wang Tau Hom', + 'Teixeira', + 'Darmstadt', + 'Kasuya', + 'Periya Pattanam', + 'Dangbo', + 'El Viejo', + 'Xapuri', + 'Woodbury', + 'Pampatar', + 'Waspan', + 'Samabouro', + 'Al Ahad al Masarihah', + 'Koath', + 'Gwanda', + 'Vinhais', + 'Islahiye', + 'Mogpog', + 'Bayt Jala', + 'Nagireddipalli', + 'Miami Beach', + 'Conversano', + 'Quartier Militaire', + 'Cauto Cristo', + 'Arhribs', + "Villa O'Higgins", + 'Orange Walk', + 'Dharmavaram', + 'Paraiso do Tocantins', + 'Calolziocorte', + 'Capitan Sarmiento', + 'Tyagadurgam', + 'Vendram', + 'Harstad', + 'Caldogno', + 'Tlaxcoapan', + 'Jiangjiafan', + 'Arta', + 'Jacona de Plancarte', + 'Sarpol-e Zahab', + 'Nahuala', + 'Boa Esperanca', + 'Mealhada', + 'Troutdale', + 'Wharton', + 'Tournon-sur-Rhone', + 'Casino', + 'Saint-Lin--Laurentides', + 'Jaco', + 'Evander', + 'Figeac', + 'Elukone', + 'Camocim', + 'Sahpur', + 'Lower Tungawan', + 'Vengur', + 'Miraima', + 'Ximeicun', + 'Hoogland', + 'Weimar', + 'Kokkola', + 'Atiquizaya', + 'Oldenburg in Holstein', + 'Kulattuppalaiyam', + 'Ramada', + 'Itampolo', + 'Bommarbettu', + 'Piove di Sacco', + 'Kanavaypatti', + 'Ise', + "Oktyabr'sk", + 'Tigzirt', + 'Oulad Amrane', + 'Kundal', + 'Cheria', + 'Kalchini', + 'Dschang', + 'Bentiu', + 'Emboscada', + 'Sangram', + 'Plerin', + 'Kezi', + 'Grobenzell', + 'Tomino', + 'Santa Cruz do Rio Pardo', + 'Isorana', + 'Al Qbab', + 'Sleepy Hollow', + 'Dehloran', + 'Taixi', + 'Noamundi', + 'Ankilimalinika', + 'Hwasu-dong', + 'San Bruno', + 'Dijon', + 'Yiyang', + 'Guntakal', + 'Suluova', + 'Kottacheruvu', + 'Ludwigshafen', + 'Ghargaon', + 'Rosa', + 'Sual', + 'Miller Place', + 'Dronten', + 'Dobbs Ferry', + 'Santa Marta', + 'Khopoli', + 'Kelilalina', + 'Bela Cruz', + 'Klela', + 'Santomera', + 'Chortoq', + 'Kemp Mill', + 'Mae Rim', + 'Yalvac', + 'Meridiala', + 'Itaporanga', + 'Macerata Campania', + 'Maxeville', + 'Sierra Colorada', + 'Ginatilan', + 'Fortaleza', + 'Tenmalai', + 'Oyonnax', + 'Taishi', + 'Krapkowice', + 'Sojitra', + "Alamat'a", + 'Flemalle-Haute', + 'Jeannette', + 'Edessa', + 'Fairview Park', + 'Pabianice', + 'An Nayrab', + 'Gussago', + 'Aridagawa', + 'Inebolu', + 'Ponte Buggianese', + 'Comallo', + 'Handeni', + 'Kadogawa', + 'Vesala', + 'Santana do Manhuacu', + 'Vicente Guerrero', + 'Trnovska Vas', + 'Franklin Square', + 'Hessle', + 'Tuvur', + 'Les Mureaux', + 'Rikuzen-Takata', + 'Shahmirzad', + 'Irshava', + 'Almirante Tamandare', + 'Bhairapura', + 'Grand Forks', + 'Adolfo Gonzales Chaves', + 'Donmatias', + 'Jobat', + 'Jami', + 'Norfolk', + 'Kasagi', + 'Senador Canedo', + 'Bhabanipur', + 'Danville', + 'Guaraciaba do Norte', + 'Perez', + 'Akaiwa', + 'Santa Cruz do Monte Castelo', + 'Deerlijk', + 'Key West', + 'Somandepalle', + 'Bartoszyce', + 'Tsuiki', + 'Hillegom', + "Qa'emiyeh", + 'Sahidganj', + 'Terrier Rouge', + 'Marikina City', + 'Vinzons', + 'Makouda', + 'Conceicao da Barra', + 'Tebesbest', + 'Hachinohe', + 'Carora', + 'Luckeesarai', + 'Castelo', + 'Bommagondanahalli', + 'Kutavur', + 'Bedworth', + 'Laarne', + 'East Grand Rapids', + 'Itatiba', + 'Pineville', + 'Banhatti', + 'Thiotte', + 'San Martin de las Piramides', + 'Puconci', + 'Saidpur Dabra', + 'Xaghra', + 'Zhuhai', + 'Altamonte Springs', + 'Warminster', + 'Zollikon', + 'Patiala', + 'Oxted', + 'Gornja Radgona', + 'Bade', + 'Dahe', + 'Risca', + 'Puxinana', + 'Mixtla de Altamirano', + 'Haderslev', + 'Sun Village', + 'Mahazoarivo', + 'Asara', + 'Tortosa', + 'Bellmead', + 'San Marino', + 'Khrestivka', + 'Usuki', + 'Yasynuvata', + 'North Valley', + 'Chennur', + 'Bishnupur', + 'Fanzhao', + 'Oltinko`l', + 'El Carmen', + 'Lagawe', + 'Argentona', + 'Torgau', + 'Tiflet', + 'Xincun', + 'Thap Khlo', + 'Havant', + 'Sulingen', + 'Apt', + 'Sabana de Torres', + 'Qyzylorda', + 'Hebburn', + 'Katerini', + 'Werota', + 'Taishan Houcun', + 'Zefyri', + 'Akseki', + 'Nkawkaw', + 'Sabangan', + 'West Sacramento', + 'Calandala', + 'Charcas', + 'Ash Shaykh `Uthman', + 'Mahajeran-e Kamar', + 'Toundout', + 'Mainvilliers', + 'Kronach', + 'Jayal', + 'Ruthen', + 'Kamenz', + 'Cayirova', + 'Temple', + 'Sammamish', + 'Agstafa', + 'Gleno', + 'Sattahip', + 'Kichha', + 'Tartagal', + 'Pingliang', + 'Ganvie', + 'Zapotiltic', + 'Temsamane', + 'Gyegu', + 'Shangqiu', + 'Niquen', + 'Baotou', + 'Orzesze', + 'Ghanzi', + 'Manikkal', + 'Zaraza', + 'Sarbisheh', + 'Mabehiri', + 'Clitheroe', + 'Jastrebarsko', + 'Frydek-Mistek', + 'Taxila', + 'Valencia West', + 'Ambalaroka', + 'Fouriesburg', + 'Ojuelos de Jalisco', + 'Saurimo', + 'Bereket', + 'Ledbury', + 'Lenexa', + 'Bakhor', + 'Come', + 'Tonk Khurd', + 'Chak Jhumra', + 'Qarah', + 'Macaparana', + 'Dormagen', + 'Kamirenjaku', + 'Nhlangano', + 'Loughton', + 'Carcarana', + 'Bahawalpur', + 'Hengshui', + 'Pointe-a-Pitre', + 'Louvain-la-Neuve', + 'Lindong', + 'Elsfleth', + 'Gangavalli', + 'Aguelmous', + 'Termas de Rio Hondo', + 'Nueva Paz', + 'Karuvellur', + 'Dholka', + 'Dishashah', + 'Neropolis', + 'Ourilandia do Norte', + 'Gorna Oryahovitsa', + 'Dangyang', + 'Raiganj Bazar', + 'Piliv', + 'Chosei', + 'Chambas', + 'Ringwood', + 'Bongaigaon', + 'Polignano a Mare', + 'Naranda', + 'Mondai', + 'Babadag', + 'Nattam', + 'Crosne', + 'Ananipalle', + 'Sorata', + 'Collipulli', + 'Famenin', + 'Waddinxveen', + 'Koratgi', + 'Mojokerto', + 'Moreno Valley', + 'Baltit', + 'Wokha', + 'Salzwedel', + 'Shangtangcun', + 'Stahnsdorf', + 'Jetpur', + 'Vellallur', + 'Drouin', + 'Tochigi', + 'Kaniyambadi', + 'Aran Bidgol', + 'Park Ridge', + 'Ammon', + 'Guipavas', + 'Miaoli', + 'Monchengladbach', + 'Sulahpet', + 'McMinns Lagoon', + 'Palangotu Adwar', + 'Delray Beach', + 'Singura', + 'Oakland Park', + 'Goonellabah', + 'Drezdenko', + 'Athurugiriya', + 'Aizumi', + 'Maria la Baja', + 'Toshloq', + 'Pale', + 'Burhar', + 'Murrieta', + 'Loufan', + 'Kibungo', + 'Doi Lo', + 'New Bedford', + 'Srinivaspur', + 'Atru', + 'Mataili Khemchand', + 'Ashibetsu', + 'Hansi', + 'Bacong', + 'Rukhae', + 'Kosching', + 'Addison', + 'Rangpur', + 'Toppenish', + 'Eyvanekey', + 'Girardot', + 'Piravanthur', + 'Korem', + 'Porto Torres', + 'Lagoa Grande', + 'Aratuba', + 'Hadithah', + 'Bel Air South', + 'Buluko', + 'Ambala', + 'Baie du Tombeau', + 'El Cairo', + 'Caluire-et-Cuire', + 'Caluya', + 'Ponedera', + 'Ban Bang Mae Nang', + 'Leer', + 'Kissing', + 'Shamalgan', + "'s-Heerenberg", + 'Miguel Calmon', + 'Bar', + 'Birak', + 'Igana', + 'Onnaing', + 'Sveta Trojica v Slovenskih Goricah', + 'Boca do Acre', + 'Amaravati', + 'Dhulkot', + 'Joubb Jannine', + 'Edeia', + 'Toda', + 'Okinoshima', + 'Murra', + 'East Renton Highlands', + 'Badshahpur', + 'Lalgudi', + 'Bomareddipalli', + 'Curaca', + 'Zetale', + 'Yuci', + 'Levittown', + 'Linbian', + 'Toyooka', + 'Krugersdorp', + 'Northfleet', + 'McKee City', + 'Atescatempa', + 'Dundo', + 'Sarableh', + 'Santo Domingo', + 'Lucca', + 'Le Chambon-Feugerolles', + 'Kanyato', + 'Sokoura', + 'Ponte de Lima', + 'Kafr Laha', + 'Covenas', + 'Shchastia', + 'Bamenda', + 'Tolmin', + 'Ottakkadai', + 'Palmetto Bay', + 'Castrop-Rauxel', + 'Barra dos Coqueiros', + 'Mahdishahr', + 'Angra do Heroismo', + 'Chulucanas', + 'Haslev', + 'Cahul', + 'Luocheng', + 'Asyut', + 'Muping', + 'Country Club Hills', + 'Ambondro', + 'Nakayama', + 'Boljevac', + 'Chaman', + 'Birqash', + 'Ghat', + 'Cungus', + 'Cuyapo', + 'Kissane Ltouqi', + 'Mexborough', + 'Mansinghpur Bijrauli', + 'Komlo', + 'Boissy-Saint-Leger', + 'Sabinopolis', + 'Talkhvoncheh', + "'s-Gravendeel", + 'Malkara', + 'Glace Bay', + 'San Andres Sajcabaja', + 'Pforzheim', + 'Wombwell', + 'New Hanover', + 'Schneverdingen', + 'Vidisha', + 'Neubiberg', + 'Banu Chhapra', + 'Pamidi', + 'Benkovac', + 'Cocoa', + 'Stawell', + 'Saint-Quentin', + 'Northdale', + 'Clermont', + 'Don Torcuato', + 'Hanchuan', + 'Hessisch Lichtenau', + 'Jena', + 'Tursunzoda', + 'Avintes', + 'Burela de Cabo', + 'Gladenbach', + 'Myszkow', + 'Quiroga', + 'Azove', + 'Sao Geraldo', + 'Penrith', + 'Arenapolis', + 'Miyada', + 'Jurbarkas', + 'Matias Olimpio', + 'Bindki', + 'Ditzingen', + 'Babaeski', + 'Lyngdal', + 'Baarn', + 'Xinmin', + 'Sondho Dullah', + 'San Onofre', + 'Halawah', + 'Soran', + 'Suihua', + 'Perere', + 'Ban Thum', + 'Massy', + 'Delta', + 'Qom', + 'Eldoret', + 'Tournavista', + 'Cangas', + 'Juchen', + 'Pattikonda', + 'Cacuaco', + 'Kamisato', + 'Ilarionove', + 'Spijkenisse', + 'Anavatti', + 'Seringueiras', + 'Beipiao', + 'Kouribga', + 'Kirangur', + 'Bismarck', + 'Ahaus', + 'Barajor', + 'Canta', + 'Sierre', + 'Gopalpur', + 'Fremont', + 'Baixa Grande', + 'Apolo', + 'Xigujing', + 'Vevcani', + 'Madhura', + 'Feucht', + 'Fehmarnsund', + 'Cesme', + 'Nerviano', + 'Brownsweg', + 'Baynala', + 'Ky Anh', + 'Khunti Dhanaili', + 'Arjona', + 'Ciudad Sandino', + 'Lyantonde', + 'Pililla', + "Santa Croce sull' Arno", + 'Liangshi', + 'Pirkkala', + 'Saligrama', + 'Odugattur', + 'Pullanvidudi', + 'Fort Irwin', + 'Veliko Gradiste', + 'Culiacan', + 'Singa', + "Conde-sur-l'Escaut", + 'North Fort Myers', + 'Martinez', + 'Raisinghnagar', + 'Heubach', + 'Accokeek', + 'Citta di Castello', + 'Sint-Genesius-Rode', + 'Iruma', + 'Curico', + 'Pitlam', + 'Niamey', + 'Araci', + 'Zaozhuang', + 'Az Zahiriyah', + 'Takouta', + 'Douar Bouchfaa', + 'Mirna', + 'Aron', + 'Firminopolis', + 'Niederwerrn', + 'Chandi', + 'Parana', + 'Bom Jesus do Galho', + 'Boussu', + 'General Nakar', + 'Elancourt', + 'Tirodi', + 'Cosenza', + 'Sooke', + 'Alga', + 'Duruma', + '`Amuda', + 'Aburi', + 'Short Hills', + 'Haripura', + 'Granada', + 'The Mumbles', + 'Yadavolu', + 'East Honolulu', + 'Vellalapuram', + 'Boufarik', + 'Oer-Erkenschwick', + 'Terkuvenganallur', + 'Orodara', + 'Didouche Mourad', + 'Stapleford', + 'Iles', + 'Cantilan', + 'Kennebunk', + 'Urasoe', + 'Singosari', + 'Onda', + 'Rushall', + 'Bukhara', + 'Ibbenburen', + 'Epsom', + 'Glendale Heights', + 'Ubai', + 'Chatra', + 'Ranavav', + 'Chevilly-Larue', + 'Kemijarvi', + 'Ungoofaaru', + 'Zaouiat Moulay Bouchta El Khammar', + 'Vinaninkarena', + 'Zaleze', + 'Zelenikovo', + 'Newfane', + 'Langedijk', + 'Orly', + 'Berchha', + 'Guimba', + 'Gamboula', + 'Alakamisy Itenina', + 'Alotau', + 'Sothgaon', + 'Bockum', + 'Sawai Madhopur', + 'Lahan', + 'Santa Ignacia', + 'Modesto', + 'Jales', + 'Baragaon', + 'Huarmey', + 'North Ridgeville', + 'Kolomyia', + 'San Martin de los Andes', + 'Saboeiro', + 'Bucay', + 'Xexeu', + 'Santo Stino di Livenza', + 'Boca Chica', + 'Keskin', + 'Namtu', + 'Nyenga', + 'Carlow', + 'Medemblik', + 'Cadoneghe', + 'Hagondange', + 'Zozocolco de Hidalgo', + 'Desamparados', + 'Bengonbeyene', + 'Bou Zemou', + 'Bellary', + 'Bremen', + 'Fitzgerald', + 'Finale Emilia', + 'Bilgi', + 'Starobilsk', + 'Korangal', + 'Ingeniero Maschwitz', + 'Akat Amnuai', + 'Afua', + 'Dondon', + 'Dhangaraha', + 'Avellaneda', + 'Castelfranco di Sopra', + 'Bang Racham', + 'Bisaul', + 'Persan', + 'Palaw', + 'Manja', + 'Lindesberg', + 'Halton Hills', + 'Mandaon', + 'Ratingen', + 'Staszow', + 'Sitakili', + 'Niebull', + 'Malabo', + 'Berceni', + 'Floha', + 'Wiltz', + 'Anamoros', + 'Banqiao', + 'Afgooye', + 'Druzhba', + 'Montevrain', + 'Socopo', + 'Logatec', + 'Prestatyn', + 'Lodhikheda', + 'Phuket', + 'Berriozabal', + 'Puan', + 'Brooklyn', + 'Casma', + 'New Square', + 'Lake Station', + 'San Juan de Rio Coco', + 'Korydallos', + 'Cubatao', + 'Stidia', + 'Kalamansig', + 'Amstetten', + 'Ventersburg', + 'Khovaling', + 'Millburn', + 'Halba', + 'Tenggarong', + 'Stelle', + 'Bacup', + 'Cacak', + 'Khamanon Kalan', + 'Fanyang', + 'Patikul', + 'Igarassu', + 'Lakeland Village', + 'Sanxing', + 'Kongsberg', + 'Harelbeke', + 'Chintalapudi', + 'Chinna Ganjam', + 'Utena', + 'Carai', + 'Calcoene', + 'Salgar', + 'Maardu', + 'Tarhunah', + 'Breaza', + 'Villamontes', + 'Vadakakarai', + 'Jaidte Lbatma', + 'Chautapal', + 'Dois Corregos', + 'Mahmudabad Nemuneh', + 'Raul Soares', + 'Walker Mill', + 'Qiaoyang', + 'Alachua', + 'Nailsea', + 'Ipaumirim', + 'Wakabadai', + 'Sebt Labrikiyne', + 'Anupshahr', + 'Calinog', + 'Hammamet', + 'Famagusta', + 'Norwich', + 'Little Falls', + 'Arealva', + 'Bad Schwalbach', + 'Dovzhansk', + 'Amiens', + 'Floridia', + 'Sukma', + 'Zoeterwoude', + 'Narahia', + 'Santo Nino', + 'Acate', + 'Zuromin', + 'Kagithane', + 'Quarrata', + 'Ivankiv', + 'Sougueur', + 'Ain Harrouda', + 'Temsia', + 'Yangjiang', + 'Baja', + 'Ampasina-Maningory', + 'Porto', + 'Kolavallur', + 'Dianbu', + 'Sakuragawa', + "L'Union", + 'Prattipadu', + 'Mogosoaia', + 'Lija', + 'Dornbirn', + 'Madera Acres', + 'Munro Turuttu', + 'Ban Ao Nang', + 'Catubig', + 'Kibungan', + 'Cienfuegos', + 'Taza', + 'Zoma-Bealoka', + 'Zabid', + 'Sandare', + 'Labuleng', + 'Dresden', + 'The Valley', + 'Le Kram', + 'Shihe', + 'Zira', + 'Kurume', + 'Wengtiancun', + 'Mucuri', + 'Burnley', + 'Aborlan', + 'Allen', + 'Diriomo', + 'Metro', + 'Mandalgovi', + 'Etten-Leur', + 'Almeria', + 'Wootton', + 'Doukouya', + 'Ban Tha Khlong', + 'Trikala', + 'Hasanpura', + 'Gisborne', + 'Cooper City', + 'Mukasi Pidariyur', + 'Oulad Yaich', + 'Ibitita', + 'Majarhat', + 'Naas', + 'Sete Barras', + 'Ongata Rongai', + 'El Parral', + 'Hayrabolu', + 'Kasipalaiyam', + 'Jamaame', + 'Tripoli', + 'Ettapur', + 'Gurnee', + 'Ofunato', + 'Statesville', + 'Taiwa', + 'Boekenhouthoek', + 'Bandar-e Khamir', + 'Meningie', + 'Valle de La Pascua', + 'Vinhedo', + 'Ksar', + 'Al Mindak', + 'Blackrock', + 'Kaua Kol', + 'Ban Yaeng', + 'Kodaimangalam', + 'Brownsville', + 'Zhushan', + 'Vrede', + 'Pombas', + 'Albatera', + 'Puerto Narino', + 'Pakpattan', + 'Awfouss', + 'Santa Cruz de Los Taques', + 'Thi Tran Ngai Giao', + 'Pakkam', + 'Chibok', + 'Wollert', + 'Berisso', + 'Pocone', + 'Eindhoven', + 'Eramala', + 'Alphen aan den Rijn', + 'Kamuli', + 'Puerto Quijarro', + 'Manaus', + 'Burleson', + 'Topsham', + 'Maribondo', + 'Buta', + 'Tampamolon Corona', + 'Alagoinha', + 'Valljkkod', + 'Nilo Pecanha', + 'Chachahuantla', + 'Dax', + 'Texcatepec', + 'Horizontina', + 'Serra Negra', + 'Kolda', + 'Bee Ridge', + 'Nekarikallu', + 'Wasilla', + 'Vatana', + 'Bestobe', + 'Fatsa', + "Sao Joao d'Alianca", + 'Sondrio', + 'Gorgonzola', + 'Nongstoin', + 'Yaguajay', + 'Solapur', + 'Abington', + 'Star', + 'Asuncion', + 'Valdosta', + 'Zhongtanying', + 'Rewahi', + 'Ankarana-Miraihina', + 'Debar', + 'Playa Grande', + 'Guabiruba', + 'Del Aire', + 'Tumen', + 'Perket', + 'Sinor', + 'Canford Cliffs', + 'Khorramdarreh', + 'Latehar', + 'Guerouma', + 'Pine Ridge', + 'Alba Iulia', + 'Qalansuwa', + 'Orocue', + 'Taraz', + 'Jesus Maria', + 'Langsa', + 'Trikkunnapuzha', + 'Nosy Varika', + 'Nishi', + 'Anjangaon', + 'Trebisacce', + 'Taucha', + 'Grosshansdorf', + 'Shirone', + 'Swakopmund', + "Bog'ot", + 'Antenor Navarro', + 'Parsippany-Troy Hills', + 'East Northport', + 'Sur Singh', + 'Huy', + 'Gandikunta', + 'Tamarakulam', + 'Cerknica', + 'Hindaun', + 'Vichy', + 'Hilo', + 'Branson', + 'Kalimala', + 'Othello', + 'Dol', + 'Nanga Eboko', + 'Angical', + 'Plains', + 'Culpeper', + 'Famjin', + 'Watrap', + 'Basrur', + 'Aracoiaba da Serra', + 'Bretten', + 'Gavere', + 'Lingxi', + 'Doctor Juan Eulogio Estigarribia', + 'Aracatuba', + 'Fredonia', + 'Wittmund', + 'Hirao', + 'Elmshorn', + 'Pfullingen', + 'Temse', + 'Betim', + 'Bhiraha', + 'Taquara', + 'Orivesi', + 'Thanh Pho Uong Bi', + 'Kamalganj', + 'Manamadurai', + 'Sint-Kruis', + 'Sankaramangalam', + 'Evergreen Park', + 'Catigbian', + 'Auhar Sheikh', + 'Gornji Vakuf', + 'Obanazawa', + 'Casandrino', + 'Saquisili', + 'Narsinghgarh', + 'Mitcham', + 'Carmelo', + 'Green', + 'Ringsted', + 'Timmins', + 'Wobulenzi', + 'Haddington', + 'Lohna', + 'West Mifflin', + 'Al Musayyib', + 'Brugg', + 'Jyvaskyla', + 'Al Muharraq', + 'Heroica Caborca', + 'Mapandan', + 'Osimo', + 'Srem', + 'Caxito', + 'Tantega', + 'Mahajamba', + 'Stara Tura', + 'Palo Alto', + 'Miskolc', + 'Dharmapuri', + 'Krefeld', + 'Sibutao', + 'Itinga', + 'Kuacjok', + 'Zhaodong', + 'Ambikapur', + 'Cologno al Serio', + 'Agua Branca', + 'Barskoon', + 'Jora', + 'Ciudadela', + 'Yenice', + 'Anderlecht', + 'Sunny Isles Beach', + 'Pilikodu', + 'San Marzano di San Giuseppe', + 'Hunenberg', + 'Khandpara', + 'Bieber', + 'Timezgana', + 'Sam Phran', + 'Yuquan', + '`Akko', + 'Ittikara', + 'Louveira', + 'Kalingiyam', + 'La Grande-Motte', + 'Maebara', + 'Billinghurst', + 'Bou Adel', + 'Leszno', + 'Inhumas', + 'Atoka', + 'Kerou', + 'Saint-Benoit', + 'Zhangzhou', + 'Belazao', + 'Senapparetti', + 'Cua', + 'Tangerang', + 'Zebbug', + 'Levanger', + 'Liminka', + 'Punceres', + 'Mavinpalli', + 'Jharsugra', + 'Hassan Abdal', + 'Karaburun', + 'Zazafotsy', + 'Simri Bakhriarpur', + 'Caprino Veronese', + 'Yorito', + 'Makaya', + 'Tenango de Doria', + 'Minamata', + 'Fujimino', + 'Vecchiano', + 'Tavas', + 'Punta Indio', + 'San Gregorio Atzompa', + 'Ambohimiarivo', + 'Hessisch Oldendorf', + 'Geretsried', + 'Calabozo', + 'Kara-Balta', + 'Pieta', + 'Grande Prairie', + 'Los Angeles', + 'Dingalan', + 'Potengi', + 'San Jose de Ocoa', + 'Suncheon', + 'Fornaka', + 'Rehti', + 'Bandixon', + 'Virapperumanallur', + 'North Lindenhurst', + 'Sainte-Julie', + 'Los Reyes de Salgado', + 'Pinamar', + 'Mayfield Heights', + 'Santa Apolonia', + 'Harpur Bhindi', + 'Campodarsego', + 'Urbana', + "Braine-l'Alleud", + 'Wukari', + 'Martahalli', + 'Leppavirta', + 'Kastel Stari', + 'Sansare', + 'Braganca Paulista', + 'Bridgeport', + 'Cecina', + 'Ossett', + 'Chepica', + 'Koratagere', + 'Muthuswamipuram', + 'Kamigori', + 'Tuchola', + 'Fukang', + 'Balanga', + 'Isola Capo Rizzuto', + 'Galmaarden', + 'Heinola', + 'Gioia Tauro', + 'Zelfana', + 'Quarai', + 'Frauenfeld', + 'Makole', + 'Puerto Lempira', + 'Brandenburg', + 'Kot Radha Kishan', + 'Armazem', + 'Mahaboboka', + 'Jingjiazhuang', + 'Ongole', + 'Magalhaes de Almeida', + 'Darat `Izzah', + 'Longtian', + 'Ahualulco de Mercado', + 'Alexander City', + 'Iwai', + 'Coolbaugh', + 'Khambhaliya', + 'Narayanavanam', + 'Littleton', + 'Ciudad Lerdo', + 'Martin Coronado', + 'Vialonga', + 'Hamminkeln', + 'Arrah', + 'Pianco', + 'Villa Elisa', + 'Tawaramoto', + 'Skien', + 'Santa Clara La Laguna', + 'Takad Sahel', + 'Giardini', + 'Barbosa Ferraz', + 'Brevnov', + 'Fuenlabrada', + 'Birhana', + 'Kaberamaido', + 'Siocon', + 'Loja', + 'Midori', + 'Sambhu Chak', + 'Federacion', + 'Masan', + 'Lousada', + 'Laguna Salada', + 'Pooler', + 'Geisenfeld', + 'Orlandia', + 'El Castillo de La Concepcion', + 'Koriyama', + 'Altagracia', + 'Minalin', + 'San Feliu de Llobregat', + 'Uithoorn', + 'Rivadavia', + 'Castello de Ampurias', + 'Zhur', + 'Greenock', + 'Criuleni', + 'Nangola', + 'Claymont', + 'Sihecun', + 'Palmers Green', + 'Guatica', + 'Mandaue City', + 'Pharkia', + 'Cambui', + 'Placerville', + 'Junin de los Andes', + 'Omachi', + 'Gaspar Hernandez', + 'Valinda', + 'Fort Walton Beach', + 'Arttuvattala', + 'Mahela', + 'Dowa', + 'Kelme', + 'Chippenham', + 'Metahara', + 'Marovantaza', + "Saint David's", + 'West Windsor', + 'Cleburne', + 'Itupiranga', + 'Trikarpur North', + 'Miyanaga', + 'Gandhari', + 'Tatarbunary', + 'Zholymbet', + 'Springwater', + 'Seekonk', + 'Groningen', + 'Chocaman', + 'Lianzhou', + 'Siggiewi', + 'Ig', + 'Sarh', + 'Al Hayy', + 'Chum Phae', + 'Meridjonou', + 'El Copey', + 'Salerno', + 'Antsampandrano', + 'Zahana', + 'Stuttgart', + 'Razan', + 'Hexiang', + 'North Merrick', + 'Hicksville', + 'Palmares Paulista', + 'Kalpi', + 'Sariyer', + 'Nandamuru', + 'Guidel', + 'Morinda', + 'Jinhe', + 'Yasinia', + 'Nova Friburgo', + 'Buriti Alegre', + 'Shahin Shahr', + 'Chivolo', + 'Gosforth', + 'Hunchun', + 'Gexianzhuang', + 'Mareno di Piave', + 'Montville', + 'Kikuyu', + 'Wauwatosa', + 'Dhalaa', + 'Villa del Carbon', + 'Tigbao', + 'Aidlingen', + 'Mekla', + 'Nieuwegein', + 'Geldern', + 'Pepillo Salcedo', + 'Belampalli', + 'Karakol', + 'Saint-Louis du Nord', + 'Bartabwa', + 'Zardab', + 'Kanakpur', + 'Dock Sur', + 'Todos Santos Cuchumatan', + 'Sunbat', + 'Matmata', + 'Le Passage', + 'Panr', + 'Galdacano', + 'Wa', + 'West Freehold', + 'Merville', + 'Sonderborg', + 'Corovode', + 'Tizgane', + 'Kadinhani', + 'Penalva', + 'Piqua', + 'Wenwu', + 'Castanuelas', + 'Jazan', + 'Nowe Miasto Lubawskie', + 'Velletri', + 'Cativa', + 'Niihama', + 'Carapebus', + 'Jai', + 'Sao Jose da Laje', + 'Southgate', + 'Ottaikkalmantapam', + 'Ladhuka', + 'Kulkent', + 'Mobetsu', + 'Pincourt', + 'Tagoloan', + 'Kiseljak', + 'Maryport', + 'Flores da Cunha', + 'Sao Jeronimo', + 'Ban Nong Han', + 'Kirk of Shotts', + 'Diyadin', + 'Uchti', + 'Marlboro Village', + 'El Consejo', + 'Dasraha Bhograjpur', + 'Hagenow', + 'Beniajan', + 'Halfway', + 'Jiming', + 'Antibes', + 'Manushmuria', + 'Nantucket', + 'La Mision', + 'Limbang', + 'Rubano', + 'Tchaourou', + 'Repatriacion', + 'Danyang', + 'Ad Duraykish', + 'Osterode', + 'Karvetnagar', + 'Secunda', + 'Kuhbanan', + 'Poissy', + 'Itupeva', + 'Liuhe', + 'New Smyrna Beach', + 'Okuta', + 'Shuangqiao', + 'Irati', + 'Lampa', + 'Gautampura', + 'Cacahoatan', + 'Mooirivier', + 'Spanaway', + 'Abu Hardub', + 'Bor', + 'Dingjiagouxiang', + 'Rehburg-Loccum', + 'Ambajogai', + 'Detmold', + 'Yuncheng', + 'Boyarka', + 'Eden', + 'Penne', + 'Barghat', + 'Ampahimanga', + 'Turkmenabat', + 'Zarqan', + 'Dover', + 'Sindirgi', + 'Panabo', + 'Holliston', + 'Tambolaka', + 'Ciudad Arce', + 'Nadbai', + 'Nova Era', + 'Bekodoka', + 'South Fayette', + 'Ampanavoana', + 'Mahbubabad', + 'Palkonda', + 'Alasehir', + 'Dongshicuo', + 'Uniondale', + 'Bhakua', + 'Damavand', + 'Kami-kawabe', + 'Deutschlandsberg', + 'Domahani', + 'Pallippatti', + 'Kaolack', + 'Bolhrad', + 'Murfreesboro', + 'Sankt Georgen im Schwarzwald', + 'Antanambe', + 'Macajuba', + 'Thies', + 'Tarlac City', + 'Taquaritinga', + 'City of Orange', + 'Glendora', + 'Tufanganj', + 'Claremore', + 'Zejtun', + 'Figueira da Foz', + 'Holmen', + 'Aiea', + 'Runkel', + 'Forbe Oroya', + 'Ondjiva', + 'Tosu', + 'Surinam', + 'Rahatgarh', + 'Winterswijk', + 'Sakiet ed Daier', + 'Kolonnawa', + 'Wawizaght', + 'Imisli', + 'Horokhiv', + 'Shenjiatun', + 'Lenguazaque', + 'Newington', + 'Lecheng', + 'Gamboma', + 'Manubolu', + 'Perumbalam', + 'Bougaribaya', + 'Dryden', + 'Kielce', + 'Edeleny', + 'Ouidah', + 'Comalapa', + 'Harrogate', + 'Qianwu', + 'Nguru', + 'South Daytona', + 'Corbin', + 'Abnub', + 'Saren', + 'Beydag', + 'Monthey', + 'Bonheiden', + 'August', + 'North Miami Beach', + 'Aulnay-sous-Bois', + 'Aaley', + 'Talne', + 'Kodungallur', + 'San Buenaventura', + 'Gerlingen', + 'West Earl', + 'Pacatu', + 'Hallein', + 'Nueva Ocotepeque', + 'Biassono', + 'Garfield Heights', + 'Motozintla', + 'Gerpinnes', + 'Mnasra', + 'Riohacha', + 'Etacheri', + 'Pudur', + "Sant'Antonio Abate", + 'Steinhagen', + 'Sfax', + 'San Miguel Chicaj', + 'El Congo', + 'Falimari', + 'Pinhal Novo', + 'Ystrad Mynach', + 'Wangen im Allgau', + 'Qazmalar', + 'Severinia', + 'Nonea', + 'Dargecit', + 'Sukumo', + 'Cittadella', + 'Yamba', + 'Sao Luis de Montes Belos', + 'Suleswaranpatti', + 'Abu Tisht', + 'Ploermel', + 'Arvika', + 'Warud', + 'Mazatlan Villa de Flores', + 'Inga', + 'Jaworzno', + 'Canalete', + 'Balayan', + 'Ankazomborona', + 'Nadimpalem', + 'Illintsi', + 'Laives', + 'Juchitan de Zaragoza', + 'Ponot', + 'Annan', + 'Fiorentino', + 'Lambarkiyine', + 'Linluo', + 'Neu-Anspach', + 'Rio Maria', + 'South Venice', + 'Moranbah', + 'North Haledon', + 'Orchard Park', + 'Pico Truncado', + 'Gomez Palacio', + 'I-n-Amenas', + 'Barreiros', + 'San Mateo', + 'Harran', + 'Toccoa', + 'Ghoradal', + 'Medgidia', + 'Roermond', + 'Madinat al Habbaniyah', + 'San Agustin Tlaxiaca', + 'Nakodar', + 'La Baneza', + 'Citrus Park', + 'Guttal', + 'Lovington', + 'Carahue', + 'Vicosa do Ceara', + 'Saitama', + 'Whistler', + 'Amjhera', + 'Rio Brilhante', + 'Mora', + 'I-n-Salah', + 'Sao Joaquim do Monte', + 'Huanian', + 'Alcalde Diaz', + 'Bijaynagar', + 'Lowton', + 'Anjahamarina', + 'Tohoue', + 'Birkenhead', + 'Ghogaon', + 'Kadachchinallur', + 'Lal-lo', + 'Colorado do Oeste', + 'Boukoumbe', + 'La Source', + 'Knittelfeld', + 'Guangping', + 'Torrington', + 'Yako', + 'Batesville', + 'Dhobipet', + 'Ain Kechera', + 'Prey Veng', + 'Webster Groves', + 'Huai Yot', + 'Thandewala', + 'Koksijde', + 'Vosselaar', + 'Ashtarak', + 'Timaru', + 'Myrtle Beach', + 'Ban Na Sai', + 'Masbate', + 'Buloqboshi', + 'Trzebnica', + 'Biskra', + 'Sidi Bousber', + 'Jiangjiehe', + 'Qinhe', + 'Kunnur', + 'Palmerston North', + 'Kodanad', + 'Gulyam', + 'Gulou', + 'Fort Dodge', + "Mek'i", + 'Mount Olive', + 'Marco de Canavezes', + 'Ucuma', + 'Kucukkuyu', + 'Sendamaram', + 'Minacu', + 'Quezon City', + 'Caxias do Sul', + 'Banjarbaru', + 'Analamisampy', + 'Zhongwangzhuang', + 'Morroa', + 'Laghzawna', + 'Talakulam', + 'Pailin', + 'Clearfield', + 'Soumpi', + 'Drochtersen', + 'Lourinha', + 'Zerbst', + 'Beohari', + 'Marina di Carrara', + 'Sherpur Khurd', + 'Ploufragan', + 'Sucat', + 'Nadikude', + 'Live Oak', + 'Puerto Casado', + 'Mortara', + 'Beichengqu', + 'Iwanuma', + 'Melle', + 'Guney', + 'Geneva', + 'Whitley Bay', + 'Chintalavadi', + 'Buwama', + 'Midlothian', + 'Guatire', + 'Baghauni', + 'Chiang Mai', + 'East Ham', + 'Lenyenye', + 'Shirakawa-tsuda', + 'Dibulla', + 'Nocera Superiore', + 'Paispamba', + 'Puerto Princesa', + 'Ban Ton Thong Chai', + 'Markham', + 'Bileh Savar', + 'Timmapuram', + 'Kone', + 'Tchindjendje', + 'Bir el Djir', + 'Saldus', + 'Coalville', + 'Waterville', + 'North Canton', + 'Dalandzadgad', + 'New Franklin', + 'Presidencia de la Plaza', + "M'Chedallah", + 'Heves', + 'Brodnica', + 'Kicevo', + 'Niaogho', + 'Sao Pedro', + 'Connahs Quay', + 'Renningen', + 'Kaiwen', + 'Frejus', + 'Nobeji', + 'Le Bardo', + 'North Fair Oaks', + 'Metzingen', + 'Thonex', + 'Argos Orestiko', + 'Erdington', + 'Takasaki', + 'Storm Lake', + 'Ronnenberg', + 'Freetown', + 'Neuenburg', + 'Pinotepa', + 'Wood Buffalo', + 'Usme', + 'Kitaakita', + 'Nagykoros', + 'Midleton', + 'South Ockendon', + 'Brahmana Periya Agraharam', + 'Mantua', + 'Hayange', + 'Qarshi', + 'Komono', + 'Yasuj', + 'Cuartero', + 'Fuding', + 'Oberderdingen', + 'Consaca', + 'Calatrava', + 'San Vicente de Baracaldo', + 'Yakakent', + 'Sowan', + 'Major Isidoro', + 'Dongou', + 'Monza', + 'Millbrae', + 'Panshi', + 'Roquebrune-sur-Argens', + 'Satravada', + 'Visby', + 'Iseyin', + 'Kesarimangalam', + 'Greensburg', + 'Nova Paka', + 'Butterworth', + 'Fort Liberte', + 'Hongseong', + 'Anand', + 'Kalamasseri', + 'Kazhukambalam', + 'Beian', + 'Derik', + 'Malalag', + 'Prakhon Chai', + 'Laje', + 'Upper Uwchlan', + 'Sun Prairie', + 'Maghaghah', + 'Al Qaryatayn', + 'Ghonchi', + 'Masabdisa', + 'Luan Chau', + 'Czersk Pomorski', + 'Poggibonsi', + 'Privas', + 'Sa`adat Shahr', + 'Divinolandia', + 'Frontino', + 'Nurota', + 'Kpandae', + 'Kamitonda', + 'Molln', + 'Rogozno', + 'Kavital', + 'Sarlat-la-Caneda', + 'Reserva', + 'Ankazotsifantatra', + 'Shiraoka', + 'Baisha', + 'Sodertalje', + 'Sao Mateus do Sul', + 'Cimahi', + 'Nirakpurpali', + 'Baluntaicun', + 'Aloran', + 'Usmat Shaharchasi', + 'Jalpura', + 'Prairieville', + 'Neuenburg am Rhein', + 'Pangzawl', + 'Oshkosh', + 'Kalaidasht', + 'El Milia', + 'Williams Lake', + 'Lillebonne', + 'Kalyves Polygyrou', + 'Nova Europa', + 'Kawit', + 'Grande Saline', + 'Shuili', + 'Khanda', + 'Sa`idi', + 'Mount Eliza', + 'Queensferry', + 'Gibara', + 'Bathurst', + 'Itri', + 'Cosquin', + 'Dakovo', + 'Jimbolia', + 'Parsad', + 'Tartar', + 'Santarem', + 'Ingenio', + 'Az Za`ayin', + 'Avola', + 'Campiernagar', + 'Hioki', + 'Gaizhou', + 'Amancio', + 'Fort Salonga', + 'Ramhormoz', + 'Es Senia', + 'Konosu', + 'Tallaght', + 'San Giovanni in Marignano', + 'Al Mahallah al Kubra', + 'Nashville', + 'Nkongsamba', + 'Cazenga', + 'Teutonia', + 'Asthanwan', + 'Genappe', + 'Neuenstadt am Kocher', + 'Grammichele', + 'Latteri', + 'Aragarcas', + 'Thevur', + 'Yaglidere', + 'Radomir', + 'Bearsden', + 'Novo Airao', + 'Bierun Stary', + 'Lagunia Surajkanth', + 'Dengtangcun', + 'Schwechat', + 'Kalkar', + 'Cukurca', + 'Xiedian', + 'Teramo', + 'Yonago', + 'Samakhiali', + 'Pemba', + 'Rancho Palos Verdes', + 'Barclayville', + 'Bridgeton', + 'Eslov', + 'Shahpur', + 'Mandalgarh', + 'Nordstemmen', + 'Portlethen', + 'Opmeer', + 'Gemona del Friuli', + 'Askim', + 'Sidi Moussa', + 'Josefina', + 'Oskarshamn', + 'Kaujalgi', + 'Vicente Lopez', + 'Mandasa', + 'Bordj Menaiel', + 'Melgaco', + 'Beaufort', + 'Catskill', + 'Madaba', + 'Savoy', + 'Rahta', + 'Chiran', + 'London Grove', + 'Malov', + 'Serra Caiada', + 'Arico el Nuevo', + 'Dongping', + 'Elumalai', + 'Montelimar', + 'Weingarten', + 'Talbahat', + 'Bima', + 'Frouzins', + 'Kanur', + 'Beavercreek', + 'Vange', + 'Tianwei', + 'Westbury', + 'Donduseni', + 'Teotepeque', + 'Felidhoo', + 'McCordsville', + 'Catamarca', + 'Gurpinar', + 'Matola', + 'Lezajsk', + 'Chinna Gollapalem', + 'Fervedouro', + 'Ambodihara', + 'Bagalkot', + 'Quillabamba', + 'Boundiali', + 'Ankara', + 'Montfoort', + 'Union', + 'Pulheim', + 'Itako', + 'Kampong Tunah Jambu', + 'Bandar `Abbas', + 'Ghotki', + 'Phek', + 'Calabar', + 'Taft', + 'Nong Bua Lamphu', + 'Yenkuvarigudem', + 'Sebeta', + 'Freeport', + 'Gehrden', + 'Doctor Phillips', + 'Leers', + 'Mannedorf', + 'Linz', + 'Carvin', + 'Zhengdong', + 'Itabera', + 'Fujita', + 'Fazakerley', + 'Rillieux-la-Pape', + 'Xikou', + 'Grain Valley', + 'Chia', + 'Taiobeiras', + 'Kamianske', + 'Novyi Svit', + 'Pasni', + 'Nawanagar', + 'Zwickau', + 'Albstadt', + 'Tawau', + 'Sandnes', + 'Hilsa', + 'Trollhattan', + 'Le Mee-sur-Seine', + 'Villa del Rosario', + 'Barlinek', + 'Dacheng', + 'Ardestan', + 'Morbegno', + 'Bujaru', + 'Oued el Abtal', + 'Catio', + 'Mabalacat', + 'Venkidanga', + 'Leshou', + 'Makedonska Kamenica', + 'Pipra Latif', + 'Lae', + 'Myeik', + 'Lisburn', + 'Curralinho', + 'Cunen', + 'Wanparti', + 'Marica', + 'Muscle Shoals', + 'Nykobing Mors', + 'Rwamagana', + "Jin'e", + 'Quitandinha', + 'Nilufer', + 'Camisano Vicentino', + 'Masera di Padova', + 'Brockville', + 'Ashiya', + 'Velenje', + 'Chencha', + 'Pongotan', + 'Rogaska Slatina', + 'Barasat', + 'Lognes', + "N'Goussa", + 'Bordeaux', + 'Huaquillas', + 'Puvalur', + 'Pasraha', + 'Belladere', + 'Tonghae', + 'Montebelluna', + 'Nihonmatsu', + 'Mariano Roque Alonso', + 'Doura', + 'Xiangxiang', + 'Mang La', + 'Dumjor', + 'Jedrzejow', + 'Butler', + 'Rebola', + 'Douar Hammadi', + 'Sala Consilina', + 'Alassio', + 'Fenoarivobe', + 'Pueblo Rico', + 'Bramhapuri', + 'Mejillones', + 'Arcore', + 'Wiefelstede', + 'Wick', + 'Porsa', + 'Urdinarrain', + 'Seabra', + 'Pompton Plains', + 'Wells', + 'Paete', + 'Thorne', + 'Moss Vale', + 'Kortrijk', + 'San Giovanni in Fiore', + 'Dhar', + 'Bonneuil-sur-Marne', + 'Beregadougou', + 'Khandaich', + 'Arrigorriaga', + 'Glossop', + 'Neusass', + 'Olivenza', + 'Chaodongcun', + 'Lichtenburg', + 'Perupalem', + 'Pulimathu', + 'Buharkent', + 'Lancing', + 'Arendal', + 'Mpessoba', + 'Massillon', + 'Lordelo do Ouro', + 'Tlaltenango de Sanchez Roman', + 'Berkley', + 'Tracunhaem', + 'Avitanallur', + 'Livron-sur-Drome', + 'Badoc', + 'Salman Bak', + 'Vaihingen an der Enz', + 'Las Torres de Cotillas', + 'Claxton Bay', + 'Popasna', + 'Astana', + 'Fairhope', + 'Barras', + 'Acala', + 'Balti', + 'San Bartolome Jocotenango', + 'Capalonga', + 'Probistip', + 'Candoi', + 'Dapa', + 'Yei', + 'Roznov pod Radhostem', + "Oulad 'Azzouz", + 'Sherobod', + 'Andondabe', + 'Gedera', + 'Mandi Dabwali', + 'Le Blanc-Mesnil', + 'Elambalur', + 'Altlandsberg', + 'Chouafaa', + 'Sao Jose da Tapera', + 'Loimaa', + 'Concepcion', + 'Dhrol', + 'Kulpahar', + 'Mililani Town', + 'Goondiwindi', + 'Varzea Nova', + 'Sampgaon', + 'Dibraghani', + 'Wiwili', + 'Elk Grove', + 'Iskenderun', + 'Tandarampattu', + 'Bani Mazar', + 'Parramos', + 'Northwood', + 'Charabidya', + 'Villa Sandino', + 'Karsiyang', + 'Loughborough', + 'Tetari', + 'Nigde', + 'Yarmouth', + 'Bonen', + 'Monserrato', + 'Echirolles', + 'Iglesias', + 'Senges', + 'Tacambaro de Codallos', + 'Zwolle', + 'Baradero', + 'Belize City', + 'Ponmundam', + 'Vaterstetten', + 'Tiddas', + 'Uracoa', + 'Nandigaon', + 'Greven', + 'Vila Franca do Campo', + 'Dhumnagar', + 'Yiwu', + 'Casoria', + 'Tovuz', + 'Yakossi', + 'Domont', + 'Bai Chay', + 'Grimsby', + 'Manzini', + 'Tiszaujvaros', + 'Sapele', + 'Lihuzhuang', + 'Michalovce', + 'Tanamarina', + 'Apartado', + 'Albu Kamal', + 'Griffith', + 'Zhashkiv', + 'Oroco', + 'Falkirk', + 'Derassi', + 'Vipava', + 'Berriane', + 'Kiskunhalas', + 'Gradiska', + 'Doesburg', + 'Jamestown', + 'Kingston upon Hull', + 'Djibloho', + 'Sachin', + '`Aliabad-e Katul', + 'Bouanri', + 'Chandpur', + 'Godalming', + 'Toamasina', + 'Basarh', + 'Taviano', + 'Apricena', + 'Takayama', + 'Nossen', + 'Hashima', + 'Staines-upon-Thames', + 'Lachen', + 'Ecclesfield', + 'Kiraz', + 'Cercado Abajo', + 'Mangalpur Gudaria', + 'Anolaima', + 'Ban Mae Chedi', + 'Namur', + 'Bragadiru', + 'Cusano Milanino', + 'Shirosato', + 'Khilchipur', + 'Lymington', + 'Kuala Kurun', + 'Santa Cruz Balanya', + 'North Babylon', + 'Thogaduru', + 'Shirin', + 'El Ghourdane', + 'Qanliko`l', + 'Jangalapalli', + 'Mariakerke', + 'Kukkundur', + 'Coyula', + 'Meghauna', + 'Ain el Hadjar', + 'Sen Monorom', + 'Madakasira', + 'Shepton Mallet', + 'Biggleswade', + 'Llallagua', + 'Birzai', + 'Beneditinos', + "Kattaqo'rg'on Shahri", + 'La Crucecita', + 'Tall Abyad', + 'Ar Rahmaniyah', + 'Milnrow', + 'Shasta Lake', + 'San Giovanni Lupatoto', + 'Lovejoy', + 'Fo-Boure', + 'Konigswinter', + 'Ironton', + 'Sabirabad', + 'Sai Wan Ho', + 'Ueda', + 'Yinchengpu', + 'Miandrarivo', + 'Horley', + 'Djidian', + 'Koundara', + 'Dereli', + 'Sidi Merouane', + 'Alwal', + 'Debre Tabor', + 'Beltsville', + 'San Francisco de los Romo', + 'Singkawang', + 'Kryvyi Rih', + 'Cisnadie', + 'Altotting', + 'Cape Canaveral', + 'Mitsuke', + 'Baroueli', + 'Abrandabad-e Shahediyeh', + 'Merkanam', + 'Huazalingo', + "L'Hay-les-Roses", + 'Riorges', + 'Serra Dourada', + 'Woensdrecht', + 'Castelli Calepio', + 'Kiruna', + 'Fatima', + 'Bensonville', + 'Weissenhorn', + 'San Jose El Idolo', + 'Racconigi', + 'Lluchmayor', + 'Inabe', + 'Amgachia', + 'Aswapuram', + 'Wilmette', + 'Zwonitz', + 'Haji Shah', + 'Nava', + 'El Cerrito', + 'Tabira', + 'Treuchtlingen', + 'Ponte da Barca', + 'Poitiers', + 'Watari', + 'As Safirah', + 'Handsworth', + 'Muniz Freire', + 'God', + 'Nova Crixas', + 'Tujg', + 'Jakobstad', + 'San Bartolo Tutotepec', + 'Kennewick', + 'Baianopolis', + 'Las Navas', + 'Paracelis', + 'Moniquira', + 'Porumamilla', + 'Arroyo Seco', + 'Bom Sucesso', + 'West Haven', + 'Kinik', + 'Nangavalli', + 'Draksharama', + 'Wells Branch', + 'Shumanay', + 'Zlocieniec', + 'Monte di Procida', + 'Novodnistrovsk', + 'Chitungwiza', + 'San Pedro de Macoris', + 'Mombin Crochu', + 'Dumbarton', + 'Ostersund', + 'Le Grand-Saconnex', + 'Uijeongbu', + 'Lomianki', + 'Piazza Armerina', + 'Butebo', + 'Kirsehir', + 'Huamachuco', + 'Ismailpur', + 'North Amityville', + 'Lanquin', + 'Rio Negrinho', + 'Ukrainsk', + 'Rockingham', + 'Zarasai', + 'Terneuzen', + 'Musiri', + 'Badanahatti', + 'Edayikunnam', + 'Caridade', + 'Jensen Beach', + 'Kuriyama', + 'Antarvedi', + 'Amos', + 'Byatarayanpur', + 'Sao Domingos do Maranhao', + 'Tarutung', + 'Worthington', + 'Fujiidera', + 'Gerd Faramarz Shahediyeh', + 'Buchach', + 'Igarape', + 'Lincolnton', + 'Ameskroud', + 'Bad Oldesloe', + 'Yorii', + 'Juticalpa', + 'Lakshmaneswaram', + 'Catanduvas', + 'Ryhope', + 'Wesselsbron', + 'As Suwayhirah as Sahil', + 'Selvazzano Dentro', + 'Tanxia', + 'East Hampton', + 'Agua Fria', + 'Garanhuns', + 'Saint-Lazare', + 'Char Fasson', + 'Malanguan', + 'Waco', + 'Kanaya', + 'Totolapan', + 'Bloemhof', + 'Tokkavadi', + 'Nogent-sur-Marne', + 'Zhuolan', + 'Nandyalampeta', + 'Invercargill', + 'Trabia', + 'Boromo', + 'Blackfalds', + 'General Trias', + 'Kalakkadu', + 'Ellesmere Port', + 'Gampola', + 'Macclesfield', + 'Bachhauta', + 'Unzen', + 'Balbalan', + 'Maimon', + 'Minanba', + 'Andalucia', + 'Baclaran', + 'Sumqayit', + 'Amargosa', + 'Ghatawan', + 'Alajuela', + 'Maroaloka', + 'Bongandanga', + 'Papagos', + 'Bairia', + 'Ghagga', + 'Lillehammer', + 'Iizuna', + 'Kifosso', + 'Crailsheim', + 'Zvornik', + 'Devgadh Bariya', + 'Imola', + 'Estreito', + 'Haga', + 'Toyoyama', + 'Abeokuta', + 'Laoang', + 'West Seneca', + 'Kharhial', + 'Menzel Temime', + 'Jankinagar', + 'El Carmen de Chucuri', + 'Huari', + 'Maua', + 'Pekalongan', + 'Coltauco', + 'Carmen de Apicala', + 'Cacador', + 'Andohajango', + 'Yangiqo`rg`on', + 'Yesagyo', + 'Sahuayo de Morelos', + 'Nijmegen', + 'West Whittier-Los Nietos', + 'Santa Rosa del Sur', + 'Tharial', + 'Boves', + 'Bodhan', + 'Bagula', + 'Gobabis', + 'Ouahigouya', + 'Maubeuge', + 'Eldorado', + 'Bakhtawarpur', + 'Ternivka', + 'Kasserine', + 'Sayula de Aleman', + 'Fallanden', + 'Fonseca', + 'Lipari', + 'Bou Djeniba', + 'Jagraon', + 'Parrita', + 'Erongaricuaro', + 'Mizumaki', + 'Dieramana', + 'Moyamba', + 'La Linea de la Concepcion', + 'Kiffa', + 'Silleda', + 'Port Said', + 'Gross-Gerau', + 'Ilakatra', + 'Wooster', + 'Sicasica', + 'Eureka', + 'Dodworth', + 'Hereford', + '`Amran', + "La Chapelle d'Armentieres", + 'Pelsall', + 'Borshchiv', + 'Kaiyuan', + 'Pandag', + 'Mortagua', + 'Errachidia', + 'Gaya', + 'Dietzenbach', + 'An Najaf', + 'Dungarpur', + 'Oued Seguin', + 'Sampaloc', + 'Traralgon', + 'Andalatanosy', + 'Gillingham', + 'Mudon', + 'Deville-les-Rouen', + 'Xicheng', + 'Afonso Claudio', + 'Daanbantayan', + 'Horqueta', + 'Bahraigh', + 'North Brunswick', + 'Marotsiraka', + 'Ribnita', + 'North Royalton', + 'Kalemie', + 'El Oro de Hidalgo', + 'Woods Cross', + 'Tsiamalao', + 'Shankarampet', + 'Tecpan de Galeana', + 'Humlebaek', + 'Phatthalung', + 'Meddappakkam', + 'Raha', + 'Sensuntepeque', + 'Paidiipalli', + 'Itatira', + 'Siddapur', + 'Catemaco', + 'Joue-les-Tours', + 'Amal', + 'Bara Belun', + 'Hidalgotitlan', + 'Algeciras', + 'Carbonita', + 'Kulrian', + 'Kasaishi', + 'Pasir Gudang', + 'Yingchuan', + 'Owo', + 'Saanich', + 'Altos', + 'Dana Point', + 'Morro da Fumaca', + 'Copparo', + 'Gerze', + 'Werneck', + 'Athis-Mons', + 'Yanam', + 'Palmilla', + 'Port St. John', + 'Kapay', + 'Pottipuram', + 'Vaniyambadi', + 'Glenmont', + 'Ocara', + 'Huasuo', + 'Raver', + 'Manouba', + 'Volklingen', + 'Calcado', + 'Kattiyeri', + 'West Boldon', + 'Asaita', + 'Maradah', + 'Nagasu', + 'Mundelein', + 'Boerne', + 'Kuji', + 'Voi', + 'Hafnarfjordhur', + 'Huatabampo', + 'Juliaca', + 'Parkland', + 'Kedougou', + 'Suqian', + 'Caicedonia', + 'Dhing', + 'Azambuja', + 'Sekimachi', + 'Jasauli', + 'Benxi', + 'Ifanhim', + 'Sparti', + 'Reichelsheim', + 'Beni Khalled', + 'Salkhua', + 'Rotenburg an der Fulda', + 'Cheticheri', + 'Dorking', + 'Al Majma`ah', + 'Ghajnsielem', + 'Yomou', + 'Monsummano', + 'Richton Park', + 'Capbreton', + 'Curitibanos', + 'East Brandywine', + 'Karmana', + 'As Salamiyah', + 'Pallippurattuseri', + 'Mareeba', + 'Port Sudan', + 'Jumilla', + 'Schleswig', + 'Cedar Lake', + 'Richmond West', + 'Puqi', + 'Sbeitla', + 'Vaddapalli', + 'River Grove', + 'Northbridge', + 'Erkoklu', + 'Miliana', + 'Autun', + 'Lohja', + 'Ixtaczoquitlan', + 'Tczew', + "Shaqra'", + 'Djugu', + "Ben N'Choud", + 'East Kilbride', + 'Ciudad Melchor Muzquiz', + 'Tezpur', + 'Aldershot', + 'Tankara', + 'Honganur', + 'Nikshahr', + 'Jeffersonville', + 'Portage', + 'Waremme', + 'Bacuag', + 'Bhajani', + 'Kutno', + 'Kinston', + 'Macabebe', + 'Greater Napanee', + 'Isla Vista', + 'Santona', + 'Rimavska Sobota', + 'Sultanganj', + 'Mittweida', + 'Humayingcun', + 'Buon Ma Thuot', + 'Meaux', + 'Beibu', + 'La Vergne', + 'Warri', + 'Huaibaijie', + 'Yasica Arriba', + 'Zayda', + 'East Whittier', + 'Wasquehal', + 'Elkton', + 'Pasupatikovil', + 'Leuna', + 'Jamtara', + 'Baildon', + 'Lobo', + 'Karor', + 'Havsa', + 'Puente de Piedra', + 'Santana do Ipanema', + 'Strombeek-Bever', + 'Egg', + 'Charter Oak', + 'Romit', + 'Sevenoaks', + 'Toshima', + 'Lashio', + 'Tocina', + 'Phu My', + 'El Fula', + 'Dimona', + 'Leopoldshohe', + 'Marungur', + 'Goleniow', + 'Ouangani', + 'Dumalinao', + 'Sulz am Neckar', + 'Colchester', + 'Tarin Kot', + 'Bhairahawa', + 'Jaguaretama', + 'Shin', + "Pallazzolo sull'Oglio", + 'Rajnagar', + 'Massi', + 'Redlynch', + 'Badin', + 'Paredes de Coura', + 'Malambo', + 'Abjij', + 'Bekasi', + 'Shaomi', + 'Salzano', + 'Harlow', + 'Flower Hill', + 'Soasio', + 'Oakton', + 'Lukula', + 'Garhakota', + 'Monteforte Irpino', + 'Shamsabad', + 'Marsala', + 'Lauri', + 'Lala', + 'Siniscola', + 'Huixtla', + 'Taxisco', + 'Pesaro', + 'Khapalu', + 'Oyster Bay', + 'Ivanhoe', + 'Xai-Xai', + 'Medulla', + 'Naini', + 'Santa Cruz del Quiche', + 'Saint-Gratien', + 'Sante Bennur', + 'Al Brouj', + 'Raje', + 'Perladka', + 'Ban Laem Chabang', + 'Gora', + 'Monitos', + 'Panchanandapur', + 'Pandacan', + 'Surbiton', + 'Sandy', + 'Wittenheim', + 'Gujranwala', + 'Zaria', + 'Hirayama', + 'Neyveli', + 'Guane', + 'Oak Forest', + 'Suzhou', + 'Tulle', + 'Prantij', + 'Rocca di Papa', + 'Tielt', + 'Bleicherode', + 'Ponte San Pietro', + "'Ain el Turk", + 'Bagou', + 'Taragi', + 'Ukal', + 'Ruy Barbosa', + 'Siroki Brijeg', + 'Pabellon de Arteaga', + 'Granite City', + 'Ait Majdane', + 'Hirehaluhosahalli', + 'Pinabacdao', + 'Kawa', + 'Phaltan', + 'Piombino Dese', + 'Belmopan', + 'Kodad', + 'Bozova', + 'Quibala', + 'Nakur', + 'Berkovitsa', + 'Chiredzi', + 'Sanmenxia', + 'Bugdayli', + 'Nersingen', + 'Palma Campania', + 'Paceco', + 'Isesaki', + 'Lopatcong', + 'Pecan Grove', + 'Thomaston', + 'Sri Jayewardenepura Kotte', + 'Quang Yen', + 'Greeley', + 'Omidiyeh', + 'Namakkal', + 'Macuro', + 'Neuenkirchen', + 'Goure', + 'Kehen', + 'Dongyangshi', + 'Fiumefreddo di Sicilia', + 'Alta Floresta', + 'Ban Na Chom Thian', + 'Viet Tri', + 'Kashgar', + 'Shawinigan', + 'Danghara', + 'Belgrade', + 'Puerto Tejada', + 'Tulin', + 'Agblangandan', + 'Poranga', + 'Lagos', + 'Mallig', + 'Ciftlik', + 'Sao Francisco de Paula', + 'Kiyama', + 'Crespo', + 'Bad Salzungen', + 'Doganhisar', + 'Indargarh', + 'Miandrivazo', + 'Mondovi', + 'Quthing', + 'Guipos', + 'Dikhil', + 'Polakala', + 'Ambaliha', + 'Anuppampattu', + 'Aquitania', + 'La Rinconada', + 'Paramaribo', + "Ma'anshan", + 'Uniao da Vitoria', + 'Cuihua', + 'Areka', + 'Huldenberg', + 'Gudlavalleru', + 'Alasandigutta', + 'Changtoushang', + 'Segni', + 'Durlesti', + 'Chivhu', + 'Carmen de Carupa', + 'Prachin Buri', + 'Buzhum', + 'Phalodi', + 'Munak', + 'Rewari', + 'La Gomera', + 'Yuhuan', + 'Woburn', + 'Aghbal', + 'Santa Maria a Vico', + 'Bogo', + 'Mendon', + 'Kong', + 'Benapol', + 'Sakoueba', + 'Uruana', + 'Chengam', + 'Freising', + 'Nobsa', + 'Ciechocinek', + 'Chengjiao', + 'Cerca Carvajal', + 'Matawan', + 'Al Madamud', + 'Mettmann', + 'Yakumo', + 'Bir Mogrein', + 'Puerto Acosta', + 'Nunna', + 'Gunjapalle', + 'Collier', + 'Mateszalka', + 'Bento Goncalves', + 'Umbrete', + 'Kapakli', + 'Padada', + 'Oud-Turnhout', + 'Karukh', + 'Fort Meade', + 'Domanic', + 'Emsburen', + 'Braunsbedra', + 'Sacramento', + 'Vidauban', + 'Ranomafana', + 'Chone', + 'Malapannanagudi', + 'Siralkoppa', + 'Mequon', + 'Rottingdean', + 'Lindenwold', + 'Chanal', + 'Wakuya', + 'Malaba', + 'Chaabat el Leham', + 'Huinan', + 'Port-Vila', + 'Silopi', + 'Tanabi', + 'Yelmalla', + 'Siteki', + 'Casiguran', + 'Kennedale', + 'Kenduadih', + 'Intibuca', + 'Fos-sur-Mer', + 'Nueva Era', + 'Jicheon', + 'Rovigo', + 'Acipayam', + 'Bajala', + 'Drama', + 'Shiv', + 'San Giorgio a Cremano', + 'Antonio Dias', + 'Jalajala', + 'Ocsa', + 'Oviedo', + 'University City', + 'Boquira', + 'Gaura', + 'Naaldwijk', + 'Manteswar', + 'Farmingville', + 'Bokonbaev', + 'Qingxicun', + 'Scharbeutz', + 'Hamrun', + 'Lake Barcroft', + 'Adeje', + 'Saint Austell', + 'Jarrow', + 'Kandira', + 'Lincang', + 'Orsay', + 'Affoltern am Albis', + 'Bilozerka', + 'Lishaocun', + 'Ochanthururtha', + 'Koekelare', + 'Vengikkal', + 'Dysselsdorp', + 'New Scotland', + 'Isfara', + 'Cuers', + 'Derry', + 'Tampere', + 'Debiapur', + 'Yandian', + 'Awan Patti', + 'Kara-Kyshtak', + 'Oguz', + 'Qualiano', + 'Jose Maria Ezeiza', + 'Pfaffenhofen', + 'Sidi Ali', + 'Arayat', + 'Carvajal', + 'Palakollu', + 'Jingzhou', + 'Owerri', + 'Bato', + 'Yanyan', + 'Dasmarinas', + 'Srifa', + 'Duzhuang', + 'Qazi Ahmad', + 'Brook Park', + 'Market Drayton', + 'Kitahiroshima', + 'Swindon', + 'Pilibhit', + 'Hoyland', + 'Georgsmarienhutte', + 'Chigorodo', + 'Abu Qir', + 'Marysville', + 'Singerei', + "Town 'n' Country", + 'Jangany', + 'Atwater', + 'Fuchucho', + 'Rutana', + 'Shamgarh', + 'Cotegipe', + 'Atascadero', + 'Maisons-Alfort', + 'Bela Vista de Minas', + 'Kopervik', + 'Madugula', + 'Semra', + 'Binh Hoa', + 'Krnov', + 'Itapaci', + 'Sao Raimundo Nonato', + 'Sint-Joost-ten-Node', + 'Maski', + 'Regen', + 'Folkestone', + 'Rardhu', + 'Toyohashi', + 'Duragan', + 'Guelendeng', + 'Bugongi', + 'Montecchio Emilia', + 'Mahwah', + 'Dayrut', + 'Papeete', + 'Worsley', + 'Mponela', + 'Barakpur', + 'Broken Hill', + 'Sakiet ez Zit', + 'Glen Burnie', + 'Negapatam', + 'Itahari', + 'Kambainellur', + 'Cienega de Flores', + 'Jau', + 'Xalatlaco', + 'Dalaman', + 'Thi Tran Dong Dang', + 'Zacatlan', + 'Changbang', + 'Chikugo', + 'Uden', + 'Kansas City', + 'Sremska Mitrovica', + 'Pizhou', + 'Fannuj', + 'Slany', + 'Soye', + 'Painal', + 'Station des Essais M.V.A.', + 'Egg Harbor', + 'Morsi', + 'Araioses', + 'Escondido', + 'Castelnuovo Berardenga', + 'Ijra', + 'Ndora', + 'Ain Taya', + 'Essaouira', + 'Kimba', + 'Taher', + 'Bouar', + 'Kyrenia', + 'Chilca', + 'Quatis', + 'Badulla', + 'Kalpatta', + 'Turffontein', + 'Potunuru', + 'Karuhatan', + 'Amalfi', + 'Wuppertal', + 'Cayo Mambi', + 'Riva del Garda', + 'Boucau', + 'Sejong', + 'Elesbao Veloso', + 'Jiaojiangcun', + 'Pullanpallikonam', + 'Borborema', + 'Corella', + 'Schkeuditz', + 'Gurgenpinari', + 'Buddayyakota', + "Zd'ar nad Sazavou", + 'Jiangmen', + 'Tallahassee', + 'Ciudad Lazaro Cardenas', + 'Peabiru', + 'Ghomrassen', + 'Sultan Kudarat', + 'Brunswick', + 'Brookes Point', + 'Jihlava', + 'Kotharpettai', + 'Koumia', + 'Hasanpur', + 'Riachao do Dantas', + 'Tinqueux', + 'Stillwater', + 'Tempoal de Sanchez', + 'Weiterstadt', + 'Ichikikushikino', + 'Atlapadu', + 'Kiashahr', + 'Bertioga', + 'Centro Habana', + 'Makassar', + 'Rajakheri', + 'Kuhbil', + 'Baldwin Park', + 'Chunchura', + 'Shepshed', + 'Yakima', + 'Rayagada', + 'Saltpond', + 'Karamadai', + 'Sainte-Suzanne', + "St. John's", + 'Peddannavaripalle', + 'Ban Houayxay', + 'Pir Maker', + 'Bagewadi', + 'Chemancheri', + 'San Luis Rio Colorado', + 'Fullerton', + 'Khargram', + 'Yacuiba', + 'Rancho Grande', + 'Giurgiu', + 'San Blas Atempa', + 'Koulamoutou', + 'Jwaneng', + 'Kamalapuram', + 'Crna Trava', + 'Brooklyn Park', + 'Singapperumalkovil', + 'Kiban', + 'Budalur', + 'Yeonil', + 'Nsele', + 'Cumra', + 'Baie-Comeau', + 'Avila', + 'Chantilly', + 'Tongyangdao', + 'Izamal', + 'Yalaguina', + 'Obersiggenthal', + 'Sadalgi', + 'Cuprija', + 'Laufenburg (Baden)', + 'Bukan', + 'Siyana', + 'Kafue', + 'Portmore', + 'Perchtoldsdorf', + 'Catemu', + 'Kaimana', + 'Demir Hisar', + 'Tabor', + 'Alakamisy', + 'Bayt Lahya', + 'Rosiori de Vede', + 'Sarnia', + 'Venustiano Carranza', + 'Nunchia', + 'Kankakee', + 'Chittur', + 'Duma', + 'Bou Arada', + 'Burton', + 'Itatiaiucu', + 'Mason', + 'Araputanga', + 'San Juan Tecuaco', + 'Meghaul', + 'Abhwar', + 'Zhujiacun', + 'Saline', + 'Fethiye', + 'Leeds', + 'Ogori', + 'Keffi', + 'Karanja', + 'Heiligenhaus', + 'Haci Zeynalabdin', + 'Gubin', + 'Chenab Nagar', + 'Gormi', + 'Lydenburg', + 'Neuhaus am Rennweg', + 'Kings Grant', + 'Umi', + 'Dengka', + 'Gangaur', + 'Atsugicho', + 'Ibshaway', + 'Mananasy-Tsitakondaza', + 'Itacarambi', + 'Minowa', + 'Corzuela', + 'Vanduvancheri', + 'Bohl-Iggelheim', + 'Shinile', + 'Wilde', + 'Montlucon', + 'Latham', + 'Picana', + 'Tuao', + 'Drapetsona', + 'Mountain Brook', + 'Montechiarugolo', + 'Kasba Tanora', + 'Rajghat Garail', + 'Kasumpti', + 'Devirammanahalli', + 'Singalandapuram', + 'Chevy Chase', + 'Aspropyrgos', + "'Ain Taghrout", + 'Delft', + 'Beining', + 'Blainville', + 'Krasnohrad', + 'Siem Reap', + 'Betamcherla', + 'Labin', + 'Pompei', + 'Gospic', + 'Hakui', + 'Gomaringen', + 'Saint-Brevin-les-Pins', + 'Langtang', + 'Mangalapadi', + 'Santa Lucia del Camino', + 'East Whiteland', + 'Morioka', + 'Bouira', + 'Coria del Rio', + 'Varzea Paulista', + 'Araira', + 'Thana Bhawan', + 'Ain Taoujdat', + 'Mumbwa', + 'Comandante Luis Piedra Buena', + 'Powell River', + 'Nampa', + 'Nisang', + 'Piran', + 'Bude', + 'Merosina', + 'Kamez', + 'Fairborn', + 'Abhar', + 'Giffoni Valle Piana', + 'Jose Bonifacio', + 'Andhana', + 'Kisanuki', + 'Landover', + 'Dekanme', + 'Raposos', + 'Columbio', + 'Flieden', + 'Antalaha', + 'Impruneta', + 'Pyapali', + 'Butuan', + 'Hlevakha', + 'Braslovce', + 'Kalajoki', + 'Minami-Boso', + 'Tocumen', + 'Matan', + 'Zapopan', + 'Calbayog City', + 'Liloy', + 'Durgi', + 'Byadgi', + 'Vero Beach South', + 'Hongtuliang', + 'Baharu', + 'Hounslow', + 'Joquicingo', + 'Cranleigh', + 'Cassilandia', + 'Burton Latimer', + 'Poco Fundo', + 'Starogard Gdanski', + 'Paikpara', + 'Calera', + 'Gyumri', + 'Higashine', + 'Hialeah Gardens', + 'Moravce', + 'Lac', + 'Poruvakara', + 'Cadaval', + 'Pasig City', + 'Montpellier', + 'Nantang', + 'Baruni', + 'Imani', + 'Rommerskirchen', + 'Orizaba', + "Saint Ann's Bay", + "Olho d'Agua das Flores", + 'Amvrosiivka', + "M'dhilla", + 'Abulug', + 'Helmstedt', + 'La Chapelle-Saint-Luc', + 'Delitzsch', + 'Gurmaila', + 'Sainte-Anne-des-Plaines', + 'Gardhabaer', + 'Sodankyla', + 'Chandrakona', + 'Leczyca', + 'Madhipura', + 'Khargapur', + 'Cruz do Espirito Santo', + 'Gloucester City', + 'Latisana', + 'Doranda', + 'Holly Springs', + 'Mechtras', + 'Grenoble', + 'Red Bluff', + 'Titu', + 'Karavalur', + 'Chiquimulilla', + 'Kirkcaldy', + 'Soledad de Doblado', + 'Ben Nasseur', + 'Miyato', + 'Temecula', + 'Araripe', + 'Ambatoharanana', + 'Union Park', + 'Cuemba', + 'Birkirkara', + 'Ambohitsilaozana', + 'La Louviere', + 'Enniscorthy', + 'Ishkashim', + 'Touna', + 'Presidente Olegario', + 'Maranguape', + 'Mati', + 'Sainte-Catherine', + 'Nerja', + 'Freiburg im Breisgau', + 'Cairo Montenotte', + 'Uchchangidurgam', + 'Jhansi', + 'Elmali', + 'Al Jabin', + 'Orono', + 'Wickliffe', + 'Lontras', + 'Mound', + 'Cosio', + 'Drummondville', + 'Royal Tunbridge Wells', + 'Dolneni', + 'Tabogon', + 'Sosnowiec', + 'Badrashni', + 'Papanduva', + 'Kalayaan', + 'Zottegem', + 'General Salgado', + 'Ozatlan', + 'Southchase', + 'Santa Adelia', + 'Aribinda', + 'Nakanojomachi', + 'Coroata', + 'Marovatolena', + 'Saubara', + 'Pingtiancun', + 'Syosset', + 'Dinslaken', + 'Carpentras', + 'San Martino di Lupari', + 'Tabarka', + 'Yulara', + 'Ratzeburg', + 'Punta Gorda', + 'San Rafael del Yuma', + 'Arima', + 'Jannat Shahr', + 'El Escorial', + 'Honwada', + 'Bhagwanpur Khurd', + 'Ayutla de los Libres', + 'Guaiba', + 'Garzon', + 'Tarangnan', + 'Marktheidenfeld', + 'Ban Chang Phuak', + 'Aurad', + 'Epazoyucan', + 'Tone', + 'Seforong', + 'Lichtervelde', + 'Seriate', + 'Suileng', + 'Viraganur', + 'Novi Banovci', + 'Knaresborough', + 'Bulisa', + 'Shaqlawah', + 'Kingstowne', + 'Zalec', + 'Siano', + 'Flexeiras', + 'Ar Raqqah', + 'Kercem', + 'El Kef', + 'Cicero Dantas', + 'Schonefeld', + 'Neves Paulista', + 'Fish Hawk', + 'Akjoujt', + 'La Courneuve', + 'Biliran', + 'Telkap', + 'Sher Muhammadpuram', + 'Arapoti', + 'Laupheim', + 'Boden', + 'Ratau', + 'Rudesheim am Rhein', + 'Xintai', + 'Temerin', + 'Rebordosa', + 'Bernolakovo', + 'Sulat', + 'Ellwangen', + 'Gates', + 'Merano', + 'Nacozari de Garcia', + 'Camp Springs', + 'Taraka', + 'Yutiancun', + 'Soanpeta', + 'Navgilem', + 'Nagakute', + 'Ipetumodu', + 'Minnetonka', + 'The Acreage', + 'American Canyon', + 'Tripurantakam', + 'Acara', + 'Greer', + 'Conception Bay South', + 'Oiwa', + 'Ukhai Purbari Patti', + 'My Hoa', + 'Miklavz na Dravskem Polju', + 'Porbandar', + 'As Samawah', + 'Tamba', + 'Namangan', + 'Alluru', + 'Zinzana', + 'Karasburg', + "Ich'on", + 'Vojnik', + 'San Miguel Siguila', + 'Lome', + 'Vieiro', + 'Hardas Bigha', + "Jalawla'", + 'Belfast', + 'Sotik Post', + 'Hejiaji', + 'Lovech', + 'Rokupr', + 'Yalda', + 'Mangaldai', + 'Goodyear', + 'Kolakaluru', + 'Bonney Lake', + 'Alcobaca', + 'Bideford', + 'Godawari', + 'Parnaiba', + 'Eskilstuna', + 'Conceicao do Almeida', + 'San Carlos Park', + 'Dolyna', + 'East Liverpool', + 'Ceylanpinar', + 'Adachi', + 'Pottassheri', + 'Kauhajoki', + 'Rio Paranaiba', + 'Patos de Minas', + 'Saint-Jean-de-Monts', + 'Irapuato', + 'Zhuolu', + 'Miadanandriana', + 'Inashiki', + 'Hildesheim', + 'Cold Springs', + 'Merksplas', + 'Engen', + 'LaSalle', + 'Uyo', + 'Vinh Chau', + 'Parsuram', + 'Yoshimi', + 'Jaypul', + 'Minooka', + 'Mehtar Lam', + 'Corsico', + 'Wanding', + 'Corbas', + 'Shaogang', + 'Lusanga', + 'Xining', + 'Navalgund', + 'Binh Minh', + 'Dindigul', + 'Doddanahalli', + 'Tefenni', + 'Samdrup Jongkhar', + 'Taylorsville', + 'Bulicun', + 'Lisieux', + 'Valley Falls', + 'Salpazari', + 'Pianoro', + 'Kedia', + 'Green Valley', + 'Cape Breton', + 'Rencun', + 'Bandar-e Genaveh', + 'Beaverton', + 'Purranque', + 'My Tho', + 'Wendlingen am Neckar', + 'Mohon', + 'Ngaoundere', + 'Boryslav', + 'Antonio Prado', + 'Ramgarh', + 'Gdynia', + 'Hoyland Nether', + 'Cori', + 'Adakli', + 'Na Wa', + 'Ramla', + 'Ellicott', + 'Nowa Sol', + 'Laakirchen', + 'Jalalpur Bhattian', + 'Jaragua do Sul', + 'Ilic', + 'Guimar', + 'Bullas', + 'Dalawarpur', + 'Anuradhapura', + 'Carnaubal', + 'Yokosuka', + 'Lake Mohawk', + 'Phulwar', + 'Bohemia', + 'Imzouren', + 'Tibigan', + 'Apostolove', + 'Cantley', + 'Mbuji-Mayi', + 'Uarini', + "Qarah Zia' od Din", + 'Cortes', + 'Cullercoats', + 'Reggio di Calabria', + 'Figline Valdarno', + 'Mutsu', + 'Maiquinique', + 'New Panamao', + 'Odder', + 'Mar de Espanha', + 'Bukedea', + 'Rath To', + 'Choppington', + 'Irugur', + 'Padang Besar', + 'Cine', + 'Beckett Ridge', + 'Baghuz Fawqani', + 'Campos del Puerto', + 'Bandar-e Torkaman', + 'Sakon Nakhon', + 'San Juan de Alicante', + 'Benicarlo', + 'Beuningen', + 'Vrable', + 'Hennebont', + 'Mamobihat', + 'Three Springs', + "Saint-Cyr-l'Ecole", + 'Brod', + 'Taourirt', + 'Sliven', + 'Stanytsia Luhanska', + 'Ruston', + 'Plauen', + 'Sarasota Springs', + 'Sao Gotardo', + 'Beloeil', + 'Liuguang', + 'Bani Suhayla', + 'Pilar', + 'Sao Joao do Araguaia', + 'Teseney', + 'Domzale', + 'Feira', + 'Ambatoria', + "Guang'an", + 'Carice', + 'Loha', + 'Carmo do Rio Claro', + 'Calle Larga', + 'Ban Yang Hom', + 'Ilha de Mocambique', + 'Barwani', + 'Lowes Island', + 'Liaocheng', + 'Shergarh', + 'La Loggia', + 'Halden', + 'Khowrzuq', + 'Sahavalanina-Antenina', + 'Alum Rock', + 'Kilakkarai', + 'Finsterwalde', + 'Ouedo', + 'Tlalnepantla', + 'Tafi Viejo', + 'Minnampalli', + 'Santa Comba', + 'Sant Joan de Vilatorrada', + 'Marl', + 'Hulkoti', + 'Libourne', + 'Orasje', + 'Svolvaer', + 'Villa Curuguaty', + 'Velden am Worthersee', + 'Riverton', + 'Selmane', + 'Jamshedpur', + 'Sinsina', + 'Amity', + 'Kani-Bonzon', + 'Ilopango', + 'Kiliia', + 'Trelew', + 'Kowdalli', + 'Sao Martinho do Bispo', + 'Bayabas', + 'Marcolandia', + 'Hemel Hempstead', + 'Titlagarh', + 'Thathupur', + 'Kavieng', + 'Pepa', + 'Mangarwara', + 'Wanderlandia', + 'Sokolka', + 'Nara', + 'Koror', + 'Mbamba Bay', + 'Wezembeek-Oppem', + 'Tanjombato', + 'Eichstatt', + 'Independence', + 'Kagoshima', + 'Velingara', + 'Ouistreham', + 'St. Stephens', + 'Altinova', + 'Juchipila', + 'Jiaxing', + 'Millcreek', + 'Ameca', + 'Palmacia', + 'Fiano Romano', + 'Costa Volpino', + 'Rioja', + 'Kalkara', + 'Zanica', + 'Husainabad', + 'Naters', + 'Mistrato', + 'Ambahive', + 'Savanna-la-Mar', + 'Irinjalakuda', + 'Padappakara', + 'Chiantla', + 'Cidade Gaucha', + 'Walton-on-the-Naze', + 'Habiganj', + 'Irukanni', + 'Tekpanja', + 'Ellisville', + 'Luancheng', + 'Rudauli', + 'Abu al Matamir', + 'Nabas', + 'Kagadi', + 'Los Llanos', + 'Ilovaisk', + 'Ar Rumaythah', + 'Melun', + 'Catral', + 'Canico', + 'Pandharpur', + 'Hiroshima', + 'Don Bosco', + 'Billericay', + 'Mentana', + 'Sandravinany', + 'Pacos de Ferreira', + 'Darsi', + 'Tuineje', + 'Medinipur', + 'Mensora', + 'Nikaia', + 'Tan Chau', + 'Ma`alot Tarshiha', + "Huai'an", + 'Spinea', + 'Silvia', + 'Alcarraz', + 'Dongxishan', + 'Putrajaya', + 'Two Rivers', + 'Inacio Martins', + 'Kharahara', + 'Jakarta', + 'Hurth', + 'Giengen an der Brenz', + 'New Delhi', + 'Morlenbach', + 'Krus na Ligas', + 'Tornquist', + 'Hacine', + 'Yanji', + 'Fraiburgo', + 'Gursu', + 'San Giljan', + 'Verin', + 'Moissac', + 'Baghambarpur', + 'Bhatpara', + 'Pontinha', + 'Cunha Alta', + 'Riacho das Almas', + 'Yadwad', + 'St. Albert', + 'Agno', + 'Sitarganj', + 'Budhni', + 'Comayagua', + 'Matagua', + 'Remagen', + 'Aigle', + 'Forest Hills', + 'Wangtan', + 'Avanhandava', + 'Karnobat', + 'Chanp', + 'Amherst', + 'Duiven', + 'Bilohirsk', + 'Pleternica', + 'Marogong', + 'Kefar Sava', + 'Quilmes', + 'Conchagua', + 'Al Khankah', + 'Dulken', + 'Lobatse', + 'Utehia', + 'Sotomayor', + 'Traunreut', + 'Aleksandrovka', + 'Hetane', + 'Bad Oeynhausen', + 'Pescara', + 'Ashkezar', + 'Seiro', + 'Torrejon de Ardoz', + 'Antanimora Atsinanana', + 'Yiewsley', + 'Fojnica', + 'Iharana', + 'Dutse', + 'Ban Lao Yao', + 'Dirusumarru', + 'Tame', + 'Beledweyne', + 'San Andres Xecul', + 'Formia', + 'Mengla', + 'Croix', + 'Kraslava', + 'Pedagadi', + 'Denbigh', + 'Barharwa Kalan', + 'Alexania', + 'Sakhnin', + 'Yenagoa', + 'Kaya', + 'Karlstad', + 'Bundibugyo', + 'Harrai', + 'Dragor', + 'San Jose de Las Matas', + 'Gabela', + 'Alpu', + 'Karema', + 'Yevlax', + 'Allanmyo', + 'Ghafurov', + 'Brandis', + 'Pulupandan', + 'Eidsvoll', + 'Hinunangan', + 'Manmad', + 'Guledagudda', + 'Bangshang', + 'Kujwa', + 'Fairview', + 'Arani', + 'Spoltore', + 'Peiting', + 'Panj', + 'Sahavato', + 'Cramlington', + 'Poggio a Caiano', + 'Sisauna', + 'Mamushe', + 'Tsevie', + 'Barikot', + 'Tecax', + 'Sivapuram', + 'Kalbacar', + 'Mitry-Mory', + 'Biguacu', + 'Trowbridge', + 'Hasanganj', + 'Chamblee', + 'Sid', + 'Alboraya', + 'Pinar del Rio', + 'Calvillo', + 'Mercedes', + 'Chapel en le Frith', + 'Kalat', + "Ra's al Khaymah", + 'Mapoteng', + 'Ponta de Pedras', + 'Glenfield', + 'Temple Terrace', + 'Tlokweng', + 'Raun', + 'Aquin', + 'Boiling Springs', + 'Slobozhanske', + 'Truckee', + 'Nuremberg', + 'Yanghe', + 'Charqueadas', + 'Clarkston', + 'Wallingford Center', + 'Colleferro', + 'Luxor', + 'Gadsden', + 'Dautphe', + 'Macedo de Cavaleiros', + 'Venissieux', + 'Shamva', + 'Chesapeake', + 'Felsberg', + 'East Los Angeles', + 'Monte Caseros', + 'Misawa', + 'Souaflia', + 'Bouguirat', + 'Talara', + 'Iarinarivo', + 'Atalaia do Norte', + 'Pangunattam', + 'Little Ferry', + 'Oulad Tayeb', + 'Masar', + 'Melena del Sur', + 'Miura', + 'Panihati', + 'Andresy', + 'Ramayampet', + 'Basoko', + 'Thala', + 'Chifeng', + 'Majhaul', + 'Nediyanad', + 'Chaumont', + 'Belen de Escobar', + 'Karak', + 'Araxa', + 'Canteleu', + 'Vanrhynsdorp', + 'Achaguas', + 'Norwood', + 'Kandahar', + 'Santa Teresa', + 'Salmon Arm', + 'Kalutara', + 'Greene', + 'Harrisonburg', + 'Lohur', + 'Dingman', + 'Phon Charoen', + 'Farakka', + 'College Place', + 'Wodzislaw Slaski', + 'Alimodian', + 'Kemi', + 'Khapdeh', + 'Xaafuun', + 'Pongalur', + 'Chandwara', + 'Tecali', + 'Villacanas', + 'Kalluru', + 'Bouarouss', + 'Misantla', + 'Mazinde', + 'Rixensart', + 'Satellite Beach', + 'Jinhua', + 'Reedsburg', + "Togoch'ale", + 'Marchena', + 'Wan Long', + "Lyuboml'", + 'Ivancice', + 'Wendelstein', + 'Helston', + 'Manduria', + 'Shama', + 'Sedriano', + 'Cheruvaranam', + 'Nechi', + 'Mandu', + 'Binefar', + 'Sha Kok Mei', + 'Muta', + 'Caripito', + 'Petrolina de Goias', + 'Lianhe', + 'Brock', + 'Schonaich', + 'Aloguinsan', + 'Acapulco de Juarez', + 'Ayt Mohamed', + 'Poplar Bluff', + 'Limburgerhof', + 'Jaggampeta', + 'Ostroleka', + 'Kalamboli', + 'Ash Shihr', + 'Sasaima', + 'Vesele', + 'Lac-Brome', + 'Matnog', + 'Skokie', + "Ha'il", + 'Tzaneen', + 'Greenford', + 'Savanur', + 'Permet', + 'Mallapur', + 'Ladyzhyn', + 'Dama', + 'Angers', + 'Montigny-le-Bretonneux', + 'Xiaodian', + 'Narok', + 'Eching', + 'Castel San Pietro Terme', + 'Itondy', + 'Alcudia', + 'Periyanayakkanpalaiyam', + 'Artigues-pres-Bordeaux', + 'Marikina Heights', + 'Ben Zakkay', + 'Cachipay', + 'Hertzogville', + 'Daman', + 'Wilsdruff', + 'Ben Guerir', + 'Sciacca', + 'Signa', + 'Tuy', + 'Kireka', + 'Reston', + 'Sarab-e Taveh-ye `Olya', + 'Singida', + 'Waldorf', + 'Ain Jemaa', + 'Al Ghat', + 'Deodrug', + 'Kotmale', + 'Guemar', + 'Skoura', + 'Tuaran', + 'Outa Bouabane', + 'Talaivasal', + 'Jerusalem', + 'Hegang', + 'Daskasan', + 'Hannan', + 'Murowana Goslina', + 'Bomlo', + 'Nova Veneza', + 'Coppell', + 'Miguelopolis', + 'Stadtallendorf', + 'Kishundaspur', + 'Yuxiaguan', + 'Aleksandrovac', + 'Mianwali', + 'Mujikharf', + 'Develi', + 'Khawr Fakkan', + 'Billapadu', + 'Cacu', + 'Oldenburg', + 'Lens', + 'Veternik', + 'Canet de Mar', + 'Vellaturu', + 'Colmar', + 'Guadalupe Nuevo', + 'Hulin', + 'Talwandi Bhai', + 'Sighisoara', + 'Santa Monica', + 'Alessandria', + 'Idku', + 'Barsaun', + 'Podebrady', + 'Dona Ines', + 'Eppelheim', + 'Lonavale', + 'Comitan', + 'Darby', + 'Billingham', + 'Saint-Maximin-la-Sainte-Baume', + 'Volterra', + 'Kombissiri', + 'San Lorenzo de Guayubin', + 'Mashyal', + 'Cogua', + 'Parral', + 'Coaticook', + 'Bekobod', + 'Ribadeo', + 'Bhanukumari', + 'Kampong Chhnang', + 'Vrbovec', + 'South Sioux City', + 'Kalaki', + 'Panama City', + 'Mustafabad', + 'Morur', + 'Zurbatiyah', + 'Gamba', + 'Toukoroba', + 'Bully-les-Mines', + 'Nattakkadaiyur', + 'Sand Springs', + 'Turek', + 'Nejapa', + 'Woodridge', + 'Laranjeiras', + 'Xiaozui', + 'Kottaiyur', + 'Sebaste', + 'Penn Forest', + 'La Esmeralda', + 'Nohsa', + 'Eskisehir', + 'Chillan Viejo', + 'Kani', + 'Terdal', + 'Sarta', + 'Jinan', + 'Oborniki', + 'Taketoyo', + 'Badnor', + 'Panchkula', + 'Tres Passos', + 'Cartaya', + 'Barra de Santa Rosa', + 'Ganapavaram', + 'Mulampilli', + 'Damaishan', + 'Meihuacun', + 'Pahsara', + 'Atessa', + 'Toucheng', + 'Chamba', + 'Kranuan', + 'Pasaul', + 'Westview', + 'Grimari', + 'San Jacinto de Buena Fe', + 'Porecatu', + 'Ihtiman', + 'Misilmeri', + 'Friesenheim', + 'Wentang', + 'Bageshwar', + 'Mahtha', + 'Tenes', + 'Eraclea', + 'Evesham', + 'Elmhurst', + 'Nahorkatiya', + 'Oil City', + 'Sidi Jaber', + 'Laxou', + 'Royal Kunia', + 'Dong Xoai', + 'Hathauri', + 'Ambinanintromby', + 'Jurovski Dol', + 'Erwitte', + 'Jerada', + 'Costas de Cao', + 'Douetire', + 'Terku Valliyur', + 'Samesi', + 'Halgeri', + 'Huichapan', + 'Bolpur', + 'Ban Bu Sung', + 'Dandong', + 'Bucaramanga', + 'Bhavnagar', + 'Walia', + 'Puerto Vallarta', + 'Rishikesh', + 'Solebury', + 'Maratturai', + 'Lindlar', + 'Bariarpur Kandh', + 'Yerbas Buenas', + 'Ottur', + 'Torpa', + 'Debre Zeyit', + 'Lemgo', + 'Piritiba', + 'San Lorenzo de El Escorial', + 'Paterson', + 'Gonzaga', + 'Calabasas', + 'Miahuatlan', + 'Castelo do Piaui', + 'Sprockhovel', + 'Adelaide', + 'Clay Cross', + "Do'stlik Shahri", + 'Carrieres-sous-Poissy', + 'Hizan', + 'Mios', + 'Edenburg', + 'Worplesdon', + 'Le Kremlin-Bicetre', + 'Nanjundapuram', + 'Muratli', + 'Massena', + 'Girona', + 'Arifwala', + 'Chillum', + 'Salcedo', + 'Caoayan', + 'Kolonodale', + 'Curacautin', + 'Ixchiguan', + 'Dubnica nad Vahom', + 'Careiro da Varzea', + 'Meckenbeuren', + 'Lacombe', + 'Chifubu', + 'Kostinbrod', + 'Lipova', + 'Sao Joao Evangelista', + 'Messini', + 'Santangpai', + 'Viransehir', + 'Ait Ali', + 'Harsova', + 'Mamou', + 'Denkendorf', + 'Kalardasht', + 'Santo Antonio do Leverger', + 'Qusar', + 'San Tan Valley', + 'Kushima', + 'West Norriton', + 'Brasilia de Minas', + 'Hassleholm', + 'Shahdol', + 'Faqus', + 'Abbots Langley', + 'Zanandore', + 'Canon City', + 'Manjeri', + 'New Milton', + 'Regensdorf', + 'Flower Mound', + 'Dharphari', + 'Chapra', + 'Tazert', + 'Hirehadagalli', + 'Walkden', + 'Hatti', + 'Ohangaron', + 'Bujanovac', + 'Dharmapuram', + 'Munchenstein', + 'Ishigaki', + 'Cocody', + 'Karimpur', + 'Appukkudal', + 'New Kensington', + 'Palmas de Monte Alto', + 'Baghduma', + 'Sorisole', + 'Qarazhal', + 'Shemonaikha', + 'Korfez', + 'Mbale', + 'Shahar Telpa', + 'Gangwuzhen', + 'Qianzhou', + 'Potosi', + 'Monte Chingolo', + 'Baba Bakala', + 'Nottuln', + 'Talakad', + 'Dearborn Heights', + 'Mulakumud', + '`Ali Shahr', + 'Nashtifan', + 'Buriti', + 'Veliko Tarnovo', + 'Forest Lake', + 'Mizuho', + 'Birni Lafia', + 'Honda', + 'Fortin de las Flores', + 'Corral de Bustos', + 'Dracut', + 'Dighwa', + 'La Riche', + 'Karsaut', + 'Mito', + 'Xunjiansi', + 'Gandia', + 'Sidi Makhlouf', + 'Xibeijie', + 'Peritoro', + 'Sanjiangkou', + 'Bounaamane', + 'Barja', + 'San Felipe del Progreso', + 'Daisen', + 'Avadi', + 'North Bay Shore', + 'Dagohoy', + 'Fuying', + 'Dabas', + 'Koipadi', + 'Bloomington', + 'Mecheria', + 'Sundargarh', + 'Rajod', + 'Serramazzoni', + 'Kokofata', + 'Urlati', + 'Temixco', + 'Barbadanes', + 'Peddapalli', + 'Le Mont-sur-Lausanne', + 'Berthoud', + 'Navrongo', + 'Brockworth', + 'West Goshen', + 'Arcos de Valdevez', + 'Lalgola', + 'Bakhmut', + 'Majibacoa', + 'Yangfang', + 'Malisheve', + 'Cloverdale', + 'Petah Tiqwa', + 'Yamanashi', + 'Riofrio', + 'Merta', + 'Yoro', + 'Trinidad', + 'Sobreda', + 'Sidi Allal el Bahraoui', + 'Naranammalpuram', + 'Baicoi', + 'Rolling Meadows', + 'Linjiang', + 'Aralam', + "Citta Sant'Angelo", + 'Kaous', + 'Zacualpa', + 'Rivas', + 'Vellipalaiyam', + 'Ciudad Santa Catarina', + 'Chaungtha', + 'Los Lunas', + 'Crna na Koroskem', + 'San Miguel Ixtahuacan', + 'Pantukan', + 'Tsushima', + 'Donggangli', + 'Nalbach', + 'Begles', + 'Addlestone', + 'Maluso', + 'Atchison', + 'Vertentes', + 'Perth', + 'Deori Khas', + 'Cho Phuoc Hai', + 'Pacifica', + 'Belhatti', + 'Audincourt', + 'Baraidih', + 'Tsiningia', + 'Ampary', + 'Drobeta-Turnu Severin', + 'Tsumeb', + 'Atlantic City', + 'Villaguay', + 'Gyangze', + 'Wokingham', + 'Cowdenbeath', + 'Tehuacan', + 'Babanusah', + 'Kolobrzeg', + 'Iguala de la Independencia', + 'Shanklin', + 'Nasriganj', + 'Haql', + 'Bonab', + 'Ratnanagar', + 'Ermoupoli', + 'Besalampy', + 'Mannar', + 'Vigo', + 'Wolverhampton', + 'Idfu', + 'Zacapa', + 'Malacacheta', + 'Jersey City', + 'Tanmpegre', + 'Gemlik', + 'Bilovodsk', + 'Putyvl', + 'Memmelsdorf', + 'Ar Rustaq', + 'Munster', + 'Dano', + 'Barhan', + 'San Giorgio Ionico', + 'Shevington', + 'Larnaca', + 'Mawu', + 'Rio Verde de Mato Grosso', + 'Arroyos y Esteros', + 'Thoubal', + 'Breisach am Rhein', + 'Aizawl', + 'Bamessing', + 'Nurmo', + 'Lewistown', + 'Marseille', + 'Hyde Park', + 'Antsahalava', + 'Gardelegen', + 'Ramena', + 'Centerville', + 'Berdiansk', + 'Contla', + 'Lunavada', + 'Schwetzingen', + 'Vilangurichchi', + 'Lijiaxiang', + 'North Tustin', + 'Sycow', + 'San Severo', + 'Tugaya', + 'Luziania', + 'Bay', + 'Sete', + 'Torbat-e Heydariyeh', + 'Lerum', + 'Las Tunas', + 'Chalala', + 'Surat', + 'Tobias Barreto', + 'Svilengrad', + 'Viswanathaperi', + 'Duartina', + 'Basantpur', + 'Chikodi', + 'Joplin', + 'Hilongos', + 'Whitefish Bay', + 'Sisian', + 'Grimbergen', + 'Soham', + 'Bage', + 'Senlis', + 'Matungao', + 'Roche-a-Bateau', + 'Belfort', + 'Asarcik', + 'Alotenango', + 'Santa Catarina Ayotzingo', + 'Villa Tunari', + 'Dangcheng', + 'Sievierodonetsk', + 'Vigan', + 'Anahuac', + 'Iesolo', + 'Chandili', + 'Aleksandrow Lodzki', + 'Palkur', + 'Parwaha', + 'Machali', + 'Corleone', + 'Heemstede', + 'Vallehermoso', + 'Ermezinde', + 'Sedalia', + 'Guanxi', + 'Valea lui Mihai', + 'Montescaglioso', + 'Heerlerbaan', + 'Seika', + 'Tongxiao', + 'Ronneby', + 'Badou', + 'Andilana Avaratra', + 'Hope Mills', + 'Taiynsha', + 'Borgampad', + 'Gonder', + 'Weigelstown', + 'Boukhralfa', + 'Kurshab', + 'Bad Liebenwerda', + 'Hodal', + 'Franco da Rocha', + 'Gangtok', + 'Kamianka-Dniprovska', + 'Acilia', + 'Paks', + 'Dastgerd', + 'Montbeliard', + 'Molteno', + 'Lakshmipuram', + 'El Tabo', + 'North Massapequa', + 'San Juan Cotzal', + 'Buftea', + 'Freystadt', + 'Chiltiupan', + 'Jabera', + 'Ikizce', + 'Khurmi', + '`Ajlun', + 'Kalpitiya', + 'Idlib', + 'Yuza', + 'Gaohucun', + 'Lavis', + 'Olesnica', + 'Parnera', + 'Windorah', + 'Munnarkod', + 'Tuckahoe', + 'Schotten', + 'Blansko', + 'Carregal do Sal', + 'Okemos', + 'Central Coast', + 'Anjehalli', + 'West Hollywood', + 'Chanthaburi', + 'Barauna', + 'Chettinayakkanpatti', + 'Aomori', + 'Sukurhutu', + 'Tiruvalam', + 'Lisala', + 'Al Bajur', + 'Santa Filomena', + 'Padre Paraiso', + 'Boura', + 'Teocuitatlan de Corona', + 'Inowroclaw', + 'Nova Milanese', + 'Yalta', + 'Lukulu', + 'Ambila', + 'Oulad Hassoune', + 'Folignano', + 'Salaman', + 'Belem de Sao Francisco', + 'Khvaf', + 'Rio Bravo', + 'Kotri', + 'Bom Jesus', + 'Ambodibonara', + 'Balvi', + 'Jiaozishan', + 'Cubuk', + 'Cagnes-sur-Mer', + 'Harrow Weald', + 'Nantingcun', + 'Choctaw', + 'Adalaj', + 'Hoi An', + 'Chintamani', + 'Ajka', + 'Havelock', + 'Votuporanga', + 'Uta', + 'Incirliova', + 'Ankazondandy', + 'Ash Shunah ash Shamaliyah', + 'Skegness', + 'Kedu', + 'Petite-Synthe', + 'Mungeli', + 'Anjahabe', + 'Maceira', + 'Sakurai', + 'Talya', + 'Ochtrup', + 'Polur', + 'Wake Forest', + 'Bushenyi', + 'Yihezhuang', + 'Vega Baja', + 'East Goshen', + 'Serra Talhada', + 'Ribeira Grande', + 'Branquinha', + 'Chimakurti', + 'Smyrna', + 'Lamesa', + 'Tabuelan', + 'Tuxpam de Rodriguez Cano', + 'Satyamangalam', + 'El Sauce', + 'Nasrullahganj', + 'Acerra', + 'Horlivka', + 'Beloit', + 'Adigaratti', + 'Puraini', + 'Gueltat Sidi Saad', + 'Egra', + 'Comendador', + 'Verrieres-le-Buisson', + 'Novoberde', + 'Onchan', + 'Puri', + 'Oudtshoorn', + 'Ab Pakhsh', + 'Melouza', + 'Schoonhoven', + 'Quilicura', + 'Arlon', + 'Steinkjer', + 'Port Macquarie', + 'Inca', + 'Erkelenz', + 'Lebrija', + 'Mandla', + 'Brus Laguna', + 'Deniliquin', + 'Schramberg', + 'Mokhotlong', + 'Walbrzych', + 'Azarshahr', + 'Highland Springs', + 'Ambodilazana', + 'Timurni', + 'Corbera de Llobregat', + 'Sanand', + 'Lugu', + 'Plovdiv', + 'Nokia', + 'Emden', + 'Biganos', + 'Sao Joao do Triunfo', + 'Carrollton', + 'Qadian', + 'Lowenberg', + 'Hongshandian', + 'Sultanpur Mor', + 'Uusikaupunki', + 'Manosque', + 'Itapevi', + 'Saudade', + 'Russi', + 'Brecksville', + 'Abaran', + 'Abu Suwayr', + 'Laranjeiras do Sul', + 'Krasnyi Luch', + 'Chekkal', + 'Grimma', + 'Aksum', + 'Arari', + 'Bromborough', + 'Yufle', + 'Indio', + 'Xonobod', + 'Trairi', + 'The Pinery', + 'Wehrheim', + 'Martuni', + 'Burbank', + 'Muritiba', + 'Nieuw-Vennep', + 'Cannock', + 'Neuhausen am Rheinfall', + 'Rostamabad', + 'Broome', + 'Voru', + 'Asilah', + 'Fazendinha', + 'West Orange', + 'Sirigeri', + 'Gurmatkal', + 'Simplicio Mendes', + 'Ede', + 'Rolesville', + 'Ashtian', + 'Saint-Genis-Laval', + 'Morada Nova', + 'Rohri', + 'Easton', + 'Tonacatepeque', + 'Marmande', + 'Neratovice', + 'Mildenhall', + 'Telaprolu', + 'North Perth', + 'Vengat', + 'Shirako', + 'Khanewal', + 'Malitbog', + 'Uherske Hradiste', + 'Sinsheim', + 'Baguanos', + 'Guigang', + 'Kumarankari', + 'Minudasht', + 'Bilauri', + 'Sihushan', + 'El Dovio', + "Sant'Anastasia", + 'Puertollano', + 'Rotorua', + 'Douar Azla', + 'Tostedt', + 'Silkeborg', + 'Velakalnattam', + 'Malvik', + 'Redentora', + 'Kimhae', + 'Cankuzo', + 'Turuvanur', + 'Siliancun', + 'Davie', + 'Ouled Rahou', + 'Pederneiras', + 'Aviano', + 'Kwale', + 'Knik-Fairview', + 'Baiyashi', + 'Pendekallu', + 'Sarai Ranjan', + 'Appleton', + 'San Pedro', + 'Bautista', + 'Maurilandia', + 'San Giovanni in Persiceto', + 'East Bethel', + 'Slovenska Bistrica', + 'Caerdydd', + 'Satana', + 'Fakola', + 'Waukee', + 'Lindsay', + 'Bailleul', + 'Ventimiglia', + 'Zaltbommel', + 'Arua', + 'Mansingha', + 'Amauna', + 'Muridke', + 'Burgthann', + 'Kayapinar', + 'Kawachicho', + 'Jiuru', + 'Hartland', + 'Oberwingert', + 'Shiddapur', + 'Sherbrooke', + 'Divaca', + 'Tayum', + 'Trecate', + 'El Menzel', + 'Rawson', + 'Imaculada', + 'Mindat', + "L'Epiphanie", + 'Ambarimaninga', + 'Oststeinbek', + 'Kuala Terengganu', + 'Sankt Polten', + 'Pageralam', + 'Carmen de Viboral', + 'Kety', + 'Inhambupe', + 'Nonantola', + 'South Lake Tahoe', + 'Hiji', + 'Erbaocun', + 'Millis', + 'Chervonohrad', + 'Williamsport', + 'Son La', + 'Leon de los Aldama', + 'Kraulshavn', + 'Figuil', + 'Ritterhude', + 'Sahel', + 'Karaga', + 'Rosarno', + 'Chudamani', + 'Stonehaven', + 'Jataizinho', + 'Surdulica', + 'Veghel', + 'Oki', + 'Hoxter', + 'Memari', + 'Holubivske', + 'Texcoco', + 'Aja', + 'Bayyavaram', + 'Pueblo', + 'Fengcheng', + 'Mossingen', + 'Arinos', + 'Bedesa', + 'Dolenjske Toplice', + 'Shadegan', + 'Pontecorvo', + 'Camano', + 'Fairburn', + 'Villefranche-sur-Saone', + 'Maiduguri', + 'Roxas City', + 'Biddeford', + 'Sokone', + 'Aravelli', + 'Palikir', + 'Herford', + 'Otsego', + 'Kamiita', + 'Brambleton', + 'Hongsi', + 'Bamafele', + 'Al Qurayn', + 'Naousa', + 'Urdorf', + 'Esira', + 'Cachoeira do Sul', + 'Botevgrad', + 'Jamjamal', + 'Sowerby Bridge', + 'Remada', + 'Vistahermosa', + 'Los Lagos', + 'Abengourou', + 'Jean-Mermoz', + 'Parker', + 'Hisor', + 'Oulunsalo', + 'Aguilar', + 'Yuscaran', + 'Sedro-Woolley', + 'Lankaran', + 'Zaniena', + 'Lucerne', + 'Tortum', + 'Lynbrook', + 'Rasiari', + 'Trappes', + 'Kirkel', + 'Balakrishnanpatti', + 'Getafe', + 'Bad Vilbel', + 'Mankayan', + 'Trindade', + 'La Ceja', + 'Tacuba', + 'Tagbina', + 'Severna Park', + 'Canosa di Puglia', + 'Gasan', + 'Daiwanishi', + 'Polohy', + 'Qaraghandy', + 'Ziri', + 'San Antonio de Padua', + 'Rarott', + 'Itami', + 'Carapo', + 'La Cruz de Rio Grande', + 'Ruskin', + 'Camooweal', + 'Barika', + 'Tohoku', + 'Pante Macassar', + 'Vocklabruck', + 'Erutukada', + 'Koili Simra', + 'Edea', + 'Targoviste', + 'Antanankambano', + 'Bangzha', + 'Bankass', + 'Podstrana', + 'Kakuma', + 'Quezaltepeque', + 'Schaan', + 'Daxincun', + 'Trikodi', + 'Yawatahama-shi', + 'Pefki', + 'The Hague', + 'Tamu', + 'Guli', + 'Shing', + 'Bakersfield', + 'Lanxi', + 'Singaparna', + 'Aljustrel', + 'Chirchiq', + 'Rio Acima', + 'Halstenbek', + 'Pandhurna', + 'Boa Nova', + 'Cerkvenjak', + 'Saint-Jean-le-Blanc', + 'Largo', + 'Basse-Terre', + 'Jimalalud', + 'Bhanas Hivre', + "Sant'Ilario d'Enza", + 'Santa Lucia Utatlan', + 'Parasurampur', + 'New Providence', + 'Sofiivka', + 'Ban Muang Kham', + 'Pingdu', + 'Kyle', + 'Nellutla', + 'Hualqui', + 'New City', + 'Tangancicuaro de Arista', + 'Brawley', + 'Rucheng', + 'Bendorf', + 'Steinen', + 'Welby', + 'Valentigney', + 'Jacinto City', + 'Mweka', + 'Baler', + 'Sasso Marconi', + 'Fanzeres', + 'Sunrise', + 'Ovidiopol', + 'Canarana I', + 'Jaitwar', + 'Settat', + 'Villa Paranacito', + 'Lerdo de Tejada', + 'Westerstede', + 'Rangapukur', + 'Vinukonda', + 'Mastaga', + 'Terrasini Favarotta', + 'El Fuerte', + 'Heydarabad', + 'Rapperswil-Jona', + 'Preston', + 'Mahasamund', + 'Bossier City', + 'Kotamobagu', + 'Sowme`eh Sara', + 'Charala', + 'Gayeri', + 'Calape', + 'Villa Rica', + 'Panying', + 'Khandauli', + 'Oristano', + 'Ar Ramtha', + 'Ben Gardane', + 'Donnacona', + 'Bagamoyo', + 'Caras', + 'Chikha', + 'Kalikavu', + 'Lewiston', + 'Maseru', + 'Huanchaco', + 'Higuerote', + 'Yangshe', + 'Salinas Victoria', + 'Marofoty', + 'Yamen', + 'Hyderabad City', + 'Gusang', + 'Mexicali', + 'Yedtare', + 'Salgado de Sao Felix', + 'Gaffney', + 'Torcy', + 'Hodos', + 'Sangerhausen', + 'Tsuruta', + 'Bladensburg', + "Sach'on", + 'Sabanozu', + 'Agustin Codazzi', + 'Kings Park West', + 'Periyamuttur', + 'Varnsdorf', + 'Akbez', + 'The Woodlands', + 'Puente Nacional', + 'Golcuk', + 'Sandbach', + 'Tullamore', + 'Chimalhuacan', + 'Kula', + 'Oliveira de Frades', + 'Yuasa', + 'Jieyang', + 'Conceicao de Jacuipe', + 'Pezinok', + 'Malgrat de Mar', + 'Ceske Budejovice', + 'Qapshaghay', + 'Membakut', + 'General Acha', + 'Studenka', + 'Cleveland', + 'Mehnajpur', + 'Darasuram', + 'Rubengera', + 'Kusadasi', + 'Buddh Gaya', + "Clermont-l'Herault", + 'Bifeng', + 'Nakama', + 'Kuiju', + 'Scheessel', + 'Kajo Kaji', + 'Medina Estates', + 'Pointe-Claire', + 'Savannakhet', + 'Yarumal', + 'Saint-Egreve', + 'Sokoto', + 'Timonium', + 'Tire', + 'Ota', + 'Otwock', + 'Pretoria-Noord', + 'Iziaslav', + 'Bell Gardens', + 'Ecija', + 'Khunays', + 'Kottaipatti', + 'Garin', + 'Tuktukan', + 'Ibara', + 'Tyre', + 'Casteldaccia', + 'Gulgam', + 'Jaffna', + 'Gariadhar', + 'Zoetermeer', + 'Kasulu', + 'Santo Antonio dos Lopes', + 'Pannawonica', + 'Cajuru', + 'Belchertown', + 'Sonseca', + 'Non Sung', + 'Kardla', + 'Furstenfeldbruck', + 'Ban Tat', + 'Bydgoszcz', + 'Semere', + 'Fortuna', + 'Corralillo', + 'Coin', + 'Siegburg', + 'Comacchio', + 'Bellavista', + 'Mission Bend', + 'Avezzano', + 'Rancho Mission Viejo', + 'Mechraa Bel Ksiri', + 'Shirebrook', + 'Kizhariyur', + 'Bueng Kan', + 'Matigou', + 'Misratah', + 'Deventer', + 'Luau', + 'Kiratpur Rajaram', + 'Huanuni', + 'Kannamanayakkanur', + 'Kluczbork', + 'North Battleford', + 'Lukaya', + 'Bo`ka', + 'Baicheng', + 'Channahon', + 'Terrace Heights', + 'Uniao', + 'Kunigal', + "Porto Sant'Elpidio", + 'Marin', + 'Bimun', + 'Dilijan', + 'Satkhira', + 'Erie', + 'Hemsworth', + 'Gueppi', + 'Urubici', + 'Daraw', + 'Kastoria', + 'Yutz', + 'Lichtenstein', + 'Unquillo', + 'Homewood', + 'Accrington', + 'Kalyanpur', + 'Diego de Almagro', + 'Beeville', + 'Koila', + 'Hathiakan', + 'Coka', + 'Bouake', + 'Veyrier', + 'Akhaltsikhe', + 'Tinaquillo', + 'Moncada', + 'Gladbeck', + 'Telpaneca', + 'Central Elgin', + 'Vari', + 'Plonsk', + 'Chateau-Thierry', + 'Schkopau', + 'Nawalpur', + 'Jagatpur', + 'La Ceiba', + 'Omuthiya', + 'Soalandy', + 'Kimberley', + 'Kappiyara', + 'Hyattsville', + 'Shichigahama', + 'Koronowo', + 'Modra', + 'Manolo Fortich', + 'Neuilly-sur-Marne', + 'San Juanito', + 'Sedhiou', + 'Pailon', + 'Vechta', + 'Schortens', + "Qia'erbagecun", + 'Coalinga', + 'Plankstadt', + 'Cachoeira Alta', + 'Grand Prairie', + 'Ulsan', + 'Bouguenais', + 'Campina da Lagoa', + 'Sorong', + 'Churumuco de Morelos', + 'Byron Bay', + 'Sarny', + 'Bilbays', + 'Patiali', + 'Milagro', + 'Kothri Kalan', + 'Idaho Falls', + 'Bombo', + 'Muttunayakkanpatti', + 'Nidamanuru', + 'Countryside', + 'Buu Long', + 'Capitan Bado', + 'Surpur', + 'Reggane', + 'Campi Bisenzio', + 'Anantasagaram', + 'Salto Grande', + 'Baduria', + 'Echague', + 'Hollywood', + 'Rahat', + 'Lower Paxton', + 'Trebbin', + 'Wardha', + 'Beek en Donk', + 'Vilhena', + 'Bergeijk', + 'Chhapia', + 'Ganaram', + 'Chhanera', + 'Kapangan', + 'Roncade', + 'Walcourt', + 'Waltenhofen', + 'Bahar', + 'Oiba', + 'Willoughby', + 'Babol', + 'Alashankou', + 'Groton', + 'Ban Talat Rangsit', + 'Neijiang', + 'Johvi', + 'Ulao', + 'Nagold', + 'Lacey', + 'Marigot', + 'Zabljak', + 'Atushi', + 'Pileru', + 'Borodyanka', + 'Guaymate', + 'Alakamisy Anativato', + 'Montecchio Maggiore', + 'Umea', + 'Mekambo', + 'Jericho', + 'Urrao', + 'Conceicao do Mato Dentro', + 'Cutro', + 'Narayankher', + 'Ocoyoacac', + 'Las Margaritas', + 'North Cornwall', + 'Katiena', + 'Liangwancun', + 'Tarawan', + 'Tianjin', + 'Eltham', + 'Ampitasimo', + 'Patzcuaro', + 'Boortmeerbeek', + 'Zary', + 'New Tecumseth', + 'Izki', + 'Faradonbeh', + 'Ezine', + 'Mushie', + 'Kuvango', + 'La Quiaca', + 'Tamgrout', + 'Buenos Aires', + 'Khowrhesht', + 'Muskegon Heights', + 'Wangsicun', + 'Kimwanyi', + 'Narra', + 'Belton', + 'Khlong Luang', + 'Barhadashi', + 'Ixtlahuacan de los Membrillos', + 'Lauterbach', + 'Mohda', + 'Chepstow', + 'Blegny', + 'Reykjavik', + 'Jangalapalle', + 'Cumayeri', + 'Tarashcha', + 'Cervera', + 'Pouso Redondo', + 'Bunde', + 'Bariyarpur', + 'Zweibrucken', + 'Alzenau in Unterfranken', + 'Santo Tomas', + 'Taxtako`pir', + 'Colinas do Tocantins', + 'Vryburg', + 'Hooksett', + 'Rahui', + 'Daejeon', + 'Chinaval', + 'Pornichet', + 'Hazelwood', + 'Sherkot', + 'Shuishang', + 'Palmitos', + 'Erin', + 'Lagoa do Itaenga', + 'Uthal', + 'Whippany', + 'Zamboanguita', + 'Kasugai', + 'Kuurne', + 'Embarcacion', + 'Alsfeld', + 'Saint-Avertin', + 'Lokwabe', + 'Bronte', + 'Gemerek', + 'Diamond Bar', + 'Germantown', + 'Tengampudur', + 'Myanaung', + 'Amritpur', + 'Manhattan Beach', + 'Spring Valley Lake', + 'Niangoloko', + 'Crevalcore', + 'Bamble', + 'Hollabrunn', + 'Furtwangen im Schwarzwald', + 'Ariquemes', + 'Baruari', + 'Paura Madan Singh', + 'Bracknell', + 'Le Bouscat', + 'Pirapozinho', + 'Puyappalli', + 'Zhengjiatun', + 'Garibaldi', + 'Aydin', + 'Sestri Levante', + 'Panjampatti', + 'Chengbin', + 'Ambohitrambo', + 'Olympia Heights', + 'Fuxin', + 'Jupiter Farms', + 'Birjand', + 'Sugauna', + 'Villa La Angostura', + 'Abu Hummus', + 'Igreja Nova', + 'Sanghera', + 'Tremembe', + 'Bhopalia', + 'Vila Velha', + 'Papampeta', + 'Dhanga', + 'Sheyban', + 'Jaltenango', + 'Tagapul-an', + 'Kulusuk', + 'Montesson', + 'Chascomus', + 'Guernica y Luno', + 'Itamarati', + 'Metepec', + 'Wadersloh', + 'Costa Marques', + 'Barod', + 'Bhaisalotan', + 'Velez-Malaga', + 'Raunds', + 'Hushihacun', + 'Sindgi', + 'Quivican', + 'Ivoti', + 'Maroteza', + 'Bazar-Korgon', + 'Baduriatola', + 'Tysons', + 'Saidapet', + 'Busto Arsizio', + 'Cabanatuan City', + 'Sami', + 'Logansport', + 'Besozzo', + 'Sonaguera', + 'Acevedo', + 'Harbiye', + 'Prairie Ridge', + 'Kasaragod', + "Hosa'ina", + 'Borgo San Dalmazzo', + 'Cockeysville', + 'Kabirpur', + 'Mikuszowice', + 'Kamiichi', + 'Arsali', + 'Enugu', + 'Sahanivotry-Manandona', + 'Savar', + 'Al Khubar', + 'Haddon', + 'Allahdurg', + 'Rodynske', + 'Puduru', + 'Jiquirica', + 'Kirishima', + 'Skive', + 'Aj Jourf', + 'Uedem', + 'Cananea', + 'Stryzhavka', + 'Bankapur', + '`Afrin', + 'Saint-Colomban', + 'Imperia', + 'Valsequillo de Gran Canaria', + 'Jette', + 'Hamm', + 'Piranga', + 'Rixheim', + 'Currimao', + 'Opuwo', + 'Herohalli', + 'Larreynaga', + 'Gravina in Puglia', + 'Benton Harbor', + 'Afragola', + 'Castelldefels', + 'Lubao', + 'Brahmanbaria', + 'Barkly West', + 'San Rafael del Norte', + 'Abu Dhabi', + 'Mamburao', + 'Chartres', + 'Hawick', + 'Shiruru', + 'Butajira', + 'Newcastle', + 'Igarape-Miri', + 'San Mariano', + 'Statesboro', + 'Cachoeira do Arari', + 'Goumori', + 'Kassaro', + 'Karaisali', + 'Yoshida', + 'Stekene', + 'Walajabad', + 'Alcorcon', + 'Seneca', + 'Cabagan', + 'Mansfield', + 'Valsad', + 'Monaragala', + 'Barro', + 'Assebroek', + 'Al Mubarraz', + "L'Isle-d'Abeau", + 'Cajueiro', + 'Wanstead', + 'Iten', + 'Salamina', + 'Jacinto Machado', + 'Kuyganyor', + 'Ar Rusayfah', + 'Morgantown', + 'Balta', + 'Anse-a-Foleur', + 'Crnomelj', + 'Dagbe', + 'Nubl', + 'Isumi', + 'Arumbavur', + 'Lohuti', + 'Backa Palanka', + 'Marktoberdorf', + 'Massango', + 'Gamay', + 'Asbury Park', + 'Piracicaba', + 'Tadas', + 'Malanvadi', + 'Ranko', + 'Falam', + 'Kerava', + 'Brevik', + 'Fort Madison', + 'San Pablo Villa de Mitla', + 'La Resolana', + 'Irun', + 'Santa Juana', + 'Senirkent', + 'Colbun', + 'Chasiv Yar', + 'Bailleston', + 'Mairwa', + 'Ba Don', + 'Caetanopolis', + 'Popovo', + 'Bandipura', + 'Brewer', + 'Raesfeld', + 'Chityal', + 'Bois-Guillaume', + 'Miahuatlan de Porfirio Diaz', + 'Eupen', + 'Riemst', + 'Reims', + 'Menen', + 'Wundanyi', + 'Guarenas', + 'Biankouma', + 'Vila Bela da Santissima Trindade', + 'Pallappalaiyam', + 'Farmington', + 'Bradenton', + 'Singoli', + 'Cainta', + 'Farahalana', + 'Simoes Filho', + 'San Zenon', + 'Planadas', + 'Catole do Rocha', + 'Solrod Strand', + 'Rovinj', + 'Dracena', + 'Jablonec nad Nisou', + 'Chhagalnaiya', + 'Ampataka', + 'Lohagara', + 'Zarautz', + 'Tiquisio', + 'Epinay-sous-Senart', + 'Soka', + 'Gandarbal', + 'Los Muermos', + 'Akyaka', + 'Az Zaqaziq', + 'Ibaretama', + 'San Jose Guayabal', + 'Phulparas', + 'Unity', + 'Anderson', + 'Post Falls', + 'Bandio', + 'Quiindy', + 'Mazoe', + 'Gokarna', + 'Weston-super-Mare', + 'Donihue', + 'Maliano', + 'Sahibganj', + 'Stropkov', + 'Williston', + 'Khutauna', + 'Mishrikot', + 'Rice Lake', + 'Boa Viagem', + 'Ashkhaneh', + 'Wabag', + 'Ban Mangkon', + 'Bognor Regis', + 'Alabel', + 'Hoor', + 'Perote', + 'Sotkamo', + 'Mukondapalli', + 'Kenzingen', + 'El Alia', + 'Barssel', + 'Libon', + 'Pljevlja', + 'Karumulaikkal', + 'Atlatlahucan', + 'Puteaux', + 'Ramnicu Sarat', + 'Karariya', + 'Floro', + 'Richard-Toll', + 'Semuto', + 'Jilotlan de los Dolores', + 'Nellikkuppam', + 'Malsch', + 'Khowrasgan', + 'Ambodimahabibo', + 'Safidon', + 'Canoinhas', + 'Ban Na Yang', + 'Kuttur', + 'Makubetsu', + 'Tsavo', + 'Guape', + 'Mapleton', + 'Sao Sebastiao da Grama', + 'Cannanore', + 'Sama', + 'Vail', + 'Alwar', + 'Cherlagandlapalem', + 'Zyryanovsk', + 'Kopong', + 'Wabrzezno', + 'Antsampanimahazo', + 'Forney', + 'Obock', + 'Banstead', + 'Kovurupalli', + 'Bientina', + 'Le Creusot', + 'Bontang', + 'Pierre', + 'Sidi Aissa', + 'San Ignacio Cerro Gordo', + 'Lancon-Provence', + 'Sao Bento do Sul', + 'Arkadelphia', + 'Lalru', + 'Neriyamangalam', + 'Kwai Chung', + 'Matsubara', + 'Metapan', + 'Hopatcong', + 'Baniyas', + 'Song Phi Nong', + 'Labason', + 'Kashima', + 'Bafanji', + 'Isola del Liri', + 'Las Rozas de Madrid', + 'Herdecke', + 'Ait Bousarane', + 'Itanhandu', + 'Odemis', + 'Mohgaon', + 'Bilgoraj', + 'Poquoson', + 'Dilolo', + 'Soliman', + 'Videira', + 'Sankt Augustin', + 'Hachimantai', + 'Oneida', + 'Medeiros Neto', + 'Sakri', + 'Chestnut Ridge', + 'Burubaytal', + 'Oruro', + 'Beauraing', + 'Mauli', + 'Curanilahue', + 'Great Neck', + 'Skofja Loka', + 'Aiken', + 'Roncador', + 'Temuco', + 'Oros', + 'Timmapur', + 'Kununurra', + 'Naqadeh', + 'Clarin', + 'Podgorica', + 'Beldanga', + 'Mutluru', + 'South Whitehall', + 'Prince Rupert', + 'Nirasaki', + 'Hodatsushimizu', + 'Trani', + 'Voghera', + 'Purkersdorf', + 'Medapadu', + 'Puerto Francisco de Orellana', + 'Fatao', + 'Sidi Yahia El Gharb', + 'Spiez', + 'Pujili', + 'Renk', + 'Quemado de Guines', + 'Antenetibe', + 'Rueil-Malmaison', + 'Saimbeyli', + 'Asagi Quscu', + 'Tsarahasina', + 'Hunasagi', + 'Chilpancingo', + 'Goycay', + 'Republic', + 'Bocholt', + 'Montgeron', + 'Dodji-Bata', + 'Panzgam', + 'Joinville-le-Pont', + 'Fergus', + 'Tenkasi', + 'Groveland', + 'El Carmen de Atrato', + 'Garou', + 'Sangao', + 'Buffalo', + 'Oulad Amrane el Mekki', + 'Bethune', + 'Sidfa', + 'Cuichapa', + 'Maria Aurora', + 'Sanzana', + 'Vaxjo', + 'Tsrar Sharif', + 'Samut Sakhon', + 'Novate Milanese', + 'Mirdaul', + 'Broadview Heights', + 'Domaa-Ahenkro', + 'Herseh Chhina', + 'Tupa', + 'Porec', + 'Mount Evelyn', + 'Balboa Heights', + 'Xuqiaocun', + 'Sumbawa Besar', + 'Nahiyat Khan Bani Sa`d', + 'Danli', + 'Bartin', + 'Feyzin', + 'Peruvanthanam', + 'Chene-Bougeries', + 'Malakal', + 'North Middleton', + 'Hauzenberg', + 'Datteln', + 'Goiatuba', + 'Solan', + 'Ol Kalou', + 'Kaedi', + 'Sakib', + 'Reyes', + 'Freudenstadt', + 'Anamalais', + 'Chengxiang', + 'Ely', + 'Monmouth', + 'Fukude', + 'Nepanagar', + 'Bousse', + 'Emba', + 'Ghusiya', + 'Noisiel', + 'Barharia', + 'Techiman', + 'Castilho', + 'Higashi-osaka', + 'Kerugoya', + 'Bouaiche', + 'Laurel', + 'Suluktu', + 'Hanzviur', + 'Rosrath', + 'Ciro Marina', + 'Cabanillas del Campo', + 'Qahjavarestan', + 'Zuidhorn', + 'Beilen', + 'Minami-Soma', + 'Douentza', + 'Florianopolis', + 'Darende', + 'Catanduva', + 'Wao', + 'Rasingapuram', + 'Huodoushancun', + 'Fontaine-les-Dijon', + 'Shinyanga', + 'Sargodha', + 'Penfield', + 'Dunaujvaros', + 'Ube', + 'Ain Dfali', + 'Andrembesoa', + 'Kochas', + 'Kondalampatti', + 'Khejroli', + 'Manassas', + 'Macaiba', + 'Uson', + 'Langelsheim', + 'Kottukal', + 'Sharan', + 'Longueuil', + 'Parappur', + 'Kurivikod', + 'Pindi Bhattian', + 'Buuhoodle', + 'Karjat', + 'Befandriana', + 'Alto Santo', + 'Pinneli', + 'Mlawa', + 'Cortez', + 'Katteragandla', + 'Badalona', + 'Zibo', + 'Keizer', + 'Marijampole', + 'Loncoche', + 'Mpika', + 'Hobro', + 'Mancora', + 'Bosconia', + 'Frohburg', + 'Weilerswist', + 'Las Charcas', + 'Carney', + 'Bhansia', + 'Simrahi', + 'Guildford', + 'Fuquay-Varina', + 'Braunau am Inn', + 'Pine Hills', + 'Franconville', + 'Noordwijkerhout', + 'Bezons', + 'Sliema', + 'Pinellas Park', + 'Kafr Qasim', + 'Dundee', + 'Valley', + 'Bromsgrove', + 'Coacalco', + 'Kralupy nad Vltavou', + 'Lafrayta', + 'Tunapuna', + 'Barmstedt', + 'Upper Saucon', + 'Palaiya Ayakkudi', + 'Mladenovac', + 'Qaratau', + 'Hurtgenwald', + 'Mailapur', + 'Tucurui', + 'Australia', + 'Cidelandia', + 'Holly Hill', + 'Kannandahalli', + 'Gilgit', + 'Roetgen', + 'Jirkov', + 'Madavur', + 'Eastham', + 'Kachavaram', + 'Qal`at an Nakhl', + 'Pearl River', + 'Oberstdorf', + 'Andilamena', + 'Tittagudi', + 'Ceel Baraf', + 'Meerbusch', + 'Jaunpur', + 'Terrell', + 'Ban Nong Kula', + 'Sarmiento', + 'Coaldale', + 'Baneh', + 'Leh', + 'Mirai', + 'Ambodisikidy', + 'Amtar', + 'Boise', + 'Solsona', + 'Maizuru', + 'Villa Luvianos', + 'Twentynine Palms', + 'Murapaka', + 'Monclova', + 'Miharu', + 'Krumbach', + 'Haldensleben', + 'Inaja', + 'Iguatu', + 'Ponto Novo', + 'Batabano', + 'Itape', + 'Poggiomarino', + 'Gayaspur', + 'Monte San Juan', + 'Kostiantynivka', + 'Bagalvad', + 'Pozoblanco', + 'Gaunivaripalle', + 'Gandhidham', + 'Pingxiangcheng', + 'Flers-lez-Lille', + 'Owasso', + 'Summerville', + 'Ban Tap Tao', + 'Mahisanrh', + 'Podaturpeta', + 'Kalanchak', + 'Lira', + 'Yaguaron', + 'Saharanpur', + 'Guthrie', + 'Tirat Karmel', + 'Sagala', + 'Griesheim', + 'Riesa', + 'Anaikal', + 'Kontiolahti', + 'Betania', + 'Varjota', + 'Pisaflores', + 'Encarnacion de Diaz', + 'Tafeng', + 'Ioannina', + 'Ha Giang', + 'Ash Shinan', + 'Maromiandra', + 'Kampel', + 'Seyyedan', + 'Elk', + 'Marcos Juarez', + 'Timri', + 'Ewarton', + 'Betul Bazar', + 'Sao Jose do Belmonte', + 'Amboahangibe', + 'Isser', + 'Yellayapalem', + 'Bhiwani', + 'Ad Dakhla', + 'Edmond', + 'Lourosa', + 'Aslanapa', + 'Ilsede', + 'Phoenix', + 'Negrine', + 'Prabhat Pattan', + 'Tapaktuan', + 'Camalig', + 'Upper Montclair', + 'Binh Long', + 'Trincomalee', + 'Yellowknife', + 'Turbo', + 'Kashaf', + 'Rapur', + 'Jamiltepec', + 'Zaggota', + 'Serui', + 'Ban Nam Dip Luang', + 'Sursee', + 'Miyoshidai', + 'Chichiriviche', + 'Kariat Ben Aouda', + 'Tranomaro', + 'Torokbalint', + 'Eiheiji', + 'Fartura', + 'Lonate Pozzolo', + 'Lixingcun', + 'Purwakarta', + "Fu'an", + 'Havi Bhauar', + 'Livinjipuram', + 'Sherwood', + 'Cayenne', + 'Hamme', + 'Bao Loc', + 'Cameta', + 'San Fructuoso de Bages', + 'Mawlamyine', + 'Yonkers', + 'Doudian', + 'Orebro', + 'Longvic', + 'Penaballi', + 'Sinzig', + 'Jambi', + 'Bandundu', + 'Poshkent', + 'Dhamdaha', + 'Springettsbury', + 'Savage', + 'Iga', + 'Narsimlapet', + 'Hatwans', + 'Marco Island', + 'Mallikkundam', + 'Loharda', + 'Aguada de Pasajeros', + 'Jining', + 'Dhana', + 'Raceland', + 'Wroclaw', + 'Sao Lourenco da Mata', + 'Kiblawan', + 'Alagoa Nova', + 'Trentham', + 'Alofi', + 'Missoula', + 'Pecanha', + 'Atok', + 'Paipa', + 'Kouroussa', + 'Arnavutkoy', + 'Ankaran', + 'Jorhat', + 'Susari', + 'Higashi-Hiroshima', + 'Incline Village', + 'Rafael Calzada', + 'Thetford', + 'Jelgava', + 'Manono', + 'Tuncheng', + 'Potrerillos', + 'Lopon', + 'Moline', + 'Cornelio Procopio', + 'Dali', + 'Agropoli', + 'Inazawa', + 'Korosavada', + 'Elne', + 'Karur', + 'Vasudevanallur', + 'Viti', + 'Rezina', + 'Paju', + 'Thohoyandou', + 'Enniskillen', + 'Bad Fallingbostel', + 'Sokobanja', + 'Pleven', + 'Bang Phongphang', + 'Danga', + 'Tahuna', + 'Belsara', + 'Battalgazi', + 'Paravada', + 'General Belgrano', + 'Qingping', + 'Jinsha', + 'Malmedy', + 'Santa Cruz Mulua', + 'Lindenberg im Allgau', + 'Karpenisi', + 'Dondo', + 'Viralippatti', + 'Tado', + 'Cimanggis', + 'Barra do Bugres', + 'Kudahuvadhoo', + 'Badru Khan', + 'Samorin', + 'Tiruverumbur', + 'Taloda', + 'Roding', + 'Bante', + 'La Independencia', + 'Basseterre', + 'Ati', + 'Cavinti', + 'Chitembo', + 'Ryugasaki', + 'Eschborn', + 'Vertientes', + 'Bobingen', + 'Haliyal', + 'Sao Gabriel da Cachoeira', + 'Dielheim', + 'Siirt', + 'Oosterend', + 'Aich', + 'Ilkhchi', + 'Labrador City', + 'Chioggia', + 'Neuquen', + 'Upper Allen', + 'Itajobi', + 'Baltimore', + 'Nagra', + 'Wegorzewo', + 'Sansa', + 'Suaita', + 'Purral', + 'Narwar', + 'Denan', + 'Kandla Port', + 'Koubel-Koundia', + 'Airdrie', + 'Karumandi Chellipalaiyam', + 'Parol', + 'San Francisco la Union', + 'Kocasinan', + 'Sidi Abdallah', + 'Merzenich', + 'Correntina', + 'Saunda', + 'Paducah', + 'Keve', + 'Nandiala', + 'Indramayu', + 'Qusmuryn', + 'Aramangalam', + 'Mavorano', + 'Koppaka', + 'Corroios', + 'Thornbury', + 'Palm City', + 'Sao Felix da Marinha', + 'Giffnock', + 'Cardenas', + 'Kyaunggon', + 'Zhoukou', + 'Red Deer', + 'Constanza', + 'Libertador General San Martin', + 'Ducheng', + 'Orsova', + 'Bures-sur-Yvette', + 'Tixtla de Guerrero', + 'Tlachichilco', + 'Kangan', + 'Lyndhurst', + 'Wexford', + 'Chitipa', + 'Palagonia', + 'Olsberg', + 'Antongomena-Bevary', + 'Wayaobu', + 'Irosin', + "Sa'ada", + 'Lamwo', + 'Bibemi', + 'Bartow', + 'Floresti', + 'Kemin', + 'Baramandougou', + 'Baybay', + 'Nansang', + 'Frenstat pod Radhostem', + 'Mizhhiria', + 'Zelino', + 'Beni Abbes', + 'Tarkwa', + 'Ezhipram', + 'Vicente Noble', + 'Hitachi-ota', + 'Muhembo', + 'Ksar el Hirane', + 'Lauchhammer', + 'Agboville', + 'Big Bear City', + 'Oradea', + 'Mabitac', + 'Trashigang', + 'An Nasiriyah', + 'Belo Oriente', + 'Pampas', + 'Schifferstadt', + 'Guatemala City', + 'Pithampur', + 'I`zaz', + 'Poranki', + 'Arcola', + 'Perugia', + 'Betmangala', + 'Haqqulobod', + 'Wujiaying', + 'Ankazoabokely', + 'Agrestina', + 'Rodenbach', + 'Nowshahr', + 'Sierning', + 'Santa Maria de Jesus', + 'Madalena', + 'Tarrafal', + 'Mitoma', + 'Roseaux', + 'Wichita', + 'Grudziadz', + 'Zarnesti', + 'Findikli', + 'Sarnen', + 'Irpin', + 'Rouen', + 'Qishe', + 'Dammartin-en-Goele', + 'Hazel Dell', + 'Charikar', + 'Ostrzeszow', + 'Tunari', + 'Kingri', + 'La Reina', + 'Boriziny', + 'Nangavaram', + 'Jahangirpur Salkhani', + 'Mangobandar', + 'Gustavia', + 'Alangudi', + 'Naumburg', + 'Sarikishty', + 'Dania Beach', + 'Budaka', + 'Tillmans Corner', + 'Ramotswa', + 'Menges', + 'Dasuya', + 'Darreh Shahr', + 'Perumkulam', + 'Moorreesburg', + 'El Ejido', + 'Lingayen', + 'Fontana', + 'Ubaporanga', + 'Shoo', + 'Heroica Matamoros', + 'Bayog', + 'Marikal', + 'Da Nang', + 'Lampertheim', + 'Basbiti', + 'Ramonville-Saint-Agne', + 'Kuwait City', + 'Manakana', + 'Mandra', + 'Tehata', + 'Stein bei Nurnberg', + 'Crigglestone', + 'Brofodoume', + 'Trnava', + 'Thimphu', + 'Gurmia', + 'Cacem', + 'Alahina', + 'Mongo', + 'Khayelitsha', + 'Sadri', + 'Fukui', + 'Dharmaj', + 'Kaatsheuvel', + 'Dammarie-le-Lys', + 'Matsakabanja', + 'Ait Ouaoumana', + 'Kirovsk', + 'Savur', + 'Baranivka', + 'Kodaikanal', + 'Lantana', + 'Shache', + 'Jacobabad', + 'President Quirino', + 'Kozienice', + 'Coatetelco', + 'Tha Muang', + 'Fanlu', + 'Ejutla de Crespo', + 'Senhora da Hora', + 'Bhadarwah', + 'Almazora', + 'Americus', + 'Schaesberg', + 'Liulin', + 'Shahrak-e Ja`fariyeh', + 'Pathankot', + 'Kirkkonummi', + 'Koyulhisar', + 'Adamankottai', + 'Ketama', + 'Irineopolis', + 'Kavali', + 'Sambalhera', + 'Nanjian', + 'San Juan de Uraba', + 'Tola Khadda', + 'Mulheim', + 'Berhoum', + 'Hawaiian Paradise Park', + 'Marg`ilon', + 'Eilendorf', + 'Oostzaan', + 'Evanston', + 'Mantasoa', + 'Ixtlahuaca', + 'Capao da Canoa', + 'Baker', + 'Altintas', + 'Taipei', + 'Siktiahi', + 'Ramabitsa', + 'Tarmount', + 'Haciqabul', + 'Ellore', + 'Palangkaraya', + 'Mugumu', + 'Ed Damer', + 'Steinfurt', + 'Malthone', + 'Villagarzon', + 'Elizabeth City', + 'La Farlede', + 'Binaqadi', + 'Barquisimeto', + 'Simaria', + 'Castel Volturno', + 'Frickenhausen', + 'Ait Ikkou', + 'Gauravaram', + 'Ubeda', + 'Simcoe', + 'Oakley', + 'Capas', + 'Jixian', + 'Muthabana', + 'Masalli', + 'Leganes', + 'Beidaying', + 'Hyeres', + 'Vinnamala', + 'Chatteris', + 'Parit Buntar', + 'Khelil', + 'Igaci', + 'Raytown', + 'Janakpur', + 'Ilford', + 'Bojnurd', + 'Toyota', + 'Orte', + 'Saint-Brieuc', + 'The Nation / La Nation', + 'Ghulja', + 'Lagoa do Mato', + 'Mohelnice', + 'Lavumisa', + 'Harda Khas', + 'Pendlebury', + 'Sonakhal', + 'Unagatla', + 'Sandhurst', + 'Villa Krause', + 'Sherghati', + 'Supaul', + 'Busovaca', + 'Luathaha', + 'Liversedge', + 'Liberty', + 'Yian', + 'Sion', + 'Itamogi', + 'Berrouaghia', + 'Bharuch', + 'Waunakee', + 'Adel', + 'Crestline', + 'Savissivik', + 'Meiganga', + 'Sannai', + 'Cuizhuangzi', + 'Cold Lake', + 'Agrigento', + 'Rio Branco do Sul', + 'Carneirinho', + 'Viborg', + 'Munsan', + 'Big Lake', + 'Rute', + 'Mela Gudalur', + 'Mbala', + 'Mateus Leme', + 'Kakamega', + 'Al Atarib', + 'Bad Harzburg', + 'Tigbauan', + 'Phak Hai', + 'San Juan de la Costa', + "Cornate d'Adda", + 'Bewdley', + 'Nyimba', + 'Vedelago', + 'Asaba', + 'Bozyazi', + 'Tuxtla', + 'Alvin', + 'Castiglion Fiorentino', + 'Umag', + 'Taquaritinga do Norte', + 'Ghoti Budrukh', + 'Relangi', + 'Woodward', + 'Santiago de Tolu', + 'Marcali', + 'Stanley', + 'Dulay` Rashid', + 'Five Forks', + 'Jandaia do Sul', + 'Culfa', + 'Suzano', + 'Motomachi', + 'Ahermoumou', + 'Jose Cardel', + 'Marsella', + 'Tyngsborough', + 'Eijsden', + 'Checy', + 'Hamidiye', + 'Mocimboa da Praia', + 'Cossato', + 'Adjohon', + 'Jamapa', + 'Dahana', + 'Banfora', + 'Rabo de Peixe', + 'Caloto', + 'West Lampeter', + 'Princeton Meadows', + 'Whitwick', + 'Siversk', + 'Mpraeso', + 'Borovskoy', + 'Cockermouth', + 'Mogadishu', + 'Traipu', + 'Frechen', + 'Cabras', + 'Enkakad', + 'Bocas de Satinga', + 'Tomares', + 'Umbauba', + 'Itiki', + 'Nordhorn', + 'Macetown', + 'Quilengues', + 'Chiclana de la Frontera', + 'Lagoa Seca', + 'Zielonka', + 'Xinqing', + 'Pedro Carbo', + 'Vespasiano', + 'Masis', + 'Prichard', + 'Sandomierz', + 'Fulwood', + 'Bad Liebenzell', + 'Zvenyhorodka', + 'Bellevue', + 'Gudgeri', + 'Srikrishnapur', + 'Madgaon', + 'Piedecuesta', + 'Ibrahimpatnam', + 'Mandrosonoro', + 'Tlumach', + 'Citrus Springs', + 'Cabestany', + 'Metuchen', + 'Baxiangshan', + 'Bithauli', + 'Araguaina', + 'Ban Piang Luang', + 'Kamrej', + 'Chicaman', + 'Kishiwada', + 'Tabua', + 'San Rafael del Sur', + 'Cibolo', + 'Le Relecq-Kerhuon', + 'Boca Raton', + 'Amecameca de Juarez', + 'Radstock', + 'Launceston', + 'Gorantla', + 'Babar', + 'Jammalamadugu', + 'Gordes', + 'Vich', + 'Arroyo Grande', + 'Dvur Kralove nad Labem', + 'Novoukrainka', + 'Gurgunta', + 'Oued Cheham', + 'Salinopolis', + 'Oak Lawn', + 'Fatehgarh Churian', + 'San Alberto', + 'Wetaskiwin', + 'San Jose Pinula', + 'Montataire', + 'Aduku', + 'Planken', + 'Trussville', + 'Sidi Lmokhtar', + 'Machchand', + 'Moletai', + 'Grand-Lahou', + 'Ergoldsbach', + 'Sao Joao dos Patos', + 'Cajapio', + 'Sestao', + 'Bayshore Gardens', + 'Jaragua', + 'Canuelas', + 'Campo do Meio', + 'Chada', + 'Bibala', + 'Suining', + 'Granby', + 'Ostend', + 'Split', + 'Clark', + 'Baikunthapur', + 'Eppingen', + 'Bara Khurd', + 'Las Vigas de Ramirez', + 'Sharm ash Shaykh', + 'Sainthia', + 'Lowestoft', + 'Kaldenkirchen', + 'Acailandia', + 'Rosita', + 'Antardipa', + 'Ihaddadene', + 'Kennett', + 'Houlong', + 'Sriramapuram', + 'Nava Raipur', + 'Zielona Gora', + 'Biella', + 'Niceville', + 'Koscierzyna', + 'Lonkly', + 'Miramas', + 'Zubin Potok', + 'Sao Vicente Ferrer', + 'Fouka', + 'Rasak', + 'Nyzhnia Krynka', + 'Bijni', + 'West Bend', + 'Kurumul', + 'Golbaf', + 'Carencro', + 'Mercer Island', + 'Lai', + 'Rimini', + 'Labutta', + 'Goubellat', + 'Yakymivka', + 'Fianarantsoa', + 'Zhengding', + 'Vittoria', + 'Tactic', + 'Arrecife', + 'Parkes', + 'Ibicoara', + 'Gidi', + 'Afumati', + 'Dongning', + 'Tameslouht', + 'Ashwaubenon', + 'Alto Parana', + 'Mattanur', + 'Chinchali', + 'Monte Siao', + 'Kallanai', + 'Florania', + 'Ghorahi', + 'Uchqurghon Shahri', + 'Tres Isletas', + 'Bambara-Maounde', + 'Bela Vista de Goias', + 'Nova Granada', + 'Kesap', + 'Beldibi', + 'Hyderabad', + 'Otaki', + 'Bhuban', + 'Stansbury Park', + 'Halgur', + 'Arda', + 'Dalupura', + 'Maraveh Tappeh', + 'Kankandighi', + 'Chornomorske', + 'Nikopol', + 'Shinagawa-ku', + 'Zeralda', + 'St. Michael', + 'Fortaleza dos Nogueiras', + 'Nansan', + 'Edattala', + 'Phu Tu Son', + 'Cipo', + 'Bintulu', + 'Amayan', + 'Rainbow City', + 'Dougabougou', + 'Levakant', + 'Allada', + 'Tabursuq', + 'Hoshangabad', + 'Gerli', + 'Bardsir', + 'Sarsawa', + 'Manicaragua', + 'Sint-Pieters-Leeuw', + 'Pescantina', + 'Nimule', + 'Ambovombe', + 'Navsari', + 'Wilbraham', + 'Keene', + 'Novska', + 'Vallabh Vidyanagar', + 'Kifri', + 'Gornji Petrovci', + 'Bareggio', + 'Tosa', + 'Kafr Shukr', + 'Konotop', + 'Frei Miguelinho', + 'Pirapora do Bom Jesus', + 'Nemocon', + 'Ribeirao Bonito', + 'Kundli', + 'Zola Predosa', + 'Bileca', + 'Vargem Grande', + 'Martinopolis', + 'Madna', + 'Colonial Park', + 'Fecamp', + 'Sesto Fiorentino', + 'Bouzina', + 'Bischofswerda', + 'Saulkrasti', + 'Margram', + 'Zapresic', + 'Muriyad', + 'Ayun', + 'Harlingen', + 'San Juan de los Morros', + 'Kozy', + 'Kandern', + 'Taibao', + 'Savonlinna', + 'Fountainebleau', + "L'Ile-Perrot", + 'Zomin Shaharchasi', + 'PortoAlexandre', + 'Nes Ziyyona', + 'Watervliet', + 'Bonito de Santa Fe', + 'Murgod', + 'Aurisina', + 'Kochlowice', + 'Lierre', + 'Wellesley', + 'East Greenwich', + 'Jacarau', + 'Nawa', + 'Upper St. Clair', + 'Qalyub', + 'Darbhanga', + 'Balakliia', + 'Makulubita', + 'Giesen', + 'Sarkeghat', + 'Paiania', + 'Thandla', + 'Gravata', + 'Ad Dis', + 'Nawada Gobindganj', + 'Mosrah', + 'Ballwin', + 'Rehovot', + "Chateau-d'Olonne", + 'Barendrecht', + 'Kihei', + 'Forbes', + 'Van Wert', + 'Angola', + 'Sokuluk', + 'Gadarpur', + 'Beji', + 'Palmela', + 'Bad Lippspringe', + 'Al Badrashayn', + 'Angelim', + 'Higashimurayama', + 'Tangshan', + 'Fritzlar', + 'Hobyo', + 'Erumapalaiyam', + 'Kahului', + 'Varkkallai', + 'Sayula', + 'Waverly', + 'Koranampatti', + 'Peristeri', + 'Weilheim an der Teck', + 'Mustafakemalpasa', + 'Babolsar', + 'Concepcion Chiquirichapa', + 'Yueshanwan', + 'Sangeorgiu de Mures', + 'Edamon', + 'Moston', + 'Gabes', + 'Heesch', + 'Sahjanwa', + 'Auburn', + 'Sorel-Tracy', + 'Sagua de Tanamo', + 'Wassenaar', + 'Sarospatak', + 'Sapahi', + 'Kangayam', + 'Oodweyne', + 'Bac Kan', + 'Hole Narsipur', + 'Canmore', + 'Mulungu do Morro', + 'Fagnano Olona', + 'Sawankhalok', + 'Odanavattam', + 'Tiruvambalapuram', + 'Torotoro', + 'Kil Valur', + 'Koshizuka', + 'Kyonpyaw', + 'Annaberg-Buchholz', + 'Lissone', + 'Maracana', + 'Paysandu', + 'Batu', + 'Ciudad Acuna', + 'Kanavaikuli', + 'Lahaina', + 'Ma`an', + 'Comala', + 'Xiongzhou', + 'Coalcoman de Vazquez Pallares', + 'Benemerito', + 'Kuchinarai', + 'Lugo', + 'Kibuku', + 'Pirajui', + 'Fountain Valley', + 'Zentsujicho', + 'Shahreza', + 'Dragomer', + 'Puyehue', + 'Floridablanca', + 'Bitterfeld', + 'Bozkurt', + 'Sewa', + 'Soreang', + 'Varedo', + 'Narot Mehra', + 'Rogasovci', + 'Nukan', + 'Skipton', + 'Bidur', + 'Walldurn', + 'Ipero', + 'Aritao', + 'Breckerfeld', + 'Manakayi', + 'Narapalli', + 'Waraseoni', + 'Nogent-sur-Oise', + 'Itumbiara', + 'Ban Mae Sam Laep', + 'El Retorno', + 'Dunfermline', + 'Tamaraikkulam', + 'Dingli', + 'Ouadda', + 'Hillview', + 'Eceabat', + 'Yangmei', + 'Mamoudzou', + 'Dietikon', + 'Siauliai', + 'Pierrelatte', + 'Hamada', + 'Hooper', + 'Sakuho', + 'Beijing', + 'Limoeiro do Norte', + 'Ladario', + 'Karuveppampatti', + 'Sheffield', + 'Aguas de Lindoia', + 'Boac', + 'Mende', + 'Gohuma Bairia', + 'Riscani', + 'Koroth', + 'Sibenik', + 'Avalurpet', + 'Roberval', + 'Madinat as Sadis min Uktubar', + 'Rosoman', + 'Porto Alegre', + 'Brugherio', + 'Brody', + 'Keuruu', + 'Lehre', + 'Zawiercie', + 'Dalyoni Bolo', + 'Loay', + 'Kolonia', + 'Bussy-Saint-Georges', + 'Oulad Imloul', + 'Lagoa Formosa', + 'Wurselen', + 'Kestel', + 'Orhei', + 'Lubuagan', + 'Quixere', + 'Scottdale', + 'Caparrapi', + "Bruay-sur-l'Escaut", + 'Nova Ponte', + 'Rostam Kola', + 'Asuncion Nochixtlan', + 'Colton', + 'Little River', + "Jian'ou", + 'Diekirch', + 'Fateha', + 'Cimitarra', + 'Hombal', + 'Lindenhurst', + 'Ouled Djellal', + 'Comanesti', + 'Bousso', + 'Streamwood', + 'Roulia', + 'Duzce', + 'Asuke', + 'Libona', + 'Rellivalasa', + 'Ukwa', + 'Yavatmal', + 'Greasley', + 'Sivas', + 'Hukumati Gizab', + 'Balikpapan', + 'Qincheng', + 'Hongfengcun', + 'Nakai', + 'Oued Zem', + 'Pumalakkundu', + 'Umaria', + 'Sao Lourenco da Serra', + 'Amawom', + 'Barra do Mendes', + 'Aklim', + 'Sambrial', + 'Bunkeflostrand', + 'Taskent', + 'Rakitovo', + 'Nerima', + 'Waxhaw', + 'Hoogezand', + 'San Vicente de Tagua Tagua', + 'Recreio', + 'Lope de Vega', + 'Hejin', + 'Margherita', + 'Bend', + 'Strijen', + 'Manin', + 'Nogi', + 'Tilothu', + 'Manching', + 'Masindi Port', + 'Sumba', + 'Amizmiz', + 'Canada de Gomez', + 'Siddhapur', + 'Ankaramena', + 'Aleppo', + 'Sansanding', + 'Tirumakudal Narsipur', + 'Gumla', + 'Usa', + 'At Tawahi', + 'Koumantou', + 'De Panne', + 'Kukes', + 'Lenoir City', + 'Tiruppalaikudi', + 'Canyon Lake', + 'Nanpingcun', + 'Gubbio', + 'Jasaan', + 'Galaosiyo Shahri', + 'Mount Sinai', + 'Tulshia', + 'Sankt Johann im Pongau', + 'Sandi', + 'Banda', + 'Kilkunda', + 'Solymar', + 'Shenzhou', + 'As Sallum', + 'Baohezhuangcun', + 'Gogui', + 'Aarschot', + 'Kadappuram', + 'Sorkheh', + 'Gawler', + 'La Falda', + 'Masqat', + 'Bazeh Kalagh', + 'Forfar', + 'Kelafo', + 'Conde', + 'Porciuncula', + 'Palanas', + 'Cuyo', + 'Las Cabezas de San Juan', + 'Kranidi', + 'New Orleans', + 'Mettupalaiyam', + 'Kati', + 'Carregado', + 'Hornsby Bend', + 'Salvatierra', + 'Begamganj', + 'Cishan', + 'Draa Ben Khedda', + 'Eshtehard', + 'Sidi Daoud', + 'Las Nieves', + 'Nea Alikarnassos', + 'San Francisco Ixhuatan', + 'Luodong', + 'Waihee-Waiehu', + 'Rosolini', + 'Tundla', + 'Ash Shihaniyah', + 'SeaTac', + 'Daigo', + 'Solana Beach', + 'Kittanapalli', + 'Guspini', + 'Rahimyar Khan', + 'Antanambao', + 'New Silksworth', + 'Bixby', + 'Sahnaya', + 'Kudal', + 'Guaira', + 'Ibaiti', + 'Iksan', + 'Muttamtura', + 'Darnetal', + 'Karma', + 'Leyland', + 'Strzelin', + 'Tam Diep', + 'Tagaytay', + 'Finale Ligure', + 'Cottonwood', + 'Cutlerville', + 'Santa Cruz de Bezana', + 'Frydlant nad Ostravici', + 'Aracuai', + 'Huangyadong', + 'Herzele', + 'Sakarya', + 'Extremoz', + 'Bauta', + 'Kela Khera', + 'Castelvetrano', + 'Kalisz', + 'Qorovul', + 'Sanchez', + 'Tamezmout', + 'Boundji', + 'Bellinzago Novarese', + 'Tungi', + 'Ichenhausen', + 'Sao Sebastiao do Uatuma', + 'Inver Grove Heights', + 'Villefranche-de-Rouergue', + 'Uad Damran', + 'Rishon LeZiyyon', + 'Nellimarla', + 'Bountiful', + 'Sahaswan', + 'Kamonkoli', + 'Santo Augusto', + 'Hammersmith', + 'Breyten', + 'Northwich', + 'Nagambhotlapalem', + 'Montabaur', + 'Ammavarikuppam', + 'Amasya', + 'Bhankarpur', + 'Santa Rosa del Penon', + 'Anshun', + 'Feidh el Botma', + 'Abdurahmoni Jomi', + 'Rionero in Vulture', + 'Bundi', + 'Almargem', + 'McNair', + 'East Palo Alto', + 'Las Flores', + 'Carmo da Mata', + 'Wilkau-Hasslau', + 'Barentin', + 'Outat Oulad Al Haj', + 'Chemax', + 'Ayapango', + 'Ramacca', + 'Oton', + 'Ghoswari', + 'Al Fallujah', + 'Cheviot', + 'Alnavar', + 'Al Qasr', + 'Santo Domingo Suchitepequez', + 'Sulleru', + 'Barahpur', + 'Chapalamadugu', + 'Ar Rutbah', + 'Areia Branca', + 'Avenel', + 'Hoover', + 'Velykodolynske', + 'Beladi', + 'Changchun', + 'Linden', + 'Hillside', + 'Taxco de Alarcon', + 'Kathri', + 'Belemoka', + 'San-Pedro', + 'Ban Huai Hin', + 'Olovo', + 'Sundekuppam', + 'El Alto', + 'Totonicapan', + 'Mujiayu', + 'Makhtal', + 'Ikoma', + 'Sylhet', + 'Passo de Camarajibe', + 'Bad Driburg', + 'Rangapara', + 'Komarom', + 'Bakhmach', + 'Qionghu', + 'Ecatzingo', + 'Pallipram', + 'Taicheng', + 'Datu Piang', + 'Tlaltetela', + 'Preveza', + 'Cambuci', + 'Werkendam', + 'Ipira', + 'Gosport', + 'Grytviken', + 'Rondonopolis', + 'Phra Phutthabat', + 'La Puebla de Cazalla', + 'Leposaviq', + 'San Juan Cotzocon', + 'Sederot', + 'Nidiyanga', + 'Makamba', + 'Resistencia', + 'Rio Blanco', + 'Monte Escobedo', + 'Vasylkiv', + 'Eyl', + 'Fenoarivo', + 'Pokrov', + 'Bang Sao Thong', + 'Granite Bay', + 'Fortul', + 'Lenoir', + 'Trent Hills', + 'Le Petit-Quevilly', + 'Tifra', + 'Jaroslaw', + 'Perrysburg', + 'Ericeira', + 'Maniago', + 'Al Qusiyah', + 'Norridge', + 'Palamos', + 'Pochampalli', + 'Buni', + 'Preetz', + 'Anaconda', + 'Chinde', + 'Bakouma', + 'Jakar', + 'Tavros', + 'Doranala', + 'Mayiladi', + 'Villecresnes', + 'Phulgachhi', + 'Pen', + 'Somersworth', + 'Igrejinha', + 'Umburetama', + 'Kakumiro', + 'Arauquita', + 'Schwieberdingen', + 'Berkeley', + 'Alquizar', + 'Adigappadi', + 'Hardinxveld-Giessendam', + 'Baindur', + 'Beko', + 'Belley', + 'Mousoulou', + 'Ome', + 'Finnsnes', + 'High Point', + 'Budenheim', + 'Temara', + 'Sulejowek', + 'Grecia', + 'Deoghar', + 'Macerata', + 'Monghyr', + 'Hullhorst', + 'Tervuren', + 'On Top of the World Designated Place', + 'Isernhagen-Sud', + 'Parner', + 'Llanera', + 'Tsurugashima', + 'Dhamaun', + 'Porto Valter', + 'Loyalsock', + 'Guntersville', + 'Gandorhun', + 'Zella-Mehlis', + 'Pazin', + 'Bunyan', + 'Toyama', + 'Lamrasla', + 'Huliyar', + 'Springville', + 'Orkelljunga', + 'Pillutla', + 'Paruthur', + 'Zahedan', + 'Baskil', + 'Morteza Gerd', + 'Remchi', + 'Chiaravalle', + 'Grunstadt', + 'Sofifi', + 'Londrina', + 'Mazatlan', + 'Khathjari', + 'Chiang Klang', + 'Wulfrath', + "Qal'at Mgouna", + 'Irigny', + 'Senahu', + 'Perenchies', + 'Vero Beach', + 'Ocho Rios', + 'Castanhal', + 'Soe', + 'My Drarga', + 'Boxtel', + 'Hoyo de Manzanares', + 'Cruz Machado', + 'Morges', + 'Guano', + 'Anantapalle', + 'Tvrdosin', + 'Caojia', + 'Plaza Huincul', + 'Ranillug', + 'Yonezawa', + 'Parnu', + 'Zerizer', + 'Rabta', + 'Suginami-ku', + 'San Jose del Guaviare', + 'Khaira Tola', + 'Ain Oussera', + 'Badvel', + 'Wijnegem', + 'Frome', + 'Theux', + 'Caimbambo', + 'Wang Saphung', + 'Dabhoi', + 'Gebre Guracha', + 'Basatpur', + 'Zambrano', + 'Puttai', + 'Brainerd', + 'San Salvador El Seco', + 'Shostka', + 'Tabocas do Brejo Velho', + 'Tabriz', + 'Bhatpuri', + 'Arpajon', + 'Curti', + 'Hyde', + 'Cayetano Germosen', + 'Cafelandia', + 'Mnagueur', + 'Rygge', + 'Landskrona', + 'Kokubunji', + 'Resende', + 'Aguasay', + 'Painan', + 'Komagane', + 'Malhada de Pedras', + 'Zhutian', + 'Baabda', + 'Jackson', + 'Qoorlugud', + 'Fraserpet', + 'La Crau', + 'Pioltello', + 'Araure', + 'Ilsenburg', + 'Yanhewan', + 'Narayanpur', + 'Holtsville', + 'Vimmerby', + 'Binzhou', + 'Ligang', + 'Quillota', + 'Montmagny', + 'Malaga', + 'Juatuba', + 'Ascope', + 'Effia-Kuma', + 'Bellwood', + 'Encarnacion', + 'Mannur', + 'Puerto Santander', + 'Kendraparha', + 'Wewak', + 'Sendjas', + 'San Pedro Pinula', + 'Kampong Thom', + 'Mpanda', + 'Trebaseleghe', + 'Kerkyra', + 'Rogatec', + 'Katigang', + 'Yushu', + 'Saint-Hyacinthe', + 'Capelle aan den IJssel', + 'Eisenach', + 'Reinfeld', + 'Idri', + 'Kunnattur', + 'Cakung', + 'Rayadrug', + 'Baoshan', + 'Laramie', + 'El Meghaier', + 'Naperville', + 'Macatuba', + 'Katalpur', + 'Carpina', + 'Blyth', + 'Veseli nad Moravou', + 'Burhia Dhanghatta', + 'Svitlodarsk', + 'Lugait', + 'Rancho Cucamonga', + 'Tabara Arriba', + 'Spondon', + 'Marienberg', + 'Middelburg', + 'Huyton', + 'Sroda Slaska', + 'Woomera', + 'Bethalto', + 'Concepcion de Ataco', + 'Fagersta', + 'Halfmoon Bay', + 'Estancia', + 'Makow Mazowiecki', + 'Malangas', + 'Pittsburg', + 'Adukam', + 'West Melbourne', + 'Haverstraw', + 'Lousa', + 'Kulpsville', + 'Plasnica', + 'Charuanwan', + 'Foca', + 'Gombe', + 'Cordeiropolis', + 'Chakicherla', + 'Licey al Medio', + 'Conceicao das Alagoas', + 'Colonia', + 'Yisuhe', + 'Vignola', + 'San Martin Sacatepequez', + 'Mbanza-Ngungu', + 'Oppatavadi', + 'Eitorf', + 'Ubach-Palenberg', + 'Ranibennur', + 'Aklvidu', + 'Capoeiras', + 'Mucambo', + 'Palmares do Sul', + 'Kondakomarla', + 'Niteroi', + 'Sai Ngam', + 'City Bell', + 'Biougra', + 'White', + 'Kumru', + 'Alcala de Henares', + 'Kalawit', + 'Porto Xavier', + 'Balancan', + 'Vodice', + 'Zouping', + 'Nagawaram', + 'Mareth', + 'Kakraul', + 'Horten', + 'Padinjarebagam', + 'Karattuppalaiyam', + 'Redding', + 'Wolgast', + 'Ambrolauri', + 'Dhanot', + 'Nilakkottai', + 'Abaete', + 'Veendam', + 'Oslo', + 'Paiganapalli', + 'White Center', + 'Taminango', + 'Constitucion', + 'Begijnendijk', + 'Baragua', + 'Inverigo', + 'Belsandi Tara', + 'Rumst', + 'Pinner', + 'Reinheim', + 'Liancourt', + 'Villa Canas', + 'Metlika', + 'Balderton', + 'Gauripur', + 'Yamada', + 'Cardona', + 'Sartalillo', + 'Odaiyakulam', + 'Laguna Paiva', + 'Carolina', + 'Bhilavadi', + 'Al Qardahah', + 'Campo Bom', + 'Laichingen', + 'Montero', + 'Nagoya', + 'Portici', + 'Sherpur', + 'Baiheqiao', + 'Saint-Chamas', + 'Bloemfontein', + 'Songyang', + 'Mamfe', + 'Bijiao', + 'Tongobory', + 'Barra do Dande', + 'Revere', + 'Celtik', + 'Carigara', + 'Laindon', + 'Chapa de Mota', + 'Djanet', + 'Vinings', + 'Saltillo', + 'Gueoul', + 'Parnagua', + 'Burton upon Trent', + 'Bocaiuva do Sul', + 'Nova Xavantina', + 'Esteli', + 'Sremska Kamenica', + 'Pennsauken', + 'Bad Wurzach', + 'Banbury', + 'Nkowakowa', + 'Koloti', + 'Chaita', + 'Las Parejas', + 'Guerande', + 'Ski', + 'Suphan Buri', + 'Cheyenne', + 'San Isidro de Lules', + 'Cisternino', + 'Rajbalhai', + 'San Ferdinando di Puglia', + 'Nosivka', + 'Singhwara', + 'Ankarabato', + 'Dod Ballapur', + 'Wattignies', + 'Lebu', + 'Elangunnapuzha', + 'Korneuburg', + 'Saint Andrews', + 'Exmouth', + 'Menaa', + 'Bungotakada', + 'Isagarh', + 'Bilecik', + 'Oulad Bou Rahmoun', + 'Manambondro', + 'Port Morant', + 'Townsend', + 'Ca Mau', + 'Kostolac', + 'Presov', + 'Valle', + 'Sahambala', + 'Chapala', + 'Tepechitlan', + 'Uruacu', + 'Bangued', + 'Renton', + 'Ummannur', + 'Lalmanirhat', + 'Nurkot', + 'Brownfield', + 'San Miguel del Padron', + 'Toualet', + 'San Antonio Aguas Calientes', + 'Los Alamitos', + 'Jilib', + 'San Mateo Ixtatan', + 'Anapolis', + 'Burhanpur', + 'Yokotemachi', + 'Torrinha', + 'Mouzaia', + 'Harshin', + 'Cirencester', + 'Bentley', + 'Man', + 'Yezhi', + 'Kota', + 'Sovicille', + 'Otawara', + 'Zihuatanejo', + 'Charata', + 'Paduma', + 'Otake', + 'Guanta', + 'Aduru', + 'Mannarai', + 'Youghal', + 'Haacht', + 'Stowmarket', + 'Fourou', + 'Barari', + 'Libanggaon', + 'Amari', + 'Lucknow', + 'Babra', + 'Idanre', + 'Bedigoazon', + 'Acari', + 'Burslem', + 'Lohara', + 'Beersel', + 'Polillo', + 'Librazhd-Qender', + 'Kumalarang', + 'Tzitzio', + 'Bisceglie', + 'Karayilan', + "Samarra'", + 'Bafwasende', + 'North Arlington', + 'Souq Sebt Oulad Nemma', + 'Bhalswa Jahangirpur', + 'Wolfsburg', + 'Eningen unter Achalm', + 'Szubin', + 'Varadarajampettai', + 'Zelenodolsk', + 'Karagwe', + 'Vissannapeta', + 'Cheramkod', + 'Sanandaj', + 'Karben', + 'Bueng Khong Long', + 'Jaboatao', + 'Vrilissia', + 'Cumaral', + 'Akil', + 'Ap Da Loi', + 'Normanton', + 'Trois-Rivieres', + 'Almirante', + 'Esperalvillo', + 'Kongupatti', + 'Quirinopolis', + 'Lask', + 'Sainte-Luce-sur-Loire', + 'Castel San Giorgio', + 'Bang Phae', + 'Chinnayagudem', + 'Arsin', + 'Numata', + 'Sab` al Bur', + 'Cumaru', + 'Tecamac', + 'Rodelas', + 'Seyah Cheshmeh', + 'Kashan', + 'Nanzhangcheng', + 'Kendari', + 'Jurado', + 'Monrovia', + 'Peshawar', + 'Guacharachi', + 'Kloten', + 'Bandirma', + 'Quevedo', + 'Adekar Kebouche', + 'Huinca Renanco', + 'Dakpatthar', + 'Chicoutimi', + 'Baiyan', + 'Pimenteiras', + 'Las Brenas', + 'Kusnacht', + 'Burnie', + 'Ercolano', + 'Kroonstad', + 'Modena', + 'Kalna', + 'Bonneville', + 'Bellair-Meadowbrook Terrace', + 'Jiyyammavalasa', + 'Kisai', + 'Vadodara', + 'Nagtala', + 'Kandiyankovil', + 'Lorena', + 'Taphan Hin', + 'Juneau', + 'Iati', + 'Niksar', + 'Roy', + 'Kapoeta', + 'Samdhin', + 'Arafat', + 'Kornepadu', + 'Ait Faska', + 'Olevsk', + 'Rantoul', + 'Glencoe', + 'Stocksbridge', + 'Tela', + 'Chethakal', + 'Canatlan', + 'Guia de Isora', + 'Veglie', + 'Taguig City', + 'Qillin', + 'Harsinghpur', + 'Sitangkai', + 'Michigan City', + 'Nagaizumi', + 'Guariba', + 'El Seibo', + 'Woolton', + 'Tainai', + 'Mukher', + 'Cartama', + 'Suknadanga', + 'Philippsburg', + 'Ladysmith', + 'Atherton', + 'Baeza', + 'Yazikonak', + 'Santa Maria Texmelucan', + 'Ban Mae Kaluang', + 'Khiriawan', + 'Eschen', + 'Tobetsu', + 'Nova Vicosa', + 'Ankarongana', + 'Shahedshahr', + 'Sonoita', + 'Kudligi', + 'Saint-Felicien', + 'Bukama', + 'Nilgiri', + 'Zwevegem', + 'Muang Sing', + 'Pinhal', + 'Saranga', + 'Ebelo', + 'Toli', + 'Cataguases', + 'Miyaki', + 'Caracol', + 'Amol', + 'Basdeopur', + 'Cevicos', + 'Charlotte', + 'Canavieiras', + 'Deva', + 'North Shields', + 'Icaraima', + 'Hoskins', + 'Kamalshahr', + 'Guapiles', + 'Araguari', + 'Bouhlou', + 'Castilla La Nueva', + 'Azemmour', + 'Juvignac', + 'Medjedel', + 'Goksun', + 'San Justo', + 'Iyo', + 'Teploklyuchenka', + 'Yaounde', + 'Ain Kercha', + 'Treviglio', + 'Novi Pazar', + 'San Lazzaro di Savena', + 'Nakhon Ratchasima', + 'Alcantara', + 'Bull Mountain', + 'Oldeani', + 'Chardonnieres', + 'Chini', + 'Piketberg', + 'Baranoa', + 'Buldon', + 'Akora', + 'Santa', + 'Olivet', + 'Kouinine', + 'Vanipenta', + 'Shahr-e Babak', + 'Porto de Moz', + 'The Hills', + 'Kaharlyk', + 'Manpaur', + 'G`azalkent', + 'Hodmezovasarhely', + 'Oak Creek', + 'Kladanj', + 'Merouana', + 'Hiratsuka', + 'Alvares Machado', + 'Lagoa Dourada', + 'Mishan', + 'Puerto Deseado', + 'Befandriana Atsimo', + 'Supia', + 'Avon Lake', + 'Rialto', + 'Renca', + 'Mesra', + 'Rognac', + 'Pongode', + 'Birkhadem', + 'Talacogon', + 'Turhapatti', + 'Szigetszentmiklos', + 'Onoto', + 'Norala', + 'Sorala', + 'Diallassagou', + 'Handa', + 'Wieliczka', + 'Tilougguit', + 'Jaimalpura', + 'Allentown', + 'Crissiumal', + 'Varberg', + 'Abidjan', + 'Cesky Tesin', + 'Burgkirchen an der Alz', + 'Nagina', + 'Shahpur Baghauni', + 'Itarhi', + 'Bad Pyrmont', + 'Raksaha', + 'Pandireddigudem', + 'Sinfra', + 'Bayonne', + 'Bahir Dar', + 'Bobo-Dioulasso', + 'Tubaran', + 'Chihuahua', + 'Hun', + 'Rexburg', + 'Kherson', + 'Harad', + 'Saint-Fons', + 'Iazizatene', + 'Sao Pedro do Sul', + 'Tirmaigiri', + 'Otumba', + 'East Cleveland', + 'Bankoumana', + 'Goiatins', + 'Kushtagi', + 'Patori', + 'Bertrix', + 'Palanan', + 'Achaljamu', + 'Elanad', + 'Mahmud-e Raqi', + 'Bougou', + 'American Fork', + 'East Barnet', + 'Mangrauni', + 'Raghunathpur', + 'Ierapetra', + 'Crvenka', + 'Mentor', + 'Fidirana', + 'Sangareddi', + 'Pflugerville', + 'Kupiskis', + "Vil'nyans'k", + 'Sonipat', + 'Zestaponi', + 'Goffstown', + 'Lengshuijiang', + 'Scottsdale', + 'Rosemont', + 'Garsekurti', + 'Collierville', + 'Bulaevo', + 'Tosagua', + 'Burzaco', + 'Silea', + 'Roosendaal', + 'Tuusula', + 'Turnu Magurele', + 'An Nabk', + 'Sasebo', + 'San Vicente de Castellet', + 'Andranomenatsa', + 'Tbilisi', + 'Postojna', + 'Kessel-Lo', + 'Arnsberg', + 'Itarare', + 'Mazeikiai', + 'Pujehun', + 'Vicovu de Sus', + 'Okayama', + 'Sarauli', + 'Lakeville', + 'Dashtigulho', + 'Itapolis', + 'Al Hazm', + 'Hammelburg', + 'Berastagi', + 'Orlu', + 'Castanet-Tolosan', + 'Lumbayanague', + 'Oeiras do Para', + 'Whitney', + 'Tubara', + 'Santa Maria Madalena', + 'Salinas de Hidalgo', + 'Sangonera la Verde', + 'Noisy-le-Sec', + 'Glenview', + 'Bern', + 'Song Cau', + 'Dyer', + 'Chabal Kalan', + 'Segala Mba', + 'Upper Hutt', + 'Massigui', + 'Nalgonda', + 'Terra Boa', + 'Svrljig', + "'Ain Tellout", + 'Bellefontaine Neighbors', + 'Sahibpur Kamal', + 'Nieuwleusen', + 'Acarlar', + 'Chuo', + 'Hellesdon', + 'Kotor', + 'Montepulciano', + 'Emstek', + 'Daye', + 'Kona', + 'Saint-Genis-Pouilly', + 'Puerto Rico', + 'Sitamau', + 'Anguera', + 'North Lebanon', + 'Pesqueira', + 'Guarei', + 'Pendurti', + 'Falls', + 'Pinillos', + 'Sighetu Marmatiei', + 'Bangui', + 'Tchitado', + 'Tanga', + 'Kesamudram', + 'Narayangarh', + 'Dapitan', + 'Kaithahi', + 'Saint-Cyr-sur-Mer', + 'Jandaira', + 'Bedum', + 'Tomatlan', + 'Pirapemas', + 'Bemahatazana-Belobaka', + 'Poblacion', + 'El Cua', + 'Maldonado', + 'Pando', + 'Madappalli', + 'Cumru', + 'Al Mahwit', + 'Chake Chake', + 'Oria', + 'Zimnicea', + 'Kivisto', + 'Bumahen', + 'Wichian Buri', + 'Carrascal', + 'Pedro Betancourt', + 'Hire Megalageri', + 'Ternate', + 'Saoner', + 'Itaituba', + 'Vohitrafeno', + 'Caluula', + 'Muggia', + 'Aizenay', + 'Khokha', + 'Ipokia', + 'Venmani Padinjara', + 'Siklos', + 'Yangshuwa', + 'Kanekallu', + 'Golbey', + 'Gengzhuangqiaocun', + 'Gustavsberg', + 'Parabiago', + 'Ambohibary', + 'Valladolid', + 'Matamey', + 'Bisee', + 'Tete', + 'Vreden', + 'Toribio', + 'Fucecchio', + 'Zangareddigudem', + 'Ceglie Messapico', + 'Licinio de Almeida', + 'Ad Dabbah', + 'Sapian', + 'Naranjo', + 'Wollaston', + 'Celaya', + 'Dire', + 'Gajiginhalu', + 'Mulug', + 'Upper Makefield', + 'Rodriguez', + 'Bocoio', + 'Thalwil', + 'Carate Brianza', + 'Bondada', + 'Ayagoz', + 'Xiada', + 'Vohburg an der Donau', + 'Mansala', + 'Rafha', + 'Anastacio', + 'Nove Mesto na Morave', + 'Ramechhap', + 'Ambinanindrano', + 'Leibnitz', + 'Alvaraes', + 'Baure', + 'Sohano', + 'Tunja', + 'Goriar', + 'Msambweni', + 'Aibak', + 'Penugolanu', + 'Castagneto Carducci', + 'Ecclesall', + 'Dunmore', + 'North Londonderry', + 'Carnot-Moon', + 'Pau Brasil', + 'Taka', + 'Sihor', + 'Terra Nova', + 'Choachi', + 'Tenri', + 'Port Louis', + 'Laoag', + 'San Martin de la Vega', + 'Nguigmi', + 'Bendapudi', + 'Eminabad', + 'Aldenham', + 'Vianen', + 'Nagasamudram', + 'Zemst', + 'Khalkhal', + 'Mount Clemens', + 'Teotlaltzingo', + 'Siribala', + 'Ligao', + 'Dom Pedrito', + 'Bushey', + 'Namakgale', + 'Waiuku', + 'Juruaia', + 'Sikasso', + 'Laplace', + 'Gao', + 'Casarano', + 'Ratangarh', + 'Brunssum', + 'Castrovillari', + 'Tarkeshwar', + 'Ruisui', + 'Monschau', + 'Alat', + 'Hetauda', + 'Tunglangan', + 'Panipat', + 'El Chal', + 'Bhanumukkala', + 'Don Galo', + 'Saddiqabad', + 'Santo Domingo Petapa', + 'Bingol', + 'Piraju', + 'Camp Verde', + 'Chembagaramanpudur', + 'Behara', + 'Harrison', + 'Nagulapadu', + 'Knemis Dades', + 'Youwangjie', + 'Sarab', + 'Rustavi', + 'Obama', + 'Dymka', + 'Bijie', + 'Tairan Camp', + 'Sahoria Subhai', + 'Southampton', + 'Port Moody', + 'Guaratinga', + 'Xa Muteba', + 'Ahmadnagar', + 'Limanowa', + 'Dembi Dolo', + 'Samrala', + 'Aichach', + 'Codroipo', + 'Nattarampalli', + 'Induno Olona', + 'Gosen', + 'Bevato', + 'Elkridge', + 'Trissino', + 'Siping', + 'Bou Hanifia el Hamamat', + 'Juayua', + 'Tordera', + 'Osnabruck', + 'Zegoua', + 'Ramain', + 'Varanasi', + 'Miedzyrzecz', + 'Bradfordville', + 'Arkansas City', + 'Sidi Mohamed Lahmar', + 'Paravai', + 'Baltara', + 'Paide', + 'Manakara', + 'Edassheri', + 'Usiacuri', + 'Yildirim', + 'Keflavik', + 'Tsetserleg', + 'Paris', + 'Gagnoa', + 'Xintang', + 'Sarni', + 'Xico', + 'Capitan Bermudez', + 'Contenda', + 'Garhwa', + 'Huayin', + 'Basuo', + 'Tenjo', + 'Cachan', + 'Quimperle', + 'Misato', + 'Pittsgrove', + 'Dumont', + 'Salford', + 'Bontoc', + 'Lexington Park', + 'Yame', + 'Narasaraopet', + 'Kesla', + 'Ystad', + 'Laqraqra', + 'Milot', + 'Benoy', + 'Jalandhar', + 'Qahderijan', + 'Wake', + 'Flowing Wells', + 'Santana do Acarau', + 'Kurdi', + 'Sison', + 'Mazamet', + 'Montrouis', + 'Kalaruch', + 'Sarotar', + 'Dabuleni', + 'Thepaha Raja Ram', + 'Glenn Heights', + 'Tuxtepec', + 'Whickham', + 'Targu Frumos', + 'Lauriya Nandangarh', + 'Taineste', + 'Medjez el Bab', + 'Sagon', + 'Cinisello Balsamo', + 'Bartalah', + 'Valabhipur', + 'Tangdukou', + 'Barreirinha', + 'Calintaan', + 'Binan', + 'Rampur', + 'Malatya', + 'Clemson', + 'Wyszkow', + 'Carmiano', + 'Yeovil', + 'Cajobi', + 'Yabuki', + 'Dorud', + 'Marrupa', + 'Maitland', + 'Jahrom', + 'Kurgunta', + 'Tonyrefail', + 'Virreyes', + 'Kalu Khan', + 'Al Qurayya', + 'Libertyville', + 'Kharagpur', + 'Woodley', + 'Mineola', + 'Chalon-sur-Saone', + 'Bouhmama', + 'Mena', + 'San Cataldo', + 'Quipungo', + 'Alakamisy-Ambohimaha', + 'Gloversville', + 'Chuimatan', + 'Nadugadda', + 'Borjomi', + 'Sibonga', + 'Palanpur', + 'Kodinar', + 'Asingan', + 'Chahchaheh', + 'Dobrova', + 'Ruzomberok', + 'Chhoti Sadri', + 'Langzhong', + 'Anekal', + 'Pontal do Parana', + 'Muhammadabad', + 'Moreira', + 'Civita Castellana', + 'Kpalime', + 'Mahespur', + 'Louny', + 'Venkatapuram', + 'Khaw Zar Chaung Wa', + 'Dahutang', + 'Data', + 'Cheddra', + 'Madridejos', + 'DeLand', + 'Koewarasan', + 'Palaiseau', + 'Ropczyce', + 'Urakawa', + 'Tanque Novo', + 'Guider', + 'Kiruhura', + 'Kasese', + 'Murrhardt', + 'Andingcun', + 'Kuhdasht', + 'Freire', + 'Singera', + 'Panglong', + 'Tampa', + 'Mirik', + 'Hatti Mattur', + 'Nakatsugawa', + 'Jitwarpur Nizamat', + 'Carmo', + 'Jocotan', + 'Forquilha', + 'Vargem Grande do Sul', + 'Peniche', + 'Xinying', + 'Nahulingo', + 'Goranboy', + 'San Pedro Sula', + 'Burr Ridge', + 'Leatherhead', + 'Belisce', + 'Villalonga', + 'Santa Anita', + 'Mayluu-Suu', + 'Skovde', + 'Buston', + 'Domodossola', + 'Avelgem', + 'El Malah', + 'Azusa', + 'Neyriz', + 'Coronel Suarez', + 'Saquarema', + 'Meizhou', + 'Apia', + 'Jawor', + 'Saint-Pol-sur-Mer', + 'Heguri', + 'Bobangui', + 'Montalegre', + 'Ben Taieb', + 'Pande', + 'Horsell', + 'Sanjo', + '`Aynkawah', + 'Sfantu-Gheorghe', + 'Escuinapa', + 'Talikota', + 'Guapiara', + 'Point Pleasant', + 'Ambohipandrano', + 'Khangaon', + 'Namlea', + 'Kottapalem', + 'Sebastiao Laranjeiras', + 'Phra Samut Chedi', + 'Madanancheri', + 'Farnworth', + 'Coshocton', + 'Garrison', + 'Peso da Regua', + 'Jaguaruna', + 'Katihar', + 'West Fargo', + 'Melaka', + 'Ambohimanambola', + 'Pabegou', + 'Nossa Senhora das Dores', + 'Burladingen', + 'Byumba', + 'Vallikunnam', + 'Mohan Eghu', + 'San Julian', + 'Miracema do Tocantins', + 'Palma', + 'Goh', + 'DeKalb', + 'Azle', + 'Mont-de-Marsan', + 'Slovenske Konjice', + 'Manazary', + 'Shende', + 'Portland', + 'Lamarao', + 'Reinach', + 'Chrzanow', + 'Hendek', + 'Iwakura', + 'Agua Clara', + 'Capim', + 'Brasilandia', + 'Port Colborne', + 'Ilsfeld', + 'Cienaga de Oro', + 'Faxinal dos Guedes', + 'Earlestown', + 'Andranomeva', + 'Visalia', + 'Tazhava', + 'Linquan', + 'Rampur Jalalpur', + 'Cricova', + 'Cholula de Rivadabia', + 'Apiai', + 'Vilandai', + 'Castellana Grotte', + 'Baturbari', + 'Jandiala', + 'Rive-de-Gier', + 'Feltham', + 'Laguna Niguel', + 'Kannal', + 'Purmerend', + 'Succasunna', + 'Ejea de los Caballeros', + 'Dolisie', + 'Vernag', + 'Tabount', + 'Kirksville', + 'Rahuri', + 'Nanjai Kilabadi', + 'Parigi', + 'Dhamsain', + 'Bainbridge', + 'Zumpango', + 'Le Beausset', + 'Westphalia', + 'Cabinda', + 'Bagahi', + 'Valmontone', + 'Al `Ajami', + 'Maromby', + 'Maaseik', + 'Wuyishan', + 'Ulbroka', + 'Santiago Juxtlahuaca', + 'Ranomena', + 'Buadiposo-Buntong', + 'Khurai', + '`Aqrah', + 'Priverno', + 'Geldrop', + 'Balandougou', + 'Legnago', + 'Don Carlos', + 'Keitumkawn', + 'Levice', + 'Gulam', + 'Ratne', + 'Jiayuguan', + 'Gidha', + 'Juba', + 'Ksar Belezma', + 'Puerto Baquerizo Moreno', + 'Ponta Pora', + 'Sidrolandia', + 'Achim', + 'North Lynnwood', + 'Haslett', + 'Porto Ferreira', + 'Anqing', + 'Takahagi', + 'Fray Luis A. Beltran', + 'Basudebpur', + 'Concon', + 'Mangochi', + 'McKeesport', + 'Matheu', + 'Sumbha', + 'Murajpur', + 'Champerico', + 'Iki', + 'Port-Bouet', + 'Santa Luzia', + 'Chitaldrug', + 'Baliqchi', + 'Uthai Thani', + 'Az Zubaydiyah', + 'Cicero', + 'Rampurwa', + 'El Salto', + 'Duero', + 'Littleover', + 'Ropazi', + 'Andradas', + 'Tirur', + 'Caramoan', + 'San Carlos Alzatate', + 'Zuojiawu', + 'Karacasu', + 'Namioka', + 'Brumunddal', + 'West Milford', + 'Alandatte', + 'Dumingag', + 'Petrolandia', + 'Arachchalur', + 'Urussanga', + 'Cerrillos', + 'Ortega', + 'Kanyobagonga', + 'Atibaia', + 'Eustis', + 'Sefaatli', + 'Lasam', + 'Montalto di Castro', + 'Cihuatlan', + 'Cirebon', + 'Rangewala', + 'Tekkalakote', + 'Cameron Park', + 'Bardaskan', + 'Manambidala', + 'Bukittinggi', + 'Sora', + 'Dashouping', + 'Escarcega', + 'Tezoyuca', + 'Karadichittur', + 'Roskilde', + 'West Caln', + "Pereyaslav-Khmel'nyts'kyy", + 'Senmanat', + 'Formosa', + 'Schaumburg', + 'Tarnobrzeg', + 'Kadaladi', + 'Ouled Haddaj', + 'Vuyyuru', + 'Baruipur', + 'Teniente Primero Manuel Irala Fernandez', + 'Menaceur', + 'Sedeh Lanjan', + 'Ciney', + 'Amboavory', + 'Jale', + 'Kalmar', + 'Koori', + 'Alsager', + 'Gulagac', + 'Zwedru', + 'Kadiyampatti', + 'Wilkes-Barre', + 'Bremerhaven', + 'Motru', + 'Bad Tolz', + 'Nha Trang', + 'Andranomavo', + 'Punta Prieta', + 'Masmouda', + 'Vavatenina', + 'Divandarreh', + 'Atambua', + 'Krosuru', + 'Wrecsam', + 'Apache Junction', + 'Barri', + 'Shingucho-shingu', + 'Kusaha', + 'Sidi Ahmed El Khadir', + 'West Springfield', + 'Al Wajh', + 'Massangena', + 'Doda', + 'Shutayil', + 'Messamena', + 'Navalcarnero', + 'Bellaire', + 'Nichelino', + 'Serra Azul', + 'Rantabe', + 'Padaivedu', + 'Monteroni di Lecce', + 'Drodro', + 'Rees', + 'Bulgan', + 'Fraijanes', + 'Montbrison', + 'Kangaroo Flat', + 'Urbach', + 'Lindon', + 'Olen', + 'Langgons', + 'Velim', + 'Marhamat', + 'Anamur', + 'Milattur', + 'Forecariah', + 'Quartier Morin', + 'Worb', + 'Playas', + 'Kingsville', + 'North Strabane', + 'Kolumalapalle', + 'Narippatta', + 'Yotsukaido', + 'Takahashi', + 'Dulce Nombre de Maria', + 'Reguiba', + 'Dapi', + 'Elk River', + 'Karaagac', + 'Duba', + 'Rasnov', + 'Cabrobo', + 'Easthampton', + 'Parvatipuram', + 'Husainpur', + 'Nipomo', + 'Chettimangurichchi', + 'Bekitro', + 'Itapagipe', + 'Palestina', + "Erval d'Oeste", + 'Vasilika', + 'Kolappalur', + 'Batken', + 'Bank', + 'Qorako`l Shahri', + 'Manor', + 'Majanji', + 'Al Balyana', + 'Niederkassel', + 'Dulce Nombre de Jesus', + 'Mason City', + 'Lavello', + 'Zaruma', + 'Mignoure', + 'Namyslow', + 'Hagaranahalli', + 'Filippoi', + 'Ita', + 'Wuzhong', + 'Bedfordview', + 'Mollet', + 'Malipakar', + 'Innisfil', + 'Cehegin', + 'Stone', + 'Lake St. Louis', + 'Panskura', + 'Injibara', + 'Festus', + 'Cicevac', + 'Busra ash Sham', + 'Krompachy', + 'Mumford', + 'Phulmalik', + 'Jundiai', + 'Annaka', + 'Senhora dos Remedios', + 'Anthem', + 'Sadarak', + 'Naga City', + 'Xiping', + 'Planeta Rica', + 'Kilgore', + 'Ciudad Sabinas Hidalgo', + 'Tsaratanana', + 'Puduppalli Kunnam', + 'Manilva', + 'Colorno', + 'Majsperk', + 'Pibrac', + 'Nova Gorica', + 'Sorbolo', + 'Halberstadt', + 'Magalang', + 'Cozumel', + 'Chanco', + 'Gympie', + 'Colwood', + 'Vire', + 'Troina', + 'Oudenbosch', + 'Bertinoro', + 'El Bazouriye', + 'Cabra', + 'Alakamisy-Ambohimahazo', + 'Milan', + 'Sanare', + 'Trencin', + 'Minas', + 'Santa Vitoria do Palmar', + 'Saintes', + 'San Jose de las Lajas', + 'Governador Dix-Sept Rosado', + 'Ville-la-Grand', + 'Stjordal', + 'Kirkwall', + 'Aigaleo', + 'Uppukkottai', + 'Lakeway', + 'Cuchi', + 'Kamina', + 'Rawa Mazowiecka', + 'Xinyuan', + 'Scarsdale', + 'Tosashimizu', + 'Akot', + 'Yaritagua', + 'East Rancho Dominguez', + 'Pongoz', + 'Ambazoa', + 'Liuchuan', + 'Higashiura', + 'Blackfoot', + 'Gniezno', + 'Blanchard', + 'Zadar', + 'Nakaechi', + 'Mairena del Aljarafe', + 'Massama', + 'Mobo', + 'Kezmarok', + 'La Porte', + 'Berching', + 'Siegsdorf', + 'New Albany', + 'Half Way Tree', + 'Jharka', + 'Zinacantepec', + 'Draveil', + 'Bek-Abad', + 'Fayetteville', + 'Oyam', + 'Pasil', + 'Clamart', + 'Mbuzini', + 'Ouenza', + 'Perdur', + 'Soamanandrariny', + 'Hanawa', + 'Yekambarakuppam', + 'Mashiki', + 'Thibodaux', + 'Nijkerk', + 'Hayang', + 'Malabon', + 'Aparri', + 'Bwana Mkubwa', + 'Charqueada', + 'Kuju', + 'Kwamhlanga', + 'Alimos', + 'Ypane', + 'Sahave', + 'Marib', + 'Shirley', + 'Bunbury', + 'Talayan', + 'Ljungby', + 'San Juan de Betulia', + 'Laixi', + 'La Ferte-Bernard', + 'Lagos de Moreno', + 'Tangbian', + 'Adalar', + 'Nyamira', + 'Desert Hot Springs', + 'Datia', + 'Cognac', + 'Jaltipan de Morelos', + 'Ponsacco', + 'Dindori', + 'Hlaingbwe', + 'Delijan', + 'Cirie', + 'Une', + 'Boldesti-Scaeni', + 'Sapeacu', + 'Nagdah', + 'Douar Ezzerarda', + 'Bali', + 'Stevenage', + 'Saryshaghan', + 'Melchor Romero', + 'Barbana', + 'Zanjan', + 'Sennan', + 'Ponta Delgada', + 'Royse City', + 'Wonthaggi', + 'Putaendo', + 'Kokawa', + 'Wloszczowa', + 'Warner Robins', + 'Kranenburg', + 'Tome', + 'Usilampatti', + 'Puerto Pinasco', + 'El Maiten', + 'Gurgaon', + 'Immenstadt im Allgau', + 'Wisla', + 'Gannavaram', + 'Yingzhong', + 'Masho Khel', + 'Reitz', + 'Belen de Umbria', + 'Ripollet', + 'Lauaan', + 'Beira', + 'Ratu', + 'Mure', + 'Medicine Hat', + 'Ixcatepec', + 'Bois-des-Filion', + 'Nogent-le-Rotrou', + 'Djibouti', + 'University of California-Santa Barbara', + 'Byahatti', + 'Bentonville', + 'Danau Kandimarg', + 'Tevragh Zeina', + 'Sattar', + 'Tranoroa', + 'Mengdong', + 'Luz', + 'Wuyang', + 'Batemans Bay', + 'Dinas', + 'Itauna', + 'Artena', + 'Carouge', + 'Xylokastro', + 'Bahia de Caraquez', + 'Marabella', + 'Bremerton', + 'Ixtlahuacan del Rio', + 'Garchitorena', + 'Huittinen', + 'Fonsorbes', + 'Bafia', + 'Da Lat', + 'Pasian di Prato', + 'Sarayonu', + 'Chiman', + 'Colombo', + 'Kirikera', + 'Pemmperena', + 'Grunwald', + 'Savalgi', + 'Chambly', + 'Puduppatti', + 'Himamaylan', + 'Lansdowne', + 'Douar Mzoura', + 'Powell', + 'Erfurt', + 'Kizhake Chalakudi', + "L'Arbaa Nait Irathen", + 'Galmi', + 'Junagarh', + 'Murgap', + 'Sallanches', + 'Loutete', + 'Rosa Zarate', + 'Caninde', + 'Santa Tecla', + 'Skoghall', + 'Banswada', + 'Cresskill', + 'Dabaozi', + 'Cortland', + 'Ennery', + 'Ifanirea', + 'Antsaidoha-Bebao', + 'Tepic', + 'Qiryat Gat', + 'Cabeceiras de Basto', + 'Pirot', + 'Waxahachie', + 'De Pere', + 'Salsomaggiore Terme', + 'Potenza Picena', + 'Wright', + 'Resadiye', + 'Melito di Napoli', + 'Toui', + 'Guercif', + 'Daga', + 'Porto Feliz', + 'Sinende', + 'Goasi', + 'Kikube', + 'North Tidworth', + 'Narona', + 'Capitao Eneas', + 'Makakilo', + 'Billere', + 'Tabas', + 'Klang', + 'Agogo', + 'Turnov', + 'Fairhaven', + 'Muriae', + 'Chakai', + 'Maniamkulam', + 'Seberang Jaya', + 'Jaboticatubas', + 'Burley', + 'Four Square Mile', + 'Kirchlinteln', + 'El Quetzal', + 'Mar del Plata', + 'Elattur', + 'Mezica', + 'Brunn am Gebirge', + 'Quetta', + 'Morokweng', + 'Kitanagoya', + 'Manacapuru', + 'Towamencin', + 'Aragona', + 'Regla', + 'Caldeirao Grande', + 'Musina', + 'Jacksonville', + 'Azul', + 'Winter Park', + 'Englefield Green', + 'Ambon', + 'Lucena', + 'Huntington Station', + 'Itarema', + 'San Francisco Chimalpa', + 'Ondokuzmayis', + 'Basford', + 'Antsaravibe', + 'Meilen', + 'Tangermunde', + 'Wijchen', + 'Castilleja de la Cuesta', + 'Lanark', + 'Usak', + 'Wall', + 'Mijas', + 'Sitionuevo', + 'East Lake', + 'Mahabo-Mananivo', + 'Dhoraji', + 'Jalacingo', + 'Willstatt', + 'Nakhl-e Taqi', + 'Opelousas', + 'Golo-Djigbe', + 'Santiago Nonualco', + 'Pulsano', + 'Simrol', + 'Ihnasya al Madinah', + 'Pozzallo', + 'Ramayipatti', + 'Sihaul', + 'Wanze', + 'Senduria', + 'Ergue-Gaberic', + 'Mauldin', + 'Sempeter pri Gorici', + 'Ammanabrolu', + 'Mitrapur', + 'Massarosa', + 'Binnish', + 'La Tour-de-Peilz', + 'Lavaltrie', + 'Barsbuttel', + 'Seberi', + "Murang'a", + 'Macherla', + 'Acharipallam', + 'Setana', + 'Yichun', + 'Lugus', + 'Parnamirim', + 'Kayes', + 'Chinu', + 'Tubmanburg', + 'Cekme', + 'Mehdauli', + 'Vaulx-en-Velin', + 'Waikabubak', + 'Fontibon', + 'Omaha', + 'Pambujan', + 'Kassorola', + 'Khonj', + 'La Maddalena', + 'Fandrandava', + 'Chinna Mupparam', + 'Nea Smyrni', + 'Burgdorf', + 'Ituporanga', + 'Rayamangalam', + 'Albury', + 'Paranapanema', + 'Smiltene', + 'Lohmar', + 'Puliyankunnu', + 'Tiruvalla', + 'Hochberg', + 'Minto', + 'Antelope', + 'Mohanur', + 'Wiang Sa', + 'Dobrich', + 'Ingelheim', + 'Shetou', + 'Gavle', + 'Svedala', + 'Borogani', + 'Kisoro', + 'Ortenberg', + 'Uttarpara', + 'Rajaldesar', + 'Al Badari', + 'Masinigudi', + 'Gold Coast', + 'Indiana', + 'Swissvale', + "Al Jazirah al Hamra'", + 'Santa Maria Capua Vetere', + 'Mangala', + 'Upper Bicutan', + 'Hacilar', + 'Woltersdorf', + 'Khwazakhela', + 'Santa Fe de Antioquia', + 'Gammasa', + 'Iwashita', + 'Bohmte', + 'Tondabayashicho', + 'Salobrena', + 'Unebicho', + 'Isaszeg', + 'Bloomsburg', + 'Vidor', + 'Niquero', + 'Niepolomice', + 'Halacho', + 'Khanpur Khairanti', + 'Sao Roque', + 'Shively', + 'Fox Crossing', + 'Postmasburg', + 'Vicentinopolis', + 'Rafael Delgado', + 'Fuglafjordhur', + 'Bekapaika', + 'Rastede', + 'Devnya', + 'Derecik', + 'Nida', + 'Odayarpatti', + 'Bala', + 'Harra', + 'Ain Youcef', + 'Kenge', + 'Sapone', + 'Dongtai', + 'Ratnapur', + 'Giron', + 'Kartuzy', + 'Lake Villa', + 'Kolaccheri', + 'Kiridh', + 'Hattersheim', + 'Daheba', + 'Et Taiyiba', + 'Ciudad del Plata', + 'Ohringen', + 'Tegina', + 'Ishii', + 'Gahmar', + 'Lancaster', + 'Carmel', + 'Firminy', + 'Akishima', + "Milla'ab", + 'Beparasy', + 'Esperanza', + 'Bignay', + 'Spruce Grove', + 'Krommenie', + 'Hollviken', + 'Westminster', + 'Shymkent', + 'Majhaulia', + 'Biscarrosse', + 'Kadur Sahib', + 'Luce', + "Al Ha'ir", + 'Teluk Intan', + 'Dubove', + 'Qiaotouba', + 'Qasbat Tadla', + 'North Walsham', + 'Aspe', + 'Dokkum', + 'Plaridel', + 'Sonsbeck', + "Cava de' Tirreni", + 'Santa Elena', + 'Barka Gaon', + 'Asagicinik', + 'Dagua', + 'Campina Verde', + 'Kaitaia', + 'Leverkusen', + 'Merchtem', + 'Kiwoko', + 'Samborondon', + 'Palm Valley', + 'Fengjia', + 'Muhos', + "'Ain Kerma", + 'Sihma', + 'Tuminkatti', + 'Letychiv', + 'Notse', + 'Pearsall', + 'Jeypore', + 'San Antonio Palopo', + 'Kingstown', + 'Lislique', + 'Sannat', + 'Monnickendam', + 'Kurabalakota', + 'Miranorte', + 'Rudersberg', + 'Kasama', + 'Granja', + 'Amarwa Khurd', + 'Ad Diwaniyah', + 'Evington', + 'Warman', + 'Kuttampuzha', + 'Mons', + 'Korsholm', + 'Gourma Rharous', + 'General Alvear', + 'Matelica', + 'Bongabon', + 'Irituia', + 'Son en Breugel', + 'Chauny', + 'Bayeux', + 'Unicov', + 'Shaler', + 'Aesch', + 'Rahata', + 'Porangaba', + 'Hattingen', + 'Ocampo', + 'Pirna', + 'Perunad', + 'Umm Badr', + 'Ramganj Mandi', + 'Saidia', + 'Mutata', + 'Manatuto', + 'Lambayeque', + 'Grasse', + 'Centreville', + 'Bandrele', + 'Glogow', + 'Canagatan', + 'Trisshileri', + 'Pavona', + 'Diamniadio', + 'Harsola', + 'Gulariya', + 'Dubendorf', + 'San Prisco', + 'Maissade', + 'Agios Nikolaos', + 'Dubak', + 'Nalut', + 'Bhadrachalam', + 'Upper Moreland', + 'Geyve', + 'El Tejar', + 'Castilla', + 'Amsin', + 'Meulebeke', + 'San Francisco El Alto', + 'Presidente Getulio', + 'Pakwach', + 'Mayfield', + 'Kalawana', + 'Evosmos', + 'Killarney', + 'Zhubei', + 'El Ksiba', + 'Sierpc', + 'Lambari', + 'Fakfak', + 'Dawlish', + 'Kambaliyampatti', + 'Dianke', + 'Gaoya', + 'Almenara', + 'Molina de Segura', + 'Zighout Youcef', + 'San Jose Poaquil', + 'Louvres', + 'Los Altos', + 'Newton Aycliffe', + 'Chesterfield', + 'Korhogo', + 'Srbac', + 'Warstein', + 'Talladega', + 'Tigaon', + 'Pozos', + 'Raja Pakar', + 'Kuttiyeri', + 'Tres Cachoeiras', + 'Luena', + 'Betatao', + 'Sredisce ob Dravi', + 'West Monroe', + 'Sonabedha', + 'Rhenen', + 'Talainayar Agraharam', + 'Serido', + 'Campobasso', + 'Zabkowice Slaskie', + 'Harji', + 'Ubata', + '`Ajab Shir', + 'Tatoufet', + 'Hailun', + 'Kiratot', + 'El Idrissia', + 'Liannong', + 'Nedelisce', + 'Pirangi', + 'Beringen', + 'Leopoldo de Bulhoes', + 'Northolt', + 'Quesada', + 'Peumo', + 'Zitiste', + 'Kerman', + 'Cigli', + 'Gaibandha', + 'Tostado', + 'Ilog', + 'Mohana', + 'Erbach', + 'Mahasoabe', + 'Latifpur', + 'Rajim', + 'Tirhassaline', + 'Rathenow', + 'Strendur', + 'Grigny', + 'Skoczow', + 'Belwa', + 'Kasavanampatti', + 'Kalinagar', + 'Navappatti', + 'Megara', + 'Lolotique', + 'Saint-Junien', + 'Pijino del Carmen', + 'Guelph/Eramosa', + 'Solok', + 'Ciudad del Este', + 'Khagaria', + 'Kinogitan', + 'La Garenne-Colombes', + 'Manaquiri', + 'Telgte', + 'Igaracu do Tiete', + 'Mantsala', + 'Bogatic', + 'St. Cloud', + 'Huntertown', + 'Smithville', + 'Nueva Valencia', + 'Piru', + 'Yukarikaraman', + 'Merzifon', + 'Cosham', + 'Kharian', + 'Mantes-la-Ville', + 'Duanzhuang', + 'Kashipur', + 'Seaside', + 'Orchha', + 'Djemmorah', + 'Kocarli', + 'Mojkovac', + 'Nigel', + 'Kursunlu', + 'Soyagaon', + 'Pamuru', + 'Bassila', + 'Di An', + 'Vaureal', + 'El Dificil', + 'Troyan', + 'Toca', + 'Bet Shemesh', + 'Kayalpattanam', + 'Bernards', + 'Zomba', + 'Okabecho-okabe', + 'Nedroma', + 'Kostel', + 'Mosbach', + 'Miyauchi', + 'Jhitkahiya', + 'Rhymney', + 'Banisilan', + 'Medina', + 'Sayarpuram', + 'Landsberg', + 'Sevastopol', + 'Ceara-Mirim', + 'Assisi', + 'Goudomp', + "Debark'", + 'Melrose Park', + 'Le Rheu', + 'Port Douglas', + 'San Andres Tuxtla', + 'Princetown', + 'Seybaplaya', + 'Riegelsberg', + 'Cagayan de Oro', + 'Lommel', + 'Wapi', + 'Feira de Santana', + 'Obertshausen', + 'Imarui', + 'Soavinandriana', + 'Strathmore', + 'Kanke', + 'Arraial do Cabo', + 'Matsudo', + 'Pandhana', + 'Sao Miguel do Guapore', + 'Medea', + 'Rheinfelden (Baden)', + 'Taglio', + 'Korgan', + 'Pantabangan', + 'Bhattiprolu', + 'Lingampet', + 'Puerto Pimentel', + 'Velampatti', + 'Vilsbiburg', + 'Mianpur Dubauli', + 'Panguipulli', + 'Hafr al Batin', + 'Brasnorte', + 'Vignate', + 'Frederikshavn', + 'Alpena', + 'Pagbilao', + 'Villers-les-Nancy', + 'Chagalamarri', + 'Dispur', + 'Menemen', + 'Baqershahr', + 'Jandola', + 'Oborniki Slaskie', + 'Bandlaguda', + 'Goulburn', + 'Safotulafai', + 'Dreieich', + 'Galatsi', + 'Meixedo', + 'Banovici', + 'San Martino Buon Albergo', + 'Recani', + 'Prudnik', + 'Sao Miguel do Araguaia', + 'Sunkarevu', + 'New Castle', + 'Ban Thung Tam Sao', + 'Nariman', + 'Pata Ellamilli', + 'Capitolio', + 'Dobele', + 'Leicester', + 'Giovinazzo', + 'Ribeiro do Amparo', + 'Pailitas', + 'San Pedro Ayampuc', + 'Stalowa Wola', + 'Khargone', + 'Lustenau', + 'Sale', + 'Narhan', + 'Rubiataba', + 'Arceburgo', + 'Hokitika', + 'Vila Frescainha', + 'Lomme', + 'Lazarevac', + 'Tikrit', + 'Sudak', + 'Phrae', + 'Ramapo', + 'Ninomiya', + 'Hrazdan', + 'Taguasco', + 'Serravalle', + 'Bushtyno', + 'Gobo', + 'Kuttalam', + 'Awans', + 'Chancay', + 'Jocotenango', + 'Woodhouse', + 'KwaDukuza', + 'Wildau', + 'Batobato', + 'Crest Hill', + 'Balvadi', + 'Karkudalpatti', + 'Santa Ines', + 'Guacari', + 'Mantena', + 'Ladera Ranch', + 'Sulechow', + 'Matruh', + 'Isla de Maipo', + 'Gothva', + 'Frutillar', + 'Raxruha', + 'Machesney Park', + 'Wingene', + 'Lejanias', + 'Le Chesnay', + 'Bissendorf', + 'Abadiania', + 'Ometepec', + 'Enna', + 'Petarukan', + 'Boone', + 'Awbari', + 'Annaram', + 'Boki-Were', + 'Al Mijlad', + 'Raiparthi', + 'Aougrout', + 'Ranchi', + 'Onojo', + 'Saumalkol', + 'Atri', + 'Kara-Kol', + 'Lauria Inferiore', + 'San Felice Circeo', + 'Wooburn', + 'Agualva', + 'Fotadrevo', + 'Herenfa', + 'Berlin', + 'Astolfo Dutra', + 'Gahini', + 'Ambanja', + 'Hargeysa', + 'Santa Cruz do Capibaribe', + 'Ertis', + 'Esperantina', + 'Biloxi', + 'Hang Tram', + 'Diinsoor', + 'Asfour', + 'Pula', + 'Cacaopera', + 'Noida', + 'Pittsfield', + 'Le Muy', + 'Barletta', + 'Buraydah', + 'Ingolstadt', + 'Chautham', + 'Northwest Harborcreek', + 'Oldsmar', + 'Neder-Over-Heembeek', + 'Kamisu', + 'Puerto Piritu', + 'Ambatolahy', + 'Daru', + 'New Brighton', + 'Queluz', + 'Epernay', + 'Bacalar', + 'Ban Nikhom Phatthana', + 'Valbonne', + 'Yondo', + 'Khowrmuj', + 'Jingdezhen', + 'Campana', + 'Kuli', + 'Ogimachi', + 'Biskupiec', + 'Framingham', + 'Lomma', + 'Papraur', + 'Mukumbura', + 'Kawayan', + 'Ncora', + 'Zhaoling', + 'Boscombe', + 'Abbeville', + 'Reisterstown', + 'Tongeren', + 'Joal-Fadiout', + 'Rosario de Lerma', + 'Velpuru', + 'Douarnenez', + 'Sofia', + 'Itayanagi', + 'Ekinozu', + 'Bonanza', + 'Mohlanapeng', + 'Cudworth', + 'Barga', + 'Okinawa', + 'Owase', + 'Ainan', + 'Nyunzu', + 'Yokohama', + 'Aiud', + 'Tachov', + 'Khagam', + 'Anosiarivo', + 'Khust', + 'Apolda', + 'Bogra', + 'Djinet', + 'Holiday City-Berkeley', + 'Carmo do Rio Verde', + 'Kirchseeon', + 'Victorica', + 'Lahar', + 'Veranopolis', + 'Bechar', + 'Noceto', + 'Nossa Senhora da Gloria', + 'Bhaluhar', + 'Hofu', + 'Sozopol', + 'Kyabe', + 'Sosua', + 'Benedikt', + 'Bad Neuenahr-Ahrweiler', + 'Narendrapatnam', + 'Gurramkonda', + 'Pinhel', + 'Shiling', + 'Nadol', + 'Paredes', + 'Adjido', + 'Trebnje', + 'Yelpur', + 'Sirpur', + 'Barvala', + 'Angol', + 'Birpur Barapatti Pindraun', + 'Hendijan', + 'Parakou', + 'Mangaratiba', + 'Schwabisch Hall', + 'Sarqan', + 'Aleshtar', + 'Warin Chamrap', + 'West Des Moines', + 'Cutervo', + 'Valiyakumaramangalam', + 'Kottoppadam', + 'Sukth', + 'Sambhal', + 'Velliyod', + 'Waldshut-Tiengen', + 'Lakhnaur', + 'Barrocas', + 'Djamaa', + 'Matale', + 'Ban Phai', + 'Sao Paulo de Olivenca', + 'Harar', + 'Barbasa', + 'Kukatpalli', + 'Aisho', + 'Raynham', + 'Harborcreek', + 'Bafra', + 'Gibsons', + 'Cluj-Napoca', + 'Hoeselt', + 'Acopiara', + 'Filipstad', + 'Camardi', + 'Bunol', + 'Rania', + "Su'ao", + 'Konen Agrahar', + 'Sidi Qacem', + 'Chapada dos Guimaraes', + 'Bad Berleburg', + 'Thabazimbi', + 'Bradley', + 'Masif Sarsink', + 'Anse Rouge', + 'Galten', + 'Oshoba', + "Alta Floresta D'Oeste", + 'Ranaghat', + 'Patchur', + 'Rameswaram', + 'Fonadhoo', + 'Kuraymah', + 'Bosanska Krupa', + 'Cajica', + 'Sabou', + 'Fundacion', + 'Koba', + 'Rudra Nagar', + 'Tskhinvali', + 'Itarantim', + 'Mirzapur', + 'Mocajuba', + 'Berazategui', + 'Penjamo', + 'Doctor Mora', + 'Boleslawiec', + 'Angat', + 'Siraha', + 'Rock Ferry', + 'Salt', + 'Az Zintan', + 'Livno', + 'Winterville', + 'Daryabad', + 'Newton Mearns', + 'Milovice', + 'Nanqiao', + 'Nord', + 'Doba', + 'Guayacanes', + 'Didcot', + 'Skelmersdale', + 'Ivoamba', + 'Roessleville', + 'Sadovoye', + 'Magugpo Poblacion', + 'Toritama', + 'Mulakaledu', + 'Baia da Traicao', + 'Pissila', + 'Echuca', + 'Les Cayes', + 'Gajwel', + 'San Jose de Jachal', + 'Swedru', + 'Ribeirao', + 'Zhetibay', + 'Monatele', + 'Gibraleon', + 'Kufstein', + 'Chak Five Hundred Seventy-five', + 'Sterling', + 'Khattan', + 'Kuse', + 'Euless', + 'Baggao', + 'Al Juwayyidah', + 'Ilobasco', + 'Assi Bou Nif', + 'Ikniwn', + 'Gudja', + 'Monteiro', + 'Bryn Mawr-Skyway', + 'Corona de Tucson', + 'Sonson', + 'Clevedon', + 'Palestrina', + 'Uberherrn', + 'Civitella in Val di Chiana', + 'Balya', + 'Vinanivao', + 'Alexandria', + 'Merida', + 'Kursumlija', + 'Delgado', + 'Menton', + 'Dharampur Bande', + 'Goiana', + 'Matican', + 'Carballo', + 'Itapebi', + 'Minsk Mazowiecki', + 'Bhadaur', + 'Saidu Sharif', + 'Lalla Mimouna', + 'Mian Sahib', + 'Borzna', + 'Pakenham', + 'Al Kut', + 'Guemoukouraba', + 'Dhandhuka', + 'Crawfordsville', + 'Arak', + 'Acahay', + '`Abasan al Kabirah', + 'Farashband', + 'San Tomas', + 'Calasparra', + 'Ambahoabe', + 'Bayindir', + 'Merauke', + 'Ayagawa', + 'Ndjamba', + 'Lakewood', + 'Krishnanagar', + 'Kyustendil', + 'Porto Franco', + 'Anoka', + 'Tulsa', + 'De Haan', + 'Caluco', + 'Dumraon', + 'Fauske', + 'Jogiara', + 'Rambha', + 'Campina Grande do Sul', + 'Pontevedra', + 'Brejolandia', + 'Sundarpur', + 'Waltikon', + 'Putten', + 'Jardim', + 'Siemianowice Slaskie', + 'Buchen in Odenwald', + 'Ningde', + 'Tonsberg', + 'Shaliuhe', + 'Siracusa', + 'Galleh Dar', + 'Ponneri', + 'Gifhorn', + 'Avarua', + 'Longzhou', + 'Wenxicun', + 'Pontardulais', + 'Alipur', + 'Doetinchem', + 'Maravatio de Ocampo', + 'Elma', + 'Paravur Tekkumbhagam', + 'Oak Hills Place', + 'Dorou', + 'Galapagar', + 'Prata', + 'Bytca', + 'Kanmaki', + 'Ban Pong Tao', + 'Antsohihy', + 'Ban Ang Sila', + 'Gorisnica', + 'Abrera', + 'Visaginas', + 'Suoluntun', + 'Le Perreux-Sur-Marne', + 'Durbat', + 'Ourinhos', + 'Homa Bay', + 'Kolkwitz', + 'Gornji Grad', + 'Soroca', + 'Licata', + 'Zhangshanying', + 'Shuangcheng', + 'Shariff Aguak', + 'Redcliff', + 'Selargius', + 'Zapotlan del Rey', + 'Uetersen', + 'Rochedale', + 'Mongeri', + 'Tonala', + 'Lloydminster', + 'Ribeira Brava', + 'Xingcheng', + 'Baku', + 'Ban Dung', + 'Klatovy', + 'Empangeni', + 'Chundale', + 'Sorontona', + 'Dieppe', + 'Grandville', + 'Udawantnagar', + 'Qaqortoq', + 'Bischheim', + 'Urucui', + 'Uychi', + 'Kalispell', + 'Amman', + 'Esplugas de Llobregat', + 'Lohfelden', + 'Nacimiento', + 'Phongsali', + 'Ngerulmud', + 'Mulsen', + 'Yby Yau', + 'Balassagyarmat', + 'Malingaon', + 'Xionglin', + 'Glenvar Heights', + 'Miho', + 'North Liberty', + 'Dongshan', + 'Bauang', + 'Beguedo', + 'Cruz Grande', + 'Douar Trougout', + 'Primrose', + 'Merrimack', + 'Raigarh', + 'Potomac', + 'Voorhees', + 'Dalippur', + 'Castle Pines', + 'La Montanita', + 'Sabang', + 'Vintar', + 'Mikumi', + 'Sydney', + 'Tarhjicht', + 'Nizao', + 'Cahors', + 'Elland', + 'Diplahan', + 'Kayankulam', + 'Custodia', + 'Felipe Carrillo Puerto', + 'Paraguacu', + 'Lohafary', + 'Austintown', + 'Huixquilucan', + 'Pulpi', + 'Oakleaf Plantation', + 'Katsina', + 'Florennes', + 'Bad Honnef am Rhein', + 'Brenes', + 'West Linn', + 'Xanthi', + 'Saint-Saulve', + 'Sierra Bullones', + 'Dravograd', + 'Bizen', + 'Kurman', + 'Kuzma', + 'Kolagallu', + 'Bordj Ghdir', + 'Jogeva', + "Sofiyivs'ka Borshchahivka", + 'Pipra', + 'Lubeck', + 'Oppegard', + 'Kuopio', + 'Tuscumbia', + 'Kasaji', + 'Fort Atkinson', + 'Tamar', + 'Middelfart', + 'Grumo Nevano', + 'Downey', + 'Singhanwala', + 'Kawasaki', + 'Opglabbeek', + 'Maun', + 'Bosel', + 'Benaulim', + 'Smethwick', + 'Maromandia', + 'Hawaiian Gardens', + 'Jantho', + 'Malangam', + 'Rock Hill', + 'Livingstone', + 'Jaranwala', + 'Krong Kep', + 'West Covina', + 'Belzig', + 'Kitagata', + 'Fountain', + 'San Lorenzo de Descardazar', + 'Bati', + 'Quzanli', + 'Hosuru', + 'Poco Verde', + 'Simeulu', + 'Yangquan', + 'Shahzadpur', + 'Lopik', + 'Tarogong', + 'Iraiyur', + 'Freiberg', + 'Corinto', + 'Ukiha', + 'Alindao', + 'Ambohimahavelona', + 'Sosan', + 'Bhagabanpur', + 'Madamba', + 'Liubymivka', + 'Hassan', + 'Sham Shui Po', + 'Barbalha', + 'Wonju', + 'Taftanaz', + 'Waipio', + 'Guidan Roumdji', + 'Vohringen', + 'Crusinallo', + 'Nagareyama', + 'Geel', + 'Takahama', + 'Czarna Bialostocka', + 'Matthews', + 'Fleury-Merogis', + 'Tall `Aran', + 'Kamikawa', + 'Rose Belle', + 'Anorombato', + 'Wolfsberg', + 'Montreal', + 'Macrohon', + 'Miribel', + 'Cobanlar', + 'Gelsenkirchen', + 'Noblesville', + 'Sabaur', + 'Aizkraukle', + 'El Bayadh', + 'Bir Jdid', + 'Gunjur', + 'Nauta', + 'Browns Mills', + 'Shawnee', + 'Bredasdorp', + 'Camas', + 'Malebennur', + 'Ninh Binh', + 'Alto do Rodrigues', + 'Wilton Manors', + 'Fort Hunt', + 'Usia', + 'Lorgues', + 'Sanrha', + 'Bluffton', + 'Kendallville', + 'Preddvor', + 'Xovos', + 'Staoueli', + 'James Island', + 'Pampa del Infierno', + 'Lucaya', + 'Chino Valley', + 'Fort Leonard Wood', + 'Mirpur Bhtoro', + 'Ixtapa Zihuatanejo', + 'Albemarle', + 'Bekkaria', + 'Payatas', + 'Vitanje', + 'Koila Dewa', + 'Zhaoqing', + 'Sabac', + 'Kakonko', + 'Hojambaz', + 'Voinjama', + 'Xiaba', + 'Ramasingavaram', + 'Of', + 'Champoton', + 'Burntwood', + 'Viernheim', + 'Estoril', + 'Aflou', + 'Ampanefena', + 'Kamiamakusa', + 'Juan L. Lacaze', + 'Motkur', + 'My Luong', + 'Vernouillet', + 'Balatan', + 'Samaipata', + 'Alwa Tirunagari', + 'Saku', + 'Kuilsrivier', + 'Lynn Haven', + 'Maisach', + 'Bingerville', + 'Alicia', + 'Riversdale', + 'Bishunpur', + 'Tepoztlan', + 'Vishakhapatnam', + 'Gameleira', + 'Nyanza', + 'Bad Frankenhausen', + 'Huasca de Ocampo', + 'Kasongan', + 'Tortoreto', + 'Moschato', + 'Requena', + 'Kelowna', + 'Nyahanga', + 'Pohadi', + 'Kalibo', + 'Round Rock', + 'Pequannock', + 'Haifa', + 'Ezpeleta', + 'Boosaaso', + 'Oberschleissheim', + 'Seesen', + 'Alexandreia', + 'Salihli', + 'Mandali', + 'Xoxocotla', + 'Jakkampalaiyam', + 'Bradford West Gwillimbury', + 'West Perth', + 'Jaszbereny', + 'Vukovar', + 'Wittstock', + 'Dartmouth', + 'Zacatecas', + 'Oswego', + "Debre Werk'", + 'Annemasse', + 'Juripiranga', + 'Tultitlan de Mariano Escobedo', + 'Coachella', + 'Zagubica', + 'Altepexi', + 'Balao', + 'Velappadi', + 'Pamukkale', + 'West Vancouver', + 'Encamp', + 'Gudibanda', + 'Bensenville', + 'Augusta', + 'Natitingou', + 'Ganyesa', + 'Jiujiang', + 'Bad Schwartau', + 'Kings Norton', + 'Dharampuri', + 'Huanta', + 'Iganga', + 'Buckeburg', + 'Perryville', + 'Bingham', + 'Severn', + 'As Sulayyil', + 'Les Coteaux', + 'Jinmingsi', + 'Mel Nariyappanur', + 'Timimoun', + 'Nato', + 'Unisan', + 'Danao', + 'Mount Hagen', + 'Fiesole', + 'Concepcion Las Minas', + 'Zagorje', + 'Eilenburg', + 'Vardenik', + 'Ribeirao Branco', + 'Bismil', + 'Lichinga', + 'Reinosa', + 'Paray-le-Monial', + 'Villamediana de Iregua', + 'Madisonville', + 'Cheam', + 'Qabatiyah', + 'Bagnacavallo', + 'Shankou', + 'San Giuseppe Vesuviano', + 'Penaflor', + 'Amatenango del Valle', + 'Vanderbijlpark', + 'Coelemu', + 'Labiod Medjadja', + 'Olkusz', + 'Shefar`am', + 'Ulan Hua', + 'Sirka', + 'Caceres', + 'Gurh', + 'Oildale', + 'Colonial Heights', + 'eMuziwezinto', + 'Uster', + 'Pampur', + 'Martinsville', + 'Suttamalli', + 'Go Cong', + 'San Miguel de Papasquiaro', + 'Aliabad', + 'Huaura', + 'Denderleeuw', + 'Kremiss', + 'Kattukkottai', + 'Sakaka', + 'Khuran Milik', + "Al Ma`alla'", + 'Belluno', + 'Liptovsky Mikulas', + 'Baghra', + 'Touboro', + 'Science City of Munoz', + 'Trzebinia', + 'Filandia', + 'Myjava', + 'Ramachandrapuran', + 'Agdangan', + 'Bourzanga', + 'Barstow', + 'Annigeri', + 'Taio', + 'Deokali', + 'Lake Country', + 'Taizhou', + 'Adwick le Street', + 'Quilon', + 'Partesh', + 'Cwmbran', + 'Vaerlose', + 'San Calixto', + 'Oued Sly', + 'Lomazzo', + 'Guzelbahce', + 'Fishkill', + 'Annapolis', + 'Washington Terrace', + 'Keansburg', + 'Xintangcun', + 'Eastwood', + 'Sinmperekou', + 'Long Hill', + 'Roswell', + 'Budakeszi', + 'Lincolnia', + 'Flagstaff', + 'Eynesil', + 'Ban Wiang Ka Long', + 'Groveton', + 'Des Peres', + 'Namacunde', + 'Zlotow', + 'Chittoor', + 'Torre del Greco', + 'Morrinhos', + 'Upper Chichester', + 'Marousi', + 'Calimete', + 'Oytal', + 'Sao Joao dos Angolares', + 'Anenii Noi', + 'Perry', + 'Ait Melloul', + 'Kitchener', + 'Amboronabo', + 'Burtonwood', + 'Croydon', + 'San Celoni', + 'Suhaj', + 'Hod HaSharon', + 'Kitenkela', + 'Alagappapuram', + 'Ramat HaSharon', + 'Tortona', + 'Rota', + 'Innisfail', + 'Cuyahoga Falls', + 'Guadix', + 'Wil', + 'Vemuladivi', + 'Taungup', + 'Itaocara', + 'San Pedro Mixtepec', + 'Konce', + 'Puerto Guzman', + 'Mahuwa Singhrai', + 'North Merritt Island', + 'Most', + 'Lahstedt', + 'Westland', + 'Liuma', + 'Charagua', + 'Krasnogorskiy', + 'Pakarya Harsidhi', + 'Beni Oulid', + 'Daqing', + 'Ecorse', + 'Pineto', + 'Olbernhau', + 'Dorfen', + 'Madeira', + 'Sassnitz', + 'Susegana', + 'Suamico', + 'Spring', + 'Milazzo', + 'Erada', + 'Obernburg am Main', + 'Oak Harbor', + 'Marokarima', + 'Malangawa', + 'McAllen', + 'Merrill', + 'Pe de Serra', + 'Bilohorodka', + 'Dhakaich', + 'Malhador', + 'Wenatchee', + 'Almere', + 'Benguela', + 'Pisek', + 'Matam', + 'Sidi Bouzid', + 'Chhota Udepur', + 'Tehran', + 'Panjakent', + 'Itapage', + 'Quarteira', + "Mi'eso", + 'Saverne', + 'Panchimalco', + 'Parambil', + 'San Miguel de Salcedo', + 'Sanwas', + 'Sidhap Kalan', + 'Umraniye', + 'Falavarjan', + 'Gaalkacyo', + 'La Ferte-sous-Jouarre', + 'Schwalbach', + 'La Junta', + 'Timbuktu', + 'Jessore', + 'Tomisato', + 'Parachinar', + 'Myslowice', + 'Beelitz', + 'Minehead', + 'Samadiala', + 'Mankera', + 'San Pedro Sacatepequez', + 'Gaithersburg', + 'Pongnam', + 'Chambery', + 'Wareham', + 'Catu', + 'Gangania', + 'Shingu', + 'Sawahlunto', + 'Aydincik', + 'Somvarpet', + 'Beshariq', + 'Hongjiang', + 'Nallamadu', + 'Hengelo', + 'Sidi Tabet', + 'Pucioasa', + 'Salvaterra', + 'Zhongbai', + 'Pital', + 'Acu', + 'La Ligua', + 'Kalugumalai', + 'Raharpur', + 'La Grande', + 'Sint-Lievens-Houtem', + 'Ban Tha Pho', + 'Shangluhu', + 'Ciudad Madero', + 'Matias Barbosa', + 'Yara', + 'Lamitan', + 'Port Laoise', + 'Adiyaman', + 'Jaguey Grande', + 'Douai', + 'Tecuci', + 'Tifni', + 'Changsha', + 'Acatzingo', + 'Eilat', + 'South Ogden', + 'Talsi', + 'Dzuunmod', + 'Kafr al Kurdi', + 'Cochrane', + 'Xigaze', + 'Terra Santa', + 'Na Klang', + 'Parsa', + 'Side', + 'Noshiromachi', + 'Tepehuacan de Guerrero', + 'Makri', + 'Bernex', + 'Magway', + 'Modugno', + 'East Gwillimbury', + 'Dornakal', + 'The Crossings', + 'Gazi', + 'Dengjiazhuang', + 'Betroka', + 'Manno', + 'Hausjarvi', + 'Menifee', + 'Qobustan', + 'Ban Bang Pu Mai', + 'Macau', + 'Lithgow', + 'Kissa', + 'Kenadsa', + 'Mosul', + 'Letterkenny', + 'Conda', + 'Poonamallee', + 'Huruta', + 'Chennevieres-sur-Marne', + 'Camiri', + 'Cazanga', + 'East Bakersfield', + 'Baiji', + 'Garsfontein', + 'Bad Iburg', + 'Glen Carbon', + 'Arvin', + 'Sobhapur', + 'Talas', + 'Aalborg', + 'Bagnara Calabra', + 'Pokhram', + 'Aragoiania', + 'Aravankara', + 'East Nottingham', + 'Ramjibanpur', + 'Kilmangalam', + 'Talisay', + 'Krusevac', + 'Baranain', + 'Gauli Palasiya', + 'Sieverne', + 'Chakradharpur', + 'Ipil', + 'Xiamen', + 'Henichesk', + 'Wajir', + 'Polonuevo', + 'Las Piedras', + 'Vysokyi', + 'Barra do Pirai', + 'Malancha', + 'Vendome', + 'Kisarazu', + 'Ambohidanerana', + 'Villareal', + 'San', + 'Ipele', + 'Bologna', + 'Berwyn', + 'Kadambanad', + 'Diest', + 'Tuy Hoa', + 'Neuilly-sur-Seine', + 'Kiryas Joel', + 'Takoma Park', + 'Suwa', + 'Heiloo', + 'Chorbogh', + 'Teror', + 'Passo do Sertao', + 'Akim Swedru', + 'Bucheon', + 'Upper', + 'Kobuleti', + 'Adesar', + 'Hugli', + 'El Khroub', + 'Mwaya', + 'Atome-Avegame', + 'Dhahran', + 'Ratnapura', + 'Roncq', + 'Ambatomena', + 'Ichihara', + 'Waiblingen', + 'Anapoima', + 'Tizi Nisly', + 'Schiffdorf', + 'Merrick', + 'Jesenik', + 'Jnane Bouih', + 'Victoria Falls', + 'Genhe', + 'Charne', + 'Bicas', + 'Yandrapalle', + 'Onklou', + 'Arezzo', + 'Taung', + 'Paphos', + 'Otacilio Costa', + 'Ichora', + 'Urlaha', + 'Espelkamp', + 'Birao', + 'Lora del Rio', + 'Altavilla Milicia', + 'Anchorage', + 'Pendik', + 'Bugojno', + 'Kadavur', + 'Zahirabad', + 'Oschersleben', + 'Guerrero Negro', + 'Posadas', + 'Tabligbo', + 'Bermeo', + 'Coquimatlan', + 'Farg`ona', + 'Resita', + 'Syurte', + 'Viacha', + 'Tsing Yi Town', + 'Pultusk', + 'Patratu', + 'Satbayev', + 'Bonga', + 'San Salvador', + 'Szentendre', + 'Yvetot', + 'Bilpura', + 'Kabugao', + 'Haskovo', + 'Ingleside', + 'Wapakoneta', + 'Alhendin', + 'Mandialaza', + 'Kharsawan', + 'Chanda', + 'Maulavi Bazar', + 'Rautara', + 'Ljig', + 'Iona', + 'Sakaiminato', + 'North Myrtle Beach', + 'Peralillo', + 'Santa Flavia', + 'Ban Thung Khao Phuang', + 'Mandalavadi', + 'Bulanik', + 'Chong-Aryk', + 'Jayamkondacholapuram', + 'Havran', + 'Belobaka', + 'Fujisawacho-niinuma', + 'Puyallup', + 'Anderanboukan', + 'San Lazaro', + 'Metpalli', + 'Cerkezkoy', + 'Attleborough', + 'Chunakara Vadakku', + 'Eqlid', + 'Rockhampton', + 'Onalaska', + 'Hani i Elezit', + 'Ituzaingo', + 'Teculutan', + 'Bajwara', + 'Loran', + 'Guinayangan', + 'Wunstorf', + 'Sheopur', + 'Gol Tappeh', + 'Casselberry', + 'Jurema', + 'Chimay', + 'Horasan', + 'Sankt Wendel', + 'Eksambe', + 'Francisco Morato', + 'Panfilovka', + 'Ensley', + 'Kudavasal', + 'Palpala', + 'Itapecerica', + 'Drancy', + 'Monaghan', + 'Beamsville', + 'Crato', + 'Keila', + 'Riedlingen', + 'Bucine', + 'Vadippatti', + 'Segou', + 'Bag`dod', + 'Vellanad', + 'Conceicao do Castelo', + 'Alenquer', + 'Kalgi', + 'Somers Point', + 'McMinnville', + 'Erlangen', + 'Dabeiba', + 'Selkirk', + 'Toffo', + 'Aba', + 'Landi Kotal', + 'Duyen Hai', + 'Ostermundigen', + 'Doutou', + 'Emmeloord', + 'Ainsdale', + 'Isla Mujeres', + 'Bosobolo', + 'Forst (Lausitz)', + 'Swarzedz', + 'Guttenberg', + 'Gibsonton', + 'Moa', + 'Nattarasankottai', + 'Itaberai', + 'Teghra English', + 'Bellingham', + 'Lafayette', + 'Fort Wayne', + 'Odranci', + 'Hannut', + 'Ashburn', + 'Malate', + 'Jardin', + 'Clarington', + 'Mandiakui', + 'Merrydale', + 'Uirauna', + 'Panvel', + 'Chaguanas', + 'Basaha', + 'Susanville', + 'Kharik', + 'Grandview', + 'Mallapalli', + 'Ban Krang', + 'Camaiore', + 'Gross-Zimmern', + 'Vehkalahti', + 'Merchweiler', + 'Mohnesee', + 'Beach Park', + 'Yeghvard', + 'Beckingen', + 'Monte Dourado', + 'Gori', + 'Striano', + 'Barueri', + 'Tinogasta', + 'Santa Isabel do Rio Negro', + 'Kriftel', + 'Shiroishi', + 'Uaua', + 'Pinamalayan', + 'Sitalpur', + 'Las Matas de Santa Cruz', + 'Longchang', + 'Causeni', + 'Lajinha', + 'Sabbashahr', + 'Itacoatiara', + 'Mashan', + 'Trondheim', + 'Walsall Wood', + 'Lompoc', + 'Ibicuitinga', + 'Machang', + 'Babai', + 'Kobe', + 'Imsida', + 'Florida Ridge', + 'Antanambao Mahatsara', + 'Gudivada', + 'Apopka', + 'Bissau', + 'Itaete', + 'Shuiding', + 'Bratunac', + 'Beaconsfield', + 'Attnang-Puchheim', + 'Mennzel Bou Zelfa', + 'Dourados', + 'Obukhiv', + 'Lengede', + 'Riberalta', + 'Cafayate', + 'Bourem Inali', + 'Carapicuiba', + 'Orangevale', + 'La Homa', + 'Jaladurgam', + 'Gilarchat', + 'Reyhanli', + 'Durango', + 'Carros', + 'Hima', + 'Panthersville', + 'Arab', + 'Parasia', + 'Graca', + 'Metekora', + 'Harunabad', + 'Thonon-les-Bains', + 'Kodikulam', + 'Sarai Jattan', + 'Anderson Creek', + 'Gazulapalle', + 'Warrenton', + 'Qiman al `Arus', + 'Vaux-le-Penil', + 'Wuyi', + 'Calafell', + 'General Carneiro', + 'Sylvan Lake', + 'Onslow', + 'Sidi Amrane', + 'Heusden', + 'Yushan', + 'Kodakkal', + 'Dodvad', + 'Chaoshan', + 'San Jose de Urquico', + 'Rosmalen', + 'Sumilao', + 'Bharno', + 'Caversham', + 'Union Choco', + 'Annappes', + 'Angostura', + 'Nandasmo', + 'Ielmo Marinho', + 'Overland Park', + 'Umrapur', + 'Pirai do Sul', + 'Kumlu', + 'Kiyosu', + 'Paragaticherla', + 'Maayon', + 'Bardejov', + 'Masaka', + 'Maoming', + 'Santa Josefa', + 'Itarsi', + 'Prilep', + 'Pangil', + 'Kottapadi', + 'Central Falls', + 'Navarre', + 'Jatai', + 'Antsoantany', + 'Tiszavasvari', + 'Philadelphia', + 'Sundsvall', + 'Teapa', + 'Sansanne-Mango', + 'Itanhomi', + 'Upanema', + 'Longbridge', + 'Bryan', + 'Nueva Granada', + 'Malial', + 'Basud', + 'Kurichchi', + 'Pichidegua', + 'Amarante do Maranhao', + 'Kankol', + 'Tinajdad', + 'Amwa Majhar', + 'Pinetown', + 'Cherry Hill Mall', + 'Nangloi Jat', + 'Teopisca', + 'Bintuni', + 'Vengavasal', + 'Westmount', + 'Garmsar', + 'Sao Lourenco do Sul', + 'Duncan', + 'Kongarapalli', + 'Taounate', + 'Itapipoca', + 'Yungay', + 'Matalom', + 'Cartavio', + 'Bind', + 'Marck', + 'Galvarino', + 'Midvale', + 'Bangkok', + 'Tausa', + 'Gaoyou', + 'Balingen', + 'Wambrechies', + 'Pomerode', + 'Dolbeau', + 'Miyar', + 'Mahalapye', + 'Mandritsara', + 'Petrovske', + 'Mansa Konko', + 'Achern', + 'Malvern', + 'Veurne', + 'Tarauaca', + 'Sahna', + 'Patiram', + 'Nandurbar', + 'Nalwar', + 'Bahawalnagar', + 'Douar Ouled Ayad', + 'Guaitarilla', + 'Campo Mourao', + 'Sartana', + 'Yaojiazhuangcun', + 'Ma`raba', + 'Santo Tome', + 'Sapulpa', + 'Iasi', + 'Starkville', + 'Monte Cristi', + 'Youfangcun', + 'Vestal', + 'Shashemene', + 'Cambre', + 'Catonsville', + 'Honow', + 'Efkarpia', + 'West Caldwell', + 'Lianga', + 'Losser', + 'La Peche', + 'Kolea', + 'Avrig', + 'Mahatsinjony', + 'Sukhodilsk', + 'Le Bourget', + 'Sao Geraldo do Araguaia', + 'Palos Verdes Estates', + 'Millville', + 'Sao Miguel das Matas', + 'Saarbrucken', + 'Tres de Maio', + 'Sortobe', + 'Dhulia', + 'Pilate', + 'Itai', + 'Groot-Brakrivier', + 'Lemsid', + 'Cimarron Hills', + 'Boppard', + 'Shouguang', + 'Ares', + 'Aioun', + 'Catmon', + 'Kizilpinar', + "Ta' Xbiex", + 'Zuzemberk', + 'Vicksburg', + 'Koppies', + 'Karaj', + 'Cherrapunji', + 'Qasr-e Shirin', + 'El Penol', + 'Bacuri', + 'Rozenburg', + 'Phusro', + 'Howard', + 'Masquefa', + 'Taisar', + 'Tirebolu', + 'Wallenhorst', + 'Pa', + 'Baghpat', + 'Woodburn', + 'Tonawanda', + 'Mparo', + 'Douar Lamrabih', + 'Avondale', + 'Arenys de Mar', + 'Anguillara Sabazia', + 'Alblasserdam', + 'Otukpo', + 'Chandera', + 'Rubino', + 'Boskoop', + 'Boujad', + 'Bijai', + 'Teotihuacan', + 'Choba', + 'Swellendam', + 'Wood Dale', + 'Motta di Livenza', + 'Modakkurichchi', + 'Rajahmundry', + 'Rio Formoso', + 'Shantipur', + 'Wolvega', + 'Ennigerloh', + 'Seydi', + 'Melvindale', + 'Shangcaiyuan', + 'Gooty', + 'Ituiutaba', + 'Dakota Ridge', + 'Langen', + 'Klaukkala', + 'Lessines', + 'Saraykoy', + 'Oshu', + 'Kac', + 'Nanan', + 'Mandvi', + 'Larbert', + 'Garalo', + 'Binningen', + 'Templeton', + 'Yejituo', + 'San Estanislao', + 'Lake Stevens', + 'Kothanuru', + 'Dhanaura', + 'Goba', + 'Kasba', + 'Hot Springs', + 'Tiruvalur', + 'Birzebbuga', + 'Morafeno', + 'Cruzilia', + 'Sao Bras de Alportel', + 'Balingoan', + 'Purisima de la Concepcion', + 'Augustinopolis', + 'Caloocan City', + 'Itubera', + 'Lublin', + 'Temoaya', + 'Sebdou', + 'Beclean', + 'Itamarandiba', + 'Bayramic', + 'Ban Lam Narai', + 'Sirsa', + 'Talaja', + 'Amberieu-en-Bugey', + 'Arilje', + 'Gorbea', + 'Zakopane', + 'Izium', + 'Masvingo', + 'Shulan', + 'Chester', + 'Shinozaki', + 'Rupahi', + 'Douar Ait Taleb', + "'Ain Boucif", + 'San Gil', + 'Charters Towers', + 'Monovar', + 'Tierra Amarilla', + 'Toprakkale', + 'Pehcevo', + 'Cinfaes', + 'Lawang Bato', + 'Olinda', + 'Jiaoxi', + 'Bogatynia', + 'Bhawanipur Rajdham', + 'Jardin America', + 'Castelginest', + 'Herborn', + 'Cordeiro', + 'Dharmsala', + 'Gitega', + 'Vransko', + 'Pananaw', + 'Wettingen', + 'Deressia', + 'Secunderabad', + 'Queimada Nova', + 'Kollankulam', + 'Dharmaragar', + 'Beylaqan', + 'Lutsk', + 'Madinat as Sadat', + 'Shengping', + 'Yasu', + 'Hanmayingcun', + 'Ukiah', + 'Svilajnac', + 'Itoman', + 'Kathu', + 'Dugny', + 'Guanajuato', + 'Dreux', + 'Brovary', + 'Sicuani', + 'Hsenwi', + 'Manama', + 'Schleiden', + 'Kovancilar', + 'Tekkali', + 'Schlangen', + 'Zama', + 'Hostivice', + 'Calpulalpan', + 'Chalchihuitan', + 'Fondettes', + 'Messadine', + 'Duas Barras', + 'Alencon', + 'Cankiri', + 'Lake Zurich', + 'Bararam', + 'Nim ka Thana', + 'Woodlawn', + 'Contramaestre', + 'Monroe', + 'Kannod', + 'Ciechanow', + 'Kishunpur', + 'Haikou', + 'Fene', + 'Moree', + 'Rasulpur Dhuria', + 'Bowie', + 'Besiri', + 'Texistepec', + 'Langenau', + 'Nowra', + 'Metema', + 'Mokeri', + 'Kelibia', + 'Contamana', + 'Albergaria-a-Velha', + 'Paracuaro', + 'Kokshetau', + 'Campo Magro', + 'General Mariano Alvarez', + 'Stevenston', + 'Nagda', + 'Sliedrecht', + 'Kilmarnock', + 'Guantiankan', + 'Barira', + 'Dunn', + 'Portugalete', + 'Nizampatam', + 'Anse a Galets', + 'Louisville', + 'Policka', + 'Moita', + 'Sitanagaram', + 'Vrchlabi', + 'Greystones', + 'Kriel', + 'Guachochi', + 'Tuzla', + 'Juigalpa', + 'Paramonga', + 'Perali', + 'Idanha-a-Nova', + 'Ambilobe', + 'Kaga Bandoro', + 'Gilroy', + 'Nilavarappatti', + 'Tokat', + 'Miaojiaping', + 'Cascais', + 'Bilzen', + 'Malmo', + 'Tutong', + 'Tergnier', + 'Kalicherla', + 'Bishop Auckland', + 'Kyotamba', + 'Sonsonate', + 'Edmundston', + 'Ban Nong Tong', + 'Carnarvon', + 'Sloviansk', + 'Molave', + 'Kurobeshin', + 'Le Raincy', + 'Chinobod', + 'Alamnagar', + 'Kot Bhai', + 'Altenholz', + 'Esanai', + 'Kita-ku', + 'Lambidou', + 'Corumba', + 'North Providence', + 'Aulnoye-Aymeries', + 'Suifenhe', + 'Shar', + 'Vakfikebir', + 'Mudgee', + 'Vailoa', + 'Georgina', + 'Pachalum', + 'Al Fqih Ben Calah', + 'Lahti', + 'Eura', + 'Wolsztyn', + 'Santa Maria da Boa Vista', + 'Udipi', + 'Olgiate Olona', + 'Okinawa Numero Uno', + 'Albany', + 'Saint Sampson', + 'Bakel', + 'Governador Lindenberg', + 'Sannieshof', + 'Charlottetown', + 'Bidkhun', + 'Tenafly', + 'Dandarah', + 'Yunnanyi', + 'Mary', + 'Ouankoro', + 'Zhaicun', + 'Loboc', + 'Naduvannur', + 'Biedenkopf', + 'Jarash', + 'Yuanyangzhen', + 'Ashington', + 'Rufino', + 'Chodziez', + 'Heidenheim', + 'Aanekoski', + 'Puerto Tirol', + 'Attock Khurd', + 'Sihung', + 'Pennsville', + 'Vejen', + 'Sanford', + 'Loano', + 'West Deer', + 'Safsaf', + 'Collingswood', + 'East Setauket', + 'Sever do Vouga', + 'Savona', + 'Mayilur', + 'Bouchabel', + 'Mbarara', + 'Bersenbruck', + 'Bevonotra', + 'Linghai', + 'Aksay', + 'Santiago Tangamandapio', + 'Changshu', + 'Buckhurst Hill', + 'Yangchun', + 'Tumbao', + 'Mazagran', + 'Bussy', + 'Meerzorg', + 'Veys', + 'Peddapuram', + 'Wuwei', + 'Kongnolli', + 'Uar Esgudud', + 'Munxar', + 'Targu Secuiesc', + 'Zuvvaladinne', + 'Tombos', + 'Sanjianxiang', + 'Colonie', + 'Velakkuttai', + 'Haveri', + 'Machilipatnam', + 'Witbank', + 'Tierralta', + 'Blytheville', + 'Gorgan', + 'Pallapatti', + 'Sariq', + 'Fort Worth', + 'Hatonuevo', + 'Steinbach', + 'Anloga', + 'East Stroudsburg', + 'Rioverde', + 'Villa Castelli', + 'Hopa', + 'Knysna', + 'Koumassi', + 'Pampierstad', + 'Agawam', + 'Utrera', + 'Oggaz', + 'Wadgira', + 'Pagqen', + 'Mizdah', + 'Bni Tajjit', + 'Douar Snada', + 'Sandy Springs', + 'Louviers', + 'Mamak', + 'Rimouski', + 'Giddarbaha', + 'Ittiva', + 'Pedro Luro', + 'Kerepestarcsa', + 'Shohimardon', + 'Santa Ana', + 'La Sierra', + 'Diguapo', + 'Soio', + 'Saint-Jean-de-Luz', + 'Illkirch-Graffenstaden', + 'Saint-Pierre-des-Corps', + 'Aivanallur', + 'Rio Piracicaba', + 'Kompalle', + 'Chiayi', + 'Rostraver', + 'Flossmoor', + 'Frunze', + 'General Roca', + 'Aglipay', + 'Nussloch', + 'Yakinca', + 'Kattupputtur', + 'Kolkata', + 'Bo', + 'San Antonio del Tachira', + 'Patrocinio', + 'Cuvelai', + 'Duarte', + 'Panetha', + 'Cave', + 'Lahore', + 'Maijdi', + 'Janhapara', + 'Tondi', + 'Al Hamalah', + 'Ludhiana', + 'El Hammadia', + 'Ejura', + 'Antsalova', + 'Fiadanana', + 'Nedumana', + 'Novo Aripuana', + 'Qufadah', + 'Igreja', + 'Punganuru', + 'Ranigaon', + 'Presidente Kennedy', + 'Pedda Kotayalanka', + 'Loudoun Valley Estates', + 'Vezirkopru', + 'Dronfield', + 'Ugo', + 'Obburdon', + 'Camiling', + 'Cermik', + 'Ampatuan', + 'Alangulam', + 'Candler-McAfee', + 'Behenjy', + 'Talanga', + 'Garissa', + 'Mbandaka', + 'Senboku', + 'Banganapalle', + 'Pedreiras', + 'Loreto', + 'Elias Fausto', + 'Columbia', + 'Sao Ludgero', + 'Revelganj', + 'Uhersky Brod', + 'Feira Grande', + 'Norten-Hardenberg', + 'Omura', + 'Wilcannia', + 'Bishopbriggs', + 'Dandoli', + 'Satna', + 'Palni', + 'Elda', + 'Bakhtiyarpur', + 'Kara-Tash', + 'Holden', + 'Kodumba', + 'Udayendram', + 'Wangjiaxian', + 'Ragusa', + 'Pijijiapan', + 'Muret', + 'Feldkirchen-Westerham', + 'Ineu', + 'Smithtown', + 'Incesu', + 'Svay Rieng', + 'Bhucho Mandi', + 'Mukaiengaru', + 'Maiquetia', + 'Manglaur', + 'Centennial', + 'Bonfinopolis', + 'Cova Figueira', + 'Ianca', + 'Mahesana', + 'San Francisco de Mostazal', + 'Langenfeld', + 'Buchholz in der Nordheide', + 'Coutras', + 'Grigiskes', + 'Biswan', + 'Perumbalai', + 'Shujalpur', + 'Ciudad Manuel Doblado', + 'Tunzi', + 'Great Harwood', + 'Andhra Tharhi', + 'Toudja', + 'Ramsar', + 'Gaesti', + 'Champigny-sur-Marne', + 'Ash Shaddadah', + 'Santaquin', + 'Quilpie', + 'Tubay', + 'Babylon', + 'Pualas', + 'Johi', + 'Sahaspur', + 'Padiham', + 'Busto Garolfo', + 'Kamatero', + 'Miary', + 'Ialysos', + 'Seydisehir', + 'Morgan Hill', + 'Malard', + 'Kafr ad Dawwar', + 'Sancoale', + 'Sakata', + 'Jinoba-an', + 'Sorgues', + 'Sumedang', + 'Sanrh Majhgawan', + 'Dalanzadgad', + 'Chundal', + 'Piombino', + 'Port Harcourt', + 'Goyang', + 'Puntarenas', + 'Gaszowice', + 'Santa Rosa de Copan', + 'Carmo da Cachoeira', + 'Bargersville', + 'Beius', + 'Stony Brook University', + 'Razlog', + 'Spenge', + 'Ban Mae Kha Tai', + 'Chilpur', + 'Pacific Grove', + 'Kalyan', + 'Balmazujvaros', + 'Hortolandia', + 'Pataili', + 'San Agustin de las Juntas', + 'Sao Felix do Xingu', + 'Prior Lake', + 'Puzol', + 'Udumanthala', + 'Novopskov', + 'Auerbach', + 'Zarate', + 'Makuyu', + 'Ertvelde', + 'Kommuru', + 'Manari', + 'Belonia', + 'Immokalee', + 'Kuiyibagecun', + 'Ascoli Piceno', + "Cassina de' Pecchi", + 'Sousa', + 'Alhaurin de la Torre', + 'Djidian Kenieba', + 'Los Rios', + 'Castel Goffredo', + 'Resana', + 'Rehli', + 'Puerto Boyaca', + 'Bandar-e Anzali', + 'Martha Lake', + 'Chopinzinho', + 'Friedrichsdorf', + 'La Granja', + 'San Agustin Loxicha', + 'Platteville', + 'Dighaun', + 'Mebane', + 'Pavumba', + 'Epinay-sur-Seine', + 'Alfredo Wagner', + 'Singen', + 'El Asintal', + 'Sankrail', + 'Nghi Son', + 'Pithoragarh', + 'Pudunagaram', + 'Tsuchiura', + 'Jhundpura', + 'Itapecuru Mirim', + 'Naranjal', + 'Pinneberg', + 'Schnaittach', + 'Penco', + 'Oissel', + 'Dungra Chhota', + 'Amudat', + "Qo'shko'pir", + 'Pachahi', + 'Sufian', + 'Haguenau', + 'Mansapur', + 'Discovery Bay', + "'Ain Leuh", + 'Tabernes de Valldigna', + 'Medvode', + 'Sillamae', + 'Baker City', + 'Gllogovc', + 'Dhrangadhra', + 'Homosassa Springs', + 'Outreau', + 'Beni', + 'Meltonakkal', + 'Mango', + 'San Pedro Jocopilas', + 'Roodepoort', + 'Unterhaching', + 'Ibiruba', + 'San Bernardo', + 'Marhanets', + 'Itapitanga', + 'Sivalarkulam', + 'Maguing', + 'Lianran', + 'Smila', + 'Forrest City', + 'Lumino', + 'Qingzhou', + 'Bajina Basta', + 'Bruggen', + 'Tapiramuta', + 'Ganga Sagar', + 'Hvardiiske', + 'Capitao Poco', + 'Carranglan', + 'Ekpe', + 'Camana', + 'Choyr', + 'Tullahoma', + 'Bothell', + 'Livadeia', + 'Samarate', + 'Brixham', + 'Anororo', + 'Ypejhu', + 'Bradford-on-Avon', + 'Wigston Magna', + 'Acigol', + 'Puerto Salgar', + 'Benicia', + 'Fundeni', + 'Dioumanzana', + 'Chellalat el Adhaouara', + 'Zonhoven', + 'Vellar', + 'Sceaux', + 'Luuka Town', + 'Kristiansand', + 'Ripley', + 'Lutry', + 'Gurabo al Medio', + 'Sepidan', + 'Chubbuck', + 'Harding', + 'Rogatica', + 'Maple Valley', + 'Qal`at Bishah', + 'Boladi', + 'Terlizzi', + 'Morriston', + 'Jaslo', + 'Mendrisio', + 'Valangiman', + 'Medveda', + 'Barton upon Humber', + 'Sauk Village', + 'Dison', + 'Little Bookham', + 'Marlton', + 'Harhorin', + 'Rampur Kalan', + 'Trofa', + 'Gatesville', + 'Etchojoa', + 'Baichigan', + 'New Hartford', + 'Charleville-Mezieres', + 'Anna', + 'Unchahra', + 'Porto de Mos', + 'Ambhua', + 'Al Minya', + 'Morro do Chapeu', + 'Saintard', + 'Bukwo', + 'Kawartha Lakes', + 'Badr Hunayn', + 'Valley Cottage', + 'Duxbury', + 'Baipingshan', + 'Fuente de Oro', + 'Nayudupet', + 'Zhexiang', + 'Khagra', + 'Sarakhs', + 'Saint-Pierre-du-Mont', + 'Urumqi', + 'Vannivedu', + 'Cesano Maderno', + 'Juarez', + 'Neuruppin', + 'Dig', + 'Momil', + 'Gondal', + 'Torres Novas', + 'Akkattettar', + 'Dourbali', + 'Ondo', + 'Monjas', + 'Mechernich', + 'Arlit', + 'Mandelieu-la-Napoule', + 'Murska Sobota', + 'Daean', + 'Kalaleh', + 'Bamei', + 'Myingyan', + 'Lingquan', + 'Pescia', + 'Malloussa', + 'El Attaf', + 'Panmana', + 'Caqueza', + 'Moulay Bousselham', + 'Pathein', + 'Reha Mota', + 'Florencio Varela', + 'Al Lataminah', + 'Azogues', + 'Jhandapur', + 'Verucchio', + 'Subachoque', + 'Solila', + "Rava-Rus'ka", + 'Witu', + 'Gander', + 'General Pico', + 'Tongluo', + 'Serinhisar', + "Fiorenzuola d'Arda", + 'Vadamadurai', + 'Bayou Cane', + 'Plunge', + 'Quakertown', + "Limeira d'Oeste", + 'Qulan', + 'Agramonte', + 'Jamunamukh', + 'Gondomar', + 'Lajas', + 'Quinapundan', + 'Kurten', + 'Coremas', + 'Mafra', + 'Pinewood', + 'Linguere', + 'Miradouro', + 'Baganga', + 'Pauini', + 'Trebur', + 'Bollnas', + 'Romulus', + 'Banire Kore', + 'Legnaro', + 'Manatanna', + 'Deruta', + 'Finestrat', + 'Chico', + 'Mankono', + 'Pimentel', + 'Umirim', + 'Velanganni', + 'Natchitoches', + 'Kanungu', + 'West Palm Beach', + 'Caraballeda', + 'Tha Bo', + 'Nishio', + 'Bragado', + 'Palopo', + 'Concorezzo', + 'Nagla', + 'Nobres', + 'Sagada', + 'Bayona', + 'Cheat Lake', + 'Zion', + 'Kochi', + 'Cho Lach', + 'Sannicandro di Bari', + 'Pelotas', + 'Selb', + 'Sugarmill Woods', + 'Oatlands', + 'Basoda', + 'Lakewood Ranch', + 'Tenango del Aire', + 'Tulkarm', + 'Bella Union', + 'Heath', + 'Massaranduba', + 'Higashikagawa', + 'Barra do Choca', + 'Bolivar', + 'Aguacatan', + 'Yakacik', + 'Alexander Bay', + 'Dehri', + 'Mehnatobod', + 'Thol', + 'Burkburnett', + 'Sanarate', + 'Pollokshaws', + 'Sencur', + 'Zhanjiang', + 'San Pedro Ixcatlan', + 'Le Pre-Saint-Gervais', + 'Jamunia', + 'Opol', + 'Ambalajia', + 'Penola', + 'Mangindrano', + 'Oued el Alleug', + 'Marai Kalan', + 'Zatec', + 'Southern Cross', + 'San Luis de la Paz', + 'Omihachiman', + 'Illapel', + 'Tsianisiha', + 'Siteia', + 'McFarland', + 'Nova Resende', + 'Rheinfelden', + 'Mubi', + 'Ourika Wawrmas', + 'Quinte West', + 'Korce', + 'Kalanaur', + 'Dhulian', + 'Balen', + 'Auterive', + 'Wronki', + 'Budha Theh', + 'Quy Nhon', + 'Cedro', + 'Garlasco', + 'Biharamulo', + 'Chateaurenard', + 'General Cabrera', + 'Gostynin', + 'Ad Diraz', + 'Asau', + 'Oceanside', + 'Longmont', + 'Nanzhuang', + 'Satadougou', + "Saint-Barthelemy-d'Anjou", + 'Owariasahi', + 'Zombo', + 'Dudley', + 'San Agustin Acasaguastlan', + 'Lochem', + 'Nidderau', + 'Devarkonda', + 'Leven', + 'Munchberg', + 'Mariani', + 'Cornillon', + 'Svidnik', + 'Heek', + 'Chak Thirty-six North Branch', + 'Tholey', + 'Charsadda', + 'Restinga Seca', + 'Villeneuve-Tolosane', + 'Profondeville', + 'Amla', + 'Ludwigslust', + 'Caterham', + 'Al Ghardaqah', + 'Mineral de la Reforma', + 'Kosice', + 'Sehnde', + 'Imam Qasim', + 'Ain El Aouda', + 'Candido Mendes', + 'Hacari', + 'Massafra', + 'Vittal', + 'Koh Kong', + 'Stockach', + "Saint Paul's Bay", + 'Tieshansi', + 'Xinyi', + 'Rawanduz', + 'Nanyuki', + 'Sarpamari', + 'Tres Coracoes', + 'Narutocho-mitsuishi', + 'Cukai', + 'Douchy-les-Mines', + 'Mandirituba', + 'Imouzzer Kandar', + 'Oulad Teima', + 'Lere', + 'Kanavaypudur', + 'Naugaon Sadat', + 'Bonnyrigg', + 'Charthawal', + 'Znojmo', + 'Cankova', + 'Tondo', + 'Badhan', + "Wu'an", + 'North Bellport', + 'Ambatosoratra', + 'Naduvattam', + 'Columbia Heights', + 'Neustadt am Rubenberge', + 'Maturin', + 'Ehringshausen', + 'Dandkhora', + 'Xinzhai', + 'Winter Gardens', + 'Bayur', + 'Dame-Marie', + 'Saco', + 'Metsemotlhaba', + 'Apen', + 'Nuevo Laredo', + 'Cofimvaba', + 'Miryal', + 'Shuangluan', + 'Thorold', + 'Zagarolo', + 'Wenling', + 'Dengtalu', + 'Oharu', + 'Sumoto', + 'Osmaniye', + 'Aquiraz', + 'Bury Saint Edmunds', + 'Nacajuca', + 'Baao', + 'Velbert', + 'Pyskowice', + 'North Platte', + 'Prostejov', + 'Paradise', + 'Newington Forest', + 'Gonghaur', + 'Rawicz', + 'Lamsabih', + 'Zaoqiao', + 'Chaoke', + 'Renala Khurd', + 'Saint-Sulpice-la-Pointe', + 'Kerkrade', + 'Glen Cove', + 'Cottbus', + 'Laurens', + 'Mont-Laurier', + 'Omalur', + 'Loum', + 'An Nu`maniyah', + 'Allende', + 'Jagdispur', + 'Bourgoin-Jallieu', + 'Icapui', + 'Niiza', + 'Disa', + 'Rhynern', + 'Mata', + 'Straubing', + 'Kingsnorth', + 'Esch-sur-Alzette', + 'Moyobamba', + 'Flores Costa Cuca', + 'Vetlanda', + 'Hengbei', + 'Hatillo de Loba', + 'Conway', + 'Ashta', + 'Diphu', + 'Sutculer', + 'Bad Worishofen', + 'Mahta', + 'Umm Qurun', + 'Strongsville', + 'Kamidani', + 'Playa del Carmen', + 'Moralzarzal', + 'Lauffen am Neckar', + 'Kelishad va Sudarjan', + 'Cocentaina', + 'Harrislee', + 'Sojat', + 'Mahallat Damanah', + 'South Frontenac', + 'Ban Phan Chali', + 'San Sebastian Coatan', + 'Diego Martin', + 'Thai Nguyen', + 'Pewaukee', + 'Ifanadiana', + 'Asjen', + 'Mankachar', + 'Apparaopeta', + 'DeRidder', + 'Orleans', + 'Nagojanahalli', + 'Peddavadlapudi', + 'Dadrewa', + 'Sagure', + 'Natal', + 'Shirakawa', + 'Calera de Tango', + 'Sahbuz', + 'Rodeio', + 'Shaying', + 'Sakoabe', + 'Ramabhadrapuram', + 'Kararan', + 'Zolote', + 'El Espinal', + 'Laverton', + 'Ramgarha', + 'Sant Julia de Loria', + "Sant'Agnello", + 'Lidzbark Warminski', + 'Shu', + 'Pweto', + 'Burscough', + "Foum Jam'a", + 'Hua Hin', + 'Marovato', + 'Gangapatnam', + 'Rijeka', + 'Jihong', + 'Seacombe', + 'Friendswood', + 'Estreito de Camara de Lobos', + 'Loei', + 'Dan', + 'Jerez de Garcia Salinas', + 'Pukhrayan', + 'Choma', + 'Tlapa de Comonfort', + 'Catbalogan', + 'Boudenib', + 'Paraparaumu Beach', + 'East Lansing', + 'Stradella', + 'Tenali', + 'Irungalur', + 'Hollymead', + 'Farap', + 'Pitesti', + 'Muzambinho', + 'La Mesa', + 'Mulki', + 'Bruck an der Mur', + 'Gongguan', + 'Vayalar', + 'Freiberg am Neckar', + 'Passa e Fica', + 'Myrhorod', + 'Mutoko', + 'Warwick', + 'Shanmukhasundarapuram', + 'Koscian', + 'Nanyangcun', + 'Patton', + 'Grimes', + 'Vempatti', + 'Smizany', + 'Chipinge', + 'Miyota', + 'Villajoyosa', + 'Almoloya del Rio', + "'Ali Ben Sliman", + 'Brodosqui', + 'Vikrutamala', + 'Valatt', + 'Aparecida', + 'Guskhara', + 'Oke-Mesi', + 'Roche-la-Moliere', + 'Sentrupert', + 'Buraan', + 'Kisii', + 'Lohardaga', + 'Angleton', + 'Quakenbruck', + 'Bystrzyca Klodzka', + 'Ippagudem', + 'Lunner', + 'Almora', + 'Hasilpur', + 'Agiripalle', + 'Parys', + 'Loningen', + 'King City', + 'Suitland', + 'Bathnaha', + 'Gachancipa', + 'Bad Bentheim', + 'Fuyang', + 'Federal Heights', + 'Vallirana', + 'Manandroy', + 'Varidhanam', + 'Valreas', + 'Konstanz', + 'Hissaramuruvani', + 'Uripa', + 'Kimbe', + 'Medina Sidonia', + 'Tarragona', + 'Antindra', + 'Montana', + 'Cervignano del Friuli', + 'Hezuo', + 'Puerto Escondido', + 'Salto de Pirapora', + 'Gaobeidian', + 'Chak Husaini', + 'Grajales', + 'Lykovrysi', + 'Ankatafa', + 'Sbiba', + 'Matanog', + 'Sikka', + 'Avsallar', + 'Sarykemer', + 'Lighthouse Point', + 'Fatehpur Sikri', + 'Lakhminia', + 'Nagari', + 'Ansongo', + 'Bad Nauheim', + 'Trostberg an der Alz', + 'Mogila', + 'Mahrail', + 'Mouans-Sartoux', + 'Hude', + 'Lazi', + 'Berkhampstead', + 'Nehram', + 'Fussa', + 'Waipahu', + 'Dawei', + 'Haldia', + 'Olten', + 'Apastepeque', + 'Krzeszowice', + 'Koini', + 'Douar Messassa', + 'Lima', + 'Honcho', + 'Mulchen', + 'Acheres', + 'Harper Woods', + 'Tlacoachistlahuaca', + 'Baikonur', + 'De Bilt', + 'Vianden', + 'Arnold', + 'Bhabhua', + 'Al Ghizlaniyah', + 'Chakur', + 'Jixi', + 'Kibiti', + 'Viechtach', + 'Comalcalco', + 'Westfield', + 'Uacu Cungo', + 'Camargo', + 'San Juan del Rio del Centauro del Norte', + 'Bebington', + 'Largs', + 'Sompeta', + 'Ipsala', + 'Pola de Laviana', + 'Jose Maria Morelos', + 'Wasserburg am Inn', + 'Al Hawiyah', + 'Kilrajakularaman', + 'Chak Sixty-one Gugera Branch', + 'Jafaro', + 'Yattir', + 'Piura', + 'Dachau', + 'Bom Jesus dos Perdoes', + 'Itacare', + 'Delcevo', + 'Negombo', + 'Tenedla', + 'Amadora', + 'At-Bashy', + 'Fort Collins', + 'Amuria', + 'Vicuna', + 'Dahu', + 'Eloy Alfaro', + 'Beaumont', + 'Lloro', + 'Vinh Long', + 'Padiyanallur', + 'Tobruk', + 'Pazar', + 'Bideipur', + 'Magdalena de Kino', + 'Parla', + 'Kanuma', + 'Quatro Barras', + 'Chikusei', + 'Panambi', + 'Arecibo', + 'Bekatra Maromiandra', + 'Ahus', + 'Tilingzhai', + 'Hanahan', + 'Lunbei', + 'Majhua', + 'Bad Segeberg', + 'Holywell', + 'Tivim', + 'El Charco', + 'Mailiao', + 'Chenlu', + 'Beylul', + 'Camarajibe', + 'Le Puy-en-Velay', + 'Santander de Quilichao', + 'Nakasongola', + 'Shabestar', + 'Lindau', + 'Hathaura', + "Ayt 'Attou ou L'Arbi", + 'Fiuggi', + 'Dhekiajuli', + 'Shuyangzha', + 'Tokoroa', + 'Chaozhou', + 'Durres', + 'Old Jamestown', + 'Chimbote', + 'Ivanovka', + 'Silver Firs', + 'Santa Ana Nextlalpan', + 'Ourtzagh', + 'Lysa nad Labem', + 'Hirakata', + 'Udine', + 'Andrelandia', + 'Seysses', + 'Atami', + 'Woudrichem', + 'Brzeszcze', + 'Zhangping', + 'Rolante', + 'Mabai', + 'Varatanapalli', + 'Catak', + 'Mahabaleshwar', + 'Galgamuwa', + 'Kelso', + 'Esquipulas', + 'Seoni Malwa', + 'Laboulaye', + 'Winter Haven', + 'Jimaguayu', + 'Rury', + 'Lubbenau/Spreewald', + 'Dijiasuoxiang', + 'Wielsbeke', + 'Pagani', + 'Kizhur', + 'San Carlos City', + 'Chaudfontaine', + 'Camacupa', + 'Celina', + 'Roudnice nad Labem', + 'Rajni', + 'Umm Ruwaba', + 'Harir', + 'Suwasra', + 'Rio Casca', + 'Bry-sur-Marne', + 'Fleron', + 'Minamikyushu', + 'Tsallagundla', + 'Bashtanka', + 'Soresina', + 'Sogut', + 'Parkersburg', + 'Artesia', + 'Barka Parbatta', + 'San Carlos de Guaroa', + 'Abreus', + 'Sarsai Nawar', + 'Saint-Marc', + 'George', + 'Kamamaung', + 'Bayburt', + 'Narsampet', + 'As Sidrah', + 'Menasha', + 'Aberaman', + 'Irikkur', + 'Herning', + 'Apeldoorn', + 'El Campo', + 'Thakhek', + 'Karanjia', + 'Maullin', + 'Druten', + 'Mundra', + 'Paveh', + 'Carovigno', + 'Jodar', + 'Montevarchi', + 'LaGrange', + 'Masanasa', + 'Maddela', + 'Chicago', + 'Kamayakkavundanpatti', + 'Xiangyang', + 'Leizhou', + 'Atner', + 'Siderno Marina', + 'Agra', + 'Shin-Kamigoto', + 'Anenecuilco', + 'Sejenane', + 'Paletwa', + 'Pantanaw', + 'Senec', + 'Messaad', + 'Brielle', + 'Cangxi', + 'Dagarua', + 'Kingston South East', + 'Allestree', + 'Oslob', + 'Bolsover', + 'Grand Turk', + 'Bohodukhiv', + 'Boulogne-sur-Mer', + 'Kyotanabe', + 'Coimbatore', + 'Jinshi', + 'Ornskoldsvik', + 'Woonsocket', + 'Buhusi', + 'Villanueva de la Canada', + 'Karugamad', + 'Jumla', + 'Pueblo Nuevo Vinas', + 'Tres de Mayo', + 'Sal Rei', + 'Valkeakoski', + 'Kungsangen', + 'Zulte', + 'Kerewan', + 'Tabango', + 'Naha', + 'Akkus', + 'Tulcea', + 'Moratuwa', + 'Utsunomiya', + 'Noeux-les-Mines', + 'Los Barrios', + 'Agadi', + 'Hlohovec', + 'Gages Lake', + 'Tiverton', + 'Golmarmara', + 'Puszczykowo', + 'Mangabe', + 'Hohr-Grenzhausen', + 'Zango', + 'Cua Lo', + 'Mansalay', + 'Leverano', + 'Yanahuanca', + 'Sinaia', + 'Gudluru', + 'Vadugapatti', + 'Ban Tha Phra', + 'Kikwit', + 'Cantagalo', + "Yan'an Beilu", + 'Tampakan', + 'Glanerbrug', + 'Copalchi', + 'Zacualtipan', + 'Fidenza', + 'Tsararano', + 'Ferguson', + 'Renukut', + 'Sao Sebastiao do Cai', + 'Mainburg', + 'Ceres', + 'Uluberiya', + 'Mauji', + 'Telfs', + 'Cachoeira dos Indios', + 'Triunfo', + 'Mittegrossefehn', + 'Murehwa', + 'Velika Polana', + 'Borgosesia', + 'Shichuanxiang', + 'Befandefa', + 'Pilar do Sul', + 'Quimper', + 'Saeby', + 'Netanya', + 'Peri-Mirim', + 'Tidjelabine', + 'Tecolutla', + 'Anakaputtur', + 'Quipapa', + 'Dikili', + 'Yuma', + 'Parakadavu', + 'Oxapampa', + 'Odense', + 'Tanambao-Daoud', + 'Bussum', + 'Dartford', + 'Bilaua', + 'Stoughton', + 'Alcanena', + 'Cloverleaf', + 'Akambadam', + 'Anomabu', + 'Lo Barnechea', + "Wen'anyi", + 'Port Orchard', + 'Ahuachapan', + 'Horta', + 'Bourg-de-Peage', + 'Neuville-les-Dieppe', + 'Walton upon Thames', + 'Jaguaquara', + 'Koshigaya', + 'Wendeburg', + 'Tall Shihab', + 'Tounfafi', + 'Al Hamah', + 'Mostar', + 'Illizi', + 'Khaspur', + 'Sirvan', + 'Lapu-Lapu City', + 'Sint-Gillis-Waas', + 'Cassongue', + 'Beahitse', + 'Virapalle', + 'Geislingen an der Steige', + 'Bogalusa', + 'Stavanger', + 'Jiaji', + 'Kannapuram', + 'Bamukumbit', + 'Maroua', + 'Correggio', + 'Bikkavolu', + 'Kumaranallur', + 'Guinagourou', + 'Salonta', + 'Zhutang', + 'Tamarankottai', + 'Tzucacab', + 'Gurais', + 'Taichung', + 'Oas', + 'Anjukulippatti', + 'Melchor Ocampo', + 'Nochistlan de Mejia', + 'Victor', + 'Limeira', + 'Chalfont Saint Peter', + 'La Marsa', + 'Cullinan', + 'Shimeo', + 'Neuhof', + 'Kannulu', + 'Daganbhuiya', + 'Antigua Guatemala', + 'Bowmanville', + 'Zemoura', + 'Tyele', + 'Cedartown', + 'Kingsland', + 'Toyomamachi-teraike', + 'Bni Khloug', + 'Montargis', + 'Sarasambo', + 'Aurora', + 'Nilka', + 'Siena', + 'Santa Vitoria', + 'Goz-Beida', + 'Murray', + 'Hennaya', + 'Santa Isabel Cholula', + 'Bellamkonda', + 'Andasibe', + 'Quvasoy', + 'Villa Park', + 'Thaon-les-Vosges', + 'Acri', + 'Limbdi', + 'Kaisariani', + 'Coconut Creek', + 'Kitakoriyamacho', + 'Gaggenau', + 'Newmarket', + 'Grombalia', + 'Dogansehir', + 'Chinsali', + 'Moisei', + 'La Vallee de Jacmel', + 'Kadamalaikkundu', + 'Wagga Wagga', + 'Sonthofen', + 'Sukkur', + 'Zhaozhou', + 'Boshruyeh', + 'Macara', + 'Cheongju', + 'Nisko', + 'Meftah', + 'Amilly', + 'Ageoshimo', + 'Butzbach', + 'Giria', + 'Sultonobod', + 'Sucua', + 'Keregodu', + 'Dudhgaon', + 'Chalma', + 'Pierre-Benite', + 'Oberriet', + 'Tramandai', + 'Shiggaon', + 'Whitestown', + 'Zaqatala', + 'Zaboli', + 'Houston', + 'Sorab', + 'Enkhuizen', + 'Kaniwara', + 'Sare-Yamou', + 'Kriens', + 'Petersburg', + 'Rawah', + 'Montenegro', + 'Boorama', + 'Gangawati', + 'Manjuyod', + 'Argostoli', + 'Clarksburg', + 'Fall River', + 'Boffa', + 'Sodag', + 'Hingyon', + 'Kanding', + 'Gresham', + 'Peruru', + 'Kemigawa', + 'Manbazar', + 'Capitol Hill', + 'Bo`z', + 'Murshidabad', + 'Resplendor', + 'Baishi Airikecun', + 'Bulancak', + 'Aibonito', + 'East Islip', + 'Mengibar', + 'Kotwapatti Rampur', + 'Qaryat al Qi`an', + 'Estiva Gerbi', + 'Sipalay', + 'Mandrosohasina', + 'Hadera', + 'Partick', + 'Pulawy', + 'Lobamba', + 'Vitoria de Santo Antao', + 'Fada Ngourma', + 'Al Hoceima', + 'Agcogon', + 'Konina', + 'Mahbubnagar', + 'Temamatla', + 'Assab', + 'Gautier', + 'Mangalkot', + 'San Benito', + 'Ben Ahmed', + 'Natori-shi', + 'Wymondham', + 'Hassi el Ghella', + 'Pesca', + 'Kuttappatti', + 'Campo de Criptana', + 'Pelham', + 'Mont-Saint-Hilaire', + 'Sao Joaquim', + 'Lusca', + "Topol'cany", + 'Itagui', + 'Artur Nogueira', + 'Cheadle Hulme', + 'Timmiarmiut', + 'Carmopolis', + 'Dolhasca', + 'Mangghystau', + 'Much', + 'Vadamugam Vellodu', + 'Vamanapuram', + 'Bordj Mokhtar', + 'Tougouni', + 'Beldaur', + 'Limbuhan', + 'Paraibano', + 'Realeza', + 'Puchheim', + 'Cardedeu', + 'Cacocum', + 'Luacano', + 'Villavicencio', + 'Fray Bartolome de Las Casas', + 'Burke', + 'Dabiya', + 'Pizarra', + 'Kothapet', + 'Ile-Ife', + 'Chittattukara', + 'Chuadanga', + 'Wausau', + 'Ban Tha Ton', + 'Feyzabad', + 'Frankenberg', + 'Gostivar', + 'Magelang', + 'Sabaya', + 'Maleme Hodar', + 'Virakeralam', + 'Bhisho', + 'Rakhiv', + 'Manjimup', + 'Catalpinar', + 'Liaoyuan', + 'Akureyri', + 'Ris-Orangis', + 'Larena', + 'Ampelokipoi', + 'Waterloo', + 'Siguiri', + 'Sujina', + 'Monte Alegre do Piaui', + 'Maicao', + 'Ambohimiadana', + "Pan'an", + 'Vallauris', + 'Lingampalli', + 'Ewell', + 'Tambau', + 'South Union', + 'Moga', + 'Talghar', + 'Salinas', + 'Gonghe', + 'Temple City', + 'Ternat', + 'San Ramon de la Nueva Oran', + 'Donaueschingen', + 'Adilcevaz', + 'Plainedge', + 'Salotgi', + 'Barotac Nuevo', + 'Chevigny-Saint-Sauveur', + 'Jaisalmer', + 'Cameri', + 'Lowshan', + 'Pleasant View', + 'Gazipura', + 'Indwe', + 'Yen Bai', + 'Hospet', + 'Jamai', + 'Palmetto Estates', + 'Ponnani', + 'Hwlffordd', + 'Tiny', + 'Bhattu Kolan', + 'Yangsan', + 'Allanridge', + 'Quyang', + 'Agoo', + 'Sabbavaram', + 'Chamical', + 'Buritama', + 'Minna', + 'Millbury', + 'San Jose Villa de Allende', + 'Ercis', + 'Mogok', + 'Dona Remedios Trinidad', + 'Rio Novo do Sul', + 'Kormend', + 'Ambohimitombo', + 'New Carrollton', + 'Mount Airy', + 'Qinhuangdao', + 'Madingou', + 'Robbinsdale', + 'Huejucar', + 'Erraballa', + 'Andover', + 'Kefar Yona', + 'Sweet Home', + 'Deming', + 'Asakuchi', + 'Al Mu`abbadah', + 'Varna', + 'Pine Bluff', + 'Rovira', + 'Brackley', + 'Kodala', + 'Patu', + 'Satoraljaujhely', + 'Ambohimanga', + 'Cherukolattur', + 'Marechal Deodoro', + 'Pelaya', + 'Cape Town', + 'Sarakkayhalli', + 'Manado Light', + 'Ihsaniye', + 'Yangiobod', + 'Natagaima', + 'Mattathur', + 'Strathroy-Caradoc', + 'Talagante', + 'Montclair', + 'Kiryandongo', + 'Nzeto', + 'Pativilca', + 'Quiapo', + 'Pulilan', + 'Serra Preta', + 'Alagoa Grande', + 'Jerez', + 'Edam', + 'Merces', + 'Galaz', + 'Pahuatlan de Valle', + 'Nathpur', + 'Orem', + 'Milford Mill', + 'Vimercate', + 'Baie de Henne', + 'Fanandrana', + 'Stenungsund', + 'Fondi', + 'Vipparla', + 'Arroyomolinos', + 'Kaniyur', + 'Cristuru Secuiesc', + 'Marawi City', + 'Dong Hoa', + 'Moura', + 'Selsey', + 'Dinalupihan', + 'Busko-Zdroj', + 'Itatim', + 'Foumban', + 'Purwa', + 'Woippy', + 'Muzhakkunnu', + 'Backa Topola', + 'Colmenarejo', + 'Burg', + 'Ashoknagar', + 'Manerbio', + 'Montmorency', + 'Carteret', + 'Kotekara', + 'El Socorro', + 'Mayahaura', + 'Besigheim', + 'Barsinghausen', + 'Raita', + 'Zwenkau', + 'Fords', + 'Palamedu', + 'McHenry', + 'Rahovec', + 'Lajosmizse', + 'Sakhmohan', + 'Lyons', + 'Ulatu', + 'Tuskegee', + 'Humacao', + 'Launaguet', + 'Paranaiba', + 'Shitab Diara', + 'Asansol', + 'Signal Mountain', + 'Hammam Bou Hadjar', + 'Novi Sad', + 'Karghar', + 'Arzano', + 'Thatri', + 'Vossevangen', + 'Cuya', + 'Lymanka', + 'Bucak', + 'Cathedral City', + 'Sidi Slimane', + 'Tapejara', + 'Marco', + 'Tingloy', + 'Shelby', + 'Sijua', + 'Moss Point', + 'Satwas', + 'Parkal', + 'Sitapur', + 'Maniyamturuttu', + 'Nakhla', + 'Ispica', + 'Nayagaon', + 'Telimele', + 'Mono', + 'Kolga', + 'Mirjaveh', + 'Warrensburg', + 'Furstenfeld', + 'Oswiecim', + 'Pariyapuram', + 'Cuito Cuanavale', + 'Yoqne`am `Illit', + 'Komatsu', + 'Farmersville', + 'Mazar-e Sharif', + 'Tasil', + 'Surla', + '`Ain el Hadjel', + 'Potukonda', + 'Alcochete', + 'McKinleyville', + 'Lage', + 'Dugda', + 'Candijay', + "Intich'o", + 'Mercier', + 'Kamnik', + 'Tleta Taghramt', + 'Dungannon', + 'Montespertoli', + 'Port Jervis', + 'Matiguas', + 'Tago', + 'Oulad Daoud', + 'Haymana', + 'Tshela', + 'Aso', + 'South Hadley', + 'Doranahalli', + 'La Palma', + 'Laitila', + 'Stara Zagora', + 'Az Zuwaydah', + 'Storozhynets', + 'Muppalla', + 'Urganch', + 'Bialystok', + 'Libertad', + 'Bilara', + 'Zemio', + 'Mbabane', + 'Tsukawaki', + 'Middle Valley', + 'Sierra Vista Southeast', + 'Balboa', + 'Ostrowiec Swietokrzyski', + 'Lucapa', + 'Chiang Rai', + 'Khujand', + 'Great Baddow', + 'Buthidaung', + 'El Chol', + 'Albuera', + 'Carmignano', + 'Sommacampagna', + 'Kutum', + 'Cambambe', + 'Cunha Pora', + 'Longtaixiang', + 'Lawas', + 'Meru', + 'Ibiuna', + 'Aalen', + 'Kuah', + 'Bertem', + 'Consuegra', + 'Gamarra', + 'Chunakhali', + 'Tavsanli', + 'Kolwezi', + 'Dori', + 'Melsele', + 'Murugampalaiyam', + 'Yirga `Alem', + 'Vrnjacka Banja', + 'Bentota', + 'Bron', + 'Uncia', + 'Woerden', + 'San Juan Nonualco', + 'National City', + 'Rajshahi', + 'Mount Kisco', + 'Ludza', + 'Pattambi', + 'Korsimoro', + 'Keota', + 'Marion', + 'Kyaukmyaung', + 'Algun', + 'Montrose', + 'Loganville', + 'Gracemere', + 'Anthony', + 'Lapeer', + 'Blachownia', + 'Dimiao', + 'Dellys', + 'Haramachida', + 'Porto da Folha', + 'Ullo', + 'Iju', + 'Caister-on-Sea', + 'Dunaharaszti', + 'Ghanpur', + 'Ban Mae Ka Hua Thung', + 'Ajodhya', + 'La Garriga', + 'Canela', + 'Mallappadi', + 'Rossington', + 'Suriapet', + 'La Caleta', + 'Kumbhraj', + 'Chengdu', + 'Tarnowskie Gory', + 'Wattwil', + 'Hoogeveen', + 'Jagalur', + 'Veymandoo', + 'Sahatona-Tamboharivo', + 'Jaqueira', + 'Marshfield', + 'Jonkoping', + 'Navabad', + 'Phuc Yen', + 'Pinyahan', + 'Palanga', + 'Fujiyoshida', + 'Quela', + 'Ulcinj', + 'Sao Raimundo das Mangabeiras', + "L'Oulja", + 'Polas', + 'Vattalkundu', + 'Lod', + 'Suwanee', + 'Asse', + 'Bensekrane', + 'Siki', + 'Neira', + 'Middelharnis', + 'Managua', + 'Ambatomborona', + 'Touama', + 'Karatepe', + 'Willoughby Hills', + 'Boonton', + 'Mwatate', + 'Sanchahe', + 'Bommayapalaiyam', + 'Fort Bliss', + 'Bronx', + 'Nahuizalco', + 'Ankazomiriotra', + 'East Kelowna', + 'Bacioi', + 'Hassloch', + 'Hengyang', + 'Xishan', + 'Tamuin', + 'Vestmanna', + 'Bochnia', + 'Znin', + 'Purattur', + 'Arapongas', + 'Montividiu', + 'Yagoua', + 'Chinna Annaluru', + 'Chiatura', + 'Dhalai', + 'El Tablon', + 'Jyllinge', + 'Ives Estates', + 'Arenoso', + 'Eppstein', + 'Stony Plain', + 'Charleroi', + 'Bressanone', + 'Graulhet', + 'Diksmuide', + 'Heverlee', + 'Nova Russas', + 'Sholaqqorghan', + 'Viskovo', + 'Palenque', + 'Gatada', + 'Kannanendal', + 'Wadenswil', + 'Nepomuceno', + 'Dalli Rajhara', + 'Okpo', + 'Canelinha', + 'Saharbani', + 'Somma Lombardo', + 'Bojnik', + 'Beylikduzu', + 'Ban Pha Bong', + 'Trumbull Center', + 'Mandera', + 'Rio do Pires', + 'Bagnolo in Piano', + 'Tianchang', + 'Lillerod', + 'Ipswich', + 'Olaippatti', + 'Duzici', + 'Pernamitta', + 'Villa de Zaachila', + 'Wakefield', + 'Mandello del Lario', + 'Heywood', + 'Adigrat', + 'Juchitepec', + 'Nizhyn', + 'San Miguel de Allende', + 'Salemata', + 'Fenton', + 'As Sulaymaniyah', + 'Olhanpur', + 'Moon', + 'Churchdown', + 'Berezne', + 'Avenal', + 'Mettuppalaiyam', + 'Fort St. John', + 'Ghogardiha', + 'Palia Kalan', + 'Dardenne Prairie', + 'Bezerros', + 'Iowa City', + 'Mondragone', + 'Baojishi', + 'Cuiaba', + 'Kopparam', + 'Gokavaram', + 'Karamursel', + 'Bariariya Tola Rajpur', + 'Guambog', + "Mirassol d'Oeste", + 'Manbengtang', + 'Cali', + 'Yaguachi Nuevo', + 'Tiruppalai', + 'Kodivalasa', + 'Elakadu', + 'Hadyach', + 'Kumaralingam', + 'La Victoria de Acentejo', + 'Busembatia', + 'Arbroath', + 'Mahanoro', + 'El Qaa', + 'Ixhuatlan de Madero', + 'Golub-Dobrzyn', + 'Bundala', + 'Lurate Caccivio', + 'Palapag', + 'Biba', + 'Gokceada', + 'Kuzhittura', + 'Assomada', + 'Imias', + 'Obihiro', + 'Makinohara', + 'Chettiyapatti', + 'Wuyuan', + 'Tukrah', + 'Gorinchem', + 'Chettikulam', + 'Knic', + 'Piratini', + 'Takamatsu', + 'Ichhapur', + 'Ross', + 'Jamay', + 'Coyotepec', + 'Hani', + 'Malilipot', + 'Kozloduy', + 'Antwerp', + 'Vikramasingapuram', + 'Houma', + 'Osawa', + 'Colonia del Sacramento', + 'Daulatnagar', + 'Nannamukku', + 'Wanderley', + 'Dunhuang', + 'Campolongo Maggiore', + 'Chiche', + 'Merksem', + 'Kaboila', + 'Boscoreale', + 'Lordegan', + 'Douar Laouamra', + 'General Juan Madariaga', + 'Kottangara', + 'Badurpalle', + 'Rumoi', + 'Blackstone', + 'Marinha Grande', + 'Honmachi', + 'Oostkamp', + 'Xingangli', + 'Castelfidardo', + 'Zemun', + 'Krishnagiri', + 'Haomen', + 'Korbach', + 'Governador Celso Ramos', + 'East Pennsboro', + 'Aurich', + 'Ajjipuram', + 'Bury', + 'Nazare da Mata', + 'Humberto de Campos', + 'Pechea', + 'Cinarcik', + 'Jidd Hafs', + 'Noyon', + 'Zhaodianzi', + 'Sacavem', + 'Bilopillya', + 'Pader', + 'Miami Lakes', + 'Aplao', + 'Camabatela', + 'Domingos Martins', + 'Mahon', + 'Takaba', + 'Konskie', + 'Basso', + 'San Juan Despi', + 'Picui', + 'Ranipet', + 'Shidongcun', + 'Santa Rita do Sapucai', + 'Park Hills', + 'Caldera', + 'Gorenja Vas', + 'Holborn', + 'Welland', + 'Radzyn Podlaski', + 'Riacho dos Machados', + 'Dukli', + 'Motherwell', + 'Santa Rosa de Viterbo', + 'El Ateuf', + 'Villa Corona', + 'Rajaram', + 'Payipira', + 'Molnlycke', + 'Kautalam', + 'Duisburg', + 'Ghoradongri', + 'Sangasso', + 'Tacna', + 'Santa Helena', + 'Casablanca', + 'Kalliyassheri', + 'Xiancun', + 'Dabaga', + 'Chilcuautla', + 'Sihora', + 'New Britain', + 'Kingsburg', + 'Saint-Raymond', + 'Garoua', + 'Tulunan', + 'Torello', + 'Punal', + 'Beutelsbach', + 'Telenesti', + 'Abim', + 'Ed Damour', + 'Tecamachalco', + 'Nootdorp', + 'Centar Zupa', + 'Bernay', + 'Jatauba', + 'Azrou', + 'Hashtrud', + 'Chimichagua', + 'Radzymin', + 'Feldkirchen', + 'Houzhuang', + 'Brant', + 'Saint-Mande', + 'Marauatpur', + 'Radovljica', + 'La Entrada', + 'Kidbrooke', + 'Dnestrovsc', + 'Melksham', + 'Keshan', + 'Stockholm', + 'Fort Mitchell', + 'Haigerloch', + 'Altinozu', + 'Odzaci', + 'La Dorada', + 'Al Buraymi', + 'New Glasgow', + 'Vermilion', + 'Chongshan', + 'Kavarna', + 'Ban San Phak Wan Luang', + 'Puliyampatti', + 'Benslimane', + 'Chaumont-Gistoux', + 'Mae Hong Son', + 'Agia Paraskevi', + 'Kattipparutti', + 'Afyonkarahisar', + 'Berdychiv', + 'Alewah', + 'Pachrukhi', + 'Warzat', + 'Tilaran', + "Gonfreville-l'Orcher", + 'Muradiye', + 'Qara', + 'Defiance', + 'Bagu Na Mohra', + 'Milenaka', + 'Ruda Slaska', + 'Suchiapa', + 'Pachuca', + 'Kingston upon Thames', + 'Kumiyama', + 'Enriquillo', + 'El Astillero', + 'Bergheim', + 'Pindoretama', + 'Ardabil', + 'Lucban', + 'Cacuso', + 'Merimandroso', + "Sa'in Qal`eh", + 'Paula Candido', + 'Varapatti', + 'Erikolam', + 'Clarksdale', + 'Carhue', + 'Lisle', + 'Teotitlan', + 'Chebrolu', + 'Gabrovo', + 'Shambhunath', + 'Creve Coeur', + 'Silver City', + 'Matehuala', + 'Tefe', + 'Nohfelden', + 'Yangambi', + 'Camotan', + 'Las Mercedes', + 'Chevella', + 'Sokolov', + 'Porto Calvo', + 'Kayattar', + 'Batu Gajah', + 'Uppada', + 'Majalgaon', + 'Saint-Ghislain', + 'Staveley', + 'Jaffar Khanpet', + 'Chaiyaphum', + 'Parole', + 'Arara', + 'Hatfield', + 'Santiago Chimaltenango', + 'Cao Bang', + 'Gungoren', + 'Marechal Floriano', + 'Rio Cuarto', + 'Tazishan', + 'Binjai', + 'Pattensen', + 'Zhangjiazhuang', + 'Maasin', + 'Kizhakkanela', + 'Taquarituba', + 'Quedlinburg', + 'Schorndorf', + 'Melilli', + 'Griffin', + 'Ambondromisotra', + 'Cetinje', + 'Channelview', + 'Hanur', + 'Kenmore', + 'Jayrud', + 'Dollis Hill', + 'Taldyqorghan', + 'Al `Uqaylah', + 'Mutia', + 'Dabra', + 'Mae Ai', + 'Bamban', + 'Mayantoc', + 'Mechta Ouled Oulha', + 'Sacapulas', + 'Jaynagar-Majilpur', + 'Gladeview', + 'Dayong', + 'Monte Rico', + 'Nova Soure', + 'San Juan Zitlaltepec', + 'Almel', + 'Sakhua', + 'Kromeriz', + 'Vitorino', + 'Hayward', + 'Kahnuj', + 'Manalurpettai', + 'Altstatten', + 'Sydney Mines', + 'Liuhu', + 'Kasaali', + 'Acton', + 'Jiquipilas', + 'Talegaon Dhamdhere', + 'San Antonio Enchisi', + 'Kaduna', + 'Saint-Ave', + 'Renapur', + 'Carlos Spegazzini', + 'Riverdale', + 'Sint-Gillis-bij-Dendermonde', + 'El Aioun', + 'Ichinoseki', + 'Phulera', + 'Donwari', + 'Motipur', + 'Capitao de Campos', + 'York', + 'Rancho Mirage', + 'Ekma', + 'Thogapalle', + 'Glodeni', + 'Sedan', + 'Cupar', + 'Charbagh', + 'Sahasmal', + "Bazal'tove", + 'Gorkha', + 'Banha', + 'Oguzeli', + 'Nauagarhi', + 'Zaio', + 'Pirojgarh', + 'Aoshang', + 'Faruka', + 'Boaco', + 'Rani Sagar', + 'Cao Lanh', + 'Boyabat', + 'Waslala', + 'Vohitsaoka', + 'Dayton', + 'Borujen', + 'Konya', + 'Naj` Hammadi', + 'Yatomi', + 'Laferriere', + 'Deo', + 'Pampan', + 'Citluk', + 'Naranjito', + 'Haiwei', + 'Bohinjska Bistrica', + 'Kochkor-Ata', + 'Chiromo', + 'Kimitsu', + 'Linkoping', + 'Valinhos', + 'Lozova', + 'Siyazan', + 'Blenheim', + "Olho d'Agua das Cunhas", + 'Oak Park', + 'La Macarena', + 'Tasso Fragoso', + 'Ladkhed', + 'Taber', + 'Atchoupa', + 'Quilpue', + 'Cimislia', + 'Cimerak', + 'Ar Ruhaybah', + 'Xo`jaobod', + 'Antombana', + 'Tarnos', + 'Blackhawk', + 'Hengchun', + 'Petrzalka', + 'Ambatolampy', + 'Renai', + 'Massalubrense', + 'Marcianise', + 'Mako', + 'Palmito', + 'Marshalltown', + 'Taywarah', + 'Guiyang', + 'Patan', + 'Montichiari', + 'Vittoriosa', + 'Chili', + 'Manasa', + 'Khushab', + 'Kujukuri', + 'Zhongzhai', + 'Cagua', + 'Kryzhopil', + 'Phuntsholing', + 'Chhapra Bahas', + 'Banak', + 'Wolfhagen', + 'Biyala', + "An'gang", + 'Ban Phe', + 'Andoain', + 'Martina Franca', + 'Tadikonda', + 'Itapetininga', + 'Wusong', + 'La Carolina', + 'Greeneville', + 'Datori', + 'Gulbahor', + 'Weifen', + 'Farnley', + 'Piedade', + 'Reiskirchen', + 'Mahitsy', + 'Akouda', + 'Hucclecote', + 'Antsenavolo', + 'Jever', + 'Sablayan', + 'Holzkirchen', + 'Ramara', + 'Phulhara', + 'Ridgeland', + 'Youdiou', + 'Talwandi Chaudhrian', + 'Tadian', + 'Messias', + 'Suar', + 'Minamisuita', + 'Nipani', + 'Jugial', + 'Bisignano', + 'Opole', + 'El Jicaro', + 'Joensuu', + 'Todupulai', + 'Kamituga', + 'Guararapes', + 'Pike Creek Valley', + 'Taimali', + 'Chiconquiaco', + 'Brookfield', + 'Belo Jardim', + 'Uttaramerur', + 'Tokorozawa', + 'Mulungu', + 'Spencer', + 'Sopron', + 'Catape', + 'Mata-Utu', + 'Cha Grande', + 'Jandira', + 'Kunnatnad', + 'Kolhapur', + 'Manchenahalli', + "Cox's Bazar", + 'Mahisi', + 'Nunspeet', + 'Xocali', + 'Hitachiomiya', + 'Beaucaire', + 'Soissons', + 'Hjorring', + 'Antonio Cardoso', + 'Blaydon', + 'Jhalida', + 'Minden', + 'Wardenburg', + 'Ain Bessem', + 'Milwaukee', + 'Coventry', + 'Puli', + 'Arqalyq', + 'Januaria', + 'Los Almacigos', + 'Moreton', + 'Jennings', + 'Laguna Woods', + 'Biloela', + 'Chaddesden', + 'Monmouth Junction', + 'Sullivan', + 'Wassenberg', + 'Canyon', + 'Mograne', + 'Mardakan', + 'Areia', + 'El Tigre', + 'Wallingford', + 'Goshogawara', + 'Chandannagar', + 'San Marcos', + 'Pedra Branca', + 'Dhani Sukhan', + 'Barni', + 'Maumere', + 'Strathroy', + 'Guozhen', + 'Hlobyne', + 'Blace', + 'Pentecoste', + 'Malden', + 'Bad Orb', + 'Hallstahammar', + 'Delano', + 'Bhadsara', + 'Thal', + 'Dongnanyanfa', + 'Rio Bueno', + 'Vendas Novas', + 'Chhara', + 'Katarmala', + 'Ngorongoro', + 'Takaoka', + 'Kalianpur', + 'Smarje', + 'Mangaldan', + 'Aulla', + 'Koila Belwa', + 'Shenjiaba', + 'Emmen', + 'Ambalavayal', + 'Crepy-en-Valois', + 'Ladwa', + 'Oxchuc', + 'Khagaur', + 'Esmeraldas', + 'Cirkulane', + 'Kaviti', + 'Wadsworth', + 'Lukovit', + 'Venafro', + 'Saint-Gely-du-Fesc', + 'Paramount', + 'Dounan', + 'Fort Beaufort', + 'Ban Mueang Na Tai', + 'Hornsey', + 'Collingwood', + 'Lower Allen', + 'Rangwasa', + 'Merelbeke', + 'Jamao al Norte', + 'Caudebec-les-Elbeuf', + 'Cakovec', + 'Matatiele', + 'Carmen de Patagones', + 'Kivsharivka', + 'Faberg', + 'Doornkop', + 'Istres', + 'Ancud', + 'Ovidiu', + 'Strangnas', + 'Shazhou', + 'Gazantarak', + 'Daule', + 'El Ksar', + 'Riobamba', + 'Paxtakor Shahri', + 'Vontimitta', + 'Pyinmana', + 'Sunset Hills', + 'Raha Tiga', + 'Ujfeherto', + 'Kiskoros', + 'Benin City', + 'Delhi Cantonment', + 'Khowy', + 'Ban Rangsit', + 'Cabudare', + 'Valderrama', + 'Turki', + 'Lohne', + 'Pangkalpinang', + 'Bazhajiemicun', + 'Ribat Al Khayr', + 'Estaimpuis', + 'Mineros', + 'Huanghuajie', + 'Espungabera', + 'Bawku', + 'San Bartolo', + 'Raghogarh', + 'Jaito', + 'Kakiri', + 'Radzionkow Nowy', + 'Chilakalurupet', + 'Maragheh', + 'Alacati', + 'Gata', + 'Rohera', + 'Lakshmicharipara', + 'Myronivka', + 'Matriz de Camarajibe', + 'Tamarana', + "Ambinanin' Andravory", + 'Kirakira', + 'Bramhall', + 'Roccastrada', + 'Hasbergen', + 'Ranjal', + 'Sawakin', + 'Romblon', + 'Jogaili', + 'Kaga', + 'Jinka', + 'Limerick', + 'Chatou', + 'Narman', + 'Ponce', + 'Baskale', + 'Wilnsdorf', + "Saint-Michel de l'Atalaye", + 'Pakala', + 'Sao Sebastiao da Boa Vista', + 'Spring Hill', + 'Orkney', + 'Mahasolo', + 'Ranranagudipeta', + 'Oeiras', + 'Carlos Manuel de Cespedes', + 'Stavroupoli', + 'Conner', + 'Koscielisko', + 'San Donato Milanese', + 'Udon Thani', + 'Jinchang', + 'Dzuunharaa', + 'Castries', + 'Inegol', + 'Novohrodivka', + 'Chyhyryn', + 'Cabarete', + 'Ganderkesee', + 'Bielawa', + 'Roura', + 'Namegawa', + 'Shabqadar', + 'Geylegphug', + 'Guapi', + 'Urgnano', + 'Zhitiqara', + 'Wildberg', + 'Begusarai', + 'Heihe', + 'Zegzel', + 'Or Yehuda', + 'Uenohara', + 'Atherstone', + 'Taku', + 'Central Islip', + 'Dessel', + 'Coal', + 'Gaoua', + 'Narwana', + 'Shuzenji', + 'West Lafayette', + 'Hazar', + 'Kongsvinger', + 'Povoa de Varzim', + 'Zunheboto', + 'Kalmiuske', + 'Zacatepec', + 'Rethen', + 'Benjamin Aceval', + 'Bandeirantes', + 'Yakou', + 'Passi', + 'Malanje', + 'Catacaos', + 'Capelinha', + 'Qingyang', + 'Alcira', + 'La Gloria', + 'Tucson', + 'Ban Chorakhe Samphan', + 'Cienaga', + 'Pebane', + 'Lontra', + 'Haikoucun', + 'Dhanwar', + 'Weifang', + 'Thari Mir Wah', + 'Nakano', + 'Coron', + 'Maysville', + 'Jeonghae', + 'Trgoviste', + 'Salaga', + "Nan'ao", + 'Locri', + 'Kenndie', + 'Florsheim', + 'Ouroeste', + 'Pizzo', + 'Woodmere', + 'Muzaffarpur', + 'Vicencia', + 'Yuriria', + 'Andoas', + 'Chauhanpatti', + 'Debila', + 'Xiwanzi', + 'Mexico City', + 'Perico', + 'Nova Ipixuna', + 'Pullambadi', + 'Osaka', + 'Kazo', + 'Garut', + 'Tonya', + 'Zawiyat Razin', + 'Hajdunanas', + 'Mollerusa', + 'Nuevo San Carlos', + 'Inverurie', + 'Cuddapah', + 'Leiria', + 'Magdeburg', + 'As Saqlawiyah', + 'Sidhi', + 'Jitaicun', + 'Alegrete', + 'Arwal', + 'Pueblo Nuevo', + 'Kovilur', + 'Valaiyampattu', + 'Kollengode', + 'Southside', + 'Tiruvattar', + 'Ahlat', + 'Chandpura', + 'Singleton', + 'Valu lui Traian', + "K'olito", + 'Norzagaray', + 'Onet Village', + 'Maserada sul Piave', + 'Gaziantep', + 'Borgentreich', + 'Cheb', + 'Santa Maria Atzompa', + 'Caspe', + 'Dalton', + 'Ilebo', + 'Harpenden', + 'Tiznit', + 'Fredrikstad', + 'Itaparica', + 'Zabol', + 'Majali', + 'Ubombo', + 'Karaiyampudur', + 'Port Orange', + 'Atitalaquia', + 'Caldas', + 'Shyroke', + 'Songadh', + 'Hai Duong', + 'Ayamonte', + 'Heroica Guaymas', + 'Haraiya', + 'Iarintsena', + 'Cardoso', + 'Yoloten', + 'Tandrano', + 'Tingo Maria', + 'Quimbaya', + 'Jambalo', + 'Samaxi', + 'Leme', + 'Bougtob', + 'Sudipen', + 'Artigas', + 'Ambatotsipihina', + 'Charlottesville', + 'Creutzwald', + 'Mangbwalu', + 'Tempe', + 'Agareb', + 'Jurh', + 'Tambo', + 'Kungalv', + 'Navipet', + 'Ramapattanam', + 'Baykan', + 'Suhr', + 'Taurisano', + 'Maydolong', + 'Oulad Said', + 'Pianiga', + 'Jefferson Hills', + 'Paine', + 'Pocheon', + 'Vennesla', + 'Porto Recanati', + 'Mirpeta', + 'Sendenhorst', + 'Carmichael', + 'Borgo San Lorenzo', + 'Torton', + 'Banta', + 'Urbino', + 'Kedzierzyn-Kozle', + 'Yamunanagar', + 'Ishidoriyacho-eso', + 'Tatui', + 'Amarapura', + 'Kodoli', + 'Monterey', + 'Basavakalyan', + 'Beroun', + 'East Donegal', + 'To`raqo`rg`on', + 'Usharal', + 'Harihar', + 'Amborompotsy', + 'Barkly East', + 'Charaut', + 'Kuttattuppatti', + 'Aracagi', + 'Hongzhai', + 'Sonqor', + 'Krishnamsettipalle', + 'Balugan', + 'Agua Preta', + 'Laayoune', + 'Huyuk', + 'Muban Saeng Bua Thong', + 'Saviano', + 'Florina', + 'Naestved', + 'Itabaianinha', + 'Tekkumbagam', + 'Valls', + 'Ozuluama de Mascarenas', + 'Wanluan', + 'Toledo', + 'Beawar', + 'Parimpudi', + 'Ramachandrapuram', + 'Jalpatagua', + 'Chur', + 'Jajireddigudem', + 'Salgotarjan', + 'Thames Ditton', + 'Sao Joao dos Poleiros', + 'Japoata', + 'Backi Petrovac', + 'Mugalivakkam', + 'Bachra', + 'Ahmadpur East', + 'Ganserndorf', + 'Attibele', + 'Briniamaro', + 'Bazidpur', + 'Santos', + 'Aimores', + 'Ciudad de la Costa', + 'Westchester', + 'Brand', + 'Codlea', + 'Nallagunta', + 'Rovinari', + 'Schiedam', + 'Highland Village', + 'Heikendorf', + 'Ifs', + 'Chuzhou', + '`Anadan', + 'Acornhoek', + 'Fonds Verrettes', + 'Hikone', + 'Cartagena del Chaira', + 'Moyogalpa', + 'Cariari', + 'Moe', + 'Sahatavy', + 'Otley', + 'Nambiyur', + 'Camden', + 'Pomona', + 'Vizianagaram', + 'Lalo', + 'Kafr Zayta', + 'Bruchsal', + 'Gua', + 'Ali Sabieh', + 'Ouargaye', + 'Huzurnagar', + 'Pharaha', + 'Yayas de Viajama', + 'Novi di Modena', + 'Chofugaoka', + 'Besagarahalli', + 'Paulinia', + 'Davis', + 'Landhaura', + 'Apace', + 'San Felice sul Panaro', + 'Silvino Lobos', + 'Liugoucun', + 'Cislago', + 'Bububu', + 'Gohpur', + 'Bhatkal', + 'Kotal', + 'Lons-le-Saunier', + 'Sisai', + 'Palangarai', + 'Harohalli', + 'Tawargeri', + 'Newton', + 'Muscoy', + 'Kade', + 'Sene', + 'Morarano Chrome', + 'Nibria', + 'Rosbach vor der Hohe', + 'Hilpoltstein', + 'Seddouk Oufella', + 'Arbaa Sahel', + 'Olivar', + 'Sevan', + 'Forquilhinha', + 'Lake Mary', + 'Paramus', + 'Naula', + 'Hukeri', + 'Pinheiro', + 'Sivaganga', + 'Baleraja', + 'Koiri Bigha', + 'Le Pecq', + 'Koflach', + 'Namerikawa', + 'Yavuzeli', + 'Songzi', + 'Etawa', + 'Shek Tong Tsui', + 'Long Binh', + 'Tecuala', + 'Vyronas', + 'Potirendaba', + 'Luino', + 'Hazle', + 'Capitan Mauricio Jose Troche', + 'Attiecoube', + 'Queensburgh', + 'Santiponce', + 'Fleurus', + 'Ammapettai', + 'Montoro', + 'Al Waqf', + 'Bam', + 'Dehaqan', + 'Santa Lucia Cotzumalguapa', + 'Tucuran', + 'Ambesisika', + 'Bholsar', + 'Chino', + 'Androndrona Anava', + 'Country Club Estates', + 'Laren', + 'Asolo', + 'Aarsal', + 'Sumner', + 'Majalengka', + 'Barwaaqo', + 'Bon Air', + 'Ampitatafika', + 'Lizzano', + 'Majdel Aanjar', + 'Dahmani', + 'Bhauradah', + 'Qaha', + 'Khorramabad', + 'Shyamnagar', + 'Suisun City', + 'Frecheirinha', + 'Shaw', + 'Chepen', + 'Nulvi', + 'Sao Miguel Arcanjo', + 'Kollipara', + 'Pajara', + 'Kortemark', + 'Cha da Alegria', + 'Crawford', + 'Mistelbach', + 'Erkner', + 'Ituni', + 'Odate', + 'Nanded', + 'Piekary Slaskie', + 'Ainapur', + 'Kapaa', + 'Nemuro', + 'Huolu', + 'Banane', + 'Tredegar', + 'Farkhor', + 'Tlayacapan', + 'Szprotawa', + 'Panchari Bazar', + 'Hirson', + 'Kukrahill', + 'Zierikzee', + 'Talata-Volonondry', + 'Medjana', + 'Santa Maria La Pila', + 'Puligunta', + 'Kataha', + 'Weston', + 'Kaikalur', + 'Glen Ellyn', + 'East St. Paul', + 'Crown Point', + 'Lagoa', + 'Aybasti', + 'Awaji', + 'Sulibele', + 'Puerto Caicedo', + 'La Jigua', + 'Vera', + 'Friedrichsthal', + 'El Dorado', + 'Bezaha', + 'Pagegiai', + 'Ban Sai Ma Tai', + 'Trzic', + 'Sao Benedito do Rio Preto', + 'Arcata', + 'Brunete', + 'Cousse', + 'Itapeva', + 'Shaoshanzhan', + 'Ban Samo Khae', + 'Fort Smith', + 'Giannitsa', + 'Gerona', + 'Degeh Bur', + 'Awsim', + 'Blitar', + 'Basavilbaso', + 'Palsud', + 'Sibolga', + "Dias d'Avila", + 'Cascades', + 'Tecpan Guatemala', + 'Overland', + 'Levin', + 'Tolongoina', + 'Asten', + 'Tamandare', + 'Kannamangalam Tekku', + 'Kandakkadava', + 'Kilattingal', + 'Bayyanagudem', + 'Bremervorde', + 'Wyandanch', + 'Lutz', + 'Kasanda', + 'Tungavi', + 'Palompon', + 'Vinjamur', + 'Ponteland', + 'Kamienna Gora', + 'Springboro', + 'Morsbach', + 'Depalpur', + 'Londuimbali', + 'Garbagnate Milanese', + 'Yenimahalle', + 'Masagua', + 'Machiques', + 'Carbonia', + 'Pisco', + 'Lynwood', + 'Choisy-le-Roi', + 'Ambalaromba', + 'Seremban', + 'Kolar', + 'Telkapalli', + 'Deoria', + 'Glenn Dale', + 'Notre-Dame-des-Prairies', + 'Majayjay', + 'Luzhang', + 'Steha', + 'Sao Jose do Cerrito', + 'Zwettl', + 'Lubango', + 'Moka', + 'Sarpang', + 'Farrukhnagar', + 'Acanceh', + 'Dumas', + 'Minignan', + 'Mazatan', + 'Kadod', + 'Capotille', + 'Wertheim', + 'Gloucester Point', + 'Jibou', + 'Champasak', + 'Katuete', + 'Atuntaqui', + 'Tupi', + 'Nort-sur-Erdre', + 'Leland', + 'Zongolica', + 'North St. Paul', + 'O`nhayot', + 'South River', + 'Euclid', + 'Miedzyrzec Podlaski', + 'Madinat ash Shamal', + 'Sandanski', + 'Parora', + 'Gela', + 'Beronono', + 'Nederland', + 'Lower Macungie', + 'Acambay', + 'Cape Girardeau', + 'Mafamude', + 'Siddhirganj', + 'Gonbad-e Kavus', + 'San Antonio del Sur', + 'Tsuruga', + 'Sarcelles', + 'Pont-Saint-Esprit', + 'Serekali', + 'Iguape', + 'Rosemount', + 'Hulikal', + 'Nordenham', + 'Bannur', + 'Westerkappeln', + 'Bozdogan', + 'Eslohe', + 'Koth', + 'Kattari', + 'Caltanissetta', + 'Francavilla al Mare', + 'Iguai', + 'Moundou', + 'Kozakai-cho', + 'Alfaro', + 'Sonsoro', + 'Ljubljana', + 'Charakunda', + 'Ambohidranandriana', + 'Caraguatay', + 'Moriyama', + 'Voula', + 'Penamiller', + 'Ponnai', + 'Juan Aldama', + 'Douglasville', + 'Pati', + 'Pfarrkirchen', + 'Roman', + 'Busan', + 'Kottapeta', + 'Nagua', + 'Salaya', + 'Ciudad Dario', + 'Buttelborn', + 'Victorville', + 'San Pelayo', + 'Mauren', + 'Khairtal', + 'Bombarral', + 'Cadillac', + 'Isiro', + 'Cabral', + 'Pelagor', + 'Guastalla', + 'Cruces', + 'Gungu', + 'Milford', + 'Tigrana', + 'Mundargi', + 'Daram', + 'Saudharkrokur', + 'Canonsburg', + 'Aourir', + 'Blue Springs', + 'Commerce', + 'Saint-Die-des-Vosges', + 'Lubuklinggau', + 'Lake City', + 'Bougouni', + 'Netrakona', + 'Meral', + 'Csongrad', + 'Tokai', + 'Linthicum', + 'Taylorville', + 'Sano', + 'Araguatins', + 'Prokuplje', + 'Dhansaria', + 'Turtkul', + 'Gyzylgaya', + 'Bollullos de la Mitacion', + 'Mallagunta', + 'San Luis Potosi', + 'Ukmerge', + 'Chenove', + 'Huejuquilla el Alto', + 'South Gate', + 'Llantwit Major', + 'Thomazeau', + 'Memunda', + 'Stockton-on-Tees', + 'Himatnagar', + 'Rapid City', + 'Banes', + 'Rheydt', + 'Bobenheim-Roxheim', + 'Lauterach', + 'Kalmthout', + 'Yashan', + 'Baures', + 'Malanday', + 'Treviso', + 'Ico', + 'Vladimirci', + 'Dora', + 'Abergavenny', + 'Parow', + 'Tineghir', + 'Iapu', + 'Cremona', + 'Tazmalt', + 'Vernon Hills', + 'Palermo', + 'Ambiula', + 'Alaverdi', + 'Altamira', + 'Sao Goncalo', + 'Sakado', + 'Pingree Grove', + 'Newton Abbot', + 'Puerto Morelos', + 'Buesaco', + 'Santa Maria da Vitoria', + 'Zeuthen', + 'Hebri', + 'Petua', + 'Sertania', + 'Yangiyer', + 'Mahmudabad', + 'Dinhata', + 'Bariarpur', + 'Mondeville', + 'Efatsy-Anandroza', + 'Rasht', + 'Port Royal', + 'Marotta', + 'Suffern', + 'Pearland', + 'Paduvari', + 'Ain Lechiakh', + 'Ruvo di Puglia', + 'Wittingen', + 'Rochester Hills', + 'Matsavaram', + 'Dunakeszi', + 'Sowa Town', + 'Barneveld', + 'Koycegiz', + 'Shanhu', + 'Zaidpur', + 'Valenca', + 'Rockaway', + 'Champua', + 'Caojiachuan', + 'Saraykent', + 'Gheorgheni', + 'Shonai', + 'Itaueira', + 'Itanagar', + 'Bandar-e Mahshahr', + 'Yelandur', + 'Kempston', + 'Elazig', + 'San Juan Guichicovi', + 'Tom Price', + 'Zhegaozhen', + 'Igdir', + 'Chang', + 'Nyakrom', + 'Shamunpet', + 'Sultanabad', + 'Tazarka', + 'Rathdrum', + 'Souahlia', + 'Konnur', + 'Rinconada', + 'Lamballe', + 'Planaltina', + 'Sunadkuppi', + 'Mangpa', + 'Marsciano', + 'Eonyang', + 'Bani Murr', + 'Baba Hassen', + 'Colatina', + 'Tianningcun', + 'Morazan', + 'Guantingzhan', + 'Misserghin', + 'Carolina Forest', + 'Tanakallu', + 'Castellarano', + 'Kumla', + 'Yorktown', + 'Santo Domingo Xenacoj', + 'Louga', + 'Fort Lee', + 'Tepperumalnallur', + 'Ampanety', + 'Ajuy', + 'Idstein', + 'Pristina', + 'Snina', + 'Habaswein', + 'Joghtay', + 'Shimizucho', + 'Kotancheri', + 'Woodstock', + 'Falagueira', + 'Moorestown-Lenola', + 'San Juan Sacatepequez', + 'Rio do Sul', + 'Mirador', + 'Moba', + 'Hassi Khelifa', + 'Nossa Senhora Aparecida', + 'Ibiza', + 'Watauga', + 'Zemrane', + 'Santa Cruz Xoxocotlan', + 'Pilis', + 'Evian-les-Bains', + 'Beraketa', + 'Goldsboro', + 'Isulan', + 'Sundern', + 'Aikaranad', + 'Yola', + 'Sunderland', + 'Ouled Ben Abd el Kader', + 'Pakaur', + 'Antsirabe Avaratra', + 'Schofield Barracks', + 'Serang', + 'Lede', + 'Guernica', + 'Mostoles', + 'Villa Mercedes', + 'Carcar', + 'Beruniy', + 'Mariano Acosta', + 'Toin', + 'Kashikishi', + 'Dar Chabanne', + 'uMhlanga Rocks', + 'Mieres', + 'Chipurupalle', + 'Aranda', + 'Nacogdoches', + 'Benner', + 'Ahvaz', + 'Sint-Michiels', + 'Yamamoto', + 'Retie', + 'Pitman', + 'Bagabag', + 'Phalaborwa', + 'Couva', + 'Kheri Naru', + 'Bazidpur Madhaul', + 'Carlton Colville', + 'Al Mafraq', + 'Amasra', + 'Peruibe', + 'Cuarte de Huerva', + 'Labrador', + 'Bawshar', + 'Pirojpur', + 'Taraza', + 'Teminabuan', + 'Shimotsuke', + 'Garca', + 'Rifadpur', + 'Los Chiles', + 'Bhandarso', + 'Capurso', + 'Caetes', + 'Pajapita', + 'Puerto Real', + 'East York', + 'Teteven', + 'Coruche', + 'Wurzen', + 'Pescaria Brava', + 'Guzhou', + 'Stanwell', + 'Khanabad', + 'Xisa', + 'Guruzala', + 'Basla', + 'Sabana Larga', + 'Dom Feliciano', + 'Kuytun', + "L'Asile", + 'Bokhtar', + 'Nazarabad', + 'Leticia', + 'Malang', + 'Ambohimiera', + 'Amjhar', + 'Veitshochheim', + 'Besana in Brianza', + 'Lynn', + 'Barura', + 'Statte', + 'Balchik', + 'Ottappidaram', + 'Afir', + 'Barleben', + 'Ashland', + 'Jirja', + 'Woodbridge', + 'Smithton', + 'Neustadt bei Coburg', + 'Hewitt', + 'Ulstein', + 'Nong Bua', + 'Piracanjuba', + 'New Mirpur', + 'Darabani', + 'Szolnok', + 'Nqutu', + 'Ii', + 'Glassmanor', + 'Eruvatti', + 'Magarao', + 'Sunam', + 'Sonaimukh', + 'Chapelle-lez-Herlaimont', + "Hai'an", + 'Blaricum', + 'El Marsa', + 'Jutiapa', + 'Cihanbeyli', + 'Bershad', + 'La Mujer', + 'Sompting', + 'Lomas de Sargentillo', + 'Guacui', + 'Mpwapwa', + 'Sanhe', + 'Kampong Trach', + 'Govindgarh', + 'Weilmunster', + 'Hopkinsville', + 'Xicotencatl', + 'Crikvenica', + 'Faizabad', + 'Dehgolan', + 'Changji', + 'Obita', + 'Ottobrunn', + 'Pak Phanang', + 'Dongta', + 'Guaduas', + 'Clarksville', + 'Luxembourg', + 'Kut-e `Abdollah', + 'Puerto Penasco', + 'Hebli', + 'Locust Grove', + 'Lappeenranta', + 'Kizilcasar', + 'Terenos', + 'Kamen', + 'Barra de Santo Antonio', + 'Saint-Servan-sur-Mer', + 'Pinto', + 'Beverly Hills', + 'Rouyn-Noranda', + 'Joaquim Pires', + 'Wichelen', + 'Saint-Medard-en-Jalles', + 'Dibrugarh', + 'Gouvieux', + 'Schriesheim', + 'Taliwang', + 'Prachuap Khiri Khan', + 'Salida', + 'Dahivel', + 'Tanjung Selor', + 'Tabio', + 'Ilampillai', + 'Acaxochitlan', + 'West Donegal', + 'Marosakoa', + 'Coahuitlan', + 'Valasske Mezirici', + 'Mengmeng', + 'Umm ar Rizam', + 'Altindag', + 'Lewisburg', + 'Kamifurano', + 'Pune', + 'Miami Springs', + 'San Sebastian de Yali', + 'Berwick', + 'Quixada', + 'Wujindian', + 'Jiadong', + 'Bagnan', + 'Puke', + 'Bogazliyan', + 'Sertaozinho', + 'Beiya', + 'Pragadavaram', + 'Alarobia Bemaha', + 'Lara', + 'Pyryatyn', + 'Kantabanji', + 'Kodusseri', + 'Meiningen', + 'Fontainebleau', + 'Panapur', + 'Ulaangom', + 'Bihpur', + 'Bodinayakkanur', + 'Lins', + 'Helsingor', + 'Maryanaj', + 'New Kru Town', + 'Mococa', + 'Bab Ezzouar', + 'Ghazaouet', + 'Pulaski', + 'Grenchen', + 'East Riverdale', + 'Bourne', + 'Maqat', + 'Oliveirinha', + 'Deltona', + 'Vermillion', + 'Chotala', + "Hong'an", + 'Houbu', + 'Furth', + 'Tchibanga', + 'Ishaka', + 'Namala Guimbala', + 'Aire-sur-la-Lys', + 'Shentang', + 'Guilford', + 'Oswaldtwistle', + 'Binga', + 'Birstall', + 'Kandukur', + 'Dunleary', + 'Majia', + 'Pamban', + 'Hata', + 'Mitchells Plain', + 'Blankenfelde', + 'Itoigawa', + 'Andriba', + 'Maghra', + 'Bugarama', + 'Urk', + 'Hoima', + 'Binbrook', + 'Manali', + 'Manevychi', + 'Gotzis', + 'Byala Slatina', + 'Capoocan', + 'Pepperell', + 'Ayr', + 'Saint-Jean-de-Braye', + 'Chungju', + 'Barobo', + 'Laamarna', + 'Mudichchur', + 'Madhyamgram', + 'Sefrou', + 'Haora', + 'Harlakhi', + 'Bremgarten', + 'Conselheiro Lafaiete', + 'Nanbei', + "'Ain Mabed", + 'Koper', + 'Knowle', + 'Cerkno', + 'Perai', + 'Baghin', + 'Colne', + 'Kingsborough', + 'Mahagaon', + 'Chengguan', + 'Santa Eugenia', + 'Yuli', + 'Bad Rothenfelde', + 'Chongqing', + 'Aviles', + 'Gokhulapur', + 'Lokapur', + 'Menfi', + 'Kisvarda', + 'Sungai Guntung', + 'Ambolidibe Atsinanana', + 'Oberkirch', + 'Poteau', + 'Raleigh', + 'Ulongue', + 'Floresta Azul', + 'Migori', + 'Veracruz', + 'Roubaix', + 'Mariscal Jose Felix Estigarribia', + 'Sint-Michielsgestel', + 'Gering', + 'Yanchep', + 'Hof', + 'Villa Regina', + 'South Amboy', + 'Songkhla', + 'Barwah', + 'Stourbridge', + 'Bodegraven', + 'New Windsor', + 'Kubadupuram', + 'Lagoa dos Gatos', + "Pa'in Chaf", + 'Allagadda', + 'Casilda', + 'Tarancon', + 'Adilabad', + 'Chakla Waini', + 'Sabadell', + 'Bekipay', + 'Tajimi', + 'Ciputat', + 'Oulad Khallouf', + 'Rajpur Kalan', + 'Ghadamis', + 'Nyaungdon', + 'Bimo', + 'Tena', + 'Kendall', + 'Muzaffarabad', + 'Tongren', + 'Vrbas', + 'Resende Costa', + 'Cherchell', + 'Namayingo', + 'Port Angeles', + 'Egersund', + 'Bhasaula Danapur', + 'Wavre', + 'Itariri', + 'Timbiras', + 'Mahajanga', + 'Lochearn', + 'Vestby', + 'Kulgo', + 'Mola di Bari', + 'Istrana', + 'Shangtianba', + 'Aue', + 'Kirchzarten', + 'Lanling', + 'Tuneri', + 'Montrouge', + 'Taslicay', + 'Choro', + 'Schio', + 'Diadema', + 'Rosstal', + 'Taohongpozhen', + 'Nueva Guadalupe', + 'Tacoma', + 'Mayyanad', + 'Botou', + 'Alfonso', + 'Bexley', + 'Marginea', + 'Alliance', + 'Davuluru', + 'Candiac', + "Hammam M'Bails", + 'Corridonia', + 'Jaguarari', + 'Bouati Mahmoud', + 'Topeka', + 'Honiton', + 'Sambalpur', + 'Kalamner', + 'Tulua', + 'Baesweiler', + 'Chatra Gobraura', + 'Swanage', + 'Santa Magdalena', + 'Marrero', + 'Mizunami', + 'Bickley', + 'Ocala', + 'Dera Baba Nanak', + 'Reda', + 'Bourem Guindou', + 'Tagum', + 'Talata Ampano', + 'Poninguinim', + 'Bad Urach', + 'Alterosa', + 'Lake Hiawatha', + 'Rhosllanerchrugog', + 'Zirapur', + 'Bakixanov', + 'Scottburgh', + 'Laubach', + 'Bhakkar', + 'Bath', + 'Iztapa', + 'Kaabong', + 'Haiku-Pauwela', + 'Walthamstow', + 'Leiyang', + 'Silverton', + 'Hangzhou', + 'Namminikara', + 'Badr', + 'Ban Bang Rin', + 'Skydra', + 'Changting', + 'Bou Nouh', + 'Villorba', + 'Conceicao de Macabu', + 'Haldipur', + 'Chavakkad', + 'Artondale', + 'Isla Raton', + 'Taiyur', + 'Mel Bhuvanagiri', + 'Faratsiho', + 'Piso Firme', + 'Venlo', + 'Nules', + 'San Gaspar Ixchil', + 'London Colney', + 'Hesarghatta', + 'Gingee', + 'Shahpura', + 'Bhikhi', + 'Kamenice', + 'Amesbury', + 'Hanoi', + 'Davenport', + 'Bishunpur Sundar', + 'Oggiono', + 'Beinan', + 'Tsimasham', + 'Campos', + 'Chaponost', + 'Amondara', + 'Pariyari', + 'Brusque', + 'Coquimbo', + 'Promissao', + 'Malakoff', + 'Yunxian Chengguanzhen', + 'Baiao', + 'Tremelo', + 'Sesto Calende', + 'Pozega', + 'Liepaja', + 'Lonigo', + 'San Leonardo', + 'Gonabad', + 'Valdemoro', + 'Sikandra', + 'Vise', + 'Rybnik', + 'Hit', + 'Rosu', + 'Fengrenxu', + 'Barrie', + 'Adjud', + 'Manta', + 'Susuz', + 'Junin', + 'Lauda-Konigshofen', + 'Rocas de Santo Domingo', + 'Barjhar', + 'Kurdamir', + 'Prabumulih', + 'Miyazaki', + 'Menzel Kamel', + 'Micco', + 'Sankt Leon-Rot', + 'De Pinte', + 'Chanaral', + 'Abiko', + 'Carlos A. Carrillo', + 'Sarande', + 'Matoes', + 'Cholchol', + 'Gangarampur', + 'Aihua', + 'Yanggao', + 'Portalegre', + 'Falea', + 'Qapqal', + 'Gotenba', + 'Villanueva del Pardillo', + 'Boysun', + 'Bundu', + 'Jucas', + 'Abony', + 'Bahabad', + 'Paradarami', + 'Eerbeek', + 'Nyon', + 'Shannon', + 'Barreirinhas', + 'Manompana', + 'Fron', + 'Nathdwara', + 'Ganassi', + 'Korntal-Munchingen', + 'Tessenderlo', + 'Prescott', + 'Chivilcoy', + 'Juina', + 'Primero de Enero', + 'Campiglia Marittima', + 'Bharra', + 'Naju', + 'Halls Creek', + 'Sakawa', + 'Ain Temouchent', + 'Caimanera', + 'Mahao', + 'Zacatelco', + 'Perumuchchi', + 'Aberdeen', + 'Dentsville', + 'Lincoln Village', + 'Bou Hadjar', + 'Retiro', + 'Ouaouzgane', + 'Balrampur', + 'Iznik', + 'Coatepeque', + 'Dicle', + 'Phon', + 'Sanpaicun', + 'Zgornja Kungota', + 'Coulommiers', + 'Woodhaven', + 'Pirai', + 'Marana', + 'Benjamin Constant', + 'Kimpese', + 'Kashiba', + 'Vandithavalam', + 'Ar Ruseris', + 'Fusui', + 'Aalten', + 'Hiranai', + 'Kigumba', + 'Ocosingo', + 'Kotabommali', + 'Sugar Hill', + 'Covington', + 'Mielec', + 'Totness', + 'Ribeirao Preto', + 'Caotun', + 'Salaiya', + 'Karapurcek', + 'Hornchurch', + 'Hlyboka', + 'Azizpur Chande', + 'Sokhodewara', + 'Brus', + 'Dilovasi', + 'Manjathala', + 'Sabbah', + 'Sadiola', + 'Lomita', + 'Aveiro', + 'Kittur', + 'Rajpur', + 'Betsukai', + 'Shintomi', + 'Tahara', + 'Vuliyattara', + 'El Kelaa des Srarhna', + 'Gammarth', + "Sal'a", + 'Kolin', + 'Ceel Dheere', + 'Magpet', + 'Tarhzirt', + 'Chateauguay', + 'Qovlar', + 'Gryfice', + 'Bokakhat', + 'Terrace', + 'Acajutiba', + 'Tefam', + 'Wolow', + 'Kuaidamao', + 'Punnayur', + 'Maliana', + 'Ouando', + 'Howell', + 'Kodarma', + 'Gines', + 'Douglas', + 'Werve', + 'Corfe Mullen', + 'Rayon', + 'Tequila', + 'Kozani', + 'Rafina', + 'Placido de Castro', + 'Mascara', + 'Pszczyna', + 'Hochheim am Main', + 'Babahoyo', + 'Tanglou', + 'Villagarcia de Arosa', + 'Sao Romao', + 'Izmir', + 'Kabwe', + 'Wulan', + 'Lake Charles', + 'Babhantoli', + 'Villaviciosa', + 'Doljevac', + 'Achchippatti', + 'Parasbani', + 'Agadez', + 'Yalluru', + 'Saumur', + 'Ambodiriana', + 'Panda', + 'Jadupatti', + 'Santo Domingo Este', + 'Manakambahiny', + 'Hajduhadhaz', + 'Kitamilo', + 'Shenwan', + 'Madattukkulam', + 'La Romana', + 'Glasgow', + 'Aars', + 'Niquelandia', + 'South Farmingdale', + 'Mangalia', + 'Kualaserba', + 'Flandes', + 'Veroli', + 'Ixtapan de la Sal', + 'Makarska', + 'Lakho', + 'Dhanur Kalyanwadi', + 'Castillo', + 'Jamui', + 'Mutyalapalle', + 'Karaikkudi', + 'Gogounou', + 'Kurumbapalaiyam', + 'Myrne', + 'Maroamalona', + 'Collado-Villalba', + 'Sikandarpur', + 'Olonne-sur-Mer', + 'Cambundi Catembo', + 'Vohimasina', + 'Chenango', + 'Muara Teweh', + 'Las Matas de Farfan', + 'Livermore', + 'West Columbia', + 'Anqiu', + 'Mumbai', + 'Ogijares', + 'Bethesda', + 'Wyndham', + 'Lake Shore', + 'Yuchi', + 'Jalandhar Cantonment', + 'Manevy', + 'Sao Jose do Rio Pardo', + 'Chimoio', + 'Dagami', + 'Sagarejo', + "Lin'an", + 'Gobardhanpur Kanap', + 'Apple Valley', + 'Allauch', + 'Villafranca di Verona', + 'Yulin', + 'Herbolzheim', + 'Dolton', + 'Terebovlya', + 'Sri Madhopur', + 'Benifayo', + 'Valambur', + 'Sendrisoa', + 'Ranipur', + 'Media Luna', + 'Ocna Mures', + 'Kulundu', + 'Damdama', + 'Milagros', + 'Smithfield', + 'Lake Butler', + 'Ciudad Barrios', + 'Escuintla', + 'Cherry Hinton', + 'Solonytsivka', + 'Ribeirao Claro', + 'Balussheri', + 'Nanjikkottai', + 'Asela', + 'Martos', + 'Canto do Buriti', + 'Samalut', + 'Dhuburi', + 'Maltahohe', + 'Horst', + 'Bafang', + 'La Blanca', + 'Seraing', + 'Hedensted', + 'Chala', + 'Bou Salem', + 'Boralday', + 'Marktredwitz', + 'Neuenrade', + 'Muddada', + 'Serrinha', + 'Horizon West', + 'Machalpur', + 'Pathra', + 'Nelspruit', + 'Rankhandi', + 'Gaoniang', + 'Ohrid', + 'Conguaco', + 'Taylors', + 'Aqadyr', + 'Kirkop', + 'El Golea', + 'Slupsk', + 'Sawran', + 'Ansan', + 'Villa Dominico', + 'Kambia', + 'Sainte-Genevieve-des-Bois', + 'An Nuhud', + 'Samarkand', + 'Ringsaker', + 'Blangmangat', + 'Nuenen', + 'North Aurora', + 'Hoek van Holland', + 'Santa Cruz Cabralia', + 'Suvalan', + 'Phra Pradaeng', + 'Arnedo', + 'Pagsanjan', + 'Pietermaritzburg', + 'Weissenthurm', + 'Pebberu', + 'Kangazha', + 'Ancona', + 'Bou Noura', + 'Owensboro', + 'Catalina Foothills', + 'Alegre', + 'Douar Imoukkane', + 'Tirkadavur', + 'Washington Court House', + 'Colmenar Viejo', + 'Baikunthpur', + 'Sitrah', + 'Presidente Janio Quadros', + 'St. Louis Park', + 'Kempten', + 'Dergaon', + 'Pannaipuram', + 'Gifu', + 'Toul', + 'Sirakorola', + 'Vaals', + 'Barranca', + 'Elgoibar', + 'Kasamatsucho', + 'Ampitahana', + 'Totowa', + 'Mocoa', + 'Beni Slimane', + 'Bethany', + 'Ramdiri', + 'Bariadi', + 'Cofradia', + 'Tandil', + 'Bolton', + 'Sirat', + 'Uspenka', + 'Capim Branco', + 'Ozumba', + 'Dighawani', + 'Keonjhargarh', + 'Makurazaki', + 'Sada', + 'Sarmin', + 'Yamkanmardi', + 'Zhujiezhen', + 'Brampton', + 'Nynashamn', + 'Dawson Creek', + 'Analalava', + 'Dobrovnik', + 'Puxi', + 'Beni Tamou', + 'Damargidda', + 'San Casciano in Val di Pesa', + 'Springdale', + 'Luque', + 'Zara', + 'Dakit', + 'Urena', + 'Naduhatti', + 'General Jose de San Martin', + 'Raia', + 'Bhuj', + 'Tisnov', + 'Tekkekoy', + 'Faridpur', + 'Sao Vicente', + 'Bad Salzuflen', + 'Itororo', + 'Petersberg', + 'Castelsarrasin', + 'Madiama', + 'Voluntari', + 'Butaleja', + 'Carandai', + 'Arusha', + 'Strumica', + 'Quijingue', + 'Banovce nad Bebravou', + 'Huaibei', + 'Siswa', + 'Ansiao', + 'Baisa', + 'Kozuchow', + 'Mions', + 'Kenema', + 'Rajaudha', + 'Onga', + 'City of Calamba', + 'Buli', + 'Lokhvytsya', + 'Chak Thathi', + 'Qasr-e Qomsheh', + 'Wilson', + 'Tarawa', + 'Libjo', + 'Batocina', + 'Tajpur', + 'Kanyakulam', + 'Manzhouli', + 'Bougaa', + 'Kitzingen', + 'Fenoughil', + 'Dhanera', + 'Dhorgaon', + 'Abohar', + 'Zug', + 'Ghaura', + 'Aparecida do Taboado', + 'Zapotlanejo', + 'Natanz', + 'Guarda', + 'Chengara', + 'Tup', + 'Livani', + 'Sirsia Hanumanganj', + 'Qal`at al Madiq', + 'Tamarac', + 'South Miami', + 'Thung Sai', + 'Grodzisk Wielkopolski', + 'Jiutepec', + 'Nautanwa', + 'Grenada', + 'Nandod', + 'Helotes', + 'Nang Rong', + 'Makiivka', + 'Paxtaobod', + 'Susaki', + 'Fuso', + 'Tsawwassen', + 'Villeurbanne', + 'Ternopil', + 'Pandaul', + 'Nardo', + 'Puerto Aysen', + 'Marvdasht', + 'Funafuti', + 'Siraway', + 'El Milagro', + 'Dinapore', + 'Conisbrough', + 'Ban Duea', + 'Kawm Umbu', + 'Derhachi', + 'Setubinha', + 'Assis', + 'Shikarpur', + 'Hukumati Baghran', + 'Manuel Urbano', + 'Penacova', + 'Mishawaka', + 'Kremenchuk', + 'Salzkotten', + 'Sakai', + 'Ostercappeln', + 'Sebikhotane', + 'Mahatalaky', + 'Recanati', + 'Sainte-Foy-les-Lyon', + 'Hengshan', + 'Antonio Enes', + 'Adivala', + 'Odaipatti', + 'Aginiparru', + 'Sao Goncalo dos Campos', + 'Sagaing', + 'Anjad', + 'Jevargi', + 'Bastia', + 'General Tinio', + 'Kailua', + 'Fukutsu', + 'Nogata', + 'Park Forest', + 'Lolokhur', + 'Moengo', + 'Hermosillo', + 'Greencastle', + 'Pittsburgh', + 'Luuq', + 'Toluca', + 'Satgachia', + 'Nova Varos', + 'Tetovo', + 'Empalme', + 'Cherryland', + 'Ka-Bungeni', + 'Fernandopolis', + 'Oita', + 'Walnut', + 'Dalian', + 'Viersen', + 'Jyvaskylan Maalaiskunta', + 'Warragul', + 'Malaikkal', + 'Loule', + 'Honolulu', + 'Azalea Park', + 'Samba Cango', + 'Boblingen', + 'Istmina', + 'Southend', + 'Kallithea', + 'Khiria', + 'Huaral', + 'Mendota', + 'Upper Buchanan', + 'Damietta', + 'Porto Empedocle', + 'Santo Antonio do Ica', + 'Nunungan', + 'Naysar', + 'Pico Rivera', + 'Riano', + 'Snodland', + 'Sangre Grande', + 'Sun City', + 'Naunhof', + 'Fisciano', + 'Vedene', + 'Khawad', + 'Vernon', + 'Ahiro', + 'Chidambaram', + 'Chacabuco', + 'Elsdorf', + 'Chuhal', + 'Djelfa', + 'Qiryat Shemona', + 'Altamirano', + 'Cubellas', + 'Allonnes', + 'Aracaju', + 'Novi Knezevac', + 'Ikalamavony', + 'Staunton', + 'Mpophomeni', + 'Manombo Atsimo', + 'Madinat Hamad', + 'Guntramsdorf', + 'Elchuru', + 'Dongyang', + 'Gardony', + 'Taro', + 'Tablat', + 'Garulia', + 'Gopichettipalaiyam', + 'Raibari Mahuawa', + 'Tibba', + 'Taoyuan District', + 'Manavadar', + 'San Pedro Garza Garcia', + 'Amuntai', + 'Damua', + 'Desio', + 'Tomboutou', + 'Parlier', + 'Modasa', + 'Ubud', + 'Makan', + 'Vieux-Conde', + 'Maranga', + 'Acobamba', + 'Rugby', + 'Paramirim', + 'Nirgua', + 'Alto Paraiso de Goias', + 'Bandar Lampung', + 'Koumaira', + 'Sebt Ait Ikkou', + 'Vavuniya', + 'Grand Terrace', + 'Surajgarha', + 'Pedro Velho', + 'Lanzhou', + 'Tieli', + 'Jadia', + 'Mapanas', + 'Nangan', + 'Glazoue', + 'Villa Literno', + 'Qianshanhong Nongchang', + 'Paso de Carrasco', + 'Calliaqua', + 'Watertown Town', + 'Tasgaon', + 'China', + 'Yoshinogari', + 'Warora', + 'Castlebar', + 'Hezhou', + 'Tijuana', + 'Vilachcheri', + 'Tama', + 'Stony Brook', + 'Puurs', + 'Dam Dam', + 'Muktsar', + 'Wishaw', + 'Clay', + 'Hattula', + 'Marojala', + 'Aguas Belas', + 'Ogano', + 'Kattagaram', + 'Sulakyurt', + 'Mariveles', + 'Kavala', + 'Leavenworth', + 'Ambohitsimanova', + 'Lingsugur', + 'Delicias', + 'Xihuachi', + 'Kukarmunda', + 'Saruu', + 'Lwengo', + 'Bokod', + 'Andraitx', + 'Polanco', + 'Willowbrook', + 'Peddapalle', + 'Doddipatla', + 'Basco', + 'Bhimavaram', + 'Timoktene', + 'Tizi', + 'Mettet', + 'Matadi', + 'Xiaotangzhuang', + 'Guna', + 'Villaricca', + 'Pfedelbach', + 'Barud', + 'San Antonio del Monte', + 'Advi Devalpalli', + 'Nowy Dwor Gdanski', + 'Hsinchu', + 'Bad Kreuznach', + 'Pasaje', + 'Miluo Chengguanzhen', + 'Puyang Chengguanzhen', + 'Vasto', + 'Abarkuh', + 'West Plains', + 'Carazinho', + 'Vedi', + 'Port Maria', + 'Karratha', + 'Fes', + 'Ghulakandoz', + 'Porto Acre', + 'Jinzhong', + 'Thyolo', + 'Dien Bien Phu', + 'Panniyannur', + 'Banbhag', + 'Saint-Lambert', + 'Bhoj', + 'Salug', + 'Sobraon', + 'Reigate', + 'Colts Neck', + 'Salcaja', + 'Liesti', + 'Tianyingcun', + 'Maia', + 'Befeta', + 'Ina', + 'Sutherlin', + 'Saint-Brice-sous-Foret', + 'St. Louis', + 'Bistaria', + 'Nixa', + 'Boqueirao', + 'Khimlasa', + 'Munai', + 'Encinitas', + 'Citlaltepec', + 'Tokigawa', + 'Kalloni', + 'Sachse', + 'Huckeswagen', + 'Meric', + 'Ilkal', + 'Bawana', + 'Greetland', + 'Alcazar de San Juan', + 'Soltau', + 'Wahiawa', + 'Mogogelo', + 'Villerupt', + 'Carqueiranne', + 'Morohongo', + 'Hervey Bay', + 'Lakhna', + 'Mardin', + 'Lidingo', + 'Dar Chioukh', + 'Juncos', + 'Alliston', + 'Ilorin', + 'Arita', + 'Skara', + 'Progress Village', + 'Savelugu', + 'Khirpai', + 'Kamalnagar', + 'Mount Holly', + 'Vreed-en-Hoop', + 'Akcakale', + 'Vence', + 'Kurawar', + 'Seoul', + 'Novi Grad', + 'Kudamatsu', + 'Colina', + 'Kottagudem', + 'Tankal', + 'Kazarman', + 'East Orange', + 'Mulanur', + 'Sfizef', + 'Larvik', + 'Pawni', + 'San Juan de Vilasar', + 'Venmani', + 'Gentilly', + 'Picnic Point', + 'Beiwusidui', + 'Pakdasht', + 'Tatvan', + 'Ardmore', + 'Capela do Alto Alegre', + 'Rakai', + 'Yakouren', + 'Puerto Asis', + 'Shirali', + 'Adjumani', + 'Huite', + 'Indaiatuba', + 'Ouled Moussa', + 'Tamboril', + 'Kasimkota', + 'Iligan', + 'Stratton Saint Margaret', + 'Jiancheng', + 'Mungod', + 'Sremcica', + 'Sara', + 'Garrel', + 'Narela', + 'Meilan', + 'Martinsicuro', + 'Culaba', + 'Suez', + 'Villamaria', + 'Baytunya', + 'Oleshky', + 'Mogaung', + 'Twinsburg', + 'Casatenovo', + 'Sadda', + 'Shiyali', + 'Independencia', + 'Jinotepe', + 'Guilin', + 'Samal', + 'Gouda', + 'Tarui', + 'Sao Felipe', + 'Srivilliputtur', + 'Malmal', + 'Pembroke Dock', + 'Schwaikheim', + 'Beizhou', + 'Horw', + 'Gohi Bishunpur', + 'Taby', + 'Ramallo', + 'Woodcrest', + 'San Jacinto Amilpas', + 'Sundarsi', + 'Basildon', + 'Harasta', + 'Brislington', + 'Collingdale', + 'Brezice', + 'Xam Nua', + 'Ans', + 'Hardiya', + 'Linnich', + 'Varamin', + 'Asuncion Mita', + 'Dalgan', + 'Sahawar', + 'Jiutai', + 'Bruckmuhl', + 'Bingley', + 'Dundigal', + 'Somers', + 'Villas', + 'Ouro Branco', + 'Apora', + 'Miduturu', + 'Manambolosy', + 'Wuchuan', + 'Kasumbalesa', + 'Brent', + 'Balma', + 'Beidou', + 'Farim', + 'Dagmara', + 'Bijaipur', + 'Karera', + 'Amersfoort', + 'Gold', + 'Patilar', + 'Tweed Heads', + 'San Quintin', + 'Saloa', + 'Ruiming', + 'Sarayan', + 'Silver Springs Shores', + 'Vakon', + 'Ingenbohl', + 'Chetma', + 'Blacksburg', + 'Pondokaren', + 'Queimadas', + 'Encantado', + 'Tsubata', + 'Mers el Hadjad', + 'Northglenn', + 'Genc', + 'Lohiyar Ujain', + 'Ruoqiang', + 'Madera', + 'Santana do Cariri', + 'Ramamangalam', + 'Bangawan', + 'Emirdag', + 'Santa Fe Springs', + 'Cabucgayan', + 'Beaver Falls', + 'Cypress', + 'Glanmire', + 'Ipua', + 'Jaca', + 'Pueblo Viejo', + 'Kashiwa', + 'Dos Hermanas', + 'Ras Tanura', + 'Sidi Abdellah Ben Taazizt', + 'Badger', + 'Velingrad', + 'Velsen-Zuid', + 'Iscuande', + 'Ziro', + 'Charneca', + 'Tourlaville', + 'Loma Linda', + 'Sevran', + 'Eraniel', + 'Trece Martires City', + 'Franceville', + 'Coari', + 'Khairabad', + 'Bunhe', + 'Taguatinga', + 'Gilan-e Gharb', + 'Nyborg', + 'Kawagoe', + 'Pinheiral', + 'Bavaro', + 'Lisse', + 'Shuilou', + 'Paraty', + 'San Pedro Huamelula', + 'Bamber Bridge', + 'Port Huron', + 'Quba', + 'Ajacuba', + 'Lambarene', + 'Sikandarabad', + 'Chornobaivka', + 'Dores de Campos', + 'Wakoro', + 'Palomares del Rio', + 'Ankola', + 'Chibia', + 'Birmingham', + 'Antrim', + 'Kingsport', + 'Rockledge', + 'Carrillos', + 'Irig', + 'Denekamp', + 'Oberhaching', + 'Tisma', + 'Uriangato', + 'Tori-Cada', + 'Wolomin', + 'Montignies-le-Tilleul', + 'Des Moines', + 'Angeles City', + 'Morinville', + 'Zunyi', + 'Port Blair', + 'Daparkha', + 'Petrosani', + 'Lewes', + 'Douar Souk L`qolla', + 'Siaton', + 'Beyne-Heusay', + 'Padang', + 'Nova Kakhovka', + 'Assare', + 'Garh Sisai', + 'Ulster', + 'Magny-les-Hameaux', + 'Vallieres', + 'Garagoa', + 'Sungurlu', + 'Gadaul', + 'Taraclia', + 'Aden', + 'Grand Bourg', + 'Sao Francisco do Guapore', + 'Meruoca', + 'Oud-Beijerland', + 'Nitra', + 'Capoterra', + 'Tasikmalaya', + 'Cuevo', + 'Fruit Cove', + 'Le Teil', + 'Beur', + 'Bouskene', + 'Saint-Pierre', + 'Palitana', + 'Bourkika', + 'Jiquilisco', + 'Hassa', + 'Ixtapaluca', + 'Velyka Dymerka', + 'Kampli', + 'Caetano', + 'Luis Antonio', + 'Horgen', + 'Nalatvad', + 'Quime', + 'Betsiboka', + 'Rancheria Payau', + 'Dongxing', + 'Panagyurishte', + 'Soure', + 'Sinalunga', + 'Bhopatpur', + 'Tottington', + 'Zogno', + 'Alpinopolis', + 'Ibirite', + 'Talusan', + 'Mae Wang', + 'Prato', + 'Barvynkove', + 'Altavilla Vicentina', + 'Mussomeli', + 'Hilchenbach', + 'Agueda', + 'Botupora', + 'San Fernando', + 'Gallarate', + 'Balombo', + 'Philipsburg', + 'Oulad Aissa', + 'Brazzaville', + 'Tissaf', + 'Sanniquellie', + 'Zeist', + 'Turgutlu', + 'Ashikaga', + 'Seclin', + 'Actopan', + 'Accra', + 'Destelbergen', + 'Paiker', + 'Iowa Colony', + 'Muvattupula', + 'Springe', + 'Coqueiral', + 'Gmunden', + 'Perry Barr', + 'Cuneo', + 'Masur', + 'Calimera', + 'Diang', + 'Nacozari Viejo', + 'Jurmala', + 'Tsarasaotra', + 'Chon Thanh', + 'Dandenong', + 'Zutphen', + 'Bunawan', + 'Kottaram', + 'Majhgawan', + 'Macedonia', + 'Totogalpa', + 'Grand Junction', + 'Medfield', + 'Tolcayuca', + 'Santiago del Estero', + 'Ibague', + 'Caucaia', + 'Quartucciu', + 'Shangshan', + 'Roldan', + 'Tiddim', + 'El Bosque', + 'Mangapet', + 'Enfield Lock', + 'Paulo Afonso', + 'Golden Gate', + 'Del City', + 'Brandys nad Labem-Stara Boleslav', + 'Ambatomasina', + 'San Pascual', + 'Gothurutha', + 'Budapest', + 'El Hamel', + 'Vadakadu', + 'Casalpusterlengo', + 'Vardannapet', + 'Glucholazy', + 'Talkha', + 'Victoriaville', + 'Fengdeng', + 'Bhalki', + "Sao Jorge d'Oeste", + 'Calaca', + 'Al `Awwamiyah', + 'Listowel', + 'Komenda', + 'Janiuay', + 'Copperas Cove', + 'Kovvali', + 'Cucer-Sandevo', + 'Birkat as Sab`', + 'Silaiyampatti', + 'Lianzhuangcun', + 'Arataca', + 'Natchez', + 'Guangyuan', + 'Ko Samui', + 'Hajduboszormeny', + 'Ambatondrazaka', + 'Akonolinga', + 'Barpeta', + 'Torrelodones', + 'Norrtalje', + 'Saurh', + 'Wohlen', + 'Felling', + 'Honjo', + 'Petare', + 'Proper Bansud', + 'Dendermonde', + 'Parauna', + 'Bibhutpur', + 'Sultepec', + 'Chiquinquira', + 'Lint', + 'Zhedao', + 'Santo Antonio de Padua', + 'Alburquerque', + 'Fuzuli', + 'Ocean Pines', + 'Atacames', + 'Francheville', + "Wadi Halfa'", + 'Ninh Hoa', + 'Baiquan', + 'Antigua', + 'Bevata', + 'Xinpo', + 'Warkan', + 'Qibray', + 'Gisors', + 'Pa Mok', + 'Tabuleiro do Norte', + 'Melres', + 'Sangam', + 'Ostrhauderfehn', + 'Buritirama', + 'Oleksandriia', + 'Dongzhang', + 'Rio Preto da Eva', + 'Idupugallu', + 'Florida City', + 'Tobias Fornier', + 'Newquay', + 'Ivins', + 'Kotah-ye `Ashro', + 'Klaksvik', + 'Klaeng', + 'Vatutine', + 'Rignano Flaminio', + 'Soamahamanina', + 'Essex', + 'Arenzano', + 'Arbaoun', + 'Ain Kansara', + 'Stein', + 'Gleisdorf', + 'Ottaviano', + 'Lloret de Mar', + 'Sindos', + 'Lausanne', + 'Swadlincote', + 'Buffalo Grove', + 'Coelho Neto', + 'Msata', + 'Ciudad Cuauhtemoc', + 'Home Gardens', + 'Resen', + 'Khergam', + 'Neu Isenburg', + 'Kiato', + 'Mahina', + 'Keelung', + 'Mahiari', + 'Itambacuri', + 'Tsiatajavona-Ankaratra', + 'Sake', + 'Narrabri', + 'Popovaca', + 'Uruma', + 'Doha', + 'Ilaiyankudi', + 'Cabo Frio', + 'Mustang', + 'Kolbermoor', + 'Anahidrano', + 'Skikda', + 'Omurtag', + 'Maqu', + 'Mouscron', + 'Anchieta', + 'Pendembu', + 'Mokokchung', + 'Cestos City', + 'Oulad Zemam', + 'Beerse', + 'Solin', + 'Orani', + 'Itapira', + 'Elburg', + 'Pretoria', + 'Nishihara', + 'Siparia', + 'Fort Riley', + 'Dar Chaifat', + 'Khiria Jhansi', + 'Rezvanshahr', + 'Gacheta', + 'Rio Mayo', + 'Huainan', + 'Sarkisla', + 'Frias', + 'Msila', + 'Neumarkt', + 'Ajjanahalli', + 'Santa Maria Xadani', + 'Loikaw', + 'Gebze', + "Shin'onsen", + 'Bhind', + 'Nakhon Si Thammarat', + 'Wangzhuang', + 'Ban Kao', + 'Barki Saria', + 'Wylie', + 'Birdsville', + 'Atoyac de Alvarez', + 'Bamberg', + 'Agourai', + 'Saavedra', + 'Gundelfingen', + 'Hunucma', + 'Ambohitrimanjaka', + 'San Pedro Necta', + 'Eeklo', + 'Gutalac', + 'Chankou', + 'Cerro Cora', + 'Gulfport', + 'Southaven', + 'Vemulapudi', + 'Pinal de Amoles', + 'Montgomery', + 'Conchali', + 'Cercola', + 'Baependi', + 'Urgup', + 'Qurayyat', + 'Ban Si Don Chai', + 'Duyun', + 'Gentio do Ouro', + 'Detroit Lakes', + 'Muna', + 'Pine Lake Park', + 'Omerli', + 'Ambatondrakalavao', + 'Las Cabras', + 'Dueville', + 'Darjeeling', + 'Los Gatos', + 'Poa', + 'Keren', + 'Jiajin', + 'Vogosca', + 'Radece', + 'Damonojodi', + 'Khurda', + 'Surallah', + 'Johor Bahru', + 'Cuervos', + 'Brixton', + 'Kasap', + 'San Juan La Laguna', + 'Dambai', + 'Marantao', + 'Aguazul', + 'Teoloyucan', + 'Munnar', + 'Madhopur Hazari', + 'Yaotsu', + 'Le Ray', + 'Segbwema', + 'La Apartada', + 'Vitrolles', + 'Amtali', + 'Neston', + 'Portage La Prairie', + 'Taytay', + 'Barahbatta', + 'Tiorpara', + 'Hajira', + 'As Sabburah', + 'Krynica', + 'East Rutherford', + 'Stovring', + 'Andernach', + 'Levski', + 'Vihiga', + 'Kadikkad', + 'Husepur', + 'Nokha', + 'Santa Isabel do Ivai', + 'Bithar', + 'Gaziemir', + 'Manapparai', + 'Sinait', + 'Brandfort', + 'Ibaraki', + 'General San Martin', + 'Parma Heights', + 'Yoshiwara', + 'Mudanya', + 'Bafq', + 'Mikolow', + "Chang'an", + 'Chota', + 'Kesbewa', + 'Sinacaban', + 'Ambarawa', + 'Molodohvardiisk', + 'Herat', + 'Sakaidecho', + 'Honefoss', + 'Handan', + 'Clydebank', + 'Glenpool', + 'Uman', + 'San Biagio di Callalta', + 'Ocean City', + 'Qiryat Yam', + 'Baldwin', + 'Sweden', + 'Soavina', + 'Hugo', + 'Tra Vinh', + 'Taibet', + 'Turi', + 'Agua Blanca Iturbide', + 'Cherasco', + 'Parun', + 'Cedar Hills', + 'Arugollu', + 'Puduppattanam', + 'Monki', + 'Dorog', + 'Tissamaharama', + 'Seffner', + 'Tongchuan', + 'Nethirimangalam', + 'Ambalanirana', + 'Torbat-e Jam', + 'Balangkayan', + 'Malazgirt', + "Uchtepa Qishlog'i", + 'Les Anglais', + 'Sing Buri', + 'Zhaoxiang', + 'Porta Westfalica', + 'Kajur', + 'Casa Grande', + 'Nkoteng', + 'Pasca', + 'Merefa', + 'Perols', + 'Ellensburg', + 'Mannukara', + 'Rum', + 'Moglingen', + 'Tendrara', + 'Traiskirchen', + 'Dialoube', + 'Poona-Piagapo', + 'Orthez', + 'Hollinwood', + 'Ferryhill', + 'Heerhugowaard', + 'Bad Soden-Salmunster', + 'Twin Falls', + 'Imamoglu', + 'Gartringen', + 'Vaudreuil-Dorion', + 'Chonthrhu', + 'Aberbargoed', + 'Langar', + 'Cabarroguis', + 'Anakapalle', + 'Geraldton', + 'Seara', + 'Guasca', + 'Ban Mae Sun Luang', + 'Sankt Johann in Tirol', + 'Musselburgh', + 'Nave', + 'Bhola', + 'Mansehra', + 'Villa Sarmiento', + 'Sao Bento do Una', + 'Balasan', + 'Bocana de Paiwas', + 'Costesti', + 'Podu Iloaiei', + 'Jaitpura', + 'Rio Colorado', + 'Villa Nueva', + 'Tlaquepaque', + 'Sutton on Hull', + 'Radomyshl', + 'Muttanampalaiyam', + 'Elon', + 'Great Falls', + 'Al `Amirat', + 'Ganzhu', + 'Machachi', + 'Lehututu', + 'Ambohimierambe-Andranofito', + 'Singur', + 'Lagindingan', + 'Bocaina', + 'Siguatepeque', + 'Jalalkhera', + 'Santa Lucija', + 'Colmeia', + 'Aneho', + 'Beterou', + 'Mont-Organise', + 'Cabanas', + 'Leduc', + 'Euxton', + 'Trebinje', + 'Patri', + 'Ostrava', + 'Bay Shore', + 'Ghatkesar', + 'Gia Nghia', + 'University Heights', + 'Montigny-les-Metz', + 'Pipraun', + 'Villa de Cura', + 'Polokwane', + 'Daloa', + 'Souma', + 'Cerea', + 'Gracanice', + 'Anteza', + 'Dedza', + 'Hilsea', + 'Koduvalli', + 'Katravulapalle', + 'Nembro', + 'Wanlaweyn', + 'Sardulgarh', + 'Hatibanda', + 'Khizrpur', + 'Sailana', + 'Holbrook', + 'Horwich', + 'Motibennur', + 'Kenner', + 'Bugallon', + 'Angermunde', + 'Boguszow-Gorce', + 'Motomiya', + 'Nanzhuangzhen', + 'Tangxing', + 'Tamanrasset', + 'Brasileia', + 'Canandaigua', + 'Gardez', + 'Qorasuv', + 'Halemba', + 'Biandanshan', + 'Mauleon', + 'Komarno', + 'Husi', + 'Ngaoundal', + 'Ferreiros', + 'Gatunda', + 'Aioi', + 'Jainagar', + 'Longyan', + 'Mocimboa', + 'Central Point', + 'Machadodorp', + 'Niesky', + 'Trets', + 'Kajang', + 'Tuxpan', + 'Anosy Avaratra', + 'Novhorod-Siverskyi', + 'Zhenjiang', + 'Srungavarapukota', + 'San Sebastian de la Gomera', + 'Frankston', + 'Ninga', + 'Morauna', + 'Saginaw', + 'Kussnacht', + 'Lerida', + 'Silchar', + 'Thakurainia', + 'Wote', + 'Riom', + 'Khachrod', + 'Takizawa', + 'Psychiko', + 'Niasso', + 'Rio das Pedras', + 'La Maquina', + 'Kaguchi', + 'San Fabian', + 'Devarapalle', + 'Nahiyat Ghammas', + 'Tlapacoyan', + 'Debe', + 'Santa Maria de Itabira', + 'Ifigha', + 'Neduvattur', + 'Monteprandone', + 'San Pedro Perulapan', + "Bou'nane", + 'Ponnagyun', + 'Guaicara', + 'Krivogastani', + 'Ino', + 'Stupava', + 'New Mills', + 'Ankadimanga', + 'Liaoyang', + 'Chittaurgarh', + 'Bim Son', + 'Cullera', + 'Blackburn', + 'Great Driffield', + 'Mukacheve', + 'Warka', + 'Villers-la-Ville', + 'Gavarr', + 'Khrustalnyi', + 'Easley', + 'Caykara', + 'Woudenberg', + 'Kismaayo', + 'Chojnice', + 'Holladay', + 'Leiderdorp', + 'Reading', + 'Evansville', + 'Bamaiya Harlal', + 'Johns Creek', + 'Qo`qon', + 'Tambaga', + 'Kouande', + 'Sapang Dalaga', + 'Rocafuerte', + 'Curepipe', + 'Jabuticabal', + 'Hasroun', + 'Nishinoomote', + 'Salemi', + 'Bailongqiaocun', + 'Niefern-Oschelbronn', + 'Jablah', + 'Susa', + 'Ortuella', + 'Bitonto', + 'Karadge', + 'Quelimane', + 'Pirthipur', + 'Crisopolis', + 'Venosa', + 'Anantapur', + 'Grajau', + 'Idah', + 'Sidlice', + 'Middle Smithfield', + 'Kanie', + 'Khari', + 'Patnagarh', + 'Tamentit', + 'Ciudad Valles', + 'Kampen', + 'Madangir', + 'Swidwin', + 'Analaroa', + 'Cayirli', + 'Cernay', + 'Houghton Regis', + 'Redon', + 'Belchatow', + 'Maktar', + 'Belagal', + 'Chikkarampalaiyam', + 'Novato', + 'Notre-Dame-de-Gravenchon', + 'Wuustwezel', + 'Palaiyampatti', + 'Kandanur', + 'Nahavand', + 'Tokushima', + 'Sandakan', + 'Avidha', + 'Chaital', + 'Shri Mahavirji', + 'Tashir', + 'Taghbalt', + 'Cottage Grove', + 'Paso de los Toros', + 'Ilicinia', + "Monteforte d'Alpone", + 'Helleland', + 'Corcuera', + 'Goa', + 'Oqqo`rg`on', + 'Chalco', + 'Chorwad', + 'Jhenida', + 'Triesen', + 'Ban Don Kaeo', + 'Nova Prata', + 'Pyrzyce', + 'Sogod', + 'Kilindoni', + 'Condega', + 'Qatana', + 'Nuth', + 'Ban Phru', + 'Kiiminki', + 'Antanandehibe', + 'La Concordia', + 'Guilherand', + 'Antsiranana', + 'Mersch', + 'Al Awjam', + 'Selouane', + 'Coronda', + 'Oregon City', + 'Bordj Zemoura', + 'Alwarkurichchi', + 'Kangasala', + 'Sonada', + 'Burdur', + 'Lollar', + 'Bethel Park', + 'Higashiagatsuma', + 'Gandujie', + 'Talugtug', + 'Cocotitlan', + 'Cassano al Ionio', + 'New Hamburg', + 'Jacobina', + 'Tourougoumbe', + 'Ribeiropolis', + 'Midsomer Norton', + 'Gretz-Armainvilliers', + 'Nagqu', + 'Sunnyvale', + 'Canberra', + 'Rupana', + 'Owosso', + 'Sao Jose do Norte', + 'Mantaly', + 'Socota', + 'Cape St. Claire', + 'Lepakshi', + 'Rounia', + 'Tavira', + 'Qazyan', + 'Chettipulam', + 'Grantsville', + 'Nagarote', + 'Baras', + 'Ashaiman', + 'Birendranagar', + 'West Allis', + 'Ouricuri', + 'Sarzana', + 'Vallegrande', + 'El Kseur', + 'Assenede', + 'Chitauria', + 'Steinheim', + 'Amsterdam', + 'Goth Tando Sumro', + 'Santa Cruz Itundujia', + 'Cartago', + 'Nandaime', + 'Andes', + 'Dialakorodji', + 'Schulzendorf', + 'Bantacan', + 'Calarasi', + "Ra's Gharib", + 'East Lake-Orient Park', + 'Baitoa', + 'Ormesson-sur-Marne', + 'El`ad', + 'Campechuela', + 'Shiotacho-matsusaki', + 'Kankaanpaa', + 'Ronda', + 'Urucuia', + 'Morlaix', + 'Satwar', + 'Bethel', + 'Corvallis', + 'Yinchuan', + 'Talavera', + 'Shahriston', + 'Royston', + 'Bexbach', + 'Vilangudi', + 'Brinkmann', + 'Hellendoorn', + 'Imi-n-Tanout', + 'South Hayling', + 'Schroeder', + 'Petrovka', + 'Zouerate', + 'Bingen am Rhein', + 'Bovenden', + 'Biri', + 'Teaneck', + 'Yvoir', + 'Santa Eulalia del Rio', + 'Rolleston', + 'Badantola', + 'Waimea', + 'Muzo', + 'Staro Nagoricane', + 'Paranhos', + 'Neustrelitz', + 'Paouignan', + 'Oakashicho', + 'Iygli', + 'Rangra', + 'Sassenage', + 'Lommedalen', + 'Giyon', + 'Conroe', + 'Upperu', + 'Qorao`zak', + 'Lingal', + 'Jasien', + 'Nonoichi', + 'Al Bardiyah', + 'Arrentela', + 'Saharsa', + 'Kalwakurti', + 'Lakeland North', + 'Bad Ems', + 'Quibaxi', + 'Huskvarna', + 'Bihac', + "'Ain Naga", + 'Euclides da Cunha', + 'East Grinstead', + 'Koneurgench', + 'Calauag', + 'Kiangan', + 'Mill Valley', + 'Turpan', + 'Cacimbinhas', + 'Urucuca', + 'Anouvong', + 'Kunimedu', + 'Islamabad', + 'Chahar Borj-e Qadim', + 'Maribor', + 'Ilgin', + 'Mount Lavinia', + 'Tsukumiura', + 'Aix-en-Provence', + 'Ipaporanga', + 'Pokotylivka', + 'Nazipur', + 'Tebingtinggi', + 'Wenzenbach', + 'Solingen', + 'Beveren', + 'Koszalin', + 'Ticul', + 'Kuroishi', + 'Marialva', + 'Auria', + 'Raffadali', + 'Kumagaya', + 'Ruppichteroth', + 'Dougoufe', + 'Dompu', + 'Petrus Steyn', + 'Lattes', + 'Raalte', + 'Taungdwingyi', + 'Guixi', + 'Ganta', + 'Schonwalde-Siedlung', + 'Ifatsy', + 'Baroda', + 'Los Andes', + 'Zhaitangcun', + 'Simraungadh', + 'Fada', + 'Moldova Noua', + 'Sankt Andra', + 'Ica', + 'Ngora', + 'Robbah', + 'Rahiar Kunchi', + 'Ouatagouna', + 'Benavente', + 'Suluru', + 'Burstadt', + 'Hindoli', + 'Santa Maria Petapa', + 'Sanana', + 'Mangidy', + 'Buldan', + 'Ustrzyki Dolne', + 'Bouznika', + 'Florstadt', + 'Santiago Papasquiaro', + 'Sirur Tajband', + 'Ottumwa', + 'Terralba', + 'Henrietta', + 'Adrar', + 'Koni', + 'Cardonal', + 'Haskah Menah', + 'Dawmat al Jandal', + 'Salzgitter', + 'Shikharpur', + 'So-Awa', + 'Baghmari', + "'Ain Arnat", + 'Gojra', + 'Majidpur', + 'Cayeli', + 'Bouansa', + 'Barhi', + 'New Amsterdam', + 'Ibigawa', + 'Schwarzenberg', + 'Darling', + 'Borgaon', + 'Daudnagar', + 'Kitsuki', + 'Fairfax', + 'Mannarakkat', + 'Oberasbach', + 'Murphy', + 'Laurentides', + 'Manjha', + 'Kobo', + 'Kameoka', + 'Bafut', + 'Krasyliv', + 'Saiha', + 'Edinburgh', + 'Kishkenekol', + 'Leyton', + 'Isiolo', + 'Maibog', + 'Chiranellur', + 'Athens', + 'Sampit', + 'Ak-Suu', + 'Toulal', + 'Rangia', + 'Morton Grove', + 'Kaithinia', + 'Antipolo', + 'Tabant', + 'Starachowice', + 'Al Yadudah', + 'Zonguldak', + 'Piaseczno', + 'Nirna', + 'Mitrovice', + 'Plainfield', + 'Wheat Ridge', + 'Oakbrook', + 'Yahualica de Gonzalez Gallo', + 'Drimmelen', + 'Campo de la Cruz', + 'El Roble', + 'Umarga', + 'Mqam at Tolba', + 'Consett', + 'Ponders End', + 'Mount Lebanon', + 'Harima', + 'Marquette-les-Lille', + 'Spata', + 'Panaon', + 'Viravada', + 'Juazeiro do Norte', + 'Tieling', + 'Montemorelos', + 'Manggar', + 'Scicli', + 'Gorlice', + 'Rong Kwang', + 'Mill Creek', + 'Rivne', + 'Linamon', + 'Creazzo', + 'Moody', + 'Patnanungan', + 'Qasr al Qarabulli', + 'Leingarten', + 'Saqultah', + 'Farob', + 'Chinju', + 'Bartolome Maso', + 'Pedreguer', + 'Kuldiga', + 'San Bernardo del Viento', + 'Kushiro', + 'Maha Sarakham', + 'Campbell River', + 'Balaxani', + 'Kilakkurichchi', + 'Uitenhage', + 'Tudela de Duero', + 'Brianka', + 'Garkha', + 'Kassel', + 'Avigliana', + 'Herk-de-Stad', + 'Kassama', + 'Al Jubayl', + 'Longavi', + 'Ugamedi', + 'Leutkirch im Allgau', + 'Lambeth', + 'Koduman', + 'Bais', + "Petite Riviere de l'Artibonite", + 'Presidencia Roque Saenz Pena', + 'Bad Munder am Deister', + 'Kottadindulu', + 'Thorigny-sur-Marne', + 'Tinkoni', + 'Bilacari', + 'Madruga', + 'Chula Vista', + 'Strzelce Opolskie', + 'Chalgeri', + 'Teningen', + 'Cumanda', + 'Ankilivalo', + 'Arica', + 'Mabacun', + 'Agios Dimitrios', + 'Pihuamo', + 'Bithlo', + 'Lititz', + 'Barth', + 'Nkhotakota', + 'Castellammare del Golfo', + 'Tearce', + 'Jinzhou', + 'Mahaditra', + 'Nelkattumseval', + 'Marinilla', + 'Taguai', + 'Ambohidronono', + 'Ansfelden', + 'Angus', + 'Chintalapalli', + 'Piedra Blanca', + 'Prenzlau', + 'San Manuel Chaparron', + 'Grantham', + 'Atyra', + 'Cornwall', + 'Conselice', + 'Brasilia', + 'Igarape Grande', + 'Toplita', + 'Malaimbandy', + 'Kasane', + 'Villa Ocampo', + 'Simarwara Durgapur', + 'Piripa', + 'Giza', + 'Xianyang', + 'Rodas', + 'Canal Winchester', + 'Vashon', + 'Pully', + 'Venice', + 'Miantsoarivo', + 'Rio Cauto', + 'Shahjanpur', + 'Motala', + "'Ain Azel", + 'Taebaek', + 'Mankato', + 'Sevres', + 'Sarangani', + 'Berndorf', + 'Paratinga', + 'Floral Park', + 'Santa Catalina', + 'Greenacres', + 'Verviers', + 'Deoni Buzurg', + 'Lantapan', + 'Brakpan', + 'Santa Ana Chiautempan', + 'Chamtha', + 'Umarkhed', + 'Chai Nat', + 'Willingboro', + 'Licab', + 'Esquel', + 'Santiago Tuxtla', + 'Suran', + 'Mazenod', + 'Holmdel', + 'Saguiaran', + 'Nidadavole', + 'Santa Rosa de Calamuchita', + 'Malkanur', + 'Avaniyapuram', + 'Saktipur', + 'Lynnfield', + 'Orange Park', + 'Lanuvio', + 'Magna', + 'Hanumangarh', + 'Ashmun', + 'Ayirapuram', + 'Viale', + 'Andarai', + 'Falesti', + 'Soverato Marina', + 'Loeches', + 'Ibirataia', + 'Chester-le-Street', + 'Gouna', + 'Azeffoun', + 'Burlingame', + 'Crest', + 'Flowood', + 'Lupane', + 'Iferhounene', + 'Eravattur', + 'Mayaguez', + 'Butte', + 'Azangaro', + 'Viladecans', + 'Argenta', + 'Rauma', + 'Khombole', + 'Trstenik', + 'Kiryu', + 'Mambusao', + 'Tan Uyen', + 'Yazoo City', + 'Turnisce', + 'Navolato', + 'San Giustino', + 'Lice', + 'Antsambahara', + 'Nagahama', + 'Herndon', + 'Phibun Mangsahan', + 'Lushnje', + 'Wanaque', + 'Chuncheon', + 'Thomassique', + 'Havza', + 'Wellington', + 'Nagato', + 'Aucamville', + 'Corupa', + "Ra's al Khafji", + 'Novi Ligure', + 'Isnos', + 'Taiyong', + 'Beigangwa', + 'Greymouth', + 'Sevilla', + 'Beech Grove', + 'Viry-Chatillon', + 'Bogdanci', + 'Hillsdale', + 'Pao de Acucar', + 'Fuqing', + 'Oderzo', + 'Osterholz-Scharmbeck', + 'Saint-Maurice', + 'Puluvappatti', + 'Kabala', + 'Marchtrenk', + 'Lorch', + 'Kamtaul', + 'San Rafael Pie de la Cuesta', + 'La Puente', + 'San Andres', + 'Robore', + 'Baladharmaram', + 'Breza', + 'Rio del Mar', + 'Bocas del Toro', + 'Gorleston-on-Sea', + 'Fair Oaks', + 'Rapallo', + 'Villahermosa', + 'Kalappatti', + 'Wilmington Island', + 'San Francisco Menendez', + 'Champahati', + 'Baden', + 'Maxaranguape', + 'Macas', + 'Rio Tinto', + 'Ingre', + 'Teroual', + 'Nikki', + 'Bir Tam Tam', + 'Myrtle Grove', + 'Wuxi', + 'Si Mustapha', + 'Rundu', + 'Bar Bigha', + 'Iriba', + 'Jebba', + 'Mohanpur Gaughata', + 'Fetromby', + 'Halwara', + 'Carignano', + 'Eagan', + 'Bambari', + 'Lachhmipur', + 'Khemis Miliana', + 'Candeias', + 'Nioro du Rip', + 'San Andres de la Barca', + 'San Juan Nepomuceno', + 'Knightdale', + 'Marano Vicentino', + 'Cergy', + "Ping'anbao", + 'Zhovti Vody', + 'Saalfelden am Steinernen Meer', + 'Lubumbashi', + 'Oxkutzkab', + 'Conakry', + 'Puenteareas', + 'Gotsucho', + 'Sohna', + 'Morehead City', + 'Lingshou', + 'Antotohazo', + 'Ceadir-Lunga', + 'Apucarana', + 'Ihosy', + 'Oulad Barhil', + 'Turkoglu', + 'Progreso', + 'Oued el Aneb', + 'Kendall West', + 'Kignan', + 'Camborne', + 'Bagha Purana', + 'Meskiana', + 'Do Gonbadan', + 'Geesthacht', + 'Lodja', + 'Winterthur', + 'Taketa', + 'Maple Heights', + 'Kelangah', + 'Stary Sacz', + 'Chaplynka', + 'Carlos Chagas', + 'Metlaoui', + 'Ciudad de Huitzuco', + 'Ranod', + 'Clevelandia', + 'Alabat', + 'Belovodskoe', + 'Arriaga', + 'Sandy Hook', + 'Sainte-Agathe-des-Monts', + 'Guacara', + "Quan'ancun", + 'Arques', + 'Nenmem', + 'Gravatal', + 'Saidabad', + 'Kolasin', + 'Merritt Island', + 'Jieshou', + 'Hvalba', + 'Maglaj', + 'Favara', + 'Elk Grove Village', + 'Oppeano', + 'Budai', + 'Novi', + 'Tambe', + 'Balungao', + 'Bocaranga', + 'Pickering', + 'Turuttiyad', + 'Fihaonana', + 'Kidira', + 'Hopkins', + 'Vitoria-Gasteiz', + 'Harpur', + 'Sibundoy', + 'El Kouif', + 'Furth im Wald', + 'Vazhani', + 'Mississippi Mills', + 'Sayville', + 'Bhawanipur', + 'Bel Air', + 'Lishui', + 'Katuria', + 'Sepatan', + 'Uwchlan', + 'Vieste', + 'Pfullendorf', + 'Poggio Renatico', + 'Balha', + 'Brandywine', + 'Manville', + 'Sokcho', + 'Gaigirgordub', + 'Kadattur', + 'Munnelli', + 'San Pancrazio Salentino', + 'Kourani', + 'As Suwayrah', + 'Lubliniec', + 'Poytya', + 'Stezzano', + 'Novomoskovsk', + 'Conchal', + 'Sandona', + 'Nishitokyo', + 'Gardnerville Ranchos', + 'Nyiregyhaza', + 'Encheng', + 'Al Maraghah', + 'Willmar', + 'Sharg`un', + 'Kaiken', + 'Peravur', + 'Ikot Abasi', + 'Swift Current', + 'Oizumi', + 'Lieksa', + 'Tarare', + 'Marton', + 'Berilo', + 'Oldham', + 'Kuppadi', + 'Horodnia', + 'Ataco', + 'Nassjo', + 'Wednesfield', + 'Los Bellosos', + 'Mombaca', + 'Recife', + 'Dalupo', + 'Capitan Pablo Lagerenza', + 'Tsarabaria', + 'La Guaira', + 'Ain Fakroun', + 'Tsiatosika', + 'Melikgazi', + 'San Gabriel', + 'Shek Wai Kok', + 'Pati do Alferes', + 'Nueva Santa Rosa', + 'Gerasdorf bei Wien', + 'Sesheke', + 'Nueva Rosita', + 'Diamante', + 'Fyzabad', + 'Masinloc', + 'Bejofo', + 'Ayolas', + 'Eski Arab', + 'Kaihua', + 'Narlica', + 'Amaga', + 'Haaltert', + 'Inhapim', + 'Itacurubi de la Cordillera', + 'Rawatsar', + 'Kakhovka', + 'Virapandi', + 'Dasai', + 'Laukaa', + 'Uummannaq', + 'Florin', + 'Perampuzha', + 'Mercato San Severino', + 'Zografos', + 'Bukit Gambir', + 'Mericourt', + 'Tchibota', + 'Mantova', + 'Santa Cruz Amilpas', + 'Atarra', + 'Saint-Jean', + 'Mansong', + 'Barbacha', + 'Perondi', + 'Lavasan', + 'Poljcane', + 'Haedo', + 'Sumber', + 'Riedisheim', + 'Manvel', + 'Willenhall', + 'Green Cove Springs', + 'Covasna', + 'Zantiebougou', + 'Mityana', + 'Schiffweiler', + 'San Antonio Sacatepequez', + 'Kalas', + 'Recreo', + 'Bugiri', + 'Rentachintala', + 'Babhani Bholwa', + 'Sedgley', + 'Dimapur', + 'Elkhart', + 'Musoma', + 'Luneburg', + 'New Iberia', + 'Espera Feliz', + 'Catumbela', + 'Leyte', + 'Palkot', + 'San Cugat del Valles', + 'Briancon', + 'Ermita', + 'Kunnumel', + 'Rain', + 'Barretos', + 'Jbail', + 'Hadibu', + 'Nagalapuram', + 'Sibagat', + 'Chamalieres', + 'Minamishibetsucho', + 'Gedaref', + 'Mrirt', + 'Rasra', + 'Holbeach', + 'San Angelo', + 'Olawa', + 'Sroda Wielkopolska', + 'Sabalpur', + 'Ban Plai Bua Phatthana', + 'Homer Glen', + 'Esparza', + 'Media', + 'Fasintsara', + 'Atarfe', + 'Tyamagondal', + 'Panganiban', + 'Arao', + 'Campogalliano', + 'Port Dickson', + 'Iracemapolis', + 'Ahmadabad', + 'Kruje', + 'Gourcy', + 'Penn', + 'Lubartow', + 'Yigilca', + 'Tiwi', + 'Buffelshoek', + 'Camacari', + 'Kunitomi', + 'Druento', + 'Qarabalyq', + 'Reghaia', + 'Edavanakad', + 'Baden-Baden', + 'Seevetal', + 'Puerto Viejo', + 'Segarai', + 'Khadbari', + 'Zag', + 'Amta', + 'Biritinga', + "Hayma'", + 'Nebbi', + 'Malacky', + 'Bacolod', + 'Nkouraba', + 'Cuatro Cienegas de Carranza', + 'Barishal', + 'Lower', + 'Lam Luk Ka', + 'Petershagen', + 'Balham', + 'Titusville', + 'Vijes', + 'Harpur Bochaha', + 'Sido', + 'Sogam', + 'Victorias', + 'Khaira', + 'Capanema', + 'Slatina', + 'Hajduszoboszlo', + 'Kentau', + 'Ba', + 'Amagasaki', + 'Changzhi', + 'Orange Lake', + 'Montigny-en-Gohelle', + 'Gangaikondan', + 'Shibin al Kawm', + 'Kai', + 'Bayanhongor', + 'Erer Sata', + 'Hamamatsu', + 'Cedar Rapids', + 'Lubbeek', + 'Pingyi', + 'Reo', + 'Ban Chomphu Nuea', + 'Mundi', + 'Kantai', + 'Genoa', + 'Agadir', + 'Wawarsing', + 'Best', + 'Tanjore', + 'Tiete', + 'Pacajus', + 'Varzea Grande', + 'Inawashiro', + 'Sigmaringen', + 'Banjarmasin', + 'Punata', + 'Fairview Heights', + 'Embu', + 'Brea', + 'Mohacs', + 'Rosedale', + 'Hammam al `Alil', + 'Papireddippatti', + 'Beaumont-sur-Oise', + 'Makokou', + 'Eastchester', + 'Huntington', + 'Zarumilla', + 'San Sebastian de Buenavista', + 'Ouezzane', + 'Ambalarondra', + 'Waukegan', + 'San Pablo Huixtepec', + 'Kasangati', + 'Boanamary', + 'Nancy', + 'El Pueblito', + 'South Miami Heights', + 'Sayyid Sadiq', + 'Xghajra', + 'Bulacan', + 'Tanichchiyam', + 'Heilbron', + 'Sao Caetano de Odivelas', + 'Ayos', + 'Rawasari', + 'Herve', + 'Fairview Shores', + 'Naklo nad Notecia', + 'San Carlos', + 'Varazze', + 'Konak', + 'Kattakampala', + 'New Berlin', + 'Tuam', + 'Talaigua Nuevo', + 'Suchanino', + 'Alcobendas', + 'Mangalapuram', + 'Lombard', + 'Temacine', + 'Fancheng', + 'Norristown', + 'Kasrawad', + 'Memuro-minami', + 'Newman', + 'Kumamoto', + 'Shimizu', + 'Adrogue', + 'Belo Horizonte', + 'Kurtalan', + 'Gulf Shores', + 'Kenitra', + 'Esquipulas Palo Gordo', + 'Dursunbey', + 'Pazhayannur', + 'Little Elm', + 'Bassersdorf', + 'Sant Just Desvern', + 'Surir', + 'Goodlettsville', + 'Nanjo', + 'Al Jammaliyah', + 'Binyin', + 'Osterwieck', + 'Novoishimskiy', + 'Ananas', + 'Lower Moreland', + 'Gradsko', + 'Qiaotou', + 'Gole', + 'Marale', + 'Kantang', + 'Rajapur', + 'Boha', + 'Orbetello', + 'Suances', + 'Cheshunt', + 'Nagykallo', + "Bu'aale", + 'Chikitigarh', + 'Djenne', + 'Le Luc', + 'Sankeshwar', + 'Hrebinka', + 'Ronchin', + 'Pugo', + 'Putnam Valley', + 'Valka', + 'Sig', + 'Andernos-les-Bains', + 'Neuchatel', + 'Varginha', + 'Noventa Vicentina', + 'Athy', + 'Aradeo', + 'Cururupu', + 'Funza', + 'Alghero', + 'Termiz', + 'Rockwall', + 'Joliet', + 'Alatri', + 'Damarcherla', + 'Nako', + 'Muzaffarnagar', + 'Kazlu Ruda', + 'Urun-Islampur', + 'Thorpe Saint Andrew', + 'Baubau', + 'Felixstowe', + 'Mimata', + 'Babenhausen', + 'Valley Center', + 'Trabzon', + 'Ban Pak Phun', + 'Koudougou', + 'Wisbech', + 'Danvers', + 'Dhamnod', + 'Rudrur', + 'Nueva Italia de Ruiz', + 'Beacon', + 'Deerfield Beach', + 'Tinkhang', + 'Aiyomojok', + 'Gevas', + 'Salou', + 'Pontarlier', + 'Valluvandad', + 'Pingtouchuanxiang', + 'Takasagocho-takasemachi', + 'Marsaskala', + 'Zequ', + 'Sarapui', + 'Bhangha', + 'Saint Albans', + 'Fountain Hills', + 'Bultfontein', + 'Plant City', + 'Bidestan', + 'Alvorada', + 'Faenza', + 'Benyahia Abderrahmane', + 'Al Hindiyah', + 'Vohitromby', + 'Guadalupe Victoria', + 'Croissy-sur-Seine', + 'Agudo', + 'Carire', + 'Rho', + 'Gassino Torinese', + 'Uzice', + 'Magny-le-Hongre', + 'Bazimini', + 'New York', + 'Croata', + 'Shahgarh', + 'Nyzhnohirskyi', + 'St. Simons', + 'Fleury-les-Aubrais', + 'Paulino Neves', + 'Buderim', + 'Kapchagay', + 'Ahogbeya', + 'Warabi', + 'Sasagawa', + 'Edappalli', + 'Bobleshwar', + 'Sardinata', + 'Niederhasli', + 'Grez-Doiceau', + 'Crimmitschau', + 'Bound Brook', + 'Magog', + 'Pottstown', + 'Loveland', + 'Fort Mill', + 'Kpandu', + 'Ngoc Son', + 'San Agustin', + 'Turkeli', + 'Keynsham', + 'Padre Las Casas', + 'Huangzhai', + 'Acul du Nord', + 'Sha Tin', + 'Reddipalle', + 'Dalby', + 'Chigwell', + 'Chaigoubu', + 'Marolinta', + 'Tarma', + 'Schwabisch Gmund', + 'La Teste-de-Buch', + 'Bouna', + 'Creil', + 'Balatonalmadi', + 'Srivardhan', + 'Ettenheim', + 'Spanish Town', + 'Castellabate', + 'Salimpur', + 'Bhusaval', + 'Ayomi', + 'Babhniyawan', + 'Dundankop', + 'Khulna', + 'Incheon', + 'Prizren', + 'Yuvileine', + 'Taastrup', + 'Maibara', + 'Liberec', + 'Bordj Bou Arreridj', + 'Bueu', + 'Baba I', + 'Uttarkashi', + 'Karuizawa', + 'Ikast', + 'Tapolca', + 'Matrah', + 'Chakia', + 'Sosa', + 'Kabalo', + 'High River', + 'Chemnitz', + 'Mirganj', + "Mohale's Hoek", + 'Capena', + "Fanja'", + 'Idumbavanam', + 'Travagliato', + 'Noicattaro', + 'Lasht-e Nesha', + 'Bel Air North', + 'Missour', + 'Itaipe', + 'Sandpoint', + 'Villepinte', + 'Tendukheda', + 'Ljubovija', + 'Mount Pleasant', + 'Yucca Valley', + 'Lai Chau', + 'Litija', + 'Liberty Lake', + 'Kidamangalam', + 'Cambara', + 'Funchal', + 'Nansana', + 'Ongwediva', + 'Jamhra', + 'Gulbene', + 'Hot Springs Village', + 'Gothini', + "Douar 'Ayn Dfali", + 'Belsh', + 'Shimokodanaka', + 'Gerash', + "Welench'iti", + 'Pozorrubio', + 'Placer', + 'Streatham', + 'Muttalakanpatti', + 'Bougival', + 'Porteiras', + 'Liuguoju', + 'Sultanhani', + 'Dhutauli', + 'Jilin', + 'Dongsu', + 'Saho', + 'Santa Cecilia', + 'Jalor', + 'Kuruvambalam', + 'Maraba', + 'Yairipok', + 'Shafter', + 'Zabari', + 'Sauzal', + 'Barharwa', + 'Sisia', + 'Fabriano', + 'Buttar', + 'Corlu', + 'Kailashahar', + 'Mosina', + 'Novo Oriente', + 'Ploemeur', + 'Goshaingaon', + 'Amba Icharua', + 'Lehara', + 'eXobho', + 'Waldenbuch', + 'Marimba', + 'Kavundappadi', + 'Al Hudaydah', + "Castelnovo ne' Monti", + 'Ipuiuna', + 'Az Zawiyah', + 'Barros Blancos', + 'Royan', + 'Zaojiao', + 'Tiztoutine', + 'Tanashicho', + 'Ebbw Vale', + 'Swidnik', + 'Snohomish', + 'Melendugno', + 'Pavia', + 'Whitman', + 'Cuilo', + 'Russas', + 'Callao', + '`Izbat al Burj', + 'Lushoto', + 'Dayr al Barsha', + 'Pepinster', + 'Bustos', + 'Ureshinomachi-shimojuku', + 'Sabugal', + 'Forest City', + 'Afonso Bezerra', + 'Kaliganj', + 'Hato Mayor', + 'Kete Krachi', + 'Rasipuram', + 'Ennepetal', + "Cassano d'Adda", + 'Ronne', + 'Olpe', + 'Karlsruhe', + 'Janpur', + 'Wepener', + 'Happy Valley', + 'Bhadrakh', + 'Gaz', + 'Kayanza', + 'St. Ann', + 'Chitcani', + 'Tafrant', + 'Itabuna', + 'Iracoubo', + 'Mirzanagar', + 'Livry-Gargan', + 'Bequimao', + 'Dazhangzi', + 'Zhugang', + 'Waalre', + 'La Roda', + 'Kamthi', + 'Piggs Peak', + 'Mahadeopur', + 'Annakattumula', + 'Patterson', + 'Koriukivka', + 'Altenberge', + 'Rajula', + 'Hayden', + 'Yambio', + 'Saram', + 'Vereeniging', + 'Beauharnois', + 'La Ravoire', + 'Kulhudhuffushi', + 'Alatsinainy-Bakaro', + 'Nedugula', + 'Goaso', + 'Araucaria', + 'Fort Washington', + 'Sargur', + "Boula'wane", + 'Hussepur', + 'Frederick', + 'An Nimas', + 'Joao Pessoa', + 'La Eliana', + 'Samsun', + 'Bang Phlat', + 'Ketugram', + 'Dhobauli', + 'Bad Wildungen', + 'Estancia Pozo Colorado', + 'Roseller Lim', + 'Skarzysko-Kamienna', + 'Alba', + 'Sengurichchi', + 'Togitsu', + 'Chas', + 'Petlad', + 'El Rama', + 'Parkstone', + 'Lorca', + 'Western Bicutan', + 'Harare', + 'Fort Valley', + 'Staryy Beyneu', + 'Mainit', + 'Rosales', + 'Isafjordhur', + 'Moreau', + 'Kapra', + 'Tarascon', + 'Tubbergen', + 'Santa Comba Dao', + 'Fatikchari', + 'Sumy', + 'Ignacio de la Llave', + "Sant'Elpidio a Mare", + 'Pocono', + 'Kakogawacho-honmachi', + 'Guajara-Mirim', + 'Beekman', + 'Meymand', + 'University of Virginia', + 'Haines City', + 'Simao Dias', + 'Signal Hill', + 'Makedonski Brod', + 'Kamakurayama', + 'Blackpool', + 'Poxoreo', + 'Kohir', + 'Talata-Angavo', + 'Bielefeld', + 'Tomesti', + 'Universal City', + 'Kotka', + 'Uttukkottai', + 'Baruta', + 'Solana', + 'Ain Mediouna', + 'Garoowe', + 'Ap Tan Ngai', + 'Sarigol', + 'Muong Lay', + 'Guryongpo', + 'Moorestown', + 'Nottampatti', + 'Marienheide', + 'Tiruppur', + 'Bikkatti', + 'Fereydunshahr', + 'Ezhamkulam', + 'Ajax', + 'Buguda', + 'Shijiazhuang', + 'Pantanal', + 'Meylan', + 'Dobanovci', + 'Bizerte', + 'Gingin', + 'Baroni Khurd', + 'Cusseta', + 'Alhambra', + 'Chaoyang', + 'Wakema', + 'Holland', + 'Prunedale', + 'Akure', + 'Huautla', + 'Ghora Gali', + 'Ayase', + 'Ciudad de Loreto', + 'Bittou', + 'Andong', + 'Halluin', + 'Yuncos', + 'Eurajoki', + 'Morden', + 'Gueret', + 'Mutukula', + 'Abovyan', + 'Al Hufuf', + 'Tapaua', + 'Tegalbuleud', + 'Brackenheim', + 'Tanaina', + 'Siloam Springs', + 'Kuusankoski', + 'Concordia', + 'Parsippany', + 'Lapanga', + 'Manhuacu', + 'Extrema', + 'El Manteco', + 'Setti Fatma', + 'Guneysinir', + 'Sagara', + 'Kohima', + 'Guacheta', + 'Hidaj', + 'Gollalagunta', + 'Sawla', + 'Tamazouzt', + 'Qoryooley', + 'Constantine', + 'Boulsa', + 'Bhataulia', + 'Oued Athmenia', + 'Villa Ballester', + 'Leipzig', + 'Khewra', + 'Wondelgem', + 'Somanya', + 'Melissa', + 'Wangdue Phodrang', + 'Rietavas', + 'Kirkby in Ashfield', + 'Khadra', + 'Whitemarsh', + 'Palauig', + 'Aleg', + 'El Barrio de la Soledad', + 'Rosario Oeste', + 'Pappakudi', + 'Zorneding', + 'Grodzisk Mazowiecki', + 'Osowa', + 'Samayanallur', + 'Manampizha', + 'Bago', + 'Country Club', + "Lu'an", + 'Santa Teresinha (2)', + 'East Rockaway', + 'Minja', + 'Ilkhechi', + 'Moreno', + 'Novoazovsk', + 'Seondha', + 'Castleton', + 'Hannover', + 'Bhopal', + 'Barnoi', + 'Casaluce', + 'Hola', + "Trezzo sull'Adda", + 'Minxiong', + 'Eboli', + 'Bairiya', + 'Bad Waldsee', + 'Montagu', + 'Torres', + 'Pelitli', + 'Ararenda', + 'Coronel Fabriciano', + 'Monteria', + 'Kavlinge', + 'Grand Gosier', + 'Tidjikja', + 'Palayad', + 'Kattipudi', + 'Kibichuo', + 'Guoxing', + 'Viera West', + 'Aw Dheegle', + 'Ipanguacu', + 'Oued Fodda', + 'Yoju', + 'Leesburg', + 'Sathiala', + 'Senkaya', + 'Kucevo', + 'Mandal', + 'Dauis', + 'Oyon', + 'Kulmbach', + 'Macul', + 'Aysha', + 'Ash Shajarah', + 'Huishi', + 'Chiyoda-ku', + 'Ceccano', + 'Massenya', + 'Impasugong', + 'Champlin', + 'Saint Ives', + 'Sycamore', + 'Mahalgaon', + 'Yanqi', + 'Puren', + 'Koronadal', + 'Santa Catarina Ixtahuacan', + 'Dulmial', + 'Bourg-les-Valence', + 'Du Yar', + 'Marsa', + 'Bootle', + 'Swidnica', + 'Saint-Avold', + 'Goleta', + 'Peshkopi', + 'Ahenkro', + 'Fort Lewis', + 'Barra do Garcas', + 'Greytown', + 'Thouare-sur-Loire', + 'Abdul Hakim', + 'Pont-Sainte-Maxence', + 'Malindi', + 'Meridian', + 'Katsuyama', + 'Pigue', + 'Iradan', + 'Mukerian', + 'Yuzhang', + 'Quang Ngai', + 'Vila Nova de Gaia', + 'Tembagapura', + 'California City', + 'Dolores Hidalgo Cuna de la Independencia Nacional', + 'Guazacapan', + 'Tympaki', + 'Zhuozhou', + 'Tangub', + 'Gelemso', + 'Paal', + 'Hassi Berkane', + 'Plandiste', + 'Eduttavaynattam', + 'Alice', + 'Hannibal', + 'Novi Travnik', + 'Kairana', + 'Ilinden', + 'Mmabatho', + 'Hoyacho', + 'Menzel Bourguiba', + 'Tinsukia', + 'Medina del Campo', + 'Ramon', + 'Pierrefitte-sur-Seine', + 'Monroeville', + 'Randaberg', + 'Maple Shade', + 'Grottaglie', + 'Hisua', + 'Endicott', + 'Palagiano', + 'Martigues', + 'Huacho', + 'Wangtang', + 'Daiyue', + 'Chiguayante', + 'Einbeck', + 'Tezonapa', + 'Sousse', + 'Vikravandi', + 'Hellemmes-Lille', + 'Manampaneva', + 'Spresiano', + 'San Jose La Arada', + 'Salina Cruz', + 'Pindamonhangaba', + 'Bad Aibling', + 'Zhangjiazhuangcun', + 'Selestat', + 'Ascencion de Guarayos', + 'Hastinapur', + 'Xangda', + 'Trujillo Alto', + "Ji'an", + 'Dapaong', + 'Kernersville', + 'Conceicao do Coite', + 'Aguas Santas', + 'A Coruna', + 'Yanshanbu', + 'Boizenburg', + 'Zachary', + 'Lake Forest', + 'La Paz', + 'Malta', + 'Alfreton', + 'Halfeti', + 'Paracuru', + 'Valdivia', + 'Belen', + 'Cawayan', + 'Oda', + 'Ankililoaka', + 'Pondaluru', + 'Larkana', + 'Polaia Kalan', + 'Curua', + 'Hayashima', + 'Brigham City', + 'Beverungen', + 'Towcester', + 'Nove Zamky', + 'Palpa', + 'Gollapudi', + 'Gescher', + 'Camboriu', + 'El Plan', + 'Sokolo', + 'Titel', + 'Vallentuna', + 'Montreux', + 'Delmas', + 'Edirne', + 'Ngolonianasso', + 'Nsiika', + 'Rowlett', + 'Kuchlagh', + 'La Palma del Condado', + 'Senago', + 'Antanandava', + 'Steger', + 'Thatta', + 'Al Hamzah', + 'Krolevets', + 'Cabrera', + 'Baia-Sprie', + 'Santiago Suchilquitongo', + 'Aabenraa', + 'San Marco in Lamis', + 'Kota Bharu', + 'Guayabal', + 'Dasaut', + 'Kauhava', + 'Sabie', + 'Garrucha', + 'Maungdaw', + 'Kaduturutti', + 'Castenedolo', + 'Rio Rico', + 'Varese', + 'Chadchan', + 'Seoni Chhapara', + 'Rodeo', + 'Saint-Esteve', + 'Kierspe', + 'Velke Mezirici', + 'Khajuraho', + 'Thuin', + 'Douz', + 'Bac Lieu', + 'Differdange', + 'Imqabba', + 'Barao de Cocais', + 'Bijar', + 'Payerne', + 'Janakammapeta', + 'Takaishi', + 'Los Alamos', + 'Xianshuigu', + 'San Giuliano Terme', + 'Leigh', + 'Sinjar', + 'Chalastra', + 'Souakene', + 'Carmo do Cajuru', + 'Tirumangalam', + 'Nagardevla Budrukh', + 'Aqchah', + 'As Sars', + "'Ain el Assel", + 'Cusco', + 'Bacarra', + 'Maracacume', + 'Tanhuato de Guerrero', + 'Winston-Salem', + 'Fukuchiyama', + 'Grangemouth', + 'Olive Branch', + 'Zumpango del Rio', + 'Mardan', + 'Greenwood', + 'Torre de Moncorvo', + 'Nanthankulam', + 'Gadzin Han', + 'Manappakkam', + 'San Vicente Pacaya', + 'Suresnes', + 'Piraziz', + 'Anadia', + 'Valle Nacional', + 'Zhongdong Shequ', + 'Howick', + 'San Pedro de Uraba', + 'Konaje', + 'Rayappanpatti', + 'Nanuque', + 'Zhutailing', + 'Bovec', + 'Villa Riva', + 'Sanza Pombo', + 'Brossard', + 'Olbia', + 'Bredene', + 'Kaliro', + 'Joetsu', + 'Kruszwica', + 'Surajpura', + 'Primeira Cruz', + 'Hanumana', + 'Ghattupal', + 'Changamkari', + 'Bistrita', + 'Les Herbiers', + 'As Suqaylibiyah', + 'Quebec City', + 'Wiehl', + 'Waltrop', + 'Kadiana', + 'Tadapurambakkam', + 'Delportshoop', + 'Pinghu', + 'Bad Endorf', + 'Singarayakonda', + 'Prestwich', + 'Weesp', + 'Itamukkala', + 'Ad Dab`ah', + 'Salvador', + 'Weipa', + 'Agdam', + 'Tolu Viejo', + 'Erzincan', + 'Arfoud', + 'Giulianova', + 'El Paso de Robles', + 'Pedda Nindrakolanu', + 'Shawangunk', + 'Flamanzi', + 'Icod de los Vinos', + 'Vatananto', + 'Frattaminore', + 'Sterling Heights', + 'Zhongliao', + 'Tirmalgiri', + 'Deutsch-Wagram', + 'Peddaboddepalle', + 'Kilosa', + 'Gulbaar', + 'Malema', + 'Novo Horizonte', + 'Blairgowrie', + 'Nieder-Olm', + 'Pertuis', + 'Xacmaz', + 'Tenerife', + 'Krishnapuram', + 'Molndal', + 'Luba', + 'Puttalam', + 'Jegunovce', + 'Kauniainen', + 'Zapatoca', + 'Abong Mbang', + 'Tiana', + 'Ryki', + 'Mitai', + 'Mullingar', + 'Dom Pedro', + 'Simiti', + 'Naguilian', + 'Roccapiemonte', + 'Lanaken', + 'Svatove', + 'Salto del Guaira', + 'Liman', + 'Paisley', + 'Skwierzyna', + 'Balagtas', + 'Belma', + 'Olathe', + 'Kumil', + 'Hamworthy', + 'Solwezi', + 'Fucheng', + 'Lanivo', + 'Dao', + 'Putao', + 'Rafaela', + 'Yozgat', + 'Sao Joao da Boa Vista', + 'Sapanca', + 'Prebold', + 'Gwangyang', + 'Imerintsiatosika', + 'Munnalam', + 'Tizayuca', + 'Sorso', + 'Anah', + 'Locarno', + 'Wageningen', + 'Muhammadganj', + 'Binangonan', + 'San Gregorio de Nigua', + 'Oneonta', + 'Bole', + 'Mannara', + 'Darnah', + 'Habo', + 'Aubagne', + 'Pinili', + 'Ostuni', + 'Jitwarpur Chauth', + 'Mainaschaff', + 'Inderbor', + 'Westlake', + 'Esher', + 'Gaimersheim', + 'Fort Knox', + 'Tiruvambadi', + 'Towada', + 'Kasangulu', + 'Chernihiv', + 'Pardubice', + 'Ekibastuz', + 'Tramore', + 'Luchenza', + 'Asarganj', + 'Mascalucia', + 'Bartica', + 'Ipixuna', + 'Gainza', + 'Buea', + 'Puerto Concordia', + 'Mohammadabad', + 'Kindia', + 'Kadingilan', + 'Amboasary-Gara', + 'Kanchanadit', + 'Sabaneta', + 'Amingaon', + 'Los Polvorines', + 'Catano', + 'Alto Longa', + 'Zharkent', + 'Samba', + 'Hempstead', + 'Arandelovac', + 'Ghogha', + 'Cluses', + 'Kumarapalaiyam', + 'Warendorf', + 'Ath', + 'Thanh Xuan', + 'Esik', + 'Luneville', + 'Burgstadt', + 'Deggendorf', + 'Kozlu', + 'Abdullahnagar', + 'Penarroya-Pueblonuevo', + 'Curug', + 'Cosmopolis', + 'Schoningen', + 'Desri', + 'Tandubas', + 'Masiu', + 'Petawawa', + 'Buxerolles', + 'Wazirabad', + 'Wath upon Dearne', + 'Agios Athanasios', + 'Novi Marof', + 'Chotebor', + 'Ciudad General Belgrano', + 'Kitaibaraki', + "'s-Gravenzande", + 'Wellington North', + 'Jiuduhe', + 'Villingen-Schwenningen', + 'Stockbridge', + 'Wauconda', + 'Kayyngdy', + 'Sultandagi', + 'Torshavn', + 'Wadala Sandhuan', + 'Nordkirchen', + 'Nandikotkur', + 'Geisenheim', + 'Shirvan', + 'Port Victoria', + 'Santo Antonio de Jesus', + 'Matulji', + 'Bagaces', + 'Thisted', + 'Perur', + 'Coreau', + 'Chitose', + 'Marka', + 'Weener', + 'Barrinha', + 'Limburg', + 'Qazax', + 'Itapa-Ekiti', + 'Cajetina', + 'Bendougouba', + 'Buriti do Tocantins', + 'Uppur', + 'Hikari', + 'Parnarama', + 'Hammerfest', + 'Alcala la Real', + 'Deolali', + 'Arukutti', + 'Dar Si Aissa', + 'Ratia', + 'Gangaura Behra', + 'Mehdya', + 'Vagos', + 'Ramdeora', + 'Saint Helena Bay', + "'Ain Fekan", + 'Saint-Germain-les-Arpajon', + 'Farrukhabad', + 'Palmeiras', + 'Saint-Lo', + 'Marwa', + "Khmis Sidi al 'Aydi", + 'San Joaquin', + 'Koteshwar', + 'Pandalkudi', + 'Kukawa', + 'Lydney', + 'Kanchanpalli', + 'Chlef', + 'Moquegua', + 'Yanguancun', + 'Dalavaypattanam', + 'Gundlupet', + 'Sabinov', + 'Praia Grande', + 'Tamba-Sasayama', + 'Dachengzicun', + 'Biloziria', + 'Sanaur', + 'Rudehen', + 'Palmares', + 'Fairfax Station', + 'Bangor', + 'Mula', + 'North Chicago', + 'Koencho', + 'Mahibadhoo', + 'Vallejuelo', + 'Cajola', + 'Mvurwi', + 'Jinku', + 'Zgorzelec', + 'Barnstable', + 'San Ignacio de Velasco', + 'Fuquan', + 'Bayan Lepas', + 'Clovis', + 'Kappeln', + 'Ivaipora', + 'Piraquara', + 'Capul', + 'Sieradz', + 'Mombasa', + 'Bayawan', + 'Kahrizak', + 'Rohnert Park', + 'Ouzera', + 'Mampong', + 'Mezokovesd', + 'Briceni', + 'Pedara', + 'Koch Bihar', + 'Thaba Nchu', + 'Dehti', + 'Sebnitz', + 'Metz', + 'Mansa', + 'Sanwer', + 'Bingawan', + 'Vechur', + 'Kirkja', + 'Tororo', + 'Miandasht', + 'Peringom', + 'Nambutalai', + 'Zarafshon Shahri', + 'Deer Park', + 'Atalaia', + 'Congleton', + 'Srebrenik', + 'Rauch', + 'Slavuta', + 'Vengattur', + 'Bokoro', + 'Pureparo de Echaiz', + 'Osijek', + 'Divrigi', + 'East San Gabriel', + 'Gapan', + 'Comilla', + 'Ropar', + 'Oak Bay', + 'San Felipe', + 'Dinmanpur', + 'Konigslutter am Elm', + 'Nittenau', + 'Ardahan', + 'Kelaa Kebira', + 'Gulcho', + 'Sanzhou', + 'Albinea', + 'Acireale', + 'Wadegaon', + 'Australind', + 'Yaopu', + 'Ramnagar', + 'Tummalacheruvu', + 'Morretes', + 'Askoy', + 'Teziutlan', + 'Tupiza', + 'Monastir', + 'Dumri', + "Estrela d'Oeste", + 'Ribeirao Pires', + 'Holesov', + 'Ghatal', + 'Santa Maria Huatulco', + 'Vleuten', + 'Ambatomiady', + 'Isale', + 'Chalmette', + 'Tirukkoyilur', + 'Ishikari', + 'Lunglei', + 'Desuri', + 'Kaikoura', + 'Vaghodia', + 'Al Fayd', + 'Kahoku', + 'Bettendorf', + 'Palafolls', + 'Hadzici', + 'Jocoro', + 'Nanto', + 'Botelhos', + 'St. Clair Shores', + 'Rahon', + 'Monte Santo', + 'Watsonville', + 'Shankar Saraiya', + 'Zlin', + 'Maner', + 'Sauce', + 'Pudupattanam', + 'Midalt', + 'Jarinu', + 'Goma', + 'Laqtah', + 'Ghorbanki', + 'Nehoiu', + 'Comayaguela', + 'Sardhana', + 'Butiama', + 'Novo Hamburgo', + 'Isahaya', + 'Rouiba', + 'Minatitlan', + 'Devikolam', + 'Putatan', + 'Ala', + 'Sirsi', + 'Lawrence', + 'Sarapaka', + 'Turmalina', + 'Yaguara', + 'Tongjin', + 'Monte Alegre de Minas', + 'Nesher', + 'Morsand', + 'Rafsanjan', + 'Brisbane', + 'Rheinberg', + 'Assamannur', + 'Unterageri', + 'Sanquelim', + 'Steinhaus', + 'Banja Luka', + 'Guaimaro', + 'Luquembo', + 'Ambatomarina', + 'Kucove', + 'Thilogne', + 'Sangereng', + 'Beni Saf', + 'Itabela', + 'Woodfield', + 'Sandavagur', + 'Drobak', + 'Fuldabruck', + 'San Luis Obispo', + 'Chandralapadu', + 'Kanp', + 'Sainte-Sophie', + 'Karakopru', + 'Maple Grove', + 'Yachiyo', + 'Wuling', + 'Foammulah', + 'Mouvaux', + 'Gorizia', + 'Umarkot', + 'Forestdale', + 'Rawatbhata', + 'Bongaree', + 'Jalingo', + 'Koog aan de Zaan', + 'Lapy', + 'Rayleigh', + 'Khandsa', + "Fontaine-l'Eveque", + 'Den Helder', + 'Nanmucun', + 'Sakaraha', + 'Flixton', + 'Magenta', + 'Muroto-misakicho', + 'Panhar', + 'Ait Ourir', + 'Mawkanin', + 'Cheadle', + 'Kuusamo', + 'Velivennu', + 'Espoo', + 'Kakhandiki', + 'Kortenberg', + 'Krasnodon', + 'Hennigsdorf', + 'Olmos', + 'Maropaika', + 'Mahadipur', + 'Itatuba', + 'Uckfield', + 'Belle Glade', + 'Acatlan de Osorio', + 'Elfers', + 'Al Jumayl', + 'Hatsukaichi', + 'At Tall', + 'Uzynaghash', + 'Beatrice', + 'Frogn', + 'Yao', + 'Monfort Heights', + 'El Mansouria', + 'Sileby', + 'Emerald', + 'Alubijid', + 'Llanquihue', + 'Yerrapalem', + 'Tuguegarao', + 'Tiel', + 'Mahallat', + 'Varena', + 'Cherukunnu', + 'Lahat', + 'Nevsehir', + 'Suonan', + 'Cloncurry', + 'Chikhli Kalan', + 'Vedasandur', + 'Coyaima', + 'Yinajia', + 'Rewtith', + 'Villa Adelina', + 'Siur', + 'Urucania', + 'Petrinja', + 'Bruntal', + 'Wietmarschen', + 'Tumkur', + 'Qana', + 'Darlowo', + 'Qamdo', + 'Nova Gradiska', + 'Barhiya', + 'Balighattam', + 'St. Petersburg', + 'Paglat', + 'Nauhata', + 'Derdara', + 'Barai', + "King's Lynn", + 'San Pablo Tacachico', + 'Presidente Bernardes', + 'Elizabethton', + 'Ezhou', + 'Kallamalai', + 'Estrela', + 'Tuburan', + 'Solapuram', + 'Dohta', + 'Yazihan', + 'Monett', + 'Mayang Imphal', + 'Starse', + 'Chilon', + 'Libano', + 'Raneswar', + 'Raydah', + 'Tanjungpandan', + 'Puning', + 'Cabreuva', + 'Shoufeng', + 'Ipecaeta', + 'Lujan', + 'Sultanhisar', + 'Kaynarca', + 'Mwanza', + 'Newport', + 'Beypazari', + 'Ramshir', + 'Trakai', + 'Mohiuddinnagar', + 'Geddes', + 'Rinteln', + 'Nagarur', + 'Bagra', + 'Polkowice', + 'Ban Sathan', + 'Cotonou', + 'Trier', + 'Odenthal', + 'Oyim', + 'Tajarhi', + 'Birigui', + 'Moravske-Toplice', + 'Tatebayashi', + 'Serravalle Pistoiese', + 'Targuist', + 'Datu Paglas', + 'Aral', + 'Mazarron', + 'Dank', + 'Elk City', + 'Chandankiari', + 'Shatiancun', + 'Kakamas', + 'Sikat', + 'Bhawanandpur', + 'Stone Ridge', + 'Kushimoto', + 'Great Wyrley', + 'Tall Banat', + 'Yunfu', + 'Westville', + 'Karkamis', + 'Ingabu', + 'Rensselaer', + 'Tonbridge', + 'Phai Sali', + 'Vaiano', + 'Bikramganj', + 'Nawsari', + 'Akcaabat', + "Al Qa'im", + 'Carambei', + 'Boloso', + 'Shijiazhuangnan', + 'Sidi Lahsene', + 'River Edge', + 'Shuozhou', + 'Walnut Park', + 'Ben Chicao', + 'Eggenfelden', + 'Floriano', + 'Sevilimedu', + 'Vesoul', + 'Chinna Kalaiyamputtur', + 'Los Cordobas', + 'Malimono', + 'Eslamabad-e Gharb', + 'Akersberga', + 'Bhaktapur', + 'Tokha', + 'Egelsbach', + 'Windham', + 'Shantou', + 'Joyo', + 'Asni', + 'Camacan', + 'Lomas de Zamora', + 'Pedernales', + 'Presidente Medici', + 'Itabirito', + 'Heris', + 'Zarraga', + 'Korgas', + 'Horti', + 'Aksaray', + 'Ghal Kalan', + 'Apex', + 'Tummapala', + 'Vavveru', + 'Maumee', + 'Chicomba', + 'La Madeleine', + 'Mekra', + 'Mataquescuintla', + 'Sitio do Quinto', + 'Khanah Sur', + 'World Golf Village', + 'Mambore', + 'Limoux', + 'Hinode', + 'Spodnji Duplek', + 'Yancheng', + 'Patia', + 'Caiguantun', + 'Gualdo Tadino', + 'Fulshear', + 'Dacun', + 'Nawabshah', + 'Sannicolau Mare', + 'Zontecomatlan de Lopez y Fuentes', + 'Devanangurichchi', + 'Kovur', + 'Manikganj', + 'Qal`ah-ye Zal', + 'Schuttorf', + 'Fushun', + 'Tsuruno', + 'Sikhio', + 'Tomelloso', + 'Israin Kalan', + 'Dinajpur', + 'Douar Oulad Mbarek', + 'Afanyangan', + 'North Branch', + 'Pattukkottai', + 'Malo Crnice', + 'Taboao da Serra', + 'Kathurah', + 'Tottori', + 'Gundlapelle', + 'Dusseldorf', + 'Guisser', + 'Abuyog', + 'Sabalgarh', + 'Cabugao', + 'Pata Kalidindi', + 'Mountain Top', + 'Limonar', + 'Urupes', + 'Mudhol', + 'Peranampattu', + 'Deyr', + 'San Enrique', + 'Santa Lucia', + 'Ghoriyan', + 'Pervomaiskyi', + 'Obikiik', + 'Jauli', + 'Grevenbroich', + 'Chupaca', + 'Ban Bueng Kok', + 'Rada`', + 'Chapeltique', + 'Ghazipur', + 'Barcarena Nova', + 'Kayaralam', + 'Saint-Gilles', + 'Crosby', + 'Tatahuicapan', + 'Nedumangad', + 'Meitingen', + 'Matomou', + 'Balud', + 'Yatou', + 'Stephanskirchen', + 'Same', + 'Rome', + 'Oud-Heverlee', + 'Mau Dhaneshpur', + 'Sparks', + 'Kyotango', + 'Hirokawa', + 'Kahama', + 'General Emilio Aguinaldo', + 'Bozhou', + 'Areiopolis', + 'Izumisano', + 'Karmauli', + 'Itele', + 'Ghedi', + 'Champdani', + 'Ringas', + 'Istog', + 'Madre de Deus', + 'San Jose', + 'Duraiswamipuram', + 'Kele', + 'Andujar', + 'Erdemli', + 'Iwakuni', + 'Clarines', + 'Saint-Martin-de-Crau', + 'Kankipadu', + 'Bantayan', + 'Kilibo', + 'Kerpen', + 'Moultrie', + 'Belaur', + 'Juan Rodriguez Clara', + "P'yongch'ang", + 'Verukulambu', + 'Esenyurt', + 'Ban Muang Ngam', + 'Wako', + 'Yankou', + 'Radeberg', + 'Haddada', + 'Mill Creek East', + 'Szekesfehervar', + 'Lower Saucon', + 'Lijiacha', + 'Xushan', + 'Tumauini', + 'Molakalumuru', + 'Mayureswar', + 'Gnarrenburg', + 'Kefamenanu', + 'Lockhart', + 'Pulgaon', + 'El Palmar', + 'Champlain', + 'Adalpur', + 'Omboue', + 'Yueyaquan', + 'Melila', + 'Potomac Park', + 'Barranqueras', + 'Santa Cruz de la Sierra', + "Yan'an", + 'Talwara', + 'Kod', + 'Hechi', + 'Green Bay', + 'Murzuq', + 'Farnham', + 'Roznava', + 'Merate', + 'Nathana', + 'Malakwal', + 'Buhi', + 'Tadepallegudem', + 'Monastyryshche', + 'Sneek', + 'Gaoshu', + 'Pergine Valsugana', + 'Fond des Blancs', + 'College', + 'Liuliang', + 'Huilongcun', + 'Ballymena', + 'Fitampito', + 'Herzogenaurach', + 'Weilheim', + 'Melegnano', + 'Coribe', + 'Thondiamannu', + 'Bermejo', + 'Granville', + 'Retalhuleu', + 'Mayari', + 'Tall Qasab', + 'Bisaria', + 'Bellinzona', + 'Klodzko', + 'Dessalines', + 'Zamosc', + 'Village St. George', + 'Sturgis', + 'Sanyi', + 'Vennandur', + 'El Paso', + 'Andurkonam', + 'Zitsa', + 'Dainyor', + 'Kaysville', + 'Tijucas do Sul', + 'Cap-Haitien', + 'Linslade', + 'Banki', + 'Santo Antonio do Amparo', + 'Diapaga', + 'Buqda Caqable', + 'Cochabamba', + 'Irthlingborough', + 'Ena', + 'Donostia', + 'Dippoldiswalde', + 'Gisenyi', + 'As Sanamayn', + "Capo d'Orlando", + 'Bahcesaray', + 'Yamanouchi', + 'Balangkas', + 'Mihona', + 'Ambodimandresy', + 'El Mirage', + 'Gazojak', + 'Marvast', + 'Etzatlan', + 'Sicklerville', + 'Pocao', + 'Nicoadala', + 'Belo Campo', + 'Maina', + 'Piripiri', + 'Bani Hasan ash Shuruq', + 'McComb', + 'Southeast', + 'Cavriglia', + 'Kole', + 'Granger', + 'Rivera', + 'Ponferrada', + 'St. Anthony', + 'Queanbeyan', + 'Rangsdorf', + 'Rio Grande da Serra', + 'Carrieres-sur-Seine', + 'Brookhaven', + 'Lauderhill', + 'Puerto Jimenez', + 'Casas Adobes', + 'Aligudarz', + 'Buchireddipalem', + 'Mae Sai', + 'Guarai', + 'Sprimont', + 'Huizucar', + 'Teano', + 'Liria', + 'Zhemgang', + 'Funing', + 'Amorebieta', + 'Irece', + 'Bansang', + 'Shizukuishi', + 'Kummarapurugupalem', + 'Buzovna', + 'Vadakkumbagam', + 'Nago', + 'Toma', + 'Barra do Ribeiro', + 'Mentone', + 'Chorhat', + 'Norrkoping', + 'Hohoe', + 'Montefiascone', + 'Dario Meira', + 'Sopetran', + 'Dras', + 'Sadpur', + 'Miryang', + 'Jagoniguda', + 'Naklo', + 'Agcabadi', + 'Kermanshah', + 'Kauswagan', + 'Barah', + 'Araujos', + 'Herculandia', + 'Sironj', + 'Varazdin', + 'Macomb', + 'Corcoran', + 'Molfetta', + 'River Vale', + 'Ban Bang Krang', + 'Cutrofiano', + 'Muh Hasan', + 'Warnes', + 'Ottobeuren', + 'Pendencias', + 'Wood-Ridge', + 'Guttikonda', + "Saint John's", + 'White Marsh', + 'Vatomandry', + 'Shrirampur', + 'Ambahita', + 'Olean', + 'Hanno', + 'Jask', + 'Navelim', + 'Camalaniugan', + 'Boumahra Ahmed', + 'Porto Real do Colegio', + 'Geneseo', + 'Risod', + 'Rio Negro', + 'Kendu Bay', + 'Soro', + 'Etawah', + 'Khed Brahma', + 'Fukuyoshi', + 'Ikot Okoro', + 'Marahra', + 'Coimbra', + 'Svitavy', + 'Urdaneta', + 'Takhatgarh', + 'Khanjahanpur', + 'Chatelet', + 'Babile', + 'Budrio', + 'Samma', + 'Konigsbach-Stein', + 'Dobris', + 'Rheine', + 'Porkeri', + 'Menzel Abderhaman', + 'Jhonkar', + 'Torrance', + 'Ladan Kara', + 'Lealman', + 'Witzenhausen', + 'Ribeira do Pombal', + 'Madhopur', + 'Villarrica', + 'Makurdi', + 'Pleasanton', + 'Gullapuram', + 'Aboisso', + 'Gravatai', + 'Chinnamanur', + 'Longjia', + 'Chinna Orampadu', + 'Bangar', + 'Summerlin South', + 'Obiliq', + 'Kurate', + 'Wentzville', + 'Vallet', + 'Moalboal', + 'Ambohidrapeto', + 'Tecozautla', + 'Passagem Franca', + 'Armthorpe', + 'Kuchai Kot', + 'Lata', + 'Kashasha', + 'Auburndale', + 'Ban Tom Klang', + 'Shendurjana', + 'Chikushino', + 'Varandarapilli', + 'Highlands', + 'Harua', + 'Namaacha', + 'Presidente Dutra', + 'Ipu', + 'Bockhorn', + 'Davangere', + 'Saint-Michel-sur-Orge', + 'Crowley', + 'Tamganj', + 'Aklera', + 'Tiruppachur', + 'Candelaria de La Frontera', + 'Sidi Aoun', + 'Verrettes', + 'El Bolson', + 'Itamaraju', + 'Corbetta', + 'Borger', + 'Kodavatipudi', + 'Poisy', + 'Kakamigahara', + 'Petite Riviere de Nippes', + 'Hammanskraal', + 'Tonami', + 'Santa Maria Jalapa del Marques', + 'Los Palacios', + 'Rolim de Moura', + 'Ambahatrazo', + 'North Little Rock', + 'Cheyyar', + 'Masakkavundanchettipalaiyam', + 'Moorhead', + 'Khamir', + "L'Assomption", + 'Galliate', + 'Bad Zwischenahn', + 'Tiruvadi', + 'Ferreira do Zezere', + 'Brecht', + 'Mampikony', + 'La Pointe', + 'Ulipuram', + 'Rubizhne', + "Sant'Angelo in Lizzola", + 'Charkhari', + 'Atascocita', + 'Ternitz', + 'Olfen', + 'Hughenden', + 'Getulina', + 'Kewatgawan', + 'Konza', + 'Ocean', + 'Koziatyn', + 'Epanomi', + 'Mattul', + 'Meise', + 'Hazrat Shiura', + 'Plzen', + 'Tokunoshima', + 'Guelmim', + 'Targu Neamt', + 'Fugu', + 'Petroupoli', + 'Cueramaro', + 'Karaman', + 'Palmira', + 'Rajasur', + 'Calenzano', + 'Puerto Cabello', + 'Kaizu', + 'Pavullo nel Frignano', + 'Embalse', + 'Pocatello', + 'Milngavie', + 'Cachoeira de Minas', + 'Barra', + 'Savanette', + 'Surbo', + 'Ronda Alta', + 'Baghlia', + 'Chanasma', + 'Waterlooville', + 'Stord', + 'Kapiri Mposhi', + 'Plombieres', + 'Khutubi', + 'Pobe', + 'Trashi Yangtse', + 'Cranston', + 'Capinota', + 'Itambe', + 'Undi', + 'South Lyon', + 'St. George', + 'Anlu', + 'Anantavur', + 'Lake Arrowhead', + 'Kankuria', + 'Mellacheruvu', + 'Novy Bor', + 'Palacaguina', + 'La Corredoria', + 'Somerset', + 'Encrucijada', + 'Rampur Tilak', + 'Bay Point', + 'Changhua', + 'Ousseltia', + "Finch'a'a", + 'Ap Binh Thanh', + 'Coonoor', + 'Nachikatsuura', + 'Shanhur', + 'Proserpine', + 'Melavayi', + 'Celebration', + 'Chalkari', + 'Pedda Pendyala', + 'Aravakkurichchi', + 'Oranjemund', + 'Langfang', + 'Jinjiang', + 'Ziracuaretiro', + 'Misseni', + 'El Ayote', + 'Penamaluru', + 'Kadinamkulam', + 'Villa Hidalgo', + 'Hallandale Beach', + 'Periya Semur', + 'Ifakara', + 'Baucau', + 'Cesa', + 'Antiguo Cuscatlan', + 'Barnstaple', + 'Grottammare', + 'Rottenburg an der Laaber', + 'Befasy', + 'Nusaybin', + 'White Bear Lake', + 'Joaquin V. Gonzalez', + 'Dorval', + 'Raghopur', + 'La Garde', + 'Laukaha', + 'Chawalhati', + 'Burnham', + 'Padinska Skela', + 'Bilehra', + 'Rosemead', + 'Grafton', + 'Diemen', + 'Centre de Flacq', + 'Yomra', + 'Attanur', + 'Haspra', + 'Liquica', + 'Mala Vyska', + 'Sanger', + 'Ban Kat', + 'Miami', + 'Karmegh', + 'Montmelo', + 'Santa Cruz Verapaz', + 'Sao Gabriel', + 'Jose Marmol', + 'Wallisellen', + 'Izumiotsu', + 'Mashhad Rizeh', + 'Tiszafoldvar', + 'Limoges', + 'Kuzhippilli', + 'Vergara', + 'Bukavu', + 'Awasa', + 'Rusera', + 'Baragoi', + 'Coolidge', + 'Karjan', + 'Jagannathpur', + 'Somireddipalle', + 'Hamura', + 'Domchanch', + 'Salama', + 'Charmahin', + 'Ocotlan', + 'Cajidiocan', + 'Dembecha', + 'Great Sankey', + 'Katsepy', + 'Casteel', + 'Netapur Tanda', + 'Vangviang', + 'Lala Musa', + 'Treia', + 'Coon Rapids', + 'Jaromer', + 'Sociedad', + 'Ganda', + 'Belao', + 'Una', + 'Feijo', + 'Halen', + 'Courrieres', + 'Rendsburg', + 'Djangoa', + 'Gotse Delchev', + 'Pematangsiantar', + 'City of Isabela', + 'Traversetolo', + 'Sahuria', + 'Hardia', + 'Bhagwanpur Desua', + 'Karamay', + 'Dammennu', + 'Pedra Preta', + 'Zakiyah', + 'Wagner', + 'Naka', + 'Searcy', + 'Pak Chong', + 'Kreuzau', + 'Ammur', + 'Curimata', + 'Oued Lill', + 'Esplanada', + 'Dagana', + 'Villalba', + 'Qorovulbozor', + 'Mengdan', + 'Kenosha', + 'Lumbatan', + 'Beyla', + 'Billdal', + 'Barao do Grajau', + 'Antsatramidola', + 'Moirang', + 'Jalakati', + 'Sakhipur', + 'Tyler', + 'Gornji Milanovac', + 'Ootacamund', + 'Luruaco', + 'Cowra', + 'Jenison', + 'Dar`a', + 'Guamare', + 'Palatka', + 'Brooklyn Center', + 'Bondo', + 'Paracuellos de Jarama', + 'Troon', + 'Passy', + 'Laredo', + 'Rubim', + 'Brand-Erbisdorf', + 'Pofadder', + 'Itzehoe', + 'Yuyao', + 'Sao Carlos', + 'Jiangdi', + 'Avon', + 'Mission Viejo', + 'Mbaiki', + 'Kakan', + 'Aland', + 'Marlborough', + 'Mesetas', + 'Shahrinav', + 'Kourou', + 'Kobilje', + 'Kragujevac', + 'Corigliano Calabro', + 'Jalpan', + 'Kongoussi', + 'Sursand', + 'Jiangjiadong', + 'Ja`fariyeh', + 'Fulham', + 'Jhabrera', + 'Tumberi', + 'Masunga', + 'Schellenberg', + 'Binfield', + 'Jose C. Paz', + 'Padre Garcia', + 'Tillor Khurd', + 'Alta Gracia', + 'Subotica', + 'Zaandijk', + 'Ochsenfurt', + 'Cholpon-Ata', + 'Veinticinco de Diciembre', + 'Shuangtian', + 'Madalum', + 'Dianguirde', + 'Pitangui', + 'Patacamaya', + 'Kosvik', + 'Xiba', + 'Debagram', + 'Ban Na Kham', + 'Sao Francisco do Conde', + 'Stegen', + 'Bulalacao', + 'Pala Oua', + 'Pak Kret', + 'Mundahal Khurd', + 'Befotaka', + 'Gobindpura', + 'Al Aaroui', + 'Mwenga', + 'Caturama', + 'Pelengana', + 'Kandel', + 'Vila Real', + 'Bechloul', + 'Nykobing Falster', + 'Mazabuka', + 'Binka', + 'Konongo', + 'Wrzesnia', + 'Vasiana', + 'Khan Shaykhun', + 'Tolna', + 'Piedrahita', + 'Wilsele', + 'Ye', + 'Acucena', + 'Ames', + 'Ventnor City', + 'Elhovo', + 'Bajiao', + 'Torreon', + 'Lana', + 'Herrenberg', + 'Pira', + 'Pascagoula', + 'Takeo', + 'Nuevitas', + 'Foothill Farms', + 'Mogotes', + 'Los Palacios y Villafranca', + 'Tanuku', + 'Oroszlany', + 'Sanyo-Onoda', + 'Eichenau', + 'Sundapalaiyam', + 'Kanoni', + 'Dioungani', + 'Evora', + 'Funtua', + 'Kawkareik', + 'Coffs Harbour', + 'Villiers', + 'Caldiran', + 'Palakkuzhi', + 'Sassenburg', + 'Oravita', + 'Liaojiayuan', + 'Nisshin', + 'Sirkhandi Bhitha', + 'Union de Tula', + 'Chitila', + 'Montecito', + 'Bozuyuk', + 'Sahiwal', + 'Nidamangalam', + 'Beixingzhuang', + 'Alaminos', + 'Kobiri', + 'Drawsko Pomorskie', + 'Manassas Park', + 'Nu`ayjah', + 'Ndjili', + 'Hamidiyeh', + 'Pleiku', + 'Candon', + 'Samokov', + 'La Belleza', + 'Kargil', + 'Barugo', + 'Leichlingen', + 'Rizal', + 'Chhabila', + 'Sinanpasa', + 'Kabudarahang', + 'Yonghetun', + 'Selden', + 'Longchuan', + 'Guanduqiao', + 'Tinnanur', + 'Mandsaur', + 'Joso', + 'Besarh', + 'Decin', + 'Kut Chap', + 'Botolan', + 'Grad', + 'Dumaguete City', + 'Mimoso do Sul', + 'Tello', + 'Iwate', + 'Pordenone', + 'Naihati', + 'Painesville', + 'Alatsinainy Ialamarina', + 'Rinopolis', + 'Mut', + 'Shirahama', + 'Port Alfred', + 'Nantan', + 'Catuipe', + 'Isola Vicentina', + 'Barahkurwa', + 'Kladno', + 'Biritiba-Mirim', + 'Southwater', + 'Kariya', + 'Kearney', + 'Botosani', + 'Queen Creek', + 'Tamanique', + 'Putla Villa de Guerrero', + 'Visbek', + 'Apac', + 'Grossbeeren', + 'Chislehurst', + 'Esposende', + 'Winnipeg', + 'Thermi', + 'Mahires', + 'Neshannock', + 'Clearwater', + 'Tallinn', + 'Manegaon', + 'Nabua', + 'Baxter', + 'Arlington Heights', + 'Manafwa', + 'Groenlo', + 'Ngerengere', + 'Lakato', + 'Corner Brook', + 'Palakodu', + 'San Pietro Vernotico', + 'Arouca', + 'Bad Nenndorf', + 'Ban Nong Hoi', + 'Grand Island', + 'Perris', + 'Long My', + 'Contai', + 'Berlare', + 'Hlinsko', + 'Oum Hadjer', + 'Kusatsu', + 'Kamudi', + "N'Zerekore", + 'Minoo', + 'Moulares', + 'Taybad', + 'Nayanagar', + 'Barberena', + 'Oromocto', + 'Phirangipuram', + 'Neosho', + 'Leno', + 'Fakirtaki', + 'Noto', + 'Phulpur', + 'Karahal', + 'Alur', + 'Garcia Hernandez', + 'Zawodzie', + 'Gararu', + 'Wallsend', + 'Debre Birhan', + 'Bargaon', + 'Washougal', + 'Wutong', + 'Kajha', + 'Tamilisan', + 'Ambohimasina', + 'Abha', + 'Holguin', + 'Epe', + 'Owen Sound', + 'Essen', + 'Sermadevi', + 'Naga', + 'Kanjikkovil', + 'Maracai', + 'Kyongju', + 'Oulad Friha', + 'Camp Pendleton South', + 'Govindapuram', + 'Sligo', + 'Cubal', + 'Mamuju', + 'Talca', + 'Carcagente', + 'Bagepalli', + 'Liuba', + 'Nao-Me-Toque', + 'Punitaqui', + 'Saint-Pierre-du-Perray', + 'Manila', + 'Alkmaar', + 'Providence', + 'Xinguara', + 'Jangaon', + 'Ibimirim', + 'McAlester', + 'Saalfeld', + 'Palladam', + 'Yacuanquer', + 'Port Denison', + 'Mama Khel', + 'Stabroek', + 'Lake Arbor', + 'Killingworth', + 'Ouled Chebel', + 'Utnur', + 'Kandangan', + 'Soest', + 'Tbeng Meanchey', + 'Haoping', + 'Sater', + 'West Bromwich', + 'Mandiraja Kulon', + 'Karczew', + 'Krems an der Donau', + 'Osako', + 'Budwan', + 'Scalea', + 'Gersthofen', + 'Shiloh', + 'Kopargo', + 'Trotwood', + 'Teltow', + 'Annonay', + 'Makwassie', + 'Ouled Rached', + 'Rankweil', + 'Farmington Hills', + 'Mbini', + 'Horice', + 'Jacqueville', + 'Banbishancun', + 'Tamanar', + 'Konidena', + 'Hengzhou', + 'Liverpool', + 'Marofototra', + 'Cheruvannur', + 'Iormughanlo', + 'Tomar', + 'Si Satchanalai', + 'Guiseley', + 'Bicske', + 'Richland', + 'Elizabeth', + 'Linares', + 'Narbonne', + 'Agua Azul do Norte', + 'Crateus', + 'Luton', + 'Bardstown', + 'Amiawar', + 'Dulhanganj', + 'Senanga', + 'Kobylka', + 'Imlil', + 'St. Catharines', + 'Laziska Gorne', + 'An Cabhan', + 'Tarbes', + 'Leutenbach', + 'Frederiksvaerk', + 'Sechura', + 'Geldermalsen', + 'Krishnarajasagara', + 'Catarroja', + 'Dugo Selo', + 'Brieselang', + 'Kosum Phisai', + 'East Fishkill', + 'Sendhwa', + 'Ampasinambo', + 'Urbano Santos', + 'Myaydo', + 'Premnagar', + 'Andovoranto', + 'Yaraka', + 'Fuller Heights', + 'Tarqui', + 'Struer', + 'Chintalapalle', + 'Boali', + 'Keswick', + 'Deal', + 'Tayasan', + 'Sakha', + 'Vandalur', + 'Somma Vesuviana', + 'Almaguer', + 'Jacksonville Beach', + 'Yuxi', + 'Torhout', + 'Buqkoosaar', + "O'Hara", + 'Dortmund', + 'Freeport City', + 'Poptun', + 'Upper Grand Lagoon', + 'Shendi', + 'Cuautitlan Izcalli', + 'Blagnac', + 'Letpandan', + 'Bhachhi', + 'Dunavarsany', + 'Lessogou', + 'Elze', + 'Clare', + 'Harvey', + 'Ain Feka', + 'Wayne', + 'Pohang', + 'Pothia', + 'Pokhraira', + 'Pontalina', + 'Amatura', + 'Sao Joao das Lampas', + 'Pinan', + 'Sidi Lakhdar', + 'Badami', + 'Matadepera', + "Sant'Agata di Militello", + 'Laiyang', + 'Selmana', + 'Rothwell', + 'Kamareddipet', + 'Hobe Sound', + 'Mong Tun', + 'Armur', + 'Islampur', + 'Wadgassen', + 'Selma', + 'Momanpet', + 'Aktepe', + 'Mjolby', + 'Patchogue', + 'Nueva Loja', + 'Kronjo', + 'Turuvekere', + 'Tejupilco', + 'Vetraz-Monthoux', + 'Rickmansworth', + 'Cicuco', + 'Chandigarh', + 'Winslow', + 'Amtala', + 'Waingapu', + 'Mayuge', + 'Ruse', + 'Sindangan', + 'Xankandi', + 'Al Qutayfah', + 'Llorente', + 'Naliya', + "Az Zarqa'", + 'Bomporto', + 'Wadern', + 'Cegled', + 'Jalapa', + 'Shizhaobi', + 'Union de Reyes', + 'Nahargarh', + 'Massapequa Park', + 'Kalvarija', + 'Portes-les-Valence', + 'Sidi ech Chahmi', + 'Hope', + 'Cumbal', + 'Soalkuchi', + 'Modling', + 'Khujner', + 'Biederitz', + 'Laval', + 'Mikkeli', + 'Otopeni', + 'Qashyr', + 'Noisy-le-Grand', + 'Titao', + 'Koga', + 'Tipasa', + 'Bukoba', + 'Pruszcz Gdanski', + 'Tachiarai', + 'Na Yung', + 'Oignies', + 'Fillmore', + 'Tachilek', + 'Lathrop', + 'Binalbagan', + 'Kallidaikurichi', + 'Leova', + 'Adazi', + 'Caibarien', + 'El Obeid', + 'Pareo', + 'Whitstable', + 'Raymond', + 'Centenario', + 'Zhangziying', + 'Satyavedu', + 'Uspantan', + 'Castelli', + 'Zuitou', + 'Chiradzulu', + 'Tadif', + 'Stains', + 'Mathba', + 'St. Clair', + 'Beni Ounif', + 'Aripuana', + 'Cumana', + 'Bhui', + 'Jeddah', + 'Settara', + 'San Andres de Llevaneras', + 'Fermo', + 'Kinross', + 'Sanjiaocheng', + 'Serrita', + 'Analapatsy', + 'La Bruyere', + 'Bac Giang', + 'Manticao', + 'Jaen', + 'Uzumlu', + 'Pauri', + 'Fernandina Beach', + 'Mullaittivu', + 'Fairfield Glade', + 'Dougouni', + 'Shuangyashan', + 'Ashford', + 'Dalan', + 'Longchamps', + 'Berat', + 'Mirangaba', + 'Bhagta', + 'Bodmin', + 'Wittenbach', + 'Capriolo', + 'Plock', + 'Petropolis', + 'Nimmekal', + 'Eisenberg', + 'Minakshipuram', + 'Fox Lake', + 'Simunul', + 'Zhangatas', + 'Besikduzu', + 'Diepenbeek', + 'Castalla', + 'Nakaseke', + 'Daimiel', + 'Aguascalientes', + 'Bluefields', + 'Weinheim', + 'Khirhar', + 'Vilkaviskis', + 'Gorha', + 'Condeixa-a-Nova', + 'Shikokuchuo', + 'Maghar', + 'Khutha Baijnath', + 'Kathmandu', + 'Tornesch', + 'Isernia', + 'Koriapatti', + 'Tharike', + 'Hastings', + 'Pindra', + 'Eislingen', + 'Bridgetown', + 'Salt Lake City', + 'Kashti', + 'Hulyaypole', + 'Sexmoan', + 'Shrewsbury', + 'Tha Yang', + 'Waghai', + 'Scone', + 'Ritto', + 'Sukrah', + 'Strausberg', + 'Kurhani', + 'Nesarg', + 'Ciudad Constitucion', + 'Francavilla Fontana', + 'Langenselbold', + 'Soklogbo', + 'Deinze', + 'Zaanstad', + 'Lafia', + 'Prosperidad', + 'Rumuruti', + 'Savigliano', + 'Hundested', + 'Neuhausen auf den Fildern', + 'Chitre', + 'Sarrebourg', + 'Ayanikkad', + 'Dapoli', + 'Centerton', + 'Plettenberg', + 'Skocjan', + 'Oamishirasato', + 'Penticton', + 'Aurillac', + 'Red Hook', + 'Kiel', + 'Mannadipattu', + 'Ronchi dei Legionari', + 'Az Zuwaytinah', + 'Ulverston', + 'Tholikuzhi', + 'Phrai Bueng', + 'St. Paul', + 'Shenley Church End', + 'Gourrama', + 'Itiuba', + 'Bena', + 'Partinico', + 'Fort Thomas', + 'Marasesti', + "Monte Sant'Angelo", + 'Lubbecke', + 'Grande-Synthe', + 'Jincheng', + 'Monteros', + 'Randburg', + 'Shakopee', + 'Escuque', + 'Bauko', + 'Muscatine', + 'Ralla', + 'Usuppur', + 'Iwaki', + 'Compton', + 'Isna', + 'Suhbaatar', + 'Igboho', + 'San Rafael Cedros', + 'Lapua', + 'Zdzieszowice', + 'Arcadia', + 'Orotina', + 'Bogande', + 'Alpignano', + 'Highland Park', + 'Newberg', + 'Veles', + 'Scituate', + 'Bellatti', + 'Tempio Pausania', + 'Buri Ram', + 'Marquette', + 'Niquinohomo', + 'Cuddalore', + 'Waimalu', + 'Potiskum', + 'Mohammedia', + 'Bamiantong', + 'La Trinitaria', + 'Bekes', + 'Cajabamba', + 'Conyers', + 'Malungun', + 'Takehara', + 'Aspen Hill', + 'Suzuka', + 'Ait Youssef Ou Ali', + 'Klaipeda', + 'Churriana de la Vega', + 'Malpura', + 'Romano di Lombardia', + 'Jose de Freitas', + 'Soc Trang', + 'Brahmadesam', + 'Chalons-en-Champagne', + 'Guria', + 'Talwandi Sabo', + 'Makhmur', + 'Podvelka', + 'Satghara', + 'Chimteppa', + 'Yaypan', + 'Kearsley', + 'Qianwangcun', + 'Suratgarh', + 'Santa Helena de Goias', + 'San Andres Itzapa', + 'Zulakallu', + 'Pinos Puente', + 'El Carmen de Bolivar', + 'Nahiyat al Iskandariyah', + 'Kasterlee', + 'Cabries', + 'Dakhan', + 'Senguio', + 'Lachute', + 'Bni Quolla', + 'Indanan', + 'Spennymoor', + 'Pottireddippatti', + 'Chaville', + 'Goto', + 'Somoto', + 'Antaritarika', + 'Chikkala', + 'Maheswa', + 'Schmallenberg', + 'Itajuba', + 'Udarband', + 'Itanhaem', + 'Sandiacre', + 'Castlegar', + 'Maler Kotla', + 'Kuressaare', + 'Huangxicun', + 'Sand', + 'Farrokh Shahr', + 'Valandovo', + 'Madakkathara', + 'Kaurihar', + 'Santa Lucia La Reforma', + 'Gjirokaster', + 'Indore', + 'Thorigne-Fouillard', + 'Fiorano Modenese', + 'Drexel Hill', + 'Ash Shamiyah', + 'Baia Farta', + 'Chakdaha', + 'Dambulla', + 'Muttukuru', + 'Chiesanuova', + 'Mehran', + 'Metkovic', + 'Portomaggiore', + 'Spokane', + 'Oldbury', + 'Vilattikulam', + 'Nasushiobara', + 'San Martin de Loba', + 'Campo Largo', + 'Yenakiieve', + 'Uropa', + 'Kaleybar', + 'Mit Salsil', + 'Hedehusene', + 'Gross-Enzersdorf', + 'Germiston', + 'Qal`eh Chan`an', + 'Rocky Point', + 'Cingoli', + 'Garden Grove', + 'Ouro Preto', + 'Mead Valley', + 'Liwonde', + 'Kokologo', + 'Monona', + 'Funato', + 'College Park', + 'Tighedouine', + 'Peringottukurusshi', + 'Ankilimivory', + 'Tabina', + 'Bahagalpur', + 'Huelva', + 'Musashino', + 'Igapora', + 'San Antonio Huista', + 'Cristais', + 'Rajkot', + 'Hasseh', + 'Wyckoff', + 'Rukungiri', + 'Rio Pomba', + 'Morteros', + 'Camillus', + 'Cholai', + 'Alto Rio Doce', + 'Imperatriz', + 'Ross on Wye', + 'Gairtganj', + 'Sakubva', + 'Porsgrunn', + 'Oss', + 'Dickson', + 'Famailla', + 'Napak', + 'La Tebaida', + 'Dhaka', + 'Pulicat', + 'Dayr Mawas', + 'Rampur Kudarkatti', + 'La Rochelle', + 'Cowansville', + 'Van Buren', + 'Montevideo', + "Sant'Antimo", + 'IJmuiden', + 'Urtaowul', + 'Chtiba', + 'Bavanat', + 'Mooresville', + 'Longbangcun', + 'Marawi', + 'Meppel', + 'Ha Long', + 'Matsubushi', + 'Massakory', + 'Jamsaut', + 'Uzungoz', + 'Phatthaya', + 'Glew', + 'Gavimane', + 'Ionia', + 'Hackney', + 'Shanshan', + 'Chilanga', + 'Puerto El Triunfo', + 'Egg Buckland', + 'Ladner', + 'Chapadinha', + 'Mangualde', + 'Aisai', + 'Itamati', + 'Kunkalagunta', + 'Yucheng', + 'Ozhur', + 'Volochysk', + 'Garliava', + 'Ananindeua', + 'Naugatuck', + 'Toronto', + 'Daoukro', + 'Isperih', + 'Sebaco', + 'Apizaco', + 'Curepto', + 'Phimai', + 'Melzo', + 'Edd', + 'Santo Agostinho', + 'Chystiakove', + 'Kobilo', + 'Rafai', + 'Potchefstroom', + 'Ban Bang Sai', + 'Makato', + 'Mairinque', + 'Suwalki', + 'Vinh Yen', + 'Odobesti', + 'Rogerstone', + 'Campos Belos', + 'Nanguneri', + 'Ban Mon Pin', + 'Bududa', + 'Devikapuram', + 'Pietrasanta', + 'Lienen', + 'Ma`arrat an Nu`man', + 'Jicome', + 'Bockenem', + 'Bossembele', + 'Dongchuan', + 'Tepetlan', + 'Piddig', + 'Cheektowaga', + 'Vohipeno', + 'Soubala', + 'Xalapa', + 'Peru', + 'Middlesborough', + 'Oral', + 'Villa Celina', + 'Bacacay', + 'Gangapur', + 'Loyola Heights', + 'South Riding', + 'Gurupi', + 'Galapa', + 'Bagor', + 'Chitemo', + 'Birnin Kebbi', + 'Tagajo', + 'Maychew', + 'Worms', + 'Tesanj', + 'South El Monte', + 'Kitcharao', + 'Shorewood', + 'Agen', + 'Kargi', + 'Oppicherla', + 'Van', + 'Port Augusta', + 'Ahlen', + 'Moudjbara', + 'Ghaxaq', + 'El Arrouch', + 'Carson', + 'Kitatajima', + 'Kamp-Lintfort', + 'Kachhari', + 'Fort Myers', + 'Imbituva', + 'North Charleston', + 'Unterfohring', + 'Triangle', + 'Tuntum', + 'Dollard-des-Ormeaux', + 'Eschweiler', + 'Pomorie', + 'Xewkija', + 'Buenavista', + 'Arsanjan', + 'Demnat', + 'Saharefo', + 'Maragogi', + 'Odivelas', + 'Villaviciosa de Odon', + 'Keszthely', + 'Alcantarilla', + 'Loutraki', + 'Falou', + 'Linfen', + 'Azamnagar', + 'Karvina', + 'Shady Hills', + 'Chopda', + 'Vredefort', + 'Westmont', + 'Ulaanbaatar', + 'Southbridge', + 'North Druid Hills', + 'Viseu', + 'Le Thor', + 'Tacaratu', + 'Elur', + 'Motupe', + 'Trim', + 'Chorzow', + 'Kelle', + 'Ljutomer', + 'Kanbara', + 'Maroviro', + 'Zapotitlan', + 'Forlimpopoli', + 'Dhuusamarreeb', + 'Bakwa-Kalonji', + 'Bakeshiyingcun', + 'Ngoulemakong', + 'Nor Hachn', + 'Ejmiatsin', + 'Handlova', + 'Pillaiyarkuppam', + 'Miramar', + 'Nanyo', + 'Northampton', + 'Heerenveen', + 'Doiwala', + 'Engenheiro Caldas', + 'Undrajavaram', + 'Mahudha', + 'Ashtead', + 'Kotagiri', + 'Nieuw Amsterdam', + 'Hamakita', + 'Ipueiras', + 'Mannargudi', + 'Ramsey', + 'La Mata', + 'Strabane', + 'Meaford', + 'Truseni', + 'Kanhangad', + 'Matanga', + 'Seohara', + 'Hijuelas', + 'Narvik', + 'Alamada', + 'Moslem Ebn-e `Aqil', + 'Kabasalan', + 'Mataram', + 'Jagodina', + 'Zifta', + 'Jambughoda', + 'Ledeberg', + 'Melonguane', + 'Okuizumo', + 'Petion-Ville', + 'Coweta', + 'Chiniot', + 'Ntara', + 'Munuf', + 'West Falls Church', + 'Kanchanaburi', + 'Nahiyat al Kifl', + 'Aqsu', + 'Ghaziabad', + 'Katpadi', + 'Midalam', + 'Omegna', + 'Noci', + 'Taniyama-chuo', + 'Patrocinio Paulista', + 'Merseburg', + 'Nashua', + 'Lamut', + 'Ankang', + 'Ahor', + 'Edakkunnam', + 'South Shields', + 'Liangwu', + 'Sonbari', + 'Shinjo', + 'Patuvilayi', + 'Ponte de Sor', + 'Kawamata', + 'Ulvila', + 'Polomolok', + 'Saila', + 'Mahaiza', + 'El Trebol', + 'Cisterniga', + 'Fossombrone', + 'Nyala', + 'Villa Gesell', + 'Lapa', + 'Nidamaluru', + 'Peraiyur', + 'Dodarasinakere', + 'Pachino', + 'Saint-Etienne-du-Rouvray', + 'Gilching', + 'Laurentian Valley', + 'Garhshankar', + 'Lambesc', + 'Hanamaki Onsen', + 'Seagoville', + 'Rheda-Wiedenbruck', + 'Sutton Coldfield', + 'Safaja', + 'Enns', + 'Mutki', + 'Villa de Leyva', + 'Chauk', + 'Aadorf', + 'Lukow', + 'Yuanquan', + 'Muniz', + 'Maxixe', + 'Soquel', + 'Hillcrest Heights', + 'Mancheral', + 'Featherstone', + 'Chelak', + 'Tondela', + 'Hostomel', + 'Alfonsine', + 'Iskilip', + 'Jaciara', + 'Gidri', + 'Tulare', + 'Mushabani', + 'Patharia', + 'Coudekerque-Branche', + 'Bastos', + 'San Antonio Abad', + 'Eagle Point', + 'Fernando de la Mora', + 'Mhajar', + 'Longhua', + 'Sevnica', + 'Karian', + 'Narsipatnam', + 'Nuuk', + 'Mount Juliet', + 'Tome-Acu', + 'Ferozepore', + 'Sirakoro', + 'Barra Velha', + 'Zabok', + 'Azandarian', + 'Conewago', + 'El Gara', + 'Mamungan', + 'Livorno', + 'Ain Zaouia', + 'Ilamatlan', + "Anse d'Hainault", + 'Voloina', + 'Itaitinga', + 'Odatturai', + 'Vedaranniyam', + 'Bretzfeld', + 'Lom Sak', + 'Yingyangcun', + 'Manamodu', + 'Cerqueira Cesar', + 'Sorgun', + 'Ban', + 'Oyrarbakki', + 'Mandaguacu', + "Sered'", + 'Ringkobing', + 'Kalihati', + 'Modi`in Makkabbim Re`ut', + 'Malverne', + 'Copenhagen', + "L'Ancienne-Lorette", + 'Dagenham', + 'Marovandrika', + 'Nossa Senhora dos Milagres', + 'Sacueni', + 'Santa Maria a Monte', + 'Souq Jamaa Fdalate', + 'Chinguar', + 'Swiedbodzin', + 'Mangalme', + 'San Anselmo', + 'Ban Patong', + 'Bazar-e Yakawlang', + 'Teresopolis', + 'Baliangao', + 'Hunsur', + 'Idigny', + 'Kose', + 'Pedra Azul', + 'Mount Vernon', + 'Uzun', + 'Hamadanak', + 'As', + 'Tounfit', + 'Blumberg', + 'Konstancin-Jeziorna', + 'Ebino', + 'Hull', + 'Tajumulco', + 'Castellaneta', + 'Sidhapa', + 'Slagelse', + 'Dunbar', + 'Nahariyya', + 'Tsuyama', + 'Selston', + 'Brummen', + 'Gigante', + 'Caluquembe', + 'Nirkunnam', + 'Peabody', + 'Braunstone', + 'San Fernando de Henares', + 'Sebt Bni Smith', + 'Lakkampatti', + 'Miami Gardens', + 'Gluckstadt', + 'Santa Maria de Palautordera', + 'Bas Limbe', + 'El Puerto de Santa Maria', + 'Bundaberg', + 'Giszowiec', + 'Gweru', + 'Belle-Anse', + 'Bodupal', + 'Inopacan', + 'Pencoed', + 'Zittau', + 'Sialkot City', + 'Obera', + 'Naikankudi', + "L'Aquila", + 'Plan-les-Ouates', + "Ch'ungmu", + 'Corte Madera', + 'Kaukauna', + 'Tsararafa', + 'Lembok', + 'Altena', + 'Gliwice', + 'Bora', + 'Hagen im Bremischen', + 'Tsaramasoandro', + 'Alto Rio Senguer', + 'Inungur', + 'Alor Setar', + 'Al Hajar al Aswad', + 'Kurunegala', + 'Efringen-Kirchen', + 'Little Egg Harbor', + 'Itagi', + 'Koppunur', + 'Bemidji', + 'Tantoyuca', + 'Guiratinga', + 'Barton', + 'An Khe', + 'Yamagata', + "Lee's Summit", + 'Nea Filadelfeia', + 'Bagneux', + 'Samtredia', + 'Yingcheng', + 'Shibata', + 'Mount Pearl Park', + 'Arendonk', + 'Dhenkanal', + 'Kapenguria', + 'Saida', + 'Gloucester', + 'Bibai', + 'Lebbeke', + 'Dhusar Tikapatti', + 'Rondon', + 'Tamayo', + 'Daksinkali', + 'Plymouth', + 'Scordia', + 'Haywards Heath', + 'Battle Ground', + 'Fishers', + 'Gonen', + 'Xingren', + 'Queenstown', + 'Port Coquitlam', + 'Raritan', + 'Nagykovacsi', + 'North Bend', + 'Wilmot', + 'Taal', + 'Ruhengeri', + 'Zhovkva', + 'Sangtuda', + 'Pont-Rouge', + 'Urbandale', + 'Reeuwijksebrug', + 'Hamburg', + 'Midsayap', + 'Janai', + 'Harrow on the Hill', + 'Nakao', + 'Kaoma', + 'Verbania', + 'Dancagan', + 'Tecumseh', + 'Luhansk', + 'Elanjivaliseri', + 'Dhariwal', + 'Mahuva', + 'Dabhaura', + 'Pilisvorosvar', + 'Ravne na Koroskem', + 'As Suwayq', + 'Semri', + 'Siliana', + 'Noria', + 'Chabahar', + 'Gimpo', + 'Parempuyre', + 'Tam Hiep', + 'Bir', + 'Miranda', + 'Dhemaji', + 'Menongue', + 'Argao', + 'Fuldatal', + 'Gualeguaychu', + 'Hoboken', + 'Melgar', + 'Bishunpura', + 'Karabuk', + 'Tirthahalli', + 'Binmaley', + 'Trajano de Morais', + 'Villeneuve-Saint-Georges', + 'Moribabougou', + 'Al Mansurah', + 'Palangavangudi', + 'Nasugbu', + 'Giugliano in Campania', + 'Emsdetten', + 'Satte', + 'Prescot', + 'Carles', + 'Razkrizje', + 'Djado', + 'Wurzburg', + 'Langhnaj', + 'Kysucke Nove Mesto', + 'Ar Rastan', + 'Huehuetoca', + 'Cerca la Source', + 'Goris', + 'Plon', + 'Bad Lauterberg', + 'Gasparillo', + 'Sao Amaro das Brotas', + 'Rangvasa', + 'Kolokonde', + 'Osmancik', + 'Trofaiach', + 'Seaford', + 'Appley Bridge', + 'Majadahonda', + 'Sudley', + 'Raman Mandi', + 'Diyarbakir', + 'Xiaoxita', + 'Azacualpa', + 'Mullassheri', + 'Aruppukkottai', + 'El Rosario', + 'Puyo', + 'Pomichna', + 'Plaisance-du-Touch', + 'Ghosrawan', + 'Yuba City', + 'Homs', + 'Baunatal', + 'Cape Coral', + 'Umburanas', + 'Kakegawa', + 'Shahr-e Pir', + 'Neiba', + 'Thiers', + 'Chorbog', + 'Melton Mowbray', + 'Ariyalur', + 'Suarez', + 'Manoel Vitorino', + 'Sint-Katelijne-Waver', + 'Nongzhangjie', + 'Bayan', + 'Ceduna', + 'Grand Falls', + 'Masallatah', + 'Meppen', + 'Bromley', + 'Vanves', + 'Novelda', + 'Kaspi', + 'Horseheads', + 'Rath', + 'Vadakarai Kil Pidagai', + 'El Kansera', + 'Tanmen', + 'Henin-Beaumont', + 'Fort Payne', + 'Southlake', + 'Kaeng Khoi', + 'Broughton Astley', + 'Oyamazaki', + 'Rodolfo Sanchez Taboada', + 'Devrukh', + 'Kombai', + 'Juvisy-sur-Orge', + 'Aigua', + 'Sandridge', + 'Oum el Bouaghi', + 'Marilandia', + 'Pirbahora', + 'Bauria', + 'Matsushige', + 'Ipatinga', + 'Venkatagirikota', + 'Hazel Crest', + 'Codegua', + 'North Castle', + 'Talhar', + 'Kirchberg', + 'Achocalla', + 'Apam', + 'Cloverly', + 'La Trinite', + 'Zivinice', + 'Thanh Hoa', + 'Pocao de Pedras', + 'Tiruvadanai', + 'Koshu', + 'Cuencame de Ceniceros', + 'Tellar', + 'Praia do Carvoeiro', + 'Pursat', + 'Cunupia', + 'North Lakhimpur', + 'Carlsbad', + 'Breinigsville', + 'Saint-Bruno-de-Montarville', + 'Oro Valley', + 'Msemrir', + 'Papendrecht', + 'Pedersore', + 'Balasore', + 'Cadale', + 'Viera East', + 'Kambila', + 'Snaresbrook', + 'Rockville', + 'Culcheth', + 'San Valentino Torio', + 'Sharbaqty', + 'Chainpura', + 'Laligam', + 'Huntsville', + 'Pidigan', + 'Hohenems', + 'Rabinal', + 'Campo do Brito', + 'Les Lilas', + 'Kudali', + 'Binnaguri', + "Land O' Lakes", + 'Hatch End', + 'Abiy Adi', + 'Prijedor', + 'Affton', + 'Pilon', + 'Boditi', + 'Ferdows', + 'Villa Dolores', + 'Desenzano del Garda', + 'Venaria Reale', + 'Cuite', + 'Nonthaburi', + 'Lawrenceburg', + 'Guasipati', + 'Tottenham', + 'Utica', + 'Al Basrah', + 'Gorukle', + 'Caranavi', + 'Douglass', + 'Havirov', + 'Sukheke Mandi', + 'Audubon', + 'Puerto del Rosario', + 'Chilkuru', + 'Burco', + 'La Mornaghia', + 'Amatitan', + 'Songhuajiangcun', + 'San Antonio de las Vueltas', + 'Azadshahr', + 'Bislig', + 'Rampura', + 'Ban Klang', + 'Granadero Baigorria', + 'Usuda', + 'Montego Bay', + 'Chornomorsk', + 'Saint-Lys', + 'Sabana Grande de Palenque', + 'Xiluodu', + 'Gigaquit', + 'Carrollwood', + 'Kigali', + 'Lyman', + 'Sao Luis', + 'Patakakani', + 'Mar de Ajo', + 'Inverell', + 'Neuville-en-Ferrain', + 'Molde', + 'Petrel', + 'Indian Harbour Beach', + 'Gahi Mammar', + 'Alanya', + 'Shazand', + 'Leso', + 'Auray', + 'Panauti', + 'Ovada', + 'Tokoname', + 'Junnar', + 'Chahar Dangeh', + 'Monte Aprazivel', + 'Maida Babhangawan', + 'Matias Romero', + 'Nasu', + 'Quata', + 'Barracao', + 'Dila', + 'Piatykhatky', + 'Sikeston', + 'Luzzi', + 'Diabougou', + 'Wiesbaden', + 'Chumphon', + 'Cervia', + 'South Dundas', + 'Halfmoon', + 'Jardim de Piranhas', + 'Carol Stream', + 'Coronel Du Graty', + "L'Isle-sur-la-Sorgue", + 'Kapolei', + 'Bad Windsheim', + 'Hitchin', + 'Almeirim', + 'Kurakhove', + 'Mataro', + 'Khao Yoi', + 'Shihezi', + 'Itaiopolis', + 'Iskandar', + 'Pinamungahan', + 'Highland City', + "Ping'an", + 'Khe Sanh', + 'Konigs Wusterhausen', + 'Kottampatti', + 'Tshabong', + 'Gastonia', + 'Fuensalida', + 'Cabot', + 'Celldomolk', + 'Sakiai', + 'Pirmasens', + 'Bostonia', + 'Ngathainggyaung', + 'Nattappettai', + 'Oulad Hamdane', + 'Campo Belo', + 'Portsmouth', + 'Birmitrapur', + 'La Fare-les-Oliviers', + 'Biberach', + 'Kadoli', + 'Sremski Karlovci', + 'Leon Valley', + 'La Huacana', + 'Cambados', + 'Ban Bang Non', + 'Ranai', + 'Orumiyeh', + 'Moyuta', + 'Hansot', + 'Pasewalk', + 'Ukunda', + 'Guarne', + 'Bethal', + 'Schwabach', + 'Laventille', + 'North Reading', + 'Hithadhoo', + 'Shubrakhit', + 'Overath', + 'Karikad', + 'Nakatsu', + 'Pancevo', + 'Hamirpur', + 'Pilar de la Horadada', + 'Akdepe', + 'Phillaur', + 'Itaquaquecetuba', + 'Bridport', + 'Marotaolana', + 'Kowary', + 'Ibaan', + 'Derazhnia', + 'Baishan', + 'Strzelce Krajenskie', + 'Ampere', + 'West Nipissing / Nipissing Ouest', + 'Dashiqiao', + 'Iguaraci', + 'Minglanilla', + 'Andalgala', + 'Dili', + 'Galena Park', + 'Cinar', + 'Akropong', + 'Aston', + 'Ire', + 'Vrhnika', + 'Randfontein', + 'Rorvik', + 'Sugbongkogon', + 'Trancas', + 'Dusti', + 'Pernes-les-Fontaines', + 'Gamharia', + 'Rozdilna', + 'Harchoune', + 'Cherakara', + 'Valantaravai', + 'Todmorden', + 'Rehau', + 'Draguignan', + 'Clifton', + 'Murud', + 'Jalna', + 'Chhatarpur', + 'Palavur', + 'Balangiga', + 'Canete', + 'Stoneham-et-Tewkesbury', + 'Puttanattam', + 'Lisen', + 'Carrefour', + 'Qostanay', + 'Triggiano', + 'Chingleput', + 'Sonupur', + 'Spodnje Hoce', + 'Oftersheim', + 'Chom Thong', + 'Nagod', + 'Ecoporanga', + 'Cowley', + 'Schiltigheim', + 'San Andres del Rabanedo', + 'Velilla de San Antonio', + 'Bad Neustadt', + 'Timbo', + 'Muskogee', + 'Enid', + 'Batouri', + 'Kragero', + 'Mirano', + 'Alangayam', + 'Cianorte', + 'Crystal Lake', + 'Sebt Gzoula', + 'Kyazanga', + 'Lendava', + 'Bad Durrheim', + 'Jiangguanchi', + 'Gonzalez Catan', + 'La Roche-sur-Foron', + 'Itapiranga', + 'Aktuluk', + 'Uslar', + 'Luis Correia', + 'Anjahamana', + 'Dracevo', + 'Pavlikeni', + 'Salvatierra de Mino', + 'El Karimia', + 'Heilsbronn', + 'Honaz', + 'Multai', + 'Zarghun Shahr', + 'Jesenice', + 'Catanauan', + 'Haaksbergen', + 'Tiruvasaladi', + 'Karvarakundu', + 'Malay', + 'Tamura', + 'Loma Plata', + 'Hamilton Square', + 'Dewal Thal', + 'Partur', + 'Koilakh', + 'Great Dunmow', + 'Sinj', + 'Bekily', + 'Hercules', + 'Dunstable', + 'Kosgi', + 'Xinsi', + 'Tomboco', + 'Southwick', + 'Sangamner', + 'Mossoro', + 'Khon Kaen', + 'Dhamnagar', + 'Denain', + 'Berezivka', + 'Humaita', + 'Malhipur', + 'San Luis de Since', + 'Martin', + 'Rajapudi', + 'Yucaipa', + 'Ortigueira', + 'City of Paranaque', + 'Kabira', + 'Kalandy', + 'Uwajima', + 'Fantino', + 'San Juan Atitan', + 'Kennesaw', + 'Prattville', + 'Showa', + 'Hakmana', + 'Maastricht', + 'Pesqueria', + 'Ban Ngao', + 'Amparafaravola', + 'Bhagwatpur', + 'Landshut', + 'Justo Daract', + 'San Vicente', + 'Hall in Tirol', + 'Avare', + 'Binxian', + 'Llaillay', + 'Hoskote', + 'La Massana', + 'Tucker', + 'Pacasmayo', + 'Ambato', + 'Apiuna', + 'Shaxi', + 'Mpigi', + 'Evere', + 'Sakaki', + 'Sampona', + 'Puerto Leguizamo', + 'Santiago del Teide', + 'Wudalianchi', + 'Blieskastel', + 'Rutesheim', + 'Phan Ri Cua', + 'Itahri', + 'Chilibre', + 'Schalksmuhle', + 'Askale', + 'Vite', + 'Ibipora', + 'Haugesund', + 'Valdemorillo', + 'Iringal', + 'Tariba', + 'Hays', + 'Annur', + 'Mariental', + 'Cieza', + 'Kirkland', + 'Nohar', + 'Shiso', + 'Yoshinogawa', + 'La Motte-Servolex', + 'Sippola', + 'Bonthe', + 'Rijswijk', + 'Pontinia', + 'Aarhus', + 'Kitaotao', + 'Rreshen', + 'Mahinawan', + 'Manrar', + 'Pattanapuram', + 'Baidoa', + 'Zhongxiang', + 'La Colonia Tovar', + 'Amelia', + 'Fuveau', + 'Aguas Formosas', + 'Trikonavattam', + 'Chewara', + 'Bhado Khara', + 'Novyi Rozdil', + 'Palepalli', + 'Ellamanda', + 'San Martin Totolan', + 'Edinet', + 'Weihai', + 'Granadilla de Abona', + 'Sulphur Springs', + 'Astoria', + 'Seyitgazi', + 'Kingsteignton', + 'Weybridge', + 'Plumtree', + 'Brugnera', + 'Stony Point', + 'Shikrapur', + 'Canguaretama', + 'Pedreira', + 'Kot Kapura', + 'Banyuwangi', + 'Sueca', + 'Afzala', + 'Kenilworth', + 'Stuhr', + 'Riverbank', + 'Jdour', + 'Al Minshah', + 'Warren', + 'Kalundborg', + 'Farroupilha', + 'Walsrode', + 'Ilheus', + 'Heroica Ciudad de Tlaxiaco', + 'Smoline', + 'Cueto', + 'Pingtang', + 'Khorugh', + 'Engandiyur', + 'Canlaon', + 'El Reno', + 'Gadwal', + 'Villa Verde', + 'Pulluru', + 'Talatona', + 'Badepalli', + 'Oltiariq', + 'Aizumisato', + 'Antsoso', + 'Jianganj', + 'Mullurkara', + 'Taouloukoult', + 'Chambray-les-Tours', + 'Tabarre', + 'Bamumkumbit', + 'Maquela do Zombo', + 'Widnau', + 'Kurihara', + 'Shumen', + 'Kosatarosh', + 'Villa Vasquez', + 'Nampicuan', + 'Waasmunster', + 'Wilmington', + 'Silao', + 'Geseke', + 'Jamsa', + 'Forres', + 'Tukh', + 'Aversa', + 'Sanpetru', + 'Terra de Areia', + 'Samahuta', + 'North Kingstown', + 'Chiplun', + 'Sztum', + 'Neustadt an der Donau', + 'Alajuelita', + 'Peyziwat', + 'San Carlos Sija', + "Ji'an Shi", + 'Ciudad de Allende', + 'Carmo do Paranaiba', + 'Dakar', + 'Paulista', + "Rignano sull'Arno", + 'Papenburg', + 'Imanombo', + 'Cabangan', + 'Miedzychod', + 'Guanabacoa', + 'Djemmal', + 'Alpedrete', + 'Alcacer do Sal', + 'Barhagarh', + 'Nong Ki', + 'Kot Shamir', + 'Yugawara', + 'Polangui', + 'Villa Ygatimi', + 'Mathura', + 'Morley', + 'Gokak', + 'Red Hill', + 'Bad Durrenberg', + 'Yeghegnadzor', + 'Muroran', + 'Fair Lawn', + 'Urai', + 'Caiaponia', + 'Chimbarongo', + 'Buabidi', + 'Erba', + 'Elandsdoorn', + 'Mongar', + 'Basankusu', + 'Longji', + 'Sucun', + 'Kakata', + 'Altus', + 'Elizabethtown', + 'Kamlapur', + 'Birkenau', + 'San Mateo Atenco', + 'Viqueque', + 'Dibaya', + 'Sao Benedito', + 'Daphne', + 'Irving', + 'Randazzo', + 'Cameron', + 'Gasa', + 'Salyan', + 'Magadi', + 'Pingzhen', + 'Kibiito', + 'Katherine', + 'Sebekoro', + 'Itamaraca', + 'Changling', + 'Tunduru', + 'River Ridge', + 'El Adjiba', + 'Pardiguda', + 'Guaranesia', + 'Subaykhan', + 'Dar Naim', + 'Fulda', + 'Meiti', + 'Choybalsan', + 'Granollers', + 'Al Qays', + 'Moldava nad Bodvou', + 'El Molar', + 'Bayt Saham', + 'Coruripe', + 'Leawood', + "Kunp'o", + 'Aracati', + 'Soaserana', + 'Ambatofotsy', + 'Linganore', + 'Rotterdam', + 'Kumano', + 'Shoeburyness', + 'Palayan City', + 'Oak Island', + 'Saylac', + 'Darwa', + 'Heidelberg', + 'Puerto Maldonado', + 'Szazhalombatta', + 'Fatwa', + 'Kolattupuzha', + 'Mahinog', + 'Villa Rumipal', + 'Somnaha', + 'Veauche', + 'Baheri', + 'Sangzishi', + 'Moser', + 'Cologne', + 'Rypin', + 'Salinas da Margarida', + 'Carini', + 'Gloria do Goita', + 'Tekes', + 'Northport', + 'Seven Oaks', + 'Nemmara', + 'Consolacion del Sur', + 'El Calafate', + 'Foumbot', + 'Magnolia', + 'Carangola', + 'Caracas', + 'Vallahbhapuram', + 'Al `Aqiq', + 'Sincan', + 'Bebra', + 'Malkapur', + 'Valongo', + 'Flawil', + 'Piprahi', + 'Cheney', + 'Tarar', + 'Gode', + 'Tangkak', + 'La Canada Flintridge', + 'Schwanewede', + 'Thomasville', + 'Wolossebougou', + 'Zunilito', + 'Aristobulo del Valle', + 'Staden', + 'Bakhri', + 'Chatillon', + 'Puerto Varas', + 'El Tarf', + 'Goianinha', + 'Bimgal', + 'Abu Qurqas', + "Aghbalou n'Kerdous", + 'Tayakou', + 'Johnson City', + 'Stjordalshalsen', + 'Kot Mumin', + 'Orbassano', + 'Carius', + 'Dikwella South', + 'Gallipoli', + 'Wschowa', + 'Sundarnagar', + 'Gustrow', + 'Pindai', + 'Mit Ghamr', + 'Xinyaoshang', + 'Torbeck', + 'Marrakech', + 'Xiushuicun', + 'Valasa', + 'Tuttlingen', + 'Avesta', + 'Highgate', + 'Osian', + 'Kanniyambram', + 'Malinao', + 'Xingsha', + 'Oltenita', + 'Capiata', + 'Malanville', + 'Hunters Creek', + 'Balwa', + 'Muli', + 'Lotte', + 'Hikkaduwa', + 'Pelahiivka', + 'Chilapa de Alvarez', + 'Farafenni', + 'Tanbaichicho', + 'Saks', + 'Calilabad', + 'Salvaterra de Magos', + 'Chittayankottai', + 'Popondetta', + 'Synelnykove', + 'Flying Fish Cove', + 'Gikongoro', + 'Baraki', + 'Karebilachi', + 'El Hachimia', + 'Highland Heights', + 'Chilecito', + 'Kawashiri', + 'Scotch Plains', + 'Adi Keyh', + 'Cheung Chau', + 'Therwil', + 'Tiruvalanjuli', + 'Bagrami', + 'San Juan Lalana', + 'Nodinge-Nol', + 'Gonzalez', + 'Moshi', + 'Zhangjiajie', + 'Bafilo', + 'Presidente Prudente', + 'Sassenberg', + 'Kot Addu', + 'Nicholasville', + 'Magitang', + 'Glauchau', + 'Bendrahalli', + 'Mislinja', + 'Nysa', + 'Tomaz pri Ormozu', + 'Tassin-la-Demi-Lune', + 'Schubelbach', + 'Juban', + 'Epinay-sur-Orge', + 'West Bradford', + 'Genk', + 'Miyakonojo', + 'Eastpointe', + 'Quispamsis', + 'Gadda Madiral', + 'Nouadhibou', + 'Neuss', + 'Yanagawa', + 'Kirano', + 'Sheldon', + 'Florange', + 'Albert', + 'Vilcun', + 'Mannheim', + 'Qahramon', + 'Joaquim Tavora', + 'Amravati', + 'Small Heath', + 'Ancon', + 'San Juan Chamelco', + 'Neunkirchen', + 'Timargara', + 'Poole', + 'Tenkodogo', + 'Jidigunta', + 'Agoncillo', + 'Diosd', + 'Kondaparti', + 'Darauli', + 'San Giuliano Milanese', + 'Farkhana', + 'Upernavik', + 'Isehara', + 'Ginsheim-Gustavsburg', + "Port Saint John's", + 'Shekhupura', + 'Malvinas Argentinas', + 'Mirbat', + 'Kishangarh', + 'Ibicui', + 'Tangalla', + 'Napa', + 'Tavares', + 'Koro', + 'Edasseri', + 'Negotin', + 'Barcs', + 'Keshwari', + 'Depew', + 'Kottaya', + 'Khair Khan', + 'Toviklin', + 'New Port Richey East', + 'Tarrega', + 'Mariel', + 'Krabi', + 'Rinconada de Malloa', + 'Felida', + 'Sidi Ifni', + 'Tobre', + 'Yorba Linda', + 'Casper', + 'Hartswater', + 'Guanambi', + 'Winthrop', + 'Marcacao', + 'Bridlington', + 'Feicheng', + 'Pinhalzinho', + 'Dubai', + 'Periyakulam', + 'Tranent', + 'Hammam Sousse', + 'Ampasimbe', + 'Santa Mariana', + 'San Antonio de Ibarra', + 'Charlton Kings', + 'Tecoanapa', + 'Kamwenge', + 'Arai', + 'Jocotepec', + 'Kiziltepe', + 'Hadali', + 'Bahadurpur', + 'Thoen', + 'Nakhon Phanom', + 'Nayoro', + 'Baramati', + 'Lamas', + 'Krupanj', + "Ning'an", + 'Monfalcone', + 'Hitachi-Naka', + 'Lower Burrell', + 'Formoso do Araguaia', + 'Vadigenhalli', + 'Bansbaria', + 'Tupanatinga', + 'Dome', + 'Niles', + 'Siquirres', + 'Boddikurapadu', + 'Bryant', + 'Serebryansk', + "'Ain el Hammam", + 'Aldo Bonzi', + 'Gajhara', + 'Tokyo', + 'Karakthal', + 'Cabildo', + 'Buon Trap', + 'Liushui', + 'Echternach', + 'Vagur', + 'Bicester', + 'Rheden', + 'Asaka', + 'Ulladulla', + 'Titara', + 'Haya', + 'Francisville', + 'Robat Karim', + 'Shidong', + 'Bhadohi', + 'Otsuki', + 'Barnaon', + 'Valavanur', + 'Kyenjojo', + 'Mara Rosa', + 'Markgroningen', + 'Planegg', + 'Cajvana', + 'Tatabanya', + 'Andemaka', + 'Nazilli', + 'Leusden', + 'Kanada', + 'Dasol', + 'Al Wakrah', + 'Lucan', + 'Jelilyuzi', + 'Puerto Quito', + 'Cran-Gevrier', + 'Damous', + 'Gunungsitoli', + 'Minamikarasuyama', + 'Sandton', + 'San Antonio del Tequendama', + 'Paiporta', + 'Guying', + 'Fontenay-le-Fleury', + 'Denov', + 'Bulambuli', + 'Yulu', + 'Cajamar', + 'Brvenica', + 'Ocozocoautla de Espinosa', + 'Panapur Langa', + 'Memmingen', + 'Ban Non Sombun', + 'Oegstgeest', + 'Aigio', + 'Bhanuvalli', + 'Rankovce', + 'Bagchini', + 'Voitsberg', + 'Ban Nong Kathao', + 'Canby', + 'Cosne sur Loire', + 'Nilothi', + 'Ma`arratmisrin', + 'Lyndon', + 'Gurgentepe', + 'Adjahome', + 'Andippatti', + 'West Manheim', + 'Brunsbuttel', + 'Grave', + 'Zapotlan de Juarez', + 'Yakkabog`', + 'Tan Phuoc Khanh', + 'Tinley Park', + 'Baligaon', + 'Bell Ville', + 'Gwagwalada', + 'Pie de Pato', + 'Mount Fletcher', + 'Waris Aliganj', + 'Queens', + 'Tamana', + 'Craibas', + 'Caivano', + 'Grants Pass', + 'Citrus Hills', + 'Elko', + 'El Abiodh Sidi Cheikh', + 'Pathardi', + 'Acatlan', + 'Westwood', + 'Cibinong', + 'Dayr `Atiyah', + 'Ja`ar', + 'Archdale', + 'Seguin', + 'Vif', + 'San Vicente de Canete', + 'Limbe', + 'Calumet City', + 'Ain el Hadid', + 'Sint-Andries', + 'Skhirate', + 'Assi-Ben Okba', + 'San Ildefonso', + 'Saint-Raphael', + 'Dire Dawa', + 'Koropi', + 'Murata', + 'Mongu', + 'Villa Maria', + 'Taqah', + 'I-n-Amguel', + 'Moloacan', + 'Milford Haven', + 'Campo Alegre', + 'Atlantic Beach', + 'Kalikapur', + 'Fuefuki', + 'Centralina', + 'Sarafand', + 'Chuangjian', + 'Kheralu', + 'Sulecin', + 'Kirchhain', + 'Coffeyville', + 'Uji', + 'Westport', + 'Compostela', + 'Stratford-upon-Avon', + 'Tougue', + 'Neves', + 'Satiro Dias', + 'Numbrecht', + 'Galle', + 'Ilion', + 'Dasarhalli', + 'Flat Rock', + 'Old Bridge', + 'Barbacena', + 'Essa', + 'Peddakurapadu', + 'Chervonopartyzansk', + 'Perth East', + 'Margosatubig', + 'Bossangoa', + 'Ngorkou', + 'Frankenthal', + 'Reguengos de Monsaraz', + 'Roverbella', + 'Annecy-le-Vieux', + 'Woodmoor', + 'Imizucho', + 'Villanueva de la Serena', + 'Kinalur', + 'Depok', + 'Ahrensburg', + 'Kingman', + 'Magu', + 'Guiping', + 'Kopavogur', + 'Hunasamaranhalli', + 'Tora', + 'Malvar', + 'Lentini', + 'Pont-du-Chateau', + 'Laghouat', + 'Jima Abajo', + 'Garbahaarrey', + 'Samsikapuram', + 'Vinanitelo', + 'Nong Wua So', + 'Jawad', + 'Tirunageswaram', + 'Koure', + 'Villabate', + 'Rezekne', + 'Nenton', + 'Canovanas', + 'Los Banos', + "Berre-l'Etang", + 'Al Qunfudhah', + 'Buenopolis', + 'Le Plessis-Robinson', + 'Bilar', + 'San Antonio de Los Altos', + 'Elblag', + 'Masamba', + 'Czeladz', + 'Tmassah', + 'San Vicente del Raspeig', + 'Tejutla', + 'Albano Laziale', + 'Sibkund', + 'Goio-Ere', + 'Kanoya', + 'Dahibhat Madhopur', + 'Santa Maria Ajoloapan', + 'Srebrenica', + 'Bacoor', + 'Novopavlovka', + 'Marcory', + 'Argos', + 'Ivandrika', + 'Iqaluit', + 'Kondazhi', + 'Kos', + 'Newhaven', + 'Bakwa', + 'Mirante da Serra', + 'Limbach-Oberfrohna', + 'Asadabad', + 'Damulog', + 'Bishops Stortford', + 'Jaguaribara', + 'Vadasikarambattu', + 'Kairaki', + 'Koidu-Bulma', + 'Alto-Cuilo', + 'Mondoro', + 'Buon Ho', + 'Laibin', + 'Prymorskyi', + 'Berane', + 'Wulongpu', + 'Bernalillo', + 'Koturkolkara', + 'Bellerive-sur-Allier', + 'Jambe', + 'Kerwada', + 'Kadoma', + 'Antanamalaza', + 'Yildiz', + 'Kamrawan', + "Kan'onjicho", + 'Sekiyado', + 'Tartarugalzinho', + 'Kudra', + 'Mauban', + 'El Tambo', + 'Taquarana', + 'Winneba', + 'Damghan', + 'Balikumbat', + 'Ulundi', + 'Salo', + 'Nyakosoba', + 'Jeffersontown', + 'Lievin', + 'Santeramo in Colle', + 'Casale Monferrato', + 'Palma del Rio', + 'Yizhu', + 'Ankafina Tsarafidy', + 'Nisarpur', + 'Tadpatri', + 'Peebles', + 'Nawalgarh', + 'Ulliyil', + 'Paittur', + 'Chhajli', + 'Concepcion Batres', + 'Nkpor', + 'DuPont', + 'Burgum', + 'Kaposvar', + 'Labangan', + 'Santany', + 'Appingedam', + 'Barton upon Irwell', + 'Bagli', + 'Hatta', + 'Leeds and the Thousand Islands', + 'Catende', + 'Friedeburg', + 'Udaipura', + 'Aranzazu', + 'Umga', + 'Vize', + 'Coriano', + 'Janjgir', + 'Brwinow', + 'Teays Valley', + 'Ban Kaeng', + 'Huebampo', + 'Oadby', + 'Hovsan', + 'Torre-Pacheco', + 'Kolluru', + 'Araban', + 'Ishiki', + 'Daganzo de Arriba', + 'Jagannadapuram', + 'Quinhamel', + 'Nsukka', + 'Midwest City', + 'Alcala', + 'Payson', + 'Kita Chauhattar', + 'Sao Luis Gonzaga do Maranhao', + 'Quezon', + 'Mani', + 'Khammam', + 'Belo Tsiribihina', + 'Carmaux', + 'Idar', + 'Denison', + 'Lucera', + 'Buda', + 'Ankofa', + 'San Miguel', + 'Isaka', + 'Netherton', + 'Conil de la Frontera', + 'Gorazde', + 'Manullahpatti', + 'Preah Vihear', + 'Coello', + 'Sopo', + 'Valadares', + 'Suruc', + 'Ros Comain', + 'Alto Hospicio', + 'Bargas', + "Anzola dell'Emilia", + 'Eichenzell', + 'Lucelia', + 'Betsiaka', + 'Sidi Bibi', + 'Thale', + 'South Stormont', + 'Kaladgi', + 'Alpen', + 'Zumbagua', + 'Encruzilhada do Sul', + 'Megrine', + 'Panorama', + 'Chitrada', + 'Adamantina', + 'Harsum', + 'Unguturu', + 'San Juan Capistrano', + 'Klasterec nad Ohri', + 'Fernley', + 'Aldenhoven', + 'Pien', + 'Cansancao', + 'Kuje', + 'Valenca do Piaui', + 'Fraga', + 'Carleton Place', + 'Castle Bromwich', + 'Leichi', + 'Armacao dos Buzios', + 'Valenton', + 'Myawadi', + 'Leandro N. Alem', + 'Merlo', + 'Lugazi', + 'Foster City', + 'Shurugwi', + 'Labe', + 'Ruwa', + 'Inongo', + 'Coto Brus', + 'Tiruchengodu', + 'Dharmasagaram', + 'Ommen', + 'Khajawa', + 'Urandi', + 'Fayroz Koh', + 'Bajpe', + 'Epalinges', + 'Longreach', + 'Omdurman', + 'Campos Altos', + 'East Lampeter', + 'Podilsk', + 'Bemaharivo', + 'Al Ahmadi', + 'Vallapuram', + 'Sirvel', + 'Gaurdah', + 'Cottica', + 'Izmail', + 'Orangeburg', + 'Crystal Beach', + 'Toumoukro', + 'Chittarkottal', + 'Klipphausen', + 'Donji Vakuf', + 'Tazah Khurmatu', + 'Laur', + 'Raiyam', + "Saint-Jean-d'Illac", + 'Dubrovnik', + 'Mikkabi', + 'Masasi', + 'Artvin', + 'Maisaram', + 'Ostwald', + 'Wuzhou', + 'San Bartolome Milpas Altas', + 'Zhunan', + 'Pine', + 'Susner', + 'Sibalom', + 'Ormoc', + 'Dimataling', + 'Maroantsetra', + 'Trevignano', + 'La Presa', + 'North Dumfries', + 'Munguia', + 'Mangalam', + 'Kraainem', + 'Bathgate', + 'Russell', + 'Oliveira do Bairro', + 'Vettur', + 'Basavana Bagevadi', + 'Ub', + 'Yepocapa', + 'Spearfish', + 'Stassfurt', + 'Irvine', + 'Bratislava', + 'Coatbridge', + 'Hudli', + 'Beni Amrane', + 'Mansourah', + 'Addanki', + 'Volnovakha', + 'Lagoa Real', + 'Salua', + 'Talata-Vohimena', + 'Kyotera', + 'Rovato', + 'Vilankulo', + 'Nanterre', + 'Timahdit', + 'Blandford Forum', + 'Bombardopolis', + 'eManzimtoti', + 'Garges-les-Gonesse', + 'Araceli', + 'Weslaco', + 'Catembe', + 'Ta Khmau', + 'Zempoala', + 'Terracina', + 'Sint-Amandsberg', + 'Monte Santo de Minas', + 'Umm Salal `Ali', + 'Mudbidri', + 'Dores do Indaia', + 'Osilnica', + 'Eger', + 'Chi Linh', + 'El Omaria', + 'Itapui', + 'Ban Bueng', + 'Balad', + 'Blooming Grove', + 'Kivertsi', + 'Bacabal', + 'Fujin', + 'Combs-la-Ville', + 'Aschheim', + 'Kettering', + 'Chinggil', + 'Nangandao', + 'Avalepalli', + 'London', + 'Aguachica', + 'Leidschendam', + 'Sannicandro Garganico', + 'Cambrils', + 'Tenenkou', + 'Lincoln City', + 'San Gennaro Vesuviano', + 'Dumaran', + 'Yuki', + 'Llanes', + 'Ksar Hellal', + 'Clanton', + 'Khomeyn', + 'Petrovaradin', + 'Whitecourt', + 'San Sebastian Salitrillo', + 'Steubenville', + 'Santiago Atitlan', + 'Cecil', + 'Barnegat', + 'Alto Garcas', + 'Xinfeng', + 'Innsbruck', + 'Santa Margarita de Mombuy', + 'Goya', + 'Inisa', + 'Temascalapa', + 'Ouake', + 'Ambararatabe', + 'Las Delicias', + 'Zawal', + 'Longkoucun', + "Fil'akovo", + 'Concepcion del Uruguay', + 'Seixal', + 'Empedrado', + 'Meram', + 'Matagob', + 'Boufatis', + 'Juanjui', + 'Butha-Buthe', + 'Mutterstadt', + 'Koulikoro', + 'Narhat', + 'Hateg', + 'Americana', + 'Copacabana', + 'Lajkovac', + 'Beasain', + 'Miyoshi', + 'Mooka', + 'Zhuangwei', + 'Dobeln', + 'Brest', + 'Hartlepool', + 'Jajpur', + 'Moncagua', + 'Tarnow', + 'Holt', + 'Hancheng', + 'Ciudad Guzman', + 'Boudouaou el Bahri', + 'Suhiya', + 'Oteapan', + 'Zhoujia', + 'Hohhot', + 'Bulle', + 'Helensburgh', + 'San Jose Villanueva', + 'Lethem', + 'Landen', + 'Gonaives', + 'Mahopac', + 'Tuyen Quang', + 'Shaowu', + 'Celbridge', + 'Artsyz', + 'Heshan', + 'Boutilimit', + 'Bure', + 'Jangid', + 'Doberlug-Kirchhain', + 'Kawara', + 'Meldola', + 'Xinglong', + 'Ntungamo', + 'Shubra al Khaymah', + 'Eldama Ravine', + 'Sukuta', + 'Ain Tedeles', + 'Bara', + 'Barei', + 'Caballococha', + 'Locorotondo', + 'Pine Creek', + 'Mechanicsville', + 'Baxdo', + 'Mysliborz', + 'Androtsy', + 'Newcastle under Lyme', + 'San Jose de Chiquitos', + 'Forchheim', + 'Sabana Iglesia', + 'Saint-Max', + 'Cordenons', + 'Dent', + 'Verdejante', + 'Enkoping', + 'Paradise Valley', + 'Arnaud', + 'Janapul', + 'Sintra', + 'Misserete', + 'Lapinig', + 'Singhbari', + 'Librazhd', + 'Amberg', + 'Pires do Rio', + 'Kenora', + 'Satosho', + 'Anosivelo', + 'Coos Bay', + 'Pathum Thani', + 'Curchorem', + 'Bergambacht', + 'Dahbed', + 'Haslingden', + 'Shahin Dezh', + 'Faridabad', + 'Patera', + 'Saint-Cyr-sur-Loire', + 'Ilhota', + 'Chianki', + 'Garcia', + 'Meine', + 'Kalamazoo', + 'Spitalfields', + 'Maralal', + 'Aruvapalam', + 'Pedro Juan Caballero', + 'Antanifotsy', + 'Suhl', + 'Hancha', + 'Sansepolcro', + 'Villa Martin Colchak', + 'Ksar Chellala', + 'Voznesensk', + 'Requinoa', + 'Vemalwada', + 'Athieme', + 'Neuburg', + 'Tikamgarh', + 'Mazidagi', + 'Florence-Graham', + 'Ikeja', + 'Dinara', + 'Ampanihy', + 'Woodinville', + 'El Palomar', + 'Shafinagar', + 'Jandrapeta', + 'Finglas', + 'Pikesville', + 'Sidney', + 'Tiffin', + 'Belvedere Park', + 'Bad Breisig', + 'Afega', + 'Canilla', + 'Hisarcik', + 'Hertford', + 'Chichkah', + 'Santa Rosa', + 'Palampur', + 'Sanmu', + 'Apuiares', + 'Courtenay', + 'Aiuaba', + 'Hidirbey', + 'Chikuma', + 'Hiddenhausen', + 'Shikohabad', + 'Chilliwack', + 'Tagalft', + 'Chelmno', + 'Colfontaine', + 'Upper Dublin', + 'Ungheni', + 'Estiva', + 'Sveta Ana', + 'Watsa', + 'Gilbert', + 'At Turrah', + 'Payariq Shahri', + 'Ibipeba', + 'San Juan de los Lagos', + 'Barcelona', + 'Ambalamanasy II', + 'Homnabad', + 'Bad Freienwalde', + 'Chandauli', + 'Comitancillo', + 'Bad Konig', + "Sint-Job-in-'t-Goor", + 'Templin', + "D'Iberville", + 'Adelanto', + 'Tepeapulco', + 'Moreni', + 'Blois', + 'Moberly', + 'Encruzilhada', + 'Tokol', + 'Kaneohe', + 'Macomia', + 'Tlalpujahua de Rayon', + 'Kaglipur', + 'Baiceng', + 'Muisne', + 'Fareham', + 'Polistena', + 'Razampeta', + 'Ipojuca', + 'Sandrakatsy', + 'Dagiapara', + 'Madhurapur', + 'Zhuangyuan', + 'Shkoder', + 'Hillsboro', + 'Vidin', + 'Quatipuru', + 'Dubrajpur', + 'Capenda Camulemba', + 'Jaisinghpur', + 'Sonneberg', + 'Gonesse', + 'Toging am Inn', + 'Laranjal Paulista', + 'Tucuru', + 'Arcueil', + 'Francisco I. Madero', + 'Tarumizu', + 'Estrela de Alagoas', + 'Charleston', + 'Cowes', + 'Sessa Aurunca', + 'Fougeres', + "Gricignano d'Aversa", + 'New Germany', + 'Paraparaumu', + 'Pleasant Prairie', + 'Alfena', + 'Payakumbuh', + 'Ramree', + 'Maromme', + 'Kovvur', + 'Derince', + 'Caledon', + 'Jieshang', + 'Navan', + 'Kumbo', + 'Santa Rita do Passa Quatro', + 'Ridgefield', + 'Kllokot', + 'Niramaruthur', + 'Despujols', + 'Narammala', + 'Oroqen Zizhiqi', + 'San Luis del Palmar', + 'Mallawi', + 'Polzela', + 'Troy', + 'El Refugio', + 'Marau', + 'Thaton', + 'Gerede', + 'Lakhanapuram', + 'Chinchina', + 'Duenas', + 'Devizes', + 'Amarillo', + 'Dakor', + 'Brotas', + 'North Auburn', + 'Soamanonga', + 'Villa Alemana', + 'Sathamba', + 'Kanazawa', + 'Namayumba', + 'Ngozi', + 'Mavalli', + 'Maxhutte-Haidhof', + 'Ratnapuram', + 'Midoun', + 'Gostyn', + 'Olopa', + 'Fugangcun', + 'Perungala', + 'Mount Washington', + 'Tekirdag', + 'Cerro Azul', + 'Lahra Muhabbat', + 'Ontario', + 'Santa Maria Chiquimula', + 'North Hempstead', + 'Arma', + 'Awash', + 'Felanitx', + 'Olmaliq', + 'Torremolinos', + 'Gbawe', + 'Sivrihisar', + 'Preussisch Oldendorf', + 'Herrin', + 'Vellalur', + 'Doboj', + 'Guaramirim', + 'Bafoulabe', + 'Nolensville', + 'Acomb', + 'Balaungi', + 'San Juan Ixcaquixtla', + 'Cadereyta', + 'Tarra', + 'Ponta do Sol', + 'Ikaruga', + 'Kaboua', + 'Inagawa', + 'Jacaltenango', + 'Nankana Sahib', + 'Ciudad Melchor de Mencos', + 'Braine-le-Chateau', + 'Gerzat', + 'Abaiara', + 'Maricopa', + 'Saint Neots', + 'Sao Goncalo do Sapucai', + 'Myebon', + 'Markapur', + 'Nova Zagora', + 'Gombong', + 'Gambela', + 'Magsingal', + 'Brezovica', + 'Greifswald', + 'Saint-Nazaire', + 'Poinciana', + 'Hombori', + 'Tsivory', + 'Weiz', + 'Jaguaripe', + 'Kibaya', + 'Wallasey', + 'Nangal Township', + 'Chongzuo', + 'Takamori', + 'Pajo', + 'Daboh', + 'Jisr ez Zarqa', + 'Tizi Rached', + 'Nangal Chaudhri', + 'North Huntingdon', + 'Balilihan', + 'San Josecito', + 'Steinfeld', + 'Velika Gorica', + 'New Cassel', + 'Kyaukme', + 'Kafr Batna', + 'Tepetzintla', + 'Takaharu', + 'Valdepenas', + 'Old Harbour', + 'Siruguppa', + 'Arasur', + 'Grajewo', + 'Aci Catena', + 'Itau de Minas', + 'Zundert', + 'Djakotome', + 'Toulou', + 'Sahar', + 'Opfikon', + 'Damanhur', + 'Yengema', + 'Subic', + 'Kolambugan', + 'Taougrite', + 'Eriyodu', + 'Kiskunmajsa', + 'Germasogeia', + 'Peresecina', + 'Yoshikawa', + "Coeur d'Alene", + 'Mobaye', + 'Borda da Mata', + 'Vecses', + 'Kui Buri', + 'Newport Beach', + 'Palo del Colle', + 'Ripoll', + 'Galsi', + 'Aldama', + 'La Grita', + 'Paese', + 'Sambir', + 'Chapelle', + 'Canteras', + 'Vega Alta', + 'Bhachau', + 'Nanfengcun', + 'Nelson', + 'Chikuzen', + 'Burrillville', + 'Nambour', + 'Sanganakallu', + 'Punch', + 'Borehamwood', + 'Bagan Si Api-api', + 'Tiogollo', + 'Pratteln', + 'Coleford', + 'Huajing', + 'Amoucha', + 'Kannivadi', + 'Winfield', + 'Kimilili', + 'Bugganipalle', + 'Mont-Dore', + 'Chaukhata', + 'Long Lama', + 'Taysan', + 'Caico', + 'Sakardih', + 'Owando', + 'Foleshill', + 'Katlehong', + 'Falkoping', + 'Vellithiruthi', + 'Pancas', + 'Rojales', + 'Juazeiro', + 'Sluis', + 'Matala', + 'Banikoara', + 'Ilicakoy', + 'Montalban', + 'La Algaba', + 'Makeni', + 'Mangrol', + 'Shirdi', + 'Kamphaeng Phet', + 'Prelouc', + 'Podujeve', + 'Redencao', + 'Isaka-Ivondro', + 'Pollensa', + 'Eemnes', + 'Kogon Shahri', + 'Asarhi', + 'Bang Khla', + 'San Andres de Sotavento', + 'Shertallai', + 'Fenglu', + 'El Doncello', + 'Prachatice', + 'Biel/Bienne', + 'Tsabit', + 'Mirante do Paranapanema', + 'Kotoura', + 'Port St. Lucie', + 'Minamichita', + 'Arapiraca', + 'Balcarce', + 'Scionzier', + 'Kharv-e Sofla', + 'Redan', + 'Rolandia', + 'Turrialba', + 'Tsaravary', + 'Sayda', + 'Banepa', + 'Soller', + 'Kaith', + 'Mahdasht', + 'Sandhausen', + 'Redditch', + 'Bemiss', + 'Callaway', + 'Rioblanco', + 'Maesteg', + 'Saronno', + 'Fulgazi', + 'Revuca', + 'Lysychansk', + 'Mandan', + 'Wangjiazhai', + 'Capela de Santana', + 'Toukoto', + 'Vwawa', + 'Dublin', + 'Newark upon Trent', + 'Zacoalco de Torres', + 'Pustomyty', + 'Sangi', + 'Zymohiria', + 'Clinton', + 'Nenjiang', + 'Nova Ubirata', + 'Cosautlan', + 'Kibuye', + 'Darfield', + 'Cornaredo', + 'Ciudad Choluteca', + 'Tvoroyri', + 'Giussano', + 'Manambur', + 'Benfreha', + 'Medarametla', + 'Meridianville', + 'Al Qa`idah', + 'Treinta y Tres', + 'Nagar Nahusa', + 'Kedainiai', + 'Kursenai', + 'Shunan', + 'Dzolokpuita', + 'Lyon', + 'Kleve', + 'Sadon', + 'Fort Pierce', + 'Sanski Most', + 'Zedelgem', + 'Paracho de Verduzco', + 'Hattem', + 'Cantel', + 'Miary-Taheza', + 'Maintirano', + 'Denham Springs', + 'Ap Khanh Hoa', + 'Kaler', + 'Le Pradet', + 'Uxbridge', + 'Cugnaux', + 'Altdorf', + 'Oberhausen', + 'Caacupe', + 'Moyo', + 'Muchun', + 'Roquevaire', + 'Tubod', + 'Bacolor', + 'Nijgaon Paranpur', + 'Sao Pedro da Aldeia', + 'Adrian', + 'Remedios de Escalada', + 'Pehowa', + 'Orlando', + "Mosciano Sant'Angelo", + 'Kasempa', + 'Tomigusuku', + 'Naic', + 'Blanes', + 'Iguacu', + 'Ben Arous', + 'Ben', + 'Westborough', + 'Parkent', + 'Nokaneng', + 'Goianesia', + 'Raniwara Kalan', + 'Lambersart', + 'Handewitt', + 'Beni Haoua', + 'Pargas', + 'Temascalcingo', + 'Abano Terme', + 'Petmanhalli', + 'Karis', + 'Dezhou', + 'Guigue', + 'Melitopol', + 'Tajerouine', + 'Malaimarpuram', + 'Asti', + 'Hanimciftligi', + 'Isua', + 'Enkesen', + 'Birtouta', + 'Relizane', + 'Igrapiuna', + 'Belle Chasse', + 'Calubian', + 'Ararat', + 'Caucete', + 'Hybla Valley', + 'Wipperfurth', + 'Bom Jesus da Lapa', + 'North Salt Lake', + 'Dayan', + 'Zouar', + 'Parang', + 'Mandi Bahauddin', + 'Rovereto', + 'Jinta', + 'Araua', + 'Eugenopolis', + 'Chota Mollakhali', + 'Nabha', + 'Mit Nama', + 'Baia Mare', + 'Katridih', + 'Iwamuro-onsen', + 'Sao Miguel do Iguacu', + 'Suesca', + 'Al Mudaybi', + 'Nauen', + 'Nansio', + 'Nada', + 'Camaligan', + 'Catandica', + 'Ostrov', + 'Wargal', + 'Simarbani', + 'Santa Venera', + 'Bad Gandersheim', + 'Kumbadaje', + 'Samrong', + 'Higashiomi', + 'Chandragiri', + 'General Enrique Mosconi', + 'Seregno', + 'La Florida', + 'Envigado', + 'Landerneau', + 'Sao Pedro da Agua Branca', + 'Orion', + 'Mudgere', + 'Kentwood', + 'Hirono', + 'Kongen', + 'Swamimalai', + 'Tiruchendur', + 'Piploda', + 'Cajamarca', + 'Upata', + 'Lobau', + 'Les Pavillons-sous-Bois', + 'Karungu', + 'Araruama', + 'Fraser', + 'Queven', + 'Kibingo', + 'Senden', + 'Zarbdor Shaharchasi', + 'Goner', + 'West Athens', + 'Butembo', + 'Vadakku Valliyur', + 'Huasco', + 'Brandsen', + 'Halikko', + 'Sabinanigo', + 'Niagara Falls', + 'Sarikei', + 'Okegawa', + 'Reichenbach/Vogtland', + 'Triuggio', + 'Villa Hayes', + 'Tiruttangal', + 'Hasuda', + 'Marpingen', + 'Toms River', + 'Belalcazar', + 'Gembloux', + 'Shuizhai', + 'Ihumwa', + 'Zacualpan de Amilpas', + 'Doddappanayakkanur', + 'Covina', + 'Brikama Ba', + 'Yerkoy', + 'Essenbach', + 'Xiushui', + 'Obuase', + 'Riga', + 'Pokhara', + 'Somoniyon', + 'Itogon', + 'Zelzate', + 'Valence', + 'Bourges', + 'Samthar', + 'Elavalli', + 'Ibitinga', + 'Chembrassheri', + 'Pilao Arcado', + 'Carignan', + 'Sipilou', + 'Colonia Nicolich', + 'Valbom', + 'Naogaon', + 'Decan', + 'Nellore', + 'Makilala', + 'Borgne', + 'Santa Clarita', + 'Vadso', + 'Nandura Buzurg', + 'Polavaram', + 'Bike', + 'Lapinlahti', + 'Cambanugoy', + 'Umri', + 'Kribi', + 'Dogachi', + 'Kara-Kulja', + 'Karibib', + 'La Salvetat-Saint-Gilles', + 'Sidi Ben Adda', + 'Tinpiple', + 'Santa Perpetua de Moguda', + 'Dushanove', + 'Plewiska', + 'Filderstadt', + 'Yerres', + 'Verkhivtseve', + 'Lop Buri', + 'Saldana', + 'Gujo', + 'Dodge City', + 'Belari', + 'Minano', + 'Hamira', + 'Keles', + 'Bichena', + 'Lagoa da Prata', + 'Ormskirk', + 'Heide', + 'Borj Hammoud', + 'Zhuzhou', + 'Heilbronn', + 'Geertruidenberg', + 'Salumbar', + 'Kings Park', + 'Neralakaje', + 'Ciudad Apodaca', + 'Amircan', + 'Samalkha', + 'Hvannasund', + 'Lier', + 'Skadovsk', + 'Nong Khai', + 'Soderhamn', + 'Aghbala', + 'Ban Wisit', + 'Ahram', + 'Dianopolis', + 'North College Hill', + 'Barrechid', + 'Elandakuttai', + 'Yatagan', + 'Macae', + 'Fukayacho', + 'Camaqua', + 'Ypacarai', + 'Santa Paula', + 'Manjo', + 'Sarmada', + 'La Seyne-sur-Mer', + 'Heze', + 'Auch', + 'Nuvem', + 'Lowicz', + 'Erdokertes', + 'Kothia', + 'Bassenge', + 'Bagh-e Malek', + 'New Port Richey', + 'Soisy-sous-Montmorency', + 'Toluprpatti', + 'Niimi', + 'Huaniu', + 'Marratxi', + 'Schwerte', + 'Kontich', + 'Jaynagar', + 'Saint-Fargeau', + 'Tamm', + 'Ain Sefra', + 'Glassboro', + 'Pitoa', + 'Hohenhameln', + 'Babati', + 'Madnur', + 'Chicopee', + 'Tanza', + 'Burke Centre', + 'Guntur', + 'Arvayheer', + 'Ban Pa Hung', + 'Santa Margarita', + 'Manihari', + 'Lamorlaye', + 'Mengen', + 'Pullach im Isartal', + 'Orleaes', + 'Patuakhali', + 'Kharan', + 'Berriozar', + 'Arad', + 'Bra', + 'Bucimas', + 'Lindas', + 'Datca', + 'Vlotho', + 'Zabalj', + 'San Jose del Cabo', + 'Aflao', + 'Joliette', + 'Mamidipalli', + 'Ganguvarpatti', + 'Sitamarhi', + 'Hockessin', + 'Piamonte', + 'Arroyohondo', + 'Alapli', + 'Conflans-Sainte-Honorine', + 'San Lawrenz', + 'Cangas de Narcea', + 'Apaseo el Alto', + 'Castelfranco Emilia', + 'Boucan Carre', + 'Mongat', + 'Sutton', + 'Koungheul', + 'Capodrise', + 'Manhumirim', + 'Mohnyin', + 'San Francisco de Macoris', + 'Veraval', + 'Sint-Martens-Lennik', + 'Ban Bo Haeo', + 'Colinas', + 'Ajaigarh', + 'Arroyito', + 'Gravelines', + 'Little Lever', + 'Sayama', + 'Vitoria do Mearim', + 'Ariana', + 'Thatcham', + 'Chateaudun', + 'Laranja da Terra', + 'Sidi Azzouz', + 'Lokoja', + 'Chamgardan', + 'Worcester Park', + 'Bagnolo Mella', + 'Dewas', + 'Safo', + 'Villanueva y Geltru', + 'Shangxiao', + 'Ayabe', + 'Neo Psychiko', + 'Appenzell', + 'Pototan', + 'Carlos Casares', + 'Vandoeuvre-les-Nancy', + 'Blagoevgrad', + 'Amirli', + 'Jalalpur Jattan', + 'Bilis Qooqaani', + 'Hemsbach', + 'Woodway', + 'Stow', + 'Fukuyama', + 'Geilenkirchen', + 'Villa Isabela', + 'Mosjoen', + 'High Wycombe', + 'Yumbel', + 'Ampasimazava', + 'Mulbagal', + 'Payao', + 'New Garden', + 'Newburn', + "Ak'ordat", + 'Northborough', + 'Pueblo Bello', + 'Prijepolje', + "Espigao D'Oeste", + 'Horstel', + 'Seropedica', + 'Terrytown', + 'Kinnelon', + 'Menggala', + 'Atimonan', + 'Grand Baie', + 'Dodoni', + 'Engenheiro Coelho', + 'Santa Croce Camerina', + 'Mambajao', + 'Fateh Nangal', + 'Karimnagar', + 'Oliveira dos Brejinhos', + 'Neykkarappatti', + 'Hooglede', + 'Malacatan', + 'Gbadolite', + 'Bhai Rupa', + 'Khallikot', + 'Uiwang', + 'Kamianka', + 'Omuta', + 'Okagaki', + 'Stepanavan', + 'Kisujszallas', + 'Digar', + 'Glenwood', + 'Siqba', + 'Olsztyn', + 'Zargar', + 'Leamington', + 'Seymour', + 'Ban Mae Ngon Khilek', + 'Wyomissing', + 'Anyang', + 'Paranacity', + 'Paderno Dugnano', + 'Haselunne', + 'Kampong Thum', + 'Paldorak', + 'Brandermill', + 'Wunsiedel', + 'Ribeirao do Largo', + 'Shirud', + 'Melong', + 'Romeoville', + 'Palma Soriano', + 'Filadelfia', + 'Taiyuan', + 'Medicina', + 'Kara', + 'Perunturuttu', + "Sant'Eufemia Lamezia", + 'Villa Canales', + 'Boankra', + 'Dildarnagar', + 'Arraijan', + 'Sonzacate', + 'Manghit', + 'La Valette-du-Var', + 'Loon op Zand', + 'Mutis', + 'Ewa Gentry', + 'Congonhal', + 'Tirua', + 'Firuzoba', + 'Mushin', + 'Okazaki', + 'Thornton', + 'Torbali', + 'Rumburk', + 'Sgamna', + 'Bel-Air', + 'Cassia', + 'Oliveira de Azemeis', + 'Sangrur', + 'Thongwa', + 'Cunco', + 'Bonn', + 'Kalanadu', + 'Magalia', + 'Ficarazzi', + 'Bemarivo', + 'Hadim', + 'Forster', + 'Mahis', + 'Axixa', + 'Putignano', + 'Claye-Souilly', + 'Jaguariuna', + 'Kilifi', + 'Santo Cristo', + 'Gandlapenta', + 'Langenhagen', + 'Orillia', + 'Tshilenge', + 'Donggou', + 'West Lincoln', + 'Victoria', + 'Hoh Ereg', + 'Queensbury', + 'Snovsk', + 'Dabrowa Gornicza', + 'Rosenberg', + 'Nayanakulam', + 'Kreminna', + 'Bissora', + 'Brezno', + 'Xireg', + 'Wittlich', + 'Kanyana', + 'Ohrdruf', + 'Libagon', + 'Fot', + 'Ban Ratchakrut', + 'Xinnongcun', + 'Sotik', + 'Hindarx', + 'Engelskirchen', + 'Marcos', + 'San Miguel Acatan', + 'Mariano Escobedo', + 'Capdepera', + 'Camarate', + 'Corinth', + 'Mejicanos', + 'Sirohi', + 'Takhli', + 'Hodonin', + 'Dabat', + 'Humansdorp', + 'Doncaster', + 'Ballitoville', + 'Combita', + 'Beilngries', + 'Soanierana Ivongo', + 'Mella', + 'Poti', + 'Dongola', + 'Deptford', + 'Azaourisse', + 'Itabirinha de Mantena', + 'Saluzzo', + 'Dumbravita', + 'Cacongo', + 'Mechelen', + 'Sablan', + 'Doaba', + 'Borre', + 'Benghazi', + 'Vasilevo', + 'Nyuzen', + 'Thames Centre', + 'Chavara Gramam', + 'Nivelles', + 'Fairmont', + 'Villa Luzuriaga', + 'Carletonville', + 'Varash', + 'Montemurlo', + 'Mukocho', + 'Sa Kaeo', + 'Gonegandla', + 'Bebandem', + 'Kulp', + 'Plainsboro', + 'Pedro Leopoldo', + 'Mokolo', + 'Mesolongi', + 'Formosa do Rio Preto', + 'Vellmar', + 'Yoko', + 'Sax', + 'Sirvar', + 'Boadilla del Monte', + 'Ziama Mansouria', + 'Brasov', + 'Remedios', + 'Rita', + 'Thane', + 'Fukusaki', + 'Pontypridd', + 'Beysehir', + 'Uchquduq Shahri', + 'Feilding', + 'Silves', + 'Galvan', + 'Great Linford', + 'Zimna Voda', + 'Hirado', + 'Edinburgh of the Seven Seas', + 'Vellodu', + 'Prayagraj', + 'Clermont-Ferrand', + 'La Crosse', + 'San Cristobal Verapaz', + 'Apollo Beach', + 'Cerete', + 'Leskovac', + 'Poltava', + 'Anan', + 'Al Fujayrah', + 'Leramatang', + 'Guastatoya', + 'Fort Wellington', + 'Erumad', + 'Genet', + 'Jondor Shaharchasi', + 'Pudong', + 'Dip', + 'Bystrc', + 'Gakuch', + 'Napoleon', + 'Mathigeri', + 'Hathapur', + 'Kinh Mon', + 'Eidsberg', + 'Quincy-sous-Senart', + 'Yardimli', + 'San Juan Cancuc', + 'Kolbuszowa', + 'Conegliano', + 'Eski Ikan', + 'Hildburghausen', + 'Tirubhuvane', + 'Nikaido-kaminoshocho', + 'Simbahan', + 'Havixbeck', + 'Para', + 'Blomberg', + 'Tionk Essil', + 'Clearview', + 'Imassogo', + 'Whittlesey', + 'Panchgani', + 'Gumani', + 'Kaikkudi', + 'Amatepec', + 'Klotze', + 'Kohtla-Jarve', + 'Vilanova del Cami', + 'Belison', + 'Kakinada', + 'Monte Alto', + 'Walldorf', + 'Alangalang', + 'Carson City', + 'Moises Padilla', + 'Ad Dir`iyah', + 'Hlatikulu', + 'Vigna di Valle', + 'Mosta', + 'Eastern Goleta Valley', + 'Ballenger Creek', + 'Tsukubamirai', + 'Metu', + 'Modachchur', + 'Sukabumi', + 'San Nicolas de los Arroyos', + 'Umingan', + 'Tinnevelly', + 'San Juan Opico', + 'San Vicente de Chucuri', + 'Jacunda', + 'Kaura Namoda', + 'Lodi', + 'Nakhon Sawan', + 'Dunwoody', + 'Katahra', + 'Zhonghechang', + 'Troyes', + 'Goalundo Ghat', + 'Saadatpur Aguani', + 'Ji-Parana', + 'Baroy', + 'Scoresbysund', + 'Santurce-Antiguo', + 'Gagny', + 'La Libertad', + 'Beypore', + 'Puerto Cumarebo', + 'Rasol', + 'Kamalia', + 'Singhana', + 'Vancouver', + 'Angouleme', + 'Cacapava', + 'Laurinburg', + 'Ilhavo', + 'Rangamati', + 'Leogane', + 'Ilkeston', + 'Luganville', + 'Somerville', + 'Biot', + 'Nanyang', + 'Sidi Yahya Zaer', + 'Saltangara', + 'Ban Doi Suthep', + 'San Lorenzo de Esmeraldas', + 'Srinagar', + 'Alberton', + 'Khenchela', + 'Belcista', + 'Chiramanangad', + 'Ordu', + 'Channubanda', + 'Niandjila', + 'Tellicherry', + 'Steenokkerzeel', + 'Conceicao do Rio Verde', + 'Kusapin', + 'Sanjat', + 'Nanxicun', + 'Cedros', + 'Soanenga', + 'La Orotava', + 'Pasvalys', + 'Verdal', + 'Romans-sur-Isere', + 'Katangi', + 'Zhob', + 'Frosinone', + 'Plan-de-Cuques', + 'Bree', + 'Sveti Nikole', + 'Ciudad Tecun Uman', + 'Helsinge', + 'Velez', + 'Balcova', + 'Beni Yakhlef', + 'Arumuganeri', + 'Condado', + 'Xiangkhoang', + 'Parsons', + 'Rouissat', + 'Cetraro', + 'Ozieri', + "Say'un", + 'San Luis Jilotepeque', + 'Vynohradiv', + 'Nampula', + 'Kunsan', + 'Hounde', + 'Robertson', + 'Oarai', + 'Sigus', + 'Golborne', + 'Richmond Heights', + 'Gateshead', + 'Zhenbeibu', + 'Chesham', + 'Canals', + 'Bakau', + 'Belas', + 'Hurricane', + 'Oyo', + 'Ciudad Piar', + 'Palmerston', + 'Chik Ballapur', + 'Bressuire', + 'Mountain Park', + 'Pantelimon', + 'Gooik', + 'Flitwick', + 'Kulattur', + 'Plumstead', + 'Verzej', + 'Kapasiawan', + 'Olds', + 'Nidgundi', + 'Santo Antonio', + 'Dimitrovgrad', + 'Oued Zenati', + 'Kahramanmaras', + 'Chengtangcun', + 'Gonikoppal', + 'Skidaway Island', + 'Moriguchi', + 'Devonport', + 'Samamea', + 'Tsimafana', + 'Lakeside', + 'San Matias', + 'Visconde do Rio Branco', + 'Rivarolo Canavese', + 'Normal', + 'Bahharet Oulad Ayyad', + 'Hurzuf', + 'Allendale', + 'Saint-Charles-Borromee', + 'Netivot', + 'Tunasan', + 'Mazagao', + 'Czarnkow', + 'Ubatuba', + 'Baco', + 'Aralik', + 'Rosamond', + 'Masindi', + 'Vargem da Roca', + 'Mbeya', + 'Byram', + 'Court-Saint-Etienne', + 'Karath', + 'Sidcup', + 'Anage', + 'Midway', + 'Mountain Ash', + 'Agouna', + 'Iakora', + 'Adendorf', + 'Warni', + 'Nakhon Nayok', + 'G`ozg`on', + 'Achacachi', + 'Soamanova', + 'Sao Mamede de Infesta', + 'Brumadinho', + 'Kosamba', + 'Sabuncu', + 'Alicante', + 'Youganning', + 'Neviges', + 'Jaro', + 'Juangriego', + 'Meshkin Dasht', + 'Veinticinco de Mayo', + 'Buyan', + 'Khirbat Ghazalah', + 'Dabola', + 'Bundehra', + 'Bierbeek', + 'Gherla', + 'Tammampatti', + 'Avranches', + 'Dubbo', + 'Southport', + 'Ban Om Noi', + 'Koumra', + 'Bridgeview', + 'Madipakkam', + 'Fiche', + 'Gura Humorului', + 'Satsumasendai', + 'Nautan Dube', + 'Ngaputaw', + 'Erlin', + 'Segorbe', + 'Khandela', + 'Bikrampur Bande', + 'Diavata', + 'Taurage', + 'Tula de Allende', + 'Minato', + 'Tumba', + "Trostyanets'", + 'La Matanza de Acentejo', + 'Sathmalpur', + 'Coycoyan de las Flores', + 'Sierra Madre', + 'Masjed Soleyman', + 'Yokoshibahikari', + 'Trezzano sul Naviglio', + 'Leon', + 'Xinpu', + 'Karacabey', + 'Graaff-Reinet', + 'Maputo', + 'Bargoed', + 'Ndali', + 'Vettikkavala', + 'Bat Yam', + 'Boxmeer', + 'Anao', + 'Riccione Marina', + 'Marilao', + "Saint-Martin-d'Heres", + 'Badamdar', + 'Shaoguan', + 'Asker', + 'Benedito Novo', + 'Az Zubayr', + 'Nemyriv', + 'Madanpur', + 'Hakha', + 'Bumba', + 'Fushe Kosove', + 'Shahrisabz', + 'Clondalkin', + 'Delvada', + 'Waldwick', + 'Pemagatshel', + 'Tubingen', + 'Ejido', + 'Awankh', + 'Shyorongi', + 'Houghton le Spring', + 'Albert Lea', + 'Lazdijai', + 'Sanando', + 'Galugah', + 'Nagcarlan', + 'Huong Thuy', + 'Nettuno', + 'Baalbek', + 'Kunnamkulam', + 'Oiso', + 'Barra do Sul', + 'Bishunpur Hakimabad', + 'North Adams', + 'Shamsa', + 'Madhuban', + 'Tirumala', + 'Ganthier', + 'Guben', + 'Lakamane', + 'Preakness', + 'Caraguatatuba', + 'Ferrol', + 'Partibanur', + 'Venkatadripalem', + 'Aquidaba', + 'Sedico', + 'Baixo Guandu', + 'Navadwip', + 'Zgharta', + 'Morro Bay', + 'Miramichi', + 'Jose Batlle y Ordonez', + 'Zuwarah', + 'Espinal', + 'Brcko', + 'Cham', + 'Kika', + 'Helixi', + 'Pillaro', + 'Lam Tin', + 'Trzebiatow', + 'Nidda', + 'Paulo Lopes', + "Santa Barbara d'Oeste", + 'San Pedro de Ycuamandiyu', + 'Wenchang', + 'Hovd', + 'Scunthorpe', + 'Maspalomas', + 'Oskemen', + 'Raibhir', + 'Palmview', + 'Herrsching am Ammersee', + 'Frederikssund', + 'Yachimata', + 'Rosario de la Frontera', + 'Sinimbu', + 'Valdagno', + 'Roseto degli Abruzzi', + 'Sidi Allal Tazi', + 'Gantt', + 'Pulimel', + 'Ambatomainty', + 'Kumaripur', + 'Haldwani', + 'Zwiesel', + 'Nanqiaotou', + 'Jovellar', + 'Mizhou', + 'Asafabad', + 'Kielczow', + 'Ciying', + 'Erice', + "Palmeira d'Oeste", + 'Comiso', + 'Colac', + 'St. Peters', + 'Gutersloh', + 'Chililabombwe', + 'Joure', + 'Axixa do Tocantins', + 'Celeken', + 'Khvansar', + 'Shepperton', + 'Baghdad', + 'Darwin', + 'Pasaco', + 'Diamond Harbour', + 'Tiruvallur', + 'Hackettstown', + 'Santo Antonio da Platina', + 'General Eugenio A. Garay', + 'St. Helens', + 'Hollister', + 'Patra', + 'Casalmaggiore', + 'Villarrubia de los Ojos', + 'Brejo da Madre de Deus', + 'Attapu', + 'Bambous', + 'Neuenhof', + 'Massape', + 'Hurlingham', + 'Longxing', + 'Xinjun', + 'Yaofeng', + 'Ipubi', + 'Sarikaya', + 'Pambadi', + 'Qinggang', + 'Pirai do Norte', + 'Tha Mai', + 'Scranton', + 'Dang`ara', + 'Murliganj', + 'Villa Sola de Vega', + 'Diedorf', + 'Panchi', + 'Pagadian', + 'Unna', + 'Dongyuancun', + 'Joacaba', + 'San Andres de Giles', + 'Niigata', + 'Bihat', + 'Torqabeh', + 'Rio do Fogo', + 'Yogyakarta', + 'Candido Sales', + 'Barangka', + 'Paramati', + 'Imito', + 'Sugar Land', + 'Kyaliwajjala', + 'Silappadi', + 'Golfito', + 'Kilcock', + 'Moinesti', + 'Gujrat', + 'Keevallur', + 'Culasi', + 'Inanantonana', + 'Sidi Ghiles', + 'Cacolo', + 'Nierstein', + 'Guia Lopes da Laguna', + 'Takieta', + 'Lumaco', + 'Gatteo', + 'Weehawken', + 'Logan', + 'Olimpia', + 'Sidi Zouine', + 'Pardanjan', + 'Celle', + 'Santa Brigida', + 'Kifisia', + 'Leimen', + 'Denizciler', + 'Berezhany', + 'Rangkasbitung', + 'Pagidyala', + 'Infanta', + 'Hackensack', + 'Nakhon Pathom', + 'Tamsaout', + 'Towson', + 'San Teodoro', + 'Mahmuda', + 'Port-Gentil', + 'Federal Way', + 'Kondapalle', + 'Missao Velha', + 'Castres', + "Ash Shuhada'", + 'Almusafes', + 'Limbiate', + 'Jiguani', + 'Amherstburg', + 'Ryde', + 'Nazare Paulista', + 'Lqoliaa', + 'Balua', + 'Pathrajolhania', + 'Ain Karma', + 'Ekangar Sarai', + 'Dunhua', + 'Cherupulassheri', + 'Vutukuru', + 'Cesario Lange', + 'Coevorden', + 'Xiayang', + 'Converse', + 'Shivpuri', + 'Lido di Iesolo', + 'Capao do Leao', + 'Yangliuqing', + 'Kanata', + 'Vientiane', + 'Darhan', + 'Pola', + 'Bardai', + 'Taskopru', + 'Marcq-en-Baroeul', + 'Chestnuthill', + 'Tonse West', + 'Ibirapitanga', + 'Carmo de Minas', + 'Nirala', + 'Gardner', + 'Chorozinho', + 'Novo Selo', + 'Koilkuntla', + 'Ixmiquilpan', + 'Pinole', + 'Kirkby', + 'Rokytne', + 'Haivoron', + 'Charana', + 'Shreveport', + 'Dunkerque', + 'Businga', + 'El Salvador', + 'Teustepe', + 'Begowal', + 'Al `Ayn', + 'Xiaguanying', + 'Mhow', + 'Vittorio Veneto', + 'Savignano sul Rubicone', + 'Bitola', + 'Chomutov', + 'Natividad', + 'Pont-a-Mousson', + 'Ballincollig', + 'Ballymoney', + 'Peixe', + 'As Saff', + 'San Antonio de Areco', + 'Ibi', + 'Hathwan', + 'Esperance', + 'Wangjiabian', + 'Pokrovsk', + 'Davao', + 'Anniston', + 'Rodental', + 'Maple Ridge', + 'Esneux', + 'Ahwa', + 'Monticello Conte Otto', + 'Royal Leamington Spa', + 'Carei', + 'Real', + 'Burjasot', + 'Pingdingshan', + 'Wumayingcun', + 'Asane', + 'Souto Soares', + 'Arvada', + 'Palu', + 'Narasapur', + 'Ivry-sur-Seine', + "Saint-Ouen-l'Aumone", + 'High Blantyre', + 'Draganesti-Olt', + 'Pattoki', + 'Cologno Monzese', + "Ville-d'Avray", + 'Dornava', + 'Ambatomanoina', + 'Qinbaling', + 'So', + 'Villanchirai', + 'Emet', + 'Agatogba', + 'Saint-Laurent-du-Var', + 'Airway Heights', + 'Brasil Novo', + 'Fangting', + 'Mutukuru', + 'Erlensee', + 'Mangur', + 'Olivenca', + "L'Isle-Jourdain", + 'Kodmial', + 'Manresa', + 'Antsahadinta', + 'Fort-Shevchenko', + 'Eisenhuttenstadt', + 'Nicastro', + 'Widekum', + 'Delmenhorst', + 'San Gwann', + 'Soalala', + 'Soweto', + 'Pachor', + 'Naugachhia', + 'Mount Isa', + 'Afmadow', + 'Suzukawa', + 'Radcliffe', + 'Boksburg', + 'Hipperholme', + 'Harim', + 'Chinnampalaiyam', + 'Tilari', + 'Giporlos', + 'Perleberg', + 'Bankya', + 'Capua', + 'Lilio', + 'Qinzhou', + 'Aratuipe', + 'Itaborai', + 'Oldebroek', + 'Tibbar', + 'Douar Ain Chkef', + 'Nueva Tolten', + 'Tetela de Ocampo', + 'Denby Dale', + 'Viareggio', + 'Gangadhar', + 'Durgapur', + 'Arcahaie', + 'Kupiansk', + 'Achhnera', + 'Cherupazhasshi', + 'Benalla', + 'Labhgaon', + 'Bou Fekrane', + 'Chahbounia', + 'Middlebury', + 'Wallerfangen', + 'Fribourg', + 'Chilly-Mazarin', + 'Tibu', + 'Wachtersbach', + 'Valparaiso', + 'Vettavalam', + 'Zamania', + 'Farmers Branch', + 'Neqab', + 'Ayinikkad', + 'Messkirch', + 'Nagamangala', + 'Joinvile', + "M'diq", + 'Schwaigern', + 'Ban Bang Phun', + 'Xudat', + 'Silay', + 'Thikriwala', + 'Lake Wylie', + 'Doukombo', + 'Tual', + 'Phu Quoc', + 'Huludao', + 'Jabonga', + 'Uetze', + 'San Mauro Pascoli', + 'Sao Desiderio', + 'Brignais', + 'Rancho Cordova', + 'Pelezi', + 'Sangota', + 'Ikhlaspur', + 'Guaratuba', + 'Mibu', + 'Arris', + 'Lysander', + 'Kameda-honcho', + 'Mzuzu', + 'Shibukawa', + 'Dongyuya', + 'Allahpur', + 'Harrodsburg', + 'Brig-Glis', + 'Villa San Giovanni', + 'Zhangaozen', + 'Alabang', + 'Saint-Jacques-de-la-Lande', + 'Rampur Rajwa', + 'Te Anau', + 'Ashwaraopeta', + 'Fridley', + 'Hukou', + 'Yerere', + 'Itajuipe', + 'Toda Rai Singh', + 'Oconomowoc', + 'Hudiksvall', + 'Ploiesti', + 'Camilo Ponce Enriquez', + 'Aheqi', + 'Povoa de Santa Iria', + 'Salaspils', + 'Marti', + 'Heswall', + 'Barcelos', + 'Axim', + 'Datoda', + 'Kandra', + 'Montreuil', + 'Lakhnadon', + 'Tarnok', + 'Brades', + 'Sabana Yegua', + 'Ed Daein', + 'Mchinji', + 'Jaral del Progreso', + 'Bouskoura', + 'Gradignan', + 'Norresundby', + 'Bairagnia', + 'Chai Prakan', + 'Cocos', + 'Mwingi', + 'Lucao', + 'Matauna', + 'Pihani', + 'Taishan', + 'Mocamedes', + 'Didieni', + 'Ankiabe-Salohy', + 'Dammapeta', + "La'tamna", + 'Upi', + 'Annakunnu', + 'Iizuka', + 'Pattani', + 'Qiqihar', + 'Maharlika Village', + 'Harborne', + 'Chamusca', + 'Nanshuicun', + 'Milledgeville', + 'Seven Pagodas', + 'Semirom', + 'Candiba', + 'Antofagasta', + 'Tayug', + 'Konobougou', + 'Profesor Salvador Mazza', + 'Perry Heights', + 'Charouine', + 'Unterschleissheim', + 'Kyzyl-Kyya', + 'Hadjout', + 'Zhailuo', + 'Bobigny', + 'Champs-Sur-Marne', + 'Amatan', + 'Tadmait', + 'Zao', + 'Temperance', + 'Grenaa', + 'Zebala', + 'Steynsrus', + 'Buka', + 'Itapororoca', + 'Maranchi', + 'Sikandra Rao', + 'Neftcala', + 'Nguekhokh', + 'Pawtucket', + 'Mechanicsburg', + 'Mold', + 'Tipitapa', + 'Gobindgarh', + 'Bemanevika', + 'Sureshjan', + 'Abomey-Calavi', + 'Caracuaro', + 'Vohimarina', + 'Didim', + 'Getulio Vargas', + 'Hoogvliet', + 'Denton', + 'Rodgau', + 'Abbiategrasso', + 'Oum Drou', + 'Sagwara', + 'Huetor-Tajar', + 'Canovellas', + 'Calan', + 'Droitwich', + 'Gradacac', + 'Czechowice-Dziedzice', + 'Newton in Makerfield', + 'Zabreh', + 'Otavi', + 'Molina', + 'Duncanville', + 'Kumaramputtur', + 'Visnagar', + 'Ichikawa', + 'Shiojiri', + 'Trinity', + 'Shchuchinsk', + 'Kemberg', + 'Isla', + 'Bedele', + 'Cocorna', + 'Pozo Colorado', + 'Motobu', + 'Rodinghausen', + 'Osterhofen', + 'Beckwith', + 'Yafran', + 'Buguey', + 'Hawkesbury', + 'Seria', + 'New London', + 'Agia Varvara', + 'Talisayan', + 'Pothuhera', + 'Tiruppuvanam', + 'Koumpentoum', + 'Sesquile', + 'Freehold', + 'El Haouaria', + 'Tall Rif`at', + 'Nova Timboteua', + 'Novi Iskar', + 'Choghadak', + 'Trinitapoli', + 'Orimattila', + 'Mussoorie', + 'Kozan', + 'Mahatsinjo', + 'Guajiquiro', + 'Bear', + 'Zhoushan', + 'Safford', + 'M.A. Rasulzada', + 'Kalaun', + 'Grijo', + 'San Cristobal Totonicapan', + 'Marbach am Neckar', + 'Panukulan', + 'Salcininkai', + 'Neptune', + 'Cerro de Pasco', + 'Pisac', + 'Puttankulam', + 'Vordingborg', + 'Coto de Caza', + 'Ahumada', + 'Angicos', + 'Jeonju', + 'Detroit', + 'La Gi', + 'Puerto Ayacucho', + 'La Reja', + 'Mymensingh', + 'Bondy', + 'Altoona', + 'Loberia', + 'Novooleksiivka', + 'Vriddhachalam', + 'Tirumalaippatti', + 'Kontcha', + 'Chennai', + 'Nagykata', + 'Havre de Grace', + 'Jimani', + 'Beaune', + 'Montornes del Valles', + 'Dothan', + 'Saiki', + 'Indaial', + 'Nantwich', + 'Foshan', + 'Abu Hamad', + 'Prilly', + 'Chelora', + 'Santa Isabel Ishuatan', + 'Urpaar', + 'Highfields', + 'Choix', + 'Poway', + 'Ormeau', + 'Pulivalam', + 'Maruim', + 'Minobu', + 'Circleville', + 'Noksan', + 'Almada', + 'Sali', + 'New Brunswick', + 'Ottapparai', + 'Sadabe', + 'Tomi', + 'Ramanayakkanpalaiyam', + 'Golpazari', + 'Grunheide', + 'Punalur', + 'Essex Junction', + "Ibra'", + 'Balupur', + 'Collegno', + 'Gzira', + 'Santa Cruz', + 'Les Irois', + 'Lobos', + 'Slubice', + 'Ichinohe', + 'Phonsavan', + 'Had Oulad Issa', + 'Diffun', + 'Cuijk', + 'Algete', + 'Laascaanood', + 'Sayo', + 'Sayada', + 'Xonqa', + 'Numan', + 'Benetuser', + 'Ilaka Atsinanana', + 'Debno', + 'Nagtipunan', + 'Chegutu', + 'Yabu', + 'Maskanah', + 'Tiruvankod', + 'Japaratinga', + 'Horodok', + 'Maevatanana', + 'Lanester', + 'Jequitinhonha', + 'Gibraltar', + 'Acqui Terme', + 'Acasusso', + 'Cumberland', + 'Yildizeli', + 'Coronel Bogado', + 'Daruvar', + 'Dupax del Sur', + 'Gharb', + 'Becerril', + 'Peachtree City', + 'Najrij', + 'Pabna', + 'Millstone', + 'Blidet Amor', + 'Kayapa', + 'Progress', + 'San Pedro del Pinatar', + 'Ambakireny', + 'Afranio', + 'Salangaippalaiyam', + 'Cupira', + 'Elmas', + 'Taunton', + 'Bianyang', + 'Piracaia', + 'Pudsey', + 'Qiryat Ata', + 'Lusaka', + 'Carterton', + 'Robbinsville', + 'Namorona', + 'Vicam Pueblo', + 'Baytown', + 'Kapfenberg', + 'Makoua', + 'Sobral de Monte Agraco', + 'Belek', + 'Rio de Oro', + 'Biga', + 'Shiliguri', + 'Agdas', + 'Bougara', + 'Mit Damsis', + 'Alto Alegre dos Parecis', + 'Cantillana', + 'Waldfeucht', + 'Urcos', + 'Kishanpura Kalan', + 'Buchloe', + 'Suffolk', + 'Gummersbach', + 'Khandhar', + 'Coracora', + 'Mpondwe', + 'Lalin', + 'Xiulin', + 'Chanwari', + 'Kumba', + 'Aware', + 'Colgong', + 'Zeven', + 'Mariano Comense', + 'Campos Lindos', + 'Diu', + 'Aligarh', + 'Nova Pazova', + 'Barhni', + 'Djibo', + 'Soddy-Daisy', + 'Seneffe', + 'Tarn Taran', + 'Dragasani', + 'Bannewitz', + 'Badagabettu', + 'Angichettippalaiyam', + 'Heroica Nogales', + 'Osecina', + 'Kuhsan', + 'Grimstad', + 'Tufanbeyli', + 'Sweetwater', + 'Chandur', + 'Novyi Buh', + 'Alzey', + 'Telsiai', + 'Purwokerto', + 'Tarakeswar', + 'Slupca', + 'Malone', + 'Nowrangapur', + 'Khorol', + 'Gudofredo Viana', + 'Od', + 'Tavriisk', + 'Shakhtarsk', + 'Silago', + 'Muskego', + 'Kartarpur', + 'Shofirkon Shahri', + 'Zhangjiakou Shi Xuanhua Qu', + 'Lloyd', + 'Togane', + 'Minabe', + 'Paloma Creek South', + 'Koelwar', + 'Takestan', + 'Cotorra', + 'Lugang', + 'Osaki', + 'Adiyakkamangalam', + 'Fatipura', + 'Jiaoxiyakou', + 'Lakkireddipalle', + 'Calamar', + 'Eastbourne', + 'Manlleu', + 'Santo Andre', + 'Glowno', + 'Ozorkow', + 'Herzliyya', + 'Zaladanki', + 'Druzhkivka', + 'Naron', + 'Nasim Shahr', + 'Penicuik', + 'Kamianets-Podilskyi', + 'Rezzato', + 'Wandlitz', + 'Eufaula', + 'El Hamma', + 'Kattirippulam', + 'Tafo', + 'Bad Sassendorf', + 'Tuticorin', + 'Venado Tuerto', + 'Kanasanapalle', + 'Paulistana', + 'Tauberbischofsheim', + 'Mino', + 'Bapaura', + 'Lao Cai', + 'Winchendon', + 'Akyazi', + 'Baclayon', + 'Radhanpur', + 'Inkerman', + 'Donsol', + 'Vila Real de Santo Antonio', + 'Bottrop', + 'South Orange Village', + 'Grezzana', + 'Konkavaripalle', + 'Nybro', + 'Dharmastala', + 'Waldbrol', + 'Shimomura', + 'Hangal', + 'Ribeirao das Neves', + 'Hachirud', + 'Asmara', + 'Mercogliano', + 'Isparta', + 'Choshi', + 'Rosetta', + 'Shimotsuma', + 'Souagui', + 'Nishigo', + 'Duitama', + 'Salkhad', + 'Tenares', + 'Paita', + 'Zephyrhills', + 'Nacaome', + 'Lezignan-Corbieres', + 'Moncks Corner', + 'Maracena', + 'Gutao', + 'Coseley', + 'Susurluk', + 'Hoofddorp', + 'Taufkirchen', + 'Lebork', + 'West Bridgford', + 'Roda', + 'Laatatra', + 'Sin-le-Noble', + 'Lake Morton-Berrydale', + 'Junik', + 'Gorey', + 'Ferrara', + 'Falla', + 'Atotonilco el Grande', + 'Barnala', + 'Port Chester', + 'Rutland', + 'Gistel', + 'Palestina de los Altos', + 'Manujan', + 'Koja', + 'Vitre', + 'Antsambalahy', + 'Ewo', + 'Silivri', + 'Nitte', + 'Riyadh', + 'Ginir', + 'Figueras', + 'Porvoo', + 'Belamoty', + 'Vista Hermosa de Negrete', + 'Heysham', + 'Laoac East', + 'Ad Dammam', + 'Chisinau', + 'Lanus', + 'Lockport', + 'Powder Springs', + 'Panamarattuppatti', + 'Bisingen', + 'Cotacachi', + 'Bayanan', + 'Ozoir-la-Ferriere', + 'Ouyen', + 'Kuttuparamba', + 'Velimese', + 'Nabeul', + 'Anisio de Abreu', + 'Uozu', + 'Cumaribo', + 'Bhadravati', + 'Kuroshio', + "Barano d'Ischia", + "Qian'an", + 'Oulmes', + 'Bethulie', + 'Tebessa', + 'Columbia City', + 'Kalvarpatti', + 'Nesconset', + 'Quilali', + 'Uddevalla', + 'Teplice', + 'Pindobacu', + 'Xihu', + 'Altonia', + 'Asudapuram', + 'North Fayette', + 'Konstantynow Lodzki', + 'Castellanza', + 'Penalolen', + 'Zimatlan de Alvarez', + 'Minad', + 'Martellago', + 'Chitral', + 'Yumbo', + 'Dunajska Streda', + 'Didy', + 'Horquetas', + 'Pinas', + 'Farragut', + 'Castro Alves', + 'Saatli', + 'Naranapuram', + 'Pine Castle', + 'Penzberg', + 'Fomeque', + 'Goodmayes', + 'Aru', + 'Dobrovo', + 'Martinez de la Torre', + 'West Glens Falls', + 'Vaddadi', + 'Barra da Estiva', + 'Whitefield', + 'Milford city', + 'Guarulhos', + 'Fangchenggang', + 'Edwardsville', + 'Broussard', + 'Lieto', + 'Quimili', + 'Kaiyun', + 'Mocha', + 'Volkach', + 'Vazante', + 'Thu Duc', + 'Penapolis', + 'Nanchital de Lazaro Cardenas del Rio', + 'Phayao', + 'Talwat', + 'Tineo', + 'Opwijk', + 'Diabali', + 'Andranovorivato', + 'Huron East', + 'Poirino', + 'Juquitiba', + 'Tizi Gheniff', + 'Rudolstadt', + 'Kozhinjampara', + 'Huangyoutang', + 'Triel-sur-Seine', + 'Bordj el Kiffan', + 'Unwana', + 'Vanthli', + 'Gramado', + 'Ogawara', + 'Arbatache', + 'Mubende', + 'Itaperuna', + 'Beccles', + 'Balabagan', + 'Jeomchon', + 'Fountain Inn', + 'Passaic', + 'Apaxco de Ocampo', + 'Bhairi', + 'Kalayapuram', + 'Tlahualilo de Zaragoza', + 'Mangasamudram', + 'Kvivik', + 'Arnstadt', + 'South Lebanon', + 'Vinnytsia', + 'Bhimbar', + 'Panakkudi', + 'Paraisopolis', + 'Deux-Montagnes', + 'Antarvedipalem', + 'Pushing', + 'Ichinomiya', + 'Padre Bernardo', + 'Jiblah', + 'Bestwig', + 'Tuba', + 'Porto Amboim', + 'Gonohe', + 'Caernarfon', + 'Oostakker', + 'Ataq', + 'General Panfilo Natera', + 'Sabratah', + 'Andira', + 'Ichtegem', + 'Coban', + 'Sangli', + 'Balhapur', + 'Narayanraopet', + 'Paimio', + 'Alvorada do Sul', + 'El Transito', + 'Tonk', + 'Methil', + 'Ban Phonla Krang', + 'Arac', + 'Selydove', + 'Pecinci', + 'Benidorm', + 'Binkolo', + 'Kailaras', + 'Quibdo', + 'Nieuw Nickerie', + 'Magstadt', + 'Bhirua', + 'Pallipalaiyam', + 'Ampasimatera', + 'Vila do Conde', + 'Fariman', + 'Darihat', + 'Jurong', + 'Zurrieq', + 'Oschatz', + 'Godella', + 'Martano', + 'Wuhu', + 'Gafanha da Nazare', + 'Elsmere', + 'Malior', + 'Sidi el Mokhfi', + 'Mingxing', + 'Elsen', + 'Zinvie', + 'Orange', + 'Rakovnik', + 'Courcouronnes', + 'Eregli', + 'Shengaocun', + 'Badkulla', + 'Zile', + 'North Highlands', + 'Bhubaneshwar', + 'Deurne', + 'Bassano del Grappa', + 'Paonta Sahib', + 'Chapantongo', + 'Samannud', + 'Narayanpet', + 'Chintapalle', + 'Myslenice', + 'Pama', + 'Pedro II', + 'Imperial', + 'Tuvagudi', + 'Erftstadt', + 'Ningbo', + 'Burglengenfeld', + 'Coatepec', + 'Horr-e Riahi', + 'Duayaw-Nkwanta', + 'Unchagao', + 'Sayram', + 'Herouville-Saint-Clair', + 'Nurhak', + 'Joniskis', + 'Fish Town', + "Vranov nad Topl'ou", + 'Thief River Falls', + 'North Miami', + 'Szarvas', + 'Poing', + 'Xanxere', + 'Bulolo', + 'Tin Shui Wai', + 'Auriol', + 'La Calera', + 'Mannachchanellur', + 'San Miguelito', + 'Harsefeld', + 'Zdunska Wola', + 'Hellin', + 'Tours', + 'Uryzhar', + 'Villebon-sur-Yvette', + "'Ain Kihal", + 'Ocean Acres', + 'Paranagua', + 'Coaraci', + 'Saaminki', + 'Ullur', + 'Muttatodi', + 'Abashiri', + 'Tadikalapudi', + 'Mahin', + 'Duderstadt', + 'Utazu', + 'Oleiros', + 'Bolekhiv', + 'Beuvry', + 'Ilagan', + 'Lakhipur', + 'Tepotzotlan', + 'Vallendar', + 'Quimavango', + 'Cobh', + 'Ayutla', + 'Pau', + 'Ngong', + 'Doorn', + 'Libenge', + 'Bin-Houye', + 'Shahr-e Kord', + 'Santiago de Maria', + 'Sabya', + 'Sunninghill', + 'Alhama de Murcia', + 'Usakos', + 'Boke', + 'Ingichka', + 'Montgomery Village', + 'Almonte', + 'Campagnano di Roma', + 'Akbou', + 'Andaingo Gara', + 'Herzberg', + 'Sande', + 'Aracataca', + 'Dipaculao', + 'La Celle-Saint-Cloud', + 'Soja', + 'Semari', + 'Bareilly', + 'Mahna', + 'Wandsworth', + 'Danwan', + 'Manganam', + 'Dinant', + 'Delran', + 'Shangzhen', + 'Mallampalli', + 'Czluchow', + 'San Borja', + 'Sanya', + 'Galion', + 'Tinchlik', + 'Show Low', + 'Mbouda', + 'Hong Kong', + 'Cedar Hill', + 'Baraawe', + 'Rabaul', + 'Matsukawa', + 'Farum', + 'Jishi', + 'Rush', + 'Ubay', + 'Schleusingen', + 'Hengken', + 'Pawai', + 'Margherita di Savoia', + 'Togba', + 'Faradabad', + 'Soron', + 'Ban Tha Mai I', + 'Santa Marta de Tormes', + 'Llantrisant', + 'Huauchinango', + 'Darmaha', + 'Hadano', + 'Porto Real', + 'Pakri', + "N'Djamena", + 'Skuvoy', + 'Novopokrovka', + 'Dighirpar', + 'Summerside', + 'Young', + 'Campagna', + 'Chavuttahalli', + 'Malalbergo', + 'San Victor Abajo', + 'Robertsganj', + 'Toubakoro', + 'Namakadu', + 'Clayton', + 'Xalqobod', + 'Moerdijk', + 'Bergerac', + 'Linxi', + 'La Barca', + 'Hopewell', + 'Riverview', + 'Nanfang', + 'Garwolin', + 'Gannan', + 'Cowell', + 'Zhongguyue', + 'Cacapava do Sul', + 'Fenyang', + 'Chimore', + 'Bahadurganj', + 'Dantewara', + 'San Feliu de Guixols', + 'Puente-Genil', + 'Basmanpur', + 'Baar', + 'Chinautla', + 'Iriga City', + 'Gonglang', + 'Pecs', + 'La Paz Centro', + 'Lienz', + 'Japaratuba', + 'Chiba', + 'Havlickuv Brod', + 'Ranchos', + 'Corning', + 'Zinder', + 'Sankt Gallen', + 'Al Lith', + 'Kaminoyama', + 'Morarano', + 'Sokyriany', + 'Untergruppenbach', + 'Makapanstad', + 'Hullahalli', + 'Empoli', + 'Melton', + 'Abiramam', + 'Villapinzon', + 'Le Vesinet', + 'Den Chai', + 'Khasab', + 'General Deheza', + 'Rideau Lakes', + 'Banora Point', + 'Dillenburg', + 'Acarape', + 'Olympia', + 'Zilina', + 'Chuarrancho', + 'Jaipur Chuhar', + 'Scaggsville', + 'Bat Khela', + 'Villa Jaragua', + 'Oosterzele', + 'La Banda', + 'West Pensacola', + 'Cleckheaton', + 'Gizo', + 'Guaimaca', + 'Chalkida', + 'Namegata', + 'Shibam', + 'Duekoue', + 'Bir Anzarane', + 'Sidi Yahia', + 'Port Hedland', + 'Cisterna di Latina', + 'Dolo', + 'Castro Daire', + 'Kolattur', + 'Hachioji', + 'Sakti', + 'Stanford', + 'Asakapalle', + 'Mazhang', + 'Claypole', + 'Sokal', + 'Byureghavan', + 'Ghasri', + 'Harbin', + 'Renqiu', + 'Bhaur', + 'Canillo', + 'Capellen', + 'Kenton', + 'Balasamudram', + 'Sondershausen', + 'Coburg', + 'Makrana', + 'Zvishavane', + 'Petapa', + 'Piparia', + 'Kiamba', + 'Meyerton', + 'Yi Xian', + 'Tewkesbury', + 'Menomonee Falls', + 'Wilkinsburg', + 'Cildir', + 'Sao Mateus do Maranhao', + 'Belleville', + 'Sandefjord', + 'Santa Branca', + 'Hinckley', + 'Tomblaine', + 'Chizhou', + 'Hardenberg', + 'Victor Harbor', + 'Broadlands', + 'Iskourane', + 'Yuanli', + 'Erattukulakkada', + 'Selcuklu', + 'Colesville', + 'Port Hope', + 'Sidi Amer El Hadi', + 'Bowringpet', + 'Kalpakathukonam', + 'Adonara', + 'Mesquite', + 'Papara', + 'Karambakkudi', + 'El Aguila', + 'West Derby', + 'Bhanvad', + 'Borj el Qoble', + 'Kamikita-kita', + 'Rio Pardo de Minas', + 'Paso Canoas', + 'Holalu', + 'Owani', + 'Katoya', + 'Semdinli', + 'Manaratsandry', + 'San Martin Texmelucan de Labastida', + 'Palo', + 'Vestavia Hills', + 'Deogarh', + 'San Juan del Cesar', + 'Teorama', + 'Secaucus', + 'Tepecoyo', + 'Kadur', + 'Belampona', + 'Ghattu', + 'Sao Jose do Calcado', + 'Shinto', + 'Al Hibah', + 'Gateway', + 'Werdohl', + 'Lenzburg', + 'Gjilan', + 'Zory', + 'Vodurivandlagudem', + 'Hoddesdon', + 'Rawmarsh', + 'Yajalon', + 'Taisheng', + 'Kizhattur', + 'Yongcong', + 'Macomer', + 'Iwamizawa', + 'Bail-Hongal', + 'Maglod', + 'Jauja', + 'Kadiyadda', + 'Tiruvengadam', + 'Alovera', + 'Sao Goncalo do Rio Abaixo', + 'Velike Lasce', + 'Foxborough', + 'Collo', + 'Cincinnati', + 'Manambolo', + 'Rugeley', + 'Kulob', + 'Saparua', + 'Plympton', + 'Malekan', + 'Calheta', + 'Kalanak', + 'Sines', + 'San Ignacio Cohuirimpo', + 'Grottaferrata', + 'Skhira', + 'Harker Heights', + 'El Nido', + 'Morangis', + 'Belp', + 'Estremoz', + 'Baft', + 'State College', + 'Likak', + 'Kanjiza', + 'Schwabmunchen', + 'Adzope', + 'Balamban', + 'Yaojiafen', + 'Klosterneuburg', + 'Coracao de Jesus', + 'Pereshchepyne', + 'Dayr Abu Sa`id', + 'Tofol', + 'Vasad', + 'Rychnov nad Kneznou', + 'Sontha', + 'Mandza', + 'Jatibonico', + 'North Whitehall', + 'Ringnod', + 'Palamel', + 'Pampa', + 'Ahrensfelde', + 'Barwat Pasrain', + 'Haider Khel', + 'Zuera', + 'Yampil', + 'Wyoming', + 'El Outaya', + 'Kikinda', + 'Zefat', + 'Naganuma', + 'Chingford', + 'Weisswasser/Oberlausitz', + 'Stockton', + 'Tournefeuille', + 'Wolfenbuttel', + 'Kieta', + 'Manambaro', + 'Abejorral', + 'Tchitato', + 'Horsforth', + 'Kunithala', + 'Yesilhisar', + 'Gulshan', + 'Sanuki', + 'Laanoussar', + 'Kerouane', + 'Huaycan', + 'Curtorim', + 'Tamallalt', + 'Coronado', + 'Mata Verde', + 'Charenton-le-Pont', + 'Tamri', + 'Villiersdorp', + 'Miorimivalana', + "Ain M'Lila", + 'Siruvachchur', + 'Valdez', + 'Bou Arfa', + 'Bonifacio', + 'Valpoy', + 'Jun Bel', + 'Northcote', + 'Macenta', + 'Guira de Melena', + 'Moranha', + "Jem'at Oulad 'Abbou", + 'Upminster', + 'Bulawayo', + 'Laguna', + 'Adria', + 'Qatlupur', + 'Rumphi', + 'Omaezaki', + 'Ksar El Kebir', + 'Cruzeiro', + 'Semic', + 'Moparipalaiyam', + 'Quanzhou', + 'Wisil', + 'Meadow Lakes', + 'Qrendi', + 'Ang Thong', + 'Nandi Hills', + 'Grayslake', + 'Teguise', + 'Kakunodatemachi', + 'Marupe', + 'Mayen', + 'Miguel Alves', + 'Karnal', + 'Owings Mills', + 'Lewe', + 'Dyykan-Kyshtak', + 'Kentville', + 'Ilijas', + 'San Pedro de Coche', + 'Yermal', + 'Zipaquira', + 'Linganaboyinacherla', + 'Es Sebt', + 'Luisiana', + 'Tamahu', + 'Kudowa-Zdroj', + 'Susice', + 'Saucillo', + 'Castelletto sopra Ticino', + 'Repentigny', + 'Manganj', + 'Algemesi', + 'Methuen Town', + 'Reota', + 'Aiyampuzha', + 'Nisia Floresta', + 'Tukwila', + 'Cayey', + 'Phu Tho', + 'Pishin', + 'Manuel B. Gonnet', + 'Moguer', + 'Petit-Goave', + 'Oulad Salmane', + 'Kadikoy', + 'Cocoa Beach', + "Bulung'ur Shahri", + 'Ambalavato', + 'Qal`eh Ganj', + 'Quierschied', + 'Barrow in Furness', + 'Beifan', + 'Cubulco', + 'Hallbergmoos', + 'Porcari', + 'Kombolcha', + 'Kirkagac', + 'Cacule', + 'Daraga', + 'Qandala', + 'Bagaha', + 'Isoanala', + 'Baulia', + 'Boultham', + 'Samundri', + 'Amangal', + 'Perambalur', + 'Gose', + 'San Pedro La Laguna', + 'Mahendragarh', + 'Offenburg', + 'Sagae', + 'Uttamapalaiyam', + 'Lesquin', + 'Novohrad-Volynskyi', + 'Takab', + 'Shahmirpet', + 'Dom Basilio', + 'Witten', + 'Lavandevil', + 'Katowice', + 'Valavakattumula', + 'Mel Seval', + 'Santa Catarina Otzolotepec', + 'Engenheiro Paulo de Frontin', + 'Alta', + 'Uran', + 'Santo Tirso', + 'Hochstadt an der Aisch', + 'Texistepeque', + 'Stevens Point', + 'Karadipara', + 'Diafarabe', + 'Travnik', + 'Sibi', + 'Bichkunda', + 'Tarpon Springs', + 'Cuicatlan', + 'Bealanana', + 'Nalhati', + 'Surak', + 'Kurumbalur', + 'Whangarei', + 'Hatten', + 'Valrico', + 'Johnstone', + 'Enterprise', + 'Olutanga', + 'Aguelhok', + 'Mezdra', + 'Tanghin-Dassouri', + 'Kamien Pomorski', + 'Santo Domingo Tehuantepec', + 'Ap Phu My', + 'Stamboliyski', + 'Kilis', + 'Ho Nai', + 'Taree', + 'Teulada', + 'Virac', + 'Vigia', + 'Shahrak-e Pars', + 'Zhengzhou', + 'Vikarabad', + 'Liubotyn', + 'Tremonton', + 'Tirmitine', + 'Genas', + 'Evato', + 'Pisa', + 'Kathua', + 'El Bordo', + 'Surin', + 'Bariri', + 'Trelaze', + 'Thatto Heath', + 'Takon', + 'Praya', + 'Baoding', + 'Nakashunbetsu', + 'Eloy', + 'Sao Miguel de Touros', + 'Moulay Driss Zerhoun', + 'El Pinar', + 'Mongomo', + 'Andranovelona', + 'Malbork', + 'Soatanana', + 'Hillerod', + 'Cape Elizabeth', + 'Tirwa', + 'Salatiga', + 'Roncaglia', + 'Selu', + 'Borgo Maggiore', + 'Shelbyville', + 'Bandar-e `Asaluyeh', + 'Ferizaj', + 'Ufeyn', + 'Devanhalli', + 'Akyurt', + 'Jawalgeri', + 'Cambita Garabitos', + 'Manalapan', + 'Surendranagar', + 'Tadinada', + 'Heumen', + 'Inzago', + 'Bulach', + 'Tinipuka', + 'Manohisoa', + 'Leisure City', + 'Hilvan', + 'La Estrella', + 'Vulcan', + 'Wallan', + 'Ramareddi', + 'Gava', + 'Beroy Atsimo', + 'Huejotzingo', + 'Tucupita', + 'Ouled Beni Messous', + 'Bedzin', + 'Bidston', + 'Marilandia do Sul', + 'Sechelt', + 'Beernem', + 'Palwal', + 'Puerto Iguazu', + 'Banchpar', + 'Targu Ocna', + 'Sacile', + 'Lajeado', + 'Razole', + 'Peringalam', + 'Cavaillon', + 'Panaji', + 'Kesennuma', + 'Linhai', + 'Silvi Paese', + 'Bairnsdale', + 'Mehidpur', + 'Sivrice', + 'Waynesville', + 'Oulu', + 'Mairena del Alcor', + 'Omatjete', + 'Mokena', + 'Awlouz', + 'Douar Bni Malek', + 'Bonao', + 'Al Karak', + 'Pitimbu', + 'Pandami', + 'Monzon', + 'Molbergen', + 'Sahit', + 'Castleford', + 'Perungulam', + 'Tonekabon', + 'Jasdan', + 'Dharmajigudem', + 'El Cacao', + 'Salavan', + 'Plato', + 'Fontenay-aux-Roses', + 'San Luis de La Loma', + 'Dinbela', + 'Hawthorn Woods', + 'Corabia', + 'Arboledas', + 'Utrecht', + 'Douar Lehouifrat', + 'Dois Vizinhos', + 'Cabo Bojador', + 'Amalou', + 'Rock Falls', + 'Sitebe', + 'Vakkam', + 'Dasnapur', + 'Ankirondro', + 'Rajupalem', + 'El Cajon', + 'Gunbarrel', + 'Yulee', + 'Chatan', + 'Palmer', + 'Fronteiras', + 'Chicureo Abajo', + 'Newberry', + 'Severance', + 'Sattenapalle', + 'Koping', + 'Muhlhausen', + 'Sylvania', + 'San Elizario', + 'Hameenkyro', + 'Confresa', + 'Barbate de Franco', + 'Ararangua', + 'Boston', + 'Frankfurt (Oder)', + 'Ganshoren', + 'Mehdipur', + 'Ambodinonoka', + 'Cajari', + 'La Primavera', + 'Brahmanandapuram', + 'Oued Rhiou', + 'Polegate', + 'Dodoma', + 'Mecheraa Asfa', + 'Aracas', + 'Rushden', + 'Korosten', + 'Deodora', + 'Pell City', + 'Beppu', + 'Greenburgh', + 'Analaiva', + 'Haar', + 'Cervantes', + 'Uelzen', + 'Budd Lake', + 'Puyang', + 'Aladag', + 'Hajeb el Aioun', + 'Camajuani', + 'Savannah', + 'Pithapuram', + 'Eldersburg', + 'San Policarpo', + 'Mennecy', + 'Ibirapua', + 'Gholia Kalan', + 'Pickerington', + 'Qadsayya', + 'Waldniel', + 'Bagalur', + 'Sao Pedro do Piaui', + 'Bar-le-Duc', + 'Nakhyaungcharipara', + 'Tralee', + 'Penukonda', + 'Ghosai', + 'Pasaquina', + 'Gevgelija', + 'Chokkampatti', + 'Illzach', + 'Huadian', + 'Baryshivka', + 'Siofok', + 'Yutan', + 'Njombe', + 'Khlung', + 'Dabouziya', + 'Tumpat', + 'Tangpingcun', + 'Chinna Salem', + 'Basaithi', + 'Aranguez', + 'Marand', + 'Tanudan', + "Bet She'an", + 'Pingxiang', + 'Westerlo', + 'Jomasho`y', + 'Brussels', + 'Kempele', + 'Kiranomena', + 'Porto Esperidiao', + 'Padre Burgos', + 'Banda del Rio Sali', + 'Cortlandt', + 'Tepatitlan de Morelos', + 'Eau Claire', + 'Saint-Constant', + 'Schermbeck', + 'Cuautitlan', + 'Kolnur', + 'Ehden', + 'Dazhuangzi', + 'Pebble Creek', + 'Meihekou', + 'Qianjiang Shequ', + 'Matamoros', + 'Calama', + 'Stoneham', + 'Dassel', + 'Khanna', + 'Cankaya', + 'Palos Hills', + 'Elurpatti', + 'Kallakkurichchi', + 'Monte San Giovanni Campano', + 'Orhaneli', + 'Bungoono', + 'Blankenberge', + 'Cordele', + 'Kure', + 'Bolgatanga', + 'Bansalan', + 'Race', + 'Morales', + 'Courcelles', + 'Evaz', + 'Pantepec', + 'Nyirbator', + 'Bellegarde-sur-Valserine', + 'Barahi', + 'Espinosa', + 'Fatehgarh', + 'Tangcun', + 'Brzeziny', + 'Pardwal', + 'Gonzales', + 'San Juan y Martinez', + 'Hirriyat Raznah', + 'Rokhaty', + 'Jiangyin', + 'Andahuaylas', + 'Pamiers', + 'Pinarbasi', + 'Rio Vermelho', + 'Boca del Rio', + 'Timana', + 'Cambridge', + 'Shancheng', + 'San German', + 'Mata Roma', + 'Compiegne', + 'Kadanganeri', + 'Argelato', + 'Torokszentmiklos', + 'Ardesen', + 'Cariamanga', + 'Korahia', + 'Saarwellingen', + 'South Abington', + 'Balete', + 'Fuman', + 'Amdel', + 'Dedemsvaart', + 'Plasencia', + 'Sharonville', + 'Villamarchante', + 'Slobozia', + 'Jinji', + 'Malak Abad', + 'Adakplame', + 'Manoke', + 'Companiganj', + 'Ozu', + 'Friedrichshafen', + 'Loudi', + 'Meerut', + 'Sheohar', + 'Sanjiang Nongchang', + 'Jos', + 'Zhangmu Touwei', + 'Siuna', + 'Clervaux', + 'Nocera Inferiore', + 'Borvayeh-ye Al Bu `Aziz', + 'Uki', + 'Humble', + 'Valaparla', + 'Ajim', + 'Kok-Janggak', + 'Etropole', + 'Idukki', + 'Olmue', + 'Maracanau', + 'Ar Rass', + 'Anivorano Avaratra', + 'Jonesboro', + 'Sanlucar de Barrameda', + 'Estahban', + 'Sujapur', + 'Yilong', + 'Ciudad Altamirano', + 'Rudnyy', + 'Wladyslawowo', + 'Hekinan', + 'Cittanova', + 'Schonebeck', + 'Mangalore', + 'Pehonko', + 'Kacanik', + 'Cauquenes', + 'Chikni', + 'Yongcheng', + 'Town and Country', + 'Assai', + 'Liujiaxia', + 'Harwich', + 'Attur', + 'Ganjam', + 'Matar', + 'Grovetown', + 'Hazro', + 'Findlay', + 'Lower Merion', + 'Hennef', + 'Musikot-Khalanga', + 'Vinjam', + 'Sao Jose', + 'Gengenbach', + 'Salmon Creek', + 'Katoomba', + 'Arrapalli', + 'Krasnystaw', + 'Ban Chang', + "Tai'an", + 'Manucan', + 'Bopolu', + 'Tissint', + 'Vohimasy', + 'Ocana', + 'Dickinson', + 'Middelkerke', + 'Jarajus', + 'El Jadid', + 'Altinyayla', + 'Rongcheng', + 'Puthupalli', + 'Pedro Afonso', + 'Muurame', + 'Castro Valley', + 'Cookstown', + 'Santa Maria das Barreiras', + 'Konand', + 'Dilbeek', + 'Meicheng', + 'Hamma Bouziane', + 'Rottweil', + 'Sao Luis do Curu', + 'Dowlatabad', + 'South Strabane', + 'Schenectady', + 'Baihar', + 'Blacklick Estates', + 'Villa Nougues', + 'Al Qurayyat', + 'Sao Jose de Mipibu', + 'Huddersfield', + 'Chibuto', + 'Groutville', + 'Vert-Saint-Denis', + 'Patzicia', + 'Kankon', + 'La Chaux-de-Fonds', + 'Altenbeken', + 'Blonie', + 'Anda', + 'Masterton', + 'Wieringerwerf', + 'Peruwelz', + 'Ilawa', + 'Dirba', + 'Shankarpalli', + 'Longquan', + 'Bodippatti', + 'Nasukarasuyama', + 'Sam', + 'Ban Nong Prue', + 'Monreale', + 'Barreira', + 'Hetanpur', + 'Shishgarh', + 'Tafresh', + 'Saltcoats', + 'Gopalasamudram', + 'Kafr Saqr', + 'Espinho', + 'Peine', + 'Radevormwald', + 'Pompano Beach', + 'Chavinda', + 'Yishi', + 'Janauba', + 'Ankalgi', + 'Pluderhausen', + 'Sopot', + 'Varpalota', + 'Sanming', + 'Santander', + 'Niskayuna', + 'Gumushacikoy', + 'Obalapuram', + 'Bollate', + 'Ghardaia', + 'Davorlim', + 'San Jacinto del Cauca', + 'Ridderkerk', + 'Athiringal', + 'Jimenez', + 'Ketrzyn', + 'Grugliasco', + 'Segoubougou', + 'Lanji', + 'Cocorote', + 'Mizil', + 'Francisco Beltrao', + 'Toksun', + 'Haka', + 'Bilasuvar', + 'Sabaneta de Yasica', + 'Abqaiq', + 'Hinundayan', + 'King', + 'Satun', + 'Fujioka', + 'Ankadinondry-Sakay', + 'Sentani', + 'Bady Bassitt', + 'Concepcion Tutuapa', + 'Woking', + 'Manlius', + 'Mutsamudu', + 'Khuzdar', + 'Czernica', + 'Balzers', + 'Saydnaya', + 'Suthalia', + 'Stevenson Ranch', + 'Dar Ould Zidouh', + 'South Salt Lake', + 'Voerde', + 'South San Francisco', + 'Sarstedt', + 'Neuwied', + 'Northview', + 'Diez', + 'Cuscatancingo', + 'Worth', + 'Wrentham', + 'Pueblo West', + 'Bispham', + 'Shillong', + 'Goes', + 'Talayazham', + 'Kosk', + 'Imus', + 'Montigny-les-Cormeilles', + 'El Guetar', + 'Campinas', + 'Muggio', + 'Latsia', + 'Leopoldsburg', + 'Tagazhi', + 'Tacaimbo', + 'Karimkunnum', + 'Olifantshoek', + 'Cocal', + 'Petrovac na Mlavi', + 'Likasi', + 'Marmaris', + 'Qarabulaq', + 'Dalin', + 'Straseni', + 'Tamluk', + 'Lemon Grove', + 'Shoreview', + 'Ewa Beach', + 'Ado-Ekiti', + 'Rio Verde', + 'Marina', + "Xi'an", + 'Jutai', + "Quartu Sant'Elena", + 'Santa Ursula', + 'Padiala', + 'Sigatoka', + 'Bien Unido', + 'Yotoco', + 'Goundam', + 'Iconha', + 'Pathari', + 'Kotra', + 'Brookside', + 'Palos de la Frontera', + 'Ban Bang Phlap', + 'Halwan', + 'Arth', + 'Jiaoxiling', + 'Dicholi', + 'Uruapan', + 'Bromont', + 'Yaprakli', + 'Junagadh', + 'Sirvintos', + 'Nandayure', + 'Karimama', + 'Pangantocan', + 'Kanpur', + 'Sao Manuel', + 'Schwelm', + 'North Bergen', + 'Curvelo', + 'Zafargarh', + 'Travilah', + 'Arifiye', + 'Eusebio', + 'Ba`qubah', + 'Nutakki', + 'Hermantown', + 'Kremenets', + 'Enrile', + 'Tavarede', + 'Wiesmoor', + 'Soke', + 'Bandraboua', + 'Dera Allahyar', + 'Welzheim', + 'Calbuco', + 'Markovci', + 'Dumka', + 'Dumaria', + 'Bogue', + 'Manuel Tames', + 'Longjumeau', + 'Igny', + 'Medenine', + 'Govindapalle', + 'Justice', + 'Surappalli', + 'Fara', + 'Sao Francisco do Maranhao', + 'Nandiyalam', + 'Tarrasa', + 'Amaliada', + 'El Hadjira', + 'Hickory', + 'Mandramo', + 'Celendin', + 'Almansa', + 'Yamatotakada', + 'Rhaude', + 'Lingtang', + 'Kfar Kidde', + 'Abadla', + 'Nova Serrana', + 'La Victoria', + 'Adis Zemen', + 'Nanticoke', + 'Douar El Arbaa Bou Quorra', + 'Passo Fundo', + 'Ain el Mediour', + 'Ban Lam Sam Kaeo', + 'Hinwil', + 'Moradabad', + 'Douar Toulal', + 'Hong', + 'Lubbock', + 'Higashikagura', + 'Trentola', + 'Prymorsk', + 'Trzcianka', + 'Borujerd', + 'Elefsina', + 'Teruel', + 'Mugdampalli', + 'Manampatrana', + 'Sisak', + 'Simpelveld', + 'Jonava', + 'Solola', + 'Santo Anastacio', + 'Nalayh', + 'Dumarao', + 'Imgarr', + 'Puerto Triunfo', + 'Dhubaria', + 'San Jose de Aerocuar', + 'Destrnik', + 'Dasso', + 'Calanogas', + 'Ash Shaykh Badr', + 'Klerksdorp', + 'Sardasht', + 'Udamalpet', + 'Xihuangni', + 'Agudos do Sul', + 'Ciudad de Atlixco', + 'Huntley', + 'Leonberg', + 'North Glengarry', + 'Baciu', + 'Hemmoor', + "Montopoli in Val d'Arno", + 'Settimo Torinese', + 'Pul-e `Alam', + 'Kizilcahamam', + 'Bulnes', + 'Koiridih', + 'Ho', + 'Heber', + 'Bristol', + 'Turbaco', + 'Arbaa Laaounate', + 'Ayyagarpet', + 'Xiluo', + 'Nordre Fale', + 'Stara Pazova', + 'Uchinada', + 'Bhikkiwind Uttar', + 'Guerou', + 'Landeh', + 'Lilburn', + 'Calvizzano', + 'San Jose del Rincon Centro', + 'Bagh', + 'Mau', + 'Vincennes', + 'Warrenville', + 'Madiun', + 'Boma', + 'Vettam', + 'Magione', + 'Piscataway', + 'Souk et Tnine Jorf el Mellah', + 'Marly-le-Roi', + 'Khansahibpuram', + 'Otsu', + 'Vitoria', + 'Motril', + 'Asheboro', + 'Cobham', + 'Kalilangan', + 'Dahua', + 'Pozo Almonte', + 'Salem', + 'Babhangaon', + 'Zero Branco', + 'Berberati', + 'Laharpur', + 'Nihal Singhwala', + 'Pesnica', + 'Santa Cruz da Baixa Verde', + 'Newburyport', + 'Alcala de Guadaira', + 'Sodegaura', + 'Al Mazar ash Shamali', + 'Aransas Pass', + 'Xuddur', + 'Port-de-Paix', + 'Kirkstall', + 'Erd', + 'Saint-Martin-Boulogne', + 'Wulong', + 'Nagdha Simla', + 'Roeselare', + 'Lubin', + 'Barberino di Mugello', + 'Cranberry', + 'Oldenzaal', + 'Mascouche', + 'Ashgabat', + 'Mtwara', + 'Mankal', + 'Este', + 'Caririacu', + 'Piranshahr', + 'Xiaozhengzhuang', + 'Khamis Mushayt', + 'Prineville', + 'Sidi Namane', + 'Tapachula', + 'Massawa', + 'Ramewadi', + 'Abancay', + 'Biratnagar', + 'Chilakhana', + 'Tadepalle', + 'Passau', + 'Imerimandroso', + 'Nilanga', + 'Tsukuba-kenkyugakuen-toshi', + 'Veldhoven', + 'Longjiang', + 'Armidale', + 'Alcoy', + 'Gabaldon', + 'Klippansbruk', + 'Yongyang', + 'Canton', + 'Hammonton', + 'Pena Forte', + 'Panamaram', + 'Kankan', + 'Sanaa', + 'Kilchberg', + 'Fulton', + 'Prainha', + 'Andranofasika', + 'Barela', + 'Bhogpur', + 'Crayford', + 'Glenshaw', + 'San Lorenzo', + 'Thiais', + 'Bahce', + 'Oliveira do Hospital', + 'Bhander', + 'Taitung', + 'Caldas da Rainha', + 'Decatur', + 'Basaon', + 'Matteson', + 'Al Hammam', + 'Tayyibat al Imam', + 'Jhakhra', + 'Stiring-Wendel', + 'Vlissingen', + 'Zhongling', + 'Palm Springs', + "Qacha's Nek", + 'Kambaneri Pudukkudi', + 'Khardah', + 'Artashat', + 'Bua Yai', + 'Point Pedro', + 'Tozeur', + 'Luxitun', + 'San Sebastian de Mariquita', + 'Saint-Sauveur', + 'Rumilly', + 'Mortad', + 'Kaithwar', + 'Abertillery', + 'Sulzbach', + 'Tillaivilagam', + 'Veroia', + 'Zeitz', + 'Graz', + 'Kitakyushu', + 'Picasent', + 'Rahden', + 'Mecatlan', + 'Tehri', + 'Mauganj', + 'Burshtyn', + 'Espargos', + 'Travis Ranch', + 'Chokkanathapuram', + 'Bhalil', + 'Pateros', + 'Nambuangongo', + 'Beckum', + 'Sanary-sur-Mer', + 'Budili', + 'Akalapura', + 'Belo Vale', + 'Pavlohrad', + 'Swinton', + 'Cento', + 'Nantou', + 'Flora', + 'Carnaiba', + 'Piotrkow Trybunalski', + 'Conceicao da Feira', + 'Dohazari', + 'Sugito', + 'Si Sa Ket', + 'Sirjan', + 'Zaandam', + 'Titisee-Neustadt', + 'Rafelbunol', + 'Abadou', + 'Suhareke', + 'Pipariya', + 'Binidayan', + 'Kunzelsau', + 'Panjgur', + 'Juana Diaz', + 'Afzalpur', + 'Porirua', + 'Elbasan', + 'Hardi', + 'Forbesganj', + 'Shah Alam', + 'Tiruvegapra', + 'Cat', + 'Clichy-sous-Bois', + 'Qumqo`rg`on', + 'Ban Tha Thong', + 'Auburn Hills', + 'Castelo Branco', + 'Borgo', + 'Rich', + 'Karukachal', + 'Maltby', + 'Notteroy', + 'Glens Falls North', + 'Cunha', + 'Alebtong', + 'Balneario de Camboriu', + 'Anandapuram', + 'Bambalang', + 'Touggourt', + 'Taihe', + 'Saidoke', + 'Jori Kalan', + 'Golet', + 'Sankaranayinar Kovil', + 'Sao Sepe', + 'Saugus', + 'Capaci', + 'Puerto Morazan', + 'Fao Rai', + 'Caracase', + 'Tranas', + 'San Giorgio del Sannio', + 'Abeche', + 'Pak Thong Chai', + 'Sola', + 'Bensalem', + 'Talen', + 'Cidreira', + 'Phangnga', + 'Kalavapudi', + 'Kapsabet', + 'Nawan Shahr', + 'Pyu', + 'Mitsinjo', + 'Bradford', + "N'Gaous", + 'Mionica', + 'Echelon', + 'Antonio Carlos', + 'La Tuque', + 'Nairn', + 'Steenbergen', + 'Sidi Abdelaziz', + 'Jijel', + 'Manzanares', + 'Zofingen', + 'Ryuyo', + 'Tigard', + 'Belm', + 'Piastow', + 'Sebring', + 'Vastervik', + 'Hengshuicun', + 'Riverside', + 'Montecristi', + 'Aprilia', + 'Penistone', + 'Mogeiro', + 'Sao Joao de Ver', + 'Robles', + 'Saint-Germain-en-Laye', + 'Bethelsdorp', + 'Saka', + 'Butia', + 'Gudipallipadu', + 'Pulivendla', + 'Huntingdon', + 'Vila Teixeira da Silva', + 'Antsakanalabe', + 'Amneville', + 'Lummen', + 'Dbaiye', + 'Semmarikulan', + 'Risalpur Cantonment', + 'Acala del Rio', + 'Porur', + 'Amarchinta', + 'Olamze', + 'Kairouan', + 'Qiantangcun', + 'Montegrotto Terme', + 'Bensheim', + 'Lenvik', + 'Pariquera-Acu', + 'Sambre', + 'Tekkebhagam', + 'Blerick', + 'Parobe', + 'Clive', + 'Davos', + 'Devanakavundanur', + 'Tupran', + 'Rossano', + 'Raman', + 'Hosan', + 'Erding', + 'Ban Tha Kham', + 'Huercal-Overa', + 'Fairmount', + 'Kamabougou', + 'Alcaudete', + 'El Banco', + 'Saksohara', + 'Ferkessedougou', + 'Darsur', + 'Gagnef', + 'Mostaganem', + 'Opatija', + 'Cambira', + 'Moninnpebougou', + 'Pinia', + 'Sillod', + 'Santo Antonio do Sudoeste', + 'Baxt', + 'Yomitan', + 'Porto Firme', + 'Kalungu', + 'Tarime', + 'Dingxi', + 'Garuva', + 'Alton', + 'Poprad', + 'Comandante Fontana', + 'Luanzhou', + 'Cuitzeo del Porvenir', + "Sant'Agata de' Goti", + 'Tsinjoarivo', + 'Tamiahua', + 'Barnis', + 'Minami-Alps', + 'Jalam', + 'Arandu', + 'Spanish Fork', + 'Tiruvennanallur', + 'Mohammadia', + 'Bayt Sahur', + 'Wilhelmshaven', + 'Claudio', + 'Nelali', + 'San Andres Villa Seca', + 'North Dundas', + 'Kilminnal', + 'Alamogordo', + 'Antsakabary', + 'Ibicarai', + 'Eral', + 'Zdolbuniv', + 'Drochia', + 'Saikaicho-kobago', + 'Coroneo', + 'Gabasumdo', + 'River Forest', + 'Ecatepec', + 'Bekopaka', + 'Fort McMurray', + 'Ban Mae Tuen', + 'Dizicheh', + 'Biggin Hill', + 'Lower Bicutan', + 'Tunceli', + 'Kurim', + 'Curiti', + 'Seminole', + 'Tori-Bossito', + 'Lake Havasu City', + 'San Benito Abad', + "'Ain el Bell", + 'Bocsa', + 'Batuco', + 'Ughara', + 'Kakdwip', + 'Nallajerla', + 'Lumbang', + 'Sarbogard', + 'Bowral', + 'Kristinehamn', + 'Meiwa', + 'Tetela del Volcan', + 'Rupenaguntla', + 'Palera', + 'Attleboro', + 'Vitomarci', + 'Guraahai', + 'Henley on Thames', + 'Stanford le Hope', + 'Cazones de Herrera', + 'Middleborough', + 'Port Perry', + 'Saryaghash', + 'Tay', + 'Marlow', + "Granarolo del l'Emilia", + 'Whitby', + 'Pahou', + 'Santa Maria di Sala', + 'Rani Sawargaon', + 'Moore', + 'Tizimin', + 'Gabane', + 'Lichtenau', + 'Wetter (Ruhr)', + 'Quva', + 'Ipaucu', + 'Tahla', + 'Enschede', + 'Padinjaremuri', + 'Oued Essalem', + 'Sanatikri', + 'Razanj', + 'Ban Bang Lamung', + 'Camberley', + 'Avignon', + 'Sittingbourne', + 'Maduraivayal', + 'Onate', + 'Arboga', + 'Duluth', + 'Iluppur', + 'Tehachapi', + 'Tijucas', + 'Bahadarpur', + 'Bugugoucun', + 'Bayi', + 'Nakuru', + 'Fontenay-sous-Bois', + 'Tachikawa', + 'Amroha', + 'Boo', + 'Fochville', + 'Idak', + 'Campbellsville', + 'Limonade', + 'Lucea', + 'Tetouan', + 'Sesori', + 'Criciuma', + 'Bedford', + 'Osvaldo Cruz', + 'Karacoban', + 'Rafael Castillo', + 'Faranah', + 'Paina', + 'Santa Maria del Tule', + 'Puno', + 'Cove', + 'Sanankoroba', + 'Nowogard', + 'Pallipattu', + 'Bhalwal', + 'Torre Annunziata', + 'Gavinivaripalem', + 'Harike', + 'Kameyama', + 'Amala', + 'Struthers', + 'Ilindu Kothi', + 'Rio Grande', + 'Coral Gables', + 'San Francisco Libre', + 'Esteban Echeverria', + 'Than', + 'Bere', + 'Villa San Jose', + 'Gaurihar Khaliqnagar', + 'Yonabaru', + 'Kretinga', + 'Banolas', + 'Kalocsa', + 'Atlautla', + 'Al Muzayrib', + 'Tsitondroina', + 'Picture Rocks', + 'Ostbevern', + 'Purwa Utar', + 'Pontchateau', + 'Bandiagara', + 'Midar', + 'Abasingammedda', + 'Chinnamandem', + 'Zhydachiv', + 'Fayzobod', + 'Bad Bevensen', + 'Nedumpura', + 'Azua', + 'Earley', + 'Sao Sebastiao do Maranhao', + 'Nossa Senhora do Livramento', + 'Desaguadero', + 'The Village', + 'Richfield', + 'Medway', + 'Panglao', + 'Erraguntla', + 'Tapilula', + 'South Park', + 'Shovot', + 'Samaca', + 'Fehrbellin', + 'Pouytenga', + 'Wenping', + 'Mendefera', + 'Matanao', + 'Bataguacu', + 'Kljuc', + 'Saint-Malo', + 'Hiriyur', + 'Copan', + 'Comodoro', + 'Ampasimpotsy-Gara', + 'Issum', + 'Thundersley', + 'Nandavaram', + 'Ivisan', + 'Uvinza', + 'Bituruna', + 'Salzhemmendorf', + 'Oguchi', + 'Maubin', + 'Pullman', + 'Lower Gwynedd', + 'Kidal', + 'Ghariyah al Gharbiyah', + 'Sagarpur', + 'Cottage Lake', + 'Macon', + 'Siayan', + 'Fatick', + 'Hinda', + 'Betio', + 'Ramos Arizpe', + 'Mbuyapey', + 'Tirana', + 'Uzyn', + 'Jolo', + 'Knoxville', + 'Durant', + 'Khmelnytskyi', + 'Mong Duong', + 'Mujui dos Campos', + 'Hendaye', + 'Despatch', + 'Borne', + 'Goirle', + 'Petnjica', + 'Barda', + 'Feliz', + 'Ut Bulag', + 'Fasano', + 'Gtarna', + 'Greensboro', + 'Boskovice', + 'Barrafranca', + 'Estero', + 'Osmangazi', + 'Demre', + 'Manjil', + 'Temascaltepec de Gonzalez', + 'Mendota Heights', + 'Nalgora', + 'Gwangju', + 'Qitai', + 'Zakhu', + 'Krishnarajpet', + 'Hayes', + 'Vitthalapuram', + 'Burla', + 'Salay', + 'Skuodas', + 'Nagano', + 'Dambal', + 'Sarauni Kalan', + 'Bocaiuva', + 'Chimbas', + 'South Pasadena', + 'Dar El Kebdani', + 'Matanzas', + 'Jarocin', + 'Sarioglan', + 'Ibate', + 'Kisenzi', + 'Shibirghan', + 'Viseu de Sus', + 'Majhariya Sheikh', + 'Qulicun', + 'Aswan', + 'Kowloon City', + 'Yverdon-les-Bains', + 'Sera', + 'Mililani Mauka', + 'Acworth', + 'Tibubeneng', + 'Saijo', + 'Wetzikon', + 'Americo Brasiliense', + 'Nova Cruz', + 'Pantao-Ragat', + 'Chichibu', + 'Kyankwanzi', + 'Jabalya', + 'Caparica', + 'Rewa', + 'Castiglione delle Stiviere', + 'Demir Kapija', + 'Ramat Gan', + 'Porto-Novo', + 'River Road', + 'Canarana', + 'Penagam', + 'Maldah', + 'Rapho', + 'Vilvoorde', + 'Gauting', + 'Aschaffenburg', + 'Samux', + 'Ekamba', + 'Kepsut', + 'Esfahan', + 'Andramy', + 'Sarezzo', + 'Miracatu', + 'Kramatorsk', + 'Daping', + 'Tunuyan', + 'Bonyhad', + 'Sao Joao da Barra', + 'Kidsgrove', + 'San Jeronimo', + 'Chinnachauku', + 'Abai', + 'Kaipram', + 'Paleng', + 'Devarshola', + 'Utraula', + 'Meadville', + 'Satupa`itea', + 'Pacatuba', + 'Saint-Georges', + 'Remigio', + 'Puerto Suarez', + 'Arden-Arcade', + 'Kankanalapalle', + 'Mankada', + 'Willow Grove', + 'Tamaki', + 'Pijnacker', + 'Naryai ka Puri', + 'Al Mazyunah', + 'Bharhopur', + 'Ekero', + 'Deh', + 'El Jem', + 'Curacavi', + 'Ladue', + 'Barki Ballia', + 'Yecapixtla', + 'Petaluma', + 'Bradley Gardens', + 'Caapora', + 'Dinklage', + 'Karad', + 'Niuchangqiao', + 'Mahalingpur', + 'Walcz', + 'Mannamturuttu', + 'Les Clayes-sous-Bois', + 'Garhara', + 'Mumaradikop', + 'Davutlar', + 'Haripur', + 'Sahsaul', + 'Pachora', + 'Testour', + 'Ratchaburi', + 'Marovoay', + 'Valente', + 'Pouso Alegre', + 'Chinnavadampatti', + 'Mariana', + 'Unjha', + 'Keighley', + 'Detva', + 'Allouez', + 'Bamako', + 'Adrasmon', + 'Ramannapeta', + 'Fort Lauderdale', + 'Webuye', + 'Peligros', + 'Leeton', + 'Bollene', + 'Lianjiang', + 'Antsirabe Afovoany', + 'Ada', + 'Tixkokob', + 'Kamagaya', + 'Cassa de la Selva', + 'Takeocho-takeo', + 'Butig', + 'Algiers', + 'Straelen', + 'Mechelen-aan-de-Maas', + 'Esmeralda', + 'Nuevo Casas Grandes', + 'Houilles', + 'Itano', + 'San Javier', + 'Emiliano Zapata', + 'Seattle', + 'Narino', + 'Tiruvannamalai', + 'Clausthal-Zellerfeld', + 'Asola', + 'Antonina', + 'Dun Dealgan', + 'Rifle', + 'Maharajgani', + 'Las Cruces', + 'Mossel Bay', + 'Tinglayan', + 'Arapgir', + 'Locogahoue', + 'White House', + 'Havana', + 'Zhetisay', + 'Navinipatti', + 'Duptiair', + 'Abcoude', + 'Capinopolis', + 'Arucas', + 'Nova Lima', + 'Cunhinga', + 'Haftkel', + 'Andacollo', + 'Kawachinagano', + 'Mountlake Terrace', + 'Kalynivka', + 'Perintalmanna', + 'Rio Real', + 'Cottingham', + 'Bas Goynuk', + 'Jianshe', + 'Wermelskirchen', + 'Hariharpara', + 'Jucuapa', + 'Choa Saidan Shah', + 'Agaram', + 'Carmen', + 'Anguo', + 'Challakere', + 'Rahimpur', + 'Pitanga', + 'Zumarraga', + 'Gohna', + 'Coyuca de Catalan', + 'Matinhos', + 'Torun', + 'Taluqan', + 'Aurad Shahjahani', + 'Persembe', + 'Bochil', + 'Nadvirna', + 'Niagadina', + 'Gubeng', + 'Sitalkuchi', + 'Dashtobod', + 'Lascano', + 'Bergisch Gladbach', + 'Dumalag', + 'Wahga', + 'Guarambare', + 'Raniyah', + 'Maddur', + 'Buba', + 'Mobarakeh', + 'Ouaklim Oukider', + 'Ito', + 'Lonar', + 'Okhargara', + 'Esil', + 'Devrek', + 'Pefka', + 'Chamonix-Mont-Blanc', + 'Bad Bergzabern', + 'Las Condes', + 'Ptolemaida', + 'Helena-West Helena', + 'Chimboy Shahri', + 'Franconia', + 'Szentes', + 'San Vito', + 'Panasapadu', + 'Ogden', + 'Harpalpur', + 'Road Town', + 'Montague', + 'Issoire', + 'Bagac', + 'Shuichecun', + 'Aylesbury', + 'Jijiga', + 'Dettingen an der Erms', + 'Thakraha', + 'Worth am Rhein', + 'Moissy-Cramayel', + 'Possneck', + 'Punjai Turaiyampalaiyam', + 'Ustka', + 'Velair', + 'As Sukhnah', + 'Carlisle', + 'Alausi', + 'Chantal', + 'Ouro Fino', + 'Korsun-Shevchenkivskyi', + 'North Andover', + 'Melekeok', + 'Mbake', + 'San Vito dei Normanni', + 'Cheranallur', + 'Whitewater', + 'Port Moresby', + 'Bryans Road', + 'Vegachi', + 'Yolombo', + 'Kewanee', + 'Mingjian', + 'Thonotosassa', + 'Isapur', + 'Kostrzyn nad Odra', + 'Friesoythe', + 'Lalam', + 'Maruturu', + 'Pudu', + 'Zahed Shahr', + 'Dungu', + 'Manica', + 'Draa el Mizan', + 'Tolmezzo', + 'Farsley', + 'Agame', + 'Pachauth', + 'Sittard', + 'Mableton', + 'Guaratingueta', + 'Lucenec', + 'Catchiungo', + 'Pitalito', + 'Bensville', + 'Shimohata', + 'Zawiat Moulay Brahim', + 'Anilao', + 'Eloi Mendes', + 'Erlanger', + 'Minamiaso', + 'Diffa', + 'Shark', + 'Osterburg', + 'Barwell', + 'Ambalanur', + 'Sigaboy', + 'Iretama', + 'Alucra', + 'Sivandipuram', + 'Opalenica', + 'Fray Bentos', + 'Kottur', + 'Yasugicho', + 'Anacortes', + 'Sangola', + 'Vanimel', + 'Guatape', + 'Zorbig', + 'Pitogo', + 'Busayra', + 'Puerto Carreno', + 'Nandigama', + 'Ampasimanolotra', + "Ma'ai", + 'Mapiri', + 'Serra', + 'Santa Iria da Azoia', + 'Pyeongtaek', + 'Hartford', + 'Hokuei', + 'Caldicot', + 'Tucacas', + 'Santiago Texacuangos', + 'Turvo', + 'Torredonjimeno', + 'Fontanafredda', + 'Rhede', + 'Agri', + 'Mandawa', + 'Sibate', + 'Tutrakan', + 'Dinga', + 'San Andres Cholula', + 'Sarpsborg', + 'Palashi', + 'Attili', + 'Pilas', + 'Libonik', + 'Tulum', + 'Tomarza', + 'Pato Branco', + 'Currumbin', + 'Fourmies', + 'Caxias', + 'Okondja', + 'Cantu', + 'Jeremoabo', + 'Ciudad General Escobedo', + 'Amberomanga', + 'Magdiwang', + 'Baardheere', + 'Ubala', + 'Chakwai', + 'Uibai', + 'Achuapa', + 'Nastola', + 'Partapnagar', + 'Naujan', + 'Letchworth', + 'Calceta', + 'Jafarabad', + 'Mamnur', + 'Merthyr Tudful', + 'Sept-Iles', + 'Bekalta', + 'Cambrai', + 'Rokiskis', + 'Pamukova', + 'Bad Laasphe', + 'Harper', + 'Registro', + 'Fern Down', + 'Perkiomen', + 'Lushar', + 'Lautaro', + 'Bhainsahi', + 'Welling', + 'Imaricho-ko', + 'Caerphilly', + 'Cunda dia Baze', + 'Monte Quemado', + 'Khipro', + 'Reriutaba', + 'DeBary', + 'Talapalli', + 'Taverny', + 'Jarjanaz', + 'Targu-Mures', + 'Bhasawar', + 'Siverek', + 'Grenade', + 'Sinincay', + 'Soledade', + 'Chattogram', + 'Srikurmam', + 'Daitocho', + 'Rombas', + 'Surabaya', + 'Le Mans', + 'Varzea Alegre', + 'Jonuta', + 'Batavia', + 'Pulimakkal', + 'Giaveno', + 'Sarangpur', + 'Septemes-les-Vallons', + 'Dolynska', + 'Targovishte', + 'Aldridge', + 'Abilene', + 'Santa Maria Jacatepec', + 'Khash', + 'Reni', + 'Denville', + 'Caracal', + 'Puebla', + 'Paravakkottai', + 'Great Bookham', + 'Bodo', + 'Mountougoula', + 'Mogi Guacu', + 'Yanagawamachi-saiwaicho', + 'Datu Odin Sinsuat', + 'Morbach', + 'Chincholi', + 'Cangzhou', + 'Pichilemu', + 'Saravan', + 'Sainte-Adele', + 'Rapar', + 'Langford Station', + 'Porthcawl', + 'Hilvarenbeek', + 'Jalarpet', + 'Bellview', + 'Initao', + 'Antaretra', + 'Iriona', + 'Peonga', + 'Vadavalli', + 'Port Talbot', + "Arbi'a Tighadwiyn", + 'Ciudad Vieja', + 'Newtown', + 'Sarasota', + 'Rohtak', + "'s-Hertogenbosch", + 'Ras Baalbek', + 'Harinakunda', + 'Calahorra', + 'Beitbridge', + 'Las Tablas', + 'Zhongli', + 'Dauin', + 'Saraqib', + 'Karranah', + 'Solaro', + 'Dehra Dun', + 'Riolandia', + 'Wai', + 'Golubovci', + 'Lomza', + 'Nkurenkuru', + 'Oudenburg', + 'North Laurel', + 'Ammi Moussa', + 'Puruliya', + 'Ayungon', + 'Mailavaram', + 'Ban Dong Mada', + 'San Sebastian', + 'Le Petit-Couronne', + 'Bani Walid', + 'Molins de Rey', + 'Bekoratsaka', + 'Luperon', + 'Abakaliki', + 'Vila Nova de Cerveira', + 'Rocca Priora', + 'Raurkela', + 'Romny', + 'Santa Marcela', + 'Chinhoyi', + 'Tanki Leendert', + 'Dej', + 'Berber', + 'Perryton', + 'Haarlem', + 'Xique-Xique', + 'Mirdoddi', + 'El Rodeo', + 'Truskavets', + 'Zugdidi', + 'Dharhwa', + 'Esslingen', + 'Kakching Khunou', + 'Campos Sales', + 'Saundhonwali', + 'Hemei', + 'Pindorama', + 'Cospicua', + 'Sevur', + 'Fiume Veneto', + 'South Hill', + 'Charipara', + 'Borio', + 'Mount Barker', + 'Soliera', + 'San Clemente', + 'Polonne', + 'Barreiras', + 'Cabrero', + 'Sainte-Therese', + 'Merredin', + 'Doume', + 'Guaynabo', + 'Mohyliv-Podilskyi', + 'Santiago de Chuco', + 'Auriflama', + 'Sao Jeronimo da Serra', + 'Rowland Heights', + 'Telkathu', + 'Zhentang', + 'Ifrane', + 'Chailaha', + 'Acoyapa', + 'Grunberg', + 'Illescas', + 'Jacare', + 'Grabels', + 'Anshan', + 'Caloundra', + 'Ruyigi', + 'Kalleribhagam', + 'Rochester', + 'Ban Rawai', + 'Dera', + 'Takanezawa', + 'Palmer Ranch', + 'Rampatti', + 'Heyunkeng', + 'Sittwe', + 'Hiep Hoa', + 'Gorlitz', + 'Yanggezhuang', + 'Ogawa', + 'Zafarwal', + 'Cachoeirinha', + 'Ra`ananna', + 'Raymore', + 'Deneysville', + 'Nurpur', + 'Nosibe', + 'Minamishiro', + 'Northbrook', + 'Colonia General Felipe Angeles', + 'Acacias', + 'G`uzor', + 'Oberwil', + 'Yanjiang', + 'Iflissen', + 'Vsetin', + 'Nimes', + 'Sangrampur', + 'Germering', + 'Coulsdon', + 'Lebon Regis', + 'Malaimachchampatti', + 'Rarz', + 'Clacton-on-Sea', + 'Droylsden', + 'Maroli', + 'Xintian', + 'Wangi', + 'Blaine', + 'Aliganj', + 'Michendorf', + 'Kalaikunda', + 'Betigeri', + 'Talipao', + 'Bheja', + 'Red Wing', + 'Merrillville', + 'Minamisatsuma', + 'Ramsbottom', + 'Catarina', + 'Korb', + 'Lingyuan', + 'Rendon', + 'Ambongo', + 'Aliyabad', + 'Millington', + 'Brdovec', + 'Gujar Khan', + 'Heeze', + 'Binondo', + 'Aix-les-Bains', + 'Civril', + 'Aranyaprathet', + 'Bargteheide', + 'Ambodiangezoka', + 'Talsint', + 'Silvania', + 'Jindayris', + 'Pacuarito', + 'Nuku`alofa', + 'Imi Mokorn', + 'Panjipara', + 'Portales', + 'Ksebia', + 'Sodo', + 'Hoppegarten', + 'Amparo', + 'Pirayu', + 'Narat', + 'Bagaura', + 'Puerto Gaitan', + 'Hoyerswerda', + 'Beckley', + 'Tsarazaza', + 'Mari`', + 'Panitan', + 'Phoenixville', + 'Kinkala', + 'Pilachikare', + 'Chellaston', + 'Ranchuelo', + 'Schuylkill', + 'Can-Avid', + 'Northam', + 'Dedham', + 'Bad Camberg', + 'Oyten', + 'Guaymas', + 'Gaeta', + 'Ankadinandriana', + 'Holalagondi', + 'North Guwahati', + 'Saint-Gaudens', + 'Rancho San Diego', + 'Vicar', + 'San Pedro Pochutla', + 'Uhingen', + 'Policoro', + 'Nabilatuk', + 'Bauyrzhan Momyshuly', + 'Mulakad', + 'Kesan', + 'Asosa', + 'Dewangarh', + 'Ash Shaykh Zuwayd', + 'Nunihat', + 'Itki Thakurgaon', + 'Korsor', + 'Cenovi', + 'Aroali', + 'Schweinfurt', + 'Hirpardangal', + 'Nadisal', + 'El Amim', + 'Zeewolde', + 'Plaisance', + 'Mokronog', + 'Xiaojiangcun', + 'Muhradah', + 'Santa Rosa de Lima', + 'Halvad', + 'Welkenraedt', + 'Kronberg', + 'Lagoa Santa', + 'Liutuancun', + 'Iguig', + 'Blue Island', + 'Codru', + 'Caramoran', + 'Stuart', + 'Marino', + 'Tacheng', + 'Bandar-e Gaz', + 'San Leandro', + 'Athi River', + 'Leirvik', + 'Wattrelos', + "As Suwayda'", + 'Singampunari', + 'Velampalaiyam', + 'Semarang', + 'Garland', + 'Coronel Oviedo', + 'Waldkirch', + 'Gusau', + 'Campton Hills', + 'Kalangala', + 'Palafrugell', + 'Esfarayen', + 'Qazaly', + 'Chelsea', + 'Gokce', + 'Harrisonville', + 'Weare', + 'Shiji', + 'Bakharia', + 'Soanindrariny', + 'Dhanbad', + 'Jayaque', + 'Tanque Verde', + 'Northenden', + 'Matias Cardoso', + 'St. Charles', + 'Gaomi', + 'Moreira Sales', + 'Bharatpur', + 'Chauki', + 'Gokcebey', + 'Kishtwar', + 'Hambantota', + 'Ez Zahra', + 'Ain Beida', + 'Bauru', + 'Chickasha', + 'Simpsonville', + 'Taman Johor Jaya', + 'Skelleftea', + 'Bellaa', + 'Narlidere', + 'Lanciano', + 'Bellmawr', + 'Tataltepec de Valdes', + 'Molo', + 'Kiskunfelegyhaza', + 'Kaisiadorys', + 'San Dionisio', + 'Corpus Christi', + 'Tutin', + 'Betanty', + 'Ambatomanjaka', + 'Koprukoy', + 'Matuga', + 'South Normanton', + 'Kalamata', + 'Trieste', + 'Balikesir', + 'Magsaysay', + 'Fuji', + 'Dorado', + 'Teyateyaneng', + 'Foiano della Chiana', + 'Borba', + 'Gaborone', + 'Puerto Armuelles', + 'Edgware', + 'Ahirauliya', + 'Felpham', + 'Amboaboa', + 'Paso del Macho', + 'Raymond Terrace', + 'Kambam', + 'Los Arabos', + 'Johnston', + 'Placentia', + 'Kharkiv', + 'Sault Ste. Marie', + 'East Glenville', + 'Tamza', + 'Akalgarh', + 'Nwoya', + 'Ordubad', + 'Bulan', + 'Musashimurayama', + 'Lipa City', + 'Tirupporur', + 'Kannudaiyampatti', + 'Sendafa', + 'Angelholm', + 'Carneiros', + 'Vellikulangara', + 'Andanappettai', + 'Mira', + 'Wangqing', + 'Asahikawa', + 'Stryi', + 'Kittery', + 'Rosso', + 'Ramsgate', + 'Diabigue', + 'Anjarkandi', + 'Santiago Tulantepec', + 'Kaul', + 'Pruszkow', + 'Karlskrona', + 'Porto-Vecchio', + 'Pasadena Hills', + 'Ban Bung Kha', + 'Wilmslow', + 'San Juan de Limay', + 'Puran Bigha', + 'Paramagudi', + 'Xima', + 'Khashuri', + 'San Lorenzo della Costa', + 'Medikunda', + 'Belpara', + 'Mountain Home', + 'Burnaby', + 'Sapouy', + 'Rhar el Melah', + 'Pessac', + 'Grevenmacher', + 'Santo Antonio do Monte', + 'Gros Islet', + 'Tarabha', + 'Wimauma', + 'Kumage', + 'Sivamalai', + 'Salmas', + 'Bad Salzdetfurth', + 'Taohuajiang', + 'Tsirang', + 'Dera Ismail Khan', + 'Westbrook', + "'Ayn Bni Mathar", + 'Veppattur', + 'Nettappakkam', + 'Saint-Herblain', + 'Cassano delle Murge', + 'San Jose Acatempa', + 'Sripur', + 'Rae Bareli', + 'Dazaifu', + 'Benguema', + 'Dobni Para', + 'Hajipur', + 'Villars-sur-Glane', + 'Tejen', + 'Itabaiana', + 'Exu', + 'Ninove', + 'Riposto', + 'Baraki Barak', + 'Surat Thani', + 'Setlagode', + 'Rajhanpur', + 'Wancheng', + 'Bom Conselho', + 'Karkkila', + 'Arden Hills', + 'Jasim', + 'Tangainony', + 'Ganguru', + 'Tamiami', + 'Anjiajia', + 'Angren', + 'Balimbing', + 'Vallejo', + 'Sabae', + 'Podgorze', + 'Rio Pardo', + 'Sarzeau', + 'Koniz', + 'El Segundo', + 'Werther', + 'Phalia', + 'Sidi Abd el Moumene', + 'Rajanagaram', + 'Riachao das Neves', + 'Betrandraka', + 'Graben-Neudorf', + "Ighrem n'Ougdal", + 'Kourimat', + 'Reno', + 'Verwood', + 'Naspur', + 'Douar El Mellaliyine', + 'Pichanal', + 'Octeville', + 'Hamadan', + 'Rackeve', + 'Khesht', + 'Anew', + 'South Fulton', + 'Cabo Verde', + 'Cooma', + 'Unnao', + 'Kandanati', + 'Sainkhera', + 'Hasbrouck Heights', + 'Antananarivo', + 'Puca Urco', + 'Hebron', + 'Qal`ah-ye Now', + 'Bara Malehra', + 'Vinales', + 'Kotturu', + 'Ainaro', + 'Kawambwa', + 'Santiago Ixcuintla', + 'Donzdorf', + 'Thong Pha Phum', + 'West Carrollton', + 'Imbau', + 'Shatrana', + 'Nalerigu', + 'Namli', + 'Cumbernauld', + 'Al Musayfirah', + 'Lulea', + 'Jamaica', + 'Vijayapati', + 'Monte Porzio Catone', + 'Carshalton', + 'Gumia', + 'Arvand Kenar', + 'Karaund', + 'Minamiaizu', + 'Gronau', + 'Jinxing', + 'Sixaola', + 'Oulad Hammou', + 'Trongsa', + 'Khenichet-sur Ouerrha', + 'Naifaru', + "K'ebri Dehar", + 'Namagiripettai', + 'East London', + 'Neibu', + 'Himi', + 'Cameron Highlands', + 'Amfilochia', + 'Saranambana', + 'Qingshan', + 'Ishikawa', + 'Monkseaton', + "Al Jahra'", + 'Simmerath', + "At Ta'if", + 'Bama', + 'Meknes', + 'Tiahounkossi', + 'Tucuma', + 'Lower Salford', + 'Punto Fijo', + 'East Greenbush', + 'Ambodimanary', + 'Nilambur', + 'Jalalabad', + 'Qingnian', + 'Barberton', + 'Atari', + 'Jilikul', + 'Cranbrook', + 'Lobogo', + 'Xiegang', + 'La Habra', + 'Alingsas', + 'Onverwacht', + 'Pimpri-Chinchwad', + 'Yatangcun', + 'Coueron', + 'Yaren', + 'Kazincbarcika', + 'Tanta', + 'Rasaunk', + 'Campoalegre', + 'Jurua', + 'Kallur', + 'Cekerek', + 'Tarwara', + 'Burketown', + 'South St. Paul', + 'Corgao', + 'An Thanh B', + 'Borgholzhausen', + 'Tahlequah', + 'Vierzon', + 'Qagan Us', + 'Baravat', + 'Vrsac', + "Za'roura", + 'Bennington', + 'Talamba', + 'Nandyal', + 'Laiwu', + 'Tacuarembo', + 'Cuncolim', + 'Xiaping', + 'Landazuri', + 'Cuautla', + 'Pires Ferreira', + 'Banaz', + 'Cote-Saint-Luc', + 'Manacor', + 'Tantangan', + 'Emmaus', + 'Sonora', + 'Pontiac', + 'Chinandega', + 'Armutlu', + 'Besni', + 'Qingquan', + 'Ceyu', + 'Majuro', + 'Herxheim', + 'Bluefield', + 'Oerlinghausen', + 'Aigues-Mortes', + 'Tosya', + "L'Ile-Saint-Denis", + 'Ban Ngio Ngam', + 'Fortim', + 'Rio Gallegos', + 'Schleiz', + 'Zoudjame', + 'Ondangwa', + 'Ampasimanjeva', + 'Altamont', + 'Wittelsheim', + 'Jayapura', + 'Arni ka Khera', + 'Commack', + 'Morombe', + 'Akdagmadeni', + 'Reidsville', + 'Chinnakkampalaiyam', + 'Girau do Ponciano', + 'Ardrossan', + 'Cherutana Tekku', + 'Kondur', + 'Gwelej', + 'Traiguen', + 'Sannois', + 'Zarach', + 'Lhuentse', + 'Redondo Beach', + 'Maynard', + 'Carmopolis de Minas', + 'Chino Hills', + 'Sohta', + 'Velddrif', + 'Tarifa', + 'Wheatfield', + 'Lasko', + 'Ho Chi Minh City', + 'Osakarovka', + 'Sirajganj', + 'Waidhofen an der Ybbs', + 'Lieusaint', + 'Worsborough', + 'Mandoto', + 'Kochkor', + 'Hindang', + 'Wolmirstedt', + 'Angri', + 'Bagnolet', + 'Hatogaya-honcho', + 'Panelas', + 'Campestre', + 'Boras', + 'Danderesso', + 'Vila Verde', + 'Amborondra', + 'Itapemirim', + 'Muthutala', + 'Qeshm', + 'Halawa', + 'Dosso', + 'Villazon', + 'Breukelen', + 'Pandi', + 'Audenge', + 'Ngou', + 'Urucara', + 'Baham', + 'Mudukulattur', + 'Tubarao', + "Dek'emhare", + 'Sidi Yakoub', + 'Bandhi', + 'Karsiyaka', + 'Shibin al Qanatir', + 'Ajas', + 'Dunedin', + 'Asturias', + 'California', + 'Catania', + 'Vinh', + 'Celano', + 'Tierra Colorada', + 'Dosquebradas', + 'Dunblane', + 'Brejao', + 'Toguere-Koumbe', + 'Lianshan', + 'Roghun', + 'Gokdepe', + 'Aul', + 'Gotvand', + 'Harnes', + 'Choloma', + 'Mamanguape', + 'Miguelturra', + 'Karlovo', + 'Goole', + 'Emir Abdelkader', + 'Sironko', + 'Bokaro Steel City', + 'Altos del Rosario', + 'Saint-Jean-de-Vedas', + 'Hyosha', + 'Tamiang Layang', + 'Scartho', + 'Oltu', + 'Sillanwali', + 'Tadangam', + 'Loures', + 'Kalecik', + 'Sao Jose do Egito', + 'Morelia', + 'Mizan Teferi', + 'Dar Bel Hamri', + 'Ingeniero Guillermo N. Juarez', + 'Vendrell', + 'Wembley', + 'Fritissa', + 'Narasingapuram', + 'Hatvan', + 'Gharyala', + 'Cachoeira Paulista', + 'Pata Putrela', + 'Batang', + 'Burnham-on-Sea', + 'Stuarts Draft', + 'Balzan', + 'Pollachi', + 'Rajpura', + 'Drachten', + 'Agadallanka', + 'Habikino', + 'Mabole', + 'Katipunan', + 'Pachhapur', + 'Banaso', + 'Grinnell', + 'Euskirchen', + 'Ahar', + 'Iranshahr', + 'Mostardas', + 'Shimotsucho-kominami', + 'Maharagama', + 'Owego', + 'Madan', + 'Tomaszow Lubelski', + 'Oisterwijk', + 'Sao Francisco', + 'San Martin Jilotepeque', + 'Iperu', + 'Balaoan', + 'Dubno', + 'Tall `Afar', + 'Kaufungen', + 'Sohwal', + 'Guamuchil', + 'Fosses', + 'Casillas', + 'Ban Noen Phoem', + 'Cuellar', + 'Aurelino Leal', + 'Zeulenroda', + 'Porto Tolle', + 'Lower Hutt', + 'Castelnau-le-Lez', + 'Matabhanga', + 'Ban Ko', + 'Balsa Nova', + 'Brentwood', + 'Brumath', + 'Luban', + 'Mainaguri', + 'Buwenge', + 'Qabqa', + 'Al `Aziziyah', + 'Frutillar Alto', + 'Vatluru', + 'Casale', + 'Ambararata', + 'Studenicani', + 'Lanskroun', + 'Sveti Ivan Zelina', + 'Tokamachi', + 'Bishopstoke', + 'Broxburn', + 'Timizart', + 'Maroharatra', + 'Isselburg', + 'Vandiyur', + 'Los Llanos de Aridane', + 'Winder', + 'Banga', + 'Trophy Club', + 'Olmsted Falls', + 'Zanesville', + 'Zhudong', + 'Bapatla', + 'Peringanad', + 'Cedar Falls', + 'Leanja', + 'Eydhafushi', + 'Paoua', + 'Andribavontsona', + 'Pergamino', + 'Kouri', + 'Bellmore', + 'Bondeno', + 'Comines', + 'Volendam', + 'Pio IX', + 'Cotija de la Paz', + 'Koratla', + 'Tallbisah', + 'Hakubacho', + 'Helsingborg', + 'Braila', + 'Samalpur', + 'Afourar', + 'Briceno', + 'Kabanga', + 'Ambohimahamasina', + 'Quirima', + 'Hakone', + 'Nova Londrina', + 'Nuneaton', + 'Plaisir', + 'Kirikhan', + 'Eccles', + 'West Little River', + 'Nideggen', + 'Gyor', + 'Parchim', + 'Hagere Hiywet', + 'Mirinzal', + 'Lupi Viejo', + 'Buckeye', + 'Ravutulapudi', + 'Landupdih', + 'Santa Barbara de Pinto', + 'Haysville', + 'Dimbokro', + 'Toulouse', + 'Mangdongshan', + 'Vladicin Han', + 'Soma', + 'Springfield', + 'Wedel', + 'Dokuchaievsk', + 'Thai Binh', + 'Mbulu', + 'Muconda', + 'Pearl', + 'Pleszew', + 'Qualicum Beach', + 'Harihans', + 'Yangtangxu', + 'Boa Esperanca do Sul', + 'Saravia', + 'Wepangandla', + 'Morristown', + 'Karaikandi', + 'Elverum', + 'Mexicaltzingo', + 'Kamdoli', + 'Tayabas', + 'Hillsborough', + 'Joao Monlevade', + 'Syracuse', + 'Elliot Lake', + 'Ciudad Guadalupe Victoria', + 'Shampur', + 'Beverstedt', + 'Miajadas', + 'Erode', + 'Sao Pedro do Ivai', + 'Volkermarkt', + 'Lagoa de Itaenga', + 'Kokstad', + 'Jinshui', + 'Miesbach', + 'Lakeland South', + 'Dong Hoi', + 'Illingen', + 'San Dona di Piave', + 'Liantang', + 'Jujutla', + 'Ad Darb', + 'Osicala', + 'Huehuetla', + 'Yambol', + 'Muthallath al Azraq', + 'Asago', + 'Periya Soragai', + 'Anar', + 'Velika Plana', + 'Becej', + 'Hengnan', + 'Brad', + 'Tudiyalur', + 'Skhour Rehamna', + 'Seonar', + 'Muktagacha', + 'Saffron Walden', + 'Cilacap', + 'Ankiliabo', + 'Ramon Magsaysay', + 'Sarenja', + 'Yamanobe', + 'Marcinelle', + 'Abergele', + 'Saraunja', + 'Arankhola', + 'Calexico', + 'Dalaguete', + 'Owatonna', + 'Jalpa de Mendez', + 'Villalbilla', + 'Frameries', + 'Lakewood Park', + 'Erlun', + 'Thandwe', + 'Mons-en-Baroeul', + 'Netishyn', + 'Mindelo', + 'Repelon', + 'Sidon', + 'Ouinhri', + 'Miramar Beach', + 'Cam Ranh', + 'Certaldo', + 'Vedurupavaluru', + 'Alginet', + 'Egil', + 'Ruteng', + 'Chesapeake Ranch Estates', + 'Sao Jose do Jacuipe', + 'Perafita', + 'Barnsley', + 'Hammond', + 'Simav', + 'South Euclid', + 'Tiquipaya', + 'Moorpark', + 'Chernivtsi', + 'Joigny', + 'Cary', + 'Pennadam', + 'Yongping', + 'Sagnay', + 'Lalibela', + 'Tazoult-Lambese', + 'Orta Nova', + 'Dumangas', + 'Trujillo', + 'Borovnica', + 'Buttayagudem', + 'Kegalle', + 'Oshikango', + 'San Juan de Arama', + 'Hathiaundha', + 'Eirunepe', + 'Pakka Kalan', + 'Kita', + 'Msoga', + 'Solothurn', + 'Welkom', + 'La Quinta', + 'Stamford', + 'Serpa', + 'Cadelbosco di Sopra', + "'Ain Tolba", + 'Chaiwu', + 'Kundiawa', + 'Clorinda', + 'Liushuquan', + 'Pingquan', + 'Ouesso', + 'Jiaganj', + 'Ibiraci', + 'Varaklani', + 'Whakatane', + 'Brzesko', + 'Fort Oglethorpe', + 'Pervomaisk', + 'Guiuan', + 'Hadiaya', + 'El Zulia', + 'Mahates', + 'Rio Segundo', + 'Patos', + 'Summerland', + 'Zalantun', + 'Khundawandpur', + 'Soledad de Graciano Sanchez', + 'Xocavand', + 'Denizli', + 'Mangai', + 'Chedaopo', + 'Rathfarnham', + 'Sibanicu', + 'Oxnard', + 'Surubim', + 'Bergama', + 'Keta', + 'Ochiai', + 'Yellanda', + 'Wilsonville', + 'Iguidiy', + 'Cordoba', + 'Tsarahonenana', + 'Flint', + 'Valentim Gentil', + 'Gumushane', + 'Cherbourg', + 'Hosir', + 'Makariv', + 'Pikine', + 'Acayucan', + 'Trebisov', + 'Bagong Pag-Asa', + 'Barr Elias', + 'Santa Coloma de Farnes', + 'Simao', + 'Ballarat', + 'Andoharanomaitso', + 'Bethlehem', + 'Mevani', + 'Sao Miguel dos Campos', + 'Heinsberg', + 'Al Kufah', + 'Pont Sonde', + 'Turkmenbasy', + 'Goldasht', + 'Hamar', + 'Pastores', + 'Veruela', + "Nong'an", + 'Senica', + 'Steinau an der Strasse', + 'Wibsey', + 'Long Khanh', + 'Lubny', + 'Aalsmeer', + 'Citong', + 'Charxin', + 'Soyapango', + 'Avanos', + 'Milas', + 'Padmanabhapuram', + 'Les Palmes', + 'Rangoon', + 'Guichen', + 'Vadakkum', + 'Holon', + 'Faraskur', + 'Cifteler', + 'Malente', + 'Salgado', + 'Udalguri', + 'Broadwater', + 'Olot', + 'Kirkintilloch', + 'Amares', + 'West Drayton', + 'Pliezhausen', + 'Manicore', + 'Kanniparamba', + 'Larisa', + 'Stans', + 'Entraigues-sur-la-Sorgue', + 'Bhelsi', + 'Nuwara Eliya', + 'Montignoso', + 'Yavoriv', + 'Thillangeri', + 'Gajendragarh', + 'Narva', + 'Chirak', + 'Forestville', + 'Waitangi', + 'Yicheng', + 'Machagai', + 'Rasivarai Tottam', + 'Poienile de sub Munte', + 'Dogubayazit', + 'Abhia', + 'Etampes', + 'Puerto San Martin', + 'Panama City Beach', + 'Mittahalli', + 'Rudravaram', + 'Nassau', + 'Bladel', + 'Bauan', + 'Bryne', + 'Mandi Bamora', + 'Schenefeld', + 'Gosaingaon', + 'Nallur', + 'Soanierana', + 'Akhnur', + 'Pedda Adsarlapalli', + 'Waalwijk', + 'Sekondi', + 'Kelo', + 'Squinzano', + 'Itikalapalle', + 'Tattamangalam', + 'Segue', + 'Jaltocan', + 'Coram', + 'Entre Rios', + 'Hafizabad', + 'Konarak', + 'Betsizaraina', + 'Ulanhot', + 'Augsburg', + 'Modica', + 'Nova Olinda', + 'Eastvale', + 'Lechang', + 'Wanaka', + 'Ormesby', + 'Malegaon', + 'Rincon de Romos', + 'Bihta', + 'Mukilteo', + 'Codajas', + 'Hindalgi', + 'Radviliskis', + 'Vasai-Virar', + 'Salor', + 'Eraura', + 'Labrea', + 'Nanuet', + 'Maryborough', + 'Bramhabarada', + 'Rubeho', + 'Scherpenzeel', + 'Osan', + 'Obando', + 'San Antonio', + 'Mamarappatti', + 'Padangpanjang', + 'Wau', + 'Thiene', + 'Avocado Heights', + 'Lake Forest Park', + 'Sallaumines', + 'Nova Venecia', + 'Varadero', + 'Amalner', + 'Debaltseve', + 'Levoca', + 'Beachwood', + "Motta Sant'Anastasia", + 'Kreuztal', + 'Kirundo', + 'Ingeniero White', + 'Tasucu', + 'Spelle', + 'Radomsko', + 'Baleyara', + 'Wencheng', + 'Ambohijanahary', + 'Oullins', + 'Ain Oulmene', + 'Sakete', + 'Alattur', + 'Sobradinho', + 'Hoki', + 'Calgary', + 'Praia', + 'Atbasar', + 'Kisslegg', + 'Chapaev', + 'Chipindo', + 'Livramento de Nossa Senhora', + 'Odemira', + 'Molango', + 'Mortugaba', + 'Kuttanallur', + 'Dahegam', + 'Gardena', + 'Round Lake', + 'San Nicolas', + 'Kinhalu', + 'Osorio', + 'Alanganallur', + 'Santa Cruz del Norte', + 'La Grange', + 'Habra', + 'Ciamis', + 'Zhuji', + 'Maduru', + 'Manyas', + "'Ain el Arbaa", + 'Alampalaiyam', + 'Ribera', + 'Qorashina', + 'Penafiel', + 'Tiraspol', + 'Pitou', + 'Pallikondai', + 'Kabuga', + 'Westerland', + 'Luckau', + 'Saddlebrooke', + 'Bijeljina', + 'Villepreux', + 'Karianga', + 'Tomar do Geru', + 'Guaraniacu', + 'Moravska Trebova', + 'Sunrise Manor', + 'King of Prussia', + 'Lemon Hill', + 'Condeuba', + 'Sikonge', + 'Metlili Chaamba', + 'Maplewood', + 'Qasigiannguit', + 'Banjar', + 'Cucuta', + 'Vazquez', + 'Sour el Ghozlane', + 'Oran', + 'Long Thanh', + 'Sao Domingos do Prata', + 'Fungurume', + 'Grado', + 'Sezze', + 'San Pedro Tapanatepec', + 'Uvalde', + 'Buenaventura', + 'Kanhauli', + 'Tadaoka-higashi', + 'Svitlovodsk', + 'Samut Songkhram', + 'Scherpenheuvel', + 'Filomeno Mata', + 'Mallappulasseri', + 'Royken', + 'Westerville', + 'Nioro', + 'Devendranagar', + 'Itabashi', + 'Itapuranga', + 'Chanteloup-les-Vignes', + 'Santa Lucia di Piave', + 'Satu Mare', + 'Tuni', + 'Chouafa', + 'Sevilla La Nueva', + 'Chaugain', + 'Cuquio', + 'Palm Coast', + 'Antanimieva', + 'Baltasar Brum', + 'Harnaut', + 'Lagoa do Carro', + 'Arenys de Munt', + 'Landecy', + 'Tancitaro', + 'Shanawan', + 'Mangoli', + 'Baharestan', + 'Pia', + 'Witney', + 'Guillena', + 'Namchi', + 'Naryn', + 'Ujhana', + 'Itigi', + 'Douar Oulad Sidi Moussa', + 'Natuba', + 'Hazel Park', + 'Farias Brito', + 'Corumba de Goias', + 'Rhyl', + 'Barkuhi', + 'Piracuruca', + 'Ranst', + 'Koka', + 'Yunshan', + 'Jiran', + 'Zanhuang', + 'Grahamstown', + 'Erandio', + 'Podili', + 'Neerpelt', + 'Leczna', + 'Richterich', + 'Narsingdi', + 'Arnhem', + 'Vodil', + 'Hakkari', + 'Simbach am Inn', + 'Panzos', + 'Chichester', + 'Driouch', + 'Tezontepec', + 'Palmeiras de Goias', + 'Tizi-n-Bechar', + 'Rosyth', + 'Greenlawn', + 'Mali', + 'Sidi Chiker', + 'Kwiha', + 'Busaar', + 'Gangammapeta', + "Be'er Ya`aqov", + 'Potangal', + 'Murayama', + 'Bang Bua Thong', + 'Lerma', + 'Santo Antonio do Taua', + 'Fair Lakes', + 'Creteil', + 'Qigexingcun', + 'Ymittos', + 'Flemington', + 'Northlake', + 'Edlapadu', + 'Angalakuduru Malepalle', + 'Pila', + 'Sinop', + 'La Higuerita', + 'Plymstock', + 'Cateel', + 'Augustow', + 'Ianantsony', + 'Bando', + 'Sizhan', + 'Uppalaguptam', + 'Damu', + 'Bordj Okhriss', + 'Panjab', + 'North Versailles', + 'Adh Dhakhirah', + 'Grove City', + 'Le Poire-sur-Vie', + 'Keshod', + 'Corby', + 'Inhassoro', + 'Hinesville', + 'Espartinas', + 'Gien', + 'Chennirkara', + 'Time', + 'Ziar nad Hronom', + 'Ravels', + 'Pakxan', + 'Namin', + 'Yaragol', + 'Maimbung', + 'Kominato', + 'Bayghanin', + 'South Bend', + 'Manzanillo', + 'Hartselle', + 'Balarampuram', + 'Cay', + 'Estepa', + 'Heliopolis', + 'Analila', + 'Korba', + 'Gusinje', + 'Lake Magdalene', + 'Ambahikily', + 'Rijen', + 'Tuta', + 'Jardinopolis', + 'Cypress Gardens', + 'Bijawar', + 'Soeda', + 'Buena Vista Tomatlan', + 'Lalejin', + 'Muro del Alcoy', + 'Lincoln Park', + 'Beecher', + 'Tansandra', + 'Ambohimanga Atsimo', + 'Manjhi', + 'Nahiyat al Karmah', + 'Rainhill', + 'Elizabethtown-Kitley', + 'Palotina', + 'Alfter', + 'Meppayyur', + 'Domoni', + 'Abay', + 'Nettetal', + 'Paithan', + 'Hafshejan', + 'Dubliany', + 'Balaka', + 'Barauli', + 'Kleinblittersdorf', + 'Belpasso', + 'Shopokov', + 'Eugene', + 'Navalyal', + 'Cieszyn', + 'Bom Retiro do Sul', + 'Taylor', + 'Perehinske', + 'Montale', + 'Attingal', + 'Fresnes', + 'Marofinaritra', + 'Arumbakkam', + 'Djebahia', + 'Diai Koura', + 'Candelaria Loxicha', + 'Boituva', + 'Broni', + 'Orangetown', + 'Pastos Bons', + 'Derinkuyu', + 'Stratford', + 'Ocotlan de Morelos', + 'Trbovlje', + 'Kitui', + 'Dhone', + 'Mohdra', + 'Zwijndrecht', + 'Chocen', + 'Hameenlinna', + 'Londonderry', + 'Ujre', + 'Koko', + 'Pomfret', + 'Rosdorf', + 'Monopoli', + 'Lingig', + 'Ravenna', + 'Herenthout', + 'Bovalino Marina', + 'Wheaton', + 'Almoradi', + 'Estanzuelas', + 'Sao Sebastiao do Passe', + 'Pont-y-pwl', + 'Puliyur', + 'Lagoa da Confusao', + 'Nighoj', + 'Giannouli', + 'Paivalike', + 'Yalamakuru', + 'Aplahoue', + 'Kotabumi', + 'Los Corrales de Buelna', + 'Marumori', + 'Sujnipur', + 'Pleasant Valley', + 'Buala', + 'Downers Grove', + 'Magallanes', + 'Bayt al Faqih', + 'Hualien', + 'Edgewater Park', + 'Pascani', + 'Ukkayapalle', + 'Cabrayil', + 'Xizhou', + 'Ravulapalem', + 'Villefontaine', + 'Al Fayyum', + 'Ulukisla', + 'Hargawan', + 'Tummanatti', + 'Pearl City', + 'Mucuge', + 'Selibe Phikwe', + 'Itsukaichi', + 'Seravezza', + 'Gopalganj', + 'Bodoco', + 'Paderborn', + 'Butare', + 'Sandur', + 'Zgornja Hajdina', + 'Stilfontein', + 'Xuan Trung', + 'Alampur Gonpura', + 'Thimiri', + 'Buhriz', + 'Ballston', + 'Kotla Qasim Khan', + 'Mannegudam', + 'Marinka', + 'Machakos', + 'Mankoeng', + 'Mirandola', + 'Dinard', + 'Komen', + 'Highlands Ranch', + 'Kanra', + 'Boldaji', + 'Kampenhout', + 'Ardea', + 'Long Branch', + 'Katiola', + 'Rancagua', + 'Taima', + 'Innsbrook', + 'Fedosiia', + 'Vohitrindry', + 'Tres Pontas', + 'Kharial', + 'Belinta', + 'Tsu', + 'Zhucaoying', + 'West Chicago', + 'Exeter', + 'Ovar', + 'Fort Portal', + 'Upper Merion', + 'Tiruvarpu', + 'Karmiel', + 'Ivanec', + 'Project Six', + 'Luofeng', + 'Muttayyapuram', + 'Kawaminami', + 'Bila Tserkva', + 'Pfungstadt', + 'Hebi', + 'Kizugawa', + 'Gumusova', + 'Wellingborough', + 'Shimencun', + 'Ourense', + 'Sollies-Pont', + 'Jatani', + 'Ushuaia', + 'Drongen', + 'Lagarto', + 'Las Guaranas', + 'Minas Novas', + 'Ponnampatti', + 'Hola Prystan', + 'Cojutepeque', + 'Randolph', + 'Matsue', + 'Adohoun', + 'Divonne-les-Bains', + 'Talsur', + 'Auki', + 'Obo', + 'Spilamberto', + 'Konodimini', + 'Hanam', + 'Gopavaram', + 'Xambioa', + 'Terra Rica', + 'Pitea', + 'Jussara', + 'Ahuimanu', + 'Hampstead', + 'Bala Cynwyd', + 'El Rosal', + 'Labasa', + 'Garner', + 'Las Maravillas', + 'Toowoomba', + 'Kukshi', + 'Buzau', + 'Tahoua', + 'Koboko', + 'Carlopolis', + 'Wildeshausen', + 'Hershey', + 'Landsmeer', + 'Swarna', + 'Wordsley', + 'Gagarin Shahri', + 'Bad Laer', + 'Adigoppula', + 'Kratovo', + 'Desavilakku', + 'Qalat', + 'Senador Pompeu', + 'Solonopole', + 'Bainet', + 'Mandurah', + 'Kyaukpyu', + 'Willistown', + 'Pirri', + 'Aweil', + 'Akividu', + 'Majdanpek', + 'Qal`eh Tall', + 'Garopaba', + 'Sograha', + 'Al Jizah', + 'Shurobod', + 'Warden', + 'Danielskuil', + 'Paidha', + 'Vargem Alta', + 'Chamestan', + 'Kumasi', + 'Kafr ash Shaykh', + 'Chirundu', + 'Arzachena', + 'Dobrada', + 'Arcot', + 'Matlock', + 'Usmanpur', + 'Silute', + 'Al Qunaytirah', + 'Jablanica', + 'Gaada', + 'Tarazu', + 'Lagoa do Ouro', + 'Yuksekova', + 'Mirfield', + 'Kurmuk', + 'Macia', + 'Karuvakulam', + 'Nice', + 'Ignalina', + 'East Franklin', + 'Malhada', + 'Imbituba', + 'Kasumi', + 'Tiangua', + 'Leonforte', + 'Enumulapalle', + 'Pushpattur', + 'Romford', + 'El Talar de Pacheco', + 'Osakasayama', + 'Lanuza', + 'Bordighera', + 'Bennane', + 'Japura', + 'Yesilli', + 'Marcos Paz', + 'Hickam Housing', + 'Ban Khamen', + 'Shirguppi', + 'Chemmaruthi', + 'Woodlesford', + 'Povazska Bystrica', + 'Kotia', + 'Gunri', + 'Nawagarh', + 'Judenburg', + 'Hammam-Lif', + 'Matina', + 'Verkhnodniprovsk', + 'San Lucas', + 'Jacaraci', + 'Glarus', + 'Manoli', + 'Monticello', + 'Urziceni', + 'Pryluky', + 'Langhirano', + 'Buriti Bravo', + 'Skenderaj', + 'Bari', + 'Cho Moi', + 'Kahla', + 'Grojec', + 'Berea', + 'Wyandotte', + 'Jaguapita', + 'Modavandisatyamangalam', + 'Danesfahan', + 'Larache', + 'North Potomac', + 'Kharupatia', + 'Kisangani', + 'Nuoro', + 'Janakkala', + 'Bhatkhori', + 'Mungaoli', + 'Yalova', + 'Qaratog', + 'Yesilova', + 'Tualatin', + 'Sandviken', + 'Bickenhill', + 'Inwood', + 'Meckenheim', + 'Davidson', + 'Kanhaipur', + 'Longton', + 'Sendurai', + 'Paniem', + 'Jujharpur', + 'Sasolburg', + 'Rambouillet', + 'March', + 'Ewing', + 'Seogwipo', + 'Huber Heights', + 'Calabanga', + 'Mallasamudram', + 'Dharawat', + 'Ngara', + 'Pensacola', + 'Tuzluca', + 'Lauenburg', + 'Kidangazhi', + 'Ucu Seles', + 'Enebakk', + 'Nalua', + 'Aubiere', + 'Manfredonia', + 'Nacunday', + 'Street', + 'Sao Bernardo do Campo', + 'Sidhauli', + 'Igarape-Acu', + 'Teodoro Schmidt', + 'Barra do Corda', + 'Tangua', + 'Yibin', + 'Ozdere', + 'Chak Habib', + 'Medchal', + 'Surab', + 'Snyder', + 'Teus', + 'Oulad Slim', + 'Ingurti', + 'Manaure', + 'Jaipur', + 'Zlate Moravce', + 'Castillejos', + 'Kalakeri', + 'Mahavelona', + 'Iesi', + 'Bedford Heights', + 'Dinokana', + 'Shimogamo', + 'Mohammad Yar', + 'Ban Kham Pom', + 'Nannestad', + 'Espiye', + 'Jiji', + 'Bulandshahr', + 'Wetteren', + 'Valattur', + 'Hejian', + 'Wete', + 'Beverley', + 'Marar', + 'Olecko', + 'Chalatenango', + 'Dommasandra', + 'Chilamatturu', + 'Petit-Trou de Nippes', + 'Ratnagiri', + 'Crozet', + 'Birganj', + 'Dehiba', + 'Vettweiss', + 'Kucuk Dalyan', + 'Nirmal', + 'Simi Valley', + 'Wels', + 'Fredericton', + 'Nykoping', + 'Salgueiro', + 'Naantali', + 'Koliakkod', + 'Cruz das Almas', + 'Cardoso Moreira', + 'Sao Paulo', + 'Lugovoy', + 'Sheffield Lake', + 'Focsani', + 'Saarijarvi', + 'La Magdalena Chichicaspa', + 'Clarkstown', + 'Bongabong', + 'Raisen', + 'Aguadas', + 'Pomaz', + 'Shahpur Undi', + 'Wervershoof', + 'Cochoapa el Grande', + 'Malaybalay', + 'Mesudiye', + 'Caravaggio', + 'Moviya', + 'Manay', + 'Kitanakagusuku', + 'Basi', + 'Kant', + 'Garmeh', + 'Weeze', + 'Kenieran', + 'Epping', + 'Serra do Salitre', + 'Sabzevar', + 'Timbiqui', + 'Andilanatoby', + 'West Point', + 'Nneyi-Umuleri', + 'Brembate', + 'Bendigo', + 'Pitrufquen', + 'Mobara', + 'Tuku', + 'Herkimer', + 'Rokunohe', + 'Aliso Viejo', + 'Shirataka', + 'Huajiang', + 'Imam Sahib', + 'Toyoake', + 'Cidade Velha', + 'Bull Run', + 'Leguevin', + 'Sao Domingos', + 'Sidi Barani', + 'Ejeda', + 'Xishrov', + 'Ebebiyin', + 'Oruvadalkotta', + 'Gurwalia Biswas', + 'Mariupol', + 'Ulft', + 'Necocli', + 'Ambriz', + 'Saltsjobaden', + 'Oulad Dahmane', + 'Adelaide River', + 'Bikaner', + 'Condoto', + 'Shah Latif Town', + 'Manantheri', + 'Mossley', + 'Piracununga', + 'Parappanangadi', + 'Revel', + 'Atmakuru', + 'Pullappalli', + 'Shengli', + 'Salto', + 'Los Mochis', + 'Pattittara', + 'Dahuaishu', + 'Yamasa', + "Val-d'Or", + 'Holic', + 'Tarxien', + 'Meishan', + 'Baghant', + 'Panrepatti', + 'Edemissen', + 'Rockport', + 'Chavassheri', + 'Swampscott', + 'Torroella de Montgri', + 'Chauk Azam', + 'Moul El Bergui', + 'Isla-Cristina', + 'Oulad Ayyad', + 'Qorveh', + 'Yoshiicho-shimobaru', + 'Jangipur', + 'Port Alberni', + 'Beauchamp', + 'Ratba', + 'Beni Douala', + 'Kunduz', + 'Seosaeng', + 'Etaples', + 'Bludenz', + 'Golaghat', + 'Sujanpur', + 'Doctor Arroyo', + 'Bugho', + 'Borgarnes', + 'Solanea', + 'Boulogne-Billancourt', + 'Khosrowshahr', + 'Paithan Kawai', + 'Kaltenkirchen', + 'Jordan', + 'Motiong', + 'Daraj', + 'Manhattan', + 'Debica', + 'Bina', + 'Nanjanad', + 'Campina', + 'Antsahavaribe', + 'Maizal', + 'Saint-Nicolas', + 'Round Lake Beach', + 'Kamalasai', + 'Yeola', + 'Dangila', + 'East Bradford', + 'Noale', + 'Germencik', + 'De Aar', + 'Taihecun', + 'Kilinochchi', + 'Karivalamvandanallur', + 'Vinany', + 'Pudtol', + 'Visselhovede', + 'Perigny', + 'Izalco', + 'Dhuri', + 'Rudarpur', + 'San Marzano sul Sarno', + 'Kambar', + 'Le Hochet', + 'Skalavik', + 'Dharhara', + 'Agutaya', + 'Montpelier', + 'Santa Pola', + 'Budelsdorf', + 'Gyapekurom', + 'Medan', + 'Egilsstadhir', + 'Somasso', + 'Carsamba', + 'Nepalganj', + 'Bobil', + 'San Guillermo', + 'Hyrum', + 'Dhauni', + 'Al Hisn', + 'Hengkou', + 'Nenagh', + 'Lake Monticello', + 'Kokiladanga', + 'Aves', + 'Iwaizumi', + 'Santa Quiteria do Maranhao', + 'Kusugal', + 'Misano Adriatico', + 'Liangyi', + "Qa'em Shahr", + 'Okene', + 'Dorsten', + 'Inglewood', + 'Waianae', + 'Nerupperichchal', + 'Ghandinagar', + 'Le Portel', + 'Nazare', + 'Douar Lehgagcha', + 'Boende', + 'Aracruz', + 'Atar', + 'Golhisar', + 'Niar', + 'Kristiansund', + "Mu'minobod", + 'Ilchester', + 'Jodoigne', + 'Mudanjiang', + 'Parapatti', + 'Youssoufia', + 'Has', + 'Rzeszow', + 'View Park-Windsor Hills', + 'Redland', + 'Bni Sidel', + 'Cumbum', + 'Sue', + 'Ban Pae', + 'Eghezee', + 'Lebedinovka', + 'Demerval Lobao', + 'Teplodar', + 'Moose Jaw', + 'Rahika', + 'Edwards', + 'Imdina', + 'Zuhres', + 'Gillette', + 'Tixter', + 'Valenii de Munte', + 'Zhangliangcun', + 'Failsworth', + 'Dormentes', + 'Chowchilla', + 'Osasco', + 'Cheste', + 'Elmadag', + 'Timberwood Park', + 'Tiruttani', + 'Souba', + 'Maripad', + 'Tiltil', + 'Piossasco', + 'Comstock Park', + 'Sagrada Familia', + 'San Raimundo', + 'Killeen', + 'Miracema', + 'Singapore', + 'Olocuilta', + 'Ribeirao do Pinhal', + 'Itaquitinga', + 'Haltom City', + 'Chanderi', + 'Jarabulus', + 'Chennampatti', + 'Izumo', + 'Taruma', + 'Sottaiyampalaiyam', + 'Ichikawamisato', + 'Brockton', + 'Pandua', + 'Willow Street', + 'Truro', + 'Topola', + 'Blumenau', + 'Braine-le-Comte', + 'Duga Resa', + 'Liesveld', + 'Cairu', + 'Kolongo-Bozo', + 'Huanghua', + 'La Oliva', + 'Yokkaichi', + 'Tres Lagoas', + 'Westervoort', + 'Michelstadt', + 'Cavalcante', + 'La Lima', + 'Ampanotokana', + 'Roma', + 'Latacunga', + 'Eckington', + 'Cam Pha', + 'Kangqiao', + 'Remanso', + 'Jipijapa', + 'Dbarwa', + 'Cody', + 'Narsarsuaq', + 'Windhoek', + 'Razgrad', + 'Xinhualu', + 'Aosta', + "M'Chouneche", + 'Aydarken', + 'Analamitsivalana', + 'Boro', + 'Yelur', + 'Manteno', + 'As Sarw', + 'Ban Bueng Phra', + 'Puliyankudi', + 'Istaravshan', + 'Pithaura', + 'Onex', + 'Chakdarra', + 'Kareli', + 'Dinshaway', + 'Matalam', + 'Yongju', + 'Kumarapuram', + 'Yidu', + 'St. Joseph', + 'Fort Bonifacio', + 'Mecayapan', + 'Saint-Dizier', + 'Sharurah', + 'Uruara', + 'Macusani', + 'Stollberg', + 'Avelino Lopes', + 'Eschenbach', + 'Kamianka-Buzka', + 'Merced', + 'Ishizaki', + 'Ratan', + 'Majholi', + 'Portimao', + 'Guyancourt', + 'Ampasimena', + 'Dengshangcun', + 'Teno', + 'Cachira', + 'Davaci', + 'Tamamura', + 'Clifton Park', + 'Ma`bar', + 'Aartselaar', + 'Blundellsands', + 'Richards Bay', + 'Bussolengo', + 'Ratnahalli', + 'Bestensee', + 'Manjacaze', + 'Solano', + 'Mercerville', + 'Wujie', + 'Luderitz', + 'Campo Formoso', + 'Pobiedziska', + 'Ennamangalam', + 'Claiborne', + 'Elesvaram', + 'Begogo', + 'San Salvo', + 'Tambura', + 'Zumbo', + 'Margate', + 'Naini Tal', + 'Mao', + 'Castelfranco di Sotto', + 'Guachaves', + 'Artemisa', + 'Ovalle', + 'Piedras Blancas', + 'Dhanauri', + 'Vengapalli', + 'Tnine Sidi Lyamani', + 'Balindong', + 'Busia', + 'Codigoro', + 'Shiqiao', + 'Eidson Road', + 'Malita', + 'Kapatagan', + 'Ervalia', + 'Sibuco', + 'Rattaphum', + 'Wolfratshausen', + 'Jucurucu', + 'Lismore', + 'Lagangilang', + 'Ech Chaibat', + 'Iguaba Grande', + 'Bayan Hot', + 'Senjan', + 'Mihara', + 'Sandwich', + 'Huanglongsi', + 'Hualaihue', + 'Campos do Jordao', + 'Radauti', + 'Hersham', + 'Rutherford', + 'Kavallemmavu', + 'Bindura', + 'Niono', + 'Hammam Dalaa', + 'Varto', + 'Qina', + 'Aringay', + 'Trofarello', + 'Goshikicho-aihara-minamidani', + 'Taozhou', + 'Wickford', + 'Casale sul Sile', + 'Pointe a Raquettes', + 'Dolianova', + 'Morpeth', + 'Safdarabad', + 'Asamankese', + 'Mifune', + 'South Huntington', + 'Antri', + 'Ambohimahazo', + 'Nangis', + 'Lincolnwood', + 'Vieira do Minho', + 'Marigliano', + 'Sankt Valentin', + 'Ota-ku', + 'Montes Claros', + 'Scottsboro', + 'Gulni', + 'Bogovinje', + 'Tlalnelhuayocan', + 'Little Canada', + 'Bni Bouayach', + 'Porto Rafti', + 'Pontal', + 'Milha', + 'Kigoma', + 'Littleborough', + 'Tarur', + 'Myers Corner', + 'Salamedu', + 'Hernando', + 'Sava', + 'Rowley Regis', + 'Qax', + 'Mor', + 'Jalalaqsi', + 'Fereydun Kenar', + 'Aubergenville', + 'Puranattukara', + 'Vondrozo', + 'Pombal', + 'Upper Providence', + 'Huizhou', + 'Mali Idos', + 'Townsville', + 'Bolbec', + 'Nanpara', + 'Tocantins', + 'Oulgaret', + 'Marmara Ereglisi', + 'Pedra', + 'Sahapur', + 'Puerto Lleras', + 'Soccorro', + 'Enerhodar', + 'Adams', + 'Khetko', + 'Bacobampo', + 'Naxxar', + 'Wilton', + 'Manantenina', + 'Montecatini Terme', + 'Ocumare del Tuy', + 'Kas', + 'Nagarpara', + 'Tagounite', + 'Magnago', + 'Paripueira', + 'Guerra', + 'Ecaussinnes-Lalaing', + 'Tittachcheri', + 'Cariacica', + 'Missaglia', + 'Niscemi', + 'Ajdabiya', + 'Santa Cruz das Palmeiras', + 'Bogucice', + 'Centurion', + 'Aalst', + 'Tupelo', + 'Kochhor', + 'Riihimaki', + 'Sjobo', + 'Dongguan', + 'Melbourne', + 'Goluchow', + 'Devapur', + 'Merimbula', + 'North Port', + 'Bou Izakarn', + 'Cuisnahuat', + 'Cunday', + 'Sao Bernardo', + 'Everett', + 'Gyal', + 'Cedar Grove', + 'Piriapolis', + 'Mamakating', + 'Narathiwat', + 'Wood River', + 'Kebemer', + 'Salzburg', + 'Roebourne', + 'Port-au-Prince', + 'Ulliyeri', + 'Simferopol', + 'Navojoa', + 'Kuna', + 'Ikeda', + 'Dinan', + 'Champadanga', + 'Kottayam', + 'Itajai', + 'Moulay Abdallah', + 'Ponnuru', + 'Pakribarawan', + 'Canakkale', + 'Mestre', + 'Kannampalaiyam', + 'Lang Suan', + 'Libiaz', + 'Naftalan', + 'Guanzhai', + 'Juruti', + 'Hautmont', + 'Coro', + 'Navani', + 'Cagdianao', + 'Bauska', + 'Waltershausen', + 'Karippira', + 'Kodiyeri', + 'Huercal de Almeria', + 'Lebane', + 'Tando Allahyar', + 'El Bordj', + 'Polva', + 'Asasa', + 'Capilla de Guadalupe', + 'Vadapalanji', + 'Mekhe', + 'Leigh-on-Sea', + 'Velykyi Bychkiv', + 'Sihali Jagir', + 'Tepetitlan', + 'Sincelejo', + 'Caorle', + 'Burrel', + 'Ebetsu', + 'Niagara-on-the-Lake', + 'Tucson Mountains', + 'Manawar', + 'Uige', + 'Ankaramy', + 'Guinobatan', + 'Andrakata', + 'Patulul', + 'Patnos', + 'Bengkulu', + 'Strakonice', + 'Bairo', + 'Sint Anthonis', + 'Astorp', + 'Chantepie', + 'Stara Gora', + 'Fierenana', + 'Phenix City', + 'Schmalkalden', + 'Nadi', + 'Vimodrone', + 'Maramag', + 'Satipo', + 'El Oued', + 'Dogbo', + 'Needham', + 'Mitu', + 'North Vancouver', + 'Belmonte', + 'Turmanin', + 'Beandrarezona', + 'Shiraz', + 'Edgewood', + 'Eqbaliyeh', + 'West Whiteland', + 'Nchelenge', + 'Sason', + 'Suknah', + 'Alhandra', + 'Boghni', + 'Versoix', + 'Beverwijk', + 'Satyun', + 'Village Green-Green Ridge', + 'Luuk', + 'Speedway', + 'Yanbu', + 'Bhitarwar', + 'Kluang', + 'Sastamala', + 'Mulangodi', + 'Olivares', + 'Kondhali', + 'Inkollu', + 'Piedras Negras', + 'Consuelito', + 'Uruguaiana', + 'Nowy Targ', + 'Puvali', + 'Hulshout', + 'Pleasant Grove', + 'Armant', + 'Viga', + 'Igbanke', + 'Plover', + 'Bene Beraq', + 'Yopougon', + 'San Nicolas de los Ranchos', + 'Piui', + 'Gieraltowice', + 'Tarana', + 'Yanai', + 'Chariyakulam', + 'Bogota', + 'Minamisanriku', + 'Werl', + 'Manuel Ribas', + 'Heusenstamm', + 'Grosseto', + 'Villeparisis', + 'Serramanna', + 'Sudlohn', + 'Mawatagama', + 'Starokostiantyniv', + 'Vaikam', + 'Ipiales', + 'New Baltimore', + 'Quinta de Tilcoco', + 'Borgaro Torinese', + 'Tapiratiba', + 'Cazzago San Martino', + 'Esperanca', + 'Yirol', + 'Mila', + 'Tangalan', + 'Sardarshahr', + 'Palmetto', + 'Heddesheim', + 'Grossburgwedel', + 'Pradera', + 'Bela Vista do Paraiso', + 'Kilwinning', + 'Dunn Loring', + 'Bcharre', + 'Bhagirathpur', + 'Cabadbaran', + 'Hino', + 'Runcorn', + 'Santiago de Compostela', + 'Sotouboua', + 'Tecate', + 'Morasar', + 'Vanono', + 'Sankt Ingbert', + 'Jajce', + 'Xinyu', + 'Hochst im Odenwald', + 'Kawthoung', + 'Cherry Hill', + 'Riebeeckstad', + 'Cacheu', + 'Tranovaho', + 'Douar Sgarta', + 'Tlemcen', + 'Mandabe', + 'Idil', + 'Bohicon', + 'East Cocalico', + 'Wekiwa Springs', + 'Magdalena Milpas Altas', + 'South Charleston', + 'Dougba', + 'Glenwood Springs', + 'Dumfries', + 'Moyale', + 'Mabini', + 'Santa Terezinha de Goias', + 'Evergreen', + 'Watford', + 'Rabor', + 'Castel Mella', + 'Tanabe', + 'Tafaraoui', + 'Hilter', + 'Shujaabad', + 'Videm', + 'Kecskemet', + 'Obertraubling', + 'Folomana', + 'Novi Becej', + 'Molalla', + 'Hagta', + 'Tisina', + 'Raikal', + 'Wendell', + 'Canet-en-Roussillon', + 'Kennedy', + 'Herzberg am Harz', + 'San Simon', + 'Miyatoko', + 'Pali', + 'Copiapo', + 'Muhldorf', + 'Bambadinca', + 'Igbaras', + 'Kothi', + 'Souq Sebt Says', + 'San Rafael Abajo', + 'Halisahar', + 'Mamaroneck', + 'Varisshiyakuni', + 'Matsoandakana', + 'Burgas', + 'Bhanghi', + 'Beverly', + 'Raichur', + 'Tahannawt', + 'Tota', + 'Lunel', + 'Souk Tlet El Gharb', + 'Racine', + 'Stockerau', + 'Mazamitla', + 'Guachucal', + 'Malepur', + 'Sarikamis', + 'Gothenburg', + 'Suganwan', + 'Kirikkale', + 'Maghull', + 'Chonchi', + 'Ospitaletto', + 'Maria da Fe', + 'Chalandri', + 'Bobon', + 'Naqadah', + 'Martinopole', + 'Enghien', + 'Savigny-le-Temple', + 'Ramchandarpur', + 'Caio', + 'Belo', + 'Bukowno', + 'Tel Aviv-Yafo', + 'Avabodji', + 'Puerto America', + 'Hanson', + 'Huangshan', + 'Bulusan', + 'Domazlice', + 'Linkenheim-Hochstetten', + 'Suaza', + 'Mangalagiri', + 'Rocky River', + 'Tanakoub', + 'Canicatti', + 'Las Rosas', + 'Mahlaing', + 'Jelenia Gora', + 'Mathila', + 'Aizawa', + 'Itatiaia', + 'Neuri', + 'Chivacoa', + 'Arvorezinha', + 'Armanaz', + 'Buritizeiro', + 'Bien Hoa', + 'Bruchkobel', + 'Dolo Bay', + 'Lefkada', + 'Tasiusaq', + 'Pallappatti', + 'Kanchrapara', + 'San Roque', + 'Jefferson', + 'Santiago de Baney', + 'Kofu', + 'Harchandpur', + 'Moss Bluff', + 'Vushtrri', + 'Mithi', + 'Smederevska Palanka', + 'Apan', + 'Deodha', + 'Nallihan', + 'Guapo', + "Ghinda'e", + 'Sar-e Pul', + 'Christiansburg', + 'Pont-a-Celles', + 'Overijse', + 'Trecastagni', + 'Oulad Embarek', + 'Dayr Hafir', + 'Caldas de Reyes', + 'Arkalochori', + 'Gafsa', + 'Cipolletti', + 'Kaikaram', + 'Shuangshuicun', + 'Iquitos', + 'Hazaribagh', + 'Bedidy', + 'Mayate', + 'Chumbicha', + 'Dilasag', + 'Karapa', + 'Petaling Jaya', + 'Castel Gandolfo', + 'Yevpatoriia', + 'Kuchaiburi', + 'Hanyu', + 'Horn Lake', + 'Kadiria', + 'Zhongba', + 'Godoy Cruz', + 'Malappuram', + 'East Peoria', + 'Markranstadt', + 'Livonia', + 'Dongen', + 'Golbasi', + 'Bhagwangola', + 'Elektrenai', + 'Hat Yai', + 'Saint John', + 'Torihama', + 'Galimuyod', + 'Raikot', + 'Bagre', + 'Komijan', + 'Ibia', + 'Holyhead', + 'Akwatia', + 'Elavanasur', + 'Tandag', + 'Chilwell', + 'Ciudad Ojeda', + 'Ciudad Serdan', + 'Radlett', + 'Vembarpatti', + 'Atripalda', + 'Gourock', + 'Anama', + 'Amblecote', + 'Excelsior Springs', + 'Dadu', + 'Offa', + 'Brindisi', + 'Kovilpatti', + 'Chrudim', + 'Cesson-Sevigne', + 'Mediouna', + 'Zengqiao', + 'Aguilares', + 'Siay', + 'Mananjary', + 'Kolarovo', + 'Melissia', + 'Stari Trg', + 'Viadana', + 'Stolberg', + 'Berekum', + 'Farako', + 'Joyabaj', + 'San Giorgio di Piano', + 'Carbonera', + 'Mackay', + 'Meltham', + 'Challapalle', + 'Saricam', + 'Tres Barras', + 'Cannes', + 'Upper Darby', + 'Arlington', + 'Sanxi', + 'Sanankoro Djitoumou', + 'Birur', + 'Manne Ekeli', + 'Regenstauf', + 'Midsalip', + 'Reggello', + 'Corinda', + 'Babatngon', + 'Bungku', + 'Zhangshu', + 'Idiofa', + 'Amboanana', + 'Langley', + 'Fishersville', + 'Mateare', + 'Linda', + 'Helena', + 'Hohenstein-Ernstthal', + 'Korla', + 'Bairuo', + 'Limoeiro do Ajuru', + 'Gandevi', + 'Rogers', + 'Dexing', + 'Padugaipattu', + 'Ilmenau', + 'Litovel', + 'Yasenivskyi', + 'Boca da Mata', + 'Sarkad', + 'Pawayan', + 'Avon Park', + 'Kondarangi Kiranur', + 'Novgorodskoye', + 'Nanattuparai', + 'Krishnapur', + 'Mendez-Nunez', + 'Alacam', + 'Pelissanne', + 'Colotlan', + 'Raahe', + 'Ridder', + 'Jisr ash Shughur', + 'Hoveyzeh', + 'Rokkasho', + 'Muquem de Sao Francisco', + 'Tsuru', + 'Ross-Betio', + 'Escanaba', + 'Tacana', + 'Traverse City', + 'Gounarou', + 'Fontaine', + 'Sahuarita', + 'Bracciano', + 'Araripina', + 'Gambissara', + 'Lumphat', + 'Gwangmyeongni', + 'Kirrayach', + 'University Place', + 'Unai', + 'Paracin', + 'Juara', + 'Ware', + 'Hilltown', + 'Summit Park', + 'Mislata', + 'Rottofreno', + 'Uniontown', + 'Kulu', + 'Bunia', + 'Ciudad Bolivar', + 'Gitagum', + 'Uniao dos Palmares', + 'Erumaippatti', + 'Pichhor', + 'Yuanlin', + 'Bulungu', + 'Kadakola', + 'Harur', + 'Raunheim', + 'Mothihari', + 'Malahide', + 'Macapa', + 'Mahabo', + 'Andonabe Atsimo', + 'Hita', + 'Salesopolis', + 'Tirkakara', + 'Malhargarh', + 'Oakengates', + 'Agrinio', + 'Whitehall', + 'Lapuyan', + 'Botticino Sera', + 'Tinoc', + 'Jiquilpan de Juarez', + 'Rockville Centre', + 'Ibatiba', + 'Ballina', + 'Broken Arrow', + 'Ziniare', + 'Clayton le Moors', + 'Fredensborg', + 'Kharod', + 'Umm al `Abid', + 'Goldenrod', + 'Yacopi', + 'Halsur', + 'Opoczno', + 'Kottapalle', + 'Ubrique', + 'Sodrazica', + 'Irakleia', + 'Sao Luis Gonzaga', + 'Sao Paulo do Potengi', + 'North Gates', + 'Alsip', + 'Choele Choel', + 'Antsiatsiaka', + 'Beocin', + 'Tenancingo', + 'Monselice', + 'Marpalli', + 'Yangqingcun', + 'Columbine', + 'Sahamadio', + 'San Nicolas Buenos Aires', + 'Tiruvur', + 'Anosimparihy', + 'Lariano', + 'Chaval', + 'Karavan', + 'Kingsbury', + 'Koduru', + 'Bangolo', + 'Heidenau', + 'Petrolina', + 'Archena', + 'Natonin', + 'Casalnuovo di Napoli', + 'Nova Odessa', + 'Kariz', + 'Caen', + 'Scugog', + 'Bangalore', + 'Zijinglu', + 'Catford', + 'Chakapara', + 'Safita', + 'Acquaviva', + 'Satai', + 'Ghabaghib', + 'La Spezia', + 'Iquique', + 'Barhampur', + 'Chalungalpadam', + 'Kerur', + 'Gulnar', + 'Banigbe', + 'Metamorfosi', + "Ma'muniyeh", + 'Tura', + 'Seelze', + 'White Plains', + 'Reddippatti', + 'Ticuantepe', + 'Ntoroko', + 'Nairobi', + 'Glubczyce', + 'Safi', + 'Larne', + 'Sebin Karahisar', + 'Donegal', + 'Pasto', + 'Ceyhan', + 'East Grand Forks', + 'Qarqan', + 'Ferney-Voltaire', + 'Caybasi', + 'Ayanavelikulangara Tekku', + 'Derventa', + 'Homburg', + 'Zaouiet Says', + 'Jethuli', + 'Ketti', + 'Rochdale', + 'Zevio', + 'Made', + 'Eleskirt', + 'Iijima', + 'Rubirizi', + 'Mombris', + 'Santa Teresita', + 'Pedappai', + 'Vineland', + 'Saint-Amable', + 'Awara', + 'Betton', + 'Alsbach-Hahnlein', + 'Tongzhou', + 'Nopala de Villagran', + 'Propria', + 'Jawkatia', + 'Morrovalle', + 'Bella Vista', + 'Lufeng', + 'Lebach', + 'Wanda', + 'East Highland Park', + 'Phu Yen', + 'Masangshy', + 'Bou Sfer', + 'Kumirimora', + 'Shibushi', + 'Falticeni', + 'Wallington', + 'Bryn', + 'Dornstadt', + 'Sembe', + 'Onan', + 'Brandizzo', + 'Voerendaal', + 'Qaladizay', + 'Butwal', + 'Kunzell', + 'Dindanko', + 'Knezha', + 'Half Moon Bay', + 'Upleta', + 'Cambuslang', + 'Zupanja', + 'Ronse', + 'Seneca Falls', + 'Karlshamn', + 'Attippattu', + 'Terzigno', + 'Brumado', + 'Bangaon', + 'Szczecin', + 'Jauharabad', + 'Pisticci', + 'Gukeng', + 'Conceicao do Araguaia', + 'Saltash', + 'Parvomay', + 'Ban Wat Phrik', + 'Cabaiguan', + 'Awa', + 'Nemours', + 'Yukuhashi', + 'Bujari', + 'Jiwachhpur', + 'Rongwo', + 'Puerto Nare', + 'Anjomachi', + 'Lagbe', + 'Mickleover', + 'Mianyang', + 'Eshowe', + 'Bonnievale', + 'Radekhiv', + 'Sagauli', + 'Ankirihitra', + 'University Park', + 'Punjai Lakkapuram', + 'Hamlin', + 'Feni', + 'Legnica', + 'Gandhali', + 'Deyang', + 'Scotts Valley', + 'North Ogden', + 'Tocantinopolis', + 'Princesa Isabel', + 'Weert', + 'Chos Malal', + 'West Odessa', + 'Mawanella', + 'Aljaraque', + 'Majhariya', + 'Nagayalanka', + 'Tring', + 'Lenox', + 'Kebila', + 'Fatehpur Bala', + 'Mucheln', + 'Sangolqui', + 'Gohadi', + 'Komaki', + 'Malaudh', + 'Coquitlam', + 'Florencia', + 'Kalisizo', + 'Eslamshahr', + 'Tychy', + 'Lazaro Cardenas', + 'Pallarimangalam', + 'Yang Talat', + 'Arsuz', + 'Bhavani', + 'Maniwa', + 'Santa Luzia do Itanhy', + 'Oranienburg', + 'Huangshi', + 'Zaranj', + 'Halver', + 'Areado', + 'Hadjadj', + 'Balykchy', + 'Effingham', + 'Valley Stream', + 'Pinhao', + 'West New York', + 'Heishanzuicun', + 'Bordentown', + 'Inirida', + 'La Huerta', + "Sant'Egidio alla Vibrata", + 'Dharapuram', + 'Ad Dulu`iyah', + 'Kaarina', + 'Rekovac', + 'Manitowoc', + 'Goroka', + 'Motul', + 'Narasingam', + 'Beckenham', + 'Kirkwood', + 'Kolondieba', + 'Pasadena', + 'Qo`ng`irot Shahri', + 'Winsen', + 'Mers el Kebir', + 'Poro', + 'Knjazevac', + 'Dajiecun', + 'Tangjin', + 'Karbinci', + 'Beykoz', + 'Amadeo', + 'Manamelkudi', + 'Tekanpur', + 'Busolwe', + 'Ac-cahrij', + 'Coroico', + 'Inhambane', + 'Jacinto', + 'Carlentini', + 'Skippack', + 'Federal', + 'Valenzano', + 'Zhangcun', + 'Loenen', + 'Muswellbrook', + 'Tamazunchale', + 'Moatize', + 'Port Salerno', + 'Lisbon', + 'Santo Estevao', + 'Irondequoit', + 'Levallois-Perret', + 'San Antonio Suchitepequez', + 'Zvecan', + 'Douar Lamjaara', + 'Winter Springs', + 'Bimawan', + 'Pentapadu Kasba', + 'Montijo', + 'Sena Madureira', + 'Virei', + 'Varzaneh', + 'Sariveliler', + 'Vatakemuri', + 'Machelen', + 'Nabunturan', + "Yong'ancun", + 'Dalsingh Sarai', + 'Etoumbi', + 'Funadhoo', + 'Antur', + 'Superior', + 'Matouying', + 'Abucay', + 'Kengarai', + 'Paterna', + 'Saqqez', + 'Spring Creek', + 'Garaimari', + 'Nan Zhuang', + 'Jones', + 'Bou Khadra', + 'Rosh Ha`Ayin', + 'Adalhat', + 'Capaya', + 'Kuruman', + 'Chaoyangdicun', + 'Villacarrillo', + 'South Portland', + 'Bambui', + 'Apalit', + 'Biddupur', + 'Baqiabad', + 'Kostanjevica na Krki', + 'Rechaiga', + 'Morwell', + 'Koundian', + 'Higashimiyoshi', + 'Castro', + 'At Tur', + 'Pirnagar', + 'Vandalia', + 'Nellipaka', + 'Zerong', + 'Goodlands', + 'Hatay', + 'Bielsko-Biala', + 'Grosse Pointe Woods', + 'Ajijic', + 'Dhanupra', + 'Pachrukha', + 'Handwara', + 'Ranopiso', + 'Vallenar', + 'Santa Maria do Suacui', + 'Loyalist', + 'Chinameca', + 'Mahazoma', + 'Silifke', + 'Falakata', + 'Ghordaur', + 'Black Forest', + 'Dale City', + 'Ranbirsinghpura', + 'Ibiassuce', + 'Tetagunta', + 'Pereiro', + 'Marmagao', + 'Amparihy', + 'Ereymentau', + 'Heishuikeng', + 'As Salt', + 'Los Patios', + 'Masyaf', + 'Ban Sai Yoi', + 'Abre Campo', + 'El Maknassi', + 'Rosaryville', + 'Dupax Del Norte', + 'Kosai', + 'La Queue-en-Brie', + 'Rasulpur', + 'Chelm', + 'Caserta', + 'Devmaudaldal', + 'Biancavilla', + 'Nilaiyur', + 'Budhanilkantha', + 'Weyburn', + 'Schertz', + 'Bela Simri', + 'Kimje', + 'Jerome', + 'Rangapuram', + 'Sandalpur', + 'Nea Erythraia', + 'Entebbe', + 'San Bartolome', + 'Al Karnak', + 'Estepona', + 'Lempdes', + 'Zengjiaba', + 'Lipkovo', + 'Buckingham', + 'Bevoay', + 'Sokouhoue', + 'Tecklenburg', + 'Bochum', + 'San Luis Talpa', + 'Ijui', + 'Woodlyn', + 'Capivari', + 'Purna', + 'Bayugan', + 'Imbert', + 'Durgauti', + 'Belen de los Andaquies', + 'Menghan', + 'Gangapur Athar', + 'Inza', + 'Tiaong', + 'Cagliari', + 'Inverness', + 'Ciudad Sahagun', + 'Gerakas', + 'Vubatalai', + 'Ratauli', + 'Catalao', + 'Telsen', + 'Secovce', + 'Sirugamani', + 'Lake Norman of Catawba', + 'Vevey', + 'Quakers Hill', + 'Struga', + 'Amarwara', + 'Mont-Saint-Martin', + 'Nova Crnja', + 'Hirehalli', + 'Ablu', + 'Llavallol', + 'El Almendro', + 'Ad Darwa', + 'Bietigheim-Bissingen', + 'Ul', + 'Indianola', + 'Ankisabe', + 'Minster', + "Wik'ro", + 'Barapire', + 'A Yun Pa', + 'Retirolandia', + 'Shahkot', + 'Itaberaba', + 'Pilappulli', + 'Coesfeld', + 'Azare', + 'Dix Hills', + 'Nazira', + 'Velen', + 'Mnichovo Hradiste', + 'Cedar City', + 'Bofete', + 'Haiphong', + 'Tokmok', + 'Goianapolis', + 'Texas City', + 'Marakkara', + 'Cameli', + 'Lundazi', + 'Antanambaobe', + 'Akhmim', + 'Abhayapuri', + 'Saint-Philbert-de-Grand-Lieu', + 'Lutterworth', + 'Vinci', + 'Kidlington', + 'Sao Joao', + 'Leopold', + 'Vigevano', + 'Croix-des-Bouquets', + 'Zele', + 'Ibateguara', + 'West Lealman', + 'Taran', + 'Pingshang', + 'Douar Ait Sidi Daoud', + 'San Martin', + 'Bajram Curri', + 'Fouesnant', + 'Hosbach', + 'Jiamusi', + 'Mendi', + 'Gennevilliers', + 'Suramala', + 'Lambunao', + 'Guatuba', + 'Hassi Bahbah', + 'Mineral del Monte', + 'Menglie', + 'Chitarpur', + 'Cristopolis', + 'Ad Diwem', + 'Tocopilla', + 'Calella', + 'Bedwas', + 'Sarur', + 'Wuhai', + 'Flero', + 'Jork', + 'Juma Shahri', + 'Hawtat Sudayr', + 'Viyapuram', + 'La Nucia', + 'Chalhuanca', + '`Utaybah', + 'Ilkley', + 'Bloomfield', + 'Dobhawan', + 'Chempalli', + 'Tipo-Tipo', + 'Risch', + 'Marosangy', + 'Kirchheim bei Munchen', + 'Ubaira', + 'Maragondon', + 'Al `Aydabi', + 'Lamia', + 'Chippewa Falls', + 'Ora', + 'Androy', + 'Valle del Guamuez', + 'Sykies', + 'Barahari', + 'Peters', + 'Naxcivan', + 'Anderlues', + 'Doraville', + 'Banaue', + 'Eersel', + 'Ganapatipalaiyam', + 'Bernal', + 'Tole Bi', + 'Badiangan', + 'Newry', + 'Boom', + 'Baguineda', + 'Thulusdhoo', + 'Kanniyakumari', + 'Ramagiri Udayagiri', + 'Tangjiacun', + 'Naranattenvanpatti', + 'Megarine', + 'Angallu', + 'Yeni Suraxani', + 'Gudimulakhandrika', + 'Port-Alfred', + 'Bantval', + 'Banska Bystrica', + 'Ratanpur', + 'Sihui', + 'Ambohimangakely', + 'Mineshita', + 'San Rafael', + 'Bhambia Bhai', + 'Nauheim', + 'Russellville', + 'Naushahro Firoz', + 'Sarvestan', + 'Pagalungan', + 'Carsibasi', + 'Emirgazi', + 'Ciudad Rio Bravo', + 'Proddatur', + 'Bruz', + 'Bartlett', + 'Yeadon', + 'Timbedgha', + 'Rishton', + 'Thaba-Tseka', + 'Pappampatti', + 'Alianca', + 'Skowhegan', + 'Gongzhuling', + 'Port Arthur', + 'Budingen', + 'Vallam', + 'Agios Ioannis Rentis', + 'Birine', + 'Quirino', + 'Honeygo', + 'Usulutan', + 'Abram', + 'Taranto', + 'Tyrnavos', + 'Nagongera', + 'Farsan', + 'Santa Rita', + 'Bueno Brandao', + 'Amingarh', + 'Port Loko', + 'Hellevoetsluis', + 'Surigao', + 'Pattamadai', + 'Balsas', + 'Matipo', + 'Onitsha', + 'Strasshof an der Nordbahn', + 'Rochefort', + 'Doral', + 'Limoeiro', + 'Ambalanjanakomby', + 'Cohoes', + 'Jaguaruana', + 'Vadakethara', + 'Prospect Heights', + 'Bonita', + 'Jarvenpaa', + 'Baj Baj', + 'Alamadi', + 'Nanzhou', + 'Sanatoga', + 'Arruda dos Vinhos', + 'Malapatan', + 'Soroti', + 'Dargahan', + 'Meze', + 'Pemangkat', + 'Dinagat', + 'Villemomble', + 'Donetsk', + 'Viru', + 'Dazhangzicun', + 'Vigneux-sur-Seine', + 'Amolatar', + 'Nemili', + 'Nagykanizsa', + 'Kedgaon', + 'Boumia', + 'Guisa', + 'Maur', + 'Saint-Laurent-du-Maroni', + 'Chenggong', + 'Rengali', + 'Bacau', + 'Kaunra', + 'Ballyfermot', + 'Aurahi', + 'Perito Moreno', + 'Shetang', + 'Suwon', + 'Virappanchathiram', + 'Celje', + 'Turhal', + 'Taquari', + 'Ikot Ekpene', + 'Allinagaram', + 'Bolintin Vale', + 'Maga', + 'Kolnad', + 'Sori', + 'Totoro', + 'San Rafael Obrajuelo', + 'Alayaman', + 'Ouani', + 'Tadla', + 'Pirque', + 'Cuxhaven', + 'Zhongzai', + 'Aliwal North', + 'Plum', + 'Saint Helier', + 'Dongcha', + 'Gokarn', + 'Sassandra', + 'Balneario do Rincao', + 'Kafr Buhum', + 'Hlukhiv', + 'Sandacho', + 'Arizona City', + 'Silamalai', + 'Mohanpur', + 'Diaobingshancun', + 'Ratekau', + 'Halgar', + 'Albertville', + 'Gadani', + 'Ascheberg', + 'Godda', + 'Tangdong', + 'Sholinghur', + 'Zuidlaren', + 'Jadopur Shukul', + 'Ekalbehri', + 'Puerto Plata', + 'Ambatturai', + 'Masanwa', + 'Crystal', + 'Dasungezhuang', + 'Eenhana', + 'Xiangtan', + 'Arbon', + 'Jerez de la Frontera', + 'Barkagaon', + 'Sumter', + 'Maroochydore', + 'Rach Gia', + 'Mirna Pec', + 'St. John', + 'Medianeira', + 'Muqui', + 'Farah', + 'Dedougou', + 'Manduri', + 'Monserrat', + 'Myrnohrad', + 'Segbana', + 'Gelnhausen', + 'Chuanliaocun', + 'Reshetylivka', + 'College Station', + 'Wum', + 'Imst', + 'Kumar Khad', + 'Bjarred', + 'Ambatofisaka II', + 'Nocatee', + 'Kanel', + 'Philipstown', + 'Torrevieja', + 'Frankfort Square', + 'Gudur', + 'Oak Grove', + 'Santana', + 'Polukallu', + 'Kanhai', + 'Trapani', + 'Sanchez-Mira', + 'Wangtuan', + 'Punta del Este', + 'Zevenaar', + 'Ban Tha Pha', + 'Sainte-Marie', + 'Karonga', + 'Cremlingen', + 'Ramallah', + 'Gatumba', + 'Caowotan', + 'Tomah', + 'Lorraine', + 'Odumase', + 'Amritsar', + 'Vlasim', + 'Yangcunzai', + 'Prataparampuram', + 'Indurti', + 'Tanjay', + 'Brzeg', + 'Manthani', + 'Passa Quatro', + 'Dallas', + 'Chinnatadagam', + 'Roxborough Park', + 'Ban Wang Pradu', + 'Were Ilu', + 'Tourcoing', + 'Shimokizukuri', + 'Dehui', + 'Ithaca', + 'Hamtic', + 'Saint-Zotique', + 'Mossendjo', + 'Ban Bo Phlap', + 'Arar', + 'Meekatharra', + 'Ghouazi', + 'Amora', + 'Yongji', + 'Nurtingen', + 'Pantar', + 'Yantai', + 'Shamli', + 'Sidi Kasem', + 'League City', + 'Ylojarvi', + 'Chakpi Karong', + 'Lehman', + 'Gunzenhausen', + 'Pirpirituba', + 'Titz', + 'Vynnyky', + 'Nicolas Romero', + 'Tekit', + 'Prinzapolka', + 'Nueva Esparta', + 'Hedongcun', + 'Lobougoula', + 'Socuellamos', + 'East Hemet', + 'Sebiston', + 'Ban Laem', + 'Mukono', + 'Mineiros do Tiete', + 'Warrnambool', + 'Normandia', + 'Monte Alegre', + 'Volda', + 'Yasothon', + 'Kearny', + 'Kahan', + 'Mihqan', + 'Playa Vicente', + 'Shimoga', + 'Konseguela', + 'Outapi', + 'Layton', + 'Brock Hall', + 'Kilsyth', + 'Al Mukalla', + 'Dhamtari', + 'Alijo', + 'Alacuas', + 'Higashiizu', + 'Lopez', + 'Ta`izz', + 'Corato', + 'Chuhuiv', + 'Albacete', + 'Gundumal', + 'Sidi Embarek', + 'Calais', + 'Camapua', + 'Portogruaro', + 'Bad Langensalza', + 'Tecolotlan', + 'Roseburg', + 'Saint-Jerome', + 'Sandila', + 'Coldwater', + 'Zhongcun', + 'Westonaria', + 'Pattanam', + 'Guihulngan', + 'Phaphot', + 'Huili Chengguanzhen', + 'Mabinay', + 'Bothell East', + 'Banavar', + 'Nallippalaiyam', + 'Quetigny', + 'Tsuno', + 'Geiro', + 'Zarrin Shahr', + 'Balpyq Bi', + 'San Antonio Oeste', + 'Krasnohorivka', + 'Bled', + 'Ama', + 'Lototla', + 'Azzano', + 'Ivai', + 'Mitanty', + 'Calicut', + 'Chelghoum el Aid', + 'Kitee', + 'Koffiefontein', + 'Fair Oaks Ranch', + 'Sao Marcos', + 'Disuq', + 'Bouzeghaia', + 'Hudson', + 'Fortuna Foothills', + 'Raska', + 'Rafah', + 'Birsfelden', + 'Loon', + 'Ivrindi', + 'Pacho', + 'Sasaguri', + 'Oroville', + 'Odiongan', + 'Bagua Grande', + 'Dera Ghazi Khan', + 'Moorslede', + 'Pilkha', + 'Kalar', + 'Odawara', + 'Monte Belo', + 'Ludwigsfelde', + 'Lopary', + 'Boriguma', + 'Storrs', + 'Khrystynivka', + 'Villa Aldama', + 'Sirali', + 'Bulwell', + 'Vadacheri', + 'Aytre', + 'Kwidzyn', + 'Furukawa', + 'Sukand', + 'Esquimalt', + 'Caraubas', + 'Antsohimbondrona', + 'Waltham Abbey', + 'Sagua la Grande', + 'Taulaha', + 'Roslyn', + 'Hale Dyamavvanahalli', + 'Cortona', + 'Minnal', + 'Brunoy', + 'Kunisakimachi-tsurugawa', + 'Rincao', + 'Golden Glades', + 'Matsuda-soryo', + 'Pirauba', + 'Ghriss', + 'Mopipi', + 'Chateauroux', + 'Chortkiv', + 'Theniet el Had', + 'Balkh', + 'Casalecchio di Reno', + 'Guacimo', + 'Arona', + 'Novaci', + 'Diakon', + 'Taunusstein', + 'Sawangan', + 'Jigani', + 'Parabita', + 'Candaba', + 'Jardim Alegre', + 'Berovo', + 'Cascina', + 'Ambohijanaka', + 'Sao Tome', + 'Cleethorpes', + 'Kalmunai', + 'Vaslui', + 'Fort William', + 'Bolobo', + 'Sanlucar la Mayor', + 'El Hajeb', + 'Quesnel', + 'Leuwiliang', + 'Caraibas', + 'Sugaon', + 'Villers-Cotterets', + 'Santamesa', + 'Santa Teresinha', + 'Anosibe-Ifanja', + 'Agarpur', + 'Kutavettur', + 'Itapetinga', + 'Lubsko', + 'Banbalah', + 'Tala', + 'Arcachon', + 'Muturkha', + 'Miyazu', + 'Akcadag', + 'Castaic', + 'Xindian', + 'Los Hidalgos', + 'Kekava', + 'Jacala', + 'Lapseki', + 'Cartaxo', + 'Londerzeel', + 'Ermua', + 'Ipiranga', + 'Trat', + 'Guiglo', + "Sant'Antioco", + 'Linton Hall', + 'Huaiyin', + 'San Salvador de Jujuy', + 'Ksour Essaf', + 'El Quisco', + 'Central', + 'Muttupet', + 'Juan de Herrera', + 'Qaryat Suluq', + 'Kressbronn am Bodensee', + 'Kall', + 'Thingangyun', + 'Lauf', + 'Villa de Alvarez', + 'Sipacate', + 'Andirin', + "Cournon-d'Auvergne", + 'Bhayandar', + 'Borongan', + 'Meerane', + 'Pekanbaru', + 'Szczytno', + 'Obu', + 'Chinnalapatti', + 'Angalakurichchi', + 'Caldas de Montbuy', + 'Altata', + 'Sonepur', + 'Benisa', + 'San Lucas Toliman', + 'Japeri', + 'Ecublens', + 'Kowloon', + 'Ivancna Gorica', + 'Bougzoul', + 'Jelcz-Laskowice', + 'Engenheiro Beltrao', + 'Stonecrest', + 'Cheltenham', + 'Ospino', + 'Qingdao', + 'Port Lavaca', + 'Weichanglu', + 'Gudiyattam', + 'Fujikawa', + 'Bamhni', + 'Porterville', + 'El Khemis des Beni Chegdal', + 'Surany', + 'Knurow', + 'Znamianka', + 'Huntersville', + 'El Eulma', + 'Bungoma', + 'Al Kharjah', + 'Rivesaltes', + 'Denzlingen', + 'Pul-e Khumri', + 'Niedernhausen', + 'Nova Floresta', + 'Cazin', + 'Virginia Beach', + 'Cassino', + 'Finnentrop', + 'Khajuri', + 'Cotabato', + 'Mahamaibe', + 'Aksu', + 'Campbellton', + 'Panay', + 'Otofuke', + 'Sarria', + 'Oklahoma City', + 'Waggaman', + 'Powdersville', + 'Ambongamarina', + 'Mirpur Khas', + 'Jamhor', + 'Florham Park', + 'Seram', + 'Senda', + 'Mancha Real', + 'Mint Hill', + 'Eggenstein-Leopoldshafen', + 'Bachhraon', + 'Friern Barnet', + 'Toboso', + 'Caledonia', + 'Dawley', + 'Bataredh', + 'Podenzano', + 'Hemiksem', + 'Pielisjarvi', + 'Pursa', + 'Marsabit', + 'Malar', + 'Tabubil', + 'White Meadow Lake', + 'Winter Garden', + 'Ryuo', + 'Jequie', + 'Ravar', + 'Gudalur', + 'Yenisehir', + 'Brookings', + 'Hamtramck', + 'Orizona', + 'Saint-Ouen', + 'Wietze', + 'Hwange', + 'Barentu', + 'Yedappalli', + 'Caucagua', + 'Gudensberg', + 'New Hope', + 'Benaguacil', + 'Aymangala', + 'Waltham', + 'Horndean', + 'Torquay', + 'Amulung', + 'Woolwich', + 'Sentjur', + 'Gondauli', + 'Krosno', + 'Nagasaki', + 'Luebo', + 'Sogutlu', + 'Valle de Santiago', + 'Ranzan', + 'Chachoengsao', + 'Golpayegan', + 'Mocuba', + 'Warrington', + 'Yercaud', + 'Capinzal', + 'Paullo', + 'Ozark', + 'Kargahia Purab', + 'Villanueva', + 'Jbabra', + 'Chunar', + 'Likiskiai', + 'Al Husayniyah', + 'Rockcreek', + 'Chichicastenango', + 'Siasi', + 'Beni Zouli', + 'Saint-Hilaire-de-Riez', + 'Devgeri', + 'Arniya', + 'Dennis', + 'Bopa', + 'East Norriton', + 'Marancheri', + 'Kalghatgi', + 'Andkhoy', + 'Dinanagar', + 'Kaifeng Chengguanzhen', + 'Jieshangya', + 'Yima', + 'Gamu', + 'Safashahr', + 'Pervari', + 'Agoue', + 'Presidente Franco', + 'Bad Homburg', + 'Taveta', + 'Croxley Green', + 'Bani', + 'Liberal', + 'Santa Maria de Ipire', + 'Hranice', + 'Mery-sur-Oise', + 'Ipupiara', + 'Takanabe', + "G'allaorol Shahri", + 'Syke', + 'Sembabule', + 'Kenley', + 'Bishnah', + 'Santa Lucia Milpas Altas', + 'Ahfir', + 'Virudunagar', + 'Cuapiaxtla de Madero', + 'Erquelinnes', + 'Galanta', + 'Islington', + 'Alaca', + 'Ganca', + 'Colcapirhua', + 'Katano', + 'White Oak', + 'Burgos', + 'Macalelon', + 'Bullhead City', + 'Obukhivka', + 'Krupka', + 'Rovaniemi', + 'Vrapciste', + 'Puerto Padre', + 'Cristalina', + 'Drug', + 'Bocono', + 'Abaji', + 'Annoeullin', + 'Savja', + 'El Coco', + 'Vauvert', + 'Rumbek', + 'Tettnang', + 'Tatsuno', + 'Olton', + 'Kabinda', + 'Miami Shores', + 'Chinnasekkadu', + 'Cotia', + 'Sapiranga', + 'Bad Rappenau', + 'Sharunah', + 'Cormeilles-en-Parisis', + 'Dossenheim', + 'Ozarow Mazowiecki', + 'Pichucalco', + 'Dowlaiswaram', + 'Palm Harbor', + 'Longba', + 'Chinique', + 'Roscoe', + 'Douar Oulad Bouziane', + 'Dayr az Zawr', + 'French Valley', + 'Kalasa', + 'Cave Spring', + 'Yakage', + 'Phagu', + 'Taishituncun', + 'Sumisip', + 'Littleport', + 'Kulachi', + 'Saravena', + 'Aguai', + 'Nederweert', + 'Haskoy', + 'Saguday', + 'Shushtar', + 'Cuilapa', + 'Formigine', + 'Kalateh-ye Mir Ab', + 'Farsund', + 'Ripon', + 'Munich', + 'Himora', + 'Banamba', + 'Mkokotoni', + 'Anori', + 'Hartsville', + 'Thikri', + 'Xiantao', + 'Libmanan', + 'Shahritus', + 'Hayle', + 'Arakkal', + 'Hoa Thanh', + 'Chetumal', + 'Cormano', + 'Witham', + 'Cleveland Heights', + 'Ludus', + 'Tolanaro', + 'Saint-Doulchard', + 'Pradopolis', + 'Lourdes', + 'Siswar', + 'Alabaster', + 'Kasibu', + 'Saint-Leu-la-Foret', + 'Sakaddi', + 'Entre Ijuis', + 'Bilina', + 'Boyovut', + 'Ambohinihaonana', + 'Patrasaer', + 'North Augusta', + 'Ciudad Nezahualcoyotl', + 'Jenks', + 'Shiyuan', + 'San Carlos Yautepec', + 'Kabarore', + 'Durban', + 'Dajabon', + 'Leognan', + "Chech'on", + 'Guelma', + 'Rossmoor', + 'Cano Martin Pena', + 'Standerton', + 'Kaimuh', + 'Bellflower', + 'Sibutu', + 'Guateque', + 'Vejer de la Frontera', + 'Gornalwood', + 'Serhetabat', + 'Kondayampalaiyam', + 'Andal', + 'Kingersheim', + 'Ait Ben Daoudi', + 'Ixhuatlancillo', + 'Song Doc', + 'Schoten', + 'Gan Yavne', + 'Koprivnice', + 'Wadi', + 'Belvidere', + 'Haibach', + 'Chishtian', + 'Ras El Oued', + 'New Haven', + 'Alamuru', + 'Qaminis', + 'Saint-Eustache', + 'Port Wentworth', + 'Hashimoto', + 'Thara', + 'Qingzhen', + 'Sancti Spiritus', + 'Andiyappanur', + 'Pozi', + 'Songnam', + 'Alken', + 'Horsens', + 'Al Hashimiyah', + 'Vanadzor', + 'Fatehpur', + 'Necochea', + 'Sagbayan', + 'La Virgen', + 'Villagran', + 'Elyria', + 'Perunkolattur', + 'Talavadi', + 'Melrose', + 'Penaranda', + 'Aroeiras', + 'Caucasia', + 'Maryland Heights', + 'Ambatomifanongoa', + 'Fairfield', + 'Liuquancun', + 'Siqueira Campos', + 'Villa Carlos Paz', + 'Blitta', + 'Ciudad de Melilla', + 'Arajpur', + 'Pantano Grande', + 'Central Signal Village', + 'Tirumuruganpundi', + 'Vilakkudi', + 'Kavadarci', + 'La Plata', + 'Short Pump', + 'Shivganj', + 'Fangasso', + 'Douar Ain Maatouf', + 'Harlau', + 'Egypt Lake-Leto', + 'Greiz', + 'Al Khums', + 'Inabanga', + 'Ylivieska', + 'Halmstad', + 'West St. Paul', + 'Boudouaou', + 'Banaybanay', + 'Pinheiro Machado', + 'Bongao', + 'Parras de la Fuente', + 'Tabhka Khas', + 'Basingstoke', + 'Ovejas', + 'Bandwar', + 'Abu Ghurayb', + 'Bekescsaba', + 'Arutla', + 'Kadwa', + 'Kyaukse', + 'North Bethesda', + 'Jilotepec', + 'Kafr `Awan', + 'Takua Pa', + 'Aberystwyth', + 'Bataipora', + 'Timmarasanayakkanur', + 'Aradippou', + 'Khampat', + 'Caln', + 'Ambodimadiro', + 'Paso de Ovejas', + 'Manavalakurichi', + 'Chajari', + 'Jacarei', + 'Bals', + 'Bishkek', + 'Ikela', + 'Saladoblanco', + 'Sirsilla', + 'Dara', + 'Wuchang', + 'Haiyang', + 'Arida', + 'Kalaiyamputtur', + "'Tlat Bni Oukil", + 'Dixon', + 'Mogi das Cruzes', + 'Tizi Ouzou', + 'Hopkinton', + 'Buchanan', + 'Amami', + 'Juiz de Fora', + 'Kargipinar', + 'Saint-Orens-de-Gameville', + 'Charlton', + 'Dortyol', + 'Parepare', + 'Cadaado', + 'Boryspil', + 'Marina del Rey', + 'Uchen', + 'Betulia', + 'Kerema', + 'Chartoun', + 'Shajapur', + 'Brooks', + 'Nova Odesa', + 'Sogne', + 'Sarahandrano', + 'Nea Ionia', + 'Sumidouro', + 'Yayladagi', + 'Cesky Krumlov', + 'Tay Ninh', + 'Ottweiler', + 'Pedro Brand', + 'Neka', + 'Masse', + 'Darcheh', + 'Adelphi', + 'Melur', + 'Bergneustadt', + 'Salempur', + 'Avanigadda', + 'Guruvarajukuppam', + 'Chandwa', + 'Saclepea', + 'Kathanian', + 'Kari', + 'San Jacinto', + 'Southall', + 'Jinja', + 'Sungaiselam', + 'Sirmaur', + 'Friedland', + 'Alpine', + 'Kerben', + 'Lubaczow', + 'Ambodimangavolo', + 'Chuxiong', + 'Ciudad Mante', + 'Chorkuh', + 'Indalvai', + 'Fengruncun', + 'Azpeitia', + 'Sallisaw', + 'Karanganyar', + 'Tokmak', + 'Baripada', + 'St. Marys', + 'Platon Sanchez', + 'Bugembe', + 'Nihtaur', + 'Kharsod B', + 'Shahriar', + 'Jabbeke', + 'Mogtedo', + 'Mayorga', + 'Rastatt', + 'Prairie Village', + 'Hato Corozal', + 'Dubuque', + 'Rocha', + 'Pataskala', + 'Blue Ash', + 'Sarandi', + 'Nkayi', + 'Coldstream', + 'Guru Har Sahai', + 'Gardanne', + 'Waukesha', + 'Saran', + 'Alfred and Plantagenet', + 'Tiadiaye', + 'Huchuan', + 'Lujan de Cuyo', + 'Fundao', + 'Ben Tre', + 'Balingasag', + 'Safipur', + 'Mitoyo', + 'At Taji', + 'Doany', + 'Fuyuan', + 'Hayesville', + 'Schwerin', + 'Phelan', + 'Bethanie', + 'Weymouth', + 'Kibanseke Premiere', + 'Buey Arriba', + 'Ibotirama', + 'Yamaguchi', + 'Vadasseri', + 'Wantage', + 'Iaboutene', + 'Karlivka', + 'Manabo', + 'San Kamphaeng', + 'El Hermel', + 'Corrente', + 'Voisins-le-Bretonneux', + 'Vemuluru', + 'Jasauli Patti', + 'Paraguacu Paulista', + 'Umreth', + 'Rakovski', + 'Kottagudi Muttanad', + 'Sao Felix do Araguaia', + 'Huong Tra', + 'Yukon', + 'Miena', + 'Datang', + 'Petrich', + 'Tholen', + 'Mosopa', + 'Fara in Sabina', + 'Alesund', + 'Penwortham', + 'Poyo', + 'Ruma', + 'Scorze', + 'Cedral', + 'Forest Grove', + 'Szeged', + 'Firavahana', + 'Bagno a Ripoli', + 'Caravelas', + 'Horn-Bad Meinberg', + 'Porto Alegre do Norte', + 'Shtime', + 'Raba', + 'Chisec', + 'Lagunia Raghukanth', + 'Ensenada Berisso', + 'Do`stobod', + 'Amarpur', + 'Lunca Cetatuii', + 'Dagupan City', + 'Saumlaki', + 'Karkamb', + 'Sobrado de Paiva', + 'Kalappalangulam', + 'Joao Lisboa', + 'The Dalles', + 'Slateng Dua', + 'Lingwala', + 'Latiano', + 'Orangeville', + 'Borazjan', + 'Pizarro', + 'Pilich', + 'Veintiocho de Noviembre', + 'Huntington Park', + 'Jesus Menendez', + "'Ain Abessa", + 'Descalvado', + 'Krapina', + 'Harwood Heights', + 'Banco Filipino International Village', + 'Guadarrama', + 'Channagiri', + 'Mokri', + 'Sanjiang', + 'Kokri', + 'Tirkha', + 'Zhangjiakou', + 'Veresegyhaz', + 'Zhuanghe', + 'Balkonda', + 'Siemiatycze', + 'Ban Saeo', + 'Torrijos', + 'Faches-Thumesnil', + 'Campo Alegre de Lourdes', + 'Francofonte', + 'Alarobia', + 'Worthing', + 'Rochelle', + 'Ilvesheim', + 'Billings', + 'Batangas', + 'Vochaiko', + 'Zaragoza', + 'Heppenheim', + 'La Mana', + 'Son Tay', + 'Magilampupuram', + 'Logrono', + 'Chiavari', + 'Gujan-Mestras', + 'Katako-Kombe', + 'Chaparral', + 'Batie', + 'Foligno', + 'University', + 'Iruttarakonam', + 'Kotla', + 'East Hanover', + 'Jomboy Shahri', + 'Changanacheri', + 'Kensington', + 'Dobje', + 'Maisons-Laffitte', + 'Oroquieta', + 'Parambatt Kavu', + 'Dois Riachos', + 'Latina', + 'Babhanganwa', + 'Ambohimahasoa', + 'Pandino', + 'Chefchaouene', + 'Teixeiras', + 'Saveh', + 'Glens Falls', + 'Tonj', + 'Bhulwal', + 'Luozi', + 'Adoni', + 'Mahazony', + 'Setagaya', + 'Banning', + 'Minamishimabara', + 'Tuz Khurmatu', + 'Sundarapandiyam', + 'Kodaira', + 'Santa Cruz de la Palma', + 'Candiota', + 'Pittsford', + 'Yakeshi', + 'Lengerich', + "Da'an", + 'Pacaembu', + 'East Point', + 'Miacatlan', + 'Sendamangalam', + 'Sidi Khaled', + 'Landquart', + 'Reinbek', + 'Millau', + 'Itaosy', + 'Bellefontaine', + 'Aracoiaba', + 'Melipilla', + 'Monor', + 'Collinsville', + 'Lenggries', + 'Pio Duran', + 'Rhondda', + 'Abu Sir Bana', + 'Cholavaram', + 'Kamepalle', + 'Yeppoon', + 'Sangenjo', + 'Hradec Kralove', + 'Kibeho', + 'Ahmetli', + 'Yurihonjo', + 'Pontassieve', + 'Cahokia Heights', + 'Ubaidullahganj', + 'Brakel', + 'Berezan', + 'Noya', + 'Reggio Emilia', + 'Huesca', + 'Bopfingen', + 'Bhainsa', + 'Dhupgari', + 'Itaiba', + 'Camenca', + 'Chmistar', + 'Sao Luis do Quitunde', + 'Foix', + 'Kond Rud', + 'Laterza', + 'Schopfheim', + 'Kasuga', + 'Ouadhia', + 'Dala', + 'Sonagazi', + 'Songjiangcun', + 'Mamidalapadu', + 'Biarritz', + 'Theodore', + 'Ngudu', + 'Ntorosso', + 'Buxar', + 'Kaliyaganj', + 'Milanoa', + 'Spisska Nova Ves', + 'Fuli', + 'Kisi', + 'Jhargram', + 'Zaporizhzhia', + 'Gazipasa', + 'Suyo', + 'North Saanich', + 'San Ricardo', + 'Komatipoort', + 'Mallapuram', + 'Yitiaoshan', + 'Kargilik', + 'Kinoni', + 'Qazyqurt', + 'Cajazeiras', + 'Semnan', + 'Pandan', + 'Koceljeva', + 'Ambodimotso Atsimo', + 'Valenza', + 'Puerto de la Cruz', + 'Tepetlaoxtoc', + 'Adjala-Tosorontio', + 'Zillah', + 'Diamondhead', + 'Hallstadt', + 'Anseong', + 'Libacao', + 'Bharella', + 'Yilan', + 'Cadolzburg', + 'Papantla de Olarte', + 'Fengguangcun', + 'Jhelum', + 'Dalanping', + 'Tegucigalpa', + 'Batala', + 'El Kerma', + 'Yangzhou', + 'Passira', + 'Hagonoy', + 'Kambaduru', + 'Jambusar', + 'Teddington', + 'Murambi', + 'Corsham', + 'Arzew', + 'Nittedal', + 'Paingkyon', + 'Maravilha', + 'Edison', + 'Montlhery', + 'Mokameh', + 'Canegrate', + 'Tezoatlan de Segura y Luna', + 'Iraucuba', + 'Kattivakkam', + 'Lino Lakes', + 'Kalyani', + 'El Playon', + 'Kabbur', + 'San Miguel Xoxtla', + 'Zirndorf', + 'Guama Abajo', + 'Sevlievo', + 'Kawai', + 'Edingen-Neckarhausen', + 'Chimalapadu', + 'Huatan', + 'Cascavel', + 'Naravarikuppam', + 'Pasighat', + 'Chimthana', + 'Priolo Gargallo', + 'Diema', + 'Yingshouyingzi', + 'Hardoi', + 'Shpola', + 'Alipur Duar', + 'Parambu', + 'Igaratinga', + 'Xinxing', + 'Damboa', + 'Edgemere', + 'Cypress Lake', + 'Lemont', + 'Karedu', + 'Puerto Villamil', + 'Thornaby on Tees', + 'Basarabeasca', + 'Bolama', + 'Islip', + 'Sonkach', + 'Cinco Ranch', + 'Tibiao', + 'Kuala Belait', + 'Nahazari', + 'Culion', + 'Villa Alegre', + 'Santiago Amoltepec', + 'Edgewater', + 'Sinuni', + 'Posusje', + 'Castellbisbal', + 'Bhainsoda', + 'Jindrichuv Hradec', + 'Pattiyurgramam', + 'Manlin', + 'Kabayan', + 'Boulder Hill', + 'Pastpar', + 'Mablethorpe', + 'Kodumur', + 'Kegen', + 'Wugang', + 'Cerquilho Velho', + 'Bent Jbail', + 'Bornova', + 'Hoganas', + 'Queretaro', + 'Ar Rayyan', + 'Bondues', + 'Pierrelaye', + 'Baiyin', + 'La Sierpe', + 'Selendi', + 'Antony', + 'Mathukumnel', + 'Kingoonya', + 'Nueva Gerona', + 'Alitagtag', + 'Simojovel de Allende', + 'Kralendijk', + 'Kanal', + 'Umm al Qaywayn', + 'Dodola', + 'Risaralda', + 'Lugoff', + 'Steinheim am Albuch', + 'Sussen', + 'Mulavana', + 'Loanda', + 'Holiday', + 'Catriel', + 'Rotonda', + 'North Codorus', + 'Amanganj', + 'Sahakevo', + 'Cadca', + "Ch'onan", + 'Ponte San Giovanni', + 'Villa Altagracia', + 'Maywood', + 'Saraburi', + 'Tyldesley', + 'Satuluru', + 'Neufahrn bei Freising', + 'Zigon', + 'Calne', + 'Serere', + 'Cumberland Hill', + 'Ivanjica', + 'Konz', + 'Perth Amboy', + 'Alerce', + 'Berikai', + 'Foum Zguid', + 'Had Dra', + 'Cinere', + 'Dalkeith', + 'Fresnillo', + 'Yaizu', + 'Ciro Redondo', + 'Despotovac', + 'Kakkat', + 'Bassum', + 'Najran', + 'Segrate', + 'Mexico', + 'Kinrooi', + 'Moknine', + 'Andreba', + 'Bresso', + 'Venadillo', + 'Reoti', + 'Baharly', + 'Los Palmitos', + 'Jordania', + 'Great Missenden', + 'Puerto Cortes', + 'Los Alcazares', + 'Agbangnizoun', + 'Chausa', + 'Capistrano', + 'West Richland', + 'Pingyuanjie', + 'Coomera', + 'Bteghrine', + 'Occhiobello', + 'Olagadam', + 'Deerfield', + 'Aroroy', + 'Macedon', + 'Spout Springs', + 'East Patchogue', + 'Ebina', + 'Soria', + 'Ouled Mimoun', + 'Navapur', + 'Balumath', + 'Hennenman', + 'Barkot', + 'Denduluru', + 'Raca', + 'Kumbhari', + 'Bayaram', + 'Liuzhou', + 'Belmonte Mezzagno', + 'Harvard', + 'Wandiwash', + 'Cukurcayir', + 'Dinkelsbuhl', + 'Chero', + 'Ngolobougou', + 'Quilevo', + 'Saint-Claude', + 'Sonari', + 'Zaventem', + 'Venecia', + 'Sharjah', + 'Shoreham-by-Sea', + 'Governador Archer', + 'Cerese', + 'Lazarivo', + 'Angara-Debou', + 'Kaele', + 'Mahe', + 'Leighton Buzzard', + 'Erfelek', + 'Willimantic', + 'Sao Joaquim da Barra', + 'Littau', + 'Kayanna', + 'Temperley', + 'Jirwa', + 'Moses Lake', + 'Merriam', + 'Cerreto Guidi', + 'San Miniato', + 'Tumby Bay', + 'Wielun', + 'Tirukkattuppalli', + 'North Las Vegas', + 'Mahemdavad', + 'Nagaiyampatti', + 'Atyrau', + 'Chorley', + 'Ravansar', + 'Bettioua', + 'Green River', + 'Chicacao', + 'Karukkalvadi', + 'Dar el Beida', + 'Langarivo', + 'Tettu', + 'Santa Barbara', + 'Ban Pong', + 'San Nicolas de los Garza', + 'Tres Coroas', + 'Muttattuteruvu', + 'Coracao de Maria', + 'Nieuwpoort', + 'Laatzen', + 'Kusumbe', + 'Xiangyuncun', + 'Coral Springs', + 'Escaldes-Engordany', + 'Durpalli', + 'Kundian', + 'Acatlan de Perez Figueroa', + 'Mendes', + 'Sansale', + 'Batan', + 'Paslek', + 'San Severino Marche', + 'Madinat `Isa', + 'Youwarou', + 'Paghman', + 'Aruvikkara', + 'Osthofen', + 'Tianzhong', + 'Marudur', + 'Crensovci', + 'Ceerigaabo', + 'Brusciano', + 'Sabana de La Mar', + 'Aileu', + 'Kutaisi', + 'Maebashi', + 'Wanggezhuang', + 'Banska Stiavnica', + 'Tola', + 'Hovelhof', + 'Johannesburg', + "Sant Sadurni d'Anoia", + 'Binalonan', + 'Dingcheng', + 'Henderson', + 'Bloxwich', + 'Gberouboue', + 'Dharmaram', + 'Abomsa', + 'Imtarfa', + 'Rancho Santa Margarita', + 'Meuselwitz', + 'Ad Dali`', + 'Nilandhoo', + 'Bayramaly', + 'Lufkin', + 'Talcher', + 'Menaka', + 'Rupauli', + 'Ipanema', + 'Tindwara', + 'Piendamo', + 'Gennep', + 'Kachnar', + 'Vitez', + 'Oporapa', + 'Litvinov', + 'Lich', + 'Hericourt', + 'Sanghar', + 'Sao Lourenco', + 'Bir Ali Ben Khalifa', + 'Hlucin', + 'Erith', + 'Ebejico', + 'Qulsary', + 'Pichor', + 'Lubon', + 'Lufilufi', + 'Mayamankurichchi', + 'Kulittalai', + 'Marshall', + 'Weil der Stadt', + 'Mahabako', + 'Lemoore', + "Al M'aziz", + 'Behat', + 'Mauriti', + 'Memphis', + 'Antas', + 'Novo Mesto', + 'Zinkiv', + 'Mi`rabah', + 'Ksar Sghir', + 'Mandapam', + 'Cupang', + 'Mina', + 'Bytom', + 'Kikuyo', + 'Yankton', + 'Spilimbergo', + 'Gottmadingen', + 'Vanersborg', + 'Harduli', + 'Wierden', + 'Paloncha', + 'Chikmagalur', + 'Qubadli', + 'Longwood', + 'Nay Pyi Taw', + 'Wald-Michelbach', + 'Kafr al Battikh', + 'Orai', + 'Juchique de Ferrer', + 'Swiebodzice', + 'Behbahan', + 'Sehore', + 'Te Awamutu', + 'Shacheng', + 'Kano', + 'Ciftlikkoy', + 'Op', + 'Yendi', + 'Sun Valley', + 'Guabari', + 'Kalyanpur Bamaiya', + 'Rauco', + 'Pedro de Toledo', + 'Kandhkot', + 'Degollado', + 'Kasai', + 'Krasnik', + 'Abu Khashab', + 'Middlesbrough', + 'Cifuentes', + 'Ganxi', + 'Mae Sot', + 'Raubling', + 'Myoko', + 'McLean', + 'Trail', + 'Reggada', + 'Migdal Ha`Emeq', + 'Banni', + 'La Grange Park', + 'Ojiya', + 'Youngstown', + 'East Longmeadow', + 'Perunkalattu', + 'Guimaraes', + 'Sete Lagoas', + 'Bhandaria', + 'Stretford', + 'Corrientes', + 'Hurst', + 'Satuek', + 'Suhum', + 'Majiagoucha', + 'Caltagirone', + 'Asthal Bohar', + 'Chipiona', + 'Aravan', + 'Kiboga', + 'Ephrata', + 'Lystrup', + 'Nowa Deba', + 'Vangaindrano', + 'New Westminster', + 'Cestas', + 'Bithan', + 'Saraiya', + 'Bad Soden am Taunus', + 'Cinnaminson', + 'Mansidao', + 'Heroldsberg', + 'Opovo', + 'Shinhidaka', + 'Mildura', + 'Sahatsiho-Ambohimanjaka', + 'Dok Kham Tai', + 'Szombathely', + 'Nova Olinda do Norte', + 'Brantford', + 'Cobram', + 'Sulzbach-Rosenberg', + 'Key Biscayne', + 'South Ubian', + 'Varde', + 'Scandiano', + 'Santa Cruz do Sul', + 'Cedar Park', + 'Erstein', + 'Matozinhos', + 'Buxin', + 'Chortiatis', + 'Camrose', + 'Ettimadai', + 'Montagnana', + 'Ivybridge', + 'Middlewich', + 'Tivat', + 'Babai Kalan', + 'Al Qusayr', + 'Vatolatsaka', + 'Cruz', + 'Linstead', + 'Lakkundi', + 'Serrolandia', + 'Shuibian', + 'Llanelli', + 'Six-Fours-les-Plages', + 'Entre Rios de Minas', + 'Saude', + "Karbala'", + 'Godinlabe', + 'Ocatlan', + 'Paranatama', + 'Begampur', + 'Khulm', + 'Alegria', + 'Partanna', + 'Bothaville', + 'Vaal Reefs', + "Alvorada D'Oeste", + 'Cotes de Fer', + 'Sibirila', + 'Heshancun', + 'Adustina', + 'Uberlingen', + 'Shawano', + 'Santa Fe', + 'Bolivia', + 'Maniche', + 'Chikura', + 'Amstelveen', + 'Mwinilunga', + 'Tetiiv', + 'Losal', + 'Ortakent', + 'Mirassol', + 'Yerba Buena', + 'Kasongo-Lunda', + 'Zongdi', + 'Pirmed', + 'Ashton', + 'La Union', + 'Anaco', + 'Front Royal', + 'Faro', + 'Votorantim', + 'Bengbu', + 'Aldaya', + 'Khem Karan', + 'Dushanbe', + 'Campulung Moldovenesc', + 'Quixeramobim', + 'Chabet el Ameur', + 'Pingtung', + 'Fukuoka', + 'Itapiuna', + 'Khiram', + 'Lami', + 'Morubagalu', + 'South Kingstown', + 'Chatham', + 'Cefalu', + 'Pattanakkad', + 'Silvan', + 'Souk Et-Tleta des Oulad Hamdane', + "Mai'Adua", + 'Ban Bang Khu Wat', + 'Ardal', + 'Collegedale', + 'Irbid', + 'Lanham', + 'San Pablo Jocopilas', + 'Santuario', + 'Betma', + 'Inezgane', + 'Pout', + 'Batcha', + 'Irlam', + 'Aldoar', + 'Atakpame', + 'Ban Bo Luang', + 'Finchley', + 'Tamalous', + 'Bagnols-sur-Ceze', + 'Matsushima', + 'Yecuatla', + 'Wuxue', + 'Ocean Springs', + 'Petilia Policastro', + 'Benenitra', + 'Elgin', + 'Guntupalle', + 'Itirucu', + 'Chengde', + 'Castelvetro di Modena', + 'Ramkali', + 'Marki', + 'Loudima Poste', + 'Usta Muhammad', + 'Banfield', + 'Patna', + 'Lendinara', + 'Toliara', + 'Tioribougou', + 'Mosbrough', + 'Yenangyaung', + 'Analanampotsy', + 'Zgornje Gorje', + 'Al Qubbah', + 'Lakeshore', + 'Kocaali', + 'Sombor', + 'Punta Arenas', + 'Elmira', + 'Serekunda', + 'Ban Khlong', + 'Ried im Innkreis', + 'Olivehurst', + 'Naruto', + 'Plainville', + 'Nakhal', + 'Hampton Bays', + 'Yaita', + 'Ambatosia', + 'Guindulman', + 'Wommelgem', + 'Jasper', + 'Sao Joao da Madeira', + 'Curiuva', + 'Destin', + 'Zigong', + 'Kushijima', + 'Fameck', + 'Telmar', + 'Noboribetsu', + 'Guanare', + 'Adis `Alem', + 'Angatuba', + 'Santa Cruz Zenzontepec', + 'Dongguazhen', + 'Castle Rock', + 'Millbrook', + 'Erlenbach am Main', + 'Kamloops', + 'South Jordan', + 'Colombia', + 'Baguio City', + 'Turkaguda', + 'Momchilgrad', + 'Aiyappan Kovil', + 'Strada', + 'Rostock', + 'Lichtenfels', + 'Al Majaridah', + 'Bagh-e Bahadoran', + 'Irvington', + 'Maheshwar', + 'Jhagarua', + 'Birchington', + 'Iba', + 'Wang Nam Yen', + 'Heilbad Heiligenstadt', + 'Meinerzhagen', + 'Shandiz', + 'Fallston', + 'Landivisiau', + 'San Juan de Aznalfarache', + 'Ettaiyapuram', + 'Kota Kinabalu', + 'Roseira', + 'Fusagasuga', + 'Bovisio Masciago', + 'Vilpatti', + 'Old Forge', + 'Kadiyam', + 'Goraya', + 'Almelo', + 'Rescaldina', + 'Bad Munstereifel', + 'Atebubu', + 'Panapakkam', + 'Morag', + 'Ferrier', + 'Velaux', + 'Sellersburg', + 'Kambhampadu', + 'Ubbergen', + 'Quilandi', + 'Digos', + 'Slavutych', + 'Terre Haute', + 'Schlitz', + '`Unayzah', + 'Zaoyang', + 'Beauvais', + 'Allacapan', + 'Shangjing', + 'Nayagarh', + 'Kanasin', + 'Velasco Ibarra', + 'Agan', + 'Nouna', + 'Puthiyangadi', + 'Salar', + 'Povoa de Lanhoso', + 'Brotas de Macaubas', + 'Donggang', + 'Inuyama', + 'Balakan', + 'Camara de Lobos', + 'Tanauan', + 'Ribas do Rio Pardo', + 'Fagundes', + 'San Rafael Petzal', + 'Iraci', + 'Kadena', + 'Ramos Mejia', + 'Vaasa', + 'Goribidnur', + 'Changping', + 'Oregon', + 'Schiller Park', + 'Mereeg', + 'Toro', + 'Lynnwood', + 'Iiyama', + 'Punta Alta', + 'Cervello', + 'Sariosiyo', + 'Kunitachi', + 'Thu Dau Mot', + 'Viljandi', + 'Kurichedu', + 'Saugerties', + 'Noveleta', + 'Paripiranga', + 'Odesa', + 'Ibirama', + 'Coamo', + 'Smolyan', + 'Montilla', + 'Khan Bebin', + 'Ambovonomby', + 'Serinyol', + 'Ayapel', + 'San Antonio de los Cobres', + 'Kadiri', + 'Quatre Bornes', + 'Bareh', + 'Buritis', + 'Los Cerrillos', + 'Potenza', + 'Sughrain', + 'Nehbandan', + 'Ampthill', + 'Palmeira das Missoes', + 'Dombovar', + 'Angadanan', + 'Yuanping', + 'Martapura', + 'Curumani', + 'Benhao', + 'Ban Bang Toei', + 'Stadskanaal', + 'Secanj', + 'Renaico', + 'Buckhall', + 'Tirutturaippundi', + 'Komotini', + 'Suroth', + 'Guene', + 'Canudos', + 'Bhagsar', + 'Lubben (Spreewald)', + 'La Ciotat', + 'Stirling', + 'Praia da Vitoria', + 'Pakra', + 'Harpanahalli', + 'Tururu', + 'Andranomanelatra', + 'Sirnia', + 'Steyr', + 'Lake Stickney', + 'Villa Ojo de Agua', + 'Tuyserkan', + 'Saint-Jean-de-la-Ruelle', + 'Ranapur', + 'Kheiredine', + 'Villa El Carmen', + 'Sherborne', + 'Kerai', + 'Barughutu', + 'Tienen', + 'Cherkasy', + 'Turmero', + 'Ahigbe Koffikro', + 'Rio Azul', + 'Baro', + 'Koshanam', + 'Malinalco', + 'Afula', + 'Perpignan', + 'Timayy al Imdid', + 'Kotgir', + 'Forbach', + 'Malka', + 'Palm Beach', + 'Falmouth', + 'Beihai', + 'Kalbarri', + 'Ivato', + 'Picos', + 'Marcon', + 'Pieksamaki', + 'Carlet', + 'Salobe', + 'Yacimiento Rio Turbio', + 'Omiyacho', + 'Kodikkulam', + 'Shorapur', + 'Dniprorudne', + 'Neutraubling', + 'Kizhakkemanad', + 'Banagi', + 'Mount Gambier', + 'Malkajgiri', + 'Sokhumi', + 'Douera', + 'Chekfa', + 'Mairi', + 'Ortaca', + 'Loria', + 'San al Hajar al Qibliyah', + 'Galeana', + 'Aguadulce', + 'Carepa', + 'Jogipet', + 'Tambacounda', + 'Hingham', + 'Huntington Beach', + 'Yeniciftlik', + 'Talupula', + 'Naruar', + 'Tudela', + 'Ayyampalaiyam', + 'Kolwara', + 'Cisauk', + 'Jettihalli', + 'Surt', + 'Allen Park', + 'Casier', + 'Zhaxi', + 'Itu', + 'Quilombo', + 'Gharghur', + 'Keerbergen', + 'Gbarnga', + 'Degana', + 'Gretna', + 'Cerro Maggiore', + 'Santa Cruz Michapa', + 'Diamou', + 'Tiruppanandal', + 'Bayji', + 'Njeru', + 'Sour', + 'Martinengo', + 'Rocklin', + 'Saint-Vallier', + 'Yabrud', + 'Alfortville', + 'Kopoky', + 'Phuoc Long', + 'Giarre', + 'Kindu', + 'Ain Cheggag', + 'Babila', + 'Busumbala', + 'Basmenj', + 'Tangjia', + 'Karimunjawa', + 'Bhagatpur', + 'Murtazabad', + 'Konganapuram', + 'Kapelle', + 'Sidi Lamine', + 'Nezahualcoyotl', + 'Prague', + 'Chandreru', + 'Nelliyalam', + 'Kouhu', + 'Bollullos par del Condado', + 'Chiryu', + 'Ain Defla', + 'Trzin', + 'Llandybie', + 'Ushtobe', + 'Mecitozu', + 'Lys-les-Lannoy', + 'Campo Ere', + 'Antambohobe', + 'Kanifing', + 'Mulukuku', + 'Micoud', + 'Siran', + 'Markt Schwaben', + 'Porangatu', + 'Manimala', + 'Liege', + 'Shiremoor', + 'Itaperucu', + 'Puerto Pilon', + 'Bourg-la-Reine', + 'Kadalur', + 'Kodikuthi', + 'Thame', + 'Soahany', + 'Kyritz', + 'Longtoushan Jiezi', + 'Meiktila', + 'Centenario do Sul', + 'Cunit', + 'Engerwitzdorf', + 'Ebreichsdorf', + 'Newbury', + 'Almoloya de Alquisiras', + 'Krishnarayapuram', + 'Kadamakudi', + 'Yongzhou', + 'Sartell', + 'Madeley', + 'Koszutka', + 'Iacanga', + 'Ekhari', + 'Kratie', + 'Nyeri', + 'Qazigund', + 'Langdu', + 'Pong Nam Ron', + 'Timon', + 'Gyeongsan', + 'Minerbio', + 'Singia', + 'East Niles', + 'Mmopone', + 'Masaurhi Buzurg', + 'Liantangcun', + 'Banino', + 'Altopascio', + 'Tillaberi', + 'Riachao do Jacuipe', + 'Nalikkalpatti', + 'Romanshorn', + 'Xinjing', + 'Cha-am', + 'Cumpana', + 'Shenandoah', + 'Pathanamthitta', + 'Tata', + 'Lake Elsinore', + 'Vilavur', + 'Ogdensburg', + 'Santa Maria de Cayon', + 'Rakvere', + 'Baretha', + 'Ankaraobato', + 'Miguel Pereira', + 'West Islip', + 'Tekkekara Kizhakku', + 'Chita', + 'Futrono', + 'Cordon', + 'Ampefy', + 'Santo Domingo de los Colorados', + 'Mtskheta', + 'Dassa-Zoume', + 'San Cristobal', + 'Corona', + 'Telemaco Borba', + 'Pedregulho', + 'Walajapet', + 'Kurnool', + 'Bois-Colombes', + 'Bitritto', + 'Baia Formosa', + 'Mopti', + 'Sassari', + 'General Pinedo', + 'Capim Grosso', + 'Sanok', + 'Nawashahr', + 'Radom', + 'Esbjerg', + 'Scheveningen', + 'Woodland Park', + 'Ljubno', + 'Tirkarur', + 'Mississauga', + 'Oudewater', + 'Plochingen', + 'Villa Donato Guerra', + 'Kuangfu', + 'Mabuhay', + 'Deh-e Shu', + 'Anjur', + 'Sung Noen', + 'Fife', + 'Mhangura', + 'Chalchuapa', + 'Herisau', + 'Cesis', + 'Flensburg', + 'Prado', + 'Fujisaki', + 'Winterveld', + 'Mlimba', + 'Chintakunta', + 'Marsaxlokk', + 'Munakata', + 'Corciano', + 'Sibilia', + 'Pullalacheruvu', + 'Trescore Balneario', + 'Querfurt', + 'Palestine', + 'Salta', + 'Scafati', + 'Atbara', + 'Unhel', + 'Rosenheim', + 'Khambhat', + 'Serafina Corea', + 'Guayos', + 'Ladson', + 'Martinho Campos', + 'Rondon do Para', + 'Gandajika', + 'Konigsbrunn', + 'Dabrowa Tarnowska', + 'Dudhpura', + 'Hurdiyo', + 'Vi Thanh', + 'Blaubeuren', + 'Berubari', + 'Wujiaqu', + 'Warrensville Heights', + 'Duc Pho', + 'Misungwi', + 'Jeju', + 'Diamond Springs', + 'Rabot', + 'Chateau-Gontier', + 'Culver City', + 'Chanhassen', + 'Campamento', + 'Venturosa', + 'Bom Principio', + 'Huquan', + 'Odlabari', + 'Burbage', + 'Siladon', + 'Nutley', + 'Kinzau-Vuete', + 'Ickenham', + 'Belavabary', + 'Kariyapatti', + 'Dzierzoniow', + 'North Cowichan', + 'Mine', + 'Srvanampatti', + 'Uba', + 'Monte Alegre de Sergipe', + 'Espanola', + 'Lenart v Slovenskih Goricah', + 'Hirske', + 'Nallikodur', + 'Kisara', + 'Salamanca', + 'North New Hyde Park', + 'Prudente de Morais', + 'Peragamanna', + 'Kaippakancheri', + 'Venray', + 'Kitakata', + 'Napindan', + 'Beinasco', + 'Anyksciai', + 'Piera', + 'Morab', + 'Charef', + 'Fraserburgh', + 'Maghalleen', + 'Palatine', + 'Batuan', + 'Maldegem', + 'Kalabahi', + 'Hollola', + 'Quimbele', + 'Ippy', + 'Oirschot', + 'Hrib-Loski Potok', + 'Ras el Metn', + 'Dalaba', + 'Thun', + 'Caguas', + 'Jadayampalaiyam', + 'Biaora', + 'Brno', + 'Fino Mornasco', + 'Lohagaon', + 'Silale', + 'Kouka', + 'Tulchyn', + 'Caimito', + 'Teijlingen', + 'Szczecinek', + 'Oulad Rahmoun', + 'Khat Azakane', + 'Koupela', + 'Giddalur', + 'Francisco Sa', + 'Adda-Doueni', + 'Santa Catarina Mita', + 'Nova Olimpia', + 'Sabalito', + 'Hire Vadvatti', + 'Duvva', + 'Iloilo', + 'Catalca', + 'Pribram', + 'McCalla', + 'Oleggio', + 'Lajes', + 'Entroncamento', + 'Vidapanakallu', + 'Moju', + 'East Brunswick', + 'Samalkot', + 'Birnin Konni', + 'Ipaba', + 'Sebba', + 'Joao Camara', + 'Sho`rchi', + 'De Witt', + 'Ebolowa', + 'Nandipeta', + 'Bokaro', + 'Port Glasgow', + 'Vellakkinar', + 'Goldenstedt', + 'Al Jawf', + 'Adliswil', + 'Castelnaudary', + 'Bula', + 'Swan Hill', + 'Brikcha', + 'Valkurti', + 'Lake Hopatcong', + 'Ingeniero Jacobacci', + 'Kemise', + 'Obidos', + 'Central Saanich', + 'Shioya', + 'Ulus', + 'Chicago Heights', + 'Tracy', + 'Al Matariyah', + 'Chelmza', + 'Ban Wat Chan', + 'Chelles', + 'Basni', + 'Moriya', + 'Arzignano', + 'Bharanikavu Tekku', + 'Paikpar', + 'Lake Elmo', + 'Pottanikad', + 'Gorakhpur', + 'Rose Hill', + 'Sallimedu', + 'Kearns', + 'Berehove', + 'Kidderminster', + 'Marieville', + 'Lillers', + 'Voreppe', + 'Rovenky', + 'Spittal an der Drau', + 'Vohipaho', + 'Selnica ob Dravi', + 'Musile di Piave', + 'Sado', + 'El Ancer', + 'Lamego', + 'Kaeng Khro', + 'Laguna Hills', + 'Bag', + 'Krotoszyn', + 'Makhu', + 'Kotha Guru', + 'Bandar-e Bushehr', + 'Borsbeek', + 'Manbij', + 'Mabaruma', + 'Godohou', + 'Landau an der Isar', + 'Zamboanga City', + 'Bendarhalli', + 'Vanavasi', + 'Karlovac', + 'Saraland', + 'Vaucresson', + 'Clusone', + 'Kumi', + 'Turayf', + 'Konakondla', + 'Adet', + 'Yuanhucun', + 'Iramaia', + 'Buttar Khurd', + 'New Richmond', + 'McDonough', + 'Monte Cristo', + 'Save', + 'Khutaha', + 'Erzin', + 'Lovrenc na Pohorju', + 'Tangail', + 'Tadmur', + 'Midyat', + 'Guanajay', + 'Colombes', + 'Garbsen', + 'Leribe', + 'Gamail', + 'Abu Hulayfah', + 'Azcoitia', + 'Abelardo Luz', + 'Kamavarapukota', + 'Bolongongo', + 'Paraiso', + 'Dum Duma', + 'Auckland', + 'Peterlee', + 'Turiacu', + 'Xaignabouli', + 'Huangyan', + 'Camarillo', + 'Volksrust', + 'San Jose de Guaribe', + 'Roca Sales', + 'Glogow Malopolski', + 'Tototlan', + 'Murrells Inlet', + 'Oxford', + 'Amodei', + 'Harbel', + 'Hue', + 'Kajhi Hridenagar', + 'Silvani', + 'Voorschoten', + 'Villeneuve-sur-Lot', + 'Kavaklidere', + 'Chibemba', + 'Avellino', + 'Brejinho', + 'Oulad Cherif', + 'Abra de Ilog', + 'Kurtkoti', + 'Tovala', + 'Gqeberha', + 'Almoloya', + 'Sao Joao do Paraiso', + 'Pella', + 'Zabre', + 'Higashimatsushima', + 'Fairland', + 'Arambakkam', + 'Skvyra', + 'Lamacaes', + 'Lumbreras', + 'Campbelltown', + 'Anoviara', + 'Jurawanpur Karari', + 'Imatra', + 'Medford', + 'Ban Phan Don', + 'Marietta', + 'Pennagaram', + 'Rotselaar', + 'Tezze sul Brenta', + 'Ponnada', + 'Golmud', + 'Ehningen', + 'Amambai', + 'Princeton', + 'Tepeji del Rio de Ocampo', + 'Mosonmagyarovar', + 'Tianguistengo', + 'Mongagua', + 'Elkhorn', + 'Langenthal', + 'Mehrabpur', + 'Obra', + 'Kabo', + 'Ban Mueang Nga', + 'Nga Bay', + 'Kannankurichchi', + 'Bayou Blue', + 'Et Tira', + 'Solita', + 'Bauchi', + 'Uribia', + 'Painkulam', + 'Calkini', + 'Sanchor', + 'Zoersel', + 'Tomiya', + 'Huvin Hippargi', + 'Teodoro Sampaio', + 'Lambton Shores', + 'Tissemsilt', + 'Kolding', + 'Quillacollo', + 'Tenosique', + 'Birnagar', + 'Laeken', + 'Talant', + 'Richterswil', + 'Kundgol', + 'Vitry-sur-Seine', + 'Conwy', + 'Oqtosh Shahri', + 'Yellapur', + 'Kumbakonam', + 'Jizhou', + 'Visoko', + 'Kassala', + 'Bloemendaal', + 'Perl', + 'Kaniv', + 'Ensenada', + 'Armavir', + 'Hirnyk', + 'Turgutalp', + 'Gaoual', + 'Mazzarino', + 'Batley', + 'Trichinopoly', + 'Ban Kang', + 'Manado', + 'Gerstetten', + 'Nechmeya', + 'Khan Yunis', + 'Anatuya', + 'Sosale', + 'Nindiri', + 'Uzwil', + 'Kesli', + 'Srbobran', + 'Jacmel', + 'Malibu', + 'Mulongo', + 'Balehonnur', + 'Froyland', + 'Vernal', + 'Kollegal', + 'San Juan', + 'Wayland', + 'Sirdala', + 'Redwood City', + 'Patalia', + 'Lycksele', + 'Alcantaras', + 'Majdal Shams', + 'Villa de San Diego de Ubate', + "Sa-ch'on", + 'Jalakandapuram', + 'Husum', + 'Coral Terrace', + 'Chropaczow', + 'Khalari', + 'Talence', + 'Arroyo Naranjo', + 'Gundrajukuppam', + 'Hinis', + 'Luoyang', + 'Argenteuil', + 'Dnipro', + 'Zajecar', + 'Usgao', + 'Serra Branca', + 'Hunduan', + 'Anosipatrana', + 'Constantina', + 'Sirur', + 'Bandar Seri Begawan', + 'Zavrc', + 'Rampur Parhat', + 'Saito', + 'Jurupa Valley', + 'Pedras de Fogo', + 'Kalymnos', + 'Jerissa', + 'Beni Khiar', + 'Ginebra', + 'Recco', + 'Kanajanahalli', + 'Miani', + 'Rionegro', + 'Honavar', + 'Bolu', + 'Shepherdsville', + 'Babura', + 'Vilnohirsk', + 'Saint-Loubes', + 'Machados', + 'Roselle', + 'Valle de Bravo', + 'Stoke Gifford', + 'Settiyarpatti', + 'Citrus Heights', + 'Amityville', + 'Muntinlupa City', + 'Poco Branco', + 'Ciudad Cortes', + 'Muncie', + 'Ballenstedt', + 'Kipushi', + 'Simri', + 'Satrovka', + 'Parasi', + 'Dumra', + 'Tha Luang', + 'Galatina', + 'Chiampo', + 'Robinson', + 'Chelsfield', + 'Hersbruck', + 'Ambodivoanio', + 'Carache', + 'Hagfors', + 'Hazlet', + 'Luchong', + 'Maili', + 'Kiangara', + 'Dengtacun', + 'Tuodian', + 'Prudhoe', + 'Codogno', + 'Philippeville', + 'Agsu', + 'Onomichi', + 'Kajiado', + 'Louang Namtha', + 'Sobral', + 'Hermosa', + 'Ouargla', + 'Welwyn Garden City', + 'Niel', + 'San Ramon', + 'Eutin', + 'Patarra', + 'Plainview', + 'Iioka', + 'Shamshernagar', + 'Ravanusa', + 'Madha', + 'Mmadinare', + 'Rawalpindi', + 'Calcinaia', + 'Chak Pahar', + 'Sunbury', + 'Cruzeiro do Oeste', + 'Pemberton', + 'Putian', + 'Sapucaia', + 'Worpswede', + 'Anaheim', + 'Tupancireta', + 'Lyaskovets', + 'Setouchi', + 'Tanay', + 'Takerbouzt', + 'Tarabuco', + 'Volpago del Montello', + 'Al `Arish', + 'Foley', + 'Avion', + 'Dina', + 'Kazerun', + 'Tuljapur', + 'Tocuyito', + 'Arakawa', + 'Sao Jose do Rio Preto', + 'Labuan', + 'Kadama', + 'Kollo', + 'Nieuwkoop', + 'Butalangu', + 'Haeryong', + 'Minbu', + 'Nobeoka', + 'Heunghae', + 'Chaidari', + 'Hoa Thuong', + 'Oelde', + 'Finote Selam', + 'Valayam', + "O'Fallon", + 'Araquari', + 'Nazaria', + 'Hofgeismar', + 'Masaya', + 'Saarlouis', + 'Schluchtern', + 'Mankara', + 'Mersa', + 'Sioux Falls', + 'Altinopolis', + 'South Plainfield', + 'Eccleston', + 'Louangphabang', + 'Kudachi', + 'Outjo', + 'Arluno', + 'Almus', + 'Zehak', + 'Elsenfeld', + 'Garag', + 'Agano', + 'Ferndale', + 'Yui', + 'Kasba Maker', + 'Krakow', + 'Aghbalou Aqourar', + 'Zakynthos', + 'Zhuchangba', + 'Tan Van', + 'Xiezhou', + 'Cinisi', + 'Drogheda', + 'Balurghat', + 'San Sebastian de los Reyes', + 'Kavaratti', + 'Egirdir', + 'Tolentino', + 'Iwanai', + 'Bhongir', + 'Nuzvid', + 'Amaha', + 'Jemaat Oulad Mhamed', + 'Karlovy Vary', + 'Kengri', + 'Khawaspur', + 'Palm Bay', + 'Murungattoluvu', + 'Autlan de Navarro', + 'Bursa', + 'Bruhl', + 'Montemor-o-Velho', + 'Berbera', + 'Mattoon', + 'Mboro', + 'Texcaltitlan', + 'Ellicott City', + 'Banbridge', + 'Bandipur', + 'Talakkad', + 'Ostroda', + 'Imphal', + 'Porto Belo', + 'Chattanooga', + 'Cogan', + 'Oued el Kheir', + 'Girard', + 'Tongshan', + 'Bhogapuram', + 'Cabanglasan', + 'Caleta Olivia', + 'Lozovo', + 'Hythe', + 'Izra', + 'Toba', + 'Sipocot', + 'Borgosatollo', + 'Messina', + 'Manadhoo', + 'Jumri Tilaiya', + 'Ollerton', + 'Riverhead', + 'Dinguiraye', + 'Salehpur', + 'Horizon City', + 'Tettuppatti', + 'Manorville', + 'Gumaca', + 'Barpathar', + 'Ankasakasabe', + 'Rio Caribe', + 'Mutare', + 'Kiramangalam', + 'Voorst', + 'El Ancor', + 'Marsta', + 'Wombourn', + 'Bagong Silangan', + 'Mogiyon', + 'Maracaibo', + 'Amay', + 'Ostrow Wielkopolski', + 'Herent', + 'Yecla', + 'Barrington', + 'Cananeia', + 'Crowborough', + 'Kandori', + 'Toconao', + 'Cazombo', + 'Basel', + 'Halavagalu', + 'Baile an Bhiataigh', + 'Baraboo', + 'Kambla', + 'Hung Yen', + 'Sun City Center', + 'Panniperumthalai', + 'Gwacheon', + 'Hikawa', + 'Zamora', + 'Las Lajas', + 'Dan Gorayo', + 'Racale', + 'La Paloma', + 'Kon Tum', + 'Oloron-Sainte-Marie', + 'Piacabucu', + 'Bourke', + 'Piraeus', + 'Ciudad Benito Juarez', + 'Peje', + 'Sagar', + 'Sivagiri', + 'Biyahmu', + 'Vianopolis', + 'Curitiba', + 'Larkspur', + 'Harenkarspel', + 'Reghin', + 'Kapchorwa', + 'Hohenau', + 'Villa Alsina', + 'Tagami', + 'We', + 'Lac des Oiseaux', + 'Pariharpur', + 'Volodymyrets', + 'Areraj', + 'Chupinguaia', + 'Anantpur', + 'Gif-sur-Yvette', + 'Bronkhorstspruit', + 'Krimpen aan den IJssel', + 'Rock Island', + 'Ban Huai So Nuea', + 'Barcellona-Pozzo di Gotto', + 'Tumbippadi', + 'Pontoise', + 'Bandar Emam', + 'Reconquista', + 'Braniewo', + 'Vettaikkaraniruppu', + 'Ancuabe', + 'Hitachi', + 'Malolos', + 'Ngaparou', + 'Bayamon', + 'Abyek', + 'Tlahuiltepa', + 'Lugano', + 'Crispiano', + 'Padre Hurtado', + 'Wlodawa', + 'Placheri', + 'General Martin Miguel de Guemes', + 'Yangyuhe', + 'La Chapelle-Saint-Mesmin', + 'Darmanesti', + '`Ayn al `Arab', + 'Yorkshire', + 'Calcinato', + 'Sadiqpur Maraul', + 'Tadley', + 'Nkokonjeru', + 'Fatime', + 'Selby', + 'Kafr Ruma', + 'South Brunswick', + 'Yahotyn', + 'North Grenville', + 'Mahajjah', + 'Wangyuanqiao', + 'Hrastnik', + 'Luckenwalde', + 'Kalaiya', + 'Matagalpa', + 'Bulbula', + 'Shirva', + 'Nogoya', + 'Leulumoega', + 'San Diego Country Estates', + 'Magong', + 'Kourouma', + 'Vorkadi', + 'Shibuya', + 'Madathapatti', + 'Cilegon', + 'Betun', + 'Mantes-la-Jolie', + 'Tokar', + 'Medog', + 'Medleri', + 'El Viso del Alcor', + 'Sao Joaquim de Bicas', + 'Cyuve', + 'Igarapava', + 'Hamilton Township', + 'Baldock', + 'Evren', + 'Sangarebougou', + 'Sohagpur', + 'Razua', + 'Naurhiya', + 'Tromsdalen', + 'Mairipora', + 'Yesilyurt', + 'Malacatancito', + 'Szydlowiec', + 'Masiaboay', + 'Taozhuangcun', + 'Gongyefu', + 'Qiziltepa', + 'Pivnichne', + 'Anandpur', + 'Machinga', + 'Irmo', + 'Guntapalli', + 'Indang', + 'Baetov', + 'Sarvar', + 'Eberbach', + 'Douar Oulad Driss', + 'Tanagura', + 'Ikare', + 'Yumurtalik', + 'Kapuvar', + 'Margraten', + 'General Las Heras', + 'Yinhua', + 'Badnawar', + 'Grao Mogol', + 'Dalja', + 'Abensberg', + 'Roque Perez', + 'Rustampur', + 'Cajati', + 'Sarso', + 'Samadh Bhai', + 'Azazga', + 'Kenar', + 'Ealing', + 'Versailles', + 'Kalima', + 'Stillorgan', + 'Portao', + 'Kwinana', + 'Gemena', + 'Oulad Chikh', + 'Arslanbob', + 'Sumenep', + 'Kleppe', + 'Anisoc', + 'Chapel Hill', + 'Timisoara', + 'Saint-Denis', + 'Temescal Valley', + 'Alayor', + 'Siuri', + 'Puerto Colombia', + 'San Andres Timilpan', + 'Tadjenanet', + 'La Londe-les-Maures', + 'Tivaouane', + 'Singaraja', + 'Frisco', + 'Pozzuoli', + 'Robe', + 'Kutina', + 'Escoublac', + 'Ginosa', + 'Weil im Schonbuch', + "Jeffrey's Bay", + 'Emporia', + 'Arbaoua', + 'Saint-Augustin-de-Desmaures', + 'Asslar', + 'Bischofshofen', + 'Vakhsh', + 'Upper Macungie', + 'Karpuzlu', + 'Dattapara', + 'Vaikuntam', + 'Haverhill', + 'Craiova', + 'Santo Amaro da Imperatriz', + 'Orpington', + 'Tibri', + 'Arlov', + 'Luwuk', + 'Pipra Naurangia', + 'Yingkou', + 'Sidi Okba', + 'Torrox', + 'Toki', + 'Matera', + 'Cristinapolis', + 'Ivano-Frankivsk', + 'Ramu', + 'Mangawan', + 'Ishioka', + 'Leones', + 'Mougins', + 'Maco', + 'Hanko', + 'Backnang', + 'Bakamune', + 'Gubbi', + 'Bazhou', + 'Guangzhou', + 'Badajoz', + 'Masdi', + 'Estcourt', + 'Kale', + 'Amaraji', + 'Guire', + 'Mesa', + 'Utebo', + 'Al Khawr', + 'Pararia', + 'Hapur', + 'Maigo', + 'Grimmen', + 'Saratoga Springs', + 'Villejuif', + 'Tucapel', + 'Zhoujiajing', + 'Nicosia', + 'Tirumalaiyampalaiyam', + 'Tamorot', + 'Radford', + 'Ambarakaraka', + 'Maragogipe', + 'Mettlach', + 'Nautla', + 'Nuevo Paysandu', + 'Kuppachchipalaiyam', + 'Steinbach am Taunus', + 'Calverton', + 'Ainring', + 'Olanchito', + 'Calayan', + 'Girardota', + 'Salem Lakes', + 'South Houston', + 'Maharajpur', + 'Saboya', + 'San Jose de Maipo', + 'Chennimalai', + 'Kecioren', + 'Auchi', + 'Elk Plain', + 'Galbois', + 'Shuilin', + 'Malabuyoc', + 'Buyuk Cakirman', + 'Rishra', + 'Aruja', + 'Piata', + 'Uvira', + 'Sohana', + 'Garmdarreh', + 'Wulingshancun', + 'Nijoni', + 'Kudlu', + 'Braunfels', + 'Attappampatti', + 'Pedana', + 'Guayaquil', + 'Crotone', + 'Anse a Pitre', + 'Svishtov', + 'Couzeix', + 'Seinajoki', + 'Schagen', + 'Weatherford', + 'Hidaka', + 'Klazienaveen', + 'Al Harah', + 'Qabb Elias', + 'Al Fashn', + 'Berja', + 'Prieska', + 'Ban Son Loi', + 'Togo', + 'Asagiri', + 'Zafferana Etnea', + 'The Bottom', + 'Kannapolis', + 'Ussel', + 'Nukus', + 'Susehri', + 'Yawata-shimizui', + 'Bhayala', + 'Leagrave', + 'Hermitage', + 'Seynod', + 'Lubawa', + 'Gran', + 'Nazerabad', + 'Shenzhen', + 'Lone Tree', + 'Birecik', + 'Ikongo', + 'Amudalavalasa', + 'Rajgarh', + 'Xalpatlahuac', + 'Lunga-Lunga', + 'Haubourdin', + 'Ambolomoty', + 'Nyamata', + 'Sukhsena', + 'Wanzleben', + 'Brazopolis', + 'Pupiales', + 'Smederevo', + 'Bischofsheim', + 'Mato Verde', + 'Jawhar', + 'Shiraoi', + 'Huanghuajing', + 'San Rafael Arriba', + 'Freienbach', + 'Edegem', + 'Sao Sebastiao de Lagoa de Roca', + 'Yangirabot', + 'Chhapera', + 'Izu', + 'East St. Louis', + 'Chegur', + 'Naawan', + 'Shuangxianxiang', + 'Kalamaria', + 'Shangzhi', + 'Bardiha Turki', + 'Alfeld', + 'Sacele', + 'Pereira Barreto', + 'Tiptree', + 'Bala Koh', + 'Buyende', + 'Macuspana', + 'Gediz', + 'Tocancipa', + 'Taneichi', + 'Makabana', + 'Richland Hills', + 'Puerto Limon', + 'Dighwara', + 'Radovis', + 'Hobbs', + 'Quinchia', + 'Santa Catarina Masahuat', + 'Roquetas de Mar', + 'Willowick', + 'Chahana', + 'Samai', + 'Tasiilaq', + 'Anao-aon', + 'Kattanam', + 'Derbisek', + 'Changuinola', + 'Schwalmstadt', + 'Camposampiero', + 'Mayumba', + 'Raipur', + 'Stanmore', + 'Wesseling', + 'Poldasht', + 'Keora', + 'Hettstedt', + 'Kihoku', + 'Cabimas', + 'Stadthagen', + 'Gorontalo', + 'Cherial', + 'Khonobod', + 'Barntrup', + 'Bhojpur Kadim', + 'Jaltenco', + 'Attendorn', + 'Andranovory', + 'Binche', + 'Muscat', + 'Ludwigsburg', + 'Ain Zora', + 'Dabutou', + 'Landgraaf', + 'Kaunas', + 'Sandwa', + 'Dingolfing', + 'Rothenbach an der Pegnitz', + 'Sheghnan', + 'Mawai', + 'Sunnyside', + 'Esteio', + 'Carnoustie', + 'Sakura', + 'Monte Compatri', + 'Rize', + 'Walvisbaai', + 'Gouande', + 'Bardipuram', + 'Rockford', + 'Pipra Dewas', + 'Jagdishpur', + 'Sonwan', + 'Bridgewater', + 'Akpassi', + 'Zoumi', + 'Tongchuanshi', + 'Guagua', + 'Ayacucho', + 'Lom', + 'Wang Sombun', + 'Pran Buri', + 'Rass el Djebel', + 'Pita', + 'Ait Hani', + 'Saraikela', + 'Cepagatti', + 'Monte Patria', + 'Bessemer', + 'Santa Juliana', + 'Obuse', + 'Schilde', + 'Varel', + 'Almhult', + 'Wesel', + 'Xanten', + 'Bastogne', + 'Glyka Nera', + 'Tasova', + 'Rampur Shamchand', + 'Maarssen', + 'La Asuncion', + 'Streaky Bay', + 'Ridgefield Park', + 'Tichi', + 'Busuanga', + 'Arakvaz-e Malekshahi', + 'Ban Bong Tai', + "Vel'ke Kapusany", + 'Maracas', + 'Rio das Flores', + 'Moers', + 'Bexleyheath', + 'Savsat', + 'Morsott', + 'Germersheim', + 'Pungulam', + 'Sussex', + 'Bilwi', + 'Abare', + 'El Tumbador', + 'Guebwiller', + 'Bourg-en-Bresse', + 'Koskapur', + 'Orvieto', + 'Quartz Hill', + 'Espita', + 'Vechelde', + 'Banting', + 'Cancun', + 'Humahuaca', + 'Hockley', + 'Barwan', + 'Gravesend', + 'Palhalan', + 'Galway', + 'Shotley Bridge', + 'Guioyo', + 'Xaxim', + 'Dunkirk', + 'Amreli', + 'Balqash', + 'Buruanga', + 'Nachchandupatti', + 'Nejo', + 'Lumba-a-Bayabao', + 'Harri', + 'Gaoliying Ercun', + 'Erumakkuzhi', + 'Campina Grande', + 'Palimbang', + 'Al Jabayish', + 'Gurdaspur', + 'Spaichingen', + 'Le Pontet', + 'Villiers-sur-Marne', + 'Doruma', + 'Isa', + 'Puerto San Jose', + 'Gunupur', + 'Salcea', + 'Maruttuvakkudi', + 'Nsanje', + 'Mahamda', + 'Pola de Siero', + 'Radenci', + 'Chincha Alta', + 'Ed Damazin', + 'Red Bank', + 'Whitehaven', + 'Oulad Driss', + 'Edinburg', + 'Floresta', + 'Vili', + 'Saghar Sultanpur', + 'Salon-de-Provence', + 'Batufah', + 'Dalkola', + 'Fostoria', + 'Yauco', + 'Maridi', + 'Nueva Imperial', + 'Saint-Jean-sur-Richelieu', + 'Tupaciguara', + 'Palmdale', + "Notre-Dame-de-l'Ile-Perrot", + 'Rio Largo', + 'Ntossoni', + 'Nagnur', + 'Wallkill', + 'Breda', + 'Solindabad', + 'Penkridge', + 'Agui', + 'George Mason', + 'Aliartos', + 'Itatinga', + 'Tekkampatti', + 'Turicato', + 'Chorleywood', + 'Grootfontein', + 'Kassa', + 'Kotli', + 'Sayreville', + 'Kottavalasa', + 'North Plainfield', + 'Madanapalle', + 'Santa Eulalia', + 'Farnborough', + 'Lerwick', + 'Rohar', + 'Holalkere', + 'Gavirate', + 'Pace', + 'Bharokhara', + 'Oraiokastro', + 'Senekane', + 'Ambohitrarivo', + 'Regente Feijo', + 'Ambotaka', + 'El Crucero', + 'Gummudipundi', + 'Romilly-sur-Seine', + 'Tanggemu Nongchang', + 'Chubek', + 'Quattro Castella', + 'Sai Buri', + 'Piuma', + 'Cerveteri', + 'West Rancho Dominguez', + 'Carmona', + 'Santa Maria', + 'Cayiralan', + 'Wennigsen', + 'Batalha', + 'Vatican City', + 'Bahrain', + 'Tenente Ananias Gomes', + 'Lusambo', + 'Angra dos Reis', + 'Pilkhua', + 'San Marcelino', + 'Kuching', + 'Moche', + 'Straza', + 'Ban Ueam', + 'Kibale', + 'Shahdadpur', + 'West Long Branch', + 'Killai', + 'Chandia', + 'Los Teques', + 'Hpa-An', + 'Wenden', + 'Sao Bento', + 'Wentorf bei Hamburg', + 'Farajok', + 'Uppugunduru', + 'Samkir', + 'Samraong', + 'Pind Dadan Khan', + 'Rajmahal', + 'Paz de Ariporo', + 'Rincon de la Victoria', + 'Vyshhorod', + 'Khaniadhana', + 'Fuxing', + 'Xibang', + 'Antanananivo', + 'Peekskill', + 'Kanhauli Manohar', + 'Kengtung', + 'Yahyali', + 'Yecun', + 'Albolote', + 'Etrotroka', + 'Robstown', + 'Bacoli', + 'Godfrey', + 'Savastepe', + 'Netphen', + 'Cam', + 'Moortebeek', + 'Koufalia', + 'Tabatinga', + 'Qadirganj', + 'Tlanchinol', + 'Kokopo', + 'Parelhas', + 'Bergkamen', + 'Crossville', + 'Charallave', + 'Mahugaon', + 'Tazhakudi', + 'Nawa Nagar Nizamat', + 'Rizhao', + 'Bilasipara', + 'Kfar Aabida', + "E'erguna", + 'Rio Branco', + 'Buique', + 'Maesawa', + 'Rabak', + 'Noqui', + 'Maxcanu', + 'Otegen Batyr', + 'Nellipoyil', + 'Oakville', + 'Serowe', + 'Conselheiro Pena', + 'Ban Fang Tuen', + 'Santa Isabel', + 'Sukhasan', + 'Ocos', + 'Cai Lay', + 'Mangamila', + 'Sikar', + 'Ogoshi', + 'Wimbledon', + 'Islam Qal`ah', + 'Iawar', + 'Kuala Lipis', + 'Gressier', + 'South Laurel', + 'Greendale', + 'Ilfracombe', + 'Prestonpans', + 'Stonegate', + 'Willich', + 'Forssa', + 'Enghien-les-Bains', + 'Balintawak', + 'Kitgum', + 'Pucallpa', + 'Bhilai Karanja', + 'Uzundere', + 'Boshof', + 'Maradi', + 'Bekasi Kota', + 'Mission', + 'Lecherias', + 'Valverde del Camino', + 'Bojaca', + 'Khowai', + 'Heerlen', + 'Bucyrus', + 'Ipameri', + 'Kadaiyam', + 'Guanagazapa', + 'Lencois', + 'Riosucio', + 'Sredets', + 'Rio de Janeiro', + 'Peringuzha', + 'Rabat', + 'Kupang', + 'Louis Trichardt', + 'Tlalixtac de Cabrera', + 'Quincy', + 'Kerrville', + 'Khandala', + 'Waconia', + 'Aventura', + 'Mahabad', + 'Ciudad Miguel Aleman', + 'Al Hamdaniyah', + 'Mankur', + 'Dumbea', + 'Sungailiat', + 'Huitan', + 'Naubatpur', + 'Soubre', + 'Kaniama', + 'Dholbaja', + 'Kuala Kapuas', + 'Oplotnica', + 'Rampur Hat', + 'Sangaree', + 'Fatoma', + 'El Arba Des Bir Lenni', + 'Huamantla', + 'Enamadala', + 'Alibunar', + 'Madirovalo', + 'Bampur', + 'Karachi', + 'Lehi', + 'Cross Lanes', + 'Abou el Hassan', + 'Telwa', + 'Ga-Kgapane', + 'Navraftor', + 'Janapadu', + 'Garesnica', + 'Awantipur', + 'El Fanar', + 'Ayyampettai', + 'Shangzhuangcun', + 'Gainesville', + 'Santanopolis', + 'La Goulette', + 'Chiknayakanhalli', + 'Murtosa', + 'Tirano', + 'Heckmondwike', + 'Mantenopolis', + 'Villa Corzo', + 'Gacko', + 'Etterbeek', + 'Dargot', + 'Kattamuru', + 'Thazhamel', + 'Armilla', + 'Eisenstadt', + 'Elbeuf', + 'Metsamor', + "'Ain el Melh", + 'Karunagapalli', + 'Dayr al Balah', + 'Qazvin', + 'Brokopondo', + 'Keetmanshoop', + 'Chopadandi', + 'Shinas', + 'Silverdale', + 'Orcutt', + 'La Concepcion', + 'Kebili', + 'Tecoluca', + 'Kursaha', + 'Laiyuan', + 'Hilliard', + 'Summit', + 'Vadakku Viravanallur', + 'Phanat Nikhom', + 'Vila Rica', + 'Vantaa', + 'Saint-Amand-les-Eaux', + 'Inole', + 'Barrancas', + 'Upala', + 'Albania', + 'Puerto Galera', + 'Calulo', + 'Mioveni', + 'Yangiariq', + 'Newport News', + 'Puerto Villarroel', + 'San Juan del Rio', + 'Badarwas', + 'Chertsey', + 'Montalvo', + 'Nulivedu', + 'Ain Nouissy', + 'Linhares', + 'Sao Joao da Ponte', + 'Palos Heights', + 'Mondolfo', + 'Vibo Valentia', + "Colle di Val d'Elsa", + 'Tache', + 'Mixquiahuala de Juarez', + 'Montegiardino', + 'Franca', + 'Iwo', + 'Northfield', + 'Neyyattinkara', + 'Hirna', + 'Acquaviva delle Fonti', + 'Voiron', + 'Iturama', + 'Aklanpa', + 'Raymondville', + 'Ambohimandroso', + 'Lakshmipur', + 'Torgelow', + 'Trento', + 'Neiva', + 'Umuarama', + 'San Mauro Torinese', + 'Pago Pago', + 'Ulricehamn', + 'San Cristobal Cucho', + 'Owendo', + 'Basht', + 'Conthey', + 'Damba', + 'Senmayacho-senmaya', + 'Gdansk', + 'Antilla', + 'Husavik', + 'Frankfurt', + 'Seaham', + 'Zagan', + 'Westerly', + 'Sivasli', + 'Nablus', + 'El Wak', + 'Saddle Brook', + 'Tepelene', + 'Vyskov', + 'Tavagnacco', + 'Ndende', + 'Salanso', + 'Laranjeira', + 'Tranquebar', + 'Battulapalle', + 'Bhilwara', + 'Cork', + 'Ennis', + 'Danjiangkou', + 'North Logan', + 'Viralimalai', + 'Firoza', + 'Bettiah', + 'Atharga', + 'Tallimarjon Shahri', + 'Yangi Marg`ilon', + 'Lohariandava', + 'Opera', + 'Gampaha', + 'Teboulba', + 'Solofra', + 'Portoferraio', + 'Daijiazhuang', + 'Jiexiu', + 'Sinkolo', + 'Joutseno', + 'Donauworth', + 'South Glengarry', + 'Nawabganj', + 'Lodhran', + 'Rio San Juan', + 'Kriva Palanka', + 'Rozaje', + 'Manapla', + 'Negresti-Oas', + 'Plaine Magnien', + 'Satsuma', + 'Fatehabad', + 'Rio do Antonio', + 'Calafat', + 'Preganziol', + 'Spalding', + 'Xinji', + 'Kilkottai', + 'Guding', + 'Milici', + 'Paranavai', + 'Skopun', + "Debre Mark'os", + 'Isingiro', + 'Port-Margot', + 'Ludinghausen', + 'Grossenluder', + 'Fenyuan', + 'Araras', + 'Terme', + 'Conneaut', + 'Winnetka', + 'Pelhrimov', + 'Pir Bakran', + 'Sukkampatti', + 'Shrirangapattana', + 'Vatra Dornei', + 'Palmaner', + 'Goose Creek', + 'Hailsham', + 'Douar Tabouda', + 'Douar Echbanat', + 'Adre', + 'Quinto di Treviso', + 'Lagoa Vermelha', + 'Ambatomivary', + 'Maidencreek', + 'Huanuco', + 'Sommerda', + "Sant'Arcangelo di Romagna", + 'Huancavelica', + 'Erramvaripalem', + 'Gyomaendrod', + 'Szigetvar', + "Xin'an", + 'Behror', + 'Antanimenabaka', + 'Sonbarsa', + 'Cuajinicuilapa', + 'Lovosice', + 'Carlos Barbosa', + 'Mlada Boleslav', + 'Wesley Chapel', + 'Adelsdorf', + 'Temascal', + 'Novovolynsk', + 'Brattleboro', + 'Yapacani', + 'Sao Sebastiao do Curral', + 'Makinsk', + 'Ojinaga', + 'Shaoxing', + 'Numazu', + 'Edakkazhiyur', + 'Riesi', + 'Bagamanoc', + 'Inkster', + 'Sugarland Run', + 'Savenay', + 'Eidhi', + 'Elvas', + 'Pannimadai', + 'Dorverden', + 'Luanshya', + 'Grays', + 'Tenente Portela', + 'Iuna', + 'Okmulgee', + 'Busra al Harir', + 'Kil Perambalur', + 'Urucurituba', + 'Villa Aberastain', + 'Sitakund', + 'Ras el-Barr', + 'Luwero', + 'Itaguacu', + 'Vadasinor', + 'Sile', + 'Inhapi', + 'Tanguieta', + 'Olney', + 'Sonpur', + 'Gillitts', + 'Fond du Lac', + 'Aboso', + 'Oujda-Angad', + 'Tiquisate', + 'Chuqung', + 'Jose Abad Santos', + 'Holsbeek', + 'Lioua', + 'Wiang Haeng', + 'Sirugudi', + 'Gomparou', + 'Kodangipatti', + 'Jitwarpur Kumhra', + 'Dhaula', + 'Monte Carmelo', + 'Zhytomyr', + 'Copertino', + 'Panggezhuang', + "M'lang", + 'Caconde', + 'Sao Sebastiao', + 'Rurrenabaque', + 'Canaman', + 'Vienna', + 'Shichinohe', + 'Catia La Mar', + 'Pachchaimalaiyankottai', + 'Bema', + 'Guadalupe', + 'Fouchana', + 'Takatsuki', + 'Nakrekal', + 'Greenfield', + 'Mirabel', + 'Sharon', + 'Valenzuela', + 'Shiroi', + 'Polotitlan de la Ilustracion', + 'Skawina', + 'Merrifield', + 'Bitetto', + 'Hinsdale', + 'Kalafotsy', + 'Reddigudem', + 'El Colegio', + 'Santa Ana Jilotzingo', + 'Korkuteli', + 'Xieqiaocun', + 'Nikko', + 'Purulha', + 'Al Hasakah', + 'Puigcerda', + 'Diabugu', + 'Sao Joao de Pirabas', + 'Yegainnyin', + 'Itasca', + 'Italva', + 'Olavarria', + 'Dikirnis', + 'Tantoucun', + 'Al Khmissat', + 'Woodland', + 'Vasco Da Gama', + 'Amalapuram', + 'Los Amates', + 'Gotha', + 'Burscheid', + 'Tanippadi', + 'Xinyingheyan', + 'St. Pete Beach', + 'Chieri', + 'Ahmadpur', + 'Capela do Alto', + 'Ebn Ziad', + 'Moimenta da Beira', + 'Schwarzenbek', + 'Sasthankotta', + 'Lannion', + 'Oupeye', + 'Digne-les-Bains', + 'Kami', + 'Widnes', + 'Bala Cangamba', + 'Edmonds', + 'Qabr as Sitt', + 'Lorient', + 'Antsinanantsena', + 'Liteni', + 'Belsand', + 'Tibau do Sul', + 'Melpanaikkadu', + 'Uranganpatti', + 'Canasgordas', + 'Totnes', + 'King Edward Point', + 'Ben Daoud', + 'Aarau', + 'San Sebastiano al Vesuvio', + 'Bagam', + 'Hobart', + 'Shimada', + 'Roelofarendsveen', + 'Broomfield', + 'Palenga', + 'Rainham', + 'Molepolole', + 'Hayama', + 'Guines', + 'Gonubie', + 'Filiasi', + 'Gethaura', + 'General Rodriguez', + 'Guilderland', + 'Acarigua', + 'Lowell', + 'Subulussalam', + 'Boiro', + 'Workington', + 'Sebes', + 'Konibodom', + 'Grevesmuhlen', + 'Mixco', + 'St. Andrews', + 'Tirora', + 'Gubat', + 'Edattirutti', + 'Bad Wildbad', + 'Newport Pagnell', + 'Jadcherla', + 'Mountain House', + 'Pindare-Mirim', + 'Hollins', + 'Barddhaman', + 'Castro-Urdiales', + 'Bandora', + 'Masandra', + 'Charo', + 'Qiryat Bialik', + 'Turangi', + 'Lavras da Mangabeira', + 'Hanover', + 'Middleburg', + 'Umm Qasr', + 'Kingswinford', + 'Dachne', + 'Surcin', + 'Al Manaqil', + 'Sorombo', + 'Maruteru', + 'Chaona', + 'Morbi', + 'Rani Shakarpura', + 'Tiko', + 'Picarras', + 'Keratsini', + 'West Deptford', + 'Natividade', + 'Kalale', + 'Hohenkirchen-Siegertsbrunn', + 'Huachipato', + 'Ubaitaba', + 'Shashijie', + 'Nalambur', + 'Monte Mor', + 'Halikner', + 'Pinczow', + 'Vellavadanparappu', + 'Ankli', + 'Oakdale', + 'Ar Rommani', + 'Phulwaria', + 'Berchem', + 'Ban Bang Muang', + 'Mangalapur', + 'Maki', + 'Puente Alto', + 'Paoy Paet', + 'Parsagarhi', + 'Gobernador Galvez', + 'Narpes', + 'Kodumudi', + 'Vostochnyy', + 'Grabouw', + 'Volketswil', + 'Qabala', + 'Falan', + 'Sankt Veit an der Glan', + 'Bargur', + 'Zalishchyky', + 'Paraiso do Norte', + 'Guymon', + 'Corsicana', + 'Malargue', + 'Cheran', + 'Makhmalpur', + 'Mitchellville', + 'Ouamri', + 'Kegeyli Shahar', + 'Nalbari', + 'Caazapa', + 'Bebedouro', + 'Crixas', + 'Jaisinghnagar', + 'Cuimba', + 'Ankireddikuntapalem', + 'Biknur', + 'Parauli', + 'Solec Kujawski', + 'La Riviera', + 'Sakae', + 'Ville Bonheur', + 'Galkot', + 'Tessalit', + 'Joao Alfredo', + 'Vinkovci', + 'Karuppur', + 'Vedappatti', + 'Palocabildo', + 'Nanjing', + 'Haidarnagar', + 'Kabankalan', + 'Acapetahua', + 'Yashio', + 'Wasaga Beach', + 'Gorzow Wielkopolski', + 'Erzurum', + 'Jordbro', + 'Ilmajoki', + 'Cuauhtemoc', + 'Soldanesti', + 'Kontagora', + 'Baleno', + 'Umbertide', + 'Cividale del Friuli', + 'Maidenhead', + 'Taupo', + 'Potters Bar', + 'Hubli', + 'Kakching', + 'Aguadilla', + 'Dobrna', + 'Souk Ahras', + 'Giessen', + 'Feriana', + 'Simdega', + 'Kadugli', + 'Makati City', + 'Harqalah', + 'Flowery Branch', + 'Spartanburg', + 'Royal Oak', + 'Fukuroi', + 'Kishmat Dhanbari', + 'Somerset East', + 'Behisatse', + 'Tummalapenta', + 'Central District', + 'Tubize', + 'Issy-les-Moulineaux', + 'Lezhe', + 'Buriti dos Lopes', + 'Krusevo', + 'Shibuya-ku', + 'Cachoeira', + 'Takahata', + 'Bozeman', + 'Yongqing', + 'Rio Vista', + 'Primavera', + 'Bainbridge Island', + 'Lo Miranda', + 'Sanharo', + 'Sentjernej', + 'Coral Hills', + 'Serres', + 'Kapan', + 'Caruaru', + 'Shijonawate', + 'Para de Minas', + 'Buco Zau', + 'Shaker Heights', + 'Zhaoyu', + 'Koto-ku', + 'Parvatgiri', + 'Evergem', + 'Asalem', + "Mu'tah", + 'Mahalleh-ye Shirinu', + 'Douar Oulad Hssine', + 'Villa Purificacion', + 'Arras', + "Sao Lourenco d'Oeste", + 'Bad Krozingen', + 'Olgiate Comasco', + 'Hanumannagar', + 'Echemmaia Est', + 'Lennox', + 'Kalimpong', + 'Kitob', + 'Las Palmas', + 'Guacima', + 'Urgut Shahri', + 'Carnot', + 'Lambertville', + 'Sabara Bangou', + 'Shahr-e Herat', + 'Longford', + 'Kambove', + 'Cartagena', + 'Odessa', + 'Bani Suwayf', + 'Toqsu', + 'Bibbiano', + 'Torres Vedras', + 'Bareja', + 'Maying', + 'Gross-Umstadt', + 'Anzoategui', + 'Holstebro', + 'Baturite', + 'Neduvannur', + "Terra Roxa d'Oeste", + 'Cencheng', + 'Marondera', + 'Azumino', + 'Sanha', + 'Porto Grande', + 'Ansermanuevo', + 'Perigueux', + 'Makronia', + "Bek'oji", + 'Los Blancos', + 'Argeles-sur-Mer', + 'Khorabar', + 'Fushe-Kruje', + 'Fotsialanana', + 'Aomar', + 'Guardamar del Segura', + 'Ksibet el Mediouni', + 'Georgian Bluffs', + 'Stockport', + 'Saray', + 'Buckley', + 'Daventry', + 'Jaqma', + 'Guifoes', + 'Patpara', + 'Bonhill', + 'Presidente Figueiredo', + 'Cutral-Co', + 'Morgan City', + 'Cernusco sul Naviglio', + 'Beheloka', + 'Bargny', + 'Brits', + 'Nakasato', + 'San Jose de Feliciano', + 'Lithia Springs', + 'Kushtia', + 'Nasipit', + 'Alsdorf', + 'Rockland', + 'Homestead', + 'Ziketan', + 'Ludvika', + 'Erbil', + 'Meguro', + 'Teolo', + 'Lapovo', + 'Streetly', + 'Dar es Salaam', + 'Middleton', + 'Ayancik', + 'Canoas', + 'Kanrangana', + 'Parczew', + 'Puck', + 'Mario Campos', + 'Bedourie', + 'Bohumin', + 'Freha', + 'Juventino Rosas', + 'Kolaras', + 'Oued Sebbah', + 'Kinattukkadavu', + 'Peravurani', + 'Barahona', + 'Kalabo', + 'Kumluca', + 'Saint-Priest', + 'Tagkawayan', + 'Durazno', + 'Ouled Rabah', + 'Susangerd', + 'Reynosa', + 'Araraquara', + 'Ambinanynony', + 'Puerto Madryn', + 'Villa Juarez', + 'Bletchley', + 'Santo Tomas de Janico', + 'El Arahal', + 'Bijapur', + 'Villeneuve-la-Garenne', + 'Nantong', + 'Semera', + 'Dean Funes', + 'Koblenz', + 'Montebello', + 'Sideradougou', + 'Luzhou', + 'Yuanchang', + 'Tulbagh', + 'Hitoyoshi', + 'Wijk bij Duurstede', + 'Damascus', + 'Branchburg', + 'Bahutal', + 'Payyanpalli', + 'Gjovik', + 'Pudukkottai', + 'Lakhdaria', + 'Paracambi', + 'El Bagre', + 'Ban Cho Ho', + 'Villamartin', + 'Natogyi', + 'Wildwood', + 'Tall Salhab', + 'Fort Erie', + 'Kirtipur', + 'Quirihue', + 'Masamagrell', + 'Medak', + 'Futtsu', + 'Cuamba', + 'Zbarazh', + 'Beniel', + 'Azzaba', + 'Banaruyeh', + 'Denver', + 'Slough', + 'Khenifra', + 'Nanbu', + 'Ibarra', + 'Galashiels', + 'Malyn', + 'Biei', + 'Eranapuram', + 'Miechow', + 'San Benedetto del Tronto', + 'St. Matthews', + 'Muhlenberg', + 'Cape Coast', + 'Massa Lombarda', + 'Raybag', + 'Villeta', + 'Jogbani', + 'Agua Blanca', + 'Kaluderica', + 'Dinnington', + 'Jepara', + 'Bhimadolu', + 'Ortona', + 'Xincheng', + 'Huancayo', + 'Crewe', + 'Koduvilarpatti', + 'Eggertsville', + 'Agege', + 'Gharyan', + 'Sucupira do Norte', + 'Datian', + 'Kaldsletta', + 'Paillaco', + 'Anjanazana', + 'Sulphur', + 'Kakrala', + 'Walin', + 'Francisco Caballero Alvarez', + 'Frenda', + 'Robertsport', + 'Simanggang', + 'Flers', + 'Tindouf', + 'Azna', + 'Umrat', + 'Chhimluang', + 'Felixlandia', + 'Tung Tau Tsuen', + 'Soledar', + 'Mejorada del Campo', + 'Nijlen', + 'Przeworsk', + 'Upper Leacock', + 'Machico', + 'Arakkapadi', + 'Gawan', + 'Tracuateua', + 'Tilbury', + 'Indiaroba', + 'Villa Constitucion', + 'Gil', + 'Soyaniquilpan', + 'Nanchang', + 'Guaxupe', + 'Gardone Val Trompia', + 'Lampang', + 'Kahror Pakka', + 'Kundurpi', + 'Gallatin', + 'Belper', + 'Beruri', + 'El Pinon', + 'Chengjiao Chengguanzhen', + 'Ad Darbasiyah', + 'Neo Karlovasi', + 'Mersin', + 'Glyfada', + 'Bastak', + 'Wolfersheim', + 'Albenga', + 'Kuqa', + 'Isanlu', + 'Kaji', + 'Barranquilla', + 'Sai Kung Tuk', + 'Hish', + 'Overpelt', + 'La Vista', + 'Livingston', + 'Bangassi-Nangou', + 'Purcellville', + 'Mashpee', + 'Alushta', + 'Tikar', + 'Katima Mulilo', + 'Duvvuru', + 'Paragominas', + 'Mosquera', + 'Yuzhnoukrainsk', + 'Senador Jose Porfirio', + 'Mutuipe', + 'Castenaso', + 'Schmolln', + 'Mporokoso', + 'Tawsalun', + 'Malo', + 'Myedu', + 'Orsta', + 'Staten Island', + 'Goch', + 'Dulag', + 'Bedlington', + 'Mangatarem', + 'Lubok Antu', + 'Zongo', + 'Toktogul', + 'Sabana Grande de Boya', + 'Mullheim', + 'Mogilno', + 'Abra Pampa', + 'Sidi Baizid', + 'Rostusa', + 'Glen Allen', + 'Barra de Sao Francisco', + 'Jocotitlan', + 'Pensilvania', + 'Petropavl', + 'Radlje ob Dravi', + 'Chichaoua', + 'Irondale', + 'Namhkam', + 'Liestal', + 'Yazu', + 'Douar Olad. Salem', + 'Mecca', + 'Fergus Falls', + 'Shimotoba', + 'Purificacion', + 'Qal`at Sukkar', + 'Zhezqazghan', + 'Kenafif', + 'Chak That', + 'Roanoke Rapids', + 'Manakondur', + 'Beni Enzar', + "Nefas Mewch'a", + 'Kerap', + 'Narsingi', + 'Arys', + 'Ajaccio', + 'Lihue', + 'Herentals', + 'Tarakan', + 'San Jose del Fragua', + 'Sitio Novo de Goias', + 'Jammu', + 'Ballesteros', + 'Bayreuth', + 'Schererville', + 'Kara-Suu', + 'Mbandjok', + 'Xinpi', + 'Caudry', + 'Jalhalli', + 'Rosario de Mora', + 'Hampden', + 'Tevaram', + 'Annapolis Neck', + 'Minokamo', + 'Ghataro Chaturbhuj', + 'Neyshabur', + 'North Mankato', + 'Nea Makri', + 'Matino', + 'San Vito al Tagliamento', + 'Shangchuankou', + 'Maldon', + 'Tirupparangunram', + 'Chateauneuf-les-Martigues', + 'Sumare', + 'La Calamine', + 'Plettenberg Bay', + "Monteroni d'Arbia", + 'Ban Charoen Mueang', + 'Pukekohe East', + 'Ban Sop Tia', + 'Barbacoas', + 'Plottier', + 'Fleetwood', + 'Fultondale', + 'Karahia', + 'Grefrath', + 'Kalavai', + 'Borsa', + 'Bournville', + 'Changwon', + 'Chik Banavar', + 'Kungsbacka', + 'Yunoshima', + 'Pithiviers', + 'Zepce', + 'Rosario do Sul', + 'Nadiad', + 'Besancon', + 'Rupbas', + 'Muong Theng', + 'Dubrovytsya', + 'Someren', + 'Lianyuan', + 'Huilongping', + 'Zrenjanin', + 'Ban Wiang Phan', + 'Jucurutu', + 'Alamos', + 'Zetang', + 'Lymm', + 'Sarajevo', + 'Saint-Sebastien-sur-Loire', + 'Sereflikochisar', + 'Suai', + 'La Leonesa', + 'Tequisquiapan', + 'Faya', + 'Fort Saskatchewan', + 'Neuilly-Plaisance', + 'Elenga', + 'Dearborn', + 'Gok', + 'Ipora', + 'Mierlo', + 'Ottappalam', + 'Mirandiba', + 'Rongjiawan', + 'Sarno', + 'Volpiano', + 'Ain Touta', + 'Swietochlowice', + 'San Dimas', + 'Brenham', + 'Birkenfeld', + 'Sveti Jurij', + 'Montfermeil', + 'Bowen', + 'Xiangcheng', + 'Bariariya', + 'Albufeira', + 'Pantin', + 'Ruffano', + 'Buurhakaba', + 'Kulai', + 'Nordlingen', + 'Alcanar', + 'Ostfildern', + 'San Juan del Puerto', + 'Zunhua', + 'Yuregir', + 'Amha', + 'San Antonio de los Banos', + 'Pojuca', + 'Cernavoda', + 'Maria', + 'Saky', + 'Ciudad Victoria', + 'Qasr-e Qand', + 'North Lauderdale', + 'Manahari', + 'Kartikapalli', + 'Herne', + 'Zabki', + 'Middle River', + 'Moncion', + 'Er Regueb', + 'Ridge', + 'Tezu', + 'Djendel', + 'Tynaarlo', + 'Katra', + 'Le Plessis-Trevise', + 'Pernik', + 'Grossostheim', + 'Dharir', + 'Kherrata', + 'Guamal', + 'Mangrawan', + 'Haldibari', + 'Yingzhou Linchang', + 'Zgierz', + 'Brownsburg', + 'Radebeul', + 'Novara', + 'Markacho', + 'Lochristi', + 'Oyem', + 'Porcia', + 'Bogoso', + 'Tapa', + 'Carmagnola', + 'Alto Parnaiba', + 'Prosper', + 'Nossombougou', + 'Tohana', + 'Turlock', + 'Gualaquiza', + 'Masrakh', + "Arba Minch'", + 'Moroto', + 'Carcassonne', + 'Paraipaba', + 'Jajarm', + 'Raparla', + "Diao'ecun", + 'Oued Laou', + 'Sint-Niklaas', + 'Masuda', + 'Tilvalli', + 'Tauranga', + 'Upplands Vasby', + 'Wabash', + 'Tapas', + 'Al `Alamayn', + 'Huozhou', + 'Tshikapa', + 'Kennedy Town', + 'Wisconsin Rapids', + 'Yangiyul', + 'Quezalguaque', + 'Bougado', + 'Cuautepec de Hinojosa', + 'Mundo Novo', + 'Verl', + 'Maghnia', + 'Dzouz', + 'Principe da Beira', + 'Bamessi', + 'Soloma', + 'Basay', + 'Closter', + 'Amatenango de la Frontera', + 'Bazarak', + 'Benairia', + 'Mocharim', + 'Kuchesfahan', + 'Kurayoshi', + 'Luohe', + 'Kampot', + 'Chaska', + 'Lynden', + 'Purushottampur', + 'Konin', + 'Long Xuyen', + 'Kizhakkott', + 'Peachtree Corners', + 'Natshal', + 'Saleaula', + 'Bahia Blanca', + 'Semey', + 'Rianxo', + 'Caridad', + 'Hammam el Rhezez', + 'Kudelstaart', + 'Huizen', + 'Narasapuram', + 'Parkville', + 'Kadungapuram', + 'Garden City', + 'Daulatkhan', + 'Tectitan', + 'Maroambihy', + 'Pallini', + 'Center Point', + 'North Bay', + 'Maihar', + 'Lons', + 'Huehuetenango', + 'Qalqilyah', + 'Koryo', + 'Betafo', + 'Rheinbach', + 'Surprise', + 'Sumbawanga', + 'Thatha', + 'Kurugodu', + 'Neustadt in Holstein', + 'Jupi', + 'Santa Isabel do Para', + 'Chandrawada', + 'Tamra', + 'Cusset', + 'Le Cres', + 'Tunduma', + "Toyloq Qishlog'i", + 'Southbourne', + 'Hempfield', + 'Dhilwan', + 'Roseville', + 'Sisimiut', + 'Aizubange', + 'Lleida', + 'Muri', + 'Phalombe', + 'Antsoha', + 'Saha', + 'Muana', + 'Djambala', + 'Istanbul', + 'Andoharanofotsy', + 'Seligenstadt', + 'Djougou', + 'Boukadir', + 'Ingeniero Pablo Nogues', + 'Barwon Heads', + 'Hazleton', + 'Ciudad Tula', + 'Northeim', + 'Galela', + 'Rehoboth', + 'Bemanonga', + 'Nawucun', + 'Gallup', + 'Malayer', + 'Abu Za`bal', + 'Seia', + 'Samalsar', + 'Melfi', + 'Puduvayal', + 'Namsos', + "Bailey's Crossroads", + 'Gardere', + 'Bermo', + 'Gaillard', + 'Qiushanxiang', + 'Rokycany', + 'Cesena', + 'Alto Piquiri', + 'Mendoza', + 'Rudrangi', + 'Kotido', + 'Turbihal', + 'Comox', + 'Shangpa', + 'Tzintzuntzan', + 'Nao Kothi', + 'Cogolin', + 'Nhan Trach', + 'Royal Wootton Bassett', + 'Suhar', + 'Prestea', + 'Zahle', + 'Cherniakhiv', + 'Thinadhoo', + 'Phuthaditjhaba', + 'Pasco', + 'Madhavaram', + 'Chuo-ku', + 'Kishi', + 'Tavistock', + 'Jitpur', + 'Legnano', + 'Heusweiler', + 'Punnila', + 'Bonoufla', + "Qiryat Mal'akhi", + 'Jaguari', + 'Erraguntlakota', + 'Valdobbiadene', + 'Lupao', + 'Hille', + 'Cosamaloapan', + 'Tromso', + 'Charkhi Dadri', + 'Dolo Odo', + 'Ebersbach an der Fils', + 'Chojnow', + 'Perkasie', + 'Zhamog', + 'Seiada', + 'Bjelovar', + 'Puerto Natales', + 'Camaguey', + 'Dabakala', + 'Katagami', + 'Panchla', + 'Borgoricco', + 'St. Albans', + 'Campeche', + 'Kontela', + 'Broughty Ferry', + 'Shihuajie', + 'Alvinopolis', + 'Parilla', + 'Georgetown', + 'North Palm Beach', + 'Canela Baja', + 'Darpa', + 'Battipaglia', + 'Upland', + 'Bombinhas', + 'Houten', + 'Ibiracu', + 'Paraopeba', + 'Hokota', + 'Whitpain', + 'Nakoushi', + 'Krasnoilsk', + 'Guapimirim', + 'Bom Jesus da Serra', + 'Tesalia', + 'Arohi', + 'Pyay', + 'Tryavna', + 'Mufulira', + 'Weligama', + 'Gaillac', + 'Rettanai', + 'Marano di Napoli', + 'Jefferson City', + 'Tulagi', + 'Nirmali', + 'Passos', + 'Htison', + 'Harewa', + 'Miren', + 'Shika', + 'Alfajayucan', + 'San Pedro Masahuat', + 'Galhinna', + 'Silla', + 'Dong Ha', + 'Legazpi City', + 'Hassi Messaoud', + 'Bhadrapur', + 'Anjahambe', + 'Sirsaganj', + 'Menglang', + 'Qarchak', + 'Gandhwani', + 'Penedo', + 'Peralta', + 'Rappang', + 'Bad Bramstedt', + 'Weinfelden', + 'Aliaga', + 'Douar Sidi Laaroussi', + 'Regedor Quissico', + 'Sidi Dahbi', + 'Joppatowne', + 'Borgo a Buggiano', + 'Tiqqi', + 'Stakhanov', + 'Basmakci', + 'Oulad Fraj', + 'Moron', + 'Thunder Bay', + 'Manoharpur', + 'Kuniyamuttur', + 'Onondaga', + 'Lopare', + 'Zumaia', + 'Kahemba', + 'Altenstadt', + 'Cabuyao', + 'Kafr az Zayyat', + 'Burriana', + 'Kulharia', + 'Barinas', + 'Nelmadur', + 'Demirozu', + "Bois-d'Arcy", + 'Lahad Datu', + 'Venganellur', + 'Tsuruoka', + 'Bordertown', + 'Amrabad', + 'Sala', + 'Coronel Freitas', + 'Bassin Bleu', + 'Porto Santo Stefano', + 'Ait Yazza', + 'Thanhlyin', + 'Tournai', + 'Valea Adanca', + 'Saint-Cloud', + 'Ginowan', + "Welk'it'e", + 'Siilinjarvi', + 'Inhangapi', + 'Huazhou', + 'Eski Yakkabog`', + 'Tobelo', + 'Horsholm', + 'Springs', + 'Lorengau', + 'Manwat', + 'Khmilnyk', + 'Hrubieszow', + 'Santa Teresa di Riva', + 'Portel', + 'El Dorado Hills', + 'Pattiswaram', + 'Bad Reichenhall', + 'Dourdan', + 'Dakhram', + 'Rio de Contas', + 'Pagudpud', + 'Sao Felix', + 'Kosjeric', + 'Lebanon', + 'Fargo', + 'Mont-Saint-Aignan', + 'Wald', + 'Eckernforde', + 'Chicholi', + 'Goldap', + 'Kurashiki', + 'Santa Maria Colotepec', + 'Kawaii', + 'Narapala', + 'Maimanah', + 'Ponda', + "'Ain Roua", + 'Manyoni', + 'Mineiros', + 'Moussoro', + 'Olhao', + 'Ridley', + 'Sidi Ouassay', + 'Nancagua', + 'Sagay', + 'Majurwa', + 'Okotoks', + 'Chengannur', + 'Middletown', + 'Heredia', + 'Mbanza Kongo', + 'Texenna', + 'Urania', + 'Cantemir', + 'Albertirsa', + 'Qala', + 'Molinella', + 'Pahrump', + 'Padugupadu', + 'Utiel', + 'Harbatpur', + 'Orestiada', + 'Tiachiv', + 'Kahta', + 'Cesenatico', + 'Omaruru', + 'Siquijor', + 'America Dourada', + 'Kilkis', + 'Ascot', + 'Zhujiagua', + 'Bagheria', + 'Puerto Wilches', + 'Torre Maggiore', + 'Tomuk', + 'Huanggang', + 'Trovagunta', + 'Devanakonda', + 'Sa Pa', + 'Narashino', + 'Koganei', + 'West Memphis', + 'Pendleton', + 'Edenvale', + 'Dieburg', + 'Ankavandra', + 'Gondalga', + 'Quang Ha', + 'Xochistlahuaca', + 'Niiyama', + 'Viedma', + 'Sukhothai', + 'Cuorgne', + 'Janzur', + 'Dhansura', + 'Rio Maior', + 'Penuganchiprolu', + 'Jaora', + 'Kanzakimachi-kanzaki', + 'Hunfeld', + 'Yabayo', + 'Torre del Mar', + 'Shenyang', + 'Odacho-oda', + 'Lagdo', + 'Otuzco', + 'Hagi', + 'Pompeu', + 'Repalle', + 'Majagual', + 'Yulinshi', + 'Periyakoduveri', + 'Ubon Ratchathani', + 'Al `Amadiyah', + 'Saint-Andre', + 'Omis', + 'Arcozelo', + 'Doujing', + 'Vuhledar', + 'Hindley', + 'Aphaur', + 'Oliveira', + 'Nasir', + 'Palm Desert', + 'Khategaon', + 'Esmoriz', + 'Belmont', + 'Koani', + 'Gyomro', + 'Mackworth', + 'Rubio', + 'Zafra', + 'San Juan Evangelista', + 'Qoubaiyat', + 'Lautoka', + 'Cerkes', + 'Villeneuve-le-Roi', + 'Xinhua', + 'Touros', + 'Nyaungu', + 'Chakand', + 'Aluksne', + 'Yishui', + 'Timperley', + 'Oakwood', + 'Chakwal', + 'Tarauna', + 'Khandrauli', + 'Huaquechula', + 'Bhatinda', + 'Puerto Williams', + 'Tongliao', + 'Staffanstorp', + 'Kisumu', + 'Mangueirinha', + 'Leopoldina', + 'Luchow', + 'Harrismith', + 'Indija', + 'Campo Redondo', + 'Lastra a Signa', + 'Akhisar', + 'Alnif', + 'Tega Cay', + 'Foughala', + 'Jinjicun', + 'Kangning', + 'Treze Tilias', + 'Landau', + 'Vaires-sur-Marne', + 'Udiyavara', + 'Boquim', + 'Hekou', + 'Kirchheim unter Teck', + 'Kondakindi Agraharam', + 'Sao Mateus', + 'Simonesia', + 'Pinerolo', + 'Ptuj', + 'Mezobereny', + 'Gex', + 'Unnan', + 'Dayr Abu Hinnis', + 'Sanampudi', + 'Simon Bolivar', + 'Oteiza', + 'Gragnano', + 'Khartsyzk', + 'Beramanja', + 'Richmond Hill', + 'Juru', + 'Padavedu', + 'Ekwari', + 'Brescia', + 'La Cruz', + 'Pulimaddi', + 'Pleasant Hill', + 'Hozin', + "Sant'Ambrogio di Valpolicella", + 'Telua', + 'Bilozerske', + 'Adami Tulu', + 'Manteca', + 'Delmiro Gouveia', + 'Mindelheim', + 'Fate', + 'Hokur Badasgom', + 'Sidi Kada', + 'Talayolaparambu', + 'Connersville', + 'Gurinhem', + 'Skopje', + 'Fairless Hills', + 'Debrecen', + 'El Realejo', + 'Gadhada', + 'Schwalmtal', + 'Yamaga', + 'Bihar', + 'Pakil', + 'Loni', + 'Chilgazi', + 'Varzobkala', + 'Samandag', + 'Portela', + 'Wanghong Yidui', + 'Qianxi', + 'Dese', + 'Hathidah Buzurg', + 'Periyapuliyur', + 'Bilston', + 'Laja', + 'Makhdumpur', + 'Les Pennes-Mirabeau', + 'Himmatpura', + 'Denia', + 'Keimoes', + 'Castillo de Teayo', + 'Conselve', + 'Longmeadow', + 'Herne Bay', + 'Sao Miguel do Guama', + 'Sunland Park', + 'Israna', + 'Bassian', + 'Qift', + 'Behshahr', + 'Kotli Ablu', + 'Hidrolandia', + 'Torre Santa Susanna', + 'Kirdasah', + 'Tanjungpinang', + 'Reshuijie', + 'Wappinger', + 'Perungudi', + 'Goworowo', + 'Knin', + 'Vardhamankota', + 'Campo Limpo', + 'Sermoneta', + 'Limoeiro de Anadia', + 'Otsuchi', + 'Niamina', + 'Kasumigaura', + 'West Puente Valley', + 'Sungai Petani', + 'East Windsor', + 'Pedro Celestino Negrete', + 'Yorkton', + 'Gueznaia', + 'Telica', + 'Mong Cai', + 'El Paisnal', + 'Provo', + 'Stefan Voda', + 'Vargem', + 'Treillieres', + 'Procida', + 'Sens', + 'Aperibe', + 'Comasagua', + 'Hulbuk', + 'Talakag', + 'Puduva', + 'Hashikami', + 'Randallstown', + 'Sahline', + 'Bejar', + 'Isnapuram', + 'Teghra', + 'Eschwege', + 'Carver', + 'Franklin Park', + 'Tremedal', + 'Itahara', + 'Lancut', + 'Vettikattiri', + 'Meyzieu', + 'Al Abraq', + 'Basista', + 'Charlotte Amalie', + 'Palembang', + 'Esparraguera', + 'Villacidro', + 'Berettyoujfalu', + 'Peravali', + 'Mastic Beach', + 'Perundurai', + 'San Francisco', + 'Bangassou', + 'Kauriya', + 'Carinhanha', + 'Otjiwarongo', + 'Minot', + 'Covilha', + 'Shahe', + 'Petrila', + 'Portchester', + 'Ban Lueak', + 'Aminpur', + 'Calenga', + 'Bafata', + 'Cumnock', + 'Clichy', + 'Tabernes Blanques', + 'Siloe', + 'Qiaotouyi', + 'Candido Mota', + 'Barbosa', + 'Borcka', + 'Maryland City', + 'Lacarak', + 'Crestview', + 'Jounie', + 'Hochdorf', + 'Montelibano', + 'Tundhul', + 'Osku', + 'Monsenhor Tabosa', + 'Anosiala', + 'Ban Pa Sak', + 'Kanakir', + 'Wakayama', + 'Muttenz', + 'Makale', + 'Medesano', + 'Lamerd', + 'Bakarpur Ogairah', + 'Wetherby', + 'Nakagawa', + 'Sao Jose dos Pinhais', + "Nova Brasilandia d'Oeste", + 'Piquet Carneiro', + 'Valmadrera', + 'Pua', + 'Chak Forty-one', + 'Sandvika', + 'Stansted Mountfitchet', + 'Snoqualmie', + 'Pereiras', + 'Joaquim Nabuco', + 'Mondragon', + 'Huixcolotla', + 'Minamiuonuma', + 'Gap', + 'General Villegas', + 'Matane', + 'El Monte', + 'Minamiminowa', + 'Saint-Andre-les-Vergers', + 'Ibb', + 'Oudenaarde', + 'Lainate', + 'Box Elder', + 'Karanchedu', + 'Guanhaes', + 'Calderara di Reno', + 'Itainopolis', + 'Gattaran', + 'Muhlacker', + 'Rengo', + 'Winkler', + 'Marathalli', + 'Cambuquira', + 'Ilulissat', + 'Kalyandrug', + 'Kesabpur', + 'Santiago de Anaya', + 'Ano Liosia', + 'Vung Tau', + 'Monaco', + 'Cuesmes', + "Ra's al `Ayn", + 'Rasebetsane', + 'Tagudin', + 'Basopatti', + 'Mack', + 'Pedra Badejo', + "Les Sables-d'Olonne", + 'Hosakote', + 'Barbastro', + 'Tutoia', + 'Manpur', + 'Higashiyamato', + 'Varvarin', + 'Manhica', + 'Kachchippalli', + 'Velugodu', + 'Palin', + 'Xinchangcun', + 'Alchevsk', + 'Anzegem', + 'Doi Saket', + 'Amersham', + 'Namburu', + 'Union Hill-Novelty Hill', + 'Apopa', + 'Zafarabad', + 'Nanminda', + 'Burlington', + 'Hibbing', + 'Galloway', + 'Union City', + 'Dukinfield', + 'Montecristo', + 'Shrigonda', + 'Uchoa', + 'Tizi-n-Tleta', + 'Stellenbosch', + 'Olaine', + 'Isabel', + 'Luqa', + 'Matinha', + 'Bni Rzine', + 'Attimarappatti', + 'Circasia', + 'Ban Krot', + 'Selimpasa', + 'Xangongo', + 'Simiganj', + 'Coacoatzintla', + 'Nueva Helvecia', + 'Chenzhou', + 'Lota', + 'Lawrenceville', + 'Vayanur', + 'Tobe', + 'Ende', + 'Haslemere', + 'Calabayan', + 'Pakxe', + 'Pajapan', + 'Udhampur', + 'Tsararivotra', + 'Telerghma', + 'Haydock', + 'Surmon Chogga Grong', + 'Trebic', + 'Alafaya', + 'Kafr Sajnah', + 'Conceicao', + 'Vellore', + 'Usingen', + 'Terenure', + 'Bouca', + 'Ghat Borul', + 'Baisuhalli', + 'Daulatpur', + 'Grossrohrsdorf', + 'Lorica', + 'Hagaribommanahalli', + 'Ban Thoet Thai', + 'Loznica', + 'Ponmala', + 'Padiyur', + 'Tigoa', + 'Budva', + 'Mistassini', + "'Ain Babouche", + 'El Limon', + 'Diouna', + 'Rieti', + 'Kuttyadi', + 'Xinyang', + 'Killiney', + 'Pop', + 'Guaymango', + 'Springbok', + 'Presque Isle', + 'Timra', + 'Abuja', + 'Miyakojima', + 'Payyannur', + 'Xunyang', + 'Bailen', + 'Chambellan', + 'Bukit Mertajam', + 'Cattolica', + 'Serdar', + 'Sarare', + 'Coronel Vivida', + 'Herriman', + 'Guliston', + 'Rouvroy', + 'Garfield', + 'Elmina', + 'Sarreguemines', + 'Milwaukie', + 'Ershui', + 'Garot', + 'Czestochowa', + 'Kirklareli', + 'La Jagua de Ibirico', + 'Stroud', + 'Kocaeli', + 'Calimaya', + 'Savalou', + 'Manalalondo', + 'Cikupa', + 'Cide', + 'Idylwood', + 'East Massapequa', + 'Andijon', + 'Ibusuki', + 'Brahmapur', + 'Mount Prospect', + 'St. James', + 'Vila Franca de Xira', + 'Bhadreswar', + 'Khandwa', + 'Amporoforo', + 'Celic', + 'Gomec', + 'Fort Carson', + 'Kosiv', + 'Fria', + 'Cliftonville', + 'Narvacan', + 'Ramanathapuram', + 'Jawasa', + 'Guclukonak', + 'Samobor', + 'Ceska Trebova', + "Anan'evo", + 'Zinjibar', + 'Indianapolis', + 'Yanggok', + 'Aberdare', + 'Palm River-Clair Mel', + 'Diari', + 'Chilmil', + 'Callosa de Segura', + 'Kummersbruck', + 'Sambava', + 'Pritzwalk', + 'Karai', + 'Lachhmangarh Sikar', + 'Wade Hampton', + 'Rapla', + 'Assa', + 'Malavalli', + 'Trinec', + 'La Verne', + 'Selibaby', + 'Zagnanado', + 'Commerce City', + 'Tredyffrin', + 'Salaberry-de-Valleyfield', + 'Longtan', + 'Karatsu', + 'Badian', + 'Sao Sebastiao do Paraiso', + 'Satyamangala', + 'Balsta', + 'Gamagori', + 'Chinampa de Gorostiza', + "Ambinanin'i Sakaleona", + 'Itiquira', + 'Center', + 'Umargam', + 'Ozurgeti', + 'Montereau-faut-Yonne', + 'Amau', + 'Nova Esperanca', + 'Venezuela', + 'Kafia Kingi', + 'Tanguturu', + 'Vinto', + 'Sonosari', + 'Sturovo', + 'Date', + 'Niska Banja', + 'An Nhon', + 'Littlehampton', + 'Fuente Palmera', + 'Sokode', + 'Donghua', + 'South Holland', + 'Frimley', + 'Bachchannapet', + 'Junnardev', + 'Dole', + 'Neuotting', + 'Monforte del Cid', + 'Baguley', + 'Brimington', + 'Calauan', + 'Durmersheim', + 'Wittenberge', + 'Echizen', + 'Dobropillia', + 'Ayuquitan', + 'Viramgam', + 'Matsuura', + 'Abu Dis', + 'Winsum', + 'Gentbrugge', + 'Villa Victoria', + 'Yovon', + 'Boaz', + 'Kotta Kalidindi', + 'Great Bend', + 'Tarcento', + 'Limbazi', + 'Bajos de Haina', + 'Karakax', + 'Ibira', + 'Yakushima', + 'Goito', + 'Nabari', + 'Sabanalarga', + 'Tiou', + 'Renens', + 'Dolores', + 'Agago', + 'Madakalavaripalli', + 'Mapastepec', + 'La Lucila', + 'Cherakhera', + 'Sadaseopet', + 'Neerijnen', + 'Krathum Baen', + 'Gansbaai', + 'Mahalandi', + 'Chanaur', + 'La Argentina', + 'Jesup', + 'Bela Crkva', + 'Soteapan', + 'Siechnice', + 'Lwakhakha', + 'Uspallata', + 'Imbatug', + 'Altavas', + 'Jaglot', + 'Colangute', + 'Kumatori', + 'Andapa', + 'Choconta', + 'Sarhari', + 'Santiago Jocotepec', + 'Arauca', + 'Hailin', + 'Shahr-e Majlesi', + 'Guyuan', + 'Murfatlar', + 'Chon Buri', + 'Bacnotan', + 'Kutna Hora', + 'Xiva', + 'Mizque', + 'West Ham', + 'Roatan', + 'Doylestown', + 'Tarichar Kalan', + 'Foz do Iguacu', + 'Garching an der Alz', + 'Tifariti', + 'Longwy', + 'Tarikere', + 'Alameda', + 'Gbanhi', + 'Catunda', + 'Kirchhundem', + 'Cuenca', + 'Delareyville', + 'Cliffside Park', + 'Orting', + 'Kapadvanj', + 'Nigran', + 'Fengyicun', + 'Pazardzhik', + 'Yeddumailaram', + 'Longkeng', + 'Nikaho', + 'Altofonte', + 'Douar Oulad Youssef', + 'Lathi', + 'Osh', + 'Daytona Beach', + 'Atharan Hazari', + 'Ami', + 'Balaguer', + 'Malnate', + 'Quanzhang', + 'Rio Claro', + 'Hajdusamson', + 'Gouvea', + 'Kunming', + 'Kulasegaram', + 'Pori', + 'Braintree', + 'Bijelo Polje', + 'Mateur', + 'Kozova', + 'Fenoarivo Atsinanana', + 'Leisure World', + 'Taman Senai', + 'Nerinjippettai', + 'Washington', + 'Basapatna', + 'Mwene-Ditu', + 'Norak', + 'South Upi', + 'Yokadouma', + 'Abbigeri', + 'Kouoro', + 'Freilassing', + 'Nymburk', + 'Cangandala', + 'Dihri', + 'Arakli', + 'Huaihua', + 'Turkauliya', + 'Ramainandro', + 'Aytos', + 'Lihe', + 'Raseborg', + 'Tomioka', + 'Sakrand', + 'Belur', + 'Kaseda-shirakame', + 'Mettingen', + 'Bugalagrande', + 'Annandale', + 'Mambere', + 'Oume', + 'Al Buwaydah', + 'Eagle', + 'Ustron', + 'Pegnitz', + 'Massaguet', + 'Bibbiena', + 'Saint-Vith', + 'Geelong', + 'Glen Rock', + 'Miarinavaratra', + 'Sao Simao', + 'Gurlan', + 'La Escala', + 'Mian Channun', + 'Tono', + 'Kevelaer', + 'Jiaozhou', + 'Einsiedeln', + 'Udaypur Gadhi', + 'Molagavalli', + 'Sira', + 'Ospina', + 'Kuduru', + 'Komarolu', + 'Arnprior', + 'Breclav', + 'Qornet Chahouane', + 'Okaya', + 'Montesarchio', + 'Tecoh', + 'Dezful', + 'Quiculungo', + 'Tam Ky', + 'Qaracuxur', + 'Daxin', + 'Horsham', + 'Tafalla', + 'Yehud', + 'Abertawe', + 'Darien', + 'Shodoshima', + 'El Arenal', + 'Litomerice', + 'Caboolture', + 'Norwalk', + 'Mananara Avaratra', + 'Herten', + 'Kihihi', + 'Aira', + 'Kuttampala', + 'Noumea', + 'Phon-Hong', + 'Thair', + 'Herzogenrath', + 'Planalto', + 'Arrecifes', + 'Fuente-Alamo de Murcia', + 'Gilbues', + 'Miltenberg', + 'Bubong', + 'Henstedt-Ulzburg', + 'Rayavaram', + 'Alberique', + 'Pimpalgaon Raja', + 'Palencia', + 'Lalganj', + "L'Isle-Adam", + 'Abasolo', + 'Sirikonda', + 'Devadanappatti', + 'Pokrovka', + 'Baliguian', + 'Corum', + 'Tlacolula de Matamoros', + 'Jeremie', + 'Myaungmya', + 'Tissa', + 'Capljina', + 'Ambariokorano', + 'Gemert', + 'Akayu', + 'Bhiwandi', + 'Chishui', + 'Abbotsford', + 'La Carlota', + 'Antalya', + 'Yongjing', + 'Tres Marias', + 'Haa', + 'Meerhout', + 'Sibu', + 'Astara', + 'Gar', + 'Ndola', + 'Sao Tiago de Custoias', + 'Karrapur', + 'Chartiers', + 'Songea', + 'Mouila', + 'Streator', + 'Al Qamishli', + 'Nikaweratiya', + 'Delbruck', + 'Batonyterenye', + 'Odzak', + 'Agudos', + 'Gatineau', + 'Vineyard', + 'Saint-Rambert', + 'Kesath', + 'Sugar Grove', + 'Tuensang', + 'Los Reyes de Juarez', + 'Sardinal', + 'Eksjo', + 'Safety Harbor', + 'Kilkenny', + 'Tsiroanomandidy', + 'Agartala', + 'Agrate Brianza', + 'Nomimachi', + 'North Tonawanda', + 'Stafford', + 'Paramoti', + 'Cavdir', + 'Houmt Souk', + 'Domagnano', + 'Kaset Wisai', + 'Piedmont', + 'Nazareth', + 'Anjialava', + 'Stebnyk', + 'Golyaka', + 'Zehdenick', + 'Birstonas', + 'Chaklasi', + 'Carira', + 'Sapatgram', + 'Bankura', + 'Rosignano Marittimo', + 'Quchan', + 'Hoeilaart', + 'Angul', + 'Erechim', + 'Xinshi', + 'Jima', + 'Upper Southampton', + 'Baramula', + 'Joao Neiva', + 'Vanukuru', + 'Shiwan', + 'White Horse', + 'Morong', + 'Frascati', + 'Schrobenhausen', + 'Luvungi', + 'Itirapina', + 'Nari Bhadaun', + 'Tarnaveni', + 'Mytilini', + 'Destrehan', + 'Eybens', + 'Dianga', + 'Pasarkemis', + 'Najafabad', + 'Swiecie', + 'Cobourg', + 'San Jorge', + 'Pfastatt', + 'Kusmaul', + 'Fallersleben', + 'Pershotravensk', + 'Mahambo', + 'Sigli', + 'Annaba', + 'Turku', + 'Pedda Vegi', + 'Mesa Geitonia', + 'Charam', + 'Charentsavan', + 'Imielin', + 'Orvault', + 'Lodz', + 'Sam Ko', + 'Foz', + 'Alexandroupoli', + 'Demmin', + 'Castelleone', + 'Burauen', + 'Capilla del Monte', + 'Ettlingen', + 'Srirangapur', + 'Camamu', + 'Saruhanli', + 'Ferfer', + 'Aurangabad', + 'Taromske', + 'Hinigaran', + 'San Juan de Dios', + 'Saint-Maur-des-Fosses', + 'Bunkyo-ku', + 'Renfrew', + 'Mus', + 'Lake Jackson', + 'Xirdalan', + 'Samayac', + 'Spanish Lake', + 'Izegem', + 'Nema', + 'Dongducheon', + 'Hecelchakan', + 'Seoni', + 'Wood Green', + 'Castelfranco Veneto', + 'Bostanici', + 'Itajiba', + 'Inagi', + 'Oakham', + 'Boa Vista', + 'Puquio', + 'Chittaranjan', + 'Tibro', + 'Pitangueiras', + 'Rouached', + 'Nouakchott', + 'Nuevo San Juan Parangaricutiro', + 'Sao Jose do Campestre', + 'Heyin', + 'Vacaria', + 'Lukavac', + 'Katy', + 'Caibiran', + 'Villasis', + 'Pontianak', + 'Pallijkarani', + 'Rayapalle', + 'San Pedro Carcha', + 'Kabirwala', + 'Idhna', + 'Kiama', + 'Armadale', + 'Braunschweig', + 'Lathasepura', + 'Bajo Boquete', + 'Shal', + 'Balyqshy', + "Long'e", + 'Felgueiras', + 'Arteijo', + 'Dhanaula', + 'Kaoni', + 'Telford', + 'Laukaria', + 'Druskininkai', + 'Sayhat', + 'Skanderborg', + 'Lindome', + 'Paramanandal', + 'Quebrangulo', + 'Bida', + 'Narragansett', + 'Valle Hermoso', + 'Santa Catarina Pinula', + 'Muriedas', + 'Tawnza', + 'Arnouville-les-Gonesse', + 'Ouaoula', + 'Shahrixon', + 'Alcamo', + 'Naujoji Akmene', + 'Pappakurichchi', + 'Toyonaka', + 'Uttukkuli', + 'Ilave', + 'Villupuram', + 'Bhojpur Jadid', + 'Ischia', + 'Rio Verde Arriba', + 'Radolfzell am Bodensee', + 'Llica', + 'Erjie', + 'Qiaomaichuan', + 'Lamont', + 'Bezliudivka', + 'Five Corners', + 'Niksic', + 'Hnivan', + 'Tamale', + 'Khanapur', + 'Ichnia', + 'Sesvete', + 'Reeuwijk', + 'Qutur', + 'Moana', + 'San Pedro Atocpan', + 'Osny', + 'Toda Bhim', + 'Zaouiet Sousse', + 'Lavras', + 'Ouardenine', + 'Katakos', + 'Hetton le Hole', + 'Iseo', + 'Lehigh', + 'Hallim', + 'Bonou', + 'Moita Bonita', + 'Shakargarh', + 'Chiapa de Corzo', + 'Zhanggu', + 'Meudon', + 'Ayikudi', + 'Cunduacan', + 'Jingling', + 'Jiantang', + 'Laojiezi', + 'Bazid Chak Kasturi', + 'Elliniko', + 'Rifu', + 'Duanshan', + 'Busselton', + 'Liubashivka', + 'Maniyur', + 'Singuilucan', + 'Erkrath', + 'Mucari', + 'Tumwater', + 'Yaoquan', + 'Santa Maria Ixhuatan', + 'Sidi Bel Abbes', + 'Namanga', + 'Afsin', + 'An Phu', + 'Bamyan', + 'Mannanchori', + 'Shahr-e Qods', + 'Bierun', + 'Vijapur', + 'Boli', + 'Hirni', + 'Ibitiara', + 'Pachchampalaiyam', + 'Hutto', + 'Talibon', + 'Bilbao', + 'Readington', + 'Pasivedalajimma', + 'Sariaya', + 'Lappersdorf', + 'Jodhpur', + 'Opava', + 'Shelton', + 'Ledegem', + 'Cabedelo', + 'Tiptur', + 'Narsapur', + 'Jamira', + 'Kaufbeuren', + 'Ricany', + 'Ansonia', + 'Mirandopolis', + 'Gondizalves', + 'Brilon', + 'Tarumirim', + 'Leek', + 'Sheopuria', + 'Dongfeng', + 'Pozanti', + 'Fuyingzicun', + 'Sartrouville', + 'Vigonovo', + 'Tatakan', + 'Kountouri', + 'Gharbia', + 'Figuig', + 'Shire', + 'Swabi', + 'Wismar', + 'Chachagui', + 'Nedumudi', + 'Carrickfergus', + 'St. Thomas', + 'Jaicos', + 'Tiruvaduturai', + 'Bolinao', + 'Eumseong', + 'Edina', + 'Essey-les-Nancy', + 'Saint-Julien-en-Genevois', + 'Grosuplje', + 'Grand Haven', + 'Al Faw', + 'Androrangavola', + 'Hassi Maameche', + 'Rubi', + 'Busesa', + 'Villa Tapia', + 'Divo', + 'Benalmadena', + 'Redmond', + 'Rajaori', + 'Kraaipan', + 'Nisporeni', + 'Wandan', + 'Aguia Branca', + 'Lake Park', + 'Hoquiam', + 'Jan Kempdorp', + 'Lentvaris', + 'Waikanae', + 'Reboucas', + "Pomigliano d'Arco", + 'Meycauayan', + 'Saugor', + 'Pasacao', + 'Schinnen', + 'Glan', + 'Lavagna', + 'Betnoti', + 'Ban Wat Sala Daeng', + 'Romsey', + 'Campi Salentina', + 'Glinde', + 'Gamprin', + 'Chandanais', + 'Taiping', + 'Marivorahona', + 'Store', + 'Vardenis', + 'Salima', + 'Kadanadu', + 'Jarqo`rg`on', + 'Barlad', + 'Bethpage', + 'Boscotrecase', + 'Dhamua', + 'Yelm', + 'Tlacotepec', + 'Parame', + 'Haapsalu', + 'Diadi', + 'Huetor Vega', + 'Jozefow', + 'Diessen am Ammersee', + 'Meyrin', + 'Crofton', + 'Galvez', + 'Boulder', + 'Masi-Manimba', + 'Aubervilliers', + 'Unguia', + 'Caslav', + 'El Centro', + 'El Fasher', + 'Beersheba', + 'Hujra Shah Muqim', + 'Bajil', + 'Tomas Oppus', + 'Liancheng', + 'Arkivan', + 'Jasidih', + 'Marturu', + 'Evry', + 'Easttown', + 'Lebedyn', + 'Garhpura', + 'Chinaur', + 'Jean-Rabel', + 'Chichigalpa', + 'Talukkara', + 'Kakuda', + 'Bozoum', + 'Tuzdybastau', + 'Pudimadaka', + 'Iraquara', + 'Blanquefort', + 'Batman', + 'Iserlohn', + 'Castano Primo', + 'Uttaradit', + 'Bartlesville', + 'Sapna', + 'Humpolec', + 'Avanashipalaiyam', + 'Rawajaya', + 'Gadarwara', + 'Mascote', + 'Narkatpalli', + 'Kendale Lakes', + 'White City', + 'Moss', + 'Nnewi', + 'Douar Oulad Aj-jabri', + 'Pata Uppal', + 'Dhiban', + 'Salitre', + 'West Babylon', + 'Khulays', + 'Teplohirsk', + 'Bannu', + 'Mudki', + 'Agar', + 'Al Madad', + 'Chokwe', + 'Udala', + 'Chichli', + 'Lemington', + 'Khatima', + 'Shangrao', + 'Chiriguana', + 'Baliuag', + 'Balua Rampur', + 'Nafplio', + 'Kudat', + 'Cabusao', + 'Acatic', + 'Madougou', + 'Tiszafured', + 'Akurana', + 'Kingston', + 'Pariaman', + 'Seacroft', + 'Tecoman', + 'Alavus', + 'Kanteru', + 'Jaramana', + 'Schodack', + 'Eniwa', + 'Fuzhou', + 'Klobuck', + 'Budhma', + 'Lelydorp', + 'Great Yarmouth', + 'Missoes', + 'Porto Velho', + 'Muhanga', + 'Porto Ingles', + 'Harderwijk', + 'Ubungo', + 'Phopnar Kalan', + 'Chrysoupoli', + 'Zarzis', + 'Nanning', + 'Tekeli', + 'Drammen', + 'Montivilliers', + 'Gualeguay', + 'Nishinomiya-hama', + 'Laguna de Duero', + 'Moraga', + 'Alzano Lombardo', + 'Miki', + 'Janin', + 'Frederico Westphalen', + 'Moulins', + 'Kuningan', + 'Castelnuovo di Porto', + 'Irimbiliyam', + 'Kharar', + 'Cholavandan', + 'Csomor', + 'Amurrio', + 'Tiruchchuli', + 'Steffisburg', + 'Parksville', + 'Anontsibe-Sakalava', + 'Nueva Concepcion', + 'Le Locle', + 'Harsewinkel', + 'Kaonke', + 'Sao Joao Batista', + 'Hokuto', + 'Aubange', + 'Bni Boufrah', + 'Sirmatpur', + 'Gignac-la-Nerthe', + 'Igarata', + 'Kharki', + 'Pamarru', + 'Bhimunipatnam', + 'Perdoes', + 'Qarqaraly', + 'Iisalmi', + 'Koussane', + 'Pittalavanipalem', + 'Tilakpur', + 'Okuchi-shinohara', + 'Alfenas', + 'Mindouli', + 'Chokkalingapuram', + 'Webster', + 'Rorschach', + 'Mascali', + 'Stauceni', + 'Mucaba', + 'Heemskerk', + 'Tari', + 'Bitam', + 'Ullal', + 'Qari Kola-ye Arateh', + 'Brownwood', + 'Santee', + 'Akbarpur', + 'Mega', + 'Motosu', + 'Csorna', + 'Cavarzere', + 'Omallur', + 'Virarajendrapet', + 'Wixom', + 'Murak', + 'Niederkruchten', + 'Aldine', + 'Jalihalli', + 'Batajnica', + 'Bardibas', + 'Madina do Boe', + 'Kallar', + 'Rhennouch', + 'East Providence', + 'Oras', + 'Vittuone', + 'Corbelia', + 'San Pedro Jicayan', + 'Telnal', + 'Parmanpur', + 'Morena', + 'Olindina', + 'Sumpango', + 'Bielsk Podlaski', + 'Mogoditshane', + 'Gulsehir', + 'Kumari', + 'Yantzaza', + 'Ambalavao', + 'Vohitany', + 'Qianxucun', + 'Pragatinagar', + 'Siaya', + 'Pombos', + 'Thuan Tien', + 'Minas de Matahambre', + 'Haaren', + 'Concarneau', + 'Al Marj', + 'Desborough', + 'Brewster', + 'San Miguel Ocotenco', + 'Toba Tek Singh', + 'Quito', + 'Pushkar', + 'Bagasra', + 'Snihurivka', + 'Nsawam', + 'Raonta', + 'Pishbar', + 'Hanamsagar', + 'Lemay', + 'Douliu', + 'Linlithgow', + 'Mamqan', + 'Phulaut', + 'Colwyn Bay', + 'East Leake', + 'Bargara', + 'Phan Rang-Thap Cham', + 'Jouy-le-Moutier', + 'Whyalla', + 'La Rioja', + 'Ferrenafe', + 'Yenmangandla', + "Ben 'Aknoun", + 'Fier', + 'Baharampur', + 'Kin', + 'Staphorst', + 'Gondar', + 'Pantnagar', + 'Barnagar', + 'Campobello di Licata', + 'Rukan', + 'Masatepe', + 'Barroso', + 'Savnik', + 'Huilong', + 'Porto Seguro', + 'Tanjungbalai', + 'Sembedu', + 'Lunenburg', + 'Kampung Tengah', + 'Tatsunocho-tominaga', + 'Oosterwolde', + 'Aver-o-Mar', + 'Poughkeepsie', + 'Anjozorobe', + 'Zengcun', + 'Soavimbahoaka', + 'Warr Acres', + 'Donacarney', + 'Galesburg', + 'Alma', + 'Fuchu', + 'Lehrte', + 'Angelopolis', + 'Ventanas', + 'Barro Alto', + 'Santana do Matos', + 'Patnongon', + 'East Dereham', + 'Tibagi', + 'Rambilli', + 'Punturin', + 'Balzar', + 'Beaufort West', + 'Sendai', + 'Szekszard', + 'Kaizuka', + 'Motatan', + 'Smiths Falls', + 'Litherland', + 'Maisenhausen', + 'Gandara', + 'Ban Mae Kham Lang Wat', + 'Madrid', + 'Pasrur', + 'Shahganj', + 'Escazu', + 'Pakruojis', + 'Shiogama', + 'Kallad', + 'Matinilla', + 'Delemont', + 'Bilga', + 'Kasur', + 'Khattab', + 'Palmi', + 'Sariz', + 'Didymoteicho', + 'Pallippuram', + 'Wagrowiec', + 'Munro', + 'Aschersleben', + 'Ndalatando', + 'Cecchina', + 'Meizichong', + 'Elamattur', + 'Umred', + 'Bonita Springs', + 'Cujubim', + 'Red Oak', + 'Montlouis-sur-Loire', + 'Santa Rosa de Osos', + 'Dehmoi', + 'Pesochin', + 'Sadao', + 'Nagyatad', + 'Khusropur', + 'Klagenfurt', + 'Bou Merdes', + 'Acatenango', + 'Demiryol', + 'Sinnuris', + 'Juazeirinho', + 'Sivakasi', + 'Hunxe', + 'Lamu', + 'Ravensthorpe', + 'Streetsboro', + 'Marugame', + 'Nizampur', + 'Salina', + 'Baglung', + 'Aketao', + 'Schwedt (Oder)', + 'Medrissa', + 'Nordwalde', + 'Rielasingen-Worblingen', + 'Santiago Tianguistenco', + 'Dahuk', + 'Lubutu', + 'Ambohipihaonana', + 'Felino', + 'Kitwe', + 'Langarud', + 'San Rafael Las Flores', + 'Kurwa Mathia', + 'Deuil-la-Barre', + 'Sitampiky', + 'Westchase', + 'Korkut', + 'Aracariguama', + 'Verneuil-sur-Seine', + 'Sucy-en-Brie', + 'Vulcanesti', + 'Berkeley Heights', + 'Suhut', + 'Saratamata', + 'Owk', + 'Holzgerlingen', + 'Neckargemund', + 'Piacenza', + 'Kakkalapalle', + 'Tendo', + 'Atlanta', + 'Kamsar', + 'East Bridgewater', + 'Krizevci', + 'Mandapeta', + 'Kusumha', + 'South Valley', + 'Bhargaon', + 'Birkerod', + 'Olintla', + 'Jiabong', + 'Winona', + 'Ambinanitelo', + 'Tlajomulco de Zuniga', + 'Monument', + 'Matay', + 'Jingping', + 'Gadoon', + 'Yingmen', + 'Bondoukou', + 'Sirpanandal', + 'Materi', + 'Englewood', + 'Nea Moudania', + 'Shanglingcun', + 'Sutton in Ashfield', + 'Maule', + 'Djidja', + 'Long Eaton', + 'Wasco', + 'Satao', + 'Idrija', + 'Catacamas', + 'Oga', + 'Canelli', + 'Seydunganallur', + 'Sidi Ettiji', + 'Civitavecchia', + 'Bouc-Bel-Air', + 'Itapetim', + 'Shizuishan', + 'Ron', + 'San Sebastian Tutla', + 'Lupeni', + 'Buenaventura Lakes', + 'Morsang-sur-Orge', + 'Adamstown', + 'Daraina', + 'Penugonda', + 'Pachkhal', + 'Genemuiden', + 'Supe', + 'Sahri', + 'Ingraj Bazar', + 'Poloros', + 'Chalil', + 'Collecchio', + 'Ipiranga do Piaui', + 'Hove', + 'Ahmadli', + 'Karahalli', + 'Matosinhos', + 'Navalmoral de la Mata', + 'Bialogard', + 'Radcliff', + 'Padakanti', + 'Malasiqui', + 'Mendicino', + 'Fredericksburg', + 'Javanrud', + 'Tegal', + 'Bailesti', + 'Beeston', + 'Huaixiangcun', + 'Puranpur', + 'Manlio Fabio Altamirano', + 'Roddam', + 'Celakovice', + 'El Espinar', + 'Plattling', + 'Juan de Acosta', + 'Sidi Rahal', + 'Zrnovci', + 'Montepuez', + 'Guruvayur', + 'Kouti', + 'Sipalakottai', + 'Vuzenica', + 'Fontenay-le-Comte', + 'Jianshi', + 'Soignies', + 'Tewksbury', + 'Montelupo Fiorentino', + 'Lacin', + 'Kibaha', + 'Minakami', + 'Bedburg', + 'Cuttack', + 'Had Zraqtane', + 'Mandamari', + 'Sadabad', + 'Azhikkal', + 'Huaiyang', + 'Ovruch', + 'Khetia', + 'Monte Azul Paulista', + 'Amparihitsokatra', + 'Luling', + 'Ayaviri', + 'Pekin', + 'Dhihdhoo', + 'Sylacauga', + 'Venkatagiri', + 'Piro', + 'Rasauli', + 'Verde Village', + 'Ostrow Mazowiecka', + 'Bahon', + 'Teixeira Soares', + 'Qasr al Farafirah', + 'Ambohimalaza', + 'Tabuk', + 'Tubungan', + 'Norseman', + 'Fresno', + 'Lingamparti', + 'Burgau', + 'Coatepec Harinas', + 'Haridwar', + 'Itaugua', + 'Cruz del Eje', + 'Hidalgo', + 'Nellaya', + 'Mandishah', + 'Digboi', + 'Darlington', + 'Solim', + 'Kintampo', + 'Rancho Arriba', + 'San Isidro', + 'Atlapexco', + 'Morada Nova de Minas', + 'Dwarka', + 'Ambatofinandrahana', + 'Tha Chang', + 'Wangguanzhuang Sicun', + 'Chatellerault', + 'Benicasim', + 'Norwell', + 'Moanda', + 'Balsamo', + 'Cesson', + 'Mels', + 'Lokbatan', + 'Karlapalem', + 'Otar', + 'Gainrha', + 'Panajachel', + 'Mulhouse', + 'Rafard', + 'Tabora', + 'Barroquinha', + 'Newport East', + 'Smarjeske Toplice', + 'Mallaram', + 'Qutubpur', + 'El Tortuguero', + 'Obernai', + 'Alella', + 'Susquehanna', + 'Caxambu', + 'Sibulan', + 'Kaleyanpur', + 'Asheville', + 'Albal', + 'Seshambe', + 'Sanga', + 'Furstenau', + 'Nea Artaki', + 'Flores', + 'Hualane', + 'Altun Kawbri', + 'McCandless', + 'Essau', + 'Andoany', + 'Navodari', + 'Cherry Creek', + 'Quitilipi', + 'Ermelo', + 'Arco', + 'Rosario del Tala', + 'Ravensburg', + 'Seveso', + 'Puerto Barrios', + 'Lucon', + 'Tadworth', + 'Banzhuangcun', + 'Sinnar', + 'Ladenburg', + 'Changzhou', + 'Futog', + 'Veenoord', + 'Pardes Hanna Karkur', + 'Palhoca', + 'Schaarbeek', + 'Jarabacoa', + 'Nazca', + 'Zurich', + 'Pacoti', + 'Lemmer', + 'Weizhou', + 'Nagpur', + 'Hueyotlipan', + 'Araria', + 'Kulat', + 'Horodenka', + 'Irupi', + 'Cinco Saltos', + 'Bhainsdehi', + 'Wamena', + 'West Haverstraw', + 'Ellon', + 'Fasa', + 'Turkan', + 'Tuzi', + 'Conjeeveram', + 'Imperial Beach', + 'Simria', + 'Golden Valley', + 'Tafas', + 'Hohenbrunn', + 'Harsin', + 'Mulundo', + 'Delaware', + "Sant'Angelo Lodigiano", + 'El Reten', + 'Madukkur', + 'Padalarang', + 'Paraiba do Sul', + 'Toboali', + 'Bagcilar', + 'Dejen', + 'Carthage', + 'Yusufeli', + 'Ponduru', + 'Conceicao dos Ouros', + 'Finnkolo', + 'San Francisco Solano', + 'Vetralla', + 'Kheda', + 'Chauddagram', + 'Vinaroz', + 'Galatge', + 'Bradwell', + 'Orlova', + 'Korostyshiv', + 'San Adrian de Besos', + 'Bernburg', + 'Galatone', + 'Paradip Garh', + 'Kukraun', + 'Bruges', + 'Karuzi', + 'Hemet', + 'Vadnagar', + 'Bernardino de Campos', + 'Pansol', + 'Keystone', + 'Satuba', + 'Weinbohla', + 'Morris', + 'Piazzola sul Brenta', + 'Shalingzicun', + 'Falkensee', + 'Uberlandia', + 'Norco', + 'Narala', + 'Widhwidh', + 'Yahualica', + 'Mokrisset', + 'Bandalli', + 'Nizwa', + 'Seal Beach', + 'Shahpur Chaumukhi', + 'Bhangar', + 'Soldado Bartra', + 'Paratdiha', + 'Esme', + 'Goulmima', + 'Waiyuanshan', + 'Fukagawa', + 'Brookdale', + 'Leiktho', + 'West University Place', + 'Kaarst', + 'Sausar', + 'Pivijay', + 'Paraibuna', + 'Saint Bernard', + 'Ponta Grossa', + 'Ushiku', + 'Greenville', + 'Peduasi', + 'Le Loroux-Bottereau', + 'Sturbridge', + '`Ibri', + 'Bururi', + 'Itarana', + 'Santol', + 'Saint-Amand-Montrond', + 'Palod', + 'Erdenet', + 'Bangramanjeshvara', + 'Schongau', + 'Tirumayam', + 'Barigarh', + 'Kinna', + 'Sarmera', + 'Middlesex', + 'Xixucun', + 'Anatoli', + 'Santa Cruz Naranjo', + 'Tocoa', + 'Cabo San Lucas', + 'Ban Dan Na Kham', + 'Martigny', + 'Morganton', + 'Caseros', + 'Ljubuski', + 'Itzer', + 'Januario Cicco', + 'Derzhavinsk', + 'Timoteo', + 'Cloppenburg', + 'Chirilagua', + 'Ordino', + 'Birsinghpur', + 'Nea Michaniona', + 'Sisophon', + 'Setif', + 'Porto San Giorgio', + 'Lakheri', + 'Gobernador Gregores', + 'Mazapil', + 'Arsikere', + 'Leon Postigo', + 'Ambovombe Afovoany', + 'Corbeil-Essonnes', + 'Ouda-yamaguchi', + 'Schloss Holte-Stukenbrock', + 'Ujjain', + 'Komorowice', + 'Pueblo Juarez', + 'Cookeville', + 'Caombo', + 'Heiligenhafen', + 'Lexington', + 'Maassluis', + 'Allschwil', + 'Ogulin', + 'Galveston', + 'Tepalcatepec', + 'Jericoacoara', + 'Gurupa', + 'Combarbala', + 'Poulton le Fylde', + 'Brandon', + 'Famy', + 'Fenggang', + 'Leping', + 'Recica', + 'Founougo', + 'San Diego', + 'Athar', + 'Teresina', + 'Xinbocun', + 'Piduguralla', + 'Buyukorhan', + "'Ain Merane", + 'Bolvadin', + 'Carpenedolo', + 'Onna', + 'Nalegaon', + 'Grandola', + 'Frondenberg', + 'Hagerstown', + 'Lalmunia Munhara', + 'Shelburne', + 'Boulia', + 'Bni Drar', + 'Courbevoic', + 'Cocieri', + 'Lentate sul Seveso', + 'Claveria', + 'Margny-les-Compiegne', + 'Leoben', + 'Pavugada', + 'Werlte', + 'Turori', + 'Puerto Montt', + 'Hauppauge', + 'Nalas', + 'Daxiang', + 'Polygyros', + 'Asahni', + 'Dzhankoi', + 'Sanliurfa', + 'Motema', + 'Gadag', + 'Negele', + 'Cuevas del Almanzora', + 'David', + 'Singhanakhon', + 'Siwan', + 'Kalush', + 'Carnaubeira da Penha', + 'Odenton', + 'Caldono', + 'Ampahana', + 'Mozzate', + 'Hemer', + 'Barcaldine', + 'Kanan', + 'Itapecerica da Serra', + 'Toftir', + 'Peterhead', + 'Xishancun', + 'Worgl', + 'Hermanus', + 'Derby', + 'Aranda de Duero', + "Aci Sant'Antonio", + 'Fetesti', + 'Masantol', + 'Vyara', + 'Puerto Berrio', + 'Norton', + 'St. Augustine Shores', + 'East Moline', + 'Shahbazpur', + 'Congonhas', + 'Naples', + 'Coromandel', + 'Aguas Zarcas', + 'Ceu Azul', + 'Sabanagrande', + 'Ranti', + 'Palapye', + 'Jitauna', + 'Brejo', + 'Abrisham', + 'Placilla de Penuelas', + 'Worcester', + 'Graneros', + 'Ras el Oued', + 'Tominian', + 'Kamatgi', + 'Tonakkal', + 'Dranesville', + 'Stepnogorsk', + 'Suchteln', + 'Casorate Primo', + 'Lajedo', + 'Chichihualco', + 'Loos', + 'Chust', + 'Winchester', + 'Tifton', + 'Deblin', + 'Armagh', + 'Mahonda', + 'Cheval', + 'Dzitbalche', + 'New Bern', + 'Le Teich', + 'Lamosina', + 'Oatfield', + 'Autazes', + 'Kikuchi', + 'Bni Gmil', + 'Ligonha', + 'Nepi', + 'Vohilengo', + 'Uruburetama', + 'Bajestan', + 'Al Kharj', + 'Cuito', + 'Vadakku Ariyanayakipuram', + 'Itaqui', + 'Cerro', + 'Acajutla', + 'Adjaouere', + 'Christchurch', + 'Miantso', + 'Damaturu', + 'Teluknaga', + 'Shaoyang', + 'Parappukara', + 'Buyukcekmece', + 'Pontefract', + 'Sangju', + 'Posoltega', + 'Longshan', + 'Scottsbluff', + 'Yate', + 'Rossville', + 'Khed', + 'Lokomby', + 'Pocking', + 'Duverge', + 'Mundamala', + 'Arivonimamo', + 'Bhimphedi', + 'Akiruno', + 'Toufen', + 'Civitanova Marche', + 'Chandlers Ford', + 'Titagarh', + 'Bengkalis', + 'Roth', + 'Lugoj', + "Yong'an", + 'Sandusky', + 'Karuvambram', + 'Chambersburg', + 'Perivale', + 'Dayalpur', + 'Gafour', + 'Zeboudja', + 'Bee Cave', + 'El Amria', + 'Agioi Anargyroi', + 'Biberist', + 'Kerikeri', + 'Lequile', + 'DeSoto', + 'Waddan', + 'Sopur', + 'Ambattur', + 'Guayama', + 'Pontes e Lacerda', + 'Vellur', + 'Thebes', + 'Cedarburg', + 'Dzialdowo', + 'Mestrino', + 'Valeggio sul Mincio', + 'San Ignacio', + 'Dafni', + 'Burbach', + 'Milton Keynes', + 'Moman Barodiya', + 'Rantau Prapat', + 'Silver Spring', + 'Goldbach', + 'Bottesford', + 'Peruvancha', + 'Bad Ischl', + 'Olivar Bajo', + 'Shitan', + 'Vohilava', + 'Pinukpuk', + 'Dashao', + 'Pocharam', + 'Daireaux', + 'Putaparti', + 'Eysines', + 'Hasanparti', + 'Gumdag', + 'Chicago Ridge', + 'Quissama', + 'Colonia Leopoldina', + 'General Mamerto Natividad', + 'Steamboat Springs', + 'Walpole', + 'Mockern', + 'Sheboygan', + 'Korolevo', + 'Wichita Falls', + 'Chepes', + 'Airmont', + 'El Geneina', + 'Fruitville', + 'Hernani', + 'Casinhas', + 'Neuried', + 'Ain Aicha', + 'Correntes', + 'Loxstedt', + 'Yakoma', + 'Aqtau', + 'Aubenas', + 'Cedar Mill', + 'Drensteinfurt', + 'Bankheri', + 'Comarnic', + 'San Ignacio de Moxo', + 'Kattagan', + 'Podcetrtek', + 'Armenia', + 'Albina', + 'Ferraz de Vasconcelos', + 'Kibawe', + 'Navegantes', + 'Panna', + 'Sebt Ait Saghiouchen', + 'Nuevo Arraijan', + 'Milicz', + 'Alleppey', + 'Mondlo', + 'Tallmadge', + 'Birni', + 'Langrucun', + 'Maria Enzersdorf', + 'Birdaban', + 'Kalingalan Caluang', + 'Ormond Beach', + 'Pontedera', + 'Jilava', + 'Guduru', + 'Ashikita', + 'Port Antonio', + 'Termini Imerese', + 'Stranraer', + 'Muheza', + 'Sonapur', + 'Rothenburg ob der Tauber', + 'De Doorns', + 'Libreville', + 'Vargaur', + 'Madona', + 'Kirlampudi', + 'Usworth', + 'Ichchapuram', + 'Groairas', + 'Raipura', + 'Thanesar', + 'Gracanica', + 'Bukkarayasamudram', + 'Brunico', + 'Spremberg', + 'Sidi El Hattab', + 'Imeni Chapayeva', + 'Tandwa', + 'Ap Khanh Hung', + 'Bagulin', + 'Ziyodin Shaharchasi', + 'Catanzaro', + 'Kavak', + 'Nalchiti', + 'Pannaikkadu', + 'Vysoke Myto', + 'Punnappatti', + 'Kanchika', + 'Sibut', + 'Marblehead', + 'Mayenne', + 'Concepcion Huista', + 'Birch Bay', + 'Mulakaluru', + 'Lynchburg', + 'Titay', + 'Trou du Nord', + 'Murraysville', + 'Kalladai', + 'Ipoh', + 'Santa Maria Chilchotla', + 'Wervik', + 'Casa de Oro-Mount Helix', + 'Jamnagar', + 'Caotan', + 'Dewsbury', + 'La Pintana', + 'Betong', + 'Jhundo', + 'Saint-Gregoire', + 'Channarayapatna', + 'Lennestadt', + 'Bir Kasdali', + 'Kissidougou', + 'Palghat', + 'Winterberg', + 'San Jose Tenango', + 'Mays Chapel', + 'Barreiro', + 'Latakia', + 'Loudeac', + 'Periyapodu', + 'Bad Schussenried', + 'Himeji', + 'Ulaan-Uul', + 'Qormi', + 'Wamba', + 'Bovolone', + 'Limavady', + 'Kara-Bak', + 'Wilrijk', + 'Bissegem', + 'Richmond', + 'Quzhou', + 'Chamarru', + 'Arhavi', + 'Tartus', + 'Mboki', + 'Gramsh', + 'Jizhuang', + 'Capitola', + 'Ashby de la Zouch', + 'Saga', + 'Mage', + 'Manvi', + 'Baud', + 'Hincesti', + 'Santiago Sacatepequez', + 'Astley', + 'Moramanga', + 'Le Mars', + 'Mahinathpur', + 'Fort Mohave', + 'Turda', + 'Kadiolo', + 'Kannan', + 'Grossenkneten', + 'Tsiately', + 'Zhipingxiang', + 'Al `Amarah', + 'Florestopolis', + 'Mazara del Vallo', + 'Antonivka', + 'Laconia', + 'Bouka', + 'Vemulanarva', + 'Budakalasz', + 'Kelkheim (Taunus)', + 'Ventania', + 'Castanos', + 'Ganzhou', + 'Lauingen', + 'Borbon', + 'Lodwar', + 'Ober-Ramstadt', + 'Qardho', + 'Kathevaram', + 'Colorado', + 'Sierra Vista', + 'Walnut Creek', + 'Tainan', + 'Guaraciaba', + 'Beni Hassane', + 'Tabuse', + 'Isfisor', + 'Long Beach', + 'Mahraurh', + 'Langerwehe', + 'An', + 'Nueve de Julio', + 'Kastamonu', + 'Harmanli', + 'Welver', + 'Binisalem', + "Imi n'Oulaoun", + 'Lizzanello', + 'Itapema', + 'Colon', + 'Andolofotsy', + 'Ilafy', + 'Chivasso', + 'Al Ghayzah', + 'Weno', + 'Hostotipaquillo', + 'Talugai', + 'Tomohon', + 'Saint-Remy-de-Provence', + 'Takikawa', + 'Ramgundam', + 'Shamaldy-Say', + 'Buram', + 'Curtea de Arges', + 'Labo', + 'Chahatpur', + 'Upington', + 'Andorinha', + 'Saymayl', + 'Nkheila', + 'Lindi', + 'Rio Tercero', + 'Grevena', + 'Peschiera del Garda', + 'Las Terrenas', + 'Holzwickede', + 'Mallet', + 'Ambara', + 'San Gregorio di Catania', + 'Chiramba', + 'Marudi', + 'Donji Kakanj', + 'Strand', + 'Azzano Decimo', + 'San Remo', + 'Brasschaat', + 'Barokhar', + 'Torghay', + 'Soledad', + 'Alfredo Chaves', + 'Dongsheng', + 'Enumclaw', + 'Bouafle', + 'Navotas', + 'Ambohitoaka', + 'Marotandrano', + 'Sao Miguel do Tapuio', + 'Wevelgem', + 'Pio XII', + 'Vigodarzere', + 'Gargzdai', + 'Rennes', + 'Lucala', + 'Piney Green', + 'Stokke', + 'Al `Ayyat', + 'Agoura Hills', + 'Akabira', + 'Cabiao', + 'Sevilla de Niefang', + 'Coconuco', + 'Yaxley', + 'Morondava', + 'Francistown', + 'Shush', + 'Papillion', + 'Morawa', + 'Halstead', + 'Lower Pottsgrove', + 'Rende', + 'Opelika', + 'Tanakpur', + 'Bolsward', + 'Majene', + 'Tullinge', + 'Ifield', + 'Calumpit', + 'Brajarajnagar', + 'Laon', + 'Tamagawa', + 'Avcilar', + 'Manikpur', + 'Portet-sur-Garonne', + 'East Chicago', + 'Reddiyapatti', + 'Bananal', + 'Somero', + 'Sabara', + 'Ragay', + 'Cupertino', + 'Kuala Pembuang', + 'Andranomamy', + 'Kavar', + 'Gommern', + 'Oxelosund', + 'Cheraro', + 'Repala', + 'Sannar', + 'Blaj', + 'Clemmons', + 'Kakarati', + 'Valenciennes', + 'Batad', + 'Kyeintali', + 'Mengjiacun', + 'Agdz', + 'Ula', + 'Parede', + 'Buguias', + 'Palleja', + 'Urubamba', + 'Bobbili', + 'Damalcheruvu', + 'Wantagh', + 'Wailuku', + 'La Piedad', + 'Texarkana', + 'Isangel', + 'Rosario', + 'Tublay', + 'Zapote', + 'Albox', + 'Kandulapuram', + 'Vrindavan', + 'Amudalapalle', + 'Cabo Rojo', + 'Sternberk', + 'Telde', + 'Kreuzlingen', + 'Dudu', + 'Vouzela', + 'Hullatti', + 'Yellandu', + 'Suzaka', + 'Ouled Abbes', + 'Ankilizato', + 'Pocklington', + 'Lescar', + 'Belgrave', + 'Az Zabadani', + 'Battambang', + 'Lehigh Acres', + 'Magurele', + 'Kato', + 'Bailin', + 'Kobarid', + 'Aketi', + 'Pokrovske', + 'Pecica', + 'Coringa', + 'Dosemealti', + 'Oued Amlil', + 'Gaotan', + 'Warburg', + 'Virgem da Lapa', + 'Amdjarass', + 'Duijiang', + 'Bagado', + 'Pujali', + 'Nan', + 'Ibrahimpatan', + 'Tornio', + 'Mount Vista', + 'Sanso', + 'Nam Dinh', + 'Martinsburg', + 'Eshkanan', + 'Maringa', + 'Alamosa', + 'Suzzara', + 'Portachuelo', + 'Vempalle', + 'San Antonio La Paz', + 'Stafa', + 'Basey', + 'Sabaudia', + 'Veliki Preslav', + 'West Manchester', + 'Weissenburg', + 'Le Havre', + 'Togamalai', + 'Omitama', + 'Bihariganj', + 'Redange-sur-Attert', + 'Saint-Chamond', + 'Anklam', + 'Perwez', + 'Qivraq', + 'Chieti', + 'Gossau', + 'Tutzing', + 'Bacaadweyn', + 'Kohat', + 'Durbuy', + 'Clarence', + 'Olesno', + 'Uberaba', + 'Andorra la Vella', + 'Ranong', + 'Meshgin Shahr', + 'Senigallia', + 'Siahkal', + 'Apatin', + 'West Park', + 'Fallsburg', + 'Bom Lugar', + 'Chassieu', + 'Chauki Hasan Chauki Makhdum', + 'Hejamadi', + 'Santa Maria do Para', + 'Al Jumayliyah', + 'Harij', + 'Reedley', + 'Wafangdian', + 'Suzak', + 'Hirekerur', + 'Muar', + 'Xarardheere', + 'Tando Muhammad Khan', + 'Uchturpan', + 'Kalba', + 'Clearlake', + 'Aulendorf', + 'Parur', + 'Joanopolis', + 'Belagola', + 'Chapeltown', + 'Shildon', + 'Uruoca', + 'Gevelsberg', + 'Hindoria', + 'Przasnysz', + 'Vigasio', + 'Alamedin', + 'Namrup', + 'Luenoufla', + 'Teofilo Otoni', + 'Gopalapuram', + 'Shahhat', + 'Mesagne', + 'Maisaka', + 'San Pedro Nonualco', + 'Panevezys', + 'Quibor', + 'Frutal', + 'Casa Branca', + 'Furukawamen', + 'Presidente Vargas', + 'Vadugappatti', + 'Nefta', + 'Maipu', + 'Opa-locka', + 'Maidstone', + 'Santo Tomas La Union', + 'Wheeling', + 'Kamakhyanagar', + 'Rozzano', + 'Boljoon', + 'Aconibe', + 'Huzhou', + 'Kongolo', + 'Tacloban', + 'Escalante', + 'Wadowice', + 'Machala', + 'Lagonoy', + 'Carnaubais', + 'Lubuk Sikaping', + 'Yupiltepeque', + 'Gwoza', + 'Padilla', + 'Dhari', + 'Refahiye', + 'Sevierville', + 'Fellbach', + 'Raub', + 'Plaine du Nord', + 'Tepexi de Rodriguez', + 'Garango', + 'Nakapiripirit', + 'Grosse Pointe Park', + 'Aerzen', + 'Lingcheng', + 'Mogliano Veneto', + 'Wiesloch', + 'Tokatippa', + 'Bezou', + 'Bela', + 'Wahlstedt', + 'Huichang', + 'Raghudebbati', + 'El Sobrante', + 'Badarpur', + 'Nakskov', + 'Kurwar', + 'Siquinala', + 'Berga', + 'Jamalpur', + 'Sidi Taibi', + 'Crema', + 'Tharad', + 'Colomba', + 'Marostica', + 'Temiskaming Shores', + 'Karwar', + 'Pallavaram', + 'Dokolo', + 'Nawai', + 'Cullman', + 'Waldkraiburg', + 'Yoichi', + 'Nizip', + 'Litomysl', + 'Huong Canh', + 'Appenweier', + 'Gimbi', + 'Hulst', + 'Beshkent Shahri', + 'Ban Wat Lak Hok', + 'San Martin De Porres', + 'Chuy', + 'Fallon', + 'Domerat', + 'Ruggell', + 'Subang', + 'Kapalong', + 'Shahrak-e Enqelab', + 'Finneytown', + 'Casamassima', + 'Forks', + 'Silvassa', + 'Pharr', + 'Ait Bouziyane', + 'Sirari', + 'Saint-Etienne', + 'Halol', + 'Aregua', + 'Calatagan', + 'Palmas', + 'Milajerd', + 'Ar Riqqah', + 'Waghausel', + 'Tlaxcala', + 'Pellezzano', + 'Segovia', + 'Villeneuve-les-Maguelone', + 'Narrogin', + 'Vila Pouca de Aguiar', + 'Madagh', + 'Tanambe', + 'Rheinau', + 'Tsubame', + 'Kozluk', + 'El Ghaziye', + 'Ciudad Insurgentes', + 'Zuchwil', + 'Shangzhou', + 'Morton', + 'Ieper', + 'Hefei', + 'Qiryat Ono', + 'West Vero Corridor', + 'Rumonge', + 'Suohe', + 'Juprelle', + 'Airmadidi', + 'Pecel', + 'Pa Sang', + 'Phra Nakhon Si Ayutthaya', + 'Castrolibero', + 'Koprivnica', + 'Formiga', + 'Petatlan', + 'Xuanzhou', + 'Navirai', + 'Weilburg', + 'Belgaum', + 'Sovetskoe', + 'Mwaline al Oued', + 'Fort-de-France', + 'Belkheir', + 'Sarapiqui', + 'Manandona', + 'Ernagudem', + 'Dunaivtsi', + 'Perama', + 'Eastmont', + 'Zeerust', + 'Sao Miguel', + 'La Crescenta-Montrose', + 'Kardzhali', + 'Faisalabad', + 'Asan', + 'Trenton', + 'Kuttyattur', + 'Ban Thap Kwang', + 'Sahtah', + 'Tila', + 'Ait Tamlil', + 'Tomball', + 'Pathiyanikunnu', + 'Markdorf', + 'Kitakami', + 'Zacatecoluca', + 'Thouars', + 'Belem', + 'Albuquerque', + 'Veenendaal', + 'Namutumba', + 'Chalette-sur-Loing', + 'Shilan', + 'Consolacion', + 'Brahmanpara', + 'Pola de Lena', + 'Gislaved', + 'Arlesheim', + 'Inuma', + 'Royton', + 'Sawadah', + 'La Magdalena Tlaltelulco', + 'Wenlan', + 'Portoviejo', + 'Jaguarao', + 'Atlit', + 'Yellareddi', + 'Chima', + 'Ribnica', + 'Loves Park', + 'Vera Cruz', + 'Sape', + 'Alauli', + 'Antargangi', + 'DeForest', + 'Lethbridge', + 'Fuerte Olimpo', + 'Kiskunlachaza', + 'Mahagama', + 'Ulubey', + 'Cacimba de Dentro', + 'Thames', + 'Junqueiropolis', + 'Ganeshpur', + 'Avrille', + 'Guediawaye', + 'Flores de Goias', + 'Nevele', + 'Osisioma', + 'Valtoha', + 'Alfonso Castaneda', + 'Embu-Guacu', + 'Ballia', + 'Elmont', + 'Adampur', + 'Montalto Uffugo', + 'Locate di Triulzi', + 'Jinju', + 'Xenia', + 'Douar Jwalla', + 'Zanzibar', + 'Ansbach', + 'Cafarnaum', + 'Riacho de Santana', + 'Magburaka', + 'Hampton', + 'Kumo', + 'Adana', + 'Salisbury', + 'Begoro', + 'Rehlingen-Siersburg', + 'Tambulig', + 'Howli', + 'Port Hueneme', + 'Saire', + 'Lishanpu', + 'Mykhailivka', + 'Xiazhai', + 'Sochaczew', + 'Minbya', + 'Vienne', + 'Shegaon', + 'Hajnowka', + 'Alberobello', + 'Karatas', + 'Nyamti', + 'Tatarikan', + 'Puqiancun', + 'Andrews', + 'Kraluv Dvur', + 'Calnali', + 'Anna Regina', + 'Voss', + 'Rietberg', + 'Baracoa', + 'Caglayancerit', + 'Larkhall', + 'Fairwood', + 'Sardoba', + 'Beni Fouda', + 'Lakshminarayanapuram', + 'Kandy', + 'Pigcawayan', + 'Yuchengcun', + 'Barru', + 'Wulflingen', + 'Koktokay', + 'Santa Rosa de Cabal', + 'Ramona', + 'Rucphen', + 'Jinghai', + 'Twist', + 'Alberdi', + 'Izola', + 'Bom Jardim', + 'Benito Juarez', + 'Grinon', + 'Mundgod', + 'Manito', + 'Ban Tha Luang Lang', + 'Colesberg', + 'Hinche', + 'Sidmant al Jabal', + 'Vilnius', + 'Mount Laurel', + 'Dyero', + 'Madari Hat', + 'Patian', + 'Guimbal', + 'Linnei', + 'Astaneh-ye Ashrafiyeh', + 'Delfzijl', + 'Walla Walla', + 'Saint-Louis du Sud', + 'Shilou', + 'Puchov', + 'Trossingen', + 'Spring Valley', + 'May Pen', + 'Hadleigh', + 'Hoffman Estates', + 'Hirschaid', + 'Dorridge', + 'Ampohibe', + 'Amapa', + 'Temirtau', + 'Lakhsetipet', + 'Raeren', + 'Liffre', + 'Hassi Fedoul', + 'West Grey', + 'Jaggayyapeta', + 'Akita', + 'Burien', + 'Kranjska Gora', + 'Urla', + 'Apapa', + 'Tucano', + 'Stouffville', + 'Bayt Ummar', + 'Chamrajnagar', + 'Cagwait', + 'Sorada', + 'Saoula', + 'Cavan Monaghan', + 'Somotillo', + 'Kabarnet', + 'Ash Shatrah', + 'Forest Hill', + 'Colleyville', + 'Nzega', + 'Kaufering', + 'Bikou', + 'Ksar Sbahi', + 'Muramvya', + 'Impfondo', + 'Dalachi', + 'Janze', + 'Baruun-Urt', + 'Scornicesti', + 'Caem', + 'Darayya', + 'Foya Tangia', + 'Robertsville', + 'Ban Ho Mae Salong', + "Bi'r al `Abd", + 'Giyani', + 'Dhamar', + 'Bni Frassen', + 'Brownhills', + 'Buckie', + 'Majagua', + 'Gainsborough', + 'Ayotoxco de Guerrero', + 'East Milton', + 'Sanchi', + 'Pogradec', + 'Yurimaguas', + 'Xingyi', + 'Tripunittura', + 'Lady Lake', + 'Safotu', + 'Gabu', + 'Pitt Meadows', + 'Sahalanona', + 'Vilaseca de Solcina', + 'Shinjuku', + 'Phnom Penh', + 'Espumoso', + 'Tiantoujiao', + 'Haukipudas', + 'Cuilapan de Guerrero', + 'Bafoussam', + 'Sunjiayan', + 'Bhanpura', + 'Sarangapuram', + 'Frontera', + 'Roh', + 'Prince Albert', + 'San Bernardino', + 'Maranello', + 'Ales', + 'Shenley Brook End', + 'Morayra', + 'Maba', + 'Pelileo', + 'Majiadiancun', + 'Broadstone', + 'Eski-Nookat', + 'Axapusco', + 'Najasa', + 'Iuiu', + 'Morieres-les-Avignon', + 'Capilla del Senor', + 'Amarante', + 'Bretigny-sur-Orge', + 'Jhaua', + 'Deulgaon Mahi', + 'Waterbury', + 'Euriapolis', + 'Thika', + 'Rothrist', + 'Tinja', + 'Umarizal', + 'Vihari', + 'Tepatlaxco', + 'Tan Son', + 'Anjangoveratra', + 'Yelimane', + 'Poulsbo', + 'Hutchinson', + 'Ittikelakunta', + 'Villena', + 'Mositai', + 'Roi Et', + 'Tulsipur', + 'Munhall', + 'Staufen im Breisgau', + 'Ciudad Hidalgo', + 'Naama', + 'Vratsa', + 'Sales Oliveira', + 'Xingtai', + 'Monteriggioni', + 'Grey Highlands', + 'Camoluk', + 'Ochsenhausen', + 'Winnenden', + 'Bogen', + 'Ambinanisakana', + 'Rolla', + 'New Philadelphia', + 'Varzelandia', + 'Can Tho', + 'Tepetlixpa', + 'Gursarai', + 'Grumo Appula', + 'Rudraprayag', + 'Kelheim', + 'Pionki', + 'Kedavur', + 'Frankfort', + 'Bishamagiri', + 'Shingbwiyang', + 'Montes Altos', + 'Longtangwan', + 'Veszprem', + 'Vadnais Heights', + 'Pozarevac', + 'Zyrardow', + 'Nis', + 'Julianadorp', + 'Beigang', + 'Wuhuang', + 'Ambalakindresy', + 'Yeosu', + 'Hisar', + 'Chithara', + 'Caldwell', + 'San Remigio', + 'Budamangalam', + 'Tamani', + 'Shetpe', + 'Velyki Luchky', + 'Jaramijo', + 'East Finchley', + 'Siedlce', + 'Tadigadapa', + 'Umuahia', + 'Jalgaon', + 'Schneeberg', + 'Chilonga', + 'Zhdanivka', + 'Bananeiras', + 'Nasaud', + 'Karlsdorf-Neuthard', + 'Culemborg', + 'Luanco', + 'Analamary', + 'Hinabangan', + 'Borgomanero', + 'Don Sak', + 'Newark', + 'Salqin', + 'Tafersit', + 'Siyang', + 'Goussainville', + 'Cermenate', + 'Gurlapeta', + 'Kiri', + 'Luis Gomes', + 'Partizanske', + 'Puducherry', + 'Strzegom', + 'Sai Mai', + 'Petlawad', + 'Vicenza', + 'Debbache el Hadj Douadi', + 'Amarpura', + 'Val-des-Monts', + 'Haicheng', + 'Kempton Park', + 'Raspur Patasia', + 'Killimangalam', + 'Thanatpin', + 'Oji', + 'Neno', + 'Kato Polemidia', + 'Anapurus', + 'Shakiso', + 'Diepholz', + 'Altrincham', + 'Nowa Ruda', + 'Sirnak', + 'Pettaivayttalai', + 'Schmelz', + 'Velur', + 'Wolverton', + 'Goygol', + 'Groesbeek', + 'Kannavam', + 'Bujumbura', + 'Ihorombe', + 'Hasami', + 'Revur', + 'Nosiarina', + 'Ciudad Guayana', + 'Economy', + 'Rayachoti', + 'Naciria', + 'Rompicherla', + 'Fairbanks', + 'Timbio', + 'Santo Amaro', + 'Vares', + 'Mafeteng', + "G'oliblar Qishlog'i", + 'Kumul', + 'Kline', + 'Alampur', + 'Moda', + 'Lhasa', + 'Sirhali Kalan', + 'Lower Providence', + 'Fuengirola', + 'Naigarhi', + 'Cottonwood Heights', + 'Aldeias Altas', + 'Sibinal', + 'Sulaco', + 'Pintuyan', + 'Sombrio', + 'Negrete', + 'Tsau', + 'Casa Nova', + 'Garupa', + 'Pencheng', + 'Langnau', + 'Gokinepalle', + 'General Conesa', + 'Bandamurlanka', + 'Morarano-Gara', + 'Tartu', + 'Hombrechtikon', + 'Wegberg', + 'Argelia', + 'Neubrandenburg', + 'Bardmoor', + 'Benipati', + 'Saint-Laurent-de-la-Salanque', + 'Sungai Penuh', + 'Iklod', + 'Alem Paraiba', + 'Uitgeest', + 'Kiranur', + 'Tinambac', + 'Ait Yaich', + 'Teniet el Abed', + 'Middlesex Centre', + 'Grand-Bassam', + 'Redhill', + 'Zhaotong', + 'Mohammad Shahr', + 'Cranendonck', + 'Vanzago', + 'Wiener Neustadt', + 'Telavi', + 'Fonte Boa', + 'Svalyava', + 'Valea Lupului', + 'Kitale', + 'Campos Gerais', + 'Dayr as Sanquriyah', + 'Atmakur', + 'Boynton Beach', + 'Can', + 'Kalongo', + 'Bad Voslau', + 'Trutnov', + 'Sunagawa', + 'Bandarbeyla', + 'San Pedro Ixtlahuaca', + 'Lonquimay', + 'Kangal', + 'Bornem', + 'Luanza', + 'Tacurong', + 'Totteridge', + 'Kumcati', + "Saint George's", + 'Uttoxeter', + 'Neath', + 'Cairns', + 'Kelkit', + 'Banlung', + 'Minneola', + 'Nedre Eiker', + 'Vembaditalam', + 'Ramanayyapeta', + 'New Ross', + 'Szamotuly', + 'Lapao', + 'Sakkamapatti', + 'Anjuna', + 'Lower Southampton', + 'Uch-Korgon', + 'Salovci', + 'Bhawanigarh', + 'Venceslau Bras', + 'Hosahalli', + 'Sibsagar', + 'Pazarcik', + 'Grigoriopol', + 'Shencottah', + 'Trenque Lauquen', + 'Oak Hills', + 'Magangue', + 'Beharona', + 'Hirakawacho', + 'Katsuura', + 'Belpukur', + 'Xingang', + 'Topoloveni', + 'Auxerre', + 'Caba', + 'Amioun', + 'Lake Oswego', + 'Nicoya', + 'Piprai', + 'Takhemaret', + 'Jula Buzarg', + 'Nam Som', + 'Wad Medani', + 'Dubasari', + 'Ricaurte', + 'Kocevje', + 'Torit', + 'Kanamadi', + 'Tasso', + 'Hermiston', + 'Seven Hills', + 'Ahmed Rachedi', + 'Maryville', + 'Lunen', + 'Marondry', + 'Ridgewood', + 'Chajul', + 'Norosi', + 'Amatitlan', + 'Williamstown', + 'Uliastay', + 'Lorsch', + 'Tekkekara', + 'Manisa', + 'Piatra Neamt', + 'Serta', + 'Padarti', + 'Agaro', + 'Boa Vista do Tupim', + 'Hariana', + 'Kobayashi', + 'Jessup', + 'Chahe', + 'Bournemouth', + 'Anajatuba', + 'Tugatog', + 'Vavur', + 'Ksar el Boukhari', + 'Masku', + 'Sungandiancun', + 'Candoni', + 'Mori', + 'Saint-Omer', + 'Alhaurin el Grande', + 'Atasu', + 'Rodos', + 'Bordj el Bahri', + 'Iheddadene', + 'Golden Hills', + 'Vista', + 'Cabrican', + 'Guara', + 'Sendarappatti', + 'Djouab', + 'Altea', + 'Omagari', + 'Firou', + 'Guinguineo', + 'Poytug`', + 'Chennamangalam', + 'Ramantali', + 'Penonome', + 'Tindivanam', + 'New River', + 'Pedda Tumbalam', + 'Hendersonville', + 'East Ridge', + 'The Colony', + 'Velizy-Villacoublay', + 'Koheda', + 'Ouaregou', + 'Sint-Truiden', + 'Zonnebeke', + 'Cartersville', + 'Serro', + 'Smorumnedre', + 'Sebt Bni Garfett', + 'Budhlada', + 'Malmesbury', + 'Kranj', + 'Union de San Antonio', + 'Batu Pahat', + 'Lian', + 'Baldeogarh', + 'Katsushika-ku', + 'Kiho', + 'Decines-Charpieu', + 'Jangy-Nookat', + 'Mudgal', + 'Pocoes', + 'Nanping', + 'Mota', + 'Maoussa', + 'Wolnzach', + 'Deysbrook', + 'Bad Essen', + 'Edogawa', + 'Cromer', + 'Brejetuba', + 'Wasilkow', + 'Beni Rached', + 'Balch Springs', + 'Folsom', + 'Nakonde', + 'Priboj', + 'Sigma', + 'Monywa', + 'Raismes', + 'Patut', + 'Kangar', + 'Kostrzyn', + 'Settsu', + 'Nandongcun', + 'Moosburg', + 'Vohitrandriana', + 'Sidi Bou Othmane', + 'Had Sahary', + 'Prescott Valley', + 'Burghausen', + 'Meco', + 'Bourbonnais', + 'San Maurizio Canavese', + 'Tequixquiac', + 'Wanyuan', + 'Hungund', + 'Huambo', + 'Sopelana', + 'Madaoua', + 'Mottola', + 'North Valley Stream', + 'Schaafheim', + 'Mataas Na Kahoy', + 'Maracay', + 'Deh Bakri', + 'Turkistan', + 'Spiesen-Elversberg', + 'Lansdale', + 'Sinha', + 'Haddonfield', + 'Mechanicstown', + 'San Vicente del Caguan', + 'Middleburg Heights', + 'New Lenox', + 'Mehlville', + 'Ambalakirajy', + 'Tak', + 'Willemstad', + 'Yato', + 'Carbondale', + 'Wakiso', + 'Farsala', + 'Gudarah', + 'Dorchester', + 'Ban Pang Mu', + 'Mosgiel', + 'Grafing bei Munchen', + 'Domkonda', + 'Challans', + 'Sulmona', + 'Ayirurpara', + 'Kaman', + 'Kumaramangalam', + 'Jiaojiazhuang', + 'Kelsterbach', + 'Saratoga', + 'Haledon', + 'Apodi', + 'Kuchinda', + 'Slidell', + 'Miamisburg', + 'Ponmana', + 'Icatu', + 'Oliva', + 'Cliza', + 'Ellenabad', + 'Pikit', + 'Fengning', + 'Erbaa', + 'Koraput', + 'Bhiloda', + 'Thenia', + 'Chinoz', + 'Zaysan', + 'Sarmastpur', + 'Lerici', + 'Wachtberg', + 'Kunjatturu', + 'Mzimba', + 'Oficina Maria Elena', + 'Paco do Lumiar', + 'Swansea', + 'Showt', + 'Batroun', + 'El Hadjar', + 'Childwall', + 'Xekong', + 'Anta', + 'Khem Karan Saray', + 'Panruti', + 'Yatton', + 'Avalpundurai', + 'Kudayattur', + 'Al Miqdadiyah', + 'Humanes de Madrid', + 'Tako', + 'As Sa`diyah', + 'Santana do Livramento', + 'Terrebonne', + 'Caninde de Sao Francisco', + 'Dombachcheri', + 'Podlehnik', + 'Andergrove', + 'Mima', + 'San Vendemiano', + 'Kindi', + 'Mengdingjie', + 'Xindi', + 'Kembhavi', + 'Verden', + 'Tarboro', + 'Manga', + 'Santa Rosa Jauregui', + 'Eiras', + 'Sapporo', + 'Puerto Octay', + 'Bothell West', + 'Almolonga', + 'Asperg', + 'Nanchong', + 'Honnali', + 'Orange City', + 'Ommangi', + 'Marilia', + 'Tobyl', + 'Coatesville', + 'Laualagaon', + 'Chinacota', + 'Breuillet', + 'Sinnamary', + 'Sun Lakes', + 'Tandur', + 'La Uruca', + 'Ann Arbor', + 'Boumerdes', + 'Cizre', + 'Bicheno', + 'Ebersberg', + 'Diangoute Kamara', + 'Havanur', + 'Barra Mansa', + 'Santa Margherita Ligure', + 'Bruchhausen-Vilsen', + 'Daet', + 'Dumai', + 'Lanta', + 'Cahama', + 'Rajgadh', + 'Kapurthala', + "Sidi Smai'il", + 'Bir el Ater', + 'Yesilkoy', + 'Yanshuiguan', + 'Arantangi', + 'Gaza', + 'Alajarvi', + 'Kondalahalli', + 'Salmanshahr', + 'Campo Maior', + 'Lago Vista', + 'Savignano sul Panaro', + 'Nong Kung Si', + 'Barnia', + 'Puttige', + 'Bracebridge', + 'Hipparga', + 'Bramsche', + 'Yangi Mirishkor', + 'Kimyogarlar', + 'Khemis el Khechna', + 'Maizieres-les-Metz', + 'Beyneu', + 'Eden Isle', + 'South Burlington', + 'Ramnagar Farsahi', + 'Vught', + 'Hexiwu', + 'Bhatpalli', + 'Kokoszki', + 'Rocky Mount', + 'Ano Syros', + 'Lutayan', + 'Ridgecrest', + 'Ranpur', + 'Ituango', + 'Kapelle-op-den-Bos', + 'Ladol', + 'Ambalabe', + 'Taramangalam', + 'Kumanovo', + 'Funyan Bira', + "Itaporanga d'Ajuda", + 'Samana', + 'Nij Khari', + 'Kafr Nabudah', + 'Dombasle-sur-Meurthe', + 'Jurbise', + 'Ciudad del Carmen', + 'Toon', + 'Big Spring', + 'Talpa de Allende', + 'Hinton', + 'Araouane', + 'Morungaba', + 'Stolac', + 'Lobez', + 'Toulon', + 'San Cesareo', + 'Three Lakes', + 'Jacareacanga', + 'Marne', + 'Fredericia', + 'Convencion', + 'Tarquinia', + 'Tepe-Korgon', + 'El Ghiate', + 'Tashkent', + 'Kirchlengern', + 'Roseau', + 'Nahan', + 'Givors', + 'Ikom', + 'Bumpe', + 'Shirhatti', + 'Reggiolo', + 'San Blas', + 'Cholet', + 'Dhirwas', + 'Bata', + 'Taito', + 'Jind', + 'Sahil', + 'La Fleche', + 'Ardakan', + 'Batangafo', + 'Kaza', + 'Bac', + 'Rio Jimenez', + 'Caycuma', + 'Kippax', + 'Denyekoro', + 'Ganganagar', + 'Mahalpur', + 'Sarpavaram', + 'Punarakh', + 'Cessnock', + 'San Fausto de Campcentellas', + 'Scandicci', + 'Valle Vista', + 'Manaoag', + 'Noe', + 'Penha', + 'Couvin', + 'Bakun', + 'Porto Uniao', + 'Bolanos de Calatrava', + 'Sun City West', + 'Orzinuovi', + 'Carrara', + 'Tilhar', + 'Prudentopolis', + 'Ciudad Real', + 'Ermont', + 'Sulop', + 'Brive-la-Gaillarde', + 'El Estor', + 'Tirschenreuth', + 'Foum el Anser', + 'Ban Pong Yaeng Nai', + 'Lissegazoun', + 'Gucheng', + 'Louth', + 'Minamiise', + 'Janow Lubelski', + 'Zacualpan', + 'Bobrynets', + 'Bel Imour', + 'El Valle del Espiritu Santo', + 'Vodiriana', + 'Ad Dujayl', + 'Puerto La Cruz', + 'Cadiz', + 'Basse Santa Su', + 'Longuenesse', + 'Kalamula', + 'Ponca City', + 'Lebowakgomo', + 'Chittandikavundanur', + 'Villarrobledo', + 'Settivaripalle', + 'Maksi', + 'Whitnash', + 'Parintins', + 'Mykolaiv', + 'Somavarappatti', + 'Az Zaydiyah', + 'Chop', + 'Pingcha', + 'Gojo', + 'Anicuns', + "Vaprio d'Adda", + 'Ailan Mubage', + 'Gernsheim', + 'Ozamiz City', + 'Bamendjou', + 'Mantingan', + 'Centre Wellington', + 'Somolu', + 'Ijevan', + 'Gurun', + 'Sonhauli', + 'Hoshoot', + 'Lippstadt', + 'Payshamba Shahri', + 'Pirapora', + 'Mariyadau', + 'Touba', + 'Cavallino', + 'Broomall', + 'Saint-Paul-Trois-Chateaux', + 'Pirangut', + 'Monte San Savino', + 'Addis Ababa', + 'Wenzhou', + 'Hongshui', + 'Bamora', + 'Dadeldhura', + 'Barrhead', + 'Qizilhacili', + 'Cenon', + 'Yany Kapu', + 'Lauderdale Lakes', + 'Franklin Farm', + 'Licheng', + 'Lacchiarella', + 'Oshwe', + 'Blantyre', + 'Birpur', + 'Bucha', + 'San Manuel', + 'Laguna Beach', + 'Donna', + 'Clute', + 'Achchampeta', + 'Rajapalaiyam', + 'Koszeg', + 'Venancio Aires', + 'Romang', + 'Four Corners', + 'Sturgeon Bay', + 'Tuscaloosa', + 'Goianira', + 'Chattamangalam', + 'Tadotsu', + 'Sindhnur', + 'Ouda-daito', + 'Harmah', + 'Nordhausen', + 'Had Laaounate', + 'Dolny Kubin', + 'Penarth', + 'Androka', + 'Cajibio', + 'Molesey', + 'Zhanjia', + 'Abuzar-e Ghaffari', + 'Sayaxche', + 'Austin', + 'Pipalrawan', + 'Chillan', + 'Baena', + 'Langenberg', + 'Mykolaivka', + 'Ferentino', + 'Biddulph', + 'Harnosand', + 'Koekelberg', + 'Little Hulton', + 'Al Qitena', + 'Lewisville', + 'Turaiyur', + 'Chakkuvarakal', + 'Tres Rios', + 'Banabuiu', + 'Muzaffargarh', + 'Erragondapalem', + 'Ghambiraopet', + 'Okara', + 'Ilioupoli', + 'Paddhari', + 'Nariar', + 'Longjing', + "M'Sila", + 'Bongor', + 'Viterbo', + 'Vlasenica', + 'Montalvania', + 'Parali', + 'Spa', + 'Westford', + 'Muttam', + 'Raamsdonksveer', + 'Garoua Boulai', + 'Batarasa', + 'Vasylkivka', + 'Estevan', + 'Luanda', + 'MacArthur', + 'Zulpich', + 'Phulbani', + 'Ifarantsa', + 'Umbita', + 'Korogwe', + 'Ilhabela', + 'Baronissi', + 'Kalyvia Thorikou', + 'Lahfayr', + 'Ba Ria', + 'Bronderslev', + 'Kaynasli', + 'Usmate Velate', + 'Hirosaki', + 'Quedgeley', + 'Zawyat ech Cheikh', + 'Soledad Atzompa', + 'Ambohitromby', + 'Joao Teves', + 'Siddipet', + 'Bitkine', + 'Bellshill', + 'Feke', + 'Grass Valley', + 'Ashton in Makerfield', + 'Punjai Puliyampatti', + 'Lobito', + 'Bernalda', + 'Loudonville', + 'Asbury Lake', + 'Gyoda', + 'Artik', + 'Rio Rancho', + 'Roissy-en-Brie', + 'Garches', + 'Chemini', +]; diff --git a/drizzle-seed/src/datasets/companyNameSuffixes.ts b/drizzle-seed/src/datasets/companyNameSuffixes.ts new file mode 100644 index 000000000..ae8ce6163 --- /dev/null +++ b/drizzle-seed/src/datasets/companyNameSuffixes.ts @@ -0,0 +1,27 @@ +export default [ + 'LLC', + 'Ltd', + 'Inc.', + 'Corp.', + 'PLC', + 'GmbH', + 'AG', + 'S.A.', + 'S.p.A.', + 'SARL', + 'B.V.', + 'N.V.', + 'Oy', + 'AB', + 'AS', + 'Pty Ltd', + 'K.K.', + 'JSC', + 'Ltda.', + 'Pvt Ltd', + 'Sdn Bhd', + 'A/S', + 'SAOG', + 'Co.', + 'SCC', +]; diff --git a/drizzle-seed/src/datasets/countries.ts b/drizzle-seed/src/datasets/countries.ts new file mode 100644 index 000000000..4808fc5e5 --- /dev/null +++ b/drizzle-seed/src/datasets/countries.ts @@ -0,0 +1,171 @@ +/** + * The original source for countries data was taken from https://www.kaggle.com/datasets/manusmitajha/countrydatacsv + * We've excluded a few countries and their cities from this list because we don't think they should ever appear in any list + */ +export default [ + 'Afghanistan', + 'Albania', + 'Algeria', + 'Angola', + 'Antigua and Barbuda', + 'Argentina', + 'Armenia', + 'Australia', + 'Austria', + 'Azerbaijan', + 'Bahamas', + 'Bahrain', + 'Bangladesh', + 'Barbados', + 'Belgium', + 'Belize', + 'Benin', + 'Bhutan', + 'Bolivia', + 'Bosnia and Herzegovina', + 'Botswana', + 'Brazil', + 'Brunei', + 'Bulgaria', + 'Burkina Faso', + 'Burundi', + 'Cambodia', + 'Cameroon', + 'Canada', + 'Cape Verde', + 'Central African Republic', + 'Chad', + 'Chile', + 'China', + 'Colombia', + 'Comoros', + 'Congo, Dem. Rep.', + 'Congo, Rep.', + 'Costa Rica', + "Cote d'Ivoire", + 'Croatia', + 'Cyprus', + 'Czech Republic', + 'Denmark', + 'Dominican Republic', + 'Ecuador', + 'Egypt', + 'El Salvador', + 'Equatorial Guinea', + 'Eritrea', + 'Estonia', + 'Fiji', + 'Finland', + 'France', + 'Gabon', + 'Gambia', + 'Georgia', + 'Germany', + 'Ghana', + 'Greece', + 'Grenada', + 'Guatemala', + 'Guinea', + 'Guinea-Bissau', + 'Guyana', + 'Haiti', + 'Hungary', + 'Iceland', + 'India', + 'Indonesia', + 'Iran', + 'Iraq', + 'Ireland', + 'Israel', + 'Italy', + 'Jamaica', + 'Japan', + 'Jordan', + 'Kazakhstan', + 'Kenya', + 'Kiribati', + 'Kuwait', + 'Kyrgyz Republic', + 'Lao', + 'Latvia', + 'Lebanon', + 'Lesotho', + 'Liberia', + 'Libya', + 'Lithuania', + 'Luxembourg', + 'Macedonia, FYR', + 'Madagascar', + 'Malawi', + 'Malaysia', + 'Maldives', + 'Mali', + 'Malta', + 'Mauritania', + 'Mauritius', + 'Micronesia, Fed. Sts.', + 'Moldova', + 'Mongolia', + 'Montenegro', + 'Morocco', + 'Mozambique', + 'Myanmar', + 'Namibia', + 'Nepal', + 'Netherlands', + 'New Zealand', + 'Niger', + 'Nigeria', + 'Norway', + 'Oman', + 'Pakistan', + 'Panama', + 'Paraguay', + 'Peru', + 'Philippines', + 'Poland', + 'Portugal', + 'Qatar', + 'Romania', + 'Rwanda', + 'Samoa', + 'Saudi Arabia', + 'Senegal', + 'Serbia', + 'Seychelles', + 'Sierra Leone', + 'Singapore', + 'Slovak Republic', + 'Slovenia', + 'Solomon Islands', + 'South Africa', + 'South Korea', + 'Spain', + 'Sri Lanka', + 'St. Vincent and the Grenadines', + 'Sudan', + 'Suriname', + 'Sweden', + 'Switzerland', + 'Tajikistan', + 'Tanzania', + 'Thailand', + 'Timor-Leste', + 'Togo', + 'Tonga', + 'Tunisia', + 'Turkey', + 'Turkmenistan', + 'Uganda', + 'Ukraine', + 'United Arab Emirates', + 'United Kingdom', + 'United States', + 'Uruguay', + 'Uzbekistan', + 'Vanuatu', + 'Venezuela', + 'Vietnam', + 'Yemen', + 'Zambia', +]; diff --git a/drizzle-seed/src/datasets/emailDomains.ts b/drizzle-seed/src/datasets/emailDomains.ts new file mode 100644 index 000000000..9904aad3e --- /dev/null +++ b/drizzle-seed/src/datasets/emailDomains.ts @@ -0,0 +1,24 @@ +export default [ + 'gmail.com', + 'yahoo.com', + 'outlook.com', + 'msn.com', + 'hotmail.com', + 'aol.com', + 'hotmail.co.uk', + 'hotmail.fr', + 'yahoo.fr', + 'wanadoo.fr', + 'orange.fr', + 'comcast.net', + 'yahoo.co.uk', + 'yahoo.com.br', + 'yahoo.co.in', + 'live.com', + 'rediffmail.com', + 'free.fr', + 'gmx.de', + 'web.de', + 'ymail.com', + 'libero.it', +]; diff --git a/drizzle-seed/src/datasets/firstNames.ts b/drizzle-seed/src/datasets/firstNames.ts new file mode 100644 index 000000000..7ca0ff928 --- /dev/null +++ b/drizzle-seed/src/datasets/firstNames.ts @@ -0,0 +1,30279 @@ +/** + * The original source for first names data was taken from https://www.kaggle.com/datasets/kaggle/us-baby-names?select=StateNames.csv + */ +export default [ + 'Robert', + 'John', + 'Michael', + 'David', + 'James', + 'Richard', + 'Christopher', + 'William', + 'Daniel', + 'Mark', + 'Thomas', + 'Jose', + 'Joseph', + 'Matthew', + 'Jason', + 'Andrew', + 'Joshua', + 'Steven', + 'Anthony', + 'Jonathan', + 'Angel', + 'Ryan', + 'Kevin', + 'Jacob', + 'Nicholas', + 'Brandon', + 'Justin', + 'Charles', + 'Gary', + 'Paul', + 'Scott', + 'George', + 'Christian', + 'Eric', + 'Brian', + 'Alexander', + 'Ronald', + 'Jayden', + 'Juan', + 'Edward', + 'Noah', + 'Diego', + 'Donald', + 'Ethan', + 'Kyle', + 'Peter', + 'Jeffrey', + 'Luis', + 'Timothy', + 'Nathan', + 'Tyler', + 'Frank', + 'Stephen', + 'Dennis', + 'Larry', + 'Jesus', + 'Kenneth', + 'Austin', + 'Adrian', + 'Adam', + 'Sebastian', + 'Gregory', + 'Carlos', + 'Aiden', + 'Gabriel', + 'Isaac', + 'Zachary', + 'Julian', + 'Benjamin', + 'Liam', + 'Billy', + 'Miguel', + 'Mason', + 'Aaron', + 'Mike', + 'Dylan', + 'Sean', + 'Alejandro', + 'Bryan', + 'Jordan', + 'Cody', + 'Jeremy', + 'Samuel', + 'Harry', + 'Victor', + 'Joe', + 'Eduardo', + 'Isaiah', + 'Jorge', + 'Logan', + 'Elijah', + 'Bruce', + 'Patrick', + 'Jerry', + 'Jesse', + 'Lawrence', + 'Steve', + 'Walter', + 'Harold', + 'Arthur', + 'Lucas', + 'Francisco', + 'Douglas', + 'Oscar', + 'Craig', + 'Alexis', + 'Todd', + 'Randy', + 'Alan', + 'Raymond', + 'Damian', + 'Willie', + 'Albert', + 'Ricardo', + 'Louis', + 'Luke', + 'Edgar', + 'Travis', + 'Evan', + 'Ricky', + 'Aidan', + 'Jack', + 'Jeff', + 'Jimmy', + 'Manuel', + 'Oliver', + 'Mateo', + 'Johnny', + 'Henry', + 'Cristian', + 'Terry', + 'Dominic', + 'Cameron', + 'Gerald', + 'Caleb', + 'Christop', + 'Bobby', + 'Alex', + 'Gavin', + 'Shawn', + 'Jackson', + 'Ivan', + 'Keith', + 'Antonio', + 'Vincent', + 'Philip', + 'Chad', + 'Alfred', + 'Eugene', + 'Erik', + 'Martin', + 'Omar', + 'Chris', + 'Stanley', + 'Sergio', + 'Francis', + 'Mario', + 'Fernando', + 'Taylor', + 'Herbert', + 'Santiago', + 'Nathaniel', + 'Cesar', + 'Barry', + 'Trevor', + 'Dustin', + 'Hunter', + 'Roger', + 'Andres', + 'Javier', + 'Bernard', + 'Jim', + 'Ian', + 'Wayne', + 'Leonardo', + 'Giovanni', + 'Josiah', + 'Jeremiah', + 'Glenn', + 'Hector', + 'Roberto', + 'Rodney', + 'Howard', + 'Eli', + 'Xavier', + 'Jaxon', + 'Levi', + 'Derek', + 'Danny', + 'Jared', + 'Landon', + 'Ralph', + 'Ruben', + 'Gael', + 'Connor', + 'Tommy', + 'Tony', + 'Marc', + 'Wyatt', + 'Rick', + 'Carter', + 'Ayden', + 'Tim', + 'Roy', + 'Owen', + 'Greg', + 'Joel', + 'Leonard', + 'Frederick', + 'Russell', + 'Jon', + 'Jaden', + 'Jeffery', + 'Irving', + 'Erick', + 'Darren', + 'Dale', + 'Carl', + 'Brayden', + 'Ronnie', + 'Gerardo', + 'Pedro', + 'Raul', + 'Elias', + 'Chase', + 'Alberto', + 'Troy', + 'Tom', + 'Axel', + 'Julio', + 'Emmanuel', + 'Edwin', + 'Norman', + 'Marcus', + 'Fred', + 'Bill', + 'Jake', + 'Marco', + 'Leo', + 'Rafael', + 'Armando', + 'Jace', + 'Garrett', + 'Jaime', + 'Earl', + 'Shane', + 'Cole', + 'Phillip', + 'Seth', + 'Corey', + 'Nicolas', + 'Randall', + 'Hayden', + 'Abraham', + 'Grayson', + 'Tristan', + 'Cory', + 'Josue', + 'Andy', + 'Warren', + 'Roman', + 'Devin', + 'Salvador', + 'Shaun', + 'Spencer', + 'Infant', + 'Ryder', + 'Dillon', + 'Max', + 'Salvatore', + 'Bradley', + 'Seymour', + 'Arturo', + 'Iker', + 'Dean', + 'Milton', + 'Sidney', + 'Gustavo', + 'Alfredo', + 'Blake', + 'Clarence', + 'Brody', + 'Enrique', + 'Brett', + 'Colton', + 'Dan', + 'Brendan', + 'Charlie', + 'Darrell', + 'Hudson', + 'Ezra', + 'Emiliano', + 'Ashton', + 'Darryl', + 'Dave', + 'Nolan', + 'Theodore', + 'Casey', + 'Colin', + 'Easton', + 'Caden', + 'Marcos', + 'Cooper', + 'Mitchell', + 'Morris', + 'Don', + 'Eddie', + 'Jay', + 'Marvin', + 'Kaden', + 'Curtis', + 'Lance', + 'Gerard', + 'Israel', + 'Ramon', + 'Rickey', + 'Alec', + 'Carson', + 'Ernesto', + 'Riley', + 'Kai', + 'Ezekiel', + 'Yahir', + 'Dakota', + 'Ron', + 'Bob', + 'Saul', + 'Kayden', + 'Adan', + 'Fabian', + 'Maxwell', + 'Allen', + 'Micheal', + 'Parker', + 'Micah', + 'Miles', + 'Gilbert', + 'Grant', + 'Malik', + 'Abel', + 'Darrin', + 'Johnathan', + 'Jase', + 'Kaleb', + 'Ray', + 'Jaxson', + 'Brent', + 'Wesley', + 'Tanner', + 'Chester', + 'Bryce', + 'Lincoln', + 'Preston', + 'Maximiliano', + 'Jerome', + 'Sam', + 'Ernest', + 'Bentley', + 'Colby', + 'Elmer', + 'Moises', + 'Joaquin', + 'Arnold', + 'Stuart', + 'Murray', + 'Asher', + 'Andre', + 'Neil', + 'Allan', + 'Brady', + 'Brad', + 'Maximus', + 'Dalton', + 'Jonah', + 'Kim', + 'Kirk', + 'Bryson', + 'Kurt', + 'Angelo', + 'Rene', + 'Jimmie', + 'Emilio', + 'Damien', + 'Harvey', + 'Moshe', + 'Derrick', + 'Kelly', + 'Franklin', + 'Rodrigo', + 'Woodrow', + 'Leon', + 'Esteban', + 'Hugo', + 'Clayton', + 'Guadalupe', + 'Darin', + 'Pablo', + 'Luca', + 'Ken', + 'Ismael', + 'Leroy', + 'Guillermo', + 'Tracy', + 'Melvin', + 'Lorenzo', + 'Clifford', + 'Hugh', + 'Mathew', + 'Jameson', + 'Billie', + 'Nelson', + 'Herman', + 'Ira', + 'Jamie', + 'Alexande', + 'Lester', + 'Glen', + 'Damon', + 'Emanuel', + 'Maverick', + 'Braxton', + 'Zayden', + 'Dominick', + 'Irwin', + 'Rudy', + 'Calvin', + 'Julius', + 'Jermaine', + 'Jakob', + 'Donovan', + 'Lee', + 'Shaquille', + 'Gordon', + 'Peyton', + 'Duane', + 'Declan', + 'Jalen', + 'Jude', + 'Tyrone', + 'Bret', + 'Gene', + 'Felix', + 'Guy', + 'Devon', + 'Cruz', + 'Rylan', + 'Clinton', + 'Jonathon', + 'Kaiden', + 'Kingston', + 'Kristopher', + 'Felipe', + 'Collin', + 'Alfonso', + 'Rodolfo', + 'King', + 'Everett', + 'Chance', + 'Johnnie', + 'Clyde', + 'Weston', + 'Karl', + 'Camden', + 'Maddox', + 'Bryant', + 'Gage', + 'Dwayne', + 'Shannon', + 'Gilberto', + 'Braden', + 'Lewis', + 'Greyson', + 'Rudolph', + 'Floyd', + 'Jayce', + 'Harrison', + 'Brayan', + 'Cayden', + 'Reginald', + 'Jaiden', + 'Brantley', + 'Hyman', + 'Perry', + 'Kent', + 'Alvin', + 'Cade', + 'Doug', + 'Romeo', + 'Jax', + 'Silas', + 'Ty', + 'Emmett', + 'Jackie', + 'Leslie', + 'Vernon', + 'Jessie', + 'Lloyd', + 'Cecil', + 'Roland', + 'Ted', + 'Amir', + 'Cash', + 'Gregg', + 'Uriel', + 'Donnie', + 'Noel', + 'Mauricio', + 'Dana', + 'Osvaldo', + 'Sawyer', + 'Rogelio', + 'Terrence', + 'Conner', + 'Darius', + 'Chaim', + 'Maurice', + 'Male', + 'Malachi', + 'Issac', + 'Ramiro', + 'Zane', + 'Jaylen', + 'Dawson', + 'Willard', + 'Randolph', + 'Wilbur', + 'Noe', + 'Huey', + 'Sammy', + 'Lonnie', + 'Morton', + 'Chandler', + 'Elliot', + 'Geoffrey', + 'Robin', + 'Muhammad', + 'Wallace', + 'Matt', + 'Drew', + 'Bailey', + 'Orlando', + 'Jasper', + 'Tyrese', + 'Matteo', + 'Leonel', + 'Simon', + 'Braylon', + 'Corbin', + 'Jayceon', + 'Gunner', + 'Dante', + 'Daryl', + 'Bennett', + 'Ulises', + 'Efrain', + 'Drake', + 'Rolando', + 'Lukas', + 'Arian', + 'Trenton', + 'Humberto', + 'Ryker', + 'Aldo', + 'Landen', + 'Xander', + 'Dwight', + 'Alvaro', + 'Sheldon', + 'Freddie', + 'Vicente', + 'Avery', + 'Marty', + 'Irvin', + 'Ariel', + 'Lane', + 'Nestor', + 'Chuck', + 'Dominique', + 'Baby', + 'Kerry', + 'Enzo', + 'Nick', + 'Yosef', + 'Edmund', + 'Oswaldo', + 'Kobe', + 'Aden', + 'Clair', + 'Freddy', + 'Karter', + 'Stacy', + 'Byron', + 'Roosevelt', + 'Claude', + 'Marion', + 'Thiago', + 'Colt', + 'Sol', + 'Lamont', + 'Neal', + 'August', + 'Cason', + 'Kason', + 'Reynaldo', + 'Malcolm', + 'Beau', + 'Ignacio', + 'Kareem', + 'Laurence', + 'Finn', + 'Domingo', + 'Rigoberto', + 'Solomon', + 'Aaden', + 'Case', + 'Horace', + 'Griffin', + 'Rocco', + 'Pete', + 'Ross', + 'Skyler', + 'Kenny', + 'Tucker', + 'Morgan', + 'Forrest', + 'Timmy', + 'Clint', + 'Garry', + 'Elwood', + 'Knox', + 'Elian', + 'Zion', + 'Trey', + 'Vito', + 'Jamel', + 'Junior', + 'Roderick', + 'Brooks', + 'Isidore', + 'Kelvin', + 'Ali', + 'Octavio', + 'Luther', + 'Milo', + 'Jett', + 'Unknown', + 'Milan', + 'Nickolas', + 'German', + 'Terence', + 'Virgil', + 'Conor', + 'Isaias', + 'Cristopher', + 'Jayson', + 'Brenden', + 'Joey', + 'Tevin', + 'Branden', + 'Arjun', + 'Carmine', + 'Wendell', + 'Judah', + 'Nikolas', + 'Izaiah', + 'Dick', + 'Jairo', + 'Giovani', + 'Ervin', + 'Graham', + 'Trent', + 'Tyson', + 'Cedric', + 'Elliott', + 'Myles', + 'Kameron', + 'Jaylon', + 'Hubert', + 'Grady', + 'Homer', + 'Quinn', + 'Payton', + 'Bennie', + 'River', + 'Dexter', + 'Emil', + 'Jamal', + 'Orion', + 'Alonzo', + 'Paxton', + 'Ashley', + 'Desmond', + 'Waylon', + 'Patsy', + 'Agustin', + 'Shimon', + 'Jarrod', + 'Rex', + 'Pat', + 'Rhett', + 'Benny', + 'Adriel', + 'Moses', + 'Daquan', + 'Johan', + 'Adolfo', + 'Otis', + 'Kadeem', + 'Jody', + 'Wilson', + 'Pasquale', + 'Kendrick', + 'Alonso', + 'Ben', + 'Ezequiel', + 'Jair', + 'Tomas', + 'Zackary', + 'Dane', + 'Nasir', + 'Alton', + 'Tristen', + 'Wilfredo', + 'Lyle', + 'Rowan', + 'Deandre', + 'Mordechai', + 'Mohamed', + 'Khalil', + 'Maximilian', + 'Devante', + 'Wade', + 'Norbert', + 'Yehuda', + 'Dallas', + 'Menachem', + 'Anderson', + 'Jonas', + 'Zachery', + 'Zaiden', + 'Giovanny', + 'Clifton', + 'Tommie', + 'Ronaldo', + 'Major', + 'Barrett', + 'Darnell', + 'Keegan', + 'Randal', + 'Aarav', + 'Burton', + 'Terrance', + 'Reid', + 'Fredrick', + 'Bobbie', + 'Ace', + 'Kyler', + 'Yoel', + 'Earnest', + 'Toby', + 'Merle', + 'Archer', + 'Santos', + 'Nico', + 'Beckett', + 'Yisroel', + 'Nehemiah', + 'Lynn', + 'Holden', + 'Matias', + 'Rufus', + 'Mohammed', + 'Hayes', + 'Marshall', + 'Trinidad', + 'Valentin', + 'Heath', + 'Weldon', + 'Ed', + 'Lionel', + 'Jaret', + 'Aron', + 'Bernardo', + 'Zander', + 'Devonte', + 'Meyer', + 'Ulysses', + 'Myron', + 'Lowell', + 'Linwood', + 'Rocky', + 'Phoenix', + 'Antoine', + 'Cyrus', + 'Demarcus', + 'Bruno', + 'Titus', + 'Madison', + 'Jarod', + 'Caiden', + 'Kash', + 'Jarvis', + 'Clay', + 'Notnamed', + 'Doyle', + 'Dallin', + 'Atticus', + 'Orville', + 'Nixon', + 'Loren', + 'Wilbert', + 'Karson', + 'Brennan', + 'Brittany', + 'Marlon', + 'Gonzalo', + 'Carlton', + 'Cary', + 'Marquis', + 'Amari', + 'Rohan', + 'Terrell', + 'Gianni', + 'Johnathon', + 'Jan', + 'Boston', + 'Ibrahim', + 'Yitzchok', + 'Jean', + 'Camron', + 'Ronny', + 'Porter', + 'Adonis', + 'Alessandro', + 'Stefan', + 'Giancarlo', + 'Clark', + 'Lupe', + 'Edgardo', + 'Scotty', + 'Messiah', + 'Benito', + 'Zachariah', + 'Kristian', + 'Bodhi', + 'Ronan', + 'Emerson', + 'Wilfred', + 'Heriberto', + 'Davis', + 'Stewart', + 'Efren', + 'Brock', + 'Christophe', + 'Sammie', + 'Kade', + 'Denis', + 'Ernie', + 'Kayson', + 'Quincy', + 'Abe', + 'Estevan', + 'Jamari', + 'Mohammad', + 'Kendall', + 'Demetrius', + 'Walker', + 'Shlomo', + 'Louie', + 'Kody', + 'Valentino', + 'Jaheim', + 'Vince', + 'Frankie', + 'Aubrey', + 'Quinton', + 'Royce', + 'Ari', + 'Abram', + 'Jessica', + 'Curt', + 'Bart', + 'Daren', + 'Braylen', + 'Alexandro', + 'Lamar', + 'Kasen', + 'Willis', + 'Vihaan', + 'Delbert', + 'Triston', + 'Yakov', + 'Courtney', + 'Niko', + 'Pierre', + 'Jaquan', + 'Braulio', + 'Santino', + 'Quentin', + 'Dario', + 'Dusty', + 'Neymar', + 'Bridger', + 'Tyrell', + 'Bertram', + 'Raymundo', + 'Isiah', + 'Reed', + 'Archie', + 'Prince', + 'Rory', + 'Davon', + 'Stacey', + 'Bradford', + 'Nikolai', + 'Kian', + 'Kase', + 'Casen', + 'Dion', + 'Isai', + 'Armand', + 'Percy', + 'Emily', + 'Leland', + 'Sterling', + 'Yandel', + 'Olin', + 'Sanford', + 'Marlin', + 'Denzel', + 'Mekhi', + 'Elbert', + 'Braydon', + 'Dewey', + 'Dudley', + 'Shmuel', + 'Jadon', + 'Braeden', + 'Yair', + 'Rob', + 'Mickey', + 'Monty', + 'Hannah', + 'Luciano', + 'Remington', + 'Akeem', + 'Julien', + 'Carmen', + 'Jensen', + 'Johnie', + 'Mack', + 'Rickie', + 'Javon', + 'Misael', + 'Elvis', + 'Eden', + 'Jess', + 'Phil', + 'Malakai', + 'Melvyn', + 'Rod', + 'Arnulfo', + 'Cohen', + 'Fidel', + 'Levar', + 'Dominik', + 'Grover', + 'Yaakov', + 'Landyn', + 'Colten', + 'Dorian', + 'Keaton', + 'Loyd', + 'Brodie', + 'Otto', + 'Eliezer', + 'Ahmed', + 'Shelby', + 'Hernan', + 'Odin', + 'Regis', + 'Jaydon', + 'Uriah', + 'Remy', + 'Tariq', + 'Sonny', + 'Carroll', + 'Xavi', + 'Christia', + 'Marcel', + 'Brendon', + 'Kellan', + 'Bowen', + 'Unnamed', + 'Scottie', + 'Justice', + 'Kurtis', + 'Stephan', + 'Daxton', + 'Coby', + 'Jadiel', + 'Dashawn', + 'Amare', + 'Cannon', + 'Blaine', + 'Tate', + 'Talmadge', + 'Nathanael', + 'Adolph', + 'Talan', + 'Tobias', + 'Sylvester', + 'Tadeo', + 'Darrel', + 'Winston', + 'Garland', + 'Meir', + 'Kory', + 'Joseluis', + 'Wilburn', + 'Rusty', + 'Avraham', + 'Ayaan', + 'Theo', + 'Mathias', + 'Marcelo', + 'Dino', + 'Kolby', + 'Cael', + 'Tzvi', + 'Davion', + 'Aryan', + 'Rhys', + 'Cain', + 'Duke', + 'Pierce', + 'Landry', + 'Tristin', + 'Emma', + 'Zackery', + 'Antone', + 'Rayan', + 'Hendrix', + 'Lucca', + 'Luka', + 'Jarrett', + 'Miguelangel', + 'Rodger', + 'Kevon', + 'Jacoby', + 'Damion', + 'Maximo', + 'Robbie', + 'Jovanny', + 'Trace', + 'Gunnar', + 'Kieran', + 'Cristobal', + 'Kris', + 'Ellis', + 'Matthias', + 'Eloy', + 'Sarah', + 'Donny', + 'Donte', + 'Ronin', + 'Reece', + 'Alijah', + 'Zayne', + 'Jamarion', + 'Laverne', + 'Gregorio', + 'Kellen', + 'Nathen', + 'Gideon', + 'Rosario', + 'Erwin', + 'Jakub', + 'Normand', + 'Rey', + 'Trevon', + 'Stetson', + 'Carmelo', + 'Rashad', + 'Tod', + 'Elizabeth', + 'Harley', + 'Darian', + 'Scot', + 'Tavon', + 'Keven', + 'Merlin', + 'Nash', + 'Deangelo', + 'Raiden', + 'Jahir', + 'Isidro', + 'Davian', + 'Raekwon', + 'Alphonse', + 'Reese', + 'Abigail', + 'Deshawn', + 'Ahmad', + 'Conrad', + 'Truman', + 'Kolton', + 'Ryland', + 'Jamaal', + 'Abdiel', + 'Aditya', + 'Keenan', + 'Brycen', + 'Thaddeus', + 'Austen', + 'Leonidas', + 'Raphael', + 'Jovani', + 'Brenton', + 'Jasmine', + 'Thurman', + 'Russel', + 'Emory', + 'Cornelius', + 'Roel', + 'Xzavier', + 'Jovanni', + 'Zev', + 'Eldon', + 'Deven', + 'Kamden', + 'Eliseo', + 'Franco', + 'Duncan', + 'Anton', + 'Amarion', + 'Deron', + 'Sage', + 'Babyboy', + 'Fredy', + 'Russ', + 'Omarion', + 'Ryne', + 'Jovany', + 'Camilo', + 'Stan', + 'Cullen', + 'Armani', + 'Adrien', + 'Royal', + 'Kane', + 'Ishaan', + 'Spenser', + 'Antwan', + 'Stephon', + 'Juanpablo', + 'Tiffany', + 'Garret', + 'Jagger', + 'Will', + 'Nigel', + 'Chadwick', + 'Casimir', + 'Abdirahman', + 'Odell', + 'Keanu', + 'Josh', + 'Mortimer', + 'Raheem', + 'Jordon', + 'Nery', + 'Monte', + 'Jaxton', + 'Deacon', + 'Reuben', + 'Carlo', + 'Skylar', + 'Jamarcus', + 'Robby', + 'Jaycob', + 'Kristofer', + 'Buddy', + 'Korbin', + 'Arlo', + 'Jennifer', + 'Rodrick', + 'Juwan', + 'Latrell', + 'Chaz', + 'Lawson', + 'Mendel', + 'Jordy', + 'Dirk', + 'Finnegan', + 'Eason', + 'Atlas', + 'Eddy', + 'Mitch', + 'Reagan', + 'Clement', + 'Jamar', + 'Kamari', + 'Jarred', + 'Lauren', + 'Roscoe', + 'Jefferson', + 'Devan', + 'Elton', + 'Cortez', + 'Leandro', + 'Finley', + 'Cordero', + 'Dov', + 'Eliyahu', + 'Princeton', + 'Avrohom', + 'Hassan', + 'Dangelo', + 'Shamar', + 'Gino', + 'Yusuf', + 'Jaylin', + 'Martez', + 'Shad', + 'Keyshawn', + 'Nikhil', + 'Yael', + 'Harlan', + 'Jeffry', + 'Frederic', + 'Derick', + 'Dondre', + 'Vance', + 'Markus', + 'London', + 'Arman', + 'Marley', + 'Van', + 'Jaeden', + 'Krish', + 'Benson', + 'Marquise', + 'Cristofer', + 'Dewayne', + 'Gannon', + 'Genaro', + 'Crew', + 'Rashawn', + 'Rayden', + 'Raylan', + 'Jaxen', + 'Fredric', + 'Beckham', + 'Tripp', + 'Mckay', + 'Deonte', + 'Johann', + 'Johnpaul', + 'Santo', + 'Hakeem', + 'Federico', + 'Bert', + 'Flynn', + 'Edison', + 'Enoch', + 'Shulem', + 'Jovan', + 'Art', + 'Isadore', + 'Hal', + 'Cristiano', + 'Urijah', + 'Dilan', + 'Benicio', + 'Kingsley', + 'Aydan', + 'Syed', + 'Nicole', + 'Rachel', + 'Tyree', + 'Maximillian', + 'Branson', + 'Davin', + 'Layton', + 'Joan', + 'Darien', + 'Deion', + 'Augustus', + 'Dariel', + 'Oziel', + 'Juancarlos', + 'Pranav', + 'Danielle', + 'Rubin', + 'Jerald', + 'Wilmer', + 'Deegan', + 'Teddy', + 'Mariano', + 'Nathanie', + 'Stevie', + 'Dorsey', + 'Maxim', + 'Jaron', + 'Coty', + 'Damarion', + 'Semaj', + 'Maria', + 'Jamison', + 'Domenick', + 'Emile', + 'Armaan', + 'Arnav', + 'Mackenzie', + 'Everardo', + 'Aurelio', + 'Cayson', + 'Edwardo', + 'Charley', + 'Geovanni', + 'Vincenzo', + 'Yadiel', + 'Francesco', + 'Koby', + 'Joziah', + 'Jasiah', + 'Makai', + 'Long', + 'Cassius', + 'Omari', + 'Ferdinand', + 'Samir', + 'Cleveland', + 'Olivia', + 'Lanny', + 'Sincere', + 'Hyrum', + 'Christina', + 'Lucian', + 'Margarito', + 'Osiel', + 'Kinsler', + 'Sydney', + 'Slade', + 'Lazaro', + 'Sal', + 'Lipa', + 'Hobert', + 'Coy', + 'Elroy', + 'Tatum', + 'Katherine', + 'Chloe', + 'Kyrie', + 'Amanda', + 'Buford', + 'Kymani', + 'Kacper', + 'Elmo', + 'Alphonso', + 'Ramses', + 'Homero', + 'Sherman', + 'Reinaldo', + 'Yechiel', + 'Jonatan', + 'Mychal', + 'Gustave', + 'Paris', + 'Zain', + 'Markanthony', + 'Dimitri', + 'Mamadou', + 'Apollo', + 'Bronson', + 'Hamza', + 'Samson', + 'Madden', + 'Tylor', + 'Jacquez', + 'Garth', + 'Giuseppe', + 'Stephanie', + 'Darion', + 'Yurem', + 'Antony', + 'Rico', + 'Rich', + 'Dontavious', + 'Erin', + 'Kannon', + 'Isaak', + 'Dovid', + 'Coleman', + 'Monroe', + 'Bryon', + 'Asa', + 'Patricio', + 'Arnoldo', + 'Alexandra', + 'Jessy', + 'Jules', + 'Alexzander', + 'Jerrod', + 'Talon', + 'Elvin', + 'Chace', + 'Amos', + 'Galen', + 'Kenji', + 'Rahul', + 'Delmar', + 'Nakia', + 'Abdullah', + 'Deon', + 'Brice', + 'Osbaldo', + 'Favian', + 'Mauro', + 'Tristian', + 'Leopoldo', + 'Hans', + 'Hank', + 'Tou', + 'Demond', + 'Jemal', + 'Ladarius', + 'Kylan', + 'Braiden', + 'Darwin', + 'Kamron', + 'Millard', + 'Dax', + 'Shaquan', + 'Aloysius', + 'Tyshawn', + 'Westley', + 'Marquez', + 'Shayne', + 'Kasey', + 'Usher', + 'Ares', + 'Killian', + 'Maynard', + 'Jeshua', + 'Vaughn', + 'Shia', + 'Naftali', + 'Zaire', + 'Taj', + 'Edmond', + 'Zechariah', + 'Ollie', + 'Hoyt', + 'Donnell', + 'Soren', + 'Isac', + 'Tyquan', + 'Legend', + 'Devyn', + 'Shon', + 'Gerry', + 'Ellsworth', + 'Naftuli', + 'Johnson', + 'Haywood', + 'Aydin', + 'Junius', + 'Wiley', + 'Lennox', + 'Siddharth', + 'Odis', + 'Zaid', + 'Lacy', + 'Hussein', + 'Nicklas', + 'Callen', + 'Izayah', + 'Jaziel', + 'Claud', + 'Horacio', + 'Cyril', + 'Jariel', + 'Shemar', + 'Rebecca', + 'Reyes', + 'Denny', + 'Dereck', + 'Marcelino', + 'Najee', + 'Mac', + 'Hollis', + 'Korey', + 'Addison', + 'Jordi', + 'Eleazar', + 'Lisandro', + 'Dayton', + 'Ammon', + 'Reymundo', + 'Erich', + 'Tenzin', + 'Mitchel', + 'Kristoffer', + 'Jerrold', + 'Kristoph', + 'Refugio', + 'Erasmo', + 'Samantha', + 'Simcha', + 'Abdullahi', + 'Booker', + 'Quadir', + 'Kyson', + 'Hoover', + 'Gus', + 'Azael', + 'Mervin', + 'Yoshio', + 'Jorje', + 'Jesiah', + 'Shirley', + 'Brigham', + 'Memphis', + 'Reyansh', + 'Flavio', + 'Lavern', + 'Rosendo', + 'Dantrell', + 'Devonta', + 'Forest', + 'Alden', + 'Lyndon', + 'Luiz', + 'Elisha', + 'Al', + 'Bentlee', + 'Eriberto', + 'Marques', + 'Alexandre', + 'Fidencio', + 'Jabari', + 'Arsenio', + 'Kaysen', + 'Ethen', + 'Cleo', + 'Blaze', + 'Aryeh', + 'Dequan', + 'Denver', + 'Luc', + 'Delmas', + 'Javion', + 'Gauge', + 'Martell', + 'Ever', + 'Gavyn', + 'Aldair', + 'Okey', + 'Carey', + 'Geovanny', + 'Kalel', + 'Layne', + 'Hiroshi', + 'Ayan', + 'Akiva', + 'Clare', + 'Sigmund', + 'Furman', + 'Claudio', + 'Garrison', + 'Draven', + 'Aidyn', + 'Vern', + 'Andreas', + 'Kwame', + 'Imanol', + 'Jorden', + 'Glynn', + 'Adalberto', + 'Varun', + 'Dashiell', + 'Baron', + 'Jasen', + 'Child', + 'Earle', + 'Izaac', + 'Vivaan', + 'Koa', + 'Lennon', + 'Marcoantonio', + 'Gaetano', + 'Sumner', + 'Barney', + 'Demarion', + 'Abner', + 'Delonte', + 'Val', + 'Jacky', + 'Demario', + 'Zavier', + 'Kale', + 'Wilton', + 'Jordyn', + 'Tatsuo', + 'Boyd', + 'Zayn', + 'Darron', + 'Moe', + 'Dillan', + 'Naquan', + 'Ned', + 'Kaylee', + 'Kelton', + 'Sahil', + 'Kermit', + 'Abelardo', + 'Sullivan', + 'Crosby', + 'Hagen', + 'Tyreek', + 'Jaquez', + 'Andrea', + 'Kyan', + 'Jeremias', + 'Tracey', + 'Ward', + 'Brixton', + 'Seamus', + 'Cedrick', + 'Enrico', + 'Emmitt', + 'Ford', + 'Travon', + 'Felton', + 'Blair', + 'Rio', + 'Dandre', + 'Kaeden', + 'Tiger', + 'Orval', + 'Castiel', + 'Yousef', + 'Anson', + 'Callan', + 'Jamey', + 'Darrius', + 'Tre', + 'Michel', + 'Mcarthur', + 'Rasheed', + 'Jamir', + 'Herschel', + 'Anibal', + 'Kinnick', + 'Hilario', + 'Shea', + 'Jencarlos', + 'Darrick', + 'Rishi', + 'Shaya', + 'Haden', + 'Ean', + 'Jaylan', + 'Rolland', + 'Leobardo', + 'Fermin', + 'Keon', + 'Lucio', + 'Keagan', + 'Savion', + 'Masao', + 'Damari', + 'Aarush', + 'Nunzio', + 'Anakin', + 'Mayson', + 'Westin', + 'Norberto', + 'Tavares', + 'Gorge', + 'Tavaris', + 'Joesph', + 'Sylas', + 'Huy', + 'Gerson', + 'Augustine', + 'Buster', + 'Jelani', + 'Haley', + 'Filip', + 'Shmiel', + 'Lucius', + 'Rojelio', + 'Gale', + 'Quintin', + 'Channing', + 'Brayton', + 'Keshawn', + 'Osmar', + 'Otha', + 'Eder', + 'Mary', + 'Eusebio', + 'Matheus', + 'Randell', + 'Brennen', + 'Trae', + 'Paolo', + 'Caesar', + 'Estill', + 'Camren', + 'Dhruv', + 'Cutter', + 'Rayyan', + 'Jeramiah', + 'Anish', + 'Donavan', + 'Sunny', + 'Hershel', + 'Salvator', + 'Jedidiah', + 'Romario', + 'Hershy', + 'Anders', + 'Trevion', + 'Murphy', + 'Kanye', + 'Jionni', + 'Bradyn', + 'Cordell', + 'Alek', + 'Luisangel', + 'Norris', + 'Nevin', + 'Jaleel', + 'Lenny', + 'Judson', + 'Tayshaun', + 'Aedan', + 'Rhyder', + 'Domenic', + 'Santana', + 'Rahsaan', + 'Sebastien', + 'Corban', + 'Rowdy', + 'Kiyoshi', + 'Armen', + 'Efraim', + 'Vladimir', + 'Callum', + 'Abdul', + 'Gianluca', + 'Mayer', + 'Mustafa', + 'Demarco', + 'Neyland', + 'Vidal', + 'Marshawn', + 'Rudolfo', + 'Nazir', + 'Azariah', + 'Shoji', + 'Worth', + 'Levern', + 'Jai', + 'Antione', + 'Dickie', + 'Yehoshua', + 'Cliff', + 'Kaison', + 'Kye', + 'Jaren', + 'Emir', + 'Henrik', + 'Maxx', + 'Kainoa', + 'Athan', + 'Cletus', + 'Jasir', + 'Dejon', + 'Jadyn', + 'Houston', + 'Kadin', + 'Erubiel', + 'Hadi', + 'Jaydin', + 'Brianna', + 'Alyssa', + 'Marcello', + 'Omer', + 'Ikaika', + 'Ramel', + 'Arron', + 'Bently', + 'Daron', + 'Avi', + 'Jerod', + 'Shelton', + 'Winfred', + 'Mendy', + 'Ryu', + 'Nikko', + 'Arley', + 'Kamdyn', + 'Bo', + 'Erica', + 'Faustino', + 'Fletcher', + 'Dionte', + 'Boyce', + 'Kennedy', + 'Reyli', + 'Paulo', + 'Baruch', + 'Bernie', + 'Mohamad', + 'Kahlil', + 'Kong', + 'Baldemar', + 'Murry', + 'Rogers', + 'Sandy', + 'Bodie', + 'Ivory', + 'Youssef', + 'Kee', + 'Jahiem', + 'Isabella', + 'Keoni', + 'Michelle', + 'Luigi', + 'Marcanthony', + 'Jericho', + 'Achilles', + 'Everette', + 'Americo', + 'Edson', + 'Hiram', + 'Jeramy', + 'Metro', + 'Davi', + 'Hezekiah', + 'Harper', + 'Kiel', + 'Brandan', + 'Said', + 'Noam', + 'Tarik', + 'Raquan', + 'Zeb', + 'Broderick', + 'Arath', + 'Emery', + 'Kip', + 'Tymir', + 'Garrick', + 'Anfernee', + 'Khalid', + 'Jamil', + 'Demian', + 'Amador', + 'Oran', + 'Franklyn', + 'Porfirio', + 'Delano', + 'Justyn', + 'Aharon', + 'Karol', + 'Alva', + 'Nicky', + 'Zack', + 'Jerimiah', + 'Josef', + 'Errol', + 'Hideo', + 'Tahj', + 'Ilan', + 'Kennith', + 'Nathanial', + 'Kyron', + 'Merton', + 'Danial', + 'Tuan', + 'Hung', + 'Massimo', + 'Krew', + 'Arya', + 'Jedediah', + 'Nosson', + 'Jakobe', + 'Eitan', + 'Edmundo', + 'Olen', + 'Benedict', + 'Quintavious', + 'Shalom', + 'Akash', + 'Maxton', + 'Anna', + 'Julia', + 'Melissa', + 'Victoria', + 'Kekoa', + 'Konner', + 'Kirby', + 'Heyward', + 'Davonte', + 'Magnus', + 'Zeus', + 'Neel', + 'Franky', + 'Isael', + 'Gaylon', + 'Kole', + 'Axton', + 'Brando', + 'Mateusz', + 'Lucien', + 'Marquavious', + 'Lon', + 'Gian', + 'Savannah', + 'Trinity', + 'Harris', + 'Kamarion', + 'Aydenn', + 'Cale', + 'Neo', + 'Justus', + 'Mose', + 'Tiago', + 'Saverio', + 'Eligh', + 'Mikel', + 'Eliot', + 'Alvis', + 'Argenis', + 'Musa', + 'Lonny', + 'Thad', + 'Guido', + 'Ceasar', + 'Obed', + 'Pinchas', + 'Barton', + 'Durell', + 'Johnatha', + 'Aric', + 'Geovany', + 'Fransisco', + 'Jaheem', + 'Jarett', + 'Yeshua', + 'Karim', + 'Aayden', + 'Merrill', + 'Michele', + 'Jaydan', + 'Octavius', + 'Jermiah', + 'Alexavier', + 'Brandyn', + 'Arvid', + 'Brentley', + 'Sutton', + 'Coen', + 'Ameer', + 'Giovany', + 'Ishan', + 'Blaise', + 'Bayron', + 'Kamil', + 'Brooklyn', + 'Catherine', + 'Akira', + 'Briggs', + 'Damani', + 'Rasheen', + 'Rayford', + 'Moishe', + 'Ephraim', + 'Esequiel', + 'Kenyon', + 'Constantine', + 'Silvio', + 'Brain', + 'Daylon', + 'Raymon', + 'Ayush', + 'Lazer', + 'Telly', + 'Elan', + 'Stone', + 'Marland', + 'Donn', + 'Shamel', + 'Silvestre', + 'Zephyr', + 'Merrick', + 'Fausto', + 'Dedrick', + 'Cornell', + 'Whitney', + 'Derrell', + 'Mitsuo', + 'Lucious', + 'Tad', + 'Lyric', + 'Darrion', + 'Dannie', + 'Gayle', + 'Burl', + 'Jayquan', + 'Carrol', + 'Laquan', + 'Tyrek', + 'Natividad', + 'Casimer', + 'Jael', + 'Aven', + 'Arnaldo', + 'Yovani', + 'Laura', + 'Dejuan', + 'Dimitrios', + 'Yash', + 'Esai', + 'Zavion', + 'Ora', + 'Durward', + 'Bradly', + 'Hazel', + 'Che', + 'Richie', + 'Diana', + 'Alois', + 'Lynwood', + 'Luverne', + 'Zeke', + 'Dash', + 'Cairo', + 'Delvin', + 'Kawika', + 'Josemanuel', + 'Devean', + 'Sameer', + 'Seneca', + 'Presley', + 'Jed', + 'Malaki', + 'Dominque', + 'Dontae', + 'Dev', + 'Darey', + 'Reggie', + 'Izaak', + 'Manny', + 'Jere', + 'Minh', + 'Ryden', + 'Montana', + 'Kaleo', + 'Jacorey', + 'Ignatius', + 'Filiberto', + 'Cache', + 'Yitzchak', + 'Yaseen', + 'Kentrell', + 'Basil', + 'Ivy', + 'Migel', + 'Jalon', + 'Lenwood', + 'Ellwood', + 'Zakary', + 'Haiden', + 'Dontrell', + 'Braedon', + 'Lorne', + 'Trever', + 'Mikael', + 'Kenzo', + 'Javaris', + 'Ambrose', + 'Alain', + 'Columbus', + 'Leif', + 'Jerold', + 'Anwar', + 'Gabino', + 'Dillion', + 'Kelby', + 'Denzil', + 'Ulisses', + 'Sami', + 'Jahmir', + 'Elimelech', + 'Dock', + 'Zahir', + 'Hardy', + 'Florian', + 'Jewel', + 'Tobin', + 'Curley', + 'Mahdi', + 'Mccoy', + 'Jaquavious', + 'Justen', + 'Lino', + 'Teodoro', + 'Kazuo', + 'Lenard', + 'Robb', + 'Takashi', + 'Maison', + 'Merlyn', + 'Brecken', + 'Ricki', + 'Jet', + 'Lars', + 'Ulices', + 'Dereon', + 'Fox', + 'Ajay', + 'Geraldo', + 'Maksim', + 'Jullian', + 'Kalani', + 'Andrei', + 'Jaidyn', + 'Maxie', + 'Javen', + 'Gail', + 'Ely', + 'Caroline', + 'Amber', + 'Crystal', + 'Kiara', + 'Megan', + 'Reilly', + 'Eugenio', + 'Fisher', + 'Langston', + 'Gavriel', + 'Abhinav', + 'Dee', + 'Kace', + 'Axl', + 'Isabel', + 'Uziel', + 'Sabastian', + 'Rylee', + 'Eliazar', + 'Renato', + 'Harland', + 'Lavar', + 'Stefano', + 'Mayra', + 'Valentine', + 'Bud', + 'Hasan', + 'Zaden', + 'Truett', + 'Korbyn', + 'Toshio', + 'Stockton', + 'Edd', + 'Trystan', + 'Daylan', + 'Jayven', + 'Dewitt', + 'Kraig', + 'Wilford', + 'Celestino', + 'Jacobo', + 'Patryk', + 'Hailey', + 'Nainoa', + 'Haskell', + 'Sharif', + 'Jerad', + 'Raynaldo', + 'Jacques', + 'Jessi', + 'Geary', + 'Gaige', + 'Garnett', + 'Jakari', + 'Yonatan', + 'Eino', + 'Phong', + 'Jerel', + 'Benzion', + 'Quinten', + 'Amado', + 'Blas', + 'Kimberly', + 'Cuauhtemoc', + 'Aayan', + 'Catarino', + 'Jeromy', + 'Kyree', + 'Apolonio', + 'Boy', + 'Antwon', + 'Hakim', + 'Creed', + 'Shiloh', + 'Shepherd', + 'Garett', + 'Oakley', + 'Miller', + 'Dajuan', + 'Mattias', + 'Titan', + 'Immanuel', + 'Lamarcus', + 'Devontae', + 'Reef', + 'Brayson', + 'Grey', + 'Deante', + 'Yariel', + 'Makhi', + 'Jayse', + 'Corbyn', + 'Domenico', + 'Sedrick', + 'Deontae', + 'Kou', + 'Shant', + 'Willy', + 'Austyn', + 'Shloime', + 'Masen', + 'Linus', + 'Florentino', + 'Gionni', + 'Boden', + 'Torrey', + 'Minoru', + 'Daulton', + 'Kolten', + 'Jennings', + 'Noble', + 'Hersh', + 'Kelsey', + 'Nicholaus', + 'Florencio', + 'Nam', + 'Juelz', + 'Kainalu', + 'Destin', + 'Damarcus', + 'Jacolby', + 'Nikita', + 'Artis', + 'Bilal', + 'Kendell', + 'Alexsander', + 'Parth', + 'Esau', + 'Glennon', + 'Kohen', + 'Isacc', + 'Aleksander', + 'Vinh', + 'Trenten', + 'Koen', + 'Candelario', + 'Connie', + 'Aram', + 'Wolfgang', + 'Amit', + 'Om', + 'Shyheim', + 'Raven', + 'Kendra', + 'Eliel', + 'Viet', + 'Kenyatta', + 'Sky', + 'Binyomin', + 'Deanthony', + 'Lachlan', + 'Tory', + 'Kenton', + 'Tamir', + 'Kramer', + 'Deshaun', + 'Javian', + 'Haruo', + 'Rupert', + 'Jevon', + 'Shlome', + 'Danilo', + 'Vanessa', + 'Fernand', + 'Daveon', + 'Les', + 'Marko', + 'Delmer', + 'Marlyn', + 'Winfield', + 'Wes', + 'Rosevelt', + 'Rayshawn', + 'Tai', + 'Kalvin', + 'Jerardo', + 'Sarkis', + 'Bertrand', + 'Kaimana', + 'Kaitlyn', + 'Summer', + 'Veer', + 'Waymon', + 'Evin', + 'Andrey', + 'Iain', + 'Kimi', + 'Foster', + 'Servando', + 'Mychael', + 'Derik', + 'Ryon', + 'Rowen', + 'Mel', + 'Ibn', + 'Werner', + 'Jameel', + 'Avrum', + 'Nachman', + 'Jomar', + 'Rudolf', + 'Tyrique', + 'Rayburn', + 'Khalif', + 'Rondal', + 'Bijan', + 'Rohit', + 'Jeremie', + 'Kain', + 'Nicola', + 'Bode', + 'Brogan', + 'Trayvon', + 'Turner', + 'Dwain', + 'Konnor', + 'Lev', + 'Zayd', + 'Finnley', + 'Brantlee', + 'Deonta', + 'Demetrio', + 'Ajani', + 'Arther', + 'Bianca', + 'Takeo', + 'Harding', + 'Jareth', + 'Rigo', + 'Epifanio', + 'Nahum', + 'Carleton', + 'Cosmo', + 'Shigeru', + 'Josias', + 'Takeshi', + 'Jacobi', + 'Michal', + 'Dorris', + 'Treveon', + 'Jaxx', + 'Aren', + 'Tejas', + 'Beverly', + 'Geoff', + 'Maddux', + 'Camryn', + 'Burt', + 'Norwood', + 'Sholom', + 'Ahron', + 'Macario', + 'Carol', + 'Camdyn', + 'Gennaro', + 'Leeroy', + 'Pinchus', + 'Kaito', + 'Burnell', + 'Frantz', + 'Laron', + 'Clemente', + 'Chasen', + 'Neri', + 'Jerrell', + 'Kashawn', + 'Keola', + 'Alvan', + 'Amar', + 'Ubaldo', + 'Roque', + 'Zalmen', + 'Daylen', + 'Kadyn', + 'Gil', + 'Bernice', + 'Yosgart', + 'Shaan', + 'Yahel', + 'Elon', + 'Levon', + 'Kit', + 'Brodrick', + 'Gaven', + 'Kaidyn', + 'Ansel', + 'Jewell', + 'Mikhail', + 'Derian', + 'Elam', + 'Tye', + 'Leigh', + 'Wayde', + 'Rian', + 'Artemio', + 'Ibrahima', + 'Noa', + 'Autumn', + 'Kylie', + 'Pernell', + 'Britton', + 'Deondre', + 'Arlen', + 'Aman', + 'Kelley', + 'Eliud', + 'Dijon', + 'Imran', + 'Eulalio', + 'Juvenal', + 'Agapito', + 'Brant', + 'Nima', + 'Yisrael', + 'Yerik', + 'Ewan', + 'Lathan', + 'Adair', + 'Gentry', + 'Kyren', + 'Lian', + 'Tayshawn', + 'Alejandra', + 'Jeancarlos', + 'Keyon', + 'Jade', + 'Shayan', + 'June', + 'Christos', + 'Adrain', + 'Jarom', + 'Kathryn', + 'Thor', + 'Haven', + 'Duy', + 'Enmanuel', + 'Montavious', + 'Cortney', + 'Teagan', + 'Blayne', + 'Anselmo', + 'Leyton', + 'Jonny', + 'Braylin', + 'Albaro', + 'Pascual', + 'Gasper', + 'Waldo', + 'Tyreke', + 'Dylon', + 'Narciso', + 'Ebony', + 'Hilton', + 'Margaret', + 'Brighton', + 'Martavious', + 'Demetrios', + 'Kishan', + 'Ansh', + 'Treyton', + 'Albin', + 'Rashon', + 'Rony', + 'Krystian', + 'Amrom', + 'Korver', + 'Richardo', + 'Kayla', + 'Katelyn', + 'Milford', + 'Bishop', + 'Ottis', + 'Emmet', + 'Codey', + 'Ayub', + 'Isreal', + 'Karas', + 'Kendarius', + 'Isamu', + 'Kunta', + 'Jermey', + 'Arvin', + 'Kayleb', + 'Sione', + 'Taurean', + 'Tyron', + 'Mihir', + 'Rami', + 'Vincente', + 'Zayan', + 'Mahlon', + 'Clovis', + 'Kirt', + 'Dyllan', + 'Ramsey', + 'Jeramie', + 'Nikolaus', + 'Edsel', + 'Asael', + 'Andrik', + 'Lisa', + 'Sandro', + 'Desean', + 'Narek', + 'Kiran', + 'Elzie', + 'Jered', + 'Arlie', + 'Yahya', + 'Lizandro', + 'Rollin', + 'Khiry', + 'Yuvraj', + 'Jeancarlo', + 'Anay', + 'Freeman', + 'Stevan', + 'Keller', + 'Ledger', + 'Jasiel', + 'Jacinto', + 'Sherwin', + 'Beaux', + 'Campbell', + 'Sherwood', + 'Torrence', + 'Daryle', + 'Chevy', + 'Adiel', + 'Patricia', + 'Jameer', + 'Bilbo', + 'Jayvon', + 'Early', + 'Boruch', + 'Jadarius', + 'Alpha', + 'Amadou', + 'Reino', + 'Betty', + 'Moussa', + 'Wolf', + 'Jenna', + 'Grace', + 'Natalie', + 'Javonte', + 'Crawford', + 'Damir', + 'Mckinley', + 'Elden', + 'Jhon', + 'Lemuel', + 'Colston', + 'Donta', + 'Pearl', + 'Taquan', + 'Salman', + 'Palmer', + 'Muhammed', + 'Brennon', + 'Cashton', + 'Ysidro', + 'Salomon', + 'Ocean', + 'Anirudh', + 'Aksel', + 'Cal', + 'Ishmael', + 'Brenda', + 'Abran', + 'Rome', + 'Leighton', + 'Canyon', + 'Kael', + 'Amin', + 'Antoni', + 'Tiara', + 'Heather', + 'Christine', + 'Brittney', + 'Angela', + 'Johathan', + 'Cipriano', + 'Coltin', + 'Verne', + 'Darrien', + 'Eamon', + 'Oskar', + 'Mikah', + 'Matix', + 'Kooper', + 'Antonino', + 'Duwayne', + 'Dagoberto', + 'Kolt', + 'Sanjay', + 'Tayden', + 'Waverly', + 'Abrahan', + 'Diamond', + 'West', + 'Jefferey', + 'Shigeo', + 'Kabir', + 'Jamell', + 'Jaedyn', + 'Malcom', + 'Gadiel', + 'Manav', + 'Audie', + 'Hipolito', + 'Theron', + 'Codie', + 'General', + 'Lindy', + 'Carver', + 'Nat', + 'Jacari', + 'Khamari', + 'Wally', + 'Kay', + 'Anastacio', + 'Jaymes', + 'Skip', + 'Cheyne', + 'Dameon', + 'Geronimo', + 'Kevyn', + 'Toney', + 'Arden', + 'Dontavius', + 'Rasheem', + 'Geovani', + 'Gaspar', + 'Baltazar', + 'Bladimir', + 'Rashan', + 'Rulon', + 'Karan', + 'Jory', + 'Chet', + 'Abiel', + 'Lazarus', + 'Britt', + 'Rodriquez', + 'Akil', + 'Zuriel', + 'Rylen', + 'Aston', + 'Graysen', + 'Jaysen', + 'Hillel', + 'Alford', + 'Tyriq', + 'Cassidy', + 'Rahiem', + 'Juanmanuel', + 'Demetri', + 'Jayton', + 'Timoteo', + 'Infantof', + 'Braedyn', + 'Corde', + 'Bee', + 'Valente', + 'Gildardo', + 'Feliciano', + 'Dalvin', + 'Tadashi', + 'Claudie', + 'Teng', + 'Genesis', + 'Tayler', + 'Joeangel', + 'Teruo', + 'Tylan', + 'Markel', + 'Linda', + 'Taven', + 'Pierson', + 'Newton', + 'Keandre', + 'Jayvion', + 'Donavon', + 'Encarnacion', + 'Melton', + 'Ritchie', + 'Erika', + 'Edgard', + 'Christoper', + 'Rocio', + 'Alvie', + 'Josedejesus', + 'Dashaun', + 'Travion', + 'Johny', + 'Marcell', + 'Monique', + 'Caitlin', + 'Durwood', + 'Gustav', + 'Rosalio', + 'Farhan', + 'Benuel', + 'Lashawn', + 'Shakeem', + 'Ocie', + 'Yasir', + 'Szymon', + 'Aaryan', + 'Hansel', + 'Slater', + 'Samarth', + 'Kiyan', + 'Storm', + 'Ava', + 'Yassin', + 'Dayquan', + 'Sherrill', + 'Khari', + 'Anas', + 'Cheskel', + 'Kamryn', + 'Zyaire', + 'Cristo', + 'Christofer', + 'Akhil', + 'Shreyas', + 'Ryley', + 'Gibson', + 'Haziel', + 'Talen', + 'Bracken', + 'Dallen', + 'Rashard', + 'Rockwell', + 'Colie', + 'Del', + 'Jihad', + 'Simeon', + 'Jahmari', + 'Ashwin', + 'Shraga', + 'Cian', + 'Alistair', + 'Cartier', + 'Stoney', + 'Verlyn', + 'Kavon', + 'Konrad', + 'Conrado', + 'Colon', + 'Randel', + 'Christ', + 'Jeremey', + 'Raleigh', + 'Lauro', + 'Dionicio', + 'Kauan', + 'Piotr', + 'Cleon', + 'Malique', + 'Rand', + 'Fritz', + 'Cordaro', + 'Pietro', + 'Faris', + 'Ezio', + 'Atharv', + 'Karthik', + 'Jahsir', + 'Saleem', + 'Abdoulaye', + 'Jiovanni', + 'Ezrah', + 'Everest', + 'Bronx', + 'Kruz', + 'Viktor', + 'Yasiel', + 'Thatcher', + 'Michelangelo', + 'Alaric', + 'Oneal', + 'Sahib', + 'Osiris', + 'Teo', + 'Joseangel', + 'Nate', + 'Walton', + 'Yousif', + 'Ezzard', + 'Yamil', + 'Angus', + 'Jhonny', + 'Fabio', + 'Darold', + 'Junious', + 'Atreyu', + 'Beck', + 'Adriano', + 'Amani', + 'Trevin', + 'Rudra', + 'Parsa', + 'Breon', + 'Umar', + 'Taha', + 'Cormac', + 'Yossi', + 'Jaison', + 'Saad', + 'Shloimy', + 'Chesky', + 'Ayman', + 'Alicia', + 'Chadd', + 'Broc', + 'Cynthia', + 'Reynold', + 'Ismail', + 'Gaylord', + 'Saburo', + 'Kao', + 'Masato', + 'Alfonzo', + 'Joshue', + 'Earvin', + 'Patric', + 'Robinson', + 'Serjio', + 'Gavino', + 'Stanford', + 'Thanh', + 'Kamren', + 'Vikram', + 'Roan', + 'Jeronimo', + 'Zahid', + 'Anjel', + 'Jayro', + 'Skye', + 'Baylor', + 'Drayden', + 'Pheng', + 'Yeng', + 'Wilber', + 'Meng', + 'Arik', + 'Jamarius', + 'Avigdor', + 'Ladarrius', + 'Nicklaus', + 'Gatlin', + 'Boone', + 'Jacen', + 'Antonia', + 'Kyran', + 'Quintavius', + 'Estil', + 'Casimiro', + 'Prentice', + 'Jodie', + 'Rashaad', + 'Konstantinos', + 'Allison', + 'Sophia', + 'Makayla', + 'Lillian', + 'Zymir', + 'Canaan', + 'Delfino', + 'Benton', + 'Apolinar', + 'Winford', + 'Dayne', + 'Shivam', + 'Fredi', + 'Yves', + 'Jarrell', + 'Ignazio', + 'Gamaliel', + 'Young', + 'Kiefer', + 'Juanjose', + 'Rehan', + 'Kegan', + 'Davante', + 'Naim', + 'Lyman', + 'Erskine', + 'Toivo', + 'Darrian', + 'Jad', + 'Ender', + 'Remi', + 'Rishaan', + 'Shaurya', + 'Viaan', + 'Chelsea', + 'Molly', + 'Sara', + 'Leib', + 'Azriel', + 'Howell', + 'Briar', + 'Korben', + 'Manning', + 'Job', + 'Brandt', + 'Jaedon', + 'Ozzy', + 'Cordarius', + 'Lannie', + 'Stanton', + 'Radames', + 'Blease', + 'Zyon', + 'Chadrick', + 'Watson', + 'Kentavious', + 'Taurus', + 'Adin', + 'Jordin', + 'Bryden', + 'Susumu', + 'Tamotsu', + 'Yukio', + 'Granville', + 'Ashby', + 'Tristyn', + 'Devaughn', + 'Deric', + 'Cecilio', + 'Pershing', + 'Noboru', + 'Rashaun', + 'Masaichi', + 'Juventino', + 'Norton', + 'Serafin', + 'Windell', + 'Cris', + 'Curtiss', + 'Boris', + 'Elio', + 'Williams', + 'Trung', + 'Torao', + 'Karon', + 'Canon', + 'Tyrik', + 'Naythan', + 'Michaelangelo', + 'Kavin', + 'Akshay', + 'Broden', + 'Quran', + 'Rishabh', + 'Hilbert', + 'Abbas', + 'Damoni', + 'Dillard', + 'Tigran', + 'Romel', + 'Chip', + 'Aeden', + 'Deagan', + 'Treyson', + 'Brannon', + 'Tremaine', + 'Fay', + 'Bryton', + 'Lucky', + 'Izak', + 'Edan', + 'Casper', + 'Koda', + 'Saquan', + 'Alcide', + 'Quinlan', + 'Maddex', + 'Hoyle', + 'Sandra', + 'Joshuah', + 'Lindsay', + 'Donato', + 'Jancarlos', + 'Kalin', + 'Zigmund', + 'Kalen', + 'Jalil', + 'Bonifacio', + 'Gabrielle', + 'Destiny', + 'Cheyenne', + 'Ulyses', + 'Rueben', + 'Markell', + 'Jermel', + 'Corwin', + 'Justine', + 'Idris', + 'Pilar', + 'Torrance', + 'Raeford', + 'Olan', + 'Octavious', + 'Quantavious', + 'Modesto', + 'Kashton', + 'Librado', + 'Bonnie', + 'Lois', + 'Justo', + 'Mahmoud', + 'Divine', + 'Baylen', + 'Rakeem', + 'Diesel', + 'Kyng', + 'Daisy', + 'Armon', + 'Joseantonio', + 'Montel', + 'Gearld', + 'Cloyd', + 'Lindell', + 'Nile', + 'Kashif', + 'Johnmichael', + 'Aramis', + 'Leopold', + 'Kamal', + 'Jerrad', + 'Jadin', + 'Mykel', + 'Jahlil', + 'Cheng', + 'Ezriel', + 'Aria', + 'Dajon', + 'Holt', + 'Chauncey', + 'Karsen', + 'Stryker', + 'Olaf', + 'Reno', + 'Colter', + 'Schuyler', + 'Orvil', + 'Auden', + 'Eyan', + 'Tyce', + 'Barbara', + 'Zamir', + 'Alexi', + 'Braelyn', + 'Brook', + 'Marchello', + 'Tyrel', + 'Oracio', + 'Jalin', + 'Verlon', + 'Raj', + 'Lindsey', + 'Andon', + 'Devlin', + 'Brysen', + 'Harman', + 'Treyvon', + 'Foy', + 'Arash', + 'Cuong', + 'Torin', + 'Rommel', + 'Lorenza', + 'Vishal', + 'Kenya', + 'Heber', + 'Victoriano', + 'Shay', + 'Tremayne', + 'Natanael', + 'Zachry', + 'Eros', + 'Veronica', + 'Wayland', + 'Rayquan', + 'Ana', + 'Jaceon', + 'Yida', + 'Rahmel', + 'Alter', + 'Lamarion', + 'Tavion', + 'Javin', + 'Lawerence', + 'Alessio', + 'Kristen', + 'Jacqueline', + 'Oren', + 'Aahil', + 'Adyan', + 'Augustin', + 'Coleton', + 'Wilfrid', + 'Dezmond', + 'Keelan', + 'Ike', + 'Kanoa', + 'Kedrick', + 'Chue', + 'Danniel', + 'Jowell', + 'Micahel', + 'Yonathan', + 'Finnian', + 'Garfield', + 'Joao', + 'Ezell', + 'Masaru', + 'Yoshito', + 'Pasco', + 'Yechezkel', + 'Shloma', + 'Adnan', + 'Jaythan', + 'Laith', + 'Greysen', + 'Maddix', + 'Alfonse', + 'Ernst', + 'Hobart', + 'Tavin', + 'Dajour', + 'Cy', + 'Estel', + 'Osman', + 'Vedant', + 'Rolf', + 'Ova', + 'Colson', + 'Kelan', + 'Oumar', + 'Olivier', + 'Seichi', + 'Tayson', + 'Roshan', + 'Blane', + 'Baxter', + 'Vu', + 'Tam', + 'Pao', + 'Wardell', + 'Davonta', + 'Montrell', + 'Ravi', + 'Durrell', + 'Bastian', + 'Aj', + 'Ren', + 'Loki', + 'Kairo', + 'Rock', + 'Mylo', + 'Lavell', + 'Bjorn', + 'Arvil', + 'Reinhold', + 'Yesenia', + 'Carsen', + 'Zephaniah', + 'Renzo', + 'Willem', + 'Unique', + 'Elmore', + 'Kalob', + 'Payne', + 'Leeland', + 'Naseem', + 'Yusef', + 'Aboubacar', + 'Ioannis', + 'Bohdan', + 'Javien', + 'Jakobi', + 'Dempsey', + 'Xavian', + 'Antavious', + 'Jc', + 'Dara', + 'Obie', + 'Celso', + 'Tyrin', + 'Eian', + 'Elgin', + 'Jaylyn', + 'Brandin', + 'Adyn', + 'Gabriela', + 'Jaidon', + 'Zavian', + 'Lonzo', + 'Elwin', + 'Tsutomu', + 'Jeanluc', + 'Caeden', + 'Auston', + 'Jasson', + 'Omid', + 'Gray', + 'Vang', + 'Nancy', + 'Nader', + 'Kylen', + 'Jarell', + 'Prentiss', + 'Tahir', + 'Ahmir', + 'Terell', + 'Ludwig', + 'Biagio', + 'Douglass', + 'Nafis', + 'Harlem', + 'Phineas', + 'Lochlan', + 'Hermon', + 'Wilder', + 'Aniello', + 'Attilio', + 'Shiv', + 'Montgomery', + 'Bowie', + 'Aries', + 'Itzae', + 'Isa', + 'Huxley', + 'Elwyn', + 'Advik', + 'Mahamadou', + 'Grayden', + 'Landin', + 'Decker', + 'Dakotah', + 'Ella', + 'Md', + 'Shayaan', + 'Isidor', + 'Joahan', + 'Tillman', + 'Jafet', + 'Panagiotis', + 'Jajuan', + 'Cristhian', + 'Demetric', + 'Zaylen', + 'Kacen', + 'Sloan', + 'Shedrick', + 'Denilson', + 'Buck', + 'Dyland', + 'Aris', + 'Demonte', + 'Telvin', + 'Raynard', + 'Quantavius', + 'Neftali', + 'Alma', + 'Kadarius', + 'Philippe', + 'Laurel', + 'Vadhir', + 'Juandiego', + 'Alekzander', + 'Napoleon', + 'Fabrizio', + 'Abisai', + 'Yasin', + 'Kamran', + 'Ole', + 'Nicolai', + 'Erling', + 'Jathan', + 'Zen', + 'Shiven', + 'Keshaun', + 'Nikola', + 'Loy', + 'Usman', + 'Concepcion', + 'Verlin', + 'Dedric', + 'Derwin', + 'Graig', + 'Serge', + 'Merritt', + 'Kervin', + 'Maleek', + 'Baldomero', + 'Germaine', + 'Hampton', + 'Shan', + 'Alvino', + 'Davy', + 'Arlington', + 'Brandy', + 'Timmie', + 'Andrae', + 'Terrion', + 'Quang', + 'Jeb', + 'Clem', + 'Judd', + 'Severo', + 'Woody', + 'Toan', + 'Alonza', + 'Gardner', + 'Delton', + 'Vinny', + 'Vilas', + 'Welton', + 'Sabian', + 'Dell', + 'Randolf', + 'Tyren', + 'Glenwood', + 'Antwain', + 'Savon', + 'Lesley', + 'Rashid', + 'Tavian', + 'Marvens', + 'Aleksandr', + 'Vivek', + 'Maximino', + 'Pavel', + 'Renee', + 'Charly', + 'Donell', + 'Shariff', + 'Ennis', + 'Menashe', + 'Ygnacio', + 'Hoke', + 'Lebron', + 'Hillard', + 'Xavion', + 'Nicolaus', + 'Kemari', + 'Sammuel', + 'Jessiah', + 'Virgle', + 'Niklas', + 'Allante', + 'Keenen', + 'Albino', + 'Rivaldo', + 'Jospeh', + 'Broadus', + 'Trequan', + 'Finis', + 'Sabas', + 'Abdoul', + 'Tyronne', + 'Tyreik', + 'Tyriek', + 'Linton', + 'Jashawn', + 'Ivey', + 'Janiel', + 'Jayme', + 'Lamarr', + 'Tiernan', + 'Meilech', + 'Fitzgerald', + 'Jonnathan', + 'Tashawn', + 'Verl', + 'Nichoals', + 'Urban', + 'Marquan', + 'Montez', + 'Akshaj', + 'Syrus', + 'Nehemias', + 'Nova', + 'Makaio', + 'Joselito', + 'Armin', + 'Monica', + 'Natasha', + 'Leonce', + 'Corby', + 'Doris', + 'Chancellor', + 'Yonah', + 'Gaston', + 'Alston', + 'Tyreese', + 'Gaither', + 'Donna', + 'Graeme', + 'Frances', + 'Earlie', + 'Oral', + 'Ruby', + 'Krishna', + 'Berkley', + 'Viraj', + 'Jame', + 'Judge', + 'Denim', + 'Guilherme', + 'Salim', + 'Rondell', + 'Marek', + 'Zac', + 'Seven', + 'Stellan', + 'Calder', + 'Eithan', + 'Eliam', + 'Gareth', + 'Auther', + 'Theodis', + 'Denzell', + 'Octave', + 'Destry', + 'Bartholomew', + 'Rajiv', + 'Jaxxon', + 'Maxson', + 'Adler', + 'Tyran', + 'Carnell', + 'Alben', + 'Saif', + 'Merwin', + 'Binyamin', + 'Hayward', + 'Arav', + 'Berry', + 'Daunte', + 'Arvo', + 'Gerhard', + 'Selmer', + 'Davie', + 'Courtland', + 'Athanasios', + 'Ori', + 'Aadi', + 'Kamar', + 'Jeremih', + 'Jayvian', + 'Doyne', + 'Macarthur', + 'Elza', + 'Harden', + 'Soham', + 'Alder', + 'Josemaria', + 'Iziah', + 'Jin', + 'Woodie', + 'Alfie', + 'Stefon', + 'Oswald', + 'Talmage', + 'Leander', + 'Jancarlo', + 'Sasha', + 'Lorin', + 'Roby', + 'Juanmiguel', + 'Johannes', + 'Allie', + 'Demetris', + 'Sharod', + 'Mynor', + 'Lex', + 'Tito', + 'Domonique', + 'Seferino', + 'Jourdan', + 'Marcial', + 'Herminio', + 'Mikal', + 'Alegandro', + 'Makana', + 'Bb', + 'Jarret', + 'Jemel', + 'Kareen', + 'Sierra', + 'Michale', + 'Jalyn', + 'Meredith', + 'Gracie', + 'Dawud', + 'Raylon', + 'Avan', + 'Dayshawn', + 'Livan', + 'Kendal', + 'Otho', + 'Dung', + 'Reuven', + 'Karmelo', + 'Myer', + 'Tadao', + 'Bentzion', + 'Tex', + 'Jamin', + 'Clois', + 'Sadao', + 'Tetsuo', + 'Izrael', + 'Avion', + 'Katsumi', + 'Gerrit', + 'Jamauri', + 'Kunal', + 'Nickolaus', + 'Hoang', + 'Bernabe', + 'Khristian', + 'Arne', + 'Javeon', + 'Vasilios', + 'Noach', + 'Ruger', + 'Kutter', + 'Kyden', + 'Marshal', + 'Jaelon', + 'Raffi', + 'Rito', + 'Parrish', + 'Duvid', + 'Jamario', + 'Verle', + 'Harmon', + 'Thai', + 'Claire', + 'Daiquan', + 'Didier', + 'Jonnie', + 'Arlan', + 'Taggart', + 'Henri', + 'Rogan', + 'Woodford', + 'Maceo', + 'Nyjah', + 'Smith', + 'Syncere', + 'Ballard', + 'Kenichi', + 'Khaled', + 'Dwaine', + 'Mathieu', + 'Ousmane', + 'Emmit', + 'Aayush', + 'Elyas', + 'Taysom', + 'Azaiah', + 'Axle', + 'Ander', + 'Azaan', + 'Vic', + 'Terrel', + 'Alen', + 'Fabricio', + 'Yeshaya', + 'Greggory', + 'Derrik', + 'Esgar', + 'Selwyn', + 'Binh', + 'Tarun', + 'Quoc', + 'Corry', + 'Wylie', + 'Jadan', + 'Aamir', + 'Barron', + 'Ciaran', + 'Melville', + 'Bronislaus', + 'Fong', + 'Hakop', + 'Jashua', + 'Stanislaus', + 'Keion', + 'Timmothy', + 'Kenan', + 'Banks', + 'Ammar', + 'Maxfield', + 'Tyre', + 'Chistian', + 'Son', + 'Shaka', + 'Jahmal', + 'Jerell', + 'Beckam', + 'Zakariya', + 'Jayshawn', + 'Orvel', + 'Yona', + 'Derrek', + 'Warner', + 'Rollie', + 'Adelbert', + 'Von', + 'Kathleen', + 'April', + 'Nikolaos', + 'Alika', + 'Barrington', + 'Inez', + 'Len', + 'Arsh', + 'Elyjah', + 'Eshaan', + 'Shayden', + 'Jaykob', + 'Raziel', + 'Makoa', + 'Cornelio', + 'Rufino', + 'Leamon', + 'Terrill', + 'Hai', + 'Jonerik', + 'Hamilton', + 'Lindbergh', + 'Enos', + 'Sabino', + 'Ara', + 'Raudel', + 'Jones', + 'Cedar', + 'Yohan', + 'Janet', + 'Archibald', + 'Boaz', + 'Cleotha', + 'Dontez', + 'Eldridge', + 'Abhay', + 'Butch', + 'Jayvien', + 'Rowland', + 'Kimo', + 'Gurney', + 'Virgilio', + 'Alfonza', + 'Perley', + 'Silverio', + 'Amilcar', + 'Kapena', + 'Issak', + 'Josemiguel', + 'Mikey', + 'Camille', + 'Gershon', + 'Mehki', + 'Carsten', + 'Lavelle', + 'Jamere', + 'Natale', + 'Elya', + 'Antwone', + 'Pedrohenrique', + 'Kyjuan', + 'Shakim', + 'Evaristo', + 'Lionell', + 'Helen', + 'Aariz', + 'Paige', + 'Jaquavius', + 'Adolphus', + 'Faith', + 'Breanna', + 'Martavius', + 'Armondo', + 'Yobani', + 'Missael', + 'Marcellus', + 'Rishab', + 'Jaxsen', + 'Jahleel', + 'Bernell', + 'Woodroe', + 'Breck', + 'Paden', + 'Trumaine', + 'Rogerio', + 'Cleve', + 'Ameen', + 'Jermain', + 'Shakir', + 'Berl', + 'Conley', + 'Vinson', + 'Andru', + 'Andrue', + 'Suraj', + 'Ruvim', + 'Rodriguez', + 'Benji', + 'Kylon', + 'Matheo', + 'Kellin', + 'Karsyn', + 'Izan', + 'Caysen', + 'Caison', + 'Witten', + 'Issa', + 'Audrey', + 'Sekou', + 'Januel', + 'Christpher', + 'Octaviano', + 'Jereme', + 'Basilio', + 'Kaine', + 'Jayvyn', + 'Vishnu', + 'Umberto', + 'Keondre', + 'Delroy', + 'Herve', + 'Rakim', + 'Denton', + 'Donavin', + 'Elder', + 'Ger', + 'Jazmin', + 'Schneider', + 'Ethyn', + 'Davien', + 'Cross', + 'Reginal', + 'Maksymilian', + 'Rahim', + 'Ridge', + 'Ved', + 'Bartosz', + 'Kaye', + 'Quamir', + 'Jasmin', + 'Diante', + 'Codi', + 'Khamani', + 'Juliocesar', + 'Lydell', + 'Dakari', + 'Eluzer', + 'Daniyal', + 'Isidoro', + 'Yousuf', + 'Rider', + 'Winthrop', + 'Diogo', + 'Kejuan', + 'Micaiah', + 'Ransom', + 'Rolla', + 'Leibish', + 'Ilyas', + 'Arham', + 'Adham', + 'Abdulrahman', + 'Lateef', + 'Rahmir', + 'Kollin', + 'Jamaine', + 'Khary', + 'De', + 'Jabbar', + 'Hardin', + 'Deryl', + 'Yanky', + 'Aviel', + 'Boubacar', + 'Eshan', + 'Hanley', + 'Hussain', + 'Tylon', + 'Leldon', + 'Raoul', + 'Braheem', + 'Kaseem', + 'Tyshaun', + 'Rashaan', + 'Kordell', + 'Anil', + 'Devion', + 'Mervyn', + 'Shaquil', + 'Shaquill', + 'Shaul', + 'Musab', + 'Muad', + 'Tomasz', + 'Madeline', + 'Delante', + 'Jahari', + 'Leah', + 'Tamika', + 'Britney', + 'Jeriel', + 'Yidel', + 'Jarad', + 'Oneil', + 'Fransico', + 'Shamir', + 'Carmello', + 'Abdulahi', + 'Shneur', + 'Yehudah', + 'Brown', + 'Sylvan', + 'Dontay', + 'French', + 'Griffen', + 'Faisal', + 'Dru', + 'Demitri', + 'Faron', + 'Deloy', + 'Juston', + 'Charleston', + 'Farrell', + 'Tab', + 'Donaciano', + 'Candido', + 'Joyce', + 'Marquel', + 'Lamonte', + 'Raheen', + 'Dashon', + 'Hieu', + 'Tyus', + 'Ciro', + 'Naeem', + 'Rush', + 'Keifer', + 'Christion', + 'Bladen', + 'Kobie', + 'Darell', + 'Mouhamed', + 'Jia', + 'Shepard', + 'Price', + 'Kasyn', + 'Truitt', + 'Jenson', + 'Aizen', + 'Markeith', + 'Braylan', + 'Jonmichael', + 'Damond', + 'Jaycion', + 'Platon', + 'Amaury', + 'Amaan', + 'Daven', + 'Tobey', + 'Hymen', + 'Altariq', + 'Jacory', + 'Ashtin', + 'Domonic', + 'Demari', + 'Denise', + 'Abimael', + 'Izaya', + 'Jovon', + 'Harout', + 'Caelan', + 'Donal', + 'Martel', + 'Jaskaran', + 'Alante', + 'Bradon', + 'Deborah', + 'Harrell', + 'Kaipo', + 'Klayton', + 'Danthony', + 'Justino', + 'Kamuela', + 'Barrie', + 'Argelis', + 'Dolores', + 'Jahaziel', + 'Iram', + 'Adian', + 'Rance', + 'Karsten', + 'Christain', + 'Jamarian', + 'Yee', + 'Adriana', + 'Jamichael', + 'Waino', + 'Anh', + 'Casmer', + 'Ronnell', + 'Tong', + 'Vicent', + 'Jarius', + 'Tiburcio', + 'Burdette', + 'Amadeo', + 'Kevan', + 'Arlyn', + 'Derald', + 'Waleed', + 'Jabez', + 'Khoa', + 'Neville', + 'Susan', + 'Leandre', + 'Jorgeluis', + 'Angelica', + 'Regan', + 'Froylan', + 'Tevita', + 'Sagar', + 'Drayton', + 'Zade', + 'Karriem', + 'Townes', + 'Ram', + 'Jaceyon', + 'Keng', + 'Isao', + 'Unkown', + 'Vivian', + 'Mamoru', + 'Dyllon', + 'Hagop', + 'Masami', + 'Shoichi', + 'Landan', + 'Cadence', + 'Yanixan', + 'Xzavion', + 'Javan', + 'Avian', + 'Cadyn', + 'Collier', + 'Clarance', + 'Karen', + 'Christy', + 'Toriano', + 'Diallo', + 'Mateus', + 'Caio', + 'Larue', + 'Gilmer', + 'Rhyan', + 'Elijiah', + 'Curren', + 'Souleymane', + 'Deklan', + 'Zakaria', + 'Hayk', + 'Ric', + 'Briley', + 'Oval', + 'Lovell', + 'Daryn', + 'Franz', + 'Spurgeon', + 'Giacomo', + 'Orrin', + 'Vester', + 'Taran', + 'Salem', + 'Naveen', + 'Linkin', + 'Kallen', + 'Kongmeng', + 'Patrice', + 'Bibb', + 'Arjan', + 'Fateh', + 'Clive', + 'Pharaoh', + 'Subhan', + 'Rayaan', + 'Zebulon', + 'Webster', + 'Raghav', + 'Zakai', + 'Ekam', + 'Caspian', + 'Atom', + 'Athen', + 'Esdras', + 'Vihan', + 'Ronav', + 'Arrow', + 'Izek', + 'Gaines', + 'Trajan', + 'Onofrio', + 'Romello', + 'Ramone', + 'Symir', + 'Kanyon', + 'Shomari', + 'Christo', + 'Anthoney', + 'Giovonni', + 'Gurshan', + 'Nathon', + 'Zach', + 'Jhonatan', + 'Shakur', + 'Favio', + 'Imani', + 'Asad', + 'Brien', + 'Aureliano', + 'Fischer', + 'Yadier', + 'Marino', + 'Kimball', + 'Saleh', + 'Greco', + 'Helmer', + 'Sai', + 'Khai', + 'Marius', + 'Joy', + 'Amauri', + 'Tegan', + 'Darl', + 'Cosimo', + 'Armond', + 'Yecheskel', + 'Natan', + 'Shabazz', + 'Devine', + 'Fabrice', + 'Tarek', + 'Renaldo', + 'Jarrel', + 'Gamal', + 'Rajesh', + 'Lavon', + 'Ahnaf', + 'Cono', + 'Gaspare', + 'Chas', + 'Jaspreet', + 'Tevon', + 'Kush', + 'Nuchem', + 'Jostin', + 'Wm', + 'Darnel', + 'Thurston', + 'Maliek', + 'Shakeel', + 'Coolidge', + 'Shaheed', + 'Anastasios', + 'Wesson', + 'Humza', + 'Kofi', + 'Jamelle', + 'Davey', + 'Llewellyn', + 'Nashawn', + 'Odie', + 'Jun', + 'Jahmere', + 'Bienvenido', + 'Safwan', + 'Mordche', + 'Demarius', + 'Cillian', + 'Alexandros', + 'Nochum', + 'Shareef', + 'Pawel', + 'Theadore', + 'Dorothy', + 'Geno', + 'Haris', + 'Dayvon', + 'Lemarcus', + 'Rayvon', + 'Laird', + 'Zayvion', + 'Dennie', + 'Dwane', + 'Orvis', + 'Chalmer', + 'Adil', + 'Zamari', + 'Kodi', + 'Braxtyn', + 'Fahim', + 'Merl', + 'Name', + 'Aaiden', + 'Dyson', + 'Westyn', + 'Wells', + 'Niles', + 'Nabil', + 'Kaelan', + 'Dmitri', + 'Demitrius', + 'Arlis', + 'Reco', + 'Glendon', + 'Abhishek', + 'Jammie', + 'Grabiel', + 'Jerson', + 'Gerhardt', + 'Kyrin', + 'Kipton', + 'Bear', + 'Jaciel', + 'Dakoda', + 'Kaelin', + 'Keilan', + 'Brendyn', + 'Fortino', + 'Diondre', + 'Arin', + 'Cleophus', + 'Dimas', + 'Caine', + 'Jakoby', + 'Hagan', + 'Layden', + 'Calen', + 'Nils', + 'Cisco', + 'Jerrick', + 'Gevork', + 'Mckenzie', + 'Justis', + 'Coltyn', + 'Brazos', + 'Jaycen', + 'Kemauri', + 'Tyrus', + 'Zaidyn', + 'Lenin', + 'Karlos', + 'Shrey', + 'Edric', + 'Tino', + 'Macklin', + 'Nevan', + 'Lawrance', + 'Arno', + 'Irby', + 'Namir', + 'Chayse', + 'Ronit', + 'Clemens', + 'Giorgio', + 'Khriz', + 'Khang', + 'Zidane', + 'Nomar', + 'Glade', + 'Doyce', + 'Kaya', + 'Surya', + 'Jaelen', + 'Vernell', + 'Issiah', + 'Henderson', + 'Jessejames', + 'Gaylen', + 'Aldahir', + 'An', + 'Asencion', + 'Garner', + 'Treston', + 'Evans', + 'Salome', + 'Cyle', + 'Sang', + 'Isaih', + 'Kirkland', + 'Loyal', + 'Jonpaul', + 'Cindy', + 'Bao', + 'Laurie', + 'Monico', + 'Kiptyn', + 'Toribio', + 'Cresencio', + 'Ruperto', + 'Dat', + 'Rustin', + 'Kendric', + 'Miquel', + 'Hasani', + 'Caron', + 'Jarron', + 'Enrigue', + 'Evelyn', + 'Paulino', + 'Eligio', + 'Melchor', + 'Deshon', + 'Johndavid', + 'Cliffton', + 'Ovidio', + 'Jacorian', + 'Laken', + 'Aedyn', + 'Ichiro', + 'Derion', + 'Sharon', + 'Yasuo', + 'Masayuki', + 'Andrez', + 'Dustyn', + 'Toua', + 'Jossue', + 'Zakkary', + 'Bernardino', + 'Deward', + 'Joanthan', + 'Sandeep', + 'Hercules', + 'Claudia', + 'Sampson', + 'Jacobe', + 'Hulon', + 'Ventura', + 'Blade', + 'Jayzen', + 'Jarren', + 'Nakoa', + 'Chan', + 'Jerrel', + 'Isamar', + 'Artie', + 'Amy', + 'Meghan', + 'Rockey', + 'Sixto', + 'Ascencion', + 'Damonte', + 'Golden', + 'Bubba', + 'Randle', + 'Adelard', + 'Rumaldo', + 'Nieves', + 'Marshaun', + 'Kavion', + 'Mikolaj', + 'Brees', + 'Gayland', + 'Herb', + 'Quenton', + 'Flint', + 'Lennie', + 'Tramaine', + 'Nadir', + 'Timur', + 'Keshav', + 'Malek', + 'Ozzie', + 'Dresden', + 'Eliah', + 'Benaiah', + 'Muhsin', + 'Walt', + 'Damen', + 'Enoc', + 'Giancarlos', + 'Darsh', + 'Maximilliano', + 'Yaniel', + 'Jeevan', + 'Malakhi', + 'Viggo', + 'Karlo', + 'Yosgar', + 'Xavior', + 'Frazier', + 'Orin', + 'Payson', + 'Tonatiuh', + 'Amando', + 'Angad', + 'Gibran', + 'Eben', + 'Deaundre', + 'Rajon', + 'Anand', + 'Andree', + 'Dany', + 'Kayvon', + 'Joell', + 'Jahsiah', + 'Rosaire', + 'Kc', + 'Page', + 'Salvadore', + 'Arjen', + 'Torey', + 'Manraj', + 'Lyam', + 'Mazen', + 'Autry', + 'Coopar', + 'Ranveer', + 'Santhiago', + 'Ronen', + 'Remmy', + 'Kamauri', + 'Andra', + 'Sohan', + 'Cayetano', + 'Jarrad', + 'Fortunato', + 'Magdaleno', + 'Dorman', + 'Cesario', + 'Doroteo', + 'Roddy', + 'Matilde', + 'Lafayette', + 'Edelmiro', + 'Higinio', + 'Yancy', + 'Zvi', + 'Pascal', + 'Timm', + 'Dickey', + 'Spiros', + 'Georgios', + 'Jarid', + 'Johnatho', + 'Nachum', + 'Efrem', + 'Stafford', + 'Pajtim', + 'Amelia', + 'Jada', + 'Lily', + 'Lydia', + 'Sherrod', + 'Stedman', + 'Ardis', + 'Levy', + 'Ulysse', + 'Zalman', + 'Marquette', + 'Gabe', + 'Blaize', + 'Ashanti', + 'Shaheem', + 'Hervey', + 'Abbott', + 'Boleslaw', + 'Tyshon', + 'Kimani', + 'Beecher', + 'Diquan', + 'Eulogio', + 'Arvel', + 'Kennth', + 'Benigno', + 'Luz', + 'Dionisio', + 'Eustacio', + 'Trino', + 'Eldred', + 'Primitivo', + 'Perfecto', + 'Delma', + 'Cosme', + 'Milburn', + 'Shameek', + 'Quayshaun', + 'Evert', + 'Green', + 'Brylan', + 'Crit', + 'Haskel', + 'Ancil', + 'Rayhan', + 'Rose', + 'Gianfranco', + 'Matan', + 'Derin', + 'Artem', + 'Abhiram', + 'Yovanni', + 'Stevenson', + 'Crue', + 'Krue', + 'Jethro', + 'Jakai', + 'Mattix', + 'Daxon', + 'Dallan', + 'Murl', + 'Harsh', + 'Uzziel', + 'Kemarion', + 'Jashaun', + 'Rodman', + 'Elie', + 'Desi', + 'Malikai', + 'Angello', + 'Amogh', + 'Advaith', + 'Adryan', + 'Nazareth', + 'Adolf', + 'Bosco', + 'Arshan', + 'Abdulaziz', + 'Theseus', + 'Riaan', + 'Reza', + 'Radley', + 'Mars', + 'Kirin', + 'Kiaan', + 'Evander', + 'Indiana', + 'Hanson', + 'Viliami', + 'Jaydenn', + 'Ilya', + 'Draco', + 'Riyan', + 'Onyx', + 'Xian', + 'Khristopher', + 'Ayrton', + 'Aurelius', + 'Crosley', + 'Obadiah', + 'Nihal', + 'Rithvik', + 'Constantino', + 'Jeyden', + 'Jaycee', + 'Bane', + 'Aakash', + 'Aniket', + 'Mathis', + 'Maximos', + 'Kohl', + 'Fuquan', + 'Rahman', + 'Aziel', + 'Alexys', + 'Iverson', + 'Marck', + 'Criss', + 'Arsen', + 'Angelgabriel', + 'Ronak', + 'Selvin', + 'Ibraheem', + 'Yordi', + 'Taylen', + 'Javari', + 'Jairus', + 'Hamzah', + 'Sacha', + 'Nayan', + 'Marciano', + 'Aneesh', + 'Manfred', + 'Adal', + 'Bernhard', + 'Jeovanny', + 'Satvik', + 'Nicolo', + 'Julious', + 'Weyman', + 'Roswell', + 'Brevin', + 'Amedeo', + 'Deforest', + 'Barnett', + 'Braydin', + 'Italo', + 'Adrienne', + 'Anne', + 'Jr', + 'Krystal', + 'Brion', + 'Wilberto', + 'Detrick', + 'Bucky', + 'Kristin', + 'Christohper', + 'Laddie', + 'Creighton', + 'Gust', + 'Darby', + 'Shanon', + 'Darious', + 'Josua', + 'Thang', + 'Demarkus', + 'Chistopher', + 'Ehren', + 'Marlo', + 'Matas', + 'Augusto', + 'Diamonte', + 'Maciej', + 'Jamon', + 'Marcin', + 'Valdemar', + 'Nickey', + 'Niam', + 'Ambrosio', + 'Crispin', + 'Lukasz', + 'Yazan', + 'Romell', + 'Darryle', + 'Renard', + 'Ewald', + 'Quint', + 'Andrzej', + 'Vittorio', + 'Keonte', + 'Lavonte', + 'Cordale', + 'Darvin', + 'Marvell', + 'Krzysztof', + 'Corben', + 'Keylan', + 'Haydon', + 'Ociel', + 'Zeth', + 'Ahmari', + 'Texas', + 'Yutaka', + 'Isami', + 'Adarius', + 'Juaquin', + 'Jaydn', + 'Jaidan', + 'Exavier', + 'Steffan', + 'Vahe', + 'Crystian', + 'Edilberto', + 'Jaquavion', + 'Xavien', + 'Delvon', + 'Otoniel', + 'Demontae', + 'Collins', + 'Keoki', + 'Nolberto', + 'Leng', + 'Karina', + 'Grigor', + 'Isrrael', + 'Kaoru', + 'Hisao', + 'Masayoshi', + 'Satoru', + 'Satoshi', + 'Nobuo', + 'Michaelanthony', + 'Lucero', + 'Jocelyn', + 'Yovany', + 'Joangel', + 'Jaelyn', + 'Caedmon', + 'Granger', + 'Heston', + 'Rhodes', + 'Kanon', + 'Judith', + 'Montavius', + 'Antron', + 'Xaiden', + 'Burhanuddin', + 'Stratton', + 'Kadence', + 'Jhett', + 'Jacion', + 'Aiyden', + 'Journey', + 'Jaziah', + 'Thien', + 'Travious', + 'Carsyn', + 'Quindarius', + 'Masyn', + 'Jalan', + 'Jaelin', + 'Dorien', + 'Aarron', + 'Dmarcus', + 'Ramin', + 'Christan', + 'Blain', + 'Rosa', + 'Christoher', + 'Vadim', + 'Martha', + 'Osher', + 'Laakea', + 'Chayton', + 'Keahi', + 'Johnatan', + 'Juanantonio', + 'Kahiau', + 'Sheridan', + 'Samual', + 'Luisalberto', + 'Zacharias', + 'Phi', + 'Marquice', + 'Chong', + 'Harpreet', + 'Fue', + 'Derrion', + 'Eber', + 'Kevion', + 'Beryl', + 'Gavan', + 'Liliana', + 'Fernie', + 'Sulo', + 'Jayren', + 'Lior', + 'Ruth', + 'Carlie', + 'Thierno', + 'Davontae', + 'Jamier', + 'Arye', + 'Kiernan', + 'Hanad', + 'Huston', + 'Winson', + 'Hobson', + 'Yates', + 'Kaua', + 'Einar', + 'Berish', + 'Annie', + 'Mahir', + 'Amr', + 'Sabir', + 'Ewell', + 'Orland', + 'Dujuan', + 'Harvie', + 'Dahmir', + 'Hosea', + 'Haneef', + 'Wei', + 'Nello', + 'Fishel', + 'Amere', + 'Rafi', + 'Charlton', + 'Colden', + 'Hughes', + 'Laurier', + 'Blong', + 'Shimshon', + 'Jahmel', + 'Steward', + 'Milbert', + 'Buel', + 'Hallie', + 'Comer', + 'Tafari', + 'Iver', + 'Evangelos', + 'Jaquarius', + 'Azan', + 'Braedan', + 'Jadarrius', + 'Vernie', + 'Andi', + 'Darry', + 'Jawad', + 'Uri', + 'Kennard', + 'Yishai', + 'Kijana', + 'Brekken', + 'Rajan', + 'Stevens', + 'Sunil', + 'Siddhant', + 'Sir', + 'Sire', + 'Jansen', + 'Theodor', + 'Kaedyn', + 'Tymere', + 'Zyair', + 'Tron', + 'Sanchez', + 'Amaru', + 'Anastasio', + 'Agastya', + 'Hawk', + 'Honor', + 'Sotero', + 'Saeed', + 'Ziggy', + 'Conan', + 'Arie', + 'Gloria', + 'Onesimo', + 'Wellington', + 'Alexei', + 'Tavarus', + 'Cayleb', + 'Arion', + 'Amadeus', + 'Bryer', + 'Jeter', + 'Merced', + 'Kaylon', + 'Lakendrick', + 'Nolen', + 'Niccolo', + 'Halston', + 'Deontre', + 'Ash', + 'Arush', + 'Artur', + 'Bidwell', + 'Tomie', + 'Author', + 'Izik', + 'Jeriah', + 'Edwyn', + 'Zhi', + 'Gilman', + 'Jawan', + 'Bryar', + 'Giles', + 'Talha', + 'Gill', + 'Abelino', + 'Kwasi', + 'Stavros', + 'Juanita', + 'Tri', + 'Consuelo', + 'Khambrel', + 'Peterson', + 'Brantly', + 'Brently', + 'Vitaliy', + 'Hashim', + 'Rain', + 'Quintus', + 'Matthieu', + 'Kayne', + 'Icker', + 'Valen', + 'Nels', + 'Josephus', + 'Nasario', + 'Romulo', + 'Kaisen', + 'Sulaiman', + 'Selim', + 'Mahad', + 'Steele', + 'Stryder', + 'Cristina', + 'Thornton', + 'Girard', + 'Prudencio', + 'Ethaniel', + 'Laurent', + 'Jayvin', + 'Jayveon', + 'Eladio', + 'Ellison', + 'Caius', + 'Christiano', + 'Navid', + 'Gerold', + 'Sven', + 'Advay', + 'Cabell', + 'Marcio', + 'Luisalfredo', + 'Ryatt', + 'Elijio', + 'Pax', + 'Neev', + 'Mehtab', + 'Eluterio', + 'Tahmir', + 'Davit', + 'Eliott', + 'Keane', + 'Kysen', + 'Rafe', + 'Legacy', + 'Erie', + 'Orlin', + 'Dawn', + 'Calum', + 'Adithya', + 'Adarsh', + 'Ulysee', + 'Thurmond', + 'Christen', + 'Thayne', + 'Sriram', + 'Yoav', + 'Lawton', + 'Kemar', + 'Duston', + 'Jatavious', + 'Luisfernando', + 'Maxime', + 'Rithik', + 'Dior', + 'Phuong', + 'Roni', + 'Manu', + 'Esteven', + 'Hazen', + 'Farris', + 'Leverne', + 'Ryen', + 'Tanay', + 'Seaborn', + 'Cicero', + 'Gianmarco', + 'Isak', + 'Lige', + 'Burke', + 'Authur', + 'Javarius', + 'Jeromie', + 'Jerred', + 'Silvano', + 'Keyan', + 'Briant', + 'Arun', + 'Jeremi', + 'Decarlos', + 'Jeanpierre', + 'Haydn', + 'Ab', + 'Anmol', + 'Shaye', + 'Nana', + 'Mateen', + 'Maurisio', + 'Nitin', + 'Dustan', + 'Srikar', + 'Arlin', + 'Burnett', + 'Johnathen', + 'Wyman', + 'Aleksandar', + 'Agustine', + 'Ronney', + 'Marisol', + 'Dmarion', + 'Keir', + 'Demetrice', + 'Jawon', + 'Ricci', + 'Javontae', + 'Armoni', + 'Alto', + 'Dawid', + 'Zakir', + 'Jarek', + 'Lary', + 'Dez', + 'Kaydon', + 'Henley', + 'Adonai', + 'Zahmir', + 'Youssouf', + 'Oisin', + 'Deniz', + 'Antonios', + 'Netanel', + 'Shlok', + 'Ranger', + 'Uzziah', + 'Eryk', + 'Sid', + 'Andersen', + 'Daylin', + 'Naftoli', + 'Lyn', + 'Orvin', + 'Kesean', + 'Hanif', + 'Adael', + 'Maury', + 'Ronn', + 'Carlyle', + 'Ankur', + 'Takumi', + 'Piero', + 'Jeanpaul', + 'Hoa', + 'Jacarri', + 'Jakhi', + 'Zyion', + 'Jeovany', + 'Eoin', + 'Etienne', + 'Amrit', + 'Dang', + 'Juliano', + 'Blakely', + 'Tauno', + 'Edin', + 'Dmitriy', + 'Lambert', + 'Roderic', + 'Felice', + 'Zaki', + 'Debra', + 'Teegan', + 'Tosh', + 'Nicholai', + 'Erickson', + 'Atharva', + 'Aaditya', + 'Anuj', + 'Diane', + 'Sachin', + 'Elazar', + 'Torian', + 'Tan', + 'Cristoval', + 'Jonathen', + 'Kobi', + 'Yuki', + 'Jacori', + 'Eduard', + 'Keron', + 'Tysean', + 'Deshun', + 'Hewitt', + 'Kaulana', + 'Jaydyn', + 'Sebastia', + 'Shamell', + 'Trysten', + 'Treshawn', + 'Samer', + 'Burnice', + 'Da', + 'Parris', + 'Royer', + 'Tien', + 'Tj', + 'Andranik', + 'Nino', + 'Luisenrique', + 'Andrick', + 'Graydon', + 'Pookela', + 'Nevaeh', + 'Zoe', + 'Hanna', + 'Joniel', + 'Jamarious', + 'Hurley', + 'Avante', + 'Iban', + 'Isaiha', + 'Chee', + 'Kealii', + 'Irbin', + 'Maynor', + 'Wendy', + 'Germain', + 'Shamus', + 'Zygmunt', + 'Garnet', + 'Lopaka', + 'Damar', + 'Ramy', + 'Everton', + 'Raylen', + 'Tryston', + 'Kullen', + 'Therman', + 'Khaliq', + 'Alon', + 'Arch', + 'Tylen', + 'Kalan', + 'Zacharia', + 'Dalen', + 'Bedford', + 'Lou', + 'Tsuneo', + 'Kalub', + 'Dadrian', + 'Jiro', + 'Fahad', + 'Quashawn', + 'Hisashi', + 'Fumio', + 'Carlito', + 'Ewing', + 'Zarek', + 'Leron', + 'Cardell', + 'Westen', + 'Hogan', + 'Payden', + 'Chazz', + 'Jarryd', + 'Sedric', + 'Homar', + 'Tylar', + 'Keone', + 'Dasean', + 'Lake', + 'Joeanthony', + 'Haroon', + 'Adonys', + 'Grayling', + 'Braelon', + 'Loras', + 'Jontavious', + 'Nesanel', + 'Carlisle', + 'Camillo', + 'Mandeep', + 'Yang', + 'Blayden', + 'Niall', + 'Evelio', + 'Zaragoza', + 'Shlomie', + 'Percell', + 'Baylee', + 'Garold', + 'Eriq', + 'Ozell', + 'Benjiman', + 'Wayman', + 'Saturnino', + 'Moody', + 'Deandra', + 'Estanislado', + 'Curvin', + 'Demonta', + 'Crimson', + 'Scout', + 'Daequan', + 'Izael', + 'Trine', + 'Demontre', + 'Rexford', + 'Fenix', + 'Raheim', + 'Rivers', + 'Cobe', + 'Jeron', + 'Yanuel', + 'Naftula', + 'Dwan', + 'Kanai', + 'Nicco', + 'Kaeson', + 'Shadman', + 'Cobi', + 'Raequan', + 'Shae', + 'Osama', + 'Ernan', + 'Dennys', + 'Aquil', + 'Tierra', + 'Sabrina', + 'Mia', + 'Melanie', + 'Marissa', + 'Carolyn', + 'Arielle', + 'Zaine', + 'Macen', + 'Shahin', + 'Casyn', + 'Osmin', + 'Alphonsus', + 'Carrington', + 'Chayce', + 'Opal', + 'Taylon', + 'Koy', + 'Ebenezer', + 'Amarii', + 'Keshun', + 'Kolin', + 'Aspen', + 'Cort', + 'Zaylon', + 'Zaedyn', + 'Zaydyn', + 'Tuff', + 'Holton', + 'Ashtyn', + 'Lathen', + 'Hershell', + 'Jerre', + 'Tsugio', + 'Josealberto', + 'Adien', + 'Acen', + 'Maurilio', + 'Ashten', + 'Wataru', + 'Keontae', + 'Donaven', + 'Javonta', + 'Jacobie', + 'Peng', + 'Ector', + 'Ankit', + 'Ann', + 'Kasim', + 'Parley', + 'Mizael', + 'Maxon', + 'Kylar', + 'Jjesus', + 'Kaven', + 'Curran', + 'Edvin', + 'Enrrique', + 'Donovin', + 'Godfrey', + 'Xayden', + 'Xzavian', + 'Carlosmanuel', + 'Ladainian', + 'Keithan', + 'Azrael', + 'Jae', + 'Marlow', + 'Aviv', + 'Orson', + 'Zamarion', + 'Chason', + 'Henrry', + 'Gevorg', + 'Dartagnan', + 'Zakee', + 'Giovannie', + 'Halen', + 'Vinay', + 'Wilfrido', + 'Winton', + 'Garet', + 'Josafat', + 'Manjot', + 'Juandaniel', + 'Manley', + 'Oshea', + 'Wali', + 'Reymond', + 'Harjot', + 'Sidharth', + 'Amer', + 'Camari', + 'Quincey', + 'Dawan', + 'Newell', + 'Sigurd', + 'Logen', + 'Rafiq', + 'Delonta', + 'Katrina', + 'Kristina', + 'Octavia', + 'Sade', + 'Ziyad', + 'Tovia', + 'Malachai', + 'Briana', + 'Alison', + 'Ashleigh', + 'Jerick', + 'Benedetto', + 'Fiore', + 'Mikail', + 'Qasim', + 'Yochanan', + 'Ettore', + 'Ferris', + 'Aziz', + 'Naseer', + 'Jabril', + 'Brodey', + 'Alvah', + 'Kalman', + 'Ziyon', + 'Zakery', + 'Sedale', + 'Jevin', + 'Kalmen', + 'Moishy', + 'Shai', + 'Zakari', + 'Bradlee', + 'Kenley', + 'Pratham', + 'Izeah', + 'Ilias', + 'Emari', + 'Race', + 'Zacarias', + 'Yuri', + 'Kleber', + 'Kailer', + 'Jhovany', + 'Iven', + 'Issaiah', + 'Hosie', + 'Dixon', + 'Massiah', + 'Remo', + 'Pinchos', + 'Mahki', + 'Gunther', + 'Irene', + 'Jamarie', + 'Kaan', + 'Jayon', + 'Moroni', + 'Jkwon', + 'Barack', + 'Alastair', + 'Fares', + 'Zackariah', + 'Yoshua', + 'Tanish', + 'Iann', + 'Linden', + 'Avinash', + 'Willam', + 'Iman', + 'Domanic', + 'Lenton', + 'Samad', + 'Aimar', + 'Buddie', + 'Jozef', + 'Josmar', + 'Mercer', + 'Collie', + 'Nephi', + 'Kenai', + 'Alquan', + 'Cezar', + 'Verbon', + 'Aeneas', + 'Jeremyah', + 'Eren', + 'Tej', + 'Jahad', + 'Deep', + 'Augusta', + 'Yaqub', + 'Yahye', + 'Vashon', + 'Kristoff', + 'Penn', + 'Loukas', + 'Kaydin', + 'Kaius', + 'Perseus', + 'Mykah', + 'Joab', + 'Cylus', + 'Emrys', + 'Mikko', + 'Jaxsyn', + 'Sudais', + 'Tiberius', + 'Rooney', + 'Yuvan', + 'Cletis', + 'Liev', + 'Ester', + 'Harlow', + 'Shreyan', + 'Samar', + 'Saharsh', + 'Ruhaan', + 'Zyler', + 'Yuma', + 'Dwyane', + 'Yanni', + 'Dutch', + 'Rajveer', + 'Tayton', + 'Kasir', + 'Luster', + 'Tage', + 'Damarius', + 'Elihu', + 'Heinz', + 'Manolo', + 'Makhai', + 'Madhav', + 'Sohum', + 'Omri', + 'Egbert', + 'Marie', + 'Keshon', + 'Jahmier', + 'Nachmen', + 'Mckade', + 'Moise', + 'Ames', + 'Iden', + 'Benard', + 'Yannick', + 'Pasha', + 'Sherrick', + 'Jordany', + 'Fenton', + 'Tytan', + 'Dashel', + 'Daksh', + 'Juliani', + 'Jhonathan', + 'Broxton', + 'Essie', + 'Devontay', + 'Maksym', + 'Park', + 'Dasani', + 'Severiano', + 'Kamel', + 'Chayanne', + 'Jarel', + 'Yolanda', + 'Tylik', + 'Marquell', + 'Jamarr', + 'Micky', + 'Socorro', + 'Waymond', + 'Michial', + 'Yoseph', + 'Lumir', + 'Placido', + 'Asif', + 'Needham', + 'Claiborne', + 'Tennis', + 'Burley', + 'Raffaele', + 'Shavar', + 'Atanacio', + 'Jahmar', + 'Arben', + 'Nabeel', + 'Cordarryl', + 'Danyal', + 'Bryston', + 'Lemont', + 'Elston', + 'Kerwin', + 'Riccardo', + 'Danzel', + 'Waldemar', + 'Ledarius', + 'Omarr', + 'Wilho', + 'Alger', + 'Raymie', + 'Kenney', + 'Abdallah', + 'Aristides', + 'Avram', + 'Tayvion', + 'Urbano', + 'Deontay', + 'Darcy', + 'Robbin', + 'Bartlomiej', + 'Dann', + 'Tyjuan', + 'Khaleel', + 'Winifred', + 'Claron', + 'Linford', + 'Hilliard', + 'Arlon', + 'Yong', + 'Malvin', + 'Zymere', + 'Newborn', + 'Eleuterio', + 'Glyn', + 'Koltyn', + 'Serapio', + 'Pius', + 'Ines', + 'Harrold', + 'Caitlyn', + 'Rajeev', + 'Constantinos', + 'Abid', + 'Calvert', + 'Parnell', + 'Aubry', + 'Damone', + 'Akim', + 'Adem', + 'Othel', + 'Joaopedro', + 'Tomer', + 'Brentlee', + 'Melquan', + 'Elpidio', + 'Jenny', + 'Alejos', + 'Romie', + 'Ardell', + 'Doctor', + 'Virginia', + 'Makenzie', + 'Maggie', + 'Tywan', + 'Elisaul', + 'Luby', + 'Teofilo', + 'Jermell', + 'Gumesindo', + 'Harless', + 'Croix', + 'Obinna', + 'Traveon', + 'Coley', + 'Tu', + 'Brylon', + 'Carlin', + 'Daneil', + 'Garen', + 'Ronell', + 'Chesley', + 'Tyrece', + 'Arville', + 'Eamonn', + 'Kayshawn', + 'Wilkie', + 'Zacchaeus', + 'Rapheal', + 'Cordaryl', + 'Quan', + 'Nhan', + 'Vann', + 'Franciscojavier', + 'Kinte', + 'Rui', + 'Chuong', + 'Chao', + 'Chai', + 'Linh', + 'Cirilo', + 'Ky', + 'Gwyn', + 'Hearl', + 'Tray', + 'Carmon', + 'Phuc', + 'Neiman', + 'Ladon', + 'Moua', + 'Eulises', + 'Jonte', + 'Yusuke', + 'Vinnie', + 'Seanpatrick', + 'Pearson', + 'Daemon', + 'Reyn', + 'Daekwon', + 'Garron', + 'Sequan', + 'Zavien', + 'Geovanie', + 'Jessee', + 'Richmond', + 'Osualdo', + 'Artin', + 'Devone', + 'Makoto', + 'Hitoshi', + 'Shinichi', + 'Samari', + 'Saxon', + 'Glennis', + 'Fadi', + 'Bronislaw', + 'Estuardo', + 'Shaheen', + 'Saman', + 'Lue', + 'Djuan', + 'Cord', + 'Linville', + 'Landis', + 'Cameren', + 'Herson', + 'Ellie', + 'Seanmichael', + 'Froilan', + 'Delon', + 'Jestin', + 'Mattew', + 'Toni', + 'Kelii', + 'Maribel', + 'Jadrian', + 'Traylon', + 'Kaiea', + 'Kaeo', + 'Taft', + 'Dameion', + 'Darryn', + 'Dondi', + 'Clell', + 'Corbett', + 'Lyndell', + 'Avenir', + 'Seldon', + 'Jakwon', + 'Jacque', + 'Deane', + 'Cheikh', + 'Carmel', + 'Kieth', + 'Tahmid', + 'Lillard', + 'Tasheem', + 'Jens', + 'Christobal', + 'Delos', + 'Lashon', + 'Jaimie', + 'Kary', + 'Kendarious', + 'Johnell', + 'Harlen', + 'Terron', + 'Corliss', + 'Liston', + 'Seng', + 'Phu', + 'Rasean', + 'Sung', + 'San', + 'Babak', + 'Adel', + 'Gillermo', + 'Avon', + 'Harlon', + 'Allyn', + 'Clary', + 'Orry', + 'Nazario', + 'Jamail', + 'Daeshawn', + 'Tal', + 'Moustafa', + 'Tarell', + 'Jahquan', + 'Jian', + 'Lazar', + 'Adama', + 'Benyamin', + 'Tayvon', + 'Lamel', + 'Davonne', + 'Tayquan', + 'Jusitn', + 'Shjon', + 'Leotis', + 'Kasheem', + 'Ilir', + 'Ravon', + 'Parish', + 'Ehan', + 'Daishawn', + 'Islam', + 'Pinches', + 'Ovadia', + 'Mechel', + 'Berlin', + 'Deryk', + 'Tymel', + 'Vijay', + 'Dyquan', + 'Agron', + 'Tarrell', + 'Itamar', + 'Mordcha', + 'Chrisotpher', + 'Alban', + 'Stephane', + 'Tanvir', + 'Demetriu', + 'Yan', + 'Asim', + 'Ahsan', + 'Mackenzi', + 'Kristofe', + 'Kenrick', + 'Cuahutemoc', + 'Tavis', + 'Audric', + 'Deaven', + 'Nicanor', + 'Mick', + 'Geoffery', + 'Timofey', + 'Dolphus', + 'Franciso', + 'Gorje', + 'Jobany', + 'Abdelrahman', + 'Clenton', + 'Yohance', + 'Milad', + 'Juanluis', + 'Luismario', + 'Marvyn', + 'Rushil', + 'Tenoch', + 'Trentin', + 'Fardeen', + 'Shashank', + 'Yuta', + 'Ritvik', + 'Akili', + 'Aleksei', + 'Gaurav', + 'Iran', + 'Caillou', + 'Borach', + 'Keisuke', + 'Kaushik', + 'Hari', + 'Izac', + 'Josejulian', + 'Juanangel', + 'Kasra', + 'Anthonie', + 'Daivd', + 'Dain', + 'Toren', + 'Sesar', + 'Eldor', + 'Pieter', + 'Yu', + 'Cloyce', + 'Dusten', + 'Aquiles', + 'Aslan', + 'Sevastian', + 'Siddarth', + 'Tysen', + 'Johncarlo', + 'Idan', + 'Daymian', + 'Domanick', + 'Arnie', + 'Bartley', + 'Newman', + 'Akram', + 'Abdulla', + 'Lew', + 'Geremy', + 'Jehu', + 'Josejuan', + 'Jailen', + 'Etai', + 'Fabien', + 'Victormanuel', + 'Ossie', + 'Egan', + 'Eldin', + 'Shamari', + 'Nussen', + 'Arda', + 'Sina', + 'Tytus', + 'Pranay', + 'Dylen', + 'Juandavid', + 'Kalil', + 'Kushal', + 'Hazael', + 'Lecil', + 'Belton', + 'Aleczander', + 'Terance', + 'Faizan', + 'Naithan', + 'Koji', + 'Akshat', + 'Andruw', + 'Bram', + 'Dieter', + 'Saahil', + 'Saulo', + 'Arnel', + 'Demarea', + 'Farhad', + 'Joeseph', + 'Alondra', + 'Belal', + 'Antoniodejesus', + 'Anival', + 'Choua', + 'Cha', + 'Bryn', + 'Xiong', + 'Aristeo', + 'Mehmet', + 'Moustapha', + 'Jandel', + 'Asante', + 'Yunus', + 'Schneur', + 'Steffen', + 'Leovardo', + 'Kacey', + 'Payam', + 'Salbador', + 'Nicholes', + 'Neema', + 'Clarke', + 'Marqus', + 'Araceli', + 'Jerman', + 'Marioalberto', + 'Joseguadalupe', + 'Emigdio', + 'Krishan', + 'Jessey', + 'Arcadio', + 'Zong', + 'Yoni', + 'Tirso', + 'Thompson', + 'Damarea', + 'Everado', + 'Edy', + 'Edder', + 'Nikki', + 'Clemmie', + 'Willian', + 'Marquese', + 'Perris', + 'Miriam', + 'Shelly', + 'Bulmaro', + 'Jasdeep', + 'Irvine', + 'Hue', + 'Gurpreet', + 'Donaldo', + 'Jonthan', + 'Geroge', + 'Francois', + 'Duc', + 'Jerico', + 'Avedis', + 'Chang', + 'Damario', + 'Kenta', + 'Nikkolas', + 'Khoi', + 'Garren', + 'Norma', + 'My', + 'Lam', + 'Sahir', + 'Yer', + 'Jaskarn', + 'Jeric', + 'Maximillion', + 'Elson', + 'Marin', + 'Loc', + 'Lemar', + 'Kristofor', + 'Nai', + 'Takoda', + 'Tung', + 'Thong', + 'Rayshaun', + 'Derreck', + 'Regino', + 'Nadav', + 'Luismiguel', + 'Josede', + 'Hao', + 'Rayce', + 'Zacary', + 'Nareg', + 'Khyree', + 'Chi', + 'Joanna', + 'Sevag', + 'Garin', + 'Juluis', + 'Petros', + 'Berel', + 'Abubakar', + 'Jorel', + 'Kazi', + 'Jaiceon', + 'Haider', + 'Feynman', + 'Muhammadali', + 'Jassiel', + 'Morrison', + 'Nakai', + 'Oden', + 'Odysseus', + 'Quest', + 'Kaidan', + 'Kilian', + 'Kirill', + 'Thorin', + 'Tru', + 'Xzander', + 'Taniela', + 'Roen', + 'Sho', + 'Aarin', + 'Gracen', + 'Gurfateh', + 'Gurman', + 'Hiro', + 'Edrick', + 'Esaias', + 'Johncarlos', + 'Sidi', + 'Cataldo', + 'Noor', + 'Philbert', + 'Eyad', + 'Arber', + 'Abrar', + 'Ladislaus', + 'Serafino', + 'Mannie', + 'Daevon', + 'Haseeb', + 'Yale', + 'Spiro', + 'Emre', + 'Daryan', + 'Camrin', + 'Kavi', + 'Doran', + 'Vaibhav', + 'Rayne', + 'Derric', + 'Orbie', + 'Reily', + 'Gio', + 'Gurnoor', + 'Jaasiel', + 'Naman', + 'Josaiah', + 'Josiyah', + 'Kasper', + 'Filippo', + 'Sigfredo', + 'Joesiah', + 'Rei', + 'Nahom', + 'Ojas', + 'Vladislav', + 'Hilary', + 'Rinaldo', + 'Even', + 'Gautam', + 'Cornel', + 'Julyan', + 'Inaki', + 'Iseah', + 'Itai', + 'Laurance', + 'Garey', + 'Lawerance', + 'Quindon', + 'Levin', + 'Leviticus', + 'Link', + 'Glenford', + 'Avyan', + 'Dmitry', + 'Eiden', + 'Advait', + 'Ahaan', + 'Arhaan', + 'Kassius', + 'Hendrick', + 'Jaiveer', + 'Nirvaan', + 'Reeve', + 'Torsten', + 'True', + 'Iwao', + 'Jahvon', + 'Paxson', + 'Kali', + 'Kwesi', + 'Yaron', + 'Ami', + 'Dashiel', + 'Meliton', + 'Sylus', + 'Mika', + 'Jireh', + 'Selig', + 'Adi', + 'Brenner', + 'Breyden', + 'Mitsuru', + 'Farley', + 'Montrel', + 'Kyland', + 'Jadakiss', + 'Tadarius', + 'Brooke', + 'Alexandria', + 'Alexa', + 'Abby', + 'Hayley', + 'Mallory', + 'Madelyn', + 'Layla', + 'Kirsten', + 'Quayshawn', + 'Deadrick', + 'Hobby', + 'Eunice', + 'Macon', + 'Ysabel', + 'Secundino', + 'Hulen', + 'Estle', + 'Tolbert', + 'Baker', + 'Tilford', + 'Shyheem', + 'Orbin', + 'Ruel', + 'Hurshel', + 'Jailyn', + 'Dequincy', + 'Jamall', + 'Draper', + 'Kenric', + 'Aime', + 'Cam', + 'Connell', + 'Treylon', + 'Bethel', + 'Rommie', + 'Alphonza', + 'Gussie', + 'Elridge', + 'Hillery', + 'Ruffin', + 'Farrel', + 'Wendall', + 'Gerome', + 'Ferrell', + 'Uvaldo', + 'Marshon', + 'Jawaun', + 'Trevell', + 'Tyvon', + 'Telesforo', + 'Ellery', + 'Cordae', + 'Loran', + 'Travell', + 'Lamari', + 'Errick', + 'Antwoine', + 'Starsky', + 'Chirag', + 'Donzell', + 'Tierre', + 'Ketan', + 'Crespin', + 'Orris', + 'Bawi', + 'Wanda', + 'Canuto', + 'Aniceto', + 'Braxten', + 'Audry', + 'Bartolo', + 'Brigido', + 'Garvin', + 'Vergil', + 'Olegario', + 'Thelma', + 'Crecencio', + 'Eleno', + 'Wright', + 'Burtis', + 'Dicky', + 'Avelino', + 'Norval', + 'Cirildo', + 'Darwyn', + 'Delwin', + 'Henery', + 'Beauford', + 'Little', + 'Ameir', + 'Arland', + 'Verner', + 'Taron', + 'Undra', + 'Khasir', + 'Kymir', + 'Aleem', + 'Ordean', + 'Carmino', + 'Lucus', + 'Jodeci', + 'Linn', + 'Sinclair', + 'Delorean', + 'Chalmers', + 'Kentavius', + 'Jarious', + 'Lajuan', + 'Narada', + 'Hussien', + 'Alonte', + 'Damarco', + 'Benjamen', + 'Randon', + 'Jabree', + 'Lawyer', + 'Wanya', + 'Samie', + 'Sim', + 'Washington', + 'Isom', + 'Keyton', + 'Quin', + 'Mahamed', + 'Liban', + 'Ramir', + 'Samaj', + 'Kipp', + 'Prentis', + 'Jibril', + 'Kyaire', + 'Buell', + 'Nasim', + 'Adell', + 'Mohamedamin', + 'Abdiaziz', + 'Harun', + 'Amire', + 'Eligah', + 'Parks', + 'Colonel', + 'Joaovictor', + 'Vinicius', + 'Mcdonald', + 'Manly', + 'Phares', + 'Geza', + 'Kemp', + 'Alphonzo', + 'Loring', + 'Haig', + 'Joaquim', + 'Craven', + 'Bynum', + 'Parke', + 'Ignatz', + 'Hebert', + 'Berton', + 'Ayomide', + 'Kidus', + 'Ayven', + 'Aziah', + 'Banner', + 'Barret', + 'Blayze', + 'Braddock', + 'Javoris', + 'Cortland', + 'Antavius', + 'Amaziah', + 'Santonio', + 'Slate', + 'Sylis', + 'Thierry', + 'Joanthony', + 'Rhylan', + 'Pryce', + 'Riggin', + 'Dequavious', + 'Bakari', + 'Marquavius', + 'Artavious', + 'Desmon', + 'Rajohn', + 'Faheem', + 'Kage', + 'Arkeem', + 'Jaquon', + 'Dontavis', + 'Quentavious', + 'Braysen', + 'Bricen', + 'Traevon', + 'Caidyn', + 'Collyn', + 'Joah', + 'Patton', + 'Coleson', + 'Eythan', + 'Hadley', + 'Jaaziel', + 'Johntavious', + 'Quadarius', + 'Rafeal', + 'Karam', + 'Krishiv', + 'Majd', + 'Yeray', + 'Whitten', + 'Johnluke', + 'Demani', + 'Easten', + 'Ediel', + 'Tellis', + 'Delvecchio', + 'Aleks', + 'Rylie', + 'Osmel', + 'Lelan', + 'Tamarion', + 'Cayman', + 'Hajime', + 'Akio', + 'Takao', + 'Seiji', + 'Ah', + 'Mitsugi', + 'Koichi', + 'Ikenna', + 'Tyquavious', + 'Brannen', + 'Slayde', + 'Sultan', + 'Cage', + 'Jillian', + 'Kara', + 'Simone', + 'Theresa', + 'Julie', + 'Alisha', + 'Candace', + 'Candice', + 'Jazmine', + 'Domani', + 'Tiana', + 'Jeovanni', + 'Khaleb', + 'Copeland', + 'Dathan', + 'Deleon', + 'Jakori', + 'Jayke', + 'Kadon', + 'Camdon', + 'Shandon', + 'Mylan', + 'Jaxin', + 'Beverley', + 'Dallon', + 'Jakeem', + 'Tallon', + 'Vraj', + 'Welford', + 'Jadarian', + 'Yancarlos', + 'Omkar', + 'Jamaree', + 'Alix', + 'Trevyn', + 'Orestes', + 'Trevis', + 'Refoel', + 'Roddrick', + 'Tarvis', + 'Tamarick', + 'Denard', + 'Kerem', + 'Treyden', + 'Stephano', + 'Shubh', + 'Carston', + 'Utah', + 'Treven', + 'Reshard', + 'Yerachmiel', + 'Osmany', + 'Vansh', + 'Samaad', + 'Shakil', + 'Saford', + 'Doyal', + 'Cai', + 'Alexey', + 'Cruze', + 'Masiah', + 'Kitai', + 'Fedor', + 'Algie', + 'Worley', + 'Jakhari', + 'Brison', + 'Lanier', + 'Eston', + 'Qadir', + 'Lonzie', + 'Rayfield', + 'Chirstopher', + 'Eron', + 'Deontray', + 'Zoltan', + 'Christon', + 'Byford', + 'Mikeal', + 'Talyn', + 'Stormy', + 'Laramie', + 'Chrisopher', + 'Breckin', + 'Kennon', + 'Json', + 'Deiondre', + 'Heron', + 'Mykal', + 'Kalai', + 'Ervey', + 'Brayam', + 'Alakai', + 'Maika', + 'Kelson', + 'Trevaughn', + 'Aundre', + 'Eathan', + 'Keylon', + 'Kolbe', + 'Sebastion', + 'Kalib', + 'Jermy', + 'Jarrid', + 'Gumaro', + 'Maliq', + 'Armstead', + 'Stephone', + 'Oris', + 'Hassel', + 'Antwine', + 'Lorraine', + 'Budd', + 'Irfan', + 'Kamrin', + 'Araf', + 'Affan', + 'Leiby', + 'Sruly', + 'Peretz', + 'Mildred', + 'Louise', + 'Ryken', + 'Ryler', + 'Tayven', + 'Taysen', + 'Brexton', + 'Zayaan', + 'Oronde', + 'Firman', + 'Collen', + 'Letcher', + 'Clearence', + 'Braydan', + 'Yasser', + 'Jeferson', + 'Yahsir', + 'Cavan', + 'Ivor', + 'Hasker', + 'Kodie', + 'Lori', + 'Jaysean', + 'Cadin', + 'Breydon', + 'Amaree', + 'Nyeem', + 'Menno', + 'Orlo', + 'Nassir', + 'Sylar', + 'Drevon', + 'Burech', + 'Lenox', + 'Shloima', + 'Daris', + 'Diontae', + 'Aidin', + 'Brydon', + 'Jasean', + 'Nasier', + 'Johney', + 'Gabrial', + 'Fate', + 'Colyn', + 'Kaleem', + 'Capers', + 'Rembert', + 'Jquan', + 'Legrand', + 'Kirubel', + 'Gaberiel', + 'Thaddaeus', + 'Rece', + 'Dymir', + 'Tylil', + 'Remigio', + 'Ahad', + 'Melquiades', + 'Ethel', + 'Euel', + 'Harvy', + 'Margarita', + 'Jakeb', + 'Kagan', + 'Trinton', + 'Faiz', + 'Iliyan', + 'Emeterio', + 'Ferman', + 'Keeton', + 'Decorian', + 'Hadyn', + 'Rashaud', + 'Davontay', + 'Brallan', + 'Benancio', + 'Espiridion', + 'Seledonio', + 'Estefan', + 'Chanse', + 'Dade', + 'Sisto', + 'Herbie', + 'Janson', + 'Eusevio', + 'Loye', + 'Leocadio', + 'Kaelon', + 'Trevian', + 'Christien', + 'Chrystian', + 'Daegan', + 'Rosbel', + 'Romero', + 'Kylin', + 'Treyvion', + 'Ezekial', + 'Jaice', + 'Jantzen', + 'Aadyn', + 'Tennyson', + 'Kaedan', + 'Kaiser', + 'Kanin', + 'Jerron', + 'Jonaven', + 'Elija', + 'Amon', + 'Valton', + 'Derwood', + 'Atilano', + 'Jovanie', + 'Kaemon', + 'Oluwatobi', + 'Atlee', + 'Tadd', + 'Tammy', + 'Lem', + 'Hilmar', + 'Foch', + 'Clenard', + 'Jd', + 'Jiovanny', + 'Ladarion', + 'Lleyton', + 'Adrik', + 'Webb', + 'Toddrick', + 'Jerrett', + 'Omero', + 'Wendel', + 'Teresa', + 'Cass', + 'Kedric', + 'Heraclio', + 'Rainier', + 'Lakota', + 'Sanjuan', + 'Daymon', + 'Rodd', + 'Yancey', + 'Trampas', + 'Viviano', + 'Heith', + 'Bj', + 'Trevante', + 'Ildefonso', + 'Jaeger', + 'Jamarkus', + 'Remijio', + 'Desiderio', + 'Ausencio', + 'Alejo', + 'Keldrick', + 'Sigifredo', + 'Treavor', + 'Britain', + 'Macedonio', + 'Kourtney', + 'Gerrick', + 'Jousha', + 'Klinton', + 'Montreal', + 'Catlin', + 'Danner', + 'Eliberto', + 'Eliodoro', + 'Lonnell', + 'Michiel', + 'Hermilo', + 'Jackey', + 'Todrick', + 'Irineo', + 'Wenceslao', + 'Duaine', + 'Cleto', + 'Gaylan', + 'Derrel', + 'Nabor', + 'Huck', + 'Hoy', + 'Antwaun', + 'Hoyte', + 'Flournoy', + 'Mayford', + 'Harlie', + 'Hansford', + 'Cutler', + 'Amerigo', + 'Teague', + 'Griffith', + 'Emidio', + 'Kenna', + 'Cru', + 'Arnett', + 'Gay', + 'Dencil', + 'Carman', + 'Doy', + 'Trevan', + 'Jahziel', + 'Rodricus', + 'Copper', + 'Dael', + 'Aydon', + 'Ricco', + 'Judas', + 'Kessler', + 'Romelo', + 'Slayton', + 'Marico', + 'Leevi', + 'Xadrian', + 'Jceon', + 'Kross', + 'Chancey', + 'Bayne', + 'Brylen', + 'Eidan', + 'Olvin', + 'Pearce', + 'Zak', + 'Jaiven', + 'Dani', + 'Bairon', + 'Cordarious', + 'Jaxyn', + 'Rylin', + 'Avin', + 'Bransen', + 'Eastyn', + 'Eyden', + 'Brenham', + 'Chaston', + 'Horatio', + 'Dakarai', + 'Jencarlo', + 'Jevan', + 'Jhayden', + 'Tracen', + 'Peggy', + 'Wynn', + 'Bennet', + 'Milas', + 'Ronal', + 'Kadrian', + 'Jhase', + 'Callahan', + 'Hays', + 'Braidyn', + 'Ezana', + 'Chidubem', + 'Virat', + 'Maxemiliano', + 'Ozias', + 'Pace', + 'Mordecai', + 'Tabor', + 'Phillipe', + 'Maritza', + 'Ricahrd', + 'Jeanette', + 'Sundeep', + 'Tyric', + 'Mina', + 'Nasser', + 'Nhia', + 'Giuliano', + 'Farid', + 'Ryo', + 'Delmont', + 'Klaus', + 'Traquan', + 'Dawayne', + 'Broward', + 'Drequan', + 'Cagney', + 'Shellie', + 'Torre', + 'Deepak', + 'Janmichael', + 'Lan', + 'Quentavius', + 'Quantez', + 'Markevious', + 'Melbourne', + 'Melford', + 'Xue', + 'Samnang', + 'Jarquez', + 'Montrez', + 'Dao', + 'Luvern', + 'Vue', + 'Jenaro', + 'Wacey', + 'Lorena', + 'Ly', + 'Casmere', + 'Marsean', + 'Marinus', + 'Shiro', + 'Shizuo', + 'Knowledge', + 'Baudelio', + 'Cher', + 'Christiaan', + 'Adriane', + 'Wilgus', + 'Gustabo', + 'Barnet', + 'Xeng', + 'Priscilla', + 'Sou', + 'Sumeet', + 'Vartan', + 'Herschell', + 'Montell', + 'Illya', + 'Flem', + 'Marwan', + 'Johnrobert', + 'Boleslaus', + 'Christie', + 'Ericberto', + 'Esmeralda', + 'Cecilia', + 'Purvis', + 'Benjie', + 'Sutter', + 'Sufyan', + 'Viraaj', + 'Sathvik', + 'Quitman', + 'Liborio', + 'Humbert', + 'Zakariah', + 'Yichen', + 'Seward', + 'Alf', + 'Sebastiano', + 'Guiseppe', + 'Stanislaw', + 'Tyrice', + 'Lenell', + 'Kewon', + 'Bahe', + 'Recardo', + 'Paola', + 'Ronson', + 'Naveed', + 'Karla', + 'Lamberto', + 'Leoncio', + 'Sandor', + 'Diamante', + 'Woodson', + 'Hargis', + 'Kelcey', + 'Daquon', + 'Estell', + 'Christapher', + 'Jalal', + 'Tania', + 'Tramell', + 'Victoralfonso', + 'Kento', + 'Kiet', + 'Krystopher', + 'Shaine', + 'Bejamin', + 'Virgel', + 'Toxie', + 'Goebel', + 'Tyon', + 'Norvin', + 'Savalas', + 'Othmar', + 'Jakaiden', + 'Reis', + 'Pratik', + 'Ashish', + 'Hutson', + 'Karmello', + 'Dacari', + 'Katsuji', + 'Sadamu', + 'Masatoshi', + 'Kiyoto', + 'Carols', + 'Waylen', + 'Shain', + 'Alexandru', + 'Jomo', + 'Kalei', + 'Shyam', + 'Zyan', + 'Tamar', + 'Prem', + 'Jamiyl', + 'Remmel', + 'Harlin', + 'Novak', + 'Fynn', + 'Gonsalo', + 'Maliki', + 'Loghan', + 'Cauy', + 'Kassem', + 'Jitsuo', + 'Itsuo', + 'Atsushi', + 'Sunao', + 'Sueo', + 'Hiromu', + 'Toshiyuki', + 'Osamu', + 'Mena', + 'Aldin', + 'Leticia', + 'Darick', + 'Kawan', + 'Rajahn', + 'Asmar', + 'Emarion', + 'Hilmer', + 'Dameyune', + 'Rondarius', + 'Brinson', + 'Trason', + 'Chung', + 'Eran', + 'Khanh', + 'Javarious', + 'Makel', + 'Zyquan', + 'Quintarius', + 'Duran', + 'Veasna', + 'Thao', + 'Gracin', + 'Eberardo', + 'Ming', + 'Lusiano', + 'Kaveh', + 'Truong', + 'Ying', + 'Kentravious', + 'Dillen', + 'Jamonte', + 'Arthuro', + 'Camarion', + 'Avett', + 'Mehdi', + 'Nishant', + 'Bartek', + 'Aarnav', + 'Jeffory', + 'Deen', + 'Dayshaun', + 'Kemonte', + 'Petar', + 'Yug', + 'Donat', + 'Sylvio', + 'Magdiel', + 'Christianjames', + 'Lessie', + 'Sander', + 'Rajvir', + 'Nahuel', + 'Pearlie', + 'Aaren', + 'Dimitry', + 'Aravind', + 'Aristotle', + 'Jeury', + 'Naji', + 'Tysheem', + 'Alcee', + 'Gustaf', + 'Jamarrion', + 'Zollie', + 'Malick', + 'Navin', + 'Juwon', + 'Usama', + 'Walid', + 'Quamel', + 'Sadiq', + 'Tamarcus', + 'Merwyn', + 'Ferdie', + 'Kalif', + 'Latif', + 'Davidson', + 'Aahan', + 'Shahid', + 'Min', + 'Kieren', + 'Oz', + 'Oryan', + 'Madox', + 'Kota', + 'Gurshaan', + 'Gagik', + 'Finnigan', + 'Finlay', + 'Exodus', + 'Kaileb', + 'Jullien', + 'Jiovani', + 'Maryland', + 'Weaver', + 'Williard', + 'Keyondre', + 'Kailen', + 'Kanan', + 'Luisantonio', + 'Izack', + 'Daniela', + 'Colm', + 'Raja', + 'Keeshawn', + 'Adhemar', + 'Hillary', + 'Abdimalik', + 'Roark', + 'Kolston', + 'Cheryl', + 'Richardson', + 'Arif', + 'Jahkeem', + 'Kumar', + 'Raywood', + 'Jaiquan', + 'Earley', + 'Buren', + 'Rossie', + 'Jakayden', + 'Ruffus', + 'Zaquan', + 'Tamer', + 'Devonne', + 'Ikeem', + 'Dhruva', + 'Georges', + 'Kwabena', + 'Yeriel', + 'Glover', + 'Sanders', + 'Adonay', + 'Gillis', + 'Yomar', + 'Ediberto', + 'Antwane', + 'Isahi', + 'Haidyn', + 'Elizandro', + 'Markjoseph', + 'Jezreel', + 'Isayah', + 'Zedekiah', + 'Nikolay', + 'Jenner', + 'Uriyah', + 'Taiga', + 'Daniele', + 'Zacharie', + 'Joanne', + 'Manpreet', + 'Mohan', + 'Eliu', + 'Faraz', + 'Robah', + 'Isham', + 'Omarian', + 'Gagandeep', + 'Zeno', + 'Waddell', + 'Plato', + 'Quavon', + 'Talib', + 'Bascom', + 'Mayo', + 'Tequan', + 'Teron', + 'Anatole', + 'Tajh', + 'Algenis', + 'Liridon', + 'Kervens', + 'Yunior', + 'Kenson', + 'Wesly', + 'Antwann', + 'Zelig', + 'Demetrious', + 'Johnbenedict', + 'Josecarlos', + 'Kona', + 'Cj', + 'Atul', + 'Asaf', + 'Aleck', + 'Anthoni', + 'Anuar', + 'Gedalya', + 'Rafay', + 'Eyal', + 'Andry', + 'Natanel', + 'Nissim', + 'Jahdiel', + 'Jophy', + 'Rehaan', + 'Jhovani', + 'Maxximus', + 'Nain', + 'Yomtov', + 'Sheikh', + 'Demir', + 'Markos', + 'Mouhamadou', + 'Ousman', + 'Izreal', + 'Hadrian', + 'Aldrin', + 'Conlan', + 'Degan', + 'Toi', + 'Finneas', + 'Latroy', + 'Adon', + 'Antuan', + 'Elchonon', + 'Uzair', + 'Mohid', + 'Nazier', + 'Eliab', + 'Roc', + 'Pavan', + 'Yovanny', + 'Sinjin', + 'Tavoris', + 'Asiel', + 'Brayant', + 'Alexsandro', + 'Adrean', + 'Darel', + 'Olajuwon', + 'Corderro', + 'Tynan', + 'Xaiver', + 'Travaris', + 'Yonis', + 'Gerren', + 'Demon', + 'Furnell', + 'Juel', + 'Harish', + 'Raiyan', + 'Elia', + 'Elijha', + 'Gautham', + 'Arvind', + 'Audel', + 'Almer', + 'Djimon', + 'Jahi', + 'Gehrig', + 'Avant', + 'Arnell', + 'Eliaz', + 'Kaedon', + 'Jaedin', + 'Voshon', + 'Malachy', + 'Gilad', + 'Gabriele', + 'Riku', + 'Cameran', + 'Yoskar', + 'Jahfari', + 'Alexiz', + 'Javante', + 'Gregor', + 'Izel', + 'Donnovan', + 'Nikos', + 'Kodey', + 'Eytan', + 'Betzalel', + 'Dimitrius', + 'Chananya', + 'Graylin', + 'Samvel', + 'Yi', + 'Wassillie', + 'Kelechi', + 'Erroll', + 'Ardit', + 'Rahn', + 'Delaine', + 'Jule', + 'Idus', + 'Dessie', + 'Juda', + 'Levester', + 'Kiante', + 'Earnie', + 'Ihor', + 'Kapono', + 'Akoni', + 'Koamalu', + 'Sholem', + 'Howie', + 'Dariusz', + 'Hall', + 'Kekai', + 'Onix', + 'Ozie', + 'Liem', + 'Collis', + 'Lemon', + 'Hinton', + 'Guss', + 'Ronda', + 'Siddhartha', + 'Owyn', + 'Rye', + 'Riot', + 'Vander', + 'Selena', + 'Barnie', + 'Lewie', + 'Jaxiel', + 'Kaizen', + 'Haloa', + 'Dermot', + 'Misha', + 'Mister', + 'Nicholis', + 'Kevork', + 'Kia', + 'Houa', + 'Huriel', + 'Jesu', + 'Dionta', + 'Silvino', + 'Ivery', + 'Iokepa', + 'Geo', + 'Dex', + 'Izaan', + 'Jasraj', + 'Jakson', + 'Niel', + 'Avelardo', + 'Arjay', + 'Aran', + 'Alanzo', + 'Aidric', + 'Lomax', + 'Rawn', + 'Simmie', + 'Tonnie', + 'Yuto', + 'Mataio', + 'Nicodemus', + 'Maximilien', + 'Raider', + 'Ridley', + 'Orest', + 'Ramzi', + 'Kaikea', + 'Kamahao', + 'Kyrillos', + 'Mace', + 'Lyrik', + 'Lyon', + 'Lux', + 'Ashkan', + 'Jurgen', + 'Khachik', + 'Maher', + 'Jaccob', + 'Jagdeep', + 'Wash', + 'Simpson', + 'Macy', + 'Haylee', + 'Hope', + 'Katie', + 'Thurmon', + 'Savanna', + 'Zoey', + 'Atiba', + 'Dylann', + 'Kaylen', + 'Helio', + 'Geovannie', + 'Praneel', + 'Kamau', + 'Rhamel', + 'Knoah', + 'Harm', + 'Nyle', + 'Maveric', + 'Neithan', + 'Niklaus', + 'Lejon', + 'Wai', + 'Indigo', + 'Sayed', + 'Abdias', + 'Daniil', + 'Rashod', + 'Wren', + 'Chico', + 'Jamarri', + 'Leiland', + 'Ranvir', + 'Mavrick', + 'Matai', + 'Deveon', + 'Teyon', + 'Ramell', + 'Haik', + 'Dupree', + 'Emon', + 'Jermal', + 'Bayley', + 'Marshell', + 'Blouncie', + 'Larson', + 'Lorenz', + 'Jhovanny', + 'Jeffie', + 'Portia', + 'Adron', + 'Calogero', + 'Mathews', + 'Aundra', + 'Aariv', + 'Keniel', + 'Jameis', + 'Konstantin', + 'Khayden', + 'Manford', + 'Polo', + 'Chanel', + 'Brittani', + 'Kazuki', + 'Kaelen', + 'Alice', + 'Maya', + 'Madeleine', + 'Kiana', + 'Latasha', + 'Felicia', + 'Gabriella', + 'Bolivar', + 'Eileen', + 'Alister', + 'Aidenn', + 'Nina', + 'Ellington', + 'Alecsander', + 'Ja', + 'Jarmaine', + 'Kyriakos', + 'Apostolos', + 'Leshawn', + 'Shondell', + 'Matvey', + 'Savino', + 'Zakariye', + 'Dozier', + 'Holland', + 'Haruto', + 'Hendrik', + 'Allah', + 'Johnanthony', + 'Eliyah', + 'Champ', + 'Dastan', + 'Caliph', + 'Manish', + 'Agostino', + 'Kaio', + 'Avyaan', + 'Gerasimos', + 'Refujio', + 'Munir', + 'Abdurrahman', + 'Selso', + 'Epimenio', + 'Suhayb', + 'Jock', + 'Larwence', + 'Saadiq', + 'Lilburn', + 'Selestino', + 'Randi', + 'Nysir', + 'Harlyn', + 'Basir', + 'Kathy', + 'Teddie', + 'Luqman', + 'Tyhir', + 'Mubarak', + 'Ridwan', + 'Filemon', + 'Bergen', + 'Danney', + 'Eual', + 'Melburn', + 'Esiquio', + 'Cree', + 'Dorwin', + 'Naasir', + 'Ysmael', + 'Nirav', + 'Chuckie', + 'Lashaun', + 'Darris', + 'Blase', + 'Kiley', + 'Demarko', + 'Taiwan', + 'Lamon', + 'Corrie', + 'Feras', + 'Excell', + 'Cornelious', + 'Martinez', + 'Marvel', + 'Climmie', + 'Martrell', + 'Valley', + 'Lonie', + 'Jovante', + 'Lavante', + 'Lugene', + 'Cordarro', + 'Lacey', + 'Derrius', + 'Tedd', + 'Levell', + 'Linas', + 'Taras', + 'Toma', + 'Klint', + 'Gualberto', + 'Feliberto', + 'Tarrance', + 'Theran', + 'Lakeith', + 'Mearl', + 'Karry', + 'Denarius', + 'Dontarius', + 'Nikia', + 'Rakesh', + 'Not', + 'Darek', + 'Gery', + 'Ontario', + 'Jimi', + 'Shamarion', + 'Kedarius', + 'Jermarcus', + 'Amarie', + 'Kordae', + 'Montie', + 'Haleem', + 'Inocencio', + 'Brockton', + 'Yoshiaki', + 'Ponciano', + 'Silvester', + 'Derron', + 'Davaughn', + 'Urie', + 'Juanito', + 'Corky', + 'Pasqual', + 'Marilyn', + 'Morley', + 'Ayoub', + 'Eliasar', + 'Mickel', + 'Skylor', + 'Kewan', + 'Teon', + 'Rafal', + 'Devanta', + 'Rosco', + 'Tywon', + 'Evon', + 'Cleven', + 'Hardie', + 'Tori', + 'Trayvond', + 'Maaz', + 'Masashi', + 'Neno', + 'Kahari', + 'Terri', + 'Toru', + 'Jalynn', + 'Avonte', + 'Satchel', + 'Tanya', + 'Kalab', + 'Avetis', + 'Miko', + 'Kodiak', + 'Lang', + 'Leondre', + 'Purnell', + 'Harutyun', + 'Gorman', + 'Vong', + 'Shervin', + 'Soloman', + 'Sue', + 'Amandeep', + 'Amritpal', + 'Leonides', + 'Melecio', + 'Mikhael', + 'Estaban', + 'Arius', + 'Calix', + 'Gurtaj', + 'Dilraj', + 'Dillinger', + 'Aidden', + 'Shivansh', + 'Shravan', + 'Saud', + 'Yarel', + 'Riker', + 'Yareth', + 'Zeppelin', + 'Ladarious', + 'Lucan', + 'Terren', + 'Tustin', + 'Nicolaas', + 'Rakan', + 'Johnjoseph', + 'Hovanes', + 'Navjot', + 'Henrique', + 'Marsalis', + 'Karanveer', + 'Jeffren', + 'Khairi', + 'Haruki', + 'Jadden', + 'Iliya', + 'Hansen', + 'Srihan', + 'Sartaj', + 'Rishik', + 'Rishan', + 'Octavian', + 'Ranbir', + 'Padraic', + 'Tanush', + 'Tlaloc', + 'Cadarius', + 'Yared', + 'Vahan', + 'Lakai', + 'Fionn', + 'Eziah', + 'Emillio', + 'Hakob', + 'Gryphon', + 'Harsha', + 'Hiroto', + 'Nivaan', + 'Radin', + 'Nicasio', + 'Mael', + 'Lysander', + 'Rees', + 'Roemello', + 'Bretton', + 'Christoph', + 'Eliceo', + 'Armany', + 'Axell', + 'Bogdan', + 'Luan', + 'Aldon', + 'Aeson', + 'Adhvik', + 'Jese', + 'Blanca', + 'Crisanto', + 'Dietrich', + 'Tarin', + 'Yama', + 'Yia', + 'Omeed', + 'Arbie', + 'Shayn', + 'Ranferi', + 'Ricard', + 'Farmer', + 'Goble', + 'Herald', + 'Hager', + 'Elva', + 'Carlis', + 'Evertt', + 'Ledford', + 'Dequarius', + 'Hughie', + 'Burgess', + 'Kourosh', + 'Jaun', + 'Nicko', + 'Victorhugo', + 'Roverto', + 'Shadi', + 'Sopheak', + 'Acie', + 'Demar', + 'Carolina', + 'Vinal', + 'Earland', + 'Sergey', + 'Dayon', + 'Kwamaine', + 'Kerney', + 'Ola', + 'Welby', + 'Kyon', + 'Tyion', + 'Kiyon', + 'Neng', + 'Raquel', + 'Nadeem', + 'Terran', + 'Tin', + 'Rudi', + 'Murad', + 'Murrell', + 'Lenville', + 'Rondall', + 'Han', + 'Hovhannes', + 'Karapet', + 'Hamed', + 'Alasdair', + 'Agam', + 'Areg', + 'Ariston', + 'Askari', + 'Ayansh', + 'Byran', + 'Dolan', + 'Devonn', + 'Edith', + 'Christoffer', + 'Alaa', + 'Ashraf', + 'Rondle', + 'Tavarius', + 'Michaeljames', + 'Nichols', + 'Sonia', + 'Ryanchristopher', + 'Garo', + 'Hien', + 'Corin', + 'Dillin', + 'Jerid', + 'Jesusalberto', + 'Zeferino', + 'Gobel', + 'Tykeem', + 'Miking', + 'Juno', + 'Jiraiya', + 'Kailash', + 'Madix', + 'Lucciano', + 'Llewyn', + 'Leone', + 'Knight', + 'Dorse', + 'Oak', + 'Irie', + 'Brodi', + 'Hridhaan', + 'Coda', + 'Dekker', + 'Evren', + 'Eisen', + 'Eddison', + 'Donatello', + 'Happy', + 'Devron', + 'Suleiman', + 'Siddhanth', + 'Zorawar', + 'Zadkiel', + 'Waylan', + 'Valor', + 'Triton', + 'Govanni', + 'Angelus', + 'Ashvin', + 'Matthews', + 'Elver', + 'Brendin', + 'Rhea', + 'Jyron', + 'Matisse', + 'Karanvir', + 'Kenshin', + 'Saketh', + 'Trigo', + 'Wil', + 'Tyrick', + 'Trejon', + 'Manvir', + 'Sascha', + 'Samay', + 'Prabhjot', + 'Piers', + 'Arshia', + 'Karo', + 'Makani', + 'Ludwin', + 'Kean', + 'Nikoli', + 'Garlin', + 'Georgio', + 'Jyren', + 'Ledell', + 'Jayceion', + 'Wiltz', + 'Elgie', + 'Jediah', + 'Izzac', + 'Izeyah', + 'Jeyson', + 'Hamid', + 'Jalani', + 'Rohin', + 'Shiva', + 'Ramces', + 'Claudell', + 'Daymien', + 'Aeron', + 'Aadan', + 'Alesandro', + 'Aleksey', + 'Galileo', + 'Esvin', + 'Indy', + 'Graden', + 'Gor', + 'Vlad', + 'Kendrell', + 'Saket', + 'Asahel', + 'Blue', + 'Arshdeep', + 'Adain', + 'Keneth', + 'Jacy', + 'Dasan', + 'Haniel', + 'Ethin', + 'Ericson', + 'Izick', + 'Elisandro', + 'Coltrane', + 'Kemani', + 'Josearmando', + 'Josealfredo', + 'Alias', + 'Anurag', + 'Carlitos', + 'Ceaser', + 'Sukhraj', + 'Severin', + 'Nishanth', + 'Mattox', + 'Rhiley', + 'Dareon', + 'Danyel', + 'Calan', + 'Nithin', + 'Donivan', + 'Taye', + 'Trustin', + 'Igor', + 'Jayr', + 'Kayin', + 'Pleas', + 'Aadit', + 'Balam', + 'Jovannie', + 'Quintrell', + 'Japheth', + 'Hero', + 'Edu', + 'Duvan', + 'Anden', + 'Anshul', + 'Ailton', + 'Raybon', + 'Rabon', + 'Kendry', + 'Manases', + 'Damyan', + 'Braven', + 'Dhani', + 'Isaia', + 'Hovik', + 'Sonnie', + 'Wolfe', + 'Banyan', + 'Hiroki', + 'Matin', + 'Sequoia', + 'Acelin', + 'Aarya', + 'Arsalan', + 'Carlosdaniel', + 'Jaryd', + 'Ariana', + 'Kylee', + 'Mariah', + 'Serenity', + 'Kailey', + 'Delaney', + 'Emilee', + 'Isabelle', + 'Jayla', + 'Drue', + 'Emani', + 'Juandedios', + 'Kedar', + 'Baily', + 'Daijon', + 'Daman', + 'Kentaro', + 'Damaria', + 'Mareco', + 'Valmore', + 'Theophile', + 'Winslow', + 'Ugo', + 'Cainan', + 'Finian', + 'Keiji', + 'Issack', + 'Blanchard', + 'Domingos', + 'Jarin', + 'Giovan', + 'Ovila', + 'Lovelace', + 'Albion', + 'Curry', + 'Christophr', + 'Nolton', + 'Unborn', + 'Torry', + 'Yoshi', + 'Perrion', + 'Nathyn', + 'Syler', + 'Sheila', + 'Jaedan', + 'Cobey', + 'Bashar', + 'Ehsan', + 'Daryll', + 'Seann', + 'Niels', + 'Nazar', + 'Frederico', + 'Esther', + 'Bobie', + 'Loyce', + 'Heberto', + 'Bentura', + 'Jafar', + 'Keigan', + 'Bertil', + 'Aloys', + 'Janie', + 'Paz', + 'Damacio', + 'Oiva', + 'Ingvald', + 'Walfred', + 'Jakeob', + 'Georgie', + 'Alcuin', + 'Raynold', + 'Josey', + 'Lasaro', + 'Jo', + 'Hjalmer', + 'Philemon', + 'Paula', + 'Christophor', + 'Estanislao', + 'Angelita', + 'Anacleto', + 'Alfons', + 'Lawayne', + 'Delrico', + 'Clemson', + 'Jaleen', + 'Jerimy', + 'Javaughn', + 'Tiofilo', + 'Hubbard', + 'Abundio', + 'Derl', + 'Keagen', + 'Aymen', + 'Freedom', + 'Venancio', + 'Pauline', + 'Gorden', + 'Hani', + 'Pharrell', + 'Jager', + 'Nyair', + 'Azeem', + 'Khyir', + 'Jabriel', + 'Yandiel', + 'Zaahir', + 'Laine', + 'Xai', + 'Vernard', + 'Augie', + 'Sostenes', + 'Darryll', + 'Asir', + 'Lindon', + 'Jearl', + 'Peder', + 'Rudolpho', + 'Clancy', + 'Yue', + 'Ronnald', + 'Onofre', + 'Kysir', + 'Helmuth', + 'Marlowe', + 'Derk', + 'Demetrick', + 'Jefrey', + 'Burrell', + 'Robie', + 'Marlan', + 'Thane', + 'Jamire', + 'Donnel', + 'Syaire', + 'York', + 'Asaad', + 'Kyair', + 'Devere', + 'Wing', + 'Yaniv', + 'Mathhew', + 'Silvia', + 'Chia', + 'Bren', + 'Cavin', + 'Aldrich', + 'Judy', + 'Erron', + 'Butler', + 'Carole', + 'Almon', + 'Gilles', + 'Christin', + 'Renald', + 'Sony', + 'Chavis', + 'Nghia', + 'Mercedes', + 'Real', + 'Josejesus', + 'Ryman', + 'Kori', + 'Ichael', + 'Jabier', + 'Nguyen', + 'Angeldejesus', + 'Bobak', + 'Brittan', + 'Shaunt', + 'Karlton', + 'Jerin', + 'Gerado', + 'Raymund', + 'Kerolos', + 'Rolan', + 'Wilbern', + 'Sipriano', + 'Hermes', + 'Robyn', + 'Ynes', + 'Vernice', + 'Pink', + 'Jevonte', + 'Jerame', + 'Tajuan', + 'Mingo', + 'Jeremia', + 'Edmon', + 'Castulo', + 'Cleofas', + 'Arlee', + 'Oather', + 'Larkin', + 'Mcarther', + 'Ryann', + 'Hong', + 'Jamieson', + 'Enedino', + 'Gerad', + 'Lenord', + 'Alireza', + 'Hollie', + 'Gilford', + 'Lajuane', + 'Izell', + 'Trenidad', + 'Shelley', + 'Ulysees', + 'Juana', + 'Coalton', + 'Remer', + 'Raiford', + 'Caydon', + 'Dalyn', + 'Wilhelm', + 'Lenzy', + 'Bartow', + 'Tibor', + 'Cebert', + 'Elizar', + 'Ellen', + 'Uchenna', + 'Toy', + 'Curlee', + 'Ralf', + 'Giulio', + 'Conway', + 'Ngai', + 'Chaka', + 'Engelbert', + 'Auburn', + 'Socrates', + 'Kostas', + 'Kamalei', + 'Kupono', + 'Carrell', + 'Lister', + 'Mattie', + 'Thermon', + 'Tina', + 'Kennan', + 'Adison', + 'Dalon', + 'Ephram', + 'Jaylynn', + 'Zabdiel', + 'Kaidon', + 'Juvencio', + 'Havis', + 'Dagan', + 'Dacorian', + 'Donavyn', + 'Evyn', + 'Issai', + 'Zenon', + 'Inman', + 'Hason', + 'Lehman', + 'Afton', + 'Clayborn', + 'Abrahm', + 'Neill', + 'Conard', + 'Mutsuo', + 'Seikichi', + 'Wetzel', + 'Masaji', + 'Masanobu', + 'Shigeto', + 'Edgel', + 'Goro', + 'Lovett', + 'Seiko', + 'Sakae', + 'Roshawn', + 'Antjuan', + 'Erby', + 'Jobe', + 'Ladarian', + 'Cyler', + 'Edel', + 'Hartsel', + 'Jill', + 'Jami', + 'Rabun', + 'Fulton', + 'Dreddy', + 'Corrado', + 'Harald', + 'Alterick', + 'Hala', + 'Powell', + 'Lesly', + 'Kalon', + 'Theodoros', + 'Etan', + 'Trev', + 'Javiel', + 'Jusiah', + 'Joncarlos', + 'Jhamari', + 'Rasheim', + 'Raysean', + 'Kreg', + 'Rahmell', + 'Kerby', + 'Eliga', + 'Clemon', + 'Aneudy', + 'Keiran', + 'Kensley', + 'Ludie', + 'Jorell', + 'Can', + 'Demondre', + 'Cierra', + 'Maurizio', + 'Tacuma', + 'Ryzen', + 'Jabar', + 'Tara', + 'Reign', + 'Jashon', + 'Lasean', + 'Artavius', + 'Akbar', + 'Un', + 'Kaikane', + 'Tanisha', + 'Elena', + 'Bridget', + 'Asia', + 'Latisha', + 'Rachael', + 'Latoya', + 'Elisabeth', + 'Janelle', + 'Ikea', + 'Kobey', + 'Kamaehu', + 'Keona', + 'Calixto', + 'Theotis', + 'Worthy', + 'Galo', + 'Holly', + 'Sevyn', + 'Petr', + 'Cerrone', + 'Tedrick', + 'Kymari', + 'Gerrard', + 'Eldo', + 'Alcides', + 'Derrian', + 'Eulas', + 'Leodis', + 'Akai', + 'Dalonte', + 'Pantelis', + 'Sheron', + 'Tommaso', + 'Treg', + 'Shirl', + 'Abrian', + 'Brewer', + 'Yamir', + 'Zadok', + 'Holdyn', + 'Jayanthony', + 'Eh', + 'Dayson', + 'Khaden', + 'Quintez', + 'Rontavious', + 'Markese', + 'Quintavis', + 'Daveion', + 'Tonny', + 'Jaevon', + 'Ahkeem', + 'Hy', + 'Adams', + 'Marian', + 'Huner', + 'Jarmarcus', + 'Treyon', + 'Tullio', + 'Oreste', + 'Oleg', + 'Xzavien', + 'Atzel', + 'Brenan', + 'Abriel', + 'Braylyn', + 'Chidera', + 'Lebaron', + 'Jameir', + 'Kameryn', + 'Shade', + 'Koltin', + 'Cordarrius', + 'Amelio', + 'Demarquez', + 'Tarus', + 'Calob', + 'Dmarco', + 'Creek', + 'Amen', + 'Cylas', + 'Davyn', + 'Haygen', + 'Godric', + 'Garn', + 'Renardo', + 'Locke', + 'Lexington', + 'Mazin', + 'Othniel', + 'Kruze', + 'Jaxston', + 'Jaxten', + 'Jeziah', + 'Jettson', + 'Zebastian', + 'Sarim', + 'Jawuan', + 'Tremain', + 'Hassell', + 'Quartez', + 'Hawkins', + 'Riggs', + 'Rebel', + 'Nael', + 'Kaycen', + 'Kamsiyochukwu', + 'Kagen', + 'Jrue', + 'Jaydeen', + 'Azazel', + 'Ayson', + 'Cheston', + 'Aarian', + 'Chavez', + 'Void', + 'Zacariah', + 'Keena', + 'Antwuan', + 'Labarron', + 'Quamere', + 'Mikell', + 'Prestyn', + 'Savian', + 'Dayden', + 'Jaivion', + 'Geremiah', + 'Aidon', + 'Bralyn', + 'Gianncarlo', + 'Jarquavious', + 'Muriel', + 'Akshar', + 'Kadir', + 'Najir', + 'Neko', + 'Jahaad', + 'Jdyn', + 'Kashon', + 'Jaquil', + 'Wah', + 'Delmos', + 'Masuo', + 'Nobuichi', + 'Kiichi', + 'Jerone', + 'Tatsumi', + 'Damarian', + 'Elier', + 'Lansing', + 'Heinrich', + 'Hasson', + 'Larrie', + 'Phyllis', + 'Jamoni', + 'Zylen', + 'Demoni', + 'Harrel', + 'Levie', + 'Zaryan', + 'Orazio', + 'Seymore', + 'Florence', + 'Kolter', + 'Kemper', + 'Daelyn', + 'Haddon', + 'Syon', + 'Sair', + 'Filadelfio', + 'Marquavion', + 'Breylon', + 'Filimon', + 'Abie', + 'Cortavious', + 'Achille', + 'Dontrez', + 'Matty', + 'Darshawn', + 'Overton', + 'Bashir', + 'Kavan', + 'Caidan', + 'Braelen', + 'Param', + 'Kani', + 'Percival', + 'Hartley', + 'Erminio', + 'Candler', + 'Ulyssee', + 'Damontae', + 'Ellijah', + 'Cesare', + 'Eleanor', + 'Eustace', + 'Joachim', + 'Tarique', + 'Altin', + 'Tyleek', + 'Posey', + 'Awais', + 'Daivon', + 'Zi', + 'Hammad', + 'Meshulem', + 'Nickie', + 'Brehon', + 'Dacoda', + 'Kwamane', + 'Rafuel', + 'Mikai', + 'Hensel', + 'Thelbert', + 'Valerio', + 'Trevonte', + 'Koran', + 'Cheick', + 'Shahzaib', + 'Tahsin', + 'Derry', + 'Mustapha', + 'Chucky', + 'Osborne', + 'Daquarius', + 'Marque', + 'Raquon', + 'Cherokee', + 'Keyshaun', + 'Mohamadou', + 'Keishawn', + 'Jahmeek', + 'Junaid', + 'Amil', + 'Mckoy', + 'Zackry', + 'Nyheim', + 'Nkosi', + 'Kweli', + 'Tydarius', + 'Umer', + 'Demorris', + 'Demarquis', + 'Hersch', + 'Luzer', + 'Li', + 'Aly', + 'Quade', + 'Quamaine', + 'Markee', + 'Jhoan', + 'Mert', + 'Supreme', + 'Tyheem', + 'Gomer', + 'Taseen', + 'Yousaf', + 'Yonason', + 'Gifford', + 'Ashar', + 'Sender', + 'Salah', + 'Saifan', + 'Raihan', + 'Nizar', + 'Abrahim', + 'Kunga', + 'Javis', + 'Evens', + 'Bayard', + 'Kaysan', + 'Padraig', + 'Ney', + 'Ahmet', + 'Misty', + 'Ayyan', + 'Saint', + 'Fern', + 'Wasil', + 'Nolie', + 'Zarif', + 'Younis', + 'Eesa', + 'Ketrick', + 'Veryl', + 'Refael', + 'Motty', + 'Naftuly', + 'Waseem', + 'Yusif', + 'Brigg', + 'Zaheer', + 'Shiya', + 'Karma', + 'Meilich', + 'Mihran', + 'Javares', + 'Efe', + 'Abubakr', + 'Avrumi', + 'Nayshawn', + 'Mostafa', + 'Hinckley', + 'Jahmeir', + 'Fintan', + 'Sollie', + 'Amiel', + 'Abu', + 'Yaro', + 'Josha', + 'Jermane', + 'Bertis', + 'Hernando', + 'Gerrod', + 'Haim', + 'Frandy', + 'Andrews', + 'Dayle', + 'Fleming', + 'Volvi', + 'Savior', + 'Shuford', + 'Plummer', + 'Ralston', + 'Dayvion', + 'Muhamed', + 'Naheem', + 'Nataniel', + 'Kaeleb', + 'Billyjoe', + 'Able', + 'Fareed', + 'Purcell', + 'Trayson', + 'Mackay', + 'Moyer', + 'Haynes', + 'Domnick', + 'Burnie', + 'Gleen', + 'Leavy', + 'Lennart', + 'Breken', + 'Arlind', + 'Clarnce', + 'Nissen', + 'Josiel', + 'Alvester', + 'Jaquay', + 'Nickolaos', + 'Ruddy', + 'Berkeley', + 'Flamur', + 'Sherif', + 'Shateek', + 'Ayodele', + 'Davone', + 'Meshach', + 'Kinston', + 'Algernon', + 'Dvonte', + 'Jawara', + 'Zamar', + 'Dayron', + 'Jaequan', + 'Tyrelle', + 'Jazion', + 'Tamel', + 'Torris', + 'Marguis', + 'Yuniel', + 'Saige', + 'Gottlieb', + 'Cori', + 'Dre', + 'Yordan', + 'Shaquell', + 'Jonel', + 'Kashaun', + 'Arjenis', + 'Tashan', + 'Fitzroy', + 'Francisc', + 'Kwaku', + 'Jakyri', + 'Trayton', + 'Jarrick', + 'Reginaldo', + 'Facundo', + 'Elma', + 'Dardan', + 'Dreshawn', + 'Demontray', + 'Chaddrick', + 'Roper', + 'Taariq', + 'Ausitn', + 'Jachai', + 'Duval', + 'Braun', + 'Taylan', + 'Dionis', + 'Samy', + 'Armistead', + 'Alize', + 'Tayshon', + 'Ainsley', + 'Kaheem', + 'Jaire', + 'Kyshawn', + 'Nahshon', + 'Aaliyah', + 'Shanard', + 'Azion', + 'Alana', + 'Alexia', + 'Breyon', + 'Trigg', + 'Wylder', + 'Zaydin', + 'Ziaire', + 'Zixuan', + 'Yanis', + 'Zair', + 'Zaven', + 'Alanmichael', + 'Viyan', + 'Vivan', + 'Klay', + 'Erico', + 'Tycho', + 'Waris', + 'Winter', + 'Aliyah', + 'Kamilo', + 'Kei', + 'Glendell', + 'Lilly', + 'Lauryn', + 'Jovian', + 'Shayla', + 'Tessa', + 'Jupiter', + 'Aaric', + 'Aadhav', + 'Jetson', + 'Abir', + 'Adhrit', + 'Alexandr', + 'Brooklynn', + 'Callie', + 'Ashlee', + 'Ashlyn', + 'Haleigh', + 'Heaven', + 'Jahkari', + 'Izaiyah', + 'Troyce', + 'Bige', + 'Hayze', + 'Neldon', + 'Marven', + 'Beckem', + 'Dvante', + 'Navarro', + 'Neiko', + 'Noeh', + 'Jen', + 'Torrian', + 'Helios', + 'Macallan', + 'Lio', + 'Wilkens', + 'Merrik', + 'Ameal', + 'Mujtaba', + 'Iktan', + 'Kavious', + 'Monterrio', + 'Hughey', + 'Calin', + 'Cali', + 'Jamaar', + 'Kenith', + 'Rihaan', + 'Deaglan', + 'Kelso', + 'Lavaris', + 'Ashot', + 'Marshun', + 'Rainer', + 'Rivan', + 'Talal', + 'Taiyo', + 'Minor', + 'Yvon', + 'Stonewall', + 'Merril', + 'Okie', + 'Trevino', + 'Imari', + 'Ithan', + 'Izmael', + 'Jayan', + 'Harut', + 'Harshaan', + 'Kainen', + 'Kalyan', + 'Kanishk', + 'Kotaro', + 'Josyah', + 'Vola', + 'Omarie', + 'Dmari', + 'Mannix', + 'Elad', + 'Shun', + 'Andriy', + 'Angelino', + 'Ary', + 'Axcel', + 'Becker', + 'Daxten', + 'Daemian', + 'Cypress', + 'Jakhai', + 'Warnie', + 'Maikel', + 'Davinci', + 'Calloway', + 'Vernal', + 'Tyrome', + 'Mont', + 'Ovie', + 'Hester', + 'Arvis', + 'Corbit', + 'Tarvaris', + 'Audra', + 'Cloud', + 'Taveon', + 'Balian', + 'Bodi', + 'Brodee', + 'Kainan', + 'Dezi', + 'Devesh', + 'Emad', + 'Esa', + 'Massie', + 'Moir', + 'Markavious', + 'Veachel', + 'Dalan', + 'Carles', + 'Antawn', + 'Jermichael', + 'Talin', + 'Sy', + 'Murrel', + 'Elster', + 'Kru', + 'Okley', + 'Maverik', + 'Diangelo', + 'Burns', + 'Jamaris', + 'Jayshaun', + 'Dantae', + 'Rahil', + 'Renny', + 'Rohith', + 'Strummer', + 'Birchel', + 'Astor', + 'Nolyn', + 'Neeko', + 'Reyan', + 'Kailan', + 'Jaideep', + 'Manveer', + 'Maeson', + 'Khris', + 'Lancelot', + 'Shaunak', + 'Shubham', + 'Siaosi', + 'Ruslan', + 'Sajan', + 'Renwick', + 'Yann', + 'Vitali', + 'Zealand', + 'Vyom', + 'Xabi', + 'Yazid', + 'Terrelle', + 'Oaks', + 'Kache', + 'Arjuna', + 'Cephas', + 'Holmes', + 'Rockie', + 'Elray', + 'Doc', + 'Mell', + 'Tyresse', + 'Maguire', + 'Sheddrick', + 'Loney', + 'Helaman', + 'Andrus', + 'Asberry', + 'Love', + 'Clebert', + 'Cashius', + 'Egypt', + 'Devansh', + 'Elige', + 'Tobe', + 'Taten', + 'Arias', + 'Leandrew', + 'Dekota', + 'Varian', + 'Lehi', + 'Colbert', + 'Ignace', + 'Suhas', + 'Syris', + 'Ahan', + 'Aithan', + 'Aiven', + 'Akshath', + 'Hamp', + 'Kato', + 'Leeon', + 'Reubin', + 'Lukah', + 'Wilmon', + 'Tait', + 'Theophilus', + 'Sion', + 'Maysen', + 'Nicoli', + 'Nason', + 'Mykell', + 'Montae', + 'Laszlo', + 'Lestat', + 'Prithvi', + 'Maxi', + 'Mekhai', + 'Hammond', + 'Atiksh', + 'Aldean', + 'Aldine', + 'Jedi', + 'Almond', + 'Edahi', + 'Hisham', + 'Clide', + 'Cosby', + 'Hayato', + 'Harnoor', + 'Gurjot', + 'Ethridge', + 'Dublin', + 'Daimian', + 'Derreon', + 'Hansell', + 'Mae', + 'Semisi', + 'Ulysess', + 'Render', + 'Eschol', + 'Rodell', + 'Atzin', + 'Alik', + 'Amiri', + 'Keyvon', + 'Noland', + 'Terius', + 'Isauro', + 'Harshith', + 'Pledger', + 'Tilman', + 'Lennis', + 'Jovin', + 'Jaymin', + 'Jaydee', + 'Asbury', + 'Lovie', + 'Mcclinton', + 'Grayton', + 'Cardin', + 'Jacey', + 'Gurveer', + 'Ethanmatthew', + 'Aaronjames', + 'Ascher', + 'Aarion', + 'Windle', + 'Jahan', + 'Jayen', + 'Jatin', + 'Jedrek', + 'Anthonyjr', + 'Dabney', + 'Galvin', + 'Ilijah', + 'Gohan', + 'Quaid', + 'Teancum', + 'Chael', + 'Chetan', + 'Cylis', + 'Manas', + 'Logun', + 'Karston', + 'Mickeal', + 'Iskander', + 'Isaah', + 'Aryaman', + 'Juvens', + 'Joncarlo', + 'Gurkirat', + 'Laymon', + 'Salesi', + 'Rion', + 'Tao', + 'Tadhg', + 'Stephens', + 'Terryl', + 'Jacquan', + 'Zubin', + 'Yul', + 'Yadriel', + 'Dolph', + 'Keiden', + 'Koston', + 'Demetre', + 'Kameren', + 'Kaedin', + 'Zebedee', + 'Tyrie', + 'Truth', + 'Lanorris', + 'Tilden', + 'Tidus', + 'Thelonious', + 'Tennessee', + 'Sirius', + 'Pervis', + 'Saatvik', + 'Adley', + 'Amarian', + 'Numa', + 'Bronco', + 'Zian', + 'Zephan', + 'Yaziel', + 'Ajit', + 'Arick', + 'Ollin', + 'Kort', + 'Tayvin', + 'Grason', + 'Leonid', + 'Nihaal', + 'Koah', + 'Southern', + 'Kavish', + 'Joeziah', + 'Javi', + 'Kaiyan', + 'Kyro', + 'Ziad', + 'Maxen', + 'Xion', + 'Mica', + 'Mansour', + 'Matteus', + 'Renner', + 'Jonan', + 'Shilo', + 'Josedaniel', + 'Kaj', + 'Robel', + 'Krithik', + 'Lautaro', + 'Evann', + 'Carden', + 'Nathaneal', + 'Wirt', + 'Kile', + 'Kevonte', + 'Jazz', + 'Vardan', + 'Tanav', + 'Tamim', + 'Ojani', + 'Raydel', + 'Rigel', + 'Sheamus', + 'Cameryn', + 'Jedd', + 'Dalessandro', + 'Daejon', + 'Zacheriah', + 'Jt', + 'Valeria', + 'Treshon', + 'Martynas', + 'Markeese', + 'Ladislado', + 'Fidensio', + 'Cincere', + 'Amonte', + 'Erion', + 'Emin', + 'Tayten', + 'Zachory', + 'Ysidoro', + 'Treshaun', + 'Franciszek', + 'Adit', + 'Neftaly', + 'Kaylan', + 'Dezmon', + 'Joby', + 'Terrick', + 'Irma', + 'Isiaha', + 'Micha', + 'Sylvia', + 'Dejan', + 'Kippy', + 'Tyreece', + 'Corie', + 'Martese', + 'Senovio', + 'Lexus', + 'Freddrick', + 'Jemarcus', + 'Kuba', + 'Corion', + 'Andrian', + 'Romualdo', + 'Lyndal', + 'Kalem', + 'Laderrick', + 'Jobin', + 'Chaise', + 'Naren', + 'Reynol', + 'Ohm', + 'Trashawn', + 'Danyell', + 'Diron', + 'Kameran', + 'Dunte', + 'Ikechukwu', + 'Trendon', + 'Visente', + 'Valeriano', + 'Dillian', + 'Chantz', + 'Bacilio', + 'Crescencio', + 'Policarpio', + 'Janice', + 'Kem', + 'Rutilio', + 'Jaqualin', + 'Kendon', + 'Keevin', + 'Adelaido', + 'Coltan', + 'Theodoro', + 'Devondre', + 'Dekendrick', + 'Deionte', + 'Taz', + 'Jimmey', + 'Cristan', + 'Chancelor', + 'Ascension', + 'Kemon', + 'Makari', + 'Cordel', + 'Colbey', + 'Ambrocio', + 'Marselino', + 'Dewain', + 'Graciano', + 'Gumecindo', + 'Lorenso', + 'Quaylon', + 'Halbert', + 'Celedonio', + 'Terrin', + 'Zuri', + 'Sherod', + 'Ermal', + 'Elisa', + 'Larnell', + 'Tully', + 'Wenceslaus', + 'Lashun', + 'Duan', + 'Correy', + 'Wilburt', + 'Antwoin', + 'Lynell', + 'Ramond', + 'Victorio', + 'Antion', + 'Dragan', + 'Priest', + 'Marice', + 'Laroy', + 'Ninos', + 'Byrl', + 'Ebert', + 'Keita', + 'Dimitris', + 'Zoran', + 'Khaalis', + 'Rollo', + 'Alwin', + 'Loraine', + 'Jerard', + 'Lyndle', + 'Quirino', + 'Ramey', + 'Jarian', + 'Marky', + 'Adlai', + 'Shamon', + 'Treyshawn', + 'Shaft', + 'Gumercindo', + 'Rita', + 'Derryl', + 'Chancy', + 'Kacy', + 'Jonothan', + 'Ruston', + 'Ranulfo', + 'Talik', + 'Johntae', + 'Kendale', + 'Diandre', + 'Reginold', + 'Tyris', + 'Davell', + 'Ladell', + 'Raymone', + 'Mariusz', + 'Edvardo', + 'Joh', + 'Lavontae', + 'Markie', + 'Laquinton', + 'Alexandar', + 'Divante', + 'Jabin', + 'Shawon', + 'Jawann', + 'Ladd', + 'Khali', + 'Gilmore', + 'Oliverio', + 'Thuan', + 'Daiel', + 'Kierre', + 'Javar', + 'Stevon', + 'Derius', + 'Chadley', + 'Manual', + 'Johnaton', + 'Lc', + 'Erek', + 'Jakaden', + 'Jden', + 'Drayke', + 'Dawsen', + 'Jadarion', + 'Shriyans', + 'Raylin', + 'Kaydan', + 'Lynden', + 'Duard', + 'Elo', + 'Amarius', + 'Cleburne', + 'Dailen', + 'Brance', + 'Braycen', + 'Daiden', + 'Cruzito', + 'Caedyn', + 'Aizik', + 'Abyan', + 'Felisiano', + 'Taevion', + 'Zaeden', + 'Zadrian', + 'Fredie', + 'Burnis', + 'Cleave', + 'Ki', + 'Quandarius', + 'Quavion', + 'Makell', + 'Myrl', + 'Tae', + 'Melik', + 'Samarion', + 'Branton', + 'Vollie', + 'Reynolds', + 'Draylon', + 'Keivon', + 'Kevontae', + 'Deundre', + 'Zaydrian', + 'Zaydan', + 'Jotham', + 'Janthony', + 'Sahid', + 'Keilon', + 'Lain', + 'Kenechukwu', + 'Kanaan', + 'Kamdon', + 'Ahmod', + 'Dong', + 'Nnamdi', + 'Jontavius', + 'Kelijah', + 'Searcy', + 'Wheeler', + 'Francisca', + 'Burrel', + 'Zyquavious', + 'Kortez', + 'Tres', + 'Tranquilino', + 'Guinn', + 'Hiawatha', + 'Jasiyah', + 'Arlos', + 'Celestine', + 'Deadrian', + 'Chinedu', + 'Cane', + 'Caedon', + 'Gabryel', + 'Garon', + 'Solon', + 'Udell', + 'Medardo', + 'Chon', + 'Zakk', + 'Trip', + 'Somtochukwu', + 'Shooter', + 'Frutoso', + 'Laurencio', + 'Izayiah', + 'Franko', + 'Izzak', + 'Braelan', + 'Dryden', + 'Wilborn', + 'Newt', + 'Petronilo', + 'Nathanel', + 'Jatavius', + 'Locadio', + 'Tyquez', + 'Laiden', + 'Allister', + 'Javarion', + 'Demarrio', + 'Shenouda', + 'Rodriques', + 'Jenard', + 'Azarias', + 'Axxel', + 'Ariyan', + 'Pate', + 'Raidyn', + 'Saylor', + 'Kreed', + 'Kayce', + 'Bray', + 'Zyren', + 'Zayvien', + 'Yeiden', + 'Kinta', + 'Trampus', + 'Lofton', + 'Zayvian', + 'Zaydon', + 'Zaidan', + 'Weslee', + 'Robben', + 'Rook', + 'Roston', + 'Trigger', + 'Steel', + 'Rustyn', + 'Jaeceon', + 'Hutton', + 'Hatcher', + 'Kartier', + 'Kallan', + 'Daxtyn', + 'Corvin', + 'Deklyn', + 'Kaveon', + 'Leviathan', + 'Leelan', + 'Lael', + 'Prynce', + 'Korban', + 'Khyren', + 'Omran', + 'Oluwademilade', + 'Orenthal', + 'Dequavius', + 'Quinterrius', + 'Quantavis', + 'Astin', + 'Asaiah', + 'Dace', + 'Brylee', + 'Kenyan', + 'Jeovani', + 'Kolson', + 'Dreyden', + 'Jujuan', + 'Gregoria', + 'Abdon', + 'Javious', + 'Latravious', + 'Nanya', + 'Kaleel', + 'Elsie', + 'Iris', + 'Javarus', + 'Hunner', + 'Ebubechukwu', + 'Ashaz', + 'Huntley', + 'Montravious', + 'Argelio', + 'Amaar', + 'Abdulmalik', + 'Deronte', + 'Ramirez', + 'Travius', + 'Xavius', + 'Rashamel', + 'Martice', + 'Oshay', + 'Jamerson', + 'Derico', + 'Benino', + 'Otilio', + 'Palani', + 'Trystin', + 'Domonick', + 'Jayron', + 'Josephine', + 'Dora', + 'Larence', + 'Feliz', + 'Tereso', + 'Natalio', + 'Olga', + 'Bralen', + 'Temple', + 'Keala', + 'Anita', + 'Eathen', + 'Lamond', + 'Jakobie', + 'Johnthan', + 'Elnathan', + 'Edris', + 'Alcario', + 'Cornie', + 'Ival', + 'Pantaleon', + 'Deavion', + 'Daevion', + 'Dorance', + 'Jailon', + 'Ragene', + 'Kaena', + 'Kaimipono', + 'Keaka', + 'Kiai', + 'Babygirl', + 'Aukai', + 'Kaitlin', + 'Kaikoa', + 'Jedadiah', + 'Pono', + 'Layth', + 'Kolbie', + 'Naaman', + 'Pacey', + 'Jearld', + 'Corinthian', + 'Bryceson', + 'Kayzen', + 'Mana', + 'Janee', + 'Janae', + 'Kelli', + 'Tamara', + 'Nora', + 'Sophie', + 'Rashida', + 'Princess', + 'Lakeisha', + 'Nadia', + 'Monet', + 'Meaghan', + 'Marquita', + 'Chiquita', + 'Charlotte', + 'Chantelle', + 'Cassandra', + 'Cara', + 'Brandi', + 'Asha', + 'Tatiana', + 'Haaheo', + 'Valerie', + 'Valencia', + 'Shoso', + 'Yoshimi', + 'Bristol', + 'Mikio', + 'Nobuyuki', + 'Tomio', + 'Kazumi', + 'Kunio', + 'Yoshiharu', + 'Balentin', + 'Paublo', + 'Nobuyoshi', + 'Toshiaki', + 'Matsuo', + 'Hachiro', + 'Tokio', + 'Eichi', + 'Manabu', + 'Masanori', + 'Yoshiyuki', + 'Tokuo', + 'Eustolio', + 'Petra', + 'Fukuichi', + 'Haruyoshi', + 'Eastin', + 'Keygan', + 'Kelin', + 'Lalo', + 'Ramona', + 'Felis', + 'Rodgers', + 'Deigo', + 'Guerin', + 'Arrington', + 'Bradin', + 'Aurora', + 'Calistro', + 'Ervie', + 'Velma', + 'Whit', + 'Adarian', + 'Jakevion', + 'Jadrien', + 'Calub', + 'Kaegan', + 'Jamorian', + 'Milam', + 'Usiel', + 'Drayven', + 'Orange', + 'Daelon', + 'Jatavion', + 'Vastine', + 'Preciliano', + 'Floyce', + 'Billye', + 'Burney', + 'Consepcion', + 'Dason', + 'Osie', + 'Tashaun', + 'Sajid', + 'Umair', + 'Tymarion', + 'Jakorian', + 'Ginobili', + 'Areeb', + 'Jonovan', + 'Jonavan', + 'Jaqualyn', + 'Billey', + 'Luisgustavo', + 'Lamario', + 'Telford', + 'Lekendrick', + 'Brinton', + 'Lebarron', + 'Marrio', + 'Tyshun', + 'Kendarrius', + 'Zylan', + 'Jarrius', + 'Kadarrius', + 'Marvis', + 'Orie', + 'Kimber', + 'Jakevious', + 'Shawndale', + 'Jakel', + 'Jaquarious', + 'Deakon', + 'Brevan', + 'Rochester', + 'Lemmie', + 'Athony', + 'Rosie', + 'Lillie', + 'Mozell', + 'Aubert', + 'Kimble', + 'Jaymon', + 'Gaza', + 'Lysle', + 'Wasco', + 'Zigmond', + 'Addie', + 'Erastus', + 'Claudius', + 'Audley', + 'Thadeus', + 'Exum', + 'Caldwell', + 'Emmert', + 'Teagen', + 'Royden', + 'Mykale', + 'Lindberg', + 'Elmon', + 'Norfleet', + 'Radford', + 'Romulus', + 'Thedore', + 'Cor', + 'Ledarrius', + 'Cyncere', + 'Hurbert', + 'Pearly', + 'Jobie', + 'Garvey', + 'Meade', + 'Casmir', + 'Bertie', + 'Belvin', + 'Lynford', + 'Verdun', + 'Junie', + 'Dover', + 'Harlee', + 'Romolo', + 'Sirr', + 'Bradey', + 'Kingsten', + 'Manuelito', + 'Leno', + 'Primo', + 'Antonie', + 'Jane', + 'Halsey', + 'Mujahid', + 'Quron', + 'Cleophas', + 'Amedio', + 'Gildo', + 'Norvel', + 'Livingston', + 'Norvell', + 'Fard', + 'Khaleef', + 'Dorr', + 'Chaquille', + 'Giro', + 'Verdell', + 'Concetto', + 'Taevon', + 'Amato', + 'Hasaan', + 'Burr', + 'Payten', + 'Baden', + 'Abdirizak', + 'Emran', + 'Abdurahman', + 'Greig', + 'Sabree', + 'Shymir', + 'Haakon', + 'Aasim', + 'Abdifatah', + 'Cheemeng', + 'Yuepheng', + 'Hamsa', + 'Abdalla', + 'Samatar', + 'Joshawa', + 'Leeman', + 'Hershal', + 'Fayette', + 'Patty', + 'Thom', + 'Yaaseen', + 'Alven', + 'Hillis', + 'Bard', + 'Nymir', + 'Imir', + 'Mohamud', + 'Muaad', + 'Mickael', + 'Hermann', + 'Varner', + 'Norm', + 'Suheyb', + 'Eivin', + 'Jamy', + 'Taro', + 'Caydin', + 'Masaharu', + 'Cassie', + 'Virgie', + 'Oddie', + 'Pamela', + 'Emmette', + 'Rayshon', + 'Vardaman', + 'Ruble', + 'Clance', + 'Rigdon', + 'Osborn', + 'Gina', + 'Rozell', + 'Marcy', + 'Farron', + 'Bartolomeo', + 'Dierre', + 'Demetrus', + 'Yoneo', + 'Blayke', + 'Decarlo', + 'Sebert', + 'Quayon', + 'Nihar', + 'Segundo', + 'Ritik', + 'Aljaquan', + 'Lealon', + 'Opie', + 'Darshan', + 'Trapper', + 'Ladarrion', + 'Thaine', + 'Abanoub', + 'Filipe', + 'Oley', + 'Zaylan', + 'Rushi', + 'Watie', + 'Cleatus', + 'Harshil', + 'Alferd', + 'Carthel', + 'Ogden', + 'Carmin', + 'Hiren', + 'Harl', + 'Drexel', + 'Shadeed', + 'Malvern', + 'Argus', + 'Sharief', + 'Almalik', + 'Audy', + 'Terral', + 'Nuno', + 'Verna', + 'Alim', + 'Sherron', + 'Terek', + 'Clardie', + 'Shadee', + 'Clendon', + 'Johnpatrick', + 'Chritopher', + 'Taheem', + 'Jahid', + 'Waitman', + 'Jabraylen', + 'Quasim', + 'Azim', + 'Eulis', + 'Wladyslaw', + 'Delmus', + 'Minter', + 'Kharter', + 'Zavhary', + 'Taji', + 'Hoskie', + 'Colsen', + 'Orlanda', + 'Shawntez', + 'Obryan', + 'Emanual', + 'Silviano', + 'Chrishawn', + 'Rayon', + 'Martino', + 'Fairley', + 'Lenward', + 'Autzen', + 'Selby', + 'Odus', + 'Redell', + 'Seavy', + 'Dennison', + 'Jamiere', + 'Rondy', + 'Donold', + 'Lindwood', + 'Laudie', + 'Obert', + 'Jahki', + 'Braidon', + 'Zalen', + 'Zymier', + 'Jahzir', + 'Nahsir', + 'Vikrant', + 'Shourya', + 'Eliyohu', + 'Tyheim', + 'Keyshon', + 'Kaydence', + 'Ekin', + 'Tresean', + 'Quendarius', + 'Shammond', + 'Malakye', + 'Findlay', + 'Ashrith', + 'Elfego', + 'Jalik', + 'Nyzir', + 'Boe', + 'Abdikadir', + 'Jameek', + 'Gyasi', + 'Khyri', + 'Mohit', + 'Shayquan', + 'Sivan', + 'Steffon', + 'Lord', + 'Leor', + 'Kujtim', + 'Haaris', + 'Rafid', + 'Nechemia', + 'Nyles', + 'Khalik', + 'Tysheen', + 'Shaheim', + 'Starling', + 'Taiquan', + 'Takeem', + 'Teshawn', + 'Tuvia', + 'Shu', + 'Schyler', + 'Indalecio', + 'Edouard', + 'Alverto', + 'Alexio', + 'Aurash', + 'Fabiola', + 'Firas', + 'Fredis', + 'Guthrie', + 'Babacar', + 'Ayinde', + 'Khallid', + 'Shadrach', + 'Rikki', + 'Prescott', + 'Saam', + 'Perla', + 'Michell', + 'Markis', + 'Nou', + 'Sher', + 'Tor', + 'Kyre', + 'Shykeem', + 'Jilberto', + 'Klye', + 'Jeramey', + 'Herber', + 'Kue', + 'Mainor', + 'Macaulay', + 'Jequan', + 'Bond', + 'Hykeem', + 'Husam', + 'Catalina', + 'Danh', + 'Aaronmichael', + 'Anthonyjames', + 'Jerrid', + 'Jobani', + 'Kenia', + 'Oshae', + 'Michaelvincent', + 'Mong', + 'Dawit', + 'Dabid', + 'Daisuke', + 'Geddy', + 'Ehab', + 'Jarmal', + 'Caelin', + 'Barak', + 'Gurtej', + 'Geordan', + 'Jacobb', + 'Estefani', + 'Esaul', + 'Karandeep', + 'Jevaughn', + 'Kassim', + 'Kion', + 'Vikas', + 'Infinite', + 'Yekusiel', + 'Zohaib', + 'Yaw', + 'Sakib', + 'Shah', + 'Zeshan', + 'Hassaan', + 'Masai', + 'Mattheus', + 'Jeniel', + 'Martine', + 'Maalik', + 'Jeanclaude', + 'Stirling', + 'Trayveon', + 'Paymon', + 'Ajai', + 'Habib', + 'Enis', + 'Grafton', + 'Nissan', + 'Oshane', + 'Mirza', + 'Malike', + 'Yianni', + 'Zachari', + 'Tadeh', + 'Patrik', + 'Richy', + 'Riki', + 'Yao', + 'Yadira', + 'Nylan', + 'Lennard', + 'Roldan', + 'Admir', + 'Oniel', + 'Addam', + 'Itzel', + 'Ivann', + 'Shabab', + 'Honorio', + 'Hrag', + 'Harutun', + 'Keano', + 'Kayvan', + 'Takahiro', + 'Juanfrancisco', + 'Eri', + 'Ermon', + 'Ramzy', + 'Selma', + 'Kasean', + 'Obrian', + 'Jonatha', + 'Jonahtan', + 'Davione', + 'Chandara', + 'Chantha', + 'Lo', + 'Loreto', + 'Derell', + 'Ganesh', + 'Janathan', + 'Alejandr', + 'Rodolphe', + 'Isaul', + 'Bejan', + 'Doron', + 'Yvette', + 'Erlon', + 'Erland', + 'Yuji', + 'Milagro', + 'Ndrew', + 'Pedram', + 'Thinh', + 'Vandy', + 'Vi', + 'Ryanjoseph', + 'Richar', + 'Hosey', + 'Adeel', + 'Nicholos', + 'Michaeljohn', + 'Philipe', + 'Bravlio', + 'Anup', + 'Davide', + 'Daquann', + 'Lequan', + 'Raymel', + 'Rahsean', + 'Woodley', + 'Jarmel', + 'Wiliam', + 'Joseh', + 'Somnang', + 'Colvin', + 'Jenkins', + 'Jaquawn', + 'Javonne', + 'Javed', + 'Joelle', + 'Lameek', + 'Kishawn', + 'Krikor', + 'Christipher', + 'Ghassan', + 'Essa', + 'Hovig', + 'Nayquan', + 'Shawndell', + 'Rawle', + 'Marwin', + 'Record', + 'Dmario', + 'Crist', + 'La', + 'Access', + 'Shaquel', + 'Tyrrell', + 'Tiquan', + 'Shavon', + 'Shatique', + 'Yochanon', + 'Keontay', + 'Shaquelle', + 'Kshawn', + 'Armend', + 'Eliazer', + 'Diony', + 'Saddam', + 'Takayuki', + 'Sukhdeep', + 'Shahan', + 'Valon', + 'Orel', + 'Tremell', + 'Chayim', + 'Jaquille', + 'Ayodeji', + 'Bekim', + 'Besnik', + 'Oluwanifemi', + 'Stalin', + 'Sadam', + 'Aniel', + 'Laureat', + 'Dyrell', + 'Jhony', + 'Barkim', + 'Ludger', + 'Mahendra', + 'Kadeen', + 'Jovaughn', + 'Khadeem', + 'Ardian', + 'Ravindra', + 'Harpal', + 'Jatinder', + 'Erving', + 'Gerrell', + 'Sylvestre', + 'Luismanuel', + 'Pharell', + 'Jahziah', + 'Salif', + 'Jakyrin', + 'Idrissa', + 'Daoud', + 'Swan', + 'Pryor', + 'Polk', + 'Rameses', + 'Prateek', + 'Lelon', + 'Ebrima', + 'Ezechiel', + 'Tevan', + 'Sohail', + 'Luiseduardo', + 'Clearance', + 'Brayn', + 'Alexsis', + 'Edwar', + 'Johnmark', + 'Hikaru', + 'Edon', + 'Chezkel', + 'Dinari', + 'Ahmadou', + 'Jadien', + 'Ismaeel', + 'Heshy', + 'Jhan', + 'Dejohn', + 'Ajdin', + 'Damier', + 'Cashmere', + 'Amitai', + 'Alp', + 'Avrahom', + 'Hooper', + 'Daichi', + 'Dariush', + 'Bryen', + 'Oseas', + 'Moyses', + 'Alderic', + 'Dickson', + 'Joon', + 'Justinkyle', + 'Jassiah', + 'Jaidin', + 'Lexie', + 'Mieczyslaw', + 'Joffre', + 'Augustino', + 'Adelino', + 'Tadeusz', + 'Humphrey', + 'Lonas', + 'Avry', + 'Tylin', + 'Dixie', + 'Goldman', + 'Yissachar', + 'Toure', + 'Yafet', + 'Siraj', + 'Nasiah', + 'Maor', + 'Roniel', + 'Kerim', + 'Danieljr', + 'Django', + 'Lion', + 'Baruc', + 'Cervando', + 'Akul', + 'Abdi', + 'Ameya', + 'Arhan', + 'Aliou', + 'Arcangel', + 'Avrumy', + 'Deandrea', + 'Dontreal', + 'Yossef', + 'Walden', + 'Tameem', + 'Kenderick', + 'Yassine', + 'Zeyad', + 'Riyad', + 'Kashmere', + 'Tevis', + 'Malichi', + 'Malakhai', + 'Yulian', + 'Clearnce', + 'Esco', + 'Fabrizzio', + 'Gianpaolo', + 'Jaskirat', + 'Termaine', + 'Daouda', + 'Abba', + 'Aaban', + 'Chanoch', + 'Raynell', + 'Ihsan', + 'Djibril', + 'Cassiel', + 'Ishaq', + 'Azlan', + 'Behruz', + 'Amirjon', + 'Anisjon', + 'Asadbek', + 'Dhilan', + 'Dream', + 'Daviel', + 'Mosha', + 'Rayane', + 'Shabsi', + 'Olie', + 'Vinicio', + 'Yuda', + 'Shohjahon', + 'Kylematthew', + 'Kien', + 'Matthewjames', + 'Giorgi', + 'Konstantine', + 'Jibreel', + 'Jadriel', + 'Lliam', + 'Travonte', + 'Taiki', + 'Rendell', + 'Wyland', + 'Arafat', + 'Tajon', + 'Loic', + 'Shaw', + 'Sukhman', + 'Randiel', + 'Stefanos', + 'Lukus', + 'Majesty', + 'Massimiliano', + 'Burach', + 'Jansel', + 'Ismaila', + 'Henoch', + 'Daelin', + 'Giordano', + 'Huber', + 'Rontrell', + 'Simran', + 'Majid', + 'Rayjon', + 'Pharoah', + 'Lamine', + 'Hanoch', + 'Chidi', + 'Jahmani', + 'Javid', + 'Kamani', + 'Endrit', + 'Endy', + 'Nasean', + 'Danyael', + 'Cinque', + 'Akaash', + 'Zeeshan', + 'Amel', + 'Adib', + 'Aboubakar', + 'Artan', + 'Burak', + 'Serigne', + 'Samin', + 'Hovsep', + 'Jomari', + 'Cesareo', + 'Dajohn', + 'Charbel', + 'Bakary', + 'Camerin', + 'Jaquel', + 'Pape', + 'Jahrel', + 'Jahrell', + 'Khadim', + 'Jeison', + 'Yobany', + 'Zaul', + 'Taryn', + 'Abou', + 'Besim', + 'Abdur', + 'Ebrahim', + 'Albi', + 'Haadi', + 'Saba', + 'Wen', + 'Felipedejesus', + 'Dragon', + 'Jamiel', + 'Alecxis', + 'Ashkon', + 'Tejon', + 'Meelad', + 'Renan', + 'Brailyn', + 'Harel', + 'Abdou', + 'Amier', + 'Jonathanjoseph', + 'Juanalberto', + 'Larenz', + 'Nerses', + 'Emmanuelle', + 'Jasmeet', + 'Jahred', + 'Elsworth', + 'Nyshawn', + 'Alexes', + 'Cranford', + 'Trenell', + 'Cephus', + 'Costas', + 'Rama', + 'Nickalas', + 'Moultrie', + 'Deklin', + 'Saafir', + 'Alexie', + 'Kajuan', + 'Jamahl', + 'Robet', + 'Antoin', + 'Turhan', + 'Mart', + 'Richrd', + 'Ante', + 'Bransyn', + 'Dargan', + 'Levan', + 'Milledge', + 'Ollis', + 'Morey', + 'Jeromey', + 'Ebon', + 'Nicholus', + 'Yvonne', + 'Gladstone', + 'Kwan', + 'Sherry', + 'Romney', + 'Nicolaos', + 'Oded', + 'Koty', + 'Mandy', + 'Adger', + 'Esaw', + 'Shaunte', + 'Nimesh', + 'Ahren', + 'Marcellino', + 'Attila', + 'Pinkney', + 'Reinhard', + 'Deanna', + 'Shanti', + 'Calmer', + 'Reda', + 'Darral', + 'Monserrate', + 'Levert', + 'Harce', + 'Ayham', + 'Breslin', + 'Dom', + 'Darrow', + 'Haidar', + 'Willaim', + 'Shann', + 'Regina', + 'Einer', + 'Zui', + 'Shonn', + 'Skipper', + 'Henning', + 'Jacek', + 'Wendelin', + 'Wilmar', + 'Algot', + 'Marlen', + 'Dquan', + 'Emanuele', + 'Erol', + 'Boby', + 'Elbin', + 'Londell', + 'Bradd', + 'Malo', + 'Mohamadali', + 'Toussaint', + 'Roald', + 'Trini', + 'Stace', + 'Erubey', + 'Labron', + 'Kyseem', + 'Duong', + 'Rande', + 'Siegfried', + 'Mamon', + 'Va', + 'Quy', + 'Raman', + 'Ramil', + 'Jasai', + 'Carla', + 'Belen', + 'Lawernce', + 'Jemar', + 'Markham', + 'Kym', + 'Jemaine', + 'Baldwin', + 'Damany', + 'Timonthy', + 'Tesfa', + 'Vinod', + 'Albertus', + 'Yupheng', + 'Danie', + 'Tashiem', + 'Uno', + 'Onnie', + 'Juliana', + 'Duff', + 'Doua', + 'Orman', + 'Kamaal', + 'Godwin', + 'Ulric', + 'Darrold', + 'Rennie', + 'Lory', + 'Jamile', + 'Terril', + 'Gable', + 'Hanh', + 'Grisel', + 'Jimmylee', + 'Mikkel', + 'Victorino', + 'Jaymere', + 'Rayn', + 'Duriel', + 'Ceferino', + 'Autrey', + 'Durant', + 'Kolsen', + 'Abayomi', + 'Azell', + 'Spyros', + 'Ato', + 'Damin', + 'Diogenes', + 'Barnaby', + 'Pinckney', + 'Keno', + 'Sherard', + 'Chukwuemeka', + 'Akin', + 'Harvel', + 'Marv', + 'Kenyetta', + 'Huel', + 'Royzell', + 'Luddie', + 'Olden', + 'Ardith', + 'Branch', + 'Bertha', + 'Hillman', + 'Namon', + 'Donnis', + 'Fitzhugh', + 'Lavaughn', + 'Lucille', + 'Amanuel', + 'Carvin', + 'Minnie', + 'Tivis', + 'Birt', + 'Bronner', + 'Vaden', + 'Joenathan', + 'Alphonsa', + 'Elvie', + 'Alpheus', + 'Clausell', + 'Clayburn', + 'Demetrias', + 'Avis', + 'Garlon', + 'Romaine', + 'Jamorris', + 'Swanson', + 'Perez', + 'Hurschel', + 'Virge', + 'Rutherford', + 'Lelton', + 'Tarris', + 'Denson', + 'Benjaman', + 'Rashun', + 'Keino', + 'Cedarius', + 'Keanthony', + 'Blakeley', + 'Burwell', + 'Kasai', + 'Euell', + 'Eldrick', + 'Ashford', + 'Demetruis', + 'Wood', + 'Blanton', + 'Daniell', + 'Robt', + 'Lamorris', + 'Waller', + 'Devoris', + 'Herley', + 'Jermery', + 'Jamicheal', + 'Horton', + 'Gradie', + 'Etheridge', + 'Millie', + 'Jammy', + 'Karey', + 'Rodregus', + 'Cordera', + 'Embry', + 'Forney', + 'Sims', + 'Gergory', + 'Rosser', + 'Benjamine', + 'Erskin', + 'Heflin', + 'Torrie', + 'Norville', + 'Arvie', + 'Bessie', + 'Keonta', + 'Tarrence', + 'Chapman', + 'Limmie', + 'Tavius', + 'Reynard', + 'Lonza', + 'Detroit', + 'Camauri', + 'Clanton', + 'Obbie', + 'Mizell', + 'Marshel', + 'Tollie', + 'Jondarius', + 'Therion', + 'Antoino', + 'Beatrice', + 'Keyonte', + 'Littleton', + 'Hozie', + 'Atwell', + 'Ottie', + 'Pelham', + 'Vickie', + 'Cederick', + 'Zaykeese', + 'Jadarious', + 'Shin', + 'Tizoc', + 'Mischa', + 'Tycen', + 'Jubal', + 'Kito', + 'Sabin', + 'Brannan', + 'Baltasar', + 'Hilda', + 'Orasio', + 'Bassel', + 'Ameet', + 'Talus', + 'Renne', + 'Reuel', + 'Saro', + 'Kam', + 'Heliodoro', + 'Hodari', + 'Mondo', + 'Damaso', + 'Damein', + 'Thunder', + 'Ravinder', + 'Remberto', + 'Rodel', + 'Yvan', + 'Marcelle', + 'Kiril', + 'Shem', + 'Bardo', + 'Carlson', + 'Jebediah', + 'Austreberto', + 'Hannibal', + 'Shawnn', + 'Kenyatte', + 'Geoffry', + 'Hadden', + 'Natnael', + 'Edurdo', + 'Errik', + 'Eva', + 'Gaelan', + 'Gilverto', + 'Antwaine', + 'Barclay', + 'Rithy', + 'Sarath', + 'Sasan', + 'Stefen', + 'Susana', + 'Le', + 'Mai', + 'Marquies', + 'Neeraj', + 'Galdino', + 'Cuitlahuac', + 'Griselda', + 'Jerret', + 'Filbert', + 'Travone', + 'Lizette', + 'Lourdes', + 'Ratana', + 'Sarith', + 'Ku', + 'Jocob', + 'Jushua', + 'Shaughn', + 'Sophal', + 'Sophana', + 'Stepan', + 'Tramel', + 'Veniamin', + 'Ha', + 'Halley', + 'Hiep', + 'Maclain', + 'Alberta', + 'Alejando', + 'Eliana', + 'Chay', + 'Esmond', + 'Frisco', + 'Dai', + 'Marta', + 'Man', + 'Kha', + 'Kin', + 'Sun', + 'Paulmichael', + 'Rj', + 'Jeoffrey', + 'Custodio', + 'Herberth', + 'Gerrad', + 'Seanpaul', + 'Sten', + 'Nereida', + 'Jasun', + 'Micharl', + 'Robbert', + 'Ronnel', + 'Rosio', + 'Othon', + 'Chau', + 'Hart', + 'Atthew', + 'Angelito', + 'Debbie', + 'Randol', + 'Jeffrie', + 'Kern', + 'Rohn', + 'Raef', + 'Arleigh', + 'Jef', + 'Reg', + 'Vinton', + 'Perrin', + 'Parry', + 'Sally', + 'Hoby', + 'Vint', + 'Dagmawi', + 'Mat', + 'Gregrey', + 'Darol', + 'Merik', + 'Rickard', + 'Clete', + 'Fredrik', + 'Darrol', + 'Lyall', + 'Jamare', + 'Duffy', + 'Barre', + 'Shawnee', + 'Tige', + 'Whittaker', + 'Tyrion', + 'Jamas', + 'Jud', + 'Spence', + 'Dione', + 'Erinn', + 'Bron', + 'Ackley', + 'Dal', + 'Monti', + 'Paco', + 'Kjell', + 'Gabor', + 'Davinder', + 'Shonte', + 'Maximiano', + 'Heshimu', + 'Jassen', + 'Jerami', + 'Jermon', + 'Keefe', + 'Keri', + 'Daric', + 'Christropher', + 'Johnney', + 'Dodd', + 'Wilferd', + 'Raymondo', + 'Keary', + 'Orlan', + 'Gerhart', + 'Clemence', + 'Pepe', + 'Whitaker', + 'Vaughan', + 'Wess', + 'Abenezer', + 'Miroslav', + 'Kurk', + 'Helmut', + 'Timothey', + 'Annette', + 'Cruise', + 'Jahel', + 'Itay', + 'Isaiahs', + 'Isack', + 'Eagan', + 'Finbar', + 'Famous', + 'Ethanjoseph', + 'Ethanjames', + 'Edi', + 'Isais', + 'Albeiro', + 'Abhijot', + 'Joshuajames', + 'Amine', + 'Edwardjames', + 'Donyae', + 'Danieljohn', + 'Avaneesh', + 'Aryav', + 'Andoni', + 'Yeison', + 'Lowen', + 'Obi', + 'Mycah', + 'Moksh', + 'Miliano', + 'Maxamillion', + 'Lazlo', + 'Jocsan', + 'Jibran', + 'Jerimyah', + 'Jefte', + 'Korde', + 'Kanav', + 'Tavita', + 'Taesean', + 'Yoltzin', + 'Xzavior', + 'Vibhav', + 'Romen', + 'Rocket', + 'Rai', + 'Orian', + 'Rumi', + 'Shota', + 'Shaheer', + 'Sadrac', + 'Semaje', + 'Sohrob', + 'Yuval', + 'Yuren', + 'Yannis', + 'Vineet', + 'Yarden', + 'Jesusjr', + 'Kartik', + 'Jairon', + 'Millen', + 'Nahun', + 'Krisna', + 'Kyrese', + 'Mher', + 'Mayan', + 'Kais', + 'Joshuan', + 'Jometh', + 'Keawe', + 'Siris', + 'Sinai', + 'Shuban', + 'Shian', + 'Sneijder', + 'Sota', + 'Uday', + 'Sevak', + 'Royale', + 'Yuuki', + 'Reyhan', + 'Seena', + 'Moisses', + 'Nayib', + 'Sumit', + 'Dayveon', + 'Christianpaul', + 'Garrin', + 'Edgerrin', + 'Edrees', + 'Estephan', + 'Assael', + 'Azad', + 'Tydus', + 'Yosuf', + 'Zekiel', + 'Strider', + 'Senai', + 'Edmar', + 'Dmorea', + 'Eman', + 'Darran', + 'Keston', + 'Keny', + 'Hardeep', + 'Heladio', + 'Hernesto', + 'Hovannes', + 'Sankalp', + 'Brenten', + 'Navraj', + 'Mavrik', + 'Nilmar', + 'Rishit', + 'Edwing', + 'Eswin', + 'Flabio', + 'Jasn', + 'Romar', + 'Sevan', + 'Shahab', + 'Justinmichael', + 'Joseandres', + 'Marcelus', + 'Mariana', + 'Andhy', + 'Angeles', + 'Tannor', + 'Tristain', + 'Joshuaray', + 'Luisdavid', + 'Damaris', + 'Daymond', + 'Anthonyjohn', + 'Dezhon', + 'Emelio', + 'Eulices', + 'Maclean', + 'Jaeson', + 'Ethanjohn', + 'Ethanjacob', + 'Jasiri', + 'Kaisei', + 'Khyle', + 'Jona', + 'Jeren', + 'Jeramyah', + 'Jesusantonio', + 'Jguadalupe', + 'Joseeduardo', + 'Elkin', + 'Prashant', + 'Anguel', + 'Anant', + 'Aisea', + 'Abhimanyu', + 'Daelen', + 'Dylin', + 'Dodge', + 'Nazaret', + 'Mikie', + 'Matthewjoseph', + 'Maximillan', + 'Savir', + 'Dhillon', + 'Donoven', + 'Ebin', + 'Edrei', + 'Elek', + 'Nykolas', + 'Nikash', + 'Nik', + 'Reyly', + 'Razi', + 'Presten', + 'Arul', + 'Avo', + 'Yandell', + 'Wynston', + 'Tallen', + 'Suhaib', + 'Joshuajohn', + 'Jesusmanuel', + 'Malacai', + 'Kethan', + 'Londen', + 'Larenzo', + 'Kriss', + 'Kohei', + 'Hamlet', + 'Martinjr', + 'Mansoor', + 'Archit', + 'Aniketh', + 'Kincaid', + 'Lunden', + 'Masaki', + 'Salam', + 'Sahith', + 'Nour', + 'Miqueas', + 'Estefano', + 'Hatim', + 'Gurvir', + 'Adeeb', + 'Tobiah', + 'Torrin', + 'Tushar', + 'Tyee', + 'Sulayman', + 'Takai', + 'Tayo', + 'Yoan', + 'Vegas', + 'Duilio', + 'Dyami', + 'Greko', + 'Harim', + 'Ioane', + 'Ashmit', + 'Bora', + 'Alekxander', + 'Alexanderjames', + 'Amanpreet', + 'Anthonny', + 'Brandom', + 'Daimon', + 'Sirus', + 'Seananthony', + 'Vignesh', + 'Vir', + 'Wisdom', + 'Rameen', + 'Kenzie', + 'Joshuamichael', + 'Josejr', + 'Joseenrique', + 'Jacksen', + 'Jeriko', + 'Jesua', + 'Myka', + 'Naithen', + 'Saurav', + 'Shalim', + 'Puneet', + 'Denali', + 'Daveyon', + 'Sohil', + 'Edilson', + 'Jafeth', + 'Nathin', + 'Maurion', + 'Mekai', + 'Nadim', + 'Jamani', + 'Jamisen', + 'Gared', + 'Gahel', + 'Emron', + 'Hanzel', + 'Xaviar', + 'Yohann', + 'Alam', + 'Brasen', + 'Ashlan', + 'Rury', + 'Ralphie', + 'Robertanthony', + 'Tomoki', + 'Zamuel', + 'Urian', + 'Vinayak', + 'Wilberth', + 'Jazziel', + 'Mizraim', + 'Mosiah', + 'Muneeb', + 'Lennin', + 'Chaitanya', + 'Cyrille', + 'Dilpreet', + 'Bhargav', + 'Captain', + 'Camil', + 'Jaion', + 'Eithen', + 'Dominyk', + 'Domenik', + 'Imad', + 'Dabin', + 'Ceejay', + 'Avishek', + 'Anoop', + 'Aaronjoshua', + 'Billal', + 'Euan', + 'Eion', + 'Beauregard', + 'Fouad', + 'Chriss', + 'Daimien', + 'Cyan', + 'Conall', + 'Inigo', + 'Jashan', + 'Jaicob', + 'Arek', + 'Benjaminjoseph', + 'Bodey', + 'Andrewjames', + 'Abdel', + 'Alian', + 'Artyom', + 'Anik', + 'Angeljesus', + 'Shriyan', + 'Sosaia', + 'Shabd', + 'Tayveon', + 'Samik', + 'Josephanthony', + 'Kaushal', + 'Gerardojr', + 'Haile', + 'Henok', + 'Imer', + 'Izaiha', + 'Vedanth', + 'Rishav', + 'Praveen', + 'Kenner', + 'Juanjr', + 'Kinan', + 'Maven', + 'Neven', + 'Niccolas', + 'Raynav', + 'Rani', + 'Noahjames', + 'Nirvan', + 'Nevaan', + 'Naythen', + 'Rhythm', + 'Samyak', + 'Sahas', + 'Roczen', + 'Kroy', + 'Johanna', + 'Miro', + 'Mayank', + 'Masson', + 'Yamato', + 'Xaden', + 'Vin', + 'Tyden', + 'Gaudencio', + 'Garreth', + 'Toryn', + 'Jaswinder', + 'Stiles', + 'Graciela', + 'Rutger', + 'Razmig', + 'Keo', + 'Kavir', + 'Kalev', + 'Kal', + 'Kabeer', + 'Jianni', + 'Terrace', + 'Vicken', + 'Westly', + 'Pardeep', + 'Lizeth', + 'Lucia', + 'Mandela', + 'Maricela', + 'Joshus', + 'Kayle', + 'Klyde', + 'Djavan', + 'Wang', + 'Aljandro', + 'Belisario', + 'Cristino', + 'Yihan', + 'Carina', + 'Chritian', + 'Juanramon', + 'Khan', + 'Jaiver', + 'Nefi', + 'Murtaza', + 'Raciel', + 'Marlene', + 'Maira', + 'Chima', + 'Cheenou', + 'Bijon', + 'Dorion', + 'Elber', + 'Emeka', + 'Ge', + 'Ratha', + 'Jaxxson', + 'Ryanjames', + 'Shannen', + 'Shue', + 'Sia', + 'Romaldo', + 'Zareh', + 'Tomy', + 'Vanna', + 'Xao', + 'Bertin', + 'Dhyan', + 'Dexton', + 'Esiah', + 'Ayce', + 'Avyukt', + 'Avner', + 'Caspar', + 'Cove', + 'Ciel', + 'Yen', + 'Yessenia', + 'Yony', + 'Fin', + 'Ezrael', + 'Ezel', + 'Ilay', + 'Harveer', + 'Hamad', + 'Asiah', + 'Ashwath', + 'Arcenio', + 'Aroldo', + 'Awet', + 'Alexx', + 'Arihant', + 'Arihaan', + 'Apolo', + 'Aero', + 'Advith', + 'Arren', + 'Beatriz', + 'Jony', + 'Joseramon', + 'Justinray', + 'Jamaul', + 'Tarren', + 'Cristal', + 'Dinh', + 'Chantra', + 'Dshawn', + 'Geraldine', + 'Fuad', + 'Edlin', + 'Jerren', + 'Jerrin', + 'Josje', + 'Chrystopher', + 'Darriel', + 'Takuya', + 'Vannak', + 'Zenas', + 'Miklos', + 'Marten', + 'Rondale', + 'Rothana', + 'Randeep', + 'Ryle', + 'Eduardoluis', + 'Christepher', + 'Davionne', + 'Eriverto', + 'Farbod', + 'Chauncy', + 'Charle', + 'Bayardo', + 'Ashneel', + 'Shoua', + 'Redmond', + 'Ustin', + 'Johnnathan', + 'Josephmichael', + 'Marisela', + 'Markandrew', + 'Michaeljoseph', + 'Marcua', + 'Nidal', + 'Phat', + 'Pritesh', + 'Seaver', + 'Ryananthony', + 'Tyan', + 'Vatche', + 'Thoren', + 'Othoniel', + 'Nicandro', + 'Rajdeep', + 'Tulio', + 'Soua', + 'Jovonte', + 'Kalyn', + 'Jamesryan', + 'Navdeep', + 'Maxmillian', + 'Kayon', + 'Koua', + 'Aaryn', + 'Wilver', + 'Zubair', + 'Ankush', + 'Andie', + 'Adonnis', + 'Jacobanthony', + 'Izekiel', + 'Izacc', + 'Escher', + 'Elijahjames', + 'Edrik', + 'Drayson', + 'Dj', + 'Giordan', + 'Dejaun', + 'Davidmichael', + 'Deshone', + 'Auron', + 'Auguste', + 'Athos', + 'Cutberto', + 'Hairo', + 'Anvay', + 'Adrick', + 'Aydeen', + 'Bassam', + 'Basem', + 'Kyrell', + 'Rjay', + 'Ozil', + 'Taisei', + 'Samanyu', + 'Marvion', + 'Mykael', + 'Mukund', + 'Namish', + 'Naoki', + 'Nishan', + 'Aideen', + 'Aalijah', + 'Hassani', + 'Harkirat', + 'Exzavier', + 'Hudsen', + 'Hrach', + 'Caelum', + 'Caeleb', + 'Destan', + 'Jaspal', + 'Huan', + 'Marcellous', + 'Mehran', + 'Luisfelipe', + 'Gelacio', + 'Eris', + 'Eneas', + 'Terin', + 'Sohrab', + 'Ravneet', + 'Uziah', + 'Vedansh', + 'Peni', + 'Nethaniel', + 'Niraj', + 'Odilon', + 'Kalden', + 'Mariela', + 'Levonte', + 'Elih', + 'Ej', + 'Eames', + 'Jarome', + 'Jishnu', + 'Gurtaaj', + 'Hamish', + 'Gryffin', + 'Jayin', + 'Trong', + 'Sebastain', + 'Sargon', + 'Wa', + 'Cheveyo', + 'Ariv', + 'Aum', + 'Caellum', + 'Bayan', + 'Balthazar', + 'Sagan', + 'Rowyn', + 'Sehaj', + 'Ivon', + 'Stavro', + 'Shrihan', + 'Noey', + 'Oswin', + 'Abrham', + 'Adalid', + 'Aldric', + 'Zayed', + 'Vonn', + 'Vaishnav', + 'Urias', + 'Yahshua', + 'Yago', + 'Darith', + 'Mantej', + 'Kyo', + 'Khyler', + 'Marcjacob', + 'Nayden', + 'Morrissey', + 'Benedicto', + 'Kendrix', + 'Xang', + 'Ranjit', + 'Raymar', + 'Milos', + 'Rayansh', + 'Rawley', + 'Paxon', + 'Krishang', + 'Leeam', + 'Yerick', + 'Yegor', + 'Viren', + 'Saathvik', + 'Shailen', + 'Sahaj', + 'Rydan', + 'Rollins', + 'Rivaan', + 'Soul', + 'Aerick', + 'Aladdin', + 'Catalino', + 'Berenice', + 'Branndon', + 'Kyleanthony', + 'Maclovio', + 'Kiven', + 'Johnchristopher', + 'Jonh', + 'Kassandra', + 'Jobanny', + 'Pastor', + 'Michaela', + 'Montre', + 'Morgen', + 'Gerber', + 'Danish', + 'Haroutun', + 'Duron', + 'Adrion', + 'Evrett', + 'Reegan', + 'Haskie', + 'Quamane', + 'Derrike', + 'Haydyn', + 'Glenville', + 'Dearl', + 'Deroe', + 'Dewell', + 'Lundy', + 'Cleaster', + 'Jeral', + 'Delontae', + 'Delford', + 'Argie', + 'Loise', + 'Elmar', + 'Donley', + 'Ferrel', + 'Carrel', + 'Athel', + 'Rector', + 'Cledith', + 'Dail', + 'Donzel', + 'Lenoard', + 'Winferd', + 'Birl', + 'Dorsie', + 'Olee', + 'Erman', + 'Dorsel', + 'Roma', + 'Othell', + 'Herold', + 'Chaffee', + 'Trygve', + 'Aubra', + 'Opha', + 'Dionne', + 'Colleen', + 'Ciara', + 'Cleotis', + 'Alissa', + 'Alesha', + 'Elise', + 'Emilie', + 'Tiera', + 'Tia', + 'Suzanne', + 'Jaleesa', + 'Jaclyn', + 'Ingrid', + 'India', + 'Georgia', + 'Francesca', + 'Female', + 'Fatima', + 'Rochelle', + 'Precious', + 'Nichelle', + 'Martina', + 'Lucy', + 'Latonya', + 'Cline', + 'Ott', + 'Ona', + 'Otmer', + 'Ersel', + 'Olufemi', + 'Gordy', + 'Marne', + 'Jahquez', + 'Daeshaun', + 'Nashaun', + 'Seiichi', + 'Shigeki', + 'Kazuto', + 'Shozo', + 'Alhaji', + 'Lonn', + 'Tevion', + 'Kaige', + 'Darlene', + 'Braydyn', + 'Masaaki', + 'Graeson', + 'Bernerd', + 'Lynne', + 'Dewaine', + 'Shig', + 'Junichi', + 'Toshiro', + 'Azavion', + 'Michio', + 'Yoshiro', + 'Heraldo', + 'Epitacio', + 'Mas', + 'Taequan', + 'Trindon', + 'Tirrell', + 'Dmonte', + 'Jaquante', + 'Yeeleng', + 'Maleik', + 'Airam', + 'Noname', + 'Shyhiem', + 'Tyquon', + 'Damonta', + 'Undray', + 'Shadrick', + 'Durwin', + 'Lataurus', + 'Corneall', + 'Dantonio', + 'Tilmon', + 'Mackie', + 'Ebbie', + 'Eligha', + 'Beth', + 'Barth', + 'Hezzie', + 'Artha', + 'Darrie', + 'Frederi', + 'Benford', + 'Elves', + 'Theodia', + 'Jaye', + 'Fran', + 'Khylan', + 'Berwyn', + 'Constance', + 'Markevion', + 'Martavion', + 'Jashun', + 'Jermarion', + 'Taylin', + 'Breland', + 'Franchot', + 'Chrishun', + 'Davarius', + 'Dearius', + 'Tredarius', + 'Jayland', + 'Cortavius', + 'Deyonta', + 'Tradarius', + 'Kemarrion', + 'Markavion', + 'Jmarion', + 'Jacarius', + 'Kairi', + 'Rasool', + 'Jarreau', + 'Khayree', + 'Brahin', + 'Hameed', + 'Rolen', + 'Cleason', + 'Cartez', + 'Nicholad', + 'Brahim', + 'Bryheem', + 'Khalief', + 'Anel', + 'Mcgwire', + 'Lula', + 'Gaddis', + 'Lowery', + 'Odies', + 'Rannie', + 'Artee', + 'Aurther', + 'Bookert', + 'Lenon', + 'Oree', + 'Gennie', + 'Emitt', + 'Sedgie', + 'Claudy', + 'Coyt', + 'Lieutenant', + 'Zannie', + 'Kenn', + 'Roosvelt', + 'Vertis', + 'Elex', + 'Eula', + 'Abron', + 'Perkins', + 'Emersyn', + 'Lakin', + 'Dravin', + 'Other', + 'President', + 'Carrie', + 'Cleother', + 'Estus', + 'Tee', + 'Raymont', + 'Woodard', + 'Ras', + 'Zennie', + 'Versie', + 'Mansfield', + 'Atha', + 'Bossie', + 'Smiley', + 'Kenard', + 'Jermie', + 'Vardell', + 'Kadan', + 'Roney', + 'Furney', + 'Caroll', + 'Benjy', + 'Shamond', + 'Tyrease', + 'Dontre', + 'Raekwan', + 'Raequon', + 'Chrishon', + 'Jahmez', + 'Jaques', + 'Zaveon', + 'Zaccheus', + 'Demaris', + 'Shaquile', + 'Shiheem', + 'Santario', + 'Monterio', + 'Jawaan', + 'Lavere', + 'Levere', + 'Guerino', + 'Lisle', + 'Fraser', + 'Grier', + 'Gurnie', + 'Lattie', + 'Wassil', + 'Domer', + 'Melio', + 'Zolton', + 'Haines', + 'Gervase', + 'Fermon', + 'Geneva', + 'Trask', + 'Linward', + 'Colen', + 'Dossie', + 'Zygmund', + 'Teofil', + 'Talbert', + 'Mosby', + 'Elworth', + 'Garvie', + 'Jiles', + 'Mallie', + 'Flay', + 'Stokes', + 'Bernis', + 'Gardiner', + 'Deno', + 'Algerd', + 'Handy', + 'Flake', + 'Hallet', + 'Coyte', + 'Wingate', + 'Burlie', + 'Sigmond', + 'Myrle', + 'Stiney', + 'Americus', + 'Claxton', + 'Acy', + 'Hill', + 'Fenner', + 'Festus', + 'Linnie', + 'Guilford', + 'Artice', + 'Constant', + 'Faber', + 'Jb', + 'Pleasant', + 'Dallis', + 'Vestal', + 'Terez', + 'English', + 'Allard', + 'Ingram', + 'Beaufort', + 'Chene', + 'Dequante', + 'Bubber', + 'Jamone', + 'Zebulun', + 'Daqwan', + 'Delshawn', + 'Jamond', + 'Dacota', + 'Wilmot', + 'Prue', + 'Wister', + 'Kenyata', + 'Darik', + 'Sumter', + 'Hovie', + 'Tallie', + 'Diontay', + 'Dontaye', + 'Brentt', + 'Felder', + 'Chappell', + 'Ralpheal', + 'Wofford', + 'Stclair', + 'Aiken', + 'Hashem', + 'Daire', + 'Grahm', + 'Jaivon', + 'Davarion', + 'Arnez', + 'Ryer', + 'Mousa', + 'Jahlon', + 'Leyland', + 'Maizen', + 'Zadyn', + 'Zein', + 'Amarri', + 'Hady', + 'Keegen', + 'Taeshawn', + 'Jontae', + 'Radwan', + 'Jsean', + 'Hartwell', + 'Roddey', + 'Arend', + 'Marjorie', + 'Clements', + 'Rae', + 'Pressley', + 'Saintclair', + 'Derrill', + 'Joann', + 'Cote', + 'Philo', + 'Urho', + 'Evart', + 'Vada', + 'Deo', + 'Tonie', + 'Irven', + 'Stjulian', + 'Durand', + 'Diarra', + 'Burnet', + 'Steed', + 'Demont', + 'Burris', + 'Donyell', + 'Gjon', + 'Demone', + 'Jodi', + 'Boban', + 'Brunson', + 'Mackey', + 'Delwyn', + 'Gordie', + 'Owens', + 'Efton', + 'Uel', + 'Ancel', + 'Zafir', + 'Kyeem', + 'Vencil', + 'Irl', + 'Tymeer', + 'Dymere', + 'Kier', + 'Murel', + 'Hale', + 'Lorn', + 'Tahjir', + 'Sufyaan', + 'Trig', + 'Yacqub', + 'Khadir', + 'Najib', + 'Ayuub', + 'Hamse', + 'Yassir', + 'Yussuf', + 'Abdihafid', + 'Abdinasir', + 'Abdiqani', + 'Tayon', + 'Abdirahim', + 'Abdishakur', + 'Mukhtar', + 'Bauer', + 'Damere', + 'Rashee', + 'Kalief', + 'Shyheed', + 'Dejour', + 'Kuran', + 'Qaadir', + 'Aldor', + 'Jasyah', + 'Hajj', + 'Ordell', + 'Gradyn', + 'Ayyub', + 'Atley', + 'Mahkai', + 'Lochlann', + 'Sakai', + 'Saamir', + 'Bernhardt', + 'Willmer', + 'Swen', + 'Hilding', + 'Knute', + 'Wael', + 'Thorvald', + 'Erle', + 'Melroy', + 'Valerian', + 'Jorgen', + 'Dacotah', + 'Shaydon', + 'Lamir', + 'Kahseem', + 'Jihaad', + 'Tylee', + 'Sakariye', + 'Qalid', + 'Syair', + 'Syire', + 'Safi', + 'Zaakir', + 'Sahmir', + 'Saahir', + 'Karlin', + 'Kowen', + 'Kahne', + 'Azir', + 'Tysir', + 'Maki', + 'Zekhi', + 'Pater', + 'Louden', + 'Jandiel', + 'Khaseem', + 'Livio', + 'Pellegrino', + 'Loretta', + 'Lothar', + 'Morty', + 'Harvard', + 'Jeris', + 'Arlene', + 'Salvotore', + 'Erasmus', + 'Canio', + 'Heywood', + 'Ivar', + 'Maitland', + 'Neale', + 'Gladys', + 'Ethelbert', + 'Fergus', + 'Arcangelo', + 'Sigismund', + 'Fremont', + 'Stillman', + 'Egidio', + 'Pincus', + 'Sabatino', + 'Solly', + 'Bela', + 'Stanly', + 'Faust', + 'Gesualdo', + 'Adolphe', + 'Ladislav', + 'Mandel', + 'Philander', + 'Catello', + 'Fordyce', + 'Brownie', + 'Darnley', + 'Alfio', + 'Emerito', + 'Darrly', + 'Delfin', + 'Chiam', + 'Beril', + 'Albie', + 'Roberts', + 'Ferdinando', + 'Maureen', + 'Herberto', + 'Lamark', + 'Philipp', + 'Uwe', + 'Dermott', + 'Amalio', + 'Sandford', + 'Shawnta', + 'Shannan', + 'Sheppard', + 'Jerauld', + 'Antoinne', + 'Oleh', + 'Tobie', + 'Thoms', + 'Valice', + 'Thurnell', + 'Deamonte', + 'Kendel', + 'Trevone', + 'Kaylob', + 'Carder', + 'Antrell', + 'Traven', + 'Jaymir', + 'Joni', + 'Keisean', + 'Krishawn', + 'Marquelle', + 'Dearis', + 'Delvonte', + 'Jamez', + 'Zebadiah', + 'Kreig', + 'Teran', + 'Resean', + 'Zackory', + 'Lamontae', + 'Albieri', + 'Albiery', + 'Chen', + 'Alexy', + 'Arslan', + 'Taliek', + 'Nakhi', + 'Naphtali', + 'Papa', + 'Pesach', + 'Michoel', + 'Salih', + 'Harshdeep', + 'Elhadj', + 'Izzy', + 'Jahkai', + 'Tyliek', + 'Vasilis', + 'Yaacov', + 'Sohaib', + 'Yissochor', + 'Mir', + 'Jasin', + 'Jensy', + 'Rehman', + 'Nazeer', + 'Jahmil', + 'Enson', + 'Nasif', + 'Rizwan', + 'Samiul', + 'Rahat', + 'Angelos', + 'Avroham', + 'Abdulai', + 'Adir', + 'Enes', + 'Yishay', + 'Doyt', + 'Gal', + 'Shoaib', + 'Quaron', + 'Ishraq', + 'Nazaire', + 'Nyzaiah', + 'Mattia', + 'Javone', + 'Mahesh', + 'Mamady', + 'Johnattan', + 'Jorman', + 'Kaliq', + 'Devendra', + 'Burhan', + 'Zishe', + 'Zeandre', + 'Arel', + 'Shalik', + 'Shameer', + 'Nisson', + 'Ralik', + 'Agim', + 'Amauris', + 'Atif', + 'Samory', + 'Shatiek', + 'Taner', + 'Rafat', + 'Zhen', + 'Radhames', + 'Raliek', + 'Ronel', + 'Sabbir', + 'Saqib', + 'Jeudy', + 'Hesham', + 'Hyun', + 'Lakeem', + 'Mishael', + 'Ivo', + 'Tajay', + 'Taleek', + 'Tishawn', + 'Tyreem', + 'Samori', + 'Nickholas', + 'Pearse', + 'Mamadi', + 'Elhadji', + 'Dawood', + 'Dilon', + 'Ishmel', + 'Yiannis', + 'Jahquel', + 'Jahquell', + 'El', + 'Equan', + 'Ho', + 'Delno', + 'Dinesh', + 'Damel', + 'Temitayo', + 'Tenzing', + 'Wahab', + 'Alisher', + 'Adonijah', + 'Bradan', + 'Efrayim', + 'Elnatan', + 'Elmin', + 'Hossain', + 'Eliav', + 'Azimjon', + 'Dovber', + 'Sheya', + 'Yahia', + 'Jasani', + 'Liav', + 'Kamare', + 'Kaysean', + 'Kinsley', + 'Nikoloz', + 'Nyrell', + 'Wyeth', + 'Jeremaih', + 'Mahin', + 'Matis', + 'Oriel', + 'Mourad', + 'Shmeil', + 'Messi', + 'Jonibek', + 'Jeyren', + 'Keyden', + 'Temur', + 'Tanveer', + 'Zyir', + 'Zidan', + 'Zayyan', + 'Varick', + 'Wesam', + 'Abdoulie', + 'Aqib', + 'Asani', + 'Bless', + 'Hasnain', + 'Hamdan', + 'Getzel', + 'Fatin', + 'Huzaifa', + 'Jarif', + 'Jahlani', + 'Davier', + 'Chuna', + 'Eashan', + 'Rafan', + 'Rakin', + 'Ngawang', + 'Mouhamad', + 'Rohaan', + 'Vanness', + 'Volvy', + 'Javel', + 'Jabir', + 'Jaevion', + 'Fahd', + 'Lean', + 'Machai', + 'Juniel', + 'Kaylin', + 'Jeremiyah', + 'Matisyahu', + 'Menasha', + 'Mikaeel', + 'Gaspard', + 'Lorik', + 'Shuaib', + 'Seif', + 'Shlomy', + 'Shneor', + 'Sonam', + 'Volf', + 'Yussef', + 'Ziv', + 'Krrish', + 'Machi', + 'Endi', + 'Frederik', + 'Abdo', + 'Alif', + 'Elchanan', + 'Yordy', + 'Shafin', + 'Siam', + 'Furkan', + 'Fallou', + 'Devyne', + 'Chaskel', + 'Arbi', + 'Younes', + 'Ziare', + 'Tanyon', + 'Terique', + 'Nicholaos', + 'Nickita', + 'Mordchai', + 'Saifullah', + 'Saliou', + 'Savier', + 'Jahmiere', + 'Jahson', + 'Javoni', + 'Jayel', + 'Jie', + 'Kwadwo', + 'Kahmani', + 'Johansel', + 'Murat', + 'Nasire', + 'Nezar', + 'Seydou', + 'Jamair', + 'Jahmeer', + 'Chanina', + 'Chezky', + 'Zyire', + 'Yoscar', + 'Alassane', + 'Aitan', + 'Dannon', + 'Donelle', + 'Harrington', + 'Sha', + 'Shamal', + 'Josph', + 'Torrell', + 'Ralphy', + 'Sharron', + 'Eleftherios', + 'Gedalia', + 'Kasheen', + 'Manoj', + 'Nuri', + 'Daran', + 'Devanand', + 'Evagelos', + 'Fatmir', + 'Haralambos', + 'Biju', + 'Nilson', + 'Wane', + 'Tarig', + 'Rober', + 'Sharone', + 'Lezer', + 'Odalis', + 'Glenston', + 'Josip', + 'Kostantinos', + 'Rahshawn', + 'Osei', + 'Shariyf', + 'Sotirios', + 'Aneudi', + 'Marios', + 'Biff', + 'Damiano', + 'Shean', + 'Rajendra', + 'Mare', + 'Richad', + 'Jaja', + 'Efstathios', + 'Nephtali', + 'Kowan', + 'Rhonda', + 'Pasqualino', + 'Confesor', + 'Linc', + 'Safet', + 'Sharrieff', + 'Kiron', + 'Damain', + 'Aurohom', + 'Kariem', + 'Tiheim', + 'Dushawn', + 'Kindu', + 'Aswad', + 'Kwane', + 'Oba', + 'Jermayne', + 'Dakeem', + 'Babatunde', + 'Ackeem', + 'Alvi', + 'Adetokunbo', + 'Akeel', + 'Kedwin', + 'Kayron', + 'Mergim', + 'Wilkins', + 'Wojciech', + 'Omair', + 'Kushtrim', + 'Kwamel', + 'Saiquan', + 'Naquon', + 'Quandell', + 'Veton', + 'Shaune', + 'Daguan', + 'Duquan', + 'Jency', + 'Ka', + 'Waqas', + 'Xiao', + 'Mahlik', + 'Kasiem', + 'Navindra', + 'Sayquan', + 'Shaquon', + 'Shiquan', + 'Rameek', + 'Jerelle', + 'Devaun', + 'Jakim', + 'Jaquell', + 'Eury', + 'Shaiquan', + 'Shakeal', + 'Shakiem', + 'Shaleek', + 'Ramesh', + 'Suhail', + 'Tylique', + 'Jawanza', + 'Jonell', + 'Hamdi', + 'Jaimeson', + 'Kerven', + 'Demetreus', + 'Giselle', + 'Aikeem', + 'Akiem', + 'Rondel', + 'Dow', + 'Gregroy', + 'Darnelle', + 'Naguan', + 'Tyronn', + 'Ricke', + 'Dishawn', + 'Rishawn', + 'Tarick', + 'Tynell', + 'Japhet', + 'Francesc', + 'Maximili', + 'Herby', + 'Jaqwan', + 'Kemal', + 'Akeen', + 'Azeez', + 'Devindra', + 'Deryck', + 'Deval', + 'Alessand', + 'Masood', + 'Uladimir', + 'Cadon', + 'Quanah', + 'Zimere', + 'Chatham', + 'Koi', + 'Zymire', + 'Jamaury', + 'Jahmire', + 'Ziyan', + 'Cowen', + 'Jamaurie', + 'Nyquan', + 'Jayleen', + 'Zymiere', + 'Zymarion', + 'Kahmari', + 'Langdon', + 'Zymari', + 'Jymir', + 'Kamaree', + 'Nycere', + 'Sayvion', + 'Jahmarion', + 'Justyce', + 'Tuck', + 'Thayer', + 'Mung', + 'Graison', + 'Delane', + 'Lemoyne', + 'Cinch', + 'Nevada', + 'Dhairya', + 'Jyaire', + 'Yazir', + 'Tahjmir', + 'Sequoyah', + 'Quention', + 'Tanmay', + 'Shreyansh', + 'Ahyan', + 'Aaryav', + 'Zaylin', + 'Laksh', + 'Basheer', + 'Bhavik', + 'Orley', + 'Vestel', + 'Altus', + 'Choice', + 'Bufford', + 'Quasir', + 'Emry', + 'Tressel', + 'Eppie', + 'Jayvier', + 'Prestin', + 'Haydin', + 'Caydan', + 'Corday', + 'Camdin', + 'Brodyn', + 'Liberato', + 'Trayon', + 'Telesfor', + 'Jayko', + 'Lavi', + 'Procopio', + 'Rubel', + 'Karder', + 'Jaymar', + 'Bryor', + 'Gottlob', + 'Saladin', + 'Tunis', + 'Saheed', + 'Alsexander', + 'Davonn', + 'Jaquill', + 'Shakeil', + 'Krunal', + 'Tashon', + 'Doyel', + 'Odes', + 'Thoams', + 'Rasul', + 'Wendyl', + 'Glendale', + 'Ahmid', + 'Altarik', + 'Amish', + 'Jaquis', + 'Dashan', + 'Salaam', + 'Bhavin', + 'Nashid', + 'Tauheed', + 'Jamill', + 'Cordney', + 'Derly', + 'Jamale', + 'Hristopher', + 'Camaron', + 'Domanique', + 'Desmund', + 'Keenon', + 'Paulanthony', + 'Demarques', + 'Meryl', + 'Medard', + 'Erbey', + 'Adrin', + 'Evo', + 'Pal', + 'Deke', + 'Glendal', + 'Tramayne', + 'Aloysuis', + 'Berthal', + 'Ashly', + 'Arien', + 'Teodulo', + 'Johsua', + 'Kelwin', + 'Quintan', + 'Mauel', + 'Quisto', + 'Gaylin', + 'Trayvion', + 'Tracer', + 'Ramsay', + 'Verlan', + 'Kyndal', + 'Donovon', + 'Samuell', + 'Treyveon', + 'Nereo', + 'Areli', + 'Dashun', + 'Devontre', + 'Stran', + 'Zarian', + 'Pacen', + 'Kamakani', + 'Alii', + 'Chidozie', + 'Cobie', + 'Acxel', + 'Jatavian', + 'Kelvon', + 'Keldon', + 'Giezi', + 'Gavon', + 'Virtus', + 'Burdell', + 'Dorrance', + 'Naail', + 'Lantz', + 'Travian', + 'Cleland', + 'Arish', + 'Elyan', + 'Chukwudi', + 'Shahrukh', + 'Coulter', + 'Karver', + 'Seeley', + 'Wynton', + 'Detric', + 'Quenten', + 'Joemichael', + 'Daruis', + 'Tyeler', + 'Montray', + 'Hermenegildo', + 'Donathan', + 'Mckenna', + 'Kijuan', + 'Braijon', + 'Vashawn', + 'Darvell', + 'Kennie', + 'Rejino', + 'Vickey', + 'Lyndall', + 'Reynoldo', + 'Malyk', + 'Armarion', + 'Brit', + 'Trayshawn', + 'Contrell', + 'Eutimio', + 'Dantrel', + 'Darrious', + 'Dawon', + 'Richey', + 'Arrion', + 'Zohair', + 'Randale', + 'Keyshone', + 'Kiwane', + 'Jibri', + 'Devell', + 'Beto', + 'Jaymz', + 'Ritchey', + 'Tremel', + 'Keante', + 'Vontrell', + 'Guadlupe', + 'Esiquiel', + 'Erasto', + 'Dub', + 'Augustas', + 'Panfilo', + 'Vuk', + 'Mickie', + 'Javonni', + 'Riddick', + 'Nikodem', + 'Marrion', + 'Kamareon', + 'Maks', + 'Eliverto', + 'Cresenciano', + 'Jerrol', + 'Joakim', + 'Maddax', + 'Kayvion', + 'Khizar', + 'Haze', + 'Aveon', + 'Amjad', + 'Audwin', + 'Almir', + 'Vicky', + 'Lonell', + 'Jabarie', + 'Jaylun', + 'Damarrion', + 'Mantas', + 'Dannye', + 'Aadarsh', + 'Caelen', + 'Tilton', + 'Kimmie', + 'Josgar', + 'Oleksandr', + 'Keyontae', + 'Fidelio', + 'Wiktor', + 'Maxymilian', + 'Cayce', + 'Rodric', + 'Manrique', + 'Kestutis', + 'Donnald', + 'Grayland', + 'Lavance', + 'Medgar', + 'Chaney', + 'Monta', + 'Lemond', + 'Medford', + 'Mareo', + 'Camerino', + 'Ronold', + 'Lancer', + 'Credell', + 'Elbridge', + 'Stony', + 'Dvid', + 'Hilberto', + 'Erineo', + 'Jerrald', + 'Antawan', + 'Cordario', + 'Levelle', + 'Ramsen', + 'Jigar', + 'Laroyce', + 'Lazerrick', + 'Artez', + 'Cordelro', + 'Creon', + 'Lonzell', + 'Shanton', + 'Orpheus', + 'Terris', + 'Renauld', + 'Deondra', + 'Fontaine', + 'Airrion', + 'Branko', + 'Enemencio', + 'Antiono', + 'Caprice', + 'Danyale', + 'Valdez', + 'Oswell', + 'Tahitoa', + 'Fannie', + 'Estes', + 'Herchel', + 'Seabron', + 'Bunyan', + 'Thelmon', + 'Agnew', + 'Broughton', + 'Harwell', + 'Mather', + 'Quillie', + 'Hardwick', + 'Phinizy', + 'Pope', + 'Addis', + 'Seals', + 'Thelman', + 'Summie', + 'Romano', + 'Zacari', + 'Kortney', + 'Makye', + 'Graycen', + 'Kavari', + 'Kamarri', + 'Ajahni', + 'Dayan', + 'Sharrod', + 'Pheonix', + 'Trentyn', + 'Jacai', + 'Jamesley', + 'Destyn', + 'Maddon', + 'Gianlucas', + 'Aydrian', + 'Bader', + 'Jaise', + 'Godson', + 'Gleb', + 'Jatniel', + 'Yaxiel', + 'Marvins', + 'Miron', + 'Yaroslav', + 'Legrande', + 'Lonzy', + 'Merrell', + 'Flemming', + 'Guerry', + 'Kimothy', + 'Remus', + 'Wyndell', + 'Barnard', + 'Denorris', + 'Edna', + 'Bevan', + 'Warnell', + 'Josie', + 'Arthor', + 'Theartis', + 'Kimsey', + 'Wymon', + 'Duglas', + 'Reshawn', + 'Natrone', + 'Treysen', + 'Davaris', + 'Jocqui', + 'Traivon', + 'Trevonne', + 'Tavarious', + 'Monson', + 'Kevis', + 'Ladonte', + 'Mackenson', + 'Bodee', + 'Chayden', + 'Dequon', + 'Keiondre', + 'Dewan', + 'Taige', + 'Renel', + 'Jasher', + 'Bayler', + 'Dodger', + 'Tyke', + 'Jarvin', + 'Edner', + 'Travonn', + 'Traxton', + 'Malosi', + 'Lavonta', + 'Janard', + 'Kyzer', + 'Packer', + 'Travoris', + 'Frantzy', + 'Makay', + 'Tamari', + 'Kanard', + 'Dairon', + 'Gabriell', + 'Kemaury', + 'Jshaun', + 'Karel', + 'Jakarri', + 'Rubens', + 'Zamauri', + 'Winsley', + 'Giulian', + 'Yosbel', + 'Kevaughn', + 'Jimson', + 'Kendly', + 'Dishon', + 'Dallyn', + 'Jephthe', + 'Luccas', + 'Kemuel', + 'Eddrick', + 'Ahmarion', + 'Amariyon', + 'Artavis', + 'Dewin', + 'Jacarie', + 'Jahn', + 'Janari', + 'Geordy', + 'Mardochee', + 'Jimari', + 'Yoshinobu', + 'Eiji', + 'Yasunobu', + 'Koon', + 'Hidemi', + 'Norio', + 'Kiyomi', + 'Shuichi', + 'Kazuyoshi', + 'Yoshitaka', + 'Kanji', + 'Tetsuro', + 'Asao', + 'Dominador', + 'Shogo', + 'Jakye', + 'Braelin', + 'Chrisangel', + 'Calab', + 'Morio', + 'Seiki', + 'Tsuyoshi', + 'Soichi', + 'Masakatsu', + 'Tadayoshi', + 'Tokuichi', + 'Yoshikatsu', + 'Matsuichi', + 'Lorrin', + 'Javeion', + 'Kail', + 'Jvon', + 'Joshwa', + 'Keylen', + 'Rylon', + 'Oved', + 'Kraven', + 'Koben', + 'Klever', + 'Nedved', + 'Dago', + 'Cortlen', + 'Reeves', + 'Yhair', + 'Xane', + 'Jamori', + 'Jayshon', + 'Jaiveon', + 'Joseth', + 'Drelynn', + 'Haldrin', + 'Keelyn', + 'Nathanuel', + 'Kvon', + 'Jayln', + 'Khyrie', + 'Zayveon', + 'Braxston', + 'Jaceion', + 'Jonavon', + 'Jesaiah', + 'Gaddiel', + 'Tobyn', + 'Becket', + 'Aydyn', + 'Arinze', + 'Dacian', + 'Aadin', + 'Fender', + 'Brysun', + 'Demarious', + 'Kaimi', + 'Ryson', + 'Jarrin', + 'Maleko', + 'Kamakana', + 'Kamalani', + 'Johnavon', + 'Kawena', + 'Aadil', + 'Blayde', + 'Garyn', + 'Izaih', + 'Bryndon', + 'Drelyn', + 'Demarian', + 'Kupaa', + 'Nalu', + 'Makena', + 'Lawaia', + 'Kaimalu', + 'Kanaloa', + 'Oshen', + 'Mj', + 'Kahekili', + 'Koalii', + 'Makua', + 'Promise', + 'Keylin', + 'Kevondrick', + 'Tobenna', + 'Infantboy', + 'Oluwatimilehin', + 'Nathanal', + 'Zakkery', + 'Shariq', + 'Sadler', + 'Rockne', + 'Drelon', + 'Ethon', + 'Catcher', + 'Clayten', + 'Kaniela', + 'Isaack', + 'Josten', + 'Zarius', + 'Tayte', + 'Ugochukwu', + 'Aiman', + 'Eduar', + 'Basel', + 'Canton', + 'Dyron', + 'Keaden', + 'Kayceon', + 'Kyrian', + 'Kree', + 'Jj', + 'Iaan', + 'Hudsyn', + 'Graceson', + 'Gatlyn', + 'Eydan', + 'Jak', + 'Townsend', + 'Owais', + 'Nandan', + 'Rayland', + 'Ridhaan', + 'Dantavious', + 'Lavoris', + 'Maricus', + 'Rodrigus', + 'Aayansh', + 'Chasten', + 'Durante', + 'Johnta', + 'Detavious', + 'Donterrius', + 'Rilyn', + 'Rilee', + 'Marquize', + 'Quinterius', + 'Jamarco', + 'Quinnton', + 'Deston', + 'Aceson', + 'Britten', + 'Adric', + 'Tabias', + 'Lajarvis', + 'Corderius', + 'Romon', + 'Que', + 'Nord', + 'Lerone', + 'Skylan', + 'Tobi', + 'Mccrae', + 'Mathayus', + 'Marcuz', + 'Levii', + 'Lander', + 'Oluwadarasimi', + 'Miklo', + 'Nijah', + 'Nero', + 'Quavis', + 'Zailyn', + 'Whitman', + 'Zavior', + 'Zlatan', + 'Crixus', + 'Cotton', + 'Chukwuebuka', + 'Draden', + 'Caston', + 'Aceyn', + 'Caeson', + 'Brax', + 'Azel', + 'Kaisyn', + 'Hunt', + 'Gaius', + 'Gabrian', + 'Falcon', + 'Iyan', + 'Jayjay', + 'Altonio', + 'Woodruff', + 'Tavare', + 'Kawaski', + 'Dontravious', + 'Gabreil', + 'Holten', + 'Dayvian', + 'Brennyn', + 'Chayson', + 'Dailon', + 'Keyshun', + 'Jaryn', + 'Jamyron', + 'Jakavion', + 'July', + 'Jonanthony', + 'Trenden', + 'Tobechukwu', + 'Yostin', + 'Casin', + 'Kaydyn', + 'Jshawn', + 'Keaghan', + 'Khalen', + 'Haylen', + 'Jamarques', + 'Alyjah', + 'Baylon', + 'Kemontae', + 'Taysean', + 'Slaton', + 'Saxton', + 'Yadir', + 'Tramon', + 'Traevion', + 'Raydon', + 'Raahim', + 'Olamide', + 'Oreoluwa', + 'Zyien', + 'Zayde', + 'Marqavious', + 'Marquavis', + 'Trevious', + 'Zyshonne', + 'Quindarrius', + 'Quintarious', + 'Quinterious', + 'Rodarius', + 'Deontavious', + 'Champion', + 'Decklan', + 'Daxx', + 'Pecos', + 'Jovonni', + 'Jaydrian', + 'Montravius', + 'Gunter', + 'Zerrick', + 'Quontavious', + 'Ayeden', + 'Audi', + 'Bentlie', + 'Brek', + 'Travonne', + 'Daquavious', + 'Jartavious', + 'Keldric', + 'Alezander', + 'Kamen', + 'Taytum', + 'Siler', + 'Yavuz', + 'Zaniel', + 'Yuriel', + 'Draiden', + 'Axzel', + 'Castin', + 'Keeland', + 'Jrake', + 'Jonhatan', + 'Jeziel', + 'Javery', + 'Severino', + 'Olavi', + 'Benoit', + 'Phillips', + 'Lothrop', + 'Konstanty', + 'Mato', + 'Carney', + 'Keithen', + 'Easley', + 'Chanler', + 'Erbie', + 'Ephriam', + 'Kentravion', + 'Kesan', + 'Ladamien', + 'Treshun', + 'Jakyron', + 'Burch', + 'Kaston', + 'Kyndall', + 'Jarden', + 'Shields', + 'Jontrell', + 'Thales', + 'Minnis', + 'Ida', + 'Hildred', + 'Helder', + 'Fernell', + 'Shone', + 'Laterrance', + 'Tuyen', + 'Roshun', + 'Vincient', + 'Ory', + 'Hilman', + 'Calton', + 'Clydell', + 'Vick', + 'Derrin', + 'Silton', + 'Tandy', + 'Emeal', + 'Rual', + 'Cardarius', + 'Jylan', + 'Hodge', + 'Charls', + 'Jacobey', + 'Jaqualon', + 'Jyrin', + 'Calib', + 'Fowler', + 'Kalep', + 'Osco', + 'Treylan', + 'Paschal', + 'Lowry', + 'Tydrick', + 'Ladavion', + 'Roe', + 'Jarmall', + 'Josuha', + 'Quindell', + 'Tra', + 'Jamaria', + 'Jermicheal', + 'Hobie', + 'Oluwaseun', + 'Trimayne', + 'Kaire', + 'Katrell', + 'Tradd', + 'Yohannes', + 'Oluwaseyi', + 'Tyski', + 'Lansana', + 'Tion', + 'Delontay', + 'Tavone', + 'Quante', + 'Taavon', + 'Daquane', + 'Burleigh', + 'Eyoel', + 'Cung', + 'Khodee', + 'Emilien', + 'Laurien', + 'Leonide', + 'Loomis', + 'Antrone', + 'Sewall', + 'Nicollas', + 'Vitor', + 'Jaythian', + 'Jasaun', + 'Tighe', + 'Colman', + 'Antionne', + 'Nygel', + 'Garnell', + 'Jamareon', + 'Alvey', + 'Carvel', + 'Carville', + 'Carlester', + 'Rutledge', + 'Mills', + 'Rayner', + 'Doil', + 'Gregario', + 'Aniseto', + 'Audon', + 'Brevyn', + 'Pio', + 'Tanis', + 'Jasinto', + 'Jaxtin', + 'Nugent', + 'Eldredge', + 'Egon', + 'Jong', + 'Pancho', + 'Lionardo', + 'Susano', + 'Trueman', + 'Braxtin', + 'Delphine', + 'Harroll', + 'Goree', + 'Manuela', + 'Epigmenio', + 'Laureano', + 'Josefina', + 'Tiodoro', + 'Silbestre', + 'Patrocinio', + 'Corando', + 'Maciah', + 'Quintyn', + 'Wrigley', + 'Onie', + 'Noal', + 'Duward', + 'Filomeno', + 'Cleburn', + 'Garvis', + 'Bisente', + 'Cedell', + 'Jap', + 'Rube', + 'Mavis', + 'Jarold', + 'Hijinio', + 'Dewie', + 'Trinida', + 'Jung', + 'Byrd', + 'Mcadoo', + 'Floy', + 'Eldie', + 'Volney', + 'Saragosa', + 'Derward', + 'Francico', + 'Genovevo', + 'Lindley', + 'Lasalle', + 'Borden', + 'Bonny', + 'Claudis', + 'Silberio', + 'Asuncion', + 'Rolly', + 'Doak', + 'Luvender', + 'Thurl', + 'Garl', + 'Arvine', + 'Johnnye', + 'Emiterio', + 'Crisoforo', + 'Eulojio', + 'Edell', + 'Infboy', + 'Ural', + 'Natalia', + 'Delia', + 'Acencion', + 'Joas', + 'Keagon', + 'Reice', + 'Esperanza', + 'Velton', + 'Eufemio', + 'Frumencio', + 'Dominga', + 'Eutiquio', + 'Dois', + 'Gean', + 'Odaniel', + 'Lyndel', + 'Kreigh', + 'Bobbye', + 'Rogue', + 'Deundra', + 'Cambron', + 'Kaitlynn', + 'Kayleigh', + 'Hailee', + 'Piper', + 'Sofia', + 'Carly', + 'Abigayle', + 'Angelina', + 'Tavish', + 'Christophere', + 'Anterrio', + 'Thimothy', + 'Montarius', + 'Marquarius', + 'Labradford', + 'Lawless', + 'Lenis', + 'Camile', + 'Tonya', + 'Hersey', + 'Abbie', + 'Loveless', + 'Aristide', + 'Ovey', + 'Ovide', + 'Robley', + 'Elward', + 'Leory', + 'Earlis', + 'Gaynell', + 'Printes', + 'Elzy', + 'Aswell', + 'Waver', + 'Wilma', + 'Minos', + 'Euclide', + 'Aster', + 'Demarrion', + 'Selbert', + 'Stoy', + 'Brack', + 'Strother', + 'Osa', + 'Ovel', + 'Custer', + 'Keveon', + 'Lenvil', + 'Hargus', + 'Kline', + 'Goldie', + 'Warfield', + 'Wavy', + 'Carless', + 'Proctor', + 'Holston', + 'Philopateer', + 'Loman', + 'Vernis', + 'Forster', + 'Jakie', + 'Martavis', + 'Louard', + 'Corbet', + 'Waldon', + 'Cluster', + 'Lafe', + 'Tayshun', + 'Browder', + 'Moss', + 'Rudell', + 'Loyde', + 'Glendel', + 'Elby', + 'Shafter', + 'Camila', + 'Elaine', + 'Scarlett', + 'Gertrude', + 'Bella', + 'Penelope', + 'Cathy', + 'Lizbeth', + 'Arianna', + 'Agnes', + 'Vicki', + 'Mila', + 'Ximena', + 'Delilah', + 'Stella', + 'Miranda', + 'Valentina', + 'Rosemary', + 'Khloe', + 'Heidi', + 'Desiree', + 'Violet', + 'Gianna', + 'Nayeli', + 'Luna', + 'Doreen', + 'Jennie', + 'Roberta', + 'Sheri', + 'Jeanne', + 'Alina', + 'Celeste', + 'Rosalie', + 'Naomi', + 'Teri', + 'Maryann', + 'Glenda', + 'Lynda', + 'Annabelle', + 'Antoinette', + 'Stephani', + 'Marcia', + 'Sherri', + 'Clara', + 'Julissa', + 'Becky', + 'Marianne', + 'Melody', + 'Sadie', + 'Sienna', + 'Marsha', + 'Belinda', + 'Jaylah', + 'Harriet', + 'Kristine', + 'Elizabet', + 'Paisley', + 'Genevieve', + 'Melinda', + 'Leilani', + 'Aubree', + 'Keira', + 'Kristy', + 'Sheryl', + 'Fernanda', + 'Tami', + 'Daleyza', + 'Rosemarie', + 'Francine', + 'Kristi', + 'Jaqueline', + 'Meagan', + 'Nichole', + 'Athena', + 'Anahi', + 'Marisa', + 'Yaretzi', + 'Lena', + 'Serena', + 'Miley', + 'Izabella', + 'Kate', + 'Joselyn', + 'Margie', + 'Krystle', + 'Dulce', + 'Pam', + 'Traci', + 'Mikayla', + 'Shari', + 'Delores', + 'Nellie', + 'Gisselle', + 'Blanche', + 'Clarissa', + 'Dianne', + 'Maxine', + 'Janis', + 'Carmela', + 'Mabel', + 'Estrella', + 'Emely', + 'Viola', + 'Penny', + 'Viviana', + 'Estelle', + 'Krista', + 'Adalynn', + 'Julianna', + 'Danna', + 'Marina', + 'Sheena', + 'Shawna', + 'Mya', + 'Leona', + 'Leila', + 'Isla', + 'Charlene', + 'Mindy', + 'Bernadette', + 'Audrina', + 'Tricia', + 'Adele', + 'Myrtle', + 'Nataly', + 'Kimberley', + 'Gwendolyn', + 'Emilia', + 'Janine', + 'Paulina', + 'Stefanie', + 'Marguerite', + 'Dayanara', + 'Katina', + 'Brielle', + 'Vera', + 'Jimena', + 'Aileen', + 'Bethany', + 'America', + 'Kellie', + 'Shanice', + 'Roxanne', + 'Darla', + 'Mamie', + 'Jocelyne', + 'Katherin', + 'Lyla', + 'Sonya', + 'Allyson', + 'Debora', + 'Chaya', + 'Jaslene', + 'Malia', + 'Daniella', + 'Alessandra', + 'Aimee', + 'Dina', + 'Arabella', + 'Juliet', + 'Laila', + 'Rhoda', + 'Angie', + 'Everly', + 'Adrianna', + 'Shelia', + 'Jana', + 'Analia', + 'Kamila', + 'Rebekah', + 'Myrna', + 'Concetta', + 'Amaya', + 'Juliette', + 'Litzy', + 'Marely', + 'Londyn', + 'Patti', + 'Adalyn', + 'Marla', + 'Tammie', + 'Cora', + 'Angelique', + 'Fiona', + 'Kari', + 'Jaylene', + 'Lucile', + 'Rubi', + 'Vivienne', + 'Hattie', + 'Noemi', + 'Celina', + 'Dena', + 'Sherlyn', + 'Selina', + 'Bonita', + 'Paulette', + 'Aisha', + 'Susie', + 'Adeline', + 'Elsa', + 'Shania', + 'Yasmin', + 'Dalia', + 'Jacquelyn', + 'Thalia', + 'Trina', + 'Allisson', + 'Chana', + 'Olive', + 'Helene', + 'Nelda', + 'Mireya', + 'Chelsey', + 'Cheri', + 'Kira', + 'Karissa', + 'Lynette', + 'Deneen', + 'Ivette', + 'Roslyn', + 'Kinley', + 'Rosalinda', + 'Lila', + 'Kaylie', + 'Dayana', + 'Melany', + 'Carissa', + 'Aniyah', + 'Kyla', + 'Yulissa', + 'Trisha', + 'Camilla', + 'Ansley', + 'Sarai', + 'Lola', + 'Arline', + 'Lara', + 'Stacie', + 'Annika', + 'Christi', + 'Brisa', + 'Gia', + 'Therese', + 'Abril', + 'Angeline', + 'Isabela', + 'Marcella', + 'Shanna', + 'Stephany', + 'Henrietta', + 'Tasha', + 'Brianne', + 'Rosanne', + 'Luann', + 'Frieda', + 'Renata', + 'Dianna', + 'Celia', + 'Sondra', + 'Aylin', + 'Melba', + 'Catina', + 'Alayna', + 'Mollie', + 'Nathalie', + 'Tabitha', + 'Tracie', + 'Scarlet', + 'Jayne', + 'Rachelle', + 'Jeannette', + 'Addyson', + 'Cecelia', + 'Annabella', + 'Dahlia', + 'Dorothea', + 'Annmarie', + 'Marlys', + 'Deirdre', + 'Evangeline', + 'Melina', + 'Erma', + 'Jeanine', + 'Roxana', + 'Yaritza', + 'Montserrat', + 'Lizzie', + 'Kerri', + 'Yoselin', + 'Migdalia', + 'Rivka', + 'Cathleen', + 'Lorene', + 'Yareli', + 'Bette', + 'Kyra', + 'Janette', + 'Beulah', + 'Danica', + 'Arely', + 'Lexi', + 'Shana', + 'Sherrie', + 'Alexus', + 'Mable', + 'Citlalli', + 'Nadine', + 'Shauna', + 'Ryleigh', + 'Jeri', + 'Phoebe', + 'Jazlyn', + 'Noreen', + 'Keisha', + 'Lora', + 'Brynlee', + 'Alivia', + 'Lottie', + 'Monserrat', + 'Giuliana', + 'Adelyn', + 'Deana', + 'Jacqueli', + 'Makenna', + 'Jeannie', + 'Noelle', + 'Imogene', + 'Daphne', + 'Reyna', + 'Katelynn', + 'Bettie', + 'Carmella', + 'Estefania', + 'Cassandr', + 'Betsy', + 'Brianda', + 'Iliana', + 'Bryanna', + 'Aranza', + 'Rihanna', + 'Anissa', + 'Alisa', + 'Azul', + 'Milagros', + 'Gemma', + 'Freda', + 'Ada', + 'Bettye', + 'Nia', + 'Oralia', + 'Alaina', + 'Anabelle', + 'Destinee', + 'Sallie', + 'Sonja', + 'Willow', + 'Staci', + 'Lia', + 'Breana', + 'Eliza', + 'Mikaela', + 'Mona', + 'Cataleya', + 'Jeannine', + 'Lilah', + 'Anabel', + 'Ashlynn', + 'Aleena', + 'Estella', + 'Ayla', + 'Adelaide', + 'Lilliana', + 'Kristie', + 'Nettie', + 'Cherie', + 'May', + 'Myra', + 'Nicolette', + 'Lissette', + 'Siena', + 'Ivanna', + 'Christa', + 'Caylee', + 'Roseann', + 'Anastasia', + 'Karin', + 'Corinne', + 'Ginger', + 'Flora', + 'Bria', + 'Gretchen', + 'Maryellen', + 'Lana', + 'Harmony', + 'Elvira', + 'Ilene', + 'Iesha', + 'Celine', + 'Faye', + 'Khadijah', + 'Elyse', + 'Joana', + 'Sharyn', + 'Leia', + 'Catherin', + 'Corina', + 'Sheree', + 'Salma', + 'Deja', + 'Liz', + 'Aracely', + 'Roselyn', + 'Samara', + 'Lorrie', + 'Frida', + 'Tessie', + 'Talia', + 'Rosalind', + 'Jailene', + 'Lisette', + 'Raelynn', + 'Yetta', + 'Catharine', + 'Adelynn', + 'Odalys', + 'Jolene', + 'Charity', + 'Aniya', + 'Sanjuanita', + 'Norah', + 'Terrie', + 'Yuliana', + 'Lorie', + 'Yazmin', + 'Eleanore', + 'Anika', + 'Elida', + 'Valery', + 'Matilda', + 'Nannie', + 'Eloise', + 'Gillian', + 'Tatyana', + 'Kimora', + 'Brynn', + 'Maliyah', + 'Madilyn', + 'Jenifer', + 'Maddison', + 'Colette', + 'Nanette', + 'Ayleen', + 'Winnie', + 'Jayda', + 'Deloris', + 'Tillie', + 'Kizzy', + 'Galilea', + 'Janessa', + 'Brenna', + 'Amelie', + 'Marybeth', + 'Lorna', + 'Kaia', + 'Sarahi', + 'Viridiana', + 'Rebeca', + 'Ericka', + 'Mareli', + 'Anaya', + 'Nathaly', + 'Candy', + 'Larissa', + 'Elle', + 'Yasmine', + 'Claudine', + 'Kyleigh', + 'Paloma', + 'Lenore', + 'Citlali', + 'Rosanna', + 'Misti', + 'Kasandra', + 'Zara', + 'Isis', + 'Alisson', + 'Cheyanne', + 'Reba', + 'Ariella', + 'Lavonne', + 'Miah', + 'Roxanna', + 'Anabella', + 'Suzette', + 'Kiera', + 'Gitty', + 'Farrah', + 'Helena', + 'Shaniqua', + 'Maryanne', + 'Liana', + 'Arleen', + 'Belle', + 'Katy', + 'Anya', + 'Selene', + 'Maura', + 'Chantel', + 'Keyla', + 'Maryjane', + 'Tisha', + 'Kisha', + 'Kaelyn', + 'Malka', + 'Maci', + 'Evelin', + 'Julianne', + 'Magdalena', + 'Kimberlee', + 'Ernestine', + 'Alyson', + 'Kaley', + 'Danika', + 'Kecia', + 'Leanne', + 'Tonia', + 'Nyla', + 'Ivonne', + 'Madelynn', + 'Ofelia', + 'Lakisha', + 'Adilene', + 'Wendi', + 'Susanne', + 'Katharine', + 'Faigy', + 'Raizy', + 'Tawny', + 'Jackeline', + 'Ariadne', + 'Giovanna', + 'Janiyah', + 'Alani', + 'Nayely', + 'Lilian', + 'Saundra', + 'Jazlynn', + 'Jaelynn', + 'Elliana', + 'Gayla', + 'Deena', + 'Earnestine', + 'Margo', + 'Herlinda', + 'Elinor', + 'Salina', + 'Casandra', + 'Nathalia', + 'Kaila', + 'Deanne', + 'Desirae', + 'Liza', + 'Bobbi', + 'Briella', + 'Gilda', + 'Averie', + 'Charlize', + 'Azalea', + 'Sanjuana', + 'Yajaira', + 'Brandie', + 'Aleah', + 'Della', + 'Elaina', + 'Yahaira', + 'Aja', + 'Bernadine', + 'Lela', + 'Annabel', + 'Xiomara', + 'Kassidy', + 'Nohely', + 'Aubrie', + 'Angelia', + 'Macie', + 'Shelbi', + 'Chelsie', + 'Lilyana', + 'Jazlene', + 'Amina', + 'Dorthy', + 'Noelia', + 'Addisyn', + 'Dalilah', + 'Clarisa', + 'Chrystal', + 'Oleta', + 'Georgina', + 'Adelina', + 'Edythe', + 'Lucinda', + 'Jannie', + 'Minerva', + 'Kelsie', + 'Madisyn', + 'Aida', + 'Katlyn', + 'Julieta', + 'Violeta', + 'Heidy', + 'Lea', + 'Leola', + 'Chasity', + 'Nell', + 'Felicity', + 'Kathi', + 'Karyn', + 'Hana', + 'Micaela', + 'Chandra', + 'Liberty', + 'Cielo', + 'Tameka', + 'Maude', + 'Malky', + 'Coraima', + 'Haylie', + 'Vanesa', + 'Sloane', + 'Karyme', + 'Evelynn', + 'Batsheva', + 'Nallely', + 'Tamra', + 'Maricruz', + 'Paislee', + 'Kynlee', + 'Marcela', + 'Marci', + 'Vonda', + 'Cinthia', + 'Amiyah', + 'Breanne', + 'Lisbeth', + 'Leanna', + 'Anais', + 'Flor', + 'Annemarie', + 'Amie', + 'Estela', + 'Tammi', + 'Rhiannon', + 'Denisse', + 'Leyla', + 'Iridian', + 'Dariana', + 'Romina', + 'Yamileth', + 'Lidia', + 'Sybil', + 'Elvia', + 'Debby', + 'Philomena', + 'Jacklyn', + 'Charlee', + 'Kathie', + 'Aryanna', + 'Katarina', + 'Elianna', + 'Zariah', + 'Andreina', + 'Filomena', + 'Xochitl', + 'Mariam', + 'Myla', + 'Janiya', + 'Kristal', + 'Estefany', + 'Debi', + 'Miracle', + 'Shaindy', + 'Evangelina', + 'Naya', + 'Maeve', + 'Judi', + 'Effie', + 'Lilia', + 'Dayami', + 'Kierra', + 'Vincenza', + 'Cari', + 'Lauri', + 'Bethzy', + 'Trudy', + 'Deidre', + 'Melisa', + 'Luciana', + 'Chantal', + 'Laisha', + 'Kennedi', + 'Ayanna', + 'Madalyn', + 'Dania', + 'Jaliyah', + 'Madilynn', + 'Citlaly', + 'Lolita', + 'Drema', + 'Iva', + 'Kailee', + 'Grecia', + 'Kailyn', + 'Ladonna', + 'Latanya', + 'Maia', + 'Jaquelin', + 'Alanna', + 'Etta', + 'Marlee', + 'Reina', + 'Aiyana', + 'Carolann', + 'Gizelle', + 'Greta', + 'Lynnette', + 'Cecile', + 'Shayna', + 'Savanah', + 'Annalise', + 'Nylah', + 'Lesa', + 'Jolie', + 'Arleth', + 'Laraine', + 'Selah', + 'Alysha', + 'Bridgette', + 'Madyson', + 'Marylou', + 'Adela', + 'Shaina', + 'Trista', + 'Katia', + 'Kayleen', + 'Lilianna', + 'Tamera', + 'Millicent', + 'Eugenia', + 'Myrtice', + 'Baila', + 'Charmaine', + 'Maegan', + 'Ruthie', + 'Jovanna', + 'Julisa', + 'Mayte', + 'Latrice', + 'Priscila', + 'Glenna', + 'Yitty', + 'Tawana', + 'Yessica', + 'Ina', + 'Brittni', + 'Johana', + 'Tess', + 'Caryn', + 'Natalee', + 'Barb', + 'Journee', + 'Malaysia', + 'Yulisa', + 'Alta', + 'Shaila', + 'Maurine', + 'Amira', + 'Tiffani', + 'Danette', + 'Fanny', + 'Justina', + 'Leann', + 'Dafne', + 'Ima', + 'Azucena', + 'Braylee', + 'Amaris', + 'Bailee', + 'Giana', + 'Josette', + 'Raegan', + 'Gena', + 'Luella', + 'Nita', + 'Laney', + 'Gisela', + 'Alexandrea', + 'Rosalia', + 'Odessa', + 'Laci', + 'Yamilex', + 'Tamia', + 'Astrid', + 'Luanne', + 'Gwen', + 'Tabatha', + 'Rivky', + 'Laureen', + 'Zina', + 'Amara', + 'Itzayana', + 'Adamaris', + 'Laylah', + 'Luisa', + 'Georgette', + 'Joselin', + 'Yamilet', + 'Nilda', + 'Luisana', + 'Coleen', + 'Cecily', + 'Jocelynn', + 'Mirella', + 'Jessika', + 'Moriah', + 'Halle', + 'Caren', + 'Earline', + 'Shantel', + 'Aliana', + 'Keila', + 'Maryam', + 'Marianna', + 'Magaly', + 'Sariah', + 'Marnie', + 'Kiersten', + 'Janeth', + 'Lyndsey', + 'Shelli', + 'Jaylee', + 'Ashlie', + 'Tianna', + 'Bree', + 'Isela', + 'Krystina', + 'Yaretzy', + 'Evelina', + 'Sarina', + 'Tyra', + 'Eloisa', + 'Maite', + 'Leilah', + 'Marcie', + 'Imelda', + 'Alena', + 'Juniper', + 'Shelbie', + 'Shakira', + 'Ember', + 'Emmalyn', + 'Elissa', + 'Skyla', + 'Lylah', + 'Xitlali', + 'Gisele', + 'Polly', + 'Ernestina', + 'Sandi', + 'Emmy', + 'Josefa', + 'Magali', + 'Ashely', + 'Eve', + 'Jayde', + 'Rosella', + 'Yuridia', + 'Sheyla', + 'Raelyn', + 'Domenica', + 'Valarie', + 'Herminia', + 'Katalina', + 'Shaquana', + 'Nelly', + 'Rosalyn', + 'Denice', + 'Saanvi', + 'Cambria', + 'Joseline', + 'Tomasa', + 'Milana', + 'Harriett', + 'Devorah', + 'Jackelyn', + 'Jacquelin', + 'Yadhira', + 'Antonella', + 'Shreya', + 'Janay', + 'Betzy', + 'Kaiya', + 'Terra', + 'Roseanne', + 'Karime', + 'Lina', + 'Macey', + 'Vilma', + 'Shaniya', + 'Deyanira', + 'Cindi', + 'Mandi', + 'Sanaa', + 'Lakesha', + 'Essence', + 'Faviola', + 'Brinley', + 'Kirstie', + 'Brissa', + 'Alia', + 'Janney', + 'Kaylynn', + 'Kamilah', + 'Kianna', + 'Adrianne', + 'Yasmeen', + 'Jerri', + 'Anayeli', + 'Ambar', + 'Lorri', + 'Hailie', + 'Demetria', + 'Awilda', + 'Isabell', + 'Leonor', + 'Florine', + 'Tennille', + 'Deann', + 'Nyah', + 'Jolette', + 'Xitlaly', + 'Vienna', + 'Lenora', + 'Keily', + 'Syble', + 'Ciera', + 'Milania', + 'Lainey', + 'Nyasia', + 'Carley', + 'Kelsi', + 'Blossom', + 'Maranda', + 'Ally', + 'Serina', + 'Charli', + 'Taraji', + 'Jena', + 'Natalya', + 'Hortencia', + 'Ila', + 'Kailani', + 'Mira', + 'Evie', + 'Ione', + 'Briseyda', + 'Aryana', + 'Yarely', + 'Susanna', + 'Amya', + 'Kaleigh', + 'Qiana', + 'Juli', + 'Mckayla', + 'Suzan', + 'Fallon', + 'Jacalyn', + 'Ileana', + 'Yesica', + 'Willa', + 'Fatoumata', + 'Arly', + 'Jakayla', + 'Chyna', + 'Jaida', + 'Sunshine', + 'Beyonce', + 'Lawanda', + 'Flossie', + 'Lupita', + 'Demi', + 'Keely', + 'Aliya', + 'Jeanie', + 'Tamiko', + 'Gigi', + 'Brissia', + 'Mariel', + 'Lluvia', + 'Jasleen', + 'Lizet', + 'Brittanie', + 'Kaci', + 'Alycia', + 'Madalynn', + 'Milena', + 'Coraline', + 'Kaela', + 'Soraya', + 'Mozelle', + 'Jessenia', + 'Wilhelmina', + 'Jazmyn', + 'Stefani', + 'Natali', + 'Christiana', + 'Ivana', + 'Eiza', + 'Zaria', + 'Zaira', + 'Lorelei', + 'Cherry', + 'Aline', + 'Briseida', + 'Siani', + 'Yara', + 'Rhianna', + 'Kalia', + 'Destiney', + 'Hindy', + 'Arlette', + 'Shyanne', + 'Joceline', + 'Janell', + 'Vianey', + 'Elnora', + 'Zoie', + 'Elba', + 'Jamila', + 'Rena', + 'Mari', + 'Chava', + 'Scarlette', + 'Shyla', + 'Corine', + 'Kaliyah', + 'Ailyn', + 'Liv', + 'Freya', + 'Diya', + 'Myrtis', + 'Aliah', + 'Margery', + 'Gracelyn', + 'Shira', + 'Riya', + 'Breann', + 'Siobhan', + 'Rochel', + 'Tiffanie', + 'Mirna', + 'Nilsa', + 'Tenley', + 'Aliza', + 'Celena', + 'Vianney', + 'Janel', + 'Toccara', + 'Dayna', + 'Rona', + 'Alba', + 'Althea', + 'Josselyn', + 'Karlie', + 'Alyce', + 'Erlinda', + 'Kadijah', + 'Rosalba', + 'Tangela', + 'Marlena', + 'Delois', + 'Chastity', + 'Coral', + 'Braelynn', + 'Dalila', + 'Rosetta', + 'Lu', + 'Venessa', + 'Kayley', + 'Barbra', + 'Jesica', + 'Dona', + 'Mitzi', + 'Catrina', + 'Gracelynn', + 'Ophelia', + 'Ayana', + 'Mara', + 'Calista', + 'Adyson', + 'Marilynn', + 'Tomeka', + 'Britni', + 'Whitley', + 'Karly', + 'Verenice', + 'Raylee', + 'Dayanna', + 'Shonda', + 'Felecia', + 'Betzaida', + 'Kaylani', + 'Shaylee', + 'Jazzlyn', + 'Giavanna', + 'Vivianna', + 'Jesusa', + 'Lashonda', + 'Maile', + 'Suzy', + 'Vania', + 'Giada', + 'Maisie', + 'Venus', + 'Emerald', + 'Wilda', + 'Saniya', + 'Naydelin', + 'Enid', + 'Leilany', + 'Jesenia', + 'Maliah', + 'Dortha', + 'Dalary', + 'Chany', + 'Amia', + 'Amalia', + 'Khaleesi', + 'Taina', + 'Abbey', + 'Dollie', + 'Joslyn', + 'Sommer', + 'Lilibeth', + 'Charleigh', + 'Sydell', + 'Shoshana', + 'Nechama', + 'Jamya', + 'Jeanmarie', + 'Albertha', + 'Akeelah', + 'Aanya', + 'Destini', + 'Kacie', + 'Maleah', + 'Cayla', + 'Bryana', + 'Zelma', + 'Anjanette', + 'Kaylah', + 'Tonja', + 'Amairani', + 'Karli', + 'Elina', + 'Aurelia', + 'Judie', + 'Letha', + 'Brittnee', + 'Yanira', + 'Ariza', + 'Kataleya', + 'Berta', + 'Soleil', + 'Marleen', + 'Desteny', + 'Gissel', + 'Suri', + 'Anjelica', + 'Lilith', + 'Breeanna', + 'Krysta', + 'Alysia', + 'Chrissy', + 'Lailah', + 'Cathryn', + 'Dawna', + 'Myah', + 'Lelia', + 'Aviana', + 'Xena', + 'Pansy', + 'Jazleen', + 'Kaylyn', + 'Mariann', + 'Celene', + 'Berniece', + 'Anjali', + 'Benita', + 'Reanna', + 'Sydnee', + 'Taliyah', + 'Raylene', + 'Kristyn', + 'Latonia', + 'Pa', + 'Nola', + 'Lyanne', + 'Danae', + 'Sharla', + 'Chanelle', + 'Aleyda', + 'Deb', + 'Sofie', + 'Shameka', + 'Emelia', + 'Miya', + 'Latricia', + 'Claribel', + 'Lacie', + 'Taisha', + 'Queen', + 'Breeana', + 'Ilana', + 'Erna', + 'Neha', + 'Melodie', + 'Ariah', + 'Ursula', + 'Janna', + 'Cienna', + 'Maryjo', + 'Vannessa', + 'Saniyah', + 'Mariajose', + 'Malaya', + 'Abbigail', + 'Elin', + 'Emi', + 'Shanaya', + 'Zahra', + 'Lorine', + 'Karrie', + 'Johnna', + 'Marni', + 'Karis', + 'Shelba', + 'Omayra', + 'Claudette', + 'Anitra', + 'Jenelle', + 'Zelda', + 'Alyse', + 'Alethea', + 'Jannet', + 'Myranda', + 'Corinna', + 'Pattie', + 'Jemma', + 'Avah', + 'Joycelyn', + 'Loriann', + 'Kirstin', + 'Davina', + 'Clementine', + 'Arantza', + 'Esme', + 'Vida', + 'Samira', + 'Alysa', + 'Ananya', + 'Cherish', + 'Jocelin', + 'Renae', + 'Jalisa', + 'Elease', + 'Salena', + 'Zhane', + 'Zulema', + 'Rubye', + 'Amerie', + 'Leatrice', + 'Geralyn', + 'Brigitte', + 'Sibyl', + 'Corrina', + 'Phylicia', + 'Karlee', + 'Kerrie', + 'Addilyn', + 'Alayah', + 'Jacquely', + 'Mirian', + 'Jovana', + 'Katelin', + 'Marielena', + 'Libby', + 'Aditi', + 'Nalani', + 'Lilyanna', + 'Mylee', + 'Goldy', + 'Melia', + 'Audriana', + 'Lillyana', + 'Enriqueta', + 'Tasia', + 'Debbi', + 'Ani', + 'Elyssa', + 'Yamile', + 'Bridgett', + 'Taniya', + 'Britany', + 'Latosha', + 'Shanda', + 'Estephanie', + 'Maudie', + 'Mariyah', + 'Tana', + 'Neva', + 'Kalea', + 'Oma', + 'Jazelle', + 'Neveah', + 'Leonora', + 'Miesha', + 'Corrine', + 'Jordynn', + 'Cornelia', + 'Ronni', + 'Malinda', + 'Janeen', + 'Neriah', + 'Brigette', + 'Windy', + 'Cassondra', + 'Klarissa', + 'Lizzette', + 'Tanika', + 'Izamar', + 'Tera', + 'Arianny', + 'Florene', + 'Evalyn', + 'Poppy', + 'Deisy', + 'Jannette', + 'Thania', + 'Kelsea', + 'Taniyah', + 'Geri', + 'Allyssa', + 'Zariyah', + 'Averi', + 'Leeann', + 'Kallie', + 'Loni', + 'Bryleigh', + 'Rosina', + 'Carlee', + 'Preslee', + 'Alexsandra', + 'Adamari', + 'Saray', + 'Yaneli', + 'Raina', + 'Lianna', + 'Keilani', + 'Tamela', + 'Ninfa', + 'Ireland', + 'Shante', + 'Racheal', + 'Zainab', + 'Blima', + 'Yocheved', + 'Gema', + 'Sayra', + 'Aretha', + 'Nya', + 'Criselda', + 'Anai', + 'Bracha', + 'Amirah', + 'Sury', + 'Twila', + 'Arissa', + 'Livia', + 'Jacquline', + 'Chiara', + 'Anneliese', + 'Quiana', + 'Monika', + 'Charisse', + 'Emerie', + 'Rosalva', + 'Halie', + 'Jenesis', + 'Zaylee', + 'Pricilla', + 'Ouida', + 'Felipa', + 'Latifah', + 'Kalley', + 'Clarice', + 'Nona', + 'Jaunita', + 'Hermelinda', + 'Analy', + 'Jizelle', + 'Theda', + 'Yoselyn', + 'Dottie', + 'Brittaney', + 'Meghann', + 'Azeneth', + 'Richelle', + 'Peggie', + 'Brittny', + 'Jaci', + 'Marietta', + 'Gissell', + 'Evolet', + 'Abbygail', + 'Naima', + 'Noelani', + 'Jaslyn', + 'Katheryn', + 'Ruthann', + 'Shelva', + 'Ashli', + 'Alianna', + 'Felicitas', + 'Delfina', + 'Rayna', + 'Christal', + 'Leta', + 'Tawnya', + 'Zaniyah', + 'Cathie', + 'Antonette', + 'Bethann', + 'Nannette', + 'Vita', + 'Santa', + 'Dejah', + 'Patience', + 'Alessia', + 'Ahuva', + 'Karely', + 'Anette', + 'Alfreda', + 'Cyndi', + 'Cami', + 'Shirlee', + 'Roxann', + 'Alvina', + 'Sima', + 'Star', + 'Tatianna', + 'Krissy', + 'Dreama', + 'Diann', + 'Birdie', + 'Yoshiko', + 'Violette', + 'Mylah', + 'Rosita', + 'Eartha', + 'Miabella', + 'Shanika', + 'Gricel', + 'Ariyah', + 'Emmalee', + 'Nidia', + 'Gladis', + 'Roxie', + 'Zoraida', + 'Kandace', + 'Annamarie', + 'Alannah', + 'Abrielle', + 'Mercy', + 'Lesli', + 'Sydni', + 'Kathrine', + 'Jiselle', + 'Anisa', + 'Felisha', + 'Kayli', + 'Nanci', + 'Ria', + 'Cailyn', + 'Melani', + 'Alyna', + 'Bambi', + 'Avril', + 'Amberly', + 'Towanda', + 'Malissa', + 'Kaleena', + 'Kinsey', + 'Andria', + 'Emogene', + 'Milani', + 'Milah', + 'Hadassah', + 'Avianna', + 'Aubri', + 'Pessy', + 'Dori', + 'Tea', + 'Keshia', + 'Adina', + 'Esha', + 'Magnolia', + 'Moesha', + 'Elana', + 'Vikki', + 'Lakendra', + 'Ilse', + 'Sydnie', + 'Laquita', + 'Hortense', + 'Elouise', + 'Tarah', + 'Shamika', + 'Genoveva', + 'Margot', + 'Aubrielle', + 'Aya', + 'Aleta', + 'Shantell', + 'Angelle', + 'Lakeshia', + 'Leota', + 'Stormie', + 'Caryl', + 'Cristy', + 'Sydelle', + 'Analisa', + 'Earlene', + 'Syreeta', + 'Paityn', + 'Citlally', + 'Nikole', + 'Leandra', + 'Elda', + 'Lizbet', + 'Blimy', + 'Lorelai', + 'Gittel', + 'Jasmyn', + 'Verania', + 'Zoya', + 'Anyssa', + 'Jeniffer', + 'Dorene', + 'Makaila', + 'Earlean', + 'Ysabella', + 'Brandee', + 'Nailea', + 'Stefany', + 'Amiya', + 'Carolee', + 'Kassie', + 'Theodora', + 'Merissa', + 'Skylah', + 'Alesia', + 'Leela', + 'Madge', + 'Shanta', + 'Soledad', + 'Sharonda', + 'Thea', + 'Capri', + 'Amparo', + 'Concha', + 'Karolina', + 'Keitha', + 'Harriette', + 'Evette', + 'Mylie', + 'Isha', + 'Suzie', + 'Carlene', + 'Brunilda', + 'Annamae', + 'Ariadna', + 'Sanai', + 'Gisell', + 'Danelle', + 'Dovie', + 'Lani', + 'Shavonne', + 'Janiah', + 'Kora', + 'Jessa', + 'Melva', + 'Yehudis', + 'Analee', + 'Enedina', + 'Oaklee', + 'Aubrianna', + 'Velia', + 'Zooey', + 'Dolly', + 'Shanae', + 'Lyndsay', + 'Allene', + 'Kamya', + 'Tedra', + 'Yecenia', + 'Nyree', + 'Shyann', + 'Kandice', + 'Edwina', + 'Aiyanna', + 'Carli', + 'Sariyah', + 'Gwyneth', + 'Roseanna', + 'Charla', + 'Nereyda', + 'Yides', + 'Helaine', + 'Evita', + 'Alanis', + 'Starr', + 'Rosalee', + 'Yaire', + 'Risa', + 'Kristel', + 'Greidys', + 'Lillianna', + 'Khushi', + 'Triniti', + 'Lilyan', + 'Myesha', + 'Kala', + 'Moira', + 'Neida', + 'Gisel', + 'Myriam', + 'Anali', + 'Izabel', + 'Savana', + 'Sanjana', + 'Willodean', + 'Briza', + 'Lyra', + 'Merry', + 'Cheryle', + 'Porsha', + 'Kaili', + 'Buffy', + 'Deidra', + 'Everleigh', + 'Gardenia', + 'Italia', + 'Novella', + 'Sahara', + 'Sirena', + 'Elide', + 'Madisen', + 'Katerina', + 'Ashlea', + 'Rianna', + 'Samatha', + 'Diandra', + 'Shanell', + 'Annalee', + 'Samiyah', + 'Joselyne', + 'Maylin', + 'Jazmyne', + 'Terese', + 'Nydia', + 'Stasia', + 'Saira', + 'Carlota', + 'Kathia', + 'Katya', + 'Elodie', + 'Priya', + 'Malena', + 'Aadhya', + 'Meera', + 'Tayla', + 'Jovita', + 'Rafaela', + 'Faiga', + 'Jaquelyn', + 'Elisheva', + 'Debbra', + 'Melyssa', + 'Chelsi', + 'Gricelda', + 'Tawanda', + 'Sharlene', + 'Mellissa', + 'Alene', + 'Amayah', + 'Nicolle', + 'Yanet', + 'Zissy', + 'Candi', + 'Hedwig', + 'Leyna', + 'Nichol', + 'Reva', + 'Fraidy', + 'Esty', + 'Kaily', + 'Mimi', + 'Shani', + 'Hadlee', + 'Naomy', + 'Kinslee', + 'Emmalynn', + 'Alverta', + 'Anushka', + 'Tinsley', + 'Armida', + 'Cleta', + 'Analise', + 'Ahtziri', + 'Anakaren', + 'Tracee', + 'Glynda', + 'Kaelynn', + 'Carie', + 'Avalon', + 'Eboni', + 'Shameeka', + 'Letitia', + 'Enola', + 'Rasheeda', + 'Taylee', + 'Jerrica', + 'Janely', + 'Taya', + 'Xochilt', + 'Rosana', + 'Doretha', + 'Henny', + 'Shaniece', + 'Charleen', + 'Abigale', + 'Marylyn', + 'Retha', + 'Keren', + 'Elly', + 'Ailani', + 'Aarna', + 'Starla', + 'Maren', + 'Nan', + 'Marivel', + 'Georgianna', + 'Era', + 'Kirra', + 'Maisha', + 'Caydence', + 'Dinah', + 'Noemy', + 'Tamatha', + 'Madonna', + 'Kristan', + 'Keana', + 'Kloe', + 'Maribeth', + 'Sana', + 'Korina', + 'Irania', + 'Izabelle', + 'Roxy', + 'Mariaguadalupe', + 'Sulema', + 'Vivien', + 'Tatia', + 'Holli', + 'Debrah', + 'Kattie', + 'Kaidence', + 'Cathey', + 'Anniston', + 'Refugia', + 'Renita', + 'Aubriella', + 'Kaleah', + 'Zuleyka', + 'Sherie', + 'Tomika', + 'Charisma', + 'Caridad', + 'Kailynn', + 'Gertie', + 'Jaslynn', + 'Agatha', + 'Avani', + 'Hennessy', + 'Pamala', + 'Malak', + 'Raizel', + 'Kami', + 'Rosalina', + 'Ferne', + 'Cloe', + 'Jeryl', + 'Louann', + 'Jacie', + 'Tais', + 'Johnsie', + 'Brittnie', + 'Collette', + 'Lettie', + 'Jeanna', + 'Kyara', + 'Renada', + 'Abrianna', + 'Nayelli', + 'Alda', + 'Yuna', + 'Cristi', + 'Yazmine', + 'Marlie', + 'Milly', + 'Anastacia', + 'Daria', + 'Caitlynn', + 'Shriya', + 'Vianca', + 'Sayuri', + 'Dennise', + 'Aleyna', + 'Jenni', + 'Tanesha', + 'Suzanna', + 'Zaniya', + 'Kesha', + 'Edie', + 'Ansleigh', + 'Emmie', + 'Marjory', + 'Lanette', + 'Babette', + 'Alaya', + 'Palma', + 'Tamie', + 'Nelle', + 'Haydee', + 'Zeinab', + 'Stephania', + 'Biridiana', + 'Yoshie', + 'Mayme', + 'Michaele', + 'Marimar', + 'Winona', + 'Christene', + 'Meadow', + 'Ariya', + 'Daleysa', + 'Thuy', + 'Nautica', + 'Hadleigh', + 'Aliyana', + 'Annabell', + 'Stacia', + 'Leonore', + 'Albina', + 'Daira', + 'Rhona', + 'Lisbet', + 'Alizae', + 'Aminata', + 'Samanta', + 'Jerilyn', + 'Darci', + 'Sudie', + 'Kynleigh', + 'Marva', + 'Karie', + 'Marbella', + 'Franchesca', + 'Kylah', + 'Lillyanna', + 'Melony', + 'Abygail', + 'Yulianna', + 'Sahana', + 'Velvet', + 'Michelina', + 'Treva', + 'Iona', + 'Adilynn', + 'Milla', + 'Teressa', + 'Coretta', + 'Venita', + 'Evalynn', + 'Chynna', + 'Janett', + 'Nohemi', + 'Symone', + 'Kaycee', + 'Racquel', + 'Jerica', + 'Chanda', + 'Vannesa', + 'Deasia', + 'Alanah', + 'Dasha', + 'Dian', + 'Iyana', + 'Katlin', + 'Shizue', + 'Mitsuko', + 'Shara', + 'Shanelle', + 'Sinead', + 'Jacinda', + 'Alecia', + 'Tanvi', + 'Genese', + 'Crissy', + 'Niki', + 'Shanequa', + 'Trish', + 'Shalonda', + 'Darleen', + 'Magda', + 'Annalisa', + 'Lashanda', + 'Carin', + 'Nahomi', + 'Londynn', + 'Alaysia', + 'Annaliese', + 'Valorie', + 'Naidelyn', + 'Abbe', + 'Karley', + 'Cinda', + 'Marilu', + 'Azaria', + 'Kitty', + 'Mechelle', + 'Jazzmin', + 'Malina', + 'Cianna', + 'Leesa', + 'Nahla', + 'Dorotha', + 'Jaeda', + 'Tinley', + 'Kelis', + 'Ayesha', + 'Cinthya', + 'Shawnte', + 'Fawn', + 'Calleigh', + 'Mittie', + 'Aide', + 'Lisset', + 'Tyesha', + 'Devora', + 'Analeigh', + 'Anahy', + 'Donnamarie', + 'Nala', + 'Haruko', + 'Lesia', + 'Aideliz', + 'Emme', + 'Mitsue', + 'Jamiya', + 'Joleen', + 'Missy', + 'Shawanda', + 'Chastelyn', + 'Jaleah', + 'Eulalia', + 'Elvera', + 'Kalina', + 'Adrina', + 'Nicolasa', + 'Belia', + 'Elodia', + 'Kazuko', + 'Ixchel', + 'Leena', + 'Yoseline', + 'Yocelin', + 'Jamiyah', + 'Mariama', + 'Audrianna', + 'Dasia', + 'Ieshia', + 'Malorie', + 'Toniann', + 'Genessis', + 'Makeda', + 'Cherise', + 'Tarsha', + 'Karri', + 'Romayne', + 'Beronica', + 'Nubia', + 'Shasta', + 'Cristin', + 'Cristine', + 'Eryn', + 'Jazzmine', + 'Alyssia', + 'Verona', + 'Divya', + 'Beatrix', + 'Chiyoko', + 'Destinie', + 'Hali', + 'Myisha', + 'Sabina', + 'Chante', + 'Brea', + 'Aundrea', + 'Harmoni', + 'Iyanna', + 'Rosaria', + 'Hettie', + 'Bronte', + 'Constanza', + 'Heavenly', + 'Georgiana', + 'Coco', + 'Eleni', + 'Brylie', + 'Ajee', + 'Jerrie', + 'Zella', + 'Xenia', + 'Djuana', + 'Bianka', + 'Lizett', + 'Destany', + 'Bettina', + 'Pennie', + 'Ciji', + 'Ciani', + 'Tosha', + 'Roxane', + 'Tenisha', + 'Pepper', + 'Ayva', + 'Dynasty', + 'Krysten', + 'Maud', + 'Janene', + 'Yomaira', + 'Kizzie', + 'Oriana', + 'Antionette', + 'Kamille', + 'Candis', + 'Kimberlie', + 'Britta', + 'Malika', + 'Khalilah', + 'Louisa', + 'Maiya', + 'Shanay', + 'Kellye', + 'Gaye', + 'Rosangelica', + 'Breonna', + 'Jenae', + 'Kaylene', + 'Rileigh', + 'Linnea', + 'Tawanna', + 'Harleen', + 'Tamya', + 'Makaylah', + 'Annabeth', + 'Alysson', + 'Adella', + 'Adalee', + 'Karisa', + 'Rosangela', + 'Ema', + 'Dayra', + 'Tena', + 'Mathilda', + 'Magan', + 'Dayanira', + 'Annelise', + 'Takisha', + 'Rosamaria', + 'Shifra', + 'Vianna', + 'Daysi', + 'Jalissa', + 'Samaya', + 'Aubriana', + 'Alora', + 'Emmeline', + 'Elora', + 'Laylani', + 'Willene', + 'Cathrine', + 'Ginny', + 'Lashunda', + 'Mikalah', + 'Kiyoko', + 'Wynter', + 'Zuleima', + 'Alease', + 'Louella', + 'Jubilee', + 'Allegra', + 'Karmen', + 'Emiliana', + 'Jianna', + 'Eisley', + 'Emmaline', + 'Teresita', + 'Mackenna', + 'Lauretta', + 'Krystin', + 'Kalene', + 'Aviva', + 'Zena', + 'Shanique', + 'Glynis', + 'Toya', + 'Linsey', + 'Denisha', + 'Marysol', + 'Marcelina', + 'Makiyah', + 'Masako', + 'Cintia', + 'Sharen', + 'Lahoma', + 'Magen', + 'Alyvia', + 'Shaniyah', + 'Anamaria', + 'Shivani', + 'Hannia', + 'Chavy', + 'Hayleigh', + 'Jaycie', + 'Mayah', + 'Delila', + 'Danita', + 'Modesta', + 'Arcelia', + 'Deedee', + 'Monserrath', + 'Angelie', + 'Mellisa', + 'Leisa', + 'Melannie', + 'Mafalda', + 'Kinlee', + 'Annetta', + 'Freida', + 'Anisha', + 'Mayrin', + 'Dajah', + 'Delylah', + 'Hortensia', + 'Joretta', + 'Lexy', + 'Laysha', + 'Anessa', + 'Jesusita', + 'Pearline', + 'Caleigh', + 'Liset', + 'Leilene', + 'Jaya', + 'Haily', + 'Tatyanna', + 'Desire', + 'Lisha', + 'Mindi', + 'Ivelisse', + 'Amariah', + 'Blythe', + 'Treasure', + 'Latarsha', + 'Emelda', + 'Latavia', + 'Debanhi', + 'Brynleigh', + 'Gala', + 'Jurnee', + 'Joslynn', + 'Harleigh', + 'Trang', + 'Audree', + 'Brande', + 'Genea', + 'Carri', + 'Kandy', + 'Kenisha', + 'Georgene', + 'Kamora', + 'Anabell', + 'Meranda', + 'Renesmee', + 'Rosaura', + 'Linette', + 'Rosamond', + 'Candida', + 'Crista', + 'Keeley', + 'Mykayla', + 'Rina', + 'Jonna', + 'Lorinda', + 'Wynona', + 'Kylene', + 'Kellee', + 'Elayne', + 'Chela', + 'Zykeria', + 'Shawnna', + 'Jaimee', + 'Zuleyma', + 'Britnee', + 'Mikala', + 'Coletta', + 'Morelia', + 'Isadora', + 'Anayah', + 'Amiah', + 'Ailin', + 'Jordana', + 'Casie', + 'Shakia', + 'Cordelia', + 'Analeah', + 'Janelly', + 'Adelita', + 'Yoana', + 'Lizabeth', + 'Latoria', + 'Pricila', + 'Margaretta', + 'Fumiko', + 'Lura', + 'Toshiko', + 'Marge', + 'Luana', + 'Marilee', + 'Jeana', + 'Tallulah', + 'Zia', + 'Betsabe', + 'Delanie', + 'Jenicka', + 'Kensington', + 'Navya', + 'Golda', + 'Kambree', + 'Orpha', + 'Rayleigh', + 'Kinleigh', + 'Karleigh', + 'Avalynn', + 'Addilynn', + 'Cambree', + 'Brinlee', + 'Liba', + 'Zendaya', + 'Farah', + 'Oumou', + 'Aislinn', + 'Karena', + 'Erendira', + 'Mariaelena', + 'Temperance', + 'Angelic', + 'Khadija', + 'Jonelle', + 'Aniah', + 'Aleigha', + 'Samaria', + 'Dedra', + 'Sammantha', + 'Bernardine', + 'Leilanie', + 'Makaela', + 'Samiya', + 'Porsche', + 'Krystel', + 'Simona', + 'Catarina', + 'Joi', + 'Etty', + 'Jannat', + 'Rubie', + 'Waneta', + 'Shaquita', + 'Shaindel', + 'Alida', + 'January', + 'Riana', + 'Jamilet', + 'Jala', + 'Gearldine', + 'Iola', + 'Tiesha', + 'Ariyana', + 'Josslyn', + 'Verla', + 'Gerri', + 'Emili', + 'Jennyfer', + 'Halo', + 'Raya', + 'Asusena', + 'Jessalyn', + 'Anaiah', + 'Sabine', + 'Dorinda', + 'Andriana', + 'Charissa', + 'Cambrie', + 'Daija', + 'Danyelle', + 'Maricarmen', + 'Melania', + 'Glinda', + 'Jaretzy', + 'Keesha', + 'Lucie', + 'Persephone', + 'Veda', + 'Avalyn', + 'Odilia', + 'Teena', + 'Daisha', + 'Shianne', + 'Nadya', + 'Peighton', + 'Shawana', + 'Lateefah', + 'Geena', + 'Aixa', + 'Magdalene', + 'Estefana', + 'China', + 'Tamekia', + 'Audrie', + 'Angely', + 'Charline', + 'Britny', + 'Quanisha', + 'Erykah', + 'Kenzi', + 'Carleigh', + 'Kamiyah', + 'Zayra', + 'Abagail', + 'Sulay', + 'Shelita', + 'Cattleya', + 'Ariela', + 'Yalitza', + 'Marleigh', + 'Colbie', + 'Lavergne', + 'Pyper', + 'Tawni', + 'Kasie', + 'Kati', + 'Cinnamon', + 'Trana', + 'Verda', + 'Romana', + 'Merrily', + 'Landri', + 'Bruchy', + 'Irlanda', + 'Lanie', + 'Kendyl', + 'Sanvi', + 'Akshara', + 'Aneesa', + 'Giulia', + 'Ruchy', + 'Giulianna', + 'Zahara', + 'Sumaya', + 'Guillermina', + 'Araseli', + 'Jackelin', + 'Norine', + 'Ariane', + 'Naidelin', + 'Gwenyth', + 'Kya', + 'Liyah', + 'Danya', + 'Sujey', + 'Grayce', + 'Honey', + 'Assunta', + 'Aleksandra', + 'Almeda', + 'Devany', + 'Spring', + 'Patrica', + 'Delisa', + 'Fantasia', + 'Cydney', + 'Laquisha', + 'Lynsey', + 'Stephenie', + 'Cassaundra', + 'Elisabet', + 'Echo', + 'Juliann', + 'Micayla', + 'Iridiana', + 'Antonietta', + 'Rosaisela', + 'Bayleigh', + 'Candelaria', + 'Zaida', + 'Mercedez', + 'Kindra', + 'Malayah', + 'Stephaine', + 'Nayla', + 'Tameeka', + 'Kiesha', + 'Pooja', + 'Sahar', + 'Paisleigh', + 'Kynslee', + 'Idella', + 'Arelis', + 'Shizuko', + 'Leslee', + 'Acacia', + 'Elexis', + 'Violetta', + 'Sailor', + 'Marceline', + 'Una', + 'Kamilla', + 'Aulani', + 'Aracelis', + 'Kikue', + 'Kasi', + 'Elwanda', + 'Brookelyn', + 'Kellyann', + 'Shaquanna', + 'Marielle', + 'Isel', + 'Agustina', + 'Vergie', + 'Arriana', + 'Perel', + 'Maylee', + 'Navy', + 'Lanell', + 'Rosann', + 'Carmelita', + 'Deisi', + 'Alyza', + 'Nailah', + 'Somaya', + 'Kiarra', + 'Tatiyana', + 'Nelida', + 'Demetra', + 'Thais', + 'Syriana', + 'Nicki', + 'Tyanna', + 'Idaly', + 'Ramonita', + 'Zuzanna', + 'Aiza', + 'Larae', + 'Alyanna', + 'Aleyah', + 'Elayna', + 'Blaire', + 'Laniyah', + 'Rilynn', + 'Kandi', + 'Sherryl', + 'Marti', + 'Cherri', + 'Kimberli', + 'Carma', + 'Trena', + 'Darcie', + 'Evelyne', + 'Allissa', + 'Meliza', + 'Regine', + 'Adalina', + 'Siya', + 'Seraphina', + 'Calliope', + 'Jiya', + 'Talisa', + 'Mistie', + 'Ignacia', + 'Crysta', + 'Lona', + 'Voncile', + 'Rutha', + 'Kamiya', + 'Anslee', + 'Janya', + 'Berenise', + 'Sonji', + 'Yaeko', + 'Nika', + 'Queena', + 'Yatziri', + 'Aiko', + 'Lisamarie', + 'Evalina', + 'Alline', + 'Alejandrina', + 'Trula', + 'Hinda', + 'Delinda', + 'Brisia', + 'Aminah', + 'Mariella', + 'Nayzeth', + 'Sherlin', + 'Idalia', + 'Madaline', + 'Shenika', + 'Janaya', + 'Fabiana', + 'Aleeah', + 'Lasonya', + 'Jania', + 'Breindy', + 'Mitzy', + 'Yaquelin', + 'Tzipora', + 'Serene', + 'Mikaila', + 'Aicha', + 'Brucha', + 'Myrka', + 'Kaaren', + 'Meg', + 'Lise', + 'Suhani', + 'Liane', + 'Celisse', + 'Jasmyne', + 'Sharde', + 'Dannielle', + 'Crystle', + 'Jenniffer', + 'Shaneka', + 'Leslye', + 'Hedy', + 'Tashina', + 'Letisia', + 'Carys', + 'Antonetta', + 'Tamisha', + 'Kaniya', + 'Darline', + 'Alizay', + 'Minna', + 'Raelene', + 'Rebecka', + 'Martika', + 'Makiya', + 'Idalis', + 'Keasia', + 'Breeann', + 'Vlasta', + 'Ellianna', + 'Caelyn', + 'Kaytlin', + 'Cathi', + 'Jamia', + 'Tahnee', + 'Zulma', + 'Mallorie', + 'Katlynn', + 'Mahi', + 'Carleen', + 'Honesty', + 'Rasheedah', + 'Ronna', + 'Lissa', + 'Sherika', + 'Carolynn', + 'Romona', + 'Jamesha', + 'Shakiyla', + 'Mccall', + 'Joanie', + 'Makala', + 'Brionna', + 'Shaunna', + 'Hawa', + 'Marylin', + 'Baylie', + 'Preslie', + 'Aaralyn', + 'Pia', + 'Beatris', + 'Adria', + 'Arianne', + 'Carmina', + 'Sebrina', + 'Malani', + 'Lovely', + 'Jahaira', + 'Miyah', + 'Sylvie', + 'Cassi', + 'Kaniyah', + 'Cailin', + 'Santina', + 'Nariah', + 'Calandra', + 'Georgine', + 'Serafina', + 'Keyana', + 'Amethyst', + 'Tehya', + 'Avni', + 'Alessa', + 'Novalee', + 'Mayleen', + 'Aadya', + 'Jacquelynn', + 'Izetta', + 'Sumiko', + 'Irasema', + 'Annamaria', + 'Niya', + 'Latrina', + 'Cicely', + 'Kristiana', + 'Kimiko', + 'Keara', + 'Mazie', + 'Najah', + 'Evelia', + 'Tiarra', + 'Jaela', + 'Montine', + 'Mandie', + 'Lavada', + 'Dimple', + 'Emiko', + 'Yocelyn', + 'Issabella', + 'Rowena', + 'Tanja', + 'Velda', + 'Chantell', + 'Gretel', + 'Jacelyn', + 'Kambri', + 'Zayla', + 'Anasofia', + 'Atiana', + 'Dulcemaria', + 'Zulay', + 'Tari', + 'Sahasra', + 'Rayleen', + 'Greydis', + 'Shiela', + 'Florinda', + 'Samya', + 'Shakima', + 'Shakeema', + 'Yanely', + 'Lavina', + 'Azalee', + 'Oneta', + 'Tammye', + 'Kelsy', + 'Kalie', + 'Keanna', + 'Daniya', + 'Antonina', + 'Katharin', + 'Tiare', + 'Yorley', + 'Jeslyn', + 'Emeli', + 'Zakia', + 'Massiel', + 'Latesha', + 'Jenessa', + 'Jayna', + 'Raylynn', + 'Ainslee', + 'Aralynn', + 'Khloee', + 'Ily', + 'Emeri', + 'Jeni', + 'Kassi', + 'Nakita', + 'Lakia', + 'Ariyanna', + 'Addalyn', + 'Keyanna', + 'Bibiana', + 'Genna', + 'Kathya', + 'Leana', + 'Trane', + 'Yomira', + 'Brigid', + 'Dionna', + 'Jerilynn', + 'Sarita', + 'Altha', + 'Laniya', + 'Zakiya', + 'Akilah', + 'Celestina', + 'Priyanka', + 'Taliah', + 'Donya', + 'Soila', + 'Quetzalli', + 'Cristel', + 'Naia', + 'Kailah', + 'Zitlaly', + 'Tonda', + 'Cate', + 'Lizzet', + 'Vesta', + 'Sherilyn', + 'Teruko', + 'Aldona', + 'Armandina', + 'Ciana', + 'Amairany', + 'Elysia', + 'Samarah', + 'Janyla', + 'Skylee', + 'Rolanda', + 'Sapphire', + 'Setsuko', + 'Miyoko', + 'Contina', + 'Imogen', + 'Jailine', + 'Vanellope', + 'Leora', + 'Jennah', + 'Perl', + 'Analiyah', + 'Hellen', + 'Tyasia', + 'Symphony', + 'Amada', + 'Otilia', + 'Avigail', + 'Tzivia', + 'Fradel', + 'Mariadelcarmen', + 'Ilona', + 'Dyan', + 'Zahraa', + 'Patrisia', + 'Jersey', + 'Lilla', + 'Lossie', + 'Somer', + 'Deserie', + 'Jaila', + 'Briseis', + 'Aniston', + 'Idell', + 'Raeleigh', + 'Gracyn', + 'Everlee', + 'Laurene', + 'Sherita', + 'Pinkie', + 'Nakisha', + 'Olevia', + 'Corene', + 'Loreen', + 'Sandie', + 'Keosha', + 'Kenleigh', + 'Alli', + 'Alyana', + 'Prisha', + 'Brookelynn', + 'Thaily', + 'Maddie', + 'Grettel', + 'Kinzley', + 'Jailynn', + 'Kalli', + 'Jazzlynn', + 'Klaudia', + 'Blanch', + 'Mariafernanda', + 'Makenzi', + 'Shonna', + 'Lita', + 'Karima', + 'Rebeccah', + 'Isaura', + 'Kalee', + 'Jori', + 'Allysa', + 'Tonisha', + 'Neda', + 'Jenine', + 'Chanell', + 'Jamaya', + 'Lorrayne', + 'Birtha', + 'Kanisha', + 'Nicollette', + 'Desiray', + 'Kaity', + 'Shamya', + 'Kathlene', + 'Jann', + 'Sari', + 'Lucila', + 'Tressie', + 'Charise', + 'Kalista', + 'Jamileth', + 'Kalena', + 'Sakura', + 'Blondell', + 'Thomasina', + 'Aila', + 'Mossie', + 'Tamala', + 'Siri', + 'Gertha', + 'Reta', + 'Easter', + 'Tala', + 'Vivianne', + 'Nila', + 'Merida', + 'Ahana', + 'Lanelle', + 'Hilaria', + 'Arlys', + 'Inell', + 'Rylynn', + 'Cosette', + 'Penne', + 'Jenevieve', + 'Jenilee', + 'Carlotta', + 'Ziva', + 'Hildegard', + 'Aleshia', + 'Nedra', + 'Madelaine', + 'Lisandra', + 'Pang', + 'Sindy', + 'Zenaida', + 'Lulu', + 'Shanya', + 'Shakema', + 'Katiria', + 'Raffaela', + 'Solange', + 'Illiana', + 'Chelsy', + 'Shanee', + 'Adriene', + 'Tyla', + 'Cailey', + 'Daijah', + 'Melonie', + 'Courteney', + 'Deysi', + 'Makinley', + 'Brynna', + 'Hildegarde', + 'Fiorella', + 'Kenadee', + 'Ellyn', + 'Ebonie', + 'Thu', + 'Charde', + 'Kaytlyn', + 'Kenadie', + 'Georgeann', + 'Analicia', + 'Emalee', + 'Shatara', + 'Lucerito', + 'Mckell', + 'Atiya', + 'Stormi', + 'Maleny', + 'Nariyah', + 'Steffanie', + 'Kirstyn', + 'Zayda', + 'Mariadejesus', + 'Deeann', + 'Abcde', + 'Eleanora', + 'Pearle', + 'Seana', + 'Denine', + 'Presleigh', + 'Keziah', + 'Queenie', + 'Henchy', + 'Merari', + 'Joscelyn', + 'Celest', + 'Mirel', + 'Sania', + 'Maryah', + 'Angelena', + 'Emelyn', + 'Gissele', + 'Fanta', + 'Gaylene', + 'Adelaida', + 'Madie', + 'Maja', + 'Nashaly', + 'Christel', + 'Rachele', + 'Raniyah', + 'Rashel', + 'Kavya', + 'Callista', + 'Elmira', + 'Rifky', + 'Syeda', + 'Tresa', + 'Detra', + 'Jarely', + 'Prisila', + 'Enedelia', + 'Trany', + 'Lainie', + 'Yisel', + 'Alynna', + 'Allysson', + 'Tamica', + 'Velva', + 'Nancee', + 'Breleigh', + 'Shanita', + 'Orelia', + 'Patrici', + 'Daja', + 'Shardae', + 'Abriana', + 'Halee', + 'Dorcas', + 'Kathey', + 'Rosia', + 'Princesa', + 'Lezly', + 'Dawnmarie', + 'Gaby', + 'Ania', + 'Denae', + 'Jahzara', + 'Jaymie', + 'Bari', + 'Suzann', + 'Alnisa', + 'Fatimah', + 'Zakiyyah', + 'Yana', + 'Naimah', + 'Tyisha', + 'Kathaleen', + 'Sameerah', + 'Chesney', + 'Shanteria', + 'Pamella', + 'Rayven', + 'Romelia', + 'Lucretia', + 'Tova', + 'Aura', + 'Chelsee', + 'Roizy', + 'Manha', + 'Nisha', + 'Tierney', + 'Girl', + 'Taelor', + 'Litzi', + 'Sneha', + 'Natisha', + 'Alliyah', + 'Sully', + 'Twyla', + 'Daisey', + 'Sarahy', + 'Shemeka', + 'Lexis', + 'Shalanda', + 'Kelcie', + 'Natacha', + 'Amyah', + 'Byanka', + 'Kymberly', + 'Navil', + 'Britani', + 'Karolyn', + 'Emelie', + 'Zana', + 'Vernita', + 'Leigha', + 'Romy', + 'Arlet', + 'Jazlin', + 'Laynie', + 'Jesslyn', + 'Adilyn', + 'Karoline', + 'Nyomi', + 'Maycee', + 'Nicol', + 'Daliah', + 'Lillyann', + 'Shawnda', + 'Dede', + 'Wiktoria', + 'Liah', + 'Liya', + 'Emmerson', + 'Aarohi', + 'Aribella', + 'Brayleigh', + 'Sumie', + 'Elke', + 'Taja', + 'Ahsley', + 'Tisa', + 'Dannette', + 'Gidget', + 'Misao', + 'Adelle', + 'Jamiah', + 'Joselynn', + 'Jalyssa', + 'Marnita', + 'Trinitee', + 'Bev', + 'Aleida', + 'Cloey', + 'Tahlia', + 'Melodee', + 'Anaiya', + 'Clover', + 'Prudence', + 'Kalynn', + 'Dezirae', + 'Solana', + 'Reena', + 'Mariko', + 'Tiffiny', + 'Elinore', + 'Madelyne', + 'Anela', + 'Bess', + 'Perri', + 'Loree', + 'Cyndy', + 'Yolonda', + 'Jolee', + 'Tequila', + 'Sumer', + 'Cherilyn', + 'Ela', + 'Kenlee', + 'Alexxis', + 'Larisa', + 'Nevaeha', + 'Nira', + 'Shaquasia', + 'Shanel', + 'Medina', + 'Rifka', + 'Sable', + 'Atara', + 'Aissatou', + 'Mecca', + 'Anastasi', + 'Falon', + 'Holley', + 'Yuliza', + 'Lili', + 'Siara', + 'Kiarah', + 'Tiffaney', + 'Alyah', + 'Annalia', + 'Naila', + 'Analiah', + 'Aymar', + 'Tambra', + 'Elna', + 'Eola', + 'Tkeyah', + 'Zola', + 'Francheska', + 'Aidee', + 'Alexzandra', + 'Cianni', + 'Myasia', + 'Carisa', + 'Ilah', + 'Yenifer', + 'Veronika', + 'Nahomy', + 'Madysen', + 'Elsy', + 'Lilli', + 'Belva', + 'Steffie', + 'Kaylea', + 'Ginamarie', + 'Sharman', + 'Latia', + 'Shakeria', + 'Audelia', + 'Odette', + 'Shaniah', + 'Diamantina', + 'Lorayne', + 'Ciarra', + 'Wilhelmena', + 'Zaina', + 'Niesha', + 'Kanesha', + 'Turquoise', + 'Tziporah', + 'Timi', + 'Fatou', + 'Karna', + 'Matsue', + 'Vina', + 'Ronisha', + 'Layan', + 'Viktoria', + 'Lilyann', + 'Maliya', + 'Jamilex', + 'Epifania', + 'Fidela', + 'Delphia', + 'Starasia', + 'Glennie', + 'Teodora', + 'Hatsue', + 'Margarett', + 'Margarette', + 'Laronda', + 'Vicenta', + 'Cotina', + 'Meilani', + 'Mannat', + 'Leylani', + 'Lailani', + 'Seerat', + 'Reya', + 'Amilia', + 'Avary', + 'Brocha', + 'Daneen', + 'Kimie', + 'Trudi', + 'Margret', + 'Djuna', + 'Charis', + 'Izzabella', + 'Brionne', + 'Elenora', + 'Lakeitha', + 'Jacki', + 'Beckie', + 'Guinevere', + 'Inara', + 'Landrie', + 'Nicoletta', + 'Ayari', + 'Zaniah', + 'Merlene', + 'Keli', + 'Maricella', + 'Leonela', + 'Donita', + 'Tehani', + 'Susannah', + 'Journi', + 'Machelle', + 'Tammara', + 'Cherrie', + 'Nelva', + 'Destanie', + 'Neyda', + 'Tabetha', + 'Wilhelmenia', + 'Brieanna', + 'Turkessa', + 'Ameera', + 'Avital', + 'Marycruz', + 'Zoila', + 'Tressa', + 'Joellen', + 'Raisa', + 'Bethanie', + 'Ermelinda', + 'Asiyah', + 'Monifa', + 'Samia', + 'Adamary', + 'Anahit', + 'Rania', + 'Miri', + 'Ether', + 'Desirea', + 'Chimere', + 'Erla', + 'Karisma', + 'Nalleli', + 'Larhonda', + 'Darlyn', + 'Anaisa', + 'Suellen', + 'Kamaria', + 'Nashla', + 'Yuriko', + 'Tzirel', + 'Tehila', + 'Myriah', + 'Frimet', + 'Cesilia', + 'Marika', + 'Frady', + 'Deloise', + 'Saleen', + 'Betsey', + 'Merri', + 'Laurette', + 'Sharita', + 'Shena', + 'Porscha', + 'Aerial', + 'Florrie', + 'Ayah', + 'Anusha', + 'Jeanelle', + 'Lessly', + 'Mahogany', + 'See', + 'Hang', + 'Karinna', + 'Leighann', + 'Elexus', + 'Markayla', + 'Kaneesha', + 'Barbie', + 'Aurea', + 'Kaeli', + 'Arwen', + 'Angelyn', + 'Jaclynn', + 'Tesla', + 'Maritsa', + 'Madelin', + 'Alisia', + 'Tyana', + 'Kimberlyn', + 'Dejanae', + 'Dalena', + 'Blessing', + 'Courtnie', + 'Amaria', + 'Micki', + 'Safa', + 'Jadah', + 'Mele', + 'Maryssa', + 'Channel', + 'Lianne', + 'Alea', + 'Chyanne', + 'Addelyn', + 'Aaleyah', + 'Michela', + 'Torri', + 'Indira', + 'Kanani', + 'Lashundra', + 'Mikaylah', + 'Zoee', + 'Taelyn', + 'Noheli', + 'Sarena', + 'Dariela', + 'Adalie', + 'Meggan', + 'Daniyah', + 'Sela', + 'Shaelyn', + 'Maylen', + 'Giovana', + 'Ayvah', + 'Arabelle', + 'Adaline', + 'Isyss', + 'Melanny', + 'Margaux', + 'Klara', + 'Janey', + 'Idolina', + 'Georgetta', + 'Amaiya', + 'Sianna', + 'Rebeka', + 'Meleny', + 'Kelle', + 'Angelika', + 'Malerie', + 'Latara', + 'Niamh', + 'Yevette', + 'Yomayra', + 'Karizma', + 'Nayelie', + 'Shantal', + 'Latoyia', + 'Jenee', + 'Shandra', + 'Magdalen', + 'Yatzari', + 'Jettie', + 'Charlsie', + 'Idy', + 'Inaya', + 'Yitta', + 'Reem', + 'Basya', + 'Skylynn', + 'Elyana', + 'Brynley', + 'Amor', + 'Amberlee', + 'Eternity', + 'Niyah', + 'Emiley', + 'Madeleyn', + 'Korie', + 'Sanaya', + 'Meira', + 'Chevonne', + 'Sabra', + 'Uma', + 'Kaira', + 'Isobel', + 'Elli', + 'Gurleen', + 'Berneice', + 'Alvera', + 'Ambrosia', + 'Roya', + 'Bettyann', + 'Alverda', + 'Tinamarie', + 'Tanasia', + 'Lavonda', + 'Jorja', + 'Heide', + 'Marwa', + 'Annaly', + 'Aaliah', + 'Ileen', + 'Lamonica', + 'Enjoli', + 'Ninel', + 'Milissa', + 'Dawne', + 'Joie', + 'Ashlei', + 'Elidia', + 'Maybelle', + 'Getsemani', + 'Gisella', + 'Mariya', + 'Adisyn', + 'Adia', + 'Caterina', + 'Bettyjane', + 'Kaydee', + 'Rasheda', + 'Camisha', + 'Chassidy', + 'Sadia', + 'Aislyn', + 'Ngoc', + 'Mirka', + 'Lanita', + 'Lashawnda', + 'Liridona', + 'Tynisa', + 'Arnelle', + 'Librada', + 'Marita', + 'Makyla', + 'Raniya', + 'Kandis', + 'Ethelyn', + 'Divina', + 'Genevie', + 'Jadelyn', + 'Ashleen', + 'Saya', + 'Marli', + 'Calli', + 'Anyla', + 'Sheng', + 'Vasiliki', + 'Yelena', + 'Darya', + 'Clarabelle', + 'Shirlene', + 'Tommye', + 'Julieann', + 'Jennefer', + 'Rana', + 'Raeann', + 'Suleima', + 'Lilyanne', + 'Jelisa', + 'Jaymee', + 'Rhylee', + 'Keyli', + 'Brooklin', + 'Meta', + 'Shakirah', + 'Loria', + 'Sharyl', + 'Sharday', + 'Manuelita', + 'Debera', + 'Lera', + 'Jacquie', + 'Ardella', + 'Jameria', + 'Winnifred', + 'Rossana', + 'Shemika', + 'Sedona', + 'Arvilla', + 'Samaira', + 'Aitana', + 'Daiana', + 'Cassia', + 'Lucianna', + 'Tama', + 'Shigeko', + 'Sueko', + 'Hatsuko', + 'Hazle', + 'Lida', + 'Wylene', + 'Sachiko', + 'Tahiry', + 'Renea', + 'Janina', + 'Becki', + 'Vy', + 'Cherryl', + 'Arionna', + 'Marrissa', + 'Randee', + 'Norita', + 'Sonali', + 'Susann', + 'Rachell', + 'Natashia', + 'Aspyn', + 'Malaika', + 'Nuvia', + 'Safiya', + 'Contessa', + 'Julyssa', + 'Analiese', + 'Jacee', + 'Kathlyn', + 'Gracey', + 'Chassity', + 'Kady', + 'Tytiana', + 'Katiana', + 'Eneida', + 'Teela', + 'Roiza', + 'Alaura', + 'Giuseppina', + 'Randa', + 'Danisha', + 'Mariza', + 'Marquisha', + 'Sharese', + 'Deseree', + 'Inaaya', + 'Rivkah', + 'Tawnie', + 'Miriah', + 'Shereen', + 'Candra', + 'Tomiko', + 'Whittney', + 'Aziza', + 'Ayala', + 'Hafsa', + 'Zaynab', + 'Kaileigh', + 'Yarima', + 'Danitza', + 'Maram', + 'Shakeya', + 'Emmer', + 'Kareema', + 'Maayan', + 'Rheanna', + 'Jaritza', + 'Marleny', + 'Zitlali', + 'Vanity', + 'Apryl', + 'Zully', + 'Tashia', + 'Courtnee', + 'Laporsha', + 'Luvenia', + 'Batya', + 'Ayelet', + 'Quetcy', + 'Tiny', + 'Felicita', + 'Omaira', + 'Nyssa', + 'Krystine', + 'Stevi', + 'Michiko', + 'Tennie', + 'Tomekia', + 'Billiejo', + 'Yohana', + 'Krystyna', + 'Kacee', + 'Naja', + 'Charmayne', + 'Twana', + 'Jeane', + 'Brittnay', + 'Cherelle', + 'Raechel', + 'Temeka', + 'Jasmeen', + 'Zuria', + 'Zailey', + 'Saydee', + 'Renatta', + 'Neta', + 'Bg', + 'Italy', + 'Terrica', + 'Goldia', + 'Monae', + 'Yelitza', + 'Ryanne', + 'Samirah', + 'Breckyn', + 'Nicolina', + 'Olympia', + 'Almeta', + 'Tamesha', + 'Zora', + 'Emmaleigh', + 'Loralei', + 'Kennadi', + 'Julieanna', + 'Jenavieve', + 'Shylah', + 'Akemi', + 'Fonda', + 'Nizhoni', + 'Iqra', + 'Gaetana', + 'Coreen', + 'Evonne', + 'Sadako', + 'Angele', + 'Macel', + 'Alinna', + 'Avneet', + 'Jannah', + 'Nickole', + 'Lotus', + 'Yukie', + 'Laiyah', + 'Kynzlee', + 'Mailen', + 'Nobuko', + 'Annaleigh', + 'Otila', + 'Shona', + 'Kimberely', + 'Delcie', + 'Zula', + 'Roselynn', + 'Aleeyah', + 'Bellarose', + 'Damya', + 'Cammie', + 'Treena', + 'Chanie', + 'Kaliah', + 'Abella', + 'Aahana', + 'Mileena', + 'Adaleigh', + 'Keiry', + 'Journie', + 'Myrtie', + 'Tsuruko', + 'Lyda', + 'Fernande', + 'Julee', + 'Estephany', + 'Louvenia', + 'Monserat', + 'Meena', + 'Jayline', + 'Brie', + 'Elicia', + 'Suzana', + 'Dusti', + 'Odile', + 'Hilma', + 'Katarzyna', + 'Jenise', + 'Hiromi', + 'Huong', + 'Deolinda', + 'Pamelia', + 'Awa', + 'Odelia', + 'Mattison', + 'Gwenda', + 'Sera', + 'Yuritzi', + 'Karishma', + 'Kaina', + 'Henna', + 'Norene', + 'Brina', + 'Chyenne', + 'Moncerrat', + 'Keilah', + 'Saphira', + 'Marylee', + 'Meri', + 'Lajuana', + 'Lindsy', + 'Shanise', + 'Sugey', + 'Jaimi', + 'Viki', + 'Ceola', + 'Naiya', + 'Adysen', + 'Shantavia', + 'Amberlyn', + 'Brihanna', + 'Laela', + 'Kenadi', + 'Hermine', + 'Bernita', + 'Deziree', + 'Anja', + 'Lawana', + 'Aletha', + 'Nella', + 'Irelyn', + 'Jakira', + 'Wynema', + 'Janai', + 'Keondra', + 'Venice', + 'Zenobia', + 'Jaelene', + 'Ammy', + 'Alizah', + 'Lakiesha', + 'Azure', + 'Aysha', + 'Saniah', + 'Mahnoor', + 'Ananda', + 'Asma', + 'Aissata', + 'Jaileen', + 'Yailin', + 'Xiana', + 'Laiza', + 'Liseth', + 'Marykate', + 'Daizy', + 'Neoma', + 'Tykeria', + 'Shamiya', + 'Nykeria', + 'Addalynn', + 'Kenzley', + 'Ardyce', + 'Anylah', + 'Vallie', + 'Darlyne', + 'Makiah', + 'Neela', + 'Naraly', + 'Danni', + 'Jolina', + 'Ailene', + 'Lyndia', + 'Erminia', + 'Asiya', + 'Alexius', + 'Mc', + 'Maylene', + 'Signe', + 'Adelfa', + 'Yusra', + 'Keyonna', + 'Yasuko', + 'Yukiko', + 'Augustina', + 'Leen', + 'Fumie', + 'Amora', + 'Annaleah', + 'Anvi', + 'Indie', + 'Haya', + 'Emmarie', + 'Enya', + 'Chieko', + 'Kinsleigh', + 'Shiann', + 'Eufemia', + 'Fusae', + 'Akiko', + 'Hosanna', + 'Alitzel', + 'Araya', + 'Anaiyah', + 'Rosy', + 'Nishka', + 'Gao', + 'Tamiya', + 'Lillyan', + 'Eudelia', + 'Kamea', + 'Berlyn', + 'Kahlan', + 'Alinah', + 'Mahealani', + 'Leeah', + 'Rosalynn', + 'Zadie', + 'Aolanis', + 'Esta', + 'Maisy', + 'Chevelle', + 'Jalayah', + 'Yatziry', + 'Alyne', + 'Jodell', + 'Sariya', + 'Yashica', + 'Jissel', + 'Letty', + 'Mariaisabel', + 'Lizzeth', + 'Yovana', + 'Dyanna', + 'Tamyra', + 'Monzerrat', + 'Seanna', + 'Eldora', + 'Mattea', + 'Zahira', + 'Jeanetta', + 'Aysia', + 'Ashlin', + 'Tenika', + 'Lezlie', + 'Kailie', + 'Jariyah', + 'Jovie', + 'Kiyah', + 'Lynlee', + 'Abriella', + 'Adleigh', + 'Ranada', + 'Vertie', + 'Flonnie', + 'Kynnedi', + 'Lya', + 'Acelynn', + 'Emalyn', + 'Emberly', + 'Yalexa', + 'Izabela', + 'Sadye', + 'Kamyla', + 'Jayleigh', + 'Cayleigh', + 'Ceil', + 'Inger', + 'Cindee', + 'Nena', + 'Loan', + 'Kiya', + 'Laure', + 'Cristen', + 'Celenia', + 'Fredda', + 'Ravyn', + 'Mee', + 'Graci', + 'Azalia', + 'Latina', + 'Hassie', + 'Dinorah', + 'Virna', + 'Autum', + 'Michala', + 'Macayla', + 'Franca', + 'Corissa', + 'Alysse', + 'Monisha', + 'Jessyca', + 'Nisa', + 'Jacqulyn', + 'Makaylee', + 'Ellin', + 'Jameelah', + 'Shalon', + 'Jlynn', + 'Kennady', + 'Brinkley', + 'Providence', + 'Phylis', + 'Eugenie', + 'Clementina', + 'Kadynce', + 'Yuvia', + 'Mailyn', + 'Taneisha', + 'Samone', + 'Aurore', + 'Brienne', + 'Tritia', + 'Fayth', + 'Jayci', + 'Jorie', + 'Loreal', + 'Taylar', + 'Maryn', + 'Melissia', + 'Midori', + 'Hisako', + 'Hulda', + 'Bobbijo', + 'Bulah', + 'Nancye', + 'Melvina', + 'Sherree', + 'Kierstin', + 'Merrilee', + 'Lonna', + 'Judyth', + 'Nancie', + 'Lark', + 'Candyce', + 'Kadejah', + 'Kenda', + 'Fara', + 'Estephania', + 'Cady', + 'Marilin', + 'Kadie', + 'Suleyma', + 'Jacquelyne', + 'Vonetta', + 'Tanairi', + 'Charlott', + 'Shannel', + 'Zenia', + 'Alise', + 'Takara', + 'Lyndsie', + 'Ivett', + 'Letisha', + 'Idania', + 'Lacee', + 'Candie', + 'Camelia', + 'Brittanee', + 'Mariaeduarda', + 'Geovanna', + 'Kirsti', + 'Michaella', + 'Kelsee', + 'Cheryll', + 'Cyrstal', + 'Keriann', + 'Latrisha', + 'Exie', + 'Deborha', + 'Verdie', + 'Zahava', + 'Zuleika', + 'Dorla', + 'Dominiqu', + 'Sharina', + 'Ardeth', + 'Alethia', + 'Starlene', + 'Shamira', + 'Shantelle', + 'Marilou', + 'Kyah', + 'Kyana', + 'Clemencia', + 'Cordie', + 'Meagen', + 'Xitlalic', + 'Gaia', + 'Ellia', + 'Elani', + 'Jaylani', + 'Krisha', + 'Khalia', + 'Aaradhya', + 'Aeris', + 'Avamarie', + 'Artemis', + 'Sheana', + 'Jolynn', + 'Sandee', + 'Wendie', + 'Willia', + 'Loriene', + 'Apolonia', + 'Eusebia', + 'Kazue', + 'Synthia', + 'Harue', + 'Siomara', + 'Nhi', + 'Maleni', + 'Toyoko', + 'Freeda', + 'Hideko', + 'Sherrye', + 'Bethanne', + 'Merrie', + 'Peri', + 'Ozella', + 'Venetia', + 'Revonda', + 'Breauna', + 'Arika', + 'Annissa', + 'Leeza', + 'Siera', + 'Jakiyah', + 'Kamaya', + 'Lashay', + 'Elvina', + 'Laquinta', + 'Faren', + 'Harmonie', + 'Brianny', + 'Jama', + 'Johna', + 'Sharalyn', + 'Aziyah', + 'Hadassa', + 'Shantinique', + 'Treasa', + 'Penni', + 'Shakera', + 'Carolyne', + 'Shaunda', + 'Talya', + 'Karyna', + 'Natosha', + 'Vivica', + 'Pauletta', + 'Laverna', + 'Danasia', + 'Shakita', + 'Sharee', + 'Yajayra', + 'Karlene', + 'Reatha', + 'Laiba', + 'Zamiyah', + 'Shirleen', + 'Bettylou', + 'Nakiya', + 'Eryka', + 'Bailie', + 'Janiece', + 'Keisa', + 'Kiah', + 'Jennica', + 'Niasia', + 'Hildy', + 'Jacquel', + 'Mahina', + 'Eshal', + 'Khloey', + 'Emelin', + 'Eesha', + 'Kaylei', + 'Aymee', + 'Alona', + 'Catelyn', + 'Arushi', + 'Ameerah', + 'Regenia', + 'Brailey', + 'Sparkle', + 'Giavonna', + 'Ashunti', + 'Naudia', + 'Kyrsten', + 'Emmalina', + 'Neve', + 'Aolani', + 'Gizella', + 'Tameika', + 'Leocadia', + 'Nidhi', + 'Wende', + 'Eshaal', + 'Cherice', + 'Lakeysha', + 'Menucha', + 'Ameena', + 'Kloey', + 'Nayelly', + 'Kathryne', + 'Lashawna', + 'Kristle', + 'Zaylie', + 'Keylee', + 'Landree', + 'Wynell', + 'Dezarae', + 'Angelli', + 'Haddie', + 'Ilyana', + 'Jaleigh', + 'Brilee', + 'Lakeya', + 'Kanika', + 'Lavinia', + 'Marykay', + 'Ruthanne', + 'Tenille', + 'Dorine', + 'Esabella', + 'Genavieve', + 'Zarah', + 'Mileidy', + 'Solara', + 'Yamila', + 'Amaia', + 'Season', + 'Cheree', + 'Luise', + 'Tracye', + 'Christeen', + 'Florida', + 'Breona', + 'Kathe', + 'Jakyra', + 'Zury', + 'Lakeesha', + 'Yaneth', + 'Keandra', + 'Agnieszka', + 'Markita', + 'Mariska', + 'Zada', + 'Breasia', + 'Aaniyah', + 'Kambria', + 'Lilit', + 'Sheilah', + 'Cherisse', + 'Hermione', + 'Angeli', + 'Britnie', + 'Lisett', + 'Joette', + 'Nga', + 'Ruthe', + 'Anamarie', + 'Mayeli', + 'Takia', + 'Lien', + 'Tenaya', + 'Kera', + 'Meah', + 'Mei', + 'Anoushka', + 'Annalyse', + 'Persia', + 'Sheccid', + 'Kyndra', + 'Susy', + 'Steffany', + 'Jennavecia', + 'Briannah', + 'Kynlie', + 'Alexxa', + 'Paizlee', + 'Jesika', + 'Kinzlee', + 'Ishani', + 'Freyja', + 'Julietta', + 'Raynette', + 'Nely', + 'Zayleigh', + 'Amberlynn', + 'Journei', + 'Eimy', + 'Delany', + 'Emarie', + 'Brilynn', + 'Audri', + 'Abilene', + 'Saoirse', + 'Naveah', + 'Ayelen', + 'Emeline', + 'Loryn', + 'Mykaela', + 'Skarlett', + 'Tionne', + 'Rashelle', + 'Jerline', + 'Ofilia', + 'Rufina', + 'Phillis', + 'Jenica', + 'Dineen', + 'Glory', + 'Camellia', + 'Alane', + 'Angelyna', + 'Amalie', + 'Kina', + 'Kateri', + 'Neyva', + 'Malisa', + 'Saida', + 'Jerika', + 'Bayli', + 'Crystale', + 'Silvana', + 'Inga', + 'Lyndi', + 'Leeanna', + 'Cheyanna', + 'Fayrene', + 'Torie', + 'Latashia', + 'Baleigh', + 'Fidencia', + 'Rori', + 'Lorianne', + 'Catrice', + 'Cherrelle', + 'Lashaunda', + 'Sammi', + 'Thomasena', + 'Roshanda', + 'Alazae', + 'Enza', + 'Mairead', + 'Pandora', + 'Kortni', + 'Timber', + 'Chasidy', + 'Danesha', + 'Camry', + 'Charlette', + 'Kaneshia', + 'Shadae', + 'Keturah', + 'Randye', + 'Kiyana', + 'Charlean', + 'Delana', + 'Tomasita', + 'Lilliam', + 'Bibi', + 'Marguita', + 'Maryalice', + 'Iraida', + 'Tyhessia', + 'Makeba', + 'Tanaya', + 'Keiara', + 'Madlyn', + 'Jelissa', + 'Shakayla', + 'Mickayla', + 'Aleisha', + 'Keyara', + 'Mekayla', + 'Mykala', + 'Riva', + 'Inaara', + 'Paulita', + 'Lashae', + 'Destynee', + 'Christianna', + 'Rise', + 'Larraine', + 'Luetta', + 'Merna', + 'Francena', + 'Diedre', + 'Georgiann', + 'Rubbie', + 'Denita', + 'Dyani', + 'Laticia', + 'Ludivina', + 'Suanne', + 'Hareem', + 'Nava', + 'Florie', + 'Sherly', + 'Vidhi', + 'Camie', + 'Sharell', + 'Chole', + 'Jolin', + 'Polina', + 'Brittiany', + 'Delicia', + 'Brystol', + 'Beaulah', + 'Leatha', + 'Jamilah', + 'Zona', + 'Elliette', + 'Joye', + 'Aashi', + 'Kerriann', + 'Xin', + 'Michaelene', + 'Senaida', + 'Emaan', + 'Nakayla', + 'Aine', + 'Jadalyn', + 'Maimouna', + 'Klaire', + 'Macee', + 'Shandi', + 'Heily', + 'Braylynn', + 'Aislynn', + 'Chevon', + 'Henretta', + 'Bellamy', + 'Icie', + 'Draya', + 'Darianna', + 'Zyana', + 'Zaelynn', + 'Story', + 'Kambrie', + 'Ranae', + 'Florencia', + 'Porfiria', + 'Elianny', + 'Karren', + 'Yachet', + 'Euna', + 'Naoma', + 'Stefania', + 'Liora', + 'Zlaty', + 'Margene', + 'Denna', + 'Isidra', + 'Faustina', + 'Bintou', + 'Arbutus', + 'Kelci', + 'Evelena', + 'Maudine', + 'Agapita', + 'Olyvia', + 'Loma', + 'Veola', + 'Mckinlee', + 'Lamya', + 'Nashali', + 'Baileigh', + 'Josselin', + 'Kaydance', + 'Paiton', + 'Myleigh', + 'Jazlyne', + 'Indya', + 'Siham', + 'Aryn', + 'Madalene', + 'Nefertiti', + 'Meridith', + 'Kamesha', + 'Peg', + 'Shelbey', + 'Pearlean', + 'Jamika', + 'Maryama', + 'Sabria', + 'Taniqua', + 'Maraya', + 'Joely', + 'Karys', + 'Charolette', + 'Orly', + 'Jennipher', + 'Kimbra', + 'Krislynn', + 'Kenlie', + 'Karrington', + 'Kambry', + 'Alasia', + 'Carletta', + 'Maija', + 'Nadirah', + 'Gladyce', + 'Shevy', + 'Jalessa', + 'Mushka', + 'Cyre', + 'Mabry', + 'Arihanna', + 'Brithany', + 'Ilianna', + 'Jozlynn', + 'Zandra', + 'Serinity', + 'Passion', + 'Lacresha', + 'Jeraldine', + 'Henriette', + 'Elenore', + 'Nastassia', + 'Ruchel', + 'Amal', + 'Madina', + 'Rosaline', + 'Liyana', + 'Pasqualina', + 'Keyra', + 'Kaycie', + 'Lyanna', + 'Naina', + 'Gennesis', + 'Aarushi', + 'Lariah', + 'Jakiya', + 'Kareena', + 'Rhiana', + 'Emilly', + 'Yeimi', + 'Matsuko', + 'Makhia', + 'Alin', + 'Addisen', + 'Lanae', + 'Oceana', + 'Laquanda', + 'Coralie', + 'Arina', + 'Harini', + 'Emy', + 'Emmarose', + 'Ellyana', + 'Eila', + 'Havana', + 'Dagny', + 'Leylah', + 'Shawanna', + 'Aleenah', + 'Adalia', + 'Aaliya', + 'Zyanya', + 'Felisa', + 'Tameca', + 'Sama', + 'Ripley', + 'Nayomi', + 'Quanesha', + 'Shequita', + 'Shanik', + 'Savina', + 'Nalah', + 'Magaby', + 'Cattaleya', + 'Calla', + 'Lillia', + 'Kaida', + 'Izabell', + 'Francia', + 'Caylin', + 'Bianey', + 'Hanah', + 'Julienne', + 'Viva', + 'Xochil', + 'Staphany', + 'Rayanne', + 'Marialuisa', + 'Devina', + 'Sabryna', + 'Estefanie', + 'Dinora', + 'Clarisse', + 'Josephina', + 'Milca', + 'Anjolie', + 'Akayla', + 'Malea', + 'Mea', + 'Meghana', + 'Briceida', + 'Betsaida', + 'Roselin', + 'Anuhea', + 'Megha', + 'Azusena', + 'Nandini', + 'Prisilla', + 'Shelsy', + 'Olene', + 'Kaneisha', + 'Onalee', + 'Jadore', + 'Monteen', + 'Trudie', + 'Leisha', + 'Drucilla', + 'Tamiyah', + 'Ashante', + 'Daysha', + 'Caliyah', + 'Sabella', + 'Emoni', + 'Jakyla', + 'Reginae', + 'Anyah', + 'Kierstyn', + 'Sharleen', + 'Doretta', + 'Harlene', + 'Gerrie', + 'Zofia', + 'Albertine', + 'Bronwyn', + 'Terresa', + 'Delta', + 'Anijah', + 'Mathilde', + 'Cindie', + 'Dalene', + 'Cyndee', + 'Eulah', + 'Ayako', + 'Beverlee', + 'Nicholle', + 'Kaitlan', + 'Yeraldin', + 'Tawney', + 'Tawnee', + 'Britteny', + 'Alishia', + 'Shireen', + 'Byanca', + 'Rebekka', + 'Annel', + 'Krizia', + 'Kerstin', + 'Shera', + 'Uyen', + 'Ligia', + 'Dallana', + 'Itsel', + 'Karine', + 'Sharmaine', + 'Noely', + 'Marrisa', + 'Karah', + 'Rayann', + 'Oksana', + 'Stephannie', + 'Brynne', + 'Alixandra', + 'Dyana', + 'Emilce', + 'Delmy', + 'Jamee', + 'Caitlan', + 'Marily', + 'Kiani', + 'Jennafer', + 'Nissa', + 'Jenell', + 'Jennette', + 'Marquitta', + 'Chimene', + 'Justyna', + 'Jenette', + 'Cassy', + 'Temika', + 'Katrice', + 'Brandis', + 'Consuela', + 'Chavon', + 'Angella', + 'Shantrell', + 'Christiane', + 'Shenna', + 'Donia', + 'Angelise', + 'Janyah', + 'Damiyah', + 'Luzmaria', + 'Meghna', + 'Natally', + 'Nerissa', + 'Kaori', + 'Laya', + 'Analyssa', + 'Teya', + 'Alizon', + 'Jasline', + 'Lavette', + 'Emmi', + 'Kamisha', + 'Taleah', + 'Shenita', + 'Kaytlynn', + 'Azariyah', + 'Dominica', + 'Malvina', + 'Skyy', + 'Shondra', + 'Lorina', + 'Donielle', + 'Kaisley', + 'Katalyna', + 'Jesslynn', + 'Yasmina', + 'Glada', + 'Maliha', + 'Irina', + 'Hiba', + 'Trinette', + 'Oona', + 'Aleeza', + 'Arisha', + 'Janean', + 'Cristie', + 'Syd', + 'Lavona', + 'Kennia', + 'Kyanna', + 'Lovenia', + 'Julieanne', + 'Launa', + 'Taunya', + 'Tytianna', + 'Becca', + 'Deonna', + 'Jihan', + 'Jomaira', + 'Shantay', + 'Talitha', + 'Shyra', + 'Alverna', + 'Chere', + 'Kamela', + 'Phaedra', + 'Stacee', + 'Gretta', + 'Kathyrn', + 'Shalee', + 'Beautiful', + 'Lissett', + 'Georgann', + 'Corrin', + 'Chelsa', + 'Cera', + 'Layna', + 'Lizanne', + 'Mariellen', + 'Lashandra', + 'Sophya', + 'Shruti', + 'Janea', + 'Rheta', + 'Jezebel', + 'Alizee', + 'Delaila', + 'Dayani', + 'Arieanna', + 'Amarah', + 'Janyia', + 'Makalah', + 'Dorie', + 'Tynisha', + 'Tran', + 'Prisma', + 'Shirin', + 'Tonette', + 'Suzi', + 'Alajah', + 'Lurline', + 'Adelia', + 'Tani', + 'Cassey', + 'Maha', + 'Cheyann', + 'Keyona', + 'Yezenia', + 'Vaness', + 'Stephine', + 'Cyndie', + 'Jaylanie', + 'Jeannemarie', + 'Mammie', + 'Sherice', + 'Delynn', + 'Aoife', + 'Kadiatou', + 'Sherese', + 'Trenyce', + 'Anaiz', + 'Anaiza', + 'Dajanae', + 'Lisaann', + 'Keiko', + 'Martiza', + 'Elysa', + 'Petrina', + 'Dierdre', + 'Davida', + 'Falyn', + 'Briona', + 'Maryjean', + 'Lanisha', + 'Marlenne', + 'Nawal', + 'Ethelene', + 'Alya', + 'Ariannah', + 'Jacinta', + 'Alaia', + 'Sindee', + 'Jalaya', + 'Mellanie', + 'Lasya', + 'Kyrah', + 'Mirabella', + 'Renay', + 'Seren', + 'Hiliana', + 'Kinzie', + 'Isra', + 'Hanan', + 'Kaleia', + 'Melynda', + 'Marine', + 'Twanna', + 'Lekisha', + 'Jamecia', + 'Penney', + 'Tiwanna', + 'Rylea', + 'Shekinah', + 'Mckenzi', + 'Abigael', + 'Patrizia', + 'Jamillah', + 'Caris', + 'Karmyn', + 'Kyli', + 'Princessa', + 'Sakinah', + 'Deserae', + 'Patrina', + 'Carmelina', + 'Mayela', + 'Sherise', + 'Ilda', + 'Florentina', + 'Nelwyn', + 'Jennine', + 'Aleeya', + 'Kynsley', + 'Arlett', + 'Tarra', + 'Lakyn', + 'Tyeisha', + 'Temima', + 'Mallori', + 'Ingeborg', + 'Elizaveta', + 'Jentry', + 'Kymber', + 'Maddisyn', + 'Allana', + 'Anistyn', + 'Emberlynn', + 'Faithlynn', + 'Arianah', + 'Tionna', + 'Lenda', + 'Laveta', + 'Alayla', + 'Aisling', + 'Miryam', + 'Marena', + 'Aneta', + 'Yzabella', + 'Mihika', + 'Raine', + 'Samiah', + 'Raveena', + 'Elfrieda', + 'Niccole', + 'Tatanisha', + 'Medha', + 'Katharina', + 'Jazmen', + 'Cally', + 'Louanne', + 'Caress', + 'Naylea', + 'Avarie', + 'Madelynne', + 'Dayla', + 'Shanterria', + 'Tesha', + 'Thanya', + 'Jalia', + 'Josalyn', + 'Ailey', + 'Brooklynne', + 'Dodie', + 'Champagne', + 'Taneka', + 'Tenesha', + 'Tinisha', + 'Deeanna', + 'Shelvia', + 'Chenoa', + 'Darcel', + 'Kailea', + 'Jatziry', + 'Merryl', + 'Sharlyn', + 'Harolyn', + 'Rilla', + 'Ayisha', + 'Jacklynn', + 'Chloee', + 'Makynzie', + 'Leyah', + 'Aalyiah', + 'Tynlee', + 'Statia', + 'Tyronda', + 'Tsuyako', + 'Casimira', + 'Kehaulani', + 'Ragan', + 'Lorissa', + 'Abelina', + 'Cuca', + 'Sachi', + 'Evany', + 'Elektra', + 'Sianni', + 'Raychel', + 'Natassia', + 'Vermell', + 'Sharifa', + 'Everley', + 'Ivanka', + 'Arisbeth', + 'Aleyza', + 'Bay', + 'Deedra', + 'Zarina', + 'Regena', + 'Kitana', + 'Latoshia', + 'Virgia', + 'Aili', + 'Breslyn', + 'Ishika', + 'Jhoana', + 'Dorrace', + 'Chanice', + 'Sheniqua', + 'Tashana', + 'Joetta', + 'Sanya', + 'Altamese', + 'Pari', + 'Niah', + 'Ysabelle', + 'Lisseth', + 'Parisa', + 'Aislin', + 'Leiah', + 'Atziri', + 'Anvita', + 'Jaydah', + 'Gabby', + 'Ashia', + 'Dymond', + 'Marah', + 'Uniqua', + 'Blimie', + 'Anny', + 'Dalinda', + 'Wauneta', + 'Gionna', + 'Rabia', + 'Jayanna', + 'Anica', + 'Maybell', + 'Kathern', + 'Amrita', + 'Mayerli', + 'Irais', + 'Kemberly', + 'Vena', + 'Kamri', + 'Destine', + 'Adreanna', + 'Seleste', + 'Claretha', + 'Brynnlee', + 'Anquette', + 'Komal', + 'Lysette', + 'Michayla', + 'Zamya', + 'Sierrah', + 'Felica', + 'Otelia', + 'Rihana', + 'Doloris', + 'Alanie', + 'Angelly', + 'Kassandr', + 'Rosemari', + 'Shaday', + 'Annemari', + 'Marlana', + 'Clorinda', + 'Oneida', + 'Shaunta', + 'Alexcia', + 'Takesha', + 'Amiracle', + 'Sharion', + 'Joline', + 'Jaziyah', + 'Teal', + 'Sueann', + 'Sora', + 'Kamiah', + 'Caressa', + 'Eleana', + 'Bernetha', + 'Alexyss', + 'Sharda', + 'Aishwarya', + 'Suhaill', + 'Radhika', + 'Wonda', + 'Renda', + 'Janny', + 'Ardelle', + 'Malory', + 'Jossie', + 'Anaid', + 'Mitsuye', + 'Shizuye', + 'Fariha', + 'Aiesha', + 'Nitya', + 'Nadiya', + 'Katerin', + 'Bruna', + 'Varsha', + 'Yaretsi', + 'Xitlalli', + 'Leshia', + 'Eda', + 'Sheronda', + 'Malikah', + 'Tayah', + 'Briann', + 'Tasnim', + 'Jayonna', + 'Kenedy', + 'Anarosa', + 'Zaya', + 'Kerline', + 'Brinda', + 'Amna', + 'Desarae', + 'Sarrah', + 'Silva', + 'Steffani', + 'Almarosa', + 'Alyshia', + 'Ariell', + 'Breeanne', + 'Alyxandra', + 'Juliane', + 'Jesseca', + 'Janisha', + 'Donisha', + 'Darnisha', + 'Jakeria', + 'Kirsty', + 'Markeisha', + 'Breena', + 'Selin', + 'Nikisha', + 'Adreana', + 'Elois', + 'Arrianna', + 'Melenie', + 'Rayanna', + 'Kaelee', + 'Shakyra', + 'Clotee', + 'Jakeline', + 'Kalysta', + 'Cesia', + 'Ankita', + 'Cristela', + 'Shunta', + 'Mozella', + 'Chrissie', + 'Adora', + 'Ashanty', + 'Ashna', + 'Lehua', + 'Nohealani', + 'Shruthi', + 'Metzli', + 'Jakelin', + 'Jisel', + 'Mikenna', + 'Miroslava', + 'Mansi', + 'Daphney', + 'Amisha', + 'Adara', + 'Alexzandria', + 'Alliah', + 'Yuriana', + 'Nanea', + 'Kahealani', + 'Ritika', + 'Arica', + 'Amayrani', + 'Kealani', + 'Dorina', + 'Lucienne', + 'Estrellita', + 'Kimberlin', + 'Lai', + 'Yovanna', + 'Rebekkah', + 'Azra', + 'Nada', + 'Gabryella', + 'Avigayil', + 'Binta', + 'Devoiry', + 'Raeanna', + 'Arlena', + 'Briauna', + 'Itati', + 'Grabiela', + 'Noella', + 'Teaghan', + 'Tzippy', + 'Faiza', + 'Zaara', + 'Tehilla', + 'Miki', + 'Sendy', + 'Kassondra', + 'Katherina', + 'Lissete', + 'Livier', + 'Lauran', + 'Dandrea', + 'Chelse', + 'Lizmarie', + 'Sunday', + 'Haidee', + 'Carrissa', + 'Nicholette', + 'Katey', + 'Katheryne', + 'Katty', + 'Kimia', + 'Leeanne', + 'Lizmary', + 'Jani', + 'Emmanuella', + 'Jahniya', + 'Talar', + 'Sintia', + 'Narda', + 'Chriselda', + 'Candance', + 'Delorise', + 'Daysy', + 'Lusine', + 'Raeanne', + 'Cherylann', + 'Ayat', + 'Halima', + 'Zissel', + 'Courtni', + 'Adahli', + 'Der', + 'Emree', + 'Brynlie', + 'Cherlyn', + 'Bostyn', + 'Francie', + 'Oaklie', + 'Shakeerah', + 'Hertha', + 'Haneefah', + 'Taheerah', + 'Nikkia', + 'Sheryll', + 'Donnabelle', + 'Teddi', + 'Jodee', + 'Tammera', + 'Janylah', + 'Laquesha', + 'Penina', + 'Gracee', + 'Thomasine', + 'Janyce', + 'Randie', + 'Mela', + 'Alka', + 'Cordia', + 'Shaquetta', + 'Mi', + 'Jaquetta', + 'Yoshiye', + 'Haruye', + 'Yoneko', + 'Fumi', + 'Wava', + 'Congetta', + 'Denee', + 'Kandyce', + 'Soraida', + 'Triana', + 'Kenedi', + 'Abena', + 'Talisha', + 'Rochell', + 'Sharisse', + 'Tijuana', + 'Amiee', + 'Nyesha', + 'Towana', + 'Lore', + 'Melodye', + 'Hayli', + 'Joyelle', + 'Shareen', + 'Amarilis', + 'Takiyah', + 'Takiya', + 'Keysha', + 'Feige', + 'Diahann', + 'Kloie', + 'Laynee', + 'Mariely', + 'Rainey', + 'Alizabeth', + 'Alyssandra', + 'Cambry', + 'Jadelynn', + 'Marylynn', + 'Keoka', + 'Jamaica', + 'Lus', + 'Shonta', + 'Kameelah', + 'Danell', + 'Evamarie', + 'Francoise', + 'Beata', + 'Caylie', + 'Elexa', + 'Joscelin', + 'Hessie', + 'Alazay', + 'Robena', + 'Texie', + 'Clarine', + 'Makennah', + 'Arletha', + 'Willette', + 'Amee', + 'Jetaun', + 'Anyia', + 'Aryssa', + 'Bonni', + 'Graciella', + 'Haileigh', + 'Sharae', + 'Shanea', + 'Ieisha', + 'Porche', + 'Teanna', + 'Ashanta', + 'Taiya', + 'Nicolett', + 'Naisha', + 'Sharice', + 'Madelein', + 'Kimberle', + 'Monifah', + 'Cameo', + 'Evelynne', + 'Edlyn', + 'Porcha', + 'Maricel', + 'Waleska', + 'Shakeena', + 'Shavone', + 'Ashlynne', + 'Yahira', + 'Shamecca', + 'Yashira', + 'Sherell', + 'Fiorela', + 'Nansi', + 'Shawntae', + 'Poonam', + 'Shala', + 'Kellyn', + 'Jazzmyn', + 'Asya', + 'Shatoya', + 'Yury', + 'Weronika', + 'Dawnette', + 'Lorita', + 'Michaelle', + 'Tomi', + 'Abbi', + 'Maudry', + 'Jaylinn', + 'Kynzie', + 'Lynnlee', + 'Madisson', + 'Denese', + 'Devona', + 'Sharika', + 'Sharilyn', + 'Zayna', + 'Janalee', + 'Sherril', + 'Timika', + 'Lynelle', + 'Rolayne', + 'Lubertha', + 'Jariah', + 'Kamala', + 'Taffy', + 'Marquetta', + 'Honora', + 'Frederica', + 'Monalisa', + 'Rashonda', + 'Francene', + 'Diedra', + 'Ceara', + 'Marylouise', + 'Kenesha', + 'Aisley', + 'Donnalee', + 'Genisis', + 'Debroah', + 'Helayne', + 'Raelee', + 'Maryrose', + 'Yalonda', + 'Chyla', + 'Edelmira', + 'Roselle', + 'Alyssah', + 'Brenley', + 'Gaynelle', + 'Shelvie', + 'Mackayla', + 'Linley', + 'Allizon', + 'Alonna', + 'Kendalyn', + 'Jozlyn', + 'Gwenn', + 'Jina', + 'Zariya', + 'Rosabella', + 'Emrie', + 'Tamu', + 'Senta', + 'Myia', + 'Emberlyn', + 'Emorie', + 'Arantxa', + 'Richele', + 'Christianne', + 'Lashan', + 'Koren', + 'Buffie', + 'Ronnette', + 'Marna', + 'Tuesday', + 'Helga', + 'Emilyn', + 'Cailee', + 'Shaquilla', + 'Dyamond', + 'Gerda', + 'Mckynzie', + 'Khloie', + 'Kendyll', + 'Maryfrances', + 'Khadejah', + 'Annalie', + 'Adaya', + 'Akia', + 'Markia', + 'Iyla', + 'Kaely', + 'Rafaella', + 'Tali', + 'Sukhmani', + 'Mili', + 'Kaylanie', + 'Maribelle', + 'Zharia', + 'Georgeanne', + 'Shamekia', + 'Siyona', + 'Layah', + 'Maylani', + 'Elianah', + 'Ellena', + 'Elyanna', + 'Yanilen', + 'Jashanti', + 'Lakita', + 'Juanell', + 'Caley', + 'Annella', + 'Vinita', + 'Zakiyah', + 'Sherian', + 'Palmira', + 'Delpha', + 'Creola', + 'Veta', + 'Sheneka', + 'Ameria', + 'Keonna', + 'Nathali', + 'Vaishnavi', + 'Zurisadai', + 'Mily', + 'Aalyah', + 'Hasini', + 'Irelynn', + 'Taneshia', + 'Lashanti', + 'Shatavia', + 'Shantoria', + 'Avelina', + 'Vanya', + 'Erline', + 'Surina', + 'Maribella', + 'Julieana', + 'Jazel', + 'Kalissa', + 'Marlis', + 'Hadasa', + 'Iveth', + 'Miliani', + 'Leiana', + 'Devynn', + 'Ahtziry', + 'Shilah', + 'Sicily', + 'Ashari', + 'Yarenis', + 'Tamiah', + 'Annis', + 'Azzie', + 'Sedalia', + 'Maebell', + 'Empress', + 'Fairy', + 'Najma', + 'Loreta', + 'Suhayla', + 'Sundus', + 'Vayda', + 'Doshia', + 'Ahlam', + 'Lashondra', + 'Ryanna', + 'Lala', + 'Merline', + 'Severa', + 'Kymora', + 'Fae', + 'Jameka', + 'Othella', + 'Wyoma', + 'Ailee', + 'Aishani', + 'Fransisca', + 'Noma', + 'Meztli', + 'Miliana', + 'Navaeh', + 'Swara', + 'Malillany', + 'Jaina', + 'Dia', + 'Ivyanna', + 'Jamira', + 'Jazaria', + 'Oletha', + 'Julieth', + 'Avia', + 'Elizebeth', + 'Yareni', + 'Korra', + 'Miraya', + 'Bernetta', + 'Helyn', + 'Suhaylah', + 'Laina', + 'Lassie', + 'Anyae', + 'Maleena', + 'Nirvana', + 'Danely', + 'Keilana', + 'Hildur', + 'Mariaclara', + 'Toshie', + 'Maniyah', + 'Hanako', + 'Asako', + 'Hiroko', + 'Hisae', + 'Suraya', + 'Kaileen', + 'Pearla', + 'Layal', + 'Batoul', + 'Johannah', + 'Gizel', + 'Venecia', + 'Yanelly', + 'Atianna', + 'Apple', + 'Arizbeth', + 'Sriya', + 'Natania', + 'Mayline', + 'Emmagrace', + 'Meriam', + 'Laree', + 'Tempie', + 'Sedonia', + 'Evalee', + 'Laquana', + 'Sheli', + 'Liesl', + 'Hazeline', + 'Blanchie', + 'Samyra', + 'Keelie', + 'Krislyn', + 'Yanelis', + 'Addysen', + 'Inis', + 'Tammra', + 'Johnette', + 'Amery', + 'Alayza', + 'Alaiyah', + 'Abree', + 'Amri', + 'Anapaula', + 'Jacelynn', + 'Kenzleigh', + 'Kenzlee', + 'Jaelah', + 'Brenlee', + 'Avalee', + 'Paizley', + 'Columbia', + 'Benedetta', + 'Daeja', + 'Myeshia', + 'Jeanene', + 'Terina', + 'Ethyl', + 'Oliwia', + 'Taniah', + 'Yaiza', + 'Eveline', + 'Monnie', + 'Margherita', + 'Jayana', + 'Macil', + 'Leontine', + 'Catera', + 'Wynelle', + 'Eldana', + 'Sallyann', + 'Yolande', + 'Marybelle', + 'Leanore', + 'Clothilde', + 'Tonita', + 'Kimaya', + 'Sumayah', + 'Latrenda', + 'Kelleen', + 'Deatrice', + 'Madelon', + 'Phyliss', + 'Argelia', + 'Mellie', + 'Emmah', + 'Jorley', + 'Muna', + 'Daphine', + 'Darina', + 'Bliss', + 'Karyl', + 'Taelynn', + 'Blenda', + 'Tonika', + 'Jerrilyn', + 'Sahra', + 'Keilyn', + 'Pearlene', + 'Arrie', + 'Ellene', + 'Fredericka', + 'Ladawn', + 'Maudell', + 'Rahma', + 'Jaylie', + 'Jaidah', + 'Vernetta', + 'Aleya', + 'Aubreigh', + 'Alaysha', + 'Adena', + 'Jacara', + 'Elfriede', + 'Maysel', + 'Munira', + 'Mumtaz', + 'Dorathy', + 'Chanin', + 'Ronette', + 'Maymie', + 'Providencia', + 'Mirta', + 'Loida', + 'Blakelyn', + 'Bentleigh', + 'Alliana', + 'Aleen', + 'Daliyah', + 'Jodene', + 'Johanne', + 'Timeka', + 'Ilhan', + 'Aloma', + 'Maris', + 'Arlyne', + 'Jene', + 'Hazelene', + 'Shakela', + 'Maida', + 'Maycie', + 'Makynlee', + 'Kawanda', + 'Consuella', + 'Sephora', + 'Andrianna', + 'Joshlyn', + 'Hollyn', + 'Kyliee', + 'Adaly', + 'Dailyn', + 'Averee', + 'Berklee', + 'Marly', + 'Gianella', + 'Ekaterina', + 'Colene', + 'Dayonna', + 'Shareka', + 'Roshni', + 'Latifa', + 'Merilyn', + 'Vernelle', + 'Marlyce', + 'Sabrena', + 'Jeneen', + 'Genie', + 'Lawanna', + 'Tashara', + 'Kayzlee', + 'Skylie', + 'Iyonna', + 'Honesti', + 'Cherylene', + 'Tahira', + 'Chizuko', + 'Aneesah', + 'Helmi', + 'Katrena', + 'Shyanna', + 'Zeola', + 'Lempi', + 'Arliss', + 'Madgie', + 'Verlie', + 'Ardys', + 'Twanda', + 'Kareemah', + 'Chardae', + 'Arlinda', + 'Darlena', + 'Karee', + 'Lorry', + 'Rolande', + 'Marlane', + 'Lelah', + 'Zahria', + 'Michalene', + 'Nayelis', + 'Abbigale', + 'Lorretta', + 'Sheril', + 'Priscille', + 'Cleda', + 'Kerrigan', + 'Wanita', + 'Ambria', + 'Wanetta', + 'Ebone', + 'Georgianne', + 'Karleen', + 'Laural', + 'Jonette', + 'Sharie', + 'Francina', + 'Yarelis', + 'Tempestt', + 'Kamie', + 'Julene', + 'Londa', + 'Haniya', + 'Kristeen', + 'Classie', + 'Nakiyah', + 'Valinda', + 'Kamree', + 'Micheline', + 'Mckaylee', + 'Prescilla', + 'Shaylynn', + 'Donelda', + 'Fayetta', + 'Terrye', + 'Dorthey', + 'Azilee', + 'Juanda', + 'Eustolia', + 'Nakeisha', + 'Hira', + 'Tarrah', + 'Jamyra', + 'Azaleah', + 'Aveline', + 'Chanae', + 'Andreana', + 'Banesa', + 'Berenis', + 'Brittini', + 'Orianna', + 'Reet', + 'Rayah', + 'Sofi', + 'Japji', + 'Kensie', + 'Roshonda', + 'Agripina', + 'Blasa', + 'Anevay', + 'Akari', + 'Krissi', + 'Maily', + 'Kitzia', + 'Keilly', + 'Raveen', + 'Kaiah', + 'Juliett', + 'Jocelynne', + 'Eowyn', + 'Calie', + 'Ebonee', + 'Chelcie', + 'Kayci', + 'Lauralee', + 'Trenity', + 'Deborrah', + 'Imagene', + 'Akasha', + 'Analaura', + 'Liani', + 'Lizania', + 'Lucina', + 'Melaine', + 'Sanah', + 'Stepanie', + 'Zabrina', + 'Janaye', + 'Jelena', + 'Kaylina', + 'Diavian', + 'Tasnia', + 'Nusrat', + 'Ashleymarie', + 'Maheen', + 'Ndeye', + 'Yumi', + 'Vittoria', + 'Amyra', + 'Yakelin', + 'Yudith', + 'Yumalay', + 'Juliza', + 'Daila', + 'Daenerys', + 'Calissa', + 'Tahirah', + 'Laquasia', + 'Jenay', + 'Crystina', + 'Eleonore', + 'Inessa', + 'Irine', + 'Vennie', + 'Oda', + 'Laurine', + 'Lavera', + 'Saraya', + 'Kerin', + 'Itzia', + 'Jennessa', + 'Katerine', + 'Rosselyn', + 'Leidy', + 'Adamariz', + 'Adylene', + 'Aylen', + 'Aniela', + 'Aleesha', + 'Alyssamarie', + 'Ainara', + 'Emalie', + 'Darlin', + 'Inna', + 'Emmely', + 'Eriana', + 'Esbeidy', + 'Chenelle', + 'Janise', + 'Sherrell', + 'Basilia', + 'Malayna', + 'Hilinai', + 'Mardell', + 'Romi', + 'Rosena', + 'Violett', + 'Zaylah', + 'Taia', + 'Anisah', + 'Esli', + 'Cleopatra', + 'Carisma', + 'Dezaray', + 'Swayze', + 'Raeven', + 'Neiva', + 'Myeisha', + 'Shelsea', + 'Yissel', + 'Velinda', + 'Josseline', + 'Denasia', + 'Digna', + 'Keiana', + 'Clytee', + 'Vernette', + 'Cheyene', + 'Roshunda', + 'Telisha', + 'Nilah', + 'Ayda', + 'Zykia', + 'Isabellamarie', + 'Melanee', + 'Laylanie', + 'Ajah', + 'Guiliana', + 'Oliva', + 'Mikela', + 'Mirabelle', + 'Nabiha', + 'Jasmina', + 'Hendy', + 'Ita', + 'Elif', + 'Reola', + 'Jamyah', + 'Tempest', + 'Arletta', + 'Keaira', + 'Ibeth', + 'Jerolyn', + 'Nelta', + 'Alishba', + 'Crisol', + 'Sabreena', + 'Silver', + 'Toba', + 'Yunuen', + 'Rishika', + 'Naomie', + 'Brittanya', + 'Annasophia', + 'Ayumi', + 'Jayleene', + 'Emmily', + 'Lyssa', + 'Natoya', + 'Vallerie', + 'Andee', + 'Annastasia', + 'Mazzy', + 'Zinnia', + 'Sheran', + 'Sumaiya', + 'Tasneem', + 'Aniylah', + 'Dua', + 'Tausha', + 'Jabria', + 'Lanora', + 'Janeli', + 'Mileydi', + 'Mikaella', + 'Ryah', + 'Rolonda', + 'Ajanae', + 'Ianna', + 'Xaria', + 'Winni', + 'Marializ', + 'Aidel', + 'Jonae', + 'Sanam', + 'Mao', + 'Tesia', + 'Yanina', + 'Brieana', + 'Genova', + 'Lashanae', + 'Anneke', + 'Siarra', + 'Sharhonda', + 'Zeldy', + 'Saron', + 'Johnisha', + 'Katelynne', + 'Janneth', + 'Corayma', + 'Helvi', + 'Asucena', + 'Lachelle', + 'Solmayra', + 'Tavia', + 'Marlina', + 'Rachal', + 'Sunni', + 'Nycole', + 'Aliannah', + 'Nafisa', + 'Simi', + 'Suki', + 'Jadalynn', + 'Kezia', + 'Athziri', + 'Huda', + 'Evy', + 'Jailah', + 'Jaselle', + 'Jaslyne', + 'Dalyla', + 'Emeraude', + 'Mahika', + 'Yoanna', + 'Fraida', + 'Tannia', + 'Selenne', + 'Analiz', + 'Angelene', + 'Anacristina', + 'Kylea', + 'Naydelyn', + 'Lecia', + 'Gitel', + 'Shareese', + 'Cassady', + 'Diem', + 'Perlita', + 'Monigue', + 'Marisha', + 'Emillee', + 'Kareli', + 'Shandreka', + 'Kerrin', + 'Tram', + 'Nohelani', + 'Monic', + 'Brandice', + 'Johnetta', + 'Evangelia', + 'Shakina', + 'Shunda', + 'Robbi', + 'Ariatna', + 'Shantae', + 'Sorangel', + 'Valene', + 'Aletta', + 'Libbie', + 'Marifer', + 'Deitra', + 'Despina', + 'Hayle', + 'Kassidi', + 'Dayrin', + 'Anjelina', + 'Gimena', + 'Llesenia', + 'Rainbow', + 'Muskaan', + 'Judit', + 'Kyley', + 'Tanna', + 'Luci', + 'Altagracia', + 'Kilee', + 'Kamry', + 'Kalyssa', + 'Jadeyn', + 'Virgen', + 'Damita', + 'Leinaala', + 'Illeana', + 'Nneka', + 'Onika', + 'Aralyn', + 'Mahalia', + 'Marelyn', + 'Jalene', + 'Bobbiejo', + 'Apollonia', + 'Anjuli', + 'Ricarda', + 'Fusako', + 'Michie', + 'Janira', + 'Citlalic', + 'Jannelle', + 'Tiffini', + 'Elisia', + 'Racine', + 'Marybel', + 'Xitlally', + 'Tynesha', + 'Sharay', + 'Shamara', + 'Aleene', + 'Rayssa', + 'Carlyn', + 'Falisha', + 'Lasandra', + 'Trinh', + 'Seema', + 'Tonianne', + 'Destani', + 'Nairobi', + 'Tomica', + 'Raena', + 'Ivania', + 'Odaliz', + 'Lilybeth', + 'Sheyenne', + 'Tereza', + 'Yuka', + 'Baleria', + 'Ayiana', + 'Floree', + 'Jhoanna', + 'Shakila', + 'Meleah', + 'Monserath', + 'Lelani', + 'Conception', + 'Zowie', + 'Teah', + 'Takayla', + 'Teaira', + 'Karyssa', + 'Delina', + 'Kamaile', + 'Rut', + 'Reanne', + 'Zamantha', + 'Ellyse', + 'Jisela', + 'Latonja', + 'Eiko', + 'Aylene', + 'Atziry', + 'Avila', + 'Andreya', + 'Delyla', + 'Aashna', + 'Dacia', + 'Shavonda', + 'Desirey', + 'Matea', + 'Makailah', + 'Henessy', + 'Naliyah', + 'Charlise', + 'Keirsten', + 'Ressie', + 'Halia', + 'Gweneth', + 'Manda', + 'Lilinoe', + 'Mariselda', + 'Tajuana', + 'Mahima', + 'Noeli', + 'Yanelli', + 'Sole', + 'Saloni', + 'Annistyn', + 'Marcille', + 'Thresa', + 'Cerenity', + 'Samnatha', + 'Alexah', + 'Analie', + 'Aryah', + 'Jazline', + 'Evony', + 'Erandy', + 'Jezelle', + 'Kamara', + 'Emelina', + 'Kadance', + 'Masae', + 'Davonna', + 'Shamaya', + 'Shalynn', + 'Rima', + 'Toria', + 'Zamira', + 'Cerina', + 'Fujiko', + 'Armine', + 'Morganne', + 'Gicela', + 'Desree', + 'Khaila', + 'Nikayla', + 'Kennedie', + 'Marylu', + 'Ilyssa', + 'Jatziri', + 'Shianna', + 'Dharma', + 'Resa', + 'Abra', + 'Neely', + 'Imo', + 'Betzabeth', + 'Briceyda', + 'Karenna', + 'Jakhia', + 'Ramiyah', + 'Khaliyah', + 'Tocarra', + 'Milee', + 'Athina', + 'Maleigha', + 'Shalyn', + 'Syliva', + 'Roseline', + 'Claira', + 'Jisselle', + 'Kiely', + 'Marisabel', + 'Maryanna', + 'Melena', + 'Mylene', + 'Mariangela', + 'Mailey', + 'Sonora', + 'Siana', + 'Shreeya', + 'Sevana', + 'Samhita', + 'Jackelyne', + 'Kyrstin', + 'Anslie', + 'Samella', + 'Jewelia', + 'Sammye', + 'Ayline', + 'Navneet', + 'Charlesetta', + 'Raye', + 'Yulonda', + 'Esmerelda', + 'Gianina', + 'Danessa', + 'Calia', + 'Everlena', + 'Sadaf', + 'Analucia', + 'Meriah', + 'Gwendalyn', + 'Disha', + 'Katana', + 'Kalaya', + 'Kaeley', + 'Tyonna', + 'Rozella', + 'Marjean', + 'Conchita', + 'Kylynn', + 'Aasiyah', + 'Maelynn', + 'Kahla', + 'Prachi', + 'Tajanae', + 'Megumi', + 'Micheala', + 'Yanitza', + 'Geselle', + 'Reather', + 'Annalicia', + 'Bonna', + 'Lilliann', + 'Callia', + 'Brigit', + 'Quintina', + 'Fujie', + 'Jolanda', + 'Nanami', + 'Yosselin', + 'Jakelyn', + 'Kadeja', + 'Eveny', + 'Emaly', + 'Ciena', + 'Julliana', + 'Jareli', + 'Jaretzi', + 'Kailin', + 'Kimiye', + 'Ammie', + 'Kiona', + 'Sumayyah', + 'Terre', + 'Laryssa', + 'Marleni', + 'Kamira', + 'Yulanda', + 'Jonda', + 'Lania', + 'Pippa', + 'Jazariah', + 'Takeya', + 'Shatima', + 'Ysenia', + 'Mikki', + 'Necole', + 'Etha', + 'Williemae', + 'Margurite', + 'Leonarda', + 'Inocencia', + 'Dominika', + 'Laisa', + 'Haylea', + 'Annamay', + 'Azia', + 'Mckynlee', + 'Maddilyn', + 'Scotlyn', + 'Lillith', + 'Mertie', + 'Kynzee', + 'Joshlynn', + 'Maelee', + 'Daleiza', + 'Xyla', + 'Royalty', + 'Railynn', + 'Patrycja', + 'Dotty', + 'Leda', + 'Toshiba', + 'Nelma', + 'Yeni', + 'Ottilie', + 'Lyna', + 'Leslieann', + 'Onita', + 'Darcey', + 'Marya', + 'Africa', + 'Seferina', + 'Theola', + 'Ysidra', + 'Zita', + 'Cing', + 'Zailynn', + 'Jennilee', + 'Sharmon', + 'Tyechia', + 'Irmgard', + 'Shameika', + 'Jemima', + 'Jazzelle', + 'Adlee', + 'Aliyanna', + 'Acelyn', + 'Catalaya', + 'Brileigh', + 'Braylie', + 'Angelin', + 'Arianni', + 'Ariani', + 'Kennya', + 'Maelyn', + 'Lillee', + 'Maripaz', + 'Laikyn', + 'Kenslee', + 'Ileane', + 'Puja', + 'Oanh', + 'Jakara', + 'Shawntay', + 'Cendy', + 'Erianna', + 'Chloie', + 'Birtie', + 'Korin', + 'Jannett', + 'Shawntel', + 'Markisha', + 'Nastassja', + 'Shalene', + 'Alexya', + 'Cloie', + 'Exa', + 'Jentri', + 'Modena', + 'Veronique', + 'Daina', + 'Mechele', + 'Lakesia', + 'Kawanna', + 'Clotilde', + 'Diamonique', + 'Teyana', + 'Rheagan', + 'Shanece', + 'Yanique', + 'Taysha', + 'Ulyssa', + 'Jadzia', + 'Kadija', + 'Towanna', + 'Lurlene', + 'Sharri', + 'Rosenda', + 'Daphna', + 'Hermina', + 'Shaquanda', + 'Saachi', + 'Sena', + 'Yazaira', + 'Yatzil', + 'Anam', + 'Sparrow', + 'Anetra', + 'Nalayah', + 'Jaylenne', + 'Joya', + 'Kensi', + 'Khylee', + 'Lilyrose', + 'Iasia', + 'Jaliah', + 'Melda', + 'Armella', + 'Zyasia', + 'Nazia', + 'Shanasia', + 'Krystie', + 'Dorothe', + 'Thora', + 'Adelene', + 'Avaya', + 'Aurielle', + 'Ailany', + 'Andromeda', + 'Loa', + 'Cleora', + 'Darling', + 'Caliana', + 'Keniyah', + 'Crystel', + 'Dimitra', + 'Renate', + 'Zyriah', + 'Taegan', + 'Marygrace', + 'Mckinzie', + 'Nivea', + 'Rhian', + 'Amarissa', + 'Kadee', + 'Devani', + 'Khara', + 'Aishia', + 'Annell', + 'Jaslin', + 'Jaide', + 'Briahna', + 'Merary', + 'Lauraine', + 'Tywana', + 'Athanasia', + 'Chantay', + 'Loretha', + 'Anyiah', + 'Marvine', + 'Jennelle', + 'Hiedi', + 'Sunnie', + 'Panagiota', + 'Lanesha', + 'Amity', + 'Denyse', + 'Nataleigh', + 'Amyia', + 'Avrie', + 'Analysa', + 'Ameris', + 'Ambrielle', + 'Kynnedy', + 'Gracy', + 'Kaelie', + 'Heydi', + 'Latrese', + 'Lavonia', + 'Latrelle', + 'Lynetta', + 'Graceann', + 'Susette', + 'Sarabeth', + 'Arnetta', + 'Shelonda', + 'Myiesha', + 'Shila', + 'Pascale', + 'Zenja', + 'Madelene', + 'Lalena', + 'Doria', + 'Dagmar', + 'Griselle', + 'Nitza', + 'Moraima', + 'Miguelina', + 'Brittania', + 'Emmalin', + 'Novie', + 'Chavonne', + 'Lashana', + 'Quyen', + 'Gennifer', + 'Zaryah', + 'Paytin', + 'Keeli', + 'Kolbi', + 'Maddyson', + 'Jackqueline', + 'Arnita', + 'Brynnley', + 'Edelyn', + 'Arial', + 'Yaneliz', + 'Ena', + 'Barbaraann', + 'Glendora', + 'Heavyn', + 'Neomi', + 'Rebbecca', + 'Laketa', + 'Renetta', + 'Carline', + 'Nezzie', + 'Shaneeka', + 'Desaray', + 'Hiromy', + 'Hallee', + 'Halli', + 'Sheba', + 'Tahisha', + 'Paetyn', + 'Katisha', + 'Joyell', + 'Joyel', + 'Zoei', + 'Zamiya', + 'Raygan', + 'Clydie', + 'Missouri', + 'Debany', + 'Kalisha', + 'Niurka', + 'Beverlyn', + 'Bell', + 'Zuly', + 'Lakayla', + 'Lainee', + 'Kynli', + 'Lundyn', + 'Erynn', + 'Braleigh', + 'Allena', + 'Lashanna', + 'Shaunya', + 'Tykia', + 'Leeba', + 'Bassheva', + 'Kandra', + 'Breyana', + 'Geovana', + 'Joandra', + 'Jessyka', + 'Analilia', + 'Charna', + 'Josefita', + 'Laurin', + 'Casi', + 'Jeniah', + 'Koraima', + 'Vivi', + 'Merlina', + 'Marinna', + 'Soriya', + 'Sarayu', + 'Ma', + 'Adali', + 'Abbygale', + 'Avonlea', + 'Bellah', + 'Makeyla', + 'Maanya', + 'Hania', + 'Ellah', + 'Esmee', + 'Jaylean', + 'Verlene', + 'Kendria', + 'Kasondra', + 'Kadesha', + 'Kadedra', + 'Reizel', + 'Reizy', + 'Sheryle', + 'Elka', + 'Caileigh', + 'Meya', + 'Rondi', + 'Janetta', + 'Dwana', + 'Yakira', + 'Donetta', + 'Laurissa', + 'Jordann', + 'Jenice', + 'Hasmik', + 'Mychelle', + 'Shabnam', + 'Sarahann', + 'Shaylene', + 'Zuleica', + 'Verenise', + 'Dejanee', + 'Alyx', + 'Breyanna', + 'Anum', + 'Jamesia', + 'Asheley', + 'Keya', + 'Lyzette', + 'Rossy', + 'Terilyn', + 'Rahaf', + 'Anabia', + 'Neala', + 'Payal', + 'Taheera', + 'Nakhia', + 'Shaela', + 'Krupa', + 'Suriya', + 'Victory', + 'Viviane', + 'Habiba', + 'Fortune', + 'Farida', + 'Erina', + 'Ranya', + 'Tifani', + 'Surie', + 'Aastha', + 'Joella', + 'Sherida', + 'Vonnie', + 'Bluma', + 'Gianny', + 'Naziyah', + 'Taylie', + 'Jakia', + 'Timia', + 'Farren', + 'Skylin', + 'Sabiha', + 'Nashley', + 'Blimi', + 'Annita', + 'Kristianna', + 'Delena', + 'Dalina', + 'Kyasia', + 'Cathlene', + 'Karalee', + 'Merilee', + 'Monette', + 'Asharia', + 'Jacquelina', + 'Nishat', + 'Charlcie', + 'Sukanya', + 'Celines', + 'Rashell', + 'Nadja', + 'Lamiyah', + 'Najae', + 'Zipporah', + 'Rawan', + 'Tailor', + 'Denesha', + 'Masiel', + 'Nida', + 'Assata', + 'Infiniti', + 'Cresencia', + 'Omega', + 'Meher', + 'Maneh', + 'Noura', + 'Yanine', + 'Maral', + 'Malori', + 'Safia', + 'Saori', + 'Vesper', + 'Audrinna', + 'Dea', + 'Kahlia', + 'Eliora', + 'Isley', + 'Laurinda', + 'Mignon', + 'Debie', + 'Denette', + 'Jolyn', + 'Casondra', + 'Donnisha', + 'Elysse', + 'Lazaria', + 'Aleia', + 'Shelbee', + 'Ivone', + 'Mazal', + 'Sherley', + 'Shantia', + 'Christelle', + 'Tatjana', + 'Roselia', + 'Pebbles', + 'Cleotilde', + 'Erendida', + 'Chardonnay', + 'Brittiny', + 'Brittanny', + 'Scarleth', + 'Mehar', + 'Neila', + 'Sofiya', + 'Lakshmi', + 'Lilianne', + 'Akeiba', + 'Shabreka', + 'Joannie', + 'Samiha', + 'Fatma', + 'Itzell', + 'Envy', + 'Maybelline', + 'Nashly', + 'Rya', + 'Kaelani', + 'Kailana', + 'Aylah', + 'Bellamarie', + 'Marizol', + 'Malyssa', + 'Madai', + 'Neelam', + 'Ysamar', + 'Sulma', + 'Sueling', + 'Song', + 'Sharayah', + 'Melisha', + 'Ashliegh', + 'Melodi', + 'Belem', + 'Chrystina', + 'Tonantzin', + 'Setareh', + 'Valeri', + 'Yaffa', + 'Niara', + 'Mame', + 'Janasia', + 'Flo', + 'Gustavia', + 'Lanya', + 'Nanie', + 'Velta', + 'Dot', + 'Luberta', + 'Ledora', + 'Olean', + 'Abbigayle', + 'Hadeel', + 'Rayma', + 'Mayola', + 'Nonnie', + 'Voncille', + 'Heloise', + 'Nolia', + 'Victorine', + 'Yola', + 'Vella', + 'Terrilyn', + 'Noelie', + 'Alean', + 'Allean', + 'Lorean', + 'Josiephine', + 'Heba', + 'Kerrianne', + 'Odeal', + 'Aigner', + 'Anaclara', + 'Gudrun', + 'Valborg', + 'Trenice', + 'Ardath', + 'Aune', + 'Teresia', + 'Lesha', + 'Dewanna', + 'Arlyce', + 'Jayliana', + 'Orene', + 'Paralee', + 'Jamyia', + 'Kemiyah', + 'Fredia', + 'Amyiah', + 'Doreatha', + 'Lashanta', + 'Cerissa', + 'Kawana', + 'Arizona', + 'Shanetta', + 'Jalesa', + 'Asmaa', + 'Garnette', + 'Clella', + 'Artemisa', + 'Liliya', + 'Oretha', + 'Adna', + 'Amyri', + 'Tyshae', + 'Maryan', + 'Santanna', + 'Bushra', + 'Jamyla', + 'Earma', + 'Delsie', + 'Verlean', + 'Sherena', + 'Carmelite', + 'Chari', + 'Darlean', + 'Shamia', + 'Audryna', + 'Genevia', + 'Avie', + 'Tamora', + 'Lavonna', + 'September', + 'Sharolyn', + 'Athziry', + 'Alyiah', + 'Aleina', + 'Alesandra', + 'Amoreena', + 'Nykia', + 'Drea', + 'Galilee', + 'Ainslie', + 'Ishita', + 'Jenavie', + 'Jezabel', + 'Erandi', + 'Evana', + 'Jiana', + 'Laniah', + 'Britanny', + 'Sanika', + 'Solash', + 'Laasya', + 'Nairi', + 'Leighla', + 'Kaiyah', + 'Suhana', + 'Taliya', + 'Maleia', + 'Candee', + 'Ninette', + 'Eugena', + 'Lateisha', + 'Salvatrice', + 'Quaneisha', + 'Mertis', + 'Bebe', + 'Rida', + 'Takyra', + 'Floye', + 'Christell', + 'Ozelle', + 'Juanice', + 'Genia', + 'Shaundra', + 'Shanin', + 'Wendee', + 'Cynde', + 'Adalynne', + 'Adelin', + 'Hayven', + 'Ayra', + 'Chimamanda', + 'Kenzlie', + 'Taylynn', + 'Zerenity', + 'Kynsleigh', + 'Dorthea', + 'Alley', + 'Melrose', + 'Keyondra', + 'Anglia', + 'Lynnea', + 'Tamira', + 'Terisa', + 'Tona', + 'Isaly', + 'Jeimy', + 'Giannah', + 'Leilanni', + 'Leya', + 'Quetzali', + 'Naylene', + 'Misaki', + 'Amely', + 'Donette', + 'Charlayne', + 'Selia', + 'Kittie', + 'Tamaya', + 'Lenna', + 'Zykerria', + 'Teisha', + 'Terrea', + 'Alita', + 'Bunny', + 'Deniece', + 'Inge', + 'Takira', + 'Monesha', + 'Mahala', + 'Donica', + 'Fortunata', + 'Valrie', + 'Zayah', + 'Ziyah', + 'Vela', + 'Vassie', + 'Omie', + 'Nadean', + 'Annalynn', + 'Adah', + 'Edmae', + 'Aalayah', + 'Yuritzy', + 'Ytzel', + 'Svetlana', + 'Soha', + 'Alfredia', + 'Kylei', + 'Landrey', + 'Lariyah', + 'Rozlyn', + 'Sakina', + 'Greer', + 'Bula', + 'Eura', + 'Harmonee', + 'Pecola', + 'Noreta', + 'Laveda', + 'Retta', + 'Rozlynn', + 'Skarlet', + 'Snow', + 'Zoha', + 'Sophiarose', + 'Anglea', + 'Itzabella', + 'Elanie', + 'Calirose', + 'Adhya', + 'Amaiyah', + 'Lavender', + 'Leylanie', + 'Kaliana', + 'Quetzaly', + 'Helon', + 'Nalia', + 'Cipriana', + 'Martyna', + 'Pola', + 'Dierra', + 'Maximina', + 'Sherica', + 'Murlene', + 'Berna', + 'Bernarda', + 'Ettie', + 'Laiken', + 'Hensley', + 'Fontella', + 'Modelle', + 'Timotea', + 'Venora', + 'Lakelyn', + 'Licia', + 'Laury', + 'Loralee', + 'Kamyah', + 'Verba', + 'Angelee', + 'Adalind', + 'Adaliz', + 'Ailynn', + 'Airi', + 'Alany', + 'Avika', + 'Avleen', + 'Leoni', + 'Saisha', + 'Savvy', + 'Philippa', + 'Jasneet', + 'Izabellah', + 'Elienai', + 'Kalayah', + 'Eureka', + 'Dionicia', + 'Zylah', + 'Zosia', + 'Yetzali', + 'Tigerlily', + 'Dorena', + 'Nakesha', + 'Lakenya', + 'Margarete', + 'Margarite', + 'Cloteal', + 'Adline', + 'Willadeen', + 'Anselma', + 'Marcheta', + 'Havyn', + 'Ilyanna', + 'Idalie', + 'Fallyn', + 'Emori', + 'Anzal', + 'Kalila', + 'Ellisyn', + 'Maddalyn', + 'Roslynn', + 'Hodan', + 'Emalynn', + 'Addy', + 'Adelyne', + 'Aizah', + 'Dalayza', + 'Cambri', + 'Annali', + 'Angelynn', + 'Caidence', + 'Auriana', + 'Azlynn', + 'Blakelee', + 'Brenleigh', + 'Tailynn', + 'Zyla', + 'Verline', + 'Pierina', + 'Panhia', + 'Valda', + 'Shela', + 'Uldine', + 'Vibha', + 'Wednesday', + 'Porshia', + 'Shabria', + 'Palmina', + 'Khristine', + 'Lannette', + 'Sandhya', + 'Janalyn', + 'Floreine', + 'Marchelle', + 'Minette', + 'Tawnia', + 'Wynne', + 'Sada', + 'Windi', + 'Clydene', + 'Shundra', + 'Joycie', + 'Delories', + 'Alvena', + 'Edmonia', + 'Denean', + 'Dhana', + 'Marjie', + 'Alicja', + 'Cammy', + 'Aryam', + 'Leonie', + 'Adrielle', + 'Felisita', + 'Tinnie', + 'Marinda', + 'Lamia', + 'Conchetta', + 'Naylah', + 'Sarayah', + 'Nataliya', + 'Delani', + 'Eknoor', + 'Ellee', + 'Maiah', + 'Mayumi', + 'Meara', + 'Kalliope', + 'Jewels', + 'Lanaya', + 'Yui', + 'Maxcine', + 'Yaqueline', + 'Yoceline', + 'Marilynne', + 'Maple', + 'Ronesha', + 'Marili', + 'Reema', + 'Rayana', + 'Aggie', + 'Talina', + 'Doristine', + 'Romelle', + 'Shaqueena', + 'Sharelle', + 'Caira', + 'Gelsey', + 'Tashawna', + 'Takeisha', + 'Jerlean', + 'Sunita', + 'Shalini', + 'Michaeline', + 'Audria', + 'Ronnisha', + 'Leonia', + 'Monna', + 'Ambra', + 'Corena', + 'Taren', + 'Alexiss', + 'Kajal', + 'Jordanne', + 'Kasia', + 'Brienna', + 'Gayane', + 'Deija', + 'Cidney', + 'Tabytha', + 'Raeleen', + 'Mkayla', + 'Harli', + 'Jassmin', + 'Ilo', + 'Lasheena', + 'Keianna', + 'Kally', + 'Makenzy', + 'Angelea', + 'Natasia', + 'Shaneequa', + 'Monay', + 'Moet', + 'Marcelline', + 'Shatia', + 'Sarafina', + 'Kaisha', + 'Tiffney', + 'Shenequa', + 'Sheretta', + 'Floria', + 'Alacia', + 'Kavita', + 'Kerianne', + 'Tameshia', + 'Jamye', + 'Shanese', + 'Latiqua', + 'Jesscia', + 'Johanny', + 'Daniqua', + 'Geneviev', + 'Bernadet', + 'Annice', + 'Megann', + 'Katee', + 'Nikeya', + 'Stavroula', + 'Tawna', + 'Sindia', + 'Marlaina', + 'Jury', + 'Tovah', + 'Shivonne', + 'Nekia', + 'Yvonnie', + 'Kyna', + 'Railey', + 'Xandria', + 'Genine', + 'Tashima', + 'Marycarmen', + 'Kiahna', + 'Jadynn', + 'Akua', + 'Eather', + 'Fatema', + 'Aiysha', + 'Allisa', + 'Ashleynicole', + 'Bobette', + 'Shandrika', + 'Hollace', + 'Chandni', + 'Cayley', + 'Brenae', + 'Areisy', + 'Annahi', + 'Anallely', + 'Klarisa', + 'Ayssa', + 'Jatavia', + 'Nohemy', + 'Mikyla', + 'Mariadelosang', + 'Shatina', + 'Kazandra', + 'Elsi', + 'Teryl', + 'Yennifer', + 'Destyni', + 'Damariz', + 'Areanna', + 'Everlean', + 'Lesslie', + 'Margrette', + 'Tuyet', + 'Jacquelene', + 'Grissel', + 'Walterine', + 'Shterna', + 'Gila', + 'Nabila', + 'Liel', + 'Sani', + 'Djeneba', + 'Angeliz', + 'Anari', + 'Amyrie', + 'Aissa', + 'Tichina', + 'Amariana', + 'Xiara', + 'Yamiles', + 'Isatou', + 'Airiana', + 'Carrigan', + 'Aldea', + 'Aarika', + 'Bryanne', + 'Alegandra', + 'Carrisa', + 'Andrina', + 'Casaundra', + 'Breanda', + 'Biviana', + 'Irena', + 'Denielle', + 'Lizzett', + 'Shaunice', + 'Sigourney', + 'Sona', + 'Paradise', + 'Lashanique', + 'Melaina', + 'Zoua', + 'Vaneza', + 'Tyresha', + 'Shyasia', + 'Tiyana', + 'Youa', + 'Zaneta', + 'Muskan', + 'Talissa', + 'Kennisha', + 'Lizandra', + 'Akosua', + 'Jaymi', + 'Chelby', + 'Chelci', + 'Aeriel', + 'Isamara', + 'Payge', + 'Hadja', + 'Fruma', + 'Fiza', + 'Fatumata', + 'Kabrina', + 'Feigy', + 'Zanaya', + 'Yanette', + 'Teairra', + 'Talor', + 'Kathrina', + 'Justeen', + 'Maryelizabeth', + 'Jannete', + 'Chantalle', + 'Haide', + 'Genelle', + 'Esthela', + 'Emilse', + 'Maegen', + 'Lyndsi', + 'Cristiana', + 'Clio', + 'Breindel', + 'Briyana', + 'Jamyria', + 'Jameshia', + 'Kadeshia', + 'Jamisha', + 'Faige', + 'Aishah', + 'Lorette', + 'Nandi', + 'Nastasia', + 'Shada', + 'Shakeia', + 'Shaneice', + 'Yanel', + 'Teryn', + 'Shaylyn', + 'Karimah', + 'Fabienne', + 'Shaianne', + 'Saleena', + 'Raychelle', + 'Pahoua', + 'Justyne', + 'Fransheska', + 'Katilyn', + 'Shadaya', + 'Quanasia', + 'Shantasia', + 'Nyasha', + 'Minahil', + 'Shahd', + 'Chani', + 'Bassy', + 'Zunairah', + 'Lynsie', + 'Charnelle', + 'Jaquana', + 'Taquana', + 'Shaasia', + 'Idelle', + 'Rogene', + 'Udy', + 'Devory', + 'Evanna', + 'Keisy', + 'Hadiya', + 'Brittainy', + 'Cortni', + 'Erikka', + 'Lindsie', + 'Mayraalejandra', + 'Topacio', + 'Elky', + 'Yita', + 'Sura', + 'Tiani', + 'Sadiya', + 'Kaitlen', + 'Jessicca', + 'Linna', + 'Stephy', + 'Hadia', + 'Jaiyana', + 'Aldina', + 'Frimy', + 'Tywanda', + 'Renarda', + 'Mardelle', + 'Alaijah', + 'Antoinetta', + 'Amyria', + 'Sheyanne', + 'Jackee', + 'Bina', + 'Khole', + 'Selenia', + 'Seidy', + 'Albertina', + 'Yoandra', + 'Yarelyn', + 'Kassaundra', + 'Lynzee', + 'Haneen', + 'Marshay', + 'Sharona', + 'Shanygne', + 'Nigeria', + 'Nechy', + 'Jhane', + 'Chrisette', + 'Gypsy', + 'Drusilla', + 'Milta', + 'Ranee', + 'Yvett', + 'Mykenzie', + 'Aracelia', + 'Vernessa', + 'Chekesha', + 'Cadance', + 'Moria', + 'Tsurue', + 'Yarisbel', + 'Verena', + 'Tomoe', + 'Breezy', + 'Swannie', + 'Tsuyuko', + 'Hisayo', + 'Gerianne', + 'Cailynn', + 'Adrionna', + 'Lillianne', + 'Eduarda', + 'Melinna', + 'Sanaiya', + 'Nohelia', + 'Zarela', + 'Yarethzy', + 'Sruthi', + 'Josefine', + 'Kiela', + 'Kersten', + 'Syriah', + 'Emaleigh', + 'Jazlynne', + 'Aeryn', + 'Danelly', + 'Dalylah', + 'Lexa', + 'Kherington', + 'Nivia', + 'Carolanne', + 'Sharlotte', + 'Vanda', + 'Deirdra', + 'Ilyse', + 'Judyann', + 'Venezia', + 'Mailee', + 'Latishia', + 'Ajla', + 'Lucine', + 'Shontell', + 'Rosiland', + 'Celinda', + 'Aanika', + 'Felicidad', + 'Denia', + 'Natsuko', + 'Analyse', + 'Angellina', + 'Brizeida', + 'Jazira', + 'Terah', + 'Reana', + 'Jennalyn', + 'Jenaya', + 'Kelani', + 'Miyuki', + 'Aracelie', + 'Dannika', + 'Danity', + 'Cadie', + 'Breelyn', + 'Kayra', + 'Mayli', + 'Malarie', + 'Tequilla', + 'Gerilyn', + 'Mieko', + 'Belynda', + 'Shamiyah', + 'Reaghan', + 'Ziya', + 'Rozanne', + 'Joyanne', + 'Zamaria', + 'Luiza', + 'Tamanika', + 'Kimya', + 'Patriciaann', + 'Eilene', + 'Bryna', + 'Yena', + 'Yarelly', + 'Maddyn', + 'Khylie', + 'Khyla', + 'Margueritte', + 'Ramya', + 'Jenea', + 'Jennavie', + 'Jazzlene', + 'Marelly', + 'Manya', + 'Lillyanne', + 'Gyselle', + 'Niyati', + 'Moana', + 'Kenosha', + 'Ezmeralda', + 'Anvitha', + 'Avelyn', + 'Dahlila', + 'Emmaly', + 'Dayamy', + 'Anajulia', + 'Mandee', + 'Valli', + 'Sharan', + 'Leasia', + 'Shiquita', + 'Malana', + 'Nadeen', + 'Parneet', + 'Lynna', + 'Saskia', + 'Samaiya', + 'Saffron', + 'Vianka', + 'Evey', + 'Ebelin', + 'Anishka', + 'Aneth', + 'Addelynn', + 'Kayly', + 'Alyzae', + 'Anniyah', + 'Ayme', + 'Alexsa', + 'Aidsa', + 'Elyn', + 'Illianna', + 'Greenlee', + 'Tinesha', + 'Sherline', + 'Yvanna', + 'Joslin', + 'Estee', + 'Lusia', + 'Nhung', + 'Janielle', + 'Smithie', + 'Yohanna', + 'Shanette', + 'Marilena', + 'Blannie', + 'Meleana', + 'Malie', + 'Jannine', + 'Kuulei', + 'Kawehi', + 'Velna', + 'Kuuipo', + 'Keani', + 'Tiffeny', + 'Billi', + 'Conni', + 'Elexia', + 'Sheily', + 'Mehak', + 'Ardelia', + 'Phung', + 'Aleasha', + 'Toyia', + 'Kalliopi', + 'Carrieann', + 'Shayal', + 'Brandye', + 'Shatisha', + 'Neola', + 'Pallavi', + 'Symantha', + 'Mackenzee', + 'Shalawn', + 'Krimson', + 'Jaquelinne', + 'Sonal', + 'Calysta', + 'Kaylamarie', + 'Kirah', + 'Belicia', + 'Anicia', + 'Aerin', + 'Marisel', + 'Priscella', + 'Lei', + 'Imaan', + 'Haruka', + 'Kila', + 'Jerusha', + 'Deva', + 'Charon', + 'Leida', + 'Deadra', + 'Areana', + 'Iriana', + 'Drenda', + 'Saadia', + 'Danne', + 'Jossalyn', + 'Kennadie', + 'Makaya', + 'Daelynn', + 'Daffne', + 'Galia', + 'Naida', + 'Yaira', + 'Latania', + 'Damarys', + 'Mireille', + 'Maribell', + 'Luzelena', + 'Anacani', + 'Sahira', + 'Shaylin', + 'Sejal', + 'Subrina', + 'Julaine', + 'Saby', + 'Zoraya', + 'Atalie', + 'Deseray', + 'Nacole', + 'Jennell', + 'Laneisha', + 'Ivie', + 'Darnella', + 'Lashone', + 'Lekeisha', + 'Puanani', + 'Uilani', + 'Donyale', + 'Terriann', + 'Marianela', + 'Josalynn', + 'Avari', + 'Blonnie', + 'Makya', + 'Seriah', + 'Nori', + 'Roselee', + 'Verbie', + 'Borghild', + 'Marcene', + 'Syretta', + 'Bama', + 'Eulene', + 'Chantale', + 'Shontae', + 'Mabell', + 'Hellon', + 'Shantanique', + 'Janki', + 'Dhara', + 'Buna', + 'Naeemah', + 'Tacara', + 'Shirleyann', + 'Tshwanda', + 'Nadege', + 'Georganne', + 'Leondra', + 'Fredricka', + 'Margaree', + 'Quincee', + 'Oaklynn', + 'Arlean', + 'Judee', + 'Nyoka', + 'Khia', + 'Kendia', + 'Mahek', + 'Anasia', + 'Jenin', + 'Gerline', + 'Elwillie', + 'Annsley', + 'Juhi', + 'Zettie', + 'Shacara', + 'Shantique', + 'Marijo', + 'Shakara', + 'Ersie', + 'Bionca', + 'Kolleen', + 'Ertha', + 'Chioma', + 'Roneisha', + 'Courtenay', + 'Altie', + 'Arla', + 'Delainey', + 'Rainelle', + 'Lockie', + 'Rayonna', + 'Nasiyah', + 'Zori', + 'Carollee', + 'Mima', + 'Irja', + 'Willadean', + 'Sigrid', + 'Myong', + 'Khaliah', + 'Sakeenah', + 'Saleemah', + 'Emmersyn', + 'Miyeko', + 'Brooksie', + 'Brailynn', + 'Raghad', + 'Nadira', + 'Hassana', + 'Toshiye', + 'Fumiye', + 'Kelise', + 'Angelis', + 'Earla', + 'Dilia', + 'Arwa', + 'Shaylie', + 'Synai', + 'Tanijah', + 'Jalaysia', + 'Charnita', + 'Marit', + 'Gaelle', + 'Shandiin', + 'Janelis', + 'Gatha', + 'Alahna', + 'Aniyla', + 'Mikelle', + 'Skai', + 'Merlinda', + 'Tariyah', + 'Arietta', + 'Terrika', + 'Elenor', + 'Ruthanna', + 'Evaline', + 'Abigaelle', + 'Alayjah', + 'Naysa', + 'Camya', + 'Pachia', + 'Kamia', + 'Sylvania', + 'Ambree', + 'Oakleigh', + 'Zania', + 'Murielle', + 'Charlyn', + 'Zykira', + 'Jestine', + 'Simonne', + 'Willodene', + 'Lyndee', + 'Sophonie', + 'Saddie', + 'Darlis', + 'Lynnda', + 'Marysa', + 'Seleena', + 'Raevyn', + 'Lilikoi', + 'Maiyer', + 'Kymberli', + 'Shayda', + 'Cassidee', + 'Jadira', + 'Delora', + 'Afsheen', + 'Adira', + 'Amena', + 'Canary', + 'Humaira', + 'Derricka', + 'Fatiha', + 'Xia', + 'Jaquelyne', + 'Aurianna', + 'Sarahjane', + 'Sanaz', + 'Taleen', + 'Teara', + 'Taiz', + 'Sharai', + 'Magally', + 'Manon', + 'Maizie', + 'Manisha', + 'Marisleysis', + 'Anjela', + 'Youlanda', + 'Jermani', + 'Elysha', + 'Claritza', + 'Gissela', + 'Icela', + 'Alixandria', + 'Asley', + 'Analuisa', + 'Maddalena', + 'Cortnee', + 'Coretha', + 'Audreanna', + 'Manal', + 'Kadijatou', + 'Pollie', + 'Mysti', + 'Tiffiany', + 'Corean', + 'Amiree', + 'Anner', + 'Cleone', + 'Lavone', + 'Fredna', + 'Konnie', + 'Robbyn', + 'Alica', + 'Bessy', + 'Aleesa', + 'Analleli', + 'Mischelle', + 'Bethani', + 'Baillie', + 'Odessie', + 'Erlene', + 'Marcile', + 'Edona', + 'Tylah', + 'Tyrah', + 'Rainell', + 'Precilla', + 'Genever', + 'Ajanee', + 'Chera', + 'Amye', + 'Monserratt', + 'Moorea', + 'Richa', + 'Willetta', + 'Shawne', + 'Trisa', + 'Lasonia', + 'Cleona', + 'Alizea', + 'Anayely', + 'Emelly', + 'Fionna', + 'Cerena', + 'Julyana', + 'Kaile', + 'Jacklin', + 'Brianca', + 'Ashleyann', + 'Richardine', + 'Kelcee', + 'Keyaira', + 'Mabelle', + 'Brecklyn', + 'Samyah', + 'Ayonna', + 'Mesha', + 'Tyeshia', + 'Tiffiney', + 'Tyara', + 'Azuri', + 'Merideth', + 'Hermie', + 'Leaner', + 'Mendi', + 'Kanoelani', + 'Kadeidra', + 'Akeela', + 'Lin', + 'Mindel', + 'Lashell', + 'Meegan', + 'Ia', + 'Ellamae', + 'Jasmen', + 'Nechuma', + 'Romilda', + 'Hiilei', + 'Osmara', + 'Keidy', + 'Rianne', + 'Afia', + 'Teylor', + 'Raquelle', + 'Grizelda', + 'Tasfia', + 'Laquasha', + 'Tandra', + 'Maeghan', + 'Kameshia', + 'Alara', + 'Emina', + 'Delaina', + 'Jacquetta', + 'Christena', + 'Topanga', + 'Viviann', + 'Eboney', + 'Kasha', + 'Sativa', + 'Secilia', + 'Niomi', + 'Neena', + 'Tanji', + 'Shandy', + 'Corryn', + 'Esly', + 'Silka', + 'Sanaii', + 'Annais', + 'Kaitlynne', + 'Epiphany', + 'Maniya', + 'Mali', + 'Madigan', + 'Sanii', + 'Jaeleen', + 'Faria', + 'Maralyn', + 'Johnae', + 'Lekesha', + 'Sharry', + 'Latecia', + 'Kimberl', + 'Charita', + 'Modean', + 'Marrie', + 'Lielle', + 'Zeina', + 'Pessel', + 'Sameera', + 'Eleonora', + 'Jannatul', + 'Coryn', + 'Dustie', + 'Demitria', + 'Jacqlyn', + 'Nekisha', + 'Latrecia', + 'Rabecca', + 'Malaysha', + 'Lugenia', + 'Elese', + 'Myrissa', + 'Lucrecia', + 'Lysandra', + 'Tarryn', + 'Tammey', + 'Bonnita', + 'Shiffy', + 'Shirel', + 'Clariza', + 'Analis', + 'Rechy', + 'Nusaiba', + 'Manahil', + 'Chamisa', + 'Almetta', + 'Moncia', + 'Leba', + 'Jeilyn', + 'Earnesteen', + 'Mennie', + 'Kieara', + 'Sheina', + 'Yo', + 'Sharnice', + 'Ravin', + 'Daisi', + 'Britini', + 'Carlina', + 'Arisa', + 'Margy', + 'Whitnee', + 'Krysti', + 'Odean', + 'Darlys', + 'Janita', + 'Donnetta', + 'Guynell', + 'Neomia', + 'Loyalty', + 'Serra', + 'Kaysie', + 'Preciosa', + 'Earleen', + 'Shatoria', + 'Kourtnie', + 'Kana', + 'Jahnavi', + 'Kyarra', + 'Licet', + 'Railyn', + 'Delisha', + 'Flordia', + 'Arsema', + 'Kena', + 'Kaelah', + 'Kashia', + 'Emonie', + 'Izola', + 'Linsay', + 'Naibe', + 'Natallie', + 'Rosi', + 'Taline', + 'Cortina', + 'Annett', + 'Kadi', + 'Lindsi', + 'Lasasha', + 'Tamre', + 'Yenny', + 'Yasaman', + 'Shawnice', + 'Thi', + 'Jannel', + 'Kaleen', + 'Demitra', + 'Meisha', + 'Mahira', + 'Emmanuela', + 'Janaiya', + 'Rechel', + 'Nazifa', + 'Zeynep', + 'Shalena', + 'Hila', + 'Ailish', + 'Altovise', + 'Anabeth', + 'Anavictoria', + 'Averey', + 'Berlynn', + 'Alitza', + 'Adelynne', + 'Aiva', + 'Alenna', + 'Harlowe', + 'Camrynn', + 'Daphnie', + 'Ezri', + 'Lanna', + 'Lua', + 'Maddilynn', + 'Maeva', + 'Maytte', + 'Jovi', + 'Karalyn', + 'Kataleah', + 'Kaylana', + 'Milliana', + 'Surveen', + 'Veera', + 'Nimrat', + 'Nimrit', + 'Radha', + 'Roisin', + 'Senna', + 'Ruhi', + 'Saja', + 'Glenice', + 'Damiana', + 'Mikeria', + 'Lakeria', + 'Yulia', + 'Zanna', + 'Lynnae', + 'Illa', + 'Buelah', + 'Novis', + 'Johnye', + 'Valree', + 'Santiaga', + 'Modell', + 'Maydell', + 'Elfida', + 'Charlyne', + 'Argentina', + 'Terica', + 'Kiandra', + 'Tangi', + 'Pascuala', + 'Narcisa', + 'Macaria', + 'Thomasa', + 'Verta', + 'Eulogia', + 'Trellis', + 'Tavaria', + 'Dakayla', + 'Oneita', + 'Kimberlynn', + 'Aslee', + 'Jenascia', + 'Shamaria', + 'Lakely', + 'Etna', + 'Gilberte', + 'Glena', + 'Delorse', + 'Margrett', + 'Endia', + 'Buena', + 'Alvilda', + 'Domitila', + 'Jasmaine', + 'Jaquita', + 'Shontavia', + 'Roneshia', + 'Leasa', + 'Feliciana', + 'Allyana', + 'Anaia', + 'Annalyn', + 'Ayane', + 'Belladonna', + 'Adanely', + 'Akshaya', + 'Aleiyah', + 'Tereasa', + 'Antonisha', + 'Darlah', + 'Dhalia', + 'Dianelly', + 'Elika', + 'Camillia', + 'Leonila', + 'Manreet', + 'Jazzlin', + 'Kaiulani', + 'Kashvi', + 'Talayah', + 'Viana', + 'Ximenna', + 'Shaylah', + 'Quorra', + 'Anagha', + 'Annalea', + 'Jaleyah', + 'Bethanny', + 'Zophia', + 'Alegria', + 'Advika', + 'Taneika', + 'Marye', + 'Latorya', + 'Sayler', + 'Nara', + 'Nithya', + 'Phoenyx', + 'Saiya', + 'Mellany', + 'Yazlin', + 'Adalena', + 'Adya', + 'Aliviah', + 'Aalia', + 'Rickia', + 'Eliyana', + 'Arella', + 'Audris', + 'Auria', + 'Avantika', + 'Aylani', + 'Beya', + 'Camilah', + 'Kaede', + 'Laylonie', + 'Jayani', + 'Katara', + 'Hera', + 'Audrea', + 'Nataley', + 'Nazli', + 'Neyla', + 'Noya', + 'Srinidhi', + 'Pranavi', + 'Sareen', + 'Satya', + 'Terika', + 'Zamora', + 'Jimmye', + 'Brigida', + 'Shereka', + 'Widline', + 'Natori', + 'Dorthie', + 'Berit', + 'Aretta', + 'Svea', + 'Wenona', + 'Amera', + 'Nayah', + 'Lollie', + 'Genice', + 'Fabianna', + 'Nazaria', + 'Edra', + 'Jamariah', + 'Willine', + 'Madolyn', + 'Wanell', + 'Lucetta', + 'Eudora', + 'Adda', + 'Shariah', + 'Jaelle', + 'Jalena', + 'Annelle', + 'Solveig', + 'Autherine', + 'Nobie', + 'Izora', + 'Eudell', + 'Wyolene', + 'Mariangel', + 'Mayar', + 'Luevenia', + 'Eniyah', + 'Lilie', + 'Eliany', + 'Ivyonna', + 'Beadie', + 'Zeta', + 'Merita', + 'Valjean', + 'Delbra', + 'Alanys', + 'Camiyah', + 'Edyth', + 'Kanya', + 'Perina', + 'Catelynn', + 'Angelisse', + 'Relda', + 'Eathel', + 'Kerrington', + 'Lyriq', + 'Brita', + 'Meda', + 'Zanya', + 'Emileigh', + 'Aracelys', + 'Lisania', + 'Evalena', + 'Traniya', + 'Janiyla', + 'Syesha', + 'Ahmya', + 'Camora', + 'Armonie', + 'Beula', + 'Veva', + 'Kateria', + 'Harumi', + 'Kimiyo', + 'Tangie', + 'Amayrany', + 'Alexiah', + 'Alyn', + 'Tokie', + 'Masayo', + 'Makenzee', + 'Arieana', + 'Asayo', + 'Seirra', + 'Elfrida', + 'Ariona', + 'Masue', + 'Mizuki', + 'Liliane', + 'Malanie', + 'Sabreen', + 'Yuritza', + 'Shanautica', + 'Kateleen', + 'Montanna', + 'Tiona', + 'Theresia', + 'Vernia', + 'Mahayla', + 'Glynna', + 'Shaelynn', + 'Isabelly', + 'Aileth', + 'Ailie', + 'Melvia', + 'Sherrel', + 'Ivah', + 'Himani', + 'Marayah', + 'Melane', + 'Evanie', + 'Atalia', + 'Athalia', + 'Bethsy', + 'Betzi', + 'California', + 'Bryonna', + 'Yaretsy', + 'Zamara', + 'Sanyah', + 'Gaylynn', + 'Vitoria', + 'Yoshino', + 'Hatsumi', + 'Tatsuko', + 'Samika', + 'Maili', + 'Charnae', + 'Jamilla', + 'Vieno', + 'Rylei', + 'Vanita', + 'Hydia', + 'Carmyn', + 'Kenslie', + 'Maryhelen', + 'Lamees', + 'Lilley', + 'Haunani', + 'Pualani', + 'Mikiyah', + 'Lovina', + 'Janith', + 'Kanoe', + 'Anouk', + 'Mayerly', + 'Kiele', + 'Lexia', + 'Janani', + 'Berlinda', + 'Belma', + 'Inayah', + 'Saloma', + 'Anely', + 'Anjolina', + 'Devonna', + 'Nikhita', + 'Nayana', + 'Naidely', + 'Hina', + 'Ismerai', + 'Daisie', + 'Sitlaly', + 'Yahayra', + 'Trinidy', + 'Vallery', + 'Ceaira', + 'Floretta', + 'Lavena', + 'Shawntavia', + 'Dessa', + 'Tareva', + 'Iyanla', + 'Kania', + 'Shakiya', + 'Latora', + 'Hermila', + 'Clora', + 'Tiyanna', + 'Saydie', + 'Sherlene', + 'Trixie', + 'Nadiyah', + 'Zarria', + 'Saidy', + 'Sabriya', + 'Keirra', + 'Leeana', + 'Leianna', + 'Jaia', + 'Ishanvi', + 'Ailed', + 'Fathima', + 'Hansika', + 'Delailah', + 'Caliah', + 'Dayleen', + 'Jolisa', + 'Sallye', + 'Levonia', + 'Tula', + 'Kristene', + 'Alanni', + 'Aleiah', + 'Aeva', + 'Ilean', + 'Annet', + 'Lateshia', + 'Markesha', + 'Nikol', + 'Nadolyn', + 'Kimyatta', + 'Ercilia', + 'Sheliah', + 'Heiley', + 'Metztli', + 'Teyla', + 'Saranya', + 'Tanishka', + 'Kayana', + 'Donnamae', + 'Lajoyce', + 'Kemya', + 'Kemora', + 'Jozelyn', + 'Keili', + 'Jaydy', + 'Linzy', + 'Marelin', + 'Melaney', + 'Aleksa', + 'Alynah', + 'Elyza', + 'Emmery', + 'Angeleen', + 'Annica', + 'Bindi', + 'Demya', + 'Nayleen', + 'Sadee', + 'Samah', + 'Shylee', + 'Talula', + 'Vannia', + 'Yarelli', + 'Zohar', + 'Miangel', + 'Orla', + 'Sundra', + 'Korinne', + 'Taniesha', + 'Zaliyah', + 'Zionna', + 'Amariyah', + 'Loris', + 'Cruzita', + 'Landa', + 'Eduvina', + 'Ileanna', + 'Ileene', + 'Jesselle', + 'Daviana', + 'Eleny', + 'Marijane', + 'Okla', + 'Violanda', + 'Dorma', + 'Leoma', + 'Esperansa', + 'Shanreka', + 'Baudelia', + 'Teasia', + 'Aubrei', + 'Jeree', + 'Ortencia', + 'Melida', + 'Pernie', + 'Sweetie', + 'Arelly', + 'Ariday', + 'Bhavya', + 'Aiyanah', + 'Akshita', + 'Ginette', + 'Docia', + 'Pegeen', + 'Alaynah', + 'Allanah', + 'Daniah', + 'Loriana', + 'Kenly', + 'Kenli', + 'Kendahl', + 'Kenady', + 'Senora', + 'Hetal', + 'Aloha', + 'Barri', + 'Shaniquah', + 'Feather', + 'Rica', + 'Adriann', + 'Fleta', + 'Shontel', + 'Kynisha', + 'Nahima', + 'Myracle', + 'Syniah', + 'Jomarie', + 'Leeandra', + 'Maylie', + 'Marijose', + 'Jaley', + 'Sydnei', + 'Amariya', + 'Alysandra', + 'Damia', + 'Laurieann', + 'Lucecita', + 'Miosotis', + 'Shelvy', + 'Bernina', + 'Darice', + 'Dorrie', + 'Myrta', + 'Yoko', + 'Vara', + 'Joanmarie', + 'Kerryann', + 'Carmesa', + 'Kenzington', + 'Oaklyn', + 'Shelbia', + 'Arhianna', + 'Ardyn', + 'Amarachi', + 'Cydnee', + 'Chloey', + 'Brailee', + 'Aily', + 'Rosette', + 'Geryl', + 'Luba', + 'Marguerita', + 'Ayannah', + 'Deziyah', + 'Lurdes', + 'Dawnelle', + 'Reiko', + 'Brynli', + 'Tenlee', + 'Kynadee', + 'Emersen', + 'Josilyn', + 'Jazalyn', + 'Maleyah', + 'Cozette', + 'Xoe', + 'Syria', + 'Charyl', + 'Gita', + 'Aniaya', + 'Yulemni', + 'Joleigh', + 'Kenzy', + 'Logann', + 'Genesys', + 'Cherita', + 'Trenise', + 'Stpehanie', + 'Riann', + 'Matilyn', + 'Akisha', + 'Coralee', + 'Presli', + 'Yariana', + 'Edda', + 'Lisabeth', + 'Farm', + 'Dennice', + 'Deepa', + 'Chiffon', + 'Alyzea', + 'Alexas', + 'Emylee', + 'Joellyn', + 'Zo', + 'Marybell', + 'Sapna', + 'Khristina', + 'Kellyanne', + 'Chrystie', + 'Damary', + 'Graziella', + 'Tene', + 'Shakisha', + 'Shirelle', + 'Gwynne', + 'Insha', + 'Lydiann', + 'Cuba', + 'Cortnie', + 'Denelle', + 'Huyen', + 'Brieann', + 'Cindia', + 'Shalina', + 'Linnette', + 'Kiamesha', + 'Anecia', + 'Brinna', + 'Kewanna', + 'Malke', + 'Yira', + 'Rashidah', + 'Karicia', + 'Chrislyn', + 'Idali', + 'Zandria', + 'Ruta', + 'Toshi', + 'Daena', + 'Aneliz', + 'Cherese', + 'Brandalyn', + 'Brieanne', + 'Chistina', + 'Denys', + 'Nyisha', + 'Lissie', + 'Sherine', + 'Marisal', + 'Tuwana', + 'Zyonna', + 'Shady', + 'Patrisha', + 'Laniece', + 'Jessamyn', + 'Letticia', + 'Shirlie', + 'Miyo', + 'Marilouise', + 'Yukiye', + 'Ltanya', + 'Geralynn', + 'Anastazia', + 'Mitzie', + 'Lluliana', + 'Rozanna', + 'Magalie', + 'Salima', + 'Bevin', + 'Gaudy', + 'Ieasha', + 'Makia', + 'Sacheen', + 'Sherene', + 'Mataya', + 'Hatsuye', + 'Chiyeko', + 'Devanny', + 'Nasya', + 'Odyssey', + 'Tunisia', + 'Caldonia', + 'Marsi', + 'Mindee', + 'Tamy', + 'Sherill', + 'Tsitsiki', + 'Arva', + 'Gayleen', + 'Kimmy', + 'Lenette', + 'Roxan', + 'Leanora', + 'Charlena', + 'Claudina', + 'Danise', + 'Denell', + 'Eydie', + 'Irish', + 'Hydeia', + 'Nichele', + 'Ronica', + 'Temre', + 'Cindra', + 'Vincenta', + 'Zyra', + 'Larita', + 'Jodine', + 'Ewelina', + 'Madylin', + 'Kinzleigh', + 'Malone', + 'Layken', + 'Verity', + 'Tinleigh', + 'Sophi', + 'Skyleigh', + 'Stanislawa', + 'Rylinn', + 'Natalynn', + 'Marlei', + 'Rhylie', + 'Payslee', + 'Paxtyn', + 'Brittyn', + 'Alaynna', + 'Avory', + 'Aubriee', + 'Jacqui', + 'Aseel', + 'Jannell', + 'Simra', + 'Raneem', + 'Kellene', + 'Shellee', + 'Tish', + 'Lashauna', + 'Ashira', + 'Sharrie', + 'Donnette', + 'Milarain', + 'Toshia', + 'Shariyah', + 'Dariah', + 'Gustava', + 'Leotha', + 'Sherelle', + 'Lindi', + 'Luanna', + 'Shanan', + 'Arelys', + 'Nyema', + 'Errin', + 'Fredrica', + 'Dhriti', + 'Yashvi', + 'Gaile', + 'Ermalinda', + 'Gregorita', + 'Klynn', + 'Kaedence', + 'Zaila', + 'Yaritzi', + 'Taylyn', + 'Tailyn', + 'Milka', + 'Maesyn', + 'Macyn', + 'Riyah', + 'Alleigh', + 'Aracelli', + 'Hadlie', + 'Iza', + 'Riddhi', + 'Kathleene', + 'Darely', + 'Eleyna', + 'Analiya', + 'Fanchon', + 'Allyce', + 'Jasma', + 'Porschia', + 'Deberah', + 'Zoi', + 'Sherlyne', + 'Favour', + 'Shakari', + 'Mckenzy', + 'Makinzie', + 'Maahi', + 'Jacqualine', + 'Nancyann', + 'Ronne', + 'Charmane', + 'Martie', + 'Leane', + 'Kama', + 'Corrinne', + 'Vangie', + 'Jonni', + 'Michon', + 'Sharise', + 'Shawnie', + 'Joane', + 'Rosary', + 'Noretta', + 'Zaylynn', + 'Paislie', + 'Infinity', + 'Amaryllis', + 'Altair', + 'Cookie', + 'Danyella', + 'Collyns', + 'Chrislynn', + 'Bryley', + 'Brelynn', + 'Finleigh', + 'Evianna', + 'Flavia', + 'Wilhemina', + 'Jaeliana', + 'Taija', + 'Naiomi', + 'Jennika', + 'Jenika', + 'Jaicee', + 'Laurice', + 'Ashaunti', + 'Alyxandria', + 'Delfinia', + 'Tyiesha', + 'Petrita', + 'Fedelina', + 'Eufelia', + 'Marshae', + 'Marquesha', + 'Feloniz', + 'Tyliyah', + 'Nadene', + 'Natascha', + 'Shawnette', + 'Jamese', + 'Tashay', + 'Mckenzee', + 'Mckinsey', + 'Langley', + 'Kensleigh', + 'Karolyna', + 'Coralyn', + 'Grethel', + 'Baylei', + 'Ariany', + 'Mekenzie', + 'Whitlee', + 'Sayde', + 'Willena', + 'Tzipporah', + 'Afsana', + 'Kearra', + 'Marialy', + 'Quiara', + 'Jing', + 'Dorathea', + 'Rachelann', + 'Melissaann', + 'Jeanett', + 'Jensine', + 'Jessicaann', + 'Ellesse', + 'Kaula', + 'Calley', + 'Malkie', + 'Shenelle', + 'Sheela', + 'Steffi', + 'Shadia', + 'Marielis', + 'Saima', + 'Tiarah', + 'Reginia', + 'Shaquala', + 'Shadiamond', + 'Kallista', + 'Allee', + 'Allexis', + 'Nakeya', + 'Reshma', + 'Sosha', + 'Kendrea', + 'Imalay', + 'Kyong', + 'Sharmin', + 'Sorah', + 'Alayshia', + 'Katja', + 'Chavie', + 'Farzana', + 'Lanasia', + 'Khayla', + 'Jamella', + 'Diva', + 'Ericca', + 'Brettany', + 'Imunique', + 'Tiasia', + 'Tajae', + 'Sidra', + 'Chelbi', + 'Kourtni', + 'Lamisha', + 'Krystyn', + 'Maly', + 'Mirtha', + 'Nary', + 'Nuria', + 'Falicia', + 'Zilpha', + 'Keyasia', + 'Ranisha', + 'Garnetta', + 'Alexxus', + 'Hae', + 'Herma', + 'Tasheena', + 'Philicia', + 'Fotini', + 'Avanell', + 'Czarina', + 'Kindle', + 'Antoinet', + 'Constanc', + 'Cassondr', + 'Destanee', + 'Christinia', + 'Shalisa', + 'Stepahnie', + 'Sopheap', + 'Somaly', + 'Shalane', + 'Saran', + 'Alaycia', + 'Carolynne', + 'Nikolette', + 'Saphire', + 'Dominigue', + 'Channa', + 'Leva', + 'Starquasia', + 'Shyan', + 'Sabah', + 'Shakiera', + 'Nagely', + 'Hajar', + 'Keniya', + 'Anhthu', + 'Ashle', + 'Taira', + 'Meline', + 'Rebeckah', + 'Daritza', + 'Kaysha', + 'Kathrin', + 'Edit', + 'Jennae', + 'Kaja', + 'Molli', + 'Hildreth', + 'Elyssia', + 'Keandrea', + 'Courtlyn', + 'Cova', + 'Kyndle', + 'Kadisha', + 'Mitchelle', + 'Chabeli', + 'Ashlen', + 'Feiga', + 'Shakena', + 'Lakeia', + 'Jehan', + 'Karianne', + 'Renisha', + 'Crystalyn', + 'Blia', + 'Amanada', + 'Neiba', + 'Oyuki', + 'Lianet', + 'Javaria', + 'Praise', + 'Sagal', + 'Avaleigh', + 'Amoni', + 'Fadumo', + 'Debhora', + 'Sharol', + 'Sahalie', + 'Aleana', + 'Dezire', + 'Catalia', + 'Barbarann', + 'Raelin', + 'Reniyah', + 'Jeniyah', + 'Jaziya', + 'Wilhemenia', + 'Wavie', + 'Modestine', + 'Tariah', + 'Cathern', + 'Asenath', + 'Nakya', + 'Reeva', + 'Tkai', + 'Orva', + 'Theora', + 'Brookie', + 'Breyonna', + 'Ellagrace', + 'Kaliya', + 'Jemimah', + 'Ahna', + 'Zetta', + 'Tanyia', + 'Dicie', + 'Malasia', + 'Janvi', + 'Talaysia', + 'Kaybree', + 'Teia', + 'Robertha', + 'Tilda', + 'Marykatherine', + 'Gusta', + 'Gola', + 'Malta', + 'Nija', + 'Kaija', + 'Tamaria', + 'Chyann', + 'Davianna', + 'Gae', + 'Ruther', + 'Kennadee', + 'Arvella', + 'Ashonti', + 'Euphemia', + 'Teyanna', + 'Jahnya', + 'Jamariya', + 'Ceanna', + 'Francenia', + 'Charletta', + 'Catheryn', + 'Theodosia', + 'Magdaline', + 'Samariah', + 'Jamara', + 'Nehemie', + 'Mikenzie', + 'Marielys', + 'Keilany', + 'Bernardita', + 'Marketa', + 'Takya', + 'Frona', + 'Draxie', + 'Genell', + 'Celesta', + 'Deloria', + 'Sister', + 'Icy', + 'Mardi', + 'Florance', + 'Azari', + 'Ahmiyah', + 'Chaniya', + 'Rheda', + 'Kateland', + 'Rielle', + 'Kjersten', + 'Olivette', + 'Tita', + 'Tharon', + 'Briasia', + 'Pakou', + 'Raniah', + 'Janaria', + 'Jaliya', + 'Alexiana', + 'Alayja', + 'Ailea', + 'Camiya', + 'Versa', + 'Vertell', + 'Loyola', + 'Mckelle', + 'Ebonique', + 'Jaynie', + 'Shamiah', + 'Keela', + 'Laterrica', + 'Fidelia', + 'Annia', + 'Rosslyn', + 'Robynn', + 'Darlynn', + 'Shakiara', + 'Shakeira', + 'Olinda', + 'Kionna', + 'Annslee', + 'Rudine', + 'Teonna', + 'Rudene', + 'Latrece', + 'Wynette', + 'Damiya', + 'Zonnie', + 'Jenne', + 'Deeanne', + 'Doree', + 'Jennilyn', + 'Lari', + 'Lourie', + 'Tedi', + 'Deaira', + 'Deairra', + 'Fatuma', + 'Gearldean', + 'Genise', + 'Karlyn', + 'Arleta', + 'Alla', + 'Donie', + 'Lady', + 'Rheba', + 'Nuha', + 'Olita', + 'Elzina', + 'Lutricia', + 'Tauna', + 'Teasha', + 'Elberta', + 'Jeralyn', + 'Shaketa', + 'Elonda', + 'Lafondra', + 'Shelle', + 'Lamiya', + 'Lejla', + 'Labria', + 'Wessie', + 'Cleola', + 'Suad', + 'Andretta', + 'Piccola', + 'Jadalee', + 'Louanna', + 'Donabelle', + 'Shauntel', + 'Vannie', + 'Naomia', + 'Ludell', + 'Ikram', + 'Ariyonna', + 'Anaelle', + 'Pamila', + 'Scheryl', + 'Kandee', + 'Donella', + 'Vicie', + 'Tajah', + 'Jodeen', + 'Debborah', + 'Varvara', + 'Jalisha', + 'Paw', + 'Tranette', + 'Ruwayda', + 'Jeanice', + 'Lowana', + 'Curlie', + 'Viveca', + 'Tommi', + 'Lynnel', + 'Shawneen', + 'Tora', + 'Ikhlas', + 'Delene', + 'Jillyn', + 'Abria', + 'Blondine', + 'Katharyn', + 'Gini', + 'Lynnell', + 'Laurey', + 'Ikran', + 'Madell', + 'Dura', + 'Trenia', + 'Arsie', + 'Runell', + 'Lawan', + 'Georgeanna', + 'Nashay', + 'Lasha', + 'Michi', + 'Arloa', + 'Kazuye', + 'Arnette', + 'Morghan', + 'Allure', + 'Kiyo', + 'Fusaye', + 'Sebrena', + 'Kikuye', + 'Mykia', + 'Soon', + 'Kyung', + 'Maysa', + 'Manessa', + 'Ople', + 'Amyre', + 'Katera', + 'Danaya', + 'Dorothey', + 'Shahidah', + 'Soliana', + 'Concettina', + 'Delphie', + 'Aqueelah', + 'Cassadee', + 'Larayne', + 'Burnette', + 'Diona', + 'Stasha', + 'Sheria', + 'Luciel', + 'Anise', + 'Cumi', + 'Marillyn', + 'Domenique', + 'Sumiye', + 'Masaye', + 'Imojean', + 'Louetta', + 'Taimi', + 'Berdie', + 'Jyl', + 'Cyrilla', + 'Kearstin', + 'Tosca', + 'Billee', + 'Milda', + 'Rema', + 'Tyne', + 'Altamease', + 'Aleaha', + 'Malaina', + 'Jersie', + 'Nadyne', + 'Suhailah', + 'Reghan', + 'Burma', + 'Kamyra', + 'Geraldean', + 'Ivalee', + 'Waunita', + 'Aritza', + 'Madalynne', + 'Talaya', + 'Azura', + 'Aldonia', + 'Robinette', + 'Ameenah', + 'Abeer', + 'Yamilette', + 'Tanae', + 'Mertha', + 'Jamirah', + 'Chun', + 'Avayah', + 'Janayah', + 'Bena', + 'Mahiyah', + 'Karn', + 'Kristien', + 'Mikesha', + 'Eriel', + 'Kemoni', + 'Aziya', + 'Raigan', + 'Rissie', + 'Tenna', + 'Tambria', + 'Birdell', + 'Almena', + 'Jonisha', + 'Marcey', + 'Rosebud', + 'Lakevia', + 'Shateria', + 'Nelia', + 'Rilda', + 'Doshie', + 'Onzell', + 'Safiyyah', + 'Lorilee', + 'Shiane', + 'Gauri', + 'Ashiya', + 'Yaileen', + 'Vendetta', + 'Margaretmary', + 'Telisa', + 'Imogean', + 'Sheryn', + 'Nance', + 'Mariette', + 'Keerthana', + 'Rosellen', + 'Michelene', + 'Kamrie', + 'Mayci', + 'Jerzi', + 'Vermelle', + 'Tondra', + 'Dorethea', + 'Wannetta', + 'Tilly', + 'Brightyn', + 'Patt', + 'Lynae', + 'Willo', + 'Cloma', + 'Yailyn', + 'Takeria', + 'Janyiah', + 'Rasheema', + 'Nafeesa', + 'Rosene', + 'Kellianne', + 'Taccara', + 'Quanda', + 'Patsie', + 'Chaquita', + 'Shakelia', + 'Guerline', + 'Tashika', + 'Taneesha', + 'Fatme', + 'Marliss', + 'Hye', + 'Marjo', + 'Meggie', + 'Maye', + 'Walline', + 'Dodi', + 'Kristyna', + 'Aliyyah', + 'Latravia', + 'Diania', + 'Elta', + 'Oralee', + 'Nikkita', + 'Rasha', + 'Sharena', + 'Tecora', + 'Pluma', + 'Ovell', + 'Keeya', + 'Dayja', + 'Sherrian', + 'Jinnie', + 'Ekta', + 'Javonda', + 'Shantrice', + 'Dava', + 'Kimbley', + 'Lafonda', + 'Lasonja', + 'Hiilani', + 'Danay', + 'Avree', + 'Kelliann', + 'Keasha', + 'Kimmarie', + 'Jannely', + 'Manasi', + 'Moncerat', + 'Miyu', + 'Jullianna', + 'Joelene', + 'Ynez', + 'Yazmeen', + 'Yasamin', + 'Syann', + 'Surena', + 'Tresia', + 'Trecia', + 'Sonjia', + 'Hokulani', + 'Amarilys', + 'Bethzaida', + 'Noraida', + 'Dietra', + 'Nealie', + 'Charice', + 'Alicea', + 'Jozie', + 'Delzora', + 'Jordis', + 'Jolett', + 'Kahlen', + 'Kallee', + 'Natilee', + 'Pecolia', + 'Iyari', + 'Shandrell', + 'Quintella', + 'Monchel', + 'Tysha', + 'Vanetta', + 'Shawneequa', + 'Odesser', + 'Lareina', + 'Jannifer', + 'Kinya', + 'Lateesha', + 'Dvora', + 'Katrin', + 'Denene', + 'Diondra', + 'Ciclali', + 'Sula', + 'Talena', + 'Afrika', + 'Cheron', + 'Emireth', + 'Cadee', + 'Jlyn', + 'Jermya', + 'Alyia', + 'Sitlali', + 'Sissy', + 'Felita', + 'Kerith', + 'Wendolyn', + 'Chaundra', + 'Angle', + 'Gladies', + 'Meygan', + 'Sereniti', + 'Saryn', + 'Vielka', + 'Tirzah', + 'Lynnmarie', + 'Lisanne', + 'Yliana', + 'Yamilett', + 'Keyoka', + 'Laquanta', + 'Teneshia', + 'Trenna', + 'Veronda', + 'Fronie', + 'Carlette', + 'Lanetta', + 'Raynelle', + 'Tianne', + 'Siria', + 'Mayda', + 'Lorien', + 'Celica', + 'Tabbitha', + 'Kayanna', + 'Julitza', + 'Kylia', + 'Heavenlee', + 'Nikka', + 'Rachana', + 'Mekenna', + 'Maritere', + 'Ai', + 'Angelisa', + 'Anysa', + 'Basia', + 'Ilka', + 'Geanine', + 'Kedra', + 'Caila', + 'Deysy', + 'Emilyann', + 'Samera', + 'Mackinzie', + 'Lynzie', + 'Akela', + 'Navpreet', + 'Reylene', + 'Reyanna', + 'Kathlynn', + 'Kiaira', + 'Guiselle', + 'Brinn', + 'Jerelyn', + 'Lorel', + 'Alandra', + 'Ardyth', + 'Kloee', + 'Mellody', + 'Carlisa', + 'Martinique', + 'Damali', + 'Cassandre', + 'Ivanelle', + 'Janaan', + 'Shontay', + 'Tamieka', + 'Tashema', + 'Irmalinda', + 'Tayna', + 'Berdena', + 'Janika', + 'Shauntay', + 'Nikea', + 'Ekaterini', + 'Glendaly', + 'Vernee', + 'Kang', + 'Candise', + 'Jamica', + 'Andera', + 'Katheleen', + 'Annagrace', + 'Bradleigh', + 'Kissy', + 'Lachandra', + 'Tamikia', + 'Shevon', + 'Wardean', + 'Betina', + 'Marcee', + 'Evia', + 'Carry', + 'Marica', + 'Tiwana', + 'Stacye', + 'Theressa', + 'Torsha', + 'Allayna', + 'Betania', + 'Berania', + 'Claryssa', + 'Clarise', + 'Cassidi', + 'Mehana', + 'Janella', + 'Mackenzy', + 'Kaeleigh', + 'Sanoe', + 'Neysa', + 'Shawntee', + 'Shannah', + 'Tihani', + 'Willye', + 'Zalma', + 'Serrina', + 'Shealyn', + 'Hiiaka', + 'Jeselle', + 'Mitsy', + 'Kela', + 'Aquila', + 'Marikay', + 'Christella', + 'Tameria', + 'Ebelina', + 'Maricar', + 'Shalimar', + 'Yanin', + 'Xuan', + 'Tifany', + 'Thy', + 'Quynh', + 'Shronda', + 'Kysha', + 'Lular', + 'Danee', + 'Christyna', + 'Antonieta', + 'Chara', + 'Bich', + 'Tishana', + 'Sophy', + 'Shoshanna', + 'Adrea', + 'Lavaun', + 'Keryn', + 'Okema', + 'Njeri', + 'Ashaki', + 'Alegra', + 'Anapatricia', + 'Terena', + 'Tuere', + 'Ensley', + 'Geraline', + 'Corrinna', + 'Carlye', + 'Dawnielle', + 'Fancy', + 'Akiba', + 'Korrie', + 'Lavita', + 'Chisa', + 'Lakishia', + 'Mandisa', + 'Lalita', + 'Sakeena', + 'Noami', + 'Olivea', + 'Lucilla', + 'Marialuiza', + 'Radonna', + 'Magaline', + 'Minda', + 'Annah', + 'Mitsuyo', + 'Kameko', + 'Miyako', + 'Satsuki', + 'Hatsuyo', + 'Aimie', + 'Jalexis', + 'Haruyo', + 'Tokiko', + 'Matsuyo', + 'Myiah', + 'Natalye', + 'Priseis', + 'Yeraldi', + 'Natsue', + 'Nobue', + 'Zyria', + 'Tierany', + 'Samyia', + 'Rhema', + 'Chiyo', + 'Lailoni', + 'Momoka', + 'Miku', + 'Havanna', + 'Izela', + 'Kendy', + 'Rashanda', + 'Aleysha', + 'Sherlita', + 'Tamana', + 'Kikuyo', + 'Tapanga', + 'Shauntell', + 'Adithi', + 'Chiamaka', + 'Devika', + 'Angy', + 'Arwyn', + 'Aparna', + 'Anneka', + 'Betzayra', + 'Analuiza', + 'Blondie', + 'October', + 'Yarexi', + 'Yarethzi', + 'Annaclaire', + 'Rosabel', + 'Jerlene', + 'Clelia', + 'Jatara', + 'Anzley', + 'Zamaya', + 'Venera', + 'Kalleigh', + 'Jaylynne', + 'Kaylor', + 'Milli', + 'Nelsy', + 'Laycee', + 'Arayah', + 'Betzabe', + 'Bethzi', + 'Haidy', + 'Chayla', + 'Elizah', + 'Evoleth', + 'Edyn', + 'Cyniah', + 'December', + 'Amerika', + 'Analea', + 'Ayshia', + 'Alauna', + 'Shamica', + 'Peaches', + 'Shenee', + 'Letecia', + 'Arminda', + 'Yolander', + 'Amariona', + 'Kaithlyn', + 'Jasiya', + 'Niharika', + 'Sareena', + 'Maryana', + 'Melanye', + 'Solei', + 'Suhey', + 'Soyla', + 'Koral', + 'Lilee', + 'Mercede', + 'Pennye', + 'Yumeka', + 'Mazel', + 'Vani', + 'Pattiann', + 'Shirell', + 'Carmencita', + 'Delayla', + 'Hailyn', + 'Brena', + 'Daana', + 'Lenise', + 'Ryhanna', + 'Lorely', + 'Tiannah', + 'Zabdi', + 'Kammy', + 'Josslynn', + 'Keilee', + 'Kamrynn', + 'Itza', + 'Jaidy', + 'Cherly', + 'Ladeana', + 'Memory', + 'Maresa', + 'Shauntae', + 'Risha', + 'Ilisa', + 'Debraann', + 'Gavriela', + 'Jenai', + 'Suzzette', + 'Mailani', + 'Leiloni', + 'Manasa', + 'Malin', + 'Faythe', + 'Haylei', + 'Haili', + 'Gwenivere', + 'Jamilette', + 'Naydeline', + 'Sakshi', + 'Nayda', + 'Nuala', + 'Chelsae', + 'Berenize', + 'Bahar', + 'Arpi', + 'Tearra', + 'Metta', + 'Lethia', + 'Akanksha', + 'Danine', + 'Alayne', + 'Jeanann', + 'Loyda', + 'Yamna', + 'Marsela', + 'Jolinda', + 'Leina', + 'Mariane', + 'Kaydince', + 'Etsuko', + 'Tinika', + 'Lashona', + 'Chidinma', + 'Jazell', + 'Derenda', + 'Cylinda', + 'Amaiah', + 'Alyzza', + 'Abbygayle', + 'Tashae', + 'Tesa', + 'Sarra', + 'Tanasha', + 'Latoy', + 'Dawnell', + 'Corinn', + 'Charmain', + 'Odetta', + 'Kimiya', + 'Kiaya', + 'Mairin', + 'Maelani', + 'Halena', + 'Dorianne', + 'Ilia', + 'Cheyenna', + 'Noora', + 'Nareh', + 'Namrata', + 'Sholanda', + 'Sita', + 'Dunia', + 'Betzayda', + 'Analissa', + 'Amulya', + 'Annaka', + 'Anneth', + 'Anaalicia', + 'Noemie', + 'Leni', + 'Robyne', + 'Skyleen', + 'Tiphanie', + 'Belmira', + 'Francelina', + 'Kreindy', + 'Kiri', + 'Kristena', + 'Lawren', + 'Christyn', + 'Deicy', + 'Hollyann', + 'Jamela', + 'Eriko', + 'Sotheary', + 'Lekeshia', + 'Onica', + 'Micole', + 'Marlisa', + 'Aqsa', + 'Bayla', + 'Abigal', + 'Charny', + 'Shaquira', + 'Rabab', + 'Yasemin', + 'Keishla', + 'Donasia', + 'Ellamarie', + 'Darianny', + 'Dahiana', + 'Areeba', + 'Shaquasha', + 'Oneisha', + 'Daicy', + 'Karem', + 'Kymberlee', + 'Kayleena', + 'Katryna', + 'Jessicamae', + 'Gessica', + 'Jameela', + 'Janele', + 'Naylani', + 'Anagabriela', + 'Andraya', + 'Andreanna', + 'Artavia', + 'Alexanderia', + 'Laporche', + 'Laporsche', + 'Folasade', + 'Kirandeep', + 'Davia', + 'Davona', + 'Darbi', + 'Baylea', + 'Sylwia', + 'Glendy', + 'Ivet', + 'Fritzi', + 'Lusero', + 'Marlayna', + 'Marlissa', + 'Leanny', + 'Duaa', + 'Ruchama', + 'Orli', + 'Nabeeha', + 'Maurissa', + 'Shevawn', + 'Shauni', + 'Shellby', + 'Sindi', + 'Taralyn', + 'Tanzania', + 'Sinthia', + 'Ondrea', + 'Nhu', + 'Narine', + 'Naly', + 'Yanett', + 'Temmy', + 'Manar', + 'Maimuna', + 'Arielys', + 'Dalya', + 'Allyse', + 'Mariateresa', + 'Mariade', + 'Lashea', + 'Kimberlyann', + 'Cyntia', + 'Cystal', + 'Elisse', + 'Tonimarie', + 'Nashalie', + 'Shatasia', + 'Teigan', + 'Muntaha', + 'Zlata', + 'Zehra', + 'Shaterra', + 'Leeya', + 'Keysi', + 'Christabel', + 'Alfrieda', + 'Mehgan', + 'Hyacinth', + 'Shley', + 'Caterin', + 'Darnesha', + 'Amaranta', + 'Jazzmen', + 'Kelia', + 'Kassy', + 'Grasiela', + 'Sheindy', + 'Yenty', + 'Tahani', + 'Umme', + 'Mayla', + 'Maryon', + 'Kiyanna', + 'Dezeray', + 'Macaela', + 'Nalley', + 'Mikeisha', + 'Sylvana', + 'Smantha', + 'Virdiana', + 'Afiya', + 'Chanise', + 'Glorimar', + 'Hui', + 'Hendel', + 'Junia', + 'Gioia', + 'Elene', + 'Dorothie', + 'Elynor', + 'Mercades', + 'Arfa', + 'Abiha', + 'Aayat', + 'Amarianna', + 'Raynisha', + 'Pahola', + 'Sarin', + 'Marixa', + 'Shavonna', + 'Tannya', + 'Tijera', + 'Girtha', + 'Tameko', + 'Caresse', + 'Bernyce', + 'Allisha', + 'Branda', + 'Jahmya', + 'Haleema', + 'Hodaya', + 'Samina', + 'Sheva', + 'Theadora', + 'Skylyn', + 'Razan', + 'Somalia', + 'Thalya', + 'Quadasia', + 'Yanil', + 'Arabia', + 'Edina', + 'Briyanna', + 'Verdia', + 'Sehar', + 'Naama', + 'Timberly', + 'Reann', + 'Narissa', + 'Maggy', + 'Marriah', + 'Joua', + 'Kellsie', + 'Kelcy', + 'Evonna', + 'Jacqueleen', + 'Xee', + 'Zaynah', + 'Janique', + 'Jailin', + 'Aniqa', + 'Melana', + 'Mariame', + 'Aundria', + 'Anacaren', + 'Anahid', + 'Jassmine', + 'Keoshia', + 'Keyera', + 'Delmi', + 'Briselda', + 'Carlisha', + 'Brittnei', + 'Clarrisa', + 'Dezerae', + 'Banessa', + 'Ariele', + 'Cherrell', + 'Daissy', + 'Cecila', + 'Jady', + 'Kristelle', + 'Kristinamarie', + 'Korinna', + 'Kortnee', + 'Jasimine', + 'Jahnay', + 'Farhana', + 'Shaliyah', + 'Nemesis', + 'Shakerria', + 'Phoua', + 'Carylon', + 'Ironesha', + 'Lariza', + 'Anesa', + 'Elantra', + 'Deandria', + 'Denecia', + 'Chelsia', + 'Teighlor', + 'Suzannah', + 'Zelene', + 'Zeena', + 'Catriona', + 'Tamarra', + 'Tannaz', + 'Titiana', + 'Briany', + 'Lyana', + 'Maytal', + 'Antanasia', + 'Kierston', + 'Dashia', + 'Ismenia', + 'Annessa', + 'Carolena', + 'Miasia', + 'Mikhaila', + 'Lamiracle', + 'Kassey', + 'Markeshia', + 'Hilarie', + 'Necha', + 'Ziara', + 'Jahniyah', + 'Safiyah', + 'Tanaisha', + 'Shamyra', + 'Laportia', + 'Shavy', + 'Viktoriya', + 'Khrystyne', + 'Kristyne', + 'Juanisha', + 'Jerrika', + 'Channelle', + 'Jacquiline', + 'Rakia', + 'Tamarah', + 'Sarha', + 'Mishelle', + 'Nastasha', + 'Acadia', + 'Brittiney', + 'Mickaela', + 'Natavia', + 'Seryna', + 'Ardene', + 'Special', + 'Simranjit', + 'Marivi', + 'Natassja', + 'Neira', + 'Nikkie', + 'Asiana', + 'Dazhane', + 'Channell', + 'Adryana', + 'Mariluz', + 'Dajia', + 'Breigh', + 'Zelpha', + 'Lataya', + 'Glenny', + 'Sharene', + 'Shaguana', + 'Henrine', + 'Camesha', + 'Birdia', + 'Dynisha', + 'Sherina', + 'Ayde', + 'Danille', + 'Charday', + 'Almadelia', + 'Larena', + 'Charlestine', + 'Suellyn', + 'Marry', + 'Constantina', + 'Tandi', + 'Lacretia', + 'Noralba', + 'Latresha', + 'Latacha', + 'Talynn', + 'Rox', + 'Chasey', + 'Nyia', + 'Alyissa', + 'Karilyn', + 'Shevonne', + 'Genny', + 'Tamicka', + 'Doneisha', + 'Cyrena', + 'Daisia', + 'Ravina', + 'Berdia', + 'Aneesha', + 'Vashti', + 'Latrica', + 'Kennetha', + 'Aarti', + 'Raiza', + 'Elspeth', + 'Kyleen', + 'Ronika', + 'Lyndsy', + 'Jone', + 'Chanta', + 'Serita', + 'Margree', + 'Ruthel', + 'Ruthella', + 'Breunna', + 'Cyann', + 'Atlanta', + 'Danniela', + 'Junita', + 'Floella', + 'Brittane', + 'Avanelle', + 'Priscill', + 'Luvina', + 'Jeneva', + 'Teretha', + 'Clarita', + 'Ilce', + 'Jacqualyn', + 'Justene', + 'Daysia', + 'Taylore', + 'Sadi', + 'Verenis', + 'Shyenne', + 'Toriana', + 'Alvira', + 'Kalah', + 'Rajanee', + 'Reonna', + 'Mariadelaluz', + 'Mychaela', + 'Charnele', + 'Aeisha', + 'Shaquaya', + 'Shaakira', + 'Tayana', + 'Cozetta', + 'Kensey', + 'Jazsmin', + 'Kaitlyne', + 'Hollye', + 'Lavren', + 'Sarit', + 'Shanieka', + 'Margorie', + 'Virgene', + 'Dannia', + 'Clorissa', + 'Breahna', + 'Rayla', + 'Dellanira', + 'Megen', + 'Matalie', + 'Taraneh', + 'Teila', + 'Etter', + 'Cheetara', + 'Shetara', + 'Jamielee', + 'Kariann', + 'Karess', + 'Bea', + 'Leyda', + 'Misa', + 'Mareena', + 'Maisee', + 'Yvonna', + 'Yocelyne', + 'Yilda', + 'Sabrinna', + 'Sirenia', + 'Tyriel', + 'Darrielle', + 'Siedah', + 'Yuko', + 'Stevee', + 'Chrystle', + 'Shaterrica', + 'Janyll', + 'Evelisse', + 'Belkis', + 'Renesmae', + 'Sahily', + 'Zurie', + 'Edelia', + 'Sequoya', + 'Waldine', + 'Marinell', + 'Moya', + 'Lavenia', + 'Liboria', + 'Meliah', + 'Meliyah', + 'Mio', + 'Xitllali', + 'Nare', + 'Oliviah', + 'Mayrani', + 'Sravya', + 'Valeska', + 'Riona', + 'Lashaundra', + 'Phebe', + 'Yeira', + 'Zarai', + 'Ayanah', + 'Kriti', + 'Kaileah', + 'Donata', + 'Jenavee', + 'Daphnee', + 'Gurneet', + 'Emmalie', + 'Rowrenia', + 'Haisley', + 'Harbor', + 'Arilyn', + 'Aubrii', + 'Avielle', + 'Avyn', + 'Bethenny', + 'Arienne', + 'Anyeli', + 'Brilyn', + 'Cataleyah', + 'Chisom', + 'Dalis', + 'Malaiya', + 'Meela', + 'Karsynn', + 'Kaselyn', + 'Kashlyn', + 'Amorette', + 'Lenita', + 'Adabelle', + 'Allisyn', + 'Alyzah', + 'Aaralynn', + 'Avyanna', + 'Aylinn', + 'Bexley', + 'Blakeleigh', + 'Caeli', + 'Chizaram', + 'Avriana', + 'Clarity', + 'Juanelle', + 'Jerelene', + 'Eluteria', + 'Lamerle', + 'Aletheia', + 'Abrie', + 'Adelie', + 'Elleigh', + 'Emmelyn', + 'Emsley', + 'Everlynn', + 'Galileah', + 'Derrica', + 'Keondria', + 'Keneshia', + 'Amberley', + 'Valkyrie', + 'Yazleemar', + 'Maybree', + 'Shloka', + 'Neah', + 'Oluwatomisin', + 'Saydi', + 'Jessalynn', + 'Katalaya', + 'Katniss', + 'Kendalynn', + 'Davionna', + 'Mercie', + 'Danett', + 'Deetya', + 'Dilynn', + 'Dunya', + 'Camyla', + 'Elliotte', + 'Ivee', + 'Jadie', + 'Kyleah', + 'Laelani', + 'Mileah', + 'Nalanie', + 'Nixie', + 'Oviya', + 'Lakecia', + 'Sharnae', + 'Abbagail', + 'Derica', + 'Truly', + 'Tvisha', + 'Vedika', + 'Xiclaly', + 'Syra', + 'Idamae', + 'Dashanti', + 'Neita', + 'Siona', + 'Jourdyn', + 'Analyn', + 'Shamiracle', + 'Daylene', + 'Kadeesha', + 'Malgorzata', + 'Dashay', + 'Else', + 'Pixie', + 'Myleah', + 'Myleen', + 'Nadiah', + 'Sadhana', + 'Samai', + 'Seraphine', + 'Sereen', + 'Sharanya', + 'Simar', + 'Mahlia', + 'Inika', + 'Jennavieve', + 'Genevy', + 'Harshita', + 'Hennessey', + 'Zari', + 'Jamiracle', + 'Loveta', + 'Coleta', + 'Adabella', + 'Alesana', + 'Brinleigh', + 'Azlyn', + 'Braelee', + 'Shaquila', + 'Shanyia', + 'Jamilia', + 'Corlis', + 'Dulcie', + 'Desha', + 'Timya', + 'Rakiya', + 'Tyliah', + 'Taura', + 'Terasha', + 'Gaynel', + 'Roylene', + 'Janecia', + 'Alonda', + 'Tyneisha', + 'Fleurette', + 'Mayleigh', + 'Meklit', + 'Sarenity', + 'Gulianna', + 'Itzayanna', + 'Ivyana', + 'Jazmynn', + 'Esmie', + 'Favor', + 'Kimbella', + 'Shanavia', + 'Yaritzel', + 'Daun', + 'Tykerria', + 'Antoria', + 'Shykemmia', + 'Remona', + 'Lucrezia', + 'Cicily', + 'Aradhya', + 'Esmae', + 'Evah', + 'Jhene', + 'Katalia', + 'Cyrine', + 'Delayza', + 'Eleonor', + 'Arohi', + 'Aseneth', + 'Avarose', + 'Caia', + 'Hulene', + 'Valera', + 'Nasaria', + 'Makesha', + 'Zera', + 'Aahna', + 'Aariyah', + 'Aashvi', + 'Adalene', + 'Annaliyah', + 'Aira', + 'Alaska', + 'Amila', + 'Amour', + 'Kaylinn', + 'Isidora', + 'Marija', + 'Suha', + 'Marigold', + 'Mayzie', + 'Liesel', + 'Darielle', + 'Sapphira', + 'Scotland', + 'Serah', + 'Srinika', + 'Novah', + 'Primrose', + 'Latresa', + 'Theia', + 'Alleen', + 'Agness', + 'Estanislada', + 'Ellouise', + 'Emilija', + 'Glynnis', + 'Paulene', + 'Wilna', + 'Maedell', + 'Lometa', + 'Cressie', + 'Allyne', + 'Calleen', + 'Joaquina', + 'Lashelle', + 'Modene', + 'Jonie', + 'Minta', + 'Milady', + 'Jearlene', + 'Rithika', + 'Simrat', + 'Vonzella', + 'Venna', + 'Pabla', + 'Benilde', + 'Eniya', + 'Shakendra', + 'Ailen', + 'Aina', + 'Marionna', + 'Millette', + 'Emiyah', + 'Kayloni', + 'Keerat', + 'Keeva', + 'Lailany', + 'Mishka', + 'Naevia', + 'Nathania', + 'Nyari', + 'Jayah', + 'Kaavya', + 'Frankee', + 'Anahita', + 'Anella', + 'Elizabella', + 'Damara', + 'Juaquina', + 'Gracia', + 'Rozalyn', + 'Ruhani', + 'Novalie', + 'Mialani', + 'Minka', + 'Nessa', + 'Sissi', + 'Sitara', + 'Jaynee', + 'Jeyla', + 'Gizzelle', + 'Maila', + 'Maizy', + 'Lamaya', + 'Katalea', + 'Khamila', + 'Shekita', + 'Chinita', + 'Anshika', + 'Aerabella', + 'Azelia', + 'Cici', + 'Daleyssa', + 'Divinity', + 'Fermina', + 'Murline', + 'Mattye', + 'Devra', + 'Jakya', + 'Santresa', + 'Larene', + 'Deola', + 'Liliann', + 'Lexxi', + 'Kamori', + 'Myonna', + 'Yitzel', + 'Lindalee', + 'Tira', + 'Mairyn', + 'Riyana', + 'Shaleen', + 'Rhyleigh', + 'Fleeta', + 'Gabrielly', + 'Deajah', + 'Yarielis', + 'Arelie', + 'Amore', + 'Sacoria', + 'Hedda', + 'Wanza', + 'Janyth', + 'Yaslin', + 'Brianah', + 'Anyelin', + 'Shayleigh', + 'Lace', + 'Kurstin', + 'Zakhia', + 'Charvi', + 'Raylie', + 'Nyellie', + 'Natalyn', + 'Libra', + 'Khianna', + 'Jolena', + 'Genevive', + 'Jadine', + 'Deniya', + 'Madysin', + 'Porchia', + 'Layleen', + 'Kemiya', + 'Donesha', + 'Jewelene', + 'Sakari', + 'Narely', + 'Maylyn', + 'Halina', + 'Nelli', + 'Myangel', + 'British', + 'Adore', + 'Alainah', + 'Shadonna', + 'Aminta', + 'Marolyn', + 'Jalea', + 'Breelynn', + 'Carah', + 'Sagrario', + 'Akyra', + 'Kailei', + 'Kenza', + 'Renette', + 'Joanann', + 'Solimar', + 'Semira', + 'Harneet', + 'Jahayra', + 'Evanny', + 'Gyzelle', + 'Nathalee', + 'Dalphine', + 'Mane', + 'Merelyn', + 'Kayliana', + 'Aubryn', + 'Brooklyne', + 'Kimari', + 'Dandra', + 'Cilia', + 'Laren', + 'Denetra', + 'Kandise', + 'Makynli', + 'Janan', + 'Rosalea', + 'Ludean', + 'Syndey', + 'Shaney', + 'Vannary', + 'Reynalda', + 'Rainee', + 'Trishia', + 'Kirbie', + 'Kristyl', + 'Lynzi', + 'Shardai', + 'Yaricza', + 'Tarina', + 'Lynley', + 'Maniah', + 'Arcilia', + 'Keaundra', + 'Karrigan', + 'Madeliene', + 'Lessley', + 'Laurynn', + 'Ragen', + 'Essance', + 'Celsey', + 'Caitlen', + 'Dulse', + 'Sulamita', + 'Evlyn', + 'Dorace', + 'Marciana', + 'Tenecia', + 'Natarsha', + 'Analiza', + 'Ladene', + 'Tatumn', + 'Maricsa', + 'Lysa', + 'Leydi', + 'Limayri', + 'Rebbeca', + 'Amreen', + 'Saina', + 'Remedy', + 'Rael', + 'Nami', + 'Nalini', + 'Naiyah', + 'Moxie', + 'Olina', + 'Whitni', + 'Dayannara', + 'Diara', + 'Arma', + 'Giorgia', + 'Evee', + 'Bricia', + 'Brizeyda', + 'Chihiro', + 'Ayram', + 'Ayushi', + 'Isolde', + 'Husna', + 'Khrystal', + 'Kriston', + 'Raylena', + 'Porschea', + 'Samanthia', + 'Mylinda', + 'Ginelle', + 'Coreena', + 'Aryel', + 'Mallary', + 'Maciel', + 'Kursten', + 'Leandrea', + 'Mackensie', + 'Camri', + 'Itzamara', + 'Aryiah', + 'Alayssa', + 'Andreah', + 'Anberlin', + 'Amrie', + 'Breah', + 'Ryane', + 'Tonna', + 'Valisa', + 'Adryanna', + 'Ajia', + 'Robynne', + 'Brystal', + 'Brylynn', + 'Kaleigha', + 'Danyka', + 'Dannica', + 'Caylen', + 'Jonier', + 'Ruthy', + 'Mada', + 'Vaida', + 'Yeila', + 'Zoelle', + 'Elzora', + 'Samreen', + 'Seylah', + 'Sayla', + 'Allina', + 'Stellarose', + 'Starlett', + 'Simrit', + 'Shina', + 'Bernestine', + 'Tranisha', + 'Tiffanyann', + 'Adamarys', + 'Tylyn', + 'Shahrzad', + 'Addisson', + 'Aeriana', + 'Alaiya', + 'Anni', + 'Ariely', + 'Anvika', + 'Aneya', + 'Bani', + 'Ayame', + 'Ayaka', + 'Aviella', + 'Alabama', + 'Adalyne', + 'Teresea', + 'Ishana', + 'Hargun', + 'Jasnoor', + 'Deby', + 'Dannelle', + 'Swetha', + 'Catherina', + 'Bridgitt', + 'Birgit', + 'Calisi', + 'Defne', + 'Delsa', + 'Demiyah', + 'Cataleah', + 'Icel', + 'Ixel', + 'Jazman', + 'Jessicamarie', + 'Desaree', + 'Chika', + 'Estephani', + 'Dilcia', + 'Dartha', + 'Lesieli', + 'Breyona', + 'Waynette', + 'Verma', + 'Calletana', + 'Cherisa', + 'Casara', + 'Jil', + 'Shella', + 'Renell', + 'Venise', + 'Loura', + 'Kaylia', + 'Leileen', + 'Jessel', + 'Janesa', + 'Kaelly', + 'Julina', + 'Joselinne', + 'Juna', + 'Hazelle', + 'Mauricia', + 'Octaviana', + 'Rumalda', + 'Kataleyah', + 'Kimela', + 'Mosella', + 'Delone', + 'Shemekia', + 'Balinda', + 'Hazell', + 'Deboraha', + 'Gizell', + 'Camilia', + 'Avalina', + 'Audreyana', + 'Baran', + 'Genesee', + 'Elyzabeth', + 'Eliya', + 'Kathyleen', + 'Deeksha', + 'Scherry', + 'Angelyne', + 'Amiliana', + 'Amaira', + 'Jeani', + 'Alysen', + 'Alania', + 'Adiana', + 'Chinyere', + 'Lamesha', + 'Keiley', + 'Lanea', + 'Rosely', + 'Surabhi', + 'Dyanne', + 'Mallika', + 'Tabbatha', + 'Shilpa', + 'Morgyn', + 'Narali', + 'Jenevie', + 'Lovette', + 'Nayleah', + 'Navi', + 'Meili', + 'Nazly', + 'Nethra', + 'Earlee', + 'Layloni', + 'Kiannah', + 'Lilyanah', + 'Liannah', + 'Jaylenn', + 'Jiayi', + 'Kattleya', + 'Kanna', + 'Jimin', + 'Kaleesi', + 'Kailia', + 'Itzy', + 'Itzela', + 'Jasminemarie', + 'Malynda', + 'Jeweline', + 'Eloiza', + 'Carolin', + 'Helma', + 'Arlyle', + 'Giannina', + 'Constancia', + 'Elyce', + 'Montoya', + 'Marline', + 'Krystale', + 'Maghan', + 'Laquitta', + 'Elishia', + 'Aliciana', + 'Maralee', + 'Brunetta', + 'Cybil', + 'Dannell', + 'Cherene', + 'Agueda', + 'Guillerma', + 'Haillie', + 'Bobbe', + 'Gesselle', + 'Esthefany', + 'Sian', + 'Ouita', + 'Sasheen', + 'Abigaile', + 'Demarie', + 'Edwena', + 'Aamiyah', + 'Breaunna', + 'Bryssa', + 'Catlyn', + 'Xaviera', + 'Sierria', + 'Skyelar', + 'Aujanae', + 'Rika', + 'Roshelle', + 'Roxsana', + 'Zonia', + 'Tifanie', + 'Thavy', + 'Teala', + 'Tanea', + 'Loukisha', + 'Melita', + 'Keiona', + 'Maryfer', + 'Delcenia', + 'Akila', + 'Gwenevere', + 'Obdulia', + 'Texana', + 'Licette', + 'Larina', + 'Lany', + 'Yailine', + 'Yomara', + 'Zavia', + 'Sydne', + 'Mariadelourdes', + 'Margeaux', + 'Daneille', + 'Doni', + 'Donalee', + 'Darilyn', + 'Jennfier', + 'Jeanny', + 'Haliegh', + 'Dymon', + 'Callee', + 'Cydni', + 'Daesha', + 'Tamila', + 'Tresha', + 'Mckennah', + 'Shouana', + 'Xcaret', + 'Yeneisy', + 'Yumalai', + 'Ziana', + 'Hanny', + 'Shanisha', + 'Nissi', + 'Mirabel', + 'Miarose', + 'Valerya', + 'Rosalin', + 'Saliha', + 'Samayah', + 'Smriti', + 'Jozette', + 'Gari', + 'Jeanell', + 'Dyann', + 'Vonna', + 'Velina', + 'Salli', + 'Nonie', + 'Olena', + 'Camela', + 'Eufracia', + 'Ethelyne', + 'Yuhan', + 'Silveria', + 'Silvestra', + 'Thressa', + 'Tiahna', + 'Vasti', + 'Calee', + 'Florentine', + 'Sherre', + 'Almira', + 'Zitlalli', + 'Vianne', + 'Yaribeth', + 'Yarelie', + 'Robbye', + 'Jasminne', + 'Sophiah', + 'Saryah', + 'Hermalinda', + 'Sinclaire', + 'Korissa', + 'Lanee', + 'Keeana', + 'Parlee', + 'Luceal', + 'Jetta', + 'Mairani', + 'Tameisha', + 'Haruna', + 'Chasiti', + 'Leighanne', + 'Anaisabel', + 'Aanchal', + 'Alesa', + 'Annisa', + 'Brigitta', + 'Elideth', + 'Chua', + 'Cherrish', + 'Aleece', + 'Maizee', + 'Navie', + 'Philomene', + 'Jilian', + 'Jesi', + 'Kortnie', + 'Beija', + 'Delissa', + 'Shiree', + 'Silbia', + 'Tamura', + 'Aerianna', + 'Abegail', + 'Braniya', + 'Calyn', + 'Carlynn', + 'Anjana', + 'Angelik', + 'Alyzabeth', + 'Amorie', + 'Joannamarie', + 'Kerissa', + 'Kennesha', + 'Laruen', + 'Korrina', + 'Felisitas', + 'Gilma', + 'Essica', + 'Gerarda', + 'Petronila', + 'Dorotea', + 'Maguadalupe', + 'Najla', + 'Loana', + 'Illyana', + 'Amunique', + 'Antwanette', + 'Krystan', + 'Shaniquia', + 'Shanequia', + 'Rainy', + 'Raynesha', + 'Shayleen', + 'Stephanee', + 'Sharaya', + 'Nikkole', + 'Cecille', + 'Christyne', + 'Auriel', + 'Franki', + 'Zelina', + 'Deshanae', + 'Deshawna', + 'Tyneshia', + 'Tyrisha', + 'Deangela', + 'Dynasia', + 'Maigan', + 'Jericka', + 'Jackalyn', + 'Kayln', + 'Ceslie', + 'Bethaney', + 'Samanvi', + 'Saidee', + 'Rosibel', + 'Spirit', + 'Srishti', + 'Varnika', + 'Vanshika', + 'Rosha', + 'Rheya', + 'Yoyo', + 'Veyda', + 'Weslyn', + 'Palak', + 'Sieanna', + 'Riannah', + 'Lovetta', + 'Lota', + 'Florice', + 'Hortence', + 'Zuley', + 'Zoejane', + 'Zemira', + 'Mineola', + 'Senona', + 'Concepsion', + 'Conrada', + 'Dardanella', + 'Rhina', + 'Rubicela', + 'Raissa', + 'Porchea', + 'Latiana', + 'Landy', + 'Monee', + 'Maritssa', + 'Marjani', + 'Meosha', + 'Cecilie', + 'Britanie', + 'Brandilyn', + 'Khrystina', + 'Atenas', + 'Kristeena', + 'Kristell', + 'Kristianne', + 'Angelicia', + 'Alexandera', + 'Jaimy', + 'Jeneffer', + 'Hayde', + 'Vickye', + 'Suzzanne', + 'Susi', + 'Sherrilyn', + 'Sanda', + 'Janeal', + 'Stephnie', + 'Luwana', + 'Shenae', + 'Yaris', + 'Marzell', + 'Lashane', + 'Liandra', + 'Keionna', + 'Korri', + 'Marlet', + 'Marytza', + 'Lorraina', + 'Deepika', + 'Devi', + 'Fion', + 'Darrah', + 'Dalisha', + 'Karessa', + 'Karrisa', + 'Kasara', + 'Ismar', + 'Jacquilyn', + 'Janica', + 'Jeannett', + 'Samanatha', + 'Samra', + 'Sayda', + 'Breklyn', + 'Ashika', + 'Bita', + 'Allysha', + 'Areil', + 'Arlenne', + 'Artelia', + 'Janicia', + 'Corinthia', + 'Angellica', + 'Maygen', + 'Maygan', + 'Odelle', + 'Wenonah', + 'Perfecta', + 'Anjelika', + 'Solmaira', + 'Fredonia', + 'Burgandy', + 'Chelcee', + 'Kellsey', + 'Lyann', + 'Jazmon', + 'Ardie', + 'Latunya', + 'Benetta', + 'Delphina', + 'Ortensia', + 'Obelia', + 'Lurene', + 'Refujia', + 'Noriko', + 'Ladelle', + 'Lella', + 'Shanie', + 'Shawndra', + 'Zell', + 'Zela', + 'Wenda', + 'Troylene', + 'Merrilyn', + 'Kapri', + 'Timesha', + 'Gwendlyn', + 'Jenean', + 'Lamona', + 'Ladana', + 'Cina', + 'Cybele', + 'Eugina', + 'Anjeanette', + 'Vana', + 'Jeneal', + 'Cherlene', + 'Railee', + 'Palin', + 'Yuliet', + 'Rechelle', + 'Sherisse', + 'Pollyanna', + 'Tiphani', + 'Tiffanee', + 'Vanisha', + 'Yurico', + 'Junko', + 'Shannell', + 'Shalise', + 'Kimberlina', + 'Kerra', + 'Shantee', + 'Emmelia', + 'Micala', + 'Lexxus', + 'Candiss', + 'Chauntel', + 'Alese', + 'Margit', + 'Any', + 'Ambur', + 'Chrysta', + 'Janese', + 'Jinny', + 'Zaydee', + 'Makisha', + 'Carola', + 'Marjan', + 'Samanth', + 'Shaquinta', + 'Polette', + 'Riane', + 'Nitasha', + 'Kasarah', + 'Jillianne', + 'Keidra', + 'Karrah', + 'Kaytie', + 'Sondi', + 'Swayzie', + 'Laporcha', + 'Bridgit', + 'Chanika', + 'Antoniette', + 'Jessicia', + 'Francies', + 'Kaizley', + 'Negin', + 'Mistica', + 'Lorenia', + 'Kalise', + 'Kynslie', + 'Dene', + 'Jizel', + 'Jinger', + 'Jayli', + 'Jariya', + 'Joelynn', + 'Haylin', + 'Isabellah', + 'Ciria', + 'Dealva', + 'Barbarita', + 'Prudencia', + 'Wanna', + 'Marieli', + 'Madisynn', + 'Madalyne', + 'Artisha', + 'Everlyn', + 'Cyerra', + 'Liezl', + 'Kabao', + 'Karmina', + 'Kashmir', + 'Nani', + 'Mithra', + 'Mishika', + 'Milynn', + 'Mehr', + 'Marybella', + 'Maisey', + 'Maddy', + 'Lyah', + 'Marnee', + 'Machele', + 'Ladona', + 'Lorilei', + 'Liara', + 'Alahni', + 'Analaya', + 'Amalya', + 'Alyannah', + 'Aayla', + 'Aarini', + 'Arliz', + 'Cyra', + 'Asenet', + 'Avy', + 'Avaree', + 'Ciela', + 'Evangelyn', + 'Kaidynce', + 'Isella', + 'Ilaria', + 'Kattaleya', + 'Laveah', + 'Lareen', + 'Lanah', + 'Deema', + 'Hannaley', + 'Fiora', + 'Eviana', + 'Ellieana', + 'Elisabetta', + 'Dejanira', + 'Manaia', + 'Malibu', + 'Charlsey', + 'Kaytee', + 'Kinberly', + 'Cinderella', + 'Miana', + 'Kimm', + 'Koni', + 'Eraina', + 'Dory', + 'Deette', + 'Nysa', + 'Nyima', + 'Nikitha', + 'Anasophia', + 'Alissandra', + 'Alisi', + 'Corynn', + 'Aubreyana', + 'Anjani', + 'Oliana', + 'Nura', + 'Nihira', + 'Loveda', + 'Gayathri', + 'Kleigh', + 'Ladaisha', + 'Ilette', + 'Jillene', + 'Jalina', + 'Izellah', + 'Tiaira', + 'Mickala', + 'Macarena', + 'Rubina', + 'Shadow', + 'Emillie', + 'Morine', + 'Novell', + 'Oletta', + 'Pura', + 'Winna', + 'Synia', + 'Shyloh', + 'Kaizlee', + 'Raley', + 'Merly', + 'Na', + 'Yenia', + 'Shayanne', + 'Raeana', + 'Tiauna', + 'Tanairy', + 'Georganna', + 'Mahsa', + 'Maiquel', + 'Korena', + 'Yamel', + 'Shamonica', + 'Romesha', + 'Terrisha', + 'Hannan', + 'Hillarie', + 'Feliza', + 'Courtny', + 'Lyndsee', + 'Katelan', + 'Lakedra', + 'Elisabel', + 'Cynthya', + 'Dannah', + 'Darienne', + 'Dejanique', + 'Madalin', + 'Makynzi', + 'Gwendolynn', + 'Alaine', + 'Bridney', + 'Kimorah', + 'Klee', + 'Kynedi', + 'Loreley', + 'Parthenia', + 'Aubryana', + 'Aryannah', + 'Edeline', + 'Elen', + 'Raguel', + 'Marizela', + 'Michella', + 'Haasini', + 'Tristine', + 'Elis', + 'Pattye', + 'Tanishia', + 'Jenel', + 'Jurea', + 'Laini', + 'Britania', + 'Christabelle', + 'Dafney', + 'Laterica', + 'Angelmarie', + 'Asuzena', + 'Aleea', + 'Teneka', + 'Yicel', + 'Malisha', + 'Prairie', + 'Makelle', + 'Shaelee', + 'Dafina', + 'Hisaye', + 'Adayah', + 'Alexsia', + 'Allysen', + 'Takako', + 'Thamara', + 'Trinitie', + 'Shaneen', + 'Sueellen', + 'Telma', + 'Meyah', + 'Rorie', + 'Preslea', + 'Elbia', + 'Ginna', + 'Marja', + 'Marites', + 'Neisha', + 'Shir', + 'Shastelyn', + 'Saraih', + 'Unity', + 'Makinna', + 'Franchelle', + 'Azadeh', + 'Charito', + 'Joli', + 'Amyrah', + 'Sharlee', + 'Jasey', + 'Kortlynn', + 'Kiari', + 'Kyria', + 'Eleina', + 'Elany', + 'Daleah', + 'Sumi', + 'Kileigh', + 'Lorianna', + 'Macady', + 'Naviah', + 'Mattilyn', + 'Raylyn', + 'Bridgitte', + 'Hasina', + 'Johnelle', + 'Gwendlyon', + 'Itxel', + 'Iyanah', + 'Jeidy', + 'Jaidynn', + 'Jaslynne', + 'Zoii', + 'Tensley', + 'Yolando', + 'Keyarah', + 'Keyri', + 'Katherinne', + 'Thersa', + 'Sinahi', + 'Secret', + 'Vivika', + 'Yobana', + 'Hailley', + 'Haliey', + 'Isys', + 'Deyla', + 'Kassidee', + 'Jalie', + 'Florestela', + 'Cyla', + 'Samyuktha', + 'Libni', + 'Laritza', + 'Breannah', + 'Breya', + 'Keelin', + 'Jarelly', + 'Jenyfer', + 'Julyanna', + 'Kaetlyn', + 'Mixtli', + 'Mykaila', + 'Nasia', + 'Judieth', + 'Misako', + 'Bre', + 'Shaley', + 'Gelila', + 'Aariana', + 'Laquetta', + 'Shizu', + 'Annay', + 'Annai', + 'Breeze', + 'Mahum', + 'Harsimran', + 'Helaina', + 'Alexza', + 'Tangelia', + 'Shellye', + 'Blondena', + 'Keva', + 'Suzzane', + 'Vallorie', + 'Absidy', + 'Alis', + 'Alexxia', + 'Allura', + 'Ariba', + 'Annete', + 'Anett', + 'Deyanara', + 'Ellise', + 'Majorie', + 'Hibah', + 'Chaselyn', + 'Hennesy', + 'Gayatri', + 'Kathelyn', + 'Caylah', + 'Athyna', + 'Arpita', + 'Ciclaly', + 'Emmamarie', + 'Virjinia', + 'Tyna', + 'Cyd', + 'Glennda', + 'Littie', + 'Orlean', + 'Derinda', + 'Hether', + 'Clata', + 'Pleshette', + 'Maricelda', + 'Charmin', + 'Matsuye', + 'Tamitha', + 'Armanda', + 'Sayaka', + 'Lacresia', + 'Demonica', + 'Skie', + 'Trynity', + 'Sereena', + 'Shefali', + 'Rewa', + 'Reshonda', + 'Yalanda', + 'Anissia', + 'Layni', + 'Paolina', + 'Manaal', + 'Mariali', + 'Merina', + 'Milenia', + 'Millenia', + 'Moncerrath', + 'Monzerrath', + 'Kaydie', + 'Adianna', + 'Toluwalase', + 'Trysta', + 'Ainsleigh', + 'Alianah', + 'Meuy', + 'Meloney', + 'Talea', + 'Sheetal', + 'Shalana', + 'Venesa', + 'Teana', + 'Kiki', + 'Imee', + 'Aubryanna', + 'Allyanna', + 'Ambrie', + 'Amory', + 'Aniyha', + 'Caelynn', + 'Reita', + 'Rylann', + 'Aijah', + 'Aaliyha', + 'Alezandra', + 'Yeraldine', + 'Forestine', + 'Sameeha', + 'Caeley', + 'Britzy', + 'Blessin', + 'Armilda', + 'Birda', + 'Lorrine', + 'Krisalyn', + 'Linell', + 'Maryl', + 'Karole', + 'Maryela', + 'Mckinzy', + 'Madailein', + 'Kendi', + 'Kayda', + 'Jenasis', + 'Madelis', + 'Jamyiah', + 'Gabryela', + 'Catie', + 'Genessa', + 'Jamelia', + 'Jenene', + 'Nicholl', + 'Saralyn', + 'Taylah', + 'Xandra', + 'Jezlyn', + 'Zakayla', + 'Jaira', + 'Veena', + 'Shaden', + 'Sahiti', + 'Sahian', + 'Shelsey', + 'Sreya', + 'Zianna', + 'Angeleah', + 'Camily', + 'Lesvia', + 'Sonda', + 'Franceska', + 'Cytlaly', + 'Ylonda', + 'Issis', + 'Moon', + 'Joei', + 'Mariposa', + 'Ramandeep', + 'Preeti', + 'Niobe', + 'Sherran', + 'Nichola', + 'Letrice', + 'Waneda', + 'Meka', + 'Takeshia', + 'Leaann', + 'Girlie', + 'Olar', + 'Pearlena', + 'Carlean', + 'Dhanya', + 'Chastelin', + 'Aryanah', + 'Brihana', + 'Bijou', + 'Haifa', + 'Genesiss', + 'Genavie', + 'Enna', + 'Jazzel', + 'Japleen', + 'Iana', + 'Rahel', + 'Rylyn', + 'Pragya', + 'Yosselyn', + 'Yarelin', + 'Ellasyn', + 'Charlaine', + 'Zayli', + 'Taide', + 'Jodean', + 'Emilynn', + 'Channon', + 'Carinne', + 'Anaira', + 'Amisadai', + 'Caraline', + 'Danella', + 'Debanhy', + 'Devanee', + 'Koneta', + 'Jenie', + 'Hollee', + 'Marelie', + 'Mahathi', + 'Madilynne', + 'Lylia', + 'Loreli', + 'Lolah', + 'Lexine', + 'Maylynn', + 'Clarinda', + 'Marlynn', + 'Netra', + 'Makaylin', + 'Naira', + 'Naleah', + 'Mishel', + 'Myli', + 'Charlotta', + 'Arlisa', + 'Kaylynne', + 'Kamillah', + 'Ksenia', + 'Briseidy', + 'Aysel', + 'Anaily', + 'Eulean', + 'Adilee', + 'Abri', + 'Aidynn', + 'Alisyn', + 'Alicen', + 'Marveline', + 'Lupie', + 'Mariabelen', + 'Makenah', + 'Kyliegh', + 'Foye', + 'Yajahira', + 'Trenda', + 'Tya', + 'Nattaly', + 'Netanya', + 'Supriya', + 'Teja', + 'Srija', + 'Sherra', + 'Janissa', + 'Mysha', + 'Essfa', + 'Alexandrya', + 'Abi', + 'Takhia', + 'Jaeli', + 'Jaelynne', + 'Dianey', + 'Denisa', + 'Aleli', + 'Akina', + 'Aayushi', + 'Adanna', + 'Aunika', + 'Ithzel', + 'Caricia', + 'Kallyn', + 'Karmin', + 'Kindall', + 'Gredmarie', + 'Peace', + 'Jennalee', + 'Yaindhi', + 'Arcola', + 'Trannie', + 'Lyza', + 'Mackynzie', + 'Peggye', + 'Zenab', + 'Megyn', + 'Navina', + 'Naileah', + 'Maddelyn', + 'Luxe', + 'Arkie', + 'Belvia', + 'Edilia', + 'Monda', + 'Ridhi', + 'Peyten', + 'Sorayah', + 'Syrena', + 'Amberle', + 'Johnita', + 'Jerrye', + 'Alfa', + 'Jonita', + 'Lakie', + 'Jenalee', + 'Minami', + 'Morena', + 'Elsbeth', + 'Sylia', + 'Eunique', + 'Ellisa', + 'Lanai', + 'Jesselyn', + 'Jolissa', + 'Julizza', + 'Laquitha', + 'Jobina', + 'Wyvonne', + 'Shalese', + 'Deshannon', + 'Almendra', + 'Alisandra', + 'Geraldene', + 'Abygale', + 'Katelyne', + 'Kennede', + 'Karisia', + 'Lindzy', + 'Keyhla', + 'Emilea', + 'Dacey', + 'Jalah', + 'Adrienna', + 'Aisa', + 'Alaisha', + 'Brithney', + 'Calynn', + 'Cassity', + 'Brendy', + 'Reagen', + 'Myrah', + 'Montserrath', + 'Pheobe', + 'Nyeli', + 'Jocell', + 'Serenidy', + 'Issabela', + 'Hanalei', + 'Laelah', + 'Emmylou', + 'Geraldy', + 'Ovetta', + 'Analena', + 'Allyna', + 'Aliyanah', + 'Magdalyn', + 'Suann', + 'Ronee', + 'Amey', + 'Chirstina', + 'Trude', + 'Jearldine', + 'Maeleigh', + 'Lizzy', + 'Liviana', + 'Eithel', + 'Meryem', + 'Yaneisy', + 'Shatika', + 'Zeniyah', + 'Xaylee', + 'Pennelope', + 'Xochilth', + 'Jullie', + 'Saki', + 'Shaiann', + 'Haille', + 'Dannya', + 'Kerie', + 'Chianti', + 'Leza', + 'Koreen', + 'Letricia', + 'Lamanda', + 'Kinza', + 'Marisella', + 'Joelyn', + 'Cinde', + 'Chyrl', + 'Cece', + 'Boni', + 'Felecity', + 'Faithe', + 'Delayna', + 'Diamon', + 'Daley', + 'Darah', + 'France', + 'Kolina', + 'Kieu', + 'Grizel', + 'Shaleigh', + 'Shaylea', + 'Anitza', + 'Carrolyn', + 'Olimpia', + 'Jeannene', + 'Victoriana', + 'Azara', + 'Avelynn', + 'Aveah', + 'Ariam', + 'Devanie', + 'Daleisa', + 'Karelly', + 'Karalynn', + 'Keyleen', + 'Kendallyn', + 'Graceyn', + 'Falynn', + 'Evoleht', + 'Everlie', + 'Emri', + 'Hartlee', + 'Eleena', + 'Jailee', + 'Insiya', + 'Analysia', + 'Chalee', + 'Amzie', + 'Amilya', + 'Celisa', + 'Airabella', + 'Laketha', + 'Kyoko', + 'Saria', + 'Neli', + 'Melonee', + 'Neidy', + 'Nyanza', + 'Aizlynn', + 'Arthurine', + 'Mikhaela', + 'Adalae', + 'Parveen', + 'Lotoya', + 'Evanjelina', + 'Deborra', + 'Lunna', + 'Makylah', + 'Mckinleigh', + 'Mayalen', + 'Ladasia', + 'Javia', + 'Evian', + 'Jaelee', + 'Oluwatamilore', + 'Payzlee', + 'Reiley', + 'Samarra', + 'Chyler', + 'Areona', + 'Vanesha', + 'Tomisha', + 'Betzaira', + 'Dalana', + 'Destenie', + 'Brennah', + 'Cassidie', + 'Deziray', + 'Dimond', + 'Braeleigh', + 'Aylee', + 'Anastyn', + 'Amillia', + 'Jailyne', + 'Jissell', + 'Jailenne', + 'Inioluwa', + 'Jensyn', + 'Allia', + 'Evolett', + 'Emmalynne', + 'Emberlee', + 'Emaline', + 'Ellayna', + 'Kollins', + 'Keyly', + 'Livi', + 'Judeen', + 'Eleah', + 'Vonceil', + 'Kaaliyah', + 'Girtie', + 'Gianelle', + 'Iniya', + 'Harlynn', + 'Greidy', + 'Shayli', + 'Belina', + 'Auri', + 'Avangeline', + 'Alizey', + 'Arlynn', + 'Anelise', + 'Aneli', + 'Delmira', + 'Vanassa', + 'Ceana', + 'Ambre', + 'Florita', + 'Balbina', + 'Clova', + 'Danice', + 'Aydee', + 'Carlena', + 'Benicia', + 'Soumya', + 'Lissandra', + 'Ling', + 'Liahna', + 'Leonna', + 'Leilana', + 'Reeya', + 'Krisinda', + 'Maleiah', + 'Maiyah', + 'Mailin', + 'Lucciana', + 'Naydeen', + 'Nailani', + 'Miette', + 'Yeva', + 'Suley', + 'Shravya', + 'Kyia', + 'Shree', + 'Cerise', + 'Katriana', + 'Jaskiran', + 'Mone', + 'Latijera', + 'Rosicela', + 'Sidnee', + 'Rosisela', + 'Troi', + 'Victorya', + 'Creasie', + 'Latorsha', + 'Erienne', + 'Jovonna', + 'Jessia', + 'Jeny', + 'Dejia', + 'Destynie', + 'Barbi', + 'Marlinda', + 'Shakeitha', + 'Mistelle', + 'Ziona', + 'Zarahi', + 'Xiadani', + 'Zyrah', + 'Zoriah', + 'Pamla', + 'Cinamon', + 'Bernardette', + 'Makensie', + 'Lexani', + 'Miyana', + 'Costella', + 'Cliffie', + 'Lashune', + 'Windie', + 'Rhondalyn', + 'Avonelle', + 'Marcine', + 'Berneda', + 'Rosabelle', + 'Huldah', + 'Emagene', + 'Clarabell', + 'Marceil', + 'Ula', + 'Renika', + 'Shaterica', + 'Labrittany', + 'Zelia', + 'Aidy', + 'Abeeha', + 'Maebelle', + 'Farzona', + 'Bryelle', + 'Aphrodite', + 'Diyora', + 'Zilphia', + 'Ercell', + 'Starlynn', + 'Renad', + 'Reham', + 'Marwah', + 'Raaina', + 'Mehreen', + 'Chermaine', + 'Ameliah', + 'Hajra', + 'Anamika', + 'Caoimhe', + 'Tasheka', + 'Cladie', + 'Claretta', + 'Ratzy', + 'Parizoda', + 'Tzurty', + 'Simrah', + 'Miamor', + 'Mala', + 'Yittel', + 'Ranata', + 'Clellie', + 'Dewana', + 'Kenyada', + 'Sennie', + 'Estie', + 'Oprah', + 'Chessie', + 'Rumaisa', + 'Rosmery', + 'Shenell', + 'Cosima', + 'Ellyanna', + 'Hebe', + 'Aamira', + 'Beily', + 'Areesha', + 'Amilah', + 'Mahdiya', + 'Ramata', + 'Naava', + 'Cannie', + 'Dorraine', + 'Verlee', + 'Anija', + 'Garnita', + 'Lorenda', + 'Mikia', + 'Marvella', + 'Sharma', + 'Pamula', + 'Anmarie', + 'Valicia', + 'Collene', + 'Ronetta', + 'Floris', + 'Andora', + 'Berdina', + 'Ivadell', + 'Lorain', + 'Kevinisha', + 'Corielle', + 'Rinda', + 'Jodelle', + 'Arta', + 'Kalima', + 'Kalifa', + 'Liat', + 'Dashawna', + 'Jahnae', + 'Eylin', + 'Tahmina', + 'Sherin', + 'Niambi', + 'Tonjua', + 'Hanifah', + 'Maham', + 'Sokhna', + 'Carliss', + 'Nimra', + 'Quianna', + 'Shadai', + 'Renella', + 'Eliska', + 'Alima', + 'Agata', + 'Adenike', + 'Charizma', + 'Shirlean', + 'Joycelin', + 'Cyanne', + 'Ambika', + 'Albana', + 'Noshin', + 'Merve', + 'Sanjida', + 'Khiabet', + 'Maudrey', + 'Manuella', + 'Linder', + 'Bisma', + 'Shataya', + 'Shandel', + 'Samanthamarie', + 'Liron', + 'Liann', + 'Merdis', + 'Daquana', + 'Chanee', + 'Ezora', + 'Janiqua', + 'Jamielyn', + 'Kyesha', + 'Eulalie', + 'Montressa', + 'Alzina', + 'Monez', + 'Casmira', + 'Eileene', + 'Ethelmae', + 'Veneta', + 'Madiha', + 'Akeema', + 'Daneisha', + 'Cecely', + 'Gwendola', + 'Javonna', + 'Teshia', + 'Yaniris', + 'Valbona', + 'Corita', + 'Deshanna', + 'Kameka', + 'Armina', + 'Georgian', + 'Shakeera', + 'Saudia', + 'Stacyann', + 'Shenique', + 'Ura', + 'Felicie', + 'Ezola', + 'Janeece', + 'Chavely', + 'Ashling', + 'Nakea', + 'Shiana', + 'Shadasia', + 'Petronella', + 'Virgin', + 'Gunhild', + 'Brianni', + 'Grainne', + 'Aneisha', + 'Chaniece', + 'Zalika', + 'Tynasia', + 'Tashauna', + 'Shazia', + 'Shatiqua', + 'Sharissa', + 'Shanyce', + 'Shandell', + 'Shakeyla', + 'Vergia', + 'Geraldyne', + 'Dorita', + 'Nathasha', + 'Samanthajo', + 'Amela', + 'Afnan', + 'Halimah', + 'Dayatra', + 'Shontrell', + 'Tziry', + 'Shanyah', + 'Shawntell', + 'Schwanda', + 'Magalene', + 'Si', + 'Ramisa', + 'Ioanna', + 'Imane', + 'Hadar', + 'Ettel', + 'Coumba', + 'Chumy', + 'Shiran', + 'Lianny', + 'Kimara', + 'Nicha', + 'Chestine', + 'Fatmata', + 'Chedva', + 'Shaima', + 'Shailyn', + 'Zarin', + 'Zahrah', + 'Wania', + 'Tsering', + 'Syrai', + 'Suriyah', + 'No', + 'Niylah', + 'Meerab', + 'Emanuela', + 'Draizy', + 'Giabella', + 'Jeily', + 'Sofya', + 'Shantrelle', + 'Analisse', + 'Ramatoulaye', + 'Raima', + 'Sumaiyah', + 'Stori', + 'Tremeka', + 'Beila', + 'Clodagh', + 'Lyniah', + 'Giavana', + 'Tikisha', + 'Kesia', + 'Shawan', + 'Mazelle', + 'Lear', + 'Rosilyn', + 'Jnaya', + 'Jahnia', + 'Shi', + 'Henya', + 'Jhoselyn', + 'Doha', + 'Dilara', + 'Adelisa', + 'Dedria', + 'Troylynn', + 'Basha', + 'Fatimata', + 'Ama', + 'Ashantee', + 'Chania', + 'Donzella', + 'Ya', + 'Fahmida', + 'Iysis', + 'Neviah', + 'Anastasiya', + 'Brandel', + 'Afra', + 'Lendora', + 'Zisel', + 'Dwanda', + 'Ciarah', + 'Brighid', + 'Rafia', + 'Keamber', + 'Virdie', + 'Girtrude', + 'Nakaya', + 'Donis', + 'Anslei', + 'Alyene', + 'Audell', + 'Nahriah', + 'Zakeria', + 'Zoria', + 'Nikeria', + 'Kynley', + 'Karaline', + 'Jacquita', + 'Shonteria', + 'Carlyon', + 'Tykira', + 'Nykerria', + 'Lema', + 'Destyne', + 'Kansas', + 'Aryonna', + 'Iyannah', + 'Jamayah', + 'Serenitee', + 'Jood', + 'Willean', + 'Makyah', + 'Kameria', + 'Shelagh', + 'Zarriah', + 'Avionna', + 'Arilynn', + 'Vira', + 'Lelar', + 'Miyonna', + 'Jaionna', + 'Nakiah', + 'Rubby', + 'Henrene', + 'Perlie', + 'Tanyah', + 'Luretha', + 'Fannye', + 'Arquilla', + 'Albirta', + 'Annakate', + 'Akeria', + 'Teola', + 'Darthy', + 'Amberleigh', + 'Floriene', + 'Alleyne', + 'Karra', + 'Shaneika', + 'Nekita', + 'Niketa', + 'Kiaraliz', + 'Anacarolina', + 'Sharonica', + 'Renota', + 'Shambrica', + 'Mylea', + 'Jalicia', + 'Shantavious', + 'Antania', + 'Derika', + 'Rashunda', + 'Shandrea', + 'Teneisha', + 'Wachovia', + 'Jalecia', + 'Leimomi', + 'Lasondra', + 'Tela', + 'Caleah', + 'Iwalani', + 'Jamyri', + 'Azyria', + 'Napua', + 'Lahela', + 'Lehuanani', + 'Lameka', + 'Davelyn', + 'Filippa', + 'Tywanna', + 'Toini', + 'Pota', + 'Berthe', + 'Aliesha', + 'Iolanda', + 'Seaira', + 'Kealohilani', + 'Leialoha', + 'Chastidy', + 'Taimane', + 'Taylorann', + 'Briunna', + 'Tyrielle', + 'Alohilani', + 'Jakala', + 'Lakendria', + 'Tiffinie', + 'Laprecious', + 'Kaylaann', + 'Marigny', + 'Roise', + 'Kaidance', + 'Niyla', + 'Mahari', + 'Zya', + 'Ruthia', + 'Timara', + 'Caniya', + 'Keirah', + 'Arieonna', + 'Alydia', + 'Alivea', + 'Ahmani', + 'Elynn', + 'Earnstine', + 'Ramiya', + 'Morrigan', + 'Masiyah', + 'Harmoney', + 'Pearley', + 'Jearlean', + 'Korrine', + 'Chyanna', + 'Catena', + 'Pacita', + 'Kalle', + 'Alzira', + 'Tashayla', + 'Tsugie', + 'Yachiyo', + 'Shellia', + 'Sueno', + 'Kazuyo', + 'Kikumi', + 'Shizuka', + 'Chiyono', + 'Shigeno', + 'Tatsue', + 'Fumiyo', + 'Misayo', + 'Momoyo', + 'Hanayo', + 'Misae', + 'Dalaney', + 'Dewanda', + 'Itsuko', + 'Nyamal', + 'Claris', + 'Virlee', + 'Lulabelle', + 'Valada', + 'Neleigh', + 'Rafelita', + 'Placida', + 'Dulcinea', + 'Pita', + 'Heer', + 'Beren', + 'Ramoncita', + 'Orlinda', + 'Florette', + 'Deluvina', + 'Lugarda', + 'Crucita', + 'Rafaelita', + 'Pablita', + 'Lamaria', + 'Terriana', + 'Terrianna', + 'Dariyah', + 'Carmie', + 'Clotine', + 'Antha', + 'Takyla', + 'Peachie', + 'Akirah', + 'Captola', + 'Sadeel', + 'Dosha', + 'Miquela', + 'Anilah', + 'Erielle', + 'Janiylah', + 'Aubriel', + 'Priti', + 'Purvi', + 'Shakeemah', + 'Anjail', + 'Shaheerah', + 'Amneris', + 'Melverine', + 'Twilla', + 'Kruti', + 'Jalee', + 'Shareefah', + 'Muslimah', + 'Tauheedah', + 'Anabela', + 'Yakima', + 'Lyllian', + 'Tanajah', + 'Sakiyah', + 'Eun', + 'Yashika', + 'Ji', + 'Demiana', + 'Mariaeduard', + 'Snigdha', + 'Dala', + 'Kum', + 'Myung', + 'Hadiyah', + 'Gopi', + 'Cresta', + 'In', + 'Davita', + 'Talayeh', + 'Tracyann', + 'Petula', + 'Nerida', + 'Jeaneen', + 'Ilissa', + 'Letta', + 'Kishia', + 'Gesenia', + 'Bethsaida', + 'Tanija', + 'Ivelise', + 'Marines', + 'Angenette', + 'Alanda', + 'Lauraann', + 'Darnetta', + 'Alisande', + 'Jeniya', + 'Patria', + 'Tieysha', + 'Tasheen', + 'Ife', + 'Loredana', + 'Amyjo', + 'Chane', + 'Nilka', + 'Sharema', + 'Grazia', + 'Renna', + 'Tahesha', + 'Tarita', + 'Jannis', + 'Geriann', + 'Areatha', + 'Rosangel', + 'Kemba', + 'Noni', + 'Margaretann', + 'Kimberleigh', + 'Latisa', + 'Kiriaki', + 'Bobbyjo', + 'Walida', + 'Lynanne', + 'Niyanna', + 'Daziah', + 'Kharma', + 'Pier', + 'Marymargaret', + 'Lorrain', + 'Ketty', + 'Helane', + 'Tarnisha', + 'Sherrice', + 'Swati', + 'Donnajean', + 'Tunya', + 'Annmargaret', + 'Raffaella', + 'Pina', + 'Deneene', + 'Lorriane', + 'Shenise', + 'Ziyonna', + 'Evagelia', + 'Chantae', + 'Tasheema', + 'Meaghen', + 'Shanikqua', + 'Lynnox', + 'Taiesha', + 'Sharima', + 'Shantai', + 'Shaena', + 'Jamine', + 'Rasheena', + 'Tashi', + 'Magdala', + 'Edia', + 'Lasheka', + 'Tiasha', + 'Quanita', + 'Jomayra', + 'Nairoby', + 'Danamarie', + 'Roena', + 'Zasha', + 'Shatema', + 'Orissa', + 'Elvire', + 'Louisiana', + 'Hoda', + 'Kashana', + 'Jaquanna', + 'Jacqulin', + 'Annamari', + 'Marquia', + 'Elmire', + 'Viney', + 'Sonna', + 'Yokasta', + 'Esma', + 'Rella', + 'Deloras', + 'Janill', + 'Samanthan', + 'Ketsia', + 'Chaunte', + 'Aderonke', + 'Sheindel', + 'Shameen', + 'Karema', + 'Amalin', + 'Glendaliz', + 'Finesse', + 'Talibah', + 'Lakima', + 'Geeta', + 'Suehay', + 'Dorice', + 'Aesha', + 'Lateasha', + 'Kimitra', + 'Omolola', + 'Bobbette', + 'Deliah', + 'Carianne', + 'Chanah', + 'Laquandra', + 'Laquanna', + 'Yanick', + 'Nathifa', + 'Nakima', + 'Gayl', + 'Shamaine', + 'Saquana', + 'Nixzaliz', + 'Chaye', + 'Maleka', + 'Latima', + 'Yamira', + 'Tashanna', + 'Kathiria', + 'Jameika', + 'Jamesetta', + 'Moniqua', + 'Yamaris', + 'Tasheba', + 'Virgina', + 'Aviance', + 'Calogera', + 'Candita', + 'Kinga', + 'Alissia', + 'Onnolee', + 'Johnda', + 'Sebastiana', + 'Michelena', + 'Tecla', + 'Mirriam', + 'Sydel', + 'Glema', + 'Tatiyanna', + 'Patrycia', + 'Fortuna', + 'Ebba', + 'Carmelia', + 'Liddie', + 'Genella', + 'Detta', + 'Malvery', + 'Evelene', + 'Loretto', + 'Nunziata', + 'Jenan', + 'Keshawna', + 'Kinisha', + 'Tikia', + 'Sueanne', + 'Cira', + 'Charda', + 'Midge', + 'Annina', + 'Delcina', + 'Barbette', + 'Danah', + 'Isolina', + 'Tanita', + 'Gracemarie', + 'Halleigh', + 'Julita', + 'Kaprice', + 'Dorothyann', + 'Binnie', + 'Bettyjean', + 'Frayda', + 'Tashiana', + 'Breshey', + 'Charnise', + 'Tashena', + 'Meribeth', + 'Sandralee', + 'Heena', + 'Walda', + 'Latika', + 'Rashaunda', + 'Linde', + 'Rosaleen', + 'Illona', + 'Clydette', + 'Benay', + 'Damonica', + 'Anajah', + 'Louelle', + 'Lunette', + 'Faduma', + 'Nadeige', + 'Meylin', + 'Elverna', + 'Etrulia', + 'Ellaree', + 'Rushie', + 'Jayona', + 'Mauri', + 'Radiah', + 'Runette', + 'Terrah', + 'Joia', + 'Ezma', + 'Glenys', + 'Ramla', + 'Shatasha', + 'Berma', + 'Chanteria', + 'Chantrell', + 'Elvi', + 'Sharnell', + 'Rether', + 'Keshana', + 'Ranesha', + 'Earther', + 'Zahirah', + 'Anye', + 'Khori', + 'Saniyyah', + 'Teniola', + 'Anniemae', + 'Oluwadamilola', + 'Aldene', + 'Amellia', + 'Junice', + 'Carolene', + 'Ireoluwa', + 'Nasra', + 'Vernease', + 'Delrose', + 'Marysue', + 'Mirlande', + 'Lashannon', + 'Taijah', + 'Markiesha', + 'Syanne', + 'Jahiya', + 'Vyonne', + 'Reniya', + 'Ryana', + 'Idonia', + 'Loette', + 'Etheleen', + 'Ariyon', + 'Jeneane', + 'Jamea', + 'Airyana', + 'Natesha', + 'Bonnell', + 'Savilla', + 'Daneshia', + 'Deneshia', + 'Alexzandrea', + 'Martharee', + 'Elfreda', + 'Danyla', + 'Retaj', + 'Childnotnamed', + 'Kariana', + 'Ladeja', + 'Johnesha', + 'Nariya', + 'Zamariah', + 'Shanyla', + 'Zykiria', + 'Micaella', + 'Angeliyah', + 'Camara', + 'Kenniyah', + 'Keyani', + 'Renie', + 'Aldena', + 'Paytyn', + 'Perma', + 'Annamary', + 'Roniyah', + 'Zeniya', + 'Capitola', + 'Jaiana', + 'Lakiya', + 'Reida', + 'Ahniya', + 'Elanor', + 'Dorothee', + 'Joud', + 'Ludmilla', + 'Traniyah', + 'Kjerstin', + 'Jeylin', + 'Teona', + 'Marypat', + 'Jacquelynne', + 'Harmonii', + 'Kenyah', + 'Anora', + 'Deniyah', + 'Tyleah', + 'Samora', + 'Almeter', + 'Floride', + 'Lether', + 'Aviah', + 'Livie', + 'Federica', + 'Khalani', + 'Dericka', + 'Ronisue', + 'Raziah', + 'Emaya', + 'Christyana', + 'Rasheka', + 'Jahira', + 'Jalana', + 'Lateria', + 'Baneen', + 'Davisha', + 'Joyanna', + 'Janelys', + 'Raneisha', + 'Israa', + 'Shauntavia', + 'Shericka', + 'Deloma', + 'Maryetta', + 'Jeannetta', + 'Tymber', + 'Charmon', + 'Lanise', + 'Charlisa', + 'Bloneva', + 'Andrena', + 'Katena', + 'Latorria', + 'Letoya', + 'Quovadis', + 'Lakeisa', + 'Sihaam', + 'Charo', + 'Annaclara', + 'Margretta', + 'Nataki', + 'Tyjae', + 'Bahja', + 'Shequila', + 'Quadira', + 'Toinette', + 'Sumeya', + 'Takita', + 'Sherlonda', + 'Daejah', + 'Zyanna', + 'Antonique', + 'Linnae', + 'Georgean', + 'Charlane', + 'Jakerria', + 'Nimo', + 'Saprina', + 'Detrice', + 'Nicolly', + 'Nayara', + 'Seandra', + 'Demetrica', + 'Kayton', + 'Jalayna', + 'Emanuelly', + 'Dondra', + 'Michaeleen', + 'Aquinnah', + 'Lakrisha', + 'Latoia', + 'Bernessia', + 'Jaydaliz', + 'Deona', + 'Donyelle', + 'Kearsten', + 'Tashira', + 'Kaisa', + 'Korrin', + 'Onelia', + 'Shawntia', + 'Faylene', + 'Nafeesah', + 'Synetta', + 'Robertine', + 'Krystn', + 'Nyjae', + 'Nijae', + 'Cieara', + 'Ellerie', + 'Thomasenia', + 'Tiki', + 'Lougenia', + 'Joeann', + 'Marlyss', + 'Saralee', + 'Dayona', + 'Alainna', + 'Gennell', + 'Berline', + 'Latoiya', + 'Eyvonne', + 'Cherline', + 'Tequesta', + 'Loann', + 'Kerstyn', + 'Najmo', + 'Shanitra', + 'Marnice', + 'Tamyah', + 'Ave', + 'Cierrah', + 'Deborahann', + 'Davette', + 'Kennidy', + 'Breelle', + 'Lundon', + 'Imoni', + 'Shamyah', + 'Lindia', + 'Caylyn', + 'Ghadeer', + 'Amirrah', + 'Arlayne', + 'Norrine', + 'Vondell', + 'Ruqaya', + 'Azariya', + 'Narice', + 'Glenadine', + 'Lallie', + 'Conola', + 'Airlie', + 'Lorelie', + 'Levis', + 'Sanyia', + 'Mckaela', + 'Arlina', + 'Dellar', + 'Zorianna', + 'Zanyiah', + 'Maleya', + 'Niyana', + 'Amonie', + 'Aryia', + 'Autie', + 'Keileigh', + 'Kyndel', + 'Saliyah', + 'Naziah', + 'Bernette', + 'Vona', + 'Venie', + 'Tyashia', + 'Khaliya', + 'Mckensie', + 'Kerigan', + 'Kaniah', + 'Eria', + 'Maziyah', + 'Kiasia', + 'Anice', + 'Dera', + 'Georgena', + 'Ezelle', + 'Eavan', + 'Marlyne', + 'Lovella', + 'Westonia', + 'Keniah', + 'Janiaya', + 'Mertice', + 'Marget', + 'Zyeria', + 'Marquerite', + 'Minha', + 'Redonna', + 'Deetta', + 'Aiyla', + 'Majel', + 'Elnor', + 'Deronda', + 'Viona', + 'Rosaleigh', + 'Virgiline', + 'Reeda', + 'Minnah', + 'Keerthi', + 'Kaleyah', + 'Myanna', + 'Remas', + 'Noralee', + 'Idabelle', + 'Albena', + 'Ellory', + 'Areej', + 'Zariel', + 'Laverle', + 'Hjordis', + 'Hilja', + 'Ragna', + 'Cordella', + 'Irean', + 'Ottilia', + 'Gerane', + 'Locklyn', + 'Equilla', + 'Dellie', + 'Aarvi', + 'Mardella', + 'Leighanna', + 'Theone', + 'Ordella', + 'Lidwina', + 'Alyda', + 'Arlyss', + 'Evangelita', + 'Hee', + 'Cherell', + 'Charelle', + 'Shealynn', + 'Anesha', + 'Jasman', + 'Stephie', + 'Ok', + 'Tacarra', + 'Sharnita', + 'Jessic', + 'Dulcey', + 'Natina', + 'Sharvae', + 'Nachelle', + 'Jillane', + 'Tarri', + 'Ajena', + 'Allexus', + 'Labrenda', + 'Pammy', + 'Shemeika', + 'Ysela', + 'Meghin', + 'Marketta', + 'Porshe', + 'Kayti', + 'Taylour', + 'Shavonte', + 'Aivah', + 'Khloi', + 'Jerzie', + 'Nikesha', + 'Cherron', + 'Coralynn', + 'Alvita', + 'Carlita', + 'Albany', + 'Deshawnda', + 'Lacole', + 'Lameeka', + 'Mashawn', + 'Kimyata', + 'Keenya', + 'Baya', + 'Kiva', + 'Samona', + 'Meggin', + 'Chanita', + 'Danissa', + 'Lileigh', + 'Addeline', + 'Shemeeka', + 'Aprille', + 'Donice', + 'Tannisha', + 'Angelette', + 'Lakeita', + 'Marcelyn', + 'Lesta', + 'Claudene', + 'Marney', + 'Tonyia', + 'Nellora', + 'Kimyetta', + 'Ameliana', + 'Electa', + 'Sherl', + 'Jeniece', + 'Jawana', + 'Errica', + 'Braya', + 'Titania', + 'Guydra', + 'Valeta', + 'Danetta', + 'Sharia', + 'Hawraa', + 'Danaja', + 'Makalynn', + 'Tayonna', + 'Kyrene', + 'Arieona', + 'Dallie', + 'Ruie', + 'Ophia', + 'Odella', + 'Vessie', + 'Offie', + 'Evadean', + 'Ample', + 'Aleecia', + 'Shakyla', + 'Makynna', + 'Lakyra', + 'Korryn', + 'Araina', + 'Semiyah', + 'Ndea', + 'Areonna', + 'Jasia', + 'Xavia', + 'Merikay', + 'Keshara', + 'Jennetta', + 'Vergene', + 'Wilodean', + 'Wyona', + 'Avonell', + 'Datha', + 'Ellar', + 'Morene', + 'Laverda', + 'Loetta', + 'Emmogene', + 'Arbadella', + 'Camaria', + 'Rochella', + 'Indiya', + 'Shayma', + 'Orneta', + 'Clotene', + 'Genoa', + 'Lanyah', + 'Oneda', + 'Glendola', + 'Rosala', + 'Zelphia', + 'Suda', + 'Jerrilynn', + 'Orlena', + 'Lorella', + 'Bernadean', + 'Novice', + 'Pheba', + 'Rukaya', + 'Gathel', + 'Meron', + 'Asianae', + 'Arriel', + 'Whisper', + 'Talesha', + 'Morgann', + 'Madissen', + 'Dajanay', + 'Karil', + 'Sherrita', + 'Chery', + 'Lezlee', + 'Daytona', + 'Raegen', + 'Dalal', + 'Majerle', + 'Lama', + 'Daijanae', + 'Celicia', + 'Cheril', + 'Cornesha', + 'Aniza', + 'Clytie', + 'Persis', + 'Aino', + 'Lawandra', + 'Deshonda', + 'Catrena', + 'Temekia', + 'Camella', + 'Arnetra', + 'Latoyna', + 'Tekisha', + 'Nalee', + 'Jennife', + 'Daphanie', + 'Shewanda', + 'Cheronda', + 'Latayna', + 'Almerinda', + 'Danene', + 'Jadwiga', + 'Ellora', + 'Tanga', + 'Tamekka', + 'Lashond', + 'Shinika', + 'Khyleigh', + 'Baelyn', + 'Clarene', + 'Monyette', + 'Lakisa', + 'Audreyanna', + 'Malayjah', + 'Keia', + 'Lajessica', + 'Marquite', + 'Odessia', + 'Marketia', + 'Malayshia', + 'Laconya', + 'Brayla', + 'Germani', + 'Luberdie', + 'Angla', + 'Cona', + 'Katrinia', + 'Shaletha', + 'Eutha', + 'Elmyra', + 'Cleva', + 'Elnore', + 'Vila', + 'Evone', + 'Margert', + 'Pairlee', + 'Bernelle', + 'Diannie', + 'Alinda', + 'Emerine', + 'Rogena', + 'Genette', + 'Jearline', + 'Estalee', + 'Bertina', + 'Cassand', + 'Kisa', + 'Veronic', + 'Idalina', + 'Walsie', + 'Gwendol', + 'Orvilla', + 'Latonga', + 'Elizabe', + 'Bernece', + 'Charlen', + 'Dola', + 'Alaija', + 'Martia', + 'Shanica', + 'Shariya', + 'Yuliya', + 'Atleigh', + 'Flannery', + 'Loeta', + 'Zakiah', + 'Alayia', + 'Glee', + 'Embree', + 'Kasidy', + 'Zacaria', + 'Derriona', + 'Jakyria', + 'Kiauna', + 'Garnelle', + 'Tyriana', + 'Juliya', + 'Maddisen', + 'Auna', + 'Jameisha', + 'Lurleen', + 'Kourtlyn', + 'Chelan', + 'Verlinda', + 'Sherria', + 'Alzada', + 'Ketara', + 'Anaka', + 'Breion', + 'Shadestiny', + 'Shanterica', + 'Tenia', + 'Keiosha', + 'Jamyriah', + 'Jamyrie', + 'Jalacia', + 'Ronita', + 'Maryln', + 'Earsie', + 'Kyri', + 'Markiyah', + 'Malajah', + 'Alandria', + 'Shaquitta', + 'Raymona', + 'Paeton', + 'Yaritzy', + 'Jonesha', + 'Anda', + 'Khadjah', + 'Amyree', + 'Vernestine', + 'Lavetta', + 'Jniya', + 'Shakiyah', + 'Aasia', + 'Roniya', + 'Keleigh', + 'Makalyn', + 'Kadasia', + 'Johneisha', + 'Jakaya', + 'Kinzey', + 'Wendelyn', + 'Darielys', + 'Wyteria', + 'Yarieliz', + 'Taysia', + 'Carmya', + 'Erionna', + 'Shameria', + 'Kearia', + 'Graycie', + 'Jurnie', + 'Calypso', + 'Finlee', + 'Fynlee', + 'Sophee', + 'Lorali', + 'Shacoria', + 'Kadeejah', + 'Lakira', + 'Kelsay', + 'Angelys', + 'Moeshia', + 'Keundra', + 'Mayara', + 'Josi', + 'Annaluiza', + 'Jacquese', + 'Jillaine', + 'Annajulia', + 'Nayeliz', + 'Maire', + 'Jamonica', + 'Jadalys', + 'Missie', + 'Machell', + 'Liisa', + 'Jalaine', + 'Odester', + 'Veria', + 'Virda', + 'Arleene', + 'Cigi', + 'Eloda', + 'Kacelyn', + 'Cidalia', + 'Vadie', + 'Wydell', + 'Donnita', + 'Lousie', + 'Oreatha', + 'Berdine', + 'Cielita', + 'Lilas', + 'Verneda', + 'Armelia', + 'Glender', + 'Elizbeth', + 'Vanella', + 'Florean', + 'Vyolet', + 'Albertia', + 'Albirda', + 'Sylva', + 'Lakresha', + 'Matha', + 'Nerine', + 'Dezzie', + 'Lodell', + 'Rosielee', + 'Julane', + 'Lodena', + 'Brookley', + 'Kynadi', + 'Krymson', + 'Etoile', + 'Meighan', + 'Izella', + 'Jakaria', + 'Jaleria', + 'Clister', + 'Alberdia', + 'Zykeriah', + 'Mileigh', + 'Isola', + 'Mamye', + 'Eller', + 'Kamoria', + 'Lakelynn', + 'Aslean', + 'Bular', + 'Emmaclaire', + 'Dasie', + 'Denotra', + 'Everlene', + 'Lynleigh', + 'Iantha', + 'Quinetta', + 'Lillion', + 'Sophronia', + 'Japonica', + 'Beauty', + 'Pearlina', + 'Evella', + 'Jatana', + 'Kechia', + 'Conswella', + 'Malissia', + 'Alexina', + 'Demeka', + 'Muguette', + 'Vaudine', + 'Aprill', + 'Villa', + 'Florece', + 'Tonjia', + 'Bethania', + 'Makinlee', + 'Latondra', + 'Audery', + 'Ericia', + 'Miyoshi', + 'Betti', + 'Harlym', + 'Novelle', + 'Liller', + 'Pinkey', + 'Narcille', + 'Lasheika', + 'Leonise', + 'Lydie', + 'Olla', + 'Rejeanne', + 'Athelene', + 'Eloyse', + 'Edolia', + 'Clotile', + 'Ethelrine', + 'Devonda', + 'Nakeshia', + 'Tomesha', + 'Orena', + 'Karlyne', + 'Enolia', + 'Faynell', + 'Margia', + 'Marvelene', + 'Justilia', + 'Iceola', + 'Shantina', + 'Shinita', + 'Loula', + 'Ireta', + 'Vanessia', + 'Ramonia', + 'Monita', + 'Shalva', + 'Ong', + 'Remonia', + 'Sheral', + 'Angelean', + 'Phyllistine', + 'Brenetta', + 'Madgeline', + 'Zyairah', + 'Anjolaoluwa', + 'Clotiel', + 'Eldine', + 'Tylia', + 'Ifeoluwa', + 'Florestine', + 'Althia', + 'Ravonda', + 'Tsion', + 'Zyaira', + 'Wylodene', + 'Janesha', + 'Vonciel', + 'Ruthey', + 'Khiana', + 'Kadesia', + 'Murdis', + 'Zhana', + 'Jillayne', + 'Quatisha', + 'Jaquasia', + 'Michaila', + 'Mashayla', + 'Travia', + 'Tyrika', + 'Aldah', + 'Makaiya', + 'Maridee', + 'Kyndell', + 'Nykira', + 'Mazell', + 'Luecile', + 'Quatasia', + 'Khala', + 'Sible', + 'Jakera', + 'Ovella', + 'Lealer', + 'Juleen', + 'Rinette', + 'Laykin', + 'Ozite', + 'Shaquanta', + 'Quanetta', + 'Shannyn', + 'Lacrystal', + 'Everline', + 'Editha', + 'Toneka', + 'Reinette', + 'Maclovia', + 'Ledia', + 'Shakeeka', + 'Shakeeta', + 'Taquanna', + 'Miyisha', + 'Patrecia', + 'Wylodean', + 'Solita', + 'Dalisa', + 'Jatoya', + 'Texanna', + 'Yvetta', + 'Lectoria', + 'Cyntrell', + 'Monyae', + 'Ibtisam', + 'Miski', + 'Renesha', + 'Maelle', + 'Azhar', + 'Zamzam', + 'Jamera', + 'Tyranika', + 'Ladan', + 'Ruweyda', + 'Jabrea', + 'Sherrica', + 'Clyda', + 'Treniece', + 'Fonnie', + 'Bedie', + 'Kewanda', + 'Mozel', + 'Tramika', + 'Quessie', + 'Tyshay', + 'Ladasha', + 'Kaarin', + 'Mazzie', + 'Genora', + 'Monie', + 'Muntas', + 'Hayat', + 'Jovanda', + 'Appolonia', + 'Cuma', + 'Briante', + 'Reneisha', + 'Zenovia', + 'Allysia', + 'Aliene', + 'Raini', + 'Tyja', + 'Iriel', + 'Deshante', + 'Shatira', + 'Demri', + 'Ajaysia', + 'Ireon', + 'Idil', + 'Nawaal', + 'Riham', + 'Nyeisha', + 'Jonique', + 'Keneisha', + 'Ravan', + 'Khadra', + 'Dawanna', + 'Gavriella', + 'Myrene', + 'Jasamine', + 'Brione', + 'Earlisha', + 'Dazia', + 'Jalesia', + 'Cabrina', + 'Marieme', + 'Gloristine', + 'Cattie', + 'Damilola', + 'Evora', + 'Almarie', + 'Vauda', + 'Tanzie', + 'Truby', + 'Tayona', + 'Francelia', + 'Brona', + 'Jannice', + 'Weltha', + 'Phylliss', + 'Vieva', + 'Danera', + 'Saratha', + 'Colinda', + 'Suzonne', + 'Shelene', + 'Shelda', + 'Annye', + 'Kaola', + 'Modine', + 'Velvie', + 'Vetra', + 'Tyrhonda', + 'Malissie', + 'Shemica', + 'Rockell', + 'Adgie', + 'Lachanda', + 'Kwanza', + 'Keyanta', + 'Hazeleen', + 'Yarnell', + 'Mettie', + 'Kissie', + 'Jawanna', + 'Ilham', + 'Enchantra', + 'Lucielle', + 'Salmo', + 'Sabrin', + 'Nicy', + 'Rubell', + 'Willet', + 'Ronata', + 'Semiko', + 'Idman', + 'Meoshia', + 'Maie', + 'Eulala', + 'Tiyonna', + 'Sabarin', + 'Merlie', + 'Oneka', + 'Khiya', + 'Geralene', + 'Hubbie', + 'Patches', + 'Robenia', + 'Carita', + 'Veleka', + 'Tamla', + 'Zondra', + 'Cheramie', + 'Nimco', + 'Chauntelle', + 'Calonia', + 'Mulki', + 'Clydia', + 'Glida', + 'Fartun', + 'Fardowsa', + 'Iyona', + 'Dwanna', + 'Angila', + 'Carletha', + 'Blakley', + 'Valecia', + 'Songa', + 'Shya', + 'Kamber', + 'Siah', + 'Sloka', + 'Sophiagrace', + 'Sophiamarie', + 'Setayesh', + 'Roselie', + 'Samhitha', + 'Savreen', + 'Zanayah', + 'Yilia', + 'Zareena', + 'Yeilin', + 'Ulyana', + 'Tylie', + 'Vaani', + 'Vasilisa', + 'Videl', + 'Xylia', + 'Rubylee', + 'Jessye', + 'Itasca', + 'Bonifacia', + 'Bennye', + 'Estellene', + 'Daycee', + 'Vung', + 'Babe', + 'Lucyle', + 'Laurencia', + 'Frankye', + 'Clariece', + 'Alsace', + 'Ernesteen', + 'Zuma', + 'Loleta', + 'Matiana', + 'Thyra', + 'Thekla', + 'Miladie', + 'Moselle', + 'Waldene', + 'Thula', + 'Ethelda', + 'Elbira', + 'Eddye', + 'Lafaye', + 'Beryle', + 'Beanna', + 'Basilisa', + 'Bernardina', + 'Vontressa', + 'Elner', + 'Gladine', + 'Saketha', + 'Nellene', + 'Margurette', + 'Levada', + 'Alcie', + 'Beuna', + 'Miaa', + 'Miia', + 'Miral', + 'Lunabella', + 'Manvi', + 'Nahlia', + 'Quetzal', + 'Preet', + 'Navreet', + 'Prajna', + 'Analayah', + 'Aalaya', + 'Aaleah', + 'Aaria', + 'Aby', + 'Adeena', + 'Adelaine', + 'Adhara', + 'Alekhya', + 'Avaline', + 'Avina', + 'Azaliah', + 'Azayla', + 'Anwita', + 'Arna', + 'Asmi', + 'Cutina', + 'Jaydalynn', + 'Jerusalem', + 'Hiyab', + 'Icey', + 'Jaanvi', + 'Khalessi', + 'Khiara', + 'Leelah', + 'Ketzaly', + 'Kaliyanei', + 'Karolynn', + 'Kaylonnie', + 'Harveen', + 'Danilynn', + 'Decklyn', + 'Deleyza', + 'Charm', + 'Calina', + 'Cathaleya', + 'Dailynn', + 'Corra', + 'Cyrene', + 'Eveleen', + 'Fia', + 'Galina', + 'Gohar', + 'Gursirat', + 'Harleyquinn', + 'Evalin', + 'Eevee', + 'Eira', + 'Elara', + 'Ellaina', + 'Ellarose', + 'Erabella', + 'Teofila', + 'Calamity', + 'Sherion', + 'Niang', + 'Oreta', + 'Leita', + 'Maedelle', + 'Othello', + 'Meshell', + 'Alfreida', + 'Detria', + 'Cloda', + 'Ermine', + 'Gertrudes', + 'Zudora', + 'Benigna', + 'Dolorez', + 'Narcissa', + 'Eduviges', + 'Dionisia', + 'Crisanta', + 'Adreena', + 'Aivy', + 'Sharanda', + 'Amma', + 'Danitra', + 'Lashuna', + 'Yasheka', + 'Sheronica', + 'Ameliya', + 'Cayetana', + 'Benancia', + 'Tiya', + 'Umaiza', + 'Vicktoria', + 'Vidushi', + 'Yaretzie', + 'Siennah', + 'Sofiah', + 'Stuti', + 'Taitum', + 'Yuli', + 'Zarya', + 'Zeriah', + 'Sadiee', + 'Rubee', + 'Ryenn', + 'Sayana', + 'Ezabella', + 'Galya', + 'Hayzel', + 'Evalette', + 'Eleanna', + 'Elize', + 'Elleana', + 'Hiya', + 'Jezabelle', + 'Jazzy', + 'Jeraldin', + 'Jocabed', + 'Kaloni', + 'Jazmeen', + 'Jasmarie', + 'Ilani', + 'Ilany', + 'Ariannie', + 'Angelinne', + 'Delaynie', + 'Calise', + 'Bethlehem', + 'Cateleya', + 'Paitynn', + 'Peytin', + 'Rainie', + 'Rhylin', + 'Rosaly', + 'Nomi', + 'Mirai', + 'Moksha', + 'Mylin', + 'Nazeli', + 'Nilani', + 'Marcelene', + 'Victorina', + 'Laiah', + 'Leeyah', + 'Miaisabella', + 'Ravleen', + 'Lazara', + 'Zuleidy', + 'Shraddha', + 'Simarpreet', + 'Rinoa', + 'Ridhima', + 'Ryla', + 'Ryleeann', + 'Ryli', + 'Sahori', + 'Smrithi', + 'Yeslin', + 'Yanessa', + 'Zeltzin', + 'Sonakshi', + 'Sophea', + 'Carlissa', + 'Bryttani', + 'Albesa', + 'Bonnye', + 'Daksha', + 'Terria', + 'Davinah', + 'Enalina', + 'Evolette', + 'Dhwani', + 'Eleora', + 'Leea', + 'Lexii', + 'Meilyn', + 'Nevah', + 'Noga', + 'Prabhleen', + 'Quinley', + 'Mursal', + 'Naiara', + 'Navah', + 'Izumi', + 'Janelli', + 'Jniyah', + 'Klaryssa', + 'Kritika', + 'Laksmi', + 'Lalani', + 'Joselle', + 'Kashish', + 'Kenyana', + 'Laquishia', + 'Deshonna', + 'Sentoria', + 'Ernestene', + 'Maxima', + 'Senovia', + 'Nestora', + 'Valta', + 'Casady', + 'Daphene', + 'Chonita', + 'Omelia', + 'Odena', + 'Melchora', + 'Quetzally', + 'Thera', + 'Gabina', + 'Donaciana', + 'Riddhima', + 'Lakessa', + 'Lakeeta', + 'Katasha', + 'Chaitra', + 'Chizara', + 'Aveyah', + 'Elah', + 'Eliannah', + 'Ellanore', + 'Emmalia', + 'Dalexa', + 'Delara', + 'Donatella', + 'Aubreanna', + 'Aberdeen', + 'Aerilyn', + 'Aleksia', + 'Annarose', + 'Anthea', + 'Aoi', + 'Amberrose', + 'Anaeli', + 'Lilou', + 'Lumen', + 'Manasvi', + 'Lillybeth', + 'Keylani', + 'Lenya', + 'Lidya', + 'Mulan', + 'Nirvi', + 'Ondine', + 'Meenakshi', + 'Mathea', + 'Melyna', + 'Io', + 'Izelle', + 'Jailia', + 'Eztli', + 'Gali', + 'Hade', + 'Hafsah', + 'Hannahgrace', + 'Kayleah', + 'Kayleeann', + 'Kemily', + 'Jeylah', + 'Jiaqi', + 'Sherrika', + 'Daffney', + 'Solstice', + 'Soriah', + 'Sumayya', + 'Saory', + 'Shaily', + 'Shanzay', + 'Sharvi', + 'Xylina', + 'Yeimy', + 'Yizel', + 'Zaidee', + 'Ziah', + 'Jesucita', + 'Madalena', + 'Vontresa', + 'Tangee', + 'Shekina', + 'Sista', + 'Norvis', + 'Winnell', + 'Yoshida', + 'Nikiya', + 'Vidala', + 'Shandria', + 'Rozelle', + 'Maragret', + 'Sixta', + 'Theta', + 'Wylma', + 'Jobita', + 'Gaudalupe', + 'Lurlean', + 'Oveta', + 'Heriberta', + 'Bacilia', + 'Senorina', + 'Denika', + 'Akeisha', + 'Tamecia', + 'Jera', + 'Crestina', + 'Shwanda', + 'Kelbie', + 'Sanayah', + 'Zaliah', + 'Nadezhda', + 'Maaliyah', + 'Mahaley', + 'Raziyah', + 'Saraiya', + 'Cyriah', + 'Chaniyah', + 'Emmarae', + 'Eleen', + 'Ashland', + 'Briniyah', + 'Ainhoa', + 'Aviyah', + 'Atarah', + 'Lutrelle', + 'Clevie', + 'Blossie', + 'Cola', + 'Para', + 'Verdelle', + 'Beddie', + 'Lilliemae', + 'Jurell', + 'Bertice', + 'Fozie', + 'Oppie', + 'Rozia', + 'Rozie', + 'Epsie', + 'Karman', + 'Estoria', + 'Dynesha', + 'Sarae', + 'Xolani', + 'Talyah', + 'Zanaria', + 'Zamiah', + 'Starkeisha', + 'Alys', + 'Izaria', + 'Cayenne', + 'Damiah', + 'Alwilda', + 'Leoda', + 'Yariah', + 'Tuleen', + 'Rhelda', + 'Carlesha', + 'Alfretta', + 'Orma', + 'Ornella', + 'Nazyia', + 'Samorah', + 'Keyonni', + 'Jeriyah', + 'Jazariyah', + 'Demaria', + 'Mikeyla', + 'Malania', + 'Miyanna', + 'Neriyah', + 'Naelle', + 'Lazariah', + 'Rea', + 'Annaya', + 'Aleanna', + 'Baylin', + 'Aela', + 'Emmilyn', + 'Anila', + 'Rodnesha', + 'Janeliz', + 'Kseniya', + 'Nyana', + 'Zemirah', + 'Somya', + 'Yanna', + 'Terryn', + 'Naika', + 'Laiyla', + 'Lyrica', + 'Loralie', + 'Lilya', + 'Wonnie', + 'Runelle', + 'Tynleigh', + 'Loralye', + 'Arynn', + 'Melvis', + 'Akiyah', + 'Matline', + 'Ellean', + 'Wylean', + 'Marfa', + 'Elliemae', + 'Nancey', + 'Waltina', + 'Ommie', + 'Lonia', + 'Reaver', + 'Virdell', + 'Rosabell', + 'Sarahgrace', + 'Faustine', + 'Euretha', + 'Sussie', + 'Rebie', + 'Oveline', + 'Reathel', + 'Algia', + 'Mylissa', + 'Rethel', + 'Nakyla', + 'Necia', + 'Deanie', + 'Beckey', + 'Yasmen', + 'Yukari', + 'Zamyra', + 'Roselinda', + 'Takeko', + 'Vicke', + 'Mckala', + 'Hanae', + 'Elley', + 'Ellyssa', + 'Geanna', + 'Geetika', + 'Elenoa', + 'Elane', + 'Deeya', + 'Deviny', + 'Genecis', + 'Jasminerose', + 'Ireri', + 'Hailei', + 'Hannya', + 'Harshini', + 'Holiday', + 'Arista', + 'Dannae', + 'Melayna', + 'Meleni', + 'Mystique', + 'Nathalya', + 'Natsumi', + 'Sharlize', + 'Shine', + 'Sindhu', + 'Starlyn', + 'Sarika', + 'Sarine', + 'Seleen', + 'Khalea', + 'Kirti', + 'Jocilyn', + 'Maille', + 'Mariaceleste', + 'Leelee', + 'Leidi', + 'Libertad', + 'Lizvet', + 'Kierstan', + 'Adja', + 'Debbye', + 'Dorenda', + 'Kiyono', + 'Katsuko', + 'Katsue', + 'Misue', + 'Umeno', + 'Rayvin', + 'Sachie', + 'Kinue', + 'Danajah', + 'Denay', + 'Tsuneko', + 'Tamae', + 'Saeko', + 'Tsutako', + 'Sumako', + 'Momoe', + 'Tomoko', + 'Asae', + 'Nautika', + 'Kourtnee', + 'Keauna', + 'Maydeen', + 'Chianne', + 'Macala', + 'Briaunna', + 'Ceirra', + 'Kimberlea', + 'Normalinda', + 'Milinda', + 'Jonetta', + 'Seleta', + 'Chryl', + 'Aaminah', + 'Mersades', + 'Mickenzie', + 'Tahlor', + 'Kimetha', + 'Hopie', + 'Guadulupe', + 'Blakelynn', + 'Orfelinda', + 'Aubre', + 'Ajayla', + 'Makenlee', + 'Journii', + 'Janayla', + 'Talulah', + 'Siddhi', + 'Shaira', + 'Yuridiana', + 'Yulitza', + 'Tulsi', + 'Yatana', + 'Jaleya', + 'Ayrianna', + 'Damaya', + 'Myana', + 'Lanyiah', + 'Kadince', + 'Aunna', + 'Avrielle', + 'Khyli', + 'Kariyah', + 'Bralynn', + 'Derrianna', + 'Maryella', + 'Charlynn', + 'Ilma', + 'Tresea', + 'Mersadies', + 'Macenzie', + 'Terriona', + 'Telia', + 'Tamryn', + 'Tahari', + 'Solyana', + 'Lyrical', + 'Akie', + 'Teruyo', + 'Shizuyo', + 'Tsuruyo', + 'Daviona', + 'Marshelia', + 'Connye', + 'Marka', + 'Adelmira', + 'Dorelia', + 'Nirel', + 'Oceanna', + 'Neeka', + 'Sherolyn', + 'Sheralyn', + 'Sharlet', + 'Milenka', + 'Astha', + 'Angeleena', + 'Anysia', + 'Apoorva', + 'Bryanah', + 'Carolyna', + 'Cecy', + 'Anadalay', + 'Akaylah', + 'Aika', + 'Aasha', + 'Ahniah', + 'Adelayda', + 'Kyaira', + 'Manmeet', + 'Linsy', + 'Malini', + 'Mairany', + 'Haeley', + 'Evelen', + 'Jezel', + 'Jinelle', + 'Joleena', + 'Hikari', + 'Inari', + 'Itcel', + 'Lokelani', + 'Keikilani', + 'Sherilynn', + 'Jamieann', + 'Lajuanna', + 'Roselind', + 'Rhetta', + 'Alysah', + 'Ameyalli', + 'Abigayl', + 'Aizza', + 'Alaiza', + 'Aslyn', + 'Anjalee', + 'Annaliza', + 'Antara', + 'Areen', + 'Carra', + 'Katieann', + 'Kimla', + 'Xan', + 'Mikiala', + 'Chrissa', + 'Belanna', + 'Ankitha', + 'Celestial', + 'Chiana', + 'Akhila', + 'Alique', + 'Alyssamae', + 'Betheny', + 'Stepheny', + 'Brittanyann', + 'Adonna', + 'Barbarella', + 'Shalamar', + 'Flecia', + 'Dlisa', + 'Anabelia', + 'Velen', + 'Xotchil', + 'Yairis', + 'Lytzy', + 'Faizah', + 'Eilleen', + 'Elona', + 'Esteffany', + 'Jesyka', + 'Jhovana', + 'Jisell', + 'Joclyn', + 'Teel', + 'Sundee', + 'Mechell', + 'Lisia', + 'Nandita', + 'Natalina', + 'Nattalie', + 'Rosaelena', + 'Siclali', + 'Skyllar', + 'Taeya', + 'Sadey', + 'Sadira', + 'Sanae', + 'Serenah', + 'Shamila', + 'Brizza', + 'Chalisa', + 'Shakeela', + 'Gordean', + 'Akane', + 'Akansha', + 'Angeni', + 'Annalina', + 'Anushree', + 'Allexa', + 'Katelynd', + 'Raenette', + 'Airiel', + 'Matina', + 'Teira', + 'Deatra', + 'Darolyn', + 'Hilliary', + 'Roanna', + 'Prissy', + 'Monya', + 'Armelinda', + 'Ginnie', + 'Darenda', + 'Leslea', + 'Marcedes', + 'Jeweliana', + 'Jewelissa', + 'Josselyne', + 'Lavanya', + 'Koryn', + 'Khushpreet', + 'Kierah', + 'Cyana', + 'Deeana', + 'Bibianna', + 'Bryannah', + 'Heidie', + 'Desteni', + 'Elleanna', + 'Sierah', + 'Sumedha', + 'Shantall', + 'Yarissa', + 'Yerania', + 'Tifanny', + 'Mehek', + 'Mirely', + 'Mitra', + 'Mar', + 'Rohini', + 'Prerana', + 'Naizeth', + 'Naydeli', + 'Melveen', + 'Moani', + 'Endora', + 'Jackquline', + 'Stefanny', + 'Tamanna', + 'Sofija', + 'Zitlalic', + 'Ymani', + 'Jumana', + 'Kailene', + 'Josephyne', + 'Leiya', + 'Letzy', + 'Litsy', + 'Lizbett', + 'Lizveth', + 'Jaiya', + 'Dreanna', + 'Celestia', + 'Electra', + 'Sevanna', + 'Sidnie', + 'Semone', + 'Sharra', + 'Sharlette', + 'Selinda', + 'Saumya', + 'Meilan', + 'Melea', + 'Maleeha', + 'Mitali', + 'Rheana', + 'Ruchi', + 'Oasis', + 'Preethi', + 'Aungelique', + 'Kristl', + 'Tashala', + 'Darcell', + 'Rolinda', + 'Toye', + 'Shirlyn', + 'Yvonda', + 'Tymia', + 'Oteka', + 'Ladora', + 'Deashia', + 'Janautica', + 'Sonnet', + 'Sucely', + 'Suriah', + 'Tallula', + 'Sanna', + 'Seniyah', + 'Seri', + 'Yexalen', + 'Yumiko', + 'Zayana', + 'Zohal', + 'Valerye', + 'Yarisbeth', + 'Vivyana', + 'Xela', + 'Brithanny', + 'Jasira', + 'Jenessy', + 'Jezebelle', + 'Leahna', + 'Leilanee', + 'Leily', + 'Kohana', + 'Dorsa', + 'Elanna', + 'Caralyn', + 'Erilyn', + 'Halyn', + 'Helayna', + 'Lionor', + 'Maela', + 'Masha', + 'Myley', + 'Malaak', + 'Malai', + 'Mariapaula', + 'Nathalye', + 'Remie', + 'Parnika', + 'Neveen', + 'Cherith', + 'Orvella', + 'Aurion', + 'Shonterria', + 'Natoria', + 'Shaterria', + 'Clo', + 'Donnia', + 'Cana', + 'Niaya', + 'Brelyn', + 'Aalliyah', + 'Shaaron', + 'Doylene', + 'Lowanda', + 'Henryetta', + 'Obera', + 'Marykathryn', + 'Dema', + 'Arcadia', + 'Lodema', + 'Aloni', + 'Analya', + 'Aashritha', + 'Ayani', + 'Audreena', + 'Audrena', + 'Ariahna', + 'Antonela', + 'Atzi', + 'Amunet', + 'Jaala', + 'Keambria', + 'Kanaya', + 'Emya', + 'Deijah', + 'Dayjah', + 'Tiye', + 'Nyja', + 'Markesia', + 'Valla', + 'Cesaria', + 'Eusevia', + 'Elpidia', + 'Jaquisha', + 'Romanita', + 'Shauntia', + 'Chasmine', + 'Deneisha', + 'Quatesha', + 'Nicosha', + 'Shandricka', + 'Shambria', + 'Shakerra', + 'Santrice', + 'Quinesha', + 'Shantika', + 'Roderica', + 'Whitnie', + 'Piedad', + 'Koleta', + 'Brazil', + 'Aamina', + 'Adaleen', + 'Adyline', + 'Bricola', + 'Analeigha', + 'Anara', + 'Ladawna', + 'Ruperta', + 'Deaundra', + 'Jaleisa', + 'Keria', + 'Sharaine', + 'Shanekqua', + 'Shanekia', + 'Kenyanna', + 'Jacoria', + 'Airianna', + 'Amana', + 'Amariz', + 'Ammi', + 'Miaya', + 'Aaniya', + 'Anaisha', + 'Bellina', + 'Annasofia', + 'Archita', + 'Arianie', + 'Shaquandra', + 'Shakeyra', + 'Tiandra', + 'Soveida', + 'Gonzala', + 'Gaylia', + 'Freddye', + 'Roxi', + 'Neya', + 'Nitika', + 'Noriah', + 'Raha', + 'Briah', + 'Syrah', + 'Talise', + 'Tarynn', + 'Tianah', + 'Solay', + 'Saraiah', + 'Sherlynn', + 'Leylany', + 'Lilu', + 'Maelie', + 'Lexxie', + 'Monzeratt', + 'Nari', + 'Naveyah', + 'Mianna', + 'Maylea', + 'Mery', + 'Marene', + 'Zeba', + 'Xymena', + 'Yaremi', + 'Yari', + 'Yulie', + 'Lile', + 'Dafnee', + 'Indra', + 'Itzelle', + 'Evangaline', + 'Evelett', + 'Evely', + 'Ghazal', + 'Arnisha', + 'Kassia', + 'Kayah', + 'Kalliyan', + 'Diannia', + 'Damyah', + 'Torianna', + 'Talasia', + 'Zakira', + 'Zyah', + 'Masiya', + 'Rhyanna', + 'Kemaya', + 'Jadasia', + 'Kanijah', + 'Henleigh', + 'Ciella', + 'Dayanne', + 'Ivannia', + 'Heydy', + 'Fergie', + 'Fianna', + 'Goretti', + 'Gwynneth', + 'Gyanna', + 'Haidi', + 'Christabella', + 'Angelinah', + 'Anina', + 'Annya', + 'Alejah', + 'Bradie', + 'Breanah', + 'Arihana', + 'Aryona', + 'Ashwika', + 'Aylet', + 'Ayleth', + 'Meleena', + 'Micel', + 'Misel', + 'Naiema', + 'Meiling', + 'Malaia', + 'Rehanna', + 'Raengel', + 'Padma', + 'Majestic', + 'Katelen', + 'Jenaveve', + 'Jennessy', + 'Jewelisa', + 'Joelie', + 'Lyliana', + 'Mahati', + 'Sherral', + 'Kamariah', + 'Larsen', + 'Khaniya', + 'Jakiah', + 'Darionna', + 'Bristal', + 'Ahlana', + 'Aireanna', + 'Alaila', + 'Jarethzy', + 'Orfalinda', + 'Nataliah', + 'Nayra', + 'Nishika', + 'Meeya', + 'Sanaia', + 'Sensi', + 'Percilla', + 'Pranathi', + 'Kathrynn', + 'Katriel', + 'Jordanna', + 'Jessilyn', + 'Jilliana', + 'Madeira', + 'Laia', + 'Leala', + 'Courtlynn', + 'Ahriana', + 'Aliena', + 'Adalay', + 'Nakyia', + 'Niema', + 'Leeasia', + 'Evenny', + 'Dorismar', + 'Dyanara', + 'Elonna', + 'Estreya', + 'Ashmita', + 'Anureet', + 'Angeliah', + 'Annaliz', + 'Dallanara', + 'Danaly', + 'Carely', + 'Sevilla', + 'Aleigh', + 'Allianna', + 'Alamar', + 'Jaiah', + 'Shellsea', + 'Sheylin', + 'Sonoma', + 'Hayla', + 'Yoali', + 'Yzabel', + 'Zeenat', + 'Zienna', + 'Shirlynn', + 'Shilynn', + 'Raphaella', + 'Makyia', + 'Inola', + 'Omaria', + 'Michiah', + 'Anareli', + 'Anacamila', + 'Anahis', + 'Anapaola', + 'Clowie', + 'Brizia', + 'Alexssa', + 'Ailanie', + 'Aileene', + 'Francille', + 'Jatoria', + 'Jaquitta', + 'Sybol', + 'Landra', + 'Danyela', + 'Cubia', + 'Arabela', + 'Adelfina', + 'Quaniya', + 'Paulyne', + 'Vanteen', + 'Treba', + 'Kaylena', + 'Kaelynne', + 'Kalanie', + 'Lezli', + 'Lithzy', + 'Lanessa', + 'Laylene', + 'Leilaney', + 'Emmajean', + 'Francella', + 'Eiliyah', + 'Jadey', + 'Jamilett', + 'Ingris', + 'Tayanna', + 'Skarlette', + 'Sady', + 'Senia', + 'Yakeline', + 'Yenna', + 'Yesmin', + 'Meily', + 'Mikeila', + 'Miu', + 'Rakel', + 'Niveah', + 'Nyemah', + 'Gorgeous', + 'Zaraya', + 'Lavaeh', + 'Meila', + 'Labella', + 'Lilyona', + 'Zykierra', + 'Orfa', + 'Seriyah', + 'Shivali', + 'Sibylla', + 'Sua', + 'Ulani', + 'Vianet', + 'Yanell', + 'Yolette', + 'Yudany', + 'Suheidy', + 'Sukhpreet', + 'Syanna', + 'Tatevik', + 'Tayde', + 'Sameria', + 'Mikiya', + 'Claramae', + 'Audine', + 'Francile', + 'Tynia', + 'Goddess', + 'Samoria', + 'Llana', + 'Oveda', + 'Amelya', + 'Auda', + 'Disaya', + 'Zanyah', + 'Samiyyah', + 'Jaianna', + 'Ruqayyah', + 'Nakira', + 'Shamirah', + 'Ta', + 'Giani', + 'Brya', + 'Cyani', + 'Ashiyah', + 'Kahli', + 'Beauton', + 'Kashay', + 'Sadiyah', + 'Mikaya', + 'Nasira', + 'Nasirah', + 'Ariauna', + 'Yasirah', + 'Skyelynn', + 'Naailah', + 'Nyelle', + 'Adessa', + 'Ayriana', + 'Mirielle', + 'Munirah', + 'Layani', + 'Haniyah', + 'Ovida', + 'Haniyyah', + 'Layonna', + 'Jazmarie', + 'Wicahpi', + 'Cante', + 'Zamyah', + 'Tanyiah', + 'Shalita', + 'Salley', + 'Jnya', + 'Santasia', + 'Shaneque', + 'Quantina', + 'Temeika', + 'Narvis', + 'Pearlee', + 'Nykesha', + 'Orrie', + 'Mozter', + 'Earthalee', + 'Rozena', + 'Anniebell', + 'Hannie', + 'Pretto', + 'Caro', + 'Everlina', + 'Arnetha', + 'Glenora', + 'Asalee', + 'Parniece', + 'Rubena', + 'Wilhemena', + 'Perline', + 'Elloree', + 'Clorine', + 'Richardean', + 'Rovena', + 'Arthuree', + 'Mikea', + 'Charnice', + 'Tylashia', + 'Rebacca', + 'Caretha', + 'Dynasti', + 'Marvie', + 'Hermenia', + 'Tekela', + 'Trenace', + 'Valetta', + 'Topaz', + 'Debara', + 'Jaquasha', + 'Markeria', + 'Alkeria', + 'Salwa', + 'Tatayana', + 'Dianelys', + 'Beyounce', + 'Drena', + 'Julysa', + 'Shuntel', + 'Antasia', + 'Alyze', + 'Marytheresa', + 'Raechelle', + 'Trevia', + 'Tomara', + 'Jermeka', + 'Curtisha', + 'Kebrina', + 'Kayte', + 'Shakeila', + 'Ronnesha', + 'Shavontae', + 'Taquila', + 'Shaquia', + 'Lynnann', + 'Markevia', + 'Terrilynn', + 'Carime', + 'Quaneshia', + 'Shaylen', + 'Corneisha', + 'Rodneshia', + 'Nateria', + 'Marycatherine', + 'Ashlyne', + 'Reyne', + 'Natia', + 'Taquisha', + 'Mikeshia', + 'Khadeja', + 'Lismary', + 'Prisca', + 'Antwonette', + 'Anesia', + 'Clotilda', + 'Willavene', + 'Lovey', + 'Aleda', + 'Karita', + 'Rakiyah', + 'Nyasiah', + 'Timaya', + 'Gabryelle', + 'Caniyah', + 'Ethelreda', + 'Aryelle', + 'Trianna', + 'Yesli', + 'Yareliz', + 'Tanyla', + 'Keyshia', + 'Makinsey', + 'Daily', + 'Caylynn', + 'Kalyse', + 'Sarabelle', + 'Araminta', + 'Magdelene', + 'Kristalyn', + 'Lianni', + 'Layana', + 'Haedyn', + 'Teyona', + 'Taziyah', + 'Ranijah', + 'Darneisha', + 'Jahzaria', + 'Palmyra', + 'Altheda', + 'Armanii', + 'Blodwyn', + 'Colletta', + 'Yelenis', + 'Yazlyn', + 'Leira', + 'Anaysia', + 'Anayiah', + 'Valia', + 'Bambina', + 'Burnetta', + 'Clarabel', + 'Philomenia', + 'Lorma', + 'Janeka', + 'Danaisha', + 'Cayci', + 'Jermia', + 'Idalys', + 'Sarajane', + 'Shakenya', + 'Kashanti', + 'Lanika', + 'Ceira', + 'Deshanti', + 'Adianez', + 'Alannis', + 'Lubov', + 'Aylana', + 'Nephtalie', + 'Harlean', + 'Shelvey', + 'Yalissa', + 'Asianna', + 'Jahnyah', + 'Jahliyah', + 'Ellissa', + 'Gabrianna', + 'Katonya', + 'Elsia', + 'Ketina', + 'Kateena', + 'Claudean', + 'Chenita', + 'Belkys', + 'Kerryn', + 'Teria', + 'Charron', + 'Charnissa', + 'Alura', + 'Bashirah', + 'Gerldine', + 'Katilynn', + 'Trellany', + 'Lacheryl', + 'Twalla', + 'Sharnise', + 'Yoland', + 'Shanai', + 'Ikia', + 'Aquilla', + 'Shalandra', + 'Nekesha', + 'Sonni', + 'Kutana', + 'Sharnay', + 'Timitra', + 'Shareena', + 'Tyeesha', + 'Natara', + 'Amatullah', + 'Nydirah', + 'Shahadah', + 'Inetha', + 'Clatie', + 'Ladye', + 'Makalia', + 'Sabriyah', + 'Graple', + 'Lorell', + 'Vercie', + 'Rayona', + 'Dayshia', + 'Nakirah', + 'Mcneva', + 'Bunia', + 'Brooxie', + 'Delcia', + 'Naje', + 'Eilish', + 'Lashara', + 'Crystall', + 'Shearon', + 'Kafi', + 'Kea', + 'Shantrel', + 'Jeanni', + 'Andreia', + 'Myrlande', + 'Jennifier', + 'Damika', + 'Carloyn', + 'Lashera', + 'Kamika', + 'Chrisann', + 'Lashavia', + 'Ivis', + 'Quinisha', + 'Yanelys', + 'Taralee', + 'Ibis', + 'Jazma', + 'Shakevia', + 'Deneane', + 'Kimala', + 'Casee', + 'Audreana', + 'Shahida', + 'Latangela', + 'Lashira', + 'Lashawndra', + 'Sherrina', + 'Shawntrell', + 'Latronda', + 'Meghaan', + 'Ayasha', + 'Raushanah', + 'Serrita', + 'Tennile', + 'Keyonda', + 'Idalmis', + 'Telicia', + 'Takeia', + 'Aristea', + 'Letesha', + 'Badia', + 'Nykea', + 'Bilan', + 'Ieva', + 'Kimmi', + 'Geniel', + 'Tamberly', + 'Tammee', + 'Sherma', + 'Emira', + 'Agena', + 'Carrin', + 'Ladean', + 'Caera', + 'Shatha', + 'Utahna', + 'Lujean', + 'Joylyn', + 'Kathren', + 'Kristiane', + 'Lenee', + 'Angi', + 'Vichelle', + 'Rochele', + 'Shonnie', + 'Anastasija', + 'Clea', + 'Myrlene', + 'Dniyah', + 'Tashanti', + 'Sireen', + 'Vincie', + 'Wreatha', + 'Josphine', + 'Casimera', + 'Hildagarde', + 'Margeret', + 'Grettell', + 'Greenley', + 'Gloriana', + 'Eyleen', + 'Evaleigh', + 'Davanee', + 'Corley', + 'Liliah', + 'Leanah', + 'Kynzlie', + 'Kynzleigh', + 'Kolette', + 'Lively', + 'Makenlie', + 'Lochlyn', + 'Kinslie', + 'Jleigh', + 'Jeslynn', + 'Jenisis', + 'Jenisha', + 'Kensli', + 'Addalie', + 'Demia', + 'Cele', + 'Aderinsola', + 'Auriella', + 'Blyss', + 'Cashlynn', + 'Callyn', + 'Allyzon', + 'Aleiya', + 'Alazne', + 'Alayzia', + 'Ailah', + 'Annora', + 'Analynn', + 'Leonilda', + 'Minnette', + 'Onolee', + 'Michaelina', + 'Rosemond', + 'Milica', + 'Ednamae', + 'Floribel', + 'Nur', + 'Ndia', + 'Thecla', + 'Immaculate', + 'Mayfred', + 'Selda', + 'Vincenzia', + 'Vitina', + 'Tammatha', + 'Joley', + 'Kelene', + 'Kriste', + 'Liese', + 'Mariaemilia', + 'Lasaundra', + 'Letica', + 'Karene', + 'Devera', + 'Denyce', + 'Dawnn', + 'Maryum', + 'Giovannina', + 'Roze', + 'Reygan', + 'Quinlyn', + 'Stassi', + 'Meelah', + 'Novaleigh', + 'Navey', + 'Mirakle', + 'Naiovy', + 'Munachiso', + 'Montzerrat', + 'Misk', + 'Mireyah', + 'Temiloluwa', + 'Zaiya', + 'Varshini', + 'Tiwatope', + 'Tinlee', + 'Geneve', + 'Kotryna', + 'Janila', + 'Janeah', + 'Mollye', + 'Dody', + 'Doreena', + 'Chelle', + 'Javaeh', + 'Dim', + 'Jamylah', + 'Kamyia', + 'Ramie', + 'Kandie', + 'Kitt', + 'Gaylyn', + 'Marji', + 'Laurena', + 'Lorre', + 'Ronelle', + 'Kresta', + 'Jonylah', + 'Kornelia', + 'Mindie', + 'Kendis', + 'Dorri', + 'Seaneen', + 'Lorilyn', + 'Lolly', + 'Pati', + 'Shalayne', + 'Dorise', + 'Joani', + 'Yailene', + 'Batool', + 'Cyntha', + 'Coni', + 'Kae', + 'Cynia', + 'Rhonna', + 'Lynnetta', + 'Terrisa', + 'Nishi', + 'Delise', + 'Ladena', + 'Bronwen', + 'Tere', + 'Tippi', + 'Peggi', + 'Portland', + 'Sherrin', + 'Tacy', + 'Terie', + 'Dore', + 'Daphane', + 'Juliene', + 'Kamile', + 'Janeil', + 'Megin', + 'Shenandoah', + 'Rashada', + 'Disa', + 'Elita', + 'Kelee', + 'Genee', + 'Taneya', + 'Storie', + 'Sheza', + 'Rielyn', + 'Venicia', + 'Zamyria', + 'Yisell', + 'Appollonia', + 'Meryle', + 'Frann', + 'Lucyann', + 'Clarivel', + 'Marguarite', + 'Nelsa', + 'Reanetta', + 'Roshaunda', + 'Channie', + 'Bathsheba', + 'Jannessa', + 'Jakaylah', + 'Jesalyn', + 'Ellyson', + 'Hally', + 'Haelyn', + 'Gabbie', + 'Emmerie', + 'Makailyn', + 'Maddi', + 'Lirio', + 'Lexee', + 'Matalyn', + 'Kenzee', + 'Kenlei', + 'Kaydi', + 'Kynlei', + 'Krissa', + 'Adalin', + 'Alayiah', + 'Ellice', + 'Caydee', + 'Annalysa', + 'Anisty', + 'Abeni', + 'Aliha', + 'Aerith', + 'Adrie', + 'Peggyann', + 'Pietrina', + 'Amberlie', + 'Dabria', + 'Cylee', + 'Amyriah', + 'Ambry', + 'Berkleigh', + 'Azula', + 'Zaryiah', + 'Zanyia', + 'Gerardine', + 'Joycelynn', + 'Jeslin', + 'Kenzli', + 'Keisi', + 'Kayelynn', + 'Jaselyn', + 'Mckinnley', + 'Maryse', + 'Peightyn', + 'Latausha', + 'Lety', + 'Tekia', + 'Arasely', + 'Arlynne', + 'Noell', + 'Patrcia', + 'Morning', + 'Meika', + 'Tanda', + 'Terasa', + 'Tika', + 'Roshon', + 'Marlaine', + 'Stephaie', + 'Franne', + 'Ewa', + 'Tomeca', + 'Chequita', + 'Dierdra', + 'Doriann', + 'Tammika', + 'Jeananne', + 'Cythia', + 'Laconda', + 'Catiria', + 'Migna', + 'Latiesha', + 'Sharin', + 'Tekesha', + 'Elga', + 'Barbarajean', + 'Ilena', + 'Evett', + 'Timiko', + 'Kachina', + 'Desere', + 'Galadriel', + 'Lynea', + 'Laurajean', + 'Rukiya', + 'Sakara', + 'Snezana', + 'Tashonda', + 'Orquidea', + 'Myshia', + 'Latrease', + 'Monquie', + 'Robina', + 'Vesna', + 'Faline', + 'Glori', + 'Jennel', + 'Keyatta', + 'Dimitria', + 'Uzma', + 'Lalia', + 'Krystiana', + 'Kaedynce', + 'Juany', + 'Kesley', + 'Kennedee', + 'Keeleigh', + 'Paiten', + 'Neelah', + 'Naylee', + 'Sairy', + 'Rocsi', + 'Mckenzey', + 'Modesty', + 'Abbiegail', + 'Jasalyn', + 'Genises', + 'Emmory', + 'Elisea', + 'Dlaney', + 'Haelee', + 'Jadence', + 'Audryana', + 'Carizma', + 'Josanne', + 'Nashira', + 'Meesha', + 'Taneil', + 'Sobeida', + 'Zakyra', + 'Syndee', + 'Zipora', + 'Amita', + 'Bridie', + 'Hilde', + 'Aspasia', + 'Yalexi', + 'Tenleigh', + 'Anjannette', + 'Zniyah', + 'Zayley', + 'Kyerra', + 'Lynnsey', + 'Dashae', + 'Jasha', + 'Anjenette', + 'Lelania', + 'Mija', + 'Lorrene', + 'Shanyn', + 'Shindana', + 'Shamra', + 'Dove', + 'Drina', + 'Caralee', + 'Charmian', + 'Katrine', + 'Lagina', + 'Jahna', + 'Nesita', + 'Teriana', + 'Dajae', + 'Kyiah', + 'Keslyn', + 'Kayelee', + 'Kamberlyn', + 'Raygen', + 'Orchid', + 'Maleigh', + 'Mairim', + 'Amily', + 'Ameli', + 'Alie', + 'Adelai', + 'Eniola', + 'Enaya', + 'Brealynn', + 'Blakleigh', + 'Ayelene', + 'Camrie', + 'Dianely', + 'Delayne', + 'Cortlyn', + 'Jaylei', + 'Jaycelynn', + 'Jaleigha', + 'Iviana', + 'Kaedance', + 'Jewelz', + 'Jillianna', + 'Faithlyn', + 'Isabeau', + 'Irany', + 'Galiana', + 'Makynzee', + 'Maebry', + 'Merit', + 'Mckinzee', + 'Kinzee', + 'Kendrah', + 'Laityn', + 'Amberlin', + 'Ahliyah', + 'Raphaela', + 'Ameri', + 'Brecklynn', + 'Cristabel', + 'Annalucia', + 'Avri', + 'Averly', + 'Shalia', + 'Sheilla', + 'Dejana', + 'Tonnette', + 'Tracia', + 'Trese', + 'Lalanya', + 'Kristiann', + 'Zunaira', + 'Zinachidi', + 'Xayla', + 'Zaybree', + 'Zanae', + 'Xoey', + 'Sirenity', + 'Renesme', + 'Raeley', + 'Preslyn', + 'Nyx', + 'Nyelli', + 'Rozalynn', + 'Safaa', + 'Abaigeal', + 'Perle', + 'Ersilia', + 'Ethlyn', + 'Dashanae', + 'Dajana', + 'Tahja', + 'Shavona', + 'Vernisha', + 'Sunya', + 'Zenorah', + 'Dorota', + 'Ramsha', + 'Nirali', + 'Najia', + 'Maryclaire', + 'Ismay', + 'Alfonsina', + 'Letizia', + 'Lotta', + 'Honore', + 'Jamille', + 'Kashe', + 'Bonnielee', + 'Lorelle', + 'Gloriajean', + 'Trenae', + 'Tonesha', + 'Maxene', + 'Aliz', + 'Annelyse', + 'Avagrace', + 'Adanelly', + 'Dariella', + 'Colbi', + 'Tema', + 'Marlea', + 'Elleen', + 'Veroncia', + 'Shelina', + 'Sundae', + 'Jericca', + 'Liduvina', + 'Jenney', + 'Pascha', + 'Roshell', + 'Marlies', + 'Marny', + 'Judithann', + 'Nancylee', + 'Freyda', + 'Joyceann', + 'Caroleann', + 'Desirie', + 'Christol', + 'Shulamith', + 'Marlise', + 'Rocquel', + 'Tamsen', + 'Sukari', + 'Tinna', + 'Magdelena', + 'Ruba', + 'Patra', + 'Erryn', + 'Buffi', + 'Chantil', + 'Kerensa', + 'Annastacia', + 'Zailee', + 'Lamika', + 'Kashlynn', + 'Jaedynn', + 'Kaly', + 'Paisyn', + 'Seraiah', + 'Mckenzye', + 'Nhyla', + 'Chandrika', + 'Dawana', + 'Elesha', + 'Caryle', + 'Karrin', + 'Valency', + 'Kianga', + 'Shawndee', + 'Tamasha', + 'Rhodora', + 'Shivangi', + 'Vermont', + 'Diasia', + 'Aniyyah', + 'Azhane', + 'Katleyn', + 'Tynetta', + 'Negan', + 'Marilyne', + 'Leronia', + 'Charmie', + 'Lateefa', + 'Hassanah', + 'Louvinia', + 'Shirly', + 'Sanjna', + 'Andelyn', + 'Jaima', + 'Aftyn', + 'Atira', + 'Weslie', + 'Tayzlee', + 'Rossi', + 'Nayvie', + 'Livvy', + 'Brinklee', + 'Drinda', + 'Nazirah', + 'Krithika', + 'Taisley', + 'Starlee', + 'Bijal', + 'Hiral', + 'Gwynn', + 'Orlene', + 'Maurene', + 'Sweta', + 'Naasia', + 'Luvinia', + 'Sayoko', + 'Geannie', + 'Rupal', + 'Zerlina', + 'Nobu', + 'Taeko', + 'Miye', + 'Carnation', + 'Joplin', + 'Yayeko', + 'Sakaye', + 'Ernell', + 'Tazuko', + 'Bayyinah', + 'Konstantina', + 'Danuta', + 'Cariann', + 'Charnette', + 'Michiye', + 'Tejal', + 'Shaheedah', + 'Zakkiyya', + 'Latoyah', + 'Audre', + 'Tayeko', + 'Qadriyyah', + 'Nikema', + 'Wadeeah', + 'Quanika', + 'Fareeda', + 'Ivelis', + 'Karigan', + 'Yayoi', + 'Tauni', + 'Shailee', + 'Ronnah', + 'Roseana', + 'Rosalita', + 'Orlidia', + 'Mckall', + 'Seattle', + 'Lauree', + 'Georgi', + 'Jacolyn', + 'Meichele', + 'Starlet', + 'Shandee', + 'Miquelle', + 'Cathe', + 'Nondas', + 'Roben', + 'Manette', + 'Monzelle', + 'Genieve', + 'Rumaysa', + 'Dariya', + 'Brynnleigh', + 'Vicci', + 'Sharli', + 'Chandi', + 'Guadelupe', + 'Jamilyn', + 'Willadene', + 'Centhia', + 'Cheryal', + 'Normalee', + 'Wilmajean', + 'Roanne', + 'Dyane', + 'Jinx', + 'Jorene', + 'Ceceilia', + 'Arikka', + 'Latanza', + 'Lacinda', + 'Rus', + 'Sangeeta', + 'Demita', + 'Jerene', + 'Marcellina', + 'Zani', + 'Izzabelle', + 'Graycee', + 'Sajada', + 'Quinlee', + 'Brooklee', + 'Shulamis', + 'Bunnie', + 'Michaelyn', + 'Dhruvi', + 'Sreeja', + 'Tzipa', + 'Doreene', + 'Bedelia', + 'Eutimia', + 'Tomacita', + 'Jerra', + 'Rosela', + 'Ignacita', + 'Conferina', + 'Andreita', + 'Lugardita', + 'Estefanita', + 'Suetta', + 'Debbe', + 'Amadita', + 'Mardel', + 'Mliss', + 'Korla', + 'Felipita', + 'Erminda', + 'Chrys', + 'Karthika', + 'Guilianna', + 'Chasya', + 'Bryndee', + 'Taeler', + 'Sinforosa', + 'Brinnley', + 'Aviya', + 'Jayma', + 'Zimal', + 'Vivia', + 'Arielis', + 'Arshiya', + 'Adiba', + 'Afreen', + 'Ajooni', + 'Alianny', + 'Fariza', + 'Breina', + 'Sila', + 'Aaima', + 'Amesha', + 'Antigone', + 'Kayse', + 'Aurelie', + 'Marianny', + 'Naba', + 'Salimata', + 'Retal', + 'Pema', + 'Pesha', + 'Reemas', + 'Emunah', + 'Farzeen', + 'Safina', + 'Sema', + 'Seynabou', + 'Roza', + 'Romaisa', + 'Yehudit', + 'Tzivi', + 'Tzivy', + 'Zahro', + 'Jeylen', + 'Klea', + 'Namirah', + 'Lamiah', + 'Mahjabeen', + 'Daielle', + 'Ogechi', + 'Laresha', + 'Laqueta', + 'Anayla', + 'Bashy', + 'Naeema', + 'Sarrinah', + 'Sevinch', + 'Frimmy', + 'Hibba', + 'Fajr', + 'Rayhona', + 'Rokia', + 'Wafa', + 'Britne', + 'Crystalann', + 'Reah', + 'Maggi', + 'Lenae', + 'Kambra', + 'Tabita', + 'Tamlyn', + 'Thuytien', + 'Titianna', + 'Trenisha', + 'Yuan', + 'Yarithza', + 'Yarixa', + 'Satin', + 'Elizeth', + 'Gabiela', + 'Jackline', + 'Janisa', + 'Graviela', + 'Gudalupe', + 'Hena', + 'Bryanda', + 'Avilene', + 'Ayerim', + 'Breiana', + 'Nicoleanne', + 'Merisa', + 'Relina', + 'Rebecah', + 'Rachyl', + 'Kasaundra', + 'Katryn', + 'Jeaneth', + 'Jenah', + 'Jocely', + 'Jorgina', + 'Lindsee', + 'Lizvette', + 'Oleen', + 'Waveline', + 'Laurabelle', + 'Charma', + 'Gleneva', + 'Yesika', + 'Felina', + 'Nguyet', + 'Krissie', + 'Silvina', + 'Stephanny', + 'Teera', + 'Kristol', + 'Karisha', + 'Lorisa', + 'Iracema', + 'Temesha', + 'Tamber', + 'Shelisa', + 'Roshana', + 'Rheannon', + 'Amala', + 'Anabelen', + 'Daizhane', + 'Darbie', + 'Dezaree', + 'Dezhane', + 'Carrina', + 'Chessa', + 'Christinejoy', + 'Aliea', + 'Adalhi', + 'Alexandrina', + 'Abrina', + 'Madaleine', + 'Maressa', + 'Marki', + 'Koryna', + 'Lilibet', + 'Mystic', + 'Neyra', + 'Ivonna', + 'Jenalyn', + 'Truc', + 'Berneta', + 'Quinci', + 'Rachelanne', + 'Raylina', + 'Nykole', + 'Stephaney', + 'Seleni', + 'Marvene', + 'Melizza', + 'Aimme', + 'Anaissa', + 'Anhelica', + 'Celyna', + 'Azalie', + 'Bereniz', + 'Meliss', + 'Leanza', + 'Lenina', + 'Karrina', + 'Kalynne', + 'Kanwal', + 'Kazzandra', + 'Mandalyn', + 'Limairy', + 'Lizzete', + 'Lyly', + 'Coua', + 'Icsel', + 'Izamary', + 'Lakindra', + 'Rosezella', + 'Wilhelmine', + 'Clela', + 'Marvelle', + 'Jenafer', + 'Katye', + 'Eliabeth', + 'Angelicamaria', + 'Adrieanna', + 'Caludia', + 'Caycee', + 'Chenay', + 'Cherika', + 'Arpine', + 'Kimberlyanne', + 'Jully', + 'Jyoti', + 'Mariha', + 'Meganelizabeth', + 'Melysa', + 'Lashanay', + 'Jericha', + 'Eliset', + 'Esmirna', + 'Clarie', + 'Conny', + 'Derrisha', + 'Frania', + 'Jeena', + 'Gresia', + 'Hlee', + 'Emanie', + 'Liany', + 'Aisatou', + 'Ashya', + 'Nefertari', + 'Nyanna', + 'Mariem', + 'Michellee', + 'Amenda', + 'Markella', + 'Kiyara', + 'Issamar', + 'Cecilee', + 'Rehana', + 'Nube', + 'Simy', + 'Laneshia', + 'Vasthi', + 'Treanna', + 'Tria', + 'Tuongvi', + 'Brany', + 'Niza', + 'Shandale', + 'Shanley', + 'Shastina', + 'Sheyna', + 'Ronniesha', + 'Rubit', + 'Ruvi', + 'Siobhain', + 'Shauntal', + 'Linzie', + 'Linzi', + 'Fatimatou', + 'Efrat', + 'Jasmely', + 'Kadidia', + 'Kamily', + 'Meirav', + 'Areebah', + 'Fatim', + 'Nuzhat', + 'Saribel', + 'Zorah', + 'Ting', + 'Laporscha', + 'Mieshia', + 'Vanecia', + 'Brittne', + 'Denetria', + 'Deamber', + 'Cymone', + 'Arieal', + 'Araly', + 'Shamieka', + 'Deshay', + 'Britainy', + 'Matraca', + 'Krystyne', + 'Kristela', + 'Kindell', + 'Ceyda', + 'Jahnasia', + 'Halimatou', + 'Graciana', + 'Haja', + 'Safiatou', + 'Su', + 'Zaineb', + 'Yianna', + 'Shilat', + 'Zanai', + 'Zeinabou', + 'Jalysa', + 'Garcia', + 'Jinna', + 'Brytni', + 'Crystalmarie', + 'Kyrstie', + 'Labrea', + 'Laurita', + 'Kathleena', + 'Salimatou', + 'Martisha', + 'Damisha', + 'Londin', + 'Toree', + 'Yadria', + 'Yaminah', + 'Nili', + 'Pella', + 'Menna', + 'Minah', + 'Porshay', + 'Rahwa', + 'Parissa', + 'Nury', + 'Sheeva', + 'Sendi', + 'Aroush', + 'Jerlyn', + 'Momina', + 'Nylia', + 'Mahreen', + 'Mattingly', + 'Emanuella', + 'Ceylin', + 'Biana', + 'Ishrat', + 'Genendy', + 'Hindel', + 'Chavi', + 'Freidy', + 'Rouguiatou', + 'Osnas', + 'Yagmur', + 'Yitel', + 'Hudy', + 'Jamielynn', + 'Valyncia', + 'Cheyla', + 'Assa', + 'Tasmia', + 'Yaslene', + 'Zaima', + 'Jenisse', + 'Juliannah', + 'Reveca', + 'Amra', + 'Anaria', + 'Arlenis', + 'Anastassia', + 'Anique', + 'Arilene', + 'Adileni', + 'Chelcy', + 'Chelesa', + 'Columba', + 'Corri', + 'Briane', + 'Carine', + 'Deziah', + 'Jojo', + 'Jaidalyn', + 'Cecelie', + 'Meagon', + 'Raysha', + 'Mylinh', + 'Madelena', + 'Saniyya', + 'Shama', + 'Shifa', + 'Nyala', + 'Lafaun', + 'Ronnetta', + 'Rondia', + 'Christe', + 'Tynnetta', + 'Ethyle', + 'Bobi', + 'Rayetta', + 'Wilmina', + 'Tangala', + 'Chloris', + 'Marvyl', + 'Larinda', + 'Narcedalia', + 'Tiaa', + 'Terressa', + 'Missi', + 'Ardythe', + 'Briget', + 'Julya', + 'Emilyanne', + 'Ayano', + 'Eliane', + 'Tatem', + 'Roselani', + 'Zareen', + 'Yaxeni', + 'Marleena', + 'Nicolemarie', + 'Patzy', + 'Morgana', + 'Mirca', + 'Mystica', + 'Rosaicela', + 'Rosaysela', + 'Serrena', + 'Shiori', + 'Yannely', + 'Threasa', + 'Zohra', + 'Lanitra', + 'Laquinthia', + 'Deshundra', + 'Mirasol', + 'Lladira', + 'Tejuana', + 'Michaelann', + 'Normajean', + 'Leasha', + 'Kajuana', + 'Xianna', + 'Yaquelyn', + 'Marcea', + 'Mohini', + 'Jaysha', + 'Saysha', + 'Makamae', + 'Lynnett', + 'Mistee', + 'Kaysee', + 'Lizel', + 'Kiora', + 'Kla', + 'Lanay', + 'Kainani', + 'Pomaikai', + 'Piilani', + 'Aulii', + 'Khristi', + 'Delfa', + 'Toka', + 'Satonya', + 'Jammi', + 'Iolani', + 'Hinaea', + 'Ilihia', + 'Kulia', + 'Darcus', + 'Raejean', + 'Brisamar', + 'Francessca', + 'Dhamar', + 'Lehiwa', + 'Ajane', + 'Alexsys', + 'Jema', + 'Imara', + 'Itzanami', + 'Ivori', + 'Tabby', + 'Charnell', + 'Vanessamarie', + 'Vibiana', + 'Kameisha', + 'Edica', + 'Shanetra', + 'Shametria', + 'Quinette', + 'Abreanna', + 'Corazon', + 'Correna', + 'Lilac', + 'Najwa', + 'Moranda', + 'Monik', + 'Deise', + 'Edid', + 'Karinne', + 'Ilsa', + 'Irazema', + 'Pegge', + 'Chenique', + 'Temisha', + 'Cristella', + 'Christle', + 'Falan', + 'Mekesha', + 'Jonquil', + 'Latarya', + 'Maretta', + 'Sonceria', + 'Latamara', + 'Ladina', + 'Rozann', + 'Suz', + 'Aleja', + 'Wray', + 'Indica', + 'Harkiran', + 'Gemini', + 'Erikah', + 'Fey', + 'Gudelia', + 'Komalpreet', + 'Anah', + 'Angelicamarie', + 'Cammi', + 'Dejane', + 'Dejanay', + 'Cilicia', + 'Merla', + 'Janann', + 'Maurita', + 'Aireana', + 'Shuronda', + 'Shunte', + 'Lacrisha', + 'Kwana', + 'Krisi', + 'Kaysi', + 'Latressa', + 'Tyronza', + 'Debralee', + 'Crissie', + 'Crissa', + 'Jameca', + 'Alicha', + 'Ketra', + 'Chrisie', + 'Delecia', + 'Rokisha', + 'Natoshia', + 'Shajuana', + 'Jenipher', + 'Jenefer', + 'Anjanae', + 'Azita', + 'Clairissa', + 'Brezhane', + 'Keera', + 'Siarah', + 'Smita', + 'Savonna', + 'Raquelin', + 'Lorren', + 'Omunique', + 'Molina', + 'Nixaliz', + 'Melitza', + 'Shylo', + 'Teniqua', + 'Charmine', + 'Deonne', + 'Kima', + 'Galit', + 'Ikesha', + 'Jamala', + 'Cherl', + 'Ageliki', + 'Ydania', + 'Kortlyn', + 'Lisvet', + 'Khya', + 'Kearstyn', + 'Seline', + 'Stormey', + 'Rehma', + 'Mckynna', + 'Brynnan', + 'Abiola', + 'Ambriel', + 'Akaysha', + 'Hailea', + 'Fryda', + 'Fedra', + 'Dacie', + 'Deissy', + 'Deyna', + 'Mayling', + 'Tessy', + 'Yaa', + 'Shameca', + 'Shivon', + 'Taesha', + 'Dinamarie', + 'Ifeoma', + 'Ashlye', + 'Patriciajo', + 'Danute', + 'Amalyn', + 'Nakeia', + 'Takima', + 'Shavonn', + 'Katira', + 'Lakema', + 'Jahaida', + 'Marshelle', + 'Angeliki', + 'Carrianne', + 'Carrieanne', + 'Tarika', + 'Sherece', + 'Kalimah', + 'Kinda', + 'Sadiga', + 'Paraskevi', + 'Ayianna', + 'Alezay', + 'Cadynce', + 'Haely', + 'Heavenleigh', + 'Dajanique', + 'Lasharn', + 'Drita', + 'Genene', + 'Gittle', + 'Carriann', + 'Emerita', + 'Jenniferann', + 'Kammie', + 'Bryony', + 'Rupinder', + 'Tenise', + 'Yazmyn', + 'Maricris', + 'Rhianon', + 'Nicolet', + 'Mui', + 'Nacy', + 'Naoko', + 'Gaila', + 'Charene', + 'Bas', + 'Geni', + 'Lorez', + 'Taneeka', + 'Tanikqua', + 'Tulani', + 'Sotiria', + 'Sheeba', + 'Katiuscia', + 'Eleftheria', + 'Ghislaine', + 'Jamiylah', + 'Omotayo', + 'Yuleidy', + 'Tylene', + 'Zanetta', + 'Yizza', + 'Ngan', + 'Natassha', + 'Sophear', + 'Starkisha', + 'Stehanie', + 'Jasie', + 'Aprile', + 'Billiejean', + 'Wilnelia', + 'Yaasmiyn', + 'Ednita', + 'Engracia', + 'Grisell', + 'Christinamarie', + 'Eftihia', + 'Jenniefer', + 'Chantee', + 'Afua', + 'Shamea', + 'Shamina', + 'Vickiana', + 'Sharoya', + 'Shateema', + 'Aubrea', + 'Alexcis', + 'Wallis', + 'Jalyne', + 'Harlea', + 'Carisia', + 'Cheynne', + 'Daylee', + 'Kyera', + 'Latayvia', + 'Raashida', + 'Saajida', + 'Nakema', + 'Annalyssa', + 'Chivonne', + 'Lyndie', + 'Sabrian', + 'Rahcel', + 'Hoai', + 'Krisann', + 'Jilliane', + 'Saide', + 'Matti', + 'Raigen', + 'Tenea', + 'Staphanie', + 'Zitlally', + 'Yudelca', + 'Raysa', + 'Monea', + 'Shanigua', + 'Shirah', + 'Chemise', + 'Jajaira', + 'Tunisha', + 'Yelissa', + 'Yudelka', + 'Taria', + 'Taralynn', + 'Condol', + 'Nikima', + 'Syrianna', + 'Anndrea', + 'Charae', + 'Ebelia', + 'Comfort', + 'Denishia', + 'Lanyia', + 'Lahna', + 'Iraima', + 'Josaline', + 'Onyinyechi', + 'Mykalah', + 'Shamyia', + 'Sarely', + 'Makaylie', + 'Madasyn', + 'Carron', + 'Shawnetta', + 'Dorca', + 'Subrena', + 'Romanda', + 'Sallyanne', + 'Ahniyah', + 'Annalissa', + 'Anikah', + 'Anet', + 'Emelee', + 'Branae', + 'Rosemaria', + 'Kimerly', + 'Lorra', + 'Breda', + 'Graceanne', + 'Kathyann', + 'Letetia', + 'Allaina', + 'Anaceli', + 'Brendalee', + 'Aidaly', + 'Arlana', + 'Trinetta', + 'Tennesha', + 'Talonda', + 'Sherrilynn', + 'Maloree', + 'Laiya', + 'Kynlea', + 'Ludwika', + 'Raeli', + 'Yadirah', + 'Yveth', + 'Sabrie', + 'Dannielynn', + 'Breely', + 'Jozlin', + 'Jewelyssa', + 'Keylie', + 'Jazzalyn', + 'Ijeoma', + 'Jaydie', + 'Irianna', + 'Ronya', + 'Lynee', + 'Myrian', + 'Cristalle', + 'Delinah', + 'Arnetia', + 'Guisela', + 'Orna', + 'Samehesha', + 'Scherrie', + 'Marylynne', + 'Judianne', + 'Tomasina', + 'Sanora', + 'Cheray', + 'Gordana', + 'Torina', + 'Yolandra', + 'Tyese', + 'Sharine', + 'Marea', + 'Areti', + 'Sharmila', + 'Charrise', + 'Cyndia', + 'Cinzia', + 'Gecenia', + 'Tarshia', + 'Luwanda', + 'Negar', + 'Sharah', + 'Sherah', + 'Sokha', + 'Marium', + 'Taslin', + 'Taleyah', + 'Parys', + 'Odeth', + 'Mirabai', + 'Myree', + 'Tyhesha', + 'Soyini', + 'Liria', + 'Jenille', + 'Marivic', + 'Mey', + 'Adrena', + 'Cristyn', + 'Jodette', + 'Ilea', + 'Jennett', + 'Latoi', + 'Charrisse', + 'Correne', + 'Reannon', + 'Shanah', + 'Shavaun', + 'Shelena', + 'Macrina', + 'Lashonna', + 'Tecia', + 'Zobeida', + 'Casilda', + 'Ketsy', + 'Lizza', + 'Lucesita', + 'Anelis', + 'Amori', + 'Atlantis', + 'Aslynn', + 'Kimbery', + 'Yolunda', + 'Pasqua', + 'Magalis', + 'Yanellie', + 'Tryniti', + 'Tniya', + 'Ziza', + 'Nadina', + 'Lloana', + 'Shoshannah', + 'Tamarie', + 'Ronique', + 'Keatyn', + 'Matison', + 'Micalah', + 'Nataya', + 'Mama', + 'Bailea', + 'Sidrah', + 'Jazzman', + 'Deanndra', + 'Shawniece', + 'Polett', + 'Rathana', + 'Timisha', + 'Tristina', + 'Vanezza', + 'Shiri', + 'Stephanieann', + 'Genessy', + 'Hema', + 'Huma', + 'Alessandria', + 'Yarisa', + 'Oyindamola', + 'Tianni', + 'Monasia', + 'Kely', + 'Khady', + 'Pegah', + 'Casarah', + 'Cassara', + 'Chalise', + 'Arti', + 'Natanya', + 'Masuma', + 'Shellyann', + 'Taje', + 'Saher', + 'Kelsye', + 'Odaly', + 'Talicia', + 'Mollee', + 'Tashea', + 'Shima', + 'Janaia', + 'Jenia', + 'Jharline', + 'Chabely', + 'Chalon', + 'Charnesha', + 'Christna', + 'Melika', + 'Melis', + 'Lesleyann', + 'Maleeka', + 'Krystalyn', + 'Krystalynn', + 'Marnisha', + 'Mariele', + 'Michelleann', + 'Melessa', + 'Diasy', + 'Dioselina', + 'Jenita', + 'Jaynae', + 'Jeanae', + 'Hripsime', + 'Janete', + 'Lanique', + 'Ashlon', + 'Aroosa', + 'Enisa', + 'Danaysha', + 'Briani', + 'Arjeta', + 'Sapir', + 'Naysha', + 'Kharisma', + 'Laterra', + 'Yannet', + 'Aruna', + 'Anaja', + 'Fahima', + 'Dasmine', + 'Amberlea', + 'Latiera', + 'Kimanh', + 'Mayuri', + 'Meshelle', + 'Morgane', + 'Nahal', + 'Mariacristina', + 'Marlisha', + 'Elaura', + 'Kacia', + 'Neesha', + 'Tila', + 'Waynisha', + 'Witney', + 'Niloofar', + 'Solina', + 'Soo', + 'Stphanie', + 'Shanesha', + 'Sharrell', + 'Nene', + 'Bleona', + 'Hudes', + 'Isatu', + 'Aylssa', + 'Camerina', + 'Arrielle', + 'Allycia', + 'Anacecilia', + 'Anairis', + 'Courney', + 'Dashanique', + 'Cedrina', + 'Celida', + 'Taaliyah', + 'Clarrissa', + 'Egla', + 'Duyen', + 'Kendle', + 'Janil', + 'Adeola', + 'Jazmene', + 'Leesha', + 'Lyzeth', + 'Madeley', + 'Khrystyna', + 'Charisa', + 'Crystelle', + 'Carinna', + 'Channy', + 'Flory', + 'Glenisha', + 'Sheida', + 'Naara', + 'Nassim', + 'Ngozi', + 'Nidya', + 'Marche', + 'Mariaesther', + 'Shaleena', + 'Kioni', + 'Nayab', + 'Nzinga', + 'Fizza', + 'Diavion', + 'Zanib', + 'Tionni', + 'Temitope', + 'Nasreen', + 'Melaysia', + 'Maame', + 'Sameen', + 'Azka', + 'Basma', + 'Virjean', + 'Jarmila', + 'Louren', + 'Mckenize', + 'Malyn', + 'Mercadies', + 'Vika', + 'Suong', + 'Mariadel', + 'Mariatheresa', + 'Marison', + 'Meleane', + 'Shabana', + 'Salote', + 'Raquell', + 'Rekha', + 'Sibel', + 'Shavaughn', + 'Shaquoia', + 'Shatera', + 'Fatina', + 'Jestina', + 'Latasia', + 'Geraldin', + 'Shirleymae', + 'Lubna', + 'Maxiel', + 'Naquasha', + 'Dalissa', + 'Chaniqua', + 'Chanele', + 'Jahlisa', + 'Faatimah', + 'Abagayle', + 'Adwoa', + 'Angeliqu', + 'Gelisa', + 'Bradi', + 'Shantice', + 'Sharece', + 'Nyiesha', + 'Yanill', + 'Yocasta', + 'Stepheni', + 'Suleika', + 'Takeema', + 'Kerrilyn', + 'Jamiyla', + 'Josephin', + 'Margarit', + 'Ilaisaane', + 'Jamilee', + 'Corvette', + 'Janitza', + 'Lexey', + 'Jazzmyne', + 'Kirstan', + 'Kattia', + 'Yatzary', + 'Pricsilla', + 'Gisette', + 'Panayiota', + 'Pinar', + 'Rasheida', + 'Tiffay', + 'Venisha', + 'Jennier', + 'Margulia', + 'Katima', + 'Anjoli', + 'Evelise', + 'Chetara', + 'Jaquelynn', + 'Pessie', + 'Quintessa', + 'Orit', + 'Nelissa', + 'Shekia', + 'Sherrise', + 'Abbye', + 'Imagine', + 'Britlyn', + 'Baley', + 'Tanequa', + 'Tanique', + 'Nocole', + 'Sokhom', + 'Krystelle', + 'Marqui', + 'Mariaangelica', + 'Raiven', + 'Nini', + 'Lesliee', + 'Crystalee', + 'Amadi', + 'Suzett', + 'Thelda', + 'Wladyslawa', + 'Shaqueen', + 'Shayra', + 'Domingue', + 'Garine', + 'Johnanna', + 'Karia', + 'Jany', + 'Ardele', + 'Bilma', + 'Lindita', + 'Lisbel', + 'Lyasia', + 'Kianie', + 'Saidah', + 'Niasha', + 'Chantele', + 'Brette', + 'Cydnie', + 'Chealsea', + 'Jaritsa', + 'Hanaa', + 'Jordain', + 'Kerria', + 'Shannara', + 'Shaquna', + 'Sultana', + 'Tajana', + 'Taquasha', + 'Queenasia', + 'Wandalee', + 'Mikalyn', + 'Jossette', + 'Jazsmine', + 'Keairra', + 'Arleny', + 'Selest', + 'Sabryn', + 'Jilliann', + 'Janin', + 'Kayliegh', + 'Alyss', + 'Asuka', + 'Chenin', + 'Eiliana', + 'Fahm', + 'Cyndle', + 'Daniesha', + 'Saranda', + 'Shany', + 'Veridiana', + 'Yanai', + 'Melanieann', + 'Mishell', + 'Mariadelosangel', + 'Rupa', + 'Orabelle', + 'Taquasia', + 'Tyquasia', + 'Cecillia', + 'Jeanet', + 'Lucely', + 'Kar', + 'Niaja', + 'Naquana', + 'Joanny', + 'Anjelique', + 'Aquasia', + 'Ardita', + 'Jatasia', + 'Donika', + 'Fantasha', + 'Dominiqua', + 'Elecia', + 'Deyra', + 'Erial', + 'Bayle', + 'Ninoska', + 'Jonee', + 'Jullisa', + 'Lavasia', + 'Laniqua', +]; diff --git a/drizzle-seed/src/datasets/jobsTitles.ts b/drizzle-seed/src/datasets/jobsTitles.ts new file mode 100644 index 000000000..3a38e3244 --- /dev/null +++ b/drizzle-seed/src/datasets/jobsTitles.ts @@ -0,0 +1,152 @@ +/** + * The original source for the job titles data was taken from https://www.kaggle.com/datasets/ravindrasinghrana/job-description-dataset + */ +export default [ + 'Digital marketing specialist', + 'Web developer', + 'Operations manager', + 'Network engineer', + 'Event manager', + 'Software tester', + 'Teacher', + 'Ux/ui designer', + 'Wedding planner', + 'Qa analyst', + 'Litigation attorney', + 'Mechanical engineer', + 'Network administrator', + 'Account manager', + 'Brand manager', + 'Social worker', + 'Social media coordinator', + 'Email marketing specialist', + 'Hr generalist', + 'Legal assistant', + 'Nurse practitioner', + 'Account director', + 'Software engineer', + 'Purchasing agent', + 'Sales consultant', + 'Civil engineer', + 'Network security specialist', + 'Ui developer', + 'Financial planner', + 'Event planner', + 'Psychologist', + 'Electrical designer', + 'Data analyst', + 'Technical writer', + 'Tax consultant', + 'Account executive', + 'Systems administrator', + 'Database administrator', + 'Research analyst', + 'Data entry clerk', + 'Registered nurse', + 'Investment analyst', + 'Speech therapist', + 'Sales manager', + 'Landscape architect', + 'Key account manager', + 'Ux researcher', + 'Investment banker', + 'It support specialist', + 'Art director', + 'Software developer', + 'Project manager', + 'Customer service manager', + 'Procurement manager', + 'Substance abuse counselor', + 'Supply chain analyst', + 'Data engineer', + 'Accountant', + 'Sales representative', + 'Environmental consultant', + 'Electrical engineer', + 'Systems engineer', + 'Art teacher', + 'Human resources manager', + 'Inventory analyst', + 'Legal counsel', + 'Database developer', + 'Procurement specialist', + 'Systems analyst', + 'Copywriter', + 'Content writer', + 'Hr coordinator', + 'Business development manager', + 'Java developer', + 'Supply chain manager', + 'Event coordinator', + 'Family nurse practitioner', + 'Front-end engineer', + 'Customer success manager', + 'Procurement coordinator', + 'Urban planner', + 'Architectural designer', + 'Financial analyst', + 'Environmental engineer', + 'Back-end developer', + 'Structural engineer', + 'Market research analyst', + 'Customer service representative', + 'Customer support specialist', + 'Business analyst', + 'Social media manager', + 'Family lawyer', + 'Chemical analyst', + 'Network technician', + 'Interior designer', + 'Software architect', + 'Nurse manager', + 'Veterinarian', + 'Process engineer', + 'It manager', + 'Quality assurance analyst', + 'Pharmaceutical sales representative', + 'Office manager', + 'Architect', + 'Physician assistant', + 'Marketing director', + 'Front-end developer', + 'Research scientist', + 'Executive assistant', + 'Hr manager', + 'Marketing manager', + 'Public relations specialist', + 'Financial controller', + 'Investment advisor', + 'Aerospace engineer', + 'Marketing analyst', + 'Paralegal', + 'Landscape designer', + 'Web designer', + 'Occupational therapist', + 'Legal advisor', + 'Marketing coordinator', + 'Dental hygienist', + 'Sem specialist', + 'Seo specialist', + 'Pediatrician', + 'Qa engineer', + 'Data scientist', + 'Financial advisor', + 'Personal assistant', + 'Seo analyst', + 'Network analyst', + 'Mechanical designer', + 'Marketing specialist', + 'Graphic designer', + 'Finance manager', + 'Physical therapist', + 'Product designer', + 'Administrative assistant', + 'Brand ambassador', + 'Project coordinator', + 'Product manager', + 'It administrator', + 'Sales associate', + 'Chemical engineer', + 'Legal secretary', + 'Market analyst', +]; diff --git a/drizzle-seed/src/datasets/lastNames.ts b/drizzle-seed/src/datasets/lastNames.ts new file mode 100644 index 000000000..117c5fe28 --- /dev/null +++ b/drizzle-seed/src/datasets/lastNames.ts @@ -0,0 +1,50003 @@ +/** + * The original source for last names data was taken from https://www.kaggle.com/datasets/fivethirtyeight/fivethirtyeight-most-common-name-dataset?resource=download&select=surnames.csv + */ +export default [ + 'Smith', + 'Johnson', + 'Williams', + 'Brown', + 'Jones', + 'Miller', + 'Davis', + 'Garcia', + 'Rodriguez', + 'Wilson', + 'Martinez', + 'Anderson', + 'Taylor', + 'Thomas', + 'Hernandez', + 'Moore', + 'Martin', + 'Jackson', + 'Thompson', + 'White', + 'Lopez', + 'Lee', + 'Gonzalez', + 'Harris', + 'Clark', + 'Lewis', + 'Robinson', + 'Walker', + 'Perez', + 'Hall', + 'Young', + 'Allen', + 'Sanchez', + 'Wright', + 'King', + 'Scott', + 'Green', + 'Baker', + 'Adams', + 'Nelson', + 'Hill', + 'Ramirez', + 'Campbell', + 'Mitchell', + 'Roberts', + 'Carter', + 'Phillips', + 'Evans', + 'Turner', + 'Torres', + 'Parker', + 'Collins', + 'Edwards', + 'Stewart', + 'Flores', + 'Morris', + 'Nguyen', + 'Murphy', + 'Rivera', + 'Cook', + 'Rogers', + 'Morgan', + 'Peterson', + 'Cooper', + 'Reed', + 'Bailey', + 'Bell', + 'Gomez', + 'Kelly', + 'Howard', + 'Ward', + 'Cox', + 'Diaz', + 'Richardson', + 'Wood', + 'Watson', + 'Brooks', + 'Bennett', + 'Gray', + 'James', + 'Reyes', + 'Cruz', + 'Hughes', + 'Price', + 'Myers', + 'Long', + 'Foster', + 'Sanders', + 'Ross', + 'Morales', + 'Powell', + 'Sullivan', + 'Russell', + 'Ortiz', + 'Jenkins', + 'Gutierrez', + 'Perry', + 'Butler', + 'Barnes', + 'Fisher', + 'Henderson', + 'Coleman', + 'Simmons', + 'Patterson', + 'Jordan', + 'Reynolds', + 'Hamilton', + 'Graham', + 'Kim', + 'Gonzales', + 'Alexander', + 'Ramos', + 'Wallace', + 'Griffin', + 'West', + 'Cole', + 'Hayes', + 'Chavez', + 'Gibson', + 'Bryant', + 'Ellis', + 'Stevens', + 'Murray', + 'Ford', + 'Marshall', + 'Owens', + 'Mcdonald', + 'Harrison', + 'Ruiz', + 'Kennedy', + 'Wells', + 'Alvarez', + 'Woods', + 'Mendoza', + 'Castillo', + 'Olson', + 'Webb', + 'Washington', + 'Tucker', + 'Freeman', + 'Burns', + 'Henry', + 'Vasquez', + 'Snyder', + 'Simpson', + 'Crawford', + 'Jimenez', + 'Porter', + 'Mason', + 'Shaw', + 'Gordon', + 'Wagner', + 'Hunter', + 'Romero', + 'Hicks', + 'Dixon', + 'Hunt', + 'Palmer', + 'Robertson', + 'Black', + 'Holmes', + 'Stone', + 'Meyer', + 'Boyd', + 'Mills', + 'Warren', + 'Fox', + 'Rose', + 'Rice', + 'Moreno', + 'Schmidt', + 'Patel', + 'Ferguson', + 'Nichols', + 'Herrera', + 'Medina', + 'Ryan', + 'Fernandez', + 'Weaver', + 'Daniels', + 'Stephens', + 'Gardner', + 'Payne', + 'Kelley', + 'Dunn', + 'Pierce', + 'Arnold', + 'Tran', + 'Spencer', + 'Peters', + 'Hawkins', + 'Grant', + 'Hansen', + 'Castro', + 'Hoffman', + 'Hart', + 'Elliott', + 'Cunningham', + 'Knight', + 'Bradley', + 'Carroll', + 'Hudson', + 'Duncan', + 'Armstrong', + 'Berry', + 'Andrews', + 'Johnston', + 'Ray', + 'Lane', + 'Riley', + 'Carpenter', + 'Perkins', + 'Aguilar', + 'Silva', + 'Richards', + 'Willis', + 'Matthews', + 'Chapman', + 'Lawrence', + 'Garza', + 'Vargas', + 'Watkins', + 'Wheeler', + 'Larson', + 'Carlson', + 'Harper', + 'George', + 'Greene', + 'Burke', + 'Guzman', + 'Morrison', + 'Munoz', + 'Jacobs', + 'Obrien', + 'Lawson', + 'Franklin', + 'Lynch', + 'Bishop', + 'Carr', + 'Salazar', + 'Austin', + 'Mendez', + 'Gilbert', + 'Jensen', + 'Williamson', + 'Montgomery', + 'Harvey', + 'Oliver', + 'Howell', + 'Dean', + 'Hanson', + 'Weber', + 'Garrett', + 'Sims', + 'Burton', + 'Fuller', + 'Soto', + 'Mccoy', + 'Welch', + 'Chen', + 'Schultz', + 'Walters', + 'Reid', + 'Fields', + 'Walsh', + 'Little', + 'Fowler', + 'Bowman', + 'Davidson', + 'May', + 'Day', + 'Schneider', + 'Newman', + 'Brewer', + 'Lucas', + 'Holland', + 'Wong', + 'Banks', + 'Santos', + 'Curtis', + 'Pearson', + 'Delgado', + 'Valdez', + 'Pena', + 'Rios', + 'Douglas', + 'Sandoval', + 'Barrett', + 'Hopkins', + 'Keller', + 'Guerrero', + 'Stanley', + 'Bates', + 'Alvarado', + 'Beck', + 'Ortega', + 'Wade', + 'Estrada', + 'Contreras', + 'Barnett', + 'Caldwell', + 'Santiago', + 'Lambert', + 'Powers', + 'Chambers', + 'Nunez', + 'Craig', + 'Leonard', + 'Lowe', + 'Rhodes', + 'Byrd', + 'Gregory', + 'Shelton', + 'Frazier', + 'Becker', + 'Maldonado', + 'Fleming', + 'Vega', + 'Sutton', + 'Cohen', + 'Jennings', + 'Parks', + 'Mcdaniel', + 'Watts', + 'Barker', + 'Norris', + 'Vaughn', + 'Vazquez', + 'Holt', + 'Schwartz', + 'Steele', + 'Benson', + 'Neal', + 'Dominguez', + 'Horton', + 'Terry', + 'Wolfe', + 'Hale', + 'Lyons', + 'Graves', + 'Haynes', + 'Miles', + 'Park', + 'Warner', + 'Padilla', + 'Bush', + 'Thornton', + 'Mccarthy', + 'Mann', + 'Zimmerman', + 'Erickson', + 'Fletcher', + 'Mckinney', + 'Page', + 'Dawson', + 'Joseph', + 'Marquez', + 'Reeves', + 'Klein', + 'Espinoza', + 'Baldwin', + 'Moran', + 'Love', + 'Robbins', + 'Higgins', + 'Ball', + 'Cortez', + 'Le', + 'Griffith', + 'Bowen', + 'Sharp', + 'Cummings', + 'Ramsey', + 'Hardy', + 'Swanson', + 'Barber', + 'Acosta', + 'Luna', + 'Chandler', + 'Blair', + 'Daniel', + 'Cross', + 'Simon', + 'Dennis', + 'Oconnor', + 'Quinn', + 'Gross', + 'Navarro', + 'Moss', + 'Fitzgerald', + 'Doyle', + 'Mclaughlin', + 'Rojas', + 'Rodgers', + 'Stevenson', + 'Singh', + 'Yang', + 'Figueroa', + 'Harmon', + 'Newton', + 'Paul', + 'Manning', + 'Garner', + 'Mcgee', + 'Reese', + 'Francis', + 'Burgess', + 'Adkins', + 'Goodman', + 'Curry', + 'Brady', + 'Christensen', + 'Potter', + 'Walton', + 'Goodwin', + 'Mullins', + 'Molina', + 'Webster', + 'Fischer', + 'Campos', + 'Avila', + 'Sherman', + 'Todd', + 'Chang', + 'Blake', + 'Malone', + 'Wolf', + 'Hodges', + 'Juarez', + 'Gill', + 'Farmer', + 'Hines', + 'Gallagher', + 'Duran', + 'Hubbard', + 'Cannon', + 'Miranda', + 'Wang', + 'Saunders', + 'Tate', + 'Mack', + 'Hammond', + 'Carrillo', + 'Townsend', + 'Wise', + 'Ingram', + 'Barton', + 'Mejia', + 'Ayala', + 'Schroeder', + 'Hampton', + 'Rowe', + 'Parsons', + 'Frank', + 'Waters', + 'Strickland', + 'Osborne', + 'Maxwell', + 'Chan', + 'Deleon', + 'Norman', + 'Harrington', + 'Casey', + 'Patton', + 'Logan', + 'Bowers', + 'Mueller', + 'Glover', + 'Floyd', + 'Hartman', + 'Buchanan', + 'Cobb', + 'French', + 'Kramer', + 'Mccormick', + 'Clarke', + 'Tyler', + 'Gibbs', + 'Moody', + 'Conner', + 'Sparks', + 'Mcguire', + 'Leon', + 'Bauer', + 'Norton', + 'Pope', + 'Flynn', + 'Hogan', + 'Robles', + 'Salinas', + 'Yates', + 'Lindsey', + 'Lloyd', + 'Marsh', + 'Mcbride', + 'Owen', + 'Solis', + 'Pham', + 'Lang', + 'Pratt', + 'Lara', + 'Brock', + 'Ballard', + 'Trujillo', + 'Shaffer', + 'Drake', + 'Roman', + 'Aguirre', + 'Morton', + 'Stokes', + 'Lamb', + 'Pacheco', + 'Patrick', + 'Cochran', + 'Shepherd', + 'Cain', + 'Burnett', + 'Hess', + 'Li', + 'Cervantes', + 'Olsen', + 'Briggs', + 'Ochoa', + 'Cabrera', + 'Velasquez', + 'Montoya', + 'Roth', + 'Meyers', + 'Cardenas', + 'Fuentes', + 'Weiss', + 'Hoover', + 'Wilkins', + 'Nicholson', + 'Underwood', + 'Short', + 'Carson', + 'Morrow', + 'Colon', + 'Holloway', + 'Summers', + 'Bryan', + 'Petersen', + 'Mckenzie', + 'Serrano', + 'Wilcox', + 'Carey', + 'Clayton', + 'Poole', + 'Calderon', + 'Gallegos', + 'Greer', + 'Rivas', + 'Guerra', + 'Decker', + 'Collier', + 'Wall', + 'Whitaker', + 'Bass', + 'Flowers', + 'Davenport', + 'Conley', + 'Houston', + 'Huff', + 'Copeland', + 'Hood', + 'Monroe', + 'Massey', + 'Roberson', + 'Combs', + 'Franco', + 'Larsen', + 'Pittman', + 'Randall', + 'Skinner', + 'Wilkinson', + 'Kirby', + 'Cameron', + 'Bridges', + 'Anthony', + 'Richard', + 'Kirk', + 'Bruce', + 'Singleton', + 'Mathis', + 'Bradford', + 'Boone', + 'Abbott', + 'Charles', + 'Allison', + 'Sweeney', + 'Atkinson', + 'Horn', + 'Jefferson', + 'Rosales', + 'York', + 'Christian', + 'Phelps', + 'Farrell', + 'Castaneda', + 'Nash', + 'Dickerson', + 'Bond', + 'Wyatt', + 'Foley', + 'Chase', + 'Gates', + 'Vincent', + 'Mathews', + 'Hodge', + 'Garrison', + 'Trevino', + 'Villarreal', + 'Heath', + 'Dalton', + 'Valencia', + 'Callahan', + 'Hensley', + 'Atkins', + 'Huffman', + 'Roy', + 'Boyer', + 'Shields', + 'Lin', + 'Hancock', + 'Grimes', + 'Glenn', + 'Cline', + 'Delacruz', + 'Camacho', + 'Dillon', + 'Parrish', + 'Oneill', + 'Melton', + 'Booth', + 'Kane', + 'Berg', + 'Harrell', + 'Pitts', + 'Savage', + 'Wiggins', + 'Brennan', + 'Salas', + 'Marks', + 'Russo', + 'Sawyer', + 'Baxter', + 'Golden', + 'Hutchinson', + 'Liu', + 'Walter', + 'Mcdowell', + 'Wiley', + 'Rich', + 'Humphrey', + 'Johns', + 'Koch', + 'Suarez', + 'Hobbs', + 'Beard', + 'Gilmore', + 'Ibarra', + 'Keith', + 'Macias', + 'Khan', + 'Andrade', + 'Ware', + 'Stephenson', + 'Henson', + 'Wilkerson', + 'Dyer', + 'Mcclure', + 'Blackwell', + 'Mercado', + 'Tanner', + 'Eaton', + 'Clay', + 'Barron', + 'Beasley', + 'Oneal', + 'Preston', + 'Small', + 'Wu', + 'Zamora', + 'Macdonald', + 'Vance', + 'Snow', + 'Mcclain', + 'Stafford', + 'Orozco', + 'Barry', + 'English', + 'Shannon', + 'Kline', + 'Jacobson', + 'Woodard', + 'Huang', + 'Kemp', + 'Mosley', + 'Prince', + 'Merritt', + 'Hurst', + 'Villanueva', + 'Roach', + 'Nolan', + 'Lam', + 'Yoder', + 'Mccullough', + 'Lester', + 'Santana', + 'Valenzuela', + 'Winters', + 'Barrera', + 'Leach', + 'Orr', + 'Berger', + 'Mckee', + 'Strong', + 'Conway', + 'Stein', + 'Whitehead', + 'Bullock', + 'Escobar', + 'Knox', + 'Meadows', + 'Solomon', + 'Velez', + 'Odonnell', + 'Kerr', + 'Stout', + 'Blankenship', + 'Browning', + 'Kent', + 'Lozano', + 'Bartlett', + 'Pruitt', + 'Buck', + 'Barr', + 'Gaines', + 'Durham', + 'Gentry', + 'Mcintyre', + 'Sloan', + 'Rocha', + 'Melendez', + 'Herman', + 'Sexton', + 'Moon', + 'Hendricks', + 'Rangel', + 'Stark', + 'Lowery', + 'Hardin', + 'Hull', + 'Sellers', + 'Ellison', + 'Calhoun', + 'Gillespie', + 'Mora', + 'Knapp', + 'Mccall', + 'Morse', + 'Dorsey', + 'Weeks', + 'Nielsen', + 'Livingston', + 'Leblanc', + 'Mclean', + 'Bradshaw', + 'Glass', + 'Middleton', + 'Buckley', + 'Schaefer', + 'Frost', + 'Howe', + 'House', + 'Mcintosh', + 'Ho', + 'Pennington', + 'Reilly', + 'Hebert', + 'Mcfarland', + 'Hickman', + 'Noble', + 'Spears', + 'Conrad', + 'Arias', + 'Galvan', + 'Velazquez', + 'Huynh', + 'Frederick', + 'Randolph', + 'Cantu', + 'Fitzpatrick', + 'Mahoney', + 'Peck', + 'Villa', + 'Michael', + 'Donovan', + 'Mcconnell', + 'Walls', + 'Boyle', + 'Mayer', + 'Zuniga', + 'Giles', + 'Pineda', + 'Pace', + 'Hurley', + 'Mays', + 'Mcmillan', + 'Crosby', + 'Ayers', + 'Case', + 'Bentley', + 'Shepard', + 'Everett', + 'Pugh', + 'David', + 'Mcmahon', + 'Dunlap', + 'Bender', + 'Hahn', + 'Harding', + 'Acevedo', + 'Raymond', + 'Blackburn', + 'Duffy', + 'Landry', + 'Dougherty', + 'Bautista', + 'Shah', + 'Potts', + 'Arroyo', + 'Valentine', + 'Meza', + 'Gould', + 'Vaughan', + 'Fry', + 'Rush', + 'Avery', + 'Herring', + 'Dodson', + 'Clements', + 'Sampson', + 'Tapia', + 'Bean', + 'Lynn', + 'Crane', + 'Farley', + 'Cisneros', + 'Benton', + 'Ashley', + 'Mckay', + 'Finley', + 'Best', + 'Blevins', + 'Friedman', + 'Moses', + 'Sosa', + 'Blanchard', + 'Huber', + 'Frye', + 'Krueger', + 'Bernard', + 'Rosario', + 'Rubio', + 'Mullen', + 'Benjamin', + 'Haley', + 'Chung', + 'Moyer', + 'Choi', + 'Horne', + 'Yu', + 'Woodward', + 'Ali', + 'Nixon', + 'Hayden', + 'Rivers', + 'Estes', + 'Mccarty', + 'Richmond', + 'Stuart', + 'Maynard', + 'Brandt', + 'Oconnell', + 'Hanna', + 'Sanford', + 'Sheppard', + 'Church', + 'Burch', + 'Levy', + 'Rasmussen', + 'Coffey', + 'Ponce', + 'Faulkner', + 'Donaldson', + 'Schmitt', + 'Novak', + 'Costa', + 'Montes', + 'Booker', + 'Cordova', + 'Waller', + 'Arellano', + 'Maddox', + 'Mata', + 'Bonilla', + 'Stanton', + 'Compton', + 'Kaufman', + 'Dudley', + 'Mcpherson', + 'Beltran', + 'Dickson', + 'Mccann', + 'Villegas', + 'Proctor', + 'Hester', + 'Cantrell', + 'Daugherty', + 'Cherry', + 'Bray', + 'Davila', + 'Rowland', + 'Levine', + 'Madden', + 'Spence', + 'Good', + 'Irwin', + 'Werner', + 'Krause', + 'Petty', + 'Whitney', + 'Baird', + 'Hooper', + 'Pollard', + 'Zavala', + 'Jarvis', + 'Holden', + 'Haas', + 'Hendrix', + 'Mcgrath', + 'Bird', + 'Lucero', + 'Terrell', + 'Riggs', + 'Joyce', + 'Mercer', + 'Rollins', + 'Galloway', + 'Duke', + 'Odom', + 'Andersen', + 'Downs', + 'Hatfield', + 'Benitez', + 'Archer', + 'Huerta', + 'Travis', + 'Mcneil', + 'Hinton', + 'Zhang', + 'Hays', + 'Mayo', + 'Fritz', + 'Branch', + 'Mooney', + 'Ewing', + 'Ritter', + 'Esparza', + 'Frey', + 'Braun', + 'Gay', + 'Riddle', + 'Haney', + 'Kaiser', + 'Holder', + 'Chaney', + 'Mcknight', + 'Gamble', + 'Vang', + 'Cooley', + 'Carney', + 'Cowan', + 'Forbes', + 'Ferrell', + 'Davies', + 'Barajas', + 'Shea', + 'Osborn', + 'Bright', + 'Cuevas', + 'Bolton', + 'Murillo', + 'Lutz', + 'Duarte', + 'Kidd', + 'Key', + 'Cooke', + 'Goff', + 'Dejesus', + 'Marin', + 'Dotson', + 'Bonner', + 'Cotton', + 'Merrill', + 'Lindsay', + 'Lancaster', + 'Mcgowan', + 'Felix', + 'Salgado', + 'Slater', + 'Carver', + 'Guthrie', + 'Holman', + 'Fulton', + 'Snider', + 'Sears', + 'Witt', + 'Newell', + 'Byers', + 'Lehman', + 'Gorman', + 'Costello', + 'Donahue', + 'Delaney', + 'Albert', + 'Workman', + 'Rosas', + 'Springer', + 'Kinney', + 'Justice', + 'Odell', + 'Lake', + 'Donnelly', + 'Law', + 'Dailey', + 'Guevara', + 'Shoemaker', + 'Barlow', + 'Marino', + 'Winter', + 'Craft', + 'Katz', + 'Pickett', + 'Espinosa', + 'Maloney', + 'Daly', + 'Goldstein', + 'Crowley', + 'Vogel', + 'Kuhn', + 'Pearce', + 'Hartley', + 'Cleveland', + 'Palacios', + 'Mcfadden', + 'Britt', + 'Wooten', + 'Cortes', + 'Dillard', + 'Childers', + 'Alford', + 'Dodd', + 'Emerson', + 'Wilder', + 'Lange', + 'Goldberg', + 'Quintero', + 'Beach', + 'Enriquez', + 'Quintana', + 'Helms', + 'Mackey', + 'Finch', + 'Cramer', + 'Minor', + 'Flanagan', + 'Franks', + 'Corona', + 'Kendall', + 'Mccabe', + 'Hendrickson', + 'Moser', + 'Mcdermott', + 'Camp', + 'Mcleod', + 'Bernal', + 'Kaplan', + 'Medrano', + 'Lugo', + 'Tracy', + 'Bacon', + 'Crowe', + 'Richter', + 'Welsh', + 'Holley', + 'Ratliff', + 'Mayfield', + 'Talley', + 'Haines', + 'Dale', + 'Gibbons', + 'Hickey', + 'Byrne', + 'Kirkland', + 'Farris', + 'Correa', + 'Tillman', + 'Sweet', + 'Kessler', + 'England', + 'Hewitt', + 'Blanco', + 'Connolly', + 'Pate', + 'Elder', + 'Bruno', + 'Holcomb', + 'Hyde', + 'Mcallister', + 'Cash', + 'Christopher', + 'Whitfield', + 'Meeks', + 'Hatcher', + 'Fink', + 'Sutherland', + 'Noel', + 'Ritchie', + 'Rosa', + 'Leal', + 'Joyner', + 'Starr', + 'Morin', + 'Delarosa', + 'Connor', + 'Hilton', + 'Alston', + 'Gilliam', + 'Wynn', + 'Wills', + 'Jaramillo', + 'Oneil', + 'Nieves', + 'Britton', + 'Rankin', + 'Belcher', + 'Guy', + 'Chamberlain', + 'Tyson', + 'Puckett', + 'Downing', + 'Sharpe', + 'Boggs', + 'Truong', + 'Pierson', + 'Godfrey', + 'Mobley', + 'John', + 'Kern', + 'Dye', + 'Hollis', + 'Bravo', + 'Magana', + 'Rutherford', + 'Ng', + 'Tuttle', + 'Lim', + 'Romano', + 'Trejo', + 'Arthur', + 'Knowles', + 'Lyon', + 'Shirley', + 'Quinones', + 'Childs', + 'Dolan', + 'Head', + 'Reyna', + 'Saenz', + 'Hastings', + 'Kenney', + 'Cano', + 'Foreman', + 'Denton', + 'Villalobos', + 'Pryor', + 'Sargent', + 'Doherty', + 'Hopper', + 'Phan', + 'Womack', + 'Lockhart', + 'Ventura', + 'Dwyer', + 'Muller', + 'Galindo', + 'Grace', + 'Sorensen', + 'Courtney', + 'Parra', + 'Rodrigues', + 'Nicholas', + 'Ahmed', + 'Mcginnis', + 'Langley', + 'Madison', + 'Locke', + 'Jamison', + 'Nava', + 'Gustafson', + 'Sykes', + 'Dempsey', + 'Hamm', + 'Rodriquez', + 'Mcgill', + 'Xiong', + 'Esquivel', + 'Simms', + 'Kendrick', + 'Boyce', + 'Vigil', + 'Downey', + 'Mckenna', + 'Sierra', + 'Webber', + 'Kirkpatrick', + 'Dickinson', + 'Couch', + 'Burks', + 'Sheehan', + 'Slaughter', + 'Pike', + 'Whitley', + 'Magee', + 'Cheng', + 'Sinclair', + 'Cassidy', + 'Rutledge', + 'Burris', + 'Bowling', + 'Crabtree', + 'Mcnamara', + 'Avalos', + 'Vu', + 'Herron', + 'Broussard', + 'Abraham', + 'Garland', + 'Corbett', + 'Corbin', + 'Stinson', + 'Chin', + 'Burt', + 'Hutchins', + 'Woodruff', + 'Lau', + 'Brandon', + 'Singer', + 'Hatch', + 'Rossi', + 'Shafer', + 'Ott', + 'Goss', + 'Gregg', + 'Dewitt', + 'Tang', + 'Polk', + 'Worley', + 'Covington', + 'Saldana', + 'Heller', + 'Emery', + 'Swartz', + 'Cho', + 'Mccray', + 'Elmore', + 'Rosenberg', + 'Simons', + 'Clemons', + 'Beatty', + 'Harden', + 'Herbert', + 'Bland', + 'Rucker', + 'Manley', + 'Ziegler', + 'Grady', + 'Lott', + 'Rouse', + 'Gleason', + 'Mcclellan', + 'Abrams', + 'Vo', + 'Albright', + 'Meier', + 'Dunbar', + 'Ackerman', + 'Padgett', + 'Mayes', + 'Tipton', + 'Coffman', + 'Peralta', + 'Shapiro', + 'Roe', + 'Weston', + 'Plummer', + 'Helton', + 'Stern', + 'Fraser', + 'Stover', + 'Fish', + 'Schumacher', + 'Baca', + 'Curran', + 'Vinson', + 'Vera', + 'Clifton', + 'Ervin', + 'Eldridge', + 'Lowry', + 'Childress', + 'Becerra', + 'Gore', + 'Seymour', + 'Chu', + 'Field', + 'Akers', + 'Carrasco', + 'Bingham', + 'Sterling', + 'Greenwood', + 'Leslie', + 'Groves', + 'Manuel', + 'Swain', + 'Edmonds', + 'Muniz', + 'Thomson', + 'Crouch', + 'Walden', + 'Smart', + 'Tomlinson', + 'Alfaro', + 'Quick', + 'Goldman', + 'Mcelroy', + 'Yarbrough', + 'Funk', + 'Hong', + 'Portillo', + 'Lund', + 'Ngo', + 'Elkins', + 'Stroud', + 'Meredith', + 'Battle', + 'Mccauley', + 'Zapata', + 'Bloom', + 'Gee', + 'Givens', + 'Cardona', + 'Schafer', + 'Robison', + 'Gunter', + 'Griggs', + 'Tovar', + 'Teague', + 'Swift', + 'Bowden', + 'Schulz', + 'Blanton', + 'Buckner', + 'Whalen', + 'Pritchard', + 'Pierre', + 'Kang', + 'Metcalf', + 'Butts', + 'Kurtz', + 'Sanderson', + 'Tompkins', + 'Inman', + 'Crowder', + 'Dickey', + 'Hutchison', + 'Conklin', + 'Hoskins', + 'Holbrook', + 'Horner', + 'Neely', + 'Tatum', + 'Hollingsworth', + 'Draper', + 'Clement', + 'Lord', + 'Reece', + 'Feldman', + 'Kay', + 'Hagen', + 'Crews', + 'Bowles', + 'Post', + 'Jewell', + 'Daley', + 'Cordero', + 'Mckinley', + 'Velasco', + 'Masters', + 'Driscoll', + 'Burrell', + 'Valle', + 'Crow', + 'Devine', + 'Larkin', + 'Chappell', + 'Pollock', + 'Ly', + 'Kimball', + 'Schmitz', + 'Lu', + 'Rubin', + 'Self', + 'Barrios', + 'Pereira', + 'Phipps', + 'Mcmanus', + 'Nance', + 'Steiner', + 'Poe', + 'Crockett', + 'Jeffries', + 'Amos', + 'Nix', + 'Newsome', + 'Dooley', + 'Payton', + 'Rosen', + 'Swenson', + 'Connelly', + 'Tolbert', + 'Segura', + 'Esposito', + 'Coker', + 'Biggs', + 'Hinkle', + 'Thurman', + 'Drew', + 'Ivey', + 'Bullard', + 'Baez', + 'Neff', + 'Maher', + 'Stratton', + 'Egan', + 'Dubois', + 'Gallardo', + 'Blue', + 'Rainey', + 'Yeager', + 'Saucedo', + 'Ferreira', + 'Sprague', + 'Lacy', + 'Hurtado', + 'Heard', + 'Connell', + 'Stahl', + 'Aldridge', + 'Amaya', + 'Forrest', + 'Erwin', + 'Gunn', + 'Swan', + 'Butcher', + 'Rosado', + 'Godwin', + 'Hand', + 'Gabriel', + 'Otto', + 'Whaley', + 'Ludwig', + 'Clifford', + 'Grove', + 'Beaver', + 'Silver', + 'Dang', + 'Hammer', + 'Dick', + 'Boswell', + 'Mead', + 'Colvin', + 'Oleary', + 'Milligan', + 'Goins', + 'Ames', + 'Dodge', + 'Kaur', + 'Escobedo', + 'Arredondo', + 'Geiger', + 'Winkler', + 'Dunham', + 'Temple', + 'Babcock', + 'Billings', + 'Grimm', + 'Lilly', + 'Wesley', + 'Mcghee', + 'Siegel', + 'Painter', + 'Bower', + 'Purcell', + 'Block', + 'Aguilera', + 'Norwood', + 'Sheridan', + 'Cartwright', + 'Coates', + 'Davison', + 'Regan', + 'Ramey', + 'Koenig', + 'Kraft', + 'Bunch', + 'Engel', + 'Tan', + 'Winn', + 'Steward', + 'Link', + 'Vickers', + 'Bragg', + 'Piper', + 'Huggins', + 'Michel', + 'Healy', + 'Jacob', + 'Mcdonough', + 'Wolff', + 'Colbert', + 'Zepeda', + 'Hoang', + 'Dugan', + 'Meade', + 'Kilgore', + 'Guillen', + 'Do', + 'Hinojosa', + 'Goode', + 'Arrington', + 'Gary', + 'Snell', + 'Willard', + 'Renteria', + 'Chacon', + 'Gallo', + 'Hankins', + 'Montano', + 'Browne', + 'Peacock', + 'Ohara', + 'Cornell', + 'Sherwood', + 'Castellanos', + 'Thorpe', + 'Stiles', + 'Sadler', + 'Latham', + 'Redmond', + 'Greenberg', + 'Cote', + 'Waddell', + 'Dukes', + 'Diamond', + 'Bui', + 'Madrid', + 'Alonso', + 'Sheets', + 'Irvin', + 'Hurt', + 'Ferris', + 'Sewell', + 'Carlton', + 'Aragon', + 'Blackmon', + 'Hadley', + 'Hoyt', + 'Mcgraw', + 'Pagan', + 'Land', + 'Tidwell', + 'Lovell', + 'Miner', + 'Doss', + 'Dahl', + 'Delatorre', + 'Stanford', + 'Kauffman', + 'Vela', + 'Gagnon', + 'Winston', + 'Gomes', + 'Thacker', + 'Coronado', + 'Ash', + 'Jarrett', + 'Hager', + 'Samuels', + 'Metzger', + 'Raines', + 'Spivey', + 'Maurer', + 'Han', + 'Voss', + 'Henley', + 'Caballero', + 'Caruso', + 'Coulter', + 'North', + 'Finn', + 'Cahill', + 'Lanier', + 'Souza', + 'Mcwilliams', + 'Deal', + 'Urban', + 'Schaffer', + 'Houser', + 'Cummins', + 'Romo', + 'Crocker', + 'Bassett', + 'Kruse', + 'Bolden', + 'Ybarra', + 'Metz', + 'Root', + 'Mcmullen', + 'Hagan', + 'Crump', + 'Guidry', + 'Brantley', + 'Kearney', + 'Beal', + 'Toth', + 'Jorgensen', + 'Timmons', + 'Milton', + 'Tripp', + 'Hurd', + 'Sapp', + 'Whitman', + 'Messer', + 'Burgos', + 'Major', + 'Westbrook', + 'Castle', + 'Serna', + 'Carlisle', + 'Varela', + 'Cullen', + 'Wilhelm', + 'Bergeron', + 'Burger', + 'Posey', + 'Barnhart', + 'Hackett', + 'Madrigal', + 'Eubanks', + 'Sizemore', + 'Hilliard', + 'Hargrove', + 'Boucher', + 'Thomason', + 'Melvin', + 'Roper', + 'Barnard', + 'Fonseca', + 'Pedersen', + 'Quiroz', + 'Washburn', + 'Holliday', + 'Yee', + 'Rudolph', + 'Bermudez', + 'Coyle', + 'Gil', + 'Pina', + 'Goodrich', + 'Elias', + 'Lockwood', + 'Cabral', + 'Carranza', + 'Duvall', + 'Cornelius', + 'Mccollum', + 'Street', + 'Mcneal', + 'Connors', + 'Angel', + 'Paulson', + 'Hinson', + 'Keenan', + 'Sheldon', + 'Farr', + 'Eddy', + 'Samuel', + 'Ring', + 'Ledbetter', + 'Betts', + 'Fontenot', + 'Gifford', + 'Hannah', + 'Hanley', + 'Person', + 'Fountain', + 'Levin', + 'Stubbs', + 'Hightower', + 'Murdock', + 'Koehler', + 'Ma', + 'Engle', + 'Smiley', + 'Carmichael', + 'Sheffield', + 'Langston', + 'Mccracken', + 'Yost', + 'Trotter', + 'Story', + 'Starks', + 'Lujan', + 'Blount', + 'Cody', + 'Rushing', + 'Benoit', + 'Herndon', + 'Jacobsen', + 'Nieto', + 'Wiseman', + 'Layton', + 'Epps', + 'Shipley', + 'Leyva', + 'Reeder', + 'Brand', + 'Roland', + 'Fitch', + 'Rico', + 'Napier', + 'Cronin', + 'Mcqueen', + 'Paredes', + 'Trent', + 'Christiansen', + 'Spangler', + 'Pettit', + 'Langford', + 'Benavides', + 'Penn', + 'Paige', + 'Weir', + 'Dietz', + 'Prater', + 'Brewster', + 'Louis', + 'Diehl', + 'Pack', + 'Spaulding', + 'Ernst', + 'Aviles', + 'Nowak', + 'Olvera', + 'Rock', + 'Mansfield', + 'Aquino', + 'Ogden', + 'Stacy', + 'Rizzo', + 'Sylvester', + 'Gillis', + 'Sands', + 'Machado', + 'Lovett', + 'Duong', + 'Hyatt', + 'Landis', + 'Platt', + 'Bustamante', + 'Hedrick', + 'Pritchett', + 'Gaston', + 'Dobson', + 'Caudill', + 'Tackett', + 'Bateman', + 'Landers', + 'Carmona', + 'Gipson', + 'Uribe', + 'Mcneill', + 'Ledford', + 'Mims', + 'Abel', + 'Gold', + 'Smallwood', + 'Thorne', + 'Mchugh', + 'Dickens', + 'Leung', + 'Tobin', + 'Kowalski', + 'Medeiros', + 'Cope', + 'Quezada', + 'Kraus', + 'Overton', + 'Montalvo', + 'Staley', + 'Woody', + 'Hathaway', + 'Osorio', + 'Laird', + 'Dobbs', + 'Capps', + 'Putnam', + 'Lay', + 'Francisco', + 'Bernstein', + 'Adair', + 'Hutton', + 'Burkett', + 'Rhoades', + 'Yanez', + 'Richey', + 'Bledsoe', + 'Mccain', + 'Beyer', + 'Cates', + 'Roche', + 'Spicer', + 'Queen', + 'Doty', + 'Darling', + 'Darby', + 'Sumner', + 'Kincaid', + 'Hay', + 'Grossman', + 'Lacey', + 'Wilkes', + 'Humphries', + 'Paz', + 'Darnell', + 'Keys', + 'Kyle', + 'Lackey', + 'Vogt', + 'Locklear', + 'Kiser', + 'Presley', + 'Bryson', + 'Bergman', + 'Peoples', + 'Fair', + 'Mcclendon', + 'Corley', + 'Prado', + 'Christie', + 'Delong', + 'Skaggs', + 'Dill', + 'Shearer', + 'Judd', + 'Stapleton', + 'Flaherty', + 'Casillas', + 'Pinto', + 'Youngblood', + 'Haywood', + 'Toney', + 'Ricks', + 'Granados', + 'Crum', + 'Triplett', + 'Soriano', + 'Waite', + 'Hoff', + 'Anaya', + 'Crenshaw', + 'Jung', + 'Canales', + 'Cagle', + 'Denny', + 'Marcus', + 'Berman', + 'Munson', + 'Ocampo', + 'Bauman', + 'Corcoran', + 'Keen', + 'Zimmer', + 'Friend', + 'Ornelas', + 'Varner', + 'Pelletier', + 'Vernon', + 'Blum', + 'Albrecht', + 'Culver', + 'Schuster', + 'Cuellar', + 'Mccord', + 'Shultz', + 'Mcrae', + 'Moreland', + 'Calvert', + 'William', + 'Whittington', + 'Eckert', + 'Keene', + 'Mohr', + 'Hanks', + 'Kimble', + 'Cavanaugh', + 'Crowell', + 'Russ', + 'Feliciano', + 'Crain', + 'Busch', + 'Mccormack', + 'Drummond', + 'Omalley', + 'Aldrich', + 'Luke', + 'Greco', + 'Mott', + 'Oakes', + 'Mallory', + 'Mclain', + 'Burrows', + 'Otero', + 'Allred', + 'Eason', + 'Finney', + 'Weller', + 'Waldron', + 'Champion', + 'Jeffers', + 'Coon', + 'Rosenthal', + 'Huddleston', + 'Solano', + 'Hirsch', + 'Akins', + 'Olivares', + 'Song', + 'Sneed', + 'Benedict', + 'Bain', + 'Okeefe', + 'Hidalgo', + 'Matos', + 'Stallings', + 'Paris', + 'Gamez', + 'Kenny', + 'Quigley', + 'Marrero', + 'Fagan', + 'Dutton', + 'Pappas', + 'Atwood', + 'Mcgovern', + 'Bagley', + 'Read', + 'Lunsford', + 'Moseley', + 'Oakley', + 'Ashby', + 'Granger', + 'Shaver', + 'Hope', + 'Coe', + 'Burroughs', + 'Helm', + 'Neumann', + 'Ambrose', + 'Michaels', + 'Prescott', + 'Light', + 'Dumas', + 'Flood', + 'Stringer', + 'Currie', + 'Comer', + 'Fong', + 'Whitlock', + 'Lemus', + 'Hawley', + 'Ulrich', + 'Staples', + 'Boykin', + 'Knutson', + 'Grover', + 'Hobson', + 'Cormier', + 'Doran', + 'Thayer', + 'Woodson', + 'Whitt', + 'Hooker', + 'Kohler', + 'Vandyke', + 'Addison', + 'Schrader', + 'Haskins', + 'Whittaker', + 'Madsen', + 'Gauthier', + 'Burnette', + 'Keating', + 'Purvis', + 'Aleman', + 'Huston', + 'Pimentel', + 'Hamlin', + 'Gerber', + 'Hooks', + 'Schwab', + 'Honeycutt', + 'Schulte', + 'Alonzo', + 'Isaac', + 'Conroy', + 'Adler', + 'Eastman', + 'Cottrell', + 'Orourke', + 'Hawk', + 'Goldsmith', + 'Rader', + 'Crandall', + 'Reynoso', + 'Shook', + 'Abernathy', + 'Baer', + 'Olivas', + 'Grayson', + 'Bartley', + 'Henning', + 'Parr', + 'Duff', + 'Brunson', + 'Baum', + 'Ennis', + 'Laughlin', + 'Foote', + 'Valadez', + 'Adamson', + 'Begay', + 'Stovall', + 'Lincoln', + 'Cheung', + 'Malloy', + 'Rider', + 'Giordano', + 'Jansen', + 'Lopes', + 'Arnett', + 'Pendleton', + 'Gage', + 'Barragan', + 'Keyes', + 'Navarrete', + 'Amador', + 'Hoffmann', + 'Schilling', + 'Hawthorne', + 'Perdue', + 'Schreiber', + 'Arevalo', + 'Naylor', + 'Deluca', + 'Marcum', + 'Altman', + 'Mark', + 'Chadwick', + 'Doan', + 'Easley', + 'Ladd', + 'Woodall', + 'Betancourt', + 'Shin', + 'Maguire', + 'Bellamy', + 'Quintanilla', + 'Ham', + 'Sorenson', + 'Mattson', + 'Brenner', + 'Means', + 'Faust', + 'Calloway', + 'Ojeda', + 'Mcnally', + 'Dietrich', + 'Ransom', + 'Hare', + 'Felton', + 'Whiting', + 'Burkhart', + 'Clinton', + 'Schwarz', + 'Cleary', + 'Wetzel', + 'Reagan', + 'Stjohn', + 'Chow', + 'Hauser', + 'Dupree', + 'Brannon', + 'Lyles', + 'Prather', + 'Willoughby', + 'Sepulveda', + 'Nugent', + 'Pickens', + 'Mosher', + 'Joiner', + 'Stoner', + 'Dowling', + 'Trimble', + 'Valdes', + 'Cheek', + 'Scruggs', + 'Coy', + 'Tilley', + 'Barney', + 'Saylor', + 'Nagy', + 'Horvath', + 'Lai', + 'Corey', + 'Ruth', + 'Sauer', + 'Baron', + 'Thao', + 'Rowell', + 'Grubbs', + 'Schaeffer', + 'Hillman', + 'Sams', + 'Hogue', + 'Hutson', + 'Busby', + 'Nickerson', + 'Bruner', + 'Parham', + 'Rendon', + 'Anders', + 'Lombardo', + 'Iverson', + 'Kinsey', + 'Earl', + 'Borden', + 'Titus', + 'Jean', + 'Tellez', + 'Beavers', + 'Cornett', + 'Sotelo', + 'Kellogg', + 'Silverman', + 'Burnham', + 'Mcnair', + 'Jernigan', + 'Escamilla', + 'Barrow', + 'Coats', + 'London', + 'Redding', + 'Ruffin', + 'Yi', + 'Boudreaux', + 'Goodson', + 'Dowell', + 'Fenton', + 'Mock', + 'Dozier', + 'Bynum', + 'Gale', + 'Jolly', + 'Beckman', + 'Goddard', + 'Craven', + 'Whitmore', + 'Leary', + 'Mccloud', + 'Gamboa', + 'Kerns', + 'Brunner', + 'Negron', + 'Hough', + 'Cutler', + 'Ledesma', + 'Pyle', + 'Monahan', + 'Tabor', + 'Burk', + 'Leone', + 'Stauffer', + 'Hayward', + 'Driver', + 'Ruff', + 'Talbot', + 'Seals', + 'Boston', + 'Carbajal', + 'Fay', + 'Purdy', + 'Mcgregor', + 'Sun', + 'Orellana', + 'Gentile', + 'Mahan', + 'Brower', + 'Patino', + 'Thurston', + 'Shipman', + 'Torrez', + 'Aaron', + 'Weiner', + 'Call', + 'Wilburn', + 'Oliva', + 'Hairston', + 'Coley', + 'Hummel', + 'Arreola', + 'Watt', + 'Sharma', + 'Lentz', + 'Arce', + 'Power', + 'Longoria', + 'Wagoner', + 'Burr', + 'Hsu', + 'Tinsley', + 'Beebe', + 'Wray', + 'Nunn', + 'Prieto', + 'German', + 'Rowley', + 'Grubb', + 'Brito', + 'Royal', + 'Valentin', + 'Bartholomew', + 'Schuler', + 'Aranda', + 'Flint', + 'Hearn', + 'Venegas', + 'Unger', + 'Mattingly', + 'Boles', + 'Casas', + 'Barger', + 'Julian', + 'Dow', + 'Dobbins', + 'Vann', + 'Chester', + 'Strange', + 'Lemon', + 'Kahn', + 'Mckinnon', + 'Gannon', + 'Waggoner', + 'Conn', + 'Meek', + 'Cavazos', + 'Skelton', + 'Lo', + 'Kumar', + 'Toledo', + 'Lorenz', + 'Vallejo', + 'Starkey', + 'Kitchen', + 'Reaves', + 'Demarco', + 'Farrar', + 'Stearns', + 'Michaud', + 'Higginbotham', + 'Fernandes', + 'Isaacs', + 'Marion', + 'Guillory', + 'Priest', + 'Meehan', + 'Oliveira', + 'Palma', + 'Oswald', + 'Loomis', + 'Galvez', + 'Lind', + 'Mena', + 'Stclair', + 'Hinds', + 'Reardon', + 'Alley', + 'Barth', + 'Crook', + 'Bliss', + 'Nagel', + 'Banuelos', + 'Parish', + 'Harman', + 'Douglass', + 'Kearns', + 'Newcomb', + 'Mulligan', + 'Coughlin', + 'Way', + 'Fournier', + 'Lawler', + 'Kaminski', + 'Barbour', + 'Sousa', + 'Stump', + 'Alaniz', + 'Ireland', + 'Rudd', + 'Carnes', + 'Lundy', + 'Godinez', + 'Pulido', + 'Dennison', + 'Burdick', + 'Baumann', + 'Dove', + 'Stoddard', + 'Liang', + 'Dent', + 'Roark', + 'Mcmahan', + 'Bowser', + 'Parnell', + 'Mayberry', + 'Wakefield', + 'Arndt', + 'Ogle', + 'Worthington', + 'Durbin', + 'Escalante', + 'Pederson', + 'Weldon', + 'Vick', + 'Knott', + 'Ryder', + 'Zarate', + 'Irving', + 'Clemens', + 'Shelley', + 'Salter', + 'Jack', + 'Cloud', + 'Dasilva', + 'Muhammad', + 'Squires', + 'Rapp', + 'Dawkins', + 'Polanco', + 'Chatman', + 'Maier', + 'Yazzie', + 'Gruber', + 'Staton', + 'Blackman', + 'Mcdonnell', + 'Dykes', + 'Laws', + 'Whitten', + 'Pfeiffer', + 'Vidal', + 'Early', + 'Kelsey', + 'Baughman', + 'Dias', + 'Starnes', + 'Crespo', + 'Lombardi', + 'Kilpatrick', + 'Deaton', + 'Satterfield', + 'Wiles', + 'Weinstein', + 'Rowan', + 'Delossantos', + 'Hamby', + 'Estep', + 'Daigle', + 'Elam', + 'Creech', + 'Heck', + 'Chavis', + 'Echols', + 'Foss', + 'Trahan', + 'Strauss', + 'Vanhorn', + 'Winslow', + 'Rea', + 'Heaton', + 'Fairchild', + 'Minton', + 'Hitchcock', + 'Linton', + 'Handy', + 'Crouse', + 'Coles', + 'Upton', + 'Foy', + 'Herrington', + 'Mcclelland', + 'Hwang', + 'Rector', + 'Luther', + 'Kruger', + 'Salcedo', + 'Chance', + 'Gunderson', + 'Tharp', + 'Griffiths', + 'Graf', + 'Branham', + 'Humphreys', + 'Renner', + 'Lima', + 'Rooney', + 'Moya', + 'Almeida', + 'Gavin', + 'Coburn', + 'Ouellette', + 'Goetz', + 'Seay', + 'Parrott', + 'Harms', + 'Robb', + 'Storey', + 'Barbosa', + 'Barraza', + 'Loyd', + 'Merchant', + 'Donohue', + 'Carrier', + 'Diggs', + 'Chastain', + 'Sherrill', + 'Whipple', + 'Braswell', + 'Weathers', + 'Linder', + 'Chapa', + 'Bock', + 'Oh', + 'Lovelace', + 'Saavedra', + 'Ferrara', + 'Callaway', + 'Salmon', + 'Templeton', + 'Christy', + 'Harp', + 'Dowd', + 'Forrester', + 'Lawton', + 'Epstein', + 'Gant', + 'Tierney', + 'Seaman', + 'Corral', + 'Dowdy', + 'Zaragoza', + 'Morrissey', + 'Eller', + 'Chau', + 'Breen', + 'High', + 'Newberry', + 'Beam', + 'Yancey', + 'Jarrell', + 'Cerda', + 'Ellsworth', + 'Lofton', + 'Thibodeaux', + 'Pool', + 'Rinehart', + 'Arteaga', + 'Marlow', + 'Hacker', + 'Will', + 'Mackenzie', + 'Hook', + 'Gilliland', + 'Emmons', + 'Pickering', + 'Medley', + 'Willey', + 'Andrew', + 'Shell', + 'Randle', + 'Brinkley', + 'Pruett', + 'Tobias', + 'Edmondson', + 'Grier', + 'Saldivar', + 'Batista', + 'Askew', + 'Moeller', + 'Chavarria', + 'Augustine', + 'Troyer', + 'Layne', + 'Mcnulty', + 'Shank', + 'Desai', + 'Herrmann', + 'Hemphill', + 'Bearden', + 'Spear', + 'Keener', + 'Holguin', + 'Culp', + 'Braden', + 'Briscoe', + 'Bales', + 'Garvin', + 'Stockton', + 'Abreu', + 'Suggs', + 'Mccartney', + 'Ferrer', + 'Rhoads', + 'Ha', + 'Nevarez', + 'Singletary', + 'Chong', + 'Alcala', + 'Cheney', + 'Westfall', + 'Damico', + 'Snodgrass', + 'Devries', + 'Looney', + 'Hein', + 'Lyle', + 'Lockett', + 'Jacques', + 'Barkley', + 'Wahl', + 'Aponte', + 'Myrick', + 'Bolin', + 'Holm', + 'Slack', + 'Scherer', + 'Martino', + 'Bachman', + 'Ely', + 'Nesbitt', + 'Marroquin', + 'Bouchard', + 'Mast', + 'Jameson', + 'Hills', + 'Mireles', + 'Bueno', + 'Pease', + 'Vitale', + 'Alarcon', + 'Linares', + 'Schell', + 'Lipscomb', + 'Arriaga', + 'Bourgeois', + 'Markham', + 'Bonds', + 'Wisniewski', + 'Ivy', + 'Oldham', + 'Wendt', + 'Fallon', + 'Joy', + 'Stamper', + 'Babb', + 'Steinberg', + 'Asher', + 'Fuchs', + 'Blank', + 'Willett', + 'Heredia', + 'Croft', + 'Lytle', + 'Lance', + 'Lassiter', + 'Barrientos', + 'Condon', + 'Barfield', + 'Darden', + 'Araujo', + 'Noonan', + 'Guinn', + 'Burleson', + 'Belanger', + 'Main', + 'Traylor', + 'Messina', + 'Zeigler', + 'Danielson', + 'Millard', + 'Kenyon', + 'Radford', + 'Graff', + 'Beaty', + 'Baggett', + 'Salisbury', + 'Crisp', + 'Trout', + 'Lorenzo', + 'Parson', + 'Gann', + 'Garber', + 'Adcock', + 'Covarrubias', + 'Scales', + 'Acuna', + 'Thrasher', + 'Card', + 'Van', + 'Mabry', + 'Mohamed', + 'Montanez', + 'Stock', + 'Redd', + 'Willingham', + 'Redman', + 'Zambrano', + 'Gaffney', + 'Herr', + 'Schubert', + 'Devlin', + 'Pringle', + 'Houck', + 'Casper', + 'Rees', + 'Wing', + 'Ebert', + 'Jeter', + 'Cornejo', + 'Gillette', + 'Shockley', + 'Amato', + 'Girard', + 'Leggett', + 'Cheatham', + 'Bustos', + 'Epperson', + 'Dubose', + 'Seitz', + 'Frias', + 'East', + 'Schofield', + 'Steen', + 'Orlando', + 'Myles', + 'Caron', + 'Grey', + 'Denney', + 'Ontiveros', + 'Burden', + 'Jaeger', + 'Reich', + 'Witherspoon', + 'Najera', + 'Frantz', + 'Hammonds', + 'Xu', + 'Leavitt', + 'Gilchrist', + 'Adam', + 'Barone', + 'Forman', + 'Ceja', + 'Ragsdale', + 'Sisk', + 'Tubbs', + 'Elizondo', + 'Pressley', + 'Bollinger', + 'Linn', + 'Huntley', + 'Dewey', + 'Geary', + 'Carlos', + 'Ragland', + 'Mixon', + 'Mcarthur', + 'Baugh', + 'Tam', + 'Nobles', + 'Clevenger', + 'Lusk', + 'Foust', + 'Cooney', + 'Tamayo', + 'Robert', + 'Longo', + 'Overstreet', + 'Oglesby', + 'Mace', + 'Churchill', + 'Matson', + 'Hamrick', + 'Rockwell', + 'Trammell', + 'Wheatley', + 'Carrington', + 'Ferraro', + 'Ralston', + 'Clancy', + 'Mondragon', + 'Carl', + 'Hu', + 'Hopson', + 'Breaux', + 'Mccurdy', + 'Mares', + 'Mai', + 'Chisholm', + 'Matlock', + 'Aiken', + 'Cary', + 'Lemons', + 'Anguiano', + 'Herrick', + 'Crawley', + 'Montero', + 'Hassan', + 'Archuleta', + 'Farias', + 'Cotter', + 'Parris', + 'Felder', + 'Luu', + 'Pence', + 'Gilman', + 'Killian', + 'Naranjo', + 'Duggan', + 'Scarborough', + 'Swann', + 'Easter', + 'Ricketts', + 'France', + 'Bello', + 'Nadeau', + 'Still', + 'Rincon', + 'Cornwell', + 'Slade', + 'Fierro', + 'Mize', + 'Christianson', + 'Greenfield', + 'Mcafee', + 'Landrum', + 'Adame', + 'Dinh', + 'Lankford', + 'Lewandowski', + 'Rust', + 'Bundy', + 'Waterman', + 'Milner', + 'Mccrary', + 'Hite', + 'Curley', + 'Donald', + 'Duckworth', + 'Cecil', + 'Carrera', + 'Speer', + 'Birch', + 'Denson', + 'Beckwith', + 'Stack', + 'Durant', + 'Lantz', + 'Dorman', + 'Christman', + 'Spann', + 'Masterson', + 'Hostetler', + 'Kolb', + 'Brink', + 'Scanlon', + 'Nye', + 'Wylie', + 'Beverly', + 'Woo', + 'Spurlock', + 'Sommer', + 'Shelby', + 'Reinhardt', + 'Robledo', + 'Bertrand', + 'Ashton', + 'Cyr', + 'Edgar', + 'Doe', + 'Harkins', + 'Brubaker', + 'Stoll', + 'Dangelo', + 'Zhou', + 'Moulton', + 'Hannon', + 'Falk', + 'Rains', + 'Broughton', + 'Applegate', + 'Hudgins', + 'Slone', + 'Yoon', + 'Farnsworth', + 'Perales', + 'Reedy', + 'Milam', + 'Franz', + 'Ponder', + 'Ricci', + 'Fontaine', + 'Irizarry', + 'Puente', + 'New', + 'Selby', + 'Cazares', + 'Doughty', + 'Moffett', + 'Balderas', + 'Fine', + 'Smalley', + 'Carlin', + 'Trinh', + 'Dyson', + 'Galvin', + 'Valdivia', + 'Benner', + 'Low', + 'Turpin', + 'Lyman', + 'Billingsley', + 'Mcadams', + 'Cardwell', + 'Fraley', + 'Patten', + 'Holton', + 'Shanks', + 'Mcalister', + 'Canfield', + 'Sample', + 'Harley', + 'Cason', + 'Tomlin', + 'Ahmad', + 'Coyne', + 'Forte', + 'Riggins', + 'Littlejohn', + 'Forsythe', + 'Brinson', + 'Halverson', + 'Bach', + 'Stuckey', + 'Falcon', + 'Wenzel', + 'Talbert', + 'Champagne', + 'Mchenry', + 'Vest', + 'Shackelford', + 'Ordonez', + 'Collazo', + 'Boland', + 'Sisson', + 'Bigelow', + 'Wharton', + 'Hyman', + 'Brumfield', + 'Oates', + 'Mesa', + 'Morrell', + 'Beckett', + 'Reis', + 'Alves', + 'Chiu', + 'Larue', + 'Streeter', + 'Grogan', + 'Blakely', + 'Brothers', + 'Hatton', + 'Kimbrough', + 'Lauer', + 'Wallis', + 'Jett', + 'Pepper', + 'Hildebrand', + 'Rawls', + 'Mello', + 'Neville', + 'Bull', + 'Steffen', + 'Braxton', + 'Cowart', + 'Simpkins', + 'Mcneely', + 'Blalock', + 'Spain', + 'Shipp', + 'Lindquist', + 'Oreilly', + 'Butterfield', + 'Perrin', + 'Qualls', + 'Edge', + 'Havens', + 'Luong', + 'Switzer', + 'Troutman', + 'Fortner', + 'Tolliver', + 'Monk', + 'Poindexter', + 'Rupp', + 'Ferry', + 'Negrete', + 'Muse', + 'Gresham', + 'Beauchamp', + 'Schmid', + 'Barclay', + 'Chun', + 'Brice', + 'Faulk', + 'Watters', + 'Briones', + 'Guajardo', + 'Harwood', + 'Grissom', + 'Harlow', + 'Whelan', + 'Burdette', + 'Palumbo', + 'Paulsen', + 'Corrigan', + 'Garvey', + 'Levesque', + 'Dockery', + 'Delgadillo', + 'Gooch', + 'Cao', + 'Mullin', + 'Ridley', + 'Stanfield', + 'Noriega', + 'Dial', + 'Ceballos', + 'Nunes', + 'Newby', + 'Baumgartner', + 'Hussain', + 'Wyman', + 'Causey', + 'Gossett', + 'Ness', + 'Waugh', + 'Choate', + 'Carman', + 'Daily', + 'Kong', + 'Devore', + 'Irby', + 'Breeden', + 'Whatley', + 'Ellington', + 'Lamar', + 'Fultz', + 'Bair', + 'Zielinski', + 'Colby', + 'Houghton', + 'Grigsby', + 'Fortune', + 'Paxton', + 'Mcmillian', + 'Hammons', + 'Bronson', + 'Keck', + 'Wellman', + 'Ayres', + 'Whiteside', + 'Menard', + 'Roush', + 'Warden', + 'Espino', + 'Strand', + 'Haggerty', + 'Banda', + 'Krebs', + 'Fabian', + 'Bowie', + 'Branson', + 'Lenz', + 'Benavidez', + 'Keeler', + 'Newsom', + 'Ezell', + 'Jeffrey', + 'Pulliam', + 'Clary', + 'Byrnes', + 'Kopp', + 'Beers', + 'Smalls', + 'Sommers', + 'Gardiner', + 'Fennell', + 'Mancini', + 'Osullivan', + 'Sebastian', + 'Bruns', + 'Giron', + 'Parent', + 'Boyles', + 'Keefe', + 'Muir', + 'Wheat', + 'Vergara', + 'Shuler', + 'Pemberton', + 'South', + 'Brownlee', + 'Brockman', + 'Royer', + 'Fanning', + 'Herzog', + 'Morley', + 'Bethea', + 'Tong', + 'Needham', + 'Roque', + 'Mojica', + 'Bunn', + 'Francois', + 'Noe', + 'Kuntz', + 'Snowden', + 'Withers', + 'Harlan', + 'Seibert', + 'Limon', + 'Kiefer', + 'Bone', + 'Sell', + 'Allan', + 'Skidmore', + 'Wren', + 'Dunaway', + 'Finnegan', + 'Moe', + 'Wolford', + 'Seeley', + 'Kroll', + 'Lively', + 'Janssen', + 'Montague', + 'Rahman', + 'Boehm', + 'Nettles', + 'Dees', + 'Krieger', + 'Peek', + 'Hershberger', + 'Sage', + 'Custer', + 'Zheng', + 'Otoole', + 'Jaimes', + 'Elrod', + 'Somers', + 'Lira', + 'Nagle', + 'Grooms', + 'Soria', + 'Drury', + 'Keane', + 'Bostic', + 'Hartmann', + 'Pauley', + 'Murrell', + 'Manzo', + 'Morey', + 'Agee', + 'Hamel', + 'Tavares', + 'Dunning', + 'Mccloskey', + 'Plunkett', + 'Maples', + 'March', + 'Armenta', + 'Waldrop', + 'Espinal', + 'Fajardo', + 'Christenson', + 'Robins', + 'Bagwell', + 'Massie', + 'Leahy', + 'Urbina', + 'Medlin', + 'Zhu', + 'Pantoja', + 'Barbee', + 'Clawson', + 'Reiter', + 'Ko', + 'Crider', + 'Maxey', + 'Worrell', + 'Brackett', + 'Mclemore', + 'Younger', + 'Her', + 'Hardesty', + 'Danner', + 'Ragan', + 'Almanza', + 'Nielson', + 'Graber', + 'Mcintire', + 'Tirado', + 'Griswold', + 'Seifert', + 'Valles', + 'Laney', + 'Gupta', + 'Malik', + 'Libby', + 'Marvin', + 'Koontz', + 'Marr', + 'Kozlowski', + 'Lemke', + 'Brant', + 'Phelan', + 'Kemper', + 'Gooden', + 'Beaulieu', + 'Cardoza', + 'Healey', + 'Zhao', + 'Hardwick', + 'Kitchens', + 'Box', + 'Stepp', + 'Comstock', + 'Poston', + 'Sager', + 'Conti', + 'Borges', + 'Farrow', + 'Acker', + 'Glaser', + 'Antonio', + 'Lennon', + 'Gaither', + 'Freitas', + 'Alicea', + 'Mcmillen', + 'Chapin', + 'Ratcliff', + 'Lerma', + 'Severson', + 'Wilde', + 'Mortensen', + 'Winchester', + 'Flannery', + 'Villasenor', + 'Centeno', + 'Burkholder', + 'Horan', + 'Meador', + 'Ingle', + 'Roldan', + 'Estrella', + 'Pullen', + 'Newkirk', + 'Gaytan', + 'Lindberg', + 'Windham', + 'Gatlin', + 'Stoltzfus', + 'Behrens', + 'Cintron', + 'Broderick', + 'Solorzano', + 'Jaime', + 'Venable', + 'Culbertson', + 'Garay', + 'Caputo', + 'Grantham', + 'Hanlon', + 'Parry', + 'Crist', + 'Cosby', + 'Shore', + 'Everhart', + 'Dorn', + 'Turley', + 'Eng', + 'Valerio', + 'Rand', + 'Hiatt', + 'Mota', + 'Judge', + 'Kinder', + 'Colwell', + 'Ashworth', + 'Tejeda', + 'Sikes', + 'Oshea', + 'Westmoreland', + 'Faber', + 'Culpepper', + 'Logsdon', + 'Fugate', + 'Apodaca', + 'Lindley', + 'Samson', + 'Liles', + 'Mcclanahan', + 'Burge', + 'Vail', + 'Etheridge', + 'Boudreau', + 'Andres', + 'Noll', + 'Higgs', + 'Snead', + 'Layman', + 'Turk', + 'Nolen', + 'Wayne', + 'Betz', + 'Victor', + 'Lafferty', + 'Carbone', + 'Skipper', + 'Zeller', + 'Kasper', + 'Desantis', + 'Fogle', + 'Gandy', + 'Mendenhall', + 'Seward', + 'Schweitzer', + 'Gulley', + 'Stine', + 'Sowers', + 'Duenas', + 'Monson', + 'Brinkman', + 'Hubert', + 'Motley', + 'Pfeifer', + 'Weinberg', + 'Eggleston', + 'Isom', + 'Quinlan', + 'Gilley', + 'Jasso', + 'Loya', + 'Mull', + 'Reichert', + 'Wirth', + 'Reddy', + 'Hodgson', + 'Stowe', + 'Mccallum', + 'Ahrens', + 'Huey', + 'Mattox', + 'Dupont', + 'Aguayo', + 'Pak', + 'Tice', + 'Alba', + 'Colburn', + 'Currier', + 'Gaskins', + 'Harder', + 'Cohn', + 'Yoo', + 'Garnett', + 'Harter', + 'Wenger', + 'Charlton', + 'Littleton', + 'Minter', + 'Henriquez', + 'Cone', + 'Vines', + 'Kimmel', + 'Crooks', + 'Caraballo', + 'Searcy', + 'Peyton', + 'Renfro', + 'Groff', + 'Thorn', + 'Moua', + 'Jay', + 'Leigh', + 'Sanborn', + 'Wicker', + 'Martens', + 'Broome', + 'Abney', + 'Fisk', + 'Argueta', + 'Upchurch', + 'Alderman', + 'Tisdale', + 'Castellano', + 'Legg', + 'Wilbur', + 'Bills', + 'Dix', + 'Mauldin', + 'Isbell', + 'Mears', + 'Latimer', + 'Ashcraft', + 'Earley', + 'Tejada', + 'Partridge', + 'Anglin', + 'Caswell', + 'Easton', + 'Kirchner', + 'Mehta', + 'Lanham', + 'Blaylock', + 'Binder', + 'Catalano', + 'Handley', + 'Storm', + 'Albertson', + 'Free', + 'Tuck', + 'Keegan', + 'Moriarty', + 'Dexter', + 'Mancuso', + 'Allard', + 'Pino', + 'Chamberlin', + 'Moffitt', + 'Haag', + 'Schott', + 'Agnew', + 'Malcolm', + 'Hallman', + 'Heckman', + 'Karr', + 'Soares', + 'Alfonso', + 'Tom', + 'Wadsworth', + 'Schindler', + 'Garibay', + 'Kuykendall', + 'Penny', + 'Littlefield', + 'Mcnabb', + 'Sam', + 'Lea', + 'Berrios', + 'Murry', + 'Regalado', + 'Dehart', + 'Mohammed', + 'Counts', + 'Solorio', + 'Preciado', + 'Armendariz', + 'Martell', + 'Barksdale', + 'Frick', + 'Haller', + 'Broyles', + 'Doll', + 'Cable', + 'Delvalle', + 'Weems', + 'Kelleher', + 'Gagne', + 'Albers', + 'Kunz', + 'Hoy', + 'Hawes', + 'Guenther', + 'Johansen', + 'Chaffin', + 'Whitworth', + 'Wynne', + 'Mcmurray', + 'Luce', + 'Fiore', + 'Straub', + 'Majors', + 'Mcduffie', + 'Bohannon', + 'Rawlings', + 'Freed', + 'Sutter', + 'Lindstrom', + 'Buss', + 'Loera', + 'Hoyle', + 'Witte', + 'Tyree', + 'Luttrell', + 'Andrus', + 'Steed', + 'Thiel', + 'Cranford', + 'Fulmer', + 'Gable', + 'Porras', + 'Weis', + 'Maas', + 'Packard', + 'Noyes', + 'Kwon', + 'Knoll', + 'Marx', + 'Feeney', + 'Israel', + 'Bohn', + 'Cockrell', + 'Glick', + 'Cosgrove', + 'Keefer', + 'Mundy', + 'Batchelor', + 'Loveless', + 'Horowitz', + 'Haskell', + 'Kunkel', + 'Colson', + 'Hedges', + 'Staggs', + 'Swisher', + 'Lomeli', + 'Padron', + 'Cota', + 'Homan', + 'Musser', + 'Curtin', + 'Salerno', + 'Segovia', + 'Keeton', + 'Brandenburg', + 'Starling', + 'Tsai', + 'Mahon', + 'Klinger', + 'Paquette', + 'Haddad', + 'Mccune', + 'Mathew', + 'Shull', + 'Higdon', + 'Guest', + 'Shay', + 'Swafford', + 'Angulo', + 'Hackney', + 'Evers', + 'Sibley', + 'Woodworth', + 'Ostrander', + 'Mangum', + 'Smyth', + 'Quarles', + 'Mccarter', + 'Close', + 'Truitt', + 'Stpierre', + 'Mackay', + 'Bayer', + 'Timm', + 'Thatcher', + 'Bess', + 'Trinidad', + 'Jacoby', + 'Proffitt', + 'Concepcion', + 'Parkinson', + 'Carreon', + 'Ramon', + 'Monroy', + 'Leger', + 'Jauregui', + 'Glynn', + 'Taggart', + 'Neil', + 'Reddick', + 'Wiese', + 'Dover', + 'Wicks', + 'Hennessy', + 'Bittner', + 'Mcclung', + 'Mcwhorter', + 'Derrick', + 'Strom', + 'Beckham', + 'Kee', + 'Coombs', + 'Schrock', + 'Holtz', + 'Maki', + 'Willson', + 'Hulsey', + 'Whitson', + 'Haugen', + 'Lumpkin', + 'Scholl', + 'Gall', + 'Carvalho', + 'Kovach', + 'Vieira', + 'Millan', + 'Irvine', + 'Held', + 'Jolley', + 'Jasper', + 'Cadena', + 'Runyon', + 'Lomax', + 'Fahey', + 'Hoppe', + 'Bivens', + 'Ruggiero', + 'Hussey', + 'Ainsworth', + 'Hardman', + 'Ulloa', + 'Dugger', + 'Fitzsimmons', + 'Scroggins', + 'Sowell', + 'Toler', + 'Barba', + 'Biddle', + 'Rafferty', + 'Trapp', + 'Byler', + 'Brill', + 'Delagarza', + 'Thigpen', + 'Hiller', + 'Martins', + 'Jankowski', + 'Findley', + 'Hollins', + 'Stull', + 'Pollack', + 'Poirier', + 'Reno', + 'Bratton', + 'Jeffery', + 'Menendez', + 'Mcnutt', + 'Kohl', + 'Forster', + 'Clough', + 'Deloach', + 'Bader', + 'Hanes', + 'Sturm', + 'Tafoya', + 'Beall', + 'Coble', + 'Demers', + 'Kohn', + 'Santamaria', + 'Vaught', + 'Correia', + 'Mcgrew', + 'Sarmiento', + 'Roby', + 'Reinhart', + 'Rosenbaum', + 'Bernier', + 'Schiller', + 'Furman', + 'Grabowski', + 'Perryman', + 'Kidwell', + 'Sabo', + 'Saxton', + 'Noland', + 'Seaton', + 'Packer', + 'Seal', + 'Ruby', + 'Smoot', + 'Lavoie', + 'Putman', + 'Fairbanks', + 'Neill', + 'Florence', + 'Beattie', + 'Tarver', + 'Stephen', + 'Bolen', + 'Mccombs', + 'Freedman', + 'Barnhill', + 'Gaddis', + 'Goad', + 'Worden', + 'Canada', + 'Vickery', + 'Calvin', + 'Mcclintock', + 'Slocum', + 'Clausen', + 'Mccutcheon', + 'Ripley', + 'Razo', + 'Southard', + 'Bourne', + 'Aiello', + 'Knudsen', + 'Angeles', + 'Keeney', + 'Stacey', + 'Neeley', + 'Holly', + 'Gallant', + 'Eads', + 'Lafleur', + 'Fredrickson', + 'Popp', + 'Bobo', + 'Pardo', + 'Artis', + 'Lawless', + 'Shen', + 'Headley', + 'Pedraza', + 'Pickard', + 'Salvador', + 'Hofmann', + 'Davey', + 'Szymanski', + 'Dallas', + 'Erb', + 'Perea', + 'Alcantar', + 'Ashford', + 'Harry', + 'Crutchfield', + 'Goebel', + 'Ridgeway', + 'Mcvey', + 'Cordell', + 'Kovacs', + 'Florez', + 'Calkins', + 'Redden', + 'Ricker', + 'Salcido', + 'Farrington', + 'Reimer', + 'Mullis', + 'Mayhew', + 'Register', + 'Kaye', + 'Blocker', + 'Buford', + 'Munguia', + 'Cady', + 'Burley', + 'Sander', + 'Robinette', + 'Stubblefield', + 'Shuman', + 'Santillan', + 'Loy', + 'Deutsch', + 'Sales', + 'Langdon', + 'Mazur', + 'Clapp', + 'Teal', + 'Buffington', + 'Elliot', + 'Halstead', + 'Sturgeon', + 'Colley', + 'Koehn', + 'Bergstrom', + 'Dunne', + 'Pond', + 'Gantt', + 'Cousins', + 'Viera', + 'Wilks', + 'Haase', + 'Sweat', + 'Simonson', + 'Breedlove', + 'Munn', + 'Pitt', + 'Faircloth', + 'Peter', + 'Wheaton', + 'Howland', + 'Merriman', + 'Fusco', + 'Burney', + 'Bedford', + 'Baltazar', + 'Persaud', + 'Gerard', + 'Bourque', + 'Chao', + 'Slagle', + 'Kirsch', + 'Volk', + 'Heim', + 'Glasgow', + 'Borders', + 'Rauch', + 'Goforth', + 'Batson', + 'Basham', + 'Mount', + 'Peace', + 'Lazo', + 'Samples', + 'Amaro', + 'Slattery', + 'Ibrahim', + 'Weatherford', + 'Taft', + 'Santoro', + 'Aparicio', + 'Jiang', + 'Ritchey', + 'Goble', + 'Spring', + 'Strain', + 'Scully', + 'Villareal', + 'Toro', + 'Duval', + 'Jonas', + 'Neuman', + 'Wozniak', + 'Varney', + 'Dell', + 'Conover', + 'Landon', + 'Sigler', + 'Galbraith', + 'Boss', + 'Cepeda', + 'Back', + 'Mateo', + 'Peebles', + 'Arsenault', + 'Cathey', + 'Calabrese', + 'Dodds', + 'Gilbertson', + 'Hoke', + 'Greenlee', + 'Sauceda', + 'Vue', + 'Lehmann', + 'Zink', + 'Lapointe', + 'Laster', + 'Moy', + 'Ammons', + 'Llamas', + 'Foltz', + 'Fleck', + 'Chew', + 'Amaral', + 'Geer', + 'Su', + 'Carden', + 'Nunley', + 'Creel', + 'Clarkson', + 'Provost', + 'Covey', + 'Paine', + 'Wofford', + 'Frame', + 'Dube', + 'Grice', + 'Tully', + 'Molnar', + 'Luciano', + 'Bartels', + 'Winstead', + 'Canady', + 'Moreau', + 'Burnside', + 'Bratcher', + 'Infante', + 'Peterman', + 'Swope', + 'Freeland', + 'Vetter', + 'Lanning', + 'Marquis', + 'Schulze', + 'Thai', + 'Coppola', + 'Rayburn', + 'Conte', + 'Martz', + 'Showalter', + 'Quinonez', + 'Bandy', + 'Rao', + 'Bunting', + 'Belt', + 'Cruse', + 'Hamblin', + 'Himes', + 'Raney', + 'Merrell', + 'See', + 'Gough', + 'Maciel', + 'Wimberly', + 'Craddock', + 'Marquardt', + 'Wentz', + 'Meeker', + 'Sandberg', + 'Mosier', + 'Wasson', + 'Hundley', + 'Joe', + 'Shumaker', + 'Fortin', + 'Embry', + 'Olivarez', + 'Akin', + 'Seidel', + 'Coons', + 'Corrales', + 'Earle', + 'Matheny', + 'Kish', + 'Outlaw', + 'Lieberman', + 'Spalding', + 'Barnette', + 'Martel', + 'Hargis', + 'Kelso', + 'Merrick', + 'Fullerton', + 'Fries', + 'Doucette', + 'Clouse', + 'Prewitt', + 'Hawks', + 'Keaton', + 'Worthy', + 'Zook', + 'Montez', + 'Poore', + 'Autry', + 'Lemay', + 'Shifflett', + 'Forsyth', + 'Briseno', + 'Piazza', + 'Welker', + 'Tennant', + 'Heinz', + 'Haggard', + 'Leighton', + 'Brittain', + 'Begley', + 'Flanders', + 'Hermann', + 'Botello', + 'Mathias', + 'Hofer', + 'Hutto', + 'Godoy', + 'Cave', + 'Pagano', + 'Asbury', + 'Bowens', + 'Withrow', + 'Olivo', + 'Harbin', + 'Andre', + 'Sandlin', + 'Wertz', + 'Desimone', + 'Greiner', + 'Heinrich', + 'Whitcomb', + 'Dayton', + 'Petrie', + 'Hair', + 'Ketchum', + 'Shanahan', + 'Bianco', + 'Heil', + 'Cochrane', + 'Wegner', + 'Dagostino', + 'Couture', + 'Ling', + 'Wingate', + 'Arenas', + 'Keel', + 'Casteel', + 'Boothe', + 'Derosa', + 'Horst', + 'Rau', + 'Palermo', + 'Mccorkle', + 'Altamirano', + 'Nall', + 'Shumate', + 'Lightfoot', + 'Creamer', + 'Romeo', + 'Coffin', + 'Hutchings', + 'Jerome', + 'Hutcheson', + 'Damron', + 'Sorrell', + 'Nickel', + 'Sells', + 'Pinkerton', + 'Dao', + 'Dion', + 'Mcfarlane', + 'Ridenour', + 'Atwell', + 'Sturgill', + 'Schoen', + 'Partin', + 'Nemeth', + 'Almonte', + 'Pan', + 'Rickard', + 'Wentworth', + 'Sammons', + 'Sayre', + 'Southerland', + 'Parisi', + 'Ahn', + 'Carrion', + 'Testa', + 'Shorter', + 'Covert', + 'Gorham', + 'Alcantara', + 'Belton', + 'Bannister', + 'Sharkey', + 'Mccreary', + 'Pannell', + 'Scarbrough', + 'Keeling', + 'Gainey', + 'Mill', + 'Camarena', + 'Herbst', + 'Roller', + 'Wild', + 'Dellinger', + 'Lovejoy', + 'Manson', + 'Dupuis', + 'Clem', + 'Resendez', + 'Burkhardt', + 'Williford', + 'Mclendon', + 'Mazza', + 'Mccaffrey', + 'Lum', + 'Settle', + 'Hefner', + 'Dupre', + 'Louie', + 'Gunther', + 'Weimer', + 'Turnbull', + 'Bradbury', + 'Maness', + 'Urena', + 'Lor', + 'Sides', + 'Wick', + 'Monaco', + 'Gillen', + 'Ives', + 'Battaglia', + 'Ulmer', + 'Schreiner', + 'Caceres', + 'Sprouse', + 'Scoggins', + 'Ahern', + 'Tracey', + 'Terrazas', + 'Bracken', + 'Gurley', + 'Soliz', + 'Alcaraz', + 'Martines', + 'Weidner', + 'Criswell', + 'Wilbanks', + 'Hennessey', + 'Mendes', + 'Peak', + 'Ruelas', + 'Caudle', + 'Fuqua', + 'Jewett', + 'Chism', + 'Volpe', + 'Nino', + 'Logue', + 'Mcculloch', + 'Furr', + 'Kersey', + 'Shinn', + 'Yan', + 'Rausch', + 'Stinnett', + 'Mowery', + 'Rivero', + 'Weed', + 'Bertram', + 'Durand', + 'Gatewood', + 'Tilton', + 'Mahaffey', + 'Niles', + 'Mccue', + 'Vargo', + 'Holcombe', + 'Ralph', + 'Castleberry', + 'Snipes', + 'Wilt', + 'Vanmeter', + 'Nutter', + 'Mendiola', + 'Burchett', + 'Enos', + 'Jobe', + 'Kirkwood', + 'Pedroza', + 'Iglesias', + 'Leong', + 'Cromer', + 'Trice', + 'Magnuson', + 'Eagle', + 'Montenegro', + 'Troy', + 'Cato', + 'Edmond', + 'Hendrick', + 'Lebron', + 'Lathrop', + 'Budd', + 'Appel', + 'Knowlton', + 'Bianchi', + 'Camarillo', + 'Ginn', + 'Pulley', + 'True', + 'Gaddy', + 'Domingo', + 'Kingsley', + 'Loftus', + 'Denham', + 'Sifuentes', + 'Siler', + 'Hardison', + 'Kwan', + 'Pendergrass', + 'Frasier', + 'Hutchens', + 'Fort', + 'Montiel', + 'Fincher', + 'Eggers', + 'Moen', + 'Griffis', + 'Hauck', + 'Lister', + 'Lundberg', + 'Tanaka', + 'Cornish', + 'Whitlow', + 'Chou', + 'Griego', + 'Robson', + 'Prosser', + 'Ballinger', + 'Fogarty', + 'Allman', + 'Atchison', + 'Conaway', + 'Riddick', + 'Rupert', + 'Krug', + 'Pinkston', + 'Coggins', + 'Narvaez', + 'Earnest', + 'Fain', + 'Rash', + 'Olmstead', + 'Sherrod', + 'Beeler', + 'Spearman', + 'Poland', + 'Rousseau', + 'Hyland', + 'Rhea', + 'Son', + 'Redmon', + 'Wilke', + 'Valenti', + 'Paulino', + 'Geyer', + 'Blackwood', + 'Leclair', + 'Olguin', + 'Maestas', + 'Buckingham', + 'Blythe', + 'Samuelson', + 'Bounds', + 'Nakamura', + 'Batts', + 'Galarza', + 'Sisco', + 'Mcvay', + 'Hynes', + 'Mertz', + 'Tremblay', + 'Orosco', + 'Prentice', + 'Wilhite', + 'Seiler', + 'Archibald', + 'Wooldridge', + 'Winfield', + 'Oden', + 'Zelaya', + 'Chestnut', + 'Guardado', + 'Mccallister', + 'Canty', + 'Grasso', + 'Collett', + 'Hylton', + 'Easterling', + 'Deangelis', + 'Treadway', + 'Ferrari', + 'Ethridge', + 'Milburn', + 'Mercier', + 'Bickford', + 'Thibodeau', + 'Bolanos', + 'Fellows', + 'Hales', + 'Greathouse', + 'Buchholz', + 'Strunk', + 'Faison', + 'Purnell', + 'Clegg', + 'Steinmetz', + 'Wojcik', + 'Alcorn', + 'Ballesteros', + 'Basile', + 'Paez', + 'Armour', + 'Devito', + 'Tello', + 'Flick', + 'Yount', + 'Estevez', + 'Hitt', + 'Houle', + 'Cha', + 'Travers', + 'Cass', + 'Loper', + 'Getz', + 'Cade', + 'Gonsalves', + 'Lear', + 'Cromwell', + 'Stephan', + 'Ocasio', + 'Deluna', + 'Tolentino', + 'Picard', + 'Eaves', + 'Toscano', + 'Ault', + 'Osburn', + 'Ruvalcaba', + 'Szabo', + 'Kozak', + 'Bear', + 'Eck', + 'Deyoung', + 'Morehead', + 'Herrin', + 'Tillery', + 'Royster', + 'Kehoe', + 'Swank', + 'Yamamoto', + 'Schoonover', + 'Clanton', + 'Stutzman', + 'Swearingen', + 'Martinson', + 'Harrelson', + 'Leo', + 'Keyser', + 'Guyton', + 'Lucio', + 'Veal', + 'Vanwinkle', + 'Angelo', + 'Zamudio', + 'Haddock', + 'Quach', + 'Thomsen', + 'Curiel', + 'Badger', + 'Teel', + 'Hibbard', + 'Dvorak', + 'Ballew', + 'Falls', + 'Bostick', + 'Monaghan', + 'Segal', + 'Denning', + 'Bahr', + 'Serrato', + 'Toomey', + 'Lacroix', + 'Antoine', + 'Resendiz', + 'Sperry', + 'Rosser', + 'Bogan', + 'Gaspar', + 'Amin', + 'Schramm', + 'Lemaster', + 'Echevarria', + 'Lilley', + 'Poling', + 'Villagomez', + 'Conde', + 'Delrio', + 'Lerner', + 'Leroy', + 'Otis', + 'Durkin', + 'Lavender', + 'Schenk', + 'Ong', + 'Guess', + 'Alanis', + 'Jacobo', + 'Ramsay', + 'Henke', + 'Sledge', + 'Whited', + 'Frazer', + 'Fortier', + 'Macleod', + 'Pascual', + 'Casanova', + 'Olds', + 'Jenson', + 'Tijerina', + 'Flora', + 'Casto', + 'Rinaldi', + 'Blunt', + 'Fontana', + 'Minnick', + 'Larios', + 'Raynor', + 'Fung', + 'Marek', + 'Valladares', + 'Clemmons', + 'Gracia', + 'Rohrer', + 'Fryer', + 'Folsom', + 'Gearhart', + 'Sumpter', + 'Kraemer', + 'Aceves', + 'Pettigrew', + 'Mclaurin', + 'Southern', + 'Barrows', + 'Landeros', + 'Janes', + 'Deguzman', + 'Mcfall', + 'Fredericks', + 'Ashe', + 'Mauro', + 'Merino', + 'Windsor', + 'Taber', + 'Armijo', + 'Bricker', + 'Pitman', + 'Morrill', + 'Sanches', + 'Deboer', + 'Conlon', + 'Reuter', + 'Stegall', + 'Clemente', + 'Romine', + 'Dykstra', + 'Ehlers', + 'Tallman', + 'Lovato', + 'Brent', + 'Pearl', + 'Pyles', + 'Cloutier', + 'Mccurry', + 'Mckeever', + 'Graziano', + 'Heflin', + 'Garman', + 'Isaacson', + 'Mcreynolds', + 'Meister', + 'Stroup', + 'Everson', + 'Halsey', + 'Mcewen', + 'Sparkman', + 'Yager', + 'Bucher', + 'Berryman', + 'Derr', + 'Jester', + 'Mickelson', + 'Sayers', + 'Whiteman', + 'Riordan', + 'Mcinnis', + 'Jose', + 'Goolsby', + 'Stidham', + 'Donley', + 'Johnsen', + 'Stallworth', + 'Franke', + 'Silvers', + 'Reitz', + 'Nathan', + 'Brogan', + 'Cardoso', + 'Linville', + 'Baptiste', + 'Gorski', + 'Rey', + 'Hazen', + 'Damon', + 'Shores', + 'Boling', + 'Jablonski', + 'Lemieux', + 'Hecht', + 'Dong', + 'Langlois', + 'Burrow', + 'Hernandes', + 'Mcdevitt', + 'Pichardo', + 'Lew', + 'Stillwell', + 'Savoy', + 'Teixeira', + 'Matheson', + 'Hildreth', + 'Warfield', + 'Hogg', + 'Tiller', + 'Unruh', + 'Rudy', + 'Bristol', + 'Matias', + 'Buxton', + 'Ambriz', + 'Chiang', + 'Pomeroy', + 'Pogue', + 'Hammock', + 'Bethel', + 'Miguel', + 'Cassell', + 'Towns', + 'Bunker', + 'Mcmichael', + 'Kress', + 'Newland', + 'Whitehurst', + 'Fazio', + 'Batten', + 'Calvillo', + 'Wallen', + 'Lung', + 'Turney', + 'Sparrow', + 'Steadman', + 'Battles', + 'Berlin', + 'Lindgren', + 'Mckeon', + 'Luckett', + 'Spradlin', + 'Sherry', + 'Timmerman', + 'Utley', + 'Beale', + 'Driggers', + 'Hintz', + 'Pellegrino', + 'Hazel', + 'Grim', + 'Desmond', + 'Spellman', + 'Boren', + 'Staten', + 'Schlegel', + 'Maya', + 'Johnstone', + 'Harwell', + 'Pinson', + 'Barreto', + 'Spooner', + 'Candelaria', + 'Hammett', + 'Sessions', + 'Mckeown', + 'Mccool', + 'Gilson', + 'Knudson', + 'Irish', + 'Spruill', + 'Kling', + 'Gerlach', + 'Carnahan', + 'Markley', + 'Laporte', + 'Flanigan', + 'Spires', + 'Cushman', + 'Plante', + 'Schlosser', + 'Sachs', + 'Jamieson', + 'Hornsby', + 'Armstead', + 'Kremer', + 'Madera', + 'Thornburg', + 'Briley', + 'Garris', + 'Jorgenson', + 'Moorman', + 'Vuong', + 'Ard', + 'Irons', + 'Fiedler', + 'Jackman', + 'Kuehn', + 'Jenks', + 'Bristow', + 'Mosby', + 'Aldana', + 'Maclean', + 'Freund', + 'Creighton', + 'Smothers', + 'Melson', + 'Lundgren', + 'Donato', + 'Usher', + 'Thornhill', + 'Lowman', + 'Mariano', + 'Button', + 'Mcbee', + 'Cupp', + 'Wickham', + 'Destefano', + 'Nutt', + 'Rambo', + 'Voigt', + 'Talbott', + 'Saxon', + 'Cedillo', + 'Mattison', + 'Speed', + 'Reiss', + 'Nan', + 'Westphal', + 'Whittle', + 'Bernhardt', + 'Boatwright', + 'Bussey', + 'Rojo', + 'Eden', + 'Crites', + 'Place', + 'He', + 'Chaves', + 'Larose', + 'Thames', + 'Hoch', + 'Knotts', + 'Simone', + 'Binkley', + 'Koester', + 'Pettis', + 'Moye', + 'Napolitano', + 'Heffner', + 'Sasser', + 'Jessup', + 'Aguiar', + 'Ogrady', + 'Pippin', + 'Worth', + 'Shively', + 'Whitmire', + 'Rutter', + 'Cedeno', + 'Welborn', + 'Mcdougal', + 'Angell', + 'Sacco', + 'Hailey', + 'Neel', + 'Paniagua', + 'Pointer', + 'Rohde', + 'Holloman', + 'Strother', + 'Guffey', + 'Fenner', + 'Huntington', + 'Shane', + 'Yuen', + 'Gosnell', + 'Martini', + 'Loving', + 'Molloy', + 'Olmos', + 'Christ', + 'Oaks', + 'Ostrowski', + 'Badillo', + 'To', + 'Laplante', + 'Martindale', + 'Richie', + 'Pleasant', + 'Palomino', + 'Rodarte', + 'Stamps', + 'Peeples', + 'Ries', + 'Brownell', + 'Walz', + 'Arana', + 'Tenney', + 'Roddy', + 'Lindner', + 'Bolt', + 'Rigsby', + 'Matteson', + 'Fielder', + 'Randazzo', + 'Deanda', + 'Drayton', + 'Ridge', + 'Tarr', + 'Shade', + 'Upshaw', + 'Woodcock', + 'Miley', + 'Hargrave', + 'Langer', + 'Yun', + 'Wilkie', + 'Choe', + 'Ching', + 'Dugas', + 'Saul', + 'Corder', + 'Bobbitt', + 'Spurgeon', + 'Gladden', + 'Woodbury', + 'Tibbs', + 'Mcgarry', + 'Mcdaniels', + 'Weigel', + 'Bickel', + 'Michels', + 'Hughey', + 'Apple', + 'Bosley', + 'Nesmith', + 'Farber', + 'Ackley', + 'Goodin', + 'Almond', + 'Garrity', + 'Bettencourt', + 'Koss', + 'Falcone', + 'Lavigne', + 'Rainwater', + 'Nation', + 'Blodgett', + 'Dabney', + 'Mabe', + 'Trowbridge', + 'Lundquist', + 'Rosenberger', + 'Dombrowski', + 'Ferro', + 'Evangelista', + 'Bowlin', + 'Mckelvey', + 'Roderick', + 'Michalski', + 'Berkowitz', + 'Sato', + 'Mayorga', + 'Corwin', + 'Mckenney', + 'Salyer', + 'Walling', + 'Abell', + 'Palacio', + 'Lash', + 'Collado', + 'Gass', + 'Luis', + 'Cooksey', + 'Moll', + 'Miramontes', + 'Luster', + 'Shrader', + 'Toliver', + 'Hard', + 'Tu', + 'Sena', + 'Mckoy', + 'Wainwright', + 'Barela', + 'Keiser', + 'Hoag', + 'Backus', + 'Huskey', + 'Brannan', + 'Brumley', + 'Palm', + 'Boynton', + 'Krauss', + 'Steel', + 'Jurado', + 'Mulder', + 'Paterson', + 'Woolsey', + 'Smithson', + 'Joslin', + 'Richman', + 'Partida', + 'Grisham', + 'Wooden', + 'Gooding', + 'Fang', + 'Mcdade', + 'Spriggs', + 'Fishman', + 'Gabel', + 'Rutkowski', + 'Pride', + 'Beals', + 'Gaskin', + 'Friday', + 'Underhill', + 'Rodas', + 'Melo', + 'Sipes', + 'Zimmermann', + 'Mosqueda', + 'Haight', + 'Beeson', + 'Judy', + 'Bankston', + 'Pieper', + 'Siebert', + 'Horning', + 'Butt', + 'Bice', + 'Sills', + 'Philips', + 'Eisenberg', + 'Schumann', + 'Conger', + 'Bare', + 'Hume', + 'Nolasco', + 'Trainor', + 'Weatherly', + 'Huebner', + 'Bosch', + 'Gayle', + 'Kuhns', + 'Byron', + 'Glaze', + 'Poulin', + 'Enright', + 'Large', + 'Comeaux', + 'Rountree', + 'Tavarez', + 'Beardsley', + 'Rubino', + 'Fee', + 'Grider', + 'Bechtel', + 'Gaona', + 'Wallin', + 'Mashburn', + 'Dalrymple', + 'Gingerich', + 'Vaccaro', + 'Hass', + 'Manzano', + 'Tyner', + 'Loza', + 'Lowell', + 'Kaufmann', + 'Bischoff', + 'Doolittle', + 'Shivers', + 'Valente', + 'Bozeman', + 'Howes', + 'Felts', + 'Feller', + 'Justus', + 'Schnell', + 'Boettcher', + 'Ivory', + 'Thorson', + 'Corn', + 'Snook', + 'Heilman', + 'Baxley', + 'Hasty', + 'Wasserman', + 'Barringer', + 'Frankel', + 'Peltier', + 'Guarino', + 'Avina', + 'Sturdivant', + 'Lien', + 'Montemayor', + 'Giddens', + 'Valverde', + 'Burchfield', + 'Pang', + 'Holbert', + 'Rooks', + 'Erdman', + 'Mcmaster', + 'Iniguez', + 'Hartwell', + 'Menchaca', + 'Bordelon', + 'Farkas', + 'Chrisman', + 'Metzler', + 'Fredrick', + 'Porterfield', + 'Slayton', + 'Quesada', + 'Hembree', + 'Peel', + 'Woodley', + 'Mather', + 'Waltz', + 'Totten', + 'Forney', + 'Woolley', + 'Trombley', + 'Yarborough', + 'Javier', + 'Durr', + 'Macklin', + 'Macon', + 'Novotny', + 'Amundson', + 'Kidder', + 'Flagg', + 'Oxendine', + 'Arguello', + 'Marler', + 'Penrod', + 'Mallett', + 'Council', + 'Kinard', + 'Bremer', + 'Towne', + 'Harless', + 'Merkel', + 'Giese', + 'Fife', + 'Byars', + 'Grande', + 'Kuo', + 'Levi', + 'Darr', + 'Sanabria', + 'Pounds', + 'Roeder', + 'Keim', + 'Brush', + 'Dreyer', + 'Taveras', + 'Furlong', + 'Dorris', + 'Prior', + 'Musgrove', + 'Weiler', + 'Munro', + 'Leake', + 'Vollmer', + 'Musick', + 'Hetrick', + 'Perdomo', + 'Kester', + 'Lock', + 'Pine', + 'Baskin', + 'Bonham', + 'Heffernan', + 'Mandel', + 'Sarver', + 'Hamer', + 'Duckett', + 'Lozada', + 'Stocker', + 'Fulcher', + 'Damato', + 'Camargo', + 'Shephard', + 'Loftis', + 'Winfrey', + 'Rueda', + 'Ledezma', + 'Gottlieb', + 'Lamont', + 'Mackie', + 'Bowe', + 'Stockwell', + 'Groth', + 'Chavira', + 'Lohr', + 'Loftin', + 'Gilmer', + 'Cushing', + 'Brody', + 'Nowlin', + 'Holiday', + 'Shirk', + 'Archie', + 'Howerton', + 'Matthew', + 'Copley', + 'Marchese', + 'Echeverria', + 'Soper', + 'Cantwell', + 'Nelms', + 'Tuggle', + 'Dumont', + 'Bard', + 'Gower', + 'Mathes', + 'Yeung', + 'Buell', + 'Bastian', + 'Burd', + 'Broadway', + 'Peng', + 'Greenwell', + 'Vanover', + 'Correll', + 'Tindall', + 'Bill', + 'Mulcahy', + 'Dionne', + 'Rathbun', + 'Baeza', + 'Booher', + 'Fried', + 'Mcginley', + 'Lavin', + 'Atherton', + 'Donnell', + 'Bays', + 'Riedel', + 'Grenier', + 'Zachary', + 'Harold', + 'Styles', + 'Wisdom', + 'Raley', + 'Tamez', + 'Arena', + 'Morelli', + 'Hazelwood', + 'Somerville', + 'Lapp', + 'Rood', + 'Salem', + 'Pape', + 'Olivera', + 'Albritton', + 'Carvajal', + 'Zayas', + 'Myer', + 'Pohl', + 'Haynie', + 'Mariscal', + 'Wampler', + 'Rife', + 'Leeper', + 'Newhouse', + 'Rodney', + 'Vandenberg', + 'Spitzer', + 'Kingston', + 'Wessel', + 'Hartzell', + 'Durden', + 'Marques', + 'Born', + 'Scribner', + 'Rocco', + 'Germain', + 'Tinoco', + 'Valdovinos', + 'Musselman', + 'Vicente', + 'Parsley', + 'Crittenden', + 'Tibbetts', + 'Hulse', + 'Mccleary', + 'Barboza', + 'Velarde', + 'Brodie', + 'Beaudoin', + 'Moreira', + 'Maggard', + 'Jara', + 'Ferrante', + 'Overby', + 'Friesen', + 'Viola', + 'Nelsen', + 'Hash', + 'Doane', + 'Deese', + 'Messick', + 'Bay', + 'Anton', + 'Ingersoll', + 'Saucier', + 'Kwiatkowski', + 'Rawson', + 'Brophy', + 'Ladner', + 'Lehr', + 'Weil', + 'Yocum', + 'Brasher', + 'Denison', + 'Hutcherson', + 'Stowers', + 'Geller', + 'Fortenberry', + 'Stebbins', + 'Conyers', + 'Toole', + 'Stoker', + 'Roden', + 'Chitwood', + 'Beeman', + 'Fannin', + 'Strait', + 'Marlowe', + 'Greenwald', + 'Hann', + 'Stumpf', + 'Samaniego', + 'Colton', + 'Bogart', + 'Morel', + 'Montelongo', + 'Boylan', + 'Guido', + 'Wyrick', + 'Horsley', + 'Tenorio', + 'Sallee', + 'Morehouse', + 'Whyte', + 'Neilson', + 'Watanabe', + 'Magallanes', + 'Mudd', + 'Kieffer', + 'Brigham', + 'Dollar', + 'Huss', + 'Albanese', + 'Spiegel', + 'Hixson', + 'Rounds', + 'Orth', + 'Blanchette', + 'Vanderpool', + 'Pfaff', + 'Speck', + 'Shreve', + 'Sevilla', + 'Neri', + 'Rohr', + 'Ruble', + 'Vanpelt', + 'Rickman', + 'Caraway', + 'Berndt', + 'Mchale', + 'Ingalls', + 'Roybal', + 'Money', + 'Mcdougall', + 'Melancon', + 'Wellington', + 'Ingraham', + 'Ritz', + 'Lashley', + 'Marchand', + 'Schatz', + 'Heiser', + 'Eby', + 'Wimmer', + 'Orton', + 'Atchley', + 'Mumford', + 'Bahena', + 'Gammon', + 'Buehler', + 'Fike', + 'Plank', + 'Carrigan', + 'Kempf', + 'Cundiff', + 'So', + 'Sauls', + 'Mohler', + 'Grillo', + 'Prichard', + 'Pastor', + 'Prasad', + 'Babin', + 'Bontrager', + 'Weddle', + 'Alberts', + 'Theis', + 'Lemoine', + 'Hartnett', + 'Kingsbury', + 'Baran', + 'Birmingham', + 'Gault', + 'Thorp', + 'Wyant', + 'Obryan', + 'Santacruz', + 'Camara', + 'Whitehouse', + 'Evenson', + 'Halvorson', + 'Palmieri', + 'Hannan', + 'Dew', + 'Au', + 'Nolte', + 'Click', + 'Wooley', + 'Hung', + 'Eberhardt', + 'Rawlins', + 'Sadowski', + 'Sarabia', + 'Soule', + 'Millar', + 'Engstrom', + 'Cowles', + 'Runyan', + 'Mitchel', + 'Torrence', + 'Silverstein', + 'Hewett', + 'Pilgrim', + 'Yeh', + 'Rosenfeld', + 'Mulholland', + 'Hatley', + 'Fawcett', + 'Delrosario', + 'Chinn', + 'Bayless', + 'Dee', + 'Deane', + 'Arriola', + 'Duda', + 'Koster', + 'Rath', + 'Karl', + 'Weiland', + 'Lemmon', + 'Blaine', + 'Scofield', + 'Marston', + 'Gist', + 'Pinckney', + 'Moritz', + 'Mclellan', + 'Fulkerson', + 'Gaynor', + 'Pitre', + 'Warrick', + 'Cobbs', + 'Meacham', + 'Guerin', + 'Tedesco', + 'Passmore', + 'Northcutt', + 'Ison', + 'Cowell', + 'Ream', + 'Walther', + 'Meraz', + 'Tribble', + 'Bumgarner', + 'Gabbard', + 'Dawes', + 'Moncada', + 'Chilton', + 'Deweese', + 'Rigby', + 'Marte', + 'Baylor', + 'Valentino', + 'Shine', + 'August', + 'Billups', + 'Jarman', + 'Jacks', + 'Coffee', + 'Friedrich', + 'Marley', + 'Hasan', + 'Pennell', + 'Abercrombie', + 'Bazan', + 'Strickler', + 'Bruton', + 'Lamm', + 'Pender', + 'Wingfield', + 'Hoffer', + 'Zahn', + 'Chaplin', + 'Reinke', + 'Larosa', + 'Maupin', + 'Bunnell', + 'Hassell', + 'Guo', + 'Galan', + 'Paschal', + 'Browder', + 'Krantz', + 'Milne', + 'Pelayo', + 'Emanuel', + 'Mccluskey', + 'Edens', + 'Radtke', + 'Alger', + 'Duhon', + 'Probst', + 'Witmer', + 'Hoagland', + 'Saechao', + 'Pitcher', + 'Villalpando', + 'Carswell', + 'Roundtree', + 'Kuhlman', + 'Tait', + 'Shaughnessy', + 'Wei', + 'Cravens', + 'Sipe', + 'Islas', + 'Hollenbeck', + 'Lockard', + 'Perrone', + 'Tapp', + 'Santoyo', + 'Jaffe', + 'Klotz', + 'Gilpin', + 'Ehrlich', + 'Klug', + 'Stowell', + 'Ibanez', + 'Lazar', + 'Osman', + 'Larkins', + 'Donofrio', + 'Ericson', + 'Schenck', + 'Mouton', + 'Medlock', + 'Hubbell', + 'Bixler', + 'Nowicki', + 'Muro', + 'Homer', + 'Grijalva', + 'Ashmore', + 'Harbison', + 'Duffey', + 'Osgood', + 'Hardee', + 'Jain', + 'Wilber', + 'Bolling', + 'Lett', + 'Phillip', + 'Dipietro', + 'Lefebvre', + 'Batiste', + 'Mcswain', + 'Distefano', + 'Hack', + 'Strobel', + 'Kipp', + 'Doerr', + 'Radcliffe', + 'Cartagena', + 'Paradis', + 'Stilwell', + 'Mccrea', + 'Searles', + 'Frausto', + 'Hendershot', + 'Gosselin', + 'Islam', + 'Freese', + 'Stockman', + 'Burwell', + 'Vandiver', + 'Engler', + 'Geisler', + 'Barham', + 'Wiegand', + 'Goncalves', + 'Theriot', + 'Doucet', + 'Bridge', + 'Catron', + 'Blanks', + 'Rahn', + 'Schaub', + 'Hershey', + 'Strader', + 'Buckman', + 'Hartwig', + 'Campo', + 'Tsang', + 'Luck', + 'Bernardo', + 'Marker', + 'Pinkney', + 'Benefield', + 'Mcginty', + 'Bode', + 'Linden', + 'Manriquez', + 'Jaquez', + 'Bedard', + 'Flack', + 'Hesse', + 'Costanzo', + 'Boardman', + 'Carper', + 'Word', + 'Miracle', + 'Edmunds', + 'Bott', + 'Flemming', + 'Manns', + 'Kesler', + 'Piatt', + 'Tankersley', + 'Eberle', + 'Roney', + 'Belk', + 'Vansickle', + 'Varga', + 'Hillard', + 'Neubauer', + 'Quirk', + 'Chevalier', + 'Mintz', + 'Kocher', + 'Casarez', + 'Tinker', + 'Elmer', + 'Decarlo', + 'Cordes', + 'Berube', + 'Kimbrell', + 'Schick', + 'Papa', + 'Alderson', + 'Callaghan', + 'Renaud', + 'Pardue', + 'Krohn', + 'Bloomfield', + 'Coward', + 'Ligon', + 'Trask', + 'Wingo', + 'Book', + 'Crutcher', + 'Canter', + 'Teran', + 'Denman', + 'Stackhouse', + 'Chambliss', + 'Gourley', + 'Earls', + 'Frizzell', + 'Bergen', + 'Abdullah', + 'Sprinkle', + 'Fancher', + 'Urias', + 'Lavelle', + 'Baumgardner', + 'Kahler', + 'Baldridge', + 'Alejandro', + 'Plascencia', + 'Hix', + 'Rule', + 'Mix', + 'Petro', + 'Hadden', + 'Fore', + 'Humes', + 'Barnum', + 'Laing', + 'Maggio', + 'Sylvia', + 'Malinowski', + 'Fell', + 'Durst', + 'Plant', + 'Vaca', + 'Abarca', + 'Shirey', + 'Parton', + 'Ta', + 'Ramires', + 'Ochs', + 'Gaitan', + 'Ledoux', + 'Darrow', + 'Messenger', + 'Chalmers', + 'Schaller', + 'Derby', + 'Coakley', + 'Saleh', + 'Kirkman', + 'Orta', + 'Crabb', + 'Spinks', + 'Dinkins', + 'Harrigan', + 'Koller', + 'Dorr', + 'Carty', + 'Sturgis', + 'Shriver', + 'Macedo', + 'Feng', + 'Bentz', + 'Bedell', + 'Osuna', + 'Dibble', + 'Dejong', + 'Fender', + 'Parada', + 'Vanburen', + 'Chaffee', + 'Stott', + 'Sigmon', + 'Nicolas', + 'Salyers', + 'Magdaleno', + 'Deering', + 'Puentes', + 'Funderburk', + 'Jang', + 'Christopherson', + 'Sellars', + 'Marcotte', + 'Oster', + 'Liao', + 'Tudor', + 'Specht', + 'Chowdhury', + 'Landa', + 'Monge', + 'Brake', + 'Behnke', + 'Llewellyn', + 'Labelle', + 'Mangan', + 'Godsey', + 'Truax', + 'Lombard', + 'Thurmond', + 'Emerick', + 'Blume', + 'Mcginn', + 'Beer', + 'Marrs', + 'Zinn', + 'Rieger', + 'Dilley', + 'Thibault', + 'Witkowski', + 'Chi', + 'Fielding', + 'Tyrrell', + 'Peeler', + 'Northrup', + 'Augustin', + 'Toy', + 'Geist', + 'Schuman', + 'Fairley', + 'Duque', + 'Villatoro', + 'Dudek', + 'Sonnier', + 'Fritts', + 'Worsham', + 'Herold', + 'Mcgehee', + 'Caskey', + 'Boatright', + 'Lazaro', + 'Deck', + 'Palomo', + 'Cory', + 'Olivier', + 'Baines', + 'Fan', + 'Futrell', + 'Halpin', + 'Garrido', + 'Koonce', + 'Fogg', + 'Meneses', + 'Mulkey', + 'Restrepo', + 'Ducharme', + 'Slate', + 'Toussaint', + 'Sorrells', + 'Fitts', + 'Dickman', + 'Alfred', + 'Grimsley', + 'Settles', + 'Etienne', + 'Eggert', + 'Hague', + 'Caldera', + 'Hillis', + 'Hollander', + 'Haire', + 'Theriault', + 'Madigan', + 'Kiernan', + 'Parkhurst', + 'Lippert', + 'Jaynes', + 'Moniz', + 'Bost', + 'Bettis', + 'Sandy', + 'Kuhl', + 'Wilk', + 'Borrego', + 'Koon', + 'Penney', + 'Pizarro', + 'Stitt', + 'Koski', + 'Galicia', + 'Quiles', + 'Real', + 'Massa', + 'Crone', + 'Teeter', + 'Voorhees', + 'Hilbert', + 'Nabors', + 'Shupe', + 'Blood', + 'Mcauliffe', + 'Waits', + 'Blakley', + 'Stoltz', + 'Maes', + 'Munroe', + 'Rhoden', + 'Abeyta', + 'Milliken', + 'Harkness', + 'Almaraz', + 'Remington', + 'Raya', + 'Frierson', + 'Olszewski', + 'Quillen', + 'Westcott', + 'Fu', + 'Tolley', + 'Olive', + 'Mcclary', + 'Corbitt', + 'Lui', + 'Lachance', + 'Meagher', + 'Cowley', + 'Hudak', + 'Cress', + 'Mccrory', + 'Talavera', + 'Mclaren', + 'Laurent', + 'Bias', + 'Whetstone', + 'Hollister', + 'Quevedo', + 'Byerly', + 'Berryhill', + 'Folk', + 'Conners', + 'Kellum', + 'Haro', + 'Mallard', + 'Mccants', + 'Risner', + 'Barros', + 'Downes', + 'Mayers', + 'Loeffler', + 'Mink', + 'Hotchkiss', + 'Bartz', + 'Alt', + 'Hindman', + 'Bayne', + 'Bagby', + 'Colin', + 'Treadwell', + 'Hemingway', + 'Bane', + 'Heintz', + 'Fite', + 'Mccomb', + 'Carmody', + 'Kistler', + 'Olinger', + 'Vestal', + 'Byrum', + 'Seale', + 'Turnage', + 'Raber', + 'Prendergast', + 'Koons', + 'Nickell', + 'Benz', + 'Mcculley', + 'Lightner', + 'Hamill', + 'Castellon', + 'Chesser', + 'Moats', + 'Buie', + 'Svoboda', + 'Wold', + 'Macmillan', + 'Boring', + 'Terrill', + 'Loveland', + 'Gaskill', + 'Verdugo', + 'Yip', + 'Oviedo', + 'Hight', + 'Carmack', + 'Scheer', + 'Dreher', + 'Appleby', + 'Lally', + 'Kibler', + 'Marra', + 'Mcnamee', + 'Cooks', + 'Kavanaugh', + 'Carrico', + 'Alden', + 'Dillman', + 'Zamarripa', + 'Serra', + 'Gilligan', + 'Nester', + 'Sokol', + 'Latta', + 'Hanrahan', + 'Ballou', + 'Hollinger', + 'Lux', + 'Caton', + 'Hamann', + 'Sackett', + 'Leiva', + 'Emory', + 'Barden', + 'Houk', + 'Lees', + 'Deltoro', + 'Lowrey', + 'Mcevoy', + 'Hibbs', + 'Crossley', + 'Rego', + 'Melchor', + 'Tull', + 'Bramlett', + 'Hsieh', + 'Warwick', + 'Sayles', + 'Mapes', + 'Pabon', + 'Dearing', + 'Stamm', + 'Joshi', + 'Quan', + 'Larry', + 'Nordstrom', + 'Heisler', + 'Bigham', + 'Walston', + 'Solberg', + 'Bodnar', + 'Posada', + 'Mancilla', + 'Ovalle', + 'Harr', + 'Mccaskill', + 'Bromley', + 'Koerner', + 'Macpherson', + 'Trudeau', + 'Blais', + 'Kiley', + 'Lawlor', + 'Suter', + 'Rothman', + 'Oberg', + 'Seely', + 'Maxfield', + 'Truman', + 'Salvatore', + 'Fouts', + 'Goulet', + 'Munger', + 'Sikora', + 'Comeau', + 'Oliphant', + 'Baber', + 'Hensel', + 'Edelman', + 'Farina', + 'Albano', + 'Aycock', + 'Sung', + 'Deckard', + 'Steinke', + 'Silveira', + 'Servin', + 'Rex', + 'Franzen', + 'Hecker', + 'Gragg', + 'Mcgriff', + 'Ellingson', + 'Kerrigan', + 'An', + 'Bartel', + 'Priddy', + 'Hodson', + 'Tse', + 'Arbogast', + 'Arceneaux', + 'Leatherman', + 'Federico', + 'Pridgen', + 'Yim', + 'Kowalczyk', + 'Deberry', + 'Lejeune', + 'Elston', + 'Mielke', + 'Shelly', + 'Stambaugh', + 'Eagan', + 'Rivard', + 'Silvia', + 'Lawhorn', + 'Denis', + 'Hendry', + 'Wieland', + 'Levinson', + 'Marlin', + 'Gerdes', + 'Pfister', + 'Carder', + 'Pipkin', + 'Angle', + 'Hang', + 'Hagerty', + 'Rhinehart', + 'Gao', + 'Petit', + 'Mccraw', + 'Markle', + 'Lupo', + 'Busse', + 'Marble', + 'Bivins', + 'Storms', + 'Yuan', + 'Waldman', + 'Suh', + 'Wyckoff', + 'Stillman', + 'Piotrowski', + 'Abrego', + 'Gregoire', + 'Bogle', + 'Wortham', + 'Phung', + 'Brister', + 'Karnes', + 'Deming', + 'Ley', + 'Carrasquillo', + 'Curtiss', + 'Appleton', + 'Salley', + 'Borja', + 'Begum', + 'Phifer', + 'Shoup', + 'Cawley', + 'Deason', + 'Castanon', + 'Loucks', + 'Hagler', + 'Mcclinton', + 'Dulaney', + 'Hargett', + 'Mcardle', + 'Burcham', + 'Philpot', + 'Laroche', + 'Breland', + 'Hatten', + 'Karp', + 'Brummett', + 'Boatman', + 'Natale', + 'Pepe', + 'Mortimer', + 'Sink', + 'Voyles', + 'Reeve', + 'Honaker', + 'Loredo', + 'Ridgway', + 'Donner', + 'Lessard', + 'Dever', + 'Salomon', + 'Hickson', + 'Nicholls', + 'Bushey', + 'Osteen', + 'Reavis', + 'Rodman', + 'Barahona', + 'Knecht', + 'Hinman', + 'Faria', + 'Dana', + 'Bancroft', + 'Hatchett', + 'Hageman', + 'Klaus', + 'Castor', + 'Lampkin', + 'Dalessandro', + 'Riffle', + 'Korn', + 'Savoie', + 'Sandifer', + 'Mciver', + 'Magill', + 'Delafuente', + 'Widener', + 'Vermillion', + 'Dandrea', + 'Mader', + 'Woodman', + 'Milan', + 'Hollowell', + 'Schaaf', + 'Kao', + 'Nail', + 'Beaman', + 'Hawkes', + 'Mclane', + 'Marchant', + 'Scanlan', + 'Syed', + 'Peabody', + 'Uhl', + 'Schauer', + 'Azevedo', + 'Wolcott', + 'Mick', + 'Melgar', + 'Pilcher', + 'Burgin', + 'Weiser', + 'Daughtry', + 'Theisen', + 'Babbitt', + 'Petry', + 'Cotten', + 'Fick', + 'Eubank', + 'Tolson', + 'Judkins', + 'Cronk', + 'Wendel', + 'Monteiro', + 'Kissinger', + 'Banta', + 'Senn', + 'Fix', + 'Brehm', + 'Rittenhouse', + 'Banner', + 'Elwell', + 'Herd', + 'Araiza', + 'Hui', + 'Nowell', + 'Brett', + 'Hua', + 'Breeding', + 'Pawlowski', + 'Thompkins', + 'Bocanegra', + 'Bosworth', + 'Dutcher', + 'Cotto', + 'Beecher', + 'Callender', + 'Hamlett', + 'Benfield', + 'Claudio', + 'Reel', + 'Brookshire', + 'Helmick', + 'Ryals', + 'Winder', + 'Thom', + 'Robin', + 'Overman', + 'Furtado', + 'Dacosta', + 'Paddock', + 'Dancy', + 'Carpio', + 'Manzanares', + 'Zito', + 'Favela', + 'Beckley', + 'Adrian', + 'Flory', + 'Nestor', + 'Spell', + 'Speight', + 'Strawn', + 'Beckner', + 'Gause', + 'Berglund', + 'Ruppert', + 'Mincey', + 'Spinelli', + 'Suzuki', + 'Mizell', + 'Kirksey', + 'Bolduc', + 'Kilmer', + 'Wesson', + 'Brinker', + 'Urrutia', + 'Markey', + 'Brenneman', + 'Haupt', + 'Sievers', + 'Puga', + 'Halloran', + 'Birdsong', + 'Stancil', + 'Wiener', + 'Calvo', + 'Macy', + 'Cairns', + 'Kahl', + 'Vice', + 'Ordaz', + 'Grow', + 'Lafrance', + 'Dryden', + 'Studer', + 'Matney', + 'Edward', + 'Rackley', + 'Gurrola', + 'Demoss', + 'Woolard', + 'Oquinn', + 'Hambrick', + 'Christmas', + 'Robey', + 'Crayton', + 'Haber', + 'Arango', + 'Newcomer', + 'Groom', + 'Corson', + 'Harness', + 'Rossman', + 'Slaton', + 'Schutz', + 'Conant', + 'Tedder', + 'Sabin', + 'Lowder', + 'Womble', + 'Jin', + 'Monday', + 'Garmon', + 'Aronson', + 'Skeen', + 'Headrick', + 'Lefevre', + 'Whittemore', + 'Pelton', + 'Barner', + 'Hildebrandt', + 'Rick', + 'Helmer', + 'Grose', + 'Zak', + 'Schroder', + 'Mahler', + 'Keeley', + 'Flinn', + 'Jordon', + 'Ozuna', + 'Sand', + 'Henkel', + 'Turcotte', + 'Vining', + 'Bellinger', + 'Neese', + 'Hagerman', + 'Mcmillin', + 'Gaylord', + 'Harney', + 'Milano', + 'Carothers', + 'Depew', + 'Bucci', + 'Pirtle', + 'Hafner', + 'Dimas', + 'Howlett', + 'Reber', + 'Abram', + 'Davalos', + 'Zajac', + 'Pedro', + 'Goodall', + 'Kaylor', + 'Wrenn', + 'Gartner', + 'Kell', + 'Curl', + 'Leathers', + 'Spiller', + 'Beason', + 'Shattuck', + 'Brewington', + 'Pinon', + 'Nazario', + 'Wash', + 'Ruggles', + 'Matz', + 'Capers', + 'Dorsett', + 'Wilmoth', + 'Bracey', + 'Lenhart', + 'Devoe', + 'Choy', + 'Oswalt', + 'Capone', + 'Wayman', + 'Parikh', + 'Eastwood', + 'Cofield', + 'Rickert', + 'Mccandless', + 'Greenway', + 'Majewski', + 'Rigdon', + 'Armbruster', + 'Royce', + 'Sterner', + 'Swaim', + 'Flournoy', + 'Amezcua', + 'Delano', + 'Westerman', + 'Grau', + 'Claxton', + 'Veliz', + 'Haun', + 'Roscoe', + 'Mccafferty', + 'Ringer', + 'Volz', + 'Blessing', + 'Mcphail', + 'Thelen', + 'Gagliardi', + 'Scholz', + 'Genovese', + 'Boyette', + 'Squire', + 'Naughton', + 'Levitt', + 'Erskine', + 'Leffler', + 'Manchester', + 'Hallett', + 'Whitmer', + 'Gillett', + 'Groce', + 'Roos', + 'Bejarano', + 'Moskowitz', + 'Constantine', + 'Fidler', + 'Roll', + 'Schutte', + 'Ohare', + 'Warnock', + 'Wester', + 'Macgregor', + 'Golding', + 'Abner', + 'Burgett', + 'Bushnell', + 'Brazil', + 'Ascencio', + 'Hock', + 'Legrand', + 'Eversole', + 'Rome', + 'Radcliff', + 'Fuhrman', + 'Schmit', + 'Tew', + 'Caro', + 'Cowen', + 'Marriott', + 'Kephart', + 'Hartung', + 'Keil', + 'Benally', + 'Hazlett', + 'Avant', + 'Desrosiers', + 'Kwong', + 'Guyer', + 'Penner', + 'Avelar', + 'Cashman', + 'Stith', + 'Orona', + 'Rager', + 'Johanson', + 'Lanza', + 'Min', + 'Cool', + 'Heine', + 'Nissen', + 'Buenrostro', + 'Mcmullin', + 'Oropeza', + 'Hom', + 'Degroot', + 'Wescott', + 'Hulbert', + 'Shrum', + 'Muncy', + 'Littrell', + 'Forest', + 'Dyke', + 'Garces', + 'Cimino', + 'Gebhardt', + 'Hickerson', + 'Satterwhite', + 'Radke', + 'Luckey', + 'Coronel', + 'Pugliese', + 'Frazee', + 'Siddiqui', + 'Flatt', + 'Abbey', + 'Gerald', + 'Bodine', + 'Lora', + 'Youngs', + 'Catlett', + 'Alexis', + 'Luo', + 'Youmans', + 'Sherlock', + 'Kinser', + 'Wales', + 'Dinsmore', + 'Abramson', + 'Stricker', + 'Rumsey', + 'Showers', + 'Mickens', + 'Tallent', + 'Setzer', + 'Etter', + 'Allgood', + 'Pagel', + 'Jefferies', + 'Bissell', + 'Colombo', + 'Musgrave', + 'Kuehl', + 'Raab', + 'Kavanagh', + 'Beane', + 'Witcher', + 'Pattison', + 'Paulus', + 'Gong', + 'Mcgough', + 'Burkhalter', + 'Vanbuskirk', + 'Kite', + 'Sass', + 'Lalonde', + 'Gormley', + 'Baier', + 'Brauer', + 'Stricklin', + 'Napoli', + 'Brotherton', + 'Stansbury', + 'Loggins', + 'Sorrentino', + 'Poff', + 'Nieman', + 'Roebuck', + 'Reiner', + 'Hovey', + 'Walley', + 'Leech', + 'Gambino', + 'Hammack', + 'Burson', + 'Tatro', + 'Perrine', + 'Carley', + 'Stadler', + 'Nason', + 'Peckham', + 'Gervais', + 'Ables', + 'Turman', + 'Dore', + 'Peavy', + 'Addington', + 'Tobar', + 'Gilstrap', + 'Brumbaugh', + 'Gerhardt', + 'Slusher', + 'Nevins', + 'Garofalo', + 'Amick', + 'Barrick', + 'Race', + 'Daggett', + 'Manion', + 'Noah', + 'Kranz', + 'Runge', + 'Wysocki', + 'Gillum', + 'Verduzco', + 'Alvey', + 'Pettus', + 'Sim', + 'Cage', + 'Mckean', + 'Harrod', + 'Weatherspoon', + 'Takahashi', + 'Wingard', + 'Endres', + 'Skiles', + 'Wald', + 'Finger', + 'Reams', + 'Ussery', + 'Fricke', + 'Jaworski', + 'Cusick', + 'Stanek', + 'Shaner', + 'Massaro', + 'Ribeiro', + 'Eades', + 'Rue', + 'Scharf', + 'Standridge', + 'Wojciechowski', + 'Victoria', + 'Galbreath', + 'Lander', + 'Martinelli', + 'Raper', + 'Karas', + 'Tomas', + 'La', + 'Kizer', + 'Gastelum', + 'Delp', + 'Sansone', + 'Therrien', + 'Brookins', + 'Shi', + 'Hammel', + 'Polley', + 'Riddell', + 'Claiborne', + 'Lampe', + 'Benham', + 'Braddock', + 'Elwood', + 'Mcminn', + 'Amerson', + 'Leija', + 'Gambrell', + 'Nuno', + 'Mallon', + 'Gard', + 'Burford', + 'Halley', + 'Maley', + 'Eicher', + 'Caban', + 'Rubenstein', + 'Tighe', + 'Harbaugh', + 'Bergmann', + 'Runnels', + 'Carrizales', + 'Gustin', + 'Wight', + 'Dominick', + 'Cannady', + 'Brace', + 'Beauregard', + 'Weitzel', + 'Orcutt', + 'Abrahamson', + 'Jorge', + 'Mccown', + 'Harriman', + 'Nicol', + 'Gott', + 'Andino', + 'Tsosie', + 'Shumway', + 'Aucoin', + 'Bowes', + 'Hixon', + 'Broom', + 'Cate', + 'Desantiago', + 'Haug', + 'Pinedo', + 'Mowry', + 'Moyers', + 'Deangelo', + 'Mcshane', + 'Boley', + 'Tiffany', + 'Steger', + 'Woodford', + 'Whitford', + 'Collette', + 'Muth', + 'Mansour', + 'Schuh', + 'Fortney', + 'Khoury', + 'Livengood', + 'Haworth', + 'Rusk', + 'Mathieu', + 'Peppers', + 'Gehring', + 'Faris', + 'Diep', + 'Rae', + 'Hupp', + 'Escalera', + 'Gwin', + 'Engelhardt', + 'Bannon', + 'Menjivar', + 'Eberhart', + 'Kershaw', + 'Cottle', + 'Palomares', + 'Carrell', + 'Galaviz', + 'Willie', + 'Troxell', + 'Visser', + 'Xie', + 'Juan', + 'Spector', + 'Izzo', + 'Woodring', + 'Gilbreath', + 'Bey', + 'Giraldo', + 'Neary', + 'Ready', + 'Toland', + 'Benge', + 'Thrower', + 'Bemis', + 'Hostetter', + 'Dull', + 'Poulos', + 'Vanegas', + 'Abad', + 'Harker', + 'Mei', + 'Nigro', + 'Messner', + 'Peres', + 'Hardaway', + 'Crumpton', + 'Dingman', + 'Hipp', + 'Lemley', + 'Maloy', + 'Ye', + 'Neighbors', + 'Proulx', + 'Jamerson', + 'Finkelstein', + 'Payan', + 'Holler', + 'Simonds', + 'Toms', + 'Schulman', + 'Aguero', + 'Hinrichs', + 'Steffens', + 'Clapper', + 'Delao', + 'Knighton', + 'Jahn', + 'Mach', + 'Heal', + 'Detwiler', + 'Corso', + 'Toner', + 'Rook', + 'Brockway', + 'Coulson', + 'Delia', + 'Giddings', + 'Hermosillo', + 'Ballenger', + 'Persinger', + 'Delk', + 'Pedigo', + 'Burg', + 'Voelker', + 'Ecker', + 'Kile', + 'Propst', + 'Rascon', + 'Stultz', + 'Swindle', + 'Swindell', + 'Deaver', + 'Welty', + 'Sussman', + 'Southworth', + 'Child', + 'Coston', + 'Lei', + 'Spillman', + 'Hochstetler', + 'Veach', + 'Melcher', + 'Chipman', + 'Lebeau', + 'Summerville', + 'Peden', + 'Lizarraga', + 'Kingery', + 'Leos', + 'Fogel', + 'Eckman', + 'Burbank', + 'Castano', + 'Chartier', + 'Medellin', + 'Torrey', + 'Peake', + 'Swinney', + 'Aziz', + 'Reinert', + 'Borg', + 'Pires', + 'Brooke', + 'Forester', + 'Greaves', + 'Delapaz', + 'Hunnicutt', + 'Bierman', + 'Stringfellow', + 'Lavallee', + 'Farnham', + 'Gadson', + 'Gainer', + 'Kulp', + 'Liston', + 'Brooker', + 'Loudermilk', + 'Reza', + 'Henshaw', + 'Hinz', + 'Brammer', + 'Frisch', + 'Toombs', + 'Esquibel', + 'Feinberg', + 'Plaza', + 'Bly', + 'Encarnacion', + 'Cockerham', + 'Shealy', + 'Haile', + 'Nave', + 'Chenoweth', + 'Goto', + 'Ernest', + 'Staub', + 'Marty', + 'Huizar', + 'Lammers', + 'Mcavoy', + 'Dishman', + 'Giroux', + 'Dowdell', + 'Via', + 'Fenn', + 'Kain', + 'Breckenridge', + 'Egbert', + 'Steelman', + 'Gasper', + 'Riojas', + 'Parmer', + 'Creed', + 'Gillispie', + 'Edgerton', + 'Yen', + 'Calder', + 'Holmberg', + 'Kreider', + 'Landau', + 'Eley', + 'Lewallen', + 'Quimby', + 'Holladay', + 'Du', + 'Leland', + 'Hyder', + 'Omeara', + 'Acton', + 'Gaspard', + 'Kennard', + 'Renfroe', + 'Hayman', + 'Gladney', + 'Glidden', + 'Wilmot', + 'Pearsall', + 'Cahoon', + 'Hallock', + 'Grigg', + 'Boggess', + 'Lewin', + 'Doering', + 'Thach', + 'Mcatee', + 'Paulk', + 'Rusch', + 'Harrold', + 'Suttles', + 'Chiles', + 'Sawyers', + 'Roger', + 'Kwok', + 'Luevano', + 'Coelho', + 'Waldo', + 'Ewell', + 'Lagunas', + 'Rude', + 'Barrington', + 'Mccomas', + 'Whiteley', + 'Jeanbaptiste', + 'Darcy', + 'Lussier', + 'Kerley', + 'Fordham', + 'Moorehead', + 'Welton', + 'Nicely', + 'Constantino', + 'Townes', + 'Giglio', + 'Damian', + 'Mckibben', + 'Resnick', + 'Endicott', + 'Lindeman', + 'Killion', + 'Gwinn', + 'Beaumont', + 'Nord', + 'Miceli', + 'Fast', + 'Bidwell', + 'Sites', + 'Drum', + 'Maze', + 'Abshire', + 'Berner', + 'Rhyne', + 'Juliano', + 'Wortman', + 'Beggs', + 'Winchell', + 'Summerlin', + 'Thrash', + 'Biggers', + 'Buckles', + 'Barnwell', + 'Thomasson', + 'Wan', + 'Arneson', + 'Rodrigue', + 'Wroblewski', + 'Quiroga', + 'Fulk', + 'Dillingham', + 'Rone', + 'Mapp', + 'Sattler', + 'Letourneau', + 'Gaudet', + 'Mccaslin', + 'Gurule', + 'Huck', + 'Hudspeth', + 'Welter', + 'Wittman', + 'Hileman', + 'Ewald', + 'Yao', + 'Kindred', + 'Kato', + 'Nickels', + 'Tyndall', + 'Sanmiguel', + 'Mayle', + 'Alfano', + 'Eichelberger', + 'Bee', + 'Sheehy', + 'Rogan', + 'Philip', + 'Dilworth', + 'Midkiff', + 'Hudgens', + 'Killingsworth', + 'Russel', + 'Criss', + 'Liddell', + 'Eberly', + 'Khalil', + 'Lattimore', + 'Koval', + 'Maxson', + 'Schram', + 'Goodell', + 'Catlin', + 'Cofer', + 'Alva', + 'Sandler', + 'Kunkle', + 'Perron', + 'Bushman', + 'Edmonson', + 'Roa', + 'Nesbit', + 'Ahearn', + 'Garver', + 'Bible', + 'Barley', + 'Struble', + 'Oxford', + 'Wulf', + 'Marron', + 'Haught', + 'Bonnell', + 'Pigg', + 'Friel', + 'Almaguer', + 'Bowler', + 'Mitchem', + 'Fussell', + 'Lemos', + 'Savino', + 'Boisvert', + 'Torgerson', + 'Annis', + 'Dicks', + 'Ruhl', + 'Pepin', + 'Wildman', + 'Gendron', + 'Melanson', + 'Sherer', + 'Duty', + 'Cassel', + 'Croteau', + 'Rolon', + 'Staats', + 'Pass', + 'Larocca', + 'Sauter', + 'Sacks', + 'Boutwell', + 'Hunsaker', + 'Omara', + 'Mcbroom', + 'Lohman', + 'Treat', + 'Dufour', + 'Brashear', + 'Yepez', + 'Lao', + 'Telles', + 'Manis', + 'Mars', + 'Shilling', + 'Tingle', + 'Macaluso', + 'Rigney', + 'Clair', + 'Matsumoto', + 'Agosto', + 'Halbert', + 'Dabbs', + 'Eckstein', + 'Mercurio', + 'Berkley', + 'Wachter', + 'Langan', + 'Peach', + 'Carreno', + 'Lepore', + 'Howie', + 'Thaxton', + 'Arrowood', + 'Weinberger', + 'Eldred', + 'Hooten', + 'Raymer', + 'Feaster', + 'Bosco', + 'Cataldo', + 'Fears', + 'Eckhardt', + 'Mullinax', + 'Spratt', + 'Laboy', + 'Marsden', + 'Carlile', + 'Bustillos', + 'Crim', + 'Surratt', + 'Kurth', + 'Gaul', + 'Machuca', + 'Rolfe', + 'Lower', + 'Edmiston', + 'Millsap', + 'Dehaven', + 'Racine', + 'Coney', + 'Rinker', + 'Maddux', + 'Burmeister', + 'Fenwick', + 'Stocks', + 'Forde', + 'Pettway', + 'Balderrama', + 'Westover', + 'Bloch', + 'Burress', + 'Hunley', + 'Futch', + 'Chee', + 'Alvarenga', + 'Bostwick', + 'Cleaver', + 'Pelkey', + 'Bryce', + 'Pisano', + 'Qureshi', + 'Varghese', + 'Cunha', + 'Hellman', + 'Grass', + 'Luker', + 'Hazelton', + 'Cathcart', + 'Yamada', + 'Gallego', + 'Menke', + 'Yingling', + 'Merriweather', + 'Fleury', + 'Salmeron', + 'Metcalfe', + 'Brook', + 'Freitag', + 'Malek', + 'Obregon', + 'Blain', + 'Mellott', + 'Alam', + 'Bessette', + 'Moncrief', + 'Arvizu', + 'Botts', + 'Moorer', + 'Landreth', + 'Hulett', + 'Marinelli', + 'Falco', + 'Silvestri', + 'Gottschalk', + 'Thiele', + 'Kight', + 'Warrington', + 'Huckaby', + 'Ledet', + 'Charbonneau', + 'Crozier', + 'Mohan', + 'Stroh', + 'Bolinger', + 'Delvecchio', + 'Macfarlane', + 'Cribbs', + 'Mcloughlin', + 'Maynor', + 'Ming', + 'Digiovanni', + 'Truesdale', + 'Pfeffer', + 'Benn', + 'Chaparro', + 'Englert', + 'Spano', + 'Ogletree', + 'Yancy', + 'Swick', + 'Hallmark', + 'Mattern', + 'Tryon', + 'Plumb', + 'Martineau', + 'Man', + 'Grube', + 'Holst', + 'Nez', + 'Belden', + 'Aikens', + 'Litton', + 'Moorhead', + 'Dufresne', + 'Bonney', + 'Heyward', + 'Halliday', + 'Ito', + 'Crossman', + 'Gast', + 'Levan', + 'Wine', + 'Desouza', + 'Kornegay', + 'Nam', + 'Keough', + 'Stotts', + 'Dickenson', + 'Ousley', + 'Leduc', + 'Revels', + 'Dizon', + 'Arreguin', + 'Shockey', + 'Alegria', + 'Blades', + 'Ignacio', + 'Mellon', + 'Ebersole', + 'Sain', + 'Weissman', + 'Wargo', + 'Claypool', + 'Zorn', + 'Julien', + 'Hinshaw', + 'Alberto', + 'Garduno', + 'Kellar', + 'Rizo', + 'Labonte', + 'Humble', + 'Downer', + 'Lykins', + 'Tower', + 'Vanhouten', + 'Chairez', + 'Campa', + 'Blizzard', + 'Standley', + 'Reiser', + 'Whitener', + 'Menefee', + 'Nalley', + 'Lasher', + 'Strang', + 'Smock', + 'Moralez', + 'Kiel', + 'Moffatt', + 'Behm', + 'Hackworth', + 'Dirks', + 'Kratz', + 'Guillot', + 'Tittle', + 'Stlouis', + 'Seymore', + 'Searle', + 'Utter', + 'Wilborn', + 'Dortch', + 'Duron', + 'Cardinal', + 'Spikes', + 'Arambula', + 'Cutter', + 'Dibenedetto', + 'Botelho', + 'Bedwell', + 'Kilby', + 'Bottoms', + 'Cassady', + 'Rothwell', + 'Bilodeau', + 'Markowitz', + 'Baucom', + 'Valley', + 'Esqueda', + 'Depalma', + 'Laskowski', + 'Hopp', + 'Casale', + 'Perreault', + 'Shuster', + 'Wolter', + 'Raby', + 'Cyrus', + 'Tseng', + 'Georges', + 'Das', + 'Wilfong', + 'Schlueter', + 'Woolf', + 'Stickney', + 'Mcinerney', + 'Curcio', + 'Fowlkes', + 'Boldt', + 'Zander', + 'Shropshire', + 'Antonelli', + 'Froehlich', + 'Butterworth', + 'Stedman', + 'Broadnax', + 'Kroeger', + 'Kellner', + 'Monreal', + 'Armas', + 'Mcguinness', + 'Canterbury', + 'Weisman', + 'Hilburn', + 'Carruthers', + 'Pell', + 'Peele', + 'Devaney', + 'Owings', + 'Mar', + 'Liggett', + 'Breslin', + 'Soucy', + 'Aguila', + 'Weidman', + 'Mingo', + 'Tarango', + 'Winger', + 'Poteet', + 'Acree', + 'Mcnew', + 'Leatherwood', + 'Aubrey', + 'Waring', + 'Soler', + 'Roof', + 'Sunderland', + 'Blackford', + 'Rabe', + 'Hepler', + 'Leonardo', + 'Spina', + 'Smythe', + 'Alex', + 'Barta', + 'Bybee', + 'Campagna', + 'Pete', + 'Batchelder', + 'Gurney', + 'Wyche', + 'Schutt', + 'Rashid', + 'Almazan', + 'Pahl', + 'Perri', + 'Viramontes', + 'Cavender', + 'Snapp', + 'Newson', + 'Sandhu', + 'Fernando', + 'Stockdale', + 'Garfield', + 'Ealy', + 'Mcfarlin', + 'Bieber', + 'Callan', + 'Arruda', + 'Oquendo', + 'Levasseur', + 'Maple', + 'Kowal', + 'Kushner', + 'Naquin', + 'Shouse', + 'Mcquade', + 'Cai', + 'Smedley', + 'Gober', + 'Saiz', + 'Brunelle', + 'Arbuckle', + 'Landes', + 'Mak', + 'Korte', + 'Oxley', + 'Boger', + 'Mickey', + 'Lent', + 'Cureton', + 'Husted', + 'Eidson', + 'Boyett', + 'Kitts', + 'Shope', + 'Hance', + 'Jessen', + 'Litchfield', + 'Torre', + 'Cargill', + 'Herren', + 'Straight', + 'Merz', + 'Weese', + 'Sperling', + 'Lapierre', + 'Yung', + 'Doggett', + 'Cauley', + 'Hardeman', + 'Margolis', + 'Watford', + 'Seltzer', + 'Fullmer', + 'Timberlake', + 'Butz', + 'Duquette', + 'Olin', + 'Leverett', + 'Hartford', + 'Otte', + 'Beaton', + 'Grimaldi', + 'Marotta', + 'Carlsen', + 'Cullum', + 'Monte', + 'Haygood', + 'Middlebrooks', + 'Lazarus', + 'Shiver', + 'Ivie', + 'Niemi', + 'Lacombe', + 'Judson', + 'Ginsberg', + 'Firestone', + 'Izquierdo', + 'Deel', + 'Jacinto', + 'Towers', + 'Fritsch', + 'Albin', + 'Kaminsky', + 'Yin', + 'Wrobel', + 'Birdwell', + 'Krieg', + 'Danforth', + 'Florio', + 'Saito', + 'Clift', + 'Duck', + 'Matt', + 'Moxley', + 'Barbieri', + 'Klatt', + 'Saltzman', + 'Chesney', + 'Bojorquez', + 'Cosentino', + 'Lodge', + 'Converse', + 'Decastro', + 'Gerhart', + 'Music', + 'Danley', + 'Santangelo', + 'Bevins', + 'Coen', + 'Seibel', + 'Lindemann', + 'Dressler', + 'Newport', + 'Bedolla', + 'Lillie', + 'Rhone', + 'Penaloza', + 'Swart', + 'Niemeyer', + 'Pilkington', + 'Matta', + 'Hollifield', + 'Gillman', + 'Montana', + 'Maroney', + 'Stenger', + 'Loos', + 'Wert', + 'Brogdon', + 'Gandhi', + 'Bent', + 'Tabb', + 'Sikorski', + 'Hagedorn', + 'Hannigan', + 'Hoss', + 'Conlin', + 'Trott', + 'Fall', + 'Granado', + 'Bartell', + 'Rubalcava', + 'Neves', + 'Poynter', + 'Alton', + 'Paschall', + 'Waltman', + 'Parke', + 'Kittle', + 'Czarnecki', + 'Bloodworth', + 'Knorr', + 'Timms', + 'Derry', + 'Messier', + 'Saad', + 'Cozart', + 'Sutphin', + 'Puryear', + 'Gatto', + 'Whitacre', + 'Verdin', + 'Bloomer', + 'Brundage', + 'Brian', + 'Seger', + 'Clare', + 'Balch', + 'Tharpe', + 'Rayford', + 'Halter', + 'Barefoot', + 'Gonsalez', + 'Lomas', + 'Monzon', + 'Howarth', + 'Mccready', + 'Gudino', + 'Serafin', + 'Sanfilippo', + 'Minnich', + 'Eldredge', + 'Malave', + 'Greeley', + 'Sisneros', + 'Kangas', + 'Peery', + 'Lunn', + 'Lukas', + 'Bunce', + 'Riccio', + 'Thies', + 'Stivers', + 'Conard', + 'Mullaney', + 'Catalan', + 'Omar', + 'Theobald', + 'Jeffcoat', + 'Kucera', + 'Borkowski', + 'Coomer', + 'Mathison', + 'Croom', + 'Rushton', + 'Stites', + 'Pendley', + 'Till', + 'Oconner', + 'Forsberg', + 'Wages', + 'Fillmore', + 'Barcenas', + 'Gillard', + 'Leak', + 'Towle', + 'Esser', + 'Dunlop', + 'Quackenbush', + 'Archambault', + 'Buller', + 'Newlin', + 'Urquhart', + 'Shanley', + 'Mote', + 'Ippolito', + 'Rozier', + 'Reidy', + 'Gregor', + 'Swaney', + 'Bradfield', + 'Fudge', + 'More', + 'Tester', + 'Higley', + 'Dambrosio', + 'Bullington', + 'Highsmith', + 'Silas', + 'Felker', + 'Sawicki', + 'Beltz', + 'Albarran', + 'Aitken', + 'Findlay', + 'Looper', + 'Tooley', + 'Lasley', + 'Moynihan', + 'Ratcliffe', + 'Grizzle', + 'Souders', + 'Nussbaum', + 'Suber', + 'Macdougall', + 'Waddle', + 'Brawner', + 'Tucci', + 'Cosme', + 'Walk', + 'Gordy', + 'Tarrant', + 'Rosenblum', + 'Huth', + 'Bridgeman', + 'Hinkley', + 'Gehrke', + 'Boden', + 'Suazo', + 'Gambill', + 'Widner', + 'Chick', + 'Mccollough', + 'Hassler', + 'Odum', + 'Pawlak', + 'Prevost', + 'Slavin', + 'Fetters', + 'Beamon', + 'Renshaw', + 'Deng', + 'Plourde', + 'Holstein', + 'Rye', + 'Holliman', + 'Melville', + 'Messinger', + 'Turcios', + 'Garnica', + 'Feeley', + 'Mariani', + 'Otten', + 'Dorado', + 'Mortenson', + 'Meissner', + 'Scarlett', + 'Sweitzer', + 'Glisson', + 'Desjardins', + 'Penland', + 'Elledge', + 'Crumley', + 'Deen', + 'Shih', + 'Heuer', + 'Gloria', + 'Lail', + 'Mcandrew', + 'Mcnaughton', + 'Cortese', + 'Stgermain', + 'Hammon', + 'Leininger', + 'Flickinger', + 'Dement', + 'Bumgardner', + 'Tessier', + 'Fulford', + 'Cervantez', + 'Wisner', + 'Shulman', + 'Sabol', + 'Papp', + 'Strasser', + 'Sartin', + 'Rothstein', + 'Grote', + 'Beaudry', + 'Deville', + 'Roop', + 'Villar', + 'Bussell', + 'Bowyer', + 'Yoshida', + 'Hertz', + 'Countryman', + 'Hoey', + 'Roseberry', + 'Schock', + 'Boozer', + 'Mccowan', + 'Kirschner', + 'Lechner', + 'Winkelman', + 'Witham', + 'Thurber', + 'Depriest', + 'Chenault', + 'Moten', + 'Tillotson', + 'Guan', + 'Ketcham', + 'Jiles', + 'Grosso', + 'Nottingham', + 'Kellam', + 'Alejo', + 'Thoma', + 'Marchetti', + 'Holifield', + 'Fortson', + 'Leasure', + 'Mceachern', + 'Oceguera', + 'Carleton', + 'Weekley', + 'Kinsella', + 'Harvell', + 'Waldon', + 'Kean', + 'Chancellor', + 'Blosser', + 'Detweiler', + 'Presnell', + 'Beachy', + 'Lingle', + 'Plumley', + 'Knopp', + 'Gamache', + 'Atwater', + 'Caine', + 'Woodland', + 'Terwilliger', + 'Moller', + 'Cleland', + 'Cottingham', + 'Janke', + 'Willman', + 'Dann', + 'Mangrum', + 'Shuck', + 'Paden', + 'Adelman', + 'Brim', + 'Tullis', + 'Hertel', + 'Gallaher', + 'Leopold', + 'Donegan', + 'Popovich', + 'Gusman', + 'Chatham', + 'Schooley', + 'Pinder', + 'Heise', + 'Maines', + 'Nystrom', + 'Jahnke', + 'Poon', + 'Murphree', + 'Pelaez', + 'Risley', + 'Sohn', + 'Shim', + 'Armentrout', + 'Kastner', + 'Philpott', + 'Mao', + 'Pursley', + 'Mangold', + 'Mccourt', + 'Hollar', + 'Desmarais', + 'Debord', + 'Gullett', + 'Gaeta', + 'Bae', + 'Houlihan', + 'Gorton', + 'Steinman', + 'Santo', + 'Snelling', + 'Corpuz', + 'Look', + 'Scudder', + 'Treece', + 'Binns', + 'Sokolowski', + 'Harner', + 'Gallup', + 'Marti', + 'Teasley', + 'Markel', + 'Casiano', + 'Nicks', + 'Recinos', + 'Paradise', + 'Colman', + 'Orange', + 'Mele', + 'Medford', + 'Templin', + 'Zuber', + 'Mackin', + 'Brodsky', + 'Householder', + 'Wirtz', + 'Hackman', + 'Tippett', + 'Polson', + 'Colston', + 'Cerna', + 'Herald', + 'Shults', + 'Shubert', + 'Mertens', + 'Dave', + 'Duffield', + 'Vanness', + 'Mayne', + 'Driskell', + 'Percy', + 'Lauderdale', + 'Cipriano', + 'Theodore', + 'Colella', + 'Kiger', + 'Brownfield', + 'Stella', + 'Wideman', + 'Maye', + 'Chisolm', + 'Muldoon', + 'Fitzwater', + 'Harville', + 'Dixson', + 'Burkey', + 'Hartsfield', + 'Schade', + 'Brawley', + 'Pelfrey', + 'Tennyson', + 'Whitted', + 'Silvas', + 'Harbour', + 'Krupa', + 'Peraza', + 'Erdmann', + 'Halpern', + 'Finnerty', + 'Mackinnon', + 'Humbert', + 'Mccarley', + 'Doster', + 'Kugler', + 'Livesay', + 'Force', + 'Haberman', + 'Lamp', + 'Hector', + 'Charron', + 'Woosley', + 'Rein', + 'Ashburn', + 'Greenleaf', + 'Niemann', + 'Carillo', + 'Skelly', + 'Nunnally', + 'Renfrow', + 'Prickett', + 'Angus', + 'Bednar', + 'Nightingale', + 'Steinbach', + 'Warnick', + 'Jason', + 'Hans', + 'Lydon', + 'Rutland', + 'Alleman', + 'Hawn', + 'Malin', + 'Beech', + 'Auger', + 'Desilva', + 'Izaguirre', + 'Isham', + 'Mandujano', + 'Glasser', + 'Dimarco', + 'Berumen', + 'Nipper', + 'Pegram', + 'Sundberg', + 'Labbe', + 'Mcphee', + 'Crafton', + 'Agustin', + 'Cantor', + 'Beller', + 'Bang', + 'Lawyer', + 'Croy', + 'Kyles', + 'Winans', + 'Battista', + 'Jost', + 'Bakken', + 'Dandridge', + 'Mustafa', + 'Ice', + 'Eklund', + 'Montesdeoca', + 'Hermes', + 'Grimaldo', + 'Vannoy', + 'Grainger', + 'Lamas', + 'Tarantino', + 'Witter', + 'Worthen', + 'Basinger', + 'Cowden', + 'Hiles', + 'Mcanally', + 'Felipe', + 'Gallimore', + 'Kapp', + 'Makowski', + 'Copenhaver', + 'Ramer', + 'Gideon', + 'Bowker', + 'Wilkens', + 'Seeger', + 'Huntsman', + 'Palladino', + 'Jessee', + 'Kittrell', + 'Rolle', + 'Ciccone', + 'Kolar', + 'Brannen', + 'Bixby', + 'Pohlman', + 'Strachan', + 'Lesher', + 'Fleischer', + 'Umana', + 'Murphey', + 'Mcentire', + 'Rabon', + 'Mcauley', + 'Bunton', + 'Soileau', + 'Sheriff', + 'Borowski', + 'Mullens', + 'Larrabee', + 'Prouty', + 'Malley', + 'Sumrall', + 'Reisinger', + 'Surber', + 'Kasten', + 'Shoemake', + 'Yowell', + 'Bonin', + 'Bevan', + 'Bove', + 'Boe', + 'Hazard', + 'Slay', + 'Carraway', + 'Kaczmarek', + 'Armitage', + 'Lowther', + 'Sheaffer', + 'Farah', + 'Atencio', + 'Ung', + 'Kirkham', + 'Cavanagh', + 'Mccutchen', + 'Shoop', + 'Nickles', + 'Borchardt', + 'Durkee', + 'Maus', + 'Shedd', + 'Petrillo', + 'Brainard', + 'Eddings', + 'Fanelli', + 'Seo', + 'Heaney', + 'Drennan', + 'Mcgarvey', + 'Saddler', + 'Lucia', + 'Higa', + 'Gailey', + 'Groh', + 'Hinckley', + 'Griner', + 'Norfleet', + 'Caplan', + 'Rademacher', + 'Souder', + 'Autrey', + 'Eskridge', + 'Drumm', + 'Fiske', + 'Giffin', + 'Townley', + 'Derose', + 'Burrus', + 'Castrejon', + 'Emmert', + 'Cothran', + 'Hartsell', + 'Kilburn', + 'Riggle', + 'Trussell', + 'Mulvey', + 'Barto', + 'Crank', + 'Lovely', + 'Woodhouse', + 'Powe', + 'Pablo', + 'Zack', + 'Murchison', + 'Dicarlo', + 'Kessel', + 'Hagood', + 'Rost', + 'Edson', + 'Blakeney', + 'Fant', + 'Brodeur', + 'Jump', + 'Spry', + 'Laguna', + 'Lotz', + 'Bergquist', + 'Collard', + 'Mash', + 'Rideout', + 'Bilbrey', + 'Selman', + 'Fortunato', + 'Holzer', + 'Pifer', + 'Mcabee', + 'Talamantes', + 'Tollefson', + 'Pastore', + 'Crew', + 'Wilcher', + 'Kutz', + 'Stallard', + 'Ressler', + 'Fehr', + 'Piercy', + 'Lafond', + 'Digiacomo', + 'Schuck', + 'Winkle', + 'Graybill', + 'Plata', + 'Gribble', + 'Odle', + 'Fraga', + 'Bressler', + 'Moultrie', + 'Tung', + 'Charette', + 'Marvel', + 'Kerby', + 'Mori', + 'Hamman', + 'Favors', + 'Freeze', + 'Delisle', + 'Straw', + 'Dingle', + 'Elizalde', + 'Cabello', + 'Zalewski', + 'Funkhouser', + 'Abate', + 'Nero', + 'Holston', + 'Josey', + 'Schreck', + 'Shroyer', + 'Paquin', + 'Bing', + 'Chauvin', + 'Maria', + 'Melgoza', + 'Arms', + 'Caddell', + 'Pitchford', + 'Sternberg', + 'Rana', + 'Lovelady', + 'Strouse', + 'Macarthur', + 'Lechuga', + 'Wolfson', + 'Mcglynn', + 'Koo', + 'Stoops', + 'Tetreault', + 'Lepage', + 'Duren', + 'Hartz', + 'Kissel', + 'Gish', + 'Largent', + 'Henninger', + 'Janson', + 'Carrick', + 'Kenner', + 'Haack', + 'Diego', + 'Wacker', + 'Wardell', + 'Ballentine', + 'Smeltzer', + 'Bibb', + 'Winton', + 'Bibbs', + 'Reinhard', + 'Nilsen', + 'Edison', + 'Kalinowski', + 'June', + 'Hewlett', + 'Blaisdell', + 'Zeman', + 'Chon', + 'Board', + 'Nealy', + 'Moretti', + 'Wanner', + 'Bonnett', + 'Hardie', + 'Mains', + 'Cordeiro', + 'Karim', + 'Kautz', + 'Craver', + 'Colucci', + 'Congdon', + 'Mounts', + 'Kurz', + 'Eder', + 'Merryman', + 'Soles', + 'Dulin', + 'Lubin', + 'Mcgowen', + 'Hockenberry', + 'Work', + 'Mazzola', + 'Crandell', + 'Mcgrady', + 'Caruthers', + 'Govea', + 'Meng', + 'Fetter', + 'Trusty', + 'Weintraub', + 'Hurlburt', + 'Reiff', + 'Nowakowski', + 'Hoard', + 'Densmore', + 'Blumenthal', + 'Neale', + 'Schiff', + 'Raleigh', + 'Steiger', + 'Marmolejo', + 'Jessie', + 'Palafox', + 'Tutt', + 'Keister', + 'Core', + 'Im', + 'Wendell', + 'Bennet', + 'Canning', + 'Krull', + 'Patti', + 'Zucker', + 'Schlesinger', + 'Wiser', + 'Dunson', + 'Olmedo', + 'Hake', + 'Champlin', + 'Braley', + 'Wheelock', + 'Geier', + 'Janis', + 'Turek', + 'Grindstaff', + 'Schaffner', + 'Deas', + 'Sirois', + 'Polito', + 'Bergin', + 'Schall', + 'Vineyard', + 'Pellegrini', + 'Corrado', + 'Oleson', + 'List', + 'Dameron', + 'Parkin', + 'Flake', + 'Hollingshead', + 'Chancey', + 'Hufford', + 'Morell', + 'Kantor', + 'Chasteen', + 'Laborde', + 'Sessoms', + 'Hermanson', + 'Burnell', + 'Dewberry', + 'Tolman', + 'Glasscock', + 'Durfee', + 'Gilroy', + 'Wilkey', + 'Dungan', + 'Saravia', + 'Weigand', + 'Bigler', + 'Vancleave', + 'Burlingame', + 'Roseman', + 'Stiffler', + 'Gagliano', + 'Kates', + 'Awad', + 'Knepp', + 'Rondeau', + 'Bertsch', + 'Wolverton', + 'Walcott', + 'Poss', + 'Frisby', + 'Wexler', + 'Reinhold', + 'Krol', + 'Stuck', + 'Ricciardi', + 'Ardoin', + 'Michaelson', + 'Lillard', + 'Burciaga', + 'Birchfield', + 'Patch', + 'Silvey', + 'Simmonds', + 'Siu', + 'Press', + 'Deans', + 'Riegel', + 'Ismail', + 'Magallon', + 'Diller', + 'Hine', + 'Michalak', + 'Dones', + 'Deitz', + 'Gulledge', + 'Stroman', + 'Kobayashi', + 'Hafer', + 'Berk', + 'Landin', + 'Gilles', + 'Obryant', + 'Cheeks', + 'Gress', + 'Lutes', + 'Raphael', + 'Pizano', + 'Bachmann', + 'Cifuentes', + 'Earp', + 'Gilreath', + 'Peluso', + 'Hubbs', + 'Alvis', + 'Peer', + 'Dutra', + 'Stetson', + 'Constant', + 'Benford', + 'Sorto', + 'Cater', + 'Rosier', + 'Isenberg', + 'Shanklin', + 'Veloz', + 'Ramage', + 'Dunford', + 'Ku', + 'Hames', + 'Eddins', + 'Ruano', + 'Frink', + 'Flower', + 'Beadle', + 'Rochester', + 'Fontes', + 'Mefford', + 'Barwick', + 'Millen', + 'Stelly', + 'Cann', + 'Rayner', + 'Carruth', + 'Wendling', + 'Shutt', + 'Hazzard', + 'Maravilla', + 'Gregorio', + 'Pavlik', + 'Hudnall', + 'Aston', + 'Mcglothlin', + 'Weise', + 'Devereaux', + 'Belle', + 'Borst', + 'Burdett', + 'Frisbie', + 'Rummel', + 'Rentz', + 'Cobos', + 'Kimura', + 'Neu', + 'Winner', + 'Candelario', + 'Callis', + 'Basso', + 'Mckim', + 'Tai', + 'Eskew', + 'Lair', + 'Pye', + 'Knuth', + 'Scarberry', + 'Alter', + 'Mcgann', + 'Anson', + 'Drews', + 'Zuckerman', + 'Petrone', + 'Ludlow', + 'Bechtold', + 'Nair', + 'Rennie', + 'Rhine', + 'Fleetwood', + 'Sudduth', + 'Leftwich', + 'Hardiman', + 'Northrop', + 'Banker', + 'Killen', + 'Mastin', + 'Mcmurry', + 'Jasinski', + 'Taliaferro', + 'Mathers', + 'Sheikh', + 'Nuss', + 'Jesse', + 'Zabel', + 'Crotty', + 'Kamp', + 'Fleenor', + 'Halcomb', + 'Eady', + 'Vella', + 'Demars', + 'Ensley', + 'Delosreyes', + 'Zendejas', + 'Leeds', + 'Just', + 'Oday', + 'Dills', + 'Zeng', + 'Barriga', + 'Millican', + 'Cascio', + 'Eakin', + 'Argo', + 'Borland', + 'Cover', + 'Diorio', + 'Coria', + 'Lease', + 'Pinkham', + 'Reichard', + 'Guadalupe', + 'Hansel', + 'Bye', + 'Westerfield', + 'Gales', + 'Mickle', + 'Licata', + 'Cram', + 'Bracy', + 'Motta', + 'Imhoff', + 'Siegfried', + 'Merry', + 'Swiger', + 'Ton', + 'Hersey', + 'Marrone', + 'Ginter', + 'Miele', + 'Breton', + 'Scheffler', + 'Pray', + 'Stapp', + 'Bogard', + 'Towner', + 'Mcelhaney', + 'Bridgewater', + 'Waldner', + 'Quijano', + 'Galante', + 'Quesenberry', + 'Rourke', + 'Harshman', + 'Traver', + 'Alvares', + 'Mcgaha', + 'Nyberg', + 'Pharr', + 'Lerch', + 'Sok', + 'Rosson', + 'Wiggs', + 'Mcelveen', + 'Dimaggio', + 'Rettig', + 'Ahumada', + 'Hetzel', + 'Welling', + 'Chadwell', + 'Swink', + 'Mckinzie', + 'Kwak', + 'Chabot', + 'Tomaszewski', + 'Bonanno', + 'Lesko', + 'Teter', + 'Stalnaker', + 'Ober', + 'Hovis', + 'Hosey', + 'Chaudhry', + 'Fey', + 'Vital', + 'Earhart', + 'Heins', + 'Crowther', + 'Hanner', + 'Behr', + 'Billington', + 'Vogler', + 'Hersh', + 'Perlman', + 'Given', + 'Files', + 'Partain', + 'Coddington', + 'Jardine', + 'Grimmett', + 'Springs', + 'Macomber', + 'Horgan', + 'Arrieta', + 'Charley', + 'Josephson', + 'Tupper', + 'Provenzano', + 'Celaya', + 'Mcvicker', + 'Sigala', + 'Wimer', + 'Ayon', + 'Dossantos', + 'Norvell', + 'Lorenzen', + 'Pasquale', + 'Lambright', + 'Goings', + 'Defelice', + 'Wen', + 'Sigman', + 'Gaylor', + 'Rehm', + 'Carino', + 'Werth', + 'Forehand', + 'Hanke', + 'Lasalle', + 'Mitchum', + 'Priester', + 'Lefler', + 'Celis', + 'Lesser', + 'Fitz', + 'Wentzel', + 'Lavery', + 'Klassen', + 'Shiflett', + 'Hedden', + 'Henn', + 'Coursey', + 'Drain', + 'Delorenzo', + 'Haws', + 'Stansberry', + 'Trump', + 'Dantzler', + 'Chaidez', + 'Mcsweeney', + 'Griffen', + 'Trail', + 'Gandara', + 'Brunk', + 'Kennon', + 'Coss', + 'Blackmore', + 'Metts', + 'Gluck', + 'Blackshear', + 'Cogan', + 'Boney', + 'Encinas', + 'Adamski', + 'Roberge', + 'Schuette', + 'Valero', + 'Barroso', + 'Antunez', + 'Mohammad', + 'Housley', + 'Escoto', + 'Ullrich', + 'Helman', + 'Trost', + 'Lafave', + 'Faith', + 'Blaney', + 'Kershner', + 'Hoehn', + 'Roemer', + 'Isley', + 'Lipinski', + 'Claus', + 'Caulfield', + 'Paiz', + 'Leyba', + 'Robinett', + 'Lambeth', + 'Tarpley', + 'Essex', + 'Eilers', + 'Epley', + 'Murdoch', + 'Sandstrom', + 'Laux', + 'Domingue', + 'Grundy', + 'Bellows', + 'Spindler', + 'Boos', + 'Bhatt', + 'Tye', + 'Salamone', + 'Cirillo', + 'Troup', + 'Jemison', + 'Calzada', + 'Dowden', + 'Geraci', + 'Dunphy', + 'Sack', + 'Sloane', + 'Hathcock', + 'Yap', + 'Ronquillo', + 'Willette', + 'Partlow', + 'Dear', + 'Tunstall', + 'Kiss', + 'Huhn', + 'Seabolt', + 'Beene', + 'Sather', + 'Lockridge', + 'Despain', + 'Wines', + 'Mcalpine', + 'Wadley', + 'Dey', + 'Loring', + 'Meadors', + 'Buettner', + 'Lavalley', + 'Bugg', + 'Creek', + 'Millett', + 'Pumphrey', + 'Fregoso', + 'Merkle', + 'Sheffer', + 'Glassman', + 'Groover', + 'Sweatt', + 'Colunga', + 'Boykins', + 'Seng', + 'Stutz', + 'Brann', + 'Blakey', + 'Munos', + 'Geddes', + 'Avendano', + 'Molitor', + 'Diedrich', + 'Langham', + 'Kindle', + 'Lacour', + 'Buckler', + 'Corum', + 'Bakke', + 'Godin', + 'Kerner', + 'Tobey', + 'Kubiak', + 'Hoyer', + 'Hedge', + 'Priebe', + 'Callison', + 'Lahr', + 'Shears', + 'Snavely', + 'Blatt', + 'Mcpeak', + 'Tinney', + 'Sullins', + 'Bernhard', + 'Gibb', + 'Vaillancourt', + 'Paugh', + 'Funes', + 'Romans', + 'Maurice', + 'Lough', + 'Kerwin', + 'Sanger', + 'Vierra', + 'Markus', + 'Comfort', + 'Krall', + 'Spies', + 'Malcom', + 'Vizcarra', + 'Beamer', + 'Kellerman', + 'Mcroberts', + 'Waterhouse', + 'Stromberg', + 'Persons', + 'Whitesell', + 'Harty', + 'Rosenblatt', + 'Broadwater', + 'Clardy', + 'Shackleford', + 'Jacquez', + 'Brittingham', + 'Lindahl', + 'Feliz', + 'Danna', + 'Garwood', + 'Heron', + 'Southwick', + 'Dehoyos', + 'Cottrill', + 'Mellor', + 'Goldfarb', + 'Grieco', + 'Helgeson', + 'Vandusen', + 'Heinen', + 'Batt', + 'Ruch', + 'Garretson', + 'Pankey', + 'Caudillo', + 'Jakubowski', + 'Plowman', + 'Starcher', + 'Wessels', + 'Moose', + 'Rosner', + 'Louden', + 'Walczak', + 'Poulsen', + 'Mcchesney', + 'Karns', + 'Casares', + 'Cusack', + 'Cespedes', + 'Cornelison', + 'Crossland', + 'Hirst', + 'Mier', + 'Roberto', + 'Canchola', + 'Bosse', + 'Shetler', + 'Melendrez', + 'Giannini', + 'Six', + 'Traynor', + 'Knepper', + 'Lonergan', + 'Kessinger', + 'Hollon', + 'Weathersby', + 'Stouffer', + 'Gingrich', + 'Breault', + 'Pompa', + 'Vanhoose', + 'Burdine', + 'Lark', + 'Stiltner', + 'Wunderlich', + 'Yong', + 'Merrifield', + 'Willhite', + 'Geiser', + 'Lambrecht', + 'Keffer', + 'Carlo', + 'Germany', + 'Turgeon', + 'Dame', + 'Tristan', + 'Bova', + 'Doak', + 'Mannino', + 'Shotwell', + 'Bash', + 'Coots', + 'Feist', + 'Mahmood', + 'Schlabach', + 'Salzman', + 'Kass', + 'Bresnahan', + 'Stonge', + 'Tesch', + 'Grajeda', + 'Mccarron', + 'Mcelwee', + 'Spradling', + 'Mckown', + 'Colgan', + 'Piedra', + 'Collum', + 'Stoffel', + 'Won', + 'Gulick', + 'Devault', + 'Enders', + 'Yanes', + 'Lansing', + 'Ebner', + 'Deegan', + 'Boutin', + 'Fetzer', + 'Andresen', + 'Trigg', + 'Sale', + 'Polite', + 'Hummer', + 'Wille', + 'Bowerman', + 'Routh', + 'Iqbal', + 'Lakey', + 'Mcadoo', + 'Laflamme', + 'Boulware', + 'Guadarrama', + 'Campana', + 'Strayer', + 'Aho', + 'Emmett', + 'Wolters', + 'Bos', + 'Knighten', + 'Averill', + 'Bhakta', + 'Schumaker', + 'Stutts', + 'Mejias', + 'Byer', + 'Mahone', + 'Staab', + 'Riehl', + 'Briceno', + 'Zabala', + 'Lafountain', + 'Clemmer', + 'Mansell', + 'Rossetti', + 'Lafontaine', + 'Mager', + 'Adamo', + 'Bogue', + 'Northern', + 'Disney', + 'Masse', + 'Senter', + 'Yaeger', + 'Dahlberg', + 'Bisson', + 'Leitner', + 'Bolding', + 'Ormsby', + 'Berard', + 'Brazell', + 'Pickle', + 'Hord', + 'Mcguigan', + 'Glennon', + 'Aman', + 'Dearman', + 'Cauthen', + 'Rembert', + 'Delucia', + 'Enciso', + 'Slusser', + 'Kratzer', + 'Schoenfeld', + 'Gillam', + 'Rael', + 'Rhode', + 'Moton', + 'Eide', + 'Eliason', + 'Helfrich', + 'Bish', + 'Goodnight', + 'Campion', + 'Blow', + 'Gerken', + 'Goldenberg', + 'Mellinger', + 'Nations', + 'Maiden', + 'Anzalone', + 'Wagers', + 'Arguelles', + 'Christen', + 'Guth', + 'Stamey', + 'Bozarth', + 'Balogh', + 'Grammer', + 'Chafin', + 'Prine', + 'Freer', + 'Alder', + 'Latorre', + 'Zaleski', + 'Lindholm', + 'Belisle', + 'Zacharias', + 'Swinson', + 'Bazemore', + 'Glazer', + 'Acord', + 'Said', + 'Liggins', + 'Lueck', + 'Luedtke', + 'Blackstone', + 'Copper', + 'Riker', + 'Braud', + 'Demello', + 'Rode', + 'Haven', + 'Rhee', + 'Galligan', + 'Record', + 'Nilson', + 'Ansley', + 'Pera', + 'Gilliard', + 'Copp', + 'Haugh', + 'Dunigan', + 'Grinnell', + 'Garr', + 'Leonhardt', + 'Elswick', + 'Shahan', + 'Mike', + 'Boddie', + 'Casella', + 'Mauricio', + 'Millet', + 'Daye', + 'Claussen', + 'Pierrelouis', + 'Fleischman', + 'Embrey', + 'Durso', + 'Whisenant', + 'Rankins', + 'Lasky', + 'Askins', + 'Rupe', + 'Rochelle', + 'Burkes', + 'Kreger', + 'Mishler', + 'Heald', + 'Jager', + 'Player', + 'Linehan', + 'Horwitz', + 'Jacobi', + 'Maine', + 'Wiest', + 'Ostrom', + 'Sealy', + 'Jimerson', + 'Alverson', + 'Senior', + 'Hassett', + 'Colter', + 'Schleicher', + 'Marini', + 'Mcbrayer', + 'Arzola', + 'Sobel', + 'Frederickson', + 'Confer', + 'Tadlock', + 'Belmonte', + 'Lebrun', + 'Clyde', + 'Alleyne', + 'Lozoya', + 'Teller', + 'Husband', + 'Brigman', + 'Secrest', + 'Krajewski', + 'Neiman', + 'Trull', + 'Watterson', + 'Vanhook', + 'Sotomayor', + 'Woodrum', + 'Baskerville', + 'Finke', + 'Hohman', + 'Arp', + 'Hearne', + 'Mauk', + 'Danko', + 'Laurie', + 'Linderman', + 'Hutt', + 'Springfield', + 'Chmielewski', + 'Klimek', + 'Phinney', + 'Leboeuf', + 'Mcglone', + 'Holmquist', + 'Cogswell', + 'Nichol', + 'Klink', + 'Dunston', + 'Krawczyk', + 'Dart', + 'Woodside', + 'Smitherman', + 'Gasca', + 'Sala', + 'Foxworth', + 'Kammerer', + 'Auer', + 'Pegues', + 'Bukowski', + 'Koger', + 'Spitz', + 'Blomquist', + 'Creasy', + 'Bomar', + 'Holub', + 'Loney', + 'Garry', + 'Habib', + 'Chea', + 'Dupuy', + 'Seaver', + 'Sowards', + 'Julius', + 'Fulks', + 'Braithwaite', + 'Bretz', + 'Mccammon', + 'Sedillo', + 'Chiasson', + 'Oney', + 'Horstman', + 'Waites', + 'Mccusker', + 'Fenske', + 'Conwell', + 'Brokaw', + 'Cloyd', + 'Biles', + 'Aguinaga', + 'Astorga', + 'Demaio', + 'Liberty', + 'Kayser', + 'Ney', + 'Barthel', + 'Lennox', + 'Trautman', + 'Purser', + 'Pitzer', + 'Mattos', + 'Liss', + 'Clack', + 'Sias', + 'Bobb', + 'Stoller', + 'Robillard', + 'Almodovar', + 'Cribb', + 'Ebel', + 'Oyler', + 'Dail', + 'Ericksen', + 'Geis', + 'Everitt', + 'Cropper', + 'Meisner', + 'Skeens', + 'Frith', + 'Privett', + 'Braddy', + 'Bolick', + 'Severance', + 'Jeffreys', + 'Bethune', + 'Delcid', + 'Buzzard', + 'Broadbent', + 'Bono', + 'Addis', + 'Johannes', + 'Tims', + 'Castorena', + 'Simonsen', + 'Glidewell', + 'Mui', + 'Ogilvie', + 'Soukup', + 'Sunday', + 'Redwine', + 'Borton', + 'Schuyler', + 'Rudisill', + 'Beckford', + 'Pascua', + 'Garton', + 'Gilkey', + 'Applewhite', + 'Halterman', + 'Alsup', + 'Delreal', + 'Hubble', + 'Quijada', + 'Kropp', + 'Dunkle', + 'Lemire', + 'Lamontagne', + 'Dunkin', + 'Paulin', + 'Attaway', + 'Baugher', + 'Hornbeck', + 'Niehaus', + 'Nice', + 'Trimmer', + 'Canaday', + 'Maney', + 'Trexler', + 'Schmucker', + 'Edinger', + 'Massengill', + 'Rowlett', + 'Caviness', + 'Kam', + 'Chesnut', + 'Giardina', + 'Spaeth', + 'Gebhart', + 'Morano', + 'Salguero', + 'Buckland', + 'Reina', + 'Jumper', + 'Navas', + 'Thrift', + 'Spradley', + 'Bitner', + 'Ayer', + 'Harber', + 'Landaverde', + 'Mcmillion', + 'Naugle', + 'Dole', + 'Seagraves', + 'Smithers', + 'Frechette', + 'Weeden', + 'Caston', + 'Cavallaro', + 'Laureano', + 'Mandell', + 'Lowrance', + 'Baty', + 'Ronan', + 'Gigliotti', + 'Rossiter', + 'Mines', + 'Alatorre', + 'Markowski', + 'Berge', + 'Hatter', + 'Weakley', + 'Borrero', + 'Glazier', + 'Lavergne', + 'Sines', + 'Ingham', + 'Meltzer', + 'Rabinowitz', + 'Siciliano', + 'Canas', + 'Perna', + 'Struck', + 'Dare', + 'Nay', + 'Severino', + 'Mathewson', + 'Bouldin', + 'Topete', + 'Brunette', + 'Sin', + 'Hendren', + 'Brickey', + 'Ferrier', + 'Alessi', + 'Scheel', + 'Storer', + 'Matherne', + 'Mecham', + 'Spiker', + 'Hibbert', + 'Klingensmith', + 'Lefever', + 'Banning', + 'Bankhead', + 'Roan', + 'Brack', + 'Pascoe', + 'Davie', + 'Scheid', + 'Jim', + 'Tweedy', + 'Strahan', + 'Revis', + 'Fermin', + 'Obrian', + 'Motes', + 'Lobo', + 'Palmisano', + 'Faught', + 'Byington', + 'Garren', + 'Hungerford', + 'Vanzandt', + 'Gust', + 'Heater', + 'Klingler', + 'Delay', + 'Wear', + 'Hendley', + 'Threatt', + 'Gaughan', + 'Kunze', + 'Hessler', + 'Lindell', + 'Monteleone', + 'Palazzolo', + 'Shear', + 'Phares', + 'Cavalier', + 'Benning', + 'Urbanski', + 'Darrah', + 'Wager', + 'Mohn', + 'Vereen', + 'Beiler', + 'Hedlund', + 'Quade', + 'Wieczorek', + 'Cicero', + 'Hoekstra', + 'Scalf', + 'Ducote', + 'Havard', + 'Espiritu', + 'Beacham', + 'Bolger', + 'Schuller', + 'Sill', + 'Dice', + 'Lemmons', + 'Orlowski', + 'Lundeen', + 'Steck', + 'Stanfill', + 'Rakes', + 'Laine', + 'Haviland', + 'Durrett', + 'Naumann', + 'Donahoe', + 'Reif', + 'Franck', + 'Amoroso', + 'Belknap', + 'Tolle', + 'Perrotta', + 'Heyer', + 'Dougan', + 'Frakes', + 'Leath', + 'Poteat', + 'Violette', + 'Marine', + 'Zellner', + 'Granillo', + 'Fontanez', + 'Didonato', + 'Bradberry', + 'Morman', + 'Mentzer', + 'Lamoureux', + 'Sabatino', + 'Catania', + 'Wenner', + 'Pastrana', + 'Shenk', + 'Losey', + 'Hepburn', + 'Antonucci', + 'Egger', + 'Higbee', + 'Adames', + 'Reep', + 'Cavallo', + 'Bridwell', + 'Villalba', + 'Poor', + 'Peet', + 'Everette', + 'Arney', + 'Towery', + 'Sharon', + 'Trainer', + 'Marrow', + 'Cumming', + 'Rimmer', + 'Stanger', + 'Pinter', + 'Felt', + 'Parrett', + 'Garrard', + 'Benedetto', + 'Lingenfelter', + 'Resch', + 'Billy', + 'Mikesell', + 'Osterman', + 'Trueblood', + 'Redfern', + 'Calderone', + 'Placencia', + 'Wamsley', + 'Warr', + 'Varnado', + 'Harshbarger', + 'Topping', + 'Feltner', + 'Decosta', + 'Tart', + 'Blumberg', + 'Shaikh', + 'Culley', + 'Bork', + 'Thibeault', + 'Stolz', + 'Ramsdell', + 'Tedford', + 'Noto', + 'Poulson', + 'Daves', + 'Altieri', + 'Mendosa', + 'Kisner', + 'Grafton', + 'Remy', + 'Hartline', + 'Cripe', + 'Sher', + 'Mulvaney', + 'Ansari', + 'Hartfield', + 'Whitton', + 'Wathen', + 'Eisele', + 'Hinojos', + 'Backer', + 'Speaks', + 'Schuetz', + 'Novoa', + 'Marcos', + 'Mask', + 'Oboyle', + 'Kircher', + 'Stang', + 'Sibert', + 'Scala', + 'Zacarias', + 'Hendon', + 'Halvorsen', + 'Montalbano', + 'Zermeno', + 'Vancamp', + 'Grams', + 'Hornberger', + 'Binion', + 'Dewald', + 'Rives', + 'Sankey', + 'Kleinman', + 'Falconer', + 'Rumph', + 'Matus', + 'Swett', + 'Spinner', + 'Depasquale', + 'Gamino', + 'Olmsted', + 'Absher', + 'Culler', + 'Fryman', + 'Lampert', + 'Carlyle', + 'Terranova', + 'Dunagan', + 'Chouinard', + 'Wesolowski', + 'Hetherington', + 'Scalise', + 'Pendergast', + 'Marcano', + 'Joubert', + 'Scheller', + 'Whisenhunt', + 'Lenoir', + 'Mahar', + 'Vanlandingham', + 'Pecoraro', + 'You', + 'Natividad', + 'Daum', + 'Penick', + 'Eddington', + 'Deleo', + 'Soltis', + 'Santucci', + 'Costanza', + 'Hiner', + 'Farlow', + 'Hartsock', + 'Duprey', + 'Fann', + 'Safford', + 'Murtha', + 'Fessler', + 'Chien', + 'Paynter', + 'Devera', + 'Hoelscher', + 'Boltz', + 'Deacon', + 'Loo', + 'Enoch', + 'Dilorenzo', + 'Saville', + 'Mirza', + 'Takacs', + 'Drexler', + 'Lakin', + 'Geraghty', + 'Widmer', + 'Esteves', + 'Llanes', + 'Cerny', + 'Quist', + 'Hargraves', + 'Toma', + 'Tarter', + 'Chapple', + 'Alderete', + 'Michelson', + 'Clymer', + 'Batey', + 'Sealey', + 'Loughlin', + 'Preece', + 'Zurita', + 'Courville', + 'Desousa', + 'Shamblin', + 'Tingley', + 'Noles', + 'Misner', + 'Standifer', + 'Dinardo', + 'Dillow', + 'Bullis', + 'Carballo', + 'Everly', + 'Mulvihill', + 'Tincher', + 'Carle', + 'Lundin', + 'Birdsall', + 'Bainbridge', + 'Suttle', + 'Wightman', + 'Mower', + 'Mountain', + 'Bickham', + 'Durante', + 'Viveros', + 'Swinford', + 'Mcgruder', + 'Tapley', + 'Grable', + 'Gwynn', + 'Wiebe', + 'Stagg', + 'Dash', + 'Heitman', + 'Cluff', + 'Huertas', + 'Fortuna', + 'Lines', + 'Sly', + 'Halford', + 'Helsel', + 'Bicknell', + 'Blakeman', + 'Colangelo', + 'Olney', + 'Quinton', + 'Rothrock', + 'Renz', + 'Hone', + 'Prejean', + 'Oshiro', + 'Serio', + 'Latour', + 'Newbold', + 'Fitzhugh', + 'Songer', + 'Cardin', + 'Geter', + 'Barbera', + 'Abbas', + 'Caesar', + 'Blakeslee', + 'Camper', + 'Mcclurg', + 'Driskill', + 'Cancel', + 'Donelson', + 'Borrelli', + 'Donoghue', + 'Shoaf', + 'Tinajero', + 'Arzate', + 'Keesee', + 'Pasley', + 'Strode', + 'Morello', + 'Trantham', + 'Ackerson', + 'Jowers', + 'Brockington', + 'Barcia', + 'Lipp', + 'Dinger', + 'Ridings', + 'Canavan', + 'Rank', + 'Hagans', + 'Lampley', + 'Beckmann', + 'Bjork', + 'Raygoza', + 'Schirmer', + 'Longmire', + 'Schiavone', + 'Breuer', + 'Lore', + 'Stenson', + 'Koziol', + 'Channell', + 'Cale', + 'Trader', + 'Culberson', + 'Mundt', + 'Sickles', + 'Nemec', + 'Holl', + 'Stribling', + 'Berens', + 'Nauman', + 'Lehner', + 'Deem', + 'Castelli', + 'Billman', + 'Orndorff', + 'Gumm', + 'Davy', + 'Pelham', + 'Spotts', + 'Jurgens', + 'Sword', + 'Adorno', + 'Gorrell', + 'Boughton', + 'Bobadilla', + 'Mauer', + 'Moline', + 'Guay', + 'Holsinger', + 'Baranowski', + 'Gutierres', + 'Beveridge', + 'Marable', + 'Berkey', + 'Lamothe', + 'Spitler', + 'Carbaugh', + 'Hoopes', + 'Wilken', + 'Milford', + 'Bingaman', + 'Crippen', + 'Shock', + 'Yarnell', + 'Oman', + 'Wethington', + 'Kost', + 'Gaudette', + 'Spielman', + 'Foran', + 'Starke', + 'Eugene', + 'Birnbaum', + 'Navarrette', + 'Hussein', + 'Ranson', + 'Hedgepeth', + 'Doctor', + 'Higuera', + 'Brough', + 'Cookson', + 'Provencher', + 'Mendonca', + 'Gowen', + 'Summer', + 'Rutz', + 'Reader', + 'Doud', + 'Raven', + 'Toribio', + 'Peachey', + 'Gunning', + 'Bittle', + 'Vale', + 'Harnish', + 'Marano', + 'Aker', + 'Damore', + 'Utz', + 'Throckmorton', + 'Bulger', + 'Vanzant', + 'Pasillas', + 'Holmgren', + 'Corpus', + 'Longley', + 'Wetmore', + 'Carstens', + 'Line', + 'Percival', + 'Ayotte', + 'Batres', + 'Pipes', + 'Ludwick', + 'Alpert', + 'Pick', + 'Carlock', + 'Edmundson', + 'Feinstein', + 'Krouse', + 'Dahlgren', + 'Sasaki', + 'Lieb', + 'Londono', + 'Oloughlin', + 'Wardlaw', + 'Lineberry', + 'Castello', + 'Milstead', + 'Parmenter', + 'Riffe', + 'Pare', + 'Sitton', + 'Tarin', + 'Delcastillo', + 'Manor', + 'Calabro', + 'Elkin', + 'Grill', + 'Boaz', + 'Coco', + 'Chamblee', + 'Celestine', + 'Nick', + 'Stork', + 'Meekins', + 'Moise', + 'Devers', + 'Jun', + 'Kegley', + 'Brick', + 'Lobato', + 'Biggerstaff', + 'Kersten', + 'Jayne', + 'Nasser', + 'Southall', + 'Kempton', + 'Eaddy', + 'Paladino', + 'Berardi', + 'Pizzo', + 'Pulver', + 'Ohalloran', + 'Fromm', + 'Cranston', + 'Rowden', + 'Capobianco', + 'Kahle', + 'Thiessen', + 'Malott', + 'Houseman', + 'Maul', + 'Gallion', + 'Tressler', + 'Pauly', + 'Pellerin', + 'Sainz', + 'Firth', + 'Cryer', + 'Jeanlouis', + 'Mong', + 'Trawick', + 'Chronister', + 'Hayashi', + 'Posner', + 'Cueva', + 'Sherwin', + 'Lacasse', + 'Gorden', + 'Bohl', + 'Twigg', + 'Coan', + 'Hocker', + 'Goodale', + 'Urbano', + 'Loeb', + 'Perrault', + 'Frawley', + 'Carcamo', + 'Richburg', + 'Moffat', + 'Hennings', + 'Weyer', + 'Myatt', + 'Ullman', + 'Tunnell', + 'Hern', + 'Lopresti', + 'Sonnenberg', + 'Knisley', + 'Twomey', + 'Jaggers', + 'Tanksley', + 'Rachal', + 'Poppe', + 'Vos', + 'Kania', + 'Speakman', + 'Peirce', + 'Pound', + 'Romer', + 'Patty', + 'Millsaps', + 'Kyser', + 'Telford', + 'Hegarty', + 'Kellett', + 'Michaelis', + 'Halligan', + 'Maughan', + 'Herb', + 'Rainer', + 'Robichaud', + 'Fiscus', + 'Sickler', + 'Blom', + 'Lavine', + 'Medel', + 'Bolyard', + 'Secor', + 'Creekmore', + 'Magruder', + 'Haskin', + 'Laliberte', + 'Drago', + 'Bernabe', + 'Leader', + 'Cavin', + 'Lukens', + 'Vassallo', + 'Pletcher', + 'Fuson', + 'Hasson', + 'Huckabee', + 'Edington', + 'Eichler', + 'Hering', + 'Vong', + 'Mardis', + 'Gu', + 'Segarra', + 'Bilyeu', + 'Runion', + 'Fragoso', + 'Gama', + 'Dunton', + 'Frady', + 'Lewellen', + 'Crumpler', + 'Jeske', + 'Furlow', + 'Delapena', + 'Kale', + 'Massengale', + 'Hamlet', + 'Galli', + 'Esteban', + 'Greeson', + 'Shue', + 'Pollak', + 'Pinney', + 'Ruffner', + 'Maitland', + 'Steven', + 'Hockett', + 'Fraire', + 'Mulhern', + 'Elbert', + 'Hoggard', + 'Labarge', + 'Silcox', + 'Saez', + 'Sluder', + 'Stamp', + 'Darlington', + 'Mccarroll', + 'Pillow', + 'Palazzo', + 'Blaha', + 'Demaria', + 'Swanger', + 'Winningham', + 'Lippincott', + 'Dake', + 'Goldsberry', + 'Seidl', + 'Woolfolk', + 'Murawski', + 'Hobart', + 'Kimber', + 'Nilsson', + 'Stough', + 'Almendarez', + 'Nevels', + 'Fasano', + 'Salmons', + 'Denmark', + 'Lathan', + 'Mosely', + 'Stengel', + 'Mendieta', + 'Felice', + 'Drown', + 'Vidrine', + 'Callihan', + 'Polston', + 'Howze', + 'Eakins', + 'Leek', + 'Featherstone', + 'Lajoie', + 'Athey', + 'Asuncion', + 'Ashbaugh', + 'Orman', + 'Morrissette', + 'Peart', + 'Hamner', + 'Zell', + 'Dry', + 'Dieter', + 'Terrones', + 'Campuzano', + 'Reveles', + 'Bakker', + 'Banister', + 'Arceo', + 'Dhillon', + 'Normand', + 'Shavers', + 'Ginsburg', + 'Go', + 'Rubinstein', + 'Arens', + 'Clutter', + 'Jaques', + 'Traxler', + 'Hackler', + 'Cisco', + 'Starrett', + 'Ceron', + 'Gillenwater', + 'Ottinger', + 'Caster', + 'Blakemore', + 'Thorsen', + 'Molinar', + 'Baur', + 'Hower', + 'Haldeman', + 'Oliveri', + 'Mcalpin', + 'Standish', + 'Bengtson', + 'Strack', + 'Cordoba', + 'Blackstock', + 'Barna', + 'Schantz', + 'Hawkinson', + 'Breese', + 'Saba', + 'Camden', + 'Gwaltney', + 'Corliss', + 'Smit', + 'Cruise', + 'Mcneese', + 'Duggins', + 'Laub', + 'Burman', + 'Kenworthy', + 'Spohn', + 'Santini', + 'Nuttall', + 'Willison', + 'Stjean', + 'Shabazz', + 'Manes', + 'Gerry', + 'Mclamb', + 'Koepke', + 'Reeser', + 'Ogburn', + 'Wegener', + 'Risinger', + 'Carrero', + 'Livermore', + 'Brewton', + 'Harsh', + 'Utterback', + 'Lecompte', + 'Schnabel', + 'Ting', + 'Honea', + 'Stryker', + 'Foshee', + 'Baptista', + 'Gravely', + 'Courson', + 'Goyette', + 'Leitch', + 'Tasker', + 'Laurence', + 'Reneau', + 'Voight', + 'Tilson', + 'Range', + 'Hallam', + 'Dufrene', + 'Boice', + 'Shrewsbury', + 'Sturges', + 'Lenard', + 'Sistrunk', + 'Weitz', + 'Carnevale', + 'Hepner', + 'Wehner', + 'Callen', + 'Oshaughnessy', + 'Wingert', + 'Mouser', + 'Palmore', + 'Rugg', + 'Elia', + 'Alcazar', + 'Avitia', + 'Penton', + 'Brisco', + 'Ambrosio', + 'Wardlow', + 'Leaf', + 'Rowles', + 'Buggs', + 'Dittmer', + 'Schweizer', + 'Puleo', + 'Vaden', + 'Haughton', + 'Cardinale', + 'Seguin', + 'Ruddy', + 'Minard', + 'Stalker', + 'Bennington', + 'Hilt', + 'Works', + 'Broadus', + 'Engels', + 'Haddix', + 'Buster', + 'Recker', + 'Bopp', + 'Wilton', + 'Costantino', + 'Boots', + 'Falkner', + 'Tennison', + 'Mcgary', + 'Holz', + 'Lofgren', + 'Putney', + 'Christner', + 'Fruge', + 'Vassar', + 'Vankirk', + 'Spoon', + 'Pearlman', + 'Guertin', + 'Meece', + 'Sartain', + 'Petterson', + 'Primm', + 'Cardillo', + 'Dryer', + 'Hartshorn', + 'Dane', + 'Chaisson', + 'Espitia', + 'Creager', + 'Disalvo', + 'Janik', + 'Parente', + 'Paiva', + 'Slaven', + 'Tague', + 'Kujawa', + 'Gruver', + 'Foor', + 'Frampton', + 'Prokop', + 'Mettler', + 'Collis', + 'Lamkin', + 'Shuey', + 'Tepper', + 'Colyer', + 'Masi', + 'Trumble', + 'Guice', + 'Hurwitz', + 'Windle', + 'Mccully', + 'Cutting', + 'Stotler', + 'Grullon', + 'Wagstaff', + 'Morfin', + 'Dehaan', + 'Noon', + 'Flesher', + 'Ferri', + 'Covell', + 'Coll', + 'Lucy', + 'Albaugh', + 'Testerman', + 'Gordillo', + 'Jepson', + 'Brinkerhoff', + 'Calle', + 'Crowl', + 'Mcelwain', + 'Chumley', + 'Brockett', + 'Thoms', + 'Revell', + 'Garzon', + 'Polak', + 'Rothenberg', + 'Socha', + 'Vallejos', + 'Felty', + 'Peguero', + 'Ping', + 'Tso', + 'Charleston', + 'Fedor', + 'Haider', + 'Abe', + 'Enlow', + 'Fifer', + 'Bumpus', + 'Keele', + 'Mcdavid', + 'Panek', + 'Scholten', + 'Dyess', + 'Heatherly', + 'Donohoe', + 'Hoban', + 'Griffey', + 'Corry', + 'Mcclean', + 'Plyler', + 'Feathers', + 'Adkison', + 'Killeen', + 'Hoeft', + 'Myhre', + 'Fiorentino', + 'Mcbeth', + 'Erazo', + 'Madson', + 'Fulbright', + 'Wilds', + 'Petrucci', + 'Mcgaughey', + 'Monteith', + 'Murguia', + 'Hausman', + 'Zukowski', + 'Shute', + 'Brisson', + 'Lain', + 'Runkle', + 'Hickok', + 'Caffrey', + 'Million', + 'Elson', + 'Peay', + 'Haga', + 'Ancheta', + 'Cordle', + 'Blas', + 'Carmen', + 'Pettiford', + 'Dimartino', + 'Spahr', + 'Mozingo', + 'Backman', + 'Stgeorge', + 'Konrad', + 'Buhler', + 'Mcelrath', + 'Oliveros', + 'Edelstein', + 'Cadet', + 'Gilmartin', + 'Munday', + 'Roane', + 'Desalvo', + 'Lepe', + 'Symons', + 'Shearin', + 'Linkous', + 'Cheshire', + 'Klemm', + 'Beagle', + 'Pooler', + 'Dewalt', + 'Esch', + 'Finnell', + 'Sinnott', + 'Kepler', + 'Toups', + 'Riccardi', + 'Caylor', + 'Tillis', + 'Messmer', + 'Rothschild', + 'Boutte', + 'Zumwalt', + 'Bohrer', + 'Elgin', + 'Kinley', + 'Schechter', + 'Gowan', + 'Pyne', + 'Cousin', + 'Hunsinger', + 'Fishel', + 'Edenfield', + 'Nadler', + 'Warman', + 'Bruhn', + 'Swint', + 'Lizotte', + 'Nardone', + 'Troxel', + 'Grindle', + 'Labrie', + 'Tao', + 'Olea', + 'Schermerhorn', + 'Stier', + 'Hettinger', + 'Farthing', + 'Roux', + 'Max', + 'Amburgey', + 'Auerbach', + 'Janzen', + 'Ortez', + 'Alejandre', + 'Peiffer', + 'Molinaro', + 'Burleigh', + 'Benites', + 'Ringler', + 'Hou', + 'Haffner', + 'Nace', + 'Crosson', + 'Karcher', + 'Neufeld', + 'Bayles', + 'Riemer', + 'Amezquita', + 'Cadwell', + 'Petrosky', + 'Swallow', + 'Minnis', + 'Krupp', + 'Nardi', + 'Orsini', + 'Diez', + 'Updike', + 'Gasser', + 'Rogerson', + 'Speicher', + 'Dubay', + 'Hollaway', + 'Teets', + 'Keown', + 'Center', + 'Blanding', + 'Whisler', + 'Spurlin', + 'Collin', + 'Greenawalt', + 'Tomes', + 'Leister', + 'Chatfield', + 'Helwig', + 'Reimers', + 'Andress', + 'Norcross', + 'Melnick', + 'Yearwood', + 'Defazio', + 'Kubik', + 'Bhatia', + 'Uddin', + 'Belmont', + 'Haden', + 'Bench', + 'Chilson', + 'Pegg', + 'Cane', + 'Goehring', + 'Lino', + 'Tyus', + 'Furey', + 'Castleman', + 'Heywood', + 'Leedy', + 'Holleman', + 'Villeda', + 'Mcveigh', + 'Carreiro', + 'Hocking', + 'Azar', + 'Blough', + 'Lieu', + 'Marcial', + 'Coblentz', + 'Hossain', + 'Weisberg', + 'Gardea', + 'Hoyos', + 'Lipsey', + 'Reger', + 'Clouser', + 'Bewley', + 'Magness', + 'Goines', + 'Thome', + 'Odea', + 'Mannion', + 'Dansby', + 'Dipasquale', + 'Constable', + 'Truelove', + 'Hubler', + 'Ulibarri', + 'Wymer', + 'Cron', + 'Hugo', + 'Hilderbrand', + 'Milazzo', + 'Vasques', + 'Sproul', + 'Shuford', + 'Chavers', + 'Kral', + 'Vecchio', + 'Mehl', + 'Rymer', + 'Henriksen', + 'Taulbee', + 'Hagy', + 'Ammerman', + 'Kagan', + 'Galdamez', + 'Krick', + 'Owsley', + 'Mullikin', + 'Beery', + 'Eccles', + 'Kleinschmidt', + 'Kloss', + 'Oldenburg', + 'Ospina', + 'Harbert', + 'Andujar', + 'Florian', + 'Antone', + 'Mcmillon', + 'Ceniceros', + 'Rippy', + 'Adkisson', + 'Stange', + 'Balmer', + 'Mazurek', + 'Dahlke', + 'Girouard', + 'Nickelson', + 'Perera', + 'Tullos', + 'Cioffi', + 'Bogdan', + 'Olivieri', + 'Petree', + 'Speights', + 'Jantz', + 'Collings', + 'Zellers', + 'Yarber', + 'Lafollette', + 'Rink', + 'Currin', + 'Chua', + 'Hartle', + 'Larocque', + 'Cuthbertson', + 'Ehrhardt', + 'Mara', + 'Rieck', + 'Lumley', + 'Anderton', + 'Hennigan', + 'Fabrizio', + 'Hutter', + 'Bruning', + 'Korman', + 'Haring', + 'Monette', + 'Woodyard', + 'Goggins', + 'Balzer', + 'Philbrick', + 'Bruder', + 'Hansford', + 'Averett', + 'Teske', + 'Mauck', + 'Billiot', + 'Collie', + 'Caffey', + 'Manos', + 'Buchan', + 'Birk', + 'Abdallah', + 'Featherston', + 'Koh', + 'Valera', + 'Deyo', + 'Buono', + 'Aubin', + 'Doody', + 'Pigott', + 'Peloquin', + 'Maniscalco', + 'Eisenhauer', + 'Biller', + 'Farwell', + 'Hartzog', + 'Brazier', + 'Talton', + 'Mcdougald', + 'Midgett', + 'Strout', + 'Spiers', + 'Eiland', + 'Garth', + 'Sequeira', + 'Noyola', + 'Petri', + 'Goodyear', + 'Dineen', + 'Bernardi', + 'Berns', + 'Coolidge', + 'Dorfman', + 'Dittman', + 'Zeno', + 'Hauer', + 'Finlay', + 'Ziemba', + 'Spillane', + 'Kays', + 'Ekstrom', + 'Hile', + 'Mckinstry', + 'Lesley', + 'Courtright', + 'Kuhlmann', + 'Verma', + 'Cripps', + 'Wigley', + 'Nickens', + 'Petrick', + 'Delozier', + 'Hardcastle', + 'Yamaguchi', + 'Romig', + 'Venezia', + 'Reading', + 'Redford', + 'Heng', + 'Anselmo', + 'Getty', + 'Marten', + 'Badgett', + 'Eisner', + 'Holtzman', + 'Stell', + 'Hiser', + 'Dustin', + 'Bordeaux', + 'Debolt', + 'Trevizo', + 'Eckard', + 'Follett', + 'Lal', + 'Dark', + 'Buskirk', + 'Roca', + 'Todaro', + 'Campanella', + 'Lindsley', + 'Wickman', + 'Pritt', + 'Cutlip', + 'Pokorny', + 'Friedlander', + 'Saari', + 'Casias', + 'Macneil', + 'Clyburn', + 'Kravitz', + 'Edgington', + 'Portis', + 'Culbreth', + 'Cuff', + 'Brouillette', + 'Artz', + 'Trudell', + 'Pledger', + 'Markovich', + 'Pisani', + 'Faller', + 'Sergent', + 'Hail', + 'Stabile', + 'Wait', + 'Mcilwain', + 'Eriksen', + 'Nee', + 'Boll', + 'Catanzaro', + 'Giuliano', + 'Oldfield', + 'Banas', + 'Ickes', + 'Vachon', + 'Gleeson', + 'Bailes', + 'Biehl', + 'Woodham', + 'Troupe', + 'Mcgoldrick', + 'Cappello', + 'Kirkendall', + 'Baisden', + 'Joshua', + 'Nicoletti', + 'Roesch', + 'Deatherage', + 'Matter', + 'Sheth', + 'Tynes', + 'Shaheen', + 'Wilbert', + 'Toles', + 'Sanner', + 'Bury', + 'Boman', + 'Bose', + 'Millner', + 'Eisen', + 'Couto', + 'Ide', + 'Howells', + 'Jiminez', + 'Crampton', + 'Monti', + 'Jelinek', + 'Morford', + 'Yeomans', + 'Turnbow', + 'Rolland', + 'Scheetz', + 'Arends', + 'Repp', + 'Hohn', + 'Paton', + 'Govan', + 'Fabela', + 'Mroz', + 'Bourassa', + 'Rizzi', + 'Froelich', + 'Molinari', + 'Lunde', + 'Navarre', + 'Alexandre', + 'Dearborn', + 'Lakes', + 'Foxx', + 'Jerez', + 'Lamanna', + 'Talarico', + 'Butera', + 'Riner', + 'Gros', + 'Champ', + 'Phoenix', + 'Vandeventer', + 'Samora', + 'Behling', + 'Karpinski', + 'Hosier', + 'Tufts', + 'Hobby', + 'Rohrbach', + 'Youngman', + 'Yeary', + 'Paisley', + 'Ben', + 'Villalta', + 'Hempel', + 'Giblin', + 'Lunt', + 'Hagar', + 'Lapoint', + 'Singley', + 'Shows', + 'Kesterson', + 'Bollman', + 'Stansell', + 'Yon', + 'Gabaldon', + 'Simental', + 'Zastrow', + 'Enloe', + 'Sasso', + 'Harkey', + 'Sansom', + 'Twyman', + 'Haslam', + 'Sowa', + 'Hunsberger', + 'Norberg', + 'Hornback', + 'Hanshaw', + 'Axtell', + 'Hoge', + 'Gantz', + 'Mccullum', + 'Blazek', + 'Scher', + 'Carlucci', + 'Jeong', + 'Tillett', + 'Woolridge', + 'Carberry', + 'Reck', + 'Nevin', + 'Armes', + 'Sidhu', + 'Wiesner', + 'Auman', + 'Teeters', + 'Rigg', + 'Moloney', + 'Feld', + 'Lucier', + 'Cardone', + 'Kilian', + 'Conder', + 'Horta', + 'Murakami', + 'Schaff', + 'Dresser', + 'Spray', + 'Hott', + 'Capuano', + 'Englund', + 'Rothe', + 'Ferree', + 'Nolt', + 'Triana', + 'Sanjuan', + 'Oller', + 'Brathwaite', + 'Richert', + 'Holdren', + 'Goree', + 'Branstetter', + 'Schimmel', + 'Jessop', + 'Nellis', + 'Sevier', + 'Rabb', + 'Mcmorris', + 'Lindo', + 'Littles', + 'Polzin', + 'Ranieri', + 'Reale', + 'Sturtevant', + 'Arnone', + 'Zamorano', + 'Keever', + 'Clow', + 'Corr', + 'Blaser', + 'Sheetz', + 'Llanos', + 'Belew', + 'Rusnak', + 'Brandes', + 'Eichhorn', + 'Guida', + 'Pucci', + 'Streit', + 'Renn', + 'Partee', + 'Rappaport', + 'Rosso', + 'Defeo', + 'Greve', + 'Schoch', + 'Langevin', + 'Manna', + 'Towe', + 'Scoville', + 'Marco', + 'Gove', + 'Mckissick', + 'Dangerfield', + 'Mcwhirter', + 'Port', + 'Marrufo', + 'Nicosia', + 'Farren', + 'Kinsley', + 'Pearman', + 'Porch', + 'Mooneyham', + 'Buff', + 'Ruben', + 'Blanc', + 'Mellen', + 'Heiman', + 'Novack', + 'Heston', + 'Huie', + 'Justin', + 'Kincade', + 'Laverty', + 'Villavicencio', + 'Burkart', + 'Offutt', + 'Halliburton', + 'Polo', + 'Barbara', + 'Trammel', + 'Rosati', + 'Sakamoto', + 'Salo', + 'Heyman', + 'Rooker', + 'Sarno', + 'Leroux', + 'Virgen', + 'Collison', + 'Branum', + 'Mcmasters', + 'Divine', + 'Mcnatt', + 'Threadgill', + 'Desir', + 'Borchers', + 'Walkup', + 'Sy', + 'Greenbaum', + 'Vidales', + 'Mercedes', + 'Selph', + 'Bardwell', + 'Whorton', + 'Demartino', + 'Endsley', + 'Verner', + 'Hillier', + 'Mancha', + 'Ricard', + 'Postell', + 'Kummer', + 'Welsch', + 'Almanzar', + 'Brunet', + 'Deeds', + 'Romanowski', + 'Ocallaghan', + 'Cueto', + 'Terhune', + 'Truesdell', + 'Whisnant', + 'Lingo', + 'Aden', + 'Labrecque', + 'Braga', + 'Iles', + 'Garrick', + 'Knickerbocker', + 'Rasberry', + 'Hervey', + 'Schill', + 'Kiely', + 'Liddle', + 'Blakeley', + 'Marez', + 'Schoonmaker', + 'Swinton', + 'Fryar', + 'Exum', + 'Gouge', + 'Hoskinson', + 'Lupton', + 'Guild', + 'Davisson', + 'Chidester', + 'Gravitt', + 'Lenox', + 'Pyatt', + 'Moberg', + 'Overholt', + 'Whiddon', + 'Foti', + 'Lipps', + 'Shankle', + 'Xiao', + 'Balentine', + 'Cesar', + 'Barreras', + 'Schroer', + 'Ram', + 'Eames', + 'Gutman', + 'Pardee', + 'Damiano', + 'Houchin', + 'Porto', + 'Leclerc', + 'Mahaney', + 'Deardorff', + 'Garey', + 'Trotta', + 'Lachapelle', + 'Suiter', + 'Ewert', + 'Costner', + 'Bever', + 'Charpentier', + 'Milewski', + 'Coffelt', + 'Schorr', + 'Leis', + 'Dasher', + 'Cullins', + 'Eveland', + 'Hornung', + 'Swingle', + 'Eudy', + 'Motter', + 'Silk', + 'Gadd', + 'Sidwell', + 'Sandusky', + 'Auld', + 'Mazariegos', + 'Hirt', + 'Zane', + 'Rickett', + 'Ritenour', + 'Goin', + 'Dipaolo', + 'Wolfgang', + 'Inouye', + 'Branton', + 'Rakestraw', + 'Kimbro', + 'Craighead', + 'Sandefur', + 'Foerster', + 'Wipf', + 'Wilkin', + 'Shoffner', + 'Overcash', + 'Simonetti', + 'Toomer', + 'Albino', + 'Eshelman', + 'Rockwood', + 'Pineiro', + 'Reames', + 'Cray', + 'Wulff', + 'Heider', + 'Bath', + 'Colletti', + 'Fiala', + 'Greenstein', + 'Moles', + 'Bashaw', + 'Adamczyk', + 'Finkel', + 'Kistner', + 'Manzi', + 'Ferretti', + 'Demarest', + 'Ahlers', + 'Lack', + 'Wedel', + 'Kinzer', + 'Sechrist', + 'Stickler', + 'Easterday', + 'Mallette', + 'Loehr', + 'Gessner', + 'Croce', + 'Stanko', + 'Innes', + 'Farfan', + 'Heady', + 'Chambless', + 'Balbuena', + 'Decicco', + 'Winsor', + 'Pereyra', + 'Zoller', + 'Ingles', + 'Churchwell', + 'Westlake', + 'Villagran', + 'Soderberg', + 'Thill', + 'Timmer', + 'Mccaleb', + 'Mckernan', + 'Vandergriff', + 'Yoho', + 'Crispin', + 'Dorton', + 'Fults', + 'Borne', + 'Maxie', + 'Bloomquist', + 'Kung', + 'Budde', + 'Weinstock', + 'Honey', + 'Diener', + 'Horak', + 'Tsui', + 'Zirkle', + 'Plum', + 'Heitz', + 'Manrique', + 'Balcom', + 'Napper', + 'Boese', + 'Stefan', + 'Kime', + 'Gautreaux', + 'Leverette', + 'Lemaire', + 'Danford', + 'Hollman', + 'Kuzma', + 'Swinehart', + 'Merriam', + 'Novick', + 'Stankiewicz', + 'Parkes', + 'Englehart', + 'Polansky', + 'Leclaire', + 'Magner', + 'Masson', + 'Mass', + 'Coogan', + 'Jepsen', + 'Pittenger', + 'Bump', + 'Hain', + 'Burchell', + 'Chesley', + 'Cawthon', + 'Dance', + 'Piccolo', + 'Lucey', + 'Ordway', + 'Recio', + 'Ginther', + 'Hauge', + 'Lesperance', + 'Suhr', + 'Ding', + 'Ogg', + 'Skiba', + 'Scannell', + 'Gillies', + 'Brame', + 'Schipper', + 'Brune', + 'Stuber', + 'Pesce', + 'Stead', + 'Bushong', + 'Juneau', + 'Mccalla', + 'Feder', + 'Plaisance', + 'Tweed', + 'Hashimoto', + 'Mounce', + 'Diana', + 'Savala', + 'Vanek', + 'Lamson', + 'Dubin', + 'Killebrew', + 'Kan', + 'Nault', + 'Mulford', + 'Salamanca', + 'Linker', + 'Penrose', + 'Kowalewski', + 'Platz', + 'Kogan', + 'Martucci', + 'Gutowski', + 'Mattes', + 'Haigh', + 'Merida', + 'Ashman', + 'Batton', + 'Biondo', + 'Sweigart', + 'Sorg', + 'Barrier', + 'Gatling', + 'Geib', + 'Henrich', + 'Dabrowski', + 'Vara', + 'Weikel', + 'Jarosz', + 'Mummert', + 'Uriarte', + 'Fifield', + 'Locker', + 'Merlo', + 'Lasater', + 'Ripple', + 'Hopwood', + 'Sherrell', + 'Ruark', + 'Litz', + 'Kinkade', + 'Simkins', + 'Grandy', + 'Lemasters', + 'Wehr', + 'Jinks', + 'Alas', + 'Bale', + 'Stimpson', + 'Glickman', + 'Hage', + 'Seabrook', + 'Stirling', + 'Rozell', + 'Woodburn', + 'Braaten', + 'Sugg', + 'Linde', + 'Castille', + 'Grewal', + 'Blackwelder', + 'Hover', + 'Spurling', + 'Mckellar', + 'Muench', + 'Bovee', + 'Amado', + 'Yau', + 'Harger', + 'Lederer', + 'Seda', + 'Doney', + 'Kimes', + 'Western', + 'Foret', + 'Luera', + 'Warnke', + 'Bussard', + 'Cartier', + 'Andreasen', + 'Lagasse', + 'Topper', + 'Nyman', + 'Hallberg', + 'Whisman', + 'Cremeans', + 'Dewar', + 'Garrow', + 'Odaniel', + 'Stabler', + 'Bourg', + 'Appling', + 'Dahlstrom', + 'Fujimoto', + 'Prudhomme', + 'Gum', + 'Nau', + 'Hiers', + 'Rockett', + 'Sobczak', + 'Traub', + 'Bevis', + 'Tilghman', + 'Plasencia', + 'Sison', + 'Blau', + 'Abbate', + 'Sisler', + 'Rudder', + 'Trotman', + 'Brust', + 'Lederman', + 'Frahm', + 'Fredette', + 'Parise', + 'Urso', + 'Amann', + 'Kaul', + 'Woolery', + 'Thielen', + 'Symonds', + 'Marcy', + 'Wiltshire', + 'Sustaita', + 'Botkin', + 'Kernan', + 'Doolin', + 'Babineaux', + 'Greenspan', + 'Delacerda', + 'Kinnard', + 'Twitty', + 'Augustus', + 'Corriveau', + 'Stults', + 'Toman', + 'Sklar', + 'Leber', + 'Considine', + 'Ohearn', + 'Deforest', + 'Mcmann', + 'Farquhar', + 'Ferrel', + 'Bickley', + 'Manno', + 'Vreeland', + 'Berthiaume', + 'Mcentee', + 'Summerfield', + 'Woodrow', + 'Reynaga', + 'Soltero', + 'Tomko', + 'Jarboe', + 'Allmon', + 'Duplessis', + 'Sydnor', + 'Diallo', + 'Cogar', + 'Mandeville', + 'Shimizu', + 'Aubuchon', + 'Gabbert', + 'Ashlock', + 'Macri', + 'Weng', + 'Walser', + 'Teng', + 'Bailon', + 'Steeves', + 'Perillo', + 'Quattlebaum', + 'Knipp', + 'Delavega', + 'Kirtley', + 'Bramble', + 'Sublett', + 'Borchert', + 'Doria', + 'Session', + 'Merced', + 'Lundstrom', + 'Bluhm', + 'Cortinas', + 'Proper', + 'Sieber', + 'Mccay', + 'Wilford', + 'Asberry', + 'Muldrow', + 'Berning', + 'Hemenway', + 'Millman', + 'Ewers', + 'Timko', + 'Reding', + 'Sayer', + 'Pickel', + 'Cogburn', + 'Chappel', + 'Custodio', + 'Reichel', + 'Robeson', + 'Waid', + 'Wagler', + 'Sappington', + 'Bart', + 'Zazueta', + 'Najar', + 'Marko', + 'Nally', + 'States', + 'Bellard', + 'Marciano', + 'Killough', + 'Cosper', + 'Sangster', + 'Heinze', + 'Bortz', + 'Matamoros', + 'Nuckols', + 'Townsley', + 'Bak', + 'Ralls', + 'Ferrin', + 'Villela', + 'Siegrist', + 'Arora', + 'Collinsworth', + 'Masten', + 'Deer', + 'Balog', + 'Buchman', + 'Scaggs', + 'Holeman', + 'Lefkowitz', + 'Santora', + 'Funke', + 'Redfield', + 'Douthit', + 'Marciniak', + 'Twitchell', + 'Sheahan', + 'Dai', + 'Demuth', + 'Ganz', + 'Bruckner', + 'Wier', + 'Alamo', + 'Aultman', + 'Chubb', + 'Branco', + 'Courter', + 'Vivian', + 'Guin', + 'Witten', + 'Glen', + 'Hyer', + 'Crowson', + 'Arendt', + 'Cipolla', + 'Prochaska', + 'Schober', + 'Harte', + 'Arciniega', + 'Beier', + 'Middlebrook', + 'Dennard', + 'Vantassel', + 'Weekes', + 'Penley', + 'Lozier', + 'Lamberson', + 'Broomfield', + 'Nygaard', + 'Pascale', + 'Hyden', + 'Mundell', + 'Kamara', + 'Ehlert', + 'Mangus', + 'Bornstein', + 'Benedetti', + 'Erikson', + 'Quint', + 'Westman', + 'Basler', + 'Smoak', + 'Leavell', + 'Kerber', + 'Kopec', + 'Emrick', + 'Mattice', + 'Render', + 'Mccree', + 'Feldmann', + 'Cutright', + 'Randell', + 'Drucker', + 'Gilmour', + 'Marconi', + 'Stripling', + 'Mucha', + 'Shipe', + 'Chalk', + 'Martone', + 'Lema', + 'Ricardo', + 'Cobian', + 'Laufer', + 'Mistretta', + 'Shortt', + 'Menzel', + 'Wickline', + 'Oddo', + 'Chai', + 'Rabideau', + 'Stogner', + 'Mckie', + 'Luongo', + 'Trieu', + 'Breshears', + 'Sturdevant', + 'Abernethy', + 'Rohan', + 'Bonnette', + 'Steffes', + 'Straka', + 'Lawhon', + 'Shawver', + 'Guilford', + 'Wiltz', + 'Digregorio', + 'Warburton', + 'Fleshman', + 'Kerstetter', + 'Byram', + 'Obannon', + 'Dalessio', + 'Gatti', + 'Kalb', + 'Boris', + 'Graver', + 'Parkins', + 'Kollar', + 'Crothers', + 'Patin', + 'Cutshall', + 'Fern', + 'Derosier', + 'Goodrum', + 'Kaelin', + 'Baynes', + 'Beesley', + 'Macintyre', + 'Butters', + 'Kinsman', + 'Huffer', + 'Eslinger', + 'Prunty', + 'Boehmer', + 'Nusbaum', + 'Gouveia', + 'Mire', + 'Mccary', + 'Mikell', + 'Petrovich', + 'Melillo', + 'Kennelly', + 'Howley', + 'Merwin', + 'Cotner', + 'Kanter', + 'Sahagun', + 'Bodden', + 'Mcconville', + 'Leddy', + 'Auten', + 'Downie', + 'Armistead', + 'Goudy', + 'Gerhard', + 'Theiss', + 'Lauria', + 'Tuthill', + 'Ammon', + 'Ikeda', + 'Schultheis', + 'Zhong', + 'Pearcy', + 'Vass', + 'Essary', + 'Wendland', + 'Zehr', + 'Hartigan', + 'Ugalde', + 'Mossman', + 'Hartwick', + 'Joaquin', + 'Andreas', + 'Bartee', + 'Gajewski', + 'Gallaway', + 'Comerford', + 'Lieber', + 'Wireman', + 'Damm', + 'Yousif', + 'Kosinski', + 'Kelm', + 'Durrant', + 'Derouen', + 'Bonk', + 'Rubalcaba', + 'Opperman', + 'Decamp', + 'Fairfield', + 'Pauls', + 'Dicicco', + 'Northup', + 'Woerner', + 'Stegman', + 'Ritch', + 'Bedoya', + 'Jeanpierre', + 'Rioux', + 'Strohl', + 'Herrell', + 'Simonton', + 'Carriere', + 'Pridemore', + 'Karam', + 'Marple', + 'Topp', + 'Heiden', + 'Leibowitz', + 'Morabito', + 'Junker', + 'Calixto', + 'Hardt', + 'Silverio', + 'Swords', + 'Rickey', + 'Roussel', + 'Earles', + 'Bastien', + 'Defilippo', + 'Bigley', + 'Mosteller', + 'Issa', + 'Prout', + 'Grossi', + 'Bartos', + 'Lipman', + 'Colegrove', + 'Stpeter', + 'Vanfleet', + 'Fordyce', + 'Risher', + 'Royston', + 'Shoulders', + 'Mendel', + 'Statler', + 'Dantonio', + 'Inglis', + 'Fogleman', + 'Loveday', + 'Straus', + 'Luft', + 'Dam', + 'Chewning', + 'Winkel', + 'Bousquet', + 'Eckhart', + 'Dillinger', + 'Locascio', + 'Shellenberger', + 'Duerr', + 'Alcocer', + 'Licht', + 'Gingras', + 'Grassi', + 'Gately', + 'Padula', + 'Brien', + 'Nimmo', + 'Nell', + 'Bondurant', + 'Hughley', + 'Schalk', + 'Cabrales', + 'Heinemann', + 'Meunier', + 'Maddock', + 'Noone', + 'Brackin', + 'Dunnigan', + 'Sargeant', + 'Kinchen', + 'Veras', + 'Gile', + 'Bacchus', + 'Ang', + 'Cowgill', + 'Currey', + 'Garlick', + 'Manus', + 'Ballance', + 'Robitaille', + 'Begin', + 'Mijares', + 'Keogh', + 'Wicklund', + 'Mccurley', + 'Truett', + 'Pullin', + 'Alkire', + 'Loughran', + 'Mort', + 'Tatman', + 'Wanamaker', + 'Haralson', + 'Harrah', + 'Stucker', + 'Reda', + 'Pascal', + 'Holter', + 'Solares', + 'Bruck', + 'Mah', + 'Didomenico', + 'Korth', + 'Virgil', + 'Nishimura', + 'Vacca', + 'Stenberg', + 'Tomczak', + 'Sayler', + 'Chasse', + 'Blazer', + 'Sleeper', + 'Doiron', + 'Nunnery', + 'Ortman', + 'Maag', + 'Cali', + 'Ferrera', + 'Hotaling', + 'Festa', + 'Murr', + 'Sterrett', + 'Cuthbert', + 'Clayborn', + 'Pendergraft', + 'Yoakum', + 'Baily', + 'Overbey', + 'Warne', + 'Hokanson', + 'Tafolla', + 'Puglisi', + 'Wooster', + 'Nassar', + 'Lesniak', + 'Noack', + 'Beres', + 'Liberatore', + 'Guyette', + 'Duffin', + 'Ishmael', + 'Dolezal', + 'Larimer', + 'Musso', + 'Borman', + 'Deemer', + 'Hobgood', + 'Triggs', + 'Mau', + 'Wainscott', + 'Seth', + 'Hodnett', + 'Mckeehan', + 'Toon', + 'Evens', + 'Drost', + 'Roehl', + 'Trapani', + 'Bains', + 'Modica', + 'Arcos', + 'Knopf', + 'Salvo', + 'Garlock', + 'Lounsbury', + 'Hennen', + 'Drescher', + 'Morgenstern', + 'Studebaker', + 'Nordin', + 'Madore', + 'Joslyn', + 'Brousseau', + 'Addy', + 'Audette', + 'Santibanez', + 'Sauers', + 'Engelman', + 'Mauney', + 'Arechiga', + 'Eckel', + 'Jerry', + 'Pernell', + 'Sedlacek', + 'Mcnary', + 'Loewen', + 'Eyler', + 'Feather', + 'Mckinnie', + 'Bowersox', + 'Laclair', + 'Melby', + 'Thoman', + 'Hose', + 'Carmon', + 'Bartram', + 'Berggren', + 'Rogge', + 'Seto', + 'Court', + 'Deskins', + 'Barcus', + 'Putt', + 'Minick', + 'Durgin', + 'Hockman', + 'Keltner', + 'Legaspi', + 'Wallach', + 'Ranney', + 'Borger', + 'Wakeman', + 'Schoolcraft', + 'Souther', + 'Villani', + 'Sauder', + 'Chupp', + 'Slover', + 'Faul', + 'Degroat', + 'Hakim', + 'Brucker', + 'Moylan', + 'Castilleja', + 'Whetzel', + 'Eanes', + 'Brouwer', + 'Okelley', + 'Crimmins', + 'Bargas', + 'Jo', + 'Clover', + 'Adan', + 'Domingues', + 'Yelton', + 'Lobdell', + 'Mattis', + 'Escudero', + 'Pentecost', + 'Riser', + 'Lorentz', + 'Neace', + 'Caplinger', + 'Lipe', + 'Satterlee', + 'Labarbera', + 'Cullison', + 'Goggin', + 'Coke', + 'Keo', + 'Buckmaster', + 'Holtzclaw', + 'Lustig', + 'Ellinger', + 'Lollar', + 'Cork', + 'Mccrae', + 'Hilario', + 'Yawn', + 'Arnette', + 'Yuhas', + 'Wardle', + 'Pixley', + 'Leflore', + 'Fluker', + 'Krier', + 'Wind', + 'Ditto', + 'Rorie', + 'Ensminger', + 'Hunsucker', + 'Levenson', + 'Millington', + 'Gorsuch', + 'Willems', + 'Fredricks', + 'Agarwal', + 'Lariviere', + 'Don', + 'Chery', + 'Pfeil', + 'Wurtz', + 'Remillard', + 'Cozad', + 'Hodgkins', + 'Cohan', + 'Nurse', + 'Espana', + 'Giguere', + 'Hoskin', + 'Pettaway', + 'Keifer', + 'Yandell', + 'Frandsen', + 'Nawrocki', + 'Vila', + 'Pouliot', + 'Boulanger', + 'Pruden', + 'Strauch', + 'Lua', + 'Rohn', + 'Greig', + 'Lightsey', + 'Etheredge', + 'Hara', + 'Ensign', + 'Ruckman', + 'Senecal', + 'Sedgwick', + 'Maciejewski', + 'Morningstar', + 'Creswell', + 'Britten', + 'Godley', + 'Laubach', + 'Schwenk', + 'Hayhurst', + 'Cammarata', + 'Paxson', + 'Mcmurtry', + 'Marasco', + 'Weatherby', + 'Fales', + 'Fondren', + 'Deherrera', + 'Gaydos', + 'Defranco', + 'Bjorklund', + 'Silberman', + 'Maxon', + 'Rockey', + 'Brass', + 'Marcoux', + 'Marquette', + 'Marcello', + 'Veit', + 'Debose', + 'Cloninger', + 'Puccio', + 'Greenman', + 'Bross', + 'Lile', + 'Behan', + 'Plumlee', + 'Hampson', + 'Steverson', + 'Wininger', + 'Mcmullan', + 'Jude', + 'Sharif', + 'Rothermel', + 'Becher', + 'Keithley', + 'Gargano', + 'Morillo', + 'Dumond', + 'Johannsen', + 'Baney', + 'Lipton', + 'Railey', + 'Clowers', + 'Rotondo', + 'Simeone', + 'Hatt', + 'Schexnayder', + 'Snoddy', + 'Gelinas', + 'Mendelson', + 'Matherly', + 'Klock', + 'Clubb', + 'Dunkley', + 'Rosenzweig', + 'Chuang', + 'Gines', + 'Galasso', + 'Helland', + 'Rohrbaugh', + 'Avilez', + 'Czajkowski', + 'Olsson', + 'Lumsden', + 'Birt', + 'Ortego', + 'Acuff', + 'Yetter', + 'Tichenor', + 'Mork', + 'Skillman', + 'Row', + 'Lollis', + 'Wolk', + 'Demott', + 'Lazenby', + 'Bellew', + 'Brickner', + 'Ragusa', + 'Stice', + 'Herlihy', + 'Guillermo', + 'Estabrook', + 'Montijo', + 'Jenner', + 'Rayfield', + 'Donlon', + 'Greenhalgh', + 'Alberti', + 'Rix', + 'Holthaus', + 'Mistry', + 'Ruzicka', + 'Sievert', + 'Koopman', + 'Kalish', + 'Kehl', + 'Ponte', + 'Varnell', + 'Guss', + 'Kovac', + 'Hosmer', + 'Scrivner', + 'Tomblin', + 'Villafuerte', + 'Branscum', + 'Nitz', + 'Reider', + 'Gaunt', + 'Richerson', + 'Hemmer', + 'Vinyard', + 'Barrie', + 'Manalo', + 'Flynt', + 'Cadle', + 'Hau', + 'Uy', + 'Manfredi', + 'Deeter', + 'Resto', + 'Carnell', + 'Drane', + 'Cusumano', + 'Fein', + 'Schneck', + 'Stucky', + 'Heid', + 'Bruggeman', + 'Schweiger', + 'Vanetten', + 'Munsey', + 'Kiker', + 'Whittier', + 'Seeman', + 'Zerbe', + 'Hillyer', + 'Burkhead', + 'Gafford', + 'Gephart', + 'Braman', + 'Plott', + 'Henriques', + 'Coppock', + 'Mcandrews', + 'Valtierra', + 'Dileo', + 'Stiner', + 'Mikel', + 'Owensby', + 'Gupton', + 'Scurlock', + 'Gittens', + 'Degnan', + 'Guillaume', + 'Helmuth', + 'Nolin', + 'Mair', + 'Bergeson', + 'Paik', + 'Kinne', + 'Goodloe', + 'Nakagawa', + 'Raposo', + 'Defreitas', + 'Korb', + 'Hinkel', + 'Magers', + 'Althoff', + 'Rafael', + 'Akhtar', + 'Cashion', + 'Mcquillan', + 'Patricio', + 'Sweeny', + 'Meaux', + 'Tyre', + 'Demeo', + 'Trivedi', + 'Goodfellow', + 'Dunleavy', + 'Middaugh', + 'Barbato', + 'Pasco', + 'Harland', + 'Shorts', + 'Mowrey', + 'Dempster', + 'Knuckles', + 'Luebke', + 'Petrella', + 'Retana', + 'Licea', + 'Rundle', + 'Cape', + 'Lou', + 'Mcconkey', + 'Leeman', + 'Cabe', + 'Timothy', + 'Crochet', + 'Fulgham', + 'Glasco', + 'Backes', + 'Konopka', + 'Mcquaid', + 'Schley', + 'Abrahams', + 'Dahlin', + 'Iversen', + 'Chico', + 'Huffaker', + 'Modlin', + 'Laduke', + 'Marquart', + 'Motz', + 'Keech', + 'Louviere', + 'Como', + 'Fye', + 'Brightwell', + 'Yamashita', + 'Desrochers', + 'Richer', + 'Bourke', + 'Broadhead', + 'Pink', + 'Okamoto', + 'Chicas', + 'Vanatta', + 'Shick', + 'Furst', + 'Layfield', + 'Mcewan', + 'Baumgart', + 'Kappel', + 'Kucharski', + 'Quam', + 'Taub', + 'Houghtaling', + 'Sundquist', + 'Monks', + 'Wake', + 'Quiros', + 'Pursell', + 'Johansson', + 'Talkington', + 'Bast', + 'Stimson', + 'Hakes', + 'Loe', + 'Caggiano', + 'Schaper', + 'Chandra', + 'Tuma', + 'Arledge', + 'Romain', + 'Hornick', + 'Bridgman', + 'Livingstone', + 'Potvin', + 'Sparling', + 'Hause', + 'Trosclair', + 'Pless', + 'Szeto', + 'Clontz', + 'Lauber', + 'Detrick', + 'Dominique', + 'Mosser', + 'Degraff', + 'Liner', + 'Fleet', + 'Czerwinski', + 'Kopf', + 'Kovar', + 'Sheedy', + 'Zaremba', + 'Mina', + 'Sweeten', + 'Ou', + 'Musto', + 'Hennig', + 'Bangs', + 'Pasternak', + 'Berrier', + 'Smidt', + 'Brayton', + 'Claytor', + 'Ellerbe', + 'Reiman', + 'Larimore', + 'Ratzlaff', + 'Mudge', + 'Ni', + 'Spillers', + 'Cuomo', + 'Gerke', + 'Polizzi', + 'Harmer', + 'Apperson', + 'Regis', + 'Ugarte', + 'Paull', + 'Lagrange', + 'Dinwiddie', + 'Becton', + 'Gadsden', + 'Conforti', + 'Desoto', + 'Orme', + 'Filer', + 'Viers', + 'Lares', + 'Stair', + 'Hipps', + 'Kaneshiro', + 'Ladson', + 'Altizer', + 'Montejano', + 'Scalzo', + 'Sowder', + 'Ebeling', + 'Faucher', + 'Dicken', + 'Sartor', + 'Mcnerney', + 'Stage', + 'Mika', + 'Hice', + 'Grinstead', + 'Bartsch', + 'Mccumber', + 'Lenahan', + 'Liska', + 'Tietz', + 'Gauna', + 'Janda', + 'Bellis', + 'Shew', + 'Kelton', + 'Doby', + 'Golson', + 'Plaster', + 'Gonsales', + 'Krone', + 'Lape', + 'Lowrie', + 'Polly', + 'Gerardi', + 'Lamoreaux', + 'Bhatti', + 'Kimsey', + 'Buhl', + 'Arvin', + 'Gillian', + 'Benbow', + 'Roesler', + 'Stlaurent', + 'Canon', + 'Swihart', + 'Corea', + 'Petitt', + 'Spates', + 'Nappi', + 'Sebring', + 'Smelser', + 'Eckenrode', + 'Palos', + 'Disanto', + 'Tabares', + 'Okane', + 'Easterly', + 'Dendy', + 'Whigham', + 'Bednarz', + 'Wedge', + 'Edelen', + 'Stiff', + 'Borjas', + 'Obando', + 'Mcspadden', + 'Breed', + 'Dismuke', + 'Jarmon', + 'Serpa', + 'Lucky', + 'Cournoyer', + 'Hedberg', + 'Martine', + 'Michell', + 'Wittig', + 'Clodfelter', + 'Davids', + 'Gattis', + 'Kull', + 'Mascorro', + 'Schad', + 'Rine', + 'Bradburn', + 'Marie', + 'Czech', + 'Sunderman', + 'Wickersham', + 'Toohey', + 'Capozzi', + 'Poplin', + 'Markland', + 'Brosnan', + 'Fetterman', + 'Heiss', + 'Haglund', + 'Jourdan', + 'Turnipseed', + 'Tiernan', + 'Horrocks', + 'Barnhardt', + 'Sing', + 'Belford', + 'Baumgarten', + 'Klee', + 'Degeorge', + 'Caulder', + 'Gladstone', + 'Dancer', + 'Satchell', + 'Vento', + 'Larock', + 'Kimberly', + 'Hunn', + 'Harvin', + 'Krahn', + 'Ogorman', + 'Storch', + 'Coomes', + 'Bevilacqua', + 'Crotts', + 'Schillinger', + 'Morelock', + 'Hayworth', + 'Avis', + 'Cranmer', + 'Getchell', + 'Tena', + 'Buzzell', + 'Widman', + 'Barter', + 'Lafayette', + 'Asencio', + 'Embree', + 'Krell', + 'Siders', + 'Fuselier', + 'Whitby', + 'Elsner', + 'Pando', + 'Surface', + 'Rolf', + 'Highland', + 'Bufford', + 'Scheidt', + 'Defrancesco', + 'Fellers', + 'Carrol', + 'Germano', + 'Licon', + 'Hilty', + 'Ringo', + 'Dowler', + 'Glowacki', + 'Slabaugh', + 'Tomasello', + 'Messing', + 'Lavalle', + 'Milo', + 'Frerichs', + 'Plotkin', + 'Ziolkowski', + 'Gentle', + 'Knobloch', + 'Larochelle', + 'Duell', + 'Hurdle', + 'Speller', + 'Ceasar', + 'Vinci', + 'Mosquera', + 'Wyse', + 'Towler', + 'Ayoub', + 'Gullickson', + 'Spade', + 'Forshee', + 'Cliff', + 'Gholson', + 'Reichenbach', + 'Lockman', + 'Morones', + 'Storie', + 'Bissett', + 'Janney', + 'Durocher', + 'Fentress', + 'Troiano', + 'Boes', + 'Rouleau', + 'Rall', + 'Sultan', + 'Braggs', + 'Bethke', + 'Schacht', + 'Straley', + 'Mcfalls', + 'Fahy', + 'Winegar', + 'Gorecki', + 'Rudnick', + 'Wigginton', + 'Dedrick', + 'Sthilaire', + 'Lovette', + 'Hanneman', + 'Loch', + 'Moores', + 'Polen', + 'Anchondo', + 'Rosato', + 'Tindell', + 'Hunsicker', + 'Penna', + 'Privette', + 'Gayton', + 'Sliger', + 'Wink', + 'Brummer', + 'Crown', + 'Sommerville', + 'Mastrangelo', + 'Latimore', + 'Merlino', + 'Thoreson', + 'Kleiner', + 'Able', + 'Boose', + 'Loyola', + 'Jimenes', + 'Lapham', + 'Srinivasan', + 'Hammers', + 'Mo', + 'Evert', + 'Vanslyke', + 'Caywood', + 'Gremillion', + 'Rauscher', + 'Eckhoff', + 'Dearth', + 'Sinha', + 'Becerril', + 'Tuten', + 'Greenwalt', + 'Curlee', + 'Burgan', + 'Feagin', + 'Gallman', + 'Germann', + 'Swensen', + 'Vanallen', + 'Bissonnette', + 'Stoudt', + 'Handler', + 'Tanguay', + 'Lovins', + 'Smotherman', + 'Cutts', + 'Herod', + 'Maclin', + 'Arcuri', + 'Hackbarth', + 'Breazeale', + 'Rainville', + 'Crick', + 'Macintosh', + 'Bloss', + 'Fridley', + 'Stefanski', + 'Beauvais', + 'Koop', + 'Andes', + 'Blomberg', + 'Vallee', + 'Lanigan', + 'Blouin', + 'Rochon', + 'Dorazio', + 'Drouin', + 'Lamonica', + 'Wilbourn', + 'Spraggins', + 'Rieder', + 'Shugart', + 'Chacko', + 'Rutan', + 'Nutting', + 'Lawley', + 'Landy', + 'January', + 'Blowers', + 'Handel', + 'Doman', + 'Swiney', + 'Ettinger', + 'Jellison', + 'Veilleux', + 'Wiens', + 'Raimondi', + 'Spink', + 'Emond', + 'Yale', + 'Rachel', + 'Alldredge', + 'Lach', + 'Morlan', + 'Wayland', + 'Colquitt', + 'Gabrielson', + 'Mccarver', + 'Frances', + 'Granville', + 'Costigan', + 'Preuss', + 'Lentini', + 'Vansant', + 'Mosca', + 'Connally', + 'Frei', + 'Laplant', + 'Lago', + 'Leiter', + 'Trumbull', + 'Shaeffer', + 'Gongora', + 'Coady', + 'Fyffe', + 'Mance', + 'Worcester', + 'Zehner', + 'Bodie', + 'Burnes', + 'Pompey', + 'Teitelbaum', + 'Beaupre', + 'Visconti', + 'Mumma', + 'Markiewicz', + 'Piscitelli', + 'Moak', + 'Bourland', + 'Pennock', + 'Hannum', + 'Robichaux', + 'Folks', + 'Coppage', + 'Heffron', + 'Mullet', + 'Kimberlin', + 'Breneman', + 'Blandford', + 'Matthias', + 'Engebretson', + 'Roessler', + 'Allee', + 'Parkman', + 'Barge', + 'Ren', + 'Backstrom', + 'Bullen', + 'Lampman', + 'Loesch', + 'Echavarria', + 'Haman', + 'Cortina', + 'Elms', + 'Gordan', + 'Pabst', + 'Snelson', + 'Vanarsdale', + 'Pecora', + 'Rabago', + 'Enger', + 'Senger', + 'Dewees', + 'Semple', + 'Howey', + 'Westlund', + 'Daw', + 'Hagemann', + 'Mcpeek', + 'Vanderhoof', + 'Ohler', + 'Bohm', + 'Mazzone', + 'Arnott', + 'Bouton', + 'Fackler', + 'Giunta', + 'Stagner', + 'Tavera', + 'Poorman', + 'Buch', + 'Mangano', + 'Bonar', + 'Gerson', + 'Ranger', + 'Mccullar', + 'Wunder', + 'Bade', + 'Armand', + 'Chalfant', + 'Lichtenstein', + 'Turco', + 'Degraw', + 'Few', + 'Haigler', + 'Lis', + 'Bittinger', + 'Morrone', + 'Hodgdon', + 'Wittenberg', + 'Imes', + 'Dreiling', + 'Landwehr', + 'Maly', + 'Warlick', + 'Terpstra', + 'Bolte', + 'Stiller', + 'Stmartin', + 'Pankratz', + 'Albee', + 'Victory', + 'Lezama', + 'Brecht', + 'Monarrez', + 'Thurlow', + 'Laskey', + 'Bothwell', + 'Candler', + 'Esh', + 'Kalman', + 'Samano', + 'Yohe', + 'Regnier', + 'Leite', + 'Ballantyne', + 'Dan', + 'Fikes', + 'Cendejas', + 'Mikula', + 'Fairman', + 'Dragon', + 'Manzella', + 'Renninger', + 'Leaman', + 'Godbey', + 'Current', + 'Mirabal', + 'Boerner', + 'Depaz', + 'Birge', + 'Westberry', + 'Severin', + 'Weddington', + 'Longenecker', + 'Mccreery', + 'Lebel', + 'Nader', + 'Gan', + 'Auguste', + 'Colonna', + 'Paramo', + 'Minyard', + 'Duley', + 'Beil', + 'Salters', + 'Brindley', + 'Simmers', + 'Lumpkins', + 'Crisman', + 'Raulerson', + 'Lanz', + 'Deroche', + 'Kemmerer', + 'Bogner', + 'Mahn', + 'Willer', + 'Gunnels', + 'Warford', + 'Reason', + 'Scherr', + 'Digirolamo', + 'Hallowell', + 'Wilcoxson', + 'Gaillard', + 'Deshields', + 'Hively', + 'Sakai', + 'Creason', + 'Jaber', + 'Lapinski', + 'Bolivar', + 'Millwood', + 'Shumpert', + 'Fujii', + 'Plemmons', + 'Lamere', + 'Cleghorn', + 'Mccaw', + 'Seavey', + 'Zwick', + 'Hosler', + 'Lepley', + 'Marden', + 'Cornwall', + 'Gauger', + 'Hofmeister', + 'Bugarin', + 'Loose', + 'Guardiola', + 'Hertzog', + 'Bigger', + 'Heineman', + 'Retzlaff', + 'Rizzuto', + 'Flannigan', + 'Rathburn', + 'Moulder', + 'Town', + 'Gautier', + 'Hamid', + 'Torrance', + 'Walthall', + 'Windom', + 'Kleckner', + 'Kirwan', + 'Gasaway', + 'Pinkard', + 'Concannon', + 'Mcquiston', + 'Yow', + 'Eshleman', + 'Riggleman', + 'Foulk', + 'Bolles', + 'Craine', + 'Hinnant', + 'Gholston', + 'Lebo', + 'Torkelson', + 'Mancia', + 'Canale', + 'Celestin', + 'Neubert', + 'Schmaltz', + 'Highfill', + 'Fisch', + 'Matte', + 'Hoefer', + 'Flippin', + 'Mclin', + 'Mikkelson', + 'Gump', + 'Kilroy', + 'Ensor', + 'Klosterman', + 'Ruppel', + 'Steffey', + 'Sauve', + 'Cessna', + 'Apgar', + 'Jacobus', + 'Pettyjohn', + 'Northington', + 'Smithey', + 'Moro', + 'Dossett', + 'Mccroskey', + 'Yelverton', + 'Mascarenas', + 'Hebb', + 'Quinteros', + 'Giang', + 'Pontius', + 'Sipple', + 'Atkin', + 'Howington', + 'Hiebert', + 'Lingerfelt', + 'Schueler', + 'Sailer', + 'Smits', + 'Keeter', + 'Macrae', + 'Mease', + 'Shortridge', + 'Scates', + 'Amstutz', + 'Kuebler', + 'Cambron', + 'Eaker', + 'Finlayson', + 'Bookout', + 'Mullett', + 'Bank', + 'Schlenker', + 'Morlock', + 'Haskett', + 'Dade', + 'Gallucci', + 'Lahey', + 'Ryerson', + 'Crownover', + 'Banfield', + 'Mcclay', + 'Diggins', + 'Conerly', + 'Primus', + 'Syverson', + 'Prindle', + 'Blasingame', + 'Deford', + 'Garnes', + 'Hoisington', + 'Glasper', + 'Lorusso', + 'Hesson', + 'Youssef', + 'Threlkeld', + 'Talmadge', + 'Winfree', + 'Heacock', + 'Rawlinson', + 'Burse', + 'Diederich', + 'Niemiec', + 'Norby', + 'Bauder', + 'Scranton', + 'Prentiss', + 'Towles', + 'Henton', + 'Purifoy', + 'Pinzon', + 'Edler', + 'Ragin', + 'Albarado', + 'Cuadra', + 'Hoadley', + 'Devita', + 'Pavon', + 'Alday', + 'Goulding', + 'Millis', + 'Dalley', + 'Kolodziej', + 'Kropf', + 'Kuiper', + 'Crespin', + 'Xavier', + 'Sailor', + 'Lagrone', + 'Boehme', + 'Tidd', + 'Wilmore', + 'Ziemer', + 'Ropp', + 'Kettler', + 'Pilon', + 'Miron', + 'Salsbury', + 'Job', + 'Sensenig', + 'Cayton', + 'Nanney', + 'Rasch', + 'Silvestre', + 'Ladue', + 'Dampier', + 'Ackermann', + 'Friedel', + 'Kleiman', + 'Geronimo', + 'Ezzell', + 'Duclos', + 'Moor', + 'Neuhaus', + 'Lan', + 'Allender', + 'Tedeschi', + 'Langton', + 'Dawley', + 'Kearse', + 'Godina', + 'Guernsey', + 'Kober', + 'Bisbee', + 'Lamphere', + 'Kinman', + 'Wesner', + 'Malo', + 'Stroupe', + 'Millette', + 'Yeoman', + 'Baig', + 'Kirchoff', + 'Tsao', + 'Cristobal', + 'Mucci', + 'Pair', + 'Barefield', + 'Dewolf', + 'Fitzmaurice', + 'Mcaleer', + 'Natal', + 'Bara', + 'Macey', + 'Mclennan', + 'Fabre', + 'Vieyra', + 'Magno', + 'Eyre', + 'Chatterton', + 'Gilland', + 'Hurlbut', + 'Umberger', + 'Roloff', + 'Brambila', + 'Mazzeo', + 'Letson', + 'Norsworthy', + 'Bier', + 'Gioia', + 'Kapoor', + 'Marlatt', + 'Flippo', + 'Houde', + 'Baughn', + 'Blackledge', + 'Fly', + 'Dinkel', + 'Rathbone', + 'Bober', + 'Boydston', + 'Ferdinand', + 'Coletti', + 'Cuenca', + 'Deters', + 'Blagg', + 'Timmins', + 'Boyden', + 'Meads', + 'Narcisse', + 'Saelee', + 'Cosner', + 'Strawser', + 'Amico', + 'Dowdle', + 'Golub', + 'Silverberg', + 'Riles', + 'Balk', + 'Buhr', + 'Feltman', + 'Stickel', + 'Zapien', + 'Cargile', + 'Kulik', + 'Lazzaro', + 'Oberle', + 'Wickstrom', + 'Maeda', + 'Cockrum', + 'Boulton', + 'Sandford', + 'Culbert', + 'Dula', + 'Ament', + 'Chunn', + 'Owenby', + 'Wasilewski', + 'Wichman', + 'Oestreich', + 'Klos', + 'Orchard', + 'Hogge', + 'Presson', + 'Cordon', + 'Gans', + 'Leonardi', + 'Manjarrez', + 'Olander', + 'Drennen', + 'Wirt', + 'Tiger', + 'Dolce', + 'Hagstrom', + 'Hirsh', + 'Tally', + 'Crumbley', + 'Mcgreevy', + 'Amidon', + 'Olague', + 'Lint', + 'Poche', + 'Lipford', + 'Engen', + 'Mcelfresh', + 'Cuneo', + 'Krumm', + 'Haak', + 'Arocho', + 'Longworth', + 'Seamon', + 'Bronner', + 'Swartzentruber', + 'Chand', + 'Wilhoit', + 'Chapel', + 'Hitchens', + 'Brzezinski', + 'Heidenreich', + 'Ellenberger', + 'Gamblin', + 'Ormond', + 'Burchard', + 'Dibella', + 'Nicoll', + 'Simcox', + 'Strohm', + 'Dittmar', + 'Wycoff', + 'Grays', + 'Spero', + 'Vess', + 'Picone', + 'Greening', + 'Maynes', + 'Knauss', + 'Wojtowicz', + 'Chaput', + 'Soliman', + 'Ponton', + 'Carlino', + 'Kestner', + 'Kelch', + 'Dimauro', + 'Iorio', + 'Parenteau', + 'Pesina', + 'Clauson', + 'Stigall', + 'Keels', + 'Waldrep', + 'Wix', + 'Draeger', + 'Ertel', + 'Starner', + 'Charest', + 'Simoneaux', + 'Ivanov', + 'Thor', + 'Gravel', + 'Trottier', + 'Clendenin', + 'Kromer', + 'Benda', + 'Touchet', + 'Hornbuckle', + 'Avent', + 'Dombroski', + 'Friedland', + 'Radabaugh', + 'Vesely', + 'Wike', + 'Lax', + 'Messersmith', + 'Deoliveira', + 'Brey', + 'Cogdill', + 'Overturf', + 'Sova', + 'Pero', + 'Beaird', + 'Cevallos', + 'Defalco', + 'Taormina', + 'Thornberry', + 'Westervelt', + 'Macaulay', + 'Hajek', + 'Brugger', + 'Leff', + 'Ketterer', + 'Ono', + 'Mullenix', + 'Frison', + 'Gullo', + 'Calhoon', + 'Summey', + 'Hockaday', + 'Dimatteo', + 'Agan', + 'Patenaude', + 'Mary', + 'Tanis', + 'Obert', + 'Elton', + 'Randles', + 'Migliore', + 'Schmalz', + 'Vanvalkenburg', + 'Quinto', + 'Palmquist', + 'Hoops', + 'Naples', + 'Orear', + 'Eberhard', + 'Fitzgibbons', + 'Adkinson', + 'Gerace', + 'Elie', + 'Dressel', + 'Silber', + 'Otey', + 'Hsiao', + 'Kreutzer', + 'Tutor', + 'Roundy', + 'Haddox', + 'Bridgers', + 'Leto', + 'Daniell', + 'Pollitt', + 'Freda', + 'Mraz', + 'Engelbrecht', + 'Ariza', + 'Grand', + 'Pavone', + 'Everts', + 'Benes', + 'Reamer', + 'Faucett', + 'Eatmon', + 'Raymundo', + 'Zaman', + 'Devitt', + 'Master', + 'Carron', + 'Hoffner', + 'Sciortino', + 'Stringham', + 'Bookman', + 'Westberg', + 'Spahn', + 'Hise', + 'Waterbury', + 'Buckwalter', + 'Hug', + 'Overly', + 'Dingus', + 'Ince', + 'Haar', + 'Shain', + 'Heaps', + 'Oppenheimer', + 'Miyamoto', + 'Schreier', + 'Martello', + 'Atteberry', + 'Folger', + 'Macke', + 'Pal', + 'Lucchesi', + 'Osterhout', + 'Liriano', + 'Legge', + 'Barra', + 'Crumb', + 'Gwyn', + 'Forst', + 'Axelrod', + 'Samayoa', + 'Edgell', + 'Purkey', + 'Lannon', + 'Branam', + 'Yeo', + 'Hatmaker', + 'Borum', + 'Villagrana', + 'Lawing', + 'Bark', + 'Muirhead', + 'Eckles', + 'Weight', + 'Surles', + 'Cullinan', + 'Lagos', + 'Naber', + 'Sloat', + 'Foos', + 'Vine', + 'Milliner', + 'Reliford', + 'Dahlquist', + 'Gibney', + 'Moroney', + 'Stecker', + 'Bella', + 'Brickhouse', + 'Canela', + 'Kula', + 'Tartaglia', + 'Siewert', + 'Hitch', + 'Brickman', + 'Cheeseman', + 'Carollo', + 'Geissler', + 'Jiron', + 'Cossey', + 'Sroka', + 'Border', + 'Brownlow', + 'Ellenburg', + 'Cella', + 'Brinton', + 'Scurry', + 'Behrendt', + 'Carstensen', + 'Schendel', + 'Bodner', + 'Eddleman', + 'Stec', + 'Capasso', + 'Leu', + 'Kennett', + 'Ruane', + 'Critchfield', + 'Carbonell', + 'Mitcham', + 'Troncoso', + 'Mckeen', + 'Cammack', + 'Broach', + 'Culbreath', + 'Callejas', + 'Wurst', + 'Brookman', + 'Guerrier', + 'Seese', + 'Kitzmiller', + 'Graybeal', + 'Yardley', + 'Cheever', + 'Virgin', + 'Brimmer', + 'Swoboda', + 'Pandya', + 'Canton', + 'Magnus', + 'Draughn', + 'Dilts', + 'Tauber', + 'Vandegrift', + 'Rene', + 'Cousineau', + 'Joo', + 'Pimental', + 'Carpentier', + 'Eager', + 'Cumberland', + 'Eastridge', + 'Moberly', + 'Erhardt', + 'Meldrum', + 'Degennaro', + 'Desanto', + 'Manahan', + 'Gowdy', + 'Popham', + 'Mee', + 'Kinslow', + 'Harned', + 'Cartee', + 'Raiford', + 'Henrichs', + 'Maffei', + 'Seamans', + 'Heckel', + 'Toll', + 'Milian', + 'Mabrey', + 'Dall', + 'Lanford', + 'Carew', + 'Bascom', + 'Christofferson', + 'Hadfield', + 'Ferber', + 'Mestas', + 'Leith', + 'Abston', + 'Cuddy', + 'Svendsen', + 'Cowling', + 'Segars', + 'Nalls', + 'Hofstetter', + 'Badgley', + 'Mccaffery', + 'Burner', + 'Laymon', + 'Pinion', + 'Schooler', + 'Brun', + 'Aldaco', + 'Savarese', + 'Gravelle', + 'Belvin', + 'Brekke', + 'Dekker', + 'Ellefson', + 'Lurie', + 'Cassity', + 'Epperly', + 'Genova', + 'Dehn', + 'Fargo', + 'Vanderford', + 'Sine', + 'Horrell', + 'Napoleon', + 'Kamm', + 'Riel', + 'Gerena', + 'Check', + 'Devane', + 'Grissett', + 'Brendel', + 'Weyant', + 'Basurto', + 'Coppinger', + 'Grosse', + 'Saeed', + 'Lunceford', + 'Washam', + 'Benard', + 'Eastham', + 'Holleran', + 'Kiesel', + 'Risch', + 'Mccullen', + 'Vizcaino', + 'Fullen', + 'Westbrooks', + 'Babich', + 'Mauch', + 'Hensler', + 'Bryner', + 'Phillippi', + 'Santistevan', + 'Jalbert', + 'Vanorden', + 'Brantner', + 'Mcgrail', + 'Rustin', + 'Lebaron', + 'Genao', + 'Quast', + 'Hamburg', + 'Mensah', + 'Heckler', + 'Popa', + 'Mantooth', + 'Hargreaves', + 'Jury', + 'Seiber', + 'Calton', + 'Lafreniere', + 'Starbuck', + 'Gow', + 'Veazey', + 'Kneeland', + 'Woodberry', + 'Vallone', + 'Sutcliffe', + 'Loh', + 'Wiltse', + 'Choudhury', + 'Rollo', + 'Bjerke', + 'Huffstetler', + 'Ogren', + 'Legere', + 'Wilmer', + 'Conboy', + 'Pressler', + 'Hon', + 'Monger', + 'Devos', + 'Houtz', + 'Shurtleff', + 'Sedlak', + 'Carolan', + 'Luc', + 'Immel', + 'Guizar', + 'Kron', + 'Lusby', + 'Whitsett', + 'Pryce', + 'Mengel', + 'Youngberg', + 'Kluge', + 'Thrush', + 'Wilsey', + 'Santee', + 'Braham', + 'Palmeri', + 'Cousino', + 'Willits', + 'Gram', + 'Dearmond', + 'Fonville', + 'Sabatini', + 'Nehring', + 'Henne', + 'Prager', + 'Mederos', + 'Schuldt', + 'Weisz', + 'Mccart', + 'Warriner', + 'Bartelt', + 'Dimond', + 'Mccubbin', + 'Say', + 'Mickel', + 'Bracamonte', + 'Volkman', + 'Brindle', + 'Bitter', + 'Dickie', + 'Inge', + 'Brinegar', + 'Lerman', + 'Bohan', + 'Rondon', + 'Dilbeck', + 'Rumbaugh', + 'Simard', + 'Berke', + 'Ealey', + 'Knauer', + 'Michalek', + 'Smolinski', + 'Wurster', + 'Zullo', + 'Nott', + 'Claar', + 'Mayor', + 'Moir', + 'Hubbert', + 'Hankerson', + 'Mok', + 'Simko', + 'Mumm', + 'Sheely', + 'Abramowitz', + 'Pusateri', + 'Boomer', + 'Chappelle', + 'Demery', + 'Coniglio', + 'Asay', + 'Nova', + 'Biel', + 'Delancey', + 'Tocco', + 'Tant', + 'Melin', + 'Lacoste', + 'Derrico', + 'Stacks', + 'Watley', + 'Stoneking', + 'Westrick', + 'Pons', + 'Malm', + 'Parekh', + 'Loop', + 'Kitt', + 'Crisostomo', + 'Ecklund', + 'Tollison', + 'Dziedzic', + 'Pillsbury', + 'Baumer', + 'Matsuda', + 'Jeon', + 'Foye', + 'Peltz', + 'Candela', + 'Levey', + 'Organ', + 'Hathorn', + 'Galeano', + 'Nies', + 'Cabezas', + 'Barras', + 'Pier', + 'Truss', + 'Leist', + 'Lheureux', + 'Nakano', + 'Ladwig', + 'Grunwald', + 'Centers', + 'Sherrard', + 'Morais', + 'Juhl', + 'Ivers', + 'Dunfee', + 'Jolliff', + 'Breeze', + 'Tapper', + 'Goodridge', + 'Kelliher', + 'Finck', + 'Roose', + 'Gauvin', + 'Coil', + 'Pounders', + 'Lobb', + 'Stalcup', + 'Swanner', + 'Boivin', + 'Neer', + 'Laxton', + 'Pai', + 'Postma', + 'Janus', + 'Didier', + 'Engleman', + 'League', + 'Fray', + 'Aguillon', + 'Richins', + 'Tolar', + 'Criner', + 'Rowlands', + 'Verdi', + 'Utt', + 'Winders', + 'Turbeville', + 'Rada', + 'Mcnichols', + 'Boddy', + 'Binford', + 'Amey', + 'Schultze', + 'Sontag', + 'Saleem', + 'Przybylski', + 'Vanderlinden', + 'Vanfossen', + 'Longacre', + 'Heasley', + 'Southwell', + 'Decesare', + 'Munch', + 'Minix', + 'Hymes', + 'Klopp', + 'Militello', + 'Schuessler', + 'Velazco', + 'Jurek', + 'Claycomb', + 'Diemer', + 'Roser', + 'Huse', + 'Perkinson', + 'Musa', + 'Leavy', + 'Seidman', + 'Vroman', + 'Stalter', + 'Grieve', + 'Aron', + 'Purdie', + 'Dusek', + 'Rago', + 'Shepler', + 'Leopard', + 'Araya', + 'Rutt', + 'Voth', + 'Hittle', + 'Husain', + 'Gratton', + 'Seigler', + 'Coppedge', + 'Nicastro', + 'Fitzgibbon', + 'Sosebee', + 'Tank', + 'Troche', + 'Delph', + 'Ryland', + 'Mazzella', + 'Rai', + 'Strecker', + 'Epp', + 'Clower', + 'Porche', + 'Gelman', + 'Herrman', + 'Balser', + 'Tosh', + 'Bonn', + 'Cerrato', + 'Varley', + 'Dingess', + 'Goodspeed', + 'Boller', + 'Heimann', + 'Gottfried', + 'Super', + 'Falzone', + 'Bizzell', + 'Litwin', + 'Ji', + 'Rogowski', + 'Tindle', + 'Hoye', + 'Balfour', + 'Focht', + 'Manz', + 'Stender', + 'Sutterfield', + 'Bayes', + 'Mullings', + 'Dockter', + 'Figueiredo', + 'Kepner', + 'Posadas', + 'Nettleton', + 'Ruder', + 'Younce', + 'Flanary', + 'Scotti', + 'Bayliss', + 'Tandy', + 'Henrickson', + 'Volker', + 'Letts', + 'Joines', + 'Fewell', + 'Wherry', + 'Stelzer', + 'Stever', + 'Viator', + 'Catt', + 'Jeffords', + 'Guerriero', + 'Milby', + 'Jozwiak', + 'Slawson', + 'Portwood', + 'Billie', + 'Borunda', + 'Chinchilla', + 'Papadopoulos', + 'Lohse', + 'Mantz', + 'Gabriele', + 'Hosford', + 'Kohut', + 'Tardiff', + 'Puma', + 'Bodin', + 'Hodgins', + 'Boon', + 'Golightly', + 'Bogert', + 'Abdi', + 'Wigfall', + 'Fleischmann', + 'Nease', + 'Rayborn', + 'Zigler', + 'Reimann', + 'Malagon', + 'Puls', + 'Grogg', + 'Drinkwater', + 'Dacus', + 'Mcfee', + 'Domino', + 'Harjo', + 'Pascarella', + 'Spengler', + 'Copple', + 'Rollings', + 'Brew', + 'Brabham', + 'Nordquist', + 'Emig', + 'Riggio', + 'Sanson', + 'Gerardo', + 'Pereda', + 'Renken', + 'Stickley', + 'Milliron', + 'Rolling', + 'Hollie', + 'Biondi', + 'Fluharty', + 'Magyar', + 'Balsamo', + 'Imler', + 'Hanlin', + 'Dycus', + 'Kirkley', + 'Wimberley', + 'Finan', + 'Kulkarni', + 'Morreale', + 'Briner', + 'Pelzer', + 'Bouie', + 'Fenstermaker', + 'Gimenez', + 'Labella', + 'Scherrer', + 'Holzman', + 'Winer', + 'Wrigley', + 'Leighty', + 'Liptak', + 'Chamness', + 'Franko', + 'Arwood', + 'Tiner', + 'Schoenberger', + 'Gear', + 'Hereford', + 'Slezak', + 'Longfellow', + 'Cull', + 'Brashears', + 'Clear', + 'Zielke', + 'Arden', + 'Bonneau', + 'Muck', + 'Tarvin', + 'Beran', + 'Coulombe', + 'Toothman', + 'Ghosh', + 'Mcguirk', + 'Pinero', + 'Ruan', + 'Gartman', + 'Peed', + 'Cassano', + 'Forcier', + 'Haque', + 'Veatch', + 'Fodor', + 'Wetherington', + 'Barrette', + 'Bottorff', + 'Holmstrom', + 'Honda', + 'Kopecky', + 'Loaiza', + 'Castelan', + 'Haydon', + 'Lamotte', + 'Mutchler', + 'Mahmoud', + 'Gleaton', + 'Rebollar', + 'Moctezuma', + 'Tannehill', + 'Bernardino', + 'Walrath', + 'Adcox', + 'Heidt', + 'Rakowski', + 'Soza', + 'Limas', + 'Wysong', + 'Mannix', + 'Pattillo', + 'Corner', + 'Kuang', + 'Loflin', + 'Ledger', + 'Ivery', + 'Likens', + 'Mctaggart', + 'Hartin', + 'Prange', + 'Stenzel', + 'Shadle', + 'Karn', + 'Duplantis', + 'Garibaldi', + 'Batty', + 'Goulart', + 'Ranck', + 'Beekman', + 'Nicolosi', + 'Arizmendi', + 'Donoho', + 'Drewry', + 'Lenihan', + 'Spatz', + 'Wible', + 'Dimmick', + 'Stelter', + 'Seyler', + 'Stringfield', + 'Bonaparte', + 'Dematteo', + 'Petrey', + 'Bellino', + 'Cavaliere', + 'Thaler', + 'Heiner', + 'Lillis', + 'Hammes', + 'Rainbolt', + 'Hillyard', + 'Farnum', + 'Overmyer', + 'Replogle', + 'Sclafani', + 'Audet', + 'Santa', + 'Hollen', + 'Lineberger', + 'Bonnet', + 'Caples', + 'Dahlen', + 'Ruggieri', + 'Keppler', + 'Ryman', + 'Copas', + 'Lyda', + 'Pusey', + 'Bostrom', + 'Patnode', + 'Richeson', + 'Hamil', + 'Wyss', + 'Mcadam', + 'Dennett', + 'Lever', + 'Drinkard', + 'Ohl', + 'Restivo', + 'Vyas', + 'Moyle', + 'Blauvelt', + 'Gregson', + 'Scull', + 'Verret', + 'Stines', + 'Forsman', + 'Gehman', + 'Watrous', + 'Gunnell', + 'Choice', + 'Castaldo', + 'Pietrzak', + 'Goodsell', + 'Klima', + 'Stratman', + 'Foutz', + 'Massingill', + 'Huneycutt', + 'Zellmer', + 'Tefft', + 'Hamblen', + 'Baggs', + 'Mcgarity', + 'Alfieri', + 'Stetler', + 'Hershman', + 'Fuerst', + 'Granda', + 'Villafane', + 'Stocking', + 'Laguerre', + 'Salvato', + 'Mcniel', + 'Trim', + 'Goldston', + 'Tannenbaum', + 'Laforge', + 'Hawker', + 'Innis', + 'Rasheed', + 'Marbury', + 'Jules', + 'Harpster', + 'Hruska', + 'Mancillas', + 'Ruck', + 'Schloss', + 'Shy', + 'Leming', + 'Eich', + 'Allain', + 'Premo', + 'Goodner', + 'Karlin', + 'Natoli', + 'Sinn', + 'Althouse', + 'Bodiford', + 'Krishnan', + 'Snedeker', + 'Weigle', + 'Blohm', + 'Renwick', + 'Menzies', + 'Stonebraker', + 'Brunetti', + 'Crompton', + 'Hucks', + 'Maharaj', + 'Bangert', + 'Hepp', + 'Kammer', + 'Sutliff', + 'Doyon', + 'Hutsell', + 'Cumbie', + 'Dibiase', + 'Linke', + 'Sapienza', + 'Sprayberry', + 'Sundstrom', + 'Vanbeek', + 'Ewart', + 'Erlandson', + 'Knutsen', + 'Nicolai', + 'Oros', + 'Almquist', + 'Tedrow', + 'Diebold', + 'Bellman', + 'Sherrer', + 'Ehret', + 'Ota', + 'Seman', + 'Folse', + 'Amy', + 'Mcateer', + 'Steinhauer', + 'Vannatta', + 'Holle', + 'Carreras', + 'Anger', + 'Clinkscales', + 'Castiglione', + 'Zakrzewski', + 'Principe', + 'Artman', + 'Waiters', + 'Tarbox', + 'Sippel', + 'Belz', + 'Joachim', + 'Pipkins', + 'Peterkin', + 'Abalos', + 'Flock', + 'Brochu', + 'Tobler', + 'Mckinnis', + 'Gatson', + 'Cronan', + 'Manthey', + 'Oberholtzer', + 'Schiltz', + 'Skowronski', + 'Matute', + 'Castonguay', + 'Bechard', + 'Drees', + 'Carte', + 'Baysinger', + 'Kees', + 'Steve', + 'Ratchford', + 'Clopton', + 'Heimbach', + 'Selig', + 'Peavey', + 'Sidney', + 'Hilliker', + 'Oehler', + 'Essig', + 'Ownby', + 'Huling', + 'Aylward', + 'Matzke', + 'Mikkelsen', + 'Vandam', + 'Rodden', + 'Plunk', + 'Mcdonell', + 'Buechler', + 'Dahm', + 'Tarlton', + 'Funches', + 'Alvidrez', + 'Padua', + 'Pingel', + 'Cid', + 'Mcburney', + 'Brunton', + 'Dwight', + 'Bucio', + 'Schiffer', + 'Dyal', + 'Cyphers', + 'Gildea', + 'Wengerd', + 'Lappin', + 'Longwell', + 'Basil', + 'Acklin', + 'Cancino', + 'Kalina', + 'Tynan', + 'Raasch', + 'Fleener', + 'Dunmire', + 'Gent', + 'Cruickshank', + 'Baltimore', + 'Shum', + 'Vanpatten', + 'Costilla', + 'Grimshaw', + 'Loar', + 'Royse', + 'Amon', + 'Amendola', + 'Mcgonagle', + 'Alm', + 'Hausmann', + 'Heitzman', + 'Mailloux', + 'Brault', + 'Capra', + 'Levis', + 'Barillas', + 'Quandt', + 'Fedele', + 'Chittenden', + 'Cheesman', + 'Wildes', + 'Bolan', + 'Metoyer', + 'Ciccarelli', + 'Melara', + 'Gano', + 'Janowski', + 'Magoon', + 'Kuster', + 'Ofarrell', + 'Joplin', + 'Cannella', + 'Middendorf', + 'Putz', + 'Saephan', + 'Sieg', + 'Lainez', + 'Roten', + 'Buras', + 'Nock', + 'Manke', + 'Hymel', + 'Devaughn', + 'Braverman', + 'Fleisher', + 'Persson', + 'Sandidge', + 'Corsi', + 'Torok', + 'Steinhoff', + 'Corby', + 'Shorey', + 'Wooton', + 'Estell', + 'Bolander', + 'Vivar', + 'Cuesta', + 'Renick', + 'Isler', + 'Caprio', + 'Crissman', + 'Wann', + 'Matchett', + 'Calahan', + 'Escareno', + 'Liguori', + 'Helt', + 'Boner', + 'Luper', + 'Hoppes', + 'Ingold', + 'Gilleland', + 'Saathoff', + 'Szczepanski', + 'Yockey', + 'Veith', + 'Wasser', + 'Denniston', + 'Fretwell', + 'Goetsch', + 'Havel', + 'Banach', + 'Schaal', + 'Nisbet', + 'Depaul', + 'Escalona', + 'Gammons', + 'Schmelzer', + 'Wehrle', + 'Guglielmo', + 'Oberlander', + 'Wolski', + 'Dimick', + 'Rebello', + 'Braunstein', + 'Vanderveen', + 'Saini', + 'Meiners', + 'Metheny', + 'Schommer', + 'Kissell', + 'Burgoyne', + 'Walmsley', + 'Parmley', + 'Arthurs', + 'Worsley', + 'Hulme', + 'Campisi', + 'Parvin', + 'Ogawa', + 'Coder', + 'Gardener', + 'Taplin', + 'Nuzzo', + 'Linthicum', + 'Rosenstein', + 'Simoneau', + 'Preble', + 'Chae', + 'Nealon', + 'Stonecipher', + 'Medders', + 'Bencomo', + 'Durazo', + 'Scotto', + 'Klem', + 'Corman', + 'Byard', + 'Evan', + 'Dengler', + 'Kohls', + 'Seidler', + 'Clute', + 'Nebel', + 'Hohl', + 'Younker', + 'Parkerson', + 'Pullins', + 'Sweeting', + 'Wiersma', + 'Callanan', + 'Lisk', + 'Fassett', + 'Alloway', + 'Lafever', + 'Ollis', + 'Gracey', + 'Tune', + 'Ester', + 'Weingarten', + 'Swigart', + 'Frew', + 'Conkle', + 'Mendelsohn', + 'Belliveau', + 'Bacher', + 'Coto', + 'Ro', + 'Lipson', + 'Standard', + 'Hoerner', + 'Moldenhauer', + 'Trivette', + 'Colligan', + 'Cacho', + 'Emrich', + 'Condit', + 'Styer', + 'Paramore', + 'Cheramie', + 'Sprenger', + 'Kreps', + 'Curd', + 'Josephs', + 'Bruch', + 'Villano', + 'Banh', + 'Kennison', + 'Hilson', + 'Gathers', + 'Weinman', + 'Brickley', + 'Jetton', + 'Munford', + 'Charboneau', + 'Dittrich', + 'Boysen', + 'Newbury', + 'Hayner', + 'Pfau', + 'Wegman', + 'Eure', + 'Heinrichs', + 'Kresge', + 'Klepper', + 'Yohn', + 'Bergan', + 'Spells', + 'Reisman', + 'Schiffman', + 'Napoles', + 'Banegas', + 'Landman', + 'Hallenbeck', + 'Sever', + 'Hole', + 'Bown', + 'Barnaby', + 'Junior', + 'Deloatch', + 'Secrist', + 'Steigerwald', + 'Kallas', + 'Littell', + 'Clinger', + 'Rehman', + 'Cothern', + 'Class', + 'Sabino', + 'Mckain', + 'Werts', + 'Asmus', + 'Fierros', + 'Heffelfinger', + 'Henthorn', + 'Weirich', + 'Ashbrook', + 'Alber', + 'Calles', + 'Bragdon', + 'Gerow', + 'Hanger', + 'Machen', + 'Patt', + 'Harada', + 'Parmelee', + 'Decaro', + 'Sons', + 'Tindal', + 'Lubbers', + 'Ferland', + 'Bruni', + 'Boyes', + 'Danis', + 'Tigner', + 'Anzaldua', + 'Gaxiola', + 'Iacono', + 'Lizama', + 'Forbis', + 'Mcguffin', + 'Greenhill', + 'Baity', + 'Welcome', + 'Lauzon', + 'Nicodemus', + 'Rabin', + 'Teegarden', + 'Yunker', + 'Salim', + 'Dews', + 'Schueller', + 'Stogsdill', + 'Minch', + 'Ellett', + 'Villafana', + 'Shan', + 'Boler', + 'Kast', + 'Shrout', + 'Taff', + 'Willcox', + 'Kahan', + 'Gerth', + 'Sabella', + 'Procopio', + 'Vedder', + 'Heeter', + 'Banes', + 'Alaimo', + 'Raza', + 'Starkweather', + 'Mutter', + 'Manners', + 'Bohanan', + 'Virden', + 'Booze', + 'Wimbush', + 'Eickhoff', + 'Hankinson', + 'Swilley', + 'Killinger', + 'Labar', + 'Tallant', + 'Rosin', + 'Hillhouse', + 'Labarre', + 'Ryans', + 'Heintzelman', + 'Cottone', + 'Bickerstaff', + 'Westley', + 'Rotter', + 'Hey', + 'Dinapoli', + 'Lohmann', + 'Reetz', + 'Vences', + 'Mckiernan', + 'Thornsberry', + 'Hofman', + 'Murrieta', + 'Vanwormer', + 'Sen', + 'Pinheiro', + 'Jaco', + 'Maner', + 'Crosley', + 'Rogalski', + 'Hollandsworth', + 'Hinze', + 'Seawright', + 'Brosius', + 'Keehn', + 'Sweetman', + 'Vicknair', + 'Casler', + 'Hagopian', + 'Westhoff', + 'Lipari', + 'Poll', + 'Lintz', + 'Rosinski', + 'Henrie', + 'Crystal', + 'Wroten', + 'Perla', + 'Zawacki', + 'Mckillip', + 'Dorantes', + 'Wallick', + 'Hoots', + 'Witty', + 'Granata', + 'Janicki', + 'Petroff', + 'Emert', + 'Raskin', + 'Picou', + 'Caple', + 'Mcelyea', + 'Blackmer', + 'Busbee', + 'Pettengill', + 'Newberg', + 'Nickle', + 'Hedman', + 'Flavin', + 'Forgione', + 'Wachtel', + 'Meader', + 'Nale', + 'Westby', + 'Pulaski', + 'Schupp', + 'Troutt', + 'Fishburn', + 'Laprade', + 'Dealba', + 'Waymire', + 'Stiefel', + 'Carner', + 'Fallin', + 'Belin', + 'Anand', + 'Lesh', + 'Okada', + 'Whipkey', + 'Mang', + 'Harvill', + 'Caver', + 'Moskal', + 'Schaible', + 'Vandeusen', + 'Boyko', + 'Matteo', + 'Crisler', + 'Capehart', + 'Heide', + 'Holdsworth', + 'Mcdonagh', + 'Burlison', + 'Beshears', + 'Gills', + 'Cowger', + 'Gendreau', + 'Goering', + 'Hewes', + 'Whelchel', + 'Kier', + 'Tramel', + 'Mcsherry', + 'Morita', + 'Cissell', + 'Knaus', + 'Vangilder', + 'Karsten', + 'Linscott', + 'Ratner', + 'Catoe', + 'Scriven', + 'Gerstner', + 'Brobst', + 'Normandin', + 'Piasecki', + 'Tamura', + 'Balboa', + 'Nathanson', + 'Huizenga', + 'Renard', + 'Deshazo', + 'Ethier', + 'Fabiano', + 'Quisenberry', + 'Mcbryde', + 'Palencia', + 'Scaglione', + 'Friese', + 'Laughter', + 'Houchins', + 'Loman', + 'Garden', + 'Cromartie', + 'Borgman', + 'Hoffpauir', + 'Choquette', + 'Jarrard', + 'Fernald', + 'Barranco', + 'Levering', + 'Ansell', + 'Perl', + 'Caudell', + 'Ewen', + 'Ohanlon', + 'Swofford', + 'Reasoner', + 'Grout', + 'Rising', + 'Buttram', + 'Vandenheuvel', + 'Imel', + 'Rearick', + 'Harn', + 'Sorrels', + 'Biggins', + 'Renda', + 'Norden', + 'Matula', + 'Walch', + 'Broad', + 'Stokley', + 'Gully', + 'Barrientes', + 'Chilcote', + 'Freel', + 'Lage', + 'Farner', + 'Rubel', + 'Demko', + 'Shao', + 'Cupples', + 'Holderman', + 'Dunnam', + 'Hughs', + 'Foskey', + 'Darst', + 'Greenblatt', + 'Shiner', + 'Brasfield', + 'Simeon', + 'Maser', + 'Lacayo', + 'Priestley', + 'Pleasants', + 'Howse', + 'Iyer', + 'Perreira', + 'Baillargeon', + 'Revilla', + 'Yarger', + 'Gries', + 'Sheeley', + 'Prim', + 'Picazo', + 'Heinlein', + 'Merola', + 'Malhotra', + 'Wein', + 'Mchone', + 'Valliere', + 'Minner', + 'Blumer', + 'Hasse', + 'Kuester', + 'Landi', + 'Suits', + 'Primeaux', + 'Jarnagin', + 'Galle', + 'Greenlaw', + 'Qiu', + 'Lamarche', + 'Acheson', + 'Gothard', + 'Mendivil', + 'Bombard', + 'Mcquillen', + 'Munden', + 'Herzberg', + 'Ros', + 'Umstead', + 'Levins', + 'Pellegrin', + 'Castagna', + 'Alvord', + 'Huckins', + 'Wagnon', + 'Plemons', + 'Dolin', + 'Garica', + 'Lyttle', + 'Bazile', + 'Astudillo', + 'Gover', + 'Galati', + 'Seager', + 'Girardi', + 'Freels', + 'Bramblett', + 'Brancato', + 'Reppert', + 'Saetern', + 'Puig', + 'Prettyman', + 'Chagnon', + 'Heavner', + 'Schlichting', + 'Saladino', + 'Stall', + 'Loiselle', + 'Sedano', + 'Panos', + 'Heilig', + 'Ridgley', + 'Basilio', + 'Rapoza', + 'Furrow', + 'Oliveras', + 'Cordray', + 'Strausbaugh', + 'Culhane', + 'Iraheta', + 'Lamantia', + 'Shires', + 'Wilding', + 'Obanion', + 'Easterwood', + 'Hearns', + 'Manske', + 'Spiess', + 'Eckley', + 'Wootton', + 'Enochs', + 'Cheatwood', + 'Woodfin', + 'Akridge', + 'Mattocks', + 'Mcdougle', + 'Legette', + 'Neher', + 'Rhoton', + 'Vartanian', + 'Dunkel', + 'Wehmeyer', + 'Foutch', + 'Dille', + 'Halle', + 'Lowden', + 'Olesen', + 'Chace', + 'Hasbrouck', + 'Lesage', + 'Pappalardo', + 'Shinkle', + 'Ishii', + 'Peralez', + 'Gabler', + 'Fichter', + 'Mcnicholas', + 'Moshier', + 'Barbeau', + 'Bossert', + 'Trivett', + 'Bamford', + 'Lauterbach', + 'Gossman', + 'Epling', + 'Welk', + 'Daub', + 'Squier', + 'Dicus', + 'Siller', + 'Romaine', + 'Meriwether', + 'Bordner', + 'Baden', + 'Hagins', + 'Sica', + 'Mullane', + 'Jurgensen', + 'Tien', + 'Gertz', + 'Touchstone', + 'Bones', + 'Kimmons', + 'Prisco', + 'Kaser', + 'Drysdale', + 'Jelks', + 'Cerrone', + 'Wolfenbarger', + 'Deckert', + 'Ganley', + 'Fleeman', + 'Cubbage', + 'Woodie', + 'Schwan', + 'Siefert', + 'Rizvi', + 'Heier', + 'Khanna', + 'Leet', + 'Gratz', + 'Mullan', + 'Moorefield', + 'Fishback', + 'Whittenburg', + 'Casson', + 'Statham', + 'Red', + 'Coldiron', + 'Keplinger', + 'Reichman', + 'Brier', + 'Vavra', + 'Housman', + 'Kitson', + 'Fekete', + 'Rotella', + 'Onofre', + 'Orvis', + 'Beutler', + 'Cadwallader', + 'Gabor', + 'Emmanuel', + 'Moretz', + 'Suniga', + 'Mcmath', + 'Kinlaw', + 'Beringer', + 'Gaudreau', + 'Lirette', + 'Drye', + 'Oubre', + 'Gardella', + 'Reigle', + 'Zubia', + 'Mccardle', + 'Ambler', + 'Lucius', + 'Fizer', + 'Hilley', + 'Fischbach', + 'Borelli', + 'Gies', + 'Barks', + 'Sheard', + 'Hammontree', + 'Hogle', + 'Fagg', + 'Buitron', + 'Eiler', + 'Grandstaff', + 'Hank', + 'Wark', + 'Decoteau', + 'Depina', + 'Clabaugh', + 'Desiderio', + 'Kuchta', + 'Trang', + 'Abril', + 'Smathers', + 'Kaspar', + 'Melia', + 'Sandman', + 'Maltese', + 'Mccasland', + 'Rayl', + 'Meche', + 'Wiggin', + 'Saint', + 'Dorner', + 'Columbus', + 'Boatner', + 'Fresquez', + 'Sykora', + 'Shriner', + 'Drumheller', + 'Mahony', + 'Redinger', + 'Radloff', + 'Mitts', + 'Casperson', + 'Gammill', + 'Moraga', + 'Baratta', + 'Tow', + 'Ocon', + 'Cruce', + 'Bohannan', + 'Hurtt', + 'Mose', + 'Caines', + 'Heisey', + 'Pitcock', + 'Swiderski', + 'Shu', + 'Buda', + 'Whidden', + 'Busick', + 'Simas', + 'Croley', + 'Morrisey', + 'Saulsberry', + 'Crudup', + 'Bongiorno', + 'Beem', + 'Bunner', + 'Rosemond', + 'Freire', + 'Casado', + 'Merideth', + 'Selden', + 'Lamarre', + 'Fullwood', + 'Hartig', + 'Kerlin', + 'Lebowitz', + 'Kibbe', + 'Fannon', + 'Hotz', + 'Yerkes', + 'Re', + 'Waddington', + 'Akbar', + 'Baek', + 'Closson', + 'Miers', + 'Bonomo', + 'Wetherbee', + 'Taranto', + 'Henslee', + 'Bartle', + 'Hilger', + 'Asaro', + 'Mahr', + 'Strozier', + 'Agudelo', + 'Kulick', + 'Skoglund', + 'Yamasaki', + 'Schlemmer', + 'Hefley', + 'Waxman', + 'Radley', + 'Sanderlin', + 'Arispe', + 'Galang', + 'Morejon', + 'Stich', + 'Cesario', + 'Silvis', + 'Gurganus', + 'Shofner', + 'Funderburg', + 'Reddish', + 'Rybak', + 'Dingler', + 'Mankin', + 'Renna', + 'Alban', + 'Mckittrick', + 'Lippman', + 'Brenton', + 'Liebman', + 'Santillo', + 'Crigger', + 'Riney', + 'Mccraney', + 'Kluck', + 'Sosnowski', + 'Anspach', + 'Bourdon', + 'Modi', + 'Heer', + 'Mastroianni', + 'Musial', + 'Whiteaker', + 'Summa', + 'Herber', + 'Roselli', + 'Orris', + 'Bert', + 'Dedmon', + 'Kelson', + 'Paone', + 'Barstow', + 'Gerst', + 'Bettinger', + 'Castner', + 'Penman', + 'Broaddus', + 'Ohman', + 'Villalon', + 'Carwile', + 'Fluellen', + 'Ort', + 'Bommarito', + 'Shuff', + 'Cannata', + 'Westgate', + 'Bien', + 'Driggs', + 'Maisonet', + 'Costin', + 'Raine', + 'Banton', + 'Buterbaugh', + 'Katzman', + 'Coreas', + 'Rosalez', + 'Gose', + 'Robie', + 'Winburn', + 'Glancy', + 'Hild', + 'Strock', + 'Umanzor', + 'Hoglund', + 'Kesner', + 'Lynam', + 'Swayze', + 'Grizzard', + 'Fettig', + 'Macko', + 'Schrum', + 'Sours', + 'Yonker', + 'Ebanks', + 'Chiodo', + 'Meaney', + 'Paras', + 'Struthers', + 'Sicard', + 'Leveille', + 'Beckstead', + 'Calero', + 'Fuhrmann', + 'Lybarger', + 'Capo', + 'Adolph', + 'Raabe', + 'Gran', + 'Borel', + 'Ary', + 'Charland', + 'Huh', + 'Steinert', + 'Stemple', + 'Groat', + 'Zang', + 'Nath', + 'Ogara', + 'Pecina', + 'Simoes', + 'Breece', + 'Nascimento', + 'Usry', + 'Gain', + 'Brassfield', + 'Lochner', + 'Pietsch', + 'Wechsler', + 'Sum', + 'Teneyck', + 'Pelt', + 'Burnley', + 'Renzi', + 'Mujica', + 'Profitt', + 'Body', + 'Debusk', + 'Robidoux', + 'Pruneda', + 'Pomerantz', + 'Gonyea', + 'Crosier', + 'Currence', + 'Newborn', + 'Tolleson', + 'Conlan', + 'Dunsmore', + 'Tansey', + 'Clinard', + 'Staudt', + 'Oppenheim', + 'Gossard', + 'Osbourne', + 'Gilyard', + 'Lucido', + 'Tonkin', + 'Mitzel', + 'Sola', + 'Palombo', + 'Duane', + 'Mac', + 'Kerry', + 'Stills', + 'Viveiros', + 'Stallman', + 'Moos', + 'Follis', + 'Maris', + 'Hollier', + 'Gundlach', + 'Moler', + 'Schweigert', + 'Chartrand', + 'Finkle', + 'Meese', + 'Nigh', + 'Amundsen', + 'Brocato', + 'Dreier', + 'Glessner', + 'Weibel', + 'Fritch', + 'Retherford', + 'Rahim', + 'Markert', + 'Ronk', + 'Olmeda', + 'Gosney', + 'Keathley', + 'Luby', + 'Harrill', + 'Dinges', + 'Rocheleau', + 'Meisel', + 'Farrer', + 'Lute', + 'Apel', + 'Pincus', + 'Maida', + 'Jimmerson', + 'Baltz', + 'Cuccia', + 'Heenan', + 'Thieme', + 'Zoeller', + 'Larocco', + 'Abdalla', + 'Classen', + 'Hassinger', + 'Filler', + 'Pidgeon', + 'Hanford', + 'Espy', + 'Goodlett', + 'Jone', + 'Ruggeri', + 'Lisi', + 'Spada', + 'Gerrard', + 'Allbritton', + 'Brazelton', + 'Boggan', + 'Dufault', + 'Espejo', + 'Bodkin', + 'Penix', + 'Dockins', + 'Rascoe', + 'Swarthout', + 'Tritt', + 'Gouin', + 'Lamberth', + 'Bourn', + 'Barnhouse', + 'Guzzo', + 'Netherton', + 'Zamarron', + 'Rosenberry', + 'Dahms', + 'Anwar', + 'Whitesides', + 'Tidmore', + 'Longstreet', + 'Claunch', + 'Ehrhart', + 'Hullinger', + 'Xia', + 'Heideman', + 'Nicklas', + 'Prins', + 'Soni', + 'Dominquez', + 'Vogelsang', + 'Pew', + 'Chess', + 'Simmerman', + 'Brunell', + 'Matthes', + 'Kinnison', + 'Cansler', + 'Weekly', + 'Eger', + 'Garabedian', + 'Milliman', + 'Severns', + 'Magnusson', + 'Fossum', + 'Salamon', + 'Vandoren', + 'Gillingham', + 'Charney', + 'Nokes', + 'Lamon', + 'Irick', + 'Okeeffe', + 'Zou', + 'Kott', + 'Quillin', + 'Friar', + 'Drummer', + 'Catchings', + 'Hamada', + 'Scheck', + 'Setser', + 'Gobble', + 'Condra', + 'Bowley', + 'Deschamps', + 'Sylva', + 'Bartolome', + 'Warfel', + 'Veltri', + 'Speers', + 'Butner', + 'Delorme', + 'Giesler', + 'Sonntag', + 'Wetherell', + 'Ohagan', + 'Torbert', + 'Grandberry', + 'Ronning', + 'Howser', + 'Soden', + 'Rasco', + 'Clauss', + 'Beland', + 'Nicola', + 'Justiniano', + 'Varnum', + 'Fergus', + 'Lazcano', + 'Sartori', + 'Carnley', + 'Lucarelli', + 'Bergh', + 'Wellborn', + 'Bow', + 'Longshore', + 'Marcel', + 'Sumlin', + 'Atilano', + 'Dostal', + 'Westendorf', + 'Stiver', + 'Morency', + 'Herrod', + 'Bologna', + 'Valiente', + 'Weinert', + 'Gaertner', + 'Prock', + 'Spangenberg', + 'Tineo', + 'Cosio', + 'Maass', + 'Rist', + 'Oatman', + 'Waguespack', + 'Cardiel', + 'Grate', + 'Behrends', + 'Linger', + 'Pozo', + 'Scoggin', + 'Jenkinson', + 'Ake', + 'Redick', + 'Bonacci', + 'Rivet', + 'Declue', + 'Swing', + 'Chopra', + 'Leib', + 'Wallner', + 'Grimmer', + 'Wilmes', + 'Pirkle', + 'Stanhope', + 'Knop', + 'Culotta', + 'Dipaola', + 'Hipolito', + 'Gerling', + 'Sennett', + 'Fulghum', + 'Grothe', + 'Krout', + 'Onorato', + 'Donis', + 'Winbush', + 'Aoki', + 'Buscher', + 'Jarquin', + 'Lemanski', + 'Mcgrane', + 'Tardif', + 'Segundo', + 'Caba', + 'Sease', + 'Blinn', + 'Losee', + 'Kirschbaum', + 'Baskett', + 'Knights', + 'Goudeau', + 'Grondin', + 'Harting', + 'Szewczyk', + 'Wieder', + 'Conatser', + 'Romanelli', + 'Freshour', + 'Brizendine', + 'Rolen', + 'Guynn', + 'Laforest', + 'Doris', + 'Sandridge', + 'Dublin', + 'Blancas', + 'Duryea', + 'Naik', + 'Paradiso', + 'Scheele', + 'Westra', + 'Hassel', + 'Bertucci', + 'Fansler', + 'Flohr', + 'Solt', + 'Suess', + 'Keiper', + 'Downard', + 'Ivester', + 'Darley', + 'Seales', + 'Kolesar', + 'Overbeck', + 'Subramanian', + 'Panter', + 'Parshall', + 'Stannard', + 'Gravley', + 'Dhaliwal', + 'Shippy', + 'Dolphin', + 'Lepper', + 'Gorby', + 'Delmonte', + 'Piccirillo', + 'Besaw', + 'Alligood', + 'Rhymes', + 'Eisenman', + 'Deveau', + 'Tilden', + 'Girton', + 'Buser', + 'Rentschler', + 'Sopko', + 'Uriostegui', + 'Wasko', + 'Noffsinger', + 'Barkman', + 'Dyck', + 'Ferrero', + 'Kiehl', + 'Leffel', + 'Rybicki', + 'Hedstrom', + 'Bracamontes', + 'Zebrowski', + 'Blundell', + 'Brightman', + 'Hegwood', + 'Beecham', + 'Kolbe', + 'Bucy', + 'Bondi', + 'Borgen', + 'Gibbens', + 'Pullman', + 'Letcher', + 'Ferebee', + 'Kitterman', + 'Seefeldt', + 'Upham', + 'Thiede', + 'Bolster', + 'Bastin', + 'Bondy', + 'Mershon', + 'Nickson', + 'Drozd', + 'Schroyer', + 'Mcmenamin', + 'Reith', + 'Lovin', + 'San', + 'Henegar', + 'Haislip', + 'Barco', + 'Arter', + 'Malecki', + 'Teeple', + 'Walpole', + 'Feil', + 'Neitzel', + 'Ostler', + 'Parmar', + 'Vinton', + 'Jan', + 'Weldy', + 'Etherton', + 'Joya', + 'Saliba', + 'Schnur', + 'Belles', + 'Mcgeorge', + 'Olden', + 'Rarick', + 'Worrall', + 'Degen', + 'Froman', + 'Odowd', + 'Einhorn', + 'Fimbres', + 'Maresca', + 'Rocker', + 'Arend', + 'Biermann', + 'Guimond', + 'Mcgurk', + 'Goll', + 'Santilli', + 'Hadlock', + 'Teer', + 'Dillion', + 'Jorden', + 'Honore', + 'Bromberg', + 'Stoneman', + 'Blossom', + 'Guzik', + 'Stockstill', + 'Wax', + 'Anello', + 'Blasko', + 'Frese', + 'Berthold', + 'Morefield', + 'Baptist', + 'Legault', + 'Bouffard', + 'Bebout', + 'Darnall', + 'Buscemi', + 'Buentello', + 'Scroggs', + 'Gatton', + 'Turnquist', + 'Lucht', + 'Remick', + 'Godlewski', + 'Bradt', + 'Waldorf', + 'Zeringue', + 'Rowen', + 'Mowbray', + 'Parkey', + 'Engram', + 'Mazzarella', + 'Kirkbride', + 'Gridley', + 'Kaster', + 'Lorenzana', + 'Wareham', + 'Star', + 'Marshburn', + 'Everman', + 'Wolfram', + 'Zick', + 'Hyun', + 'Yerger', + 'Baham', + 'Gebhard', + 'Ruf', + 'Suchy', + 'Tieman', + 'Wenz', + 'Schiro', + 'Fout', + 'Abdo', + 'Hayter', + 'Cleaves', + 'Fritsche', + 'Meurer', + 'Riendeau', + 'Ventimiglia', + 'Cervera', + 'Mallow', + 'Allie', + 'Hanscom', + 'Viloria', + 'Dubon', + 'Leeson', + 'Ruffing', + 'Jonson', + 'Fenimore', + 'Gonzaga', + 'Schriver', + 'Traina', + 'Mecca', + 'Lantigua', + 'Baril', + 'Harford', + 'Bartow', + 'Asbell', + 'Rumley', + 'Brogden', + 'Derryberry', + 'Ketner', + 'Dakin', + 'Wass', + 'Fallis', + 'Wada', + 'Studdard', + 'Lecroy', + 'Fetty', + 'Nass', + 'Chute', + 'Parman', + 'Bevans', + 'Headen', + 'Hysell', + 'Merten', + 'Most', + 'Fuss', + 'Schrank', + 'Last', + 'Even', + 'Vaz', + 'Sifford', + 'Streets', + 'Claude', + 'Bronstein', + 'Sherburne', + 'Wadkins', + 'Gascon', + 'Seiter', + 'Steffan', + 'Cardozo', + 'Henricks', + 'Claflin', + 'Etzel', + 'Kulas', + 'Trinkle', + 'Ortegon', + 'Phaneuf', + 'Langworthy', + 'Barb', + 'Mazon', + 'Veney', + 'Redondo', + 'Tieu', + 'Laursen', + 'Nanez', + 'Votaw', + 'Walraven', + 'Abella', + 'Dsouza', + 'Bayley', + 'Townson', + 'Applebaum', + 'Mazzei', + 'Piche', + 'Rivenbark', + 'Urrea', + 'Dolph', + 'Bonifacio', + 'Shehan', + 'Glascock', + 'Verde', + 'Gadberry', + 'Trimm', + 'Dowe', + 'Khang', + 'Mulhall', + 'Selzer', + 'Raub', + 'Ore', + 'Copes', + 'Masuda', + 'Moscoso', + 'Zeitler', + 'Mollica', + 'Iler', + 'Leventhal', + 'Manders', + 'Prue', + 'Fergerson', + 'Brose', + 'Phu', + 'Debellis', + 'Haan', + 'Schoening', + 'Stager', + 'Demos', + 'Rumble', + 'Brunt', + 'Nivens', + 'Manigault', + 'Buendia', + 'Deschenes', + 'Wittmer', + 'Hamon', + 'Hentz', + 'Loud', + 'Oseguera', + 'Rayo', + 'Macfarland', + 'Mimms', + 'Grunewald', + 'Hartness', + 'Wynkoop', + 'Wallingford', + 'Juergens', + 'Meszaros', + 'Riehle', + 'Trego', + 'Neece', + 'Coggin', + 'Burrill', + 'Laurel', + 'Routt', + 'Rodger', + 'Krum', + 'Faulkenberry', + 'Labadie', + 'Hemming', + 'Fulp', + 'Jamal', + 'Deloney', + 'Fells', + 'Bohnert', + 'Kapadia', + 'Guill', + 'Coop', + 'Broadhurst', + 'Mccrimmon', + 'Bonfiglio', + 'Capetillo', + 'Chamorro', + 'Gargiulo', + 'Stoehr', + 'Schlecht', + 'Karlson', + 'Garten', + 'Remer', + 'Mebane', + 'Finnigan', + 'Bourdeau', + 'Espindola', + 'Shukla', + 'Petras', + 'Steinberger', + 'Casner', + 'Carico', + 'Seevers', + 'Westwood', + 'Hosea', + 'Mcphillips', + 'Nygren', + 'Wagaman', + 'Coghlan', + 'Sutherlin', + 'Sellman', + 'Bashore', + 'Mullican', + 'Stoneburner', + 'Montag', + 'Karst', + 'Murch', + 'Puffer', + 'Sabala', + 'Pauli', + 'Odonoghue', + 'Lassen', + 'Mattera', + 'Mcaninch', + 'Portugal', + 'Clingan', + 'Michener', + 'Munsell', + 'Streetman', + 'Harton', + 'Swarts', + 'Honig', + 'Jesus', + 'Rentas', + 'Trosper', + 'Coffield', + 'Burket', + 'Donaghy', + 'Byun', + 'Riess', + 'Mcqueary', + 'Stayton', + 'Ferron', + 'Wedding', + 'Tibbitts', + 'Frisbee', + 'Reinoso', + 'Lama', + 'Allyn', + 'Sheen', + 'Tyra', + 'Golder', + 'Veasey', + 'Schroth', + 'Kukla', + 'Narayan', + 'Vandemark', + 'Horace', + 'Kadlec', + 'Portnoy', + 'Reynosa', + 'Surprenant', + 'Savell', + 'Seagle', + 'Vandervort', + 'Eye', + 'Eccleston', + 'Blaise', + 'Glaspie', + 'Cressman', + 'Lahti', + 'Yocom', + 'Leppert', + 'Brendle', + 'Greenough', + 'Relyea', + 'Marinez', + 'Bouley', + 'Fincham', + 'Highley', + 'Goza', + 'Norrell', + 'Yusuf', + 'Ohm', + 'Thakkar', + 'Cosenza', + 'Efird', + 'Heger', + 'Dysart', + 'Mango', + 'Fitchett', + 'Kring', + 'Paolucci', + 'Menges', + 'Layden', + 'Mccleery', + 'Benko', + 'Sandor', + 'Blakney', + 'Zanders', + 'Gengler', + 'Fujita', + 'Huls', + 'Basquez', + 'Trepanier', + 'Spadaro', + 'Ankney', + 'Damiani', + 'Games', + 'Cherney', + 'Fitzsimons', + 'Dearmas', + 'Bonet', + 'Diem', + 'Shimp', + 'Agrawal', + 'Gaw', + 'Gahagan', + 'Fossett', + 'Kafka', + 'Dedios', + 'Coryell', + 'Bahe', + 'Wurm', + 'Wishart', + 'Dray', + 'Armer', + 'Khalid', + 'Gassaway', + 'Vawter', + 'Loew', + 'Coello', + 'Curren', + 'Gilder', + 'Letendre', + 'Sprecher', + 'Rexrode', + 'Minich', + 'Koepp', + 'Mulloy', + 'Bohman', + 'Gambrel', + 'Hackley', + 'Demasi', + 'Hoffert', + 'Kittredge', + 'Maltby', + 'Nyquist', + 'Schieber', + 'Kennell', + 'Calderwood', + 'Compean', + 'Romines', + 'Simonelli', + 'Pico', + 'Oda', + 'Holte', + 'Bate', + 'Learn', + 'Lowenstein', + 'Holtman', + 'Mingus', + 'Sessa', + 'Legendre', + 'Gerrish', + 'Schoenberg', + 'Liberman', + 'Mclachlan', + 'Higginson', + 'Vince', + 'Mallery', + 'Delamora', + 'Difranco', + 'Lein', + 'Haltom', + 'Dority', + 'Marcellus', + 'Heskett', + 'Harward', + 'Spinney', + 'Darwin', + 'Baylis', + 'Amodeo', + 'Schwandt', + 'Mcmorrow', + 'Foraker', + 'Fyfe', + 'Shingleton', + 'Blandon', + 'Waddy', + 'Ricca', + 'Scheffer', + 'Balliet', + 'Philipp', + 'Rish', + 'Hattaway', + 'Krejci', + 'Orduno', + 'Passarelli', + 'Skala', + 'Oram', + 'Raynes', + 'Hiett', + 'Tolan', + 'Kimbell', + 'Delara', + 'Farhat', + 'Kamps', + 'Mohney', + 'Escarcega', + 'Mell', + 'Mcquay', + 'Cannizzaro', + 'Deuel', + 'Losoya', + 'Goldin', + 'Zaidi', + 'Gillmore', + 'Buelow', + 'Maust', + 'Guerrera', + 'Bouck', + 'Bick', + 'Kelty', + 'Pines', + 'Braziel', + 'Bruening', + 'Frenzel', + 'Kenna', + 'Loria', + 'Koren', + 'Cornelio', + 'Poisson', + 'Raker', + 'Ptak', + 'Bohr', + 'Coury', + 'Failla', + 'Cipriani', + 'Delany', + 'Marmon', + 'Kinch', + 'Figgins', + 'Delfino', + 'Risser', + 'Hickox', + 'Fager', + 'Turpen', + 'Dalzell', + 'Falvey', + 'Leiker', + 'Mcgonigal', + 'Vaquera', + 'Weisser', + 'Viviano', + 'Shrock', + 'Minaya', + 'Chitty', + 'Costley', + 'Granberry', + 'Dimaria', + 'Roma', + 'Ortis', + 'Burnam', + 'Burruss', + 'Stoughton', + 'Cales', + 'Burrage', + 'Vanwagner', + 'Espada', + 'Mccuen', + 'Baize', + 'Pullum', + 'Gerrity', + 'Vicari', + 'Heuser', + 'Semler', + 'Fear', + 'Havener', + 'Kash', + 'Thibodaux', + 'Hadaway', + 'Smithwick', + 'Eisenhart', + 'Hodgin', + 'Cluck', + 'Godby', + 'Belli', + 'Demaree', + 'Beyers', + 'Jared', + 'Mall', + 'Defoe', + 'Chmura', + 'Hepworth', + 'Hintze', + 'Luk', + 'Vanriper', + 'Solari', + 'Atlas', + 'Outland', + 'Hanselman', + 'Scharff', + 'Rhein', + 'Milone', + 'Rochford', + 'Mynatt', + 'Lambdin', + 'Sandell', + 'Grounds', + 'Tabler', + 'Smartt', + 'Dejean', + 'Clayborne', + 'Vangorder', + 'Eastin', + 'Hiler', + 'Lisle', + 'Gramling', + 'Degarmo', + 'Malec', + 'Tinkham', + 'Vanauken', + 'Andrzejewski', + 'Rundell', + 'Happel', + 'Strine', + 'Koerber', + 'Haner', + 'Ashcroft', + 'Hille', + 'Cairo', + 'Upson', + 'Mooring', + 'Koury', + 'Vito', + 'Oberlin', + 'Christiano', + 'Redfearn', + 'Trower', + 'Hibbler', + 'Sumter', + 'Raftery', + 'Geise', + 'Wohl', + 'Gorney', + 'Peasley', + 'Heap', + 'Brazeal', + 'Mccleskey', + 'Yard', + 'Mcroy', + 'Amend', + 'Cutshaw', + 'Kazmierczak', + 'Strandberg', + 'Lasko', + 'Newlon', + 'File', + 'Bevill', + 'Silvera', + 'Arakaki', + 'Kelsch', + 'Ostendorf', + 'Cowie', + 'Hove', + 'Doles', + 'Bouvier', + 'Fecteau', + 'Hasegawa', + 'Paschke', + 'Taing', + 'Heldt', + 'Allaire', + 'Ochsner', + 'Giusti', + 'Reisner', + 'Swim', + 'Laidlaw', + 'Vanderbilt', + 'Atterberry', + 'Barthelemy', + 'Chalker', + 'Degregorio', + 'Mastro', + 'Patlan', + 'Gipe', + 'Roosa', + 'Filkins', + 'Styron', + 'Bryer', + 'Blackston', + 'Hagel', + 'Fralick', + 'Linhart', + 'Moura', + 'Pavia', + 'Pavao', + 'Furry', + 'Petrus', + 'Fairweather', + 'Blystone', + 'Co', + 'Divito', + 'Villicana', + 'Winch', + 'Tome', + 'Lanoue', + 'Biron', + 'Noell', + 'Mckeel', + 'Worthey', + 'Aten', + 'Eyer', + 'Zhen', + 'Tischler', + 'Luoma', + 'Opp', + 'Riggin', + 'Furness', + 'Wolbert', + 'Penning', + 'Draves', + 'Whitehill', + 'Dudgeon', + 'Kinkead', + 'Luca', + 'Rosell', + 'Macauley', + 'Goldner', + 'Ishikawa', + 'Kirchhoff', + 'Lamarca', + 'Miyashiro', + 'Weger', + 'Wuest', + 'Kreis', + 'Urbanek', + 'Palko', + 'Victorino', + 'Morado', + 'Burchette', + 'Holyfield', + 'Tulloch', + 'Twombly', + 'Munk', + 'Woolford', + 'Knisely', + 'Locher', + 'Eckart', + 'Rancourt', + 'Pyron', + 'Edney', + 'Besser', + 'Truex', + 'Monterroso', + 'Bruneau', + 'Province', + 'Permenter', + 'Nims', + 'Rollison', + 'Cabell', + 'Sylvain', + 'Salman', + 'Signorelli', + 'Vegas', + 'Maddy', + 'Bachelder', + 'Sevigny', + 'Stolte', + 'Chavarin', + 'Lukes', + 'Rather', + 'Gartland', + 'Kurek', + 'Nantz', + 'Savard', + 'Finegan', + 'No', + 'Chichester', + 'Newbill', + 'Mahnke', + 'Sax', + 'Sowinski', + 'Wendler', + 'Cadiz', + 'Male', + 'Mealey', + 'Brookes', + 'Enderle', + 'Valenta', + 'Tooker', + 'Whitbeck', + 'Threet', + 'Cavitt', + 'Murtagh', + 'Phalen', + 'Errico', + 'Merkley', + 'Ju', + 'Zachery', + 'Bramer', + 'Henline', + 'Noga', + 'Woelfel', + 'Deras', + 'Amen', + 'Aldape', + 'Bartling', + 'Claros', + 'Spurrier', + 'Ginder', + 'Fred', + 'Giberson', + 'Ryba', + 'Sommerfeld', + 'Dahle', + 'Endo', + 'Haddon', + 'Bowlby', + 'Wagener', + 'Ketter', + 'Balint', + 'Goheen', + 'Motsinger', + 'Celentano', + 'Drawdy', + 'Dennehy', + 'Mcelligott', + 'Nakamoto', + 'Deines', + 'Goldsby', + 'Drakeford', + 'Steffy', + 'Streich', + 'Villasana', + 'Cermak', + 'Prill', + 'Ellzey', + 'Gartrell', + 'Duffie', + 'Rother', + 'Buse', + 'Luz', + 'Groen', + 'Laviolette', + 'Roles', + 'Days', + 'Eash', + 'Haefner', + 'Font', + 'Mcree', + 'Bustillo', + 'Coughlan', + 'Bax', + 'Hoxie', + 'Barre', + 'Scaife', + 'Nowacki', + 'Reichardt', + 'Rogel', + 'Ivins', + 'Vanderburg', + 'Etchison', + 'Chesson', + 'Molden', + 'Giuliani', + 'Goodpaster', + 'Kriner', + 'Sturtz', + 'Tschida', + 'Henschel', + 'Asselin', + 'Kocsis', + 'Kroger', + 'Swayne', + 'Gallop', + 'Fraker', + 'Lauro', + 'Tuohy', + 'Scholes', + 'Croxton', + 'Fertig', + 'Gregerson', + 'Gundersen', + 'Lehrer', + 'Monsivais', + 'Pilla', + 'Weishaar', + 'Gutshall', + 'Winget', + 'Human', + 'Oberry', + 'Learned', + 'Marburger', + 'Teed', + 'Parrilla', + 'Due', + 'Hartzler', + 'Cieslak', + 'Feltz', + 'Geren', + 'Wile', + 'Waldrip', + 'Clore', + 'Stutler', + 'Feehan', + 'Lacher', + 'Felter', + 'Barakat', + 'Flippen', + 'Holsey', + 'Finkbeiner', + 'Istre', + 'Lengyel', + 'Lupercio', + 'Beegle', + 'Habel', + 'Hammill', + 'Kifer', + 'Buswell', + 'Deboard', + 'Guilliams', + 'Ahlstrom', + 'Beliveau', + 'Sasse', + 'Delker', + 'Letterman', + 'Avey', + 'Bohlen', + 'Piner', + 'Folmar', + 'Barile', + 'Komar', + 'Bonelli', + 'Lamay', + 'Cora', + 'Deere', + 'Sanon', + 'Deppe', + 'Emmerich', + 'Giannone', + 'Navarra', + 'Hudock', + 'Seaborn', + 'Burda', + 'Faz', + 'Stefani', + 'Beemer', + 'Vose', + 'Calandra', + 'Eno', + 'Figueredo', + 'Lauck', + 'Schwindt', + 'Dumais', + 'Hedger', + 'Capp', + 'Barreiro', + 'Buker', + 'Spruell', + 'Bertolini', + 'Hoar', + 'Tiemann', + 'Vandenbosch', + 'Winebrenner', + 'Maio', + 'Winship', + 'Brissette', + 'Hansell', + 'Elsey', + 'Hansard', + 'Gildersleeve', + 'Hambright', + 'Borba', + 'Konieczny', + 'Lundell', + 'Tiedemann', + 'Siegler', + 'Ying', + 'Mckinsey', + 'Olah', + 'Boersma', + 'Younkin', + 'Evanoff', + 'Nakashima', + 'Scalia', + 'Piro', + 'Colorado', + 'Felan', + 'Fuentez', + 'Blea', + 'Gowin', + 'Hanning', + 'Byrom', + 'Morant', + 'Bachand', + 'Mcsorley', + 'Peaslee', + 'Bardsley', + 'Stilson', + 'Severs', + 'Kincheloe', + 'Kyler', + 'Aurand', + 'Bento', + 'Hoeppner', + 'Mertes', + 'Pickrell', + 'Rustad', + 'Millikan', + 'Celestino', + 'Hovland', + 'Kurowski', + 'Zollinger', + 'Tallon', + 'Junkins', + 'Mizrahi', + 'Bomberger', + 'Farrand', + 'Curto', + 'Bona', + 'Donatelli', + 'Eppley', + 'Schurman', + 'Henao', + 'Tomberlin', + 'Provencio', + 'Speidel', + 'Cree', + 'Inskeep', + 'Yeates', + 'Hoggatt', + 'Hinkson', + 'Ficklin', + 'Mcnealy', + 'Cabanas', + 'Laycock', + 'Theroux', + 'Weymouth', + 'Mabie', + 'Hatchell', + 'Bohanon', + 'Bilger', + 'Nazarian', + 'Weist', + 'Depue', + 'Mangini', + 'Gelb', + 'Luman', + 'Blass', + 'Desroches', + 'Hearon', + 'Mcmiller', + 'Stoltenberg', + 'Parenti', + 'Daulton', + 'Smail', + 'Chisum', + 'Benefiel', + 'Tetrault', + 'Foland', + 'Reddington', + 'Mattei', + 'Custis', + 'Fransen', + 'Zylstra', + 'Salvaggio', + 'Factor', + 'Deshong', + 'Biederman', + 'Sirianni', + 'Steckler', + 'Thrall', + 'Dorsch', + 'Harpe', + 'Tell', + 'Galusha', + 'Guttman', + 'Raposa', + 'Jaros', + 'Lipka', + 'Shive', + 'Shand', + 'Brizuela', + 'Horvat', + 'Pisciotta', + 'Sorge', + 'Riebe', + 'Vanderlaan', + 'Isenhour', + 'Franson', + 'Goslin', + 'Amore', + 'Leachman', + 'Foulks', + 'Alamillo', + 'Scarpa', + 'Tickle', + 'Pettitt', + 'Orrell', + 'Fleckenstein', + 'Sapien', + 'Roye', + 'Mcmeans', + 'Sligh', + 'Landgraf', + 'Cecere', + 'Aune', + 'Ketron', + 'Welcher', + 'Tilford', + 'Maston', + 'Overall', + 'Fails', + 'Bah', + 'Ketterman', + 'Lindauer', + 'Saxe', + 'Majka', + 'Goodenough', + 'Panella', + 'Ramm', + 'Caley', + 'Christine', + 'Kinsler', + 'Pippen', + 'Murph', + 'Ammann', + 'Falkowski', + 'Madonna', + 'Seligman', + 'Rommel', + 'Lareau', + 'Melone', + 'Frasure', + 'Joyal', + 'Piekarski', + 'Porcelli', + 'Kennington', + 'Pica', + 'Ankrom', + 'Capron', + 'Chatmon', + 'Horrigan', + 'Morelos', + 'Noren', + 'Paolini', + 'Wildermuth', + 'Rossow', + 'Dorgan', + 'Pawlik', + 'Reiber', + 'Rothenberger', + 'Mcgonigle', + 'Oren', + 'Jeans', + 'Vivas', + 'Gerner', + 'Brzozowski', + 'Croyle', + 'Klick', + 'Vidaurri', + 'Wollman', + 'Brouillard', + 'Dejohn', + 'Meikle', + 'Grochowski', + 'Kaczor', + 'Philbin', + 'Sperber', + 'Vancil', + 'Zornes', + 'Strope', + 'Housel', + 'Minks', + 'Dike', + 'Jasmin', + 'Denicola', + 'Gokey', + 'Dominy', + 'Gillham', + 'Viray', + 'Herz', + 'Hursh', + 'Koeller', + 'Caicedo', + 'Near', + 'Harrel', + 'Veale', + 'Gustavson', + 'Lopiccolo', + 'Goldschmidt', + 'Loder', + 'Vannorman', + 'Maske', + 'Randel', + 'Pinner', + 'Buntin', + 'Roache', + 'Pinnock', + 'Dimaio', + 'Heckert', + 'Perrigo', + 'Schank', + 'Lisowski', + 'Brownstein', + 'Sharer', + 'Hambleton', + 'Maker', + 'Hursey', + 'Aguado', + 'Tian', + 'Rheaume', + 'Becraft', + 'Sowders', + 'Bratt', + 'Tebo', + 'Eid', + 'Reinecke', + 'Storck', + 'Pech', + 'Alspaugh', + 'Grell', + 'Purdue', + 'Jennette', + 'Pauling', + 'Wint', + 'Knupp', + 'Madewell', + 'Schwanke', + 'Tellier', + 'Washer', + 'Staff', + 'Keely', + 'Lisenby', + 'Walder', + 'Kennerly', + 'Ip', + 'Michalik', + 'Eichner', + 'Disbrow', + 'Bellomy', + 'Boesch', + 'Chirico', + 'Lietz', + 'Ploof', + 'Dyar', + 'Bai', + 'Lary', + 'Corbo', + 'Danaher', + 'Schiavo', + 'Giacalone', + 'Pentz', + 'Studley', + 'Doyal', + 'Edie', + 'Nathaniel', + 'Cambra', + 'Fenstermacher', + 'Garst', + 'Gaudio', + 'Zavaleta', + 'Castilla', + 'Griffeth', + 'Warthen', + 'Derringer', + 'Samsel', + 'Mattia', + 'Boelter', + 'Mathieson', + 'Estelle', + 'Frisk', + 'Hipple', + 'Garceau', + 'Ehrman', + 'Buchner', + 'Frailey', + 'Ganey', + 'Belser', + 'Leiby', + 'Schwind', + 'Hagberg', + 'Hooley', + 'Rafter', + 'Hasting', + 'Mcnab', + 'Piggott', + 'Millhouse', + 'Brescia', + 'Giancola', + 'Grob', + 'Uresti', + 'Tawney', + 'Huot', + 'Mizer', + 'Storrs', + 'Shobe', + 'Blade', + 'Baumbach', + 'Eppler', + 'Henningsen', + 'Kmetz', + 'Sepeda', + 'Pangburn', + 'Falgout', + 'Hurn', + 'Sholar', + 'Kendricks', + 'Brimhall', + 'Bucklin', + 'Hruby', + 'Hunziker', + 'Krenz', + 'Schwager', + 'Murley', + 'Crittendon', + 'Broady', + 'Kintz', + 'Entrekin', + 'Estey', + 'Sharrow', + 'Quarterman', + 'Gumbs', + 'Steely', + 'Machin', + 'Difiore', + 'Desch', + 'Wiedemann', + 'Tonn', + 'Villines', + 'Mcdole', + 'Bashir', + 'Beauford', + 'Crary', + 'Gallina', + 'Wolak', + 'Aburto', + 'Hasler', + 'Gullion', + 'Bracewell', + 'Rusher', + 'Sarvis', + 'Dargan', + 'Garbarino', + 'Pigeon', + 'Blasi', + 'Viens', + 'Reising', + 'Vosburgh', + 'Canipe', + 'Mcnett', + 'Bruss', + 'Shiflet', + 'Pinard', + 'Lattin', + 'Armbrust', + 'Peffer', + 'Shotts', + 'Arbaugh', + 'Hux', + 'First', + 'Bolds', + 'Ceaser', + 'Cephas', + 'Bormann', + 'Broadwell', + 'Qian', + 'Talamantez', + 'Vandermolen', + 'Maza', + 'Kinnear', + 'Bullins', + 'Arant', + 'Brodbeck', + 'Rolfes', + 'Wisneski', + 'Dague', + 'Dudas', + 'Greener', + 'Noguera', + 'Greeno', + 'Daddario', + 'Giambrone', + 'Menon', + 'Sherrick', + 'Spier', + 'Semon', + 'Fendley', + 'Crichton', + 'Moree', + 'Stratford', + 'Zobel', + 'Halladay', + 'Keesler', + 'Prewett', + 'Deavers', + 'Kamal', + 'Bottom', + 'Caves', + 'Harshaw', + 'Fretz', + 'Secord', + 'Seibold', + 'Pantaleon', + 'Greek', + 'Baumeister', + 'Kleven', + 'Kos', + 'Orban', + 'Papke', + 'Shatto', + 'Cui', + 'Boan', + 'Nevitt', + 'Hultgren', + 'Kreiser', + 'Veres', + 'Jent', + 'Merck', + 'Gibby', + 'Hosch', + 'Mallet', + 'Dock', + 'Dallman', + 'Loiacono', + 'Tetzlaff', + 'Arboleda', + 'Mclelland', + 'Willing', + 'Coonrod', + 'Cappiello', + 'Courtemanche', + 'Halperin', + 'Odegard', + 'Hornyak', + 'Stem', + 'Doner', + 'Saffold', + 'Hochman', + 'Ing', + 'Knudtson', + 'Laabs', + 'Selleck', + 'Bassler', + 'Kamin', + 'Hur', + 'Forward', + 'Finnie', + 'Blubaugh', + 'Hitz', + 'Litteral', + 'Mansur', + 'Rosenow', + 'Vermeulen', + 'Markarian', + 'Marceau', + 'Weisner', + 'Sharpless', + 'Cunniff', + 'Guilfoyle', + 'Lauver', + 'Lukasik', + 'Ripp', + 'Wierzbicki', + 'Wunsch', + 'Boothby', + 'Selfridge', + 'Mckey', + 'Vandermeer', + 'Vanhoy', + 'Edlund', + 'Eggen', + 'Bickett', + 'Hallum', + 'Brow', + 'Rhymer', + 'Buckalew', + 'Haughey', + 'Hentges', + 'Matthies', + 'Mccloy', + 'Simmon', + 'Concha', + 'Feingold', + 'Maglio', + 'Olaughlin', + 'Tassone', + 'Abbasi', + 'Oyola', + 'Mook', + 'Makin', + 'Carnegie', + 'Yue', + 'Sethi', + 'Duchene', + 'Mcnear', + 'Bartolo', + 'Hegedus', + 'Knoblauch', + 'Orner', + 'Hottinger', + 'Lovitt', + 'Harkless', + 'Anastasio', + 'Hohmann', + 'Mangione', + 'Dalby', + 'Urich', + 'Shuttleworth', + 'Guilbeau', + 'Bausch', + 'Demartini', + 'Difrancesco', + 'Schwalm', + 'Steere', + 'Guel', + 'Blanford', + 'Flax', + 'Fearon', + 'Severe', + 'Canto', + 'Krogh', + 'Meola', + 'Dykema', + 'Angelini', + 'Pooley', + 'Raff', + 'Rister', + 'Baehr', + 'Daubert', + 'Dechant', + 'Kliewer', + 'Hamdan', + 'Gaiser', + 'Lichty', + 'Pomerleau', + 'Uhler', + 'Membreno', + 'Printz', + 'Worman', + 'Thornley', + 'Burbridge', + 'Burdge', + 'Schnitzer', + 'Swanberg', + 'Steinkamp', + 'Heidel', + 'Karch', + 'Igo', + 'Mccausland', + 'Huskins', + 'Kuss', + 'Newbern', + 'Peete', + 'Godbolt', + 'Climer', + 'Neuenschwander', + 'Then', + 'Tietjen', + 'Trombetta', + 'Hawke', + 'Hazlewood', + 'Mayse', + 'Patillo', + 'Banos', + 'Kuck', + 'Lashbrook', + 'Sarkisian', + 'Goldberger', + 'Moravec', + 'Arey', + 'Crosswhite', + 'Elders', + 'Fricks', + 'Hercules', + 'Bester', + 'Erhart', + 'Kuper', + 'Sickels', + 'Mun', + 'Beddingfield', + 'Panetta', + 'Poplawski', + 'Lansford', + 'Negri', + 'Dawe', + 'Belair', + 'Lattimer', + 'Betty', + 'Raye', + 'Gobert', + 'Dragoo', + 'Horney', + 'Strawbridge', + 'Howery', + 'Bosarge', + 'Panzer', + 'Labrador', + 'Ransdell', + 'Trumbo', + 'Aubry', + 'Fenderson', + 'Fukuda', + 'Grosz', + 'Jacome', + 'Slick', + 'Kogut', + 'Haig', + 'Fouse', + 'Hufnagel', + 'Kehr', + 'Musselwhite', + 'Otwell', + 'Raddatz', + 'Oliverio', + 'Sluss', + 'Crossen', + 'Guidroz', + 'Mollett', + 'Sumler', + 'Chmiel', + 'Guinan', + 'Vita', + 'Wieser', + 'Ohlson', + 'Bubb', + 'Stennett', + 'Bugbee', + 'Minchew', + 'Grado', + 'Calcagno', + 'Losh', + 'Witzel', + 'Brandl', + 'Geoghegan', + 'Vanbrunt', + 'Smalling', + 'Carignan', + 'Schuelke', + 'Sienkiewicz', + 'Sollars', + 'Dames', + 'Malkin', + 'Rodriges', + 'Rozanski', + 'Tews', + 'Aust', + 'Bardin', + 'Voorhies', + 'Rines', + 'Courts', + 'Bannerman', + 'Martinsen', + 'Malick', + 'Collar', + 'Twilley', + 'Freiberg', + 'Latiolais', + 'Zehnder', + 'Mannon', + 'Becnel', + 'Cowans', + 'Arrigo', + 'Crago', + 'Curtsinger', + 'Gassman', + 'Marcelo', + 'Rosendahl', + 'Benito', + 'Cortright', + 'Carlon', + 'Kenton', + 'Hemminger', + 'Martinek', + 'Galeana', + 'Cobble', + 'Ruffino', + 'Wittrock', + 'Aberle', + 'Catanese', + 'Huezo', + 'Soules', + 'Ashraf', + 'Mera', + 'Gash', + 'Agnello', + 'Hauk', + 'Hayek', + 'Rahm', + 'Higham', + 'Kondo', + 'Almon', + 'Earwood', + 'Kriebel', + 'Philbrook', + 'Rimer', + 'Cuffee', + 'Wolfgram', + 'Wardwell', + 'Ridder', + 'Runner', + 'Houchens', + 'Vasser', + 'Charlesworth', + 'Dierks', + 'Molter', + 'Orosz', + 'Roudebush', + 'Coca', + 'Brost', + 'Lovern', + 'Brott', + 'Baudoin', + 'Prophet', + 'Bermea', + 'Ulm', + 'Bahl', + 'Ulery', + 'Caraveo', + 'Maez', + 'Corchado', + 'Baillie', + 'Colmenero', + 'Rebolledo', + 'Shevlin', + 'Mehaffey', + 'Hedin', + 'Pickell', + 'Spiro', + 'Coatney', + 'Gentner', + 'Fuhr', + 'Zeh', + 'Fuerte', + 'Knerr', + 'Nakata', + 'Voll', + 'Zach', + 'Gatica', + 'Rabalais', + 'Macek', + 'Petti', + 'Dickison', + 'Sheley', + 'Kinner', + 'Effinger', + 'Axelson', + 'Overbay', + 'Vancleve', + 'Speegle', + 'Muntz', + 'Sang', + 'Mcleroy', + 'Aleshire', + 'Holdridge', + 'Knouse', + 'Saling', + 'Zacher', + 'Zambrana', + 'Neblett', + 'Cichon', + 'Herdman', + 'Poli', + 'Schisler', + 'Antrim', + 'Babineau', + 'Coplin', + 'Straughn', + 'Watlington', + 'Burbach', + 'Campanelli', + 'Coletta', + 'Tennis', + 'Dymond', + 'Darosa', + 'Chard', + 'Delcampo', + 'Lyden', + 'Piland', + 'Eslick', + 'Beets', + 'Ransome', + 'Schuett', + 'Styers', + 'Fegley', + 'Corning', + 'Crume', + 'Villeneuve', + 'Schmeling', + 'Zeiger', + 'Blaker', + 'Ramsden', + 'Carol', + 'Roseboro', + 'Egner', + 'Filip', + 'Poitras', + 'Flanery', + 'Cothren', + 'Bridger', + 'Hoose', + 'Demas', + 'Kozel', + 'Marzano', + 'Penwell', + 'Rast', + 'Whicker', + 'Haslett', + 'Bibby', + 'Keese', + 'Montilla', + 'Sultana', + 'Resendes', + 'Vanscoy', + 'Dinan', + 'Bala', + 'Dirksen', + 'Ek', + 'Shimer', + 'Doshi', + 'Mayeux', + 'Streater', + 'Dattilo', + 'Marlar', + 'Senft', + 'Vanalstine', + 'Rehberg', + 'Vanderhoff', + 'Brenes', + 'Motto', + 'Sproles', + 'Toone', + 'Royall', + 'Beaudette', + 'Belding', + 'Berta', + 'Carmean', + 'Simonian', + 'Avera', + 'Martina', + 'Kind', + 'Buchheit', + 'Corrao', + 'Crumrine', + 'Wertman', + 'Lininger', + 'Pressman', + 'Slane', + 'Manges', + 'Theus', + 'Canizales', + 'Eugenio', + 'Ferrigno', + 'Ellard', + 'Stilley', + 'Crabbe', + 'Procter', + 'Baccus', + 'Hellmann', + 'Risk', + 'Schild', + 'Tostado', + 'Fessenden', + 'Glines', + 'Perone', + 'Carns', + 'Belote', + 'Deshotel', + 'Bottomley', + 'Delbosque', + 'Dubinsky', + 'Flinchum', + 'Berlanga', + 'Darland', + 'Daniele', + 'Jess', + 'Mungia', + 'Harlin', + 'Rocca', + 'Saltsman', + 'Trovato', + 'Dionisio', + 'Erbe', + 'Dauzat', + 'Laferriere', + 'Kear', + 'Brannigan', + 'Guard', + 'Roquemore', + 'Brehmer', + 'Kappes', + 'Kepley', + 'Labounty', + 'Sudol', + 'Walburn', + 'Bibeau', + 'Euler', + 'Brawn', + 'Pilot', + 'Bunger', + 'Earnhardt', + 'Fischetti', + 'Buitrago', + 'Calo', + 'Surette', + 'Martyn', + 'Tollett', + 'Tuller', + 'Noakes', + 'Marson', + 'Bongiovanni', + 'Novello', + 'Werling', + 'Wyland', + 'Palen', + 'Sigmund', + 'Salzer', + 'Abels', + 'Penson', + 'Cazarez', + 'Diblasi', + 'Jantzen', + 'Kittleson', + 'Hurlbert', + 'Shepardson', + 'Munz', + 'Bozek', + 'Woll', + 'Forth', + 'Colvard', + 'Baginski', + 'Beirne', + 'Lemmer', + 'Shover', + 'Lucci', + 'Hockensmith', + 'Mayhall', + 'Faucette', + 'Soloman', + 'Lembo', + 'Tarnowski', + 'Westerlund', + 'Gossage', + 'Bold', + 'Davi', + 'Crater', + 'Saia', + 'Spisak', + 'Zerr', + 'Penate', + 'Piel', + 'Raja', + 'Farney', + 'Cutrer', + 'Liverman', + 'Brar', + 'Nocera', + 'Coutu', + 'Rishel', + 'Spurr', + 'Kail', + 'Molino', + 'Favreau', + 'Mullinix', + 'Pospisil', + 'Rohloff', + 'Slavens', + 'Stumbo', + 'Ahl', + 'Hosking', + 'Speaker', + 'Tarkington', + 'Majeski', + 'Skoog', + 'Kirch', + 'Vannostrand', + 'Olmo', + 'Dorrell', + 'Newcombe', + 'Halls', + 'Riffel', + 'Luque', + 'Rolston', + 'Lokey', + 'Nicholes', + 'Gula', + 'Schrage', + 'Goshorn', + 'Woodell', + 'Ahmadi', + 'Austria', + 'Shaul', + 'Berwick', + 'Graczyk', + 'Lacourse', + 'Porcaro', + 'Rexroad', + 'Chrzanowski', + 'Abele', + 'Woodin', + 'Gillan', + 'Lone', + 'Orzechowski', + 'Fader', + 'Regina', + 'Ban', + 'Morriss', + 'Rickards', + 'Gannaway', + 'Tassin', + 'Accardi', + 'Engelke', + 'Kruk', + 'Mantilla', + 'Soderstrom', + 'Kriz', + 'Cantley', + 'Cangelosi', + 'Kalin', + 'Sobolewski', + 'Prinz', + 'Bessey', + 'Chittum', + 'Marcucci', + 'Annunziata', + 'Hegg', + 'Mishra', + 'Heppner', + 'Benningfield', + 'Rhoten', + 'Smolen', + 'Lewellyn', + 'Tall', + 'Comiskey', + 'Gobel', + 'Klump', + 'Stauber', + 'Tocci', + 'Gosser', + 'Tussey', + 'Summitt', + 'Ottman', + 'Vester', + 'Pasko', + 'Latshaw', + 'Kies', + 'Valderrama', + 'Leese', + 'Orduna', + 'Gilcrease', + 'Alli', + 'Berberich', + 'Delariva', + 'Harb', + 'Schmuck', + 'Spang', + 'Uecker', + 'Garfinkel', + 'Mcalexander', + 'Monty', + 'Leonetti', + 'Knipe', + 'Loudon', + 'Leisure', + 'Swearengin', + 'Tinnin', + 'Engelmann', + 'Noblitt', + 'Ruhland', + 'Shewmaker', + 'Smetana', + 'Vangundy', + 'Yzaguirre', + 'Nehls', + 'Sullens', + 'Mahurin', + 'Ferman', + 'Lenhardt', + 'Littman', + 'Udell', + 'Coutts', + 'Mcginness', + 'Nakayama', + 'Goguen', + 'Lass', + 'Tibbits', + 'Pafford', + 'Fett', + 'Ruis', + 'Trogdon', + 'Tarleton', + 'Isabell', + 'Paylor', + 'Grandison', + 'Bejar', + 'Highfield', + 'Peplinski', + 'Hammitt', + 'Mitton', + 'Dashiell', + 'Turrentine', + 'Rusin', + 'Sheeran', + 'Barrs', + 'Grund', + 'Kowalsky', + 'Mccaughey', + 'Orantes', + 'Oshields', + 'Tourville', + 'Szymczak', + 'Gagner', + 'Kemble', + 'Delangel', + 'Kaler', + 'Treanor', + 'Deems', + 'Ours', + 'Loss', + 'Remley', + 'Welles', + 'Bogardus', + 'Feher', + 'Grzybowski', + 'Meinert', + 'Mickelsen', + 'Opitz', + 'Osowski', + 'Paglia', + 'Srivastava', + 'Hirata', + 'Vandermark', + 'Maggi', + 'Gautreau', + 'Fonte', + 'Meck', + 'Mcquinn', + 'Criddle', + 'Hulin', + 'Fulmore', + 'Baldino', + 'Neugebauer', + 'Sletten', + 'Talcott', + 'Tessmer', + 'Vrooman', + 'Whitlatch', + 'Miano', + 'Arauz', + 'Lafon', + 'Cashin', + 'Carrow', + 'Feely', + 'Provo', + 'Botsford', + 'Chojnacki', + 'Pritts', + 'Duby', + 'Danos', + 'Mundo', + 'Strum', + 'Bealer', + 'Barmore', + 'Birkholz', + 'Hedgecock', + 'Vides', + 'Mcjunkin', + 'Paley', + 'Dennie', + 'Cosey', + 'Trombly', + 'Wagar', + 'Tope', + 'Venters', + 'Neptune', + 'Allshouse', + 'Kuczynski', + 'Beams', + 'Kilbourne', + 'Troxler', + 'Mcgahee', + 'Latson', + 'Miraglia', + 'Suda', + 'Prall', + 'Searls', + 'Tevis', + 'Vales', + 'Coberly', + 'Eichman', + 'Hiltz', + 'Mancera', + 'Mrozek', + 'Obermeyer', + 'Wiedeman', + 'Yoshimura', + 'Pascucci', + 'Denk', + 'Pita', + 'Abdul', + 'Schurr', + 'Huntoon', + 'Sund', + 'Blose', + 'Agostini', + 'Cogdell', + 'Hamburger', + 'Orwig', + 'Pelley', + 'Mcnelly', + 'Litten', + 'Osterberg', + 'Zepp', + 'Mathur', + 'Ardon', + 'Petre', + 'Schroeter', + 'Christoff', + 'Ridenhour', + 'Hibler', + 'Coachman', + 'Tadeo', + 'Vanderploeg', + 'Ference', + 'Connery', + 'Albro', + 'Bublitz', + 'Fagundes', + 'Purpura', + 'Deeb', + 'Melzer', + 'Haus', + 'Huffine', + 'Groner', + 'Laforce', + 'Burriss', + 'Longino', + 'Seldon', + 'Chicoine', + 'Neira', + 'Pintor', + 'Trager', + 'Garg', + 'Camilleri', + 'Limbaugh', + 'Marinello', + 'Sanz', + 'Hankey', + 'Aylor', + 'Homes', + 'Marro', + 'Stalder', + 'Creasey', + 'Blankinship', + 'Waldrup', + 'Aubert', + 'Quintanar', + 'Tarbell', + 'Mayton', + 'Baba', + 'Voltz', + 'Cuba', + 'Bracco', + 'Dimeo', + 'Cauble', + 'Rodela', + 'Sambrano', + 'Doten', + 'Jobes', + 'Laura', + 'Farrier', + 'Mixson', + 'Bassi', + 'Kroening', + 'Papineau', + 'Scheuerman', + 'Zertuche', + 'Cardella', + 'Taube', + 'Bazzi', + 'Sautter', + 'Tobon', + 'Venditti', + 'Nordman', + 'Loken', + 'Fortino', + 'Godbout', + 'Knaub', + 'Larabee', + 'Meserve', + 'Slama', + 'Junge', + 'Stamand', + 'Daigneault', + 'Fredericksen', + 'Loveall', + 'Clothier', + 'Kuehne', + 'Delahoussaye', + 'Bosquez', + 'Hildenbrand', + 'Muto', + 'Vanvliet', + 'Frederiksen', + 'Mero', + 'Rapier', + 'Feldt', + 'Mcpartland', + 'Stegner', + 'Veenstra', + 'Yeater', + 'Yeatts', + 'Rosenbloom', + 'Shepperd', + 'Marchbanks', + 'Tapscott', + 'Baynard', + 'Osby', + 'Cumberbatch', + 'Brassard', + 'Dahlman', + 'Doi', + 'Katona', + 'Niesen', + 'Slavik', + 'Macneill', + 'Marsala', + 'Fazekas', + 'Cudd', + 'Ocana', + 'Brimer', + 'Lachman', + 'Balla', + 'Shahid', + 'Gammage', + 'Canez', + 'Fickes', + 'Goldblatt', + 'Mcgeehan', + 'Westerberg', + 'Legler', + 'Stanberry', + 'Hillery', + 'Colosimo', + 'Florek', + 'Heckathorn', + 'Lenart', + 'Mcneilly', + 'Viles', + 'Davin', + 'Pierro', + 'Edman', + 'Patron', + 'Tipps', + 'Ardis', + 'Hassen', + 'Crase', + 'Gebert', + 'Predmore', + 'Entwistle', + 'Lourenco', + 'Snively', + 'Chivers', + 'Byas', + 'Edsall', + 'Sneddon', + 'Kloster', + 'Luedke', + 'Barcelo', + 'Corns', + 'Paula', + 'Tacker', + 'Marton', + 'Lyke', + 'Huitt', + 'Tinch', + 'Tagle', + 'Linnell', + 'Loden', + 'Witman', + 'Condrey', + 'Swindler', + 'Denby', + 'Mcdow', + 'Bennion', + 'Berkman', + 'Esguerra', + 'Kohli', + 'Leicht', + 'Platero', + 'Purtell', + 'Sarro', + 'Spera', + 'Wasielewski', + 'Nold', + 'Gander', + 'Coster', + 'Burn', + 'Sindelar', + 'Spivak', + 'Stangl', + 'Eakes', + 'Host', + 'Raybon', + 'Stickle', + 'Vitiello', + 'Borntrager', + 'Glorioso', + 'Winnie', + 'Blocher', + 'Che', + 'Godbold', + 'Blumenfeld', + 'Hallford', + 'Nuckolls', + 'Rasor', + 'Tardy', + 'Hayslett', + 'Kivett', + 'Pettry', + 'Klopfenstein', + 'Martelli', + 'Dunker', + 'Klass', + 'Denn', + 'Vessels', + 'Stukes', + 'Iannone', + 'Kovarik', + 'Perlmutter', + 'Som', + 'Kump', + 'Tack', + 'Warf', + 'Coffer', + 'Baas', + 'Balli', + 'Fleishman', + 'Lyall', + 'Meli', + 'Petrovic', + 'Sego', + 'Tignor', + 'Maule', + 'Stinchcomb', + 'Doxey', + 'Garbutt', + 'Drewes', + 'Prestridge', + 'Vivanco', + 'Weinmann', + 'Amrhein', + 'Schluter', + 'Cleek', + 'Rossignol', + 'Rezendes', + 'Marone', + 'Sloss', + 'Weary', + 'Leishman', + 'Searfoss', + 'Springman', + 'Wolfer', + 'Hires', + 'Mccampbell', + 'Casselman', + 'Frasca', + 'Lintner', + 'Preiss', + 'Neilsen', + 'Twiss', + 'Boughner', + 'Donnellan', + 'Rech', + 'Mccaulley', + 'Massenburg', + 'Dermody', + 'Neuberger', + 'Rifkin', + 'Ullom', + 'Marth', + 'Blacker', + 'Kase', + 'Garon', + 'Calaway', + 'Grange', + 'Yopp', + 'Service', + 'Blassingame', + 'Lockley', + 'Straughter', + 'Porath', + 'Situ', + 'Stansfield', + 'Eves', + 'Cianci', + 'Colindres', + 'Killam', + 'Luiz', + 'Stahlman', + 'Silvernail', + 'Moorhouse', + 'Langner', + 'Soucie', + 'Lucke', + 'Manly', + 'Huggard', + 'Higareda', + 'Matarazzo', + 'Jusino', + 'Winnett', + 'Matheney', + 'Bufkin', + 'Bilbo', + 'Levingston', + 'Auxier', + 'Guevarra', + 'Triolo', + 'Roder', + 'Clever', + 'Moodie', + 'Cabana', + 'Kiesling', + 'Lindblom', + 'Reuther', + 'Rubi', + 'Brinkmann', + 'Donati', + 'Cresswell', + 'Fortes', + 'Bayard', + 'Grayer', + 'Malveaux', + 'Hauger', + 'Hirschman', + 'Soroka', + 'Witek', + 'Pugsley', + 'Eoff', + 'Alewine', + 'Hastie', + 'Budzinski', + 'Burgard', + 'Hebel', + 'Kleist', + 'Lawhead', + 'Saporito', + 'Sugarman', + 'Sechler', + 'Cohoon', + 'Treadaway', + 'Silliman', + 'Horsey', + 'Chauhan', + 'Jovel', + 'Giorgio', + 'Waltrip', + 'Templeman', + 'Morning', + 'Fava', + 'Mcinturff', + 'Migliaccio', + 'Moncayo', + 'Pesek', + 'Olivero', + 'Devall', + 'Dauphin', + 'Banerjee', + 'Benway', + 'Bermejo', + 'Dacey', + 'Pilarski', + 'Pinnell', + 'Chia', + 'Pung', + 'Rahe', + 'Greenhaw', + 'Byrns', + 'Ancona', + 'Granato', + 'Luciani', + 'Shryock', + 'Sloop', + 'Murcia', + 'Croll', + 'Congleton', + 'Okelly', + 'Norville', + 'Flesch', + 'Murad', + 'Seddon', + 'Waybright', + 'Cremer', + 'Hagman', + 'Largo', + 'Solar', + 'Costales', + 'Gier', + 'Tober', + 'Reeb', + 'Lands', + 'Hoback', + 'Ingrassia', + 'Youngquist', + 'Tyrell', + 'Profit', + 'Collura', + 'Oldaker', + 'Vogl', + 'Spafford', + 'Laughman', + 'Goris', + 'Coghill', + 'Sweatman', + 'Rozelle', + 'Chatelain', + 'Fouch', + 'Legros', + 'Koza', + 'Vialpando', + 'Subia', + 'Danz', + 'Dosch', + 'Debruin', + 'Stefanik', + 'Gamber', + 'Saylors', + 'Cost', + 'Bernat', + 'Eastburn', + 'Getman', + 'Maillet', + 'Dogan', + 'Finklea', + 'Alongi', + 'Ballas', + 'Konkel', + 'Ryu', + 'Scoles', + 'Oles', + 'Algarin', + 'Seago', + 'Delaune', + 'Pettey', + 'Gettys', + 'Blanch', + 'Kea', + 'Cambridge', + 'Ciesielski', + 'Pribble', + 'Mayhugh', + 'Dery', + 'Allsup', + 'Hauptman', + 'Shoff', + 'Spath', + 'Lipsky', + 'Lakhani', + 'Lona', + 'Andrea', + 'Heist', + 'Herzig', + 'Insley', + 'Frasher', + 'Muise', + 'Kettle', + 'Catano', + 'Harkleroad', + 'Rominger', + 'Schreffler', + 'Bielecki', + 'Knarr', + 'Arvidson', + 'Harnden', + 'Galyon', + 'Rando', + 'Delima', + 'Constance', + 'Bosman', + 'Meinke', + 'Rosenquist', + 'Stickles', + 'Batz', + 'Eitel', + 'Kouba', + 'Marmol', + 'Rini', + 'Kinyon', + 'Munns', + 'Hilts', + 'Verrett', + 'Shead', + 'Staggers', + 'Naccarato', + 'Shupp', + 'Willeford', + 'Gayer', + 'Bran', + 'Krider', + 'Cue', + 'Dubiel', + 'Kawamoto', + 'Quayle', + 'Meckley', + 'Weingart', + 'Ivan', + 'Aller', + 'Pattee', + 'Pile', + 'Shinault', + 'Alzate', + 'Goudreau', + 'Weitzman', + 'Zurek', + 'Portman', + 'Tellis', + 'Achenbach', + 'Cranfill', + 'Scheib', + 'Rud', + 'Forgey', + 'Sardina', + 'Hayslip', + 'Fadden', + 'Ethington', + 'Jette', + 'Maberry', + 'Stecher', + 'Mcgahan', + 'Buffa', + 'Lehto', + 'Lesch', + 'Minier', + 'Niblett', + 'Behar', + 'Gochenour', + 'Thole', + 'Woodmansee', + 'Guse', + 'Breunig', + 'Deibert', + 'Levario', + 'Liming', + 'Oltman', + 'Vought', + 'Higby', + 'Lummus', + 'Casimir', + 'Grabow', + 'Helzer', + 'Madero', + 'Panico', + 'Ruud', + 'Beas', + 'Knebel', + 'Lorence', + 'Sizer', + 'Goodwill', + 'Darrell', + 'Dismukes', + 'Wimbish', + 'Kleine', + 'Prohaska', + 'Freeborn', + 'Caso', + 'Meis', + 'Bise', + 'Maxim', + 'Chumbley', + 'Eaglin', + 'Bergey', + 'Hillenbrand', + 'Pacifico', + 'Plath', + 'Rio', + 'Ristau', + 'Zych', + 'Whang', + 'Fister', + 'Forbush', + 'Lagarde', + 'Atha', + 'Hallinan', + 'Hesser', + 'Hoak', + 'Kohr', + 'Longnecker', + 'Nomura', + 'Raia', + 'Seybold', + 'Spagnola', + 'Majano', + 'Sanmartin', + 'Mangual', + 'Stanback', + 'Gangi', + 'Lauritzen', + 'Seeber', + 'Disla', + 'Frain', + 'Besse', + 'Makris', + 'Ducker', + 'Demps', + 'Laporta', + 'Pavey', + 'Reineke', + 'Najjar', + 'Mcclaskey', + 'Luff', + 'Vanderveer', + 'Mccoll', + 'Leamon', + 'Meinhardt', + 'Dinatale', + 'Laffoon', + 'Jenny', + 'Skipworth', + 'Folds', + 'Burstein', + 'Freas', + 'Lizardo', + 'Selle', + 'Vrabel', + 'Beranek', + 'Hakala', + 'Spataro', + 'Prahl', + 'Meas', + 'Haston', + 'Croker', + 'Carmouche', + 'Doolan', + 'Guerrieri', + 'Poulton', + 'Mauger', + 'Klose', + 'Husk', + 'Pharis', + 'Dipalma', + 'Hamaker', + 'Simek', + 'Strube', + 'Corl', + 'Bence', + 'Meigs', + 'Gillaspie', + 'Moring', + 'Eli', + 'Mccullers', + 'Erving', + 'Dopp', + 'Falbo', + 'Gensler', + 'Heroux', + 'Hertzler', + 'Muscarella', + 'Wittmann', + 'Willner', + 'Howton', + 'Brummitt', + 'Demar', + 'Hardrick', + 'Benavente', + 'Choo', + 'Tiscareno', + 'Bunge', + 'Helle', + 'Ogan', + 'Allbright', + 'Jervis', + 'Tompson', + 'Sheats', + 'Hebron', + 'Esters', + 'Fiorillo', + 'Narciso', + 'Slowik', + 'Kush', + 'Sole', + 'Bitting', + 'Bradham', + 'Goggans', + 'Rushin', + 'Huguley', + 'Kittelson', + 'Nadel', + 'Noggle', + 'Xue', + 'Alameda', + 'Hege', + 'Liberto', + 'Maron', + 'Aber', + 'Brodersen', + 'Clasen', + 'Couturier', + 'Godines', + 'Ozment', + 'Parga', + 'Rohm', + 'Voris', + 'Leaver', + 'Newhart', + 'Sabourin', + 'Kelling', + 'Repass', + 'Wigington', + 'Prioleau', + 'Antle', + 'Goucher', + 'Kreitzer', + 'Reuss', + 'Rosenfield', + 'Sliva', + 'Nolting', + 'Radel', + 'Quintal', + 'Lisa', + 'Temples', + 'Cavins', + 'Gazaway', + 'Hopewell', + 'Albury', + 'Broberg', + 'Khuu', + 'Zelinski', + 'Kurian', + 'Treacy', + 'Rake', + 'Tirrell', + 'Macdowell', + 'Smead', + 'Edgerly', + 'Fowles', + 'Yorke', + 'Goodwyn', + 'Sciacca', + 'Breitenbach', + 'Charity', + 'Greenidge', + 'Kendig', + 'Navarette', + 'Doremus', + 'Marcelino', + 'Ribera', + 'Luse', + 'Hasley', + 'Halton', + 'Jakes', + 'Balas', + 'Cheema', + 'Dettman', + 'Schachter', + 'Weisenberger', + 'Lehn', + 'Sailors', + 'Alcott', + 'Mancino', + 'Mineo', + 'Montz', + 'Stettler', + 'Brannock', + 'Shumake', + 'Blunk', + 'Feuerstein', + 'Mangino', + 'Bitzer', + 'Padden', + 'Wetter', + 'Blase', + 'Helvey', + 'Sabia', + 'Folden', + 'Wyllie', + 'Hoosier', + 'Gehringer', + 'Peifer', + 'Schneiderman', + 'Raj', + 'Gift', + 'Sue', + 'Wedgeworth', + 'Bischof', + 'Coviello', + 'Flor', + 'Barrentine', + 'Ells', + 'Dundas', + 'Baine', + 'Bouknight', + 'Koning', + 'Mallari', + 'Monje', + 'Wingler', + 'Stainbrook', + 'Mari', + 'Hemby', + 'Boateng', + 'Enfinger', + 'Esquer', + 'Salvatierra', + 'Tercero', + 'Porta', + 'Speth', + 'Plate', + 'Rockhold', + 'Hampshire', + 'Stipe', + 'Buescher', + 'Denault', + 'Fahnestock', + 'Vandehey', + 'Brouse', + 'Ciaccio', + 'Hund', + 'Wire', + 'Sherron', + 'Fairfax', + 'Owusu', + 'Cuervo', + 'Minjarez', + 'Zarco', + 'Vandyne', + 'Gedeon', + 'Kegler', + 'Ebron', + 'Murtaugh', + 'Pariseau', + 'Morvant', + 'Ellwood', + 'Beazley', + 'Farrelly', + 'Mccollom', + 'Alegre', + 'Dussault', + 'Goulette', + 'Hession', + 'Regier', + 'Speranza', + 'Spinella', + 'Maloof', + 'Nogueira', + 'Beaudin', + 'Sable', + 'Samford', + 'Marchan', + 'Rodriques', + 'Rhines', + 'Aldrete', + 'Creedon', + 'Laberge', + 'Sandel', + 'Spady', + 'Horsman', + 'Schimpf', + 'Sottile', + 'Than', + 'Ybanez', + 'Sagastume', + 'Vosburg', + 'Langlais', + 'Windley', + 'Bielski', + 'Meyerson', + 'Rizk', + 'Sparacino', + 'Winebarger', + 'Helsley', + 'Alward', + 'Wilker', + 'Clyne', + 'Bergren', + 'Gin', + 'Heberling', + 'Noh', + 'Rotz', + 'Laffey', + 'Zurawski', + 'Aliff', + 'Coover', + 'Steves', + 'Brain', + 'Greggs', + 'Burts', + 'Culwell', + 'Halbrook', + 'Marcantel', + 'Alsip', + 'Esslinger', + 'Kinnaird', + 'Rew', + 'Wimbley', + 'Dalal', + 'Litke', + 'Ostlund', + 'Petersheim', + 'Vezina', + 'Vickrey', + 'Vida', + 'Stachowiak', + 'Santizo', + 'Stow', + 'Hoel', + 'Parrino', + 'Elsberry', + 'Pharris', + 'Chiarello', + 'Konen', + 'Ogata', + 'Tousignant', + 'Turano', + 'Zoll', + 'Reser', + 'Ribble', + 'Dally', + 'Kersh', + 'Crivello', + 'Glantz', + 'Vanvleet', + 'Dy', + 'Woolwine', + 'Ager', + 'Romney', + 'Dedeaux', + 'Ringgold', + 'Mir', + 'Rexford', + 'Whitehair', + 'Wilczynski', + 'Kleinsasser', + 'Siemens', + 'Kindig', + 'Kemmer', + 'Fonda', + 'Litt', + 'Mcferrin', + 'Riche', + 'Beaudet', + 'Lasala', + 'Maglione', + 'Milani', + 'Moscato', + 'Pangilinan', + 'Haycraft', + 'Camilo', + 'Trafton', + 'Stroble', + 'Dollard', + 'Consiglio', + 'Kinnaman', + 'Mumaw', + 'Mustard', + 'Nees', + 'Rupprecht', + 'Gimbel', + 'Chamberland', + 'Lish', + 'Beedle', + 'Minder', + 'Broxton', + 'Cocco', + 'Vore', + 'Slough', + 'Pehrson', + 'Graney', + 'Reade', + 'Cozzi', + 'Mowrer', + 'Necaise', + 'Notaro', + 'Vanderwall', + 'Jeffs', + 'Lynd', + 'Perino', + 'Poyner', + 'Oscar', + 'Mihalik', + 'Coscia', + 'Zoellner', + 'Shippee', + 'Casimiro', + 'Phillippe', + 'Bartolotta', + 'Graciano', + 'Schnoor', + 'Aube', + 'Duguay', + 'Dickerman', + 'Santi', + 'Cude', + 'Haver', + 'Heidelberg', + 'Farquharson', + 'Bianchini', + 'Kasprzak', + 'Pizzi', + 'Urquiza', + 'Knee', + 'Lust', + 'Strayhorn', + 'Ader', + 'Canup', + 'Mira', + 'Saulnier', + 'Stalvey', + 'Takeuchi', + 'Updegraff', + 'Barletta', + 'Mikhail', + 'Abadie', + 'Cohee', + 'Sones', + 'Hird', + 'Mizelle', + 'Graddy', + 'Demay', + 'Escandon', + 'Kozar', + 'Lecuyer', + 'Tredway', + 'Danks', + 'Pry', + 'Mathena', + 'Gomer', + 'Moussa', + 'Journey', + 'Brison', + 'Denardo', + 'Digiorgio', + 'Worster', + 'Kottke', + 'Sayegh', + 'Aday', + 'Chain', + 'Digby', + 'Beeks', + 'Malpass', + 'Toft', + 'Fucci', + 'Stam', + 'Smoker', + 'Willms', + 'Bohner', + 'Sugar', + 'Tay', + 'Faye', + 'Melnik', + 'Pankow', + 'Stehle', + 'Vecchione', + 'Weatherwax', + 'Monterrosa', + 'Bodily', + 'Serino', + 'Jerkins', + 'Bosma', + 'Luczak', + 'Serafini', + 'Baze', + 'Hemmings', + 'Darrington', + 'Fraizer', + 'Henrikson', + 'Kok', + 'Larrison', + 'Mirabella', + 'Newhall', + 'Hollenbach', + 'Formica', + 'Haake', + 'Seim', + 'Zeledon', + 'Crabill', + 'Mensch', + 'Prevatt', + 'Riggan', + 'Gallien', + 'Erby', + 'Running', + 'Shisler', + 'Sidebottom', + 'Sladek', + 'Alejos', + 'Momin', + 'Bickers', + 'Smither', + 'Ahart', + 'Huseman', + 'Cantero', + 'Reiley', + 'Mcneeley', + 'Quill', + 'Binger', + 'Ellerbee', + 'Cearley', + 'Guilmette', + 'Helbig', + 'Nuzum', + 'Gravatt', + 'Turlington', + 'Deramus', + 'Casados', + 'Harrop', + 'Kardos', + 'Krehbiel', + 'Homa', + 'Agostino', + 'Candia', + 'Byerley', + 'Kincer', + 'Vitello', + 'Backhaus', + 'Burzynski', + 'Zaborowski', + 'Puebla', + 'Pedrick', + 'Hyson', + 'Mazyck', + 'Deno', + 'Yutzy', + 'Dubbs', + 'Shimek', + 'Saha', + 'Philipps', + 'Chretien', + 'Bramwell', + 'Mccalister', + 'Ebright', + 'Parkhill', + 'Rieke', + 'Karras', + 'Mcbain', + 'Gibbon', + 'Beckler', + 'Nordby', + 'Sipos', + 'Swider', + 'Treiber', + 'Weakland', + 'Zagorski', + 'Peavler', + 'Cirino', + 'Corzine', + 'Barbier', + 'Dolby', + 'Sheperd', + 'Vanderhorst', + 'Cornman', + 'Dippel', + 'Gramlich', + 'Hoffmeister', + 'Markwell', + 'Milks', + 'Schriner', + 'Cusimano', + 'Emberton', + 'Kimbler', + 'Merrow', + 'Huard', + 'Paulo', + 'Durrance', + 'Faherty', + 'Palmatier', + 'Rezac', + 'Speir', + 'Streicher', + 'Ackman', + 'Veitch', + 'Bedgood', + 'Pantano', + 'Raman', + 'Eusebio', + 'Coldwell', + 'Omer', + 'Swanigan', + 'Stepney', + 'Breiner', + 'Casebolt', + 'Deblasio', + 'Mascaro', + 'Maselli', + 'Overfield', + 'Enyart', + 'Litman', + 'Borer', + 'Dudash', + 'Mcniff', + 'Cherian', + 'Scearce', + 'Brakefield', + 'Hamed', + 'Cooperman', + 'Kinzel', + 'Mchargue', + 'Schiefelbein', + 'Varughese', + 'Brumm', + 'Novy', + 'Vicars', + 'Barratt', + 'Titsworth', + 'Mole', + 'Crisafulli', + 'Deitch', + 'Slager', + 'Tokarz', + 'Speelman', + 'Tunney', + 'Peal', + 'Chenevert', + 'Haggins', + 'Heitmann', + 'Scheuer', + 'Stuhr', + 'Zenner', + 'Wishon', + 'Arno', + 'Lauder', + 'Goertz', + 'Jew', + 'Knapik', + 'Lococo', + 'Murnane', + 'Pawloski', + 'Contino', + 'Holbrooks', + 'Carlstrom', + 'Heitkamp', + 'Muszynski', + 'Shelnutt', + 'Tortora', + 'Dietrick', + 'Kyzer', + 'Colt', + 'Propes', + 'Caffee', + 'Fankhauser', + 'Liotta', + 'Patil', + 'Broder', + 'Disher', + 'Telfer', + 'Lampkins', + 'Bartman', + 'Beauchemin', + 'Gatz', + 'Pedrosa', + 'Schuch', + 'Zorrilla', + 'Capote', + 'Vanderslice', + 'Boulden', + 'Kirkendoll', + 'Fausto', + 'Krom', + 'Ngai', + 'Sepe', + 'Domenech', + 'Dines', + 'Aschenbrenner', + 'Carias', + 'Inoue', + 'Montagna', + 'Pulsifer', + 'Rieman', + 'Seelye', + 'Yochum', + 'Defilippis', + 'Lacross', + 'Betances', + 'Jenne', + 'Rousey', + 'Brunswick', + 'Wadlington', + 'Brainerd', + 'Dauria', + 'Dinicola', + 'Fath', + 'Gemmell', + 'Rudman', + 'Urbaniak', + 'Fillion', + 'Brandel', + 'Devin', + 'Derrickson', + 'Jenkin', + 'Ebling', + 'Ferranti', + 'Lueders', + 'Alvear', + 'Gero', + 'Maury', + 'Estill', + 'Beadles', + 'Philyaw', + 'Tann', + 'Bednarski', + 'Nagata', + 'Partington', + 'Sobol', + 'Soohoo', + 'Welliver', + 'Yam', + 'Popejoy', + 'Berthelot', + 'Manwaring', + 'Cahn', + 'Layer', + 'Poarch', + 'Tee', + 'Arellanes', + 'Ehler', + 'Montalto', + 'Pavlick', + 'Rauh', + 'Mcnees', + 'Balke', + 'Alles', + 'Caperton', + 'Frier', + 'Thweatt', + 'Whitely', + 'Demby', + 'Kowalik', + 'Loffredo', + 'Solem', + 'Clampitt', + 'Dossey', + 'Fauver', + 'Toto', + 'Corlett', + 'Nickols', + 'Golston', + 'Graef', + 'Salsman', + 'Hartl', + 'Towell', + 'Lasseter', + 'Arata', + 'Diver', + 'Malan', + 'Lanter', + 'Justis', + 'Prime', + 'Ditzler', + 'Engelhart', + 'Plouffe', + 'Zaldivar', + 'Elser', + 'Witherow', + 'Mateer', + 'Rikard', + 'Dolson', + 'Mariner', + 'Amis', + 'Toby', + 'Evins', + 'Midgette', + 'Pinnix', + 'Blackard', + 'Huisman', + 'Lager', + 'Deloera', + 'Dutt', + 'Goodrow', + 'Morphis', + 'Quin', + 'Frankenfield', + 'Craycraft', + 'Mazer', + 'Meloy', + 'Lebouef', + 'Beresford', + 'Spiva', + 'Michie', + 'Jarreau', + 'Vallier', + 'Dunmore', + 'Cerra', + 'Ciulla', + 'Dauer', + 'Helling', + 'Jackowski', + 'Taboada', + 'Balistreri', + 'Blattner', + 'Cabot', + 'Lawver', + 'Cornette', + 'Arline', + 'Amsden', + 'Degner', + 'Ungar', + 'Birney', + 'Goldie', + 'Croston', + 'Wixon', + 'Alan', + 'Garneau', + 'Kolakowski', + 'Vitek', + 'Witherell', + 'Licari', + 'Badeaux', + 'Sammon', + 'Greenland', + 'Corlew', + 'Cashwell', + 'Aldinger', + 'Bilderback', + 'Kleeman', + 'Sisto', + 'Menz', + 'Bakos', + 'Ebbert', + 'Berliner', + 'Kin', + 'Cabaniss', + 'Ouzts', + 'Mccook', + 'Campfield', + 'Gulino', + 'Odriscoll', + 'Weyand', + 'Mcguckin', + 'Crean', + 'Boyington', + 'Bracero', + 'Carini', + 'Chawla', + 'Chaudhary', + 'Koehl', + 'Wahlstrom', + 'Francoeur', + 'Leveque', + 'Ledgerwood', + 'Paluch', + 'Wyble', + 'Latif', + 'Koen', + 'Eddie', + 'Mcgirt', + 'Boxley', + 'Exline', + 'Lujano', + 'Michalowski', + 'Rottman', + 'Throop', + 'Zech', + 'Baros', + 'Bohne', + 'Mule', + 'Monica', + 'Lasiter', + 'Alsop', + 'Pittard', + 'Whitefield', + 'Mccaskey', + 'Paek', + 'Reilley', + 'Wasik', + 'Bouma', + 'Garrigan', + 'Nett', + 'Mclarty', + 'Flemings', + 'Alcorta', + 'Spoor', + 'Mccranie', + 'Coverdale', + 'Guaman', + 'Jenness', + 'Knoop', + 'Scarpelli', + 'Schrecengost', + 'Toews', + 'Caughey', + 'Laska', + 'Helfer', + 'Bevers', + 'Forbus', + 'Mccrady', + 'Reasor', + 'Aggarwal', + 'Locicero', + 'Uber', + 'Vadnais', + 'Budnick', + 'Duhamel', + 'Stelling', + 'Kicklighter', + 'Basco', + 'Otts', + 'Tippins', + 'Bliven', + 'Gayheart', + 'Knauf', + 'Lalli', + 'Quigg', + 'Kingman', + 'Boros', + 'Henneman', + 'Lofland', + 'Pendarvis', + 'Keitt', + 'Gelfand', + 'Greaney', + 'Kindt', + 'Stimac', + 'Kirn', + 'Tokar', + 'Miura', + 'Wendorf', + 'Vigue', + 'Dorey', + 'Fegan', + 'Meares', + 'Thierry', + 'Ambrosino', + 'Coenen', + 'Kersting', + 'Leas', + 'Millward', + 'Petzold', + 'Morphew', + 'Filippone', + 'Stoffer', + 'Mani', + 'Clairmont', + 'Mccreight', + 'Cully', + 'Bissonette', + 'Kochan', + 'Linneman', + 'Parlier', + 'Bergner', + 'Sterns', + 'Steveson', + 'Clingerman', + 'Karg', + 'Medved', + 'Prakash', + 'Ulman', + 'Petroski', + 'Hagaman', + 'Huddle', + 'Auclair', + 'Shives', + 'Dunavant', + 'Glade', + 'Chauncey', + 'Pough', + 'Burgoon', + 'Pluta', + 'Couey', + 'Punch', + 'Colmenares', + 'Fosdick', + 'Henze', + 'Kaczynski', + 'Lomonaco', + 'Roepke', + 'Schenkel', + 'Schlatter', + 'Schoenherr', + 'Tripodi', + 'Zeiler', + 'Bunt', + 'Dolly', + 'Boyland', + 'Bickle', + 'Cincotta', + 'Crull', + 'Enfield', + 'Saltz', + 'Skelley', + 'Younts', + 'Bussiere', + 'Latona', + 'Sensabaugh', + 'Grosvenor', + 'Woolbright', + 'Shorty', + 'Brungardt', + 'Cardon', + 'Carlberg', + 'Clevinger', + 'Rucinski', + 'Vanhooser', + 'Westling', + 'Imperial', + 'Tyer', + 'Elzey', + 'Aslam', + 'Fesler', + 'Leiser', + 'Smitley', + 'Orgeron', + 'Scuderi', + 'Flatley', + 'Whiteford', + 'Tison', + 'Laurin', + 'Fortman', + 'Whitty', + 'Kirton', + 'Cassella', + 'Flom', + 'Seigel', + 'Cossette', + 'Bryden', + 'Gobin', + 'Hieb', + 'Marzullo', + 'Matuszak', + 'Rolph', + 'Spilman', + 'Vanvoorhis', + 'Sande', + 'Suydam', + 'Gledhill', + 'Krill', + 'Mackiewicz', + 'Templet', + 'Friedrichs', + 'Ruddell', + 'Kats', + 'Nourse', + 'Millender', + 'Wafer', + 'Fauntleroy', + 'Archibeque', + 'Maslowski', + 'Metzgar', + 'Pizana', + 'Mcguffey', + 'Estridge', + 'Vanalstyne', + 'Decuir', + 'Mcbean', + 'Hardnett', + 'Avilla', + 'Spadafora', + 'Weisel', + 'Kann', + 'Leyden', + 'Purdom', + 'Tappan', + 'Gunnells', + 'Slaten', + 'Hansley', + 'Chiappetta', + 'Rozek', + 'Tiede', + 'Winland', + 'Dubuque', + 'Heslin', + 'Bradway', + 'Eckels', + 'Saffell', + 'Germaine', + 'Apolinar', + 'Coloma', + 'Gawlik', + 'Chipps', + 'Hicklin', + 'Glanton', + 'Dalke', + 'Denlinger', + 'Kuipers', + 'Houpt', + 'Parcell', + 'Claeys', + 'Ferreri', + 'Greif', + 'Lucente', + 'Siems', + 'Yousef', + 'Llerena', + 'Rote', + 'Suero', + 'Malmberg', + 'Touchette', + 'Luton', + 'Wess', + 'Height', + 'Stampley', + 'Anastasi', + 'Bulman', + 'Deharo', + 'Laube', + 'Severt', + 'Midgley', + 'Colling', + 'Ell', + 'Burbage', + 'Commander', + 'Hubner', + 'Zurcher', + 'Arocha', + 'Nobile', + 'Tingler', + 'Ellman', + 'Lolley', + 'Pewitt', + 'Mcduff', + 'Hyler', + 'Goltz', + 'Kubota', + 'Lamberti', + 'Ohern', + 'Uhrig', + 'Dummer', + 'Keesling', + 'Litzinger', + 'Moriarity', + 'Servantes', + 'Rohe', + 'Stokely', + 'Weedon', + 'Pippins', + 'Dehner', + 'Krogman', + 'Luecke', + 'Rosete', + 'Zona', + 'Lowy', + 'Applebee', + 'Heather', + 'Cruikshank', + 'Linson', + 'Brandy', + 'Koser', + 'Ruel', + 'Ruppe', + 'Saeteurn', + 'Dewolfe', + 'Sawtelle', + 'Rudin', + 'Raver', + 'Bassham', + 'Yaw', + 'Segrest', + 'Belfiore', + 'Heeren', + 'Kotowski', + 'Luken', + 'Makela', + 'Ranallo', + 'Schug', + 'Seery', + 'Payson', + 'Caufield', + 'Lacefield', + 'Bratten', + 'Jr', + 'Buske', + 'Ternes', + 'Bivona', + 'Felber', + 'Rott', + 'Pitkin', + 'Pridmore', + 'Oyer', + 'Astle', + 'Jeppesen', + 'Shimabukuro', + 'Soltys', + 'Vieth', + 'Rasnick', + 'Calfee', + 'Brignac', + 'Lamy', + 'Facey', + 'Alper', + 'Borquez', + 'Cavalieri', + 'Niswonger', + 'Pajak', + 'Schwabe', + 'Ringel', + 'Abbe', + 'Fenley', + 'Churchman', + 'Haydel', + 'Stockard', + 'Adamek', + 'Ellerman', + 'Torpey', + 'Waldroup', + 'Hunte', + 'Bienaime', + 'Lazzara', + 'Nemitz', + 'Wingerter', + 'Boer', + 'Franken', + 'Lebow', + 'Manger', + 'Baisley', + 'Pane', + 'Gayden', + 'Bertelsen', + 'Curfman', + 'Leanos', + 'Nissley', + 'Odwyer', + 'Manzer', + 'Kollman', + 'Quon', + 'Holgate', + 'Cola', + 'Mckissack', + 'Cousar', + 'Bilski', + 'Boehler', + 'Kawamura', + 'April', + 'Mckelvy', + 'Lanni', + 'Roehm', + 'Salva', + 'Stackpole', + 'Stracener', + 'Masiello', + 'Barrus', + 'Tubb', + 'Brummel', + 'Devereux', + 'Foushee', + 'Corado', + 'Gladfelter', + 'Grewe', + 'Hodapp', + 'Swartwood', + 'Vacek', + 'Wrona', + 'Shaffner', + 'Ullah', + 'Heslop', + 'Mungo', + 'Haymon', + 'Behrend', + 'Falter', + 'Feola', + 'Gruner', + 'Picklesimer', + 'Riedl', + 'Stegeman', + 'Harpole', + 'Moyes', + 'Boulay', + 'Brighton', + 'Guise', + 'Laury', + 'Badilla', + 'Cypher', + 'Houdek', + 'Juhasz', + 'Klingbeil', + 'Pinales', + 'Fellman', + 'Daher', + 'Allmond', + 'Bal', + 'Crager', + 'Hillebrand', + 'Menezes', + 'Serpas', + 'Zager', + 'Alvardo', + 'Summerford', + 'Stillings', + 'Vandergrift', + 'Hanchett', + 'Minto', + 'Daughtery', + 'Gillon', + 'Rajan', + 'Vasko', + 'Wirick', + 'Woolever', + 'Caserta', + 'Welle', + 'Kimbrel', + 'Traywick', + 'Hands', + 'Spratley', + 'Iannuzzi', + 'Krikorian', + 'Runk', + 'Sood', + 'Riese', + 'Antunes', + 'Winsett', + 'Mans', + 'Capel', + 'Condron', + 'Nilles', + 'Petz', + 'Salemi', + 'Bainter', + 'Patchett', + 'Hirschfeld', + 'Murrin', + 'Lamey', + 'Mcglothin', + 'Hodo', + 'Hirth', + 'Kaltenbach', + 'Kensinger', + 'Leidy', + 'Shurtz', + 'Braatz', + 'Brafford', + 'Willet', + 'Clendening', + 'Basch', + 'Brockwell', + 'Oberman', + 'Palmateer', + 'Osornio', + 'Gehl', + 'Staker', + 'Mattila', + 'Dawn', + 'Cowherd', + 'Appleman', + 'Carbonaro', + 'Castruita', + 'Pilling', + 'Wenrich', + 'Christoffersen', + 'Hinzman', + 'Kaup', + 'Pettersen', + 'Jue', + 'Khalsa', + 'Mutz', + 'Remus', + 'Arch', + 'Shands', + 'Borek', + 'Buresh', + 'Egli', + 'Feldkamp', + 'Hampel', + 'Lichtenberg', + 'Morimoto', + 'Brasel', + 'Demelo', + 'Royalty', + 'Averitt', + 'Metivier', + 'Bradsher', + 'Avallone', + 'Demeter', + 'Masucci', + 'Musil', + 'Wichmann', + 'Broman', + 'Taunton', + 'Blewett', + 'Duhart', + 'Goo', + 'Hanus', + 'Mathai', + 'Shutts', + 'Taniguchi', + 'Vanleeuwen', + 'Delvillar', + 'Hane', + 'Givan', + 'Croskey', + 'Elamin', + 'Deffenbaugh', + 'Miklos', + 'Passalacqua', + 'Woessner', + 'Lapan', + 'Miah', + 'Coty', + 'Baksh', + 'Beehler', + 'Goel', + 'Wolfinger', + 'Goodhue', + 'Toal', + 'Mattoon', + 'Haq', + 'Nida', + 'Dant', + 'Varnadore', + 'Tippit', + 'Every', + 'Bohling', + 'Lichtenberger', + 'Louk', + 'Soderquist', + 'Werkheiser', + 'Willbanks', + 'Whitis', + 'Millikin', + 'Dietzel', + 'Frase', + 'Ishida', + 'Pilger', + 'Grajales', + 'Kole', + 'Roff', + 'Ballantine', + 'Basden', + 'Cadenas', + 'Caliendo', + 'Hotard', + 'Vidrio', + 'Lichtman', + 'Devinney', + 'Fugitt', + 'Proud', + 'Hults', + 'Galey', + 'Verna', + 'Newburn', + 'Lafortune', + 'Fobbs', + 'Azure', + 'Cheong', + 'Heft', + 'Aispuro', + 'Longstreth', + 'Lajeunesse', + 'Howle', + 'Galley', + 'Lovan', + 'Convery', + 'Malatesta', + 'Warnecke', + 'Glavin', + 'Reil', + 'Filson', + 'Poage', + 'Fountaine', + 'Nolley', + 'Raglin', + 'Backlund', + 'Doerfler', + 'Faunce', + 'Hooton', + 'Lightcap', + 'Stepanek', + 'Grosser', + 'Weld', + 'Filippi', + 'Youn', + 'Matis', + 'Harnett', + 'Ferrill', + 'Segers', + 'Ponds', + 'Cuyler', + 'Faile', + 'Flaugher', + 'Kuehner', + 'Giorgi', + 'Eckler', + 'Sergeant', + 'Twiggs', + 'Boeck', + 'Flach', + 'Iliff', + 'Mcmurtrey', + 'Mcnelis', + 'Steckel', + 'Rouillard', + 'Folkerts', + 'Mechling', + 'Whitcher', + 'Daws', + 'Joly', + 'Abt', + 'Eells', + 'Niccum', + 'Twining', + 'Grinder', + 'Melrose', + 'Yarbro', + 'Degenhardt', + 'Dimeglio', + 'Okamura', + 'Kriss', + 'Payette', + 'Chui', + 'Mowers', + 'Foose', + 'Kinzie', + 'Blick', + 'Rizer', + 'Alcock', + 'Sirmans', + 'Behrman', + 'Carsten', + 'Kopacz', + 'Randhawa', + 'Schwing', + 'Burkhard', + 'Cunanan', + 'Exley', + 'Balducci', + 'Leman', + 'Hyslop', + 'Burtch', + 'Hadnot', + 'Lanphear', + 'Finchum', + 'Voit', + 'Jock', + 'Wilhoite', + 'Officer', + 'Mayweather', + 'Ravenell', + 'Arehart', + 'Bonetti', + 'Cloer', + 'Galliher', + 'Niven', + 'Uyeda', + 'Coughenour', + 'Siddiqi', + 'Karimi', + 'Cupit', + 'Loupe', + 'Hammell', + 'Antley', + 'Ally', + 'Southers', + 'Haymond', + 'Hosley', + 'Broz', + 'Kinoshita', + 'Kohout', + 'Lipke', + 'Ostrow', + 'Teves', + 'Gaus', + 'Meiser', + 'Cravey', + 'Noss', + 'Drayer', + 'Crooms', + 'Carrano', + 'Mckechnie', + 'Uhrich', + 'Villalva', + 'Wilkening', + 'Benevides', + 'Kepple', + 'Pon', + 'Randol', + 'Leadbetter', + 'Russom', + 'Locklin', + 'Battiste', + 'Abundis', + 'Agosta', + 'Bartek', + 'Brillhart', + 'Hoffmaster', + 'Mehr', + 'Spanos', + 'Denker', + 'Kimberling', + 'Schon', + 'Felten', + 'Lightle', + 'Ramseur', + 'Branning', + 'Deblois', + 'Inocencio', + 'Maricle', + 'Nishimoto', + 'Oviatt', + 'Shunk', + 'Taddeo', + 'Villarruel', + 'Otterson', + 'Clune', + 'Seamster', + 'Dandy', + 'Cybulski', + 'Daza', + 'Eastep', + 'Faulhaber', + 'Friedberg', + 'Gentz', + 'Scola', + 'Sebesta', + 'Glinski', + 'Schoon', + 'Graeber', + 'Sinks', + 'Wee', + 'Summerall', + 'Deets', + 'Furnish', + 'Kelemen', + 'Maiorano', + 'Teachout', + 'Paquet', + 'Mcgahey', + 'Kill', + 'Horman', + 'Selders', + 'Cottman', + 'Delfin', + 'Fronk', + 'Seelig', + 'Visco', + 'Briles', + 'Castillon', + 'Suire', + 'Havey', + 'Arner', + 'Farver', + 'Marts', + 'Gean', + 'Hugh', + 'Stoney', + 'Townsel', + 'Sandquist', + 'Neidig', + 'Miser', + 'Leeth', + 'Hocutt', + 'Balcazar', + 'Caporale', + 'Guymon', + 'Horstmann', + 'Miedema', + 'Zickefoose', + 'Casterline', + 'Pfannenstiel', + 'Becht', + 'Myres', + 'Ried', + 'Vallery', + 'Bator', + 'Calise', + 'Cotterman', + 'Desautels', + 'Hinchey', + 'Kostka', + 'Orenstein', + 'Rosenau', + 'Skow', + 'Cuello', + 'Herder', + 'Cure', + 'Eadie', + 'Claggett', + 'Batie', + 'Kirwin', + 'Troia', + 'Sinnett', + 'Books', + 'Maize', + 'Tremble', + 'Sinkler', + 'Gallon', + 'Winkles', + 'Zion', + 'Walt', + 'Pearse', + 'Gathright', + 'Isakson', + 'Saeger', + 'Siegle', + 'Wittwer', + 'Modesto', + 'Bensen', + 'Royals', + 'Mccane', + 'Begaye', + 'Matuszewski', + 'Schrier', + 'Shimko', + 'Torchia', + 'Ausmus', + 'Casazza', + 'Mealer', + 'Yant', + 'Amar', + 'Callas', + 'Depaola', + 'Kintner', + 'Lech', + 'Marsico', + 'Boerger', + 'Rak', + 'Kellen', + 'Kennemer', + 'Carbo', + 'Rennick', + 'Brennen', + 'Dorrough', + 'Shealey', + 'Breyer', + 'Dilks', + 'Geske', + 'Hundt', + 'Occhipinti', + 'Strauser', + 'Schult', + 'Transue', + 'Holding', + 'Vanhorne', + 'Critchlow', + 'Steptoe', + 'Buerger', + 'Claassen', + 'Farinas', + 'Ruland', + 'Holsapple', + 'Mcclintic', + 'Bendel', + 'Muriel', + 'Mckeithan', + 'Shellman', + 'Balzano', + 'Bement', + 'Montesinos', + 'Ringle', + 'Sobotka', + 'Donahoo', + 'Dicker', + 'Harling', + 'Burkley', + 'Browner', + 'Iovino', + 'Kubala', + 'Labriola', + 'Morra', + 'Orloff', + 'Patchen', + 'Recchia', + 'Budge', + 'Glendenning', + 'Nethery', + 'Scholtz', + 'Aybar', + 'Buis', + 'Mattie', + 'Bonsall', + 'Conine', + 'Dettmer', + 'Gerding', + 'Plantz', + 'Vandorn', + 'Tremaine', + 'Ruddick', + 'Murrow', + 'Mceachin', + 'Bridgeforth', + 'Docherty', + 'Hultman', + 'Liechty', + 'Touchton', + 'Yokoyama', + 'Borth', + 'Daoud', + 'Mealy', + 'Hearst', + 'Stalling', + 'Drapeau', + 'Hellwig', + 'Longtin', + 'Rappa', + 'Tormey', + 'Vanantwerp', + 'Sabel', + 'Neagle', + 'Duet', + 'Liebert', + 'Lush', + 'Aly', + 'Behn', + 'Brereton', + 'Atienza', + 'Dubey', + 'Gennaro', + 'Miltenberger', + 'Nitschke', + 'Ragle', + 'Schumm', + 'Tangen', + 'Waibel', + 'Whitham', + 'Stallone', + 'Perritt', + 'Coody', + 'Hinch', + 'Depuy', + 'Dunkelberger', + 'Texeira', + 'Tomita', + 'Diers', + 'Elsasser', + 'Neve', + 'Clendenen', + 'Pettibone', + 'Dobyns', + 'Ciotti', + 'Dodrill', + 'Fridman', + 'Lepine', + 'Nygard', + 'Shreves', + 'Sollenberger', + 'Leinbach', + 'Diazdeleon', + 'Bourget', + 'Ramadan', + 'Allensworth', + 'Scarboro', + 'Prowell', + 'Ghee', + 'Edouard', + 'Duca', + 'Ziebell', + 'Kercher', + 'Greger', + 'Mas', + 'Shier', + 'Branca', + 'Melchior', + 'Cast', + 'Saner', + 'Beswick', + 'Carone', + 'Sobieski', + 'Zweifel', + 'Beahm', + 'Defrank', + 'Krebsbach', + 'Mericle', + 'Mcinnes', + 'Lown', + 'Brumback', + 'Clause', + 'Claborn', + 'Rollin', + 'Montford', + 'Beckles', + 'Grebe', + 'Groesbeck', + 'Guidi', + 'Mathisen', + 'Mukherjee', + 'Rotolo', + 'Seybert', + 'Odegaard', + 'Mackley', + 'Glatt', + 'Going', + 'Perks', + 'Sansbury', + 'Prude', + 'Bequette', + 'Difilippo', + 'Dodgen', + 'Terpening', + 'Vanepps', + 'Poncedeleon', + 'Qu', + 'Ullery', + 'Wisener', + 'Lok', + 'Lutton', + 'Bellah', + 'Kinsel', + 'Tone', + 'Carabajal', + 'Koll', + 'Shankar', + 'Edick', + 'Donathan', + 'Andree', + 'Perrino', + 'Moffit', + 'Gaddie', + 'Breidenbach', + 'Jespersen', + 'Larrick', + 'Mauriello', + 'Morgado', + 'Roh', + 'Svec', + 'Tebbe', + 'Thieman', + 'Cerezo', + 'Perkowski', + 'Colville', + 'Yarnall', + 'Chason', + 'Brach', + 'Meller', + 'Brayboy', + 'Salaam', + 'Keleher', + 'Kilbourn', + 'Lowenthal', + 'Rispoli', + 'Vanzee', + 'Vlahos', + 'Trojan', + 'Birdsell', + 'Defoor', + 'Mcclusky', + 'Barret', + 'Smoke', + 'Berkeley', + 'Cuadrado', + 'Galyean', + 'Gruen', + 'Gualtieri', + 'Kurland', + 'Sposato', + 'Stieber', + 'Weatherman', + 'Strausser', + 'Miera', + 'Edlin', + 'Gilford', + 'Mouzon', + 'Buczek', + 'Krapf', + 'Lucatero', + 'Amburn', + 'Peddicord', + 'Forero', + 'Domer', + 'Farish', + 'Segraves', + 'Sant', + 'Engles', + 'Douthitt', + 'Lall', + 'Wormley', + 'Geisel', + 'Hao', + 'Polhemus', + 'Slifer', + 'Mowen', + 'Markin', + 'Rape', + 'Bollin', + 'Bulloch', + 'Pouncey', + 'Rufus', + 'Goodlow', + 'Dammann', + 'Delgrosso', + 'Gadbois', + 'Leap', + 'Lorentzen', + 'Sprankle', + 'Stucki', + 'Vitela', + 'Walck', + 'Winkelmann', + 'Mund', + 'Bley', + 'Channel', + 'Griebel', + 'Nordberg', + 'Slinkard', + 'Orrick', + 'Crooker', + 'Groll', + 'Maradiaga', + 'Jolin', + 'Boni', + 'Prom', + 'Reder', + 'Easler', + 'Totty', + 'Arnaud', + 'Bohler', + 'Heikkila', + 'Kehler', + 'Klingenberg', + 'Matera', + 'Striegel', + 'Urzua', + 'Baldi', + 'Burling', + 'Osmond', + 'Rucks', + 'Diel', + 'Kassel', + 'Schewe', + 'Conkling', + 'Ricke', + 'Schack', + 'Shirah', + 'Brauner', + 'Carriker', + 'Mcduffy', + 'Bieker', + 'Credeur', + 'Fabry', + 'Holdeman', + 'Jeansonne', + 'Klett', + 'Kolstad', + 'Mustain', + 'Strub', + 'Ricketson', + 'Fairbairn', + 'Langel', + 'Fenster', + 'Slatton', + 'Ehrenberg', + 'Espinola', + 'Hannaford', + 'Hinderliter', + 'Siqueiros', + 'Ange', + 'Gillin', + 'Battin', + 'Belue', + 'Spigner', + 'Simien', + 'Gervasi', + 'Pallares', + 'Plotner', + 'Puri', + 'Swiatek', + 'Vanmatre', + 'Corp', + 'Devillier', + 'Bucholtz', + 'Bremner', + 'Jen', + 'Evanson', + 'Ghent', + 'Eastland', + 'Kappler', + 'Grahn', + 'Shadrick', + 'Kibby', + 'Chaires', + 'Kontos', + 'Petrov', + 'Pillai', + 'Chadbourne', + 'Sotolongo', + 'Allende', + 'Kells', + 'Hayford', + 'Hempstead', + 'Livers', + 'Farrior', + 'Authement', + 'Bitz', + 'Corkery', + 'Klawitter', + 'Mongold', + 'Somma', + 'Topham', + 'Defrancisco', + 'Noda', + 'Breon', + 'Thetford', + 'Rod', + 'Kisling', + 'Drouillard', + 'Dotts', + 'Gramajo', + 'Masek', + 'Volkert', + 'Vora', + 'Pietras', + 'Sheffler', + 'Shrestha', + 'Kono', + 'Panza', + 'Brunn', + 'Tatom', + 'Nasir', + 'Barris', + 'Bursey', + 'Elsea', + 'Kettner', + 'Martorana', + 'Lindow', + 'Chevez', + 'Pater', + 'Hennis', + 'Iman', + 'Stembridge', + 'Satcher', + 'Britz', + 'Hommel', + 'Llanas', + 'Pathak', + 'Schwartzman', + 'Janz', + 'Hickle', + 'Deakins', + 'Mantle', + 'Billing', + 'Veiga', + 'Darbonne', + 'Angelle', + 'Granderson', + 'Odoms', + 'Mondesir', + 'Ducksworth', + 'Anker', + 'Deneen', + 'Follmer', + 'Norred', + 'Whitecotton', + 'Halsted', + 'Schiele', + 'Reddin', + 'Pichon', + 'Eustice', + 'Finelli', + 'Kawasaki', + 'Kerekes', + 'Surrett', + 'Divers', + 'Kerney', + 'Bohlman', + 'Oberst', + 'Prough', + 'Tarwater', + 'Wangler', + 'Piceno', + 'Persico', + 'Lastra', + 'Fillman', + 'Barlett', + 'Cort', + 'Kuchar', + 'Plaisted', + 'Rufo', + 'Whitmarsh', + 'Fusaro', + 'Bajwa', + 'Belter', + 'Aldama', + 'Conlee', + 'Tweedie', + 'Greear', + 'Riviera', + 'Stormer', + 'Flannagan', + 'Heatley', + 'Feazell', + 'Bastidas', + 'Benninger', + 'Canseco', + 'Hanners', + 'Kreiner', + 'Pestana', + 'Simerly', + 'Such', + 'Tiedeman', + 'Weible', + 'Zawadzki', + 'Rayman', + 'Crose', + 'Sheeler', + 'Kirven', + 'Winford', + 'Mackall', + 'Balderson', + 'Calleja', + 'Klinefelter', + 'Lauffer', + 'Probert', + 'Melero', + 'Ravelo', + 'Degroff', + 'Pylant', + 'Ricco', + 'Varona', + 'Pickney', + 'Bachmeier', + 'Dulay', + 'Hanover', + 'Virgilio', + 'Spino', + 'Bohon', + 'Cantin', + 'Pettijohn', + 'Branigan', + 'Duhe', + 'Perine', + 'Thedford', + 'Shamburger', + 'Guarnieri', + 'Guptill', + 'Nyland', + 'Setliff', + 'Shreffler', + 'Viggiano', + 'Pries', + 'Sunde', + 'Bulmer', + 'Platts', + 'Jeremiah', + 'Fawley', + 'Jansson', + 'Rebelo', + 'Prochnow', + 'Waldeck', + 'Citron', + 'Roughton', + 'Ryckman', + 'Molano', + 'Cannaday', + 'Ned', + 'Beckerman', + 'Galaz', + 'Graziani', + 'Kawakami', + 'Limones', + 'Mousseau', + 'Riha', + 'Huser', + 'Casady', + 'Kirker', + 'Benish', + 'Tomczyk', + 'Hallahan', + 'Kue', + 'Siple', + 'Kandel', + 'Maring', + 'Bosak', + 'Gandolfo', + 'Reichart', + 'Robarge', + 'Shufelt', + 'Forry', + 'Richart', + 'Shireman', + 'Tozzi', + 'Trudel', + 'Tat', + 'Maday', + 'Faw', + 'Lawrie', + 'Mingle', + 'Yasin', + 'Cutrone', + 'Fairbrother', + 'Ficken', + 'Kluesner', + 'Lagana', + 'Schoenborn', + 'Greb', + 'Stromain', + 'Mcpeters', + 'Toepfer', + 'Wehrman', + 'Kozma', + 'Rohner', + 'Kittel', + 'Louderback', + 'Daughtrey', + 'Philippe', + 'Bargo', + 'Cullinane', + 'Fama', + 'Fredenburg', + 'Pedone', + 'Santillanes', + 'Zahner', + 'Zupan', + 'Dundon', + 'Gilfillan', + 'Grego', + 'Otter', + 'Jamil', + 'Beaubien', + 'Collingwood', + 'Quinney', + 'Botero', + 'Edstrom', + 'Flink', + 'Ortner', + 'Schmidtke', + 'Reichle', + 'Leder', + 'Pelosi', + 'Fiorito', + 'Berber', + 'Hislop', + 'Dunstan', + 'Favorite', + 'Wooding', + 'Gariepy', + 'Gottesman', + 'Guercio', + 'Konz', + 'Kothari', + 'Laguardia', + 'Lamphier', + 'Puetz', + 'Casagrande', + 'Quay', + 'Rieth', + 'Vowell', + 'Mcanulty', + 'Mian', + 'Lucus', + 'Alvizo', + 'Domanski', + 'Elling', + 'Maniaci', + 'Neumeyer', + 'Piraino', + 'Schroll', + 'Willsey', + 'Avellaneda', + 'Wilcoxen', + 'Murrey', + 'Bennette', + 'Boyajian', + 'Distler', + 'Lindamood', + 'Maclaren', + 'Onken', + 'Stefano', + 'Uselton', + 'Wilgus', + 'Rardin', + 'Boen', + 'Stillwagon', + 'Satter', + 'Allis', + 'Capell', + 'Nedd', + 'Arcand', + 'Breit', + 'Horwath', + 'Lakatos', + 'Roling', + 'Hessel', + 'Cusson', + 'Rockefeller', + 'Shiffer', + 'Briney', + 'Celeste', + 'Sayed', + 'Revelle', + 'Corker', + 'Baldonado', + 'Lokken', + 'Plymale', + 'Sugden', + 'Twist', + 'Parten', + 'Geil', + 'Sime', + 'Grisby', + 'Jeanty', + 'Baroni', + 'Ditullio', + 'Domenico', + 'Geiss', + 'Gemmill', + 'Leng', + 'Lewicki', + 'Weyandt', + 'Haycock', + 'Coonce', + 'Pillar', + 'Medcalf', + 'Sall', + 'Goldsborough', + 'Bergerson', + 'Daffron', + 'Hinchman', + 'Leibold', + 'Sarkissian', + 'Serratos', + 'Uhlig', + 'Wurth', + 'Ost', + 'Steinmann', + 'Saum', + 'Bullion', + 'Dejonge', + 'Assad', + 'Adelson', + 'Sholes', + 'Clermont', + 'Tabron', + 'Kilduff', + 'Millspaugh', + 'Partyka', + 'Santore', + 'Wensel', + 'Zima', + 'Raschke', + 'Simonis', + 'Tuell', + 'Obriant', + 'Lewter', + 'Nealey', + 'Baranski', + 'Bloomberg', + 'Franchi', + 'Klemme', + 'Raborn', + 'Wohlgemuth', + 'Basta', + 'Bernardini', + 'Canlas', + 'Yeargin', + 'Stingley', + 'Crosland', + 'Bob', + 'Ascher', + 'Dibona', + 'Farabaugh', + 'Kilcoyne', + 'Poblete', + 'Beato', + 'Teasdale', + 'Rossell', + 'Lawhorne', + 'Jama', + 'Behringer', + 'Hallstrom', + 'Kitzman', + 'Klenk', + 'Mctigue', + 'Onate', + 'Rodda', + 'Siegal', + 'Pepple', + 'Tash', + 'Gager', + 'Hing', + 'Yokley', + 'Epting', + 'Mangham', + 'Zackery', + 'Blackerby', + 'Canedo', + 'Glatz', + 'Hilker', + 'Hummell', + 'Mangels', + 'Gamel', + 'Gang', + 'Hooser', + 'Moates', + 'Mutch', + 'Lyerly', + 'Vesey', + 'Satterthwaite', + 'Calcote', + 'Saulsbury', + 'Averette', + 'Ates', + 'Rita', + 'Vicencio', + 'Wismer', + 'Mayoral', + 'Crader', + 'Levens', + 'Joel', + 'Haye', + 'Drager', + 'Eiden', + 'Escutia', + 'Inzunza', + 'Moroz', + 'Sepulvado', + 'Tomaselli', + 'Zartman', + 'Isaak', + 'Philippi', + 'Mcgeary', + 'Taha', + 'Buttler', + 'Crisci', + 'Kot', + 'Micek', + 'Mondello', + 'Petrarca', + 'Rossini', + 'Villalvazo', + 'Weedman', + 'Mitten', + 'Favre', + 'Varnes', + 'Betancur', + 'Bevington', + 'Bockman', + 'Feldstein', + 'Kujawski', + 'Siemer', + 'Soderlund', + 'Fricker', + 'Gerstein', + 'Kick', + 'Haff', + 'Brackman', + 'Hulen', + 'Nephew', + 'Birkett', + 'Gardenhire', + 'Garn', + 'Kellenberger', + 'Mogensen', + 'Murata', + 'Weisbrod', + 'Vilchis', + 'Meder', + 'Akey', + 'Mcmanis', + 'Delatte', + 'Guiles', + 'Turnbough', + 'Murrah', + 'Kilgo', + 'Marcelin', + 'Cecchini', + 'Chrysler', + 'Eick', + 'Fletes', + 'Luevanos', + 'Kurt', + 'Firman', + 'Hensen', + 'Champine', + 'Holford', + 'Appelbaum', + 'Ciampa', + 'Florentino', + 'Lorton', + 'Lubinski', + 'Moquin', + 'Welke', + 'Grinberg', + 'Bolstad', + 'Ade', + 'Outten', + 'Grear', + 'Haith', + 'Borntreger', + 'Steinhauser', + 'Facio', + 'Preslar', + 'Speirs', + 'Grasser', + 'Zuck', + 'Deslauriers', + 'Frates', + 'Mayville', + 'Suddeth', + 'Littlepage', + 'Aversa', + 'Chagolla', + 'Godshall', + 'Jordahl', + 'Oakland', + 'Monsen', + 'Rudolf', + 'Mccollister', + 'Mickles', + 'Flaig', + 'Friberg', + 'Grubaugh', + 'Sliwinski', + 'Stach', + 'Bechtol', + 'Pasch', + 'Keebler', + 'Fagin', + 'Mister', + 'Wynter', + 'Bednarek', + 'Blansett', + 'Crossett', + 'Kettering', + 'Lafata', + 'Raffa', + 'Roig', + 'Schopp', + 'Voegele', + 'Waldschmidt', + 'Clatterbuck', + 'Amer', + 'Kraut', + 'Furniss', + 'Edgecomb', + 'Aspinwall', + 'Buckelew', + 'Loranger', + 'Koppel', + 'Vernier', + 'Latino', + 'Hayton', + 'Girod', + 'Primrose', + 'Jetter', + 'Hyche', + 'Ottley', + 'Isidro', + 'Kort', + 'Mulroy', + 'Reznik', + 'Tozer', + 'Vanderheyden', + 'Kassab', + 'Paro', + 'Belen', + 'Vandever', + 'Harsch', + 'Rawley', + 'Gonder', + 'Delbridge', + 'Alumbaugh', + 'Basulto', + 'Hoehne', + 'Mccaig', + 'Qin', + 'Rasnake', + 'Tewksbury', + 'Ratajczak', + 'Reinbold', + 'Mcgillivray', + 'Nuccio', + 'Steinbeck', + 'Deland', + 'Callow', + 'Wootten', + 'Lytton', + 'Calix', + 'Stinger', + 'Slider', + 'Cadman', + 'Faulconer', + 'Higashi', + 'Lamping', + 'Sellner', + 'Walko', + 'Kilkenny', + 'Charter', + 'Gauntt', + 'Bronk', + 'Legare', + 'Hukill', + 'Kulikowski', + 'Kunde', + 'Michelsen', + 'Mottola', + 'Pasion', + 'Stimmel', + 'Deavila', + 'Lian', + 'Koga', + 'Kitchin', + 'Whitner', + 'Bucholz', + 'Kilbride', + 'Klumpp', + 'Osinski', + 'Petrich', + 'Saar', + 'Robards', + 'Flakes', + 'Accardo', + 'Gebauer', + 'Matyas', + 'Montesano', + 'Schiefer', + 'Zuehlke', + 'Swartout', + 'Gidley', + 'Burghardt', + 'Delcambre', + 'Jerman', + 'Laufenberg', + 'Paterno', + 'Piccione', + 'Wenning', + 'Wilhelmi', + 'Rathjen', + 'Bauch', + 'Hiott', + 'Bagnall', + 'Miskell', + 'Snellings', + 'Sally', + 'Bjornson', + 'Din', + 'Kroeker', + 'Mitra', + 'Saxena', + 'Hausler', + 'Scogin', + 'Jeronimo', + 'Holderfield', + 'Cruze', + 'Christina', + 'Beville', + 'Whitehorn', + 'Bembry', + 'Fludd', + 'Abboud', + 'Blomgren', + 'Friddle', + 'Jarvi', + 'Nastasi', + 'Tomich', + 'Peinado', + 'Rinaldo', + 'Proudfoot', + 'Down', + 'Lawry', + 'Noor', + 'Bachelor', + 'Mullenax', + 'Pocock', + 'Resler', + 'Sprunger', + 'Wiegel', + 'Wohlers', + 'Niedzwiecki', + 'Bourgoin', + 'Grist', + 'Nora', + 'Gude', + 'Mcgaughy', + 'Borror', + 'Bushee', + 'Crego', + 'Engberg', + 'Karle', + 'Raso', + 'Rayas', + 'Roehrig', + 'Villamil', + 'Croucher', + 'Candido', + 'Rockhill', + 'Dahn', + 'Philp', + 'Grasty', + 'Basnight', + 'Cacioppo', + 'Heavener', + 'Hoenig', + 'Janisch', + 'Labombard', + 'Sheng', + 'Wettstein', + 'Wymore', + 'Zuluaga', + 'Canova', + 'Maclennan', + 'Tuley', + 'Geddings', + 'Cayetano', + 'Bogar', + 'Malbrough', + 'Bradish', + 'Chiaramonte', + 'Eguia', + 'Loux', + 'Nemecek', + 'Ouimet', + 'Roxas', + 'Yoshioka', + 'Cossio', + 'Sleight', + 'Walla', + 'Younan', + 'Hee', + 'Bartlow', + 'Parchman', + 'Leaks', + 'Folz', + 'Knittel', + 'Lovvorn', + 'Melick', + 'Weingartner', + 'Eustace', + 'Robbs', + 'Jacquet', + 'Direnzo', + 'Domke', + 'Kestler', + 'Pavelka', + 'Pileggi', + 'Silvestro', + 'Leedom', + 'Kyte', + 'Espey', + 'Kincannon', + 'Robicheaux', + 'Lard', + 'Falkenstein', + 'Fino', + 'Kotz', + 'Lammert', + 'Markovic', + 'Mcwaters', + 'Shibata', + 'Garoutte', + 'Brum', + 'Hora', + 'Gundrum', + 'Leer', + 'Coller', + 'Delsignore', + 'Ebarb', + 'Heras', + 'Skolnick', + 'Sponseller', + 'Baltes', + 'Rabinovich', + 'Welden', + 'Papas', + 'Bingman', + 'Neto', + 'Burrough', + 'Ollie', + 'Deitrick', + 'Hermansen', + 'Datta', + 'Gebo', + 'Bulla', + 'Rippey', + 'Solon', + 'Draughon', + 'Sylvestre', + 'Outen', + 'Westfield', + 'Daoust', + 'Kuan', + 'Kubat', + 'Labuda', + 'Olejniczak', + 'Radomski', + 'Scheuermann', + 'Schunk', + 'Tuazon', + 'Wineland', + 'Gizzi', + 'Millay', + 'Hamp', + 'Murdaugh', + 'Hayles', + 'Plowden', + 'Lesure', + 'Artrip', + 'Kenneally', + 'Piehl', + 'Vandermeulen', + 'Camberos', + 'Hochberg', + 'Sinner', + 'Crass', + 'Gade', + 'Tedrick', + 'Nicholl', + 'Speece', + 'Chatterjee', + 'Gillihan', + 'Luzzi', + 'Obyrne', + 'Uchida', + 'Kidney', + 'Dorough', + 'Dangler', + 'Mcneel', + 'Ruley', + 'Mcloud', + 'Smarr', + 'Gayles', + 'Janiszewski', + 'Kubo', + 'Mckibbin', + 'Szatkowski', + 'Lehnert', + 'Mcilvain', + 'Mcclish', + 'Mcentyre', + 'Strawder', + 'Briere', + 'Headlee', + 'Leszczynski', + 'Mauser', + 'Rask', + 'Wisler', + 'Burba', + 'Shaulis', + 'Showman', + 'Proto', + 'Creasman', + 'Slye', + 'Dunwoody', + 'Ellingsworth', + 'Linebaugh', + 'Riva', + 'Um', + 'Muldowney', + 'Burlew', + 'Gettings', + 'Clingman', + 'Shield', + 'Trollinger', + 'Stiger', + 'Kellman', + 'Arviso', + 'Boettger', + 'Deak', + 'Deiter', + 'Hackenberg', + 'Langone', + 'Lichter', + 'Siano', + 'Wrinkle', + 'Dickert', + 'Boor', + 'Ludington', + 'Griffing', + 'Perin', + 'Woodby', + 'Quail', + 'Harriss', + 'Bilotta', + 'Chino', + 'Cocke', + 'Corbell', + 'Dearden', + 'Facundo', + 'Gaskell', + 'Grieser', + 'Houts', + 'Zuk', + 'Yamauchi', + 'Caouette', + 'Perham', + 'Hewson', + 'Keppel', + 'Artiaga', + 'Sa', + 'Ginger', + 'Goosby', + 'Bollig', + 'Grippo', + 'Hoffmeyer', + 'Klaas', + 'Rohlfing', + 'Stolp', + 'Vielma', + 'Gresh', + 'Mignone', + 'Parsell', + 'Sprout', + 'Hase', + 'Nadal', + 'Joye', + 'Butkus', + 'Donlan', + 'Fuhrer', + 'Grobe', + 'Haverkamp', + 'Janecek', + 'Pancoast', + 'Rathke', + 'Scheibe', + 'Schneller', + 'Scally', + 'Valeriano', + 'Fail', + 'Everage', + 'Murff', + 'Demayo', + 'Dieterich', + 'Kramp', + 'Macchia', + 'Ruyle', + 'Zuidema', + 'Tischer', + 'Palo', + 'Bahn', + 'Hartson', + 'Rosborough', + 'Hartke', + 'Hixenbaugh', + 'Matlack', + 'Hoefler', + 'Hsia', + 'Cech', + 'Donham', + 'Szafranski', + 'Jennison', + 'Emmer', + 'Christians', + 'Swigert', + 'Mclawhorn', + 'Costas', + 'Culligan', + 'Eisenstein', + 'Joos', + 'Villacorta', + 'Majerus', + 'Lukowski', + 'Byford', + 'Canepa', + 'Jeppson', + 'Larison', + 'Waechter', + 'Bleich', + 'Trigo', + 'Lill', + 'Mcisaac', + 'Oflaherty', + 'Dedman', + 'Lynes', + 'Everidge', + 'Armfield', + 'Cadieux', + 'Dembowski', + 'Flewelling', + 'Guadagno', + 'Lamendola', + 'Meidinger', + 'Muzzy', + 'Pacelli', + 'Pangle', + 'Denzer', + 'Sharman', + 'Venzor', + 'Shadwick', + 'Saine', + 'Lighty', + 'Twine', + 'Buehner', + 'Caruana', + 'Filipiak', + 'Fiori', + 'Kellison', + 'Odonovan', + 'Ragone', + 'Enyeart', + 'Coale', + 'Coombes', + 'Yarrington', + 'Leno', + 'Coad', + 'Well', + 'Labranche', + 'Banaszak', + 'Jovanovic', + 'Junk', + 'Kratochvil', + 'Marchi', + 'Mcnitt', + 'Monnin', + 'Portales', + 'Nazzaro', + 'Laramie', + 'Kohlman', + 'Pinette', + 'Craw', + 'Aldred', + 'Jolicoeur', + 'Nevers', + 'Boseman', + 'Apostol', + 'Barbaro', + 'Dirienzo', + 'Kimrey', + 'Knaack', + 'Marenco', + 'Meixner', + 'Placek', + 'Prigge', + 'Sablan', + 'Stoecker', + 'Ulrey', + 'Madonia', + 'Mariotti', + 'Hypes', + 'Teti', + 'Pothier', + 'Duer', + 'Reay', + 'Charlie', + 'Alix', + 'Cropp', + 'Wellons', + 'Haugland', + 'Malkowski', + 'Powley', + 'Query', + 'Stolle', + 'Twedt', + 'Grech', + 'Musson', + 'Larrimore', + 'Esper', + 'Suleiman', + 'Gillie', + 'Aaronson', + 'Brueggeman', + 'Kupfer', + 'Orf', + 'Pozzi', + 'Rayos', + 'Scheiner', + 'Schmoll', + 'Sirota', + 'Trickey', + 'Ahuja', + 'Halm', + 'Jaycox', + 'Carithers', + 'Bjorkman', + 'Klar', + 'Lembke', + 'Nordyke', + 'Primeau', + 'Wachs', + 'Wissinger', + 'Doonan', + 'Mikulski', + 'Murthy', + 'Raju', + 'Thrailkill', + 'Splawn', + 'Lockamy', + 'Brassell', + 'Mcshan', + 'Hawbaker', + 'Kracht', + 'Lahman', + 'Lauritsen', + 'Metzner', + 'Presser', + 'Rapoport', + 'Romani', + 'Wolken', + 'Bertone', + 'Bhat', + 'Lenzi', + 'Lefort', + 'Makar', + 'Melnyk', + 'Siguenza', + 'Ristow', + 'Piller', + 'Mcgaugh', + 'Lampton', + 'Delva', + 'Gethers', + 'Leday', + 'Bateson', + 'Beckstrom', + 'Bedsole', + 'Hauber', + 'Hodgkinson', + 'Croghan', + 'Glanz', + 'Gaver', + 'Pinkley', + 'Traynham', + 'Heffley', + 'Indelicato', + 'Lindblad', + 'Petrik', + 'Ptacek', + 'Capen', + 'Carrara', + 'Ortuno', + 'Lobue', + 'Corella', + 'Lybrand', + 'Myler', + 'Steer', + 'Mckamey', + 'Coman', + 'Auker', + 'Escue', + 'Knell', + 'Mahood', + 'Tillinghast', + 'Deremer', + 'Janak', + 'Naegele', + 'Patnaude', + 'Leahey', + 'Pupo', + 'Bouse', + 'Bradstreet', + 'Symes', + 'Callies', + 'Duncanson', + 'Blanche', + 'Span', + 'Shakir', + 'Finneran', + 'Lenker', + 'Mendola', + 'Navin', + 'Palka', + 'Spanier', + 'Stahler', + 'Vannatter', + 'Botta', + 'Gonser', + 'Edelson', + 'Brashier', + 'Golla', + 'Parramore', + 'Bigby', + 'El', + 'Habeck', + 'Kleinhans', + 'Knobel', + 'Pekar', + 'Remmers', + 'Dea', + 'Foo', + 'Plumer', + 'Combest', + 'Godbee', + 'Hilaire', + 'Lepak', + 'Sgro', + 'Vierling', + 'Harm', + 'Holtsclaw', + 'Gaetano', + 'Kindler', + 'Sabbagh', + 'Politte', + 'Amor', + 'Tilly', + 'Trone', + 'Callaham', + 'Roussell', + 'Asplund', + 'Cacciatore', + 'Dries', + 'Friedl', + 'Hartranft', + 'Kimmell', + 'Lengacher', + 'Scardino', + 'Werley', + 'Zappa', + 'Hust', + 'Seiden', + 'Bultman', + 'Withey', + 'Brandow', + 'Oler', + 'Ladouceur', + 'Celli', + 'Condie', + 'Egge', + 'Kleman', + 'Krafft', + 'Margulies', + 'Weier', + 'Mikels', + 'Pavel', + 'Sigel', + 'Foulke', + 'Kluttz', + 'Mcgown', + 'Acero', + 'Gering', + 'Knauff', + 'Ruesch', + 'Rydberg', + 'Shonk', + 'Weisgerber', + 'Wieber', + 'Zinser', + 'Lilienthal', + 'Crosbie', + 'Luckie', + 'Chenier', + 'Aceto', + 'Atnip', + 'Hisey', + 'Imhof', + 'Klocke', + 'Renderos', + 'Schaad', + 'Shoults', + 'Slevin', + 'Tenenbaum', + 'Vrana', + 'Dicesare', + 'Colarusso', + 'Killgore', + 'Courtois', + 'Tysinger', + 'Agard', + 'Brutus', + 'Woodfork', + 'Boeckman', + 'Breitenstein', + 'Downen', + 'Franzese', + 'Garbe', + 'Iannucci', + 'Kist', + 'Mccolgan', + 'Seib', + 'Sereno', + 'Varma', + 'Fought', + 'Barcomb', + 'Happ', + 'Yeaton', + 'Sharples', + 'Huson', + 'Askin', + 'Elliston', + 'Birks', + 'Allums', + 'Richarson', + 'Arterburn', + 'Auyeung', + 'Engman', + 'Segall', + 'Sjoberg', + 'Sturman', + 'Buys', + 'Basford', + 'Gaut', + 'Hollomon', + 'Antal', + 'Groseclose', + 'Motyka', + 'Reddell', + 'Ansel', + 'Fausett', + 'Girgis', + 'Brownson', + 'Pouncy', + 'Behler', + 'Ciesla', + 'Dewall', + 'Helmers', + 'Pizzuto', + 'Sao', + 'Hourigan', + 'Novelli', + 'Kuta', + 'Gau', + 'Verville', + 'Parkison', + 'Souter', + 'Whitelaw', + 'Vercher', + 'Coger', + 'Issac', + 'Cardamone', + 'Heneghan', + 'Herrero', + 'Plancarte', + 'Reach', + 'Sarinana', + 'Zweig', + 'Berkheimer', + 'Brosseau', + 'Angstadt', + 'Popoca', + 'Brode', + 'Presswood', + 'Hannibal', + 'Pigford', + 'Argento', + 'Dieringer', + 'Kinnett', + 'Maclachlan', + 'Perko', + 'Rosenkranz', + 'Kobus', + 'Merk', + 'Prevatte', + 'Kaya', + 'Didio', + 'Thong', + 'Cowin', + 'Tumlin', + 'Lopp', + 'Callier', + 'Sesay', + 'Beerman', + 'Creger', + 'Eyster', + 'Libbey', + 'Minear', + 'Pontious', + 'Stemen', + 'Strahl', + 'Trillo', + 'Dively', + 'Lackner', + 'Welte', + 'Likes', + 'Mazzoni', + 'Resh', + 'Oser', + 'Dilday', + 'Requena', + 'Bail', + 'Ellen', + 'Buchanon', + 'Almeda', + 'Dimino', + 'Griess', + 'Wetzler', + 'Kriegel', + 'Attanasio', + 'Reighard', + 'Alling', + 'Wiginton', + 'Penfield', + 'Barbe', + 'Alred', + 'Ridout', + 'Lucien', + 'Cerullo', + 'Esterline', + 'Garriott', + 'Hendershott', + 'Kaczmarczyk', + 'Pazos', + 'Racicot', + 'Kowaleski', + 'Lippold', + 'Bankert', + 'Emigh', + 'Cupps', + 'Jagger', + 'Leavens', + 'Lies', + 'Ater', + 'Bleau', + 'Pellot', + 'Crosslin', + 'Faulks', + 'Antwine', + 'Calixte', + 'Brod', + 'Hamad', + 'Junkin', + 'Koeppel', + 'Leifer', + 'Vannest', + 'Olcott', + 'Delange', + 'Hillen', + 'Merlin', + 'Gundy', + 'Hogans', + 'Arseneau', + 'Buzard', + 'Ewalt', + 'Persing', + 'Pursel', + 'Rohrs', + 'Sisemore', + 'Vilchez', + 'Bernath', + 'Rosenbalm', + 'Woolverton', + 'Gibbins', + 'Like', + 'Larsson', + 'Savidge', + 'Strohmeyer', + 'Trentham', + 'Wotring', + 'Boster', + 'Sewall', + 'Glore', + 'Burtis', + 'Marchman', + 'Fouche', + 'Okafor', + 'Khatri', + 'Lengel', + 'Pribyl', + 'Rodewald', + 'Cafaro', + 'Mattix', + 'Shingler', + 'Seawell', + 'Square', + 'Belnap', + 'Heidemann', + 'Kretz', + 'Nebeker', + 'Zemke', + 'Reiners', + 'Cassels', + 'Hout', + 'Favor', + 'Rattray', + 'Custard', + 'Bellucci', + 'Bucklew', + 'Casavant', + 'Davanzo', + 'Kleber', + 'Koeppen', + 'Kulpa', + 'Ledonne', + 'Scarano', + 'Schaar', + 'Staiger', + 'Trigueros', + 'Trobaugh', + 'Tufano', + 'Tschetter', + 'Labra', + 'Beverage', + 'Hulet', + 'Stairs', + 'Waggener', + 'Candy', + 'Kaba', + 'Feiner', + 'Ipock', + 'Nelligan', + 'Pottorff', + 'Beno', + 'Beausoleil', + 'Mayen', + 'Kalil', + 'Deller', + 'Cormack', + 'Hayne', + 'Below', + 'Bundick', + 'Avakian', + 'Desmet', + 'Dobler', + 'Dykeman', + 'Eckstrom', + 'Mahle', + 'Meers', + 'Bortner', + 'Kroon', + 'Lindenmuth', + 'Mcnichol', + 'Sechrest', + 'Abdulla', + 'Gaudin', + 'Lamers', + 'Luffman', + 'Marchione', + 'Paredez', + 'Polster', + 'Maresh', + 'Kristoff', + 'Rickel', + 'Frary', + 'Lorance', + 'Round', + 'Toye', + 'Claybrook', + 'Senegal', + 'Gayhart', + 'Mcmackin', + 'Sagan', + 'Sarkar', + 'Whistler', + 'Stutsman', + 'Alderfer', + 'Spainhour', + 'Karol', + 'Ke', + 'Mifflin', + 'Salah', + 'Alberty', + 'Hynson', + 'Beisel', + 'Castelo', + 'Dau', + 'Diliberto', + 'Dollins', + 'Fiorini', + 'Fritzler', + 'Hanan', + 'Hauschild', + 'Overholser', + 'Wrobleski', + 'Peil', + 'Bellon', + 'Buice', + 'Rolls', + 'Shack', + 'Arakelian', + 'Carpino', + 'Liou', + 'Lydick', + 'Supple', + 'Tammaro', + 'Walbridge', + 'Jandreau', + 'Riter', + 'Roeser', + 'Merson', + 'Bole', + 'Franey', + 'Berrett', + 'Carton', + 'Mcnish', + 'Earnhart', + 'Lehrman', + 'Lipski', + 'Mandelbaum', + 'Tanabe', + 'Mirabile', + 'Ocegueda', + 'Clementi', + 'Shake', + 'Buckle', + 'Rowsey', + 'Eifert', + 'Giesen', + 'Standiford', + 'Vallecillo', + 'Walworth', + 'Berkshire', + 'Feit', + 'Lande', + 'Fiddler', + 'Deputy', + 'Feemster', + 'Evelyn', + 'Bocchino', + 'Cozza', + 'Dirocco', + 'Kock', + 'Luisi', + 'Marcantonio', + 'Presti', + 'Rahimi', + 'Ridinger', + 'Sergi', + 'Viana', + 'Kabat', + 'Suriel', + 'Mester', + 'Bozman', + 'Huffines', + 'Linck', + 'Lodato', + 'Ownbey', + 'Pietz', + 'Rudnicki', + 'Schoener', + 'Schrag', + 'Spicher', + 'Sze', + 'Villella', + 'Steinle', + 'Seaberg', + 'Derks', + 'Mavis', + 'Luellen', + 'Garlington', + 'Nimmons', + 'Brevard', + 'Seabrooks', + 'Ahlquist', + 'Golembiewski', + 'Kochis', + 'Popov', + 'Poulter', + 'Redington', + 'Wingrove', + 'Krepps', + 'Viars', + 'Gallatin', + 'Gilham', + 'Jimison', + 'Glosson', + 'Campeau', + 'Goodhart', + 'Koth', + 'Lettieri', + 'Siragusa', + 'Sojka', + 'Tichy', + 'Viar', + 'Carrozza', + 'Chaffins', + 'Eagleson', + 'Prestwood', + 'Deshazer', + 'Ike', + 'Kubacki', + 'Minogue', + 'Sunseri', + 'Turnbaugh', + 'Heminger', + 'Delira', + 'Jani', + 'Platte', + 'Waterson', + 'Keeble', + 'Kiper', + 'Crigler', + 'Swaby', + 'Brisbin', + 'Galiano', + 'Negley', + 'Regal', + 'Stottlemyer', + 'Volkmann', + 'Herrold', + 'Cypert', + 'Markman', + 'Laman', + 'Williard', + 'Terrio', + 'Raulston', + 'Harrow', + 'Humiston', + 'Kantner', + 'Mcmonagle', + 'Polasek', + 'Ruocco', + 'Schelling', + 'Seip', + 'Woller', + 'Despres', + 'Melius', + 'Keiffer', + 'Voges', + 'Figg', + 'Judice', + 'Henery', + 'Dejarnette', + 'Prosper', + 'Duenez', + 'Frenette', + 'Jaimez', + 'Krist', + 'Kuch', + 'Schlachter', + 'Traeger', + 'Mrozinski', + 'Colberg', + 'Lade', + 'Been', + 'Revere', + 'Greely', + 'Belizaire', + 'Amberg', + 'Cerniglia', + 'Lattanzio', + 'Leitz', + 'Ocker', + 'Ratto', + 'Thornburgh', + 'Yule', + 'Hibner', + 'Puerto', + 'Shoultz', + 'Baley', + 'Linley', + 'Alfrey', + 'Bazaldua', + 'Deniz', + 'Lohnes', + 'Marder', + 'Pelland', + 'Urick', + 'Loberg', + 'Rempel', + 'Faux', + 'Tomkins', + 'Gail', + 'Mccardell', + 'Reuben', + 'Brabant', + 'Hutzler', + 'Liedtke', + 'Nowack', + 'Pittsley', + 'Pelc', + 'Darragh', + 'Pae', + 'Blanke', + 'Brinks', + 'Delap', + 'Brea', + 'Milsap', + 'Borneman', + 'Crofts', + 'Nakai', + 'Silguero', + 'Speciale', + 'Martindelcampo', + 'Vandenburg', + 'Wimsatt', + 'Harbor', + 'Mccorvey', + 'Bensinger', + 'Carhart', + 'Condo', + 'Lemen', + 'Malchow', + 'Vandewater', + 'Ventresca', + 'Morena', + 'Mendell', + 'Faustino', + 'Kleiber', + 'Alberson', + 'Lamonte', + 'Kiner', + 'Belgrave', + 'Blitz', + 'Dildine', + 'Gosch', + 'Grabill', + 'Klemp', + 'Larrea', + 'Pallas', + 'Leonhard', + 'Littler', + 'Dilling', + 'Weatherbee', + 'Robnett', + 'Lacount', + 'Brackins', + 'Counterman', + 'Divincenzo', + 'Dobrowolski', + 'Eppard', + 'Estepp', + 'Gahan', + 'Steininger', + 'Tancredi', + 'Wixom', + 'Combes', + 'Dena', + 'Warn', + 'Teems', + 'Askey', + 'Delmar', + 'Ogles', + 'Herriott', + 'Aguinaldo', + 'In', + 'Kinter', + 'Moul', + 'Santaniello', + 'Tringali', + 'Vanasse', + 'Vanwagoner', + 'Whitesel', + 'Vanderwal', + 'Friedmann', + 'Kalis', + 'Cayer', + 'Para', + 'Wander', + 'Cothron', + 'Betters', + 'Cloward', + 'Cusano', + 'Encinias', + 'Imai', + 'Lalone', + 'Saks', + 'Nosal', + 'Crossan', + 'Caverly', + 'Tewell', + 'Lowney', + 'Merle', + 'Meighan', + 'Labat', + 'Pou', + 'Linsey', + 'Gaviria', + 'Manthei', + 'Marquina', + 'Siegert', + 'Blondin', + 'Maskell', + 'Kimpel', + 'Cappel', + 'Tootle', + 'Folkes', + 'Mainor', + 'Offord', + 'Clagg', + 'Minshew', + 'Niebuhr', + 'Schanz', + 'Stotz', + 'Takeda', + 'Huelsman', + 'Madril', + 'Monico', + 'Stradley', + 'Thein', + 'Cannell', + 'Malson', + 'Ludden', + 'Couts', + 'Mishoe', + 'Dales', + 'Slemp', + 'Stueve', + 'Ziemann', + 'Fluke', + 'Vitali', + 'Monn', + 'Dooling', + 'Lambe', + 'Cail', + 'Louder', + 'Lotts', + 'Augusta', + 'Ando', + 'Depaolo', + 'Egolf', + 'Hibdon', + 'Marzan', + 'Mccawley', + 'Mcgivern', + 'Minjares', + 'Mullally', + 'Portner', + 'Vinciguerra', + 'Wolpert', + 'Yingst', + 'Checo', + 'Starck', + 'Ra', + 'Credle', + 'Baldauf', + 'Bamberger', + 'Besch', + 'Caulkins', + 'Huyck', + 'Portela', + 'Walberg', + 'Kutcher', + 'Hunger', + 'Trant', + 'Cumbee', + 'Cheadle', + 'Drewery', + 'Andrada', + 'Dollinger', + 'Dondero', + 'Salvati', + 'Sefton', + 'Siemers', + 'Sitz', + 'Smale', + 'Wenk', + 'Reschke', + 'Puglia', + 'Koob', + 'Overland', + 'Furrer', + 'Gohl', + 'Hegge', + 'Hentschel', + 'Huberty', + 'Krise', + 'Stasiak', + 'Tripoli', + 'Palomera', + 'Norling', + 'Smucker', + 'Hennes', + 'Metro', + 'Himmel', + 'Paolino', + 'Prato', + 'Wommack', + 'Mcpheeters', + 'Ronald', + 'Eppinger', + 'Cantey', + 'Appell', + 'Capellan', + 'Fielden', + 'Garfias', + 'Heit', + 'Janusz', + 'Pagliaro', + 'Pitz', + 'Winegardner', + 'Gregorich', + 'Schlager', + 'Selvidge', + 'Shultis', + 'Severn', + 'Buffum', + 'Crafts', + 'Antony', + 'Timpson', + 'Deveaux', + 'Maese', + 'Merlos', + 'Mojarro', + 'Policastro', + 'Tawil', + 'Flamm', + 'Aasen', + 'Lipkin', + 'Dyches', + 'Caulk', + 'Rampersad', + 'Pettie', + 'Hagwood', + 'Jedlicka', + 'Paoli', + 'Perkey', + 'Shaub', + 'Vires', + 'Glad', + 'Mandrell', + 'Angeli', + 'Antuna', + 'Bessler', + 'Cebula', + 'Heagy', + 'Mankowski', + 'Sitler', + 'Vanleuven', + 'Blanck', + 'Dannenberg', + 'Moren', + 'Hites', + 'Leckie', + 'Tham', + 'Dower', + 'Beans', + 'Alls', + 'Sipp', + 'Dygert', + 'Kubicek', + 'Matsumura', + 'Shiroma', + 'Smiddy', + 'Szilagyi', + 'Winkleman', + 'Zentz', + 'Niehoff', + 'Boedeker', + 'Dimmitt', + 'Trew', + 'Wilner', + 'Traughber', + 'Bardales', + 'Borbon', + 'Bramhall', + 'Crofoot', + 'Desilets', + 'Disch', + 'Kehrer', + 'Leffingwell', + 'Olalde', + 'Wawrzyniak', + 'Jagodzinski', + 'Schwerin', + 'Heiney', + 'Hirano', + 'Rueter', + 'Sarris', + 'Magnan', + 'Rigsbee', + 'Blay', + 'Edgeworth', + 'Hafford', + 'Legrande', + 'Netter', + 'Dulac', + 'Etherington', + 'Gaede', + 'Matranga', + 'Misch', + 'Gryder', + 'Kolman', + 'Reyer', + 'Landsman', + 'Huppert', + 'Steagall', + 'Heims', + 'Baldini', + 'Breithaupt', + 'Claypoole', + 'Feuer', + 'Heishman', + 'Pallotta', + 'Sponaugle', + 'Pershing', + 'Spaid', + 'Salt', + 'Giger', + 'Whetsel', + 'Balaban', + 'Baus', + 'Croke', + 'Heimer', + 'Milnes', + 'Onstott', + 'Wagman', + 'Magro', + 'Havlik', + 'Menge', + 'Talmage', + 'Aungst', + 'Dichiara', + 'Kuhr', + 'Milstein', + 'Sinatra', + 'Speiser', + 'Vise', + 'Panther', + 'Phair', + 'Commons', + 'Mincy', + 'Ashline', + 'Eagen', + 'Enns', + 'Epler', + 'Giltner', + 'Rexroat', + 'Schein', + 'Wellner', + 'Wickert', + 'Ardito', + 'Ihrig', + 'Schuerman', + 'Wentland', + 'Wohlford', + 'Stoy', + 'Kohan', + 'Ratley', + 'Hazell', + 'Coppin', + 'Blackshire', + 'Coolbaugh', + 'Essman', + 'Gandee', + 'Moccia', + 'Mullarkey', + 'Sugrue', + 'Woomer', + 'Arriaza', + 'Pipitone', + 'Heart', + 'Prothro', + 'Connaughton', + 'Covelli', + 'Lunger', + 'Mcilroy', + 'Morataya', + 'Swedberg', + 'Trembley', + 'Wiederhold', + 'Zappia', + 'Perret', + 'Glander', + 'Snedden', + 'Stonestreet', + 'Archey', + 'Arbour', + 'Cordaro', + 'Diskin', + 'Dumlao', + 'Fravel', + 'Spagnuolo', + 'Derossett', + 'Grigorian', + 'Mercadante', + 'Harcourt', + 'Norgaard', + 'Terhaar', + 'Touch', + 'Mccubbins', + 'Tadros', + 'Zabriskie', + 'Fontanilla', + 'Ruse', + 'Springsteen', + 'Getter', + 'Berrian', + 'Louissaint', + 'Cobbins', + 'Dorney', + 'Kugel', + 'Luth', + 'Poffenberger', + 'Sidoti', + 'Steinfeld', + 'Poley', + 'Dreger', + 'Ertl', + 'Capper', + 'Laswell', + 'Spragg', + 'Coltrane', + 'Winborne', + 'Langhorne', + 'Fambro', + 'Berkebile', + 'Bosserman', + 'Cygan', + 'Debonis', + 'Munsch', + 'Pflug', + 'Skowron', + 'Ediger', + 'Bosler', + 'Morden', + 'Virtue', + 'Orso', + 'Claire', + 'Damas', + 'Eichenlaub', + 'Gatchell', + 'Mikus', + 'Tjaden', + 'Tremper', + 'Tusing', + 'Longest', + 'Baires', + 'Dobos', + 'Deforge', + 'Kawa', + 'Hodder', + 'Thornell', + 'Mcgarrity', + 'Gotcher', + 'Judah', + 'Busey', + 'Perrier', + 'Hawthorn', + 'Captain', + 'Costlow', + 'Frohlich', + 'Gulla', + 'Hildebrant', + 'Hilgendorf', + 'Ramachandran', + 'Reaume', + 'Vollrath', + 'Lambertson', + 'Wyer', + 'Coit', + 'Dietsch', + 'Struve', + 'Vicario', + 'Ahlberg', + 'Warshaw', + 'Ryon', + 'Evatt', + 'Mobbs', + 'Gartin', + 'Kenley', + 'Marcell', + 'Bumpers', + 'Jans', + 'Karczewski', + 'Mazurkiewicz', + 'Nadolny', + 'Verrill', + 'Sitter', + 'Freyer', + 'Hindle', + 'Hergert', + 'Inda', + 'Magwood', + 'Basa', + 'Covello', + 'Pacini', + 'Ruoff', + 'Schenker', + 'Zwicker', + 'Popovic', + 'Augustyn', + 'Sutera', + 'Almy', + 'Keisler', + 'Vowels', + 'Lemond', + 'Abila', + 'Beardslee', + 'Benvenuto', + 'Deschaine', + 'Hodel', + 'Turbyfill', + 'Vejar', + 'Iddings', + 'Labrada', + 'Bowne', + 'Seel', + 'Stretch', + 'Haswell', + 'Rickerson', + 'Speas', + 'Southward', + 'Tony', + 'Burrier', + 'Casco', + 'Lorch', + 'Pietrowski', + 'Rabbitt', + 'Sefcik', + 'Trenary', + 'Trisler', + 'Zarazua', + 'Kube', + 'Riera', + 'Stmarie', + 'Starns', + 'Carmel', + 'Shire', + 'Britto', + 'Lacks', + 'Cifelli', + 'Dusenberry', + 'Lusher', + 'Mattioli', + 'Quiring', + 'Regner', + 'Shetty', + 'Stober', + 'Winemiller', + 'Zinke', + 'Heffington', + 'Santelli', + 'Figeroa', + 'Dishon', + 'Doble', + 'Canino', + 'Tahir', + 'Stamant', + 'Sharpton', + 'Sancho', + 'Linzy', + 'Ba', + 'Bonebrake', + 'Frenkel', + 'Irion', + 'Marines', + 'Lacava', + 'Drennon', + 'Fallen', + 'Whiten', + 'Bielawski', + 'Brasch', + 'Eichorn', + 'Gattuso', + 'Neis', + 'Tkach', + 'Usrey', + 'Walkowiak', + 'Dorame', + 'Orem', + 'Crombie', + 'Lowes', + 'Truscott', + 'Marlette', + 'Bushell', + 'Gosa', + 'Hillary', + 'Byfield', + 'Engdahl', + 'Ganser', + 'Hollars', + 'Lambros', + 'Matzen', + 'Moldovan', + 'Najarian', + 'Schoff', + 'Soo', + 'Spargo', + 'Wierenga', + 'Maysonet', + 'Dewan', + 'Bardo', + 'Figgs', + 'Bostian', + 'Graser', + 'Pecor', + 'Rodrigo', + 'Spilker', + 'Suen', + 'Nafziger', + 'Khouri', + 'Milling', + 'Benke', + 'Chapdelaine', + 'Darwish', + 'Merrigan', + 'Narayanan', + 'Neuner', + 'Wallman', + 'Caracciolo', + 'Uren', + 'Borge', + 'Garside', + 'Veasley', + 'Arquette', + 'Gastineau', + 'Helbling', + 'Maggiore', + 'Prell', + 'Vangelder', + 'Giaquinto', + 'Macha', + 'Jonsson', + 'Febus', + 'Lady', + 'Hughson', + 'Wickliffe', + 'Archila', + 'Bearce', + 'Harstad', + 'Krein', + 'Kulesza', + 'Levitan', + 'Nakasone', + 'Saraceno', + 'Stankus', + 'Shelden', + 'Hopping', + 'Diab', + 'Agar', + 'Mcpike', + 'Betterton', + 'Buzbee', + 'Dieguez', + 'Lins', + 'Phuong', + 'Pinegar', + 'Postel', + 'Beatrice', + 'Biddy', + 'Over', + 'Riding', + 'Rials', + 'Rance', + 'Simington', + 'Degraffenreid', + 'Sherard', + 'Clum', + 'Harkin', + 'Mallen', + 'Messerschmidt', + 'Patz', + 'Shatzer', + 'Stetz', + 'Beckert', + 'Worm', + 'Belmontes', + 'Narron', + 'Lyne', + 'Mckendrick', + 'Rester', + 'Archbold', + 'Whorley', + 'Monts', + 'Crapo', + 'Gribbin', + 'Lamborn', + 'Leverenz', + 'Mccarville', + 'Nishida', + 'Ryberg', + 'Smeal', + 'Piontek', + 'Routhier', + 'Willmon', + 'Proffit', + 'Sharrock', + 'Gasque', + 'Minott', + 'Corpening', + 'Capizzi', + 'Dubuc', + 'Gurevich', + 'Hohenstein', + 'Kotch', + 'Peper', + 'Rehbein', + 'Stortz', + 'Corvin', + 'Savant', + 'Ryle', + 'Madere', + 'Firmin', + 'Bitterman', + 'Bruso', + 'Guzzi', + 'Hefty', + 'Almada', + 'Mcninch', + 'Mangin', + 'On', + 'Hardage', + 'Garson', + 'Hisle', + 'Dease', + 'Critelli', + 'Digennaro', + 'Ehle', + 'Freestone', + 'Grieb', + 'Haubert', + 'Kelsay', + 'Loughman', + 'Neth', + 'Pen', + 'Ranta', + 'Sater', + 'Tomei', + 'Castiglia', + 'Kosek', + 'Zentner', + 'Nowland', + 'Klinedinst', + 'Karls', + 'Charon', + 'Cart', + 'Umphrey', + 'Laramore', + 'Mckenny', + 'Hamler', + 'Stoudemire', + 'Diercks', + 'Hodzic', + 'Huntzinger', + 'Runde', + 'Scavone', + 'Halbach', + 'Banales', + 'Thiry', + 'Waterfield', + 'Bebee', + 'Dass', + 'Caughman', + 'Admire', + 'Attebery', + 'Faubion', + 'Friess', + 'Goldsworthy', + 'Raburn', + 'Vantine', + 'Newswanger', + 'Manhart', + 'Grecco', + 'Meany', + 'Rumpf', + 'Dunlevy', + 'Franceschi', + 'Romanski', + 'Alwine', + 'Cahall', + 'Czaja', + 'Krawiec', + 'Mikolajczyk', + 'Neyman', + 'Perrotti', + 'Weideman', + 'Coppa', + 'Ingerson', + 'Avena', + 'Crunk', + 'Cadenhead', + 'Gittings', + 'Gloss', + 'Trowell', + 'Denard', + 'Funchess', + 'Kinnamon', + 'Mailhot', + 'Mollohan', + 'Polacek', + 'Pozos', + 'Rempe', + 'Schutter', + 'Shimkus', + 'Bedrosian', + 'Beede', + 'Conry', + 'Legan', + 'Pickford', + 'Chamblin', + 'Depinto', + 'Geibel', + 'Gilpatrick', + 'Hashmi', + 'Hermsen', + 'Petruzzi', + 'Robben', + 'Sorkin', + 'Gambardella', + 'Podgorski', + 'Langenfeld', + 'Yanke', + 'Zipperer', + 'Tillson', + 'Ariola', + 'Kelman', + 'Hert', + 'Fearn', + 'Goods', + 'Cervenka', + 'Kreft', + 'Kreidler', + 'Kuhar', + 'Leffew', + 'Maziarz', + 'Vollmar', + 'Zmuda', + 'Eisenhower', + 'Yelle', + 'Bhagat', + 'Kirst', + 'Gilkerson', + 'Kindel', + 'Argyle', + 'Bedingfield', + 'Manney', + 'Guion', + 'Rencher', + 'Plater', + 'Beitzel', + 'Camero', + 'Delaluz', + 'Fennelly', + 'Keenum', + 'Kingrey', + 'Mckillop', + 'Munyon', + 'Rorick', + 'Schrimsher', + 'Sohl', + 'Torbett', + 'Lynde', + 'Reiland', + 'Shepley', + 'Cudney', + 'Cather', + 'Abed', + 'Holen', + 'Jobson', + 'Husbands', + 'Marc', + 'Blatz', + 'Feucht', + 'Gunkel', + 'Margolin', + 'Messerly', + 'Womer', + 'Teston', + 'Ditch', + 'Marta', + 'Osier', + 'Awan', + 'Marcella', + 'Silvester', + 'Baugus', + 'Wilcoxon', + 'Nowling', + 'Torain', + 'Badalamenti', + 'Bartosh', + 'Czajka', + 'Savedra', + 'Shaker', + 'Shambaugh', + 'Stapley', + 'Goeke', + 'Schepers', + 'Tyo', + 'Rhodus', + 'Arencibia', + 'Kara', + 'Aitchison', + 'Parlin', + 'Benny', + 'Shakespeare', + 'Altomare', + 'Axe', + 'Bednarczyk', + 'Feasel', + 'Heikkinen', + 'Heyl', + 'Konecny', + 'Montalbo', + 'Semones', + 'Zuercher', + 'Dorrance', + 'Gehrig', + 'Kretzer', + 'Puchalski', + 'Asche', + 'Astacio', + 'Steers', + 'Jeanes', + 'Bamberg', + 'Matthis', + 'Maultsby', + 'Bunkley', + 'Afonso', + 'Danielsen', + 'Freier', + 'Graeff', + 'Gutknecht', + 'Jansky', + 'Lindenberg', + 'Macphee', + 'Pequeno', + 'Petrocelli', + 'Petrowski', + 'Prete', + 'Igoe', + 'Demonte', + 'Khatib', + 'Agin', + 'Siddall', + 'Mcdill', + 'Higginbottom', + 'Gallow', + 'Inniss', + 'Ballman', + 'Bieniek', + 'Casino', + 'Garringer', + 'Griese', + 'Heritage', + 'Zeitz', + 'Montanaro', + 'Qi', + 'Belcastro', + 'Brautigam', + 'Wakeland', + 'Keasler', + 'Oglesbee', + 'Saye', + 'Steppe', + 'Cichocki', + 'Melgarejo', + 'Primavera', + 'Rippe', + 'Sieger', + 'Stutes', + 'Tustin', + 'Vanloon', + 'Konkol', + 'Altmann', + 'Anderegg', + 'Bun', + 'Mcduffee', + 'Deo', + 'Persad', + 'Kindell', + 'Antillon', + 'Ast', + 'Kumm', + 'Lauricella', + 'Minkler', + 'Pilch', + 'Porreca', + 'Shoopman', + 'Skeels', + 'Chanthavong', + 'Hounshell', + 'Pitner', + 'Space', + 'Blackley', + 'Groomes', + 'Bleeker', + 'Duddy', + 'Inlow', + 'Knabe', + 'Lehmkuhl', + 'Salais', + 'Statz', + 'Sundin', + 'Woolston', + 'Hojnacki', + 'Drolet', + 'Gallivan', + 'Viner', + 'Hafley', + 'Hollan', + 'Phillis', + 'Montrose', + 'Colclough', + 'Coaxum', + 'Basel', + 'Campoverde', + 'Cirelli', + 'Delmonico', + 'Goh', + 'Goyal', + 'Hungate', + 'Lufkin', + 'Passaro', + 'Penta', + 'Quispe', + 'Ovalles', + 'Bulkley', + 'Show', + 'Purington', + 'Sockwell', + 'Mccluney', + 'Asato', + 'Buchta', + 'Cassara', + 'Cesena', + 'Empey', + 'Fass', + 'Gazda', + 'Giannetti', + 'Giuffre', + 'Jahns', + 'Jong', + 'Ruh', + 'Schmieder', + 'Sheerin', + 'Weinheimer', + 'Iwamoto', + 'Ouyang', + 'Uranga', + 'Ranalli', + 'Woolum', + 'Calabria', + 'Arrowsmith', + 'Cashen', + 'Vogan', + 'Giffen', + 'Sherk', + 'Denner', + 'Lanclos', + 'Whittlesey', + 'Dora', + 'Plain', + 'Bransford', + 'Bradwell', + 'Davitt', + 'Dehoff', + 'Lotito', + 'Roell', + 'Satterly', + 'Stahr', + 'Thiem', + 'Helberg', + 'Vause', + 'Willmore', + 'Seid', + 'Linebarger', + 'Geddis', + 'Bringhurst', + 'Damelio', + 'Fetterolf', + 'Galban', + 'Henkle', + 'Kamen', + 'Kaneko', + 'Kissane', + 'Rua', + 'Tehrani', + 'Tingey', + 'Lizardi', + 'Strick', + 'Halper', + 'Striker', + 'Amason', + 'Lesueur', + 'Tatem', + 'Bulluck', + 'Hobdy', + 'Flythe', + 'Brookover', + 'Fishbein', + 'Hartless', + 'Snelgrove', + 'Weikert', + 'Wissman', + 'Bourbeau', + 'Colclasure', + 'Sampley', + 'Shubin', + 'Rhoda', + 'Mcclane', + 'Meals', + 'Peets', + 'Anding', + 'Clewis', + 'Gaymon', + 'Bierly', + 'Brockmeyer', + 'Burnworth', + 'Dierking', + 'Patzer', + 'Seipel', + 'Shieh', + 'Pazmino', + 'Bailie', + 'Ducey', + 'Sessler', + 'Hornaday', + 'Andry', + 'Mowatt', + 'Charlot', + 'Buchholtz', + 'Gaulke', + 'Gondek', + 'Grossmann', + 'Hammerschmidt', + 'Heinle', + 'Huckabay', + 'Neathery', + 'Vanzile', + 'Vossler', + 'Schillaci', + 'Lem', + 'Paff', + 'Oja', + 'Broker', + 'Marlett', + 'Innocent', + 'Adsit', + 'Begg', + 'Kocian', + 'Maddalena', + 'Melamed', + 'Mikos', + 'Pio', + 'Poth', + 'Richwine', + 'Ruda', + 'Sackman', + 'Querry', + 'Padro', + 'Sober', + 'Ayscue', + 'Puff', + 'Hunton', + 'Woltz', + 'Alsobrook', + 'Baskins', + 'Daggs', + 'Brands', + 'Buechel', + 'Gonda', + 'Haberkorn', + 'Hartel', + 'Hazeltine', + 'Lantrip', + 'Leoni', + 'Licona', + 'Stanke', + 'Zwart', + 'Aplin', + 'Leatham', + 'Ace', + 'Ganter', + 'Bartolomeo', + 'Colgrove', + 'Halling', + 'Hesler', + 'Hainline', + 'Susi', + 'Kroner', + 'Sanden', + 'Rylander', + 'Basaldua', + 'Fujiwara', + 'Hengst', + 'Kapur', + 'Kienzle', + 'Miao', + 'Mutschler', + 'Orsi', + 'Pais', + 'Termini', + 'Yamane', + 'Zipp', + 'Wildey', + 'Bauerle', + 'Rehn', + 'Hipsher', + 'Staubin', + 'Esquilin', + 'Goley', + 'Buenaventura', + 'Frutos', + 'Gaugler', + 'Maclellan', + 'Mehring', + 'Stiers', + 'Gearheart', + 'Bong', + 'Maddocks', + 'Canary', + 'Urie', + 'Skillings', + 'Amir', + 'Bogus', + 'Oakman', + 'Barresi', + 'Cappelli', + 'Clausing', + 'Genest', + 'Grella', + 'Mulherin', + 'Roettger', + 'Corle', + 'Mantel', + 'Mody', + 'Delapp', + 'Dunnington', + 'Harvard', + 'Berquist', + 'Foglia', + 'Gilbride', + 'Krenek', + 'Gagnier', + 'Berney', + 'Bazzell', + 'Selvage', + 'Gullette', + 'Lavan', + 'Gunderman', + 'Holaday', + 'Horine', + 'Salata', + 'Slaybaugh', + 'Tobia', + 'Knick', + 'Tinkle', + 'Calcaterra', + 'Fauth', + 'Helmke', + 'Margiotta', + 'Mejorado', + 'Salomone', + 'Sevy', + 'Suri', + 'Vasconcellos', + 'Vetrano', + 'Flaten', + 'Sweetser', + 'Logston', + 'Varon', + 'Allsop', + 'Mickler', + 'Swails', + 'Conejo', + 'Derosia', + 'Hamre', + 'Hanvey', + 'Holscher', + 'Interiano', + 'Kleinberg', + 'Kravetz', + 'Reinking', + 'Schow', + 'Schur', + 'Vanbrocklin', + 'Yinger', + 'Zelenka', + 'Chagoya', + 'Sieben', + 'Devora', + 'Archambeau', + 'Burpee', + 'Shamp', + 'Stander', + 'Weaks', + 'Viney', + 'Halloway', + 'Artiga', + 'Clinkenbeard', + 'Kenison', + 'Loeza', + 'Schaap', + 'Simoni', + 'Frock', + 'Galea', + 'Graven', + 'Brookhart', + 'Gurr', + 'Mackintosh', + 'Arjona', + 'Busche', + 'Salvi', + 'Bedenbaugh', + 'Duan', + 'Clara', + 'Brundidge', + 'Akhter', + 'Amsler', + 'Bolz', + 'Bonura', + 'Brumbelow', + 'Droste', + 'Lohmeyer', + 'Lorah', + 'Louthan', + 'Botti', + 'Feigenbaum', + 'Thon', + 'Osbourn', + 'Peugh', + 'Viau', + 'Elsayed', + 'Hilyard', + 'Coram', + 'Alvin', + 'Milbourne', + 'Hickmon', + 'Basu', + 'Fasnacht', + 'Heathcock', + 'Matsui', + 'Oyama', + 'Stransky', + 'Blakesley', + 'Antes', + 'Flury', + 'Lacrosse', + 'Lull', + 'Clelland', + 'Rugh', + 'Hamelin', + 'Reta', + 'Barnet', + 'Ballow', + 'Pyburn', + 'Slayden', + 'Freshwater', + 'Fomby', + 'Bourquin', + 'Bowersock', + 'Calleros', + 'Dallmann', + 'Gootee', + 'Koelling', + 'Parfitt', + 'Pruss', + 'Tretter', + 'Bellini', + 'Gulden', + 'Pett', + 'Mcglasson', + 'Yerby', + 'Buth', + 'Curnow', + 'Goller', + 'Halderman', + 'Kulig', + 'Laue', + 'Roesner', + 'Samra', + 'Sorrow', + 'Vanbibber', + 'Mellin', + 'Villacis', + 'Hilborn', + 'Ditty', + 'Vasey', + 'Crall', + 'Sera', + 'Honeywell', + 'Blanchet', + 'Halim', + 'Nevius', + 'Ines', + 'Stuard', + 'Birr', + 'Curnutt', + 'Deibler', + 'Jaster', + 'Ouk', + 'Poppell', + 'Provence', + 'Rebman', + 'Schmick', + 'Terra', + 'Zea', + 'Hoven', + 'Loth', + 'Arreaga', + 'Cambre', + 'Roots', + 'Gains', + 'Jeancharles', + 'Cerritos', + 'Ihle', + 'Zambito', + 'Brueggemann', + 'Kluth', + 'Schwartzkopf', + 'Shott', + 'Mcglaughlin', + 'Decoster', + 'Northam', + 'Esau', + 'Fling', + 'Castile', + 'Milledge', + 'Desjarlais', + 'Laframboise', + 'Remigio', + 'Rudloff', + 'Utecht', + 'Enrique', + 'Wygant', + 'Fairbank', + 'Behl', + 'Meuse', + 'Pyke', + 'Fury', + 'Chowning', + 'Hyndman', + 'Donat', + 'Nuckles', + 'Cartledge', + 'Bilal', + 'Antonacci', + 'Huether', + 'Kha', + 'Mascia', + 'Rothberg', + 'Sieck', + 'Younes', + 'Sassaman', + 'Amparan', + 'Benesh', + 'Faraci', + 'Gaber', + 'Lehew', + 'Belzer', + 'Segoviano', + 'Teagle', + 'Burian', + 'Menne', + 'Niemeier', + 'Old', + 'Olenick', + 'Takemoto', + 'Tepe', + 'Test', + 'Zahler', + 'Matsuoka', + 'Hopf', + 'Misenheimer', + 'Mings', + 'Hullett', + 'Beutel', + 'Criscuolo', + 'Fedak', + 'Holtkamp', + 'Kretschmer', + 'Mongillo', + 'Mulrooney', + 'Panganiban', + 'Pollick', + 'Sgroi', + 'Shirkey', + 'Stodola', + 'Tozier', + 'Weidler', + 'Puskar', + 'Fiorello', + 'Stille', + 'Pomales', + 'Gladding', + 'Griffie', + 'Warmack', + 'Uzzell', + 'Stennis', + 'Buttrey', + 'Ekberg', + 'Harmsen', + 'Lieske', + 'Madriz', + 'Mohs', + 'Reininger', + 'Edgin', + 'Galla', + 'Chattin', + 'Frayer', + 'Brents', + 'Lasker', + 'Angelone', + 'Boulter', + 'Burritt', + 'Choudhry', + 'Claffey', + 'Elizarraras', + 'Gaumer', + 'Gawronski', + 'Henwood', + 'Lapine', + 'Bitar', + 'Himel', + 'Almand', + 'Brase', + 'Lala', + 'Salama', + 'Essick', + 'Longman', + 'Mone', + 'Reynard', + 'Brackney', + 'Cottam', + 'Donadio', + 'Geesey', + 'Laudenslager', + 'Mcgilvray', + 'Yano', + 'Bueche', + 'Irey', + 'Carneal', + 'Tinder', + 'Walke', + 'Baston', + 'Segar', + 'Brisbane', + 'Venson', + 'Arguijo', + 'Beitler', + 'Burek', + 'Burgener', + 'Collyer', + 'Donlin', + 'Duhaime', + 'Dworak', + 'Frech', + 'Kozik', + 'Montejo', + 'Nhan', + 'Quirarte', + 'Tram', + 'Deshpande', + 'Silverthorn', + 'Leard', + 'Sheller', + 'Alphin', + 'Boxer', + 'Shawn', + 'Pinnick', + 'Stigler', + 'Arpin', + 'Falkenberg', + 'Gerig', + 'Lemonds', + 'Salm', + 'Sarkis', + 'Paprocki', + 'Probasco', + 'Haithcock', + 'Carn', + 'Farrish', + 'Haliburton', + 'Copen', + 'Pieri', + 'Slaymaker', + 'Cardarelli', + 'Veneziano', + 'Melfi', + 'Solley', + 'Hymer', + 'Pleitez', + 'Hinsley', + 'Bruen', + 'Arita', + 'Dreisbach', + 'Fichtner', + 'Keckler', + 'Slaby', + 'Tanguma', + 'Wiberg', + 'Ferrucci', + 'Lick', + 'Maginnis', + 'Quaranta', + 'Bera', + 'Maybee', + 'Hennessee', + 'Kerrick', + 'Kabir', + 'Branscome', + 'Fullington', + 'Menser', + 'Brooking', + 'Patridge', + 'Gue', + 'Gowens', + 'Redus', + 'Ector', + 'Distasio', + 'Kissner', + 'Prada', + 'Sponsler', + 'Tempel', + 'Wedemeyer', + 'Degler', + 'Bodenhamer', + 'Sherbert', + 'Jefferis', + 'Belgarde', + 'Bevel', + 'Figaro', + 'Bertino', + 'Fabbri', + 'Kovacevic', + 'Kunst', + 'Leja', + 'Ruffo', + 'Stearman', + 'Trickett', + 'Zafar', + 'Valdivieso', + 'Curbelo', + 'Mabee', + 'Emma', + 'Arman', + 'Swasey', + 'Lyday', + 'Muff', + 'Rideaux', + 'Ahlgren', + 'Cobo', + 'Hanratty', + 'Litwiller', + 'Mallonee', + 'Glunt', + 'Moudy', + 'Hickam', + 'Mahmud', + 'Fate', + 'Hemsley', + 'Biery', + 'Buechner', + 'Fragale', + 'Hornbaker', + 'Lacorte', + 'Mateos', + 'Mickley', + 'Reusch', + 'Sabado', + 'Schnurr', + 'Gasior', + 'Konkle', + 'Okazaki', + 'Doubleday', + 'Couvillion', + 'Lupien', + 'Oder', + 'Ohair', + 'Win', + 'Quaintance', + 'Diltz', + 'Poythress', + 'Percell', + 'Weatherall', + 'Ainslie', + 'Brandner', + 'Byrge', + 'Cawood', + 'Heatwole', + 'Kerschner', + 'Looker', + 'Racz', + 'Skirvin', + 'Steitz', + 'Svenson', + 'Vermette', + 'Zupancic', + 'Monnier', + 'Scafidi', + 'Trousdale', + 'Bares', + 'Costantini', + 'Frees', + 'Kallio', + 'Methvin', + 'Prudencio', + 'Hayse', + 'Mahabir', + 'Wafford', + 'Borgmann', + 'Cogley', + 'Gigante', + 'Kurkowski', + 'Lavoy', + 'Wertheimer', + 'Wienke', + 'Goodling', + 'Danek', + 'Brinley', + 'Charlson', + 'Whitsell', + 'Lowen', + 'Minnix', + 'Lowers', + 'Palin', + 'Burgher', + 'Lorick', + 'Sobers', + 'Gavigan', + 'Italiano', + 'Liebl', + 'Prevette', + 'Wehunt', + 'Radin', + 'Guillotte', + 'Mode', + 'Halfacre', + 'Stjames', + 'Isabelle', + 'Meggs', + 'Burkard', + 'Giannotti', + 'Justo', + 'Kasprzyk', + 'Kuba', + 'Mino', + 'Morganti', + 'Schnelle', + 'Serfass', + 'Yacoub', + 'Thode', + 'Wykoff', + 'Macbeth', + 'Oxner', + 'Mayhue', + 'Saulter', + 'Budnik', + 'Gandarilla', + 'Michalec', + 'Eisel', + 'Newmark', + 'Placido', + 'Bellar', + 'Dollarhide', + 'Huett', + 'Copher', + 'Lacaze', + 'Dominic', + 'Bibler', + 'Boydstun', + 'Faas', + 'Grana', + 'Guardino', + 'Illig', + 'Luebbert', + 'Lyford', + 'Mcgettigan', + 'Repko', + 'Widmann', + 'Trevathan', + 'Ewan', + 'Mcray', + 'Footman', + 'Kerchner', + 'Leggio', + 'Bullinger', + 'Rushford', + 'Edel', + 'Leandro', + 'Burkman', + 'Grattan', + 'Tench', + 'Dartez', + 'Lemar', + 'Fane', + 'Zenon', + 'Sabb', + 'Blatchford', + 'Chilcoat', + 'Hahne', + 'Hanssen', + 'Mawhinney', + 'Pflueger', + 'Pol', + 'Vitelli', + 'Brierley', + 'Zundel', + 'Mcgillicuddy', + 'Adriano', + 'Mate', + 'Wilkison', + 'Ramnarine', + 'Peaks', + 'Bacote', + 'Barretto', + 'Benevento', + 'Gubler', + 'Koelsch', + 'Naas', + 'Patane', + 'Schnitzler', + 'Sprenkle', + 'Ulbrich', + 'Violante', + 'Rench', + 'Najarro', + 'Kristensen', + 'Poma', + 'Sara', + 'Jerrell', + 'Sarratt', + 'Mondy', + 'Antill', + 'Belleville', + 'Dworkin', + 'Holdaway', + 'Lenderman', + 'Murga', + 'Reiling', + 'Stasko', + 'Topel', + 'Verity', + 'Vinas', + 'Ziebarth', + 'Vanguilder', + 'Stoots', + 'Yantis', + 'Faries', + 'Tulley', + 'Baucum', + 'Fugett', + 'Harring', + 'Semien', + 'Dauphinais', + 'Furukawa', + 'Grilli', + 'Ohanian', + 'Ormiston', + 'Osegueda', + 'Wiegert', + 'Zier', + 'Chiesa', + 'Radecki', + 'Mongeon', + 'Stake', + 'Sweetland', + 'Shearon', + 'Lamore', + 'Mccuiston', + 'Minson', + 'Burditt', + 'Mcferren', + 'Covin', + 'Straker', + 'Elzy', + 'Althaus', + 'Anzures', + 'Glaeser', + 'Huseby', + 'Nitta', + 'Ribaudo', + 'Sobota', + 'Spieker', + 'Stefaniak', + 'Valois', + 'Vanwie', + 'Venturini', + 'Beltre', + 'Ewer', + 'Hartt', + 'Keaney', + 'Throne', + 'Edrington', + 'Inmon', + 'Isabel', + 'Brayman', + 'Devilbiss', + 'Krasner', + 'Malak', + 'Tito', + 'Vermeer', + 'Benigno', + 'Bosque', + 'Berridge', + 'Clines', + 'Brite', + 'Mcbeath', + 'Gleaves', + 'Koenen', + 'Kubicki', + 'Kudla', + 'Seiple', + 'Warkentin', + 'Choiniere', + 'Nassif', + 'Banko', + 'Muncie', + 'Garling', + 'Causby', + 'Mcgaw', + 'Burkeen', + 'Balan', + 'Georgia', + 'Hick', + 'Tumblin', + 'Badon', + 'Warrior', + 'Yearby', + 'Hiestand', + 'Hughart', + 'Proffer', + 'Sult', + 'Yepes', + 'Zachman', + 'Beddow', + 'Molyneux', + 'Camejo', + 'Stephany', + 'Cadogan', + 'Gosha', + 'Goodwine', + 'Harewood', + 'Burnsed', + 'Frappier', + 'Minardi', + 'Rieser', + 'Tabbert', + 'Marietta', + 'Butch', + 'Steil', + 'Canal', + 'Brundige', + 'Comas', + 'Hopkinson', + 'Shomo', + 'Kendle', + 'Bowsher', + 'Illingworth', + 'Kampa', + 'Manasco', + 'Mcdorman', + 'Theurer', + 'Widger', + 'Carbonneau', + 'Stachura', + 'Eriksson', + 'Trostle', + 'Foxworthy', + 'Lex', + 'Belman', + 'Isola', + 'Mckane', + 'Gearing', + 'Rimes', + 'Couillard', + 'Emanuele', + 'Pho', + 'Scimeca', + 'Skaar', + 'Vibbert', + 'Bilby', + 'Hink', + 'Gohn', + 'Nguy', + 'Perrett', + 'Bowland', + 'Comes', + 'Moffet', + 'Pauline', + 'Donalson', + 'Tilman', + 'Hansberry', + 'Acedo', + 'Camarda', + 'Devivo', + 'Eurich', + 'Jojola', + 'Railsback', + 'Rumfelt', + 'Stastny', + 'Strittmatter', + 'Houseknecht', + 'Rynearson', + 'Weinrich', + 'Kinghorn', + 'Astin', + 'Aguillard', + 'Hameed', + 'Drone', + 'Lonon', + 'Burgio', + 'Klimas', + 'Riegler', + 'Schiano', + 'Slonaker', + 'Deery', + 'Weissinger', + 'Cea', + 'Grenz', + 'Arent', + 'Sopher', + 'Jarratt', + 'Mitchener', + 'Conigliaro', + 'Dohm', + 'Feenstra', + 'Meiers', + 'Hetland', + 'Kinsinger', + 'Kmiec', + 'Teich', + 'Fukushima', + 'Kerins', + 'Cienfuegos', + 'Orlandi', + 'Bonser', + 'Okun', + 'Coate', + 'Rittenberry', + 'Mcclaine', + 'Dunklin', + 'Citizen', + 'Danzy', + 'Geers', + 'Georgeson', + 'Kikuchi', + 'Macinnis', + 'Malizia', + 'Mukai', + 'Plants', + 'Ehmann', + 'Haren', + 'Lachney', + 'Duchesne', + 'Collinson', + 'Connett', + 'Hostler', + 'Farnell', + 'Osler', + 'Triche', + 'Ballweg', + 'Bansal', + 'Galo', + 'Hollabaugh', + 'Hultquist', + 'Mcbrien', + 'Pelz', + 'Picciano', + 'Tashjian', + 'Thresher', + 'Uphoff', + 'Shawley', + 'Tomasek', + 'Aldaz', + 'Harig', + 'Kullman', + 'Vaness', + 'Isabella', + 'Munley', + 'Bissette', + 'Thackston', + 'Borgia', + 'Camire', + 'Charters', + 'Feiler', + 'Geisinger', + 'Racca', + 'Rasmusson', + 'Stonesifer', + 'Vidmar', + 'Arciga', + 'Bialek', + 'Baruch', + 'Kornfeld', + 'Harmeyer', + 'Picon', + 'Suppa', + 'Strate', + 'Hyre', + 'Verdon', + 'Reily', + 'Castell', + 'Foard', + 'Exner', + 'Furnari', + 'Guereca', + 'Hallgren', + 'Holsclaw', + 'Ketelsen', + 'Magnani', + 'Mehling', + 'Naser', + 'Seder', + 'Sparr', + 'Strnad', + 'Tatar', + 'Crecelius', + 'Knicely', + 'Vantassell', + 'Balsley', + 'Babbs', + 'Gowans', + 'Mcclam', + 'Batdorf', + 'Belsky', + 'Gull', + 'Letizia', + 'Ludlum', + 'Mascari', + 'Scheffel', + 'Spurgin', + 'Dignan', + 'Steffensen', + 'Freeberg', + 'Honan', + 'Hamric', + 'Woolman', + 'Valeri', + 'Saab', + 'Boyers', + 'Pardon', + 'Deasy', + 'Forshey', + 'Juntunen', + 'Kamel', + 'Macisaac', + 'Marinaro', + 'Milroy', + 'Parillo', + 'Rappold', + 'Schippers', + 'Smola', + 'Staniszewski', + 'Strasburg', + 'Epple', + 'Dewitte', + 'Hubley', + 'Queener', + 'Stoddart', + 'Briant', + 'Mcclurkin', + 'Binkowski', + 'Eberts', + 'Kilbane', + 'Kiraly', + 'Monsalve', + 'Othman', + 'Pasek', + 'Rinke', + 'Steinbrecher', + 'Trees', + 'Winther', + 'Boal', + 'Eber', + 'Funez', + 'Harryman', + 'Boyter', + 'Rill', + 'Jolliffe', + 'Dorian', + 'Demore', + 'Sebree', + 'Jeff', + 'Jolivette', + 'Elko', + 'Jividen', + 'Lenzen', + 'Marsee', + 'Milbrandt', + 'Orihuela', + 'Osterhoudt', + 'Parras', + 'Schnepp', + 'Tenaglia', + 'Thoren', + 'Diosdado', + 'Pingree', + 'Rutigliano', + 'Filbert', + 'Babel', + 'Stollings', + 'Hopes', + 'Bynes', + 'Brockmann', + 'Carta', + 'Deleeuw', + 'Demo', + 'Margeson', + 'Mckitrick', + 'Reyez', + 'Sidor', + 'Strehlow', + 'Timlin', + 'Wegrzyn', + 'Burgdorf', + 'Benzing', + 'Bonneville', + 'Clonts', + 'Camps', + 'Graydon', + 'Pasha', + 'Andreoli', + 'Cockerill', + 'Covino', + 'Hajjar', + 'Korpi', + 'Pohlmann', + 'Wente', + 'Wickwire', + 'Schaber', + 'Vonderhaar', + 'Manser', + 'Fitton', + 'Galindez', + 'Ares', + 'Longmore', + 'Buchert', + 'Delisi', + 'Gaulin', + 'Genco', + 'Helgerson', + 'Khawaja', + 'Radosevich', + 'Sannicolas', + 'Sterk', + 'Theberge', + 'Voiles', + 'Warchol', + 'Potthoff', + 'Runkel', + 'Stachowski', + 'Snay', + 'Share', + 'Conkey', + 'Pontes', + 'Mathies', + 'Brittian', + 'Allgeier', + 'Daughenbaugh', + 'Glock', + 'Meisinger', + 'Pantaleo', + 'Saitta', + 'Weick', + 'Burak', + 'Borda', + 'Rim', + 'Bunyard', + 'Neaves', + 'Mcilvaine', + 'Zee', + 'Buskey', + 'Roseborough', + 'Bellin', + 'Fasulo', + 'Grab', + 'Jia', + 'Knab', + 'Skalski', + 'Stensland', + 'Zajicek', + 'Echeverry', + 'Kolenda', + 'Cadden', + 'Delawder', + 'Propp', + 'Scheeler', + 'Clukey', + 'Loven', + 'Bogen', + 'Whittingham', + 'Barcelona', + 'Braasch', + 'Haubrich', + 'Kolberg', + 'Vendetti', + 'Sheesley', + 'Bartoli', + 'Knierim', + 'Amparo', + 'Lauth', + 'Rosero', + 'Burry', + 'Guynes', + 'Cumbo', + 'Pridgeon', + 'Aarons', + 'Alarid', + 'Arakawa', + 'Benzel', + 'Bywater', + 'Grosch', + 'Heth', + 'Logiudice', + 'Maisel', + 'Morquecho', + 'Wahlberg', + 'Teigen', + 'Bockelman', + 'Rehak', + 'Bitler', + 'Brion', + 'Niece', + 'Selvey', + 'Sudderth', + 'Ruddock', + 'Sandiford', + 'Aguas', + 'Folan', + 'Herwig', + 'Krupinski', + 'Mccarrick', + 'Mudgett', + 'Pancake', + 'Redner', + 'Wentzell', + 'Soliday', + 'Marschall', + 'Krakowski', + 'Rebholz', + 'Dold', + 'Giller', + 'Gassett', + 'Brazzell', + 'Bellow', + 'Tolen', + 'Gloster', + 'Gagliardo', + 'Harbuck', + 'Lorber', + 'Natarajan', + 'Sarna', + 'Schrack', + 'Vena', + 'Witzke', + 'Minassian', + 'Loi', + 'Rogue', + 'Trace', + 'Bomba', + 'Cozzens', + 'Evett', + 'Boze', + 'Petros', + 'Cotta', + 'Eisenmann', + 'Florea', + 'Hammersley', + 'Keohane', + 'Necessary', + 'Nodine', + 'Pekarek', + 'Sjogren', + 'Ruybal', + 'Arabie', + 'Huntsinger', + 'Eiseman', + 'Mehler', + 'Craner', + 'Vandine', + 'Gaffey', + 'Menna', + 'Royle', + 'Cordrey', + 'Gala', + 'Gauss', + 'Dacruz', + 'Cardell', + 'Devan', + 'Calmes', + 'Humber', + 'Stoute', + 'Balko', + 'Cera', + 'Griesbach', + 'Kissick', + 'Kloos', + 'Oertel', + 'Sedlock', + 'Stellato', + 'Tuite', + 'Bero', + 'Rinard', + 'Dambra', + 'Cinelli', + 'Tea', + 'Hicken', + 'Linch', + 'Dials', + 'Bennefield', + 'Hillsman', + 'Flemister', + 'Alvaro', + 'Goranson', + 'Henk', + 'Ryden', + 'Verhagen', + 'Wessling', + 'Willetts', + 'Neidlinger', + 'Pereida', + 'Lainhart', + 'Nemes', + 'Rudzinski', + 'Sward', + 'Rom', + 'Rosko', + 'Runions', + 'Henney', + 'Ridgely', + 'Tomson', + 'Arballo', + 'Bohorquez', + 'Brixey', + 'Durling', + 'Espina', + 'Esquivias', + 'Nungaray', + 'Ovando', + 'Zapf', + 'Pizza', + 'Arel', + 'Ballin', + 'Heathman', + 'Morison', + 'Troop', + 'Monfort', + 'Copland', + 'Harriott', + 'Mcwhite', + 'Amini', + 'Cirilo', + 'Gassner', + 'Gulbranson', + 'Kovatch', + 'Venne', + 'Terriquez', + 'Savin', + 'Amo', + 'Moris', + 'Crable', + 'Delaughter', + 'Greenhouse', + 'Eckardt', + 'Hendrixson', + 'Manansala', + 'Mongeau', + 'Panko', + 'Pichette', + 'Sliwa', + 'Tabak', + 'Determan', + 'Freeburg', + 'Portell', + 'Steller', + 'Buffkin', + 'Righter', + 'Mcguinn', + 'Corrie', + 'Tatham', + 'Smelley', + 'Terrel', + 'Selmon', + 'Blecha', + 'Eisler', + 'Engelking', + 'Goen', + 'Krey', + 'Mceldowney', + 'Plamondon', + 'Slovak', + 'Sorce', + 'Spagnolo', + 'Wambold', + 'Colborn', + 'Englander', + 'Monsour', + 'Pait', + 'Perricone', + 'Loveridge', + 'Cragg', + 'Dies', + 'Holsten', + 'Dagley', + 'Beverley', + 'Bayona', + 'Cam', + 'Chock', + 'Coppersmith', + 'Donath', + 'Guillemette', + 'Iannelli', + 'Potratz', + 'Selander', + 'Suk', + 'Waldvogel', + 'Olberding', + 'Giaimo', + 'Spoto', + 'Crocco', + 'Waskiewicz', + 'Krizan', + 'Vigo', + 'Boarman', + 'Ron', + 'Facer', + 'Garlow', + 'Filsaime', + 'Andersson', + 'Demski', + 'Derouin', + 'Diegel', + 'Feria', + 'Foth', + 'Hertzberg', + 'Jillson', + 'Kram', + 'Mammen', + 'Melhorn', + 'Monjaras', + 'Oslund', + 'Petrin', + 'Pinho', + 'Scheerer', + 'Shadden', + 'Sitzman', + 'Stumbaugh', + 'Wengert', + 'Gershon', + 'Mcelhinney', + 'Batterson', + 'Macqueen', + 'Janas', + 'Gladson', + 'Aull', + 'Wasinger', + 'Shemwell', + 'Seats', + 'Colas', + 'Allbee', + 'Fithian', + 'Fonner', + 'Gergen', + 'Lubrano', + 'Mannarino', + 'Piscopo', + 'Sydow', + 'Werle', + 'Aumiller', + 'Coplen', + 'Dardar', + 'Morrisette', + 'Mchaney', + 'Simes', + 'Gillison', + 'Emmel', + 'Klunk', + 'Luber', + 'Madeira', + 'Schlicht', + 'Tremain', + 'Cleaveland', + 'Boulet', + 'Golladay', + 'Enck', + 'Fera', + 'Hammar', + 'Hebner', + 'Ishee', + 'Nanni', + 'Palomar', + 'Pangborn', + 'Rogala', + 'Rushlow', + 'Wiedman', + 'Laber', + 'Schoenfelder', + 'Sonner', + 'Duffer', + 'Granier', + 'Sawin', + 'Dwiggins', + 'Jaso', + 'Popplewell', + 'Loren', + 'Ord', + 'Dearmon', + 'Hammen', + 'Misra', + 'Reindl', + 'Siordia', + 'Woodhead', + 'Yasuda', + 'Dockstader', + 'Kobs', + 'Tokarski', + 'Villers', + 'Mase', + 'Arrant', + 'Hedgpeth', + 'Eggleton', + 'Frederic', + 'Victorian', + 'Akerman', + 'Balazs', + 'Brandau', + 'Depietro', + 'Dillenbeck', + 'Goodnow', + 'Larner', + 'Mcmurtrie', + 'Salameh', + 'Swicegood', + 'Koshy', + 'Stdenis', + 'Deakin', + 'Izzi', + 'Teater', + 'Gramm', + 'Doig', + 'Blacklock', + 'Haymore', + 'Heggie', + 'Kirklin', + 'Kassa', + 'Ryles', + 'Tenner', + 'Ndiaye', + 'Burrola', + 'Faires', + 'Grega', + 'Krentz', + 'Needles', + 'Portz', + 'Ruedas', + 'Sitko', + 'Viernes', + 'Setter', + 'Tricarico', + 'Prest', + 'Olivar', + 'Whitsitt', + 'Labossiere', + 'Bellomo', + 'Burgeson', + 'Capriotti', + 'Drinnon', + 'Gulati', + 'Haffey', + 'Lasota', + 'Laughery', + 'Mees', + 'Melander', + 'Paoletti', + 'Petermann', + 'Zerby', + 'Burhans', + 'Lasseigne', + 'Vannote', + 'Wai', + 'Berson', + 'Gritton', + 'Searl', + 'Toller', + 'Brackeen', + 'Screws', + 'Hagens', + 'Billingslea', + 'Hyppolite', + 'Asmussen', + 'Bitton', + 'Diiorio', + 'Grigoryan', + 'Hauenstein', + 'Krukowski', + 'Mulcahey', + 'Perras', + 'Prak', + 'Reitzel', + 'Spackman', + 'Valenciano', + 'Wieck', + 'Yeagley', + 'Zanetti', + 'Goeller', + 'Azizi', + 'Grise', + 'Mogan', + 'Traverso', + 'Nangle', + 'Saladin', + 'Hardgrove', + 'Osei', + 'Fehrenbach', + 'Giesbrecht', + 'Halas', + 'Hetzler', + 'Orsak', + 'Salaz', + 'Surace', + 'Whipp', + 'Charlebois', + 'Stayer', + 'Stelmach', + 'Hitchings', + 'Senters', + 'Mcnaught', + 'Cordier', + 'Dawsey', + 'Barhorst', + 'Clauser', + 'Dibernardo', + 'Hawkey', + 'Hritz', + 'Patchin', + 'Raatz', + 'Seubert', + 'Slingerland', + 'Vanderwoude', + 'Aquilino', + 'Goertzen', + 'Navratil', + 'Mccuistion', + 'Vallin', + 'Moors', + 'Connely', + 'Fedrick', + 'Bontempo', + 'Dishong', + 'Felch', + 'Laino', + 'Minshall', + 'Montroy', + 'Plotts', + 'Radice', + 'Sachse', + 'Safran', + 'Schecter', + 'Traut', + 'Vasile', + 'Yadon', + 'Gorka', + 'Roelofs', + 'Suit', + 'Asbill', + 'Torrens', + 'Kimmey', + 'Ruger', + 'Vinzant', + 'Watkin', + 'Rawles', + 'Cubero', + 'Duch', + 'Endress', + 'Fangman', + 'Holben', + 'Holzapfel', + 'Karner', + 'Otteson', + 'Stangel', + 'Terrebonne', + 'Wagley', + 'Wisecup', + 'Bengston', + 'Leck', + 'Coalson', + 'Farooq', + 'Safi', + 'Smyers', + 'All', + 'Else', + 'Wason', + 'Nairn', + 'Panton', + 'Ahrendt', + 'Arvizo', + 'Klahn', + 'Robak', + 'Schier', + 'Start', + 'Tiano', + 'Kraatz', + 'Corzo', + 'Maranto', + 'Elm', + 'Eagles', + 'Acres', + 'Schoolfield', + 'Ancrum', + 'Ahner', + 'Augsburger', + 'Berna', + 'Danh', + 'Fruth', + 'Galluzzo', + 'Racette', + 'Selva', + 'Szekely', + 'Zirbel', + 'Hauff', + 'Markgraf', + 'Wonderly', + 'Rydell', + 'Julia', + 'Chris', + 'Simson', + 'Bridgeford', + 'Jeffress', + 'Brailsford', + 'Bluford', + 'Boser', + 'Fichera', + 'Meininger', + 'Meyerhoff', + 'Modzelewski', + 'Niese', + 'Pavlovich', + 'Radovich', + 'Ratz', + 'Frankowski', + 'Berti', + 'Geno', + 'Fares', + 'Marney', + 'Harwick', + 'Tata', + 'Bobby', + 'Dobbin', + 'Roosevelt', + 'Greenaway', + 'Janvier', + 'Oatis', + 'Beilke', + 'Brelsford', + 'Dowty', + 'Giudice', + 'Hetzer', + 'Imboden', + 'Irelan', + 'Nie', + 'Ramberg', + 'Rega', + 'Sproat', + 'Sytsma', + 'Unrein', + 'Davignon', + 'Ganoe', + 'Leinweber', + 'Mantell', + 'Troisi', + 'Sahr', + 'Esperanza', + 'Asper', + 'Lathem', + 'Eagleton', + 'Lamons', + 'Gaulden', + 'Bloodgood', + 'Cerone', + 'Claro', + 'Durfey', + 'Enamorado', + 'Herrada', + 'Maw', + 'Schlagel', + 'Signor', + 'Reisch', + 'Gruenwald', + 'Helbert', + 'Lorenzi', + 'Woodlief', + 'Huval', + 'Batman', + 'Meadow', + 'Croswell', + 'Bordonaro', + 'Earnshaw', + 'Freiburger', + 'Gunnoe', + 'Lamberton', + 'Martella', + 'Mischke', + 'Shelor', + 'Venuti', + 'Bilek', + 'Mcmains', + 'Balding', + 'Mestre', + 'Mcconnaughey', + 'Manso', + 'Decoste', + 'Egerton', + 'Alvino', + 'Arizpe', + 'Blaschke', + 'Foglesong', + 'Heyn', + 'Irigoyen', + 'Komorowski', + 'Lesinski', + 'Nghiem', + 'Rund', + 'Santiesteban', + 'Strahm', + 'Hendel', + 'Capes', + 'Carls', + 'Bon', + 'Sires', + 'Nichelson', + 'Brimm', + 'Aikins', + 'Berra', + 'Brazee', + 'Burkert', + 'Capalbo', + 'Criscione', + 'Feddersen', + 'Hofbauer', + 'Jacobowitz', + 'Mackowiak', + 'Mcenroe', + 'Philbeck', + 'Shimada', + 'Ticknor', + 'Wozny', + 'Biernacki', + 'Hirschi', + 'Polich', + 'Sokoloski', + 'Dolores', + 'Knoch', + 'Ge', + 'Groome', + 'Markell', + 'Fearing', + 'Mcclaren', + 'Hadsell', + 'Rumple', + 'Samudio', + 'Scardina', + 'Spinosa', + 'Abramov', + 'Siracusa', + 'Goren', + 'Rocchio', + 'Bibi', + 'Lamer', + 'Liddy', + 'Anna', + 'Coxe', + 'De', + 'Rodes', + 'Cheshier', + 'Coulon', + 'Closs', + 'Tigue', + 'Seville', + 'Hopkin', + 'Rodwell', + 'Bibbins', + 'Baldree', + 'Bawden', + 'Bishoff', + 'Costabile', + 'Dec', + 'Hillegass', + 'Infantino', + 'Mantia', + 'Mcamis', + 'Northcott', + 'Ruprecht', + 'Sanpedro', + 'Campione', + 'Muchow', + 'Ostby', + 'Mohl', + 'Pulice', + 'Vigna', + 'Thomann', + 'Lillibridge', + 'Manville', + 'Vives', + 'Bellanger', + 'Desormeaux', + 'Lovingood', + 'Stjulien', + 'Echeverri', + 'Florey', + 'Gieseke', + 'Maeder', + 'Marcinko', + 'Nuncio', + 'Quirino', + 'Versteeg', + 'Voelkel', + 'Wanless', + 'Morocho', + 'Monteagudo', + 'Aikin', + 'Bramley', + 'Bartleson', + 'Skeete', + 'Batra', + 'Dolloff', + 'Gehr', + 'Hellyer', + 'Hersch', + 'Hier', + 'Lannan', + 'Reffitt', + 'Carboni', + 'Schouten', + 'Burkle', + 'Riches', + 'Busa', + 'Rademaker', + 'Hult', + 'Synder', + 'Bossard', + 'Tunis', + 'Pamplin', + 'Oats', + 'Mcphaul', + 'Baik', + 'Kieser', + 'Pareja', + 'Raffaele', + 'Erhard', + 'Iwasaki', + 'Tonelli', + 'Mabey', + 'Debruyn', + 'Carrel', + 'Myron', + 'Arai', + 'Vallo', + 'Points', + 'Buteau', + 'Becknell', + 'Lue', + 'Antos', + 'Folkers', + 'Galletta', + 'Hissong', + 'Knoche', + 'Kundert', + 'Larussa', + 'Lobos', + 'Poitra', + 'Rinn', + 'Seamons', + 'Senko', + 'Villaverde', + 'Weatherholt', + 'Maliszewski', + 'Jurkowski', + 'Scism', + 'Hallas', + 'Collet', + 'Capello', + 'Lena', + 'Popper', + 'Aikman', + 'Blakes', + 'Cadigan', + 'Dupler', + 'Kazi', + 'Masri', + 'Matejka', + 'Mcgirr', + 'Pistone', + 'Prenger', + 'Ranes', + 'Thiemann', + 'Voeller', + 'Cockman', + 'Burtt', + 'Looby', + 'Bonnie', + 'Mcclenny', + 'Ridgell', + 'Nails', + 'Lesane', + 'Bertolino', + 'Doheny', + 'Fechter', + 'Holshouser', + 'Kierstead', + 'Krewson', + 'Lanahan', + 'Vig', + 'Wiswell', + 'Freytag', + 'Haselden', + 'Kuras', + 'Navar', + 'Raisor', + 'Finamore', + 'Kipper', + 'Morissette', + 'Laughton', + 'Awe', + 'Manier', + 'Cumby', + 'Cabada', + 'Hafen', + 'Kojima', + 'Massari', + 'Mctague', + 'Stehr', + 'Vandevelde', + 'Voong', + 'Wisely', + 'Girardin', + 'Bies', + 'Demaris', + 'Galles', + 'Goldstone', + 'Kai', + 'Cord', + 'Brigance', + 'Gomillion', + 'Drakes', + 'Bartkowiak', + 'Chica', + 'Draheim', + 'Honeyman', + 'Klapper', + 'Kniffen', + 'Knoblock', + 'Scherzer', + 'Tougas', + 'Toyama', + 'Urbach', + 'Walia', + 'Wattenbarger', + 'Marz', + 'Cesare', + 'Miro', + 'Kervin', + 'Godard', + 'Beiter', + 'Betcher', + 'Evarts', + 'Evensen', + 'Gaff', + 'Griffitts', + 'Grunden', + 'Hoffart', + 'Kroupa', + 'Maiers', + 'Mckendry', + 'Puett', + 'Shoe', + 'Stermer', + 'Wineinger', + 'Brocious', + 'Chudy', + 'Spofford', + 'Wessinger', + 'Weich', + 'Croff', + 'Ephraim', + 'Sallis', + 'Blasco', + 'Burningham', + 'Buschmann', + 'Forget', + 'Kulak', + 'Panozzo', + 'Pierpont', + 'Priolo', + 'Puhl', + 'Ruffolo', + 'Voisine', + 'Mancinelli', + 'Santacroce', + 'Vanvalkenburgh', + 'Veverka', + 'Desena', + 'Agner', + 'Boron', + 'Wheeling', + 'Plato', + 'Tonge', + 'Deibel', + 'Herriman', + 'Holroyd', + 'Huitron', + 'Hum', + 'Kreamer', + 'Lada', + 'Lucena', + 'Pao', + 'Planck', + 'Vanroekel', + 'Bodell', + 'Francia', + 'Anastasia', + 'Haxton', + 'Maile', + 'Warning', + 'Labeau', + 'Pujol', + 'Done', + 'Minney', + 'Hogsett', + 'Tayler', + 'Delancy', + 'Philson', + 'Allemand', + 'Buhrman', + 'Diefenbach', + 'Gawel', + 'Kovacic', + 'Kralik', + 'Lazor', + 'Mcnemar', + 'Warth', + 'Glanzer', + 'Keep', + 'Hochstein', + 'Febles', + 'Morneau', + 'Agostinelli', + 'Galeas', + 'Landen', + 'Lion', + 'Attwood', + 'Capshaw', + 'Willy', + 'Dekle', + 'Murrill', + 'Coby', + 'Falvo', + 'Kanagy', + 'Mihalko', + 'Schellenberg', + 'Sugimoto', + 'Lippard', + 'Sardo', + 'Suckow', + 'Demichele', + 'Kath', + 'Lappe', + 'Lego', + 'Schleifer', + 'Vold', + 'Kingsland', + 'Mitch', + 'Manlove', + 'Cuozzo', + 'Dauber', + 'Deininger', + 'Goldbach', + 'Halfmann', + 'Kazarian', + 'Marksberry', + 'Marzec', + 'Mcmurphy', + 'Oregan', + 'Paczkowski', + 'Pinsky', + 'Poynor', + 'Schertz', + 'Tetrick', + 'Umali', + 'Valenza', + 'Witherington', + 'Kesselring', + 'Nylund', + 'Cinnamon', + 'Rielly', + 'Surman', + 'Fowle', + 'Hains', + 'Sharlow', + 'Lones', + 'Durgan', + 'Savory', + 'Minger', + 'Okon', + 'Berends', + 'Binning', + 'Malina', + 'Loeser', + 'Marthaler', + 'Pacella', + 'Vasta', + 'Hinerman', + 'Goodchild', + 'Chuck', + 'Linney', + 'Beckworth', + 'Carrie', + 'Lovings', + 'Ginyard', + 'Bredeson', + 'Debiase', + 'Gorder', + 'Noce', + 'Redlin', + 'Schwinn', + 'Zins', + 'Burtner', + 'Kosakowski', + 'Erler', + 'Altom', + 'Husman', + 'Markos', + 'Thorman', + 'Fagen', + 'Voisin', + 'Gauldin', + 'Pressey', + 'Calbert', + 'Holness', + 'Alspach', + 'Broeker', + 'Danziger', + 'Klenke', + 'Popescu', + 'Schoenrock', + 'Schreckengost', + 'Syme', + 'Trick', + 'Plautz', + 'Beckel', + 'Dealmeida', + 'Winne', + 'Moron', + 'Seed', + 'Capozzoli', + 'Gawron', + 'Kobel', + 'Kouns', + 'Nunemaker', + 'Steinbacher', + 'Stookey', + 'Vidana', + 'Zoch', + 'Ohlinger', + 'Hudkins', + 'Ferren', + 'Gille', + 'Sheckler', + 'Kittell', + 'Roath', + 'Ziglar', + 'Brecher', + 'Coldren', + 'Degraaf', + 'Eddinger', + 'Joffe', + 'Luthy', + 'Metzinger', + 'Nayak', + 'Paule', + 'Prudente', + 'Wooddell', + 'Zuccaro', + 'Rineer', + 'Soos', + 'Manka', + 'Vandervoort', + 'Kitchell', + 'Casserly', + 'Watchman', + 'Poteete', + 'Dopson', + 'Mathurin', + 'Cataldi', + 'Crepeau', + 'Fackrell', + 'Goben', + 'Macinnes', + 'Scherf', + 'Shaddix', + 'Sorber', + 'Teichman', + 'Wydra', + 'Holzworth', + 'Baade', + 'Tinnell', + 'Tinkler', + 'Mauzy', + 'Alphonse', + 'Fullard', + 'Adger', + 'Akiyama', + 'Bloxham', + 'Coultas', + 'Esler', + 'Giebel', + 'Goswick', + 'Heikes', + 'Javed', + 'Linan', + 'Mooers', + 'Nemetz', + 'Pradhan', + 'Rainone', + 'Romito', + 'Treichel', + 'Vohs', + 'Grosskopf', + 'Weisinger', + 'Ruple', + 'Naff', + 'Meaders', + 'Lamarr', + 'Toppin', + 'Apicella', + 'Beecroft', + 'Boshears', + 'Breier', + 'Cuadros', + 'Umbarger', + 'Alioto', + 'Ravenscroft', + 'Vesper', + 'Oak', + 'Tigges', + 'Simmer', + 'Hanby', + 'Webre', + 'Lenk', + 'Mcelvain', + 'Boy', + 'Debarros', + 'Hickenbottom', + 'Quincy', + 'Billips', + 'Ollison', + 'Barbuto', + 'Clearwater', + 'Cronkhite', + 'Groleau', + 'Mehra', + 'Tessler', + 'Kegel', + 'Borenstein', + 'Newnam', + 'Crofton', + 'Phenix', + 'Dankert', + 'Hymas', + 'Lobel', + 'Marszalek', + 'Moceri', + 'Ottaviano', + 'Papazian', + 'Roedel', + 'Jochum', + 'Urquidez', + 'Lapin', + 'Garro', + 'Lamond', + 'Sessums', + 'Tooke', + 'Steadham', + 'Azam', + 'Bleier', + 'Buelna', + 'Bupp', + 'Burridge', + 'Derderian', + 'Derstine', + 'Halberg', + 'Katzer', + 'Meegan', + 'Ortmann', + 'Herschberger', + 'Sanroman', + 'Winiarski', + 'Alcon', + 'Picker', + 'Demille', + 'Huron', + 'Hankin', + 'Dahmen', + 'Fronczak', + 'Klingman', + 'Perugini', + 'Pettinato', + 'Powelson', + 'Saffer', + 'Schwenke', + 'Pals', + 'Estremera', + 'Sofia', + 'Arvelo', + 'Terrero', + 'Bankes', + 'Sais', + 'Netherland', + 'Odeh', + 'Sutphen', + 'Caddy', + 'Dorval', + 'Glaude', + 'Mcadory', + 'Eichinger', + 'Lesniewski', + 'Petito', + 'Pfohl', + 'Presler', + 'Rys', + 'Sano', + 'Willenborg', + 'Seppala', + 'Shibley', + 'Cajigas', + 'Gal', + 'Farag', + 'Pickles', + 'Rump', + 'Grills', + 'Mikes', + 'Adderley', + 'Altland', + 'Araki', + 'Beitz', + 'Brotzman', + 'Buonocore', + 'Fayard', + 'Gelber', + 'Jurewicz', + 'Lezcano', + 'Marsteller', + 'Minarik', + 'Opsahl', + 'Pranger', + 'Tiburcio', + 'Zollo', + 'Engh', + 'Henault', + 'Barrineau', + 'Pilkinton', + 'Pratte', + 'Niland', + 'Warda', + 'Southwood', + 'Clinch', + 'Halsell', + 'Mccaa', + 'Isreal', + 'Pinkett', + 'Asch', + 'Beauchesne', + 'Bruemmer', + 'Doebler', + 'Ehlinger', + 'Goelz', + 'Hashemi', + 'Karel', + 'Magiera', + 'Martorano', + 'Mooneyhan', + 'Cibrian', + 'Cavey', + 'Kosko', + 'Christo', + 'Cockrill', + 'Mansker', + 'Balls', + 'Degree', + 'Tiggs', + 'Alberico', + 'Clugston', + 'Elman', + 'Frueh', + 'Kampf', + 'Kochanski', + 'Leider', + 'Marsella', + 'Mckendree', + 'Moffa', + 'Quattrocchi', + 'Raval', + 'Snoke', + 'Akopyan', + 'Barrilleaux', + 'Cambria', + 'Kawaguchi', + 'Bonde', + 'Dawdy', + 'Willig', + 'Kazee', + 'Debow', + 'Beachum', + 'Vicks', + 'Aurelio', + 'Barocio', + 'Bonesteel', + 'Ezzo', + 'Gesell', + 'Krzeminski', + 'Madan', + 'Magda', + 'Manring', + 'Mcfaul', + 'Morera', + 'Purinton', + 'Retzer', + 'Schonfeld', + 'Staszak', + 'Stubbe', + 'Talerico', + 'Wikoff', + 'Zia', + 'Seyfried', + 'Diangelo', + 'Keach', + 'Shipton', + 'Shewmake', + 'Behrmann', + 'Hopps', + 'Paster', + 'Augenstein', + 'Castaldi', + 'Ferrufino', + 'Gregersen', + 'Hosseini', + 'Keniston', + 'Nadolski', + 'Ouimette', + 'Pellett', + 'Riebel', + 'Schwark', + 'Spelman', + 'Tesar', + 'Yahn', + 'Grossnickle', + 'Rosillo', + 'Dostie', + 'Noa', + 'Khalaf', + 'Cardosa', + 'Afzal', + 'Mercure', + 'Wheless', + 'Tailor', + 'Mcgarrah', + 'Miler', + 'Norfolk', + 'Crapps', + 'Dansereau', + 'Jenney', + 'Keast', + 'Lieser', + 'Mihm', + 'Porco', + 'Zelinsky', + 'Sleeth', + 'Mcelreath', + 'Hemann', + 'Capaldi', + 'Huggett', + 'Reagle', + 'Mayotte', + 'Liller', + 'Leen', + 'Demmer', + 'Tunison', + 'Woodbridge', + 'Haymes', + 'Cunning', + 'Blaze', + 'Eatman', + 'Ulysse', + 'Bagshaw', + 'Buczkowski', + 'Cardello', + 'Decola', + 'Diloreto', + 'Evola', + 'Glassburn', + 'Hazelbaker', + 'Holycross', + 'Minasian', + 'Regula', + 'Ruge', + 'Uhlman', + 'Lamprecht', + 'Shifflet', + 'Weikle', + 'Coupe', + 'Isherwood', + 'Dimon', + 'Pop', + 'Willhoite', + 'Bari', + 'Boise', + 'Doom', + 'Mccolley', + 'Bircher', + 'Wannamaker', + 'Eppes', + 'Pea', + 'Okeke', + 'Alpizar', + 'Arista', + 'Barbagallo', + 'Baumert', + 'Bhattacharya', + 'Gheen', + 'Hutchcraft', + 'Karlen', + 'Klier', + 'Ladnier', + 'Marrujo', + 'Reister', + 'Rorrer', + 'Tarpey', + 'Wisecarver', + 'Beydoun', + 'Fillinger', + 'Kemnitz', + 'Takata', + 'Leight', + 'Kross', + 'Junco', + 'Holmer', + 'Sando', + 'Biddix', + 'Dawood', + 'Frisco', + 'Flagler', + 'Arntz', + 'Bache', + 'Bundrick', + 'Glasson', + 'Los', + 'Scheiber', + 'Shellenbarger', + 'Steinmeyer', + 'Sura', + 'Tanski', + 'Teodoro', + 'Vanaken', + 'Jodoin', + 'Klinker', + 'Szydlowski', + 'Yamashiro', + 'Kutch', + 'Hoth', + 'Edwardson', + 'Gess', + 'Mohamad', + 'Goodine', + 'Carolina', + 'Blauser', + 'Emerich', + 'Flook', + 'Graul', + 'Gribben', + 'Herbold', + 'Kreutz', + 'Lavey', + 'Lukacs', + 'Maiorana', + 'Openshaw', + 'Plattner', + 'Sauro', + 'Schardt', + 'Tortorici', + 'Wendlandt', + 'Danowski', + 'Mcnellis', + 'Pinkowski', + 'Linz', + 'Virga', + 'Jardin', + 'Maclaughlin', + 'Rama', + 'Deline', + 'Kimbel', + 'Hagin', + 'Pottinger', + 'Detmer', + 'Ferrone', + 'Matthiesen', + 'Melchert', + 'Ruehl', + 'Takach', + 'Briese', + 'Elmendorf', + 'Valentini', + 'Hersom', + 'Bordeau', + 'Linsley', + 'Keatts', + 'Dina', + 'Boye', + 'Riviere', + 'Stodghill', + 'Madry', + 'Angelos', + 'Bou', + 'Ketterling', + 'Niemczyk', + 'Pardini', + 'Rippel', + 'Schieffer', + 'Schnee', + 'Shogren', + 'Sholl', + 'Ullmann', + 'Ure', + 'Curless', + 'Gonnella', + 'Tholen', + 'Valladolid', + 'Silbernagel', + 'Cohrs', + 'Shahin', + 'Beth', + 'Holmen', + 'Tippie', + 'Opie', + 'Sprowl', + 'Byam', + 'Bethany', + 'Saintil', + 'Auriemma', + 'Blust', + 'Dibello', + 'Digangi', + 'Farnam', + 'Farnan', + 'Linford', + 'Mcgroarty', + 'Meisenheimer', + 'Pagels', + 'Sauber', + 'Schwalbe', + 'Seemann', + 'Slivka', + 'Twardowski', + 'Wickey', + 'Zettler', + 'Zuchowski', + 'Feldhaus', + 'Baldock', + 'Cowman', + 'Carp', + 'Camera', + 'Balon', + 'Neveu', + 'Caminiti', + 'Carreira', + 'Gura', + 'Hershkowitz', + 'Killoran', + 'Narducci', + 'Reigel', + 'Saccone', + 'Tomasi', + 'Wieneke', + 'Sibrian', + 'Hashem', + 'Kellems', + 'Stouder', + 'Villamar', + 'Piette', + 'Wand', + 'Battey', + 'Staunton', + 'Bedore', + 'Hanel', + 'Jutras', + 'Kanner', + 'Mathiesen', + 'Northway', + 'Privitera', + 'Reichelt', + 'Zucco', + 'Roys', + 'Aderholt', + 'Lampson', + 'Olen', + 'Mcgarr', + 'Schools', + 'Leaphart', + 'Lykes', + 'Brightbill', + 'Koos', + 'Lahue', + 'Laplaca', + 'Naqvi', + 'Novo', + 'Puerta', + 'Siers', + 'Strutz', + 'Trimboli', + 'Waldie', + 'Goold', + 'Falke', + 'Corter', + 'Cartmell', + 'Brazel', + 'Farabee', + 'Majeed', + 'Hilden', + 'Kealoha', + 'Neider', + 'Parodi', + 'Rizza', + 'Rong', + 'Silberstein', + 'Snellgrove', + 'Trojanowski', + 'Warneke', + 'Wissler', + 'Yiu', + 'Grein', + 'Sak', + 'Daines', + 'Monzo', + 'Emmerson', + 'Lorraine', + 'Samaroo', + 'Edmund', + 'Cacace', + 'Dornan', + 'Eyman', + 'Hovanec', + 'Jeschke', + 'Limberg', + 'Maturo', + 'Pandey', + 'Somoza', + 'Streiff', + 'Wiemer', + 'Zablocki', + 'Crace', + 'Leinen', + 'Rucci', + 'Blyth', + 'Clemans', + 'Magid', + 'Ferrick', + 'Garriga', + 'Martir', + 'Tanton', + 'Hoon', + 'Echard', + 'Borrell', + 'Howden', + 'Gravett', + 'Lando', + 'Amacher', + 'Dalman', + 'Hollenbaugh', + 'Sigrist', + 'Tamashiro', + 'Therriault', + 'Villafranca', + 'Matthys', + 'Salois', + 'Sforza', + 'Swager', + 'Borah', + 'Sentell', + 'Besson', + 'Ghani', + 'Bilinski', + 'Holzinger', + 'Kus', + 'Lobianco', + 'Morawski', + 'Perz', + 'Sada', + 'Wollenberg', + 'Yusko', + 'Caughron', + 'Diffenderfer', + 'Slowinski', + 'Skiver', + 'Galland', + 'Hodes', + 'Boyne', + 'Towry', + 'Alers', + 'Hellums', + 'Certain', + 'Megginson', + 'Creer', + 'Coutee', + 'Strothers', + 'Stfleur', + 'Barga', + 'Bina', + 'Cellini', + 'Digiulio', + 'Douma', + 'Klement', + 'Mccambridge', + 'Parmeter', + 'Presto', + 'Salmi', + 'Seabaugh', + 'Barreda', + 'Nepomuceno', + 'Zent', + 'Yonce', + 'Loreto', + 'Honer', + 'Conquest', + 'Gathings', + 'Wims', + 'Upshur', + 'Aeschliman', + 'Casaus', + 'Dumke', + 'Earlywine', + 'Ferreyra', + 'Heyne', + 'Hudon', + 'Kuder', + 'Malia', + 'Brueckner', + 'Luchsinger', + 'Ornellas', + 'Ramseyer', + 'Weidemann', + 'Walbert', + 'Zola', + 'Linquist', + 'Storts', + 'Dente', + 'Lebleu', + 'Stockham', + 'Rollinson', + 'Auzenne', + 'Abebe', + 'Bartol', + 'Cozzolino', + 'Der', + 'Fata', + 'Gorr', + 'Janousek', + 'Moschella', + 'Riedy', + 'Dust', + 'Malmgren', + 'Puterbaugh', + 'Sacchetti', + 'Lascano', + 'Begnaud', + 'Duling', + 'Porteous', + 'Debnam', + 'Abron', + 'Delehanty', + 'Fazenbaker', + 'Flener', + 'Gora', + 'Herter', + 'Johann', + 'Keiter', + 'Lucca', + 'Passman', + 'Saindon', + 'Schoppe', + 'Skibinski', + 'Stueber', + 'Tegeler', + 'Jochim', + 'Buttner', + 'Crilly', + 'Swanton', + 'Muncey', + 'Negrin', + 'Thorburn', + 'Delpino', + 'Kinn', + 'Gaiter', + 'Obi', + 'Hohensee', + 'Rollman', + 'Scheff', + 'Shor', + 'Tumbleson', + 'Mccrum', + 'Knack', + 'Llano', + 'Saber', + 'Rosman', + 'Bankson', + 'Atkisson', + 'Kennel', + 'Cammon', + 'Bangura', + 'Cichy', + 'Gillikin', + 'Hiltner', + 'Lubben', + 'Mcqueeney', + 'Nasca', + 'Nordgren', + 'Ostermann', + 'Quito', + 'Sakowski', + 'Schut', + 'Stobaugh', + 'Alessio', + 'Gorelik', + 'Heinzman', + 'Westrich', + 'Nardella', + 'Cruzado', + 'Lansberry', + 'Dubreuil', + 'Nylander', + 'Rabel', + 'Moret', + 'Crout', + 'Ardrey', + 'Rolley', + 'Finks', + 'Cliett', + 'Caito', + 'Clingenpeel', + 'Delprete', + 'Dolen', + 'Heidrich', + 'Hinrichsen', + 'Jindra', + 'Madej', + 'Panzarella', + 'Sandin', + 'Seekins', + 'Shilts', + 'Sokoloff', + 'Maggart', + 'Pigman', + 'Travieso', + 'Denbow', + 'Dollison', + 'Gaye', + 'Binette', + 'Dutta', + 'Grandinetti', + 'Kitch', + 'Tangeman', + 'Finstad', + 'Rodkey', + 'Servis', + 'Tiwari', + 'Rodd', + 'Parfait', + 'Seck', + 'Delaurentis', + 'Dragan', + 'Fleig', + 'Giacobbe', + 'Hilligoss', + 'Kroh', + 'Lippe', + 'Maleski', + 'Perini', + 'Rutten', + 'Stauss', + 'Yoshikawa', + 'Dibattista', + 'Gilsdorf', + 'Riemenschneider', + 'Streck', + 'Gessler', + 'Springstead', + 'Zaki', + 'Lambie', + 'Barczak', + 'Ellerbrock', + 'Foresman', + 'Holstine', + 'Lemm', + 'Santillana', + 'Trautwein', + 'Unsworth', + 'Valderas', + 'Vaquero', + 'Vetsch', + 'Wadleigh', + 'Yonts', + 'Mcguiness', + 'Auvil', + 'Leeder', + 'Sprowls', + 'Cala', + 'Portalatin', + 'Casso', + 'Chirinos', + 'Less', + 'Baltzell', + 'Bo', + 'Whetsell', + 'Ledlow', + 'Fullbright', + 'Arnell', + 'Stainback', + 'Mcleish', + 'Lyn', + 'Bermeo', + 'Billet', + 'Craun', + 'Gladwell', + 'Goral', + 'Herbig', + 'Kluver', + 'Mermelstein', + 'Odette', + 'Poggi', + 'Schacher', + 'Thielman', + 'Cianciolo', + 'Ferrie', + 'Kapusta', + 'Kreager', + 'Messineo', + 'Rovira', + 'Stricklen', + 'Wansley', + 'Amell', + 'Baena', + 'Depaula', + 'Fickett', + 'Housewright', + 'Kreiger', + 'Legate', + 'Lutterman', + 'Men', + 'Pautz', + 'Swecker', + 'Tantillo', + 'Dudeck', + 'Bellas', + 'Marian', + 'Bienvenu', + 'Riden', + 'Hosein', + 'Couser', + 'Batterton', + 'Desantos', + 'Dieterle', + 'Drabek', + 'Grennan', + 'Greulich', + 'Ludlam', + 'Maltos', + 'Marcin', + 'Ostertag', + 'Rednour', + 'Tippetts', + 'Updyke', + 'Ormsbee', + 'Reutter', + 'Uyehara', + 'Musumeci', + 'Antonini', + 'Thistle', + 'Marcia', + 'Renne', + 'Jines', + 'Dorothy', + 'Menter', + 'Crosser', + 'Ditommaso', + 'Glueck', + 'Malta', + 'Mcgranahan', + 'Mensing', + 'Ostroff', + 'Rota', + 'Rothfuss', + 'Borcherding', + 'Haveman', + 'Swallows', + 'Heltzel', + 'Aloi', + 'Stipp', + 'Broda', + 'Darter', + 'Gressett', + 'Brasier', + 'Lana', + 'Crooke', + 'Seegers', + 'Sirmons', + 'Berberian', + 'Goers', + 'Losch', + 'Memon', + 'Paternoster', + 'Rierson', + 'Miyake', + 'Barndt', + 'Kirstein', + 'Azua', + 'Zeck', + 'Britain', + 'Lanman', + 'Gorges', + 'Clock', + 'Alman', + 'Callicutt', + 'Walford', + 'Searight', + 'Eakle', + 'Federici', + 'Hosack', + 'Jarecki', + 'Kauffmann', + 'Maras', + 'Nisley', + 'Sandahl', + 'Shidler', + 'Wnek', + 'Moneymaker', + 'Santander', + 'Schneeberger', + 'Luviano', + 'Gorin', + 'Negus', + 'Coulston', + 'Polin', + 'Winslett', + 'Anstett', + 'Cowsert', + 'Dipiazza', + 'Fitting', + 'Forslund', + 'Poquette', + 'Tibbets', + 'Tomasini', + 'Toor', + 'Starry', + 'Venema', + 'Cedano', + 'Carro', + 'Samons', + 'Matty', + 'Ellenwood', + 'Kilcrease', + 'Noblin', + 'Decatur', + 'Heckard', + 'Nard', + 'Beighley', + 'Delamater', + 'Eblen', + 'Heninger', + 'Kehn', + 'Rotunno', + 'Uppal', + 'Hynek', + 'Zenk', + 'Brasil', + 'Mu', + 'Julio', + 'Cassar', + 'Crisco', + 'Oriley', + 'Turton', + 'Goens', + 'Cargo', + 'Toure', + 'Breitbach', + 'Cahalan', + 'Chadha', + 'Kittinger', + 'Marnell', + 'Masias', + 'Matousek', + 'Mittal', + 'Nieblas', + 'Onan', + 'Purdum', + 'Tursi', + 'Esplin', + 'Etsitty', + 'Fratto', + 'Przybyla', + 'Cassin', + 'Nitti', + 'Arshad', + 'Sandoz', + 'Walzer', + 'Everton', + 'Russum', + 'Morland', + 'Fennel', + 'Viel', + 'Jarrells', + 'Vassell', + 'Frigo', + 'Kodama', + 'Naron', + 'Oelke', + 'Remaley', + 'Shean', + 'Cloonan', + 'Clayman', + 'Lasch', + 'Lepard', + 'Rewis', + 'Vankeuren', + 'Lightbody', + 'Houseworth', + 'Caison', + 'Denmon', + 'Rauls', + 'Sallie', + 'Humphery', + 'Showell', + 'Raysor', + 'Angotti', + 'Barbero', + 'Buxbaum', + 'Capella', + 'Horsch', + 'Kunselman', + 'Nishikawa', + 'Perotti', + 'Sprung', + 'Szucs', + 'Emch', + 'Kotula', + 'Mendizabal', + 'Yeaman', + 'Beste', + 'Kader', + 'Forker', + 'Wiggers', + 'Cotham', + 'Primo', + 'Fetterhoff', + 'Giarrusso', + 'Glosser', + 'Lumbreras', + 'Rosano', + 'Strohecker', + 'Wanek', + 'Waycaster', + 'Worthley', + 'Salasar', + 'Boulos', + 'Pulsipher', + 'Scheider', + 'Lorimer', + 'Alamilla', + 'Zapp', + 'Deis', + 'Tariq', + 'Kasey', + 'Famiglietti', + 'Flansburg', + 'Georgiou', + 'Groft', + 'Heistand', + 'Merker', + 'Stoeckel', + 'Tackitt', + 'Verbeck', + 'Weyers', + 'Wiltrout', + 'Brabec', + 'Caligiuri', + 'Dudzinski', + 'Grieger', + 'Benfer', + 'Pesta', + 'Wool', + 'Sunshine', + 'Oka', + 'Stamour', + 'Barrio', + 'Mathe', + 'Vanduyne', + 'Brager', + 'Mcphatter', + 'Ahluwalia', + 'Borys', + 'Dreibelbis', + 'Kalmbach', + 'Karwoski', + 'Moomaw', + 'Youngren', + 'Offerman', + 'Nine', + 'Symington', + 'Branan', + 'Turberville', + 'Heber', + 'Loughridge', + 'Vanderberg', + 'Mccannon', + 'Linda', + 'Dupee', + 'Cottom', + 'Mcphearson', + 'Razor', + 'Buchwald', + 'Fraze', + 'Grannis', + 'Krolikowski', + 'Lapidus', + 'Madruga', + 'Mcmartin', + 'Quinlivan', + 'Riaz', + 'Spittler', + 'Zahm', + 'Zender', + 'Eisman', + 'Hourihan', + 'Shirazi', + 'Herendeen', + 'Perdew', + 'Pendell', + 'Chernoff', + 'Lyell', + 'Clarey', + 'Macken', + 'Guthridge', + 'Redditt', + 'Bedi', + 'Debenedictis', + 'Distel', + 'Gapinski', + 'Iwanski', + 'Medici', + 'Schmutz', + 'Tuel', + 'Verburg', + 'Galgano', + 'Skogen', + 'Aymond', + 'Raymo', + 'Croney', + 'Carry', + 'Rhynes', + 'Lamour', + 'Shedrick', + 'Tookes', + 'Baltierra', + 'Leitzel', + 'Letchworth', + 'Montesino', + 'Preis', + 'Sanzone', + 'Shantz', + 'Teo', + 'Twohig', + 'Wajda', + 'Windisch', + 'Zinck', + 'Fiero', + 'Hornby', + 'Paget', + 'Serano', + 'Rodrick', + 'Lewison', + 'Dyas', + 'Delcarmen', + 'Garske', + 'Hontz', + 'Mcquown', + 'Melling', + 'Rolando', + 'Rosencrans', + 'Steichen', + 'Teeples', + 'Forseth', + 'Quijas', + 'Schraeder', + 'Vaidya', + 'Ventre', + 'Mountjoy', + 'Morr', + 'Leviner', + 'Paulette', + 'Dobie', + 'Brue', + 'Prier', + 'Biffle', + 'Neyland', + 'Valcourt', + 'Mckeithen', + 'Lemelle', + 'Alviar', + 'Auth', + 'Bahm', + 'Bierbaum', + 'Cazier', + 'Eschbach', + 'Etzler', + 'Nowlan', + 'Sahota', + 'Vanaman', + 'Zaugg', + 'Hogeland', + 'Choat', + 'Walmer', + 'Cepero', + 'Michal', + 'Foxwell', + 'Decoursey', + 'Molyneaux', + 'Peat', + 'Jeanfrancois', + 'Arevalos', + 'Bachert', + 'Beachler', + 'Berrones', + 'Clavijo', + 'Elsen', + 'Fuhs', + 'Hooven', + 'Johannessen', + 'Klausner', + 'Masso', + 'Puzio', + 'Sekula', + 'Smyser', + 'Stepanian', + 'Barg', + 'Trueman', + 'Constante', + 'Cubas', + 'Dowers', + 'Pratts', + 'Cockburn', + 'Counce', + 'Nappier', + 'Lindon', + 'Burrowes', + 'Cokley', + 'Tillmon', + 'Bao', + 'Inks', + 'Liberato', + 'Moehring', + 'Ryker', + 'Sar', + 'Swartzendruber', + 'Torgersen', + 'Treto', + 'Tungate', + 'Ricotta', + 'Weesner', + 'Willyard', + 'Callicoat', + 'Hoque', + 'Atkison', + 'Mcwherter', + 'Dubuisson', + 'Wanzer', + 'Stradford', + 'Abruzzo', + 'Amerman', + 'Bame', + 'Bantz', + 'Bleakley', + 'Galt', + 'Hoobler', + 'Jaquith', + 'Lessman', + 'Polinski', + 'Rasche', + 'Roeber', + 'Rubright', + 'Sarnowski', + 'Signore', + 'Solum', + 'Vankampen', + 'Vath', + 'Malmquist', + 'Mittelstadt', + 'Belyea', + 'Haverty', + 'Wickett', + 'Sansing', + 'Yeatman', + 'Brocker', + 'Wonders', + 'Both', + 'Rabun', + 'Rocke', + 'Meachum', + 'Blane', + 'Lapsley', + 'Biswas', + 'Derocher', + 'Haran', + 'Hehn', + 'Keshishian', + 'Kniffin', + 'Lacina', + 'Skolnik', + 'Spiewak', + 'Wileman', + 'Eble', + 'Kraynak', + 'Wiesen', + 'Micheli', + 'Scroggin', + 'Roch', + 'Denise', + 'Altenburg', + 'Hornstein', + 'Netto', + 'Opel', + 'Passey', + 'Roeske', + 'Schrantz', + 'Abrahamsen', + 'Powless', + 'Callais', + 'Desjardin', + 'Pirro', + 'Yonkers', + 'Macallister', + 'Dady', + 'Ruskin', + 'Escott', + 'Abbot', + 'Sankar', + 'Bolar', + 'Angelucci', + 'Biegel', + 'Cirone', + 'Damewood', + 'Flett', + 'Kronenberg', + 'Ky', + 'Nagler', + 'Perlstein', + 'Saperstein', + 'Tenbrink', + 'Vana', + 'Wnuk', + 'Bonnema', + 'Schoenecker', + 'Pichler', + 'Armendarez', + 'Oiler', + 'Rouch', + 'Boas', + 'Laracuente', + 'Milbourn', + 'Summy', + 'Counter', + 'Gracie', + 'Belfield', + 'Bynoe', + 'Jalloh', + 'Blazier', + 'Bochenek', + 'Broughman', + 'Chuong', + 'Cregger', + 'Estacio', + 'Kaleta', + 'Lanctot', + 'Mish', + 'Novosel', + 'Passero', + 'Ripplinger', + 'Vitt', + 'Walborn', + 'Friscia', + 'Memmott', + 'Tripi', + 'Weinhold', + 'Honn', + 'Gianni', + 'Poch', + 'Sagar', + 'Markum', + 'Primmer', + 'Belmore', + 'Rain', + 'Bevard', + 'Skyles', + 'Farland', + 'Mccleese', + 'Teachey', + 'Moulden', + 'Antolin', + 'Augello', + 'Borrayo', + 'Effler', + 'Hornak', + 'Hosman', + 'Leingang', + 'Limbach', + 'Oregel', + 'Ritzman', + 'Rochefort', + 'Schimke', + 'Stefanelli', + 'Vien', + 'Zurn', + 'Badolato', + 'Bieri', + 'Clarkin', + 'Folino', + 'Kelchner', + 'Pote', + 'Brahm', + 'Hoop', + 'Macbride', + 'Hunting', + 'Brule', + 'Wainright', + 'Rolison', + 'Bennie', + 'Banghart', + 'Bertke', + 'Bozzo', + 'Gadomski', + 'Granberg', + 'Kostecki', + 'Lemelin', + 'Levengood', + 'Puskas', + 'Swanstrom', + 'Willcutt', + 'Deitrich', + 'Grieves', + 'Ferran', + 'Boileau', + 'Kendra', + 'Trippe', + 'Mcconnel', + 'Cara', + 'Stephans', + 'Bachus', + 'Applin', + 'Utsey', + 'Auston', + 'Arras', + 'Bencosme', + 'Berntsen', + 'Decarolis', + 'Dettloff', + 'Duerksen', + 'Pavlovic', + 'Schwantes', + 'Sjostrom', + 'Sugiyama', + 'Sulak', + 'Virani', + 'Winberg', + 'Yoshimoto', + 'Comito', + 'Pandolfo', + 'Cathers', + 'Hardisty', + 'Collom', + 'Wain', + 'Worthing', + 'Leep', + 'Simo', + 'Boom', + 'Bald', + 'Applegarth', + 'Gilbreth', + 'Griest', + 'Jobin', + 'Matsuura', + 'Misko', + 'Scerbo', + 'Scheidler', + 'Sterba', + 'Tomaino', + 'Wixson', + 'Yadao', + 'Hietpas', + 'Gruss', + 'Fors', + 'Gosse', + 'Katt', + 'Virk', + 'Quebedeaux', + 'Barkey', + 'Salam', + 'Willford', + 'Tarry', + 'Chancy', + 'Beynon', + 'Eckes', + 'Eischen', + 'Felger', + 'Kimm', + 'Labate', + 'Mehan', + 'Netzer', + 'Strosnider', + 'Trezza', + 'Vial', + 'Waugaman', + 'Zieman', + 'Ankeny', + 'Digman', + 'Farino', + 'Faro', + 'Vasconcelos', + 'Nevill', + 'Rave', + 'Sabine', + 'Hagg', + 'Weightman', + 'Berton', + 'Fipps', + 'Knapper', + 'Camel', + 'Gilkes', + 'Aldous', + 'Delucca', + 'Dicke', + 'Evitts', + 'Hachey', + 'Rinck', + 'Treese', + 'Uher', + 'Victorio', + 'Vignola', + 'Willert', + 'Baun', + 'Wever', + 'Varn', + 'Yokum', + 'Dunk', + 'Maben', + 'Arzu', + 'Guider', + 'Bonhomme', + 'Majette', + 'Crislip', + 'Gresko', + 'Luppino', + 'Posch', + 'Potenza', + 'Rial', + 'Ruderman', + 'Shaff', + 'Balboni', + 'Solheim', + 'Mey', + 'Sittig', + 'Perman', + 'Sumners', + 'Deaner', + 'Keizer', + 'Reves', + 'Glanville', + 'Menzie', + 'Mccowen', + 'Steib', + 'Portee', + 'Azad', + 'Dallaire', + 'Denno', + 'Deptula', + 'Fischman', + 'Guilbault', + 'Imperato', + 'Koehne', + 'Menning', + 'Mirelez', + 'Stanislawski', + 'Streb', + 'Sumida', + 'Wolke', + 'Kerfoot', + 'Pirie', + 'Saracino', + 'Maslanka', + 'Slominski', + 'Nienaber', + 'Serena', + 'Kamper', + 'Matheis', + 'Westin', + 'Ishman', + 'Biagi', + 'Chiou', + 'Dieckmann', + 'Frieden', + 'Huestis', + 'Presutti', + 'Ribas', + 'Siedlecki', + 'Steege', + 'Uehara', + 'Petrosyan', + 'Siebold', + 'Turi', + 'Rady', + 'Vanorman', + 'Arif', + 'Hiland', + 'Naidu', + 'Clagett', + 'Ludy', + 'Bodley', + 'Avelino', + 'Citro', + 'Cuda', + 'Derbyshire', + 'Kruszewski', + 'Kupper', + 'Mahl', + 'Muratore', + 'Noecker', + 'Osmer', + 'Pasquariello', + 'Schlick', + 'Snover', + 'Strzelecki', + 'Studt', + 'Sunga', + 'Belmares', + 'Seifried', + 'Urioste', + 'Housh', + 'Babu', + 'Bures', + 'Augusto', + 'Faddis', + 'Pun', + 'Chopp', + 'Tullock', + 'Sea', + 'Boisseau', + 'Herbin', + 'Balcer', + 'Copus', + 'Eichenberger', + 'Enterline', + 'Gamarra', + 'Gursky', + 'Hovsepian', + 'Laffin', + 'Melena', + 'Rappe', + 'Soma', + 'Spira', + 'Spraker', + 'Teuscher', + 'Hochhalter', + 'Brenden', + 'Snee', + 'Polan', + 'Hataway', + 'Tirey', + 'Cobler', + 'Marren', + 'Ress', + 'Bennis', + 'Busha', + 'Galler', + 'Orea', + 'Nailor', + 'Magby', + 'Bridgett', + 'Island', + 'Camino', + 'Coderre', + 'Gangloff', + 'Gillilan', + 'Goergen', + 'Henthorne', + 'Heverly', + 'Loughry', + 'Records', + 'Schweikert', + 'Seeds', + 'Vanderwerf', + 'Westall', + 'Cristiano', + 'Biser', + 'Cartmill', + 'Greenly', + 'Kountz', + 'Craney', + 'Sheffey', + 'Gelin', + 'Gourdine', + 'Canham', + 'Edgmon', + 'Enz', + 'Feldpausch', + 'Hestand', + 'Kaus', + 'Kostelnik', + 'Ocanas', + 'Riggi', + 'Rohl', + 'Scheurer', + 'Sleeman', + 'Tosi', + 'Phegley', + 'Abelson', + 'Mclees', + 'Sinor', + 'Babson', + 'Whalley', + 'Manton', + 'Patteson', + 'Doyen', + 'Asad', + 'Thurmon', + 'Cassese', + 'Ditmore', + 'Duva', + 'Pilato', + 'Polaski', + 'Rzepka', + 'Sevin', + 'Sivak', + 'Speckman', + 'Stepien', + 'Switalski', + 'Valletta', + 'Knoth', + 'Niver', + 'Ciancio', + 'Giza', + 'Liebowitz', + 'Orengo', + 'Rothgeb', + 'Witz', + 'Airhart', + 'Gayman', + 'Belland', + 'Eury', + 'Randal', + 'Mcghie', + 'Briganti', + 'Hoopingarner', + 'Lugar', + 'Manfre', + 'Mongelli', + 'Squibb', + 'Vasil', + 'Cap', + 'Veillon', + 'Ege', + 'Spice', + 'Nevel', + 'Vanleer', + 'Petway', + 'Petitfrere', + 'Barcena', + 'Belville', + 'Brezina', + 'Ketcherside', + 'Knodel', + 'Krinsky', + 'Lundahl', + 'Mescher', + 'Pilat', + 'Sneller', + 'Staller', + 'Steinhaus', + 'Stensrud', + 'Szalay', + 'Tani', + 'Saviano', + 'Genna', + 'Emry', + 'Allin', + 'Harvel', + 'Harth', + 'Pay', + 'Harries', + 'Brannum', + 'Elijah', + 'Hoyte', + 'Bazinet', + 'Bhandari', + 'Brozek', + 'Cava', + 'Dalbey', + 'Delgiudice', + 'Klages', + 'Riffey', + 'Straube', + 'Zagar', + 'Zientek', + 'Dilger', + 'Hof', + 'Karwowski', + 'Rybarczyk', + 'Spiering', + 'Stamos', + 'Gangemi', + 'Olavarria', + 'Sardinas', + 'Magin', + 'Payano', + 'Deady', + 'Henricksen', + 'Kary', + 'Garnier', + 'Babic', + 'Behymer', + 'Billig', + 'Huegel', + 'Ishihara', + 'Mcglinchey', + 'Misuraca', + 'Petrosino', + 'Zizzo', + 'Reierson', + 'Wadman', + 'Brander', + 'Risko', + 'Basye', + 'Mcmakin', + 'Straughan', + 'Chesnutt', + 'Sima', + 'Ree', + 'Mankins', + 'Soberanis', + 'Greenup', + 'Commodore', + 'Carucci', + 'Defibaugh', + 'Finfrock', + 'Funston', + 'Grantz', + 'Guiney', + 'Ohrt', + 'Tinsman', + 'Godek', + 'Mcgrory', + 'Mikeska', + 'Kamer', + 'Lovas', + 'Kirshner', + 'Bevacqua', + 'Franqui', + 'Walts', + 'Doke', + 'Orsborn', + 'Tavernier', + 'Kibble', + 'Scipio', + 'Diop', + 'Antczak', + 'Bastida', + 'Callister', + 'Dusseau', + 'Ficarra', + 'Garcilazo', + 'Hughett', + 'Liebel', + 'Rodenbaugh', + 'Rosselli', + 'Teresi', + 'Bohnsack', + 'Steidl', + 'Vanderheiden', + 'Demma', + 'Dutson', + 'Mcmeekin', + 'Glassford', + 'Serrao', + 'Marriner', + 'Mcchristian', + 'Lias', + 'Blahnik', + 'Brunke', + 'Daleo', + 'Fullam', + 'Goetzinger', + 'Leva', + 'Rehder', + 'Ripperger', + 'Shindler', + 'Tussing', + 'Mayr', + 'Rozzi', + 'Bonsignore', + 'Te', + 'Graft', + 'Ok', + 'Clink', + 'Mccamey', + 'Goldring', + 'Tartt', + 'Fullilove', + 'Amodio', + 'Arkin', + 'Dettmann', + 'Ellingwood', + 'Figura', + 'Fritzinger', + 'Heilmann', + 'Hillstrom', + 'Marasigan', + 'Pavlov', + 'Totman', + 'Dokken', + 'Serpico', + 'Shumard', + 'Rathman', + 'Siegmund', + 'Woodhull', + 'Oregon', + 'Roselle', + 'Taul', + 'Maddix', + 'Nwosu', + 'Bavaro', + 'Carella', + 'Cowdrey', + 'Goodnough', + 'Koffler', + 'Mahajan', + 'Montalvan', + 'Morga', + 'Parrella', + 'Quiggle', + 'Rehrig', + 'Rotondi', + 'Tavenner', + 'Wigger', + 'Yax', + 'Bartko', + 'Netzel', + 'Zechman', + 'Socia', + 'Vea', + 'Wemple', + 'Matti', + 'Striplin', + 'Hollin', + 'Geddie', + 'Nolden', + 'Freeney', + 'Jeanjacques', + 'Bermudes', + 'Castrellon', + 'Catino', + 'Feeser', + 'Kreitz', + 'Maisano', + 'Melkonian', + 'Toste', + 'Vancura', + 'Bylsma', + 'Wiant', + 'Mcpheron', + 'Gere', + 'Geoffroy', + 'Fuston', + 'Petteway', + 'Barsky', + 'Bovard', + 'Buttars', + 'Christophersen', + 'Dudzik', + 'Ganger', + 'Hilgers', + 'Holzhauer', + 'Minervini', + 'Pong', + 'Rozycki', + 'Sulzer', + 'Tauscher', + 'Upright', + 'Verastegui', + 'Lobello', + 'Sandt', + 'Timbrook', + 'Yniguez', + 'Nuzzi', + 'Sakata', + 'Koran', + 'Veloso', + 'Cullers', + 'Culton', + 'Reynold', + 'Feagins', + 'Amaker', + 'Cafferty', + 'Coontz', + 'Iden', + 'Mazzotta', + 'Montanye', + 'Wandell', + 'Weiman', + 'Vik', + 'Staib', + 'Lasso', + 'Waynick', + 'Boniface', + 'Massingale', + 'Gainous', + 'Sharper', + 'Columbia', + 'Felkins', + 'Gatzke', + 'Heindel', + 'Ludeman', + 'Mcmunn', + 'Mogavero', + 'Ratti', + 'Rickabaugh', + 'Ripper', + 'Tessman', + 'Triano', + 'Vanderpol', + 'Langille', + 'Holten', + 'Steeley', + 'Solan', + 'Devaul', + 'Lindler', + 'Armor', + 'Fambrough', + 'Golliday', + 'Bognar', + 'Gamba', + 'Gettinger', + 'Hanzel', + 'Krumwiede', + 'Marcinkowski', + 'Nicolay', + 'Peppard', + 'Sisti', + 'Sundeen', + 'Senatore', + 'Diebel', + 'Demarais', + 'Letellier', + 'Goon', + 'Texidor', + 'Baughan', + 'Gunder', + 'Lalor', + 'Wigglesworth', + 'Aird', + 'Basey', + 'Afshar', + 'Anhalt', + 'Bondoc', + 'Bunten', + 'Daniello', + 'Kazmierski', + 'Marcott', + 'Petruska', + 'Trejos', + 'Droege', + 'Fukumoto', + 'Harju', + 'Hauf', + 'Yagi', + 'Mccallie', + 'Moulds', + 'Singleterry', + 'Ramkissoon', + 'Sanks', + 'Siggers', + 'Myrie', + 'Conteh', + 'Biss', + 'Brees', + 'Collopy', + 'Dashner', + 'Dehaas', + 'Delzer', + 'Fees', + 'Finocchiaro', + 'Forsgren', + 'Giampietro', + 'Levandowski', + 'Mallick', + 'Maudlin', + 'Micheletti', + 'Newhard', + 'Parmentier', + 'Pintado', + 'Pliego', + 'Radigan', + 'Selke', + 'Uptain', + 'Wigton', + 'Zabinski', + 'Becenti', + 'Guthmiller', + 'Malecha', + 'Eardley', + 'Muscat', + 'Ruhe', + 'Battersby', + 'Lamie', + 'Stan', + 'Dutch', + 'Duplechain', + 'Dildy', + 'Auch', + 'Baltzer', + 'Degaetano', + 'Mileski', + 'Parrillo', + 'Schoof', + 'Stires', + 'Villescas', + 'Knittle', + 'Degrave', + 'Deihl', + 'Moseman', + 'Prillaman', + 'Wakeley', + 'Jake', + 'Murden', + 'Shareef', + 'Yarbough', + 'Bothe', + 'Boutilier', + 'Breck', + 'Buschman', + 'Coccia', + 'Eberlein', + 'Harriger', + 'Neas', + 'Sullenger', + 'Walp', + 'Yaple', + 'Zinger', + 'Zufelt', + 'Marinaccio', + 'Viele', + 'Markee', + 'Melody', + 'Rooke', + 'Ales', + 'Mumphrey', + 'Bessinger', + 'Bialas', + 'Brugh', + 'Chum', + 'Diehm', + 'Frieze', + 'Hieber', + 'Malouf', + 'Maltz', + 'Mcmanaway', + 'Musante', + 'Pester', + 'Roda', + 'Snarr', + 'Tovey', + 'Buchmann', + 'Fluck', + 'Sadowsky', + 'Viteri', + 'Loewe', + 'Mullaly', + 'Lamboy', + 'Bouman', + 'Provencal', + 'Siddons', + 'Chelette', + 'Rachels', + 'Dynes', + 'Nobel', + 'Desselle', + 'Tillison', + 'Bajaj', + 'Bresee', + 'Hisel', + 'Mallo', + 'Meints', + 'Potocki', + 'Spore', + 'Steier', + 'Toothaker', + 'Wildt', + 'Darcangelo', + 'Karbowski', + 'Scaccia', + 'Lascola', + 'Duman', + 'Mccaul', + 'Rowton', + 'Setters', + 'Hendryx', + 'Belson', + 'Manny', + 'Winckler', + 'Longe', + 'Mclucas', + 'Lenon', + 'Linen', + 'Anstine', + 'Belkin', + 'Drozdowski', + 'Ender', + 'Ferra', + 'Lessig', + 'Marucci', + 'Nardo', + 'Nipp', + 'Passarella', + 'Roecker', + 'Siddique', + 'Stanczak', + 'Stavros', + 'Tomasetti', + 'Lagreca', + 'Seegmiller', + 'Keena', + 'Suddarth', + 'Wayt', + 'Matas', + 'Ryer', + 'Mortimore', + 'Durnell', + 'Pieters', + 'Slocumb', + 'Andaya', + 'Brymer', + 'Dufek', + 'Ekman', + 'Espericueta', + 'Feltes', + 'Hammann', + 'Heydt', + 'Inthavong', + 'Jagielski', + 'Nast', + 'Petrucelli', + 'Phippen', + 'Vanderzanden', + 'Whinery', + 'Zatarain', + 'Zelenak', + 'Aquilina', + 'Hougland', + 'Isais', + 'Canney', + 'Flath', + 'Ragon', + 'Len', + 'Violet', + 'Carra', + 'Everetts', + 'Lockey', + 'Dahmer', + 'Fuquay', + 'Alpers', + 'Borromeo', + 'Bringas', + 'Brumit', + 'Campanile', + 'Folts', + 'Hirai', + 'Kiessling', + 'Krogstad', + 'Ovitt', + 'Bhardwaj', + 'Hlavaty', + 'Monceaux', + 'Spatola', + 'Trunzo', + 'Girvin', + 'Shady', + 'Grimley', + 'Tagg', + 'Weddell', + 'Mcfadyen', + 'Reagin', + 'Philo', + 'Emily', + 'Codd', + 'Cherrington', + 'Skates', + 'Deary', + 'Ballester', + 'Barilla', + 'Cicchetti', + 'Dyche', + 'Goossen', + 'Graveline', + 'Hajduk', + 'Halliwell', + 'Kohnen', + 'Kupiec', + 'Machacek', + 'Manship', + 'Slinker', + 'Mallozzi', + 'Dotter', + 'Brazeau', + 'Manon', + 'Crofford', + 'Gauthreaux', + 'Petillo', + 'Bailor', + 'Ganesh', + 'Reaser', + 'Barren', + 'Adachi', + 'Aguiniga', + 'Cartrette', + 'Crady', + 'Hegland', + 'Isner', + 'Karasek', + 'Labrum', + 'Maroon', + 'Rullo', + 'Schull', + 'Stawicki', + 'Withee', + 'Penfold', + 'Foronda', + 'Claridge', + 'Coiner', + 'Guimaraes', + 'Mawyer', + 'Rivkin', + 'Kiggins', + 'Hackel', + 'Wey', + 'Fairhurst', + 'Albertini', + 'Gaal', + 'Flurry', + 'Patricia', + 'Savery', + 'Colen', + 'Cuthrell', + 'Maffett', + 'Dungey', + 'Luter', + 'Hurston', + 'Ahles', + 'Czapla', + 'Gallas', + 'Kotecki', + 'Lazzari', + 'Marcellino', + 'Valvo', + 'Vukovich', + 'Wisor', + 'Agler', + 'Wease', + 'Gallentine', + 'Christoph', + 'Poyer', + 'Norment', + 'Rhett', + 'Amabile', + 'Barish', + 'Heifner', + 'Kolarik', + 'Mcquarrie', + 'Morua', + 'Nahas', + 'Razzano', + 'Riegle', + 'Torralba', + 'Perfetti', + 'Stalzer', + 'Killman', + 'Lenning', + 'Wyler', + 'Soward', + 'Releford', + 'Battisti', + 'Bergum', + 'Catapano', + 'Doerner', + 'Ehlen', + 'Finken', + 'Genereux', + 'Hillegas', + 'Hopple', + 'Kaatz', + 'Lacson', + 'Macario', + 'Marzolf', + 'Muha', + 'Picha', + 'Springston', + 'Stooksbury', + 'Weide', + 'Glodowski', + 'Lueth', + 'Assaf', + 'Robuck', + 'Lamaster', + 'Foulkes', + 'Swopes', + 'Winkfield', + 'Aristizabal', + 'Aylesworth', + 'Bellotti', + 'Bittick', + 'Capistran', + 'Cizek', + 'Dinneen', + 'Ellender', + 'Friske', + 'Hoffa', + 'Klinge', + 'Kuklinski', + 'Luzier', + 'Martensen', + 'Rolin', + 'Shankles', + 'Siska', + 'Wiegman', + 'Winterbottom', + 'Crookston', + 'Gorospe', + 'Curci', + 'Lamberty', + 'Antonetti', + 'Sheer', + 'Durning', + 'Hootman', + 'Doub', + 'Klaiber', + 'Mayeaux', + 'Domingos', + 'Wheeless', + 'Vantrease', + 'Summerhill', + 'Agresta', + 'Annas', + 'Aquilar', + 'Crea', + 'Froese', + 'Medlen', + 'Peeters', + 'Rhudy', + 'Risse', + 'Schor', + 'Zimmerer', + 'Bombardier', + 'Halfhill', + 'Koppenhaver', + 'Kruckenberg', + 'Boccia', + 'Rella', + 'Carelli', + 'Overson', + 'Tamburro', + 'Rosamond', + 'Lie', + 'Mesquita', + 'Jennett', + 'Jewel', + 'Waye', + 'Bogucki', + 'Colpitts', + 'Galpin', + 'Hrdlicka', + 'Kading', + 'Kushnir', + 'Leano', + 'Liebig', + 'Mceuen', + 'Nestler', + 'Payer', + 'Santarelli', + 'Schrupp', + 'Schwarze', + 'Semrau', + 'Solanki', + 'Terzian', + 'Treloar', + 'Ureno', + 'Vohra', + 'Voshell', + 'Nakanishi', + 'Senese', + 'Dierker', + 'Quinley', + 'Monier', + 'Rounsaville', + 'Mcfaddin', + 'Defrance', + 'Joynes', + 'Levert', + 'Adragna', + 'Buczynski', + 'Cranor', + 'Englebert', + 'Furney', + 'Gorny', + 'Mockler', + 'Pavlicek', + 'Petrini', + 'Schadt', + 'Slagel', + 'Cumpston', + 'Priore', + 'Paonessa', + 'Carling', + 'Espaillat', + 'Hem', + 'Griffo', + 'Tomer', + 'Venn', + 'Giraud', + 'Becks', + 'Mungin', + 'Attard', + 'Brucato', + 'Dreyfus', + 'Droz', + 'Falck', + 'Firebaugh', + 'Fiser', + 'Hemmelgarn', + 'Hofacker', + 'Kreeger', + 'Rippee', + 'Ruehle', + 'Saputo', + 'Scovill', + 'Silbaugh', + 'Smolenski', + 'Spickler', + 'Swango', + 'Kaehler', + 'Mootz', + 'Noblett', + 'Zarcone', + 'Katzenberger', + 'Kita', + 'Brezinski', + 'Castles', + 'Padin', + 'Hinde', + 'Barretta', + 'Amiri', + 'Shelburne', + 'Mccoin', + 'Heaston', + 'Aldredge', + 'Milhouse', + 'Wilbon', + 'Cephus', + 'Barsness', + 'Belch', + 'Blatter', + 'Boyum', + 'Corvino', + 'Dagenais', + 'Doscher', + 'Elizarraraz', + 'Gierke', + 'Habegger', + 'Ketcher', + 'Kristiansen', + 'Oldroyd', + 'Sandage', + 'Tesoriero', + 'Unzueta', + 'Wollam', + 'Cefalu', + 'Achey', + 'Wegmann', + 'Lessner', + 'Bunk', + 'Mallin', + 'Polis', + 'Aronoff', + 'Portal', + 'Crock', + 'Escher', + 'Medler', + 'Pretty', + 'Younge', + 'Agbayani', + 'Brinkmeyer', + 'Castrillon', + 'Feick', + 'Gutmann', + 'Hagenbuch', + 'Hesseltine', + 'Houska', + 'Kimzey', + 'Kolasa', + 'Lentine', + 'Lobaugh', + 'Maimone', + 'Meshell', + 'Nardini', + 'Rosetti', + 'Siefker', + 'Sileo', + 'Silveria', + 'Argumedo', + 'Lesmeister', + 'Donnan', + 'Hermans', + 'Raggio', + 'Dupras', + 'Empson', + 'Bevier', + 'Tumey', + 'Donn', + 'Darville', + 'Douse', + 'Cheyne', + 'Dewing', + 'Jansma', + 'Mayeda', + 'Nield', + 'Obermiller', + 'Opfer', + 'Surma', + 'Tiffin', + 'Tirpak', + 'Wassel', + 'Blickenstaff', + 'Dorland', + 'Kulhanek', + 'Andras', + 'Estupinan', + 'Gonce', + 'Weast', + 'Souto', + 'Guirguis', + 'Glazebrook', + 'Dain', + 'Loyer', + 'Bensley', + 'Verge', + 'Tubman', + 'Onley', + 'Dais', + 'Barash', + 'Bullman', + 'Crispino', + 'Davino', + 'Isenhart', + 'Kneller', + 'Loschiavo', + 'Opper', + 'Pfleger', + 'Wahler', + 'Zelasko', + 'Havrilla', + 'Mintzer', + 'Devoll', + 'Giannelli', + 'Sees', + 'Barritt', + 'Mesta', + 'Sostre', + 'Rohman', + 'Padget', + 'Edds', + 'Slinger', + 'Borowicz', + 'Bregman', + 'Bubar', + 'Debartolo', + 'Desposito', + 'Grieshaber', + 'Ludtke', + 'Pagani', + 'Quiambao', + 'Schapiro', + 'Winward', + 'Bouska', + 'Olstad', + 'Rough', + 'Genz', + 'Husby', + 'Nealis', + 'Hyams', + 'Andrades', + 'Mcgibbon', + 'Edwin', + 'Buckhalter', + 'Baylon', + 'Fiene', + 'Fillingim', + 'Fiorenza', + 'Greenstreet', + 'Krager', + 'Laxson', + 'Noreen', + 'Roberds', + 'Rundquist', + 'Smelcer', + 'Tabone', + 'Train', + 'Zeoli', + 'Defries', + 'Kolp', + 'Maahs', + 'Mcnall', + 'Ehman', + 'Keeth', + 'Shackleton', + 'Hogarth', + 'Westbury', + 'Gulliver', + 'Oquin', + 'Holiman', + 'Saintlouis', + 'Vaughns', + 'Aichele', + 'Arbelaez', + 'Bathurst', + 'Bresler', + 'Cecena', + 'Drollinger', + 'Fellner', + 'Griesemer', + 'Harnois', + 'Hire', + 'Kraker', + 'Roylance', + 'Zaccaria', + 'Dinunzio', + 'Foisy', + 'Nordlund', + 'Peppler', + 'Kishbaugh', + 'Marcil', + 'Mcfarren', + 'Puello', + 'Supplee', + 'Boyea', + 'Depp', + 'Tift', + 'Wince', + 'Pam', + 'Ifill', + 'Brodt', + 'Caamano', + 'Gibler', + 'Litherland', + 'Miesner', + 'Pixler', + 'Schwimmer', + 'Suriano', + 'Abendroth', + 'Gillaspy', + 'Kumpf', + 'Schroepfer', + 'Boals', + 'Seneca', + 'Sasson', + 'Hindes', + 'Posten', + 'Lann', + 'Anctil', + 'Arebalo', + 'Beacom', + 'Boberg', + 'Coufal', + 'Didion', + 'Fromme', + 'Greenan', + 'Guerrette', + 'Hudec', + 'Kazmi', + 'Lucchese', + 'Mouw', + 'Savastano', + 'Schomer', + 'Shorb', + 'Storz', + 'Finazzo', + 'Knigge', + 'Pawlikowski', + 'Cercone', + 'Sutfin', + 'Valdespino', + 'Mccartin', + 'Yurko', + 'Treaster', + 'Peaden', + 'Russin', + 'Dibartolo', + 'Dona', + 'Skillern', + 'Brackens', + 'Amyx', + 'Bornemann', + 'Comtois', + 'Kaestner', + 'Kallenbach', + 'Krupka', + 'Lineback', + 'Lopata', + 'Mcclenahan', + 'Monteverde', + 'Otani', + 'Panchal', + 'Pawlicki', + 'Suman', + 'Vallance', + 'Zammit', + 'Liszewski', + 'Trunk', + 'Sharifi', + 'Lents', + 'Watkinson', + 'Willow', + 'Flaming', + 'Sol', + 'Dory', + 'Purchase', + 'Haris', + 'Bigsby', + 'Boonstra', + 'Emge', + 'Goodpasture', + 'Iwata', + 'Kau', + 'Syring', + 'Vlach', + 'Klaassen', + 'Vicuna', + 'Wasden', + 'Cattell', + 'Ridlon', + 'Fassler', + 'Scullion', + 'Hibbitts', + 'Mcgillis', + 'Pla', + 'Mustin', + 'Darty', + 'Minniefield', + 'Bloyd', + 'Calnan', + 'Casal', + 'Fickel', + 'Gamero', + 'Higuchi', + 'Huante', + 'Knies', + 'Letner', + 'Quang', + 'Teufel', + 'Topolski', + 'Tumminello', + 'Vanorder', + 'Slawinski', + 'Nyce', + 'Asmar', + 'Loudin', + 'Karen', + 'Budden', + 'Mothershed', + 'Fenelon', + 'Mccrorey', + 'Ashenfelter', + 'Auge', + 'Christison', + 'Cilley', + 'Corsetti', + 'Coxwell', + 'Critchley', + 'Griep', + 'Hausner', + 'Hiemstra', + 'Koprowski', + 'Kozicki', + 'Marling', + 'Marmo', + 'Noller', + 'Pich', + 'Recendez', + 'Renegar', + 'Rinne', + 'Zeis', + 'Buzzelli', + 'Lipham', + 'Schaner', + 'Kartchner', + 'Kealy', + 'Sinopoli', + 'Krishna', + 'Brinn', + 'Zachry', + 'Barbre', + 'Sharber', + 'Fritze', + 'Hanshew', + 'Lemere', + 'Maruyama', + 'Masker', + 'Melendy', + 'Pelto', + 'Rigo', + 'Rohling', + 'Scobee', + 'Sundell', + 'Tranter', + 'Vancuren', + 'Augustyniak', + 'Mehringer', + 'Sulkowski', + 'Gittins', + 'Twiford', + 'Dumm', + 'Jacklin', + 'Mcquaig', + 'Richison', + 'Jex', + 'Meritt', + 'Hegler', + 'Duboise', + 'Houze', + 'Akana', + 'Corsaro', + 'Delosangeles', + 'Guidice', + 'Maccallum', + 'Moes', + 'Steinhardt', + 'Stirewalt', + 'Wooters', + 'Schissler', + 'Sobeck', + 'Boyte', + 'Jilek', + 'Suder', + 'Kellis', + 'Blankenbaker', + 'Lank', + 'Mandigo', + 'Fremont', + 'Rideau', + 'Beidler', + 'Boda', + 'Gulotta', + 'Havelka', + 'Herberger', + 'Isenhower', + 'Lattanzi', + 'Pandolfi', + 'Shearman', + 'Wilmarth', + 'Dutkiewicz', + 'Mazzuca', + 'Tabarez', + 'Vermilyea', + 'Kray', + 'Vitti', + 'Packwood', + 'Paulos', + 'Howson', + 'Collman', + 'Ameen', + 'Berisha', + 'Capece', + 'Fantasia', + 'Galas', + 'Laszlo', + 'Luthi', + 'Maietta', + 'Mcconaghy', + 'Naab', + 'Nerio', + 'Pineau', + 'Rossbach', + 'Senne', + 'Unangst', + 'Kautzman', + 'Muhs', + 'Ripka', + 'Wehling', + 'Hoot', + 'Jee', + 'Megna', + 'Tirone', + 'Walle', + 'Brandi', + 'Lutter', + 'Mona', + 'Roley', + 'Mcfann', + 'Swader', + 'Cavett', + 'Delmore', + 'Walthour', + 'Goldson', + 'Biddinger', + 'Bjornstad', + 'Buesing', + 'Cerino', + 'Diede', + 'Hagle', + 'Hodgman', + 'Killmer', + 'Loa', + 'Matsunaga', + 'Micciche', + 'Newquist', + 'Poppen', + 'Shellhammer', + 'Tienda', + 'Tino', + 'Mihelich', + 'Garsia', + 'Orzel', + 'Ericsson', + 'Dose', + 'Kotter', + 'Amante', + 'Hanif', + 'Huckleberry', + 'Blandin', + 'Carvin', + 'Axton', + 'Delosrios', + 'Diekmann', + 'Failing', + 'Filipek', + 'Otting', + 'Rozman', + 'Sadeghi', + 'Slutsky', + 'Speake', + 'Szostak', + 'Tacy', + 'Kmiecik', + 'Macgillivray', + 'Yeakel', + 'Dykman', + 'Gorey', + 'Dowding', + 'Revel', + 'Geathers', + 'Cappa', + 'Davidoff', + 'Lukehart', + 'Mccutchan', + 'Neeb', + 'Nikolic', + 'Piorkowski', + 'Sandvig', + 'Schmidgall', + 'Stockbridge', + 'Thornock', + 'Valk', + 'Wiechmann', + 'Chait', + 'Gacek', + 'Schupbach', + 'Gemma', + 'Rus', + 'Barch', + 'Wyles', + 'Scrivener', + 'Salls', + 'Akram', + 'Mcclatchey', + 'Bromfield', + 'Burl', + 'Redwood', + 'Starkes', + 'Beaston', + 'Boggio', + 'Cantillo', + 'Cina', + 'Cryan', + 'Dubs', + 'Edmisten', + 'Fitzer', + 'Fugere', + 'Fundora', + 'Galvis', + 'Jafri', + 'Nalepa', + 'Peri', + 'Pippenger', + 'Rheault', + 'Rohrbacher', + 'Romberg', + 'Samek', + 'Stehlik', + 'Stepan', + 'Torrisi', + 'Wessner', + 'Zappala', + 'Bangerter', + 'Czerniak', + 'Mcshea', + 'Raczkowski', + 'Rohwer', + 'Spehar', + 'Lague', + 'Messman', + 'Angst', + 'Temme', + 'Tolles', + 'Lawn', + 'Ayars', + 'Austen', + 'Stansel', + 'Fairclough', + 'Tribbett', + 'Peevy', + 'Fraiser', + 'Caradine', + 'Fiegel', + 'Gignac', + 'Halpert', + 'Karels', + 'Knappenberger', + 'Prezioso', + 'Rohlfs', + 'Szot', + 'Varano', + 'Weinreich', + 'Butterbaugh', + 'Heying', + 'Vandewalle', + 'Yandle', + 'Thede', + 'Astor', + 'Blanchfield', + 'Hegeman', + 'Fels', + 'Miniard', + 'Lorio', + 'Muhammed', + 'Lazard', + 'Ehmke', + 'Hulst', + 'Imlay', + 'Kinzler', + 'Knaak', + 'Poehler', + 'Prusak', + 'Rakow', + 'Raupp', + 'Sucher', + 'Tanenbaum', + 'Burich', + 'Macmaster', + 'Shapley', + 'Thurgood', + 'Mires', + 'Gotay', + 'Attia', + 'Martis', + 'Greenley', + 'Fothergill', + 'Bonvillain', + 'Buffalo', + 'Dues', + 'Crute', + 'Cantone', + 'Dewit', + 'Dovel', + 'Klopfer', + 'Philhower', + 'Piatek', + 'Pion', + 'Rapaport', + 'Vanwert', + 'Wikstrom', + 'Graffeo', + 'Kissling', + 'Niday', + 'Soong', + 'Adami', + 'Hammersmith', + 'Keir', + 'Yo', + 'Grizzell', + 'Stclaire', + 'Swales', + 'Nole', + 'Pole', + 'Hartgrove', + 'Carrothers', + 'Carlone', + 'Ciano', + 'Finucane', + 'Fitterer', + 'Gellman', + 'Hakimi', + 'Janos', + 'Krings', + 'Malmstrom', + 'Markwardt', + 'Rodin', + 'Schau', + 'Scheible', + 'Orick', + 'Dine', + 'Tremmel', + 'Shon', + 'Wilms', + 'Bren', + 'Bertin', + 'Poster', + 'Jeng', + 'Stcharles', + 'Jenning', + 'Eutsey', + 'Fayne', + 'Gustave', + 'Mccargo', + 'Boruff', + 'Boschert', + 'Burmester', + 'Colello', + 'Conchas', + 'Devi', + 'Dishaw', + 'Funaro', + 'Gallen', + 'Hsueh', + 'Lanser', + 'Macaraeg', + 'Munster', + 'Petsch', + 'Routon', + 'Werkmeister', + 'Woznicki', + 'Boroff', + 'Cochenour', + 'Dibartolomeo', + 'Elzinga', + 'Heyen', + 'Lapaglia', + 'Schiel', + 'Rauda', + 'Woltman', + 'Carll', + 'Kanda', + 'Runnells', + 'Hazelett', + 'Arnwine', + 'Sherfield', + 'Borthwick', + 'Coyner', + 'Ensey', + 'Feinman', + 'Leyendecker', + 'Lickteig', + 'Lubeck', + 'Maccarone', + 'Minahan', + 'Plew', + 'Saur', + 'Schleich', + 'Sixtos', + 'Soller', + 'Valek', + 'Umland', + 'Swogger', + 'Iannacone', + 'Tomey', + 'Venuto', + 'Peru', + 'Adolf', + 'Lemme', + 'Bureau', + 'River', + 'Buffaloe', + 'Leacock', + 'Threat', + 'Boza', + 'Constancio', + 'Dandurand', + 'Hiscock', + 'Kaley', + 'Michaelsen', + 'Roberti', + 'Sicilia', + 'Sliker', + 'Sooter', + 'Steyer', + 'Tabora', + 'Vanderbeek', + 'Vanscyoc', + 'Piercey', + 'Sabater', + 'Bride', + 'Tippens', + 'Acquaviva', + 'Baublitz', + 'Mccanna', + 'Mckaig', + 'Merenda', + 'Obermeier', + 'Pechacek', + 'Pugmire', + 'Shaneyfelt', + 'Steuer', + 'Zeidler', + 'Bodenheimer', + 'Gaglio', + 'Maceachern', + 'Munsterman', + 'Rayle', + 'Wisnewski', + 'Baar', + 'Thi', + 'Foulds', + 'Rufino', + 'Chrisco', + 'Barrientez', + 'Lare', + 'Munnerlyn', + 'Pitter', + 'Koroma', + 'Caisse', + 'Espe', + 'Kerin', + 'Melchiorre', + 'Mentz', + 'Paasch', + 'Parrales', + 'Rhew', + 'Sigley', + 'Skiff', + 'Stockert', + 'Viglione', + 'Kraska', + 'Botto', + 'Ponzio', + 'Wolfley', + 'Wack', + 'Kilborn', + 'Dunnavant', + 'Pitney', + 'Dolman', + 'Biscoe', + 'Michelle', + 'Azcona', + 'Brasington', + 'Fazzino', + 'Hoefs', + 'Kohlmeyer', + 'Laser', + 'Morea', + 'Morrin', + 'Neuwirth', + 'Nicklaus', + 'Pennypacker', + 'Rueckert', + 'Schriefer', + 'Scovel', + 'Swyers', + 'Thebeau', + 'Mijangos', + 'Douville', + 'Tidball', + 'Smullen', + 'Lecount', + 'Pruiett', + 'Branche', + 'Arment', + 'Babiarz', + 'Char', + 'Granlund', + 'Hillock', + 'Kahrs', + 'Khong', + 'Lalley', + 'Laspina', + 'Pietila', + 'Ponciano', + 'Rosengren', + 'Slee', + 'Snowberger', + 'Weglarz', + 'Camarata', + 'Villalovos', + 'Buza', + 'Kenning', + 'Rohrig', + 'Sedor', + 'Perretta', + 'Hamberg', + 'Mongan', + 'Formby', + 'Portier', + 'Silcott', + 'Levell', + 'Barrantes', + 'Bellefeuille', + 'Beneke', + 'Bilbao', + 'Danahy', + 'Delahanty', + 'Deppen', + 'Dicostanzo', + 'Dudding', + 'Elmquist', + 'Handa', + 'Hatem', + 'Loverde', + 'Mesick', + 'Onofrio', + 'Ramesh', + 'Tiberio', + 'Trachtenberg', + 'Vanwagenen', + 'Cassada', + 'Pepitone', + 'Stillson', + 'Pfarr', + 'Radle', + 'Scallan', + 'Carlen', + 'Bermingham', + 'Sagers', + 'Llorens', + 'Turay', + 'Beamish', + 'Carlini', + 'Galipeau', + 'Heavey', + 'Kempker', + 'Masser', + 'Montellano', + 'Peine', + 'Pietro', + 'Plitt', + 'Pollman', + 'Rike', + 'Spees', + 'Vandervelde', + 'Vanwey', + 'Grundman', + 'Marinucci', + 'Molenda', + 'Shideler', + 'Turrubiartes', + 'Schaer', + 'Firkins', + 'Haid', + 'Parnes', + 'Pulse', + 'Masone', + 'Burpo', + 'Tharrington', + 'Winborn', + 'Petite', + 'Buttry', + 'Clason', + 'Eutsler', + 'Haberer', + 'Haft', + 'Kotler', + 'Meloche', + 'Raether', + 'Rengifo', + 'Roback', + 'Stangle', + 'Wilderman', + 'Chickering', + 'Gervacio', + 'Penaranda', + 'Schnieders', + 'Coyer', + 'Laramee', + 'Curts', + 'Bailiff', + 'Truby', + 'Molder', + 'Hedley', + 'Carbon', + 'Gudger', + 'Fontenette', + 'Askren', + 'Deshane', + 'Enriques', + 'Fake', + 'Jungers', + 'Krech', + 'Niemela', + 'Perfetto', + 'Ritt', + 'Soldano', + 'Stanish', + 'Strege', + 'Wichert', + 'Wolz', + 'Zimbelman', + 'Abplanalp', + 'Nikkel', + 'Oravec', + 'Coile', + 'Mizuno', + 'Fenlon', + 'Vanloo', + 'Callery', + 'Hortman', + 'Hashim', + 'Sorey', + 'Ajayi', + 'Alesi', + 'Alessandro', + 'Avants', + 'Bachtel', + 'Bonine', + 'Butkovich', + 'Cerros', + 'Colina', + 'Dayhoff', + 'Favata', + 'Haning', + 'Kamath', + 'Kosik', + 'Loughrey', + 'Mollo', + 'Nagi', + 'Nesler', + 'Nosek', + 'Ordoyne', + 'Politis', + 'Zwolinski', + 'Yaffe', + 'Sigal', + 'Burow', + 'Scarbro', + 'Buckel', + 'Broxson', + 'Goyer', + 'Goding', + 'Delee', + 'Jefferys', + 'Blissett', + 'Balian', + 'Brader', + 'Curreri', + 'Dickmann', + 'Eckerle', + 'Erives', + 'Fedewa', + 'Frisina', + 'Gropp', + 'Hinck', + 'Lamorte', + 'Litzenberger', + 'Proehl', + 'Struss', + 'Tamburello', + 'Digioia', + 'Galarneau', + 'Jurkiewicz', + 'Macnaughton', + 'Talsma', + 'Vlasak', + 'Weyrauch', + 'Yontz', + 'Kho', + 'Stgermaine', + 'Grauer', + 'Benware', + 'Rearden', + 'Molin', + 'Pendergrast', + 'Sivils', + 'Ellery', + 'Ikner', + 'Metayer', + 'Toran', + 'Seaberry', + 'Banderas', + 'Bannan', + 'Critzer', + 'Doescher', + 'Haakenson', + 'Hignite', + 'Hoeksema', + 'Inserra', + 'Korbel', + 'Kruzel', + 'Langen', + 'Mittelstaedt', + 'Popkin', + 'Schwarting', + 'Toral', + 'Ilagan', + 'Lamica', + 'Lierman', + 'Zimmerly', + 'Fosse', + 'Pagnotta', + 'Trenholm', + 'Clayson', + 'Cerutti', + 'Wollard', + 'Mcburnett', + 'Stallcup', + 'Magan', + 'Wonder', + 'Gillock', + 'Ellisor', + 'Clayburn', + 'Mabery', + 'Cariaga', + 'Crail', + 'Dieckman', + 'Joynt', + 'Kleinert', + 'Kutner', + 'Milla', + 'Nauta', + 'Rende', + 'Robare', + 'Santella', + 'Scianna', + 'Sevcik', + 'Smolik', + 'Staudinger', + 'Cedillos', + 'Shroff', + 'Ueda', + 'Yearout', + 'Zuno', + 'Pottle', + 'Klabunde', + 'Tusa', + 'Schomburg', + 'Alto', + 'Packett', + 'Muns', + 'Dante', + 'Jarnigan', + 'Londo', + 'Bigbee', + 'Isles', + 'Nembhard', + 'Appiah', + 'Hypolite', + 'Acebedo', + 'Arlt', + 'Champney', + 'Kawahara', + 'Lehan', + 'Pavlak', + 'Ritacco', + 'Seckinger', + 'Turvey', + 'Vanevery', + 'Wronski', + 'Bahnsen', + 'Clites', + 'Ellwanger', + 'Husak', + 'Lydic', + 'Zubiate', + 'Muehlbauer', + 'Neumeister', + 'Wellnitz', + 'Langstaff', + 'Gort', + 'Eve', + 'Stones', + 'Stanard', + 'Whichard', + 'Cheers', + 'Baldus', + 'Bertoni', + 'Chesebro', + 'Dino', + 'Dubray', + 'Icenhour', + 'Marquard', + 'Mette', + 'Potash', + 'Winterhalter', + 'Crupi', + 'Lascala', + 'Tauer', + 'Vandenburgh', + 'Mende', + 'Swarey', + 'Sarles', + 'Platter', + 'Dekeyser', + 'Jaye', + 'Pelle', + 'Caroll', + 'Rosette', + 'Shepperson', + 'Fooks', + 'Kennerson', + 'Bolser', + 'Chim', + 'Diefenderfer', + 'Frosch', + 'Holzwarth', + 'Kjos', + 'Langland', + 'Meland', + 'Stufflebeam', + 'Worland', + 'Barrales', + 'Chhay', + 'Corkern', + 'Creegan', + 'Golan', + 'Marceaux', + 'Matsuo', + 'Micallef', + 'Otsuka', + 'Rinella', + 'Creveling', + 'Krane', + 'Mcnay', + 'Detter', + 'Drexel', + 'Kibodeaux', + 'Shippey', + 'Medearis', + 'Samms', + 'Drzewiecki', + 'Fariss', + 'Glandon', + 'Heinecke', + 'Hendler', + 'Jungwirth', + 'Panepinto', + 'Rohleder', + 'Saragosa', + 'Stuller', + 'Wissel', + 'Atwal', + 'Tisch', + 'Esterly', + 'Mourad', + 'Brickell', + 'Bough', + 'Rubens', + 'Angevine', + 'Tolin', + 'Sago', + 'Apfel', + 'Ashdown', + 'Derusha', + 'Fiorino', + 'Koyama', + 'Matteucci', + 'Newbrough', + 'Seufert', + 'Stahley', + 'Tyburski', + 'Zaino', + 'Cdebaca', + 'Hormann', + 'Wangen', + 'Winterton', + 'Beagley', + 'Sowden', + 'Daul', + 'Errington', + 'Steber', + 'Emfinger', + 'Olan', + 'Fiveash', + 'Carriger', + 'Breakfield', + 'Ezekiel', + 'Wallington', + 'Hollimon', + 'Izzard', + 'Lyde', + 'Bellmore', + 'Benkert', + 'Bhargava', + 'Dacanay', + 'Dano', + 'Diprima', + 'Garlitz', + 'Hannemann', + 'Janiak', + 'Klann', + 'Kunce', + 'Malicki', + 'Mcgivney', + 'Nordeen', + 'Procell', + 'Rands', + 'Smeltz', + 'Sutch', + 'Wach', + 'Wentling', + 'Karapetyan', + 'Mcvicar', + 'Pennisi', + 'Perley', + 'Graner', + 'Hartney', + 'Shadley', + 'Pennebaker', + 'Cayce', + 'Marris', + 'Burges', + 'Odem', + 'Charvat', + 'Delgreco', + 'Diven', + 'Latu', + 'Mccallion', + 'Mcfeely', + 'Mon', + 'Nagai', + 'Obrecht', + 'Opdyke', + 'Pearlstein', + 'Pomroy', + 'Prothero', + 'Rado', + 'Roehr', + 'Seiffert', + 'Spake', + 'Stech', + 'Thakur', + 'Trzcinski', + 'Uvalle', + 'Vazques', + 'Anschutz', + 'Boecker', + 'Descoteaux', + 'Idol', + 'Stanzione', + 'Welp', + 'Schumer', + 'Ridner', + 'Kasner', + 'Auton', + 'Barca', + 'Ocheltree', + 'Biernat', + 'Mercuri', + 'Truslow', + 'Witters', + 'Mcelhannon', + 'Mccrackin', + 'Brabson', + 'Baumberger', + 'Double', + 'Garis', + 'Kasparian', + 'Kooistra', + 'Loser', + 'Mangone', + 'Massman', + 'Raimondo', + 'Sparacio', + 'Valli', + 'Viets', + 'Wessell', + 'Kieu', + 'Vonderheide', + 'Wojnar', + 'Furbee', + 'Heyden', + 'Lackie', + 'Ehrich', + 'Roupe', + 'Holy', + 'Care', + 'Isa', + 'Samad', + 'Rougeau', + 'Chavous', + 'Rattler', + 'Wedderburn', + 'President', + 'Blackham', + 'Bobak', + 'Crimi', + 'Durland', + 'Gargus', + 'Gitlin', + 'Levandoski', + 'Niu', + 'Piccirilli', + 'Sauvageau', + 'Schweers', + 'Talty', + 'Uthe', + 'Verga', + 'Warzecha', + 'Erisman', + 'Gallacher', + 'Shanholtz', + 'Fulgencio', + 'Migues', + 'Garin', + 'Heisel', + 'Stong', + 'Christiana', + 'Bonenfant', + 'Clancey', + 'Kindley', + 'Nill', + 'Mood', + 'Atterbury', + 'Tobe', + 'Eisenhardt', + 'Franceschini', + 'Heiland', + 'Kreuzer', + 'Lockaby', + 'Scarola', + 'Tessitore', + 'Warehime', + 'Kukowski', + 'Ruhlman', + 'Frymire', + 'Bartone', + 'Wrightson', + 'Langlinais', + 'Planas', + 'Darsey', + 'Darin', + 'Gammel', + 'Giroir', + 'Aspinall', + 'Hollywood', + 'Childres', + 'Copelin', + 'Teamer', + 'Okoro', + 'Abshier', + 'Arizaga', + 'Berenson', + 'Biegler', + 'Dugdale', + 'Erlich', + 'Gavino', + 'Haaland', + 'Lautenschlager', + 'Lilja', + 'Livingood', + 'Lockner', + 'Pyeatt', + 'Reist', + 'Rummell', + 'Schadler', + 'Snare', + 'Zawada', + 'Dumler', + 'Moncivais', + 'Sammarco', + 'Laraway', + 'Voorhis', + 'Detty', + 'Manko', + 'Zale', + 'Autin', + 'Quaid', + 'Denver', + 'Demario', + 'Nearing', + 'Amerine', + 'Bea', + 'Carraher', + 'Dierkes', + 'Dutko', + 'Hosek', + 'Kassner', + 'Meo', + 'Mesler', + 'Norquist', + 'Pacetti', + 'Pellerito', + 'Ryser', + 'Turnmire', + 'Caniglia', + 'Zollman', + 'Gerwig', + 'Denslow', + 'Stapler', + 'Majid', + 'Prestage', + 'Eargle', + 'Spight', + 'Argabright', + 'Borgeson', + 'Cipollone', + 'Dippold', + 'Korf', + 'Milhoan', + 'Pinelli', + 'Roblero', + 'Scolaro', + 'Sperl', + 'Svensson', + 'Bauguess', + 'Freimuth', + 'Luquin', + 'Barman', + 'Solivan', + 'Buel', + 'Birkeland', + 'Cafiero', + 'Degollado', + 'Demeyer', + 'Hoberg', + 'Homola', + 'Kadel', + 'Koslowski', + 'Lefrancois', + 'Macconnell', + 'Madill', + 'Nudelman', + 'Raucci', + 'Reidenbach', + 'Schermer', + 'Sergio', + 'Bucko', + 'Haegele', + 'Nibert', + 'Sidell', + 'Slape', + 'Hellard', + 'Russi', + 'Wilcock', + 'Verdejo', + 'Lessley', + 'Camille', + 'Topps', + 'Acampora', + 'Blacketer', + 'Clapham', + 'Efaw', + 'Louks', + 'Mersch', + 'Odden', + 'Schettler', + 'Schnarr', + 'Sieracki', + 'Skog', + 'Zobrist', + 'Corless', + 'Zunker', + 'Bega', + 'Victoriano', + 'Singler', + 'Keltz', + 'Valcarcel', + 'Curet', + 'Harvison', + 'Mccullah', + 'Cranfield', + 'Gardin', + 'Mewborn', + 'Bisel', + 'Carfagno', + 'Carli', + 'Chirino', + 'Fairless', + 'Gaboury', + 'Goetze', + 'Guitron', + 'Haut', + 'Krupski', + 'Lata', + 'Misiak', + 'Sawaya', + 'Schomaker', + 'Schulke', + 'Tin', + 'Dewhurst', + 'Krummel', + 'Hannahs', + 'Carlow', + 'Hemp', + 'Bowdoin', + 'Breda', + 'Chriss', + 'Kebede', + 'Binney', + 'Brasseaux', + 'Cunliffe', + 'Gantner', + 'Gillick', + 'Hottle', + 'Hren', + 'Irani', + 'Klitzke', + 'Luhrs', + 'Micale', + 'Oien', + 'Oppelt', + 'Rallo', + 'Ringwald', + 'Stonerock', + 'Strebel', + 'Tiberi', + 'Volner', + 'Whetstine', + 'Wrubel', + 'Brakebill', + 'Fechner', + 'Geurts', + 'Hoefling', + 'Misener', + 'Andros', + 'Dimock', + 'Rosendo', + 'Megill', + 'Gloyd', + 'Garney', + 'Andries', + 'Esco', + 'Rhames', + 'Draine', + 'Plair', + 'Jiggetts', + 'Atcheson', + 'Brienza', + 'Cerveny', + 'Depaoli', + 'Deroo', + 'Dorf', + 'Guidotti', + 'Heimlich', + 'Insalaco', + 'Kaczorowski', + 'Kinnunen', + 'Loureiro', + 'Lyster', + 'Pia', + 'Piccoli', + 'Quale', + 'Sadek', + 'Stenstrom', + 'Strause', + 'Tortorella', + 'Traweek', + 'Vanderwerff', + 'Varian', + 'Vink', + 'Waxler', + 'Wynia', + 'Annese', + 'Economou', + 'Whitsel', + 'Dougher', + 'Schnieder', + 'Cosman', + 'Farra', + 'Osmon', + 'Bardon', + 'Rampersaud', + 'Jane', + 'Kirts', + 'Chennault', + 'Thomison', + 'Graig', + 'Narine', + 'Gunner', + 'Aamodt', + 'Adinolfi', + 'Adolphson', + 'Aki', + 'Alderton', + 'Aloisio', + 'Bellavia', + 'Clutts', + 'Coughran', + 'Frasco', + 'Guinta', + 'Hatala', + 'Ibach', + 'Mecum', + 'Medero', + 'Neria', + 'Nery', + 'Pignataro', + 'Podesta', + 'Statzer', + 'Stombaugh', + 'Szczesny', + 'Kovaleski', + 'Ades', + 'Bauers', + 'Bern', + 'Horsfall', + 'Masood', + 'Cinque', + 'Stay', + 'Beare', + 'Donavan', + 'Ikerd', + 'Seney', + 'Layson', + 'Coler', + 'Tuft', + 'Tamplin', + 'Billinger', + 'Scrivens', + 'Bartolomei', + 'Baza', + 'Dimattia', + 'Dotterer', + 'Dushane', + 'Fulop', + 'Iacovelli', + 'Macnamara', + 'Mahlum', + 'Noteboom', + 'Rebstock', + 'Drechsler', + 'Itzkowitz', + 'Rigler', + 'Schrom', + 'Pirozzi', + 'Ferre', + 'Shiley', + 'Villanova', + 'Barona', + 'Farrel', + 'Shelman', + 'Nute', + 'Rowlette', + 'Tarrance', + 'Cadorette', + 'Christenberry', + 'Deocampo', + 'Farace', + 'Fesmire', + 'Kallman', + 'Koogler', + 'Pitsch', + 'Salce', + 'Schnepf', + 'Totaro', + 'Towey', + 'Urdiales', + 'Gotschall', + 'Brunett', + 'Dier', + 'Hainsworth', + 'Seabury', + 'Cornelious', + 'Altobelli', + 'Andreozzi', + 'Bohlmann', + 'Carranco', + 'Daubenspeck', + 'Delagrange', + 'Delo', + 'Faler', + 'Ficke', + 'Hellinger', + 'Hudman', + 'Ihde', + 'Landolfi', + 'Leiner', + 'Mosman', + 'Rang', + 'Tarbet', + 'Wineman', + 'Fehrman', + 'Guinto', + 'Icenogle', + 'Tomasik', + 'Looman', + 'Iriarte', + 'Denaro', + 'Montross', + 'Piersall', + 'Lauren', + 'Lablanc', + 'Kindrick', + 'Deriso', + 'Manker', + 'Maycock', + 'Cullens', + 'Frieson', + 'Clippinger', + 'Colavito', + 'Fassbender', + 'Fennessy', + 'Granada', + 'Gugliotta', + 'Guiliano', + 'Hirschberg', + 'Kerbs', + 'Kusch', + 'Limmer', + 'Malpica', + 'Mcaloon', + 'Morken', + 'Pytel', + 'Resnik', + 'Spangle', + 'Worstell', + 'Kerkhoff', + 'Kupka', + 'Stanczyk', + 'Storlie', + 'Thurow', + 'Caetano', + 'Ernandez', + 'Males', + 'Coopersmith', + 'Everest', + 'Leander', + 'Demeritt', + 'Thomes', + 'Codner', + 'Livsey', + 'Alcoser', + 'Arico', + 'Balestrieri', + 'Cavalli', + 'Florendo', + 'Gottshall', + 'Hinesley', + 'Lafuente', + 'Landess', + 'Ornstein', + 'Pettingill', + 'Romesburg', + 'Tokunaga', + 'Wiersema', + 'Janeway', + 'Pecha', + 'Steimel', + 'Sproule', + 'Sommerfield', + 'Mirsky', + 'Staines', + 'Pu', + 'Corbit', + 'Mcelmurry', + 'Wickes', + 'Yell', + 'Mordecai', + 'Aye', + 'Boldin', + 'China', + 'Fason', + 'Thibeaux', + 'Nesby', + 'Bergevin', + 'Besecker', + 'Dohrmann', + 'Fujioka', + 'Fyock', + 'Goralski', + 'Kirschenbaum', + 'Knipper', + 'Menor', + 'Mischler', + 'Nolder', + 'Odoherty', + 'Pickerill', + 'Poremba', + 'Swantek', + 'Difabio', + 'Kulka', + 'Servais', + 'Wickizer', + 'Melecio', + 'Zeek', + 'Fruit', + 'Agnes', + 'Bar', + 'Mccarrell', + 'Hopgood', + 'Califano', + 'Cratty', + 'Dishner', + 'Gabrielli', + 'Hamacher', + 'Hinote', + 'Jakob', + 'Klinkhammer', + 'Krasinski', + 'Krysiak', + 'Pardi', + 'Petrilli', + 'Razon', + 'Reifsnyder', + 'Reisig', + 'Reller', + 'Sassano', + 'Steinhart', + 'Wrede', + 'Zevallos', + 'Coombe', + 'Quesnel', + 'Rebuck', + 'Wantz', + 'Bendele', + 'Lacomb', + 'Hagge', + 'Donelan', + 'Kempe', + 'Po', + 'Varnadoe', + 'Constantin', + 'Deon', + 'Motte', + 'Beckum', + 'Parchment', + 'Meriweather', + 'Borucki', + 'Fatima', + 'Gerkin', + 'Guglielmi', + 'Hettich', + 'Hoerr', + 'Karlsson', + 'Kenealy', + 'Paolillo', + 'Pfenning', + 'Rueger', + 'Schildt', + 'Sem', + 'Vilches', + 'Dornbusch', + 'Erdahl', + 'Kleinhenz', + 'Moneypenny', + 'Tomasko', + 'Vandevender', + 'Cromley', + 'Tun', + 'Velasques', + 'Roble', + 'Burgo', + 'Waples', + 'Mabon', + 'Benincasa', + 'Buttermore', + 'Dalbec', + 'Eikenberry', + 'Fuehrer', + 'Hossler', + 'Lepp', + 'Opheim', + 'Sarsfield', + 'Strobl', + 'Strouth', + 'Tousley', + 'Wilczek', + 'Kleppe', + 'Muraoka', + 'Wiencek', + 'Pinckard', + 'Ahsan', + 'Welder', + 'Forton', + 'Lorden', + 'Stlawrence', + 'Marina', + 'Mcquire', + 'Randleman', + 'Pates', + 'Fluitt', + 'Scotland', + 'Clerk', + 'Townsell', + 'Arrasmith', + 'Baisch', + 'Berling', + 'Busler', + 'Curtice', + 'Ebinger', + 'Fleeger', + 'Geng', + 'Goettsch', + 'Henneberry', + 'Johannesen', + 'Mcilrath', + 'Perigo', + 'Phibbs', + 'Riske', + 'Scarcella', + 'Vandyken', + 'Barstad', + 'Dicamillo', + 'Ernsberger', + 'Guebara', + 'Peetz', + 'Newcome', + 'Alterman', + 'Weik', + 'Trier', + 'Yeats', + 'Hugg', + 'Crayne', + 'Ige', + 'Coach', + 'Archuletta', + 'Bodi', + 'Cadavid', + 'Ceccarelli', + 'Derksen', + 'Deutscher', + 'Genter', + 'Gogel', + 'Gorczyca', + 'Grohs', + 'Koplin', + 'Kozloski', + 'Lillo', + 'Oplinger', + 'Pulis', + 'Renk', + 'Repka', + 'Scavo', + 'Vitagliano', + 'Weinkauf', + 'Yellin', + 'Boehlke', + 'Montecalvo', + 'Castrillo', + 'Grenon', + 'Wellen', + 'Keelan', + 'Coville', + 'Rison', + 'Jourdain', + 'Chestnutt', + 'Sharpley', + 'Acharya', + 'Bartles', + 'Burruel', + 'Capelle', + 'Contos', + 'Friedrichsen', + 'Heaberlin', + 'Hermiz', + 'Iracheta', + 'Klutts', + 'Koziel', + 'Salto', + 'Scaturro', + 'Stasik', + 'Stitzel', + 'Wiseley', + 'Paccione', + 'Squyres', + 'Leverich', + 'Holderness', + 'Elvin', + 'Morand', + 'Lizana', + 'Woolen', + 'Amarante', + 'Arn', + 'Biedermann', + 'Daddio', + 'Davilla', + 'Forti', + 'Gripp', + 'Hanzlik', + 'Iannotti', + 'Larin', + 'Nakajima', + 'Novacek', + 'Pesch', + 'Regino', + 'Rosengarten', + 'Schleif', + 'Searing', + 'Sikkema', + 'Walstrom', + 'Guastella', + 'Hemstreet', + 'Rorabaugh', + 'Weisenburger', + 'Cannan', + 'Band', + 'Fowkes', + 'Bennetts', + 'Purviance', + 'Tippin', + 'Brossard', + 'Seigle', + 'Babyak', + 'Billiter', + 'Cartner', + 'Deetz', + 'Dorow', + 'Laur', + 'Leblond', + 'Lecomte', + 'Morando', + 'Reitman', + 'Sarria', + 'Scheu', + 'Timmermann', + 'Vaneck', + 'Vangorp', + 'Windhorst', + 'Kaeser', + 'Kosloski', + 'Cappuccio', + 'Knitter', + 'Evon', + 'Garbett', + 'Wickens', + 'Ruston', + 'Fregia', + 'Ashurst', + 'Ede', + 'Strider', + 'Reaux', + 'Castellani', + 'Debus', + 'Degracia', + 'Hineman', + 'Laning', + 'Litts', + 'Losito', + 'Massi', + 'Mazzara', + 'Schriber', + 'Seyfert', + 'Strength', + 'Treptow', + 'Yuhasz', + 'Kamrath', + 'Krigbaum', + 'Marrocco', + 'Wanta', + 'Yakubov', + 'Hy', + 'Sabedra', + 'Belling', + 'Deats', + 'Mahaffy', + 'Brodrick', + 'Mcneece', + 'Madding', + 'Mottley', + 'Asp', + 'Borgerding', + 'Conrady', + 'Dagenhart', + 'Defusco', + 'Duensing', + 'Ensz', + 'Fockler', + 'Gajda', + 'Masino', + 'Minster', + 'Naso', + 'Nifong', + 'Ohlsen', + 'Prairie', + 'Rosendale', + 'Rotman', + 'Salzano', + 'Samet', + 'Takagi', + 'Vandagriff', + 'Vespa', + 'Zaragosa', + 'Howdyshell', + 'Kilburg', + 'Mellado', + 'Mollet', + 'Varone', + 'Benne', + 'Dillehay', + 'Ruther', + 'Gullick', + 'Lasure', + 'Wilkenson', + 'Lawrance', + 'Amacker', + 'Wisher', + 'Pryer', + 'Torian', + 'Aragona', + 'Dains', + 'Darrigo', + 'Escajeda', + 'Fertitta', + 'Futral', + 'Kielty', + 'Kightlinger', + 'Lanuza', + 'Marich', + 'Mcenaney', + 'Mohrman', + 'Pressnell', + 'Prestia', + 'Scullin', + 'Seidner', + 'Steigerwalt', + 'Wassell', + 'Bonavita', + 'Bourgault', + 'Sentz', + 'Viswanathan', + 'Hanchey', + 'Volpi', + 'Wilensky', + 'Mathey', + 'Mages', + 'Raimo', + 'Cozine', + 'Sprow', + 'Petties', + 'Bracht', + 'Cayabyab', + 'Comp', + 'Flamenco', + 'Friederich', + 'Hori', + 'Husmann', + 'Isidoro', + 'Ketchem', + 'Krishnamurthy', + 'Kucinski', + 'Lalani', + 'Lamacchia', + 'Lecher', + 'Morante', + 'Schrieber', + 'Sciarra', + 'Vandamme', + 'Welz', + 'Bozich', + 'Cancilla', + 'Panduro', + 'Mcglade', + 'Wasmund', + 'Riso', + 'Moronta', + 'Kemple', + 'Rocks', + 'Sainsbury', + 'Solo', + 'Harnage', + 'Sturkie', + 'Hollingworth', + 'Denley', + 'Bumpass', + 'Lovick', + 'Bribiesca', + 'Dewilde', + 'Drohan', + 'Geringer', + 'Kokoszka', + 'Kronberg', + 'Lewinski', + 'Lunney', + 'Morehart', + 'Ty', + 'Vasseur', + 'Vona', + 'Wriston', + 'Casarrubias', + 'Copsey', + 'Rochette', + 'Macwilliams', + 'Natali', + 'Milanes', + 'Rux', + 'Woodcox', + 'Bernett', + 'Bronaugh', + 'Fulwood', + 'Bhalla', + 'Depalo', + 'Hench', + 'Huckeba', + 'Kasch', + 'Kisor', + 'Marinos', + 'Nakahara', + 'Parrent', + 'Rantz', + 'Schoenbeck', + 'Schwieterman', + 'Selk', + 'Swonger', + 'Walding', + 'Nunamaker', + 'Schuchardt', + 'Leverton', + 'Fiallo', + 'Viruet', + 'Fadel', + 'Robel', + 'Calley', + 'Renton', + 'Rack', + 'Brin', + 'Cocks', + 'Mcivor', + 'Bois', + 'Demary', + 'Bason', + 'Dowlen', + 'Prophete', + 'Collymore', + 'Beisner', + 'Briand', + 'Cumberledge', + 'Curro', + 'Cutcher', + 'Daponte', + 'Eckroth', + 'Edgemon', + 'Farinella', + 'Kobe', + 'Muilenburg', + 'Osiecki', + 'Cutsinger', + 'Biggar', + 'Maciver', + 'Quesinberry', + 'Rippetoe', + 'Baswell', + 'Caven', + 'Mimbs', + 'Hurlock', + 'Cham', + 'Cypress', + 'Emile', + 'Beitel', + 'Bellavance', + 'Casada', + 'Fandel', + 'Gillentine', + 'Gorelick', + 'Kassis', + 'Klim', + 'Kohnke', + 'Lutgen', + 'Nalbandian', + 'Schepis', + 'Troester', + 'Hartje', + 'Hippensteel', + 'Kiehn', + 'Kuenzi', + 'Greenburg', + 'Boroughs', + 'Catton', + 'Adney', + 'Olivencia', + 'Mcdermitt', + 'Ashwell', + 'Leazer', + 'Poag', + 'Prevo', + 'Porcher', + 'Hugley', + 'Salone', + 'Jupiter', + 'Bratz', + 'Ehresman', + 'Fauber', + 'Filippelli', + 'Kesling', + 'Kronk', + 'Mcelhiney', + 'Mcgreal', + 'Miyasato', + 'Moomey', + 'Nicolini', + 'Osberg', + 'Ostroski', + 'Sanzo', + 'Sybert', + 'Dimichele', + 'Gerrits', + 'Shatley', + 'Weider', + 'Faraj', + 'Paules', + 'Yarberry', + 'Lege', + 'Pembroke', + 'Clipper', + 'Filmore', + 'Crichlow', + 'Blaustein', + 'Boak', + 'Canzoneri', + 'Crescenzo', + 'Ebaugh', + 'Feig', + 'Jens', + 'Knoebel', + 'Mohammadi', + 'Montour', + 'Norgren', + 'Pasquini', + 'Prost', + 'Reh', + 'Rosal', + 'Thesing', + 'Titcomb', + 'Wolinski', + 'Zeitlin', + 'Depoy', + 'Guccione', + 'Ritsema', + 'Valent', + 'Drey', + 'Govoni', + 'Lonsdale', + 'Hultz', + 'Harvie', + 'Levison', + 'Colomb', + 'Dace', + 'Cleckley', + 'Godette', + 'Brentlinger', + 'Fetrow', + 'Giuffrida', + 'Kopka', + 'Kurtzman', + 'Panameno', + 'Pannone', + 'Parzych', + 'Seipp', + 'Stobbe', + 'Thulin', + 'Torosian', + 'Trani', + 'Zietlow', + 'Montufar', + 'Stohr', + 'Woloszyn', + 'Cimini', + 'Angles', + 'Nicasio', + 'Vi', + 'Em', + 'Couchman', + 'Hobbie', + 'Bluestein', + 'Phillipson', + 'Shiels', + 'Altice', + 'Williston', + 'Kone', + 'Tadesse', + 'Abbruzzese', + 'Badders', + 'Duxbury', + 'Egeland', + 'Freyre', + 'Haen', + 'Hineline', + 'Kniss', + 'Kothe', + 'Kyker', + 'Popelka', + 'Sanjose', + 'Slaugh', + 'Wecker', + 'Wiechman', + 'Bilello', + 'Keezer', + 'Knode', + 'Longhurst', + 'Wisser', + 'Cease', + 'Contrera', + 'Berroa', + 'Aguon', + 'Pott', + 'Blitch', + 'Suares', + 'Bein', + 'Acre', + 'Ailes', + 'Tutwiler', + 'Porte', + 'Ashwood', + 'Blackson', + 'Viverette', + 'Balthazar', + 'Kidane', + 'Allegretti', + 'Corbeil', + 'Crossno', + 'Cudworth', + 'Federspiel', + 'Hamstra', + 'Kibbey', + 'Lefevers', + 'Loomer', + 'Losada', + 'Medema', + 'Palmerin', + 'Peregoy', + 'Previte', + 'Riedinger', + 'Schlossberg', + 'Wilemon', + 'Lepkowski', + 'Mcdanel', + 'Commisso', + 'Baiza', + 'Fones', + 'Divis', + 'Diedrick', + 'Grave', + 'Bonkowski', + 'Cerami', + 'Drinkwine', + 'Hauke', + 'Heun', + 'Keilman', + 'Klemmer', + 'Mella', + 'Olarte', + 'Ryall', + 'Veltman', + 'Wlodarczyk', + 'Bashor', + 'Kubinski', + 'Vanacker', + 'Prouse', + 'Perrott', + 'Berrio', + 'Mccarney', + 'Seiders', + 'Jafari', + 'Louque', + 'Melder', + 'Grazier', + 'Gabay', + 'Hardway', + 'Sadiq', + 'Sully', + 'Durrell', + 'Barno', + 'Maybin', + 'Brazile', + 'Asante', + 'Awalt', + 'Badal', + 'Cucinotta', + 'Grenfell', + 'Hartis', + 'Herbster', + 'Hesch', + 'Klosowski', + 'Overfelt', + 'Pangelinan', + 'Pflum', + 'Rozema', + 'Spivack', + 'Vallez', + 'Vetere', + 'Villamor', + 'Wedekind', + 'Bobrowski', + 'Nguyenthi', + 'Nowaczyk', + 'Vis', + 'Pownall', + 'Susan', + 'Yanni', + 'Gest', + 'Balthrop', + 'Treasure', + 'Harston', + 'Frett', + 'Buttery', + 'Chiarelli', + 'Colledge', + 'Czaplicki', + 'Fahringer', + 'Fedder', + 'Gerstenberger', + 'Gretz', + 'Hallquist', + 'Hemme', + 'Kolling', + 'Krauth', + 'Liquori', + 'Podolsky', + 'Scheirer', + 'Sehgal', + 'Selinger', + 'Wintermute', + 'Chokshi', + 'Dimarzio', + 'Santoni', + 'Wetherby', + 'Flis', + 'Comley', + 'Boyt', + 'Farrah', + 'Mario', + 'Mcquilkin', + 'Tim', + 'Cusic', + 'Enge', + 'Millage', + 'Waheed', + 'Kenan', + 'Silmon', + 'Mcconico', + 'Bougher', + 'Braly', + 'Coriell', + 'Daignault', + 'Henschen', + 'Holsomback', + 'Johal', + 'Kellams', + 'Schaumburg', + 'Stockinger', + 'Urquidi', + 'Cabanillas', + 'Lindbloom', + 'Willinger', + 'Redpath', + 'Baller', + 'Juarbe', + 'Badia', + 'Elderkin', + 'Dessert', + 'Retter', + 'Mccollam', + 'Rivette', + 'Devins', + 'Hewell', + 'Penniman', + 'Arbuthnot', + 'Cotman', + 'Tezeno', + 'Albo', + 'Beezley', + 'Can', + 'Chesler', + 'Dehne', + 'Demchak', + 'Edberg', + 'Gotham', + 'Ingels', + 'Kaercher', + 'Kwiecinski', + 'Landolt', + 'Macdonnell', + 'Malicoat', + 'Meinen', + 'Niswander', + 'Pandit', + 'Pettet', + 'Pliska', + 'Ploch', + 'Ratigan', + 'Sampsel', + 'Sick', + 'Ciampi', + 'Mctighe', + 'Riester', + 'Salvucci', + 'Tornow', + 'Vencill', + 'Racey', + 'Haroldson', + 'Finder', + 'Dennen', + 'Stano', + 'Boys', + 'Camillo', + 'Woodfield', + 'Turrell', + 'Sami', + 'Annan', + 'Yeldell', + 'Madlock', + 'Manigo', + 'Arcila', + 'Bauza', + 'Bisceglia', + 'Crouthamel', + 'Debenedetto', + 'Delude', + 'Dorta', + 'Fairburn', + 'Garciagarcia', + 'Geeslin', + 'Kazanjian', + 'Loescher', + 'Mccarl', + 'Mulqueen', + 'Pultz', + 'Shutter', + 'Spacek', + 'Yamanaka', + 'Borkholder', + 'Halko', + 'Pieroni', + 'Proano', + 'Sarkisyan', + 'Riopelle', + 'Routson', + 'Fogelman', + 'Sou', + 'Tress', + 'Altemus', + 'Bosh', + 'Laroque', + 'Hueston', + 'Latin', + 'Taitt', + 'Lymon', + 'Chadd', + 'Challis', + 'Comella', + 'Drabik', + 'Entz', + 'Hagner', + 'Knobbe', + 'Luckenbill', + 'Macphail', + 'Mogg', + 'Paustian', + 'Rimel', + 'Schilke', + 'Folkman', + 'Lemery', + 'Quinby', + 'Cliburn', + 'Rowand', + 'Wambach', + 'Gammell', + 'Nobrega', + 'Hoggan', + 'Nightengale', + 'Alison', + 'Batte', + 'Borner', + 'Hudnell', + 'Casseus', + 'Boteler', + 'Cantos', + 'Contois', + 'Coventry', + 'Dezarn', + 'Eisenbarth', + 'Hegel', + 'Jahr', + 'Joss', + 'Lober', + 'Marcks', + 'Portilla', + 'Reinders', + 'Scouten', + 'Siri', + 'Sobocinski', + 'Tesh', + 'Veno', + 'Wheeldon', + 'Yankee', + 'Wanke', + 'Wollin', + 'Longobardi', + 'Mccarson', + 'Sampsell', + 'Harrer', + 'Bakewell', + 'Mcgalliard', + 'Truluck', + 'Bremmer', + 'Lois', + 'Goody', + 'Kassim', + 'Conniff', + 'Elenes', + 'Esker', + 'Groshong', + 'Hallisey', + 'Loree', + 'Marken', + 'Molle', + 'Muntean', + 'Ozaki', + 'Roen', + 'Rumer', + 'Shorr', + 'Tanzer', + 'Varady', + 'Hillmer', + 'Macari', + 'Schuld', + 'Swartzlander', + 'Tsuji', + 'Holahan', + 'Abee', + 'Rowse', + 'Pawley', + 'Samp', + 'Shad', + 'Wintz', + 'Rainford', + 'Cellucci', + 'Cumpton', + 'Dando', + 'Dress', + 'Funari', + 'Gouker', + 'Hemberger', + 'Latz', + 'Meckes', + 'Parrinello', + 'Picardi', + 'Pilz', + 'Pretzer', + 'Schriever', + 'Sodano', + 'Stetter', + 'Storti', + 'Tiu', + 'Zimmerle', + 'Dragone', + 'Engert', + 'Fullenkamp', + 'Rockafellow', + 'Siwek', + 'Zillmer', + 'Devol', + 'Milke', + 'Taira', + 'Richner', + 'Aros', + 'Mancil', + 'Yetman', + 'Hanney', + 'Kinion', + 'Ferrand', + 'Conyer', + 'Chahal', + 'Fulfer', + 'Gurski', + 'Horseman', + 'Liebe', + 'Nyhus', + 'Pernice', + 'Pesqueira', + 'Rieker', + 'Trautmann', + 'Yellowhair', + 'Schwanz', + 'Salinger', + 'Carvell', + 'Heymann', + 'Grad', + 'Pharo', + 'Pipher', + 'Magalhaes', + 'Kissee', + 'Winthrop', + 'Leid', + 'Sledd', + 'Bladen', + 'Rahaman', + 'Holdman', + 'Goldwire', + 'Lawal', + 'Sinkfield', + 'Bryk', + 'Butkiewicz', + 'Gagen', + 'Gettle', + 'Goede', + 'Hardenbrook', + 'Heinsohn', + 'Kovalcik', + 'Needleman', + 'Obeso', + 'Parziale', + 'Schaus', + 'Wadlow', + 'Haluska', + 'Stiteler', + 'Zaruba', + 'Tschirhart', + 'Biscardi', + 'Gopal', + 'Avella', + 'Ponto', + 'Levit', + 'Trevor', + 'Pimienta', + 'Plass', + 'Guthery', + 'Cordy', + 'Tuff', + 'Zellars', + 'Altier', + 'Berges', + 'Connick', + 'Deruyter', + 'Divita', + 'Frankovich', + 'Ingenito', + 'Kosman', + 'Lantis', + 'Lovering', + 'Sortino', + 'Waage', + 'Wildrick', + 'Barberio', + 'Domin', + 'Meisels', + 'Sender', + 'Giovanni', + 'Sanguinetti', + 'Beary', + 'Helmstetter', + 'Joens', + 'Beaven', + 'Kines', + 'Surrency', + 'Sheilds', + 'Chamber', + 'Albarez', + 'Ambrocio', + 'Arrellano', + 'Berrigan', + 'Bookwalter', + 'Caravella', + 'Higbie', + 'Lotter', + 'Lougee', + 'Manganiello', + 'Nobriga', + 'Roorda', + 'Serr', + 'Squillace', + 'Tejera', + 'Tipping', + 'Wohler', + 'Carreto', + 'Deignan', + 'Luebbers', + 'Engelhard', + 'Hollenback', + 'Baldo', + 'Gearin', + 'Bia', + 'Figueras', + 'Lule', + 'Libert', + 'Florida', + 'Wyne', + 'Mccright', + 'Jacko', + 'Cawthorne', + 'Rhue', + 'Betton', + 'Cisse', + 'Arth', + 'Bendickson', + 'Cangialosi', + 'Coltharp', + 'Cubias', + 'Czarnik', + 'Erpelding', + 'Erway', + 'Heister', + 'Mergen', + 'Murrietta', + 'Nachman', + 'Nusser', + 'Ostrem', + 'Pei', + 'Pescatore', + 'Reim', + 'Shaull', + 'Spranger', + 'Uphold', + 'Yslas', + 'Heinold', + 'Lindemuth', + 'Redeker', + 'Rochin', + 'Wisehart', + 'Carsey', + 'Nocella', + 'Combe', + 'Thacher', + 'Hammad', + 'Bene', + 'Yelvington', + 'Mccrone', + 'Driessen', + 'Saxby', + 'Maull', + 'Jeune', + 'Amorim', + 'Degrazia', + 'Doege', + 'Flinchbaugh', + 'Goodreau', + 'Hanisch', + 'Hoaglund', + 'Imamura', + 'Lafler', + 'Linne', + 'Profeta', + 'Reifschneider', + 'Santaana', + 'Scaffidi', + 'Shreeve', + 'Stadelman', + 'Dippolito', + 'Pizzuti', + 'Rodenberg', + 'Schartz', + 'Reiger', + 'Solie', + 'Willen', + 'Atallah', + 'Wyers', + 'Harpel', + 'Cleckler', + 'Fobes', + 'Sniffen', + 'Pedroso', + 'Samara', + 'Malcomb', + 'Penry', + 'Stearn', + 'Seller', + 'Abeita', + 'Bilotti', + 'Brosky', + 'Clewell', + 'Fraijo', + 'Gaskey', + 'Goodfriend', + 'Mesaros', + 'Musch', + 'Nulph', + 'Obarr', + 'Roat', + 'Sabato', + 'Sauerwein', + 'Schum', + 'Silsby', + 'Weyenberg', + 'Corrente', + 'Egloff', + 'Kohrs', + 'Sammartino', + 'Thoennes', + 'Carmer', + 'Madura', + 'Shang', + 'Faxon', + 'Monell', + 'Laden', + 'Yousuf', + 'Mcgauley', + 'Salmond', + 'Berhane', + 'Abood', + 'Bondar', + 'Buehrer', + 'Capelli', + 'Gersten', + 'Hambly', + 'Haymaker', + 'Kosar', + 'Lahaie', + 'Lecrone', + 'Lippy', + 'Pohle', + 'Shimmel', + 'Viall', + 'Yother', + 'Deviney', + 'Kosiba', + 'Wiederholt', + 'Sivley', + 'Wheelis', + 'Kanipe', + 'Braz', + 'Peacher', + 'Quadri', + 'Hancox', + 'Paye', + 'Curlin', + 'Broden', + 'Mckeller', + 'Baltodano', + 'Baquero', + 'Bolek', + 'Brede', + 'Bulson', + 'Christmann', + 'Cisler', + 'Delio', + 'Duffee', + 'Duzan', + 'Kuschel', + 'Mohon', + 'Nedrow', + 'Sengupta', + 'Timpe', + 'Veeder', + 'Zollner', + 'Zummo', + 'Hribar', + 'Laredo', + 'Mcdivitt', + 'Nazari', + 'Davern', + 'Heizer', + 'Orejel', + 'Haggett', + 'Flore', + 'Soley', + 'Bardell', + 'Comegys', + 'Bessent', + 'Shaheed', + 'Brugman', + 'Choudhary', + 'Fehl', + 'Fogt', + 'Heckmann', + 'Iacobucci', + 'Klaver', + 'Lumbert', + 'Mussman', + 'Pierotti', + 'Pihl', + 'Sandrock', + 'Scritchfield', + 'Siefken', + 'Stavropoulos', + 'Thomley', + 'Zenker', + 'Enke', + 'Knoke', + 'Rung', + 'Mikita', + 'Kunkler', + 'Deskin', + 'Egnor', + 'Vader', + 'Allers', + 'Pi', + 'Sproull', + 'Peller', + 'Kendell', + 'Jinkins', + 'Iglehart', + 'Brookens', + 'Darrough', + 'Winzer', + 'Amenta', + 'Aughenbaugh', + 'Barnick', + 'Conaty', + 'Eichmann', + 'Gilday', + 'Guhl', + 'Koskela', + 'Makuch', + 'Osoria', + 'Pujols', + 'Reinsch', + 'Reiswig', + 'Rosebrock', + 'Sahli', + 'Seitzinger', + 'Shermer', + 'Vasbinder', + 'Zanghi', + 'Flahive', + 'Mieczkowski', + 'Osmundson', + 'Willmann', + 'Agramonte', + 'Aven', + 'Vanderzee', + 'Fraher', + 'Kannan', + 'Shira', + 'Zetina', + 'Gilden', + 'Hingle', + 'Boutros', + 'Scutt', + 'Foree', + 'Gillins', + 'Screen', + 'Birden', + 'Guinyard', + 'Berreth', + 'Bertini', + 'Bousman', + 'Butchko', + 'Caras', + 'Donoso', + 'Gavilanes', + 'Karow', + 'Kouri', + 'Rediger', + 'Rininger', + 'Rosecrans', + 'Toops', + 'Vigliotti', + 'Cancio', + 'Karger', + 'Milholland', + 'Thielke', + 'Amster', + 'Rosch', + 'Elks', + 'Vasco', + 'Doshier', + 'Belasco', + 'Lean', + 'Dickason', + 'Suitt', + 'Tipler', + 'Obey', + 'Crear', + 'Redic', + 'Agredano', + 'Amarillas', + 'Arnesen', + 'Celedon', + 'Clapsaddle', + 'Coveney', + 'Demorest', + 'Gleich', + 'Guenthner', + 'Haverland', + 'Jaffee', + 'Kusek', + 'Manni', + 'Mysliwiec', + 'Nakama', + 'Ngan', + 'Ohmer', + 'Romanoff', + 'Salaiz', + 'Zeiders', + 'Bartholow', + 'Budke', + 'Centanni', + 'Koppelman', + 'Liberti', + 'Gatta', + 'Lovegrove', + 'Maggs', + 'Malay', + 'Blind', + 'Kerman', + 'Frans', + 'Rendleman', + 'Tyrone', + 'Ambers', + 'Rambert', + 'Killings', + 'Balicki', + 'Bohac', + 'Brisbois', + 'Cervone', + 'Curtner', + 'Ertle', + 'Fantozzi', + 'Feger', + 'Fineman', + 'Garate', + 'Goldy', + 'Gudmundson', + 'Harcrow', + 'Herdt', + 'Klapp', + 'Mirra', + 'Radu', + 'Saiki', + 'Unser', + 'Valko', + 'Verhoff', + 'Candelas', + 'Ireton', + 'Vanhuss', + 'Wierman', + 'Zawistowski', + 'Geiman', + 'Mess', + 'Full', + 'Fuertes', + 'Derickson', + 'Mccole', + 'Godden', + 'Mizzell', + 'Sane', + 'Shirer', + 'Fickling', + 'Marcelle', + 'Tramble', + 'Cappelletti', + 'Catterton', + 'Champeau', + 'Czyzewski', + 'Dirusso', + 'Herget', + 'Heupel', + 'Hinchliffe', + 'Levitsky', + 'Maheu', + 'Nakao', + 'Petsche', + 'Pilkenton', + 'Raska', + 'Rief', + 'Scheidegger', + 'Schmeltzer', + 'Sherlin', + 'Skarda', + 'Strassburg', + 'Sundaram', + 'Wuertz', + 'Bonanni', + 'Montante', + 'Ottesen', + 'Nading', + 'Bram', + 'Debell', + 'Sia', + 'Latch', + 'Largen', + 'Nack', + 'Smillie', + 'Debold', + 'Bruer', + 'Steedley', + 'Mckinny', + 'Radney', + 'Amadio', + 'Bearman', + 'Canny', + 'Cansino', + 'Cupo', + 'Ekstrand', + 'Forrer', + 'Imm', + 'Kawano', + 'Klingaman', + 'Kovacevich', + 'Lukasiewicz', + 'Mcdermid', + 'Michon', + 'Mincks', + 'Piano', + 'Ronayne', + 'Schaum', + 'Sciandra', + 'Villafan', + 'Wolin', + 'Schrager', + 'Strawderman', + 'Hable', + 'Skees', + 'Persky', + 'Defore', + 'Edmonston', + 'Base', + 'Barrell', + 'Cressey', + 'Husser', + 'Matin', + 'Mckennon', + 'Barak', + 'Buffone', + 'Clemence', + 'Delaguila', + 'Eberwein', + 'Eichholz', + 'Faraone', + 'Herington', + 'Kempa', + 'Kenefick', + 'Lahaye', + 'Larusso', + 'Osterloh', + 'Pfluger', + 'Pomponio', + 'Shiu', + 'Stokke', + 'Trembly', + 'Weck', + 'Alire', + 'Babayan', + 'Hustad', + 'Stumph', + 'Zwiebel', + 'Wicke', + 'Brauch', + 'Milos', + 'Haggart', + 'Mento', + 'Kennamer', + 'Thibeau', + 'Winge', + 'Lords', + 'Debaun', + 'Haw', + 'Mould', + 'Elison', + 'Etling', + 'Froemming', + 'Ghazarian', + 'Justesen', + 'Kawai', + 'Lensing', + 'Lindhorst', + 'Poveda', + 'Rabadan', + 'Vigeant', + 'Warnken', + 'Bermel', + 'Manry', + 'Suppes', + 'Stauder', + 'Dayley', + 'Lose', + 'Tappe', + 'Harle', + 'Mcquain', + 'Bettes', + 'Carline', + 'Cordner', + 'Habeeb', + 'Sisney', + 'Kyer', + 'Bruins', + 'Prosise', + 'Molton', + 'Blye', + 'Mccuin', + 'Babler', + 'Caiazzo', + 'Cereceres', + 'Ciaramitaro', + 'Corkran', + 'Crawshaw', + 'Degan', + 'Dunlavy', + 'Gronewold', + 'Hartner', + 'Kornacki', + 'Lapolla', + 'Mountz', + 'Mumpower', + 'Orefice', + 'Prats', + 'Repasky', + 'Schlee', + 'Sekhon', + 'Stanich', + 'Yilmaz', + 'Desisto', + 'Hanko', + 'Nichter', + 'Risenhoover', + 'Tomasso', + 'Blome', + 'Carda', + 'Ebrahimi', + 'Devor', + 'Pappa', + 'Caravello', + 'Lunday', + 'Slim', + 'Praytor', + 'Pickerel', + 'Wahab', + 'Breeland', + 'Flowe', + 'Brodnax', + 'Monds', + 'Sylla', + 'Bekele', + 'Mozee', + 'Beechy', + 'Birky', + 'Dellavalle', + 'Delmastro', + 'Dematteis', + 'Eckberg', + 'Eisenbraun', + 'Englehardt', + 'Fazzio', + 'Gedney', + 'Hana', + 'Keeran', + 'Lallier', + 'Martenson', + 'Mcelheny', + 'Paar', + 'Suski', + 'Vossen', + 'Westergaard', + 'Westermann', + 'Wiemann', + 'Golz', + 'Lofquist', + 'Pracht', + 'Tifft', + 'Ruhnke', + 'Schnider', + 'How', + 'Knaggs', + 'Bleck', + 'Whitelock', + 'Berringer', + 'Clepper', + 'Birkhead', + 'Pilson', + 'Inabinet', + 'Gentles', + 'Respress', + 'Crumble', + 'Bandera', + 'Bartunek', + 'Buerkle', + 'Dulong', + 'Eisinger', + 'Favero', + 'Giusto', + 'Guisinger', + 'Kiddy', + 'Krisher', + 'Lounsberry', + 'Morikawa', + 'Mowdy', + 'Penaflor', + 'Picariello', + 'Quirion', + 'Scali', + 'Scheibel', + 'Schlitt', + 'Sermeno', + 'Thalman', + 'Barraclough', + 'Boshart', + 'Glatfelter', + 'Hjelm', + 'Horlacher', + 'Muratalla', + 'Schepp', + 'Fogerty', + 'Mulero', + 'Manner', + 'Creecy', + 'Leftridge', + 'Ancira', + 'Anselmi', + 'Blew', + 'Coykendall', + 'Dembinski', + 'Emmerling', + 'Fawver', + 'Giard', + 'Heinzen', + 'Kasson', + 'Linam', + 'Lofaro', + 'Magnotta', + 'Pitzen', + 'Ripa', + 'Skowronek', + 'Sliter', + 'Stauch', + 'Szczepaniak', + 'Yerian', + 'Baccam', + 'Berres', + 'Helstrom', + 'Kocurek', + 'Kostelecky', + 'Corkins', + 'Fesperman', + 'Gibble', + 'Liranzo', + 'Karan', + 'Lavely', + 'Yorks', + 'Lisenbee', + 'Jerger', + 'Cockroft', + 'Brodhead', + 'Weathersbee', + 'Salih', + 'Pore', + 'Melbourne', + 'Code', + 'Scotton', + 'Addie', + 'Snipe', + 'Cuffie', + 'Haynesworth', + 'Borawski', + 'Borchard', + 'Cacciola', + 'Dedic', + 'Grzyb', + 'Hecox', + 'Horacek', + 'Nierman', + 'Nofziger', + 'Raup', + 'Rissler', + 'Segler', + 'Serviss', + 'Soon', + 'Tesmer', + 'Campanaro', + 'Curnutte', + 'Rabold', + 'Schreyer', + 'Siebenaler', + 'Zenteno', + 'Deveney', + 'Kuchera', + 'Ruden', + 'Skaff', + 'Sciulli', + 'Howeth', + 'Hanly', + 'Gola', + 'Forkner', + 'Rosene', + 'Beeker', + 'Mazo', + 'Lambson', + 'Younis', + 'Batch', + 'Ayo', + 'Ackles', + 'Hansbrough', + 'Terrance', + 'Bacani', + 'Cracraft', + 'Ebben', + 'Falzarano', + 'Ferreras', + 'Hovatter', + 'Jaskiewicz', + 'Killpack', + 'Kwasniewski', + 'Mahnken', + 'Natera', + 'Noboa', + 'Rapson', + 'Raybuck', + 'Shima', + 'Vahle', + 'Sheeks', + 'Laker', + 'Krok', + 'Debo', + 'Oberly', + 'Chelf', + 'Catala', + 'Airey', + 'Osten', + 'Golay', + 'Eliot', + 'Lebert', + 'Swaggerty', + 'Hue', + 'Seavers', + 'Bomer', + 'Bouyer', + 'Andazola', + 'Blancarte', + 'Brierly', + 'Centofanti', + 'Dalesandro', + 'Dickstein', + 'Kalas', + 'Langman', + 'Mouradian', + 'Okubo', + 'Overbaugh', + 'Popek', + 'Runnion', + 'Sannes', + 'Schamber', + 'Silfies', + 'Sinko', + 'Sit', + 'Cerrillo', + 'Gayler', + 'Kauth', + 'Culkin', + 'Peers', + 'Spidle', + 'Ballon', + 'Rasmus', + 'Queenan', + 'Reynaud', + 'Ambroise', + 'Mcclenton', + 'Adelmann', + 'Avellino', + 'Fickle', + 'Humm', + 'Hussong', + 'Iturralde', + 'Kritzer', + 'Lautzenheiser', + 'Linsky', + 'Malarkey', + 'Mallia', + 'Marban', + 'Mccance', + 'Nawaz', + 'Pallone', + 'Rindfleisch', + 'Schmall', + 'Sowle', + 'Stanco', + 'Whelpley', + 'Winning', + 'Kopczynski', + 'Pickup', + 'Tsou', + 'Phebus', + 'Munter', + 'Sisko', + 'Fico', + 'Mosco', + 'Rani', + 'Kon', + 'Baggott', + 'Brom', + 'Valerius', + 'Fines', + 'Megee', + 'Salsberry', + 'Sheff', + 'Mourning', + 'Archambeault', + 'Bhatnagar', + 'Budreau', + 'Dieffenbach', + 'Gildner', + 'Hevener', + 'Hippler', + 'Jonker', + 'Keef', + 'Kirlin', + 'Litvak', + 'Liz', + 'Mulhearn', + 'Popal', + 'Samaha', + 'Schwartzberg', + 'Sotello', + 'Weiskopf', + 'Neitzke', + 'Strelow', + 'Nitsch', + 'Lynne', + 'Olver', + 'Bange', + 'Boot', + 'Carmine', + 'Bellville', + 'Lafitte', + 'Condry', + 'Mccotter', + 'Spruiell', + 'Moman', + 'Legree', + 'Bongard', + 'Deiss', + 'Devoy', + 'Gusler', + 'Ianni', + 'Kolker', + 'Lagomarsino', + 'Leier', + 'Marbut', + 'Minsky', + 'Okumura', + 'Roza', + 'Siemon', + 'Vescio', + 'Wirkus', + 'Huizinga', + 'Lazalde', + 'Morici', + 'Ungaro', + 'Detamore', + 'Meer', + 'Erman', + 'Sherrow', + 'Laforte', + 'Pellman', + 'Bostock', + 'Lender', + 'Peagler', + 'Rhem', + 'Brisbon', + 'Angers', + 'Azbill', + 'Busto', + 'Coggeshall', + 'Cucci', + 'Defino', + 'Duey', + 'Fecht', + 'Grudzinski', + 'Guarneri', + 'Huesca', + 'Kolbeck', + 'Mennella', + 'Nishi', + 'Ohaver', + 'Porth', + 'Romanello', + 'Serrata', + 'Thoele', + 'Thornsbury', + 'Ulsh', + 'Vanderlinde', + 'Weninger', + 'Bonaventura', + 'Cura', + 'Filley', + 'Grabinski', + 'Kloc', + 'Kulinski', + 'Maruca', + 'Dantoni', + 'Grohman', + 'Starbird', + 'Rach', + 'Asman', + 'Mosso', + 'Slaney', + 'Kall', + 'Nevil', + 'Blann', + 'Frear', + 'Mosey', + 'Wrench', + 'Balkcom', + 'Liburd', + 'Yeboah', + 'Abbatiello', + 'Creviston', + 'Dunivan', + 'Durnin', + 'Eckerman', + 'Fennimore', + 'Gohlke', + 'Holtan', + 'Kochevar', + 'Kraushaar', + 'Landino', + 'Maack', + 'Montefusco', + 'Noguchi', + 'Norgard', + 'Olafson', + 'Paulick', + 'Petropoulos', + 'Principato', + 'Qazi', + 'Sammis', + 'Sida', + 'Sorum', + 'Vandal', + 'Vertrees', + 'Votta', + 'Wiesman', + 'Fleagle', + 'Panaro', + 'Stolarski', + 'Ogborn', + 'Petta', + 'Annett', + 'Campas', + 'Xing', + 'Lorey', + 'Restaino', + 'Forgue', + 'Rourk', + 'Modisette', + 'Aris', + 'Vandunk', + 'Dia', + 'Alverio', + 'Ancell', + 'Bieler', + 'Bouwman', + 'Campillo', + 'Cebreros', + 'Chant', + 'Cira', + 'Cragun', + 'Geppert', + 'Hemmert', + 'Kister', + 'Luger', + 'Ojala', + 'Pfeifle', + 'Piechocki', + 'Saldarriaga', + 'Skoda', + 'Vangorden', + 'Winberry', + 'Zeeb', + 'Gehm', + 'Oshima', + 'Tofte', + 'Tsoi', + 'Delman', + 'Harsha', + 'Finton', + 'Triola', + 'Bingle', + 'Delise', + 'Westergard', + 'Aul', + 'Celia', + 'Headings', + 'Mates', + 'Coste', + 'Venus', + 'Shearn', + 'Adell', + 'Minnifield', + 'Baxa', + 'Cieri', + 'Coppens', + 'Delahoz', + 'Fratus', + 'Gribbins', + 'Homann', + 'Ilg', + 'Majchrzak', + 'Mcclard', + 'Podolak', + 'Pollan', + 'Savio', + 'Schloemer', + 'Sesma', + 'Tilbury', + 'Torrico', + 'Vanduyn', + 'Eisert', + 'Levalley', + 'Silversmith', + 'Zanoni', + 'Grupe', + 'Marmolejos', + 'Marsch', + 'Martes', + 'Gorley', + 'Furbush', + 'Hughlett', + 'Stcyr', + 'Faustin', + 'Bushaw', + 'Cerbone', + 'Equihua', + 'Fiorella', + 'Ganzer', + 'Gugel', + 'Hladik', + 'Kalra', + 'Leuenberger', + 'Lusardi', + 'Nogales', + 'Schifano', + 'Swalley', + 'Tangney', + 'Zakarian', + 'Arenz', + 'Bottcher', + 'Gervasio', + 'Peschel', + 'Potteiger', + 'Teruya', + 'Tullier', + 'Lenhard', + 'Brusseau', + 'Streett', + 'Loan', + 'Fahmy', + 'Broadfoot', + 'Shugars', + 'Wilshire', + 'Mohabir', + 'Baye', + 'Sean', + 'Caruth', + 'Arroyos', + 'Campise', + 'Capparelli', + 'Desanti', + 'Dunsworth', + 'Fasching', + 'Heldman', + 'Keagle', + 'Kulesa', + 'Lawrenz', + 'Monhollen', + 'Niekamp', + 'Nucci', + 'Ostman', + 'Salzmann', + 'Schemmel', + 'Selin', + 'Stencel', + 'Zilka', + 'Friesner', + 'Onstad', + 'Poovey', + 'Squillante', + 'Tullo', + 'Uriegas', + 'Vigilante', + 'Lasswell', + 'Navedo', + 'Dunnagan', + 'Pevey', + 'Santino', + 'Waldren', + 'Leven', + 'Stinnette', + 'Eleazer', + 'Ragas', + 'Cockfield', + 'Lafontant', + 'Babinski', + 'Balash', + 'Hadler', + 'Kantz', + 'Latini', + 'Lavy', + 'Mally', + 'Maurin', + 'Mifsud', + 'Miguez', + 'Muma', + 'Needle', + 'Orrico', + 'Zalazar', + 'Chinen', + 'Coluccio', + 'Gibboney', + 'Knapke', + 'Moczygemba', + 'Leonguerrero', + 'Punzalan', + 'Lortz', + 'Rosel', + 'Mcclaran', + 'Weatherhead', + 'Mcgurn', + 'Sanville', + 'Goe', + 'Phang', + 'Briskey', + 'Bluitt', + 'Hapner', + 'Lamadrid', + 'Leuthold', + 'Litchford', + 'Scaduto', + 'Smoyer', + 'Stonehouse', + 'Streng', + 'Susman', + 'Swoyer', + 'Tempesta', + 'Tiedt', + 'Politi', + 'Ruotolo', + 'Schwendeman', + 'Siegenthaler', + 'Streff', + 'Strite', + 'Kroft', + 'Lewey', + 'Silbert', + 'Frie', + 'Bentson', + 'Coin', + 'Lupe', + 'Mousa', + 'Syler', + 'Fester', + 'Tenny', + 'Surgeon', + 'Blowe', + 'Metellus', + 'Borboa', + 'Danker', + 'Ferch', + 'Fritzsche', + 'Gudiel', + 'Kilmartin', + 'Nieland', + 'Soffer', + 'Yescas', + 'Chappelear', + 'Hincapie', + 'Landowski', + 'Barfoot', + 'Hesketh', + 'Mittelman', + 'Escorcia', + 'Meetze', + 'Coral', + 'Huddleson', + 'Hoo', + 'Googe', + 'Munir', + 'Reine', + 'Studstill', + 'Swims', + 'Ganaway', + 'Daise', + 'Blando', + 'Bream', + 'Cangemi', + 'Dicola', + 'Difalco', + 'Gleim', + 'Goerke', + 'Jauch', + 'Lashway', + 'Mckinlay', + 'Mura', + 'Polsky', + 'Roehrich', + 'Schwalbach', + 'Tegtmeier', + 'Theel', + 'Wuthrich', + 'Yabut', + 'Zara', + 'Ardizzone', + 'Blasius', + 'Deramo', + 'Heffern', + 'Rickels', + 'Wojtas', + 'Bue', + 'Garant', + 'Kitagawa', + 'Vorhees', + 'Randa', + 'Seider', + 'Bi', + 'Womac', + 'Santerre', + 'Mesmer', + 'Bailly', + 'Argue', + 'Spidell', + 'Manu', + 'General', + 'Exantus', + 'Neloms', + 'Piggee', + 'Agcaoili', + 'Ambrosini', + 'Balleza', + 'Bhavsar', + 'Brandstetter', + 'Cascone', + 'Deyton', + 'Fette', + 'Gershman', + 'Hanni', + 'Hitchner', + 'Manthe', + 'Marengo', + 'Ockerman', + 'Pergola', + 'Ratterree', + 'Shober', + 'Swezey', + 'Vadala', + 'Waszak', + 'Wishard', + 'Zhuang', + 'Bobst', + 'Filippini', + 'Giardino', + 'Johanning', + 'Kloepfer', + 'Dahan', + 'Rahmani', + 'Hett', + 'Sha', + 'Spaugh', + 'Darner', + 'Dagen', + 'Gaier', + 'Musco', + 'Holling', + 'Keahey', + 'Merricks', + 'Nur', + 'Andrick', + 'Demauro', + 'Haury', + 'Hsiung', + 'Kotarski', + 'Kriesel', + 'Leleux', + 'Nazar', + 'Oganesyan', + 'Polivka', + 'Sansoucie', + 'Serafino', + 'Stammer', + 'Tamm', + 'Wachowiak', + 'Zinda', + 'Goedde', + 'Pedregon', + 'Snader', + 'Witczak', + 'Kem', + 'Prabhu', + 'Purtle', + 'Nola', + 'Om', + 'Finster', + 'Bryans', + 'Mateus', + 'Bour', + 'Santy', + 'Mola', + 'Guile', + 'Denne', + 'Bol', + 'Mont', + 'Perro', + 'Haji', + 'Swinger', + 'Mitchelle', + 'Creary', + 'Leeks', + 'Barsotti', + 'Bolender', + 'Dohner', + 'Federman', + 'Lancour', + 'Lueken', + 'Pettinger', + 'Rathmann', + 'Schiess', + 'Schulenberg', + 'Troyan', + 'Dafoe', + 'Delahunt', + 'Domagala', + 'Ganske', + 'Grasmick', + 'Guinther', + 'Hlavac', + 'Klumb', + 'Susko', + 'Vanhandel', + 'Burget', + 'Thaker', + 'Winker', + 'Castellucci', + 'Guerette', + 'Garde', + 'Busher', + 'Usery', + 'Braker', + 'Blan', + 'Goar', + 'Loiseau', + 'Anderberg', + 'Bamber', + 'Biagini', + 'Dack', + 'Groeneveld', + 'Habig', + 'Howk', + 'Kutsch', + 'Mcgloin', + 'Nevares', + 'Piedrahita', + 'Puffenbarger', + 'Racer', + 'Stanaland', + 'Turck', + 'Vanvleck', + 'Velardi', + 'Verhoeven', + 'Wernick', + 'Wherley', + 'Zamzow', + 'Binegar', + 'Kaluza', + 'Kudrna', + 'Marbach', + 'Schwichtenberg', + 'Chay', + 'Lanthier', + 'Balling', + 'Parcher', + 'Venner', + 'Nolette', + 'Quant', + 'Grierson', + 'Quest', + 'Level', + 'Birkner', + 'Evancho', + 'Grinde', + 'Horiuchi', + 'Hoselton', + 'Kuk', + 'Maiello', + 'Matuska', + 'Melito', + 'Northey', + 'Pallante', + 'Porzio', + 'Rad', + 'Rizzolo', + 'Thull', + 'Urenda', + 'Dalfonso', + 'Harbold', + 'Kemerer', + 'Knapton', + 'Meeder', + 'Ruckle', + 'Segui', + 'Behne', + 'Bamburg', + 'Galen', + 'Hallen', + 'Herandez', + 'Chittick', + 'Deshon', + 'Verrier', + 'Sorel', + 'Neylon', + 'Thatch', + 'Bayly', + 'Beever', + 'Galka', + 'Gruhn', + 'Gsell', + 'Happe', + 'Hovan', + 'Marter', + 'Matarese', + 'Mellema', + 'Ollila', + 'Schempp', + 'Serda', + 'Skenandore', + 'Stemper', + 'Toupin', + 'Vandeven', + 'Yauger', + 'Koenigs', + 'Mullendore', + 'Ouellet', + 'Sullenberger', + 'Julson', + 'Pelot', + 'Clamp', + 'Berte', + 'Beese', + 'Matkin', + 'Erie', + 'Rosenburg', + 'Reap', + 'Stelle', + 'Rayon', + 'Hoit', + 'Hollyfield', + 'Kindall', + 'Agent', + 'Glascoe', + 'Holts', + 'Wynder', + 'Balderston', + 'Bernardy', + 'Blehm', + 'Casebeer', + 'Emler', + 'Farrugia', + 'Guzzardo', + 'Johnsrud', + 'Maffeo', + 'Mccartan', + 'Redburn', + 'Reesman', + 'Savas', + 'Shamoon', + 'Shown', + 'Spinale', + 'Tabaka', + 'Wedell', + 'Armato', + 'Bassford', + 'Bungard', + 'Faerber', + 'Freet', + 'Oesterle', + 'Vandeberg', + 'Bacha', + 'Stemm', + 'Edgett', + 'Karrick', + 'Girten', + 'Orgill', + 'Meridith', + 'Cullom', + 'Hennington', + 'Minns', + 'Appleberry', + 'Abare', + 'Annen', + 'Beierle', + 'Berish', + 'Cracchiolo', + 'Dilullo', + 'Kehm', + 'Kuhne', + 'Modglin', + 'Norland', + 'Petruzzelli', + 'Schabel', + 'Stauffacher', + 'Villena', + 'Wageman', + 'Willden', + 'Faiella', + 'Mangiaracina', + 'Petralia', + 'Witwer', + 'Tropp', + 'Bores', + 'Burkel', + 'Stanifer', + 'Teele', + 'Cornick', + 'Credit', + 'Dorvil', + 'Bonillas', + 'Callinan', + 'Colleran', + 'Finer', + 'Krach', + 'Lubas', + 'Lutman', + 'Marien', + 'Mccort', + 'Merica', + 'Mies', + 'Nicotra', + 'Novosad', + 'Priem', + 'Ramakrishnan', + 'Zolman', + 'Deitsch', + 'Georgi', + 'Haberstroh', + 'Kofoed', + 'Kreischer', + 'Nazareno', + 'Norkus', + 'Steimle', + 'Fellin', + 'Ghanem', + 'Kosch', + 'Pages', + 'Balthazor', + 'Corte', + 'Hoh', + 'Shrewsberry', + 'Beharry', + 'Waight', + 'Leconte', + 'Clowney', + 'Tesfaye', + 'Andis', + 'Brosch', + 'Bruckman', + 'Carducci', + 'Erbes', + 'Ferreiro', + 'Gatten', + 'Heggen', + 'Kackley', + 'Klamm', + 'Korff', + 'Lehane', + 'Mech', + 'Montanari', + 'Pousson', + 'Soderholm', + 'Strey', + 'Upp', + 'Wahlen', + 'Cedrone', + 'Steuber', + 'Vonfeldt', + 'Deridder', + 'Shams', + 'Barnas', + 'Bake', + 'Brownrigg', + 'Donohoo', + 'Mccorry', + 'Spruce', + 'Masden', + 'Porchia', + 'Fofana', + 'Bless', + 'Caler', + 'Calva', + 'Carnero', + 'Chakraborty', + 'Clenney', + 'Dockendorf', + 'Dziak', + 'Errickson', + 'Ewoldt', + 'Klippel', + 'Krass', + 'Luebbe', + 'Parlett', + 'Paternostro', + 'Peterka', + 'Petitti', + 'Puthoff', + 'Wessman', + 'Brossman', + 'Glotfelty', + 'Grabau', + 'Kortz', + 'Sienko', + 'Yonan', + 'Fakhoury', + 'Bunney', + 'Sillas', + 'Guerry', + 'Sedwick', + 'Okey', + 'Virgo', + 'Babers', + 'Casali', + 'Chiquito', + 'Correnti', + 'Doverspike', + 'Fryberger', + 'Golas', + 'Golob', + 'Hufstetler', + 'Inoa', + 'Lasser', + 'Nesheim', + 'Peveto', + 'Reckner', + 'Rydzewski', + 'Shartzer', + 'Smouse', + 'Tipple', + 'Wantland', + 'Wolfert', + 'Yordy', + 'Zuleta', + 'Heimerl', + 'Mccarren', + 'Cabeza', + 'Neice', + 'Kassem', + 'Hodgen', + 'Charrier', + 'Duggar', + 'Blacksmith', + 'Cush', + 'Trunnell', + 'Laventure', + 'Salahuddin', + 'Batalla', + 'Brahmbhatt', + 'Breslow', + 'Cua', + 'Deatley', + 'Digrazia', + 'Divirgilio', + 'Falin', + 'Freiberger', + 'Gladish', + 'Holyoak', + 'Lazos', + 'Loader', + 'Mcclafferty', + 'Meloni', + 'Muhr', + 'Salzwedel', + 'Schaab', + 'Shehadeh', + 'Suresh', + 'Verdusco', + 'Younglove', + 'Damman', + 'Fulco', + 'Neikirk', + 'Laver', + 'Biro', + 'Shill', + 'Labarr', + 'Kari', + 'Mcclory', + 'Torelli', + 'Knock', + 'Dormer', + 'Papin', + 'Stoneham', + 'Weathington', + 'Albus', + 'Andel', + 'Banville', + 'Cassens', + 'Chalifoux', + 'Dellaquila', + 'Depauw', + 'Deschene', + 'Genung', + 'Greider', + 'Luhman', + 'Mastropietro', + 'Mignogna', + 'Pisarski', + 'Terrien', + 'Thomure', + 'Tornabene', + 'Beheler', + 'Chimento', + 'Engelbert', + 'Gambone', + 'Goettl', + 'Jasperson', + 'Kovalenko', + 'Infinger', + 'Timbs', + 'Dasgupta', + 'Purdon', + 'Velie', + 'Eland', + 'Ankrum', + 'Narain', + 'Mcfarling', + 'Creagh', + 'Bunyan', + 'Rattigan', + 'Reddix', + 'Aumann', + 'Beilfuss', + 'Bogosian', + 'Bramel', + 'Burlingham', + 'Cruzan', + 'Demel', + 'Dorff', + 'Figley', + 'Friesz', + 'Huffstutler', + 'Mcdaris', + 'Meinecke', + 'Moench', + 'Newville', + 'Normile', + 'Pfund', + 'Pilar', + 'Seckman', + 'Szoke', + 'Zyla', + 'Freilich', + 'Hammerle', + 'Kopel', + 'Liskey', + 'Mesina', + 'Schlicher', + 'Dalen', + 'Bettin', + 'Malanga', + 'Dern', + 'Tuckey', + 'Warder', + 'Harren', + 'Siner', + 'Mahdi', + 'Ahmann', + 'Allor', + 'Claywell', + 'Corkill', + 'Follansbee', + 'Iseman', + 'Lawter', + 'Myslinski', + 'Sauser', + 'Tornatore', + 'Bhasin', + 'Governale', + 'Karstens', + 'Klocek', + 'Stempien', + 'Petrino', + 'Kohlmeier', + 'Igou', + 'Sari', + 'Mareno', + 'Bouche', + 'Romas', + 'Urey', + 'Sprott', + 'Ponzo', + 'Nevills', + 'Affolter', + 'Alleva', + 'Allgaier', + 'Azbell', + 'Branagan', + 'Fiebig', + 'Geremia', + 'Grabert', + 'Grahl', + 'Gruwell', + 'Koebel', + 'Krauter', + 'Kuhnert', + 'Kuperman', + 'Laverdiere', + 'Leuck', + 'Masella', + 'Mierzejewski', + 'Platek', + 'Samaan', + 'Selsor', + 'Vickroy', + 'Whitenack', + 'Zanella', + 'Cavagnaro', + 'Galioto', + 'Schoeneman', + 'Zanotti', + 'Bort', + 'Alpaugh', + 'Culverhouse', + 'Perona', + 'Wheelwright', + 'Amber', + 'Bradner', + 'Sedberry', + 'Goethe', + 'Swygert', + 'Nisbett', + 'Harts', + 'Pendelton', + 'Keita', + 'Addair', + 'Anania', + 'Armagost', + 'Brumett', + 'Butala', + 'Celmer', + 'Forquer', + 'Hagadorn', + 'Jalomo', + 'Koranda', + 'Lemmond', + 'Liske', + 'Mcglamery', + 'Ramiro', + 'Tickner', + 'Toso', + 'Tosti', + 'Beerbower', + 'Bichler', + 'Buege', + 'Cadotte', + 'Chiong', + 'Romberger', + 'Mandarino', + 'Deter', + 'Wallack', + 'Bligh', + 'Harer', + 'Terral', + 'Hobert', + 'Doren', + 'Affleck', + 'Marquess', + 'Lewton', + 'Covel', + 'Reff', + 'Gowins', + 'Claybrooks', + 'Artiles', + 'Brunelli', + 'Campusano', + 'Deshaies', + 'Elpers', + 'Fait', + 'Heathcote', + 'Katayama', + 'Landreneau', + 'Nardelli', + 'Padovano', + 'Pendry', + 'Santillano', + 'Ubaldo', + 'Wurz', + 'Bathke', + 'Fillers', + 'Reitano', + 'Patrone', + 'Mountford', + 'Farran', + 'Burdo', + 'Danish', + 'Windell', + 'Amrine', + 'Pilgreen', + 'Pross', + 'Bowery', + 'Girdner', + 'Stockley', + 'Chisom', + 'Bigos', + 'Cavallero', + 'Choma', + 'Chorba', + 'Doubek', + 'Eynon', + 'Fitzmorris', + 'Gergely', + 'Hilsabeck', + 'Hime', + 'Kafer', + 'Kilday', + 'Lairson', + 'Mccanless', + 'Meenan', + 'Mossburg', + 'Muscato', + 'Raap', + 'Ramp', + 'Reali', + 'Reinard', + 'Rivadeneira', + 'Schwenn', + 'Serbin', + 'Soeder', + 'Wagle', + 'Jablonowski', + 'Vanni', + 'Grapes', + 'Hilleary', + 'Mondor', + 'Natalie', + 'Seat', + 'Heming', + 'Waide', + 'Haverly', + 'Eva', + 'Marshman', + 'Mais', + 'Portlock', + 'Scoby', + 'Sharps', + 'Buday', + 'Bumbalough', + 'Burback', + 'Carano', + 'Eustis', + 'Flaim', + 'Fraticelli', + 'Grimme', + 'Heape', + 'Hoaglin', + 'Kreuser', + 'Odgers', + 'Pastorius', + 'Pavek', + 'Rogoff', + 'Skorupski', + 'Stene', + 'Tomasino', + 'Varble', + 'Vasek', + 'Woolums', + 'Arcaro', + 'Graley', + 'Larkey', + 'Ortlieb', + 'Piccone', + 'Verhey', + 'Inch', + 'Laroe', + 'Brockmeier', + 'Familia', + 'Soll', + 'Duplechin', + 'Blevens', + 'Gell', + 'Hipkins', + 'Kleinpeter', + 'Swindall', + 'Sabir', + 'Kinloch', + 'Muldrew', + 'Clausell', + 'Bouch', + 'Casciano', + 'Dewhirst', + 'Draney', + 'Fourman', + 'Fuente', + 'Ganci', + 'Gentzler', + 'Gerhold', + 'Ingoglia', + 'Jerabek', + 'Keisling', + 'Larivee', + 'Negro', + 'Pelchat', + 'Quilty', + 'Reinig', + 'Rubeck', + 'Rudick', + 'Rulli', + 'Spagnoli', + 'Wiltsie', + 'Vitolo', + 'Neuhauser', + 'Khurana', + 'Vint', + 'Kant', + 'Nead', + 'Deroy', + 'Ransford', + 'Stromer', + 'Buley', + 'Bloxom', + 'Rieves', + 'Bastos', + 'Deckman', + 'Duenes', + 'Hessling', + 'Kresse', + 'Langdale', + 'Penberthy', + 'Polyak', + 'Sagun', + 'Salehi', + 'Sas', + 'Soja', + 'Spieth', + 'Verhulst', + 'Walen', + 'Woodling', + 'Acierno', + 'Bergsma', + 'Biskup', + 'Buonomo', + 'Gores', + 'Koffman', + 'Redder', + 'Ishak', + 'Billow', + 'Ratledge', + 'Widder', + 'Margerum', + 'Bussing', + 'Caccamo', + 'Carozza', + 'Cwik', + 'Forner', + 'Goeden', + 'Greninger', + 'Hartenstein', + 'Hermida', + 'Krutz', + 'Kubes', + 'Kulow', + 'Lynott', + 'Mank', + 'Meinders', + 'Mikrut', + 'Moots', + 'Patek', + 'Pogorzelski', + 'Reinstein', + 'Ruiter', + 'Rupard', + 'Salvia', + 'Sissom', + 'Sligar', + 'Spendlove', + 'Vian', + 'Wissing', + 'Witucki', + 'Brossart', + 'Warhurst', + 'Staron', + 'Gilly', + 'Borck', + 'Mccarn', + 'Stanbery', + 'Aydelotte', + 'Etters', + 'Rho', + 'Menzer', + 'Knoble', + 'Luallen', + 'Meda', + 'Myre', + 'Nevils', + 'Seide', + 'Rouser', + 'Bernas', + 'Bressette', + 'Dohn', + 'Domina', + 'Filion', + 'Fossen', + 'Grunder', + 'Hofland', + 'Larranaga', + 'Launius', + 'Lento', + 'Mohrmann', + 'Papenfuss', + 'Polcyn', + 'Pollina', + 'Reinheimer', + 'Rueb', + 'Sacher', + 'Sauseda', + 'Whitwell', + 'Caspers', + 'Dejager', + 'Kastelic', + 'Kildow', + 'Sappenfield', + 'Schultes', + 'Tucciarone', + 'Gogan', + 'Sarti', + 'Percle', + 'Cagney', + 'Wasley', + 'Getts', + 'Sahm', + 'Brandle', + 'Osbon', + 'Febres', + 'Billett', + 'Pall', + 'Spearing', + 'Thursby', + 'Junious', + 'Allenbaugh', + 'Calamia', + 'Cregan', + 'Hostettler', + 'Leete', + 'Pirrone', + 'Ploeger', + 'Revak', + 'Sarlo', + 'Sayavong', + 'Schlichter', + 'Shonkwiler', + 'Soots', + 'Spak', + 'Thien', + 'Torgeson', + 'Urbanczyk', + 'Vredenburg', + 'Wormuth', + 'Yankovich', + 'Badertscher', + 'Holewinski', + 'Kalinoski', + 'Kwasny', + 'Neidert', + 'Remmel', + 'Uram', + 'Zettlemoyer', + 'Sanna', + 'Walthers', + 'Kinkaid', + 'Rummage', + 'Vane', + 'Morgen', + 'Stum', + 'Ainsley', + 'Mckelvie', + 'Barbin', + 'Shariff', + 'Blanchett', + 'Mayon', + 'Broadie', + 'Millien', + 'Azzarello', + 'Bocock', + 'Bohlander', + 'Brennecke', + 'Daman', + 'Dixit', + 'Goth', + 'Kocur', + 'Koslow', + 'Loncar', + 'Narez', + 'Oleksy', + 'Ouderkirk', + 'Rathe', + 'Sandmann', + 'Scarpino', + 'Siegman', + 'Soloway', + 'Tomeo', + 'Vantuyl', + 'Benesch', + 'Doornbos', + 'Gisler', + 'Nistler', + 'Pelzel', + 'Piecuch', + 'Schweiss', + 'Zieba', + 'Domangue', + 'Curti', + 'Iams', + 'Viger', + 'Sandefer', + 'Maybury', + 'Haneline', + 'Shappell', + 'Charlier', + 'Belardo', + 'Lynk', + 'Ocain', + 'Ismael', + 'Blacksher', + 'Lesesne', + 'Blash', + 'Fantroy', + 'Bucciarelli', + 'Deruiter', + 'Fetner', + 'Filla', + 'Frontera', + 'Furlan', + 'Goepfert', + 'Gorsline', + 'Gugino', + 'Kleis', + 'Kriger', + 'Lebarron', + 'Lesnick', + 'Losano', + 'Macquarrie', + 'Marczak', + 'Mazariego', + 'Moraes', + 'Murano', + 'Myint', + 'Philley', + 'Ruffalo', + 'Salyards', + 'Swab', + 'Trester', + 'Vlcek', + 'Abramo', + 'Kaczmarski', + 'Mastronardi', + 'Lafont', + 'Tomerlin', + 'Mchan', + 'Blanda', + 'Deandrade', + 'Klien', + 'Meno', + 'Maia', + 'Durall', + 'Lansdowne', + 'Cones', + 'Adley', + 'Taffe', + 'Ikard', + 'Sylve', + 'Bartok', + 'Farler', + 'Farnworth', + 'Gookin', + 'Guijarro', + 'Hazan', + 'Hosterman', + 'Klees', + 'Knust', + 'Leadingham', + 'Lefeber', + 'Maisch', + 'Muchmore', + 'Pini', + 'Polinsky', + 'Quakenbush', + 'Rought', + 'Ruta', + 'Tingen', + 'Urness', + 'Valade', + 'Wadle', + 'Hietala', + 'Hockenbury', + 'Ivanoff', + 'Mcevers', + 'Miyazaki', + 'Druckenmiller', + 'Neisler', + 'Vroom', + 'Berland', + 'Rizor', + 'Caris', + 'Jenison', + 'Folmer', + 'Si', + 'Pulling', + 'Houge', + 'Snuggs', + 'Enis', + 'Peeks', + 'Stacker', + 'Destin', + 'Ojo', + 'Barraco', + 'Childree', + 'Ciszewski', + 'Dicenzo', + 'Gowing', + 'Granquist', + 'Kapinos', + 'Khalili', + 'Kienitz', + 'Konrath', + 'Kosa', + 'Schilz', + 'Sealock', + 'Soucek', + 'Stefanko', + 'Trow', + 'Udy', + 'Fricano', + 'Hunnewell', + 'Sieler', + 'Stranahan', + 'Thammavongsa', + 'Zettel', + 'Cutrell', + 'Balter', + 'Clavel', + 'Thibert', + 'Ondo', + 'Senna', + 'Kun', + 'Maximo', + 'Wares', + 'Caldeira', + 'Furgerson', + 'Franklyn', + 'Christophe', + 'Bady', + 'Blanken', + 'Boike', + 'Cuen', + 'Davidian', + 'Glauser', + 'Gleave', + 'Guzy', + 'Halleck', + 'Kempfer', + 'Kenkel', + 'Kloth', + 'Knable', + 'Mcenery', + 'Pizzolato', + 'Schryver', + 'Seminara', + 'Shenoy', + 'Somera', + 'Stroop', + 'Weirick', + 'Yatsko', + 'Evanko', + 'Koegel', + 'Lastinger', + 'Schrenk', + 'Vitullo', + 'Holste', + 'Susa', + 'Pedley', + 'Cove', + 'Levett', + 'Gillyard', + 'Boeding', + 'Delpozo', + 'Denoyer', + 'Farese', + 'Floro', + 'Gavina', + 'Hargus', + 'Kisiel', + 'Konig', + 'Krotz', + 'Lundblad', + 'Masoner', + 'Mumper', + 'Nolf', + 'Sandgren', + 'Schussler', + 'Shallcross', + 'Singhal', + 'Standen', + 'Teta', + 'Vacanti', + 'Yokota', + 'Borski', + 'Filice', + 'Frankum', + 'Kleinsmith', + 'Plauche', + 'Spohr', + 'Goya', + 'Rosensteel', + 'Srey', + 'Touhey', + 'Launer', + 'Dome', + 'Mossey', + 'Mclay', + 'Sturgess', + 'Demond', + 'Buren', + 'Millin', + 'Riddles', + 'Arps', + 'Dugar', + 'Carradine', + 'Brasseur', + 'Burchill', + 'Champoux', + 'Chojnowski', + 'Cyphert', + 'Devincentis', + 'Donze', + 'Gaspari', + 'Harshberger', + 'Merchan', + 'Mulgrew', + 'Parma', + 'Pasqua', + 'Pierpoint', + 'Rozeboom', + 'Rumery', + 'Stahle', + 'Stierwalt', + 'Swander', + 'Tiegs', + 'Trabucco', + 'Withington', + 'Frericks', + 'Kilman', + 'Locastro', + 'Samonte', + 'Sanko', + 'Wisman', + 'Flecha', + 'Coplan', + 'Zafra', + 'Art', + 'Maxam', + 'Cavaness', + 'Willi', + 'Vanliew', + 'Fresh', + 'Bauserman', + 'Bergemann', + 'Buchler', + 'Curbow', + 'Dimascio', + 'Einstein', + 'Favila', + 'Galeno', + 'Granat', + 'Halteman', + 'Janczak', + 'Janicek', + 'Jundt', + 'Karren', + 'Modesitt', + 'Provance', + 'Reasons', + 'Riveron', + 'Salts', + 'Salvino', + 'Sawhney', + 'Shallenberger', + 'Sirk', + 'Tylka', + 'Baumler', + 'Mcmenamy', + 'Territo', + 'Thackeray', + 'Much', + 'Papageorge', + 'Rynders', + 'Bacigalupo', + 'Fulwider', + 'Hendricksen', + 'Lepre', + 'Mangel', + 'Dering', + 'Soda', + 'Bazar', + 'Dinning', + 'Portera', + 'Schatzman', + 'Kernodle', + 'Bashford', + 'Ferrebee', + 'Cortner', + 'Sanker', + 'Livings', + 'Jemmott', + 'Arzaga', + 'Cihak', + 'Cobarrubias', + 'Coey', + 'Coutinho', + 'Deneau', + 'Droll', + 'Hickel', + 'Hillmann', + 'Kitto', + 'Lefebre', + 'Lev', + 'Mato', + 'Mcomber', + 'Norlin', + 'Renstrom', + 'Rhyner', + 'Sacca', + 'Sangha', + 'Sutor', + 'Dwire', + 'Huyser', + 'Kressin', + 'Moilanen', + 'Picado', + 'Schmidlin', + 'Albor', + 'Zaldana', + 'Failor', + 'Dubberly', + 'Youse', + 'Mohiuddin', + 'Shiel', + 'Loran', + 'Hamme', + 'Castine', + 'Lanum', + 'Mcelderry', + 'Riggsbee', + 'Madkins', + 'Abts', + 'Bekker', + 'Boccio', + 'Florin', + 'Lienemann', + 'Madara', + 'Manganello', + 'Mcfetridge', + 'Medsker', + 'Minish', + 'Roberg', + 'Sajdak', + 'Schwall', + 'Sedivy', + 'Suto', + 'Wieberg', + 'Catherman', + 'Ficker', + 'Leckrone', + 'Lieder', + 'Rodak', + 'Tomek', + 'Everard', + 'Spong', + 'Glacken', + 'Polka', + 'Aley', + 'Farro', + 'Stanwood', + 'Petter', + 'Desrosier', + 'Kerl', + 'Goslee', + 'Burston', + 'Pennywell', + 'Birchard', + 'Federer', + 'Flicker', + 'Frangos', + 'Korhonen', + 'Kozikowski', + 'Kyger', + 'Mccoskey', + 'Standing', + 'Terada', + 'Trierweiler', + 'Trupiano', + 'Urbanowicz', + 'Viegas', + 'Ybarbo', + 'Brinlee', + 'Daddona', + 'Deisher', + 'Schwieger', + 'Farless', + 'Slaght', + 'Jarvie', + 'Hunkins', + 'Barrack', + 'Bisset', + 'Bruley', + 'Molen', + 'Milas', + 'Matts', + 'Wickware', + 'Timbers', + 'Minus', + 'Kennebrew', + 'Boorman', + 'Faughn', + 'Feight', + 'Githens', + 'Hazelrigg', + 'Hutzell', + 'Klang', + 'Kogler', + 'Lechtenberg', + 'Malachowski', + 'Orsburn', + 'Retz', + 'Saban', + 'Tak', + 'Underdahl', + 'Veldman', + 'Virnig', + 'Wanat', + 'Achord', + 'Drenth', + 'Heibel', + 'Hendee', + 'Raiche', + 'Saunier', + 'Wertheim', + 'Forand', + 'Stathis', + 'Raider', + 'Cassaro', + 'Cly', + 'Hagey', + 'Moad', + 'Rhody', + 'Fogler', + 'Hellen', + 'Sweezy', + 'Farid', + 'Suddreth', + 'Kenneth', + 'Pindell', + 'Corney', + 'Monsanto', + 'Laye', + 'Lingard', + 'Armwood', + 'Asif', + 'Axley', + 'Barkan', + 'Bittel', + 'Boesen', + 'Camilli', + 'Champa', + 'Dauenhauer', + 'Ehrmann', + 'Gangl', + 'Gatrell', + 'Gehret', + 'Hankel', + 'Kalbach', + 'Kessell', + 'Khatoon', + 'Lanese', + 'Manco', + 'Masteller', + 'Pruner', + 'Remmert', + 'Valasek', + 'Vater', + 'Yurick', + 'Zavalza', + 'Biesecker', + 'Frankenberg', + 'Hovorka', + 'Poissant', + 'Neises', + 'Moog', + 'Hadad', + 'Wittenburg', + 'Devere', + 'Hynds', + 'Sparkes', + 'Brailey', + 'Addo', + 'Accetta', + 'Altschuler', + 'Amescua', + 'Corredor', + 'Didonna', + 'Jencks', + 'Keady', + 'Keidel', + 'Mancebo', + 'Matusiak', + 'Rakoczy', + 'Reamy', + 'Sardella', + 'Slotnick', + 'Fotheringham', + 'Gettman', + 'Kunzler', + 'Manganaro', + 'Manygoats', + 'Huelskamp', + 'Newsham', + 'Kohen', + 'Cong', + 'Goulden', + 'Timmers', + 'Aderhold', + 'Shinall', + 'Cowser', + 'Uzzle', + 'Harps', + 'Balster', + 'Baringer', + 'Bechler', + 'Billick', + 'Chenard', + 'Ditta', + 'Fiallos', + 'Kampe', + 'Kretzschmar', + 'Manukyan', + 'Mcbreen', + 'Mcmanigal', + 'Miko', + 'Mol', + 'Orrego', + 'Penalosa', + 'Ronco', + 'Thum', + 'Tupa', + 'Vittitow', + 'Wierzba', + 'Gavitt', + 'Hampe', + 'Kowalkowski', + 'Neuroth', + 'Sterkel', + 'Herling', + 'Boldman', + 'Camus', + 'Drier', + 'Arcia', + 'Feagans', + 'Thompsen', + 'Maka', + 'Villalona', + 'Bonito', + 'Buist', + 'Dato', + 'Yankey', + 'Daluz', + 'Hollands', + 'Durio', + 'Bradly', + 'Daffin', + 'Chhabra', + 'Dettling', + 'Dolinger', + 'Flenniken', + 'Henrichsen', + 'Laduca', + 'Lashomb', + 'Leick', + 'Luchini', + 'Mcmanaman', + 'Minkoff', + 'Nobbe', + 'Oyster', + 'Quintela', + 'Robar', + 'Sakurai', + 'Solak', + 'Stolt', + 'Taddei', + 'Puopolo', + 'Schwarzkopf', + 'Stango', + 'Mcparland', + 'Schembri', + 'Standefer', + 'Dayan', + 'Sculley', + 'Bhuiyan', + 'Delauder', + 'Harrity', + 'Bree', + 'Haste', + 'Mcbay', + 'Garmany', + 'Maison', + 'Common', + 'Hanton', + 'Aigner', + 'Aliaga', + 'Boeve', + 'Cromie', + 'Demick', + 'Filipowicz', + 'Frickey', + 'Garrigus', + 'Heindl', + 'Hilmer', + 'Homeyer', + 'Lanterman', + 'Larch', + 'Masci', + 'Minami', + 'Palmiter', + 'Rufener', + 'Saal', + 'Sarmento', + 'Seewald', + 'Sestito', + 'Somarriba', + 'Sparano', + 'Vorce', + 'Wombles', + 'Zarr', + 'Antonson', + 'Bruzzese', + 'Chillemi', + 'Dannunzio', + 'Hogrefe', + 'Mastandrea', + 'Moynahan', + 'Wangerin', + 'Wedeking', + 'Ziobro', + 'Flegel', + 'Axsom', + 'Buzby', + 'Slowey', + 'Cuebas', + 'App', + 'Dar', + 'Robers', + 'Elting', + 'Demus', + 'Finkley', + 'Taborn', + 'Balogun', + 'Binstock', + 'Gebel', + 'Hinnenkamp', + 'Kosta', + 'Lamphear', + 'Linhares', + 'Luzader', + 'Mcconathy', + 'Motl', + 'Mroczkowski', + 'Reznicek', + 'Rieken', + 'Sadlowski', + 'Schlink', + 'Snuffer', + 'Tep', + 'Vaske', + 'Whisner', + 'Amesquita', + 'Demler', + 'Macdonell', + 'Rajala', + 'Sandate', + 'Kolk', + 'Bickerton', + 'Dugal', + 'Kirtland', + 'Neilan', + 'Doughman', + 'Crye', + 'Depena', + 'Quire', + 'Hafeez', + 'Rosse', + 'Devon', + 'Deboe', + 'Kitchings', + 'Blackett', + 'Acey', + 'Mcculler', + 'Obie', + 'Pleas', + 'Lurry', + 'Abid', + 'Bierlein', + 'Boisclair', + 'Cabanilla', + 'Celano', + 'Conrow', + 'Deeley', + 'Frankhouser', + 'Janowiak', + 'Jarchow', + 'Mcnicol', + 'Peixoto', + 'Pompeo', + 'Reitmeyer', + 'Scalera', + 'Schnorr', + 'Sideris', + 'Solesbee', + 'Stejskal', + 'Strole', + 'Tosto', + 'Wenke', + 'Dombek', + 'Gottschall', + 'Halbur', + 'Kuchler', + 'Kuyper', + 'Wruck', + 'Lorenc', + 'Search', + 'Chohan', + 'Monda', + 'Clowes', + 'Farson', + 'Rhoad', + 'Clavin', + 'Ramus', + 'Hayley', + 'Dolley', + 'Menton', + 'Dejarnett', + 'Challenger', + 'Branner', + 'Shed', + 'Dada', + 'Flewellen', + 'Volcy', + 'Allphin', + 'Barberena', + 'Bencivenga', + 'Bienkowski', + 'Bossi', + 'Corsini', + 'Dardis', + 'Falconi', + 'Fitzhenry', + 'Gaglione', + 'Handlin', + 'Kainz', + 'Lorge', + 'Nase', + 'Pavich', + 'Perelman', + 'Shanafelt', + 'Towsley', + 'Weill', + 'Zollars', + 'Appelt', + 'Cannizzo', + 'Carrubba', + 'Detar', + 'Dobrzynski', + 'Hashman', + 'Maassen', + 'Mccullagh', + 'Rettinger', + 'Roediger', + 'Rybolt', + 'Savoca', + 'Wortmann', + 'Boria', + 'Mairs', + 'Stream', + 'Larmore', + 'Sama', + 'Graden', + 'Hollinshead', + 'Mandy', + 'Gidney', + 'Demming', + 'Alexandra', + 'Caleb', + 'Abdullahi', + 'Cabal', + 'Dikeman', + 'Ellenbecker', + 'Fosnaugh', + 'Funck', + 'Heidorn', + 'Housden', + 'Ilic', + 'Illescas', + 'Kohlmann', + 'Lagman', + 'Larez', + 'Penafiel', + 'Pense', + 'Ragonese', + 'Reitan', + 'Shetterly', + 'Trapasso', + 'Zank', + 'Zecca', + 'Grisanti', + 'Hemker', + 'Mascolo', + 'Muhlenkamp', + 'Riemann', + 'Schindel', + 'Uncapher', + 'Zelman', + 'Koper', + 'Byrn', + 'Calzadilla', + 'Dilly', + 'Beiser', + 'Maller', + 'Bagg', + 'Winnick', + 'Sillman', + 'Bilton', + 'Esmond', + 'Sconyers', + 'Lemma', + 'Geralds', + 'Lazare', + 'Threats', + 'Accurso', + 'Boitnott', + 'Calcagni', + 'Chavera', + 'Corda', + 'Delisio', + 'Demont', + 'Eichel', + 'Faulds', + 'Ficek', + 'Gappa', + 'Graci', + 'Hammaker', + 'Heino', + 'Katcher', + 'Keslar', + 'Larsh', + 'Lashua', + 'Leising', + 'Magri', + 'Manbeck', + 'Mcwatters', + 'Mixer', + 'Moder', + 'Noori', + 'Pallo', + 'Pfingsten', + 'Plett', + 'Prehn', + 'Reyburn', + 'Savini', + 'Sebek', + 'Thang', + 'Lemberg', + 'Xiang', + 'Stiegler', + 'Groman', + 'Bowlen', + 'Grignon', + 'Morren', + 'Dini', + 'Mcaulay', + 'Ngu', + 'Bethell', + 'Warring', + 'Belyeu', + 'Ramcharan', + 'Mcjunkins', + 'Alms', + 'Ayub', + 'Brem', + 'Dresen', + 'Flori', + 'Geesaman', + 'Haugan', + 'Heppler', + 'Hermance', + 'Korinek', + 'Lograsso', + 'Madriaga', + 'Milbrath', + 'Radwan', + 'Riemersma', + 'Rivett', + 'Roggenbuck', + 'Stefanick', + 'Storment', + 'Ziegenfuss', + 'Blackhurst', + 'Daquila', + 'Maruska', + 'Rybka', + 'Schweer', + 'Tandon', + 'Hersman', + 'Galster', + 'Lemp', + 'Hantz', + 'Enderson', + 'Marchal', + 'Conly', + 'Bali', + 'Canaan', + 'Anstead', + 'Savary', + 'Andy', + 'Tisdell', + 'Livas', + 'Grinage', + 'Afanador', + 'Alviso', + 'Aracena', + 'Denio', + 'Dentremont', + 'Eldreth', + 'Gravois', + 'Huebsch', + 'Kalbfleisch', + 'Labree', + 'Mones', + 'Reitsma', + 'Schnapp', + 'Seek', + 'Shuping', + 'Tortorice', + 'Viscarra', + 'Wahlers', + 'Wittner', + 'Yake', + 'Zamani', + 'Carriveau', + 'Delage', + 'Gargan', + 'Goldade', + 'Golec', + 'Lapage', + 'Meinhart', + 'Mierzwa', + 'Riggenbach', + 'Schloesser', + 'Sedam', + 'Winkels', + 'Woldt', + 'Beckers', + 'Teach', + 'Feagan', + 'Booe', + 'Slates', + 'Bears', + 'Market', + 'Moone', + 'Verdun', + 'Ibe', + 'Jeudy', + 'Agudo', + 'Brisendine', + 'Casillo', + 'Chalupa', + 'Daversa', + 'Fissel', + 'Fleites', + 'Giarratano', + 'Glackin', + 'Granzow', + 'Hawver', + 'Hayashida', + 'Hovermale', + 'Huaman', + 'Jezek', + 'Lansdell', + 'Loughery', + 'Niedzielski', + 'Orellano', + 'Pebley', + 'Rojek', + 'Tomic', + 'Yellen', + 'Zerkle', + 'Boettner', + 'Decook', + 'Digilio', + 'Dinsdale', + 'Germer', + 'Kleve', + 'Marcinek', + 'Mendicino', + 'Pehl', + 'Revoir', + 'Osmun', + 'Bahner', + 'Shone', + 'Howald', + 'Kanode', + 'Amari', + 'Enix', + 'Levene', + 'Joffrion', + 'Lenis', + 'Carmicheal', + 'Njoku', + 'Coffel', + 'Ditter', + 'Grupp', + 'Kabel', + 'Kanzler', + 'Konop', + 'Lupi', + 'Mautz', + 'Mccahill', + 'Perella', + 'Perich', + 'Rion', + 'Ruvolo', + 'Torio', + 'Vipperman', + 'Bentivegna', + 'Formanek', + 'Smet', + 'Tarquinio', + 'Wesche', + 'Dearinger', + 'Makara', + 'Duba', + 'Iser', + 'Nicklow', + 'Wignall', + 'Wanger', + 'Goda', + 'Huckstep', + 'Basse', + 'Debruhl', + 'Hainey', + 'Damour', + 'Ebbs', + 'Armond', + 'Ewings', + 'Rease', + 'Okoye', + 'Arentz', + 'Baack', + 'Bellantoni', + 'Buckholz', + 'Cirigliano', + 'Colletta', + 'Dutka', + 'Everingham', + 'Gilardi', + 'Hudelson', + 'Klimczak', + 'Kneip', + 'Papaleo', + 'Peregrino', + 'Piechowski', + 'Prucha', + 'Ryburn', + 'Scholle', + 'Scholtes', + 'Socarras', + 'Wrightsman', + 'Yum', + 'Campau', + 'Dwinell', + 'Haupert', + 'Lotspeich', + 'Madar', + 'Casa', + 'Michals', + 'Rainier', + 'Tenpenny', + 'Lakeman', + 'Spadoni', + 'Cantrelle', + 'Mangal', + 'Chachere', + 'Swoope', + 'Carwell', + 'Voltaire', + 'Durrah', + 'Roulhac', + 'Aboytes', + 'Apuzzo', + 'Bielinski', + 'Bollenbacher', + 'Borjon', + 'Croak', + 'Dansie', + 'Espin', + 'Euceda', + 'Garone', + 'Garthwaite', + 'Hata', + 'Heu', + 'Hogenson', + 'Jahner', + 'Keesey', + 'Kotas', + 'Labrake', + 'Laitinen', + 'Laumann', + 'Miske', + 'Nickless', + 'Onishi', + 'Setty', + 'Shinnick', + 'Takayama', + 'Tassinari', + 'Tribe', + 'Bowdish', + 'Friesenhahn', + 'Hoffarth', + 'Wachowski', + 'Gudgel', + 'Gautney', + 'Matar', + 'Ellenberg', + 'Inghram', + 'Bevil', + 'Rasul', + 'Niblack', + 'Perkin', + 'Goring', + 'Potier', + 'Bachrach', + 'Bozza', + 'Budz', + 'Devens', + 'Ditzel', + 'Drahos', + 'Ducat', + 'Fahrner', + 'Friedline', + 'Geurin', + 'Goodenow', + 'Greenfeld', + 'Grunow', + 'Ingber', + 'Kashani', + 'Kochman', + 'Kozub', + 'Kukuk', + 'Leppo', + 'Liew', + 'Metheney', + 'Molony', + 'Montemurro', + 'Neiss', + 'Postlethwait', + 'Quaglia', + 'Ruszkowski', + 'Shertzer', + 'Titone', + 'Waldmann', + 'Wenninger', + 'Wheeland', + 'Zorich', + 'Mervine', + 'Weatherholtz', + 'Brotman', + 'Malenfant', + 'Nong', + 'Rogness', + 'Dibert', + 'Gallahan', + 'Gange', + 'Chilcott', + 'Axt', + 'Wiler', + 'Jacot', + 'Ory', + 'Abdon', + 'Fenter', + 'Bryars', + 'Ramroop', + 'Jacox', + 'Mainer', + 'Figures', + 'Alig', + 'Bires', + 'Cassata', + 'Cholewa', + 'Dispenza', + 'Eckmann', + 'Gauer', + 'Gloor', + 'Hattori', + 'Huster', + 'Kopplin', + 'Krugman', + 'Lancon', + 'Ledin', + 'Limb', + 'Marentes', + 'Minges', + 'Monacelli', + 'Monteon', + 'Naslund', + 'Nitsche', + 'Rapozo', + 'Rimkus', + 'Schwerdtfeger', + 'Vandenbos', + 'Balandran', + 'Biehn', + 'Briody', + 'Hackmann', + 'Kalka', + 'Keranen', + 'Lortie', + 'Mannella', + 'Shiffler', + 'Stempel', + 'Takaki', + 'Tomassi', + 'Reidel', + 'Ciprian', + 'Penza', + 'Vite', + 'Cormany', + 'Derousse', + 'Beus', + 'Shurley', + 'Courtwright', + 'Donna', + 'Karney', + 'Keats', + 'Harron', + 'Stjacques', + 'Regester', + 'Stoke', + 'Garron', + 'Sulaiman', + 'Fusilier', + 'Hence', + 'Altidor', + 'Rollerson', + 'Anfinson', + 'Badua', + 'Balmaceda', + 'Bringman', + 'Bystrom', + 'Goffinet', + 'Guindon', + 'Hilling', + 'Makepeace', + 'Mooradian', + 'Muzquiz', + 'Newcom', + 'Perrella', + 'Postlewait', + 'Raetz', + 'Riveros', + 'Saephanh', + 'Scharer', + 'Sheeder', + 'Sitar', + 'Umlauf', + 'Voegeli', + 'Yurkovich', + 'Chaudhari', + 'Chianese', + 'Clonch', + 'Gasparini', + 'Giambalvo', + 'Gindlesperger', + 'Rauen', + 'Riegert', + 'Collingsworth', + 'Stief', + 'Zeisler', + 'Kirsten', + 'Vessey', + 'Scherman', + 'Ledwith', + 'Goudie', + 'Ayre', + 'Salome', + 'Knoles', + 'Munyan', + 'Corbet', + 'Hagewood', + 'Humphry', + 'Bernardez', + 'Drummonds', + 'Lide', + 'Veals', + 'Andolina', + 'Anzaldo', + 'Aufiero', + 'Bakshi', + 'Berdan', + 'Birrell', + 'Colcord', + 'Dutro', + 'Eisenhour', + 'Falgoust', + 'Foertsch', + 'Forlenza', + 'Harroun', + 'Kurtenbach', + 'Livesey', + 'Luka', + 'Manseau', + 'Mcdaid', + 'Miska', + 'Overley', + 'Panzica', + 'Reish', + 'Riolo', + 'Roseland', + 'Shenberger', + 'Splinter', + 'Strupp', + 'Sturgell', + 'Swatzell', + 'Totherow', + 'Villarroel', + 'Wenig', + 'Zimny', + 'Brunetto', + 'Hiester', + 'Kasinger', + 'Laverde', + 'Mihalek', + 'Aquila', + 'Moreton', + 'Collums', + 'Ergle', + 'Keziah', + 'Bourbon', + 'Scaff', + 'Leamy', + 'Sublette', + 'Winkley', + 'Arlington', + 'Cuffe', + 'Guity', + 'Mcmickle', + 'Summerour', + 'Baggerly', + 'Biltz', + 'Calma', + 'Dephillips', + 'Graffam', + 'Holsopple', + 'Izumi', + 'Joerger', + 'Kesselman', + 'Kingdon', + 'Kinkel', + 'Knezevich', + 'Liebler', + 'Maceda', + 'Qualey', + 'Robeck', + 'Sciarrino', + 'Sooy', + 'Stahly', + 'Stieglitz', + 'Strike', + 'Unwin', + 'Urizar', + 'Volmer', + 'Winterstein', + 'Aronov', + 'Czyz', + 'Marrazzo', + 'Seagren', + 'Wiegmann', + 'Yearsley', + 'Brommer', + 'Sterne', + 'Armel', + 'Kryger', + 'Barten', + 'Bodwell', + 'Hollett', + 'Sharron', + 'Scobey', + 'Croson', + 'Gainor', + 'Axel', + 'Basore', + 'Bengel', + 'Chiem', + 'Desanctis', + 'Gillooly', + 'Groulx', + 'Hulings', + 'Koenigsberg', + 'Kuchinski', + 'Pagaduan', + 'Pataky', + 'Rietz', + 'Robello', + 'Schuchman', + 'Shek', + 'Brattain', + 'Gottwald', + 'Klapperich', + 'Kosky', + 'Ruegg', + 'Smid', + 'Taillon', + 'Klonowski', + 'Attar', + 'Mansoor', + 'Daus', + 'Falla', + 'Guyot', + 'Hasten', + 'Mcdowall', + 'Tugwell', + 'Remo', + 'Dishmon', + 'Leggette', + 'Sudler', + 'Prescod', + 'Benvenuti', + 'Bittenbender', + 'Burkland', + 'Crehan', + 'Donjuan', + 'Ewbank', + 'Fluegel', + 'Freiman', + 'Fuelling', + 'Grabner', + 'Gras', + 'Horr', + 'Jurich', + 'Kentner', + 'Laski', + 'Minero', + 'Olivos', + 'Porro', + 'Purves', + 'Smethers', + 'Spallone', + 'Stangler', + 'Gebbia', + 'Fowers', + 'Gaster', + 'Fero', + 'Gamon', + 'Wiss', + 'Strassner', + 'Cott', + 'Houp', + 'Fidel', + 'Parisien', + 'Daisy', + 'Calais', + 'Boers', + 'Bolle', + 'Caccavale', + 'Colantonio', + 'Columbo', + 'Goswami', + 'Hakanson', + 'Jelley', + 'Kahlon', + 'Lopezgarcia', + 'Marier', + 'Mesko', + 'Monter', + 'Mowell', + 'Piech', + 'Shortell', + 'Slechta', + 'Starman', + 'Tiemeyer', + 'Troutner', + 'Vandeveer', + 'Voorheis', + 'Woodhams', + 'Helget', + 'Kalk', + 'Kiester', + 'Lagace', + 'Obst', + 'Parrack', + 'Rennert', + 'Rodeheaver', + 'Schuermann', + 'Warmuth', + 'Wisnieski', + 'Yahnke', + 'Yurek', + 'Faver', + 'Belleau', + 'Moan', + 'Remsen', + 'Bonano', + 'Genson', + 'Genis', + 'Risen', + 'Franze', + 'Lauderback', + 'Ferns', + 'Cooler', + 'Mcwilliam', + 'Micheals', + 'Gotch', + 'Teat', + 'Bacus', + 'Banik', + 'Bernhart', + 'Doell', + 'Francese', + 'Gasbarro', + 'Gietzen', + 'Gossen', + 'Haberle', + 'Havlicek', + 'Henion', + 'Kevorkian', + 'Liem', + 'Loor', + 'Moede', + 'Mostafa', + 'Mottern', + 'Naito', + 'Nofsinger', + 'Omelia', + 'Pirog', + 'Pirone', + 'Plucinski', + 'Raghavan', + 'Robaina', + 'Seliga', + 'Stade', + 'Steinhilber', + 'Wedin', + 'Wieman', + 'Zemaitis', + 'Creps', + 'Gumina', + 'Inglett', + 'Jhaveri', + 'Kolasinski', + 'Salvesen', + 'Vallely', + 'Weseman', + 'Zysk', + 'Gourlay', + 'Zanger', + 'Delorey', + 'Sneider', + 'Tacey', + 'Valls', + 'Ossman', + 'Watton', + 'Breau', + 'Burell', + 'Villard', + 'Janice', + 'Honor', + 'Arterberry', + 'Sow', + 'Cucchiara', + 'Diemert', + 'Fluty', + 'Guadiana', + 'Ionescu', + 'Kearley', + 'Krzyzanowski', + 'Lavecchia', + 'Lundmark', + 'Melichar', + 'Mulkern', + 'Odonohue', + 'Payment', + 'Pinnow', + 'Popoff', + 'Prus', + 'Reinoehl', + 'Scarlata', + 'Schamp', + 'Schowalter', + 'Scinto', + 'Semmler', + 'Sheline', + 'Sigg', + 'Trauger', + 'Bleiler', + 'Carrino', + 'Hauth', + 'Kunsman', + 'Reicks', + 'Rotenberg', + 'Soltesz', + 'Wascher', + 'Mattina', + 'Tamblyn', + 'Bellanca', + 'Heward', + 'Seif', + 'Agha', + 'Gosling', + 'Defreese', + 'Lyvers', + 'Robley', + 'Hadi', + 'Ledyard', + 'Mitchner', + 'Berrien', + 'Clinkscale', + 'Affeldt', + 'Aung', + 'Azpeitia', + 'Boehnlein', + 'Cavan', + 'Ekdahl', + 'Ellyson', + 'Fahl', + 'Herrig', + 'Hulick', + 'Ihrke', + 'Kaeding', + 'Keagy', + 'Mehlman', + 'Minniear', + 'Paniccia', + 'Pleva', + 'Prestidge', + 'Pulford', + 'Quattrone', + 'Riquelme', + 'Rombach', + 'Sarwar', + 'Sivertsen', + 'Sprang', + 'Wardrop', + 'Anglemyer', + 'Bobek', + 'Scronce', + 'Snethen', + 'Stancliff', + 'Booton', + 'Pinal', + 'Weihe', + 'Bria', + 'Lopresto', + 'Awbrey', + 'Fogal', + 'Ning', + 'Hydrick', + 'Lumb', + 'Pommier', + 'Hendy', + 'Armon', + 'Spenser', + 'Beachem', + 'Decrescenzo', + 'Heaphy', + 'Kalata', + 'Kastl', + 'Kosel', + 'Kunert', + 'Laatsch', + 'Lanpher', + 'Malinski', + 'Mazzie', + 'Neuendorf', + 'Salloum', + 'Tays', + 'Yackel', + 'Calvario', + 'Feese', + 'Feldner', + 'Kness', + 'Kozuch', + 'Magat', + 'Pantalone', + 'Rilling', + 'Teska', + 'Fantauzzi', + 'Wartman', + 'Stansbery', + 'Sox', + 'Napp', + 'Schauf', + 'Cumings', + 'Coxon', + 'Labor', + 'Brash', + 'Egleston', + 'Quintin', + 'Oki', + 'Date', + 'Tuckett', + 'Devaux', + 'Hewins', + 'Abdelrahman', + 'Schumpert', + 'Dort', + 'Limbrick', + 'Linwood', + 'Delaine', + 'Liverpool', + 'Azimi', + 'Biever', + 'Craigo', + 'Eschete', + 'Fortini', + 'Francom', + 'Giacomini', + 'Girdler', + 'Halasz', + 'Hillin', + 'Inglese', + 'Isaza', + 'Lewman', + 'Ploetz', + 'Rampley', + 'Reifsteck', + 'Rossano', + 'Sanagustin', + 'Sotak', + 'Spainhower', + 'Stecklein', + 'Stolberg', + 'Teschner', + 'Thew', + 'Blaszczyk', + 'Caradonna', + 'Cillo', + 'Diluzio', + 'Hagemeyer', + 'Holstrom', + 'Jewkes', + 'Mcquaide', + 'Osterhaus', + 'Twaddle', + 'Wenck', + 'Yakel', + 'Zeiner', + 'Zulauf', + 'Mirabelli', + 'Gerold', + 'Sherr', + 'Ogando', + 'Achilles', + 'Woodlee', + 'Underdown', + 'Peirson', + 'Abdelaziz', + 'Bently', + 'Junes', + 'Furtick', + 'Muckle', + 'Freemon', + 'Jamar', + 'Scriber', + 'Michaux', + 'Cheatum', + 'Hollings', + 'Telfair', + 'Amadeo', + 'Bargar', + 'Berchtold', + 'Boomhower', + 'Camba', + 'Compo', + 'Dellavecchia', + 'Doring', + 'Doyel', + 'Geck', + 'Giovannini', + 'Herda', + 'Kopko', + 'Kuns', + 'Maciag', + 'Neenan', + 'Neglia', + 'Nienhuis', + 'Niznik', + 'Pieczynski', + 'Quintos', + 'Quirin', + 'Ravi', + 'Teaster', + 'Tipsword', + 'Troiani', + 'Consuegra', + 'Damaso', + 'Garavaglia', + 'Pischke', + 'Prowse', + 'Rumore', + 'Simcoe', + 'Slentz', + 'Sposito', + 'Sulser', + 'Weichel', + 'Sandobal', + 'Siver', + 'Vickerman', + 'Sham', + 'Gutridge', + 'Gracy', + 'Weatherington', + 'Benett', + 'Nottage', + 'Myricks', + 'Tukes', + 'Alcaide', + 'Curatolo', + 'Dalziel', + 'Fandrich', + 'Fisette', + 'Gianino', + 'Grether', + 'Hari', + 'Ichikawa', + 'Lantzy', + 'Monteforte', + 'Moskovitz', + 'Porritt', + 'Raz', + 'Rodenbeck', + 'Ryczek', + 'Strehle', + 'Vanduzer', + 'Voge', + 'Wiker', + 'Yanik', + 'Zangari', + 'Cahue', + 'Dellapenna', + 'Gohr', + 'Gurka', + 'Imburgia', + 'Langenberg', + 'Kivi', + 'Pikul', + 'Sexson', + 'Sharrer', + 'Aramburo', + 'Kadar', + 'Casasola', + 'Nina', + 'Borras', + 'Toledano', + 'Wykle', + 'Naeem', + 'Bailer', + 'Lalla', + 'Booty', + 'Turenne', + 'Merrit', + 'Duffus', + 'Hemmingway', + 'Asare', + 'Ahlborn', + 'Arroyave', + 'Brandenberger', + 'Carolus', + 'Coonan', + 'Dacunha', + 'Dost', + 'Filter', + 'Freudenberg', + 'Grabski', + 'Hengel', + 'Holohan', + 'Kohne', + 'Kollmann', + 'Levick', + 'Lupinacci', + 'Meservey', + 'Reisdorf', + 'Rodabaugh', + 'Shimon', + 'Soth', + 'Spall', + 'Tener', + 'Thier', + 'Welshans', + 'Chermak', + 'Ciolino', + 'Frantzen', + 'Grassman', + 'Okuda', + 'Passantino', + 'Schellinger', + 'Sneath', + 'Bolla', + 'Bobe', + 'Maves', + 'Matey', + 'Shafi', + 'Rothchild', + 'Ker', + 'Verrette', + 'Thorington', + 'Lathers', + 'Merriwether', + 'Bendall', + 'Bercier', + 'Botz', + 'Claybaugh', + 'Creson', + 'Dilone', + 'Gabehart', + 'Gencarelli', + 'Ghormley', + 'Hacking', + 'Haefele', + 'Haros', + 'Holderby', + 'Krotzer', + 'Nanda', + 'Oltmanns', + 'Orndoff', + 'Poniatowski', + 'Rosol', + 'Sheneman', + 'Shifrin', + 'Smay', + 'Swickard', + 'Thayne', + 'Tripathi', + 'Vonbehren', + 'Pummill', + 'Schnitker', + 'Steines', + 'Beechler', + 'Faron', + 'Villari', + 'Spickard', + 'Levings', + 'Polack', + 'Standre', + 'Castel', + 'Louise', + 'Janey', + 'Lindor', + 'Bulthuis', + 'Cantrall', + 'Cisnero', + 'Dangel', + 'Deborde', + 'Decena', + 'Grandon', + 'Gritz', + 'Heberlein', + 'Kestenbaum', + 'Kubitz', + 'Luers', + 'Naiman', + 'Ramaswamy', + 'Sek', + 'Slauson', + 'Walsworth', + 'Biehler', + 'Capano', + 'Casstevens', + 'Forgette', + 'Furnas', + 'Gilkison', + 'Janoski', + 'Jerde', + 'Mcclimans', + 'Rohlf', + 'Vliet', + 'Heeney', + 'Zapanta', + 'Lighthall', + 'Shallow', + 'Neils', + 'Raikes', + 'Clarkston', + 'Claud', + 'Guilbeaux', + 'Pennie', + 'Arizola', + 'Aud', + 'Checketts', + 'Corvera', + 'Easterbrook', + 'Gamm', + 'Grassel', + 'Guarin', + 'Hanf', + 'Hitsman', + 'Lackman', + 'Lubitz', + 'Lupian', + 'Olexa', + 'Omori', + 'Oscarson', + 'Picasso', + 'Plewa', + 'Schmahl', + 'Stolze', + 'Todisco', + 'Zarzycki', + 'Baluyot', + 'Cerrito', + 'Elenbaas', + 'Gavidia', + 'Heisner', + 'Karpowicz', + 'Neidhardt', + 'Silkwood', + 'Taras', + 'Dobias', + 'Widen', + 'Blandino', + 'Fanguy', + 'Probus', + 'Guilbert', + 'Shadowens', + 'Keepers', + 'Bruin', + 'Hitson', + 'Crymes', + 'Roston', + 'Beaubrun', + 'Arrambide', + 'Betti', + 'Brockhaus', + 'Bumanglag', + 'Cabreja', + 'Dicenso', + 'Hartlaub', + 'Hertlein', + 'Lapenna', + 'Rathje', + 'Rotert', + 'Salzberg', + 'Siniard', + 'Tomsic', + 'Wondra', + 'Zenger', + 'Norrod', + 'Opalka', + 'Osment', + 'Zhan', + 'Lemcke', + 'Meranda', + 'Joles', + 'Labay', + 'Monserrate', + 'Grime', + 'Martha', + 'Coltrain', + 'Vardaman', + 'Wragg', + 'Frater', + 'Offer', + 'Elcock', + 'Auble', + 'Bistline', + 'Chorney', + 'Colgate', + 'Dadamo', + 'Deol', + 'Discher', + 'Ertz', + 'Fletchall', + 'Galletti', + 'Geffre', + 'Grall', + 'Hoos', + 'Iezzi', + 'Kawecki', + 'Madamba', + 'Margolies', + 'Mccreedy', + 'Okimoto', + 'Oum', + 'Pangan', + 'Pasternack', + 'Plazola', + 'Prochazka', + 'Tewes', + 'Tramontana', + 'Yauch', + 'Zarling', + 'Zemanek', + 'Altshuler', + 'Bartkowski', + 'Cuoco', + 'Garcialopez', + 'Kauzlarich', + 'Shishido', + 'Zaun', + 'Hallin', + 'Starliper', + 'Belflower', + 'Kneece', + 'Genet', + 'Palmero', + 'Willmott', + 'Riek', + 'Belger', + 'Abbitt', + 'Statum', + 'Jacque', + 'Chisley', + 'Habersham', + 'Berardinelli', + 'Bodle', + 'Deshaw', + 'Ingalsbe', + 'Kirchgessner', + 'Kuna', + 'Pellow', + 'Pickler', + 'Pistole', + 'Rosenstock', + 'Salceda', + 'Sawatzky', + 'Schappell', + 'Scholer', + 'Shellabarger', + 'Spader', + 'Swadley', + 'Travelstead', + 'Varin', + 'Villwock', + 'Wiemers', + 'Bedoy', + 'Borowiak', + 'Celio', + 'Dornfeld', + 'Juhnke', + 'Livernois', + 'Sakaguchi', + 'Sandall', + 'Sivertson', + 'Whitcraft', + 'Anda', + 'Aprile', + 'Kritz', + 'Speier', + 'Karman', + 'Kise', + 'Madia', + 'Bodo', + 'Madole', + 'Harl', + 'Gach', + 'Stalls', + 'Holme', + 'Lomba', + 'Tutton', + 'Windon', + 'Bines', + 'Benoist', + 'Cirrincione', + 'Coday', + 'Delrosso', + 'Dlouhy', + 'Domenick', + 'Edelmann', + 'Goos', + 'Hamling', + 'Huda', + 'Hutzel', + 'Lanasa', + 'Loudenslager', + 'Lueras', + 'Magnussen', + 'Mcferran', + 'Nowinski', + 'Pikula', + 'Precht', + 'Quilici', + 'Robling', + 'Rusche', + 'Schettino', + 'Scibelli', + 'Soderman', + 'Spirito', + 'Teaford', + 'Updegrove', + 'Weygandt', + 'Zervos', + 'Brunker', + 'Demuro', + 'Eckenrod', + 'Emley', + 'Franek', + 'Frankenberger', + 'Longbrake', + 'Magallanez', + 'Stofko', + 'Zenz', + 'Galik', + 'Crevier', + 'Fina', + 'Harari', + 'Dudney', + 'Inga', + 'Sowles', + 'Folker', + 'Cressy', + 'Eckerson', + 'Gerringer', + 'Capito', + 'Huxtable', + 'Arcement', + 'Lansdown', + 'Amara', + 'Brazill', + 'Flye', + 'Currington', + 'Buffin', + 'Desta', + 'Cheuvront', + 'Fuoco', + 'Gerbino', + 'Hilyer', + 'Hogsed', + 'Kubis', + 'Lautner', + 'Loeber', + 'Meyn', + 'Mortell', + 'Nunziato', + 'Opdahl', + 'Panebianco', + 'Reffner', + 'Repsher', + 'Riccobono', + 'Wik', + 'Circle', + 'Hovde', + 'Keaveney', + 'Landsberg', + 'Pesavento', + 'Bedel', + 'Glas', + 'Thurn', + 'Jaffer', + 'Dantin', + 'Risi', + 'Many', + 'Egler', + 'Craghead', + 'Ann', + 'Turnbo', + 'Crumby', + 'Faciane', + 'Brummell', + 'Bujak', + 'Chaddock', + 'Cullop', + 'Eberling', + 'Ennen', + 'Frum', + 'Gassert', + 'Grothaus', + 'Hucke', + 'Lanphere', + 'Lozon', + 'Macadam', + 'Mezo', + 'Peretti', + 'Perlin', + 'Prestwich', + 'Redmann', + 'Ringley', + 'Rivenburg', + 'Sandow', + 'Spreitzer', + 'Stachnik', + 'Szczesniak', + 'Tworek', + 'Wogan', + 'Zygmunt', + 'Austad', + 'Chiappone', + 'Gelineau', + 'Lannom', + 'Livezey', + 'Monrroy', + 'Norem', + 'Oetting', + 'Ostberg', + 'Takeshita', + 'Gorsky', + 'Allcorn', + 'Pemble', + 'Josselyn', + 'Lanzo', + 'Hoare', + 'Ticer', + 'Netterville', + 'Lawes', + 'Lenton', + 'Garraway', + 'Cyprian', + 'Alferez', + 'Allocco', + 'Aslanian', + 'Brenna', + 'Carachure', + 'Devoss', + 'Dubas', + 'Garrabrant', + 'Gerloff', + 'Gerritsen', + 'Hobaugh', + 'Jasek', + 'Kulis', + 'Lenehan', + 'Lodes', + 'Mandich', + 'Manter', + 'Mcfatridge', + 'Mikolajczak', + 'Netz', + 'Perrelli', + 'Ribar', + 'Sekerak', + 'Shingledecker', + 'Talamante', + 'Taverna', + 'Thoresen', + 'Throneberry', + 'Vanacore', + 'Vieau', + 'Wermuth', + 'Zeidan', + 'Counihan', + 'Dircks', + 'Markovitz', + 'Panas', + 'Steffel', + 'Bergstedt', + 'Mohar', + 'Sonne', + 'Mitsch', + 'Aceituno', + 'Loker', + 'Treen', + 'Prunier', + 'Amberson', + 'Allington', + 'Artley', + 'Caffery', + 'Rhoney', + 'Nimmer', + 'Ledwell', + 'Barkus', + 'Fralin', + 'Locks', + 'Azzara', + 'Bartosik', + 'Bertelson', + 'Birman', + 'Brogna', + 'Cachola', + 'Dennington', + 'Enea', + 'Gallogly', + 'Grafe', + 'Jankowiak', + 'Kaas', + 'Karis', + 'Kostick', + 'Lentsch', + 'Locken', + 'Mathys', + 'Maxcy', + 'Monegro', + 'Olano', + 'Paske', + 'Raible', + 'Rowbotham', + 'Vanderbeck', + 'Vanosdol', + 'Wenzler', + 'Yglesias', + 'Eisenberger', + 'Grzelak', + 'Hamidi', + 'Hottel', + 'Markoff', + 'Santagata', + 'Seefeld', + 'Stachowicz', + 'Stiehl', + 'Staver', + 'Raad', + 'Sarber', + 'Rudge', + 'Connelley', + 'Danser', + 'Chumney', + 'Hind', + 'Desper', + 'Fergusson', + 'Ringwood', + 'Byles', + 'Alyea', + 'Benzinger', + 'Betzer', + 'Brix', + 'Chiarella', + 'Chiriboga', + 'Cicala', + 'Cohick', + 'Creeden', + 'Delligatti', + 'Garbacz', + 'Grossberg', + 'Habecker', + 'Inscoe', + 'Irias', + 'Karlsen', + 'Kilts', + 'Koetter', + 'Laflin', + 'Laperle', + 'Mizner', + 'Navia', + 'Nolet', + 'Procaccini', + 'Pula', + 'Scarfo', + 'Schmelz', + 'Taaffe', + 'Troth', + 'Vanlaningham', + 'Vosberg', + 'Whitchurch', + 'Benak', + 'Hanawalt', + 'Lindman', + 'Moschetti', + 'Rozas', + 'Sporleder', + 'Stopka', + 'Turowski', + 'Wahlgren', + 'Youngstrom', + 'Jabbour', + 'Myerson', + 'Perlow', + 'Cannone', + 'Kil', + 'Stiverson', + 'Cedar', + 'Sweeden', + 'Pourciau', + 'Salina', + 'Delmoral', + 'Balle', + 'Cohea', + 'Bute', + 'Rayne', + 'Cawthorn', + 'Conely', + 'Cartlidge', + 'Powel', + 'Nwankwo', + 'Centrella', + 'Delaura', + 'Deprey', + 'Dulude', + 'Garrod', + 'Gassen', + 'Greenberger', + 'Huneke', + 'Kunzman', + 'Laakso', + 'Oppermann', + 'Radich', + 'Rozen', + 'Schoffstall', + 'Swetnam', + 'Vitrano', + 'Wolber', + 'Amirault', + 'Przybysz', + 'Trzeciak', + 'Fontan', + 'Mathie', + 'Roswell', + 'Mcquitty', + 'Kye', + 'Lucious', + 'Chilcutt', + 'Difazio', + 'Diperna', + 'Gashi', + 'Goodstein', + 'Gruetzmacher', + 'Imus', + 'Krumholz', + 'Lanzetta', + 'Leaming', + 'Lehigh', + 'Lobosco', + 'Pardoe', + 'Pellicano', + 'Purtee', + 'Ramanathan', + 'Roszkowski', + 'Satre', + 'Steinborn', + 'Stinebaugh', + 'Thiesen', + 'Tierno', + 'Wrisley', + 'Yazdani', + 'Zwilling', + 'Berntson', + 'Gisclair', + 'Golliher', + 'Neumeier', + 'Stohl', + 'Swartley', + 'Wannemacher', + 'Wickard', + 'Duford', + 'Rosello', + 'Merfeld', + 'Arko', + 'Cotney', + 'Hai', + 'Milley', + 'Figueira', + 'Willes', + 'Helmes', + 'Abair', + 'Life', + 'Izard', + 'Duskin', + 'Moland', + 'Primer', + 'Hagos', + 'Anyanwu', + 'Balasubramanian', + 'Bluth', + 'Calk', + 'Chrzan', + 'Constanza', + 'Durney', + 'Ekholm', + 'Erny', + 'Ferrando', + 'Froberg', + 'Gonyer', + 'Guagliardo', + 'Hreha', + 'Kobza', + 'Kuruvilla', + 'Preziosi', + 'Ricciuti', + 'Rosiles', + 'Schiesser', + 'Schmoyer', + 'Slota', + 'Szeliga', + 'Verba', + 'Widjaja', + 'Wrzesinski', + 'Zufall', + 'Bumstead', + 'Dohrman', + 'Dommer', + 'Eisenmenger', + 'Glogowski', + 'Kaufhold', + 'Kuiken', + 'Ricklefs', + 'Sinyard', + 'Steenbergen', + 'Schweppe', + 'Chatwin', + 'Dingee', + 'Mittleman', + 'Menear', + 'Milot', + 'Riccardo', + 'Clemenson', + 'Mellow', + 'Gabe', + 'Rolla', + 'Vander', + 'Casselberry', + 'Hubbart', + 'Colvert', + 'Billingsly', + 'Burgman', + 'Cattaneo', + 'Duthie', + 'Hedtke', + 'Heidler', + 'Hertenstein', + 'Hudler', + 'Hustead', + 'Ibsen', + 'Krutsinger', + 'Mauceri', + 'Mersereau', + 'Morad', + 'Rentfro', + 'Rumrill', + 'Shedlock', + 'Sindt', + 'Soulier', + 'Squitieri', + 'Trageser', + 'Vatter', + 'Vollman', + 'Wagster', + 'Caselli', + 'Dibacco', + 'Gick', + 'Kachel', + 'Lukaszewski', + 'Minniti', + 'Neeld', + 'Zarrella', + 'Hedglin', + 'Jahan', + 'Nathe', + 'Starn', + 'Kana', + 'Bernet', + 'Rossa', + 'Barro', + 'Smylie', + 'Bowlds', + 'Mccalley', + 'Oniel', + 'Thaggard', + 'Cayson', + 'Sinegal', + 'Bergfeld', + 'Bickmore', + 'Boch', + 'Bushway', + 'Carneiro', + 'Cerio', + 'Colbath', + 'Eade', + 'Eavenson', + 'Epping', + 'Fredricksen', + 'Gramer', + 'Hassman', + 'Hinderer', + 'Kantrowitz', + 'Kaplowitz', + 'Kelner', + 'Lecates', + 'Lothrop', + 'Lupica', + 'Masterman', + 'Meeler', + 'Neumiller', + 'Newbauer', + 'Noyce', + 'Nulty', + 'Shanker', + 'Taheri', + 'Timblin', + 'Vitucci', + 'Zappone', + 'Femia', + 'Hejl', + 'Helmbrecht', + 'Kiesow', + 'Maschino', + 'Brougher', + 'Koff', + 'Reffett', + 'Langhoff', + 'Milman', + 'Sidener', + 'Levie', + 'Chaudry', + 'Rattan', + 'Finkler', + 'Bollen', + 'Booz', + 'Shipps', + 'Theall', + 'Scallion', + 'Furlough', + 'Landfair', + 'Albuquerque', + 'Beckstrand', + 'Colglazier', + 'Darcey', + 'Fahr', + 'Gabert', + 'Gertner', + 'Gettler', + 'Giovannetti', + 'Hulvey', + 'Juenger', + 'Kantola', + 'Kemmerling', + 'Leclere', + 'Liberati', + 'Lopezlopez', + 'Minerva', + 'Redlich', + 'Shoun', + 'Sickinger', + 'Vivier', + 'Yerdon', + 'Ziomek', + 'Dechert', + 'Delbene', + 'Galassi', + 'Rawdon', + 'Wesenberg', + 'Laurino', + 'Grosjean', + 'Levay', + 'Zike', + 'Stukey', + 'Loft', + 'Kool', + 'Hatchel', + 'Mainville', + 'Salis', + 'Greenslade', + 'Mantey', + 'Spratlin', + 'Fayette', + 'Marner', + 'Rolan', + 'Pain', + 'Colquhoun', + 'Brave', + 'Locust', + 'Sconiers', + 'Bahler', + 'Barrero', + 'Bartha', + 'Basnett', + 'Berghoff', + 'Bomgardner', + 'Brindisi', + 'Campoli', + 'Carawan', + 'Chhim', + 'Corro', + 'Crissey', + 'Deterding', + 'Dileonardo', + 'Dowis', + 'Hagemeier', + 'Heichel', + 'Kipfer', + 'Lemberger', + 'Maestri', + 'Mauri', + 'Nakatani', + 'Notestine', + 'Polakowski', + 'Schlobohm', + 'Segel', + 'Socci', + 'Stieg', + 'Thorstad', + 'Trausch', + 'Whitledge', + 'Wilkowski', + 'Barkdull', + 'Dubeau', + 'Ellingsen', + 'Hayduk', + 'Lauter', + 'Lizak', + 'Machamer', + 'Makarewicz', + 'Shuffield', + 'Heiserman', + 'Sandeen', + 'Plough', + 'Stemler', + 'Bossler', + 'Catalina', + 'Betley', + 'Bonello', + 'Pryde', + 'Nickey', + 'Schanck', + 'Single', + 'Mulberry', + 'Point', + 'Danson', + 'Flemmings', + 'Behnken', + 'Catone', + 'Cummiskey', + 'Currens', + 'Gersch', + 'Kitamura', + 'Meddaugh', + 'Montagne', + 'Nouri', + 'Olejnik', + 'Pintar', + 'Placke', + 'Quinter', + 'Rakers', + 'Stuteville', + 'Sullo', + 'Voelz', + 'Barabas', + 'Estock', + 'Hultberg', + 'Savitz', + 'Treml', + 'Vigneault', + 'Jezierski', + 'Zayed', + 'Dewell', + 'Yanko', + 'Moulin', + 'Whalin', + 'Elsworth', + 'Summit', + 'Esty', + 'Mahadeo', + 'Shular', + 'Amedee', + 'Bellerose', + 'Bendixen', + 'Briski', + 'Buysse', + 'Desa', + 'Dobry', + 'Dufner', + 'Fetterly', + 'Finau', + 'Gaudioso', + 'Giangrande', + 'Heuring', + 'Kitchel', + 'Latulippe', + 'Pombo', + 'Vancott', + 'Woofter', + 'Bojarski', + 'Cretella', + 'Heumann', + 'Limpert', + 'Mcneff', + 'Pluff', + 'Tumlinson', + 'Widick', + 'Yeargan', + 'Hanft', + 'Novinger', + 'Ruddle', + 'Wrye', + 'Felde', + 'Basic', + 'Babington', + 'Karson', + 'Forgy', + 'Rendall', + 'Icard', + 'Jann', + 'Ady', + 'Therrell', + 'Sroufe', + 'Maden', + 'Ganus', + 'Preddy', + 'Marberry', + 'Fonder', + 'Latty', + 'Leatherbury', + 'Mentor', + 'Brissett', + 'Mcglory', + 'Readus', + 'Akau', + 'Bellone', + 'Berendt', + 'Bok', + 'Broten', + 'Colosi', + 'Corio', + 'Gilani', + 'Huffmaster', + 'Kieler', + 'Leonor', + 'Lips', + 'Madron', + 'Missey', + 'Nabozny', + 'Panning', + 'Reinwald', + 'Ridener', + 'Silvio', + 'Soder', + 'Spieler', + 'Vaeth', + 'Vincenti', + 'Walczyk', + 'Washko', + 'Wiater', + 'Wilen', + 'Windish', + 'Consalvo', + 'Fioravanti', + 'Hinners', + 'Paduano', + 'Ranum', + 'Parlato', + 'Dweck', + 'Matern', + 'Cryder', + 'Rubert', + 'Furgason', + 'Virella', + 'Boylen', + 'Devenport', + 'Perrodin', + 'Hollingshed', + 'Pennix', + 'Bogdanski', + 'Carretero', + 'Cubillos', + 'Deponte', + 'Forrey', + 'Gatchalian', + 'Geisen', + 'Gombos', + 'Hartlage', + 'Huddy', + 'Kou', + 'Matsko', + 'Muffley', + 'Niazi', + 'Nodarse', + 'Pawelek', + 'Pyper', + 'Stahnke', + 'Udall', + 'Baldyga', + 'Chrostowski', + 'Frable', + 'Handshoe', + 'Helderman', + 'Lambing', + 'Marolf', + 'Maynez', + 'Bunde', + 'Coia', + 'Piersol', + 'Agne', + 'Manwarren', + 'Bolter', + 'Kirsh', + 'Limerick', + 'Degray', + 'Bossie', + 'Frizell', + 'Saulters', + 'Staple', + 'Raspberry', + 'Arvie', + 'Abler', + 'Caya', + 'Ceci', + 'Dado', + 'Dewoody', + 'Hartzel', + 'Haverstick', + 'Kagel', + 'Kinnan', + 'Krock', + 'Kubica', + 'Laun', + 'Leimbach', + 'Mecklenburg', + 'Messmore', + 'Milich', + 'Mor', + 'Nachreiner', + 'Novelo', + 'Poer', + 'Vaupel', + 'Wery', + 'Breisch', + 'Cashdollar', + 'Corbridge', + 'Craker', + 'Heiberger', + 'Landress', + 'Leichty', + 'Wiedmann', + 'Yankowski', + 'Rigel', + 'Eary', + 'Riggen', + 'Nazir', + 'Shambo', + 'Gingery', + 'Guyon', + 'Bogie', + 'Kar', + 'Manifold', + 'Lafavor', + 'Montas', + 'Yeadon', + 'Cutchin', + 'Burkins', + 'Achille', + 'Bulls', + 'Torry', + 'Bartkus', + 'Beshara', + 'Busalacchi', + 'Calkin', + 'Corkum', + 'Crilley', + 'Cuny', + 'Delgaudio', + 'Devenney', + 'Emanuelson', + 'Fiel', + 'Galanti', + 'Gravina', + 'Herzing', + 'Huckaba', + 'Jaquish', + 'Kellermann', + 'Ketola', + 'Klunder', + 'Kolinski', + 'Kosak', + 'Loscalzo', + 'Moehle', + 'Ressel', + 'Skora', + 'Steakley', + 'Traugott', + 'Volden', + 'Berrong', + 'Kehres', + 'Loeffelholz', + 'Mensinger', + 'Nudo', + 'Pargas', + 'Endy', + 'Corniel', + 'Azzam', + 'Soard', + 'Flud', + 'Shuffler', + 'Hiley', + 'Logwood', + 'Ducre', + 'Aikey', + 'Ardolino', + 'Bergstresser', + 'Cen', + 'Delpriore', + 'Divelbiss', + 'Fishkin', + 'Gaucin', + 'Hemmingsen', + 'Inscore', + 'Kathman', + 'Kempen', + 'Koble', + 'Maestre', + 'Mcmonigle', + 'Merendino', + 'Meske', + 'Pietrzyk', + 'Renfrew', + 'Shevchenko', + 'Wied', + 'Digeronimo', + 'Heberer', + 'Himmelberger', + 'Nordmeyer', + 'Pocius', + 'Sigurdson', + 'Simic', + 'Steury', + 'Kealey', + 'Sabat', + 'Verstraete', + 'Patchell', + 'Finigan', + 'Critz', + 'Janelle', + 'Cima', + 'Zachariah', + 'Lebon', + 'Kellough', + 'Whitehall', + 'Jaudon', + 'Civil', + 'Dokes', + 'Slappy', + 'Bernacki', + 'Castronovo', + 'Douty', + 'Formoso', + 'Handelman', + 'Hauswirth', + 'Janowicz', + 'Klostermann', + 'Lochridge', + 'Mcdiarmid', + 'Schmale', + 'Shaddox', + 'Sitzes', + 'Spaw', + 'Urbanik', + 'Voller', + 'Fujikawa', + 'Kimmet', + 'Klingel', + 'Stoffregen', + 'Thammavong', + 'Varelas', + 'Whobrey', + 'Mandella', + 'Montuori', + 'Safrit', + 'Turan', + 'Khokhar', + 'Sircy', + 'Sabio', + 'Fill', + 'Brandao', + 'Avans', + 'Mencer', + 'Sherley', + 'Mccadden', + 'Sydney', + 'Smack', + 'Lastrapes', + 'Rowser', + 'Moultry', + 'Faulcon', + 'Arnall', + 'Babiak', + 'Balsam', + 'Bezanson', + 'Bocook', + 'Bohall', + 'Celi', + 'Costillo', + 'Crom', + 'Crusan', + 'Dibari', + 'Donaho', + 'Followell', + 'Gaudino', + 'Gericke', + 'Gori', + 'Hurrell', + 'Jakubiak', + 'Kazemi', + 'Koslosky', + 'Massoud', + 'Niebla', + 'Noffke', + 'Panjwani', + 'Papandrea', + 'Patella', + 'Plambeck', + 'Plichta', + 'Prinkey', + 'Raptis', + 'Ruffini', + 'Shoen', + 'Temkin', + 'Thul', + 'Vandall', + 'Wyeth', + 'Zalenski', + 'Consoli', + 'Gumbert', + 'Milanowski', + 'Musolf', + 'Naeger', + 'Okonski', + 'Orrison', + 'Solache', + 'Verdone', + 'Woehler', + 'Yonke', + 'Risdon', + 'Orzech', + 'Bergland', + 'Collen', + 'Bloodsworth', + 'Furgeson', + 'Moch', + 'Callegari', + 'Alphonso', + 'Ozier', + 'Paulding', + 'Ringold', + 'Yarde', + 'Abbett', + 'Axford', + 'Capwell', + 'Datz', + 'Delillo', + 'Delisa', + 'Dicaprio', + 'Dimare', + 'Faughnan', + 'Fehrenbacher', + 'Gellert', + 'Ging', + 'Gladhill', + 'Goates', + 'Hammerstrom', + 'Hilbun', + 'Iodice', + 'Kadish', + 'Kilker', + 'Lurvey', + 'Maue', + 'Michna', + 'Parslow', + 'Pawelski', + 'Quenzer', + 'Raboin', + 'Sader', + 'Sawka', + 'Velis', + 'Wilczewski', + 'Willemsen', + 'Zebley', + 'Benscoter', + 'Denhartog', + 'Dolinsky', + 'Malacara', + 'Mccosh', + 'Modugno', + 'Tsay', + 'Vanvoorst', + 'Mincher', + 'Nickol', + 'Elster', + 'Kerce', + 'Brittan', + 'Quilter', + 'Spike', + 'Mcintee', + 'Boldon', + 'Balderama', + 'Cauffman', + 'Chovanec', + 'Difonzo', + 'Fagerstrom', + 'Galanis', + 'Jeziorski', + 'Krasowski', + 'Lansdale', + 'Laven', + 'Magallan', + 'Mahal', + 'Mehrer', + 'Naus', + 'Peltzer', + 'Petraitis', + 'Pritz', + 'Salway', + 'Savich', + 'Schmehl', + 'Teniente', + 'Tuccillo', + 'Wahlquist', + 'Wetz', + 'Brozovich', + 'Catalfamo', + 'Dioguardi', + 'Guzzetta', + 'Hanak', + 'Lipschutz', + 'Sholtis', + 'Bleecker', + 'Sattar', + 'Thivierge', + 'Camfield', + 'Heslep', + 'Tree', + 'Calvey', + 'Mcgowin', + 'Strickling', + 'Manderson', + 'Dieudonne', + 'Bonini', + 'Bruinsma', + 'Burgueno', + 'Cotugno', + 'Fukunaga', + 'Krog', + 'Lacerda', + 'Larrivee', + 'Lepera', + 'Pinilla', + 'Reichenberger', + 'Rovner', + 'Rubiano', + 'Saraiva', + 'Smolka', + 'Soboleski', + 'Tallmadge', + 'Wigand', + 'Wikle', + 'Bentsen', + 'Bierer', + 'Cohenour', + 'Dobberstein', + 'Holderbaum', + 'Polhamus', + 'Skousen', + 'Theiler', + 'Fornes', + 'Sisley', + 'Zingale', + 'Nimtz', + 'Prieur', + 'Mccaughan', + 'Fawaz', + 'Hobbins', + 'Killingbeck', + 'Roads', + 'Nicolson', + 'Mcculloh', + 'Verges', + 'Badley', + 'Shorten', + 'Litaker', + 'Laseter', + 'Stthomas', + 'Mcguffie', + 'Depass', + 'Flemons', + 'Ahola', + 'Armacost', + 'Bearse', + 'Downum', + 'Drechsel', + 'Farooqi', + 'Filosa', + 'Francesconi', + 'Kielbasa', + 'Latella', + 'Monarch', + 'Ozawa', + 'Papadakis', + 'Politano', + 'Poucher', + 'Roussin', + 'Safley', + 'Schwer', + 'Tesoro', + 'Tsan', + 'Wintersteen', + 'Zanni', + 'Barlage', + 'Brancheau', + 'Buening', + 'Dahlem', + 'Forni', + 'Gerety', + 'Gutekunst', + 'Leamer', + 'Liwanag', + 'Meech', + 'Wigal', + 'Bonta', + 'Cheetham', + 'Crespi', + 'Fahs', + 'Prow', + 'Postle', + 'Delacy', + 'Dufort', + 'Gallery', + 'Romey', + 'Aime', + 'Molock', + 'Dixion', + 'Carstarphen', + 'Appleyard', + 'Aylsworth', + 'Barberi', + 'Contini', + 'Cugini', + 'Eiben', + 'Faso', + 'Hartog', + 'Jelen', + 'Loayza', + 'Maugeri', + 'Mcgannon', + 'Osorno', + 'Paratore', + 'Sahagian', + 'Sarracino', + 'Scallon', + 'Sypniewski', + 'Teters', + 'Throgmorton', + 'Vogelpohl', + 'Walkowski', + 'Winchel', + 'Niedermeyer', + 'Jayroe', + 'Montello', + 'Neyer', + 'Milder', + 'Obar', + 'Stanis', + 'Pro', + 'Pin', + 'Fatheree', + 'Cotterell', + 'Reeds', + 'Comrie', + 'Zamor', + 'Gradney', + 'Poullard', + 'Betker', + 'Bondarenko', + 'Buchko', + 'Eischens', + 'Glavan', + 'Hannold', + 'Heafner', + 'Karaffa', + 'Krabbe', + 'Meinzer', + 'Olgin', + 'Raeder', + 'Sarff', + 'Senechal', + 'Sette', + 'Shovlin', + 'Slife', + 'Tallarico', + 'Trivino', + 'Wyszynski', + 'Audia', + 'Facemire', + 'Januszewski', + 'Klebba', + 'Kovacik', + 'Moroni', + 'Nieder', + 'Schorn', + 'Sundby', + 'Tehan', + 'Trias', + 'Kissler', + 'Margo', + 'Jefcoat', + 'Bulow', + 'Maire', + 'Vizcarrondo', + 'Ki', + 'Ayuso', + 'Mayhan', + 'Usman', + 'Blincoe', + 'Whidby', + 'Tinson', + 'Calarco', + 'Cena', + 'Ciccarello', + 'Cloe', + 'Consolo', + 'Davydov', + 'Decristofaro', + 'Delmundo', + 'Dubrow', + 'Ellinwood', + 'Gehling', + 'Halberstadt', + 'Hascall', + 'Hoeffner', + 'Huettl', + 'Iafrate', + 'Imig', + 'Khoo', + 'Krausz', + 'Kuether', + 'Kulla', + 'Marchesani', + 'Ormonde', + 'Platzer', + 'Preusser', + 'Rebel', + 'Reidhead', + 'Riehm', + 'Robertshaw', + 'Runco', + 'Sandino', + 'Spare', + 'Trefethen', + 'Tribby', + 'Yamazaki', + 'Ziesmer', + 'Calamari', + 'Deyoe', + 'Marullo', + 'Neidigh', + 'Salveson', + 'Senesac', + 'Ausburn', + 'Herner', + 'Seagrave', + 'Lormand', + 'Niblock', + 'Somes', + 'Naim', + 'Murren', + 'Callander', + 'Glassco', + 'Henri', + 'Jabbar', + 'Bordes', + 'Altemose', + 'Bagnell', + 'Belloso', + 'Beougher', + 'Birchall', + 'Cantara', + 'Demetriou', + 'Galford', + 'Hast', + 'Heiny', + 'Hieronymus', + 'Jehle', + 'Khachatryan', + 'Kristof', + 'Kubas', + 'Mano', + 'Munar', + 'Ogas', + 'Riccitelli', + 'Sidman', + 'Suchocki', + 'Tortorello', + 'Trombino', + 'Vullo', + 'Badura', + 'Clerkin', + 'Criollo', + 'Dashnaw', + 'Mednick', + 'Pickrel', + 'Mawson', + 'Hockey', + 'Alo', + 'Frankland', + 'Gaby', + 'Hoda', + 'Marchena', + 'Fawbush', + 'Cowing', + 'Aydelott', + 'Dieu', + 'Rise', + 'Morten', + 'Gunby', + 'Modeste', + 'Balcerzak', + 'Cutbirth', + 'Dejoseph', + 'Desaulniers', + 'Dimperio', + 'Dubord', + 'Gruszka', + 'Haske', + 'Hehr', + 'Kolander', + 'Kusiak', + 'Lampron', + 'Mapel', + 'Montie', + 'Mumme', + 'Naramore', + 'Raffel', + 'Ruter', + 'Sawa', + 'Sencion', + 'Somogyi', + 'Ventola', + 'Zabawa', + 'Alagna', + 'Burmaster', + 'Chirco', + 'Gjerde', + 'Hilgenberg', + 'Huntress', + 'Kochel', + 'Nist', + 'Schena', + 'Toolan', + 'Wurzer', + 'Masih', + 'Ritts', + 'Rousse', + 'Buckey', + 'Sausedo', + 'Dolle', + 'Bena', + 'Franca', + 'Commins', + 'Gago', + 'Pattie', + 'Brener', + 'Verley', + 'Griffy', + 'Heiskell', + 'Osley', + 'Babula', + 'Barbone', + 'Berzins', + 'Demirjian', + 'Dietze', + 'Haseltine', + 'Heinbaugh', + 'Henneke', + 'Korba', + 'Levitz', + 'Lorenzini', + 'Mansilla', + 'Peffley', + 'Poletti', + 'Portelli', + 'Rottinghaus', + 'Scifres', + 'Stadel', + 'Stettner', + 'Swauger', + 'Vanwart', + 'Vorhies', + 'Worst', + 'Yadav', + 'Yebra', + 'Kreiter', + 'Mroczek', + 'Pennella', + 'Stangelo', + 'Suchan', + 'Weiand', + 'Widhalm', + 'Wojcicki', + 'Gutzman', + 'Griffee', + 'Konicki', + 'Moorehouse', + 'Neighbor', + 'Butte', + 'Cooter', + 'Humpherys', + 'Morrish', + 'Stockhausen', + 'Slatter', + 'Cheely', + 'Yassin', + 'Bazil', + 'Mcsween', + 'Anastos', + 'Annunziato', + 'Bora', + 'Burkitt', + 'Cino', + 'Codding', + 'Criado', + 'Firestine', + 'Goecke', + 'Golda', + 'Holloran', + 'Homen', + 'Laubscher', + 'Memmer', + 'Navejar', + 'Peraino', + 'Petrizzo', + 'Pflieger', + 'Pint', + 'Porcello', + 'Raffety', + 'Riedesel', + 'Salado', + 'Scaletta', + 'Schuring', + 'Slaydon', + 'Solecki', + 'Spomer', + 'Waldridge', + 'Zawislak', + 'Bottone', + 'Helgesen', + 'Knippel', + 'Loutzenhiser', + 'Mallinson', + 'Malnar', + 'Pethtel', + 'Sissel', + 'Thorstenson', + 'Winokur', + 'Dittmann', + 'Fencl', + 'Kernen', + 'Gath', + 'Hiney', + 'Godman', + 'Hopton', + 'Tinley', + 'Wamble', + 'Greg', + 'Garrette', + 'Acoff', + 'Ausman', + 'Burggraf', + 'Colliver', + 'Dejulio', + 'Fedorchak', + 'Finocchio', + 'Grasse', + 'Harpold', + 'Hopman', + 'Kilzer', + 'Losasso', + 'Lovallo', + 'Neumayer', + 'Purohit', + 'Reddinger', + 'Scheper', + 'Valbuena', + 'Wenzl', + 'Eilerman', + 'Galbo', + 'Haydu', + 'Vipond', + 'Wesselman', + 'Yeagle', + 'Boutelle', + 'Odonnel', + 'Morocco', + 'Speak', + 'Ruckel', + 'Cornier', + 'Burbidge', + 'Esselman', + 'Daisey', + 'Juran', + 'Henard', + 'Trench', + 'Hurry', + 'Estis', + 'Allport', + 'Beedy', + 'Blower', + 'Bogacz', + 'Caldas', + 'Carriero', + 'Garand', + 'Gonterman', + 'Harbeck', + 'Husar', + 'Lizcano', + 'Lonardo', + 'Meneely', + 'Misiewicz', + 'Pagliuca', + 'Pember', + 'Rybacki', + 'Safar', + 'Seeberger', + 'Siharath', + 'Spoerl', + 'Tattersall', + 'Birchmeier', + 'Denunzio', + 'Dustman', + 'Franchini', + 'Gettel', + 'Goldrick', + 'Goodheart', + 'Keshishyan', + 'Mcgrogan', + 'Newingham', + 'Scheier', + 'Skorupa', + 'Utech', + 'Weidenbach', + 'Chaloupka', + 'Grater', + 'Libman', + 'Recore', + 'Savona', + 'Verbeke', + 'Lunetta', + 'Schlater', + 'Staffieri', + 'Troll', + 'Leyton', + 'Peto', + 'Trella', + 'Follin', + 'Morro', + 'Woodhall', + 'Krauser', + 'Salles', + 'Brunty', + 'Wadford', + 'Shaddock', + 'Minnie', + 'Mountcastle', + 'Butter', + 'Galentine', + 'Longsworth', + 'Edgecombe', + 'Babino', + 'Printup', + 'Humbles', + 'Vessel', + 'Relford', + 'Taite', + 'Aliberti', + 'Brostrom', + 'Budlong', + 'Bykowski', + 'Coursen', + 'Darga', + 'Doutt', + 'Gomberg', + 'Greaser', + 'Hilde', + 'Hirschy', + 'Mayorquin', + 'Mcartor', + 'Mechler', + 'Mein', + 'Montville', + 'Peskin', + 'Popiel', + 'Ricciardelli', + 'Terrana', + 'Urton', + 'Cardiff', + 'Foiles', + 'Humann', + 'Pokorney', + 'Seehafer', + 'Sporer', + 'Timme', + 'Tweten', + 'Widrick', + 'Harnack', + 'Chamlee', + 'Lafountaine', + 'Lowdermilk', + 'Akel', + 'Maulden', + 'Sloman', + 'Odonald', + 'Hitchman', + 'Pendergraph', + 'Klugh', + 'Mctier', + 'Stargell', + 'Hailu', + 'Kanu', + 'Abrahamian', + 'Ackerly', + 'Belongia', + 'Cudmore', + 'Jaskolski', + 'Kedzierski', + 'Licciardi', + 'Lowenberg', + 'Meitzler', + 'Metzer', + 'Mitcheltree', + 'Nishioka', + 'Pascuzzi', + 'Pelphrey', + 'Ramones', + 'Schuchard', + 'Smithee', + 'Bignell', + 'Blaszak', + 'Borello', + 'Fiacco', + 'Garrelts', + 'Guzowski', + 'Rychlik', + 'Siebers', + 'Speziale', + 'Zauner', + 'Corell', + 'Welt', + 'Koby', + 'Auletta', + 'Bursch', + 'Luckman', + 'Vanhoesen', + 'Russian', + 'Statton', + 'Yahya', + 'Boxx', + 'Haltiwanger', + 'Redhead', + 'Mcgregory', + 'Baccari', + 'Berrey', + 'Bogden', + 'Braniff', + 'Cafarelli', + 'Clavette', + 'Corallo', + 'Dealy', + 'Gilger', + 'Gitter', + 'Goldwasser', + 'Hillesheim', + 'Hulsizer', + 'Jankovic', + 'Limburg', + 'Lopera', + 'Mcaleese', + 'Mcclintick', + 'Montealegre', + 'Mosko', + 'Nogle', + 'Ordones', + 'Papesh', + 'Peragine', + 'Picco', + 'Podraza', + 'Ras', + 'Rezek', + 'Rork', + 'Schraufnagel', + 'Scipione', + 'Terlizzi', + 'Vanblarcom', + 'Yoshino', + 'Beaverson', + 'Behunin', + 'Isch', + 'Janiga', + 'Koeppe', + 'Laurich', + 'Vondrak', + 'Walkley', + 'Hottenstein', + 'Garms', + 'Macknight', + 'Seagroves', + 'Shehata', + 'Arons', + 'Liley', + 'Pressly', + 'Cowper', + 'Branon', + 'Abdella', + 'Milord', + 'Appenzeller', + 'Ardila', + 'Belgard', + 'Boop', + 'Burbano', + 'Capitano', + 'Carrig', + 'Conrey', + 'Donica', + 'Fineberg', + 'Gemberling', + 'Harrier', + 'Hufnagle', + 'Kitner', + 'Lessing', + 'Manoukian', + 'Menk', + 'Repetto', + 'Rhinesmith', + 'Stechschulte', + 'Yep', + 'Zuhlke', + 'Abundiz', + 'Buccellato', + 'Closser', + 'Gielow', + 'Nurmi', + 'Pelka', + 'Piscitello', + 'Shoaff', + 'Champlain', + 'Conran', + 'Leidig', + 'Carel', + 'Zahid', + 'Dimitri', + 'Sapia', + 'Labauve', + 'Khalifa', + 'Gonsoulin', + 'Parrot', + 'Propps', + 'Dunnaway', + 'Cayo', + 'Mccleod', + 'Bonifas', + 'Dirkes', + 'Farruggia', + 'Gut', + 'Heacox', + 'Herrejon', + 'Ipina', + 'Keatley', + 'Kowitz', + 'Kratky', + 'Langseth', + 'Nidiffer', + 'Plimpton', + 'Riesenberg', + 'Sulewski', + 'Tabar', + 'Takara', + 'Tomassetti', + 'Tweet', + 'Weltz', + 'Youtsey', + 'Franckowiak', + 'Geffert', + 'Glawe', + 'Hillestad', + 'Ladewig', + 'Luckow', + 'Radebaugh', + 'Ransbottom', + 'Stordahl', + 'Weimar', + 'Wiegers', + 'Jowett', + 'Tomb', + 'Waitt', + 'Beaudreau', + 'Notter', + 'Rijo', + 'Denike', + 'Mam', + 'Vent', + 'Gamage', + 'Carre', + 'Childrey', + 'Heaven', + 'Forge', + 'Beckom', + 'Collick', + 'Bovell', + 'Hardimon', + 'Shells', + 'Bolf', + 'Canete', + 'Cozby', + 'Dunlavey', + 'Febo', + 'Lamke', + 'Lant', + 'Larned', + 'Leiss', + 'Lofthouse', + 'Marohn', + 'Stradling', + 'Subramaniam', + 'Vitug', + 'Ziccardi', + 'Akamine', + 'Bellissimo', + 'Bottini', + 'Braund', + 'Cavasos', + 'Heltsley', + 'Landstrom', + 'Lisiecki', + 'Navejas', + 'Sobczyk', + 'Trela', + 'Yablonski', + 'Yocham', + 'Fier', + 'Laiche', + 'Zenor', + 'Grew', + 'Naval', + 'Garratt', + 'Sako', + 'Zollicoffer', + 'Momon', + 'Bensman', + 'Cirincione', + 'Dimitrov', + 'Domeier', + 'Gaska', + 'Gensel', + 'Gernert', + 'Groot', + 'Guarisco', + 'Llorente', + 'Ludemann', + 'Moisan', + 'Muzio', + 'Neiswender', + 'Ottaway', + 'Paslay', + 'Readinger', + 'Skok', + 'Spittle', + 'Sweany', + 'Tanzi', + 'Upadhyay', + 'Valone', + 'Varas', + 'Benecke', + 'Faulstich', + 'Hebda', + 'Jobst', + 'Schleis', + 'Shuart', + 'Treinen', + 'Fok', + 'Dentler', + 'Ginty', + 'Ronda', + 'Tess', + 'Scantlin', + 'Kham', + 'Murin', + 'Faubert', + 'Ocarroll', + 'Maranda', + 'Gadsby', + 'Mouse', + 'Lunden', + 'Asquith', + 'Batley', + 'Bazzle', + 'Hooke', + 'Macneal', + 'Desnoyers', + 'Verdier', + 'Biglow', + 'Leverson', + 'Becherer', + 'Cecilio', + 'Correale', + 'Ehinger', + 'Erney', + 'Fassnacht', + 'Humpal', + 'Korpela', + 'Kratt', + 'Kunes', + 'Lockyer', + 'Macho', + 'Manfredo', + 'Maturino', + 'Raineri', + 'Seiger', + 'Stant', + 'Tecson', + 'Tempest', + 'Traverse', + 'Vonk', + 'Wormington', + 'Yeske', + 'Erichsen', + 'Fiorelli', + 'Fouty', + 'Hodgkiss', + 'Lindenbaum', + 'Matusik', + 'Mazzocco', + 'Oldani', + 'Ronca', + 'Amero', + 'Ormand', + 'Cagley', + 'Teutsch', + 'Likins', + 'Blurton', + 'Lapier', + 'Rensch', + 'Howitt', + 'Kady', + 'Broce', + 'Gaba', + 'Summerson', + 'Faure', + 'Densley', + 'Matkins', + 'Boleware', + 'Rahming', + 'Degrate', + 'Broaden', + 'Barbian', + 'Brancaccio', + 'Dimiceli', + 'Doukas', + 'Fredell', + 'Fritchman', + 'Gahr', + 'Geerdes', + 'Heidrick', + 'Hernon', + 'Ipsen', + 'Koci', + 'Lato', + 'Lyng', + 'Montella', + 'Petraglia', + 'Redlinger', + 'Riedlinger', + 'Rodier', + 'Shenton', + 'Smigiel', + 'Spanbauer', + 'Swetland', + 'Sypolt', + 'Taubert', + 'Wallander', + 'Willers', + 'Ziller', + 'Bielak', + 'Careaga', + 'Droddy', + 'Girardot', + 'Kanouse', + 'Perusse', + 'Schwier', + 'Velo', + 'Westrum', + 'Bouza', + 'Calverley', + 'Shupert', + 'Simi', + 'Zieger', + 'Nicole', + 'Fergeson', + 'Guerrant', + 'Tongue', + 'Amison', + 'Darius', + 'Banasiak', + 'Cocca', + 'Dannemiller', + 'Frommer', + 'Guardia', + 'Herl', + 'Lippa', + 'Nappo', + 'Olaya', + 'Ozburn', + 'Patry', + 'Pontiff', + 'Rauth', + 'Reier', + 'Rolfs', + 'Sassone', + 'Servidio', + 'Shough', + 'Tencza', + 'Ernster', + 'Helminiak', + 'Mcmanamon', + 'Ottens', + 'Vinh', + 'Bula', + 'Elza', + 'Serres', + 'Holan', + 'Wetherill', + 'Balis', + 'Schexnider', + 'Harral', + 'Dulany', + 'Webley', + 'Addleman', + 'Antonopoulos', + 'Badman', + 'Czerwonka', + 'Deweerd', + 'Donaghey', + 'Duszynski', + 'Firkus', + 'Foell', + 'Goyne', + 'Hattabaugh', + 'Herbel', + 'Liebelt', + 'Lovera', + 'Quenneville', + 'Ramic', + 'Rissmiller', + 'Schlag', + 'Selover', + 'Seyer', + 'Stangeland', + 'Stutesman', + 'Suminski', + 'Sweger', + 'Tetlow', + 'Thornbury', + 'Votava', + 'Weberg', + 'Canniff', + 'Evetts', + 'Gutterman', + 'Kasparek', + 'Krenzer', + 'Luckenbaugh', + 'Mainwaring', + 'Vanderweide', + 'Balladares', + 'Riesterer', + 'Salmen', + 'Mirando', + 'Rockman', + 'Warnes', + 'Crispell', + 'Corban', + 'Chrystal', + 'Barlowe', + 'Perot', + 'Ka', + 'Stockett', + 'Montfort', + 'Reagor', + 'Coote', + 'Christon', + 'Dor', + 'Apt', + 'Bandel', + 'Bibbee', + 'Brunkhorst', + 'Dexheimer', + 'Disharoon', + 'Engelstad', + 'Glaza', + 'Locey', + 'Loughney', + 'Minotti', + 'Posa', + 'Renzulli', + 'Schlauch', + 'Shadix', + 'Sloboda', + 'Topor', + 'Vacha', + 'Cerulli', + 'Ciaravino', + 'Cisek', + 'Congrove', + 'Domzalski', + 'Fleitas', + 'Helfand', + 'Lehnen', + 'Moleski', + 'Walski', + 'Dazey', + 'Mckellips', + 'Kanne', + 'Deguire', + 'Macmurray', + 'Marcelli', + 'Creach', + 'Antrobus', + 'Hykes', + 'Barriere', + 'Avinger', + 'Handford', + 'Beaufort', + 'Abend', + 'Bozzi', + 'Burnsworth', + 'Crosthwaite', + 'Eilert', + 'Frigon', + 'Hanbury', + 'Hoilman', + 'Isaksen', + 'Juday', + 'Legarda', + 'Mcgourty', + 'Mittler', + 'Olkowski', + 'Pau', + 'Pescador', + 'Pinkerman', + 'Renno', + 'Rescigno', + 'Salsgiver', + 'Schlanger', + 'Sobek', + 'Stasi', + 'Talaga', + 'Tish', + 'Tropea', + 'Umphress', + 'Weisheit', + 'Bartolini', + 'Dassow', + 'Ferullo', + 'Fetherolf', + 'Kimery', + 'Kurihara', + 'Schneiter', + 'Sramek', + 'Swier', + 'Weinzierl', + 'Karrer', + 'Hurta', + 'Lodico', + 'Conkright', + 'Sandvik', + 'Pash', + 'Pinell', + 'Dougal', + 'Burnet', + 'Hoe', + 'Rann', + 'Curvin', + 'Route', + 'Outler', + 'Corprew', + 'Berhe', + 'Eleby', + 'Acoba', + 'Ante', + 'Baio', + 'Befort', + 'Brueck', + 'Chevere', + 'Ciani', + 'Farnes', + 'Hamar', + 'Hirschhorn', + 'Imbrogno', + 'Kegg', + 'Leever', + 'Mesker', + 'Nodal', + 'Olveda', + 'Paletta', + 'Pilant', + 'Rissman', + 'Sebold', + 'Siebel', + 'Smejkal', + 'Stai', + 'Vanderkolk', + 'Allday', + 'Canupp', + 'Dieck', + 'Hinders', + 'Karcz', + 'Shomaker', + 'Tuinstra', + 'Urquizo', + 'Wiltgen', + 'Withem', + 'Yanda', + 'Blizard', + 'Christenbury', + 'Helser', + 'Jing', + 'Stave', + 'Waddill', + 'Mairena', + 'Rebert', + 'Gara', + 'Shipes', + 'Hartsoe', + 'Bargeron', + 'Arne', + 'Ebrahim', + 'Basha', + 'Rozar', + 'Venter', + 'Mounger', + 'Marsalis', + 'Gildon', + 'Antkowiak', + 'Brus', + 'Cicalese', + 'Einspahr', + 'Faucheux', + 'Frix', + 'Gateley', + 'Hamberger', + 'Holdorf', + 'Hollibaugh', + 'Junod', + 'Keaveny', + 'Knechtel', + 'Kuffel', + 'Mcwhirt', + 'Navis', + 'Neave', + 'Rackers', + 'Romagnoli', + 'Shawhan', + 'Valvano', + 'Vina', + 'Wielgus', + 'Wojtaszek', + 'Bartnik', + 'Fiebelkorn', + 'Gertsch', + 'Morgenthaler', + 'Nambo', + 'Nemmers', + 'Nihart', + 'Nilges', + 'Pulgarin', + 'Recktenwald', + 'Vandenbrink', + 'Wion', + 'Cundy', + 'Burby', + 'Cu', + 'Vansciver', + 'Herne', + 'Doughtie', + 'Cowdery', + 'Woodle', + 'Lafosse', + 'Hodgens', + 'Mckune', + 'Car', + 'Callens', + 'Corsey', + 'Brimage', + 'Westry', + 'Arismendez', + 'Benenati', + 'Brine', + 'Brookbank', + 'Burfield', + 'Charnock', + 'Copado', + 'Demilio', + 'Elvira', + 'Fantini', + 'Ferko', + 'Flanagin', + 'Gotto', + 'Hartsough', + 'Heckart', + 'Herskowitz', + 'Hoene', + 'Ishibashi', + 'Kysar', + 'Leaverton', + 'Longfield', + 'Mischel', + 'Musleh', + 'Neyra', + 'Obeirne', + 'Ostrum', + 'Pedretti', + 'Pilkerton', + 'Plasse', + 'Reesor', + 'Roznowski', + 'Rusinko', + 'Sickle', + 'Spiteri', + 'Stash', + 'Syracuse', + 'Trachsel', + 'Weinand', + 'Gruenberg', + 'Gutkowski', + 'Morella', + 'Morneault', + 'Slivinski', + 'Blessinger', + 'Taketa', + 'Hussaini', + 'Obeid', + 'Seebeck', + 'Spayd', + 'Keasling', + 'Famularo', + 'Carne', + 'Lacosse', + 'Morino', + 'Gutzmer', + 'Spinola', + 'Deahl', + 'Crumm', + 'Folley', + 'Lennard', + 'Rowson', + 'Pickron', + 'Union', + 'Abraha', + 'Yohannes', + 'Whidbee', + 'Mccaster', + 'Batzel', + 'Borowy', + 'Disanti', + 'Druck', + 'Elsbury', + 'Eschmann', + 'Fehn', + 'Flesner', + 'Grawe', + 'Haapala', + 'Helvie', + 'Hudy', + 'Joswick', + 'Kilcullen', + 'Mabus', + 'Marzo', + 'Obradovich', + 'Oriordan', + 'Phy', + 'Scarff', + 'Schappert', + 'Scire', + 'Vandevander', + 'Weyland', + 'Anstey', + 'Feeback', + 'Komarek', + 'Kyllo', + 'Manivong', + 'Timberman', + 'Tinkey', + 'Zempel', + 'Haselhorst', + 'Herberg', + 'Laris', + 'Morter', + 'Fredman', + 'Reny', + 'Ferrall', + 'Silverthorne', + 'Shuttlesworth', + 'Stigers', + 'Koker', + 'Mollette', + 'Mansel', + 'Chrisp', + 'Glymph', + 'Preyer', + 'Worlds', + 'Arutyunyan', + 'Carrizosa', + 'Dambrosia', + 'Dantuono', + 'Delduca', + 'Florencio', + 'Garafola', + 'Habermehl', + 'Hanaway', + 'Harmes', + 'Heinonen', + 'Hellstrom', + 'Herzer', + 'Klahr', + 'Kobler', + 'Korner', + 'Lancia', + 'Leask', + 'Ledo', + 'Manzanarez', + 'Myung', + 'Prestigiacomo', + 'Serpe', + 'Tonche', + 'Ventrella', + 'Walrod', + 'Warga', + 'Wasmer', + 'Weins', + 'Zaccaro', + 'Bartus', + 'Fiumara', + 'Incorvaia', + 'Khatun', + 'Kisamore', + 'Riesen', + 'Santry', + 'Schmierer', + 'Talamo', + 'Zaccone', + 'Liddick', + 'Mcclune', + 'Hade', + 'Calcutt', + 'Gillet', + 'Husein', + 'Be', + 'Lavell', + 'Veley', + 'Buckholtz', + 'Naves', + 'Debrosse', + 'Palms', + 'Lacewell', + 'Tates', + 'Tekle', + 'Golphin', + 'Asleson', + 'Bartlebaugh', + 'Benter', + 'Bielefeld', + 'Cappetta', + 'Hanback', + 'Heeg', + 'Helf', + 'Hibberd', + 'Holsworth', + 'Kowalchuk', + 'Kruczek', + 'Lieurance', + 'Markwood', + 'Muckey', + 'Rasey', + 'Rautio', + 'Salek', + 'Schwaller', + 'Scibilia', + 'Speltz', + 'Stopper', + 'Struckman', + 'Surowiec', + 'Texter', + 'Venturi', + 'Wolfenden', + 'Zortman', + 'Dehler', + 'Gillogly', + 'Hoelzel', + 'Iida', + 'Paparella', + 'Petrea', + 'Pflaum', + 'Spampinato', + 'Spaur', + 'Umbaugh', + 'Cerney', + 'Athens', + 'Salvas', + 'Gardinier', + 'Ammar', + 'Arns', + 'Calvi', + 'Palazzola', + 'Starlin', + 'Quave', + 'Rhame', + 'Gulliford', + 'Nettle', + 'Picken', + 'Warde', + 'Pelissier', + 'Mcteer', + 'Freeny', + 'Tappin', + 'Bromell', + 'People', + 'Carthen', + 'Battenfield', + 'Bunte', + 'Estrin', + 'Fitzner', + 'Flattery', + 'Hlavacek', + 'Holecek', + 'Jorstad', + 'Jurczak', + 'Kraszewski', + 'Lencioni', + 'Mamula', + 'Mater', + 'Petrakis', + 'Safranek', + 'Santorelli', + 'Speyer', + 'Waterworth', + 'Worner', + 'Antonellis', + 'Codispoti', + 'Docken', + 'Economos', + 'Petrilla', + 'Puccinelli', + 'Rondinelli', + 'Leibel', + 'Santoya', + 'Hader', + 'Yeakley', + 'Dowse', + 'Hattan', + 'Lia', + 'Emel', + 'Corse', + 'Danes', + 'Rambin', + 'Dura', + 'Kyne', + 'Sanderford', + 'Mincer', + 'Rawl', + 'Staves', + 'Mccleave', + 'Faniel', + 'Abeln', + 'Asta', + 'Beymer', + 'Cresap', + 'Cryderman', + 'Gutwein', + 'Kaszuba', + 'Maland', + 'Marella', + 'Mcmannis', + 'Molenaar', + 'Olivarria', + 'Panfil', + 'Pieratt', + 'Ramthun', + 'Resurreccion', + 'Rosander', + 'Rostad', + 'Sallas', + 'Santone', + 'Schey', + 'Shasteen', + 'Spalla', + 'Sui', + 'Tannous', + 'Tarman', + 'Trayer', + 'Wolman', + 'Chausse', + 'Debacker', + 'Dozal', + 'Hach', + 'Klossner', + 'Kruchten', + 'Mahowald', + 'Rosenlund', + 'Steffenhagen', + 'Vanmaanen', + 'Wildasin', + 'Winiecki', + 'Dilauro', + 'Wygal', + 'Cadmus', + 'Smallman', + 'Sear', + 'Berch', + 'Nabor', + 'Bro', + 'Storr', + 'Goynes', + 'Chestang', + 'Alvillar', + 'Arya', + 'Aton', + 'Bors', + 'Brydon', + 'Castagno', + 'Catena', + 'Catterson', + 'Chhun', + 'Delrossi', + 'Garnsey', + 'Harbeson', + 'Holum', + 'Iglesia', + 'Kleen', + 'Lavallie', + 'Lossing', + 'Miyata', + 'Myszka', + 'Peth', + 'Pyka', + 'Radler', + 'Roggenkamp', + 'Sarra', + 'Schmeltz', + 'Schreifels', + 'Schrimpf', + 'Scrogham', + 'Sieminski', + 'Singson', + 'Stichter', + 'Vajda', + 'Vilardo', + 'Ziff', + 'Cegielski', + 'Fanara', + 'Mefferd', + 'Polanski', + 'Reining', + 'Roggow', + 'Sassi', + 'Wagenknecht', + 'Roadcap', + 'Tuman', + 'Demesa', + 'Surita', + 'Armando', + 'Macks', + 'Megan', + 'Angello', + 'Bosher', + 'Neugent', + 'Croslin', + 'Bumpas', + 'Gladman', + 'Demmons', + 'Mcnairy', + 'Sermons', + 'Okonkwo', + 'Alvira', + 'Barfuss', + 'Bersch', + 'Bustin', + 'Ciriello', + 'Cords', + 'Cuddeback', + 'Debono', + 'Delosh', + 'Haeger', + 'Ida', + 'Kneer', + 'Koppen', + 'Kottwitz', + 'Laib', + 'Matsushita', + 'Mckone', + 'Meester', + 'Ohashi', + 'Pickert', + 'Risso', + 'Vannice', + 'Vargason', + 'Vorpahl', + 'Gluth', + 'Goossens', + 'Kloeppel', + 'Krolczyk', + 'Lequire', + 'Nila', + 'Savoia', + 'Wassmer', + 'Bianca', + 'Rousselle', + 'Wittler', + 'Gillean', + 'Cervi', + 'Fremin', + 'Vanzanten', + 'Varvel', + 'Sween', + 'Peron', + 'Trudo', + 'Welford', + 'Scovil', + 'Beazer', + 'Cohill', + 'Estime', + 'Alcalde', + 'Bugay', + 'Bushard', + 'Dethloff', + 'Gahn', + 'Gronau', + 'Hogston', + 'Kleinfelter', + 'Ksiazek', + 'Lyness', + 'Marak', + 'Munafo', + 'Noorani', + 'Plonski', + 'Pontarelli', + 'Presas', + 'Ringenberg', + 'Sabillon', + 'Schaut', + 'Shankland', + 'Sheil', + 'Shugrue', + 'Soter', + 'Stankovich', + 'Arrants', + 'Boeckmann', + 'Boothroyd', + 'Dysinger', + 'Gersh', + 'Monnig', + 'Scheiderer', + 'Slifka', + 'Vilardi', + 'Podell', + 'Tarallo', + 'Goodroe', + 'Sardinha', + 'Blish', + 'Califf', + 'Dorion', + 'Dougall', + 'Hamza', + 'Boggus', + 'Mccan', + 'Branscomb', + 'Baatz', + 'Bendix', + 'Hartstein', + 'Hechler', + 'Komatsu', + 'Kooiman', + 'Loghry', + 'Lorson', + 'Mcgoff', + 'Moga', + 'Monsees', + 'Nigg', + 'Pacitti', + 'Shiffman', + 'Shoupe', + 'Snarski', + 'Vrba', + 'Wilmeth', + 'Yurchak', + 'Budney', + 'Estok', + 'Knipple', + 'Krzywicki', + 'Librizzi', + 'Obringer', + 'Poliquin', + 'Severtson', + 'Vecchiarelli', + 'Zelazny', + 'Eis', + 'Wildeman', + 'Gatt', + 'Gordin', + 'Dusenbury', + 'Prew', + 'Mander', + 'Tine', + 'Debarr', + 'Bann', + 'Mcguirt', + 'Vanloan', + 'Basdeo', + 'Kosh', + 'Bertha', + 'Mcglothen', + 'Youman', + 'Hallums', + 'Mcfield', + 'Asano', + 'Barbo', + 'Braver', + 'Bua', + 'Buetow', + 'Buttke', + 'Estela', + 'Kauk', + 'Kosmicki', + 'Kuecker', + 'Lahm', + 'Lienhard', + 'Lombera', + 'Menken', + 'Niederhauser', + 'Norcia', + 'Petrelli', + 'Phong', + 'Piontkowski', + 'Prihoda', + 'Raffo', + 'Sherpa', + 'Shinsky', + 'Skoczylas', + 'Sosinski', + 'Sua', + 'Sur', + 'Thorndike', + 'Trease', + 'Wessler', + 'Witting', + 'Ackroyd', + 'Bartnick', + 'Dziuba', + 'Lisko', + 'Muradyan', + 'Pistilli', + 'Riechers', + 'Saxman', + 'Rodi', + 'Venables', + 'Holway', + 'Vargus', + 'Oley', + 'Delmont', + 'Fuster', + 'Wyndham', + 'Whittenberg', + 'Chustz', + 'Swilling', + 'Moncure', + 'Housey', + 'Mckiver', + 'Shelvin', + 'Aslin', + 'Begeman', + 'Capek', + 'Christlieb', + 'Colasanti', + 'Daidone', + 'Detlefsen', + 'Elsass', + 'Faus', + 'Francke', + 'Hensarling', + 'Hollmann', + 'Isaacks', + 'Kocis', + 'Kofman', + 'Kwiatek', + 'Osterkamp', + 'Pickar', + 'Prellwitz', + 'Ramo', + 'Steenson', + 'Tomasulo', + 'Weinreb', + 'Wiard', + 'Ambs', + 'Baglio', + 'Frayre', + 'Hisaw', + 'Justman', + 'Morrical', + 'Sherfey', + 'Gera', + 'Ilgenfritz', + 'Silos', + 'Boge', + 'Darocha', + 'Hennon', + 'Hendriks', + 'Purrington', + 'Eunice', + 'Kirks', + 'Barbar', + 'Guichard', + 'Bonny', + 'Lobban', + 'Winrow', + 'Alavi', + 'Binner', + 'Canan', + 'Ciullo', + 'Cyran', + 'Doolen', + 'Enquist', + 'Fatzinger', + 'Forsell', + 'Harnisch', + 'Hirose', + 'Lunz', + 'Mcbrearty', + 'Mcgavin', + 'Minkin', + 'Ralphs', + 'Ruegsegger', + 'Shetter', + 'Slagter', + 'Tyminski', + 'Ubben', + 'Vanderschaaf', + 'Wigfield', + 'Zellman', + 'Bettenhausen', + 'Busker', + 'Jabs', + 'Mishkin', + 'Sturdy', + 'Vanstone', + 'Tierce', + 'Cormican', + 'Mazzucco', + 'Buenger', + 'Gallier', + 'Duma', + 'Rainbow', + 'Herlong', + 'Chriswell', + 'Litsey', + 'Wyke', + 'Kissoon', + 'Sesler', + 'Farve', + 'Lalanne', + 'Myhand', + 'Heggs', + 'Andujo', + 'Arcilla', + 'Bult', + 'Caponigro', + 'Commerford', + 'Ditmars', + 'Dressen', + 'Eggemeyer', + 'Forstner', + 'From', + 'Heldreth', + 'Hevia', + 'Leiphart', + 'Mastrocola', + 'Mcanelly', + 'Mccrillis', + 'Mellick', + 'Mogle', + 'Mummey', + 'Nishiyama', + 'Nordine', + 'Picinich', + 'Rafiq', + 'Savo', + 'Selvig', + 'Sestak', + 'Shafran', + 'Smithhart', + 'Soltani', + 'Stillion', + 'Szuch', + 'Tigert', + 'Trine', + 'Un', + 'Brest', + 'Callari', + 'Jaskowiak', + 'Maneval', + 'Sarchet', + 'Szuba', + 'Taubman', + 'Wandel', + 'Blok', + 'Pasquarello', + 'Sava', + 'Diekman', + 'Blight', + 'Lovgren', + 'Clemson', + 'Lince', + 'Kanady', + 'Whipps', + 'Coren', + 'Coye', + 'Patman', + 'Souffrant', + 'Bloodsaw', + 'Amano', + 'Cassaday', + 'Cutillo', + 'Dayrit', + 'Deringer', + 'Duwe', + 'Favazza', + 'Fennema', + 'Hackleman', + 'Harders', + 'Imperiale', + 'Kano', + 'Kingma', + 'Meuser', + 'Neiger', + 'Neitz', + 'Nied', + 'Prows', + 'Riss', + 'Rotundo', + 'Scheurich', + 'Stopa', + 'Tonks', + 'Veen', + 'Volante', + 'Maerz', + 'Nunnelley', + 'Sommerfeldt', + 'Spoonemore', + 'Wechter', + 'Wehrli', + 'Ackert', + 'Begun', + 'Dreyfuss', + 'Frezza', + 'Mako', + 'Nagao', + 'Lassetter', + 'Linse', + 'Raum', + 'Graca', + 'Enslow', + 'Bruff', + 'Hodgkin', + 'Coone', + 'Trippett', + 'Tippitt', + 'Sumerlin', + 'Carelock', + 'Whitelow', + 'Beightol', + 'Cappadona', + 'Carrizal', + 'Clendaniel', + 'Cresci', + 'Dietzman', + 'Figge', + 'Heyde', + 'Jarema', + 'Kyllonen', + 'Laminack', + 'Luddy', + 'Monical', + 'Mula', + 'Picotte', + 'Sandiego', + 'Seki', + 'Senner', + 'Starkman', + 'Stassi', + 'Stuckert', + 'Wiers', + 'Wieting', + 'Ziska', + 'Ardelean', + 'Hulslander', + 'Loewenstein', + 'Mearns', + 'Roese', + 'Sweaney', + 'Winick', + 'Zaring', + 'Farry', + 'Dulle', + 'Gunnerson', + 'Duden', + 'Arts', + 'Lame', + 'Mcquerry', + 'Smiles', + 'Pennick', + 'Adderly', + 'Becka', + 'Bluemel', + 'Bocek', + 'Bouwens', + 'Deren', + 'Dewitz', + 'Doland', + 'Ewton', + 'Funnell', + 'Gavel', + 'Haidar', + 'Kalkbrenner', + 'Kawashima', + 'Kueker', + 'Lutze', + 'Macareno', + 'Nenninger', + 'Schone', + 'Seever', + 'Sexauer', + 'Sibilia', + 'Sperrazza', + 'Vanderhoef', + 'Vanoss', + 'Werre', + 'Wotton', + 'Behney', + 'Bossart', + 'Ellithorpe', + 'Eyrich', + 'Fosco', + 'Fulginiti', + 'Grumbles', + 'Hoeger', + 'Kizziah', + 'Kloiber', + 'Kudo', + 'Majcher', + 'Stickels', + 'Stoler', + 'Umholtz', + 'Vasallo', + 'Wenker', + 'Wittmeyer', + 'Telesco', + 'Jha', + 'Maulding', + 'Campton', + 'Verble', + 'Mclure', + 'Bernardin', + 'Eison', + 'Coffie', + 'Ceesay', + 'Balakrishnan', + 'Barich', + 'Bigman', + 'Blumenstein', + 'Bonafede', + 'Cebulski', + 'Chesbro', + 'Cuaresma', + 'Demarino', + 'Derienzo', + 'Donmoyer', + 'Fairall', + 'Gelpi', + 'Giambra', + 'Hasselman', + 'Highlander', + 'Hunker', + 'Iyengar', + 'Kulaga', + 'Kuznicki', + 'Labus', + 'Limbert', + 'Molchan', + 'Neuharth', + 'Overgaard', + 'Paszkiewicz', + 'Plescia', + 'Redcay', + 'Ritzer', + 'Smirnov', + 'Valiquette', + 'Vannortwick', + 'Warstler', + 'Yantz', + 'Beardall', + 'Cimmino', + 'Crnkovich', + 'Konishi', + 'Kosowski', + 'Ragen', + 'Sebert', + 'Valla', + 'Venancio', + 'Maltez', + 'Skehan', + 'Abrantes', + 'Colfer', + 'Beman', + 'Wilhelmsen', + 'Wilking', + 'Rorer', + 'Shutes', + 'Albany', + 'Wearing', + 'Assefa', + 'Angeloni', + 'Bisher', + 'Blancett', + 'Briel', + 'Chiara', + 'Clearman', + 'Dengel', + 'Detert', + 'Fadely', + 'Flinders', + 'Garguilo', + 'Goes', + 'Hakimian', + 'Henehan', + 'Homewood', + 'Kalla', + 'Keirn', + 'Kerwood', + 'Laflam', + 'Lynskey', + 'Minhas', + 'Mow', + 'Olk', + 'Ostergaard', + 'Palecek', + 'Poirrier', + 'Raudenbush', + 'Schlottman', + 'Shatz', + 'Sieloff', + 'Stikeleather', + 'Swavely', + 'Tapanes', + 'Teehan', + 'Wendorff', + 'Wollner', + 'Bichsel', + 'Brandenburger', + 'Demattia', + 'Eggebrecht', + 'Koelzer', + 'Landrigan', + 'Morsch', + 'Pittinger', + 'Rewerts', + 'Schopf', + 'Tetro', + 'Westenberger', + 'Kieft', + 'Overy', + 'Cutrona', + 'Misa', + 'Erich', + 'Swapp', + 'Welchel', + 'Messa', + 'Ala', + 'Witbeck', + 'Mothershead', + 'Stofer', + 'Mcneice', + 'Ayling', + 'Zakaria', + 'Bu', + 'Rauf', + 'Richbourg', + 'Fristoe', + 'Dorch', + 'Mcclarin', + 'Privott', + 'Bonsu', + 'Ayson', + 'Bifulco', + 'Brungard', + 'Bub', + 'Budzynski', + 'Chizmar', + 'Coriz', + 'Corser', + 'Daughdrill', + 'Delre', + 'Elfers', + 'Fabrizi', + 'Gunawan', + 'Haecker', + 'Hammac', + 'Handwerk', + 'Larcom', + 'Liera', + 'Littlewood', + 'Luikart', + 'Pasquarella', + 'Radman', + 'Ranft', + 'Rigas', + 'Santin', + 'Sorbello', + 'Tayag', + 'Ureste', + 'Weidinger', + 'Yerena', + 'Aase', + 'Galyen', + 'Halferty', + 'Hindley', + 'Kunath', + 'Laprairie', + 'Oza', + 'Stohler', + 'Tokarczyk', + 'Yusupov', + 'Nogueras', + 'Jersey', + 'Eastes', + 'Agron', + 'Boso', + 'Kender', + 'Couse', + 'Moreta', + 'Larrow', + 'Degrace', + 'Sonier', + 'Tisdel', + 'Creque', + 'Esther', + 'Girtman', + 'Seraphin', + 'Wesby', + 'Kargbo', + 'Adjei', + 'Angeline', + 'Biby', + 'Brucks', + 'Bucaro', + 'Farman', + 'Gerdeman', + 'Hodsdon', + 'Hoying', + 'Kasperek', + 'Keinath', + 'Kidman', + 'Kleier', + 'Kuban', + 'Lacko', + 'Latourette', + 'Leffert', + 'Leonhart', + 'Mathern', + 'Ploss', + 'Poblano', + 'Raigoza', + 'Santor', + 'Schmitzer', + 'Sirico', + 'Skalsky', + 'Spreen', + 'Standlee', + 'Vonbargen', + 'Cederberg', + 'Cornforth', + 'Dercole', + 'Diblasio', + 'Fleer', + 'Fredlund', + 'Gehris', + 'Guck', + 'Lannen', + 'Lurz', + 'Mazzaferro', + 'Neukam', + 'Rookstool', + 'Scharrer', + 'Sevey', + 'Sicairos', + 'Skrocki', + 'Sneeringer', + 'Stefanowicz', + 'Zuleger', + 'Harmel', + 'Sendejo', + 'Bearer', + 'Shur', + 'Weers', + 'Norell', + 'Plotnick', + 'Cecchi', + 'Gandia', + 'Bastone', + 'Tole', + 'Tramell', + 'Willock', + 'Rhome', + 'Curington', + 'Rapley', + 'Hazley', + 'Todman', + 'Lathon', + 'Alperin', + 'Axtman', + 'Boeke', + 'Butson', + 'Cestaro', + 'Cosgriff', + 'Docter', + 'Eblin', + 'Filsinger', + 'Franzone', + 'Gareau', + 'Garfinkle', + 'Gatch', + 'Germosen', + 'Grzywacz', + 'Huesman', + 'Kasel', + 'Kazan', + 'Manalang', + 'Marando', + 'Marchio', + 'Massimino', + 'Mcneer', + 'Menger', + 'Milanese', + 'Monrreal', + 'Moretto', + 'Mulvany', + 'Petkus', + 'Rehling', + 'Rubbo', + 'Rudnik', + 'Settlemire', + 'Treon', + 'Yaklin', + 'Zittel', + 'Betzold', + 'Bohlin', + 'Churilla', + 'Conrath', + 'Ozbun', + 'Sciuto', + 'Stitz', + 'Sweigert', + 'Tamanaha', + 'Wallgren', + 'Eplin', + 'Ion', + 'Liford', + 'Orendorff', + 'Wootan', + 'Carmical', + 'Mince', + 'Stormes', + 'Lantry', + 'Sportsman', + 'Corron', + 'Padia', + 'Cunnington', + 'Pitta', + 'Ori', + 'Obara', + 'Gaultney', + 'Vanlue', + 'Emmitt', + 'Roddey', + 'Payen', + 'Elmi', + 'Culmer', + 'Mealing', + 'Allegra', + 'Bano', + 'Batterman', + 'Bickell', + 'Dager', + 'Drach', + 'Duchesneau', + 'Erdos', + 'Fedorko', + 'Fluhr', + 'Gassmann', + 'Gillig', + 'Goedert', + 'Golomb', + 'Hatler', + 'Jalali', + 'Joosten', + 'Koke', + 'Lausch', + 'Leisner', + 'Mallinger', + 'Marsolek', + 'Mashek', + 'Ognibene', + 'Oishi', + 'Outman', + 'Paganelli', + 'Passino', + 'Petrak', + 'Rosenwald', + 'Schroader', + 'Stehman', + 'Tenuta', + 'Todt', + 'Tritz', + 'Boerman', + 'Doeden', + 'Etcheverry', + 'Grissinger', + 'Gruenewald', + 'Lijewski', + 'Marcom', + 'Niebauer', + 'Rukavina', + 'Sakuma', + 'Woehrle', + 'Amores', + 'Krammes', + 'Shontz', + 'Bunning', + 'Widdowson', + 'Blankenburg', + 'Goans', + 'Longan', + 'Aboud', + 'Michelli', + 'Rivere', + 'Colla', + 'Lory', + 'Lougheed', + 'Wadel', + 'Chalkley', + 'Gaubert', + 'Goodlin', + 'Bommer', + 'Abbs', + 'Rashad', + 'Malachi', + 'Abrigo', + 'Akre', + 'Antolik', + 'Bachner', + 'Blegen', + 'Cona', + 'Diantonio', + 'Emde', + 'Enrico', + 'Follette', + 'Hagarty', + 'Hanser', + 'Hulsman', + 'Jelinski', + 'Kalisz', + 'Kolek', + 'Kough', + 'Ninneman', + 'Offield', + 'Perezgarcia', + 'Plude', + 'Printy', + 'Rosengrant', + 'Salminen', + 'Schamberger', + 'Teall', + 'Zipfel', + 'Bickler', + 'Casanas', + 'Holtzapple', + 'Sachdeva', + 'Scharnhorst', + 'Schnack', + 'Grode', + 'Strough', + 'Teare', + 'Korona', + 'Creelman', + 'Simper', + 'Marett', + 'Nadeem', + 'Pollet', + 'Eduardo', + 'Chipley', + 'Vanrossum', + 'Fabio', + 'Colona', + 'Whirley', + 'Hider', + 'Plaskett', + 'Trabue', + 'Gibert', + 'Cabiness', + 'Loyal', + 'Rayson', + 'Aloia', + 'Aukerman', + 'Broxterman', + 'Cada', + 'Catalanotto', + 'Condos', + 'Corriher', + 'Eliopoulos', + 'Furia', + 'Girolamo', + 'Haese', + 'Israelson', + 'Jaworowski', + 'Jirik', + 'Kalmar', + 'Leipold', + 'Lemmo', + 'Loja', + 'Loughmiller', + 'Matelski', + 'Mcrorie', + 'Moeckel', + 'Naill', + 'Raczka', + 'Rathgeber', + 'Shamoun', + 'Shannahan', + 'Simler', + 'Stamer', + 'Stonehocker', + 'Twersky', + 'Voeltz', + 'Willets', + 'Wolgamott', + 'Yamin', + 'Acri', + 'Dalgleish', + 'Ehrenreich', + 'Huish', + 'Huxley', + 'Pinkstaff', + 'Rincones', + 'Saric', + 'Shreiner', + 'Stitely', + 'Tippets', + 'Vanamburg', + 'Zbikowski', + 'Sharrett', + 'Suther', + 'Renta', + 'Balles', + 'Florentine', + 'Chrisley', + 'Offner', + 'Matheus', + 'Akens', + 'Dugue', + 'Rigaud', + 'Mohamud', + 'Magloire', + 'Stigger', + 'Andrist', + 'Chaudoin', + 'Clos', + 'Cragin', + 'Dinius', + 'Duignan', + 'Elk', + 'Frenz', + 'Frogge', + 'Giammarino', + 'Hackl', + 'Jaeckel', + 'Knieriem', + 'Lajara', + 'Lisak', + 'Luxton', + 'Merriott', + 'Montini', + 'Olender', + 'Orebaugh', + 'Orren', + 'Osika', + 'Sciascia', + 'Selvaggio', + 'Stoneback', + 'Sweis', + 'Torosyan', + 'Trupp', + 'Wardrip', + 'Wigle', + 'Beissel', + 'Brakke', + 'Carosella', + 'Dobek', + 'Eidem', + 'Homolka', + 'Kemery', + 'Kinderman', + 'Palla', + 'Puccini', + 'Szarek', + 'Vandehei', + 'Arca', + 'Jou', + 'Needs', + 'Habermann', + 'Hyle', + 'Jagoda', + 'Smigielski', + 'Guttierrez', + 'Awwad', + 'Maccormack', + 'Bassin', + 'Achee', + 'Demark', + 'Jardon', + 'Kelsoe', + 'Olear', + 'Comacho', + 'Rosetta', + 'Peddie', + 'Delsol', + 'Nwachukwu', + 'Bagdasarian', + 'Boehringer', + 'Bunke', + 'Burkhammer', + 'Delahoya', + 'Dietzen', + 'Ditmer', + 'Duchaine', + 'Felske', + 'Gumpert', + 'Hansson', + 'Hedeen', + 'Jalil', + 'Kalal', + 'Kanan', + 'Kaska', + 'Kaufer', + 'Knoff', + 'Kornblum', + 'Lanzi', + 'Obenchain', + 'Piatkowski', + 'Prugh', + 'Rima', + 'Shadduck', + 'Sodergren', + 'Spitzley', + 'Tauzin', + 'Weigelt', + 'Baldassarre', + 'Biglin', + 'Fuhriman', + 'Gaumond', + 'Ledvina', + 'Meckler', + 'Minteer', + 'Nesser', + 'Riederer', + 'Ruelle', + 'Turchi', + 'Alberg', + 'Vanderlip', + 'Halder', + 'Hop', + 'Larmon', + 'Bonfield', + 'Ketch', + 'Mannis', + 'Mcallen', + 'Alfonzo', + 'Sampey', + 'Guillet', + 'Madaris', + 'Lisby', + 'Crowner', + 'Frager', + 'Coar', + 'Crewe', + 'Levier', + 'Ligons', + 'Abello', + 'Brinsfield', + 'Buccieri', + 'Cantera', + 'Cieslinski', + 'Cragle', + 'Flater', + 'Grunert', + 'Higinbotham', + 'Janish', + 'Kuennen', + 'Lanners', + 'Lesiak', + 'Litvin', + 'Madueno', + 'Maffia', + 'Manetta', + 'Marschke', + 'Mourer', + 'Nordahl', + 'Nordan', + 'Pankowski', + 'Petron', + 'Qualley', + 'Recht', + 'Rosenbach', + 'Ruttenberg', + 'Saam', + 'Savarino', + 'Solana', + 'Stumpff', + 'Tsukamoto', + 'Vanlanen', + 'Wainer', + 'Kasza', + 'Kuehler', + 'Landgren', + 'Omahony', + 'Paullin', + 'Ramales', + 'Schmelzle', + 'Schnakenberg', + 'Touma', + 'Urgiles', + 'Vorndran', + 'Corne', + 'Higman', + 'Dutil', + 'Reef', + 'Racanelli', + 'Gladwin', + 'Jaspers', + 'Crutchley', + 'Homme', + 'Hughbanks', + 'Crismon', + 'Burdin', + 'Dise', + 'Enzor', + 'Hally', + 'Mccone', + 'Mckell', + 'Belo', + 'Moat', + 'Ijames', + 'Bussie', + 'Papillion', + 'Pratcher', + 'Baranek', + 'Bidlack', + 'Boyadjian', + 'Chern', + 'Conahan', + 'Dimuzio', + 'Erker', + 'Fregeau', + 'Gelsinger', + 'Gonzalo', + 'Heo', + 'Hoog', + 'Jovanovich', + 'Kaschak', + 'Kasik', + 'Katich', + 'Laible', + 'Mastel', + 'Muellner', + 'Pingleton', + 'Rexroth', + 'Schmitter', + 'Stick', + 'Strollo', + 'Traficante', + 'Veteto', + 'Wampole', + 'Winings', + 'Amalfitano', + 'Amiot', + 'Camaj', + 'Cuartas', + 'Drotar', + 'Eatherton', + 'Fioretti', + 'Fudala', + 'Gehrman', + 'Gittleman', + 'Heppe', + 'Maffucci', + 'Tammen', + 'Chovan', + 'Ginley', + 'Stipes', + 'Antigua', + 'Ironside', + 'Kuroda', + 'Lebar', + 'Laske', + 'Salay', + 'Gisi', + 'Mccormic', + 'Veron', + 'Robbin', + 'Morain', + 'Mayden', + 'Vanputten', + 'Triplet', + 'Ravenel', + 'Moragne', + 'Bowdry', + 'Agundez', + 'Allinson', + 'Bosko', + 'Buehrle', + 'Devey', + 'Gasiorowski', + 'Goettel', + 'Halleran', + 'Innocenti', + 'Orser', + 'Scarpati', + 'Scherff', + 'Schlott', + 'Skilling', + 'Speedy', + 'Staal', + 'Szafran', + 'Szczech', + 'Szczepanik', + 'Venturella', + 'Vert', + 'Vogelgesang', + 'Vollbrecht', + 'Wiehe', + 'Achterberg', + 'Fadness', + 'Groene', + 'Halbrooks', + 'Leavenworth', + 'Pruski', + 'Redifer', + 'Schmiesing', + 'Stanforth', + 'Stepanski', + 'Ziel', + 'Hefter', + 'Urman', + 'Muela', + 'Simpler', + 'Elick', + 'Shalabi', + 'Cooner', + 'Ferriera', + 'Templer', + 'Prashad', + 'Gorum', + 'Wheller', + 'Spratling', + 'Gutter', + 'Eke', + 'Rias', + 'Belcourt', + 'Bernards', + 'Camburn', + 'Cerqueira', + 'Conkel', + 'Deist', + 'Derobertis', + 'Desio', + 'Eimer', + 'Fayad', + 'Frommelt', + 'Guariglia', + 'Laba', + 'Labine', + 'Lanius', + 'Loconte', + 'Nop', + 'Omary', + 'Penninger', + 'Pentland', + 'Pinkus', + 'Richoux', + 'Sturrock', + 'Theil', + 'Vanvranken', + 'Bartoszek', + 'Bruski', + 'Engelken', + 'Kranich', + 'Mrazek', + 'Muralles', + 'Pienta', + 'Salido', + 'Sridhar', + 'Turkington', + 'Vellucci', + 'Verhage', + 'Derenzo', + 'Lucker', + 'Wands', + 'Parrow', + 'Branyon', + 'Houff', + 'Bossier', + 'Reels', + 'Rockmore', + 'Altmeyer', + 'Anacker', + 'Antoniou', + 'Berlinger', + 'Busser', + 'Caracci', + 'Caseres', + 'Corcino', + 'Demint', + 'Dhanani', + 'Erekson', + 'Farinacci', + 'Ganesan', + 'Gornick', + 'Gresser', + 'Kremers', + 'Kreuter', + 'Lesieur', + 'Linarez', + 'Mccrystal', + 'Morang', + 'Pucillo', + 'Spicuzza', + 'Tranchina', + 'Tullar', + 'Vantilburg', + 'Yeck', + 'Zandstra', + 'Zeleny', + 'Bearss', + 'Burgner', + 'Delich', + 'Fetsch', + 'Grom', + 'Kreisel', + 'Laprise', + 'Legarreta', + 'Musacchio', + 'Rembold', + 'Sjoblom', + 'Skalicky', + 'Sokolov', + 'Tuminello', + 'Vanskiver', + 'Zidek', + 'Severa', + 'Stables', + 'Guffy', + 'Lebeck', + 'Barradas', + 'Chanley', + 'Dayal', + 'Villafranco', + 'Droke', + 'Popwell', + 'Renier', + 'Bolten', + 'Mille', + 'Swagerty', + 'Grismore', + 'Brantly', + 'Divens', + 'Ottey', + 'Hagger', + 'Advincula', + 'Boschee', + 'Buckbee', + 'Carlan', + 'Casciato', + 'Cregar', + 'Fehring', + 'Ianniello', + 'Interrante', + 'Juedes', + 'Kosier', + 'Lizaola', + 'Lorenzetti', + 'Mccauslin', + 'Older', + 'Osuch', + 'Ramstad', + 'Sare', + 'Stavinoha', + 'Taborda', + 'Warmoth', + 'Weissmann', + 'Winograd', + 'Woeste', + 'Zywicki', + 'Blalack', + 'Chavoya', + 'Clickner', + 'Daigrepont', + 'Dissinger', + 'Kovalik', + 'Lemler', + 'Shortall', + 'Tucholski', + 'Vanmetre', + 'Zetino', + 'Niezgoda', + 'Recupero', + 'Booms', + 'Ramsburg', + 'Berka', + 'Mininger', + 'Tamer', + 'Baka', + 'Jago', + 'Bucks', + 'Laude', + 'Andrepont', + 'Gair', + 'Hayer', + 'Kitching', + 'Towson', + 'Slappey', + 'Syms', + 'Derico', + 'Badie', + 'Kenon', + 'Goffney', + 'Amigon', + 'Belsito', + 'Bergamo', + 'Caputi', + 'Delpilar', + 'Entsminger', + 'Gehres', + 'Geimer', + 'Hada', + 'Krolak', + 'Kruer', + 'Malaney', + 'Mancias', + 'Misiaszek', + 'Pring', + 'Salonga', + 'Schaefers', + 'Schmied', + 'Schwertfeger', + 'Scialabba', + 'Stemmer', + 'Stifter', + 'Suon', + 'Szczygiel', + 'Weisse', + 'Yackley', + 'Decasas', + 'Donado', + 'Drenning', + 'Eppich', + 'Kertesz', + 'Mihal', + 'Mochizuki', + 'Schiebel', + 'Schlageter', + 'Scruton', + 'Weckerly', + 'Wemhoff', + 'Wernette', + 'Zietz', + 'Iwanicki', + 'Ara', + 'Barson', + 'Resor', + 'Rampy', + 'Iskander', + 'Oharra', + 'Kope', + 'Soli', + 'Bodkins', + 'Bussa', + 'Maletta', + 'Clemen', + 'Vaneaton', + 'Berkel', + 'Salvage', + 'Gilchrest', + 'Whitter', + 'Bruster', + 'Mccowin', + 'Gullatt', + 'Cherubin', + 'Flamer', + 'Gueye', + 'Angerer', + 'Baray', + 'Barreca', + 'Bresson', + 'Brougham', + 'Buscaglia', + 'Candee', + 'Decelles', + 'Durflinger', + 'Dusenbery', + 'Enomoto', + 'Galliano', + 'Klooster', + 'Lowrimore', + 'Manda', + 'Morace', + 'Raisanen', + 'Ravenscraft', + 'Rutman', + 'Schmieg', + 'Schorsch', + 'Selim', + 'Stanchfield', + 'Stankowski', + 'Tolosa', + 'Uyeno', + 'Vancleef', + 'Kamdar', + 'Kazlauskas', + 'Kwasnik', + 'Pivonka', + 'Shrode', + 'Sellinger', + 'Deliz', + 'Longerbeam', + 'Schobert', + 'Shader', + 'Collister', + 'Curtright', + 'Franc', + 'Wakely', + 'Duree', + 'Laban', + 'Gascoigne', + 'Noy', + 'Hulon', + 'Michele', + 'Crowden', + 'Dolton', + 'Ryner', + 'Gene', + 'Tetterton', + 'Laffitte', + 'Laidler', + 'Hoston', + 'Akter', + 'Biebel', + 'Bohnenkamp', + 'Bottger', + 'Brecheisen', + 'Bumbarger', + 'Burgert', + 'Burtnett', + 'Coffing', + 'Corigliano', + 'Dault', + 'Dettinger', + 'Fenech', + 'Golaszewski', + 'Hernando', + 'Hoppel', + 'Kadrmas', + 'Khim', + 'Labrado', + 'Leh', + 'Michiels', + 'Milkovich', + 'Mosel', + 'Nestle', + 'Nunan', + 'Palomarez', + 'Peretz', + 'Perno', + 'Popowski', + 'Pottebaum', + 'Rallis', + 'Rase', + 'Rotramel', + 'Sokolik', + 'Sparlin', + 'Zipf', + 'Abruzzese', + 'Branin', + 'Cheslock', + 'Chimenti', + 'Czechowski', + 'Diveley', + 'Eisenbeis', + 'Eisenhut', + 'Friedt', + 'Gehlhausen', + 'Kamphaus', + 'Mctiernan', + 'Monnett', + 'Schue', + 'Steffensmeier', + 'Gens', + 'Schlotterbeck', + 'Ask', + 'Leser', + 'Renville', + 'Wisenbaker', + 'Kellow', + 'Mounsey', + 'Dupin', + 'Causer', + 'Yapp', + 'Stmary', + 'Bowditch', + 'Nickolson', + 'Molla', + 'Larke', + 'Kamau', + 'Cardinali', + 'Deely', + 'Deep', + 'Dietel', + 'Ferraris', + 'Fons', + 'Hahm', + 'Huy', + 'Imber', + 'Leichliter', + 'Longanecker', + 'Lordi', + 'Ludewig', + 'Maiolo', + 'Mckern', + 'Meyering', + 'Muhl', + 'Nylen', + 'Ohlendorf', + 'Palmgren', + 'Raffield', + 'Reusser', + 'Revette', + 'Ridolfi', + 'Rosemeyer', + 'Seber', + 'Silberberg', + 'Sitzmann', + 'Tayman', + 'Tygart', + 'Vertz', + 'Volkmer', + 'Bellemare', + 'Benanti', + 'Bialecki', + 'Biber', + 'Dipierro', + 'Dornbush', + 'Eichhorst', + 'Messana', + 'Neisen', + 'Ottoson', + 'Salmonson', + 'Turcott', + 'Vlachos', + 'Wojdyla', + 'Dagg', + 'Hernan', + 'Mannes', + 'Fent', + 'Tappen', + 'Hyers', + 'Gery', + 'Deam', + 'Channing', + 'Gesner', + 'Swaringen', + 'Lakins', + 'Cogbill', + 'Allsbrook', + 'Kennemore', + 'Sumrell', + 'Luma', + 'Rookard', + 'Shakoor', + 'Philbert', + 'Maragh', + 'Wordlaw', + 'Ofori', + 'Arseneault', + 'Arslanian', + 'Aydin', + 'Balthaser', + 'Bensch', + 'Boord', + 'Botting', + 'Brummet', + 'Cassiday', + 'Chubbuck', + 'Crance', + 'Dobis', + 'Dymek', + 'Kakar', + 'Kipnis', + 'Kooi', + 'Kovack', + 'Malzahn', + 'Melendes', + 'Micucci', + 'Miklas', + 'Molander', + 'Nungesser', + 'Razavi', + 'Reppond', + 'Reznick', + 'Rosten', + 'Schwegler', + 'Sielaff', + 'Sincavage', + 'Soave', + 'Socorro', + 'Tausch', + 'Tracz', + 'Vey', + 'Weltman', + 'Wittich', + 'Emswiler', + 'Etzkorn', + 'Kuchenbecker', + 'Lampi', + 'Pfahler', + 'Thronson', + 'Trefz', + 'Pont', + 'Hendrie', + 'Russon', + 'Coleson', + 'Gregori', + 'Herzfeld', + 'Tamas', + 'Oslin', + 'Warrell', + 'Basher', + 'Elizabeth', + 'Nickolas', + 'Prigmore', + 'Okray', + 'Cannedy', + 'Mercy', + 'Daigre', + 'Leggins', + 'Savannah', + 'Russaw', + 'Opoku', + 'Angier', + 'Behrle', + 'Budny', + 'Cislo', + 'Covalt', + 'Dershem', + 'Devincent', + 'Dhar', + 'Dombrosky', + 'Dragovich', + 'Drobny', + 'Fess', + 'Genthner', + 'Gierhart', + 'Hadzic', + 'Hehir', + 'Henle', + 'Heyd', + 'Hudlow', + 'Janko', + 'Kapral', + 'Kietzman', + 'Malburg', + 'Maret', + 'Mcever', + 'Sann', + 'Scheidel', + 'Schultheiss', + 'Sedita', + 'Sigl', + 'Starace', + 'Stoklosa', + 'Tainter', + 'Tamburrino', + 'Vankleeck', + 'Vannucci', + 'Wernecke', + 'Widmayer', + 'Agresti', + 'Boshell', + 'Dartt', + 'Dobkin', + 'Effertz', + 'Gaydosh', + 'Hocevar', + 'Kluger', + 'Mcguffee', + 'Pekala', + 'Tuchman', + 'Keylon', + 'Pletz', + 'Germond', + 'Keedy', + 'Meir', + 'Tromp', + 'Solly', + 'Baerga', + 'Jawad', + 'Chanda', + 'Scobie', + 'Snowball', + 'Pricer', + 'Graper', + 'Bally', + 'Mcfarlan', + 'Duncombe', + 'Mccory', + 'Costen', + 'Poplar', + 'Denkins', + 'Padmore', + 'Waithe', + 'Adduci', + 'Aldaba', + 'Berhow', + 'Cocuzza', + 'Dubroc', + 'Earnheart', + 'Eickholt', + 'Gutzwiller', + 'Heavin', + 'Himebaugh', + 'Jakubik', + 'Kiang', + 'Klusman', + 'Knueppel', + 'Neddo', + 'Oakey', + 'Rachlin', + 'Spegal', + 'Spizzirri', + 'Stavola', + 'Zika', + 'Beverlin', + 'Boehle', + 'Caltagirone', + 'Chernick', + 'Ciaccia', + 'Courchaine', + 'Covault', + 'Crihfield', + 'Fojtik', + 'Gronski', + 'Huwe', + 'Ostrovsky', + 'Quraishi', + 'Rauber', + 'Scalici', + 'Schuetze', + 'Advani', + 'Galer', + 'Rog', + 'Husson', + 'Karpen', + 'Ess', + 'Henman', + 'Slatten', + 'Bango', + 'Barkin', + 'Vessell', + 'Mayson', + 'Kittles', + 'Quince', + 'Beardmore', + 'Breceda', + 'Carmony', + 'Ciliberto', + 'Cotroneo', + 'Dimitroff', + 'Granahan', + 'Haacke', + 'Huska', + 'Jankiewicz', + 'Klipp', + 'Kostic', + 'Langarica', + 'Lanphier', + 'Maran', + 'Marmion', + 'Mclinden', + 'Mcpeake', + 'Minkel', + 'Nicolo', + 'Quihuis', + 'Siemsen', + 'Somero', + 'Spuhler', + 'Spychalski', + 'Stary', + 'Stitzer', + 'Stucke', + 'Tango', + 'Ticas', + 'Vivero', + 'Campen', + 'Fei', + 'Ganas', + 'Klipfel', + 'Vodicka', + 'Zajdel', + 'Ulin', + 'Bodey', + 'Moral', + 'Fellenz', + 'Charo', + 'Cliver', + 'Clasby', + 'Neeson', + 'Durell', + 'Hew', + 'Mcgray', + 'Breaker', + 'Haslem', + 'Verser', + 'Broner', + 'Mannings', + 'Darensbourg', + 'Petithomme', + 'Akbari', + 'Amdahl', + 'Boeger', + 'Bougie', + 'Buffo', + 'Cisar', + 'Deleonardis', + 'Diffee', + 'Dillen', + 'Dingley', + 'Dugo', + 'Fedora', + 'Habibi', + 'Hartland', + 'Hennelly', + 'Kachmar', + 'Louth', + 'Mughal', + 'Muska', + 'Narang', + 'Pontillo', + 'Roel', + 'Shehorn', + 'Smick', + 'Soliven', + 'Starzyk', + 'Swaminathan', + 'Teagarden', + 'Thune', + 'Vokes', + 'Volkov', + 'Weckesser', + 'Wigen', + 'Donaghue', + 'Ederer', + 'Glaus', + 'Gwozdz', + 'Kimler', + 'Kocak', + 'Lagerquist', + 'Pellecchia', + 'Ruminski', + 'Scholler', + 'Steurer', + 'Tlatelpa', + 'Zegarra', + 'Janssens', + 'Jass', + 'Ciriaco', + 'Kessner', + 'Georg', + 'Harre', + 'Brannam', + 'Beel', + 'Kaine', + 'Roher', + 'Evora', + 'Rittman', + 'Sion', + 'Millon', + 'Morre', + 'Bouler', + 'Seegars', + 'Jenifer', + 'Bernd', + 'Chahine', + 'Crisanto', + 'Desautel', + 'Dirosa', + 'Fehringer', + 'Fukui', + 'Hetz', + 'Hueber', + 'Ivanova', + 'Klecker', + 'Kulzer', + 'Machi', + 'Menn', + 'Mudry', + 'Niro', + 'Nyenhuis', + 'Pressel', + 'Prusinski', + 'Roske', + 'Shaefer', + 'Stear', + 'Stumpo', + 'Teas', + 'Tolsma', + 'Troha', + 'Vanveen', + 'Waltermire', + 'Zaretsky', + 'Zingg', + 'Arntson', + 'Dizdarevic', + 'Kassebaum', + 'Natzke', + 'Passanisi', + 'Rodebaugh', + 'Skonieczny', + 'Vanhoozer', + 'Wiechert', + 'Golonka', + 'Roycroft', + 'Robl', + 'Lisboa', + 'Brandis', + 'Symmes', + 'Nou', + 'Pawson', + 'Comins', + 'Ranker', + 'Silman', + 'Lonas', + 'Goldthwaite', + 'Aries', + 'Leckey', + 'Conolly', + 'Ezelle', + 'Degrasse', + 'Tarte', + 'Bonaventure', + 'Rambeau', + 'Alsobrooks', + 'Blumenberg', + 'Snape', + 'Delane', + 'Sarr', + 'Rankine', + 'Mcclarty', + 'Skipwith', + 'Mapps', + 'Poke', + 'Ahlman', + 'Brunkow', + 'Crissinger', + 'Critcher', + 'Cronce', + 'Earney', + 'Fischler', + 'Franta', + 'Haist', + 'Hirschfield', + 'Jacobe', + 'Karraker', + 'Kronenberger', + 'Layland', + 'Liscano', + 'Lohrman', + 'Luy', + 'Macik', + 'Makinen', + 'Mis', + 'Musarra', + 'Orbe', + 'Ortloff', + 'Potempa', + 'Presta', + 'Rebollo', + 'Rudden', + 'Schab', + 'Settlemyre', + 'Shaban', + 'Shiraishi', + 'Shrake', + 'Suba', + 'Tornquist', + 'Treglia', + 'Vanschaick', + 'Velten', + 'Waln', + 'Addeo', + 'Dacquisto', + 'Fenno', + 'Gilberg', + 'Halberstam', + 'Holck', + 'Landgrebe', + 'Lipa', + 'Luehrs', + 'Mkrtchyan', + 'Proscia', + 'Schucker', + 'Selner', + 'Sinisi', + 'Wandersee', + 'Weigold', + 'Winterrowd', + 'Stoutenburg', + 'Medinger', + 'Bittman', + 'Gerges', + 'Langelier', + 'Berdine', + 'Hartshorne', + 'Matters', + 'Lavere', + 'Delauter', + 'Caillouet', + 'Elford', + 'Derrington', + 'Mollison', + 'Erskin', + 'Doswell', + 'Loadholt', + 'Stepter', + 'Contee', + 'Adwell', + 'Banez', + 'Birchler', + 'Bodman', + 'Bransfield', + 'Butzer', + 'Cenci', + 'Fabro', + 'Fila', + 'Follman', + 'Geoffrion', + 'Hardegree', + 'Klindt', + 'Kuzniar', + 'Lapenta', + 'Lasorsa', + 'Lykens', + 'Madariaga', + 'Mcginnity', + 'Mezger', + 'Milleson', + 'Nisly', + 'Palau', + 'Salz', + 'Sholly', + 'Spartz', + 'Spevak', + 'Svehla', + 'Trafford', + 'Treu', + 'Winski', + 'Zervas', + 'Bautch', + 'Dybas', + 'Hillenburg', + 'Krahl', + 'Loretto', + 'Mcanany', + 'Meschke', + 'Panuco', + 'Pezzullo', + 'Pokorski', + 'Reinertson', + 'Spoden', + 'Steinbrenner', + 'Wedig', + 'Mom', + 'Furner', + 'Harpin', + 'Carlston', + 'Oo', + 'Betten', + 'Duro', + 'Veronica', + 'Klutz', + 'Coven', + 'Siles', + 'Carby', + 'Duvernay', + 'Gory', + 'Adamczak', + 'Adee', + 'Agius', + 'Bachicha', + 'Belka', + 'Bridenstine', + 'Cappella', + 'Chiao', + 'Georgiadis', + 'Hansmann', + 'Kettlewell', + 'Klemann', + 'Kracke', + 'Legacy', + 'Mateja', + 'Mcgarrigle', + 'Peitz', + 'Pergande', + 'Proia', + 'Reicher', + 'Rentfrow', + 'Rudkin', + 'Sahni', + 'Santopietro', + 'Sarin', + 'Schear', + 'Seckel', + 'Sopp', + 'Sorci', + 'Terbush', + 'Uplinger', + 'Vantol', + 'Zaro', + 'Cuppett', + 'Depetro', + 'Hofferber', + 'Kreifels', + 'Kuznetsov', + 'Matassa', + 'Mazanec', + 'Naegle', + 'Sphar', + 'Villaneda', + 'Wachholz', + 'Pastrano', + 'Pilotte', + 'Shedden', + 'Molt', + 'Dalia', + 'Bishara', + 'Dumoulin', + 'Dehnert', + 'Dilmore', + 'Termine', + 'Bracher', + 'Laplace', + 'Sherin', + 'Morine', + 'Garrott', + 'Banford', + 'Drumwright', + 'Linnen', + 'Belay', + 'Juste', + 'Moment', + 'Adamec', + 'Alessandrini', + 'Bolda', + 'Buonanno', + 'Corrow', + 'Couvillon', + 'Dahnke', + 'Durrani', + 'Errett', + 'Fingerhut', + 'Ittner', + 'Kandler', + 'Khosla', + 'Mascio', + 'Mesch', + 'Napolitan', + 'Packman', + 'Parady', + 'Saline', + 'Spatafore', + 'Squiers', + 'Stailey', + 'Stolar', + 'Strommen', + 'Vahey', + 'Vanbebber', + 'Wimpee', + 'Wolinsky', + 'Yambao', + 'Ciocca', + 'Fornwalt', + 'Giannattasio', + 'Herbers', + 'Korol', + 'Lindenberger', + 'Lysne', + 'Piacentini', + 'Vogeler', + 'Cassetta', + 'Hildebran', + 'Masoud', + 'Shiller', + 'Fisler', + 'Loll', + 'Wattles', + 'Carris', + 'Hippe', + 'Torregrossa', + 'Thain', + 'Enman', + 'Kanno', + 'Jeane', + 'Clendenning', + 'Halt', + 'Dorin', + 'Carnathan', + 'Bisch', + 'Simm', + 'Goatley', + 'July', + 'Oke', + 'Basley', + 'Dillahunt', + 'Times', + 'Mcglown', + 'Cohens', + 'Jeanphilippe', + 'Benshoof', + 'Bensing', + 'Bir', + 'Birnie', + 'Burklow', + 'Capili', + 'Cordts', + 'Falanga', + 'Farooqui', + 'Furber', + 'Godino', + 'Gollnick', + 'Harmening', + 'Hilpert', + 'Hrivnak', + 'Iribe', + 'Krienke', + 'Kuntzman', + 'Laslo', + 'Loso', + 'Omohundro', + 'Rabadi', + 'Reisenauer', + 'Rohrich', + 'Salak', + 'Schuckman', + 'Semmel', + 'Sendelbach', + 'Sidler', + 'Stegmann', + 'Sudbeck', + 'Tara', + 'Walcher', + 'Walkenhorst', + 'Wellbrock', + 'Capaldo', + 'Cotnoir', + 'Durrence', + 'Fralix', + 'Leibfried', + 'Schlarb', + 'Whitenight', + 'Grannan', + 'Mugford', + 'Filo', + 'Soh', + 'Deprez', + 'Semidey', + 'Vandivier', + 'Shawl', + 'Happy', + 'Gartley', + 'Jonathan', + 'Bouquet', + 'Warsaw', + 'Verne', + 'Furse', + 'Holms', + 'Bassette', + 'Fishburne', + 'Ambrosius', + 'Amrein', + 'Astorino', + 'Bedonie', + 'Bibee', + 'Brearley', + 'Chesher', + 'Colasurdo', + 'Deike', + 'Dimarino', + 'Felling', + 'Freid', + 'Gad', + 'Gambale', + 'Gieser', + 'Greff', + 'Halseth', + 'Hamor', + 'Hargens', + 'Hohenberger', + 'Hohler', + 'Illes', + 'Koscielniak', + 'Kotara', + 'Krygier', + 'Lopinto', + 'Mangas', + 'Mantione', + 'Mcendree', + 'Musich', + 'Nordling', + 'Panagopoulos', + 'Pollio', + 'Score', + 'Semaan', + 'Tortorelli', + 'Trabert', + 'Troung', + 'Vittorio', + 'Barkdoll', + 'Dombeck', + 'Ferriter', + 'Gancarz', + 'Gubbels', + 'Kertz', + 'Langenderfer', + 'Roppolo', + 'Siglin', + 'Trnka', + 'Vanderkooi', + 'Yaun', + 'Witkin', + 'Caryl', + 'Boies', + 'Carattini', + 'Hannes', + 'Harmison', + 'Mctavish', + 'Bille', + 'Sullivant', + 'Yeakey', + 'Respess', + 'Gooley', + 'Maura', + 'Jukes', + 'Oguin', + 'Demory', + 'Morson', + 'Hathorne', + 'Anklam', + 'Antaya', + 'Bentler', + 'Bettcher', + 'Bresette', + 'Broadrick', + 'Degante', + 'Demaray', + 'Dipinto', + 'Doberstein', + 'Dorminey', + 'Dorwart', + 'Gugliuzza', + 'Jesser', + 'Kjar', + 'Kujala', + 'Lemarr', + 'Lynds', + 'Novitsky', + 'Oropesa', + 'Scarpulla', + 'Schave', + 'Siravo', + 'Torma', + 'Uva', + 'Winkowski', + 'Boscia', + 'Buikema', + 'Byland', + 'Enneking', + 'Enstrom', + 'Gotsch', + 'Kulakowski', + 'Mattheis', + 'Niemuth', + 'Oberdorf', + 'Rabuck', + 'Shinners', + 'Struebing', + 'Dickes', + 'Hettrick', + 'Pille', + 'Vilar', + 'Blewitt', + 'Gutt', + 'Haseley', + 'Pennel', + 'Figuereo', + 'Lassalle', + 'Tannahill', + 'Teats', + 'Mumby', + 'Cheves', + 'Spark', + 'Ale', + 'Wally', + 'Lowndes', + 'Ballo', + 'Couper', + 'Alberta', + 'Puller', + 'Rochell', + 'Bachar', + 'Ballengee', + 'Bellizzi', + 'Boback', + 'Cammarano', + 'Dirr', + 'Findling', + 'Fruin', + 'Ghattas', + 'Kaliszewski', + 'Kammeyer', + 'Kwiecien', + 'Lamora', + 'Lehrke', + 'Macewen', + 'Nasta', + 'Neibert', + 'Ogaz', + 'Olesky', + 'Otano', + 'Prescher', + 'Romick', + 'Scibetta', + 'Slicker', + 'Ungerer', + 'Vanheel', + 'Wadas', + 'Weissert', + 'Armiger', + 'Brusca', + 'Christeson', + 'Crookshanks', + 'Demarinis', + 'Fahrney', + 'Heiple', + 'Howat', + 'Knoedler', + 'Kuske', + 'Leifheit', + 'Lukach', + 'Nauert', + 'Obremski', + 'Seidenberg', + 'Smigelski', + 'Visscher', + 'Wauneka', + 'Whitmoyer', + 'Wyand', + 'Ilardi', + 'Jackel', + 'Rackham', + 'Macgowan', + 'Braid', + 'Bringle', + 'Dirk', + 'Paci', + 'Wears', + 'Vanbergen', + 'Sidle', + 'Mellish', + 'Paino', + 'State', + 'Cargle', + 'Harcum', + 'Beyene', + 'Mwangi', + 'Anderle', + 'Cancienne', + 'Compeau', + 'Egle', + 'Farone', + 'Harke', + 'Hollopeter', + 'Jambor', + 'Jermyn', + 'Kadakia', + 'Kerker', + 'Langowski', + 'Lechman', + 'Nagengast', + 'Narvaiz', + 'Paola', + 'Partch', + 'Plucker', + 'Rawe', + 'Rohland', + 'Rosebrook', + 'Stanphill', + 'Stoltman', + 'Volkers', + 'Balingit', + 'Bausman', + 'Besler', + 'Dalto', + 'Edgren', + 'Hairfield', + 'Janek', + 'Kenoyer', + 'Koska', + 'Mihok', + 'Monjaraz', + 'Reisz', + 'Snedegar', + 'Vandezande', + 'Viscomi', + 'Kiene', + 'Dib', + 'Kuc', + 'Magley', + 'Swearingin', + 'Culliton', + 'Roome', + 'Fendrick', + 'Trindade', + 'Whaling', + 'Tarbutton', + 'Sider', + 'Swingler', + 'Lover', + 'Clarida', + 'Jocelyn', + 'Mervin', + 'Blaize', + 'Semper', + 'Bagsby', + 'Pree', + 'Dieujuste', + 'Anacleto', + 'Annable', + 'Bacci', + 'Bottari', + 'Cinco', + 'Delzell', + 'Dowless', + 'Drilling', + 'Egert', + 'Fanton', + 'Geerts', + 'Ghaffari', + 'Guggenheim', + 'Hankes', + 'Hediger', + 'Hornig', + 'Kauer', + 'Kossman', + 'Krasnow', + 'Lauman', + 'Lebsack', + 'Liendo', + 'Marhefka', + 'Noguez', + 'Oxman', + 'Pa', + 'Pella', + 'Pongratz', + 'Prisk', + 'Rajagopalan', + 'Rozo', + 'Vanvorst', + 'Wachob', + 'Avolio', + 'Banet', + 'Boissonneault', + 'Coglianese', + 'Crudele', + 'Dobratz', + 'Gerdts', + 'Koors', + 'Mazzanti', + 'Ozimek', + 'Vanhove', + 'Zern', + 'Kalama', + 'Mikelson', + 'Renehan', + 'Blecher', + 'Meath', + 'Bonus', + 'Wesch', + 'Kirkey', + 'Goldbeck', + 'Hun', + 'Morgans', + 'Strohman', + 'Lanagan', + 'Wyly', + 'Syers', + 'Berne', + 'Tondreau', + 'Witts', + 'Budhu', + 'Flott', + 'Alsbrooks', + 'Mabin', + 'Kingsberry', + 'Berend', + 'Brandeberry', + 'Carandang', + 'Ciavarella', + 'Foil', + 'Galano', + 'Garzia', + 'Golembeski', + 'Kossow', + 'Kren', + 'Lefave', + 'Macmahon', + 'Nilan', + 'Peregrina', + 'Pralle', + 'Sahakian', + 'Sarate', + 'Scalzi', + 'Soulliere', + 'Srock', + 'Stammen', + 'Sterry', + 'Tadych', + 'Trembath', + 'Watwood', + 'Wolske', + 'Woolson', + 'Aversano', + 'Chavana', + 'Digiuseppe', + 'Escano', + 'Harkrider', + 'Liebmann', + 'Soldan', + 'Swiatkowski', + 'Tomala', + 'Keay', + 'Lindstedt', + 'Maille', + 'Thurner', + 'Favia', + 'Guedes', + 'Simao', + 'Rambow', + 'Chriscoe', + 'Hiss', + 'Mcraney', + 'Barke', + 'Hobday', + 'Buri', + 'Sigle', + 'Bawa', + 'Lalande', + 'Bordon', + 'Friley', + 'Feild', + 'Arington', + 'Jons', + 'Funderburke', + 'Mccommons', + 'Troublefield', + 'Mable', + 'Hullum', + 'Wrice', + 'Cager', + 'Barse', + 'Braunschweig', + 'Dasch', + 'Fraioli', + 'Giefer', + 'Giovanniello', + 'Glahn', + 'Hatheway', + 'Holtrop', + 'Katsaros', + 'Koetting', + 'Malinoski', + 'Markov', + 'Mcclosky', + 'Mccormac', + 'Mertins', + 'Milito', + 'Mroczka', + 'Overdorf', + 'Palombi', + 'Peninger', + 'Provenza', + 'Quinnell', + 'Roady', + 'Ruthven', + 'Savitsky', + 'Shenefield', + 'Stapel', + 'Venkataraman', + 'Zachow', + 'Aaberg', + 'Bajorek', + 'Bankowski', + 'Barquero', + 'Delcamp', + 'Deshler', + 'Halili', + 'Hebenstreit', + 'Hirota', + 'Hladky', + 'Kliethermes', + 'Koestner', + 'Kroes', + 'Luepke', + 'Mckeough', + 'Mielcarek', + 'Nobis', + 'Olenik', + 'Plessinger', + 'Shillingburg', + 'Spadaccini', + 'Springborn', + 'Werden', + 'Willenbring', + 'Zyskowski', + 'Paucar', + 'Werst', + 'Wohlwend', + 'Nauss', + 'Alma', + 'Tebeau', + 'Paskett', + 'Spindle', + 'Twiddy', + 'Alomar', + 'Mi', + 'Billard', + 'Bails', + 'Channer', + 'Fripp', + 'Abreo', + 'Adamowicz', + 'Bocian', + 'Breden', + 'Breitkreutz', + 'Celona', + 'Chizek', + 'Chrestman', + 'Ciaramella', + 'Compher', + 'Crannell', + 'Dermer', + 'Duryee', + 'Feuerborn', + 'Garrels', + 'Gausman', + 'Grippi', + 'Guadamuz', + 'Hatlestad', + 'Heon', + 'Hokenson', + 'Kaden', + 'Kluever', + 'Lagares', + 'Mamone', + 'Mascola', + 'Matich', + 'Messimer', + 'Mezera', + 'Mongiello', + 'Moradi', + 'Nessler', + 'Nijjar', + 'Nin', + 'Pasquarelli', + 'Pawlowicz', + 'Petitto', + 'Petruccelli', + 'Pullano', + 'Rebar', + 'Romack', + 'Rosener', + 'Soland', + 'Solow', + 'Vandervelden', + 'Vazguez', + 'Vonruden', + 'Balmes', + 'Berninger', + 'Broecker', + 'Clogston', + 'Fontanella', + 'Gubbins', + 'Kampen', + 'Levenhagen', + 'Lyter', + 'Nagamine', + 'Regas', + 'Riecke', + 'Veltre', + 'Wojahn', + 'Angelino', + 'Mccomber', + 'Grisso', + 'Saran', + 'Pecore', + 'Sorter', + 'Encalada', + 'Robart', + 'Deerman', + 'Lori', + 'Mcnee', + 'Dagher', + 'Villars', + 'Chaplain', + 'Houtman', + 'Dingwall', + 'Akerson', + 'Donaway', + 'Dimmer', + 'Mittman', + 'Camm', + 'Kenedy', + 'Bilbro', + 'Brocks', + 'Mansaray', + 'Acebo', + 'Ahr', + 'Alayon', + 'Benyo', + 'Blatnik', + 'Degidio', + 'Dumire', + 'Elefante', + 'Gase', + 'Gilboy', + 'Gradillas', + 'Haverstock', + 'Heberle', + 'Hilmes', + 'Hjort', + 'Johnsey', + 'Lambiase', + 'Marland', + 'Mcevilly', + 'Mergenthaler', + 'Mini', + 'Noska', + 'Patrie', + 'Rohrback', + 'Seelbach', + 'Stopher', + 'Trzaska', + 'Vanessen', + 'Veillette', + 'Walizer', + 'Zapalac', + 'Andalon', + 'Beukema', + 'Cieslik', + 'Dukart', + 'Gerads', + 'Gilhooly', + 'Hinebaugh', + 'Jumonville', + 'Macchi', + 'Oldenkamp', + 'Plotz', + 'Robideau', + 'Streed', + 'Trochez', + 'Grames', + 'Beltram', + 'Fishbaugh', + 'Lais', + 'Ossa', + 'Wilden', + 'Erick', + 'Dosier', + 'Trust', + 'Swaine', + 'Darity', + 'Mccroy', + 'Yuille', + 'Cantave', + 'Barsanti', + 'Carbonara', + 'Cavanah', + 'Chrismer', + 'Cuestas', + 'Czaplewski', + 'Denes', + 'Dorio', + 'Geraldo', + 'Giebler', + 'Goewey', + 'Gorniak', + 'Grabe', + 'Guidera', + 'Hannig', + 'Herin', + 'Kadow', + 'Klauer', + 'Kleppinger', + 'Lerro', + 'Manoogian', + 'Mentzel', + 'Muramoto', + 'Ollinger', + 'Pacey', + 'Pufahl', + 'Quero', + 'Revuelta', + 'Rickles', + 'Rudie', + 'Ruggerio', + 'Salberg', + 'Schwoerer', + 'Stephani', + 'Stevick', + 'Strada', + 'Thorley', + 'Thrun', + 'Virts', + 'Wingett', + 'Balfe', + 'Branaman', + 'Brookshier', + 'Carlsson', + 'Chismar', + 'Habben', + 'Migdal', + 'Ozga', + 'Rivest', + 'Russman', + 'Schellhorn', + 'Staup', + 'Pietri', + 'Welby', + 'Cisney', + 'Hijazi', + 'Brines', + 'Calderin', + 'Mudrick', + 'Domine', + 'Parlow', + 'Ervine', + 'Banis', + 'Mathenia', + 'Carbin', + 'Rashed', + 'Mcgilvery', + 'Prichett', + 'Feimster', + 'Smoots', + 'Persley', + 'Desire', + 'Abadi', + 'Bercaw', + 'Bertz', + 'Bibian', + 'Brosious', + 'Brunken', + 'Calvano', + 'Chenette', + 'Chiusano', + 'Dendinger', + 'Diffley', + 'Eichenberg', + 'Gawne', + 'Gelardi', + 'Gottman', + 'Gulyas', + 'Hak', + 'Haydock', + 'Hettler', + 'Hinsch', + 'Kozlik', + 'Krebbs', + 'Krichbaum', + 'Loges', + 'Lyssy', + 'Mitnick', + 'Podolski', + 'Priego', + 'Radhakrishnan', + 'Reineck', + 'Ruggirello', + 'Samborski', + 'Schwalb', + 'Sitek', + 'Sprinkel', + 'Tkachuk', + 'Viscuso', + 'Working', + 'Zinner', + 'Anspaugh', + 'Anthes', + 'Bratsch', + 'Breining', + 'Cejka', + 'Delbuono', + 'Hugill', + 'Huyett', + 'Irlbeck', + 'Kilgus', + 'Langwell', + 'Margulis', + 'Meara', + 'Napierala', + 'Stanaway', + 'Worton', + 'Gaucher', + 'Bakeman', + 'Pasos', + 'Feazel', + 'Evitt', + 'Marrin', + 'Baskette', + 'Orne', + 'Ivens', + 'Burnstein', + 'Rodell', + 'Bowell', + 'Maraj', + 'Lango', + 'Boudoin', + 'Wider', + 'Walkins', + 'Raheem', + 'Talford', + 'Jeanmarie', + 'Drumgoole', + 'Arnot', + 'Bennick', + 'Buchinger', + 'Cleven', + 'Corsello', + 'Delucchi', + 'Dicocco', + 'Eachus', + 'Eilts', + 'Fandino', + 'Fyke', + 'Giammarco', + 'Gwartney', + 'Hawken', + 'Henkelman', + 'Jaggi', + 'Jurczyk', + 'Kamman', + 'Kattner', + 'Keator', + 'Klus', + 'Leidner', + 'Ligas', + 'Martus', + 'Maslow', + 'Piccinini', + 'Pysher', + 'Riga', + 'Siek', + 'Sizelove', + 'Vanostrand', + 'Vastine', + 'Viviani', + 'Youngerman', + 'Zahniser', + 'Brigante', + 'Burklund', + 'Cajina', + 'Coppolino', + 'Goytia', + 'Icenhower', + 'Ihnen', + 'Jablonsky', + 'Koepsell', + 'Mennenga', + 'Redenius', + 'Tengan', + 'Weishaupt', + 'Dorst', + 'Kief', + 'Busk', + 'Luba', + 'Quine', + 'Deshotels', + 'Roulston', + 'Diniz', + 'Chandley', + 'Saleeby', + 'Maro', + 'Faidley', + 'Burrous', + 'Ilyas', + 'Roster', + 'Clovis', + 'Bacot', + 'Pembleton', + 'Bellot', + 'Entzminger', + 'Ryce', + 'Posley', + 'Alvi', + 'Audino', + 'Bitters', + 'Boomershine', + 'Boyack', + 'Branda', + 'Bresnan', + 'Brusco', + 'Bunda', + 'Catanzarite', + 'Dohmen', + 'Elbaum', + 'Farago', + 'Ferrentino', + 'Gimpel', + 'Grzeskowiak', + 'Gutting', + 'Henandez', + 'Herbeck', + 'Hoben', + 'Hunnell', + 'Ibbotson', + 'Kida', + 'Kirchman', + 'Kubin', + 'Laplume', + 'Laskin', + 'Lefferts', + 'Leimer', + 'Locatelli', + 'Pitsenbarger', + 'Reum', + 'Rittgers', + 'Scadden', + 'Shammas', + 'Tatge', + 'Tiongson', + 'Wengler', + 'Wenrick', + 'Wortley', + 'Bretado', + 'Detloff', + 'Dlugosz', + 'Eisemann', + 'Embler', + 'Graffius', + 'Kienast', + 'Kucher', + 'Larew', + 'Lemmerman', + 'Maners', + 'Peckinpaugh', + 'Rupnow', + 'Schubring', + 'Staheli', + 'Stege', + 'Talwar', + 'Truszkowski', + 'Coda', + 'Comunale', + 'Holtry', + 'Newfield', + 'Blankley', + 'Devino', + 'Wahba', + 'Cathell', + 'Timson', + 'Setzler', + 'Shacklett', + 'Nicols', + 'Rocque', + 'Nest', + 'Freelove', + 'Neat', + 'Kina', + 'Caslin', + 'Creal', + 'Wyre', + 'Compere', + 'Brisker', + 'Givhan', + 'Menifee', + 'Hymon', + 'Boakye', + 'Aguillar', + 'Alpern', + 'Antico', + 'Attridge', + 'Bjorge', + 'Bordwell', + 'Brumbach', + 'Castronova', + 'Cowher', + 'Fakhouri', + 'Hanigan', + 'Heidecker', + 'Hosick', + 'Lorang', + 'Magadan', + 'Marovich', + 'Masur', + 'Nienow', + 'Passow', + 'Priola', + 'Prose', + 'Radillo', + 'Saracco', + 'Schlender', + 'Sellards', + 'Stirn', + 'Strathman', + 'Supan', + 'Taguchi', + 'Tufte', + 'Vanderleest', + 'Vanderpoel', + 'Vondra', + 'Wayment', + 'Wisinski', + 'Brodowski', + 'Cichowski', + 'Delarocha', + 'Demyan', + 'Dobies', + 'Hegner', + 'Karapetian', + 'Konieczka', + 'Lazarz', + 'Loughner', + 'Portanova', + 'Rosentreter', + 'Rothlisberger', + 'Schropp', + 'Trenkamp', + 'Flaharty', + 'Murfin', + 'Waner', + 'Baiz', + 'Dunegan', + 'Gillson', + 'Erne', + 'Mahin', + 'Hardgrave', + 'Felps', + 'Bevens', + 'Abdou', + 'Songy', + 'Boule', + 'Wisham', + 'Devonshire', + 'Havis', + 'Relf', + 'Pean', + 'Manago', + 'Brazzle', + 'Mckelvin', + 'Goulbourne', + 'Pinkins', + 'Yelder', + 'Akina', + 'Allerton', + 'Aminov', + 'Barsamian', + 'Biondolillo', + 'Bouchillon', + 'Bustle', + 'Dolney', + 'Dunkerley', + 'Farha', + 'Floor', + 'Gaustad', + 'Gilberti', + 'Helder', + 'Kolber', + 'Kuznia', + 'Longhi', + 'Mamaril', + 'Milhorn', + 'Mozo', + 'Norbury', + 'Okano', + 'Perkovich', + 'Rafanan', + 'Rulo', + 'Ruperto', + 'Scow', + 'Shadoan', + 'Smisek', + 'Steinfeldt', + 'Thobe', + 'Venturino', + 'Widell', + 'Broccoli', + 'Helmig', + 'Koegler', + 'Lewandoski', + 'Pequignot', + 'Radermacher', + 'Resetar', + 'Rostro', + 'Sebald', + 'Walgren', + 'Lottes', + 'Capraro', + 'Grine', + 'Gordner', + 'Crus', + 'Easom', + 'Bayle', + 'Barts', + 'Duguid', + 'Estel', + 'Peggs', + 'Cheaney', + 'Rossin', + 'Mackel', + 'Vassel', + 'Fils', + 'Senat', + 'Alarie', + 'Allar', + 'Brownlie', + 'Bumbaugh', + 'Caissie', + 'Cordone', + 'Critser', + 'Delconte', + 'Falzon', + 'Formosa', + 'Frerking', + 'Gadea', + 'Ganem', + 'Guzek', + 'Hauch', + 'Heese', + 'Hemmen', + 'Holzschuh', + 'Impson', + 'Jablon', + 'Kiedrowski', + 'Krob', + 'Kuhnle', + 'Laake', + 'Larouche', + 'Leaton', + 'Leyland', + 'Lorenson', + 'Macduff', + 'Maready', + 'Newberger', + 'Ohnstad', + 'Pinela', + 'Polino', + 'Postema', + 'Pyon', + 'Radziewicz', + 'Rathod', + 'Salopek', + 'Salvadore', + 'Sawchuk', + 'Trotto', + 'Vereb', + 'Auslander', + 'Beninati', + 'Blunck', + 'Decandia', + 'Deeney', + 'Escatel', + 'Foskett', + 'Hagmann', + 'Hussar', + 'Jakubek', + 'Kluender', + 'Mcelhinny', + 'Salatino', + 'Sangalang', + 'Schoenfeldt', + 'Stogdill', + 'Svitak', + 'Taravella', + 'Tezak', + 'Wieseler', + 'Komperda', + 'Reinitz', + 'Malis', + 'Duce', + 'Salib', + 'Keelin', + 'Labell', + 'Symmonds', + 'Gwynne', + 'Byus', + 'Burgy', + 'Delfosse', + 'Benskin', + 'Hedgepath', + 'Ursin', + 'Kinnebrew', + 'Tinnon', + 'Callum', + 'Allah', + 'Arduini', + 'Azucena', + 'Birkel', + 'Bowermaster', + 'Caires', + 'Chrobak', + 'Cottier', + 'Cropley', + 'Crotteau', + 'Dutan', + 'Ezernack', + 'Fabiani', + 'Fauser', + 'Feeny', + 'Ferdig', + 'Fliss', + 'Gallus', + 'Harlacher', + 'Hasselbach', + 'Honsinger', + 'Landberg', + 'Lohn', + 'Losinski', + 'Maung', + 'Melikian', + 'Nooney', + 'Oyervides', + 'Prum', + 'Riepe', + 'Seebach', + 'Sendejas', + 'Sprick', + 'Torino', + 'Weida', + 'Geschke', + 'Girgenti', + 'Klever', + 'Rathert', + 'Roszell', + 'Sarich', + 'Shimmin', + 'Trimpe', + 'Turrubiates', + 'Zelada', + 'Danzig', + 'Diamant', + 'Hannen', + 'Odland', + 'Puzzo', + 'Slyter', + 'Smaldone', + 'Ebey', + 'Beg', + 'Magel', + 'Tebbs', + 'Gali', + 'Winney', + 'Juba', + 'Stargel', + 'Waren', + 'Stann', + 'Ducasse', + 'Vaugh', + 'Lewers', + 'Stjuste', + 'Heckstall', + 'Bokhari', + 'Bonino', + 'Brummond', + 'Caterino', + 'Deatrick', + 'Decorte', + 'Demara', + 'Dubree', + 'Dulski', + 'Feck', + 'Foglio', + 'Heinzelman', + 'Jory', + 'Knoell', + 'Kronick', + 'Maclay', + 'Mastrogiovanni', + 'Reichling', + 'Rueff', + 'Sellitto', + 'Sensing', + 'Sheu', + 'Soberanes', + 'Stahlecker', + 'Wholey', + 'Yochim', + 'Zeiss', + 'Bojanowski', + 'Bonawitz', + 'Caporaso', + 'Dalesio', + 'Exposito', + 'Giovinazzo', + 'Palardy', + 'Rastogi', + 'Saenger', + 'Sirek', + 'Sonoda', + 'Sovereign', + 'Weimann', + 'Wirtanen', + 'Enerson', + 'Olliff', + 'Kallam', + 'Leggitt', + 'Goude', + 'Rampey', + 'Letsinger', + 'Walles', + 'Kater', + 'Betsill', + 'Creese', + 'Lisbon', + 'Abitz', + 'Bednarik', + 'Bendorf', + 'Berkovich', + 'Brevik', + 'Cassatt', + 'Ciarlo', + 'Cookman', + 'Cosma', + 'Defee', + 'Essner', + 'Fallas', + 'Holda', + 'Kemler', + 'Kovich', + 'Krimmel', + 'Landauer', + 'Meharg', + 'Moncus', + 'Nabi', + 'Redenbaugh', + 'Ruwe', + 'Scalisi', + 'Shughart', + 'Sloma', + 'Sovine', + 'Tomaso', + 'Trueba', + 'Urista', + 'Vanyo', + 'Wolanski', + 'Zettle', + 'Arvanitis', + 'Baeten', + 'Caponi', + 'Carrazco', + 'Galambos', + 'Hartsook', + 'Helseth', + 'Kobylarz', + 'Krugh', + 'Meckel', + 'Ohnemus', + 'Voytek', + 'Winegarden', + 'Zuba', + 'Piloto', + 'Shames', + 'Debella', + 'Keddy', + 'Perra', + 'Winks', + 'Hemrick', + 'Snowdon', + 'Cleere', + 'Leavey', + 'Courington', + 'Herson', + 'Nelon', + 'Bloise', + 'Mcphie', + 'Catledge', + 'Mcneary', + 'Hoffler', + 'Suell', + 'Coard', + 'Woolfork', + 'Biros', + 'Brouhard', + 'Dinovo', + 'Disano', + 'Emami', + 'Flegal', + 'Hardebeck', + 'Hobin', + 'Huttner', + 'Kloosterman', + 'Knutzen', + 'Kopinski', + 'Mailman', + 'Mankey', + 'Mccamish', + 'Mccorquodale', + 'Minichiello', + 'Miyasaki', + 'Osher', + 'Prutzman', + 'Sagen', + 'Shawgo', + 'Sokolow', + 'Southam', + 'Sulik', + 'Wiedel', + 'Wollschlager', + 'Cantalupo', + 'Cruser', + 'Denomme', + 'Dinardi', + 'Donahey', + 'Havlin', + 'Lasecki', + 'Margraf', + 'Mchaffie', + 'Mihaly', + 'Omlor', + 'Roope', + 'Schremp', + 'Vanhecke', + 'Washabaugh', + 'Zaunbrecher', + 'Joost', + 'Pensinger', + 'Kraner', + 'Mikles', + 'Delair', + 'Bukhari', + 'Earll', + 'Sans', + 'Gatliff', + 'Casteneda', + 'Shalom', + 'Fidalgo', + 'Leitao', + 'Degrange', + 'Fruits', + 'Kercheval', + 'Mew', + 'Chopin', + 'Seawood', + 'Agro', + 'Aliano', + 'Badour', + 'Betsch', + 'Buchbinder', + 'Cleavenger', + 'Collazos', + 'Cusmano', + 'Dienes', + 'Dittus', + 'Eggenberger', + 'Fierst', + 'Gingell', + 'Greever', + 'Grisales', + 'Hegstrom', + 'Justen', + 'Kalt', + 'Kirkhart', + 'Krage', + 'Kyzar', + 'Livolsi', + 'Neyhart', + 'Nunziata', + 'Orlich', + 'Parcel', + 'Peshlakai', + 'Schemm', + 'Segner', + 'Urieta', + 'Wolfman', + 'Coonradt', + 'Disilvestro', + 'Dobrowski', + 'Gramza', + 'Kotlyar', + 'Micka', + 'Miksch', + 'Mione', + 'Montone', + 'Palmerton', + 'Parrill', + 'Passafiume', + 'Rosoff', + 'Spaziani', + 'Venditto', + 'Wisch', + 'Fini', + 'Horky', + 'Perel', + 'Arzuaga', + 'Nasworthy', + 'Carland', + 'Elden', + 'Moises', + 'Maione', + 'Glace', + 'Laverdure', + 'Sieh', + 'Toulouse', + 'Hannam', + 'Cumber', + 'Rendell', + 'Hardey', + 'Maddison', + 'Brittle', + 'Helen', + 'Aina', + 'Allwood', + 'Fenty', + 'Herard', + 'Traore', + 'Ator', + 'Bedsaul', + 'Bickert', + 'Brendlinger', + 'Camuso', + 'Dutter', + 'Eastlick', + 'Fernholz', + 'Guza', + 'Heitzenrater', + 'Huo', + 'Isbill', + 'Katzenstein', + 'Keigley', + 'Kelnhofer', + 'Klarich', + 'Mangat', + 'Mathiason', + 'Murzyn', + 'Odenthal', + 'Pascarelli', + 'Passwaters', + 'Rotunda', + 'Schons', + 'Sein', + 'Sobon', + 'Stayner', + 'Tri', + 'Uhlir', + 'Viscusi', + 'Winstanley', + 'Xi', + 'Yodice', + 'Aerts', + 'Antosh', + 'Baldinger', + 'Brislin', + 'Christopoulos', + 'Faurot', + 'Fusselman', + 'Hamsher', + 'Henckel', + 'Macht', + 'Moellering', + 'Oclair', + 'Pavelko', + 'Poehlman', + 'Rajewski', + 'Richcreek', + 'Schmeichel', + 'Venkatesh', + 'Zemba', + 'Zuelke', + 'Dechellis', + 'Reddig', + 'Splain', + 'Claw', + 'Mottram', + 'Crise', + 'Villaflor', + 'Allocca', + 'Buttrum', + 'Cocking', + 'Mundie', + 'Tavis', + 'Saidi', + 'Latter', + 'Tuberville', + 'Spease', + 'Leatherberry', + 'Peatross', + 'Claridy', + 'Duerson', + 'Durley', + 'Mekonnen', + 'Thiam', + 'Aderman', + 'Al', + 'Andreu', + 'Beine', + 'Bowron', + 'Campi', + 'Chura', + 'Ciraulo', + 'Daywalt', + 'Fleek', + 'Friant', + 'Gahm', + 'Gongaware', + 'Grosh', + 'Heaslip', + 'Knape', + 'Kravets', + 'Kritikos', + 'Kumagai', + 'Kustra', + 'Madani', + 'Mich', + 'Norlander', + 'Paulhus', + 'Rabanal', + 'Saker', + 'Stupak', + 'Suchomel', + 'Vandenberghe', + 'Wehrenberg', + 'Zaccardi', + 'Davlin', + 'Dykhouse', + 'Grandfield', + 'Hullender', + 'Kallis', + 'Livshits', + 'Rihn', + 'Criger', + 'Michl', + 'Tutino', + 'Zulueta', + 'Cristo', + 'Meline', + 'Fetch', + 'Dung', + 'Shami', + 'Teale', + 'Cocker', + 'Eshbach', + 'Phagan', + 'Millea', + 'Tayloe', + 'Olivia', + 'Houchen', + 'Peddy', + 'Ferryman', + 'Boodram', + 'Maduro', + 'Fullman', + 'Landingham', + 'Pee', + 'Argenbright', + 'Aronowitz', + 'Baldenegro', + 'Barentine', + 'Bernasconi', + 'Bicking', + 'Bohle', + 'Camerer', + 'Dufford', + 'Ende', + 'Gessel', + 'Grauman', + 'Jaqua', + 'Kagawa', + 'Kalinski', + 'Kanz', + 'Klasen', + 'Koloski', + 'Kriete', + 'Litalien', + 'Maish', + 'Massar', + 'Muraski', + 'Pickelsimer', + 'Sagraves', + 'Servellon', + 'Shellito', + 'Shiveley', + 'Stanislaw', + 'Volland', + 'Biehle', + 'Cruey', + 'Eagar', + 'Ermis', + 'Goracke', + 'Mackert', + 'Malloch', + 'Merillat', + 'Rylee', + 'Schelin', + 'Tibbals', + 'Zandi', + 'Golde', + 'Steuart', + 'Jamie', + 'Lavis', + 'Bromwell', + 'Tregre', + 'Alkhatib', + 'Carvey', + 'Essa', + 'Wale', + 'Mccarey', + 'Brandley', + 'Hermon', + 'Stenhouse', + 'Oguinn', + 'Barclift', + 'Sylvan', + 'Smyre', + 'Ellerby', + 'Alemany', + 'Beyl', + 'Boven', + 'Bultema', + 'Buzan', + 'Cappo', + 'Cottongim', + 'Detore', + 'Dierolf', + 'Dueck', + 'Egelston', + 'Emard', + 'Eveleth', + 'Ferrini', + 'Fodera', + 'Hidy', + 'Kahley', + 'Karasik', + 'Klare', + 'Koudelka', + 'Lafleche', + 'Minturn', + 'Montemarano', + 'Plock', + 'Ratterman', + 'Reingold', + 'Rieber', + 'Schnackenberg', + 'Schrade', + 'Steffek', + 'Stehling', + 'Sticha', + 'Velaquez', + 'Weissberg', + 'Allnutt', + 'Barkhurst', + 'Bettendorf', + 'Canonico', + 'Deshmukh', + 'Dobosz', + 'Glab', + 'Kirkeby', + 'Menapace', + 'Parizek', + 'Pursifull', + 'Ragucci', + 'Raisch', + 'Schronce', + 'Tuason', + 'Duross', + 'Hainer', + 'Kinnick', + 'Rens', + 'Williamsen', + 'Hilke', + 'Hark', + 'Mellett', + 'Decarvalho', + 'Filyaw', + 'Sian', + 'Mccard', + 'Symon', + 'Grade', + 'Giboney', + 'Sadik', + 'Caul', + 'Gater', + 'Sulton', + 'Dungee', + 'Adriance', + 'Almas', + 'Andler', + 'Bellina', + 'Belshe', + 'Blouch', + 'Bradeen', + 'Brandwein', + 'Buechele', + 'Cristina', + 'Davidov', + 'Defiore', + 'Defrain', + 'Derasmo', + 'Dober', + 'Grosshans', + 'Hoek', + 'Hofstad', + 'Ingman', + 'Kille', + 'Langill', + 'Matic', + 'Niederer', + 'Novella', + 'Oelkers', + 'Percifield', + 'Phariss', + 'Pola', + 'Pompei', + 'Potthast', + 'Raden', + 'Radick', + 'Rendina', + 'Sicotte', + 'Sleep', + 'Wadhwa', + 'Buccheri', + 'Calogero', + 'Catrett', + 'Flemmer', + 'Mancinas', + 'Mcmichen', + 'Measel', + 'Pudlo', + 'Ruether', + 'Shusterman', + 'Stabley', + 'Teffeteller', + 'Waisanen', + 'Zappulla', + 'Symanski', + 'Mckenrick', + 'Moger', + 'Obispo', + 'Armenteros', + 'Roses', + 'Makki', + 'Faley', + 'Rumford', + 'Schonberg', + 'Hizer', + 'Blaydes', + 'Coor', + 'Mccalip', + 'Stancill', + 'Cal', + 'Murat', + 'Amie', + 'Placide', + 'Akpan', + 'Bembenek', + 'Bilyk', + 'Bizzarro', + 'Bugge', + 'Cunnane', + 'Degenhart', + 'Doehring', + 'Flammia', + 'Fritcher', + 'Godinho', + 'Gouger', + 'Heyboer', + 'Humenik', + 'Iannaccone', + 'Lacivita', + 'Lagunes', + 'Leitzke', + 'Luty', + 'Maute', + 'Micke', + 'Midura', + 'Nydam', + 'Rasp', + 'Rediker', + 'Requejo', + 'Roskos', + 'Ruckert', + 'Saldierna', + 'Salemme', + 'Tsuchiya', + 'Vallas', + 'Werder', + 'Arenivas', + 'Bartholomay', + 'Brozowski', + 'Dusza', + 'Frevert', + 'Giannopoulos', + 'Kormos', + 'Martos', + 'Mollenhauer', + 'Romanek', + 'Solinger', + 'Tomaro', + 'Zangara', + 'Buttrick', + 'Pardy', + 'Alvelo', + 'Breth', + 'Hemond', + 'Kayes', + 'Manne', + 'Grandchamp', + 'Gilbo', + 'Calame', + 'Clippard', + 'Gieger', + 'Penalver', + 'Ecton', + 'Totton', + 'Poyser', + 'Kettles', + 'Hosang', + 'Waker', + 'Maryland', + 'Girma', + 'Baribeau', + 'Boehnke', + 'Brunick', + 'Buhrow', + 'Cerreta', + 'Dascoli', + 'Eroh', + 'Fallert', + 'Fotopoulos', + 'Granholm', + 'Hebdon', + 'Hoelzer', + 'Hyser', + 'Lisanti', + 'Mastrianni', + 'Mewes', + 'Mulanax', + 'Nikolai', + 'Odekirk', + 'Ofallon', + 'Onnen', + 'Or', + 'Osso', + 'Ridpath', + 'Schara', + 'Schnipke', + 'Slayter', + 'Sodhi', + 'Steffler', + 'Stegemann', + 'Weisensel', + 'Bertling', + 'Dueitt', + 'Keehner', + 'Khaimov', + 'Kramlich', + 'Salkeld', + 'Ulbricht', + 'Vultaggio', + 'Dennin', + 'Mondo', + 'Kett', + 'Dom', + 'Kalan', + 'Yaney', + 'Nicley', + 'Carabello', + 'Ellegood', + 'Mcglocklin', + 'Figuero', + 'Pillard', + 'Wolfrey', + 'Leys', + 'Cobert', + 'Wahid', + 'Fede', + 'Ausbrooks', + 'Gums', + 'Gillion', + 'Mcgeachy', + 'Parran', + 'Likely', + 'Marbley', + 'Argote', + 'Bhullar', + 'Botros', + 'Brethauer', + 'Chell', + 'Conradi', + 'Covill', + 'Crays', + 'Crysler', + 'Handke', + 'Hanneken', + 'Hidrogo', + 'Hirayama', + 'Huebert', + 'Hurford', + 'Iskra', + 'Malczewski', + 'Menees', + 'Monforte', + 'Murdick', + 'Naclerio', + 'Nohr', + 'Pangallo', + 'Payeur', + 'Pozniak', + 'Rammel', + 'Schield', + 'Schrick', + 'Seifer', + 'Sperduto', + 'Stagliano', + 'Staubs', + 'Stromme', + 'Tourigny', + 'Traister', + 'Vandecar', + 'Wilhelms', + 'Wilinski', + 'Wittke', + 'Clougherty', + 'Crotwell', + 'Hannula', + 'Heavrin', + 'Heidinger', + 'Keehan', + 'Ortwein', + 'Palinkas', + 'Seivert', + 'Sloniker', + 'Yielding', + 'Lac', + 'Shove', + 'Venard', + 'Violett', + 'Foresta', + 'Gapp', + 'Dejongh', + 'Ambrosia', + 'Simkin', + 'Sastre', + 'Mcarthy', + 'Bering', + 'Sarah', + 'Hickling', + 'Sookdeo', + 'Val', + 'Colden', + 'Feltus', + 'Hailes', + 'Canizalez', + 'Cloke', + 'Connole', + 'Dancel', + 'Demmon', + 'Ehrler', + 'Fruchey', + 'Helinski', + 'Hepfer', + 'Katzen', + 'Kressler', + 'Lagrow', + 'Nethercutt', + 'Novitski', + 'Papale', + 'Pesola', + 'Petrosian', + 'Pies', + 'Prazak', + 'Preza', + 'Reiche', + 'Salle', + 'Savic', + 'Servello', + 'Sherbondy', + 'Solazzo', + 'Stabenow', + 'Walstad', + 'Yaden', + 'Zagal', + 'Zani', + 'Dimambro', + 'Engquist', + 'Fochtman', + 'Frasch', + 'Fuerstenberg', + 'Galus', + 'Gronowski', + 'Grossenbacher', + 'Hahs', + 'Iavarone', + 'Kerper', + 'Kravchenko', + 'Kwolek', + 'Lusignan', + 'Lybbert', + 'Maertens', + 'Mahany', + 'Medico', + 'Orrantia', + 'Reitmeier', + 'Sieve', + 'Sterbenz', + 'Tenpas', + 'Wischmeyer', + 'Zajkowski', + 'Cregg', + 'Shetley', + 'Tisher', + 'Coup', + 'Murdy', + 'Lysaght', + 'Sesco', + 'Koy', + 'Wakley', + 'Bertholf', + 'Swaner', + 'Stakes', + 'Gren', + 'Elahi', + 'Torney', + 'Gopaul', + 'Egland', + 'Gingles', + 'Aurich', + 'Biela', + 'Binz', + 'Blumenstock', + 'Boardwine', + 'Boehner', + 'Boening', + 'Crankshaw', + 'Decarli', + 'Fauble', + 'Georgopoulos', + 'Gieske', + 'Hasselbring', + 'Heeb', + 'Janosik', + 'Kalafut', + 'Karpf', + 'Kramm', + 'Lanyon', + 'Lewelling', + 'Lilla', + 'Marik', + 'Moyano', + 'Oppel', + 'Panagos', + 'Renovato', + 'Rohlman', + 'Rostron', + 'Todhunter', + 'Torello', + 'Umfleet', + 'Wien', + 'Youker', + 'Ytuarte', + 'Zavada', + 'Altvater', + 'Arnzen', + 'Blixt', + 'Elek', + 'Geiselman', + 'Hiltunen', + 'Jachim', + 'Kolenovic', + 'Kooyman', + 'Muecke', + 'Pierron', + 'Preisler', + 'Rogus', + 'Schoeller', + 'Solimine', + 'Speagle', + 'Courser', + 'Mascarenhas', + 'Dorer', + 'Scotten', + 'Goy', + 'Avers', + 'Blanca', + 'Choung', + 'Goleman', + 'Nanna', + 'Lave', + 'Seley', + 'Meggison', + 'Ripoll', + 'Mannan', + 'Bihm', + 'Tribbey', + 'Ports', + 'Asby', + 'Philibert', + 'Furby', + 'Keal', + 'Louallen', + 'Idris', + 'Artist', + 'Branford', + 'Sabree', + 'Ainley', + 'Amezola', + 'Andreason', + 'Athans', + 'Batiz', + 'Bostelman', + 'Bozic', + 'Butman', + 'Coiro', + 'Defina', + 'Garbo', + 'Gewirtz', + 'Hathcoat', + 'Heebner', + 'Helbing', + 'Kasler', + 'Kastler', + 'Kearby', + 'Krus', + 'Lezotte', + 'Lithgow', + 'Mealor', + 'Moltz', + 'Morcom', + 'Norbeck', + 'Novicki', + 'Osmani', + 'Posluszny', + 'Quiroa', + 'Rahal', + 'Roddenberry', + 'Rodino', + 'Sallade', + 'Saraceni', + 'Schmaus', + 'Stathopoulos', + 'Swatek', + 'Tupy', + 'Vonseggern', + 'Zens', + 'Ahonen', + 'Arrazola', + 'Avedisian', + 'Bachtell', + 'Bastarache', + 'Chavero', + 'Darienzo', + 'Giampa', + 'Gillott', + 'Hierholzer', + 'Kruckeberg', + 'Lafrenz', + 'Milkowski', + 'Missildine', + 'Passaretti', + 'Rogstad', + 'Saadeh', + 'Sielski', + 'Slavick', + 'Tieken', + 'Wittenmyer', + 'Yepiz', + 'Zimdars', + 'Rail', + 'Kook', + 'Jian', + 'Piet', + 'Sanjurjo', + 'Shampine', + 'Christel', + 'Hechavarria', + 'Blucher', + 'Crimm', + 'Lebreton', + 'Charbonnet', + 'Bolls', + 'Stroder', + 'Baise', + 'Mcnease', + 'Alen', + 'Priestly', + 'Mannie', + 'Doleman', + 'Areas', + 'Atayde', + 'Berent', + 'Bodmer', + 'Brodin', + 'Buntrock', + 'Eckrich', + 'Emberson', + 'Hilgert', + 'Hirn', + 'Holihan', + 'Hoshino', + 'Jeung', + 'Leece', + 'Leonardis', + 'Macera', + 'Mcferron', + 'Muster', + 'Naef', + 'Pecka', + 'Peloso', + 'Pensyl', + 'Reaney', + 'Reidinger', + 'Rockholt', + 'Tabrizi', + 'Trauth', + 'Trulock', + 'Tupou', + 'Asbridge', + 'Franzel', + 'Gesualdi', + 'Grimwood', + 'Hardinger', + 'Kondrat', + 'Koskinen', + 'Ludolph', + 'Marchesi', + 'Mehrtens', + 'Racioppi', + 'Sabey', + 'Stroebel', + 'Swendsen', + 'Vandewalker', + 'Korber', + 'Messler', + 'Mowat', + 'Kor', + 'Pua', + 'Sarazin', + 'Wayson', + 'Oland', + 'Bandi', + 'Fabel', + 'Frankl', + 'Rane', + 'Mozer', + 'Weaber', + 'Moustafa', + 'Robe', + 'Lindy', + 'Medaris', + 'Derden', + 'Benthall', + 'Ayler', + 'Osias', + 'Choyce', + 'Scantlebury', + 'Patmon', + 'Ahlgrim', + 'Boffa', + 'Brideau', + 'Bubeck', + 'Bubel', + 'Casio', + 'Casique', + 'Casten', + 'Colebank', + 'Demoura', + 'Devincenzo', + 'Elsesser', + 'Fauci', + 'Frentz', + 'Hemler', + 'Keitel', + 'Luan', + 'Luhn', + 'Luquette', + 'Mazurowski', + 'Mendibles', + 'Mickiewicz', + 'Minelli', + 'Mistler', + 'Nemer', + 'Nikolaus', + 'Offill', + 'Pezza', + 'Ruzich', + 'Skrzypek', + 'Swimmer', + 'Trucks', + 'Vaccarella', + 'Zeidman', + 'Brattin', + 'Deblock', + 'Dufrane', + 'Gural', + 'Hufstedler', + 'Kapuscinski', + 'Lyerla', + 'Musolino', + 'Neubecker', + 'Polus', + 'Protzman', + 'Retzloff', + 'Sachdev', + 'Sazama', + 'Shrider', + 'Tobolski', + 'Mcbane', + 'Clabo', + 'Fredrich', + 'Lace', + 'Bertran', + 'Kama', + 'Simonet', + 'Lippitt', + 'Thomlinson', + 'Vallot', + 'Dede', + 'Brimley', + 'Parler', + 'Standfield', + 'Goodie', + 'Isidore', + 'Philogene', + 'Abramczyk', + 'Andert', + 'Besancon', + 'Bieda', + 'Birkey', + 'Boquet', + 'Borak', + 'Bottino', + 'Breyfogle', + 'Crill', + 'Daffern', + 'Derrig', + 'Dimalanta', + 'Dresch', + 'Feulner', + 'Friede', + 'Furth', + 'Gamet', + 'Garramone', + 'Gaunce', + 'Gitto', + 'Guandique', + 'Hoxworth', + 'Hubers', + 'Ingwersen', + 'Junio', + 'Kassing', + 'Magrath', + 'Martelle', + 'Mcweeney', + 'Neris', + 'Nesheiwat', + 'Remlinger', + 'Rentmeester', + 'Schlein', + 'Schoneman', + 'Sterr', + 'Streib', + 'Szymanowski', + 'Trompeter', + 'Tullius', + 'Cherico', + 'Cremin', + 'Dominey', + 'Gotthardt', + 'Kowalke', + 'Onderdonk', + 'Pirrello', + 'Rumberger', + 'Schreur', + 'Westerhoff', + 'Maroni', + 'Dire', + 'Menta', + 'Hoeg', + 'Meise', + 'Standerfer', + 'Roam', + 'Tibbett', + 'Beevers', + 'Evrard', + 'Locklair', + 'Brester', + 'Sirmon', + 'Woodbeck', + 'Wires', + 'Durette', + 'Raul', + 'Stephanie', + 'Mcwain', + 'Skeeters', + 'Wilbourne', + 'Debroux', + 'Keyton', + 'Noris', + 'Fanta', + 'Goshen', + 'Kithcart', + 'Shepheard', + 'Sherod', + 'Buntyn', + 'Gissendanner', + 'Goodley', + 'Mckissic', + 'Bissinger', + 'Biswell', + 'Borruso', + 'Danese', + 'Eslava', + 'Gehle', + 'Gibeau', + 'Gionet', + 'Greth', + 'Gul', + 'Hambley', + 'Harshfield', + 'Helin', + 'Henken', + 'Hogland', + 'Hoxha', + 'Hurlbutt', + 'Kaminer', + 'Kien', + 'Kliebert', + 'Koivisto', + 'Kooken', + 'Laconte', + 'Lovo', + 'Manninen', + 'Maxham', + 'Mcleland', + 'Mclerran', + 'Milici', + 'Negrette', + 'Nicotera', + 'Nissan', + 'Philipson', + 'Pimenta', + 'Pinch', + 'Rietveld', + 'Seyller', + 'Shollenberger', + 'Sochacki', + 'Telleria', + 'Toda', + 'Unrue', + 'Vanbenschoten', + 'Versace', + 'Villada', + 'Watry', + 'Wirsing', + 'Zeimet', + 'Zynda', + 'Angelillo', + 'Fleissner', + 'Freehling', + 'Grewell', + 'Heick', + 'Kartes', + 'Kishi', + 'Kopke', + 'Laubenstein', + 'Leske', + 'Lohmeier', + 'Marotz', + 'Moccio', + 'Mullineaux', + 'Muzyka', + 'Ostermiller', + 'Penuelas', + 'Plagge', + 'Stolarz', + 'Wertenberger', + 'Sella', + 'Allinger', + 'Betzler', + 'Rosenkrantz', + 'Trimarchi', + 'Dionicio', + 'Frohman', + 'Landenberger', + 'Shillings', + 'Chill', + 'Leather', + 'Sonn', + 'Connel', + 'Fougere', + 'Alia', + 'Wisby', + 'Haisley', + 'Minion', + 'Mccathern', + 'Rozzell', + 'Armbrister', + 'Ryant', + 'Almeyda', + 'Bonjour', + 'Bordas', + 'Bozard', + 'Buccola', + 'Cihlar', + 'Dargis', + 'Faivre', + 'Fejes', + 'Grulke', + 'Harken', + 'Heimberger', + 'Hochmuth', + 'Keadle', + 'Kedrowski', + 'Kortman', + 'Krahenbuhl', + 'Krasniqi', + 'Kundrat', + 'Leistner', + 'Loguidice', + 'Mcauliff', + 'Mchatton', + 'Minella', + 'Muccio', + 'Normington', + 'Nuttle', + 'Orsino', + 'Reker', + 'Respicio', + 'Shein', + 'Teichert', + 'Varisco', + 'Accomando', + 'Amelio', + 'Burckhard', + 'Fleischhacker', + 'Hagglund', + 'Kessenich', + 'Langrehr', + 'Lauderbaugh', + 'Misquez', + 'Muneton', + 'Ourada', + 'Rulon', + 'Scholze', + 'Stellmach', + 'Sudano', + 'Thelander', + 'Yeckley', + 'Corsino', + 'Grage', + 'Isla', + 'Narramore', + 'Coolman', + 'Heatherington', + 'Newey', + 'Kunda', + 'Motts', + 'Tawfik', + 'Tindel', + 'Passon', + 'Sypher', + 'Conceicao', + 'Haraway', + 'Deamer', + 'Nored', + 'Mamo', + 'Mcgilberry', + 'Akerley', + 'Andreatta', + 'Aronhalt', + 'Barz', + 'Bebber', + 'Brubacher', + 'Cabriales', + 'Dyckman', + 'Ellers', + 'Finerty', + 'Hargan', + 'Haselton', + 'Hellmuth', + 'Hoffmeier', + 'Homrich', + 'Hrabak', + 'Intrieri', + 'Lebeda', + 'Lutzke', + 'Malka', + 'Mcglinn', + 'Nicklin', + 'Nusz', + 'Pennings', + 'Rebmann', + 'Rodocker', + 'Sacra', + 'Saksa', + 'Shehane', + 'Siever', + 'Snide', + 'Sotero', + 'Sponsel', + 'Therien', + 'Viti', + 'Wubben', + 'Zieske', + 'Billingham', + 'Bruschi', + 'Cullipher', + 'Eppolito', + 'Greuel', + 'Huq', + 'Matott', + 'Mohlman', + 'Monterroza', + 'Risberg', + 'Shvartsman', + 'Sigafoos', + 'Zehring', + 'Manuele', + 'Asghar', + 'Shelp', + 'Grieder', + 'Hippert', + 'Dani', + 'Beserra', + 'Kennan', + 'Scholfield', + 'Joh', + 'Swailes', + 'Pear', + 'Hell', + 'Kittler', + 'Pickeral', + 'Somerset', + 'Streat', + 'Tinner', + 'Landor', + 'Pretlow', + 'Tensley', + 'Abela', + 'Abramovich', + 'Acocella', + 'Avino', + 'Bacchi', + 'Bayliff', + 'Beganovic', + 'Belinsky', + 'Bilicki', + 'Borowiec', + 'Bucknam', + 'Calandro', + 'Ciszek', + 'Cooling', + 'Cundari', + 'Derk', + 'Ekern', + 'Engelson', + 'Fennessey', + 'Ferencz', + 'Filipkowski', + 'Frescas', + 'Frisinger', + 'Gegg', + 'Hanken', + 'Harbach', + 'Jipson', + 'Kasal', + 'Kinstler', + 'Langenbach', + 'Leccese', + 'Maalouf', + 'Mcinerny', + 'Mcpartlin', + 'Meth', + 'Mitzner', + 'Riano', + 'Saggese', + 'Schroff', + 'Skibicki', + 'Textor', + 'Vancampen', + 'Vukelich', + 'Wascom', + 'Workinger', + 'Xin', + 'Bronkema', + 'Gerstel', + 'Geving', + 'Gravlin', + 'Hannay', + 'Haughn', + 'Lippi', + 'Lonsway', + 'Paradowski', + 'Poust', + 'Thinnes', + 'Wassenaar', + 'Hemm', + 'Isip', + 'Pastorino', + 'Barkett', + 'Montalban', + 'Ballestero', + 'Floren', + 'Rossen', + 'Chuba', + 'Burrington', + 'Derman', + 'Wickland', + 'Dunman', + 'Beek', + 'Petitjean', + 'Michelin', + 'Chapell', + 'Pullam', + 'Adamcik', + 'Albarracin', + 'Batrez', + 'Berghuis', + 'Birkland', + 'Boulier', + 'Broderson', + 'Bruun', + 'Cicio', + 'Davidow', + 'Denova', + 'Dooner', + 'Espeland', + 'Fifita', + 'Guidone', + 'Hartnell', + 'Havranek', + 'Janca', + 'Klepac', + 'Langhorst', + 'Lippmann', + 'Merrihew', + 'Mondelli', + 'Monterosso', + 'Moster', + 'Noxon', + 'Poznanski', + 'Reents', + 'Samaras', + 'Silvius', + 'Srour', + 'Stasio', + 'Steffe', + 'Steimer', + 'Stracke', + 'Taney', + 'Theodorou', + 'Trickel', + 'Tunks', + 'Vavrek', + 'Whitfill', + 'Wohlfeil', + 'Zirkelbach', + 'Brissey', + 'Busboom', + 'Collignon', + 'Emling', + 'Fratzke', + 'Genrich', + 'Giglia', + 'Hayakawa', + 'Lupinski', + 'Pulvermacher', + 'Steinbrink', + 'Xayavong', + 'Yerkey', + 'Arlotta', + 'Calia', + 'Pfiffner', + 'Gostomski', + 'Declerck', + 'Demedeiros', + 'Dirickson', + 'Wo', + 'Hosie', + 'Chad', + 'Herbison', + 'Fleece', + 'Connon', + 'Dun', + 'Gaffin', + 'Plush', + 'Gravette', + 'Houseal', + 'Seaward', + 'Esson', + 'Mayhorn', + 'Surrell', + 'Horsford', + 'Mcduffey', + 'Huger', + 'Alexie', + 'Apsey', + 'Belke', + 'Bourcier', + 'Cardena', + 'Daun', + 'Dunworth', + 'Ehrsam', + 'Elizardo', + 'Elkhatib', + 'Emick', + 'Fernau', + 'Finnan', + 'Hitzeman', + 'Housand', + 'Kallstrom', + 'Katen', + 'Kerstein', + 'Kiracofe', + 'Klammer', + 'Largaespada', + 'Limoges', + 'Lodwick', + 'Lozito', + 'Madl', + 'Mauthe', + 'Mogel', + 'Newstrom', + 'Ninh', + 'Obrochta', + 'Opsal', + 'Ordiway', + 'Osentoski', + 'Paxman', + 'Plume', + 'Rickenbach', + 'Rinks', + 'Saltmarsh', + 'Scheuring', + 'Schwegel', + 'Skov', + 'Woodrome', + 'Zdanowicz', + 'Zera', + 'Basgall', + 'Bornhorst', + 'Clotfelter', + 'Coulthard', + 'Dresner', + 'Fischl', + 'Grahek', + 'Grefe', + 'Knightly', + 'Kuenzel', + 'Mccumbers', + 'Millstein', + 'Mulnix', + 'Weiher', + 'Yust', + 'Metter', + 'Polio', + 'Ayad', + 'Banke', + 'Lawlis', + 'Coba', + 'Twyford', + 'Burck', + 'Barthold', + 'Sames', + 'Jacquot', + 'Allsopp', + 'Mcglaun', + 'Hollinsworth', + 'Gillings', + 'Buchannon', + 'Bas', + 'Beaber', + 'Berto', + 'Bobrow', + 'Bochicchio', + 'Bohland', + 'Burghart', + 'Chaloux', + 'Costella', + 'Depace', + 'Dils', + 'Diviney', + 'Ehly', + 'Ermer', + 'Fussner', + 'Gunia', + 'Guterrez', + 'Holik', + 'Holster', + 'Kasperski', + 'Koscinski', + 'Lamoureaux', + 'Marotti', + 'Masullo', + 'Mcconahy', + 'Mehlhaff', + 'Mocarski', + 'Moosman', + 'Pavlich', + 'Pfisterer', + 'Ruacho', + 'Semrad', + 'Slemmer', + 'Stineman', + 'Toelle', + 'Vanderstelt', + 'Wagy', + 'Wuensch', + 'Wykes', + 'Zar', + 'Bouchie', + 'Friis', + 'Gehrt', + 'Hempfling', + 'Henkes', + 'Huggler', + 'Kelbaugh', + 'Petrenko', + 'Pfost', + 'Rubendall', + 'Shimel', + 'Stapf', + 'Sweeton', + 'Tsuda', + 'Vitanza', + 'Voytko', + 'Bibbo', + 'Hagee', + 'Majer', + 'Mangieri', + 'Pala', + 'Volle', + 'Cabassa', + 'Lipsett', + 'Macdougal', + 'Minar', + 'Eline', + 'Eskin', + 'Angeletti', + 'Lattner', + 'Kimple', + 'Marsan', + 'Tornes', + 'Moncur', + 'Sanderfer', + 'Crite', + 'Levels', + 'Valcin', + 'Motton', + 'Foggie', + 'Battistoni', + 'Bedient', + 'Bendt', + 'Bennison', + 'Bonnin', + 'Caridi', + 'Cedotal', + 'Choinski', + 'Cossin', + 'Devargas', + 'Deveny', + 'Dosher', + 'Dredge', + 'Fittro', + 'Gorgone', + 'Gourd', + 'Herra', + 'Holwerda', + 'Iannello', + 'Klintworth', + 'Kubena', + 'Leyvas', + 'Magowan', + 'Mendolia', + 'Nehme', + 'Pelikan', + 'Pfalzgraf', + 'Raith', + 'Reichenberg', + 'Reinertsen', + 'Sens', + 'Simer', + 'Spektor', + 'Sweda', + 'Wordell', + 'Blasing', + 'Dinoto', + 'Goblirsch', + 'Helming', + 'Hibshman', + 'Lamountain', + 'Latka', + 'Licausi', + 'Malerba', + 'Mentink', + 'Meskill', + 'Moening', + 'Montminy', + 'Ryno', + 'Sluka', + 'Solarz', + 'Swainston', + 'Tagliaferri', + 'Twichell', + 'Vertucci', + 'Voland', + 'Wolgast', + 'Bissen', + 'Duray', + 'Flaum', + 'Taves', + 'Caplin', + 'Hayat', + 'Pollett', + 'Baris', + 'Taher', + 'Anes', + 'Beza', + 'Pere', + 'Tipper', + 'Farrey', + 'Slott', + 'Sinquefield', + 'Bobbett', + 'Calico', + 'Eigner', + 'Gambrill', + 'Donigan', + 'Daney', + 'Natt', + 'Gettis', + 'Kincy', + 'Dolberry', + 'Curenton', + 'Elzie', + 'Beretta', + 'Carbine', + 'Carpenito', + 'Clarin', + 'Conrado', + 'Conradt', + 'Courteau', + 'Daft', + 'Debruler', + 'Delahunty', + 'Duerst', + 'Dzik', + 'Ellner', + 'Faeth', + 'Fournet', + 'Galinski', + 'Goldenstein', + 'Hanauer', + 'Higgason', + 'Hoeper', + 'Hollo', + 'Ildefonso', + 'Jocson', + 'Kasprowicz', + 'Kochanowski', + 'Labrosse', + 'Lazaroff', + 'Leino', + 'Levinsky', + 'Lopezhernandez', + 'Mckeague', + 'Otremba', + 'Paluzzi', + 'Pevehouse', + 'Polgar', + 'Raneri', + 'Rumler', + 'Sanantonio', + 'Schissel', + 'Senteno', + 'Sieling', + 'Smee', + 'Swiggum', + 'Tarnow', + 'Tavakoli', + 'Tholl', + 'Valdiviezo', + 'Willadsen', + 'Wilmouth', + 'Dudziak', + 'Eskenazi', + 'Garity', + 'Gravino', + 'Impastato', + 'Kuhner', + 'Mcclaflin', + 'Nein', + 'Precourt', + 'Rotenberry', + 'Sciara', + 'Arenson', + 'Coupland', + 'Sedler', + 'Pizer', + 'Him', + 'Combee', + 'Rhorer', + 'Gelles', + 'Baroody', + 'Basten', + 'Sprinkles', + 'Vanier', + 'Clementson', + 'Robberson', + 'Harten', + 'Kade', + 'Bhola', + 'Bahar', + 'Pellum', + 'Isadore', + 'Dixie', + 'Axline', + 'Backs', + 'Berdahl', + 'Billeter', + 'Bily', + 'Broerman', + 'Declercq', + 'Derleth', + 'Fanucchi', + 'Forkey', + 'Gallinger', + 'Gionfriddo', + 'Gretzinger', + 'Grima', + 'Helgren', + 'Hoelting', + 'Hundertmark', + 'Inscho', + 'Jernberg', + 'Kamiya', + 'Lekas', + 'Marchini', + 'Markuson', + 'Matsushima', + 'Meineke', + 'Mizrachi', + 'Moglia', + 'Nagele', + 'Naro', + 'Padillo', + 'Palleschi', + 'Palomba', + 'Purgason', + 'Qadri', + 'Recalde', + 'Rosiak', + 'Rumney', + 'Savitt', + 'Shibuya', + 'Szalkowski', + 'Wagg', + 'Wolsey', + 'Zumpano', + 'Benbrook', + 'Blasdel', + 'Carusone', + 'Karalis', + 'Koep', + 'Kohles', + 'Rumbo', + 'Siggins', + 'Unverzagt', + 'Eatherly', + 'Kapper', + 'Salser', + 'Wege', + 'Zinsmeister', + 'Alf', + 'Wish', + 'Falero', + 'Bur', + 'Imam', + 'Biven', + 'Merritts', + 'Kaigler', + 'Verdell', + 'Feggins', + 'Acerra', + 'Antenucci', + 'Benegas', + 'Bisesi', + 'Boshers', + 'Chap', + 'Clouatre', + 'Doxtater', + 'Dullea', + 'Eischeid', + 'Gundry', + 'Hinger', + 'Hodak', + 'Iseminger', + 'Juris', + 'Kirchen', + 'Knezevic', + 'Kobrin', + 'Krizek', + 'Leza', + 'Lusty', + 'Luttrull', + 'Mattke', + 'Mossbarger', + 'Narro', + 'Osland', + 'Ostwald', + 'Pepperman', + 'Pritzl', + 'Reasner', + 'Schimming', + 'Schulenburg', + 'Trefry', + 'Vigorito', + 'Bayardo', + 'Bieser', + 'Brinkmeier', + 'Camposano', + 'Cremeens', + 'Delgrande', + 'Demopoulos', + 'Deyarmin', + 'Grismer', + 'Jubb', + 'Kinker', + 'Lauf', + 'Mabile', + 'Muehl', + 'Orlick', + 'Pillado', + 'Pizzano', + 'Poppleton', + 'Quickel', + 'Stoneberg', + 'Szwed', + 'Zadrozny', + 'Ziemke', + 'Zupko', + 'Diesel', + 'Hornbrook', + 'Pillion', + 'Holaway', + 'Massad', + 'Rossmiller', + 'Parriott', + 'Toya', + 'Dross', + 'Burwick', + 'Kaman', + 'Bruna', + 'Milles', + 'Acrey', + 'Toogood', + 'Austell', + 'Chastang', + 'Jasmine', + 'Eckford', + 'Stiggers', + 'Saintvil', + 'Adeyemi', + 'Basto', + 'Bolon', + 'Brilliant', + 'Brockhoff', + 'Colao', + 'Emens', + 'Endler', + 'Fabris', + 'Falletta', + 'Felver', + 'Ferdon', + 'Golinski', + 'Gosdin', + 'Gronlund', + 'Guijosa', + 'Hainley', + 'Halama', + 'Heinicke', + 'Heldenbrand', + 'Helmkamp', + 'Hoctor', + 'Hoeck', + 'Kroboth', + 'Lamagna', + 'Lingg', + 'Locurto', + 'Marchewka', + 'Micco', + 'Mormino', + 'Newmeyer', + 'Ostrosky', + 'Redel', + 'Saccoccio', + 'Stavely', + 'Stidd', + 'Tonne', + 'Tonnesen', + 'Umbach', + 'Vardanyan', + 'Wank', + 'Wolven', + 'Cilento', + 'Delmonaco', + 'Denigris', + 'Gerbig', + 'Gradilla', + 'Grebner', + 'Landini', + 'Marohl', + 'Muenchow', + 'Niedermeier', + 'Nussbaumer', + 'Nycz', + 'Pizzino', + 'Schader', + 'Schuneman', + 'Takano', + 'Ureta', + 'Vanderloop', + 'Windholz', + 'Wombacher', + 'Woulfe', + 'Hamley', + 'Schickel', + 'Yuill', + 'Batta', + 'Galant', + 'Mofield', + 'Kint', + 'Barnell', + 'Ashmead', + 'Crossin', + 'Lasco', + 'Chasen', + 'Swire', + 'Gleghorn', + 'Bearfield', + 'Goodgame', + 'Daris', + 'Plump', + 'Derricott', + 'Burno', + 'Baylock', + 'Vanterpool', + 'Judon', + 'Mells', + 'Proby', + 'Bagan', + 'Batcheller', + 'Bjelland', + 'Boline', + 'Boullion', + 'Broomall', + 'Carcia', + 'Cassinelli', + 'Cerro', + 'Colantuono', + 'Dembeck', + 'Doto', + 'Eckersley', + 'Edell', + 'Ewy', + 'Goodness', + 'Huhta', + 'Kallen', + 'Keimig', + 'Kemppainen', + 'Koopmann', + 'Lacap', + 'Lehtinen', + 'Maciolek', + 'Marchuk', + 'Mcfate', + 'Mentel', + 'Minihan', + 'Mohsin', + 'Oppedisano', + 'Patriarca', + 'Raske', + 'Schueneman', + 'Shostak', + 'Sibal', + 'Spadafore', + 'Suitor', + 'Tavella', + 'Vy', + 'Wies', + 'Beadnell', + 'Bogusz', + 'Cleverly', + 'Dellorusso', + 'Dudenhoeffer', + 'Glendinning', + 'Glomb', + 'Heinkel', + 'Jiwani', + 'Lonigro', + 'Machala', + 'Marsicano', + 'Neuenfeldt', + 'Overlock', + 'Popko', + 'Russomanno', + 'Saxer', + 'Scicchitano', + 'Spiegelberg', + 'Spindel', + 'Timpone', + 'Vincelette', + 'Waidelich', + 'Wissink', + 'Woolstenhulme', + 'Danza', + 'Sleasman', + 'Frometa', + 'Savinon', + 'Higgerson', + 'Helmich', + 'Nahar', + 'Campus', + 'Hassey', + 'Mccorkel', + 'Tola', + 'Ferrington', + 'Nicolls', + 'Markes', + 'Edgley', + 'Dupriest', + 'Wah', + 'Mclester', + 'Scantling', + 'Goffe', + 'Battie', + 'Battershell', + 'Bearup', + 'Bisig', + 'Brouillet', + 'Canby', + 'Chaussee', + 'Colandrea', + 'Colocho', + 'Daube', + 'Dobransky', + 'Dolbow', + 'Dyk', + 'Elfrink', + 'Figel', + 'Hauter', + 'Henkels', + 'Keillor', + 'Kollasch', + 'Krabill', + 'Kubly', + 'Kvasnicka', + 'Leise', + 'Martirosyan', + 'Mihalic', + 'Montecinos', + 'Myren', + 'Okerlund', + 'Ozer', + 'Rajput', + 'Reihl', + 'Rimando', + 'Saffle', + 'Schmelter', + 'Tellado', + 'Wachsmuth', + 'Wussow', + 'Zylka', + 'Caiola', + 'Certo', + 'Disabatino', + 'Ehrke', + 'Lahmann', + 'Lamartina', + 'Manheim', + 'Mckevitt', + 'Nardozzi', + 'Neuzil', + 'Novotney', + 'Oldfather', + 'Sietsema', + 'Stemmler', + 'Stumm', + 'Ueno', + 'Weckwerth', + 'Berrocal', + 'Nolde', + 'Alava', + 'Revier', + 'Sester', + 'Saller', + 'Tonga', + 'Kala', + 'Reveron', + 'Homesley', + 'Pagett', + 'Blackie', + 'Raimer', + 'Fitt', + 'Kimbley', + 'Amory', + 'Cabler', + 'Juett', + 'Crate', + 'Burres', + 'Siddle', + 'Barnfield', + 'Bordenave', + 'Cubit', + 'Elem', + 'Hardmon', + 'Augspurger', + 'Barriger', + 'Bau', + 'Bloomingdale', + 'Busta', + 'Canoy', + 'Carapia', + 'Cavenaugh', + 'Conkin', + 'Coppernoll', + 'Daloia', + 'Debruyne', + 'Egly', + 'Esmail', + 'Estorga', + 'Gladu', + 'Gladue', + 'Harvath', + 'Hirschmann', + 'Juel', + 'Kappus', + 'Kopriva', + 'Krul', + 'Lavorgna', + 'Maginn', + 'Malphrus', + 'Mcilhenny', + 'Perazzo', + 'Peredo', + 'Pineo', + 'Rigoni', + 'Robleto', + 'Schoene', + 'Sevillano', + 'Stears', + 'Stoltzfoos', + 'Sutley', + 'Terracciano', + 'Villacres', + 'Yoak', + 'Brensinger', + 'Brodzinski', + 'Cordial', + 'Cornacchia', + 'Corralejo', + 'Demarchi', + 'Dziuk', + 'Hirzel', + 'Keirns', + 'Kocourek', + 'Kupec', + 'Nazaryan', + 'Oftedahl', + 'Pignatelli', + 'Pundt', + 'Repinski', + 'Ryther', + 'Sampedro', + 'Shemanski', + 'Siess', + 'Trettel', + 'Urquilla', + 'Vantil', + 'Vicens', + 'Dunahoo', + 'Safer', + 'Romaniello', + 'Tallo', + 'Cavell', + 'Cobern', + 'Yarrow', + 'Serge', + 'Adel', + 'Allum', + 'Pruit', + 'Wali', + 'Forson', + 'Bells', + 'Blyden', + 'Andreotti', + 'Bagnato', + 'Beauchaine', + 'Biedrzycki', + 'Brabo', + 'Brodman', + 'Bruyere', + 'Canizares', + 'Chio', + 'Coudriet', + 'Dara', + 'Dhawan', + 'Diclemente', + 'Doro', + 'Elvir', + 'Fivecoat', + 'Frate', + 'Furuya', + 'Greis', + 'Halbleib', + 'Heuerman', + 'Hoener', + 'Holberg', + 'Hoogendoorn', + 'Inclan', + 'Jokinen', + 'Kretchmer', + 'Lafromboise', + 'Mccomsey', + 'Mckiddy', + 'Pelky', + 'Plaia', + 'Ponti', + 'Reichl', + 'Schicker', + 'Sotto', + 'Staehle', + 'Thau', + 'Turchin', + 'Zill', + 'Aicher', + 'Arrigoni', + 'Bertagnolli', + 'Binetti', + 'Dahlheimer', + 'Delashmit', + 'Disque', + 'Hemmerling', + 'Hovater', + 'Kachur', + 'Massmann', + 'Schlup', + 'Turkovich', + 'Underberg', + 'Wambolt', + 'Vassey', + 'Larney', + 'Brisky', + 'Minas', + 'Kata', + 'Magar', + 'Arlen', + 'Corporan', + 'Westland', + 'Detherage', + 'Reen', + 'Morale', + 'Hoes', + 'Baynham', + 'Norrington', + 'Lartigue', + 'Hakeem', + 'Kendrix', + 'Cazeau', + 'Amadi', + 'Mczeal', + 'Alwin', + 'Barcellos', + 'Bastedo', + 'Bintz', + 'Brackenbury', + 'Brockel', + 'Bucek', + 'Cecala', + 'Dapper', + 'Dettore', + 'Dowdall', + 'Dralle', + 'Essenmacher', + 'Evaristo', + 'Fecher', + 'Feldmeier', + 'Fetherston', + 'Futterman', + 'Garlinghouse', + 'Germani', + 'Gotz', + 'Hoen', + 'Janikowski', + 'Kiess', + 'Lagerstrom', + 'Lozinski', + 'Magnone', + 'Markow', + 'Mayall', + 'Mehdi', + 'Mineau', + 'Morgenroth', + 'Nitzsche', + 'Nordell', + 'Pavlock', + 'Peruzzi', + 'Pettine', + 'Pinos', + 'Polidoro', + 'Rahl', + 'Rudis', + 'Ryback', + 'Santellan', + 'Scharfenberg', + 'Schnake', + 'Schwake', + 'Seeling', + 'Senk', + 'Siron', + 'Speich', + 'Summerhays', + 'Torno', + 'Vangieson', + 'Wiacek', + 'Begnoche', + 'Carrejo', + 'Chervenak', + 'Edminster', + 'Halonen', + 'Macumber', + 'Mazeika', + 'Mikami', + 'Minetti', + 'Mosbrucker', + 'Mundis', + 'Onder', + 'Prowant', + 'Pyo', + 'Sedlack', + 'Stanbro', + 'Woehl', + 'Wrage', + 'Carpentieri', + 'Guedry', + 'Hodde', + 'Waggy', + 'Weitman', + 'Handal', + 'Gosman', + 'Mckeone', + 'Oliveria', + 'Soutar', + 'Glance', + 'Surprise', + 'Milius', + 'Crammer', + 'Mclear', + 'Borris', + 'Malon', + 'Mane', + 'Arrick', + 'Brazzel', + 'Matthewson', + 'Philemon', + 'Selvy', + 'Lites', + 'Deadwyler', + 'Marzette', + 'Alipio', + 'Arancibia', + 'Arrona', + 'Basista', + 'Blethen', + 'Brull', + 'Colaianni', + 'Dreese', + 'Giammona', + 'Giovanetti', + 'Grandmaison', + 'Grondahl', + 'Gulli', + 'Hellenbrand', + 'Iturbe', + 'Koesters', + 'Kondracki', + 'Konitzer', + 'Kubic', + 'Lauerman', + 'Mcfadin', + 'Musquiz', + 'Papalia', + 'Porrazzo', + 'Prien', + 'Reichley', + 'Treichler', + 'Ursua', + 'Vanblaricom', + 'Wich', + 'Windler', + 'Wos', + 'Zampino', + 'Alexopoulos', + 'Bambrick', + 'Beabout', + 'Brechtel', + 'Buroker', + 'Dahler', + 'Everding', + 'Furno', + 'Gikas', + 'Gilkeson', + 'Hubka', + 'Konwinski', + 'Krisko', + 'Kuligowski', + 'Maltbie', + 'Molstad', + 'Nonnemacher', + 'Nowotny', + 'Odisho', + 'Remsburg', + 'Rollyson', + 'Siegmann', + 'Slaubaugh', + 'Wasco', + 'Carlyon', + 'Chanin', + 'Cominsky', + 'Karber', + 'Aynes', + 'Swamy', + 'Kolden', + 'Rochel', + 'Julin', + 'Demarcus', + 'Malena', + 'Morice', + 'Burst', + 'Sukhu', + 'Mccravy', + 'Rinehardt', + 'Veazie', + 'Isaiah', + 'Bradby', + 'Poellnitz', + 'Agyemang', + 'Agate', + 'Aschoff', + 'Beenken', + 'Bogenschutz', + 'Casamento', + 'Correira', + 'Ebers', + 'Ellertson', + 'Forcum', + 'Gortney', + 'Jarriel', + 'Jasmer', + 'Kennebeck', + 'Kimpton', + 'Lad', + 'Lasek', + 'Licavoli', + 'Lipper', + 'Luedecke', + 'Maqueda', + 'Matsen', + 'Mest', + 'Neang', + 'Neault', + 'Newlun', + 'Oetken', + 'Rodick', + 'Rollinger', + 'Sabins', + 'Schalow', + 'Sheils', + 'Spilde', + 'Virzi', + 'Watz', + 'Wehrly', + 'Boscarino', + 'Chavolla', + 'Dasaro', + 'Eisenbach', + 'Ignatowski', + 'Kievit', + 'Kuzminski', + 'Lickliter', + 'Moravek', + 'Pawling', + 'Prause', + 'Redler', + 'Wunschel', + 'Suchanek', + 'Eyring', + 'Loge', + 'Tout', + 'Fross', + 'Swiss', + 'Deforrest', + 'Umphlett', + 'Herran', + 'Matton', + 'Passe', + 'Ode', + 'Della', + 'Caillier', + 'Baten', + 'Chesterfield', + 'Odneal', + 'Azeez', + 'Salami', + 'Ramson', + 'Mcvea', + 'Pittmon', + 'Cheatom', + 'Dorsainvil', + 'Cheeseboro', + 'Lavalais', + 'Allegro', + 'Bressi', + 'Brocklehurst', + 'Cassarino', + 'Dario', + 'Gazzola', + 'Glinka', + 'Goffredo', + 'Halabi', + 'Kroeze', + 'Lenig', + 'Marciel', + 'Marcussen', + 'Massoni', + 'Mayernik', + 'Nawrot', + 'Palazzi', + 'Pfefferkorn', + 'Placeres', + 'Polimeni', + 'Recendiz', + 'Sawdey', + 'Seidell', + 'Suchecki', + 'Titzer', + 'Virag', + 'Vitulli', + 'Wiltfong', + 'Wolden', + 'Woolworth', + 'Yandow', + 'Zeiter', + 'Zogg', + 'Brosh', + 'Dunsmoor', + 'Gucciardo', + 'Gumz', + 'Luginbill', + 'Mathwig', + 'Pannullo', + 'Raitt', + 'Reutzel', + 'Sonnen', + 'Bahri', + 'Guiffre', + 'Hons', + 'Platner', + 'Balaguer', + 'Lapre', + 'Rabbani', + 'Talent', + 'Hoster', + 'Thal', + 'Apo', + 'Duggin', + 'Kirley', + 'Burnard', + 'Lourie', + 'Wilham', + 'Craton', + 'Griff', + 'Falwell', + 'Upperman', + 'Laverne', + 'Wi', + 'Foucher', + 'Sudberry', + 'Oriol', + 'Cowens', + 'Marshell', + 'Chargois', + 'Bordley', + 'Artale', + 'Boeker', + 'Cookston', + 'Dattilio', + 'Dewinter', + 'Ditton', + 'Droessler', + 'Dusch', + 'Eltringham', + 'Feige', + 'Giel', + 'Grigas', + 'Hannagan', + 'Haubner', + 'Henzler', + 'Kippes', + 'Kneebone', + 'Lozeau', + 'Mallek', + 'Mandato', + 'Mangiapane', + 'Matusek', + 'Newgard', + 'Notte', + 'Purdin', + 'Ramaker', + 'Reddoch', + 'Rensing', + 'Rohrman', + 'Romm', + 'Rudiger', + 'Torti', + 'Travaglini', + 'Uno', + 'Wojciak', + 'Yannuzzi', + 'Zeien', + 'Arpino', + 'Borgstrom', + 'Burkemper', + 'Cristino', + 'Detjen', + 'Gienger', + 'Glockner', + 'Grillot', + 'Jentz', + 'Kendzierski', + 'Klebe', + 'Knippenberg', + 'Kusler', + 'Olofson', + 'Orlov', + 'Rindt', + 'Stallbaumer', + 'Troost', + 'Turri', + 'Uzelac', + 'Weichert', + 'Sweazy', + 'Alcivar', + 'Canner', + 'Lottman', + 'Salame', + 'Berkes', + 'Pickren', + 'Ganson', + 'Odonell', + 'Geron', + 'Kasa', + 'Banbury', + 'Tinnel', + 'Umble', + 'Flow', + 'Kirt', + 'Rhule', + 'Diles', + 'Seeney', + 'Givans', + 'Mckethan', + 'Crusoe', + 'Darko', + 'Mucker', + 'Kizzee', + 'Daniely', + 'Nutall', + 'Angove', + 'Appelhans', + 'Balder', + 'Blatchley', + 'Botkins', + 'Brisk', + 'Burandt', + 'Clowdus', + 'Debauche', + 'Deily', + 'Group', + 'Hoecker', + 'Holsonback', + 'Humpert', + 'Jacquin', + 'Jurica', + 'Karnik', + 'Krontz', + 'Lapiana', + 'Lenzo', + 'Luscombe', + 'Madey', + 'Mirabito', + 'Neifert', + 'Pennino', + 'Piechota', + 'Pizzimenti', + 'Reeg', + 'Roarty', + 'Routzahn', + 'Salsedo', + 'Schuff', + 'Silveri', + 'Steckman', + 'Supak', + 'Swackhamer', + 'Trusler', + 'Vizzini', + 'Wences', + 'Whelton', + 'Zachar', + 'Albertsen', + 'Bischel', + 'Brigandi', + 'Campoy', + 'Castagnola', + 'Doenges', + 'Flessner', + 'Garbers', + 'Jezewski', + 'Kozlov', + 'Niedbalski', + 'Schillo', + 'Schoepke', + 'Schranz', + 'Trulson', + 'Vanwyhe', + 'Versluis', + 'Zavadil', + 'Brau', + 'Rudell', + 'Golen', + 'Meter', + 'Sherrin', + 'Tolly', + 'Mandala', + 'Calcano', + 'Lewing', + 'Sedeno', + 'Ramalho', + 'Haggar', + 'Borns', + 'Matherson', + 'Cobin', + 'Turnley', + 'Pone', + 'Tuner', + 'Crandle', + 'Sturkey', + 'Heggins', + 'Tisby', + 'Allbaugh', + 'Baars', + 'Bethard', + 'Brenizer', + 'Bussman', + 'Casebier', + 'Castanos', + 'Climaco', + 'Dux', + 'Farrens', + 'Frediani', + 'Gaccione', + 'Garciaperez', + 'Hoppa', + 'Juckett', + 'Klinkner', + 'Kooy', + 'Krinke', + 'Locy', + 'Lovecchio', + 'Lukin', + 'Machia', + 'Mand', + 'Maslin', + 'Mehrotra', + 'Nicolet', + 'Peyser', + 'Reckart', + 'Roanhorse', + 'Rokicki', + 'Sargis', + 'Sciullo', + 'Shevchuk', + 'Sindoni', + 'Slankard', + 'Sobiech', + 'Stoneberger', + 'Stys', + 'Tuzzolino', + 'Waligora', + 'Wiland', + 'Clabough', + 'Drawbaugh', + 'Figurski', + 'Gibeault', + 'Gojcaj', + 'Hartfiel', + 'Inbody', + 'Konarski', + 'Kruszka', + 'Letarte', + 'Lillich', + 'Mccandlish', + 'Mollenkopf', + 'Oltmann', + 'Pfenninger', + 'Ruediger', + 'Schaben', + 'Shauger', + 'Wilczak', + 'Wolanin', + 'Ziehm', + 'Bassinger', + 'Brannick', + 'Schlereth', + 'Capri', + 'Roscher', + 'Pasqual', + 'Lallo', + 'Sweney', + 'Rozario', + 'Hamblet', + 'Muckleroy', + 'Frankson', + 'Moure', + 'Shrieves', + 'Bosket', + 'Strowbridge', + 'Hawkin', + 'Cooperwood', + 'Agena', + 'Barrowman', + 'Belko', + 'Blasdell', + 'Brobeck', + 'Chieffo', + 'Cooperrider', + 'Dickard', + 'Erion', + 'Fradkin', + 'Hattery', + 'Hefferon', + 'Hofstra', + 'Hoiland', + 'Jirak', + 'Klugman', + 'Klundt', + 'Knope', + 'Lawniczak', + 'Luckenbach', + 'Manzione', + 'Mccombie', + 'Minden', + 'Mousel', + 'Ridling', + 'Rightmire', + 'Ritzel', + 'Santori', + 'Semmens', + 'Snyders', + 'Spargur', + 'Staszewski', + 'Swiech', + 'Tasso', + 'Veldhuizen', + 'Vuolo', + 'Wojnarowski', + 'Yoe', + 'Bachler', + 'Cimo', + 'Hippen', + 'Klimaszewski', + 'Kohlhepp', + 'Kovacich', + 'Kretsch', + 'Lacoursiere', + 'Lopezmartinez', + 'Marsiglia', + 'Metzker', + 'Murchie', + 'Paradee', + 'Pfefferle', + 'Rothert', + 'Skellenger', + 'Tourangeau', + 'Beumer', + 'Thunder', + 'Uden', + 'Broe', + 'Moxon', + 'Kassin', + 'Murton', + 'Hockley', + 'Vinet', + 'Suthers', + 'Bayman', + 'Cokeley', + 'Ailey', + 'Crossfield', + 'Desha', + 'Dowson', + 'Acheampong', + 'Boomsma', + 'Buer', + 'Caratachea', + 'Dascenzo', + 'Debes', + 'Degroote', + 'Dillie', + 'Dorsi', + 'Dorward', + 'Eyestone', + 'Geister', + 'Gonia', + 'Heiler', + 'Hin', + 'Hoheisel', + 'Horger', + 'Hulce', + 'Kainer', + 'Kerkman', + 'Kloehn', + 'Krempasky', + 'Kuehnel', + 'Leetch', + 'Lio', + 'Lohrey', + 'Lucchetti', + 'Machnik', + 'Majeske', + 'Martire', + 'Mores', + 'Oyen', + 'Pappert', + 'Platas', + 'Podany', + 'Prata', + 'Radoncic', + 'Sainato', + 'Salada', + 'Serota', + 'Tatsch', + 'Torbeck', + 'Vilhauer', + 'Waltner', + 'Wauters', + 'Welge', + 'Yoss', + 'Bigwood', + 'Brunsman', + 'Civitello', + 'Compston', + 'Cuccaro', + 'Denholm', + 'Emmick', + 'Gadzinski', + 'Goedken', + 'Graumann', + 'Hackert', + 'Hardacre', + 'Hehl', + 'Magliocco', + 'Marotto', + 'Ozanich', + 'Pidcock', + 'Schlangen', + 'Scoma', + 'Sobecki', + 'Spreng', + 'Thalmann', + 'Wolfrum', + 'Groninger', + 'Howatt', + 'Kindy', + 'Swor', + 'Ledden', + 'Voyer', + 'Colli', + 'Andrae', + 'Duchemin', + 'Boker', + 'Malter', + 'Snooks', + 'Morss', + 'Haylett', + 'Mitter', + 'Fairey', + 'Kenerson', + 'Albea', + 'Ellerson', + 'Alcindor', + 'Gadison', + 'Arabia', + 'Bundren', + 'Calica', + 'Cartaya', + 'Cielo', + 'Ebbers', + 'Entler', + 'Friedly', + 'Granja', + 'Landt', + 'Lorensen', + 'Michelini', + 'Oliveto', + 'Piela', + 'Reust', + 'Roussos', + 'Sanluis', + 'Seier', + 'Sobolik', + 'Stader', + 'Stetzer', + 'Tetley', + 'Zirbes', + 'Bridenbaugh', + 'Chinnici', + 'Crabbs', + 'Evilsizer', + 'Favaloro', + 'Haeberle', + 'Hopfensperger', + 'Kijowski', + 'Kingbird', + 'Leikam', + 'Montavon', + 'Petrossian', + 'Quizhpi', + 'Spoelstra', + 'Testani', + 'Plaut', + 'Windt', + 'Dubie', + 'Kozinski', + 'Sorell', + 'Nish', + 'Katon', + 'Soy', + 'Pelcher', + 'Sayres', + 'Waitman', + 'Relph', + 'Hearld', + 'Farewell', + 'Giordani', + 'Canida', + 'Martian', + 'Suliman', + 'Mckesson', + 'Randon', + 'Eastmond', + 'Willaims', + 'Collington', + 'Hardge', + 'Asevedo', + 'Beauchene', + 'Bebeau', + 'Bobick', + 'Bogacki', + 'Bolich', + 'Bonadonna', + 'Butsch', + 'Coltrin', + 'Corbello', + 'Dastrup', + 'Dunshee', + 'Firpo', + 'Foister', + 'Franssen', + 'Fredriksen', + 'Gfeller', + 'Glassner', + 'Johanns', + 'Korson', + 'Langsam', + 'Linstrom', + 'Longstaff', + 'Lukic', + 'Maler', + 'Marteney', + 'Milardo', + 'Rhatigan', + 'Ruetz', + 'Semel', + 'Senske', + 'Shatswell', + 'Simmering', + 'Tasch', + 'Vanskike', + 'Verano', + 'Viscardi', + 'Weidmann', + 'Doubet', + 'Farraj', + 'Fritter', + 'Griesinger', + 'Horkey', + 'Hornik', + 'Izatt', + 'Klayman', + 'Mantei', + 'Notz', + 'Oberholzer', + 'Petko', + 'Rueth', + 'Rygiel', + 'Tumolo', + 'Unterreiner', + 'Urgo', + 'Weisbecker', + 'Weniger', + 'Zarro', + 'Zunino', + 'Goldmann', + 'Verderber', + 'Glennie', + 'Shere', + 'Lamos', + 'Face', + 'Sparger', + 'Donnay', + 'Kage', + 'Leason', + 'Mcgue', + 'Brickle', + 'Mae', + 'Thomaston', + 'Dunnell', + 'Tillie', + 'Miggins', + 'Geffrard', + 'Aubel', + 'Backe', + 'Beaumier', + 'Bloor', + 'Brackbill', + 'Brandvold', + 'Bylund', + 'Carbary', + 'Catrambone', + 'Dapolito', + 'Dillenburg', + 'Elliff', + 'Fehnel', + 'Ferriss', + 'Gellner', + 'Graw', + 'Guilbeault', + 'Hautala', + 'Hollenberg', + 'Imparato', + 'Kaner', + 'Kley', + 'Lanzer', + 'Laterza', + 'Legner', + 'Lombardozzi', + 'Mcerlean', + 'Mcgilton', + 'Mohring', + 'Neeper', + 'Pollinger', + 'Pullara', + 'Sagona', + 'Scripter', + 'Skillen', + 'Streeper', + 'Tritch', + 'Vayda', + 'Verbeek', + 'Wenberg', + 'Youngers', + 'Bayus', + 'Cobaugh', + 'Dolak', + 'Forys', + 'Genther', + 'Jankovich', + 'Kneale', + 'Komp', + 'Kreher', + 'Kuwahara', + 'Mclouth', + 'Melland', + 'Molesky', + 'Neustadt', + 'Oesterling', + 'Quirke', + 'Roeper', + 'Stantz', + 'Vandenboom', + 'Venhuizen', + 'Westermeyer', + 'Embury', + 'Cozort', + 'Crispo', + 'Woollard', + 'Thiery', + 'Lecy', + 'Terris', + 'Stencil', + 'Yero', + 'Bollard', + 'Chander', + 'Shepp', + 'Younkins', + 'Jon', + 'Anselm', + 'Deveraux', + 'Better', + 'Birth', + 'Hoskie', + 'Kirtz', + 'Encalade', + 'Aprea', + 'Bernick', + 'Bialy', + 'Bolenbaugh', + 'Chinea', + 'Cwiklinski', + 'Dunavan', + 'Dunckel', + 'Essen', + 'Ferner', + 'Gallick', + 'Gruba', + 'Hauss', + 'Intriago', + 'Javaid', + 'Kaney', + 'Klemens', + 'Kuriakose', + 'Leyda', + 'Losurdo', + 'Mcelhone', + 'Methot', + 'Morioka', + 'Mundorf', + 'Nocito', + 'Nordmann', + 'Oommen', + 'Pfahl', + 'Piquette', + 'Prinsen', + 'Sacramento', + 'Shenker', + 'Skidgel', + 'Sobalvarro', + 'Soldo', + 'Synan', + 'Tostenson', + 'Trotti', + 'Vienneau', + 'Vigneau', + 'Waitkus', + 'Wiess', + 'Bartmess', + 'Comparan', + 'Dalonzo', + 'Dutrow', + 'Fleegle', + 'Fronek', + 'Handrich', + 'Hazelip', + 'Heinig', + 'Macapagal', + 'Masciarelli', + 'Pitstick', + 'Radakovich', + 'Ripberger', + 'Schwebel', + 'Slomski', + 'Stinchfield', + 'Zegers', + 'Zeiser', + 'Kimmer', + 'Rippon', + 'Satz', + 'Bosques', + 'Mcnickle', + 'Yarwood', + 'Babar', + 'Ghazi', + 'Mcquary', + 'Africa', + 'Sofer', + 'Marsland', + 'Curby', + 'Odor', + 'Gillem', + 'Selmer', + 'Delmas', + 'Lamison', + 'Lanes', + 'Shadd', + 'Goard', + 'Haylock', + 'Sermon', + 'Meachem', + 'Vernet', + 'Akiona', + 'Avitabile', + 'Berkson', + 'Bisono', + 'Busic', + 'Caroselli', + 'Corradi', + 'Delval', + 'Egley', + 'Elkind', + 'Everling', + 'Ferrario', + 'Frumkin', + 'Gelder', + 'Gironda', + 'Glasheen', + 'Goette', + 'Gotts', + 'Haub', + 'Herro', + 'Hudzik', + 'Hula', + 'Inboden', + 'Isensee', + 'Kiesewetter', + 'Koetje', + 'Laughridge', + 'Lovewell', + 'Meeuwsen', + 'Mokry', + 'Navarez', + 'Plake', + 'Quain', + 'Reppucci', + 'Sorn', + 'Tallerico', + 'Uselman', + 'Verrastro', + 'Wineberg', + 'Blazina', + 'Falardeau', + 'Garavito', + 'Gellerman', + 'Havins', + 'Kurdziel', + 'Liedel', + 'Lofstrom', + 'Pakula', + 'Presby', + 'Ringstad', + 'Rokosz', + 'Schuchart', + 'Seckler', + 'Verderame', + 'Veselka', + 'Asfour', + 'Delanoy', + 'Fromer', + 'Koba', + 'Kostrzewa', + 'Melle', + 'Merkey', + 'Scalese', + 'Oritz', + 'Kilgour', + 'Piker', + 'Janet', + 'Huge', + 'Hails', + 'Dobey', + 'Escoe', + 'Rasool', + 'Gilcrest', + 'Codrington', + 'Jeangilles', + 'Outley', + 'Bambach', + 'Beaulac', + 'Begue', + 'Bobeck', + 'Buccino', + 'Carrigg', + 'Cranney', + 'Denninger', + 'Dicioccio', + 'Eapen', + 'Fargnoli', + 'Fatica', + 'Fernicola', + 'Forse', + 'Freck', + 'Gardipee', + 'Gibas', + 'Goeman', + 'Guadian', + 'Hlad', + 'Jakab', + 'Kishimoto', + 'Krenn', + 'Lagesse', + 'Lhommedieu', + 'Lusch', + 'Mausolf', + 'Mazzocchi', + 'Mcdavitt', + 'Noseworthy', + 'Passante', + 'Placzek', + 'Quamme', + 'Ringgenberg', + 'Spiegelman', + 'Vinluan', + 'Wachsman', + 'Bacigalupi', + 'Baechle', + 'Baetz', + 'Barsch', + 'Colbaugh', + 'Devoto', + 'Dimercurio', + 'Dosanjh', + 'Dukeman', + 'Ferger', + 'Garinger', + 'Grelle', + 'Guyett', + 'Harpenau', + 'Hundal', + 'Kamerer', + 'Klomp', + 'Licklider', + 'Martinec', + 'Matzek', + 'Nixdorf', + 'Pankonin', + 'Pogosyan', + 'Schweickert', + 'Smethurst', + 'Stroope', + 'Zwack', + 'Tebbetts', + 'Stains', + 'Tosado', + 'Carles', + 'Rings', + 'Hebard', + 'Choplin', + 'Townshend', + 'Doorn', + 'Aja', + 'Picking', + 'Oneall', + 'Logie', + 'Aro', + 'Dua', + 'Heney', + 'Manard', + 'Atchinson', + 'Breech', + 'Brashers', + 'Addams', + 'Nooner', + 'Barsh', + 'Orum', + 'Dancey', + 'Bamba', + 'Kareem', + 'Theard', + 'Marseille', + 'Molette', + 'Getachew', + 'Saintfleur', + 'Frimpong', + 'Anglada', + 'Attardo', + 'Barreira', + 'Bleicher', + 'Bonecutter', + 'Bricco', + 'Compian', + 'Creppel', + 'Cuadras', + 'Cuccio', + 'Cutsforth', + 'Dinino', + 'Eskelson', + 'Freemyer', + 'Friedhoff', + 'Grandt', + 'Holzmann', + 'Hoverson', + 'Hurteau', + 'Iacona', + 'Jergens', + 'Kingham', + 'Leiterman', + 'Leugers', + 'Leyh', + 'Lotti', + 'Majkowski', + 'Mossberg', + 'Nuffer', + 'Oaxaca', + 'Pagenkopf', + 'Paille', + 'Petzoldt', + 'Rogalla', + 'Siddens', + 'Siddoway', + 'Spatafora', + 'Tufo', + 'Weismann', + 'Werntz', + 'Wilz', + 'Ammirati', + 'Benninghoff', + 'Escarsega', + 'Fessel', + 'Hurless', + 'Jastrzebski', + 'Klingerman', + 'Kurilla', + 'Kuzmin', + 'Meserole', + 'Politz', + 'Pollino', + 'Rettke', + 'Sinay', + 'Strebeck', + 'Strycharz', + 'Suhre', + 'Thumm', + 'Trybus', + 'Uhrin', + 'Weisberger', + 'Zeger', + 'Carringer', + 'Sitts', + 'Lungren', + 'Iiams', + 'Sudbury', + 'Surrette', + 'Chellis', + 'Yore', + 'Joice', + 'Foot', + 'Ausley', + 'Scioneaux', + 'Mcaffee', + 'Pinn', + 'Maina', + 'Dorce', + 'Agrusa', + 'Albornoz', + 'Arave', + 'Bacallao', + 'Bendavid', + 'Bochner', + 'Bortle', + 'Carragher', + 'Chalfin', + 'Courtade', + 'Dagle', + 'Debuhr', + 'Fowble', + 'Galinsky', + 'Hardigree', + 'Haulk', + 'Hendron', + 'Herringshaw', + 'Jayaraman', + 'Koestler', + 'Konicek', + 'Kutscher', + 'Lachowicz', + 'Lafauci', + 'Lansky', + 'Lazarski', + 'Lolli', + 'Ludvigsen', + 'Manternach', + 'Martorelli', + 'Mcquillin', + 'Mikaelian', + 'Northcraft', + 'Nyborg', + 'Palone', + 'Peckman', + 'Schwebach', + 'Simbeck', + 'Sittler', + 'Udovich', + 'Viesca', + 'Yazell', + 'Zimmers', + 'Bielen', + 'Cohron', + 'Dearcos', + 'Feezor', + 'Hilgart', + 'Karriker', + 'Klingberg', + 'Leisenring', + 'Napora', + 'Nedved', + 'Okeson', + 'Seratt', + 'Trautner', + 'Trimarco', + 'Turkel', + 'Bronder', + 'Itani', + 'Verona', + 'Blackbird', + 'Laque', + 'Karpel', + 'Louro', + 'Hamson', + 'Ashland', + 'Gruel', + 'Breer', + 'Wesely', + 'Bebo', + 'Conery', + 'Mccarry', + 'Cradic', + 'Aytes', + 'Dikes', + 'Soltau', + 'Debois', + 'Berko', + 'Callins', + 'Anastacio', + 'Balbi', + 'Bata', + 'Bechel', + 'Borsuk', + 'Chihuahua', + 'Cindric', + 'Denapoli', + 'Dotzler', + 'Dusing', + 'Dziekan', + 'Eifler', + 'Franchino', + 'Garritano', + 'Herrarte', + 'Jaskot', + 'Kettell', + 'Kingsford', + 'Marsters', + 'Oshel', + 'Overacker', + 'Pagliarulo', + 'Pannier', + 'Pyun', + 'Rardon', + 'Reville', + 'Rogozinski', + 'Scatena', + 'Schoeppner', + 'Senkbeil', + 'Silkey', + 'Takhar', + 'Whitebread', + 'Wiech', + 'Adelsberger', + 'Aslinger', + 'Bhattacharyya', + 'Brege', + 'Burright', + 'Cafarella', + 'Chlebowski', + 'Decaprio', + 'Dilello', + 'Dresher', + 'Finkbiner', + 'Gerlich', + 'Ignasiak', + 'Kataoka', + 'Kearl', + 'Pingitore', + 'Sellick', + 'Sinning', + 'Stojanovic', + 'Vanasten', + 'Vanluven', + 'Westerfeld', + 'Mahala', + 'Biancardi', + 'Velardo', + 'Payes', + 'Debello', + 'Kyes', + 'Reever', + 'Joung', + 'Coran', + 'Perrow', + 'Linzer', + 'Birchett', + 'Poles', + 'Cajuste', + 'Albergo', + 'Andal', + 'Belaire', + 'Borell', + 'Bruehl', + 'Celani', + 'Cerruti', + 'Crellin', + 'Delcarlo', + 'Dubach', + 'Elicker', + 'Fialkowski', + 'Ganim', + 'Gladieux', + 'Glendening', + 'Glomski', + 'Kalp', + 'Kavan', + 'Kawabata', + 'Kever', + 'Kisch', + 'Maiorino', + 'Masaki', + 'Mcgeough', + 'Miyoshi', + 'Nand', + 'Nitka', + 'Novakovich', + 'Penagos', + 'Pierini', + 'Rassi', + 'Rorke', + 'Rosenboom', + 'Rossmann', + 'Scarfone', + 'Scarsella', + 'Siedschlag', + 'Sobotta', + 'Studnicka', + 'Teeling', + 'Tegtmeyer', + 'Woznick', + 'Beske', + 'Dersch', + 'Deschepper', + 'Duffner', + 'Geroux', + 'Lindvall', + 'Linnemann', + 'Roethler', + 'Scanlin', + 'Schaecher', + 'Schmude', + 'Schwertner', + 'Shimamoto', + 'Stratmann', + 'Stufflebean', + 'Ulatowski', + 'Witkop', + 'Landrus', + 'Sahin', + 'Araque', + 'Massett', + 'Meanor', + 'Sebo', + 'Delic', + 'Bryand', + 'Frederico', + 'Portuondo', + 'Verry', + 'Browe', + 'Winecoff', + 'Gipp', + 'Khamis', + 'Ingrum', + 'Gilliand', + 'Poinsett', + 'Hagley', + 'Valliant', + 'Henly', + 'Bingley', + 'Romulus', + 'Moyd', + 'Abascal', + 'Adelstein', + 'Arabian', + 'Barcelos', + 'Barot', + 'Cabacungan', + 'Darco', + 'Dickmeyer', + 'Gindi', + 'Grone', + 'Haberland', + 'Hachem', + 'Humbarger', + 'Insco', + 'Kravchuk', + 'Mackowski', + 'Madrazo', + 'Malesky', + 'Markowicz', + 'Mcconnon', + 'Meiring', + 'Micalizzi', + 'Moeser', + 'Mortier', + 'Muegge', + 'Ollar', + 'Pamperin', + 'Pusch', + 'Remache', + 'Roginski', + 'Rothbauer', + 'Sellin', + 'Stachurski', + 'Stelmack', + 'Suprenant', + 'Totzke', + 'Uemura', + 'Vandercook', + 'Yott', + 'Zaher', + 'Autio', + 'Barnhard', + 'Brys', + 'Chisenhall', + 'Deiters', + 'Fetsko', + 'Finzel', + 'Gangwer', + 'Grygiel', + 'Heidelberger', + 'Kommer', + 'Latchford', + 'Liszka', + 'Mcconaha', + 'Miazga', + 'Nettesheim', + 'Oelschlager', + 'Rafuse', + 'Reichow', + 'Santosuosso', + 'Sebastiani', + 'Serratore', + 'Spenner', + 'Steffenson', + 'Strehl', + 'Tropeano', + 'Vanstraten', + 'Vegh', + 'Virrueta', + 'Wilhide', + 'Prey', + 'Ullmer', + 'Ferraz', + 'Mazor', + 'Vinje', + 'Mory', + 'Rody', + 'Dowen', + 'Bord', + 'Rajkumar', + 'Qadir', + 'Turbin', + 'Rorex', + 'Wilmott', + 'Grandpre', + 'Bucker', + 'Reasonover', + 'Holoman', + 'Mustapha', + 'Warsame', + 'Laday', + 'Whack', + 'Blahut', + 'Boxell', + 'Britnell', + 'Buehl', + 'Burri', + 'Cesaro', + 'Degrand', + 'Demetro', + 'Fadeley', + 'Fischel', + 'Florer', + 'Givler', + 'Gockley', + 'Iuliano', + 'Koral', + 'Kotlarz', + 'Kraai', + 'Kvamme', + 'Latchaw', + 'Lopeman', + 'Manocchio', + 'Martinezgarcia', + 'Minehart', + 'Narasimhan', + 'Nier', + 'Niziolek', + 'Oliff', + 'Piascik', + 'Pitera', + 'Pronovost', + 'Roseboom', + 'Rosevear', + 'Runkles', + 'Santmyer', + 'Skillin', + 'Stamas', + 'Storbeck', + 'Teicher', + 'Titterington', + 'Tomkinson', + 'Tzeng', + 'Vukovic', + 'Wescoat', + 'Algeo', + 'Aronow', + 'Balbach', + 'Brockbank', + 'Caloca', + 'Caughlin', + 'Devincenzi', + 'Doetsch', + 'Filby', + 'Godar', + 'Keeven', + 'Marchetta', + 'Quiram', + 'Rudeen', + 'Siemen', + 'Suderman', + 'Tacke', + 'Walby', + 'Fram', + 'Maccarthy', + 'Fana', + 'Kimberley', + 'Richens', + 'Doser', + 'Bigford', + 'Brazie', + 'Haroon', + 'Mcginniss', + 'Knipfer', + 'Seltz', + 'Laton', + 'Balow', + 'Cramp', + 'Edger', + 'Alonge', + 'Beagles', + 'Ken', + 'Peary', + 'Lifsey', + 'Acy', + 'Lightbourne', + 'Antwi', + 'Arntzen', + 'Bracknell', + 'Brewbaker', + 'Carville', + 'Cinquemani', + 'Corales', + 'Corgan', + 'Craze', + 'Dechristopher', + 'Eltzroth', + 'Fjelstad', + 'Forinash', + 'Gudenkauf', + 'Hapeman', + 'Hassing', + 'Hurm', + 'Jaurigue', + 'Kneisel', + 'Kulwicki', + 'Lookingbill', + 'Moist', + 'Naderi', + 'Nicoli', + 'Nicoson', + 'Olvey', + 'Remaly', + 'Stare', + 'Steinruck', + 'Switala', + 'Tada', + 'Toves', + 'Traber', + 'Tuohey', + 'Venti', + 'Vinal', + 'Wahle', + 'Yarosh', + 'Balinski', + 'Bauknecht', + 'Bernauer', + 'Bink', + 'Chudzik', + 'Coppess', + 'Corrick', + 'Gruener', + 'Kutter', + 'Malkiewicz', + 'Marking', + 'Mcgrain', + 'Melberg', + 'Ohmann', + 'Pellicane', + 'Regehr', + 'Schmoldt', + 'Schmuhl', + 'Starmer', + 'Stiens', + 'Whilden', + 'Yearick', + 'Desmith', + 'Habiger', + 'Papay', + 'Study', + 'Toot', + 'Franzoni', + 'Neuhoff', + 'Boreman', + 'Sayas', + 'Hinks', + 'Dax', + 'Sasnett', + 'Hannis', + 'Rotan', + 'Haze', + 'Jennifer', + 'Barganier', + 'Milson', + 'Kinnie', + 'Boyde', + 'Dyce', + 'Cuttino', + 'Neals', + 'Mccovery', + 'Abaya', + 'Balz', + 'Bezold', + 'Breighner', + 'Buttacavoli', + 'Cattani', + 'Detzel', + 'Douthat', + 'Dunay', + 'Eicholtz', + 'Eirich', + 'Felkner', + 'Friedenberg', + 'Haskew', + 'Henes', + 'Jamroz', + 'Kelter', + 'Kutzer', + 'Laughner', + 'Livoti', + 'Magistro', + 'Makinson', + 'Manwell', + 'Mckimmy', + 'Mcwethy', + 'Pacholski', + 'Pankau', + 'Poh', + 'Purewal', + 'Remedios', + 'Ringuette', + 'Rocchi', + 'Rojero', + 'Sabina', + 'Schiffner', + 'Sellen', + 'Setaro', + 'Soledad', + 'Stoermer', + 'Tal', + 'Vanwyk', + 'Waack', + 'Xenos', + 'Yoakam', + 'Zweber', + 'Apachito', + 'Belluomini', + 'Cancelliere', + 'Cervini', + 'Davidovich', + 'Deguia', + 'Doxtator', + 'Errera', + 'Eshbaugh', + 'Mandt', + 'Pautler', + 'Raczynski', + 'Roemmich', + 'Rosamilia', + 'Shelhamer', + 'Vandevoorde', + 'Vanengen', + 'Vindiola', + 'Weyman', + 'Dufur', + 'Reaver', + 'Bugh', + 'Starley', + 'Macmullen', + 'Mataya', + 'Bucknell', + 'Taitano', + 'Coole', + 'Huguet', + 'Top', + 'Rockford', + 'Carrithers', + 'Garrell', + 'Toppins', + 'Mayner', + 'Dantes', + 'Tones', + 'Dauphine', + 'Shillingford', + 'Massiah', + 'Angermeier', + 'Arrizon', + 'Azer', + 'Badami', + 'Beeck', + 'Buddenhagen', + 'Cheyney', + 'Danielski', + 'Delgiorno', + 'Enslin', + 'Erber', + 'Fluegge', + 'Fresco', + 'Frishman', + 'Geigle', + 'Gervase', + 'Giangregorio', + 'Glauber', + 'Hedding', + 'Janota', + 'Labore', + 'Ladley', + 'Levee', + 'Lipuma', + 'Lomanto', + 'Magos', + 'Mangen', + 'Miltner', + 'Mitschke', + 'Pingley', + 'Puertas', + 'Schwed', + 'Seminario', + 'Sinsel', + 'Sliney', + 'Spielmann', + 'Standage', + 'Waas', + 'Cooprider', + 'Delguercio', + 'Dockham', + 'Dohse', + 'Doubrava', + 'Emerine', + 'Frazzini', + 'Godown', + 'Heidbreder', + 'Ladow', + 'Lariccia', + 'Molzahn', + 'Opiela', + 'Ordorica', + 'Otterness', + 'Owczarzak', + 'Rafalski', + 'Smigel', + 'Urbas', + 'Andon', + 'Kota', + 'Ruzzo', + 'Pheasant', + 'Proch', + 'Sullinger', + 'Ezra', + 'Portes', + 'Mynhier', + 'Depree', + 'Slight', + 'Selley', + 'Daughety', + 'Shamel', + 'Glasby', + 'Casher', + 'Brisby', + 'Whittley', + 'Brye', + 'Mackins', + 'Allam', + 'Berwanger', + 'Borgmeyer', + 'Brumlow', + 'Cashmore', + 'Clementz', + 'Coopman', + 'Corti', + 'Danzer', + 'Deater', + 'Delprado', + 'Dibuono', + 'Dwan', + 'Edling', + 'Ekins', + 'Feighner', + 'Galica', + 'Gasparro', + 'Geisert', + 'Gilvin', + 'Glotzbach', + 'Goostree', + 'Hollenkamp', + 'Hronek', + 'Kamins', + 'Khun', + 'Klimowicz', + 'Langella', + 'Letz', + 'Lindh', + 'Lycan', + 'Magouirk', + 'Mcbryar', + 'Milonas', + 'Patalano', + 'Petrides', + 'Plocher', + 'Signer', + 'Sinagra', + 'Taibi', + 'Thissen', + 'Thueson', + 'Tietje', + 'Trebilcock', + 'Zelek', + 'Alavez', + 'Beyersdorf', + 'Ferraiolo', + 'Flodin', + 'Fulwiler', + 'Gieselman', + 'Heisinger', + 'Hutmacher', + 'Laraia', + 'Lempke', + 'Marchiano', + 'Mendia', + 'Milberger', + 'Murri', + 'Willhelm', + 'Yannone', + 'Diss', + 'Golab', + 'Meuth', + 'Strebe', + 'Berenguer', + 'Cunard', + 'Girvan', + 'Pacer', + 'Nate', + 'Weare', + 'Dile', + 'Donate', + 'Pamer', + 'Charlet', + 'Roades', + 'Krah', + 'Merton', + 'Debrito', + 'Montel', + 'Guimont', + 'Caire', + 'Olley', + 'Ausborn', + 'Ramdass', + 'Stores', + 'Hush', + 'Watler', + 'Robotham', + 'Stanislaus', + 'Bellevue', + 'Almeter', + 'Bartold', + 'Bathgate', + 'Bollier', + 'Boundy', + 'Bushart', + 'Buzek', + 'Cauthon', + 'Daudelin', + 'Delguidice', + 'Depaolis', + 'Dysert', + 'Forsee', + 'Goglia', + 'Gruenhagen', + 'Guilfoil', + 'Guldin', + 'Gurnee', + 'Henzel', + 'Jurney', + 'Kable', + 'Korenek', + 'Kussman', + 'Liese', + 'Mauss', + 'Mexicano', + 'Morini', + 'Oathout', + 'Paragas', + 'Phommachanh', + 'Pixton', + 'Pucciarelli', + 'Rabine', + 'Ramlow', + 'Ravert', + 'Redhouse', + 'Renault', + 'Rybinski', + 'Sahlin', + 'Scherger', + 'Schoeffler', + 'Smolinsky', + 'Stadnik', + 'Stallsmith', + 'Timoney', + 'Whiteeagle', + 'Woodsmall', + 'Zinter', + 'Bargmann', + 'Basich', + 'Bossio', + 'Coutant', + 'Curcuru', + 'Duitsman', + 'Hunkele', + 'Kingry', + 'Kotek', + 'Mancusi', + 'Orama', + 'Paszek', + 'Schrodt', + 'Schuknecht', + 'Torsiello', + 'Troise', + 'Wernimont', + 'Wipperfurth', + 'Wissner', + 'Zahradnik', + 'Deasis', + 'Pac', + 'Vowles', + 'Montesi', + 'Carie', + 'Name', + 'Broy', + 'Hillson', + 'Exton', + 'Skerritt', + 'Ude', + 'Allston', + 'Cliatt', + 'Chevis', + 'Poitier', + 'Barrasso', + 'Bartnicki', + 'Broski', + 'Cobleigh', + 'Crickenberger', + 'Cruces', + 'Cumba', + 'Diodato', + 'Dipietrantonio', + 'Eyerly', + 'Fedler', + 'Fetting', + 'Francavilla', + 'Frein', + 'Gasparyan', + 'Gingold', + 'Gunnarson', + 'Houy', + 'Huelsmann', + 'Jeppsen', + 'Labreck', + 'Lefton', + 'Maenza', + 'Mauritz', + 'Mingione', + 'Mullany', + 'Mussell', + 'Muston', + 'Paraiso', + 'Peelman', + 'Penuel', + 'Piccola', + 'Punt', + 'Ramella', + 'Rauser', + 'Reas', + 'Reino', + 'Schlack', + 'Sebastiano', + 'Sgambati', + 'Shackett', + 'Szpak', + 'Thalacker', + 'Theissen', + 'Tutko', + 'Astarita', + 'Blazejewski', + 'Dejaynes', + 'Djordjevic', + 'Eckenroth', + 'Estala', + 'Giacomo', + 'Glaub', + 'Golubski', + 'Guerreiro', + 'Housholder', + 'Kashuba', + 'Klute', + 'Lennartz', + 'Messamore', + 'Rovito', + 'Schreurs', + 'Starcevich', + 'Starkel', + 'Szczerba', + 'Thomassen', + 'Varkey', + 'Yorio', + 'Guba', + 'Unzicker', + 'Howry', + 'Bido', + 'Farella', + 'Frane', + 'Werry', + 'Cornia', + 'Postal', + 'Humphres', + 'Ran', + 'Macnair', + 'Duston', + 'Aveni', + 'Mcconn', + 'Sistare', + 'Wadell', + 'Naraine', + 'Mubarak', + 'Lonzo', + 'Shyne', + 'Tilmon', + 'Symonette', + 'Shinholster', + 'Oree', + 'Ogarro', + 'Quashie', + 'Almario', + 'Antonsen', + 'Armetta', + 'Avetisyan', + 'Bania', + 'Barricklow', + 'Bloemker', + 'Cannavo', + 'Dolliver', + 'Espenshade', + 'Falor', + 'Fukuhara', + 'Gemme', + 'Goldfinger', + 'Gonya', + 'Hamamoto', + 'Hindi', + 'Hiraldo', + 'Holquin', + 'Janco', + 'Janow', + 'Lemming', + 'Macchio', + 'Mago', + 'Mavity', + 'Mcnamer', + 'Mushrush', + 'Niskanen', + 'Ohms', + 'Pawluk', + 'Popple', + 'Poser', + 'Schiavi', + 'Stram', + 'Streight', + 'Stueck', + 'Vansandt', + 'Vivona', + 'Vongphakdy', + 'Zalar', + 'Zipper', + 'Altic', + 'Billmeyer', + 'Boghosian', + 'Bohlke', + 'Cisewski', + 'Gabrielsen', + 'Gianotti', + 'Heffler', + 'Holian', + 'Kannenberg', + 'Lenius', + 'Manuelito', + 'Mugavero', + 'Reinier', + 'Rekowski', + 'Sadlier', + 'Scialdone', + 'Stromquist', + 'Vittetoe', + 'Vorwald', + 'Widrig', + 'Audi', + 'Peral', + 'Devery', + 'Gato', + 'Sower', + 'Vanes', + 'Bonnes', + 'Hense', + 'Counsell', + 'Frankie', + 'Colford', + 'Wanser', + 'Mickels', + 'Briddell', + 'Washinton', + 'Antilla', + 'Baxendale', + 'Beining', + 'Belveal', + 'Boedecker', + 'Bottenfield', + 'Bufano', + 'Castellana', + 'Chaikin', + 'Cherne', + 'Costilow', + 'Dzialo', + 'Goeken', + 'Gombert', + 'Hammerman', + 'Hansman', + 'Hartling', + 'Kalani', + 'Klich', + 'Kolodziejski', + 'Kramar', + 'Lapinsky', + 'Latterell', + 'Lipsitz', + 'Loma', + 'Lukenbill', + 'Marxen', + 'Metallo', + 'Molner', + 'Niquette', + 'Ostrand', + 'Pelster', + 'Previti', + 'Rennaker', + 'Roering', + 'Roode', + 'Saltos', + 'Sangiovanni', + 'Schiraldi', + 'Schlafer', + 'Schwering', + 'Seedorf', + 'Sklenar', + 'Spinello', + 'Steinhorst', + 'Urueta', + 'Vonstein', + 'Bonczek', + 'Casalino', + 'Chiaro', + 'Doffing', + 'Downham', + 'Gillotti', + 'Hearl', + 'Karges', + 'Kunesh', + 'Langeland', + 'Maertz', + 'Mattinson', + 'Mignano', + 'Pasquinelli', + 'Petracca', + 'Pherigo', + 'Pikus', + 'Reichmuth', + 'Schwegman', + 'Schwerdt', + 'Seelman', + 'Winquist', + 'Wyka', + 'Yahr', + 'Bunkers', + 'Delnegro', + 'Norder', + 'Manas', + 'Polites', + 'Grape', + 'Jares', + 'Surges', + 'Asa', + 'Copeman', + 'Askar', + 'Goman', + 'Whitmyer', + 'Cohran', + 'Imbert', + 'Beaner', + 'Hugger', + 'Petion', + 'Lauture', + 'Andringa', + 'Athanas', + 'Butrick', + 'Caronna', + 'Dedominicis', + 'Eligio', + 'Fasick', + 'Hilinski', + 'Hinely', + 'Idler', + 'Janosko', + 'Kempner', + 'Klosinski', + 'Lapeyrouse', + 'Lindroth', + 'Marcon', + 'Meding', + 'Peppin', + 'Quizon', + 'Rectenwald', + 'Roessner', + 'Roets', + 'Schonberger', + 'Szostek', + 'Wassink', + 'Whan', + 'Yeakle', + 'Alguire', + 'Bielenberg', + 'Bisaillon', + 'Bonenberger', + 'Centola', + 'Colaizzi', + 'Deroos', + 'Eberlin', + 'Ehrig', + 'Ferenc', + 'Freiermuth', + 'Fruchter', + 'Garnto', + 'Huxford', + 'Knous', + 'Luttman', + 'Mulry', + 'Schirm', + 'Stankovic', + 'Authier', + 'Derise', + 'Doo', + 'Kessen', + 'Maline', + 'Porada', + 'Vasconez', + 'Haseman', + 'Tonner', + 'Woodroof', + 'Bedrossian', + 'Cranmore', + 'Dodaro', + 'Hommes', + 'Harmony', + 'Peno', + 'Mccommon', + 'Colver', + 'Olinde', + 'Oba', + 'Colone', + 'Warbington', + 'Monie', + 'Whitmill', + 'Moxey', + 'Canion', + 'Mcclenney', + 'Hallmon', + 'Austill', + 'Berni', + 'Boehning', + 'Bueso', + 'Cefalo', + 'Conneely', + 'Demicco', + 'Dieppa', + 'Duris', + 'Durnil', + 'Erxleben', + 'Hashimi', + 'Hedquist', + 'Koc', + 'Lamattina', + 'Lassman', + 'Ligman', + 'Lukins', + 'Mackler', + 'Manolis', + 'Mou', + 'Oblak', + 'Omahoney', + 'Paolo', + 'Pollok', + 'Priess', + 'Reeh', + 'Rempfer', + 'Rickerd', + 'Schoettle', + 'Serritella', + 'Steedman', + 'Suss', + 'Tanimoto', + 'Thaden', + 'Thelin', + 'Vanwingerden', + 'Wacha', + 'Weldin', + 'Youkhana', + 'Bazzano', + 'Behring', + 'Caliri', + 'Cocchi', + 'Croissant', + 'Dibbern', + 'Figiel', + 'Flygare', + 'Grieshop', + 'Iten', + 'Kaupp', + 'Linnane', + 'Plybon', + 'Rappleye', + 'Romanik', + 'Saefong', + 'Schetter', + 'Schryer', + 'Siwik', + 'Snitker', + 'Tomasic', + 'Wavra', + 'Auen', + 'Thone', + 'Marso', + 'Shadid', + 'Cake', + 'Louvier', + 'Macia', + 'Areola', + 'Kardell', + 'Strome', + 'Coogle', + 'Delis', + 'Pistorius', + 'Raybourn', + 'Sula', + 'Math', + 'Sanda', + 'Renaldo', + 'Pat', + 'Florance', + 'Brank', + 'Alice', + 'Rosebrough', + 'Quiett', + 'Henigan', + 'Mcclees', + 'Dase', + 'Bagot', + 'Kings', + 'Lanehart', + 'Barbary', + 'Stitts', + 'Aurora', + 'Baldoni', + 'Barkalow', + 'Bohnet', + 'Bosshart', + 'Decapua', + 'Denbo', + 'Deneault', + 'Dinse', + 'Dul', + 'Estle', + 'Filipski', + 'Fishell', + 'Fluckiger', + 'Glassberg', + 'Janick', + 'Juda', + 'Kibbee', + 'Kreisler', + 'Lawther', + 'Levangie', + 'Lichtenwalner', + 'Lucking', + 'Meiner', + 'Mileham', + 'Milz', + 'Reposa', + 'Rinehimer', + 'Rupley', + 'Sandez', + 'Schinke', + 'Sharpnack', + 'Sineath', + 'Tax', + 'Thumma', + 'Urda', + 'Widdison', + 'Bergdoll', + 'Bruhl', + 'Chesmore', + 'Delfavero', + 'Ferderer', + 'Haueter', + 'Hirshberg', + 'Hollobaugh', + 'Lalama', + 'Mckeag', + 'Mehlhoff', + 'Mirchandani', + 'Orwick', + 'Puskarich', + 'Schlotzhauer', + 'Stoiber', + 'Swetz', + 'Basara', + 'Magaw', + 'Amble', + 'Hawe', + 'Toren', + 'Parilla', + 'Gowell', + 'Selkirk', + 'Edris', + 'Ariel', + 'Kihara', + 'Dunkerson', + 'Halk', + 'Mooty', + 'Tippen', + 'Fullenwider', + 'Herford', + 'Salton', + 'Feider', + 'Buckhannon', + 'Mckneely', + 'Milon', + 'Whiters', + 'Barasch', + 'Baria', + 'Basques', + 'Beavin', + 'Borre', + 'Branz', + 'Broers', + 'Conca', + 'Cortopassi', + 'Courchesne', + 'Crisanti', + 'Cumpian', + 'Dagan', + 'Dekay', + 'Demartin', + 'Dewaard', + 'Dowland', + 'Duffell', + 'Ebersol', + 'Faiola', + 'Frontz', + 'Fryling', + 'Garczynski', + 'Hanway', + 'Huettner', + 'Janovsky', + 'Johndrow', + 'Kahana', + 'Kaniewski', + 'Kulish', + 'Lich', + 'Lincks', + 'Loppnow', + 'Macnab', + 'Mcconaughy', + 'Melroy', + 'Noviello', + 'Orn', + 'Pacas', + 'Peppel', + 'Polidori', + 'Radi', + 'Riesgo', + 'Romanoski', + 'Sagrero', + 'Schirripa', + 'Spack', + 'Sternhagen', + 'Tamburri', + 'Traczyk', + 'Uballe', + 'Vandruff', + 'Voght', + 'Weant', + 'Weinel', + 'Angerman', + 'Boultinghouse', + 'Dolinar', + 'Dripps', + 'Dubow', + 'Ehrhard', + 'Janvrin', + 'Lazear', + 'Liddiard', + 'Madayag', + 'Mirkin', + 'Monticello', + 'Mulka', + 'Oliger', + 'Pierceall', + 'Pittner', + 'Polkowski', + 'Prindiville', + 'Rasnic', + 'Tellefsen', + 'Uffelman', + 'Vandenbergh', + 'Weisenbach', + 'Wiedmeyer', + 'Wintle', + 'Wisz', + 'Yorba', + 'Holtmeyer', + 'Tabet', + 'Laham', + 'Barsoum', + 'Henner', + 'Idle', + 'Shaft', + 'Rennels', + 'Swarm', + 'Forgie', + 'Khaled', + 'Avon', + 'Hewey', + 'Grober', + 'Pipe', + 'Macfadden', + 'Keath', + 'Fergason', + 'Polland', + 'Brownley', + 'Haslip', + 'Crocket', + 'Tines', + 'Juniel', + 'Opara', + 'Bethley', + 'Ambuehl', + 'Bagheri', + 'Baquera', + 'Bertoli', + 'Bisek', + 'Borroto', + 'Botten', + 'Bovenzi', + 'Bruntz', + 'Buehring', + 'Canche', + 'Cicco', + 'Dambach', + 'Delellis', + 'Deniston', + 'Dirico', + 'Feagle', + 'Frayne', + 'Haagenson', + 'Janicke', + 'Kashyap', + 'Kastel', + 'Kruck', + 'Langi', + 'Lapka', + 'Marschner', + 'Megia', + 'Nesta', + 'Nevala', + 'Oblinger', + 'Picchi', + 'Rodeffer', + 'Salkin', + 'Scavuzzo', + 'Sladky', + 'Soyars', + 'Suchil', + 'Thielbar', + 'Timoteo', + 'Vanhise', + 'Varden', + 'Waldoch', + 'Watling', + 'Werk', + 'Becvar', + 'Betteridge', + 'Bolliger', + 'Bonifield', + 'Buchberger', + 'Caprara', + 'Castrogiovanni', + 'Fallaw', + 'Geeting', + 'Hiegel', + 'Hulgan', + 'Kokesh', + 'Lanting', + 'Mcphetridge', + 'Nuxoll', + 'Soun', + 'Strothman', + 'Triska', + 'Vensel', + 'Wesolek', + 'Wixted', + 'Wolgemuth', + 'Yedinak', + 'Anthis', + 'Manfred', + 'Agans', + 'Lafoe', + 'Mcginnes', + 'Folwell', + 'Galvao', + 'Carmo', + 'Valin', + 'Woon', + 'Degregory', + 'Evangelist', + 'Coast', + 'Strater', + 'Decou', + 'Pears', + 'Nellums', + 'Kynard', + 'Boursiquot', + 'Ruffins', + 'Akhavan', + 'Baloga', + 'Barany', + 'Buche', + 'Davoli', + 'Fennewald', + 'Figler', + 'Frede', + 'Gannett', + 'Ghannam', + 'Handlon', + 'Herridge', + 'Jakel', + 'Kamphuis', + 'Kattan', + 'Kemplin', + 'Klecka', + 'Korver', + 'Kozakiewicz', + 'Linenberger', + 'Lofaso', + 'Lorman', + 'Lueder', + 'Mcconahay', + 'Mcternan', + 'Mench', + 'Norenberg', + 'Oro', + 'Ostenson', + 'Pant', + 'Peardon', + 'Pertuit', + 'Ritzert', + 'Salvetti', + 'Sandner', + 'Sheek', + 'Sniegowski', + 'Sorbo', + 'Sperbeck', + 'Sump', + 'Supinski', + 'Sweetin', + 'Toenjes', + 'Velotta', + 'Venier', + 'Veracruz', + 'Wender', + 'Yamagata', + 'Arostegui', + 'Balestra', + 'Blumstein', + 'Carras', + 'Grauberger', + 'Howdeshell', + 'Murayama', + 'Nippert', + 'Notch', + 'Reisert', + 'Sebren', + 'Tetzloff', + 'Venneman', + 'Douds', + 'Lineman', + 'Powles', + 'Huet', + 'Matto', + 'Roes', + 'Dillin', + 'Lagan', + 'Bakes', + 'Yann', + 'Canterberry', + 'Milum', + 'Hinderman', + 'Linzey', + 'Ballen', + 'Ventress', + 'Prysock', + 'Bangle', + 'Blinder', + 'Bugaj', + 'Carlisi', + 'Dimario', + 'Dzikowski', + 'Gaetz', + 'Galves', + 'Ghazal', + 'Golebiewski', + 'Hadsall', + 'Hogberg', + 'Krammer', + 'Kreisher', + 'Lamia', + 'Luhmann', + 'Lupa', + 'Michelotti', + 'Nesci', + 'Paape', + 'Posthumus', + 'Reth', + 'Sassman', + 'Schlechter', + 'Schlie', + 'Schumacker', + 'Seliger', + 'Shanholtzer', + 'Strojny', + 'Taglieri', + 'Tibbles', + 'Tregoning', + 'Valine', + 'Zeiset', + 'Antu', + 'Bierwirth', + 'Birenbaum', + 'Boeder', + 'Dobkins', + 'Fenoglio', + 'Jentsch', + 'Marcinkiewicz', + 'Mruk', + 'Muhlbauer', + 'Namba', + 'Oettinger', + 'Rigor', + 'Rothweiler', + 'Schmader', + 'Schork', + 'Vandevoort', + 'Brenny', + 'Neels', + 'Fodge', + 'Que', + 'Dalpe', + 'Guerard', + 'Lammey', + 'Alfredo', + 'Corrin', + 'Quarry', + 'Reise', + 'Derrow', + 'Worrel', + 'Tennent', + 'Cassis', + 'Winson', + 'Cornet', + 'Garlin', + 'Saucer', + 'Ursery', + 'Saffo', + 'Battee', + 'Ackerley', + 'Ackland', + 'Allmendinger', + 'Altamura', + 'Anastas', + 'Artola', + 'Baldassari', + 'Bayron', + 'Bouwkamp', + 'Buonopane', + 'Chronis', + 'Coffaro', + 'Dech', + 'Delfierro', + 'Depaulo', + 'Digges', + 'Dowda', + 'Drab', + 'Feijoo', + 'Formato', + 'Friedli', + 'Hanahan', + 'Hegna', + 'Igarashi', + 'Kamai', + 'Kory', + 'Kuzel', + 'Lewkowicz', + 'Lumbra', + 'Mccreadie', + 'Meisch', + 'Montoro', + 'Pamintuan', + 'Petrow', + 'Pulcini', + 'Shewell', + 'Spitznagel', + 'Swedlund', + 'Terhorst', + 'Wilberg', + 'Willwerth', + 'Affinito', + 'Baune', + 'Beichner', + 'Boutell', + 'Challender', + 'Ellestad', + 'Gomm', + 'Hochstatter', + 'Jasko', + 'Kielar', + 'Kimmerle', + 'Kirshenbaum', + 'Kotila', + 'Lecker', + 'Manross', + 'Mcnevin', + 'Neuburger', + 'Verderosa', + 'Wiltsey', + 'Caminero', + 'Gianfrancesco', + 'Shiverdecker', + 'Amman', + 'Flavell', + 'Oconor', + 'Shure', + 'Hanagan', + 'Bokor', + 'Mashaw', + 'Ground', + 'Brittenham', + 'Pinera', + 'Smaltz', + 'Hold', + 'Gallamore', + 'Delon', + 'Hearing', + 'Rynes', + 'Cocklin', + 'Cassie', + 'Calligan', + 'Josue', + 'Congo', + 'Tennell', + 'Blyther', + 'Azarian', + 'Bauernfeind', + 'Beeghly', + 'Berget', + 'Brayfield', + 'Cerasoli', + 'Dedecker', + 'Gloeckner', + 'Herriges', + 'Hoganson', + 'Ivancic', + 'Jakeway', + 'Kayne', + 'Kitko', + 'Kohlbeck', + 'Krabbenhoft', + 'Kumari', + 'Lauri', + 'Leiber', + 'Minke', + 'Montecino', + 'Moutray', + 'Munshi', + 'Ohlin', + 'Portocarrero', + 'Rados', + 'Roedl', + 'Rossing', + 'Schake', + 'Simonin', + 'Staffa', + 'Stroschein', + 'Titman', + 'Treder', + 'Vonada', + 'Xenakis', + 'Aulds', + 'Benedick', + 'Boulais', + 'Butikofer', + 'Butorac', + 'Contento', + 'Goetting', + 'Goldammer', + 'Hopke', + 'Koppes', + 'Phetteplace', + 'Roehrs', + 'Schul', + 'Slabach', + 'Steinmiller', + 'Sucharski', + 'Vorwerk', + 'Wahlert', + 'Wheatcraft', + 'Abellera', + 'Jutte', + 'Baumgarner', + 'Tijerino', + 'Awadallah', + 'Horen', + 'Lina', + 'Stanbrough', + 'College', + 'Jarry', + 'Keas', + 'Mordan', + 'Ramnauth', + 'Rena', + 'Wa', + 'Petters', + 'Ramnath', + 'Hellams', + 'Mamon', + 'Cheese', + 'Meggett', + 'Anttila', + 'Beilman', + 'Binsfeld', + 'Brining', + 'Brubeck', + 'Carcione', + 'Chandran', + 'Chaudhuri', + 'Cogliano', + 'Dimaano', + 'Dols', + 'Doughten', + 'Ehrenfeld', + 'Elena', + 'Fausnaugh', + 'Fetz', + 'Fogelson', + 'Fraleigh', + 'Gaza', + 'Giesey', + 'Gockel', + 'Gougeon', + 'Granito', + 'Grassia', + 'Hauserman', + 'Idrovo', + 'Iwan', + 'Janning', + 'Kaffenberger', + 'Kichline', + 'Kimoto', + 'Kolodny', + 'Kortum', + 'Lafevers', + 'Lodi', + 'Longton', + 'Ludke', + 'Manganelli', + 'Mccuan', + 'Merryfield', + 'Mezquita', + 'Morandi', + 'Neibauer', + 'Oran', + 'Ozaeta', + 'Pacha', + 'Palese', + 'Perala', + 'Pisarcik', + 'Pobanz', + 'Pommer', + 'Pontrelli', + 'Prabhakar', + 'Rehmann', + 'Scheunemann', + 'Severini', + 'Skalla', + 'Srinivas', + 'Stadtmiller', + 'Trentman', + 'Trinka', + 'Tutterow', + 'Vari', + 'Wence', + 'Zeff', + 'Anagnos', + 'Arvayo', + 'Bihl', + 'Darbyshire', + 'Deeg', + 'Domagalski', + 'Estenson', + 'Finkenbinder', + 'Gaboriault', + 'Kastens', + 'Lacek', + 'Merkin', + 'Mersman', + 'Nicolaus', + 'Offerdahl', + 'Pallett', + 'Platten', + 'Quesnell', + 'Skene', + 'Sondag', + 'Wolfrom', + 'Mineer', + 'Sor', + 'Canard', + 'Mcmeen', + 'Tur', + 'Giner', + 'Mackrell', + 'Alic', + 'Sampath', + 'Baby', + 'Beales', + 'Kadri', + 'Minot', + 'Bienvenue', + 'Millirons', + 'Woodstock', + 'Landing', + 'Limehouse', + 'Andonian', + 'Armentor', + 'Asai', + 'Cutaia', + 'Darji', + 'Delsanto', + 'Deutch', + 'Droge', + 'Emme', + 'Flenner', + 'Gaida', + 'Gladd', + 'Guettler', + 'Guggisberg', + 'Guier', + 'Habenicht', + 'Heininger', + 'Helfman', + 'Hiscox', + 'Holtorf', + 'Hovious', + 'Juul', + 'Lacock', + 'Lepisto', + 'Malanowski', + 'Marineau', + 'Matza', + 'Meffert', + 'Nuon', + 'Oneto', + 'Padmanabhan', + 'Pantuso', + 'Pesci', + 'Rosenbluth', + 'Rubano', + 'Sedlar', + 'Sferrazza', + 'Sifuentez', + 'Simione', + 'Torossian', + 'Vaux', + 'Weilbacher', + 'Wiatrek', + 'Brzoska', + 'Caltabiano', + 'Csaszar', + 'Eyerman', + 'Geissinger', + 'Gioffre', + 'Grilliot', + 'Grotz', + 'Harrower', + 'Jaroszewski', + 'Jokerst', + 'Kamali', + 'Kampmann', + 'Klemz', + 'Koike', + 'Lista', + 'Mcconkie', + 'Mencia', + 'Missler', + 'Olshefski', + 'Omdahl', + 'Penunuri', + 'Scheckel', + 'Schreiter', + 'Swackhammer', + 'Taflinger', + 'Tegethoff', + 'Ummel', + 'Wetsel', + 'Wissmann', + 'Porr', + 'Ramser', + 'Russett', + 'Clucas', + 'Matlin', + 'Noblet', + 'Boyan', + 'Koman', + 'Lope', + 'Deman', + 'Latendresse', + 'Bound', + 'Rijos', + 'Bouillon', + 'Crunkleton', + 'Jayson', + 'Anne', + 'Staude', + 'Sturn', + 'Burdell', + 'Arther', + 'Yett', + 'Woolcock', + 'Clemon', + 'Saintjean', + 'Sainvil', + 'Coverson', + 'Barroga', + 'Benedicto', + 'Borin', + 'Budrow', + 'Cuddihy', + 'Forness', + 'Gohman', + 'Hepker', + 'Hilscher', + 'Holien', + 'Holstad', + 'Hopfer', + 'Hulburt', + 'Kalter', + 'Kuehnle', + 'Lachica', + 'Macioce', + 'Massimo', + 'Matsubara', + 'Meaker', + 'Mehmedovic', + 'Minckler', + 'Miralles', + 'Mostek', + 'Oshita', + 'Parthasarathy', + 'Roszak', + 'Rottenberg', + 'Rydman', + 'Shankman', + 'Sprong', + 'Stenerson', + 'Strubel', + 'Tavano', + 'Thornberg', + 'Trumpower', + 'Whittinghill', + 'Altenhofen', + 'Bartolucci', + 'Debski', + 'Dekoning', + 'Dottavio', + 'Emminger', + 'Hodkinson', + 'Hurtubise', + 'Lauridsen', + 'Leinberger', + 'Luskin', + 'Pask', + 'Rehfeld', + 'Spagna', + 'Szumski', + 'Szymborski', + 'Teem', + 'Tritschler', + 'Tschantz', + 'Tsutsui', + 'Vanecek', + 'Haddaway', + 'Colombe', + 'Mayol', + 'Shivley', + 'Maturin', + 'Babe', + 'Bovey', + 'Bathe', + 'Belliard', + 'Loner', + 'Arrow', + 'Billa', + 'Mcneish', + 'Kinton', + 'Scarber', + 'Donson', + 'Atherley', + 'Abdulaziz', + 'Age', + 'Carreker', + 'Tory', + 'Leduff', + 'Wattley', + 'Altergott', + 'Belitz', + 'Bidinger', + 'Blauch', + 'Cariker', + 'Condren', + 'Curiale', + 'Dronet', + 'Elstad', + 'Esquerra', + 'Fread', + 'Gilb', + 'Goga', + 'Gonyo', + 'Grudzien', + 'Hino', + 'Ishler', + 'Jacober', + 'Kilty', + 'Kuhrt', + 'Lairmore', + 'Lamba', + 'Lorek', + 'Lucich', + 'Marcou', + 'Mcgath', + 'Menze', + 'Mindel', + 'Nabb', + 'Ottosen', + 'Pann', + 'Ratkowski', + 'Saurer', + 'Sedore', + 'Shonka', + 'Soberano', + 'Sossamon', + 'Stdennis', + 'Stillinger', + 'Tager', + 'Tersigni', + 'Tissue', + 'Trampe', + 'Twite', + 'Whitling', + 'Wiebusch', + 'Abundez', + 'Bisping', + 'Candella', + 'Dahill', + 'Groebner', + 'Gulbrandsen', + 'Hasenauer', + 'Heesch', + 'Hipwell', + 'Kamrowski', + 'Keyworth', + 'Kleinschmit', + 'Legorreta', + 'Minium', + 'Mixter', + 'Neiswonger', + 'Purk', + 'Rinkenberger', + 'Rosenkrans', + 'Rozenberg', + 'Simenson', + 'Soltes', + 'Storino', + 'Viereck', + 'Schaafsma', + 'Craigie', + 'Amorin', + 'Latner', + 'Bowmer', + 'Nasby', + 'Bada', + 'Rami', + 'Mcglashan', + 'Reede', + 'Police', + 'Cobey', + 'Dahir', + 'Dirden', + 'Destine', + 'Akkerman', + 'Azzopardi', + 'Blankenhorn', + 'Bolio', + 'Brandhorst', + 'Buchter', + 'Canul', + 'Cocozza', + 'Collantes', + 'Cronic', + 'Cullifer', + 'Delpizzo', + 'Demoranville', + 'Dolder', + 'Dvorsky', + 'Eggett', + 'Elgersma', + 'Episcopo', + 'Esses', + 'Fehlman', + 'Gansen', + 'Garciamartinez', + 'Goldwater', + 'Gushue', + 'Hittner', + 'Igel', + 'Jupin', + 'Kostoff', + 'Kruschke', + 'Kuechler', + 'Labs', + 'Lacerte', + 'Lagle', + 'Leischner', + 'Linders', + 'Marulanda', + 'Meindl', + 'Melman', + 'Menden', + 'Orbach', + 'Patak', + 'Patras', + 'Petroni', + 'Rabenold', + 'Rapisarda', + 'Rodenburg', + 'Roelle', + 'Schar', + 'Scherbarth', + 'Simar', + 'Thoen', + 'Trana', + 'Tuch', + 'Turko', + 'Wamser', + 'Weinfeld', + 'Wirz', + 'Zatorski', + 'Zbinden', + 'Aksamit', + 'Asebedo', + 'Biello', + 'Bouchey', + 'Callejo', + 'Espanol', + 'Flathers', + 'Kunka', + 'Liaw', + 'Mckowen', + 'Mitrano', + 'Needler', + 'Och', + 'Paolella', + 'Patricelli', + 'Recine', + 'Rengel', + 'Spinler', + 'Wagenaar', + 'Winnicki', + 'Eichert', + 'Dabb', + 'Imrie', + 'Antoni', + 'Lardner', + 'Maund', + 'Schou', + 'Brittin', + 'Anthon', + 'Was', + 'Nevis', + 'Delamar', + 'Mcnorton', + 'Tankard', + 'Boardley', + 'Garcon', + 'Wimes', + 'Antell', + 'Belmarez', + 'Boff', + 'Boughan', + 'Cando', + 'Carrender', + 'Carrieri', + 'Charnley', + 'Cittadino', + 'Cwynar', + 'Deupree', + 'Doepke', + 'Fasone', + 'Fauteux', + 'Foody', + 'Fornal', + 'Fust', + 'Gasner', + 'Gloe', + 'Gorter', + 'Grumbine', + 'Hancher', + 'Hapke', + 'Heckendorn', + 'Heinlen', + 'Hilgeman', + 'Kahre', + 'Kakos', + 'Kops', + 'Lahn', + 'Leiferman', + 'Lothamer', + 'Mallis', + 'Napierkowski', + 'Orbin', + 'Panno', + 'Piacente', + 'Posas', + 'Ragasa', + 'Sonora', + 'Stupka', + 'Tio', + 'Valido', + 'Weyrick', + 'Argall', + 'Arrighi', + 'Bohlken', + 'Desrocher', + 'Distad', + 'Erkkila', + 'Gherardi', + 'Goughnour', + 'Koltz', + 'Koperski', + 'Lafalce', + 'Lucken', + 'Meleski', + 'Mortellaro', + 'Nagorski', + 'Pedrotti', + 'Pruyn', + 'Revard', + 'Saffran', + 'Schnoebelen', + 'Sermersheim', + 'Skroch', + 'Vandervliet', + 'Alwood', + 'Bosso', + 'Hor', + 'Licerio', + 'Septer', + 'Labo', + 'Lessa', + 'Ooley', + 'Gorgas', + 'Medal', + 'Coull', + 'Creely', + 'Bolland', + 'Ishaq', + 'Legore', + 'Alicia', + 'Fillingame', + 'Levers', + 'Flight', + 'Woodrick', + 'Berrie', + 'Buckels', + 'Pigue', + 'Crosse', + 'Speakes', + 'Wynes', + 'Mussa', + 'Highbaugh', + 'Venning', + 'Dupas', + 'Mccastle', + 'Andreoni', + 'Bakula', + 'Besemer', + 'Blier', + 'Braaksma', + 'Brocco', + 'Cajas', + 'Campano', + 'Crapser', + 'Dentinger', + 'Deziel', + 'Dragos', + 'Ekblad', + 'Gargis', + 'Gilberto', + 'Guadron', + 'Hollern', + 'Leibensperger', + 'Lindaman', + 'Lumadue', + 'Mault', + 'Mieses', + 'Nanninga', + 'Nudd', + 'Ouch', + 'Ramin', + 'Reggio', + 'Ruttan', + 'Saccomanno', + 'Scheaffer', + 'Sohm', + 'Spaniol', + 'Stenner', + 'Strieter', + 'Takashima', + 'Vaid', + 'Venzke', + 'Wallwork', + 'Zaffuto', + 'Zaucha', + 'Zemel', + 'Zinni', + 'Alltop', + 'Ciolek', + 'Empie', + 'Flitton', + 'Gullikson', + 'Hassebrock', + 'Kanitz', + 'Kirschenmann', + 'Krivanek', + 'Loseke', + 'Mckercher', + 'Melching', + 'Nham', + 'Ormerod', + 'Randlett', + 'Reifel', + 'Sawada', + 'Sofranko', + 'Stoia', + 'Umeda', + 'Eagon', + 'Hucker', + 'Kenniston', + 'Salus', + 'Ayyad', + 'Camey', + 'Dacy', + 'Joa', + 'Peerson', + 'Rossy', + 'Aure', + 'Keetch', + 'Sprigg', + 'Southgate', + 'Parden', + 'Andris', + 'Bossman', + 'Blondell', + 'Carmickle', + 'Pelly', + 'Mceachron', + 'Marry', + 'Burel', + 'Shark', + 'Flash', + 'Rickenbacker', + 'Foots', + 'Sillah', + 'Almgren', + 'Awtrey', + 'Berganza', + 'Boehne', + 'Bralley', + 'Brosnahan', + 'Caddick', + 'Chandonnet', + 'Cullimore', + 'Darroch', + 'Eimers', + 'Flam', + 'Howerter', + 'Jerzak', + 'Kabler', + 'Kirkes', + 'Kopper', + 'Krakow', + 'Linskey', + 'Lizzi', + 'Luria', + 'Marcrum', + 'Mathy', + 'Matulich', + 'Miskin', + 'Moghadam', + 'Nagarajan', + 'Packham', + 'Papania', + 'Paup', + 'Rippeon', + 'Rolli', + 'Rubey', + 'Scherzinger', + 'Scrima', + 'Sharar', + 'Shoberg', + 'Stupar', + 'Tendler', + 'Tobiason', + 'Vanvooren', + 'Zisa', + 'Bindel', + 'Flasch', + 'Graetz', + 'Heintzman', + 'Kosanke', + 'Longden', + 'Mahfouz', + 'Mormile', + 'Nannini', + 'Olaes', + 'Panik', + 'Putzier', + 'Radilla', + 'Schaedler', + 'Schoepf', + 'Sianez', + 'Taucher', + 'Wiebelhaus', + 'Banka', + 'Console', + 'Derego', + 'Vile', + 'Colgin', + 'Drage', + 'Josten', + 'Luckadoo', + 'Ryen', + 'Bako', + 'Ow', + 'Patient', + 'Elmes', + 'Mossa', + 'Colee', + 'Comber', + 'Tippy', + 'Perrell', + 'Axon', + 'Rickson', + 'Postlewaite', + 'Lafargue', + 'Guffin', + 'Cains', + 'Dewindt', + 'Cathy', + 'Tallie', + 'Ausby', + 'Alires', + 'Baz', + 'Bergeman', + 'Bodensteiner', + 'Borghi', + 'Dematos', + 'Denzler', + 'Dorko', + 'Duffett', + 'Dykas', + 'Emerton', + 'Fenger', + 'Fosberg', + 'Gwinner', + 'Kniess', + 'Lerew', + 'Lohner', + 'Lun', + 'Maita', + 'Mandler', + 'Marcoe', + 'Nikolov', + 'Paschen', + 'Paver', + 'Prosperi', + 'Rackliff', + 'Roever', + 'Ruberg', + 'Ruest', + 'Schnick', + 'Schuur', + 'Sowash', + 'Zanca', + 'Brecheen', + 'Brusky', + 'Chauca', + 'Debernardi', + 'Froio', + 'Gadway', + 'Karoly', + 'Kintzel', + 'Kneisley', + 'Kruser', + 'Lindfors', + 'Lwin', + 'Oursler', + 'Peruski', + 'Petteys', + 'Rottmann', + 'Schroeck', + 'Stenglein', + 'Vigen', + 'Wempe', + 'Zehren', + 'Wollen', + 'Dismore', + 'Santalucia', + 'Laza', + 'Pesnell', + 'Litle', + 'Markson', + 'Piercefield', + 'Jerrett', + 'Virginia', + 'Demonbreun', + 'Tugman', + 'Ramoutar', + 'Bazin', + 'Ola', + 'Alamin', + 'Adebayo', + 'Berkland', + 'Bernt', + 'Briguglio', + 'Bulnes', + 'Burack', + 'Cantoran', + 'Giardini', + 'Goetzke', + 'Graziosi', + 'Guberman', + 'Kamaka', + 'Karvonen', + 'Kitz', + 'Kopera', + 'Krempa', + 'Linkenhoker', + 'Mascioli', + 'Matlick', + 'Mcmahill', + 'Medaglia', + 'Mirarchi', + 'Mondry', + 'Muhlestein', + 'Murty', + 'Orender', + 'Pesantez', + 'Postiglione', + 'Reisen', + 'Riff', + 'Scarantino', + 'Seelinger', + 'Seher', + 'Sharum', + 'Sorice', + 'Staebler', + 'Tanney', + 'Tech', + 'Tramontano', + 'Trude', + 'Vasudevan', + 'Wareing', + 'Westerhold', + 'Wohlfarth', + 'Achorn', + 'Boesel', + 'Calabaza', + 'Dunkleberger', + 'Erck', + 'Fanger', + 'Felmlee', + 'Friebel', + 'Gabrys', + 'Godsil', + 'Goldhammer', + 'Gourneau', + 'Kaseman', + 'Keysor', + 'Mccargar', + 'Mittag', + 'Narum', + 'Schoeneck', + 'Stenquist', + 'Sunderlin', + 'Tarazon', + 'Tietze', + 'Wemmer', + 'Witthuhn', + 'Durango', + 'Simerson', + 'Beber', + 'Bjorn', + 'Neuville', + 'Preas', + 'Reitter', + 'Senf', + 'Mcclatchy', + 'Sanor', + 'Benney', + 'Sarrazin', + 'Woodliff', + 'Bramlet', + 'Cullin', + 'Wessells', + 'Higgens', + 'Rout', + 'Craigen', + 'Ackers', + 'Wickliff', + 'Hofler', + 'Pilgram', + 'Mcfayden', + 'Dillworth', + 'Robenson', + 'Mateen', + 'Ambrogio', + 'Aoun', + 'Aranas', + 'Balsiger', + 'Bonzo', + 'Busam', + 'Casassa', + 'Ciborowski', + 'Cotterill', + 'Cressler', + 'Cristales', + 'Crumpacker', + 'Daloisio', + 'Damasco', + 'Depolo', + 'Diguglielmo', + 'Dominik', + 'Esbenshade', + 'Fineran', + 'Formisano', + 'Gandolfi', + 'Geidel', + 'Gerwitz', + 'Grammatico', + 'Idleman', + 'Iwinski', + 'Kerth', + 'Lacouture', + 'Lafoy', + 'Lapid', + 'Lardizabal', + 'Lembcke', + 'Maga', + 'Mahrt', + 'Maniatis', + 'Martinezlopez', + 'Martinovich', + 'Milham', + 'Muscatello', + 'Perezperez', + 'Quiocho', + 'Rickner', + 'Sackrider', + 'Schwarm', + 'Schwebke', + 'Scollard', + 'Seader', + 'Shutters', + 'Skare', + 'Slothower', + 'Steeber', + 'Want', + 'Cherubini', + 'Coslett', + 'Degener', + 'Dulak', + 'Faull', + 'Freyman', + 'Gatchel', + 'Ginzburg', + 'Gronberg', + 'Landeck', + 'Lehenbauer', + 'Lubke', + 'Mcconaughey', + 'Mendonsa', + 'Minnehan', + 'Palaguachi', + 'Peedin', + 'Raithel', + 'Rezabek', + 'Rolfson', + 'Schuitema', + 'Sjodin', + 'Underkoffler', + 'Verrilli', + 'Yogi', + 'Zimpfer', + 'Zingaro', + 'Butrum', + 'Ritson', + 'Martinka', + 'Cashatt', + 'Kearn', + 'Sawtell', + 'Boyster', + 'Broyhill', + 'Cockerell', + 'Thane', + 'Resende', + 'Pealer', + 'Perrot', + 'Everhardt', + 'Breach', + 'Bry', + 'Juma', + 'Mclaine', + 'Paddy', + 'Hennesy', + 'Ledee', + 'Web', + 'Delone', + 'Louison', + 'Hamiel', + 'Tutson', + 'Bellingham', + 'Brenn', + 'Bussen', + 'Charrette', + 'Denenberg', + 'Depascale', + 'Derner', + 'Dondlinger', + 'Favro', + 'Frana', + 'Goeser', + 'Guerrini', + 'Hamideh', + 'Hetu', + 'Hnat', + 'Hollerbach', + 'Kenagy', + 'Kregel', + 'Lammi', + 'Laubacher', + 'Madarang', + 'Mangine', + 'Marut', + 'Mcmahen', + 'Memoli', + 'Milko', + 'Morash', + 'Mulvehill', + 'Nelles', + 'Perfecto', + 'Perkes', + 'Pesantes', + 'Peschke', + 'Polyakov', + 'Preheim', + 'Prust', + 'Reha', + 'Richardt', + 'Rockers', + 'Sartwell', + 'Schedler', + 'Scheler', + 'Skop', + 'Stefko', + 'Tatlock', + 'Tiley', + 'Waldecker', + 'Weinbaum', + 'Aguallo', + 'Benassi', + 'Bezio', + 'Bockover', + 'Dobesh', + 'Encina', + 'Eversman', + 'Haverfield', + 'Heigl', + 'Holzhauser', + 'Liebenow', + 'Mesenbrink', + 'Mittendorf', + 'Normoyle', + 'Pickart', + 'Rosselot', + 'Shigley', + 'Skufca', + 'Stroot', + 'Walth', + 'Wernert', + 'Lahood', + 'Ragain', + 'Stumpe', + 'Kolle', + 'Minerd', + 'Dickeson', + 'Koone', + 'Stoessel', + 'Kington', + 'Soe', + 'Wailes', + 'Monet', + 'Mccullars', + 'Huguenin', + 'Warnell', + 'Calip', + 'Sandles', + 'Fayson', + 'Balik', + 'Bauermeister', + 'Bianculli', + 'Bin', + 'Bring', + 'Busenbark', + 'Canevari', + 'Crile', + 'Dyment', + 'Egelhoff', + 'Elbe', + 'Estudillo', + 'Feigel', + 'Flammer', + 'Folta', + 'Ghuman', + 'Hefferan', + 'Hennick', + 'Hosner', + 'Kilner', + 'Liuzzi', + 'Maj', + 'Massing', + 'Nicolaisen', + 'Ohlrich', + 'Ozdemir', + 'Piccininni', + 'Prem', + 'Primiano', + 'Reek', + 'Riling', + 'Rohweder', + 'Rosasco', + 'Sandau', + 'Santarsiero', + 'Schuhmacher', + 'Stenseth', + 'Stilts', + 'Strohmeier', + 'Thorell', + 'Torr', + 'Vaswani', + 'Yono', + 'Amadon', + 'Ballowe', + 'Betke', + 'Borgwardt', + 'Decelle', + 'Dibiasio', + 'Fieldhouse', + 'Hegyi', + 'Heuberger', + 'Kreiling', + 'Montney', + 'Sammut', + 'Senseney', + 'Takenaka', + 'Tramonte', + 'Zalesky', + 'Zumstein', + 'Bents', + 'Vandersluis', + 'Wieringa', + 'Houlton', + 'Lippens', + 'Maino', + 'Keeny', + 'Bethards', + 'Guillette', + 'Lenn', + 'Minge', + 'Masley', + 'Christley', + 'Gabrielle', + 'Bruington', + 'Perren', + 'Ander', + 'Leeb', + 'Callicott', + 'Peaster', + 'Hardister', + 'Daughtridge', + 'Mclauchlin', + 'Culliver', + 'Missouri', + 'Aloisi', + 'Barua', + 'Bezek', + 'Broshears', + 'Busbin', + 'Cajamarca', + 'Dellarocco', + 'Dezeeuw', + 'Ferrelli', + 'Fieber', + 'Fredin', + 'Giovannoni', + 'Glasner', + 'Grenda', + 'Haberl', + 'Heimsoth', + 'Heinl', + 'Hellickson', + 'Hernandezlopez', + 'Huckeby', + 'Jungman', + 'Langhans', + 'Lingelbach', + 'Manera', + 'Maneri', + 'Marzella', + 'Mennen', + 'Molesworth', + 'Nagano', + 'Narula', + 'Niner', + 'Nordhoff', + 'Olazabal', + 'Perfect', + 'Plonka', + 'Pund', + 'Reincke', + 'Schimek', + 'Seegert', + 'Summar', + 'Tanori', + 'Trethewey', + 'Wehler', + 'Wirthlin', + 'Wolaver', + 'Zuver', + 'Bendure', + 'Bither', + 'Bungert', + 'Chaviano', + 'Derhammer', + 'Disbro', + 'Facchini', + 'Hoefle', + 'Hoepner', + 'Kimmes', + 'Korus', + 'Manfredonia', + 'Neuser', + 'Samarin', + 'Sanghera', + 'Sherburn', + 'Shiplett', + 'Steckelberg', + 'Faist', + 'Cardy', + 'Colan', + 'Goodbar', + 'Boro', + 'Moden', + 'Hardick', + 'Esteve', + 'Rawling', + 'Benet', + 'Nabers', + 'Atkerson', + 'Countess', + 'Thwaites', + 'Caroline', + 'Whisonant', + 'Alridge', + 'Pamphile', + 'Abdelnour', + 'Allebach', + 'Armenti', + 'Baudendistel', + 'Biers', + 'Bockrath', + 'Borgert', + 'Bovino', + 'Burgamy', + 'Cadiente', + 'Calabretta', + 'Cariveau', + 'Christoffel', + 'Daigler', + 'Dannels', + 'Darnold', + 'Decock', + 'Dominski', + 'Fest', + 'Forren', + 'Freise', + 'Galperin', + 'Hackbart', + 'Holtzer', + 'Idell', + 'Kapala', + 'Kohlenberg', + 'Kolton', + 'Lemburg', + 'Lievanos', + 'Maranan', + 'Marchitto', + 'Masini', + 'Mayabb', + 'Mccrossen', + 'Metrick', + 'Molinelli', + 'Oehlert', + 'Parlee', + 'Pizzini', + 'Polachek', + 'Salmans', + 'Selbe', + 'Sickman', + 'Stegmaier', + 'Sulek', + 'Thall', + 'Tiznado', + 'Tonini', + 'Trostel', + 'Warshawsky', + 'Aument', + 'Byrer', + 'Dechaine', + 'Fearnow', + 'Gallicchio', + 'Gertler', + 'Greubel', + 'Hironaka', + 'Kashner', + 'Kleffner', + 'Korthals', + 'Kundinger', + 'Lenger', + 'Lingafelter', + 'Luczynski', + 'Ostermeier', + 'Petrasek', + 'Righetti', + 'Tvedt', + 'Weindel', + 'Wurtzel', + 'Zumbro', + 'Wikel', + 'Burdi', + 'Ozturk', + 'Parmele', + 'Oteri', + 'Alexa', + 'Erven', + 'Keng', + 'Fare', + 'Sade', + 'Saw', + 'Jaquay', + 'Pillay', + 'Kearsley', + 'Kirkby', + 'Game', + 'Herst', + 'Vallie', + 'Bayon', + 'Whitler', + 'Pe', + 'Lockerman', + 'Cogle', + 'Rouzer', + 'Curling', + 'Mandley', + 'Kleckley', + 'Buckson', + 'Risby', + 'Averhart', + 'Almendariz', + 'Angelopoulos', + 'Brallier', + 'Decaire', + 'Deloria', + 'Derham', + 'Drudge', + 'Eckelberry', + 'Ehling', + 'Engebretsen', + 'Ercole', + 'Fiscal', + 'Gabino', + 'Gelvin', + 'Giannetto', + 'Godeaux', + 'Goshert', + 'Hedrich', + 'Ioannou', + 'Jungbluth', + 'Kia', + 'Krusemark', + 'Lader', + 'Lythgoe', + 'Malinak', + 'Mcinvale', + 'Melis', + 'Metsker', + 'Minasyan', + 'Nuhfer', + 'Omana', + 'Parco', + 'Pha', + 'Phanthavong', + 'Proa', + 'Sarli', + 'Schirtzinger', + 'Schlotter', + 'Sharrar', + 'Spielberg', + 'Stelzner', + 'Tschudy', + 'Utke', + 'Weipert', + 'Yera', + 'Berkemeier', + 'Bothun', + 'Dalporto', + 'Deschler', + 'Dragonetti', + 'Hasz', + 'Holtzinger', + 'Kallal', + 'Kesinger', + 'Kilfoyle', + 'Kobylinski', + 'Kramme', + 'Kreh', + 'Lindseth', + 'Plaugher', + 'Rehfeldt', + 'Repine', + 'Roudabush', + 'Swoveland', + 'Teper', + 'Tucek', + 'Wadding', + 'Wenzlick', + 'Ghobrial', + 'Golberg', + 'Soyka', + 'Matura', + 'Moras', + 'Natter', + 'Apps', + 'Imran', + 'Rossel', + 'Harne', + 'Les', + 'Silla', + 'Deblanc', + 'Rhinehardt', + 'Delaware', + 'Alkins', + 'Laidley', + 'Maree', + 'Cassells', + 'Abdulrahman', + 'Cange', + 'Devone', + 'Eustache', + 'Negash', + 'Tanks', + 'Sivels', + 'Cabbagestalk', + 'Ahlin', + 'Akard', + 'Barbaree', + 'Bielat', + 'Bressman', + 'Capurro', + 'Cortazar', + 'Dauphinee', + 'Dornak', + 'Eckl', + 'Eisenhuth', + 'Fazzini', + 'Fraim', + 'Glaab', + 'Glod', + 'Guedea', + 'Hearty', + 'Hinostroza', + 'Honold', + 'Jostes', + 'Korzeniewski', + 'Lobell', + 'Lopardo', + 'Middlekauff', + 'Monfils', + 'Oshana', + 'Schiappa', + 'Schubach', + 'Servantez', + 'Shaler', + 'Siverson', + 'Slimp', + 'Slovacek', + 'Staat', + 'Strassman', + 'Waffle', + 'Wuebker', + 'Beigel', + 'Berardo', + 'Berkery', + 'Bloyer', + 'Cronkright', + 'Cuautle', + 'Devenny', + 'Ghrist', + 'Gipple', + 'Gwilliam', + 'Hunzeker', + 'Ierardi', + 'Kathol', + 'Kienle', + 'Krack', + 'Loeper', + 'Minchey', + 'Pecht', + 'Schaberg', + 'Schollmeyer', + 'Siniscalchi', + 'Toback', + 'Tramp', + 'Vandaele', + 'Witzig', + 'Wivell', + 'Moros', + 'Saso', + 'Gares', + 'Heagle', + 'Murrillo', + 'Stankey', + 'Shamon', + 'Avram', + 'Achor', + 'Ovens', + 'Rames', + 'Perris', + 'Kernes', + 'Semmes', + 'Thaw', + 'Stevison', + 'Clemetson', + 'Belmar', + 'Guster', + 'Bascomb', + 'Adrien', + 'Jeanpaul', + 'Alabi', + 'Jallow', + 'Atamian', + 'Basque', + 'Bubier', + 'Casad', + 'Czekaj', + 'Dejoy', + 'Dulworth', + 'Fatula', + 'Favale', + 'Feutz', + 'Freundlich', + 'Frid', + 'Gagan', + 'Gaughran', + 'Guderian', + 'Hagemeister', + 'Haser', + 'Leibman', + 'Meddings', + 'Narlock', + 'Offenberger', + 'Pesa', + 'Poupard', + 'Raus', + 'Repetti', + 'Revello', + 'Robarts', + 'Rowin', + 'Saltarelli', + 'Sanghvi', + 'Schleyer', + 'Silba', + 'Steuck', + 'Stoffers', + 'Tangredi', + 'Taussig', + 'Tiso', + 'Wehmeier', + 'Zwiefelhofer', + 'Bartelson', + 'Brabender', + 'Cornfield', + 'Davtyan', + 'Delnero', + 'Frontino', + 'Gathman', + 'Graessle', + 'Hinchcliff', + 'Houdeshell', + 'Kapler', + 'Karabin', + 'Kerestes', + 'Lemmen', + 'Merkt', + 'Mitro', + 'Nahm', + 'Nancarrow', + 'Novakowski', + 'Parraz', + 'Revolorio', + 'Schamel', + 'Scowden', + 'Steever', + 'Suastegui', + 'Villarin', + 'Wuellner', + 'Dooly', + 'Erno', + 'Arbelo', + 'Groshek', + 'Boliver', + 'Gane', + 'Bees', + 'Dowds', + 'Newmann', + 'Kewley', + 'Stile', + 'Lobe', + 'Skeet', + 'Burgen', + 'Mckamie', + 'Hubanks', + 'Suleman', + 'Billey', + 'Efferson', + 'Mcleary', + 'Housen', + 'Shambley', + 'Fanfan', + 'Bacca', + 'Battaglini', + 'Bonfanti', + 'Bongers', + 'Butzin', + 'Caira', + 'Councilman', + 'Crounse', + 'Dadisman', + 'Donais', + 'Estabrooks', + 'Fornoff', + 'Froh', + 'Gaige', + 'Garofolo', + 'Grivas', + 'Jacuinde', + 'Kalmus', + 'Kientz', + 'Kostenko', + 'Kras', + 'Lagoy', + 'Larzelere', + 'Lizer', + 'Maric', + 'Mayette', + 'Mcfeeters', + 'Meadowcroft', + 'Newgent', + 'Parpart', + 'Pauwels', + 'Perriello', + 'Persichetti', + 'Proietti', + 'Siefring', + 'Simones', + 'Taliercio', + 'Thilges', + 'Thumann', + 'Thun', + 'Tuomi', + 'Uhde', + 'Umscheid', + 'Uran', + 'Velador', + 'Veltkamp', + 'Waddoups', + 'Yeley', + 'Bihn', + 'Bladow', + 'Boeh', + 'Chadderdon', + 'Ensing', + 'Fasbender', + 'Folkert', + 'Goellner', + 'Heitmeyer', + 'Iovine', + 'Klinke', + 'Nessel', + 'Perleberg', + 'Rajagopal', + 'Sackmann', + 'Sapio', + 'Schickling', + 'Schliep', + 'Siminski', + 'Sirrine', + 'Sporn', + 'Stockburger', + 'Tangonan', + 'Tarkowski', + 'Tartaglione', + 'Traum', + 'Vanoverbeke', + 'Weirauch', + 'Wellendorf', + 'Wonnacott', + 'Camplin', + 'Leth', + 'Meltz', + 'Cavero', + 'Florido', + 'Tremont', + 'Riviello', + 'Piotter', + 'Munce', + 'Trescott', + 'Eben', + 'Vaillant', + 'Furches', + 'Bazen', + 'Esse', + 'Losier', + 'Zahir', + 'Lazier', + 'Lightell', + 'Christal', + 'Behe', + 'Blayney', + 'Buchalter', + 'Demarsh', + 'Dhondt', + 'Diefendorf', + 'Dillavou', + 'Dombkowski', + 'Duchow', + 'Fettes', + 'Gallaga', + 'Gallet', + 'Haaf', + 'Hartinger', + 'Jech', + 'Klas', + 'Kostal', + 'Kubler', + 'Leisey', + 'Leisinger', + 'Marinas', + 'Mcpeck', + 'Miccio', + 'Mikkola', + 'Morath', + 'Olthoff', + 'Pacific', + 'Penado', + 'Petronio', + 'Pirani', + 'Pitones', + 'Pociask', + 'Ratay', + 'Riesberg', + 'Ruberto', + 'Sabet', + 'Sabic', + 'Simonich', + 'Skains', + 'Skarzynski', + 'Spreeman', + 'Steig', + 'Struckhoff', + 'Trolinger', + 'Uliano', + 'Vaquerano', + 'Zukas', + 'Zwahlen', + 'Amborn', + 'Amspacher', + 'Azzaro', + 'Bartoletti', + 'Berkstresser', + 'Buboltz', + 'Ekstein', + 'Fohl', + 'Heinzel', + 'Hellmer', + 'Kapfer', + 'Kurka', + 'Mccreless', + 'Miyahira', + 'Nebergall', + 'Orlosky', + 'Pajor', + 'Quartararo', + 'Rahilly', + 'Rzasa', + 'Sabas', + 'Slutz', + 'Speros', + 'Stumpp', + 'Tamburo', + 'Tesler', + 'Tonkovich', + 'Urbieta', + 'Vallandingham', + 'Youngdahl', + 'Juliana', + 'Rienstra', + 'Prideaux', + 'Coval', + 'Hausen', + 'Seith', + 'Ny', + 'Bian', + 'Gressman', + 'Yanick', + 'Mannina', + 'Nater', + 'Gurry', + 'Vaile', + 'Sortor', + 'Woodington', + 'Apollo', + 'Mozley', + 'Patience', + 'Hearron', + 'Milloy', + 'Huntsberry', + 'Polidore', + 'Ridges', + 'Bonton', + 'Mercadel', + 'Alikhan', + 'Antis', + 'Bartosiewicz', + 'Brems', + 'Clopper', + 'Colato', + 'Collver', + 'Daino', + 'Degrande', + 'Dellis', + 'Depner', + 'Disantis', + 'Dolecki', + 'Dollens', + 'Eliasen', + 'Fasig', + 'Favinger', + 'Furuta', + 'Gharibian', + 'Gombar', + 'Gordo', + 'Gornik', + 'Gulas', + 'Khoshaba', + 'Laurita', + 'Liby', + 'Linhardt', + 'Lookabaugh', + 'Lorincz', + 'Mautner', + 'Mcquigg', + 'Meine', + 'Melaragno', + 'Meroney', + 'Mikesh', + 'Miu', + 'Monasterio', + 'Navarete', + 'Orendain', + 'Puricelli', + 'Riede', + 'Rubis', + 'Sandness', + 'Schellhase', + 'Stehlin', + 'Sunder', + 'Teaney', + 'Terman', + 'Tith', + 'Totino', + 'Tudisco', + 'Urwin', + 'Vandrunen', + 'Vasicek', + 'Youtz', + 'Berwald', + 'Bilow', + 'Bubolz', + 'Cieslewicz', + 'Denbleyker', + 'Ensinger', + 'Gantenbein', + 'Gurnsey', + 'Herceg', + 'Kless', + 'Kollias', + 'Leppek', + 'Naeve', + 'Oncale', + 'Pastran', + 'Pinyan', + 'Porrata', + 'Pustejovsky', + 'Renko', + 'Scioli', + 'Sinkhorn', + 'Sporrer', + 'Tomkiewicz', + 'Weisbeck', + 'Gautam', + 'Gleed', + 'Shave', + 'Crotzer', + 'Demarr', + 'Reckard', + 'Coyt', + 'Norberto', + 'Ury', + 'Crispen', + 'Parcells', + 'Meiklejohn', + 'Risden', + 'Bracker', + 'Askari', + 'Hyneman', + 'Auberry', + 'Bruney', + 'Weakly', + 'Ysaguirre', + 'Calender', + 'Benison', + 'Nazaire', + 'Pondexter', + 'Fryson', + 'Aguino', + 'Antonino', + 'Babilonia', + 'Banfill', + 'Beger', + 'Berardino', + 'Bizub', + 'Contractor', + 'Convey', + 'Cossairt', + 'Cruzen', + 'Dible', + 'Dorning', + 'Ellena', + 'Fafard', + 'Fano', + 'Favaro', + 'Feeler', + 'Foulger', + 'Gulbrandson', + 'Heckaman', + 'Heimerman', + 'Herms', + 'Hotchkin', + 'Jinright', + 'Kisler', + 'Kontz', + 'Kryder', + 'Lopezperez', + 'Lumm', + 'Mcelravy', + 'Meditz', + 'Melucci', + 'Meras', + 'Miyahara', + 'Musella', + 'Nelis', + 'Nhem', + 'Olivan', + 'Popson', + 'Presgraves', + 'Reindel', + 'Riege', + 'Rivenburgh', + 'Sahl', + 'Selberg', + 'Tashiro', + 'Todorov', + 'Toutant', + 'Turski', + 'Vankuren', + 'Westrup', + 'Beeney', + 'Bickhart', + 'Borkenhagen', + 'Bukoski', + 'Citrin', + 'Civello', + 'Forstrom', + 'Froning', + 'Geiler', + 'Hargadon', + 'Hemric', + 'Jeffus', + 'Klingele', + 'Kooiker', + 'Lizalde', + 'Nardiello', + 'Pestka', + 'Pignato', + 'Pudwill', + 'Rabelo', + 'Remund', + 'Skluzacek', + 'Stegenga', + 'Steidle', + 'Stenz', + 'Terlecki', + 'Vanselow', + 'Waskey', + 'Azhar', + 'Wroe', + 'Tool', + 'Leibert', + 'Vary', + 'Scovell', + 'Derick', + 'Arrey', + 'Cavness', + 'Garley', + 'Sholtz', + 'Legard', + 'Heyliger', + 'Thorns', + 'Sowells', + 'Alemu', + 'Aragones', + 'Ayllon', + 'Baab', + 'Blankenbeckler', + 'Brengle', + 'Burick', + 'Deuser', + 'Disabato', + 'Doddridge', + 'Dolinski', + 'Economy', + 'Ems', + 'Hagenow', + 'Iwen', + 'Kiesler', + 'Lehrmann', + 'Loisel', + 'Mallicoat', + 'Mansouri', + 'Marse', + 'Mccartt', + 'Menninger', + 'Montee', + 'Nappa', + 'Ohanesian', + 'Podgurski', + 'Prosch', + 'Puder', + 'Ritthaler', + 'Rodelo', + 'Shipper', + 'Shorkey', + 'Sirna', + 'Smedberg', + 'Smink', + 'Strahle', + 'Troeger', + 'Twaddell', + 'Vandyk', + 'Wandrey', + 'Yaworski', + 'Zagami', + 'Duecker', + 'Finlinson', + 'Frysinger', + 'Grush', + 'Knackstedt', + 'Morozov', + 'Murgia', + 'Naffziger', + 'Ontko', + 'Piltz', + 'Roskelley', + 'Sonderman', + 'Garrand', + 'Kopack', + 'Theys', + 'Sanseverino', + 'Budai', + 'Selwyn', + 'Assante', + 'Nary', + 'Fildes', + 'Tano', + 'Hogen', + 'Gennett', + 'Melka', + 'Thorner', + 'Grandjean', + 'Dury', + 'Gerrald', + 'Quilling', + 'Mccallon', + 'Preister', + 'Kydd', + 'Cranshaw', + 'Folson', + 'Roker', + 'Dockett', + 'Stfort', + 'Haymer', + 'Njie', + 'Adamik', + 'Aredondo', + 'Bathrick', + 'Beldin', + 'Blackwater', + 'Branscom', + 'Cappucci', + 'Cartelli', + 'Carullo', + 'Cunneen', + 'Davee', + 'Deboy', + 'Defrates', + 'Esham', + 'Furio', + 'Garverick', + 'Gimlin', + 'Gosline', + 'Gromer', + 'Halbig', + 'Hasbrook', + 'Holgerson', + 'Hupfer', + 'Jochem', + 'Kihn', + 'Klotzbach', + 'Lantagne', + 'Leichter', + 'Lerette', + 'Lupu', + 'Machorro', + 'Mieles', + 'Mikulec', + 'Mirante', + 'Nasrallah', + 'Piccini', + 'Pinkhasov', + 'Poplaski', + 'Pottenger', + 'Rahrig', + 'Ranganathan', + 'Ravan', + 'Righi', + 'Rogacki', + 'Sadlon', + 'Salafia', + 'Schlitz', + 'Slayback', + 'Stetzel', + 'Tamargo', + 'Tenore', + 'Verkuilen', + 'Vuncannon', + 'Waggle', + 'Bacorn', + 'Boerema', + 'Cimorelli', + 'Ciresi', + 'Dethlefs', + 'Dimarzo', + 'Ficco', + 'Floresca', + 'Gnau', + 'Hefel', + 'Holbein', + 'Klepacki', + 'Konigsberg', + 'Lienau', + 'Malsam', + 'Meidl', + 'Nawabi', + 'Netzley', + 'Renbarger', + 'Rumbold', + 'Sarafian', + 'Sonnenfeld', + 'Tindol', + 'Trettin', + 'Tuckerman', + 'Vanderweele', + 'Weppler', + 'Westbay', + 'Zaveri', + 'Boran', + 'Deighan', + 'Rothery', + 'Yom', + 'Gatley', + 'Caldron', + 'Lucado', + 'Dromgoole', + 'Novell', + 'Sherriff', + 'Gerrick', + 'Balgobin', + 'Danger', + 'Sookram', + 'Daron', + 'Knibbs', + 'Faggart', + 'Beidleman', + 'Russey', + 'Lagrand', + 'Bluett', + 'Glaspy', + 'Baldon', + 'Trueheart', + 'Cradle', + 'Asfaw', + 'Ballinas', + 'Bogdon', + 'Brizzi', + 'Carrio', + 'Cherny', + 'Crogan', + 'Depierro', + 'Dhami', + 'Dresden', + 'Finnicum', + 'Geltz', + 'Granade', + 'Granieri', + 'Guia', + 'Hashagen', + 'Hollick', + 'Jicha', + 'Jollie', + 'Kathan', + 'Malara', + 'Manabat', + 'Mehall', + 'Midcap', + 'Mitre', + 'Newburg', + 'Parveen', + 'Pianka', + 'Plouff', + 'Posillico', + 'Ransier', + 'Reano', + 'Roskam', + 'Rufer', + 'Schnetzer', + 'Scorsone', + 'Sitterly', + 'Skilton', + 'Sohail', + 'Starin', + 'Stavish', + 'Tufaro', + 'Vano', + 'Vinsant', + 'Vlahakis', + 'Vondrasek', + 'Waldroop', + 'Wamboldt', + 'Achatz', + 'Bomkamp', + 'Fetzner', + 'Gemmer', + 'Haroutunian', + 'Hurtig', + 'Juncaj', + 'Kleban', + 'Knier', + 'Kopischke', + 'Kugelman', + 'Lacoss', + 'Meulemans', + 'Neyens', + 'Niccoli', + 'Oberhaus', + 'Penkala', + 'Podoll', + 'Roupp', + 'Scozzari', + 'Siverling', + 'Uhls', + 'Werber', + 'Grealish', + 'Montieth', + 'Haik', + 'Kuri', + 'Kanaan', + 'Prenatt', + 'Dingledine', + 'Mccamy', + 'Balin', + 'Droney', + 'Clyatt', + 'Ramone', + 'Anglen', + 'Mathus', + 'Bagent', + 'Lamarque', + 'Arscott', + 'Romes', + 'Speigner', + 'Latouche', + 'Tripplett', + 'Eversley', + 'Aquirre', + 'Bernales', + 'Bouthillier', + 'Cavendish', + 'Detienne', + 'Dewbre', + 'Dimuro', + 'Dosh', + 'Dunklee', + 'Duyck', + 'Emilio', + 'Ence', + 'Garofano', + 'Gellis', + 'Haertel', + 'Handyside', + 'Hornburg', + 'Jenniges', + 'Kallhoff', + 'Klontz', + 'Langsdorf', + 'Leabo', + 'Lorette', + 'Maracle', + 'Merta', + 'Muoio', + 'Nierenberg', + 'Oborn', + 'Osorto', + 'Ruscitti', + 'Santaella', + 'Spinnato', + 'Stentz', + 'Stocke', + 'Sundt', + 'Thorup', + 'Tresch', + 'Urdaneta', + 'Uttech', + 'Vosler', + 'Wieand', + 'Zacharia', + 'Zeleznik', + 'Zoucha', + 'Zuch', + 'Abrell', + 'Atiyeh', + 'Aydt', + 'Cleeton', + 'Crisan', + 'Cwikla', + 'Denz', + 'Diesing', + 'Emmi', + 'Fringer', + 'Gibbard', + 'Graunke', + 'Gschwind', + 'Hafele', + 'Hoogland', + 'Howsare', + 'Kesecker', + 'Kilgallon', + 'Kleyman', + 'Kufahl', + 'Laut', + 'Malstrom', + 'Michetti', + 'Nosbisch', + 'Rasner', + 'Rosekrans', + 'Schnebly', + 'Staebell', + 'Theilen', + 'Tieszen', + 'Mellone', + 'Burcher', + 'Feister', + 'Hoage', + 'Irmen', + 'Derwin', + 'Dien', + 'Markins', + 'Egnew', + 'Dunlow', + 'Brickel', + 'Curt', + 'Smyly', + 'Whedbee', + 'Larman', + 'Boisselle', + 'Jaquess', + 'Bowns', + 'Nile', + 'Boyson', + 'Phillipps', + 'Weech', + 'Pillars', + 'Cauldwell', + 'Wynns', + 'Toca', + 'Scorza', + 'Ramsaran', + 'Arkwright', + 'Gurganious', + 'Jubert', + 'Beed', + 'Kellem', + 'Gervin', + 'Yarn', + 'Bookhart', + 'Sullen', + 'Moncrieffe', + 'Eze', + 'Agyeman', + 'Aldea', + 'Amodei', + 'Attig', + 'Bergthold', + 'Blaskowski', + 'Blitzer', + 'Bowring', + 'Brenning', + 'Chappuis', + 'Cordasco', + 'Cosens', + 'Denoble', + 'Dochterman', + 'Domek', + 'Embleton', + 'Georgiades', + 'Gintz', + 'Grooters', + 'Hoell', + 'Honse', + 'Jagiello', + 'Jaskulski', + 'Kaluzny', + 'Keske', + 'Khiev', + 'Koeneman', + 'Majestic', + 'Mandile', + 'Marandola', + 'Mcinroy', + 'Nienhaus', + 'Peckenpaugh', + 'Raquel', + 'Rossler', + 'Rusconi', + 'Schaffert', + 'Schipani', + 'Sittner', + 'Sweezey', + 'Swenor', + 'Tagliaferro', + 'Tubby', + 'Ulep', + 'Vallette', + 'Westergren', + 'Yaros', + 'Yasui', + 'Anway', + 'Bannick', + 'Biasi', + 'Breitling', + 'Catarino', + 'Dunaj', + 'Giovanelli', + 'Hemmerich', + 'Iott', + 'Knotek', + 'Kraeger', + 'Laskaris', + 'Lomboy', + 'Oleski', + 'Reibel', + 'Rightmyer', + 'Salmela', + 'Salow', + 'Siebels', + 'Spielvogel', + 'Streitmatter', + 'Ucci', + 'Windmiller', + 'Wojtkiewicz', + 'Zirkel', + 'Markie', + 'Nedeau', + 'Froehle', + 'Jesson', + 'Regala', + 'Boody', + 'Hayen', + 'Ose', + 'Loewy', + 'Radliff', + 'Davia', + 'Sky', + 'Halker', + 'Alu', + 'Ey', + 'Badawi', + 'Yeargain', + 'Jeanette', + 'Doublin', + 'Nolton', + 'Streety', + 'Blueford', + 'Abeles', + 'Aldava', + 'Alsteen', + 'Altadonna', + 'Apa', + 'Behlke', + 'Bellisario', + 'Bienstock', + 'Brenan', + 'Capley', + 'Castoro', + 'Demir', + 'Evinger', + 'Gartside', + 'Gellatly', + 'Goldinger', + 'Grabel', + 'Henkin', + 'Herrle', + 'Honegger', + 'Kunin', + 'Larmer', + 'Lizano', + 'Lorino', + 'Malcomson', + 'Matesic', + 'Mathiasen', + 'Mccolm', + 'Meenach', + 'Mullady', + 'Neiderer', + 'Ogier', + 'Omura', + 'Plog', + 'Pomplun', + 'Procida', + 'Raisbeck', + 'Rastetter', + 'Reither', + 'Rettberg', + 'Roblee', + 'Rossitto', + 'Scahill', + 'Schmoker', + 'Segreto', + 'Shelstad', + 'Shwartz', + 'Sondgeroth', + 'Supnet', + 'Swartzbaugh', + 'Tkachenko', + 'Urbani', + 'Vanslooten', + 'Varricchio', + 'Villarino', + 'Whiston', + 'Wyffels', + 'Yehle', + 'Basinski', + 'Belvedere', + 'Bernabei', + 'Bolotin', + 'Bresett', + 'Dabkowski', + 'Dalsanto', + 'Gotwalt', + 'Hellberg', + 'Hunke', + 'Kroenke', + 'Leppla', + 'Luginbuhl', + 'Mimnaugh', + 'Mullenbach', + 'Nearhood', + 'Raser', + 'Resendis', + 'Seydel', + 'Sozio', + 'Stillions', + 'Stormont', + 'Strimple', + 'Toruno', + 'Trouten', + 'Tryba', + 'Vandalen', + 'Wilhelmy', + 'Orland', + 'Loui', + 'Morcos', + 'Radell', + 'Artus', + 'Truxillo', + 'Copelan', + 'Bress', + 'Unthank', + 'Sudlow', + 'Branden', + 'Rowzee', + 'Montreuil', + 'Sollers', + 'Umar', + 'Coulibaly', + 'Allegretto', + 'Andreen', + 'Bielicki', + 'Bustard', + 'Cardosi', + 'Carkhuff', + 'Cetina', + 'Clouthier', + 'Dolata', + 'Fiola', + 'Fjeld', + 'Gawthrop', + 'Glastetter', + 'Hamlyn', + 'Hanten', + 'Huerter', + 'Kreiss', + 'Lestrange', + 'Litzau', + 'Luberto', + 'Menconi', + 'Milosevic', + 'Munera', + 'Nachtigal', + 'Nethers', + 'Nicolaou', + 'Olund', + 'Paddack', + 'Pfiester', + 'Pilley', + 'Polendo', + 'Porcayo', + 'Preast', + 'Runquist', + 'Saccente', + 'Santoli', + 'Saragoza', + 'Selway', + 'Smestad', + 'Stebner', + 'Toben', + 'Trapnell', + 'Urschel', + 'Verno', + 'Vidovich', + 'Walterscheid', + 'Yoh', + 'Zmijewski', + 'Allwein', + 'Bessire', + 'Broering', + 'Budzik', + 'Denherder', + 'Goerner', + 'Goldbaum', + 'Grussing', + 'Huaracha', + 'Ippoliti', + 'Kanak', + 'Kaucher', + 'Kious', + 'Kirkner', + 'Kratzke', + 'Kubisiak', + 'Kueny', + 'Mazzilli', + 'Mazzo', + 'Mcclenathan', + 'Mehlberg', + 'Miotke', + 'Nihiser', + 'Olheiser', + 'Oravetz', + 'Radwanski', + 'Shinsato', + 'Vandekamp', + 'Zagata', + 'Abert', + 'Llera', + 'Thommen', + 'Wirkkala', + 'Brasuell', + 'Shawler', + 'Mourey', + 'Gavia', + 'Morgano', + 'Newill', + 'Rathel', + 'Wist', + 'Braner', + 'Soman', + 'Koskey', + 'Searson', + 'Brocksmith', + 'Peale', + 'Couzens', + 'Shall', + 'Anis', + 'Stanly', + 'Cauthorn', + 'Kinkle', + 'Laughinghouse', + 'Mellette', + 'Rox', + 'Demetrius', + 'Cullars', + 'Summons', + 'Banwart', + 'Bartl', + 'Bebb', + 'Bobier', + 'Bogdanoff', + 'Bollmann', + 'Borrowman', + 'Borseth', + 'Buttitta', + 'Canelo', + 'Cassedy', + 'Cata', + 'Crivelli', + 'Daane', + 'Dhingra', + 'Dipple', + 'Dovidio', + 'Duesler', + 'Eissler', + 'Ent', + 'Falotico', + 'Goodrick', + 'Goupil', + 'Huels', + 'Keithly', + 'Killilea', + 'Klausing', + 'Kludt', + 'Licitra', + 'Llerenas', + 'Merolla', + 'Oatley', + 'Osmanovic', + 'Poudrier', + 'Raben', + 'Realmuto', + 'Reczek', + 'Ricchio', + 'Rossner', + 'Rozak', + 'Sandora', + 'Schuenemann', + 'Seres', + 'Shoptaw', + 'Splitt', + 'Tonkinson', + 'Willardson', + 'Winterberg', + 'Zayac', + 'Bobzien', + 'Buhman', + 'Carotenuto', + 'Chynoweth', + 'Defenbaugh', + 'Dipiero', + 'Duve', + 'Goonan', + 'Gragert', + 'Hangartner', + 'Heemstra', + 'Hensch', + 'Hollatz', + 'Jakubowicz', + 'Kapaun', + 'Kiener', + 'Landesman', + 'Lenzini', + 'Longbottom', + 'Parde', + 'Pincock', + 'Schlicker', + 'Shankel', + 'Vidas', + 'Waisner', + 'Zilberman', + 'Allcock', + 'Durban', + 'Javid', + 'Shoda', + 'Edes', + 'Boxwell', + 'Dezern', + 'Rubley', + 'Angelica', + 'Jeannette', + 'Planer', + 'Pata', + 'Lothridge', + 'Lucks', + 'Bais', + 'Sandra', + 'Enwright', + 'Maxton', + 'Radway', + 'Hoof', + 'Morisset', + 'Danzey', + 'Ancar', + 'Mcwright', + 'Leggs', + 'Monestime', + 'Massaquoi', + 'Barkow', + 'Bastyr', + 'Bautz', + 'Behanna', + 'Bewick', + 'Bezdek', + 'Bielby', + 'Bretschneider', + 'Bugher', + 'Carchi', + 'Chapp', + 'Conser', + 'Crete', + 'Derflinger', + 'Elsbernd', + 'Freimark', + 'Gerwin', + 'Grunfeld', + 'Harpham', + 'Hoeschen', + 'Holmlund', + 'Horch', + 'Hulsebus', + 'Kassabian', + 'Konczal', + 'Korell', + 'Lacuesta', + 'Lantier', + 'Larowe', + 'Lietzke', + 'Lunny', + 'Masin', + 'Massicotte', + 'Michalsky', + 'Notarianni', + 'Pautsch', + 'Poppy', + 'Sukup', + 'Suleski', + 'Tafel', + 'Wanninger', + 'Zaffino', + 'Zody', + 'Arganbright', + 'Bohmer', + 'Cintora', + 'Connatser', + 'Dlugos', + 'Fariello', + 'Fedie', + 'Felicetti', + 'Garno', + 'Gottsch', + 'Gratzer', + 'Gubser', + 'Kappelman', + 'Kuechle', + 'Laningham', + 'Latsch', + 'Longie', + 'Luscher', + 'Lybeck', + 'Rhude', + 'Setterlund', + 'Sobh', + 'Sonneborn', + 'Villamizar', + 'Wolstenholme', + 'Zacek', + 'Leppanen', + 'Casdorph', + 'Pinsker', + 'Reutov', + 'Rede', + 'Sheck', + 'Bakley', + 'Radde', + 'Moher', + 'Khader', + 'Rossie', + 'Scriver', + 'Provine', + 'Debarge', + 'Darke', + 'Griswell', + 'Naji', + 'Frere', + 'Cheevers', + 'Schnyder', + 'Curb', + 'Luten', + 'Cashaw', + 'Agerton', + 'Barnier', + 'Bluestone', + 'Boward', + 'Boyar', + 'Briano', + 'Bryngelson', + 'Calef', + 'Caraher', + 'Castelluccio', + 'Conk', + 'Crewse', + 'Demarzo', + 'Deutschman', + 'Eckrote', + 'Edmister', + 'Ferg', + 'Ghan', + 'Giampaolo', + 'Goedecke', + 'Gonet', + 'Gradel', + 'Gregston', + 'Grzesiak', + 'Guallpa', + 'Hanline', + 'Hardyman', + 'Hogate', + 'Houg', + 'Justiss', + 'Kaps', + 'Klopf', + 'Kniskern', + 'Laneve', + 'Lenhoff', + 'Lojewski', + 'Melott', + 'Milillo', + 'Passage', + 'Pereyda', + 'Plack', + 'Poet', + 'Prospero', + 'Quadros', + 'Revelo', + 'Rogier', + 'Sanabia', + 'Tragesser', + 'Vanarsdall', + 'Vanausdal', + 'Verbrugge', + 'Wandler', + 'Zoss', + 'Balzarini', + 'Brotz', + 'Bulin', + 'Bumann', + 'Cancro', + 'Centner', + 'Deblasi', + 'Duesing', + 'Friedley', + 'Frieling', + 'Heinke', + 'Holzheimer', + 'Klinck', + 'Knouff', + 'Kuczek', + 'Leible', + 'Lerum', + 'Liddicoat', + 'Mikowski', + 'Nonaka', + 'Ohlman', + 'Picaso', + 'Plamann', + 'Porretta', + 'Prajapati', + 'Rancour', + 'Stepka', + 'Studzinski', + 'Vaysman', + 'Wallenstein', + 'Wunderlin', + 'Pattinson', + 'Siskind', + 'Sitzer', + 'Thuman', + 'Barella', + 'Brillon', + 'Arnholt', + 'Karge', + 'Dohman', + 'Morone', + 'Macie', + 'Aken', + 'Lye', + 'Student', + 'Westen', + 'Bonsell', + 'Komara', + 'Hafiz', + 'Stickland', + 'Morina', + 'Creekmur', + 'Hussien', + 'Walrond', + 'Louischarles', + 'Alkema', + 'Angert', + 'Arcidiacono', + 'Ashkar', + 'Bookbinder', + 'Bootz', + 'Cilia', + 'Devilla', + 'Difatta', + 'Enberg', + 'Enderby', + 'Forbess', + 'Frutiger', + 'Graefe', + 'Guenette', + 'Hauschildt', + 'Keirsey', + 'Kolka', + 'Kopelman', + 'Lewan', + 'Mcluckie', + 'Mia', + 'Moebius', + 'Oestreicher', + 'Oprea', + 'Ortolano', + 'Padovani', + 'Pensabene', + 'Phimmasone', + 'Pointon', + 'Punches', + 'Schertzer', + 'Seoane', + 'Skramstad', + 'Sorlie', + 'Syfert', + 'Tasca', + 'Townzen', + 'Wernli', + 'Wurzel', + 'Yazdi', + 'Devendorf', + 'Featherly', + 'Frush', + 'Heringer', + 'Iwai', + 'Kallenberger', + 'Kobashigawa', + 'Langbehn', + 'Livecchi', + 'Middlesworth', + 'Niess', + 'Osterlund', + 'Ruz', + 'Seiwert', + 'Vanwieren', + 'Wernet', + 'Grabbe', + 'Gaugh', + 'Mcclarren', + 'Raudales', + 'Urry', + 'Clere', + 'Lacer', + 'Mathia', + 'Mccrumb', + 'Cotrell', + 'Mannor', + 'Medine', + 'Tittsworth', + 'Hughston', + 'Buick', + 'Limes', + 'Hams', + 'Thagard', + 'Leavelle', +]; diff --git a/drizzle-seed/src/datasets/loremIpsumSentences.ts b/drizzle-seed/src/datasets/loremIpsumSentences.ts new file mode 100644 index 000000000..f03277d86 --- /dev/null +++ b/drizzle-seed/src/datasets/loremIpsumSentences.ts @@ -0,0 +1,1639 @@ +/** + * Data was generated, using https://www.lipsum.com/ + */ +export default [ + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + 'Nam porta quis ex a blandit.', + 'Donec ullamcorper erat sed diam luctus, eu euismod nibh eleifend.', + 'Curabitur sit amet tortor vehicula lacus mollis efficitur eu feugiat tortor.', + 'Quisque in erat vitae nisl tristique blandit.', + 'Vivamus in lectus tellus.', + 'Donec quis neque sit amet diam elementum accumsan.', + 'Sed vitae sollicitudin tellus, sed rhoncus magna.', + 'Aliquam eu interdum purus, sed viverra lorem.', + 'Etiam eget viverra dui.', + 'Morbi vel risus dolor.', + 'Donec laoreet, ipsum sed vestibulum venenatis, ligula leo fermentum enim, in pharetra lorem massa volutpat metus.', + 'Aliquam egestas mi in urna blandit, quis viverra justo condimentum.', + 'Maecenas pulvinar quam sapien, sed euismod enim rhoncus quis.', + 'Maecenas at quam non elit varius rutrum.', + 'Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + 'Quisque et malesuada erat.', + 'Maecenas eleifend tellus eu luctus tempor.', + 'Cras at scelerisque massa, quis dapibus urna.', + 'Aliquam porttitor a risus quis luctus.', + 'Aenean mollis ex tempor ligula cursus, interdum porttitor nibh fringilla.', + 'Donec aliquet ac nulla nec scelerisque.', + 'Curabitur neque diam, posuere nec tortor a, posuere pretium odio.', + 'Nullam et vehicula ante.', + 'Etiam mattis, odio quis sodales maximus, nisl lectus sagittis ligula, quis ornare urna nibh ac est.', + 'Pellentesque eget finibus eros.', + 'Maecenas gravida risus vitae vestibulum facilisis.', + 'Sed rhoncus libero fringilla arcu viverra tempus.', + 'Suspendisse non lacus vitae urna viverra vehicula.', + 'Pellentesque eu elementum enim.', + 'Morbi aliquet nisl eu accumsan rhoncus.', + 'Ut fringilla dolor ut odio blandit, et dignissim lectus placerat.', + 'Aliquam vulputate mauris elit, in semper purus accumsan tempor.', + 'Sed at elit ut ligula bibendum tincidunt.', + 'Maecenas ut tristique ipsum, ac sollicitudin quam.', + 'Pellentesque ut ante quis tellus pellentesque tempus.', + 'Nulla suscipit ex eget ex cursus accumsan.', + 'Sed at purus sapien.', + 'Fusce feugiat ante ac massa aliquam, maximus bibendum arcu convallis.', + 'Interdum et malesuada fames ac ante ipsum primis in faucibus.', + 'Cras vitae dignissim leo, ac pretium est.', + 'Aliquam lectus lectus, varius in eros eget, tempus sollicitudin ex.', + 'Nunc gravida mi lectus, tincidunt ultrices sapien lobortis cursus.', + 'Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.', + 'Maecenas aliquam vulputate justo vel lacinia.', + 'Nam facilisis augue vitae dolor mattis, sit amet maximus orci molestie.', + 'Etiam et nibh id lorem viverra aliquet.', + 'Quisque et mauris et odio finibus ullamcorper id eget odio.', + 'Duis sit amet varius purus.', + 'In congue posuere libero, nec tincidunt dui suscipit ac.', + 'Vivamus suscipit risus vel massa commodo pulvinar vitae eu diam.', + 'Mauris porta non orci at dapibus.', + 'Sed ullamcorper, sem ac fringilla tristique, purus massa hendrerit turpis, at elementum massa nulla nec quam.', + 'Praesent sed felis vitae felis vestibulum hendrerit vel at ipsum.', + 'Nunc egestas, lectus feugiat consequat auctor, erat mauris pretium sapien, et consequat magna ex id purus.', + 'Maecenas nibh ex, bibendum at augue eget, pulvinar cursus libero.', + 'Quisque ultricies vestibulum neque, in sollicitudin felis euismod in.', + 'Maecenas viverra mauris sit amet neque vulputate, sed suscipit sapien laoreet.', + 'Sed vitae sapien maximus, faucibus enim a, placerat erat.', + 'Cras maximus ipsum nec dui fermentum, eu facilisis augue fringilla.', + 'Sed eget nibh ante.', + 'Praesent pellentesque sodales tellus non consectetur.', + 'Suspendisse pulvinar, massa id gravida facilisis, diam nulla molestie metus, et convallis purus elit quis sapien.', + 'Mauris fermentum nec metus id consectetur.', + 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.', + 'Nulla vel maximus nunc.', + 'Duis dolor orci, tempor nec odio at, gravida congue ex.', + 'Pellentesque faucibus, est et eleifend commodo, ipsum nunc lobortis felis, at aliquam erat leo eu massa.', + 'Morbi egestas vehicula lacus, in pharetra nulla dictum in.', + 'Ut facilisis, erat eu suscipit mollis, ipsum ex sagittis augue, sit amet vehicula neque nunc ut leo.', + 'Donec dapibus non odio non auctor.', + 'Donec vitae ipsum eget risus vulputate vestibulum.', + 'Cras vestibulum purus leo, in porttitor erat finibus quis.', + 'Vivamus tincidunt justo diam, placerat maximus orci congue ac.', + 'Curabitur pulvinar congue accumsan.', + 'Vivamus eget velit dictum, sagittis diam eu, elementum diam.', + 'Quisque pharetra pellentesque purus at tristique.', + 'Cras dignissim arcu massa, eu pellentesque eros tristique id.', + 'Proin efficitur turpis vel sem ultricies molestie.', + 'Curabitur rhoncus viverra nibh ut sollicitudin.', + 'Vestibulum ut magna dolor.', + 'Suspendisse placerat eleifend lorem, at aliquet enim lacinia ut.', + 'Integer at nisi eu ex viverra viverra.', + 'Morbi finibus bibendum volutpat.', + 'Donec facilisis sem id eros tempor vehicula.', + 'Phasellus a dolor in dolor finibus iaculis et at quam.', + 'Phasellus volutpat nulla eget mauris blandit pharetra ut sit amet augue.', + 'Phasellus leo urna, ornare ut mauris ultrices, posuere imperdiet dui.', + 'Morbi accumsan bibendum neque, sit amet eleifend nunc bibendum nec.', + 'Praesent dapibus tristique tempor.', + 'Duis dapibus nulla in lectus luctus, nec blandit sem tristique.', + 'In odio dolor, consectetur eget sapien egestas, viverra pharetra urna.', + 'Nam risus est, suscipit fermentum tincidunt id, vehicula vitae arcu.', + 'Aenean venenatis pretium condimentum.', + 'Mauris lobortis blandit dapibus.', + 'Phasellus aliquet efficitur condimentum.', + 'Nam pulvinar ullamcorper metus ac vehicula.', + 'Donec eget auctor tellus.', + 'Morbi quis diam ultrices, tristique lectus eu, vehicula dolor.', + 'Aenean malesuada lorem sed vestibulum rutrum.', + 'Praesent quis metus id quam facilisis blandit.', + 'Proin venenatis eleifend augue nec gravida.', + 'Nulla eget vehicula mauris, vel rutrum ligula.', + 'Ut interdum aliquam fermentum.', + 'Morbi elementum metus ut velit pellentesque lacinia.', + 'Suspendisse malesuada est sed varius rhoncus.', + 'Sed eu porta ex.', + 'Nullam dignissim egestas dapibus.', + 'Vestibulum a pharetra ipsum.', + 'Donec in interdum diam.', + 'Morbi viverra id sem quis mollis.', + 'In eget porta lorem.', + 'Aliquam tincidunt feugiat magna, vel finibus odio rutrum sit amet.', + 'Morbi faucibus metus at vehicula efficitur.', + 'Cras metus lectus, egestas lacinia leo vitae, lacinia dapibus quam.', + 'Morbi tincidunt ut velit sed hendrerit.', + 'Vivamus eleifend at leo porttitor blandit.', + 'Morbi egestas diam augue, vel condimentum odio pulvinar id.', + 'Morbi porta vulputate ante sed lacinia.', + 'Fusce massa est, varius et lacinia sit amet, dictum at turpis.', + 'Vestibulum viverra augue elit, eget tristique ipsum accumsan vitae.', + 'Sed sit amet ex sapien.', + 'Mauris dapibus tincidunt scelerisque.', + 'Aliquam nunc libero, vestibulum id facilisis in, sollicitudin vitae nulla.', + 'Aenean a nulla commodo, rutrum orci eget, pellentesque erat.', + 'Aenean ut sem felis.', + 'Donec sapien ante, ornare sit amet ornare id, mattis lobortis tellus.', + 'Nam ut placerat metus.', + 'Vivamus in cursus eros, sit amet scelerisque mauris.', + 'Integer tempus, justo vel aliquet aliquam, mi libero iaculis leo, placerat sollicitudin mauris ipsum faucibus justo.', + 'Cras at vehicula urna.', + 'Phasellus id nunc eu enim ultricies hendrerit.', + 'Nulla sodales sodales orci in placerat.', + 'Donec placerat, justo in imperdiet euismod, nulla metus pharetra nibh, nec auctor tortor mauris ac augue.', + 'Donec at elit non odio malesuada consequat non id velit.', + 'Morbi pellentesque eleifend iaculis.', + 'Aliquam ullamcorper lacinia vulputate.', + 'Nulla commodo risus et efficitur mollis.', + 'In venenatis consectetur metus, in iaculis ligula bibendum fermentum.', + 'Nullam ac finibus nisl.', + 'Aenean blandit sagittis justo, ut cursus tortor vehicula vel.', + 'Integer at pulvinar eros, sed dictum ex.', + 'Phasellus bibendum interdum porttitor.', + 'Fusce blandit egestas nisl, quis mattis elit commodo in.', + 'Donec in ex justo.', + 'Aenean elementum tristique eros, vel mattis tellus malesuada nec.', + 'Quisque euismod tincidunt erat.', + 'Proin turpis orci, vehicula vitae ipsum et, auctor ornare ex.', + 'Nunc efficitur nisl sit amet justo faucibus, eu bibendum diam pretium.', + 'Nullam consectetur finibus dui at malesuada.', + 'Ut elementum, ante vitae gravida feugiat, orci enim molestie libero, ut vehicula purus ipsum a eros.', + 'Ut mi neque, vestibulum nec nibh eu, imperdiet elementum ipsum.', + 'Donec cursus augue quis ex rutrum lacinia.', + 'Mauris purus mi, pellentesque at leo in, auctor ultrices massa.', + 'Maecenas finibus quam quis arcu mattis porttitor.', + 'Suspendisse ac urna ac odio aliquet congue.', + 'Integer suscipit, odio in ullamcorper ornare, diam nibh elementum eros, a aliquam lacus velit vel mauris.', + 'Quisque ut bibendum risus.', + 'Suspendisse bibendum augue pellentesque, dapibus leo ac, luctus purus.', + 'Phasellus interdum ipsum sit amet elit rhoncus varius.', + 'Pellentesque pharetra lorem et nibh aliquam, vel luctus elit sodales.', + 'Maecenas ornare cursus metus in efficitur.', + 'Phasellus laoreet ipsum nec erat mattis, vitae vulputate risus auctor.', + 'Maecenas augue magna, mattis elementum dapibus sed, vulputate venenatis ante.', + 'Fusce non lorem vitae velit molestie auctor.', + 'Etiam sodales, orci sed consequat luctus, ante urna hendrerit ipsum, at ultrices mauris neque in velit.', + 'Vestibulum a egestas ipsum.', + 'Donec sit amet laoreet mi.', + 'Quisque varius ligula dolor.', + 'Morbi sodales volutpat nulla, et ullamcorper lacus bibendum at.', + 'In mattis in dui quis facilisis.', + 'Cras pulvinar, massa eu rhoncus rhoncus, mi mi ultricies turpis, eu iaculis elit nulla et metus.', + 'Donec et neque suscipit, iaculis ipsum at, maximus eros.', + 'Quisque eu accumsan risus.', + 'Phasellus in consectetur nisl.', + 'Nullam interdum porttitor enim fermentum bibendum.', + 'Vestibulum consequat fermentum mollis.', + 'Quisque id velit sit amet magna posuere aliquam vel in nunc.', + 'Maecenas nisl lectus, sollicitudin eu auctor nec, cursus vel quam.', + 'Proin elementum efficitur velit vel vestibulum.', + 'Nunc non tincidunt ex.', + 'Fusce nec nisl eget nunc fringilla dignissim vel nec ex.', + 'Cras malesuada erat quis ligula lacinia consectetur.', + 'Aliquam semper elit ante, sed accumsan lacus molestie in.', + 'Vivamus porttitor enim eros, eu ultricies lectus pulvinar eget.', + 'Nullam consequat tincidunt ligula, eu luctus nisi congue id.', + 'Aenean lacinia lobortis ante, fermentum vulputate turpis eleifend faucibus.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Phasellus tempus libero non ipsum cursus rhoncus.', + 'Sed euismod molestie augue vitae fringilla.', + 'Pellentesque mi tortor, tempor quis condimentum quis, lobortis quis quam.', + 'Sed in vestibulum purus, in vestibulum neque.', + 'Etiam pellentesque ligula ligula, sit amet varius mi venenatis fringilla.', + 'Morbi vitae est ac diam convallis sagittis in facilisis ligula.', + 'Sed vel consequat diam.', + 'Nunc ac tempor felis.', + 'Aenean luctus tristique urna lacinia venenatis.', + 'Suspendisse vehicula auctor accumsan.', + 'Suspendisse ultrices rhoncus nisi a pellentesque.', + 'Sed sollicitudin id orci ut laoreet.', + 'Cras pulvinar lorem ut ipsum malesuada, sed euismod turpis placerat.', + 'Ut vitae massa quis augue posuere ultricies.', + 'In quis erat posuere, posuere dolor ac, tempus tortor.', + 'Aliquam aliquet nisl eu tortor mollis, id dictum nisi congue.', + 'Etiam pulvinar, ex a tincidunt bibendum, nisl elit venenatis lacus, nec dictum odio ligula non nulla.', + 'Etiam sit amet nunc vestibulum, pharetra diam ac, lacinia felis.', + 'Quisque volutpat laoreet lorem, sit amet porta justo ultrices aliquet.', + 'Praesent aliquet nisi elit, ut facilisis orci accumsan vitae.', + 'Quisque vehicula augue at leo varius, ac dictum tortor viverra.', + 'Proin eu bibendum diam.', + 'Aliquam blandit, erat et feugiat varius, erat mauris convallis ipsum, ut convallis massa erat vel neque.', + 'Sed commodo nec ipsum in maximus.', + 'Pellentesque ligula nisl, tincidunt volutpat convallis non, interdum quis felis.', + 'Nunc ultrices neque ut diam congue, non tristique metus tempor.', + 'Pellentesque sodales metus leo, at eleifend dui pretium at.', + 'Suspendisse sit amet metus at est viverra fermentum.', + 'Donec ac odio vitae urna blandit consectetur.', + 'Vivamus tincidunt cursus nunc in mollis.', + 'Nullam malesuada quis odio eu imperdiet.', + 'Integer convallis sapien vitae semper varius.', + 'Nullam malesuada tincidunt lacus elementum condimentum.', + 'Nam eget neque vitae leo convallis aliquam id eu quam.', + 'Quisque aliquet elementum lectus, vitae pharetra nisl facilisis at.', + 'Fusce ut velit porttitor, porta erat ac, vehicula odio.', + 'Sed tempor est at nulla mollis aliquet.', + 'Quisque luctus dolor eu placerat ultrices.', + 'Vivamus luctus ex non ante pretium venenatis.', + 'Ut non arcu vitae velit pellentesque accumsan eget id risus.', + 'Pellentesque accumsan elementum turpis, a aliquam dui sodales nec.', + 'Donec quis semper tortor, scelerisque venenatis velit.', + 'Morbi tempus lacus pretium risus rhoncus, tincidunt lacinia diam dapibus.', + 'Donec libero neque, aliquet non aliquet et, mollis at est.', + 'Fusce mauris tortor, molestie ut porttitor nec, euismod consequat metus.', + 'Maecenas in nunc blandit, sagittis orci sed, fringilla risus.', + 'Suspendisse vel vulputate velit.', + 'Nulla aliquam facilisis velit.', + 'Donec placerat porttitor sapien.', + 'Quisque non pharetra mi.', + 'Suspendisse mattis justo nec arcu efficitur, nec suscipit mi tempor.', + 'Sed et dui vitae nisi accumsan faucibus nec vel odio.', + 'Donec at lacus eget nisi ultricies efficitur.', + 'Aenean ultricies elit eget mi consectetur imperdiet.', + 'Ut lorem magna, ullamcorper sit amet dui quis, pulvinar cursus felis.', + 'Morbi ligula nibh, fermentum nec pellentesque eget, sodales in sapien.', + 'Sed eu vehicula mi.', + 'Vestibulum et erat erat.', + 'Maecenas eleifend ultricies erat eget vehicula.', + 'Donec varius lectus ut metus finibus pellentesque.', + 'Aliquam nec orci scelerisque, elementum odio non, aliquet ante.', + 'Nulla eget nisi ac magna aliquet efficitur vitae sed felis.', + 'Suspendisse purus erat, blandit eget leo quis, iaculis vestibulum sapien.', + 'Vivamus rutrum, leo ac suscipit tincidunt, ipsum sem volutpat purus, quis sodales augue lacus id mi.', + 'Aenean interdum ac turpis eu viverra.', + 'Suspendisse rhoncus rutrum augue.', + 'Ut dolor lectus, rutrum et metus et, volutpat sagittis urna.', + 'Donec blandit tortor sed pellentesque maximus.', + 'Phasellus molestie congue erat, ut euismod leo pulvinar nec.', + 'Nulla elementum vestibulum libero vehicula aliquet.', + 'Sed venenatis enim eu nisi laoreet, sit amet sagittis magna gravida.', + 'Suspendisse semper molestie ligula sit amet lobortis.', + 'Nulla urna eros, condimentum a odio id, aliquet scelerisque justo.', + 'Suspendisse sit amet orci ante.', + 'Sed congue sem sapien, ac ornare nibh porta efficitur.', + 'Nullam suscipit, lectus ac gravida ultrices, lectus neque viverra sem, sit amet eleifend purus felis vulputate odio.', + 'In velit lacus, facilisis quis nunc vitae, imperdiet bibendum mauris.', + 'Duis iaculis sodales turpis, vestibulum rutrum eros efficitur ac.', + 'Aenean interdum congue libero vel suscipit.', + 'Quisque pharetra semper lorem ac posuere.', + 'Mauris viverra neque pellentesque, semper augue id, placerat arcu.', + 'Mauris sit amet bibendum nisi, a laoreet ipsum.', + 'Proin tristique auctor massa convallis imperdiet.', + 'Curabitur congue sed neque vel imperdiet.', + 'Quisque egestas metus at diam feugiat, vestibulum ornare nulla venenatis.', + 'Donec non hendrerit urna.', + 'Curabitur id justo ex.', + 'Sed consectetur urna a purus egestas, a fringilla leo scelerisque.', + 'Morbi interdum massa sed ligula dapibus semper.', + 'Nam sit amet condimentum erat.', + 'Nam vel magna porta, ultrices nisl eu, lacinia lorem.', + 'Pellentesque accumsan, felis sit amet elementum tincidunt, risus arcu bibendum eros, vitae commodo justo orci vitae ex.', + 'Vestibulum eu fermentum lacus.', + 'Nulla quis pulvinar metus.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Curabitur malesuada non erat vitae dapibus.', + 'Donec sit amet facilisis ante, vitae tristique risus.', + 'Vestibulum maximus vehicula purus sed tincidunt.', + 'Fusce facilisis odio et fermentum dapibus.', + 'In hac habitasse platea dictumst.', + 'Etiam et viverra felis, in vulputate enim.', + 'Donec vel pulvinar elit.', + 'Mauris quis velit suscipit, accumsan libero eget, consectetur sapien.', + 'Maecenas vel placerat justo, sit amet eleifend sem.', + 'Pellentesque cursus felis enim, vitae convallis lectus finibus et.', + 'Aliquam eu dolor eros.', + 'Cras dictum, est quis porttitor semper, turpis lacus maximus eros, at luctus diam orci et elit.', + 'Nulla id augue tincidunt, sollicitudin mi vel, pellentesque mi.', + 'Vestibulum ultricies turpis a congue rutrum.', + 'Praesent sed dictum nunc.', + 'Donec finibus commodo ligula non tincidunt.', + 'Aliquam eget tellus velit.', + 'Proin tempor elit at nulla commodo molestie.', + 'Morbi ultricies sit amet tortor eu porttitor.', + 'Duis congue elit ac porttitor lobortis.', + 'Sed fringilla mi pretium lacinia finibus.', + 'Maecenas faucibus metus sed ipsum tristique, sed vulputate odio bibendum.', + 'Nulla facilisi.', + 'Nulla non dapibus nibh, id ultricies augue.', + 'Vestibulum vitae lorem neque.', + 'Maecenas non augue nibh.', + 'Suspendisse laoreet dapibus auctor.', + 'In sit amet lorem eget purus ultrices tincidunt ut at neque.', + 'Fusce congue, nunc sit amet lobortis pellentesque, sapien ex rutrum elit, vel gravida nulla velit sed dui.', + 'Cras nec hendrerit sapien, eu euismod elit.', + 'Maecenas lobortis egestas interdum.', + 'Nunc sagittis bibendum erat sit amet varius.', + 'Mauris varius nunc at odio facilisis facilisis.', + 'Sed maximus sit amet urna vitae aliquam.', + 'Donec vel ipsum sed sapien aliquet pharetra id vitae leo.', + 'Sed vitae diam elit.', + 'Nam tempor, risus nec gravida mollis, velit neque efficitur leo, sit amet porta purus magna euismod ipsum.', + 'Suspendisse potenti.', + 'Donec interdum vulputate lorem, vitae pellentesque sem mollis at.', + 'Vivamus vitae faucibus libero.', + 'Etiam laoreet semper accumsan.', + 'Morbi imperdiet, ex ut fringilla fermentum, sapien ipsum efficitur magna, a ultrices purus massa at nibh.', + 'Sed a dolor euismod, facilisis ex eget, efficitur est.', + 'Phasellus eleifend, felis quis convallis semper, dui magna accumsan leo, a mattis magna urna in ligula.', + 'Donec porta sollicitudin vestibulum.', + 'Nunc et nisl in ligula iaculis rutrum id consequat neque.', + 'Nunc sed purus quis felis aliquet accumsan.', + 'Aliquam congue placerat condimentum.', + 'Proin ultrices condimentum facilisis.', + 'Aenean in faucibus odio.', + 'Pellentesque enim ex, mattis non risus ut, euismod imperdiet lorem.', + 'Integer quis magna non risus luctus posuere.', + 'Vestibulum pellentesque suscipit arcu, id dignissim leo rhoncus nec.', + 'Praesent vitae sodales quam.', + 'Morbi viverra nibh quam, quis dapibus nibh consequat sed.', + 'Morbi sed risus sollicitudin, tincidunt augue vel, posuere orci.', + 'Nunc nisi nisi, varius ac commodo ac, placerat hendrerit nisi.', + 'Donec sapien magna, elementum eu mi vitae, laoreet euismod turpis.', + 'Cras eget pretium eros.', + 'Sed tincidunt ante id tortor porta, ac pellentesque erat suscipit.', + 'Fusce consequat nisi dolor, eget tincidunt tellus imperdiet at.', + 'Nullam scelerisque commodo eleifend.', + 'Mauris et nisl bibendum, varius sem at, sollicitudin libero.', + 'Quisque purus felis, tristique id ligula in, ullamcorper pellentesque felis.', + 'Phasellus et tortor ut sem rhoncus suscipit ac eget elit.', + 'Donec rhoncus ex finibus neque volutpat, ut placerat metus gravida.', + 'Suspendisse at sem id diam efficitur dapibus.', + 'Aliquam erat volutpat.', + 'Nunc ac nibh eget augue sodales ornare.', + 'Integer ultricies neque at felis aliquam, vel interdum felis mollis.', + 'Nulla iaculis libero velit, a consequat eros hendrerit venenatis.', + 'Etiam aliquet eros magna, ut ultricies metus feugiat vitae.', + 'Maecenas est orci, accumsan eu eleifend vitae, sollicitudin vitae metus.', + 'Sed aliquet, tellus sed euismod sodales, lectus leo imperdiet dui, eu luctus mauris turpis id turpis.', + 'Sed eget accumsan felis, viverra euismod nulla.', + 'Nullam convallis odio consectetur nisl tempus, sed dictum urna tempor.', + 'Proin scelerisque elit tortor, a ultricies odio ullamcorper vel.', + 'Etiam ultrices congue neque ac sollicitudin.', + 'Ut placerat consectetur sapien ut rhoncus.', + 'Ut aliquam quam nec ornare fermentum.', + 'Vivamus aliquet facilisis magna.', + 'Vestibulum dictum sed leo non cursus.', + 'Morbi egestas et augue fringilla bibendum.', + 'Etiam vel maximus tellus.', + 'Praesent et turpis justo.', + 'Morbi a hendrerit diam, cursus posuere lorem.', + 'In sed sem id eros dignissim tincidunt.', + 'Nullam porta varius risus at ullamcorper.', + 'Nam varius sodales dolor, dapibus rutrum ligula vulputate at.', + 'Nam ultricies sed ante eget convallis.', + 'Duis ultrices est ac orci auctor, et malesuada neque sodales.', + 'Aliquam venenatis sodales aliquam.', + 'Phasellus ut lectus id sapien dictum luctus a vitae nibh.', + 'Sed euismod varius malesuada.', + 'Ut faucibus ultricies posuere.', + 'Nunc vitae diam in mi pellentesque vehicula eu elementum lectus.', + 'Vivamus gravida felis eget ipsum consectetur tincidunt.', + 'Nullam nunc eros, blandit ut finibus sit amet, porta nec lectus.', + 'Vestibulum non orci neque.', + 'Praesent velit massa, pulvinar quis mauris sit amet, consequat tincidunt mauris.', + 'Quisque id cursus magna.', + 'Donec eros ante, placerat at efficitur in, placerat id turpis.', + 'Morbi non dui tortor.', + 'Quisque at turpis sodales, pharetra justo ut, accumsan est.', + 'Sed molestie dolor mi, ac feugiat elit blandit et.', + 'Nullam libero ex, rutrum ac ultrices vitae, tincidunt ut velit.', + 'Proin pharetra placerat eros, eget mattis risus semper at.', + 'In feugiat congue risus.', + 'Curabitur non odio ligula.', + 'Nulla sit amet ligula facilisis, venenatis ante eget, porttitor libero.', + 'In eu sodales sem.', + 'In iaculis ex eget nisi euismod, eget porta libero condimentum.', + 'Vivamus tristique faucibus nunc.', + 'Nam sit amet cursus erat.', + 'Suspendisse ligula velit, molestie ac nisl quis, cursus sodales nunc.', + 'Nunc vel semper odio, at scelerisque felis.', + 'Fusce egestas purus id enim accumsan ultrices.', + 'Curabitur porttitor justo urna, nec ultricies magna varius non.', + 'Nullam euismod, nunc varius efficitur viverra, sem justo scelerisque elit, a pretium ante sem id mi.', + 'Sed sagittis faucibus urna, eu sollicitudin magna.', + 'Nam pretium velit quis lectus viverra sodales.', + 'Cras lectus mi, accumsan non vulputate et, hendrerit ac libero.', + 'Integer nec faucibus risus.', + 'Vestibulum a finibus nulla.', + 'Quisque consequat nisi varius, laoreet justo et, elementum dui.', + 'Praesent cursus quam nec vestibulum porta.', + 'Nunc fermentum semper molestie.', + 'Cras fermentum, sem et lobortis iaculis, magna erat bibendum sapien, in sollicitudin erat metus in lectus.', + 'Nullam ligula est, tincidunt vitae consectetur vel, rutrum at erat.', + 'Etiam in rhoncus nisl, ut tempor ex.', + 'Phasellus mollis tempus urna, vel hendrerit felis aliquam sit amet.', + 'Aliquam eget mi tellus.', + 'Maecenas consectetur enim diam, a fringilla nunc suscipit egestas.', + 'Phasellus ac efficitur dolor.', + 'Nullam efficitur metus a risus sodales, quis vestibulum urna lacinia.', + 'Nam eu risus vulputate, commodo purus quis, ullamcorper nunc.', + 'Maecenas in urna tortor.', + 'Duis a purus volutpat ligula tristique suscipit.', + 'Sed id libero accumsan, finibus ipsum et, sagittis justo.', + 'Suspendisse malesuada lectus in ligula interdum condimentum.', + 'Fusce viverra ipsum lacus, et condimentum nisi tincidunt vitae.', + 'Ut pulvinar sodales nisl non dictum.', + 'Proin et efficitur tortor.', + 'Cras viverra lacinia dolor, a condimentum mauris rhoncus eu.', + 'Quisque non nunc lobortis, iaculis neque et, venenatis eros.', + 'Etiam posuere, risus quis feugiat gravida, velit nisi ornare enim, vitae dictum leo massa id orci.', + 'Sed sit amet ligula nisi.', + 'Cras et velit eget urna pulvinar dignissim.', + 'Phasellus feugiat enim eu dolor molestie, vitae molestie dui consectetur.', + 'Morbi scelerisque sapien et diam tincidunt volutpat.', + 'Praesent viverra lobortis tristique.', + 'Vestibulum placerat rutrum congue.', + 'Sed vel leo eu odio feugiat bibendum.', + 'Mauris lobortis ante tortor, ac mattis nunc consequat sit amet.', + 'Aenean sollicitudin faucibus purus, ut facilisis neque convallis quis.', + 'Aenean sit amet risus in libero eleifend pellentesque nec non lacus.', + 'Maecenas iaculis at ligula eget rutrum.', + 'Aliquam vitae tristique justo.', + 'Aliquam enim nibh, porta accumsan tortor at, condimentum feugiat tellus.', + 'Morbi dignissim egestas maximus.', + 'Sed dui risus, vulputate ac accumsan vel, rhoncus vitae nunc.', + 'Phasellus elementum ac enim a tincidunt.', + 'Curabitur vulputate enim ut leo suscipit rhoncus.', + 'Ut vitae dapibus dui.', + 'Proin sed nulla purus.', + 'Etiam a eros elementum, fringilla orci nec, cursus magna.', + 'Curabitur egestas ultricies risus, vitae ultrices dolor.', + 'Donec et tempus leo.', + 'Phasellus justo tellus, lacinia ut lorem sed, pretium hendrerit dolor.', + 'Mauris in mattis libero, sed pulvinar lorem.', + 'Cras quis auctor velit.', + 'Vestibulum vitae hendrerit tortor.', + 'Cras dictum ligula eget arcu malesuada suscipit ac sed arcu.', + 'Suspendisse vel enim sit amet metus eleifend venenatis.', + 'Quisque eget purus in lorem vulputate congue.', + 'Curabitur non enim vulputate, accumsan purus nec, suscipit lacus.', + 'Donec eros est, pretium blandit semper eu, dignissim vitae leo.', + 'Maecenas molestie erat ac magna finibus, quis sollicitudin dui euismod.', + 'Curabitur rutrum dolor ut nibh suscipit luctus.', + 'Fusce venenatis orci nulla, eget semper libero dictum sed.', + 'Sed id justo id est eleifend tristique.', + 'Phasellus eleifend eget lectus vitae luctus.', + 'Fusce vitae dolor id dui aliquam gravida ac id ex.', + 'Maecenas elementum, mi sed suscipit malesuada, magna ex laoreet lorem, lacinia pellentesque erat nisl quis augue.', + 'Ut egestas tincidunt tincidunt.', + 'Nullam consectetur magna id dictum varius.', + 'Pellentesque mattis, velit ac volutpat euismod, ipsum magna volutpat tellus, ac pharetra dolor erat vel felis.', + 'Nunc pretium, tortor blandit gravida pretium, neque nulla vehicula diam, eget aliquet turpis eros eu orci.', + 'Integer non arcu eget odio eleifend tempor quis eget elit.', + 'Ut molestie nulla ornare, congue nulla vel, eleifend tellus.', + 'Pellentesque ultrices diam ut risus convallis viverra.', + 'Integer ex erat, molestie in rhoncus ornare, rhoncus id ipsum.', + 'Fusce non nulla id augue molestie malesuada.', + 'Proin in ornare ligula.', + 'Fusce sit amet augue eget orci imperdiet consequat.', + 'Maecenas sodales est dui, vel feugiat orci aliquam a.', + 'Aenean pulvinar quam in nunc fringilla, et convallis turpis congue.', + 'Proin ex erat, vehicula tristique mi vehicula, finibus congue ex.', + 'Nunc ornare fermentum convallis.', + 'Quisque scelerisque orci non dignissim sodales.', + 'Donec eget facilisis enim.', + 'Maecenas at libero at urna vestibulum mattis.', + 'Curabitur fringilla ex purus, quis egestas tortor lacinia nec.', + 'Sed vel est consequat, sagittis lacus at, ullamcorper augue.', + 'Sed eget dui ac nisi hendrerit auctor.', + 'Nulla consectetur placerat magna, at mattis felis rutrum in.', + 'Nullam vitae risus viverra, faucibus lacus a, eleifend eros.', + 'Nullam tempus sit amet eros vitae semper.', + 'Nullam vestibulum sem sed purus congue, hendrerit porttitor leo maximus.', + 'Praesent fringilla aliquet efficitur.', + 'Aliquam quis metus at ante posuere gravida.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Aliquam sapien dui, mollis sed hendrerit id, fermentum sed tortor.', + 'Ut eget velit a urna interdum volutpat.', + 'Maecenas rhoncus dui vitae tempus rhoncus.', + 'Phasellus eu molestie sem.', + 'Mauris quis aliquam lectus, nec vehicula dui.', + 'Aenean eget imperdiet odio.', + 'Vestibulum non ullamcorper lacus.', + 'Etiam eu augue eget massa tempus rutrum eu sit amet leo.', + 'Vestibulum nec nulla quis tellus lacinia scelerisque quis vitae felis.', + 'Donec convallis, elit sit amet viverra fermentum, libero eros auctor elit, a tincidunt erat eros vitae ligula.', + 'Cras ornare placerat ultrices.', + 'Mauris blandit, nunc eu viverra interdum, est odio bibendum urna, eget mattis purus nisl sollicitudin mauris.', + 'Cras ornare velit ac facilisis rhoncus.', + 'Donec lacus lectus, consectetur in fringilla ac, aliquet et nisl.', + 'Morbi sit amet nulla vitae arcu porttitor elementum ac vitae nulla.', + 'Duis sed tristique velit, non rutrum tellus.', + 'Cras et imperdiet nisl.', + 'Fusce id ipsum a dui volutpat volutpat.', + 'Nam eget augue et lectus placerat vehicula.', + 'In egestas condimentum mi, id efficitur nunc mattis sit amet.', + 'Nunc pulvinar tortor nec dolor vehicula, at porta elit porttitor.', + 'Praesent ac auctor erat.', + 'Donec eu faucibus eros, eu varius tortor.', + 'Sed eget sapien at est lacinia molestie eu in ligula.', + 'Duis mollis vehicula cursus.', + 'Duis finibus auctor pellentesque.', + 'Nullam sed urna diam.', + 'Nulla quis ipsum lacinia, placerat nisl et, dignissim est.', + 'Vivamus hendrerit, urna vel pulvinar maximus, elit turpis placerat dolor, quis sodales erat turpis sed lorem.', + 'Nulla dapibus porta odio, at porta ligula convallis a.', + 'Morbi rhoncus tempor libero, lobortis facilisis ligula convallis at.', + 'Etiam dapibus lacinia massa a finibus.', + 'Nam eget convallis mi.', + 'Integer posuere consectetur nisl eu ullamcorper.', + 'Cras et lorem sit amet dui venenatis pellentesque non laoreet quam.', + 'Sed eget fermentum diam, eget suscipit nulla.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Aliquam luctus eros quis metus faucibus luctus.', + 'Suspendisse rutrum libero magna, eu porttitor purus pretium vel.', + 'Curabitur ultricies pellentesque dui sit amet volutpat.', + 'Fusce tincidunt vulputate elit et efficitur.', + 'Nunc tincidunt malesuada dignissim.', + 'Nullam ornare venenatis purus semper porta.', + 'Nullam nisl massa, porttitor non gravida id, bibendum at dui.', + 'Curabitur rhoncus at massa ac ultricies.', + 'Phasellus aliquet ex in quam placerat feugiat.', + 'Nullam placerat in quam vitae venenatis.', + 'Vivamus quis mi accumsan, egestas nunc ac, laoreet arcu.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Sed faucibus imperdiet tortor vitae dapibus.', + 'Morbi neque sapien, aliquam eget leo in, maximus feugiat eros.', + 'In interdum ipsum quis dictum posuere.', + 'Vestibulum pellentesque ullamcorper rutrum.', + 'Vivamus sed lacus imperdiet, vehicula augue id, aliquet magna.', + 'Donec mollis auctor consectetur.', + 'Proin ultrices orci tellus, in volutpat leo pellentesque id.', + 'Donec sapien mauris, sagittis iaculis iaculis non, iaculis at nunc.', + 'In dapibus leo ac elit gravida, in ornare tortor mattis.', + 'Nam ac auctor arcu, id semper ex.', + 'Sed vitae mauris sagittis, vestibulum sapien sed, consectetur tortor.', + 'Sed dapibus metus vitae condimentum sagittis.', + 'Integer purus leo, pretium id vulputate sit amet, tempus at quam.', + 'Donec egestas laoreet efficitur.', + 'Phasellus et ante vehicula, consectetur lacus ut, vehicula nunc.', + 'Vestibulum ultricies, ligula et consequat fermentum, nisi mauris imperdiet turpis, tincidunt mollis felis tellus sed quam.', + 'Praesent id arcu dui.', + 'Suspendisse suscipit, velit vel tempus ultricies, turpis magna facilisis lectus, et varius enim sem vel enim.', + 'Vivamus id elit turpis.', + 'Duis porta, nibh sit amet pharetra dapibus, massa neque elementum turpis, et porta ante ex at libero.', + 'In tempus, sem a pulvinar viverra, turpis nulla malesuada metus, vitae posuere augue odio at nunc.', + 'Donec lectus sem, cursus ut vestibulum vitae, facilisis ac mi.', + 'Maecenas bibendum nisl eu libero hendrerit, vel mollis lorem tristique.', + 'Nulla cursus cursus mauris.', + 'Vestibulum laoreet augue ac nunc pulvinar, vestibulum ullamcorper purus volutpat.', + 'Vivamus iaculis euismod accumsan.', + 'Vestibulum eu dui feugiat, consectetur libero id, consectetur arcu.', + 'Nam lobortis ut turpis ac convallis.', + 'Duis dapibus turpis nec aliquet porta.', + 'Suspendisse id gravida nunc.', + 'Nullam tristique risus et magna dictum bibendum.', + 'Morbi semper tellus id arcu dictum, vitae accumsan purus sollicitudin.', + 'Nunc id laoreet diam.', + 'Praesent congue, elit ac molestie pharetra, nulla orci viverra turpis, quis tristique dolor sem quis magna.', + 'Donec eu ligula mauris.', + 'Etiam nec pretium arcu, et vehicula leo.', + 'Pellentesque non libero eu justo aliquet dictum.', + 'Mauris vel aliquet nulla.', + 'Aliquam vitae pharetra purus.', + 'Morbi aliquam aliquet malesuada.', + 'Duis id luctus arcu.', + 'In rutrum mattis leo.', + 'Sed mattis augue sed nulla porta, sit amet efficitur libero aliquet.', + 'Vivamus quis dignissim nibh.', + 'Donec accumsan vitae nisl ac placerat.', + 'Maecenas in neque nunc.', + 'Donec placerat quis ex id egestas.', + 'Quisque aliquam ex vel convallis eleifend.', + 'Mauris sodales elementum risus, quis fermentum augue vulputate a.', + 'Suspendisse sollicitudin finibus tellus, vitae sollicitudin eros tincidunt et.', + 'Nulla ut ex in eros consectetur aliquam.', + 'Ut maximus nulla tellus, eget tincidunt nulla auctor a.', + 'Vivamus accumsan dictum felis, sit amet tempor sapien pulvinar at.', + 'Morbi interdum, justo in scelerisque varius, purus enim vulputate nisi, consectetur interdum odio lorem vel justo.', + 'Aenean vitae hendrerit tortor.', + 'Suspendisse maximus imperdiet mi eu pellentesque.', + 'Quisque ultrices ultrices tortor, eget tristique odio pretium nec.', + 'Fusce metus dui, ultrices vel bibendum non, elementum sit amet magna.', + 'Nullam euismod ligula non ligula pulvinar, eu elementum velit cursus.', + 'Donec neque quam, feugiat nec vehicula non, ultricies non ex.', + 'Vivamus felis dui, vulputate in sollicitudin id, blandit nec odio.', + 'Pellentesque risus elit, mattis a purus vitae, varius auctor eros.', + 'Donec non rhoncus magna.', + 'Vestibulum volutpat orci enim, sed cursus massa vehicula ut.', + 'Vestibulum in rhoncus mi.', + 'Fusce vitae pulvinar nunc.', + 'Nam sit amet urna et lacus auctor accumsan et malesuada mauris.', + 'Curabitur ac eleifend urna.', + 'Maecenas a justo sed augue consequat blandit nec sit amet lacus.', + 'Phasellus vehicula est diam, in pharetra turpis porta ut.', + 'Nunc arcu lorem, pretium vitae feugiat in, elementum ac purus.', + 'Phasellus eget mollis diam, eu lacinia mi.', + 'Aenean eget lectus nulla.', + 'Integer sapien nibh, blandit quis libero mattis, ultricies consequat nisl.', + 'Nunc ac sagittis ligula, vel varius ante.', + 'Proin ut turpis a erat viverra lobortis eu quis quam.', + 'Mauris eu augue vel nisl interdum accumsan.', + 'Ut ut euismod leo.', + 'Aliquam urna turpis, blandit nec suscipit non, convallis at ante.', + 'Nulla quis molestie erat, ut venenatis nunc.', + 'Fusce pellentesque sit amet felis eu mattis.', + 'Mauris felis elit, gravida at dapibus ut, cursus at ante.', + 'Praesent in lacus euismod, porta ipsum id, feugiat mauris.', + 'Maecenas in eros nec arcu aliquet hendrerit.', + 'Duis bibendum rutrum mi.', + 'Donec elementum, felis eu fringilla placerat, mi lacus molestie tortor, et varius libero justo in tortor.', + 'Integer rutrum at neque et luctus.', + 'Nullam faucibus tempus metus, vitae dignissim leo viverra a.', + 'Integer augue erat, aliquet id tortor a, convallis dignissim tellus.', + 'Morbi elementum mollis tellus, id interdum arcu sodales sit amet.', + 'Suspendisse a sapien quis nibh convallis laoreet eu eget sem.', + 'Aliquam blandit odio vel nulla rhoncus dapibus.', + 'Nullam mollis tristique ligula, in tristique mauris eleifend id.', + 'Pellentesque eget consequat nunc.', + 'Donec et orci hendrerit, lacinia nisl in, pretium ex.', + 'Quisque sit amet eleifend tortor.', + 'Proin viverra dui eget tortor faucibus hendrerit.', + 'Etiam pretium fringilla justo, quis ornare risus posuere quis.', + 'Sed commodo maximus mauris, eu vulputate metus consectetur eget.', + 'Maecenas in arcu porttitor, condimentum arcu at, pretium ante.', + 'Ut vel urna viverra diam gravida condimentum non at enim.', + 'In ligula orci, malesuada convallis est a, egestas auctor elit.', + 'Sed blandit sagittis ipsum, id tempus diam ornare at.', + 'Mauris volutpat faucibus magna ac sodales.', + 'Fusce eget arcu et nunc rhoncus egestas et vel metus.', + 'Vestibulum egestas euismod bibendum.', + 'Ut id ex cursus, congue nulla ac, finibus mi.', + 'Suspendisse vitae tempor arcu.', + 'Integer ultricies orci purus, non finibus nisi laoreet in.', + 'Vestibulum metus purus, sodales rutrum tincidunt pharetra, eleifend vel dui.', + 'Pellentesque convallis dolor sed consequat pretium.', + 'Fusce suscipit ex ante, ac accumsan quam eleifend non.', + 'Donec porta, neque eu cursus cursus, enim arcu consequat neque, cursus laoreet dolor nunc at sem.', + 'Praesent sit amet arcu eros.', + 'Donec congue tellus nec mi ullamcorper pretium.', + 'Duis aliquet, orci eu facilisis dapibus, mauris erat congue neque, in commodo diam libero maximus urna.', + 'Curabitur interdum et metus at ullamcorper.', + 'Nulla a dui purus.', + 'Proin sed dapibus risus.', + 'Nunc consectetur posuere maximus.', + 'In sodales sem nisl, ut varius est venenatis at.', + 'Vestibulum non consectetur lorem.', + 'Nunc id risus sapien.', + 'Sed tristique condimentum tortor, tincidunt vulputate turpis.', + 'Ut neque purus, molestie eu varius vitae, venenatis sit amet nulla.', + 'Quisque dapibus libero libero, sed blandit lectus blandit sed.', + 'Nulla congue urna quis metus molestie vehicula.', + 'Vivamus sed aliquet felis, volutpat dignissim metus.', + 'Duis id augue neque.', + 'Nullam placerat mollis malesuada.', + 'Aenean malesuada elit ac ante imperdiet posuere sed et nibh.', + 'Vivamus id interdum ligula.', + 'Nunc nisl tellus, aliquam nec tristique et, elementum non est.', + 'Praesent fermentum gravida dolor, eu viverra justo posuere id.', + 'Ut nec iaculis velit, quis pretium mi.', + 'Vivamus scelerisque dolor sit amet erat dapibus consectetur.', + 'Pellentesque dolor risus, maximus quis gravida non, viverra sit amet dui.', + 'Phasellus placerat lectus velit, id ultrices augue posuere id.', + 'In consequat aliquet justo, in ornare turpis tempus sed.', + 'Fusce condimentum rhoncus condimentum.', + 'Phasellus convallis, sem molestie scelerisque congue, est justo lobortis diam, id commodo ligula ipsum eu nibh.', + 'Etiam id dolor vehicula, vehicula orci vitae, elementum dolor.', + 'Proin sit amet massa et dui varius auctor at nec ex.', + 'Donec ultrices sem vel nisi fermentum vulputate.', + 'In viverra quam ante, sit amet efficitur est varius sed.', + 'Sed vestibulum, tortor sed tincidunt congue, eros turpis mollis ipsum, id dictum nibh ipsum et metus.', + 'Proin nec sem eros.', + 'Donec vulputate lacus nisl, nec consectetur nulla blandit ac.', + 'Nulla sapien ipsum, tristique a mi sed, iaculis accumsan sapien.', + 'Etiam vitae est quis purus rhoncus blandit.', + 'Proin suscipit nec tortor sit amet malesuada.', + 'Aenean felis odio, facilisis sit amet enim in, condimentum sollicitudin ante.', + 'Nullam porttitor vel nulla sit amet feugiat.', + 'Phasellus mi libero, vulputate eu magna at, molestie aliquet erat.', + 'Mauris eros lorem, malesuada nec ligula vitae, pellentesque consequat est.', + 'Donec sodales pellentesque mi vitae pulvinar.', + 'Morbi sapien nisi, commodo nec ultricies et, iaculis nec nisl.', + 'Vestibulum maximus luctus elit malesuada tincidunt.', + 'Duis eget varius orci, eget sagittis eros.', + 'Quisque eu eros nisl.', + 'Pellentesque eleifend aliquam metus, a finibus neque sodales eu.', + 'Sed tempus ligula sapien, eu scelerisque nisl porttitor gravida.', + 'Sed vitae lectus sit amet lectus ornare interdum.', + 'Aenean arcu diam, porta sit amet lorem eget, sagittis iaculis erat.', + 'Nulla pharetra, sem non auctor ultrices, ex metus dictum magna, at sollicitudin ex justo ut turpis.', + 'Sed aliquam luctus semper.', + 'Nullam vitae malesuada sapien, tempor scelerisque lorem.', + 'Integer congue lorem ligula, ac volutpat lorem sagittis id.', + 'Nam nec pretium elit.', + 'Quisque volutpat ex dui, a sagittis augue consequat tincidunt.', + 'Cras tristique felis arcu, at vestibulum enim scelerisque sollicitudin.', + 'Nunc est metus, semper vel magna et, tincidunt scelerisque felis.', + 'Morbi lacus nisl, porttitor ac justo non, ultricies fringilla tellus.', + 'Ut eu metus metus.', + 'Proin vehicula vestibulum sollicitudin.', + 'Sed iaculis sem non ante ultricies, at semper libero porttitor.', + 'Ut dapibus laoreet sem ac consectetur.', + 'Etiam hendrerit, odio sit amet iaculis semper, ligula sapien rhoncus lorem, sit amet cursus eros ante sed nunc.', + 'Etiam interdum pellentesque enim id dapibus.', + 'Fusce luctus orci tortor.', + 'Cras id bibendum risus.', + 'Nam pretium felis nec ante tincidunt interdum.', + 'Nam cursus nibh non justo pharetra tristique.', + 'Nam facilisis dapibus lacus sit amet volutpat.', + 'Morbi felis ex, semper sed tortor eu, finibus aliquet lacus.', + 'Integer a orci augue.', + 'Vivamus lobortis tellus sed est fringilla ornare.', + 'Mauris tempus ante tortor, ac feugiat dui viverra et.', + 'Vivamus risus leo, ultrices at eleifend vel, luctus non arcu.', + 'Nullam dictum purus commodo turpis maximus, a mollis nibh efficitur.', + 'Nullam elementum dapibus suscipit.', + 'Nullam blandit sem lacus, vel blandit eros fermentum et.', + 'Sed cursus fermentum augue sit amet rutrum.', + 'Maecenas posuere, ante sed tristique ultrices, nisl orci molestie metus, sed vehicula mauris odio quis neque.', + 'Aliquam quis elit enim.', + 'Aenean cursus, turpis vel rhoncus imperdiet, dolor est consectetur metus, nec egestas elit orci ac ex.', + 'Fusce convallis justo eget dui ultrices, nec venenatis felis venenatis.', + 'Praesent eleifend, arcu eget auctor venenatis, nibh mi aliquet ligula, ac sagittis risus mi sed est.', + 'Phasellus pharetra, leo sed elementum aliquam, nisl justo lacinia ante, eu vehicula justo diam a sem.', + 'Praesent ac convallis neque, a dictum ipsum.', + 'Quisque venenatis nulla porta nunc semper sollicitudin.', + 'Duis a lectus velit.', + 'Phasellus lobortis, arcu et feugiat imperdiet, magna ipsum vestibulum massa, eget ullamcorper libero eros sed justo.', + 'Vivamus eget augue a ligula ultrices condimentum.', + 'Maecenas at eros a eros dictum mollis.', + 'Sed pellentesque tempor purus rhoncus pulvinar.', + 'Vestibulum faucibus urna quis convallis rutrum.', + 'Donec ultricies tempor nunc, a facilisis velit elementum non.', + 'Sed in risus in ante eleifend congue sed non nisl.', + 'Vestibulum in ante quis libero rhoncus sollicitudin id in quam.', + 'Sed imperdiet dapibus purus.', + 'Sed blandit, enim a cursus scelerisque, ante purus ornare massa, in dictum lacus neque id quam.', + 'Suspendisse tincidunt consectetur eros ac imperdiet.', + 'Sed ac justo feugiat, convallis ligula eget, interdum erat.', + 'Integer fermentum id arcu quis blandit.', + 'Curabitur iaculis, mauris at efficitur condimentum, justo lectus ornare quam, a euismod enim dolor gravida sem.', + 'Vivamus eu diam et nisl tincidunt pretium.', + 'Nullam sodales pulvinar urna in ultricies.', + 'Phasellus in condimentum enim.', + 'Vivamus eu mollis lacus.', + 'Etiam id ante eget dolor vehicula porta.', + 'Etiam purus urna, bibendum sollicitudin viverra quis, tristique id felis.', + 'Morbi porttitor tortor eget lorem commodo, nec pharetra urna vestibulum.', + 'Integer id faucibus massa.', + 'Duis interdum, quam quis ornare vulputate, eros est sodales ligula, a tincidunt mauris turpis ac diam.', + 'Mauris dictum nisl a vulputate cursus.', + 'Nulla cursus accumsan nisi, sit amet vulputate sapien semper ac.', + 'Vestibulum malesuada sodales condimentum.', + 'Sed tincidunt iaculis interdum.', + 'Maecenas quis nulla arcu.', + 'Fusce lacus urna, vulputate eu fringilla ut, vulputate quis magna.', + 'Vivamus a commodo neque.', + 'Donec maximus erat libero, eget sagittis magna tincidunt ac.', + 'Proin at dui id orci ornare vestibulum.', + 'Ut porttitor eget urna non efficitur.', + 'Nullam ut ligula est.', + 'Vestibulum vulputate, nulla sit amet laoreet egestas, ex mauris mattis metus, ut bibendum elit diam nec felis.', + 'Duis tempus finibus lorem, sit amet consequat dolor porta eu.', + 'Phasellus vel fringilla orci.', + 'Curabitur nec elit pulvinar mi vestibulum accumsan id quis augue.', + 'Ut ante neque, malesuada sed lacinia id, faucibus eget dui.', + 'In dui nibh, dignissim sed nisi at, feugiat vestibulum odio.', + 'Nunc ac lacus eleifend, laoreet tellus sit amet, condimentum nulla.', + 'Sed ac elit a lacus fermentum auctor in ac mi.', + 'Donec a justo in tellus laoreet facilisis.', + 'Pellentesque a enim dui.', + 'Vivamus sit amet rhoncus neque.', + 'Vivamus risus leo, aliquet ut sollicitudin vel, blandit in risus.', + 'Pellentesque eget tincidunt urna.', + 'Duis iaculis suscipit diam a tempus.', + 'Etiam posuere eu est vel congue.', + 'Nunc vel accumsan justo.', + 'Sed pharetra arcu vitae mauris eleifend, eu fermentum elit fermentum.', + 'In suscipit quam neque, ut dapibus urna venenatis in.', + 'Vivamus ultrices consequat risus, ac vestibulum orci porta finibus.', + 'Fusce sem orci, egestas ut feugiat sit amet, molestie quis arcu.', + 'Fusce vel ex nec justo ullamcorper viverra sit amet sed justo.', + 'Nunc sit amet leo consequat, commodo mauris quis, euismod mi.', + 'Ut finibus sapien ut dictum maximus.', + 'Suspendisse sed dui urna.', + 'Ut mattis et ex sit amet sagittis.', + 'Nulla vitae condimentum metus.', + 'Fusce sodales nulla metus, lacinia tincidunt sapien lobortis tincidunt.', + 'Vestibulum dapibus urna diam, nec ultricies neque feugiat et.', + 'Vestibulum eget quam ac lectus fermentum sagittis eu sit amet massa.', + 'Suspendisse quis diam eget felis faucibus tempus.', + 'Nullam nec consectetur urna.', + 'Aenean pharetra ullamcorper nibh, in maximus dui molestie non.', + 'Mauris laoreet, ex id volutpat bibendum, magna purus sodales lacus, eu fringilla ante ex ac metus.', + 'Suspendisse ac sapien massa.', + 'Donec pellentesque, ipsum in mollis accumsan, nisi risus sodales nisl, sed malesuada enim nibh quis mi.', + 'Duis varius viverra lacus non ultricies.', + 'Vestibulum venenatis id odio eget gravida.', + 'Suspendisse at quam et justo sollicitudin ornare eget ut felis.', + 'Etiam rhoncus ornare nisl ac tincidunt.', + 'Etiam vitae maximus tellus.', + 'In nibh leo, mattis vel tellus id, facilisis imperdiet lacus.', + 'Mauris sagittis ut erat eget porta.', + 'Nam a lectus laoreet, consequat elit ac, porta magna.', + 'Aenean commodo suscipit lorem, quis iaculis risus interdum ut.', + 'In cursus ullamcorper quam vel imperdiet.', + 'Nullam id mattis lectus.', + 'Cras sagittis massa urna, vitae mollis elit tincidunt a.', + 'Aliquam commodo urna quis nunc elementum ultricies at interdum massa.', + 'Sed pharetra urna eros, eget aliquam sem interdum id.', + 'Integer vestibulum dolor eget urna suscipit ultricies.', + 'Nam facilisis velit non mi pulvinar, eu mattis massa interdum.', + 'Sed faucibus, velit id tempor maximus, magna odio sodales ligula, vitae efficitur massa nunc non odio.', + 'Integer mattis lorem vitae turpis molestie faucibus.', + 'Praesent sagittis, quam quis placerat viverra, orci eros interdum mauris, ac iaculis erat lectus vel augue.', + 'Donec dapibus leo leo, accumsan tincidunt augue aliquet et.', + 'Ut non erat sed odio gravida blandit.', + 'Praesent placerat ante nulla, a iaculis magna lobortis in.', + 'Nulla erat nisi, pharetra at luctus vitae, cursus eget neque.', + 'Vivamus diam ante, pulvinar elementum vestibulum ut, fringilla quis lacus.', + 'Pellentesque ultrices odio placerat sollicitudin tincidunt.', + 'Nunc accumsan nisl nunc, tempor egestas odio elementum a.', + 'Vestibulum ut leo euismod, hendrerit tortor sed, eleifend purus.', + 'Aenean venenatis viverra elementum.', + 'Vivamus eu mattis quam, sit amet iaculis mi.', + 'Proin ultricies, arcu et tempus blandit, neque tortor vehicula felis, quis mattis magna metus non velit.', + 'Mauris imperdiet eu quam nec efficitur.', + 'Nam sodales sem at nulla laoreet, a luctus odio viverra.', + 'Morbi non lectus semper, interdum lectus ac, elementum purus.', + 'Vestibulum efficitur faucibus volutpat.', + 'Aliquam pellentesque, ex id laoreet gravida, sapien orci sodales dolor, vitae pretium turpis dolor a metus.', + 'Nulla metus tellus, porttitor in placerat non, laoreet eget nunc.', + 'Maecenas euismod massa et viverra consectetur.', + 'Curabitur est sapien, commodo vel urna lacinia, accumsan viverra libero.', + 'Maecenas fringilla, odio vitae congue malesuada, elit mi rhoncus erat, at hendrerit metus magna et eros.', + 'Suspendisse efficitur cursus purus quis commodo.', + 'Duis egestas sem urna.', + 'Suspendisse consectetur posuere purus id dignissim.', + 'Aenean ut congue velit.', + 'Etiam suscipit, tellus non laoreet maximus, orci dolor faucibus velit, quis vulputate leo dui in lacus.', + 'Ut iaculis metus ante, sed sollicitudin sem consequat ut.', + 'Fusce semper mattis turpis, vel elementum leo ornare eget.', + 'Donec magna nulla, vulputate quis lacinia sit amet, tempor ac mauris.', + 'Aenean interdum purus ligula, ut porttitor arcu aliquam vitae.', + 'Morbi venenatis sem in velit venenatis rutrum.', + 'Nullam porta leo convallis, molestie massa non, sagittis metus.', + 'Nunc posuere pretium augue, eu condimentum augue sollicitudin sit amet.', + 'Pellentesque elementum ipsum nec tincidunt aliquam.', + 'Pellentesque massa enim, vehicula quis euismod non, lobortis eget magna.', + 'Mauris posuere risus non velit vestibulum pretium non non ipsum.', + 'Cras vel ornare turpis, vel feugiat purus.', + 'Quisque odio eros, porttitor nec vulputate vitae, sollicitudin pretium purus.', + 'Maecenas imperdiet lacus a urna finibus fringilla sit amet et felis.', + 'Aenean quis ipsum tempus, pellentesque nunc mattis, tristique diam.', + 'Vestibulum vitae nunc hendrerit, gravida sem eu, tempus risus.', + 'Donec condimentum bibendum ipsum, a hendrerit neque posuere nec.', + 'Donec a dolor a massa maximus efficitur.', + 'Praesent velit massa, tempus ac semper quis, scelerisque vitae ante.', + 'Aliquam purus urna, hendrerit vitae sagittis at, porta vel justo.', + 'Curabitur pellentesque consectetur lobortis.', + 'Vivamus scelerisque hendrerit venenatis.', + 'Integer tincidunt ut diam sed congue.', + 'Sed ut aliquam nisi.', + 'Nullam nec eros id nunc semper luctus.', + 'Aliquam maximus eleifend dui, nec blandit massa bibendum eget.', + 'Donec interdum placerat tincidunt.', + 'Quisque non nulla sapien.', + 'Etiam tincidunt eros eget elit bibendum gravida.', + 'Quisque fringilla facilisis tortor quis ullamcorper.', + 'Integer gravida justo in iaculis posuere.', + 'Praesent sed tincidunt sapien.', + 'Sed euismod vitae ex vel scelerisque.', + 'Aenean nisi felis, ornare et feugiat eget, sodales vitae odio.', + 'Aenean libero sapien, lacinia ac sapien ac, laoreet dignissim dui.', + 'Nunc nibh massa, convallis in augue et, efficitur mattis elit.', + 'Suspendisse id nisl luctus, sollicitudin justo non, luctus arcu.', + 'Aliquam a est massa.', + 'Pellentesque dignissim mattis arcu.', + 'Aliquam efficitur ante metus, ut pellentesque felis suscipit eu.', + 'Ut facilisis vestibulum arcu elementum dignissim.', + 'Cras non sapien mauris.', + 'Maecenas interdum libero eu libero luctus, sit amet efficitur leo porttitor.', + 'Duis ut mollis ex.', + 'Quisque mi eros, suscipit vitae tempus ut, condimentum sit amet est.', + 'Ut non posuere erat.', + 'Curabitur bibendum magna turpis, non tincidunt risus dictum at.', + 'Etiam tempus magna at odio auctor, ac euismod nibh pulvinar.', + 'Morbi dapibus et sapien in elementum.', + 'Ut finibus est odio, eu convallis nunc viverra id.', + 'Quisque rhoncus mollis est sit amet semper.', + 'Ut dapibus urna sed diam ornare, eu efficitur leo feugiat.', + 'Vestibulum vel felis et erat molestie volutpat.', + 'Maecenas molestie lorem eget quam porta, a venenatis felis accumsan.', + 'In id auctor risus.', + 'Phasellus at diam sed orci porttitor tempus.', + 'Nunc dapibus, massa id ornare condimentum, mi sem ullamcorper nunc, et auctor felis felis id sem.', + 'Suspendisse nec vehicula augue.', + 'Aliquam imperdiet sagittis justo at iaculis.', + 'Praesent vulputate tellus ornare malesuada faucibus.', + 'Sed sed tristique ante.', + 'Curabitur ac augue et leo fermentum commodo eu in nulla.', + 'Aliquam pellentesque risus velit, a consequat dolor vestibulum ac.', + 'Fusce in dolor porttitor arcu viverra gravida.', + 'Maecenas ex orci, pretium vitae dui eget, scelerisque dapibus arcu.', + 'Praesent efficitur efficitur imperdiet.', + 'Curabitur eget tortor finibus, elementum orci quis, viverra arcu.', + 'Aenean ac tincidunt lacus.', + 'Donec vel ultricies est.', + 'Mauris mollis nisi a efficitur scelerisque.', + 'Nam dictum lacinia odio at pharetra.', + 'Quisque ultricies arcu in venenatis rutrum.', + 'In odio ipsum, euismod in posuere eget, placerat et felis.', + 'Curabitur mi est, placerat quis egestas non, mollis sed urna.', + 'Praesent malesuada, dolor in fermentum faucibus, tellus velit accumsan ipsum, tincidunt luctus turpis nulla sed enim.', + 'Integer rhoncus, turpis id tincidunt pulvinar, metus orci cursus mi, nec feugiat lorem elit ut enim.', + 'Aliquam et felis vel elit porta cursus in sit amet diam.', + 'In a vehicula eros, eu ullamcorper turpis.', + 'Vivamus eleifend libero non nulla accumsan porttitor.', + 'Suspendisse vel neque ultrices, scelerisque lacus in, ornare massa.', + 'Duis dolor leo, ullamcorper vel lacinia eget, aliquam rhoncus risus.', + 'Vivamus dapibus ac elit sed imperdiet.', + 'Vestibulum eget auctor dui, at tempus dolor.', + 'Sed consequat placerat libero, et sodales sapien porttitor non.', + 'Aenean arcu diam, imperdiet sit amet purus a, ornare sodales metus.', + 'Integer accumsan ante sem, at facilisis ipsum egestas et.', + 'Nulla non orci dolor.', + 'Sed rhoncus facilisis condimentum.', + 'Nulla vitae maximus nisl.', + 'Praesent a rhoncus ante, a pharetra ante.', + 'Fusce volutpat eu risus nec eleifend.', + 'Suspendisse nibh leo, semper in egestas eget, placerat vel nulla.', + 'Ut malesuada condimentum eros, id dignissim nunc imperdiet ac.', + 'Praesent posuere tortor vitae augue convallis malesuada.', + 'Donec congue sem eu leo dignissim, at blandit felis blandit.', + 'In auctor, sapien quis hendrerit auctor, arcu tellus aliquam ante, quis vulputate purus metus eget mauris.', + 'Proin eget purus purus.', + 'Vestibulum pretium pharetra egestas.', + 'Proin vulputate augue non odio commodo, eu varius sem porta.', + 'Quisque porta massa quis finibus dignissim.', + 'Sed sit amet lectus sit amet elit porta rutrum.', + 'Nunc ornare vulputate tellus, eu rutrum turpis sagittis rutrum.', + 'Nam elit justo, laoreet a tortor et, tempus dapibus sapien.', + 'Sed velit augue, maximus et dignissim sed, mollis id mi.', + 'Integer eget libero consequat, placerat massa maximus, efficitur dui.', + 'Praesent quis ipsum a ex ultricies euismod a sit amet mi.', + 'Curabitur at accumsan urna.', + 'Cras pulvinar leo sit amet ligula suscipit mattis.', + 'Morbi dapibus facilisis euismod.', + 'Quisque efficitur venenatis eros ac elementum.', + 'Suspendisse imperdiet nunc non libero consectetur, eget blandit libero mattis.', + 'Vivamus tempor ullamcorper sapien vitae aliquam.', + 'In eget tempus ante.', + 'Vestibulum accumsan enim sed est eleifend, non commodo orci tristique.', + 'Nam pellentesque nisi a laoreet lobortis.', + 'Sed faucibus eros nec urna elementum, sed tincidunt est elementum.', + 'Suspendisse bibendum, velit nec tempus ullamcorper, urna elit auctor mauris, et tempus dui purus ut sapien.', + 'Aliquam posuere pulvinar lorem, ac vulputate neque congue eget.', + 'Vivamus sit amet elit id ante pellentesque rhoncus.', + 'Maecenas sagittis dui justo, id bibendum nulla egestas ac.', + 'Mauris placerat sapien urna, eget porta nisi molestie eu.', + 'Pellentesque metus arcu, gravida eget erat et, condimentum sodales quam.', + 'Ut finibus tortor ac dui vestibulum, et interdum elit fringilla.', + 'Aliquam a fringilla augue.', + 'Aenean placerat, enim nec dapibus viverra, arcu leo pharetra nibh, id pretium nisl purus et orci.', + 'Praesent felis odio, bibendum ut rutrum non, vehicula mollis tortor.', + 'Nam id vulputate magna.', + 'Vivamus ultrices purus vitae risus vehicula, et varius magna fringilla.', + 'Integer mollis, arcu in aliquet eleifend, augue felis suscipit augue, vitae consectetur sem elit non neque.', + 'Suspendisse dictum, lectus et sagittis dictum, turpis lorem ultrices odio, vitae tincidunt ex dolor vitae leo.', + 'Nulla aliquet risus ut augue finibus, ac egestas ante varius.', + 'In eget est a urna pulvinar bibendum quis eget dui.', + 'In sodales auctor imperdiet.', + 'Aenean et ipsum commodo, gravida erat vel, molestie nunc.', + 'Etiam maximus nibh finibus ex aliquet aliquam.', + 'Aliquam ultricies tellus lectus, ac suscipit tellus congue ac.', + 'Ut id ullamcorper urna.', + 'Aliquam ut faucibus nunc.', + 'Morbi vel elit dapibus, faucibus sem quis, feugiat lacus.', + 'Sed euismod diam mi, ac lacinia diam ornare sed.', + 'Duis dictum sodales turpis at feugiat.', + 'Donec id orci maximus, venenatis metus quis, tincidunt sapien.', + 'Etiam et justo non orci elementum bibendum ut sed elit.', + 'Donec imperdiet porta augue eget suscipit.', + 'Donec posuere dui eget quam faucibus hendrerit.', + 'Nunc non nibh mi.', + 'Nullam augue ex, tincidunt nec turpis pretium, porttitor tempor neque.', + 'Integer vel neque commodo, consectetur nulla a, blandit risus.', + 'Quisque maximus est condimentum hendrerit placerat.', + 'Morbi sagittis posuere feugiat.', + 'Mauris nec lacinia dolor, eu accumsan ante.', + 'Sed eu lorem auctor, gravida ligula vitae, auctor arcu.', + 'Curabitur porttitor et lacus nec tempor.', + 'Nulla sed posuere lorem, at facilisis quam.', + 'Sed ornare leo vitae ipsum condimentum, in ullamcorper magna rhoncus.', + 'Nullam quis augue tristique, scelerisque turpis sit amet, placerat tortor.', + 'Suspendisse aliquam magna a suscipit egestas.', + 'Fusce dictum consectetur mattis.', + 'Etiam commodo iaculis neque quis scelerisque.', + 'Nulla eu condimentum lectus, vitae tincidunt nisi.', + 'Vestibulum lacinia ac ligula quis fringilla.', + 'Pellentesque aliquam posuere nunc sed malesuada.', + 'Fusce a sem lobortis, egestas tortor eu, mollis sapien.', + 'Praesent malesuada consequat ante in hendrerit.', + 'Pellentesque lorem ligula, sodales quis suscipit at, venenatis in risus.', + 'Phasellus sapien nibh, tincidunt ut suscipit non, hendrerit id turpis.', + 'Maecenas ut lorem non risus efficitur tristique ac at arcu.', + 'Phasellus consequat urna ligula, a luctus justo cursus ac.', + 'Praesent et augue augue.', + 'Morbi accumsan neque id nisl malesuada, quis cursus sapien blandit.', + 'Phasellus ultrices dignissim neque a posuere.', + 'Mauris eu vehicula nunc.', + 'Sed egestas nisi dui, at lobortis dui condimentum vitae.', + 'Quisque sit amet dui eu massa molestie malesuada iaculis in nulla.', + 'Phasellus et molestie lacus.', + 'Pellentesque egestas iaculis tortor, ac tempus ante commodo non.', + 'Maecenas ullamcorper dictum tortor ut luctus.', + 'Curabitur id dui quis felis pharetra elementum vitae nec elit.', + 'Nunc dictum malesuada ante, in elementum nulla ornare ut.', + 'Vivamus luctus lacus id venenatis eleifend.', + 'Suspendisse a venenatis turpis.', + 'Sed suscipit feugiat massa sed molestie.', + 'Suspendisse vitae ornare quam.', + 'Vivamus tincidunt metus sed aliquet sodales.', + 'Ut quis massa a magna vulputate dictum in vitae ex.', + 'Phasellus nulla elit, volutpat eu tincidunt eu, fringilla interdum metus.', + 'Praesent dignissim felis nec est molestie, in commodo lectus tempor.', + 'Donec quis mi venenatis, suscipit nibh eget, euismod dui.', + 'Morbi enim elit, tempor at euismod quis, lacinia sit amet risus.', + 'Vestibulum vitae pharetra magna, non luctus mauris.', + 'Nullam vel luctus arcu, condimentum posuere libero.', + 'Ut ullamcorper, dolor ac interdum auctor, massa leo vehicula urna, sed interdum lacus magna in quam.', + 'Integer pretium pulvinar sem, eget vehicula sem egestas vel.', + 'Aenean malesuada odio eget fermentum facilisis.', + 'Suspendisse finibus, tortor sit amet porta ultricies, sapien dolor sodales metus, a commodo risus nulla vel justo.', + 'Integer nec justo at neque aliquam ultrices a quis libero.', + 'Ut sem ligula, facilisis ut turpis quis, convallis porta ex.', + 'Nam sed ullamcorper ipsum, ut tincidunt risus.', + 'Curabitur nisi nisl, finibus et maximus id, bibendum hendrerit risus.', + 'Suspendisse molestie laoreet quam, in lobortis ipsum sodales id.', + 'Integer et suscipit nisi.', + 'Mauris mattis porta malesuada.', + 'Vivamus interdum blandit dolor, vitae egestas turpis rutrum eget.', + 'In a est sit amet dolor tristique vehicula.', + 'Sed et vehicula magna, eget laoreet dui.', + 'In convallis sem in maximus luctus.', + 'Vestibulum vestibulum convallis diam, nec tristique nisl cursus vel.', + 'Suspendisse nec lorem eget ligula venenatis placerat et et massa.', + 'Vestibulum efficitur ac libero vel fermentum.', + 'Cras condimentum diam turpis, sit amet egestas neque hendrerit ac.', + 'Pellentesque mattis mollis dignissim.', + 'Donec eleifend magna ac pulvinar sagittis.', + 'Vestibulum accumsan vulputate odio et molestie.', + 'Vestibulum accumsan volutpat interdum.', + 'Fusce vestibulum feugiat odio bibendum bibendum.', + 'Mauris non blandit nibh, id mattis dolor.', + 'Nunc interdum ipsum quis sem scelerisque sagittis.', + 'Integer sit amet dapibus velit, sit amet facilisis sem.', + 'In hendrerit sapien vel nulla rutrum, at lobortis quam gravida.', + 'Etiam euismod est quis leo convallis, eu interdum risus viverra.', + 'Nam ullamcorper imperdiet erat, ut efficitur nunc molestie a.', + 'Sed eget tellus cursus, ullamcorper odio sit amet, semper est.', + 'Aliquam suscipit urna ex, quis sodales nisi dapibus non.', + 'Nulla quis leo non tellus sollicitudin suscipit.', + 'Fusce in aliquet nulla.', + 'Donec risus tellus, imperdiet sed vulputate ut, pulvinar malesuada quam.', + 'Morbi id ligula leo.', + 'Fusce varius mauris dui, vel placerat magna efficitur eget.', + 'Morbi vulputate et lectus a porta.', + 'Quisque porta tortor sapien, quis rhoncus libero maximus volutpat.', + 'Cras sodales ex nec tortor finibus, aliquet scelerisque sem pellentesque.', + 'Aliquam ornare sodales quam.', + 'Donec eleifend ornare velit, in mollis elit.', + 'Nunc bibendum venenatis dui, sit amet scelerisque ex blandit eget.', + 'In non lacus iaculis, dictum urna id, placerat lorem.', + 'Vestibulum quis sem imperdiet, pellentesque neque ac, varius justo.', + 'Phasellus porta, augue at mattis dignissim, erat tortor porttitor leo, eu pretium purus lectus quis diam.', + 'Nam scelerisque, turpis eget pharetra sollicitudin, erat lacus tincidunt odio, at condimentum augue eros nec lectus.', + 'Proin vestibulum, tortor non maximus sodales, quam nibh gravida risus, vitae porta ex nisi eget velit.', + 'Cras at orci eu tortor vulputate facilisis nec in ex.', + 'Donec a turpis pulvinar, gravida nisl ut, suscipit justo.', + 'Vestibulum pharetra, lacus eu sodales vestibulum, eros lectus ullamcorper odio, in vulputate dui leo a enim.', + 'Aenean at consectetur quam, in elementum ipsum.', + 'Vestibulum maximus aliquam leo, vitae accumsan felis hendrerit varius.', + 'Sed bibendum vestibulum nibh, scelerisque dictum ex feugiat et.', + 'Suspendisse placerat dolor quis aliquam maximus.', + 'Sed sed enim convallis, sodales nulla id, molestie nisi.', + 'Aliquam at iaculis ante.', + 'Cras blandit hendrerit accumsan.', + 'Vestibulum convallis nisi vel dui luctus, sit amet malesuada mi tincidunt.', + 'Nunc tempor eget massa porta dignissim.', + 'Proin ut congue neque, sit amet maximus felis.', + 'Mauris ultrices eleifend nunc.', + 'Maecenas maximus mauris ac sagittis volutpat.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Cras ac pulvinar diam.', + 'Donec mollis mi eu arcu convallis mattis.', + 'Donec ipsum lectus, placerat sed consectetur id, ultricies nec tortor.', + 'Cras tellus augue, faucibus et felis ut, vehicula pretium sem.', + 'Fusce sit amet cursus leo, nec cursus dui.', + 'Curabitur massa leo, varius ut consectetur in, sodales sit amet nisi.', + 'In faucibus nibh id massa porttitor, vitae sollicitudin metus pretium.', + 'Phasellus ultrices erat enim, vitae mollis justo tincidunt at.', + 'Donec accumsan commodo quam non iaculis.', + 'Pellentesque viverra et magna eget sollicitudin.', + 'Suspendisse at dui eu diam mattis congue sagittis in magna.', + 'Fusce fermentum commodo arcu sed consectetur.', + 'Fusce nec orci lacus.', + 'Aliquam eu mauris accumsan, ullamcorper massa eu, facilisis augue.', + 'Curabitur vel tincidunt felis, vitae faucibus nibh.', + 'Cras mattis dignissim viverra.', + 'Phasellus sed erat congue, maximus quam id, blandit lectus.', + 'Pellentesque a volutpat magna.', + 'Aenean tempus, tortor sit amet porttitor consectetur, ante libero pulvinar urna, at euismod purus erat a turpis.', + 'Vestibulum congue interdum laoreet.', + 'Morbi auctor sollicitudin lacus nec feugiat.', + 'Etiam et justo eget elit egestas bibendum eget varius nibh.', + 'Phasellus tempor ullamcorper tellus, fermentum lobortis velit luctus vel.', + 'In commodo ac ligula sit amet maximus.', + 'Duis consectetur nibh velit, vitae tristique urna mattis at.', + 'Cras vitae risus at metus finibus vestibulum.', + 'Ut sit amet suscipit mauris.', + 'Fusce euismod dolor non nibh consequat viverra.', + 'Duis viverra orci magna, vel volutpat turpis pretium vel.', + 'Integer ultricies tempus augue ut ultrices.', + 'Ut gravida ante venenatis commodo dapibus.', + 'Fusce tincidunt id nisl nec tincidunt.', + 'Phasellus sed diam bibendum, tincidunt felis ac, malesuada augue.', + 'In convallis mauris non turpis convallis auctor.', + 'Vivamus dolor tortor, suscipit at vulputate vitae, ullamcorper vitae ipsum.', + 'Sed dictum eros neque, sit amet cursus felis condimentum ac.', + 'Sed laoreet diam eu euismod tempus.', + 'Phasellus ultricies suscipit lacus, at faucibus est varius ac.', + 'Praesent aliquam tristique interdum.', + 'Quisque quis porttitor ipsum, sed pellentesque arcu.', + 'Ut convallis eros sed tellus euismod posuere.', + 'Proin eget dictum lacus.', + 'Mauris scelerisque ex ac faucibus maximus.', + 'Donec at leo sed libero iaculis gravida sed ac enim.', + 'Proin a consequat ligula.', + 'In euismod tempus velit vel condimentum.', + 'Proin viverra convallis ipsum sit amet accumsan.', + 'Ut mi nisl, consequat a neque eu, aliquam placerat quam.', + 'Duis tempus ullamcorper risus ut finibus.', + 'Duis ac enim eros.', + 'In blandit malesuada tellus, in bibendum massa condimentum in.', + 'Vivamus quis orci libero.', + 'Cras eu condimentum ipsum.', + 'Maecenas lacinia lobortis euismod.', + 'Nulla at imperdiet nibh, eget lacinia augue.', + 'Curabitur sit amet pulvinar ipsum.', + 'Praesent tincidunt velit in nunc congue dictum.', + 'Cras arcu arcu, elementum sit amet molestie non, pellentesque id orci.', + 'Vestibulum eleifend faucibus magna pellentesque imperdiet.', + 'Curabitur convallis non nunc nec consectetur.', + 'Integer at maximus tellus, ac pellentesque velit.', + 'Etiam nec elementum turpis, et blandit sapien.', + 'Mauris iaculis pulvinar ipsum, ac vulputate lacus maximus sit amet.', + 'Mauris quis turpis in orci ornare posuere at quis lorem.', + 'Etiam egestas aliquam rhoncus.', + 'Maecenas metus ex, lobortis malesuada rutrum viverra, pellentesque quis ligula.', + 'Pellentesque a nunc orci.', + 'Integer vitae elit sodales nisl aliquet luctus nec eu augue.', + 'Pellentesque feugiat eget urna eu molestie.', + 'Quisque dolor sem, gravida id nisl nec, sodales hendrerit sapien.', + 'Vivamus vehicula neque lacus.', + 'Duis non justo et nunc consequat sagittis non in eros.', + 'Morbi nulla diam, interdum et massa at, eleifend lobortis nibh.', + 'Nunc sollicitudin pharetra tincidunt.', + 'Pellentesque nulla diam, bibendum ac dictum a, facilisis gravida est.', + 'Fusce tempus turpis fringilla pellentesque pretium.', + 'Aenean ultricies sapien dolor, ullamcorper auctor libero interdum eu.', + 'Duis quis velit in urna laoreet imperdiet id ut sem.', + 'Phasellus fermentum odio at tempor scelerisque.', + 'Donec semper viverra ex, ut hendrerit ante tristique vel.', + 'Cras vel tempor massa.', + 'Sed lacinia viverra vestibulum.', + 'Suspendisse libero elit, porta at enim eu, iaculis consectetur lectus.', + 'Pellentesque aliquet lorem vehicula sapien sagittis, vel tristique augue venenatis.', + 'Nunc felis diam, iaculis vitae tortor at, rutrum efficitur orci.', + 'Pellentesque mi metus, luctus a tellus eget, eleifend elementum tortor.', + 'Praesent aliquet quam efficitur urna blandit lacinia.', + 'Pellentesque euismod sodales ultrices.', + 'Quisque non arcu ut arcu molestie dapibus.', + 'Aenean euismod lacus mi.', + 'Morbi sodales massa sed nisl luctus, eget posuere tortor vehicula.', + 'Etiam interdum convallis enim eu sagittis.', + 'Mauris sollicitudin nisi eget diam placerat, ac malesuada ligula vestibulum.', + 'Phasellus in vulputate elit.', + 'Phasellus porta consequat scelerisque.', + 'Ut tincidunt eget quam et faucibus.', + 'Integer mi elit, blandit at vehicula non, porta ut odio.', + 'Donec sollicitudin varius finibus.', + 'Nam a venenatis massa.', + 'Vivamus sit amet porta arcu.', + 'Maecenas dui nunc, venenatis ac sem ac, elementum molestie tellus.', + 'Aliquam scelerisque, velit ac venenatis vestibulum, nisi ante semper risus, in eleifend diam lorem ac ligula.', + 'Aliquam pulvinar dui porttitor magna sagittis volutpat.', + 'Sed posuere tortor a tellus tincidunt semper.', + 'Nulla rhoncus id nunc vitae condimentum.', + 'Donec efficitur faucibus ex eget varius.', + 'Cras fermentum vestibulum tellus eget iaculis.', + 'Vestibulum vestibulum nec purus eget semper.', + 'Sed commodo purus arcu, a consequat felis sollicitudin a.', + 'Suspendisse mollis lectus sed nulla dapibus gravida.', + 'Sed fermentum sem et nunc venenatis luctus.', + 'Phasellus dapibus est non magna iaculis, vel venenatis ex ornare.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec malesuada commodo nibh, id vulputate enim viverra at.', + 'Sed venenatis viverra mattis.', + 'Aliquam tincidunt dignissim sem, et sodales purus mollis id.', + 'Nam vitae pellentesque augue, a congue magna.', + 'Quisque vitae blandit nisi, sed vehicula magna.', + 'Aliquam id diam ac purus sagittis pharetra mattis eget ipsum.', + 'Praesent pulvinar gravida mi, a ornare velit cursus ac.', + 'Aliquam bibendum vulputate consequat.', + 'Nulla elit ante, ultrices quis eleifend eu, egestas quis ipsum.', + 'Aliquam non auctor nulla.', + 'Curabitur in condimentum ex.', + 'Mauris vestibulum ligula sit amet tortor porttitor iaculis.', + 'Ut sollicitudin sed nunc eu iaculis.', + 'Integer mattis egestas tellus, et volutpat ligula placerat non.', + 'Aliquam id sem interdum, scelerisque arcu in, tempus elit.', + 'Etiam tristique, mi et euismod dictum, leo augue posuere tellus, vitae malesuada libero dolor sed urna.', + 'Donec interdum dolor metus, ac euismod magna pulvinar in.', + 'Cras at nunc at nibh sollicitudin tristique.', + 'Nullam nec quam porta, rhoncus diam et, porta erat.', + 'Vestibulum ut vestibulum ante.', + 'Aliquam tincidunt blandit metus ac varius.', + 'Vivamus sollicitudin, quam a suscipit volutpat, leo eros commodo ex, sed sodales urna diam sed nulla.', + 'Sed a nibh ac felis efficitur luctus sit amet mollis leo.', + 'Vestibulum tempor urna quis erat accumsan hendrerit.', + 'Etiam euismod mauris non est iaculis dignissim.', + 'Nunc in dui ultrices, placerat tellus ut, sollicitudin magna.', + 'Aliquam efficitur nunc ac elit viverra laoreet.', + 'Pellentesque dui nisl, viverra vitae venenatis eu, ultricies vel risus.', + 'Integer volutpat quam non erat condimentum placerat.', + 'Maecenas molestie odio vel ultrices porta.', + 'Integer ullamcorper mollis elementum.', + 'Suspendisse mi sapien, mattis ut posuere vitae, vulputate a nisi.', + 'Nulla et ullamcorper odio.', + 'Mauris nec arcu massa.', + 'Aliquam quis eleifend ante.', + 'Nulla dignissim pulvinar hendrerit.', + 'Aenean lobortis tempus condimentum.', + 'Sed rhoncus metus quis mi ullamcorper tincidunt.', + 'Phasellus augue nisi, auctor quis posuere sed, mattis eu libero.', + 'Mauris pharetra ac libero at sodales.', + 'Cras efficitur enim ut tempor convallis.', + 'Donec lectus lorem, consectetur quis felis sed, vehicula suscipit massa.', + 'Vestibulum posuere viverra ultrices.', + 'Vivamus mollis cursus nibh sed fermentum.', + 'Vestibulum in varius ligula.', + 'Donec sit amet est scelerisque, sodales odio a, dictum ligula.', + 'Suspendisse consequat laoreet est, sit amet pulvinar elit sodales vitae.', + 'Nunc fermentum sodales eros, at vestibulum arcu vulputate ut.', + 'Integer faucibus aliquet eros.', + 'Suspendisse metus quam, placerat nec rutrum a, feugiat vel sapien.', + 'Donec malesuada, eros id blandit scelerisque, tellus libero ultricies leo, ac accumsan arcu metus eu nisl.', + 'Integer vitae arcu turpis.', + 'Sed eget congue orci, vel porta tellus.', + 'Integer ligula nisl, finibus eu sollicitudin ac, malesuada vitae nisi.', + 'Donec sit amet vulputate metus.', + 'Phasellus enim sem, varius ac vulputate ut, dapibus id tellus.', + 'Nam non malesuada metus.', + 'Nulla scelerisque magna ut est imperdiet, ac luctus sem sodales.', + 'In auctor neque enim, eu hendrerit eros fringilla nec.', + 'Duis quis purus rhoncus, malesuada enim vitae, bibendum nisl.', + 'Donec ut libero lacinia, tempus enim sed, volutpat metus.', + 'In commodo posuere nisi vitae faucibus.', + 'Maecenas felis odio, vehicula ac ullamcorper non, maximus id elit.', + 'Curabitur congue urna in mi venenatis euismod.', + 'Suspendisse hendrerit lacus ac risus tempor, non tristique urna venenatis.', + 'Suspendisse cursus urna ornare, varius risus sit amet, lobortis eros.', + 'Fusce consequat porttitor tortor in dignissim.', + 'Ut nulla magna, semper posuere ex quis, pharetra tempor quam.', + 'Morbi enim ligula, tincidunt id ligula ac, imperdiet pretium arcu.', + 'Maecenas quis risus malesuada nisl efficitur pretium.', + 'Integer at ante congue, luctus neque sed, dictum sem.', + 'Phasellus luctus diam nec risus porttitor posuere.', + 'Vestibulum ultrices tristique ex.', + 'Nulla id lacus erat.', + 'Vestibulum eu orci turpis.', + 'Ut feugiat auctor interdum.', + 'Donec at convallis dui.', + 'Phasellus placerat vitae dui eu tincidunt.', + 'Vestibulum metus lacus, fermentum id dignissim a, sagittis a nulla.', + 'In fermentum turpis in dui dignissim iaculis.', + 'Suspendisse vehicula ex vel imperdiet vestibulum.', + 'Suspendisse lobortis felis non augue lacinia ornare.', + 'Cras porta neque tellus, sed aliquet purus vulputate tincidunt.', + 'Nullam non purus tellus.', + 'Vivamus ex diam, condimentum ut ornare sit amet, venenatis pharetra turpis.', + 'Aliquam dui tortor, volutpat ut molestie eu, efficitur id nibh.', + 'Morbi vel ante et tellus rhoncus mattis id at sem.', + 'In vel tellus sapien.', + 'Aenean nec est finibus, iaculis orci a, molestie turpis.', + 'Proin ornare eget odio luctus sodales.', + 'Etiam hendrerit a nisl at pellentesque.', + 'Nunc blandit blandit mauris, eget blandit nisi luctus eget.', + 'Ut justo justo, imperdiet nec magna maximus, venenatis vestibulum leo.', + 'Cras a consequat quam.', + 'Vestibulum ac lectus ullamcorper, efficitur lacus quis, pulvinar est.', + 'Aenean nec odio elit.', + 'Nulla quis viverra odio, nec cursus erat.', + 'Vestibulum lobortis est nec sem dignissim, id luctus tortor congue.', + 'Morbi sollicitudin massa et justo aliquam volutpat.', + 'Aliquam bibendum tristique lacus sit amet mattis.', + 'Sed hendrerit lorem feugiat est feugiat ultricies.', + 'Cras dictum, turpis id imperdiet volutpat, nisl orci facilisis mi, in tincidunt arcu diam et dui.', + 'Mauris congue neque libero, vitae sagittis elit consectetur in.', + 'Cras commodo at sem et fermentum.', + 'Nullam consequat ligula in est pellentesque malesuada.', + 'In sit amet elit ac erat varius posuere scelerisque in lectus.', + 'Nunc ac odio vitae orci placerat mollis at in velit.', + 'Vivamus interdum nunc quis velit viverra consectetur.', + 'Nam sit amet semper arcu.', + 'Donec pellentesque feugiat lorem nec elementum.', + 'Quisque tincidunt maximus vehicula.', + 'Curabitur fermentum, ligula in sollicitudin tempus, odio libero euismod augue, vulputate pellentesque lorem nisi vehicula nulla.', + 'Aenean quis mauris et neque venenatis laoreet.', + 'Fusce id porta augue.', + 'Integer ac nunc vel enim ultrices consequat.', + 'Mauris magna purus, congue ut sapien in, molestie luctus nulla.', + 'Donec consequat, augue in tristique scelerisque, nisi sem tincidunt lorem, varius tempus est nunc in ipsum.', + 'Duis dictum ut est ac viverra.', + 'Aliquam id tincidunt ligula.', + 'Aliquam vitae tortor ut massa eleifend imperdiet sed et ipsum.', + 'Maecenas aliquet tellus ac nisl molestie, vel ullamcorper lacus vulputate.', + 'Mauris nec lacus sapien.', + 'Integer sagittis dolor sit amet velit mollis, quis sodales odio sollicitudin.', + 'Vivamus varius, libero a cursus imperdiet, lorem diam vestibulum risus, eget dictum lectus dolor eget eros.', + 'Nullam vitae orci varius, suscipit magna vitae, efficitur tellus.', + 'Praesent sagittis mi nec rutrum tempus.', + 'Aenean eu eros in erat gravida consectetur.', + 'Nulla lacinia vitae urna commodo ultricies.', + 'In interdum fermentum malesuada.', + 'Nullam placerat vel velit vel blandit.', + 'Praesent blandit tortor nec nisl viverra rutrum.', + 'Fusce ac euismod dui.', + 'Curabitur auctor quam dui, quis tristique ligula ornare et.', + 'Vivamus tellus diam, fringilla a congue quis, porta sit amet diam.', + 'Proin consectetur pulvinar malesuada.', + 'Duis tempor maximus libero non fringilla.', + 'Maecenas et elit leo.', + 'Fusce porttitor ex tortor, iaculis mollis sapien scelerisque eu.', + 'Etiam in dignissim tellus, nec egestas mauris.', + 'Aenean lacinia nec sapien quis suscipit.', + 'Ut id libero nec ligula laoreet rutrum.', + 'In id hendrerit nisl, sed luctus tortor.', + 'Morbi interdum augue justo, tincidunt suscipit sem lacinia vel.', + 'Aliquam a massa tortor.', + 'Sed eget libero id est pharetra laoreet.', + 'Morbi molestie, ex eu aliquet maximus, ante felis efficitur ligula, ac commodo justo augue quis velit.', + 'Integer lorem nulla, rhoncus a magna placerat, semper faucibus quam.', + 'Curabitur imperdiet aliquet diam nec scelerisque.', + 'Sed sed pellentesque risus.', + 'Sed tortor odio, vestibulum et augue a, maximus congue turpis.', + 'Donec pulvinar mi a enim rutrum, eu blandit neque molestie.', + 'Nullam tristique pulvinar sapien, ut consectetur velit mollis eu.', + 'Suspendisse vestibulum nisi leo, et ornare mi congue id.', + 'Integer urna nulla, molestie vitae arcu in, finibus aliquet felis.', + 'Maecenas laoreet venenatis felis, eget finibus urna pharetra sed.', + 'Pellentesque in turpis a nulla rutrum egestas vel in augue.', + 'Curabitur a lectus ac nulla porta vehicula.', + 'Cras quis euismod massa.', + 'Sed consequat arcu vitae gravida pellentesque.', + 'Donec rhoncus rhoncus imperdiet.', + 'Praesent pulvinar risus sed orci dignissim, sed tincidunt leo viverra.', + 'Aenean euismod maximus posuere.', + 'Quisque odio dolor, suscipit ut semper sed, molestie vel nulla.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Quisque auctor, leo at vulputate tempus, est nisi imperdiet arcu, nec dignissim nunc mauris eget enim.', + 'Aliquam at posuere mauris, ac dignissim nibh.', + 'Donec lacinia lobortis tempus.', + 'Sed blandit varius enim et sodales.', + 'Morbi pretium vulputate ipsum et congue.', + 'Quisque scelerisque justo eget ullamcorper vestibulum.', + 'Cras quis erat ut turpis dictum aliquam rutrum vel ligula.', + 'Sed ipsum elit, congue quis mi sit amet, semper porttitor magna.', + 'Nulla vel tellus condimentum, accumsan ex ac, gravida mauris.', + 'Donec cursus, nisi in vestibulum suscipit, magna tellus interdum tortor, a tincidunt mi turpis vitae libero.', + 'Etiam consectetur, odio ut iaculis convallis, ex nisl rhoncus enim, vitae placerat sem dui eu elit.', + 'Curabitur libero tellus, posuere nec fringilla sed, lobortis nec quam.', + 'Curabitur a augue ligula.', + 'Mauris pharetra eu ante non porta.', + 'Cras efficitur velit sem.', + 'Proin at dapibus arcu.', + 'Integer nec purus vitae lorem aliquam placerat.', + 'Integer sem risus, ultricies sit amet magna eget, viverra vehicula augue.', + 'Morbi blandit ligula vitae interdum euismod.', + 'Vestibulum egestas eleifend pulvinar.', + 'Ut euismod ex rutrum, viverra augue non, molestie libero.', + 'Proin fringilla, urna eu condimentum pharetra, dolor quam sollicitudin mi, vitae consequat sapien purus id magna.', + 'Phasellus pulvinar vel massa eu ullamcorper.', + 'Etiam nunc leo, vestibulum a tortor quis, laoreet gravida odio.', + 'Nullam tristique consequat lacus nec aliquam.', + 'Pellentesque aliquet augue facilisis felis pretium faucibus.', + 'Integer vitae ultrices diam, id lobortis ipsum.', + 'In at augue nibh.', + 'In non gravida ante.', + 'Aenean euismod eros augue.', + 'Nunc ac metus eget mauris bibendum cursus.', + 'Etiam et massa eu lacus molestie dignissim.', + 'Proin dictum ante non urna sollicitudin eleifend.', + 'Mauris convallis ultricies neque sit amet semper.', + 'Morbi venenatis euismod quam sed gravida.', + 'Nulla elementum orci at justo scelerisque, vel dapibus eros scelerisque.', + 'Integer accumsan augue posuere, suscipit odio vitae, tincidunt nisi.', + 'Quisque in orci malesuada, lobortis neque sit amet, pretium odio.', + 'Integer tempus eget sapien non sodales.', + 'Nunc ut dapibus justo.', + 'Quisque id nulla elit.', + 'Nam quis justo eget velit convallis facilisis.', + 'Quisque iaculis ex lectus, sit amet dictum neque pellentesque volutpat.', + 'Aenean quis tellus lacinia, gravida elit non, interdum quam.', + 'Donec interdum orci ut mauris molestie lacinia.', + 'Donec risus elit, mattis et viverra placerat, viverra et turpis.', + 'Morbi in sodales urna.', + 'Nam lorem ligula, tempus vitae sapien eget, vulputate fermentum purus.', + 'Aenean vulputate, nulla id euismod aliquet, leo ligula ornare tortor, sed tincidunt ante metus non felis.', + 'Cras volutpat, dolor consectetur luctus volutpat, mauris eros laoreet augue, at vehicula purus enim in tortor.', + 'Cras mi est, tincidunt in sapien nec, tempor cursus purus.', + 'Phasellus rutrum nibh a sagittis feugiat.', + 'Aenean sit amet tincidunt enim, at tincidunt justo.', + 'Pellentesque maximus nisi vitae nibh porttitor gravida.', + 'Aliquam ac sem mollis, pulvinar ligula id, rhoncus turpis.', + 'Ut placerat turpis ac finibus fringilla.', + 'Sed sit amet est eu tortor efficitur dignissim.', + 'Mauris iaculis, dolor et lobortis congue, augue massa scelerisque libero, in lobortis augue dolor et libero.', + 'Mauris pharetra finibus turpis, non maximus quam pellentesque sit amet.', + 'Praesent feugiat, ex eu aliquam tempor, sem nibh tempus est, eget tincidunt velit quam eget est.', + 'Donec imperdiet enim tellus, vel tincidunt felis accumsan rutrum.', + 'Ut ac sem sit amet sem posuere luctus at in enim.', + 'Nulla euismod, libero vel finibus lobortis, nulla libero porttitor tellus, a interdum odio quam nec nunc.', + 'Phasellus quis efficitur risus, ullamcorper condimentum nisl.', + 'Aliquam id neque a nunc vehicula euismod.', + 'In nec ultrices eros.', + 'Nunc sit amet purus neque.', + 'Pellentesque pharetra nisl augue, sed sollicitudin eros faucibus eget.', + 'Morbi sit amet lorem eget enim cursus vehicula.', + 'Etiam euismod ante in venenatis bibendum.', + 'Curabitur eu efficitur tortor.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nulla interdum nibh in vehicula tincidunt.', + 'Sed fringilla, magna non malesuada dignissim, quam enim mollis tellus, non faucibus purus tellus a ipsum.', + 'Ut placerat varius diam in vulputate.', + 'Mauris aliquet lectus id lacus iaculis, nec viverra ante porttitor.', + 'Maecenas finibus posuere risus.', + 'Suspendisse sit amet lectus quis nunc tincidunt bibendum eget in felis.', + 'In mattis dolor purus, id tempus nibh rutrum ut.', + 'Phasellus ornare diam ac elit laoreet, ac egestas ante maximus.', + 'In et lacus leo.', + 'Nam volutpat id nulla non dictum.', + 'Nunc blandit eu libero at consequat.', + 'In pretium lacus ac leo malesuada condimentum.', + 'Maecenas congue dictum ultricies.', + 'Sed id tincidunt ex.', + 'Praesent gravida lectus id ante facilisis, nec pharetra justo rutrum.', + 'Praesent cursus lobortis accumsan.', + 'Aenean sed lacus ac arcu blandit placerat.', + 'Quisque vitae ligula vitae elit congue dictum.', + 'Nulla condimentum fermentum nulla ac porta.', + 'Cras ornare diam vitae augue maximus, quis faucibus dui fermentum.', + 'Maecenas porttitor porttitor felis, sit amet facilisis diam sodales vitae.', + 'Aliquam dictum arcu tortor, et fringilla leo euismod vel.', + 'Phasellus diam mauris, feugiat aliquet fermentum in, porttitor et tortor.', + 'Maecenas ex justo, sagittis sed magna sed, efficitur venenatis felis.', + 'In placerat et nunc et malesuada.', + 'Aenean vehicula neque odio, vitae molestie mauris aliquet quis.', + 'Vestibulum gravida dolor vel velit semper rhoncus.', + 'Ut egestas sodales nulla quis rutrum.', + 'Integer quis nisi nec enim vestibulum convallis.', + 'Fusce eget nisi rutrum justo porttitor gravida nec nec ipsum.', + 'Nam blandit nec leo ut porttitor.', + 'Suspendisse a nunc sed ante fringilla fermentum consectetur vitae orci.', + 'Nunc bibendum arcu erat, eu ullamcorper est placerat ac.', + 'Sed facilisis, enim a tempor ullamcorper, metus nunc interdum lacus, id pellentesque mauris magna ut augue.', + 'Curabitur eu dignissim velit.', + 'Sed ut quam erat.', + 'Sed faucibus sapien felis, ac malesuada nunc cursus et.', + 'Sed vestibulum lacus nec sapien ultrices, at euismod tellus dignissim.', + 'Integer sagittis vulputate lectus, sed scelerisque tortor pulvinar id.', + 'Integer finibus venenatis massa, eget fringilla arcu placerat et.', + 'Proin blandit neque a quam blandit mollis.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse potenti.', + 'Ut nec risus nisl.', + 'Vestibulum rhoncus pellentesque augue fringilla molestie.', + 'Praesent sodales eget sapien eu tristique.', + 'In nec purus leo.', + 'Vivamus vitae sem sed massa bibendum tempor eu id lectus.', + 'Ut id pulvinar nunc.', + 'Nam tempus dignissim lectus, ac pellentesque neque porttitor non.', + 'Suspendisse lobortis rhoncus dui, ac ullamcorper dolor dignissim sed.', + 'Vestibulum sollicitudin faucibus nisl a laoreet.', + 'Aenean consequat purus et lorem suscipit, sed efficitur magna facilisis.', + 'Mauris fermentum malesuada tortor et tempus.', + 'Maecenas interdum rutrum pretium.', + 'Morbi non neque eget lorem suscipit congue id eget quam.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse malesuada purus nibh, volutpat facilisis lacus iaculis a.', + 'Aenean eu pharetra ligula.', + 'Nulla nec leo porta, sollicitudin nunc et, lacinia quam.', + 'Nunc placerat tristique pellentesque.', + 'Ut enim nisi, condimentum quis felis ut, vestibulum cursus mi.', + 'Vestibulum ut ipsum eros.', + 'Proin vehicula bibendum enim, vitae laoreet ante auctor vitae.', + 'Donec imperdiet vestibulum congue.', + 'Sed velit mi, dictum in commodo at, semper a neque.', + 'Aliquam lectus turpis, vulputate at nunc et, laoreet porttitor turpis.', + 'Nullam eu mauris eget augue tincidunt ornare.', + 'Pellentesque sit amet leo eu nibh placerat sagittis.', + 'Curabitur et finibus odio.', + 'Fusce tristique non tellus sed egestas.', + 'Donec metus nunc, consequat non lorem sit amet, vehicula venenatis nisl.', + 'Aenean sodales molestie posuere.', + 'Mauris ut sollicitudin orci.', + 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nunc sit amet condimentum mauris, eu fermentum risus.', + 'Cras quis ante felis.', + 'Pellentesque id interdum neque.', + 'Phasellus erat tellus, tempus quis pulvinar volutpat, efficitur in odio.', + 'Maecenas a venenatis ex, at tempor libero.', + 'Pellentesque suscipit ipsum eget tincidunt faucibus.', + 'Aenean sollicitudin est odio, vitae vulputate ligula dapibus sit amet.', + 'Nam finibus arcu at dui blandit ornare.', + 'Integer id dapibus est, ut fringilla lorem.', + 'Aenean interdum quis dui nec pharetra.', + 'Maecenas non diam non elit fringilla tempor id sollicitudin purus.', + 'Nullam odio metus, aliquam eu dolor non, rutrum sodales mauris.', + 'Maecenas nibh sem, faucibus at turpis vitae, tristique vestibulum eros.', + 'Duis ac dolor eget augue luctus dignissim.', + 'Fusce eget libero hendrerit, placerat purus id, volutpat tellus.', + 'Fusce viverra, arcu ut molestie ultricies, dui tortor lacinia risus, eu auctor elit mauris eu orci.', + 'Praesent semper mi eu mi dignissim, imperdiet dictum urna tincidunt.', + 'Nulla in lorem id sapien rhoncus ultrices.', + 'Quisque imperdiet, tortor ac viverra blandit, massa sapien auctor tortor, at fermentum ex tortor sit amet sem.', + 'Fusce nisl libero, sollicitudin vel feugiat iaculis, consectetur ac diam.', + 'Aliquam velit arcu, faucibus id ornare a, pharetra et leo.', + 'Nullam eu fringilla felis.', + 'Donec dignissim risus facilisis bibendum tincidunt.', + 'Donec sed orci nunc.', + 'Fusce at metus lobortis, iaculis ante laoreet, aliquam nisi.', + 'Integer imperdiet ornare turpis, sed viverra felis mattis non.', + 'Nulla tincidunt purus sed fermentum volutpat.', + 'Phasellus eu dignissim massa, non consectetur lorem.', + 'Praesent venenatis, nulla nec ornare vulputate, velit ipsum lobortis nisl, sed consequat nibh turpis vel diam.', + 'Pellentesque pharetra odio lobortis, congue enim eu, sagittis velit.', + 'Mauris sed molestie tortor.', + 'Suspendisse consectetur nunc vel dolor aliquet, vel venenatis eros laoreet.', + 'Nullam malesuada nulla libero, dapibus pretium mi iaculis a.', + 'Donec placerat nibh leo, id tristique enim tincidunt sed.', + 'Nunc elementum, arcu nec ultrices convallis, urna turpis finibus velit, eu euismod nibh orci ac eros.', + 'Proin cursus pellentesque turpis, vel tempor lorem feugiat et.', + 'Duis finibus aliquet lacus, at accumsan tortor posuere nec.', + 'Aliquam id sem justo.', + 'Suspendisse eget dignissim eros.', + 'Suspendisse feugiat scelerisque ante id fermentum.', + 'Quisque pellentesque libero et sem pellentesque ultrices.', + 'Nunc dignissim magna interdum, feugiat odio sit amet, pharetra lacus.', + 'Duis in sapien aliquam, volutpat est sit amet, semper risus.', + 'Proin blandit enim at fermentum mattis.', + 'Proin pharetra, orci a semper porttitor, purus felis placerat lorem, nec mollis orci tellus sit amet elit.', + 'Duis sed convallis turpis, a pellentesque nibh.', + 'Proin et est vel nisl dictum aliquam et et sem.', + 'Donec sed augue laoreet, suscipit sem quis, consectetur est.', + 'Sed hendrerit arcu quis porttitor vestibulum.', + 'Pellentesque interdum lorem urna, et vestibulum enim pharetra et.', + 'Cras sed neque sit amet erat aliquam semper.', + 'Fusce sit amet eros lacus.', + 'Cras commodo, nibh et sodales vehicula, eros magna pellentesque orci, et laoreet lacus dolor nec enim.', + 'Donec et quam ultrices, porta justo tempor, auctor odio.', + 'Morbi eget iaculis nisi, ut finibus orci.', + 'Sed tellus lectus, consequat nec dapibus ac, interdum vitae lectus.', + 'Praesent accumsan vehicula lacus ut efficitur.', + 'Integer sit amet nisl non odio tincidunt sodales eu ut mauris.', + 'Duis euismod risus quis iaculis sodales.', + 'Pellentesque eleifend vel lorem sed iaculis.', + 'Duis a mollis ex.', + 'Nunc ullamcorper id felis non aliquam.', + 'Etiam ut posuere lacus.', + 'Duis quis elementum ligula.', + 'Aenean pulvinar elit a eleifend luctus.', + 'Vivamus accumsan tincidunt dui in pellentesque.', + 'Cras vulputate metus at suscipit vestibulum.', + 'Phasellus ultrices consequat lectus, ac tristique nunc mattis sit amet.', + 'Donec arcu diam, mollis ut euismod sit amet, tincidunt vel ipsum.', + 'Maecenas aliquet orci ac rutrum laoreet.', + 'Quisque maximus nisl sed sapien posuere pulvinar.', + 'Sed interdum, ante et laoreet iaculis, arcu ligula pretium mi, eget bibendum lorem urna sit amet odio.', + 'Praesent consequat nisl quis tellus mollis eleifend.', + 'Suspendisse facilisis sem vitae sapien rhoncus, ac dignissim nunc pharetra.', + 'Quisque id lacus ut neque vehicula pellentesque.', + 'Quisque scelerisque, risus sit amet condimentum consectetur, quam erat pretium tellus, ut tempor metus lectus suscipit risus.', + 'Vestibulum eu lectus eget nunc aliquet laoreet.', + 'Phasellus ornare neque auctor pulvinar pellentesque.', + 'Aliquam vitae dignissim mi, ac mattis nibh.', + 'Duis vitae porta velit, ac efficitur mauris.', + 'Sed id nisi nisl.', + 'Donec malesuada odio in posuere eleifend.', + 'Cras ut mi quis tortor mollis iaculis sed a dolor.', + 'Nunc a nisi vitae orci consectetur semper.', + 'Mauris tristique pharetra mattis.', + 'Sed iaculis fermentum mauris a tempus.', + 'Quisque cursus, mauris vel tristique molestie, massa libero suscipit orci, ut sodales lacus massa vel odio.', + 'Sed eu mi sapien.', + 'Sed tincidunt ullamcorper mauris nec lobortis.', + 'Suspendisse at est in diam elementum commodo.', + 'Ut felis lectus, hendrerit sit amet vulputate sit amet, cursus sit amet quam.', + 'Quisque porta arcu ac purus scelerisque, ac aliquam mi ornare.', + 'Sed ultricies vitae purus et convallis.', + 'Nunc ligula nisl, malesuada ut scelerisque ac, maximus quis odio.', + 'Duis nisi arcu, commodo ac purus ac, dignissim convallis arcu.', + 'Suspendisse eget scelerisque libero.', + 'Morbi dolor purus, vehicula id sem sed, condimentum viverra eros.', + 'Etiam bibendum commodo enim, ac vulputate ex consequat aliquet.', + 'Pellentesque porta nisl sit amet tortor dignissim, quis aliquet arcu consectetur.', + 'Integer et pretium lectus.', + 'Fusce efficitur posuere ipsum, ut convallis nisl sollicitudin ultrices.', + 'Sed suscipit elementum est, vitae laoreet tellus dignissim ultricies.', + 'Praesent viverra nisl ut odio posuere, tristique finibus nibh rhoncus.', + 'Aliquam consequat ornare orci ac ultrices.', + 'Vivamus vel lacinia velit.', + 'Vestibulum sit amet sapien sit amet velit tincidunt suscipit.', + 'Etiam ornare molestie aliquet.', + 'Sed gravida enim quis nunc interdum imperdiet.', + 'Proin cursus odio ac dolor blandit, quis sollicitudin ante rutrum.', +]; diff --git a/drizzle-seed/src/datasets/phonesInfo.ts b/drizzle-seed/src/datasets/phonesInfo.ts new file mode 100644 index 000000000..3412857ed --- /dev/null +++ b/drizzle-seed/src/datasets/phonesInfo.ts @@ -0,0 +1,851 @@ +/** + * The original source for the phones info data was taken from https://www.kaggle.com/datasets/leighplt/country-code?select=mobile_telephone_prefixes_by_country.csv + * + * Data format is: ["country prefix, operator prefix, number length including operator prefix and excluding country prefix"] + */ +export default [ + '93,70,9', + '93,71,9', + '93,72,9', + '93,73,9', + '93,74,9', + '93,75,9', + '93,76,9', + '93,77,9', + '93,78,9', + '93,79,9', + '355,66,9', + '355,67,9', + '355,68,9', + '355,69,9', + '213,5,9', + '213,6,9', + '213,7,9', + '1,684,10', + '1,264 772,10', + '1,268 7,10', + '374,55,6', + '374,95,6', + '374,41,6', + '374,44,6', + '374,77,6', + '374,93,6', + '374,94,6', + '374,98,6', + '374,91,6', + '374,99,6', + '374,43,6', + '374,97,6', + '61,4,9', + '672,1,9', + '43,650,10', + '43,660,10', + '43,664,10', + '43,676,10', + '43,680,10', + '43,677,11', + '43,681,11', + '43,688,11', + '43,699,11', + '994,41,9', + '994,50,9', + '994,51,9', + '994,55,9', + '994,70,9', + '994,77,9', + '994,99,9', + '1,242 35,10', + '1,242 45,10', + '1,242 55,10', + '973,31,8', + '973,322,8', + '973,33,8', + '973,340,8', + '973,341,8', + '973,343,8', + '973,344,8', + '973,345,8', + '973,353,8', + '973,355,8', + '973,36,8', + '973,377,8', + '973,383,8', + '973,384,8', + '973,388,8', + '973,39,8', + '973,663,8', + '973,666,8', + '973,669,8', + '880,13,10', + '880,14,10', + '880,15,10', + '880,16,10', + '880,17,10', + '880,18,10', + '880,19,10', + '1,246,10', + '32,456,9', + '32,47,9', + '32,48,9', + '32,49,9', + '501,6,7', + '1,441,10', + '387,60,8', + '387,69,8', + '387,62,8', + '387,63,8', + '387,64,8', + '387,65,8', + '387,66,8', + '246,387,7', + '1,284,10', + '359,87,9', + '359,88,9', + '359,89,9', + '359,988,9', + '226,70,8', + '226,71,8', + '226,72,8', + '226,74,8', + '226,75,8', + '226,77,8', + '226,78,8', + '226,79,8', + '855,92,9', + '855,12,9', + '855,11,9', + '855,77,9', + '855,99,9', + '1,345,10', + '235,66,8', + '235,63,8', + '235,65,8', + '235,99,8', + '235,95,8', + '235,93,8', + '235,90,8', + '235,77,8', + '56,9,9', + '86,13,11', + '86,15,11', + '86,18,11', + '86,19,11', + '57,30,10', + '57,310,10', + '57,311,10', + '57,312,10', + '57,313,10', + '57,314,10', + '57,315,10', + '57,316,10', + '57,317,10', + '57,318,10', + '57,319,10', + '57,32,10', + '682,5,5', + '682,7,5', + '506,6,8', + '506,7,8', + '506,8,8', + '385,91,9', + '385,92,9', + '385,95,9', + '385,97,9', + '385,98,9', + '385,99,9', + '357,94,8', + '357,95,8', + '357,96,8', + '357,97,8', + '357,99,8', + '420,601,9', + '420,602,9', + '420,603,9', + '420,604,9', + '420,605,9', + '420,606,9', + '420,607,9', + '420,608,9', + '420,702,9', + '420,72,9', + '420,73,9', + '420,77,9', + '420,790,9', + '45,2,8', + '45,30,8', + '45,31,8', + '45,40,8', + '45,41,8', + '45,42,8', + '45,50,8', + '45,51,8', + '45,52,8', + '45,53,8', + '45,60,8', + '45,61,8', + '45,71,8', + '45,81,8', + '1,767 2,10', + '1,809,10', + '1,829,10', + '1,849,10', + '670,77,8', + '670,78,8', + '593,9,9', + '20,10,10', + '20,11,10', + '20,12,10', + '503,6,8', + '503,7,8', + '268,7,8', + '500,5,5', + '500,6,5', + '298,21,5', + '298,22,5', + '298,23,5', + '298,24,5', + '298,25,5', + '298,26,5', + '298,27,5', + '298,28,5', + '298,29,5', + '298,5,5', + '298,71,5', + '298,72,5', + '298,73,5', + '298,74,5', + '298,75,5', + '298,76,5', + '298,77,5', + '298,78,5', + '298,79,5', + '298,91,5', + '298,92,5', + '298,93,5', + '298,94,5', + '298,95,5', + '298,96,5', + '298,97,5', + '298,98,5', + '298,99,5', + '691,92,7', + '691,93,7', + '691,95,7', + '691,97,7', + '358,457,10', + '33,6,9', + '33,700,9', + '33,73,9', + '33,74,9', + '33,75,9', + '33,76,9', + '33,77,9', + '33,78,9', + '594,694,9', + '241,2,7', + '241,3,7', + '241,4,7', + '241,5,7', + '241,6,7', + '241,7,7', + '995,544,9', + '995,514,9', + '995,551,9', + '995,555,9', + '995,557,9', + '995,558,9', + '995,568,9', + '995,570,9', + '995,571,9', + '995,574,9', + '995,577,9', + '995,578,9', + '995,579,9', + '995,591,9', + '995,592,9', + '995,593,9', + '995,595,9', + '995,596,9', + '995,597,9', + '995,598,9', + '995,599,9', + '49,151,10', + '49,152,10', + '49,155,10', + '49,157,10', + '49,159,10', + '49,162,10', + '49,163,10', + '49,170,10', + '49,171,10', + '49,172,10', + '49,173,10', + '49,174,10', + '49,175,10', + '49,176,10', + '49,177,10', + '49,178,10', + '49,179,10', + '233,20,9', + '233,50,9', + '233,23,9', + '233,24,9', + '233,54,9', + '233,55,9', + '233,59,9', + '233,26,9', + '233,56,9', + '233,27,9', + '233,57,9', + '233,28,9', + '30,690,10', + '30,693,10', + '30,694,10', + '30,695,10', + '30,697,10', + '30,698,10', + '30,699,10', + '1,473 41,10', + '1,671,10', + '502,231,8', + '502,2324,8', + '502,2326,8', + '502,2327,8', + '502,2328,8', + '502,2329,8', + '502,2428,8', + '502,2429,8', + '502,30,8', + '502,310,8', + '502,311,8', + '502,448,8', + '502,449,8', + '502,45,8', + '502,46,8', + '502,478,8', + '502,479,8', + '502,480,8', + '502,481,8', + '502,49,8', + '502,5,8', + '1,808,10', + '504,3,8', + '504,7,8', + '504,8,8', + '504,9,8', + '36,20,9', + '36,30,9', + '36,31,9', + '36,38,9', + '36,50,9', + '36,60,9', + '36,70,9', + '91,7,10', + '91,8,10', + '91,90,10', + '91,91,10', + '91,92,10', + '91,93,10', + '91,94,10', + '91,95,10', + '91,96,10', + '91,97,10', + '91,98,10', + '91,99,10', + '62,811,9', + '62,813,11', + '62,814,11', + '62,815,10', + '62,818,9', + '62,819,10', + '62,838,10', + '62,852,11', + '62,853,11', + '62,855,10', + '62,858,11', + '62,859,11', + '62,878,11', + '62,896,10', + '62,897,10', + '62,898,10', + '62,899,10', + '98,91,10', + '98,990,10', + '353,8,9', + '353,83,9', + '353,85,9', + '353,86,9', + '353,87,9', + '353,89,9', + '972,50,9', + '972,52,9', + '972,53,9', + '972,54,9', + '972,556,9', + '972,558,9', + '972,559,9', + '972,58,9', + '39,310,10', + '39,31100,10', + '39,31101,10', + '39,31105,10', + '39,313,10', + '39,319,10', + '39,320,10', + '39,324,10', + '39,327,10', + '39,328,10', + '39,329,10', + '39,331,10', + '39,333,10', + '39,334,10', + '39,338,10', + '39,339,10', + '39,340,10', + '39,342,10', + '39,344,10', + '39,345,10', + '39,346,10', + '39,347,10', + '39,348,10', + '39,349,10', + '39,3505,10', + '39,3510,10', + '39,3512,10', + '39,366,10', + '39,370,10', + '39,3710,10', + '39,3711,10', + '39,373,10', + '39,377,10', + '39,380,10', + '39,385,10', + '39,388,10', + '39,389,10', + '39,391,10', + '39,392,10', + '39,393,10', + '1,876,10', + '81,060,11', + '81,070,11', + '81,080,11', + '81,090,11', + '254,10,10', + '254,11,10', + '254,70,10', + '254,71,10', + '254,72,10', + '254,73,10', + '254,74,10', + '254,75,10', + '254,763,10', + '254,77,10', + '254,78,10', + '686,63,8', + '686,7,8', + '383,44,8', + '383,45,8', + '383,49,8', + '965,5,8', + '965,6,8', + '965,9,8', + '371,2,8', + '231,46,7', + '231,47,7', + '231,5,7', + '231,64,7', + '231,65,7', + '231,7,8', + '218,91,10', + '218,92,10', + '218,94,10', + '370,6,8', + '352,621,9', + '352,628,9', + '352,661,9', + '352,668,9', + '352,691,9', + '352,698,9', + '60,11,7', + '60,12,7', + '60,13,7', + '60,14,7', + '60,16,7', + '60,17,7', + '60,18,7', + '60,19,7', + '960,7,7', + '960,9,7', + '223,6,8', + '223,7,8', + '596,696,9', + '230,57,8', + '230,58,8', + '230,59,8', + '230,54,8', + '52,1,10', + '373,60,8', + '373,65,8', + '373,67,8', + '373,68,8', + '373,69,8', + '373,78,8', + '373,79,8', + '976,70,8', + '976,88,8', + '976,89,8', + '976,91,8', + '976,93,8', + '976,94,8', + '976,95,8', + '976,96,8', + '976,98,8', + '976,99,8', + '382,60,8', + '382,63,8', + '382,66,8', + '382,67,8', + '382,68,8', + '382,69,8', + '1,664,10', + '95,92,8', + '95,925,10', + '95,926,10', + '95,943,9', + '95,94,10', + '95,944,9', + '95,95,8', + '95,96,8', + '95,973,9', + '95,991,9', + '95,93,9', + '95,996,10', + '95,997,10', + '95,977,10', + '95,978,10', + '95,979,10', + '977,98,10', + '31,6,9', + '687,7,6', + '687,8,6', + '687,9,6', + '64,22,9', + '64,27,9', + '505,8,8', + '227,9,8', + '234,804,8', + '234,805,8', + '234,803,8', + '234,802,8', + '234,809,8', + '683,1,4', + '683,3,4', + '683,4,4', + '672,38,6', + '389,70,8', + '389,71,8', + '389,72,8', + '389,74,8', + '389,75,8', + '389,76,8', + '389,77,8', + '389,78,8', + '389,79,8', + '90,533,7', + '1,670,10', + '47,4,8', + '47,59,8', + '47,9,8', + '968,91,8', + '92,30,10', + '92,31,10', + '92,32,10', + '92,33,10', + '92,34,10', + '507,6,8', + '595,9,9', + '51,9,9', + '63,973,10', + '63,974,10', + '63,905,10', + '63,906,10', + '63,977,10', + '63,915,10', + '63,916,10', + '63,926,10', + '63,927,10', + '63,935,10', + '63,936,10', + '63,937,10', + '63,996,10', + '63,997,10', + '63,917,10', + '63,979,10', + '63,920,10', + '63,930,10', + '63,938,10', + '63,939,10', + '63,907,10', + '63,908,10', + '63,909,10', + '63,910,10', + '63,912,10', + '63,919,10', + '63,921,10', + '63,928,10', + '63,929,10', + '63,947,10', + '63,948,10', + '63,949,10', + '63,989,10', + '63,918,10', + '63,999,10', + '63,922,10', + '63,923,10', + '63,932,10', + '63,933,10', + '63,942,10', + '63,943,10', + '48,50,9', + '48,45,9', + '48,51,9', + '48,53,9', + '48,57,9', + '48,60,9', + '48,66,9', + '48,69,9', + '48,72,9', + '48,73,9', + '48,78,9', + '48,79,9', + '48,88,9', + '351,91,9', + '351,921,9', + '351,922,9', + '351,924,9', + '351,925,9', + '351,926,9', + '351,927,9', + '351,9290,9', + '351,9291,9', + '351,9292,9', + '351,9293,9', + '351,9294,9', + '351,93,9', + '351,96,9', + '1,787,10', + '1,939,10', + '974,33,8', + '974,55,8', + '974,66,8', + '974,77,8', + '1,869,10', + '1,758,10', + '1,784,10', + '685,77,5', + '966,50,9', + '966,51,9', + '966,53,9', + '966,54,9', + '966,55,9', + '966,56,9', + '966,57,9', + '966,58,9', + '966,59,9', + '381,60,9', + '381,61,9', + '381,62,9', + '381,63,9', + '381,64,9', + '381,65,9', + '381,66,9', + '381,677,9', + '381,68,9', + '381,69,8', + '65,8,8', + '65,9,8', + '1,721,10', + '421,901,9', + '421,902,9', + '421,903,9', + '421,904,9', + '421,905,9', + '421,906,9', + '421,907,9', + '421,908,9', + '421,910,9', + '421,911,9', + '421,912,9', + '421,914,9', + '421,915,9', + '421,916,9', + '421,917,9', + '421,918,9', + '421,940,9', + '421,944,9', + '421,948,9', + '421,949,9', + '421,950,9', + '421,951,9', + '386,20,8', + '386,21,8', + '386,30,8', + '386,31,8', + '386,40,8', + '386,41,8', + '386,49,8', + '386,50,8', + '386,51,8', + '386,60,8', + '386,61,8', + '386,64,8', + '386,70,8', + '386,71,8', + '677,74,7', + '677,75,7', + '27,60,9', + '27,710,9', + '27,711,9', + '27,712,9', + '27,713,9', + '27,714,9', + '27,715,9', + '27,716,9', + '27,717,9', + '27,718,9', + '27,719,9', + '27,72,9', + '27,73,9', + '27,74,9', + '27,741,9', + '27,76,9', + '27,78,9', + '27,79,9', + '27,811,9', + '27,812,9', + '27,813,9', + '27,814,9', + '27,82,9', + '27,83,9', + '27,84,9', + '34,6,9', + '34,7,9', + '94,70,7', + '94,71,7', + '94,72,7', + '94,75,7', + '94,76,7', + '94,77,7', + '94,78,7', + '46,70,7', + '46,71 0,10', + '46,73 00,7', + '46,73 01,7', + '46,73 10,7', + '46,73 11,7', + '46,73 12,7', + '46,73 13,7', + '46,73 16,7', + '46,73 170,7', + '46,73 18,7', + '46,73 19,7', + '46,73 20,7', + '46,73 23,7', + '46,73 27,7', + '46,73 28,7', + '46,73 29,7', + '46,73 3,7', + '46,73 455,7', + '46,73 456,7', + '46,73 6,7', + '46,73 85,7', + '46,73 86,7', + '46,73 87,7', + '46,73 88,7', + '46,73 89,7', + '46,73 9,7', + '41,74,9', + '41,75,9', + '41,76,9', + '41,77,9', + '41,78,9', + '41,79,9', + '963,93,9', + '963,98,9', + '963,99,9', + '963,94,9', + '963,95,9', + '963,96,9', + '886,9,9', + '66,6,9', + '66,8,9', + '66,9,9', + '228,90,8', + '228,91,8', + '228,92,8', + '228,97,8', + '228,98,8', + '228,99,8', + '1,868,10', + '216,2,8', + '216,3,8', + '216,4,8', + '216,5,8', + '216,9,8', + '90,50,11', + '90,53,11', + '90,54,11', + '90,55,11', + '1,649,10', + '380,39,9', + '380,50,9', + '380,63,9', + '380,66,9', + '380,67,9', + '380,68,9', + '380,91,9', + '380,92,9', + '380,93,9', + '380,94,9', + '380,95,9', + '380,96,9', + '380,97,9', + '380,98,9', + '380,99,9', + '971,50,9', + '971,52,9', + '971,54,9', + '971,55,9', + '971,56,9', + '971,58,9', + '44,71,10', + '44,72,10', + '44,73,10', + '44,74,10', + '44,75,10', + '44,7624,10', + '44,77,10', + '44,78,10', + '44,79,10', + '598,91,8', + '598,93,8', + '598,94,8', + '598,95,8', + '598,96,8', + '598,97,8', + '598,98,8', + '598,99,8', + '39,06 698,10', + '58,4,7', + '58,412,7', + '58,414,7', + '58,416,7', + '58,424,7', + '58,426,7', + '1,340,10', + '967,7,9', + '967,70,9', + '967,71,9', + '967,73,9', + '967,77,9', +]; diff --git a/drizzle-seed/src/datasets/states.ts b/drizzle-seed/src/datasets/states.ts new file mode 100644 index 000000000..1de77160d --- /dev/null +++ b/drizzle-seed/src/datasets/states.ts @@ -0,0 +1,52 @@ +export default [ + 'Alabama', + 'Alaska', + 'Arizona', + 'Arkansas', + 'California', + 'Colorado', + 'Connecticut', + 'Delaware', + 'Florida', + 'Georgia', + 'Hawaii', + 'Idaho', + 'Illinois', + 'Indiana', + 'Iowa', + 'Kansas', + 'Kentucky', + 'Louisiana', + 'Maine', + 'Maryland', + 'Massachusetts', + 'Michigan', + 'Minnesota', + 'Mississippi', + 'Missouri', + 'Montana', + 'Nebraska', + 'Nevada', + 'New Hampshire', + 'New Jersey', + 'New Mexico', + 'New York', + 'North Carolina', + 'North Dakota', + 'Ohio', + 'Oklahoma', + 'Oregon', + 'Pennsylvania', + 'Rhode Island', + 'South Carolina', + 'South Dakota', + 'Tennessee', + 'Texas', + 'Utah', + 'Vermont', + 'Virginia', + 'Washington', + 'West Virginia', + 'Wisconsin', + 'Wyoming', +]; diff --git a/drizzle-seed/src/datasets/streetSuffix.ts b/drizzle-seed/src/datasets/streetSuffix.ts new file mode 100644 index 000000000..e9b20c392 --- /dev/null +++ b/drizzle-seed/src/datasets/streetSuffix.ts @@ -0,0 +1,200 @@ +/** + * The original data was taken from the сopycat library: https://github.com/supabase-community/copycat/blob/main/src/locales/en/address/street_suffix.ts + */ +export default [ + 'Alley', + 'Avenue', + 'Branch', + 'Bridge', + 'Brook', + 'Brooks', + 'Burg', + 'Burgs', + 'Bypass', + 'Camp', + 'Canyon', + 'Cape', + 'Causeway', + 'Center', + 'Centers', + 'Circle', + 'Circles', + 'Cliff', + 'Cliffs', + 'Club', + 'Common', + 'Corner', + 'Corners', + 'Course', + 'Court', + 'Courts', + 'Cove', + 'Coves', + 'Creek', + 'Crescent', + 'Crest', + 'Crossing', + 'Crossroad', + 'Curve', + 'Dale', + 'Dam', + 'Divide', + 'Drive', + 'Drives', + 'Estate', + 'Estates', + 'Expressway', + 'Extension', + 'Extensions', + 'Fall', + 'Falls', + 'Ferry', + 'Field', + 'Fields', + 'Flat', + 'Flats', + 'Ford', + 'Fords', + 'Forest', + 'Forge', + 'Forges', + 'Fork', + 'Forks', + 'Fort', + 'Freeway', + 'Garden', + 'Gardens', + 'Gateway', + 'Glen', + 'Glens', + 'Green', + 'Greens', + 'Grove', + 'Groves', + 'Harbor', + 'Harbors', + 'Haven', + 'Heights', + 'Highway', + 'Hill', + 'Hills', + 'Hollow', + 'Inlet', + 'Island', + 'Islands', + 'Isle', + 'Junction', + 'Junctions', + 'Key', + 'Keys', + 'Knoll', + 'Knolls', + 'Lake', + 'Lakes', + 'Land', + 'Landing', + 'Lane', + 'Light', + 'Lights', + 'Loaf', + 'Lock', + 'Locks', + 'Lodge', + 'Loop', + 'Mall', + 'Manor', + 'Manors', + 'Meadow', + 'Meadows', + 'Mews', + 'Mill', + 'Mills', + 'Mission', + 'Motorway', + 'Mount', + 'Mountain', + 'Mountains', + 'Neck', + 'Orchard', + 'Oval', + 'Overpass', + 'Park', + 'Parks', + 'Parkway', + 'Parkways', + 'Pass', + 'Passage', + 'Path', + 'Pike', + 'Pine', + 'Pines', + 'Place', + 'Plain', + 'Plains', + 'Plaza', + 'Point', + 'Points', + 'Port', + 'Ports', + 'Prairie', + 'Radial', + 'Ramp', + 'Ranch', + 'Rapid', + 'Rapids', + 'Rest', + 'Ridge', + 'Ridges', + 'River', + 'Road', + 'Roads', + 'Route', + 'Row', + 'Rue', + 'Run', + 'Shoal', + 'Shoals', + 'Shore', + 'Shores', + 'Skyway', + 'Spring', + 'Springs', + 'Spur', + 'Spurs', + 'Square', + 'Squares', + 'Station', + 'Stravenue', + 'Stream', + 'Street', + 'Streets', + 'Summit', + 'Terrace', + 'Throughway', + 'Trace', + 'Track', + 'Trafficway', + 'Trail', + 'Tunnel', + 'Turnpike', + 'Underpass', + 'Union', + 'Unions', + 'Valley', + 'Valleys', + 'Via', + 'Viaduct', + 'View', + 'Views', + 'Village', + 'Villages', + 'Ville', + 'Vista', + 'Walk', + 'Walks', + 'Wall', + 'Way', + 'Ways', + 'Well', + 'Wells', +]; diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts new file mode 100644 index 000000000..47c9f408e --- /dev/null +++ b/drizzle-seed/src/index.ts @@ -0,0 +1,873 @@ +import { entityKind, getTableName, is, sql } from 'drizzle-orm'; + +import type { MySqlColumn, MySqlSchema } from 'drizzle-orm/mysql-core'; +import { getTableConfig as getMysqlTableConfig, MySqlDatabase, MySqlTable } from 'drizzle-orm/mysql-core'; + +import type { PgColumn, PgSchema } from 'drizzle-orm/pg-core'; +import { getTableConfig as getPgTableConfig, PgDatabase, PgTable } from 'drizzle-orm/pg-core'; + +import type { SQLiteColumn } from 'drizzle-orm/sqlite-core'; +import { BaseSQLiteDatabase, getTableConfig as getSqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; + +import type { AbstractGenerator } from './services/GeneratorsWrappers.ts'; +import { generatorsFuncs } from './services/GeneratorsWrappers.ts'; +import seedService from './services/SeedService.ts'; +import type { DrizzleStudioObjectType, DrizzleStudioRelationType } from './types/drizzleStudio.ts'; +import type { RefinementsType } from './types/seedService.ts'; +import type { Relation, Table } from './types/tables.ts'; + +type InferCallbackType< + DB extends + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + SCHEMA extends { + [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable; + }, +> = DB extends PgDatabase ? SCHEMA extends { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable; + } ? { + // iterates through schema fields. example -> schema: {"tableName": PgTable} + [ + table in keyof SCHEMA as SCHEMA[table] extends PgTable ? table + : never + ]?: { + count?: number; + columns?: { + // iterates through table fields. example -> table: {"columnName": PgColumn} + [ + column in keyof SCHEMA[table] as SCHEMA[table][column] extends PgColumn ? column + : never + ]?: AbstractGenerator; + }; + with?: { + [ + refTable in keyof SCHEMA as SCHEMA[refTable] extends PgTable ? refTable + : never + ]?: + | number + | { weight: number; count: number | number[] }[]; + }; + }; + } + : {} + : DB extends MySqlDatabase ? SCHEMA extends { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable; + } ? { + // iterates through schema fields. example -> schema: {"tableName": MySqlTable} + [ + table in keyof SCHEMA as SCHEMA[table] extends MySqlTable ? table + : never + ]?: { + count?: number; + columns?: { + // iterates through table fields. example -> table: {"columnName": MySqlColumn} + [ + column in keyof SCHEMA[table] as SCHEMA[table][column] extends MySqlColumn ? column + : never + ]?: AbstractGenerator; + }; + with?: { + [ + refTable in keyof SCHEMA as SCHEMA[refTable] extends MySqlTable ? refTable + : never + ]?: + | number + | { weight: number; count: number | number[] }[]; + }; + }; + } + : {} + : DB extends BaseSQLiteDatabase ? SCHEMA extends { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable; + } ? { + // iterates through schema fields. example -> schema: {"tableName": SQLiteTable} + [ + table in keyof SCHEMA as SCHEMA[table] extends SQLiteTable ? table + : never + ]?: { + count?: number; + columns?: { + // iterates through table fields. example -> table: {"columnName": SQLiteColumn} + [ + column in keyof SCHEMA[table] as SCHEMA[table][column] extends SQLiteColumn ? column + : never + ]?: AbstractGenerator; + }; + with?: { + [ + refTable in keyof SCHEMA as SCHEMA[refTable] extends SQLiteTable ? refTable + : never + ]?: + | number + | { weight: number; count: number | number[] }[]; + }; + }; + } + : {} + : {}; + +class SeedPromise< + DB extends + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + SCHEMA extends { + [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable; + }, +> implements Promise { + static readonly [entityKind]: string = 'SeedPromise'; + + [Symbol.toStringTag] = 'SeedPromise'; + + constructor( + private db: DB, + private schema: SCHEMA, + private options?: { count?: number; seed?: number }, + ) {} + + then( + onfulfilled?: + | ((value: void) => TResult1 | PromiseLike) + | null + | undefined, + onrejected?: + | ((reason: any) => TResult2 | PromiseLike) + | null + | undefined, + ): Promise { + return seedFunc(this.db, this.schema, this.options).then( + onfulfilled, + onrejected, + ); + } + + catch( + onrejected?: + | ((reason: any) => TResult | PromiseLike) + | null + | undefined, + ): Promise { + return this.then(undefined, onrejected); + } + + finally(onfinally?: (() => void) | null | undefined): Promise { + return this.then( + (value) => { + onfinally?.(); + return value; + }, + (reason) => { + onfinally?.(); + throw reason; + }, + ); + } + + async refine( + callback: (funcs: typeof generatorsFuncs) => InferCallbackType, + ): Promise { + const refinements = callback(generatorsFuncs) as RefinementsType; + + await seedFunc(this.db, this.schema, this.options, refinements); + } +} + +export function getGeneratorsFunctions() { + return generatorsFuncs; +} + +export async function seedForDrizzleStudio( + { sqlDialect, drizzleStudioObject, drizzleStudioRelations, schemasRefinements, options }: { + sqlDialect: 'postgresql' | 'mysql' | 'sqlite'; + drizzleStudioObject: DrizzleStudioObjectType; + drizzleStudioRelations: DrizzleStudioRelationType[]; + schemasRefinements?: { [schemaName: string]: RefinementsType }; + options?: { count?: number; seed?: number }; + }, +) { + const generatedSchemas: { + [schemaName: string]: { + tables: { + tableName: string; + rows: { + [columnName: string]: string | number | boolean | undefined; + }[]; + }[]; + }; + } = {}; + + let tables: Table[], relations: Relation[], refinements: RefinementsType | undefined; + drizzleStudioRelations = drizzleStudioRelations.filter((rel) => rel.type === 'one'); + for (const [schemaName, { tables: drizzleStudioTables }] of Object.entries(drizzleStudioObject)) { + tables = []; + for (const [tableName, table] of Object.entries(drizzleStudioTables)) { + const drizzleStudioColumns = Object.values(table.columns); + const columns = drizzleStudioColumns.map((col) => ({ + name: col.name, + dataType: 'string', + columnType: col.type, + default: col.default, + hasDefault: col.default === undefined ? false : true, + isUnique: col.isUnique === undefined ? false : col.isUnique, + notNull: col.notNull, + })); + tables.push( + { + name: tableName, + columns, + primaryKeys: drizzleStudioColumns.filter((col) => col.primaryKey === true).map((col) => col.name), + }, + ); + } + + relations = drizzleStudioRelations.filter((rel) => rel.schema === schemaName && rel.refSchema === schemaName); + + refinements = schemasRefinements !== undefined && schemasRefinements[schemaName] !== undefined + ? schemasRefinements[schemaName] + : undefined; + + const generatedTablesGenerators = seedService.generatePossibleGenerators( + sqlDialect, + tables, + relations, + refinements, + options, + ); + + const generatedTables = await seedService.generateTablesValues( + relations, + generatedTablesGenerators, + undefined, + undefined, + { ...options, preserveData: true, insertDataInDb: false }, + ); + + generatedSchemas[schemaName] = { tables: generatedTables }; + } + + return generatedSchemas; +} + +/** + * @param db - database you would like to seed. + * @param schema - object that contains all your database tables you would like to seed. + * @param options - object that contains properties `count` and `seed`: + * + * `count` - number of rows you want to generate. + * + * `seed` - a number that controls the state of generated data. (if the `seed` number is the same and nothing is changed in the seeding script, generated data will remain the same each time you seed database) + * + * @returns SeedPromise - a class object that has a refine method that is used to change generators for columns. + * + * @example + * ```ts + * // base seeding + * await seed(db, schema); + * + * // seeding with count specified + * await seed(db, schema, { count: 100000 }); + * + * // seeding with count and seed specified + * await seed(db, schema, { count: 100000, seed: 1 }); + * + * //seeding using refine + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * name: funcs.firstName({ isUnique: true }), + * email: funcs.email(), + * phone: funcs.phoneNumber({ template: "+380 99 ###-##-##" }), + * password: funcs.string({ isUnique: true }), + * }, + * count: 100000, + * }, + * posts: { + * columns: { + * title: funcs.valuesFromArray({ + * values: ["Title1", "Title2", "Title3", "Title4", "Title5"], + * }), + * content: funcs.loremIpsum({ sentencesCount: 3 }), + * }, + * }, + * })); + * + * ``` + */ +export function seed< + DB extends + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + SCHEMA extends { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; + }, +>(db: DB, schema: SCHEMA, options?: { count?: number; seed?: number }) { + return new SeedPromise(db, schema, options); +} + +const seedFunc = async ( + db: PgDatabase | MySqlDatabase | BaseSQLiteDatabase, + schema: { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; + }, + options: { count?: number; seed?: number } = {}, + refinements?: RefinementsType, +) => { + if (is(db, PgDatabase)) { + const { pgSchema } = filterPgTables(schema); + + await seedPostgres(db, pgSchema, options, refinements); + } else if (is(db, MySqlDatabase)) { + const { mySqlSchema } = filterMySqlTables(schema); + + await seedMySql(db, mySqlSchema, options, refinements); + } else if (is(db, BaseSQLiteDatabase)) { + const { sqliteSchema } = filterSqliteTables(schema); + + await seedSqlite(db, sqliteSchema, options, refinements); + } else { + throw new Error('given db is not supported.'); + } +}; + +/** + * deletes all data from specified tables + * + * @param db - database you would like to reset. + * @param schema - object that contains all your database tables you would like to delete data from. + * + * `If db is a PgDatabase object`, we will execute sql query and delete data from your tables the following way: + * ```sql + * truncate tableName1, tableName2, ... cascade; + * ``` + * + * `If db is a MySqlDatabase object`, we will execute sql queries and delete data from your tables the following way: + * ```sql + * SET FOREIGN_KEY_CHECKS = 0; + * truncate tableName1; + * truncate tableName2; + * . + * . + * . + * + * SET FOREIGN_KEY_CHECKS = 1; + * ``` + * + * `If db is a BaseSQLiteDatabase object`, we will execute sql queries and delete data from your tables the following way: + * ```sql + * PRAGMA foreign_keys = OFF; + * delete from tableName1; + * delete from tableName2; + * . + * . + * . + * + * PRAGMA foreign_keys = ON; + * ``` + * + * @example + * ```ts + * await reset(db, schema); + * ``` + */ +export async function reset< + DB extends + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + SCHEMA extends { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; + }, +>(db: DB, schema: SCHEMA) { + if (is(db, PgDatabase)) { + const { pgSchema } = filterPgTables(schema); + + if (Object.entries(pgSchema).length > 0) { + await resetPostgres(db, pgSchema); + } + } else if (is(db, MySqlDatabase)) { + const { mySqlSchema } = filterMySqlTables(schema); + + if (Object.entries(mySqlSchema).length > 0) { + await resetMySql(db, mySqlSchema); + } + } else if (is(db, BaseSQLiteDatabase)) { + const { sqliteSchema } = filterSqliteTables(schema); + + if (Object.entries(sqliteSchema).length > 0) { + await resetSqlite(db, sqliteSchema); + } + } else { + throw new Error('given db is not supported.'); + } +} + +// Postgres----------------------------------------------------------------------------------------------------------- +const resetPostgres = async ( + db: PgDatabase, + schema: { [key: string]: PgTable }, +) => { + const tablesToTruncate = Object.entries(schema).map(([_, table]) => { + const config = getPgTableConfig(table); + config.schema = config.schema === undefined ? 'public' : config.schema; + + return `${config.schema}.${config.name}`; + }); + + await db.execute(sql.raw(`truncate ${tablesToTruncate.join(',')} cascade;`)); +}; + +const filterPgTables = (schema: { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; +}) => { + const pgSchema = Object.fromEntries( + Object.entries(schema).filter((keyValue): keyValue is [string, PgTable] => is(keyValue[1], PgTable)), + ); + + return { pgSchema }; +}; + +const seedPostgres = async ( + db: PgDatabase, + schema: { [key: string]: PgTable }, + options: { count?: number; seed?: number } = {}, + refinements?: RefinementsType, +) => { + const { tables, relations } = getPostgresInfo(schema); + const generatedTablesGenerators = seedService.generatePossibleGenerators( + 'postgresql', + tables, + relations, + refinements, + options, + ); + + await seedService.generateTablesValues( + relations, + generatedTablesGenerators, + db, + schema, + options, + ); +}; + +const getPostgresInfo = (schema: { [key: string]: PgTable }) => { + let tableConfig: ReturnType; + let dbToTsColumnNamesMap: { [key: string]: string }; + const dbToTsTableNamesMap: { [key: string]: string } = Object.fromEntries( + Object.entries(schema).map(([key, value]) => [getTableName(value), key]), + ); + + const tables: Table[] = []; + const relations: Relation[] = []; + const dbToTsColumnNamesMapGlobal: { + [tableName: string]: { [dbColumnName: string]: string }; + } = {}; + + const getDbToTsColumnNamesMap = (table: PgTable) => { + let dbToTsColumnNamesMap: { [dbColName: string]: string } = {}; + + const tableName = getTableName(table); + if (Object.hasOwn(dbToTsColumnNamesMapGlobal, tableName)) { + dbToTsColumnNamesMap = dbToTsColumnNamesMapGlobal[tableName]!; + return dbToTsColumnNamesMap; + } + + const tableConfig = getPgTableConfig(table); + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + dbToTsColumnNamesMapGlobal[tableName] = dbToTsColumnNamesMap; + + return dbToTsColumnNamesMap; + }; + + for (const table of Object.values(schema)) { + tableConfig = getPgTableConfig(table); + + dbToTsColumnNamesMap = {}; + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + + relations.push( + ...tableConfig.foreignKeys.map((fk) => { + const table = dbToTsTableNamesMap[tableConfig.name] as string; + const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; + + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( + fk.reference().foreignTable, + ); + + return { + table, + columns: fk + .reference() + .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), + refTable, + refColumns: fk + .reference() + .foreignColumns.map( + (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, + ), + }; + }), + ); + + tables.push({ + name: dbToTsTableNamesMap[tableConfig.name] as string, + columns: tableConfig.columns.map((column) => ({ + name: dbToTsColumnNamesMap[column.name] as string, + columnType: column.columnType.replace('Pg', '').toLowerCase(), + dataType: column.dataType, + hasDefault: column.hasDefault, + default: column.default, + enumValues: column.enumValues, + isUnique: column.isUnique, + notNull: column.notNull, + generatedIdentityType: column.generatedIdentity?.type, + })), + primaryKeys: tableConfig.columns + .filter((column) => column.primary) + .map((column) => dbToTsColumnNamesMap[column.name] as string), + }); + } + + return { tables, relations }; +}; + +// MySql----------------------------------------------------------------------------------------------------- +const resetMySql = async ( + db: MySqlDatabase, + schema: { [key: string]: MySqlTable }, +) => { + const tablesToTruncate = Object.entries(schema).map(([_tsTableName, table]) => { + const dbTableName = getTableName(table); + return dbTableName; + }); + + await db.execute(sql.raw('SET FOREIGN_KEY_CHECKS = 0;')); + + for (const tableName of tablesToTruncate) { + const sqlQuery = `truncate \`${tableName}\`;`; + await db.execute(sql.raw(sqlQuery)); + } + + await db.execute(sql.raw('SET FOREIGN_KEY_CHECKS = 1;')); +}; + +const filterMySqlTables = (schema: { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; +}) => { + const mySqlSchema = Object.fromEntries( + Object.entries(schema).filter( + (keyValue): keyValue is [string, MySqlTable] => is(keyValue[1], MySqlTable), + ), + ); + + return { mySqlSchema }; +}; + +const seedMySql = async ( + db: MySqlDatabase, + schema: { [key: string]: MySqlTable }, + options: { count?: number; seed?: number } = {}, + refinements?: RefinementsType, +) => { + const { tables, relations } = getMySqlInfo(schema); + + const generatedTablesGenerators = seedService.generatePossibleGenerators( + 'mysql', + tables, + relations, + refinements, + options, + ); + + await seedService.generateTablesValues( + relations, + generatedTablesGenerators, + db, + schema, + options, + ); +}; + +const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { + let tableConfig: ReturnType; + let dbToTsColumnNamesMap: { [key: string]: string }; + + const dbToTsTableNamesMap: { [key: string]: string } = Object.fromEntries( + Object.entries(schema).map(([key, value]) => [getTableName(value), key]), + ); + + const tables: Table[] = []; + const relations: Relation[] = []; + const dbToTsColumnNamesMapGlobal: { + [tableName: string]: { [dbColumnName: string]: string }; + } = {}; + + const getDbToTsColumnNamesMap = (table: MySqlTable) => { + let dbToTsColumnNamesMap: { [dbColName: string]: string } = {}; + + const tableName = getTableName(table); + if (Object.hasOwn(dbToTsColumnNamesMapGlobal, tableName)) { + dbToTsColumnNamesMap = dbToTsColumnNamesMapGlobal[tableName]!; + return dbToTsColumnNamesMap; + } + + const tableConfig = getMysqlTableConfig(table); + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + dbToTsColumnNamesMapGlobal[tableName] = dbToTsColumnNamesMap; + + return dbToTsColumnNamesMap; + }; + + for (const table of Object.values(schema)) { + tableConfig = getMysqlTableConfig(table); + + dbToTsColumnNamesMap = {}; + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + + relations.push( + ...tableConfig.foreignKeys.map((fk) => { + const table = dbToTsTableNamesMap[tableConfig.name] as string; + const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( + fk.reference().foreignTable, + ); + + return { + table, + columns: fk + .reference() + .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), + refTable, + refColumns: fk + .reference() + .foreignColumns.map( + (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, + ), + }; + }), + ); + + tables.push({ + name: dbToTsTableNamesMap[tableConfig.name] as string, + columns: tableConfig.columns.map((column) => ({ + name: dbToTsColumnNamesMap[column.name] as string, + columnType: column.columnType.replace('MySql', '').toLowerCase(), + dataType: column.dataType, + hasDefault: column.hasDefault, + default: column.default, + enumValues: column.enumValues, + isUnique: column.isUnique, + notNull: column.notNull, + })), + primaryKeys: tableConfig.columns + .filter((column) => column.primary) + .map((column) => dbToTsColumnNamesMap[column.name] as string), + }); + } + + return { tables, relations }; +}; + +// Sqlite------------------------------------------------------------------------------------------------------------------------ +const resetSqlite = async ( + db: BaseSQLiteDatabase, + schema: { [key: string]: SQLiteTable }, +) => { + const tablesToTruncate = Object.entries(schema).map(([_tsTableName, table]) => { + const dbTableName = getTableName(table); + return dbTableName; + }); + + await db.run(sql.raw('PRAGMA foreign_keys = OFF')); + + for (const tableName of tablesToTruncate) { + const sqlQuery = `delete from \`${tableName}\`;`; + await db.run(sql.raw(sqlQuery)); + } + + await db.run(sql.raw('PRAGMA foreign_keys = ON')); +}; + +const filterSqliteTables = (schema: { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | any; +}) => { + const sqliteSchema = Object.fromEntries( + Object.entries(schema).filter( + (keyValue): keyValue is [string, SQLiteTable] => is(keyValue[1], SQLiteTable), + ), + ); + + return { sqliteSchema }; +}; + +const seedSqlite = async ( + db: BaseSQLiteDatabase, + schema: { [key: string]: SQLiteTable }, + options: { count?: number; seed?: number } = {}, + refinements?: RefinementsType, +) => { + const { tables, relations } = getSqliteInfo(schema); + + const generatedTablesGenerators = seedService.generatePossibleGenerators( + 'sqlite', + tables, + relations, + refinements, + options, + ); + + await seedService.generateTablesValues( + relations, + generatedTablesGenerators, + db, + schema, + options, + ); +}; + +const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { + let tableConfig: ReturnType; + let dbToTsColumnNamesMap: { [key: string]: string }; + const dbToTsTableNamesMap: { [key: string]: string } = Object.fromEntries( + Object.entries(schema).map(([key, value]) => [getTableName(value), key]), + ); + + const tables: Table[] = []; + const relations: Relation[] = []; + const dbToTsColumnNamesMapGlobal: { + [tableName: string]: { [dbColumnName: string]: string }; + } = {}; + + const getDbToTsColumnNamesMap = (table: SQLiteTable) => { + let dbToTsColumnNamesMap: { [dbColName: string]: string } = {}; + + const tableName = getTableName(table); + if (Object.hasOwn(dbToTsColumnNamesMapGlobal, tableName)) { + dbToTsColumnNamesMap = dbToTsColumnNamesMapGlobal[tableName]!; + return dbToTsColumnNamesMap; + } + + const tableConfig = getSqliteTableConfig(table); + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + dbToTsColumnNamesMapGlobal[tableName] = dbToTsColumnNamesMap; + + return dbToTsColumnNamesMap; + }; + + for (const table of Object.values(schema)) { + tableConfig = getSqliteTableConfig(table); + + dbToTsColumnNamesMap = {}; + for (const [tsCol, col] of Object.entries(tableConfig.columns[0]!.table)) { + dbToTsColumnNamesMap[col.name] = tsCol; + } + + relations.push( + ...tableConfig.foreignKeys.map((fk) => { + const table = dbToTsTableNamesMap[tableConfig.name] as string; + const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( + fk.reference().foreignTable, + ); + + return { + table, + columns: fk + .reference() + .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), + refTable, + refColumns: fk + .reference() + .foreignColumns.map( + (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, + ), + }; + }), + ); + + tables.push({ + name: dbToTsTableNamesMap[tableConfig.name] as string, + columns: tableConfig.columns.map((column) => ({ + name: dbToTsColumnNamesMap[column.name] as string, + columnType: column.columnType.replace('SQLite', '').toLowerCase(), + dataType: column.dataType, + hasDefault: column.hasDefault, + default: column.default, + enumValues: column.enumValues, + isUnique: column.isUnique, + notNull: column.notNull, + })), + primaryKeys: tableConfig.columns + .filter((column) => column.primary) + .map((column) => dbToTsColumnNamesMap[column.name] as string), + }); + } + + return { tables, relations }; +}; + +export { default as firstNames } from './datasets/firstNames.ts'; +export { default as lastNames } from './datasets/lastNames.ts'; diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts new file mode 100644 index 000000000..266c0277b --- /dev/null +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -0,0 +1,3405 @@ +import { entityKind } from 'drizzle-orm'; +import prand from 'pure-rand'; +import adjectives from '../datasets/adjectives.ts'; +import cityNames from '../datasets/cityNames.ts'; +import companyNameSuffixes from '../datasets/companyNameSuffixes.ts'; +import countries from '../datasets/countries.ts'; +import emailDomains from '../datasets/emailDomains.ts'; +import firstNames from '../datasets/firstNames.ts'; +import jobsTitles from '../datasets/jobsTitles.ts'; +import lastNames from '../datasets/lastNames.ts'; +import loremIpsumSentences from '../datasets/loremIpsumSentences.ts'; +import phonesInfo from '../datasets/phonesInfo.ts'; +import states from '../datasets/states.ts'; +import streetSuffix from '../datasets/streetSuffix.ts'; +import { fastCartesianProduct, fillTemplate, getWeightedIndices } from './utils.ts'; + +export abstract class AbstractGenerator { + static readonly [entityKind]: string = 'AbstractGenerator'; + + public isUnique = false; + public notNull = false; + public uniqueVersionOfGen?: new(params: T) => AbstractGenerator; + public dataType?: string; + public timeSpent?: number; + + constructor(public params: T) {} + + abstract init(params: { count: number | { weight: number; count: number | number[] }[]; seed: number }): void; + + abstract generate(params: { i: number }): number | string | boolean | unknown | undefined | void; +} + +function createGenerator, T>( + generatorConstructor: new(params: T) => GeneratorType, +) { + return ( + ...args: GeneratorType extends GenerateValuesFromArray | GenerateDefault | WeightedRandomGenerator ? [T] + : ([] | [T]) + ): GeneratorType => { + let params = args[0]; + if (params === undefined) params = {} as T; + return new generatorConstructor(params); + }; +} + +// Generators Classes ----------------------------------------------------------------------------------------------------------------------- +export class GenerateWeightedCount extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'GenerateWeightedCount'; + + private state: { + rng: prand.RandomGenerator; + weightedIndices: number[]; + weightedCount: { weight: number; count: number | number[] }[]; + } | undefined; + + init({ seed, count }: { count: { weight: number; count: number | number[] }[]; seed: number }) { + const rng = prand.xoroshiro128plus(seed); + const weightedIndices = getWeightedIndices(count.map((val) => val.weight)); + this.state = { rng, weightedIndices, weightedCount: count }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + // logic for this generator + let idx: number; + const weightedCount = this.state.weightedCount; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.weightedIndices.length - 1, this.state.rng); + const objIdx = this.state.weightedIndices[idx] as number; + + if (typeof weightedCount[objIdx]!.count === 'number') { + return weightedCount[objIdx]!.count as number; + } else { + // typeof weightedCount[objIdx]!.count === 'object' // number[] + const possCounts = weightedCount[objIdx]!.count as number[]; + [idx, this.state.rng] = prand.uniformIntDistribution(0, possCounts.length - 1, this.state.rng); + return possCounts[idx]!; + } + } +} + +export class HollowGenerator extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'HollowGenerator'; + + init() {} + + generate() {} +} + +export class GenerateDefault extends AbstractGenerator<{ + defaultValue: unknown; +}> { + static override readonly [entityKind]: string = 'GenerateDefault'; + + init() {} + + generate() { + return this.params.defaultValue; + } +} + +export class GenerateValuesFromArray extends AbstractGenerator< + { + values: + | (number | string | boolean | undefined)[] + | { weight: number; values: (number | string | boolean | undefined)[] }[]; + isUnique?: boolean; + } +> { + static override readonly [entityKind]: string = 'GenerateValuesFromArray'; + + public weightedCountSeed: number | undefined = undefined; + public maxRepeatedValuesCount?: number | { weight: number; count: number | number[] }[] = undefined; + private state: { + rng: prand.RandomGenerator; + values: + | (number | string | boolean | undefined)[] + | { weight: number; values: (number | string | boolean | undefined)[] }[]; + genIndicesObj: GenerateUniqueInt | undefined; + genIndicesObjList: GenerateUniqueInt[] | undefined; + valuesWeightedIndices: number[] | undefined; + genMaxRepeatedValuesCount: GenerateDefault | GenerateWeightedCount | undefined; + } | undefined; + public override timeSpent: number = 0; + + checks({ count }: { count: number }) { + const { values } = this.params; + const { maxRepeatedValuesCount, notNull, isUnique } = this; + if (values.length === 0) { + throw new Error('values length equals zero.'); + } + + if ( + typeof values[0] === 'object' + && !(values as { weight: number; values: any[] }[]).every((val) => val.values.length !== 0) + ) { + throw new Error('one of weighted values length equals zero.'); + } + + if ( + maxRepeatedValuesCount !== undefined && ( + (typeof maxRepeatedValuesCount === 'number' && maxRepeatedValuesCount <= 0) + || (typeof maxRepeatedValuesCount === 'object' && !maxRepeatedValuesCount + .every((obj) => + (typeof obj.count) === 'number' + ? (obj.count as number) > 0 + : (obj.count as number[]).every((count) => count > 0) + )) + ) + ) { + throw new Error('maxRepeatedValuesCount should be greater than zero.'); + } + + let allValuesCount = values.length; + if (typeof values[0] === 'object') { + allValuesCount = (values as { values: any[] }[]).reduce((acc, currVal) => acc + currVal.values.length, 0); + } + + if ( + notNull === true + && maxRepeatedValuesCount !== undefined + && ( + (typeof values[0] !== 'object' && typeof maxRepeatedValuesCount === 'number' + && maxRepeatedValuesCount * values.length < count) + || (typeof values[0] === 'object' && typeof maxRepeatedValuesCount === 'number' + && maxRepeatedValuesCount * allValuesCount < count) + ) + ) { + throw new Error("(maxRepeatedValuesCount * values.length) < count. can't fill notNull column with null values."); + } + + if ( + isUnique === true && maxRepeatedValuesCount !== undefined && ( + (typeof maxRepeatedValuesCount === 'number' && maxRepeatedValuesCount > 1) + || (typeof maxRepeatedValuesCount === 'object' && !maxRepeatedValuesCount + .every((obj) => + (typeof obj.count) === 'number' + ? obj.count === 1 + : (obj.count as number[]).every((count) => count === 1) + )) + ) + ) { + throw new Error("maxRepeatedValuesCount can't be greater than 1 if column is unique."); + } + + if ( + isUnique === true && notNull === true && ( + (typeof values[0] !== 'object' && values.length < count) + || (typeof values[0] === 'object' && allValuesCount < count) + ) + ) { + // console.log(maxRepeatedValuesCount, values.length, allValuesCount, count) + throw new Error('there are no enough values to fill unique column.'); + } + } + + init({ count, seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + this.checks({ count }); + + let { maxRepeatedValuesCount } = this; + const { params, isUnique, notNull, weightedCountSeed } = this; + + const values = params.values; + + let valuesWeightedIndices; + if (typeof values[0] === 'object') { + valuesWeightedIndices = getWeightedIndices((values as { weight: number }[]).map((val) => val.weight)); + if (isUnique === true && notNull === true) { + let idx: number, valueIdx: number, rng = prand.xoroshiro128plus(seed); + const indicesCounter: { [key: number]: number } = {}; + for (let i = 0; i < count; i++) { + [idx, rng] = prand.uniformIntDistribution(0, valuesWeightedIndices.length - 1, rng); + valueIdx = valuesWeightedIndices[idx]!; + if (!Object.hasOwn(indicesCounter, valueIdx)) indicesCounter[valueIdx] = 0; + indicesCounter[valueIdx]! += 1; + } + + for (const [idx, value] of values.entries()) { + if ((value as { values: (number | string | boolean | undefined)[] }).values.length < indicesCounter[idx]!) { + throw new Error( + 'weighted values arrays is too small to generate values with specified probability for unique not null column.' + + `it's planned to generate: ${ + Object.entries(indicesCounter).map(([idx, count]) => { + return `${count} values with probability ${(values as { weight: number }[])[Number(idx)]?.weight}`; + }).join(',') + }`, + ); + } + } + } + } + if (isUnique === true && maxRepeatedValuesCount === undefined) { + maxRepeatedValuesCount = 1; + } + let genMaxRepeatedValuesCount: GenerateDefault | GenerateWeightedCount | undefined; + if (typeof maxRepeatedValuesCount === 'number') { + genMaxRepeatedValuesCount = new GenerateDefault({ defaultValue: maxRepeatedValuesCount }); + } else if (typeof maxRepeatedValuesCount === 'object') { + genMaxRepeatedValuesCount = new GenerateWeightedCount({}); + (genMaxRepeatedValuesCount as GenerateWeightedCount).init( + { + count: maxRepeatedValuesCount, + seed: weightedCountSeed === undefined ? seed : weightedCountSeed, + }, + ); + } + + let genIndicesObj: GenerateUniqueInt | undefined; + let genIndicesObjList: GenerateUniqueInt[] | undefined; + + if (maxRepeatedValuesCount !== undefined) { + if (typeof values[0] !== 'object') { + genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: values.length - 1 }); + genIndicesObj.genMaxRepeatedValuesCount = genMaxRepeatedValuesCount; + genIndicesObj.skipCheck = true; + genIndicesObj.init({ count, seed }); + } else if (typeof values[0] === 'object') { + genIndicesObjList = []; + for (const obj of values as { weight: number; values: (number | string | boolean | undefined)[] }[]) { + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: obj.values.length - 1 }); + genIndicesObj.genMaxRepeatedValuesCount = genMaxRepeatedValuesCount; + genIndicesObj.skipCheck = true; + genIndicesObj.init({ count, seed }); + genIndicesObjList.push(genIndicesObj); + } + } + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng, values, valuesWeightedIndices, genMaxRepeatedValuesCount, genIndicesObj, genIndicesObjList }; + } + + generate() { + const t0 = new Date(); + + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number, + value: string | number | boolean | undefined; + let valueIdx: number; + + if (this.state.valuesWeightedIndices === undefined) { + if (this.state.genIndicesObj === undefined) { + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.values.length - 1, this.state.rng); + } else { + idx = this.state.genIndicesObj.generate() as number; + } + + value = (this.state.values as (number | string | boolean | undefined)[])[idx]; + } else { + // weighted values + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + this.state.valuesWeightedIndices.length - 1, + this.state.rng, + ); + valueIdx = this.state.valuesWeightedIndices[idx] as number; + const currValues = + (this.state.values![valueIdx] as { weight: number; values: (number | string | boolean | undefined)[] }).values; + if (this.state.genIndicesObjList === undefined) { + // isUnique !== true + [idx, this.state.rng] = prand.uniformIntDistribution(0, currValues.length - 1, this.state.rng); + } else { + // isUnique === true + idx = this.state.genIndicesObjList[valueIdx]!.generate() as number; + } + value = currValues[idx]; + } + + this.timeSpent += (Date.now() - t0.getTime()) / 1000; + return value; + } +} + +export class GenerateSelfRelationsValuesFromArray extends AbstractGenerator<{ values: (number | string | boolean)[] }> { + static override readonly [entityKind]: string = 'GenerateSelfRelationsValuesFromArray'; + + private state: { + rng: prand.RandomGenerator; + firstValuesCount: number; + firstValues: (string | number | boolean)[]; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + let rng = prand.xoroshiro128plus(seed); + + // generate 15-40 % values with the same value as reference column + let percent = 30; + [percent, rng] = prand.uniformIntDistribution(20, 40, rng); + const firstValuesCount = Math.floor((percent / 100) * count), firstValues: (string | number | boolean)[] = []; + + this.state = { rng, firstValuesCount, firstValues }; + } + + generate({ i }: { i: number }) { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const { values } = this.params; + let idx: number; + + if (i < this.state.firstValuesCount) { + this.state.firstValues.push(values[i]!); + return values[i]; + } else { + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.firstValues.length - 1, this.state.rng); + return this.state.firstValues[idx]; + } + } +} + +export class GenerateIntPrimaryKey extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'GenerateIntPrimaryKey'; + + public maxValue?: number | bigint; + + init({ count }: { count: number; seed: number }) { + if (this.maxValue !== undefined && count > this.maxValue) { + throw new Error('count exceeds max number for this column type.'); + } + } + + generate({ i }: { i: number }) { + if (this.dataType === 'bigint') { + return BigInt(i + 1); + } + + return i + 1; + } +} + +export class GenerateNumber extends AbstractGenerator< + { + minValue?: number; + maxValue?: number; + precision?: number; + isUnique?: boolean; + } | undefined +> { + static override readonly [entityKind]: string = 'GenerateNumber'; + + private state: { + rng: prand.RandomGenerator; + minValue: number; + maxValue: number; + precision: number; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueNumber; + + init({ seed }: { seed: number }) { + if (this.params === undefined) this.params = {}; + + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + let { minValue, maxValue, precision } = this.params; + if (precision === undefined) { + precision = 100; + } + + if (maxValue === undefined) { + maxValue = precision * 1000; + } else { + maxValue *= precision; + } + + if (minValue === undefined) { + minValue = -maxValue; + } else { + minValue *= precision; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng, minValue, maxValue, precision }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let value: number; + + [value, this.state.rng] = prand.uniformIntDistribution(this.state.minValue, this.state.maxValue, this.state.rng); + return value / this.state.precision; + } +} + +export class GenerateUniqueNumber extends AbstractGenerator< + { + minValue?: number; + maxValue?: number; + precision?: number; + isUnique?: boolean; + } | undefined +> { + static override readonly [entityKind]: string = 'GenerateUniqueNumber'; + + private state: { + genUniqueIntObj: GenerateUniqueInt; + minValue: number; + maxValue: number; + precision: number; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + if (this.params === undefined) this.params = {}; + let { minValue, maxValue, precision } = this.params; + + if (precision === undefined) { + precision = 100; + } + + if (maxValue === undefined) { + maxValue = count * precision; + } else { + maxValue *= precision; + } + + if (minValue === undefined) { + minValue = -maxValue; + } else { + minValue *= precision; + } + + const genUniqueIntObj = new GenerateUniqueInt({ minValue, maxValue }); + genUniqueIntObj.init({ count, seed }); + + this.state = { genUniqueIntObj, minValue, maxValue, precision }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const value = this.state.genUniqueIntObj.generate() as number / this.state.precision; + + return value; + } +} + +export class GenerateInt extends AbstractGenerator<{ + minValue?: number | bigint; + maxValue?: number | bigint; + isUnique?: boolean; +}> { + static override readonly [entityKind]: string = 'GenerateInt'; + + private state: { + rng: prand.RandomGenerator; + minValue: number | bigint; + maxValue: number | bigint; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueInt; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + let { minValue, maxValue } = this.params; + + if (maxValue === undefined) { + maxValue = 1000; + } + + if (minValue === undefined) { + minValue = -maxValue; + } + + if (typeof minValue === 'number' && typeof maxValue === 'number') { + minValue = minValue >= 0 ? Math.ceil(minValue) : Math.floor(minValue); + maxValue = maxValue >= 0 ? Math.floor(maxValue) : Math.ceil(maxValue); + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng, minValue, maxValue }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let value: number | bigint; + if (typeof this.state.minValue === 'bigint' && typeof this.state.maxValue === 'bigint') { + [value, this.state.rng] = prand.uniformBigIntDistribution( + this.state.minValue, + this.state.maxValue, + this.state.rng, + ); + } else { + [value, this.state.rng] = prand.uniformIntDistribution( + this.state.minValue as number, + this.state.maxValue as number, + this.state.rng, + ); + } + + if (this.dataType === 'string') { + return String(value); + } + + if (this.dataType === 'bigint') { + value = BigInt(value); + } + return value; + } +} + +export class GenerateUniqueInt extends AbstractGenerator<{ + minValue?: number | bigint; + maxValue?: number | bigint; + isUnique?: boolean; +}> { + static override readonly [entityKind]: string = 'GenerateUniqueInt'; + + public genMaxRepeatedValuesCount: GenerateDefault | GenerateWeightedCount | undefined; + public skipCheck?: boolean = false; + public state: { + rng: prand.RandomGenerator; + minValue: number | bigint; + maxValue: number | bigint; + intervals: (number | bigint)[][]; + integersCount: Map; + } | undefined; + public override isUnique = true; + public override timeSpent = 0; + + init({ count, seed }: { count: number; seed: number }) { + const rng = prand.xoroshiro128plus(seed); + let { minValue, maxValue } = this.params; + + if (maxValue === undefined) { + maxValue = count * 10; + } + if (minValue === undefined) { + minValue = -maxValue; + } + + const intervals = [[minValue, maxValue]]; + + const integersCount = new Map(); + + if (typeof minValue === 'bigint' && typeof maxValue === 'bigint') { + if (this.skipCheck === false && maxValue - minValue + BigInt(1) < count) { + throw new Error( + 'count exceeds max number of unique integers in given range(min, max), try to make range wider.', + ); + } + } else if (typeof minValue === 'number' && typeof maxValue === 'number') { + minValue = minValue >= 0 ? Math.ceil(minValue) : Math.floor(minValue); + maxValue = maxValue >= 0 ? Math.floor(maxValue) : Math.ceil(maxValue); + if (this.skipCheck === false && maxValue - minValue + 1 < count) { + throw new Error( + 'count exceeds max number of unique integers in given range(min, max), try to make range wider.', + ); + } + } else { + throw new Error( + 'minValue and maxValue should be the same type.', + ); + } + + this.state = { rng, minValue, maxValue, intervals, integersCount }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let intervalIdx: number, + numb: number | bigint | undefined; + + const intervalsToAdd: (number | bigint)[][] = []; + + if (this.state.intervals.length === 0) { + if (this.skipCheck === false) { + throw new RangeError( + 'generateUniqueInt: count exceeds max number of unique integers in given range(min, max), try to increase range.', + ); + } else { + return; + } + } + + [intervalIdx, this.state.rng] = prand.uniformIntDistribution( + 0, + this.state.intervals.length - 1, + this.state.rng, + ); + + const interval = this.state.intervals[intervalIdx] as (number | bigint)[]; + const [currMinNumb, currMaxNumb] = [interval[0] as number | bigint, interval[1] as number | bigint]; + + if (typeof currMinNumb === 'number' && typeof currMaxNumb === 'number') { + numb = this.generateNumber(currMinNumb, currMaxNumb, intervalsToAdd as number[][], intervalIdx); + } else if (typeof currMinNumb === 'bigint' && typeof currMaxNumb === 'bigint') { + numb = this.generateBigint( + currMinNumb as bigint, + currMaxNumb as bigint, + intervalsToAdd as bigint[][], + intervalIdx, + ); + } + + if (this.dataType === 'string') { + return String(numb); + } + + if (this.dataType === 'bigint' && numb !== undefined) { + numb = BigInt(numb); + } + return numb; + } + + generateNumber(currMinNumb: number, currMaxNumb: number, intervalsToAdd: number[][], intervalIdx: number) { + let numb: number; + + [numb, this.state!.rng] = prand.uniformIntDistribution(currMinNumb, currMaxNumb, this.state!.rng); + + if (this.genMaxRepeatedValuesCount !== undefined) { + if (this.state!.integersCount.get(numb) === undefined) { + this.state!.integersCount.set(numb, this.genMaxRepeatedValuesCount.generate() as number); + } + this.state!.integersCount.set(numb, this.state!.integersCount.get(numb)! - 1); + } + + if (this.state!.integersCount.get(numb) === undefined || this.state!.integersCount.get(numb) === 0) { + if (numb === currMinNumb) { + intervalsToAdd = numb + 1 <= currMaxNumb ? [[numb + 1, currMaxNumb]] : []; + } else if (numb === currMaxNumb) { + intervalsToAdd = [[currMinNumb, numb - 1]]; + } else { + intervalsToAdd = [ + [currMinNumb, numb - 1], + [numb + 1, currMaxNumb], + ]; + } + + const t0 = new Date(); + this.state!.intervals[intervalIdx] = this.state!.intervals[this.state!.intervals.length - 1]!; + this.state?.intervals.pop(); + this.timeSpent += (Date.now() - t0.getTime()) / 1000; + this.state!.intervals.push(...intervalsToAdd); + } + + return numb; + } + + generateBigint(currMinNumb: bigint, currMaxNumb: bigint, intervalsToAdd: bigint[][], intervalIdx: number) { + let numb: bigint; + [numb, this.state!.rng] = prand.uniformBigIntDistribution(currMinNumb, currMaxNumb, this.state!.rng); + if (this.genMaxRepeatedValuesCount !== undefined) { + if (this.state!.integersCount.get(numb) === undefined) { + this.state!.integersCount.set(numb, this.genMaxRepeatedValuesCount.generate() as number); + } + this.state!.integersCount.set(numb, this.state!.integersCount.get(numb)! - 1); + } + + if (this.state!.integersCount.get(numb) === undefined || this.state!.integersCount.get(numb) === 0) { + if (numb === currMinNumb) { + intervalsToAdd = numb + BigInt(1) <= currMaxNumb ? [[numb + BigInt(1), currMaxNumb]] : []; + } else if (numb === currMaxNumb) { + intervalsToAdd = [[currMinNumb, numb - BigInt(1)]]; + } else { + intervalsToAdd = [ + [currMinNumb, numb - BigInt(1)], + [numb + BigInt(1), currMaxNumb], + ]; + } + + this.state!.intervals[intervalIdx] = this.state!.intervals[this.state!.intervals.length - 1]!; + this.state?.intervals.pop(); + this.state!.intervals.push(...intervalsToAdd); + } + + return numb; + } +} + +export class GenerateBoolean extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'GenerateBoolean'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let value: number; + + [value, this.state.rng] = prand.uniformIntDistribution(0, 1, this.state.rng); + return value === 1; + } +} + +export class GenerateDate extends AbstractGenerator<{ minDate?: string | Date; maxDate?: string | Date }> { + static override readonly [entityKind]: string = 'GenerateDate'; + + private state: { + rng: prand.RandomGenerator; + minDate: Date; + maxDate: Date; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + let { minDate, maxDate } = this.params; + const anchorDate = new Date('2024-05-08'); + const deltaMilliseconds = 4 * 31536000000; + + if (typeof minDate === 'string') { + minDate = new Date(minDate); + } + + if (typeof maxDate === 'string') { + maxDate = new Date(maxDate); + } + + if (minDate === undefined) { + if (maxDate === undefined) { + minDate = new Date(anchorDate.getTime() - deltaMilliseconds); + maxDate = new Date(anchorDate.getTime() + deltaMilliseconds); + } else { + minDate = new Date(maxDate.getTime() - (2 * deltaMilliseconds)); + } + } + + if (maxDate === undefined) { + maxDate = new Date(minDate.getTime() + (2 * deltaMilliseconds)); + } + + this.state = { rng, minDate, maxDate }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let milliseconds: number; + + [milliseconds, this.state.rng] = prand.uniformIntDistribution( + this.state.minDate.getTime(), + this.state.maxDate.getTime(), + this.state.rng, + ); + const date = new Date(milliseconds); + + if (this.dataType === 'string') { + return date.toISOString().replace(/T.+/, ''); + } + return date; + } +} +export class GenerateTime extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'GenerateTime'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const anchorDateTime = new Date('2024-05-08T12:00:00.000Z'); + const oneDayInMilliseconds = 86400000; + + let date = new Date(); + let milliseconds: number; + + [milliseconds, this.state.rng] = prand.uniformIntDistribution( + -oneDayInMilliseconds, + oneDayInMilliseconds, + this.state.rng, + ); + date = new Date(date.setTime(anchorDateTime.getTime() + milliseconds)); + + return date.toISOString().replace(/(\d{4}-\d{2}-\d{2}T)|(\.\d{3}Z)/g, ''); + } +} +export class GenerateTimestampInt extends AbstractGenerator<{ unitOfTime?: 'seconds' | 'milliseconds' }> { + static override readonly [entityKind]: string = 'GenerateTimestampInt'; + + private state: { + generateTimestampObj: GenerateTimestamp; + } | undefined; + + init({ seed }: { seed: number }) { + const generateTimestampObj = new GenerateTimestamp({}); + generateTimestampObj.dataType = 'date'; + generateTimestampObj.init({ seed }); + + this.state = { generateTimestampObj }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const date = this.state.generateTimestampObj.generate() as Date; + + if (this.params.unitOfTime === 'seconds') { + return Math.floor(date.getTime() / 1000); + } else if (this.params.unitOfTime === 'milliseconds') { + return date.getTime(); + } else { + // this.params.unitOfTime === undefined + return Math.floor(date.getTime() / 1000); + } + } +} + +export class GenerateTimestamp extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'GenerateTimestamp'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const anchorTimestamp = new Date('2024-05-08'); + const twoYearsInMilliseconds = 2 * 31536000000; + + let date = new Date(); + let milliseconds: number; + + [milliseconds, this.state.rng] = prand.uniformIntDistribution( + -twoYearsInMilliseconds, + twoYearsInMilliseconds, + this.state.rng, + ); + date = new Date(date.setTime(anchorTimestamp.getTime() + milliseconds)); + + if (this.dataType === 'string') { + return date + .toISOString() + .replace('T', ' ') + .replace(/\.\d{3}Z/, ''); + } + + return date; + } +} + +export class GenerateDatetime extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'GenerateDatetime'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const anchorDate = new Date('2024-05-08'); + const twoYearsInMilliseconds = 2 * 31536000000; + + let date = new Date(); + let milliseconds: number; + + [milliseconds, this.state.rng] = prand.uniformIntDistribution( + -twoYearsInMilliseconds, + twoYearsInMilliseconds, + this.state.rng, + ); + date = new Date(date.setTime(anchorDate.getTime() + milliseconds)); + + if (this.dataType === 'string') { + return date + .toISOString() + .replace('T', ' ') + .replace(/\.\d{3}Z/, ''); + } + + return date; + } +} + +export class GenerateYear extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'GenerateYear'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const anchorDate = new Date('2024-05-08'); + const tenYears = 10; + + let date = new Date(); + let years: number; + + [years, this.state.rng] = prand.uniformIntDistribution(-tenYears, tenYears, this.state.rng); + date = new Date(date.setFullYear(anchorDate.getFullYear() + years)); + + return date + .toISOString() + .replace(/(-\d{2}-\d{2}T)|(\d{2}:\d{2}:\d{2}\.\d{3}Z)/g, ''); + } +} + +export class GenerateJson extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'GenerateJson'; + + private state: { + emailGeneratorObj: GenerateEmail; + nameGeneratorObj: GenerateFirstName; + booleanGeneratorObj: GenerateBoolean; + salaryGeneratorObj: GenerateInt; + dateGeneratorObj: GenerateDate; + visitedCountriesNumberGeneratorObj: GenerateInt; + seed: number; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const emailGeneratorObj = new GenerateEmail({}); + emailGeneratorObj.init({ count, seed }); + + const nameGeneratorObj = new GenerateFirstName({}); + nameGeneratorObj.init({ seed }); + + const booleanGeneratorObj = new GenerateBoolean({}); + booleanGeneratorObj.init({ + seed, + }); + + const salaryGeneratorObj = new GenerateInt({ minValue: 200, maxValue: 4000 }); + salaryGeneratorObj.init({ + count, + seed, + ...salaryGeneratorObj.params, + }); + + const dateGeneratorObj = new GenerateDate({}); + dateGeneratorObj.dataType = 'string'; + dateGeneratorObj.init({ seed }); + + const visitedCountriesNumberGeneratorObj = new GenerateInt({ minValue: 0, maxValue: 4 }); + visitedCountriesNumberGeneratorObj.init( + { count, seed, ...visitedCountriesNumberGeneratorObj.params }, + ); + + this.state = { + emailGeneratorObj, + nameGeneratorObj, + booleanGeneratorObj, + salaryGeneratorObj, + dateGeneratorObj, + visitedCountriesNumberGeneratorObj, + seed, + }; + } + + generate({ i }: { i: number }) { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const visitedCountries: string[] = []; + const email = this.state.emailGeneratorObj.generate(); + const name = this.state.nameGeneratorObj.generate(); + const isGraduated = this.state.booleanGeneratorObj.generate(); + const hasJob = this.state.booleanGeneratorObj.generate(); + const salary = this.state.salaryGeneratorObj.generate() as number; + const startedWorking = this.state.dateGeneratorObj.generate() as string; + const visitedCountriesNumber = this.state.visitedCountriesNumberGeneratorObj.generate() as number; + + const uniqueCountriesGeneratorObj = new GenerateUniqueCountry({}); + uniqueCountriesGeneratorObj.init({ + count: visitedCountriesNumber, + seed: this.state.seed + i, + }); + for (let j = 0; j < visitedCountriesNumber; j++) { + visitedCountries.push(uniqueCountriesGeneratorObj.generate()); + } + + const returnJson = hasJob + ? { + email, + name, + isGraduated, + hasJob, + salary, + startedWorking, + visitedCountries, + } + : { + email, + name, + isGraduated, + hasJob, + visitedCountries, + }; + + if (this.dataType === 'string') { + return JSON.stringify(returnJson); + } + + return returnJson; + } +} + +export class GenerateEnum extends AbstractGenerator<{ enumValues: (string | number | boolean)[] }> { + static override readonly [entityKind]: string = 'GenerateEnum'; + + private state: { + enumValuesGenerator: GenerateValuesFromArray; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const { enumValues } = this.params; + const enumValuesGenerator = new GenerateValuesFromArray({ values: enumValues }); + enumValuesGenerator.init({ count, seed }); + this.state = { enumValuesGenerator }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + // logic for this generator + return this.state.enumValuesGenerator.generate(); + } +} + +export class GenerateInterval extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateInterval'; + + private state: { rng: prand.RandomGenerator } | undefined; + override uniqueVersionOfGen = GenerateUniqueInterval; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let yearsNumb: number, + monthsNumb: number, + daysNumb: number, + hoursNumb: number, + minutesNumb: number, + secondsNumb: number; + + let interval = ''; + + [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); + [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); + + [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); + + [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); + + [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + + [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + + interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` + + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` + + `${daysNumb === 0 ? '' : `${daysNumb} days `}` + + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` + + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` + + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; + + return interval; + } +} + +export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateUniqueInterval'; + + private state: { + rng: prand.RandomGenerator; + intervalSet: Set; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const maxUniqueIntervalsNumber = 6 * 13 * 29 * 25 * 61 * 61; + if (count > maxUniqueIntervalsNumber) { + throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`); + } + + const rng = prand.xoroshiro128plus(seed); + const intervalSet = new Set(); + this.state = { rng, intervalSet }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let yearsNumb: number, + monthsNumb: number, + daysNumb: number, + hoursNumb: number, + minutesNumb: number, + secondsNumb: number; + + let interval = ''; + + for (;;) { + [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); + [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); + [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); + [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); + [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + + interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` + + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` + + `${daysNumb === 0 ? '' : `${daysNumb} days `}` + + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` + + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` + + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; + + if (!this.state.intervalSet.has(interval)) { + this.state.intervalSet.add(interval); + break; + } + } + + return interval; + } +} + +export class GenerateString extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateString'; + + private state: { rng: prand.RandomGenerator } | undefined; + override uniqueVersionOfGen = GenerateUniqueString; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const minStringLength = 7; + const maxStringLength = 20; + const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let idx: number, + strLength: number, + currStr: string; + + currStr = ''; + [strLength, this.state.rng] = prand.uniformIntDistribution( + minStringLength, + maxStringLength, + this.state.rng, + ); + for (let j = 0; j < strLength; j++) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + stringChars.length - 1, + this.state.rng, + ); + currStr += stringChars[idx]; + } + return currStr; + } +} + +export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateUniqueString'; + + private state: { rng: prand.RandomGenerator } | undefined; + public override isUnique = true; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + this.state = { rng }; + } + + generate({ i }: { i: number }) { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const minStringLength = 7; + const maxStringLength = 20; + const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let idx: number, + strLength: number; + let currStr: string; + + currStr = ''; + const uniqueStr = i.toString(16); + [strLength, this.state.rng] = prand.uniformIntDistribution( + minStringLength, + maxStringLength - uniqueStr.length, + this.state.rng, + ); + for (let j = 0; j < strLength - uniqueStr.length; j++) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + stringChars.length - 1, + this.state.rng, + ); + currStr += stringChars[idx]; + } + + return currStr.slice(0, 4) + uniqueStr + currStr.slice(4); + } +} + +export class GenerateFirstName extends AbstractGenerator<{ + isUnique?: boolean; +}> { + static override readonly [entityKind]: string = 'GenerateFirstName'; + + override timeSpent: number = 0; + private state: { + rng: prand.RandomGenerator; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueFirstName; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + // logic for this generator + // names dataset contains about 30000 unique names. + // TODO: generate names accordingly to max column length + let idx: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, firstNames.length - 1, this.state.rng); + return firstNames[idx] as string; + } +} + +export class GenerateUniqueFirstName extends AbstractGenerator<{ + isUnique?: boolean; +}> { + static override readonly [entityKind]: string = 'GenerateUniqueFirstName'; + + private state: { + genIndicesObj: GenerateUniqueInt; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + if (count > firstNames.length) { + throw new Error('count exceeds max number of unique first names.'); + } + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: firstNames.length - 1 }); + genIndicesObj.init({ count, seed }); + + this.state = { genIndicesObj }; + } + + generate() { + // names dataset contains about 30000 unique names. + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const nameIdx = this.state.genIndicesObj.generate() as number; + const name = firstNames[nameIdx] as string; + + return name; + } +} + +export class GenerateLastName extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateLastName'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueLastName; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, lastNames.length - 1, this.state.rng); + return lastNames[idx]; + } +} + +export class GenerateUniqueLastName extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateUniqueLastName'; + + private state: { + genIndicesObj: GenerateUniqueInt; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + if (count > lastNames.length) { + throw new Error('count exceeds max number of unique last names.'); + } + + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: lastNames.length - 1 }); + genIndicesObj.init({ count, seed }); + + this.state = { genIndicesObj }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const surnameIdx = this.state.genIndicesObj.generate() as number; + const surname = lastNames[surnameIdx] as string; + + return surname; + } +} + +export class GenerateFullName extends AbstractGenerator<{ + isUnique?: boolean; +}> { + static override readonly [entityKind]: string = 'GenerateFullName'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueFullName; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, firstNames.length - 1, this.state.rng); + const name = firstNames[idx] as string; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, lastNames.length - 1, this.state.rng); + const surname = lastNames[idx] as string; + + const fullName = `${name} ${surname}`; + + return fullName; + } +} + +export class GenerateUniqueFullName extends AbstractGenerator<{ + isUnique?: boolean; +}> { + static override readonly [entityKind]: string = 'GenerateUniqueFullName'; + + private state: { + fullnameSet: Set; + rng: prand.RandomGenerator; + } | undefined; + public override isUnique = true; + public override timeSpent = 0; + + init({ count, seed }: { count: number; seed: number }) { + const t0 = new Date(); + + const maxUniqueFullNamesNumber = firstNames.length * lastNames.length; + if (count > maxUniqueFullNamesNumber) { + throw new RangeError( + `count exceeds max number of unique full names(${maxUniqueFullNamesNumber}).`, + ); + } + const rng = prand.xoroshiro128plus(seed); + const fullnameSet = new Set(); + + this.state = { rng, fullnameSet }; + this.timeSpent += (Date.now() - t0.getTime()) / 1000; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let fullname: string, name: string, surname: string, idx: number; + + const t0 = new Date(); + for (;;) { + [idx, this.state.rng] = prand.uniformIntDistribution(0, firstNames.length - 1, this.state.rng); + name = firstNames[idx] as string; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, lastNames.length - 1, this.state.rng); + surname = lastNames[idx] as string; + + fullname = `${name} ${surname}`; + + if (!this.state.fullnameSet.has(fullname)) { + this.state.fullnameSet.add(fullname); + break; + } + } + + this.timeSpent += (Date.now() - t0.getTime()) / 1000; + return fullname; + } +} + +export class GenerateEmail extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'GenerateEmail'; + + private state: { + genIndicesObj: GenerateUniqueInt; + arraysToGenerateFrom: string[][]; + } | undefined; + public override timeSpent: number = 0; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + const domainsArray = emailDomains; + const adjectivesArray = adjectives; + const namesArray = firstNames; + + const maxUniqueEmailsNumber = adjectivesArray.length * namesArray.length * domainsArray.length; + if (count > maxUniqueEmailsNumber) { + throw new RangeError( + `count exceeds max number of unique emails(${maxUniqueEmailsNumber}).`, + ); + } + + const arraysToGenerateFrom = [adjectivesArray, namesArray, domainsArray]; + const genIndicesObj = new GenerateUniqueInt({ + minValue: 0, + maxValue: maxUniqueEmailsNumber - 1, + }); + genIndicesObj.init({ count, seed }); + + this.state = { genIndicesObj, arraysToGenerateFrom }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const t0 = new Date(); + const emailIndex = this.state.genIndicesObj.generate() as number; + this.timeSpent += (Date.now() - t0.getTime()) / 1000; + const tokens = fastCartesianProduct( + this.state.arraysToGenerateFrom, + emailIndex, + ) as string[]; + + const [adjective, name, domain] = [tokens[0] as string, tokens[1] as string, tokens[2] as string]; + + const email = `${adjective}_${name.toLowerCase()}@${domain}`; + + return email; + } +} + +export class GeneratePhoneNumber extends AbstractGenerator<{ + template?: string; + prefixes?: string[]; + generatedDigitsNumbers?: number | number[]; +}> { + static override readonly [entityKind]: string = 'GeneratePhoneNumber'; + + private state: { + rng: prand.RandomGenerator; + placeholdersCount?: number; + prefixesArray: string[]; + generatedDigitsNumbers: number[]; + generatorsMap: Map; + phoneNumbersSet: Set; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + let { generatedDigitsNumbers } = this.params; + const { prefixes, template } = this.params; + + const rng = prand.xoroshiro128plus(seed); + + if (template !== undefined) { + const iterArray = [...template.matchAll(/#/g)]; + const placeholdersCount = iterArray.length; + + const maxUniquePhoneNumbersCount = Math.pow(10, placeholdersCount); + if (maxUniquePhoneNumbersCount < count) { + throw new RangeError( + `count exceeds max number of unique phone numbers(${maxUniquePhoneNumbersCount}).`, + ); + } + + const generatorsMap = new Map(); + const genObj = new GenerateUniqueInt({ minValue: 0, maxValue: maxUniquePhoneNumbersCount - 1 }); + genObj.init({ + count, + seed, + }); + + generatorsMap.set( + template, + genObj, + ); + + const prefixesArray: string[] = []; + const generatedDigitsNumbers: number[] = []; + const phoneNumbersSet = new Set(); + + this.state = { rng, placeholdersCount, generatorsMap, prefixesArray, generatedDigitsNumbers, phoneNumbersSet }; + return; + } + + let prefixesArray: string[]; + if (prefixes === undefined || prefixes.length === 0) { + prefixesArray = phonesInfo.map((phoneInfo) => phoneInfo.split(',').slice(0, -1).join(' ')); + generatedDigitsNumbers = phonesInfo.map((phoneInfo) => { + // tokens = ["380","99","9"] = + // = ["country prefix", "operator prefix", "number length including operator prefix and excluding country prefix"] + const tokens = phoneInfo.split(','); + const operatorPrefixLength = tokens[1]!.replaceAll(' ', '').length; + + return Number(tokens[2]) - operatorPrefixLength; + }); + } else { + prefixesArray = prefixes; + if (typeof generatedDigitsNumbers === 'number') { + generatedDigitsNumbers = Array.from({ length: prefixes.length }).fill( + generatedDigitsNumbers, + ); + } else if ( + generatedDigitsNumbers === undefined + || generatedDigitsNumbers.length === 0 + ) { + generatedDigitsNumbers = Array.from({ length: prefixes.length }).fill(7); + } + } + + if (new Set(prefixesArray).size !== prefixesArray.length) { + throw new Error('prefixes are not unique.'); + } + + const maxUniquePhoneNumbersCount = generatedDigitsNumbers.reduce( + (a, b) => a + Math.pow(10, b), + 0, + ); + if (maxUniquePhoneNumbersCount < count) { + throw new RangeError( + `count exceeds max number of unique phone numbers(${maxUniquePhoneNumbersCount}).`, + ); + } + + const generatorsMap = new Map(); + let maxValue: number, prefix: string, generatedDigitsNumber: number; + for (const [i, element] of prefixesArray.entries()) { + prefix = element as string; + generatedDigitsNumber = generatedDigitsNumbers[i] as number; + maxValue = Math.pow(10, generatedDigitsNumber) - 1; + + if (!generatorsMap.has(prefix)) { + const genObj = new GenerateUniqueInt({ minValue: 0, maxValue }); + genObj.init({ + count: Math.min(count, maxValue + 1), + seed, + }); + genObj.skipCheck = true; + generatorsMap.set( + prefix, + genObj, + ); + } + } + const phoneNumbersSet = new Set(); + + this.state = { rng, prefixesArray, generatedDigitsNumbers, generatorsMap, phoneNumbersSet }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let prefix: string, generatedDigitsNumber: number, numberBody: string, phoneNumber: string, idx: number; + + if (this.params.template === undefined) { + for (;;) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + this.state.prefixesArray.length - 1, + this.state.rng, + ); + prefix = this.state.prefixesArray[idx] as string; + generatedDigitsNumber = this.state.generatedDigitsNumbers[idx] as number; + + numberBody = String(this.state.generatorsMap.get(prefix)?.generate()); + if (numberBody === 'undefined') { + this.state.prefixesArray!.splice(idx, 1); + this.state.generatedDigitsNumbers.splice(idx, 1); + + this.state.generatorsMap.delete(prefix); + + continue; + } + + if (this.state.phoneNumbersSet.has(numberBody)) { + continue; + } + this.state.phoneNumbersSet.add(numberBody); + + break; + } + + const digitsNumberDiff = generatedDigitsNumber - numberBody.length; + if (digitsNumberDiff > 0) { + numberBody = '0'.repeat(digitsNumberDiff) + numberBody; + } + + phoneNumber = (prefix.includes('+') ? '' : '+') + prefix + '' + numberBody; + + return phoneNumber; + } else { + numberBody = String(this.state.generatorsMap.get(this.params.template)?.generate()); + phoneNumber = fillTemplate({ + template: this.params.template, + values: [...numberBody], + defaultValue: '0', + placeholdersCount: this.state.placeholdersCount, + }); + + return phoneNumber; + } + } +} + +export class GenerateCountry extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateCountry'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueCountry; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, countries.length - 1, this.state.rng); + const country = countries[idx] as string; + + return country; + } +} + +export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateUniqueCountry'; + + private state: { + genIndicesObj: GenerateUniqueInt; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + if (count > countries.length) { + throw new Error('count exceeds max number of unique countries.'); + } + + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: countries.length - 1 }); + genIndicesObj.init({ count, seed }); + + this.state = { genIndicesObj }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const countryIdx = this.state.genIndicesObj.generate() as number; + const country = countries[countryIdx] as string; + + return country; + } +} + +export class GenerateJobTitle extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'GenerateJobTitle'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + let idx; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, jobsTitles.length - 1, this.state.rng); + + return jobsTitles[idx]; + } +} + +export class GenerateStreetAdddress extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateStreetAdddress'; + + private state: { + rng: prand.RandomGenerator; + possStreetNames: string[][]; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueStreetAdddress; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + const possStreetNames = [firstNames, lastNames]; + this.state = { rng, possStreetNames }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx, streetBaseNameIdx, streetSuffixIdx, streetNumber; + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.possStreetNames.length - 1, this.state.rng); + + [streetBaseNameIdx, this.state.rng] = prand.uniformIntDistribution( + 0, + this.state.possStreetNames[idx]!.length - 1, + this.state.rng, + ); + [streetSuffixIdx, this.state.rng] = prand.uniformIntDistribution(0, streetSuffix.length - 1, this.state.rng); + const streetName = `${this.state.possStreetNames[idx]![streetBaseNameIdx]} ${streetSuffix[streetSuffixIdx]}`; + + [streetNumber, this.state.rng] = prand.uniformIntDistribution(1, 999, this.state.rng); + + return `${streetNumber} ${streetName}`; + } +} + +export class GenerateUniqueStreetAdddress extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateUniqueStreetAdddress'; + + private state: { + rng: prand.RandomGenerator; + possStreetNameObjs: { + indicesGen: GenerateUniqueInt; + maxUniqueStreetNamesNumber: number; + count: number; + arraysToChooseFrom: string[][]; + }[]; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const streetNumberStrs = Array.from({ length: 999 }, (_, i) => String(i + 1)); + const maxUniqueStreetnamesNumber = streetNumberStrs.length * firstNames.length * streetSuffix.length + + streetNumberStrs.length * firstNames.length * streetSuffix.length; + + if (count > maxUniqueStreetnamesNumber) { + throw new RangeError( + `count exceeds max number of unique street names(${maxUniqueStreetnamesNumber}).`, + ); + } + + const rng = prand.xoroshiro128plus(seed); + // ["1", "2", ..., "999"] + + const possStreetNameObjs = [ + { + indicesGen: new GenerateUniqueInt({ + minValue: 0, + maxValue: streetNumberStrs.length * firstNames.length * streetSuffix.length - 1, + }), + maxUniqueStreetNamesNumber: streetNumberStrs.length * firstNames.length * streetSuffix.length, + count: 0, + arraysToChooseFrom: [streetNumberStrs, firstNames, streetSuffix], + }, + { + indicesGen: new GenerateUniqueInt({ + minValue: 0, + maxValue: streetNumberStrs.length * lastNames.length * streetSuffix.length - 1, + }), + maxUniqueStreetNamesNumber: streetNumberStrs.length * firstNames.length * streetSuffix.length, + count: 0, + arraysToChooseFrom: [streetNumberStrs, lastNames, streetSuffix], + }, + ]; + + for (const possStreetNameObj of possStreetNameObjs) { + possStreetNameObj.indicesGen.skipCheck = true; + possStreetNameObj.indicesGen.init({ count, seed }); + } + + this.state = { rng, possStreetNameObjs }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let streetNameObjIdx; + [streetNameObjIdx, this.state.rng] = prand.uniformIntDistribution( + 0, + this.state.possStreetNameObjs.length - 1, + this.state.rng, + ); + const streetNameObj = this.state.possStreetNameObjs[streetNameObjIdx]!; + + const idx = streetNameObj.indicesGen.generate() as number; + const values = fastCartesianProduct(streetNameObj.arraysToChooseFrom, idx) as string[]; + + streetNameObj.count += 1; + if (streetNameObj.count === streetNameObj.maxUniqueStreetNamesNumber) { + this.state.possStreetNameObjs[streetNameObjIdx] = this.state + .possStreetNameObjs.at(-1)!; + this.state.possStreetNameObjs.pop(); + } + + const streetName = fillTemplate({ template: '# # #', values, placeholdersCount: 3 }); + + return streetName; + } +} + +export class GenerateCity extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateCity'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueCity; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx; + [idx, this.state.rng] = prand.uniformIntDistribution(0, cityNames.length - 1, this.state.rng); + + return cityNames[idx]; + } +} + +export class GenerateUniqueCity extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateUniqueCity'; + + private state: { + genIndicesObj: GenerateUniqueInt; + } | undefined; + public override isUnique = true; + + init({ count, seed }: { count: number; seed: number }) { + if (count > cityNames.length) { + throw new Error('count exceeds max number of unique cities.'); + } + + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: cityNames.length - 1 }); + genIndicesObj.init({ count, seed }); + + this.state = { genIndicesObj }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const cityIdx = this.state.genIndicesObj.generate() as number; + const city = cityNames[cityIdx] as string; + + return city; + } +} + +export class GeneratePostcode extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GeneratePostcode'; + + private state: { + rng: prand.RandomGenerator; + templates: string[]; + } | undefined; + override uniqueVersionOfGen = GenerateUniquePostcode; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + const templates = ['#####', '#####-####']; + + this.state = { rng, templates }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number, postcodeNumber: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.templates.length - 1, this.state.rng); + const template = this.state.templates[idx]!; + + const iterArray = [...template.matchAll(/#/g)]; + const placeholdersCount = iterArray.length; + + [postcodeNumber, this.state.rng] = prand.uniformIntDistribution( + 0, + Math.pow(10, placeholdersCount) - 1, + this.state.rng, + ); + const postcode = fillTemplate({ + template, + placeholdersCount, + values: [...String(postcodeNumber)], + defaultValue: '0', + }); + + return postcode; + } +} + +export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateUniquePostcode'; + + private state: { + rng: prand.RandomGenerator; + templates: { + template: string; + indicesGen: GenerateUniqueInt; + placeholdersCount: number; + count: number; + maxUniquePostcodeNumber: number; + }[]; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const maxUniquePostcodeNumber = Math.pow(10, 5) + Math.pow(10, 9); + if (count > maxUniquePostcodeNumber) { + throw new RangeError( + `count exceeds max number of unique postcodes(${maxUniquePostcodeNumber}).`, + ); + } + + const rng = prand.xoroshiro128plus(seed); + const templates = [ + { + template: '#####', + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: Math.pow(10, 5) - 1 }), + placeholdersCount: 5, + count: 0, + maxUniquePostcodeNumber: Math.pow(10, 5), + }, + { + template: '#####-####', + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: Math.pow(10, 9) - 1 }), + placeholdersCount: 9, + count: 0, + maxUniquePostcodeNumber: Math.pow(10, 9), + }, + ]; + + for (const templateObj of templates) { + templateObj.indicesGen.skipCheck = true; + templateObj.indicesGen.init({ count, seed }); + } + + this.state = { rng, templates }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.templates.length - 1, this.state.rng); + const templateObj = this.state.templates[idx]!; + + const postcodeNumber = templateObj.indicesGen.generate() as number; + + templateObj.count += 1; + if (templateObj.count === templateObj.maxUniquePostcodeNumber) { + this.state.templates[idx] = this.state.templates.at(-1)!; + this.state.templates.pop(); + } + + const postcode = fillTemplate({ + template: templateObj.template, + placeholdersCount: templateObj.placeholdersCount, + values: [...String(postcodeNumber)], + defaultValue: '0', + }); + + return postcode; + } +} + +export class GenerateState extends AbstractGenerator<{}> { + static override readonly [entityKind]: string = 'GenerateState'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx; + [idx, this.state.rng] = prand.uniformIntDistribution(0, states.length - 1, this.state.rng); + + return states[idx]; + } +} + +export class GenerateCompanyName extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateCompanyName'; + + private state: { + rng: prand.RandomGenerator; + templates: { template: string; placeholdersCount: number }[]; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueCompanyName; + + init({ seed }: { seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const rng = prand.xoroshiro128plus(seed); + const templates = [ + { template: '#', placeholdersCount: 1 }, + { template: '# - #', placeholdersCount: 2 }, + { template: '# and #', placeholdersCount: 2 }, + { template: '#, # and #', placeholdersCount: 3 }, + ]; + + this.state = { rng, templates }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let templateIdx, idx, lastName, companyNameSuffix, companyName; + [templateIdx, this.state.rng] = prand.uniformIntDistribution(0, this.state.templates.length - 1, this.state.rng); + const templateObj = this.state.templates[templateIdx]!; + + if (templateObj.template === '#') { + [idx, this.state.rng] = prand.uniformIntDistribution(0, lastNames.length - 1, this.state.rng); + lastName = lastNames[idx]; + + [idx, this.state.rng] = prand.uniformIntDistribution(0, companyNameSuffixes.length - 1, this.state.rng); + companyNameSuffix = companyNameSuffixes[idx]; + + companyName = `${lastName} ${companyNameSuffix}`; + return companyName; + } + + const values = []; + for (let i = 0; i < templateObj.placeholdersCount; i++) { + [idx, this.state.rng] = prand.uniformIntDistribution(0, lastNames.length - 1, this.state.rng); + values.push(lastNames[idx]!); + } + + companyName = fillTemplate({ + template: templateObj.template, + values, + placeholdersCount: templateObj.placeholdersCount, + }); + return companyName; + } +} + +export class GenerateUniqueCompanyName extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateUniqueCompanyName'; + + private state: { + rng: prand.RandomGenerator; + templates: { + template: string; + placeholdersCount: number; + indicesGen: GenerateUniqueInt; + maxUniqueCompanyNameNumber: number; + count: number; + arraysToChooseFrom: string[][]; + }[]; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const maxUniqueCompanyNameNumber = lastNames.length * companyNameSuffixes.length + Math.pow(lastNames.length, 2) + + Math.pow(lastNames.length, 2) + Math.pow(lastNames.length, 3); + if (count > maxUniqueCompanyNameNumber) { + throw new RangeError( + `count exceeds max number of unique company names(${maxUniqueCompanyNameNumber}).`, + ); + } + + const rng = prand.xoroshiro128plus(seed); + // when count reach maxUniqueCompanyNameNumber template will be deleted from array + const templates = [ + { + template: '# - #', + placeholdersCount: 1, + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: lastNames.length * companyNameSuffixes.length - 1 }), + maxUniqueCompanyNameNumber: lastNames.length * companyNameSuffixes.length, + count: 0, + arraysToChooseFrom: [lastNames, companyNameSuffixes], + }, + { + template: '# - #', + placeholdersCount: 2, + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: Math.pow(lastNames.length, 2) - 1 }), + maxUniqueCompanyNameNumber: Math.pow(lastNames.length, 2), + count: 0, + arraysToChooseFrom: [lastNames, lastNames], + }, + { + template: '# and #', + placeholdersCount: 2, + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: Math.pow(lastNames.length, 2) - 1 }), + maxUniqueCompanyNameNumber: Math.pow(lastNames.length, 2), + count: 0, + arraysToChooseFrom: [lastNames, lastNames], + }, + { + template: '#, # and #', + placeholdersCount: 3, + indicesGen: new GenerateUniqueInt({ minValue: 0, maxValue: Math.pow(lastNames.length, 3) - 1 }), + maxUniqueCompanyNameNumber: Math.pow(lastNames.length, 3), + count: 0, + arraysToChooseFrom: [lastNames, lastNames, lastNames], + }, + ]; + + for (const templateObj of templates) { + templateObj.indicesGen.skipCheck = true; + templateObj.indicesGen.init({ count, seed }); + } + + this.state = { rng, templates }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let templateIdx; + [templateIdx, this.state.rng] = prand.uniformIntDistribution(0, this.state.templates.length - 1, this.state.rng); + const templateObj = this.state.templates[templateIdx]!; + + const idx = templateObj.indicesGen.generate() as number; + const values = fastCartesianProduct(templateObj.arraysToChooseFrom, idx) as string[]; + + templateObj.count += 1; + if (templateObj.count === templateObj.maxUniqueCompanyNameNumber) { + this.state.templates[templateIdx] = this.state.templates.at(-1)!; + this.state.templates.pop(); + } + + const companyName = fillTemplate({ + template: templateObj.template, + values, + placeholdersCount: templateObj.placeholdersCount, + }); + return companyName; + } +} + +export class GenerateLoremIpsum extends AbstractGenerator<{ sentencesCount?: number }> { + static override readonly [entityKind]: string = 'GenerateLoremIpsum'; + + private state: { + rng: prand.RandomGenerator; + } | undefined; + + init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + if (this.params.sentencesCount === undefined) this.params.sentencesCount = 1; + + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx, resultText: string = ''; + for (let i = 0; i < this.params.sentencesCount!; i++) { + [idx, this.state.rng] = prand.uniformIntDistribution(0, loremIpsumSentences.length - 1, this.state.rng); + resultText += loremIpsumSentences[idx] + ' '; + } + + return resultText; + } +} + +export class WeightedRandomGenerator extends AbstractGenerator<{ weight: number; value: AbstractGenerator }[]> { + static override readonly [entityKind]: string = 'WeightedRandomGenerator'; + + private state: { + rng: prand.RandomGenerator; + weightedIndices: number[]; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const weights = this.params.map((weightedGen) => weightedGen.weight); + const weightedIndices = getWeightedIndices(weights); + + let idx: number, valueIdx: number, tempRng = prand.xoroshiro128plus(seed); + const indicesCounter: { [key: number]: number } = {}; + for (let i = 0; i < count; i++) { + [idx, tempRng] = prand.uniformIntDistribution(0, weightedIndices.length - 1, tempRng); + valueIdx = weightedIndices[idx]!; + if (!Object.hasOwn(indicesCounter, valueIdx)) indicesCounter[valueIdx] = 0; + indicesCounter[valueIdx]! += 1; + } + + for (const [idx, weightedGen] of this.params.entries()) { + weightedGen.value.isUnique = this.isUnique; + weightedGen.value.dataType = this.dataType; + weightedGen.value.init({ count: indicesCounter[idx]!, seed }); + + if ( + weightedGen.value.uniqueVersionOfGen !== undefined + && weightedGen.value.isUnique === true + ) { + const uniqueGen = new weightedGen.value.uniqueVersionOfGen({ + ...weightedGen.value.params, + }); + uniqueGen.init({ + count: indicesCounter[idx]!, + seed, + }); + uniqueGen.isUnique = weightedGen.value.isUnique; + uniqueGen.dataType = weightedGen.value.dataType; + + weightedGen.value = uniqueGen; + } + } + + const rng = prand.xoroshiro128plus(seed); + + this.state = { weightedIndices, rng }; + } + + generate({ i }: { i: number }) { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let idx: number; + [idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.weightedIndices.length - 1, this.state.rng); + const generatorIdx = this.state.weightedIndices[idx] as number; + const value = this.params[generatorIdx]!.value.generate({ i }); + + return value; + } +} + +export class GeneratePoint extends AbstractGenerator<{ + isUnique?: boolean; + minXValue?: number; + maxXValue?: number; + minYValue?: number; + maxYValue?: number; +}> { + static override readonly [entityKind]: string = 'GeneratePoint'; + + private state: { + xCoordinateGen: GenerateNumber; + yCoordinateGen: GenerateNumber; + } | undefined; + override uniqueVersionOfGen = GenerateUniquePoint; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const xCoordinateGen = new GenerateNumber({ + minValue: this.params.minXValue, + maxValue: this.params.maxXValue, + precision: 10, + }); + xCoordinateGen.init({ seed }); + + const yCoordinateGen = new GenerateNumber({ + minValue: this.params.minYValue, + maxValue: this.params.maxYValue, + precision: 10, + }); + yCoordinateGen.init({ seed }); + + this.state = { xCoordinateGen, yCoordinateGen }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const x = this.state.xCoordinateGen.generate(); + const y = this.state.yCoordinateGen.generate(); + + if (this.dataType === 'json') { + return { x, y }; + } else if (this.dataType === 'string') { + return `[${x}, ${y}]`; + } else { + // if (this.dataType === "array") + return [x, y]; + } + } +} + +export class GenerateUniquePoint extends AbstractGenerator<{ + minXValue?: number; + maxXValue?: number; + minYValue?: number; + maxYValue?: number; + isUnique?: boolean; +}> { + static override readonly [entityKind]: string = 'GenerateUniquePoint'; + + private state: { + xCoordinateGen: GenerateUniqueNumber; + yCoordinateGen: GenerateUniqueNumber; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const xCoordinateGen = new GenerateUniqueNumber({ + minValue: this.params.minXValue, + maxValue: this.params.maxXValue, + precision: 10, + }); + xCoordinateGen.init({ count, seed }); + + const yCoordinateGen = new GenerateUniqueNumber({ + minValue: this.params.minYValue, + maxValue: this.params.maxYValue, + precision: 10, + }); + yCoordinateGen.init({ count, seed }); + + this.state = { xCoordinateGen, yCoordinateGen }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const x = this.state.xCoordinateGen.generate(); + const y = this.state.yCoordinateGen.generate(); + + if (this.dataType === 'json') { + return { x, y }; + } else if (this.dataType === 'string') { + return `[${x}, ${y}]`; + } else { + // if (this.dataType === "array") + return [x, y]; + } + } +} + +export class GenerateLine extends AbstractGenerator<{ + isUnique?: boolean; + minAValue?: number; + maxAValue?: number; + minBValue?: number; + maxBValue?: number; + minCValue?: number; + maxCValue?: number; +}> { + static override readonly [entityKind]: string = 'GenerateLine'; + + private state: { + aCoefficientGen: GenerateNumber; + bCoefficientGen: GenerateNumber; + cCoefficientGen: GenerateNumber; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueLine; + + init({ seed }: { count: number; seed: number }) { + if (this.params.isUnique !== undefined) { + if (this.params.isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = this.params.isUnique; + } + + const aCoefficientGen = new GenerateNumber({ + minValue: this.params.minAValue, + maxValue: this.params.maxAValue, + precision: 10, + }); + aCoefficientGen.init({ seed }); + + const bCoefficientGen = new GenerateNumber({ + minValue: this.params.minBValue, + maxValue: this.params.maxBValue, + precision: 10, + }); + bCoefficientGen.init({ seed }); + + const cCoefficientGen = new GenerateNumber({ + minValue: this.params.minCValue, + maxValue: this.params.maxCValue, + precision: 10, + }); + cCoefficientGen.init({ seed }); + + this.state = { aCoefficientGen, bCoefficientGen, cCoefficientGen }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let b: number; + const a = this.state.aCoefficientGen.generate(); + + b = this.state.bCoefficientGen.generate(); + while (a === 0 && b === 0) { + b = this.state.bCoefficientGen.generate(); + } + + const c = this.state.cCoefficientGen.generate(); + + if (this.dataType === 'json') { + return { a, b, c }; + } else if (this.dataType === 'string') { + return `[${a}, ${b}, ${c}]`; + } else { + // if (this.dataType === "array") + return [a, b, c]; + } + } +} + +export class GenerateUniqueLine extends AbstractGenerator<{ + minAValue?: number; + maxAValue?: number; + minBValue?: number; + maxBValue?: number; + minCValue?: number; + maxCValue?: number; + isUnique?: boolean; +}> { + static override readonly [entityKind]: string = 'GenerateUniqueLine'; + + private state: { + aCoefficientGen: GenerateUniqueNumber; + bCoefficientGen: GenerateUniqueNumber; + cCoefficientGen: GenerateUniqueNumber; + } | undefined; + + init({ count, seed }: { count: number; seed: number }) { + const aCoefficientGen = new GenerateUniqueNumber({ + minValue: this.params.minAValue, + maxValue: this.params.maxAValue, + precision: 10, + }); + aCoefficientGen.init({ count, seed }); + + const bCoefficientGen = new GenerateUniqueNumber({ + minValue: this.params.minBValue, + maxValue: this.params.maxBValue, + precision: 10, + }); + bCoefficientGen.init({ count, seed }); + + const cCoefficientGen = new GenerateUniqueNumber({ + minValue: this.params.minCValue, + maxValue: this.params.maxCValue, + precision: 10, + }); + cCoefficientGen.init({ count, seed }); + + this.state = { aCoefficientGen, bCoefficientGen, cCoefficientGen }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let b: number; + const a = this.state.aCoefficientGen.generate(); + + b = this.state.bCoefficientGen.generate(); + while (a === 0 && b === 0) { + b = this.state.bCoefficientGen.generate(); + } + + const c = this.state.cCoefficientGen.generate(); + + if (this.dataType === 'json') { + return { a, b, c }; + } else if (this.dataType === 'string') { + return `[${a}, ${b}, ${c}]`; + } else { + // if (this.dataType === "array") + return [a, b, c]; + } + } +} + +export const generatorsFuncs = { + /** + * generates same given value each time the generator is called. + * @param defaultValue - value you want to generate + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.default({ defaultValue: "post content" }), + * }, + * }, + * })); + * ``` + */ + default: createGenerator(GenerateDefault), + + /** + * generates values from given array + * @param values - array of values you want to generate. can be array of weighted values. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * title: funcs.valuesFromArray({ + * values: ["Title1", "Title2", "Title3", "Title4", "Title5"], + * isUnique: true + * }), + * }, + * }, + * })); + * + * ``` + * weighted values example + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * title: funcs.valuesFromArray({ + * values: [ + * { weight: 0.35, values: ["Title1", "Title2"] }, + * { weight: 0.5, values: ["Title3", "Title4"] }, + * { weight: 0.15, values: ["Title5"] }, + * ], + * isUnique: false + * }), + * }, + * }, + * })); + * + * ``` + */ + valuesFromArray: createGenerator(GenerateValuesFromArray), + + /** + * generates sequential integers starting with 1. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * id: funcs.intPrimaryKey(), + * }, + * }, + * })); + * + * ``` + */ + intPrimaryKey: createGenerator(GenerateIntPrimaryKey), + + /** + * generates numbers with floating point in given range. + * @param minValue - lower border of range. + * @param maxValue - upper border of range. + * @param precision - precision of generated number: + * precision equals 10 means that values will be accurate to one tenth (1.2, 34.6); + * precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67). + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * products: { + * columns: { + * unitPrice: funcs.number({ minValue: 10, maxValue: 120, precision: 100, isUnique: false }), + * }, + * }, + * })); + * + * ``` + */ + number: createGenerator(GenerateNumber), + // uniqueNumber: createGenerator(GenerateUniqueNumber), + + /** + * generates integers within given range. + * @param minValue - lower border of range. + * @param maxValue - upper border of range. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * products: { + * columns: { + * unitsInStock: funcs.number({ minValue: 0, maxValue: 100, isUnique: false }), + * }, + * }, + * })); + * + * ``` + */ + int: createGenerator(GenerateInt), + // uniqueInt: createGenerator(GenerateUniqueInt), + + /** + * generates boolean values(true or false) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * isAvailable: funcs.boolean() + * }, + * }, + * })); + * + * ``` + */ + boolean: createGenerator(GenerateBoolean), + + /** + * generates date within given range. + * @param minDate - lower border of range. + * @param maxDate - upper border of range. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthDate: funcs.date({ minDate: "1990-01-01", maxDate: "2010-12-31" }) + * }, + * }, + * })); + * + * ``` + */ + date: createGenerator(GenerateDate), + + /** + * generates time in 24 hours style. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthTime: funcs.time() + * }, + * }, + * })); + * + * ``` + */ + time: createGenerator(GenerateTime), + + /** + * generates timestamps. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * orders: { + * columns: { + * shippedDate: funcs.timestamp() + * }, + * }, + * })); + * + * ``` + */ + timestamp: createGenerator(GenerateTimestamp), + + /** + * generates datetime objects. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * orders: { + * columns: { + * shippedDate: funcs.datetime() + * }, + * }, + * })); + * + * ``` + */ + datetime: createGenerator(GenerateDatetime), + + /** + * generates years. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthYear: funcs.year() + * }, + * }, + * })); + * + * ``` + */ + year: createGenerator(GenerateYear), + + /** + * generates json objects with fixed structure. + * + * json structure can equal this: + * ``` + * { + * email, + * name, + * isGraduated, + * hasJob, + * salary, + * startedWorking, + * visitedCountries, + * } + * ``` + * or this + * ``` + * { + * email, + * name, + * isGraduated, + * hasJob, + * visitedCountries, + * } + * ``` + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * metadata: funcs.json() + * }, + * }, + * })); + * ``` + */ + json: createGenerator(GenerateJson), + // jsonb: createGenerator(GenerateJsonb), + + /** + * generates time intervals. + * + * interval example: "1 years 12 days 5 minutes" + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * timeSpentOnWebsite: funcs.interval() + * }, + * }, + * })); + * ``` + */ + interval: createGenerator(GenerateInterval), + // uniqueInterval: createGenerator(GenerateUniqueInterval), + + /** + * generates random strings. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * hashedPassword: funcs.string({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + string: createGenerator(GenerateString), + // uniqueString: createGenerator(GenerateUniqueString), + + /** + * generates person's first names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * firstName: funcs.firstName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + firstName: createGenerator(GenerateFirstName), + // uniqueFirstName: createGenerator(GenerateUniqueName), + + /** + * generates person's last names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * lastName: funcs.lastName({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + lastName: createGenerator(GenerateLastName), + // uniqueLastName: createGenerator(GenerateUniqueSurname), + + /** + * generates person's full names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * fullName: funcs.fullName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + fullName: createGenerator(GenerateFullName), + // uniqueFullName: createGenerator(GenerateUniqueFullName), + + /** + * generates unique emails. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * email: funcs.email() + * }, + * }, + * })); + * ``` + */ + email: createGenerator(GenerateEmail), + + /** + * generates unique phone numbers. + * + * @param template - phone number template, where all '#' symbols will be substituted with generated digits. + * @param prefixes - array of any string you want to be your phone number prefixes.(not compatible with template property) + * @param generatedDigitsNumbers - number of digits that will be added at the end of prefixes.(not compatible with template property) + * @example + * ```ts + * //generate phone number using template property + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({template: "+(380) ###-####"}) + * }, + * }, + * })); + * + * //generate phone number using prefixes and generatedDigitsNumbers properties + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67" ], generatedDigitsNumbers: 7}) + * }, + * }, + * })); + * + * //generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67", "+1" ], generatedDigitsNumbers: [7, 7, 10]}) + * }, + * }, + * })); + * + * ``` + */ + phoneNumber: createGenerator(GeneratePhoneNumber), + + /** + * generates country's names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * country: funcs.country({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + country: createGenerator(GenerateCountry), + // uniqueCountry: createGenerator(GenerateUniqueCountry), + + /** + * generates city's names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * city: funcs.city({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + city: createGenerator(GenerateCity), + // uniqueCity: createGenerator(GenerateUniqueCityName), + + /** + * generates street address. + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * streetAddress: funcs.streetAddress({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + streetAddress: createGenerator(GenerateStreetAdddress), + // uniqueStreetAddress: createGenerator(GenerateUniqueStreetAdddress), + + /** + * generates job titles. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * jobTitle: funcs.jobTitle() + * }, + * }, + * })); + * ``` + */ + jobTitle: createGenerator(GenerateJobTitle), + + /** + * generates postal codes. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * postcode: funcs.postcode({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + postcode: createGenerator(GeneratePostcode), + // uniquePostcoe: createGenerator(GenerateUniquePostcode), + + /** + * generates states of America. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * state: funcs.state() + * }, + * }, + * })); + * ``` + */ + state: createGenerator(GenerateState), + + /** + * generates company's names. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * company: funcs.companyName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + companyName: createGenerator(GenerateCompanyName), + // uniqueCompanyName: createGenerator(GenerateUniqueCompanyName), + + /** + * generates 'lorem ipsum' text sentences. + * + * @param sentencesCount - number of sentences you want to generate as one generated value(string). + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.loremIpsum({sentencesCount: 2}) + * }, + * }, + * })); + * ``` + */ + loremIpsum: createGenerator(GenerateLoremIpsum), + + /** + * generates 2D points within specified ranges for x and y coordinates. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param minXValue - lower bound of range for x coordinate. + * @param maxXValue - upper bound of range for x coordinate. + * @param minYValue - lower bound of range for y coordinate. + * @param maxYValue - upper bound of range for y coordinate. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * triangles: { + * columns: { + * pointCoords: funcs.point({ + * isUnique: true, + * minXValue: -5, maxXValue:20, + * minYValue: 0, maxYValue: 30 + * }) + * }, + * }, + * })); + * ``` + */ + point: createGenerator(GeneratePoint), + // uniquePoint: createGenerator(GenerateUniquePoint), + + /** + * generates 2D lines within specified ranges for a, b and c parameters of line. + * + * ``` + * line equation: a*x + b*y + c = 0 + * ``` + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param minAValue - lower bound of range for a parameter. + * @param maxAValue - upper bound of range for x parameter. + * @param minBValue - lower bound of range for y parameter. + * @param maxBValue - upper bound of range for y parameter. + * @param minCValue - lower bound of range for y parameter. + * @param maxCValue - upper bound of range for y parameter. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * lines: { + * columns: { + * lineParams: funcs.point({ + * isUnique: true, + * minAValue: -5, maxAValue:20, + * minBValue: 0, maxBValue: 30, + * minCValue: 0, maxCValue: 10 + * }) + * }, + * }, + * })); + * ``` + */ + line: createGenerator(GenerateLine), + // uniqueLine: createGenerator(GenerateUniqueLine), + + /** + * gives you the opportunity to call different generators with different probabilities to generate values for one column. + * @param params - array of generators with probabilities you would like to call them to generate values. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.weightedRandom([ + * { + * weight: 0.6, + * value: funcs.loremIpsum({ sentencesCount: 3 }), + * }, + * { + * weight: 0.4, + * value: funcs.default({ defaultValue: "TODO" }), + * }, + * ]), + * }, + * }, + * })); + * ``` + */ + weightedRandom: createGenerator(WeightedRandomGenerator), +}; diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts new file mode 100644 index 000000000..d5166faae --- /dev/null +++ b/drizzle-seed/src/services/SeedService.ts @@ -0,0 +1,1160 @@ +import { entityKind, is } from 'drizzle-orm'; +import type { MySqlTable } from 'drizzle-orm/mysql-core'; +import { MySqlDatabase } from 'drizzle-orm/mysql-core'; +import type { PgTable } from 'drizzle-orm/pg-core'; +import { PgDatabase } from 'drizzle-orm/pg-core'; +import { PgliteSession } from 'drizzle-orm/pglite'; +import type { SQLiteTable } from 'drizzle-orm/sqlite-core'; +import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core'; +import type { + GeneratePossibleGeneratorsColumnType, + GeneratePossibleGeneratorsTableType, + RefinementsType, + TableGeneratorsType, +} from '../types/seedService.ts'; +import type { Column, Prettify, Relation, Table } from '../types/tables.ts'; +import type { AbstractGenerator } from './GeneratorsWrappers.ts'; +import { + GenerateBoolean, + GenerateDate, + GenerateDatetime, + GenerateDefault, + GenerateEmail, + GenerateEnum, + GenerateFirstName, + GenerateInt, + GenerateInterval, + GenerateIntPrimaryKey, + GenerateJson, + GenerateLine, + GenerateNumber, + GeneratePoint, + GenerateSelfRelationsValuesFromArray, + GenerateString, + GenerateTime, + GenerateTimestamp, + GenerateUniqueString, + GenerateValuesFromArray, + GenerateWeightedCount, + GenerateYear, + HollowGenerator, +} from './GeneratorsWrappers.ts'; +import { generateHashFromString } from './utils.ts'; + +class SeedService { + static readonly [entityKind]: string = 'SeedService'; + + private defaultCountForTable = 10; + private postgresPgLiteMaxParametersNumber = 32740; + private postgresMaxParametersNumber = 65535; + // there is no max parameters number in mysql, so you can increase mysqlMaxParametersNumber if it's needed. + private mysqlMaxParametersNumber = 100000; + // SQLITE_MAX_VARIABLE_NUMBER, which by default equals to 999 for SQLite versions prior to 3.32.0 (2020-05-22) or 32766 for SQLite versions after 3.32.0. + private sqliteMaxParametersNumber = 32766; + + generatePossibleGenerators = ( + connectionType: 'postgresql' | 'mysql' | 'sqlite', + tables: Table[], + relations: Relation[], + refinements?: RefinementsType, + options?: { count?: number; seed?: number }, + ) => { + let columnPossibleGenerator: Prettify; + let tablePossibleGenerators: Prettify; + const customSeed = options?.seed === undefined ? 0 : options.seed; + + // sorting table in order which they will be filled up (tables with foreign keys case) + // relations = relations.filter(rel => rel.type === "one"); + const tablesInOutRelations = this.getTablesInOutRelations(relations); + const orderedTablesNames = this.getOrderedTablesList(tablesInOutRelations); + tables = tables.sort((table1, table2) => { + const table1Order = orderedTablesNames.indexOf( + table1.name, + ), + table2Order = orderedTablesNames.indexOf( + table2.name, + ); + return table1Order - table2Order; + }); + + const tablesPossibleGenerators: Prettify< + (typeof tablePossibleGenerators)[] + > = tables.map((table) => ({ + tableName: table.name, + columnsPossibleGenerators: [], + withFromTable: {}, + })); + + for (const [i, table] of tables.entries()) { + // get foreignKey columns relations + const foreignKeyColumns: { + [columnName: string]: { table: string; column: string }; + } = {}; + + for ( + const rel of relations + .filter((rel) => rel.table === table.name) + ) { + for (const [idx, col] of rel.columns.entries()) { + foreignKeyColumns[col] = { + table: rel.refTable, + column: rel.refColumns[idx] as string, + }; + } + } + + if (refinements !== undefined && refinements[table.name] !== undefined) { + if (refinements[table.name]!.count !== undefined) { + tablesPossibleGenerators[i]!.count = refinements[table.name]!.count; + } + + if (refinements[table.name]!.with !== undefined) { + tablesPossibleGenerators[i]!.count = refinements[table.name]!.count + || options?.count + || this.defaultCountForTable; + let idx: number; + for ( + const fkTableName of Object.keys( + refinements[table.name]!.with as {}, + ) + ) { + if (!tablesInOutRelations[table.name]?.dependantTableNames.has(fkTableName)) { + const reason = tablesInOutRelations[table.name]?.selfRelation === true + ? `"${table.name}" table has self reference` + : `"${fkTableName}" table doesn't have reference to "${table.name}" table`; + throw new Error( + `${reason}. you can't specify "${fkTableName}" as parameter in ${table.name}.with object.`, + ); + } + + idx = tablesPossibleGenerators.findIndex( + (table) => table.tableName === fkTableName, + ); + if (idx !== -1) { + let newTableWithCount: number, + weightedCountSeed: number | undefined; + if ( + typeof refinements![table.name]!.with![fkTableName] === 'number' + ) { + newTableWithCount = (tablesPossibleGenerators[i]!.withCount + || tablesPossibleGenerators[i]!.count)! + * (refinements[table.name]!.with![fkTableName] as number); + } else { + const weightedRepeatedValuesCount = refinements[table.name]! + .with![fkTableName] as { + weight: number; + count: number | number[]; + }[]; + + weightedCountSeed = customSeed + + generateHashFromString(`${table.name}.${fkTableName}`); + + newTableWithCount = this.getWeightedWithCount( + weightedRepeatedValuesCount, + (tablesPossibleGenerators[i]!.withCount + || tablesPossibleGenerators[i]!.count)!, + weightedCountSeed, + ); + } + + if ( + tablesPossibleGenerators[idx]!.withCount === undefined + || newTableWithCount > tablesPossibleGenerators[idx]!.withCount! + ) { + tablesPossibleGenerators[idx]!.withCount = newTableWithCount; + } + + tablesPossibleGenerators[idx]!.withFromTable[table.name] = { + repeatedValuesCount: refinements[table.name]!.with![fkTableName]!, + weightedCountSeed, + }; + } + } + } + } + tablePossibleGenerators = tablesPossibleGenerators[i]!; + for (const col of table.columns) { + // col.myType = typeMap[col._type as keyof typeof typeMap]; + columnPossibleGenerator = { + columnName: col.name, + isUnique: col.isUnique, + notNull: col.notNull, + generatedIdentityType: col.generatedIdentityType, + generator: undefined, + }; + + if ( + refinements !== undefined + && refinements[table.name] !== undefined + && refinements[table.name]!.columns !== undefined + && refinements[table.name]!.columns[col.name] !== undefined + ) { + const genObj = refinements[table.name]!.columns[col.name]!; + // for now only GenerateValuesFromArray support notNull property + genObj.notNull = col.notNull; + + columnPossibleGenerator.generator = genObj; + } else if (Object.hasOwn(foreignKeyColumns, col.name)) { + // TODO: I might need to assign repeatedValuesCount to column there instead of doing so in generateTablesValues + columnPossibleGenerator.generator = new HollowGenerator({}); + } else if (col.hasDefault && col.default !== undefined) { + columnPossibleGenerator.generator = new GenerateDefault({ + defaultValue: col.default, + }); + } // TODO: rewrite pickGeneratorFor... using new col properties: isUnique and notNull + else if (connectionType === 'postgresql') { + columnPossibleGenerator = this.pickGeneratorForPostgresColumn( + columnPossibleGenerator, + table, + col, + ); + } else if (connectionType === 'mysql') { + columnPossibleGenerator = this.pickGeneratorForMysqlColumn( + columnPossibleGenerator, + table, + col, + ); + } else if (connectionType === 'sqlite') { + columnPossibleGenerator = this.pickGeneratorForSqlite( + columnPossibleGenerator, + table, + col, + ); + } + + if (columnPossibleGenerator.generator === undefined) { + throw new Error( + `column with type ${col.columnType} is not supported for now.`, + ); + } + + columnPossibleGenerator.generator.isUnique = col.isUnique; + columnPossibleGenerator.generator.dataType = col.dataType; + tablePossibleGenerators.columnsPossibleGenerators.push( + columnPossibleGenerator, + ); + } + } + + return tablesPossibleGenerators; + }; + + getOrderedTablesList = (tablesInOutRelations: ReturnType): string[] => { + const leafTablesNames = Object.entries(tablesInOutRelations) + .filter( + (tableRel) => + tableRel[1].out === 0 + || (tableRel[1].out !== 0 + && tableRel[1].selfRelCount === tableRel[1].out), + ) + .map((tableRel) => tableRel[0]); + + const orderedTablesNames: string[] = []; + let parent: string, children: string[]; + for (let i = 0; leafTablesNames.length !== 0; i++) { + parent = leafTablesNames.shift() as string; + + if (orderedTablesNames.includes(parent)) { + continue; + } + + if (tablesInOutRelations[parent] === undefined) { + orderedTablesNames.push(parent); + continue; + } + + for (const orderedTableName of orderedTablesNames) { + tablesInOutRelations[parent]!.requiredTableNames.delete(orderedTableName); + } + + if (tablesInOutRelations[parent]!.requiredTableNames.size === 0) { + orderedTablesNames.push(parent); + } else { + leafTablesNames.push(parent); + continue; + } + + children = [...tablesInOutRelations[parent]!.dependantTableNames]; + leafTablesNames.push(...children); + } + return orderedTablesNames; + }; + + getTablesInOutRelations = (relations: Relation[]) => { + const tablesInOutRelations: { + [tableName: string]: { + out: number; + in: number; + selfRelation: boolean; + selfRelCount: number; + requiredTableNames: Set; + dependantTableNames: Set; + }; + } = {}; + + for (const rel of relations) { + if (tablesInOutRelations[rel.table] === undefined) { + tablesInOutRelations[rel.table] = { + out: 0, + in: 0, + selfRelation: false, + selfRelCount: 0, + requiredTableNames: new Set(), + dependantTableNames: new Set(), + }; + } + + if (tablesInOutRelations[rel.refTable] === undefined) { + tablesInOutRelations[rel.refTable] = { + out: 0, + in: 0, + selfRelation: false, + selfRelCount: 0, + requiredTableNames: new Set(), + dependantTableNames: new Set(), + }; + } + + tablesInOutRelations[rel.table]!.out += 1; + tablesInOutRelations[rel.refTable]!.in += 1; + + if (rel.refTable === rel.table) { + tablesInOutRelations[rel.table]!.selfRelation = true; + tablesInOutRelations[rel.table]!.selfRelCount = rel.columns.length; + } else { + tablesInOutRelations[rel.table]!.requiredTableNames.add(rel.refTable); + tablesInOutRelations[rel.refTable]!.dependantTableNames.add(rel.table); + } + } + + return tablesInOutRelations; + }; + + getWeightedWithCount = ( + weightedCount: { weight: number; count: number | number[] }[], + count: number, + seed: number, + ) => { + const gen = new GenerateWeightedCount({}); + gen.init({ count: weightedCount, seed }); + let weightedWithCount = 0; + for (let i = 0; i < count; i++) { + weightedWithCount += gen.generate(); + } + + return weightedWithCount; + }; + + // TODO: revise serial part generators + pickGeneratorForPostgresColumn = ( + columnPossibleGenerator: Prettify, + table: Table, + col: Column, + ) => { + // INT ------------------------------------------------------------------------------------------------------------ + if ( + (col.columnType.includes('serial') + || col.columnType === 'integer' + || col.columnType === 'smallint' + || col.columnType.includes('bigint')) + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateIntPrimaryKey({}); + return columnPossibleGenerator; + } + + let minValue: number | bigint | undefined; + let maxValue: number | bigint | undefined; + if (col.columnType.includes('serial')) { + minValue = 1; + if (col.columnType === 'smallserial') { + // 2^16 / 2 - 1, 2 bytes + maxValue = 32767; + } else if (col.columnType === 'serial') { + // 2^32 / 2 - 1, 4 bytes + maxValue = 2147483647; + } else if (col.columnType === 'bigserial') { + // 2^64 / 2 - 1, 8 bytes + minValue = BigInt(1); + maxValue = BigInt('9223372036854775807'); + } + } else if (col.columnType.includes('int')) { + if (col.columnType === 'smallint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -32768; + maxValue = 32767; + } else if (col.columnType === 'integer') { + // 2^32 / 2 - 1, 4 bytes + minValue = -2147483648; + maxValue = 2147483647; + } else if (col.columnType.includes('bigint')) { + if (col.dataType === 'bigint') { + // 2^64 / 2 - 1, 8 bytes + minValue = BigInt('-9223372036854775808'); + maxValue = BigInt('9223372036854775807'); + } else if (col.dataType === 'number') { + // if you’re expecting values above 2^31 but below 2^53 + minValue = -9007199254740991; + maxValue = 9007199254740991; + } + } + } + + if ( + col.columnType.includes('int') + && !col.columnType.includes('interval') + && !col.columnType.includes('point') + ) { + columnPossibleGenerator.generator = new GenerateInt({ + minValue, + maxValue, + }); + return columnPossibleGenerator; + } + + if (col.columnType.includes('serial')) { + const genObj = new GenerateIntPrimaryKey({}); + genObj.maxValue = maxValue; + columnPossibleGenerator.generator = genObj; + } + + // NUMBER(real, double, decimal, numeric) + if ( + col.columnType === 'real' + || col.columnType === 'doubleprecision' + || col.columnType === 'decimal' + || col.columnType === 'numeric' + ) { + columnPossibleGenerator.generator = new GenerateNumber({}); + return columnPossibleGenerator; + } + + // STRING + if ( + (col.columnType === 'text' + || col.columnType === 'varchar' + || col.columnType === 'char') + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateUniqueString({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'varchar' + || col.columnType === 'char') + && col.name.toLowerCase().includes('name') + ) { + columnPossibleGenerator.generator = new GenerateFirstName({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'varchar' + || col.columnType === 'char') + && col.name.toLowerCase().includes('email') + ) { + columnPossibleGenerator.generator = new GenerateEmail({}); + return columnPossibleGenerator; + } + + if ( + col.columnType === 'text' + || col.columnType === 'varchar' + || col.columnType === 'char' + ) { + // console.log(col, table) + columnPossibleGenerator.generator = new GenerateString({}); + return columnPossibleGenerator; + } + + // BOOLEAN + if (col.columnType === 'boolean') { + columnPossibleGenerator.generator = new GenerateBoolean({}); + return columnPossibleGenerator; + } + + // DATE, TIME, TIMESTAMP + if (col.columnType.includes('date')) { + columnPossibleGenerator.generator = new GenerateDate({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'time') { + columnPossibleGenerator.generator = new GenerateTime({}); + return columnPossibleGenerator; + } + + if (col.columnType.includes('timestamp')) { + columnPossibleGenerator.generator = new GenerateTimestamp({}); + return columnPossibleGenerator; + } + + // JSON, JSONB + if (col.columnType === 'json' || col.columnType === 'jsonb') { + columnPossibleGenerator.generator = new GenerateJson({}); + return columnPossibleGenerator; + } + + // if (col.columnType === "jsonb") { + // columnPossibleGenerator.generator = new GenerateJsonb({}); + // return columnPossibleGenerator; + // } + + // ENUM + if (col.enumValues !== undefined) { + columnPossibleGenerator.generator = new GenerateEnum({ + enumValues: col.enumValues, + }); + return columnPossibleGenerator; + } + + // INTERVAL + if (col.columnType === 'interval') { + columnPossibleGenerator.generator = new GenerateInterval({}); + return columnPossibleGenerator; + } + + // POINT, LINE + if (col.columnType.includes('point')) { + columnPossibleGenerator.generator = new GeneratePoint({}); + return columnPossibleGenerator; + } + + if (col.columnType.includes('line')) { + columnPossibleGenerator.generator = new GenerateLine({}); + return columnPossibleGenerator; + } + + return columnPossibleGenerator; + }; + + pickGeneratorForMysqlColumn = ( + columnPossibleGenerator: Prettify, + table: Table, + col: Column, + ) => { + // console.log(col); + // INT ------------------------------------------------------------------------------------------------------------ + if ( + (col.columnType.includes('serial') || col.columnType.includes('int')) + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateIntPrimaryKey({}); + return columnPossibleGenerator; + } + + let minValue: number | bigint | undefined; + let maxValue: number | bigint | undefined; + if (col.columnType === 'serial') { + // 2^64 % 2 - 1, 8 bytes + minValue = BigInt(0); + maxValue = BigInt('9223372036854775807'); + } else if (col.columnType.includes('int')) { + if (col.columnType === 'tinyint') { + // 2^8 / 2 - 1, 1 bytes + minValue = -128; + maxValue = 127; + } else if (col.columnType === 'smallint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -32768; + maxValue = 32767; + } else if (col.columnType === 'mediumint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -8388608; + maxValue = 8388607; + } else if (col.columnType === 'int') { + // 2^32 / 2 - 1, 4 bytes + minValue = -2147483648; + maxValue = 2147483647; + } else if (col.columnType === 'bigint') { + // 2^64 / 2 - 1, 8 bytes + minValue = BigInt('-9223372036854775808'); + maxValue = BigInt('9223372036854775807'); + } + } + + if (col.columnType.includes('int')) { + columnPossibleGenerator.generator = new GenerateInt({ + minValue, + maxValue, + }); + return columnPossibleGenerator; + } + + if (col.columnType.includes('serial')) { + const genObj = new GenerateIntPrimaryKey({}); + genObj.maxValue = maxValue; + columnPossibleGenerator.generator = genObj; + } + + // NUMBER(real, double, decimal, float) + if ( + col.columnType === 'real' + || col.columnType === 'double' + || col.columnType === 'decimal' + || col.columnType === 'float' + ) { + columnPossibleGenerator.generator = new GenerateNumber({}); + return columnPossibleGenerator; + } + + // STRING + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.includes('char') + || col.columnType.includes('varchar') + || col.columnType.includes('binary') + || col.columnType.includes('varbinary')) + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateUniqueString({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.includes('char') + || col.columnType.includes('varchar') + || col.columnType.includes('binary') + || col.columnType.includes('varbinary')) + && col.name.toLowerCase().includes('name') + ) { + columnPossibleGenerator.generator = new GenerateFirstName({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.includes('char') + || col.columnType.includes('varchar') + || col.columnType.includes('binary') + || col.columnType.includes('varbinary')) + && col.name.toLowerCase().includes('email') + ) { + columnPossibleGenerator.generator = new GenerateEmail({}); + return columnPossibleGenerator; + } + + if ( + col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.includes('char') + || col.columnType.includes('varchar') + || col.columnType.includes('binary') + || col.columnType.includes('varbinary') + ) { + // console.log(col, table); + columnPossibleGenerator.generator = new GenerateString({}); + return columnPossibleGenerator; + } + + // BOOLEAN + if (col.columnType === 'boolean') { + columnPossibleGenerator.generator = new GenerateBoolean({}); + return columnPossibleGenerator; + } + + // DATE, TIME, TIMESTAMP, DATETIME, YEAR + if (col.columnType.includes('datetime')) { + columnPossibleGenerator.generator = new GenerateDatetime({}); + return columnPossibleGenerator; + } + + if (col.columnType.includes('date')) { + columnPossibleGenerator.generator = new GenerateDate({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'time') { + columnPossibleGenerator.generator = new GenerateTime({}); + return columnPossibleGenerator; + } + + if (col.columnType.includes('timestamp')) { + columnPossibleGenerator.generator = new GenerateTimestamp({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'year') { + columnPossibleGenerator.generator = new GenerateYear({}); + return columnPossibleGenerator; + } + + // JSON + if (col.columnType === 'json') { + columnPossibleGenerator.generator = new GenerateJson({}); + return columnPossibleGenerator; + } + + // ENUM + if (col.enumValues !== undefined) { + columnPossibleGenerator.generator = new GenerateEnum({ + enumValues: col.enumValues, + }); + return columnPossibleGenerator; + } + + return columnPossibleGenerator; + }; + + pickGeneratorForSqlite = ( + columnPossibleGenerator: Prettify, + table: Table, + col: Column, + ) => { + // int section --------------------------------------------------------------------------------------- + if ( + (col.columnType === 'integer' || col.columnType === 'numeric') + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateIntPrimaryKey({}); + return columnPossibleGenerator; + } + + if ( + col.columnType === 'integer' + || col.columnType === 'numeric' + || col.columnType === 'bigint' + ) { + columnPossibleGenerator.generator = new GenerateInt({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'boolean') { + columnPossibleGenerator.generator = new GenerateBoolean({}); + return columnPossibleGenerator; + } + + // number section ------------------------------------------------------------------------------------ + if (col.columnType === 'real' || col.columnType === 'numeric') { + columnPossibleGenerator.generator = new GenerateNumber({}); + return columnPossibleGenerator; + } + + // string section ------------------------------------------------------------------------------------ + if ( + (col.columnType === 'text' + || col.columnType === 'numeric' + || col.columnType === 'blob') + && table.primaryKeys.includes(col.name) + ) { + columnPossibleGenerator.generator = new GenerateUniqueString({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'numeric' + || col.columnType === 'blob') + && col.name.toLowerCase().includes('name') + ) { + columnPossibleGenerator.generator = new GenerateFirstName({}); + return columnPossibleGenerator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'numeric' + || col.columnType === 'blob') + && col.name.toLowerCase().includes('email') + ) { + columnPossibleGenerator.generator = new GenerateEmail({}); + return columnPossibleGenerator; + } + + if ( + col.columnType === 'text' + || col.columnType === 'numeric' + || col.columnType === 'blob' + || col.columnType === 'blobbuffer' + ) { + columnPossibleGenerator.generator = new GenerateString({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'textjson' || col.columnType === 'blobjson') { + columnPossibleGenerator.generator = new GenerateJson({}); + return columnPossibleGenerator; + } + + if (col.columnType === 'timestamp' || col.columnType === 'timestamp_ms') { + columnPossibleGenerator.generator = new GenerateTimestamp({}); + return columnPossibleGenerator; + } + + return columnPossibleGenerator; + }; + + generateTablesValues = async ( + relations: Relation[], + tablesGenerators: ReturnType, + db?: + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + schema?: { [key: string]: PgTable | MySqlTable | SQLiteTable }, + options?: { count?: number; seed?: number; preserveData?: boolean; insertDataInDb?: boolean }, + ) => { + // console.time( + // "generateTablesValues-----------------------------------------------------" + // ); + const customSeed = options?.seed === undefined ? 0 : options.seed; + let tableCount: number | undefined; + let columnsGenerators: Prettify[]; + let tableGenerators: Prettify; + + let tableValues: { + [columnName: string]: string | number | boolean | undefined; + }[]; + + let tablesValues: { + tableName: string; + rows: typeof tableValues; + }[] = []; + + let pRNGSeed: number; + // relations = relations.filter(rel => rel.type === "one"); + let filteredRelations: Relation[]; + + let preserveData: boolean, insertDataInDb: boolean = true; + if (options?.preserveData !== undefined) preserveData = options.preserveData; + if (options?.insertDataInDb !== undefined) insertDataInDb = options.insertDataInDb; + + // TODO: now I'm generating tablesInOutRelations twice, first time in generatePossibleGenerators and second time here. maybe should generate it once instead. + const tablesInOutRelations = this.getTablesInOutRelations(relations); + for (const table of tablesGenerators) { + tableCount = table.count === undefined ? options?.count || this.defaultCountForTable : table.count; + + tableGenerators = {}; + columnsGenerators = table.columnsPossibleGenerators; + + filteredRelations = relations.filter( + (rel) => rel.table === table.tableName, + ); + + // adding pRNG seed to column + for (const col of columnsGenerators) { + const columnRelations = filteredRelations.filter((rel) => rel.columns.includes(col.columnName)); + pRNGSeed = (columnRelations.length !== 0 + && columnRelations[0]!.columns.length >= 2) + ? (customSeed + generateHashFromString( + `${columnRelations[0]!.table}.${columnRelations[0]!.columns.join('_')}`, + )) + : (customSeed + generateHashFromString(`${table.tableName}.${col.columnName}`)); + + tableGenerators[col.columnName] = { + pRNGSeed, + ...col, + }; + } + + // get values to generate columns with foreign key + + // if table posts contains foreign key to table users, then rel.table === 'posts' and rel.refTable === 'users', because table posts has reference to table users. + if (filteredRelations.length !== 0) { + for (const rel of filteredRelations) { + if ( + table.withFromTable[rel.refTable] !== undefined + && table.withCount !== undefined + ) { + tableCount = table.withCount; + } + + for (let colIdx = 0; colIdx < rel.columns.length; colIdx++) { + let refColumnValues: (string | number | boolean)[]; + let hasSelfRelation: boolean; + let repeatedValuesCount: + | number + | { weight: number; count: number | number[] }[] + | undefined, + weightedCountSeed: number | undefined; + let genObj: AbstractGenerator; + + if (rel.table === rel.refTable) { + const refColName = rel.refColumns[colIdx] as string; + pRNGSeed = generateHashFromString( + `${table.tableName}.${refColName}`, + ); + + const refColumnGenerator: typeof tableGenerators = {}; + refColumnGenerator[refColName] = { + ...tableGenerators[refColName]!, + pRNGSeed, + }; + + refColumnValues = (await this.generateColumnsValuesByGenerators({ + tableGenerators: refColumnGenerator, + count: tableCount, + preserveData: true, + insertDataInDb: false, + }))!.map((rows) => rows[refColName]) as (string | number | boolean)[]; + + hasSelfRelation = true; + genObj = new GenerateSelfRelationsValuesFromArray({ + values: refColumnValues, + }); + } else { + refColumnValues = tablesValues + .find((val) => val.tableName === rel.refTable)! + .rows!.map((row) => row[rel.refColumns[colIdx]!]!); + hasSelfRelation = false; + + if ( + table.withFromTable[rel.refTable] !== undefined + && table.withFromTable[rel.refTable]!.repeatedValuesCount + !== undefined + ) { + repeatedValuesCount = table.withFromTable[rel.refTable]!.repeatedValuesCount; + weightedCountSeed = table.withFromTable[rel.refTable]!.weightedCountSeed; + } + + genObj = new GenerateValuesFromArray({ values: refColumnValues }); + (genObj as GenerateValuesFromArray).notNull = tableGenerators[rel.columns[colIdx]!]!.notNull; + (genObj as GenerateValuesFromArray).weightedCountSeed = weightedCountSeed; + (genObj as GenerateValuesFromArray).maxRepeatedValuesCount = repeatedValuesCount; + } + + // console.log(rel.columns[colIdx], tableGenerators) + tableGenerators[rel.columns[colIdx]!]!.generator = genObj; + tableGenerators[rel.columns[colIdx]!] = { + ...tableGenerators[rel.columns[colIdx]!]!, + hasSelfRelation, + hasRelation: true, + }; + } + } + } + + preserveData = ( + options?.preserveData === undefined + && tablesInOutRelations[table.tableName]?.in === 0 + ) + ? false + : true; + + tableValues = await this.generateColumnsValuesByGenerators({ + tableGenerators, + db, + schema, + tableName: table.tableName, + count: tableCount, + preserveData, + insertDataInDb, + }); + + if (preserveData === true) { + tablesValues.push({ + tableName: table.tableName, + rows: tableValues, + }); + } + + // removing "link" from table that was required to generate current table + if (tablesInOutRelations[table.tableName] !== undefined) { + for (const tableName of tablesInOutRelations[table.tableName]!.requiredTableNames) { + tablesInOutRelations[tableName]!.in -= 1; + } + } + + if (preserveData === false) { + tablesValues = tablesValues.filter( + (table) => + tablesInOutRelations[table.tableName] !== undefined && tablesInOutRelations[table.tableName]!.in > 0, + ); + } + } + + return tablesValues; + }; + + generateColumnsValuesByGenerators = async ({ + tableGenerators, + db, + schema, + tableName, + count, + preserveData = true, + insertDataInDb = true, + batchSize = 10000, + }: { + tableGenerators: Prettify; + db?: + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase; + schema?: { [key: string]: PgTable | MySqlTable | SQLiteTable }; + tableName?: string; + count?: number; + preserveData?: boolean; + insertDataInDb?: boolean; + batchSize?: number; + }) => { + if (count === undefined) { + count = this.defaultCountForTable; + } + + let columnGenerator: (typeof tableGenerators)[string]; + const columnsGenerators: { + [columnName: string]: AbstractGenerator; + } = {}; + let generatedValues: { [columnName: string]: number | string | boolean | undefined }[] = []; + + let columnsNumber = 0; + let override = false; + for (const columnName of Object.keys(tableGenerators)) { + columnsNumber += 1; + columnGenerator = tableGenerators[columnName]!; + override = tableGenerators[columnName]?.generatedIdentityType === 'always' ? true : override; + + columnsGenerators[columnName] = columnGenerator.generator!; + columnsGenerators[columnName]!.init({ + count, + seed: columnGenerator.pRNGSeed, + }); + + if ( + columnsGenerators[columnName]!.uniqueVersionOfGen !== undefined + && columnsGenerators[columnName]!.isUnique === true + ) { + const uniqueGen = new columnsGenerators[columnName]!.uniqueVersionOfGen!({ + ...columnsGenerators[columnName]!.params, + }); + uniqueGen.init({ + count, + seed: columnGenerator.pRNGSeed, + }); + uniqueGen.isUnique = columnsGenerators[columnName]!.isUnique; + uniqueGen.dataType = columnsGenerators[columnName]!.dataType; + + columnsGenerators[columnName] = uniqueGen; + } + } + let maxParametersNumber: number; + if (is(db, PgDatabase)) { + maxParametersNumber = is(db._.session, PgliteSession) + ? this.postgresPgLiteMaxParametersNumber + : this.postgresMaxParametersNumber; + } else if (is(db, MySqlDatabase)) { + maxParametersNumber = this.mysqlMaxParametersNumber; + } else { + // is(db, BaseSQLiteDatabase) + maxParametersNumber = this.sqliteMaxParametersNumber; + } + const maxBatchSize = Math.floor(maxParametersNumber / columnsNumber); + batchSize = batchSize > maxBatchSize ? maxBatchSize : batchSize; + + if ( + insertDataInDb === true + && (db === undefined || schema === undefined || tableName === undefined) + ) { + throw new Error('db or schema or tableName is undefined.'); + } + + let row: { [columnName: string]: string | number | boolean }, + generatedValue, + i: number; + + for (i = 0; i < count; i++) { + row = {}; + generatedValues.push(row); + + for (const columnName of Object.keys(columnsGenerators)) { + // generatedValue = columnsGenerators[columnName].next().value as + // | string + // | number + // | boolean; + generatedValue = columnsGenerators[columnName]!.generate({ i }) as + | string + | number + | boolean; + row[columnName as keyof typeof row] = generatedValue; + } + + if ( + insertDataInDb === true + && ((i + 1) % batchSize === 0 || i === count - 1) + ) { + if (preserveData === false) { + await this.insertInDb({ + generatedValues, + db: db as + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + schema: schema as { + [key: string]: PgTable | MySqlTable | SQLiteTable; + }, + tableName: tableName as string, + override, + }); + generatedValues = []; + } else { + const batchCount = Math.floor(i / batchSize); + + await this.insertInDb({ + generatedValues: generatedValues.slice( + batchSize * batchCount, + batchSize * (batchCount + 1), + ), + db: db as + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + schema: schema as { + [key: string]: PgTable | MySqlTable | SQLiteTable; + }, + tableName: tableName as string, + override, + }); + } + } + } + + return preserveData === true ? generatedValues : []; + }; + + insertInDb = async ({ + generatedValues, + db, + schema, + tableName, + override, + }: { + generatedValues: { + [columnName: string]: number | string | boolean | undefined; + }[]; + db: + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase; + schema: { + [key: string]: PgTable | MySqlTable | SQLiteTable; + }; + tableName: string; + override: boolean; + }) => { + if (is(db, PgDatabase)) { + const query = db.insert((schema as { [key: string]: PgTable })[tableName]!); + if (override === true) { + return await query.overridingSystemValue().values(generatedValues); + } + await query.values(generatedValues); + } else if (is(db, MySqlDatabase)) { + await db + .insert((schema as { [key: string]: MySqlTable })[tableName]!) + .values(generatedValues); + } else if (is(db, BaseSQLiteDatabase)) { + await db + .insert((schema as { [key: string]: SQLiteTable })[tableName]!) + .values(generatedValues); + } + }; +} + +export default new SeedService(); diff --git a/drizzle-seed/src/services/utils.ts b/drizzle-seed/src/services/utils.ts new file mode 100644 index 000000000..6f59fc63c --- /dev/null +++ b/drizzle-seed/src/services/utils.ts @@ -0,0 +1,83 @@ +export const fastCartesianProduct = (sets: (number | string | boolean | object)[][], index: number) => { + const resultList = []; + let currSet: (typeof sets)[number]; + let element: (typeof sets)[number][number]; + + for (let i = sets.length - 1; i >= 0; i--) { + currSet = sets[i]!; + element = currSet[index % currSet.length]!; + resultList.unshift(element); + index = Math.floor(index / currSet.length); + } + + return resultList; +}; + +/** + * @param weights positive number in range [0, 1], that represents probabilities to choose index of array. Example: weights = [0.2, 0.8] + * @param [accuracy=100] approximate number of elements in returning array + * @returns Example: with weights = [0.2, 0.8] and accuracy = 10 returning array of indices gonna equal this: [0, 0, 1, 1, 1, 1, 1, 1, 1, 1] + */ +export const getWeightedIndices = (weights: number[], accuracy = 100) => { + const weightsSum = weights.reduce((acc, currVal) => acc + currVal, 0); + if (weightsSum !== 1) { + throw new Error(`sum of all weights don't equal to 1; ${weightsSum} !== 1`); + } + + // const accuracy = 100; + const weightedIndices: number[] = []; + for (const [index, weight] of weights.entries()) { + const ticketsNumb = Math.floor(weight * accuracy); + weightedIndices.push(...Array.from({ length: ticketsNumb }).fill(index)); + } + + return weightedIndices; +}; + +export const generateHashFromString = (s: string) => { + let hash = 0; + // p and m are prime numbers + const p = 53; + const m = 28871271685163; + + for (let i = 0; i < s.length; i++) { + hash += ((s.codePointAt(i) || 0) * Math.pow(p, i)) % m; + } + + return hash; +}; + +/** + * @param param0.template example: "#####" or "#####-####" + * @param param0.values example: ["3", "2", "h"] + * @param param0.defaultValue example: "0" + * @returns + */ +export const fillTemplate = ({ template, placeholdersCount, values, defaultValue = ' ' }: { + template: string; + placeholdersCount?: number; + values: string[]; + defaultValue?: string; +}) => { + if (placeholdersCount === undefined) { + const iterArray = [...template.matchAll(/#/g)]; + placeholdersCount = iterArray.length; + } + + const diff = placeholdersCount - values.length; + if (diff > 0) { + values.unshift(...Array.from({ length: diff }).fill(defaultValue)); + } + + let resultStr = '', valueIdx = 0; + for (const si of template) { + if (si === '#') { + resultStr += values[valueIdx]; + valueIdx += 1; + continue; + } + resultStr += si; + } + + return resultStr; +}; diff --git a/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts b/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts new file mode 100644 index 000000000..cfd275da0 --- /dev/null +++ b/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts @@ -0,0 +1,131 @@ +import lastNames from '../../datasets/lastNames.ts'; +import { + GenerateBoolean, + GenerateCity, + GenerateCompanyName, + GenerateCountry, + GenerateDate, + GenerateDatetime, + GenerateDefault, + GenerateEmail, + GenerateFirstName, + GenerateFullName, + GenerateInt, + GenerateInterval, + GenerateIntPrimaryKey, + GenerateJobTitle, + GenerateJson, + GenerateLastName, + GenerateLine, + GenerateLoremIpsum, + GenerateNumber, + GeneratePhoneNumber, + GeneratePoint, + GeneratePostcode, + GenerateState, + GenerateStreetAdddress, + GenerateString, + GenerateTime, + GenerateTimestamp, + GenerateUniqueCompanyName, + GenerateUniqueFullName, + GenerateUniqueInt, + GenerateUniqueInterval, + GenerateUniqueLine, + GenerateUniqueNumber, + GenerateUniquePoint, + GenerateUniquePostcode, + GenerateUniqueStreetAdddress, + GenerateUniqueString, + GenerateValuesFromArray, + GenerateYear, + WeightedRandomGenerator, +} from '../../services/GeneratorsWrappers.ts'; + +const benchmark = ({ generatorName, generator, count = 100000, seed = 1 }: { + generatorName: string; + generator: (typeof generatorsFuncs)[keyof typeof generatorsFuncs]; + count?: number; + seed?: number; +}) => { + generator.init({ count, seed }); + + let timeSpentToInit = 0, timeSpent = 0; + const t0 = new Date(); + + generator.init({ count, seed }); + timeSpentToInit += (Date.now() - t0.getTime()) / 1000; + + for (let i = 0; i < count; i++) { + const val = generator.generate({ i }); + if (val === undefined) { + console.log(val, `in ${generatorName} generator.`); + } + } + + timeSpent += (Date.now() - t0.getTime()) / 1000; + console.log(`${generatorName} spent ${timeSpentToInit} to init and spent ${timeSpent} to generate ${count} rows.`); + console.log( + 'time spent in particular code part:', + generator.timeSpent, + ';', + generator.timeSpent === undefined ? generator.timeSpent : (generator.timeSpent / timeSpent), + 'percent of all time', + ); + console.log('\n'); +}; + +const generatorsFuncs = { + default: new GenerateDefault({ defaultValue: 'defaultValue' }), + valuesFromArray: new GenerateValuesFromArray({ values: lastNames }), + intPrimaryKey: new GenerateIntPrimaryKey({}), + number: new GenerateNumber({}), + uniqueNumber: new GenerateUniqueNumber({}), + int: new GenerateInt({}), + uniqueInt: new GenerateUniqueInt({}), + boolean: new GenerateBoolean({}), + date: new GenerateDate({}), + time: new GenerateTime({}), + timestamp: new GenerateTimestamp({}), + datetime: new GenerateDatetime({}), + year: new GenerateYear({}), + json: new GenerateJson({}), + jsonb: new GenerateJson({}), + interval: new GenerateInterval({}), + uniqueInterval: new GenerateUniqueInterval({}), + string: new GenerateString({}), + uniqueString: new GenerateUniqueString({}), + firstName: new GenerateFirstName({}), + // uniqueFirstName: new GenerateUniqueName({}), + lastName: new GenerateLastName({}), + // uniqueLastName: new GenerateUniqueSurname({}), + fullName: new GenerateFullName({}), + uniqueFullName: new GenerateUniqueFullName({}), + email: new GenerateEmail({}), + phoneNumber: new GeneratePhoneNumber({ template: '+380 ## ## ### ##' }), + country: new GenerateCountry({}), + // uniqueCountry: new GenerateUniqueCountry({}), + city: new GenerateCity({}), + // uniqueCity: new GenerateUniqueCity({}), + streetAddress: new GenerateStreetAdddress({}), + uniqueStreetAddress: new GenerateUniqueStreetAdddress({}), + jobTitle: new GenerateJobTitle({}), + postcode: new GeneratePostcode({}), + uniquePostcode: new GenerateUniquePostcode({}), + state: new GenerateState({}), + companyName: new GenerateCompanyName({}), + uniqueCompanyName: new GenerateUniqueCompanyName({}), + loremIpsum: new GenerateLoremIpsum({}), + point: new GeneratePoint({}), + uniquePoint: new GenerateUniquePoint({}), + line: new GenerateLine({}), + uniqueLine: new GenerateUniqueLine({}), + weightedRandom: new WeightedRandomGenerator([ + { weight: 0.8, value: new GenerateUniqueInt({ minValue: 0, maxValue: 90000 }) }, + { weight: 0.2, value: new GenerateDefault({ defaultValue: Number.NaN }) }, + ]), +}; + +for (const [generatorName, generator] of Object.entries(generatorsFuncs)) { + benchmark({ generatorName, generator, count: 100000, seed: 1 }); +} diff --git a/drizzle-seed/src/tests/mysql/allDataTypesTest/drizzle.config.ts b/drizzle-seed/src/tests/mysql/allDataTypesTest/drizzle.config.ts new file mode 100644 index 000000000..78ff7a54b --- /dev/null +++ b/drizzle-seed/src/tests/mysql/allDataTypesTest/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/mysql/allDataTypesTest/mysqlSchema.ts', + out: './src/tests/mysql/allDataTypesTest/mysqlMigrations', + dialect: 'mysql', +}); diff --git a/drizzle-seed/src/tests/mysql/allDataTypesTest/mysqlSchema.ts b/drizzle-seed/src/tests/mysql/allDataTypesTest/mysqlSchema.ts new file mode 100644 index 000000000..217fe74e7 --- /dev/null +++ b/drizzle-seed/src/tests/mysql/allDataTypesTest/mysqlSchema.ts @@ -0,0 +1,56 @@ +import { + bigint, + binary, + boolean, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + mysqlEnum, + mysqlTable, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, +} from 'drizzle-orm/mysql-core'; + +export const allDataTypes = mysqlTable('all_data_types', { + int: int('integer'), + tinyint: tinyint('tinyint'), + smallint: smallint('smallint'), + mediumint: mediumint('mediumint'), + biginteger: bigint('bigint', { mode: 'bigint' }), + bigintNumber: bigint('bigint_number', { mode: 'number' }), + real: real('real'), + decimal: decimal('decimal'), + double: double('double'), + float: float('float'), + serial: serial('serial'), + binary: binary('binary', { length: 255 }), + varbinary: varbinary('varbinary', { length: 256 }), + char: char('char', { length: 255 }), + varchar: varchar('varchar', { length: 256 }), + text: text('text'), + boolean: boolean('boolean'), + dateString: date('date_string', { mode: 'string' }), + date: date('date', { mode: 'date' }), + datetime: datetime('datetime', { mode: 'date' }), + datetimeString: datetime('datetimeString', { mode: 'string' }), + time: time('time'), + year: year('year'), + timestampDate: timestamp('timestamp_date', { mode: 'date' }), + timestampString: timestamp('timestamp_string', { mode: 'string' }), + json: json('json'), + mysqlEnum: mysqlEnum('popularity', ['unknown', 'known', 'popular']), +}); diff --git a/drizzle-seed/src/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts b/drizzle-seed/src/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts new file mode 100644 index 000000000..dc663800e --- /dev/null +++ b/drizzle-seed/src/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts @@ -0,0 +1,121 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import type { MySql2Database } from 'drizzle-orm/mysql2'; +import { drizzle } from 'drizzle-orm/mysql2'; +import getPort from 'get-port'; +import type { Connection } from 'mysql2/promise'; +import { createConnection } from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, expect, test } from 'vitest'; +import { seed } from '../../../index.ts'; +import * as schema from './mysqlSchema.ts'; + +let mysqlContainer: Docker.Container; +let client: Connection; +let db: MySql2Database; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +beforeAll(async () => { + const connectionString = await createDockerDB(); + + const sleep = 1000; + let timeLeft = 40000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + const client = await createConnection(connectionString); + await client.connect(); + db = drizzle(client); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } + + await db.execute( + sql` + CREATE TABLE \`all_data_types\` ( + \`integer\` int, + \`tinyint\` tinyint, + \`smallint\` smallint, + \`mediumint\` mediumint, + \`bigint\` bigint, + \`bigint_number\` bigint, + \`real\` real, + \`decimal\` decimal, + \`double\` double, + \`float\` float, + \`serial\` serial AUTO_INCREMENT, + \`binary\` binary(255), + \`varbinary\` varbinary(256), + \`char\` char(255), + \`varchar\` varchar(256), + \`text\` text, + \`boolean\` boolean, + \`date_string\` date, + \`date\` date, + \`datetime\` datetime, + \`datetimeString\` datetime, + \`time\` time, + \`year\` year, + \`timestamp_date\` timestamp, + \`timestamp_string\` timestamp, + \`json\` json, + \`popularity\` enum('unknown','known','popular') + ); + `, + ); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +test('basic seed test', async () => { + await seed(db, schema, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); diff --git a/drizzle-seed/src/tests/mysql/drizzle.config.ts b/drizzle-seed/src/tests/mysql/drizzle.config.ts new file mode 100644 index 000000000..9a84354e3 --- /dev/null +++ b/drizzle-seed/src/tests/mysql/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/mysql/mysqlSchema.ts', + out: './src/tests/mysql/mysqlMigrations', + dialect: 'mysql', +}); diff --git a/drizzle-seed/src/tests/mysql/generatorsTest/drizzle.config.ts b/drizzle-seed/src/tests/mysql/generatorsTest/drizzle.config.ts new file mode 100644 index 000000000..621d8acc1 --- /dev/null +++ b/drizzle-seed/src/tests/mysql/generatorsTest/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/mysql/generatorsTest/mysqlSchema.ts', + out: './src/tests/mysql/generatorsTest/mysqlMigrations', + dialect: 'mysql', +}); diff --git a/drizzle-seed/src/tests/mysql/generatorsTest/generators.test.ts b/drizzle-seed/src/tests/mysql/generatorsTest/generators.test.ts new file mode 100644 index 000000000..223d5b54e --- /dev/null +++ b/drizzle-seed/src/tests/mysql/generatorsTest/generators.test.ts @@ -0,0 +1,128 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import type { MySql2Database } from 'drizzle-orm/mysql2'; +import { drizzle } from 'drizzle-orm/mysql2'; +import getPort from 'get-port'; +import type { Connection } from 'mysql2/promise'; +import { createConnection } from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, expect, test } from 'vitest'; +import { seed } from '../../../index.ts'; +import * as schema from './mysqlSchema.ts'; + +let mysqlContainer: Docker.Container; +let client: Connection; +let db: MySql2Database; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +beforeAll(async () => { + const connectionString = await createDockerDB(); + + const sleep = 1000; + let timeLeft = 40000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + db = drizzle(client); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } + + await db.execute( + sql` + CREATE TABLE \`datetime_table\` ( + \`datetime\` datetime + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`year_table\` ( + \`year\` year + ); + `, + ); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +const count = 10000; + +test('datetime generator test', async () => { + await seed(db, { datetimeTable: schema.datetimeTable }).refine((funcs) => ({ + datetimeTable: { + count, + columns: { + datetime: funcs.datetime(), + }, + }, + })); + + const data = await db.select().from(schema.datetimeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('year generator test', async () => { + await seed(db, { yearTable: schema.yearTable }).refine((funcs) => ({ + yearTable: { + count, + columns: { + year: funcs.year(), + }, + }, + })); + + const data = await db.select().from(schema.yearTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); diff --git a/drizzle-seed/src/tests/mysql/generatorsTest/mysqlSchema.ts b/drizzle-seed/src/tests/mysql/generatorsTest/mysqlSchema.ts new file mode 100644 index 000000000..c9a7edc62 --- /dev/null +++ b/drizzle-seed/src/tests/mysql/generatorsTest/mysqlSchema.ts @@ -0,0 +1,9 @@ +import { datetime, mysqlTable, year } from 'drizzle-orm/mysql-core'; + +export const datetimeTable = mysqlTable('datetime_table', { + datetime: datetime('datetime'), +}); + +export const yearTable = mysqlTable('year_table', { + year: year('year'), +}); diff --git a/drizzle-seed/src/tests/mysql/mysql.test.ts b/drizzle-seed/src/tests/mysql/mysql.test.ts new file mode 100644 index 000000000..d1b6790ec --- /dev/null +++ b/drizzle-seed/src/tests/mysql/mysql.test.ts @@ -0,0 +1,381 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import type { MySql2Database } from 'drizzle-orm/mysql2'; +import { drizzle } from 'drizzle-orm/mysql2'; +import getPort from 'get-port'; +import type { Connection } from 'mysql2/promise'; +import { createConnection } from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../index.ts'; +import * as schema from './mysqlSchema.ts'; + +let mysqlContainer: Docker.Container; +let client: Connection; +let db: MySql2Database; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +beforeAll(async () => { + const connectionString = await createDockerDB(); + + const sleep = 1000; + let timeLeft = 40000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + db = drizzle(client); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } + + await db.execute( + sql` + CREATE TABLE \`customer\` ( + \`id\` varchar(256) NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text, + \`region\` text, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + \`fax\` text, + CONSTRAINT \`customer_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`order_detail\` ( + \`unit_price\` float NOT NULL, + \`quantity\` int NOT NULL, + \`discount\` float NOT NULL, + \`order_id\` int NOT NULL, + \`product_id\` int NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`employee\` ( + \`id\` int NOT NULL, + \`last_name\` text NOT NULL, + \`first_name\` text, + \`title\` text NOT NULL, + \`title_of_courtesy\` text NOT NULL, + \`birth_date\` timestamp NOT NULL, + \`hire_date\` timestamp NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`home_phone\` text NOT NULL, + \`extension\` int NOT NULL, + \`notes\` text NOT NULL, + \`reports_to\` int, + \`photo_path\` text, + CONSTRAINT \`employee_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`order\` ( + \`id\` int NOT NULL, + \`order_date\` timestamp NOT NULL, + \`required_date\` timestamp NOT NULL, + \`shipped_date\` timestamp, + \`ship_via\` int NOT NULL, + \`freight\` float NOT NULL, + \`ship_name\` text NOT NULL, + \`ship_city\` text NOT NULL, + \`ship_region\` text, + \`ship_postal_code\` text, + \`ship_country\` text NOT NULL, + \`customer_id\` varchar(256) NOT NULL, + \`employee_id\` int NOT NULL, + CONSTRAINT \`order_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`product\` ( + \`id\` int NOT NULL, + \`name\` text NOT NULL, + \`quantity_per_unit\` text NOT NULL, + \`unit_price\` float NOT NULL, + \`units_in_stock\` int NOT NULL, + \`units_on_order\` int NOT NULL, + \`reorder_level\` int NOT NULL, + \`discontinued\` int NOT NULL, + \`supplier_id\` int NOT NULL, + CONSTRAINT \`product_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`supplier\` ( + \`id\` int NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`region\` text, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + CONSTRAINT \`supplier_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order_detail\` ADD CONSTRAINT \`order_detail_order_id_order_id_fk\` FOREIGN KEY (\`order_id\`) REFERENCES \`order\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order_detail\` ADD CONSTRAINT \`order_detail_product_id_product_id_fk\` FOREIGN KEY (\`product_id\`) REFERENCES \`product\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`employee\` ADD CONSTRAINT \`employee_reports_to_employee_id_fk\` FOREIGN KEY (\`reports_to\`) REFERENCES \`employee\`(\`id\`) ON DELETE no action ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order\` ADD CONSTRAINT \`order_customer_id_customer_id_fk\` FOREIGN KEY (\`customer_id\`) REFERENCES \`customer\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order\` ADD CONSTRAINT \`order_employee_id_employee_id_fk\` FOREIGN KEY (\`employee_id\`) REFERENCES \`employee\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`product\` ADD CONSTRAINT \`product_supplier_id_supplier_id_fk\` FOREIGN KEY (\`supplier_id\`) REFERENCES \`supplier\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); diff --git a/drizzle-seed/src/tests/mysql/mysqlSchema.ts b/drizzle-seed/src/tests/mysql/mysqlSchema.ts new file mode 100644 index 000000000..624d45d3e --- /dev/null +++ b/drizzle-seed/src/tests/mysql/mysqlSchema.ts @@ -0,0 +1,102 @@ +import type { AnyMySqlColumn } from 'drizzle-orm/mysql-core'; +import { float, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'; + +export const customers = mysqlTable('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = mysqlTable( + 'employee', + { + id: int('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: int('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: int('reports_to').references((): AnyMySqlColumn => employees.id), + photoPath: text('photo_path'), + }, +); + +export const orders = mysqlTable('order', { + id: int('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: int('ship_via').notNull(), + freight: float('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: varchar('customer_id', { length: 256 }) + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: int('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = mysqlTable('supplier', { + id: int('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = mysqlTable('product', { + id: int('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: float('unit_price').notNull(), + unitsInStock: int('units_in_stock').notNull(), + unitsOnOrder: int('units_on_order').notNull(), + reorderLevel: int('reorder_level').notNull(), + discontinued: int('discontinued').notNull(), + + supplierId: int('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = mysqlTable('order_detail', { + unitPrice: float('unit_price').notNull(), + quantity: int('quantity').notNull(), + discount: float('discount').notNull(), + + orderId: int('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: int('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); diff --git a/drizzle-seed/src/tests/northwind/mysqlSchema.ts b/drizzle-seed/src/tests/northwind/mysqlSchema.ts new file mode 100644 index 000000000..624d45d3e --- /dev/null +++ b/drizzle-seed/src/tests/northwind/mysqlSchema.ts @@ -0,0 +1,102 @@ +import type { AnyMySqlColumn } from 'drizzle-orm/mysql-core'; +import { float, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'; + +export const customers = mysqlTable('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = mysqlTable( + 'employee', + { + id: int('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: int('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: int('reports_to').references((): AnyMySqlColumn => employees.id), + photoPath: text('photo_path'), + }, +); + +export const orders = mysqlTable('order', { + id: int('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: int('ship_via').notNull(), + freight: float('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: varchar('customer_id', { length: 256 }) + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: int('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = mysqlTable('supplier', { + id: int('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = mysqlTable('product', { + id: int('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: float('unit_price').notNull(), + unitsInStock: int('units_in_stock').notNull(), + unitsOnOrder: int('units_on_order').notNull(), + reorderLevel: int('reorder_level').notNull(), + discontinued: int('discontinued').notNull(), + + supplierId: int('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = mysqlTable('order_detail', { + unitPrice: float('unit_price').notNull(), + quantity: int('quantity').notNull(), + discount: float('discount').notNull(), + + orderId: int('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: int('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); diff --git a/drizzle-seed/src/tests/northwind/mysqlTest.ts b/drizzle-seed/src/tests/northwind/mysqlTest.ts new file mode 100644 index 000000000..98c2dd742 --- /dev/null +++ b/drizzle-seed/src/tests/northwind/mysqlTest.ts @@ -0,0 +1,176 @@ +import 'dotenv/config'; +import path from 'path'; + +import { drizzle } from 'drizzle-orm/mysql2'; +import { migrate } from 'drizzle-orm/mysql2/migrator'; +import mysql from 'mysql2/promise'; + +import * as schema from './mysqlSchema.ts'; + +import { seed } from '../../index.ts'; + +const { Mysql_HOST, Mysql_PORT, Mysql_DATABASE, Mysql_USER, Mysql_PASSWORD } = process.env; + +const mysqlPool = mysql.createPool({ + host: Mysql_HOST, + port: Number(Mysql_PORT) || 3306, + database: Mysql_DATABASE, + user: Mysql_USER, + password: Mysql_PASSWORD, + // ssl: { rejectUnauthorized: false } +}); + +const db = drizzle(mysqlPool); + +console.log('database connection was established successfully.'); + +(async () => { + await migrate(db, { migrationsFolder: path.join(__dirname, '../../../mysqlMigrations') }); + console.log('database was migrated.'); + + // await seed(db, schema, { count: 100000, seed: 1 }); + + const titlesOfCourtesy = ['Ms.', 'Mrs.', 'Dr.']; + const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100]; + const reorderLevels = [0, 5, 10, 15, 20, 25, 30]; + const quantityPerUnit = [ + '100 - 100 g pieces', + '100 - 250 g bags', + '10 - 200 g glasses', + '10 - 4 oz boxes', + '10 - 500 g pkgs.', + '10 - 500 g pkgs.', + '10 boxes x 12 pieces', + '10 boxes x 20 bags', + '10 boxes x 8 pieces', + '10 kg pkg.', + '10 pkgs.', + '12 - 100 g bars', + '12 - 100 g pkgs', + '12 - 12 oz cans', + '12 - 1 lb pkgs.', + '12 - 200 ml jars', + '12 - 250 g pkgs.', + '12 - 355 ml cans', + '12 - 500 g pkgs.', + '750 cc per bottle', + '5 kg pkg.', + '50 bags x 30 sausgs.', + '500 ml', + '500 g', + '48 pieces', + '48 - 6 oz jars', + '4 - 450 g glasses', + '36 boxes', + '32 - 8 oz bottles', + '32 - 500 g boxes', + ]; + const discounts = [0.05, 0.15, 0.2, 0.25]; + + await seed(db, schema).refine((funcs) => ({ + customers: { + count: 10000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + fax: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + employees: { + count: 200, + columns: { + firstName: funcs.firstName({}), + lastName: funcs.lastName({}), + title: funcs.jobTitle({}), + titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }), + birthDate: funcs.date({ minDate: '1990-01-01', maxDate: '2010-12-31' }), + hireDate: funcs.date({ minDate: '2010-12-31', maxDate: '2024-08-26' }), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + country: funcs.country({}), + homePhone: funcs.phoneNumber({ template: '(###) ###-####' }), + extension: funcs.int({ minValue: 428, maxValue: 5467 }), + notes: funcs.loremIpsum({}), + }, + }, + orders: { + count: 50000, + columns: { + shipVia: funcs.int({ minValue: 1, maxValue: 3 }), + freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }), + shipName: funcs.streetAddress({}), + shipCity: funcs.city({}), + shipRegion: funcs.state({}), + shipPostalCode: funcs.postcode({}), + shipCountry: funcs.country({}), + }, + with: { + details: [ + { weight: 0.6, count: [1, 2, 3, 4] }, + { weight: 0.2, count: [5, 6, 7, 8, 9, 10] }, + { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] }, + { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] }, + ], + }, + }, + suppliers: { + count: 1000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + products: { + count: 5000, + columns: { + name: funcs.companyName({}), + quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }), + unitPrice: funcs.weightedRandom( + [ + { + weight: 0.5, + value: funcs.int({ minValue: 3, maxValue: 300 }), + }, + { + weight: 0.5, + value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 }), + }, + ], + ), + unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }), + unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }), + reorderLevel: funcs.valuesFromArray({ values: reorderLevels }), + discontinued: funcs.int({ minValue: 0, maxValue: 1 }), + }, + }, + details: { + columns: { + unitPrice: funcs.number({ minValue: 10, maxValue: 130 }), + quantity: funcs.int({ minValue: 1, maxValue: 130 }), + discount: funcs.weightedRandom( + [ + { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) }, + { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }, + ], + ), + }, + }, + })); + + await mysqlPool.end(); +})().then(); diff --git a/drizzle-seed/src/tests/northwind/pgSchema.ts b/drizzle-seed/src/tests/northwind/pgSchema.ts new file mode 100644 index 000000000..f0f9a05fb --- /dev/null +++ b/drizzle-seed/src/tests/northwind/pgSchema.ts @@ -0,0 +1,104 @@ +import type { AnyPgColumn } from 'drizzle-orm/pg-core'; +import { integer, numeric, pgSchema, text, timestamp, varchar } from 'drizzle-orm/pg-core'; + +export const schema = pgSchema('seeder_lib_pg'); + +export const customers = schema.table('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = schema.table('employee', { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to').references((): AnyPgColumn => employees.id), + photoPath: text('photo_path'), +}); + +export const orders = schema.table('order', { + id: integer('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = schema.table( + 'supplier', + { + id: integer('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), + }, +); + +export const products = schema.table('product', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = schema.table('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); diff --git a/drizzle-seed/src/tests/northwind/pgTest.ts b/drizzle-seed/src/tests/northwind/pgTest.ts new file mode 100644 index 000000000..284f28957 --- /dev/null +++ b/drizzle-seed/src/tests/northwind/pgTest.ts @@ -0,0 +1,175 @@ +import 'dotenv/config'; +import path from 'path'; + +import { drizzle } from 'drizzle-orm/node-postgres'; +import { migrate } from 'drizzle-orm/node-postgres/migrator'; +import { Pool as PgPool } from 'pg'; + +import { seed } from '../../index.ts'; +import * as schema from './pgSchema.ts'; + +const { PG_HOST, PG_PORT, PG_DATABASE, PG_USER, PG_PASSWORD } = process.env; + +const pgPool = new PgPool({ + host: PG_HOST, + port: Number(PG_PORT) || 5432, + database: PG_DATABASE, + user: PG_USER, + password: PG_PASSWORD, + // ssl: true +}); + +const db = drizzle(pgPool); + +console.log('database connection was established successfully.'); + +(async () => { + await migrate(db, { migrationsFolder: path.join(__dirname, '../../../pgMigrations') }); + console.log('database was migrated.'); + + // await seed(db, schema, { count: 100000, seed: 1 }); + + const titlesOfCourtesy = ['Ms.', 'Mrs.', 'Dr.']; + const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100]; + const reorderLevels = [0, 5, 10, 15, 20, 25, 30]; + const quantityPerUnit = [ + '100 - 100 g pieces', + '100 - 250 g bags', + '10 - 200 g glasses', + '10 - 4 oz boxes', + '10 - 500 g pkgs.', + '10 - 500 g pkgs.', + '10 boxes x 12 pieces', + '10 boxes x 20 bags', + '10 boxes x 8 pieces', + '10 kg pkg.', + '10 pkgs.', + '12 - 100 g bars', + '12 - 100 g pkgs', + '12 - 12 oz cans', + '12 - 1 lb pkgs.', + '12 - 200 ml jars', + '12 - 250 g pkgs.', + '12 - 355 ml cans', + '12 - 500 g pkgs.', + '750 cc per bottle', + '5 kg pkg.', + '50 bags x 30 sausgs.', + '500 ml', + '500 g', + '48 pieces', + '48 - 6 oz jars', + '4 - 450 g glasses', + '36 boxes', + '32 - 8 oz bottles', + '32 - 500 g boxes', + ]; + const discounts = [0.05, 0.15, 0.2, 0.25]; + + await seed(db, schema).refine((funcs) => ({ + customers: { + count: 10000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + fax: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + employees: { + count: 200, + columns: { + firstName: funcs.firstName({}), + lastName: funcs.lastName({}), + title: funcs.jobTitle({}), + titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }), + birthDate: funcs.date({ minDate: '1990-01-01', maxDate: '2010-12-31' }), + hireDate: funcs.date({ minDate: '2010-12-31', maxDate: '2024-08-26' }), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + country: funcs.country({}), + homePhone: funcs.phoneNumber({ template: '(###) ###-####' }), + extension: funcs.int({ minValue: 428, maxValue: 5467 }), + notes: funcs.loremIpsum({}), + }, + }, + orders: { + count: 50000, + columns: { + shipVia: funcs.int({ minValue: 1, maxValue: 3 }), + freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }), + shipName: funcs.streetAddress({}), + shipCity: funcs.city({}), + shipRegion: funcs.state({}), + shipPostalCode: funcs.postcode({}), + shipCountry: funcs.country({}), + }, + with: { + details: [ + { weight: 0.6, count: [1, 2, 3, 4] }, + { weight: 0.2, count: [5, 6, 7, 8, 9, 10] }, + { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] }, + { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] }, + ], + }, + }, + suppliers: { + count: 1000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + products: { + count: 5000, + columns: { + name: funcs.companyName({}), + quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }), + unitPrice: funcs.weightedRandom( + [ + { + weight: 0.5, + value: funcs.int({ minValue: 3, maxValue: 300 }), + }, + { + weight: 0.5, + value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 }), + }, + ], + ), + unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }), + unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }), + reorderLevel: funcs.valuesFromArray({ values: reorderLevels }), + discontinued: funcs.int({ minValue: 0, maxValue: 1 }), + }, + }, + details: { + columns: { + unitPrice: funcs.number({ minValue: 10, maxValue: 130 }), + quantity: funcs.int({ minValue: 1, maxValue: 130 }), + discount: funcs.weightedRandom( + [ + { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) }, + { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }, + ], + ), + }, + }, + })); + + await pgPool.end(); +})().then(); diff --git a/drizzle-seed/src/tests/northwind/sqliteSchema.ts b/drizzle-seed/src/tests/northwind/sqliteSchema.ts new file mode 100644 index 000000000..fa00dd365 --- /dev/null +++ b/drizzle-seed/src/tests/northwind/sqliteSchema.ts @@ -0,0 +1,107 @@ +import { foreignKey, integer, numeric, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const customers = sqliteTable('customer', { + id: text('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = sqliteTable( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: integer('birth_date', { mode: 'timestamp' }).notNull(), + hireDate: integer('hire_date', { mode: 'timestamp' }).notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to'), + photoPath: text('photo_path'), + }, + (table) => ({ + reportsToFk: foreignKey(() => ({ + columns: [table.reportsTo], + foreignColumns: [table.id], + })), + }), +); + +export const orders = sqliteTable('order', { + id: integer('id').primaryKey(), + orderDate: integer('order_date', { mode: 'timestamp' }).notNull(), + requiredDate: integer('required_date', { mode: 'timestamp' }).notNull(), + shippedDate: integer('shipped_date', { mode: 'timestamp' }), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = sqliteTable('supplier', { + id: integer('id').primaryKey({ autoIncrement: true }), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = sqliteTable('product', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = sqliteTable('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); diff --git a/drizzle-seed/src/tests/northwind/sqliteTest.ts b/drizzle-seed/src/tests/northwind/sqliteTest.ts new file mode 100644 index 000000000..d64f2c447 --- /dev/null +++ b/drizzle-seed/src/tests/northwind/sqliteTest.ts @@ -0,0 +1,162 @@ +import 'dotenv/config'; +import path from 'path'; + +import betterSqlite3 from 'better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import { migrate } from 'drizzle-orm/better-sqlite3/migrator'; + +import { seed } from '../../index.ts'; +import * as schema from './sqliteSchema.ts'; + +const { Sqlite_PATH } = process.env; +const sqliteDb = betterSqlite3(Sqlite_PATH); +const db = drizzle(sqliteDb); + +console.log('database connection was established successfully.'); + +(async () => { + migrate(db, { migrationsFolder: path.join(__dirname, '../../../sqliteMigrations') }); + console.log('database was migrated.'); + + const titlesOfCourtesy = ['Ms.', 'Mrs.', 'Dr.']; + const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100]; + const reorderLevels = [0, 5, 10, 15, 20, 25, 30]; + const quantityPerUnit = [ + '100 - 100 g pieces', + '100 - 250 g bags', + '10 - 200 g glasses', + '10 - 4 oz boxes', + '10 - 500 g pkgs.', + '10 - 500 g pkgs.', + '10 boxes x 12 pieces', + '10 boxes x 20 bags', + '10 boxes x 8 pieces', + '10 kg pkg.', + '10 pkgs.', + '12 - 100 g bars', + '12 - 100 g pkgs', + '12 - 12 oz cans', + '12 - 1 lb pkgs.', + '12 - 200 ml jars', + '12 - 250 g pkgs.', + '12 - 355 ml cans', + '12 - 500 g pkgs.', + '750 cc per bottle', + '5 kg pkg.', + '50 bags x 30 sausgs.', + '500 ml', + '500 g', + '48 pieces', + '48 - 6 oz jars', + '4 - 450 g glasses', + '36 boxes', + '32 - 8 oz bottles', + '32 - 500 g boxes', + ]; + const discounts = [0.05, 0.15, 0.2, 0.25]; + + await seed(db, schema).refine((funcs) => ({ + customers: { + count: 10000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + fax: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + employees: { + count: 200, + columns: { + firstName: funcs.firstName({}), + lastName: funcs.lastName({}), + title: funcs.jobTitle({}), + titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }), + birthDate: funcs.date({ minDate: '1990-01-01', maxDate: '2010-12-31' }), + hireDate: funcs.date({ minDate: '2010-12-31', maxDate: '2024-08-26' }), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + country: funcs.country({}), + homePhone: funcs.phoneNumber({ template: '(###) ###-####' }), + extension: funcs.int({ minValue: 428, maxValue: 5467 }), + notes: funcs.loremIpsum({}), + }, + }, + orders: { + count: 50000, + columns: { + shipVia: funcs.int({ minValue: 1, maxValue: 3 }), + freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }), + shipName: funcs.streetAddress({}), + shipCity: funcs.city({}), + shipRegion: funcs.state({}), + shipPostalCode: funcs.postcode({}), + shipCountry: funcs.country({}), + }, + with: { + details: [ + { weight: 0.6, count: [1, 2, 3, 4] }, + { weight: 0.2, count: [5, 6, 7, 8, 9, 10] }, + { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] }, + { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] }, + ], + }, + }, + suppliers: { + count: 1000, + columns: { + companyName: funcs.companyName({}), + contactName: funcs.fullName({}), + contactTitle: funcs.jobTitle({}), + address: funcs.streetAddress({}), + city: funcs.city({}), + postalCode: funcs.postcode({}), + region: funcs.state({}), + country: funcs.country({}), + phone: funcs.phoneNumber({ template: '(###) ###-####' }), + }, + }, + products: { + count: 5000, + columns: { + name: funcs.companyName({}), + quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }), + unitPrice: funcs.weightedRandom( + [ + { + weight: 0.5, + value: funcs.int({ minValue: 3, maxValue: 300 }), + }, + { + weight: 0.5, + value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 }), + }, + ], + ), + unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }), + unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }), + reorderLevel: funcs.valuesFromArray({ values: reorderLevels }), + discontinued: funcs.int({ minValue: 0, maxValue: 1 }), + }, + }, + details: { + columns: { + unitPrice: funcs.number({ minValue: 10, maxValue: 130 }), + quantity: funcs.int({ minValue: 1, maxValue: 130 }), + discount: funcs.weightedRandom( + [ + { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) }, + { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }, + ], + ), + }, + }, + })); +})().then(); diff --git a/drizzle-seed/src/tests/pg/allDataTypesTest/drizzle.config.ts b/drizzle-seed/src/tests/pg/allDataTypesTest/drizzle.config.ts new file mode 100644 index 000000000..131b4d025 --- /dev/null +++ b/drizzle-seed/src/tests/pg/allDataTypesTest/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/pg/allDataTypesTest/pgSchema.ts', + out: './src/tests/pg/allDataTypesTest/pgMigrations', + dialect: 'postgresql', +}); diff --git a/drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts b/drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts new file mode 100644 index 000000000..c8dd22355 --- /dev/null +++ b/drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts @@ -0,0 +1,62 @@ +import { + bigint, + bigserial, + boolean, + char, + date, + decimal, + doublePrecision, + integer, + interval, + json, + jsonb, + line, + numeric, + pgEnum, + pgSchema, + point, + real, + serial, + smallint, + smallserial, + text, + time, + timestamp, + varchar, +} from 'drizzle-orm/pg-core'; + +export const schema = pgSchema('seeder_lib_pg'); + +export const moodEnum = pgEnum('mood_enum', ['sad', 'ok', 'happy']); + +export const allDataTypes = schema.table('all_data_types', { + integer: integer('integer'), + smallint: smallint('smallint'), + biginteger: bigint('bigint', { mode: 'bigint' }), + bigintNumber: bigint('bigint_number', { mode: 'number' }), + serial: serial('serial'), + smallserial: smallserial('smallserial'), + bigserial: bigserial('bigserial', { mode: 'bigint' }), + bigserialNumber: bigserial('bigserial_number', { mode: 'number' }), + boolean: boolean('boolean'), + text: text('text'), + varchar: varchar('varchar', { length: 256 }), + char: char('char', { length: 256 }), + numeric: numeric('numeric'), + decimal: decimal('decimal'), + real: real('real'), + doublePrecision: doublePrecision('double_precision'), + json: json('json'), + jsonb: jsonb('jsonb'), + time: time('time'), + timestampDate: timestamp('timestamp_date', { mode: 'date' }), + timestampString: timestamp('timestamp_string', { mode: 'string' }), + dateString: date('date_string', { mode: 'string' }), + date: date('date', { mode: 'date' }), + interval: interval('interval'), + point: point('point', { mode: 'xy' }), + pointTuple: point('point_tuple', { mode: 'tuple' }), + line: line('line', { mode: 'abc' }), + lineTuple: line('line_tuple', { mode: 'tuple' }), + moodEnum: moodEnum('mood_enum'), +}); diff --git a/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts b/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts new file mode 100644 index 000000000..b876915b2 --- /dev/null +++ b/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts @@ -0,0 +1,78 @@ +import { PGlite } from '@electric-sql/pglite'; +import { sql } from 'drizzle-orm'; +import type { PgliteDatabase } from 'drizzle-orm/pglite'; +import { drizzle } from 'drizzle-orm/pglite'; +import { afterAll, beforeAll, expect, test } from 'vitest'; +import { seed } from '../../../index.ts'; +import * as schema from './pgSchema.ts'; + +let client: PGlite; +let db: PgliteDatabase; + +beforeAll(async () => { + client = new PGlite(); + + db = drizzle(client); + + await db.execute(sql`CREATE SCHEMA "seeder_lib_pg";`); + + await db.execute( + sql` + DO $$ BEGIN + CREATE TYPE "seeder_lib_pg"."mood_enum" AS ENUM('sad', 'ok', 'happy'); + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."all_data_types" ( + "integer" integer, + "smallint" smallint, + "bigint" bigint, + "bigint_number" bigint, + "serial" serial NOT NULL, + "smallserial" "smallserial" NOT NULL, + "bigserial" bigserial, + "bigserial_number" bigserial NOT NULL, + "boolean" boolean, + "text" text, + "varchar" varchar(256), + "char" char(256), + "numeric" numeric, + "decimal" numeric, + "real" real, + "double_precision" double precision, + "json" json, + "jsonb" jsonb, + "time" time, + "timestamp_date" timestamp, + "timestamp_string" timestamp, + "date_string" date, + "date" date, + "interval" interval, + "point" "point", + "point_tuple" "point", + "line" "line", + "line_tuple" "line", + "mood_enum" "seeder_lib_pg"."mood_enum" + ); + `, + ); +}); + +afterAll(async () => { + await client.close(); +}); + +test('all data types test', async () => { + await seed(db, schema, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); diff --git a/drizzle-seed/src/tests/pg/drizzle.config.ts b/drizzle-seed/src/tests/pg/drizzle.config.ts new file mode 100644 index 000000000..65b65236f --- /dev/null +++ b/drizzle-seed/src/tests/pg/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/pg/pgSchema.ts', + out: './src/tests/pg/pgMigrations', + dialect: 'postgresql', +}); diff --git a/drizzle-seed/src/tests/pg/generatorsTest/drizzle.config.ts b/drizzle-seed/src/tests/pg/generatorsTest/drizzle.config.ts new file mode 100644 index 000000000..30331986c --- /dev/null +++ b/drizzle-seed/src/tests/pg/generatorsTest/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/tests/pg/generatorsTest/pgSchema.ts', + out: './src/tests/pg/generatorsTest/pgMigrations', + dialect: 'postgresql', +}); diff --git a/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts b/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts new file mode 100644 index 000000000..1e01d0453 --- /dev/null +++ b/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts @@ -0,0 +1,1372 @@ +import { afterAll, beforeAll, expect, test } from 'vitest'; + +import { PGlite } from '@electric-sql/pglite'; +import type { PgliteDatabase } from 'drizzle-orm/pglite'; +import { drizzle } from 'drizzle-orm/pglite'; + +import { reset, seed } from '../../../index.ts'; +import * as schema from './pgSchema.ts'; + +import { sql } from 'drizzle-orm'; +import cities from '../../../datasets/cityNames.ts'; +import countries from '../../../datasets/countries.ts'; +import firstNames from '../../../datasets/firstNames.ts'; +import lastNames from '../../../datasets/lastNames.ts'; + +let client: PGlite; +let db: PgliteDatabase; + +beforeAll(async () => { + client = new PGlite(); + + db = drizzle(client); + + await db.execute(sql`CREATE SCHEMA "seeder_lib_pg";`); + + await db.execute( + sql` + DO $$ BEGIN + CREATE TYPE "seeder_lib_pg"."enum" AS ENUM('sad', 'ok', 'happy'); + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."boolean_table" ( + "boolean" boolean + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_table" ( + "city" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_unique_table" ( + "city_unique" varchar(256), + CONSTRAINT "city_unique_table_city_unique_unique" UNIQUE("city_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_table" ( + "company_name" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_unique_table" ( + "company_name_unique" varchar(256), + CONSTRAINT "company_name_unique_table_company_name_unique_unique" UNIQUE("company_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_table" ( + "country" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_unique_table" ( + "country_unique" varchar(256), + CONSTRAINT "country_unique_table_country_unique_unique" UNIQUE("country_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."date_table" ( + "date" date + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."default_table" ( + "default_string" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."email_table" ( + "email" varchar(256), + CONSTRAINT "email_table_email_unique" UNIQUE("email") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."enum_table" ( + "mood_enum" "seeder_lib_pg"."enum" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."first_name_table" ( + "first_name" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."first_name_unique_table" ( + "first_name_unique" varchar(256), + CONSTRAINT "first_name_unique_table_first_name_unique_unique" UNIQUE("first_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name__table" ( + "full_name_" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name_unique_table" ( + "full_name_unique" varchar(256), + CONSTRAINT "full_name_unique_table_full_name_unique_unique" UNIQUE("full_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_primary_key_table" ( + "int_primary_key" integer, + CONSTRAINT "int_primary_key_table_int_primary_key_unique" UNIQUE("int_primary_key") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_table" ( + "int" integer + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_unique_table" ( + "int_unique" integer, + CONSTRAINT "int_unique_table_int_unique_unique" UNIQUE("int_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_table" ( + "interval" interval + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_unique_table" ( + "interval_unique" interval, + CONSTRAINT "interval_unique_table_interval_unique_unique" UNIQUE("interval_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."job_Title_table" ( + "job_title" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."json_table" ( + "json" json + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_table" ( + "last_name" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_unique_table" ( + "last_name_unique" varchar(256), + CONSTRAINT "last_name_unique_table_last_name_unique_unique" UNIQUE("last_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."line_table" ( + "line" "line" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."lorem_ipsum_table" ( + "lorem_ipsum" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_table" ( + "number" real + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_unique_table" ( + "number_unique" real, + CONSTRAINT "number_unique_table_number_unique_unique" UNIQUE("number_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."phone_number_table" ( + "phoneNumber" varchar(256), + "phone_number_template" varchar(256), + "phone_number_prefixes" varchar(256), + CONSTRAINT "phone_number_table_phoneNumber_unique" UNIQUE("phoneNumber"), + CONSTRAINT "phone_number_table_phone_number_template_unique" UNIQUE("phone_number_template"), + CONSTRAINT "phone_number_table_phone_number_prefixes_unique" UNIQUE("phone_number_prefixes") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."point_table" ( + "point" "point" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_table" ( + "postcode" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_unique_table" ( + "postcode_unique" varchar(256), + CONSTRAINT "postcode_unique_table_postcode_unique_unique" UNIQUE("postcode_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."state_table" ( + "state" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_table" ( + "street_address" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_unique_table" ( + "street_address_unique" varchar(256), + CONSTRAINT "street_address_unique_table_street_address_unique_unique" UNIQUE("street_address_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_table" ( + "string" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_unique_table" ( + "string_unique" varchar(256), + CONSTRAINT "string_unique_table_string_unique_unique" UNIQUE("string_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."time_table" ( + "time" time + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."timestamp_table" ( + "timestamp" timestamp + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_table" ( + "values_from_array_not_null" varchar(256) NOT NULL, + "values_from_array_weighted_not_null" varchar(256) NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_unique_table" ( + "values_from_array" varchar(256), + "values_from_array_not_null" varchar(256) NOT NULL, + "values_from_array_weighted" varchar(256), + "values_from_array_weighted_not_null" varchar(256) NOT NULL, + CONSTRAINT "values_from_array_unique_table_values_from_array_unique" UNIQUE("values_from_array"), + CONSTRAINT "values_from_array_unique_table_values_from_array_not_null_unique" UNIQUE("values_from_array_not_null"), + CONSTRAINT "values_from_array_unique_table_values_from_array_weighted_unique" UNIQUE("values_from_array_weighted"), + CONSTRAINT "values_from_array_unique_table_values_from_array_weighted_not_null_unique" UNIQUE("values_from_array_weighted_not_null") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."weighted_random_table" ( + "weighted_random" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."weighted_random_with_unique_gens_table" ( + "weighted_random_with_unique_gens" varchar(256), + CONSTRAINT "weighted_random_with_unique_gens_table_weighted_random_with_unique_gens_unique" UNIQUE("weighted_random_with_unique_gens") + ); + `, + ); +}); + +afterAll(async () => { + await client.close(); +}); + +const count = 10000; + +test('enum generator test', async () => { + await seed(db, { enumTable: schema.enumTable }).refine(() => ({ + enumTable: { + count, + }, + })); + + const data = await db.select().from(schema.enumTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('default generator test', async () => { + await seed(db, { defaultTable: schema.defaultTable }).refine((funcs) => ({ + defaultTable: { + count, + columns: { + defaultString: funcs.default({ defaultValue: 'default string' }), + }, + }, + })); + + const data = await db.select().from(schema.defaultTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('valuesFromArray generator test', async () => { + await seed(db, { valuesFromArrayTable: schema.valuesFromArrayTable }).refine((funcs) => ({ + valuesFromArrayTable: { + count, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ values: lastNames }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames, weight: 0.3 }, + { values: firstNames, weight: 0.7 }, + ], + }), + }, + }, + })); + + const data = await db.select().from(schema.valuesFromArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('valuesFromArray unique generator test', async () => { + // valuesFromArrayUniqueTable----------------------------------------------------------------------------------- + await seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }, { seed: 1 }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArray: funcs.valuesFromArray({ values: lastNames.slice(0, 20), isUnique: true }), + valuesFromArrayNotNull: funcs.valuesFromArray({ values: lastNames, isUnique: true }), + valuesFromArrayWeighted: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 20000), weight: 0.3 }, + { values: lastNames.slice(20000), weight: 0.7 }, + ], + isUnique: true, + }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 14920), weight: 0.3 }, + { values: lastNames.slice(14920), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })); + + const data = await db.select().from(schema.valuesFromArrayUniqueTable); + // console.log(valuesFromArrayUniqueTableData); + const predicate = data.length !== 0 && data.every((row) => + row['valuesFromArrayWeightedNotNull'] !== null + && row['valuesFromArrayNotNull'] !== null + ); + expect(predicate).toBe(true); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 20000), weight: 0.3 }, + { values: lastNames.slice(20000), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow( + /^weighted values arrays is too small to generate values with specified probability for unique not null column\..+/, + ); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ + values: lastNames.slice(20), + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow('there are no enough values to fill unique column.'); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }, { seed: 1 }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49999, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ + values: lastNames, + isUnique: true, + }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 14854), weight: 0.3 }, + { values: lastNames.slice(14854), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow('there are no enough values to fill unique column.'); +}); + +test('intPrimaryKey generator test', async () => { + await seed(db, { intPrimaryKeyTable: schema.intPrimaryKeyTable }).refine((funcs) => ({ + intPrimaryKeyTable: { + count, + columns: { + intPrimaryKey: funcs.intPrimaryKey(), + }, + }, + })); + + const data = await db.select().from(schema.intPrimaryKeyTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('number generator test', async () => { + await seed(db, { numberTable: schema.numberTable }).refine((funcs) => ({ + numberTable: { + count, + columns: { + number: funcs.number(), + }, + }, + })); + + const data = await db.select().from(schema.numberTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('number unique generator test', async () => { + // numberUniqueTable----------------------------------------------------------------------------------- + await seed(db, { numberUniqueTable: schema.numberUniqueTable }).refine((funcs) => ({ + numberUniqueTable: { + count: 20070, + columns: { + numberUnique: funcs.number({ isUnique: true, minValue: -100.23, maxValue: 100.46 }), + }, + }, + })); + + const data = await db.select().from(schema.numberUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && val >= -100.23 && val <= 100.46) + ); + expect(predicate).toBe(true); + + await expect( + seed(db, { numberUniqueTable: schema.numberUniqueTable }).refine((funcs) => ({ + numberUniqueTable: { + count: 20071, + columns: { + numberUnique: funcs.number({ isUnique: true, minValue: -100.23, maxValue: 100.46 }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); +}); + +test('int generator test', async () => { + await seed(db, { intTable: schema.intTable }).refine((funcs) => ({ + intTable: { + count, + columns: { + int: funcs.int(), + }, + }, + })); + + const data = await db.select().from(schema.intTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('int unique generator test', async () => { + // intUniqueTable----------------------------------------------------------------------------------- + await seed(db, { intUniqueTable: schema.intUniqueTable }).refine((funcs) => ({ + intUniqueTable: { + count: 201, + columns: { + intUnique: funcs.int({ isUnique: true, minValue: -100, maxValue: 100 }), + }, + }, + })); + + const data = await db.select().from(schema.intUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { intUniqueTable: schema.intUniqueTable }).refine((funcs) => ({ + intUniqueTable: { + count: 202, + columns: { + intUnique: funcs.int({ isUnique: true, minValue: -100, maxValue: 100 }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); +}); + +test('boolean generator test', async () => { + await seed(db, { booleanTable: schema.booleanTable }).refine((funcs) => ({ + booleanTable: { + count, + columns: { + boolean: funcs.boolean(), + }, + }, + })); + + const data = await db.select().from(schema.booleanTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('date generator test', async () => { + await seed(db, { dateTable: schema.dateTable }).refine((funcs) => ({ + dateTable: { + count, + columns: { + date: funcs.date(), + }, + }, + })); + + const data = await db.select().from(schema.dateTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('time generator test', async () => { + await seed(db, { timeTable: schema.timeTable }).refine((funcs) => ({ + timeTable: { + count, + columns: { + time: funcs.time(), + }, + }, + })); + + const data = await db.select().from(schema.timeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('timestamp generator test', async () => { + await seed(db, { timestampTable: schema.timestampTable }).refine((funcs) => ({ + timestampTable: { + count, + columns: { + timestamp: funcs.timestamp(), + }, + }, + })); + + const data = await db.select().from(schema.timestampTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('json generator test', async () => { + await seed(db, { jsonTable: schema.jsonTable }).refine((funcs) => ({ + jsonTable: { + count, + columns: { + json: funcs.json(), + }, + }, + })); + + const data = await db.select().from(schema.jsonTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('interval generator test', async () => { + await seed(db, { intervalTable: schema.intervalTable }).refine((funcs) => ({ + intervalTable: { + count, + columns: { + interval: funcs.interval(), + }, + }, + })); + + const data = await db.select().from(schema.intervalTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('interval unique generator test', async () => { + // intervalUniqueTable----------------------------------------------------------------------------------- + await seed(db, { intervalUniqueTable: schema.intervalUniqueTable }).refine((funcs) => ({ + intervalUniqueTable: { + count, + columns: { + intervalUnique: funcs.interval({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.intervalUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('string generator test', async () => { + await seed(db, { stringTable: schema.stringTable }).refine((funcs) => ({ + stringTable: { + count, + columns: { + string: funcs.string(), + }, + }, + })); + + const data = await db.select().from(schema.stringTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('string unique generator test', async () => { + await seed(db, { stringUniqueTable: schema.stringUniqueTable }).refine((funcs) => ({ + stringUniqueTable: { + count, + columns: { + stringUnique: funcs.string({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.stringUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('email generator test', async () => { + await seed(db, { emailTable: schema.emailTable }).refine((funcs) => ({ + emailTable: { + count, + columns: { + email: funcs.email(), + }, + }, + })); + + const data = await db.select().from(schema.emailTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('firstName generator test', async () => { + await seed(db, { firstNameTable: schema.firstNameTable }).refine((funcs) => ({ + firstNameTable: { + count, + columns: { + firstName: funcs.firstName(), + }, + }, + })); + + const data = await db.select().from(schema.firstNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('firstName unique generator test', async () => { + // firstNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { firstNameUniqueTable: schema.firstNameUniqueTable }).refine((funcs) => ({ + firstNameUniqueTable: { + count: 30274, + columns: { + firstNameUnique: funcs.firstName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.firstNameUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { firstNameUniqueTable: schema.firstNameUniqueTable }, { count: 30275 }).refine((funcs) => ({ + firstNameUniqueTable: { + count: 30275, + columns: { + firstNameUnique: funcs.firstName({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique first names.'); +}); + +test('lastName generator test', async () => { + await seed(db, { lastNameTable: schema.lastNameTable }).refine((funcs) => ({ + lastNameTable: { + count, + columns: { + lastName: funcs.lastName(), + }, + }, + })); + + const data = await db.select().from(schema.lastNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('lastName unique generator test', async () => { + // lastNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { lastNameUniqueTable: schema.lastNameUniqueTable }).refine((funcs) => ({ + lastNameUniqueTable: { + count: 49998, + columns: { + lastNameUnique: funcs.lastName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.lastNameUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { lastNameUniqueTable: schema.lastNameUniqueTable }).refine((funcs) => ({ + lastNameUniqueTable: { + count: 49999, + columns: { + lastNameUnique: funcs.lastName({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique last names.'); +}); + +test('fullName generator test', async () => { + await seed(db, { fullNameTable: schema.fullNameTable }).refine((funcs) => ({ + fullNameTable: { + count, + columns: { + fullName: funcs.fullName(), + }, + }, + })); + + const data = await db.select().from(schema.fullNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('fullName unique generator test', async () => { + // fullNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { fullNameUniqueTable: schema.fullNameUniqueTable }).refine((funcs) => ({ + fullNameUniqueTable: { + count, + columns: { + fullNameUnique: funcs.fullName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.fullNameUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('country generator test', async () => { + await seed(db, { countryTable: schema.countryTable }).refine((funcs) => ({ + countryTable: { + count, + columns: { + country: funcs.country(), + }, + }, + })); + + const data = await db.select().from(schema.countryTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('country unique generator test', async () => { + // countryUniqueTable----------------------------------------------------------------------------------- + await seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ + countryUniqueTable: { + count: countries.length, + columns: { + countryUnique: funcs.country({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.countryUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ + countryUniqueTable: { + count: countries.length + 1, + columns: { + countryUnique: funcs.country({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique countries.'); +}); + +test('city generator test', async () => { + await seed(db, { cityTable: schema.cityTable }).refine((funcs) => ({ + cityTable: { + count, + columns: { + city: funcs.city(), + }, + }, + })); + + const data = await db.select().from(schema.cityTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('city unique generator test', async () => { + // cityUniqueTable----------------------------------------------------------------------------------- + await reset(db, { cityUniqueTable: schema.cityUniqueTable }); + await seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ + cityUniqueTable: { + count: cities.length, + columns: { + cityUnique: funcs.city({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.cityUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ + cityUniqueTable: { + count: cities.length + 1, + columns: { + cityUnique: funcs.city({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique cities.'); +}); + +test('streetAddress generator test', async () => { + await seed(db, { streetAddressTable: schema.streetAddressTable }).refine((funcs) => ({ + streetAddressTable: { + count, + columns: { + streetAddress: funcs.streetAddress(), + }, + }, + })); + + const data = await db.select().from(schema.streetAddressTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('streetAddress unique generator test', async () => { + await seed(db, { streetAddressUniqueTable: schema.streetAddressUniqueTable }).refine((funcs) => ({ + streetAddressUniqueTable: { + count, + columns: { + streetAddressUnique: funcs.streetAddress({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.streetAddressUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('jobTitle generator test', async () => { + await seed(db, { jobTitleTable: schema.jobTitleTable }).refine((funcs) => ({ + jobTitleTable: { + count, + columns: { + jobTitle: funcs.jobTitle(), + }, + }, + })); + + const data = await db.select().from(schema.jobTitleTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('postcode generator test', async () => { + await seed(db, { postcodeTable: schema.postcodeTable }).refine((funcs) => ({ + postcodeTable: { + count, + columns: { + postcode: funcs.postcode(), + }, + }, + })); + + const data = await db.select().from(schema.postcodeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('postcode unique generator test', async () => { + await seed(db, { postcodeUniqueTable: schema.postcodeUniqueTable }).refine((funcs) => ({ + postcodeUniqueTable: { + count, + columns: { + postcodeUnique: funcs.postcode({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.postcodeUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('state generator test', async () => { + await seed(db, { stateTable: schema.stateTable }).refine((funcs) => ({ + stateTable: { + count, + columns: { + state: funcs.state(), + }, + }, + })); + + const data = await db.select().from(schema.stateTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('companyName generator test', async () => { + await seed(db, { companyNameTable: schema.companyNameTable }).refine((funcs) => ({ + companyNameTable: { + count, + columns: { + companyName: funcs.companyName(), + }, + }, + })); + + const data = await db.select().from(schema.companyNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('companyName unique generator test', async () => { + await seed(db, { companyNameUniqueTable: schema.companyNameUniqueTable }).refine((funcs) => ({ + companyNameUniqueTable: { + count, + columns: { + companyNameUnique: funcs.companyName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.companyNameUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('loremIpsum generator test', async () => { + await seed(db, { loremIpsumTable: schema.loremIpsumTable }).refine((funcs) => ({ + loremIpsumTable: { + count, + columns: { + loremIpsum: funcs.loremIpsum(), + }, + }, + })); + + const data = await db.select().from(schema.loremIpsumTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('point generator test', async () => { + await seed(db, { pointTable: schema.pointTable }).refine((funcs) => ({ + pointTable: { + count, + columns: { + point: funcs.point(), + }, + }, + })); + + const data = await db.select().from(schema.pointTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('point unique generator test', async () => { + await reset(db, { pointTable: schema.pointTable }); + await seed(db, { pointTable: schema.pointTable }).refine((funcs) => ({ + pointTable: { + count, + columns: { + point: funcs.point({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.pointTable); + // every value in each row does not equal undefined. + let predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + // using Set because PGlite does not support unique point + const pointStrsSet = new Set(data.map((row) => row.point!.map(String).join(','))); + predicate = pointStrsSet.size === data.length; + expect(predicate).toBe(true); +}); + +test('line generator test', async () => { + await seed(db, { lineTable: schema.lineTable }).refine((funcs) => ({ + lineTable: { + count, + columns: { + line: funcs.line(), + }, + }, + })); + + const data = await db.select().from(schema.lineTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('line unique generator test', async () => { + await reset(db, { lineTable: schema.lineTable }); + await seed(db, { lineTable: schema.lineTable }).refine((funcs) => ({ + lineTable: { + count, + columns: { + line: funcs.line({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.lineTable); + // every value in each row does not equal undefined. + let predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + // using Set because PGlite does not support unique point + const lineStrsSet = new Set(data.map((row) => row.line!.map(String).join(','))); + predicate = lineStrsSet.size === data.length; + expect(predicate).toBe(true); +}); + +test('phoneNumber generator test', async () => { + await seed(db, { phoneNumberTable: schema.phoneNumberTable }).refine((funcs) => ({ + phoneNumberTable: { + count, + columns: { + phoneNumber: funcs.phoneNumber(), + phoneNumberPrefixes: funcs.phoneNumber({ + prefixes: ['+380 99', '+380 67', '+1'], + generatedDigitsNumbers: [7, 7, 10], + }), + phoneNumberTemplate: funcs.phoneNumber({ template: '+380 ## ## ### ##' }), + }, + }, + })); + + const data = await db.select().from(schema.phoneNumberTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('weightedRandom generator test', async () => { + await seed(db, { weightedRandomTable: schema.weightedRandomTable }).refine((funcs) => ({ + weightedRandomTable: { + count, + columns: { + weightedRandom: funcs.weightedRandom([ + { value: funcs.default({ defaultValue: 'default value' }), weight: 0.3 }, + { value: funcs.loremIpsum(), weight: 0.7 }, + ]), + }, + }, + })); + + const data = await db.select().from(schema.weightedRandomTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('weightedRandom with unique gens generator test', async () => { + await seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 10000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.3, value: funcs.email() }, + { weight: 0.7, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })); + + const data = await db.select().from(schema.weightedRandomWithUniqueGensTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 40000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.1, value: funcs.email() }, + { weight: 0.9, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique first names.'); + + await expect( + seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 10000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.2, value: funcs.email() }, + { weight: 0.9, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })), + ).rejects.toThrow("sum of all weights don't equal to 1; 1.1 !== 1"); +}); diff --git a/drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts b/drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts new file mode 100644 index 000000000..57f585297 --- /dev/null +++ b/drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts @@ -0,0 +1,205 @@ +import { + boolean, + date, + integer, + interval, + json, + line, + pgSchema, + point, + real, + text, + time, + timestamp, + varchar, +} from 'drizzle-orm/pg-core'; + +export const schema = pgSchema('seeder_lib_pg'); + +export const moodEnum = schema.enum('enum', ['sad', 'ok', 'happy']); + +export const enumTable = schema.table('enum_table', { + mood: moodEnum('mood_enum'), +}); + +export const defaultTable = schema.table('default_table', { + defaultString: text('default_string'), +}); + +export const valuesFromArrayTable = schema.table('values_from_array_table', { + valuesFromArrayNotNull: varchar('values_from_array_not_null', { length: 256 }).notNull(), + valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).notNull(), +}); + +export const valuesFromArrayUniqueTable = schema.table('values_from_array_unique_table', { + valuesFromArray: varchar('values_from_array', { length: 256 }).unique(), + valuesFromArrayNotNull: varchar('values_from_array_not_null', { length: 256 }).unique().notNull(), + valuesFromArrayWeighted: varchar('values_from_array_weighted', { length: 256 }).unique(), + valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).unique().notNull(), +}); + +export const intPrimaryKeyTable = schema.table('int_primary_key_table', { + intPrimaryKey: integer('int_primary_key').unique(), +}); + +export const numberTable = schema.table('number_table', { + number: real('number'), +}); + +export const numberUniqueTable = schema.table('number_unique_table', { + numberUnique: real('number_unique').unique(), +}); + +export const intTable = schema.table('int_table', { + int: integer('int'), +}); + +export const intUniqueTable = schema.table('int_unique_table', { + intUnique: integer('int_unique').unique(), +}); + +export const booleanTable = schema.table('boolean_table', { + boolean: boolean('boolean'), +}); + +export const dateTable = schema.table('date_table', { + date: date('date'), +}); + +export const timeTable = schema.table('time_table', { + time: time('time'), +}); + +export const timestampTable = schema.table('timestamp_table', { + timestamp: timestamp('timestamp'), +}); + +export const jsonTable = schema.table('json_table', { + json: json('json'), +}); + +export const intervalTable = schema.table('interval_table', { + interval: interval('interval'), +}); + +export const intervalUniqueTable = schema.table('interval_unique_table', { + intervalUnique: interval('interval_unique').unique(), +}); + +export const stringTable = schema.table('string_table', { + string: text('string'), +}); + +export const stringUniqueTable = schema.table('string_unique_table', { + stringUnique: varchar('string_unique', { length: 256 }).unique(), +}); + +export const emailTable = schema.table('email_table', { + email: varchar('email', { length: 256 }).unique(), +}); + +export const firstNameTable = schema.table('first_name_table', { + firstName: varchar('first_name', { length: 256 }), +}); + +export const firstNameUniqueTable = schema.table('first_name_unique_table', { + firstNameUnique: varchar('first_name_unique', { length: 256 }).unique(), +}); + +export const lastNameTable = schema.table('last_name_table', { + lastName: varchar('last_name', { length: 256 }), +}); + +export const lastNameUniqueTable = schema.table('last_name_unique_table', { + lastNameUnique: varchar('last_name_unique', { length: 256 }).unique(), +}); + +export const fullNameTable = schema.table('full_name__table', { + fullName: varchar('full_name_', { length: 256 }), +}); + +export const fullNameUniqueTable = schema.table('full_name_unique_table', { + fullNameUnique: varchar('full_name_unique', { length: 256 }).unique(), +}); + +export const countryTable = schema.table('country_table', { + country: varchar('country', { length: 256 }), +}); + +export const countryUniqueTable = schema.table('country_unique_table', { + countryUnique: varchar('country_unique', { length: 256 }).unique(), +}); + +export const cityTable = schema.table('city_table', { + city: varchar('city', { length: 256 }), +}); + +export const cityUniqueTable = schema.table('city_unique_table', { + cityUnique: varchar('city_unique', { length: 256 }).unique(), +}); + +export const streetAddressTable = schema.table('street_address_table', { + streetAddress: varchar('street_address', { length: 256 }), +}); + +export const streetAddressUniqueTable = schema.table('street_address_unique_table', { + streetAddressUnique: varchar('street_address_unique', { length: 256 }).unique(), +}); + +export const jobTitleTable = schema.table('job_Title_table', { + jobTitle: text('job_title'), +}); + +export const postcodeTable = schema.table('postcode_table', { + postcode: varchar('postcode', { length: 256 }), +}); + +export const postcodeUniqueTable = schema.table('postcode_unique_table', { + postcodeUnique: varchar('postcode_unique', { length: 256 }).unique(), +}); + +export const stateTable = schema.table('state_table', { + state: text('state'), +}); + +export const companyNameTable = schema.table('company_name_table', { + companyName: text('company_name'), +}); + +export const companyNameUniqueTable = schema.table('company_name_unique_table', { + companyNameUnique: varchar('company_name_unique', { length: 256 }).unique(), +}); + +export const loremIpsumTable = schema.table('lorem_ipsum_table', { + loremIpsum: text('lorem_ipsum'), +}); + +export const pointTable = schema.table('point_table', { + point: point('point'), +}); + +export const lineTable = schema.table('line_table', { + line: line('line'), +}); + +// export const pointUniqueTable = schema.table("point_unique_table", { +// pointUnique: point("point_unique").unique(), +// }); + +// export const lineUniqueTable = schema.table("line_unique_table", { +// lineUnique: line("line_unique").unique(), +// }); + +export const phoneNumberTable = schema.table('phone_number_table', { + phoneNumber: varchar('phoneNumber', { length: 256 }).unique(), + phoneNumberTemplate: varchar('phone_number_template', { length: 256 }).unique(), + phoneNumberPrefixes: varchar('phone_number_prefixes', { length: 256 }).unique(), +}); + +export const weightedRandomTable = schema.table('weighted_random_table', { + weightedRandom: varchar('weighted_random', { length: 256 }), +}); + +export const weightedRandomWithUniqueGensTable = schema.table('weighted_random_with_unique_gens_table', { + weightedRandomWithUniqueGens: varchar('weighted_random_with_unique_gens', { length: 256 }).unique(), +}); diff --git a/drizzle-seed/src/tests/pg/pg.test.ts b/drizzle-seed/src/tests/pg/pg.test.ts new file mode 100644 index 000000000..bd9ec7504 --- /dev/null +++ b/drizzle-seed/src/tests/pg/pg.test.ts @@ -0,0 +1,363 @@ +import { PGlite } from '@electric-sql/pglite'; +import { sql } from 'drizzle-orm'; +import type { PgliteDatabase } from 'drizzle-orm/pglite'; +import { drizzle } from 'drizzle-orm/pglite'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../index.ts'; +import * as schema from './pgSchema.ts'; + +let client: PGlite; +let db: PgliteDatabase; + +beforeAll(async () => { + client = new PGlite(); + + db = drizzle(client); + + await db.execute(sql`CREATE SCHEMA "seeder_lib_pg";`); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."customer" ( + "id" varchar(256) PRIMARY KEY NOT NULL, + "company_name" text NOT NULL, + "contact_name" text NOT NULL, + "contact_title" text NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "postal_code" text, + "region" text, + "country" text NOT NULL, + "phone" text NOT NULL, + "fax" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."order_detail" ( + "unit_price" numeric NOT NULL, + "quantity" integer NOT NULL, + "discount" numeric NOT NULL, + "order_id" integer NOT NULL, + "product_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."employee" ( + "id" integer PRIMARY KEY NOT NULL, + "last_name" text NOT NULL, + "first_name" text, + "title" text NOT NULL, + "title_of_courtesy" text NOT NULL, + "birth_date" timestamp NOT NULL, + "hire_date" timestamp NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "postal_code" text NOT NULL, + "country" text NOT NULL, + "home_phone" text NOT NULL, + "extension" integer NOT NULL, + "notes" text NOT NULL, + "reports_to" integer, + "photo_path" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."order" ( + "id" integer PRIMARY KEY NOT NULL, + "order_date" timestamp NOT NULL, + "required_date" timestamp NOT NULL, + "shipped_date" timestamp, + "ship_via" integer NOT NULL, + "freight" numeric NOT NULL, + "ship_name" text NOT NULL, + "ship_city" text NOT NULL, + "ship_region" text, + "ship_postal_code" text, + "ship_country" text NOT NULL, + "customer_id" text NOT NULL, + "employee_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."product" ( + "id" integer PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "quantity_per_unit" text NOT NULL, + "unit_price" numeric NOT NULL, + "units_in_stock" integer NOT NULL, + "units_on_order" integer NOT NULL, + "reorder_level" integer NOT NULL, + "discontinued" integer NOT NULL, + "supplier_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."supplier" ( + "id" integer PRIMARY KEY NOT NULL, + "company_name" text NOT NULL, + "contact_name" text NOT NULL, + "contact_title" text NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "region" text, + "postal_code" text NOT NULL, + "country" text NOT NULL, + "phone" text NOT NULL + ); + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order_detail" ADD CONSTRAINT "order_detail_order_id_order_id_fk" FOREIGN KEY ("order_id") REFERENCES "seeder_lib_pg"."order"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order_detail" ADD CONSTRAINT "order_detail_product_id_product_id_fk" FOREIGN KEY ("product_id") REFERENCES "seeder_lib_pg"."product"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."employee" ADD CONSTRAINT "employee_reports_to_employee_id_fk" FOREIGN KEY ("reports_to") REFERENCES "seeder_lib_pg"."employee"("id") ON DELETE no action ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order" ADD CONSTRAINT "order_customer_id_customer_id_fk" FOREIGN KEY ("customer_id") REFERENCES "seeder_lib_pg"."customer"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order" ADD CONSTRAINT "order_employee_id_employee_id_fk" FOREIGN KEY ("employee_id") REFERENCES "seeder_lib_pg"."employee"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."product" ADD CONSTRAINT "product_supplier_id_supplier_id_fk" FOREIGN KEY ("supplier_id") REFERENCES "seeder_lib_pg"."supplier"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."identity_columns_table" ( + "id" integer generated always as identity, + "id1" integer generated by default as identity, + "name" text + ); + `, + ); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +afterAll(async () => { + await client.close(); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('seeding with identity columns', async () => { + await seed(db, { identityColumnsTable: schema.identityColumnsTable }); + + const result = await db.select().from(schema.identityColumnsTable); + + expect(result.length).toBe(10); +}); diff --git a/drizzle-seed/src/tests/pg/pgSchema.ts b/drizzle-seed/src/tests/pg/pgSchema.ts new file mode 100644 index 000000000..2c1c95045 --- /dev/null +++ b/drizzle-seed/src/tests/pg/pgSchema.ts @@ -0,0 +1,136 @@ +// import { serial, integer, varchar, pgSchema, getTableConfig as getPgTableConfig } from "drizzle-orm/pg-core"; + +// export const schema = pgSchema("seeder_lib_pg"); + +// export const users = schema.table("users", { +// id: serial("id").primaryKey(), +// name: varchar("name", { length: 256 }), +// email: varchar("email", { length: 256 }), +// phone: varchar("phone", { length: 256 }), +// password: varchar("password", { length: 256 }) +// }); + +// export const posts = schema.table("posts", { +// id: serial("id").primaryKey(), +// title: varchar("title", { length: 256 }), +// content: varchar("content", { length: 256 }), +// userId: integer("user_id").references(() => users.id) +// }); + +// export const comments = schema.table("comments", { +// id: serial("id").primaryKey(), +// content: varchar("content", { length: 256 }), +// postId: integer("post_id").references(() => posts.id), +// userId: integer("user_id").references(() => users.id) +// }); + +import type { AnyPgColumn } from 'drizzle-orm/pg-core'; +import { integer, numeric, pgSchema, text, timestamp, varchar } from 'drizzle-orm/pg-core'; + +export const schema = pgSchema('seeder_lib_pg'); + +export const customers = schema.table('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = schema.table( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to').references((): AnyPgColumn => employees.id), + photoPath: text('photo_path'), + }, +); + +export const orders = schema.table('order', { + id: integer('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = schema.table('supplier', { + id: integer('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = schema.table('product', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = schema.table('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); + +export const identityColumnsTable = schema.table('identity_columns_table', { + id: integer().generatedAlwaysAsIdentity(), + id1: integer().generatedByDefaultAsIdentity(), + name: text(), +}); diff --git a/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqliteSchema.ts b/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqliteSchema.ts new file mode 100644 index 000000000..f9737344e --- /dev/null +++ b/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqliteSchema.ts @@ -0,0 +1,15 @@ +import { blob, integer, numeric, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const allDataTypes = sqliteTable('all_data_types', { + integerNumber: integer('integer_number', { mode: 'number' }), + integerBoolean: integer('integer_boolean', { mode: 'boolean' }), + integerTimestamp: integer('integer_timestamp', { mode: 'timestamp' }), + integerTimestampms: integer('integer_timestampms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { mode: 'text' }), + textJson: text('text_json', { mode: 'json' }), + blobBigint: blob('blob_bigint', { mode: 'bigint' }), + blobBuffer: blob('blob_buffer', { mode: 'buffer' }), + blobJson: blob('blob_json', { mode: 'json' }), + numeric: numeric('numeric'), +}); diff --git a/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts b/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts new file mode 100644 index 000000000..b377ba9a1 --- /dev/null +++ b/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts @@ -0,0 +1,53 @@ +import BetterSqlite3 from 'better-sqlite3'; +import { sql } from 'drizzle-orm'; +import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import { afterAll, beforeAll, expect, test } from 'vitest'; +import { seed } from '../../../index.ts'; +import * as schema from './sqliteSchema.ts'; + +let client: BetterSqlite3.Database; +let db: BetterSQLite3Database; + +beforeAll(async () => { + client = new BetterSqlite3(':memory:'); + + db = drizzle(client); + + db.run( + sql.raw(` + CREATE TABLE \`all_data_types\` ( + \`integer_number\` integer, + \`integer_boolean\` integer, + \`integer_timestamp\` integer, + \`integer_timestampms\` integer, + \`real\` real, + \`text\` text, + \`text_json\` text, + \`blob_bigint\` blob, + \`blob_buffer\` blob, + \`blob_json\` blob, + \`numeric\` numeric +); + + `), + ); +}); + +afterAll(async () => { + client.close(); +}); + +test('basic seed test', async () => { + // migrate(db, { migrationsFolder: path.join(__dirname, "sqliteMigrations") }); + + await seed(db, schema, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); + + client.close(); +}); diff --git a/drizzle-seed/src/tests/sqlite/sqlite.test.ts b/drizzle-seed/src/tests/sqlite/sqlite.test.ts new file mode 100644 index 000000000..50db1fa8b --- /dev/null +++ b/drizzle-seed/src/tests/sqlite/sqlite.test.ts @@ -0,0 +1,290 @@ +import BetterSqlite3 from 'better-sqlite3'; +import { sql } from 'drizzle-orm'; +import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../index.ts'; +import * as schema from './sqliteSchema.ts'; + +let client: BetterSqlite3.Database; +let db: BetterSQLite3Database; + +beforeAll(async () => { + client = new BetterSqlite3(':memory:'); + + db = drizzle(client); + + db.run( + sql.raw(` + CREATE TABLE \`customer\` ( + \`id\` text PRIMARY KEY NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text, + \`region\` text, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + \`fax\` text +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`order_detail\` ( + \`unit_price\` numeric NOT NULL, + \`quantity\` integer NOT NULL, + \`discount\` numeric NOT NULL, + \`order_id\` integer NOT NULL, + \`product_id\` integer NOT NULL, + FOREIGN KEY (\`order_id\`) REFERENCES \`order\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`product_id\`) REFERENCES \`product\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`employee\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`last_name\` text NOT NULL, + \`first_name\` text, + \`title\` text NOT NULL, + \`title_of_courtesy\` text NOT NULL, + \`birth_date\` integer NOT NULL, + \`hire_date\` integer NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`home_phone\` text NOT NULL, + \`extension\` integer NOT NULL, + \`notes\` text NOT NULL, + \`reports_to\` integer, + \`photo_path\` text, + FOREIGN KEY (\`reports_to\`) REFERENCES \`employee\`(\`id\`) ON UPDATE no action ON DELETE no action +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`order\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`order_date\` integer NOT NULL, + \`required_date\` integer NOT NULL, + \`shipped_date\` integer, + \`ship_via\` integer NOT NULL, + \`freight\` numeric NOT NULL, + \`ship_name\` text NOT NULL, + \`ship_city\` text NOT NULL, + \`ship_region\` text, + \`ship_postal_code\` text, + \`ship_country\` text NOT NULL, + \`customer_id\` text NOT NULL, + \`employee_id\` integer NOT NULL, + FOREIGN KEY (\`customer_id\`) REFERENCES \`customer\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`employee_id\`) REFERENCES \`employee\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`product\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`name\` text NOT NULL, + \`quantity_per_unit\` text NOT NULL, + \`unit_price\` numeric NOT NULL, + \`units_in_stock\` integer NOT NULL, + \`units_on_order\` integer NOT NULL, + \`reorder_level\` integer NOT NULL, + \`discontinued\` integer NOT NULL, + \`supplier_id\` integer NOT NULL, + FOREIGN KEY (\`supplier_id\`) REFERENCES \`supplier\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`supplier\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`region\` text, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`phone\` text NOT NULL +); + `), + ); +}); + +afterAll(async () => { + client.close(); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); diff --git a/drizzle-seed/src/tests/sqlite/sqliteSchema.ts b/drizzle-seed/src/tests/sqlite/sqliteSchema.ts new file mode 100644 index 000000000..fa00dd365 --- /dev/null +++ b/drizzle-seed/src/tests/sqlite/sqliteSchema.ts @@ -0,0 +1,107 @@ +import { foreignKey, integer, numeric, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const customers = sqliteTable('customer', { + id: text('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = sqliteTable( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: integer('birth_date', { mode: 'timestamp' }).notNull(), + hireDate: integer('hire_date', { mode: 'timestamp' }).notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to'), + photoPath: text('photo_path'), + }, + (table) => ({ + reportsToFk: foreignKey(() => ({ + columns: [table.reportsTo], + foreignColumns: [table.id], + })), + }), +); + +export const orders = sqliteTable('order', { + id: integer('id').primaryKey(), + orderDate: integer('order_date', { mode: 'timestamp' }).notNull(), + requiredDate: integer('required_date', { mode: 'timestamp' }).notNull(), + shippedDate: integer('shipped_date', { mode: 'timestamp' }), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = sqliteTable('supplier', { + id: integer('id').primaryKey({ autoIncrement: true }), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = sqliteTable('product', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = sqliteTable('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); diff --git a/drizzle-seed/src/tests/vitest.config.ts b/drizzle-seed/src/tests/vitest.config.ts new file mode 100644 index 000000000..a74ccd37c --- /dev/null +++ b/drizzle-seed/src/tests/vitest.config.ts @@ -0,0 +1,25 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: [ + './src/tests/pg/**/*.test.ts', + './src/tests/mysql/**/*.test.ts', + './src/tests/sqlite/**/*.test.ts', + ], + exclude: [], + typecheck: { + tsconfig: 'tsconfig.json', + }, + testTimeout: 100000, + hookTimeout: 100000, + isolate: true, + poolOptions: { + threads: { + singleThread: true, + }, + }, + maxWorkers: 1, + fileParallelism: false, + }, +}); diff --git a/drizzle-seed/src/types/drizzleStudio.ts b/drizzle-seed/src/types/drizzleStudio.ts new file mode 100644 index 000000000..c3b635b97 --- /dev/null +++ b/drizzle-seed/src/types/drizzleStudio.ts @@ -0,0 +1,65 @@ +export type DbPrimaryKey = { + name: string; + columns: string[]; +}; + +export type DbForeignKey = { + name: string; + tableFrom: string; + columnsFrom: string[]; + schemaFrom: string; + schemaTo: string; + tableTo: string; + columnsTo: string[]; + onUpdate?: string; + onDelete?: string; +}; + +export type DbColumn = { + name: string; + type: string; + primaryKey: boolean; + notNull: boolean; + default?: any; + isUnique?: any; + autoIncrement?: boolean; + uniqueName?: string; + nullsNotDistinct?: boolean; + onUpdate?: boolean; +}; + +export type DbTable = { + name: string; + type: 'table'; + database?: string; + schema: string; + columns: Record; + indexes: Record; + foreignKeys: Record; + compositePrimaryKeys: Record; + uniqueConstraints: Record; +}; + +export type DbView = Omit & { + type: 'view' | 'mat_view'; +}; + +export type DbSchema = { + database?: string; + tables: Record; + views: Record; + enums: Record; +}; + +export type DrizzleStudioObjectType = { [schemaName: string]: DbSchema }; + +export type DrizzleStudioRelationType = { + name: string; + type: 'one' | 'many'; + table: string; + schema: string; + columns: string[]; + refTable: string; + refSchema: string; + refColumns: string[]; +}; diff --git a/drizzle-seed/src/types/seedService.ts b/drizzle-seed/src/types/seedService.ts new file mode 100644 index 000000000..2490d5e26 --- /dev/null +++ b/drizzle-seed/src/types/seedService.ts @@ -0,0 +1,45 @@ +import type { AbstractGenerator } from '../services/GeneratorsWrappers.ts'; +import type { Prettify } from './tables.ts'; + +export type TableGeneratorsType = { + [columnName: string]: Prettify< + { + hasSelfRelation?: boolean | undefined; + hasRelation?: boolean | undefined; + pRNGSeed: number; + } & GeneratePossibleGeneratorsColumnType + >; +}; + +export type GeneratePossibleGeneratorsColumnType = { + columnName: string; + generator: AbstractGenerator | undefined; + isUnique: boolean; + notNull: boolean; + generatedIdentityType?: 'always' | 'byDefault' | undefined; +}; + +export type GeneratePossibleGeneratorsTableType = Prettify<{ + tableName: string; + count?: number; + withCount?: number; + withFromTable: { + [withFromTableName: string]: { + repeatedValuesCount: + | number + | { weight: number; count: number | number[] }[]; + weightedCountSeed?: number; + }; + }; + // repeatedValuesCount?: number, + // withFromTableName?: string, + columnsPossibleGenerators: GeneratePossibleGeneratorsColumnType[]; +}>; + +export type RefinementsType = Prettify<{ + [tableName: string]: { + count?: number; + columns: { [columnName: string]: AbstractGenerator<{}> }; + with?: { [tableName: string]: number | { weight: number; count: number | number[] }[] }; + }; +}>; diff --git a/drizzle-seed/src/types/tables.ts b/drizzle-seed/src/types/tables.ts new file mode 100644 index 000000000..637e96c48 --- /dev/null +++ b/drizzle-seed/src/types/tables.ts @@ -0,0 +1,36 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export type Column = { + name: string; + dataType: string; + columnType: string; + default?: any; + hasDefault: boolean; + enumValues?: string[]; + isUnique: boolean; + notNull: boolean; + generatedIdentityType?: 'always' | 'byDefault' | undefined; +}; + +export type Table = { + name: string; + columns: Column[]; + primaryKeys: string[]; +}; + +export type Relation = { + // name: string; + // type: "one" | "many"; + table: string; + // schema: string; + columns: string[]; + refTable: string; + // refSchema: string; + refColumns: string[]; +}; + +export type Prettify = + & { + [K in keyof T]: T[K]; + } + & {}; diff --git a/drizzle-seed/tsconfig.build.json b/drizzle-seed/tsconfig.build.json new file mode 100644 index 000000000..3377281ba --- /dev/null +++ b/drizzle-seed/tsconfig.build.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "src" + }, + "include": ["src"] +} diff --git a/drizzle-seed/tsconfig.json b/drizzle-seed/tsconfig.json new file mode 100644 index 000000000..c75766c3f --- /dev/null +++ b/drizzle-seed/tsconfig.json @@ -0,0 +1,48 @@ +{ + "compilerOptions": { + "isolatedModules": true, + "composite": false, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["es2020", "es2018", "es2017", "es7", "es6", "es5", "es2022"], + "declarationMap": false, + "sourceMap": true, + "allowJs": true, + "incremental": false, + "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + "exactOptionalPropertyTypes": false, /* Interpret optional property types as written, rather than adding 'undefined'. */ + "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + "allowUnusedLabels": false, /* Disable error reporting for unused labels. */ + "allowUnreachableCode": false, /* Disable error reporting for unreachable code. */ + "skipLibCheck": true, /* Skip type checking all .d.ts files. */ + "noErrorTruncation": true, /* Disable truncating types in error messages. */ + "checkJs": true, + "noEmit": true, + "allowImportingTsExtensions": true, + "outDir": "dist", + "baseUrl": ".", + "declaration": true, + "paths": { + "~/*": ["src/*"] + } + }, + "exclude": ["**/dist"], + "include": ["src", "*.ts"] +} diff --git a/integration-tests/package.json b/integration-tests/package.json index b7a5cca5b..389001d8b 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -17,7 +17,7 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20241004.0", "@libsql/client": "^0.10.0", - "@neondatabase/serverless": "0.9.0", + "@neondatabase/serverless": "^0.9.0", "@originjs/vite-plugin-commonjs": "^1.0.3", "@paralleldrive/cuid2": "^2.2.2", "@types/async-retry": "^1.4.8", @@ -61,6 +61,7 @@ "drizzle-typebox": "workspace:../drizzle-typebox/dist", "drizzle-valibot": "workspace:../drizzle-valibot/dist", "drizzle-zod": "workspace:../drizzle-zod/dist", + "drizzle-seed": "workspace:../drizzle-seed/dist", "express": "^4.18.2", "get-port": "^7.0.0", "mysql2": "^3.3.3", diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 49d9c3025..5e5f4ec72 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -5358,24 +5358,64 @@ export function tests() { test('insert multiple rows into table with generated identity column', async (ctx) => { const { db } = ctx.pg; - const users = pgTable('users', { - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), + const identityColumnsTable = pgTable('identity_columns_table', { + id: integer('id').generatedAlwaysAsIdentity(), + id1: integer('id1').generatedByDefaultAsIdentity(), name: text('name').notNull(), }); - await db.execute(sql`drop table if exists ${users}`); - await db.execute(sql`create table ${users} ("id" integer generated always as identity primary key, "name" text)`); + // not passing identity columns + await db.execute(sql`drop table if exists ${identityColumnsTable}`); + await db.execute( + sql`create table ${identityColumnsTable} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, + ); - const result = await db.insert(users).values([ + let result = await db.insert(identityColumnsTable).values([ { name: 'John' }, { name: 'Jane' }, { name: 'Bob' }, ]).returning(); expect(result).toEqual([ - { id: 1, name: 'John' }, - { id: 2, name: 'Jane' }, - { id: 3, name: 'Bob' }, + { id: 1, id1: 1, name: 'John' }, + { id: 2, id1: 2, name: 'Jane' }, + { id: 3, id1: 3, name: 'Bob' }, + ]); + + // passing generated by default as identity column + await db.execute(sql`drop table if exists ${identityColumnsTable}`); + await db.execute( + sql`create table ${identityColumnsTable} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, + ); + + result = await db.insert(identityColumnsTable).values([ + { name: 'John', id1: 3 }, + { name: 'Jane', id1: 5 }, + { name: 'Bob', id1: 5 }, + ]).returning(); + + expect(result).toEqual([ + { id: 1, id1: 3, name: 'John' }, + { id: 2, id1: 5, name: 'Jane' }, + { id: 3, id1: 5, name: 'Bob' }, + ]); + + // passing all identity columns + await db.execute(sql`drop table if exists ${identityColumnsTable}`); + await db.execute( + sql`create table ${identityColumnsTable} ("id" integer generated always as identity, "id1" integer generated by default as identity, "name" text)`, + ); + + result = await db.insert(identityColumnsTable).overridingSystemValue().values([ + { name: 'John', id: 2, id1: 3 }, + { name: 'Jane', id: 4, id1: 5 }, + { name: 'Bob', id: 4, id1: 5 }, + ]).returning(); + + expect(result).toEqual([ + { id: 2, id1: 3, name: 'John' }, + { id: 4, id1: 5, name: 'Jane' }, + { id: 4, id1: 5, name: 'Bob' }, ]); }); }); diff --git a/integration-tests/tests/seeder/mysql.test.ts b/integration-tests/tests/seeder/mysql.test.ts new file mode 100644 index 000000000..5ae7f9f15 --- /dev/null +++ b/integration-tests/tests/seeder/mysql.test.ts @@ -0,0 +1,490 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import type { MySql2Database } from 'drizzle-orm/mysql2'; +import { drizzle } from 'drizzle-orm/mysql2'; +import { reset, seed } from 'drizzle-seed'; +import getPort from 'get-port'; +import type { Connection } from 'mysql2/promise'; +import { createConnection } from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import * as schema from './mysqlSchema.ts'; + +let mysqlContainer: Docker.Container; +let client: Connection; +let db: MySql2Database; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +const createNorthwindTables = async () => { + await db.execute( + sql` + CREATE TABLE \`customer\` ( + \`id\` varchar(256) NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text, + \`region\` text, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + \`fax\` text, + CONSTRAINT \`customer_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`order_detail\` ( + \`unit_price\` float NOT NULL, + \`quantity\` int NOT NULL, + \`discount\` float NOT NULL, + \`order_id\` int NOT NULL, + \`product_id\` int NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`employee\` ( + \`id\` int NOT NULL, + \`last_name\` text NOT NULL, + \`first_name\` text, + \`title\` text NOT NULL, + \`title_of_courtesy\` text NOT NULL, + \`birth_date\` timestamp NOT NULL, + \`hire_date\` timestamp NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`home_phone\` text NOT NULL, + \`extension\` int NOT NULL, + \`notes\` text NOT NULL, + \`reports_to\` int, + \`photo_path\` text, + CONSTRAINT \`employee_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`order\` ( + \`id\` int NOT NULL, + \`order_date\` timestamp NOT NULL, + \`required_date\` timestamp NOT NULL, + \`shipped_date\` timestamp, + \`ship_via\` int NOT NULL, + \`freight\` float NOT NULL, + \`ship_name\` text NOT NULL, + \`ship_city\` text NOT NULL, + \`ship_region\` text, + \`ship_postal_code\` text, + \`ship_country\` text NOT NULL, + \`customer_id\` varchar(256) NOT NULL, + \`employee_id\` int NOT NULL, + CONSTRAINT \`order_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`product\` ( + \`id\` int NOT NULL, + \`name\` text NOT NULL, + \`quantity_per_unit\` text NOT NULL, + \`unit_price\` float NOT NULL, + \`units_in_stock\` int NOT NULL, + \`units_on_order\` int NOT NULL, + \`reorder_level\` int NOT NULL, + \`discontinued\` int NOT NULL, + \`supplier_id\` int NOT NULL, + CONSTRAINT \`product_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`supplier\` ( + \`id\` int NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`region\` text, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + CONSTRAINT \`supplier_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order_detail\` ADD CONSTRAINT \`order_detail_order_id_order_id_fk\` FOREIGN KEY (\`order_id\`) REFERENCES \`order\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order_detail\` ADD CONSTRAINT \`order_detail_product_id_product_id_fk\` FOREIGN KEY (\`product_id\`) REFERENCES \`product\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`employee\` ADD CONSTRAINT \`employee_reports_to_employee_id_fk\` FOREIGN KEY (\`reports_to\`) REFERENCES \`employee\`(\`id\`) ON DELETE no action ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order\` ADD CONSTRAINT \`order_customer_id_customer_id_fk\` FOREIGN KEY (\`customer_id\`) REFERENCES \`customer\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`order\` ADD CONSTRAINT \`order_employee_id_employee_id_fk\` FOREIGN KEY (\`employee_id\`) REFERENCES \`employee\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); + + await db.execute( + sql` + ALTER TABLE \`product\` ADD CONSTRAINT \`product_supplier_id_supplier_id_fk\` FOREIGN KEY (\`supplier_id\`) REFERENCES \`supplier\`(\`id\`) ON DELETE cascade ON UPDATE no action; + `, + ); +}; + +const createAllDataTypesTable = async () => { + await db.execute( + sql` + CREATE TABLE \`all_data_types\` ( + \`integer\` int, + \`tinyint\` tinyint, + \`smallint\` smallint, + \`mediumint\` mediumint, + \`bigint\` bigint, + \`bigint_number\` bigint, + \`real\` real, + \`decimal\` decimal, + \`double\` double, + \`float\` float, + \`serial\` serial AUTO_INCREMENT, + \`binary\` binary(255), + \`varbinary\` varbinary(256), + \`char\` char(255), + \`varchar\` varchar(256), + \`text\` text, + \`boolean\` boolean, + \`date_string\` date, + \`date\` date, + \`datetime\` datetime, + \`datetimeString\` datetime, + \`time\` time, + \`year\` year, + \`timestamp_date\` timestamp, + \`timestamp_string\` timestamp, + \`json\` json, + \`popularity\` enum('unknown','known','popular') + ); + `, + ); +}; + +const createAllGeneratorsTables = async () => { + await db.execute( + sql` + CREATE TABLE \`datetime_table\` ( + \`datetime\` datetime + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`year_table\` ( + \`year\` year + ); + `, + ); +}; + +beforeAll(async () => { + const connectionString = await createDockerDB(); + + const sleep = 1000; + let timeLeft = 40000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + db = drizzle(client); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } + + await createNorthwindTables(); + await createAllDataTypesTable(); + await createAllGeneratorsTables(); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +// All data types test ------------------------------- +test('basic seed test for all mysql data types', async () => { + await seed(db, schema, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); + +// All generators test------------------------------- +const count = 10000; + +test('datetime generator test', async () => { + await seed(db, { datetimeTable: schema.datetimeTable }).refine((funcs) => ({ + datetimeTable: { + count, + columns: { + datetime: funcs.datetime(), + }, + }, + })); + + const data = await db.select().from(schema.datetimeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('year generator test', async () => { + await seed(db, { yearTable: schema.yearTable }).refine((funcs) => ({ + yearTable: { + count, + columns: { + year: funcs.year(), + }, + }, + })); + + const data = await db.select().from(schema.yearTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); diff --git a/integration-tests/tests/seeder/mysqlSchema.ts b/integration-tests/tests/seeder/mysqlSchema.ts new file mode 100644 index 000000000..2caa97fa0 --- /dev/null +++ b/integration-tests/tests/seeder/mysqlSchema.ts @@ -0,0 +1,167 @@ +import type { AnyMySqlColumn } from 'drizzle-orm/mysql-core'; +import { + bigint, + binary, + boolean, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + mysqlEnum, + mysqlTable, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, +} from 'drizzle-orm/mysql-core'; + +export const customers = mysqlTable('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = mysqlTable( + 'employee', + { + id: int('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: int('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: int('reports_to').references((): AnyMySqlColumn => employees.id), + photoPath: text('photo_path'), + }, +); + +export const orders = mysqlTable('order', { + id: int('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: int('ship_via').notNull(), + freight: float('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: varchar('customer_id', { length: 256 }) + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: int('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = mysqlTable('supplier', { + id: int('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = mysqlTable('product', { + id: int('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: float('unit_price').notNull(), + unitsInStock: int('units_in_stock').notNull(), + unitsOnOrder: int('units_on_order').notNull(), + reorderLevel: int('reorder_level').notNull(), + discontinued: int('discontinued').notNull(), + + supplierId: int('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = mysqlTable('order_detail', { + unitPrice: float('unit_price').notNull(), + quantity: int('quantity').notNull(), + discount: float('discount').notNull(), + + orderId: int('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: int('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); + +// All data types table ------------------------------- +export const allDataTypes = mysqlTable('all_data_types', { + int: int('integer'), + tinyint: tinyint('tinyint'), + smallint: smallint('smallint'), + mediumint: mediumint('mediumint'), + biginteger: bigint('bigint', { mode: 'bigint' }), + bigintNumber: bigint('bigint_number', { mode: 'number' }), + real: real('real'), + decimal: decimal('decimal'), + double: double('double'), + float: float('float'), + serial: serial('serial'), + binary: binary('binary', { length: 255 }), + varbinary: varbinary('varbinary', { length: 256 }), + char: char('char', { length: 255 }), + varchar: varchar('varchar', { length: 256 }), + text: text('text'), + boolean: boolean('boolean'), + dateString: date('date_string', { mode: 'string' }), + date: date('date', { mode: 'date' }), + datetime: datetime('datetime', { mode: 'date' }), + datetimeString: datetime('datetimeString', { mode: 'string' }), + time: time('time'), + year: year('year'), + timestampDate: timestamp('timestamp_date', { mode: 'date' }), + timestampString: timestamp('timestamp_string', { mode: 'string' }), + json: json('json'), + mysqlEnum: mysqlEnum('popularity', ['unknown', 'known', 'popular']), +}); + +// All generators tables ------------------------------- +export const datetimeTable = mysqlTable('datetime_table', { + datetime: datetime('datetime'), +}); + +export const yearTable = mysqlTable('year_table', { + year: year('year'), +}); diff --git a/integration-tests/tests/seeder/pg.test.ts b/integration-tests/tests/seeder/pg.test.ts new file mode 100644 index 000000000..33cd06f7e --- /dev/null +++ b/integration-tests/tests/seeder/pg.test.ts @@ -0,0 +1,1775 @@ +import { PGlite } from '@electric-sql/pglite'; +import { sql } from 'drizzle-orm'; +import type { PgliteDatabase } from 'drizzle-orm/pglite'; +import { drizzle } from 'drizzle-orm/pglite'; +import { firstNames, lastNames, reset, seed } from 'drizzle-seed'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import * as schema from './pgSchema.ts'; + +let client: PGlite; +let db: PgliteDatabase; + +const createNorthwindTables = async () => { + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."customer" ( + "id" varchar(256) PRIMARY KEY NOT NULL, + "company_name" text NOT NULL, + "contact_name" text NOT NULL, + "contact_title" text NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "postal_code" text, + "region" text, + "country" text NOT NULL, + "phone" text NOT NULL, + "fax" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."order_detail" ( + "unit_price" numeric NOT NULL, + "quantity" integer NOT NULL, + "discount" numeric NOT NULL, + "order_id" integer NOT NULL, + "product_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."employee" ( + "id" integer PRIMARY KEY NOT NULL, + "last_name" text NOT NULL, + "first_name" text, + "title" text NOT NULL, + "title_of_courtesy" text NOT NULL, + "birth_date" timestamp NOT NULL, + "hire_date" timestamp NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "postal_code" text NOT NULL, + "country" text NOT NULL, + "home_phone" text NOT NULL, + "extension" integer NOT NULL, + "notes" text NOT NULL, + "reports_to" integer, + "photo_path" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."order" ( + "id" integer PRIMARY KEY NOT NULL, + "order_date" timestamp NOT NULL, + "required_date" timestamp NOT NULL, + "shipped_date" timestamp, + "ship_via" integer NOT NULL, + "freight" numeric NOT NULL, + "ship_name" text NOT NULL, + "ship_city" text NOT NULL, + "ship_region" text, + "ship_postal_code" text, + "ship_country" text NOT NULL, + "customer_id" text NOT NULL, + "employee_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."product" ( + "id" integer PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "quantity_per_unit" text NOT NULL, + "unit_price" numeric NOT NULL, + "units_in_stock" integer NOT NULL, + "units_on_order" integer NOT NULL, + "reorder_level" integer NOT NULL, + "discontinued" integer NOT NULL, + "supplier_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."supplier" ( + "id" integer PRIMARY KEY NOT NULL, + "company_name" text NOT NULL, + "contact_name" text NOT NULL, + "contact_title" text NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "region" text, + "postal_code" text NOT NULL, + "country" text NOT NULL, + "phone" text NOT NULL + ); + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order_detail" ADD CONSTRAINT "order_detail_order_id_order_id_fk" FOREIGN KEY ("order_id") REFERENCES "seeder_lib_pg"."order"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order_detail" ADD CONSTRAINT "order_detail_product_id_product_id_fk" FOREIGN KEY ("product_id") REFERENCES "seeder_lib_pg"."product"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."employee" ADD CONSTRAINT "employee_reports_to_employee_id_fk" FOREIGN KEY ("reports_to") REFERENCES "seeder_lib_pg"."employee"("id") ON DELETE no action ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order" ADD CONSTRAINT "order_customer_id_customer_id_fk" FOREIGN KEY ("customer_id") REFERENCES "seeder_lib_pg"."customer"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."order" ADD CONSTRAINT "order_employee_id_employee_id_fk" FOREIGN KEY ("employee_id") REFERENCES "seeder_lib_pg"."employee"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + DO $$ BEGIN + ALTER TABLE "seeder_lib_pg"."product" ADD CONSTRAINT "product_supplier_id_supplier_id_fk" FOREIGN KEY ("supplier_id") REFERENCES "seeder_lib_pg"."supplier"("id") ON DELETE cascade ON UPDATE no action; + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); +}; + +const createAllDataTypesTable = async () => { + await db.execute( + sql` + DO $$ BEGIN + CREATE TYPE "seeder_lib_pg"."mood_enum" AS ENUM('sad', 'ok', 'happy'); + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."all_data_types" ( + "integer" integer, + "smallint" smallint, + "bigint" bigint, + "bigint_number" bigint, + "serial" serial NOT NULL, + "smallserial" "smallserial" NOT NULL, + "bigserial" bigserial, + "bigserial_number" bigserial NOT NULL, + "boolean" boolean, + "text" text, + "varchar" varchar(256), + "char" char(256), + "numeric" numeric, + "decimal" numeric, + "real" real, + "double_precision" double precision, + "json" json, + "jsonb" jsonb, + "time" time, + "timestamp_date" timestamp, + "timestamp_string" timestamp, + "date_string" date, + "date" date, + "interval" interval, + "point" "point", + "point_tuple" "point", + "line" "line", + "line_tuple" "line", + "mood_enum" "seeder_lib_pg"."mood_enum" + ); + `, + ); +}; + +const createAllGeneratorsTables = async () => { + await db.execute( + sql` + DO $$ BEGIN + CREATE TYPE "seeder_lib_pg"."enum" AS ENUM('sad', 'ok', 'happy'); + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."boolean_table" ( + "boolean" boolean + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_table" ( + "city" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_unique_table" ( + "city_unique" varchar(256), + CONSTRAINT "city_unique_table_city_unique_unique" UNIQUE("city_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_table" ( + "company_name" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_unique_table" ( + "company_name_unique" varchar(256), + CONSTRAINT "company_name_unique_table_company_name_unique_unique" UNIQUE("company_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_table" ( + "country" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_unique_table" ( + "country_unique" varchar(256), + CONSTRAINT "country_unique_table_country_unique_unique" UNIQUE("country_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."date_table" ( + "date" date + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."default_table" ( + "default_string" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."email_table" ( + "email" varchar(256), + CONSTRAINT "email_table_email_unique" UNIQUE("email") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."enum_table" ( + "mood_enum" "seeder_lib_pg"."enum" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."first_name_table" ( + "first_name" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."first_name_unique_table" ( + "first_name_unique" varchar(256), + CONSTRAINT "first_name_unique_table_first_name_unique_unique" UNIQUE("first_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name__table" ( + "full_name_" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name_unique_table" ( + "full_name_unique" varchar(256), + CONSTRAINT "full_name_unique_table_full_name_unique_unique" UNIQUE("full_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_primary_key_table" ( + "int_primary_key" integer, + CONSTRAINT "int_primary_key_table_int_primary_key_unique" UNIQUE("int_primary_key") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_table" ( + "int" integer + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_unique_table" ( + "int_unique" integer, + CONSTRAINT "int_unique_table_int_unique_unique" UNIQUE("int_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_table" ( + "interval" interval + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_unique_table" ( + "interval_unique" interval, + CONSTRAINT "interval_unique_table_interval_unique_unique" UNIQUE("interval_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."job_title_table" ( + "job_title" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."json_table" ( + "json" json + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_table" ( + "last_name" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_unique_table" ( + "last_name_unique" varchar(256), + CONSTRAINT "last_name_unique_table_last_name_unique_unique" UNIQUE("last_name_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."line_table" ( + "line" "line" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."lorem_ipsum_table" ( + "lorem_ipsum" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_table" ( + "number" real + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_unique_table" ( + "number_unique" real, + CONSTRAINT "number_unique_table_number_unique_unique" UNIQUE("number_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."phone_number_table" ( + "phoneNumber" varchar(256), + "phone_number_template" varchar(256), + "phone_number_prefixes" varchar(256), + CONSTRAINT "phone_number_table_phoneNumber_unique" UNIQUE("phoneNumber"), + CONSTRAINT "phone_number_table_phone_number_template_unique" UNIQUE("phone_number_template"), + CONSTRAINT "phone_number_table_phone_number_prefixes_unique" UNIQUE("phone_number_prefixes") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."point_table" ( + "point" "point" + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_table" ( + "postcode" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_unique_table" ( + "postcode_unique" varchar(256), + CONSTRAINT "postcode_unique_table_postcode_unique_unique" UNIQUE("postcode_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."state_table" ( + "state" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_table" ( + "street_address" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_unique_table" ( + "street_address_unique" varchar(256), + CONSTRAINT "street_address_unique_table_street_address_unique_unique" UNIQUE("street_address_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_table" ( + "string" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_unique_table" ( + "string_unique" varchar(256), + CONSTRAINT "string_unique_table_string_unique_unique" UNIQUE("string_unique") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."time_table" ( + "time" time + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."timestamp_table" ( + "timestamp" timestamp + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_table" ( + "values_from_array_not_null" varchar(256) NOT NULL, + "values_from_array_weighted_not_null" varchar(256) NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_unique_table" ( + "values_from_array" varchar(256), + "values_from_array_not_null" varchar(256) NOT NULL, + "values_from_array_weighted" varchar(256), + "values_from_array_weighted_not_null" varchar(256) NOT NULL, + CONSTRAINT "values_from_array_unique_table_values_from_array_unique" UNIQUE("values_from_array"), + CONSTRAINT "values_from_array_unique_table_values_from_array_not_null_unique" UNIQUE("values_from_array_not_null"), + CONSTRAINT "values_from_array_unique_table_values_from_array_weighted_unique" UNIQUE("values_from_array_weighted"), + CONSTRAINT "values_from_array_unique_table_values_from_array_weighted_not_null_unique" UNIQUE("values_from_array_weighted_not_null") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."weighted_random_table" ( + "weighted_random" varchar(256) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."weighted_random_with_unique_gens_table" ( + "weighted_random_with_unique_gens" varchar(256), + CONSTRAINT "weighted_random_with_unique_gens_table_weighted_random_with_unique_gens_unique" UNIQUE("weighted_random_with_unique_gens") + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."identity_columns_table" ( + "id" integer GENERATED ALWAYS AS IDENTITY, + "id1" integer, + "name" text + ); + `, + ); +}; + +beforeAll(async () => { + client = new PGlite(); + + db = drizzle(client); + + await db.execute(sql`CREATE SCHEMA IF NOT EXISTS "seeder_lib_pg";`); + + await createNorthwindTables(); + await createAllDataTypesTable(); + await createAllGeneratorsTables(); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +afterAll(async () => { + await client.close(); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('seeding with identity columns', async () => { + await seed(db, { identityColumnsTable: schema.identityColumnsTable }); + + const result = await db.select().from(schema.identityColumnsTable); + + expect(result.length).toBe(10); +}); + +// All data types test ------------------------------- +test('basic seed test for all postgres data types', async () => { + await seed(db, { allDataTypes: schema.allDataTypes }, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); + +// All generators test------------------------------- +const count = 10000; + +test('enum generator test', async () => { + await seed(db, { enumTable: schema.enumTable }).refine(() => ({ + enumTable: { + count, + }, + })); + + const data = await db.select().from(schema.enumTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('default generator test', async () => { + await seed(db, { defaultTable: schema.defaultTable }).refine((funcs) => ({ + defaultTable: { + count, + columns: { + defaultString: funcs.default({ defaultValue: 'default string' }), + }, + }, + })); + + const data = await db.select().from(schema.defaultTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('valuesFromArray generator test', async () => { + await seed(db, { valuesFromArrayTable: schema.valuesFromArrayTable }).refine((funcs) => ({ + valuesFromArrayTable: { + count, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ values: lastNames }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames, weight: 0.3 }, + { values: firstNames, weight: 0.7 }, + ], + }), + }, + }, + })); + + const data = await db.select().from(schema.valuesFromArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('valuesFromArray unique generator test', async () => { + // valuesFromArrayUniqueTable----------------------------------------------------------------------------------- + await seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }, { seed: 1 }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArray: funcs.valuesFromArray({ values: lastNames.slice(0, 20), isUnique: true }), + valuesFromArrayNotNull: funcs.valuesFromArray({ values: lastNames, isUnique: true }), + valuesFromArrayWeighted: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 20000), weight: 0.3 }, + { values: lastNames.slice(20000), weight: 0.7 }, + ], + isUnique: true, + }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 14920), weight: 0.3 }, + { values: lastNames.slice(14920), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })); + + const data = await db.select().from(schema.valuesFromArrayUniqueTable); + // console.log(valuesFromArrayUniqueTableData); + const predicate = data.length !== 0 && data.every((row) => + row['valuesFromArrayWeightedNotNull'] !== null + && row['valuesFromArrayNotNull'] !== null + ); + expect(predicate).toBe(true); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 20000), weight: 0.3 }, + { values: lastNames.slice(20000), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow( + /^weighted values arrays is too small to generate values with specified probability for unique not null column\..+/, + ); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49998, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ + values: lastNames.slice(20), + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow('there are no enough values to fill unique column.'); + + await expect( + seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }, { seed: 1 }).refine((funcs) => ({ + valuesFromArrayUniqueTable: { + count: 49999, + columns: { + valuesFromArrayNotNull: funcs.valuesFromArray({ + values: lastNames, + isUnique: true, + }), + valuesFromArrayWeightedNotNull: funcs.valuesFromArray({ + values: [ + { values: lastNames.slice(0, 14854), weight: 0.3 }, + { values: lastNames.slice(14854), weight: 0.7 }, + ], + isUnique: true, + }), + }, + }, + })), + ).rejects.toThrow('there are no enough values to fill unique column.'); +}); + +test('intPrimaryKey generator test', async () => { + await seed(db, { intPrimaryKeyTable: schema.intPrimaryKeyTable }).refine((funcs) => ({ + intPrimaryKeyTable: { + count, + columns: { + intPrimaryKey: funcs.intPrimaryKey(), + }, + }, + })); + + const data = await db.select().from(schema.intPrimaryKeyTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('number generator test', async () => { + await seed(db, { numberTable: schema.numberTable }).refine((funcs) => ({ + numberTable: { + count, + columns: { + number: funcs.number(), + }, + }, + })); + + const data = await db.select().from(schema.numberTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('number unique generator test', async () => { + // numberUniqueTable----------------------------------------------------------------------------------- + await seed(db, { numberUniqueTable: schema.numberUniqueTable }).refine((funcs) => ({ + numberUniqueTable: { + count: 20070, + columns: { + numberUnique: funcs.number({ isUnique: true, minValue: -100.23, maxValue: 100.46 }), + }, + }, + })); + + const data = await db.select().from(schema.numberUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && val >= -100.23 && val <= 100.46) + ); + expect(predicate).toBe(true); + + await expect( + seed(db, { numberUniqueTable: schema.numberUniqueTable }).refine((funcs) => ({ + numberUniqueTable: { + count: 20071, + columns: { + numberUnique: funcs.number({ isUnique: true, minValue: -100.23, maxValue: 100.46 }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); +}); + +test('int generator test', async () => { + await seed(db, { intTable: schema.intTable }).refine((funcs) => ({ + intTable: { + count, + columns: { + int: funcs.int(), + }, + }, + })); + + const data = await db.select().from(schema.intTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('int unique generator test', async () => { + // intUniqueTable----------------------------------------------------------------------------------- + await seed(db, { intUniqueTable: schema.intUniqueTable }).refine((funcs) => ({ + intUniqueTable: { + count: 201, + columns: { + intUnique: funcs.int({ isUnique: true, minValue: -100, maxValue: 100 }), + }, + }, + })); + + const data = await db.select().from(schema.intUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { intUniqueTable: schema.intUniqueTable }).refine((funcs) => ({ + intUniqueTable: { + count: 202, + columns: { + intUnique: funcs.int({ isUnique: true, minValue: -100, maxValue: 100 }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); +}); + +test('boolean generator test', async () => { + await seed(db, { booleanTable: schema.booleanTable }).refine((funcs) => ({ + booleanTable: { + count, + columns: { + boolean: funcs.boolean(), + }, + }, + })); + + const data = await db.select().from(schema.booleanTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('date generator test', async () => { + await seed(db, { dateTable: schema.dateTable }).refine((funcs) => ({ + dateTable: { + count, + columns: { + date: funcs.date(), + }, + }, + })); + + const data = await db.select().from(schema.dateTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('time generator test', async () => { + await seed(db, { timeTable: schema.timeTable }).refine((funcs) => ({ + timeTable: { + count, + columns: { + time: funcs.time(), + }, + }, + })); + + const data = await db.select().from(schema.timeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('timestamp generator test', async () => { + await seed(db, { timestampTable: schema.timestampTable }).refine((funcs) => ({ + timestampTable: { + count, + columns: { + timestamp: funcs.timestamp(), + }, + }, + })); + + const data = await db.select().from(schema.timestampTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('json generator test', async () => { + await seed(db, { jsonTable: schema.jsonTable }).refine((funcs) => ({ + jsonTable: { + count, + columns: { + json: funcs.json(), + }, + }, + })); + + const data = await db.select().from(schema.jsonTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('interval generator test', async () => { + await seed(db, { intervalTable: schema.intervalTable }).refine((funcs) => ({ + intervalTable: { + count, + columns: { + interval: funcs.interval(), + }, + }, + })); + + const data = await db.select().from(schema.intervalTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('interval unique generator test', async () => { + // intervalUniqueTable----------------------------------------------------------------------------------- + await seed(db, { intervalUniqueTable: schema.intervalUniqueTable }).refine((funcs) => ({ + intervalUniqueTable: { + count, + columns: { + intervalUnique: funcs.interval({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.intervalUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('string generator test', async () => { + await seed(db, { stringTable: schema.stringTable }).refine((funcs) => ({ + stringTable: { + count, + columns: { + string: funcs.string(), + }, + }, + })); + + const data = await db.select().from(schema.stringTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('string unique generator test', async () => { + await seed(db, { stringUniqueTable: schema.stringUniqueTable }).refine((funcs) => ({ + stringUniqueTable: { + count, + columns: { + stringUnique: funcs.string({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.stringUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('email generator test', async () => { + await seed(db, { emailTable: schema.emailTable }).refine((funcs) => ({ + emailTable: { + count, + columns: { + email: funcs.email(), + }, + }, + })); + + const data = await db.select().from(schema.emailTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('firstName generator test', async () => { + await seed(db, { firstNameTable: schema.firstNameTable }).refine((funcs) => ({ + firstNameTable: { + count, + columns: { + firstName: funcs.firstName(), + }, + }, + })); + + const data = await db.select().from(schema.firstNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('firstName unique generator test', async () => { + // firstNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { firstNameUniqueTable: schema.firstNameUniqueTable }).refine((funcs) => ({ + firstNameUniqueTable: { + count: 30274, + columns: { + firstNameUnique: funcs.firstName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.firstNameUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { firstNameUniqueTable: schema.firstNameUniqueTable }, { count: 30275 }).refine((funcs) => ({ + firstNameUniqueTable: { + count: 30275, + columns: { + firstNameUnique: funcs.firstName({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique first names.'); +}); + +test('lastName generator test', async () => { + await seed(db, { lastNameTable: schema.lastNameTable }).refine((funcs) => ({ + lastNameTable: { + count, + columns: { + lastName: funcs.lastName(), + }, + }, + })); + + const data = await db.select().from(schema.lastNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('lastName unique generator test', async () => { + // lastNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { lastNameUniqueTable: schema.lastNameUniqueTable }).refine((funcs) => ({ + lastNameUniqueTable: { + count: 49998, + columns: { + lastNameUnique: funcs.lastName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.lastNameUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { lastNameUniqueTable: schema.lastNameUniqueTable }).refine((funcs) => ({ + lastNameUniqueTable: { + count: 49999, + columns: { + lastNameUnique: funcs.lastName({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique last names.'); +}); + +test('fullName generator test', async () => { + await seed(db, { fullNameTable: schema.fullNameTable }).refine((funcs) => ({ + fullNameTable: { + count, + columns: { + fullName: funcs.fullName(), + }, + }, + })); + + const data = await db.select().from(schema.fullNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('fullName unique generator test', async () => { + // fullNameUniqueTable----------------------------------------------------------------------------------- + await seed(db, { fullNameUniqueTable: schema.fullNameUniqueTable }).refine((funcs) => ({ + fullNameUniqueTable: { + count, + columns: { + fullNameUnique: funcs.fullName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.fullNameUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('country generator test', async () => { + await seed(db, { countryTable: schema.countryTable }).refine((funcs) => ({ + countryTable: { + count, + columns: { + country: funcs.country(), + }, + }, + })); + + const data = await db.select().from(schema.countryTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('country unique generator test', async () => { + // countryUniqueTable----------------------------------------------------------------------------------- + await seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ + countryUniqueTable: { + count: 160, + columns: { + countryUnique: funcs.country({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.countryUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ + countryUniqueTable: { + count: 168, + columns: { + countryUnique: funcs.country({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique countries.'); +}); + +test('city generator test', async () => { + await seed(db, { cityTable: schema.cityTable }).refine((funcs) => ({ + cityTable: { + count, + columns: { + city: funcs.city(), + }, + }, + })); + + const data = await db.select().from(schema.cityTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('city unique generator test', async () => { + // cityUniqueTable----------------------------------------------------------------------------------- + await reset(db, { cityUniqueTable: schema.cityUniqueTable }); + await seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ + cityUniqueTable: { + count: 38884, + columns: { + cityUnique: funcs.city({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.cityUniqueTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ + cityUniqueTable: { + count: 42985, + columns: { + cityUnique: funcs.city({ isUnique: true }), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique cities.'); +}); + +test('streetAddress generator test', async () => { + await seed(db, { streetAddressTable: schema.streetAddressTable }).refine((funcs) => ({ + streetAddressTable: { + count, + columns: { + streetAddress: funcs.streetAddress(), + }, + }, + })); + + const data = await db.select().from(schema.streetAddressTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('streetAddress unique generator test', async () => { + await seed(db, { streetAddressUniqueTable: schema.streetAddressUniqueTable }).refine((funcs) => ({ + streetAddressUniqueTable: { + count, + columns: { + streetAddressUnique: funcs.streetAddress({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.streetAddressUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('jobTitle generator test', async () => { + await seed(db, { jobTitleTable: schema.jobTitleTable }).refine((funcs) => ({ + jobTitleTable: { + count, + columns: { + jobTitle: funcs.jobTitle(), + }, + }, + })); + + const data = await db.select().from(schema.jobTitleTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('postcode generator test', async () => { + await seed(db, { postcodeTable: schema.postcodeTable }).refine((funcs) => ({ + postcodeTable: { + count, + columns: { + postcode: funcs.postcode(), + }, + }, + })); + + const data = await db.select().from(schema.postcodeTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('postcode unique generator test', async () => { + await seed(db, { postcodeUniqueTable: schema.postcodeUniqueTable }).refine((funcs) => ({ + postcodeUniqueTable: { + count, + columns: { + postcodeUnique: funcs.postcode({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.postcodeUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('state generator test', async () => { + await seed(db, { stateTable: schema.stateTable }).refine((funcs) => ({ + stateTable: { + count, + columns: { + state: funcs.state(), + }, + }, + })); + + const data = await db.select().from(schema.stateTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('companyName generator test', async () => { + await seed(db, { companyNameTable: schema.companyNameTable }).refine((funcs) => ({ + companyNameTable: { + count, + columns: { + companyName: funcs.companyName(), + }, + }, + })); + + const data = await db.select().from(schema.companyNameTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('companyName unique generator test', async () => { + await seed(db, { companyNameUniqueTable: schema.companyNameUniqueTable }).refine((funcs) => ({ + companyNameUniqueTable: { + count, + columns: { + companyNameUnique: funcs.companyName({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.companyNameUniqueTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('loremIpsum generator test', async () => { + await seed(db, { loremIpsumTable: schema.loremIpsumTable }).refine((funcs) => ({ + loremIpsumTable: { + count, + columns: { + loremIpsum: funcs.loremIpsum(), + }, + }, + })); + + const data = await db.select().from(schema.loremIpsumTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('point generator test', async () => { + await seed(db, { pointTable: schema.pointTable }).refine((funcs) => ({ + pointTable: { + count, + columns: { + point: funcs.point(), + }, + }, + })); + + const data = await db.select().from(schema.pointTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('point unique generator test', async () => { + await reset(db, { pointTable: schema.pointTable }); + await seed(db, { pointTable: schema.pointTable }).refine((funcs) => ({ + pointTable: { + count, + columns: { + point: funcs.point({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.pointTable); + // every value in each row does not equal undefined. + let predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + // using Set because PGlite does not support unique point + const pointStrsSet = new Set(data.map((row) => row.point!.map(String).join(','))); + predicate = pointStrsSet.size === data.length; + expect(predicate).toBe(true); +}); + +test('line generator test', async () => { + await seed(db, { lineTable: schema.lineTable }).refine((funcs) => ({ + lineTable: { + count, + columns: { + line: funcs.line(), + }, + }, + })); + + const data = await db.select().from(schema.lineTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('line unique generator test', async () => { + await reset(db, { lineTable: schema.lineTable }); + await seed(db, { lineTable: schema.lineTable }).refine((funcs) => ({ + lineTable: { + count, + columns: { + line: funcs.line({ isUnique: true }), + }, + }, + })); + + const data = await db.select().from(schema.lineTable); + // every value in each row does not equal undefined. + let predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + // using Set because PGlite does not support unique point + const lineStrsSet = new Set(data.map((row) => row.line!.map(String).join(','))); + predicate = lineStrsSet.size === data.length; + expect(predicate).toBe(true); +}); + +test('phoneNumber generator test', async () => { + await seed(db, { phoneNumberTable: schema.phoneNumberTable }).refine((funcs) => ({ + phoneNumberTable: { + count, + columns: { + phoneNumber: funcs.phoneNumber(), + phoneNumberPrefixes: funcs.phoneNumber({ + prefixes: ['+380 99', '+380 67', '+1'], + generatedDigitsNumbers: [7, 7, 10], + }), + phoneNumberTemplate: funcs.phoneNumber({ template: '+380 ## ## ### ##' }), + }, + }, + })); + + const data = await db.select().from(schema.phoneNumberTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('weightedRandom generator test', async () => { + await seed(db, { weightedRandomTable: schema.weightedRandomTable }).refine((funcs) => ({ + weightedRandomTable: { + count, + columns: { + weightedRandom: funcs.weightedRandom([ + { value: funcs.default({ defaultValue: 'default value' }), weight: 0.3 }, + { value: funcs.loremIpsum(), weight: 0.7 }, + ]), + }, + }, + })); + + const data = await db.select().from(schema.weightedRandomTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('weightedRandom with unique gens generator test', async () => { + await seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 10000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.3, value: funcs.email() }, + { weight: 0.7, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })); + + const data = await db.select().from(schema.weightedRandomWithUniqueGensTable); + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + await expect( + seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 40000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.1, value: funcs.email() }, + { weight: 0.9, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })), + ).rejects.toThrow('count exceeds max number of unique first names.'); + + await expect( + seed(db, { weightedRandomWithUniqueGensTable: schema.weightedRandomWithUniqueGensTable }).refine((funcs) => ({ + weightedRandomWithUniqueGensTable: { + count: 10000, + columns: { + weightedRandomWithUniqueGens: funcs.weightedRandom([ + { weight: 0.2, value: funcs.email() }, + { weight: 0.9, value: funcs.firstName({ isUnique: true }) }, + ]), + }, + }, + })), + ).rejects.toThrow("sum of all weights don't equal to 1; 1.1 !== 1"); +}); diff --git a/integration-tests/tests/seeder/pgSchema.ts b/integration-tests/tests/seeder/pgSchema.ts new file mode 100644 index 000000000..ef5c4943a --- /dev/null +++ b/integration-tests/tests/seeder/pgSchema.ts @@ -0,0 +1,357 @@ +import type { AnyPgColumn } from 'drizzle-orm/pg-core'; +import { + bigint, + bigserial, + boolean, + char, + date, + decimal, + doublePrecision, + integer, + interval, + json, + jsonb, + line, + numeric, + pgEnum, + pgSchema, + point, + real, + serial, + smallint, + smallserial, + text, + time, + timestamp, + varchar, +} from 'drizzle-orm/pg-core'; + +export const schema = pgSchema('seeder_lib_pg'); + +export const customers = schema.table('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = schema.table( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to').references((): AnyPgColumn => employees.id), + photoPath: text('photo_path'), + }, +); + +export const orders = schema.table('order', { + id: integer('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = schema.table('supplier', { + id: integer('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = schema.table('product', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = schema.table('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); + +// All data types table ------------------------------- +export const moodEnum = pgEnum('mood_enum', ['sad', 'ok', 'happy']); + +export const allDataTypes = schema.table('all_data_types', { + integer: integer('integer'), + smallint: smallint('smallint'), + biginteger: bigint('bigint', { mode: 'bigint' }), + bigintNumber: bigint('bigint_number', { mode: 'number' }), + serial: serial('serial'), + smallserial: smallserial('smallserial'), + bigserial: bigserial('bigserial', { mode: 'bigint' }), + bigserialNumber: bigserial('bigserial_number', { mode: 'number' }), + boolean: boolean('boolean'), + text: text('text'), + varchar: varchar('varchar', { length: 256 }), + char: char('char', { length: 256 }), + numeric: numeric('numeric'), + decimal: decimal('decimal'), + real: real('real'), + doublePrecision: doublePrecision('double_precision'), + json: json('json'), + jsonb: jsonb('jsonb'), + time: time('time'), + timestampDate: timestamp('timestamp_date', { mode: 'date' }), + timestampString: timestamp('timestamp_string', { mode: 'string' }), + dateString: date('date_string', { mode: 'string' }), + date: date('date', { mode: 'date' }), + interval: interval('interval'), + point: point('point', { mode: 'xy' }), + pointTuple: point('point_tuple', { mode: 'tuple' }), + line: line('line', { mode: 'abc' }), + lineTuple: line('line_tuple', { mode: 'tuple' }), + moodEnum: moodEnum('mood_enum'), +}); + +// All generators tables ------------------------------- +export const enumTable = schema.table('enum_table', { + mood: moodEnum('mood_enum'), +}); + +export const defaultTable = schema.table('default_table', { + defaultString: text('default_string'), +}); + +export const valuesFromArrayTable = schema.table('values_from_array_table', { + valuesFromArrayNotNull: varchar('values_from_array_not_null', { length: 256 }).notNull(), + valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).notNull(), +}); + +export const valuesFromArrayUniqueTable = schema.table('values_from_array_unique_table', { + valuesFromArray: varchar('values_from_array', { length: 256 }).unique(), + valuesFromArrayNotNull: varchar('values_from_array_not_null', { length: 256 }).unique().notNull(), + valuesFromArrayWeighted: varchar('values_from_array_weighted', { length: 256 }).unique(), + valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).unique().notNull(), +}); + +export const intPrimaryKeyTable = schema.table('int_primary_key_table', { + intPrimaryKey: integer('int_primary_key').unique(), +}); + +export const numberTable = schema.table('number_table', { + number: real('number'), +}); + +export const numberUniqueTable = schema.table('number_unique_table', { + numberUnique: real('number_unique').unique(), +}); + +export const intTable = schema.table('int_table', { + int: integer('int'), +}); + +export const intUniqueTable = schema.table('int_unique_table', { + intUnique: integer('int_unique').unique(), +}); + +export const booleanTable = schema.table('boolean_table', { + boolean: boolean('boolean'), +}); + +export const dateTable = schema.table('date_table', { + date: date('date'), +}); + +export const timeTable = schema.table('time_table', { + time: time('time'), +}); + +export const timestampTable = schema.table('timestamp_table', { + timestamp: timestamp('timestamp'), +}); + +export const jsonTable = schema.table('json_table', { + json: json('json'), +}); + +export const intervalTable = schema.table('interval_table', { + interval: interval('interval'), +}); + +export const intervalUniqueTable = schema.table('interval_unique_table', { + intervalUnique: interval('interval_unique').unique(), +}); + +export const stringTable = schema.table('string_table', { + string: text('string'), +}); + +export const stringUniqueTable = schema.table('string_unique_table', { + stringUnique: varchar('string_unique', { length: 256 }).unique(), +}); + +export const emailTable = schema.table('email_table', { + email: varchar('email', { length: 256 }).unique(), +}); + +export const firstNameTable = schema.table('first_name_table', { + firstName: varchar('first_name', { length: 256 }), +}); + +export const firstNameUniqueTable = schema.table('first_name_unique_table', { + firstNameUnique: varchar('first_name_unique', { length: 256 }).unique(), +}); + +export const lastNameTable = schema.table('last_name_table', { + lastName: varchar('last_name', { length: 256 }), +}); + +export const lastNameUniqueTable = schema.table('last_name_unique_table', { + lastNameUnique: varchar('last_name_unique', { length: 256 }).unique(), +}); + +export const fullNameTable = schema.table('full_name__table', { + fullName: varchar('full_name_', { length: 256 }), +}); + +export const fullNameUniqueTable = schema.table('full_name_unique_table', { + fullNameUnique: varchar('full_name_unique', { length: 256 }).unique(), +}); + +export const countryTable = schema.table('country_table', { + country: varchar('country', { length: 256 }), +}); + +export const countryUniqueTable = schema.table('country_unique_table', { + countryUnique: varchar('country_unique', { length: 256 }).unique(), +}); + +export const cityTable = schema.table('city_table', { + city: varchar('city', { length: 256 }), +}); + +export const cityUniqueTable = schema.table('city_unique_table', { + cityUnique: varchar('city_unique', { length: 256 }).unique(), +}); + +export const streetAddressTable = schema.table('street_address_table', { + streetAddress: varchar('street_address', { length: 256 }), +}); + +export const streetAddressUniqueTable = schema.table('street_address_unique_table', { + streetAddressUnique: varchar('street_address_unique', { length: 256 }).unique(), +}); + +export const jobTitleTable = schema.table('job_title_table', { + jobTitle: text('job_title'), +}); + +export const postcodeTable = schema.table('postcode_table', { + postcode: varchar('postcode', { length: 256 }), +}); + +export const postcodeUniqueTable = schema.table('postcode_unique_table', { + postcodeUnique: varchar('postcode_unique', { length: 256 }).unique(), +}); + +export const stateTable = schema.table('state_table', { + state: text('state'), +}); + +export const companyNameTable = schema.table('company_name_table', { + companyName: text('company_name'), +}); + +export const companyNameUniqueTable = schema.table('company_name_unique_table', { + companyNameUnique: varchar('company_name_unique', { length: 256 }).unique(), +}); + +export const loremIpsumTable = schema.table('lorem_ipsum_table', { + loremIpsum: text('lorem_ipsum'), +}); + +export const pointTable = schema.table('point_table', { + point: point('point'), +}); + +export const lineTable = schema.table('line_table', { + line: line('line'), +}); + +// export const pointUniqueTable = schema.table("point_unique_table", { +// pointUnique: point("point_unique").unique(), +// }); + +// export const lineUniqueTable = schema.table("line_unique_table", { +// lineUnique: line("line_unique").unique(), +// }); + +export const phoneNumberTable = schema.table('phone_number_table', { + phoneNumber: varchar('phoneNumber', { length: 256 }).unique(), + phoneNumberTemplate: varchar('phone_number_template', { length: 256 }).unique(), + phoneNumberPrefixes: varchar('phone_number_prefixes', { length: 256 }).unique(), +}); + +export const weightedRandomTable = schema.table('weighted_random_table', { + weightedRandom: varchar('weighted_random', { length: 256 }), +}); + +export const weightedRandomWithUniqueGensTable = schema.table('weighted_random_with_unique_gens_table', { + weightedRandomWithUniqueGens: varchar('weighted_random_with_unique_gens', { length: 256 }).unique(), +}); + +export const identityColumnsTable = schema.table('identity_columns_table', { + id: integer('id').generatedAlwaysAsIdentity(), + id1: integer('id1'), + name: text('name'), +}); diff --git a/integration-tests/tests/seeder/sqlite.test.ts b/integration-tests/tests/seeder/sqlite.test.ts new file mode 100644 index 000000000..f9d124401 --- /dev/null +++ b/integration-tests/tests/seeder/sqlite.test.ts @@ -0,0 +1,322 @@ +import BetterSqlite3 from 'better-sqlite3'; +import { sql } from 'drizzle-orm'; +import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import { reset, seed } from 'drizzle-seed'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import * as schema from './sqliteSchema.ts'; + +let client: BetterSqlite3.Database; +let db: BetterSQLite3Database; + +beforeAll(async () => { + client = new BetterSqlite3(':memory:'); + + db = drizzle(client); + + db.run( + sql.raw(` + CREATE TABLE \`customer\` ( + \`id\` text PRIMARY KEY NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text, + \`region\` text, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + \`fax\` text +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`order_detail\` ( + \`unit_price\` numeric NOT NULL, + \`quantity\` integer NOT NULL, + \`discount\` numeric NOT NULL, + \`order_id\` integer NOT NULL, + \`product_id\` integer NOT NULL, + FOREIGN KEY (\`order_id\`) REFERENCES \`order\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`product_id\`) REFERENCES \`product\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`employee\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`last_name\` text NOT NULL, + \`first_name\` text, + \`title\` text NOT NULL, + \`title_of_courtesy\` text NOT NULL, + \`birth_date\` integer NOT NULL, + \`hire_date\` integer NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`home_phone\` text NOT NULL, + \`extension\` integer NOT NULL, + \`notes\` text NOT NULL, + \`reports_to\` integer, + \`photo_path\` text, + FOREIGN KEY (\`reports_to\`) REFERENCES \`employee\`(\`id\`) ON UPDATE no action ON DELETE no action +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`order\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`order_date\` integer NOT NULL, + \`required_date\` integer NOT NULL, + \`shipped_date\` integer, + \`ship_via\` integer NOT NULL, + \`freight\` numeric NOT NULL, + \`ship_name\` text NOT NULL, + \`ship_city\` text NOT NULL, + \`ship_region\` text, + \`ship_postal_code\` text, + \`ship_country\` text NOT NULL, + \`customer_id\` text NOT NULL, + \`employee_id\` integer NOT NULL, + FOREIGN KEY (\`customer_id\`) REFERENCES \`customer\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`employee_id\`) REFERENCES \`employee\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`product\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`name\` text NOT NULL, + \`quantity_per_unit\` text NOT NULL, + \`unit_price\` numeric NOT NULL, + \`units_in_stock\` integer NOT NULL, + \`units_on_order\` integer NOT NULL, + \`reorder_level\` integer NOT NULL, + \`discontinued\` integer NOT NULL, + \`supplier_id\` integer NOT NULL, + FOREIGN KEY (\`supplier_id\`) REFERENCES \`supplier\`(\`id\`) ON UPDATE no action ON DELETE cascade +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`supplier\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`region\` text, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`phone\` text NOT NULL +); + `), + ); + + // All data types test ------------------------------- + db.run( + sql.raw(` + CREATE TABLE \`all_data_types\` ( + \`integer_number\` integer, + \`integer_boolean\` integer, + \`integer_timestamp\` integer, + \`integer_timestampms\` integer, + \`real\` real, + \`text\` text, + \`text_json\` text, + \`blob_bigint\` blob, + \`blob_buffer\` blob, + \`blob_json\` blob, + \`numeric\` numeric +); + `), + ); +}); + +afterAll(async () => { + client.close(); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +test('basic seed test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); +}); + +test('seed with options.count:11 test', async () => { + await seed(db, schema, { count: 11 }); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(11); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) customers count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(11); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test('redefine(refine) all tables count', async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 12, + }, + details: { + count: 13, + }, + employees: { + count: 14, + }, + orders: { + count: 15, + }, + products: { + count: 16, + }, + suppliers: { + count: 17, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(12); + expect(details.length).toBe(13); + expect(employees.length).toBe(14); + expect(orders.length).toBe(15); + expect(products.length).toBe(16); + expect(suppliers.length).toBe(17); +}); + +test("redefine(refine) orders count using 'with' in customers", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +test("sequential using of 'with'", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); +}); + +// All data types test ------------------------------- +test('basic seed test for all sqlite data types', async () => { + // migrate(db, { migrationsFolder: path.join(__dirname, "sqliteMigrations") }); + + await seed(db, { allDataTypes: schema.allDataTypes }, { count: 10000 }); + + const allDataTypes = await db.select().from(schema.allDataTypes); + // every value in each 10 rows does not equal undefined. + const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); diff --git a/integration-tests/tests/seeder/sqliteSchema.ts b/integration-tests/tests/seeder/sqliteSchema.ts new file mode 100644 index 000000000..338833659 --- /dev/null +++ b/integration-tests/tests/seeder/sqliteSchema.ts @@ -0,0 +1,122 @@ +import { blob, foreignKey, integer, numeric, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const customers = sqliteTable('customer', { + id: text('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = sqliteTable( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: integer('birth_date', { mode: 'timestamp' }).notNull(), + hireDate: integer('hire_date', { mode: 'timestamp' }).notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to'), + photoPath: text('photo_path'), + }, + (table) => ({ + reportsToFk: foreignKey(() => ({ + columns: [table.reportsTo], + foreignColumns: [table.id], + })), + }), +); + +export const orders = sqliteTable('order', { + id: integer('id').primaryKey(), + orderDate: integer('order_date', { mode: 'timestamp' }).notNull(), + requiredDate: integer('required_date', { mode: 'timestamp' }).notNull(), + shippedDate: integer('shipped_date', { mode: 'timestamp' }), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id') + .notNull() + .references(() => customers.id, { onDelete: 'cascade' }), + + employeeId: integer('employee_id') + .notNull() + .references(() => employees.id, { onDelete: 'cascade' }), +}); + +export const suppliers = sqliteTable('supplier', { + id: integer('id').primaryKey({ autoIncrement: true }), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = sqliteTable('product', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id') + .notNull() + .references(() => suppliers.id, { onDelete: 'cascade' }), +}); + +export const details = sqliteTable('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id') + .notNull() + .references(() => orders.id, { onDelete: 'cascade' }), + + productId: integer('product_id') + .notNull() + .references(() => products.id, { onDelete: 'cascade' }), +}); + +// All data types table ------------------------------- +export const allDataTypes = sqliteTable('all_data_types', { + integerNumber: integer('integer_number', { mode: 'number' }), + integerBoolean: integer('integer_boolean', { mode: 'boolean' }), + integerTimestamp: integer('integer_timestamp', { mode: 'timestamp' }), + integerTimestampms: integer('integer_timestampms', { mode: 'timestamp_ms' }), + real: real('real'), + text: text('text', { mode: 'text' }), + textJson: text('text_json', { mode: 'json' }), + blobBigint: blob('blob_bigint', { mode: 'bigint' }), + blobBuffer: blob('blob_buffer', { mode: 'buffer' }), + blobJson: blob('blob_json', { mode: 'json' }), + numeric: numeric('numeric'), +}); diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 84ea9b1c8..87c7e7f3c 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -5,6 +5,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { include: [ + 'tests/seeder/**/*.test.ts', 'tests/extensions/postgis/**/*', 'tests/relational/**/*.test.ts', 'tests/pg/**/*.test.ts', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 759aad057..f13c32c4b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,22 +13,22 @@ importers: version: 0.15.3 '@trivago/prettier-plugin-sort-imports': specifier: ^4.2.0 - version: 4.2.0(prettier@3.0.3) + version: 4.3.0(prettier@3.3.3) '@typescript-eslint/eslint-plugin': specifier: ^6.7.3 - version: 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3) + version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) '@typescript-eslint/experimental-utils': specifier: ^5.62.0 - version: 5.62.0(eslint@8.50.0)(typescript@5.6.3) + version: 5.62.0(eslint@8.57.1)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^6.7.3 - version: 6.7.3(eslint@8.50.0)(typescript@5.6.3) + version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) bun-types: specifier: ^1.0.3 - version: 1.0.3 + version: 1.1.34 concurrently: specifier: ^8.2.1 - version: 8.2.1 + version: 8.2.2 dprint: specifier: ^0.46.2 version: 0.46.3 @@ -40,43 +40,43 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.687.0)(@cloudflare/workers-types@4.20241106.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.5)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.10)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.1.34)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.3.3)(pg@8.13.1)(postgres@3.4.5)(sql.js@1.12.0)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 - version: 8.50.0 + version: 8.57.1 eslint-plugin-drizzle-internal: specifier: link:eslint/eslint-plugin-drizzle-internal version: link:eslint/eslint-plugin-drizzle-internal eslint-plugin-import: specifier: ^2.28.1 - version: 2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0) + version: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1) eslint-plugin-no-instanceof: specifier: ^1.0.1 version: 1.0.1 eslint-plugin-unicorn: specifier: ^48.0.1 - version: 48.0.1(eslint@8.50.0) + version: 48.0.1(eslint@8.57.1) eslint-plugin-unused-imports: specifier: ^3.0.0 - version: 3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0) + version: 3.2.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1) glob: specifier: ^10.3.10 - version: 10.3.10 + version: 10.4.5 prettier: specifier: ^3.0.3 - version: 3.0.3 + version: 3.3.3 recast: specifier: ^0.23.9 version: 0.23.9 resolve-tspaths: specifier: ^0.8.16 - version: 0.8.16(typescript@5.6.3) + version: 0.8.22(typescript@5.6.3) tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3) + version: 7.3.0(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3) tsx: specifier: ^4.10.5 - version: 4.10.5 + version: 4.19.2 turbo: specifier: ^2.2.3 version: 2.2.3 @@ -91,50 +91,50 @@ importers: version: 0.10.2 '@esbuild-kit/esm-loader': specifier: ^2.5.5 - version: 2.5.5 + version: 2.6.5 esbuild: specifier: ^0.19.7 version: 0.19.12 esbuild-register: specifier: ^3.5.0 - version: 3.5.0(esbuild@0.19.12) + version: 3.6.0(esbuild@0.19.12) devDependencies: '@arethetypeswrong/cli': specifier: ^0.15.3 version: 0.15.3 '@aws-sdk/client-rds-data': specifier: ^3.556.0 - version: 3.583.0 + version: 3.687.0 '@cloudflare/workers-types': specifier: ^4.20230518.0 - version: 4.20240524.0 + version: 4.20241106.0 '@electric-sql/pglite': specifier: ^0.2.12 version: 0.2.12 '@hono/node-server': specifier: ^1.9.0 - version: 1.12.0 + version: 1.13.5(hono@4.6.9) '@hono/zod-validator': specifier: ^0.2.1 - version: 0.2.2(hono@4.5.0)(zod@3.23.7) + version: 0.2.2(hono@4.6.9)(zod@3.23.8) '@libsql/client': specifier: ^0.10.0 version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': specifier: ^0.9.1 - version: 0.9.3 + version: 0.9.5 '@originjs/vite-plugin-commonjs': specifier: ^1.0.3 version: 1.0.3 '@planetscale/database': specifier: ^1.16.0 - version: 1.18.0 + version: 1.19.0 '@types/better-sqlite3': specifier: ^7.6.4 - version: 7.6.10 + version: 7.6.11 '@types/dockerode': specifier: ^3.3.28 - version: 3.3.29 + version: 3.3.31 '@types/glob': specifier: ^8.1.0 version: 8.1.0 @@ -149,10 +149,10 @@ importers: version: 5.1.2 '@types/node': specifier: ^18.11.15 - version: 18.19.33 + version: 18.19.64 '@types/pg': specifier: ^8.10.7 - version: 8.11.6 + version: 8.11.10 '@types/pluralize': specifier: ^0.0.33 version: 0.0.33 @@ -164,19 +164,19 @@ importers: version: 9.0.8 '@types/ws': specifier: ^8.5.10 - version: 8.5.11 + version: 8.5.13 '@typescript-eslint/eslint-plugin': specifier: ^7.2.0 - version: 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3) + version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^7.2.0 - version: 7.16.1(eslint@8.57.0)(typescript@5.6.3) + version: 7.18.0(eslint@8.57.1)(typescript@5.6.3) '@vercel/postgres': specifier: ^0.8.0 version: 0.8.0 ava: specifier: ^5.1.0 - version: 5.3.0(@ava/typescript@5.0.0) + version: 5.3.1 better-sqlite3: specifier: ^9.4.3 version: 9.6.0 @@ -209,16 +209,16 @@ importers: version: 3.0.0 esbuild-node-externals: specifier: ^1.9.0 - version: 1.14.0(esbuild@0.19.12) + version: 1.15.0(esbuild@0.19.12) eslint: specifier: ^8.57.0 - version: 8.57.0 + version: 8.57.1 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@8.57.0) + version: 9.1.0(eslint@8.57.1) eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8) + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8) get-port: specifier: ^6.1.2 version: 6.1.2 @@ -230,7 +230,7 @@ importers: version: 0.0.5 hono: specifier: ^4.1.5 - version: 4.5.0 + version: 4.6.9 json-diff: specifier: 1.0.6 version: 1.0.6 @@ -251,25 +251,25 @@ importers: version: 17.1.0 pg: specifier: ^8.11.5 - version: 8.11.5 + version: 8.13.1 pluralize: specifier: ^8.0.0 version: 8.0.0 postgres: specifier: ^3.4.4 - version: 3.4.4 + version: 3.4.5 prettier: specifier: ^2.8.1 version: 2.8.8 semver: specifier: ^7.5.4 - version: 7.6.2 + version: 7.6.3 superjson: specifier: ^2.2.1 version: 2.2.1 tsup: specifier: ^8.0.2 - version: 8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.4.2) + version: 8.3.5(postcss@8.4.47)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.6.0) tsx: specifier: ^3.12.1 version: 3.14.0 @@ -281,31 +281,31 @@ importers: version: 9.0.1 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) vitest: specifier: ^1.4.0 - version: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) wrangler: specifier: ^3.22.1 - version: 3.65.0(@cloudflare/workers-types@4.20240524.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3) + version: 3.85.0(@cloudflare/workers-types@4.20241106.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3) ws: specifier: ^8.16.0 - version: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) zod: specifier: ^3.20.2 - version: 3.23.7 + version: 3.23.8 zx: specifier: ^7.2.2 - version: 7.2.2 + version: 7.2.3 drizzle-orm: devDependencies: '@aws-sdk/client-rds-data': specifier: ^3.549.0 - version: 3.583.0 + version: 3.687.0 '@cloudflare/workers-types': specifier: ^4.20230904.0 - version: 4.20240512.0 + version: 4.20241106.0 '@electric-sql/pglite': specifier: ^0.2.12 version: 0.2.12 @@ -320,19 +320,19 @@ importers: version: 2.14.4 '@neondatabase/serverless': specifier: ^0.9.0 - version: 0.9.0 + version: 0.9.5 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + version: 2.0.22(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 - version: 1.8.0 + version: 1.9.0 '@originjs/vite-plugin-commonjs': specifier: ^1.0.3 version: 1.0.3 '@planetscale/database': specifier: ^1.16.0 - version: 1.18.0 + version: 1.19.0 '@prisma/client': specifier: 5.14.0 version: 5.14.0(prisma@5.14.0) @@ -341,16 +341,16 @@ importers: version: 0.1.1 '@types/better-sqlite3': specifier: ^7.6.4 - version: 7.6.10 + version: 7.6.11 '@types/node': specifier: ^20.2.5 - version: 20.12.12 + version: 20.17.6 '@types/pg': specifier: ^8.10.1 - version: 8.11.6 + version: 8.11.10 '@types/react': specifier: ^18.2.45 - version: 18.3.1 + version: 18.3.12 '@types/sql.js': specifier: ^1.4.4 version: 1.4.9 @@ -359,7 +359,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.4(typescript@5.6.3) + version: 0.29.5(typescript@5.6.3) better-sqlite3: specifier: ^8.4.0 version: 8.7.0 @@ -371,10 +371,10 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^14.0.0 - version: 14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + version: 14.0.6(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) knex: specifier: ^2.4.2 - version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) + version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7) kysely: specifier: ^0.25.0 version: 0.25.0 @@ -383,10 +383,10 @@ importers: version: 3.3.3 pg: specifier: ^8.11.0 - version: 8.11.5 + version: 8.13.1 postgres: specifier: ^3.3.5 - version: 3.4.4 + version: 3.4.5 prisma: specifier: 5.14.0 version: 5.14.0 @@ -395,43 +395,125 @@ importers: version: 18.3.1 sql.js: specifier: ^1.8.0 - version: 1.10.3 + version: 1.12.0 sqlite3: specifier: ^5.1.2 version: 5.1.7 tslib: specifier: ^2.5.2 - version: 2.6.2 + version: 2.8.1 tsx: specifier: ^3.12.7 version: 3.14.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + version: 1.6.0(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) zod: specifier: ^3.20.2 - version: 3.23.7 + version: 3.23.8 zx: specifier: ^7.2.2 - version: 7.2.2 + version: 7.2.3 + + drizzle-seed: + dependencies: + pure-rand: + specifier: ^6.1.0 + version: 6.1.0 + devDependencies: + '@arethetypeswrong/cli': + specifier: ^0.16.1 + version: 0.16.4 + '@electric-sql/pglite': + specifier: ^0.2.12 + version: 0.2.12 + '@rollup/plugin-terser': + specifier: ^0.4.4 + version: 0.4.4(rollup@4.24.4) + '@rollup/plugin-typescript': + specifier: ^11.1.6 + version: 11.1.6(rollup@4.24.4)(tslib@2.8.1)(typescript@5.6.3) + '@types/better-sqlite3': + specifier: ^7.6.11 + version: 7.6.11 + '@types/dockerode': + specifier: ^3.3.31 + version: 3.3.31 + '@types/node': + specifier: ^22.5.4 + version: 22.9.0 + '@types/pg': + specifier: ^8.11.6 + version: 8.11.10 + '@types/uuid': + specifier: ^10.0.0 + version: 10.0.0 + better-sqlite3: + specifier: ^11.1.2 + version: 11.5.0 + cpy: + specifier: ^11.1.0 + version: 11.1.0 + dockerode: + specifier: ^4.0.2 + version: 4.0.2 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + drizzle-kit: + specifier: workspace:./drizzle-kit/dist + version: link:drizzle-kit/dist + drizzle-orm: + specifier: workspace:./drizzle-orm/dist + version: link:drizzle-orm/dist + get-port: + specifier: ^7.1.0 + version: 7.1.0 + mysql2: + specifier: ^3.3.3 + version: 3.3.3 + pg: + specifier: ^8.12.0 + version: 8.13.1 + resolve-tspaths: + specifier: ^0.8.19 + version: 0.8.22(typescript@5.6.3) + rollup: + specifier: ^4.21.2 + version: 4.24.4 + tslib: + specifier: ^2.7.0 + version: 2.8.1 + tsx: + specifier: ^4.19.0 + version: 4.19.2 + uuid: + specifier: ^10.0.0 + version: 10.0.0 + vitest: + specifier: ^2.0.5 + version: 2.1.4(@types/node@22.9.0)(terser@5.36.0) + zx: + specifier: ^8.1.5 + version: 8.2.0 drizzle-typebox: devDependencies: '@rollup/plugin-terser': specifier: ^0.4.1 - version: 0.4.1(rollup@3.27.2) + version: 0.4.4(rollup@3.29.5) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.6.3) + version: 11.1.6(rollup@3.29.5)(tslib@2.8.1)(typescript@5.6.3) '@sinclair/typebox': specifier: ^0.29.6 version: 0.29.6 '@types/node': specifier: ^18.15.10 - version: 18.15.10 + version: 18.19.64 cpy: specifier: ^10.1.0 version: 10.1.0 @@ -440,31 +522,31 @@ importers: version: link:../drizzle-orm/dist rimraf: specifier: ^5.0.0 - version: 5.0.0 + version: 5.0.10 rollup: specifier: ^3.20.7 - version: 3.27.2 + version: 3.29.5 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) zx: specifier: ^7.2.2 - version: 7.2.2 + version: 7.2.3 drizzle-valibot: devDependencies: '@rollup/plugin-terser': specifier: ^0.4.1 - version: 0.4.1(rollup@3.27.2) + version: 0.4.4(rollup@3.29.5) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.6.3) + version: 11.1.6(rollup@3.29.5)(tslib@2.8.1)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 - version: 18.15.10 + version: 18.19.64 cpy: specifier: ^10.1.0 version: 10.1.0 @@ -473,34 +555,34 @@ importers: version: link:../drizzle-orm/dist rimraf: specifier: ^5.0.0 - version: 5.0.0 + version: 5.0.10 rollup: specifier: ^3.20.7 - version: 3.27.2 + version: 3.29.5 valibot: specifier: ^0.30.0 version: 0.30.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) zx: specifier: ^7.2.2 - version: 7.2.2 + version: 7.2.3 drizzle-zod: devDependencies: '@rollup/plugin-terser': specifier: ^0.4.1 - version: 0.4.1(rollup@3.20.7) + version: 0.4.4(rollup@3.29.5) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.6.3) + version: 11.1.6(rollup@3.29.5)(tslib@2.8.1)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 - version: 18.15.10 + version: 18.19.64 cpy: specifier: ^10.1.0 version: 10.1.0 @@ -509,58 +591,58 @@ importers: version: link:../drizzle-orm/dist rimraf: specifier: ^5.0.0 - version: 5.0.0 + version: 5.0.10 rollup: specifier: ^3.20.7 - version: 3.20.7 + version: 3.29.5 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) zod: specifier: ^3.20.2 - version: 3.21.4 + version: 3.23.8 zx: specifier: ^7.2.2 - version: 7.2.2 + version: 7.2.3 eslint-plugin-drizzle: devDependencies: '@types/node': specifier: ^20.10.1 - version: 20.10.1 + version: 20.17.6 '@typescript-eslint/parser': specifier: ^6.10.0 - version: 6.10.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) '@typescript-eslint/rule-tester': specifier: ^6.10.0 - version: 6.10.0(@eslint/eslintrc@3.1.0)(eslint@8.53.0)(typescript@5.2.2) + version: 6.21.0(@eslint/eslintrc@2.1.4)(eslint@8.57.1)(typescript@5.6.3) '@typescript-eslint/utils': specifier: ^6.10.0 - version: 6.10.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) cpy-cli: specifier: ^5.0.0 version: 5.0.0 eslint: specifier: ^8.53.0 - version: 8.53.0 + version: 8.57.1 typescript: specifier: ^5.2.2 - version: 5.2.2 + version: 5.6.3 vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@20.10.1)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + version: 1.6.0(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) integration-tests: dependencies: '@aws-sdk/client-rds-data': specifier: ^3.549.0 - version: 3.583.0 + version: 3.687.0 '@aws-sdk/credential-providers': specifier: ^3.549.0 - version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0) + version: 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)) '@electric-sql/pglite': specifier: 0.2.12 version: 0.2.12 @@ -575,7 +657,7 @@ importers: version: 2.14.4 '@planetscale/database': specifier: ^1.16.0 - version: 1.18.0 + version: 1.19.0 '@prisma/client': specifier: 5.14.0 version: 5.14.0(prisma@5.14.0) @@ -590,7 +672,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.4(typescript@5.6.3) + version: 0.29.5(typescript@5.6.3) async-retry: specifier: ^1.3.3 version: 1.3.3 @@ -605,7 +687,10 @@ importers: version: 16.4.5 drizzle-prisma-generator: specifier: ^0.1.2 - version: 0.1.4 + version: 0.1.7 + drizzle-seed: + specifier: workspace:../drizzle-seed/dist + version: link:../drizzle-seed/dist drizzle-typebox: specifier: workspace:../drizzle-typebox/dist version: link:../drizzle-typebox/dist @@ -617,7 +702,7 @@ importers: version: link:../drizzle-zod/dist express: specifier: ^4.18.2 - version: 4.19.2 + version: 4.21.1 get-port: specifier: ^7.0.0 version: 7.1.0 @@ -626,10 +711,10 @@ importers: version: 3.3.3 pg: specifier: ^8.11.0 - version: 8.11.5 + version: 8.13.1 postgres: specifier: ^3.3.5 - version: 3.4.4 + version: 3.4.5 prisma: specifier: 5.14.0 version: 5.14.0 @@ -638,13 +723,13 @@ importers: version: 0.5.21 sql.js: specifier: ^1.8.0 - version: 1.10.3 + version: 1.12.0 sqlite3: specifier: ^5.1.4 version: 5.1.7 sst: specifier: ^3.0.4 - version: 3.0.14 + version: 3.3.5(hono@4.6.9)(valibot@0.30.0) uuid: specifier: ^9.0.0 version: 9.0.1 @@ -653,20 +738,20 @@ importers: version: 0.5.6 vitest: specifier: ^2.1.2 - version: 2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + version: 2.1.4(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) ws: specifier: ^8.16.0 version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) zod: specifier: ^3.20.2 - version: 3.23.7 + version: 3.23.8 devDependencies: '@cloudflare/workers-types': specifier: ^4.20241004.0 - version: 4.20241004.0 + version: 4.20241106.0 '@neondatabase/serverless': - specifier: 0.9.0 - version: 0.9.0 + specifier: ^0.9.0 + version: 0.9.5 '@originjs/vite-plugin-commonjs': specifier: ^1.0.3 version: 1.0.3 @@ -675,25 +760,25 @@ importers: version: 2.2.2 '@types/async-retry': specifier: ^1.4.8 - version: 1.4.8 + version: 1.4.9 '@types/axios': specifier: ^0.14.0 - version: 0.14.0 + version: 0.14.4 '@types/better-sqlite3': specifier: ^7.6.4 - version: 7.6.10 + version: 7.6.11 '@types/dockerode': specifier: ^3.3.18 - version: 3.3.29 + version: 3.3.31 '@types/express': specifier: ^4.17.16 version: 4.17.21 '@types/node': specifier: ^20.2.5 - version: 20.12.12 + version: 20.17.6 '@types/pg': specifier: ^8.10.1 - version: 8.11.6 + version: 8.11.10 '@types/sql.js': specifier: ^1.4.4 version: 1.4.9 @@ -702,41 +787,37 @@ importers: version: 9.0.8 '@types/ws': specifier: ^8.5.10 - version: 8.5.11 + version: 8.5.13 '@vitest/ui': specifier: ^1.6.0 - version: 1.6.0(vitest@2.1.2) + version: 1.6.0(vitest@2.1.4) ava: specifier: ^5.3.0 - version: 5.3.0(@ava/typescript@5.0.0) + version: 5.3.1 axios: specifier: ^1.4.0 - version: 1.6.8 + version: 1.7.7 cross-env: specifier: ^7.0.3 version: 7.0.3 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.12.12)(typescript@5.6.3) + version: 10.9.2(@types/node@20.17.6)(typescript@5.6.3) tsx: specifier: ^4.14.0 - version: 4.16.2 + version: 4.19.2 vite: specifier: ^5.2.13 - version: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + version: 5.4.10(@types/node@20.17.6)(terser@5.36.0) vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)) zx: specifier: ^7.2.2 - version: 7.2.2 + version: 7.2.3 packages: - '@aashutoshrathi/word-wrap@1.2.6': - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -749,321 +830,141 @@ packages: engines: {node: '>=18'} hasBin: true + '@arethetypeswrong/cli@0.16.4': + resolution: {integrity: sha512-qMmdVlJon5FtA+ahn0c1oAVNxiq4xW5lqFiTZ21XHIeVwAVIQ+uRz4UEivqRMsjVV1grzRgJSKqaOrq1MvlVyQ==} + engines: {node: '>=18'} + hasBin: true + '@arethetypeswrong/core@0.15.1': resolution: {integrity: sha512-FYp6GBAgsNz81BkfItRz8RLZO03w5+BaeiPma1uCfmxTnxbtuMrI/dbzGiOk8VghO108uFI0oJo0OkewdSHw7g==} engines: {node: '>=18'} - '@ava/typescript@5.0.0': - resolution: {integrity: sha512-2twsQz2fUd95QK1MtKuEnjkiN47SKHZfi/vWj040EN6Eo2ZW3SNcAwncJqXXoMTYZTWtBRXYp3Fg8z+JkFI9aQ==} - engines: {node: ^18.18 || ^20.8 || ^21 || ^22} - - '@aws-crypto/crc32@3.0.0': - resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==} - - '@aws-crypto/ie11-detection@3.0.0': - resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} - - '@aws-crypto/sha256-browser@3.0.0': - resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} - - '@aws-crypto/sha256-js@3.0.0': - resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} - - '@aws-crypto/supports-web-crypto@3.0.0': - resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} - - '@aws-crypto/util@3.0.0': - resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} - - '@aws-sdk/client-cognito-identity@3.569.0': - resolution: {integrity: sha512-cD1HcdJNpUZgrATWCAQs2amQKI69pG+jF4b5ySq9KJkVi6gv2PWsD6QGDG8H12lMWaIKYlOpKbpnYTpcuvqUcg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-lambda@3.478.0': - resolution: {integrity: sha512-7+PEE1aV3qVeuswL6cUBfHeljxC/WaXFj+214/W3q71uRdLbX5Z7ZOD15sJbjSu+4VZN9ugMaxEcp+oLiqWl+A==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/client-rds-data@3.583.0': - resolution: {integrity: sha512-xBnrVGNmMsTafzlaeZiFUahr3TP4zF2yRnsWzibylbXXIjaGdcLoiskNizo62syCh/8LbgpY6EN34EeYWsfMiw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sso-oidc@3.569.0': - resolution: {integrity: sha512-u5DEjNEvRvlKKh1QLCDuQ8GIrx+OFvJFLfhorsp4oCxDylvORs+KfyKKnJAw4wYEEHyxyz9GzHD7p6a8+HLVHw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sso-oidc@3.583.0': - resolution: {integrity: sha512-LO3wmrFXPi2kNE46lD1XATfRrvdNxXd4DlTFouoWmr7lvqoUkcbmtkV2r/XChZA2z0HiDauphC1e8b8laJVeSg==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sso@3.478.0': - resolution: {integrity: sha512-Jxy9cE1JMkPR0PklCpq3cORHnZq/Z4klhSTNGgZNeBWovMa+plor52kyh8iUNHKl3XEJvTbHM7V+dvrr/x0P1g==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/client-sso@3.568.0': - resolution: {integrity: sha512-LSD7k0ZBQNWouTN5dYpUkeestoQ+r5u6cp6o+FATKeiFQET85RNA3xJ4WPnOI5rBC1PETKhQXvF44863P3hCaQ==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sso@3.583.0': - resolution: {integrity: sha512-FNJ2MmiBtZZwgkj4+GLVrzqwmD6D8FBptrFZk7PnGkSf7v1Q8txYNI6gY938RRhYJ4lBW4cNbhPvWoDxAl90Hw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sts@3.478.0': - resolution: {integrity: sha512-D+QID0dYzmn9dcxgKP3/nMndUqiQbDLsqI0Zf2pG4MW5gPhVNKlDGIV3Ztz8SkMjzGJExNOLW2L569o8jshJVw==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/client-sts@3.569.0': - resolution: {integrity: sha512-3AyipQ2zHszkcTr8n1Sp7CiMUi28aMf1vOhEo0KKi0DWGo1Z1qJEpWeRP363KG0n9/8U3p1IkXGz5FRbpXZxIw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/client-sts@3.583.0': - resolution: {integrity: sha512-xDMxiemPDWr9dY2Q4AyixkRnk/hvS6fs6OWxuVCz1WO47YhaAfOsEGAgQMgDLLaOfj/oLU5D14uTNBEPGh4rBA==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/core@3.477.0': - resolution: {integrity: sha512-o0434EH+d1BxHZvgG7z8vph2SYefciQ5RnJw2MgvETGnthgqsnI4nnNJLSw0FVeqCeS18n6vRtzqlGYR2YPCNg==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/core@3.567.0': - resolution: {integrity: sha512-zUDEQhC7blOx6sxhHdT75x98+SXQVdUIMu8z8AjqMWiYK2v4WkOS8i6dOS4E5OjL5J1Ac+ruy8op/Bk4AFqSIw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/core@3.582.0': - resolution: {integrity: sha512-ofmD96IQc9g1dbyqlCyxu5fCG7kIl9p1NoN5+vGBUyLdbmPCV3Pdg99nRHYEJuv2MgGx5AUFGDPMHcqbJpnZIw==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-cognito-identity@3.569.0': - resolution: {integrity: sha512-CHS0Zyuazh5cYLaJr2/I9up0xAu8Y+um/h0o4xNf00cKGT0Sdhoby5vyelHjVTeZt+OeOMTBt6IdqGwVbVG9gQ==} - engines: {node: '>=16.0.0'} + '@arethetypeswrong/core@0.16.4': + resolution: {integrity: sha512-RI3HXgSuKTfcBf1hSEg1P9/cOvmI0flsMm6/QL3L3wju4AlHDqd55JFPfXs4pzgEAgy5L9pul4/HPPz99x2GvA==} + engines: {node: '>=18'} - '@aws-sdk/credential-provider-env@3.468.0': - resolution: {integrity: sha512-k/1WHd3KZn0EQYjadooj53FC0z24/e4dUZhbSKTULgmxyO62pwh9v3Brvw4WRa/8o2wTffU/jo54tf4vGuP/ZA==} - engines: {node: '>=14.0.0'} + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} - '@aws-sdk/credential-provider-env@3.568.0': - resolution: {integrity: sha512-MVTQoZwPnP1Ev5A7LG+KzeU6sCB8BcGkZeDT1z1V5Wt7GPq0MgFQTSSjhImnB9jqRSZkl1079Bt3PbO6lfIS8g==} + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-env@3.577.0': - resolution: {integrity: sha512-Jxu255j0gToMGEiqufP8ZtKI8HW90lOLjwJ3LrdlD/NLsAY0tOQf1fWc53u28hWmmNGMxmCrL2p66IOgMDhDUw==} - engines: {node: '>=16.0.0'} + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} - '@aws-sdk/credential-provider-http@3.568.0': - resolution: {integrity: sha512-gL0NlyI2eW17hnCrh45hZV+qjtBquB+Bckiip9R6DIVRKqYcoILyiFhuOgf2bXeF23gVh6j18pvUvIoTaFWs5w==} - engines: {node: '>=16.0.0'} + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-sdk/credential-provider-http@3.582.0': - resolution: {integrity: sha512-kGOUKw5ryPkDIYB69PjK3SicVLTbWB06ouFN2W1EvqUJpkQGPAUGzYcomKtt3mJaCTf/1kfoaHwARAl6KKSP8Q==} + '@aws-sdk/client-cognito-identity@3.687.0': + resolution: {integrity: sha512-jcQTioloSed+Jc3snjrgpWejkOm8t3Zt+jWrApw3ejN8qBtpFCH43M7q/CSDVZ9RS1IjX+KRWoBFnrDOnbuw0Q==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-ini@3.478.0': - resolution: {integrity: sha512-SsrYEYUvTG9ZoPC+zB19AnVoOKID+QIEHJDIi1GCZXW5kTVyr1saTVm4orG2TjYvbHQMddsWtHOvGYXZWAYMbw==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-ini@3.568.0': - resolution: {integrity: sha512-m5DUN9mpto5DhEvo6w3+8SS6q932ja37rTNvpPqWJIaWhj7OorAwVirSaJQAQB/M8+XCUIrUonxytphZB28qGQ==} + '@aws-sdk/client-rds-data@3.687.0': + resolution: {integrity: sha512-/m+HcjbINf74SIoXjXM61GcWzFYtN6OdL1JIO+FTN8P8usMvOOD14B8QGLghp0XAWhdl7NKU8y8BmaXShEffIw==} engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sts': ^3.568.0 - '@aws-sdk/credential-provider-ini@3.583.0': - resolution: {integrity: sha512-8I0oWNg/yps6ctjhEeL/qJ9BIa/+xXP7RPDQqFKZ2zBkWbmLLOoMWXRvl8uKUBD6qCe+DGmcu9skfVXeXSesEQ==} + '@aws-sdk/client-sso-oidc@3.687.0': + resolution: {integrity: sha512-Rdd8kLeTeh+L5ZuG4WQnWgYgdv7NorytKdZsGjiag1D8Wv3PcJvPqqWdgnI0Og717BSXVoaTYaN34FyqFYSx6Q==} engines: {node: '>=16.0.0'} peerDependencies: - '@aws-sdk/client-sts': ^3.583.0 - - '@aws-sdk/credential-provider-node@3.478.0': - resolution: {integrity: sha512-nwDutJYeHiIZCQDgKIUrsgwAWTil0mNe+cbd+j8fi+wwxkWUzip+F0+z02molJ8WrUUKNRhqB1V5aVx7IranuA==} - engines: {node: '>=14.0.0'} + '@aws-sdk/client-sts': ^3.687.0 - '@aws-sdk/credential-provider-node@3.569.0': - resolution: {integrity: sha512-7jH4X2qlPU3PszZP1zvHJorhLARbU1tXvp8ngBe8ArXBrkFpl/dQ2Y/IRAICPm/pyC1IEt8L/CvKp+dz7v/eRw==} + '@aws-sdk/client-sso@3.687.0': + resolution: {integrity: sha512-dfj0y9fQyX4kFill/ZG0BqBTLQILKlL7+O5M4F9xlsh2WNuV2St6WtcOg14Y1j5UODPJiJs//pO+mD1lihT5Kw==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-node@3.583.0': - resolution: {integrity: sha512-yBNypBXny7zJH85SzxDj8s1mbLXv9c/Vbq0qR3R3POj2idZ6ywB/qlIRC1XwBuv49Wvg8kA1wKXk3K3jrpcVIw==} + '@aws-sdk/client-sts@3.687.0': + resolution: {integrity: sha512-SQjDH8O4XCTtouuCVYggB0cCCrIaTzUZIkgJUpOsIEJBLlTbNOb/BZqUShAQw2o9vxr2rCeOGjAQOYPysW/Pmg==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-process@3.468.0': - resolution: {integrity: sha512-OYSn1A/UsyPJ7Z8Q2cNhTf55O36shPmSsvOfND04nSfu1nPaR+VUvvsP7v+brhGpwC/GAKTIdGAo4blH31BS6A==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-process@3.568.0': - resolution: {integrity: sha512-r01zbXbanP17D+bQUb7mD8Iu2SuayrrYZ0Slgvx32qgz47msocV9EPCSwI4Hkw2ZtEPCeLQR4XCqFJB1D9P50w==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/credential-provider-process@3.577.0': - resolution: {integrity: sha512-Gin6BWtOiXxIgITrJ3Nwc+Y2P1uVT6huYR4EcbA/DJUPWyO0n9y5UFLewPvVbLkRn15JeEqErBLUrHclkiOKtw==} + '@aws-sdk/core@3.686.0': + resolution: {integrity: sha512-Xt3DV4DnAT3v2WURwzTxWQK34Ew+iiLzoUoguvLaZrVMFOqMMrwVjP+sizqIaHp1j7rGmFcN5I8saXnsDLuQLA==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-sso@3.478.0': - resolution: {integrity: sha512-LsDShG51X/q+s5ZFN7kHVqrd8ZHdyEyHqdhoocmRvvw2Dif50M0AqQfvCrW1ndj5CNzXO4x/eH8EK5ZOVlS6Sg==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-sso@3.568.0': - resolution: {integrity: sha512-+TA77NWOEXMUcfLoOuim6xiyXFg1GqHj55ggI1goTKGVvdHYZ+rhxZbwjI29+ewzPt/qcItDJcvhrjOrg9lCag==} + '@aws-sdk/credential-provider-cognito-identity@3.687.0': + resolution: {integrity: sha512-hJq9ytoj2q/Jonc7mox/b0HT+j4NeMRuU184DkXRJbvIvwwB+oMt12221kThLezMhwIYfXEteZ7GEId7Hn8Y8g==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-sso@3.583.0': - resolution: {integrity: sha512-G/1EvL9tBezSiU+06tG4K/kOvFfPjnheT4JSXqjPM7+vjKzgp2jxp1J9MMd69zs4jVWon932zMeGgjrCplzMEg==} + '@aws-sdk/credential-provider-env@3.686.0': + resolution: {integrity: sha512-osD7lPO8OREkgxPiTWmA1i6XEmOth1uW9HWWj/+A2YGCj1G/t2sHu931w4Qj9NWHYZtbTTXQYVRg+TErALV7nQ==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-web-identity@3.468.0': - resolution: {integrity: sha512-rexymPmXjtkwCPfhnUq3EjO1rSkf39R4Jz9CqiM7OsqK2qlT5Y/V3gnMKn0ZMXsYaQOMfM3cT5xly5R+OKDHlw==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-web-identity@3.568.0': - resolution: {integrity: sha512-ZJSmTmoIdg6WqAULjYzaJ3XcbgBzVy36lir6Y0UBMRGaxDgos1AARuX6EcYzXOl+ksLvxt/xMQ+3aYh1LWfKSw==} + '@aws-sdk/credential-provider-http@3.686.0': + resolution: {integrity: sha512-xyGAD/f3vR/wssUiZrNFWQWXZvI4zRm2wpHhoHA1cC2fbRMNFYtFn365yw6dU7l00ZLcdFB1H119AYIUZS7xbw==} engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sts': ^3.568.0 - '@aws-sdk/credential-provider-web-identity@3.577.0': - resolution: {integrity: sha512-ZGHGNRaCtJJmszb9UTnC7izNCtRUttdPlLdMkh41KPS32vfdrBDHs1JrpbZijItRj1xKuOXsiYSXLAaHGcLh8Q==} + '@aws-sdk/credential-provider-ini@3.687.0': + resolution: {integrity: sha512-6d5ZJeZch+ZosJccksN0PuXv7OSnYEmanGCnbhUqmUSz9uaVX6knZZfHCZJRgNcfSqg9QC0zsFA/51W5HCUqSQ==} engines: {node: '>=16.0.0'} peerDependencies: - '@aws-sdk/client-sts': ^3.577.0 - - '@aws-sdk/credential-providers@3.569.0': - resolution: {integrity: sha512-UL7EewaM1Xk6e4XLsxrCBv/owVSDI6Katnok6uMfqA8dA0x3ELjO7W35DW4wpWejQHErN5Gp1zloV9y3t34FMQ==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/middleware-host-header@3.468.0': - resolution: {integrity: sha512-gwQ+/QhX+lhof304r6zbZ/V5l5cjhGRxLL3CjH1uJPMcOAbw9wUlMdl+ibr8UwBZ5elfKFGiB1cdW/0uMchw0w==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/middleware-host-header@3.567.0': - resolution: {integrity: sha512-zQHHj2N3in9duKghH7AuRNrOMLnKhW6lnmb7dznou068DJtDr76w475sHp2TF0XELsOGENbbBsOlN/S5QBFBVQ==} - engines: {node: '>=16.0.0'} + '@aws-sdk/client-sts': ^3.687.0 - '@aws-sdk/middleware-host-header@3.577.0': - resolution: {integrity: sha512-9ca5MJz455CODIVXs0/sWmJm7t3QO4EUa1zf8pE8grLpzf0J94bz/skDWm37Pli13T3WaAQBHCTiH2gUVfCsWg==} + '@aws-sdk/credential-provider-node@3.687.0': + resolution: {integrity: sha512-Pqld8Nx11NYaBUrVk3bYiGGpLCxkz8iTONlpQWoVWFhSOzlO7zloNOaYbD2XgFjjqhjlKzE91drs/f41uGeCTA==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-logger@3.468.0': - resolution: {integrity: sha512-X5XHKV7DHRXI3f29SAhJPe/OxWRFgDWDMMCALfzhmJfCi6Jfh0M14cJKoC+nl+dk9lB+36+jKjhjETZaL2bPlA==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/middleware-logger@3.568.0': - resolution: {integrity: sha512-BinH72RG7K3DHHC1/tCulocFv+ZlQ9SrPF9zYT0T1OT95JXuHhB7fH8gEABrc6DAtOdJJh2fgxQjPy5tzPtsrA==} + '@aws-sdk/credential-provider-process@3.686.0': + resolution: {integrity: sha512-sXqaAgyzMOc+dm4CnzAR5Q6S9OWVHyZjLfW6IQkmGjqeQXmZl24c4E82+w64C+CTkJrFLzH1VNOYp1Hy5gE6Qw==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-logger@3.577.0': - resolution: {integrity: sha512-aPFGpGjTZcJYk+24bg7jT4XdIp42mFXSuPt49lw5KygefLyJM/sB0bKKqPYYivW0rcuZ9brQ58eZUNthrzYAvg==} + '@aws-sdk/credential-provider-sso@3.687.0': + resolution: {integrity: sha512-N1YCoE7DovIRF2ReyRrA4PZzF0WNi4ObPwdQQkVxhvSm7PwjbWxrfq7rpYB+6YB1Uq3QPzgVwUFONE36rdpxUQ==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-recursion-detection@3.468.0': - resolution: {integrity: sha512-vch9IQib2Ng9ucSyRW2eKNQXHUPb5jUPCLA5otTW/8nGjcOU37LxQG4WrxO7uaJ9Oe8hjHO+hViE3P0KISUhtA==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/middleware-recursion-detection@3.567.0': - resolution: {integrity: sha512-rFk3QhdT4IL6O/UWHmNdjJiURutBCy+ogGqaNHf/RELxgXH3KmYorLwCe0eFb5hq8f6vr3zl4/iH7YtsUOuo1w==} + '@aws-sdk/credential-provider-web-identity@3.686.0': + resolution: {integrity: sha512-40UqCpPxyHCXDP7CGd9JIOZDgDZf+u1OyLaGBpjQJlz1HYuEsIWnnbTe29Yg3Ah/Zc3g4NBWcUdlGVotlnpnDg==} engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.686.0 - '@aws-sdk/middleware-recursion-detection@3.577.0': - resolution: {integrity: sha512-pn3ZVEd2iobKJlR3H+bDilHjgRnNrQ6HMmK9ZzZw89Ckn3Dcbv48xOv4RJvu0aU8SDLl/SNCxppKjeLDTPGBNA==} + '@aws-sdk/credential-providers@3.687.0': + resolution: {integrity: sha512-3aKlmKaOplpanOycmoigbTrQsqtxpzhpfquCey51aHf9GYp2yYyYF1YOgkXpE3qm3w6eiEN1asjJ2gqoECUuPA==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-signing@3.468.0': - resolution: {integrity: sha512-s+7fSB1gdnnTj5O0aCCarX3z5Vppop8kazbNSZADdkfHIDWCN80IH4ZNjY3OWqaAz0HmR4LNNrovdR304ojb4Q==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/middleware-user-agent@3.478.0': - resolution: {integrity: sha512-Rec+nAPIzzwxgHPW+xqY6tooJGFOytpYg/xSRv8/IXl3xKGhmpMGs6gDWzmMBv/qy5nKTvLph/csNWJ98GWXCw==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/middleware-user-agent@3.567.0': - resolution: {integrity: sha512-a7DBGMRBLWJU3BqrQjOtKS4/RcCh/BhhKqwjCE0FEhhm6A/GGuAs/DcBGOl6Y8Wfsby3vejSlppTLH/qtV1E9w==} + '@aws-sdk/middleware-host-header@3.686.0': + resolution: {integrity: sha512-+Yc6rO02z+yhFbHmRZGvEw1vmzf/ifS9a4aBjJGeVVU+ZxaUvnk+IUZWrj4YQopUQ+bSujmMUzJLXSkbDq7yuw==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-user-agent@3.583.0': - resolution: {integrity: sha512-xVNXXXDWvBVI/AeVtSdA9SVumqxiZaESk/JpUn9GMkmtTKfter0Cweap+1iQ9j8bRAO0vNhmIkbcvdB1S4WVUw==} + '@aws-sdk/middleware-logger@3.686.0': + resolution: {integrity: sha512-cX43ODfA2+SPdX7VRxu6gXk4t4bdVJ9pkktbfnkE5t27OlwNfvSGGhnHrQL8xTOFeyQ+3T+oowf26gf1OI+vIg==} engines: {node: '>=16.0.0'} - '@aws-sdk/region-config-resolver@3.470.0': - resolution: {integrity: sha512-C1o1J06iIw8cyAAOvHqT4Bbqf+PgQ/RDlSyjt2gFfP2OovDpc2o2S90dE8f8iZdSGpg70N5MikT1DBhW9NbhtQ==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/region-config-resolver@3.567.0': - resolution: {integrity: sha512-VMDyYi5Dh2NydDiIARZ19DwMfbyq0llS736cp47qopmO6wzdeul7WRTx8NKfEYN0/AwEaqmTW0ohx58jSB1lYg==} + '@aws-sdk/middleware-recursion-detection@3.686.0': + resolution: {integrity: sha512-jF9hQ162xLgp9zZ/3w5RUNhmwVnXDBlABEUX8jCgzaFpaa742qR/KKtjjZQ6jMbQnP+8fOCSXFAVNMU+s6v81w==} engines: {node: '>=16.0.0'} - '@aws-sdk/region-config-resolver@3.577.0': - resolution: {integrity: sha512-4ChCFACNwzqx/xjg3zgFcW8Ali6R9C95cFECKWT/7CUM1D0MGvkclSH2cLarmHCmJgU6onKkJroFtWp0kHhgyg==} + '@aws-sdk/middleware-user-agent@3.687.0': + resolution: {integrity: sha512-nUgsKiEinyA50CaDXojAkOasAU3Apdg7Qox6IjNUC4ZjgOu7QWsCDB5N28AYMUt06cNYeYQdfMX1aEzG85a1Mg==} engines: {node: '>=16.0.0'} - '@aws-sdk/token-providers@3.478.0': - resolution: {integrity: sha512-7b5tj1y/wGHZIZ+ckjOUKgKrMuCJMF/G1UKZKIqqdekeEsjcThbvoxAMeY0FEowu2ODVk/ggOmpBFxcu0iYd6A==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/token-providers@3.568.0': - resolution: {integrity: sha512-mCQElYzY5N2JlXB7LyjOoLvRN/JiSV+E9szLwhYN3dleTUCMbGqWb7RiAR2V3fO+mz8f9kR7DThTExKJbKogKw==} + '@aws-sdk/region-config-resolver@3.686.0': + resolution: {integrity: sha512-6zXD3bSD8tcsMAVVwO1gO7rI1uy2fCD3czgawuPGPopeLiPpo6/3FoUWCQzk2nvEhj7p9Z4BbjwZGSlRkVrXTw==} engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sso-oidc': ^3.568.0 - '@aws-sdk/token-providers@3.577.0': - resolution: {integrity: sha512-0CkIZpcC3DNQJQ1hDjm2bdSy/Xjs7Ny5YvSsacasGOkNfk+FdkiQy6N67bZX3Zbc9KIx+Nz4bu3iDeNSNplnnQ==} + '@aws-sdk/token-providers@3.686.0': + resolution: {integrity: sha512-9oL4kTCSePFmyKPskibeiOXV6qavPZ63/kXM9Wh9V6dTSvBtLeNnMxqGvENGKJcTdIgtoqyqA6ET9u0PJ5IRIg==} engines: {node: '>=16.0.0'} peerDependencies: - '@aws-sdk/client-sso-oidc': ^3.577.0 - - '@aws-sdk/types@3.468.0': - resolution: {integrity: sha512-rx/9uHI4inRbp2tw3Y4Ih4PNZkVj32h7WneSg3MVgVjAoVD5Zti9KhS5hkvsBxfgmQmg0AQbE+b1sy5WGAgntA==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/types@3.567.0': - resolution: {integrity: sha512-JBznu45cdgQb8+T/Zab7WpBmfEAh77gsk99xuF4biIb2Sw1mdseONdoGDjEJX57a25TzIv/WUJ2oABWumckz1A==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/types@3.577.0': - resolution: {integrity: sha512-FT2JZES3wBKN/alfmhlo+3ZOq/XJ0C7QOZcDNrpKjB0kqYoKjhVKZ/Hx6ArR0czkKfHzBBEs6y40ebIHx2nSmA==} - engines: {node: '>=16.0.0'} - - '@aws-sdk/util-endpoints@3.478.0': - resolution: {integrity: sha512-u9Mcg3euGJGs5clPt9mBuhBjHiEKiD0PnfvArhfq9i+dcY5mbCq/i1Dezp3iv1fZH9xxQt7hPXDfSpt1yUSM6g==} - engines: {node: '>=14.0.0'} + '@aws-sdk/client-sso-oidc': ^3.686.0 - '@aws-sdk/util-endpoints@3.567.0': - resolution: {integrity: sha512-WVhot3qmi0BKL9ZKnUqsvCd++4RF2DsJIG32NlRaml1FT9KaqSzNv0RXeA6k/kYwiiNT7y3YWu3Lbzy7c6vG9g==} + '@aws-sdk/types@3.686.0': + resolution: {integrity: sha512-xFnrb3wxOoJcW2Xrh63ZgFo5buIu9DF7bOHnwoUxHdNpUXicUh0AHw85TjXxyxIAd0d1psY/DU7QHoNI3OswgQ==} engines: {node: '>=16.0.0'} - '@aws-sdk/util-endpoints@3.583.0': - resolution: {integrity: sha512-ZC9mb2jq6BFXPYsUsD2tmYcnlmd+9PGNwnFNn8jk4abna5Jjk2wDknN81ybktmBR5ttN9W8ugmktuKtvAMIDCQ==} + '@aws-sdk/util-endpoints@3.686.0': + resolution: {integrity: sha512-7msZE2oYl+6QYeeRBjlDgxQUhq/XRky3cXE0FqLFs2muLS7XSuQEXkpOXB3R782ygAP6JX0kmBxPTLurRTikZg==} engines: {node: '>=16.0.0'} - '@aws-sdk/util-locate-window@3.568.0': - resolution: {integrity: sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==} + '@aws-sdk/util-locate-window@3.679.0': + resolution: {integrity: sha512-zKTd48/ZWrCplkXpYDABI74rQlbR0DNHs8nH95htfSLj9/mWRSwaGptoxwcihaq/77vi/fl2X3y0a1Bo8bt7RA==} engines: {node: '>=16.0.0'} - '@aws-sdk/util-user-agent-browser@3.468.0': - resolution: {integrity: sha512-OJyhWWsDEizR3L+dCgMXSUmaCywkiZ7HSbnQytbeKGwokIhD69HTiJcibF/sgcM5gk4k3Mq3puUhGnEZ46GIig==} - - '@aws-sdk/util-user-agent-browser@3.567.0': - resolution: {integrity: sha512-cqP0uXtZ7m7hRysf3fRyJwcY1jCgQTpJy7BHB5VpsE7DXlXHD5+Ur5L42CY7UrRPrB6lc6YGFqaAOs5ghMcLyA==} - - '@aws-sdk/util-user-agent-browser@3.577.0': - resolution: {integrity: sha512-zEAzHgR6HWpZOH7xFgeJLc6/CzMcx4nxeQolZxVZoB5pPaJd3CjyRhZN0xXeZB0XIRCWmb4yJBgyiugXLNMkLA==} - - '@aws-sdk/util-user-agent-node@3.470.0': - resolution: {integrity: sha512-QxsZ9iVHcBB/XRdYvwfM5AMvNp58HfqkIrH88mY0cmxuvtlIGDfWjczdDrZMJk9y0vIq+cuoCHsGXHu7PyiEAQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true - - '@aws-sdk/util-user-agent-node@3.568.0': - resolution: {integrity: sha512-NVoZoLnKF+eXPBvXg+KqixgJkPSrerR6Gqmbjwqbv14Ini+0KNKB0/MXas1mDGvvEgtNkHI/Cb9zlJ3KXpti2A==} - engines: {node: '>=16.0.0'} - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true + '@aws-sdk/util-user-agent-browser@3.686.0': + resolution: {integrity: sha512-YiQXeGYZegF1b7B2GOR61orhgv79qmI0z7+Agm3NXLO6hGfVV3kFUJbXnjtH1BgWo5hbZYW7HQ2omGb3dnb6Lg==} - '@aws-sdk/util-user-agent-node@3.577.0': - resolution: {integrity: sha512-XqvtFjbSMtycZTWVwDe8DRWovuoMbA54nhUoZwVU6rW9OSD6NZWGR512BUGHFaWzW0Wg8++Dj10FrKTG2XtqfA==} + '@aws-sdk/util-user-agent-node@3.687.0': + resolution: {integrity: sha512-idkP6ojSTZ4ek1pJ8wIN7r9U3KR5dn0IkJn3KQBXQ58LWjkRqLtft2vxzdsktWwhPKjjmIKl1S0kbvqLawf8XQ==} engines: {node: '>=16.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -1071,60 +972,52 @@ packages: aws-crt: optional: true - '@aws-sdk/util-utf8-browser@3.259.0': - resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} - '@babel/code-frame@7.10.4': resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==} - '@babel/code-frame@7.22.10': - resolution: {integrity: sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==} - engines: {node: '>=6.9.0'} - - '@babel/code-frame@7.22.13': - resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} - '@babel/code-frame@7.24.6': - resolution: {integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==} + '@babel/compat-data@7.26.2': + resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.24.6': - resolution: {integrity: sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.24.6': - resolution: {integrity: sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==} + '@babel/core@7.26.0': + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} engines: {node: '>=6.9.0'} '@babel/generator@7.17.7': resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} engines: {node: '>=6.9.0'} - '@babel/generator@7.24.6': - resolution: {integrity: sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==} + '@babel/generator@7.2.0': + resolution: {integrity: sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg==} + + '@babel/generator@7.26.2': + resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.24.6': - resolution: {integrity: sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==} + '@babel/helper-annotate-as-pure@7.25.9': + resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} engines: {node: '>=6.9.0'} - '@babel/helper-builder-binary-assignment-operator-visitor@7.24.6': - resolution: {integrity: sha512-+wnfqc5uHiMYtvRX7qu80Toef8BXeh4HHR1SPeonGb1SKPniNEd4a/nlaJJMv/OIEYvIVavvo0yR7u10Gqz0Iw==} + '@babel/helper-builder-binary-assignment-operator-visitor@7.25.9': + resolution: {integrity: sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.24.6': - resolution: {integrity: sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==} + '@babel/helper-compilation-targets@7.25.9': + resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.24.6': - resolution: {integrity: sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==} + '@babel/helper-create-class-features-plugin@7.25.9': + resolution: {integrity: sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.24.6': - resolution: {integrity: sha512-C875lFBIWWwyv6MHZUG9HmRrlTDgOsLWZfYR0nW69gaKJNe0/Mpxx5r0EID2ZdHQkdUmQo2t0uNckTL08/1BgA==} + '@babel/helper-create-regexp-features-plugin@7.25.9': + resolution: {integrity: sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1134,158 +1027,119 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - '@babel/helper-environment-visitor@7.22.5': - resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-environment-visitor@7.24.6': - resolution: {integrity: sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==} - engines: {node: '>=6.9.0'} - - '@babel/helper-function-name@7.22.5': - resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-function-name@7.24.6': - resolution: {integrity: sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==} + '@babel/helper-environment-visitor@7.24.7': + resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} engines: {node: '>=6.9.0'} - '@babel/helper-hoist-variables@7.22.5': - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + '@babel/helper-function-name@7.24.7': + resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} engines: {node: '>=6.9.0'} - '@babel/helper-hoist-variables@7.24.6': - resolution: {integrity: sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==} + '@babel/helper-hoist-variables@7.24.7': + resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.24.6': - resolution: {integrity: sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==} + '@babel/helper-member-expression-to-functions@7.25.9': + resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.24.6': - resolution: {integrity: sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==} + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.24.6': - resolution: {integrity: sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==} + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-optimise-call-expression@7.24.6': - resolution: {integrity: sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==} + '@babel/helper-optimise-call-expression@7.25.9': + resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.24.6': - resolution: {integrity: sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==} + '@babel/helper-plugin-utils@7.25.9': + resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} engines: {node: '>=6.9.0'} - '@babel/helper-remap-async-to-generator@7.24.6': - resolution: {integrity: sha512-1Qursq9ArRZPAMOZf/nuzVW8HgJLkTB9y9LfP4lW2MVp4e9WkLJDovfKBxoDcCk6VuzIxyqWHyBoaCtSRP10yg==} + '@babel/helper-remap-async-to-generator@7.25.9': + resolution: {integrity: sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-replace-supers@7.24.6': - resolution: {integrity: sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==} + '@babel/helper-replace-supers@7.25.9': + resolution: {integrity: sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-simple-access@7.24.6': - resolution: {integrity: sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==} - engines: {node: '>=6.9.0'} - - '@babel/helper-skip-transparent-expression-wrappers@7.24.6': - resolution: {integrity: sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-split-export-declaration@7.22.6': - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} - engines: {node: '>=6.9.0'} - - '@babel/helper-split-export-declaration@7.24.6': - resolution: {integrity: sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.22.5': - resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.23.4': - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.24.6': - resolution: {integrity: sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.22.20': - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + '@babel/helper-simple-access@7.25.9': + resolution: {integrity: sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.22.5': - resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.24.6': - resolution: {integrity: sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==} + '@babel/helper-split-export-declaration@7.24.7': + resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.24.6': - resolution: {integrity: sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==} + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.24.6': - resolution: {integrity: sha512-f1JLrlw/jbiNfxvdrfBgio/gRBk3yTAEJWirpAkiJG2Hb22E7cEYKHWo0dFPTv/niPovzIdPdEDetrv6tC6gPQ==} + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.24.6': - resolution: {integrity: sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==} + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.22.10': - resolution: {integrity: sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==} + '@babel/helper-wrap-function@7.25.9': + resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.22.20': - resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} + '@babel/helpers@7.26.0': + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.24.6': - resolution: {integrity: sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==} + '@babel/highlight@7.25.9': + resolution: {integrity: sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.22.10': - resolution: {integrity: sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==} + '@babel/parser@7.26.2': + resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@7.24.6': - resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==} - engines: {node: '>=6.0.0'} - hasBin: true + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9': + resolution: {integrity: sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.6': - resolution: {integrity: sha512-bYndrJ6Ph6Ar+GaB5VAc0JPoP80bQCm4qon6JEzXfRl5QZyQ8Ur1K6k7htxWmPA5z+k7JQvaMUrtXlqclWYzKw==} + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9': + resolution: {integrity: sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.6': - resolution: {integrity: sha512-iVuhb6poq5ikqRq2XWU6OQ+R5o9wF+r/or9CeUyovgptz0UlnK4/seOQ1Istu/XybYjAhQv1FRSSfHHufIku5Q==} + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9': + resolution: {integrity: sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.6': - resolution: {integrity: sha512-c8TER5xMDYzzFcGqOEp9l4hvB7dcbhcGjcLVwxWfe4P5DOafdwjsBJZKsmv+o3aXh7NhopvayQIovHrh2zSRUQ==} + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9': + resolution: {integrity: sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.6': - resolution: {integrity: sha512-z8zEjYmwBUHN/pCF3NuWBhHQjJCrd33qAi8MgANfMrAvn72k2cImT8VjK9LJFu4ysOLJqhfkYYb3MvwANRUNZQ==} + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9': + resolution: {integrity: sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1304,14 +1158,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-proposal-decorators@7.24.6': - resolution: {integrity: sha512-8DjR0/DzlBhz2SVi9a19/N2U5+C3y3rseXuyoKL9SP8vnbewscj1eHZtL6kpEn4UCuUmqEo0mvqyDYRFoN2gpA==} + '@babel/plugin-proposal-decorators@7.25.9': + resolution: {integrity: sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-proposal-export-default-from@7.24.6': - resolution: {integrity: sha512-qPPDbYs9j5IArMFqYi85QxatHURSzRyskKpIbjrVoVglDuGdhu1s7UTCmXvP/qR2aHa3EdJ8X3iZvQAHjmdHUw==} + '@babel/plugin-proposal-export-default-from@7.25.9': + resolution: {integrity: sha512-ykqgwNfSnNOB+C8fV5X4mG3AVmvu+WVxcaU9xHHtBb7PCrPeweMmPjGsn8eMaeJg6SJuoUuZENeeSWaarWqonQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1369,6 +1223,11 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-class-properties@7.12.13': resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: @@ -1380,8 +1239,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-decorators@7.24.6': - resolution: {integrity: sha512-gInH8LEqBp+wkwTVihCd/qf+4s28g81FZyvlIbAurHk9eSiItEKG7E0uNK2UdpgsD79aJVAW3R3c85h0YJ0jsw==} + '@babel/plugin-syntax-decorators@7.25.9': + resolution: {integrity: sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1391,31 +1250,26 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-export-default-from@7.24.6': - resolution: {integrity: sha512-Nzl7kZ4tjOM2LJpejBMPwZs7OJfc26++2HsMQuSrw6gxpqXGtZZ3Rj4Zt4Qm7vulMZL2gHIGGc2stnlQnHQCqA==} + '@babel/plugin-syntax-export-default-from@7.25.9': + resolution: {integrity: sha512-9MhJ/SMTsVqsd69GyQg89lYR4o9T+oDGv5F6IsigxxqFVOyR/IflDLYP8WDI1l8fkhNGGktqkvL5qwNCtGEpgQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-export-namespace-from@7.8.3': - resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-flow@7.24.6': - resolution: {integrity: sha512-gNkksSdV8RbsCoHF9sjVYrHfYACMl/8U32UfUhJ9+84/ASXw8dlx+eHyyF0m6ncQJ9IBSxfuCkB36GJqYdXTOA==} + '@babel/plugin-syntax-flow@7.26.0': + resolution: {integrity: sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.24.6': - resolution: {integrity: sha512-BE6o2BogJKJImTmGpkmOic4V0hlRRxVtzqxiSPa8TIFxyhi4EFjHm08nq1M4STK4RytuLMgnSz0/wfflvGFNOg==} + '@babel/plugin-syntax-import-assertions@7.26.0': + resolution: {integrity: sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.24.6': - resolution: {integrity: sha512-D+CfsVZousPXIdudSII7RGy52+dYRtbyKAZcvtQKq/NpsivyMVduepzcLqG5pMBugtMdedxdC8Ramdpcne9ZWQ==} + '@babel/plugin-syntax-import-attributes@7.26.0': + resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1430,8 +1284,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.24.6': - resolution: {integrity: sha512-lWfvAIFNWMlCsU0DRUun2GpFwZdGTukLaHJqRh1JRb80NdAP5Sb1HDHB5X9P9OtgZHQl089UzQkpYlBq2VTPRw==} + '@babel/plugin-syntax-jsx@7.25.9': + resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1478,8 +1332,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.24.6': - resolution: {integrity: sha512-TzCtxGgVTEJWWwcYwQhCIQ6WaKlo80/B+Onsk4RRCcYqpYGFcG9etPW94VToGte5AAcxRrhjPUFvUS3Y2qKi4A==} + '@babel/plugin-syntax-typescript@7.25.9': + resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1490,356 +1344,368 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-arrow-functions@7.24.6': - resolution: {integrity: sha512-jSSSDt4ZidNMggcLx8SaKsbGNEfIl0PHx/4mFEulorE7bpYLbN0d3pDW3eJ7Y5Z3yPhy3L3NaPCYyTUY7TuugQ==} + '@babel/plugin-transform-arrow-functions@7.25.9': + resolution: {integrity: sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-generator-functions@7.24.6': - resolution: {integrity: sha512-VEP2o4iR2DqQU6KPgizTW2mnMx6BG5b5O9iQdrW9HesLkv8GIA8x2daXBQxw1MrsIkFQGA/iJ204CKoQ8UcnAA==} + '@babel/plugin-transform-async-generator-functions@7.25.9': + resolution: {integrity: sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-to-generator@7.24.6': - resolution: {integrity: sha512-NTBA2SioI3OsHeIn6sQmhvXleSl9T70YY/hostQLveWs0ic+qvbA3fa0kwAwQ0OA/XGaAerNZRQGJyRfhbJK4g==} + '@babel/plugin-transform-async-to-generator@7.25.9': + resolution: {integrity: sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoped-functions@7.24.6': - resolution: {integrity: sha512-XNW7jolYHW9CwORrZgA/97tL/k05qe/HL0z/qqJq1mdWhwwCM6D4BJBV7wAz9HgFziN5dTOG31znkVIzwxv+vw==} + '@babel/plugin-transform-block-scoped-functions@7.25.9': + resolution: {integrity: sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.24.6': - resolution: {integrity: sha512-S/t1Xh4ehW7sGA7c1j/hiOBLnEYCp/c2sEG4ZkL8kI1xX9tW2pqJTCHKtdhe/jHKt8nG0pFCrDHUXd4DvjHS9w==} + '@babel/plugin-transform-block-scoping@7.25.9': + resolution: {integrity: sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-properties@7.24.6': - resolution: {integrity: sha512-j6dZ0Z2Z2slWLR3kt9aOmSIrBvnntWjMDN/TVcMPxhXMLmJVqX605CBRlcGI4b32GMbfifTEsdEjGjiE+j/c3A==} + '@babel/plugin-transform-class-properties@7.25.9': + resolution: {integrity: sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-static-block@7.24.6': - resolution: {integrity: sha512-1QSRfoPI9RoLRa8Mnakc6v3e0gJxiZQTYrMfLn+mD0sz5+ndSzwymp2hDcYJTyT0MOn0yuWzj8phlIvO72gTHA==} + '@babel/plugin-transform-class-static-block@7.26.0': + resolution: {integrity: sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 - '@babel/plugin-transform-classes@7.24.6': - resolution: {integrity: sha512-+fN+NO2gh8JtRmDSOB6gaCVo36ha8kfCW1nMq2Gc0DABln0VcHN4PrALDvF5/diLzIRKptC7z/d7Lp64zk92Fg==} + '@babel/plugin-transform-classes@7.25.9': + resolution: {integrity: sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-computed-properties@7.24.6': - resolution: {integrity: sha512-cRzPobcfRP0ZtuIEkA8QzghoUpSB3X3qSH5W2+FzG+VjWbJXExtx0nbRqwumdBN1x/ot2SlTNQLfBCnPdzp6kg==} + '@babel/plugin-transform-computed-properties@7.25.9': + resolution: {integrity: sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.24.6': - resolution: {integrity: sha512-YLW6AE5LQpk5npNXL7i/O+U9CE4XsBCuRPgyjl1EICZYKmcitV+ayuuUGMJm2lC1WWjXYszeTnIxF/dq/GhIZQ==} + '@babel/plugin-transform-destructuring@7.25.9': + resolution: {integrity: sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dotall-regex@7.24.6': - resolution: {integrity: sha512-rCXPnSEKvkm/EjzOtLoGvKseK+dS4kZwx1HexO3BtRtgL0fQ34awHn34aeSHuXtZY2F8a1X8xqBBPRtOxDVmcA==} + '@babel/plugin-transform-dotall-regex@7.25.9': + resolution: {integrity: sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-keys@7.24.6': - resolution: {integrity: sha512-/8Odwp/aVkZwPFJMllSbawhDAO3UJi65foB00HYnK/uXvvCPm0TAXSByjz1mpRmp0q6oX2SIxpkUOpPFHk7FLA==} + '@babel/plugin-transform-duplicate-keys@7.25.9': + resolution: {integrity: sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dynamic-import@7.24.6': - resolution: {integrity: sha512-vpq8SSLRTBLOHUZHSnBqVo0AKX3PBaoPs2vVzYVWslXDTDIpwAcCDtfhUcHSQQoYoUvcFPTdC8TZYXu9ZnLT/w==} + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9': + resolution: {integrity: sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-dynamic-import@7.25.9': + resolution: {integrity: sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.24.6': - resolution: {integrity: sha512-EemYpHtmz0lHE7hxxxYEuTYOOBZ43WkDgZ4arQ4r+VX9QHuNZC+WH3wUWmRNvR8ECpTRne29aZV6XO22qpOtdA==} + '@babel/plugin-transform-exponentiation-operator@7.25.9': + resolution: {integrity: sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-export-namespace-from@7.24.6': - resolution: {integrity: sha512-inXaTM1SVrIxCkIJ5gqWiozHfFMStuGbGJAxZFBoHcRRdDP0ySLb3jH6JOwmfiinPwyMZqMBX+7NBDCO4z0NSA==} + '@babel/plugin-transform-export-namespace-from@7.25.9': + resolution: {integrity: sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-flow-strip-types@7.24.6': - resolution: {integrity: sha512-1l8b24NoCpaQ13Vi6FtLG1nv6kNoi8PWvQb1AYO7GHZDpFfBYc3lbXArx1lP2KRt8b4pej1eWc/zrRmsQTfOdQ==} + '@babel/plugin-transform-flow-strip-types@7.25.9': + resolution: {integrity: sha512-/VVukELzPDdci7UUsWQaSkhgnjIWXnIyRpM02ldxaVoFK96c41So8JcKT3m0gYjyv7j5FNPGS5vfELrWalkbDA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-for-of@7.24.6': - resolution: {integrity: sha512-n3Sf72TnqK4nw/jziSqEl1qaWPbCRw2CziHH+jdRYvw4J6yeCzsj4jdw8hIntOEeDGTmHVe2w4MVL44PN0GMzg==} + '@babel/plugin-transform-for-of@7.25.9': + resolution: {integrity: sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-function-name@7.24.6': - resolution: {integrity: sha512-sOajCu6V0P1KPljWHKiDq6ymgqB+vfo3isUS4McqW1DZtvSVU2v/wuMhmRmkg3sFoq6GMaUUf8W4WtoSLkOV/Q==} + '@babel/plugin-transform-function-name@7.25.9': + resolution: {integrity: sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-json-strings@7.24.6': - resolution: {integrity: sha512-Uvgd9p2gUnzYJxVdBLcU0KurF8aVhkmVyMKW4MIY1/BByvs3EBpv45q01o7pRTVmTvtQq5zDlytP3dcUgm7v9w==} + '@babel/plugin-transform-json-strings@7.25.9': + resolution: {integrity: sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-literals@7.24.6': - resolution: {integrity: sha512-f2wHfR2HF6yMj+y+/y07+SLqnOSwRp8KYLpQKOzS58XLVlULhXbiYcygfXQxJlMbhII9+yXDwOUFLf60/TL5tw==} + '@babel/plugin-transform-literals@7.25.9': + resolution: {integrity: sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.24.6': - resolution: {integrity: sha512-EKaWvnezBCMkRIHxMJSIIylzhqK09YpiJtDbr2wsXTwnO0TxyjMUkaw4RlFIZMIS0iDj0KyIg7H7XCguHu/YDA==} + '@babel/plugin-transform-logical-assignment-operators@7.25.9': + resolution: {integrity: sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-member-expression-literals@7.24.6': - resolution: {integrity: sha512-9g8iV146szUo5GWgXpRbq/GALTnY+WnNuRTuRHWWFfWGbP9ukRL0aO/jpu9dmOPikclkxnNsjY8/gsWl6bmZJQ==} + '@babel/plugin-transform-member-expression-literals@7.25.9': + resolution: {integrity: sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-amd@7.24.6': - resolution: {integrity: sha512-eAGogjZgcwqAxhyFgqghvoHRr+EYRQPFjUXrTYKBRb5qPnAVxOOglaxc4/byHqjvq/bqO2F3/CGwTHsgKJYHhQ==} + '@babel/plugin-transform-modules-amd@7.25.9': + resolution: {integrity: sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-commonjs@7.24.6': - resolution: {integrity: sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==} + '@babel/plugin-transform-modules-commonjs@7.25.9': + resolution: {integrity: sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.24.6': - resolution: {integrity: sha512-xg1Z0J5JVYxtpX954XqaaAT6NpAY6LtZXvYFCJmGFJWwtlz2EmJoR8LycFRGNE8dBKizGWkGQZGegtkV8y8s+w==} + '@babel/plugin-transform-modules-systemjs@7.25.9': + resolution: {integrity: sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-umd@7.24.6': - resolution: {integrity: sha512-esRCC/KsSEUvrSjv5rFYnjZI6qv4R1e/iHQrqwbZIoRJqk7xCvEUiN7L1XrmW5QSmQe3n1XD88wbgDTWLbVSyg==} + '@babel/plugin-transform-modules-umd@7.25.9': + resolution: {integrity: sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-named-capturing-groups-regex@7.24.6': - resolution: {integrity: sha512-6DneiCiu91wm3YiNIGDWZsl6GfTTbspuj/toTEqLh9d4cx50UIzSdg+T96p8DuT7aJOBRhFyaE9ZvTHkXrXr6Q==} + '@babel/plugin-transform-named-capturing-groups-regex@7.25.9': + resolution: {integrity: sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-new-target@7.24.6': - resolution: {integrity: sha512-f8liz9JG2Va8A4J5ZBuaSdwfPqN6axfWRK+y66fjKYbwf9VBLuq4WxtinhJhvp1w6lamKUwLG0slK2RxqFgvHA==} + '@babel/plugin-transform-new-target@7.25.9': + resolution: {integrity: sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-nullish-coalescing-operator@7.24.6': - resolution: {integrity: sha512-+QlAiZBMsBK5NqrBWFXCYeXyiU1y7BQ/OYaiPAcQJMomn5Tyg+r5WuVtyEuvTbpV7L25ZSLfE+2E9ywj4FD48A==} + '@babel/plugin-transform-nullish-coalescing-operator@7.25.9': + resolution: {integrity: sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-numeric-separator@7.24.6': - resolution: {integrity: sha512-6voawq8T25Jvvnc4/rXcWZQKKxUNZcKMS8ZNrjxQqoRFernJJKjE3s18Qo6VFaatG5aiX5JV1oPD7DbJhn0a4Q==} + '@babel/plugin-transform-numeric-separator@7.25.9': + resolution: {integrity: sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-rest-spread@7.24.6': - resolution: {integrity: sha512-OKmi5wiMoRW5Smttne7BwHM8s/fb5JFs+bVGNSeHWzwZkWXWValR1M30jyXo1s/RaqgwwhEC62u4rFH/FBcBPg==} + '@babel/plugin-transform-object-rest-spread@7.25.9': + resolution: {integrity: sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-super@7.24.6': - resolution: {integrity: sha512-N/C76ihFKlZgKfdkEYKtaRUtXZAgK7sOY4h2qrbVbVTXPrKGIi8aww5WGe/+Wmg8onn8sr2ut6FXlsbu/j6JHg==} + '@babel/plugin-transform-object-super@7.25.9': + resolution: {integrity: sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-catch-binding@7.24.6': - resolution: {integrity: sha512-L5pZ+b3O1mSzJ71HmxSCmTVd03VOT2GXOigug6vDYJzE5awLI7P1g0wFcdmGuwSDSrQ0L2rDOe/hHws8J1rv3w==} + '@babel/plugin-transform-optional-catch-binding@7.25.9': + resolution: {integrity: sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.24.6': - resolution: {integrity: sha512-cHbqF6l1QP11OkYTYQ+hhVx1E017O5ZcSPXk9oODpqhcAD1htsWG2NpHrrhthEO2qZomLK0FXS+u7NfrkF5aOQ==} + '@babel/plugin-transform-optional-chaining@7.25.9': + resolution: {integrity: sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-parameters@7.24.6': - resolution: {integrity: sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA==} + '@babel/plugin-transform-parameters@7.25.9': + resolution: {integrity: sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-methods@7.24.6': - resolution: {integrity: sha512-T9LtDI0BgwXOzyXrvgLTT8DFjCC/XgWLjflczTLXyvxbnSR/gpv0hbmzlHE/kmh9nOvlygbamLKRo6Op4yB6aw==} + '@babel/plugin-transform-private-methods@7.25.9': + resolution: {integrity: sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-property-in-object@7.24.6': - resolution: {integrity: sha512-Qu/ypFxCY5NkAnEhCF86Mvg3NSabKsh/TPpBVswEdkGl7+FbsYHy1ziRqJpwGH4thBdQHh8zx+z7vMYmcJ7iaQ==} + '@babel/plugin-transform-private-property-in-object@7.25.9': + resolution: {integrity: sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-property-literals@7.24.6': - resolution: {integrity: sha512-oARaglxhRsN18OYsnPTpb8TcKQWDYNsPNmTnx5++WOAsUJ0cSC/FZVlIJCKvPbU4yn/UXsS0551CFKJhN0CaMw==} + '@babel/plugin-transform-property-literals@7.25.9': + resolution: {integrity: sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-display-name@7.24.6': - resolution: {integrity: sha512-/3iiEEHDsJuj9QU09gbyWGSUxDboFcD7Nj6dnHIlboWSodxXAoaY/zlNMHeYAC0WsERMqgO9a7UaM77CsYgWcg==} + '@babel/plugin-transform-react-display-name@7.25.9': + resolution: {integrity: sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-development@7.24.6': - resolution: {integrity: sha512-F7EsNp5StNDouSSdYyDSxh4J+xvj/JqG+Cb6s2fA+jCyHOzigG5vTwgH8tU2U8Voyiu5zCG9bAK49wTr/wPH0w==} + '@babel/plugin-transform-react-jsx-development@7.25.9': + resolution: {integrity: sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-self@7.24.6': - resolution: {integrity: sha512-FfZfHXtQ5jYPQsCRyLpOv2GeLIIJhs8aydpNh39vRDjhD411XcfWDni5i7OjP/Rs8GAtTn7sWFFELJSHqkIxYg==} + '@babel/plugin-transform-react-jsx-self@7.25.9': + resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-source@7.24.6': - resolution: {integrity: sha512-BQTBCXmFRreU3oTUXcGKuPOfXAGb1liNY4AvvFKsOBAJ89RKcTsIrSsnMYkj59fNa66OFKnSa4AJZfy5Y4B9WA==} + '@babel/plugin-transform-react-jsx-source@7.25.9': + resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx@7.24.6': - resolution: {integrity: sha512-pCtPHhpRZHfwdA5G1Gpk5mIzMA99hv0R8S/Ket50Rw+S+8hkt3wBWqdqHaPw0CuUYxdshUgsPiLQ5fAs4ASMhw==} + '@babel/plugin-transform-react-jsx@7.25.9': + resolution: {integrity: sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-pure-annotations@7.24.6': - resolution: {integrity: sha512-0HoDQlFJJkXRyV2N+xOpUETbKHcouSwijRQbKWVtxsPoq5bbB30qZag9/pSc5xcWVYjTHlLsBsY+hZDnzQTPNw==} + '@babel/plugin-transform-react-pure-annotations@7.25.9': + resolution: {integrity: sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.24.6': - resolution: {integrity: sha512-SMDxO95I8WXRtXhTAc8t/NFQUT7VYbIWwJCJgEli9ml4MhqUMh4S6hxgH6SmAC3eAQNWCDJFxcFeEt9w2sDdXg==} + '@babel/plugin-transform-regenerator@7.25.9': + resolution: {integrity: sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-reserved-words@7.24.6': - resolution: {integrity: sha512-DcrgFXRRlK64dGE0ZFBPD5egM2uM8mgfrvTMOSB2yKzOtjpGegVYkzh3s1zZg1bBck3nkXiaOamJUqK3Syk+4A==} + '@babel/plugin-transform-regexp-modifiers@7.26.0': + resolution: {integrity: sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-reserved-words@7.25.9': + resolution: {integrity: sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-runtime@7.24.6': - resolution: {integrity: sha512-W3gQydMb0SY99y/2lV0Okx2xg/8KzmZLQsLaiCmwNRl1kKomz14VurEm+2TossUb+sRvBCnGe+wx8KtIgDtBbQ==} + '@babel/plugin-transform-runtime@7.25.9': + resolution: {integrity: sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-shorthand-properties@7.24.6': - resolution: {integrity: sha512-xnEUvHSMr9eOWS5Al2YPfc32ten7CXdH7Zwyyk7IqITg4nX61oHj+GxpNvl+y5JHjfN3KXE2IV55wAWowBYMVw==} + '@babel/plugin-transform-shorthand-properties@7.25.9': + resolution: {integrity: sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-spread@7.24.6': - resolution: {integrity: sha512-h/2j7oIUDjS+ULsIrNZ6/TKG97FgmEk1PXryk/HQq6op4XUUUwif2f69fJrzK0wza2zjCS1xhXmouACaWV5uPA==} + '@babel/plugin-transform-spread@7.25.9': + resolution: {integrity: sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-sticky-regex@7.24.6': - resolution: {integrity: sha512-fN8OcTLfGmYv7FnDrsjodYBo1DhPL3Pze/9mIIE2MGCT1KgADYIOD7rEglpLHZj8PZlC/JFX5WcD+85FLAQusw==} + '@babel/plugin-transform-sticky-regex@7.25.9': + resolution: {integrity: sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-template-literals@7.24.6': - resolution: {integrity: sha512-BJbEqJIcKwrqUP+KfUIkxz3q8VzXe2R8Wv8TaNgO1cx+nNavxn/2+H8kp9tgFSOL6wYPPEgFvU6IKS4qoGqhmg==} + '@babel/plugin-transform-template-literals@7.25.9': + resolution: {integrity: sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typeof-symbol@7.24.6': - resolution: {integrity: sha512-IshCXQ+G9JIFJI7bUpxTE/oA2lgVLAIK8q1KdJNoPXOpvRaNjMySGuvLfBw/Xi2/1lLo953uE8hyYSDW3TSYig==} + '@babel/plugin-transform-typeof-symbol@7.25.9': + resolution: {integrity: sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.24.6': - resolution: {integrity: sha512-H0i+hDLmaYYSt6KU9cZE0gb3Cbssa/oxWis7PX4ofQzbvsfix9Lbh8SRk7LCPDlLWJHUiFeHU0qRRpF/4Zv7mQ==} + '@babel/plugin-transform-typescript@7.25.9': + resolution: {integrity: sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-escapes@7.24.6': - resolution: {integrity: sha512-bKl3xxcPbkQQo5eX9LjjDpU2xYHeEeNQbOhj0iPvetSzA+Tu9q/o5lujF4Sek60CM6MgYvOS/DJuwGbiEYAnLw==} + '@babel/plugin-transform-unicode-escapes@7.25.9': + resolution: {integrity: sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-property-regex@7.24.6': - resolution: {integrity: sha512-8EIgImzVUxy15cZiPii9GvLZwsy7Vxc+8meSlR3cXFmBIl5W5Tn9LGBf7CDKkHj4uVfNXCJB8RsVfnmY61iedA==} + '@babel/plugin-transform-unicode-property-regex@7.25.9': + resolution: {integrity: sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-regex@7.24.6': - resolution: {integrity: sha512-pssN6ExsvxaKU638qcWb81RrvvgZom3jDgU/r5xFZ7TONkZGFf4MhI2ltMb8OcQWhHyxgIavEU+hgqtbKOmsPA==} + '@babel/plugin-transform-unicode-regex@7.25.9': + resolution: {integrity: sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-sets-regex@7.24.6': - resolution: {integrity: sha512-quiMsb28oXWIDK0gXLALOJRXLgICLiulqdZGOaPPd0vRT7fQp74NtdADAVu+D8s00C+0Xs0MxVP0VKF/sZEUgw==} + '@babel/plugin-transform-unicode-sets-regex@7.25.9': + resolution: {integrity: sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.24.6': - resolution: {integrity: sha512-CrxEAvN7VxfjOG8JNF2Y/eMqMJbZPZ185amwGUBp8D9USK90xQmv7dLdFSa+VbD7fdIqcy/Mfv7WtzG8+/qxKg==} + '@babel/preset-env@7.26.0': + resolution: {integrity: sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/preset-flow@7.24.6': - resolution: {integrity: sha512-huoe0T1Qs9fQhMWbmqE/NHUeZbqmHDsN6n/jYvPcUUHfuKiPV32C9i8tDhMbQ1DEKTjbBP7Rjm3nSLwlB2X05g==} + '@babel/preset-flow@7.25.9': + resolution: {integrity: sha512-EASHsAhE+SSlEzJ4bzfusnXSHiU+JfAYzj+jbw2vgQKgq5HrUr8qs+vgtiEL5dOH6sEweI+PNt2D7AqrDSHyqQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1849,65 +1715,46 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - '@babel/preset-react@7.24.6': - resolution: {integrity: sha512-8mpzh1bWvmINmwM3xpz6ahu57mNaWavMm+wBNjQ4AFu1nghKBiIRET7l/Wmj4drXany/BBGjJZngICcD98F1iw==} + '@babel/preset-react@7.25.9': + resolution: {integrity: sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/preset-typescript@7.24.6': - resolution: {integrity: sha512-U10aHPDnokCFRXgyT/MaIRTivUu2K/mu0vJlwRS9LxJmJet+PFQNKpggPyFCUtC6zWSBPjvxjnpNkAn3Uw2m5w==} + '@babel/preset-typescript@7.26.0': + resolution: {integrity: sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/register@7.24.6': - resolution: {integrity: sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==} + '@babel/register@7.25.9': + resolution: {integrity: sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/regjsgen@0.8.0': - resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} - - '@babel/runtime@7.22.10': - resolution: {integrity: sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==} - engines: {node: '>=6.9.0'} - - '@babel/runtime@7.24.6': - resolution: {integrity: sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.22.5': - resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} + '@babel/runtime@7.26.0': + resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} engines: {node: '>=6.9.0'} - '@babel/template@7.24.6': - resolution: {integrity: sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==} + '@babel/template@7.25.9': + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.17.3': - resolution: {integrity: sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==} + '@babel/traverse@7.23.2': + resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.24.6': - resolution: {integrity: sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==} + '@babel/traverse@7.25.9': + resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} engines: {node: '>=6.9.0'} '@babel/types@7.17.0': resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} engines: {node: '>=6.9.0'} - '@babel/types@7.22.10': - resolution: {integrity: sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.23.6': - resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.24.6': - resolution: {integrity: sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==} + '@babel/types@7.26.0': + resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} engines: {node: '>=6.9.0'} '@balena/dockerignore@1.0.2': @@ -1917,44 +1764,42 @@ packages: resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} engines: {node: '>=16.13'} - '@cloudflare/workerd-darwin-64@1.20240712.0': - resolution: {integrity: sha512-KB1vbOhr62BCAwVr3VaRcngzPeSCQ7zPA9VGrfwYXIxo0Y4zlW1z0EVtcewFSz5XXKr3BtNnJXxdjDPUNkguQw==} + '@cloudflare/workerd-darwin-64@1.20241022.0': + resolution: {integrity: sha512-1NNYun37myMTgCUiPQEJ0cMal4mKZVTpkD0b2tx9hV70xji+frVJcSK8YVLeUm1P+Rw1d/ct8DMgQuCpsz3Fsw==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20240712.0': - resolution: {integrity: sha512-UDwFnCfQGFVCNxOeHxKNEc1ANQk/3OIiFWpVsxgZqJqU/22XM88JHxJW+YcBKsaUGUlpLyImaYUn2/rG+i+9UQ==} + '@cloudflare/workerd-darwin-arm64@1.20241022.0': + resolution: {integrity: sha512-FOO/0P0U82EsTLTdweNVgw+4VOk5nghExLPLSppdOziq6IR5HVgP44Kmq5LdsUeHUhwUmfOh9hzaTpkNzUqKvw==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20240712.0': - resolution: {integrity: sha512-MxpMHSJcZRUL66TO7BEnEim9WgZ8wJEVOB1Rq7a/IF2hI4/8f+N+02PChh62NkBlWxDfTXAtZy0tyQMm0EGjHg==} + '@cloudflare/workerd-linux-64@1.20241022.0': + resolution: {integrity: sha512-RsNc19BQJG9yd+ngnjuDeG9ywZG+7t1L4JeglgceyY5ViMNMKVO7Zpbsu69kXslU9h6xyQG+lrmclg3cBpnhYA==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20240712.0': - resolution: {integrity: sha512-DtLYZsFFFAMgn+6YCHoQS6nYY4nbdAtcAFa4PhWTjLJDbvQEn3IoK9Bi4ajCL7xG36FeuBdZliSbBiiv7CJjfQ==} + '@cloudflare/workerd-linux-arm64@1.20241022.0': + resolution: {integrity: sha512-x5mUXpKxfsosxcFmcq5DaqLs37PejHYVRsNz1cWI59ma7aC4y4Qn6Tf3i0r9MwQTF/MccP4SjVslMU6m4W7IaA==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20240712.0': - resolution: {integrity: sha512-u8zoT9PQiiwxuz9npquLBFWrC/RlBWGGZ1aylarZNFlM4sFrRm+bRr6i+KtS+fltHIVXj3teuoKYytA1ppf9Yw==} + '@cloudflare/workerd-windows-64@1.20241022.0': + resolution: {integrity: sha512-eBCClx4szCOgKqOlxxbdNszMqQf3MRG1B9BRIqEM/diDfdR9IrZ8l3FaEm+l9gXgPmS6m1NBn40aWuGBl8UTSw==} engines: {node: '>=16'} cpu: [x64] os: [win32] - '@cloudflare/workers-types@4.20240512.0': - resolution: {integrity: sha512-o2yTEWg+YK/I1t/Me+dA0oarO0aCbjibp6wSeaw52DSE9tDyKJ7S+Qdyw/XsMrKn4t8kF6f/YOba+9O4MJfW9w==} - - '@cloudflare/workers-types@4.20240524.0': - resolution: {integrity: sha512-GpSr4uE7y39DU9f0+wmrL76xd03wn0jy1ClITaa3ZZltKjirAV8TW1GzHrvvKyVGx6u3lekrFnB1HzVHsCYHDQ==} + '@cloudflare/workers-shared@0.7.0': + resolution: {integrity: sha512-LLQRTqx7lKC7o2eCYMpyc5FXV8d0pUX6r3A+agzhqS9aoR5A6zCPefwQGcvbKx83ozX22ATZcemwxQXn12UofQ==} + engines: {node: '>=16.7.0'} - '@cloudflare/workers-types@4.20241004.0': - resolution: {integrity: sha512-3LrPvtecs4umknOF1bTPNLHUG/ZjeSE6PYBQ/tbO7lwaVhjZTaTugiaCny2byrZupBlVNuubQVktcAgMfw0C1A==} + '@cloudflare/workers-types@4.20241106.0': + resolution: {integrity: sha512-pI4ivacmp+vgNO/siHDsZ6BdITR0LC4Mh/1+yzVLcl9U75pt5DUDCOWOiqIRFXRq6H65DPnJbEPFo3x9UfgofQ==} '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -2008,12 +1853,12 @@ packages: '@electric-sql/pglite@0.2.12': resolution: {integrity: sha512-J/X42ujcoFEbOkgRyoNqZB5qcqrnJRWVlwpH3fKYoJkTz49N91uAK/rDSSG/85WRas9nC9mdV4FnMTxnQWE/rw==} - '@esbuild-kit/core-utils@3.1.0': - resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} + '@esbuild-kit/core-utils@3.3.2': + resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.is' - '@esbuild-kit/esm-loader@2.5.5': - resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} + '@esbuild-kit/esm-loader@2.6.5': + resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-plugins/node-globals-polyfill@0.2.3': @@ -2032,20 +1877,20 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.20.2': - resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.23.0': - resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==} + '@esbuild/aix-ppc64@0.24.0': + resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -2068,20 +1913,20 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.20.2': - resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.23.0': - resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==} + '@esbuild/android-arm64@0.24.0': + resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -2104,20 +1949,20 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.20.2': - resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.23.0': - resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==} + '@esbuild/android-arm@0.24.0': + resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -2140,20 +1985,20 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.20.2': - resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.23.0': - resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==} + '@esbuild/android-x64@0.24.0': + resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -2176,20 +2021,20 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.20.2': - resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.23.0': - resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==} + '@esbuild/darwin-arm64@0.24.0': + resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -2212,20 +2057,20 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.20.2': - resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.23.0': - resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==} + '@esbuild/darwin-x64@0.24.0': + resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -2248,20 +2093,20 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.20.2': - resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.23.0': - resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==} + '@esbuild/freebsd-arm64@0.24.0': + resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -2284,20 +2129,20 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.20.2': - resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.23.0': - resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==} + '@esbuild/freebsd-x64@0.24.0': + resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -2320,20 +2165,20 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.20.2': - resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.23.0': - resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==} + '@esbuild/linux-arm64@0.24.0': + resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -2356,20 +2201,20 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.20.2': - resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.23.0': - resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==} + '@esbuild/linux-arm@0.24.0': + resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -2392,20 +2237,20 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.20.2': - resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.23.0': - resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==} + '@esbuild/linux-ia32@0.24.0': + resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -2434,20 +2279,20 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.20.2': - resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.23.0': - resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==} + '@esbuild/linux-loong64@0.24.0': + resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -2470,20 +2315,20 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.20.2': - resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.23.0': - resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==} + '@esbuild/linux-mips64el@0.24.0': + resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -2506,20 +2351,20 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.20.2': - resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.23.0': - resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==} + '@esbuild/linux-ppc64@0.24.0': + resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -2542,20 +2387,20 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.20.2': - resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.23.0': - resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==} + '@esbuild/linux-riscv64@0.24.0': + resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -2578,20 +2423,20 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.20.2': - resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.23.0': - resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==} + '@esbuild/linux-s390x@0.24.0': + resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -2614,20 +2459,20 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.20.2': - resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.23.0': - resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==} + '@esbuild/linux-x64@0.24.0': + resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -2650,26 +2495,32 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.20.2': - resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.23.0': - resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==} + '@esbuild/netbsd-x64@0.24.0': + resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.23.0': - resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==} + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.24.0': + resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -2692,20 +2543,20 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.20.2': - resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.23.0': - resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==} + '@esbuild/openbsd-x64@0.24.0': + resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -2728,20 +2579,20 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.20.2': - resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.23.0': - resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==} + '@esbuild/sunos-x64@0.24.0': + resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -2764,20 +2615,20 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.20.2': - resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.23.0': - resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==} + '@esbuild/win32-arm64@0.24.0': + resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -2800,20 +2651,20 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.20.2': - resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.23.0': - resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==} + '@esbuild/win32-ia32@0.24.0': + resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -2836,91 +2687,67 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.20.2': - resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.23.0': - resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==} + '@esbuild/win32-x64@0.24.0': + resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + '@eslint-community/eslint-utils@4.4.1': + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.11.0': - resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint-community/regexpp@4.9.0': - resolution: {integrity: sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ==} + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/eslintrc@2.1.2': - resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/eslintrc@2.1.3': - resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/eslintrc@2.1.4': resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/eslintrc@3.1.0': - resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@8.50.0': - resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/js@8.53.0': - resolution: {integrity: sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/js@8.57.0': - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} '@ewoudenberg/difflib@0.1.0': resolution: {integrity: sha512-OU5P5mJyD3OoWYMWY+yIgwvgNS9cFAU10f+DDuvtogcWQOoJIsQ4Hy2McSfUfhKjq8L0FuWVb4Rt7kgA+XK86A==} - '@expo/bunyan@4.0.0': - resolution: {integrity: sha512-Ydf4LidRB/EBI+YrB+cVLqIseiRfjUI/AeHBgjGMtq3GroraDu81OV7zqophRgupngoL3iS3JUMDMnxO7g39qA==} - engines: {'0': node >=0.10.0} + '@expo/bunyan@4.0.1': + resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} + engines: {node: '>=0.10.0'} - '@expo/cli@0.18.13': - resolution: {integrity: sha512-ZO1fpDK8z6mLeQGuFP6e3cZyCHV55ohZY7/tEyhpft3bwysS680eyFg5SFe+tWNFesnziFrbtI8JaUyhyjqovA==} + '@expo/cli@0.18.30': + resolution: {integrity: sha512-V90TUJh9Ly8stYo8nwqIqNWCsYjE28GlVFWEhAFCUOp99foiQr8HSTpiiX5GIrprcPoWmlGoY+J5fQA29R4lFg==} hasBin: true '@expo/code-signing-certificates@0.0.5': resolution: {integrity: sha512-BNhXkY1bblxKZpltzAx98G2Egj9g1Q+JRcvR7E99DOj862FTCX+ZPsAUtPTr7aHxwtrL7+fL3r0JSmM9kBm+Bw==} - '@expo/config-plugins@8.0.4': - resolution: {integrity: sha512-Hi+xuyNWE2LT4LVbGttHJgl9brnsdWAhEB42gWKb5+8ae86Nr/KwUBQJsJppirBYTeLjj5ZlY0glYnAkDa2jqw==} + '@expo/config-plugins@8.0.10': + resolution: {integrity: sha512-KG1fnSKRmsudPU9BWkl59PyE0byrE2HTnqbOrgwr2FAhqh7tfr9nRs6A9oLS/ntpGzmFxccTEcsV0L4apsuxxg==} - '@expo/config-types@51.0.0': - resolution: {integrity: sha512-acn03/u8mQvBhdTQtA7CNhevMltUhbSrpI01FYBJwpVntufkU++ncQujWKlgY/OwIajcfygk1AY4xcNZ5ImkRA==} + '@expo/config-types@51.0.3': + resolution: {integrity: sha512-hMfuq++b8VySb+m9uNNrlpbvGxYc8OcFCUX9yTmi9tlx6A4k8SDabWFBgmnr4ao3wEArvWrtUQIfQCVtPRdpKA==} - '@expo/config@9.0.2': - resolution: {integrity: sha512-BKQ4/qBf3OLT8hHp5kjObk2vxwoRQ1yYQBbG/OM9Jdz32yYtrU8opTbKRAxfZEWH5i3ZHdLrPdC1rO0I6WxtTw==} + '@expo/config@9.0.4': + resolution: {integrity: sha512-g5ns5u1JSKudHYhjo1zaSfkJ/iZIcWmUmIQptMJZ6ag1C0ShL2sj8qdfU8MmAMuKLOgcIfSaiWlQnm4X3VJVkg==} - '@expo/devcert@1.1.2': - resolution: {integrity: sha512-FyWghLu7rUaZEZSTLt/XNRukm0c9GFfwP0iFaswoDWpV6alvVg+zRAfCLdIVQEz1SVcQ3zo1hMZFDrnKGvkCuQ==} + '@expo/devcert@1.1.4': + resolution: {integrity: sha512-fqBODr8c72+gBSX5Ty3SIzaY4bXainlpab78+vEYEKL3fXmsOswMLf0+KE36mUEAa36BYabX7K3EiXOXX5OPMw==} '@expo/env@0.3.0': resolution: {integrity: sha512-OtB9XVHWaXidLbHvrVDeeXa09yvTl3+IQN884sO6PhIi2/StXfgSH/9zC7IvzrDB8kW3EBJ1PPLuCUJ2hxAT7Q==} @@ -2931,11 +2758,11 @@ packages: '@expo/json-file@8.3.3': resolution: {integrity: sha512-eZ5dld9AD0PrVRiIWpRkm5aIoWBw3kAyd8VkuWEy92sEthBKDDDHAnK2a0dw0Eil6j7rK7lS/Qaq/Zzngv2h5A==} - '@expo/metro-config@0.18.4': - resolution: {integrity: sha512-vh9WDf/SzE+NYCn6gqbzLKiXtENFlFZdAqyj9nI38RvQ4jw6TJIQ8+ExcdLDT3MOG36Ytg44XX9Zb3OWF6LVxw==} + '@expo/metro-config@0.18.11': + resolution: {integrity: sha512-/uOq55VbSf9yMbUO1BudkUM2SsGW1c5hr9BnhIqYqcsFv0Jp5D3DtJ4rljDKaUeNLbwr6m7pqIrkSMq5NrYf4Q==} - '@expo/osascript@2.1.2': - resolution: {integrity: sha512-/ugqDG+52uzUiEpggS9GPdp9g0U9EQrXcTdluHDmnlGmR2nV/F83L7c+HCUyPnf77QXwkr8gQk16vQTbxBQ5eA==} + '@expo/osascript@2.1.3': + resolution: {integrity: sha512-aOEkhPzDsaAfolSswObGiYW0Pf0ROfR9J2NBRLQACdQ6uJlyAMiPF45DVEVknAU9juKh0y8ZyvC9LXqLEJYohA==} engines: {node: '>=12'} '@expo/package-manager@1.5.2': @@ -2944,8 +2771,8 @@ packages: '@expo/plist@0.1.3': resolution: {integrity: sha512-GW/7hVlAylYg1tUrEASclw1MMk9FP4ZwyFAY/SUTJIhPDQHtfOlXREyWV3hhrHdX/K+pS73GNgdfT6E/e+kBbg==} - '@expo/prebuild-config@7.0.4': - resolution: {integrity: sha512-E2n3QbwgV8Qa0CBw7BHrWBDWD7l8yw+N/yjvXpSPFFtoZLMSKyegdkJFACh2u+UIRKUSZm8zQwHeZR0rqAxV9g==} + '@expo/prebuild-config@7.0.9': + resolution: {integrity: sha512-9i6Cg7jInpnGEHN0jxnW0P+0BexnePiBzmbUvzSbRXpdXihYUX2AKMu73jgzxn5P1hXOSkzNS7umaY+BZ+aBag==} peerDependencies: expo-modules-autolinking: '>=0.8.1' @@ -2960,8 +2787,8 @@ packages: resolution: {integrity: sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==} engines: {node: '>=12'} - '@expo/vector-icons@14.0.2': - resolution: {integrity: sha512-70LpmXQu4xa8cMxjp1fydgRPsalefnHaXLzIwaHMEzcZhnyjw2acZz8azRrZOslPVAWlxItOa2Dd7WtD/kI+CA==} + '@expo/vector-icons@14.0.4': + resolution: {integrity: sha512-+yKshcbpDfbV4zoXOgHxCwh7lkE9VVTT5T03OUlBsqfze1PLy6Hi4jp1vSb1GVbY6eskvMIivGVc9SKzIv0oEQ==} '@expo/websql@1.0.1': resolution: {integrity: sha512-H9/t1V7XXyKC343FJz/LwaVBfDhs6IqhDtSYWpt8LNSQDVjf5NvVJLc5wp+KCpRidZx8+0+YeHJN45HOXmqjFA==} @@ -2982,15 +2809,11 @@ packages: peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@hapi/hoek@9.3.0': - resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} - - '@hapi/topo@5.1.0': - resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} - - '@hono/node-server@1.12.0': - resolution: {integrity: sha512-e6oHjNiErRxsZRZBmc2KucuvY3btlO/XPncIpP2X75bRdTilF9GLjm3NHvKKunpJbbJJj31/FoPTksTf8djAVw==} + '@hono/node-server@1.13.5': + resolution: {integrity: sha512-lSo+CFlLqAFB4fX7ePqI9nauEn64wOfJHAfc9duYFTvAG3o416pC0nTGeNjuLHchLedH+XyWda5v79CVx1PIjg==} engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 '@hono/zod-validator@0.2.2': resolution: {integrity: sha512-dSDxaPV70Py8wuIU2QNpoVEIOSzSXZ/6/B/h4xA7eOMz7+AarKTSGV8E6QwrdcCbBLkpqfJ4Q2TmBO0eP1tCBQ==} @@ -2998,18 +2821,8 @@ packages: hono: '>=3.9.0' zod: ^3.19.1 - '@humanwhocodes/config-array@0.11.11': - resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - - '@humanwhocodes/config-array@0.11.13': - resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - - '@humanwhocodes/config-array@0.11.14': - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} deprecated: Use @eslint/config-array instead @@ -3017,14 +2830,6 @@ packages: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/object-schema@1.2.1': - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - deprecated: Use @eslint/object-schema instead - - '@humanwhocodes/object-schema@2.0.1': - resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} - deprecated: Use @eslint/object-schema instead - '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead @@ -3040,6 +2845,14 @@ packages: resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} engines: {node: '>=12'} + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + '@jest/create-cache-key-function@29.7.0': resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3056,56 +2869,36 @@ packages: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/types@26.6.2': - resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} - engines: {node: '>= 10.14.2'} + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@24.9.0': + resolution: {integrity: sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==} + engines: {node: '>= 6'} '@jest/types@29.6.3': resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jridgewell/gen-mapping@0.3.3': - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} - engines: {node: '>=6.0.0'} - '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} - '@jridgewell/resolve-uri@3.1.0': - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} - engines: {node: '>=6.0.0'} - '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/set-array@1.1.2': - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - '@jridgewell/set-array@1.2.1': resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.3': - resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==} - '@jridgewell/source-map@0.3.6': resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} - '@jridgewell/sourcemap-codec@1.4.14': - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - - '@jridgewell/sourcemap-codec@1.4.15': - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/trace-mapping@0.3.18': - resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} - '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} @@ -3123,23 +2916,13 @@ packages: '@libsql/core@0.10.0': resolution: {integrity: sha512-rqynAXGaiSpTsykOZdBtI1N4z4O+KZ6mt33K/aHeXAY0gSIfK/ctxuWa0Y1Bjo4FMz1idBTCXz4Ps5kITOvZZw==} - '@libsql/darwin-arm64@0.3.19': - resolution: {integrity: sha512-rmOqsLcDI65zzxlUOoEiPJLhqmbFsZF6p4UJQ2kMqB+Kc0Rt5/A1OAdOZ/Wo8fQfJWjR1IbkbpEINFioyKf+nQ==} + '@libsql/darwin-arm64@0.4.7': + resolution: {integrity: sha512-yOL742IfWUlUevnI5PdnIT4fryY3LYTdLm56bnY0wXBw7dhFcnjuA7jrH3oSVz2mjZTHujxoITgAE7V6Z+eAbg==} cpu: [arm64] os: [darwin] - '@libsql/darwin-arm64@0.4.1': - resolution: {integrity: sha512-XICT9/OyU8Aa9Iv1xZIHgvM09n/1OQUk3VC+s5uavzdiGHrDMkOWzN47JN7/FiMa/NWrcgoEiDMk3+e7mE53Ig==} - cpu: [arm64] - os: [darwin] - - '@libsql/darwin-x64@0.3.19': - resolution: {integrity: sha512-q9O55B646zU+644SMmOQL3FIfpmEvdWpRpzubwFc2trsa+zoBlSkHuzU9v/C+UNoPHQVRMP7KQctJ455I/h/xw==} - cpu: [x64] - os: [darwin] - - '@libsql/darwin-x64@0.4.1': - resolution: {integrity: sha512-pSKxhRrhu4SsTD+IBRZXcs1SkwMdeAG1tv6Z/Ctp/sOEYrgkU8MDKLqkOr9NsmwpK4S0+JdwjkLMyhTkct/5TQ==} + '@libsql/darwin-x64@0.4.7': + resolution: {integrity: sha512-ezc7V75+eoyyH07BO9tIyJdqXXcRfZMbKcLCeF8+qWK5nP8wWuMcfOVywecsXGRbT99zc5eNra4NEx6z5PkSsA==} cpu: [x64] os: [darwin] @@ -3153,53 +2936,28 @@ packages: '@libsql/isomorphic-ws@0.1.5': resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} - '@libsql/linux-arm64-gnu@0.3.19': - resolution: {integrity: sha512-mgeAUU1oqqh57k7I3cQyU6Trpdsdt607eFyEmH5QO7dv303ti+LjUvh1pp21QWV6WX7wZyjeJV1/VzEImB+jRg==} - cpu: [arm64] - os: [linux] - - '@libsql/linux-arm64-gnu@0.4.1': - resolution: {integrity: sha512-9lpvb24tO2qZd9nq5dlq3ESA3hSKYWBIK7lJjfiCM6f7a70AUwBY9QoPJV9q4gILIyVnR1YBGrlm50nnb+dYgw==} - cpu: [arm64] - os: [linux] - - '@libsql/linux-arm64-musl@0.3.19': - resolution: {integrity: sha512-VEZtxghyK6zwGzU9PHohvNxthruSxBEnRrX7BSL5jQ62tN4n2JNepJ6SdzXp70pdzTfwroOj/eMwiPt94gkVRg==} + '@libsql/linux-arm64-gnu@0.4.7': + resolution: {integrity: sha512-WlX2VYB5diM4kFfNaYcyhw5y+UJAI3xcMkEUJZPtRDEIu85SsSFrQ+gvoKfcVh76B//ztSeEX2wl9yrjF7BBCA==} cpu: [arm64] os: [linux] - '@libsql/linux-arm64-musl@0.4.1': - resolution: {integrity: sha512-lyxi+lFxE+NcBRDMQCxCtDg3c4WcKAbc9u63d5+B23Vm+UgphD9XY4seu+tGrBy1MU2tuNVix7r9S7ECpAaVrA==} + '@libsql/linux-arm64-musl@0.4.7': + resolution: {integrity: sha512-6kK9xAArVRlTCpWeqnNMCoXW1pe7WITI378n4NpvU5EJ0Ok3aNTIC2nRPRjhro90QcnmLL1jPcrVwO4WD1U0xw==} cpu: [arm64] os: [linux] - '@libsql/linux-x64-gnu@0.3.19': - resolution: {integrity: sha512-2t/J7LD5w2f63wGihEO+0GxfTyYIyLGEvTFEsMO16XI5o7IS9vcSHrxsvAJs4w2Pf907uDjmc7fUfMg6L82BrQ==} + '@libsql/linux-x64-gnu@0.4.7': + resolution: {integrity: sha512-CMnNRCmlWQqqzlTw6NeaZXzLWI8bydaXDke63JTUCvu8R+fj/ENsLrVBtPDlxQ0wGsYdXGlrUCH8Qi9gJep0yQ==} cpu: [x64] os: [linux] - '@libsql/linux-x64-gnu@0.4.1': - resolution: {integrity: sha512-psvuQ3UFBEmDFV8ZHG+WkUHIJiWv+elZ+zIPvOVedlIKdxG1O+8WthWUAhFHOGnbiyzc4sAZ4c3de1oCvyHxyQ==} + '@libsql/linux-x64-musl@0.4.7': + resolution: {integrity: sha512-nI6tpS1t6WzGAt1Kx1n1HsvtBbZ+jHn0m7ogNNT6pQHZQj7AFFTIMeDQw/i/Nt5H38np1GVRNsFe99eSIMs9XA==} cpu: [x64] os: [linux] - '@libsql/linux-x64-musl@0.3.19': - resolution: {integrity: sha512-BLsXyJaL8gZD8+3W2LU08lDEd9MIgGds0yPy5iNPp8tfhXx3pV/Fge2GErN0FC+nzt4DYQtjL+A9GUMglQefXQ==} - cpu: [x64] - os: [linux] - - '@libsql/linux-x64-musl@0.4.1': - resolution: {integrity: sha512-PDidJ3AhGDqosGg3OAZzGxMFIbnuOALya4BoezJKl667AFv3x7BBQ30H81Mngsq3Fh8RkJkXSdWfL91+Txb1iA==} - cpu: [x64] - os: [linux] - - '@libsql/win32-x64-msvc@0.3.19': - resolution: {integrity: sha512-ay1X9AobE4BpzG0XPw1gplyLZPGHIgJOovvW23gUrukRegiUP62uzhpRbKNogLlUOynyXeq//prHgPXiebUfWg==} - cpu: [x64] - os: [win32] - - '@libsql/win32-x64-msvc@0.4.1': - resolution: {integrity: sha512-IdODVqV/PrdOnHA/004uWyorZQuRsB7U7bCRCE3vXgABj3eJLJGc6cv2C6ksEaEoVxJbD8k53H4VVAGrtYwXzQ==} + '@libsql/win32-x64-msvc@0.4.7': + resolution: {integrity: sha512-7pJzOWzPm6oJUxml+PCDRzYQ4A1hTMHAciTAHfFK4fkbDZX33nWPVG7Y3vqdKtslcwAzwmrNDc6sXy2nwWnbiw==} cpu: [x64] os: [win32] @@ -3229,15 +2987,12 @@ packages: '@neondatabase/serverless@0.7.2': resolution: {integrity: sha512-wU3WA2uTyNO7wjPs3Mg0G01jztAxUxzd9/mskMmtPwPTjf7JKWi9AW5/puOGXLxmZ9PVgRFeBVRVYq5nBPhsCg==} - '@neondatabase/serverless@0.9.0': - resolution: {integrity: sha512-mmJnUAzlzvxNSZuuhI6kgJjH+JgFdBMYUWxihtq/nj0Tjt+Y5UU3W+SvRFoucnd5NObYkuLYQzk+zV5DGFKGJg==} - - '@neondatabase/serverless@0.9.3': - resolution: {integrity: sha512-6ZBK8asl2Z3+ADEaELvbaVVGVlmY1oAzkxxZfpmXPKFuJhbDN+5fU3zYBamsahS/Ch1zE+CVWB3R+8QEI2LMSw==} + '@neondatabase/serverless@0.9.5': + resolution: {integrity: sha512-siFas6gItqv6wD/pZnvdu34wEqgG3nSE6zWZdq5j2DEsa+VvX8i/5HXJOo06qrw5axPXn+lGCxeR+NLaSPIXug==} - '@noble/hashes@1.4.0': - resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} - engines: {node: '>= 16'} + '@noble/hashes@1.5.0': + resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==} + engines: {node: ^14.21.3 || >=16} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -3269,8 +3024,8 @@ packages: react: '*' react-native: '*' - '@opentelemetry/api@1.8.0': - resolution: {integrity: sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==} + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} '@originjs/vite-plugin-commonjs@1.0.3': @@ -3287,12 +3042,12 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@planetscale/database@1.18.0': - resolution: {integrity: sha512-t2XdOfrVgcF7AW791FtdPS27NyNqcE1SpoXgk3HpziousvUMsJi4Q6NL3JyOBpsMOrvk94749o8yyonvX5quPw==} + '@planetscale/database@1.19.0': + resolution: {integrity: sha512-Tv4jcFUFAFjOWrGSio49H6R2ijALv0ZzVBfJKIdm+kl9X046Fh4LLawrF9OMsglVbK6ukqMJsUCeucGAFTBcMA==} engines: {node: '>=16'} - '@polka/url@1.0.0-next.25': - resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} + '@polka/url@1.0.0-next.28': + resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} '@prisma/client@5.14.0': resolution: {integrity: sha512-akMSuyvLKeoU4LeyBAUdThP/uhVP3GuLygFE3MlYzaCb3/J8SfsYBE5PkaFuLuVpLyA6sFoW+16z/aPhNAESqg==} @@ -3306,8 +3061,8 @@ packages: '@prisma/debug@5.14.0': resolution: {integrity: sha512-iq56qBZuFfX3fCxoxT8gBX33lQzomBU0qIUaEj1RebsKVz1ob/BVH1XSBwwwvRVtZEV1b7Fxx2eVu34Ge/mg3w==} - '@prisma/debug@5.16.1': - resolution: {integrity: sha512-JsNgZAg6BD9RInLSrg7ZYzo11N7cVvYArq3fHGSD89HSgtN0VDdjV6bib7YddbcO6snzjchTiLfjeTqBjtArVQ==} + '@prisma/debug@5.22.0': + resolution: {integrity: sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==} '@prisma/engines-version@5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48': resolution: {integrity: sha512-ip6pNkRo1UxWv+6toxNcYvItNYaqQjXdFNGJ+Nuk2eYtRoEdoF13wxo7/jsClJFFenMPVNVqXQDV0oveXnR1cA==} @@ -3318,101 +3073,95 @@ packages: '@prisma/fetch-engine@5.14.0': resolution: {integrity: sha512-VrheA9y9DMURK5vu8OJoOgQpxOhas3qF0IBHJ8G/0X44k82kc8E0w98HCn2nhnbOOMwbWsJWXfLC2/F8n5u0gQ==} - '@prisma/generator-helper@5.16.1': - resolution: {integrity: sha512-WxV/msovIubvr20iIdPJN0MUj46J26ax+sV+vMQSCeVoHQW//xdJZoPnimG54M7+CA9kupXjVpgjiPX4rcKQeA==} + '@prisma/generator-helper@5.22.0': + resolution: {integrity: sha512-LwqcBQ5/QsuAaLNQZAIVIAJDJBMjHwMwn16e06IYx/3Okj/xEEfw9IvrqB2cJCl3b2mCBlh3eVH0w9WGmi4aHg==} '@prisma/get-platform@5.14.0': resolution: {integrity: sha512-/yAyBvcEjRv41ynZrhdrPtHgk47xLRRq/o5eWGcUpBJ1YrUZTYB8EoPiopnP7iQrMATK8stXQdPOoVlrzuTQZw==} - '@react-native-community/cli-clean@13.6.6': - resolution: {integrity: sha512-cBwJTwl0NyeA4nyMxbhkWZhxtILYkbU3TW3k8AXLg+iGphe0zikYMGB3T+haTvTc6alTyEFwPbimk9bGIqkjAQ==} - - '@react-native-community/cli-config@13.6.6': - resolution: {integrity: sha512-mbG425zCKr8JZhv/j11382arezwS/70juWMsn8j2lmrGTrP1cUdW0MF15CCIFtJsqyK3Qs+FTmqttRpq81QfSg==} - - '@react-native-community/cli-debugger-ui@13.6.6': - resolution: {integrity: sha512-Vv9u6eS4vKSDAvdhA0OiQHoA7y39fiPIgJ6biT32tN4avHDtxlc6TWZGiqv7g98SBvDWvoVAmdPLcRf3kU+c8g==} - - '@react-native-community/cli-doctor@13.6.6': - resolution: {integrity: sha512-TWZb5g6EmQe2Ua2TEWNmyaEayvlWH4GmdD9ZC+p8EpKFpB1NpDGMK6sXbpb42TDvwZg5s4TDRplK0PBEA/SVDg==} - - '@react-native-community/cli-hermes@13.6.6': - resolution: {integrity: sha512-La5Ie+NGaRl3klei6WxKoOxmCUSGGxpOk6vU5pEGf0/O7ky+Ay0io+zXYUZqlNMi/cGpO7ZUijakBYOB/uyuFg==} - - '@react-native-community/cli-platform-android@13.6.6': - resolution: {integrity: sha512-/tMwkBeNxh84syiSwNlYtmUz/Ppc+HfKtdopL/5RB+fd3SV1/5/NPNjMlyLNgFKnpxvKCInQ7dnl6jGHJjeHjg==} - - '@react-native-community/cli-platform-apple@13.6.6': - resolution: {integrity: sha512-bOmSSwoqNNT3AmCRZXEMYKz1Jf1l2F86Nhs7qBcXdY/sGiJ+Flng564LOqvdAlVLTbkgz47KjNKCS2pP4Jg0Mg==} - - '@react-native-community/cli-platform-ios@13.6.6': - resolution: {integrity: sha512-vjDnRwhlSN5ryqKTas6/DPkxuouuyFBAqAROH4FR1cspTbn6v78JTZKDmtQy9JMMo7N5vZj1kASU5vbFep9IOQ==} - - '@react-native-community/cli-server-api@13.6.6': - resolution: {integrity: sha512-ZtCXxoFlM7oDv3iZ3wsrT3SamhtUJuIkX2WePLPlN5bcbq7zimbPm2lHyicNJtpcGQ5ymsgpUWPCNZsWQhXBqQ==} - - '@react-native-community/cli-tools@13.6.6': - resolution: {integrity: sha512-ptOnn4AJczY5njvbdK91k4hcYazDnGtEPrqIwEI+k/CTBHNdb27Rsm2OZ7ye6f7otLBqF8gj/hK6QzJs8CEMgw==} - - '@react-native-community/cli-types@13.6.6': - resolution: {integrity: sha512-733iaYzlmvNK7XYbnWlMjdE+2k0hlTBJW071af/xb6Bs+hbJqBP9c03FZuYH2hFFwDDntwj05bkri/P7VgSxug==} + '@react-native/assets-registry@0.76.1': + resolution: {integrity: sha512-1mcDjyvC4Z+XYtY+Abl6pW9P49l/9HJmRChX7EHF1SoXe7zPAPBoAqeZsJNtf8dhJR3u/eGvapr1yJq8T/psEg==} + engines: {node: '>=18'} - '@react-native-community/cli@13.6.6': - resolution: {integrity: sha512-IqclB7VQ84ye8Fcs89HOpOscY4284VZg2pojHNl8H0Lzd4DadXJWQoxC7zWm8v2f8eyeX2kdhxp2ETD5tceIgA==} + '@react-native/babel-plugin-codegen@0.74.87': + resolution: {integrity: sha512-+vJYpMnENFrwtgvDfUj+CtVJRJuUnzAUYT0/Pb68Sq9RfcZ5xdcCuUgyf7JO+akW2VTBoJY427wkcxU30qrWWw==} engines: {node: '>=18'} - hasBin: true - '@react-native/assets-registry@0.74.83': - resolution: {integrity: sha512-2vkLMVnp+YTZYTNSDIBZojSsjz8sl5PscP3j4GcV6idD8V978SZfwFlk8K0ti0BzRs11mzL0Pj17km597S/eTQ==} + '@react-native/babel-plugin-codegen@0.76.1': + resolution: {integrity: sha512-V9bGLyEdAF39nvn4L5gaJcPX1SvCHPJhaT3qfpVGvCnl7WPhdRyCq++WsN8HXlpo6WOAf6//oruLnLdl3RNM4Q==} engines: {node: '>=18'} - '@react-native/babel-plugin-codegen@0.74.83': - resolution: {integrity: sha512-+S0st3t4Ro00bi9gjT1jnK8qTFOU+CwmziA7U9odKyWrCoRJrgmrvogq/Dr1YXlpFxexiGIupGut1VHxr+fxJA==} + '@react-native/babel-preset@0.74.87': + resolution: {integrity: sha512-hyKpfqzN2nxZmYYJ0tQIHG99FQO0OWXp/gVggAfEUgiT+yNKas1C60LuofUsK7cd+2o9jrpqgqW4WzEDZoBlTg==} engines: {node: '>=18'} + peerDependencies: + '@babel/core': '*' - '@react-native/babel-preset@0.74.83': - resolution: {integrity: sha512-KJuu3XyVh3qgyUer+rEqh9a/JoUxsDOzkJNfRpDyXiAyjDRoVch60X/Xa/NcEQ93iCVHAWs0yQ+XGNGIBCYE6g==} + '@react-native/babel-preset@0.76.1': + resolution: {integrity: sha512-b6YRmA13CmVuTQKHRen/Q0glHwmZFZoEDs+MJ1NL0UNHq9V5ytvdwTW1ntkmjtXuTnPMzkwYvumJBN9UTZjkBA==} engines: {node: '>=18'} peerDependencies: '@babel/core': '*' - '@react-native/codegen@0.74.83': - resolution: {integrity: sha512-GgvgHS3Aa2J8/mp1uC/zU8HuTh8ZT5jz7a4mVMWPw7+rGyv70Ba8uOVBq6UH2Q08o617IATYc+0HfyzAfm4n0w==} + '@react-native/codegen@0.74.87': + resolution: {integrity: sha512-GMSYDiD+86zLKgMMgz9z0k6FxmRn+z6cimYZKkucW4soGbxWsbjUAZoZ56sJwt2FJ3XVRgXCrnOCgXoH/Bkhcg==} + engines: {node: '>=18'} + peerDependencies: + '@babel/preset-env': ^7.1.6 + + '@react-native/codegen@0.76.1': + resolution: {integrity: sha512-7lE0hk2qq27wVeK5eF654v7XsKoRa7ficrfSwIDEDZ1aLB2xgUzLrsq+glSAP9EuzT6ycHhtD3QyqI+TqnlS/A==} engines: {node: '>=18'} peerDependencies: '@babel/preset-env': ^7.1.6 - '@react-native/community-cli-plugin@0.74.83': - resolution: {integrity: sha512-7GAFjFOg1mFSj8bnFNQS4u8u7+QtrEeflUIDVZGEfBZQ3wMNI5ycBzbBGycsZYiq00Xvoc6eKFC7kvIaqeJpUQ==} + '@react-native/community-cli-plugin@0.76.1': + resolution: {integrity: sha512-dECc1LuleMQDX/WK2oJInrYCpHb3OFBJxYkhPOAXb9HiktMWRA9T93qqpTDshmtLdYqvxeO9AM5eeoSL412WnQ==} + engines: {node: '>=18'} + peerDependencies: + '@react-native-community/cli-server-api': '*' + peerDependenciesMeta: + '@react-native-community/cli-server-api': + optional: true + + '@react-native/debugger-frontend@0.74.85': + resolution: {integrity: sha512-gUIhhpsYLUTYWlWw4vGztyHaX/kNlgVspSvKe2XaPA7o3jYKUoNLc3Ov7u70u/MBWfKdcEffWq44eSe3j3s5JQ==} + engines: {node: '>=18'} + + '@react-native/debugger-frontend@0.76.1': + resolution: {integrity: sha512-0gExx7GR8o2ctGfjIZ9+x54iFbg0eP6+kMYzRA6AcgmFAmMGLADMmjtObCN0CqGeZyWtdVVqcv5mAwRwmMlNWA==} engines: {node: '>=18'} - '@react-native/debugger-frontend@0.74.83': - resolution: {integrity: sha512-RGQlVUegBRxAUF9c1ss1ssaHZh6CO+7awgtI9sDeU0PzDZY/40ImoPD5m0o0SI6nXoVzbPtcMGzU+VO590pRfA==} + '@react-native/dev-middleware@0.74.85': + resolution: {integrity: sha512-BRmgCK5vnMmHaKRO+h8PKJmHHH3E6JFuerrcfE3wG2eZ1bcSr+QTu8DAlpxsDWvJvHpCi8tRJGauxd+Ssj/c7w==} engines: {node: '>=18'} - '@react-native/dev-middleware@0.74.83': - resolution: {integrity: sha512-UH8iriqnf7N4Hpi20D7M2FdvSANwTVStwFCSD7VMU9agJX88Yk0D1T6Meh2RMhUu4kY2bv8sTkNRm7LmxvZqgA==} + '@react-native/dev-middleware@0.76.1': + resolution: {integrity: sha512-htaFSN2dwI0CinsMxjRuvIVdSDN6d6TDPeOJczM1bdAYalZX1M58knTKs5LJDComW5tleOCAg5lS5tIeFlM9+Q==} engines: {node: '>=18'} - '@react-native/gradle-plugin@0.74.83': - resolution: {integrity: sha512-Pw2BWVyOHoBuJVKxGVYF6/GSZRf6+v1Ygc+ULGz5t20N8qzRWPa2fRZWqoxsN7TkNLPsECYY8gooOl7okOcPAQ==} + '@react-native/gradle-plugin@0.76.1': + resolution: {integrity: sha512-X7rNFltPa9QYxvYrQGaSCw7U57C+y+DwspXf4AnLZj0bQm9tL6UYpijh5vE3VmPcHn76/RNU2bpFjVvWg6gjqw==} engines: {node: '>=18'} - '@react-native/js-polyfills@0.74.83': - resolution: {integrity: sha512-/t74n8r6wFhw4JEoOj3bN71N1NDLqaawB75uKAsSjeCwIR9AfCxlzZG0etsXtOexkY9KMeZIQ7YwRPqUdNXuqw==} + '@react-native/js-polyfills@0.76.1': + resolution: {integrity: sha512-HO3fzJ0FnrnQGmxdXxh2lcGGAMfaX9h1Pg1Zh38MkVw35/KnZHxHqxg6cruze6iWwZdfqSoIcQoalmMuAHby7Q==} engines: {node: '>=18'} - '@react-native/metro-babel-transformer@0.74.83': - resolution: {integrity: sha512-hGdx5N8diu8y+GW/ED39vTZa9Jx1di2ZZ0aapbhH4egN1agIAusj5jXTccfNBwwWF93aJ5oVbRzfteZgjbutKg==} + '@react-native/metro-babel-transformer@0.76.1': + resolution: {integrity: sha512-LUAKqgsrioXS2a+pE0jak8sutTbLo3T34KWv7mdVUZ5lUACpqkIql1EFtIQlWjIcR4oZE480CkPbRHBI681tkQ==} engines: {node: '>=18'} peerDependencies: '@babel/core': '*' - '@react-native/normalize-colors@0.74.83': - resolution: {integrity: sha512-jhCY95gRDE44qYawWVvhTjTplW1g+JtKTKM3f8xYT1dJtJ8QWv+gqEtKcfmOHfDkSDaMKG0AGBaDTSK8GXLH8Q==} + '@react-native/normalize-colors@0.74.85': + resolution: {integrity: sha512-pcE4i0X7y3hsAE0SpIl7t6dUc0B0NZLd1yv7ssm4FrLhWG+CGyIq4eFDXpmPU1XHmL5PPySxTAjEMiwv6tAmOw==} - '@react-native/virtualized-lists@0.74.83': - resolution: {integrity: sha512-rmaLeE34rj7py4FxTod7iMTC7BAsm+HrGA8WxYmEJeyTV7WSaxAkosKoYBz8038mOiwnG9VwA/7FrB6bEQvn1A==} + '@react-native/normalize-colors@0.76.1': + resolution: {integrity: sha512-/+CUk/wGWIdXbJYVLw/q6Fs8Z0x91zzfXIbNiZUdSW1TNEDmytkF371H8a1/Nx3nWa1RqCMVsaZHCG4zqxeDvg==} + + '@react-native/virtualized-lists@0.76.1': + resolution: {integrity: sha512-uWJfv0FC3zmlYORr0Sa17ngbAaw6K9yw4MAkBZyFeTM+W6AJRvTVyR1Mes/MU+vIyGFChnTcyaQrQz8jWqADOA==} engines: {node: '>=18'} peerDependencies: '@types/react': ^18.2.6 @@ -3426,33 +3175,20 @@ packages: resolution: {integrity: sha512-lzD84av1ZQhYUS+jsGqJiCMaJO2dn9u+RTT9n9q6D3SaKVwWqv+7AoRKqBu19bkwyE+iFRl1ymr40QS90jVFYg==} engines: {node: '>=14.15'} - '@rollup/plugin-terser@0.4.1': - resolution: {integrity: sha512-aKS32sw5a7hy+fEXVy+5T95aDIwjpGHCTv833HXVtyKMDoVS7pBr5K3L9hEQoNqbJFjfANPrNpIXlTQ7is00eA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.x || ^3.x - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-typescript@11.1.0': - resolution: {integrity: sha512-86flrfE+bSHB69znnTV6kVjkncs2LBMhcTCyxWgRxLyfXfQrxg4UwlAqENnjrrxnSNS/XKCDJCl8EkdFJVHOxw==} + '@rollup/plugin-terser@0.4.4': + resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^2.14.0||^3.0.0 - tslib: '*' - typescript: '>=3.7.0' + rollup: ^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - tslib: - optional: true - '@rollup/plugin-typescript@11.1.1': - resolution: {integrity: sha512-Ioir+x5Bejv72Lx2Zbz3/qGg7tvGbxQZALCLoJaGrkNXak/19+vKgKYJYM3i/fJxvsb23I9FuFQ8CUBEfsmBRg==} + '@rollup/plugin-typescript@11.1.6': + resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^2.14.0||^3.0.0 + rollup: ^2.14.0||^3.0.0||^4.0.0 tslib: '*' typescript: '>=3.7.0' peerDependenciesMeta: @@ -3461,187 +3197,111 @@ packages: tslib: optional: true - '@rollup/pluginutils@5.0.2': - resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} + '@rollup/pluginutils@5.1.3': + resolution: {integrity: sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.18.0': - resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm-eabi@4.18.1': - resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==} + '@rollup/rollup-android-arm-eabi@4.24.4': + resolution: {integrity: sha512-jfUJrFct/hTA0XDM5p/htWKoNNTbDLY0KRwEt6pyOA6k2fmk0WVwl65PdUdJZgzGEHWx+49LilkcSaumQRyNQw==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.18.0': - resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-android-arm64@4.18.1': - resolution: {integrity: sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==} + '@rollup/rollup-android-arm64@4.24.4': + resolution: {integrity: sha512-j4nrEO6nHU1nZUuCfRKoCcvh7PIywQPUCBa2UsootTHvTHIoIu2BzueInGJhhvQO/2FTRdNYpf63xsgEqH9IhA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.18.0': - resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-arm64@4.18.1': - resolution: {integrity: sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==} + '@rollup/rollup-darwin-arm64@4.24.4': + resolution: {integrity: sha512-GmU/QgGtBTeraKyldC7cDVVvAJEOr3dFLKneez/n7BvX57UdhOqDsVwzU7UOnYA7AAOt+Xb26lk79PldDHgMIQ==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.18.0': - resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} + '@rollup/rollup-darwin-x64@4.24.4': + resolution: {integrity: sha512-N6oDBiZCBKlwYcsEPXGDE4g9RoxZLK6vT98M8111cW7VsVJFpNEqvJeIPfsCzbf0XEakPslh72X0gnlMi4Ddgg==} cpu: [x64] os: [darwin] - '@rollup/rollup-darwin-x64@4.18.1': - resolution: {integrity: sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-linux-arm-gnueabihf@4.18.0': - resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} - cpu: [arm] - os: [linux] + '@rollup/rollup-freebsd-arm64@4.24.4': + resolution: {integrity: sha512-py5oNShCCjCyjWXCZNrRGRpjWsF0ic8f4ieBNra5buQz0O/U6mMXCpC1LvrHuhJsNPgRt36tSYMidGzZiJF6mw==} + cpu: [arm64] + os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.18.1': - resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==} - cpu: [arm] - os: [linux] + '@rollup/rollup-freebsd-x64@4.24.4': + resolution: {integrity: sha512-L7VVVW9FCnTTp4i7KrmHeDsDvjB4++KOBENYtNYAiYl96jeBThFfhP6HVxL74v4SiZEVDH/1ILscR5U9S4ms4g==} + cpu: [x64] + os: [freebsd] - '@rollup/rollup-linux-arm-musleabihf@4.18.0': - resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==} + '@rollup/rollup-linux-arm-gnueabihf@4.24.4': + resolution: {integrity: sha512-10ICosOwYChROdQoQo589N5idQIisxjaFE/PAnX2i0Zr84mY0k9zul1ArH0rnJ/fpgiqfu13TFZR5A5YJLOYZA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.18.1': - resolution: {integrity: sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==} + '@rollup/rollup-linux-arm-musleabihf@4.24.4': + resolution: {integrity: sha512-ySAfWs69LYC7QhRDZNKqNhz2UKN8LDfbKSMAEtoEI0jitwfAG2iZwVqGACJT+kfYvvz3/JgsLlcBP+WWoKCLcw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.18.0': - resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.18.1': - resolution: {integrity: sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.18.0': - resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==} + '@rollup/rollup-linux-arm64-gnu@4.24.4': + resolution: {integrity: sha512-uHYJ0HNOI6pGEeZ/5mgm5arNVTI0nLlmrbdph+pGXpC9tFHFDQmDMOEqkmUObRfosJqpU8RliYoGz06qSdtcjg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.18.1': - resolution: {integrity: sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==} + '@rollup/rollup-linux-arm64-musl@4.24.4': + resolution: {integrity: sha512-38yiWLemQf7aLHDgTg85fh3hW9stJ0Muk7+s6tIkSUOMmi4Xbv5pH/5Bofnsb6spIwD5FJiR+jg71f0CH5OzoA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': - resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': - resolution: {integrity: sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==} + '@rollup/rollup-linux-powerpc64le-gnu@4.24.4': + resolution: {integrity: sha512-q73XUPnkwt9ZNF2xRS4fvneSuaHw2BXuV5rI4cw0fWYVIWIBeDZX7c7FWhFQPNTnE24172K30I+dViWRVD9TwA==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.18.0': - resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==} + '@rollup/rollup-linux-riscv64-gnu@4.24.4': + resolution: {integrity: sha512-Aie/TbmQi6UXokJqDZdmTJuZBCU3QBDA8oTKRGtd4ABi/nHgXICulfg1KI6n9/koDsiDbvHAiQO3YAUNa/7BCw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.18.1': - resolution: {integrity: sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.18.0': - resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.18.1': - resolution: {integrity: sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==} + '@rollup/rollup-linux-s390x-gnu@4.24.4': + resolution: {integrity: sha512-P8MPErVO/y8ohWSP9JY7lLQ8+YMHfTI4bAdtCi3pC2hTeqFJco2jYspzOzTUB8hwUWIIu1xwOrJE11nP+0JFAQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.18.0': - resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.18.1': - resolution: {integrity: sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.18.0': - resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==} + '@rollup/rollup-linux-x64-gnu@4.24.4': + resolution: {integrity: sha512-K03TljaaoPK5FOyNMZAAEmhlyO49LaE4qCsr0lYHUKyb6QacTNF9pnfPpXnFlFD3TXuFbFbz7tJ51FujUXkXYA==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.18.1': - resolution: {integrity: sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==} + '@rollup/rollup-linux-x64-musl@4.24.4': + resolution: {integrity: sha512-VJYl4xSl/wqG2D5xTYncVWW+26ICV4wubwN9Gs5NrqhJtayikwCXzPL8GDsLnaLU3WwhQ8W02IinYSFJfyo34Q==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.18.0': - resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==} + '@rollup/rollup-win32-arm64-msvc@4.24.4': + resolution: {integrity: sha512-ku2GvtPwQfCqoPFIJCqZ8o7bJcj+Y54cZSr43hHca6jLwAiCbZdBUOrqE6y29QFajNAzzpIOwsckaTFmN6/8TA==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-arm64-msvc@4.18.1': - resolution: {integrity: sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.18.0': - resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.18.1': - resolution: {integrity: sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==} + '@rollup/rollup-win32-ia32-msvc@4.24.4': + resolution: {integrity: sha512-V3nCe+eTt/W6UYNr/wGvO1fLpHUrnlirlypZfKCT1fG6hWfqhPgQV/K/mRBXBpxc0eKLIF18pIOFVPh0mqHjlg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.18.0': - resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==} + '@rollup/rollup-win32-x64-msvc@4.24.4': + resolution: {integrity: sha512-LTw1Dfd0mBIEqUVCxbvTE/LLo+9ZxVC9k99v1v4ahg9Aak6FpqOfNu5kRkeTAn0wphoC4JU7No1/rL+bBCEwhg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.18.1': - resolution: {integrity: sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==} - cpu: [x64] - os: [win32] + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} '@segment/loosely-validate-event@2.0.0': resolution: {integrity: sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==} - '@sideway/address@4.1.5': - resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} - - '@sideway/formula@3.0.1': - resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} - - '@sideway/pinpoint@2.0.0': - resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} - '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -3652,82 +3312,41 @@ packages: resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} + '@sindresorhus/merge-streams@2.3.0': + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + '@sinonjs/commons@3.0.1': resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - '@smithy/abort-controller@2.2.0': - resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==} - engines: {node: '>=14.0.0'} + '@smithy/abort-controller@3.1.6': + resolution: {integrity: sha512-0XuhuHQlEqbNQZp7QxxrFTdVWdwxch4vjxYgfInF91hZFkPxf9QDrdQka0KfxFMPqLNzSw0b95uGTrLliQUavQ==} + engines: {node: '>=16.0.0'} - '@smithy/abort-controller@3.0.0': - resolution: {integrity: sha512-p6GlFGBt9K4MYLu72YuJ523NVR4A8oHlC5M2JO6OmQqN8kAc/uh1JqLE+FizTokrSJGg0CSvC+BrsmGzKtsZKA==} + '@smithy/config-resolver@3.0.10': + resolution: {integrity: sha512-Uh0Sz9gdUuz538nvkPiyv1DZRX9+D15EKDtnQP5rYVAzM/dnYk3P8cg73jcxyOitPgT3mE3OVj7ky7sibzHWkw==} engines: {node: '>=16.0.0'} - '@smithy/config-resolver@2.2.0': - resolution: {integrity: sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==} - engines: {node: '>=14.0.0'} - - '@smithy/config-resolver@3.0.0': - resolution: {integrity: sha512-2GzOfADwYLQugYkKQhIyZyQlM05K+tMKvRnc6eFfZcpJGRfKoMUMYdPlBKmqHwQFXQKBrGV6cxL9oymWgDzvFw==} - engines: {node: '>=16.0.0'} - - '@smithy/core@1.4.2': - resolution: {integrity: sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==} - engines: {node: '>=14.0.0'} - - '@smithy/core@2.0.1': - resolution: {integrity: sha512-rcMkjvwxH/bER+oZUPR0yTA0ELD6m3A+d92+CFkdF6HJFCBB1bXo7P5pm21L66XwTN01B6bUhSCQ7cymWRD8zg==} + '@smithy/core@2.5.1': + resolution: {integrity: sha512-DujtuDA7BGEKExJ05W5OdxCoyekcKT3Rhg1ZGeiUWaz2BJIWXjZmsG/DIP4W48GHno7AQwRsaCb8NcBgH3QZpg==} engines: {node: '>=16.0.0'} - '@smithy/credential-provider-imds@2.3.0': - resolution: {integrity: sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==} - engines: {node: '>=14.0.0'} - - '@smithy/credential-provider-imds@3.0.0': - resolution: {integrity: sha512-lfmBiFQcA3FsDAPxNfY0L7CawcWtbyWsBOHo34nF095728JLkBX4Y9q/VPPE2r7fqMVK+drmDigqE2/SSQeVRA==} + '@smithy/credential-provider-imds@3.2.5': + resolution: {integrity: sha512-4FTQGAsuwqTzVMmiRVTn0RR9GrbRfkP0wfu/tXWVHd2LgNpTY0uglQpIScXK4NaEyXbB3JmZt8gfVqO50lP8wg==} engines: {node: '>=16.0.0'} - '@smithy/eventstream-codec@2.2.0': - resolution: {integrity: sha512-8janZoJw85nJmQZc4L8TuePp2pk1nxLgkxIR0TUjKJ5Dkj5oelB9WtiSSGXCQvNsJl0VSTvK/2ueMXxvpa9GVw==} - - '@smithy/eventstream-serde-browser@2.2.0': - resolution: {integrity: sha512-UaPf8jKbcP71BGiO0CdeLmlg+RhWnlN8ipsMSdwvqBFigl5nil3rHOI/5GE3tfiuX8LvY5Z9N0meuU7Rab7jWw==} - engines: {node: '>=14.0.0'} - - '@smithy/eventstream-serde-config-resolver@2.2.0': - resolution: {integrity: sha512-RHhbTw/JW3+r8QQH7PrganjNCiuiEZmpi6fYUAetFfPLfZ6EkiA08uN3EFfcyKubXQxOwTeJRZSQmDDCdUshaA==} - engines: {node: '>=14.0.0'} - - '@smithy/eventstream-serde-node@2.2.0': - resolution: {integrity: sha512-zpQMtJVqCUMn+pCSFcl9K/RPNtQE0NuMh8sKpCdEHafhwRsjP50Oq/4kMmvxSRy6d8Jslqd8BLvDngrUtmN9iA==} - engines: {node: '>=14.0.0'} - - '@smithy/eventstream-serde-universal@2.2.0': - resolution: {integrity: sha512-pvoe/vvJY0mOpuF84BEtyZoYfbehiFj8KKWk1ds2AT0mTLYFVs+7sBJZmioOFdBXKd48lfrx1vumdPdmGlCLxA==} - engines: {node: '>=14.0.0'} - - '@smithy/fetch-http-handler@2.5.0': - resolution: {integrity: sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==} + '@smithy/fetch-http-handler@4.0.0': + resolution: {integrity: sha512-MLb1f5tbBO2X6K4lMEKJvxeLooyg7guq48C2zKr4qM7F2Gpkz4dc+hdSgu77pCJ76jVqFBjZczHYAs6dp15N+g==} - '@smithy/fetch-http-handler@3.0.1': - resolution: {integrity: sha512-uaH74i5BDj+rBwoQaXioKpI0SHBJFtOVwzrCpxZxphOW0ki5jhj7dXvDMYM2IJem8TpdFvS2iC08sjOblfFGFg==} - - '@smithy/hash-node@2.2.0': - resolution: {integrity: sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==} - engines: {node: '>=14.0.0'} - - '@smithy/hash-node@3.0.0': - resolution: {integrity: sha512-84qXstNemP3XS5jcof0el6+bDfjzuvhJPQTEfro3lgtbCtKgzPm3MgiS6ehXVPjeQ5+JS0HqmTz8f/RYfzHVxw==} + '@smithy/hash-node@3.0.8': + resolution: {integrity: sha512-tlNQYbfpWXHimHqrvgo14DrMAgUBua/cNoz9fMYcDmYej7MAmUcjav/QKQbFc3NrcPxeJ7QClER4tWZmfwoPng==} engines: {node: '>=16.0.0'} - '@smithy/invalid-dependency@2.2.0': - resolution: {integrity: sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==} - - '@smithy/invalid-dependency@3.0.0': - resolution: {integrity: sha512-F6wBBaEFgJzj0s4KUlliIGPmqXemwP6EavgvDqYwCH40O5Xr2iMHvS8todmGVZtuJCorBkXsYLyTu4PuizVq5g==} + '@smithy/invalid-dependency@3.0.8': + resolution: {integrity: sha512-7Qynk6NWtTQhnGTTZwks++nJhQ1O54Mzi7fz4PqZOiYXb4Z1Flpb2yRvdALoggTS8xjtohWUM+RygOtB30YL3Q==} '@smithy/is-array-buffer@2.2.0': resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} @@ -3737,158 +3356,80 @@ packages: resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==} engines: {node: '>=16.0.0'} - '@smithy/middleware-content-length@2.2.0': - resolution: {integrity: sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==} - engines: {node: '>=14.0.0'} - - '@smithy/middleware-content-length@3.0.0': - resolution: {integrity: sha512-3C4s4d/iGobgCtk2tnWW6+zSTOBg1PRAm2vtWZLdriwTroFbbWNSr3lcyzHdrQHnEXYCC5K52EbpfodaIUY8sg==} + '@smithy/middleware-content-length@3.0.10': + resolution: {integrity: sha512-T4dIdCs1d/+/qMpwhJ1DzOhxCZjZHbHazEPJWdB4GDi2HjIZllVzeBEcdJUN0fomV8DURsgOyrbEUzg3vzTaOg==} engines: {node: '>=16.0.0'} - '@smithy/middleware-endpoint@2.5.1': - resolution: {integrity: sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==} - engines: {node: '>=14.0.0'} - - '@smithy/middleware-endpoint@3.0.0': - resolution: {integrity: sha512-aXOAWztw/5qAfp0NcA2OWpv6ZI/E+Dh9mByif7i91D/0iyYNUcKvskmXiowKESFkuZ7PIMd3VOR4fTibZDs2OQ==} + '@smithy/middleware-endpoint@3.2.1': + resolution: {integrity: sha512-wWO3xYmFm6WRW8VsEJ5oU6h7aosFXfszlz3Dj176pTij6o21oZnzkCLzShfmRaaCHDkBXWBdO0c4sQAvLFP6zA==} engines: {node: '>=16.0.0'} - '@smithy/middleware-retry@2.3.1': - resolution: {integrity: sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==} - engines: {node: '>=14.0.0'} - - '@smithy/middleware-retry@3.0.1': - resolution: {integrity: sha512-hBhSEuL841FhJBK/19WpaGk5YWSzFk/P2UaVjANGKRv3eYNO8Y1lANWgqnuPWjOyCEWMPr58vELFDWpxvRKANw==} + '@smithy/middleware-retry@3.0.25': + resolution: {integrity: sha512-m1F70cPaMBML4HiTgCw5I+jFNtjgz5z5UdGnUbG37vw6kh4UvizFYjqJGHvicfgKMkDL6mXwyPp5mhZg02g5sg==} engines: {node: '>=16.0.0'} - '@smithy/middleware-serde@2.3.0': - resolution: {integrity: sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==} - engines: {node: '>=14.0.0'} - - '@smithy/middleware-serde@3.0.0': - resolution: {integrity: sha512-I1vKG1foI+oPgG9r7IMY1S+xBnmAn1ISqployvqkwHoSb8VPsngHDTOgYGYBonuOKndaWRUGJZrKYYLB+Ane6w==} + '@smithy/middleware-serde@3.0.8': + resolution: {integrity: sha512-Xg2jK9Wc/1g/MBMP/EUn2DLspN8LNt+GMe7cgF+Ty3vl+Zvu+VeZU5nmhveU+H8pxyTsjrAkci8NqY6OuvZnjA==} engines: {node: '>=16.0.0'} - '@smithy/middleware-stack@2.2.0': - resolution: {integrity: sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==} - engines: {node: '>=14.0.0'} - - '@smithy/middleware-stack@3.0.0': - resolution: {integrity: sha512-+H0jmyfAyHRFXm6wunskuNAqtj7yfmwFB6Fp37enytp2q047/Od9xetEaUbluyImOlGnGpaVGaVfjwawSr+i6Q==} + '@smithy/middleware-stack@3.0.8': + resolution: {integrity: sha512-d7ZuwvYgp1+3682Nx0MD3D/HtkmZd49N3JUndYWQXfRZrYEnCWYc8BHcNmVsPAp9gKvlurdg/mubE6b/rPS9MA==} engines: {node: '>=16.0.0'} - '@smithy/node-config-provider@2.3.0': - resolution: {integrity: sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==} - engines: {node: '>=14.0.0'} - - '@smithy/node-config-provider@3.0.0': - resolution: {integrity: sha512-buqfaSdDh0zo62EPLf8rGDvcpKwGpO5ho4bXS2cdFhlOta7tBkWJt+O5uiaAeICfIOfPclNOndshDNSanX2X9g==} + '@smithy/node-config-provider@3.1.9': + resolution: {integrity: sha512-qRHoah49QJ71eemjuS/WhUXB+mpNtwHRWQr77J/m40ewBVVwvo52kYAmb7iuaECgGTTcYxHS4Wmewfwy++ueew==} engines: {node: '>=16.0.0'} - '@smithy/node-http-handler@2.5.0': - resolution: {integrity: sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==} - engines: {node: '>=14.0.0'} - - '@smithy/node-http-handler@3.0.0': - resolution: {integrity: sha512-3trD4r7NOMygwLbUJo4eodyQuypAWr7uvPnebNJ9a70dQhVn+US8j/lCnvoJS6BXfZeF7PkkkI0DemVJw+n+eQ==} + '@smithy/node-http-handler@3.2.5': + resolution: {integrity: sha512-PkOwPNeKdvX/jCpn0A8n9/TyoxjGZB8WVoJmm9YzsnAgggTj4CrjpRHlTQw7dlLZ320n1mY1y+nTRUDViKi/3w==} engines: {node: '>=16.0.0'} - '@smithy/property-provider@2.2.0': - resolution: {integrity: sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==} - engines: {node: '>=14.0.0'} - - '@smithy/property-provider@3.0.0': - resolution: {integrity: sha512-LmbPgHBswdXCrkWWuUwBm9w72S2iLWyC/5jet9/Y9cGHtzqxi+GVjfCfahkvNV4KXEwgnH8EMpcrD9RUYe0eLQ==} + '@smithy/property-provider@3.1.8': + resolution: {integrity: sha512-ukNUyo6rHmusG64lmkjFeXemwYuKge1BJ8CtpVKmrxQxc6rhUX0vebcptFA9MmrGsnLhwnnqeH83VTU9hwOpjA==} engines: {node: '>=16.0.0'} - '@smithy/protocol-http@3.3.0': - resolution: {integrity: sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==} - engines: {node: '>=14.0.0'} - - '@smithy/protocol-http@4.0.0': - resolution: {integrity: sha512-qOQZOEI2XLWRWBO9AgIYuHuqjZ2csyr8/IlgFDHDNuIgLAMRx2Bl8ck5U5D6Vh9DPdoaVpuzwWMa0xcdL4O/AQ==} + '@smithy/protocol-http@4.1.5': + resolution: {integrity: sha512-hsjtwpIemmCkm3ZV5fd/T0bPIugW1gJXwZ/hpuVubt2hEUApIoUTrf6qIdh9MAWlw0vjMrA1ztJLAwtNaZogvg==} engines: {node: '>=16.0.0'} - '@smithy/querystring-builder@2.2.0': - resolution: {integrity: sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==} - engines: {node: '>=14.0.0'} - - '@smithy/querystring-builder@3.0.0': - resolution: {integrity: sha512-bW8Fi0NzyfkE0TmQphDXr1AmBDbK01cA4C1Z7ggwMAU5RDz5AAv/KmoRwzQAS0kxXNf/D2ALTEgwK0U2c4LtRg==} + '@smithy/querystring-builder@3.0.8': + resolution: {integrity: sha512-btYxGVqFUARbUrN6VhL9c3dnSviIwBYD9Rz1jHuN1hgh28Fpv2xjU1HeCeDJX68xctz7r4l1PBnFhGg1WBBPuA==} engines: {node: '>=16.0.0'} - '@smithy/querystring-parser@2.2.0': - resolution: {integrity: sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==} - engines: {node: '>=14.0.0'} - - '@smithy/querystring-parser@3.0.0': - resolution: {integrity: sha512-UzHwthk0UEccV4dHzPySnBy34AWw3V9lIqUTxmozQ+wPDAO9csCWMfOLe7V9A2agNYy7xE+Pb0S6K/J23JSzfQ==} + '@smithy/querystring-parser@3.0.8': + resolution: {integrity: sha512-BtEk3FG7Ks64GAbt+JnKqwuobJNX8VmFLBsKIwWr1D60T426fGrV2L3YS5siOcUhhp6/Y6yhBw1PSPxA5p7qGg==} engines: {node: '>=16.0.0'} - '@smithy/service-error-classification@2.1.5': - resolution: {integrity: sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==} - engines: {node: '>=14.0.0'} - - '@smithy/service-error-classification@3.0.0': - resolution: {integrity: sha512-3BsBtOUt2Gsnc3X23ew+r2M71WwtpHfEDGhHYHSDg6q1t8FrWh15jT25DLajFV1H+PpxAJ6gqe9yYeRUsmSdFA==} + '@smithy/service-error-classification@3.0.8': + resolution: {integrity: sha512-uEC/kCCFto83bz5ZzapcrgGqHOh/0r69sZ2ZuHlgoD5kYgXJEThCoTuw/y1Ub3cE7aaKdznb+jD9xRPIfIwD7g==} engines: {node: '>=16.0.0'} - '@smithy/shared-ini-file-loader@2.4.0': - resolution: {integrity: sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==} - engines: {node: '>=14.0.0'} - - '@smithy/shared-ini-file-loader@3.0.0': - resolution: {integrity: sha512-REVw6XauXk8xE4zo5aGL7Rz4ywA8qNMUn8RtWeTRQsgAlmlvbJ7CEPBcaXU2NDC3AYBgYAXrGyWD8XrN8UGDog==} + '@smithy/shared-ini-file-loader@3.1.9': + resolution: {integrity: sha512-/+OsJRNtoRbtsX0UpSgWVxFZLsJHo/4sTr+kBg/J78sr7iC+tHeOvOJrS5hCpVQ6sWBbhWLp1UNiuMyZhE6pmA==} engines: {node: '>=16.0.0'} - '@smithy/signature-v4@2.3.0': - resolution: {integrity: sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==} - engines: {node: '>=14.0.0'} - - '@smithy/signature-v4@3.0.0': - resolution: {integrity: sha512-kXFOkNX+BQHe2qnLxpMEaCRGap9J6tUGLzc3A9jdn+nD4JdMwCKTJ+zFwQ20GkY+mAXGatyTw3HcoUlR39HwmA==} + '@smithy/signature-v4@4.2.1': + resolution: {integrity: sha512-NsV1jF4EvmO5wqmaSzlnTVetemBS3FZHdyc5CExbDljcyJCEEkJr8ANu2JvtNbVg/9MvKAWV44kTrGS+Pi4INg==} engines: {node: '>=16.0.0'} - '@smithy/smithy-client@2.5.1': - resolution: {integrity: sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==} - engines: {node: '>=14.0.0'} - - '@smithy/smithy-client@3.0.1': - resolution: {integrity: sha512-KAiFY4Y4jdHxR+4zerH/VBhaFKM8pbaVmJZ/CWJRwtM/CmwzTfXfvYwf6GoUwiHepdv+lwiOXCuOl6UBDUEINw==} + '@smithy/smithy-client@3.4.2': + resolution: {integrity: sha512-dxw1BDxJiY9/zI3cBqfVrInij6ShjpV4fmGHesGZZUiP9OSE/EVfdwdRz0PgvkEvrZHpsj2htRaHJfftE8giBA==} engines: {node: '>=16.0.0'} - '@smithy/types@2.12.0': - resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==} - engines: {node: '>=14.0.0'} - - '@smithy/types@3.0.0': - resolution: {integrity: sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==} + '@smithy/types@3.6.0': + resolution: {integrity: sha512-8VXK/KzOHefoC65yRgCn5vG1cysPJjHnOVt9d0ybFQSmJgQj152vMn4EkYhGuaOmnnZvCPav/KnYyE6/KsNZ2w==} engines: {node: '>=16.0.0'} - '@smithy/url-parser@2.2.0': - resolution: {integrity: sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==} - - '@smithy/url-parser@3.0.0': - resolution: {integrity: sha512-2XLazFgUu+YOGHtWihB3FSLAfCUajVfNBXGGYjOaVKjLAuAxx3pSBY3hBgLzIgB17haf59gOG3imKqTy8mcrjw==} - - '@smithy/util-base64@2.3.0': - resolution: {integrity: sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==} - engines: {node: '>=14.0.0'} + '@smithy/url-parser@3.0.8': + resolution: {integrity: sha512-4FdOhwpTW7jtSFWm7SpfLGKIBC9ZaTKG5nBF0wK24aoQKQyDIKUw3+KFWCQ9maMzrgTJIuOvOnsV2lLGW5XjTg==} '@smithy/util-base64@3.0.0': resolution: {integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==} engines: {node: '>=16.0.0'} - '@smithy/util-body-length-browser@2.2.0': - resolution: {integrity: sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==} - '@smithy/util-body-length-browser@3.0.0': resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==} - '@smithy/util-body-length-node@2.3.0': - resolution: {integrity: sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==} - engines: {node: '>=14.0.0'} - '@smithy/util-body-length-node@3.0.0': resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==} engines: {node: '>=16.0.0'} @@ -3901,74 +3442,38 @@ packages: resolution: {integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==} engines: {node: '>=16.0.0'} - '@smithy/util-config-provider@2.3.0': - resolution: {integrity: sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==} - engines: {node: '>=14.0.0'} - '@smithy/util-config-provider@3.0.0': resolution: {integrity: sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==} engines: {node: '>=16.0.0'} - '@smithy/util-defaults-mode-browser@2.2.1': - resolution: {integrity: sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==} - engines: {node: '>= 10.0.0'} - - '@smithy/util-defaults-mode-browser@3.0.1': - resolution: {integrity: sha512-nW5kEzdJn1Bn5TF+gOPHh2rcPli8JU9vSSXLbfg7uPnfR1TMRQqs9zlYRhIb87NeSxIbpdXOI94tvXSy+fvDYg==} - engines: {node: '>= 10.0.0'} - - '@smithy/util-defaults-mode-node@2.3.1': - resolution: {integrity: sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==} + '@smithy/util-defaults-mode-browser@3.0.25': + resolution: {integrity: sha512-fRw7zymjIDt6XxIsLwfJfYUfbGoO9CmCJk6rjJ/X5cd20+d2Is7xjU5Kt/AiDt6hX8DAf5dztmfP5O82gR9emA==} engines: {node: '>= 10.0.0'} - '@smithy/util-defaults-mode-node@3.0.1': - resolution: {integrity: sha512-TFk+Qb+elLc/MOhtSp+50fstyfZ6avQbgH2d96xUBpeScu+Al9elxv+UFAjaTHe0HQe5n+wem8ZLpXvU8lwV6Q==} + '@smithy/util-defaults-mode-node@3.0.25': + resolution: {integrity: sha512-H3BSZdBDiVZGzt8TG51Pd2FvFO0PAx/A0mJ0EH8a13KJ6iUCdYnw/Dk/MdC1kTd0eUuUGisDFaxXVXo4HHFL1g==} engines: {node: '>= 10.0.0'} - '@smithy/util-endpoints@1.2.0': - resolution: {integrity: sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==} - engines: {node: '>= 14.0.0'} - - '@smithy/util-endpoints@2.0.0': - resolution: {integrity: sha512-+exaXzEY3DNt2qtA2OtRNSDlVrE4p32j1JSsQkzA5AdP0YtJNjkYbYhJxkFmPYcjI1abuwopOZCwUmv682QkiQ==} + '@smithy/util-endpoints@2.1.4': + resolution: {integrity: sha512-kPt8j4emm7rdMWQyL0F89o92q10gvCUa6sBkBtDJ7nV2+P7wpXczzOfoDJ49CKXe5CCqb8dc1W+ZdLlrKzSAnQ==} engines: {node: '>=16.0.0'} - '@smithy/util-hex-encoding@2.2.0': - resolution: {integrity: sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==} - engines: {node: '>=14.0.0'} - '@smithy/util-hex-encoding@3.0.0': resolution: {integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==} engines: {node: '>=16.0.0'} - '@smithy/util-middleware@2.2.0': - resolution: {integrity: sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==} - engines: {node: '>=14.0.0'} - - '@smithy/util-middleware@3.0.0': - resolution: {integrity: sha512-q5ITdOnV2pXHSVDnKWrwgSNTDBAMHLptFE07ua/5Ty5WJ11bvr0vk2a7agu7qRhrCFRQlno5u3CneU5EELK+DQ==} + '@smithy/util-middleware@3.0.8': + resolution: {integrity: sha512-p7iYAPaQjoeM+AKABpYWeDdtwQNxasr4aXQEA/OmbOaug9V0odRVDy3Wx4ci8soljE/JXQo+abV0qZpW8NX0yA==} engines: {node: '>=16.0.0'} - '@smithy/util-retry@2.2.0': - resolution: {integrity: sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==} - engines: {node: '>= 14.0.0'} - - '@smithy/util-retry@3.0.0': - resolution: {integrity: sha512-nK99bvJiziGv/UOKJlDvFF45F00WgPLKVIGUfAK+mDhzVN2hb/S33uW2Tlhg5PVBoqY7tDVqL0zmu4OxAHgo9g==} + '@smithy/util-retry@3.0.8': + resolution: {integrity: sha512-TCEhLnY581YJ+g1x0hapPz13JFqzmh/pMWL2KEFASC51qCfw3+Y47MrTmea4bUE5vsdxQ4F6/KFbUeSz22Q1ow==} engines: {node: '>=16.0.0'} - '@smithy/util-stream@2.2.0': - resolution: {integrity: sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==} - engines: {node: '>=14.0.0'} - - '@smithy/util-stream@3.0.1': - resolution: {integrity: sha512-7F7VNNhAsfMRA8I986YdOY5fE0/T1/ZjFF6OLsqkvQVNP3vZ/szYDfGCyphb7ioA09r32K/0qbSFfNFU68aSzA==} + '@smithy/util-stream@3.2.1': + resolution: {integrity: sha512-R3ufuzJRxSJbE58K9AEnL/uSZyVdHzud9wLS8tIbXclxKzoe09CRohj2xV8wpx5tj7ZbiJaKYcutMm1eYgz/0A==} engines: {node: '>=16.0.0'} - '@smithy/util-uri-escape@2.2.0': - resolution: {integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==} - engines: {node: '>=14.0.0'} - '@smithy/util-uri-escape@3.0.0': resolution: {integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==} engines: {node: '>=16.0.0'} @@ -3981,10 +3486,6 @@ packages: resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==} engines: {node: '>=16.0.0'} - '@smithy/util-waiter@2.2.0': - resolution: {integrity: sha512-IHk53BVw6MPMi2Gsn+hCng8rFA3ZmR3Rk7GllxDUW9qFJl/hiSvskn7XldkECapQVkIg/1dHpMAxI9xSTaLLSA==} - engines: {node: '>=14.0.0'} - '@tidbcloud/serverless@0.1.1': resolution: {integrity: sha512-km2P5Mgr9nqVah5p5aMYbO3dBqecSwZ0AU7+BhJH+03L2eJO6qCATcBR8UHPuVLhA7GCt3CambKvVYK79pVQ2g==} engines: {node: '>=16'} @@ -3993,8 +3494,8 @@ packages: resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} engines: {node: '>= 6'} - '@trivago/prettier-plugin-sort-imports@4.2.0': - resolution: {integrity: sha512-YBepjbt+ZNBVmN3ev1amQH3lWCmHyt5qTbLCp/syXJRu/Kw2koXh44qayB1gMRxcL/gV8egmjN5xWSrYyfUtyw==} + '@trivago/prettier-plugin-sort-imports@4.3.0': + resolution: {integrity: sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==} peerDependencies: '@vue/compiler-sfc': 3.x prettier: 2.x - 3.x @@ -4014,15 +3515,27 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - '@types/async-retry@1.4.8': - resolution: {integrity: sha512-Qup/B5PWLe86yI5I3av6ePGaeQrIHNKCwbsQotD6aHQ6YkHsMUxVZkZsmx/Ry3VZQ6uysHwTjQ7666+k6UjVJA==} + '@types/async-retry@1.4.9': + resolution: {integrity: sha512-s1ciZQJzRh3708X/m3vPExr5KJlzlZJvXsKpbtE2luqNcbROr64qU+3KpJsYHqWMeaxI839OvXf9PrUSw1Xtyg==} + + '@types/axios@0.14.4': + resolution: {integrity: sha512-9JgOaunvQdsQ/qW2OPmE5+hCeUB52lQSolecrFrthct55QekhmXEwT203s20RL+UHtCQc15y3VXpby9E7Kkh/g==} + deprecated: This is a stub types definition. axios provides its own type definitions, so you do not need this installed. + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - '@types/axios@0.14.0': - resolution: {integrity: sha512-KqQnQbdYE54D7oa/UmYVMZKq7CO4l8DEENzOKc4aBRwxCXSlJXGz83flFx5L7AWrOQnmuN3kVsRdt+GZPPjiVQ==} - deprecated: This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed! + '@types/babel__traverse@7.20.6': + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} - '@types/better-sqlite3@7.6.10': - resolution: {integrity: sha512-TZBjD+yOsyrUJGmcUj6OS3JADk3+UZcNv3NOBqGkM09bZdi28fNZw8ODqbMOLfKCu7RYCO62/ldq1iHbzxqoPw==} + '@types/better-sqlite3@7.6.11': + resolution: {integrity: sha512-i8KcD3PgGtGBLl3+mMYA8PdKkButvPyARxA7IQAd6qeslht13qxb1zzO8dRCtE7U3IoJS782zDBAeoKiM695kg==} '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} @@ -4036,20 +3549,17 @@ packages: '@types/docker-modem@3.0.6': resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} - '@types/dockerode@3.3.29': - resolution: {integrity: sha512-5PRRq/yt5OT/Jf77ltIdz4EiR9+VLnPF+HpU4xGFwUqmV24Co2HKBNW3w+slqZ1CYchbcDeqJASHDYWzZCcMiQ==} + '@types/dockerode@3.3.31': + resolution: {integrity: sha512-42R9eoVqJDSvVspV89g7RwRqfNExgievLNWoHkg7NoWIqAmavIbgQBb4oc0qRtHkxE+I3Xxvqv7qVXFABKPBTg==} - '@types/emscripten@1.39.11': - resolution: {integrity: sha512-dOeX2BeNA7j6BTEqJQL3ut0bRCfsyQMd5i4FT8JfHfYhAOuJPCGh0dQFbxVJxUyQ+75x6enhDdndGb624/QszA==} + '@types/emscripten@1.39.13': + resolution: {integrity: sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==} - '@types/estree@1.0.1': - resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/estree@1.0.5': - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - - '@types/express-serve-static-core@4.19.0': - resolution: {integrity: sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==} + '@types/express-serve-static-core@4.19.6': + resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} '@types/express@4.17.21': resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} @@ -4060,6 +3570,9 @@ packages: '@types/glob@8.1.0': resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + '@types/http-errors@2.0.4': resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} @@ -4069,14 +3582,17 @@ packages: '@types/istanbul-lib-report@3.0.3': resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + '@types/istanbul-reports@1.1.2': + resolution: {integrity: sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==} + '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} '@types/json-diff@1.0.3': resolution: {integrity: sha512-Qvxm8fpRMv/1zZR3sQWImeRK2mBYJji20xF51Fq9Gt//Ed18u0x6/FNLogLS1xhfUWTEmDyqveJqn95ltB6Kvw==} - '@types/json-schema@7.0.13': - resolution: {integrity: sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==} + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} @@ -4093,26 +3609,29 @@ packages: '@types/minimatch@5.1.2': resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - '@types/minimist@1.2.2': - resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} + '@types/minimist@1.2.5': + resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} - '@types/node@18.15.10': - resolution: {integrity: sha512-9avDaQJczATcXgfmMAW3MIWArOO7A+m90vuCFLr8AotWf8igO/mRoYukrk2cqZVtv38tHs33retzHEilM7FpeQ==} + '@types/node@18.19.64': + resolution: {integrity: sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==} + + '@types/node@20.12.14': + resolution: {integrity: sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==} - '@types/node@18.19.33': - resolution: {integrity: sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A==} + '@types/node@20.17.6': + resolution: {integrity: sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==} - '@types/node@20.10.1': - resolution: {integrity: sha512-T2qwhjWwGH81vUEx4EXmBKsTJRXFXNZTL4v0gi01+zyBmCwzE6TyHszqX01m+QHTEq+EZNo13NeJIdEqf+Myrg==} + '@types/node@22.9.0': + resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} - '@types/node@20.12.12': - resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - '@types/normalize-package-data@2.4.1': - resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} + '@types/pg@8.11.10': + resolution: {integrity: sha512-LczQUW4dbOQzsH2RQ5qoeJ6qJPdrcM/DcMLoqWQkMLMsq83J5lAX3LXjdkWdpscFy67JSOWDnh7Ny/sPFykmkg==} '@types/pg@8.11.6': resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==} @@ -4123,20 +3642,20 @@ packages: '@types/pluralize@0.0.33': resolution: {integrity: sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==} - '@types/prop-types@15.7.12': - resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} + '@types/prop-types@15.7.13': + resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} - '@types/ps-tree@1.1.2': - resolution: {integrity: sha512-ZREFYlpUmPQJ0esjxoG1fMvB2HNaD3z+mjqdSosZvd3RalncI9NEur73P8ZJz4YQdL64CmV1w0RuqoRUlhQRBw==} + '@types/ps-tree@1.1.6': + resolution: {integrity: sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==} - '@types/qs@6.9.15': - resolution: {integrity: sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==} + '@types/qs@6.9.17': + resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==} '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/react@18.3.1': - resolution: {integrity: sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==} + '@types/react@18.3.12': + resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==} '@types/retry@0.12.5': resolution: {integrity: sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw==} @@ -4153,32 +3672,35 @@ packages: '@types/sql.js@1.4.9': resolution: {integrity: sha512-ep8b36RKHlgWPqjNG9ToUrPiwkhwh0AEzy883mO5Xnd+cL6VBH1EvSjBAAuxLUFF2Vn/moE3Me6v9E1Lo+48GQ==} - '@types/ssh2@1.15.0': - resolution: {integrity: sha512-YcT8jP5F8NzWeevWvcyrrLB3zcneVjzYY9ZDSMAMboI+2zR1qYWFhwsyOFVzT7Jorn67vqxC0FRiw8YyG9P1ww==} + '@types/ssh2@1.15.1': + resolution: {integrity: sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA==} '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@types/uuid@9.0.8': resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} - '@types/which@3.0.0': - resolution: {integrity: sha512-ASCxdbsrwNfSMXALlC3Decif9rwDMu+80KGp5zI2RLRotfMsTv7fHL8W8VDp24wymzDyIFudhUeSCugrgRFfHQ==} + '@types/which@3.0.4': + resolution: {integrity: sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w==} - '@types/ws@8.5.11': - resolution: {integrity: sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==} + '@types/ws@8.5.13': + resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - '@types/yargs@15.0.19': - resolution: {integrity: sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==} + '@types/yargs@13.0.12': + resolution: {integrity: sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ==} - '@types/yargs@17.0.32': - resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - '@typescript-eslint/eslint-plugin@6.7.3': - resolution: {integrity: sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==} + '@typescript-eslint/eslint-plugin@6.21.0': + resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -4188,8 +3710,8 @@ packages: typescript: optional: true - '@typescript-eslint/eslint-plugin@7.16.1': - resolution: {integrity: sha512-SxdPak/5bO0EnGktV05+Hq8oatjAYVY3Zh2bye9pGZy6+jwyR3LG3YKkV4YatlsgqXP28BTeVm9pqwJM96vf2A==} + '@typescript-eslint/eslint-plugin@7.18.0': + resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -4205,18 +3727,8 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/parser@6.10.0': - resolution: {integrity: sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/parser@6.7.3': - resolution: {integrity: sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==} + '@typescript-eslint/parser@6.21.0': + resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4225,8 +3737,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@7.16.1': - resolution: {integrity: sha512-u+1Qx86jfGQ5i4JjK33/FnawZRpsLxRnKzGE6EABZ40KxVT/vWsiZFEBBHjFOljmmV3MBYOHEKi0Jm9hbAOClA==} + '@typescript-eslint/parser@7.18.0': + resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -4235,8 +3747,8 @@ packages: typescript: optional: true - '@typescript-eslint/rule-tester@6.10.0': - resolution: {integrity: sha512-I0ZY+9ei73dlOuXwIYWsn/r/ue26Ygf4yEJPxeJRPI06YWDawmR1FI1dXL6ChAWVrmBQRvWep/1PxnV41zfcMA==} + '@typescript-eslint/rule-tester@6.21.0': + resolution: {integrity: sha512-twxQo4He8+AQ/YG70Xt7Fl/ImBLpi7qElxHN6/aK+U4z97JsITCG7DdIIUw5M+qKtDMCYkZCEE2If8dnHI7jWA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@eslint/eslintrc': '>=2' @@ -4246,20 +3758,16 @@ packages: resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/scope-manager@6.10.0': - resolution: {integrity: sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==} - engines: {node: ^16.0.0 || >=18.0.0} - - '@typescript-eslint/scope-manager@6.7.3': - resolution: {integrity: sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==} + '@typescript-eslint/scope-manager@6.21.0': + resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/scope-manager@7.16.1': - resolution: {integrity: sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==} + '@typescript-eslint/scope-manager@7.18.0': + resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/type-utils@6.7.3': - resolution: {integrity: sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw==} + '@typescript-eslint/type-utils@6.21.0': + resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4268,8 +3776,8 @@ packages: typescript: optional: true - '@typescript-eslint/type-utils@7.16.1': - resolution: {integrity: sha512-rbu/H2MWXN4SkjIIyWcmYBjlp55VT+1G3duFOIukTNFxr9PI35pLc2ydwAfejCEitCv4uztA07q0QWanOHC7dA==} + '@typescript-eslint/type-utils@7.18.0': + resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -4282,16 +3790,12 @@ packages: resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/types@6.10.0': - resolution: {integrity: sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==} - engines: {node: ^16.0.0 || >=18.0.0} - - '@typescript-eslint/types@6.7.3': - resolution: {integrity: sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==} + '@typescript-eslint/types@6.21.0': + resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/types@7.16.1': - resolution: {integrity: sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==} + '@typescript-eslint/types@7.18.0': + resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} engines: {node: ^18.18.0 || >=20.0.0} '@typescript-eslint/typescript-estree@5.62.0': @@ -4303,17 +3807,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@6.10.0': - resolution: {integrity: sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/typescript-estree@6.7.3': - resolution: {integrity: sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==} + '@typescript-eslint/typescript-estree@6.21.0': + resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -4321,8 +3816,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@7.16.1': - resolution: {integrity: sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==} + '@typescript-eslint/typescript-estree@7.18.0': + resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -4336,20 +3831,14 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@6.10.0': - resolution: {integrity: sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==} + '@typescript-eslint/utils@6.21.0': + resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@6.7.3': - resolution: {integrity: sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - - '@typescript-eslint/utils@7.16.1': - resolution: {integrity: sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA==} + '@typescript-eslint/utils@7.18.0': + resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -4358,16 +3847,12 @@ packages: resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/visitor-keys@6.10.0': - resolution: {integrity: sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==} + '@typescript-eslint/visitor-keys@6.21.0': + resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/visitor-keys@6.7.3': - resolution: {integrity: sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==} - engines: {node: ^16.0.0 || >=18.0.0} - - '@typescript-eslint/visitor-keys@7.16.1': - resolution: {integrity: sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==} + '@typescript-eslint/visitor-keys@7.18.0': + resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} engines: {node: ^18.18.0 || >=20.0.0} '@typescript/analyze-trace@0.10.1': @@ -4394,14 +3879,13 @@ packages: '@vitest/expect@1.6.0': resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} - '@vitest/expect@2.1.2': - resolution: {integrity: sha512-FEgtlN8mIUSEAAnlvn7mP8vzaWhEaAEvhSXCqrsijM7K6QqjB11qoRZYEd4AKSCDz8p0/+yH5LzhZ47qt+EyPg==} + '@vitest/expect@2.1.4': + resolution: {integrity: sha512-DOETT0Oh1avie/D/o2sgMHGrzYUFFo3zqESB2Hn70z6QB1HrS2IQ9z5DfyTqU8sg4Bpu13zZe9V4+UTNQlUeQA==} - '@vitest/mocker@2.1.2': - resolution: {integrity: sha512-ExElkCGMS13JAJy+812fw1aCv2QO/LBK6CyO4WOPAzLTmve50gydOlWhgdBJPx2ztbADUq3JVI0C5U+bShaeEA==} + '@vitest/mocker@2.1.4': + resolution: {integrity: sha512-Ky/O1Lc0QBbutJdW0rqLeFNbuLEyS+mIPiNdlVlp2/yhJ0SbyYqObS5IHdhferJud8MbbwMnexg4jordE5cCoQ==} peerDependencies: - '@vitest/spy': 2.1.2 - msw: ^2.3.5 + msw: ^2.4.9 vite: ^5.0.0 peerDependenciesMeta: msw: @@ -4409,26 +3893,26 @@ packages: vite: optional: true - '@vitest/pretty-format@2.1.2': - resolution: {integrity: sha512-FIoglbHrSUlOJPDGIrh2bjX1sNars5HbxlcsFKCtKzu4+5lpsRhOCVcuzp0fEhAGHkPZRIXVNzPcpSlkoZ3LuA==} + '@vitest/pretty-format@2.1.4': + resolution: {integrity: sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==} '@vitest/runner@1.6.0': resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} - '@vitest/runner@2.1.2': - resolution: {integrity: sha512-UCsPtvluHO3u7jdoONGjOSil+uON5SSvU9buQh3lP7GgUXHp78guN1wRmZDX4wGK6J10f9NUtP6pO+SFquoMlw==} + '@vitest/runner@2.1.4': + resolution: {integrity: sha512-sKRautINI9XICAMl2bjxQM8VfCMTB0EbsBc/EDFA57V6UQevEKY/TOPOF5nzcvCALltiLfXWbq4MaAwWx/YxIA==} '@vitest/snapshot@1.6.0': resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} - '@vitest/snapshot@2.1.2': - resolution: {integrity: sha512-xtAeNsZ++aRIYIUsek7VHzry/9AcxeULlegBvsdLncLmNCR6tR8SRjn8BbDP4naxtccvzTqZ+L1ltZlRCfBZFA==} + '@vitest/snapshot@2.1.4': + resolution: {integrity: sha512-3Kab14fn/5QZRog5BPj6Rs8dc4B+mim27XaKWFWHWA87R56AKjHTGcBFKpvZKDzC4u5Wd0w/qKsUIio3KzWW4Q==} '@vitest/spy@1.6.0': resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} - '@vitest/spy@2.1.2': - resolution: {integrity: sha512-GSUi5zoy+abNRJwmFhBDC0yRuVUn8WMlQscvnbbXdKLXX9dE59YbfwXxuJ/mth6eeqIzofU8BB5XDo/Ns/qK2A==} + '@vitest/spy@2.1.4': + resolution: {integrity: sha512-4JOxa+UAizJgpZfaCPKK2smq9d8mmjZVPMt2kOsg/R8QkoRzydHH1qHxIYNvr1zlEaFj4SXiaaJWxq/LPLKaLg==} '@vitest/ui@1.6.0': resolution: {integrity: sha512-k3Lyo+ONLOgylctiGovRKy7V4+dIN2yxstX3eY5cWFXH6WP+ooVX79YSyi0GagdTQzLmT43BF27T0s6dOIPBXA==} @@ -4438,11 +3922,11 @@ packages: '@vitest/utils@1.6.0': resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} - '@vitest/utils@2.1.2': - resolution: {integrity: sha512-zMO2KdYy6mx56btx9JvAqAZ6EyS3g49krMPPrgOp1yxGZiA93HumGk+bZ5jIZtOg5/VBYl5eBmGRQHqq4FG6uQ==} + '@vitest/utils@2.1.4': + resolution: {integrity: sha512-MXDnZn0Awl2S86PSNIim5PWXgIAx8CIkzu35mBdSApUip6RFOGXBCf3YFyeEu8n1IHk4bWD46DeYFu9mQlFIRg==} - '@xata.io/client@0.29.4': - resolution: {integrity: sha512-dRff4E/wINr0SYIlOHwApo0h8jzpAHVf2RcbGMkK9Xrddbe90KmCEx/gue9hLhBOoCCp6qUht2h9BsuVPruymw==} + '@xata.io/client@0.29.5': + resolution: {integrity: sha512-b55dmPVNVFOE5nj2F2G6t9l/d5yYBhIu5X5w3rznhhsriGHkrzn93tqJexIZPS77E7f/yDXcFz06KbvR3bHK5w==} peerDependencies: typescript: '>=4.5' @@ -4471,22 +3955,12 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} - - acorn@8.10.0: - resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} - hasBin: true - - acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.8.2: - resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} hasBin: true @@ -4520,12 +3994,13 @@ packages: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} - ansi-escapes@6.2.0: - resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==} + ansi-escapes@6.2.1: + resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} engines: {node: '>=14.16'} - ansi-fragments@0.2.1: - resolution: {integrity: sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==} + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} ansi-regex@4.1.1: resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} @@ -4535,8 +4010,8 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.0.1: - resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} ansi-styles@3.2.1: @@ -4565,9 +4040,6 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - appdirsjs@1.2.7: - resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==} - application-config-path@0.1.1: resolution: {integrity: sha512-zy9cHePtMP0YhwG+CfHm0bgwdnga2X3gZexpdCwEj//dpb+TKajtiC8REEUJUSq6Ab4f9cgNy2l8ObXzCXFkEw==} @@ -4594,9 +4066,6 @@ packages: argsarray@0.0.1: resolution: {integrity: sha512-u96dg2GcAKtpTrBdDoFIM7PjcBA+6rSP0OR94MOReNRyUECL6MtQt5XXmRr4qrftYaef9+l5hcpO5te7sML1Cg==} - array-buffer-byte-length@1.0.0: - resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} - array-buffer-byte-length@1.0.1: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} @@ -4608,28 +4077,24 @@ packages: array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - array-includes@3.1.6: - resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} + array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - array.prototype.findlastindex@1.2.2: - resolution: {integrity: sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==} - engines: {node: '>= 0.4'} - - array.prototype.flat@1.3.1: - resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} + array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} engines: {node: '>= 0.4'} - array.prototype.flatmap@1.3.1: - resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} + array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} - arraybuffer.prototype.slice@1.0.1: - resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==} + array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} engines: {node: '>= 0.4'} arraybuffer.prototype.slice@1.0.3: @@ -4668,10 +4133,6 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} - astral-regex@1.0.0: - resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} - engines: {node: '>=4'} - async-limiter@1.0.1: resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} @@ -4685,8 +4146,8 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - ava@5.3.0: - resolution: {integrity: sha512-QYvBdyygl1LGX13IuYsC4bkwVCzZeovMGbxYkD73i7DVJxNlWnFa06YgrBOTbjw2QvSKUl5fOJ92Kj5WK9hSeg==} + ava@5.3.1: + resolution: {integrity: sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==} engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} hasBin: true peerDependencies: @@ -4695,33 +4156,42 @@ packages: '@ava/typescript': optional: true - available-typed-arrays@1.0.5: - resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} - engines: {node: '>= 0.4'} - available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - aws-ssl-profiles@1.1.1: - resolution: {integrity: sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==} - engines: {node: '>= 6.0.0'} + aws4fetch@1.0.20: + resolution: {integrity: sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==} - axios@1.6.8: - resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} + axios@1.7.7: + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} babel-core@7.0.0-bridge.0: resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} peerDependencies: '@babel/core': ^7.0.0-0 + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-polyfill-corejs2@0.4.11: resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-polyfill-corejs3@0.10.4: - resolution: {integrity: sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==} + babel-plugin-polyfill-corejs3@0.10.6: + resolution: {integrity: sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 @@ -4730,14 +4200,31 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-react-native-web@0.19.12: - resolution: {integrity: sha512-eYZ4+P6jNcB37lObWIg0pUbi7+3PKoU1Oie2j0C8UF3cXyXoR74tO2NBjI/FORb2LJyItJZEAmjU5pSaJYEL1w==} + babel-plugin-react-compiler@0.0.0-experimental-592953e-20240517: + resolution: {integrity: sha512-OjG1SVaeQZaJrqkMFJatg8W/MTow8Ak5rx2SI0ETQBO1XvOk/XZGMbltNCPdFJLKghBYoBjC+Y3Ap/Xr7B01mA==} + + babel-plugin-react-native-web@0.19.13: + resolution: {integrity: sha512-4hHoto6xaN23LCyZgL9LJZc3olmAxd7b6jDzlZnKXAh4rRAbZRKNBJoOOdp46OBqgy+K0t0guTj5/mhA8inymQ==} + + babel-plugin-syntax-hermes-parser@0.23.1: + resolution: {integrity: sha512-uNLD0tk2tLUjGFdmCk+u/3FEw2o+BAwW4g+z2QVlxJrzZYOOPADroEcNtTPt5lNiScctaUmnsTkVEnOwZUOLhA==} babel-plugin-transform-flow-enums@0.0.2: resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} - babel-preset-expo@11.0.6: - resolution: {integrity: sha512-jRi9I5/jT+dnIiNJDjDg+I/pV+AlxrIW/DNbdqYoRWPZA/LHDqD6IJnJXLxbuTcQ+llp+0LWcU7f/kC/PgGpkw==} + babel-preset-current-node-syntax@1.1.0: + resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-expo@11.0.15: + resolution: {integrity: sha512-rgiMTYwqIPULaO7iZdqyL7aAff9QLOX6OWUtLZBlOrOTreGY1yHah/5+l8MvI6NVc/8Zj5LY4Y5uMSnJIuzTLw==} + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -4752,6 +4239,9 @@ packages: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} + better-sqlite3@11.5.0: + resolution: {integrity: sha512-e/6eggfOutzoK0JWiU36jsisdWoHOfN9iWiW/SieKvb7SAa6aGNmBM/UKyp+/wWSXpLlWNN8tCPwoDNPhzUvuQ==} + better-sqlite3@8.7.0: resolution: {integrity: sha512-99jZU4le+f3G6aIl6PmmV0cxUIWqKieHxsiF7G34CVFiE+/UabpYqkU0NJIkY/96mQKikHeBjtR27vFfs5JpEw==} @@ -4762,8 +4252,8 @@ packages: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} - binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} bindings@1.5.0: @@ -4778,13 +4268,16 @@ packages: blueimp-md5@2.19.0: resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} - body-parser@1.20.2: - resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} bowser@2.11.0: resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + bplist-creator@0.0.7: + resolution: {integrity: sha512-xp/tcaV3T5PCiaY04mXga7o/TE+t95gqeLmADeBI1CvZtdWTbgBt3uLpvh4UWtenKeBhCV6oVxGk38yZr2uYEA==} + bplist-creator@0.1.0: resolution: {integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==} @@ -4806,8 +4299,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.23.0: - resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + browserslist@4.24.2: + resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -4850,11 +4343,11 @@ packages: bun-types@0.6.14: resolution: {integrity: sha512-sRdvu+t59+H/TVOe7FSGFWYITbqkhiCx9NxVUHt2+JOXM9gUOe5uMPvVvcr/hGngnh+/yb5a7uPE4JaS6uxujg==} - bun-types@1.0.3: - resolution: {integrity: sha512-XlyKVdYCHa7K5PHYGcwOVOrGE/bMnLS51y7zFA3ZAAXyiQ6dTaNXNCWTTufgII/6ruN770uhAXphQmzvU/r2fQ==} + bun-types@1.1.34: + resolution: {integrity: sha512-br5QygTEL/TwB4uQOb96Ky22j4Gq2WxWH/8Oqv20fk5HagwKXo/akB+LiYgSfzexCt6kkcUaVm+bKiPl71xPvw==} - bundle-require@4.0.2: - resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} + bundle-require@4.2.1: + resolution: {integrity: sha512-7Q/6vkyYAwOmQNRw75x+4yRtZCZJXUDmHHlFdkiV0wgv/reNjtJwpu1jPJ0w2kbEpIM0uoKI3S4/f39dU7AjSA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: esbuild: '>=0.17' @@ -4869,10 +4362,6 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} - bytes@3.0.0: - resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} - engines: {node: '>= 0.8'} - bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -4885,13 +4374,10 @@ packages: resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} engines: {node: '>= 10'} - cacache@18.0.3: - resolution: {integrity: sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==} + cacache@18.0.4: + resolution: {integrity: sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==} engines: {node: ^16.14.0 || >=18.0.0} - call-bind@1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} - call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} @@ -4912,8 +4398,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - callsites@4.1.0: - resolution: {integrity: sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==} + callsites@4.2.0: + resolution: {integrity: sha512-kfzR4zzQtAE9PC7CzZsjl3aBNbXWuXiSeOCdLcPpBfGW8YuCqQHcRPFDbr/BPVmd3EEPVpuFzLyuT/cUhPr4OQ==} engines: {node: '>=12.20'} camelcase@5.3.1: @@ -4928,8 +4414,8 @@ packages: resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} engines: {node: '>=14.16'} - caniuse-lite@1.0.30001624: - resolution: {integrity: sha512-0dWnQG87UevOCPYaOR49CBcLBwoZLpws+k6W37nLjWUhumP1Isusj0p2u+3KhjNloRWK9OKMgjBBzPujQHw4nA==} + caniuse-lite@1.0.30001679: + resolution: {integrity: sha512-j2YqID/YwpLnKzCmBOS4tlZdWprXm3ZmQLBH9ZBXFOhoxLA46fwyBvx6toCBWBmnuwUY/qB3kEU6gFx8qgCroA==} capnp-ts@0.7.0: resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} @@ -4942,12 +4428,12 @@ packages: resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} engines: {node: '>=12.19'} - chai@4.4.1: - resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} + chai@4.5.0: + resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} engines: {node: '>=4'} - chai@5.1.1: - resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} + chai@5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} engines: {node: '>=12'} chalk@2.4.2: @@ -4976,14 +4462,14 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} - chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} + chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -4996,16 +4482,15 @@ packages: engines: {node: '>=12.13.0'} hasBin: true + chromium-edge-launcher@0.2.0: + resolution: {integrity: sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==} + chunkd@2.0.1: resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} ci-info@2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} - ci-info@3.8.0: - resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} - engines: {node: '>=8'} - ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -5013,6 +4498,9 @@ packages: ci-parallel-vars@1.0.1: resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} + cjs-module-lexer@1.4.1: + resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} + clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} @@ -5029,33 +4517,31 @@ packages: resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} engines: {node: '>=0.10.0'} - cli-color@2.0.3: - resolution: {integrity: sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==} + cli-color@2.0.4: + resolution: {integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==} engines: {node: '>=0.10'} cli-cursor@2.1.0: resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==} engines: {node: '>=4'} - cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} + cli-highlight@2.1.11: + resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - cli-table3@0.6.3: - resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} engines: {node: 10.* || >= 12.*} cli-truncate@3.1.0: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -5096,9 +4582,6 @@ packages: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true - colorette@1.4.0: - resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - colorette@2.0.19: resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} @@ -5117,10 +4600,6 @@ packages: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} - commander@11.0.0: - resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==} - engines: {node: '>=16'} - commander@12.1.0: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} @@ -5149,14 +4628,6 @@ packages: component-type@1.2.2: resolution: {integrity: sha512-99VUHREHiN5cLeHm3YLq312p6v+HUEcwtLCAtelvUDI6+SH5g5Cr85oNR2S1o6ywzL0ykMbuwLzM2ANocjEOIA==} - compressible@2.0.18: - resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} - engines: {node: '>= 0.6'} - - compression@1.7.4: - resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} - engines: {node: '>= 0.8.0'} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -5164,13 +4635,13 @@ packages: resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} - concurrently@8.2.1: - resolution: {integrity: sha512-nVraf3aXOpIcNud5pB9M82p1tynmZkrSGQ1p6X/VY8cJ+2LMVqAgXsJxYYefACSHbTYlm92O1xuhdGTjwoEvbQ==} + concurrently@8.2.2: + resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} engines: {node: ^14.13.0 || >=16.0.0} hasBin: true - confbox@0.1.7: - resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} connect@3.7.0: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} @@ -5201,20 +4672,24 @@ packages: cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - cookie@0.5.0: - resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} - cookie@0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} copy-anything@3.0.5: resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} engines: {node: '>=12.13'} - core-js-compat@3.37.1: - resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} + copy-file@11.0.0: + resolution: {integrity: sha512-mFsNh/DIANLqFt5VHZoGirdg7bK5+oTWlhnGu6tgRhzBlnEKWaPX2xrFaLltii/6rmhqFMJqffUgknuRdpYlHw==} + engines: {node: '>=18'} + + core-js-compat@3.39.0: + resolution: {integrity: sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -5240,6 +4715,10 @@ packages: resolution: {integrity: sha512-VC2Gs20JcTyeQob6UViBLnyP0bYHkBh6EiKzot9vi2DmeGlFT9Wd7VG3NBrkNx/jYvFBeyDOMMHdHQhbtKLgHQ==} engines: {node: '>=16'} + cpy@11.1.0: + resolution: {integrity: sha512-QGHetPSSuprVs+lJmMDcivvrBwTKASzXQ5qxFvRC2RFESjjod71bDvFvhxTjDgkNjrrb72AI6JPjfYwxrIy33A==} + engines: {node: '>=18'} + create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -5255,8 +4734,8 @@ packages: resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} engines: {node: '>=4.8'} - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + cross-spawn@7.0.5: + resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==} engines: {node: '>= 8'} crypt@0.0.2: @@ -5277,8 +4756,9 @@ packages: resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} engines: {node: '>=0.10.0'} - d@1.0.1: - resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} + d@1.0.2: + resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} + engines: {node: '>=0.12'} dag-map@1.0.2: resolution: {integrity: sha512-+LSAiGFwQ9dRnRdOeaj7g47ZFJcOUPukAP8J3A3fuZ1g9Y44BG+P1sgApjLXTQPOzC4+7S9Wr8kXsfpINM4jpw==} @@ -5306,16 +4786,13 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} - date-fns@3.6.0: - resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} date-time@3.1.0: resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} engines: {node: '>=6'} - dayjs@1.11.11: - resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==} - debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -5341,15 +4818,6 @@ packages: supports-color: optional: true - debug@4.3.5: - resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -5359,16 +4827,12 @@ packages: supports-color: optional: true - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} - deep-eql@4.1.3: - resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + deep-eql@4.1.4: + resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} engines: {node: '>=6'} deep-eql@5.0.2: @@ -5382,10 +4846,6 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - default-gateway@4.2.0: resolution: {integrity: sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==} engines: {node: '>=6'} @@ -5401,10 +4861,6 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} - define-properties@1.2.0: - resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} - engines: {node: '>= 0.4'} - define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -5463,8 +4919,8 @@ packages: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} - diff@5.1.0: - resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} difflib@0.2.4: @@ -5478,10 +4934,18 @@ packages: resolution: {integrity: sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ==} engines: {node: '>= 8.0'} + docker-modem@5.0.3: + resolution: {integrity: sha512-89zhop5YVhcPEt5FpUFGr3cDyceGhq/F9J+ZndQ4KfqNvfbJpPMfgeixFgUj5OjCYAboElqODxY5Z1EBsSa6sg==} + engines: {node: '>= 8.0'} + dockerode@3.3.5: resolution: {integrity: sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA==} engines: {node: '>= 8.0'} + dockerode@4.0.2: + resolution: {integrity: sha512-9wM1BVpVMFr2Pw3eJNXrYYt6DT9k0xMcsSCjtPvyQ+xa1iPg/Mo3T/gUcwI0B2cczqCeCYRPF8yFYDwtFXT0+w==} + engines: {node: '>= 8.0'} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -5580,8 +5044,8 @@ packages: sqlite3: optional: true - drizzle-prisma-generator@0.1.4: - resolution: {integrity: sha512-6gY17/wTWfNF40rKjiYeWdkU8Gi6FQiOlU4oXa8uuo3ZZ8E6FH3250AhgCOMWAKZLpjQnk8FSzS0GXzwHkShkQ==} + drizzle-prisma-generator@0.1.7: + resolution: {integrity: sha512-KW+Z6W4hjvsiOCCPEmGyO+Oal7KPv2yQ3uZzHasaVIn+gUWGrkcy8BCDEp1h7uRBRSAd/l17EM4DfljhgYXxBw==} hasBin: true duplexer@0.1.2: @@ -5593,8 +5057,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.4.783: - resolution: {integrity: sha512-bT0jEz/Xz1fahQpbZ1D7LgmPYZ3iHVY39NcWWro1+hA2IvjiPeaXtfSqrQ+nXjApMvQRE2ASt1itSLRrebHMRQ==} + electron-to-chromium@1.5.55: + resolution: {integrity: sha512-6maZ2ASDOTBtjt9FhqYPRnbvKU5tjG0IN9SztUOWYw2AzNDNpKJYLJmlK0/En4Hs/aiWnB+JZ+gW19PIGszgKg==} emittery@1.0.3: resolution: {integrity: sha512-tJdCJitoy2lrC2ldJcqN4vkqJ00lT+tOWNT1hBJjO/3FDMJa5TTIiYGCKGkn/WfCyOzUMObeohbVTj00fhiLiA==} @@ -5613,6 +5077,10 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} @@ -5631,10 +5099,9 @@ packages: resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - envinfo@7.13.0: - resolution: {integrity: sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==} - engines: {node: '>=4'} - hasBin: true + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} eol@0.9.1: resolution: {integrity: sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==} @@ -5648,14 +5115,6 @@ packages: error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} - errorhandler@1.5.1: - resolution: {integrity: sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==} - engines: {node: '>= 0.8'} - - es-abstract@1.22.1: - resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==} - engines: {node: '>= 0.4'} - es-abstract@1.23.3: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} @@ -5672,30 +5131,27 @@ packages: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} engines: {node: '>= 0.4'} - es-set-tostringtag@2.0.1: - resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} - engines: {node: '>= 0.4'} - es-set-tostringtag@2.0.3: resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} - es-shim-unscopables@1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} - es5-ext@0.10.62: - resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} + es5-ext@0.10.64: + resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} engines: {node: '>=0.10'} es6-iterator@2.0.3: resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - es6-symbol@3.1.3: - resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} + es6-symbol@3.1.4: + resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} + engines: {node: '>=0.12'} es6-weak-map@2.0.3: resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} @@ -5790,11 +5246,11 @@ packages: cpu: [x64] os: [netbsd] - esbuild-node-externals@1.14.0: - resolution: {integrity: sha512-jMWnTlCII3cLEjR5+u0JRSTJuP+MgbjEHKfwSIAI41NgLQ0ZjfzjchlbEn0r7v2u5gCBMSEYvYlkO7GDG8gG3A==} + esbuild-node-externals@1.15.0: + resolution: {integrity: sha512-lM5f3CQL9Ctv6mBwwYAEMcphK2qrjVRnemT1mufECpFaidZvFVvQDPcuno/MQfLVk4utVuSVxm1RHLyg/ONQ/A==} engines: {node: '>=12'} peerDependencies: - esbuild: 0.12 - 0.23 + esbuild: 0.12 - 0.24 esbuild-openbsd-64@0.14.54: resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} @@ -5802,8 +5258,8 @@ packages: cpu: [x64] os: [openbsd] - esbuild-register@3.5.0: - resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==} + esbuild-register@3.6.0: + resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} peerDependencies: esbuild: '>=0.12 <1' @@ -5851,27 +5307,23 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.20.2: - resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} - engines: {node: '>=12'} - hasBin: true - esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} hasBin: true - esbuild@0.23.0: - resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==} + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} engines: {node: '>=18'} hasBin: true - escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} + esbuild@0.24.0: + resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==} + engines: {node: '>=18'} + hasBin: true - escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} escape-html@1.0.3: @@ -5902,8 +5354,8 @@ packages: eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - eslint-module-utils@2.8.0: - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + eslint-module-utils@2.12.0: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -5923,12 +5375,12 @@ packages: eslint-import-resolver-webpack: optional: true - eslint-plugin-import@2.28.1: - resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} + eslint-plugin-import@2.31.0: + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 peerDependenciesMeta: '@typescript-eslint/parser': optional: true @@ -5956,12 +5408,12 @@ packages: peerDependencies: eslint: '>=8.44.0' - eslint-plugin-unused-imports@3.0.0: - resolution: {integrity: sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==} + eslint-plugin-unused-imports@3.2.0: + resolution: {integrity: sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - '@typescript-eslint/eslint-plugin': ^6.0.0 - eslint: ^8.0.0 + '@typescript-eslint/eslint-plugin': 6 - 7 + eslint: '8' peerDependenciesMeta: '@typescript-eslint/eslint-plugin': optional: true @@ -5982,24 +5434,8 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-visitor-keys@4.0.0: - resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint@8.50.0: - resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true - - eslint@8.53.0: - resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true - - eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true @@ -6008,9 +5444,9 @@ packages: resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} engines: {node: '>=6'} - espree@10.0.1: - resolution: {integrity: sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + esniff@2.0.1: + resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} + engines: {node: '>=0.10'} espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} @@ -6021,8 +5457,8 @@ packages: engines: {node: '>=4'} hasBin: true - esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -6095,13 +5531,17 @@ packages: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - expo-asset@10.0.6: - resolution: {integrity: sha512-waP73/ccn/HZNNcGM4/s3X3icKjSSbEQ9mwc6tX34oYNg+XE5WdwOuZ9wgVVFrU7wZMitq22lQXd2/O0db8bxg==} + expect-type@1.1.0: + resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} + engines: {node: '>=12.0.0'} + + expo-asset@10.0.10: + resolution: {integrity: sha512-0qoTIihB79k+wGus9wy0JMKq7DdenziVx3iUkGvMAy2azscSgWH6bd2gJ9CGnhC6JRd3qTMFBL0ou/fx7WZl7A==} peerDependencies: expo: '*' - expo-constants@16.0.1: - resolution: {integrity: sha512-s6aTHtglp926EsugWtxN7KnpSsE9FCEjb7CgEjQQ78Gpu4btj4wB+IXot2tlqNwqv+x7xFe5veoPGfJDGF/kVg==} + expo-constants@16.0.2: + resolution: {integrity: sha512-9tNY3OVO0jfiMzl7ngb6IOyR5VFzNoN5OOazUWoeGfmMqVB5kltTemRvKraK9JRbBKIw+SOYLEmF0sEqgFZ6OQ==} peerDependencies: expo: '*' @@ -6110,8 +5550,8 @@ packages: peerDependencies: expo: '*' - expo-font@12.0.5: - resolution: {integrity: sha512-h/VkN4jlHYDJ6T6pPgOYTVoDEfBY0CTKQe4pxnPDGQiE6H+DFdDgk+qWVABGpRMH0+zXoHB+AEi3OoQjXIynFA==} + expo-font@12.0.10: + resolution: {integrity: sha512-Q1i2NuYri3jy32zdnBaHHCya1wH1yMAsI+3CCmj9zlQzlhsS9Bdwcj2W3c5eU5FvH2hsNQy4O+O1NnM6o/pDaQ==} peerDependencies: expo: '*' @@ -6120,24 +5560,27 @@ packages: peerDependencies: expo: '*' - expo-modules-autolinking@1.11.1: - resolution: {integrity: sha512-2dy3lTz76adOl7QUvbreMCrXyzUiF8lygI7iFJLjgIQIVH+43KnFWE5zBumpPbkiaq0f0uaFpN9U0RGQbnKiMw==} + expo-modules-autolinking@1.11.3: + resolution: {integrity: sha512-oYh8EZEvYF5TYppxEKUTTJmbr8j7eRRnrIxzZtMvxLTXoujThVPMFS/cbnSnf2bFm1lq50TdDNABhmEi7z0ngQ==} hasBin: true - expo-modules-core@1.12.11: - resolution: {integrity: sha512-CF5G6hZo/6uIUz6tj4dNRlvE5L4lakYukXPqz5ZHQ+6fLk1NQVZbRdpHjMkxO/QSBQcKUzG/ngeytpoJus7poQ==} + expo-modules-core@1.12.26: + resolution: {integrity: sha512-y8yDWjOi+rQRdO+HY+LnUlz8qzHerUaw/LUjKPU/mX8PRXP4UUPEEp5fjAwBU44xjNmYSHWZDwet4IBBE+yQUA==} expo-sqlite@14.0.6: resolution: {integrity: sha512-T3YNx7LT7lM4UQRgi8ml+cj0Wf3Ep09+B4CVaWtUCjdyYJIZjsHDT65hypKG+r6btTLLEd11hjlrstNQhzt5gQ==} peerDependencies: expo: '*' - expo@51.0.8: - resolution: {integrity: sha512-bdTOiMb1f3PChtuqEZ9czUm2gMTmS0r1+H+Pkm2O3PsuLnOgxfIBzL6S37+J4cUocLBaENrmx9SOGKpzhBqXpg==} + expo@51.0.38: + resolution: {integrity: sha512-/B9npFkOPmv6WMIhdjQXEY0Z9k/67UZIVkodW8JxGIXwKUZAGHL+z1R5hTtWimpIrvVhyHUFU3f8uhfEKYhHNQ==} hasBin: true - express@4.19.2: - resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} + exponential-backoff@3.1.1: + resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} + + express@4.21.1: + resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==} engines: {node: '>= 0.10.0'} ext@1.7.0: @@ -6149,10 +5592,6 @@ packages: fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} - fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -6163,16 +5602,12 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-xml-parser@4.2.5: - resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} - hasBin: true - - fast-xml-parser@4.4.0: - resolution: {integrity: sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==} + fast-xml-parser@4.4.1: + resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} hasBin: true - fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -6186,6 +5621,14 @@ packages: fbjs@3.0.5: resolution: {integrity: sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==} + fdir@6.4.2: + resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + fetch-blob@3.2.0: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} @@ -6215,8 +5658,8 @@ packages: resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} engines: {node: '>= 0.8'} - finalhandler@1.2.0: - resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} find-cache-dir@2.1.0: @@ -6242,12 +5685,9 @@ packages: find-yarn-workspace-root@2.0.0: resolution: {integrity: sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==} - flat-cache@3.1.0: - resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==} - engines: {node: '>=12.0.0'} - - flatted@3.2.9: - resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} @@ -6255,12 +5695,12 @@ packages: flow-enums-runtime@0.0.6: resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} - flow-parser@0.236.0: - resolution: {integrity: sha512-0OEk9Gr+Yj7wjDW2KgaNYUypKau71jAfFyeLQF5iVtxqc6uJHag/MT7pmaEApf4qM7u86DkBcd4ualddYMfbLw==} + flow-parser@0.252.0: + resolution: {integrity: sha512-z8hKPUjZ33VLn4HVntifqmEhmolUMopysnMNzazoDqo1GLUkBsreLNsxETlKJMPotUWStQnen6SGvUNe1j4Hlg==} engines: {node: '>=0.4.0'} - follow-redirects@1.15.6: - resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -6274,16 +5714,16 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - foreground-child@3.1.1: - resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} - form-data@3.0.1: - resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} + form-data@3.0.2: + resolution: {integrity: sha512-sJe+TQb2vIaIyO783qN6BlMYWMw3WBOHA1Ay2qxsnjuafEOQFJ2JakedOQirT6D5XPRxDvS7AHYyem9fTpb4LQ==} engines: {node: '>= 6'} - form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} formdata-polyfill@4.0.10: @@ -6308,8 +5748,8 @@ packages: fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs-extra@11.1.1: - resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} + fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} engines: {node: '>=14.14'} fs-extra@8.1.0: @@ -6340,16 +5780,9 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.5: - resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} - engines: {node: '>= 0.4'} - function.prototype.name@1.1.6: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} @@ -6357,8 +5790,8 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - fx@28.0.0: - resolution: {integrity: sha512-vKQDA9g868cZiW8ulgs2uN1yx1i7/nsS33jTMOxekk0Z03BJLffVcdW6AVD32fWb3E6RtmWWuBXBZOk8cLXFNQ==} + fx@35.0.0: + resolution: {integrity: sha512-O07q+Lknrom5RUX/u53tjo2KTTLUnL0K703JbqMYb19ORijfJNvijzFqqYXEjdk25T9R14S6t6wHD8fCWXCM0g==} hasBin: true gauge@4.0.4: @@ -6380,9 +5813,6 @@ packages: get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - get-intrinsic@1.2.1: - resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} - get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} @@ -6418,16 +5848,12 @@ packages: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} - get-symbol-description@1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} - engines: {node: '>= 0.4'} - get-symbol-description@1.0.2: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} - get-tsconfig@4.7.5: - resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} getenv@1.0.0: resolution: {integrity: sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==} @@ -6450,20 +5876,10 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.3.10: - resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - - glob@10.4.1: - resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==} - engines: {node: '>=16 || 14 >=14.18'} + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true - glob@6.0.4: - resolution: {integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==} - deprecated: Glob versions prior to v9 are no longer supported - glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} deprecated: Glob versions prior to v9 are no longer supported @@ -6481,18 +5897,10 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - globals@13.22.0: - resolution: {integrity: sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==} + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} - globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -6505,6 +5913,10 @@ packages: resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + globby@14.0.2: + resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==} + engines: {node: '>=18'} + globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} @@ -6541,16 +5953,9 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-property-descriptors@1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} - has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} - engines: {node: '>= 0.4'} - has-proto@1.0.3: resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} engines: {node: '>= 0.4'} @@ -6559,10 +5964,6 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} - has-tostringtag@1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} - engines: {node: '>= 0.4'} - has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} @@ -6570,10 +5971,6 @@ packages: has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} - hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -6584,26 +5981,27 @@ packages: hermes-estree@0.19.1: resolution: {integrity: sha512-daLGV3Q2MKk8w4evNMKwS8zBE/rcpA800nu1Q5kM08IKijoSnPe9Uo1iIxzPKRkn95IxxsgBMPeYHt3VG4ej2g==} - hermes-estree@0.20.1: - resolution: {integrity: sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==} + hermes-estree@0.23.1: + resolution: {integrity: sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==} + + hermes-estree@0.24.0: + resolution: {integrity: sha512-LyoXLB7IFzeZW0EvAbGZacbxBN7t6KKSDqFJPo3Ydow7wDlrDjXwsdiAHV6XOdvEN9MEuWXsSIFN4tzpyrXIHw==} hermes-parser@0.19.1: resolution: {integrity: sha512-Vp+bXzxYJWrpEuJ/vXxUsLnt0+y4q9zyi4zUlkLqD8FKv4LjIfOvP69R/9Lty3dCyKh0E2BU7Eypqr63/rKT/A==} - hermes-parser@0.20.1: - resolution: {integrity: sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==} + hermes-parser@0.23.1: + resolution: {integrity: sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==} - hermes-profile-transformer@0.0.6: - resolution: {integrity: sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==} - engines: {node: '>=8'} + hermes-parser@0.24.0: + resolution: {integrity: sha512-IJooSvvu2qNRe7oo9Rb04sUT4omtZqZqf9uq9WM25Tb6v3usmvA93UqfnnoWs5V0uYjEl9Al6MNU10MCGKLwpg==} - hono@4.0.1: - resolution: {integrity: sha512-S9cREGPJIAK437RhroOf1PGlJPIlt5itl69OmQ6onPLo5pdCbSHGL8v4uAKxrdHjcTyuoyvKPqWm5jv0dGkdFA==} - engines: {node: '>=16.0.0'} + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - hono@4.5.0: - resolution: {integrity: sha512-ZbezypZfn4odyApjCCv+Fw5OgweBqRLA/EsMyc4FUknFvBJcBIKhHy4sqmD1rWpBc/3wUlaQ6tqOPjk36R1ckg==} - engines: {node: '>=16.0.0'} + hono@4.6.9: + resolution: {integrity: sha512-p/pN5yZLuZaHzyAOT2nw2/Ud6HhJHYmDNGH6Ck1OWBhPMVeM1r74jbCRwNi0gyFRjjbsGgoHbOyj7mT1PDNbTw==} + engines: {node: '>=16.9.0'} hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -6657,12 +6055,8 @@ packages: resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} engines: {node: '>=10 <11 || >=12 <13 || >=14'} - ignore@5.2.4: - resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} - engines: {node: '>= 4'} - - ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} image-size@1.1.1: @@ -6710,10 +6104,6 @@ packages: resolution: {integrity: sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==} engines: {node: '>=6'} - internal-slot@1.0.5: - resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} - engines: {node: '>= 0.4'} - internal-slot@1.0.7: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} @@ -6741,9 +6131,6 @@ packages: resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} engines: {node: '>=8'} - is-array-buffer@3.0.2: - resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} - is-array-buffer@3.0.4: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} @@ -6773,17 +6160,9 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.11.0: - resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} - - is-core-module@2.12.1: - resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} - - is-core-module@2.13.0: - resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} - - is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} is-data-view@1.0.1: resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} @@ -6813,10 +6192,6 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-fullwidth-code-point@2.0.0: - resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} - engines: {node: '>=4'} - is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -6833,10 +6208,6 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} - is-invalid-path@0.1.0: resolution: {integrity: sha512-aZMG0T3F34mTg4eTdszcGXx54oiZ4NtHSft3hWNJMGJXUUqdIj3cOZuHcU0nCWWcY3jd7yRe/3AEm3vSNTpBGQ==} engines: {node: '>=0.10.0'} @@ -6844,10 +6215,6 @@ packages: is-lambda@1.0.1: resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} - is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} - engines: {node: '>= 0.4'} - is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} @@ -6889,9 +6256,6 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} - is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} - is-shared-array-buffer@1.0.3: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} @@ -6916,18 +6280,10 @@ packages: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} - is-typed-array@1.1.12: - resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} - engines: {node: '>= 0.4'} - is-typed-array@1.1.13: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} @@ -6943,10 +6299,6 @@ packages: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} engines: {node: '>=12.13'} - is-wsl@1.1.0: - resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} - engines: {node: '>=4'} - is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -6964,13 +6316,19 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - jackspeak@2.3.6: - resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} - engines: {node: '>=14'} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} - jackspeak@3.1.2: - resolution: {integrity: sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==} - engines: {node: '>=14'} + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + itty-time@1.0.6: + resolution: {integrity: sha512-+P8IZaLLBtFv8hCkIjcymZOp4UJ+xW6bSlQsXGqrkmJh7vSiMFSlNne0mCYagEE0N7HDNR5jJBRxwN0oYv61Rw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} javascript-natural-sort@0.7.1: resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} @@ -6983,6 +6341,10 @@ packages: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-message-util@29.7.0: resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6991,6 +6353,10 @@ packages: resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@29.7.0: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7006,14 +6372,11 @@ packages: jimp-compact@0.16.1: resolution: {integrity: sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==} - joi@17.13.1: - resolution: {integrity: sha512-vaBlIKCyo4FCUtCm7Eu4QZd/q02bWcxfUO6YSXAZOWF6gzcLBeba8kwotUdYJjDLW8Cz8RywsSOqiNJZW0mNvg==} - join-component@1.1.0: resolution: {integrity: sha512-bF7vcQxbODoGK1imE2P9GS9aw4zD0Sd+Hni68IMZLj7zRnquH7dXUmMw9hDI5S/Jzt7q+IyTXN0rSg2GI0IKhQ==} - jose@4.15.5: - resolution: {integrity: sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==} + jose@4.15.9: + resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} jose@5.2.3: resolution: {integrity: sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA==} @@ -7127,8 +6490,8 @@ packages: resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==} engines: {node: '>=12.20'} - keyv@4.5.3: - resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==} + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} @@ -7182,12 +6545,8 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - libsql@0.3.19: - resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} - os: [darwin, linux, win32] - - libsql@0.4.1: - resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} + libsql@0.4.7: + resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==} os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -7199,114 +6558,52 @@ packages: cpu: [arm64] os: [darwin] - lightningcss-darwin-arm64@1.25.1: - resolution: {integrity: sha512-G4Dcvv85bs5NLENcu/s1f7ehzE3D5ThnlWSDwE190tWXRQCQaqwcuHe+MGSVI/slm0XrxnaayXY+cNl3cSricw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - lightningcss-darwin-x64@1.19.0: resolution: {integrity: sha512-Lif1wD6P4poaw9c/4Uh2z+gmrWhw/HtXFoeZ3bEsv6Ia4tt8rOJBdkfVaUJ6VXmpKHALve+iTyP2+50xY1wKPw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-darwin-x64@1.25.1: - resolution: {integrity: sha512-dYWuCzzfqRueDSmto6YU5SoGHvZTMU1Em9xvhcdROpmtOQLorurUZz8+xFxZ51lCO2LnYbfdjZ/gCqWEkwixNg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.25.1: - resolution: {integrity: sha512-hXoy2s9A3KVNAIoKz+Fp6bNeY+h9c3tkcx1J3+pS48CqAt+5bI/R/YY4hxGL57fWAIquRjGKW50arltD6iRt/w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.19.0: resolution: {integrity: sha512-P15VXY5682mTXaiDtbnLYQflc8BYb774j2R84FgDLJTN6Qp0ZjWEFyN1SPqyfTj2B2TFjRHRUvQSSZ7qN4Weig==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm-gnueabihf@1.25.1: - resolution: {integrity: sha512-tWyMgHFlHlp1e5iW3EpqvH5MvsgoN7ZkylBbG2R2LWxnvH3FuWCJOhtGcYx9Ks0Kv0eZOBud789odkYLhyf1ng==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - lightningcss-linux-arm64-gnu@1.19.0: resolution: {integrity: sha512-zwXRjWqpev8wqO0sv0M1aM1PpjHz6RVIsBcxKszIG83Befuh4yNysjgHVplF9RTU7eozGe3Ts7r6we1+Qkqsww==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-arm64-gnu@1.25.1: - resolution: {integrity: sha512-Xjxsx286OT9/XSnVLIsFEDyDipqe4BcLeB4pXQ/FEA5+2uWCCuAEarUNQumRucnj7k6ftkAHUEph5r821KBccQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - lightningcss-linux-arm64-musl@1.19.0: resolution: {integrity: sha512-vSCKO7SDnZaFN9zEloKSZM5/kC5gbzUjoJQ43BvUpyTFUX7ACs/mDfl2Eq6fdz2+uWhUh7vf92c4EaaP4udEtA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-arm64-musl@1.25.1: - resolution: {integrity: sha512-IhxVFJoTW8wq6yLvxdPvyHv4NjzcpN1B7gjxrY3uaykQNXPHNIpChLB52+wfH+yS58zm1PL4LemUp8u9Cfp6Bw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - lightningcss-linux-x64-gnu@1.19.0: resolution: {integrity: sha512-0AFQKvVzXf9byrXUq9z0anMGLdZJS+XSDqidyijI5njIwj6MdbvX2UZK/c4FfNmeRa2N/8ngTffoIuOUit5eIQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-linux-x64-gnu@1.25.1: - resolution: {integrity: sha512-RXIaru79KrREPEd6WLXfKfIp4QzoppZvD3x7vuTKkDA64PwTzKJ2jaC43RZHRt8BmyIkRRlmywNhTRMbmkPYpA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - lightningcss-linux-x64-musl@1.19.0: resolution: {integrity: sha512-SJoM8CLPt6ECCgSuWe+g0qo8dqQYVcPiW2s19dxkmSI5+Uu1GIRzyKA0b7QqmEXolA+oSJhQqCmJpzjY4CuZAg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-linux-x64-musl@1.25.1: - resolution: {integrity: sha512-TdcNqFsAENEEFr8fJWg0Y4fZ/nwuqTRsIr7W7t2wmDUlA8eSXVepeeONYcb+gtTj1RaXn/WgNLB45SFkz+XBZA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - lightningcss-win32-x64-msvc@1.19.0: resolution: {integrity: sha512-C+VuUTeSUOAaBZZOPT7Etn/agx/MatzJzGRkeV+zEABmPuntv1zihncsi+AyGmjkkzq3wVedEy7h0/4S84mUtg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss-win32-x64-msvc@1.25.1: - resolution: {integrity: sha512-9KZZkmmy9oGDSrnyHuxP6iMhbsgChUiu/NSgOx+U1I/wTngBStDf2i2aGRCHvFqj19HqqBEI4WuGVQBa2V6e0A==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - lightningcss@1.19.0: resolution: {integrity: sha512-yV5UR7og+Og7lQC+70DA7a8ta1uiOPnWPJfxa0wnxylev5qfo4P+4iMpzWAdYWOca4jdNQZii+bDL/l+4hUXIA==} engines: {node: '>= 12.0.0'} - lightningcss@1.25.1: - resolution: {integrity: sha512-V0RMVZzK1+rCHpymRv4URK2lNhIRyO8g7U7zOFwVAhJuat74HtkjIQpQRKNCwFEYkRGpafOpmXXLoaoBcyVtBg==} - engines: {node: '>= 12.0.0'} - - lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - lilconfig@3.1.2: resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} engines: {node: '>=14'} @@ -7361,14 +6658,6 @@ packages: resolution: {integrity: sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==} engines: {node: '>=4'} - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - - logkitty@0.7.1: - resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==} - hasBin: true - long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} @@ -7382,9 +6671,8 @@ packages: loupe@3.1.2: resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} - lru-cache@10.2.2: - resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} - engines: {node: 14 || >=16.14} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -7401,21 +6689,14 @@ packages: resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} engines: {node: '>=16.14'} - lru-cache@9.1.2: - resolution: {integrity: sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==} - engines: {node: 14 || >=16.14} - lru-queue@0.1.0: resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - magic-string@0.30.10: - resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} - - magic-string@0.30.11: - resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} + magic-string@0.30.12: + resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} @@ -7444,6 +6725,12 @@ packages: peerDependencies: marked: '>=1 <12' + marked-terminal@7.2.1: + resolution: {integrity: sha512-rQ1MoMFXZICWNsKMiiHwP/Z+92PLKskTPXj+e7uwXmuMPkNn7iTqC+IvDekVm1MPeC9wYQeLxeFaOvudRR/XbQ==} + engines: {node: '>=16.0.0'} + peerDependencies: + marked: '>=1 <15' + marked@9.1.6: resolution: {integrity: sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==} engines: {node: '>= 16'} @@ -7485,8 +6772,9 @@ packages: memoize-one@5.2.1: resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} - memoizee@0.4.15: - resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} + memoizee@0.4.17: + resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==} + engines: {node: '>=0.12'} memory-cache@0.2.0: resolution: {integrity: sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==} @@ -7495,8 +6783,8 @@ packages: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} - merge-descriptors@1.0.1: - resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -7509,68 +6797,64 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - metro-babel-transformer@0.80.9: - resolution: {integrity: sha512-d76BSm64KZam1nifRZlNJmtwIgAeZhZG3fi3K+EmPOlrR8rDtBxQHDSN3fSGeNB9CirdTyabTMQCkCup6BXFSQ==} - engines: {node: '>=18'} + metro-babel-transformer@0.81.0: + resolution: {integrity: sha512-Dc0QWK4wZIeHnyZ3sevWGTnnSkIDDn/SWyfrn99zbKbDOCoCYy71PAn9uCRrP/hduKLJQOy+tebd63Rr9D8tXg==} + engines: {node: '>=18.18'} - metro-cache-key@0.80.9: - resolution: {integrity: sha512-hRcYGhEiWIdM87hU0fBlcGr+tHDEAT+7LYNCW89p5JhErFt/QaAkVx4fb5bW3YtXGv5BTV7AspWPERoIb99CXg==} - engines: {node: '>=18'} + metro-cache-key@0.81.0: + resolution: {integrity: sha512-qX/IwtknP9bQZL78OK9xeSvLM/xlGfrs6SlUGgHvrxtmGTRSsxcyqxR+c+7ch1xr05n62Gin/O44QKg5V70rNQ==} + engines: {node: '>=18.18'} - metro-cache@0.80.9: - resolution: {integrity: sha512-ujEdSI43QwI+Dj2xuNax8LMo8UgKuXJEdxJkzGPU6iIx42nYa1byQ+aADv/iPh5sh5a//h5FopraW5voXSgm2w==} - engines: {node: '>=18'} + metro-cache@0.81.0: + resolution: {integrity: sha512-DyuqySicHXkHUDZFVJmh0ygxBSx6pCKUrTcSgb884oiscV/ROt1Vhye+x+OIHcsodyA10gzZtrVtxIFV4l9I4g==} + engines: {node: '>=18.18'} - metro-config@0.80.9: - resolution: {integrity: sha512-28wW7CqS3eJrunRGnsibWldqgwRP9ywBEf7kg+uzUHkSFJNKPM1K3UNSngHmH0EZjomizqQA2Zi6/y6VdZMolg==} - engines: {node: '>=18'} + metro-config@0.81.0: + resolution: {integrity: sha512-6CinEaBe3WLpRlKlYXXu8r1UblJhbwD6Gtnoib5U8j6Pjp7XxMG9h/DGMeNp9aGLDu1OieUqiXpFo7O0/rR5Kg==} + engines: {node: '>=18.18'} - metro-core@0.80.9: - resolution: {integrity: sha512-tbltWQn+XTdULkGdzHIxlxk4SdnKxttvQQV3wpqqFbHDteR4gwCyTR2RyYJvxgU7HELfHtrVbqgqAdlPByUSbg==} - engines: {node: '>=18'} + metro-core@0.81.0: + resolution: {integrity: sha512-CVkM5YCOAFkNMvJai6KzA0RpztzfEKRX62/PFMOJ9J7K0uq/UkOFLxcgpcncMIrfy0PbfEj811b69tjULUQe1Q==} + engines: {node: '>=18.18'} - metro-file-map@0.80.9: - resolution: {integrity: sha512-sBUjVtQMHagItJH/wGU9sn3k2u0nrCl0CdR4SFMO1tksXLKbkigyQx4cbpcyPVOAmGTVuy3jyvBlELaGCAhplQ==} - engines: {node: '>=18'} + metro-file-map@0.81.0: + resolution: {integrity: sha512-zMDI5uYhQCyxbye/AuFx/pAbsz9K+vKL7h1ShUXdN2fz4VUPiyQYRsRqOoVG1DsiCgzd5B6LW0YW77NFpjDQeg==} + engines: {node: '>=18.18'} - metro-minify-terser@0.80.9: - resolution: {integrity: sha512-FEeCeFbkvvPuhjixZ1FYrXtO0araTpV6UbcnGgDUpH7s7eR5FG/PiJz3TsuuPP/HwCK19cZtQydcA2QrCw446A==} - engines: {node: '>=18'} + metro-minify-terser@0.81.0: + resolution: {integrity: sha512-U2ramh3W822ZR1nfXgIk+emxsf5eZSg10GbQrT0ZizImK8IZ5BmJY+BHRIkQgHzWFpExOVxC7kWbGL1bZALswA==} + engines: {node: '>=18.18'} - metro-resolver@0.80.9: - resolution: {integrity: sha512-wAPIjkN59BQN6gocVsAvvpZ1+LQkkqUaswlT++cJafE/e54GoVkMNCmrR4BsgQHr9DknZ5Um/nKueeN7kaEz9w==} - engines: {node: '>=18'} + metro-resolver@0.81.0: + resolution: {integrity: sha512-Uu2Q+buHhm571cEwpPek8egMbdSTqmwT/5U7ZVNpK6Z2ElQBBCxd7HmFAslKXa7wgpTO2FAn6MqGeERbAtVDUA==} + engines: {node: '>=18.18'} - metro-runtime@0.80.9: - resolution: {integrity: sha512-8PTVIgrVcyU+X/rVCy/9yxNlvXsBCk5JwwkbAm/Dm+Abo6NBGtNjWF0M1Xo/NWCb4phamNWcD7cHdR91HhbJvg==} - engines: {node: '>=18'} + metro-runtime@0.81.0: + resolution: {integrity: sha512-6oYB5HOt37RuGz2eV4A6yhcl+PUTwJYLDlY9vhT+aVjbUWI6MdBCf69vc4f5K5Vpt+yOkjy+2LDwLS0ykWFwYw==} + engines: {node: '>=18.18'} - metro-source-map@0.80.9: - resolution: {integrity: sha512-RMn+XS4VTJIwMPOUSj61xlxgBvPeY4G6s5uIn6kt6HB6A/k9ekhr65UkkDD7WzHYs3a9o869qU8tvOZvqeQzgw==} - engines: {node: '>=18'} + metro-source-map@0.81.0: + resolution: {integrity: sha512-TzsVxhH83dyxg4A4+L1nzNO12I7ps5IHLjKGZH3Hrf549eiZivkdjYiq/S5lOB+p2HiQ+Ykcwtmcja95LIC62g==} + engines: {node: '>=18.18'} - metro-symbolicate@0.80.9: - resolution: {integrity: sha512-Ykae12rdqSs98hg41RKEToojuIW85wNdmSe/eHUgMkzbvCFNVgcC0w3dKZEhSsqQOXapXRlLtHkaHLil0UD/EA==} - engines: {node: '>=18'} + metro-symbolicate@0.81.0: + resolution: {integrity: sha512-C/1rWbNTPYp6yzID8IPuQPpVGzJ2rbWYBATxlvQ9dfK5lVNoxcwz77hjcY8ISLsRRR15hyd/zbjCNKPKeNgE1Q==} + engines: {node: '>=18.18'} hasBin: true - metro-transform-plugins@0.80.9: - resolution: {integrity: sha512-UlDk/uc8UdfLNJhPbF3tvwajyuuygBcyp+yBuS/q0z3QSuN/EbLllY3rK8OTD9n4h00qZ/qgxGv/lMFJkwP4vg==} - engines: {node: '>=18'} + metro-transform-plugins@0.81.0: + resolution: {integrity: sha512-uErLAPBvttGCrmGSCa0dNHlOTk3uJFVEVWa5WDg6tQ79PRmuYRwzUgLhVzn/9/kyr75eUX3QWXN79Jvu4txt6Q==} + engines: {node: '>=18.18'} - metro-transform-worker@0.80.9: - resolution: {integrity: sha512-c/IrzMUVnI0hSVVit4TXzt3A1GiUltGVlzCmLJWxNrBGHGrJhvgePj38+GXl1Xf4Fd4vx6qLUkKMQ3ux73bFLQ==} - engines: {node: '>=18'} + metro-transform-worker@0.81.0: + resolution: {integrity: sha512-HrQ0twiruhKy0yA+9nK5bIe3WQXZcC66PXTvRIos61/EASLAP2DzEmW7IxN/MGsfZegN2UzqL2CG38+mOB45vg==} + engines: {node: '>=18.18'} - metro@0.80.9: - resolution: {integrity: sha512-Bc57Xf3GO2Xe4UWQsBj/oW6YfLPABEu8jfDVDiNmJvoQW4CO34oDPuYKe4KlXzXhcuNsqOtSxpbjCRRVjhhREg==} - engines: {node: '>=18'} + metro@0.81.0: + resolution: {integrity: sha512-kzdzmpL0gKhEthZ9aOV7sTqvg6NuTxDV8SIm9pf9sO8VVEbKrQk5DNcwupOUjgPPFAuKUc2NkT0suyT62hm2xg==} + engines: {node: '>=18.18'} hasBin: true - micromatch@4.0.7: - resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} - engines: {node: '>=8.6'} - micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -7588,11 +6872,6 @@ packages: engines: {node: '>=4'} hasBin: true - mime@2.6.0: - resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} - engines: {node: '>=4.0.0'} - hasBin: true - mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -7618,8 +6897,8 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - miniflare@3.20240712.0: - resolution: {integrity: sha512-zVbsMX2phvJS1uTPmjK6CvVBq4ON2UkmvTw9IMfNPACsWJmHEdsBDxsYEG1vKAduJdI5gULLuJf7qpFxByDhGw==} + miniflare@3.20241022.0: + resolution: {integrity: sha512-x9Fbq1Hmz1f0osIT9Qmj78iX4UpCP2EqlZnA/tzj/3+I49vc3Kq0fNqSSKplcdf6HlCHdL3fOBicmreQF4BUUQ==} engines: {node: '>=16.13'} hasBin: true @@ -7634,8 +6913,12 @@ packages: resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} engines: {node: '>=10'} - minimatch@9.0.4: - resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} + minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: @@ -7693,8 +6976,8 @@ packages: engines: {node: '>=10'} hasBin: true - mlly@1.7.0: - resolution: {integrity: sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==} + mlly@1.7.2: + resolution: {integrity: sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==} mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} @@ -7717,14 +7000,6 @@ packages: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true - mv@2.1.1: - resolution: {integrity: sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==} - engines: {node: '>=0.8.0'} - - mysql2@3.11.0: - resolution: {integrity: sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==} - engines: {node: '>= 8.0'} - mysql2@3.3.3: resolution: {integrity: sha512-MxDQJztArk4JFX1PKVjDhIXRzAmVJfuqZrVU+my6NeYBAA/XZRaDw5q7vga8TNvgyy3Lv3rivBFBBuJFbsdjaw==} engines: {node: '>= 8.0'} @@ -7736,8 +7011,8 @@ packages: resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} engines: {node: '>=12.0.0'} - nan@2.19.0: - resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} + nan@2.22.0: + resolution: {integrity: sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==} nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} @@ -7750,14 +7025,14 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - ncp@2.0.0: - resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==} - hasBin: true - negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -7773,20 +7048,15 @@ packages: nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} - nocache@3.0.4: - resolution: {integrity: sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==} - engines: {node: '>=12.0.0'} - - node-abi@3.62.0: - resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==} + node-abi@3.71.0: + resolution: {integrity: sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==} engines: {node: '>=10'} node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - node-addon-api@7.1.0: - resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==} - engines: {node: ^16 || ^18 || >= 20} + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} node-dir@0.1.17: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} @@ -7800,9 +7070,6 @@ packages: resolution: {integrity: sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==} engines: {node: '>=18'} - node-fetch-native@1.6.4: - resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} - node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -7824,8 +7091,8 @@ packages: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} - node-gyp-build@4.8.1: - resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} + node-gyp-build@4.8.2: + resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==} hasBin: true node-gyp@8.4.1: @@ -7836,12 +7103,8 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - - node-stream-zip@1.15.0: - resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} - engines: {node: '>=0.12.0'} + node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} nofilter@3.1.0: resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} @@ -7888,9 +7151,9 @@ packages: nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} - ob1@0.80.9: - resolution: {integrity: sha512-v9yOxowkZbxWhKOaaTyLjIm1aLy4ebMNcSn4NYJKOAI/Qv+SkfEfszpLr2GIxsccmb2Y2HA9qtsqiIJ80ucpVA==} - engines: {node: '>=18'} + ob1@0.81.0: + resolution: {integrity: sha512-6Cvrkxt1tqaRdWqTAMcVYEiO5i1xcF9y7t06nFdjFqkfPsEloCf8WwhXdwBpNUkVYSQlSGS7cDgVQR86miBfBQ==} + engines: {node: '>=18.18'} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} @@ -7900,38 +7163,36 @@ packages: resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} engines: {node: '>= 6'} - object-inspect@1.12.3: - resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} - - object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - object.assign@4.1.4: - resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} - engines: {node: '>= 0.4'} - object.assign@4.1.5: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} - object.fromentries@2.0.6: - resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} - object.groupby@1.0.0: - resolution: {integrity: sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==} + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} - object.values@1.1.6: - resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} + object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + ohash@1.1.4: + resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} + ohm-js@17.1.0: resolution: {integrity: sha512-xc3B5dgAjTBQGHaH7B58M2Pmv6WvzrJ/3/7LeUzXNg0/sY3jQPdSd/S2SstppaleO77rifR1tyhdfFGNIwxf2Q==} engines: {node: '>=0.12.1'} @@ -7948,10 +7209,6 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} - on-headers@1.0.2: - resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -7967,10 +7224,6 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} - open@6.4.0: - resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==} - engines: {node: '>=8'} - open@7.4.2: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} @@ -7982,18 +7235,14 @@ packages: openid-client@5.6.4: resolution: {integrity: sha512-T1h3B10BRPKfcObdBklX639tVz+xh34O7GjofqrqiAQdm7eHsQ00ih18x6wuJ/E6FxdtS2u3FmUGPDeEcMwzNA==} - optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} ora@3.4.0: resolution: {integrity: sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==} engines: {node: '>=6'} - ora@5.4.1: - resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} - engines: {node: '>=10'} - os-homedir@1.0.2: resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} engines: {node: '>=0.10.0'} @@ -8014,10 +7263,18 @@ packages: resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-event@6.0.1: + resolution: {integrity: sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==} + engines: {node: '>=16.17'} + p-filter@3.0.0: resolution: {integrity: sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-filter@4.1.0: + resolution: {integrity: sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==} + engines: {node: '>=18'} + p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} @@ -8066,14 +7323,25 @@ packages: resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==} engines: {node: '>=16'} + p-map@7.0.2: + resolution: {integrity: sha512-z4cYYMMdKHzw4O5UkWJImbZynVIo0lSGTXc7bzB1e/rrDqkgGUNysK/o4bTr+0+xKvvLoTyGqYC4Fgljy9qe1Q==} + engines: {node: '>=18'} + p-timeout@5.1.0: resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} engines: {node: '>=12'} + p-timeout@6.1.3: + resolution: {integrity: sha512-UJUyfKbwvr/uZSV6btANfb+0t/mOhKV/KXcCUTp8FcQI+v/0d+wXqH4htrW0E4rR6WiEO/EPvUFiV9D5OI4vlw==} + engines: {node: '>=14.16'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -8097,6 +7365,15 @@ packages: resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==} engines: {node: '>=10'} + parse5-htmlparser2-tree-adapter@6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + + parse5@5.1.1: + resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -8135,24 +7412,24 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-scurry@1.10.1: - resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} - engines: {node: '>=16 || 14 >=14.17'} - path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-to-regexp@0.1.7: - resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + path-to-regexp@0.1.10: + resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} - path-to-regexp@6.2.2: - resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + path-type@5.0.0: + resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} + engines: {node: '>=12'} + pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} @@ -8172,8 +7449,8 @@ packages: pg-connection-string@2.6.1: resolution: {integrity: sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==} - pg-connection-string@2.6.4: - resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} + pg-connection-string@2.7.0: + resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==} pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} @@ -8183,13 +7460,13 @@ packages: resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} engines: {node: '>=4'} - pg-pool@3.6.2: - resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==} + pg-pool@3.7.0: + resolution: {integrity: sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==} peerDependencies: pg: '>=8.0' - pg-protocol@1.6.1: - resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==} + pg-protocol@1.7.0: + resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==} pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} @@ -8199,8 +7476,8 @@ packages: resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} engines: {node: '>=10'} - pg@8.11.5: - resolution: {integrity: sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==} + pg@8.13.1: + resolution: {integrity: sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==} engines: {node: '>= 8.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -8211,11 +7488,8 @@ packages: pgpass@1.0.5: resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - - picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -8225,6 +7499,10 @@ packages: resolution: {integrity: sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==} engines: {node: '>=10'} + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} @@ -8241,8 +7519,8 @@ packages: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} - pkg-types@1.1.0: - resolution: {integrity: sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA==} + pkg-types@1.2.1: + resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} plist@3.1.0: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} @@ -8264,8 +7542,8 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} - postcss-load-config@4.0.1: - resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} + postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} engines: {node: '>= 14'} peerDependencies: postcss: '>=8.0.9' @@ -8294,12 +7572,8 @@ packages: yaml: optional: true - postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} - engines: {node: ^10 || ^12 || >=14} - - postcss@8.4.39: - resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} + postcss@8.4.47: + resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -8337,8 +7611,8 @@ packages: postgres-range@1.1.4: resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} - postgres@3.4.4: - resolution: {integrity: sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==} + postgres@3.4.5: + resolution: {integrity: sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg==} engines: {node: '>=12'} pouchdb-collections@1.0.1: @@ -8362,8 +7636,8 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.0.3: - resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} hasBin: true @@ -8371,9 +7645,9 @@ packages: resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} engines: {node: '>=6'} - pretty-format@26.6.2: - resolution: {integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==} - engines: {node: '>= 10'} + pretty-format@24.9.0: + resolution: {integrity: sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==} + engines: {node: '>= 6'} pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} @@ -8438,30 +7712,24 @@ packages: engines: {node: '>= 0.10'} hasBin: true - pump@3.0.0: - resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} - - punycode@2.3.0: - resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} - engines: {node: '>=6'} + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qrcode-terminal@0.11.0: resolution: {integrity: sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==} hasBin: true - qs@6.11.0: - resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} - querystring@0.2.1: - resolution: {integrity: sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==} - engines: {node: '>=0.4.x'} - deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -8483,28 +7751,22 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - react-devtools-core@5.2.0: - resolution: {integrity: sha512-vZK+/gvxxsieAoAyYaiRIVFxlajb7KXhgBDV7OsoMzaAE+IqGpoxusBjIgq5ibqA2IloKu0p9n7tE68z1xs18A==} + react-devtools-core@5.3.2: + resolution: {integrity: sha512-crr9HkVrDiJ0A4zot89oS0Cgv0Oa4OG1Em4jit3P3ZxZSKPMYyMjfwMqgcJna9o625g8oN87rBm8SWWrSTBZxg==} react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - - react-is@18.2.0: - resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-native@0.74.1: - resolution: {integrity: sha512-0H2XpmghwOtfPpM2LKqHIN7gxy+7G/r1hwJHKLV6uoyXGC/gCojRtoo5NqyKrWpFC8cqyT6wTYCLuG7CxEKilg==} + react-native@0.76.1: + resolution: {integrity: sha512-z4KnbrnnAvloRs9NGnah3u6/LK3IbtNMrvByxa3ifigbMlsMY4WPRYV9lvt/hH4Mzt8bfuI+utnOxFyJTTq3lg==} engines: {node: '>=18'} hasBin: true peerDependencies: '@types/react': ^18.2.6 - react: 18.2.0 + react: ^18.2.0 peerDependenciesMeta: '@types/react': optional: true @@ -8513,11 +7775,6 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} - react-shallow-renderer@16.15.0: - resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} - peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -8541,6 +7798,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.0.2: + resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} + engines: {node: '>= 14.16.0'} + readline@1.3.0: resolution: {integrity: sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==} @@ -8559,8 +7820,8 @@ packages: redeyed@2.1.1: resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==} - regenerate-unicode-properties@10.1.1: - resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} + regenerate-unicode-properties@10.2.0: + resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} engines: {node: '>=4'} regenerate@1.4.2: @@ -8569,9 +7830,6 @@ packages: regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - regenerator-runtime@0.14.0: - resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} - regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -8582,24 +7840,23 @@ packages: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true - regexp.prototype.flags@1.5.0: - resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} + regexp.prototype.flags@1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} engines: {node: '>= 0.4'} - regexp.prototype.flags@1.5.2: - resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} - engines: {node: '>= 0.4'} - - regexpu-core@5.3.2: - resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} + regexpu-core@6.1.1: + resolution: {integrity: sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==} engines: {node: '>=4'} + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + regjsparser@0.10.0: resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} hasBin: true - regjsparser@0.9.1: - resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} + regjsparser@0.11.2: + resolution: {integrity: sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==} hasBin: true remove-trailing-slash@0.1.1: @@ -8613,9 +7870,6 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - requireg@0.2.2: resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==} engines: {node: '>= 4.0.0'} @@ -8639,8 +7893,8 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve-tspaths@0.8.16: - resolution: {integrity: sha512-5c90plgcKFcCk66Ve1vFh6tm0fLKmSz6vaW4CezP6i69Q8fgWX3YGPYmKPEughem+nPHT1358P+rXrhw5pibwg==} + resolve-tspaths@0.8.22: + resolution: {integrity: sha512-x9loBJyTLdx3grlcNpH/Y2t8IkfadtbzYhzpo683C6olazn0/4Y3cfSBiqDA0f2vSmq5tITKJCN9e1ezBh6jhA==} hasBin: true peerDependencies: typescript: '>=3.0.3' @@ -8649,18 +7903,6 @@ packages: resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} engines: {node: '>=10'} - resolve@1.22.1: - resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} - hasBin: true - - resolve@1.22.2: - resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} - hasBin: true - - resolve@1.22.4: - resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} - hasBin: true - resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -8672,10 +7914,6 @@ packages: resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==} engines: {node: '>=4'} - restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} - retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} @@ -8688,29 +7926,18 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@2.4.5: - resolution: {integrity: sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rimraf@5.0.0: - resolution: {integrity: sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==} - engines: {node: '>=14'} + rimraf@5.0.10: + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} hasBin: true rollup-plugin-inject@3.0.2: @@ -8723,23 +7950,13 @@ packages: rollup-pluginutils@2.8.2: resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - rollup@3.20.7: - resolution: {integrity: sha512-P7E2zezKSLhWnTz46XxjSmInrbOCiul1yf+kJccMxT56vxjHwCbDfoLbiqFgu+WQoo9ij2PkraYaBstgB2prBA==} - engines: {node: '>=14.18.0', npm: '>=8.0.0'} - hasBin: true - - rollup@3.27.2: - resolution: {integrity: sha512-YGwmHf7h2oUHkVBT248x0yt6vZkYQ3/rvE5iQuVBh3WO8GcJ6BNeOkpoX1yMHIiBm18EMLjBPIoUDkhgnyxGOQ==} + rollup@3.29.5: + resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true - rollup@4.18.0: - resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - rollup@4.18.1: - resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==} + rollup@4.24.4: + resolution: {integrity: sha512-vGorVWIsWfX3xbcyAS+I047kFKapHYivmkaT63Smj77XwvLSJos6M1xGqZnBPFQFBRZDOcG1QnYEIxAvTr/HjA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -8753,10 +7970,6 @@ packages: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} - safe-array-concat@1.0.0: - resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==} - engines: {node: '>=0.4'} - safe-array-concat@1.1.2: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} @@ -8767,12 +7980,6 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-json-stringify@1.2.0: - resolution: {integrity: sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==} - - safe-regex-test@1.0.0: - resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} - safe-regex-test@1.0.3: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} @@ -8798,8 +8005,8 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.6.2: - resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true @@ -8807,6 +8014,10 @@ packages: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + seq-queue@0.0.5: resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} @@ -8818,18 +8029,18 @@ packages: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} - serialize-javascript@6.0.1: - resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==} + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - serve-static@1.15.0: - resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-cookie-parser@2.6.0: - resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} @@ -8868,9 +8079,6 @@ packages: shell-quote@1.8.1: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} - side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} - side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} @@ -8881,10 +8089,6 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - signal-exit@4.0.2: - resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} - engines: {node: '>=14'} - signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -8917,9 +8121,9 @@ packages: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} - slice-ansi@2.1.0: - resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} - engines: {node: '>=6'} + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} @@ -8933,8 +8137,8 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - smob@0.0.6: - resolution: {integrity: sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw==} + smob@1.5.0: + resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} socks-proxy-agent@6.2.1: resolution: {integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==} @@ -8944,8 +8148,8 @@ packages: resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} source-map-support@0.5.21: @@ -8959,10 +8163,6 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - source-map@0.7.4: - resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} - engines: {node: '>= 8'} - source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} @@ -8977,14 +8177,14 @@ packages: spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - spdx-exceptions@2.3.0: - resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - spdx-license-ids@3.0.13: - resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} + spdx-license-ids@3.0.20: + resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} split-ca@1.0.1: resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} @@ -9008,8 +8208,8 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - sql.js@1.10.3: - resolution: {integrity: sha512-H46aWtQkdyjZwFQgraUruy5h/DyJBbAK3EA/WEMqiqF6PGPfKBSKBj/er3dVyYqVIoYfRf5TFM/loEjtQIrqJg==} + sql.js@1.12.0: + resolution: {integrity: sha512-Bi+43yMx/tUFZVYD4AUscmdL6NHn3gYQ+CM+YheFWLftOmrEC/Mz6Yh7E96Y2WDHYz3COSqT+LP6Z79zgrwJlA==} sqlite3@5.1.7: resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==} @@ -9018,8 +8218,8 @@ packages: resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} engines: {node: '>= 0.6'} - ssh2@1.15.0: - resolution: {integrity: sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==} + ssh2@1.16.0: + resolution: {integrity: sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==} engines: {node: '>=10.16.0'} ssri@10.0.6: @@ -9030,8 +8230,42 @@ packages: resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} engines: {node: '>= 8'} - sst@3.0.14: - resolution: {integrity: sha512-MC93uHwMxM1uwDg9Old8qo8LsmhvrMD3YFkS5Me8ThozwFIKzwqXicJWTE3iL+0DkPSPhdiSxafRdKhu/Qk5DA==} + sst-darwin-arm64@3.3.5: + resolution: {integrity: sha512-kHQcmGhNMbIIhgz49Ejki6zp5TiCRwHaf+3c13GOzMrCIng2GixboGoNjMBFdSwXogQcJBc0BBOQo1oxmr4CxQ==} + cpu: [arm64] + os: [darwin] + + sst-darwin-x64@3.3.5: + resolution: {integrity: sha512-jouPGqUjlfMpwOyBzbYMMW/ezRlAqte4BnzASdPG7Cr23jX8Hl06yVFSzFAougfFA3vBnln6qCgLtNP/vDqCew==} + cpu: [x64] + os: [darwin] + + sst-linux-arm64@3.3.5: + resolution: {integrity: sha512-0fl7cR80bqScR1SS6iAAab4tjaT3M2dQCfjl0aTaBTeI+DmTD+SbteGcVwkQaXjcETuIUEKUAFd6F5EF0LewlA==} + cpu: [arm64] + os: [linux] + + sst-linux-x64@3.3.5: + resolution: {integrity: sha512-Et6DMlp8UGsUlToeMzWpEfRpxiYexMmnbfNd+usZMq7kC2or8Ze6ec3HR6Mm2pXjcwEZ6GUZRPWATWfqH7yNmw==} + cpu: [x64] + os: [linux] + + sst-linux-x86@3.3.5: + resolution: {integrity: sha512-ZjW1gkBbGRjCiCaZg+NBEeVwQ9/NFr5BjxLbwMX0zDwwDUim9W/PC89sHYZO9KnJX3D39+X8QC11vRnxpYQkNw==} + cpu: [x86] + os: [linux] + + sst@3.3.5: + resolution: {integrity: sha512-YqiDtvCFPfztusQbOU974R8WwGJNLs33X57NuVwUYCH9miMlw0Rz/hWMlwR9uMyQm7b6vc+Sf1kBPqy5iuPk6w==} + hasBin: true + peerDependencies: + hono: 4.x + valibot: 0.30.x + peerDependenciesMeta: + hono: + optional: true + valibot: + optional: true stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} @@ -9084,23 +8318,13 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} - string.prototype.trim@1.2.7: - resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} - engines: {node: '>= 0.4'} - string.prototype.trim@1.2.9: resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} - string.prototype.trimend@1.0.6: - resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} - string.prototype.trimend@1.0.8: resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} - string.prototype.trimstart@1.0.6: - resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} - string.prototype.trimstart@1.0.8: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} @@ -9176,9 +8400,6 @@ packages: sudo-prompt@9.1.1: resolution: {integrity: sha512-es33J1g2HjMpyAhz8lOR+ICmXXAqTuKbuXuUWLhOLew20oN9oUCgCJx615U/v7aioZg7IX5lIh9x34vwneu4pA==} - sudo-prompt@9.2.1: - resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==} - superjson@2.2.1: resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} engines: {node: '>=16'} @@ -9203,16 +8424,16 @@ packages: resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} engines: {node: '>=8'} - supports-hyperlinks@3.0.0: - resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} + supports-hyperlinks@3.1.0: + resolution: {integrity: sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==} engines: {node: '>=14.18'} supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - synckit@0.9.1: - resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} + synckit@0.9.2: + resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} engines: {node: ^14.18.0 || >=16.0.0} tar-fs@2.0.1: @@ -9261,15 +8482,14 @@ packages: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} engines: {node: '>=8'} - terser@5.17.1: - resolution: {integrity: sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==} + terser@5.36.0: + resolution: {integrity: sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==} engines: {node: '>=10'} hasBin: true - terser@5.31.0: - resolution: {integrity: sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==} - engines: {node: '>=10'} - hasBin: true + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -9301,8 +8521,9 @@ packages: resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} engines: {node: '>=4'} - timers-ext@0.1.7: - resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==} + timers-ext@0.1.8: + resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==} + engines: {node: '>=0.12'} tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -9310,14 +8531,15 @@ packages: tiny-queue@0.2.1: resolution: {integrity: sha512-EijGsv7kzd9I9g0ByCl6h42BWNGUZrlCSejfrb3AKeHC33SGbASu1VDf5O3rRiiUOhAC9CHdZxFPbZu0HmR70A==} - tinybench@2.8.0: - resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} - tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.0: - resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} + tinyexec@0.3.1: + resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} + + tinyglobby@0.2.10: + resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} + engines: {node: '>=12.0.0'} tinypool@0.8.4: resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} @@ -9368,8 +8590,8 @@ packages: tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - traverse@0.6.9: - resolution: {integrity: sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg==} + traverse@0.6.10: + resolution: {integrity: sha512-hN4uFRxbK+PX56DxYiGHsTn2dME3TVr9vbNqlQGcGcPhJAn+tdP126iA+TArMpI4YSgnTkMWyoLl5bf81Hi5TA==} engines: {node: '>= 0.4'} tree-kill@1.2.2: @@ -9380,14 +8602,12 @@ packages: resolution: {integrity: sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==} engines: {node: '>=0.6'} - ts-api-utils@1.0.3: - resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} - engines: {node: '>=16.13.0'} - peerDependencies: - typescript: '>=4.2.0' + trim-right@1.0.1: + resolution: {integrity: sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==} + engines: {node: '>=0.10.0'} - ts-api-utils@1.3.0: - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + ts-api-utils@1.4.0: + resolution: {integrity: sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' @@ -9412,8 +8632,8 @@ packages: '@swc/wasm': optional: true - tsconfck@3.0.3: - resolution: {integrity: sha512-4t0noZX9t6GcPTfBAbIbbIU4pfpCwh0ueq3S4O/5qXI1VwK1outmxhe9dOiEWqMz3MW2LKgDTpqWV+37IWuVbA==} + tsconfck@3.1.4: + resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} engines: {node: ^18 || >=20} hasBin: true peerDependencies: @@ -9422,23 +8642,24 @@ packages: typescript: optional: true - tsconfig-paths@3.14.2: - resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsup@7.2.0: - resolution: {integrity: sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==} - engines: {node: '>=16.14'} + tsup@7.3.0: + resolution: {integrity: sha512-Ja1eaSRrE+QarmATlNO5fse2aOACYMBX+IZRKy1T+gpyH+jXgRrl5l4nHIQJQ1DoDgEjHDTw8cpE085UdBZuWQ==} + engines: {node: '>=18'} + deprecated: Breaking node 16 hasBin: true peerDependencies: '@swc/core': ^1 postcss: ^8.4.12 - typescript: '>=4.1.0' + typescript: '>=4.5.0' peerDependenciesMeta: '@swc/core': optional: true @@ -9447,8 +8668,8 @@ packages: typescript: optional: true - tsup@8.1.2: - resolution: {integrity: sha512-Gzw/PXSX/z0aYMNmkcI54bKKFVFJQbLne+EqTJZeQ3lNT3QpumjtMU4rl+ZwTTp8oRF3ahMbEAxT2sZPJLFSrg==} + tsup@8.3.5: + resolution: {integrity: sha512-Tunf6r6m6tnZsG9GYWndg0z8dEV7fD733VBFzFJ5Vcm1FtlXB8xBD/rtrBi2a3YKEV7hHtxiZtW5EAVADoe1pA==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -9476,13 +8697,8 @@ packages: resolution: {integrity: sha512-xHtFaKtHxM9LOklMmJdI3BEnQq/D5F73Of2E1GDrITi9sgoVkvIsrQUTY1G8FlmGtA+awCI4EBlTRRYxkL2sRg==} hasBin: true - tsx@4.10.5: - resolution: {integrity: sha512-twDSbf7Gtea4I2copqovUiNTEDrT8XNFXsuHpfGbdpW/z9ZW4fTghzzhAG0WfrCuJmJiOEY1nLIjq4u3oujRWQ==} - engines: {node: '>=18.0.0'} - hasBin: true - - tsx@4.16.2: - resolution: {integrity: sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==} + tsx@4.19.2: + resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} engines: {node: '>=18.0.0'} hasBin: true @@ -9534,6 +8750,10 @@ packages: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} + type-detect@4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} + engines: {node: '>=4'} + type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} @@ -9566,47 +8786,25 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} - type-fest@3.13.1: - resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} - engines: {node: '>=14.16'} - type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - type@1.2.0: - resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} - - type@2.7.2: - resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} - - typed-array-buffer@1.0.0: - resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} - engines: {node: '>= 0.4'} + type@2.7.3: + resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} - typed-array-byte-length@1.0.0: - resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} - engines: {node: '>= 0.4'} - typed-array-byte-length@1.0.1: resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} engines: {node: '>= 0.4'} - typed-array-byte-offset@1.0.0: - resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} - engines: {node: '>= 0.4'} - typed-array-byte-offset@1.0.2: resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} engines: {node: '>= 0.4'} - typed-array-length@1.0.4: - resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} - typed-array-length@1.0.6: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} @@ -9615,26 +8813,27 @@ packages: resolution: {integrity: sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A==} engines: {node: '>= 0.4'} - typescript@5.2.2: - resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.3.3: resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} hasBin: true + typescript@5.6.1-rc: + resolution: {integrity: sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ==} + engines: {node: '>=14.17'} + hasBin: true + typescript@5.6.3: resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} hasBin: true - ua-parser-js@1.0.38: - resolution: {integrity: sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==} + ua-parser-js@1.0.39: + resolution: {integrity: sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw==} + hasBin: true - ufo@1.5.3: - resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} + ufo@1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -9642,15 +8841,18 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici@5.28.4: resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} engines: {node: '>=14.0'} - unenv-nightly@1.10.0-1717606461.a117952: - resolution: {integrity: sha512-u3TfBX02WzbHTpaEfWEKwDijDSFAHcgXkayUZ+MVDrjhLFvgAJzFGTSTmwlEhwWi2exyRQey23ah9wELMM6etg==} + unenv-nightly@2.0.0-20241024-111401-d4156ac: + resolution: {integrity: sha512-xJO1hfY+Te+/XnfCYrCbFbRcgu6XEODND1s5wnVbaBCkuQX7JXF7fHEXPrukFE2j8EOH848P8QN19VO47XN8hw==} - unicode-canonical-property-names-ecmascript@2.0.0: - resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} unicode-emoji-modifier-base@1.0.0: @@ -9661,14 +8863,18 @@ packages: resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} engines: {node: '>=4'} - unicode-match-property-value-ecmascript@2.1.0: - resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} + unicode-match-property-value-ecmascript@2.2.0: + resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} engines: {node: '>=4'} unicode-property-aliases-ecmascript@2.1.0: resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} engines: {node: '>=4'} + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + unique-filename@1.1.1: resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} @@ -9699,10 +8905,6 @@ packages: resolution: {integrity: sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==} engines: {node: '>= 10.0.0'} - universalify@2.0.0: - resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} - engines: {node: '>= 10.0.0'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -9711,8 +8913,8 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - update-browserslist-db@1.0.16: - resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -9737,6 +8939,10 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + uuid@7.0.3: resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==} hasBin: true @@ -9773,8 +8979,8 @@ packages: resolution: {integrity: sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - validate-npm-package-name@5.0.0: - resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==} + validate-npm-package-name@5.0.1: + resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} vary@1.1.2: @@ -9786,8 +8992,8 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite-node@2.1.2: - resolution: {integrity: sha512-HPcGNN5g/7I2OtPjLqgOtCRu/qhVvBxTUD3qzitmL0SrG1cWFzxzhMDWussxSbrRYWqnKf8P2jiNhPMSN+ymsQ==} + vite-node@2.1.4: + resolution: {integrity: sha512-kqa9v+oi4HwkG6g8ufRnb5AeplcRw8jUF6/7/Qz1qRQOXHImG8YnLbB+LLszENwFnoBl9xIf9nVdCFzNd7GQEg==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -9799,8 +9005,8 @@ packages: vite: optional: true - vite@5.2.12: - resolution: {integrity: sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==} + vite@5.4.10: + resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -9808,6 +9014,7 @@ packages: less: '*' lightningcss: ^1.21.0 sass: '*' + sass-embedded: '*' stylus: '*' sugarss: '*' terser: ^5.4.0 @@ -9820,33 +9027,7 @@ packages: optional: true sass: optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - - vite@5.3.3: - resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: + sass-embedded: optional: true stylus: optional: true @@ -9880,15 +9061,15 @@ packages: jsdom: optional: true - vitest@2.1.2: - resolution: {integrity: sha512-veNjLizOMkRrJ6xxb+pvxN6/QAWg95mzcRjtmkepXdN87FNfxAss9RKe2far/G9cQpipfgP2taqg0KiWsquj8A==} + vitest@2.1.4: + resolution: {integrity: sha512-eDjxbVAJw1UJJCHr5xr/xM86Zx+YxIEXGAR+bmnEID7z9qWfoxpHw0zdobz+TQAFOLT+nEXz3+gx6nUJ7RgmlQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.1.2 - '@vitest/ui': 2.1.2 + '@vitest/browser': 2.1.4 + '@vitest/ui': 2.1.4 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -9914,8 +9095,8 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - web-streams-polyfill@3.2.1: - resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} webidl-conversions@3.0.1: @@ -9952,13 +9133,6 @@ packages: which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - - which-typed-array@1.1.11: - resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} - engines: {node: '>= 0.4'} - which-typed-array@1.1.15: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} @@ -9977,11 +9151,6 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} hasBin: true - why-is-node-running@2.2.2: - resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} - engines: {node: '>=8'} - hasBin: true - why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -9993,28 +9162,28 @@ packages: wonka@4.0.15: resolution: {integrity: sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==} + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - workerd@1.20240712.0: - resolution: {integrity: sha512-hdIHZif82hBDy9YnMtcmDGgbLU5f2P2aGpi/X8EKhTSLDppVUGrkY3XB536J4jGjA2D5dS0FUEXCl5bAJEed8Q==} + workerd@1.20241022.0: + resolution: {integrity: sha512-jyGXsgO9DRcJyx6Ovv7gUyDPc3UYC2i/E0p9GFUg6GUzpldw4Y93y9kOmdfsOnKZ3+lY53veSiUniiBPE6Q2NQ==} engines: {node: '>=16'} hasBin: true - wrangler@3.65.0: - resolution: {integrity: sha512-IDy4ttyJZssazAd5CXHw4NWeZFGxngdNF5m2ogltdT3CV7uHfCvPVdMcr4uNMpRZd0toHmAE3LtQeXxDFFp88A==} + wrangler@3.85.0: + resolution: {integrity: sha512-r5YCWUaF4ApLnloNE6jHHgRYdFzYHoajTlC1tns42UzQ2Ls63VAqD3b0cxOqzDUfmlSb3skpmu0B0Ssi3QWPAg==} engines: {node: '>=16.17.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20240712.0 + '@cloudflare/workers-types': ^4.20241022.0 peerDependenciesMeta: '@cloudflare/workers-types': optional: true - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -10029,12 +9198,16 @@ packages: write-file-atomic@2.4.3: resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + write-file-atomic@5.0.1: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - ws@6.2.2: - resolution: {integrity: sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==} + ws@6.2.3: + resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -10044,8 +9217,8 @@ packages: utf-8-validate: optional: true - ws@7.5.9: - resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 @@ -10068,18 +9241,6 @@ packages: utf-8-validate: optional: true - ws@8.17.0: - resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -10119,9 +9280,6 @@ packages: xxhash-wasm@1.0.2: resolution: {integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==} - y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -10132,19 +9290,11 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yaml@2.3.1: - resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} - engines: {node: '>= 14'} - - yaml@2.4.2: - resolution: {integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==} + yaml@2.6.0: + resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==} engines: {node: '>= 14'} hasBin: true - yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} - yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -10153,10 +9303,6 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} - yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} @@ -10173,27 +9319,33 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-queue@1.0.0: - resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + yocto-queue@1.1.1: + resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==} engines: {node: '>=12.20'} - youch@3.3.3: - resolution: {integrity: sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==} + youch@3.3.4: + resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} - zod@3.21.4: - resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} + zod-validation-error@2.1.0: + resolution: {integrity: sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.18.0 - zod@3.23.7: - resolution: {integrity: sha512-NBeIoqbtOiUMomACV/y+V3Qfs9+Okr18vR5c/5pHClPpufWOrsx8TENboDPe265lFdfewX2yBtNTLPvnmCxwog==} + zod@3.23.8: + resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} - zx@7.2.2: - resolution: {integrity: sha512-50Gjicd6ijTt7Zcz5fNX+rHrmE0uVqC+X6lYKhf2Cu8wIxDpNIzXwTmzchNdW+JY3LFsRcU43B1lHE4HBMmKgQ==} + zx@7.2.3: + resolution: {integrity: sha512-QODu38nLlYXg/B/Gw7ZKiZrvPkEsjPN3LQ5JFXM7h0JvwhEdPNNl+4Ao1y4+o3CLNiDUNcwzQYZ4/Ko7kKzCMA==} engines: {node: '>= 16.0.0'} hasBin: true -snapshots: + zx@8.2.0: + resolution: {integrity: sha512-ec7Z1Ki9h4CsKqbMjZ8H7G1PbbZYErscxT314LF66Ljx1YRENisqa5m9IN2VjbYgOKxdv5t0MbVd3Hf+II3e7w==} + engines: {node: '>= 12.17.0'} + hasBin: true - '@aashutoshrathi/word-wrap@1.2.6': {} +snapshots: '@ampproject/remapping@2.3.0': dependencies: @@ -10206,2234 +9358,1494 @@ snapshots: dependencies: '@arethetypeswrong/core': 0.15.1 chalk: 4.1.2 - cli-table3: 0.6.3 + cli-table3: 0.6.5 commander: 10.0.1 marked: 9.1.6 marked-terminal: 6.2.0(marked@9.1.6) - semver: 7.6.2 + semver: 7.6.3 + + '@arethetypeswrong/cli@0.16.4': + dependencies: + '@arethetypeswrong/core': 0.16.4 + chalk: 4.1.2 + cli-table3: 0.6.5 + commander: 10.0.1 + marked: 9.1.6 + marked-terminal: 7.2.1(marked@9.1.6) + semver: 7.6.3 '@arethetypeswrong/core@0.15.1': dependencies: '@andrewbranch/untar.js': 1.0.3 fflate: 0.8.2 - semver: 7.6.2 + semver: 7.6.3 ts-expose-internals-conditionally: 1.0.0-empty.0 typescript: 5.3.3 - validate-npm-package-name: 5.0.0 - - '@ava/typescript@5.0.0': - dependencies: - escape-string-regexp: 5.0.0 - execa: 8.0.1 - optional: true - - '@aws-crypto/crc32@3.0.0': - dependencies: - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.577.0 - tslib: 1.14.1 - - '@aws-crypto/ie11-detection@3.0.0': - dependencies: - tslib: 1.14.1 + validate-npm-package-name: 5.0.1 - '@aws-crypto/sha256-browser@3.0.0': + '@arethetypeswrong/core@0.16.4': dependencies: - '@aws-crypto/ie11-detection': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-crypto/supports-web-crypto': 3.0.0 - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-locate-window': 3.568.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 + '@andrewbranch/untar.js': 1.0.3 + cjs-module-lexer: 1.4.1 + fflate: 0.8.2 + lru-cache: 10.4.3 + semver: 7.6.3 + typescript: 5.6.1-rc + validate-npm-package-name: 5.0.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.686.0 + '@aws-sdk/util-locate-window': 3.679.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 - '@aws-crypto/sha256-js@3.0.0': + '@aws-crypto/sha256-js@5.2.0': dependencies: - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.577.0 - tslib: 1.14.1 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.686.0 + tslib: 2.8.1 - '@aws-crypto/supports-web-crypto@3.0.0': + '@aws-crypto/supports-web-crypto@5.2.0': dependencies: - tslib: 1.14.1 + tslib: 2.8.1 - '@aws-crypto/util@3.0.0': + '@aws-crypto/util@5.2.0': dependencies: - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - - '@aws-sdk/client-cognito-identity@3.569.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/client-sts': 3.569.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 + '@aws-sdk/types': 3.686.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-lambda@3.478.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.478.0 - '@aws-sdk/core': 3.477.0 - '@aws-sdk/credential-provider-node': 3.478.0 - '@aws-sdk/middleware-host-header': 3.468.0 - '@aws-sdk/middleware-logger': 3.468.0 - '@aws-sdk/middleware-recursion-detection': 3.468.0 - '@aws-sdk/middleware-signing': 3.468.0 - '@aws-sdk/middleware-user-agent': 3.478.0 - '@aws-sdk/region-config-resolver': 3.470.0 - '@aws-sdk/types': 3.468.0 - '@aws-sdk/util-endpoints': 3.478.0 - '@aws-sdk/util-user-agent-browser': 3.468.0 - '@aws-sdk/util-user-agent-node': 3.470.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/eventstream-serde-browser': 2.2.0 - '@smithy/eventstream-serde-config-resolver': 2.2.0 - '@smithy/eventstream-serde-node': 2.2.0 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-stream': 2.2.0 - '@smithy/util-utf8': 2.3.0 - '@smithy/util-waiter': 2.2.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-rds-data@3.583.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/client-sts': 3.583.0 - '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.583.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.583.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 + tslib: 2.8.1 + + '@aws-sdk/client-cognito-identity@3.687.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.687.0(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/client-sts': 3.687.0 + '@aws-sdk/core': 3.686.0 + '@aws-sdk/credential-provider-node': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/middleware-host-header': 3.686.0 + '@aws-sdk/middleware-logger': 3.686.0 + '@aws-sdk/middleware-recursion-detection': 3.686.0 + '@aws-sdk/middleware-user-agent': 3.687.0 + '@aws-sdk/region-config-resolver': 3.686.0 + '@aws-sdk/types': 3.686.0 + '@aws-sdk/util-endpoints': 3.686.0 + '@aws-sdk/util-user-agent-browser': 3.686.0 + '@aws-sdk/util-user-agent-node': 3.687.0 + '@smithy/config-resolver': 3.0.10 + '@smithy/core': 2.5.1 + '@smithy/fetch-http-handler': 4.0.0 + '@smithy/hash-node': 3.0.8 + '@smithy/invalid-dependency': 3.0.8 + '@smithy/middleware-content-length': 3.0.10 + '@smithy/middleware-endpoint': 3.2.1 + '@smithy/middleware-retry': 3.0.25 + '@smithy/middleware-serde': 3.0.8 + '@smithy/middleware-stack': 3.0.8 + '@smithy/node-config-provider': 3.1.9 + '@smithy/node-http-handler': 3.2.5 + '@smithy/protocol-http': 4.1.5 + '@smithy/smithy-client': 3.4.2 + '@smithy/types': 3.6.0 + '@smithy/url-parser': 3.0.8 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.25 + '@smithy/util-defaults-mode-node': 3.0.25 + '@smithy/util-endpoints': 2.1.4 + '@smithy/util-middleware': 3.0.8 + '@smithy/util-retry': 3.0.8 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-sso-oidc@3.569.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.569.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0 - '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.583.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.583.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 + '@aws-sdk/client-rds-data@3.687.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.687.0(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/client-sts': 3.687.0 + '@aws-sdk/core': 3.686.0 + '@aws-sdk/credential-provider-node': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/middleware-host-header': 3.686.0 + '@aws-sdk/middleware-logger': 3.686.0 + '@aws-sdk/middleware-recursion-detection': 3.686.0 + '@aws-sdk/middleware-user-agent': 3.687.0 + '@aws-sdk/region-config-resolver': 3.686.0 + '@aws-sdk/types': 3.686.0 + '@aws-sdk/util-endpoints': 3.686.0 + '@aws-sdk/util-user-agent-browser': 3.686.0 + '@aws-sdk/util-user-agent-node': 3.687.0 + '@smithy/config-resolver': 3.0.10 + '@smithy/core': 2.5.1 + '@smithy/fetch-http-handler': 4.0.0 + '@smithy/hash-node': 3.0.8 + '@smithy/invalid-dependency': 3.0.8 + '@smithy/middleware-content-length': 3.0.10 + '@smithy/middleware-endpoint': 3.2.1 + '@smithy/middleware-retry': 3.0.25 + '@smithy/middleware-serde': 3.0.8 + '@smithy/middleware-stack': 3.0.8 + '@smithy/node-config-provider': 3.1.9 + '@smithy/node-http-handler': 3.2.5 + '@smithy/protocol-http': 4.1.5 + '@smithy/smithy-client': 3.4.2 + '@smithy/types': 3.6.0 + '@smithy/url-parser': 3.0.8 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.25 + '@smithy/util-defaults-mode-node': 3.0.25 + '@smithy/util-endpoints': 2.1.4 + '@smithy/util-middleware': 3.0.8 + '@smithy/util-retry': 3.0.8 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sts' - - aws-crt - - '@aws-sdk/client-sso@3.478.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.477.0 - '@aws-sdk/middleware-host-header': 3.468.0 - '@aws-sdk/middleware-logger': 3.468.0 - '@aws-sdk/middleware-recursion-detection': 3.468.0 - '@aws-sdk/middleware-user-agent': 3.478.0 - '@aws-sdk/region-config-resolver': 3.470.0 - '@aws-sdk/types': 3.468.0 - '@aws-sdk/util-endpoints': 3.478.0 - '@aws-sdk/util-user-agent-browser': 3.468.0 - '@aws-sdk/util-user-agent-node': 3.470.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso@3.568.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-sso@3.583.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.582.0 - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.583.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.583.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 + '@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sts': 3.687.0 + '@aws-sdk/core': 3.686.0 + '@aws-sdk/credential-provider-node': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/middleware-host-header': 3.686.0 + '@aws-sdk/middleware-logger': 3.686.0 + '@aws-sdk/middleware-recursion-detection': 3.686.0 + '@aws-sdk/middleware-user-agent': 3.687.0 + '@aws-sdk/region-config-resolver': 3.686.0 + '@aws-sdk/types': 3.686.0 + '@aws-sdk/util-endpoints': 3.686.0 + '@aws-sdk/util-user-agent-browser': 3.686.0 + '@aws-sdk/util-user-agent-node': 3.687.0 + '@smithy/config-resolver': 3.0.10 + '@smithy/core': 2.5.1 + '@smithy/fetch-http-handler': 4.0.0 + '@smithy/hash-node': 3.0.8 + '@smithy/invalid-dependency': 3.0.8 + '@smithy/middleware-content-length': 3.0.10 + '@smithy/middleware-endpoint': 3.2.1 + '@smithy/middleware-retry': 3.0.25 + '@smithy/middleware-serde': 3.0.8 + '@smithy/middleware-stack': 3.0.8 + '@smithy/node-config-provider': 3.1.9 + '@smithy/node-http-handler': 3.2.5 + '@smithy/protocol-http': 4.1.5 + '@smithy/smithy-client': 3.4.2 + '@smithy/types': 3.6.0 + '@smithy/url-parser': 3.0.8 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.25 + '@smithy/util-defaults-mode-node': 3.0.25 + '@smithy/util-endpoints': 2.1.4 + '@smithy/util-middleware': 3.0.8 + '@smithy/util-retry': 3.0.8 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-sts@3.478.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.477.0 - '@aws-sdk/credential-provider-node': 3.478.0 - '@aws-sdk/middleware-host-header': 3.468.0 - '@aws-sdk/middleware-logger': 3.468.0 - '@aws-sdk/middleware-recursion-detection': 3.468.0 - '@aws-sdk/middleware-user-agent': 3.478.0 - '@aws-sdk/region-config-resolver': 3.470.0 - '@aws-sdk/types': 3.468.0 - '@aws-sdk/util-endpoints': 3.478.0 - '@aws-sdk/util-user-agent-browser': 3.468.0 - '@aws-sdk/util-user-agent-node': 3.470.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - fast-xml-parser: 4.2.5 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-sts@3.569.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.583.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.583.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 + '@aws-sdk/client-sso@3.687.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.686.0 + '@aws-sdk/middleware-host-header': 3.686.0 + '@aws-sdk/middleware-logger': 3.686.0 + '@aws-sdk/middleware-recursion-detection': 3.686.0 + '@aws-sdk/middleware-user-agent': 3.687.0 + '@aws-sdk/region-config-resolver': 3.686.0 + '@aws-sdk/types': 3.686.0 + '@aws-sdk/util-endpoints': 3.686.0 + '@aws-sdk/util-user-agent-browser': 3.686.0 + '@aws-sdk/util-user-agent-node': 3.687.0 + '@smithy/config-resolver': 3.0.10 + '@smithy/core': 2.5.1 + '@smithy/fetch-http-handler': 4.0.0 + '@smithy/hash-node': 3.0.8 + '@smithy/invalid-dependency': 3.0.8 + '@smithy/middleware-content-length': 3.0.10 + '@smithy/middleware-endpoint': 3.2.1 + '@smithy/middleware-retry': 3.0.25 + '@smithy/middleware-serde': 3.0.8 + '@smithy/middleware-stack': 3.0.8 + '@smithy/node-config-provider': 3.1.9 + '@smithy/node-http-handler': 3.2.5 + '@smithy/protocol-http': 4.1.5 + '@smithy/smithy-client': 3.4.2 + '@smithy/types': 3.6.0 + '@smithy/url-parser': 3.0.8 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.1 - '@smithy/util-defaults-mode-node': 3.0.1 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.25 + '@smithy/util-defaults-mode-node': 3.0.25 + '@smithy/util-endpoints': 2.1.4 + '@smithy/util-middleware': 3.0.8 + '@smithy/util-retry': 3.0.8 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/core@3.477.0': - dependencies: - '@smithy/core': 1.4.2 - '@smithy/protocol-http': 3.3.0 - '@smithy/signature-v4': 2.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - - '@aws-sdk/core@3.567.0': - dependencies: - '@smithy/core': 1.4.2 - '@smithy/protocol-http': 3.3.0 - '@smithy/signature-v4': 2.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - fast-xml-parser: 4.2.5 - tslib: 2.6.2 - - '@aws-sdk/core@3.582.0': - dependencies: - '@smithy/core': 2.0.1 - '@smithy/protocol-http': 4.0.0 - '@smithy/signature-v4': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - fast-xml-parser: 4.2.5 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-cognito-identity@3.569.0': - dependencies: - '@aws-sdk/client-cognito-identity': 3.569.0 - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-env@3.468.0': - dependencies: - '@aws-sdk/types': 3.468.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-env@3.568.0': - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-env@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-http@3.568.0': - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/property-provider': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-http@3.582.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/node-http-handler': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/util-stream': 3.0.1 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-ini@3.478.0': - dependencies: - '@aws-sdk/credential-provider-env': 3.468.0 - '@aws-sdk/credential-provider-process': 3.468.0 - '@aws-sdk/credential-provider-sso': 3.478.0 - '@aws-sdk/credential-provider-web-identity': 3.468.0 - '@aws-sdk/types': 3.468.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': - dependencies: - '@aws-sdk/client-sts': 3.583.0 - '@aws-sdk/credential-provider-env': 3.577.0 - '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/types': 3.577.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@aws-sdk/client-sts@3.687.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.687.0(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/core': 3.686.0 + '@aws-sdk/credential-provider-node': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/middleware-host-header': 3.686.0 + '@aws-sdk/middleware-logger': 3.686.0 + '@aws-sdk/middleware-recursion-detection': 3.686.0 + '@aws-sdk/middleware-user-agent': 3.687.0 + '@aws-sdk/region-config-resolver': 3.686.0 + '@aws-sdk/types': 3.686.0 + '@aws-sdk/util-endpoints': 3.686.0 + '@aws-sdk/util-user-agent-browser': 3.686.0 + '@aws-sdk/util-user-agent-node': 3.687.0 + '@smithy/config-resolver': 3.0.10 + '@smithy/core': 2.5.1 + '@smithy/fetch-http-handler': 4.0.0 + '@smithy/hash-node': 3.0.8 + '@smithy/invalid-dependency': 3.0.8 + '@smithy/middleware-content-length': 3.0.10 + '@smithy/middleware-endpoint': 3.2.1 + '@smithy/middleware-retry': 3.0.25 + '@smithy/middleware-serde': 3.0.8 + '@smithy/middleware-stack': 3.0.8 + '@smithy/node-config-provider': 3.1.9 + '@smithy/node-http-handler': 3.2.5 + '@smithy/protocol-http': 4.1.5 + '@smithy/smithy-client': 3.4.2 + '@smithy/types': 3.6.0 + '@smithy/url-parser': 3.0.8 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.25 + '@smithy/util-defaults-mode-node': 3.0.25 + '@smithy/util-endpoints': 2.1.4 + '@smithy/util-middleware': 3.0.8 + '@smithy/util-retry': 3.0.8 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-node@3.478.0': - dependencies: - '@aws-sdk/credential-provider-env': 3.468.0 - '@aws-sdk/credential-provider-ini': 3.478.0 - '@aws-sdk/credential-provider-process': 3.468.0 - '@aws-sdk/credential-provider-sso': 3.478.0 - '@aws-sdk/credential-provider-web-identity': 3.468.0 - '@aws-sdk/types': 3.468.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@aws-sdk/core@3.686.0': + dependencies: + '@aws-sdk/types': 3.686.0 + '@smithy/core': 2.5.1 + '@smithy/node-config-provider': 3.1.9 + '@smithy/property-provider': 3.1.8 + '@smithy/protocol-http': 4.1.5 + '@smithy/signature-v4': 4.2.1 + '@smithy/smithy-client': 3.4.2 + '@smithy/types': 3.6.0 + '@smithy/util-middleware': 3.0.8 + fast-xml-parser: 4.4.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-cognito-identity@3.687.0': + dependencies: + '@aws-sdk/client-cognito-identity': 3.687.0 + '@aws-sdk/types': 3.686.0 + '@smithy/property-provider': 3.1.8 + '@smithy/types': 3.6.0 + tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@aws-sdk/credential-provider-env@3.686.0': + dependencies: + '@aws-sdk/core': 3.686.0 + '@aws-sdk/types': 3.686.0 + '@smithy/property-provider': 3.1.8 + '@smithy/types': 3.6.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.686.0': + dependencies: + '@aws-sdk/core': 3.686.0 + '@aws-sdk/types': 3.686.0 + '@smithy/fetch-http-handler': 4.0.0 + '@smithy/node-http-handler': 3.2.5 + '@smithy/property-provider': 3.1.8 + '@smithy/protocol-http': 4.1.5 + '@smithy/smithy-client': 3.4.2 + '@smithy/types': 3.6.0 + '@smithy/util-stream': 3.2.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0)': + dependencies: + '@aws-sdk/client-sts': 3.687.0 + '@aws-sdk/core': 3.686.0 + '@aws-sdk/credential-provider-env': 3.686.0 + '@aws-sdk/credential-provider-http': 3.686.0 + '@aws-sdk/credential-provider-process': 3.686.0 + '@aws-sdk/credential-provider-sso': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)) + '@aws-sdk/credential-provider-web-identity': 3.686.0(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/types': 3.686.0 + '@smithy/credential-provider-imds': 3.2.5 + '@smithy/property-provider': 3.1.8 + '@smithy/shared-ini-file-loader': 3.1.9 + '@smithy/types': 3.6.0 + tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': - dependencies: - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@aws-sdk/credential-provider-node@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0)': + dependencies: + '@aws-sdk/credential-provider-env': 3.686.0 + '@aws-sdk/credential-provider-http': 3.686.0 + '@aws-sdk/credential-provider-ini': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/credential-provider-process': 3.686.0 + '@aws-sdk/credential-provider-sso': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)) + '@aws-sdk/credential-provider-web-identity': 3.686.0(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/types': 3.686.0 + '@smithy/credential-provider-imds': 3.2.5 + '@smithy/property-provider': 3.1.8 + '@smithy/shared-ini-file-loader': 3.1.9 + '@smithy/types': 3.6.0 + tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@aws-sdk/credential-provider-process@3.686.0': + dependencies: + '@aws-sdk/core': 3.686.0 + '@aws-sdk/types': 3.686.0 + '@smithy/property-provider': 3.1.8 + '@smithy/shared-ini-file-loader': 3.1.9 + '@smithy/types': 3.6.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))': + dependencies: + '@aws-sdk/client-sso': 3.687.0 + '@aws-sdk/core': 3.686.0 + '@aws-sdk/token-providers': 3.686.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)) + '@aws-sdk/types': 3.686.0 + '@smithy/property-provider': 3.1.8 + '@smithy/shared-ini-file-loader': 3.1.9 + '@smithy/types': 3.6.0 + tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': - dependencies: - '@aws-sdk/credential-provider-env': 3.577.0 - '@aws-sdk/credential-provider-http': 3.582.0 - '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/types': 3.577.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@aws-sdk/credential-provider-web-identity@3.686.0(@aws-sdk/client-sts@3.687.0)': + dependencies: + '@aws-sdk/client-sts': 3.687.0 + '@aws-sdk/core': 3.686.0 + '@aws-sdk/types': 3.686.0 + '@smithy/property-provider': 3.1.8 + '@smithy/types': 3.6.0 + tslib: 2.8.1 + + '@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))': + dependencies: + '@aws-sdk/client-cognito-identity': 3.687.0 + '@aws-sdk/client-sso': 3.687.0 + '@aws-sdk/client-sts': 3.687.0 + '@aws-sdk/core': 3.686.0 + '@aws-sdk/credential-provider-cognito-identity': 3.687.0 + '@aws-sdk/credential-provider-env': 3.686.0 + '@aws-sdk/credential-provider-http': 3.686.0 + '@aws-sdk/credential-provider-ini': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/credential-provider-node': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/credential-provider-process': 3.686.0 + '@aws-sdk/credential-provider-sso': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)) + '@aws-sdk/credential-provider-web-identity': 3.686.0(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/types': 3.686.0 + '@smithy/credential-provider-imds': 3.2.5 + '@smithy/property-provider': 3.1.8 + '@smithy/types': 3.6.0 + tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-process@3.468.0': - dependencies: - '@aws-sdk/types': 3.468.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-process@3.568.0': + '@aws-sdk/middleware-host-header@3.686.0': dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@aws-sdk/types': 3.686.0 + '@smithy/protocol-http': 4.1.5 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@aws-sdk/credential-provider-process@3.577.0': + '@aws-sdk/middleware-logger@3.686.0': dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@aws-sdk/types': 3.686.0 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.478.0': + '@aws-sdk/middleware-recursion-detection@3.686.0': dependencies: - '@aws-sdk/client-sso': 3.478.0 - '@aws-sdk/token-providers': 3.478.0 - '@aws-sdk/types': 3.468.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt + '@aws-sdk/types': 3.686.0 + '@smithy/protocol-http': 4.1.5 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)': + '@aws-sdk/middleware-user-agent@3.687.0': dependencies: - '@aws-sdk/client-sso': 3.568.0 - '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt + '@aws-sdk/core': 3.686.0 + '@aws-sdk/types': 3.686.0 + '@aws-sdk/util-endpoints': 3.686.0 + '@smithy/core': 2.5.1 + '@smithy/protocol-http': 4.1.5 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/region-config-resolver@3.686.0': dependencies: - '@aws-sdk/client-sso': 3.568.0 - '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt + '@aws-sdk/types': 3.686.0 + '@smithy/node-config-provider': 3.1.9 + '@smithy/types': 3.6.0 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.8 + tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/token-providers@3.686.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))': dependencies: - '@aws-sdk/client-sso': 3.583.0 - '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - - '@aws-sdk/credential-provider-web-identity@3.468.0': - dependencies: - '@aws-sdk/types': 3.468.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': - dependencies: - '@aws-sdk/client-sts': 3.569.0 - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - - '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': - dependencies: - '@aws-sdk/client-sts': 3.583.0 - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)': - dependencies: - '@aws-sdk/client-cognito-identity': 3.569.0 - '@aws-sdk/client-sso': 3.568.0 - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-cognito-identity': 3.569.0 - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt + '@aws-sdk/client-sso-oidc': 3.687.0(@aws-sdk/client-sts@3.687.0) + '@aws-sdk/types': 3.686.0 + '@smithy/property-provider': 3.1.8 + '@smithy/shared-ini-file-loader': 3.1.9 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.468.0': + '@aws-sdk/types@3.686.0': dependencies: - '@aws-sdk/types': 3.468.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.567.0': + '@aws-sdk/util-endpoints@3.686.0': dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@aws-sdk/types': 3.686.0 + '@smithy/types': 3.6.0 + '@smithy/util-endpoints': 2.1.4 + tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.577.0': + '@aws-sdk/util-locate-window@3.679.0': dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.468.0': + '@aws-sdk/util-user-agent-browser@3.686.0': dependencies: - '@aws-sdk/types': 3.468.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@aws-sdk/types': 3.686.0 + '@smithy/types': 3.6.0 + bowser: 2.11.0 + tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.568.0': + '@aws-sdk/util-user-agent-node@3.687.0': dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@aws-sdk/middleware-user-agent': 3.687.0 + '@aws-sdk/types': 3.686.0 + '@smithy/node-config-provider': 3.1.9 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.577.0': + '@babel/code-frame@7.10.4': dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@babel/highlight': 7.25.9 - '@aws-sdk/middleware-recursion-detection@3.468.0': + '@babel/code-frame@7.26.2': dependencies: - '@aws-sdk/types': 3.468.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 - '@aws-sdk/middleware-recursion-detection@3.567.0': - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/compat-data@7.26.2': {} - '@aws-sdk/middleware-recursion-detection@3.577.0': + '@babel/core@7.26.0': dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + convert-source-map: 2.0.0 + debug: 4.3.7 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - '@aws-sdk/middleware-signing@3.468.0': + '@babel/generator@7.17.7': dependencies: - '@aws-sdk/types': 3.468.0 - '@smithy/property-provider': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/signature-v4': 2.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + '@babel/types': 7.17.0 + jsesc: 2.5.2 + source-map: 0.5.7 - '@aws-sdk/middleware-user-agent@3.478.0': + '@babel/generator@7.2.0': dependencies: - '@aws-sdk/types': 3.468.0 - '@aws-sdk/util-endpoints': 3.478.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/types': 7.26.0 + jsesc: 2.5.2 + lodash: 4.17.21 + source-map: 0.5.7 + trim-right: 1.0.1 - '@aws-sdk/middleware-user-agent@3.567.0': + '@babel/generator@7.26.2': dependencies: - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.0.2 - '@aws-sdk/middleware-user-agent@3.583.0': + '@babel/helper-annotate-as-pure@7.25.9': dependencies: - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.583.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@babel/types': 7.26.0 - '@aws-sdk/region-config-resolver@3.470.0': + '@babel/helper-builder-binary-assignment-operator-visitor@7.25.9': dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-config-provider': 2.3.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color - '@aws-sdk/region-config-resolver@3.567.0': + '@babel/helper-compilation-targets@7.25.9': dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-config-provider': 2.3.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + '@babel/compat-data': 7.26.2 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.2 + lru-cache: 5.1.1 + semver: 6.3.1 - '@aws-sdk/region-config-resolver@3.577.0': + '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.0)': dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 - - '@aws-sdk/token-providers@3.478.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/middleware-host-header': 3.468.0 - '@aws-sdk/middleware-logger': 3.468.0 - '@aws-sdk/middleware-recursion-detection': 3.468.0 - '@aws-sdk/middleware-user-agent': 3.478.0 - '@aws-sdk/region-config-resolver': 3.470.0 - '@aws-sdk/types': 3.468.0 - '@aws-sdk/util-endpoints': 3.478.0 - '@aws-sdk/util-user-agent-browser': 3.468.0 - '@aws-sdk/util-user-agent-node': 3.470.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/property-provider': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/traverse': 7.25.9 + semver: 6.3.1 transitivePeerDependencies: - - aws-crt + - supports-color - '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)': + '@babel/helper-create-regexp-features-plugin@7.25.9(@babel/core@7.26.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + regexpu-core: 6.1.1 + semver: 6.3.1 - '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.26.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + debug: 4.3.7 + lodash.debounce: 4.0.8 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color - '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@babel/helper-environment-visitor@7.24.7': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@babel/types': 7.26.0 - '@aws-sdk/types@3.468.0': + '@babel/helper-function-name@7.24.7': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 - '@aws-sdk/types@3.567.0': + '@babel/helper-hoist-variables@7.24.7': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/types': 7.26.0 - '@aws-sdk/types@3.577.0': + '@babel/helper-member-expression-to-functions@7.25.9': dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color - '@aws-sdk/util-endpoints@3.478.0': + '@babel/helper-module-imports@7.25.9': dependencies: - '@aws-sdk/types': 3.468.0 - '@smithy/util-endpoints': 1.2.0 - tslib: 2.6.2 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color - '@aws-sdk/util-endpoints@3.567.0': + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/types': 2.12.0 - '@smithy/util-endpoints': 1.2.0 - tslib: 2.6.2 + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color - '@aws-sdk/util-endpoints@3.583.0': + '@babel/helper-optimise-call-expression@7.25.9': dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/types': 3.0.0 - '@smithy/util-endpoints': 2.0.0 - tslib: 2.6.2 + '@babel/types': 7.26.0 - '@aws-sdk/util-locate-window@3.568.0': - dependencies: - tslib: 2.6.2 + '@babel/helper-plugin-utils@7.25.9': {} - '@aws-sdk/util-user-agent-browser@3.468.0': + '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.0)': dependencies: - '@aws-sdk/types': 3.468.0 - '@smithy/types': 2.12.0 - bowser: 2.11.0 - tslib: 2.6.2 + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-wrap-function': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color - '@aws-sdk/util-user-agent-browser@3.567.0': + '@babel/helper-replace-supers@7.25.9(@babel/core@7.26.0)': dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/types': 2.12.0 - bowser: 2.11.0 - tslib: 2.6.2 + '@babel/core': 7.26.0 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color - '@aws-sdk/util-user-agent-browser@3.577.0': + '@babel/helper-simple-access@7.25.9': dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/types': 3.0.0 - bowser: 2.11.0 - tslib: 2.6.2 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color - '@aws-sdk/util-user-agent-node@3.470.0': + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': dependencies: - '@aws-sdk/types': 3.468.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color - '@aws-sdk/util-user-agent-node@3.568.0': + '@babel/helper-split-export-declaration@7.24.7': dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/types': 7.26.0 - '@aws-sdk/util-user-agent-node@3.577.0': - dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@babel/helper-string-parser@7.25.9': {} - '@aws-sdk/util-utf8-browser@3.259.0': - dependencies: - tslib: 2.6.2 + '@babel/helper-validator-identifier@7.25.9': {} - '@babel/code-frame@7.10.4': + '@babel/helper-validator-option@7.25.9': {} + + '@babel/helper-wrap-function@7.25.9': dependencies: - '@babel/highlight': 7.24.6 + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color - '@babel/code-frame@7.22.10': + '@babel/helpers@7.26.0': dependencies: - '@babel/highlight': 7.22.10 - chalk: 2.4.2 + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 - '@babel/code-frame@7.22.13': + '@babel/highlight@7.25.9': dependencies: - '@babel/highlight': 7.22.20 + '@babel/helper-validator-identifier': 7.25.9 chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.1.1 - '@babel/code-frame@7.24.6': + '@babel/parser@7.26.2': dependencies: - '@babel/highlight': 7.24.6 - picocolors: 1.0.1 + '@babel/types': 7.26.0 - '@babel/compat-data@7.24.6': {} - - '@babel/core@7.24.6': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.0)': dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.24.6 - '@babel/generator': 7.24.6 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) - '@babel/helpers': 7.24.6 - '@babel/parser': 7.24.6 - '@babel/template': 7.24.6 - '@babel/traverse': 7.24.6 - '@babel/types': 7.24.6 - convert-source-map: 2.0.0 - debug: 4.3.7 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/traverse': 7.25.9 transitivePeerDependencies: - supports-color - '@babel/generator@7.17.7': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/types': 7.17.0 - jsesc: 2.5.2 - source-map: 0.5.7 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/generator@7.24.6': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/types': 7.24.6 - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 2.5.2 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-annotate-as-pure@7.24.6': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/types': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color - '@babel/helper-builder-binary-assignment-operator-visitor@7.24.6': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/types': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/helper-compilation-targets@7.24.6': + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.26.0)': dependencies: - '@babel/compat-data': 7.24.6 - '@babel/helper-validator-option': 7.24.6 - browserslist: 4.23.0 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-create-class-features-plugin@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-function-name': 7.24.6 - '@babel/helper-member-expression-to-functions': 7.24.6 - '@babel/helper-optimise-call-expression': 7.24.6 - '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 - '@babel/helper-split-export-declaration': 7.24.6 - semver: 6.3.1 - - '@babel/helper-create-regexp-features-plugin@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-annotate-as-pure': 7.24.6 - regexpu-core: 5.3.2 - semver: 6.3.1 - - '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - debug: 4.3.7 - lodash.debounce: 4.0.8 - resolve: 1.22.8 + '@babel/core': 7.26.0 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) transitivePeerDependencies: - supports-color - '@babel/helper-environment-visitor@7.22.5': {} - - '@babel/helper-environment-visitor@7.24.6': {} - - '@babel/helper-function-name@7.22.5': - dependencies: - '@babel/template': 7.22.5 - '@babel/types': 7.22.10 - - '@babel/helper-function-name@7.24.6': - dependencies: - '@babel/template': 7.24.6 - '@babel/types': 7.24.6 - - '@babel/helper-hoist-variables@7.22.5': + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.26.0)': dependencies: - '@babel/types': 7.23.6 - - '@babel/helper-hoist-variables@7.24.6': - dependencies: - '@babel/types': 7.24.6 - - '@babel/helper-member-expression-to-functions@7.24.6': - dependencies: - '@babel/types': 7.24.6 - - '@babel/helper-module-imports@7.24.6': - dependencies: - '@babel/types': 7.24.6 - - '@babel/helper-module-transforms@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-module-imports': 7.24.6 - '@babel/helper-simple-access': 7.24.6 - '@babel/helper-split-export-declaration': 7.24.6 - '@babel/helper-validator-identifier': 7.24.6 - - '@babel/helper-optimise-call-expression@7.24.6': - dependencies: - '@babel/types': 7.24.6 - - '@babel/helper-plugin-utils@7.24.6': {} - - '@babel/helper-remap-async-to-generator@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-wrap-function': 7.24.6 - - '@babel/helper-replace-supers@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-member-expression-to-functions': 7.24.6 - '@babel/helper-optimise-call-expression': 7.24.6 - - '@babel/helper-simple-access@7.24.6': - dependencies: - '@babel/types': 7.24.6 - - '@babel/helper-skip-transparent-expression-wrappers@7.24.6': - dependencies: - '@babel/types': 7.24.6 - - '@babel/helper-split-export-declaration@7.22.6': - dependencies: - '@babel/types': 7.23.6 - - '@babel/helper-split-export-declaration@7.24.6': - dependencies: - '@babel/types': 7.24.6 - - '@babel/helper-string-parser@7.22.5': {} - - '@babel/helper-string-parser@7.23.4': {} - - '@babel/helper-string-parser@7.24.6': {} - - '@babel/helper-validator-identifier@7.22.20': {} - - '@babel/helper-validator-identifier@7.22.5': {} - - '@babel/helper-validator-identifier@7.24.6': {} - - '@babel/helper-validator-option@7.24.6': {} - - '@babel/helper-wrap-function@7.24.6': - dependencies: - '@babel/helper-function-name': 7.24.6 - '@babel/template': 7.24.6 - '@babel/types': 7.24.6 - - '@babel/helpers@7.24.6': - dependencies: - '@babel/template': 7.24.6 - '@babel/types': 7.24.6 - - '@babel/highlight@7.22.10': - dependencies: - '@babel/helper-validator-identifier': 7.22.5 - chalk: 2.4.2 - js-tokens: 4.0.0 - - '@babel/highlight@7.22.20': - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - - '@babel/highlight@7.24.6': - dependencies: - '@babel/helper-validator-identifier': 7.24.6 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.0.1 + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/parser@7.22.10': + '@babel/plugin-proposal-decorators@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/types': 7.17.0 + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color - '@babel/parser@7.24.6': + '@babel/plugin-proposal-export-default-from@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/types': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 - '@babel/plugin-transform-optional-chaining': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/compat-data': 7.26.2 + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.24.6)': + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.24.6)': + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color - '@babel/plugin-proposal-decorators@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-decorators': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 - '@babel/plugin-proposal-export-default-from@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-export-default-from': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.24.6)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.24.6)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.24.6)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.24.6)': + '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/compat-data': 7.24.6 - '@babel/core': 7.24.6 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.24.6)': + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.24.6)': + '@babel/plugin-syntax-export-default-from@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.6)': + '@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.6)': + '@babel/plugin-syntax-import-assertions@7.26.0(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.6)': + '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.6)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-decorators@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.6)': + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-export-default-from@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.6)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-flow@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-import-assertions@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-import-attributes@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.6)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.6)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-jsx@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.6)': + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.6)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.6)': + '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.6)': + '@babel/plugin-transform-async-generator-functions@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.6)': + '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.6)': + '@babel/plugin-transform-block-scoped-functions@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.6)': + '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.6)': + '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-syntax-typescript@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-class-static-block@7.26.0(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.6)': + '@babel/plugin-transform-classes@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) + '@babel/traverse': 7.25.9 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-arrow-functions@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/template': 7.25.9 - '@babel/plugin-transform-async-generator-functions@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-async-to-generator@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-module-imports': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-block-scoped-functions@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-block-scoping@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-class-properties@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-class-static-block@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-exponentiation-operator@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-classes@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-function-name': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) - '@babel/helper-split-export-declaration': 7.24.6 - globals: 11.12.0 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-computed-properties@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-flow-strip-types@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/template': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-transform-destructuring@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-for-of@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-dotall-regex@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-duplicate-keys@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-json-strings@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-dynamic-import@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-literals@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-exponentiation-operator@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-export-namespace-from@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-member-expression-literals@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-flow-strip-types@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-modules-amd@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-flow': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-for-of@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-modules-commonjs@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-simple-access': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-function-name@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-modules-systemjs@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-function-name': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-json-strings@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-modules-umd@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-literals@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-logical-assignment-operators@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-new-target@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-member-expression-literals@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-nullish-coalescing-operator@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-modules-amd@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-modules-commonjs@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-simple-access': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-systemjs@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-object-super@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-hoist-variables': 7.24.6 - '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-validator-identifier': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-modules-umd@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-named-capturing-groups-regex@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-new-target@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-nullish-coalescing-operator@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-numeric-separator@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-object-rest-spread@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-property-literals@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-object-super@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-react-display-name@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-optional-catch-binding@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-react-jsx-development@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-optional-chaining@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-parameters@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-private-methods@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-private-property-in-object@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-react-pure-annotations@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-property-literals@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + regenerator-transform: 0.15.2 - '@babel/plugin-transform-react-display-name@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-regexp-modifiers@7.26.0(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-jsx-development@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/plugin-transform-react-jsx': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-jsx-self@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-runtime@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.26.0) + babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.26.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-react-jsx-source@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-jsx@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-spread@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-module-imports': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) - '@babel/types': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-react-pure-annotations@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-regenerator@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-template-literals@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - regenerator-transform: 0.15.2 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-reserved-words@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-typeof-symbol@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-runtime@7.24.6(@babel/core@7.24.6)': + '@babel/plugin-transform-typescript@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-module-imports': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.6) - babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.6) - babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.6) - semver: 6.3.1 + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - - '@babel/plugin-transform-spread@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 - - '@babel/plugin-transform-sticky-regex@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - - '@babel/plugin-transform-template-literals@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - - '@babel/plugin-transform-typeof-symbol@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - - '@babel/plugin-transform-typescript@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-typescript': 7.24.6(@babel/core@7.24.6) - - '@babel/plugin-transform-unicode-escapes@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - - '@babel/plugin-transform-unicode-property-regex@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 - - '@babel/plugin-transform-unicode-regex@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 - - '@babel/plugin-transform-unicode-sets-regex@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/core': 7.24.6 - '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) - '@babel/helper-plugin-utils': 7.24.6 - - '@babel/preset-env@7.24.6(@babel/core@7.24.6)': - dependencies: - '@babel/compat-data': 7.24.6 - '@babel/core': 7.24.6 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-validator-option': 7.24.6 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.6) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.6) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.6) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-syntax-import-assertions': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-syntax-import-attributes': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.6) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.6) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.6) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.6) - '@babel/plugin-transform-arrow-functions': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-async-generator-functions': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-async-to-generator': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-block-scoped-functions': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-block-scoping': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-class-properties': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-class-static-block': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-classes': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-computed-properties': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-destructuring': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-dotall-regex': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-duplicate-keys': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-dynamic-import': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-exponentiation-operator': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-export-namespace-from': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-for-of': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-function-name': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-json-strings': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-literals': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-logical-assignment-operators': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-member-expression-literals': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-modules-amd': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-modules-systemjs': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-modules-umd': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-named-capturing-groups-regex': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-new-target': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-nullish-coalescing-operator': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-numeric-separator': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-object-rest-spread': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-object-super': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-optional-catch-binding': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-optional-chaining': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-private-methods': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-private-property-in-object': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-property-literals': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-regenerator': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-reserved-words': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-shorthand-properties': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-spread': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-sticky-regex': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-template-literals': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-typeof-symbol': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-unicode-escapes': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-unicode-property-regex': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-unicode-regex': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-unicode-sets-regex': 7.24.6(@babel/core@7.24.6) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.6) - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.6) - babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.6) - babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.6) - core-js-compat: 3.37.1 + '@babel/plugin-transform-unicode-escapes@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/preset-env@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/compat-data': 7.26.2 + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0) + '@babel/plugin-syntax-import-assertions': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-async-generator-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-block-scoped-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-class-static-block': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-dotall-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-duplicate-keys': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-dynamic-import': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-exponentiation-operator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-json-strings': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-member-expression-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-amd': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-systemjs': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-umd': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-new-target': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-object-super': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-property-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-regexp-modifiers': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-transform-reserved-words': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-template-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-typeof-symbol': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-escapes': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-property-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-sets-regex': 7.25.9(@babel/core@7.26.0) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.26.0) + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.26.0) + babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.26.0) + core-js-compat: 3.39.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-flow@7.24.6(@babel/core@7.24.6)': + '@babel/preset-flow@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-validator-option': 7.24.6 - '@babel/plugin-transform-flow-strip-types': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.6)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/types': 7.24.6 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/types': 7.26.0 esutils: 2.0.3 - '@babel/preset-react@7.24.6(@babel/core@7.24.6)': + '@babel/preset-react@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-validator-option': 7.24.6 - '@babel/plugin-transform-react-display-name': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-react-jsx': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-react-jsx-development': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-react-pure-annotations': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx-development': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-pure-annotations': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color - '@babel/preset-typescript@7.24.6(@babel/core@7.24.6)': + '@babel/preset-typescript@7.26.0(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-validator-option': 7.24.6 - '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-typescript': 7.24.6(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color - '@babel/register@7.24.6(@babel/core@7.24.6)': + '@babel/register@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.24.6 + '@babel/core': 7.26.0 clone-deep: 4.0.1 find-cache-dir: 2.1.0 make-dir: 2.1.0 pirates: 4.0.6 source-map-support: 0.5.21 - '@babel/regjsgen@0.8.0': {} - - '@babel/runtime@7.22.10': - dependencies: - regenerator-runtime: 0.14.0 - - '@babel/runtime@7.24.6': + '@babel/runtime@7.26.0': dependencies: regenerator-runtime: 0.14.1 - '@babel/template@7.22.5': + '@babel/template@7.25.9': dependencies: - '@babel/code-frame': 7.22.10 - '@babel/parser': 7.22.10 - '@babel/types': 7.22.10 + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 - '@babel/template@7.24.6': + '@babel/traverse@7.23.2': dependencies: - '@babel/code-frame': 7.24.6 - '@babel/parser': 7.24.6 - '@babel/types': 7.24.6 - - '@babel/traverse@7.17.3': - dependencies: - '@babel/code-frame': 7.22.10 - '@babel/generator': 7.17.7 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-function-name': 7.22.5 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.22.10 - '@babel/types': 7.17.0 - debug: 4.3.4 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/traverse@7.24.6': + '@babel/traverse@7.25.9': dependencies: - '@babel/code-frame': 7.24.6 - '@babel/generator': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-function-name': 7.24.6 - '@babel/helper-hoist-variables': 7.24.6 - '@babel/helper-split-export-declaration': 7.24.6 - '@babel/parser': 7.24.6 - '@babel/types': 7.24.6 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: @@ -12441,26 +10853,13 @@ snapshots: '@babel/types@7.17.0': dependencies: - '@babel/helper-validator-identifier': 7.22.5 - to-fast-properties: 2.0.0 - - '@babel/types@7.22.10': - dependencies: - '@babel/helper-string-parser': 7.22.5 - '@babel/helper-validator-identifier': 7.22.5 - to-fast-properties: 2.0.0 - - '@babel/types@7.23.6': - dependencies: - '@babel/helper-string-parser': 7.23.4 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.25.9 to-fast-properties: 2.0.0 - '@babel/types@7.24.6': + '@babel/types@7.26.0': dependencies: - '@babel/helper-string-parser': 7.24.6 - '@babel/helper-validator-identifier': 7.24.6 - to-fast-properties: 2.0.0 + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 '@balena/dockerignore@1.0.2': {} @@ -12468,26 +10867,27 @@ snapshots: dependencies: mime: 3.0.0 - '@cloudflare/workerd-darwin-64@1.20240712.0': + '@cloudflare/workerd-darwin-64@1.20241022.0': optional: true - '@cloudflare/workerd-darwin-arm64@1.20240712.0': + '@cloudflare/workerd-darwin-arm64@1.20241022.0': optional: true - '@cloudflare/workerd-linux-64@1.20240712.0': + '@cloudflare/workerd-linux-64@1.20241022.0': optional: true - '@cloudflare/workerd-linux-arm64@1.20240712.0': + '@cloudflare/workerd-linux-arm64@1.20241022.0': optional: true - '@cloudflare/workerd-windows-64@1.20240712.0': + '@cloudflare/workerd-windows-64@1.20241022.0': optional: true - '@cloudflare/workers-types@4.20240512.0': {} - - '@cloudflare/workers-types@4.20240524.0': {} + '@cloudflare/workers-shared@0.7.0': + dependencies: + mime: 3.0.0 + zod: 3.23.8 - '@cloudflare/workers-types@4.20241004.0': {} + '@cloudflare/workers-types@4.20241106.0': {} '@colors/colors@1.5.0': optional: true @@ -12523,15 +10923,15 @@ snapshots: '@electric-sql/pglite@0.2.12': {} - '@esbuild-kit/core-utils@3.1.0': + '@esbuild-kit/core-utils@3.3.2': dependencies: - esbuild: 0.17.19 + esbuild: 0.18.20 source-map-support: 0.5.21 - '@esbuild-kit/esm-loader@2.5.5': + '@esbuild-kit/esm-loader@2.6.5': dependencies: - '@esbuild-kit/core-utils': 3.1.0 - get-tsconfig: 4.7.5 + '@esbuild-kit/core-utils': 3.3.2 + get-tsconfig: 4.8.1 '@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19)': dependencies: @@ -12546,13 +10946,13 @@ snapshots: '@esbuild/aix-ppc64@0.19.12': optional: true - '@esbuild/aix-ppc64@0.20.2': + '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/aix-ppc64@0.21.5': + '@esbuild/aix-ppc64@0.23.1': optional: true - '@esbuild/aix-ppc64@0.23.0': + '@esbuild/aix-ppc64@0.24.0': optional: true '@esbuild/android-arm64@0.17.19': @@ -12564,13 +10964,13 @@ snapshots: '@esbuild/android-arm64@0.19.12': optional: true - '@esbuild/android-arm64@0.20.2': + '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/android-arm64@0.21.5': + '@esbuild/android-arm64@0.23.1': optional: true - '@esbuild/android-arm64@0.23.0': + '@esbuild/android-arm64@0.24.0': optional: true '@esbuild/android-arm@0.17.19': @@ -12582,13 +10982,13 @@ snapshots: '@esbuild/android-arm@0.19.12': optional: true - '@esbuild/android-arm@0.20.2': + '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/android-arm@0.21.5': + '@esbuild/android-arm@0.23.1': optional: true - '@esbuild/android-arm@0.23.0': + '@esbuild/android-arm@0.24.0': optional: true '@esbuild/android-x64@0.17.19': @@ -12600,13 +11000,13 @@ snapshots: '@esbuild/android-x64@0.19.12': optional: true - '@esbuild/android-x64@0.20.2': + '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/android-x64@0.21.5': + '@esbuild/android-x64@0.23.1': optional: true - '@esbuild/android-x64@0.23.0': + '@esbuild/android-x64@0.24.0': optional: true '@esbuild/darwin-arm64@0.17.19': @@ -12618,13 +11018,13 @@ snapshots: '@esbuild/darwin-arm64@0.19.12': optional: true - '@esbuild/darwin-arm64@0.20.2': + '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/darwin-arm64@0.21.5': + '@esbuild/darwin-arm64@0.23.1': optional: true - '@esbuild/darwin-arm64@0.23.0': + '@esbuild/darwin-arm64@0.24.0': optional: true '@esbuild/darwin-x64@0.17.19': @@ -12636,13 +11036,13 @@ snapshots: '@esbuild/darwin-x64@0.19.12': optional: true - '@esbuild/darwin-x64@0.20.2': + '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/darwin-x64@0.21.5': + '@esbuild/darwin-x64@0.23.1': optional: true - '@esbuild/darwin-x64@0.23.0': + '@esbuild/darwin-x64@0.24.0': optional: true '@esbuild/freebsd-arm64@0.17.19': @@ -12654,13 +11054,13 @@ snapshots: '@esbuild/freebsd-arm64@0.19.12': optional: true - '@esbuild/freebsd-arm64@0.20.2': + '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/freebsd-arm64@0.21.5': + '@esbuild/freebsd-arm64@0.23.1': optional: true - '@esbuild/freebsd-arm64@0.23.0': + '@esbuild/freebsd-arm64@0.24.0': optional: true '@esbuild/freebsd-x64@0.17.19': @@ -12672,13 +11072,13 @@ snapshots: '@esbuild/freebsd-x64@0.19.12': optional: true - '@esbuild/freebsd-x64@0.20.2': + '@esbuild/freebsd-x64@0.21.5': optional: true - '@esbuild/freebsd-x64@0.21.5': + '@esbuild/freebsd-x64@0.23.1': optional: true - '@esbuild/freebsd-x64@0.23.0': + '@esbuild/freebsd-x64@0.24.0': optional: true '@esbuild/linux-arm64@0.17.19': @@ -12690,13 +11090,13 @@ snapshots: '@esbuild/linux-arm64@0.19.12': optional: true - '@esbuild/linux-arm64@0.20.2': + '@esbuild/linux-arm64@0.21.5': optional: true - '@esbuild/linux-arm64@0.21.5': + '@esbuild/linux-arm64@0.23.1': optional: true - '@esbuild/linux-arm64@0.23.0': + '@esbuild/linux-arm64@0.24.0': optional: true '@esbuild/linux-arm@0.17.19': @@ -12708,13 +11108,13 @@ snapshots: '@esbuild/linux-arm@0.19.12': optional: true - '@esbuild/linux-arm@0.20.2': + '@esbuild/linux-arm@0.21.5': optional: true - '@esbuild/linux-arm@0.21.5': + '@esbuild/linux-arm@0.23.1': optional: true - '@esbuild/linux-arm@0.23.0': + '@esbuild/linux-arm@0.24.0': optional: true '@esbuild/linux-ia32@0.17.19': @@ -12726,13 +11126,13 @@ snapshots: '@esbuild/linux-ia32@0.19.12': optional: true - '@esbuild/linux-ia32@0.20.2': + '@esbuild/linux-ia32@0.21.5': optional: true - '@esbuild/linux-ia32@0.21.5': + '@esbuild/linux-ia32@0.23.1': optional: true - '@esbuild/linux-ia32@0.23.0': + '@esbuild/linux-ia32@0.24.0': optional: true '@esbuild/linux-loong64@0.14.54': @@ -12747,13 +11147,13 @@ snapshots: '@esbuild/linux-loong64@0.19.12': optional: true - '@esbuild/linux-loong64@0.20.2': + '@esbuild/linux-loong64@0.21.5': optional: true - '@esbuild/linux-loong64@0.21.5': + '@esbuild/linux-loong64@0.23.1': optional: true - '@esbuild/linux-loong64@0.23.0': + '@esbuild/linux-loong64@0.24.0': optional: true '@esbuild/linux-mips64el@0.17.19': @@ -12765,13 +11165,13 @@ snapshots: '@esbuild/linux-mips64el@0.19.12': optional: true - '@esbuild/linux-mips64el@0.20.2': + '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/linux-mips64el@0.21.5': + '@esbuild/linux-mips64el@0.23.1': optional: true - '@esbuild/linux-mips64el@0.23.0': + '@esbuild/linux-mips64el@0.24.0': optional: true '@esbuild/linux-ppc64@0.17.19': @@ -12783,13 +11183,13 @@ snapshots: '@esbuild/linux-ppc64@0.19.12': optional: true - '@esbuild/linux-ppc64@0.20.2': + '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.21.5': + '@esbuild/linux-ppc64@0.23.1': optional: true - '@esbuild/linux-ppc64@0.23.0': + '@esbuild/linux-ppc64@0.24.0': optional: true '@esbuild/linux-riscv64@0.17.19': @@ -12801,13 +11201,13 @@ snapshots: '@esbuild/linux-riscv64@0.19.12': optional: true - '@esbuild/linux-riscv64@0.20.2': + '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.21.5': + '@esbuild/linux-riscv64@0.23.1': optional: true - '@esbuild/linux-riscv64@0.23.0': + '@esbuild/linux-riscv64@0.24.0': optional: true '@esbuild/linux-s390x@0.17.19': @@ -12819,13 +11219,13 @@ snapshots: '@esbuild/linux-s390x@0.19.12': optional: true - '@esbuild/linux-s390x@0.20.2': + '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/linux-s390x@0.21.5': + '@esbuild/linux-s390x@0.23.1': optional: true - '@esbuild/linux-s390x@0.23.0': + '@esbuild/linux-s390x@0.24.0': optional: true '@esbuild/linux-x64@0.17.19': @@ -12837,13 +11237,13 @@ snapshots: '@esbuild/linux-x64@0.19.12': optional: true - '@esbuild/linux-x64@0.20.2': + '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/linux-x64@0.21.5': + '@esbuild/linux-x64@0.23.1': optional: true - '@esbuild/linux-x64@0.23.0': + '@esbuild/linux-x64@0.24.0': optional: true '@esbuild/netbsd-x64@0.17.19': @@ -12855,16 +11255,19 @@ snapshots: '@esbuild/netbsd-x64@0.19.12': optional: true - '@esbuild/netbsd-x64@0.20.2': + '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/netbsd-x64@0.21.5': + '@esbuild/netbsd-x64@0.23.1': + optional: true + + '@esbuild/netbsd-x64@0.24.0': optional: true - '@esbuild/netbsd-x64@0.23.0': + '@esbuild/openbsd-arm64@0.23.1': optional: true - '@esbuild/openbsd-arm64@0.23.0': + '@esbuild/openbsd-arm64@0.24.0': optional: true '@esbuild/openbsd-x64@0.17.19': @@ -12876,13 +11279,13 @@ snapshots: '@esbuild/openbsd-x64@0.19.12': optional: true - '@esbuild/openbsd-x64@0.20.2': + '@esbuild/openbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-x64@0.21.5': + '@esbuild/openbsd-x64@0.23.1': optional: true - '@esbuild/openbsd-x64@0.23.0': + '@esbuild/openbsd-x64@0.24.0': optional: true '@esbuild/sunos-x64@0.17.19': @@ -12894,13 +11297,13 @@ snapshots: '@esbuild/sunos-x64@0.19.12': optional: true - '@esbuild/sunos-x64@0.20.2': + '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/sunos-x64@0.21.5': + '@esbuild/sunos-x64@0.23.1': optional: true - '@esbuild/sunos-x64@0.23.0': + '@esbuild/sunos-x64@0.24.0': optional: true '@esbuild/win32-arm64@0.17.19': @@ -12912,13 +11315,13 @@ snapshots: '@esbuild/win32-arm64@0.19.12': optional: true - '@esbuild/win32-arm64@0.20.2': + '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-arm64@0.21.5': + '@esbuild/win32-arm64@0.23.1': optional: true - '@esbuild/win32-arm64@0.23.0': + '@esbuild/win32-arm64@0.24.0': optional: true '@esbuild/win32-ia32@0.17.19': @@ -12930,13 +11333,13 @@ snapshots: '@esbuild/win32-ia32@0.19.12': optional: true - '@esbuild/win32-ia32@0.20.2': + '@esbuild/win32-ia32@0.21.5': optional: true - '@esbuild/win32-ia32@0.21.5': + '@esbuild/win32-ia32@0.23.1': optional: true - '@esbuild/win32-ia32@0.23.0': + '@esbuild/win32-ia32@0.24.0': optional: true '@esbuild/win32-x64@0.17.19': @@ -12948,83 +11351,29 @@ snapshots: '@esbuild/win32-x64@0.19.12': optional: true - '@esbuild/win32-x64@0.20.2': - optional: true - '@esbuild/win32-x64@0.21.5': optional: true - '@esbuild/win32-x64@0.23.0': + '@esbuild/win32-x64@0.23.1': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.50.0)': - dependencies: - eslint: 8.50.0 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/eslint-utils@4.4.0(eslint@8.53.0)': - dependencies: - eslint: 8.53.0 - eslint-visitor-keys: 3.4.3 + '@esbuild/win32-x64@0.24.0': + optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)': dependencies: - eslint: 8.57.0 + eslint: 8.57.1 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.11.0': {} - - '@eslint-community/regexpp@4.9.0': {} - - '@eslint/eslintrc@2.1.2': - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 9.6.1 - globals: 13.22.0 - ignore: 5.3.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/eslintrc@2.1.3': - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 9.6.1 - globals: 13.22.0 - ignore: 5.3.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color + '@eslint-community/regexpp@4.12.1': {} '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 9.6.1 - globals: 13.22.0 - ignore: 5.3.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/eslintrc@3.1.0': dependencies: ajv: 6.12.6 debug: 4.3.7 - espree: 10.0.1 - globals: 14.0.0 - ignore: 5.3.1 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -13032,49 +11381,43 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.50.0': {} - - '@eslint/js@8.53.0': {} - - '@eslint/js@8.57.0': {} + '@eslint/js@8.57.1': {} '@ewoudenberg/difflib@0.1.0': dependencies: heap: 0.2.7 - '@expo/bunyan@4.0.0': + '@expo/bunyan@4.0.1': dependencies: uuid: 8.3.2 - optionalDependencies: - mv: 2.1.1 - safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': + '@expo/cli@0.18.30(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.3)(utf-8-validate@6.0.3)': dependencies: - '@babel/runtime': 7.24.6 + '@babel/runtime': 7.26.0 '@expo/code-signing-certificates': 0.0.5 - '@expo/config': 9.0.2 - '@expo/config-plugins': 8.0.4 - '@expo/devcert': 1.1.2 + '@expo/config': 9.0.4 + '@expo/config-plugins': 8.0.10 + '@expo/devcert': 1.1.4 '@expo/env': 0.3.0 '@expo/image-utils': 0.5.1(encoding@0.1.13) '@expo/json-file': 8.3.3 - '@expo/metro-config': 0.18.4 - '@expo/osascript': 2.1.2 + '@expo/metro-config': 0.18.11 + '@expo/osascript': 2.1.3 '@expo/package-manager': 1.5.2 '@expo/plist': 0.1.3 - '@expo/prebuild-config': 7.0.4(encoding@0.1.13)(expo-modules-autolinking@1.11.1) + '@expo/prebuild-config': 7.0.9(encoding@0.1.13)(expo-modules-autolinking@1.11.3) '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.85(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 arg: 5.0.2 better-opn: 3.0.2 + bplist-creator: 0.0.7 bplist-parser: 0.3.2 - cacache: 18.0.3 + cacache: 18.0.4 chalk: 4.1.2 ci-info: 3.9.0 connect: 3.7.0 @@ -13082,7 +11425,7 @@ snapshots: env-editor: 0.4.2 fast-glob: 3.3.2 find-yarn-workspace-root: 2.0.0 - form-data: 3.0.1 + form-data: 3.0.2 freeport-async: 2.0.0 fs-extra: 8.1.0 getenv: 1.0.0 @@ -13113,7 +11456,7 @@ snapshots: resolve: 1.22.8 resolve-from: 5.0.0 resolve.exports: 2.0.2 - semver: 7.6.2 + semver: 7.6.3 send: 0.18.0 slugify: 1.6.6 source-map-support: 0.5.21 @@ -13139,9 +11482,9 @@ snapshots: node-forge: 1.3.1 nullthrows: 1.1.1 - '@expo/config-plugins@8.0.4': + '@expo/config-plugins@8.0.10': dependencies: - '@expo/config-types': 51.0.0 + '@expo/config-types': 51.0.3 '@expo/json-file': 8.3.3 '@expo/plist': 0.1.3 '@expo/sdk-runtime-versions': 1.0.0 @@ -13151,7 +11494,7 @@ snapshots: getenv: 1.0.0 glob: 7.1.6 resolve-from: 5.0.0 - semver: 7.6.2 + semver: 7.6.3 slash: 3.0.0 slugify: 1.6.6 xcode: 3.0.1 @@ -13159,39 +11502,38 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/config-types@51.0.0': {} + '@expo/config-types@51.0.3': {} - '@expo/config@9.0.2': + '@expo/config@9.0.4': dependencies: '@babel/code-frame': 7.10.4 - '@expo/config-plugins': 8.0.4 - '@expo/config-types': 51.0.0 + '@expo/config-plugins': 8.0.10 + '@expo/config-types': 51.0.3 '@expo/json-file': 8.3.3 getenv: 1.0.0 glob: 7.1.6 require-from-string: 2.0.2 resolve-from: 5.0.0 - semver: 7.6.2 + semver: 7.6.3 slugify: 1.6.6 sucrase: 3.34.0 transitivePeerDependencies: - supports-color - '@expo/devcert@1.1.2': + '@expo/devcert@1.1.4': dependencies: application-config-path: 0.1.1 command-exists: 1.2.9 debug: 3.2.7 eol: 0.9.1 get-port: 3.2.0 - glob: 7.2.3 + glob: 10.4.5 lodash: 4.17.21 mkdirp: 0.5.6 password-prompt: 1.1.3 - rimraf: 2.7.1 sudo-prompt: 8.2.5 tmp: 0.0.33 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -13215,7 +11557,7 @@ snapshots: node-fetch: 2.7.0(encoding@0.1.13) parse-png: 2.1.0 resolve-from: 5.0.0 - semver: 7.6.2 + semver: 7.6.3 tempy: 0.3.0 transitivePeerDependencies: - encoding @@ -13226,13 +11568,13 @@ snapshots: json5: 2.2.3 write-file-atomic: 2.4.3 - '@expo/metro-config@0.18.4': + '@expo/metro-config@0.18.11': dependencies: - '@babel/core': 7.24.6 - '@babel/generator': 7.24.6 - '@babel/parser': 7.24.6 - '@babel/types': 7.24.6 - '@expo/config': 9.0.2 + '@babel/core': 7.26.0 + '@babel/generator': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + '@expo/config': 9.0.4 '@expo/env': 0.3.0 '@expo/json-file': 8.3.3 '@expo/spawn-async': 1.7.2 @@ -13244,12 +11586,12 @@ snapshots: glob: 7.2.3 jsc-safe-url: 0.2.4 lightningcss: 1.19.0 - postcss: 8.4.39 + postcss: 8.4.47 resolve-from: 5.0.0 transitivePeerDependencies: - supports-color - '@expo/osascript@2.1.2': + '@expo/osascript@2.1.3': dependencies: '@expo/spawn-async': 1.7.2 exec-async: 2.2.0 @@ -13275,19 +11617,19 @@ snapshots: base64-js: 1.5.1 xmlbuilder: 14.0.0 - '@expo/prebuild-config@7.0.4(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': + '@expo/prebuild-config@7.0.9(encoding@0.1.13)(expo-modules-autolinking@1.11.3)': dependencies: - '@expo/config': 9.0.2 - '@expo/config-plugins': 8.0.4 - '@expo/config-types': 51.0.0 + '@expo/config': 9.0.4 + '@expo/config-plugins': 8.0.10 + '@expo/config-types': 51.0.3 '@expo/image-utils': 0.5.1(encoding@0.1.13) '@expo/json-file': 8.3.3 - '@react-native/normalize-colors': 0.74.83 + '@react-native/normalize-colors': 0.74.85 debug: 4.3.7 - expo-modules-autolinking: 1.11.1 + expo-modules-autolinking: 1.11.3 fs-extra: 9.1.0 resolve-from: 5.0.0 - semver: 7.6.2 + semver: 7.6.3 xml2js: 0.6.0 transitivePeerDependencies: - encoding @@ -13295,7 +11637,7 @@ snapshots: '@expo/rudder-sdk-node@1.1.1(encoding@0.1.13)': dependencies: - '@expo/bunyan': 4.0.0 + '@expo/bunyan': 4.0.1 '@segment/loosely-validate-event': 2.0.0 fetch-retry: 4.1.1 md5: 2.3.0 @@ -13309,9 +11651,9 @@ snapshots: '@expo/spawn-async@1.7.2': dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 - '@expo/vector-icons@14.0.2': + '@expo/vector-icons@14.0.4': dependencies: prop-types: 15.8.1 @@ -13339,49 +11681,25 @@ snapshots: dependencies: graphql: 15.8.0 - '@hapi/hoek@9.3.0': {} - - '@hapi/topo@5.1.0': + '@hono/node-server@1.13.5(hono@4.6.9)': dependencies: - '@hapi/hoek': 9.3.0 + hono: 4.6.9 - '@hono/node-server@1.12.0': {} - - '@hono/zod-validator@0.2.2(hono@4.5.0)(zod@3.23.7)': + '@hono/zod-validator@0.2.2(hono@4.6.9)(zod@3.23.8)': dependencies: - hono: 4.5.0 - zod: 3.23.7 + hono: 4.6.9 + zod: 3.23.8 - '@humanwhocodes/config-array@0.11.11': - dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@humanwhocodes/config-array@0.11.13': - dependencies: - '@humanwhocodes/object-schema': 2.0.1 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@humanwhocodes/config-array@0.11.14': + '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.4 + debug: 4.3.7 minimatch: 3.1.2 transitivePeerDependencies: - supports-color '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@1.2.1': {} - - '@humanwhocodes/object-schema@2.0.1': {} - '@humanwhocodes/object-schema@2.0.3': {} '@iarna/toml@2.2.5': {} @@ -13397,6 +11715,16 @@ snapshots: '@isaacs/ttlcache@1.4.1': {} + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + '@jest/create-cache-key-function@29.7.0': dependencies: '@jest/types': 29.6.3 @@ -13405,14 +11733,14 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.17.6 jest-mock: 29.7.0 '@jest/fake-timers@29.7.0': dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.12.12 + '@types/node': 20.17.6 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -13421,73 +11749,67 @@ snapshots: dependencies: '@sinclair/typebox': 0.27.8 - '@jest/types@26.6.2': + '@jest/transform@29.7.0': dependencies: - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 20.12.12 - '@types/yargs': 15.0.19 + '@babel/core': 7.26.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@24.9.0': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 1.1.2 + '@types/yargs': 13.0.12 '@jest/types@29.6.3': dependencies: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.12.12 - '@types/yargs': 17.0.32 + '@types/node': 20.17.6 + '@types/yargs': 17.0.33 chalk: 4.1.2 - '@jridgewell/gen-mapping@0.3.3': - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.18 - '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 - '@jridgewell/resolve-uri@3.1.0': {} - '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/set-array@1.1.2': {} - '@jridgewell/set-array@1.2.1': {} - '@jridgewell/source-map@0.3.3': - dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.18 - '@jridgewell/source-map@0.3.6': dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@jridgewell/sourcemap-codec@1.4.14': {} - - '@jridgewell/sourcemap-codec@1.4.15': {} - '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/trace-mapping@0.3.18': - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@libsql/client-wasm@0.10.0': dependencies: @@ -13499,7 +11821,7 @@ snapshots: '@libsql/core': 0.10.0 '@libsql/hrana-client': 0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) js-base64: 3.7.7 - libsql: 0.4.1 + libsql: 0.4.7 promise-limit: 2.7.0 transitivePeerDependencies: - bufferutil @@ -13509,16 +11831,10 @@ snapshots: dependencies: js-base64: 3.7.7 - '@libsql/darwin-arm64@0.3.19': - optional: true - - '@libsql/darwin-arm64@0.4.1': - optional: true - - '@libsql/darwin-x64@0.3.19': + '@libsql/darwin-arm64@0.4.7': optional: true - '@libsql/darwin-x64@0.4.1': + '@libsql/darwin-x64@0.4.7': optional: true '@libsql/hrana-client@0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)': @@ -13535,40 +11851,25 @@ snapshots: '@libsql/isomorphic-ws@0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: - '@types/ws': 8.5.11 + '@types/ws': 8.5.13 ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate - '@libsql/linux-arm64-gnu@0.3.19': - optional: true - - '@libsql/linux-arm64-gnu@0.4.1': - optional: true - - '@libsql/linux-arm64-musl@0.3.19': - optional: true - - '@libsql/linux-arm64-musl@0.4.1': + '@libsql/linux-arm64-gnu@0.4.7': optional: true - '@libsql/linux-x64-gnu@0.3.19': + '@libsql/linux-arm64-musl@0.4.7': optional: true - '@libsql/linux-x64-gnu@0.4.1': + '@libsql/linux-x64-gnu@0.4.7': optional: true - '@libsql/linux-x64-musl@0.3.19': + '@libsql/linux-x64-musl@0.4.7': optional: true - '@libsql/linux-x64-musl@0.4.1': - optional: true - - '@libsql/win32-x64-msvc@0.3.19': - optional: true - - '@libsql/win32-x64-msvc@0.4.1': + '@libsql/win32-x64-msvc@0.4.7': optional: true '@miniflare/core@2.14.4': @@ -13580,7 +11881,7 @@ snapshots: busboy: 1.6.0 dotenv: 10.0.0 kleur: 4.1.5 - set-cookie-parser: 2.6.0 + set-cookie-parser: 2.7.1 undici: 5.28.4 urlpattern-polyfill: 4.0.3 @@ -13595,7 +11896,7 @@ snapshots: '@miniflare/shared@2.14.4': dependencies: - '@types/better-sqlite3': 7.6.10 + '@types/better-sqlite3': 7.6.11 kleur: 4.1.5 npx-import: 1.1.4 picomatch: 2.3.1 @@ -13610,15 +11911,11 @@ snapshots: dependencies: '@types/pg': 8.6.6 - '@neondatabase/serverless@0.9.0': - dependencies: - '@types/pg': 8.6.6 - - '@neondatabase/serverless@0.9.3': + '@neondatabase/serverless@0.9.5': dependencies: '@types/pg': 8.11.6 - '@noble/hashes@1.4.0': {} + '@noble/hashes@1.5.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -13630,17 +11927,17 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 + fastq: 1.17.1 '@npmcli/fs@1.1.1': dependencies: '@gar/promisify': 1.1.3 - semver: 7.6.2 + semver: 7.6.3 optional: true '@npmcli/fs@3.1.1': dependencies: - semver: 7.6.2 + semver: 7.6.3 '@npmcli/move-file@1.1.2': dependencies: @@ -13648,12 +11945,12 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) - '@opentelemetry/api@1.8.0': {} + '@opentelemetry/api@1.9.0': {} '@originjs/vite-plugin-commonjs@1.0.3': dependencies: @@ -13661,16 +11958,16 @@ snapshots: '@paralleldrive/cuid2@2.2.2': dependencies: - '@noble/hashes': 1.4.0 + '@noble/hashes': 1.5.0 '@pkgjs/parseargs@0.11.0': optional: true '@pkgr/core@0.1.1': {} - '@planetscale/database@1.18.0': {} + '@planetscale/database@1.19.0': {} - '@polka/url@1.0.0-next.25': {} + '@polka/url@1.0.0-next.28': {} '@prisma/client@5.14.0(prisma@5.14.0)': optionalDependencies: @@ -13678,7 +11975,7 @@ snapshots: '@prisma/debug@5.14.0': {} - '@prisma/debug@5.16.1': {} + '@prisma/debug@5.22.0': {} '@prisma/engines-version@5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48': {} @@ -13695,245 +11992,168 @@ snapshots: '@prisma/engines-version': 5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48 '@prisma/get-platform': 5.14.0 - '@prisma/generator-helper@5.16.1': + '@prisma/generator-helper@5.22.0': dependencies: - '@prisma/debug': 5.16.1 + '@prisma/debug': 5.22.0 '@prisma/get-platform@5.14.0': dependencies: '@prisma/debug': 5.14.0 - '@react-native-community/cli-clean@13.6.6(encoding@0.1.13)': - dependencies: - '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - chalk: 4.1.2 - execa: 5.1.1 - fast-glob: 3.3.2 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-config@13.6.6(encoding@0.1.13)': - dependencies: - '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - chalk: 4.1.2 - cosmiconfig: 5.2.1 - deepmerge: 4.3.1 - fast-glob: 3.3.2 - joi: 17.13.1 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-debugger-ui@13.6.6': - dependencies: - serve-static: 1.15.0 - transitivePeerDependencies: - - supports-color - - '@react-native-community/cli-doctor@13.6.6(encoding@0.1.13)': - dependencies: - '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-platform-apple': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - chalk: 4.1.2 - command-exists: 1.2.9 - deepmerge: 4.3.1 - envinfo: 7.13.0 - execa: 5.1.1 - hermes-profile-transformer: 0.0.6 - node-stream-zip: 1.15.0 - ora: 5.4.1 - semver: 7.6.2 - strip-ansi: 5.2.0 - wcwidth: 1.0.1 - yaml: 2.4.2 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-hermes@13.6.6(encoding@0.1.13)': - dependencies: - '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - chalk: 4.1.2 - hermes-profile-transformer: 0.0.6 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-platform-android@13.6.6(encoding@0.1.13)': - dependencies: - '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - chalk: 4.1.2 - execa: 5.1.1 - fast-glob: 3.3.2 - fast-xml-parser: 4.4.0 - logkitty: 0.7.1 - transitivePeerDependencies: - - encoding + '@react-native/assets-registry@0.76.1': {} - '@react-native-community/cli-platform-apple@13.6.6(encoding@0.1.13)': + '@react-native/babel-plugin-codegen@0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0))': dependencies: - '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - chalk: 4.1.2 - execa: 5.1.1 - fast-glob: 3.3.2 - fast-xml-parser: 4.4.0 - ora: 5.4.1 + '@react-native/codegen': 0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0)) transitivePeerDependencies: - - encoding - - '@react-native-community/cli-platform-ios@13.6.6(encoding@0.1.13)': - dependencies: - '@react-native-community/cli-platform-apple': 13.6.6(encoding@0.1.13) - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': - dependencies: - '@react-native-community/cli-debugger-ui': 13.6.6 - '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - compression: 1.7.4 - connect: 3.7.0 - errorhandler: 1.5.1 - nocache: 3.0.4 - pretty-format: 26.6.2 - serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8) - transitivePeerDependencies: - - bufferutil - - encoding + - '@babel/preset-env' - supports-color - - utf-8-validate - '@react-native-community/cli-tools@13.6.6(encoding@0.1.13)': + '@react-native/babel-plugin-codegen@0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0))': dependencies: - appdirsjs: 1.2.7 - chalk: 4.1.2 - execa: 5.1.1 - find-up: 5.0.0 - mime: 2.6.0 - node-fetch: 2.7.0(encoding@0.1.13) - open: 6.4.0 - ora: 5.4.1 - semver: 7.6.2 - shell-quote: 1.8.1 - sudo-prompt: 9.2.1 - transitivePeerDependencies: - - encoding - - '@react-native-community/cli-types@13.6.6': - dependencies: - joi: 17.13.1 - - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': - dependencies: - '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-debugger-ui': 13.6.6 - '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) - '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-types': 13.6.6 - chalk: 4.1.2 - commander: 9.5.0 - deepmerge: 4.3.1 - execa: 5.1.1 - find-up: 4.1.0 - fs-extra: 8.1.0 - graceful-fs: 4.2.11 - prompts: 2.4.2 - semver: 7.6.2 + '@react-native/codegen': 0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0)) transitivePeerDependencies: - - bufferutil - - encoding + - '@babel/preset-env' - supports-color - - utf-8-validate - '@react-native/assets-registry@0.74.83': {} - - '@react-native/babel-plugin-codegen@0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6))': - dependencies: - '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + '@react-native/babel-preset@0.74.87(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))': + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.26.0) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-export-default-from': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.26.0) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.26.0) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.26.0) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-export-default-from': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) + '@babel/template': 7.25.9 + '@react-native/babel-plugin-codegen': 0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.26.0) + react-refresh: 0.14.2 transitivePeerDependencies: - '@babel/preset-env' - supports-color - '@react-native/babel-preset@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))': - dependencies: - '@babel/core': 7.24.6 - '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.24.6) - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.6) - '@babel/plugin-proposal-export-default-from': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.24.6) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.6) - '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.24.6) - '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.24.6) - '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.24.6) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.6) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-syntax-export-default-from': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-syntax-flow': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-arrow-functions': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-async-to-generator': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-block-scoping': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-classes': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-computed-properties': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-destructuring': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-flow-strip-types': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-function-name': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-literals': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-named-capturing-groups-regex': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-private-methods': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-private-property-in-object': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-react-display-name': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-react-jsx': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-react-jsx-self': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-react-jsx-source': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-runtime': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-shorthand-properties': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-spread': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-sticky-regex': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-typescript': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-unicode-regex': 7.24.6(@babel/core@7.24.6) - '@babel/template': 7.24.6 - '@react-native/babel-plugin-codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.24.6) + '@react-native/babel-preset@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))': + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-proposal-export-default-from': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-export-default-from': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-async-generator-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) + '@babel/template': 7.25.9 + '@react-native/babel-plugin-codegen': 0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + babel-plugin-syntax-hermes-parser: 0.23.1 + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.26.0) react-refresh: 0.14.2 transitivePeerDependencies: - '@babel/preset-env' - supports-color - '@react-native/codegen@0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6))': + '@react-native/codegen@0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0))': dependencies: - '@babel/parser': 7.24.6 - '@babel/preset-env': 7.24.6(@babel/core@7.24.6) + '@babel/parser': 7.26.2 + '@babel/preset-env': 7.26.0(@babel/core@7.26.0) glob: 7.2.3 hermes-parser: 0.19.1 invariant: 2.2.4 - jscodeshift: 0.14.0(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + jscodeshift: 0.14.0(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + mkdirp: 0.5.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + '@react-native/codegen@0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0))': + dependencies: + '@babel/parser': 7.26.2 + '@babel/preset-env': 7.26.0(@babel/core@7.26.0) + glob: 7.2.3 + hermes-parser: 0.23.1 + invariant: 2.2.4 + jscodeshift: 0.14.0(@babel/preset-env@7.26.0(@babel/core@7.26.0)) mkdirp: 0.5.6 nullthrows: 1.1.1 + yargs: 17.7.2 transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/community-cli-plugin@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) - '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) - '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + '@react-native/dev-middleware': 0.76.1(bufferutil@4.0.8)(utf-8-validate@6.0.3) + '@react-native/metro-babel-transformer': 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-core: 0.80.9 + invariant: 2.2.4 + metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + metro-config: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + metro-core: 0.81.0 node-fetch: 2.7.0(encoding@0.1.13) - querystring: 0.2.1 readline: 1.3.0 transitivePeerDependencies: - '@babel/core' @@ -13943,12 +12163,14 @@ snapshots: - supports-color - utf-8-validate - '@react-native/debugger-frontend@0.74.83': {} + '@react-native/debugger-frontend@0.74.85': {} + + '@react-native/debugger-frontend@0.76.1': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/dev-middleware@0.74.85(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.74.83 + '@react-native/debugger-frontend': 0.74.85 '@rnx-kit/chromium-edge-launcher': 1.0.0 chrome-launcher: 0.15.2 connect: 3.7.0 @@ -13957,43 +12179,63 @@ snapshots: nullthrows: 1.1.1 open: 7.4.2 selfsigned: 2.4.1 - serve-static: 1.15.0 + serve-static: 1.16.2 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding - supports-color - utf-8-validate - '@react-native/gradle-plugin@0.74.83': {} + '@react-native/dev-middleware@0.76.1(bufferutil@4.0.8)(utf-8-validate@6.0.3)': + dependencies: + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.76.1 + chrome-launcher: 0.15.2 + chromium-edge-launcher: 0.2.0 + connect: 3.7.0 + debug: 2.6.9 + nullthrows: 1.1.1 + open: 7.4.2 + selfsigned: 2.4.1 + serve-static: 1.16.2 + ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/gradle-plugin@0.76.1': {} - '@react-native/js-polyfills@0.74.83': {} + '@react-native/js-polyfills@0.76.1': {} - '@react-native/metro-babel-transformer@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))': + '@react-native/metro-babel-transformer@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))': dependencies: - '@babel/core': 7.24.6 - '@react-native/babel-preset': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - hermes-parser: 0.19.1 + '@babel/core': 7.26.0 + '@react-native/babel-preset': 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + hermes-parser: 0.23.1 nullthrows: 1.1.1 transitivePeerDependencies: - '@babel/preset-env' - supports-color - '@react-native/normalize-colors@0.74.83': {} + '@react-native/normalize-colors@0.74.85': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@react-native/normalize-colors@0.76.1': {} + + '@react-native/virtualized-lists@0.76.1(@types/react@18.3.12)(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) optionalDependencies: - '@types/react': 18.3.1 + '@types/react': 18.3.12 '@rnx-kit/chromium-edge-launcher@1.0.0': dependencies: - '@types/node': 18.19.33 + '@types/node': 18.19.64 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -14002,729 +12244,414 @@ snapshots: transitivePeerDependencies: - supports-color - '@rollup/plugin-terser@0.4.1(rollup@3.20.7)': + '@rollup/plugin-terser@0.4.4(rollup@3.29.5)': dependencies: - serialize-javascript: 6.0.1 - smob: 0.0.6 - terser: 5.17.1 + serialize-javascript: 6.0.2 + smob: 1.5.0 + terser: 5.36.0 optionalDependencies: - rollup: 3.20.7 + rollup: 3.29.5 - '@rollup/plugin-terser@0.4.1(rollup@3.27.2)': + '@rollup/plugin-terser@0.4.4(rollup@4.24.4)': dependencies: - serialize-javascript: 6.0.1 - smob: 0.0.6 - terser: 5.17.1 + serialize-javascript: 6.0.2 + smob: 1.5.0 + terser: 5.36.0 optionalDependencies: - rollup: 3.27.2 + rollup: 4.24.4 - '@rollup/plugin-typescript@11.1.0(rollup@3.20.7)(tslib@2.6.2)(typescript@5.6.3)': + '@rollup/plugin-typescript@11.1.6(rollup@3.29.5)(tslib@2.8.1)(typescript@5.6.3)': dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.20.7) - resolve: 1.22.1 + '@rollup/pluginutils': 5.1.3(rollup@3.29.5) + resolve: 1.22.8 typescript: 5.6.3 optionalDependencies: - rollup: 3.20.7 - tslib: 2.6.2 + rollup: 3.29.5 + tslib: 2.8.1 - '@rollup/plugin-typescript@11.1.1(rollup@3.27.2)(tslib@2.6.2)(typescript@5.6.3)': + '@rollup/plugin-typescript@11.1.6(rollup@4.24.4)(tslib@2.8.1)(typescript@5.6.3)': dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.27.2) - resolve: 1.22.2 + '@rollup/pluginutils': 5.1.3(rollup@4.24.4) + resolve: 1.22.8 typescript: 5.6.3 optionalDependencies: - rollup: 3.27.2 - tslib: 2.6.2 + rollup: 4.24.4 + tslib: 2.8.1 - '@rollup/pluginutils@5.0.2(rollup@3.20.7)': + '@rollup/pluginutils@5.1.3(rollup@3.29.5)': dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.6 estree-walker: 2.0.2 - picomatch: 2.3.1 + picomatch: 4.0.2 optionalDependencies: - rollup: 3.20.7 + rollup: 3.29.5 - '@rollup/pluginutils@5.0.2(rollup@3.27.2)': + '@rollup/pluginutils@5.1.3(rollup@4.24.4)': dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.6 estree-walker: 2.0.2 - picomatch: 2.3.1 + picomatch: 4.0.2 optionalDependencies: - rollup: 3.27.2 - - '@rollup/rollup-android-arm-eabi@4.18.0': - optional: true - - '@rollup/rollup-android-arm-eabi@4.18.1': - optional: true - - '@rollup/rollup-android-arm64@4.18.0': - optional: true - - '@rollup/rollup-android-arm64@4.18.1': - optional: true - - '@rollup/rollup-darwin-arm64@4.18.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.18.1': - optional: true - - '@rollup/rollup-darwin-x64@4.18.0': - optional: true - - '@rollup/rollup-darwin-x64@4.18.1': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.18.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.18.1': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.18.0': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.18.1': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.18.0': - optional: true + rollup: 4.24.4 - '@rollup/rollup-linux-arm64-gnu@4.18.1': + '@rollup/rollup-android-arm-eabi@4.24.4': optional: true - '@rollup/rollup-linux-arm64-musl@4.18.0': + '@rollup/rollup-android-arm64@4.24.4': optional: true - '@rollup/rollup-linux-arm64-musl@4.18.1': + '@rollup/rollup-darwin-arm64@4.24.4': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': + '@rollup/rollup-darwin-x64@4.24.4': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': + '@rollup/rollup-freebsd-arm64@4.24.4': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.18.0': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.18.1': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.18.0': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.18.1': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.18.0': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.18.1': - optional: true - - '@rollup/rollup-linux-x64-musl@4.18.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.18.1': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.18.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.18.1': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.18.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.18.1': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.18.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.18.1': - optional: true - - '@segment/loosely-validate-event@2.0.0': - dependencies: - component-type: 1.2.2 - join-component: 1.1.0 - - '@sideway/address@4.1.5': - dependencies: - '@hapi/hoek': 9.3.0 - - '@sideway/formula@3.0.1': {} - - '@sideway/pinpoint@2.0.0': {} - - '@sinclair/typebox@0.27.8': {} - - '@sinclair/typebox@0.29.6': {} - - '@sindresorhus/is@4.6.0': {} - - '@sinonjs/commons@3.0.1': - dependencies: - type-detect: 4.0.8 - - '@sinonjs/fake-timers@10.3.0': - dependencies: - '@sinonjs/commons': 3.0.1 - - '@smithy/abort-controller@2.2.0': - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - - '@smithy/abort-controller@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/config-resolver@2.2.0': - dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-config-provider': 2.3.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 - - '@smithy/config-resolver@3.0.0': - dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 - - '@smithy/core@1.4.2': - dependencies: - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 - - '@smithy/core@2.0.1': - dependencies: - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 + '@rollup/rollup-freebsd-x64@4.24.4': + optional: true - '@smithy/credential-provider-imds@2.3.0': - dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - tslib: 2.6.2 + '@rollup/rollup-linux-arm-gnueabihf@4.24.4': + optional: true - '@smithy/credential-provider-imds@3.0.0': - dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - tslib: 2.6.2 + '@rollup/rollup-linux-arm-musleabihf@4.24.4': + optional: true - '@smithy/eventstream-codec@2.2.0': - dependencies: - '@aws-crypto/crc32': 3.0.0 - '@smithy/types': 2.12.0 - '@smithy/util-hex-encoding': 2.2.0 - tslib: 2.6.2 + '@rollup/rollup-linux-arm64-gnu@4.24.4': + optional: true - '@smithy/eventstream-serde-browser@2.2.0': - dependencies: - '@smithy/eventstream-serde-universal': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@rollup/rollup-linux-arm64-musl@4.24.4': + optional: true - '@smithy/eventstream-serde-config-resolver@2.2.0': - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@rollup/rollup-linux-powerpc64le-gnu@4.24.4': + optional: true - '@smithy/eventstream-serde-node@2.2.0': - dependencies: - '@smithy/eventstream-serde-universal': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@rollup/rollup-linux-riscv64-gnu@4.24.4': + optional: true - '@smithy/eventstream-serde-universal@2.2.0': - dependencies: - '@smithy/eventstream-codec': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@rollup/rollup-linux-s390x-gnu@4.24.4': + optional: true - '@smithy/fetch-http-handler@2.5.0': - dependencies: - '@smithy/protocol-http': 3.3.0 - '@smithy/querystring-builder': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/util-base64': 2.3.0 - tslib: 2.6.2 + '@rollup/rollup-linux-x64-gnu@4.24.4': + optional: true - '@smithy/fetch-http-handler@3.0.1': - dependencies: - '@smithy/protocol-http': 4.0.0 - '@smithy/querystring-builder': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-base64': 3.0.0 - tslib: 2.6.2 + '@rollup/rollup-linux-x64-musl@4.24.4': + optional: true - '@smithy/hash-node@2.2.0': - dependencies: - '@smithy/types': 2.12.0 - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + '@rollup/rollup-win32-arm64-msvc@4.24.4': + optional: true - '@smithy/hash-node@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - '@smithy/util-buffer-from': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 + '@rollup/rollup-win32-ia32-msvc@4.24.4': + optional: true - '@smithy/invalid-dependency@2.2.0': - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@rollup/rollup-win32-x64-msvc@4.24.4': + optional: true - '@smithy/invalid-dependency@3.0.0': - dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@rtsao/scc@1.1.0': {} - '@smithy/is-array-buffer@2.2.0': + '@segment/loosely-validate-event@2.0.0': dependencies: - tslib: 2.6.2 + component-type: 1.2.2 + join-component: 1.1.0 - '@smithy/is-array-buffer@3.0.0': - dependencies: - tslib: 2.6.2 + '@sinclair/typebox@0.27.8': {} - '@smithy/middleware-content-length@2.2.0': - dependencies: - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@sinclair/typebox@0.29.6': {} - '@smithy/middleware-content-length@3.0.0': - dependencies: - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@sindresorhus/is@4.6.0': {} - '@smithy/middleware-endpoint@2.5.1': - dependencies: - '@smithy/middleware-serde': 2.3.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + '@sindresorhus/merge-streams@2.3.0': {} - '@smithy/middleware-endpoint@3.0.0': + '@sinonjs/commons@3.0.1': dependencies: - '@smithy/middleware-serde': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-middleware': 3.0.0 - tslib: 2.6.2 + type-detect: 4.0.8 - '@smithy/middleware-retry@2.3.1': + '@sinonjs/fake-timers@10.3.0': dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/service-error-classification': 2.1.5 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - tslib: 2.6.2 - uuid: 9.0.1 + '@sinonjs/commons': 3.0.1 - '@smithy/middleware-retry@3.0.1': + '@smithy/abort-controller@3.1.6': dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/service-error-classification': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - tslib: 2.6.2 - uuid: 9.0.1 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/middleware-serde@2.3.0': + '@smithy/config-resolver@3.0.10': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@smithy/node-config-provider': 3.1.9 + '@smithy/types': 3.6.0 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.8 + tslib: 2.8.1 - '@smithy/middleware-serde@3.0.0': + '@smithy/core@2.5.1': dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@smithy/middleware-serde': 3.0.8 + '@smithy/protocol-http': 4.1.5 + '@smithy/types': 3.6.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-middleware': 3.0.8 + '@smithy/util-stream': 3.2.1 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 - '@smithy/middleware-stack@2.2.0': + '@smithy/credential-provider-imds@3.2.5': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@smithy/node-config-provider': 3.1.9 + '@smithy/property-provider': 3.1.8 + '@smithy/types': 3.6.0 + '@smithy/url-parser': 3.0.8 + tslib: 2.8.1 - '@smithy/middleware-stack@3.0.0': + '@smithy/fetch-http-handler@4.0.0': dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@smithy/protocol-http': 4.1.5 + '@smithy/querystring-builder': 3.0.8 + '@smithy/types': 3.6.0 + '@smithy/util-base64': 3.0.0 + tslib: 2.8.1 - '@smithy/node-config-provider@2.3.0': + '@smithy/hash-node@3.0.8': dependencies: - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@smithy/types': 3.6.0 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 - '@smithy/node-config-provider@3.0.0': + '@smithy/invalid-dependency@3.0.8': dependencies: - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/node-http-handler@2.5.0': + '@smithy/is-array-buffer@2.2.0': dependencies: - '@smithy/abort-controller': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/querystring-builder': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 - '@smithy/node-http-handler@3.0.0': + '@smithy/is-array-buffer@3.0.0': dependencies: - '@smithy/abort-controller': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/querystring-builder': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.8.1 - '@smithy/property-provider@2.2.0': + '@smithy/middleware-content-length@3.0.10': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@smithy/protocol-http': 4.1.5 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/property-provider@3.0.0': + '@smithy/middleware-endpoint@3.2.1': dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@smithy/core': 2.5.1 + '@smithy/middleware-serde': 3.0.8 + '@smithy/node-config-provider': 3.1.9 + '@smithy/shared-ini-file-loader': 3.1.9 + '@smithy/types': 3.6.0 + '@smithy/url-parser': 3.0.8 + '@smithy/util-middleware': 3.0.8 + tslib: 2.8.1 - '@smithy/protocol-http@3.3.0': + '@smithy/middleware-retry@3.0.25': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@smithy/node-config-provider': 3.1.9 + '@smithy/protocol-http': 4.1.5 + '@smithy/service-error-classification': 3.0.8 + '@smithy/smithy-client': 3.4.2 + '@smithy/types': 3.6.0 + '@smithy/util-middleware': 3.0.8 + '@smithy/util-retry': 3.0.8 + tslib: 2.8.1 + uuid: 9.0.1 - '@smithy/protocol-http@4.0.0': + '@smithy/middleware-serde@3.0.8': dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/querystring-builder@2.2.0': + '@smithy/middleware-stack@3.0.8': dependencies: - '@smithy/types': 2.12.0 - '@smithy/util-uri-escape': 2.2.0 - tslib: 2.6.2 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/querystring-builder@3.0.0': + '@smithy/node-config-provider@3.1.9': dependencies: - '@smithy/types': 3.0.0 - '@smithy/util-uri-escape': 3.0.0 - tslib: 2.6.2 + '@smithy/property-provider': 3.1.8 + '@smithy/shared-ini-file-loader': 3.1.9 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/querystring-parser@2.2.0': + '@smithy/node-http-handler@3.2.5': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@smithy/abort-controller': 3.1.6 + '@smithy/protocol-http': 4.1.5 + '@smithy/querystring-builder': 3.0.8 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/querystring-parser@3.0.0': + '@smithy/property-provider@3.1.8': dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/service-error-classification@2.1.5': + '@smithy/protocol-http@4.1.5': dependencies: - '@smithy/types': 2.12.0 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/service-error-classification@3.0.0': + '@smithy/querystring-builder@3.0.8': dependencies: - '@smithy/types': 3.0.0 + '@smithy/types': 3.6.0 + '@smithy/util-uri-escape': 3.0.0 + tslib: 2.8.1 - '@smithy/shared-ini-file-loader@2.4.0': + '@smithy/querystring-parser@3.0.8': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/shared-ini-file-loader@3.0.0': + '@smithy/service-error-classification@3.0.8': dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@smithy/types': 3.6.0 - '@smithy/signature-v4@2.3.0': + '@smithy/shared-ini-file-loader@3.1.9': dependencies: - '@smithy/is-array-buffer': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/util-hex-encoding': 2.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-uri-escape': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/signature-v4@3.0.0': + '@smithy/signature-v4@4.2.1': dependencies: '@smithy/is-array-buffer': 3.0.0 - '@smithy/types': 3.0.0 + '@smithy/protocol-http': 4.1.5 + '@smithy/types': 3.6.0 '@smithy/util-hex-encoding': 3.0.0 - '@smithy/util-middleware': 3.0.0 + '@smithy/util-middleware': 3.0.8 '@smithy/util-uri-escape': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - - '@smithy/smithy-client@2.5.1': - dependencies: - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-stack': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 - - '@smithy/smithy-client@3.0.1': - dependencies: - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 - '@smithy/util-stream': 3.0.1 - tslib: 2.6.2 - - '@smithy/types@2.12.0': - dependencies: - tslib: 2.6.2 - - '@smithy/types@3.0.0': - dependencies: - tslib: 2.6.2 + tslib: 2.8.1 - '@smithy/url-parser@2.2.0': + '@smithy/smithy-client@3.4.2': dependencies: - '@smithy/querystring-parser': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@smithy/core': 2.5.1 + '@smithy/middleware-endpoint': 3.2.1 + '@smithy/middleware-stack': 3.0.8 + '@smithy/protocol-http': 4.1.5 + '@smithy/types': 3.6.0 + '@smithy/util-stream': 3.2.1 + tslib: 2.8.1 - '@smithy/url-parser@3.0.0': + '@smithy/types@3.6.0': dependencies: - '@smithy/querystring-parser': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + tslib: 2.8.1 - '@smithy/util-base64@2.3.0': + '@smithy/url-parser@3.0.8': dependencies: - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + '@smithy/querystring-parser': 3.0.8 + '@smithy/types': 3.6.0 + tslib: 2.8.1 '@smithy/util-base64@3.0.0': dependencies: '@smithy/util-buffer-from': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-body-length-browser@2.2.0': - dependencies: - tslib: 2.6.2 + tslib: 2.8.1 '@smithy/util-body-length-browser@3.0.0': dependencies: - tslib: 2.6.2 - - '@smithy/util-body-length-node@2.3.0': - dependencies: - tslib: 2.6.2 + tslib: 2.8.1 '@smithy/util-body-length-node@3.0.0': dependencies: - tslib: 2.6.2 + tslib: 2.8.1 '@smithy/util-buffer-from@2.2.0': dependencies: '@smithy/is-array-buffer': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 '@smithy/util-buffer-from@3.0.0': dependencies: '@smithy/is-array-buffer': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-config-provider@2.3.0': - dependencies: - tslib: 2.6.2 + tslib: 2.8.1 '@smithy/util-config-provider@3.0.0': dependencies: - tslib: 2.6.2 - - '@smithy/util-defaults-mode-browser@2.2.1': - dependencies: - '@smithy/property-provider': 2.2.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - bowser: 2.11.0 - tslib: 2.6.2 + tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@3.0.1': + '@smithy/util-defaults-mode-browser@3.0.25': dependencies: - '@smithy/property-provider': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 + '@smithy/property-provider': 3.1.8 + '@smithy/smithy-client': 3.4.2 + '@smithy/types': 3.6.0 bowser: 2.11.0 - tslib: 2.6.2 - - '@smithy/util-defaults-mode-node@2.3.1': - dependencies: - '@smithy/config-resolver': 2.2.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - - '@smithy/util-defaults-mode-node@3.0.1': - dependencies: - '@smithy/config-resolver': 3.0.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-endpoints@1.2.0': - dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 - '@smithy/util-endpoints@2.0.0': + '@smithy/util-defaults-mode-node@3.0.25': dependencies: - '@smithy/node-config-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 + '@smithy/config-resolver': 3.0.10 + '@smithy/credential-provider-imds': 3.2.5 + '@smithy/node-config-provider': 3.1.9 + '@smithy/property-provider': 3.1.8 + '@smithy/smithy-client': 3.4.2 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/util-hex-encoding@2.2.0': + '@smithy/util-endpoints@2.1.4': dependencies: - tslib: 2.6.2 + '@smithy/node-config-provider': 3.1.9 + '@smithy/types': 3.6.0 + tslib: 2.8.1 '@smithy/util-hex-encoding@3.0.0': dependencies: - tslib: 2.6.2 + tslib: 2.8.1 - '@smithy/util-middleware@2.2.0': + '@smithy/util-middleware@3.0.8': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/util-middleware@3.0.0': + '@smithy/util-retry@3.0.8': dependencies: - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-retry@2.2.0': - dependencies: - '@smithy/service-error-classification': 2.1.5 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - - '@smithy/util-retry@3.0.0': - dependencies: - '@smithy/service-error-classification': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-stream@2.2.0': - dependencies: - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/types': 2.12.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-hex-encoding': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + '@smithy/service-error-classification': 3.0.8 + '@smithy/types': 3.6.0 + tslib: 2.8.1 - '@smithy/util-stream@3.0.1': + '@smithy/util-stream@3.2.1': dependencies: - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/node-http-handler': 3.0.0 - '@smithy/types': 3.0.0 + '@smithy/fetch-http-handler': 4.0.0 + '@smithy/node-http-handler': 3.2.5 + '@smithy/types': 3.6.0 '@smithy/util-base64': 3.0.0 '@smithy/util-buffer-from': 3.0.0 '@smithy/util-hex-encoding': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-uri-escape@2.2.0': - dependencies: - tslib: 2.6.2 + tslib: 2.8.1 '@smithy/util-uri-escape@3.0.0': dependencies: - tslib: 2.6.2 + tslib: 2.8.1 '@smithy/util-utf8@2.3.0': dependencies: '@smithy/util-buffer-from': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 '@smithy/util-utf8@3.0.0': dependencies: '@smithy/util-buffer-from': 3.0.0 - tslib: 2.6.2 - - '@smithy/util-waiter@2.2.0': - dependencies: - '@smithy/abort-controller': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 '@tidbcloud/serverless@0.1.1': {} '@tootallnate/once@1.1.2': optional: true - '@trivago/prettier-plugin-sort-imports@4.2.0(prettier@3.0.3)': + '@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.3.3)': dependencies: '@babel/generator': 7.17.7 - '@babel/parser': 7.22.10 - '@babel/traverse': 7.17.3 + '@babel/parser': 7.26.2 + '@babel/traverse': 7.23.2 '@babel/types': 7.17.0 javascript-natural-sort: 0.7.1 lodash: 4.17.21 - prettier: 3.0.3 + prettier: 3.3.3 transitivePeerDependencies: - supports-color @@ -14736,71 +12663,94 @@ snapshots: '@tsconfig/node16@1.0.4': {} - '@types/async-retry@1.4.8': + '@types/async-retry@1.4.9': dependencies: '@types/retry': 0.12.5 - '@types/axios@0.14.0': + '@types/axios@0.14.4': dependencies: - axios: 1.6.8 + axios: 1.7.7 transitivePeerDependencies: - debug - '@types/better-sqlite3@7.6.10': + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + + '@types/babel__generator@7.6.8': + dependencies: + '@babel/types': 7.26.0 + + '@types/babel__template@7.4.4': dependencies: - '@types/node': 20.12.12 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + + '@types/babel__traverse@7.20.6': + dependencies: + '@babel/types': 7.26.0 + + '@types/better-sqlite3@7.6.11': + dependencies: + '@types/node': 18.19.64 '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 20.12.12 + '@types/node': 20.17.6 '@types/braces@3.0.4': {} '@types/connect@3.4.38': dependencies: - '@types/node': 20.12.12 + '@types/node': 20.17.6 '@types/docker-modem@3.0.6': dependencies: - '@types/node': 20.12.12 - '@types/ssh2': 1.15.0 + '@types/node': 18.19.64 + '@types/ssh2': 1.15.1 - '@types/dockerode@3.3.29': + '@types/dockerode@3.3.31': dependencies: '@types/docker-modem': 3.0.6 - '@types/node': 20.12.12 - '@types/ssh2': 1.15.0 + '@types/node': 18.19.64 + '@types/ssh2': 1.15.1 - '@types/emscripten@1.39.11': {} + '@types/emscripten@1.39.13': {} - '@types/estree@1.0.1': {} + '@types/estree@1.0.6': {} - '@types/estree@1.0.5': {} - - '@types/express-serve-static-core@4.19.0': + '@types/express-serve-static-core@4.19.6': dependencies: - '@types/node': 20.12.12 - '@types/qs': 6.9.15 + '@types/node': 20.17.6 + '@types/qs': 6.9.17 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 '@types/express@4.17.21': dependencies: '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.19.0 - '@types/qs': 6.9.15 + '@types/express-serve-static-core': 4.19.6 + '@types/qs': 6.9.17 '@types/serve-static': 1.15.7 '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 20.12.12 + '@types/node': 18.19.64 '@types/glob@8.1.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.12.12 + '@types/node': 18.19.64 + + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 20.17.6 '@types/http-errors@2.0.4': {} @@ -14810,19 +12760,24 @@ snapshots: dependencies: '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports@1.1.2': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-lib-report': 3.0.3 + '@types/istanbul-reports@3.0.4': dependencies: '@types/istanbul-lib-report': 3.0.3 '@types/json-diff@1.0.3': {} - '@types/json-schema@7.0.13': {} + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} '@types/jsonfile@6.1.4': dependencies: - '@types/node': 20.12.12 + '@types/node': 18.19.64 '@types/micromatch@4.0.9': dependencies: @@ -14832,53 +12787,61 @@ snapshots: '@types/minimatch@5.1.2': {} - '@types/minimist@1.2.2': {} + '@types/minimist@1.2.5': {} '@types/node-forge@1.3.11': dependencies: - '@types/node': 20.12.12 - - '@types/node@18.15.10': {} + '@types/node': 18.19.64 - '@types/node@18.19.33': + '@types/node@18.19.64': dependencies: undici-types: 5.26.5 - '@types/node@20.10.1': + '@types/node@20.12.14': dependencies: undici-types: 5.26.5 - '@types/node@20.12.12': + '@types/node@20.17.6': dependencies: - undici-types: 5.26.5 + undici-types: 6.19.8 + + '@types/node@22.9.0': + dependencies: + undici-types: 6.19.8 + + '@types/normalize-package-data@2.4.4': {} - '@types/normalize-package-data@2.4.1': {} + '@types/pg@8.11.10': + dependencies: + '@types/node': 18.19.64 + pg-protocol: 1.7.0 + pg-types: 4.0.2 '@types/pg@8.11.6': dependencies: - '@types/node': 20.12.12 - pg-protocol: 1.6.1 + '@types/node': 18.19.64 + pg-protocol: 1.7.0 pg-types: 4.0.2 '@types/pg@8.6.6': dependencies: - '@types/node': 20.12.12 - pg-protocol: 1.6.1 + '@types/node': 18.19.64 + pg-protocol: 1.7.0 pg-types: 2.2.0 '@types/pluralize@0.0.33': {} - '@types/prop-types@15.7.12': {} + '@types/prop-types@15.7.13': {} - '@types/ps-tree@1.1.2': {} + '@types/ps-tree@1.1.6': {} - '@types/qs@6.9.15': {} + '@types/qs@6.9.17': {} '@types/range-parser@1.2.7': {} - '@types/react@18.3.1': + '@types/react@18.3.12': dependencies: - '@types/prop-types': 15.7.12 + '@types/prop-types': 15.7.13 csstype: 3.1.3 '@types/retry@0.12.5': {} @@ -14888,137 +12851,126 @@ snapshots: '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 20.12.12 + '@types/node': 20.17.6 '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 20.12.12 + '@types/node': 20.17.6 '@types/send': 0.17.4 '@types/sql.js@1.4.9': dependencies: - '@types/emscripten': 1.39.11 - '@types/node': 20.12.12 + '@types/emscripten': 1.39.13 + '@types/node': 20.17.6 - '@types/ssh2@1.15.0': + '@types/ssh2@1.15.1': dependencies: - '@types/node': 18.19.33 + '@types/node': 18.19.64 '@types/stack-utils@2.0.3': {} + '@types/uuid@10.0.0': {} + '@types/uuid@9.0.8': {} - '@types/which@3.0.0': {} + '@types/which@3.0.4': {} - '@types/ws@8.5.11': + '@types/ws@8.5.13': dependencies: - '@types/node': 20.12.12 + '@types/node': 18.19.64 '@types/yargs-parser@21.0.3': {} - '@types/yargs@15.0.19': + '@types/yargs@13.0.12': dependencies: '@types/yargs-parser': 21.0.3 - '@types/yargs@17.0.32': + '@types/yargs@17.0.33': dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.9.0 - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 6.7.3 - '@typescript-eslint/type-utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) - '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 6.7.3 - debug: 4.3.4 - eslint: 8.50.0 + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.7 + eslint: 8.57.1 graphemer: 1.4.0 - ignore: 5.2.4 + ignore: 5.3.2 natural-compare: 1.4.0 - semver: 7.6.2 - ts-api-utils: 1.0.3(typescript@5.6.3) + semver: 7.6.3 + ts-api-utils: 1.4.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 7.16.1 - '@typescript-eslint/type-utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) - '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 7.16.1 - eslint: 8.57.0 + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/type-utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 7.18.0 + eslint: 8.57.1 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.6.3) + ts-api-utils: 1.4.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/experimental-utils@5.62.0(eslint@8.50.0)(typescript@5.6.3)': + '@typescript-eslint/experimental-utils@5.62.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.50.0)(typescript@5.6.3) - eslint: 8.50.0 + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.6.3) + eslint: 8.57.1 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.2.2)': - dependencies: - '@typescript-eslint/scope-manager': 6.10.0 - '@typescript-eslint/types': 6.10.0 - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.10.0 - debug: 4.3.4 - eslint: 8.53.0 - optionalDependencies: - typescript: 5.2.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3)': + '@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@typescript-eslint/scope-manager': 6.7.3 - '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 6.7.3 - debug: 4.3.4 - eslint: 8.50.0 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.7 + eslint: 8.57.1 optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3)': + '@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@typescript-eslint/scope-manager': 7.16.1 - '@typescript-eslint/types': 7.16.1 - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 7.16.1 - debug: 4.3.4 - eslint: 8.57.0 + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 7.18.0 + debug: 4.3.7 + eslint: 8.57.1 optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/rule-tester@6.10.0(@eslint/eslintrc@3.1.0)(eslint@8.53.0)(typescript@5.2.2)': + '@typescript-eslint/rule-tester@6.21.0(@eslint/eslintrc@2.1.4)(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@eslint/eslintrc': 3.1.0 - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) - '@typescript-eslint/utils': 6.10.0(eslint@8.53.0)(typescript@5.2.2) + '@eslint/eslintrc': 2.1.4 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) ajv: 6.12.6 - eslint: 8.53.0 + eslint: 8.57.1 lodash.merge: 4.6.2 - semver: 7.6.2 + semver: 7.6.3 transitivePeerDependencies: - supports-color - typescript @@ -15028,40 +12980,35 @@ snapshots: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - '@typescript-eslint/scope-manager@6.10.0': + '@typescript-eslint/scope-manager@6.21.0': dependencies: - '@typescript-eslint/types': 6.10.0 - '@typescript-eslint/visitor-keys': 6.10.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 - '@typescript-eslint/scope-manager@6.7.3': + '@typescript-eslint/scope-manager@7.18.0': dependencies: - '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/visitor-keys': 6.7.3 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 - '@typescript-eslint/scope-manager@7.16.1': + '@typescript-eslint/type-utils@6.21.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 7.16.1 - '@typescript-eslint/visitor-keys': 7.16.1 - - '@typescript-eslint/type-utils@6.7.3(eslint@8.50.0)(typescript@5.6.3)': - dependencies: - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) - '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) - debug: 4.3.4 - eslint: 8.50.0 - ts-api-utils: 1.0.3(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) + debug: 4.3.7 + eslint: 8.57.1 + ts-api-utils: 1.4.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@7.16.1(eslint@8.57.0)(typescript@5.6.3)': + '@typescript-eslint/type-utils@7.18.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) - '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) - debug: 4.3.4 - eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) + '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) + debug: 4.3.7 + eslint: 8.57.1 + ts-api-utils: 1.4.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -15069,119 +13016,90 @@ snapshots: '@typescript-eslint/types@5.62.0': {} - '@typescript-eslint/types@6.10.0': {} + '@typescript-eslint/types@6.21.0': {} - '@typescript-eslint/types@6.7.3': {} - - '@typescript-eslint/types@7.16.1': {} + '@typescript-eslint/types@7.18.0': {} '@typescript-eslint/typescript-estree@5.62.0(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4 + debug: 4.3.7 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.2 + semver: 7.6.3 tsutils: 3.21.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2)': - dependencies: - '@typescript-eslint/types': 6.10.0 - '@typescript-eslint/visitor-keys': 6.10.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.6.2 - ts-api-utils: 1.0.3(typescript@5.2.2) - optionalDependencies: - typescript: 5.2.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/typescript-estree@6.7.3(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@6.21.0(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/visitor-keys': 6.7.3 - debug: 4.3.4 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.7 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.2 - ts-api-utils: 1.0.3(typescript@5.6.3) + minimatch: 9.0.3 + semver: 7.6.3 + ts-api-utils: 1.4.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.16.1(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@7.18.0(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 7.16.1 - '@typescript-eslint/visitor-keys': 7.16.1 - debug: 4.3.4 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 + debug: 4.3.7 globby: 11.1.0 is-glob: 4.0.3 - minimatch: 9.0.4 - semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.6.3) + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.4.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@8.50.0)(typescript@5.6.3)': + '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) - '@types/json-schema': 7.0.13 + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.3) - eslint: 8.50.0 + eslint: 8.57.1 eslint-scope: 5.1.1 - semver: 7.6.2 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/utils@6.10.0(eslint@8.53.0)(typescript@5.2.2)': - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) - '@types/json-schema': 7.0.13 - '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 6.10.0 - '@typescript-eslint/types': 6.10.0 - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) - eslint: 8.53.0 - semver: 7.6.2 + semver: 7.6.3 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@6.7.3(eslint@8.50.0)(typescript@5.6.3)': + '@typescript-eslint/utils@6.21.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) - '@types/json-schema': 7.0.13 + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 6.7.3 - '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) - eslint: 8.50.0 - semver: 7.6.2 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) + eslint: 8.57.1 + semver: 7.6.3 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@7.16.1(eslint@8.57.0)(typescript@5.6.3)': + '@typescript-eslint/utils@7.18.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 7.16.1 - '@typescript-eslint/types': 7.16.1 - '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) - eslint: 8.57.0 + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) + eslint: 8.57.1 transitivePeerDependencies: - supports-color - typescript @@ -15191,19 +13109,14 @@ snapshots: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@6.10.0': - dependencies: - '@typescript-eslint/types': 6.10.0 - eslint-visitor-keys: 3.4.3 - - '@typescript-eslint/visitor-keys@6.7.3': + '@typescript-eslint/visitor-keys@6.21.0': dependencies: - '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/types': 6.21.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@7.16.1': + '@typescript-eslint/visitor-keys@7.18.0': dependencies: - '@typescript-eslint/types': 7.16.1 + '@typescript-eslint/types': 7.18.0 eslint-visitor-keys: 3.4.3 '@typescript/analyze-trace@0.10.1': @@ -15242,24 +13155,32 @@ snapshots: dependencies: '@vitest/spy': 1.6.0 '@vitest/utils': 1.6.0 - chai: 4.4.1 + chai: 4.5.0 - '@vitest/expect@2.1.2': + '@vitest/expect@2.1.4': dependencies: - '@vitest/spy': 2.1.2 - '@vitest/utils': 2.1.2 - chai: 5.1.1 + '@vitest/spy': 2.1.4 + '@vitest/utils': 2.1.4 + chai: 5.1.2 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0))': + '@vitest/mocker@2.1.4(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0))': + dependencies: + '@vitest/spy': 2.1.4 + estree-walker: 3.0.3 + magic-string: 0.30.12 + optionalDependencies: + vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) + + '@vitest/mocker@2.1.4(vite@5.4.10(@types/node@22.9.0)(terser@5.36.0))': dependencies: - '@vitest/spy': 2.1.2 + '@vitest/spy': 2.1.4 estree-walker: 3.0.3 - magic-string: 0.30.11 + magic-string: 0.30.12 optionalDependencies: - vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.4.10(@types/node@22.9.0)(terser@5.36.0) - '@vitest/pretty-format@2.1.2': + '@vitest/pretty-format@2.1.4': dependencies: tinyrainbow: 1.2.0 @@ -15269,28 +13190,28 @@ snapshots: p-limit: 5.0.0 pathe: 1.1.2 - '@vitest/runner@2.1.2': + '@vitest/runner@2.1.4': dependencies: - '@vitest/utils': 2.1.2 + '@vitest/utils': 2.1.4 pathe: 1.1.2 '@vitest/snapshot@1.6.0': dependencies: - magic-string: 0.30.10 + magic-string: 0.30.12 pathe: 1.1.2 pretty-format: 29.7.0 - '@vitest/snapshot@2.1.2': + '@vitest/snapshot@2.1.4': dependencies: - '@vitest/pretty-format': 2.1.2 - magic-string: 0.30.11 + '@vitest/pretty-format': 2.1.4 + magic-string: 0.30.12 pathe: 1.1.2 '@vitest/spy@1.6.0': dependencies: tinyspy: 2.2.1 - '@vitest/spy@2.1.2': + '@vitest/spy@2.1.4': dependencies: tinyspy: 3.0.2 @@ -15301,21 +13222,21 @@ snapshots: fflate: 0.8.2 flatted: 3.3.1 pathe: 1.1.2 - picocolors: 1.0.1 + picocolors: 1.1.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + vitest: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) optional: true - '@vitest/ui@1.6.0(vitest@2.1.2)': + '@vitest/ui@1.6.0(vitest@2.1.4)': dependencies: '@vitest/utils': 1.6.0 fast-glob: 3.3.2 fflate: 0.8.2 flatted: 3.3.1 pathe: 1.1.2 - picocolors: 1.0.1 + picocolors: 1.1.1 sirv: 2.0.4 - vitest: 2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + vitest: 2.1.4(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) '@vitest/utils@1.6.0': dependencies: @@ -15324,13 +13245,13 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 - '@vitest/utils@2.1.2': + '@vitest/utils@2.1.4': dependencies: - '@vitest/pretty-format': 2.1.2 + '@vitest/pretty-format': 2.1.4 loupe: 3.1.2 tinyrainbow: 1.2.0 - '@xata.io/client@0.29.4(typescript@5.6.3)': + '@xata.io/client@0.29.5(typescript@5.6.3)': dependencies: typescript: 5.6.3 @@ -15350,25 +13271,19 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-jsx@5.3.2(acorn@8.10.0): + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: - acorn: 8.10.0 + acorn: 8.14.0 - acorn-jsx@5.3.2(acorn@8.11.3): + acorn-walk@8.3.4: dependencies: - acorn: 8.11.3 - - acorn-walk@8.3.2: {} - - acorn@8.10.0: {} + acorn: 8.14.0 - acorn@8.11.3: {} - - acorn@8.8.2: {} + acorn@8.14.0: {} agent-base@6.0.2: dependencies: - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -15402,21 +13317,17 @@ snapshots: dependencies: type-fest: 0.21.3 - ansi-escapes@6.2.0: - dependencies: - type-fest: 3.13.1 + ansi-escapes@6.2.1: {} - ansi-fragments@0.2.1: + ansi-escapes@7.0.0: dependencies: - colorette: 1.4.0 - slice-ansi: 2.1.0 - strip-ansi: 5.2.0 + environment: 1.1.0 ansi-regex@4.1.1: {} ansi-regex@5.0.1: {} - ansi-regex@6.0.1: {} + ansi-regex@6.1.0: {} ansi-styles@3.2.1: dependencies: @@ -15439,8 +13350,6 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - appdirsjs@1.2.7: {} - application-config-path@0.1.1: {} aproba@2.0.0: @@ -15464,11 +13373,6 @@ snapshots: argsarray@0.0.1: {} - array-buffer-byte-length@1.0.0: - dependencies: - call-bind: 1.0.2 - is-array-buffer: 3.0.2 - array-buffer-byte-length@1.0.1: dependencies: call-bind: 1.0.7 @@ -15478,46 +13382,39 @@ snapshots: array-flatten@1.1.1: {} - array-includes@3.1.6: + array-includes@3.1.8: dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 is-string: 1.0.7 array-union@2.1.0: {} - array.prototype.findlastindex@1.2.2: - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - es-shim-unscopables: 1.0.0 - get-intrinsic: 1.2.1 - - array.prototype.flat@1.3.1: + array.prototype.findlastindex@1.2.5: dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - es-shim-unscopables: 1.0.0 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 - array.prototype.flatmap@1.3.1: + array.prototype.flat@1.3.2: dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - es-shim-unscopables: 1.0.0 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 - arraybuffer.prototype.slice@1.0.1: + array.prototype.flatmap@1.3.2: dependencies: - array-buffer-byte-length: 1.0.0 - call-bind: 1.0.2 - define-properties: 1.2.0 - get-intrinsic: 1.2.1 - is-array-buffer: 3.0.2 - is-shared-array-buffer: 1.0.2 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 arraybuffer.prototype.slice@1.0.3: dependencies: @@ -15550,13 +13447,11 @@ snapshots: ast-types@0.15.2: dependencies: - tslib: 2.6.2 + tslib: 2.8.1 ast-types@0.16.1: dependencies: - tslib: 2.6.2 - - astral-regex@1.0.0: {} + tslib: 2.8.1 async-limiter@1.0.1: {} @@ -15568,17 +13463,17 @@ snapshots: at-least-node@1.0.0: {} - ava@5.3.0(@ava/typescript@5.0.0): + ava@5.3.1: dependencies: - acorn: 8.11.3 - acorn-walk: 8.3.2 + acorn: 8.14.0 + acorn-walk: 8.3.4 ansi-styles: 6.2.1 arrgv: 1.0.2 arrify: 3.0.0 - callsites: 4.1.0 + callsites: 4.2.0 cbor: 8.1.0 chalk: 5.3.0 - chokidar: 3.5.3 + chokidar: 3.6.0 chunkd: 2.0.1 ci-info: 3.9.0 ci-parallel-vars: 1.0.1 @@ -15588,7 +13483,7 @@ snapshots: common-path-prefix: 3.0.0 concordance: 5.0.4 currently-unhandled: 0.4.1 - debug: 4.3.4 + debug: 4.3.7 emittery: 1.0.3 figures: 5.0.0 globby: 13.2.2 @@ -15613,80 +13508,145 @@ snapshots: temp-dir: 3.0.0 write-file-atomic: 5.0.1 yargs: 17.7.2 - optionalDependencies: - '@ava/typescript': 5.0.0 transitivePeerDependencies: - supports-color - available-typed-arrays@1.0.5: {} - available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 - aws-ssl-profiles@1.1.1: - optional: true + aws4fetch@1.0.20: {} - axios@1.6.8: + axios@1.7.7: dependencies: - follow-redirects: 1.15.6 - form-data: 4.0.0 + follow-redirects: 1.15.9 + form-data: 4.0.1 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug - babel-core@7.0.0-bridge.0(@babel/core@7.24.6): + babel-core@7.0.0-bridge.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + + babel-jest@29.7.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.26.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@6.1.1: + dependencies: + '@babel/helper-plugin-utils': 7.25.9 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: dependencies: - '@babel/core': 7.24.6 + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.6 - babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.6): + babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.26.0): dependencies: - '@babel/compat-data': 7.24.6 - '@babel/core': 7.24.6 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) + '@babel/compat-data': 7.26.2 + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.6): + babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.26.0): dependencies: - '@babel/core': 7.24.6 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) - core-js-compat: 3.37.1 + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) + core-js-compat: 3.39.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.24.6): + babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.26.0): dependencies: - '@babel/core': 7.24.6 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) transitivePeerDependencies: - supports-color - babel-plugin-react-native-web@0.19.12: {} + babel-plugin-react-compiler@0.0.0-experimental-592953e-20240517: + dependencies: + '@babel/generator': 7.2.0 + '@babel/types': 7.26.0 + chalk: 4.1.2 + invariant: 2.2.4 + pretty-format: 24.9.0 + zod: 3.23.8 + zod-validation-error: 2.1.0(zod@3.23.8) + + babel-plugin-react-native-web@0.19.13: {} + + babel-plugin-syntax-hermes-parser@0.23.1: + dependencies: + hermes-parser: 0.23.1 - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.24.6): + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.26.0): dependencies: - '@babel/plugin-syntax-flow': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) transitivePeerDependencies: - '@babel/core' - babel-preset-expo@11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)): - dependencies: - '@babel/plugin-proposal-decorators': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-export-namespace-from': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-object-rest-spread': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) - '@babel/preset-react': 7.24.6(@babel/core@7.24.6) - '@babel/preset-typescript': 7.24.6(@babel/core@7.24.6) - '@react-native/babel-preset': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - babel-plugin-react-native-web: 0.19.12 + babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.0) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0) + + babel-preset-expo@11.0.15(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)): + dependencies: + '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/preset-react': 7.25.9(@babel/core@7.26.0) + '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) + '@react-native/babel-preset': 0.74.87(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + babel-plugin-react-compiler: 0.0.0-experimental-592953e-20240517 + babel-plugin-react-native-web: 0.19.13 react-refresh: 0.14.2 transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' - supports-color + babel-preset-jest@29.6.3(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) + balanced-match@1.0.2: {} base64-js@1.5.1: {} @@ -15699,6 +13659,11 @@ snapshots: dependencies: open: 8.4.2 + better-sqlite3@11.5.0: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.2 + better-sqlite3@8.7.0: dependencies: bindings: 1.5.0 @@ -15711,7 +13676,7 @@ snapshots: big-integer@1.6.52: {} - binary-extensions@2.2.0: {} + binary-extensions@2.3.0: {} bindings@1.5.0: dependencies: @@ -15727,7 +13692,7 @@ snapshots: blueimp-md5@2.19.0: {} - body-parser@1.20.2: + body-parser@1.20.3: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -15737,7 +13702,7 @@ snapshots: http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.11.0 + qs: 6.13.0 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 @@ -15746,6 +13711,10 @@ snapshots: bowser@2.11.0: {} + bplist-creator@0.0.7: + dependencies: + stream-buffers: 2.2.0 + bplist-creator@0.1.0: dependencies: stream-buffers: 2.2.0 @@ -15771,12 +13740,12 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.23.0: + browserslist@4.24.2: dependencies: - caniuse-lite: 1.0.30001624 - electron-to-chromium: 1.4.783 - node-releases: 2.0.14 - update-browserslist-db: 1.0.16(browserslist@4.23.0) + caniuse-lite: 1.0.30001679 + electron-to-chromium: 1.5.55 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.2) bser@2.1.1: dependencies: @@ -15800,7 +13769,7 @@ snapshots: bufferutil@4.0.8: dependencies: - node-gyp-build: 4.8.1 + node-gyp-build: 4.8.2 buildcheck@0.0.6: optional: true @@ -15811,28 +13780,29 @@ snapshots: builtins@5.1.0: dependencies: - semver: 7.6.2 + semver: 7.6.3 bun-types@0.6.14: {} - bun-types@1.0.3: {} + bun-types@1.1.34: + dependencies: + '@types/node': 20.12.14 + '@types/ws': 8.5.13 - bundle-require@4.0.2(esbuild@0.18.20): + bundle-require@4.2.1(esbuild@0.19.12): dependencies: - esbuild: 0.18.20 + esbuild: 0.19.12 load-tsconfig: 0.2.5 - bundle-require@5.0.0(esbuild@0.23.0): + bundle-require@5.0.0(esbuild@0.24.0): dependencies: - esbuild: 0.23.0 + esbuild: 0.24.0 load-tsconfig: 0.2.5 busboy@1.6.0: dependencies: streamsearch: 1.1.0 - bytes@3.0.0: {} - bytes@3.1.2: {} cac@6.7.14: {} @@ -15861,12 +13831,12 @@ snapshots: - bluebird optional: true - cacache@18.0.3: + cacache@18.0.4: dependencies: '@npmcli/fs': 3.1.1 fs-minipass: 3.0.3 - glob: 10.4.1 - lru-cache: 10.2.2 + glob: 10.4.5 + lru-cache: 10.4.3 minipass: 7.1.2 minipass-collect: 2.0.1 minipass-flush: 1.0.5 @@ -15876,11 +13846,6 @@ snapshots: tar: 6.2.1 unique-filename: 3.0.0 - call-bind@1.0.2: - dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.2.1 - call-bind@1.0.7: dependencies: es-define-property: 1.0.0 @@ -15901,7 +13866,7 @@ snapshots: callsites@3.1.0: {} - callsites@4.1.0: {} + callsites@4.2.0: {} camelcase@5.3.1: {} @@ -15909,12 +13874,12 @@ snapshots: camelcase@7.0.1: {} - caniuse-lite@1.0.30001624: {} + caniuse-lite@1.0.30001679: {} capnp-ts@0.7.0: dependencies: - debug: 4.3.4 - tslib: 2.6.2 + debug: 4.3.7 + tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -15927,17 +13892,17 @@ snapshots: dependencies: nofilter: 3.1.0 - chai@4.4.1: + chai@4.5.0: dependencies: assertion-error: 1.1.0 check-error: 1.0.3 - deep-eql: 4.1.3 + deep-eql: 4.1.4 get-func-name: 2.0.2 loupe: 2.3.7 pathval: 1.1.1 - type-detect: 4.0.8 + type-detect: 4.1.0 - chai@5.1.1: + chai@5.1.2: dependencies: assertion-error: 2.0.1 check-error: 2.1.1 @@ -15966,20 +13931,8 @@ snapshots: dependencies: get-func-name: 2.0.2 - check-error@2.1.1: {} - - chokidar@3.5.3: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - + check-error@2.1.1: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -15992,16 +13945,31 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.1: + dependencies: + readdirp: 4.0.2 + chownr@1.1.4: {} chownr@2.0.0: {} chrome-launcher@0.15.2: dependencies: - '@types/node': 20.12.12 + '@types/node': 20.17.6 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + transitivePeerDependencies: + - supports-color + + chromium-edge-launcher@0.2.0: + dependencies: + '@types/node': 20.17.6 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 + mkdirp: 1.0.4 + rimraf: 3.0.2 transitivePeerDependencies: - supports-color @@ -16009,12 +13977,12 @@ snapshots: ci-info@2.0.0: {} - ci-info@3.8.0: {} - ci-info@3.9.0: {} ci-parallel-vars@1.0.1: {} + cjs-module-lexer@1.4.1: {} + clean-regexp@1.0.0: dependencies: escape-string-regexp: 1.0.5 @@ -16027,25 +13995,30 @@ snapshots: clean-yaml-object@0.1.0: {} - cli-color@2.0.3: + cli-color@2.0.4: dependencies: - d: 1.0.1 - es5-ext: 0.10.62 + d: 1.0.2 + es5-ext: 0.10.64 es6-iterator: 2.0.3 - memoizee: 0.4.15 - timers-ext: 0.1.7 + memoizee: 0.4.17 + timers-ext: 0.1.8 cli-cursor@2.1.0: dependencies: restore-cursor: 2.0.0 - cli-cursor@3.1.0: + cli-highlight@2.1.11: dependencies: - restore-cursor: 3.1.0 + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.0 cli-spinners@2.9.2: {} - cli-table3@0.6.3: + cli-table3@0.6.5: dependencies: string-width: 4.2.3 optionalDependencies: @@ -16056,12 +14029,6 @@ snapshots: slice-ansi: 5.0.0 string-width: 5.1.2 - cliui@6.0.0: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - cliui@7.0.4: dependencies: string-width: 4.2.3 @@ -16103,8 +14070,6 @@ snapshots: color-support@1.1.3: optional: true - colorette@1.4.0: {} - colorette@2.0.19: {} colors@1.4.0: {} @@ -16117,8 +14082,6 @@ snapshots: commander@10.0.1: {} - commander@11.0.0: {} - commander@12.1.0: {} commander@2.20.3: {} @@ -16135,22 +14098,6 @@ snapshots: component-type@1.2.2: {} - compressible@2.0.18: - dependencies: - mime-db: 1.52.0 - - compression@1.7.4: - dependencies: - accepts: 1.3.8 - bytes: 3.0.0 - compressible: 2.0.18 - debug: 2.6.9 - on-headers: 1.0.2 - safe-buffer: 5.1.2 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - concat-map@0.0.1: {} concordance@5.0.4: @@ -16161,10 +14108,10 @@ snapshots: js-string-escape: 1.0.1 lodash: 4.17.21 md5-hex: 3.0.1 - semver: 7.6.2 + semver: 7.6.3 well-known-symbols: 2.0.0 - concurrently@8.2.1: + concurrently@8.2.2: dependencies: chalk: 4.1.2 date-fns: 2.30.0 @@ -16176,7 +14123,7 @@ snapshots: tree-kill: 1.2.2 yargs: 17.7.2 - confbox@0.1.7: {} + confbox@0.1.8: {} connect@3.7.0: dependencies: @@ -16204,17 +14151,22 @@ snapshots: cookie-signature@1.0.6: {} - cookie@0.5.0: {} + cookie@0.7.1: {} - cookie@0.6.0: {} + cookie@0.7.2: {} copy-anything@3.0.5: dependencies: is-what: 4.1.16 - core-js-compat@3.37.1: + copy-file@11.0.0: + dependencies: + graceful-fs: 4.2.11 + p-event: 6.0.1 + + core-js-compat@3.39.0: dependencies: - browserslist: 4.23.0 + browserslist: 4.24.2 core-util-is@1.0.3: {} @@ -16234,7 +14186,7 @@ snapshots: cpu-features@0.0.10: dependencies: buildcheck: 0.0.6 - nan: 2.19.0 + nan: 2.22.0 optional: true cpy-cli@5.0.0: @@ -16248,16 +14200,25 @@ snapshots: cp-file: 10.0.0 globby: 13.2.2 junk: 4.0.1 - micromatch: 4.0.7 + micromatch: 4.0.8 nested-error-stacks: 2.1.1 p-filter: 3.0.0 p-map: 6.0.0 + cpy@11.1.0: + dependencies: + copy-file: 11.0.0 + globby: 14.0.2 + junk: 4.0.1 + micromatch: 4.0.8 + p-filter: 4.1.0 + p-map: 7.0.2 + create-require@1.1.1: {} cross-env@7.0.3: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 cross-fetch@3.1.8(encoding@0.1.13): dependencies: @@ -16273,7 +14234,7 @@ snapshots: shebang-command: 1.2.0 which: 1.3.1 - cross-spawn@7.0.3: + cross-spawn@7.0.5: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -16291,10 +14252,10 @@ snapshots: dependencies: array-find-index: 1.0.2 - d@1.0.1: + d@1.0.2: dependencies: - es5-ext: 0.10.62 - type: 1.2.0 + es5-ext: 0.10.64 + type: 2.7.3 dag-map@1.0.2: {} @@ -16322,16 +14283,14 @@ snapshots: date-fns@2.30.0: dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.26.0 - date-fns@3.6.0: {} + date-fns@4.1.0: {} date-time@3.1.0: dependencies: time-zone: 1.0.0 - dayjs@1.11.11: {} - debug@2.6.9: dependencies: ms: 2.0.0 @@ -16344,23 +14303,17 @@ snapshots: dependencies: ms: 2.1.2 - debug@4.3.5: - dependencies: - ms: 2.1.2 - debug@4.3.7: dependencies: ms: 2.1.3 - decamelize@1.2.0: {} - decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 - deep-eql@4.1.3: + deep-eql@4.1.4: dependencies: - type-detect: 4.0.8 + type-detect: 4.1.0 deep-eql@5.0.2: {} @@ -16368,8 +14321,6 @@ snapshots: deep-is@0.1.4: {} - deepmerge@4.3.1: {} - default-gateway@4.2.0: dependencies: execa: 1.0.0 @@ -16387,11 +14338,6 @@ snapshots: define-lazy-prop@2.0.0: {} - define-properties@1.2.0: - dependencies: - has-property-descriptors: 1.0.0 - object-keys: 1.1.1 - define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -16436,7 +14382,7 @@ snapshots: diff@4.0.2: {} - diff@5.1.0: {} + diff@5.2.0: {} difflib@0.2.4: dependencies: @@ -16448,10 +14394,19 @@ snapshots: docker-modem@3.0.8: dependencies: - debug: 4.3.4 + debug: 4.3.7 + readable-stream: 3.6.2 + split-ca: 1.0.1 + ssh2: 1.16.0 + transitivePeerDependencies: + - supports-color + + docker-modem@5.0.3: + dependencies: + debug: 4.3.7 readable-stream: 3.6.2 split-ca: 1.0.1 - ssh2: 1.15.0 + ssh2: 1.16.0 transitivePeerDependencies: - supports-color @@ -16463,6 +14418,14 @@ snapshots: transitivePeerDependencies: - supports-color + dockerode@4.0.2: + dependencies: + '@balena/dockerignore': 1.0.2 + docker-modem: 5.0.3 + tar-fs: 2.0.1 + transitivePeerDependencies: + - supports-color + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -16496,54 +14459,54 @@ snapshots: drizzle-kit@0.19.13: dependencies: '@drizzle-team/studio': 0.0.5 - '@esbuild-kit/esm-loader': 2.5.5 + '@esbuild-kit/esm-loader': 2.6.5 camelcase: 7.0.1 chalk: 5.3.0 commander: 9.5.0 esbuild: 0.18.20 - esbuild-register: 3.5.0(esbuild@0.18.20) + esbuild-register: 3.6.0(esbuild@0.18.20) glob: 8.1.0 hanji: 0.0.5 json-diff: 0.9.0 minimatch: 7.4.6 - zod: 3.23.7 + zod: 3.23.8 transitivePeerDependencies: - supports-color drizzle-kit@0.25.0-b1faa33: dependencies: '@drizzle-team/brocli': 0.10.2 - '@esbuild-kit/esm-loader': 2.5.5 + '@esbuild-kit/esm-loader': 2.6.5 esbuild: 0.19.12 - esbuild-register: 3.5.0(esbuild@0.19.12) + esbuild-register: 3.6.0(esbuild@0.19.12) transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.687.0)(@cloudflare/workers-types@4.20241106.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.5)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.10)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.1.34)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.3.3)(pg@8.13.1)(postgres@3.4.5)(sql.js@1.12.0)(sqlite3@5.1.7): optionalDependencies: - '@aws-sdk/client-rds-data': 3.583.0 - '@cloudflare/workers-types': 4.20241004.0 + '@aws-sdk/client-rds-data': 3.687.0 + '@cloudflare/workers-types': 4.20241106.0 '@libsql/client': 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - '@neondatabase/serverless': 0.9.3 - '@opentelemetry/api': 1.8.0 - '@planetscale/database': 1.18.0 - '@types/better-sqlite3': 7.6.10 - '@types/pg': 8.11.6 + '@neondatabase/serverless': 0.9.5 + '@opentelemetry/api': 1.9.0 + '@planetscale/database': 1.19.0 + '@types/better-sqlite3': 7.6.11 + '@types/pg': 8.11.10 '@types/sql.js': 1.4.9 '@vercel/postgres': 0.8.0 - better-sqlite3: 9.6.0 - bun-types: 1.0.3 - knex: 2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7) + better-sqlite3: 11.5.0 + bun-types: 1.1.34 + knex: 2.5.1(better-sqlite3@11.5.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7) kysely: 0.25.0 - mysql2: 3.11.0 - pg: 8.11.5 - postgres: 3.4.4 - sql.js: 1.10.3 + mysql2: 3.3.3 + pg: 8.13.1 + postgres: 3.4.5 + sql.js: 1.12.0 sqlite3: 5.1.7 - drizzle-prisma-generator@0.1.4: + drizzle-prisma-generator@0.1.7: dependencies: - '@prisma/generator-helper': 5.16.1 + '@prisma/generator-helper': 5.22.0 duplexer@0.1.2: {} @@ -16551,7 +14514,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.4.783: {} + electron-to-chromium@1.5.55: {} emittery@1.0.3: {} @@ -16563,6 +14526,8 @@ snapshots: encodeurl@1.0.2: {} + encodeurl@2.0.0: {} + encoding@0.1.13: dependencies: iconv-lite: 0.6.3 @@ -16579,7 +14544,7 @@ snapshots: env-paths@3.0.0: {} - envinfo@7.13.0: {} + environment@1.1.0: {} eol@0.9.1: {} @@ -16594,53 +14559,6 @@ snapshots: dependencies: stackframe: 1.3.4 - errorhandler@1.5.1: - dependencies: - accepts: 1.3.8 - escape-html: 1.0.3 - - es-abstract@1.22.1: - dependencies: - array-buffer-byte-length: 1.0.0 - arraybuffer.prototype.slice: 1.0.1 - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - es-set-tostringtag: 2.0.1 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.5 - get-intrinsic: 1.2.1 - get-symbol-description: 1.0.0 - globalthis: 1.0.3 - gopd: 1.0.1 - has: 1.0.3 - has-property-descriptors: 1.0.0 - has-proto: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.5 - is-array-buffer: 3.0.2 - is-callable: 1.2.7 - is-negative-zero: 2.0.2 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - is-string: 1.0.7 - is-typed-array: 1.1.12 - is-weakref: 1.0.2 - object-inspect: 1.12.3 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.5.0 - safe-array-concat: 1.0.0 - safe-regex-test: 1.0.0 - string.prototype.trim: 1.2.7 - string.prototype.trimend: 1.0.6 - string.prototype.trimstart: 1.0.6 - typed-array-buffer: 1.0.0 - typed-array-byte-length: 1.0.0 - typed-array-byte-offset: 1.0.0 - typed-array-length: 1.0.4 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.11 - es-abstract@1.23.3: dependencies: array-buffer-byte-length: 1.0.1 @@ -16674,10 +14592,10 @@ snapshots: is-string: 1.0.7 is-typed-array: 1.1.13 is-weakref: 1.0.2 - object-inspect: 1.13.1 + object-inspect: 1.13.2 object-keys: 1.1.1 object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 + regexp.prototype.flags: 1.5.3 safe-array-concat: 1.1.2 safe-regex-test: 1.0.3 string.prototype.trim: 1.2.9 @@ -16700,21 +14618,15 @@ snapshots: dependencies: es-errors: 1.3.0 - es-set-tostringtag@2.0.1: - dependencies: - get-intrinsic: 1.2.1 - has: 1.0.3 - has-tostringtag: 1.0.0 - es-set-tostringtag@2.0.3: dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 hasown: 2.0.2 - es-shim-unscopables@1.0.0: + es-shim-unscopables@1.0.2: dependencies: - has: 1.0.3 + hasown: 2.0.2 es-to-primitive@1.2.1: dependencies: @@ -16722,29 +14634,30 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 - es5-ext@0.10.62: + es5-ext@0.10.64: dependencies: es6-iterator: 2.0.3 - es6-symbol: 3.1.3 + es6-symbol: 3.1.4 + esniff: 2.0.1 next-tick: 1.1.0 es6-iterator@2.0.3: dependencies: - d: 1.0.1 - es5-ext: 0.10.62 - es6-symbol: 3.1.3 + d: 1.0.2 + es5-ext: 0.10.64 + es6-symbol: 3.1.4 - es6-symbol@3.1.3: + es6-symbol@3.1.4: dependencies: - d: 1.0.1 + d: 1.0.2 ext: 1.7.0 es6-weak-map@2.0.3: dependencies: - d: 1.0.1 - es5-ext: 0.10.62 + d: 1.0.2 + es5-ext: 0.10.64 es6-iterator: 2.0.3 - es6-symbol: 3.1.3 + es6-symbol: 3.1.4 esbuild-android-64@0.14.54: optional: true @@ -16791,25 +14704,25 @@ snapshots: esbuild-netbsd-64@0.14.54: optional: true - esbuild-node-externals@1.14.0(esbuild@0.19.12): + esbuild-node-externals@1.15.0(esbuild@0.19.12): dependencies: esbuild: 0.19.12 find-up: 5.0.0 - tslib: 2.6.2 + tslib: 2.8.1 esbuild-openbsd-64@0.14.54: optional: true - esbuild-register@3.5.0(esbuild@0.18.20): + esbuild-register@3.6.0(esbuild@0.18.20): dependencies: - debug: 4.3.4 + debug: 4.3.7 esbuild: 0.18.20 transitivePeerDependencies: - supports-color - esbuild-register@3.5.0(esbuild@0.19.12): + esbuild-register@3.6.0(esbuild@0.19.12): dependencies: - debug: 4.3.4 + debug: 4.3.7 esbuild: 0.19.12 transitivePeerDependencies: - supports-color @@ -16926,32 +14839,6 @@ snapshots: '@esbuild/win32-ia32': 0.19.12 '@esbuild/win32-x64': 0.19.12 - esbuild@0.20.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.20.2 - '@esbuild/android-arm': 0.20.2 - '@esbuild/android-arm64': 0.20.2 - '@esbuild/android-x64': 0.20.2 - '@esbuild/darwin-arm64': 0.20.2 - '@esbuild/darwin-x64': 0.20.2 - '@esbuild/freebsd-arm64': 0.20.2 - '@esbuild/freebsd-x64': 0.20.2 - '@esbuild/linux-arm': 0.20.2 - '@esbuild/linux-arm64': 0.20.2 - '@esbuild/linux-ia32': 0.20.2 - '@esbuild/linux-loong64': 0.20.2 - '@esbuild/linux-mips64el': 0.20.2 - '@esbuild/linux-ppc64': 0.20.2 - '@esbuild/linux-riscv64': 0.20.2 - '@esbuild/linux-s390x': 0.20.2 - '@esbuild/linux-x64': 0.20.2 - '@esbuild/netbsd-x64': 0.20.2 - '@esbuild/openbsd-x64': 0.20.2 - '@esbuild/sunos-x64': 0.20.2 - '@esbuild/win32-arm64': 0.20.2 - '@esbuild/win32-ia32': 0.20.2 - '@esbuild/win32-x64': 0.20.2 - esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -16978,36 +14865,61 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - esbuild@0.23.0: + esbuild@0.23.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 + + esbuild@0.24.0: optionalDependencies: - '@esbuild/aix-ppc64': 0.23.0 - '@esbuild/android-arm': 0.23.0 - '@esbuild/android-arm64': 0.23.0 - '@esbuild/android-x64': 0.23.0 - '@esbuild/darwin-arm64': 0.23.0 - '@esbuild/darwin-x64': 0.23.0 - '@esbuild/freebsd-arm64': 0.23.0 - '@esbuild/freebsd-x64': 0.23.0 - '@esbuild/linux-arm': 0.23.0 - '@esbuild/linux-arm64': 0.23.0 - '@esbuild/linux-ia32': 0.23.0 - '@esbuild/linux-loong64': 0.23.0 - '@esbuild/linux-mips64el': 0.23.0 - '@esbuild/linux-ppc64': 0.23.0 - '@esbuild/linux-riscv64': 0.23.0 - '@esbuild/linux-s390x': 0.23.0 - '@esbuild/linux-x64': 0.23.0 - '@esbuild/netbsd-x64': 0.23.0 - '@esbuild/openbsd-arm64': 0.23.0 - '@esbuild/openbsd-x64': 0.23.0 - '@esbuild/sunos-x64': 0.23.0 - '@esbuild/win32-arm64': 0.23.0 - '@esbuild/win32-ia32': 0.23.0 - '@esbuild/win32-x64': 0.23.0 - - escalade@3.1.1: {} - - escalade@3.1.2: {} + '@esbuild/aix-ppc64': 0.24.0 + '@esbuild/android-arm': 0.24.0 + '@esbuild/android-arm64': 0.24.0 + '@esbuild/android-x64': 0.24.0 + '@esbuild/darwin-arm64': 0.24.0 + '@esbuild/darwin-x64': 0.24.0 + '@esbuild/freebsd-arm64': 0.24.0 + '@esbuild/freebsd-x64': 0.24.0 + '@esbuild/linux-arm': 0.24.0 + '@esbuild/linux-arm64': 0.24.0 + '@esbuild/linux-ia32': 0.24.0 + '@esbuild/linux-loong64': 0.24.0 + '@esbuild/linux-mips64el': 0.24.0 + '@esbuild/linux-ppc64': 0.24.0 + '@esbuild/linux-riscv64': 0.24.0 + '@esbuild/linux-s390x': 0.24.0 + '@esbuild/linux-x64': 0.24.0 + '@esbuild/netbsd-x64': 0.24.0 + '@esbuild/openbsd-arm64': 0.24.0 + '@esbuild/openbsd-x64': 0.24.0 + '@esbuild/sunos-x64': 0.24.0 + '@esbuild/win32-arm64': 0.24.0 + '@esbuild/win32-ia32': 0.24.0 + '@esbuild/win32-x64': 0.24.0 + + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -17019,50 +14931,52 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-prettier@9.1.0(eslint@8.57.0): + eslint-config-prettier@9.1.0(eslint@8.57.1): dependencies: - eslint: 8.57.0 + eslint: 8.57.1 eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 - is-core-module: 2.13.0 - resolve: 1.22.4 + is-core-module: 2.15.1 + resolve: 1.22.8 transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) - eslint: 8.50.0 + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.3) + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1): dependencies: - array-includes: 3.1.6 - array.prototype.findlastindex: 1.2.2 - array.prototype.flat: 1.3.1 - array.prototype.flatmap: 1.3.1 + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.50.0 + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) - has: 1.0.3 - is-core-module: 2.13.0 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) + hasown: 2.0.2 + is-core-module: 2.15.1 is-glob: 4.0.3 minimatch: 3.1.2 - object.fromentries: 2.0.6 - object.groupby: 1.0.0 - object.values: 1.1.6 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 semver: 6.3.1 - tsconfig-paths: 3.14.2 + string.prototype.trimend: 1.0.8 + tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -17070,23 +14984,23 @@ snapshots: eslint-plugin-no-instanceof@1.0.1: {} - eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8): + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8): dependencies: - eslint: 8.57.0 + eslint: 8.57.1 prettier: 2.8.8 prettier-linter-helpers: 1.0.0 - synckit: 0.9.1 + synckit: 0.9.2 optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@8.57.0) + eslint-config-prettier: 9.1.0(eslint@8.57.1) - eslint-plugin-unicorn@48.0.1(eslint@8.50.0): + eslint-plugin-unicorn@48.0.1(eslint@8.57.1): dependencies: - '@babel/helper-validator-identifier': 7.22.5 - '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) - ci-info: 3.8.0 + '@babel/helper-validator-identifier': 7.25.9 + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + ci-info: 3.9.0 clean-regexp: 1.0.0 - eslint: 8.50.0 - esquery: 1.5.0 + eslint: 8.57.1 + esquery: 1.6.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 jsesc: 3.0.2 @@ -17095,15 +15009,15 @@ snapshots: read-pkg-up: 7.0.1 regexp-tree: 0.1.27 regjsparser: 0.10.0 - semver: 7.6.2 + semver: 7.6.3 strip-indent: 3.0.0 - eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0): + eslint-plugin-unused-imports@3.2.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1): dependencies: - eslint: 8.50.0 + eslint: 8.57.1 eslint-rule-composer: 0.3.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) eslint-rule-composer@0.3.0: {} @@ -17119,121 +15033,34 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint-visitor-keys@4.0.0: {} - - eslint@8.50.0: - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) - '@eslint-community/regexpp': 4.9.0 - '@eslint/eslintrc': 2.1.2 - '@eslint/js': 8.50.0 - '@humanwhocodes/config-array': 0.11.11 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.5.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.22.0 - graphemer: 1.4.0 - ignore: 5.2.4 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.3 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - eslint@8.53.0: - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) - '@eslint-community/regexpp': 4.9.0 - '@eslint/eslintrc': 2.1.3 - '@eslint/js': 8.53.0 - '@humanwhocodes/config-array': 0.11.13 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.5.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.22.0 - graphemer: 1.4.0 - ignore: 5.2.4 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.3 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - eslint@8.57.0: + eslint@8.57.1: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.9.0 + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.1 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 + cross-spawn: 7.0.5 + debug: 4.3.7 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.22.0 + globals: 13.24.0 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -17243,7 +15070,7 @@ snapshots: lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: @@ -17251,21 +15078,22 @@ snapshots: esm@3.2.25: {} - espree@10.0.1: + esniff@2.0.1: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) - eslint-visitor-keys: 4.0.0 + d: 1.0.2 + es5-ext: 0.10.64 + event-emitter: 0.3.5 + type: 2.7.3 espree@9.6.1: dependencies: - acorn: 8.10.0 - acorn-jsx: 5.3.2(acorn@8.10.0) + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} - esquery@1.5.0: + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -17283,7 +15111,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 esutils@2.0.3: {} @@ -17291,8 +15119,8 @@ snapshots: event-emitter@0.3.5: dependencies: - d: 1.0.1 - es5-ext: 0.10.62 + d: 1.0.2 + es5-ext: 0.10.64 event-stream@3.3.4: dependencies: @@ -17320,7 +15148,7 @@ snapshots: execa@5.1.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -17332,7 +15160,7 @@ snapshots: execa@6.1.0: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 get-stream: 6.0.1 human-signals: 3.0.1 is-stream: 3.0.0 @@ -17344,7 +15172,7 @@ snapshots: execa@8.0.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 get-stream: 8.0.1 human-signals: 5.0.0 is-stream: 3.0.0 @@ -17360,68 +15188,72 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expect-type@1.1.0: {} + + expo-asset@10.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo-constants: 16.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-constants@16.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + '@expo/config': 9.0.4 + '@expo/env': 0.3.0 + expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-file-system@17.0.1(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-font@12.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-keep-awake@13.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-modules-autolinking@1.11.1: + expo-modules-autolinking@1.11.3: dependencies: chalk: 4.1.2 commander: 7.2.0 fast-glob: 3.3.2 find-up: 5.0.0 fs-extra: 9.1.0 + require-from-string: 2.0.2 + resolve-from: 5.0.0 - expo-modules-core@1.12.11: + expo-modules-core@1.12.26: dependencies: invariant: 2.2.4 - expo-sqlite@14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-sqlite@14.0.6(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): - dependencies: - '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) - '@expo/config': 9.0.2 - '@expo/config-plugins': 8.0.4 - '@expo/metro-config': 0.18.4 - '@expo/vector-icons': 14.0.2 - babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-modules-autolinking: 1.11.1 - expo-modules-core: 1.12.11 + expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + + expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + dependencies: + '@babel/runtime': 7.26.0 + '@expo/cli': 0.18.30(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.3)(utf-8-validate@6.0.3) + '@expo/config': 9.0.4 + '@expo/config-plugins': 8.0.10 + '@expo/metro-config': 0.18.11 + '@expo/vector-icons': 14.0.4 + babel-preset-expo: 11.0.15(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + expo-asset: 10.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-file-system: 17.0.1(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-font: 12.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-keep-awake: 13.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-modules-autolinking: 1.11.3 + expo-modules-core: 1.12.26 fbemitter: 3.0.0(encoding@0.1.13) whatwg-url-without-unicode: 8.0.0-3 transitivePeerDependencies: @@ -17432,34 +15264,36 @@ snapshots: - supports-color - utf-8-validate - express@4.19.2: + exponential-backoff@3.1.1: {} + + express@4.21.1: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.2 + body-parser: 1.20.3 content-disposition: 0.5.4 content-type: 1.0.5 - cookie: 0.6.0 + cookie: 0.7.1 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.2.0 + finalhandler: 1.3.1 fresh: 0.5.2 http-errors: 2.0.0 - merge-descriptors: 1.0.1 + merge-descriptors: 1.0.3 methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.7 + path-to-regexp: 0.1.10 proxy-addr: 2.0.7 - qs: 6.11.0 + qs: 6.13.0 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 + send: 0.19.0 + serve-static: 1.16.2 setprototypeof: 1.2.0 statuses: 2.0.1 type-is: 1.6.18 @@ -17470,41 +15304,29 @@ snapshots: ext@1.7.0: dependencies: - type: 2.7.2 + type: 2.7.3 fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} - fast-glob@3.3.1: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.7 - fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.7 + micromatch: 4.0.8 fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} - fast-xml-parser@4.2.5: - dependencies: - strnum: 1.0.5 - - fast-xml-parser@4.4.0: + fast-xml-parser@4.4.1: dependencies: strnum: 1.0.5 - fastq@1.15.0: + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -17528,14 +15350,18 @@ snapshots: object-assign: 4.1.1 promise: 7.3.1 setimmediate: 1.0.5 - ua-parser-js: 1.0.38 + ua-parser-js: 1.0.39 transitivePeerDependencies: - encoding + fdir@6.4.2(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + fetch-blob@3.2.0: dependencies: node-domexception: 1.0.0 - web-streams-polyfill: 3.2.1 + web-streams-polyfill: 3.3.3 fetch-retry@4.1.1: {} @@ -17548,7 +15374,7 @@ snapshots: file-entry-cache@6.0.1: dependencies: - flat-cache: 3.1.0 + flat-cache: 3.2.0 file-uri-to-path@1.0.0: {} @@ -17568,10 +15394,10 @@ snapshots: transitivePeerDependencies: - supports-color - finalhandler@1.2.0: + finalhandler@1.3.1: dependencies: debug: 2.6.9 - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 @@ -17609,21 +15435,19 @@ snapshots: dependencies: micromatch: 4.0.8 - flat-cache@3.1.0: + flat-cache@3.2.0: dependencies: - flatted: 3.2.9 - keyv: 4.5.3 + flatted: 3.3.1 + keyv: 4.5.4 rimraf: 3.0.2 - flatted@3.2.9: {} - flatted@3.3.1: {} flow-enums-runtime@0.0.6: {} - flow-parser@0.236.0: {} + flow-parser@0.252.0: {} - follow-redirects@1.15.6: {} + follow-redirects@1.15.9: {} fontfaceobserver@2.3.0: {} @@ -17631,18 +15455,18 @@ snapshots: dependencies: is-callable: 1.2.7 - foreground-child@3.1.1: + foreground-child@3.3.0: dependencies: - cross-spawn: 7.0.3 - signal-exit: 4.0.2 + cross-spawn: 7.0.5 + signal-exit: 4.1.0 - form-data@3.0.1: + form-data@3.0.2: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - form-data@4.0.0: + form-data@4.0.1: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 @@ -17662,7 +15486,7 @@ snapshots: fs-constants@1.0.0: {} - fs-extra@11.1.1: + fs-extra@11.2.0: dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 @@ -17701,17 +15525,8 @@ snapshots: fsevents@2.3.3: optional: true - function-bind@1.1.1: {} - function-bind@1.1.2: {} - function.prototype.name@1.1.5: - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - functions-have-names: 1.2.3 - function.prototype.name@1.1.6: dependencies: call-bind: 1.0.7 @@ -17721,7 +15536,7 @@ snapshots: functions-have-names@1.2.3: {} - fx@28.0.0: {} + fx@35.0.0: {} gauge@4.0.4: dependencies: @@ -17745,13 +15560,6 @@ snapshots: get-func-name@2.0.2: {} - get-intrinsic@1.2.1: - dependencies: - function-bind: 1.1.1 - has: 1.0.3 - has-proto: 1.0.1 - has-symbols: 1.0.3 - get-intrinsic@1.2.4: dependencies: es-errors: 1.3.0 @@ -17775,24 +15583,19 @@ snapshots: get-stream@4.1.0: dependencies: - pump: 3.0.0 + pump: 3.0.2 get-stream@6.0.1: {} get-stream@8.0.1: {} - get-symbol-description@1.0.0: - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - get-symbol-description@1.0.2: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 - get-tsconfig@4.7.5: + get-tsconfig@4.8.1: dependencies: resolve-pkg-maps: 1.0.0 @@ -17812,31 +15615,15 @@ snapshots: glob-to-regexp@0.4.1: {} - glob@10.3.10: - dependencies: - foreground-child: 3.1.1 - jackspeak: 2.3.6 - minimatch: 9.0.4 - minipass: 5.0.0 - path-scurry: 1.10.1 - - glob@10.4.1: + glob@10.4.5: dependencies: - foreground-child: 3.1.1 - jackspeak: 3.1.2 - minimatch: 9.0.4 + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 minipass: 7.1.2 + package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@6.0.4: - dependencies: - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - optional: true - glob@7.1.6: dependencies: fs.realpath: 1.0.0 @@ -17865,16 +15652,10 @@ snapshots: globals@11.12.0: {} - globals@13.22.0: + globals@13.24.0: dependencies: type-fest: 0.20.2 - globals@14.0.0: {} - - globalthis@1.0.3: - dependencies: - define-properties: 1.2.0 - globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -17884,8 +15665,8 @@ snapshots: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.1 - ignore: 5.3.1 + fast-glob: 3.3.2 + ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 @@ -17893,15 +15674,24 @@ snapshots: dependencies: dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.1 + ignore: 5.3.2 merge2: 1.4.1 slash: 4.0.0 + globby@14.0.2: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.2 + ignore: 5.3.2 + path-type: 5.0.0 + slash: 5.1.0 + unicorn-magic: 0.1.0 + globrex@0.1.2: {} gopd@1.0.1: dependencies: - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.4 graceful-fs@4.2.11: {} @@ -17910,7 +15700,7 @@ snapshots: graphql-tag@2.12.6(graphql@15.8.0): dependencies: graphql: 15.8.0 - tslib: 2.6.2 + tslib: 2.8.1 graphql@15.8.0: {} @@ -17925,24 +15715,14 @@ snapshots: has-flag@4.0.0: {} - has-property-descriptors@1.0.0: - dependencies: - get-intrinsic: 1.2.1 - has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.0 - has-proto@1.0.1: {} - has-proto@1.0.3: {} has-symbols@1.0.3: {} - has-tostringtag@1.0.0: - dependencies: - has-symbols: 1.0.3 - has-tostringtag@1.0.2: dependencies: has-symbols: 1.0.3 @@ -17950,10 +15730,6 @@ snapshots: has-unicode@2.0.1: optional: true - has@1.0.3: - dependencies: - function-bind: 1.1.1 - hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -17962,23 +15738,25 @@ snapshots: hermes-estree@0.19.1: {} - hermes-estree@0.20.1: {} + hermes-estree@0.23.1: {} + + hermes-estree@0.24.0: {} hermes-parser@0.19.1: dependencies: hermes-estree: 0.19.1 - hermes-parser@0.20.1: + hermes-parser@0.23.1: dependencies: - hermes-estree: 0.20.1 + hermes-estree: 0.23.1 - hermes-profile-transformer@0.0.6: + hermes-parser@0.24.0: dependencies: - source-map: 0.7.4 + hermes-estree: 0.24.0 - hono@4.0.1: {} + highlight.js@10.7.3: {} - hono@4.5.0: {} + hono@4.6.9: {} hosted-git-info@2.8.9: {} @@ -18001,7 +15779,7 @@ snapshots: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color optional: true @@ -18009,7 +15787,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -18036,9 +15814,7 @@ snapshots: ignore-by-default@2.1.0: {} - ignore@5.2.4: {} - - ignore@5.3.1: {} + ignore@5.3.2: {} image-size@1.1.1: dependencies: @@ -18079,12 +15855,6 @@ snapshots: default-gateway: 4.2.0 ipaddr.js: 1.9.1 - internal-slot@1.0.5: - dependencies: - get-intrinsic: 1.2.1 - has: 1.0.3 - side-channel: 1.0.4 - internal-slot@1.0.7: dependencies: es-errors: 1.3.0 @@ -18109,12 +15879,6 @@ snapshots: irregular-plurals@3.5.0: {} - is-array-buffer@3.0.2: - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - is-typed-array: 1.1.12 - is-array-buffer@3.0.4: dependencies: call-bind: 1.0.7 @@ -18128,12 +15892,12 @@ snapshots: is-binary-path@2.1.0: dependencies: - binary-extensions: 2.2.0 + binary-extensions: 2.3.0 is-boolean-object@1.1.2: dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 + call-bind: 1.0.7 + has-tostringtag: 1.0.2 is-buffer@1.1.6: {} @@ -18143,19 +15907,7 @@ snapshots: is-callable@1.2.7: {} - is-core-module@2.11.0: - dependencies: - has: 1.0.3 - - is-core-module@2.12.1: - dependencies: - has: 1.0.3 - - is-core-module@2.13.0: - dependencies: - has: 1.0.3 - - is-core-module@2.13.1: + is-core-module@2.15.1: dependencies: hasown: 2.0.2 @@ -18165,7 +15917,7 @@ snapshots: is-date-object@1.0.5: dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 is-directory@0.3.1: {} @@ -18177,8 +15929,6 @@ snapshots: is-extglob@2.1.1: {} - is-fullwidth-code-point@2.0.0: {} - is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@4.0.0: {} @@ -18191,8 +15941,6 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-interactive@1.0.0: {} - is-invalid-path@0.1.0: dependencies: is-glob: 2.0.1 @@ -18200,13 +15948,11 @@ snapshots: is-lambda@1.0.1: optional: true - is-negative-zero@2.0.2: {} - is-negative-zero@2.0.3: {} is-number-object@1.0.7: dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 is-number@7.0.0: {} @@ -18228,12 +15974,8 @@ snapshots: is-regex@1.1.4: dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - - is-shared-array-buffer@1.0.2: - dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 + has-tostringtag: 1.0.2 is-shared-array-buffer@1.0.3: dependencies: @@ -18247,22 +15989,16 @@ snapshots: is-string@1.0.7: dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 is-symbol@1.0.4: dependencies: has-symbols: 1.0.3 - is-typed-array@1.1.12: - dependencies: - which-typed-array: 1.1.11 - is-typed-array@1.1.13: dependencies: which-typed-array: 1.1.15 - is-unicode-supported@0.1.0: {} - is-unicode-supported@1.3.0: {} is-valid-path@0.1.1: @@ -18271,12 +16007,10 @@ snapshots: is-weakref@1.0.2: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 is-what@4.1.16: {} - is-wsl@1.1.0: {} - is-wsl@2.2.0: dependencies: is-docker: 2.2.1 @@ -18289,13 +16023,21 @@ snapshots: isobject@3.0.1: {} - jackspeak@2.3.6: + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1: dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 + '@babel/core': 7.26.0 + '@babel/parser': 7.26.2 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - jackspeak@3.1.2: + itty-time@1.0.6: {} + + jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: @@ -18308,15 +16050,31 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.17.6 jest-mock: 29.7.0 jest-util: 29.7.0 jest-get-type@29.6.3: {} + jest-haste-map@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 20.17.6 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + jest-message-util@29.7.0: dependencies: - '@babel/code-frame': 7.24.6 + '@babel/code-frame': 7.26.2 '@jest/types': 29.6.3 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -18329,13 +16087,15 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.17.6 jest-util: 29.7.0 + jest-regex-util@29.6.3: {} + jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.17.6 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -18352,24 +16112,16 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 20.12.12 + '@types/node': 20.17.6 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 jimp-compact@0.16.1: {} - joi@17.13.1: - dependencies: - '@hapi/hoek': 9.3.0 - '@hapi/topo': 5.1.0 - '@sideway/address': 4.1.5 - '@sideway/formula': 3.0.1 - '@sideway/pinpoint': 2.0.0 - join-component@1.1.0: {} - jose@4.15.5: {} + jose@4.15.9: {} jose@5.2.3: {} @@ -18399,21 +16151,21 @@ snapshots: jsc-safe-url@0.2.4: {} - jscodeshift@0.14.0(@babel/preset-env@7.24.6(@babel/core@7.24.6)): - dependencies: - '@babel/core': 7.24.6 - '@babel/parser': 7.24.6 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.6) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.6) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.6) - '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) - '@babel/preset-env': 7.24.6(@babel/core@7.24.6) - '@babel/preset-flow': 7.24.6(@babel/core@7.24.6) - '@babel/preset-typescript': 7.24.6(@babel/core@7.24.6) - '@babel/register': 7.24.6(@babel/core@7.24.6) - babel-core: 7.0.0-bridge.0(@babel/core@7.24.6) + jscodeshift@0.14.0(@babel/preset-env@7.26.0(@babel/core@7.26.0)): + dependencies: + '@babel/core': 7.26.0 + '@babel/parser': 7.26.2 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) + '@babel/preset-env': 7.26.0(@babel/core@7.26.0) + '@babel/preset-flow': 7.25.9(@babel/core@7.26.0) + '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) + '@babel/register': 7.25.9(@babel/core@7.26.0) + babel-core: 7.0.0-bridge.0(@babel/core@7.26.0) chalk: 4.1.2 - flow-parser: 0.236.0 + flow-parser: 0.252.0 graceful-fs: 4.2.11 micromatch: 4.0.8 neo-async: 2.6.2 @@ -18434,7 +16186,7 @@ snapshots: json-diff@0.9.0: dependencies: - cli-color: 2.0.3 + cli-color: 2.0.4 difflib: 0.2.4 dreamopt: 0.8.0 @@ -18456,7 +16208,7 @@ snapshots: lodash: 4.17.21 md5: 2.2.1 memory-cache: 0.2.0 - traverse: 0.6.9 + traverse: 0.6.10 valid-url: 1.0.9 json-schema-traverse@0.4.1: {} @@ -18475,7 +16227,7 @@ snapshots: jsonfile@6.1.0: dependencies: - universalify: 2.0.0 + universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 @@ -18488,7 +16240,7 @@ snapshots: junk@4.0.1: {} - keyv@4.5.3: + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -18498,12 +16250,12 @@ snapshots: kleur@4.1.5: {} - knex@2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7): + knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7): dependencies: colorette: 2.0.19 commander: 10.0.1 debug: 4.3.4 - escalade: 3.1.2 + escalade: 3.2.0 esm: 3.2.25 get-package-type: 0.1.0 getopts: 2.3.0 @@ -18515,19 +16267,20 @@ snapshots: tarn: 3.0.2 tildify: 2.0.0 optionalDependencies: - better-sqlite3: 8.7.0 + better-sqlite3: 11.5.0 mysql2: 3.3.3 - pg: 8.11.5 + pg: 8.13.1 sqlite3: 5.1.7 transitivePeerDependencies: - supports-color + optional: true - knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7): + knex@2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7): dependencies: colorette: 2.0.19 commander: 10.0.1 debug: 4.3.4 - escalade: 3.1.2 + escalade: 3.2.0 esm: 3.2.25 get-package-type: 0.1.0 getopts: 2.3.0 @@ -18539,13 +16292,12 @@ snapshots: tarn: 3.0.2 tildify: 2.0.0 optionalDependencies: - better-sqlite3: 9.6.0 - mysql2: 3.11.0 - pg: 8.11.5 + better-sqlite3: 8.7.0 + mysql2: 3.3.3 + pg: 8.13.1 sqlite3: 5.1.7 transitivePeerDependencies: - supports-color - optional: true kysely@0.25.0: {} @@ -18556,32 +16308,18 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - libsql@0.3.19: + libsql@0.4.7: dependencies: '@neon-rs/load': 0.0.4 detect-libc: 2.0.2 optionalDependencies: - '@libsql/darwin-arm64': 0.3.19 - '@libsql/darwin-x64': 0.3.19 - '@libsql/linux-arm64-gnu': 0.3.19 - '@libsql/linux-arm64-musl': 0.3.19 - '@libsql/linux-x64-gnu': 0.3.19 - '@libsql/linux-x64-musl': 0.3.19 - '@libsql/win32-x64-msvc': 0.3.19 - - libsql@0.4.1: - dependencies: - '@neon-rs/load': 0.0.4 - detect-libc: 2.0.2 - libsql: 0.3.19 - optionalDependencies: - '@libsql/darwin-arm64': 0.4.1 - '@libsql/darwin-x64': 0.4.1 - '@libsql/linux-arm64-gnu': 0.4.1 - '@libsql/linux-arm64-musl': 0.4.1 - '@libsql/linux-x64-gnu': 0.4.1 - '@libsql/linux-x64-musl': 0.4.1 - '@libsql/win32-x64-msvc': 0.4.1 + '@libsql/darwin-arm64': 0.4.7 + '@libsql/darwin-x64': 0.4.7 + '@libsql/linux-arm64-gnu': 0.4.7 + '@libsql/linux-arm64-musl': 0.4.7 + '@libsql/linux-x64-gnu': 0.4.7 + '@libsql/linux-x64-musl': 0.4.7 + '@libsql/win32-x64-msvc': 0.4.7 lighthouse-logger@1.4.2: dependencies: @@ -18593,54 +16331,27 @@ snapshots: lightningcss-darwin-arm64@1.19.0: optional: true - lightningcss-darwin-arm64@1.25.1: - optional: true - lightningcss-darwin-x64@1.19.0: optional: true - lightningcss-darwin-x64@1.25.1: - optional: true - - lightningcss-freebsd-x64@1.25.1: - optional: true - lightningcss-linux-arm-gnueabihf@1.19.0: optional: true - lightningcss-linux-arm-gnueabihf@1.25.1: - optional: true - lightningcss-linux-arm64-gnu@1.19.0: optional: true - lightningcss-linux-arm64-gnu@1.25.1: - optional: true - lightningcss-linux-arm64-musl@1.19.0: optional: true - lightningcss-linux-arm64-musl@1.25.1: - optional: true - lightningcss-linux-x64-gnu@1.19.0: optional: true - lightningcss-linux-x64-gnu@1.25.1: - optional: true - lightningcss-linux-x64-musl@1.19.0: optional: true - lightningcss-linux-x64-musl@1.25.1: - optional: true - lightningcss-win32-x64-msvc@1.19.0: optional: true - lightningcss-win32-x64-msvc@1.25.1: - optional: true - lightningcss@1.19.0: dependencies: detect-libc: 1.0.3 @@ -18654,23 +16365,6 @@ snapshots: lightningcss-linux-x64-musl: 1.19.0 lightningcss-win32-x64-msvc: 1.19.0 - lightningcss@1.25.1: - dependencies: - detect-libc: 1.0.3 - optionalDependencies: - lightningcss-darwin-arm64: 1.25.1 - lightningcss-darwin-x64: 1.25.1 - lightningcss-freebsd-x64: 1.25.1 - lightningcss-linux-arm-gnueabihf: 1.25.1 - lightningcss-linux-arm64-gnu: 1.25.1 - lightningcss-linux-arm64-musl: 1.25.1 - lightningcss-linux-x64-gnu: 1.25.1 - lightningcss-linux-x64-musl: 1.25.1 - lightningcss-win32-x64-msvc: 1.25.1 - optional: true - - lilconfig@2.1.0: {} - lilconfig@3.1.2: {} lines-and-columns@1.2.4: {} @@ -18681,8 +16375,8 @@ snapshots: local-pkg@0.5.0: dependencies: - mlly: 1.7.0 - pkg-types: 1.1.0 + mlly: 1.7.2 + pkg-types: 1.2.1 locate-path@3.0.0: dependencies: @@ -18715,17 +16409,6 @@ snapshots: dependencies: chalk: 2.4.2 - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - - logkitty@0.7.1: - dependencies: - ansi-fragments: 0.2.1 - dayjs: 1.11.11 - yargs: 15.4.1 - long@5.2.3: {} loose-envify@1.4.0: @@ -18738,7 +16421,7 @@ snapshots: loupe@3.1.2: {} - lru-cache@10.2.2: {} + lru-cache@10.4.3: {} lru-cache@5.1.1: dependencies: @@ -18752,21 +16435,15 @@ snapshots: lru-cache@8.0.5: {} - lru-cache@9.1.2: {} - lru-queue@0.1.0: dependencies: - es5-ext: 0.10.62 + es5-ext: 0.10.64 magic-string@0.25.9: dependencies: sourcemap-codec: 1.4.8 - magic-string@0.30.10: - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - - magic-string@0.30.11: + magic-string@0.30.12: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -18791,7 +16468,7 @@ snapshots: minipass-fetch: 1.4.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 - negotiator: 0.6.3 + negotiator: 0.6.4 promise-retry: 2.0.1 socks-proxy-agent: 6.2.1 ssri: 8.0.1 @@ -18812,13 +16489,24 @@ snapshots: marked-terminal@6.2.0(marked@9.1.6): dependencies: - ansi-escapes: 6.2.0 + ansi-escapes: 6.2.1 cardinal: 2.1.1 chalk: 5.3.0 - cli-table3: 0.6.3 + cli-table3: 0.6.5 + marked: 9.1.6 + node-emoji: 2.1.3 + supports-hyperlinks: 3.1.0 + + marked-terminal@7.2.1(marked@9.1.6): + dependencies: + ansi-escapes: 7.0.0 + ansi-regex: 6.1.0 + chalk: 5.3.0 + cli-highlight: 2.1.11 + cli-table3: 0.6.5 marked: 9.1.6 node-emoji: 2.1.3 - supports-hyperlinks: 3.0.0 + supports-hyperlinks: 3.1.0 marked@9.1.6: {} @@ -18859,22 +16547,22 @@ snapshots: memoize-one@5.2.1: {} - memoizee@0.4.15: + memoizee@0.4.17: dependencies: - d: 1.0.1 - es5-ext: 0.10.62 + d: 1.0.2 + es5-ext: 0.10.64 es6-weak-map: 2.0.3 event-emitter: 0.3.5 is-promise: 2.2.2 lru-queue: 0.1.0 next-tick: 1.1.0 - timers-ext: 0.1.7 + timers-ext: 0.1.8 memory-cache@0.2.0: {} meow@12.1.1: {} - merge-descriptors@1.0.1: {} + merge-descriptors@1.0.3: {} merge-stream@2.0.0: {} @@ -18882,46 +16570,52 @@ snapshots: methods@1.1.2: {} - metro-babel-transformer@0.80.9: + metro-babel-transformer@0.81.0: dependencies: - '@babel/core': 7.24.6 - hermes-parser: 0.20.1 + '@babel/core': 7.26.0 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.24.0 nullthrows: 1.1.1 transitivePeerDependencies: - supports-color - metro-cache-key@0.80.9: {} + metro-cache-key@0.81.0: + dependencies: + flow-enums-runtime: 0.0.6 - metro-cache@0.80.9: + metro-cache@0.81.0: dependencies: - metro-core: 0.80.9 - rimraf: 3.0.2 + exponential-backoff: 3.1.1 + flow-enums-runtime: 0.0.6 + metro-core: 0.81.0 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-config@0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 + flow-enums-runtime: 0.0.6 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-cache: 0.80.9 - metro-core: 0.80.9 - metro-runtime: 0.80.9 + metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + metro-cache: 0.81.0 + metro-core: 0.81.0 + metro-runtime: 0.81.0 transitivePeerDependencies: - bufferutil - - encoding - supports-color - utf-8-validate - metro-core@0.80.9: + metro-core@0.81.0: dependencies: + flow-enums-runtime: 0.0.6 lodash.throttle: 4.1.1 - metro-resolver: 0.80.9 + metro-resolver: 0.81.0 - metro-file-map@0.80.9: + metro-file-map@0.81.0: dependencies: anymatch: 3.1.3 debug: 2.6.9 fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 invariant: 2.2.4 jest-worker: 29.7.0 @@ -18934,33 +16628,40 @@ snapshots: transitivePeerDependencies: - supports-color - metro-minify-terser@0.80.9: + metro-minify-terser@0.81.0: dependencies: - terser: 5.31.0 + flow-enums-runtime: 0.0.6 + terser: 5.36.0 - metro-resolver@0.80.9: {} + metro-resolver@0.81.0: + dependencies: + flow-enums-runtime: 0.0.6 - metro-runtime@0.80.9: + metro-runtime@0.81.0: dependencies: - '@babel/runtime': 7.24.6 + '@babel/runtime': 7.26.0 + flow-enums-runtime: 0.0.6 - metro-source-map@0.80.9: + metro-source-map@0.81.0: dependencies: - '@babel/traverse': 7.24.6 - '@babel/types': 7.24.6 + '@babel/traverse': 7.25.9 + '@babel/traverse--for-generate-function-map': '@babel/traverse@7.25.9' + '@babel/types': 7.26.0 + flow-enums-runtime: 0.0.6 invariant: 2.2.4 - metro-symbolicate: 0.80.9 + metro-symbolicate: 0.81.0 nullthrows: 1.1.1 - ob1: 0.80.9 + ob1: 0.81.0 source-map: 0.5.7 vlq: 1.0.1 transitivePeerDependencies: - supports-color - metro-symbolicate@0.80.9: + metro-symbolicate@0.81.0: dependencies: + flow-enums-runtime: 0.0.6 invariant: 2.2.4 - metro-source-map: 0.80.9 + metro-source-map: 0.81.0 nullthrows: 1.1.1 source-map: 0.5.7 through2: 2.0.5 @@ -18968,45 +16669,46 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-plugins@0.80.9: + metro-transform-plugins@0.81.0: dependencies: - '@babel/core': 7.24.6 - '@babel/generator': 7.24.6 - '@babel/template': 7.24.6 - '@babel/traverse': 7.24.6 + '@babel/core': 7.26.0 + '@babel/generator': 7.26.2 + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + flow-enums-runtime: 0.0.6 nullthrows: 1.1.1 transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): - dependencies: - '@babel/core': 7.24.6 - '@babel/generator': 7.24.6 - '@babel/parser': 7.24.6 - '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-babel-transformer: 0.80.9 - metro-cache: 0.80.9 - metro-cache-key: 0.80.9 - metro-minify-terser: 0.80.9 - metro-source-map: 0.80.9 - metro-transform-plugins: 0.80.9 + metro-transform-worker@0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + dependencies: + '@babel/core': 7.26.0 + '@babel/generator': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + flow-enums-runtime: 0.0.6 + metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + metro-babel-transformer: 0.81.0 + metro-cache: 0.81.0 + metro-cache-key: 0.81.0 + metro-minify-terser: 0.81.0 + metro-source-map: 0.81.0 + metro-transform-plugins: 0.81.0 nullthrows: 1.1.1 transitivePeerDependencies: - bufferutil - - encoding - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro@0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: - '@babel/code-frame': 7.24.6 - '@babel/core': 7.24.6 - '@babel/generator': 7.24.6 - '@babel/parser': 7.24.6 - '@babel/template': 7.24.6 - '@babel/traverse': 7.24.6 - '@babel/types': 7.24.6 + '@babel/code-frame': 7.26.2 + '@babel/core': 7.26.0 + '@babel/generator': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 accepts: 1.3.8 chalk: 4.1.2 ci-info: 2.0.0 @@ -19014,46 +16716,39 @@ snapshots: debug: 2.6.9 denodeify: 1.2.1 error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 - hermes-parser: 0.20.1 + hermes-parser: 0.24.0 image-size: 1.1.1 invariant: 2.2.4 jest-worker: 29.7.0 jsc-safe-url: 0.2.4 lodash.throttle: 4.1.1 - metro-babel-transformer: 0.80.9 - metro-cache: 0.80.9 - metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-core: 0.80.9 - metro-file-map: 0.80.9 - metro-resolver: 0.80.9 - metro-runtime: 0.80.9 - metro-source-map: 0.80.9 - metro-symbolicate: 0.80.9 - metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-babel-transformer: 0.81.0 + metro-cache: 0.81.0 + metro-cache-key: 0.81.0 + metro-config: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + metro-core: 0.81.0 + metro-file-map: 0.81.0 + metro-resolver: 0.81.0 + metro-runtime: 0.81.0 + metro-source-map: 0.81.0 + metro-symbolicate: 0.81.0 + metro-transform-plugins: 0.81.0 + metro-transform-worker: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) mime-types: 2.1.35 - node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 - rimraf: 3.0.2 serialize-error: 2.1.0 source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 transitivePeerDependencies: - bufferutil - - encoding - supports-color - utf-8-validate - micromatch@4.0.7: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -19067,8 +16762,6 @@ snapshots: mime@1.6.0: {} - mime@2.6.0: {} - mime@3.0.0: {} mimic-fn@1.2.0: {} @@ -19081,20 +16774,20 @@ snapshots: min-indent@1.0.1: {} - miniflare@3.20240712.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + miniflare@3.20241022.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: '@cspotcode/source-map-support': 0.8.1 - acorn: 8.11.3 - acorn-walk: 8.3.2 + acorn: 8.14.0 + acorn-walk: 8.3.4 capnp-ts: 0.7.0 exit-hook: 2.2.1 glob-to-regexp: 0.4.1 stoppable: 1.1.0 undici: 5.28.4 - workerd: 1.20240712.0 + workerd: 1.20241022.0 ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - youch: 3.3.3 - zod: 3.23.7 + youch: 3.3.4 + zod: 3.23.8 transitivePeerDependencies: - bufferutil - supports-color @@ -19112,7 +16805,11 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimatch@9.0.4: + minimatch@9.0.3: + dependencies: + brace-expansion: 2.0.1 + + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -19170,12 +16867,12 @@ snapshots: mkdirp@1.0.4: {} - mlly@1.7.0: + mlly@1.7.2: dependencies: - acorn: 8.11.3 + acorn: 8.14.0 pathe: 1.1.2 - pkg-types: 1.1.0 - ufo: 1.5.3 + pkg-types: 1.2.1 + ufo: 1.5.4 mri@1.2.0: {} @@ -19189,26 +16886,6 @@ snapshots: mustache@4.2.0: {} - mv@2.1.1: - dependencies: - mkdirp: 0.5.6 - ncp: 2.0.0 - rimraf: 2.4.5 - optional: true - - mysql2@3.11.0: - dependencies: - aws-ssl-profiles: 1.1.1 - denque: 2.1.0 - generate-function: 2.3.1 - iconv-lite: 0.6.3 - long: 5.2.3 - lru-cache: 8.0.5 - named-placeholders: 1.1.3 - seq-queue: 0.0.5 - sqlstring: 2.3.3 - optional: true - mysql2@3.3.3: dependencies: denque: 2.1.0 @@ -19230,7 +16907,7 @@ snapshots: dependencies: lru-cache: 7.18.3 - nan@2.19.0: + nan@2.22.0: optional: true nanoid@3.3.7: {} @@ -19239,11 +16916,11 @@ snapshots: natural-compare@1.4.0: {} - ncp@2.0.0: - optional: true - negotiator@0.6.3: {} + negotiator@0.6.4: + optional: true + neo-async@2.6.2: {} nested-error-stacks@2.0.1: {} @@ -19254,15 +16931,13 @@ snapshots: nice-try@1.0.5: {} - nocache@3.0.4: {} - - node-abi@3.62.0: + node-abi@3.71.0: dependencies: - semver: 7.6.2 + semver: 7.6.3 node-abort-controller@3.1.1: {} - node-addon-api@7.1.0: {} + node-addon-api@7.1.1: {} node-dir@0.1.17: dependencies: @@ -19277,8 +16952,6 @@ snapshots: emojilib: 2.4.0 skin-tone: 2.0.0 - node-fetch-native@1.6.4: {} - node-fetch@2.7.0(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 @@ -19299,7 +16972,7 @@ snapshots: node-forge@1.3.1: {} - node-gyp-build@4.8.1: {} + node-gyp-build@4.8.2: {} node-gyp@8.4.1: dependencies: @@ -19310,7 +16983,7 @@ snapshots: nopt: 5.0.0 npmlog: 6.0.2 rimraf: 3.0.2 - semver: 7.6.2 + semver: 7.6.3 tar: 6.2.1 which: 2.0.2 transitivePeerDependencies: @@ -19320,9 +16993,7 @@ snapshots: node-int64@0.4.0: {} - node-releases@2.0.14: {} - - node-stream-zip@1.15.0: {} + node-releases@2.0.18: {} nofilter@3.1.0: {} @@ -19336,7 +17007,7 @@ snapshots: normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.4 + resolve: 1.22.8 semver: 5.7.2 validate-npm-package-license: 3.0.4 @@ -19373,30 +17044,23 @@ snapshots: dependencies: execa: 6.1.0 parse-package-name: 1.0.0 - semver: 7.6.2 + semver: 7.6.3 validate-npm-package-name: 4.0.0 nullthrows@1.1.1: {} - ob1@0.80.9: {} + ob1@0.81.0: + dependencies: + flow-enums-runtime: 0.0.6 object-assign@4.1.1: {} object-hash@2.2.0: {} - object-inspect@1.12.3: {} - - object-inspect@1.13.1: {} + object-inspect@1.13.2: {} object-keys@1.1.1: {} - object.assign@4.1.4: - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - has-symbols: 1.0.3 - object-keys: 1.1.1 - object.assign@4.1.5: dependencies: call-bind: 1.0.7 @@ -19404,27 +17068,29 @@ snapshots: has-symbols: 1.0.3 object-keys: 1.1.1 - object.fromentries@2.0.6: + object.fromentries@2.0.8: dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 - object.groupby@1.0.0: + object.groupby@1.0.3: dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 - object.values@1.1.6: + object.values@1.2.0: dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 obuf@1.1.2: {} + ohash@1.1.4: {} + ohm-js@17.1.0: {} oidc-token-hash@5.0.3: {} @@ -19437,8 +17103,6 @@ snapshots: dependencies: ee-first: 1.1.1 - on-headers@1.0.2: {} - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -19455,10 +17119,6 @@ snapshots: dependencies: mimic-fn: 4.0.0 - open@6.4.0: - dependencies: - is-wsl: 1.1.0 - open@7.4.2: dependencies: is-docker: 2.2.1 @@ -19472,19 +17132,19 @@ snapshots: openid-client@5.6.4: dependencies: - jose: 4.15.5 + jose: 4.15.9 lru-cache: 6.0.0 object-hash: 2.2.0 oidc-token-hash: 5.0.3 - optionator@0.9.3: + optionator@0.9.4: dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 + word-wrap: 1.2.5 ora@3.4.0: dependencies: @@ -19495,18 +17155,6 @@ snapshots: strip-ansi: 5.2.0 wcwidth: 1.0.1 - ora@5.4.1: - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - os-homedir@1.0.2: {} os-tmpdir@1.0.2: {} @@ -19522,10 +17170,18 @@ snapshots: dependencies: p-timeout: 5.1.0 + p-event@6.0.1: + dependencies: + p-timeout: 6.1.3 + p-filter@3.0.0: dependencies: p-map: 5.5.0 + p-filter@4.1.0: + dependencies: + p-map: 7.0.2 + p-finally@1.0.0: {} p-limit@2.3.0: @@ -19538,11 +17194,11 @@ snapshots: p-limit@4.0.0: dependencies: - yocto-queue: 1.0.0 + yocto-queue: 1.1.1 p-limit@5.0.0: dependencies: - yocto-queue: 1.0.0 + yocto-queue: 1.1.1 p-locate@3.0.0: dependencies: @@ -19570,10 +17226,16 @@ snapshots: p-map@6.0.0: {} + p-map@7.0.2: {} + p-timeout@5.1.0: {} + p-timeout@6.1.3: {} + p-try@2.2.0: {} + package-json-from-dist@1.0.1: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -19585,7 +17247,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.22.13 + '@babel/code-frame': 7.26.2 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -19598,12 +17260,20 @@ snapshots: dependencies: pngjs: 3.4.0 + parse5-htmlparser2-tree-adapter@6.0.1: + dependencies: + parse5: 6.0.1 + + parse5@5.1.1: {} + + parse5@6.0.1: {} + parseurl@1.3.3: {} password-prompt@1.1.3: dependencies: ansi-escapes: 4.3.2 - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 path-exists@3.0.0: {} @@ -19621,22 +17291,19 @@ snapshots: path-parse@1.0.7: {} - path-scurry@1.10.1: - dependencies: - lru-cache: 9.1.2 - minipass: 5.0.0 - path-scurry@1.11.1: dependencies: - lru-cache: 10.2.2 + lru-cache: 10.4.3 minipass: 7.1.2 - path-to-regexp@0.1.7: {} + path-to-regexp@0.1.10: {} - path-to-regexp@6.2.2: {} + path-to-regexp@6.3.0: {} path-type@4.0.0: {} + path-type@5.0.0: {} + pathe@1.1.2: {} pathval@1.1.1: {} @@ -19652,17 +17319,17 @@ snapshots: pg-connection-string@2.6.1: {} - pg-connection-string@2.6.4: {} + pg-connection-string@2.7.0: {} pg-int8@1.0.1: {} pg-numeric@1.0.2: {} - pg-pool@3.6.2(pg@8.11.5): + pg-pool@3.7.0(pg@8.13.1): dependencies: - pg: 8.11.5 + pg: 8.13.1 - pg-protocol@1.6.1: {} + pg-protocol@1.7.0: {} pg-types@2.2.0: dependencies: @@ -19682,11 +17349,11 @@ snapshots: postgres-interval: 3.0.0 postgres-range: 1.1.4 - pg@8.11.5: + pg@8.13.1: dependencies: - pg-connection-string: 2.6.4 - pg-pool: 3.6.2(pg@8.11.5) - pg-protocol: 1.6.1 + pg-connection-string: 2.7.0 + pg-pool: 3.7.0(pg@8.13.1) + pg-protocol: 1.7.0 pg-types: 2.2.0 pgpass: 1.0.5 optionalDependencies: @@ -19696,14 +17363,14 @@ snapshots: dependencies: split2: 4.2.0 - picocolors@1.0.0: {} - - picocolors@1.0.1: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} picomatch@3.0.1: {} + picomatch@4.0.2: {} + pify@4.0.1: {} pirates@4.0.6: {} @@ -19717,10 +17384,10 @@ snapshots: dependencies: find-up: 3.0.0 - pkg-types@1.1.0: + pkg-types@1.2.1: dependencies: - confbox: 0.1.7 - mlly: 1.7.0 + confbox: 0.1.8 + mlly: 1.7.2 pathe: 1.1.2 plist@3.1.0: @@ -19739,33 +17406,27 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)): + postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3)): dependencies: - lilconfig: 2.1.0 - yaml: 2.3.1 + lilconfig: 3.1.2 + yaml: 2.6.0 optionalDependencies: - postcss: 8.4.39 - ts-node: 10.9.2(@types/node@20.12.12)(typescript@5.6.3) + postcss: 8.4.47 + ts-node: 10.9.2(@types/node@22.9.0)(typescript@5.6.3) - postcss-load-config@6.0.1(postcss@8.4.39)(tsx@3.14.0)(yaml@2.4.2): + postcss-load-config@6.0.1(postcss@8.4.47)(tsx@3.14.0)(yaml@2.6.0): dependencies: lilconfig: 3.1.2 optionalDependencies: - postcss: 8.4.39 + postcss: 8.4.47 tsx: 3.14.0 - yaml: 2.4.2 - - postcss@8.4.38: - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 + yaml: 2.6.0 - postcss@8.4.39: + postcss@8.4.47: dependencies: nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 + picocolors: 1.1.1 + source-map-js: 1.2.1 postgres-array@2.0.0: {} @@ -19789,7 +17450,7 @@ snapshots: postgres-range@1.1.4: {} - postgres@3.4.4: {} + postgres@3.4.5: {} pouchdb-collections@1.0.1: {} @@ -19801,8 +17462,8 @@ snapshots: minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 1.0.2 - node-abi: 3.62.0 - pump: 3.0.0 + node-abi: 3.71.0 + pump: 3.0.2 rc: 1.2.8 simple-get: 4.0.1 tar-fs: 2.1.1 @@ -19816,22 +17477,22 @@ snapshots: prettier@2.8.8: {} - prettier@3.0.3: {} + prettier@3.3.3: {} pretty-bytes@5.6.0: {} - pretty-format@26.6.2: + pretty-format@24.9.0: dependencies: - '@jest/types': 26.6.2 - ansi-regex: 5.0.1 - ansi-styles: 4.3.0 - react-is: 17.0.2 + '@jest/types': 24.9.0 + ansi-regex: 4.1.1 + ansi-styles: 3.2.1 + react-is: 16.13.1 pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 - react-is: 18.2.0 + react-is: 18.3.1 pretty-ms@8.0.0: dependencies: @@ -19888,23 +17549,21 @@ snapshots: dependencies: event-stream: 3.3.4 - pump@3.0.0: + pump@3.0.2: dependencies: end-of-stream: 1.4.4 once: 1.4.0 - punycode@2.3.0: {} - punycode@2.3.1: {} + pure-rand@6.1.0: {} + qrcode-terminal@0.11.0: {} - qs@6.11.0: + qs@6.13.0: dependencies: side-channel: 1.0.6 - querystring@0.2.1: {} - queue-microtask@1.2.3: {} queue@6.0.2: @@ -19931,67 +17590,65 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8): + react-devtools-core@5.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate react-is@16.13.1: {} - react-is@17.0.2: {} - - react-is@18.2.0: {} - react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): + react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) - '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) - '@react-native/assets-registry': 0.74.83 - '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - '@react-native/gradle-plugin': 0.74.83 - '@react-native/js-polyfills': 0.74.83 - '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-native/assets-registry': 0.76.1 + '@react-native/codegen': 0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + '@react-native/community-cli-plugin': 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/gradle-plugin': 0.76.1 + '@react-native/js-polyfills': 0.76.1 + '@react-native/normalize-colors': 0.76.1 + '@react-native/virtualized-lists': 0.76.1(@types/react@18.3.12)(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 + babel-jest: 29.7.0(@babel/core@7.26.0) + babel-plugin-syntax-hermes-parser: 0.23.1 base64-js: 1.5.1 chalk: 4.1.2 + commander: 12.1.0 event-target-shim: 5.0.1 flow-enums-runtime: 0.0.6 + glob: 7.2.3 invariant: 2.2.4 jest-environment-node: 29.7.0 jsc-android: 250231.0.0 memoize-one: 5.2.1 - metro-runtime: 0.80.9 - metro-source-map: 0.80.9 + metro-runtime: 0.81.0 + metro-source-map: 0.81.0 mkdirp: 0.5.6 nullthrows: 1.1.1 - pretty-format: 26.6.2 + pretty-format: 29.7.0 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8) + react-devtools-core: 5.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) react-refresh: 0.14.2 - react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 + semver: 7.6.3 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 optionalDependencies: - '@types/react': 18.3.1 + '@types/react': 18.3.12 transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' + - '@react-native-community/cli-server-api' - bufferutil - encoding - supports-color @@ -19999,12 +17656,6 @@ snapshots: react-refresh@0.14.2: {} - react-shallow-renderer@16.15.0(react@18.3.1): - dependencies: - object-assign: 4.1.1 - react: 18.3.1 - react-is: 18.3.1 - react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -20017,7 +17668,7 @@ snapshots: read-pkg@5.2.0: dependencies: - '@types/normalize-package-data': 2.4.1 + '@types/normalize-package-data': 2.4.4 normalize-package-data: 2.5.0 parse-json: 5.2.0 type-fest: 0.6.0 @@ -20042,6 +17693,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.0.2: {} + readline@1.3.0: {} recast@0.21.5: @@ -20049,7 +17702,7 @@ snapshots: ast-types: 0.15.2 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.6.2 + tslib: 2.8.1 recast@0.23.9: dependencies: @@ -20057,7 +17710,7 @@ snapshots: esprima: 4.0.1 source-map: 0.6.1 tiny-invariant: 1.3.3 - tslib: 2.6.2 + tslib: 2.8.1 rechoir@0.8.0: dependencies: @@ -20067,7 +17720,7 @@ snapshots: dependencies: esprima: 4.0.1 - regenerate-unicode-properties@10.1.1: + regenerate-unicode-properties@10.2.0: dependencies: regenerate: 1.4.2 @@ -20075,45 +17728,39 @@ snapshots: regenerator-runtime@0.13.11: {} - regenerator-runtime@0.14.0: {} - regenerator-runtime@0.14.1: {} regenerator-transform@0.15.2: dependencies: - '@babel/runtime': 7.24.6 + '@babel/runtime': 7.26.0 regexp-tree@0.1.27: {} - regexp.prototype.flags@1.5.0: - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - functions-have-names: 1.2.3 - - regexp.prototype.flags@1.5.2: + regexp.prototype.flags@1.5.3: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 - regexpu-core@5.3.2: + regexpu-core@6.1.1: dependencies: - '@babel/regjsgen': 0.8.0 regenerate: 1.4.2 - regenerate-unicode-properties: 10.1.1 - regjsparser: 0.9.1 + regenerate-unicode-properties: 10.2.0 + regjsgen: 0.8.0 + regjsparser: 0.11.2 unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.1.0 + unicode-match-property-value-ecmascript: 2.2.0 + + regjsgen@0.8.0: {} regjsparser@0.10.0: dependencies: jsesc: 0.5.0 - regjsparser@0.9.1: + regjsparser@0.11.2: dependencies: - jsesc: 0.5.0 + jsesc: 3.0.2 remove-trailing-slash@0.1.1: {} @@ -20121,8 +17768,6 @@ snapshots: require-from-string@2.0.2: {} - require-main-filename@2.0.0: {} - requireg@0.2.2: dependencies: nested-error-stacks: 2.0.1 @@ -20141,36 +17786,18 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve-tspaths@0.8.16(typescript@5.6.3): + resolve-tspaths@0.8.22(typescript@5.6.3): dependencies: ansi-colors: 4.1.3 - commander: 11.0.0 - fast-glob: 3.3.1 + commander: 12.1.0 + fast-glob: 3.3.2 typescript: 5.6.3 resolve.exports@2.0.2: {} - resolve@1.22.1: - dependencies: - is-core-module: 2.11.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - resolve@1.22.2: - dependencies: - is-core-module: 2.12.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - resolve@1.22.4: - dependencies: - is-core-module: 2.13.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - resolve@1.22.8: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -20183,11 +17810,6 @@ snapshots: onetime: 2.0.1 signal-exit: 3.0.7 - restore-cursor@3.1.0: - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - retry@0.12.0: optional: true @@ -20195,26 +17817,17 @@ snapshots: reusify@1.0.4: {} - rimraf@2.4.5: - dependencies: - glob: 6.0.4 - optional: true - rimraf@2.6.3: dependencies: glob: 7.2.3 - rimraf@2.7.1: - dependencies: - glob: 7.2.3 - rimraf@3.0.2: dependencies: glob: 7.2.3 - rimraf@5.0.0: + rimraf@5.0.10: dependencies: - glob: 10.4.1 + glob: 10.4.5 rollup-plugin-inject@3.0.2: dependencies: @@ -20230,56 +17843,32 @@ snapshots: dependencies: estree-walker: 0.6.1 - rollup@3.20.7: - optionalDependencies: - fsevents: 2.3.3 - - rollup@3.27.2: - optionalDependencies: - fsevents: 2.3.3 - - rollup@4.18.0: - dependencies: - '@types/estree': 1.0.5 + rollup@3.29.5: optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.18.0 - '@rollup/rollup-android-arm64': 4.18.0 - '@rollup/rollup-darwin-arm64': 4.18.0 - '@rollup/rollup-darwin-x64': 4.18.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.18.0 - '@rollup/rollup-linux-arm-musleabihf': 4.18.0 - '@rollup/rollup-linux-arm64-gnu': 4.18.0 - '@rollup/rollup-linux-arm64-musl': 4.18.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0 - '@rollup/rollup-linux-riscv64-gnu': 4.18.0 - '@rollup/rollup-linux-s390x-gnu': 4.18.0 - '@rollup/rollup-linux-x64-gnu': 4.18.0 - '@rollup/rollup-linux-x64-musl': 4.18.0 - '@rollup/rollup-win32-arm64-msvc': 4.18.0 - '@rollup/rollup-win32-ia32-msvc': 4.18.0 - '@rollup/rollup-win32-x64-msvc': 4.18.0 fsevents: 2.3.3 - rollup@4.18.1: + rollup@4.24.4: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.18.1 - '@rollup/rollup-android-arm64': 4.18.1 - '@rollup/rollup-darwin-arm64': 4.18.1 - '@rollup/rollup-darwin-x64': 4.18.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.18.1 - '@rollup/rollup-linux-arm-musleabihf': 4.18.1 - '@rollup/rollup-linux-arm64-gnu': 4.18.1 - '@rollup/rollup-linux-arm64-musl': 4.18.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.18.1 - '@rollup/rollup-linux-riscv64-gnu': 4.18.1 - '@rollup/rollup-linux-s390x-gnu': 4.18.1 - '@rollup/rollup-linux-x64-gnu': 4.18.1 - '@rollup/rollup-linux-x64-musl': 4.18.1 - '@rollup/rollup-win32-arm64-msvc': 4.18.1 - '@rollup/rollup-win32-ia32-msvc': 4.18.1 - '@rollup/rollup-win32-x64-msvc': 4.18.1 + '@rollup/rollup-android-arm-eabi': 4.24.4 + '@rollup/rollup-android-arm64': 4.24.4 + '@rollup/rollup-darwin-arm64': 4.24.4 + '@rollup/rollup-darwin-x64': 4.24.4 + '@rollup/rollup-freebsd-arm64': 4.24.4 + '@rollup/rollup-freebsd-x64': 4.24.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.24.4 + '@rollup/rollup-linux-arm-musleabihf': 4.24.4 + '@rollup/rollup-linux-arm64-gnu': 4.24.4 + '@rollup/rollup-linux-arm64-musl': 4.24.4 + '@rollup/rollup-linux-powerpc64le-gnu': 4.24.4 + '@rollup/rollup-linux-riscv64-gnu': 4.24.4 + '@rollup/rollup-linux-s390x-gnu': 4.24.4 + '@rollup/rollup-linux-x64-gnu': 4.24.4 + '@rollup/rollup-linux-x64-musl': 4.24.4 + '@rollup/rollup-win32-arm64-msvc': 4.24.4 + '@rollup/rollup-win32-ia32-msvc': 4.24.4 + '@rollup/rollup-win32-x64-msvc': 4.24.4 fsevents: 2.3.3 run-parallel@1.2.0: @@ -20288,19 +17877,12 @@ snapshots: rxjs@7.8.1: dependencies: - tslib: 2.6.2 + tslib: 2.8.1 sade@1.8.1: dependencies: mri: 1.2.0 - safe-array-concat@1.0.0: - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - has-symbols: 1.0.3 - isarray: 2.0.5 - safe-array-concat@1.1.2: dependencies: call-bind: 1.0.7 @@ -20312,15 +17894,6 @@ snapshots: safe-buffer@5.2.1: {} - safe-json-stringify@1.2.0: - optional: true - - safe-regex-test@1.0.0: - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - is-regex: 1.1.4 - safe-regex-test@1.0.3: dependencies: call-bind: 1.0.7 @@ -20344,9 +17917,27 @@ snapshots: semver@6.3.1: {} - semver@7.6.2: {} + semver@7.6.3: {} + + send@0.18.0: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color - send@0.18.0: + send@0.19.0: dependencies: debug: 2.6.9 depd: 2.0.0 @@ -20372,22 +17963,23 @@ snapshots: dependencies: type-fest: 0.13.1 - serialize-javascript@6.0.1: + serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 - serve-static@1.15.0: + serve-static@1.16.2: dependencies: - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.18.0 + send: 0.19.0 transitivePeerDependencies: - supports-color - set-blocking@2.0.0: {} + set-blocking@2.0.0: + optional: true - set-cookie-parser@2.6.0: {} + set-cookie-parser@2.7.1: {} set-function-length@1.2.2: dependencies: @@ -20427,25 +18019,17 @@ snapshots: shell-quote@1.8.1: {} - side-channel@1.0.4: - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - object-inspect: 1.12.3 - side-channel@1.0.6: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 - object-inspect: 1.13.1 + object-inspect: 1.13.2 siginfo@2.0.0: {} signal-exit@3.0.7: {} - signal-exit@4.0.2: {} - signal-exit@4.1.0: {} simple-concat@1.0.1: {} @@ -20464,7 +18048,7 @@ snapshots: sirv@2.0.4: dependencies: - '@polka/url': 1.0.0-next.25 + '@polka/url': 1.0.0-next.28 mrmime: 2.0.0 totalist: 3.0.1 @@ -20478,11 +18062,7 @@ snapshots: slash@4.0.0: {} - slice-ansi@2.1.0: - dependencies: - ansi-styles: 3.2.1 - astral-regex: 1.0.0 - is-fullwidth-code-point: 2.0.0 + slash@5.1.0: {} slice-ansi@5.0.0: dependencies: @@ -20494,12 +18074,12 @@ snapshots: smart-buffer@4.2.0: optional: true - smob@0.0.6: {} + smob@1.5.0: {} socks-proxy-agent@6.2.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.7 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -20511,7 +18091,7 @@ snapshots: smart-buffer: 4.2.0 optional: true - source-map-js@1.2.0: {} + source-map-js@1.2.1: {} source-map-support@0.5.21: dependencies: @@ -20522,8 +18102,6 @@ snapshots: source-map@0.6.1: {} - source-map@0.7.4: {} - source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 @@ -20535,16 +18113,16 @@ snapshots: spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.13 + spdx-license-ids: 3.0.20 - spdx-exceptions@2.3.0: {} + spdx-exceptions@2.5.0: {} spdx-expression-parse@3.0.1: dependencies: - spdx-exceptions: 2.3.0 - spdx-license-ids: 3.0.13 + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.20 - spdx-license-ids@3.0.13: {} + spdx-license-ids@3.0.20: {} split-ca@1.0.1: {} @@ -20567,12 +18145,12 @@ snapshots: sprintf-js@1.1.3: optional: true - sql.js@1.10.3: {} + sql.js@1.12.0: {} sqlite3@5.1.7: dependencies: bindings: 1.5.0 - node-addon-api: 7.1.0 + node-addon-api: 7.1.1 prebuild-install: 7.1.2 tar: 6.2.1 optionalDependencies: @@ -20583,13 +18161,13 @@ snapshots: sqlstring@2.3.3: {} - ssh2@1.15.0: + ssh2@1.16.0: dependencies: asn1: 0.2.6 bcrypt-pbkdf: 1.0.2 optionalDependencies: cpu-features: 0.0.10 - nan: 2.19.0 + nan: 2.22.0 ssri@10.0.6: dependencies: @@ -20600,14 +18178,34 @@ snapshots: minipass: 3.3.6 optional: true - sst@3.0.14: + sst-darwin-arm64@3.3.5: + optional: true + + sst-darwin-x64@3.3.5: + optional: true + + sst-linux-arm64@3.3.5: + optional: true + + sst-linux-x64@3.3.5: + optional: true + + sst-linux-x86@3.3.5: + optional: true + + sst@3.3.5(hono@4.6.9)(valibot@0.30.0): dependencies: - '@aws-sdk/client-lambda': 3.478.0 - hono: 4.0.1 + aws4fetch: 1.0.20 jose: 5.2.3 openid-client: 5.6.4 - transitivePeerDependencies: - - aws-crt + optionalDependencies: + hono: 4.6.9 + sst-darwin-arm64: 3.3.5 + sst-darwin-x64: 3.3.5 + sst-linux-arm64: 3.3.5 + sst-linux-x64: 3.3.5 + sst-linux-x86: 3.3.5 + valibot: 0.30.0 stack-utils@2.0.6: dependencies: @@ -20654,12 +18252,6 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 - string.prototype.trim@1.2.7: - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - string.prototype.trim@1.2.9: dependencies: call-bind: 1.0.7 @@ -20667,24 +18259,12 @@ snapshots: es-abstract: 1.23.3 es-object-atoms: 1.0.0 - string.prototype.trimend@1.0.6: - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - string.prototype.trimend@1.0.8: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 - string.prototype.trimstart@1.0.6: - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - string.prototype.trimstart@1.0.8: dependencies: call-bind: 1.0.7 @@ -20709,7 +18289,7 @@ snapshots: strip-ansi@7.1.0: dependencies: - ansi-regex: 6.0.1 + ansi-regex: 6.1.0 strip-bom@3.0.0: {} @@ -20737,7 +18317,7 @@ snapshots: sucrase@3.34.0: dependencies: - '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 glob: 7.1.6 lines-and-columns: 1.2.4 @@ -20749,7 +18329,7 @@ snapshots: dependencies: '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 - glob: 10.4.1 + glob: 10.4.5 lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.6 @@ -20759,8 +18339,6 @@ snapshots: sudo-prompt@9.1.1: {} - sudo-prompt@9.2.1: {} - superjson@2.2.1: dependencies: copy-anything: 3.0.5 @@ -20789,30 +18367,30 @@ snapshots: has-flag: 4.0.0 supports-color: 7.2.0 - supports-hyperlinks@3.0.0: + supports-hyperlinks@3.1.0: dependencies: has-flag: 4.0.0 supports-color: 7.2.0 supports-preserve-symlinks-flag@1.0.0: {} - synckit@0.9.1: + synckit@0.9.2: dependencies: '@pkgr/core': 0.1.1 - tslib: 2.6.2 + tslib: 2.8.1 tar-fs@2.0.1: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.0 + pump: 3.0.2 tar-stream: 2.2.0 tar-fs@2.1.1: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.0 + pump: 3.0.2 tar-stream: 2.2.0 tar-stream@2.2.0: @@ -20863,19 +18441,18 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - terser@5.17.1: + terser@5.36.0: dependencies: - '@jridgewell/source-map': 0.3.3 - acorn: 8.8.2 + '@jridgewell/source-map': 0.3.6 + acorn: 8.14.0 commander: 2.20.3 source-map-support: 0.5.21 - terser@5.31.0: + test-exclude@6.0.0: dependencies: - '@jridgewell/source-map': 0.3.6 - acorn: 8.11.3 - commander: 2.20.3 - source-map-support: 0.5.21 + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 text-table@0.2.0: {} @@ -20904,20 +18481,23 @@ snapshots: time-zone@1.0.0: {} - timers-ext@0.1.7: + timers-ext@0.1.8: dependencies: - es5-ext: 0.10.62 + es5-ext: 0.10.64 next-tick: 1.1.0 tiny-invariant@1.3.3: {} tiny-queue@0.2.1: {} - tinybench@2.8.0: {} - tinybench@2.9.0: {} - tinyexec@0.3.0: {} + tinyexec@0.3.1: {} + + tinyglobby@0.2.10: + dependencies: + fdir: 6.4.2(picomatch@4.0.2) + picomatch: 4.0.2 tinypool@0.8.4: {} @@ -20949,9 +18529,9 @@ snapshots: tr46@1.0.1: dependencies: - punycode: 2.3.0 + punycode: 2.3.1 - traverse@0.6.9: + traverse@0.6.10: dependencies: gopd: 1.0.1 typedarray.prototype.slice: 1.0.3 @@ -20961,15 +18541,9 @@ snapshots: treeify@1.1.0: {} - ts-api-utils@1.0.3(typescript@5.2.2): - dependencies: - typescript: 5.2.2 - - ts-api-utils@1.0.3(typescript@5.6.3): - dependencies: - typescript: 5.6.3 + trim-right@1.0.1: {} - ts-api-utils@1.3.0(typescript@5.6.3): + ts-api-utils@1.4.0(typescript@5.6.3): dependencies: typescript: 5.6.3 @@ -20977,16 +18551,34 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3): + ts-node@10.9.2(@types/node@20.17.6)(typescript@5.6.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.17.6 + acorn: 8.14.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.6.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.12.12 - acorn: 8.11.3 - acorn-walk: 8.3.2 + '@types/node': 22.9.0 + acorn: 8.14.0 + acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 @@ -20994,12 +18586,13 @@ snapshots: typescript: 5.6.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + optional: true - tsconfck@3.0.3(typescript@5.6.3): + tsconfck@3.1.4(typescript@5.6.3): optionalDependencies: typescript: 5.6.3 - tsconfig-paths@3.14.2: + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 json5: 1.0.2 @@ -21008,50 +18601,51 @@ snapshots: tslib@1.14.1: {} - tslib@2.6.2: {} + tslib@2.8.1: {} - tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3): + tsup@7.3.0(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3): dependencies: - bundle-require: 4.0.2(esbuild@0.18.20) + bundle-require: 4.2.1(esbuild@0.19.12) cac: 6.7.14 - chokidar: 3.5.3 - debug: 4.3.4 - esbuild: 0.18.20 + chokidar: 3.6.0 + debug: 4.3.7 + esbuild: 0.19.12 execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)) + postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3)) resolve-from: 5.0.0 - rollup: 3.27.2 + rollup: 4.24.4 source-map: 0.8.0-beta.0 - sucrase: 3.34.0 + sucrase: 3.35.0 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.4.39 + postcss: 8.4.47 typescript: 5.6.3 transitivePeerDependencies: - supports-color - ts-node - tsup@8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.4.2): + tsup@8.3.5(postcss@8.4.47)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.6.0): dependencies: - bundle-require: 5.0.0(esbuild@0.23.0) + bundle-require: 5.0.0(esbuild@0.24.0) cac: 6.7.14 - chokidar: 3.6.0 + chokidar: 4.0.1 consola: 3.2.3 - debug: 4.3.5 - esbuild: 0.23.0 - execa: 5.1.1 - globby: 11.1.0 + debug: 4.3.7 + esbuild: 0.24.0 joycon: 3.1.1 - postcss-load-config: 6.0.1(postcss@8.4.39)(tsx@3.14.0)(yaml@2.4.2) + picocolors: 1.1.1 + postcss-load-config: 6.0.1(postcss@8.4.47)(tsx@3.14.0)(yaml@2.6.0) resolve-from: 5.0.0 - rollup: 4.18.1 + rollup: 4.24.4 source-map: 0.8.0-beta.0 sucrase: 3.35.0 + tinyexec: 0.3.1 + tinyglobby: 0.2.10 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.4.39 + postcss: 8.4.47 typescript: 5.6.3 transitivePeerDependencies: - jiti @@ -21067,22 +18661,15 @@ snapshots: tsx@3.14.0: dependencies: esbuild: 0.18.20 - get-tsconfig: 4.7.5 + get-tsconfig: 4.8.1 source-map-support: 0.5.21 optionalDependencies: fsevents: 2.3.3 - tsx@4.10.5: + tsx@4.19.2: dependencies: - esbuild: 0.20.2 - get-tsconfig: 4.7.5 - optionalDependencies: - fsevents: 2.3.3 - - tsx@4.16.2: - dependencies: - esbuild: 0.21.5 - get-tsconfig: 4.7.5 + esbuild: 0.23.1 + get-tsconfig: 4.8.1 optionalDependencies: fsevents: 2.3.3 @@ -21125,6 +18712,8 @@ snapshots: type-detect@4.0.8: {} + type-detect@4.1.0: {} + type-fest@0.13.1: {} type-fest@0.16.0: {} @@ -21141,22 +18730,12 @@ snapshots: type-fest@0.8.1: {} - type-fest@3.13.1: {} - type-is@1.6.18: dependencies: media-typer: 0.3.0 mime-types: 2.1.35 - type@1.2.0: {} - - type@2.7.2: {} - - typed-array-buffer@1.0.0: - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - is-typed-array: 1.1.12 + type@2.7.3: {} typed-array-buffer@1.0.2: dependencies: @@ -21164,13 +18743,6 @@ snapshots: es-errors: 1.3.0 is-typed-array: 1.1.13 - typed-array-byte-length@1.0.0: - dependencies: - call-bind: 1.0.2 - for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 - typed-array-byte-length@1.0.1: dependencies: call-bind: 1.0.7 @@ -21179,14 +18751,6 @@ snapshots: has-proto: 1.0.3 is-typed-array: 1.1.13 - typed-array-byte-offset@1.0.0: - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 - typed-array-byte-offset@1.0.2: dependencies: available-typed-arrays: 1.0.7 @@ -21196,12 +18760,6 @@ snapshots: has-proto: 1.0.3 is-typed-array: 1.1.13 - typed-array-length@1.0.4: - dependencies: - call-bind: 1.0.2 - for-each: 0.3.3 - is-typed-array: 1.1.12 - typed-array-length@1.0.6: dependencies: call-bind: 1.0.7 @@ -21220,51 +18778,53 @@ snapshots: typed-array-buffer: 1.0.2 typed-array-byte-offset: 1.0.2 - typescript@5.2.2: {} - typescript@5.3.3: {} + typescript@5.6.1-rc: {} + typescript@5.6.3: {} - ua-parser-js@1.0.38: {} + ua-parser-js@1.0.39: {} - ufo@1.5.3: {} + ufo@1.5.4: {} unbox-primitive@1.0.2: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 undici-types@5.26.5: {} + undici-types@6.19.8: {} + undici@5.28.4: dependencies: '@fastify/busboy': 2.1.1 - unenv-nightly@1.10.0-1717606461.a117952: + unenv-nightly@2.0.0-20241024-111401-d4156ac: dependencies: - consola: 3.2.3 defu: 6.1.4 - mime: 3.0.0 - node-fetch-native: 1.6.4 + ohash: 1.1.4 pathe: 1.1.2 - ufo: 1.5.3 + ufo: 1.5.4 - unicode-canonical-property-names-ecmascript@2.0.0: {} + unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-emoji-modifier-base@1.0.0: {} unicode-match-property-ecmascript@2.0.0: dependencies: - unicode-canonical-property-names-ecmascript: 2.0.0 + unicode-canonical-property-names-ecmascript: 2.0.1 unicode-property-aliases-ecmascript: 2.1.0 - unicode-match-property-value-ecmascript@2.1.0: {} + unicode-match-property-value-ecmascript@2.2.0: {} unicode-property-aliases-ecmascript@2.1.0: {} + unicorn-magic@0.1.0: {} + unique-filename@1.1.1: dependencies: unique-slug: 2.0.2 @@ -21295,21 +18855,19 @@ snapshots: universalify@1.0.0: {} - universalify@2.0.0: {} - universalify@2.0.1: {} unpipe@1.0.0: {} - update-browserslist-db@1.0.16(browserslist@4.23.0): + update-browserslist-db@1.1.1(browserslist@4.24.2): dependencies: - browserslist: 4.23.0 - escalade: 3.1.2 - picocolors: 1.0.1 + browserslist: 4.24.2 + escalade: 3.2.0 + picocolors: 1.1.1 uri-js@4.4.1: dependencies: - punycode: 2.3.0 + punycode: 2.3.1 url-join@4.0.0: {} @@ -21317,12 +18875,14 @@ snapshots: utf-8-validate@6.0.3: dependencies: - node-gyp-build: 4.8.1 + node-gyp-build: 4.8.2 util-deprecate@1.0.2: {} utils-merge@1.0.1: {} + uuid@10.0.0: {} + uuid@7.0.3: {} uuid@8.3.2: {} @@ -21332,7 +18892,7 @@ snapshots: uvu@0.5.6: dependencies: dequal: 2.0.3 - diff: 5.1.0 + diff: 5.2.0 kleur: 4.1.5 sade: 1.8.1 @@ -21355,382 +18915,268 @@ snapshots: dependencies: builtins: 5.1.0 - validate-npm-package-name@5.0.0: - dependencies: - builtins: 5.1.0 + validate-npm-package-name@5.0.1: {} vary@1.1.2: {} - vite-node@1.6.0(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0): - dependencies: - cac: 6.7.14 - debug: 4.3.4 - pathe: 1.1.2 - picocolors: 1.0.1 - vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - stylus - - sugarss - - supports-color - - terser - - vite-node@1.6.0(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0): + vite-node@1.6.0(@types/node@18.19.64)(terser@5.36.0): dependencies: cac: 6.7.14 - debug: 4.3.4 + debug: 4.3.7 pathe: 1.1.2 - picocolors: 1.0.1 - vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) + picocolors: 1.1.1 + vite: 5.4.10(@types/node@18.19.64)(terser@5.36.0) transitivePeerDependencies: - '@types/node' - less - lightningcss - sass + - sass-embedded - stylus - sugarss - supports-color - terser - vite-node@1.6.0(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0): + vite-node@1.6.0(@types/node@20.17.6)(terser@5.36.0): dependencies: cac: 6.7.14 - debug: 4.3.4 + debug: 4.3.7 pathe: 1.1.2 - picocolors: 1.0.1 - vite: 5.3.3(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0) + picocolors: 1.1.1 + vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) transitivePeerDependencies: - '@types/node' - less - lightningcss - sass + - sass-embedded - stylus - sugarss - supports-color - terser - vite-node@1.6.0(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): + vite-node@2.1.4(@types/node@20.17.6)(terser@5.36.0): dependencies: cac: 6.7.14 - debug: 4.3.4 + debug: 4.3.7 pathe: 1.1.2 - picocolors: 1.0.1 - vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) transitivePeerDependencies: - '@types/node' - less - lightningcss - sass + - sass-embedded - stylus - sugarss - supports-color - terser - vite-node@2.1.2(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): + vite-node@2.1.4(@types/node@22.9.0)(terser@5.36.0): dependencies: cac: 6.7.14 debug: 4.3.7 pathe: 1.1.2 - vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.4.10(@types/node@22.9.0)(terser@5.36.0) transitivePeerDependencies: - '@types/node' - less - lightningcss - sass + - sass-embedded - stylus - sugarss - supports-color - terser - vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)): - dependencies: - debug: 4.3.4 - globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.6.3) - optionalDependencies: - vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) - transitivePeerDependencies: - - supports-color - - typescript - - vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)): + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)): dependencies: - debug: 4.3.4 + debug: 4.3.7 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.6.3) + tsconfck: 3.1.4(typescript@5.6.3) optionalDependencies: - vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.4.10(@types/node@18.19.64)(terser@5.36.0) transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)): + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)): dependencies: - debug: 4.3.4 + debug: 4.3.7 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.6.3) + tsconfck: 3.1.4(typescript@5.6.3) optionalDependencies: - vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) transitivePeerDependencies: - supports-color - typescript - vite@5.2.12(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0): - dependencies: - esbuild: 0.20.2 - postcss: 8.4.38 - rollup: 4.18.0 - optionalDependencies: - '@types/node': 18.15.10 - fsevents: 2.3.3 - lightningcss: 1.25.1 - terser: 5.31.0 - - vite@5.2.12(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0): - dependencies: - esbuild: 0.20.2 - postcss: 8.4.38 - rollup: 4.18.0 - optionalDependencies: - '@types/node': 18.19.33 - fsevents: 2.3.3 - lightningcss: 1.25.1 - terser: 5.31.0 - - vite@5.2.12(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0): - dependencies: - esbuild: 0.20.2 - postcss: 8.4.38 - rollup: 4.18.0 - optionalDependencies: - '@types/node': 20.10.1 - fsevents: 2.3.3 - lightningcss: 1.25.1 - terser: 5.31.0 - - vite@5.2.12(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): - dependencies: - esbuild: 0.20.2 - postcss: 8.4.38 - rollup: 4.18.0 - optionalDependencies: - '@types/node': 20.12.12 - fsevents: 2.3.3 - lightningcss: 1.25.1 - terser: 5.31.0 - - vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0): - dependencies: - esbuild: 0.21.5 - postcss: 8.4.39 - rollup: 4.18.0 - optionalDependencies: - '@types/node': 18.15.10 - fsevents: 2.3.3 - lightningcss: 1.25.1 - terser: 5.31.0 - - vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0): + vite@5.4.10(@types/node@18.19.64)(terser@5.36.0): dependencies: esbuild: 0.21.5 - postcss: 8.4.39 - rollup: 4.18.0 + postcss: 8.4.47 + rollup: 4.24.4 optionalDependencies: - '@types/node': 18.19.33 + '@types/node': 18.19.64 fsevents: 2.3.3 - lightningcss: 1.25.1 - terser: 5.31.0 + terser: 5.36.0 - vite@5.3.3(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0): + vite@5.4.10(@types/node@20.17.6)(terser@5.36.0): dependencies: esbuild: 0.21.5 - postcss: 8.4.39 - rollup: 4.18.0 + postcss: 8.4.47 + rollup: 4.24.4 optionalDependencies: - '@types/node': 20.10.1 + '@types/node': 20.17.6 fsevents: 2.3.3 - lightningcss: 1.25.1 - terser: 5.31.0 + terser: 5.36.0 - vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): + vite@5.4.10(@types/node@22.9.0)(terser@5.36.0): dependencies: esbuild: 0.21.5 - postcss: 8.4.39 - rollup: 4.18.0 + postcss: 8.4.47 + rollup: 4.24.4 optionalDependencies: - '@types/node': 20.12.12 + '@types/node': 22.9.0 fsevents: 2.3.3 - lightningcss: 1.25.1 - terser: 5.31.0 - - vitest@1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): - dependencies: - '@vitest/expect': 1.6.0 - '@vitest/runner': 1.6.0 - '@vitest/snapshot': 1.6.0 - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - acorn-walk: 8.3.2 - chai: 4.4.1 - debug: 4.3.4 - execa: 8.0.1 - local-pkg: 0.5.0 - magic-string: 0.30.10 - pathe: 1.1.2 - picocolors: 1.0.0 - std-env: 3.7.0 - strip-literal: 2.1.0 - tinybench: 2.8.0 - tinypool: 0.8.4 - vite: 5.2.12(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) - vite-node: 1.6.0(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) - why-is-node-running: 2.2.2 - optionalDependencies: - '@types/node': 18.15.10 - '@vitest/ui': 1.6.0(vitest@1.6.0) - transitivePeerDependencies: - - less - - lightningcss - - sass - - stylus - - sugarss - - supports-color - - terser + terser: 5.36.0 - vitest@1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): + vitest@1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0): dependencies: '@vitest/expect': 1.6.0 '@vitest/runner': 1.6.0 '@vitest/snapshot': 1.6.0 '@vitest/spy': 1.6.0 '@vitest/utils': 1.6.0 - acorn-walk: 8.3.2 - chai: 4.4.1 - debug: 4.3.4 + acorn-walk: 8.3.4 + chai: 4.5.0 + debug: 4.3.7 execa: 8.0.1 local-pkg: 0.5.0 - magic-string: 0.30.10 + magic-string: 0.30.12 pathe: 1.1.2 - picocolors: 1.0.0 + picocolors: 1.1.1 std-env: 3.7.0 strip-literal: 2.1.0 - tinybench: 2.8.0 + tinybench: 2.9.0 tinypool: 0.8.4 - vite: 5.2.12(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) - vite-node: 1.6.0(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) - why-is-node-running: 2.2.2 + vite: 5.4.10(@types/node@18.19.64)(terser@5.36.0) + vite-node: 1.6.0(@types/node@18.19.64)(terser@5.36.0) + why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 18.19.33 + '@types/node': 18.19.64 '@vitest/ui': 1.6.0(vitest@1.6.0) transitivePeerDependencies: - less - lightningcss - sass + - sass-embedded - stylus - sugarss - supports-color - terser - vitest@1.6.0(@types/node@20.10.1)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): + vitest@1.6.0(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0): dependencies: '@vitest/expect': 1.6.0 '@vitest/runner': 1.6.0 '@vitest/snapshot': 1.6.0 '@vitest/spy': 1.6.0 '@vitest/utils': 1.6.0 - acorn-walk: 8.3.2 - chai: 4.4.1 - debug: 4.3.4 + acorn-walk: 8.3.4 + chai: 4.5.0 + debug: 4.3.7 execa: 8.0.1 local-pkg: 0.5.0 - magic-string: 0.30.10 + magic-string: 0.30.12 pathe: 1.1.2 - picocolors: 1.0.0 + picocolors: 1.1.1 std-env: 3.7.0 strip-literal: 2.1.0 - tinybench: 2.8.0 + tinybench: 2.9.0 tinypool: 0.8.4 - vite: 5.2.12(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0) - vite-node: 1.6.0(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0) - why-is-node-running: 2.2.2 + vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) + vite-node: 1.6.0(@types/node@20.17.6)(terser@5.36.0) + why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 20.10.1 + '@types/node': 20.17.6 '@vitest/ui': 1.6.0(vitest@1.6.0) transitivePeerDependencies: - less - lightningcss - sass + - sass-embedded - stylus - sugarss - supports-color - terser - vitest@1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): + vitest@2.1.4(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0): dependencies: - '@vitest/expect': 1.6.0 - '@vitest/runner': 1.6.0 - '@vitest/snapshot': 1.6.0 - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - acorn-walk: 8.3.2 - chai: 4.4.1 - debug: 4.3.4 - execa: 8.0.1 - local-pkg: 0.5.0 - magic-string: 0.30.10 + '@vitest/expect': 2.1.4 + '@vitest/mocker': 2.1.4(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)) + '@vitest/pretty-format': 2.1.4 + '@vitest/runner': 2.1.4 + '@vitest/snapshot': 2.1.4 + '@vitest/spy': 2.1.4 + '@vitest/utils': 2.1.4 + chai: 5.1.2 + debug: 4.3.7 + expect-type: 1.1.0 + magic-string: 0.30.12 pathe: 1.1.2 - picocolors: 1.0.0 std-env: 3.7.0 - strip-literal: 2.1.0 - tinybench: 2.8.0 - tinypool: 0.8.4 - vite: 5.2.12(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) - vite-node: 1.6.0(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) - why-is-node-running: 2.2.2 + tinybench: 2.9.0 + tinyexec: 0.3.1 + tinypool: 1.0.1 + tinyrainbow: 1.2.0 + vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) + vite-node: 2.1.4(@types/node@20.17.6)(terser@5.36.0) + why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 20.12.12 - '@vitest/ui': 1.6.0(vitest@1.6.0) + '@types/node': 20.17.6 + '@vitest/ui': 1.6.0(vitest@2.1.4) transitivePeerDependencies: - less - lightningcss + - msw - sass + - sass-embedded - stylus - sugarss - supports-color - terser - vitest@2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): + vitest@2.1.4(@types/node@22.9.0)(terser@5.36.0): dependencies: - '@vitest/expect': 2.1.2 - '@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) - '@vitest/pretty-format': 2.1.2 - '@vitest/runner': 2.1.2 - '@vitest/snapshot': 2.1.2 - '@vitest/spy': 2.1.2 - '@vitest/utils': 2.1.2 - chai: 5.1.1 + '@vitest/expect': 2.1.4 + '@vitest/mocker': 2.1.4(vite@5.4.10(@types/node@22.9.0)(terser@5.36.0)) + '@vitest/pretty-format': 2.1.4 + '@vitest/runner': 2.1.4 + '@vitest/snapshot': 2.1.4 + '@vitest/spy': 2.1.4 + '@vitest/utils': 2.1.4 + chai: 5.1.2 debug: 4.3.7 - magic-string: 0.30.11 + expect-type: 1.1.0 + magic-string: 0.30.12 pathe: 1.1.2 std-env: 3.7.0 tinybench: 2.9.0 - tinyexec: 0.3.0 + tinyexec: 0.3.1 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) - vite-node: 2.1.2(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + vite: 5.4.10(@types/node@22.9.0)(terser@5.36.0) + vite-node: 2.1.4(@types/node@22.9.0)(terser@5.36.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 20.12.12 - '@vitest/ui': 1.6.0(vitest@2.1.2) + '@types/node': 22.9.0 transitivePeerDependencies: - less - lightningcss - msw - sass + - sass-embedded - stylus - sugarss - supports-color @@ -21746,7 +19192,7 @@ snapshots: dependencies: defaults: 1.0.4 - web-streams-polyfill@3.2.1: {} + web-streams-polyfill@3.3.3: {} webidl-conversions@3.0.1: {} @@ -21785,16 +19231,6 @@ snapshots: is-string: 1.0.7 is-symbol: 1.0.4 - which-module@2.0.1: {} - - which-typed-array@1.1.11: - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.0 - which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 @@ -21815,11 +19251,6 @@ snapshots: dependencies: isexe: 2.0.0 - why-is-node-running@2.2.2: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 @@ -21832,48 +19263,47 @@ snapshots: wonka@4.0.15: {} + word-wrap@1.2.5: {} + wordwrap@1.0.0: {} - workerd@1.20240712.0: + workerd@1.20241022.0: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20240712.0 - '@cloudflare/workerd-darwin-arm64': 1.20240712.0 - '@cloudflare/workerd-linux-64': 1.20240712.0 - '@cloudflare/workerd-linux-arm64': 1.20240712.0 - '@cloudflare/workerd-windows-64': 1.20240712.0 + '@cloudflare/workerd-darwin-64': 1.20241022.0 + '@cloudflare/workerd-darwin-arm64': 1.20241022.0 + '@cloudflare/workerd-linux-64': 1.20241022.0 + '@cloudflare/workerd-linux-arm64': 1.20241022.0 + '@cloudflare/workerd-windows-64': 1.20241022.0 - wrangler@3.65.0(@cloudflare/workers-types@4.20240524.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3): + wrangler@3.85.0(@cloudflare/workers-types@4.20241106.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: '@cloudflare/kv-asset-handler': 0.3.4 + '@cloudflare/workers-shared': 0.7.0 '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) blake3-wasm: 2.1.5 - chokidar: 3.5.3 - date-fns: 3.6.0 + chokidar: 3.6.0 + date-fns: 4.1.0 esbuild: 0.17.19 - miniflare: 3.20240712.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + itty-time: 1.0.6 + miniflare: 3.20241022.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) nanoid: 3.3.7 - path-to-regexp: 6.2.2 + path-to-regexp: 6.3.0 resolve: 1.22.8 resolve.exports: 2.0.2 selfsigned: 2.4.1 source-map: 0.6.1 - unenv: unenv-nightly@1.10.0-1717606461.a117952 + unenv: unenv-nightly@2.0.0-20241024-111401-d4156ac + workerd: 1.20241022.0 xxhash-wasm: 1.0.2 optionalDependencies: - '@cloudflare/workers-types': 4.20240524.0 + '@cloudflare/workers-types': 4.20241106.0 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -21894,27 +19324,29 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + write-file-atomic@5.0.1: dependencies: imurmurhash: 0.1.4 - signal-exit: 4.0.2 + signal-exit: 4.1.0 - ws@6.2.2(bufferutil@4.0.8): + ws@6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8): - optionalDependencies: - bufferutil: 4.0.8 - - ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 utf-8-validate: 6.0.3 - ws@8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 utf-8-validate: 6.0.3 @@ -21944,45 +19376,22 @@ snapshots: xxhash-wasm@1.0.2: {} - y18n@4.0.3: {} - y18n@5.0.8: {} yallist@3.1.1: {} yallist@4.0.0: {} - yaml@2.3.1: {} - - yaml@2.4.2: {} - - yargs-parser@18.1.3: - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 + yaml@2.6.0: {} yargs-parser@20.2.9: {} yargs-parser@21.1.1: {} - yargs@15.4.1: - dependencies: - cliui: 6.0.0 - decamelize: 1.2.0 - find-up: 4.1.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 4.2.3 - which-module: 2.0.1 - y18n: 4.0.3 - yargs-parser: 18.1.3 - yargs@16.2.0: dependencies: cliui: 7.0.4 - escalade: 3.1.2 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -21992,7 +19401,7 @@ snapshots: yargs@17.7.2: dependencies: cliui: 8.0.1 - escalade: 3.1.1 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -22003,32 +19412,39 @@ snapshots: yocto-queue@0.1.0: {} - yocto-queue@1.0.0: {} + yocto-queue@1.1.1: {} - youch@3.3.3: + youch@3.3.4: dependencies: - cookie: 0.5.0 + cookie: 0.7.2 mustache: 4.2.0 stacktracey: 2.1.8 - zod@3.21.4: {} + zod-validation-error@2.1.0(zod@3.23.8): + dependencies: + zod: 3.23.8 - zod@3.23.7: {} + zod@3.23.8: {} - zx@7.2.2: + zx@7.2.3: dependencies: '@types/fs-extra': 11.0.4 - '@types/minimist': 1.2.2 - '@types/node': 18.19.33 - '@types/ps-tree': 1.1.2 - '@types/which': 3.0.0 + '@types/minimist': 1.2.5 + '@types/node': 18.19.64 + '@types/ps-tree': 1.1.6 + '@types/which': 3.0.4 chalk: 5.3.0 - fs-extra: 11.1.1 - fx: 28.0.0 + fs-extra: 11.2.0 + fx: 35.0.0 globby: 13.2.2 minimist: 1.2.8 node-fetch: 3.3.1 ps-tree: 1.2.0 webpod: 0.0.2 which: 3.0.1 - yaml: 2.4.2 + yaml: 2.6.0 + + zx@8.2.0: + optionalDependencies: + '@types/fs-extra': 11.0.4 + '@types/node': 22.9.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7cf196659..0a4ddf3b4 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,5 +4,6 @@ packages: - drizzle-zod - drizzle-typebox - drizzle-valibot + - drizzle-seed - integration-tests - eslint-plugin-drizzle diff --git a/turbo.json b/turbo.json index e978069b2..6af34fa47 100644 --- a/turbo.json +++ b/turbo.json @@ -17,7 +17,8 @@ "test:types": { "dependsOn": [ "^test:types", - "drizzle-orm#build" + "drizzle-orm#build", + "drizzle-seed#build" ], "inputs": [ "src/**/*.ts", @@ -157,7 +158,7 @@ ], "outputLogs": "new-only" }, - "integration-tests#build": { + "drizzle-seed#build": { "dependsOn": [ "drizzle-orm#build" ], @@ -179,6 +180,29 @@ ], "outputLogs": "new-only" }, + "integration-tests#build": { + "dependsOn": [ + "drizzle-orm#build", + "drizzle-seed#build" + ], + "inputs": [ + "src/**/*.ts", + "package.json", + "README.md", + "../README.md", + "tsconfig.json", + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" + ], + "outputs": [ + "dist/**", + "dist-dts/**" + ], + "outputLogs": "new-only" + }, "pack": { "dependsOn": [ "build", From 345f365ecb3b1423f03695da2776884eefbfe7e0 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 21 Nov 2024 15:35:32 +0200 Subject: [PATCH 378/492] Add publish script --- drizzle-seed/package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index c529f22e8..a0ac6a125 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -15,7 +15,8 @@ "start:pg": "npx tsx ./src/tests/northwind/pgTest.ts", "start:mysql": "npx tsx ./src/tests/northwind/mysqlTest.ts", "start:sqlite": "npx tsx ./src/tests/northwind/sqliteTest.ts", - "benchmark": "npx tsx ./src/tests/benchmarks/generatorsBenchmark.ts" + "benchmark": "npx tsx ./src/tests/benchmarks/generatorsBenchmark.ts", + "publish": "npm publish package.tgz" }, "author": "Drizzle Team", "license": "Apache-2.0", @@ -100,4 +101,4 @@ "dependencies": { "pure-rand": "^6.1.0" } -} +} \ No newline at end of file From fcaa0a52e8b0e8d6bb327ebb2860e24bfc99bd63 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 21 Nov 2024 15:47:13 +0200 Subject: [PATCH 379/492] dprint! --- drizzle-seed/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index a0ac6a125..32ada8a46 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -101,4 +101,4 @@ "dependencies": { "pure-rand": "^6.1.0" } -} \ No newline at end of file +} From a2d734c4d8515d8c02aa499de022f5d1eb8e962b Mon Sep 17 00:00:00 2001 From: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:09:18 +0200 Subject: [PATCH 380/492] Neon `$withAuth` (#3562) * Added `` for `neon-http` driver, updated `@neondatabase/serverless` version, fixed `.catch` on `` requiring strict return type * Fixed package version mismatch --------- Co-authored-by: Andrii Sherman --- drizzle-orm/package.json | 4 +- drizzle-orm/src/neon-http/driver.ts | 56 + drizzle-orm/src/neon-http/session.ts | 64 +- drizzle-orm/src/pg-core/db.ts | 4 +- .../src/pg-core/query-builders/count.ts | 10 +- .../src/pg-core/query-builders/delete.ts | 9 +- .../src/pg-core/query-builders/insert.ts | 53 +- .../src/pg-core/query-builders/query.ts | 9 +- .../refresh-materialized-view.ts | 9 +- .../src/pg-core/query-builders/select.ts | 49 +- .../src/pg-core/query-builders/update.ts | 37 +- drizzle-orm/src/pg-core/session.ts | 28 +- integration-tests/package.json | 2 +- integration-tests/tests/pg/neon-http.test.ts | 112 +- pnpm-lock.yaml | 12203 ++++++++++------ 15 files changed, 8090 insertions(+), 4559 deletions(-) diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 809a28520..87c3f0bc2 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -49,7 +49,7 @@ "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", - "@neondatabase/serverless": ">=0.1", + "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1", @@ -169,7 +169,7 @@ "@libsql/client": "^0.10.0", "@libsql/client-wasm": "^0.10.0", "@miniflare/d1": "^2.14.4", - "@neondatabase/serverless": "^0.9.0", + "@neondatabase/serverless": "^0.10.0", "@op-engineering/op-sqlite": "^2.0.16", "@opentelemetry/api": "^1.4.1", "@originjs/vite-plugin-commonjs": "^1.0.3", diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index cfa0c7861..76ae5c426 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -40,11 +40,67 @@ export class NeonHttpDriver { } } +function wrap( + target: T, + token: string, + cb: (target: any, p: string | symbol, res: any) => any, + deep?: boolean, +) { + return new Proxy(target, { + get(target, p) { + const element = target[p as keyof typeof p]; + if (typeof element !== 'function' && (typeof element !== 'object' || element === null)) return element; + + if (deep) return wrap(element, token, cb); + if (p === 'query') return wrap(element, token, cb, true); + + return new Proxy(element as any, { + apply(target, thisArg, argArray) { + const res = target.call(thisArg, ...argArray); + if ('setToken' in res && typeof res.setToken === 'function') { + res.setToken(token); + } + return cb(target, p, res); + }, + }); + }, + }); +} + export class NeonHttpDatabase< TSchema extends Record = Record, > extends PgDatabase { static override readonly [entityKind]: string = 'NeonHttpDatabase'; + $withAuth( + token: string, + ): Omit< + this, + Exclude< + keyof this, + | '$count' + | 'delete' + | 'select' + | 'selectDistinct' + | 'selectDistinctOn' + | 'update' + | 'insert' + | 'with' + | 'query' + | 'execute' + | 'refreshMaterializedView' + > + > { + this.authToken = token; + + return wrap(this, token, (target, p, res) => { + if (p === 'with') { + return wrap(res, token, (_, __, res) => res); + } + return res; + }); + } + /** @internal */ declare readonly session: NeonHttpSession>; diff --git a/drizzle-orm/src/neon-http/session.ts b/drizzle-orm/src/neon-http/session.ts index cd4a855e7..c8f8f5a33 100644 --- a/drizzle-orm/src/neon-http/session.ts +++ b/drizzle-orm/src/neon-http/session.ts @@ -38,7 +38,14 @@ export class NeonHttpPreparedQuery extends PgPrep super(query); } - async execute(placeholderValues: Record | undefined = {}): Promise { + async execute(placeholderValues: Record | undefined): Promise; + /** @internal */ + async execute(placeholderValues: Record | undefined, token?: string): Promise; + /** @internal */ + async execute( + placeholderValues: Record | undefined = {}, + token: string | undefined = this.authToken, + ): Promise { const params = fillPlaceholders(this.query.params, placeholderValues); this.logger.logQuery(this.query.sql, params); @@ -46,10 +53,28 @@ export class NeonHttpPreparedQuery extends PgPrep const { fields, client, query, customResultMapper } = this; if (!fields && !customResultMapper) { - return client(query.sql, params, rawQueryConfig); + return client( + query.sql, + params, + token === undefined + ? rawQueryConfig + : { + ...rawQueryConfig, + authToken: token, + }, + ); } - const result = await client(query.sql, params, queryConfig); + const result = await client( + query.sql, + params, + token === undefined + ? queryConfig + : { + ...queryConfig, + authToken: token, + }, + ); return this.mapResult(result); } @@ -71,13 +96,26 @@ export class NeonHttpPreparedQuery extends PgPrep all(placeholderValues: Record | undefined = {}): Promise { const params = fillPlaceholders(this.query.params, placeholderValues); this.logger.logQuery(this.query.sql, params); - return this.client(this.query.sql, params, rawQueryConfig).then((result) => result.rows); + return this.client( + this.query.sql, + params, + this.authToken === undefined ? rawQueryConfig : { + ...rawQueryConfig, + authToken: this.authToken, + }, + ).then((result) => result.rows); } - values(placeholderValues: Record | undefined = {}): Promise { + values(placeholderValues: Record | undefined): Promise; + /** @internal */ + values(placeholderValues: Record | undefined, token?: string): Promise; + /** @internal */ + values(placeholderValues: Record | undefined = {}, token?: string): Promise { const params = fillPlaceholders(this.query.params, placeholderValues); this.logger.logQuery(this.query.sql, params); - return this.client(this.query.sql, params, { arrayMode: true, fullResults: true }).then((result) => result.rows); + return this.client(this.query.sql, params, { arrayMode: true, fullResults: true, authToken: token }).then(( + result, + ) => result.rows); } /** @internal */ @@ -125,7 +163,9 @@ export class NeonHttpSession< ); } - async batch, T extends Readonly<[U, ...U[]]>>(queries: T) { + async batch, T extends Readonly<[U, ...U[]]>>( + queries: T, + ) { const preparedQueries: PreparedQuery[] = []; const builtQueries: NeonQueryPromise[] = []; @@ -143,7 +183,7 @@ export class NeonHttpSession< const batchResults = await this.client.transaction(builtQueries, queryConfig); - return batchResults.map((result, i) => preparedQueries[i]!.mapResult(result, true)); + return batchResults.map((result, i) => preparedQueries[i]!.mapResult(result, true)) as any; } // change return type to QueryRows @@ -161,8 +201,12 @@ export class NeonHttpSession< return this.client(query, params, { arrayMode: false, fullResults: true }); } - override async count(sql: SQL): Promise { - const res = await this.execute<{ rows: [{ count: string }] }>(sql); + override async count(sql: SQL): Promise; + /** @internal */ + override async count(sql: SQL, token?: string): Promise; + /** @internal */ + override async count(sql: SQL, token?: string): Promise { + const res = await this.execute<{ rows: [{ count: string }] }>(sql, token); return Number( res['rows'][0]['count'], diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index 362c15c86..e3c7e4444 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -597,6 +597,8 @@ export class PgDatabase< return new PgRefreshMaterializedView(view, this.session, this.dialect); } + protected authToken?: string; + execute = Record>( query: SQLWrapper | string, ): PgRaw> { @@ -611,7 +613,7 @@ export class PgDatabase< false, ); return new PgRaw( - () => prepared.execute(), + () => prepared.execute(undefined, this.authToken), sequel, builtQuery, (result) => prepared.mapResult(result, true), diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index af16fda01..e620c7428 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -7,6 +7,7 @@ export class PgCountBuilder< TSession extends PgSession, > extends SQL implements Promise, SQLWrapper { private sql: SQL; + private token?: string; static override readonly [entityKind] = 'PgCountBuilder'; [Symbol.toStringTag] = 'PgCountBuilder'; @@ -46,11 +47,16 @@ export class PgCountBuilder< ); } + /** @intrnal */ + setToken(token: string) { + this.token = token; + } + then( onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { - return Promise.resolve(this.session.count(this.sql)) + return Promise.resolve(this.session.count(this.sql, this.token)) .then( onfulfilled, onrejected, @@ -58,7 +64,7 @@ export class PgCountBuilder< } catch( - onRejected?: ((reason: any) => never | PromiseLike) | null | undefined, + onRejected?: ((reason: any) => any) | null | undefined, ): Promise { return this.then(undefined, onRejected); } diff --git a/drizzle-orm/src/pg-core/query-builders/delete.ts b/drizzle-orm/src/pg-core/query-builders/delete.ts index b42d46711..97bcdc044 100644 --- a/drizzle-orm/src/pg-core/query-builders/delete.ts +++ b/drizzle-orm/src/pg-core/query-builders/delete.ts @@ -232,9 +232,16 @@ export class PgDeleteBase< return this._prepare(name); } + private authToken?: string; + /** @internal */ + setToken(token: string) { + this.authToken = token; + return this; + } + override execute: ReturnType['execute'] = (placeholderValues) => { return tracer.startActiveSpan('drizzle.operation', () => { - return this._prepare().execute(placeholderValues); + return this._prepare().execute(placeholderValues, this.authToken); }); }; diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index b1a39fa05..18b972102 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -63,16 +63,16 @@ export class PgInsertBuilder< private overridingSystemValue_?: boolean, ) {} - overridingSystemValue(): Omit, 'overridingSystemValue'> { - this.overridingSystemValue_ = true; - return this as any; + private authToken?: string; + /** @internal */ + setToken(token: string) { + this.authToken = token; + return this; } - values(value: PgInsertValue): PgInsertBase; - values(values: PgInsertValue[]): PgInsertBase; - values( - values: PgInsertValue | PgInsertValue[], - ): PgInsertBase { + values(value: PgInsertValue): PgInsertBase; + values(values: PgInsertValue[]): PgInsertBase; + values(values: PgInsertValue | PgInsertValue[]): PgInsertBase { values = Array.isArray(values) ? values : [values]; if (values.length === 0) { throw new Error('values() must be called with at least one value'); @@ -87,15 +87,25 @@ export class PgInsertBuilder< return result; }); - return new PgInsertBase( - this.table, - mappedValues, - this.session, - this.dialect, - this.withList, - false, - this.overridingSystemValue_, - ); + return this.authToken === undefined + ? new PgInsertBase( + this.table, + mappedValues, + this.session, + this.dialect, + this.withList, + false, + this.overridingSystemValue_, + ) + : new PgInsertBase( + this.table, + mappedValues, + this.session, + this.dialect, + this.withList, + false, + this.overridingSystemValue_, + ).setToken(this.authToken) as any; } select(selectQuery: (qb: QueryBuilder) => PgInsertSelectQueryBuilder): PgInsertBase; @@ -385,9 +395,16 @@ export class PgInsertBase< return this._prepare(name); } + private authToken?: string; + /** @internal */ + setToken(token: string) { + this.authToken = token; + return this; + } + override execute: ReturnType['execute'] = (placeholderValues) => { return tracer.startActiveSpan('drizzle.operation', () => { - return this._prepare().execute(placeholderValues); + return this._prepare().execute(placeholderValues, this.authToken); }); }; diff --git a/drizzle-orm/src/pg-core/query-builders/query.ts b/drizzle-orm/src/pg-core/query-builders/query.ts index 07f485669..c664e761d 100644 --- a/drizzle-orm/src/pg-core/query-builders/query.ts +++ b/drizzle-orm/src/pg-core/query-builders/query.ts @@ -142,9 +142,16 @@ export class PgRelationalQuery extends QueryPromise return this._toSQL().builtQuery; } + private authToken?: string; + /** @internal */ + setToken(token: string) { + this.authToken = token; + return this; + } + override execute(): Promise { return tracer.startActiveSpan('drizzle.operation', () => { - return this._prepare().execute(); + return this._prepare().execute(undefined, this.authToken); }); } } diff --git a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts index 62ade9139..f171023da 100644 --- a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts +++ b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts @@ -92,9 +92,16 @@ export class PgRefreshMaterializedView return this._prepare(name); } + private authToken?: string; + /** @internal */ + setToken(token: string) { + this.authToken = token; + return this; + } + execute: ReturnType['execute'] = (placeholderValues) => { return tracer.startActiveSpan('drizzle.operation', () => { - return this._prepare().execute(placeholderValues); + return this._prepare().execute(placeholderValues, this.authToken); }); }; } diff --git a/drizzle-orm/src/pg-core/query-builders/select.ts b/drizzle-orm/src/pg-core/query-builders/select.ts index 0fbc85fa6..813a89bd1 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.ts @@ -81,6 +81,13 @@ export class PgSelectBuilder< this.distinct = config.distinct; } + private authToken?: string; + /** @internal */ + setToken(token: string) { + this.authToken = token; + return this; + } + /** * Specify the table, subquery, or other target that you're * building a select query against. @@ -115,15 +122,25 @@ export class PgSelectBuilder< fields = getTableColumns(source); } - return new PgSelectBase({ - table: source, - fields, - isPartialSelect, - session: this.session, - dialect: this.dialect, - withList: this.withList, - distinct: this.distinct, - }) as any; + return (this.authToken === undefined + ? new PgSelectBase({ + table: source, + fields, + isPartialSelect, + session: this.session, + dialect: this.dialect, + withList: this.withList, + distinct: this.distinct, + }) + : new PgSelectBase({ + table: source, + fields, + isPartialSelect, + session: this.session, + dialect: this.dialect, + withList: this.withList, + distinct: this.distinct, + }).setToken(this.authToken)) as any; } } @@ -951,7 +968,7 @@ export class PgSelectBase< /** @internal */ _prepare(name?: string): PgSelectPrepare { - const { session, config, dialect, joinsNotNullableMap } = this; + const { session, config, dialect, joinsNotNullableMap, authToken } = this; if (!session) { throw new Error('Cannot execute a query on a query builder. Please use a database instance instead.'); } @@ -961,7 +978,8 @@ export class PgSelectBase< PreparedQueryConfig & { execute: TResult } >(dialect.sqlToQuery(this.getSQL()), fieldsList, name, true); query.joinsNotNullableMap = joinsNotNullableMap; - return query; + + return authToken === undefined ? query : query.setToken(authToken); }); } @@ -976,9 +994,16 @@ export class PgSelectBase< return this._prepare(name); } + private authToken?: string; + /** @internal */ + setToken(token: string) { + this.authToken = token; + return this; + } + execute: ReturnType['execute'] = (placeholderValues) => { return tracer.startActiveSpan('drizzle.operation', () => { - return this._prepare().execute(placeholderValues); + return this._prepare().execute(placeholderValues, this.authToken); }); }; } diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index 12e076d97..a8810ed5a 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -64,16 +64,30 @@ export class PgUpdateBuilder, ): PgUpdateWithout, false, 'leftJoin' | 'rightJoin' | 'innerJoin' | 'fullJoin'> { - return new PgUpdateBase( - this.table, - mapUpdateSet(this.table, values), - this.session, - this.dialect, - this.withList, - ); + return this.authToken === undefined + ? new PgUpdateBase( + this.table, + mapUpdateSet(this.table, values), + this.session, + this.dialect, + this.withList, + ) + : new PgUpdateBase( + this.table, + mapUpdateSet(this.table, values), + this.session, + this.dialect, + this.withList, + ).setToken(this.authToken); } } @@ -534,8 +548,15 @@ export class PgUpdateBase< return this._prepare(name); } + private authToken?: string; + /** @internal */ + setToken(token: string) { + this.authToken = token; + return this; + } + override execute: ReturnType['execute'] = (placeholderValues) => { - return this._prepare().execute(placeholderValues); + return this._prepare().execute(placeholderValues, this.authToken); }; $dynamic(): PgUpdateDynamic { diff --git a/drizzle-orm/src/pg-core/session.ts b/drizzle-orm/src/pg-core/session.ts index d909e82db..8dff92f6b 100644 --- a/drizzle-orm/src/pg-core/session.ts +++ b/drizzle-orm/src/pg-core/session.ts @@ -17,6 +17,8 @@ export interface PreparedQueryConfig { export abstract class PgPreparedQuery implements PreparedQuery { constructor(protected query: Query) {} + protected authToken?: string; + getQuery(): Query { return this.query; } @@ -25,12 +27,22 @@ export abstract class PgPreparedQuery implements return response; } + /** @internal */ + setToken(token?: string) { + this.authToken = token; + return this; + } + static readonly [entityKind]: string = 'PgPreparedQuery'; /** @internal */ joinsNotNullableMap?: Record; abstract execute(placeholderValues?: Record): Promise; + /** @internal */ + abstract execute(placeholderValues?: Record, token?: string): Promise; + /** @internal */ + abstract execute(placeholderValues?: Record, token?: string): Promise; /** @internal */ abstract all(placeholderValues?: Record): Promise; @@ -62,7 +74,11 @@ export abstract class PgSession< customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => T['execute'], ): PgPreparedQuery; - execute(query: SQL): Promise { + execute(query: SQL): Promise; + /** @internal */ + execute(query: SQL, token?: string): Promise; + /** @internal */ + execute(query: SQL, token?: string): Promise { return tracer.startActiveSpan('drizzle.operation', () => { const prepared = tracer.startActiveSpan('drizzle.prepareQuery', () => { return this.prepareQuery( @@ -73,7 +89,7 @@ export abstract class PgSession< ); }); - return prepared.execute(); + return prepared.setToken(token).execute(undefined, token); }); } @@ -86,8 +102,12 @@ export abstract class PgSession< ).all(); } - async count(sql: SQL): Promise { - const res = await this.execute<[{ count: string }]>(sql); + async count(sql: SQL): Promise; + /** @internal */ + async count(sql: SQL, token?: string): Promise; + /** @internal */ + async count(sql: SQL, token?: string): Promise { + const res = await this.execute<[{ count: string }]>(sql, token); return Number( res[0]['count'], diff --git a/integration-tests/package.json b/integration-tests/package.json index 389001d8b..598f87adb 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -17,7 +17,7 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20241004.0", "@libsql/client": "^0.10.0", - "@neondatabase/serverless": "^0.9.0", + "@neondatabase/serverless": "0.10.0", "@originjs/vite-plugin-commonjs": "^1.0.3", "@paralleldrive/cuid2": "^2.2.2", "@types/async-retry": "^1.4.8", diff --git a/integration-tests/tests/pg/neon-http.test.ts b/integration-tests/tests/pg/neon-http.test.ts index 319c84f40..7cb433653 100644 --- a/integration-tests/tests/pg/neon-http.test.ts +++ b/integration-tests/tests/pg/neon-http.test.ts @@ -1,11 +1,11 @@ import { neon, type NeonQueryFunction } from '@neondatabase/serverless'; import retry from 'async-retry'; -import { sql } from 'drizzle-orm'; +import { eq, sql } from 'drizzle-orm'; import { drizzle, type NeonHttpDatabase } from 'drizzle-orm/neon-http'; import { migrate } from 'drizzle-orm/neon-http/migrator'; -import { pgTable, serial, timestamp } from 'drizzle-orm/pg-core'; +import { pgMaterializedView, pgTable, serial, timestamp } from 'drizzle-orm/pg-core'; import { Client } from 'pg'; -import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'; import { skipTests } from '~/common'; import { randomString } from '~/utils'; import { tests, usersMigratorTable, usersTable } from './pg-common'; @@ -443,7 +443,7 @@ beforeEach(async () => { create table users ( id serial primary key, name text not null, - verified boolean not null default false, + verified boolean not null default false, jsonb jsonb, created_at timestamptz not null default now() ) @@ -482,3 +482,107 @@ test('insert via db.execute w/ query builder', async () => { ); expect(inserted.rows).toEqual([{ id: 1, name: 'John' }]); }); + +describe('$withAuth tests', (it) => { + const client = vi.fn(); + const db = drizzle({ + client: client as any as NeonQueryFunction, + schema: { + usersTable, + }, + }); + + it('$count', async () => { + await db.$withAuth('$count').$count(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ arrayMode: false, fullResults: true, authToken: '$count' }); + }); + + it('delete', async () => { + await db.$withAuth('delete').delete(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ arrayMode: false, fullResults: true, authToken: 'delete' }); + }); + + it('select', async () => { + await db.$withAuth('select').select().from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ arrayMode: true, fullResults: true, authToken: 'select' }); + }); + + it('selectDistinct', async () => { + await db.$withAuth('selectDistinct').selectDistinct().from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ + arrayMode: true, + fullResults: true, + authToken: 'selectDistinct', + }); + }); + + it('selectDistinctOn', async () => { + await db.$withAuth('selectDistinctOn').selectDistinctOn([usersTable.name]).from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ + arrayMode: true, + fullResults: true, + authToken: 'selectDistinctOn', + }); + }); + + it('update', async () => { + await db.$withAuth('update').update(usersTable).set({ + name: 'CHANGED', + }).where(eq(usersTable.name, 'TARGET')).catch(() => null); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ arrayMode: false, fullResults: true, authToken: 'update' }); + }); + + it('insert', async () => { + await db.$withAuth('insert').insert(usersTable).values({ + name: 'WITHAUTHUSER', + }).catch(() => null); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ arrayMode: false, fullResults: true, authToken: 'insert' }); + }); + + it('with', async () => { + await db.$withAuth('with').with(db.$with('WITH').as((qb) => qb.select().from(usersTable))).select().from(usersTable) + .catch(() => null); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ arrayMode: true, fullResults: true, authToken: 'with' }); + }); + + it('rqb', async () => { + await db.$withAuth('rqb').query.usersTable.findFirst().catch(() => null); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ arrayMode: true, fullResults: true, authToken: 'rqb' }); + }); + + it('exec', async () => { + await db.$withAuth('exec').execute(`SELECT 1`).catch(() => null); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ arrayMode: false, fullResults: true, authToken: 'exec' }); + }); + + it('prepared', async () => { + const prep = db.$withAuth('prepared').select().from(usersTable).prepare('withAuthPrepared'); + + await prep.execute().catch(() => null); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ arrayMode: true, fullResults: true, authToken: 'prepared' }); + }); + + it('refreshMaterializedView', async () => { + const johns = pgMaterializedView('johns') + .as((qb) => qb.select().from(usersTable).where(eq(usersTable.name, 'John'))); + + await db.$withAuth('refreshMaterializedView').refreshMaterializedView(johns); + + expect(client.mock.lastCall?.[2]).toStrictEqual({ + arrayMode: false, + fullResults: true, + authToken: 'refreshMaterializedView', + }); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f13c32c4b..fb912db04 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,22 +13,22 @@ importers: version: 0.15.3 '@trivago/prettier-plugin-sort-imports': specifier: ^4.2.0 - version: 4.3.0(prettier@3.3.3) + version: 4.2.0(prettier@3.0.3) '@typescript-eslint/eslint-plugin': specifier: ^6.7.3 - version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) + version: 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/experimental-utils': specifier: ^5.62.0 - version: 5.62.0(eslint@8.57.1)(typescript@5.6.3) + version: 5.62.0(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^6.7.3 - version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) + version: 6.7.3(eslint@8.50.0)(typescript@5.6.3) bun-types: specifier: ^1.0.3 - version: 1.1.34 + version: 1.0.3 concurrently: specifier: ^8.2.1 - version: 8.2.2 + version: 8.2.1 dprint: specifier: ^0.46.2 version: 0.46.3 @@ -40,46 +40,46 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.687.0)(@cloudflare/workers-types@4.20241106.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.5)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.10)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.1.34)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.3.3)(pg@8.13.1)(postgres@3.4.5)(sql.js@1.12.0)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 - version: 8.57.1 + version: 8.50.0 eslint-plugin-drizzle-internal: specifier: link:eslint/eslint-plugin-drizzle-internal version: link:eslint/eslint-plugin-drizzle-internal eslint-plugin-import: specifier: ^2.28.1 - version: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1) + version: 2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0) eslint-plugin-no-instanceof: specifier: ^1.0.1 version: 1.0.1 eslint-plugin-unicorn: specifier: ^48.0.1 - version: 48.0.1(eslint@8.57.1) + version: 48.0.1(eslint@8.50.0) eslint-plugin-unused-imports: specifier: ^3.0.0 - version: 3.2.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1) + version: 3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0) glob: specifier: ^10.3.10 - version: 10.4.5 + version: 10.3.10 prettier: specifier: ^3.0.3 - version: 3.3.3 + version: 3.0.3 recast: specifier: ^0.23.9 version: 0.23.9 resolve-tspaths: specifier: ^0.8.16 - version: 0.8.22(typescript@5.6.3) + version: 0.8.16(typescript@5.6.3) tsup: specifier: ^7.2.0 - version: 7.3.0(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3) tsx: specifier: ^4.10.5 - version: 4.19.2 + version: 4.10.5 turbo: specifier: ^2.2.3 - version: 2.2.3 + version: 2.3.0 typescript: specifier: 5.6.3 version: 5.6.3 @@ -91,50 +91,50 @@ importers: version: 0.10.2 '@esbuild-kit/esm-loader': specifier: ^2.5.5 - version: 2.6.5 + version: 2.5.5 esbuild: specifier: ^0.19.7 version: 0.19.12 esbuild-register: specifier: ^3.5.0 - version: 3.6.0(esbuild@0.19.12) + version: 3.5.0(esbuild@0.19.12) devDependencies: '@arethetypeswrong/cli': specifier: ^0.15.3 version: 0.15.3 '@aws-sdk/client-rds-data': specifier: ^3.556.0 - version: 3.687.0 + version: 3.583.0 '@cloudflare/workers-types': specifier: ^4.20230518.0 - version: 4.20241106.0 + version: 4.20240524.0 '@electric-sql/pglite': specifier: ^0.2.12 version: 0.2.12 '@hono/node-server': specifier: ^1.9.0 - version: 1.13.5(hono@4.6.9) + version: 1.12.0 '@hono/zod-validator': specifier: ^0.2.1 - version: 0.2.2(hono@4.6.9)(zod@3.23.8) + version: 0.2.2(hono@4.5.0)(zod@3.23.7) '@libsql/client': specifier: ^0.10.0 version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': specifier: ^0.9.1 - version: 0.9.5 + version: 0.9.3 '@originjs/vite-plugin-commonjs': specifier: ^1.0.3 version: 1.0.3 '@planetscale/database': specifier: ^1.16.0 - version: 1.19.0 + version: 1.18.0 '@types/better-sqlite3': specifier: ^7.6.4 - version: 7.6.11 + version: 7.6.10 '@types/dockerode': specifier: ^3.3.28 - version: 3.3.31 + version: 3.3.29 '@types/glob': specifier: ^8.1.0 version: 8.1.0 @@ -149,10 +149,10 @@ importers: version: 5.1.2 '@types/node': specifier: ^18.11.15 - version: 18.19.64 + version: 18.19.33 '@types/pg': specifier: ^8.10.7 - version: 8.11.10 + version: 8.11.6 '@types/pluralize': specifier: ^0.0.33 version: 0.0.33 @@ -164,19 +164,19 @@ importers: version: 9.0.8 '@types/ws': specifier: ^8.5.10 - version: 8.5.13 + version: 8.5.11 '@typescript-eslint/eslint-plugin': specifier: ^7.2.0 - version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) + version: 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^7.2.0 - version: 7.18.0(eslint@8.57.1)(typescript@5.6.3) + version: 7.16.1(eslint@8.57.0)(typescript@5.6.3) '@vercel/postgres': specifier: ^0.8.0 version: 0.8.0 ava: specifier: ^5.1.0 - version: 5.3.1 + version: 5.3.0(@ava/typescript@5.0.0) better-sqlite3: specifier: ^9.4.3 version: 9.6.0 @@ -209,16 +209,16 @@ importers: version: 3.0.0 esbuild-node-externals: specifier: ^1.9.0 - version: 1.15.0(esbuild@0.19.12) + version: 1.14.0(esbuild@0.19.12) eslint: specifier: ^8.57.0 - version: 8.57.1 + version: 8.57.0 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@8.57.1) + version: 9.1.0(eslint@8.57.0) eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8) + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8) get-port: specifier: ^6.1.2 version: 6.1.2 @@ -230,7 +230,7 @@ importers: version: 0.0.5 hono: specifier: ^4.1.5 - version: 4.6.9 + version: 4.5.0 json-diff: specifier: 1.0.6 version: 1.0.6 @@ -251,25 +251,25 @@ importers: version: 17.1.0 pg: specifier: ^8.11.5 - version: 8.13.1 + version: 8.11.5 pluralize: specifier: ^8.0.0 version: 8.0.0 postgres: specifier: ^3.4.4 - version: 3.4.5 + version: 3.4.4 prettier: specifier: ^2.8.1 version: 2.8.8 semver: specifier: ^7.5.4 - version: 7.6.3 + version: 7.6.2 superjson: specifier: ^2.2.1 version: 2.2.1 tsup: specifier: ^8.0.2 - version: 8.3.5(postcss@8.4.47)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.6.0) + version: 8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.4.2) tsx: specifier: ^3.12.1 version: 3.14.0 @@ -281,31 +281,31 @@ importers: version: 9.0.1 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.4.0 - version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) wrangler: specifier: ^3.22.1 - version: 3.85.0(@cloudflare/workers-types@4.20241106.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3) + version: 3.65.0(@cloudflare/workers-types@4.20240524.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3) ws: specifier: ^8.16.0 - version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + version: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) zod: specifier: ^3.20.2 - version: 3.23.8 + version: 3.23.7 zx: specifier: ^7.2.2 - version: 7.2.3 + version: 7.2.2 drizzle-orm: devDependencies: '@aws-sdk/client-rds-data': specifier: ^3.549.0 - version: 3.687.0 + version: 3.583.0 '@cloudflare/workers-types': specifier: ^4.20230904.0 - version: 4.20241106.0 + version: 4.20240512.0 '@electric-sql/pglite': specifier: ^0.2.12 version: 0.2.12 @@ -319,20 +319,20 @@ importers: specifier: ^2.14.4 version: 2.14.4 '@neondatabase/serverless': - specifier: ^0.9.0 - version: 0.9.5 + specifier: ^0.10.0 + version: 0.10.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 - version: 1.9.0 + version: 1.8.0 '@originjs/vite-plugin-commonjs': specifier: ^1.0.3 version: 1.0.3 '@planetscale/database': specifier: ^1.16.0 - version: 1.19.0 + version: 1.18.0 '@prisma/client': specifier: 5.14.0 version: 5.14.0(prisma@5.14.0) @@ -341,16 +341,16 @@ importers: version: 0.1.1 '@types/better-sqlite3': specifier: ^7.6.4 - version: 7.6.11 + version: 7.6.10 '@types/node': specifier: ^20.2.5 - version: 20.17.6 + version: 20.12.12 '@types/pg': specifier: ^8.10.1 - version: 8.11.10 + version: 8.11.6 '@types/react': specifier: ^18.2.45 - version: 18.3.12 + version: 18.3.1 '@types/sql.js': specifier: ^1.4.4 version: 1.4.9 @@ -359,7 +359,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.5(typescript@5.6.3) + version: 0.29.4(typescript@5.6.3) better-sqlite3: specifier: ^8.4.0 version: 8.7.0 @@ -371,10 +371,10 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^14.0.0 - version: 14.0.6(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + version: 14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) knex: specifier: ^2.4.2 - version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7) + version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) kysely: specifier: ^0.25.0 version: 0.25.0 @@ -383,10 +383,10 @@ importers: version: 3.3.3 pg: specifier: ^8.11.0 - version: 8.13.1 + version: 8.11.5 postgres: specifier: ^3.3.5 - version: 3.4.5 + version: 3.4.4 prisma: specifier: 5.14.0 version: 5.14.0 @@ -395,28 +395,28 @@ importers: version: 18.3.1 sql.js: specifier: ^1.8.0 - version: 1.12.0 + version: 1.10.3 sqlite3: specifier: ^5.1.2 version: 5.1.7 tslib: specifier: ^2.5.2 - version: 2.8.1 + version: 2.6.2 tsx: specifier: ^3.12.7 version: 3.14.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) zod: specifier: ^3.20.2 - version: 3.23.8 + version: 3.23.7 zx: specifier: ^7.2.2 - version: 7.2.3 + version: 7.2.2 drizzle-seed: dependencies: @@ -432,22 +432,22 @@ importers: version: 0.2.12 '@rollup/plugin-terser': specifier: ^0.4.4 - version: 0.4.4(rollup@4.24.4) + version: 0.4.4(rollup@4.27.3) '@rollup/plugin-typescript': specifier: ^11.1.6 - version: 11.1.6(rollup@4.24.4)(tslib@2.8.1)(typescript@5.6.3) + version: 11.1.6(rollup@4.27.3)(tslib@2.8.1)(typescript@5.6.3) '@types/better-sqlite3': specifier: ^7.6.11 - version: 7.6.11 + version: 7.6.12 '@types/dockerode': specifier: ^3.3.31 - version: 3.3.31 + version: 3.3.32 '@types/node': specifier: ^22.5.4 - version: 22.9.0 + version: 22.9.1 '@types/pg': specifier: ^8.11.6 - version: 8.11.10 + version: 8.11.6 '@types/uuid': specifier: ^10.0.0 version: 10.0.0 @@ -483,7 +483,7 @@ importers: version: 0.8.22(typescript@5.6.3) rollup: specifier: ^4.21.2 - version: 4.24.4 + version: 4.27.3 tslib: specifier: ^2.7.0 version: 2.8.1 @@ -495,25 +495,25 @@ importers: version: 10.0.0 vitest: specifier: ^2.0.5 - version: 2.1.4(@types/node@22.9.0)(terser@5.36.0) + version: 2.1.2(@types/node@22.9.1)(lightningcss@1.25.1)(terser@5.31.0) zx: specifier: ^8.1.5 - version: 8.2.0 + version: 8.2.2 drizzle-typebox: devDependencies: '@rollup/plugin-terser': specifier: ^0.4.1 - version: 0.4.4(rollup@3.29.5) + version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.6(rollup@3.29.5)(tslib@2.8.1)(typescript@5.6.3) + version: 11.1.1(rollup@3.27.2)(tslib@2.8.1)(typescript@5.6.3) '@sinclair/typebox': specifier: ^0.29.6 version: 0.29.6 '@types/node': specifier: ^18.15.10 - version: 18.19.64 + version: 18.15.10 cpy: specifier: ^10.1.0 version: 10.1.0 @@ -522,31 +522,31 @@ importers: version: link:../drizzle-orm/dist rimraf: specifier: ^5.0.0 - version: 5.0.10 + version: 5.0.0 rollup: specifier: ^3.20.7 - version: 3.29.5 + version: 3.27.2 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) zx: specifier: ^7.2.2 - version: 7.2.3 + version: 7.2.2 drizzle-valibot: devDependencies: '@rollup/plugin-terser': specifier: ^0.4.1 - version: 0.4.4(rollup@3.29.5) + version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.6(rollup@3.29.5)(tslib@2.8.1)(typescript@5.6.3) + version: 11.1.1(rollup@3.27.2)(tslib@2.8.1)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 - version: 18.19.64 + version: 18.15.10 cpy: specifier: ^10.1.0 version: 10.1.0 @@ -555,34 +555,34 @@ importers: version: link:../drizzle-orm/dist rimraf: specifier: ^5.0.0 - version: 5.0.10 + version: 5.0.0 rollup: specifier: ^3.20.7 - version: 3.29.5 + version: 3.27.2 valibot: specifier: ^0.30.0 version: 0.30.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) zx: specifier: ^7.2.2 - version: 7.2.3 + version: 7.2.2 drizzle-zod: devDependencies: '@rollup/plugin-terser': specifier: ^0.4.1 - version: 0.4.4(rollup@3.29.5) + version: 0.4.1(rollup@3.20.7) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.6(rollup@3.29.5)(tslib@2.8.1)(typescript@5.6.3) + version: 11.1.0(rollup@3.20.7)(tslib@2.8.1)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 - version: 18.19.64 + version: 18.15.10 cpy: specifier: ^10.1.0 version: 10.1.0 @@ -591,58 +591,58 @@ importers: version: link:../drizzle-orm/dist rimraf: specifier: ^5.0.0 - version: 5.0.10 + version: 5.0.0 rollup: specifier: ^3.20.7 - version: 3.29.5 + version: 3.20.7 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) zod: specifier: ^3.20.2 - version: 3.23.8 + version: 3.21.4 zx: specifier: ^7.2.2 - version: 7.2.3 + version: 7.2.2 eslint-plugin-drizzle: devDependencies: '@types/node': specifier: ^20.10.1 - version: 20.17.6 + version: 20.10.1 '@typescript-eslint/parser': specifier: ^6.10.0 - version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) + version: 6.10.0(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/rule-tester': specifier: ^6.10.0 - version: 6.21.0(@eslint/eslintrc@2.1.4)(eslint@8.57.1)(typescript@5.6.3) + version: 6.10.0(@eslint/eslintrc@3.1.0)(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/utils': specifier: ^6.10.0 - version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) + version: 6.10.0(eslint@8.53.0)(typescript@5.2.2) cpy-cli: specifier: ^5.0.0 version: 5.0.0 eslint: specifier: ^8.53.0 - version: 8.57.1 + version: 8.53.0 typescript: specifier: ^5.2.2 - version: 5.6.3 + version: 5.2.2 vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@20.10.1)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) integration-tests: dependencies: '@aws-sdk/client-rds-data': specifier: ^3.549.0 - version: 3.687.0 + version: 3.583.0 '@aws-sdk/credential-providers': specifier: ^3.549.0 - version: 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)) + version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0) '@electric-sql/pglite': specifier: 0.2.12 version: 0.2.12 @@ -657,7 +657,7 @@ importers: version: 2.14.4 '@planetscale/database': specifier: ^1.16.0 - version: 1.19.0 + version: 1.18.0 '@prisma/client': specifier: 5.14.0 version: 5.14.0(prisma@5.14.0) @@ -672,7 +672,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.5(typescript@5.6.3) + version: 0.29.4(typescript@5.6.3) async-retry: specifier: ^1.3.3 version: 1.3.3 @@ -687,7 +687,7 @@ importers: version: 16.4.5 drizzle-prisma-generator: specifier: ^0.1.2 - version: 0.1.7 + version: 0.1.4 drizzle-seed: specifier: workspace:../drizzle-seed/dist version: link:../drizzle-seed/dist @@ -702,7 +702,7 @@ importers: version: link:../drizzle-zod/dist express: specifier: ^4.18.2 - version: 4.21.1 + version: 4.19.2 get-port: specifier: ^7.0.0 version: 7.1.0 @@ -711,10 +711,10 @@ importers: version: 3.3.3 pg: specifier: ^8.11.0 - version: 8.13.1 + version: 8.11.5 postgres: specifier: ^3.3.5 - version: 3.4.5 + version: 3.4.4 prisma: specifier: 5.14.0 version: 5.14.0 @@ -723,13 +723,13 @@ importers: version: 0.5.21 sql.js: specifier: ^1.8.0 - version: 1.12.0 + version: 1.10.3 sqlite3: specifier: ^5.1.4 version: 5.1.7 sst: specifier: ^3.0.4 - version: 3.3.5(hono@4.6.9)(valibot@0.30.0) + version: 3.0.14 uuid: specifier: ^9.0.0 version: 9.0.1 @@ -738,20 +738,20 @@ importers: version: 0.5.6 vitest: specifier: ^2.1.2 - version: 2.1.4(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) ws: specifier: ^8.16.0 version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) zod: specifier: ^3.20.2 - version: 3.23.8 + version: 3.23.7 devDependencies: '@cloudflare/workers-types': specifier: ^4.20241004.0 - version: 4.20241106.0 + version: 4.20241004.0 '@neondatabase/serverless': - specifier: ^0.9.0 - version: 0.9.5 + specifier: 0.10.0 + version: 0.10.0 '@originjs/vite-plugin-commonjs': specifier: ^1.0.3 version: 1.0.3 @@ -760,25 +760,25 @@ importers: version: 2.2.2 '@types/async-retry': specifier: ^1.4.8 - version: 1.4.9 + version: 1.4.8 '@types/axios': specifier: ^0.14.0 - version: 0.14.4 + version: 0.14.0 '@types/better-sqlite3': specifier: ^7.6.4 - version: 7.6.11 + version: 7.6.10 '@types/dockerode': specifier: ^3.3.18 - version: 3.3.31 + version: 3.3.29 '@types/express': specifier: ^4.17.16 version: 4.17.21 '@types/node': specifier: ^20.2.5 - version: 20.17.6 + version: 20.12.12 '@types/pg': specifier: ^8.10.1 - version: 8.11.10 + version: 8.11.6 '@types/sql.js': specifier: ^1.4.4 version: 1.4.9 @@ -787,37 +787,41 @@ importers: version: 9.0.8 '@types/ws': specifier: ^8.5.10 - version: 8.5.13 + version: 8.5.11 '@vitest/ui': specifier: ^1.6.0 - version: 1.6.0(vitest@2.1.4) + version: 1.6.0(vitest@2.1.2) ava: specifier: ^5.3.0 - version: 5.3.1 + version: 5.3.0(@ava/typescript@5.0.0) axios: specifier: ^1.4.0 - version: 1.7.7 + version: 1.6.8 cross-env: specifier: ^7.0.3 version: 7.0.3 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.17.6)(typescript@5.6.3) + version: 10.9.2(@types/node@20.12.12)(typescript@5.6.3) tsx: specifier: ^4.14.0 - version: 4.19.2 + version: 4.16.2 vite: specifier: ^5.2.13 - version: 5.4.10(@types/node@20.17.6)(terser@5.36.0) + version: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) zx: specifier: ^7.2.2 - version: 7.2.3 + version: 7.2.2 packages: + '@aashutoshrathi/word-wrap@1.2.6': + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -843,128 +847,317 @@ packages: resolution: {integrity: sha512-RI3HXgSuKTfcBf1hSEg1P9/cOvmI0flsMm6/QL3L3wju4AlHDqd55JFPfXs4pzgEAgy5L9pul4/HPPz99x2GvA==} engines: {node: '>=18'} - '@aws-crypto/sha256-browser@5.2.0': - resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + '@ava/typescript@5.0.0': + resolution: {integrity: sha512-2twsQz2fUd95QK1MtKuEnjkiN47SKHZfi/vWj040EN6Eo2ZW3SNcAwncJqXXoMTYZTWtBRXYp3Fg8z+JkFI9aQ==} + engines: {node: ^18.18 || ^20.8 || ^21 || ^22} + + '@aws-crypto/crc32@3.0.0': + resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==} + + '@aws-crypto/ie11-detection@3.0.0': + resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} + + '@aws-crypto/sha256-browser@3.0.0': + resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} + + '@aws-crypto/sha256-js@3.0.0': + resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} + + '@aws-crypto/supports-web-crypto@3.0.0': + resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} - '@aws-crypto/sha256-js@5.2.0': - resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + '@aws-crypto/util@3.0.0': + resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} + + '@aws-sdk/client-cognito-identity@3.569.0': + resolution: {integrity: sha512-cD1HcdJNpUZgrATWCAQs2amQKI69pG+jF4b5ySq9KJkVi6gv2PWsD6QGDG8H12lMWaIKYlOpKbpnYTpcuvqUcg==} engines: {node: '>=16.0.0'} - '@aws-crypto/supports-web-crypto@5.2.0': - resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + '@aws-sdk/client-lambda@3.478.0': + resolution: {integrity: sha512-7+PEE1aV3qVeuswL6cUBfHeljxC/WaXFj+214/W3q71uRdLbX5Z7ZOD15sJbjSu+4VZN9ugMaxEcp+oLiqWl+A==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/client-rds-data@3.583.0': + resolution: {integrity: sha512-xBnrVGNmMsTafzlaeZiFUahr3TP4zF2yRnsWzibylbXXIjaGdcLoiskNizo62syCh/8LbgpY6EN34EeYWsfMiw==} + engines: {node: '>=16.0.0'} - '@aws-crypto/util@5.2.0': - resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + '@aws-sdk/client-sso-oidc@3.569.0': + resolution: {integrity: sha512-u5DEjNEvRvlKKh1QLCDuQ8GIrx+OFvJFLfhorsp4oCxDylvORs+KfyKKnJAw4wYEEHyxyz9GzHD7p6a8+HLVHw==} + engines: {node: '>=16.0.0'} - '@aws-sdk/client-cognito-identity@3.687.0': - resolution: {integrity: sha512-jcQTioloSed+Jc3snjrgpWejkOm8t3Zt+jWrApw3ejN8qBtpFCH43M7q/CSDVZ9RS1IjX+KRWoBFnrDOnbuw0Q==} + '@aws-sdk/client-sso-oidc@3.583.0': + resolution: {integrity: sha512-LO3wmrFXPi2kNE46lD1XATfRrvdNxXd4DlTFouoWmr7lvqoUkcbmtkV2r/XChZA2z0HiDauphC1e8b8laJVeSg==} engines: {node: '>=16.0.0'} - '@aws-sdk/client-rds-data@3.687.0': - resolution: {integrity: sha512-/m+HcjbINf74SIoXjXM61GcWzFYtN6OdL1JIO+FTN8P8usMvOOD14B8QGLghp0XAWhdl7NKU8y8BmaXShEffIw==} + '@aws-sdk/client-sso@3.478.0': + resolution: {integrity: sha512-Jxy9cE1JMkPR0PklCpq3cORHnZq/Z4klhSTNGgZNeBWovMa+plor52kyh8iUNHKl3XEJvTbHM7V+dvrr/x0P1g==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/client-sso@3.568.0': + resolution: {integrity: sha512-LSD7k0ZBQNWouTN5dYpUkeestoQ+r5u6cp6o+FATKeiFQET85RNA3xJ4WPnOI5rBC1PETKhQXvF44863P3hCaQ==} engines: {node: '>=16.0.0'} - '@aws-sdk/client-sso-oidc@3.687.0': - resolution: {integrity: sha512-Rdd8kLeTeh+L5ZuG4WQnWgYgdv7NorytKdZsGjiag1D8Wv3PcJvPqqWdgnI0Og717BSXVoaTYaN34FyqFYSx6Q==} + '@aws-sdk/client-sso@3.583.0': + resolution: {integrity: sha512-FNJ2MmiBtZZwgkj4+GLVrzqwmD6D8FBptrFZk7PnGkSf7v1Q8txYNI6gY938RRhYJ4lBW4cNbhPvWoDxAl90Hw==} engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sts': ^3.687.0 - '@aws-sdk/client-sso@3.687.0': - resolution: {integrity: sha512-dfj0y9fQyX4kFill/ZG0BqBTLQILKlL7+O5M4F9xlsh2WNuV2St6WtcOg14Y1j5UODPJiJs//pO+mD1lihT5Kw==} + '@aws-sdk/client-sts@3.478.0': + resolution: {integrity: sha512-D+QID0dYzmn9dcxgKP3/nMndUqiQbDLsqI0Zf2pG4MW5gPhVNKlDGIV3Ztz8SkMjzGJExNOLW2L569o8jshJVw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/client-sts@3.569.0': + resolution: {integrity: sha512-3AyipQ2zHszkcTr8n1Sp7CiMUi28aMf1vOhEo0KKi0DWGo1Z1qJEpWeRP363KG0n9/8U3p1IkXGz5FRbpXZxIw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/client-sts@3.583.0': + resolution: {integrity: sha512-xDMxiemPDWr9dY2Q4AyixkRnk/hvS6fs6OWxuVCz1WO47YhaAfOsEGAgQMgDLLaOfj/oLU5D14uTNBEPGh4rBA==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/core@3.477.0': + resolution: {integrity: sha512-o0434EH+d1BxHZvgG7z8vph2SYefciQ5RnJw2MgvETGnthgqsnI4nnNJLSw0FVeqCeS18n6vRtzqlGYR2YPCNg==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/core@3.567.0': + resolution: {integrity: sha512-zUDEQhC7blOx6sxhHdT75x98+SXQVdUIMu8z8AjqMWiYK2v4WkOS8i6dOS4E5OjL5J1Ac+ruy8op/Bk4AFqSIw==} engines: {node: '>=16.0.0'} - '@aws-sdk/client-sts@3.687.0': - resolution: {integrity: sha512-SQjDH8O4XCTtouuCVYggB0cCCrIaTzUZIkgJUpOsIEJBLlTbNOb/BZqUShAQw2o9vxr2rCeOGjAQOYPysW/Pmg==} + '@aws-sdk/core@3.582.0': + resolution: {integrity: sha512-ofmD96IQc9g1dbyqlCyxu5fCG7kIl9p1NoN5+vGBUyLdbmPCV3Pdg99nRHYEJuv2MgGx5AUFGDPMHcqbJpnZIw==} engines: {node: '>=16.0.0'} - '@aws-sdk/core@3.686.0': - resolution: {integrity: sha512-Xt3DV4DnAT3v2WURwzTxWQK34Ew+iiLzoUoguvLaZrVMFOqMMrwVjP+sizqIaHp1j7rGmFcN5I8saXnsDLuQLA==} + '@aws-sdk/credential-provider-cognito-identity@3.569.0': + resolution: {integrity: sha512-CHS0Zyuazh5cYLaJr2/I9up0xAu8Y+um/h0o4xNf00cKGT0Sdhoby5vyelHjVTeZt+OeOMTBt6IdqGwVbVG9gQ==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-cognito-identity@3.687.0': - resolution: {integrity: sha512-hJq9ytoj2q/Jonc7mox/b0HT+j4NeMRuU184DkXRJbvIvwwB+oMt12221kThLezMhwIYfXEteZ7GEId7Hn8Y8g==} + '@aws-sdk/credential-provider-env@3.468.0': + resolution: {integrity: sha512-k/1WHd3KZn0EQYjadooj53FC0z24/e4dUZhbSKTULgmxyO62pwh9v3Brvw4WRa/8o2wTffU/jo54tf4vGuP/ZA==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-env@3.568.0': + resolution: {integrity: sha512-MVTQoZwPnP1Ev5A7LG+KzeU6sCB8BcGkZeDT1z1V5Wt7GPq0MgFQTSSjhImnB9jqRSZkl1079Bt3PbO6lfIS8g==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-env@3.577.0': + resolution: {integrity: sha512-Jxu255j0gToMGEiqufP8ZtKI8HW90lOLjwJ3LrdlD/NLsAY0tOQf1fWc53u28hWmmNGMxmCrL2p66IOgMDhDUw==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-env@3.686.0': - resolution: {integrity: sha512-osD7lPO8OREkgxPiTWmA1i6XEmOth1uW9HWWj/+A2YGCj1G/t2sHu931w4Qj9NWHYZtbTTXQYVRg+TErALV7nQ==} + '@aws-sdk/credential-provider-http@3.568.0': + resolution: {integrity: sha512-gL0NlyI2eW17hnCrh45hZV+qjtBquB+Bckiip9R6DIVRKqYcoILyiFhuOgf2bXeF23gVh6j18pvUvIoTaFWs5w==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-http@3.686.0': - resolution: {integrity: sha512-xyGAD/f3vR/wssUiZrNFWQWXZvI4zRm2wpHhoHA1cC2fbRMNFYtFn365yw6dU7l00ZLcdFB1H119AYIUZS7xbw==} + '@aws-sdk/credential-provider-http@3.582.0': + resolution: {integrity: sha512-kGOUKw5ryPkDIYB69PjK3SicVLTbWB06ouFN2W1EvqUJpkQGPAUGzYcomKtt3mJaCTf/1kfoaHwARAl6KKSP8Q==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-ini@3.478.0': + resolution: {integrity: sha512-SsrYEYUvTG9ZoPC+zB19AnVoOKID+QIEHJDIi1GCZXW5kTVyr1saTVm4orG2TjYvbHQMddsWtHOvGYXZWAYMbw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-ini@3.568.0': + resolution: {integrity: sha512-m5DUN9mpto5DhEvo6w3+8SS6q932ja37rTNvpPqWJIaWhj7OorAwVirSaJQAQB/M8+XCUIrUonxytphZB28qGQ==} engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.568.0 - '@aws-sdk/credential-provider-ini@3.687.0': - resolution: {integrity: sha512-6d5ZJeZch+ZosJccksN0PuXv7OSnYEmanGCnbhUqmUSz9uaVX6knZZfHCZJRgNcfSqg9QC0zsFA/51W5HCUqSQ==} + '@aws-sdk/credential-provider-ini@3.583.0': + resolution: {integrity: sha512-8I0oWNg/yps6ctjhEeL/qJ9BIa/+xXP7RPDQqFKZ2zBkWbmLLOoMWXRvl8uKUBD6qCe+DGmcu9skfVXeXSesEQ==} engines: {node: '>=16.0.0'} peerDependencies: - '@aws-sdk/client-sts': ^3.687.0 + '@aws-sdk/client-sts': ^3.583.0 + + '@aws-sdk/credential-provider-node@3.478.0': + resolution: {integrity: sha512-nwDutJYeHiIZCQDgKIUrsgwAWTil0mNe+cbd+j8fi+wwxkWUzip+F0+z02molJ8WrUUKNRhqB1V5aVx7IranuA==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-node@3.569.0': + resolution: {integrity: sha512-7jH4X2qlPU3PszZP1zvHJorhLARbU1tXvp8ngBe8ArXBrkFpl/dQ2Y/IRAICPm/pyC1IEt8L/CvKp+dz7v/eRw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-node@3.583.0': + resolution: {integrity: sha512-yBNypBXny7zJH85SzxDj8s1mbLXv9c/Vbq0qR3R3POj2idZ6ywB/qlIRC1XwBuv49Wvg8kA1wKXk3K3jrpcVIw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-process@3.468.0': + resolution: {integrity: sha512-OYSn1A/UsyPJ7Z8Q2cNhTf55O36shPmSsvOfND04nSfu1nPaR+VUvvsP7v+brhGpwC/GAKTIdGAo4blH31BS6A==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-process@3.568.0': + resolution: {integrity: sha512-r01zbXbanP17D+bQUb7mD8Iu2SuayrrYZ0Slgvx32qgz47msocV9EPCSwI4Hkw2ZtEPCeLQR4XCqFJB1D9P50w==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-process@3.577.0': + resolution: {integrity: sha512-Gin6BWtOiXxIgITrJ3Nwc+Y2P1uVT6huYR4EcbA/DJUPWyO0n9y5UFLewPvVbLkRn15JeEqErBLUrHclkiOKtw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-sso@3.478.0': + resolution: {integrity: sha512-LsDShG51X/q+s5ZFN7kHVqrd8ZHdyEyHqdhoocmRvvw2Dif50M0AqQfvCrW1ndj5CNzXO4x/eH8EK5ZOVlS6Sg==} + engines: {node: '>=14.0.0'} - '@aws-sdk/credential-provider-node@3.687.0': - resolution: {integrity: sha512-Pqld8Nx11NYaBUrVk3bYiGGpLCxkz8iTONlpQWoVWFhSOzlO7zloNOaYbD2XgFjjqhjlKzE91drs/f41uGeCTA==} + '@aws-sdk/credential-provider-sso@3.568.0': + resolution: {integrity: sha512-+TA77NWOEXMUcfLoOuim6xiyXFg1GqHj55ggI1goTKGVvdHYZ+rhxZbwjI29+ewzPt/qcItDJcvhrjOrg9lCag==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-process@3.686.0': - resolution: {integrity: sha512-sXqaAgyzMOc+dm4CnzAR5Q6S9OWVHyZjLfW6IQkmGjqeQXmZl24c4E82+w64C+CTkJrFLzH1VNOYp1Hy5gE6Qw==} + '@aws-sdk/credential-provider-sso@3.583.0': + resolution: {integrity: sha512-G/1EvL9tBezSiU+06tG4K/kOvFfPjnheT4JSXqjPM7+vjKzgp2jxp1J9MMd69zs4jVWon932zMeGgjrCplzMEg==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-sso@3.687.0': - resolution: {integrity: sha512-N1YCoE7DovIRF2ReyRrA4PZzF0WNi4ObPwdQQkVxhvSm7PwjbWxrfq7rpYB+6YB1Uq3QPzgVwUFONE36rdpxUQ==} + '@aws-sdk/credential-provider-web-identity@3.468.0': + resolution: {integrity: sha512-rexymPmXjtkwCPfhnUq3EjO1rSkf39R4Jz9CqiM7OsqK2qlT5Y/V3gnMKn0ZMXsYaQOMfM3cT5xly5R+OKDHlw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.568.0': + resolution: {integrity: sha512-ZJSmTmoIdg6WqAULjYzaJ3XcbgBzVy36lir6Y0UBMRGaxDgos1AARuX6EcYzXOl+ksLvxt/xMQ+3aYh1LWfKSw==} engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.568.0 - '@aws-sdk/credential-provider-web-identity@3.686.0': - resolution: {integrity: sha512-40UqCpPxyHCXDP7CGd9JIOZDgDZf+u1OyLaGBpjQJlz1HYuEsIWnnbTe29Yg3Ah/Zc3g4NBWcUdlGVotlnpnDg==} + '@aws-sdk/credential-provider-web-identity@3.577.0': + resolution: {integrity: sha512-ZGHGNRaCtJJmszb9UTnC7izNCtRUttdPlLdMkh41KPS32vfdrBDHs1JrpbZijItRj1xKuOXsiYSXLAaHGcLh8Q==} engines: {node: '>=16.0.0'} peerDependencies: - '@aws-sdk/client-sts': ^3.686.0 + '@aws-sdk/client-sts': ^3.577.0 + + '@aws-sdk/credential-providers@3.569.0': + resolution: {integrity: sha512-UL7EewaM1Xk6e4XLsxrCBv/owVSDI6Katnok6uMfqA8dA0x3ELjO7W35DW4wpWejQHErN5Gp1zloV9y3t34FMQ==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-host-header@3.468.0': + resolution: {integrity: sha512-gwQ+/QhX+lhof304r6zbZ/V5l5cjhGRxLL3CjH1uJPMcOAbw9wUlMdl+ibr8UwBZ5elfKFGiB1cdW/0uMchw0w==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-host-header@3.567.0': + resolution: {integrity: sha512-zQHHj2N3in9duKghH7AuRNrOMLnKhW6lnmb7dznou068DJtDr76w475sHp2TF0XELsOGENbbBsOlN/S5QBFBVQ==} + engines: {node: '>=16.0.0'} - '@aws-sdk/credential-providers@3.687.0': - resolution: {integrity: sha512-3aKlmKaOplpanOycmoigbTrQsqtxpzhpfquCey51aHf9GYp2yYyYF1YOgkXpE3qm3w6eiEN1asjJ2gqoECUuPA==} + '@aws-sdk/middleware-host-header@3.577.0': + resolution: {integrity: sha512-9ca5MJz455CODIVXs0/sWmJm7t3QO4EUa1zf8pE8grLpzf0J94bz/skDWm37Pli13T3WaAQBHCTiH2gUVfCsWg==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-host-header@3.686.0': - resolution: {integrity: sha512-+Yc6rO02z+yhFbHmRZGvEw1vmzf/ifS9a4aBjJGeVVU+ZxaUvnk+IUZWrj4YQopUQ+bSujmMUzJLXSkbDq7yuw==} + '@aws-sdk/middleware-logger@3.468.0': + resolution: {integrity: sha512-X5XHKV7DHRXI3f29SAhJPe/OxWRFgDWDMMCALfzhmJfCi6Jfh0M14cJKoC+nl+dk9lB+36+jKjhjETZaL2bPlA==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-logger@3.568.0': + resolution: {integrity: sha512-BinH72RG7K3DHHC1/tCulocFv+ZlQ9SrPF9zYT0T1OT95JXuHhB7fH8gEABrc6DAtOdJJh2fgxQjPy5tzPtsrA==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-logger@3.577.0': + resolution: {integrity: sha512-aPFGpGjTZcJYk+24bg7jT4XdIp42mFXSuPt49lw5KygefLyJM/sB0bKKqPYYivW0rcuZ9brQ58eZUNthrzYAvg==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.468.0': + resolution: {integrity: sha512-vch9IQib2Ng9ucSyRW2eKNQXHUPb5jUPCLA5otTW/8nGjcOU37LxQG4WrxO7uaJ9Oe8hjHO+hViE3P0KISUhtA==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.567.0': + resolution: {integrity: sha512-rFk3QhdT4IL6O/UWHmNdjJiURutBCy+ogGqaNHf/RELxgXH3KmYorLwCe0eFb5hq8f6vr3zl4/iH7YtsUOuo1w==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.577.0': + resolution: {integrity: sha512-pn3ZVEd2iobKJlR3H+bDilHjgRnNrQ6HMmK9ZzZw89Ckn3Dcbv48xOv4RJvu0aU8SDLl/SNCxppKjeLDTPGBNA==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-signing@3.468.0': + resolution: {integrity: sha512-s+7fSB1gdnnTj5O0aCCarX3z5Vppop8kazbNSZADdkfHIDWCN80IH4ZNjY3OWqaAz0HmR4LNNrovdR304ojb4Q==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-user-agent@3.478.0': + resolution: {integrity: sha512-Rec+nAPIzzwxgHPW+xqY6tooJGFOytpYg/xSRv8/IXl3xKGhmpMGs6gDWzmMBv/qy5nKTvLph/csNWJ98GWXCw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-user-agent@3.567.0': + resolution: {integrity: sha512-a7DBGMRBLWJU3BqrQjOtKS4/RcCh/BhhKqwjCE0FEhhm6A/GGuAs/DcBGOl6Y8Wfsby3vejSlppTLH/qtV1E9w==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-logger@3.686.0': - resolution: {integrity: sha512-cX43ODfA2+SPdX7VRxu6gXk4t4bdVJ9pkktbfnkE5t27OlwNfvSGGhnHrQL8xTOFeyQ+3T+oowf26gf1OI+vIg==} + '@aws-sdk/middleware-user-agent@3.583.0': + resolution: {integrity: sha512-xVNXXXDWvBVI/AeVtSdA9SVumqxiZaESk/JpUn9GMkmtTKfter0Cweap+1iQ9j8bRAO0vNhmIkbcvdB1S4WVUw==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-recursion-detection@3.686.0': - resolution: {integrity: sha512-jF9hQ162xLgp9zZ/3w5RUNhmwVnXDBlABEUX8jCgzaFpaa742qR/KKtjjZQ6jMbQnP+8fOCSXFAVNMU+s6v81w==} + '@aws-sdk/region-config-resolver@3.470.0': + resolution: {integrity: sha512-C1o1J06iIw8cyAAOvHqT4Bbqf+PgQ/RDlSyjt2gFfP2OovDpc2o2S90dE8f8iZdSGpg70N5MikT1DBhW9NbhtQ==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/region-config-resolver@3.567.0': + resolution: {integrity: sha512-VMDyYi5Dh2NydDiIARZ19DwMfbyq0llS736cp47qopmO6wzdeul7WRTx8NKfEYN0/AwEaqmTW0ohx58jSB1lYg==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-user-agent@3.687.0': - resolution: {integrity: sha512-nUgsKiEinyA50CaDXojAkOasAU3Apdg7Qox6IjNUC4ZjgOu7QWsCDB5N28AYMUt06cNYeYQdfMX1aEzG85a1Mg==} + '@aws-sdk/region-config-resolver@3.577.0': + resolution: {integrity: sha512-4ChCFACNwzqx/xjg3zgFcW8Ali6R9C95cFECKWT/7CUM1D0MGvkclSH2cLarmHCmJgU6onKkJroFtWp0kHhgyg==} engines: {node: '>=16.0.0'} - '@aws-sdk/region-config-resolver@3.686.0': - resolution: {integrity: sha512-6zXD3bSD8tcsMAVVwO1gO7rI1uy2fCD3czgawuPGPopeLiPpo6/3FoUWCQzk2nvEhj7p9Z4BbjwZGSlRkVrXTw==} + '@aws-sdk/token-providers@3.478.0': + resolution: {integrity: sha512-7b5tj1y/wGHZIZ+ckjOUKgKrMuCJMF/G1UKZKIqqdekeEsjcThbvoxAMeY0FEowu2ODVk/ggOmpBFxcu0iYd6A==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/token-providers@3.568.0': + resolution: {integrity: sha512-mCQElYzY5N2JlXB7LyjOoLvRN/JiSV+E9szLwhYN3dleTUCMbGqWb7RiAR2V3fO+mz8f9kR7DThTExKJbKogKw==} engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sso-oidc': ^3.568.0 - '@aws-sdk/token-providers@3.686.0': - resolution: {integrity: sha512-9oL4kTCSePFmyKPskibeiOXV6qavPZ63/kXM9Wh9V6dTSvBtLeNnMxqGvENGKJcTdIgtoqyqA6ET9u0PJ5IRIg==} + '@aws-sdk/token-providers@3.577.0': + resolution: {integrity: sha512-0CkIZpcC3DNQJQ1hDjm2bdSy/Xjs7Ny5YvSsacasGOkNfk+FdkiQy6N67bZX3Zbc9KIx+Nz4bu3iDeNSNplnnQ==} engines: {node: '>=16.0.0'} peerDependencies: - '@aws-sdk/client-sso-oidc': ^3.686.0 + '@aws-sdk/client-sso-oidc': ^3.577.0 + + '@aws-sdk/types@3.468.0': + resolution: {integrity: sha512-rx/9uHI4inRbp2tw3Y4Ih4PNZkVj32h7WneSg3MVgVjAoVD5Zti9KhS5hkvsBxfgmQmg0AQbE+b1sy5WGAgntA==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/types@3.567.0': + resolution: {integrity: sha512-JBznu45cdgQb8+T/Zab7WpBmfEAh77gsk99xuF4biIb2Sw1mdseONdoGDjEJX57a25TzIv/WUJ2oABWumckz1A==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/types@3.577.0': + resolution: {integrity: sha512-FT2JZES3wBKN/alfmhlo+3ZOq/XJ0C7QOZcDNrpKjB0kqYoKjhVKZ/Hx6ArR0czkKfHzBBEs6y40ebIHx2nSmA==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/util-endpoints@3.478.0': + resolution: {integrity: sha512-u9Mcg3euGJGs5clPt9mBuhBjHiEKiD0PnfvArhfq9i+dcY5mbCq/i1Dezp3iv1fZH9xxQt7hPXDfSpt1yUSM6g==} + engines: {node: '>=14.0.0'} - '@aws-sdk/types@3.686.0': - resolution: {integrity: sha512-xFnrb3wxOoJcW2Xrh63ZgFo5buIu9DF7bOHnwoUxHdNpUXicUh0AHw85TjXxyxIAd0d1psY/DU7QHoNI3OswgQ==} + '@aws-sdk/util-endpoints@3.567.0': + resolution: {integrity: sha512-WVhot3qmi0BKL9ZKnUqsvCd++4RF2DsJIG32NlRaml1FT9KaqSzNv0RXeA6k/kYwiiNT7y3YWu3Lbzy7c6vG9g==} engines: {node: '>=16.0.0'} - '@aws-sdk/util-endpoints@3.686.0': - resolution: {integrity: sha512-7msZE2oYl+6QYeeRBjlDgxQUhq/XRky3cXE0FqLFs2muLS7XSuQEXkpOXB3R782ygAP6JX0kmBxPTLurRTikZg==} + '@aws-sdk/util-endpoints@3.583.0': + resolution: {integrity: sha512-ZC9mb2jq6BFXPYsUsD2tmYcnlmd+9PGNwnFNn8jk4abna5Jjk2wDknN81ybktmBR5ttN9W8ugmktuKtvAMIDCQ==} engines: {node: '>=16.0.0'} - '@aws-sdk/util-locate-window@3.679.0': - resolution: {integrity: sha512-zKTd48/ZWrCplkXpYDABI74rQlbR0DNHs8nH95htfSLj9/mWRSwaGptoxwcihaq/77vi/fl2X3y0a1Bo8bt7RA==} + '@aws-sdk/util-locate-window@3.568.0': + resolution: {integrity: sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==} engines: {node: '>=16.0.0'} - '@aws-sdk/util-user-agent-browser@3.686.0': - resolution: {integrity: sha512-YiQXeGYZegF1b7B2GOR61orhgv79qmI0z7+Agm3NXLO6hGfVV3kFUJbXnjtH1BgWo5hbZYW7HQ2omGb3dnb6Lg==} + '@aws-sdk/util-user-agent-browser@3.468.0': + resolution: {integrity: sha512-OJyhWWsDEizR3L+dCgMXSUmaCywkiZ7HSbnQytbeKGwokIhD69HTiJcibF/sgcM5gk4k3Mq3puUhGnEZ46GIig==} + + '@aws-sdk/util-user-agent-browser@3.567.0': + resolution: {integrity: sha512-cqP0uXtZ7m7hRysf3fRyJwcY1jCgQTpJy7BHB5VpsE7DXlXHD5+Ur5L42CY7UrRPrB6lc6YGFqaAOs5ghMcLyA==} + + '@aws-sdk/util-user-agent-browser@3.577.0': + resolution: {integrity: sha512-zEAzHgR6HWpZOH7xFgeJLc6/CzMcx4nxeQolZxVZoB5pPaJd3CjyRhZN0xXeZB0XIRCWmb4yJBgyiugXLNMkLA==} + + '@aws-sdk/util-user-agent-node@3.470.0': + resolution: {integrity: sha512-QxsZ9iVHcBB/XRdYvwfM5AMvNp58HfqkIrH88mY0cmxuvtlIGDfWjczdDrZMJk9y0vIq+cuoCHsGXHu7PyiEAQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + + '@aws-sdk/util-user-agent-node@3.568.0': + resolution: {integrity: sha512-NVoZoLnKF+eXPBvXg+KqixgJkPSrerR6Gqmbjwqbv14Ini+0KNKB0/MXas1mDGvvEgtNkHI/Cb9zlJ3KXpti2A==} + engines: {node: '>=16.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true - '@aws-sdk/util-user-agent-node@3.687.0': - resolution: {integrity: sha512-idkP6ojSTZ4ek1pJ8wIN7r9U3KR5dn0IkJn3KQBXQ58LWjkRqLtft2vxzdsktWwhPKjjmIKl1S0kbvqLawf8XQ==} + '@aws-sdk/util-user-agent-node@3.577.0': + resolution: {integrity: sha512-XqvtFjbSMtycZTWVwDe8DRWovuoMbA54nhUoZwVU6rW9OSD6NZWGR512BUGHFaWzW0Wg8++Dj10FrKTG2XtqfA==} engines: {node: '>=16.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -972,52 +1165,60 @@ packages: aws-crt: optional: true + '@aws-sdk/util-utf8-browser@3.259.0': + resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + '@babel/code-frame@7.10.4': resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==} - '@babel/code-frame@7.26.2': - resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + '@babel/code-frame@7.22.10': + resolution: {integrity: sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==} + engines: {node: '>=6.9.0'} + + '@babel/code-frame@7.22.13': + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.26.2': - resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==} + '@babel/code-frame@7.24.6': + resolution: {integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==} engines: {node: '>=6.9.0'} - '@babel/core@7.26.0': - resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + '@babel/compat-data@7.24.6': + resolution: {integrity: sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.24.6': + resolution: {integrity: sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==} engines: {node: '>=6.9.0'} '@babel/generator@7.17.7': resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} engines: {node: '>=6.9.0'} - '@babel/generator@7.2.0': - resolution: {integrity: sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg==} - - '@babel/generator@7.26.2': - resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==} + '@babel/generator@7.24.6': + resolution: {integrity: sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.25.9': - resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} + '@babel/helper-annotate-as-pure@7.24.6': + resolution: {integrity: sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==} engines: {node: '>=6.9.0'} - '@babel/helper-builder-binary-assignment-operator-visitor@7.25.9': - resolution: {integrity: sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==} + '@babel/helper-builder-binary-assignment-operator-visitor@7.24.6': + resolution: {integrity: sha512-+wnfqc5uHiMYtvRX7qu80Toef8BXeh4HHR1SPeonGb1SKPniNEd4a/nlaJJMv/OIEYvIVavvo0yR7u10Gqz0Iw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.25.9': - resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} + '@babel/helper-compilation-targets@7.24.6': + resolution: {integrity: sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.25.9': - resolution: {integrity: sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==} + '@babel/helper-create-class-features-plugin@7.24.6': + resolution: {integrity: sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.25.9': - resolution: {integrity: sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==} + '@babel/helper-create-regexp-features-plugin@7.24.6': + resolution: {integrity: sha512-C875lFBIWWwyv6MHZUG9HmRrlTDgOsLWZfYR0nW69gaKJNe0/Mpxx5r0EID2ZdHQkdUmQo2t0uNckTL08/1BgA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1027,119 +1228,158 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - '@babel/helper-environment-visitor@7.24.7': - resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} + '@babel/helper-environment-visitor@7.22.5': + resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-environment-visitor@7.24.6': + resolution: {integrity: sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.22.5': + resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.24.6': + resolution: {integrity: sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==} engines: {node: '>=6.9.0'} - '@babel/helper-function-name@7.24.7': - resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} + '@babel/helper-hoist-variables@7.22.5': + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} - '@babel/helper-hoist-variables@7.24.7': - resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} + '@babel/helper-hoist-variables@7.24.6': + resolution: {integrity: sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.25.9': - resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} + '@babel/helper-member-expression-to-functions@7.24.6': + resolution: {integrity: sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.25.9': - resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + '@babel/helper-module-imports@7.24.6': + resolution: {integrity: sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.26.0': - resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + '@babel/helper-module-transforms@7.24.6': + resolution: {integrity: sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-optimise-call-expression@7.25.9': - resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} + '@babel/helper-optimise-call-expression@7.24.6': + resolution: {integrity: sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.25.9': - resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} + '@babel/helper-plugin-utils@7.24.6': + resolution: {integrity: sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==} engines: {node: '>=6.9.0'} - '@babel/helper-remap-async-to-generator@7.25.9': - resolution: {integrity: sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==} + '@babel/helper-remap-async-to-generator@7.24.6': + resolution: {integrity: sha512-1Qursq9ArRZPAMOZf/nuzVW8HgJLkTB9y9LfP4lW2MVp4e9WkLJDovfKBxoDcCk6VuzIxyqWHyBoaCtSRP10yg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-replace-supers@7.25.9': - resolution: {integrity: sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==} + '@babel/helper-replace-supers@7.24.6': + resolution: {integrity: sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-simple-access@7.25.9': - resolution: {integrity: sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==} + '@babel/helper-simple-access@7.24.6': + resolution: {integrity: sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-skip-transparent-expression-wrappers@7.24.6': + resolution: {integrity: sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-split-export-declaration@7.22.6': + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-split-export-declaration@7.24.6': + resolution: {integrity: sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.22.5': + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.23.4': + resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.24.6': + resolution: {integrity: sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.22.20': + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} - '@babel/helper-skip-transparent-expression-wrappers@7.25.9': - resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} + '@babel/helper-validator-identifier@7.22.5': + resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} engines: {node: '>=6.9.0'} - '@babel/helper-split-export-declaration@7.24.7': - resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} + '@babel/helper-validator-identifier@7.24.6': + resolution: {integrity: sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.25.9': - resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + '@babel/helper-validator-option@7.24.6': + resolution: {integrity: sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.25.9': - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + '@babel/helper-wrap-function@7.24.6': + resolution: {integrity: sha512-f1JLrlw/jbiNfxvdrfBgio/gRBk3yTAEJWirpAkiJG2Hb22E7cEYKHWo0dFPTv/niPovzIdPdEDetrv6tC6gPQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.25.9': - resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + '@babel/helpers@7.24.6': + resolution: {integrity: sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.25.9': - resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==} + '@babel/highlight@7.22.10': + resolution: {integrity: sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.26.0': - resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + '@babel/highlight@7.22.20': + resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.25.9': - resolution: {integrity: sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==} + '@babel/highlight@7.24.6': + resolution: {integrity: sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==} engines: {node: '>=6.9.0'} - '@babel/parser@7.26.2': - resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==} + '@babel/parser@7.22.10': + resolution: {integrity: sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9': - resolution: {integrity: sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@babel/parser@7.24.6': + resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==} + engines: {node: '>=6.0.0'} + hasBin: true - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9': - resolution: {integrity: sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==} + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.6': + resolution: {integrity: sha512-bYndrJ6Ph6Ar+GaB5VAc0JPoP80bQCm4qon6JEzXfRl5QZyQ8Ur1K6k7htxWmPA5z+k7JQvaMUrtXlqclWYzKw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9': - resolution: {integrity: sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==} + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.6': + resolution: {integrity: sha512-iVuhb6poq5ikqRq2XWU6OQ+R5o9wF+r/or9CeUyovgptz0UlnK4/seOQ1Istu/XybYjAhQv1FRSSfHHufIku5Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9': - resolution: {integrity: sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==} + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.6': + resolution: {integrity: sha512-c8TER5xMDYzzFcGqOEp9l4hvB7dcbhcGjcLVwxWfe4P5DOafdwjsBJZKsmv+o3aXh7NhopvayQIovHrh2zSRUQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9': - resolution: {integrity: sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==} + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.6': + resolution: {integrity: sha512-z8zEjYmwBUHN/pCF3NuWBhHQjJCrd33qAi8MgANfMrAvn72k2cImT8VjK9LJFu4ysOLJqhfkYYb3MvwANRUNZQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1158,14 +1398,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-proposal-decorators@7.25.9': - resolution: {integrity: sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==} + '@babel/plugin-proposal-decorators@7.24.6': + resolution: {integrity: sha512-8DjR0/DzlBhz2SVi9a19/N2U5+C3y3rseXuyoKL9SP8vnbewscj1eHZtL6kpEn4UCuUmqEo0mvqyDYRFoN2gpA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-proposal-export-default-from@7.25.9': - resolution: {integrity: sha512-ykqgwNfSnNOB+C8fV5X4mG3AVmvu+WVxcaU9xHHtBb7PCrPeweMmPjGsn8eMaeJg6SJuoUuZENeeSWaarWqonQ==} + '@babel/plugin-proposal-export-default-from@7.24.6': + resolution: {integrity: sha512-qPPDbYs9j5IArMFqYi85QxatHURSzRyskKpIbjrVoVglDuGdhu1s7UTCmXvP/qR2aHa3EdJ8X3iZvQAHjmdHUw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1223,11 +1463,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-bigint@7.8.3': - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-class-properties@7.12.13': resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: @@ -1239,8 +1474,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-decorators@7.25.9': - resolution: {integrity: sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==} + '@babel/plugin-syntax-decorators@7.24.6': + resolution: {integrity: sha512-gInH8LEqBp+wkwTVihCd/qf+4s28g81FZyvlIbAurHk9eSiItEKG7E0uNK2UdpgsD79aJVAW3R3c85h0YJ0jsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1250,26 +1485,31 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-export-default-from@7.25.9': - resolution: {integrity: sha512-9MhJ/SMTsVqsd69GyQg89lYR4o9T+oDGv5F6IsigxxqFVOyR/IflDLYP8WDI1l8fkhNGGktqkvL5qwNCtGEpgQ==} + '@babel/plugin-syntax-export-default-from@7.24.6': + resolution: {integrity: sha512-Nzl7kZ4tjOM2LJpejBMPwZs7OJfc26++2HsMQuSrw6gxpqXGtZZ3Rj4Zt4Qm7vulMZL2gHIGGc2stnlQnHQCqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-flow@7.26.0': - resolution: {integrity: sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==} + '@babel/plugin-syntax-export-namespace-from@7.8.3': + resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-flow@7.24.6': + resolution: {integrity: sha512-gNkksSdV8RbsCoHF9sjVYrHfYACMl/8U32UfUhJ9+84/ASXw8dlx+eHyyF0m6ncQJ9IBSxfuCkB36GJqYdXTOA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.26.0': - resolution: {integrity: sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==} + '@babel/plugin-syntax-import-assertions@7.24.6': + resolution: {integrity: sha512-BE6o2BogJKJImTmGpkmOic4V0hlRRxVtzqxiSPa8TIFxyhi4EFjHm08nq1M4STK4RytuLMgnSz0/wfflvGFNOg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.26.0': - resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} + '@babel/plugin-syntax-import-attributes@7.24.6': + resolution: {integrity: sha512-D+CfsVZousPXIdudSII7RGy52+dYRtbyKAZcvtQKq/NpsivyMVduepzcLqG5pMBugtMdedxdC8Ramdpcne9ZWQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1284,8 +1524,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.25.9': - resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + '@babel/plugin-syntax-jsx@7.24.6': + resolution: {integrity: sha512-lWfvAIFNWMlCsU0DRUun2GpFwZdGTukLaHJqRh1JRb80NdAP5Sb1HDHB5X9P9OtgZHQl089UzQkpYlBq2VTPRw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1332,8 +1572,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.25.9': - resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + '@babel/plugin-syntax-typescript@7.24.6': + resolution: {integrity: sha512-TzCtxGgVTEJWWwcYwQhCIQ6WaKlo80/B+Onsk4RRCcYqpYGFcG9etPW94VToGte5AAcxRrhjPUFvUS3Y2qKi4A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1344,368 +1584,356 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-arrow-functions@7.25.9': - resolution: {integrity: sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==} + '@babel/plugin-transform-arrow-functions@7.24.6': + resolution: {integrity: sha512-jSSSDt4ZidNMggcLx8SaKsbGNEfIl0PHx/4mFEulorE7bpYLbN0d3pDW3eJ7Y5Z3yPhy3L3NaPCYyTUY7TuugQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-generator-functions@7.25.9': - resolution: {integrity: sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==} + '@babel/plugin-transform-async-generator-functions@7.24.6': + resolution: {integrity: sha512-VEP2o4iR2DqQU6KPgizTW2mnMx6BG5b5O9iQdrW9HesLkv8GIA8x2daXBQxw1MrsIkFQGA/iJ204CKoQ8UcnAA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-to-generator@7.25.9': - resolution: {integrity: sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==} + '@babel/plugin-transform-async-to-generator@7.24.6': + resolution: {integrity: sha512-NTBA2SioI3OsHeIn6sQmhvXleSl9T70YY/hostQLveWs0ic+qvbA3fa0kwAwQ0OA/XGaAerNZRQGJyRfhbJK4g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoped-functions@7.25.9': - resolution: {integrity: sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==} + '@babel/plugin-transform-block-scoped-functions@7.24.6': + resolution: {integrity: sha512-XNW7jolYHW9CwORrZgA/97tL/k05qe/HL0z/qqJq1mdWhwwCM6D4BJBV7wAz9HgFziN5dTOG31znkVIzwxv+vw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.25.9': - resolution: {integrity: sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==} + '@babel/plugin-transform-block-scoping@7.24.6': + resolution: {integrity: sha512-S/t1Xh4ehW7sGA7c1j/hiOBLnEYCp/c2sEG4ZkL8kI1xX9tW2pqJTCHKtdhe/jHKt8nG0pFCrDHUXd4DvjHS9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-properties@7.25.9': - resolution: {integrity: sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==} + '@babel/plugin-transform-class-properties@7.24.6': + resolution: {integrity: sha512-j6dZ0Z2Z2slWLR3kt9aOmSIrBvnntWjMDN/TVcMPxhXMLmJVqX605CBRlcGI4b32GMbfifTEsdEjGjiE+j/c3A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-static-block@7.26.0': - resolution: {integrity: sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==} + '@babel/plugin-transform-class-static-block@7.24.6': + resolution: {integrity: sha512-1QSRfoPI9RoLRa8Mnakc6v3e0gJxiZQTYrMfLn+mD0sz5+ndSzwymp2hDcYJTyT0MOn0yuWzj8phlIvO72gTHA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 - '@babel/plugin-transform-classes@7.25.9': - resolution: {integrity: sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==} + '@babel/plugin-transform-classes@7.24.6': + resolution: {integrity: sha512-+fN+NO2gh8JtRmDSOB6gaCVo36ha8kfCW1nMq2Gc0DABln0VcHN4PrALDvF5/diLzIRKptC7z/d7Lp64zk92Fg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-computed-properties@7.25.9': - resolution: {integrity: sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==} + '@babel/plugin-transform-computed-properties@7.24.6': + resolution: {integrity: sha512-cRzPobcfRP0ZtuIEkA8QzghoUpSB3X3qSH5W2+FzG+VjWbJXExtx0nbRqwumdBN1x/ot2SlTNQLfBCnPdzp6kg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.25.9': - resolution: {integrity: sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==} + '@babel/plugin-transform-destructuring@7.24.6': + resolution: {integrity: sha512-YLW6AE5LQpk5npNXL7i/O+U9CE4XsBCuRPgyjl1EICZYKmcitV+ayuuUGMJm2lC1WWjXYszeTnIxF/dq/GhIZQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dotall-regex@7.25.9': - resolution: {integrity: sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==} + '@babel/plugin-transform-dotall-regex@7.24.6': + resolution: {integrity: sha512-rCXPnSEKvkm/EjzOtLoGvKseK+dS4kZwx1HexO3BtRtgL0fQ34awHn34aeSHuXtZY2F8a1X8xqBBPRtOxDVmcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-keys@7.25.9': - resolution: {integrity: sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==} + '@babel/plugin-transform-duplicate-keys@7.24.6': + resolution: {integrity: sha512-/8Odwp/aVkZwPFJMllSbawhDAO3UJi65foB00HYnK/uXvvCPm0TAXSByjz1mpRmp0q6oX2SIxpkUOpPFHk7FLA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9': - resolution: {integrity: sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-dynamic-import@7.25.9': - resolution: {integrity: sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==} + '@babel/plugin-transform-dynamic-import@7.24.6': + resolution: {integrity: sha512-vpq8SSLRTBLOHUZHSnBqVo0AKX3PBaoPs2vVzYVWslXDTDIpwAcCDtfhUcHSQQoYoUvcFPTdC8TZYXu9ZnLT/w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.25.9': - resolution: {integrity: sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==} + '@babel/plugin-transform-exponentiation-operator@7.24.6': + resolution: {integrity: sha512-EemYpHtmz0lHE7hxxxYEuTYOOBZ43WkDgZ4arQ4r+VX9QHuNZC+WH3wUWmRNvR8ECpTRne29aZV6XO22qpOtdA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-export-namespace-from@7.25.9': - resolution: {integrity: sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==} + '@babel/plugin-transform-export-namespace-from@7.24.6': + resolution: {integrity: sha512-inXaTM1SVrIxCkIJ5gqWiozHfFMStuGbGJAxZFBoHcRRdDP0ySLb3jH6JOwmfiinPwyMZqMBX+7NBDCO4z0NSA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-flow-strip-types@7.25.9': - resolution: {integrity: sha512-/VVukELzPDdci7UUsWQaSkhgnjIWXnIyRpM02ldxaVoFK96c41So8JcKT3m0gYjyv7j5FNPGS5vfELrWalkbDA==} + '@babel/plugin-transform-flow-strip-types@7.24.6': + resolution: {integrity: sha512-1l8b24NoCpaQ13Vi6FtLG1nv6kNoi8PWvQb1AYO7GHZDpFfBYc3lbXArx1lP2KRt8b4pej1eWc/zrRmsQTfOdQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-for-of@7.25.9': - resolution: {integrity: sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==} + '@babel/plugin-transform-for-of@7.24.6': + resolution: {integrity: sha512-n3Sf72TnqK4nw/jziSqEl1qaWPbCRw2CziHH+jdRYvw4J6yeCzsj4jdw8hIntOEeDGTmHVe2w4MVL44PN0GMzg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-function-name@7.25.9': - resolution: {integrity: sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==} + '@babel/plugin-transform-function-name@7.24.6': + resolution: {integrity: sha512-sOajCu6V0P1KPljWHKiDq6ymgqB+vfo3isUS4McqW1DZtvSVU2v/wuMhmRmkg3sFoq6GMaUUf8W4WtoSLkOV/Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-json-strings@7.25.9': - resolution: {integrity: sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==} + '@babel/plugin-transform-json-strings@7.24.6': + resolution: {integrity: sha512-Uvgd9p2gUnzYJxVdBLcU0KurF8aVhkmVyMKW4MIY1/BByvs3EBpv45q01o7pRTVmTvtQq5zDlytP3dcUgm7v9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-literals@7.25.9': - resolution: {integrity: sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==} + '@babel/plugin-transform-literals@7.24.6': + resolution: {integrity: sha512-f2wHfR2HF6yMj+y+/y07+SLqnOSwRp8KYLpQKOzS58XLVlULhXbiYcygfXQxJlMbhII9+yXDwOUFLf60/TL5tw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.25.9': - resolution: {integrity: sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==} + '@babel/plugin-transform-logical-assignment-operators@7.24.6': + resolution: {integrity: sha512-EKaWvnezBCMkRIHxMJSIIylzhqK09YpiJtDbr2wsXTwnO0TxyjMUkaw4RlFIZMIS0iDj0KyIg7H7XCguHu/YDA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-member-expression-literals@7.25.9': - resolution: {integrity: sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==} + '@babel/plugin-transform-member-expression-literals@7.24.6': + resolution: {integrity: sha512-9g8iV146szUo5GWgXpRbq/GALTnY+WnNuRTuRHWWFfWGbP9ukRL0aO/jpu9dmOPikclkxnNsjY8/gsWl6bmZJQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-amd@7.25.9': - resolution: {integrity: sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==} + '@babel/plugin-transform-modules-amd@7.24.6': + resolution: {integrity: sha512-eAGogjZgcwqAxhyFgqghvoHRr+EYRQPFjUXrTYKBRb5qPnAVxOOglaxc4/byHqjvq/bqO2F3/CGwTHsgKJYHhQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-commonjs@7.25.9': - resolution: {integrity: sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==} + '@babel/plugin-transform-modules-commonjs@7.24.6': + resolution: {integrity: sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.25.9': - resolution: {integrity: sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==} + '@babel/plugin-transform-modules-systemjs@7.24.6': + resolution: {integrity: sha512-xg1Z0J5JVYxtpX954XqaaAT6NpAY6LtZXvYFCJmGFJWwtlz2EmJoR8LycFRGNE8dBKizGWkGQZGegtkV8y8s+w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-umd@7.25.9': - resolution: {integrity: sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==} + '@babel/plugin-transform-modules-umd@7.24.6': + resolution: {integrity: sha512-esRCC/KsSEUvrSjv5rFYnjZI6qv4R1e/iHQrqwbZIoRJqk7xCvEUiN7L1XrmW5QSmQe3n1XD88wbgDTWLbVSyg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-named-capturing-groups-regex@7.25.9': - resolution: {integrity: sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==} + '@babel/plugin-transform-named-capturing-groups-regex@7.24.6': + resolution: {integrity: sha512-6DneiCiu91wm3YiNIGDWZsl6GfTTbspuj/toTEqLh9d4cx50UIzSdg+T96p8DuT7aJOBRhFyaE9ZvTHkXrXr6Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-new-target@7.25.9': - resolution: {integrity: sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==} + '@babel/plugin-transform-new-target@7.24.6': + resolution: {integrity: sha512-f8liz9JG2Va8A4J5ZBuaSdwfPqN6axfWRK+y66fjKYbwf9VBLuq4WxtinhJhvp1w6lamKUwLG0slK2RxqFgvHA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-nullish-coalescing-operator@7.25.9': - resolution: {integrity: sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==} + '@babel/plugin-transform-nullish-coalescing-operator@7.24.6': + resolution: {integrity: sha512-+QlAiZBMsBK5NqrBWFXCYeXyiU1y7BQ/OYaiPAcQJMomn5Tyg+r5WuVtyEuvTbpV7L25ZSLfE+2E9ywj4FD48A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-numeric-separator@7.25.9': - resolution: {integrity: sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==} + '@babel/plugin-transform-numeric-separator@7.24.6': + resolution: {integrity: sha512-6voawq8T25Jvvnc4/rXcWZQKKxUNZcKMS8ZNrjxQqoRFernJJKjE3s18Qo6VFaatG5aiX5JV1oPD7DbJhn0a4Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-rest-spread@7.25.9': - resolution: {integrity: sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==} + '@babel/plugin-transform-object-rest-spread@7.24.6': + resolution: {integrity: sha512-OKmi5wiMoRW5Smttne7BwHM8s/fb5JFs+bVGNSeHWzwZkWXWValR1M30jyXo1s/RaqgwwhEC62u4rFH/FBcBPg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-super@7.25.9': - resolution: {integrity: sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==} + '@babel/plugin-transform-object-super@7.24.6': + resolution: {integrity: sha512-N/C76ihFKlZgKfdkEYKtaRUtXZAgK7sOY4h2qrbVbVTXPrKGIi8aww5WGe/+Wmg8onn8sr2ut6FXlsbu/j6JHg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-catch-binding@7.25.9': - resolution: {integrity: sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==} + '@babel/plugin-transform-optional-catch-binding@7.24.6': + resolution: {integrity: sha512-L5pZ+b3O1mSzJ71HmxSCmTVd03VOT2GXOigug6vDYJzE5awLI7P1g0wFcdmGuwSDSrQ0L2rDOe/hHws8J1rv3w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.25.9': - resolution: {integrity: sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==} + '@babel/plugin-transform-optional-chaining@7.24.6': + resolution: {integrity: sha512-cHbqF6l1QP11OkYTYQ+hhVx1E017O5ZcSPXk9oODpqhcAD1htsWG2NpHrrhthEO2qZomLK0FXS+u7NfrkF5aOQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-parameters@7.25.9': - resolution: {integrity: sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==} + '@babel/plugin-transform-parameters@7.24.6': + resolution: {integrity: sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-methods@7.25.9': - resolution: {integrity: sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==} + '@babel/plugin-transform-private-methods@7.24.6': + resolution: {integrity: sha512-T9LtDI0BgwXOzyXrvgLTT8DFjCC/XgWLjflczTLXyvxbnSR/gpv0hbmzlHE/kmh9nOvlygbamLKRo6Op4yB6aw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-property-in-object@7.25.9': - resolution: {integrity: sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==} + '@babel/plugin-transform-private-property-in-object@7.24.6': + resolution: {integrity: sha512-Qu/ypFxCY5NkAnEhCF86Mvg3NSabKsh/TPpBVswEdkGl7+FbsYHy1ziRqJpwGH4thBdQHh8zx+z7vMYmcJ7iaQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-property-literals@7.25.9': - resolution: {integrity: sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==} + '@babel/plugin-transform-property-literals@7.24.6': + resolution: {integrity: sha512-oARaglxhRsN18OYsnPTpb8TcKQWDYNsPNmTnx5++WOAsUJ0cSC/FZVlIJCKvPbU4yn/UXsS0551CFKJhN0CaMw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-display-name@7.25.9': - resolution: {integrity: sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==} + '@babel/plugin-transform-react-display-name@7.24.6': + resolution: {integrity: sha512-/3iiEEHDsJuj9QU09gbyWGSUxDboFcD7Nj6dnHIlboWSodxXAoaY/zlNMHeYAC0WsERMqgO9a7UaM77CsYgWcg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-development@7.25.9': - resolution: {integrity: sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==} + '@babel/plugin-transform-react-jsx-development@7.24.6': + resolution: {integrity: sha512-F7EsNp5StNDouSSdYyDSxh4J+xvj/JqG+Cb6s2fA+jCyHOzigG5vTwgH8tU2U8Voyiu5zCG9bAK49wTr/wPH0w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-self@7.25.9': - resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} + '@babel/plugin-transform-react-jsx-self@7.24.6': + resolution: {integrity: sha512-FfZfHXtQ5jYPQsCRyLpOv2GeLIIJhs8aydpNh39vRDjhD411XcfWDni5i7OjP/Rs8GAtTn7sWFFELJSHqkIxYg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-source@7.25.9': - resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} + '@babel/plugin-transform-react-jsx-source@7.24.6': + resolution: {integrity: sha512-BQTBCXmFRreU3oTUXcGKuPOfXAGb1liNY4AvvFKsOBAJ89RKcTsIrSsnMYkj59fNa66OFKnSa4AJZfy5Y4B9WA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx@7.25.9': - resolution: {integrity: sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==} + '@babel/plugin-transform-react-jsx@7.24.6': + resolution: {integrity: sha512-pCtPHhpRZHfwdA5G1Gpk5mIzMA99hv0R8S/Ket50Rw+S+8hkt3wBWqdqHaPw0CuUYxdshUgsPiLQ5fAs4ASMhw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-pure-annotations@7.25.9': - resolution: {integrity: sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==} + '@babel/plugin-transform-react-pure-annotations@7.24.6': + resolution: {integrity: sha512-0HoDQlFJJkXRyV2N+xOpUETbKHcouSwijRQbKWVtxsPoq5bbB30qZag9/pSc5xcWVYjTHlLsBsY+hZDnzQTPNw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.25.9': - resolution: {integrity: sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==} + '@babel/plugin-transform-regenerator@7.24.6': + resolution: {integrity: sha512-SMDxO95I8WXRtXhTAc8t/NFQUT7VYbIWwJCJgEli9ml4MhqUMh4S6hxgH6SmAC3eAQNWCDJFxcFeEt9w2sDdXg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regexp-modifiers@7.26.0': - resolution: {integrity: sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-reserved-words@7.25.9': - resolution: {integrity: sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==} + '@babel/plugin-transform-reserved-words@7.24.6': + resolution: {integrity: sha512-DcrgFXRRlK64dGE0ZFBPD5egM2uM8mgfrvTMOSB2yKzOtjpGegVYkzh3s1zZg1bBck3nkXiaOamJUqK3Syk+4A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-runtime@7.25.9': - resolution: {integrity: sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==} + '@babel/plugin-transform-runtime@7.24.6': + resolution: {integrity: sha512-W3gQydMb0SY99y/2lV0Okx2xg/8KzmZLQsLaiCmwNRl1kKomz14VurEm+2TossUb+sRvBCnGe+wx8KtIgDtBbQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-shorthand-properties@7.25.9': - resolution: {integrity: sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==} + '@babel/plugin-transform-shorthand-properties@7.24.6': + resolution: {integrity: sha512-xnEUvHSMr9eOWS5Al2YPfc32ten7CXdH7Zwyyk7IqITg4nX61oHj+GxpNvl+y5JHjfN3KXE2IV55wAWowBYMVw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-spread@7.25.9': - resolution: {integrity: sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==} + '@babel/plugin-transform-spread@7.24.6': + resolution: {integrity: sha512-h/2j7oIUDjS+ULsIrNZ6/TKG97FgmEk1PXryk/HQq6op4XUUUwif2f69fJrzK0wza2zjCS1xhXmouACaWV5uPA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-sticky-regex@7.25.9': - resolution: {integrity: sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==} + '@babel/plugin-transform-sticky-regex@7.24.6': + resolution: {integrity: sha512-fN8OcTLfGmYv7FnDrsjodYBo1DhPL3Pze/9mIIE2MGCT1KgADYIOD7rEglpLHZj8PZlC/JFX5WcD+85FLAQusw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-template-literals@7.25.9': - resolution: {integrity: sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==} + '@babel/plugin-transform-template-literals@7.24.6': + resolution: {integrity: sha512-BJbEqJIcKwrqUP+KfUIkxz3q8VzXe2R8Wv8TaNgO1cx+nNavxn/2+H8kp9tgFSOL6wYPPEgFvU6IKS4qoGqhmg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typeof-symbol@7.25.9': - resolution: {integrity: sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==} + '@babel/plugin-transform-typeof-symbol@7.24.6': + resolution: {integrity: sha512-IshCXQ+G9JIFJI7bUpxTE/oA2lgVLAIK8q1KdJNoPXOpvRaNjMySGuvLfBw/Xi2/1lLo953uE8hyYSDW3TSYig==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.25.9': - resolution: {integrity: sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==} + '@babel/plugin-transform-typescript@7.24.6': + resolution: {integrity: sha512-H0i+hDLmaYYSt6KU9cZE0gb3Cbssa/oxWis7PX4ofQzbvsfix9Lbh8SRk7LCPDlLWJHUiFeHU0qRRpF/4Zv7mQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-escapes@7.25.9': - resolution: {integrity: sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==} + '@babel/plugin-transform-unicode-escapes@7.24.6': + resolution: {integrity: sha512-bKl3xxcPbkQQo5eX9LjjDpU2xYHeEeNQbOhj0iPvetSzA+Tu9q/o5lujF4Sek60CM6MgYvOS/DJuwGbiEYAnLw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-property-regex@7.25.9': - resolution: {integrity: sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==} + '@babel/plugin-transform-unicode-property-regex@7.24.6': + resolution: {integrity: sha512-8EIgImzVUxy15cZiPii9GvLZwsy7Vxc+8meSlR3cXFmBIl5W5Tn9LGBf7CDKkHj4uVfNXCJB8RsVfnmY61iedA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-regex@7.25.9': - resolution: {integrity: sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==} + '@babel/plugin-transform-unicode-regex@7.24.6': + resolution: {integrity: sha512-pssN6ExsvxaKU638qcWb81RrvvgZom3jDgU/r5xFZ7TONkZGFf4MhI2ltMb8OcQWhHyxgIavEU+hgqtbKOmsPA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-sets-regex@7.25.9': - resolution: {integrity: sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==} + '@babel/plugin-transform-unicode-sets-regex@7.24.6': + resolution: {integrity: sha512-quiMsb28oXWIDK0gXLALOJRXLgICLiulqdZGOaPPd0vRT7fQp74NtdADAVu+D8s00C+0Xs0MxVP0VKF/sZEUgw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.26.0': - resolution: {integrity: sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==} + '@babel/preset-env@7.24.6': + resolution: {integrity: sha512-CrxEAvN7VxfjOG8JNF2Y/eMqMJbZPZ185amwGUBp8D9USK90xQmv7dLdFSa+VbD7fdIqcy/Mfv7WtzG8+/qxKg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/preset-flow@7.25.9': - resolution: {integrity: sha512-EASHsAhE+SSlEzJ4bzfusnXSHiU+JfAYzj+jbw2vgQKgq5HrUr8qs+vgtiEL5dOH6sEweI+PNt2D7AqrDSHyqQ==} + '@babel/preset-flow@7.24.6': + resolution: {integrity: sha512-huoe0T1Qs9fQhMWbmqE/NHUeZbqmHDsN6n/jYvPcUUHfuKiPV32C9i8tDhMbQ1DEKTjbBP7Rjm3nSLwlB2X05g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1715,46 +1943,65 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - '@babel/preset-react@7.25.9': - resolution: {integrity: sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==} + '@babel/preset-react@7.24.6': + resolution: {integrity: sha512-8mpzh1bWvmINmwM3xpz6ahu57mNaWavMm+wBNjQ4AFu1nghKBiIRET7l/Wmj4drXany/BBGjJZngICcD98F1iw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/preset-typescript@7.26.0': - resolution: {integrity: sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==} + '@babel/preset-typescript@7.24.6': + resolution: {integrity: sha512-U10aHPDnokCFRXgyT/MaIRTivUu2K/mu0vJlwRS9LxJmJet+PFQNKpggPyFCUtC6zWSBPjvxjnpNkAn3Uw2m5w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/register@7.25.9': - resolution: {integrity: sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA==} + '@babel/register@7.24.6': + resolution: {integrity: sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.26.0': - resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} + '@babel/regjsgen@0.8.0': + resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} + + '@babel/runtime@7.22.10': + resolution: {integrity: sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==} + engines: {node: '>=6.9.0'} + + '@babel/runtime@7.24.6': + resolution: {integrity: sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.22.5': + resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} engines: {node: '>=6.9.0'} - '@babel/template@7.25.9': - resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + '@babel/template@7.24.6': + resolution: {integrity: sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.23.2': - resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} + '@babel/traverse@7.17.3': + resolution: {integrity: sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.25.9': - resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} + '@babel/traverse@7.24.6': + resolution: {integrity: sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==} engines: {node: '>=6.9.0'} '@babel/types@7.17.0': resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} engines: {node: '>=6.9.0'} - '@babel/types@7.26.0': - resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} + '@babel/types@7.22.10': + resolution: {integrity: sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.23.6': + resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.24.6': + resolution: {integrity: sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==} engines: {node: '>=6.9.0'} '@balena/dockerignore@1.0.2': @@ -1764,42 +2011,44 @@ packages: resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} engines: {node: '>=16.13'} - '@cloudflare/workerd-darwin-64@1.20241022.0': - resolution: {integrity: sha512-1NNYun37myMTgCUiPQEJ0cMal4mKZVTpkD0b2tx9hV70xji+frVJcSK8YVLeUm1P+Rw1d/ct8DMgQuCpsz3Fsw==} + '@cloudflare/workerd-darwin-64@1.20240712.0': + resolution: {integrity: sha512-KB1vbOhr62BCAwVr3VaRcngzPeSCQ7zPA9VGrfwYXIxo0Y4zlW1z0EVtcewFSz5XXKr3BtNnJXxdjDPUNkguQw==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20241022.0': - resolution: {integrity: sha512-FOO/0P0U82EsTLTdweNVgw+4VOk5nghExLPLSppdOziq6IR5HVgP44Kmq5LdsUeHUhwUmfOh9hzaTpkNzUqKvw==} + '@cloudflare/workerd-darwin-arm64@1.20240712.0': + resolution: {integrity: sha512-UDwFnCfQGFVCNxOeHxKNEc1ANQk/3OIiFWpVsxgZqJqU/22XM88JHxJW+YcBKsaUGUlpLyImaYUn2/rG+i+9UQ==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20241022.0': - resolution: {integrity: sha512-RsNc19BQJG9yd+ngnjuDeG9ywZG+7t1L4JeglgceyY5ViMNMKVO7Zpbsu69kXslU9h6xyQG+lrmclg3cBpnhYA==} + '@cloudflare/workerd-linux-64@1.20240712.0': + resolution: {integrity: sha512-MxpMHSJcZRUL66TO7BEnEim9WgZ8wJEVOB1Rq7a/IF2hI4/8f+N+02PChh62NkBlWxDfTXAtZy0tyQMm0EGjHg==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20241022.0': - resolution: {integrity: sha512-x5mUXpKxfsosxcFmcq5DaqLs37PejHYVRsNz1cWI59ma7aC4y4Qn6Tf3i0r9MwQTF/MccP4SjVslMU6m4W7IaA==} + '@cloudflare/workerd-linux-arm64@1.20240712.0': + resolution: {integrity: sha512-DtLYZsFFFAMgn+6YCHoQS6nYY4nbdAtcAFa4PhWTjLJDbvQEn3IoK9Bi4ajCL7xG36FeuBdZliSbBiiv7CJjfQ==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20241022.0': - resolution: {integrity: sha512-eBCClx4szCOgKqOlxxbdNszMqQf3MRG1B9BRIqEM/diDfdR9IrZ8l3FaEm+l9gXgPmS6m1NBn40aWuGBl8UTSw==} + '@cloudflare/workerd-windows-64@1.20240712.0': + resolution: {integrity: sha512-u8zoT9PQiiwxuz9npquLBFWrC/RlBWGGZ1aylarZNFlM4sFrRm+bRr6i+KtS+fltHIVXj3teuoKYytA1ppf9Yw==} engines: {node: '>=16'} cpu: [x64] os: [win32] - '@cloudflare/workers-shared@0.7.0': - resolution: {integrity: sha512-LLQRTqx7lKC7o2eCYMpyc5FXV8d0pUX6r3A+agzhqS9aoR5A6zCPefwQGcvbKx83ozX22ATZcemwxQXn12UofQ==} - engines: {node: '>=16.7.0'} + '@cloudflare/workers-types@4.20240512.0': + resolution: {integrity: sha512-o2yTEWg+YK/I1t/Me+dA0oarO0aCbjibp6wSeaw52DSE9tDyKJ7S+Qdyw/XsMrKn4t8kF6f/YOba+9O4MJfW9w==} + + '@cloudflare/workers-types@4.20240524.0': + resolution: {integrity: sha512-GpSr4uE7y39DU9f0+wmrL76xd03wn0jy1ClITaa3ZZltKjirAV8TW1GzHrvvKyVGx6u3lekrFnB1HzVHsCYHDQ==} - '@cloudflare/workers-types@4.20241106.0': - resolution: {integrity: sha512-pI4ivacmp+vgNO/siHDsZ6BdITR0LC4Mh/1+yzVLcl9U75pt5DUDCOWOiqIRFXRq6H65DPnJbEPFo3x9UfgofQ==} + '@cloudflare/workers-types@4.20241004.0': + resolution: {integrity: sha512-3LrPvtecs4umknOF1bTPNLHUG/ZjeSE6PYBQ/tbO7lwaVhjZTaTugiaCny2byrZupBlVNuubQVktcAgMfw0C1A==} '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -1853,12 +2102,12 @@ packages: '@electric-sql/pglite@0.2.12': resolution: {integrity: sha512-J/X42ujcoFEbOkgRyoNqZB5qcqrnJRWVlwpH3fKYoJkTz49N91uAK/rDSSG/85WRas9nC9mdV4FnMTxnQWE/rw==} - '@esbuild-kit/core-utils@3.3.2': - resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + '@esbuild-kit/core-utils@3.1.0': + resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} deprecated: 'Merged into tsx: https://tsx.is' - '@esbuild-kit/esm-loader@2.6.5': - resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + '@esbuild-kit/esm-loader@2.5.5': + resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-plugins/node-globals-polyfill@0.2.3': @@ -1877,20 +2126,20 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + '@esbuild/aix-ppc64@0.20.2': + resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.23.1': - resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} - engines: {node: '>=18'} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.24.0': - resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==} + '@esbuild/aix-ppc64@0.23.0': + resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -1913,20 +2162,20 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + '@esbuild/android-arm64@0.20.2': + resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.23.1': - resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} - engines: {node: '>=18'} + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.24.0': - resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==} + '@esbuild/android-arm64@0.23.0': + resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -1949,20 +2198,20 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + '@esbuild/android-arm@0.20.2': + resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} engines: {node: '>=12'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.23.1': - resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} - engines: {node: '>=18'} + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.24.0': - resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==} + '@esbuild/android-arm@0.23.0': + resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -1985,20 +2234,20 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + '@esbuild/android-x64@0.20.2': + resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} engines: {node: '>=12'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.23.1': - resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} - engines: {node: '>=18'} + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.24.0': - resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==} + '@esbuild/android-x64@0.23.0': + resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -2021,20 +2270,20 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + '@esbuild/darwin-arm64@0.20.2': + resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.23.1': - resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} - engines: {node: '>=18'} + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.24.0': - resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==} + '@esbuild/darwin-arm64@0.23.0': + resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -2057,20 +2306,20 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + '@esbuild/darwin-x64@0.20.2': + resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.23.1': - resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} - engines: {node: '>=18'} + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.24.0': - resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==} + '@esbuild/darwin-x64@0.23.0': + resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -2093,20 +2342,20 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + '@esbuild/freebsd-arm64@0.20.2': + resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.23.1': - resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} - engines: {node: '>=18'} + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.24.0': - resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==} + '@esbuild/freebsd-arm64@0.23.0': + resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -2129,20 +2378,20 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + '@esbuild/freebsd-x64@0.20.2': + resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.23.1': - resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} - engines: {node: '>=18'} + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.24.0': - resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==} + '@esbuild/freebsd-x64@0.23.0': + resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -2165,20 +2414,20 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + '@esbuild/linux-arm64@0.20.2': + resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.23.1': - resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} - engines: {node: '>=18'} + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.24.0': - resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==} + '@esbuild/linux-arm64@0.23.0': + resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -2201,20 +2450,20 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + '@esbuild/linux-arm@0.20.2': + resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} engines: {node: '>=12'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.23.1': - resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} - engines: {node: '>=18'} + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.24.0': - resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==} + '@esbuild/linux-arm@0.23.0': + resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -2237,20 +2486,20 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + '@esbuild/linux-ia32@0.20.2': + resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.23.1': - resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} - engines: {node: '>=18'} + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.24.0': - resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==} + '@esbuild/linux-ia32@0.23.0': + resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -2279,20 +2528,20 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + '@esbuild/linux-loong64@0.20.2': + resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.23.1': - resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} - engines: {node: '>=18'} + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.24.0': - resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==} + '@esbuild/linux-loong64@0.23.0': + resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -2315,20 +2564,20 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.20.2': + resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.23.1': - resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.24.0': - resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==} + '@esbuild/linux-mips64el@0.23.0': + resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -2351,20 +2600,20 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + '@esbuild/linux-ppc64@0.20.2': + resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.23.1': - resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} - engines: {node: '>=18'} + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.24.0': - resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==} + '@esbuild/linux-ppc64@0.23.0': + resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -2387,20 +2636,20 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + '@esbuild/linux-riscv64@0.20.2': + resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.23.1': - resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} - engines: {node: '>=18'} + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.24.0': - resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==} + '@esbuild/linux-riscv64@0.23.0': + resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -2423,20 +2672,20 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + '@esbuild/linux-s390x@0.20.2': + resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.23.1': - resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} - engines: {node: '>=18'} + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.24.0': - resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==} + '@esbuild/linux-s390x@0.23.0': + resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -2459,20 +2708,20 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + '@esbuild/linux-x64@0.20.2': + resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} engines: {node: '>=12'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.23.1': - resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} - engines: {node: '>=18'} + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.24.0': - resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==} + '@esbuild/linux-x64@0.23.0': + resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -2495,32 +2744,26 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + '@esbuild/netbsd-x64@0.20.2': + resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.23.1': - resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} - engines: {node: '>=18'} + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.24.0': - resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==} + '@esbuild/netbsd-x64@0.23.0': + resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.23.1': - resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-arm64@0.24.0': - resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==} + '@esbuild/openbsd-arm64@0.23.0': + resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -2543,20 +2786,20 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + '@esbuild/openbsd-x64@0.20.2': + resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.23.1': - resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} - engines: {node: '>=18'} + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.24.0': - resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==} + '@esbuild/openbsd-x64@0.23.0': + resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -2579,20 +2822,20 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + '@esbuild/sunos-x64@0.20.2': + resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} engines: {node: '>=12'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.23.1': - resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} - engines: {node: '>=18'} + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.24.0': - resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==} + '@esbuild/sunos-x64@0.23.0': + resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -2615,20 +2858,20 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + '@esbuild/win32-arm64@0.20.2': + resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.23.1': - resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} - engines: {node: '>=18'} + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.24.0': - resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==} + '@esbuild/win32-arm64@0.23.0': + resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -2651,20 +2894,20 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + '@esbuild/win32-ia32@0.20.2': + resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} engines: {node: '>=12'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.23.1': - resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} - engines: {node: '>=18'} + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.24.0': - resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==} + '@esbuild/win32-ia32@0.23.0': + resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -2687,67 +2930,91 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + '@esbuild/win32-x64@0.20.2': + resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} engines: {node: '>=12'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.23.1': - resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} - engines: {node: '>=18'} + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.24.0': - resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} + '@esbuild/win32-x64@0.23.0': + resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.4.1': - resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + '@eslint-community/regexpp@4.11.0': + resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint-community/regexpp@4.9.0': + resolution: {integrity: sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.2': + resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.3': + resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@2.1.4': resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + '@eslint/eslintrc@3.1.0': + resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@8.50.0': + resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.53.0': + resolution: {integrity: sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.0': + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} '@ewoudenberg/difflib@0.1.0': resolution: {integrity: sha512-OU5P5mJyD3OoWYMWY+yIgwvgNS9cFAU10f+DDuvtogcWQOoJIsQ4Hy2McSfUfhKjq8L0FuWVb4Rt7kgA+XK86A==} - '@expo/bunyan@4.0.1': - resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {node: '>=0.10.0'} + '@expo/bunyan@4.0.0': + resolution: {integrity: sha512-Ydf4LidRB/EBI+YrB+cVLqIseiRfjUI/AeHBgjGMtq3GroraDu81OV7zqophRgupngoL3iS3JUMDMnxO7g39qA==} + engines: {'0': node >=0.10.0} - '@expo/cli@0.18.30': - resolution: {integrity: sha512-V90TUJh9Ly8stYo8nwqIqNWCsYjE28GlVFWEhAFCUOp99foiQr8HSTpiiX5GIrprcPoWmlGoY+J5fQA29R4lFg==} + '@expo/cli@0.18.13': + resolution: {integrity: sha512-ZO1fpDK8z6mLeQGuFP6e3cZyCHV55ohZY7/tEyhpft3bwysS680eyFg5SFe+tWNFesnziFrbtI8JaUyhyjqovA==} hasBin: true '@expo/code-signing-certificates@0.0.5': resolution: {integrity: sha512-BNhXkY1bblxKZpltzAx98G2Egj9g1Q+JRcvR7E99DOj862FTCX+ZPsAUtPTr7aHxwtrL7+fL3r0JSmM9kBm+Bw==} - '@expo/config-plugins@8.0.10': - resolution: {integrity: sha512-KG1fnSKRmsudPU9BWkl59PyE0byrE2HTnqbOrgwr2FAhqh7tfr9nRs6A9oLS/ntpGzmFxccTEcsV0L4apsuxxg==} + '@expo/config-plugins@8.0.4': + resolution: {integrity: sha512-Hi+xuyNWE2LT4LVbGttHJgl9brnsdWAhEB42gWKb5+8ae86Nr/KwUBQJsJppirBYTeLjj5ZlY0glYnAkDa2jqw==} - '@expo/config-types@51.0.3': - resolution: {integrity: sha512-hMfuq++b8VySb+m9uNNrlpbvGxYc8OcFCUX9yTmi9tlx6A4k8SDabWFBgmnr4ao3wEArvWrtUQIfQCVtPRdpKA==} + '@expo/config-types@51.0.0': + resolution: {integrity: sha512-acn03/u8mQvBhdTQtA7CNhevMltUhbSrpI01FYBJwpVntufkU++ncQujWKlgY/OwIajcfygk1AY4xcNZ5ImkRA==} - '@expo/config@9.0.4': - resolution: {integrity: sha512-g5ns5u1JSKudHYhjo1zaSfkJ/iZIcWmUmIQptMJZ6ag1C0ShL2sj8qdfU8MmAMuKLOgcIfSaiWlQnm4X3VJVkg==} + '@expo/config@9.0.2': + resolution: {integrity: sha512-BKQ4/qBf3OLT8hHp5kjObk2vxwoRQ1yYQBbG/OM9Jdz32yYtrU8opTbKRAxfZEWH5i3ZHdLrPdC1rO0I6WxtTw==} - '@expo/devcert@1.1.4': - resolution: {integrity: sha512-fqBODr8c72+gBSX5Ty3SIzaY4bXainlpab78+vEYEKL3fXmsOswMLf0+KE36mUEAa36BYabX7K3EiXOXX5OPMw==} + '@expo/devcert@1.1.2': + resolution: {integrity: sha512-FyWghLu7rUaZEZSTLt/XNRukm0c9GFfwP0iFaswoDWpV6alvVg+zRAfCLdIVQEz1SVcQ3zo1hMZFDrnKGvkCuQ==} '@expo/env@0.3.0': resolution: {integrity: sha512-OtB9XVHWaXidLbHvrVDeeXa09yvTl3+IQN884sO6PhIi2/StXfgSH/9zC7IvzrDB8kW3EBJ1PPLuCUJ2hxAT7Q==} @@ -2758,11 +3025,11 @@ packages: '@expo/json-file@8.3.3': resolution: {integrity: sha512-eZ5dld9AD0PrVRiIWpRkm5aIoWBw3kAyd8VkuWEy92sEthBKDDDHAnK2a0dw0Eil6j7rK7lS/Qaq/Zzngv2h5A==} - '@expo/metro-config@0.18.11': - resolution: {integrity: sha512-/uOq55VbSf9yMbUO1BudkUM2SsGW1c5hr9BnhIqYqcsFv0Jp5D3DtJ4rljDKaUeNLbwr6m7pqIrkSMq5NrYf4Q==} + '@expo/metro-config@0.18.4': + resolution: {integrity: sha512-vh9WDf/SzE+NYCn6gqbzLKiXtENFlFZdAqyj9nI38RvQ4jw6TJIQ8+ExcdLDT3MOG36Ytg44XX9Zb3OWF6LVxw==} - '@expo/osascript@2.1.3': - resolution: {integrity: sha512-aOEkhPzDsaAfolSswObGiYW0Pf0ROfR9J2NBRLQACdQ6uJlyAMiPF45DVEVknAU9juKh0y8ZyvC9LXqLEJYohA==} + '@expo/osascript@2.1.2': + resolution: {integrity: sha512-/ugqDG+52uzUiEpggS9GPdp9g0U9EQrXcTdluHDmnlGmR2nV/F83L7c+HCUyPnf77QXwkr8gQk16vQTbxBQ5eA==} engines: {node: '>=12'} '@expo/package-manager@1.5.2': @@ -2771,8 +3038,8 @@ packages: '@expo/plist@0.1.3': resolution: {integrity: sha512-GW/7hVlAylYg1tUrEASclw1MMk9FP4ZwyFAY/SUTJIhPDQHtfOlXREyWV3hhrHdX/K+pS73GNgdfT6E/e+kBbg==} - '@expo/prebuild-config@7.0.9': - resolution: {integrity: sha512-9i6Cg7jInpnGEHN0jxnW0P+0BexnePiBzmbUvzSbRXpdXihYUX2AKMu73jgzxn5P1hXOSkzNS7umaY+BZ+aBag==} + '@expo/prebuild-config@7.0.4': + resolution: {integrity: sha512-E2n3QbwgV8Qa0CBw7BHrWBDWD7l8yw+N/yjvXpSPFFtoZLMSKyegdkJFACh2u+UIRKUSZm8zQwHeZR0rqAxV9g==} peerDependencies: expo-modules-autolinking: '>=0.8.1' @@ -2787,8 +3054,8 @@ packages: resolution: {integrity: sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==} engines: {node: '>=12'} - '@expo/vector-icons@14.0.4': - resolution: {integrity: sha512-+yKshcbpDfbV4zoXOgHxCwh7lkE9VVTT5T03OUlBsqfze1PLy6Hi4jp1vSb1GVbY6eskvMIivGVc9SKzIv0oEQ==} + '@expo/vector-icons@14.0.2': + resolution: {integrity: sha512-70LpmXQu4xa8cMxjp1fydgRPsalefnHaXLzIwaHMEzcZhnyjw2acZz8azRrZOslPVAWlxItOa2Dd7WtD/kI+CA==} '@expo/websql@1.0.1': resolution: {integrity: sha512-H9/t1V7XXyKC343FJz/LwaVBfDhs6IqhDtSYWpt8LNSQDVjf5NvVJLc5wp+KCpRidZx8+0+YeHJN45HOXmqjFA==} @@ -2809,11 +3076,15 @@ packages: peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@hono/node-server@1.13.5': - resolution: {integrity: sha512-lSo+CFlLqAFB4fX7ePqI9nauEn64wOfJHAfc9duYFTvAG3o416pC0nTGeNjuLHchLedH+XyWda5v79CVx1PIjg==} + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@hapi/topo@5.1.0': + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + + '@hono/node-server@1.12.0': + resolution: {integrity: sha512-e6oHjNiErRxsZRZBmc2KucuvY3btlO/XPncIpP2X75bRdTilF9GLjm3NHvKKunpJbbJJj31/FoPTksTf8djAVw==} engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 '@hono/zod-validator@0.2.2': resolution: {integrity: sha512-dSDxaPV70Py8wuIU2QNpoVEIOSzSXZ/6/B/h4xA7eOMz7+AarKTSGV8E6QwrdcCbBLkpqfJ4Q2TmBO0eP1tCBQ==} @@ -2821,8 +3092,18 @@ packages: hono: '>=3.9.0' zod: ^3.19.1 - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + '@humanwhocodes/config-array@0.11.11': + resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/config-array@0.11.13': + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/config-array@0.11.14': + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} deprecated: Use @eslint/config-array instead @@ -2830,6 +3111,14 @@ packages: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} + '@humanwhocodes/object-schema@1.2.1': + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead + + '@humanwhocodes/object-schema@2.0.1': + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + deprecated: Use @eslint/object-schema instead + '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead @@ -2845,14 +3134,6 @@ packages: resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} engines: {node: '>=12'} - '@istanbuljs/load-nyc-config@1.1.0': - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - '@jest/create-cache-key-function@29.7.0': resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2869,36 +3150,56 @@ packages: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/transform@29.7.0': - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/types@24.9.0': - resolution: {integrity: sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==} - engines: {node: '>= 6'} + '@jest/types@26.6.2': + resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} + engines: {node: '>= 10.14.2'} '@jest/types@29.6.3': resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jridgewell/gen-mapping@0.3.3': + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} + '@jridgewell/resolve-uri@3.1.0': + resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + engines: {node: '>=6.0.0'} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + '@jridgewell/set-array@1.1.2': + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + '@jridgewell/set-array@1.2.1': resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.3': + resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==} + '@jridgewell/source-map@0.3.6': resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + '@jridgewell/sourcemap-codec@1.4.14': + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + + '@jridgewell/sourcemap-codec@1.4.15': + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/trace-mapping@0.3.18': + resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} + '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} @@ -2916,13 +3217,23 @@ packages: '@libsql/core@0.10.0': resolution: {integrity: sha512-rqynAXGaiSpTsykOZdBtI1N4z4O+KZ6mt33K/aHeXAY0gSIfK/ctxuWa0Y1Bjo4FMz1idBTCXz4Ps5kITOvZZw==} - '@libsql/darwin-arm64@0.4.7': - resolution: {integrity: sha512-yOL742IfWUlUevnI5PdnIT4fryY3LYTdLm56bnY0wXBw7dhFcnjuA7jrH3oSVz2mjZTHujxoITgAE7V6Z+eAbg==} + '@libsql/darwin-arm64@0.3.19': + resolution: {integrity: sha512-rmOqsLcDI65zzxlUOoEiPJLhqmbFsZF6p4UJQ2kMqB+Kc0Rt5/A1OAdOZ/Wo8fQfJWjR1IbkbpEINFioyKf+nQ==} + cpu: [arm64] + os: [darwin] + + '@libsql/darwin-arm64@0.4.1': + resolution: {integrity: sha512-XICT9/OyU8Aa9Iv1xZIHgvM09n/1OQUk3VC+s5uavzdiGHrDMkOWzN47JN7/FiMa/NWrcgoEiDMk3+e7mE53Ig==} cpu: [arm64] os: [darwin] - '@libsql/darwin-x64@0.4.7': - resolution: {integrity: sha512-ezc7V75+eoyyH07BO9tIyJdqXXcRfZMbKcLCeF8+qWK5nP8wWuMcfOVywecsXGRbT99zc5eNra4NEx6z5PkSsA==} + '@libsql/darwin-x64@0.3.19': + resolution: {integrity: sha512-q9O55B646zU+644SMmOQL3FIfpmEvdWpRpzubwFc2trsa+zoBlSkHuzU9v/C+UNoPHQVRMP7KQctJ455I/h/xw==} + cpu: [x64] + os: [darwin] + + '@libsql/darwin-x64@0.4.1': + resolution: {integrity: sha512-pSKxhRrhu4SsTD+IBRZXcs1SkwMdeAG1tv6Z/Ctp/sOEYrgkU8MDKLqkOr9NsmwpK4S0+JdwjkLMyhTkct/5TQ==} cpu: [x64] os: [darwin] @@ -2936,28 +3247,53 @@ packages: '@libsql/isomorphic-ws@0.1.5': resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} - '@libsql/linux-arm64-gnu@0.4.7': - resolution: {integrity: sha512-WlX2VYB5diM4kFfNaYcyhw5y+UJAI3xcMkEUJZPtRDEIu85SsSFrQ+gvoKfcVh76B//ztSeEX2wl9yrjF7BBCA==} + '@libsql/linux-arm64-gnu@0.3.19': + resolution: {integrity: sha512-mgeAUU1oqqh57k7I3cQyU6Trpdsdt607eFyEmH5QO7dv303ti+LjUvh1pp21QWV6WX7wZyjeJV1/VzEImB+jRg==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-arm64-gnu@0.4.1': + resolution: {integrity: sha512-9lpvb24tO2qZd9nq5dlq3ESA3hSKYWBIK7lJjfiCM6f7a70AUwBY9QoPJV9q4gILIyVnR1YBGrlm50nnb+dYgw==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-arm64-musl@0.3.19': + resolution: {integrity: sha512-VEZtxghyK6zwGzU9PHohvNxthruSxBEnRrX7BSL5jQ62tN4n2JNepJ6SdzXp70pdzTfwroOj/eMwiPt94gkVRg==} cpu: [arm64] os: [linux] - '@libsql/linux-arm64-musl@0.4.7': - resolution: {integrity: sha512-6kK9xAArVRlTCpWeqnNMCoXW1pe7WITI378n4NpvU5EJ0Ok3aNTIC2nRPRjhro90QcnmLL1jPcrVwO4WD1U0xw==} + '@libsql/linux-arm64-musl@0.4.1': + resolution: {integrity: sha512-lyxi+lFxE+NcBRDMQCxCtDg3c4WcKAbc9u63d5+B23Vm+UgphD9XY4seu+tGrBy1MU2tuNVix7r9S7ECpAaVrA==} cpu: [arm64] os: [linux] - '@libsql/linux-x64-gnu@0.4.7': - resolution: {integrity: sha512-CMnNRCmlWQqqzlTw6NeaZXzLWI8bydaXDke63JTUCvu8R+fj/ENsLrVBtPDlxQ0wGsYdXGlrUCH8Qi9gJep0yQ==} + '@libsql/linux-x64-gnu@0.3.19': + resolution: {integrity: sha512-2t/J7LD5w2f63wGihEO+0GxfTyYIyLGEvTFEsMO16XI5o7IS9vcSHrxsvAJs4w2Pf907uDjmc7fUfMg6L82BrQ==} + cpu: [x64] + os: [linux] + + '@libsql/linux-x64-gnu@0.4.1': + resolution: {integrity: sha512-psvuQ3UFBEmDFV8ZHG+WkUHIJiWv+elZ+zIPvOVedlIKdxG1O+8WthWUAhFHOGnbiyzc4sAZ4c3de1oCvyHxyQ==} + cpu: [x64] + os: [linux] + + '@libsql/linux-x64-musl@0.3.19': + resolution: {integrity: sha512-BLsXyJaL8gZD8+3W2LU08lDEd9MIgGds0yPy5iNPp8tfhXx3pV/Fge2GErN0FC+nzt4DYQtjL+A9GUMglQefXQ==} cpu: [x64] os: [linux] - '@libsql/linux-x64-musl@0.4.7': - resolution: {integrity: sha512-nI6tpS1t6WzGAt1Kx1n1HsvtBbZ+jHn0m7ogNNT6pQHZQj7AFFTIMeDQw/i/Nt5H38np1GVRNsFe99eSIMs9XA==} + '@libsql/linux-x64-musl@0.4.1': + resolution: {integrity: sha512-PDidJ3AhGDqosGg3OAZzGxMFIbnuOALya4BoezJKl667AFv3x7BBQ30H81Mngsq3Fh8RkJkXSdWfL91+Txb1iA==} cpu: [x64] os: [linux] - '@libsql/win32-x64-msvc@0.4.7': - resolution: {integrity: sha512-7pJzOWzPm6oJUxml+PCDRzYQ4A1hTMHAciTAHfFK4fkbDZX33nWPVG7Y3vqdKtslcwAzwmrNDc6sXy2nwWnbiw==} + '@libsql/win32-x64-msvc@0.3.19': + resolution: {integrity: sha512-ay1X9AobE4BpzG0XPw1gplyLZPGHIgJOovvW23gUrukRegiUP62uzhpRbKNogLlUOynyXeq//prHgPXiebUfWg==} + cpu: [x64] + os: [win32] + + '@libsql/win32-x64-msvc@0.4.1': + resolution: {integrity: sha512-IdODVqV/PrdOnHA/004uWyorZQuRsB7U7bCRCE3vXgABj3eJLJGc6cv2C6ksEaEoVxJbD8k53H4VVAGrtYwXzQ==} cpu: [x64] os: [win32] @@ -2984,15 +3320,21 @@ packages: '@neon-rs/load@0.0.4': resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==} + '@neondatabase/serverless@0.10.0': + resolution: {integrity: sha512-+0mjRGJFL2kGyTtWo60PxIcgv0a/X/vCu4DV2iS3tL+Rl/OrFocJoN3aNajugvgBQj624aOK7LowLijoQHWIXg==} + + '@neondatabase/serverless@0.10.3': + resolution: {integrity: sha512-F4kqSj++GUwLnO3OzPb95Y/xn3qVLkjJA/36YTqT7c3MRgA/IBOIs/Is1+HBZkGfEwfMG3A9tFkxiEg5eBjxDw==} + '@neondatabase/serverless@0.7.2': resolution: {integrity: sha512-wU3WA2uTyNO7wjPs3Mg0G01jztAxUxzd9/mskMmtPwPTjf7JKWi9AW5/puOGXLxmZ9PVgRFeBVRVYq5nBPhsCg==} - '@neondatabase/serverless@0.9.5': - resolution: {integrity: sha512-siFas6gItqv6wD/pZnvdu34wEqgG3nSE6zWZdq5j2DEsa+VvX8i/5HXJOo06qrw5axPXn+lGCxeR+NLaSPIXug==} + '@neondatabase/serverless@0.9.3': + resolution: {integrity: sha512-6ZBK8asl2Z3+ADEaELvbaVVGVlmY1oAzkxxZfpmXPKFuJhbDN+5fU3zYBamsahS/Ch1zE+CVWB3R+8QEI2LMSw==} - '@noble/hashes@1.5.0': - resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==} - engines: {node: ^14.21.3 || >=16} + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -3024,8 +3366,8 @@ packages: react: '*' react-native: '*' - '@opentelemetry/api@1.9.0': - resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + '@opentelemetry/api@1.8.0': + resolution: {integrity: sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==} engines: {node: '>=8.0.0'} '@originjs/vite-plugin-commonjs@1.0.3': @@ -3042,12 +3384,12 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@planetscale/database@1.19.0': - resolution: {integrity: sha512-Tv4jcFUFAFjOWrGSio49H6R2ijALv0ZzVBfJKIdm+kl9X046Fh4LLawrF9OMsglVbK6ukqMJsUCeucGAFTBcMA==} + '@planetscale/database@1.18.0': + resolution: {integrity: sha512-t2XdOfrVgcF7AW791FtdPS27NyNqcE1SpoXgk3HpziousvUMsJi4Q6NL3JyOBpsMOrvk94749o8yyonvX5quPw==} engines: {node: '>=16'} - '@polka/url@1.0.0-next.28': - resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} + '@polka/url@1.0.0-next.25': + resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} '@prisma/client@5.14.0': resolution: {integrity: sha512-akMSuyvLKeoU4LeyBAUdThP/uhVP3GuLygFE3MlYzaCb3/J8SfsYBE5PkaFuLuVpLyA6sFoW+16z/aPhNAESqg==} @@ -3061,8 +3403,8 @@ packages: '@prisma/debug@5.14.0': resolution: {integrity: sha512-iq56qBZuFfX3fCxoxT8gBX33lQzomBU0qIUaEj1RebsKVz1ob/BVH1XSBwwwvRVtZEV1b7Fxx2eVu34Ge/mg3w==} - '@prisma/debug@5.22.0': - resolution: {integrity: sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==} + '@prisma/debug@5.16.1': + resolution: {integrity: sha512-JsNgZAg6BD9RInLSrg7ZYzo11N7cVvYArq3fHGSD89HSgtN0VDdjV6bib7YddbcO6snzjchTiLfjeTqBjtArVQ==} '@prisma/engines-version@5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48': resolution: {integrity: sha512-ip6pNkRo1UxWv+6toxNcYvItNYaqQjXdFNGJ+Nuk2eYtRoEdoF13wxo7/jsClJFFenMPVNVqXQDV0oveXnR1cA==} @@ -3073,95 +3415,101 @@ packages: '@prisma/fetch-engine@5.14.0': resolution: {integrity: sha512-VrheA9y9DMURK5vu8OJoOgQpxOhas3qF0IBHJ8G/0X44k82kc8E0w98HCn2nhnbOOMwbWsJWXfLC2/F8n5u0gQ==} - '@prisma/generator-helper@5.22.0': - resolution: {integrity: sha512-LwqcBQ5/QsuAaLNQZAIVIAJDJBMjHwMwn16e06IYx/3Okj/xEEfw9IvrqB2cJCl3b2mCBlh3eVH0w9WGmi4aHg==} + '@prisma/generator-helper@5.16.1': + resolution: {integrity: sha512-WxV/msovIubvr20iIdPJN0MUj46J26ax+sV+vMQSCeVoHQW//xdJZoPnimG54M7+CA9kupXjVpgjiPX4rcKQeA==} '@prisma/get-platform@5.14.0': resolution: {integrity: sha512-/yAyBvcEjRv41ynZrhdrPtHgk47xLRRq/o5eWGcUpBJ1YrUZTYB8EoPiopnP7iQrMATK8stXQdPOoVlrzuTQZw==} - '@react-native/assets-registry@0.76.1': - resolution: {integrity: sha512-1mcDjyvC4Z+XYtY+Abl6pW9P49l/9HJmRChX7EHF1SoXe7zPAPBoAqeZsJNtf8dhJR3u/eGvapr1yJq8T/psEg==} - engines: {node: '>=18'} + '@react-native-community/cli-clean@13.6.6': + resolution: {integrity: sha512-cBwJTwl0NyeA4nyMxbhkWZhxtILYkbU3TW3k8AXLg+iGphe0zikYMGB3T+haTvTc6alTyEFwPbimk9bGIqkjAQ==} - '@react-native/babel-plugin-codegen@0.74.87': - resolution: {integrity: sha512-+vJYpMnENFrwtgvDfUj+CtVJRJuUnzAUYT0/Pb68Sq9RfcZ5xdcCuUgyf7JO+akW2VTBoJY427wkcxU30qrWWw==} - engines: {node: '>=18'} + '@react-native-community/cli-config@13.6.6': + resolution: {integrity: sha512-mbG425zCKr8JZhv/j11382arezwS/70juWMsn8j2lmrGTrP1cUdW0MF15CCIFtJsqyK3Qs+FTmqttRpq81QfSg==} - '@react-native/babel-plugin-codegen@0.76.1': - resolution: {integrity: sha512-V9bGLyEdAF39nvn4L5gaJcPX1SvCHPJhaT3qfpVGvCnl7WPhdRyCq++WsN8HXlpo6WOAf6//oruLnLdl3RNM4Q==} - engines: {node: '>=18'} + '@react-native-community/cli-debugger-ui@13.6.6': + resolution: {integrity: sha512-Vv9u6eS4vKSDAvdhA0OiQHoA7y39fiPIgJ6biT32tN4avHDtxlc6TWZGiqv7g98SBvDWvoVAmdPLcRf3kU+c8g==} - '@react-native/babel-preset@0.74.87': - resolution: {integrity: sha512-hyKpfqzN2nxZmYYJ0tQIHG99FQO0OWXp/gVggAfEUgiT+yNKas1C60LuofUsK7cd+2o9jrpqgqW4WzEDZoBlTg==} - engines: {node: '>=18'} - peerDependencies: - '@babel/core': '*' + '@react-native-community/cli-doctor@13.6.6': + resolution: {integrity: sha512-TWZb5g6EmQe2Ua2TEWNmyaEayvlWH4GmdD9ZC+p8EpKFpB1NpDGMK6sXbpb42TDvwZg5s4TDRplK0PBEA/SVDg==} + + '@react-native-community/cli-hermes@13.6.6': + resolution: {integrity: sha512-La5Ie+NGaRl3klei6WxKoOxmCUSGGxpOk6vU5pEGf0/O7ky+Ay0io+zXYUZqlNMi/cGpO7ZUijakBYOB/uyuFg==} + + '@react-native-community/cli-platform-android@13.6.6': + resolution: {integrity: sha512-/tMwkBeNxh84syiSwNlYtmUz/Ppc+HfKtdopL/5RB+fd3SV1/5/NPNjMlyLNgFKnpxvKCInQ7dnl6jGHJjeHjg==} + + '@react-native-community/cli-platform-apple@13.6.6': + resolution: {integrity: sha512-bOmSSwoqNNT3AmCRZXEMYKz1Jf1l2F86Nhs7qBcXdY/sGiJ+Flng564LOqvdAlVLTbkgz47KjNKCS2pP4Jg0Mg==} + + '@react-native-community/cli-platform-ios@13.6.6': + resolution: {integrity: sha512-vjDnRwhlSN5ryqKTas6/DPkxuouuyFBAqAROH4FR1cspTbn6v78JTZKDmtQy9JMMo7N5vZj1kASU5vbFep9IOQ==} - '@react-native/babel-preset@0.76.1': - resolution: {integrity: sha512-b6YRmA13CmVuTQKHRen/Q0glHwmZFZoEDs+MJ1NL0UNHq9V5ytvdwTW1ntkmjtXuTnPMzkwYvumJBN9UTZjkBA==} + '@react-native-community/cli-server-api@13.6.6': + resolution: {integrity: sha512-ZtCXxoFlM7oDv3iZ3wsrT3SamhtUJuIkX2WePLPlN5bcbq7zimbPm2lHyicNJtpcGQ5ymsgpUWPCNZsWQhXBqQ==} + + '@react-native-community/cli-tools@13.6.6': + resolution: {integrity: sha512-ptOnn4AJczY5njvbdK91k4hcYazDnGtEPrqIwEI+k/CTBHNdb27Rsm2OZ7ye6f7otLBqF8gj/hK6QzJs8CEMgw==} + + '@react-native-community/cli-types@13.6.6': + resolution: {integrity: sha512-733iaYzlmvNK7XYbnWlMjdE+2k0hlTBJW071af/xb6Bs+hbJqBP9c03FZuYH2hFFwDDntwj05bkri/P7VgSxug==} + + '@react-native-community/cli@13.6.6': + resolution: {integrity: sha512-IqclB7VQ84ye8Fcs89HOpOscY4284VZg2pojHNl8H0Lzd4DadXJWQoxC7zWm8v2f8eyeX2kdhxp2ETD5tceIgA==} engines: {node: '>=18'} - peerDependencies: - '@babel/core': '*' + hasBin: true - '@react-native/codegen@0.74.87': - resolution: {integrity: sha512-GMSYDiD+86zLKgMMgz9z0k6FxmRn+z6cimYZKkucW4soGbxWsbjUAZoZ56sJwt2FJ3XVRgXCrnOCgXoH/Bkhcg==} + '@react-native/assets-registry@0.74.83': + resolution: {integrity: sha512-2vkLMVnp+YTZYTNSDIBZojSsjz8sl5PscP3j4GcV6idD8V978SZfwFlk8K0ti0BzRs11mzL0Pj17km597S/eTQ==} engines: {node: '>=18'} - peerDependencies: - '@babel/preset-env': ^7.1.6 - '@react-native/codegen@0.76.1': - resolution: {integrity: sha512-7lE0hk2qq27wVeK5eF654v7XsKoRa7ficrfSwIDEDZ1aLB2xgUzLrsq+glSAP9EuzT6ycHhtD3QyqI+TqnlS/A==} + '@react-native/babel-plugin-codegen@0.74.83': + resolution: {integrity: sha512-+S0st3t4Ro00bi9gjT1jnK8qTFOU+CwmziA7U9odKyWrCoRJrgmrvogq/Dr1YXlpFxexiGIupGut1VHxr+fxJA==} engines: {node: '>=18'} - peerDependencies: - '@babel/preset-env': ^7.1.6 - '@react-native/community-cli-plugin@0.76.1': - resolution: {integrity: sha512-dECc1LuleMQDX/WK2oJInrYCpHb3OFBJxYkhPOAXb9HiktMWRA9T93qqpTDshmtLdYqvxeO9AM5eeoSL412WnQ==} + '@react-native/babel-preset@0.74.83': + resolution: {integrity: sha512-KJuu3XyVh3qgyUer+rEqh9a/JoUxsDOzkJNfRpDyXiAyjDRoVch60X/Xa/NcEQ93iCVHAWs0yQ+XGNGIBCYE6g==} engines: {node: '>=18'} peerDependencies: - '@react-native-community/cli-server-api': '*' - peerDependenciesMeta: - '@react-native-community/cli-server-api': - optional: true + '@babel/core': '*' - '@react-native/debugger-frontend@0.74.85': - resolution: {integrity: sha512-gUIhhpsYLUTYWlWw4vGztyHaX/kNlgVspSvKe2XaPA7o3jYKUoNLc3Ov7u70u/MBWfKdcEffWq44eSe3j3s5JQ==} + '@react-native/codegen@0.74.83': + resolution: {integrity: sha512-GgvgHS3Aa2J8/mp1uC/zU8HuTh8ZT5jz7a4mVMWPw7+rGyv70Ba8uOVBq6UH2Q08o617IATYc+0HfyzAfm4n0w==} engines: {node: '>=18'} + peerDependencies: + '@babel/preset-env': ^7.1.6 - '@react-native/debugger-frontend@0.76.1': - resolution: {integrity: sha512-0gExx7GR8o2ctGfjIZ9+x54iFbg0eP6+kMYzRA6AcgmFAmMGLADMmjtObCN0CqGeZyWtdVVqcv5mAwRwmMlNWA==} + '@react-native/community-cli-plugin@0.74.83': + resolution: {integrity: sha512-7GAFjFOg1mFSj8bnFNQS4u8u7+QtrEeflUIDVZGEfBZQ3wMNI5ycBzbBGycsZYiq00Xvoc6eKFC7kvIaqeJpUQ==} engines: {node: '>=18'} - '@react-native/dev-middleware@0.74.85': - resolution: {integrity: sha512-BRmgCK5vnMmHaKRO+h8PKJmHHH3E6JFuerrcfE3wG2eZ1bcSr+QTu8DAlpxsDWvJvHpCi8tRJGauxd+Ssj/c7w==} + '@react-native/debugger-frontend@0.74.83': + resolution: {integrity: sha512-RGQlVUegBRxAUF9c1ss1ssaHZh6CO+7awgtI9sDeU0PzDZY/40ImoPD5m0o0SI6nXoVzbPtcMGzU+VO590pRfA==} engines: {node: '>=18'} - '@react-native/dev-middleware@0.76.1': - resolution: {integrity: sha512-htaFSN2dwI0CinsMxjRuvIVdSDN6d6TDPeOJczM1bdAYalZX1M58knTKs5LJDComW5tleOCAg5lS5tIeFlM9+Q==} + '@react-native/dev-middleware@0.74.83': + resolution: {integrity: sha512-UH8iriqnf7N4Hpi20D7M2FdvSANwTVStwFCSD7VMU9agJX88Yk0D1T6Meh2RMhUu4kY2bv8sTkNRm7LmxvZqgA==} engines: {node: '>=18'} - '@react-native/gradle-plugin@0.76.1': - resolution: {integrity: sha512-X7rNFltPa9QYxvYrQGaSCw7U57C+y+DwspXf4AnLZj0bQm9tL6UYpijh5vE3VmPcHn76/RNU2bpFjVvWg6gjqw==} + '@react-native/gradle-plugin@0.74.83': + resolution: {integrity: sha512-Pw2BWVyOHoBuJVKxGVYF6/GSZRf6+v1Ygc+ULGz5t20N8qzRWPa2fRZWqoxsN7TkNLPsECYY8gooOl7okOcPAQ==} engines: {node: '>=18'} - '@react-native/js-polyfills@0.76.1': - resolution: {integrity: sha512-HO3fzJ0FnrnQGmxdXxh2lcGGAMfaX9h1Pg1Zh38MkVw35/KnZHxHqxg6cruze6iWwZdfqSoIcQoalmMuAHby7Q==} + '@react-native/js-polyfills@0.74.83': + resolution: {integrity: sha512-/t74n8r6wFhw4JEoOj3bN71N1NDLqaawB75uKAsSjeCwIR9AfCxlzZG0etsXtOexkY9KMeZIQ7YwRPqUdNXuqw==} engines: {node: '>=18'} - '@react-native/metro-babel-transformer@0.76.1': - resolution: {integrity: sha512-LUAKqgsrioXS2a+pE0jak8sutTbLo3T34KWv7mdVUZ5lUACpqkIql1EFtIQlWjIcR4oZE480CkPbRHBI681tkQ==} + '@react-native/metro-babel-transformer@0.74.83': + resolution: {integrity: sha512-hGdx5N8diu8y+GW/ED39vTZa9Jx1di2ZZ0aapbhH4egN1agIAusj5jXTccfNBwwWF93aJ5oVbRzfteZgjbutKg==} engines: {node: '>=18'} peerDependencies: '@babel/core': '*' - '@react-native/normalize-colors@0.74.85': - resolution: {integrity: sha512-pcE4i0X7y3hsAE0SpIl7t6dUc0B0NZLd1yv7ssm4FrLhWG+CGyIq4eFDXpmPU1XHmL5PPySxTAjEMiwv6tAmOw==} - - '@react-native/normalize-colors@0.76.1': - resolution: {integrity: sha512-/+CUk/wGWIdXbJYVLw/q6Fs8Z0x91zzfXIbNiZUdSW1TNEDmytkF371H8a1/Nx3nWa1RqCMVsaZHCG4zqxeDvg==} + '@react-native/normalize-colors@0.74.83': + resolution: {integrity: sha512-jhCY95gRDE44qYawWVvhTjTplW1g+JtKTKM3f8xYT1dJtJ8QWv+gqEtKcfmOHfDkSDaMKG0AGBaDTSK8GXLH8Q==} - '@react-native/virtualized-lists@0.76.1': - resolution: {integrity: sha512-uWJfv0FC3zmlYORr0Sa17ngbAaw6K9yw4MAkBZyFeTM+W6AJRvTVyR1Mes/MU+vIyGFChnTcyaQrQz8jWqADOA==} + '@react-native/virtualized-lists@0.74.83': + resolution: {integrity: sha512-rmaLeE34rj7py4FxTod7iMTC7BAsm+HrGA8WxYmEJeyTV7WSaxAkosKoYBz8038mOiwnG9VwA/7FrB6bEQvn1A==} engines: {node: '>=18'} peerDependencies: '@types/react': ^18.2.6 @@ -3175,6 +3523,15 @@ packages: resolution: {integrity: sha512-lzD84av1ZQhYUS+jsGqJiCMaJO2dn9u+RTT9n9q6D3SaKVwWqv+7AoRKqBu19bkwyE+iFRl1ymr40QS90jVFYg==} engines: {node: '>=14.15'} + '@rollup/plugin-terser@0.4.1': + resolution: {integrity: sha512-aKS32sw5a7hy+fEXVy+5T95aDIwjpGHCTv833HXVtyKMDoVS7pBr5K3L9hEQoNqbJFjfANPrNpIXlTQ7is00eA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.x || ^3.x + peerDependenciesMeta: + rollup: + optional: true + '@rollup/plugin-terser@0.4.4': resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} engines: {node: '>=14.0.0'} @@ -3184,6 +3541,32 @@ packages: rollup: optional: true + '@rollup/plugin-typescript@11.1.0': + resolution: {integrity: sha512-86flrfE+bSHB69znnTV6kVjkncs2LBMhcTCyxWgRxLyfXfQrxg4UwlAqENnjrrxnSNS/XKCDJCl8EkdFJVHOxw==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.14.0||^3.0.0 + tslib: '*' + typescript: '>=3.7.0' + peerDependenciesMeta: + rollup: + optional: true + tslib: + optional: true + + '@rollup/plugin-typescript@11.1.1': + resolution: {integrity: sha512-Ioir+x5Bejv72Lx2Zbz3/qGg7tvGbxQZALCLoJaGrkNXak/19+vKgKYJYM3i/fJxvsb23I9FuFQ8CUBEfsmBRg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.14.0||^3.0.0 + tslib: '*' + typescript: '>=3.7.0' + peerDependenciesMeta: + rollup: + optional: true + tslib: + optional: true + '@rollup/plugin-typescript@11.1.6': resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==} engines: {node: '>=14.0.0'} @@ -3197,6 +3580,15 @@ packages: tslib: optional: true + '@rollup/pluginutils@5.0.2': + resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/pluginutils@5.1.3': resolution: {integrity: sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==} engines: {node: '>=14.0.0'} @@ -3206,102 +3598,188 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.24.4': - resolution: {integrity: sha512-jfUJrFct/hTA0XDM5p/htWKoNNTbDLY0KRwEt6pyOA6k2fmk0WVwl65PdUdJZgzGEHWx+49LilkcSaumQRyNQw==} + '@rollup/rollup-android-arm-eabi@4.18.1': + resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.24.4': - resolution: {integrity: sha512-j4nrEO6nHU1nZUuCfRKoCcvh7PIywQPUCBa2UsootTHvTHIoIu2BzueInGJhhvQO/2FTRdNYpf63xsgEqH9IhA==} + '@rollup/rollup-android-arm-eabi@4.27.3': + resolution: {integrity: sha512-EzxVSkIvCFxUd4Mgm4xR9YXrcp976qVaHnqom/Tgm+vU79k4vV4eYTjmRvGfeoW8m9LVcsAy/lGjcgVegKEhLQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.18.1': + resolution: {integrity: sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-android-arm64@4.27.3': + resolution: {integrity: sha512-LJc5pDf1wjlt9o/Giaw9Ofl+k/vLUaYsE2zeQGH85giX2F+wn/Cg8b3c5CDP3qmVmeO5NzwVUzQQxwZvC2eQKw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.24.4': - resolution: {integrity: sha512-GmU/QgGtBTeraKyldC7cDVVvAJEOr3dFLKneez/n7BvX57UdhOqDsVwzU7UOnYA7AAOt+Xb26lk79PldDHgMIQ==} + '@rollup/rollup-darwin-arm64@4.18.1': + resolution: {integrity: sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-arm64@4.27.3': + resolution: {integrity: sha512-OuRysZ1Mt7wpWJ+aYKblVbJWtVn3Cy52h8nLuNSzTqSesYw1EuN6wKp5NW/4eSre3mp12gqFRXOKTcN3AI3LqA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.24.4': - resolution: {integrity: sha512-N6oDBiZCBKlwYcsEPXGDE4g9RoxZLK6vT98M8111cW7VsVJFpNEqvJeIPfsCzbf0XEakPslh72X0gnlMi4Ddgg==} + '@rollup/rollup-darwin-x64@4.18.1': + resolution: {integrity: sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.27.3': + resolution: {integrity: sha512-xW//zjJMlJs2sOrCmXdB4d0uiilZsOdlGQIC/jjmMWT47lkLLoB1nsNhPUcnoqyi5YR6I4h+FjBpILxbEy8JRg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.24.4': - resolution: {integrity: sha512-py5oNShCCjCyjWXCZNrRGRpjWsF0ic8f4ieBNra5buQz0O/U6mMXCpC1LvrHuhJsNPgRt36tSYMidGzZiJF6mw==} + '@rollup/rollup-freebsd-arm64@4.27.3': + resolution: {integrity: sha512-58E0tIcwZ+12nK1WiLzHOD8I0d0kdrY/+o7yFVPRHuVGY3twBwzwDdTIBGRxLmyjciMYl1B/U515GJy+yn46qw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.24.4': - resolution: {integrity: sha512-L7VVVW9FCnTTp4i7KrmHeDsDvjB4++KOBENYtNYAiYl96jeBThFfhP6HVxL74v4SiZEVDH/1ILscR5U9S4ms4g==} + '@rollup/rollup-freebsd-x64@4.27.3': + resolution: {integrity: sha512-78fohrpcVwTLxg1ZzBMlwEimoAJmY6B+5TsyAZ3Vok7YabRBUvjYTsRXPTjGEvv/mfgVBepbW28OlMEz4w8wGA==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.24.4': - resolution: {integrity: sha512-10ICosOwYChROdQoQo589N5idQIisxjaFE/PAnX2i0Zr84mY0k9zul1ArH0rnJ/fpgiqfu13TFZR5A5YJLOYZA==} + '@rollup/rollup-linux-arm-gnueabihf@4.18.1': + resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-gnueabihf@4.27.3': + resolution: {integrity: sha512-h2Ay79YFXyQi+QZKo3ISZDyKaVD7uUvukEHTOft7kh00WF9mxAaxZsNs3o/eukbeKuH35jBvQqrT61fzKfAB/Q==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.18.1': + resolution: {integrity: sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.24.4': - resolution: {integrity: sha512-ySAfWs69LYC7QhRDZNKqNhz2UKN8LDfbKSMAEtoEI0jitwfAG2iZwVqGACJT+kfYvvz3/JgsLlcBP+WWoKCLcw==} + '@rollup/rollup-linux-arm-musleabihf@4.27.3': + resolution: {integrity: sha512-Sv2GWmrJfRY57urktVLQ0VKZjNZGogVtASAgosDZ1aUB+ykPxSi3X1nWORL5Jk0sTIIwQiPH7iE3BMi9zGWfkg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.24.4': - resolution: {integrity: sha512-uHYJ0HNOI6pGEeZ/5mgm5arNVTI0nLlmrbdph+pGXpC9tFHFDQmDMOEqkmUObRfosJqpU8RliYoGz06qSdtcjg==} + '@rollup/rollup-linux-arm64-gnu@4.18.1': + resolution: {integrity: sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.27.3': + resolution: {integrity: sha512-FPoJBLsPW2bDNWjSrwNuTPUt30VnfM8GPGRoLCYKZpPx0xiIEdFip3dH6CqgoT0RnoGXptaNziM0WlKgBc+OWQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.18.1': + resolution: {integrity: sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.24.4': - resolution: {integrity: sha512-38yiWLemQf7aLHDgTg85fh3hW9stJ0Muk7+s6tIkSUOMmi4Xbv5pH/5Bofnsb6spIwD5FJiR+jg71f0CH5OzoA==} + '@rollup/rollup-linux-arm64-musl@4.27.3': + resolution: {integrity: sha512-TKxiOvBorYq4sUpA0JT+Fkh+l+G9DScnG5Dqx7wiiqVMiRSkzTclP35pE6eQQYjP4Gc8yEkJGea6rz4qyWhp3g==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.24.4': - resolution: {integrity: sha512-q73XUPnkwt9ZNF2xRS4fvneSuaHw2BXuV5rI4cw0fWYVIWIBeDZX7c7FWhFQPNTnE24172K30I+dViWRVD9TwA==} + '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': + resolution: {integrity: sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.24.4': - resolution: {integrity: sha512-Aie/TbmQi6UXokJqDZdmTJuZBCU3QBDA8oTKRGtd4ABi/nHgXICulfg1KI6n9/koDsiDbvHAiQO3YAUNa/7BCw==} + '@rollup/rollup-linux-powerpc64le-gnu@4.27.3': + resolution: {integrity: sha512-v2M/mPvVUKVOKITa0oCFksnQQ/TqGrT+yD0184/cWHIu0LoIuYHwox0Pm3ccXEz8cEQDLk6FPKd1CCm+PlsISw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.18.1': + resolution: {integrity: sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.27.3': + resolution: {integrity: sha512-LdrI4Yocb1a/tFVkzmOE5WyYRgEBOyEhWYJe4gsDWDiwnjYKjNs7PS6SGlTDB7maOHF4kxevsuNBl2iOcj3b4A==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.24.4': - resolution: {integrity: sha512-P8MPErVO/y8ohWSP9JY7lLQ8+YMHfTI4bAdtCi3pC2hTeqFJco2jYspzOzTUB8hwUWIIu1xwOrJE11nP+0JFAQ==} + '@rollup/rollup-linux-s390x-gnu@4.18.1': + resolution: {integrity: sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.27.3': + resolution: {integrity: sha512-d4wVu6SXij/jyiwPvI6C4KxdGzuZOvJ6y9VfrcleHTwo68fl8vZC5ZYHsCVPUi4tndCfMlFniWgwonQ5CUpQcA==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.24.4': - resolution: {integrity: sha512-K03TljaaoPK5FOyNMZAAEmhlyO49LaE4qCsr0lYHUKyb6QacTNF9pnfPpXnFlFD3TXuFbFbz7tJ51FujUXkXYA==} + '@rollup/rollup-linux-x64-gnu@4.18.1': + resolution: {integrity: sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.27.3': + resolution: {integrity: sha512-/6bn6pp1fsCGEY5n3yajmzZQAh+mW4QPItbiWxs69zskBzJuheb3tNynEjL+mKOsUSFK11X4LYF2BwwXnzWleA==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.24.4': - resolution: {integrity: sha512-VJYl4xSl/wqG2D5xTYncVWW+26ICV4wubwN9Gs5NrqhJtayikwCXzPL8GDsLnaLU3WwhQ8W02IinYSFJfyo34Q==} + '@rollup/rollup-linux-x64-musl@4.18.1': + resolution: {integrity: sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.24.4': - resolution: {integrity: sha512-ku2GvtPwQfCqoPFIJCqZ8o7bJcj+Y54cZSr43hHca6jLwAiCbZdBUOrqE6y29QFajNAzzpIOwsckaTFmN6/8TA==} + '@rollup/rollup-linux-x64-musl@4.27.3': + resolution: {integrity: sha512-nBXOfJds8OzUT1qUreT/en3eyOXd2EH5b0wr2bVB5999qHdGKkzGzIyKYaKj02lXk6wpN71ltLIaQpu58YFBoQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.18.1': + resolution: {integrity: sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-arm64-msvc@4.27.3': + resolution: {integrity: sha512-ogfbEVQgIZOz5WPWXF2HVb6En+kWzScuxJo/WdQTqEgeyGkaa2ui5sQav9Zkr7bnNCLK48uxmmK0TySm22eiuw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.24.4': - resolution: {integrity: sha512-V3nCe+eTt/W6UYNr/wGvO1fLpHUrnlirlypZfKCT1fG6hWfqhPgQV/K/mRBXBpxc0eKLIF18pIOFVPh0mqHjlg==} + '@rollup/rollup-win32-ia32-msvc@4.18.1': + resolution: {integrity: sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.27.3': + resolution: {integrity: sha512-ecE36ZBMLINqiTtSNQ1vzWc5pXLQHlf/oqGp/bSbi7iedcjcNb6QbCBNG73Euyy2C+l/fn8qKWEwxr+0SSfs3w==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.24.4': - resolution: {integrity: sha512-LTw1Dfd0mBIEqUVCxbvTE/LLo+9ZxVC9k99v1v4ahg9Aak6FpqOfNu5kRkeTAn0wphoC4JU7No1/rL+bBCEwhg==} + '@rollup/rollup-win32-x64-msvc@4.18.1': + resolution: {integrity: sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==} cpu: [x64] os: [win32] - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@rollup/rollup-win32-x64-msvc@4.27.3': + resolution: {integrity: sha512-vliZLrDmYKyaUoMzEbMTg2JkerfBjn03KmAw9CykO0Zzkzoyd7o3iZNam/TpyWNjNT+Cz2iO3P9Smv2wgrR+Eg==} + cpu: [x64] + os: [win32] '@segment/loosely-validate-event@2.0.0': resolution: {integrity: sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==} + '@sideway/address@4.1.5': + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + + '@sideway/formula@3.0.1': + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + + '@sideway/pinpoint@2.0.0': + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -3322,114 +3800,237 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - '@smithy/abort-controller@3.1.6': - resolution: {integrity: sha512-0XuhuHQlEqbNQZp7QxxrFTdVWdwxch4vjxYgfInF91hZFkPxf9QDrdQka0KfxFMPqLNzSw0b95uGTrLliQUavQ==} - engines: {node: '>=16.0.0'} + '@smithy/abort-controller@2.2.0': + resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==} + engines: {node: '>=14.0.0'} - '@smithy/config-resolver@3.0.10': - resolution: {integrity: sha512-Uh0Sz9gdUuz538nvkPiyv1DZRX9+D15EKDtnQP5rYVAzM/dnYk3P8cg73jcxyOitPgT3mE3OVj7ky7sibzHWkw==} + '@smithy/abort-controller@3.0.0': + resolution: {integrity: sha512-p6GlFGBt9K4MYLu72YuJ523NVR4A8oHlC5M2JO6OmQqN8kAc/uh1JqLE+FizTokrSJGg0CSvC+BrsmGzKtsZKA==} engines: {node: '>=16.0.0'} - '@smithy/core@2.5.1': - resolution: {integrity: sha512-DujtuDA7BGEKExJ05W5OdxCoyekcKT3Rhg1ZGeiUWaz2BJIWXjZmsG/DIP4W48GHno7AQwRsaCb8NcBgH3QZpg==} - engines: {node: '>=16.0.0'} + '@smithy/config-resolver@2.2.0': + resolution: {integrity: sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==} + engines: {node: '>=14.0.0'} - '@smithy/credential-provider-imds@3.2.5': - resolution: {integrity: sha512-4FTQGAsuwqTzVMmiRVTn0RR9GrbRfkP0wfu/tXWVHd2LgNpTY0uglQpIScXK4NaEyXbB3JmZt8gfVqO50lP8wg==} + '@smithy/config-resolver@3.0.0': + resolution: {integrity: sha512-2GzOfADwYLQugYkKQhIyZyQlM05K+tMKvRnc6eFfZcpJGRfKoMUMYdPlBKmqHwQFXQKBrGV6cxL9oymWgDzvFw==} engines: {node: '>=16.0.0'} - '@smithy/fetch-http-handler@4.0.0': - resolution: {integrity: sha512-MLb1f5tbBO2X6K4lMEKJvxeLooyg7guq48C2zKr4qM7F2Gpkz4dc+hdSgu77pCJ76jVqFBjZczHYAs6dp15N+g==} + '@smithy/core@1.4.2': + resolution: {integrity: sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==} + engines: {node: '>=14.0.0'} - '@smithy/hash-node@3.0.8': - resolution: {integrity: sha512-tlNQYbfpWXHimHqrvgo14DrMAgUBua/cNoz9fMYcDmYej7MAmUcjav/QKQbFc3NrcPxeJ7QClER4tWZmfwoPng==} + '@smithy/core@2.0.1': + resolution: {integrity: sha512-rcMkjvwxH/bER+oZUPR0yTA0ELD6m3A+d92+CFkdF6HJFCBB1bXo7P5pm21L66XwTN01B6bUhSCQ7cymWRD8zg==} engines: {node: '>=16.0.0'} - '@smithy/invalid-dependency@3.0.8': - resolution: {integrity: sha512-7Qynk6NWtTQhnGTTZwks++nJhQ1O54Mzi7fz4PqZOiYXb4Z1Flpb2yRvdALoggTS8xjtohWUM+RygOtB30YL3Q==} - - '@smithy/is-array-buffer@2.2.0': - resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + '@smithy/credential-provider-imds@2.3.0': + resolution: {integrity: sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==} engines: {node: '>=14.0.0'} - '@smithy/is-array-buffer@3.0.0': - resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==} + '@smithy/credential-provider-imds@3.0.0': + resolution: {integrity: sha512-lfmBiFQcA3FsDAPxNfY0L7CawcWtbyWsBOHo34nF095728JLkBX4Y9q/VPPE2r7fqMVK+drmDigqE2/SSQeVRA==} engines: {node: '>=16.0.0'} - '@smithy/middleware-content-length@3.0.10': - resolution: {integrity: sha512-T4dIdCs1d/+/qMpwhJ1DzOhxCZjZHbHazEPJWdB4GDi2HjIZllVzeBEcdJUN0fomV8DURsgOyrbEUzg3vzTaOg==} - engines: {node: '>=16.0.0'} + '@smithy/eventstream-codec@2.2.0': + resolution: {integrity: sha512-8janZoJw85nJmQZc4L8TuePp2pk1nxLgkxIR0TUjKJ5Dkj5oelB9WtiSSGXCQvNsJl0VSTvK/2ueMXxvpa9GVw==} - '@smithy/middleware-endpoint@3.2.1': - resolution: {integrity: sha512-wWO3xYmFm6WRW8VsEJ5oU6h7aosFXfszlz3Dj176pTij6o21oZnzkCLzShfmRaaCHDkBXWBdO0c4sQAvLFP6zA==} - engines: {node: '>=16.0.0'} + '@smithy/eventstream-serde-browser@2.2.0': + resolution: {integrity: sha512-UaPf8jKbcP71BGiO0CdeLmlg+RhWnlN8ipsMSdwvqBFigl5nil3rHOI/5GE3tfiuX8LvY5Z9N0meuU7Rab7jWw==} + engines: {node: '>=14.0.0'} - '@smithy/middleware-retry@3.0.25': - resolution: {integrity: sha512-m1F70cPaMBML4HiTgCw5I+jFNtjgz5z5UdGnUbG37vw6kh4UvizFYjqJGHvicfgKMkDL6mXwyPp5mhZg02g5sg==} - engines: {node: '>=16.0.0'} + '@smithy/eventstream-serde-config-resolver@2.2.0': + resolution: {integrity: sha512-RHhbTw/JW3+r8QQH7PrganjNCiuiEZmpi6fYUAetFfPLfZ6EkiA08uN3EFfcyKubXQxOwTeJRZSQmDDCdUshaA==} + engines: {node: '>=14.0.0'} + + '@smithy/eventstream-serde-node@2.2.0': + resolution: {integrity: sha512-zpQMtJVqCUMn+pCSFcl9K/RPNtQE0NuMh8sKpCdEHafhwRsjP50Oq/4kMmvxSRy6d8Jslqd8BLvDngrUtmN9iA==} + engines: {node: '>=14.0.0'} + + '@smithy/eventstream-serde-universal@2.2.0': + resolution: {integrity: sha512-pvoe/vvJY0mOpuF84BEtyZoYfbehiFj8KKWk1ds2AT0mTLYFVs+7sBJZmioOFdBXKd48lfrx1vumdPdmGlCLxA==} + engines: {node: '>=14.0.0'} + + '@smithy/fetch-http-handler@2.5.0': + resolution: {integrity: sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==} + + '@smithy/fetch-http-handler@3.0.1': + resolution: {integrity: sha512-uaH74i5BDj+rBwoQaXioKpI0SHBJFtOVwzrCpxZxphOW0ki5jhj7dXvDMYM2IJem8TpdFvS2iC08sjOblfFGFg==} + + '@smithy/hash-node@2.2.0': + resolution: {integrity: sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==} + engines: {node: '>=14.0.0'} + + '@smithy/hash-node@3.0.0': + resolution: {integrity: sha512-84qXstNemP3XS5jcof0el6+bDfjzuvhJPQTEfro3lgtbCtKgzPm3MgiS6ehXVPjeQ5+JS0HqmTz8f/RYfzHVxw==} + engines: {node: '>=16.0.0'} + + '@smithy/invalid-dependency@2.2.0': + resolution: {integrity: sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==} + + '@smithy/invalid-dependency@3.0.0': + resolution: {integrity: sha512-F6wBBaEFgJzj0s4KUlliIGPmqXemwP6EavgvDqYwCH40O5Xr2iMHvS8todmGVZtuJCorBkXsYLyTu4PuizVq5g==} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@3.0.0': + resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==} + engines: {node: '>=16.0.0'} + + '@smithy/middleware-content-length@2.2.0': + resolution: {integrity: sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-content-length@3.0.0': + resolution: {integrity: sha512-3C4s4d/iGobgCtk2tnWW6+zSTOBg1PRAm2vtWZLdriwTroFbbWNSr3lcyzHdrQHnEXYCC5K52EbpfodaIUY8sg==} + engines: {node: '>=16.0.0'} + + '@smithy/middleware-endpoint@2.5.1': + resolution: {integrity: sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-endpoint@3.0.0': + resolution: {integrity: sha512-aXOAWztw/5qAfp0NcA2OWpv6ZI/E+Dh9mByif7i91D/0iyYNUcKvskmXiowKESFkuZ7PIMd3VOR4fTibZDs2OQ==} + engines: {node: '>=16.0.0'} + + '@smithy/middleware-retry@2.3.1': + resolution: {integrity: sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-retry@3.0.1': + resolution: {integrity: sha512-hBhSEuL841FhJBK/19WpaGk5YWSzFk/P2UaVjANGKRv3eYNO8Y1lANWgqnuPWjOyCEWMPr58vELFDWpxvRKANw==} + engines: {node: '>=16.0.0'} + + '@smithy/middleware-serde@2.3.0': + resolution: {integrity: sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==} + engines: {node: '>=14.0.0'} - '@smithy/middleware-serde@3.0.8': - resolution: {integrity: sha512-Xg2jK9Wc/1g/MBMP/EUn2DLspN8LNt+GMe7cgF+Ty3vl+Zvu+VeZU5nmhveU+H8pxyTsjrAkci8NqY6OuvZnjA==} + '@smithy/middleware-serde@3.0.0': + resolution: {integrity: sha512-I1vKG1foI+oPgG9r7IMY1S+xBnmAn1ISqployvqkwHoSb8VPsngHDTOgYGYBonuOKndaWRUGJZrKYYLB+Ane6w==} engines: {node: '>=16.0.0'} - '@smithy/middleware-stack@3.0.8': - resolution: {integrity: sha512-d7ZuwvYgp1+3682Nx0MD3D/HtkmZd49N3JUndYWQXfRZrYEnCWYc8BHcNmVsPAp9gKvlurdg/mubE6b/rPS9MA==} + '@smithy/middleware-stack@2.2.0': + resolution: {integrity: sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-stack@3.0.0': + resolution: {integrity: sha512-+H0jmyfAyHRFXm6wunskuNAqtj7yfmwFB6Fp37enytp2q047/Od9xetEaUbluyImOlGnGpaVGaVfjwawSr+i6Q==} engines: {node: '>=16.0.0'} - '@smithy/node-config-provider@3.1.9': - resolution: {integrity: sha512-qRHoah49QJ71eemjuS/WhUXB+mpNtwHRWQr77J/m40ewBVVwvo52kYAmb7iuaECgGTTcYxHS4Wmewfwy++ueew==} + '@smithy/node-config-provider@2.3.0': + resolution: {integrity: sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==} + engines: {node: '>=14.0.0'} + + '@smithy/node-config-provider@3.0.0': + resolution: {integrity: sha512-buqfaSdDh0zo62EPLf8rGDvcpKwGpO5ho4bXS2cdFhlOta7tBkWJt+O5uiaAeICfIOfPclNOndshDNSanX2X9g==} engines: {node: '>=16.0.0'} - '@smithy/node-http-handler@3.2.5': - resolution: {integrity: sha512-PkOwPNeKdvX/jCpn0A8n9/TyoxjGZB8WVoJmm9YzsnAgggTj4CrjpRHlTQw7dlLZ320n1mY1y+nTRUDViKi/3w==} + '@smithy/node-http-handler@2.5.0': + resolution: {integrity: sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==} + engines: {node: '>=14.0.0'} + + '@smithy/node-http-handler@3.0.0': + resolution: {integrity: sha512-3trD4r7NOMygwLbUJo4eodyQuypAWr7uvPnebNJ9a70dQhVn+US8j/lCnvoJS6BXfZeF7PkkkI0DemVJw+n+eQ==} engines: {node: '>=16.0.0'} - '@smithy/property-provider@3.1.8': - resolution: {integrity: sha512-ukNUyo6rHmusG64lmkjFeXemwYuKge1BJ8CtpVKmrxQxc6rhUX0vebcptFA9MmrGsnLhwnnqeH83VTU9hwOpjA==} + '@smithy/property-provider@2.2.0': + resolution: {integrity: sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==} + engines: {node: '>=14.0.0'} + + '@smithy/property-provider@3.0.0': + resolution: {integrity: sha512-LmbPgHBswdXCrkWWuUwBm9w72S2iLWyC/5jet9/Y9cGHtzqxi+GVjfCfahkvNV4KXEwgnH8EMpcrD9RUYe0eLQ==} engines: {node: '>=16.0.0'} - '@smithy/protocol-http@4.1.5': - resolution: {integrity: sha512-hsjtwpIemmCkm3ZV5fd/T0bPIugW1gJXwZ/hpuVubt2hEUApIoUTrf6qIdh9MAWlw0vjMrA1ztJLAwtNaZogvg==} + '@smithy/protocol-http@3.3.0': + resolution: {integrity: sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==} + engines: {node: '>=14.0.0'} + + '@smithy/protocol-http@4.0.0': + resolution: {integrity: sha512-qOQZOEI2XLWRWBO9AgIYuHuqjZ2csyr8/IlgFDHDNuIgLAMRx2Bl8ck5U5D6Vh9DPdoaVpuzwWMa0xcdL4O/AQ==} engines: {node: '>=16.0.0'} - '@smithy/querystring-builder@3.0.8': - resolution: {integrity: sha512-btYxGVqFUARbUrN6VhL9c3dnSviIwBYD9Rz1jHuN1hgh28Fpv2xjU1HeCeDJX68xctz7r4l1PBnFhGg1WBBPuA==} + '@smithy/querystring-builder@2.2.0': + resolution: {integrity: sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==} + engines: {node: '>=14.0.0'} + + '@smithy/querystring-builder@3.0.0': + resolution: {integrity: sha512-bW8Fi0NzyfkE0TmQphDXr1AmBDbK01cA4C1Z7ggwMAU5RDz5AAv/KmoRwzQAS0kxXNf/D2ALTEgwK0U2c4LtRg==} engines: {node: '>=16.0.0'} - '@smithy/querystring-parser@3.0.8': - resolution: {integrity: sha512-BtEk3FG7Ks64GAbt+JnKqwuobJNX8VmFLBsKIwWr1D60T426fGrV2L3YS5siOcUhhp6/Y6yhBw1PSPxA5p7qGg==} + '@smithy/querystring-parser@2.2.0': + resolution: {integrity: sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==} + engines: {node: '>=14.0.0'} + + '@smithy/querystring-parser@3.0.0': + resolution: {integrity: sha512-UzHwthk0UEccV4dHzPySnBy34AWw3V9lIqUTxmozQ+wPDAO9csCWMfOLe7V9A2agNYy7xE+Pb0S6K/J23JSzfQ==} engines: {node: '>=16.0.0'} - '@smithy/service-error-classification@3.0.8': - resolution: {integrity: sha512-uEC/kCCFto83bz5ZzapcrgGqHOh/0r69sZ2ZuHlgoD5kYgXJEThCoTuw/y1Ub3cE7aaKdznb+jD9xRPIfIwD7g==} + '@smithy/service-error-classification@2.1.5': + resolution: {integrity: sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==} + engines: {node: '>=14.0.0'} + + '@smithy/service-error-classification@3.0.0': + resolution: {integrity: sha512-3BsBtOUt2Gsnc3X23ew+r2M71WwtpHfEDGhHYHSDg6q1t8FrWh15jT25DLajFV1H+PpxAJ6gqe9yYeRUsmSdFA==} engines: {node: '>=16.0.0'} - '@smithy/shared-ini-file-loader@3.1.9': - resolution: {integrity: sha512-/+OsJRNtoRbtsX0UpSgWVxFZLsJHo/4sTr+kBg/J78sr7iC+tHeOvOJrS5hCpVQ6sWBbhWLp1UNiuMyZhE6pmA==} + '@smithy/shared-ini-file-loader@2.4.0': + resolution: {integrity: sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==} + engines: {node: '>=14.0.0'} + + '@smithy/shared-ini-file-loader@3.0.0': + resolution: {integrity: sha512-REVw6XauXk8xE4zo5aGL7Rz4ywA8qNMUn8RtWeTRQsgAlmlvbJ7CEPBcaXU2NDC3AYBgYAXrGyWD8XrN8UGDog==} engines: {node: '>=16.0.0'} - '@smithy/signature-v4@4.2.1': - resolution: {integrity: sha512-NsV1jF4EvmO5wqmaSzlnTVetemBS3FZHdyc5CExbDljcyJCEEkJr8ANu2JvtNbVg/9MvKAWV44kTrGS+Pi4INg==} + '@smithy/signature-v4@2.3.0': + resolution: {integrity: sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==} + engines: {node: '>=14.0.0'} + + '@smithy/signature-v4@3.0.0': + resolution: {integrity: sha512-kXFOkNX+BQHe2qnLxpMEaCRGap9J6tUGLzc3A9jdn+nD4JdMwCKTJ+zFwQ20GkY+mAXGatyTw3HcoUlR39HwmA==} engines: {node: '>=16.0.0'} - '@smithy/smithy-client@3.4.2': - resolution: {integrity: sha512-dxw1BDxJiY9/zI3cBqfVrInij6ShjpV4fmGHesGZZUiP9OSE/EVfdwdRz0PgvkEvrZHpsj2htRaHJfftE8giBA==} + '@smithy/smithy-client@2.5.1': + resolution: {integrity: sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==} + engines: {node: '>=14.0.0'} + + '@smithy/smithy-client@3.0.1': + resolution: {integrity: sha512-KAiFY4Y4jdHxR+4zerH/VBhaFKM8pbaVmJZ/CWJRwtM/CmwzTfXfvYwf6GoUwiHepdv+lwiOXCuOl6UBDUEINw==} engines: {node: '>=16.0.0'} - '@smithy/types@3.6.0': - resolution: {integrity: sha512-8VXK/KzOHefoC65yRgCn5vG1cysPJjHnOVt9d0ybFQSmJgQj152vMn4EkYhGuaOmnnZvCPav/KnYyE6/KsNZ2w==} + '@smithy/types@2.12.0': + resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==} + engines: {node: '>=14.0.0'} + + '@smithy/types@3.0.0': + resolution: {integrity: sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==} engines: {node: '>=16.0.0'} - '@smithy/url-parser@3.0.8': - resolution: {integrity: sha512-4FdOhwpTW7jtSFWm7SpfLGKIBC9ZaTKG5nBF0wK24aoQKQyDIKUw3+KFWCQ9maMzrgTJIuOvOnsV2lLGW5XjTg==} + '@smithy/url-parser@2.2.0': + resolution: {integrity: sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==} + + '@smithy/url-parser@3.0.0': + resolution: {integrity: sha512-2XLazFgUu+YOGHtWihB3FSLAfCUajVfNBXGGYjOaVKjLAuAxx3pSBY3hBgLzIgB17haf59gOG3imKqTy8mcrjw==} + + '@smithy/util-base64@2.3.0': + resolution: {integrity: sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==} + engines: {node: '>=14.0.0'} '@smithy/util-base64@3.0.0': resolution: {integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==} engines: {node: '>=16.0.0'} + '@smithy/util-body-length-browser@2.2.0': + resolution: {integrity: sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==} + '@smithy/util-body-length-browser@3.0.0': resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==} + '@smithy/util-body-length-node@2.3.0': + resolution: {integrity: sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==} + engines: {node: '>=14.0.0'} + '@smithy/util-body-length-node@3.0.0': resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==} engines: {node: '>=16.0.0'} @@ -3442,38 +4043,74 @@ packages: resolution: {integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==} engines: {node: '>=16.0.0'} + '@smithy/util-config-provider@2.3.0': + resolution: {integrity: sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==} + engines: {node: '>=14.0.0'} + '@smithy/util-config-provider@3.0.0': resolution: {integrity: sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==} engines: {node: '>=16.0.0'} - '@smithy/util-defaults-mode-browser@3.0.25': - resolution: {integrity: sha512-fRw7zymjIDt6XxIsLwfJfYUfbGoO9CmCJk6rjJ/X5cd20+d2Is7xjU5Kt/AiDt6hX8DAf5dztmfP5O82gR9emA==} + '@smithy/util-defaults-mode-browser@2.2.1': + resolution: {integrity: sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==} + engines: {node: '>= 10.0.0'} + + '@smithy/util-defaults-mode-browser@3.0.1': + resolution: {integrity: sha512-nW5kEzdJn1Bn5TF+gOPHh2rcPli8JU9vSSXLbfg7uPnfR1TMRQqs9zlYRhIb87NeSxIbpdXOI94tvXSy+fvDYg==} + engines: {node: '>= 10.0.0'} + + '@smithy/util-defaults-mode-node@2.3.1': + resolution: {integrity: sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==} engines: {node: '>= 10.0.0'} - '@smithy/util-defaults-mode-node@3.0.25': - resolution: {integrity: sha512-H3BSZdBDiVZGzt8TG51Pd2FvFO0PAx/A0mJ0EH8a13KJ6iUCdYnw/Dk/MdC1kTd0eUuUGisDFaxXVXo4HHFL1g==} + '@smithy/util-defaults-mode-node@3.0.1': + resolution: {integrity: sha512-TFk+Qb+elLc/MOhtSp+50fstyfZ6avQbgH2d96xUBpeScu+Al9elxv+UFAjaTHe0HQe5n+wem8ZLpXvU8lwV6Q==} engines: {node: '>= 10.0.0'} - '@smithy/util-endpoints@2.1.4': - resolution: {integrity: sha512-kPt8j4emm7rdMWQyL0F89o92q10gvCUa6sBkBtDJ7nV2+P7wpXczzOfoDJ49CKXe5CCqb8dc1W+ZdLlrKzSAnQ==} + '@smithy/util-endpoints@1.2.0': + resolution: {integrity: sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==} + engines: {node: '>= 14.0.0'} + + '@smithy/util-endpoints@2.0.0': + resolution: {integrity: sha512-+exaXzEY3DNt2qtA2OtRNSDlVrE4p32j1JSsQkzA5AdP0YtJNjkYbYhJxkFmPYcjI1abuwopOZCwUmv682QkiQ==} engines: {node: '>=16.0.0'} + '@smithy/util-hex-encoding@2.2.0': + resolution: {integrity: sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==} + engines: {node: '>=14.0.0'} + '@smithy/util-hex-encoding@3.0.0': resolution: {integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==} engines: {node: '>=16.0.0'} - '@smithy/util-middleware@3.0.8': - resolution: {integrity: sha512-p7iYAPaQjoeM+AKABpYWeDdtwQNxasr4aXQEA/OmbOaug9V0odRVDy3Wx4ci8soljE/JXQo+abV0qZpW8NX0yA==} + '@smithy/util-middleware@2.2.0': + resolution: {integrity: sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==} + engines: {node: '>=14.0.0'} + + '@smithy/util-middleware@3.0.0': + resolution: {integrity: sha512-q5ITdOnV2pXHSVDnKWrwgSNTDBAMHLptFE07ua/5Ty5WJ11bvr0vk2a7agu7qRhrCFRQlno5u3CneU5EELK+DQ==} engines: {node: '>=16.0.0'} - '@smithy/util-retry@3.0.8': - resolution: {integrity: sha512-TCEhLnY581YJ+g1x0hapPz13JFqzmh/pMWL2KEFASC51qCfw3+Y47MrTmea4bUE5vsdxQ4F6/KFbUeSz22Q1ow==} + '@smithy/util-retry@2.2.0': + resolution: {integrity: sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==} + engines: {node: '>= 14.0.0'} + + '@smithy/util-retry@3.0.0': + resolution: {integrity: sha512-nK99bvJiziGv/UOKJlDvFF45F00WgPLKVIGUfAK+mDhzVN2hb/S33uW2Tlhg5PVBoqY7tDVqL0zmu4OxAHgo9g==} engines: {node: '>=16.0.0'} - '@smithy/util-stream@3.2.1': - resolution: {integrity: sha512-R3ufuzJRxSJbE58K9AEnL/uSZyVdHzud9wLS8tIbXclxKzoe09CRohj2xV8wpx5tj7ZbiJaKYcutMm1eYgz/0A==} + '@smithy/util-stream@2.2.0': + resolution: {integrity: sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-stream@3.0.1': + resolution: {integrity: sha512-7F7VNNhAsfMRA8I986YdOY5fE0/T1/ZjFF6OLsqkvQVNP3vZ/szYDfGCyphb7ioA09r32K/0qbSFfNFU68aSzA==} engines: {node: '>=16.0.0'} + '@smithy/util-uri-escape@2.2.0': + resolution: {integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==} + engines: {node: '>=14.0.0'} + '@smithy/util-uri-escape@3.0.0': resolution: {integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==} engines: {node: '>=16.0.0'} @@ -3486,6 +4123,10 @@ packages: resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==} engines: {node: '>=16.0.0'} + '@smithy/util-waiter@2.2.0': + resolution: {integrity: sha512-IHk53BVw6MPMi2Gsn+hCng8rFA3ZmR3Rk7GllxDUW9qFJl/hiSvskn7XldkECapQVkIg/1dHpMAxI9xSTaLLSA==} + engines: {node: '>=14.0.0'} + '@tidbcloud/serverless@0.1.1': resolution: {integrity: sha512-km2P5Mgr9nqVah5p5aMYbO3dBqecSwZ0AU7+BhJH+03L2eJO6qCATcBR8UHPuVLhA7GCt3CambKvVYK79pVQ2g==} engines: {node: '>=16'} @@ -3494,8 +4135,8 @@ packages: resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} engines: {node: '>= 6'} - '@trivago/prettier-plugin-sort-imports@4.3.0': - resolution: {integrity: sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==} + '@trivago/prettier-plugin-sort-imports@4.2.0': + resolution: {integrity: sha512-YBepjbt+ZNBVmN3ev1amQH3lWCmHyt5qTbLCp/syXJRu/Kw2koXh44qayB1gMRxcL/gV8egmjN5xWSrYyfUtyw==} peerDependencies: '@vue/compiler-sfc': 3.x prettier: 2.x - 3.x @@ -3515,27 +4156,18 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - '@types/async-retry@1.4.9': - resolution: {integrity: sha512-s1ciZQJzRh3708X/m3vPExr5KJlzlZJvXsKpbtE2luqNcbROr64qU+3KpJsYHqWMeaxI839OvXf9PrUSw1Xtyg==} - - '@types/axios@0.14.4': - resolution: {integrity: sha512-9JgOaunvQdsQ/qW2OPmE5+hCeUB52lQSolecrFrthct55QekhmXEwT203s20RL+UHtCQc15y3VXpby9E7Kkh/g==} - deprecated: This is a stub types definition. axios provides its own type definitions, so you do not need this installed. + '@types/async-retry@1.4.8': + resolution: {integrity: sha512-Qup/B5PWLe86yI5I3av6ePGaeQrIHNKCwbsQotD6aHQ6YkHsMUxVZkZsmx/Ry3VZQ6uysHwTjQ7666+k6UjVJA==} - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + '@types/axios@0.14.0': + resolution: {integrity: sha512-KqQnQbdYE54D7oa/UmYVMZKq7CO4l8DEENzOKc4aBRwxCXSlJXGz83flFx5L7AWrOQnmuN3kVsRdt+GZPPjiVQ==} + deprecated: This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed! - '@types/babel__generator@7.6.8': - resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + '@types/better-sqlite3@7.6.10': + resolution: {integrity: sha512-TZBjD+yOsyrUJGmcUj6OS3JADk3+UZcNv3NOBqGkM09bZdi28fNZw8ODqbMOLfKCu7RYCO62/ldq1iHbzxqoPw==} - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.20.6': - resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} - - '@types/better-sqlite3@7.6.11': - resolution: {integrity: sha512-i8KcD3PgGtGBLl3+mMYA8PdKkButvPyARxA7IQAd6qeslht13qxb1zzO8dRCtE7U3IoJS782zDBAeoKiM695kg==} + '@types/better-sqlite3@7.6.12': + resolution: {integrity: sha512-fnQmj8lELIj7BSrZQAdBMHEHX8OZLYIHXqAKT1O7tDfLxaINzf00PMjw22r3N/xXh0w/sGHlO6SVaCQ2mj78lg==} '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} @@ -3549,17 +4181,26 @@ packages: '@types/docker-modem@3.0.6': resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} - '@types/dockerode@3.3.31': - resolution: {integrity: sha512-42R9eoVqJDSvVspV89g7RwRqfNExgievLNWoHkg7NoWIqAmavIbgQBb4oc0qRtHkxE+I3Xxvqv7qVXFABKPBTg==} + '@types/dockerode@3.3.29': + resolution: {integrity: sha512-5PRRq/yt5OT/Jf77ltIdz4EiR9+VLnPF+HpU4xGFwUqmV24Co2HKBNW3w+slqZ1CYchbcDeqJASHDYWzZCcMiQ==} + + '@types/dockerode@3.3.32': + resolution: {integrity: sha512-xxcG0g5AWKtNyh7I7wswLdFvym4Mlqks5ZlKzxEUrGHS0r0PUOfxm2T0mspwu10mHQqu3Ck3MI3V2HqvLWE1fg==} + + '@types/emscripten@1.39.11': + resolution: {integrity: sha512-dOeX2BeNA7j6BTEqJQL3ut0bRCfsyQMd5i4FT8JfHfYhAOuJPCGh0dQFbxVJxUyQ+75x6enhDdndGb624/QszA==} - '@types/emscripten@1.39.13': - resolution: {integrity: sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==} + '@types/estree@1.0.1': + resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} + + '@types/estree@1.0.5': + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/express-serve-static-core@4.19.6': - resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} + '@types/express-serve-static-core@4.19.0': + resolution: {integrity: sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==} '@types/express@4.17.21': resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} @@ -3570,9 +4211,6 @@ packages: '@types/glob@8.1.0': resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} - '@types/graceful-fs@4.1.9': - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - '@types/http-errors@2.0.4': resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} @@ -3582,17 +4220,14 @@ packages: '@types/istanbul-lib-report@3.0.3': resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - '@types/istanbul-reports@1.1.2': - resolution: {integrity: sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==} - '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} '@types/json-diff@1.0.3': resolution: {integrity: sha512-Qvxm8fpRMv/1zZR3sQWImeRK2mBYJji20xF51Fq9Gt//Ed18u0x6/FNLogLS1xhfUWTEmDyqveJqn95ltB6Kvw==} - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/json-schema@7.0.13': + resolution: {integrity: sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==} '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} @@ -3609,29 +4244,29 @@ packages: '@types/minimatch@5.1.2': resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - '@types/minimist@1.2.5': - resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + '@types/minimist@1.2.2': + resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} - '@types/node@18.19.64': - resolution: {integrity: sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==} + '@types/node@18.15.10': + resolution: {integrity: sha512-9avDaQJczATcXgfmMAW3MIWArOO7A+m90vuCFLr8AotWf8igO/mRoYukrk2cqZVtv38tHs33retzHEilM7FpeQ==} - '@types/node@20.12.14': - resolution: {integrity: sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==} + '@types/node@18.19.33': + resolution: {integrity: sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A==} - '@types/node@20.17.6': - resolution: {integrity: sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==} + '@types/node@20.10.1': + resolution: {integrity: sha512-T2qwhjWwGH81vUEx4EXmBKsTJRXFXNZTL4v0gi01+zyBmCwzE6TyHszqX01m+QHTEq+EZNo13NeJIdEqf+Myrg==} - '@types/node@22.9.0': - resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} + '@types/node@20.12.12': + resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} - '@types/normalize-package-data@2.4.4': - resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/node@22.9.1': + resolution: {integrity: sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==} - '@types/pg@8.11.10': - resolution: {integrity: sha512-LczQUW4dbOQzsH2RQ5qoeJ6qJPdrcM/DcMLoqWQkMLMsq83J5lAX3LXjdkWdpscFy67JSOWDnh7Ny/sPFykmkg==} + '@types/normalize-package-data@2.4.1': + resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} '@types/pg@8.11.6': resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==} @@ -3642,20 +4277,20 @@ packages: '@types/pluralize@0.0.33': resolution: {integrity: sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==} - '@types/prop-types@15.7.13': - resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} + '@types/prop-types@15.7.12': + resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} - '@types/ps-tree@1.1.6': - resolution: {integrity: sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==} + '@types/ps-tree@1.1.2': + resolution: {integrity: sha512-ZREFYlpUmPQJ0esjxoG1fMvB2HNaD3z+mjqdSosZvd3RalncI9NEur73P8ZJz4YQdL64CmV1w0RuqoRUlhQRBw==} - '@types/qs@6.9.17': - resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==} + '@types/qs@6.9.15': + resolution: {integrity: sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==} '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/react@18.3.12': - resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==} + '@types/react@18.3.1': + resolution: {integrity: sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==} '@types/retry@0.12.5': resolution: {integrity: sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw==} @@ -3672,8 +4307,8 @@ packages: '@types/sql.js@1.4.9': resolution: {integrity: sha512-ep8b36RKHlgWPqjNG9ToUrPiwkhwh0AEzy883mO5Xnd+cL6VBH1EvSjBAAuxLUFF2Vn/moE3Me6v9E1Lo+48GQ==} - '@types/ssh2@1.15.1': - resolution: {integrity: sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA==} + '@types/ssh2@1.15.0': + resolution: {integrity: sha512-YcT8jP5F8NzWeevWvcyrrLB3zcneVjzYY9ZDSMAMboI+2zR1qYWFhwsyOFVzT7Jorn67vqxC0FRiw8YyG9P1ww==} '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -3684,23 +4319,23 @@ packages: '@types/uuid@9.0.8': resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} - '@types/which@3.0.4': - resolution: {integrity: sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w==} + '@types/which@3.0.0': + resolution: {integrity: sha512-ASCxdbsrwNfSMXALlC3Decif9rwDMu+80KGp5zI2RLRotfMsTv7fHL8W8VDp24wymzDyIFudhUeSCugrgRFfHQ==} - '@types/ws@8.5.13': - resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + '@types/ws@8.5.11': + resolution: {integrity: sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==} '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - '@types/yargs@13.0.12': - resolution: {integrity: sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ==} + '@types/yargs@15.0.19': + resolution: {integrity: sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==} - '@types/yargs@17.0.33': - resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@types/yargs@17.0.32': + resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} - '@typescript-eslint/eslint-plugin@6.21.0': - resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} + '@typescript-eslint/eslint-plugin@6.7.3': + resolution: {integrity: sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -3710,8 +4345,8 @@ packages: typescript: optional: true - '@typescript-eslint/eslint-plugin@7.18.0': - resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} + '@typescript-eslint/eslint-plugin@7.16.1': + resolution: {integrity: sha512-SxdPak/5bO0EnGktV05+Hq8oatjAYVY3Zh2bye9pGZy6+jwyR3LG3YKkV4YatlsgqXP28BTeVm9pqwJM96vf2A==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -3727,8 +4362,18 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/parser@6.21.0': - resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} + '@typescript-eslint/parser@6.10.0': + resolution: {integrity: sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@6.7.3': + resolution: {integrity: sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -3737,8 +4382,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@7.18.0': - resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} + '@typescript-eslint/parser@7.16.1': + resolution: {integrity: sha512-u+1Qx86jfGQ5i4JjK33/FnawZRpsLxRnKzGE6EABZ40KxVT/vWsiZFEBBHjFOljmmV3MBYOHEKi0Jm9hbAOClA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -3747,8 +4392,8 @@ packages: typescript: optional: true - '@typescript-eslint/rule-tester@6.21.0': - resolution: {integrity: sha512-twxQo4He8+AQ/YG70Xt7Fl/ImBLpi7qElxHN6/aK+U4z97JsITCG7DdIIUw5M+qKtDMCYkZCEE2If8dnHI7jWA==} + '@typescript-eslint/rule-tester@6.10.0': + resolution: {integrity: sha512-I0ZY+9ei73dlOuXwIYWsn/r/ue26Ygf4yEJPxeJRPI06YWDawmR1FI1dXL6ChAWVrmBQRvWep/1PxnV41zfcMA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@eslint/eslintrc': '>=2' @@ -3758,16 +4403,20 @@ packages: resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/scope-manager@6.21.0': - resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} + '@typescript-eslint/scope-manager@6.10.0': + resolution: {integrity: sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/scope-manager@6.7.3': + resolution: {integrity: sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/scope-manager@7.18.0': - resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} + '@typescript-eslint/scope-manager@7.16.1': + resolution: {integrity: sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/type-utils@6.21.0': - resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} + '@typescript-eslint/type-utils@6.7.3': + resolution: {integrity: sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -3776,8 +4425,8 @@ packages: typescript: optional: true - '@typescript-eslint/type-utils@7.18.0': - resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} + '@typescript-eslint/type-utils@7.16.1': + resolution: {integrity: sha512-rbu/H2MWXN4SkjIIyWcmYBjlp55VT+1G3duFOIukTNFxr9PI35pLc2ydwAfejCEitCv4uztA07q0QWanOHC7dA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -3790,12 +4439,16 @@ packages: resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/types@6.21.0': - resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} + '@typescript-eslint/types@6.10.0': + resolution: {integrity: sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/types@6.7.3': + resolution: {integrity: sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/types@7.18.0': - resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} + '@typescript-eslint/types@7.16.1': + resolution: {integrity: sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==} engines: {node: ^18.18.0 || >=20.0.0} '@typescript-eslint/typescript-estree@5.62.0': @@ -3807,8 +4460,17 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@6.21.0': - resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} + '@typescript-eslint/typescript-estree@6.10.0': + resolution: {integrity: sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/typescript-estree@6.7.3': + resolution: {integrity: sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -3816,8 +4478,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@7.18.0': - resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} + '@typescript-eslint/typescript-estree@7.16.1': + resolution: {integrity: sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -3831,14 +4493,20 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@6.21.0': - resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} + '@typescript-eslint/utils@6.10.0': + resolution: {integrity: sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + + '@typescript-eslint/utils@6.7.3': + resolution: {integrity: sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@7.18.0': - resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} + '@typescript-eslint/utils@7.16.1': + resolution: {integrity: sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -3847,12 +4515,16 @@ packages: resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/visitor-keys@6.21.0': - resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} + '@typescript-eslint/visitor-keys@6.10.0': + resolution: {integrity: sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/visitor-keys@6.7.3': + resolution: {integrity: sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/visitor-keys@7.18.0': - resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} + '@typescript-eslint/visitor-keys@7.16.1': + resolution: {integrity: sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==} engines: {node: ^18.18.0 || >=20.0.0} '@typescript/analyze-trace@0.10.1': @@ -3879,13 +4551,14 @@ packages: '@vitest/expect@1.6.0': resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} - '@vitest/expect@2.1.4': - resolution: {integrity: sha512-DOETT0Oh1avie/D/o2sgMHGrzYUFFo3zqESB2Hn70z6QB1HrS2IQ9z5DfyTqU8sg4Bpu13zZe9V4+UTNQlUeQA==} + '@vitest/expect@2.1.2': + resolution: {integrity: sha512-FEgtlN8mIUSEAAnlvn7mP8vzaWhEaAEvhSXCqrsijM7K6QqjB11qoRZYEd4AKSCDz8p0/+yH5LzhZ47qt+EyPg==} - '@vitest/mocker@2.1.4': - resolution: {integrity: sha512-Ky/O1Lc0QBbutJdW0rqLeFNbuLEyS+mIPiNdlVlp2/yhJ0SbyYqObS5IHdhferJud8MbbwMnexg4jordE5cCoQ==} + '@vitest/mocker@2.1.2': + resolution: {integrity: sha512-ExElkCGMS13JAJy+812fw1aCv2QO/LBK6CyO4WOPAzLTmve50gydOlWhgdBJPx2ztbADUq3JVI0C5U+bShaeEA==} peerDependencies: - msw: ^2.4.9 + '@vitest/spy': 2.1.2 + msw: ^2.3.5 vite: ^5.0.0 peerDependenciesMeta: msw: @@ -3893,26 +4566,26 @@ packages: vite: optional: true - '@vitest/pretty-format@2.1.4': - resolution: {integrity: sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==} + '@vitest/pretty-format@2.1.2': + resolution: {integrity: sha512-FIoglbHrSUlOJPDGIrh2bjX1sNars5HbxlcsFKCtKzu4+5lpsRhOCVcuzp0fEhAGHkPZRIXVNzPcpSlkoZ3LuA==} '@vitest/runner@1.6.0': resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} - '@vitest/runner@2.1.4': - resolution: {integrity: sha512-sKRautINI9XICAMl2bjxQM8VfCMTB0EbsBc/EDFA57V6UQevEKY/TOPOF5nzcvCALltiLfXWbq4MaAwWx/YxIA==} + '@vitest/runner@2.1.2': + resolution: {integrity: sha512-UCsPtvluHO3u7jdoONGjOSil+uON5SSvU9buQh3lP7GgUXHp78guN1wRmZDX4wGK6J10f9NUtP6pO+SFquoMlw==} '@vitest/snapshot@1.6.0': resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} - '@vitest/snapshot@2.1.4': - resolution: {integrity: sha512-3Kab14fn/5QZRog5BPj6Rs8dc4B+mim27XaKWFWHWA87R56AKjHTGcBFKpvZKDzC4u5Wd0w/qKsUIio3KzWW4Q==} + '@vitest/snapshot@2.1.2': + resolution: {integrity: sha512-xtAeNsZ++aRIYIUsek7VHzry/9AcxeULlegBvsdLncLmNCR6tR8SRjn8BbDP4naxtccvzTqZ+L1ltZlRCfBZFA==} '@vitest/spy@1.6.0': resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} - '@vitest/spy@2.1.4': - resolution: {integrity: sha512-4JOxa+UAizJgpZfaCPKK2smq9d8mmjZVPMt2kOsg/R8QkoRzydHH1qHxIYNvr1zlEaFj4SXiaaJWxq/LPLKaLg==} + '@vitest/spy@2.1.2': + resolution: {integrity: sha512-GSUi5zoy+abNRJwmFhBDC0yRuVUn8WMlQscvnbbXdKLXX9dE59YbfwXxuJ/mth6eeqIzofU8BB5XDo/Ns/qK2A==} '@vitest/ui@1.6.0': resolution: {integrity: sha512-k3Lyo+ONLOgylctiGovRKy7V4+dIN2yxstX3eY5cWFXH6WP+ooVX79YSyi0GagdTQzLmT43BF27T0s6dOIPBXA==} @@ -3922,11 +4595,11 @@ packages: '@vitest/utils@1.6.0': resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} - '@vitest/utils@2.1.4': - resolution: {integrity: sha512-MXDnZn0Awl2S86PSNIim5PWXgIAx8CIkzu35mBdSApUip6RFOGXBCf3YFyeEu8n1IHk4bWD46DeYFu9mQlFIRg==} + '@vitest/utils@2.1.2': + resolution: {integrity: sha512-zMO2KdYy6mx56btx9JvAqAZ6EyS3g49krMPPrgOp1yxGZiA93HumGk+bZ5jIZtOg5/VBYl5eBmGRQHqq4FG6uQ==} - '@xata.io/client@0.29.5': - resolution: {integrity: sha512-b55dmPVNVFOE5nj2F2G6t9l/d5yYBhIu5X5w3rznhhsriGHkrzn93tqJexIZPS77E7f/yDXcFz06KbvR3bHK5w==} + '@xata.io/client@0.29.4': + resolution: {integrity: sha512-dRff4E/wINr0SYIlOHwApo0h8jzpAHVf2RcbGMkK9Xrddbe90KmCEx/gue9hLhBOoCCp6qUht2h9BsuVPruymw==} peerDependencies: typescript: '>=4.5' @@ -3955,12 +4628,22 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + + acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} engines: {node: '>=0.4.0'} + hasBin: true - acorn@8.14.0: - resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + acorn@8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} hasBin: true @@ -3994,14 +4677,17 @@ packages: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} - ansi-escapes@6.2.1: - resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} + ansi-escapes@6.2.0: + resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==} engines: {node: '>=14.16'} ansi-escapes@7.0.0: resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} engines: {node: '>=18'} + ansi-fragments@0.2.1: + resolution: {integrity: sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==} + ansi-regex@4.1.1: resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} engines: {node: '>=6'} @@ -4010,6 +4696,10 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + ansi-regex@6.1.0: resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} @@ -4040,6 +4730,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + appdirsjs@1.2.7: + resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==} + application-config-path@0.1.1: resolution: {integrity: sha512-zy9cHePtMP0YhwG+CfHm0bgwdnga2X3gZexpdCwEj//dpb+TKajtiC8REEUJUSq6Ab4f9cgNy2l8ObXzCXFkEw==} @@ -4066,6 +4759,9 @@ packages: argsarray@0.0.1: resolution: {integrity: sha512-u96dg2GcAKtpTrBdDoFIM7PjcBA+6rSP0OR94MOReNRyUECL6MtQt5XXmRr4qrftYaef9+l5hcpO5te7sML1Cg==} + array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + array-buffer-byte-length@1.0.1: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} @@ -4077,24 +4773,28 @@ packages: array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + array-includes@3.1.6: + resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} engines: {node: '>= 0.4'} array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - array.prototype.findlastindex@1.2.5: - resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + array.prototype.findlastindex@1.2.2: + resolution: {integrity: sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.1: + resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} engines: {node: '>= 0.4'} - array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + array.prototype.flatmap@1.3.1: + resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} engines: {node: '>= 0.4'} - array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + arraybuffer.prototype.slice@1.0.1: + resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==} engines: {node: '>= 0.4'} arraybuffer.prototype.slice@1.0.3: @@ -4133,6 +4833,10 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} + astral-regex@1.0.0: + resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} + engines: {node: '>=4'} + async-limiter@1.0.1: resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} @@ -4146,8 +4850,8 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - ava@5.3.1: - resolution: {integrity: sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==} + ava@5.3.0: + resolution: {integrity: sha512-QYvBdyygl1LGX13IuYsC4bkwVCzZeovMGbxYkD73i7DVJxNlWnFa06YgrBOTbjw2QvSKUl5fOJ92Kj5WK9hSeg==} engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} hasBin: true peerDependencies: @@ -4156,42 +4860,33 @@ packages: '@ava/typescript': optional: true + available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - aws4fetch@1.0.20: - resolution: {integrity: sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==} + aws-ssl-profiles@1.1.1: + resolution: {integrity: sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==} + engines: {node: '>= 6.0.0'} - axios@1.7.7: - resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + axios@1.6.8: + resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} babel-core@7.0.0-bridge.0: resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} peerDependencies: '@babel/core': ^7.0.0-0 - babel-jest@29.7.0: - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.8.0 - - babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - - babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - babel-plugin-polyfill-corejs2@0.4.11: resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-polyfill-corejs3@0.10.6: - resolution: {integrity: sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==} + babel-plugin-polyfill-corejs3@0.10.4: + resolution: {integrity: sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 @@ -4200,31 +4895,14 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-react-compiler@0.0.0-experimental-592953e-20240517: - resolution: {integrity: sha512-OjG1SVaeQZaJrqkMFJatg8W/MTow8Ak5rx2SI0ETQBO1XvOk/XZGMbltNCPdFJLKghBYoBjC+Y3Ap/Xr7B01mA==} - - babel-plugin-react-native-web@0.19.13: - resolution: {integrity: sha512-4hHoto6xaN23LCyZgL9LJZc3olmAxd7b6jDzlZnKXAh4rRAbZRKNBJoOOdp46OBqgy+K0t0guTj5/mhA8inymQ==} - - babel-plugin-syntax-hermes-parser@0.23.1: - resolution: {integrity: sha512-uNLD0tk2tLUjGFdmCk+u/3FEw2o+BAwW4g+z2QVlxJrzZYOOPADroEcNtTPt5lNiScctaUmnsTkVEnOwZUOLhA==} + babel-plugin-react-native-web@0.19.12: + resolution: {integrity: sha512-eYZ4+P6jNcB37lObWIg0pUbi7+3PKoU1Oie2j0C8UF3cXyXoR74tO2NBjI/FORb2LJyItJZEAmjU5pSaJYEL1w==} babel-plugin-transform-flow-enums@0.0.2: resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} - babel-preset-current-node-syntax@1.1.0: - resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} - peerDependencies: - '@babel/core': ^7.0.0 - - babel-preset-expo@11.0.15: - resolution: {integrity: sha512-rgiMTYwqIPULaO7iZdqyL7aAff9QLOX6OWUtLZBlOrOTreGY1yHah/5+l8MvI6NVc/8Zj5LY4Y5uMSnJIuzTLw==} - - babel-preset-jest@29.6.3: - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.0.0 + babel-preset-expo@11.0.6: + resolution: {integrity: sha512-jRi9I5/jT+dnIiNJDjDg+I/pV+AlxrIW/DNbdqYoRWPZA/LHDqD6IJnJXLxbuTcQ+llp+0LWcU7f/kC/PgGpkw==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -4252,8 +4930,8 @@ packages: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} bindings@1.5.0: @@ -4268,16 +4946,13 @@ packages: blueimp-md5@2.19.0: resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} - body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + body-parser@1.20.2: + resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} bowser@2.11.0: resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - bplist-creator@0.0.7: - resolution: {integrity: sha512-xp/tcaV3T5PCiaY04mXga7o/TE+t95gqeLmADeBI1CvZtdWTbgBt3uLpvh4UWtenKeBhCV6oVxGk38yZr2uYEA==} - bplist-creator@0.1.0: resolution: {integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==} @@ -4299,8 +4974,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.24.2: - resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} + browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -4343,11 +5018,11 @@ packages: bun-types@0.6.14: resolution: {integrity: sha512-sRdvu+t59+H/TVOe7FSGFWYITbqkhiCx9NxVUHt2+JOXM9gUOe5uMPvVvcr/hGngnh+/yb5a7uPE4JaS6uxujg==} - bun-types@1.1.34: - resolution: {integrity: sha512-br5QygTEL/TwB4uQOb96Ky22j4Gq2WxWH/8Oqv20fk5HagwKXo/akB+LiYgSfzexCt6kkcUaVm+bKiPl71xPvw==} + bun-types@1.0.3: + resolution: {integrity: sha512-XlyKVdYCHa7K5PHYGcwOVOrGE/bMnLS51y7zFA3ZAAXyiQ6dTaNXNCWTTufgII/6ruN770uhAXphQmzvU/r2fQ==} - bundle-require@4.2.1: - resolution: {integrity: sha512-7Q/6vkyYAwOmQNRw75x+4yRtZCZJXUDmHHlFdkiV0wgv/reNjtJwpu1jPJ0w2kbEpIM0uoKI3S4/f39dU7AjSA==} + bundle-require@4.0.2: + resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: esbuild: '>=0.17' @@ -4362,6 +5037,10 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} + bytes@3.0.0: + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} + engines: {node: '>= 0.8'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -4374,10 +5053,13 @@ packages: resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} engines: {node: '>= 10'} - cacache@18.0.4: - resolution: {integrity: sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==} + cacache@18.0.3: + resolution: {integrity: sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==} engines: {node: ^16.14.0 || >=18.0.0} + call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} @@ -4398,8 +5080,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - callsites@4.2.0: - resolution: {integrity: sha512-kfzR4zzQtAE9PC7CzZsjl3aBNbXWuXiSeOCdLcPpBfGW8YuCqQHcRPFDbr/BPVmd3EEPVpuFzLyuT/cUhPr4OQ==} + callsites@4.1.0: + resolution: {integrity: sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==} engines: {node: '>=12.20'} camelcase@5.3.1: @@ -4414,8 +5096,8 @@ packages: resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} engines: {node: '>=14.16'} - caniuse-lite@1.0.30001679: - resolution: {integrity: sha512-j2YqID/YwpLnKzCmBOS4tlZdWprXm3ZmQLBH9ZBXFOhoxLA46fwyBvx6toCBWBmnuwUY/qB3kEU6gFx8qgCroA==} + caniuse-lite@1.0.30001624: + resolution: {integrity: sha512-0dWnQG87UevOCPYaOR49CBcLBwoZLpws+k6W37nLjWUhumP1Isusj0p2u+3KhjNloRWK9OKMgjBBzPujQHw4nA==} capnp-ts@0.7.0: resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} @@ -4428,12 +5110,12 @@ packages: resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} engines: {node: '>=12.19'} - chai@4.5.0: - resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} + chai@4.4.1: + resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} engines: {node: '>=4'} - chai@5.1.2: - resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} + chai@5.1.1: + resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} engines: {node: '>=12'} chalk@2.4.2: @@ -4462,14 +5144,14 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} + chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} - chokidar@4.0.1: - resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} - engines: {node: '>= 14.16.0'} - chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -4482,15 +5164,16 @@ packages: engines: {node: '>=12.13.0'} hasBin: true - chromium-edge-launcher@0.2.0: - resolution: {integrity: sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==} - chunkd@2.0.1: resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} ci-info@2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + ci-info@3.8.0: + resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} + engines: {node: '>=8'} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -4517,14 +5200,18 @@ packages: resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} engines: {node: '>=0.10.0'} - cli-color@2.0.4: - resolution: {integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==} + cli-color@2.0.3: + resolution: {integrity: sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==} engines: {node: '>=0.10'} cli-cursor@2.1.0: resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==} engines: {node: '>=4'} + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + cli-highlight@2.1.11: resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} engines: {node: '>=8.0.0', npm: '>=5.0.0'} @@ -4534,6 +5221,10 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} + cli-table3@0.6.3: + resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} + engines: {node: 10.* || >= 12.*} + cli-table3@0.6.5: resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} engines: {node: 10.* || >= 12.*} @@ -4542,6 +5233,9 @@ packages: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -4582,6 +5276,9 @@ packages: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + colorette@2.0.19: resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} @@ -4600,6 +5297,10 @@ packages: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} + commander@11.0.0: + resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==} + engines: {node: '>=16'} + commander@12.1.0: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} @@ -4628,6 +5329,14 @@ packages: component-type@1.2.2: resolution: {integrity: sha512-99VUHREHiN5cLeHm3YLq312p6v+HUEcwtLCAtelvUDI6+SH5g5Cr85oNR2S1o6ywzL0ykMbuwLzM2ANocjEOIA==} + compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + + compression@1.7.4: + resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} + engines: {node: '>= 0.8.0'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -4635,13 +5344,13 @@ packages: resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} - concurrently@8.2.2: - resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} + concurrently@8.2.1: + resolution: {integrity: sha512-nVraf3aXOpIcNud5pB9M82p1tynmZkrSGQ1p6X/VY8cJ+2LMVqAgXsJxYYefACSHbTYlm92O1xuhdGTjwoEvbQ==} engines: {node: ^14.13.0 || >=16.0.0} hasBin: true - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + confbox@0.1.7: + resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} connect@3.7.0: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} @@ -4672,12 +5381,12 @@ packages: cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - cookie@0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} copy-anything@3.0.5: @@ -4688,8 +5397,8 @@ packages: resolution: {integrity: sha512-mFsNh/DIANLqFt5VHZoGirdg7bK5+oTWlhnGu6tgRhzBlnEKWaPX2xrFaLltii/6rmhqFMJqffUgknuRdpYlHw==} engines: {node: '>=18'} - core-js-compat@3.39.0: - resolution: {integrity: sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==} + core-js-compat@3.37.1: + resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -4734,8 +5443,8 @@ packages: resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} engines: {node: '>=4.8'} - cross-spawn@7.0.5: - resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==} + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} crypt@0.0.2: @@ -4756,9 +5465,8 @@ packages: resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} engines: {node: '>=0.10.0'} - d@1.0.2: - resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} - engines: {node: '>=0.12'} + d@1.0.1: + resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} dag-map@1.0.2: resolution: {integrity: sha512-+LSAiGFwQ9dRnRdOeaj7g47ZFJcOUPukAP8J3A3fuZ1g9Y44BG+P1sgApjLXTQPOzC4+7S9Wr8kXsfpINM4jpw==} @@ -4786,13 +5494,16 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} - date-fns@4.1.0: - resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + date-fns@3.6.0: + resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} date-time@3.1.0: resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} engines: {node: '>=6'} + dayjs@1.11.11: + resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -4818,6 +5529,15 @@ packages: supports-color: optional: true + debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -4827,12 +5547,16 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} - deep-eql@4.1.4: - resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} + deep-eql@4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} deep-eql@5.0.2: @@ -4846,6 +5570,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + default-gateway@4.2.0: resolution: {integrity: sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==} engines: {node: '>=6'} @@ -4861,6 +5589,10 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} + define-properties@1.2.0: + resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} + engines: {node: '>= 0.4'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -4919,8 +5651,8 @@ packages: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} - diff@5.2.0: - resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + diff@5.1.0: + resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} engines: {node: '>=0.3.1'} difflib@0.2.4: @@ -5044,8 +5776,8 @@ packages: sqlite3: optional: true - drizzle-prisma-generator@0.1.7: - resolution: {integrity: sha512-KW+Z6W4hjvsiOCCPEmGyO+Oal7KPv2yQ3uZzHasaVIn+gUWGrkcy8BCDEp1h7uRBRSAd/l17EM4DfljhgYXxBw==} + drizzle-prisma-generator@0.1.4: + resolution: {integrity: sha512-6gY17/wTWfNF40rKjiYeWdkU8Gi6FQiOlU4oXa8uuo3ZZ8E6FH3250AhgCOMWAKZLpjQnk8FSzS0GXzwHkShkQ==} hasBin: true duplexer@0.1.2: @@ -5057,8 +5789,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.55: - resolution: {integrity: sha512-6maZ2ASDOTBtjt9FhqYPRnbvKU5tjG0IN9SztUOWYw2AzNDNpKJYLJmlK0/En4Hs/aiWnB+JZ+gW19PIGszgKg==} + electron-to-chromium@1.4.783: + resolution: {integrity: sha512-bT0jEz/Xz1fahQpbZ1D7LgmPYZ3iHVY39NcWWro1+hA2IvjiPeaXtfSqrQ+nXjApMvQRE2ASt1itSLRrebHMRQ==} emittery@1.0.3: resolution: {integrity: sha512-tJdCJitoy2lrC2ldJcqN4vkqJ00lT+tOWNT1hBJjO/3FDMJa5TTIiYGCKGkn/WfCyOzUMObeohbVTj00fhiLiA==} @@ -5077,10 +5809,6 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} @@ -5099,6 +5827,11 @@ packages: resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + envinfo@7.13.0: + resolution: {integrity: sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==} + engines: {node: '>=4'} + hasBin: true + environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} @@ -5115,6 +5848,14 @@ packages: error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + errorhandler@1.5.1: + resolution: {integrity: sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==} + engines: {node: '>= 0.8'} + + es-abstract@1.22.1: + resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==} + engines: {node: '>= 0.4'} + es-abstract@1.23.3: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} @@ -5131,27 +5872,30 @@ packages: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} engines: {node: '>= 0.4'} + es-set-tostringtag@2.0.1: + resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} + engines: {node: '>= 0.4'} + es-set-tostringtag@2.0.3: resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} - es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + es-shim-unscopables@1.0.0: + resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} - es5-ext@0.10.64: - resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} + es5-ext@0.10.62: + resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} engines: {node: '>=0.10'} es6-iterator@2.0.3: resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - es6-symbol@3.1.4: - resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} - engines: {node: '>=0.12'} + es6-symbol@3.1.3: + resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} es6-weak-map@2.0.3: resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} @@ -5246,11 +5990,11 @@ packages: cpu: [x64] os: [netbsd] - esbuild-node-externals@1.15.0: - resolution: {integrity: sha512-lM5f3CQL9Ctv6mBwwYAEMcphK2qrjVRnemT1mufECpFaidZvFVvQDPcuno/MQfLVk4utVuSVxm1RHLyg/ONQ/A==} + esbuild-node-externals@1.14.0: + resolution: {integrity: sha512-jMWnTlCII3cLEjR5+u0JRSTJuP+MgbjEHKfwSIAI41NgLQ0ZjfzjchlbEn0r7v2u5gCBMSEYvYlkO7GDG8gG3A==} engines: {node: '>=12'} peerDependencies: - esbuild: 0.12 - 0.24 + esbuild: 0.12 - 0.23 esbuild-openbsd-64@0.14.54: resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} @@ -5258,8 +6002,8 @@ packages: cpu: [x64] os: [openbsd] - esbuild-register@3.6.0: - resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} + esbuild-register@3.5.0: + resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==} peerDependencies: esbuild: '>=0.12 <1' @@ -5307,23 +6051,27 @@ packages: engines: {node: '>=12'} hasBin: true + esbuild@0.20.2: + resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + engines: {node: '>=12'} + hasBin: true + esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} hasBin: true - esbuild@0.23.1: - resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + esbuild@0.23.0: + resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==} engines: {node: '>=18'} hasBin: true - esbuild@0.24.0: - resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==} - engines: {node: '>=18'} - hasBin: true + escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} escape-html@1.0.3: @@ -5354,8 +6102,8 @@ packages: eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - eslint-module-utils@2.12.0: - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + eslint-module-utils@2.8.0: + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -5375,12 +6123,12 @@ packages: eslint-import-resolver-webpack: optional: true - eslint-plugin-import@2.31.0: - resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} + eslint-plugin-import@2.28.1: + resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 peerDependenciesMeta: '@typescript-eslint/parser': optional: true @@ -5408,12 +6156,12 @@ packages: peerDependencies: eslint: '>=8.44.0' - eslint-plugin-unused-imports@3.2.0: - resolution: {integrity: sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==} + eslint-plugin-unused-imports@3.0.0: + resolution: {integrity: sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - '@typescript-eslint/eslint-plugin': 6 - 7 - eslint: '8' + '@typescript-eslint/eslint-plugin': ^6.0.0 + eslint: ^8.0.0 peerDependenciesMeta: '@typescript-eslint/eslint-plugin': optional: true @@ -5434,8 +6182,24 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + eslint-visitor-keys@4.0.0: + resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@8.50.0: + resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + eslint@8.53.0: + resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true @@ -5444,9 +6208,9 @@ packages: resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} engines: {node: '>=6'} - esniff@2.0.1: - resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} - engines: {node: '>=0.10'} + espree@10.0.1: + resolution: {integrity: sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} @@ -5457,8 +6221,8 @@ packages: engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -5531,17 +6295,13 @@ packages: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - expect-type@1.1.0: - resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} - engines: {node: '>=12.0.0'} - - expo-asset@10.0.10: - resolution: {integrity: sha512-0qoTIihB79k+wGus9wy0JMKq7DdenziVx3iUkGvMAy2azscSgWH6bd2gJ9CGnhC6JRd3qTMFBL0ou/fx7WZl7A==} + expo-asset@10.0.6: + resolution: {integrity: sha512-waP73/ccn/HZNNcGM4/s3X3icKjSSbEQ9mwc6tX34oYNg+XE5WdwOuZ9wgVVFrU7wZMitq22lQXd2/O0db8bxg==} peerDependencies: expo: '*' - expo-constants@16.0.2: - resolution: {integrity: sha512-9tNY3OVO0jfiMzl7ngb6IOyR5VFzNoN5OOazUWoeGfmMqVB5kltTemRvKraK9JRbBKIw+SOYLEmF0sEqgFZ6OQ==} + expo-constants@16.0.1: + resolution: {integrity: sha512-s6aTHtglp926EsugWtxN7KnpSsE9FCEjb7CgEjQQ78Gpu4btj4wB+IXot2tlqNwqv+x7xFe5veoPGfJDGF/kVg==} peerDependencies: expo: '*' @@ -5550,8 +6310,8 @@ packages: peerDependencies: expo: '*' - expo-font@12.0.10: - resolution: {integrity: sha512-Q1i2NuYri3jy32zdnBaHHCya1wH1yMAsI+3CCmj9zlQzlhsS9Bdwcj2W3c5eU5FvH2hsNQy4O+O1NnM6o/pDaQ==} + expo-font@12.0.5: + resolution: {integrity: sha512-h/VkN4jlHYDJ6T6pPgOYTVoDEfBY0CTKQe4pxnPDGQiE6H+DFdDgk+qWVABGpRMH0+zXoHB+AEi3OoQjXIynFA==} peerDependencies: expo: '*' @@ -5560,27 +6320,24 @@ packages: peerDependencies: expo: '*' - expo-modules-autolinking@1.11.3: - resolution: {integrity: sha512-oYh8EZEvYF5TYppxEKUTTJmbr8j7eRRnrIxzZtMvxLTXoujThVPMFS/cbnSnf2bFm1lq50TdDNABhmEi7z0ngQ==} + expo-modules-autolinking@1.11.1: + resolution: {integrity: sha512-2dy3lTz76adOl7QUvbreMCrXyzUiF8lygI7iFJLjgIQIVH+43KnFWE5zBumpPbkiaq0f0uaFpN9U0RGQbnKiMw==} hasBin: true - expo-modules-core@1.12.26: - resolution: {integrity: sha512-y8yDWjOi+rQRdO+HY+LnUlz8qzHerUaw/LUjKPU/mX8PRXP4UUPEEp5fjAwBU44xjNmYSHWZDwet4IBBE+yQUA==} + expo-modules-core@1.12.11: + resolution: {integrity: sha512-CF5G6hZo/6uIUz6tj4dNRlvE5L4lakYukXPqz5ZHQ+6fLk1NQVZbRdpHjMkxO/QSBQcKUzG/ngeytpoJus7poQ==} expo-sqlite@14.0.6: resolution: {integrity: sha512-T3YNx7LT7lM4UQRgi8ml+cj0Wf3Ep09+B4CVaWtUCjdyYJIZjsHDT65hypKG+r6btTLLEd11hjlrstNQhzt5gQ==} peerDependencies: expo: '*' - expo@51.0.38: - resolution: {integrity: sha512-/B9npFkOPmv6WMIhdjQXEY0Z9k/67UZIVkodW8JxGIXwKUZAGHL+z1R5hTtWimpIrvVhyHUFU3f8uhfEKYhHNQ==} + expo@51.0.8: + resolution: {integrity: sha512-bdTOiMb1f3PChtuqEZ9czUm2gMTmS0r1+H+Pkm2O3PsuLnOgxfIBzL6S37+J4cUocLBaENrmx9SOGKpzhBqXpg==} hasBin: true - exponential-backoff@3.1.1: - resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} - - express@4.21.1: - resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==} + express@4.19.2: + resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} engines: {node: '>= 0.10.0'} ext@1.7.0: @@ -5592,6 +6349,10 @@ packages: fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -5602,12 +6363,16 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-xml-parser@4.4.1: - resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} + fast-xml-parser@4.2.5: + resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} + hasBin: true + + fast-xml-parser@4.4.0: + resolution: {integrity: sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==} hasBin: true - fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -5621,14 +6386,6 @@ packages: fbjs@3.0.5: resolution: {integrity: sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==} - fdir@6.4.2: - resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - fetch-blob@3.2.0: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} @@ -5658,8 +6415,8 @@ packages: resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} engines: {node: '>= 0.8'} - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + finalhandler@1.2.0: + resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} engines: {node: '>= 0.8'} find-cache-dir@2.1.0: @@ -5685,9 +6442,12 @@ packages: find-yarn-workspace-root@2.0.0: resolution: {integrity: sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@3.1.0: + resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==} + engines: {node: '>=12.0.0'} + + flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} @@ -5695,12 +6455,12 @@ packages: flow-enums-runtime@0.0.6: resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} - flow-parser@0.252.0: - resolution: {integrity: sha512-z8hKPUjZ33VLn4HVntifqmEhmolUMopysnMNzazoDqo1GLUkBsreLNsxETlKJMPotUWStQnen6SGvUNe1j4Hlg==} + flow-parser@0.236.0: + resolution: {integrity: sha512-0OEk9Gr+Yj7wjDW2KgaNYUypKau71jAfFyeLQF5iVtxqc6uJHag/MT7pmaEApf4qM7u86DkBcd4ualddYMfbLw==} engines: {node: '>=0.4.0'} - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -5714,16 +6474,16 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - foreground-child@3.3.0: - resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} - form-data@3.0.2: - resolution: {integrity: sha512-sJe+TQb2vIaIyO783qN6BlMYWMw3WBOHA1Ay2qxsnjuafEOQFJ2JakedOQirT6D5XPRxDvS7AHYyem9fTpb4LQ==} + form-data@3.0.1: + resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} engines: {node: '>= 6'} - form-data@4.0.1: - resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} formdata-polyfill@4.0.10: @@ -5748,8 +6508,8 @@ packages: fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs-extra@11.2.0: - resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + fs-extra@11.1.1: + resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} engines: {node: '>=14.14'} fs-extra@8.1.0: @@ -5780,9 +6540,16 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function.prototype.name@1.1.5: + resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + engines: {node: '>= 0.4'} + function.prototype.name@1.1.6: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} @@ -5790,8 +6557,8 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - fx@35.0.0: - resolution: {integrity: sha512-O07q+Lknrom5RUX/u53tjo2KTTLUnL0K703JbqMYb19ORijfJNvijzFqqYXEjdk25T9R14S6t6wHD8fCWXCM0g==} + fx@28.0.0: + resolution: {integrity: sha512-vKQDA9g868cZiW8ulgs2uN1yx1i7/nsS33jTMOxekk0Z03BJLffVcdW6AVD32fWb3E6RtmWWuBXBZOk8cLXFNQ==} hasBin: true gauge@4.0.4: @@ -5813,6 +6580,9 @@ packages: get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + get-intrinsic@1.2.1: + resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} + get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} @@ -5848,12 +6618,16 @@ packages: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} + get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + get-symbol-description@1.0.2: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} - get-tsconfig@4.8.1: - resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + get-tsconfig@4.7.5: + resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} getenv@1.0.0: resolution: {integrity: sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==} @@ -5876,10 +6650,20 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + glob@10.4.1: + resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==} + engines: {node: '>=16 || 14 >=14.18'} hasBin: true + glob@6.0.4: + resolution: {integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==} + deprecated: Glob versions prior to v9 are no longer supported + glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} deprecated: Glob versions prior to v9 are no longer supported @@ -5897,10 +6681,18 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + globals@13.22.0: + resolution: {integrity: sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==} engines: {node: '>=8'} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -5953,9 +6745,16 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-property-descriptors@1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + has-proto@1.0.3: resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} engines: {node: '>= 0.4'} @@ -5964,6 +6763,10 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} + has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} @@ -5971,6 +6774,10 @@ packages: has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -5981,27 +6788,29 @@ packages: hermes-estree@0.19.1: resolution: {integrity: sha512-daLGV3Q2MKk8w4evNMKwS8zBE/rcpA800nu1Q5kM08IKijoSnPe9Uo1iIxzPKRkn95IxxsgBMPeYHt3VG4ej2g==} - hermes-estree@0.23.1: - resolution: {integrity: sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==} - - hermes-estree@0.24.0: - resolution: {integrity: sha512-LyoXLB7IFzeZW0EvAbGZacbxBN7t6KKSDqFJPo3Ydow7wDlrDjXwsdiAHV6XOdvEN9MEuWXsSIFN4tzpyrXIHw==} + hermes-estree@0.20.1: + resolution: {integrity: sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==} hermes-parser@0.19.1: resolution: {integrity: sha512-Vp+bXzxYJWrpEuJ/vXxUsLnt0+y4q9zyi4zUlkLqD8FKv4LjIfOvP69R/9Lty3dCyKh0E2BU7Eypqr63/rKT/A==} - hermes-parser@0.23.1: - resolution: {integrity: sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==} + hermes-parser@0.20.1: + resolution: {integrity: sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==} - hermes-parser@0.24.0: - resolution: {integrity: sha512-IJooSvvu2qNRe7oo9Rb04sUT4omtZqZqf9uq9WM25Tb6v3usmvA93UqfnnoWs5V0uYjEl9Al6MNU10MCGKLwpg==} + hermes-profile-transformer@0.0.6: + resolution: {integrity: sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==} + engines: {node: '>=8'} highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - hono@4.6.9: - resolution: {integrity: sha512-p/pN5yZLuZaHzyAOT2nw2/Ud6HhJHYmDNGH6Ck1OWBhPMVeM1r74jbCRwNi0gyFRjjbsGgoHbOyj7mT1PDNbTw==} - engines: {node: '>=16.9.0'} + hono@4.0.1: + resolution: {integrity: sha512-S9cREGPJIAK437RhroOf1PGlJPIlt5itl69OmQ6onPLo5pdCbSHGL8v4uAKxrdHjcTyuoyvKPqWm5jv0dGkdFA==} + engines: {node: '>=16.0.0'} + + hono@4.5.0: + resolution: {integrity: sha512-ZbezypZfn4odyApjCCv+Fw5OgweBqRLA/EsMyc4FUknFvBJcBIKhHy4sqmD1rWpBc/3wUlaQ6tqOPjk36R1ckg==} + engines: {node: '>=16.0.0'} hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -6055,11 +6864,15 @@ packages: resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} engines: {node: '>=10 <11 || >=12 <13 || >=14'} - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} - image-size@1.1.1: + ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + + image-size@1.1.1: resolution: {integrity: sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==} engines: {node: '>=16.x'} hasBin: true @@ -6104,6 +6917,10 @@ packages: resolution: {integrity: sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==} engines: {node: '>=6'} + internal-slot@1.0.5: + resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} + engines: {node: '>= 0.4'} + internal-slot@1.0.7: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} @@ -6131,6 +6948,9 @@ packages: resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} engines: {node: '>=8'} + is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + is-array-buffer@3.0.4: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} @@ -6160,9 +6980,17 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.15.1: - resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} - engines: {node: '>= 0.4'} + is-core-module@2.11.0: + resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} + + is-core-module@2.12.1: + resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} + + is-core-module@2.13.0: + resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} + + is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} is-data-view@1.0.1: resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} @@ -6192,6 +7020,10 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -6208,6 +7040,10 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + is-invalid-path@0.1.0: resolution: {integrity: sha512-aZMG0T3F34mTg4eTdszcGXx54oiZ4NtHSft3hWNJMGJXUUqdIj3cOZuHcU0nCWWcY3jd7yRe/3AEm3vSNTpBGQ==} engines: {node: '>=0.10.0'} @@ -6215,6 +7051,10 @@ packages: is-lambda@1.0.1: resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} + is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} @@ -6256,6 +7096,9 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} + is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + is-shared-array-buffer@1.0.3: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} @@ -6280,10 +7123,18 @@ packages: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} + is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} + is-typed-array@1.1.13: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} @@ -6299,6 +7150,10 @@ packages: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} engines: {node: '>=12.13'} + is-wsl@1.1.0: + resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} + engines: {node: '>=4'} + is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -6316,19 +7171,13 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - - istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - - itty-time@1.0.6: - resolution: {integrity: sha512-+P8IZaLLBtFv8hCkIjcymZOp4UJ+xW6bSlQsXGqrkmJh7vSiMFSlNne0mCYagEE0N7HDNR5jJBRxwN0oYv61Rw==} + jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@3.1.2: + resolution: {integrity: sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==} + engines: {node: '>=14'} javascript-natural-sort@0.7.1: resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} @@ -6341,10 +7190,6 @@ packages: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-message-util@29.7.0: resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6353,10 +7198,6 @@ packages: resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-util@29.7.0: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6372,11 +7213,14 @@ packages: jimp-compact@0.16.1: resolution: {integrity: sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==} + joi@17.13.1: + resolution: {integrity: sha512-vaBlIKCyo4FCUtCm7Eu4QZd/q02bWcxfUO6YSXAZOWF6gzcLBeba8kwotUdYJjDLW8Cz8RywsSOqiNJZW0mNvg==} + join-component@1.1.0: resolution: {integrity: sha512-bF7vcQxbODoGK1imE2P9GS9aw4zD0Sd+Hni68IMZLj7zRnquH7dXUmMw9hDI5S/Jzt7q+IyTXN0rSg2GI0IKhQ==} - jose@4.15.9: - resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} + jose@4.15.5: + resolution: {integrity: sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==} jose@5.2.3: resolution: {integrity: sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA==} @@ -6490,8 +7334,8 @@ packages: resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==} engines: {node: '>=12.20'} - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyv@4.5.3: + resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==} kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} @@ -6545,8 +7389,12 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - libsql@0.4.7: - resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==} + libsql@0.3.19: + resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} + os: [darwin, linux, win32] + + libsql@0.4.1: + resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -6558,52 +7406,114 @@ packages: cpu: [arm64] os: [darwin] + lightningcss-darwin-arm64@1.25.1: + resolution: {integrity: sha512-G4Dcvv85bs5NLENcu/s1f7ehzE3D5ThnlWSDwE190tWXRQCQaqwcuHe+MGSVI/slm0XrxnaayXY+cNl3cSricw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-x64@1.19.0: resolution: {integrity: sha512-Lif1wD6P4poaw9c/4Uh2z+gmrWhw/HtXFoeZ3bEsv6Ia4tt8rOJBdkfVaUJ6VXmpKHALve+iTyP2+50xY1wKPw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + lightningcss-darwin-x64@1.25.1: + resolution: {integrity: sha512-dYWuCzzfqRueDSmto6YU5SoGHvZTMU1Em9xvhcdROpmtOQLorurUZz8+xFxZ51lCO2LnYbfdjZ/gCqWEkwixNg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.25.1: + resolution: {integrity: sha512-hXoy2s9A3KVNAIoKz+Fp6bNeY+h9c3tkcx1J3+pS48CqAt+5bI/R/YY4hxGL57fWAIquRjGKW50arltD6iRt/w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.19.0: resolution: {integrity: sha512-P15VXY5682mTXaiDtbnLYQflc8BYb774j2R84FgDLJTN6Qp0ZjWEFyN1SPqyfTj2B2TFjRHRUvQSSZ7qN4Weig==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + lightningcss-linux-arm-gnueabihf@1.25.1: + resolution: {integrity: sha512-tWyMgHFlHlp1e5iW3EpqvH5MvsgoN7ZkylBbG2R2LWxnvH3FuWCJOhtGcYx9Ks0Kv0eZOBud789odkYLhyf1ng==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm64-gnu@1.19.0: resolution: {integrity: sha512-zwXRjWqpev8wqO0sv0M1aM1PpjHz6RVIsBcxKszIG83Befuh4yNysjgHVplF9RTU7eozGe3Ts7r6we1+Qkqsww==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + lightningcss-linux-arm64-gnu@1.25.1: + resolution: {integrity: sha512-Xjxsx286OT9/XSnVLIsFEDyDipqe4BcLeB4pXQ/FEA5+2uWCCuAEarUNQumRucnj7k6ftkAHUEph5r821KBccQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + lightningcss-linux-arm64-musl@1.19.0: resolution: {integrity: sha512-vSCKO7SDnZaFN9zEloKSZM5/kC5gbzUjoJQ43BvUpyTFUX7ACs/mDfl2Eq6fdz2+uWhUh7vf92c4EaaP4udEtA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + lightningcss-linux-arm64-musl@1.25.1: + resolution: {integrity: sha512-IhxVFJoTW8wq6yLvxdPvyHv4NjzcpN1B7gjxrY3uaykQNXPHNIpChLB52+wfH+yS58zm1PL4LemUp8u9Cfp6Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + lightningcss-linux-x64-gnu@1.19.0: resolution: {integrity: sha512-0AFQKvVzXf9byrXUq9z0anMGLdZJS+XSDqidyijI5njIwj6MdbvX2UZK/c4FfNmeRa2N/8ngTffoIuOUit5eIQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + lightningcss-linux-x64-gnu@1.25.1: + resolution: {integrity: sha512-RXIaru79KrREPEd6WLXfKfIp4QzoppZvD3x7vuTKkDA64PwTzKJ2jaC43RZHRt8BmyIkRRlmywNhTRMbmkPYpA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + lightningcss-linux-x64-musl@1.19.0: resolution: {integrity: sha512-SJoM8CLPt6ECCgSuWe+g0qo8dqQYVcPiW2s19dxkmSI5+Uu1GIRzyKA0b7QqmEXolA+oSJhQqCmJpzjY4CuZAg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + lightningcss-linux-x64-musl@1.25.1: + resolution: {integrity: sha512-TdcNqFsAENEEFr8fJWg0Y4fZ/nwuqTRsIr7W7t2wmDUlA8eSXVepeeONYcb+gtTj1RaXn/WgNLB45SFkz+XBZA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + lightningcss-win32-x64-msvc@1.19.0: resolution: {integrity: sha512-C+VuUTeSUOAaBZZOPT7Etn/agx/MatzJzGRkeV+zEABmPuntv1zihncsi+AyGmjkkzq3wVedEy7h0/4S84mUtg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + lightningcss-win32-x64-msvc@1.25.1: + resolution: {integrity: sha512-9KZZkmmy9oGDSrnyHuxP6iMhbsgChUiu/NSgOx+U1I/wTngBStDf2i2aGRCHvFqj19HqqBEI4WuGVQBa2V6e0A==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss@1.19.0: resolution: {integrity: sha512-yV5UR7og+Og7lQC+70DA7a8ta1uiOPnWPJfxa0wnxylev5qfo4P+4iMpzWAdYWOca4jdNQZii+bDL/l+4hUXIA==} engines: {node: '>= 12.0.0'} + lightningcss@1.25.1: + resolution: {integrity: sha512-V0RMVZzK1+rCHpymRv4URK2lNhIRyO8g7U7zOFwVAhJuat74HtkjIQpQRKNCwFEYkRGpafOpmXXLoaoBcyVtBg==} + engines: {node: '>= 12.0.0'} + + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + lilconfig@3.1.2: resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} engines: {node: '>=14'} @@ -6658,6 +7568,14 @@ packages: resolution: {integrity: sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==} engines: {node: '>=4'} + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + logkitty@0.7.1: + resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==} + hasBin: true + long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} @@ -6671,6 +7589,10 @@ packages: loupe@3.1.2: resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} + lru-cache@10.2.2: + resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} + engines: {node: 14 || >=16.14} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -6689,14 +7611,21 @@ packages: resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} engines: {node: '>=16.14'} + lru-cache@9.1.2: + resolution: {integrity: sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==} + engines: {node: 14 || >=16.14} + lru-queue@0.1.0: resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - magic-string@0.30.12: - resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} + magic-string@0.30.10: + resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + + magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} @@ -6772,9 +7701,8 @@ packages: memoize-one@5.2.1: resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} - memoizee@0.4.17: - resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==} - engines: {node: '>=0.12'} + memoizee@0.4.15: + resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} memory-cache@0.2.0: resolution: {integrity: sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==} @@ -6783,8 +7711,8 @@ packages: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-descriptors@1.0.1: + resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -6797,64 +7725,68 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - metro-babel-transformer@0.81.0: - resolution: {integrity: sha512-Dc0QWK4wZIeHnyZ3sevWGTnnSkIDDn/SWyfrn99zbKbDOCoCYy71PAn9uCRrP/hduKLJQOy+tebd63Rr9D8tXg==} - engines: {node: '>=18.18'} + metro-babel-transformer@0.80.9: + resolution: {integrity: sha512-d76BSm64KZam1nifRZlNJmtwIgAeZhZG3fi3K+EmPOlrR8rDtBxQHDSN3fSGeNB9CirdTyabTMQCkCup6BXFSQ==} + engines: {node: '>=18'} - metro-cache-key@0.81.0: - resolution: {integrity: sha512-qX/IwtknP9bQZL78OK9xeSvLM/xlGfrs6SlUGgHvrxtmGTRSsxcyqxR+c+7ch1xr05n62Gin/O44QKg5V70rNQ==} - engines: {node: '>=18.18'} + metro-cache-key@0.80.9: + resolution: {integrity: sha512-hRcYGhEiWIdM87hU0fBlcGr+tHDEAT+7LYNCW89p5JhErFt/QaAkVx4fb5bW3YtXGv5BTV7AspWPERoIb99CXg==} + engines: {node: '>=18'} - metro-cache@0.81.0: - resolution: {integrity: sha512-DyuqySicHXkHUDZFVJmh0ygxBSx6pCKUrTcSgb884oiscV/ROt1Vhye+x+OIHcsodyA10gzZtrVtxIFV4l9I4g==} - engines: {node: '>=18.18'} + metro-cache@0.80.9: + resolution: {integrity: sha512-ujEdSI43QwI+Dj2xuNax8LMo8UgKuXJEdxJkzGPU6iIx42nYa1byQ+aADv/iPh5sh5a//h5FopraW5voXSgm2w==} + engines: {node: '>=18'} - metro-config@0.81.0: - resolution: {integrity: sha512-6CinEaBe3WLpRlKlYXXu8r1UblJhbwD6Gtnoib5U8j6Pjp7XxMG9h/DGMeNp9aGLDu1OieUqiXpFo7O0/rR5Kg==} - engines: {node: '>=18.18'} + metro-config@0.80.9: + resolution: {integrity: sha512-28wW7CqS3eJrunRGnsibWldqgwRP9ywBEf7kg+uzUHkSFJNKPM1K3UNSngHmH0EZjomizqQA2Zi6/y6VdZMolg==} + engines: {node: '>=18'} - metro-core@0.81.0: - resolution: {integrity: sha512-CVkM5YCOAFkNMvJai6KzA0RpztzfEKRX62/PFMOJ9J7K0uq/UkOFLxcgpcncMIrfy0PbfEj811b69tjULUQe1Q==} - engines: {node: '>=18.18'} + metro-core@0.80.9: + resolution: {integrity: sha512-tbltWQn+XTdULkGdzHIxlxk4SdnKxttvQQV3wpqqFbHDteR4gwCyTR2RyYJvxgU7HELfHtrVbqgqAdlPByUSbg==} + engines: {node: '>=18'} - metro-file-map@0.81.0: - resolution: {integrity: sha512-zMDI5uYhQCyxbye/AuFx/pAbsz9K+vKL7h1ShUXdN2fz4VUPiyQYRsRqOoVG1DsiCgzd5B6LW0YW77NFpjDQeg==} - engines: {node: '>=18.18'} + metro-file-map@0.80.9: + resolution: {integrity: sha512-sBUjVtQMHagItJH/wGU9sn3k2u0nrCl0CdR4SFMO1tksXLKbkigyQx4cbpcyPVOAmGTVuy3jyvBlELaGCAhplQ==} + engines: {node: '>=18'} - metro-minify-terser@0.81.0: - resolution: {integrity: sha512-U2ramh3W822ZR1nfXgIk+emxsf5eZSg10GbQrT0ZizImK8IZ5BmJY+BHRIkQgHzWFpExOVxC7kWbGL1bZALswA==} - engines: {node: '>=18.18'} + metro-minify-terser@0.80.9: + resolution: {integrity: sha512-FEeCeFbkvvPuhjixZ1FYrXtO0araTpV6UbcnGgDUpH7s7eR5FG/PiJz3TsuuPP/HwCK19cZtQydcA2QrCw446A==} + engines: {node: '>=18'} - metro-resolver@0.81.0: - resolution: {integrity: sha512-Uu2Q+buHhm571cEwpPek8egMbdSTqmwT/5U7ZVNpK6Z2ElQBBCxd7HmFAslKXa7wgpTO2FAn6MqGeERbAtVDUA==} - engines: {node: '>=18.18'} + metro-resolver@0.80.9: + resolution: {integrity: sha512-wAPIjkN59BQN6gocVsAvvpZ1+LQkkqUaswlT++cJafE/e54GoVkMNCmrR4BsgQHr9DknZ5Um/nKueeN7kaEz9w==} + engines: {node: '>=18'} - metro-runtime@0.81.0: - resolution: {integrity: sha512-6oYB5HOt37RuGz2eV4A6yhcl+PUTwJYLDlY9vhT+aVjbUWI6MdBCf69vc4f5K5Vpt+yOkjy+2LDwLS0ykWFwYw==} - engines: {node: '>=18.18'} + metro-runtime@0.80.9: + resolution: {integrity: sha512-8PTVIgrVcyU+X/rVCy/9yxNlvXsBCk5JwwkbAm/Dm+Abo6NBGtNjWF0M1Xo/NWCb4phamNWcD7cHdR91HhbJvg==} + engines: {node: '>=18'} - metro-source-map@0.81.0: - resolution: {integrity: sha512-TzsVxhH83dyxg4A4+L1nzNO12I7ps5IHLjKGZH3Hrf549eiZivkdjYiq/S5lOB+p2HiQ+Ykcwtmcja95LIC62g==} - engines: {node: '>=18.18'} + metro-source-map@0.80.9: + resolution: {integrity: sha512-RMn+XS4VTJIwMPOUSj61xlxgBvPeY4G6s5uIn6kt6HB6A/k9ekhr65UkkDD7WzHYs3a9o869qU8tvOZvqeQzgw==} + engines: {node: '>=18'} - metro-symbolicate@0.81.0: - resolution: {integrity: sha512-C/1rWbNTPYp6yzID8IPuQPpVGzJ2rbWYBATxlvQ9dfK5lVNoxcwz77hjcY8ISLsRRR15hyd/zbjCNKPKeNgE1Q==} - engines: {node: '>=18.18'} + metro-symbolicate@0.80.9: + resolution: {integrity: sha512-Ykae12rdqSs98hg41RKEToojuIW85wNdmSe/eHUgMkzbvCFNVgcC0w3dKZEhSsqQOXapXRlLtHkaHLil0UD/EA==} + engines: {node: '>=18'} hasBin: true - metro-transform-plugins@0.81.0: - resolution: {integrity: sha512-uErLAPBvttGCrmGSCa0dNHlOTk3uJFVEVWa5WDg6tQ79PRmuYRwzUgLhVzn/9/kyr75eUX3QWXN79Jvu4txt6Q==} - engines: {node: '>=18.18'} + metro-transform-plugins@0.80.9: + resolution: {integrity: sha512-UlDk/uc8UdfLNJhPbF3tvwajyuuygBcyp+yBuS/q0z3QSuN/EbLllY3rK8OTD9n4h00qZ/qgxGv/lMFJkwP4vg==} + engines: {node: '>=18'} - metro-transform-worker@0.81.0: - resolution: {integrity: sha512-HrQ0twiruhKy0yA+9nK5bIe3WQXZcC66PXTvRIos61/EASLAP2DzEmW7IxN/MGsfZegN2UzqL2CG38+mOB45vg==} - engines: {node: '>=18.18'} + metro-transform-worker@0.80.9: + resolution: {integrity: sha512-c/IrzMUVnI0hSVVit4TXzt3A1GiUltGVlzCmLJWxNrBGHGrJhvgePj38+GXl1Xf4Fd4vx6qLUkKMQ3ux73bFLQ==} + engines: {node: '>=18'} - metro@0.81.0: - resolution: {integrity: sha512-kzdzmpL0gKhEthZ9aOV7sTqvg6NuTxDV8SIm9pf9sO8VVEbKrQk5DNcwupOUjgPPFAuKUc2NkT0suyT62hm2xg==} - engines: {node: '>=18.18'} + metro@0.80.9: + resolution: {integrity: sha512-Bc57Xf3GO2Xe4UWQsBj/oW6YfLPABEu8jfDVDiNmJvoQW4CO34oDPuYKe4KlXzXhcuNsqOtSxpbjCRRVjhhREg==} + engines: {node: '>=18'} hasBin: true + micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + engines: {node: '>=8.6'} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -6872,6 +7804,11 @@ packages: engines: {node: '>=4'} hasBin: true + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -6897,8 +7834,8 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - miniflare@3.20241022.0: - resolution: {integrity: sha512-x9Fbq1Hmz1f0osIT9Qmj78iX4UpCP2EqlZnA/tzj/3+I49vc3Kq0fNqSSKplcdf6HlCHdL3fOBicmreQF4BUUQ==} + miniflare@3.20240712.0: + resolution: {integrity: sha512-zVbsMX2phvJS1uTPmjK6CvVBq4ON2UkmvTw9IMfNPACsWJmHEdsBDxsYEG1vKAduJdI5gULLuJf7qpFxByDhGw==} engines: {node: '>=16.13'} hasBin: true @@ -6913,12 +7850,8 @@ packages: resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} engines: {node: '>=10'} - minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.4: + resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: @@ -6976,8 +7909,8 @@ packages: engines: {node: '>=10'} hasBin: true - mlly@1.7.2: - resolution: {integrity: sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==} + mlly@1.7.0: + resolution: {integrity: sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==} mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} @@ -7000,6 +7933,14 @@ packages: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true + mv@2.1.1: + resolution: {integrity: sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==} + engines: {node: '>=0.8.0'} + + mysql2@3.11.0: + resolution: {integrity: sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==} + engines: {node: '>= 8.0'} + mysql2@3.3.3: resolution: {integrity: sha512-MxDQJztArk4JFX1PKVjDhIXRzAmVJfuqZrVU+my6NeYBAA/XZRaDw5q7vga8TNvgyy3Lv3rivBFBBuJFbsdjaw==} engines: {node: '>= 8.0'} @@ -7011,8 +7952,8 @@ packages: resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} engines: {node: '>=12.0.0'} - nan@2.22.0: - resolution: {integrity: sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==} + nan@2.19.0: + resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} @@ -7025,14 +7966,14 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + ncp@2.0.0: + resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==} + hasBin: true + negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -7048,15 +7989,20 @@ packages: nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} - node-abi@3.71.0: - resolution: {integrity: sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==} + nocache@3.0.4: + resolution: {integrity: sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==} + engines: {node: '>=12.0.0'} + + node-abi@3.62.0: + resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==} engines: {node: '>=10'} node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-addon-api@7.1.0: + resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==} + engines: {node: ^16 || ^18 || >= 20} node-dir@0.1.17: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} @@ -7070,6 +8016,9 @@ packages: resolution: {integrity: sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==} engines: {node: '>=18'} + node-fetch-native@1.6.4: + resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -7091,8 +8040,8 @@ packages: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} - node-gyp-build@4.8.2: - resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==} + node-gyp-build@4.8.1: + resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} hasBin: true node-gyp@8.4.1: @@ -7103,8 +8052,12 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.18: - resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + + node-stream-zip@1.15.0: + resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} + engines: {node: '>=0.12.0'} nofilter@3.1.0: resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} @@ -7151,9 +8104,9 @@ packages: nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} - ob1@0.81.0: - resolution: {integrity: sha512-6Cvrkxt1tqaRdWqTAMcVYEiO5i1xcF9y7t06nFdjFqkfPsEloCf8WwhXdwBpNUkVYSQlSGS7cDgVQR86miBfBQ==} - engines: {node: '>=18.18'} + ob1@0.80.9: + resolution: {integrity: sha512-v9yOxowkZbxWhKOaaTyLjIm1aLy4ebMNcSn4NYJKOAI/Qv+SkfEfszpLr2GIxsccmb2Y2HA9qtsqiIJ80ucpVA==} + engines: {node: '>=18'} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} @@ -7163,36 +8116,38 @@ packages: resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} engines: {node: '>= 6'} - object-inspect@1.13.2: - resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} - engines: {node: '>= 0.4'} + object-inspect@1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + + object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + object.assign@4.1.5: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} - object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + object.fromentries@2.0.6: + resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} engines: {node: '>= 0.4'} - object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} + object.groupby@1.0.0: + resolution: {integrity: sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==} - object.values@1.2.0: - resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + object.values@1.1.6: + resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} engines: {node: '>= 0.4'} obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - ohash@1.1.4: - resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} - ohm-js@17.1.0: resolution: {integrity: sha512-xc3B5dgAjTBQGHaH7B58M2Pmv6WvzrJ/3/7LeUzXNg0/sY3jQPdSd/S2SstppaleO77rifR1tyhdfFGNIwxf2Q==} engines: {node: '>=0.12.1'} @@ -7209,6 +8164,10 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} + on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -7224,6 +8183,10 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + open@6.4.0: + resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==} + engines: {node: '>=8'} + open@7.4.2: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} @@ -7235,14 +8198,18 @@ packages: openid-client@5.6.4: resolution: {integrity: sha512-T1h3B10BRPKfcObdBklX639tVz+xh34O7GjofqrqiAQdm7eHsQ00ih18x6wuJ/E6FxdtS2u3FmUGPDeEcMwzNA==} - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} ora@3.4.0: resolution: {integrity: sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==} engines: {node: '>=6'} + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + os-homedir@1.0.2: resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} engines: {node: '>=0.10.0'} @@ -7339,9 +8306,6 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -7412,15 +8376,19 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-to-regexp@0.1.10: - resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + path-to-regexp@0.1.7: + resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} - path-to-regexp@6.3.0: - resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-to-regexp@6.2.2: + resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} @@ -7449,6 +8417,9 @@ packages: pg-connection-string@2.6.1: resolution: {integrity: sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==} + pg-connection-string@2.6.4: + resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} + pg-connection-string@2.7.0: resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==} @@ -7460,11 +8431,19 @@ packages: resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} engines: {node: '>=4'} + pg-pool@3.6.2: + resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==} + peerDependencies: + pg: '>=8.0' + pg-pool@3.7.0: resolution: {integrity: sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==} peerDependencies: pg: '>=8.0' + pg-protocol@1.6.1: + resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==} + pg-protocol@1.7.0: resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==} @@ -7476,6 +8455,15 @@ packages: resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} engines: {node: '>=10'} + pg@8.11.5: + resolution: {integrity: sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + pg@8.13.1: resolution: {integrity: sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==} engines: {node: '>= 8.0.0'} @@ -7488,8 +8476,11 @@ packages: pgpass@1.0.5: resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -7519,8 +8510,8 @@ packages: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} - pkg-types@1.2.1: - resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} + pkg-types@1.1.0: + resolution: {integrity: sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA==} plist@3.1.0: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} @@ -7542,8 +8533,8 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + postcss-load-config@4.0.1: + resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} engines: {node: '>= 14'} peerDependencies: postcss: '>=8.0.9' @@ -7572,8 +8563,12 @@ packages: yaml: optional: true - postcss@8.4.47: - resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} + postcss@8.4.38: + resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.4.39: + resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -7611,8 +8606,8 @@ packages: postgres-range@1.1.4: resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} - postgres@3.4.5: - resolution: {integrity: sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg==} + postgres@3.4.4: + resolution: {integrity: sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==} engines: {node: '>=12'} pouchdb-collections@1.0.1: @@ -7636,8 +8631,8 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.3.3: - resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + prettier@3.0.3: + resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} engines: {node: '>=14'} hasBin: true @@ -7645,9 +8640,9 @@ packages: resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} engines: {node: '>=6'} - pretty-format@24.9.0: - resolution: {integrity: sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==} - engines: {node: '>= 6'} + pretty-format@26.6.2: + resolution: {integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==} + engines: {node: '>= 10'} pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} @@ -7712,8 +8707,12 @@ packages: engines: {node: '>= 0.10'} hasBin: true - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + + punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} @@ -7726,10 +8725,15 @@ packages: resolution: {integrity: sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==} hasBin: true - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + qs@6.11.0: + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} + querystring@0.2.1: + resolution: {integrity: sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==} + engines: {node: '>=0.4.x'} + deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -7751,22 +8755,28 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - react-devtools-core@5.3.2: - resolution: {integrity: sha512-crr9HkVrDiJ0A4zot89oS0Cgv0Oa4OG1Em4jit3P3ZxZSKPMYyMjfwMqgcJna9o625g8oN87rBm8SWWrSTBZxg==} + react-devtools-core@5.2.0: + resolution: {integrity: sha512-vZK+/gvxxsieAoAyYaiRIVFxlajb7KXhgBDV7OsoMzaAE+IqGpoxusBjIgq5ibqA2IloKu0p9n7tE68z1xs18A==} react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-native@0.76.1: - resolution: {integrity: sha512-z4KnbrnnAvloRs9NGnah3u6/LK3IbtNMrvByxa3ifigbMlsMY4WPRYV9lvt/hH4Mzt8bfuI+utnOxFyJTTq3lg==} + react-native@0.74.1: + resolution: {integrity: sha512-0H2XpmghwOtfPpM2LKqHIN7gxy+7G/r1hwJHKLV6uoyXGC/gCojRtoo5NqyKrWpFC8cqyT6wTYCLuG7CxEKilg==} engines: {node: '>=18'} hasBin: true peerDependencies: '@types/react': ^18.2.6 - react: ^18.2.0 + react: 18.2.0 peerDependenciesMeta: '@types/react': optional: true @@ -7775,6 +8785,11 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} + react-shallow-renderer@16.15.0: + resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -7798,10 +8813,6 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - readdirp@4.0.2: - resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} - engines: {node: '>= 14.16.0'} - readline@1.3.0: resolution: {integrity: sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==} @@ -7820,8 +8831,8 @@ packages: redeyed@2.1.1: resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==} - regenerate-unicode-properties@10.2.0: - resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} + regenerate-unicode-properties@10.1.1: + resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} engines: {node: '>=4'} regenerate@1.4.2: @@ -7830,6 +8841,9 @@ packages: regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -7840,23 +8854,24 @@ packages: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true - regexp.prototype.flags@1.5.3: - resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + regexp.prototype.flags@1.5.0: + resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} engines: {node: '>= 0.4'} - regexpu-core@6.1.1: - resolution: {integrity: sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==} - engines: {node: '>=4'} + regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} - regjsgen@0.8.0: - resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + regexpu-core@5.3.2: + resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} + engines: {node: '>=4'} regjsparser@0.10.0: resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} hasBin: true - regjsparser@0.11.2: - resolution: {integrity: sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==} + regjsparser@0.9.1: + resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} hasBin: true remove-trailing-slash@0.1.1: @@ -7870,6 +8885,9 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + requireg@0.2.2: resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==} engines: {node: '>= 4.0.0'} @@ -7893,6 +8911,12 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve-tspaths@0.8.16: + resolution: {integrity: sha512-5c90plgcKFcCk66Ve1vFh6tm0fLKmSz6vaW4CezP6i69Q8fgWX3YGPYmKPEughem+nPHT1358P+rXrhw5pibwg==} + hasBin: true + peerDependencies: + typescript: '>=3.0.3' + resolve-tspaths@0.8.22: resolution: {integrity: sha512-x9loBJyTLdx3grlcNpH/Y2t8IkfadtbzYhzpo683C6olazn0/4Y3cfSBiqDA0f2vSmq5tITKJCN9e1ezBh6jhA==} hasBin: true @@ -7903,6 +8927,18 @@ packages: resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} engines: {node: '>=10'} + resolve@1.22.1: + resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + hasBin: true + + resolve@1.22.2: + resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} + hasBin: true + + resolve@1.22.4: + resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} + hasBin: true + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -7914,6 +8950,10 @@ packages: resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==} engines: {node: '>=4'} + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} @@ -7926,18 +8966,29 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rimraf@2.4.5: + resolution: {integrity: sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rimraf@5.0.10: - resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} + rimraf@5.0.0: + resolution: {integrity: sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==} + engines: {node: '>=14'} hasBin: true rollup-plugin-inject@3.0.2: @@ -7950,13 +9001,23 @@ packages: rollup-pluginutils@2.8.2: resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - rollup@3.29.5: - resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==} + rollup@3.20.7: + resolution: {integrity: sha512-P7E2zezKSLhWnTz46XxjSmInrbOCiul1yf+kJccMxT56vxjHwCbDfoLbiqFgu+WQoo9ij2PkraYaBstgB2prBA==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + + rollup@3.27.2: + resolution: {integrity: sha512-YGwmHf7h2oUHkVBT248x0yt6vZkYQ3/rvE5iQuVBh3WO8GcJ6BNeOkpoX1yMHIiBm18EMLjBPIoUDkhgnyxGOQ==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true - rollup@4.24.4: - resolution: {integrity: sha512-vGorVWIsWfX3xbcyAS+I047kFKapHYivmkaT63Smj77XwvLSJos6M1xGqZnBPFQFBRZDOcG1QnYEIxAvTr/HjA==} + rollup@4.18.1: + resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rollup@4.27.3: + resolution: {integrity: sha512-SLsCOnlmGt9VoZ9Ek8yBK8tAdmPHeppkw+Xa7yDlCEhDTvwYei03JlWo1fdc7YTfLZ4tD8riJCUyAgTbszk1fQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -7970,6 +9031,10 @@ packages: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} + safe-array-concat@1.0.0: + resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==} + engines: {node: '>=0.4'} + safe-array-concat@1.1.2: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} @@ -7980,6 +9045,12 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-json-stringify@1.2.0: + resolution: {integrity: sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==} + + safe-regex-test@1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + safe-regex-test@1.0.3: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} @@ -8005,8 +9076,8 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + semver@7.6.2: + resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} engines: {node: '>=10'} hasBin: true @@ -8014,10 +9085,6 @@ packages: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - seq-queue@0.0.5: resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} @@ -8029,18 +9096,18 @@ packages: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serialize-javascript@6.0.1: + resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==} - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + serve-static@1.15.0: + resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} engines: {node: '>= 0.8.0'} set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-cookie-parser@2.7.1: - resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-cookie-parser@2.6.0: + resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} @@ -8079,6 +9146,9 @@ packages: shell-quote@1.8.1: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} @@ -8089,6 +9159,10 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.0.2: + resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} + engines: {node: '>=14'} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -8125,6 +9199,10 @@ packages: resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} engines: {node: '>=14.16'} + slice-ansi@2.1.0: + resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} + engines: {node: '>=6'} + slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} engines: {node: '>=12'} @@ -8137,6 +9215,9 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + smob@0.0.6: + resolution: {integrity: sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw==} + smob@1.5.0: resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} @@ -8148,8 +9229,8 @@ packages: resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} source-map-support@0.5.21: @@ -8163,6 +9244,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} @@ -8177,14 +9262,14 @@ packages: spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + spdx-exceptions@2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - spdx-license-ids@3.0.20: - resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} + spdx-license-ids@3.0.13: + resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} split-ca@1.0.1: resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} @@ -8208,8 +9293,8 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - sql.js@1.12.0: - resolution: {integrity: sha512-Bi+43yMx/tUFZVYD4AUscmdL6NHn3gYQ+CM+YheFWLftOmrEC/Mz6Yh7E96Y2WDHYz3COSqT+LP6Z79zgrwJlA==} + sql.js@1.10.3: + resolution: {integrity: sha512-H46aWtQkdyjZwFQgraUruy5h/DyJBbAK3EA/WEMqiqF6PGPfKBSKBj/er3dVyYqVIoYfRf5TFM/loEjtQIrqJg==} sqlite3@5.1.7: resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==} @@ -8218,8 +9303,8 @@ packages: resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} engines: {node: '>= 0.6'} - ssh2@1.16.0: - resolution: {integrity: sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==} + ssh2@1.15.0: + resolution: {integrity: sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==} engines: {node: '>=10.16.0'} ssri@10.0.6: @@ -8230,42 +9315,8 @@ packages: resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} engines: {node: '>= 8'} - sst-darwin-arm64@3.3.5: - resolution: {integrity: sha512-kHQcmGhNMbIIhgz49Ejki6zp5TiCRwHaf+3c13GOzMrCIng2GixboGoNjMBFdSwXogQcJBc0BBOQo1oxmr4CxQ==} - cpu: [arm64] - os: [darwin] - - sst-darwin-x64@3.3.5: - resolution: {integrity: sha512-jouPGqUjlfMpwOyBzbYMMW/ezRlAqte4BnzASdPG7Cr23jX8Hl06yVFSzFAougfFA3vBnln6qCgLtNP/vDqCew==} - cpu: [x64] - os: [darwin] - - sst-linux-arm64@3.3.5: - resolution: {integrity: sha512-0fl7cR80bqScR1SS6iAAab4tjaT3M2dQCfjl0aTaBTeI+DmTD+SbteGcVwkQaXjcETuIUEKUAFd6F5EF0LewlA==} - cpu: [arm64] - os: [linux] - - sst-linux-x64@3.3.5: - resolution: {integrity: sha512-Et6DMlp8UGsUlToeMzWpEfRpxiYexMmnbfNd+usZMq7kC2or8Ze6ec3HR6Mm2pXjcwEZ6GUZRPWATWfqH7yNmw==} - cpu: [x64] - os: [linux] - - sst-linux-x86@3.3.5: - resolution: {integrity: sha512-ZjW1gkBbGRjCiCaZg+NBEeVwQ9/NFr5BjxLbwMX0zDwwDUim9W/PC89sHYZO9KnJX3D39+X8QC11vRnxpYQkNw==} - cpu: [x86] - os: [linux] - - sst@3.3.5: - resolution: {integrity: sha512-YqiDtvCFPfztusQbOU974R8WwGJNLs33X57NuVwUYCH9miMlw0Rz/hWMlwR9uMyQm7b6vc+Sf1kBPqy5iuPk6w==} - hasBin: true - peerDependencies: - hono: 4.x - valibot: 0.30.x - peerDependenciesMeta: - hono: - optional: true - valibot: - optional: true + sst@3.0.14: + resolution: {integrity: sha512-MC93uHwMxM1uwDg9Old8qo8LsmhvrMD3YFkS5Me8ThozwFIKzwqXicJWTE3iL+0DkPSPhdiSxafRdKhu/Qk5DA==} stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} @@ -8318,13 +9369,23 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string.prototype.trim@1.2.7: + resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} + engines: {node: '>= 0.4'} + string.prototype.trim@1.2.9: resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} + string.prototype.trimend@1.0.6: + resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} + string.prototype.trimend@1.0.8: resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + string.prototype.trimstart@1.0.6: + resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} + string.prototype.trimstart@1.0.8: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} @@ -8400,6 +9461,9 @@ packages: sudo-prompt@9.1.1: resolution: {integrity: sha512-es33J1g2HjMpyAhz8lOR+ICmXXAqTuKbuXuUWLhOLew20oN9oUCgCJx615U/v7aioZg7IX5lIh9x34vwneu4pA==} + sudo-prompt@9.2.1: + resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==} + superjson@2.2.1: resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} engines: {node: '>=16'} @@ -8424,6 +9488,10 @@ packages: resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} engines: {node: '>=8'} + supports-hyperlinks@3.0.0: + resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} + engines: {node: '>=14.18'} + supports-hyperlinks@3.1.0: resolution: {integrity: sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==} engines: {node: '>=14.18'} @@ -8432,8 +9500,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - synckit@0.9.2: - resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} + synckit@0.9.1: + resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} tar-fs@2.0.1: @@ -8482,14 +9550,15 @@ packages: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} engines: {node: '>=8'} - terser@5.36.0: - resolution: {integrity: sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==} + terser@5.17.1: + resolution: {integrity: sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==} engines: {node: '>=10'} hasBin: true - test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} + terser@5.31.0: + resolution: {integrity: sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==} + engines: {node: '>=10'} + hasBin: true text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -8521,9 +9590,8 @@ packages: resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} engines: {node: '>=4'} - timers-ext@0.1.8: - resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==} - engines: {node: '>=0.12'} + timers-ext@0.1.7: + resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==} tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -8531,15 +9599,14 @@ packages: tiny-queue@0.2.1: resolution: {integrity: sha512-EijGsv7kzd9I9g0ByCl6h42BWNGUZrlCSejfrb3AKeHC33SGbASu1VDf5O3rRiiUOhAC9CHdZxFPbZu0HmR70A==} + tinybench@2.8.0: + resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.1: - resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} - - tinyglobby@0.2.10: - resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} - engines: {node: '>=12.0.0'} + tinyexec@0.3.0: + resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} tinypool@0.8.4: resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} @@ -8590,8 +9657,8 @@ packages: tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - traverse@0.6.10: - resolution: {integrity: sha512-hN4uFRxbK+PX56DxYiGHsTn2dME3TVr9vbNqlQGcGcPhJAn+tdP126iA+TArMpI4YSgnTkMWyoLl5bf81Hi5TA==} + traverse@0.6.9: + resolution: {integrity: sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg==} engines: {node: '>= 0.4'} tree-kill@1.2.2: @@ -8602,12 +9669,14 @@ packages: resolution: {integrity: sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==} engines: {node: '>=0.6'} - trim-right@1.0.1: - resolution: {integrity: sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==} - engines: {node: '>=0.10.0'} + ts-api-utils@1.0.3: + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' - ts-api-utils@1.4.0: - resolution: {integrity: sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==} + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' @@ -8632,8 +9701,8 @@ packages: '@swc/wasm': optional: true - tsconfck@3.1.4: - resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} + tsconfck@3.0.3: + resolution: {integrity: sha512-4t0noZX9t6GcPTfBAbIbbIU4pfpCwh0ueq3S4O/5qXI1VwK1outmxhe9dOiEWqMz3MW2LKgDTpqWV+37IWuVbA==} engines: {node: ^18 || >=20} hasBin: true peerDependencies: @@ -8642,24 +9711,26 @@ packages: typescript: optional: true - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tsconfig-paths@3.14.2: + resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsup@7.3.0: - resolution: {integrity: sha512-Ja1eaSRrE+QarmATlNO5fse2aOACYMBX+IZRKy1T+gpyH+jXgRrl5l4nHIQJQ1DoDgEjHDTw8cpE085UdBZuWQ==} - engines: {node: '>=18'} - deprecated: Breaking node 16 + tsup@7.2.0: + resolution: {integrity: sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==} + engines: {node: '>=16.14'} hasBin: true peerDependencies: '@swc/core': ^1 postcss: ^8.4.12 - typescript: '>=4.5.0' + typescript: '>=4.1.0' peerDependenciesMeta: '@swc/core': optional: true @@ -8668,8 +9739,8 @@ packages: typescript: optional: true - tsup@8.3.5: - resolution: {integrity: sha512-Tunf6r6m6tnZsG9GYWndg0z8dEV7fD733VBFzFJ5Vcm1FtlXB8xBD/rtrBi2a3YKEV7hHtxiZtW5EAVADoe1pA==} + tsup@8.1.2: + resolution: {integrity: sha512-Gzw/PXSX/z0aYMNmkcI54bKKFVFJQbLne+EqTJZeQ3lNT3QpumjtMU4rl+ZwTTp8oRF3ahMbEAxT2sZPJLFSrg==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -8697,6 +9768,16 @@ packages: resolution: {integrity: sha512-xHtFaKtHxM9LOklMmJdI3BEnQq/D5F73Of2E1GDrITi9sgoVkvIsrQUTY1G8FlmGtA+awCI4EBlTRRYxkL2sRg==} hasBin: true + tsx@4.10.5: + resolution: {integrity: sha512-twDSbf7Gtea4I2copqovUiNTEDrT8XNFXsuHpfGbdpW/z9ZW4fTghzzhAG0WfrCuJmJiOEY1nLIjq4u3oujRWQ==} + engines: {node: '>=18.0.0'} + hasBin: true + + tsx@4.16.2: + resolution: {integrity: sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==} + engines: {node: '>=18.0.0'} + hasBin: true + tsx@4.19.2: resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} engines: {node: '>=18.0.0'} @@ -8705,38 +9786,38 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - turbo-darwin-64@2.2.3: - resolution: {integrity: sha512-Rcm10CuMKQGcdIBS3R/9PMeuYnv6beYIHqfZFeKWVYEWH69sauj4INs83zKMTUiZJ3/hWGZ4jet9AOwhsssLyg==} + turbo-darwin-64@2.3.0: + resolution: {integrity: sha512-pji+D49PhFItyQjf2QVoLZw2d3oRGo8gJgKyOiRzvip78Rzie74quA8XNwSg/DuzM7xx6gJ3p2/LylTTlgZXxQ==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@2.2.3: - resolution: {integrity: sha512-+EIMHkuLFqUdJYsA3roj66t9+9IciCajgj+DVek+QezEdOJKcRxlvDOS2BUaeN8kEzVSsNiAGnoysFWYw4K0HA==} + turbo-darwin-arm64@2.3.0: + resolution: {integrity: sha512-AJrGIL9BO41mwDF/IBHsNGwvtdyB911vp8f5mbNo1wG66gWTvOBg7WCtYQBvCo11XTenTfXPRSsAb7w3WAZb6w==} cpu: [arm64] os: [darwin] - turbo-linux-64@2.2.3: - resolution: {integrity: sha512-UBhJCYnqtaeOBQLmLo8BAisWbc9v9daL9G8upLR+XGj6vuN/Nz6qUAhverN4Pyej1g4Nt1BhROnj6GLOPYyqxQ==} + turbo-linux-64@2.3.0: + resolution: {integrity: sha512-jZqW6vc2sPJT3M/3ZmV1Cg4ecQVPqsbHncG/RnogHpBu783KCSXIndgxvUQNm9qfgBYbZDBnP1md63O4UTElhw==} cpu: [x64] os: [linux] - turbo-linux-arm64@2.2.3: - resolution: {integrity: sha512-hJYT9dN06XCQ3jBka/EWvvAETnHRs3xuO/rb5bESmDfG+d9yQjeTMlhRXKrr4eyIMt6cLDt1LBfyi+6CQ+VAwQ==} + turbo-linux-arm64@2.3.0: + resolution: {integrity: sha512-HUbDLJlvd/hxuyCNO0BmEWYQj0TugRMvSQeG8vHJH+Lq8qOgDAe7J0K73bFNbZejZQxW3C3XEiZFB3pnpO78+A==} cpu: [arm64] os: [linux] - turbo-windows-64@2.2.3: - resolution: {integrity: sha512-NPrjacrZypMBF31b4HE4ROg4P3nhMBPHKS5WTpMwf7wydZ8uvdEHpESVNMOtqhlp857zbnKYgP+yJF30H3N2dQ==} + turbo-windows-64@2.3.0: + resolution: {integrity: sha512-c5rxrGNTYDWX9QeMzWLFE9frOXnKjHGEvQMp1SfldDlbZYsloX9UKs31TzUThzfTgTiz8NYuShaXJ2UvTMnV/g==} cpu: [x64] os: [win32] - turbo-windows-arm64@2.2.3: - resolution: {integrity: sha512-fnNrYBCqn6zgKPKLHu4sOkihBI/+0oYFr075duRxqUZ+1aLWTAGfHZLgjVeLh3zR37CVzuerGIPWAEkNhkWEIw==} + turbo-windows-arm64@2.3.0: + resolution: {integrity: sha512-7qfUuYhfIVb1AZgs89DxhXK+zZez6O2ocmixEQ4hXZK7ytnBt5vaz2zGNJJKFNYIL5HX1C3tuHolnpNgDNCUIg==} cpu: [arm64] os: [win32] - turbo@2.2.3: - resolution: {integrity: sha512-5lDvSqIxCYJ/BAd6rQGK/AzFRhBkbu4JHVMLmGh/hCb7U3CqSnr5Tjwfy9vc+/5wG2DJ6wttgAaA7MoCgvBKZQ==} + turbo@2.3.0: + resolution: {integrity: sha512-/uOq5o2jwRPyaUDnwBpOR5k9mQq4c3wziBgWNWttiYQPmbhDtrKYPRBxTvA2WpgQwRIbt8UM612RMN8n/TvmHA==} hasBin: true tweetnacl@0.14.5: @@ -8750,10 +9831,6 @@ packages: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} - type-detect@4.1.0: - resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} - engines: {node: '>=4'} - type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} @@ -8786,25 +9863,47 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} + type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - type@2.7.3: - resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} + type@1.2.0: + resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} + + type@2.7.2: + resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} + + typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.1: resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} engines: {node: '>= 0.4'} + typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + typed-array-byte-offset@1.0.2: resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} engines: {node: '>= 0.4'} + typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + typed-array-length@1.0.6: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} @@ -8813,6 +9912,11 @@ packages: resolution: {integrity: sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A==} engines: {node: '>= 0.4'} + typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + typescript@5.3.3: resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} @@ -8828,12 +9932,11 @@ packages: engines: {node: '>=14.17'} hasBin: true - ua-parser-js@1.0.39: - resolution: {integrity: sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw==} - hasBin: true + ua-parser-js@1.0.38: + resolution: {integrity: sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==} - ufo@1.5.4: - resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + ufo@1.5.3: + resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -8848,11 +9951,11 @@ packages: resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} engines: {node: '>=14.0'} - unenv-nightly@2.0.0-20241024-111401-d4156ac: - resolution: {integrity: sha512-xJO1hfY+Te+/XnfCYrCbFbRcgu6XEODND1s5wnVbaBCkuQX7JXF7fHEXPrukFE2j8EOH848P8QN19VO47XN8hw==} + unenv-nightly@1.10.0-1717606461.a117952: + resolution: {integrity: sha512-u3TfBX02WzbHTpaEfWEKwDijDSFAHcgXkayUZ+MVDrjhLFvgAJzFGTSTmwlEhwWi2exyRQey23ah9wELMM6etg==} - unicode-canonical-property-names-ecmascript@2.0.1: - resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + unicode-canonical-property-names-ecmascript@2.0.0: + resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} engines: {node: '>=4'} unicode-emoji-modifier-base@1.0.0: @@ -8863,8 +9966,8 @@ packages: resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} engines: {node: '>=4'} - unicode-match-property-value-ecmascript@2.2.0: - resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} + unicode-match-property-value-ecmascript@2.1.0: + resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} engines: {node: '>=4'} unicode-property-aliases-ecmascript@2.1.0: @@ -8905,6 +10008,10 @@ packages: resolution: {integrity: sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==} engines: {node: '>= 10.0.0'} + universalify@2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -8913,8 +10020,8 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - update-browserslist-db@1.1.1: - resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + update-browserslist-db@1.0.16: + resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -8979,8 +10086,8 @@ packages: resolution: {integrity: sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - validate-npm-package-name@5.0.1: - resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} + validate-npm-package-name@5.0.0: + resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} vary@1.1.2: @@ -8992,8 +10099,8 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite-node@2.1.4: - resolution: {integrity: sha512-kqa9v+oi4HwkG6g8ufRnb5AeplcRw8jUF6/7/Qz1qRQOXHImG8YnLbB+LLszENwFnoBl9xIf9nVdCFzNd7GQEg==} + vite-node@2.1.2: + resolution: {integrity: sha512-HPcGNN5g/7I2OtPjLqgOtCRu/qhVvBxTUD3qzitmL0SrG1cWFzxzhMDWussxSbrRYWqnKf8P2jiNhPMSN+ymsQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -9005,8 +10112,8 @@ packages: vite: optional: true - vite@5.4.10: - resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} + vite@5.2.12: + resolution: {integrity: sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -9014,7 +10121,6 @@ packages: less: '*' lightningcss: ^1.21.0 sass: '*' - sass-embedded: '*' stylus: '*' sugarss: '*' terser: ^5.4.0 @@ -9027,7 +10133,33 @@ packages: optional: true sass: optional: true - sass-embedded: + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vite@5.3.3: + resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: optional: true stylus: optional: true @@ -9061,15 +10193,15 @@ packages: jsdom: optional: true - vitest@2.1.4: - resolution: {integrity: sha512-eDjxbVAJw1UJJCHr5xr/xM86Zx+YxIEXGAR+bmnEID7z9qWfoxpHw0zdobz+TQAFOLT+nEXz3+gx6nUJ7RgmlQ==} + vitest@2.1.2: + resolution: {integrity: sha512-veNjLizOMkRrJ6xxb+pvxN6/QAWg95mzcRjtmkepXdN87FNfxAss9RKe2far/G9cQpipfgP2taqg0KiWsquj8A==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.1.4 - '@vitest/ui': 2.1.4 + '@vitest/browser': 2.1.2 + '@vitest/ui': 2.1.2 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -9095,8 +10227,8 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + web-streams-polyfill@3.2.1: + resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} engines: {node: '>= 8'} webidl-conversions@3.0.1: @@ -9133,6 +10265,13 @@ packages: which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which-typed-array@1.1.11: + resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} + engines: {node: '>= 0.4'} + which-typed-array@1.1.15: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} @@ -9151,6 +10290,11 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} hasBin: true + why-is-node-running@2.2.2: + resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} + engines: {node: '>=8'} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -9162,28 +10306,28 @@ packages: wonka@4.0.15: resolution: {integrity: sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==} - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - workerd@1.20241022.0: - resolution: {integrity: sha512-jyGXsgO9DRcJyx6Ovv7gUyDPc3UYC2i/E0p9GFUg6GUzpldw4Y93y9kOmdfsOnKZ3+lY53veSiUniiBPE6Q2NQ==} + workerd@1.20240712.0: + resolution: {integrity: sha512-hdIHZif82hBDy9YnMtcmDGgbLU5f2P2aGpi/X8EKhTSLDppVUGrkY3XB536J4jGjA2D5dS0FUEXCl5bAJEed8Q==} engines: {node: '>=16'} hasBin: true - wrangler@3.85.0: - resolution: {integrity: sha512-r5YCWUaF4ApLnloNE6jHHgRYdFzYHoajTlC1tns42UzQ2Ls63VAqD3b0cxOqzDUfmlSb3skpmu0B0Ssi3QWPAg==} + wrangler@3.65.0: + resolution: {integrity: sha512-IDy4ttyJZssazAd5CXHw4NWeZFGxngdNF5m2ogltdT3CV7uHfCvPVdMcr4uNMpRZd0toHmAE3LtQeXxDFFp88A==} engines: {node: '>=16.17.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20241022.0 + '@cloudflare/workers-types': ^4.20240712.0 peerDependenciesMeta: '@cloudflare/workers-types': optional: true + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -9198,16 +10342,12 @@ packages: write-file-atomic@2.4.3: resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} - write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - write-file-atomic@5.0.1: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - ws@6.2.3: - resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} + ws@6.2.2: + resolution: {integrity: sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==} peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -9217,8 +10357,8 @@ packages: utf-8-validate: optional: true - ws@7.5.10: - resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 @@ -9241,6 +10381,18 @@ packages: utf-8-validate: optional: true + ws@8.17.0: + resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -9280,6 +10432,9 @@ packages: xxhash-wasm@1.0.2: resolution: {integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -9290,11 +10445,19 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yaml@2.6.0: - resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==} + yaml@2.3.1: + resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} + engines: {node: '>= 14'} + + yaml@2.4.2: + resolution: {integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==} engines: {node: '>= 14'} hasBin: true + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -9303,6 +10466,10 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} @@ -9319,34 +10486,33 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-queue@1.1.1: - resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==} + yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} - youch@3.3.4: - resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} + youch@3.3.3: + resolution: {integrity: sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==} - zod-validation-error@2.1.0: - resolution: {integrity: sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.18.0 + zod@3.21.4: + resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} - zod@3.23.8: - resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + zod@3.23.7: + resolution: {integrity: sha512-NBeIoqbtOiUMomACV/y+V3Qfs9+Okr18vR5c/5pHClPpufWOrsx8TENboDPe265lFdfewX2yBtNTLPvnmCxwog==} - zx@7.2.3: - resolution: {integrity: sha512-QODu38nLlYXg/B/Gw7ZKiZrvPkEsjPN3LQ5JFXM7h0JvwhEdPNNl+4Ao1y4+o3CLNiDUNcwzQYZ4/Ko7kKzCMA==} + zx@7.2.2: + resolution: {integrity: sha512-50Gjicd6ijTt7Zcz5fNX+rHrmE0uVqC+X6lYKhf2Cu8wIxDpNIzXwTmzchNdW+JY3LFsRcU43B1lHE4HBMmKgQ==} engines: {node: '>= 16.0.0'} hasBin: true - zx@8.2.0: - resolution: {integrity: sha512-ec7Z1Ki9h4CsKqbMjZ8H7G1PbbZYErscxT314LF66Ljx1YRENisqa5m9IN2VjbYgOKxdv5t0MbVd3Hf+II3e7w==} + zx@8.2.2: + resolution: {integrity: sha512-HSIdpU5P2ONI0nssnhsUZNCH9Sd/Z8LIFk9n8QTbu6JufzJx7qR7ajrMN21s06JqWSApcN012377iWsv8Vs5bg==} engines: {node: '>= 12.17.0'} hasBin: true snapshots: + '@aashutoshrathi/word-wrap@1.2.6': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.5 @@ -9358,30 +10524,30 @@ snapshots: dependencies: '@arethetypeswrong/core': 0.15.1 chalk: 4.1.2 - cli-table3: 0.6.5 + cli-table3: 0.6.3 commander: 10.0.1 marked: 9.1.6 marked-terminal: 6.2.0(marked@9.1.6) - semver: 7.6.3 + semver: 7.6.2 '@arethetypeswrong/cli@0.16.4': dependencies: '@arethetypeswrong/core': 0.16.4 chalk: 4.1.2 - cli-table3: 0.6.5 + cli-table3: 0.6.3 commander: 10.0.1 marked: 9.1.6 marked-terminal: 7.2.1(marked@9.1.6) - semver: 7.6.3 + semver: 7.6.2 '@arethetypeswrong/core@0.15.1': dependencies: '@andrewbranch/untar.js': 1.0.3 fflate: 0.8.2 - semver: 7.6.3 + semver: 7.6.2 ts-expose-internals-conditionally: 1.0.0-empty.0 typescript: 5.3.3 - validate-npm-package-name: 5.0.1 + validate-npm-package-name: 5.0.0 '@arethetypeswrong/core@0.16.4': dependencies: @@ -9389,1463 +10555,2223 @@ snapshots: cjs-module-lexer: 1.4.1 fflate: 0.8.2 lru-cache: 10.4.3 - semver: 7.6.3 + semver: 7.6.2 typescript: 5.6.1-rc - validate-npm-package-name: 5.0.1 + validate-npm-package-name: 5.0.0 - '@aws-crypto/sha256-browser@5.2.0': + '@ava/typescript@5.0.0': dependencies: - '@aws-crypto/sha256-js': 5.2.0 - '@aws-crypto/supports-web-crypto': 5.2.0 - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.686.0 - '@aws-sdk/util-locate-window': 3.679.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 + escape-string-regexp: 5.0.0 + execa: 8.0.1 + optional: true - '@aws-crypto/sha256-js@5.2.0': + '@aws-crypto/crc32@3.0.0': dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.686.0 - tslib: 2.8.1 + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.577.0 + tslib: 1.14.1 - '@aws-crypto/supports-web-crypto@5.2.0': + '@aws-crypto/ie11-detection@3.0.0': dependencies: - tslib: 2.8.1 + tslib: 1.14.1 + + '@aws-crypto/sha256-browser@3.0.0': + dependencies: + '@aws-crypto/ie11-detection': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-crypto/supports-web-crypto': 3.0.0 + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-locate-window': 3.568.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + + '@aws-crypto/sha256-js@3.0.0': + dependencies: + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.577.0 + tslib: 1.14.1 + + '@aws-crypto/supports-web-crypto@3.0.0': + dependencies: + tslib: 1.14.1 - '@aws-crypto/util@5.2.0': + '@aws-crypto/util@3.0.0': dependencies: - '@aws-sdk/types': 3.686.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + + '@aws-sdk/client-cognito-identity@3.569.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.569.0 + '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/core': 3.567.0 + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/middleware-host-header': 3.567.0 + '@aws-sdk/middleware-logger': 3.568.0 + '@aws-sdk/middleware-recursion-detection': 3.567.0 + '@aws-sdk/middleware-user-agent': 3.567.0 + '@aws-sdk/region-config-resolver': 3.567.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@aws-sdk/util-user-agent-browser': 3.567.0 + '@aws-sdk/util-user-agent-node': 3.568.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt - '@aws-sdk/client-cognito-identity@3.687.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.687.0(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/client-sts': 3.687.0 - '@aws-sdk/core': 3.686.0 - '@aws-sdk/credential-provider-node': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/middleware-host-header': 3.686.0 - '@aws-sdk/middleware-logger': 3.686.0 - '@aws-sdk/middleware-recursion-detection': 3.686.0 - '@aws-sdk/middleware-user-agent': 3.687.0 - '@aws-sdk/region-config-resolver': 3.686.0 - '@aws-sdk/types': 3.686.0 - '@aws-sdk/util-endpoints': 3.686.0 - '@aws-sdk/util-user-agent-browser': 3.686.0 - '@aws-sdk/util-user-agent-node': 3.687.0 - '@smithy/config-resolver': 3.0.10 - '@smithy/core': 2.5.1 - '@smithy/fetch-http-handler': 4.0.0 - '@smithy/hash-node': 3.0.8 - '@smithy/invalid-dependency': 3.0.8 - '@smithy/middleware-content-length': 3.0.10 - '@smithy/middleware-endpoint': 3.2.1 - '@smithy/middleware-retry': 3.0.25 - '@smithy/middleware-serde': 3.0.8 - '@smithy/middleware-stack': 3.0.8 - '@smithy/node-config-provider': 3.1.9 - '@smithy/node-http-handler': 3.2.5 - '@smithy/protocol-http': 4.1.5 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 - '@smithy/url-parser': 3.0.8 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.25 - '@smithy/util-defaults-mode-node': 3.0.25 - '@smithy/util-endpoints': 2.1.4 - '@smithy/util-middleware': 3.0.8 - '@smithy/util-retry': 3.0.8 - '@smithy/util-utf8': 3.0.0 + '@aws-sdk/client-lambda@3.478.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.478.0 + '@aws-sdk/core': 3.477.0 + '@aws-sdk/credential-provider-node': 3.478.0 + '@aws-sdk/middleware-host-header': 3.468.0 + '@aws-sdk/middleware-logger': 3.468.0 + '@aws-sdk/middleware-recursion-detection': 3.468.0 + '@aws-sdk/middleware-signing': 3.468.0 + '@aws-sdk/middleware-user-agent': 3.478.0 + '@aws-sdk/region-config-resolver': 3.470.0 + '@aws-sdk/types': 3.468.0 + '@aws-sdk/util-endpoints': 3.478.0 + '@aws-sdk/util-user-agent-browser': 3.468.0 + '@aws-sdk/util-user-agent-node': 3.470.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/eventstream-serde-browser': 2.2.0 + '@smithy/eventstream-serde-config-resolver': 2.2.0 + '@smithy/eventstream-serde-node': 2.2.0 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-stream': 2.2.0 + '@smithy/util-utf8': 2.3.0 + '@smithy/util-waiter': 2.2.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-rds-data@3.687.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.687.0(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/client-sts': 3.687.0 - '@aws-sdk/core': 3.686.0 - '@aws-sdk/credential-provider-node': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/middleware-host-header': 3.686.0 - '@aws-sdk/middleware-logger': 3.686.0 - '@aws-sdk/middleware-recursion-detection': 3.686.0 - '@aws-sdk/middleware-user-agent': 3.687.0 - '@aws-sdk/region-config-resolver': 3.686.0 - '@aws-sdk/types': 3.686.0 - '@aws-sdk/util-endpoints': 3.686.0 - '@aws-sdk/util-user-agent-browser': 3.686.0 - '@aws-sdk/util-user-agent-node': 3.687.0 - '@smithy/config-resolver': 3.0.10 - '@smithy/core': 2.5.1 - '@smithy/fetch-http-handler': 4.0.0 - '@smithy/hash-node': 3.0.8 - '@smithy/invalid-dependency': 3.0.8 - '@smithy/middleware-content-length': 3.0.10 - '@smithy/middleware-endpoint': 3.2.1 - '@smithy/middleware-retry': 3.0.25 - '@smithy/middleware-serde': 3.0.8 - '@smithy/middleware-stack': 3.0.8 - '@smithy/node-config-provider': 3.1.9 - '@smithy/node-http-handler': 3.2.5 - '@smithy/protocol-http': 4.1.5 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 - '@smithy/url-parser': 3.0.8 + '@aws-sdk/client-rds-data@3.583.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/core': 3.582.0 + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/middleware-host-header': 3.577.0 + '@aws-sdk/middleware-logger': 3.577.0 + '@aws-sdk/middleware-recursion-detection': 3.577.0 + '@aws-sdk/middleware-user-agent': 3.583.0 + '@aws-sdk/region-config-resolver': 3.577.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-endpoints': 3.583.0 + '@aws-sdk/util-user-agent-browser': 3.577.0 + '@aws-sdk/util-user-agent-node': 3.577.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 + '@smithy/fetch-http-handler': 3.0.1 + '@smithy/hash-node': 3.0.0 + '@smithy/invalid-dependency': 3.0.0 + '@smithy/middleware-content-length': 3.0.0 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 + '@smithy/middleware-serde': 3.0.0 + '@smithy/middleware-stack': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/node-http-handler': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + '@smithy/url-parser': 3.0.0 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.25 - '@smithy/util-defaults-mode-node': 3.0.25 - '@smithy/util-endpoints': 2.1.4 - '@smithy/util-middleware': 3.0.8 - '@smithy/util-retry': 3.0.8 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 + '@smithy/util-middleware': 3.0.0 + '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso-oidc@3.569.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/core': 3.567.0 + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/middleware-host-header': 3.567.0 + '@aws-sdk/middleware-logger': 3.568.0 + '@aws-sdk/middleware-recursion-detection': 3.567.0 + '@aws-sdk/middleware-user-agent': 3.567.0 + '@aws-sdk/region-config-resolver': 3.567.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@aws-sdk/util-user-agent-browser': 3.567.0 + '@aws-sdk/util-user-agent-node': 3.568.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sts': 3.687.0 - '@aws-sdk/core': 3.686.0 - '@aws-sdk/credential-provider-node': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/middleware-host-header': 3.686.0 - '@aws-sdk/middleware-logger': 3.686.0 - '@aws-sdk/middleware-recursion-detection': 3.686.0 - '@aws-sdk/middleware-user-agent': 3.687.0 - '@aws-sdk/region-config-resolver': 3.686.0 - '@aws-sdk/types': 3.686.0 - '@aws-sdk/util-endpoints': 3.686.0 - '@aws-sdk/util-user-agent-browser': 3.686.0 - '@aws-sdk/util-user-agent-node': 3.687.0 - '@smithy/config-resolver': 3.0.10 - '@smithy/core': 2.5.1 - '@smithy/fetch-http-handler': 4.0.0 - '@smithy/hash-node': 3.0.8 - '@smithy/invalid-dependency': 3.0.8 - '@smithy/middleware-content-length': 3.0.10 - '@smithy/middleware-endpoint': 3.2.1 - '@smithy/middleware-retry': 3.0.25 - '@smithy/middleware-serde': 3.0.8 - '@smithy/middleware-stack': 3.0.8 - '@smithy/node-config-provider': 3.1.9 - '@smithy/node-http-handler': 3.2.5 - '@smithy/protocol-http': 4.1.5 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 - '@smithy/url-parser': 3.0.8 + '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/core': 3.582.0 + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/middleware-host-header': 3.577.0 + '@aws-sdk/middleware-logger': 3.577.0 + '@aws-sdk/middleware-recursion-detection': 3.577.0 + '@aws-sdk/middleware-user-agent': 3.583.0 + '@aws-sdk/region-config-resolver': 3.577.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-endpoints': 3.583.0 + '@aws-sdk/util-user-agent-browser': 3.577.0 + '@aws-sdk/util-user-agent-node': 3.577.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 + '@smithy/fetch-http-handler': 3.0.1 + '@smithy/hash-node': 3.0.0 + '@smithy/invalid-dependency': 3.0.0 + '@smithy/middleware-content-length': 3.0.0 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 + '@smithy/middleware-serde': 3.0.0 + '@smithy/middleware-stack': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/node-http-handler': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + '@smithy/url-parser': 3.0.0 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.25 - '@smithy/util-defaults-mode-node': 3.0.25 - '@smithy/util-endpoints': 2.1.4 - '@smithy/util-middleware': 3.0.8 - '@smithy/util-retry': 3.0.8 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 + '@smithy/util-middleware': 3.0.0 + '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sts' + - aws-crt + + '@aws-sdk/client-sso@3.478.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/core': 3.477.0 + '@aws-sdk/middleware-host-header': 3.468.0 + '@aws-sdk/middleware-logger': 3.468.0 + '@aws-sdk/middleware-recursion-detection': 3.468.0 + '@aws-sdk/middleware-user-agent': 3.478.0 + '@aws-sdk/region-config-resolver': 3.470.0 + '@aws-sdk/types': 3.468.0 + '@aws-sdk/util-endpoints': 3.478.0 + '@aws-sdk/util-user-agent-browser': 3.468.0 + '@aws-sdk/util-user-agent-node': 3.470.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso@3.568.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/core': 3.567.0 + '@aws-sdk/middleware-host-header': 3.567.0 + '@aws-sdk/middleware-logger': 3.568.0 + '@aws-sdk/middleware-recursion-detection': 3.567.0 + '@aws-sdk/middleware-user-agent': 3.567.0 + '@aws-sdk/region-config-resolver': 3.567.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@aws-sdk/util-user-agent-browser': 3.567.0 + '@aws-sdk/util-user-agent-node': 3.568.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso@3.687.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.686.0 - '@aws-sdk/middleware-host-header': 3.686.0 - '@aws-sdk/middleware-logger': 3.686.0 - '@aws-sdk/middleware-recursion-detection': 3.686.0 - '@aws-sdk/middleware-user-agent': 3.687.0 - '@aws-sdk/region-config-resolver': 3.686.0 - '@aws-sdk/types': 3.686.0 - '@aws-sdk/util-endpoints': 3.686.0 - '@aws-sdk/util-user-agent-browser': 3.686.0 - '@aws-sdk/util-user-agent-node': 3.687.0 - '@smithy/config-resolver': 3.0.10 - '@smithy/core': 2.5.1 - '@smithy/fetch-http-handler': 4.0.0 - '@smithy/hash-node': 3.0.8 - '@smithy/invalid-dependency': 3.0.8 - '@smithy/middleware-content-length': 3.0.10 - '@smithy/middleware-endpoint': 3.2.1 - '@smithy/middleware-retry': 3.0.25 - '@smithy/middleware-serde': 3.0.8 - '@smithy/middleware-stack': 3.0.8 - '@smithy/node-config-provider': 3.1.9 - '@smithy/node-http-handler': 3.2.5 - '@smithy/protocol-http': 4.1.5 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 - '@smithy/url-parser': 3.0.8 + '@aws-sdk/client-sso@3.583.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/core': 3.582.0 + '@aws-sdk/middleware-host-header': 3.577.0 + '@aws-sdk/middleware-logger': 3.577.0 + '@aws-sdk/middleware-recursion-detection': 3.577.0 + '@aws-sdk/middleware-user-agent': 3.583.0 + '@aws-sdk/region-config-resolver': 3.577.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-endpoints': 3.583.0 + '@aws-sdk/util-user-agent-browser': 3.577.0 + '@aws-sdk/util-user-agent-node': 3.577.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 + '@smithy/fetch-http-handler': 3.0.1 + '@smithy/hash-node': 3.0.0 + '@smithy/invalid-dependency': 3.0.0 + '@smithy/middleware-content-length': 3.0.0 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 + '@smithy/middleware-serde': 3.0.0 + '@smithy/middleware-stack': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/node-http-handler': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + '@smithy/url-parser': 3.0.0 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.25 - '@smithy/util-defaults-mode-node': 3.0.25 - '@smithy/util-endpoints': 2.1.4 - '@smithy/util-middleware': 3.0.8 - '@smithy/util-retry': 3.0.8 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 + '@smithy/util-middleware': 3.0.0 + '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sts@3.687.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.687.0(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/core': 3.686.0 - '@aws-sdk/credential-provider-node': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/middleware-host-header': 3.686.0 - '@aws-sdk/middleware-logger': 3.686.0 - '@aws-sdk/middleware-recursion-detection': 3.686.0 - '@aws-sdk/middleware-user-agent': 3.687.0 - '@aws-sdk/region-config-resolver': 3.686.0 - '@aws-sdk/types': 3.686.0 - '@aws-sdk/util-endpoints': 3.686.0 - '@aws-sdk/util-user-agent-browser': 3.686.0 - '@aws-sdk/util-user-agent-node': 3.687.0 - '@smithy/config-resolver': 3.0.10 - '@smithy/core': 2.5.1 - '@smithy/fetch-http-handler': 4.0.0 - '@smithy/hash-node': 3.0.8 - '@smithy/invalid-dependency': 3.0.8 - '@smithy/middleware-content-length': 3.0.10 - '@smithy/middleware-endpoint': 3.2.1 - '@smithy/middleware-retry': 3.0.25 - '@smithy/middleware-serde': 3.0.8 - '@smithy/middleware-stack': 3.0.8 - '@smithy/node-config-provider': 3.1.9 - '@smithy/node-http-handler': 3.2.5 - '@smithy/protocol-http': 4.1.5 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 - '@smithy/url-parser': 3.0.8 + '@aws-sdk/client-sts@3.478.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/core': 3.477.0 + '@aws-sdk/credential-provider-node': 3.478.0 + '@aws-sdk/middleware-host-header': 3.468.0 + '@aws-sdk/middleware-logger': 3.468.0 + '@aws-sdk/middleware-recursion-detection': 3.468.0 + '@aws-sdk/middleware-user-agent': 3.478.0 + '@aws-sdk/region-config-resolver': 3.470.0 + '@aws-sdk/types': 3.468.0 + '@aws-sdk/util-endpoints': 3.478.0 + '@aws-sdk/util-user-agent-browser': 3.468.0 + '@aws-sdk/util-user-agent-node': 3.470.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + fast-xml-parser: 4.2.5 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sts@3.569.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.569.0 + '@aws-sdk/core': 3.567.0 + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/middleware-host-header': 3.567.0 + '@aws-sdk/middleware-logger': 3.568.0 + '@aws-sdk/middleware-recursion-detection': 3.567.0 + '@aws-sdk/middleware-user-agent': 3.567.0 + '@aws-sdk/region-config-resolver': 3.567.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@aws-sdk/util-user-agent-browser': 3.567.0 + '@aws-sdk/util-user-agent-node': 3.568.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.569.0 + '@aws-sdk/core': 3.567.0 + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/middleware-host-header': 3.567.0 + '@aws-sdk/middleware-logger': 3.568.0 + '@aws-sdk/middleware-recursion-detection': 3.567.0 + '@aws-sdk/middleware-user-agent': 3.567.0 + '@aws-sdk/region-config-resolver': 3.567.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@aws-sdk/util-user-agent-browser': 3.567.0 + '@aws-sdk/util-user-agent-node': 3.568.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + + '@aws-sdk/client-sts@3.583.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/core': 3.582.0 + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/middleware-host-header': 3.577.0 + '@aws-sdk/middleware-logger': 3.577.0 + '@aws-sdk/middleware-recursion-detection': 3.577.0 + '@aws-sdk/middleware-user-agent': 3.583.0 + '@aws-sdk/region-config-resolver': 3.577.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-endpoints': 3.583.0 + '@aws-sdk/util-user-agent-browser': 3.577.0 + '@aws-sdk/util-user-agent-node': 3.577.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 + '@smithy/fetch-http-handler': 3.0.1 + '@smithy/hash-node': 3.0.0 + '@smithy/invalid-dependency': 3.0.0 + '@smithy/middleware-content-length': 3.0.0 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 + '@smithy/middleware-serde': 3.0.0 + '@smithy/middleware-stack': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/node-http-handler': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + '@smithy/url-parser': 3.0.0 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.25 - '@smithy/util-defaults-mode-node': 3.0.25 - '@smithy/util-endpoints': 2.1.4 - '@smithy/util-middleware': 3.0.8 - '@smithy/util-retry': 3.0.8 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 + '@smithy/util-middleware': 3.0.0 + '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.686.0': - dependencies: - '@aws-sdk/types': 3.686.0 - '@smithy/core': 2.5.1 - '@smithy/node-config-provider': 3.1.9 - '@smithy/property-provider': 3.1.8 - '@smithy/protocol-http': 4.1.5 - '@smithy/signature-v4': 4.2.1 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 - '@smithy/util-middleware': 3.0.8 - fast-xml-parser: 4.4.1 + '@aws-sdk/core@3.477.0': + dependencies: + '@smithy/core': 1.4.2 + '@smithy/protocol-http': 3.3.0 + '@smithy/signature-v4': 2.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/core@3.567.0': + dependencies: + '@smithy/core': 1.4.2 + '@smithy/protocol-http': 3.3.0 + '@smithy/signature-v4': 2.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + fast-xml-parser: 4.2.5 tslib: 2.8.1 - '@aws-sdk/credential-provider-cognito-identity@3.687.0': + '@aws-sdk/core@3.582.0': dependencies: - '@aws-sdk/client-cognito-identity': 3.687.0 - '@aws-sdk/types': 3.686.0 - '@smithy/property-provider': 3.1.8 - '@smithy/types': 3.6.0 + '@smithy/core': 2.0.1 + '@smithy/protocol-http': 4.0.0 + '@smithy/signature-v4': 3.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + fast-xml-parser: 4.2.5 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-cognito-identity@3.569.0': + dependencies: + '@aws-sdk/client-cognito-identity': 3.569.0 + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-env@3.686.0': + '@aws-sdk/credential-provider-env@3.468.0': + dependencies: + '@aws-sdk/types': 3.468.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.568.0': + dependencies: + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.577.0': + dependencies: + '@aws-sdk/types': 3.577.0 + '@smithy/property-provider': 3.0.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.568.0': dependencies: - '@aws-sdk/core': 3.686.0 - '@aws-sdk/types': 3.686.0 - '@smithy/property-provider': 3.1.8 - '@smithy/types': 3.6.0 + '@aws-sdk/types': 3.567.0 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/property-provider': 2.2.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/util-stream': 2.2.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.686.0': - dependencies: - '@aws-sdk/core': 3.686.0 - '@aws-sdk/types': 3.686.0 - '@smithy/fetch-http-handler': 4.0.0 - '@smithy/node-http-handler': 3.2.5 - '@smithy/property-provider': 3.1.8 - '@smithy/protocol-http': 4.1.5 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 - '@smithy/util-stream': 3.2.1 + '@aws-sdk/credential-provider-http@3.582.0': + dependencies: + '@aws-sdk/types': 3.577.0 + '@smithy/fetch-http-handler': 3.0.1 + '@smithy/node-http-handler': 3.0.0 + '@smithy/property-provider': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + '@smithy/util-stream': 3.0.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.478.0': + dependencies: + '@aws-sdk/credential-provider-env': 3.468.0 + '@aws-sdk/credential-provider-process': 3.468.0 + '@aws-sdk/credential-provider-sso': 3.478.0 + '@aws-sdk/credential-provider-web-identity': 3.468.0 + '@aws-sdk/types': 3.468.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt - '@aws-sdk/credential-provider-ini@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0)': - dependencies: - '@aws-sdk/client-sts': 3.687.0 - '@aws-sdk/core': 3.686.0 - '@aws-sdk/credential-provider-env': 3.686.0 - '@aws-sdk/credential-provider-http': 3.686.0 - '@aws-sdk/credential-provider-process': 3.686.0 - '@aws-sdk/credential-provider-sso': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)) - '@aws-sdk/credential-provider-web-identity': 3.686.0(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/types': 3.686.0 - '@smithy/credential-provider-imds': 3.2.5 - '@smithy/property-provider': 3.1.8 - '@smithy/shared-ini-file-loader': 3.1.9 - '@smithy/types': 3.6.0 + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + dependencies: + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-env': 3.568.0 + '@aws-sdk/credential-provider-process': 3.568.0 + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/types': 3.567.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-node@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0)': - dependencies: - '@aws-sdk/credential-provider-env': 3.686.0 - '@aws-sdk/credential-provider-http': 3.686.0 - '@aws-sdk/credential-provider-ini': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/credential-provider-process': 3.686.0 - '@aws-sdk/credential-provider-sso': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)) - '@aws-sdk/credential-provider-web-identity': 3.686.0(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/types': 3.686.0 - '@smithy/credential-provider-imds': 3.2.5 - '@smithy/property-provider': 3.1.8 - '@smithy/shared-ini-file-loader': 3.1.9 - '@smithy/types': 3.6.0 + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': + dependencies: + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-env': 3.568.0 + '@aws-sdk/credential-provider-process': 3.568.0 + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/types': 3.567.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-process@3.686.0': - dependencies: - '@aws-sdk/core': 3.686.0 - '@aws-sdk/types': 3.686.0 - '@smithy/property-provider': 3.1.8 - '@smithy/shared-ini-file-loader': 3.1.9 - '@smithy/types': 3.6.0 + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + dependencies: + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-env': 3.568.0 + '@aws-sdk/credential-provider-process': 3.568.0 + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/types': 3.567.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt - '@aws-sdk/credential-provider-sso@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))': - dependencies: - '@aws-sdk/client-sso': 3.687.0 - '@aws-sdk/core': 3.686.0 - '@aws-sdk/token-providers': 3.686.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)) - '@aws-sdk/types': 3.686.0 - '@smithy/property-provider': 3.1.8 - '@smithy/shared-ini-file-loader': 3.1.9 - '@smithy/types': 3.6.0 + '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': + dependencies: + '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/credential-provider-env': 3.577.0 + '@aws-sdk/credential-provider-process': 3.577.0 + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/types': 3.577.0 + '@smithy/credential-provider-imds': 3.0.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-web-identity@3.686.0(@aws-sdk/client-sts@3.687.0)': - dependencies: - '@aws-sdk/client-sts': 3.687.0 - '@aws-sdk/core': 3.686.0 - '@aws-sdk/types': 3.686.0 - '@smithy/property-provider': 3.1.8 - '@smithy/types': 3.6.0 + '@aws-sdk/credential-provider-node@3.478.0': + dependencies: + '@aws-sdk/credential-provider-env': 3.468.0 + '@aws-sdk/credential-provider-ini': 3.478.0 + '@aws-sdk/credential-provider-process': 3.468.0 + '@aws-sdk/credential-provider-sso': 3.478.0 + '@aws-sdk/credential-provider-web-identity': 3.468.0 + '@aws-sdk/types': 3.468.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt - '@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))': - dependencies: - '@aws-sdk/client-cognito-identity': 3.687.0 - '@aws-sdk/client-sso': 3.687.0 - '@aws-sdk/client-sts': 3.687.0 - '@aws-sdk/core': 3.686.0 - '@aws-sdk/credential-provider-cognito-identity': 3.687.0 - '@aws-sdk/credential-provider-env': 3.686.0 - '@aws-sdk/credential-provider-http': 3.686.0 - '@aws-sdk/credential-provider-ini': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/credential-provider-node': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/credential-provider-process': 3.686.0 - '@aws-sdk/credential-provider-sso': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)) - '@aws-sdk/credential-provider-web-identity': 3.686.0(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/types': 3.686.0 - '@smithy/credential-provider-imds': 3.2.5 - '@smithy/property-provider': 3.1.8 - '@smithy/types': 3.6.0 + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + dependencies: + '@aws-sdk/credential-provider-env': 3.568.0 + '@aws-sdk/credential-provider-http': 3.568.0 + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-process': 3.568.0 + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/types': 3.567.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/middleware-host-header@3.686.0': - dependencies: - '@aws-sdk/types': 3.686.0 - '@smithy/protocol-http': 4.1.5 - '@smithy/types': 3.6.0 + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': + dependencies: + '@aws-sdk/credential-provider-env': 3.568.0 + '@aws-sdk/credential-provider-http': 3.568.0 + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/credential-provider-process': 3.568.0 + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/types': 3.567.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt - '@aws-sdk/middleware-logger@3.686.0': - dependencies: - '@aws-sdk/types': 3.686.0 - '@smithy/types': 3.6.0 + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': + dependencies: + '@aws-sdk/credential-provider-env': 3.568.0 + '@aws-sdk/credential-provider-http': 3.568.0 + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-process': 3.568.0 + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/types': 3.567.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + + '@aws-sdk/credential-provider-node@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': + dependencies: + '@aws-sdk/credential-provider-env': 3.577.0 + '@aws-sdk/credential-provider-http': 3.582.0 + '@aws-sdk/credential-provider-ini': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/credential-provider-process': 3.577.0 + '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/types': 3.577.0 + '@smithy/credential-provider-imds': 3.0.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt - '@aws-sdk/middleware-recursion-detection@3.686.0': + '@aws-sdk/credential-provider-process@3.468.0': dependencies: - '@aws-sdk/types': 3.686.0 - '@smithy/protocol-http': 4.1.5 - '@smithy/types': 3.6.0 + '@aws-sdk/types': 3.468.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.687.0': + '@aws-sdk/credential-provider-process@3.568.0': dependencies: - '@aws-sdk/core': 3.686.0 - '@aws-sdk/types': 3.686.0 - '@aws-sdk/util-endpoints': 3.686.0 - '@smithy/core': 2.5.1 - '@smithy/protocol-http': 4.1.5 - '@smithy/types': 3.6.0 + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@aws-sdk/region-config-resolver@3.686.0': + '@aws-sdk/credential-provider-process@3.577.0': dependencies: - '@aws-sdk/types': 3.686.0 - '@smithy/node-config-provider': 3.1.9 - '@smithy/types': 3.6.0 - '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.8 + '@aws-sdk/types': 3.577.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 - '@aws-sdk/token-providers@3.686.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))': + '@aws-sdk/credential-provider-sso@3.478.0': dependencies: - '@aws-sdk/client-sso-oidc': 3.687.0(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/types': 3.686.0 - '@smithy/property-provider': 3.1.8 - '@smithy/shared-ini-file-loader': 3.1.9 - '@smithy/types': 3.6.0 + '@aws-sdk/client-sso': 3.478.0 + '@aws-sdk/token-providers': 3.478.0 + '@aws-sdk/types': 3.468.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt - '@aws-sdk/types@3.686.0': + '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)': dependencies: - '@smithy/types': 3.6.0 + '@aws-sdk/client-sso': 3.568.0 + '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt - '@aws-sdk/util-endpoints@3.686.0': + '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/types': 3.686.0 - '@smithy/types': 3.6.0 - '@smithy/util-endpoints': 2.1.4 + '@aws-sdk/client-sso': 3.568.0 + '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt - '@aws-sdk/util-locate-window@3.679.0': + '@aws-sdk/credential-provider-sso@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: + '@aws-sdk/client-sso': 3.583.0 + '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/types': 3.577.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt - '@aws-sdk/util-user-agent-browser@3.686.0': + '@aws-sdk/credential-provider-web-identity@3.468.0': dependencies: - '@aws-sdk/types': 3.686.0 - '@smithy/types': 3.6.0 - bowser: 2.11.0 + '@aws-sdk/types': 3.468.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.687.0': + '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: - '@aws-sdk/middleware-user-agent': 3.687.0 - '@aws-sdk/types': 3.686.0 - '@smithy/node-config-provider': 3.1.9 - '@smithy/types': 3.6.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@babel/code-frame@7.10.4': + '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': dependencies: - '@babel/highlight': 7.25.9 + '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/code-frame@7.26.2': + '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@babel/helper-validator-identifier': 7.25.9 - js-tokens: 4.0.0 - picocolors: 1.1.1 + '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/types': 3.577.0 + '@smithy/property-provider': 3.0.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 - '@babel/compat-data@7.26.2': {} + '@aws-sdk/credential-providers@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)': + dependencies: + '@aws-sdk/client-cognito-identity': 3.569.0 + '@aws-sdk/client-sso': 3.568.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) + '@aws-sdk/credential-provider-cognito-identity': 3.569.0 + '@aws-sdk/credential-provider-env': 3.568.0 + '@aws-sdk/credential-provider-http': 3.568.0 + '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-process': 3.568.0 + '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/types': 3.567.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt - '@babel/core@7.26.0': + '@aws-sdk/middleware-host-header@3.468.0': dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.2 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helpers': 7.26.0 - '@babel/parser': 7.26.2 - '@babel/template': 7.25.9 - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - convert-source-map: 2.0.0 - debug: 4.3.7 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color + '@aws-sdk/types': 3.468.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/generator@7.17.7': + '@aws-sdk/middleware-host-header@3.567.0': dependencies: - '@babel/types': 7.17.0 - jsesc: 2.5.2 - source-map: 0.5.7 + '@aws-sdk/types': 3.567.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/generator@7.2.0': + '@aws-sdk/middleware-host-header@3.577.0': dependencies: - '@babel/types': 7.26.0 - jsesc: 2.5.2 - lodash: 4.17.21 - source-map: 0.5.7 - trim-right: 1.0.1 + '@aws-sdk/types': 3.577.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 - '@babel/generator@7.26.2': + '@aws-sdk/middleware-logger@3.468.0': dependencies: - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 3.0.2 + '@aws-sdk/types': 3.468.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/helper-annotate-as-pure@7.25.9': + '@aws-sdk/middleware-logger@3.568.0': dependencies: - '@babel/types': 7.26.0 + '@aws-sdk/types': 3.567.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/helper-builder-binary-assignment-operator-visitor@7.25.9': + '@aws-sdk/middleware-logger@3.577.0': dependencies: - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@aws-sdk/types': 3.577.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 - '@babel/helper-compilation-targets@7.25.9': + '@aws-sdk/middleware-recursion-detection@3.468.0': dependencies: - '@babel/compat-data': 7.26.2 - '@babel/helper-validator-option': 7.25.9 - browserslist: 4.24.2 - lru-cache: 5.1.1 - semver: 6.3.1 + '@aws-sdk/types': 3.468.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.0)': + '@aws-sdk/middleware-recursion-detection@3.567.0': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-member-expression-to-functions': 7.25.9 - '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/traverse': 7.25.9 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color + '@aws-sdk/types': 3.567.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/helper-create-regexp-features-plugin@7.25.9(@babel/core@7.26.0)': + '@aws-sdk/middleware-recursion-detection@3.577.0': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - regexpu-core: 6.1.1 - semver: 6.3.1 + '@aws-sdk/types': 3.577.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 - '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.26.0)': + '@aws-sdk/middleware-signing@3.468.0': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.7 - lodash.debounce: 4.0.8 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color + '@aws-sdk/types': 3.468.0 + '@smithy/property-provider': 2.2.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/signature-v4': 2.3.0 + '@smithy/types': 2.12.0 + '@smithy/util-middleware': 2.2.0 + tslib: 2.8.1 - '@babel/helper-environment-visitor@7.24.7': + '@aws-sdk/middleware-user-agent@3.478.0': dependencies: - '@babel/types': 7.26.0 + '@aws-sdk/types': 3.468.0 + '@aws-sdk/util-endpoints': 3.478.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/helper-function-name@7.24.7': + '@aws-sdk/middleware-user-agent@3.567.0': dependencies: - '@babel/template': 7.25.9 - '@babel/types': 7.26.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/helper-hoist-variables@7.24.7': + '@aws-sdk/middleware-user-agent@3.583.0': dependencies: - '@babel/types': 7.26.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-endpoints': 3.583.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 - '@babel/helper-member-expression-to-functions@7.25.9': + '@aws-sdk/region-config-resolver@3.470.0': dependencies: - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@smithy/node-config-provider': 2.3.0 + '@smithy/types': 2.12.0 + '@smithy/util-config-provider': 2.3.0 + '@smithy/util-middleware': 2.2.0 + tslib: 2.8.1 - '@babel/helper-module-imports@7.25.9': + '@aws-sdk/region-config-resolver@3.567.0': dependencies: - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@aws-sdk/types': 3.567.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/types': 2.12.0 + '@smithy/util-config-provider': 2.3.0 + '@smithy/util-middleware': 2.2.0 + tslib: 2.8.1 - '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': + '@aws-sdk/region-config-resolver@3.577.0': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.25.9 + '@aws-sdk/types': 3.577.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/types': 3.0.0 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.478.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/middleware-host-header': 3.468.0 + '@aws-sdk/middleware-logger': 3.468.0 + '@aws-sdk/middleware-recursion-detection': 3.468.0 + '@aws-sdk/middleware-user-agent': 3.478.0 + '@aws-sdk/region-config-resolver': 3.470.0 + '@aws-sdk/types': 3.468.0 + '@aws-sdk/util-endpoints': 3.478.0 + '@aws-sdk/util-user-agent-browser': 3.468.0 + '@aws-sdk/util-user-agent-node': 3.470.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/property-provider': 2.2.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 transitivePeerDependencies: - - supports-color + - aws-crt - '@babel/helper-optimise-call-expression@7.25.9': + '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)': dependencies: - '@babel/types': 7.26.0 + '@aws-sdk/client-sso-oidc': 3.569.0 + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/helper-plugin-utils@7.25.9': {} + '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': + dependencies: + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/types': 3.567.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.0)': + '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-wrap-function': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/types': 3.577.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 - '@babel/helper-replace-supers@7.25.9(@babel/core@7.26.0)': + '@aws-sdk/types@3.468.0': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-member-expression-to-functions': 7.25.9 - '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/helper-simple-access@7.25.9': + '@aws-sdk/types@3.567.0': dependencies: - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + '@aws-sdk/types@3.577.0': dependencies: - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@smithy/types': 3.0.0 + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.478.0': + dependencies: + '@aws-sdk/types': 3.468.0 + '@smithy/util-endpoints': 1.2.0 + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.567.0': + dependencies: + '@aws-sdk/types': 3.567.0 + '@smithy/types': 2.12.0 + '@smithy/util-endpoints': 1.2.0 + tslib: 2.8.1 - '@babel/helper-split-export-declaration@7.24.7': + '@aws-sdk/util-endpoints@3.583.0': dependencies: - '@babel/types': 7.26.0 + '@aws-sdk/types': 3.577.0 + '@smithy/types': 3.0.0 + '@smithy/util-endpoints': 2.0.0 + tslib: 2.8.1 - '@babel/helper-string-parser@7.25.9': {} + '@aws-sdk/util-locate-window@3.568.0': + dependencies: + tslib: 2.8.1 - '@babel/helper-validator-identifier@7.25.9': {} + '@aws-sdk/util-user-agent-browser@3.468.0': + dependencies: + '@aws-sdk/types': 3.468.0 + '@smithy/types': 2.12.0 + bowser: 2.11.0 + tslib: 2.8.1 - '@babel/helper-validator-option@7.25.9': {} + '@aws-sdk/util-user-agent-browser@3.567.0': + dependencies: + '@aws-sdk/types': 3.567.0 + '@smithy/types': 2.12.0 + bowser: 2.11.0 + tslib: 2.8.1 - '@babel/helper-wrap-function@7.25.9': + '@aws-sdk/util-user-agent-browser@3.577.0': dependencies: - '@babel/template': 7.25.9 - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@aws-sdk/types': 3.577.0 + '@smithy/types': 3.0.0 + bowser: 2.11.0 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.470.0': + dependencies: + '@aws-sdk/types': 3.468.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.568.0': + dependencies: + '@aws-sdk/types': 3.567.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.577.0': + dependencies: + '@aws-sdk/types': 3.577.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 - '@babel/helpers@7.26.0': + '@aws-sdk/util-utf8-browser@3.259.0': dependencies: - '@babel/template': 7.25.9 - '@babel/types': 7.26.0 + tslib: 2.8.1 + + '@babel/code-frame@7.10.4': + dependencies: + '@babel/highlight': 7.24.6 - '@babel/highlight@7.25.9': + '@babel/code-frame@7.22.10': dependencies: - '@babel/helper-validator-identifier': 7.25.9 + '@babel/highlight': 7.22.10 + chalk: 2.4.2 + + '@babel/code-frame@7.22.13': + dependencies: + '@babel/highlight': 7.22.20 chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.1.1 - '@babel/parser@7.26.2': + '@babel/code-frame@7.24.6': dependencies: - '@babel/types': 7.26.0 + '@babel/highlight': 7.24.6 + picocolors: 1.0.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.0)': + '@babel/compat-data@7.24.6': {} + + '@babel/core@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/traverse': 7.25.9 + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helpers': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/template': 7.24.6 + '@babel/traverse': 7.24.6 + '@babel/types': 7.24.6 + convert-source-map: 2.0.0 + debug: 4.3.7 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9(@babel/core@7.26.0)': + '@babel/generator@7.17.7': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/types': 7.17.0 + jsesc: 2.5.2 + source-map: 0.5.7 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9(@babel/core@7.26.0)': + '@babel/generator@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/types': 7.24.6 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9(@babel/core@7.26.0)': + '@babel/helper-annotate-as-pure@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/types': 7.24.6 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9(@babel/core@7.26.0)': + '@babel/helper-builder-binary-assignment-operator-visitor@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/types': 7.24.6 - '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.26.0)': + '@babel/helper-compilation-targets@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/compat-data': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + browserslist: 4.23.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-member-expression-to-functions': 7.24.6 + '@babel/helper-optimise-call-expression': 7.24.6 + '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/helper-split-export-declaration': 7.24.6 + semver: 6.3.1 - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.26.0)': + '@babel/helper-create-regexp-features-plugin@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + regexpu-core: 5.3.2 + semver: 6.3.1 - '@babel/plugin-proposal-decorators@7.25.9(@babel/core@7.26.0)': + '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + debug: 4.3.7 + lodash.debounce: 4.0.8 + resolve: 1.22.8 transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-export-default-from@7.25.9(@babel/core@7.26.0)': + '@babel/helper-environment-visitor@7.22.5': {} + + '@babel/helper-environment-visitor@7.24.6': {} + + '@babel/helper-function-name@7.22.5': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/template': 7.22.5 + '@babel/types': 7.22.10 - '@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.26.0)': + '@babel/helper-function-name@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) + '@babel/template': 7.24.6 + '@babel/types': 7.24.6 - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.26.0)': + '@babel/helper-hoist-variables@7.22.5': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + '@babel/types': 7.23.6 - '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.26.0)': + '@babel/helper-hoist-variables@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) + '@babel/types': 7.24.6 - '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.26.0)': + '@babel/helper-member-expression-to-functions@7.24.6': dependencies: - '@babel/compat-data': 7.26.2 - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/types': 7.24.6 - '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.26.0)': + '@babel/helper-module-imports@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) + '@babel/types': 7.24.6 - '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.26.0)': + '@babel/helper-module-transforms@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-module-imports': 7.24.6 + '@babel/helper-simple-access': 7.24.6 + '@babel/helper-split-export-declaration': 7.24.6 + '@babel/helper-validator-identifier': 7.24.6 - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0)': + '@babel/helper-optimise-call-expression@7.24.6': dependencies: - '@babel/core': 7.26.0 + '@babel/types': 7.24.6 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0)': + '@babel/helper-plugin-utils@7.24.6': {} + + '@babel/helper-remap-async-to-generator@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-wrap-function': 7.24.6 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0)': + '@babel/helper-replace-supers@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-member-expression-to-functions': 7.24.6 + '@babel/helper-optimise-call-expression': 7.24.6 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0)': + '@babel/helper-simple-access@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/types': 7.24.6 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.0)': + '@babel/helper-skip-transparent-expression-wrappers@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/types': 7.24.6 - '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.0)': + '@babel/helper-split-export-declaration@7.22.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/types': 7.23.6 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.26.0)': + '@babel/helper-split-export-declaration@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/types': 7.24.6 + + '@babel/helper-string-parser@7.22.5': {} + + '@babel/helper-string-parser@7.23.4': {} + + '@babel/helper-string-parser@7.24.6': {} + + '@babel/helper-validator-identifier@7.22.20': {} + + '@babel/helper-validator-identifier@7.22.5': {} - '@babel/plugin-syntax-export-default-from@7.25.9(@babel/core@7.26.0)': + '@babel/helper-validator-identifier@7.24.6': {} + + '@babel/helper-validator-option@7.24.6': {} + + '@babel/helper-wrap-function@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-function-name': 7.24.6 + '@babel/template': 7.24.6 + '@babel/types': 7.24.6 - '@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.0)': + '@babel/helpers@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/template': 7.24.6 + '@babel/types': 7.24.6 - '@babel/plugin-syntax-import-assertions@7.26.0(@babel/core@7.26.0)': + '@babel/highlight@7.22.10': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-identifier': 7.22.5 + chalk: 2.4.2 + js-tokens: 4.0.0 - '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)': + '@babel/highlight@7.22.20': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)': + '@babel/highlight@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-identifier': 7.24.6 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0)': + '@babel/parser@7.22.10': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/types': 7.17.0 - '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': + '@babel/parser@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/types': 7.24.6 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/plugin-transform-optional-chaining': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0)': + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0)': + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.0)': + '@babel/plugin-proposal-decorators@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-decorators': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0)': + '@babel/plugin-proposal-export-default-from@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-export-default-from': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.26.0)': + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) - '@babel/plugin-transform-async-generator-functions@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/compat-data': 7.24.6 + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-block-scoped-functions@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 - '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-class-static-block@7.26.0(@babel/core@7.26.0)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-classes@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) - '@babel/traverse': 7.25.9 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-decorators@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/template': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-export-default-from@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-flow@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-import-assertions@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-exponentiation-operator@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-import-attributes@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-flow-strip-types@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-for-of@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-jsx@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-json-strings@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-literals@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-member-expression-literals@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-modules-amd@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-modules-commonjs@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-simple-access': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-modules-systemjs@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-modules-umd@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-typescript@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-new-target@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-arrow-functions@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-nullish-coalescing-operator@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-async-generator-functions@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) - '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-async-to-generator@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-module-imports': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-block-scoped-functions@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-object-super@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-block-scoping@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-class-properties@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-class-static-block@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.6) - '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-classes@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) + '@babel/helper-split-export-declaration': 7.24.6 + globals: 11.12.0 - '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-computed-properties@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/template': 7.24.6 - '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-destructuring@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-property-literals@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-dotall-regex@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-react-display-name@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-duplicate-keys@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-react-jsx-development@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-dynamic-import@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-exponentiation-operator@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-export-namespace-from@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-flow-strip-types@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-flow': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-react-pure-annotations@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-for-of@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 - '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-function-name@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - regenerator-transform: 0.15.2 + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-regexp-modifiers@7.26.0(@babel/core@7.26.0)': + '@babel/plugin-transform-json-strings@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-literals@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-runtime@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-logical-assignment-operators@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.26.0) - babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) - babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.26.0) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) - '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-member-expression-literals@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-spread@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-modules-amd@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-modules-commonjs@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-simple-access': 7.24.6 + + '@babel/plugin-transform-modules-systemjs@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-hoist-variables': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-validator-identifier': 7.24.6 + + '@babel/plugin-transform-modules-umd@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-named-capturing-groups-regex@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-new-target@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-nullish-coalescing-operator@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + + '@babel/plugin-transform-numeric-separator@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) + + '@babel/plugin-transform-object-rest-spread@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) + + '@babel/plugin-transform-object-super@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) + + '@babel/plugin-transform-optional-catch-binding@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) + + '@babel/plugin-transform-optional-chaining@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + + '@babel/plugin-transform-parameters@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-private-methods@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-private-property-in-object@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.6) + + '@babel/plugin-transform-property-literals@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-react-display-name@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-react-jsx-development@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/plugin-transform-react-jsx': 7.24.6(@babel/core@7.24.6) + + '@babel/plugin-transform-react-jsx-self@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-react-jsx-source@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-react-jsx@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-module-imports': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) + '@babel/types': 7.24.6 - '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-react-pure-annotations@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-template-literals@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-regenerator@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + regenerator-transform: 0.15.2 - '@babel/plugin-transform-typeof-symbol@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-reserved-words@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-typescript@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-runtime@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-module-imports': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.6) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.6) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.6) + semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/preset-env@7.26.0(@babel/core@7.26.0)': - dependencies: - '@babel/compat-data': 7.26.2 - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0) - '@babel/plugin-syntax-import-assertions': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-generator-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-block-scoped-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-class-static-block': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-dotall-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-duplicate-keys': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-dynamic-import': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-exponentiation-operator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-json-strings': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-member-expression-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-amd': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-systemjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-umd': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-new-target': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-super': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-property-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-regexp-modifiers': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-transform-reserved-words': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-template-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-typeof-symbol': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-escapes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-property-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-sets-regex': 7.25.9(@babel/core@7.26.0) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.26.0) - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.26.0) - babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) - babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.26.0) - core-js-compat: 3.39.0 + '@babel/plugin-transform-shorthand-properties@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-spread@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + + '@babel/plugin-transform-sticky-regex@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-template-literals@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-typeof-symbol@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-typescript@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-typescript': 7.24.6(@babel/core@7.24.6) + + '@babel/plugin-transform-unicode-escapes@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-unicode-property-regex@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-unicode-regex@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-unicode-sets-regex@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/preset-env@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/compat-data': 7.24.6 + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.6) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.6) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-import-assertions': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-import-attributes': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-transform-arrow-functions': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-async-generator-functions': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-async-to-generator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-block-scoped-functions': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-block-scoping': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-class-properties': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-class-static-block': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-classes': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-computed-properties': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-destructuring': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-dotall-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-duplicate-keys': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-dynamic-import': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-exponentiation-operator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-export-namespace-from': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-for-of': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-function-name': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-json-strings': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-literals': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-logical-assignment-operators': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-member-expression-literals': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-amd': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-systemjs': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-umd': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-named-capturing-groups-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-new-target': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-numeric-separator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-object-rest-spread': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-object-super': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-optional-catch-binding': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-optional-chaining': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-private-methods': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-private-property-in-object': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-property-literals': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-regenerator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-reserved-words': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-shorthand-properties': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-spread': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-sticky-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-template-literals': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-typeof-symbol': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-escapes': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-property-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-sets-regex': 7.24.6(@babel/core@7.24.6) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.6) + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.6) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.6) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.6) + core-js-compat: 3.37.1 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-flow@7.25.9(@babel/core@7.26.0)': + '@babel/preset-flow@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + '@babel/plugin-transform-flow-strip-types': 7.24.6(@babel/core@7.24.6) - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.26.0)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/types': 7.26.0 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/types': 7.24.6 esutils: 2.0.3 - '@babel/preset-react@7.25.9(@babel/core@7.26.0)': + '@babel/preset-react@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-development': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-pure-annotations': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + '@babel/plugin-transform-react-display-name': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-jsx': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-jsx-development': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-pure-annotations': 7.24.6(@babel/core@7.24.6) - '@babel/preset-typescript@7.26.0(@babel/core@7.26.0)': + '@babel/preset-typescript@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-typescript': 7.24.6(@babel/core@7.24.6) - '@babel/register@7.25.9(@babel/core@7.26.0)': + '@babel/register@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 + '@babel/core': 7.24.6 clone-deep: 4.0.1 find-cache-dir: 2.1.0 make-dir: 2.1.0 pirates: 4.0.6 source-map-support: 0.5.21 - '@babel/runtime@7.26.0': + '@babel/regjsgen@0.8.0': {} + + '@babel/runtime@7.22.10': + dependencies: + regenerator-runtime: 0.14.0 + + '@babel/runtime@7.24.6': dependencies: regenerator-runtime: 0.14.1 - '@babel/template@7.25.9': + '@babel/template@7.22.5': dependencies: - '@babel/code-frame': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 + '@babel/code-frame': 7.22.10 + '@babel/parser': 7.22.10 + '@babel/types': 7.22.10 - '@babel/traverse@7.23.2': + '@babel/template@7.24.6': dependencies: - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.2 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-function-name': 7.24.7 - '@babel/helper-hoist-variables': 7.24.7 - '@babel/helper-split-export-declaration': 7.24.7 - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - debug: 4.3.7 + '@babel/code-frame': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + + '@babel/traverse@7.17.3': + dependencies: + '@babel/code-frame': 7.22.10 + '@babel/generator': 7.17.7 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-function-name': 7.22.5 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.22.10 + '@babel/types': 7.17.0 + debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/traverse@7.25.9': + '@babel/traverse@7.24.6': dependencies: - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/template': 7.25.9 - '@babel/types': 7.26.0 + '@babel/code-frame': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-hoist-variables': 7.24.6 + '@babel/helper-split-export-declaration': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: @@ -10853,13 +12779,26 @@ snapshots: '@babel/types@7.17.0': dependencies: - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.22.5 + to-fast-properties: 2.0.0 + + '@babel/types@7.22.10': + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.5 + to-fast-properties: 2.0.0 + + '@babel/types@7.23.6': + dependencies: + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 - '@babel/types@7.26.0': + '@babel/types@7.24.6': dependencies: - '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-string-parser': 7.24.6 + '@babel/helper-validator-identifier': 7.24.6 + to-fast-properties: 2.0.0 '@balena/dockerignore@1.0.2': {} @@ -10867,27 +12806,26 @@ snapshots: dependencies: mime: 3.0.0 - '@cloudflare/workerd-darwin-64@1.20241022.0': + '@cloudflare/workerd-darwin-64@1.20240712.0': optional: true - '@cloudflare/workerd-darwin-arm64@1.20241022.0': + '@cloudflare/workerd-darwin-arm64@1.20240712.0': optional: true - '@cloudflare/workerd-linux-64@1.20241022.0': + '@cloudflare/workerd-linux-64@1.20240712.0': optional: true - '@cloudflare/workerd-linux-arm64@1.20241022.0': + '@cloudflare/workerd-linux-arm64@1.20240712.0': optional: true - '@cloudflare/workerd-windows-64@1.20241022.0': + '@cloudflare/workerd-windows-64@1.20240712.0': optional: true - '@cloudflare/workers-shared@0.7.0': - dependencies: - mime: 3.0.0 - zod: 3.23.8 + '@cloudflare/workers-types@4.20240512.0': {} + + '@cloudflare/workers-types@4.20240524.0': {} - '@cloudflare/workers-types@4.20241106.0': {} + '@cloudflare/workers-types@4.20241004.0': {} '@colors/colors@1.5.0': optional: true @@ -10923,15 +12861,15 @@ snapshots: '@electric-sql/pglite@0.2.12': {} - '@esbuild-kit/core-utils@3.3.2': + '@esbuild-kit/core-utils@3.1.0': dependencies: - esbuild: 0.18.20 + esbuild: 0.17.19 source-map-support: 0.5.21 - '@esbuild-kit/esm-loader@2.6.5': + '@esbuild-kit/esm-loader@2.5.5': dependencies: - '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.8.1 + '@esbuild-kit/core-utils': 3.1.0 + get-tsconfig: 4.7.5 '@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19)': dependencies: @@ -10946,13 +12884,13 @@ snapshots: '@esbuild/aix-ppc64@0.19.12': optional: true - '@esbuild/aix-ppc64@0.21.5': + '@esbuild/aix-ppc64@0.20.2': optional: true - '@esbuild/aix-ppc64@0.23.1': + '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/aix-ppc64@0.24.0': + '@esbuild/aix-ppc64@0.23.0': optional: true '@esbuild/android-arm64@0.17.19': @@ -10964,13 +12902,13 @@ snapshots: '@esbuild/android-arm64@0.19.12': optional: true - '@esbuild/android-arm64@0.21.5': + '@esbuild/android-arm64@0.20.2': optional: true - '@esbuild/android-arm64@0.23.1': + '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/android-arm64@0.24.0': + '@esbuild/android-arm64@0.23.0': optional: true '@esbuild/android-arm@0.17.19': @@ -10982,13 +12920,13 @@ snapshots: '@esbuild/android-arm@0.19.12': optional: true - '@esbuild/android-arm@0.21.5': + '@esbuild/android-arm@0.20.2': optional: true - '@esbuild/android-arm@0.23.1': + '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/android-arm@0.24.0': + '@esbuild/android-arm@0.23.0': optional: true '@esbuild/android-x64@0.17.19': @@ -11000,13 +12938,13 @@ snapshots: '@esbuild/android-x64@0.19.12': optional: true - '@esbuild/android-x64@0.21.5': + '@esbuild/android-x64@0.20.2': optional: true - '@esbuild/android-x64@0.23.1': + '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/android-x64@0.24.0': + '@esbuild/android-x64@0.23.0': optional: true '@esbuild/darwin-arm64@0.17.19': @@ -11018,13 +12956,13 @@ snapshots: '@esbuild/darwin-arm64@0.19.12': optional: true - '@esbuild/darwin-arm64@0.21.5': + '@esbuild/darwin-arm64@0.20.2': optional: true - '@esbuild/darwin-arm64@0.23.1': + '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/darwin-arm64@0.24.0': + '@esbuild/darwin-arm64@0.23.0': optional: true '@esbuild/darwin-x64@0.17.19': @@ -11036,13 +12974,13 @@ snapshots: '@esbuild/darwin-x64@0.19.12': optional: true - '@esbuild/darwin-x64@0.21.5': + '@esbuild/darwin-x64@0.20.2': optional: true - '@esbuild/darwin-x64@0.23.1': + '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/darwin-x64@0.24.0': + '@esbuild/darwin-x64@0.23.0': optional: true '@esbuild/freebsd-arm64@0.17.19': @@ -11054,13 +12992,13 @@ snapshots: '@esbuild/freebsd-arm64@0.19.12': optional: true - '@esbuild/freebsd-arm64@0.21.5': + '@esbuild/freebsd-arm64@0.20.2': optional: true - '@esbuild/freebsd-arm64@0.23.1': + '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/freebsd-arm64@0.24.0': + '@esbuild/freebsd-arm64@0.23.0': optional: true '@esbuild/freebsd-x64@0.17.19': @@ -11072,13 +13010,13 @@ snapshots: '@esbuild/freebsd-x64@0.19.12': optional: true - '@esbuild/freebsd-x64@0.21.5': + '@esbuild/freebsd-x64@0.20.2': optional: true - '@esbuild/freebsd-x64@0.23.1': + '@esbuild/freebsd-x64@0.21.5': optional: true - '@esbuild/freebsd-x64@0.24.0': + '@esbuild/freebsd-x64@0.23.0': optional: true '@esbuild/linux-arm64@0.17.19': @@ -11090,13 +13028,13 @@ snapshots: '@esbuild/linux-arm64@0.19.12': optional: true - '@esbuild/linux-arm64@0.21.5': + '@esbuild/linux-arm64@0.20.2': optional: true - '@esbuild/linux-arm64@0.23.1': + '@esbuild/linux-arm64@0.21.5': optional: true - '@esbuild/linux-arm64@0.24.0': + '@esbuild/linux-arm64@0.23.0': optional: true '@esbuild/linux-arm@0.17.19': @@ -11108,13 +13046,13 @@ snapshots: '@esbuild/linux-arm@0.19.12': optional: true - '@esbuild/linux-arm@0.21.5': + '@esbuild/linux-arm@0.20.2': optional: true - '@esbuild/linux-arm@0.23.1': + '@esbuild/linux-arm@0.21.5': optional: true - '@esbuild/linux-arm@0.24.0': + '@esbuild/linux-arm@0.23.0': optional: true '@esbuild/linux-ia32@0.17.19': @@ -11126,13 +13064,13 @@ snapshots: '@esbuild/linux-ia32@0.19.12': optional: true - '@esbuild/linux-ia32@0.21.5': + '@esbuild/linux-ia32@0.20.2': optional: true - '@esbuild/linux-ia32@0.23.1': + '@esbuild/linux-ia32@0.21.5': optional: true - '@esbuild/linux-ia32@0.24.0': + '@esbuild/linux-ia32@0.23.0': optional: true '@esbuild/linux-loong64@0.14.54': @@ -11147,13 +13085,13 @@ snapshots: '@esbuild/linux-loong64@0.19.12': optional: true - '@esbuild/linux-loong64@0.21.5': + '@esbuild/linux-loong64@0.20.2': optional: true - '@esbuild/linux-loong64@0.23.1': + '@esbuild/linux-loong64@0.21.5': optional: true - '@esbuild/linux-loong64@0.24.0': + '@esbuild/linux-loong64@0.23.0': optional: true '@esbuild/linux-mips64el@0.17.19': @@ -11165,13 +13103,13 @@ snapshots: '@esbuild/linux-mips64el@0.19.12': optional: true - '@esbuild/linux-mips64el@0.21.5': + '@esbuild/linux-mips64el@0.20.2': optional: true - '@esbuild/linux-mips64el@0.23.1': + '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/linux-mips64el@0.24.0': + '@esbuild/linux-mips64el@0.23.0': optional: true '@esbuild/linux-ppc64@0.17.19': @@ -11183,13 +13121,13 @@ snapshots: '@esbuild/linux-ppc64@0.19.12': optional: true - '@esbuild/linux-ppc64@0.21.5': + '@esbuild/linux-ppc64@0.20.2': optional: true - '@esbuild/linux-ppc64@0.23.1': + '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.24.0': + '@esbuild/linux-ppc64@0.23.0': optional: true '@esbuild/linux-riscv64@0.17.19': @@ -11201,13 +13139,13 @@ snapshots: '@esbuild/linux-riscv64@0.19.12': optional: true - '@esbuild/linux-riscv64@0.21.5': + '@esbuild/linux-riscv64@0.20.2': optional: true - '@esbuild/linux-riscv64@0.23.1': + '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.24.0': + '@esbuild/linux-riscv64@0.23.0': optional: true '@esbuild/linux-s390x@0.17.19': @@ -11219,13 +13157,13 @@ snapshots: '@esbuild/linux-s390x@0.19.12': optional: true - '@esbuild/linux-s390x@0.21.5': + '@esbuild/linux-s390x@0.20.2': optional: true - '@esbuild/linux-s390x@0.23.1': + '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/linux-s390x@0.24.0': + '@esbuild/linux-s390x@0.23.0': optional: true '@esbuild/linux-x64@0.17.19': @@ -11237,13 +13175,13 @@ snapshots: '@esbuild/linux-x64@0.19.12': optional: true - '@esbuild/linux-x64@0.21.5': + '@esbuild/linux-x64@0.20.2': optional: true - '@esbuild/linux-x64@0.23.1': + '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/linux-x64@0.24.0': + '@esbuild/linux-x64@0.23.0': optional: true '@esbuild/netbsd-x64@0.17.19': @@ -11255,19 +13193,16 @@ snapshots: '@esbuild/netbsd-x64@0.19.12': optional: true - '@esbuild/netbsd-x64@0.21.5': - optional: true - - '@esbuild/netbsd-x64@0.23.1': + '@esbuild/netbsd-x64@0.20.2': optional: true - '@esbuild/netbsd-x64@0.24.0': + '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-arm64@0.23.1': + '@esbuild/netbsd-x64@0.23.0': optional: true - '@esbuild/openbsd-arm64@0.24.0': + '@esbuild/openbsd-arm64@0.23.0': optional: true '@esbuild/openbsd-x64@0.17.19': @@ -11279,13 +13214,13 @@ snapshots: '@esbuild/openbsd-x64@0.19.12': optional: true - '@esbuild/openbsd-x64@0.21.5': + '@esbuild/openbsd-x64@0.20.2': optional: true - '@esbuild/openbsd-x64@0.23.1': + '@esbuild/openbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-x64@0.24.0': + '@esbuild/openbsd-x64@0.23.0': optional: true '@esbuild/sunos-x64@0.17.19': @@ -11297,13 +13232,13 @@ snapshots: '@esbuild/sunos-x64@0.19.12': optional: true - '@esbuild/sunos-x64@0.21.5': + '@esbuild/sunos-x64@0.20.2': optional: true - '@esbuild/sunos-x64@0.23.1': + '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/sunos-x64@0.24.0': + '@esbuild/sunos-x64@0.23.0': optional: true '@esbuild/win32-arm64@0.17.19': @@ -11315,13 +13250,13 @@ snapshots: '@esbuild/win32-arm64@0.19.12': optional: true - '@esbuild/win32-arm64@0.21.5': + '@esbuild/win32-arm64@0.20.2': optional: true - '@esbuild/win32-arm64@0.23.1': + '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-arm64@0.24.0': + '@esbuild/win32-arm64@0.23.0': optional: true '@esbuild/win32-ia32@0.17.19': @@ -11333,13 +13268,13 @@ snapshots: '@esbuild/win32-ia32@0.19.12': optional: true - '@esbuild/win32-ia32@0.21.5': + '@esbuild/win32-ia32@0.20.2': optional: true - '@esbuild/win32-ia32@0.23.1': + '@esbuild/win32-ia32@0.21.5': optional: true - '@esbuild/win32-ia32@0.24.0': + '@esbuild/win32-ia32@0.23.0': optional: true '@esbuild/win32-x64@0.17.19': @@ -11351,29 +13286,83 @@ snapshots: '@esbuild/win32-x64@0.19.12': optional: true - '@esbuild/win32-x64@0.21.5': + '@esbuild/win32-x64@0.20.2': optional: true - '@esbuild/win32-x64@0.23.1': + '@esbuild/win32-x64@0.21.5': optional: true - '@esbuild/win32-x64@0.24.0': + '@esbuild/win32-x64@0.23.0': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)': + '@eslint-community/eslint-utils@4.4.0(eslint@8.50.0)': dependencies: - eslint: 8.57.1 + eslint: 8.50.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.12.1': {} + '@eslint-community/eslint-utils@4.4.0(eslint@8.53.0)': + dependencies: + eslint: 8.53.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.11.0': {} + + '@eslint-community/regexpp@4.9.0': {} + + '@eslint/eslintrc@2.1.2': + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.22.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/eslintrc@2.1.3': + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.22.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.7 + debug: 4.3.4 espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 + globals: 13.22.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/eslintrc@3.1.0': + dependencies: + ajv: 6.12.6 + debug: 4.3.7 + espree: 10.0.1 + globals: 14.0.0 + ignore: 5.3.1 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -11381,43 +13370,49 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.1': {} + '@eslint/js@8.50.0': {} + + '@eslint/js@8.53.0': {} + + '@eslint/js@8.57.0': {} '@ewoudenberg/difflib@0.1.0': dependencies: heap: 0.2.7 - '@expo/bunyan@4.0.1': + '@expo/bunyan@4.0.0': dependencies: uuid: 8.3.2 + optionalDependencies: + mv: 2.1.1 + safe-json-stringify: 1.2.0 - '@expo/cli@0.18.30(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.3)(utf-8-validate@6.0.3)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': dependencies: - '@babel/runtime': 7.26.0 + '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 - '@expo/config': 9.0.4 - '@expo/config-plugins': 8.0.10 - '@expo/devcert': 1.1.4 + '@expo/config': 9.0.2 + '@expo/config-plugins': 8.0.4 + '@expo/devcert': 1.1.2 '@expo/env': 0.3.0 '@expo/image-utils': 0.5.1(encoding@0.1.13) '@expo/json-file': 8.3.3 - '@expo/metro-config': 0.18.11 - '@expo/osascript': 2.1.3 + '@expo/metro-config': 0.18.4 + '@expo/osascript': 2.1.2 '@expo/package-manager': 1.5.2 '@expo/plist': 0.1.3 - '@expo/prebuild-config': 7.0.9(encoding@0.1.13)(expo-modules-autolinking@1.11.3) + '@expo/prebuild-config': 7.0.4(encoding@0.1.13)(expo-modules-autolinking@1.11.1) '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.85(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 arg: 5.0.2 better-opn: 3.0.2 - bplist-creator: 0.0.7 bplist-parser: 0.3.2 - cacache: 18.0.4 + cacache: 18.0.3 chalk: 4.1.2 ci-info: 3.9.0 connect: 3.7.0 @@ -11425,7 +13420,7 @@ snapshots: env-editor: 0.4.2 fast-glob: 3.3.2 find-yarn-workspace-root: 2.0.0 - form-data: 3.0.2 + form-data: 3.0.1 freeport-async: 2.0.0 fs-extra: 8.1.0 getenv: 1.0.0 @@ -11456,7 +13451,7 @@ snapshots: resolve: 1.22.8 resolve-from: 5.0.0 resolve.exports: 2.0.2 - semver: 7.6.3 + semver: 7.6.2 send: 0.18.0 slugify: 1.6.6 source-map-support: 0.5.21 @@ -11482,9 +13477,9 @@ snapshots: node-forge: 1.3.1 nullthrows: 1.1.1 - '@expo/config-plugins@8.0.10': + '@expo/config-plugins@8.0.4': dependencies: - '@expo/config-types': 51.0.3 + '@expo/config-types': 51.0.0 '@expo/json-file': 8.3.3 '@expo/plist': 0.1.3 '@expo/sdk-runtime-versions': 1.0.0 @@ -11494,7 +13489,7 @@ snapshots: getenv: 1.0.0 glob: 7.1.6 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.6.2 slash: 3.0.0 slugify: 1.6.6 xcode: 3.0.1 @@ -11502,35 +13497,36 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/config-types@51.0.3': {} + '@expo/config-types@51.0.0': {} - '@expo/config@9.0.4': + '@expo/config@9.0.2': dependencies: '@babel/code-frame': 7.10.4 - '@expo/config-plugins': 8.0.10 - '@expo/config-types': 51.0.3 + '@expo/config-plugins': 8.0.4 + '@expo/config-types': 51.0.0 '@expo/json-file': 8.3.3 getenv: 1.0.0 glob: 7.1.6 require-from-string: 2.0.2 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.6.2 slugify: 1.6.6 sucrase: 3.34.0 transitivePeerDependencies: - supports-color - '@expo/devcert@1.1.4': + '@expo/devcert@1.1.2': dependencies: application-config-path: 0.1.1 command-exists: 1.2.9 debug: 3.2.7 eol: 0.9.1 get-port: 3.2.0 - glob: 10.4.5 + glob: 7.2.3 lodash: 4.17.21 mkdirp: 0.5.6 password-prompt: 1.1.3 + rimraf: 2.7.1 sudo-prompt: 8.2.5 tmp: 0.0.33 tslib: 2.8.1 @@ -11557,7 +13553,7 @@ snapshots: node-fetch: 2.7.0(encoding@0.1.13) parse-png: 2.1.0 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.6.2 tempy: 0.3.0 transitivePeerDependencies: - encoding @@ -11568,13 +13564,13 @@ snapshots: json5: 2.2.3 write-file-atomic: 2.4.3 - '@expo/metro-config@0.18.11': + '@expo/metro-config@0.18.4': dependencies: - '@babel/core': 7.26.0 - '@babel/generator': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - '@expo/config': 9.0.4 + '@babel/core': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + '@expo/config': 9.0.2 '@expo/env': 0.3.0 '@expo/json-file': 8.3.3 '@expo/spawn-async': 1.7.2 @@ -11586,12 +13582,12 @@ snapshots: glob: 7.2.3 jsc-safe-url: 0.2.4 lightningcss: 1.19.0 - postcss: 8.4.47 + postcss: 8.4.39 resolve-from: 5.0.0 transitivePeerDependencies: - supports-color - '@expo/osascript@2.1.3': + '@expo/osascript@2.1.2': dependencies: '@expo/spawn-async': 1.7.2 exec-async: 2.2.0 @@ -11617,19 +13613,19 @@ snapshots: base64-js: 1.5.1 xmlbuilder: 14.0.0 - '@expo/prebuild-config@7.0.9(encoding@0.1.13)(expo-modules-autolinking@1.11.3)': + '@expo/prebuild-config@7.0.4(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': dependencies: - '@expo/config': 9.0.4 - '@expo/config-plugins': 8.0.10 - '@expo/config-types': 51.0.3 + '@expo/config': 9.0.2 + '@expo/config-plugins': 8.0.4 + '@expo/config-types': 51.0.0 '@expo/image-utils': 0.5.1(encoding@0.1.13) '@expo/json-file': 8.3.3 - '@react-native/normalize-colors': 0.74.85 + '@react-native/normalize-colors': 0.74.83 debug: 4.3.7 - expo-modules-autolinking: 1.11.3 + expo-modules-autolinking: 1.11.1 fs-extra: 9.1.0 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.6.2 xml2js: 0.6.0 transitivePeerDependencies: - encoding @@ -11637,7 +13633,7 @@ snapshots: '@expo/rudder-sdk-node@1.1.1(encoding@0.1.13)': dependencies: - '@expo/bunyan': 4.0.1 + '@expo/bunyan': 4.0.0 '@segment/loosely-validate-event': 2.0.0 fetch-retry: 4.1.1 md5: 2.3.0 @@ -11651,9 +13647,9 @@ snapshots: '@expo/spawn-async@1.7.2': dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 - '@expo/vector-icons@14.0.4': + '@expo/vector-icons@14.0.2': dependencies: prop-types: 15.8.1 @@ -11681,25 +13677,49 @@ snapshots: dependencies: graphql: 15.8.0 - '@hono/node-server@1.13.5(hono@4.6.9)': + '@hapi/hoek@9.3.0': {} + + '@hapi/topo@5.1.0': + dependencies: + '@hapi/hoek': 9.3.0 + + '@hono/node-server@1.12.0': {} + + '@hono/zod-validator@0.2.2(hono@4.5.0)(zod@3.23.7)': dependencies: - hono: 4.6.9 + hono: 4.5.0 + zod: 3.23.7 - '@hono/zod-validator@0.2.2(hono@4.6.9)(zod@3.23.8)': + '@humanwhocodes/config-array@0.11.11': dependencies: - hono: 4.6.9 - zod: 3.23.8 + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color - '@humanwhocodes/config-array@0.13.0': + '@humanwhocodes/config-array@0.11.13': + dependencies: + '@humanwhocodes/object-schema': 2.0.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.7 + debug: 4.3.4 minimatch: 3.1.2 transitivePeerDependencies: - supports-color '@humanwhocodes/module-importer@1.0.1': {} + '@humanwhocodes/object-schema@1.2.1': {} + + '@humanwhocodes/object-schema@2.0.1': {} + '@humanwhocodes/object-schema@2.0.3': {} '@iarna/toml@2.2.5': {} @@ -11715,16 +13735,6 @@ snapshots: '@isaacs/ttlcache@1.4.1': {} - '@istanbuljs/load-nyc-config@1.1.0': - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 3.14.1 - resolve-from: 5.0.0 - - '@istanbuljs/schema@0.1.3': {} - '@jest/create-cache-key-function@29.7.0': dependencies: '@jest/types': 29.6.3 @@ -11733,14 +13743,14 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.6 + '@types/node': 20.12.12 jest-mock: 29.7.0 '@jest/fake-timers@29.7.0': dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.17.6 + '@types/node': 20.12.12 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -11749,67 +13759,73 @@ snapshots: dependencies: '@sinclair/typebox': 0.27.8 - '@jest/transform@29.7.0': - dependencies: - '@babel/core': 7.26.0 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.8 - pirates: 4.0.6 - slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color - - '@jest/types@24.9.0': + '@jest/types@26.6.2': dependencies: '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 1.1.2 - '@types/yargs': 13.0.12 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.12.12 + '@types/yargs': 15.0.19 + chalk: 4.1.2 '@jest/types@29.6.3': dependencies: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.17.6 - '@types/yargs': 17.0.33 + '@types/node': 20.12.12 + '@types/yargs': 17.0.32 chalk: 4.1.2 + '@jridgewell/gen-mapping@0.3.3': + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/resolve-uri@3.1.0': {} + '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/set-array@1.1.2': {} + '@jridgewell/set-array@1.2.1': {} + '@jridgewell/source-map@0.3.3': + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/source-map@0.3.6': dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/sourcemap-codec@1.4.14': {} + + '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/trace-mapping@0.3.18': + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.4.15 '@libsql/client-wasm@0.10.0': dependencies: @@ -11821,7 +13837,7 @@ snapshots: '@libsql/core': 0.10.0 '@libsql/hrana-client': 0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) js-base64: 3.7.7 - libsql: 0.4.7 + libsql: 0.4.1 promise-limit: 2.7.0 transitivePeerDependencies: - bufferutil @@ -11831,10 +13847,16 @@ snapshots: dependencies: js-base64: 3.7.7 - '@libsql/darwin-arm64@0.4.7': + '@libsql/darwin-arm64@0.3.19': + optional: true + + '@libsql/darwin-arm64@0.4.1': optional: true - '@libsql/darwin-x64@0.4.7': + '@libsql/darwin-x64@0.3.19': + optional: true + + '@libsql/darwin-x64@0.4.1': optional: true '@libsql/hrana-client@0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)': @@ -11851,25 +13873,40 @@ snapshots: '@libsql/isomorphic-ws@0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: - '@types/ws': 8.5.13 + '@types/ws': 8.5.11 ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate - '@libsql/linux-arm64-gnu@0.4.7': + '@libsql/linux-arm64-gnu@0.3.19': + optional: true + + '@libsql/linux-arm64-gnu@0.4.1': + optional: true + + '@libsql/linux-arm64-musl@0.3.19': optional: true - '@libsql/linux-arm64-musl@0.4.7': + '@libsql/linux-arm64-musl@0.4.1': optional: true - '@libsql/linux-x64-gnu@0.4.7': + '@libsql/linux-x64-gnu@0.3.19': optional: true - '@libsql/linux-x64-musl@0.4.7': + '@libsql/linux-x64-gnu@0.4.1': optional: true - '@libsql/win32-x64-msvc@0.4.7': + '@libsql/linux-x64-musl@0.3.19': + optional: true + + '@libsql/linux-x64-musl@0.4.1': + optional: true + + '@libsql/win32-x64-msvc@0.3.19': + optional: true + + '@libsql/win32-x64-msvc@0.4.1': optional: true '@miniflare/core@2.14.4': @@ -11881,7 +13918,7 @@ snapshots: busboy: 1.6.0 dotenv: 10.0.0 kleur: 4.1.5 - set-cookie-parser: 2.7.1 + set-cookie-parser: 2.6.0 undici: 5.28.4 urlpattern-polyfill: 4.0.3 @@ -11896,7 +13933,7 @@ snapshots: '@miniflare/shared@2.14.4': dependencies: - '@types/better-sqlite3': 7.6.11 + '@types/better-sqlite3': 7.6.10 kleur: 4.1.5 npx-import: 1.1.4 picomatch: 2.3.1 @@ -11907,15 +13944,24 @@ snapshots: '@neon-rs/load@0.0.4': {} + '@neondatabase/serverless@0.10.0': + dependencies: + '@types/pg': 8.11.6 + + '@neondatabase/serverless@0.10.3': + dependencies: + '@types/pg': 8.11.6 + optional: true + '@neondatabase/serverless@0.7.2': dependencies: '@types/pg': 8.6.6 - '@neondatabase/serverless@0.9.5': + '@neondatabase/serverless@0.9.3': dependencies: '@types/pg': 8.11.6 - '@noble/hashes@1.5.0': {} + '@noble/hashes@1.4.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -11927,17 +13973,17 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 + fastq: 1.15.0 '@npmcli/fs@1.1.1': dependencies: '@gar/promisify': 1.1.3 - semver: 7.6.3 + semver: 7.6.2 optional: true '@npmcli/fs@3.1.1': dependencies: - semver: 7.6.3 + semver: 7.6.2 '@npmcli/move-file@1.1.2': dependencies: @@ -11945,12 +13991,12 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) - '@opentelemetry/api@1.9.0': {} + '@opentelemetry/api@1.8.0': {} '@originjs/vite-plugin-commonjs@1.0.3': dependencies: @@ -11958,16 +14004,16 @@ snapshots: '@paralleldrive/cuid2@2.2.2': dependencies: - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.4.0 '@pkgjs/parseargs@0.11.0': optional: true '@pkgr/core@0.1.1': {} - '@planetscale/database@1.19.0': {} + '@planetscale/database@1.18.0': {} - '@polka/url@1.0.0-next.28': {} + '@polka/url@1.0.0-next.25': {} '@prisma/client@5.14.0(prisma@5.14.0)': optionalDependencies: @@ -11975,7 +14021,7 @@ snapshots: '@prisma/debug@5.14.0': {} - '@prisma/debug@5.22.0': {} + '@prisma/debug@5.16.1': {} '@prisma/engines-version@5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48': {} @@ -11992,168 +14038,245 @@ snapshots: '@prisma/engines-version': 5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48 '@prisma/get-platform': 5.14.0 - '@prisma/generator-helper@5.22.0': + '@prisma/generator-helper@5.16.1': dependencies: - '@prisma/debug': 5.22.0 + '@prisma/debug': 5.16.1 '@prisma/get-platform@5.14.0': dependencies: '@prisma/debug': 5.14.0 - '@react-native/assets-registry@0.76.1': {} + '@react-native-community/cli-clean@13.6.6(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + execa: 5.1.1 + fast-glob: 3.3.2 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-config@13.6.6(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + cosmiconfig: 5.2.1 + deepmerge: 4.3.1 + fast-glob: 3.3.2 + joi: 17.13.1 + transitivePeerDependencies: + - encoding - '@react-native/babel-plugin-codegen@0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0))': + '@react-native-community/cli-debugger-ui@13.6.6': dependencies: - '@react-native/codegen': 0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + serve-static: 1.15.0 transitivePeerDependencies: - - '@babel/preset-env' - supports-color - '@react-native/babel-plugin-codegen@0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0))': + '@react-native-community/cli-doctor@13.6.6(encoding@0.1.13)': dependencies: - '@react-native/codegen': 0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-platform-apple': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + command-exists: 1.2.9 + deepmerge: 4.3.1 + envinfo: 7.13.0 + execa: 5.1.1 + hermes-profile-transformer: 0.0.6 + node-stream-zip: 1.15.0 + ora: 5.4.1 + semver: 7.6.2 + strip-ansi: 5.2.0 + wcwidth: 1.0.1 + yaml: 2.4.2 transitivePeerDependencies: - - '@babel/preset-env' + - encoding + + '@react-native-community/cli-hermes@13.6.6(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + hermes-profile-transformer: 0.0.6 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-platform-android@13.6.6(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + execa: 5.1.1 + fast-glob: 3.3.2 + fast-xml-parser: 4.4.0 + logkitty: 0.7.1 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-platform-apple@13.6.6(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + execa: 5.1.1 + fast-glob: 3.3.2 + fast-xml-parser: 4.4.0 + ora: 5.4.1 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-platform-ios@13.6.6(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-platform-apple': 13.6.6(encoding@0.1.13) + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-debugger-ui': 13.6.6 + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + compression: 1.7.4 + connect: 3.7.0 + errorhandler: 1.5.1 + nocache: 3.0.4 + pretty-format: 26.6.2 + serve-static: 1.15.0 + ws: 6.2.2(bufferutil@4.0.8) + transitivePeerDependencies: + - bufferutil + - encoding - supports-color + - utf-8-validate - '@react-native/babel-preset@0.74.87(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))': - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.26.0) - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-export-default-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.26.0) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.26.0) - '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.26.0) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-export-default-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) - '@babel/template': 7.25.9 - '@react-native/babel-plugin-codegen': 0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.26.0) - react-refresh: 0.14.2 + '@react-native-community/cli-tools@13.6.6(encoding@0.1.13)': + dependencies: + appdirsjs: 1.2.7 + chalk: 4.1.2 + execa: 5.1.1 + find-up: 5.0.0 + mime: 2.6.0 + node-fetch: 2.7.0(encoding@0.1.13) + open: 6.4.0 + ora: 5.4.1 + semver: 7.6.2 + shell-quote: 1.8.1 + sudo-prompt: 9.2.1 transitivePeerDependencies: - - '@babel/preset-env' + - encoding + + '@react-native-community/cli-types@13.6.6': + dependencies: + joi: 17.13.1 + + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-debugger-ui': 13.6.6 + '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-types': 13.6.6 + chalk: 4.1.2 + commander: 9.5.0 + deepmerge: 4.3.1 + execa: 5.1.1 + find-up: 4.1.0 + fs-extra: 8.1.0 + graceful-fs: 4.2.11 + prompts: 2.4.2 + semver: 7.6.2 + transitivePeerDependencies: + - bufferutil + - encoding - supports-color + - utf-8-validate - '@react-native/babel-preset@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))': - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-proposal-export-default-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-export-default-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-generator-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) - '@babel/template': 7.25.9 - '@react-native/babel-plugin-codegen': 0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - babel-plugin-syntax-hermes-parser: 0.23.1 - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.26.0) - react-refresh: 0.14.2 + '@react-native/assets-registry@0.74.83': {} + + '@react-native/babel-plugin-codegen@0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6))': + dependencies: + '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) transitivePeerDependencies: - '@babel/preset-env' - supports-color - '@react-native/codegen@0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0))': - dependencies: - '@babel/parser': 7.26.2 - '@babel/preset-env': 7.26.0(@babel/core@7.26.0) - glob: 7.2.3 - hermes-parser: 0.19.1 - invariant: 2.2.4 - jscodeshift: 0.14.0(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - mkdirp: 0.5.6 - nullthrows: 1.1.1 + '@react-native/babel-preset@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))': + dependencies: + '@babel/core': 7.24.6 + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.24.6) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-export-default-from': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.24.6) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.24.6) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.6) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-export-default-from': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-flow': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-transform-arrow-functions': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-async-to-generator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-block-scoping': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-classes': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-computed-properties': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-destructuring': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-flow-strip-types': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-function-name': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-literals': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-named-capturing-groups-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-private-methods': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-private-property-in-object': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-display-name': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-jsx': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-jsx-self': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-jsx-source': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-runtime': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-shorthand-properties': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-spread': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-sticky-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-typescript': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-regex': 7.24.6(@babel/core@7.24.6) + '@babel/template': 7.24.6 + '@react-native/babel-plugin-codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.24.6) + react-refresh: 0.14.2 transitivePeerDependencies: + - '@babel/preset-env' - supports-color - '@react-native/codegen@0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0))': + '@react-native/codegen@0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6))': dependencies: - '@babel/parser': 7.26.2 - '@babel/preset-env': 7.26.0(@babel/core@7.26.0) + '@babel/parser': 7.24.6 + '@babel/preset-env': 7.24.6(@babel/core@7.24.6) glob: 7.2.3 - hermes-parser: 0.23.1 + hermes-parser: 0.19.1 invariant: 2.2.4 - jscodeshift: 0.14.0(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + jscodeshift: 0.14.0(@babel/preset-env@7.24.6(@babel/core@7.24.6)) mkdirp: 0.5.6 nullthrows: 1.1.1 - yargs: 17.7.2 transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: - '@react-native/dev-middleware': 0.76.1(bufferutil@4.0.8)(utf-8-validate@6.0.3) - '@react-native/metro-babel-transformer': 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - invariant: 2.2.4 - metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - metro-config: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - metro-core: 0.81.0 + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) + querystring: 0.2.1 readline: 1.3.0 transitivePeerDependencies: - '@babel/core' @@ -12163,14 +14286,12 @@ snapshots: - supports-color - utf-8-validate - '@react-native/debugger-frontend@0.74.85': {} - - '@react-native/debugger-frontend@0.76.1': {} + '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.85(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.74.85 + '@react-native/debugger-frontend': 0.74.83 '@rnx-kit/chromium-edge-launcher': 1.0.0 chrome-launcher: 0.15.2 connect: 3.7.0 @@ -12179,63 +14300,43 @@ snapshots: nullthrows: 1.1.1 open: 7.4.2 selfsigned: 2.4.1 - serve-static: 1.16.2 + serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding - supports-color - utf-8-validate - '@react-native/dev-middleware@0.76.1(bufferutil@4.0.8)(utf-8-validate@6.0.3)': - dependencies: - '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.76.1 - chrome-launcher: 0.15.2 - chromium-edge-launcher: 0.2.0 - connect: 3.7.0 - debug: 2.6.9 - nullthrows: 1.1.1 - open: 7.4.2 - selfsigned: 2.4.1 - serve-static: 1.16.2 - ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@react-native/gradle-plugin@0.76.1': {} + '@react-native/gradle-plugin@0.74.83': {} - '@react-native/js-polyfills@0.76.1': {} + '@react-native/js-polyfills@0.74.83': {} - '@react-native/metro-babel-transformer@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))': + '@react-native/metro-babel-transformer@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))': dependencies: - '@babel/core': 7.26.0 - '@react-native/babel-preset': 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - hermes-parser: 0.23.1 + '@babel/core': 7.24.6 + '@react-native/babel-preset': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + hermes-parser: 0.19.1 nullthrows: 1.1.1 transitivePeerDependencies: - '@babel/preset-env' - supports-color - '@react-native/normalize-colors@0.74.85': {} - - '@react-native/normalize-colors@0.76.1': {} + '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.76.1(@types/react@18.3.12)(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) optionalDependencies: - '@types/react': 18.3.12 + '@types/react': 18.3.1 '@rnx-kit/chromium-edge-launcher@1.0.0': dependencies: - '@types/node': 18.19.64 + '@types/node': 18.19.33 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -12244,306 +14345,582 @@ snapshots: transitivePeerDependencies: - supports-color - '@rollup/plugin-terser@0.4.4(rollup@3.29.5)': + '@rollup/plugin-terser@0.4.1(rollup@3.20.7)': dependencies: - serialize-javascript: 6.0.2 - smob: 1.5.0 - terser: 5.36.0 + serialize-javascript: 6.0.1 + smob: 0.0.6 + terser: 5.17.1 + optionalDependencies: + rollup: 3.20.7 + + '@rollup/plugin-terser@0.4.1(rollup@3.27.2)': + dependencies: + serialize-javascript: 6.0.1 + smob: 0.0.6 + terser: 5.17.1 optionalDependencies: - rollup: 3.29.5 + rollup: 3.27.2 - '@rollup/plugin-terser@0.4.4(rollup@4.24.4)': + '@rollup/plugin-terser@0.4.4(rollup@4.27.3)': dependencies: - serialize-javascript: 6.0.2 + serialize-javascript: 6.0.1 smob: 1.5.0 - terser: 5.36.0 + terser: 5.31.0 optionalDependencies: - rollup: 4.24.4 + rollup: 4.27.3 - '@rollup/plugin-typescript@11.1.6(rollup@3.29.5)(tslib@2.8.1)(typescript@5.6.3)': + '@rollup/plugin-typescript@11.1.0(rollup@3.20.7)(tslib@2.8.1)(typescript@5.6.3)': dependencies: - '@rollup/pluginutils': 5.1.3(rollup@3.29.5) - resolve: 1.22.8 + '@rollup/pluginutils': 5.0.2(rollup@3.20.7) + resolve: 1.22.1 + typescript: 5.6.3 + optionalDependencies: + rollup: 3.20.7 + tslib: 2.8.1 + + '@rollup/plugin-typescript@11.1.1(rollup@3.27.2)(tslib@2.8.1)(typescript@5.6.3)': + dependencies: + '@rollup/pluginutils': 5.0.2(rollup@3.27.2) + resolve: 1.22.2 typescript: 5.6.3 optionalDependencies: - rollup: 3.29.5 + rollup: 3.27.2 tslib: 2.8.1 - '@rollup/plugin-typescript@11.1.6(rollup@4.24.4)(tslib@2.8.1)(typescript@5.6.3)': + '@rollup/plugin-typescript@11.1.6(rollup@4.27.3)(tslib@2.8.1)(typescript@5.6.3)': dependencies: - '@rollup/pluginutils': 5.1.3(rollup@4.24.4) + '@rollup/pluginutils': 5.1.3(rollup@4.27.3) resolve: 1.22.8 typescript: 5.6.3 optionalDependencies: - rollup: 4.24.4 + rollup: 4.27.3 tslib: 2.8.1 - '@rollup/pluginutils@5.1.3(rollup@3.29.5)': + '@rollup/pluginutils@5.0.2(rollup@3.20.7)': dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.1 estree-walker: 2.0.2 - picomatch: 4.0.2 + picomatch: 2.3.1 optionalDependencies: - rollup: 3.29.5 + rollup: 3.20.7 - '@rollup/pluginutils@5.1.3(rollup@4.24.4)': + '@rollup/pluginutils@5.0.2(rollup@3.27.2)': dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.1 + estree-walker: 2.0.2 + picomatch: 2.3.1 + optionalDependencies: + rollup: 3.27.2 + + '@rollup/pluginutils@5.1.3(rollup@4.27.3)': + dependencies: + '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 4.0.2 optionalDependencies: - rollup: 4.24.4 + rollup: 4.27.3 + + '@rollup/rollup-android-arm-eabi@4.18.1': + optional: true + + '@rollup/rollup-android-arm-eabi@4.27.3': + optional: true + + '@rollup/rollup-android-arm64@4.18.1': + optional: true + + '@rollup/rollup-android-arm64@4.27.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.18.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.27.3': + optional: true + + '@rollup/rollup-darwin-x64@4.18.1': + optional: true + + '@rollup/rollup-darwin-x64@4.27.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.27.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.27.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.18.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.27.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.18.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.27.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.18.1': + optional: true - '@rollup/rollup-android-arm-eabi@4.24.4': + '@rollup/rollup-linux-arm64-gnu@4.27.3': optional: true - '@rollup/rollup-android-arm64@4.24.4': + '@rollup/rollup-linux-arm64-musl@4.18.1': optional: true - '@rollup/rollup-darwin-arm64@4.24.4': + '@rollup/rollup-linux-arm64-musl@4.27.3': optional: true - '@rollup/rollup-darwin-x64@4.24.4': + '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': optional: true - '@rollup/rollup-freebsd-arm64@4.24.4': + '@rollup/rollup-linux-powerpc64le-gnu@4.27.3': optional: true - '@rollup/rollup-freebsd-x64@4.24.4': + '@rollup/rollup-linux-riscv64-gnu@4.18.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.24.4': + '@rollup/rollup-linux-riscv64-gnu@4.27.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.24.4': + '@rollup/rollup-linux-s390x-gnu@4.18.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.24.4': + '@rollup/rollup-linux-s390x-gnu@4.27.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.24.4': + '@rollup/rollup-linux-x64-gnu@4.18.1': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.24.4': + '@rollup/rollup-linux-x64-gnu@4.27.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.24.4': + '@rollup/rollup-linux-x64-musl@4.18.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.24.4': + '@rollup/rollup-linux-x64-musl@4.27.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.24.4': + '@rollup/rollup-win32-arm64-msvc@4.18.1': optional: true - '@rollup/rollup-linux-x64-musl@4.24.4': + '@rollup/rollup-win32-arm64-msvc@4.27.3': optional: true - '@rollup/rollup-win32-arm64-msvc@4.24.4': + '@rollup/rollup-win32-ia32-msvc@4.18.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.24.4': + '@rollup/rollup-win32-ia32-msvc@4.27.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.24.4': + '@rollup/rollup-win32-x64-msvc@4.18.1': optional: true - '@rtsao/scc@1.1.0': {} + '@rollup/rollup-win32-x64-msvc@4.27.3': + optional: true '@segment/loosely-validate-event@2.0.0': dependencies: - component-type: 1.2.2 - join-component: 1.1.0 + component-type: 1.2.2 + join-component: 1.1.0 + + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + + '@sideway/formula@3.0.1': {} + + '@sideway/pinpoint@2.0.0': {} + + '@sinclair/typebox@0.27.8': {} + + '@sinclair/typebox@0.29.6': {} + + '@sindresorhus/is@4.6.0': {} + + '@sindresorhus/merge-streams@2.3.0': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@smithy/abort-controller@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/abort-controller@3.0.0': + dependencies: + '@smithy/types': 3.0.0 + tslib: 2.8.1 + + '@smithy/config-resolver@2.2.0': + dependencies: + '@smithy/node-config-provider': 2.3.0 + '@smithy/types': 2.12.0 + '@smithy/util-config-provider': 2.3.0 + '@smithy/util-middleware': 2.2.0 + tslib: 2.8.1 + + '@smithy/config-resolver@3.0.0': + dependencies: + '@smithy/node-config-provider': 3.0.0 + '@smithy/types': 3.0.0 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.0 + tslib: 2.8.1 + + '@smithy/core@1.4.2': + dependencies: + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/util-middleware': 2.2.0 + tslib: 2.8.1 + + '@smithy/core@2.0.1': + dependencies: + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 + '@smithy/middleware-serde': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + '@smithy/util-middleware': 3.0.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@2.3.0': + dependencies: + '@smithy/node-config-provider': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@3.0.0': + dependencies: + '@smithy/node-config-provider': 3.0.0 + '@smithy/property-provider': 3.0.0 + '@smithy/types': 3.0.0 + '@smithy/url-parser': 3.0.0 + tslib: 2.8.1 + + '@smithy/eventstream-codec@2.2.0': + dependencies: + '@aws-crypto/crc32': 3.0.0 + '@smithy/types': 2.12.0 + '@smithy/util-hex-encoding': 2.2.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-browser@2.2.0': + dependencies: + '@smithy/eventstream-serde-universal': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-config-resolver@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-node@2.2.0': + dependencies: + '@smithy/eventstream-serde-universal': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-universal@2.2.0': + dependencies: + '@smithy/eventstream-codec': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@2.5.0': + dependencies: + '@smithy/protocol-http': 3.3.0 + '@smithy/querystring-builder': 2.2.0 + '@smithy/types': 2.12.0 + '@smithy/util-base64': 2.3.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@3.0.1': + dependencies: + '@smithy/protocol-http': 4.0.0 + '@smithy/querystring-builder': 3.0.0 + '@smithy/types': 3.0.0 + '@smithy/util-base64': 3.0.0 + tslib: 2.8.1 + + '@smithy/hash-node@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + '@smithy/util-buffer-from': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@smithy/hash-node@3.0.0': + dependencies: + '@smithy/types': 3.0.0 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 + + '@smithy/invalid-dependency@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@sinclair/typebox@0.27.8': {} + '@smithy/invalid-dependency@3.0.0': + dependencies: + '@smithy/types': 3.0.0 + tslib: 2.8.1 - '@sinclair/typebox@0.29.6': {} + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 - '@sindresorhus/is@4.6.0': {} + '@smithy/is-array-buffer@3.0.0': + dependencies: + tslib: 2.8.1 - '@sindresorhus/merge-streams@2.3.0': {} + '@smithy/middleware-content-length@2.2.0': + dependencies: + '@smithy/protocol-http': 3.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@sinonjs/commons@3.0.1': + '@smithy/middleware-content-length@3.0.0': dependencies: - type-detect: 4.0.8 + '@smithy/protocol-http': 4.0.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 - '@sinonjs/fake-timers@10.3.0': + '@smithy/middleware-endpoint@2.5.1': dependencies: - '@sinonjs/commons': 3.0.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-middleware': 2.2.0 + tslib: 2.8.1 - '@smithy/abort-controller@3.1.6': + '@smithy/middleware-endpoint@3.0.0': dependencies: - '@smithy/types': 3.6.0 + '@smithy/middleware-serde': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 + '@smithy/types': 3.0.0 + '@smithy/url-parser': 3.0.0 + '@smithy/util-middleware': 3.0.0 tslib: 2.8.1 - '@smithy/config-resolver@3.0.10': + '@smithy/middleware-retry@2.3.1': dependencies: - '@smithy/node-config-provider': 3.1.9 - '@smithy/types': 3.6.0 - '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.8 + '@smithy/node-config-provider': 2.3.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/service-error-classification': 2.1.5 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 tslib: 2.8.1 + uuid: 9.0.1 - '@smithy/core@2.5.1': + '@smithy/middleware-retry@3.0.1': dependencies: - '@smithy/middleware-serde': 3.0.8 - '@smithy/protocol-http': 4.1.5 - '@smithy/types': 3.6.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-middleware': 3.0.8 - '@smithy/util-stream': 3.2.1 - '@smithy/util-utf8': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/service-error-classification': 3.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + '@smithy/util-middleware': 3.0.0 + '@smithy/util-retry': 3.0.0 tslib: 2.8.1 + uuid: 9.0.1 - '@smithy/credential-provider-imds@3.2.5': + '@smithy/middleware-serde@2.3.0': dependencies: - '@smithy/node-config-provider': 3.1.9 - '@smithy/property-provider': 3.1.8 - '@smithy/types': 3.6.0 - '@smithy/url-parser': 3.0.8 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/fetch-http-handler@4.0.0': + '@smithy/middleware-serde@3.0.0': dependencies: - '@smithy/protocol-http': 4.1.5 - '@smithy/querystring-builder': 3.0.8 - '@smithy/types': 3.6.0 - '@smithy/util-base64': 3.0.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/hash-node@3.0.8': + '@smithy/middleware-stack@2.2.0': dependencies: - '@smithy/types': 3.6.0 - '@smithy/util-buffer-from': 3.0.0 - '@smithy/util-utf8': 3.0.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/invalid-dependency@3.0.8': + '@smithy/middleware-stack@3.0.0': dependencies: - '@smithy/types': 3.6.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/is-array-buffer@2.2.0': + '@smithy/node-config-provider@2.3.0': dependencies: + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/is-array-buffer@3.0.0': + '@smithy/node-config-provider@3.0.0': dependencies: + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/middleware-content-length@3.0.10': + '@smithy/node-http-handler@2.5.0': dependencies: - '@smithy/protocol-http': 4.1.5 - '@smithy/types': 3.6.0 + '@smithy/abort-controller': 2.2.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/querystring-builder': 2.2.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/middleware-endpoint@3.2.1': + '@smithy/node-http-handler@3.0.0': dependencies: - '@smithy/core': 2.5.1 - '@smithy/middleware-serde': 3.0.8 - '@smithy/node-config-provider': 3.1.9 - '@smithy/shared-ini-file-loader': 3.1.9 - '@smithy/types': 3.6.0 - '@smithy/url-parser': 3.0.8 - '@smithy/util-middleware': 3.0.8 + '@smithy/abort-controller': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/querystring-builder': 3.0.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/middleware-retry@3.0.25': + '@smithy/property-provider@2.2.0': dependencies: - '@smithy/node-config-provider': 3.1.9 - '@smithy/protocol-http': 4.1.5 - '@smithy/service-error-classification': 3.0.8 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 - '@smithy/util-middleware': 3.0.8 - '@smithy/util-retry': 3.0.8 + '@smithy/types': 2.12.0 tslib: 2.8.1 - uuid: 9.0.1 - '@smithy/middleware-serde@3.0.8': + '@smithy/property-provider@3.0.0': dependencies: - '@smithy/types': 3.6.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/middleware-stack@3.0.8': + '@smithy/protocol-http@3.3.0': dependencies: - '@smithy/types': 3.6.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/node-config-provider@3.1.9': + '@smithy/protocol-http@4.0.0': dependencies: - '@smithy/property-provider': 3.1.8 - '@smithy/shared-ini-file-loader': 3.1.9 - '@smithy/types': 3.6.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/node-http-handler@3.2.5': + '@smithy/querystring-builder@2.2.0': dependencies: - '@smithy/abort-controller': 3.1.6 - '@smithy/protocol-http': 4.1.5 - '@smithy/querystring-builder': 3.0.8 - '@smithy/types': 3.6.0 + '@smithy/types': 2.12.0 + '@smithy/util-uri-escape': 2.2.0 tslib: 2.8.1 - '@smithy/property-provider@3.1.8': + '@smithy/querystring-builder@3.0.0': dependencies: - '@smithy/types': 3.6.0 + '@smithy/types': 3.0.0 + '@smithy/util-uri-escape': 3.0.0 tslib: 2.8.1 - '@smithy/protocol-http@4.1.5': + '@smithy/querystring-parser@2.2.0': dependencies: - '@smithy/types': 3.6.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/querystring-builder@3.0.8': + '@smithy/querystring-parser@3.0.0': dependencies: - '@smithy/types': 3.6.0 - '@smithy/util-uri-escape': 3.0.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/querystring-parser@3.0.8': + '@smithy/service-error-classification@2.1.5': + dependencies: + '@smithy/types': 2.12.0 + + '@smithy/service-error-classification@3.0.0': + dependencies: + '@smithy/types': 3.0.0 + + '@smithy/shared-ini-file-loader@2.4.0': dependencies: - '@smithy/types': 3.6.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/service-error-classification@3.0.8': + '@smithy/shared-ini-file-loader@3.0.0': dependencies: - '@smithy/types': 3.6.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 - '@smithy/shared-ini-file-loader@3.1.9': + '@smithy/signature-v4@2.3.0': dependencies: - '@smithy/types': 3.6.0 + '@smithy/is-array-buffer': 2.2.0 + '@smithy/types': 2.12.0 + '@smithy/util-hex-encoding': 2.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-uri-escape': 2.2.0 + '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@smithy/signature-v4@4.2.1': + '@smithy/signature-v4@3.0.0': dependencies: '@smithy/is-array-buffer': 3.0.0 - '@smithy/protocol-http': 4.1.5 - '@smithy/types': 3.6.0 + '@smithy/types': 3.0.0 '@smithy/util-hex-encoding': 3.0.0 - '@smithy/util-middleware': 3.0.8 + '@smithy/util-middleware': 3.0.0 '@smithy/util-uri-escape': 3.0.0 '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 - '@smithy/smithy-client@3.4.2': + '@smithy/smithy-client@2.5.1': + dependencies: + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-stack': 2.2.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/types': 2.12.0 + '@smithy/util-stream': 2.2.0 + tslib: 2.8.1 + + '@smithy/smithy-client@3.0.1': + dependencies: + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-stack': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/types': 3.0.0 + '@smithy/util-stream': 3.0.1 + tslib: 2.8.1 + + '@smithy/types@2.12.0': + dependencies: + tslib: 2.8.1 + + '@smithy/types@3.0.0': dependencies: - '@smithy/core': 2.5.1 - '@smithy/middleware-endpoint': 3.2.1 - '@smithy/middleware-stack': 3.0.8 - '@smithy/protocol-http': 4.1.5 - '@smithy/types': 3.6.0 - '@smithy/util-stream': 3.2.1 tslib: 2.8.1 - '@smithy/types@3.6.0': + '@smithy/url-parser@2.2.0': dependencies: + '@smithy/querystring-parser': 2.2.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/url-parser@3.0.8': + '@smithy/url-parser@3.0.0': dependencies: - '@smithy/querystring-parser': 3.0.8 - '@smithy/types': 3.6.0 + '@smithy/querystring-parser': 3.0.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 + + '@smithy/util-base64@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 '@smithy/util-base64@3.0.0': @@ -12552,10 +14929,18 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 + '@smithy/util-body-length-browser@2.2.0': + dependencies: + tslib: 2.8.1 + '@smithy/util-body-length-browser@3.0.0': dependencies: tslib: 2.8.1 + '@smithy/util-body-length-node@2.3.0': + dependencies: + tslib: 2.8.1 + '@smithy/util-body-length-node@3.0.0': dependencies: tslib: 2.8.1 @@ -12570,60 +14955,118 @@ snapshots: '@smithy/is-array-buffer': 3.0.0 tslib: 2.8.1 + '@smithy/util-config-provider@2.3.0': + dependencies: + tslib: 2.8.1 + '@smithy/util-config-provider@3.0.0': dependencies: tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@3.0.25': + '@smithy/util-defaults-mode-browser@2.2.1': + dependencies: + '@smithy/property-provider': 2.2.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + bowser: 2.11.0 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-browser@3.0.1': dependencies: - '@smithy/property-provider': 3.1.8 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 + '@smithy/property-provider': 3.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 bowser: 2.11.0 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@3.0.25': + '@smithy/util-defaults-mode-node@2.3.1': + dependencies: + '@smithy/config-resolver': 2.2.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-node@3.0.1': + dependencies: + '@smithy/config-resolver': 3.0.0 + '@smithy/credential-provider-imds': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/property-provider': 3.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + tslib: 2.8.1 + + '@smithy/util-endpoints@1.2.0': dependencies: - '@smithy/config-resolver': 3.0.10 - '@smithy/credential-provider-imds': 3.2.5 - '@smithy/node-config-provider': 3.1.9 - '@smithy/property-provider': 3.1.8 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/util-endpoints@2.1.4': + '@smithy/util-endpoints@2.0.0': + dependencies: + '@smithy/node-config-provider': 3.0.0 + '@smithy/types': 3.0.0 + tslib: 2.8.1 + + '@smithy/util-hex-encoding@2.2.0': dependencies: - '@smithy/node-config-provider': 3.1.9 - '@smithy/types': 3.6.0 tslib: 2.8.1 '@smithy/util-hex-encoding@3.0.0': dependencies: tslib: 2.8.1 - '@smithy/util-middleware@3.0.8': + '@smithy/util-middleware@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/util-middleware@3.0.0': + dependencies: + '@smithy/types': 3.0.0 + tslib: 2.8.1 + + '@smithy/util-retry@2.2.0': + dependencies: + '@smithy/service-error-classification': 2.1.5 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/util-retry@3.0.0': dependencies: - '@smithy/types': 3.6.0 + '@smithy/service-error-classification': 3.0.0 + '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/util-retry@3.0.8': + '@smithy/util-stream@2.2.0': dependencies: - '@smithy/service-error-classification': 3.0.8 - '@smithy/types': 3.6.0 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/types': 2.12.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-buffer-from': 2.2.0 + '@smithy/util-hex-encoding': 2.2.0 + '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@smithy/util-stream@3.2.1': + '@smithy/util-stream@3.0.1': dependencies: - '@smithy/fetch-http-handler': 4.0.0 - '@smithy/node-http-handler': 3.2.5 - '@smithy/types': 3.6.0 + '@smithy/fetch-http-handler': 3.0.1 + '@smithy/node-http-handler': 3.0.0 + '@smithy/types': 3.0.0 '@smithy/util-base64': 3.0.0 '@smithy/util-buffer-from': 3.0.0 '@smithy/util-hex-encoding': 3.0.0 '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 + '@smithy/util-uri-escape@2.2.0': + dependencies: + tslib: 2.8.1 + '@smithy/util-uri-escape@3.0.0': dependencies: tslib: 2.8.1 @@ -12638,20 +15081,26 @@ snapshots: '@smithy/util-buffer-from': 3.0.0 tslib: 2.8.1 + '@smithy/util-waiter@2.2.0': + dependencies: + '@smithy/abort-controller': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + '@tidbcloud/serverless@0.1.1': {} '@tootallnate/once@1.1.2': optional: true - '@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.3.3)': + '@trivago/prettier-plugin-sort-imports@4.2.0(prettier@3.0.3)': dependencies: '@babel/generator': 7.17.7 - '@babel/parser': 7.26.2 - '@babel/traverse': 7.23.2 + '@babel/parser': 7.22.10 + '@babel/traverse': 7.17.3 '@babel/types': 7.17.0 javascript-natural-sort: 0.7.1 lodash: 4.17.21 - prettier: 3.3.3 + prettier: 3.0.3 transitivePeerDependencies: - supports-color @@ -12663,94 +15112,83 @@ snapshots: '@tsconfig/node16@1.0.4': {} - '@types/async-retry@1.4.9': + '@types/async-retry@1.4.8': dependencies: '@types/retry': 0.12.5 - '@types/axios@0.14.4': + '@types/axios@0.14.0': dependencies: - axios: 1.7.7 + axios: 1.6.8 transitivePeerDependencies: - debug - '@types/babel__core@7.20.5': + '@types/better-sqlite3@7.6.10': dependencies: - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - '@types/babel__generator': 7.6.8 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.20.6 + '@types/node': 20.12.12 - '@types/babel__generator@7.6.8': + '@types/better-sqlite3@7.6.12': dependencies: - '@babel/types': 7.26.0 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - - '@types/babel__traverse@7.20.6': - dependencies: - '@babel/types': 7.26.0 - - '@types/better-sqlite3@7.6.11': - dependencies: - '@types/node': 18.19.64 + '@types/node': 20.12.12 '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 20.17.6 + '@types/node': 20.12.12 '@types/braces@3.0.4': {} '@types/connect@3.4.38': dependencies: - '@types/node': 20.17.6 + '@types/node': 20.12.12 '@types/docker-modem@3.0.6': dependencies: - '@types/node': 18.19.64 - '@types/ssh2': 1.15.1 + '@types/node': 20.12.12 + '@types/ssh2': 1.15.0 + + '@types/dockerode@3.3.29': + dependencies: + '@types/docker-modem': 3.0.6 + '@types/node': 20.12.12 + '@types/ssh2': 1.15.0 - '@types/dockerode@3.3.31': + '@types/dockerode@3.3.32': dependencies: '@types/docker-modem': 3.0.6 - '@types/node': 18.19.64 - '@types/ssh2': 1.15.1 + '@types/node': 20.12.12 + '@types/ssh2': 1.15.0 + + '@types/emscripten@1.39.11': {} - '@types/emscripten@1.39.13': {} + '@types/estree@1.0.1': {} + + '@types/estree@1.0.5': {} '@types/estree@1.0.6': {} - '@types/express-serve-static-core@4.19.6': + '@types/express-serve-static-core@4.19.0': dependencies: - '@types/node': 20.17.6 - '@types/qs': 6.9.17 + '@types/node': 20.12.12 + '@types/qs': 6.9.15 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 '@types/express@4.17.21': dependencies: '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.19.6 - '@types/qs': 6.9.17 + '@types/express-serve-static-core': 4.19.0 + '@types/qs': 6.9.15 '@types/serve-static': 1.15.7 '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 18.19.64 + '@types/node': 20.12.12 '@types/glob@8.1.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 18.19.64 - - '@types/graceful-fs@4.1.9': - dependencies: - '@types/node': 20.17.6 + '@types/node': 20.12.12 '@types/http-errors@2.0.4': {} @@ -12760,24 +15198,19 @@ snapshots: dependencies: '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports@1.1.2': - dependencies: - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-lib-report': 3.0.3 - '@types/istanbul-reports@3.0.4': dependencies: '@types/istanbul-lib-report': 3.0.3 '@types/json-diff@1.0.3': {} - '@types/json-schema@7.0.15': {} + '@types/json-schema@7.0.13': {} '@types/json5@0.0.29': {} '@types/jsonfile@6.1.4': dependencies: - '@types/node': 18.19.64 + '@types/node': 20.12.12 '@types/micromatch@4.0.9': dependencies: @@ -12787,61 +15220,57 @@ snapshots: '@types/minimatch@5.1.2': {} - '@types/minimist@1.2.5': {} + '@types/minimist@1.2.2': {} '@types/node-forge@1.3.11': dependencies: - '@types/node': 18.19.64 + '@types/node': 20.12.12 + + '@types/node@18.15.10': {} - '@types/node@18.19.64': + '@types/node@18.19.33': dependencies: undici-types: 5.26.5 - '@types/node@20.12.14': + '@types/node@20.10.1': dependencies: undici-types: 5.26.5 - '@types/node@20.17.6': + '@types/node@20.12.12': dependencies: - undici-types: 6.19.8 + undici-types: 5.26.5 - '@types/node@22.9.0': + '@types/node@22.9.1': dependencies: undici-types: 6.19.8 - '@types/normalize-package-data@2.4.4': {} - - '@types/pg@8.11.10': - dependencies: - '@types/node': 18.19.64 - pg-protocol: 1.7.0 - pg-types: 4.0.2 + '@types/normalize-package-data@2.4.1': {} '@types/pg@8.11.6': dependencies: - '@types/node': 18.19.64 - pg-protocol: 1.7.0 + '@types/node': 20.12.12 + pg-protocol: 1.6.1 pg-types: 4.0.2 '@types/pg@8.6.6': dependencies: - '@types/node': 18.19.64 - pg-protocol: 1.7.0 + '@types/node': 20.12.12 + pg-protocol: 1.6.1 pg-types: 2.2.0 '@types/pluralize@0.0.33': {} - '@types/prop-types@15.7.13': {} + '@types/prop-types@15.7.12': {} - '@types/ps-tree@1.1.6': {} + '@types/ps-tree@1.1.2': {} - '@types/qs@6.9.17': {} + '@types/qs@6.9.15': {} '@types/range-parser@1.2.7': {} - '@types/react@18.3.12': + '@types/react@18.3.1': dependencies: - '@types/prop-types': 15.7.13 + '@types/prop-types': 15.7.12 csstype: 3.1.3 '@types/retry@0.12.5': {} @@ -12851,22 +15280,22 @@ snapshots: '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 20.17.6 + '@types/node': 20.12.12 '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 20.17.6 + '@types/node': 20.12.12 '@types/send': 0.17.4 '@types/sql.js@1.4.9': dependencies: - '@types/emscripten': 1.39.13 - '@types/node': 20.17.6 + '@types/emscripten': 1.39.11 + '@types/node': 20.12.12 - '@types/ssh2@1.15.1': + '@types/ssh2@1.15.0': dependencies: - '@types/node': 18.19.64 + '@types/node': 18.19.33 '@types/stack-utils@2.0.3': {} @@ -12874,103 +15303,116 @@ snapshots: '@types/uuid@9.0.8': {} - '@types/which@3.0.4': {} + '@types/which@3.0.0': {} - '@types/ws@8.5.13': + '@types/ws@8.5.11': dependencies: - '@types/node': 18.19.64 + '@types/node': 20.12.12 '@types/yargs-parser@21.0.3': {} - '@types/yargs@13.0.12': + '@types/yargs@15.0.19': dependencies: '@types/yargs-parser': 21.0.3 - '@types/yargs@17.0.33': + '@types/yargs@17.0.32': dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.7 - eslint: 8.57.1 + '@eslint-community/regexpp': 4.9.0 + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/type-utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 6.7.3 + debug: 4.3.4 + eslint: 8.50.0 graphemer: 1.4.0 - ignore: 5.3.2 + ignore: 5.2.4 natural-compare: 1.4.0 - semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) + semver: 7.6.2 + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/type-utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 7.18.0 - eslint: 8.57.1 + '@eslint-community/regexpp': 4.11.0 + '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 7.16.1 + '@typescript-eslint/type-utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 7.16.1 + eslint: 8.57.0 graphemer: 1.4.0 - ignore: 5.3.2 + ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.4.0(typescript@5.6.3) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/experimental-utils@5.62.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/experimental-utils@5.62.0(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.6.3) - eslint: 8.57.1 + '@typescript-eslint/utils': 5.62.0(eslint@8.50.0)(typescript@5.6.3) + eslint: 8.50.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.2.2)': dependencies: - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.7 - eslint: 8.57.1 + '@typescript-eslint/scope-manager': 6.10.0 + '@typescript-eslint/types': 6.10.0 + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.10.0 + debug: 4.3.4 + eslint: 8.53.0 + optionalDependencies: + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3)': + dependencies: + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 6.7.3 + debug: 4.3.4 + eslint: 8.50.0 optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.7 - eslint: 8.57.1 + '@typescript-eslint/scope-manager': 7.16.1 + '@typescript-eslint/types': 7.16.1 + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 7.16.1 + debug: 4.3.4 + eslint: 8.57.0 optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/rule-tester@6.21.0(@eslint/eslintrc@2.1.4)(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/rule-tester@6.10.0(@eslint/eslintrc@3.1.0)(eslint@8.53.0)(typescript@5.2.2)': dependencies: - '@eslint/eslintrc': 2.1.4 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) + '@eslint/eslintrc': 3.1.0 + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) + '@typescript-eslint/utils': 6.10.0(eslint@8.53.0)(typescript@5.2.2) ajv: 6.12.6 - eslint: 8.57.1 + eslint: 8.53.0 lodash.merge: 4.6.2 - semver: 7.6.3 + semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript @@ -12980,35 +15422,40 @@ snapshots: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - '@typescript-eslint/scope-manager@6.21.0': + '@typescript-eslint/scope-manager@6.10.0': dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 + '@typescript-eslint/types': 6.10.0 + '@typescript-eslint/visitor-keys': 6.10.0 - '@typescript-eslint/scope-manager@7.18.0': + '@typescript-eslint/scope-manager@6.7.3': dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/visitor-keys': 6.7.3 - '@typescript-eslint/type-utils@6.21.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/scope-manager@7.16.1': dependencies: - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - debug: 4.3.7 - eslint: 8.57.1 - ts-api-utils: 1.4.0(typescript@5.6.3) + '@typescript-eslint/types': 7.16.1 + '@typescript-eslint/visitor-keys': 7.16.1 + + '@typescript-eslint/type-utils@6.7.3(eslint@8.50.0)(typescript@5.6.3)': + dependencies: + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + debug: 4.3.4 + eslint: 8.50.0 + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@7.18.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/type-utils@7.16.1(eslint@8.57.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) - '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) - debug: 4.3.7 - eslint: 8.57.1 - ts-api-utils: 1.4.0(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) + '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) + debug: 4.3.4 + eslint: 8.57.0 + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -13016,90 +15463,119 @@ snapshots: '@typescript-eslint/types@5.62.0': {} - '@typescript-eslint/types@6.21.0': {} + '@typescript-eslint/types@6.10.0': {} + + '@typescript-eslint/types@6.7.3': {} - '@typescript-eslint/types@7.18.0': {} + '@typescript-eslint/types@7.16.1': {} '@typescript-eslint/typescript-estree@5.62.0(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.7 + debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.3 + semver: 7.6.2 tsutils: 3.21.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@6.21.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2)': dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.7 + '@typescript-eslint/types': 6.10.0 + '@typescript-eslint/visitor-keys': 6.10.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.6.2 + ts-api-utils: 1.0.3(typescript@5.2.2) + optionalDependencies: + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@6.7.3(typescript@5.6.3)': + dependencies: + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/visitor-keys': 6.7.3 + debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - minimatch: 9.0.3 - semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) + semver: 7.6.2 + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.18.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@7.16.1(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.7 + '@typescript-eslint/types': 7.16.1 + '@typescript-eslint/visitor-keys': 7.16.1 + debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) + minimatch: 9.0.4 + semver: 7.6.2 + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/utils@5.62.0(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@types/json-schema': 7.0.15 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@types/json-schema': 7.0.13 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.3) - eslint: 8.57.1 + eslint: 8.50.0 eslint-scope: 5.1.1 - semver: 7.6.3 + semver: 7.6.2 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/utils@6.10.0(eslint@8.53.0)(typescript@5.2.2)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) + '@types/json-schema': 7.0.13 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 6.10.0 + '@typescript-eslint/types': 6.10.0 + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) + eslint: 8.53.0 + semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@6.21.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/utils@6.7.3(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@types/json-schema': 7.0.15 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@types/json-schema': 7.0.13 '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) - eslint: 8.57.1 - semver: 7.6.3 + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) + eslint: 8.50.0 + semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@7.18.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/utils@7.16.1(eslint@8.57.0)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) - eslint: 8.57.1 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 7.16.1 + '@typescript-eslint/types': 7.16.1 + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) + eslint: 8.57.0 transitivePeerDependencies: - supports-color - typescript @@ -13109,14 +15585,19 @@ snapshots: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@6.21.0': + '@typescript-eslint/visitor-keys@6.10.0': + dependencies: + '@typescript-eslint/types': 6.10.0 + eslint-visitor-keys: 3.4.3 + + '@typescript-eslint/visitor-keys@6.7.3': dependencies: - '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/types': 6.7.3 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@7.18.0': + '@typescript-eslint/visitor-keys@7.16.1': dependencies: - '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/types': 7.16.1 eslint-visitor-keys: 3.4.3 '@typescript/analyze-trace@0.10.1': @@ -13155,32 +15636,32 @@ snapshots: dependencies: '@vitest/spy': 1.6.0 '@vitest/utils': 1.6.0 - chai: 4.5.0 + chai: 4.4.1 - '@vitest/expect@2.1.4': + '@vitest/expect@2.1.2': dependencies: - '@vitest/spy': 2.1.4 - '@vitest/utils': 2.1.4 - chai: 5.1.2 + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.4(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0))': + '@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0))': dependencies: - '@vitest/spy': 2.1.4 + '@vitest/spy': 2.1.2 estree-walker: 3.0.3 - magic-string: 0.30.12 + magic-string: 0.30.11 optionalDependencies: - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) - '@vitest/mocker@2.1.4(vite@5.4.10(@types/node@22.9.0)(terser@5.36.0))': + '@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@22.9.1)(lightningcss@1.25.1)(terser@5.31.0))': dependencies: - '@vitest/spy': 2.1.4 + '@vitest/spy': 2.1.2 estree-walker: 3.0.3 - magic-string: 0.30.12 + magic-string: 0.30.11 optionalDependencies: - vite: 5.4.10(@types/node@22.9.0)(terser@5.36.0) + vite: 5.3.3(@types/node@22.9.1)(lightningcss@1.25.1)(terser@5.31.0) - '@vitest/pretty-format@2.1.4': + '@vitest/pretty-format@2.1.2': dependencies: tinyrainbow: 1.2.0 @@ -13190,28 +15671,28 @@ snapshots: p-limit: 5.0.0 pathe: 1.1.2 - '@vitest/runner@2.1.4': + '@vitest/runner@2.1.2': dependencies: - '@vitest/utils': 2.1.4 + '@vitest/utils': 2.1.2 pathe: 1.1.2 '@vitest/snapshot@1.6.0': dependencies: - magic-string: 0.30.12 + magic-string: 0.30.10 pathe: 1.1.2 pretty-format: 29.7.0 - '@vitest/snapshot@2.1.4': + '@vitest/snapshot@2.1.2': dependencies: - '@vitest/pretty-format': 2.1.4 - magic-string: 0.30.12 + '@vitest/pretty-format': 2.1.2 + magic-string: 0.30.11 pathe: 1.1.2 '@vitest/spy@1.6.0': dependencies: tinyspy: 2.2.1 - '@vitest/spy@2.1.4': + '@vitest/spy@2.1.2': dependencies: tinyspy: 3.0.2 @@ -13222,21 +15703,21 @@ snapshots: fflate: 0.8.2 flatted: 3.3.1 pathe: 1.1.2 - picocolors: 1.1.1 + picocolors: 1.0.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) + vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) optional: true - '@vitest/ui@1.6.0(vitest@2.1.4)': + '@vitest/ui@1.6.0(vitest@2.1.2)': dependencies: '@vitest/utils': 1.6.0 fast-glob: 3.3.2 fflate: 0.8.2 flatted: 3.3.1 pathe: 1.1.2 - picocolors: 1.1.1 + picocolors: 1.0.1 sirv: 2.0.4 - vitest: 2.1.4(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) + vitest: 2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) '@vitest/utils@1.6.0': dependencies: @@ -13245,13 +15726,13 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 - '@vitest/utils@2.1.4': + '@vitest/utils@2.1.2': dependencies: - '@vitest/pretty-format': 2.1.4 + '@vitest/pretty-format': 2.1.2 loupe: 3.1.2 tinyrainbow: 1.2.0 - '@xata.io/client@0.29.5(typescript@5.6.3)': + '@xata.io/client@0.29.4(typescript@5.6.3)': dependencies: typescript: 5.6.3 @@ -13271,19 +15752,25 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-jsx@5.3.2(acorn@8.14.0): + acorn-jsx@5.3.2(acorn@8.10.0): dependencies: - acorn: 8.14.0 + acorn: 8.10.0 - acorn-walk@8.3.4: + acorn-jsx@5.3.2(acorn@8.11.3): dependencies: - acorn: 8.14.0 + acorn: 8.11.3 + + acorn-walk@8.3.2: {} + + acorn@8.10.0: {} + + acorn@8.11.3: {} - acorn@8.14.0: {} + acorn@8.8.2: {} agent-base@6.0.2: dependencies: - debug: 4.3.7 + debug: 4.3.4 transitivePeerDependencies: - supports-color @@ -13317,16 +15804,26 @@ snapshots: dependencies: type-fest: 0.21.3 - ansi-escapes@6.2.1: {} + ansi-escapes@6.2.0: + dependencies: + type-fest: 3.13.1 ansi-escapes@7.0.0: dependencies: environment: 1.1.0 + ansi-fragments@0.2.1: + dependencies: + colorette: 1.4.0 + slice-ansi: 2.1.0 + strip-ansi: 5.2.0 + ansi-regex@4.1.1: {} ansi-regex@5.0.1: {} + ansi-regex@6.0.1: {} + ansi-regex@6.1.0: {} ansi-styles@3.2.1: @@ -13350,6 +15847,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + appdirsjs@1.2.7: {} + application-config-path@0.1.1: {} aproba@2.0.0: @@ -13373,6 +15872,11 @@ snapshots: argsarray@0.0.1: {} + array-buffer-byte-length@1.0.0: + dependencies: + call-bind: 1.0.2 + is-array-buffer: 3.0.2 + array-buffer-byte-length@1.0.1: dependencies: call-bind: 1.0.7 @@ -13382,39 +15886,46 @@ snapshots: array-flatten@1.1.1: {} - array-includes@3.1.8: + array-includes@3.1.6: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + get-intrinsic: 1.2.1 is-string: 1.0.7 array-union@2.1.0: {} - array.prototype.findlastindex@1.2.5: + array.prototype.findlastindex@1.2.2: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - es-object-atoms: 1.0.0 - es-shim-unscopables: 1.0.2 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 + get-intrinsic: 1.2.1 - array.prototype.flat@1.3.2: + array.prototype.flat@1.3.1: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-shim-unscopables: 1.0.2 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 - array.prototype.flatmap@1.3.2: + array.prototype.flatmap@1.3.1: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-shim-unscopables: 1.0.2 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 + + arraybuffer.prototype.slice@1.0.1: + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.2.0 + get-intrinsic: 1.2.1 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 arraybuffer.prototype.slice@1.0.3: dependencies: @@ -13453,6 +15964,8 @@ snapshots: dependencies: tslib: 2.8.1 + astral-regex@1.0.0: {} + async-limiter@1.0.1: {} async-retry@1.3.3: @@ -13463,17 +15976,17 @@ snapshots: at-least-node@1.0.0: {} - ava@5.3.1: + ava@5.3.0(@ava/typescript@5.0.0): dependencies: - acorn: 8.14.0 - acorn-walk: 8.3.4 + acorn: 8.11.3 + acorn-walk: 8.3.2 ansi-styles: 6.2.1 arrgv: 1.0.2 arrify: 3.0.0 - callsites: 4.2.0 + callsites: 4.1.0 cbor: 8.1.0 chalk: 5.3.0 - chokidar: 3.6.0 + chokidar: 3.5.3 chunkd: 2.0.1 ci-info: 3.9.0 ci-parallel-vars: 1.0.1 @@ -13483,7 +15996,7 @@ snapshots: common-path-prefix: 3.0.0 concordance: 5.0.4 currently-unhandled: 0.4.1 - debug: 4.3.7 + debug: 4.3.4 emittery: 1.0.3 figures: 5.0.0 globby: 13.2.2 @@ -13508,145 +16021,80 @@ snapshots: temp-dir: 3.0.0 write-file-atomic: 5.0.1 yargs: 17.7.2 + optionalDependencies: + '@ava/typescript': 5.0.0 transitivePeerDependencies: - supports-color + available-typed-arrays@1.0.5: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 - aws4fetch@1.0.20: {} + aws-ssl-profiles@1.1.1: + optional: true - axios@1.7.7: + axios@1.6.8: dependencies: - follow-redirects: 1.15.9 - form-data: 4.0.1 + follow-redirects: 1.15.6 + form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug - babel-core@7.0.0-bridge.0(@babel/core@7.26.0): - dependencies: - '@babel/core': 7.26.0 - - babel-jest@29.7.0(@babel/core@7.26.0): - dependencies: - '@babel/core': 7.26.0 - '@jest/transform': 29.7.0 - '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.26.0) - chalk: 4.1.2 - graceful-fs: 4.2.11 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - - babel-plugin-istanbul@6.1.1: - dependencies: - '@babel/helper-plugin-utils': 7.25.9 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - - babel-plugin-jest-hoist@29.6.3: + babel-core@7.0.0-bridge.0(@babel/core@7.24.6): dependencies: - '@babel/template': 7.25.9 - '@babel/types': 7.26.0 - '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.20.6 + '@babel/core': 7.24.6 - babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.26.0): + babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.6): dependencies: - '@babel/compat-data': 7.26.2 - '@babel/core': 7.26.0 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) + '@babel/compat-data': 7.24.6 + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.26.0): + babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.6): dependencies: - '@babel/core': 7.26.0 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) - core-js-compat: 3.39.0 + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) + core-js-compat: 3.37.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.26.0): + babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.24.6): dependencies: - '@babel/core': 7.26.0 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) transitivePeerDependencies: - supports-color - babel-plugin-react-compiler@0.0.0-experimental-592953e-20240517: - dependencies: - '@babel/generator': 7.2.0 - '@babel/types': 7.26.0 - chalk: 4.1.2 - invariant: 2.2.4 - pretty-format: 24.9.0 - zod: 3.23.8 - zod-validation-error: 2.1.0(zod@3.23.8) - - babel-plugin-react-native-web@0.19.13: {} + babel-plugin-react-native-web@0.19.12: {} - babel-plugin-syntax-hermes-parser@0.23.1: + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.24.6): dependencies: - hermes-parser: 0.23.1 - - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.26.0): - dependencies: - '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-flow': 7.24.6(@babel/core@7.24.6) transitivePeerDependencies: - '@babel/core' - babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.0): - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.0) - '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.0) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0) - - babel-preset-expo@11.0.15(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)): - dependencies: - '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/preset-react': 7.25.9(@babel/core@7.26.0) - '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) - '@react-native/babel-preset': 0.74.87(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - babel-plugin-react-compiler: 0.0.0-experimental-592953e-20240517 - babel-plugin-react-native-web: 0.19.13 + babel-preset-expo@11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)): + dependencies: + '@babel/plugin-proposal-decorators': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-export-namespace-from': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-object-rest-spread': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) + '@babel/preset-react': 7.24.6(@babel/core@7.24.6) + '@babel/preset-typescript': 7.24.6(@babel/core@7.24.6) + '@react-native/babel-preset': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + babel-plugin-react-native-web: 0.19.12 react-refresh: 0.14.2 transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' - supports-color - babel-preset-jest@29.6.3(@babel/core@7.26.0): - dependencies: - '@babel/core': 7.26.0 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) - balanced-match@1.0.2: {} base64-js@1.5.1: {} @@ -13676,7 +16124,7 @@ snapshots: big-integer@1.6.52: {} - binary-extensions@2.3.0: {} + binary-extensions@2.2.0: {} bindings@1.5.0: dependencies: @@ -13692,7 +16140,7 @@ snapshots: blueimp-md5@2.19.0: {} - body-parser@1.20.3: + body-parser@1.20.2: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -13702,7 +16150,7 @@ snapshots: http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.13.0 + qs: 6.11.0 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 @@ -13711,10 +16159,6 @@ snapshots: bowser@2.11.0: {} - bplist-creator@0.0.7: - dependencies: - stream-buffers: 2.2.0 - bplist-creator@0.1.0: dependencies: stream-buffers: 2.2.0 @@ -13740,12 +16184,12 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.24.2: + browserslist@4.23.0: dependencies: - caniuse-lite: 1.0.30001679 - electron-to-chromium: 1.5.55 - node-releases: 2.0.18 - update-browserslist-db: 1.1.1(browserslist@4.24.2) + caniuse-lite: 1.0.30001624 + electron-to-chromium: 1.4.783 + node-releases: 2.0.14 + update-browserslist-db: 1.0.16(browserslist@4.23.0) bser@2.1.1: dependencies: @@ -13769,7 +16213,7 @@ snapshots: bufferutil@4.0.8: dependencies: - node-gyp-build: 4.8.2 + node-gyp-build: 4.8.1 buildcheck@0.0.6: optional: true @@ -13780,29 +16224,28 @@ snapshots: builtins@5.1.0: dependencies: - semver: 7.6.3 + semver: 7.6.2 bun-types@0.6.14: {} - bun-types@1.1.34: - dependencies: - '@types/node': 20.12.14 - '@types/ws': 8.5.13 + bun-types@1.0.3: {} - bundle-require@4.2.1(esbuild@0.19.12): + bundle-require@4.0.2(esbuild@0.18.20): dependencies: - esbuild: 0.19.12 + esbuild: 0.18.20 load-tsconfig: 0.2.5 - bundle-require@5.0.0(esbuild@0.24.0): + bundle-require@5.0.0(esbuild@0.23.0): dependencies: - esbuild: 0.24.0 + esbuild: 0.23.0 load-tsconfig: 0.2.5 busboy@1.6.0: dependencies: streamsearch: 1.1.0 + bytes@3.0.0: {} + bytes@3.1.2: {} cac@6.7.14: {} @@ -13831,12 +16274,12 @@ snapshots: - bluebird optional: true - cacache@18.0.4: + cacache@18.0.3: dependencies: '@npmcli/fs': 3.1.1 fs-minipass: 3.0.3 - glob: 10.4.5 - lru-cache: 10.4.3 + glob: 10.4.1 + lru-cache: 10.2.2 minipass: 7.1.2 minipass-collect: 2.0.1 minipass-flush: 1.0.5 @@ -13846,6 +16289,11 @@ snapshots: tar: 6.2.1 unique-filename: 3.0.0 + call-bind@1.0.2: + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.2.1 + call-bind@1.0.7: dependencies: es-define-property: 1.0.0 @@ -13866,7 +16314,7 @@ snapshots: callsites@3.1.0: {} - callsites@4.2.0: {} + callsites@4.1.0: {} camelcase@5.3.1: {} @@ -13874,11 +16322,11 @@ snapshots: camelcase@7.0.1: {} - caniuse-lite@1.0.30001679: {} + caniuse-lite@1.0.30001624: {} capnp-ts@0.7.0: dependencies: - debug: 4.3.7 + debug: 4.3.4 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -13892,17 +16340,17 @@ snapshots: dependencies: nofilter: 3.1.0 - chai@4.5.0: + chai@4.4.1: dependencies: assertion-error: 1.1.0 check-error: 1.0.3 - deep-eql: 4.1.4 + deep-eql: 4.1.3 get-func-name: 2.0.2 loupe: 2.3.7 pathval: 1.1.1 - type-detect: 4.1.0 + type-detect: 4.0.8 - chai@5.1.2: + chai@5.1.1: dependencies: assertion-error: 2.0.1 check-error: 2.1.1 @@ -13933,7 +16381,7 @@ snapshots: check-error@2.1.1: {} - chokidar@3.6.0: + chokidar@3.5.3: dependencies: anymatch: 3.1.3 braces: 3.0.3 @@ -13945,9 +16393,17 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - chokidar@4.0.1: + chokidar@3.6.0: dependencies: - readdirp: 4.0.2 + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 chownr@1.1.4: {} @@ -13955,21 +16411,10 @@ snapshots: chrome-launcher@0.15.2: dependencies: - '@types/node': 20.17.6 - escape-string-regexp: 4.0.0 - is-wsl: 2.2.0 - lighthouse-logger: 1.4.2 - transitivePeerDependencies: - - supports-color - - chromium-edge-launcher@0.2.0: - dependencies: - '@types/node': 20.17.6 + '@types/node': 20.12.12 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 - mkdirp: 1.0.4 - rimraf: 3.0.2 transitivePeerDependencies: - supports-color @@ -13977,6 +16422,8 @@ snapshots: ci-info@2.0.0: {} + ci-info@3.8.0: {} + ci-info@3.9.0: {} ci-parallel-vars@1.0.1: {} @@ -13995,18 +16442,22 @@ snapshots: clean-yaml-object@0.1.0: {} - cli-color@2.0.4: + cli-color@2.0.3: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 + d: 1.0.1 + es5-ext: 0.10.62 es6-iterator: 2.0.3 - memoizee: 0.4.17 - timers-ext: 0.1.8 + memoizee: 0.4.15 + timers-ext: 0.1.7 cli-cursor@2.1.0: dependencies: restore-cursor: 2.0.0 + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + cli-highlight@2.1.11: dependencies: chalk: 4.1.2 @@ -14018,6 +16469,12 @@ snapshots: cli-spinners@2.9.2: {} + cli-table3@0.6.3: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + cli-table3@0.6.5: dependencies: string-width: 4.2.3 @@ -14029,6 +16486,12 @@ snapshots: slice-ansi: 5.0.0 string-width: 5.1.2 + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + cliui@7.0.4: dependencies: string-width: 4.2.3 @@ -14070,6 +16533,8 @@ snapshots: color-support@1.1.3: optional: true + colorette@1.4.0: {} + colorette@2.0.19: {} colors@1.4.0: {} @@ -14082,6 +16547,8 @@ snapshots: commander@10.0.1: {} + commander@11.0.0: {} + commander@12.1.0: {} commander@2.20.3: {} @@ -14098,6 +16565,22 @@ snapshots: component-type@1.2.2: {} + compressible@2.0.18: + dependencies: + mime-db: 1.52.0 + + compression@1.7.4: + dependencies: + accepts: 1.3.8 + bytes: 3.0.0 + compressible: 2.0.18 + debug: 2.6.9 + on-headers: 1.0.2 + safe-buffer: 5.1.2 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + concat-map@0.0.1: {} concordance@5.0.4: @@ -14108,10 +16591,10 @@ snapshots: js-string-escape: 1.0.1 lodash: 4.17.21 md5-hex: 3.0.1 - semver: 7.6.3 + semver: 7.6.2 well-known-symbols: 2.0.0 - concurrently@8.2.2: + concurrently@8.2.1: dependencies: chalk: 4.1.2 date-fns: 2.30.0 @@ -14123,7 +16606,7 @@ snapshots: tree-kill: 1.2.2 yargs: 17.7.2 - confbox@0.1.8: {} + confbox@0.1.7: {} connect@3.7.0: dependencies: @@ -14151,9 +16634,9 @@ snapshots: cookie-signature@1.0.6: {} - cookie@0.7.1: {} + cookie@0.5.0: {} - cookie@0.7.2: {} + cookie@0.6.0: {} copy-anything@3.0.5: dependencies: @@ -14164,9 +16647,9 @@ snapshots: graceful-fs: 4.2.11 p-event: 6.0.1 - core-js-compat@3.39.0: + core-js-compat@3.37.1: dependencies: - browserslist: 4.24.2 + browserslist: 4.23.0 core-util-is@1.0.3: {} @@ -14186,7 +16669,7 @@ snapshots: cpu-features@0.0.10: dependencies: buildcheck: 0.0.6 - nan: 2.22.0 + nan: 2.19.0 optional: true cpy-cli@5.0.0: @@ -14200,7 +16683,7 @@ snapshots: cp-file: 10.0.0 globby: 13.2.2 junk: 4.0.1 - micromatch: 4.0.8 + micromatch: 4.0.7 nested-error-stacks: 2.1.1 p-filter: 3.0.0 p-map: 6.0.0 @@ -14218,7 +16701,7 @@ snapshots: cross-env@7.0.3: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 cross-fetch@3.1.8(encoding@0.1.13): dependencies: @@ -14234,7 +16717,7 @@ snapshots: shebang-command: 1.2.0 which: 1.3.1 - cross-spawn@7.0.5: + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -14252,10 +16735,10 @@ snapshots: dependencies: array-find-index: 1.0.2 - d@1.0.2: + d@1.0.1: dependencies: - es5-ext: 0.10.64 - type: 2.7.3 + es5-ext: 0.10.62 + type: 1.2.0 dag-map@1.0.2: {} @@ -14283,14 +16766,16 @@ snapshots: date-fns@2.30.0: dependencies: - '@babel/runtime': 7.26.0 + '@babel/runtime': 7.22.10 - date-fns@4.1.0: {} + date-fns@3.6.0: {} date-time@3.1.0: dependencies: time-zone: 1.0.0 + dayjs@1.11.11: {} + debug@2.6.9: dependencies: ms: 2.0.0 @@ -14303,17 +16788,23 @@ snapshots: dependencies: ms: 2.1.2 + debug@4.3.5: + dependencies: + ms: 2.1.2 + debug@4.3.7: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 - deep-eql@4.1.4: + deep-eql@4.1.3: dependencies: - type-detect: 4.1.0 + type-detect: 4.0.8 deep-eql@5.0.2: {} @@ -14321,6 +16812,8 @@ snapshots: deep-is@0.1.4: {} + deepmerge@4.3.1: {} + default-gateway@4.2.0: dependencies: execa: 1.0.0 @@ -14338,6 +16831,11 @@ snapshots: define-lazy-prop@2.0.0: {} + define-properties@1.2.0: + dependencies: + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -14382,7 +16880,7 @@ snapshots: diff@4.0.2: {} - diff@5.2.0: {} + diff@5.1.0: {} difflib@0.2.4: dependencies: @@ -14394,10 +16892,10 @@ snapshots: docker-modem@3.0.8: dependencies: - debug: 4.3.7 + debug: 4.3.4 readable-stream: 3.6.2 split-ca: 1.0.1 - ssh2: 1.16.0 + ssh2: 1.15.0 transitivePeerDependencies: - supports-color @@ -14406,7 +16904,7 @@ snapshots: debug: 4.3.7 readable-stream: 3.6.2 split-ca: 1.0.1 - ssh2: 1.16.0 + ssh2: 1.15.0 transitivePeerDependencies: - supports-color @@ -14459,54 +16957,54 @@ snapshots: drizzle-kit@0.19.13: dependencies: '@drizzle-team/studio': 0.0.5 - '@esbuild-kit/esm-loader': 2.6.5 + '@esbuild-kit/esm-loader': 2.5.5 camelcase: 7.0.1 chalk: 5.3.0 commander: 9.5.0 esbuild: 0.18.20 - esbuild-register: 3.6.0(esbuild@0.18.20) + esbuild-register: 3.5.0(esbuild@0.18.20) glob: 8.1.0 hanji: 0.0.5 json-diff: 0.9.0 minimatch: 7.4.6 - zod: 3.23.8 + zod: 3.23.7 transitivePeerDependencies: - supports-color drizzle-kit@0.25.0-b1faa33: dependencies: '@drizzle-team/brocli': 0.10.2 - '@esbuild-kit/esm-loader': 2.6.5 + '@esbuild-kit/esm-loader': 2.5.5 esbuild: 0.19.12 - esbuild-register: 3.6.0(esbuild@0.19.12) + esbuild-register: 3.5.0(esbuild@0.19.12) transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.687.0)(@cloudflare/workers-types@4.20241106.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.5)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.10)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.1.34)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.3.3)(pg@8.13.1)(postgres@3.4.5)(sql.js@1.12.0)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: - '@aws-sdk/client-rds-data': 3.687.0 - '@cloudflare/workers-types': 4.20241106.0 + '@aws-sdk/client-rds-data': 3.583.0 + '@cloudflare/workers-types': 4.20241004.0 '@libsql/client': 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - '@neondatabase/serverless': 0.9.5 - '@opentelemetry/api': 1.9.0 - '@planetscale/database': 1.19.0 - '@types/better-sqlite3': 7.6.11 - '@types/pg': 8.11.10 + '@neondatabase/serverless': 0.10.3 + '@opentelemetry/api': 1.8.0 + '@planetscale/database': 1.18.0 + '@types/better-sqlite3': 7.6.12 + '@types/pg': 8.11.6 '@types/sql.js': 1.4.9 '@vercel/postgres': 0.8.0 better-sqlite3: 11.5.0 - bun-types: 1.1.34 - knex: 2.5.1(better-sqlite3@11.5.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7) + bun-types: 1.0.3 + knex: 2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7) kysely: 0.25.0 - mysql2: 3.3.3 + mysql2: 3.11.0 pg: 8.13.1 - postgres: 3.4.5 - sql.js: 1.12.0 + postgres: 3.4.4 + sql.js: 1.10.3 sqlite3: 5.1.7 - drizzle-prisma-generator@0.1.7: + drizzle-prisma-generator@0.1.4: dependencies: - '@prisma/generator-helper': 5.22.0 + '@prisma/generator-helper': 5.16.1 duplexer@0.1.2: {} @@ -14514,7 +17012,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.55: {} + electron-to-chromium@1.4.783: {} emittery@1.0.3: {} @@ -14526,8 +17024,6 @@ snapshots: encodeurl@1.0.2: {} - encodeurl@2.0.0: {} - encoding@0.1.13: dependencies: iconv-lite: 0.6.3 @@ -14544,6 +17040,8 @@ snapshots: env-paths@3.0.0: {} + envinfo@7.13.0: {} + environment@1.1.0: {} eol@0.9.1: {} @@ -14559,6 +17057,53 @@ snapshots: dependencies: stackframe: 1.3.4 + errorhandler@1.5.1: + dependencies: + accepts: 1.3.8 + escape-html: 1.0.3 + + es-abstract@1.22.1: + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.1 + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + es-set-tostringtag: 2.0.1 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.5 + get-intrinsic: 1.2.1 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has: 1.0.3 + has-property-descriptors: 1.0.0 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.5 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.12 + is-weakref: 1.0.2 + object-inspect: 1.12.3 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.5.0 + safe-array-concat: 1.0.0 + safe-regex-test: 1.0.0 + string.prototype.trim: 1.2.7 + string.prototype.trimend: 1.0.6 + string.prototype.trimstart: 1.0.6 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.11 + es-abstract@1.23.3: dependencies: array-buffer-byte-length: 1.0.1 @@ -14592,10 +17137,10 @@ snapshots: is-string: 1.0.7 is-typed-array: 1.1.13 is-weakref: 1.0.2 - object-inspect: 1.13.2 + object-inspect: 1.13.1 object-keys: 1.1.1 object.assign: 4.1.5 - regexp.prototype.flags: 1.5.3 + regexp.prototype.flags: 1.5.2 safe-array-concat: 1.1.2 safe-regex-test: 1.0.3 string.prototype.trim: 1.2.9 @@ -14618,15 +17163,21 @@ snapshots: dependencies: es-errors: 1.3.0 + es-set-tostringtag@2.0.1: + dependencies: + get-intrinsic: 1.2.1 + has: 1.0.3 + has-tostringtag: 1.0.0 + es-set-tostringtag@2.0.3: dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 hasown: 2.0.2 - es-shim-unscopables@1.0.2: + es-shim-unscopables@1.0.0: dependencies: - hasown: 2.0.2 + has: 1.0.3 es-to-primitive@1.2.1: dependencies: @@ -14634,30 +17185,29 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 - es5-ext@0.10.64: + es5-ext@0.10.62: dependencies: es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esniff: 2.0.1 + es6-symbol: 3.1.3 next-tick: 1.1.0 es6-iterator@2.0.3: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-symbol: 3.1.4 + d: 1.0.1 + es5-ext: 0.10.62 + es6-symbol: 3.1.3 - es6-symbol@3.1.4: + es6-symbol@3.1.3: dependencies: - d: 1.0.2 + d: 1.0.1 ext: 1.7.0 es6-weak-map@2.0.3: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 + d: 1.0.1 + es5-ext: 0.10.62 es6-iterator: 2.0.3 - es6-symbol: 3.1.4 + es6-symbol: 3.1.3 esbuild-android-64@0.14.54: optional: true @@ -14704,25 +17254,25 @@ snapshots: esbuild-netbsd-64@0.14.54: optional: true - esbuild-node-externals@1.15.0(esbuild@0.19.12): + esbuild-node-externals@1.14.0(esbuild@0.19.12): dependencies: esbuild: 0.19.12 find-up: 5.0.0 - tslib: 2.8.1 + tslib: 2.6.2 esbuild-openbsd-64@0.14.54: optional: true - esbuild-register@3.6.0(esbuild@0.18.20): + esbuild-register@3.5.0(esbuild@0.18.20): dependencies: - debug: 4.3.7 + debug: 4.3.4 esbuild: 0.18.20 transitivePeerDependencies: - supports-color - esbuild-register@3.6.0(esbuild@0.19.12): + esbuild-register@3.5.0(esbuild@0.19.12): dependencies: - debug: 4.3.7 + debug: 4.3.4 esbuild: 0.19.12 transitivePeerDependencies: - supports-color @@ -14839,6 +17389,32 @@ snapshots: '@esbuild/win32-ia32': 0.19.12 '@esbuild/win32-x64': 0.19.12 + esbuild@0.20.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.20.2 + '@esbuild/android-arm': 0.20.2 + '@esbuild/android-arm64': 0.20.2 + '@esbuild/android-x64': 0.20.2 + '@esbuild/darwin-arm64': 0.20.2 + '@esbuild/darwin-x64': 0.20.2 + '@esbuild/freebsd-arm64': 0.20.2 + '@esbuild/freebsd-x64': 0.20.2 + '@esbuild/linux-arm': 0.20.2 + '@esbuild/linux-arm64': 0.20.2 + '@esbuild/linux-ia32': 0.20.2 + '@esbuild/linux-loong64': 0.20.2 + '@esbuild/linux-mips64el': 0.20.2 + '@esbuild/linux-ppc64': 0.20.2 + '@esbuild/linux-riscv64': 0.20.2 + '@esbuild/linux-s390x': 0.20.2 + '@esbuild/linux-x64': 0.20.2 + '@esbuild/netbsd-x64': 0.20.2 + '@esbuild/openbsd-x64': 0.20.2 + '@esbuild/sunos-x64': 0.20.2 + '@esbuild/win32-arm64': 0.20.2 + '@esbuild/win32-ia32': 0.20.2 + '@esbuild/win32-x64': 0.20.2 + esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -14865,61 +17441,36 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - esbuild@0.23.1: - optionalDependencies: - '@esbuild/aix-ppc64': 0.23.1 - '@esbuild/android-arm': 0.23.1 - '@esbuild/android-arm64': 0.23.1 - '@esbuild/android-x64': 0.23.1 - '@esbuild/darwin-arm64': 0.23.1 - '@esbuild/darwin-x64': 0.23.1 - '@esbuild/freebsd-arm64': 0.23.1 - '@esbuild/freebsd-x64': 0.23.1 - '@esbuild/linux-arm': 0.23.1 - '@esbuild/linux-arm64': 0.23.1 - '@esbuild/linux-ia32': 0.23.1 - '@esbuild/linux-loong64': 0.23.1 - '@esbuild/linux-mips64el': 0.23.1 - '@esbuild/linux-ppc64': 0.23.1 - '@esbuild/linux-riscv64': 0.23.1 - '@esbuild/linux-s390x': 0.23.1 - '@esbuild/linux-x64': 0.23.1 - '@esbuild/netbsd-x64': 0.23.1 - '@esbuild/openbsd-arm64': 0.23.1 - '@esbuild/openbsd-x64': 0.23.1 - '@esbuild/sunos-x64': 0.23.1 - '@esbuild/win32-arm64': 0.23.1 - '@esbuild/win32-ia32': 0.23.1 - '@esbuild/win32-x64': 0.23.1 - - esbuild@0.24.0: + esbuild@0.23.0: optionalDependencies: - '@esbuild/aix-ppc64': 0.24.0 - '@esbuild/android-arm': 0.24.0 - '@esbuild/android-arm64': 0.24.0 - '@esbuild/android-x64': 0.24.0 - '@esbuild/darwin-arm64': 0.24.0 - '@esbuild/darwin-x64': 0.24.0 - '@esbuild/freebsd-arm64': 0.24.0 - '@esbuild/freebsd-x64': 0.24.0 - '@esbuild/linux-arm': 0.24.0 - '@esbuild/linux-arm64': 0.24.0 - '@esbuild/linux-ia32': 0.24.0 - '@esbuild/linux-loong64': 0.24.0 - '@esbuild/linux-mips64el': 0.24.0 - '@esbuild/linux-ppc64': 0.24.0 - '@esbuild/linux-riscv64': 0.24.0 - '@esbuild/linux-s390x': 0.24.0 - '@esbuild/linux-x64': 0.24.0 - '@esbuild/netbsd-x64': 0.24.0 - '@esbuild/openbsd-arm64': 0.24.0 - '@esbuild/openbsd-x64': 0.24.0 - '@esbuild/sunos-x64': 0.24.0 - '@esbuild/win32-arm64': 0.24.0 - '@esbuild/win32-ia32': 0.24.0 - '@esbuild/win32-x64': 0.24.0 - - escalade@3.2.0: {} + '@esbuild/aix-ppc64': 0.23.0 + '@esbuild/android-arm': 0.23.0 + '@esbuild/android-arm64': 0.23.0 + '@esbuild/android-x64': 0.23.0 + '@esbuild/darwin-arm64': 0.23.0 + '@esbuild/darwin-x64': 0.23.0 + '@esbuild/freebsd-arm64': 0.23.0 + '@esbuild/freebsd-x64': 0.23.0 + '@esbuild/linux-arm': 0.23.0 + '@esbuild/linux-arm64': 0.23.0 + '@esbuild/linux-ia32': 0.23.0 + '@esbuild/linux-loong64': 0.23.0 + '@esbuild/linux-mips64el': 0.23.0 + '@esbuild/linux-ppc64': 0.23.0 + '@esbuild/linux-riscv64': 0.23.0 + '@esbuild/linux-s390x': 0.23.0 + '@esbuild/linux-x64': 0.23.0 + '@esbuild/netbsd-x64': 0.23.0 + '@esbuild/openbsd-arm64': 0.23.0 + '@esbuild/openbsd-x64': 0.23.0 + '@esbuild/sunos-x64': 0.23.0 + '@esbuild/win32-arm64': 0.23.0 + '@esbuild/win32-ia32': 0.23.0 + '@esbuild/win32-x64': 0.23.0 + + escalade@3.1.1: {} + + escalade@3.1.2: {} escape-html@1.0.3: {} @@ -14931,52 +17482,50 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-prettier@9.1.0(eslint@8.57.1): + eslint-config-prettier@9.1.0(eslint@8.57.0): dependencies: - eslint: 8.57.1 + eslint: 8.57.0 eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 - is-core-module: 2.15.1 - resolve: 1.22.8 + is-core-module: 2.13.0 + resolve: 1.22.4 transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - eslint: 8.57.1 + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1): + eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0): dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 + array-includes: 3.1.6 + array.prototype.findlastindex: 1.2.2 + array.prototype.flat: 1.3.1 + array.prototype.flatmap: 1.3.1 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.1 + eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) - hasown: 2.0.2 - is-core-module: 2.15.1 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) + has: 1.0.3 + is-core-module: 2.13.0 is-glob: 4.0.3 minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.0 + object.fromentries: 2.0.6 + object.groupby: 1.0.0 + object.values: 1.1.6 semver: 6.3.1 - string.prototype.trimend: 1.0.8 - tsconfig-paths: 3.15.0 + tsconfig-paths: 3.14.2 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -14984,23 +17533,23 @@ snapshots: eslint-plugin-no-instanceof@1.0.1: {} - eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8): + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8): dependencies: - eslint: 8.57.1 + eslint: 8.57.0 prettier: 2.8.8 prettier-linter-helpers: 1.0.0 - synckit: 0.9.2 + synckit: 0.9.1 optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@8.57.1) + eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-plugin-unicorn@48.0.1(eslint@8.57.1): + eslint-plugin-unicorn@48.0.1(eslint@8.50.0): dependencies: - '@babel/helper-validator-identifier': 7.25.9 - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - ci-info: 3.9.0 + '@babel/helper-validator-identifier': 7.22.5 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + ci-info: 3.8.0 clean-regexp: 1.0.0 - eslint: 8.57.1 - esquery: 1.6.0 + eslint: 8.50.0 + esquery: 1.5.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 jsesc: 3.0.2 @@ -15009,15 +17558,15 @@ snapshots: read-pkg-up: 7.0.1 regexp-tree: 0.1.27 regjsparser: 0.10.0 - semver: 7.6.3 + semver: 7.6.2 strip-indent: 3.0.0 - eslint-plugin-unused-imports@3.2.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1): + eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0): dependencies: - eslint: 8.57.1 + eslint: 8.50.0 eslint-rule-composer: 0.3.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3) eslint-rule-composer@0.3.0: {} @@ -15033,34 +17582,121 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint@8.57.1: + eslint-visitor-keys@4.0.0: {} + + eslint@8.50.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@eslint-community/regexpp': 4.9.0 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.50.0 + '@humanwhocodes/config-array': 0.11.11 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.22.0 + graphemer: 1.4.0 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + eslint@8.53.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) + '@eslint-community/regexpp': 4.9.0 + '@eslint/eslintrc': 2.1.3 + '@eslint/js': 8.53.0 + '@humanwhocodes/config-array': 0.11.13 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.22.0 + graphemer: 1.4.0 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + eslint@8.57.0: dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.1 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.9.0 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.5 - debug: 4.3.7 + cross-spawn: 7.0.3 + debug: 4.3.4 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.6.0 + esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.24.0 + globals: 13.22.0 graphemer: 1.4.0 - ignore: 5.3.2 + ignore: 5.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -15070,7 +17706,7 @@ snapshots: lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.4 + optionator: 0.9.3 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: @@ -15078,22 +17714,21 @@ snapshots: esm@3.2.25: {} - esniff@2.0.1: + espree@10.0.1: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-emitter: 0.3.5 - type: 2.7.3 + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) + eslint-visitor-keys: 4.0.0 espree@9.6.1: dependencies: - acorn: 8.14.0 - acorn-jsx: 5.3.2(acorn@8.14.0) + acorn: 8.10.0 + acorn-jsx: 5.3.2(acorn@8.10.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} - esquery@1.6.0: + esquery@1.5.0: dependencies: estraverse: 5.3.0 @@ -15111,7 +17746,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.5 esutils@2.0.3: {} @@ -15119,8 +17754,8 @@ snapshots: event-emitter@0.3.5: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 + d: 1.0.1 + es5-ext: 0.10.62 event-stream@3.3.4: dependencies: @@ -15148,7 +17783,7 @@ snapshots: execa@5.1.1: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -15160,7 +17795,7 @@ snapshots: execa@6.1.0: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 get-stream: 6.0.1 human-signals: 3.0.1 is-stream: 3.0.0 @@ -15172,7 +17807,7 @@ snapshots: execa@8.0.1: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 get-stream: 8.0.1 human-signals: 5.0.0 is-stream: 3.0.0 @@ -15188,72 +17823,68 @@ snapshots: expand-template@2.0.3: {} - expect-type@1.1.0: {} - - expo-asset@10.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-constants: 16.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + '@react-native/assets-registry': 0.74.83 + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - '@expo/config': 9.0.4 - '@expo/env': 0.3.0 - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@expo/config': 9.0.2 + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-font@12.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-modules-autolinking@1.11.3: + expo-modules-autolinking@1.11.1: dependencies: chalk: 4.1.2 commander: 7.2.0 fast-glob: 3.3.2 find-up: 5.0.0 fs-extra: 9.1.0 - require-from-string: 2.0.2 - resolve-from: 5.0.0 - expo-modules-core@1.12.26: + expo-modules-core@1.12.11: dependencies: invariant: 2.2.4 - expo-sqlite@14.0.6(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-sqlite@14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - - expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): - dependencies: - '@babel/runtime': 7.26.0 - '@expo/cli': 0.18.30(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.3)(utf-8-validate@6.0.3) - '@expo/config': 9.0.4 - '@expo/config-plugins': 8.0.10 - '@expo/metro-config': 0.18.11 - '@expo/vector-icons': 14.0.4 - babel-preset-expo: 11.0.15(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - expo-asset: 10.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-file-system: 17.0.1(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-font: 12.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-keep-awake: 13.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-modules-autolinking: 1.11.3 - expo-modules-core: 1.12.26 + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): + dependencies: + '@babel/runtime': 7.24.6 + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) + '@expo/config': 9.0.2 + '@expo/config-plugins': 8.0.4 + '@expo/metro-config': 0.18.4 + '@expo/vector-icons': 14.0.2 + babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-modules-autolinking: 1.11.1 + expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) whatwg-url-without-unicode: 8.0.0-3 transitivePeerDependencies: @@ -15264,36 +17895,34 @@ snapshots: - supports-color - utf-8-validate - exponential-backoff@3.1.1: {} - - express@4.21.1: + express@4.19.2: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.3 + body-parser: 1.20.2 content-disposition: 0.5.4 content-type: 1.0.5 - cookie: 0.7.1 + cookie: 0.6.0 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 - encodeurl: 2.0.0 + encodeurl: 1.0.2 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.3.1 + finalhandler: 1.2.0 fresh: 0.5.2 http-errors: 2.0.0 - merge-descriptors: 1.0.3 + merge-descriptors: 1.0.1 methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.10 + path-to-regexp: 0.1.7 proxy-addr: 2.0.7 - qs: 6.13.0 + qs: 6.11.0 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.19.0 - serve-static: 1.16.2 + send: 0.18.0 + serve-static: 1.15.0 setprototypeof: 1.2.0 statuses: 2.0.1 type-is: 1.6.18 @@ -15304,29 +17933,41 @@ snapshots: ext@1.7.0: dependencies: - type: 2.7.3 + type: 2.7.2 fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.7 + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.8 + micromatch: 4.0.7 fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} - fast-xml-parser@4.4.1: + fast-xml-parser@4.2.5: dependencies: strnum: 1.0.5 - fastq@1.17.1: + fast-xml-parser@4.4.0: + dependencies: + strnum: 1.0.5 + + fastq@1.15.0: dependencies: reusify: 1.0.4 @@ -15350,18 +17991,14 @@ snapshots: object-assign: 4.1.1 promise: 7.3.1 setimmediate: 1.0.5 - ua-parser-js: 1.0.39 + ua-parser-js: 1.0.38 transitivePeerDependencies: - encoding - fdir@6.4.2(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - fetch-blob@3.2.0: dependencies: node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 + web-streams-polyfill: 3.2.1 fetch-retry@4.1.1: {} @@ -15374,7 +18011,7 @@ snapshots: file-entry-cache@6.0.1: dependencies: - flat-cache: 3.2.0 + flat-cache: 3.1.0 file-uri-to-path@1.0.0: {} @@ -15394,10 +18031,10 @@ snapshots: transitivePeerDependencies: - supports-color - finalhandler@1.3.1: + finalhandler@1.2.0: dependencies: debug: 2.6.9 - encodeurl: 2.0.0 + encodeurl: 1.0.2 escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 @@ -15435,19 +18072,21 @@ snapshots: dependencies: micromatch: 4.0.8 - flat-cache@3.2.0: + flat-cache@3.1.0: dependencies: - flatted: 3.3.1 - keyv: 4.5.4 + flatted: 3.2.9 + keyv: 4.5.3 rimraf: 3.0.2 + flatted@3.2.9: {} + flatted@3.3.1: {} flow-enums-runtime@0.0.6: {} - flow-parser@0.252.0: {} + flow-parser@0.236.0: {} - follow-redirects@1.15.9: {} + follow-redirects@1.15.6: {} fontfaceobserver@2.3.0: {} @@ -15455,18 +18094,18 @@ snapshots: dependencies: is-callable: 1.2.7 - foreground-child@3.3.0: + foreground-child@3.1.1: dependencies: - cross-spawn: 7.0.5 - signal-exit: 4.1.0 + cross-spawn: 7.0.3 + signal-exit: 4.0.2 - form-data@3.0.2: + form-data@3.0.1: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - form-data@4.0.1: + form-data@4.0.0: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 @@ -15486,7 +18125,7 @@ snapshots: fs-constants@1.0.0: {} - fs-extra@11.2.0: + fs-extra@11.1.1: dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 @@ -15525,8 +18164,17 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.1: {} + function-bind@1.1.2: {} + function.prototype.name@1.1.5: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + functions-have-names: 1.2.3 + function.prototype.name@1.1.6: dependencies: call-bind: 1.0.7 @@ -15536,7 +18184,7 @@ snapshots: functions-have-names@1.2.3: {} - fx@35.0.0: {} + fx@28.0.0: {} gauge@4.0.4: dependencies: @@ -15560,6 +18208,13 @@ snapshots: get-func-name@2.0.2: {} + get-intrinsic@1.2.1: + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-proto: 1.0.1 + has-symbols: 1.0.3 + get-intrinsic@1.2.4: dependencies: es-errors: 1.3.0 @@ -15583,19 +18238,24 @@ snapshots: get-stream@4.1.0: dependencies: - pump: 3.0.2 + pump: 3.0.0 get-stream@6.0.1: {} get-stream@8.0.1: {} + get-symbol-description@1.0.0: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + get-symbol-description@1.0.2: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 - get-tsconfig@4.8.1: + get-tsconfig@4.7.5: dependencies: resolve-pkg-maps: 1.0.0 @@ -15615,15 +18275,31 @@ snapshots: glob-to-regexp@0.4.1: {} - glob@10.4.5: + glob@10.3.10: + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.4 + minipass: 5.0.0 + path-scurry: 1.10.1 + + glob@10.4.1: dependencies: - foreground-child: 3.3.0 - jackspeak: 3.4.3 - minimatch: 9.0.5 + foreground-child: 3.1.1 + jackspeak: 3.1.2 + minimatch: 9.0.4 minipass: 7.1.2 - package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@6.0.4: + dependencies: + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + optional: true + glob@7.1.6: dependencies: fs.realpath: 1.0.0 @@ -15652,10 +18328,16 @@ snapshots: globals@11.12.0: {} - globals@13.24.0: + globals@13.22.0: dependencies: type-fest: 0.20.2 + globals@14.0.0: {} + + globalthis@1.0.3: + dependencies: + define-properties: 1.2.0 + globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -15665,8 +18347,8 @@ snapshots: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.2 + fast-glob: 3.3.1 + ignore: 5.3.1 merge2: 1.4.1 slash: 3.0.0 @@ -15674,7 +18356,7 @@ snapshots: dependencies: dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.2 + ignore: 5.3.1 merge2: 1.4.1 slash: 4.0.0 @@ -15682,7 +18364,7 @@ snapshots: dependencies: '@sindresorhus/merge-streams': 2.3.0 fast-glob: 3.3.2 - ignore: 5.3.2 + ignore: 5.3.1 path-type: 5.0.0 slash: 5.1.0 unicorn-magic: 0.1.0 @@ -15691,7 +18373,7 @@ snapshots: gopd@1.0.1: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.1 graceful-fs@4.2.11: {} @@ -15715,14 +18397,24 @@ snapshots: has-flag@4.0.0: {} + has-property-descriptors@1.0.0: + dependencies: + get-intrinsic: 1.2.1 + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.0 + has-proto@1.0.1: {} + has-proto@1.0.3: {} has-symbols@1.0.3: {} + has-tostringtag@1.0.0: + dependencies: + has-symbols: 1.0.3 + has-tostringtag@1.0.2: dependencies: has-symbols: 1.0.3 @@ -15730,6 +18422,10 @@ snapshots: has-unicode@2.0.1: optional: true + has@1.0.3: + dependencies: + function-bind: 1.1.1 + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -15738,25 +18434,25 @@ snapshots: hermes-estree@0.19.1: {} - hermes-estree@0.23.1: {} - - hermes-estree@0.24.0: {} + hermes-estree@0.20.1: {} hermes-parser@0.19.1: dependencies: hermes-estree: 0.19.1 - hermes-parser@0.23.1: + hermes-parser@0.20.1: dependencies: - hermes-estree: 0.23.1 + hermes-estree: 0.20.1 - hermes-parser@0.24.0: + hermes-profile-transformer@0.0.6: dependencies: - hermes-estree: 0.24.0 + source-map: 0.7.4 highlight.js@10.7.3: {} - hono@4.6.9: {} + hono@4.0.1: {} + + hono@4.5.0: {} hosted-git-info@2.8.9: {} @@ -15779,7 +18475,7 @@ snapshots: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.3.4 transitivePeerDependencies: - supports-color optional: true @@ -15787,7 +18483,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.3.4 transitivePeerDependencies: - supports-color @@ -15814,7 +18510,9 @@ snapshots: ignore-by-default@2.1.0: {} - ignore@5.3.2: {} + ignore@5.2.4: {} + + ignore@5.3.1: {} image-size@1.1.1: dependencies: @@ -15855,6 +18553,12 @@ snapshots: default-gateway: 4.2.0 ipaddr.js: 1.9.1 + internal-slot@1.0.5: + dependencies: + get-intrinsic: 1.2.1 + has: 1.0.3 + side-channel: 1.0.4 + internal-slot@1.0.7: dependencies: es-errors: 1.3.0 @@ -15879,6 +18583,12 @@ snapshots: irregular-plurals@3.5.0: {} + is-array-buffer@3.0.2: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-typed-array: 1.1.12 + is-array-buffer@3.0.4: dependencies: call-bind: 1.0.7 @@ -15892,12 +18602,12 @@ snapshots: is-binary-path@2.1.0: dependencies: - binary-extensions: 2.3.0 + binary-extensions: 2.2.0 is-boolean-object@1.1.2: dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 + call-bind: 1.0.2 + has-tostringtag: 1.0.0 is-buffer@1.1.6: {} @@ -15907,7 +18617,19 @@ snapshots: is-callable@1.2.7: {} - is-core-module@2.15.1: + is-core-module@2.11.0: + dependencies: + has: 1.0.3 + + is-core-module@2.12.1: + dependencies: + has: 1.0.3 + + is-core-module@2.13.0: + dependencies: + has: 1.0.3 + + is-core-module@2.13.1: dependencies: hasown: 2.0.2 @@ -15917,7 +18639,7 @@ snapshots: is-date-object@1.0.5: dependencies: - has-tostringtag: 1.0.2 + has-tostringtag: 1.0.0 is-directory@0.3.1: {} @@ -15929,6 +18651,8 @@ snapshots: is-extglob@2.1.1: {} + is-fullwidth-code-point@2.0.0: {} + is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@4.0.0: {} @@ -15941,6 +18665,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-interactive@1.0.0: {} + is-invalid-path@0.1.0: dependencies: is-glob: 2.0.1 @@ -15948,11 +18674,13 @@ snapshots: is-lambda@1.0.1: optional: true + is-negative-zero@2.0.2: {} + is-negative-zero@2.0.3: {} is-number-object@1.0.7: dependencies: - has-tostringtag: 1.0.2 + has-tostringtag: 1.0.0 is-number@7.0.0: {} @@ -15974,8 +18702,12 @@ snapshots: is-regex@1.1.4: dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + + is-shared-array-buffer@1.0.2: + dependencies: + call-bind: 1.0.2 is-shared-array-buffer@1.0.3: dependencies: @@ -15989,16 +18721,22 @@ snapshots: is-string@1.0.7: dependencies: - has-tostringtag: 1.0.2 + has-tostringtag: 1.0.0 is-symbol@1.0.4: dependencies: has-symbols: 1.0.3 + is-typed-array@1.1.12: + dependencies: + which-typed-array: 1.1.11 + is-typed-array@1.1.13: dependencies: which-typed-array: 1.1.15 + is-unicode-supported@0.1.0: {} + is-unicode-supported@1.3.0: {} is-valid-path@0.1.1: @@ -16007,10 +18745,12 @@ snapshots: is-weakref@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.2 is-what@4.1.16: {} + is-wsl@1.1.0: {} + is-wsl@2.2.0: dependencies: is-docker: 2.2.1 @@ -16023,21 +18763,13 @@ snapshots: isobject@3.0.1: {} - istanbul-lib-coverage@3.2.2: {} - - istanbul-lib-instrument@5.2.1: + jackspeak@2.3.6: dependencies: - '@babel/core': 7.26.0 - '@babel/parser': 7.26.2 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - itty-time@1.0.6: {} + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 - jackspeak@3.4.3: + jackspeak@3.1.2: dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: @@ -16050,31 +18782,15 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.6 + '@types/node': 20.12.12 jest-mock: 29.7.0 jest-util: 29.7.0 jest-get-type@29.6.3: {} - jest-haste-map@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.9 - '@types/node': 20.17.6 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.11 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 - micromatch: 4.0.8 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 - jest-message-util@29.7.0: dependencies: - '@babel/code-frame': 7.26.2 + '@babel/code-frame': 7.24.6 '@jest/types': 29.6.3 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -16087,15 +18803,13 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.6 + '@types/node': 20.12.12 jest-util: 29.7.0 - jest-regex-util@29.6.3: {} - jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.6 + '@types/node': 20.12.12 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -16112,16 +18826,24 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 20.17.6 + '@types/node': 20.12.12 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 jimp-compact@0.16.1: {} + joi@17.13.1: + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + join-component@1.1.0: {} - jose@4.15.9: {} + jose@4.15.5: {} jose@5.2.3: {} @@ -16151,21 +18873,21 @@ snapshots: jsc-safe-url@0.2.4: {} - jscodeshift@0.14.0(@babel/preset-env@7.26.0(@babel/core@7.26.0)): - dependencies: - '@babel/core': 7.26.0 - '@babel/parser': 7.26.2 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/preset-env': 7.26.0(@babel/core@7.26.0) - '@babel/preset-flow': 7.25.9(@babel/core@7.26.0) - '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) - '@babel/register': 7.25.9(@babel/core@7.26.0) - babel-core: 7.0.0-bridge.0(@babel/core@7.26.0) + jscodeshift@0.14.0(@babel/preset-env@7.24.6(@babel/core@7.24.6)): + dependencies: + '@babel/core': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.6) + '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) + '@babel/preset-env': 7.24.6(@babel/core@7.24.6) + '@babel/preset-flow': 7.24.6(@babel/core@7.24.6) + '@babel/preset-typescript': 7.24.6(@babel/core@7.24.6) + '@babel/register': 7.24.6(@babel/core@7.24.6) + babel-core: 7.0.0-bridge.0(@babel/core@7.24.6) chalk: 4.1.2 - flow-parser: 0.252.0 + flow-parser: 0.236.0 graceful-fs: 4.2.11 micromatch: 4.0.8 neo-async: 2.6.2 @@ -16186,7 +18908,7 @@ snapshots: json-diff@0.9.0: dependencies: - cli-color: 2.0.4 + cli-color: 2.0.3 difflib: 0.2.4 dreamopt: 0.8.0 @@ -16208,7 +18930,7 @@ snapshots: lodash: 4.17.21 md5: 2.2.1 memory-cache: 0.2.0 - traverse: 0.6.10 + traverse: 0.6.9 valid-url: 1.0.9 json-schema-traverse@0.4.1: {} @@ -16227,7 +18949,7 @@ snapshots: jsonfile@6.1.0: dependencies: - universalify: 2.0.1 + universalify: 2.0.0 optionalDependencies: graceful-fs: 4.2.11 @@ -16240,7 +18962,7 @@ snapshots: junk@4.0.1: {} - keyv@4.5.4: + keyv@4.5.3: dependencies: json-buffer: 3.0.1 @@ -16250,12 +18972,12 @@ snapshots: kleur@4.1.5: {} - knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7): + knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7): dependencies: colorette: 2.0.19 commander: 10.0.1 debug: 4.3.4 - escalade: 3.2.0 + escalade: 3.1.2 esm: 3.2.25 get-package-type: 0.1.0 getopts: 2.3.0 @@ -16268,19 +18990,19 @@ snapshots: tildify: 2.0.0 optionalDependencies: better-sqlite3: 11.5.0 - mysql2: 3.3.3 + mysql2: 3.11.0 pg: 8.13.1 sqlite3: 5.1.7 transitivePeerDependencies: - supports-color optional: true - knex@2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7): + knex@2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7): dependencies: colorette: 2.0.19 commander: 10.0.1 debug: 4.3.4 - escalade: 3.2.0 + escalade: 3.1.2 esm: 3.2.25 get-package-type: 0.1.0 getopts: 2.3.0 @@ -16294,7 +19016,7 @@ snapshots: optionalDependencies: better-sqlite3: 8.7.0 mysql2: 3.3.3 - pg: 8.13.1 + pg: 8.11.5 sqlite3: 5.1.7 transitivePeerDependencies: - supports-color @@ -16308,18 +19030,32 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - libsql@0.4.7: + libsql@0.3.19: + dependencies: + '@neon-rs/load': 0.0.4 + detect-libc: 2.0.2 + optionalDependencies: + '@libsql/darwin-arm64': 0.3.19 + '@libsql/darwin-x64': 0.3.19 + '@libsql/linux-arm64-gnu': 0.3.19 + '@libsql/linux-arm64-musl': 0.3.19 + '@libsql/linux-x64-gnu': 0.3.19 + '@libsql/linux-x64-musl': 0.3.19 + '@libsql/win32-x64-msvc': 0.3.19 + + libsql@0.4.1: dependencies: '@neon-rs/load': 0.0.4 detect-libc: 2.0.2 + libsql: 0.3.19 optionalDependencies: - '@libsql/darwin-arm64': 0.4.7 - '@libsql/darwin-x64': 0.4.7 - '@libsql/linux-arm64-gnu': 0.4.7 - '@libsql/linux-arm64-musl': 0.4.7 - '@libsql/linux-x64-gnu': 0.4.7 - '@libsql/linux-x64-musl': 0.4.7 - '@libsql/win32-x64-msvc': 0.4.7 + '@libsql/darwin-arm64': 0.4.1 + '@libsql/darwin-x64': 0.4.1 + '@libsql/linux-arm64-gnu': 0.4.1 + '@libsql/linux-arm64-musl': 0.4.1 + '@libsql/linux-x64-gnu': 0.4.1 + '@libsql/linux-x64-musl': 0.4.1 + '@libsql/win32-x64-msvc': 0.4.1 lighthouse-logger@1.4.2: dependencies: @@ -16331,27 +19067,54 @@ snapshots: lightningcss-darwin-arm64@1.19.0: optional: true + lightningcss-darwin-arm64@1.25.1: + optional: true + lightningcss-darwin-x64@1.19.0: optional: true + lightningcss-darwin-x64@1.25.1: + optional: true + + lightningcss-freebsd-x64@1.25.1: + optional: true + lightningcss-linux-arm-gnueabihf@1.19.0: optional: true + lightningcss-linux-arm-gnueabihf@1.25.1: + optional: true + lightningcss-linux-arm64-gnu@1.19.0: optional: true + lightningcss-linux-arm64-gnu@1.25.1: + optional: true + lightningcss-linux-arm64-musl@1.19.0: optional: true + lightningcss-linux-arm64-musl@1.25.1: + optional: true + lightningcss-linux-x64-gnu@1.19.0: optional: true + lightningcss-linux-x64-gnu@1.25.1: + optional: true + lightningcss-linux-x64-musl@1.19.0: optional: true + lightningcss-linux-x64-musl@1.25.1: + optional: true + lightningcss-win32-x64-msvc@1.19.0: optional: true + lightningcss-win32-x64-msvc@1.25.1: + optional: true + lightningcss@1.19.0: dependencies: detect-libc: 1.0.3 @@ -16365,6 +19128,23 @@ snapshots: lightningcss-linux-x64-musl: 1.19.0 lightningcss-win32-x64-msvc: 1.19.0 + lightningcss@1.25.1: + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.25.1 + lightningcss-darwin-x64: 1.25.1 + lightningcss-freebsd-x64: 1.25.1 + lightningcss-linux-arm-gnueabihf: 1.25.1 + lightningcss-linux-arm64-gnu: 1.25.1 + lightningcss-linux-arm64-musl: 1.25.1 + lightningcss-linux-x64-gnu: 1.25.1 + lightningcss-linux-x64-musl: 1.25.1 + lightningcss-win32-x64-msvc: 1.25.1 + optional: true + + lilconfig@2.1.0: {} + lilconfig@3.1.2: {} lines-and-columns@1.2.4: {} @@ -16375,8 +19155,8 @@ snapshots: local-pkg@0.5.0: dependencies: - mlly: 1.7.2 - pkg-types: 1.2.1 + mlly: 1.7.0 + pkg-types: 1.1.0 locate-path@3.0.0: dependencies: @@ -16409,6 +19189,17 @@ snapshots: dependencies: chalk: 2.4.2 + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + logkitty@0.7.1: + dependencies: + ansi-fragments: 0.2.1 + dayjs: 1.11.11 + yargs: 15.4.1 + long@5.2.3: {} loose-envify@1.4.0: @@ -16421,6 +19212,8 @@ snapshots: loupe@3.1.2: {} + lru-cache@10.2.2: {} + lru-cache@10.4.3: {} lru-cache@5.1.1: @@ -16435,15 +19228,21 @@ snapshots: lru-cache@8.0.5: {} + lru-cache@9.1.2: {} + lru-queue@0.1.0: dependencies: - es5-ext: 0.10.64 + es5-ext: 0.10.62 magic-string@0.25.9: dependencies: sourcemap-codec: 1.4.8 - magic-string@0.30.12: + magic-string@0.30.10: + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + + magic-string@0.30.11: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -16468,7 +19267,7 @@ snapshots: minipass-fetch: 1.4.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 - negotiator: 0.6.4 + negotiator: 0.6.3 promise-retry: 2.0.1 socks-proxy-agent: 6.2.1 ssri: 8.0.1 @@ -16489,13 +19288,13 @@ snapshots: marked-terminal@6.2.0(marked@9.1.6): dependencies: - ansi-escapes: 6.2.1 + ansi-escapes: 6.2.0 cardinal: 2.1.1 chalk: 5.3.0 - cli-table3: 0.6.5 + cli-table3: 0.6.3 marked: 9.1.6 node-emoji: 2.1.3 - supports-hyperlinks: 3.1.0 + supports-hyperlinks: 3.0.0 marked-terminal@7.2.1(marked@9.1.6): dependencies: @@ -16547,22 +19346,22 @@ snapshots: memoize-one@5.2.1: {} - memoizee@0.4.17: + memoizee@0.4.15: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 + d: 1.0.1 + es5-ext: 0.10.62 es6-weak-map: 2.0.3 event-emitter: 0.3.5 is-promise: 2.2.2 lru-queue: 0.1.0 next-tick: 1.1.0 - timers-ext: 0.1.8 + timers-ext: 0.1.7 memory-cache@0.2.0: {} meow@12.1.1: {} - merge-descriptors@1.0.3: {} + merge-descriptors@1.0.1: {} merge-stream@2.0.0: {} @@ -16570,52 +19369,46 @@ snapshots: methods@1.1.2: {} - metro-babel-transformer@0.81.0: + metro-babel-transformer@0.80.9: dependencies: - '@babel/core': 7.26.0 - flow-enums-runtime: 0.0.6 - hermes-parser: 0.24.0 + '@babel/core': 7.24.6 + hermes-parser: 0.20.1 nullthrows: 1.1.1 transitivePeerDependencies: - supports-color - metro-cache-key@0.81.0: - dependencies: - flow-enums-runtime: 0.0.6 + metro-cache-key@0.80.9: {} - metro-cache@0.81.0: + metro-cache@0.80.9: dependencies: - exponential-backoff: 3.1.1 - flow-enums-runtime: 0.0.6 - metro-core: 0.81.0 + metro-core: 0.80.9 + rimraf: 3.0.2 - metro-config@0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 - flow-enums-runtime: 0.0.6 jest-validate: 29.7.0 - metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - metro-cache: 0.81.0 - metro-core: 0.81.0 - metro-runtime: 0.81.0 + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-cache: 0.80.9 + metro-core: 0.80.9 + metro-runtime: 0.80.9 transitivePeerDependencies: - bufferutil + - encoding - supports-color - utf-8-validate - metro-core@0.81.0: + metro-core@0.80.9: dependencies: - flow-enums-runtime: 0.0.6 lodash.throttle: 4.1.1 - metro-resolver: 0.81.0 + metro-resolver: 0.80.9 - metro-file-map@0.81.0: + metro-file-map@0.80.9: dependencies: anymatch: 3.1.3 debug: 2.6.9 fb-watchman: 2.0.2 - flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 invariant: 2.2.4 jest-worker: 29.7.0 @@ -16628,40 +19421,33 @@ snapshots: transitivePeerDependencies: - supports-color - metro-minify-terser@0.81.0: + metro-minify-terser@0.80.9: dependencies: - flow-enums-runtime: 0.0.6 - terser: 5.36.0 + terser: 5.31.0 - metro-resolver@0.81.0: - dependencies: - flow-enums-runtime: 0.0.6 + metro-resolver@0.80.9: {} - metro-runtime@0.81.0: + metro-runtime@0.80.9: dependencies: - '@babel/runtime': 7.26.0 - flow-enums-runtime: 0.0.6 + '@babel/runtime': 7.24.6 - metro-source-map@0.81.0: + metro-source-map@0.80.9: dependencies: - '@babel/traverse': 7.25.9 - '@babel/traverse--for-generate-function-map': '@babel/traverse@7.25.9' - '@babel/types': 7.26.0 - flow-enums-runtime: 0.0.6 + '@babel/traverse': 7.24.6 + '@babel/types': 7.24.6 invariant: 2.2.4 - metro-symbolicate: 0.81.0 + metro-symbolicate: 0.80.9 nullthrows: 1.1.1 - ob1: 0.81.0 + ob1: 0.80.9 source-map: 0.5.7 vlq: 1.0.1 transitivePeerDependencies: - supports-color - metro-symbolicate@0.81.0: + metro-symbolicate@0.80.9: dependencies: - flow-enums-runtime: 0.0.6 invariant: 2.2.4 - metro-source-map: 0.81.0 + metro-source-map: 0.80.9 nullthrows: 1.1.1 source-map: 0.5.7 through2: 2.0.5 @@ -16669,46 +19455,45 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-plugins@0.81.0: + metro-transform-plugins@0.80.9: dependencies: - '@babel/core': 7.26.0 - '@babel/generator': 7.26.2 - '@babel/template': 7.25.9 - '@babel/traverse': 7.25.9 - flow-enums-runtime: 0.0.6 + '@babel/core': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/template': 7.24.6 + '@babel/traverse': 7.24.6 nullthrows: 1.1.1 transitivePeerDependencies: - supports-color - metro-transform-worker@0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): - dependencies: - '@babel/core': 7.26.0 - '@babel/generator': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - flow-enums-runtime: 0.0.6 - metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - metro-babel-transformer: 0.81.0 - metro-cache: 0.81.0 - metro-cache-key: 0.81.0 - metro-minify-terser: 0.81.0 - metro-source-map: 0.81.0 - metro-transform-plugins: 0.81.0 + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + dependencies: + '@babel/core': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-babel-transformer: 0.80.9 + metro-cache: 0.80.9 + metro-cache-key: 0.80.9 + metro-minify-terser: 0.80.9 + metro-source-map: 0.80.9 + metro-transform-plugins: 0.80.9 nullthrows: 1.1.1 transitivePeerDependencies: - bufferutil + - encoding - supports-color - utf-8-validate - metro@0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: - '@babel/code-frame': 7.26.2 - '@babel/core': 7.26.0 - '@babel/generator': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/template': 7.25.9 - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 + '@babel/code-frame': 7.24.6 + '@babel/core': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/template': 7.24.6 + '@babel/traverse': 7.24.6 + '@babel/types': 7.24.6 accepts: 1.3.8 chalk: 4.1.2 ci-info: 2.0.0 @@ -16716,39 +19501,46 @@ snapshots: debug: 2.6.9 denodeify: 1.2.1 error-stack-parser: 2.1.4 - flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 - hermes-parser: 0.24.0 + hermes-parser: 0.20.1 image-size: 1.1.1 invariant: 2.2.4 jest-worker: 29.7.0 jsc-safe-url: 0.2.4 lodash.throttle: 4.1.1 - metro-babel-transformer: 0.81.0 - metro-cache: 0.81.0 - metro-cache-key: 0.81.0 - metro-config: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - metro-core: 0.81.0 - metro-file-map: 0.81.0 - metro-resolver: 0.81.0 - metro-runtime: 0.81.0 - metro-source-map: 0.81.0 - metro-symbolicate: 0.81.0 - metro-transform-plugins: 0.81.0 - metro-transform-worker: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + metro-babel-transformer: 0.80.9 + metro-cache: 0.80.9 + metro-cache-key: 0.80.9 + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-core: 0.80.9 + metro-file-map: 0.80.9 + metro-resolver: 0.80.9 + metro-runtime: 0.80.9 + metro-source-map: 0.80.9 + metro-symbolicate: 0.80.9 + metro-transform-plugins: 0.80.9 + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) mime-types: 2.1.35 + node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 + rimraf: 3.0.2 serialize-error: 2.1.0 source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) yargs: 17.7.2 transitivePeerDependencies: - bufferutil + - encoding - supports-color - utf-8-validate + micromatch@4.0.7: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -16762,6 +19554,8 @@ snapshots: mime@1.6.0: {} + mime@2.6.0: {} + mime@3.0.0: {} mimic-fn@1.2.0: {} @@ -16774,20 +19568,20 @@ snapshots: min-indent@1.0.1: {} - miniflare@3.20241022.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + miniflare@3.20240712.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: '@cspotcode/source-map-support': 0.8.1 - acorn: 8.14.0 - acorn-walk: 8.3.4 + acorn: 8.11.3 + acorn-walk: 8.3.2 capnp-ts: 0.7.0 exit-hook: 2.2.1 glob-to-regexp: 0.4.1 stoppable: 1.1.0 undici: 5.28.4 - workerd: 1.20241022.0 + workerd: 1.20240712.0 ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - youch: 3.3.4 - zod: 3.23.8 + youch: 3.3.3 + zod: 3.23.7 transitivePeerDependencies: - bufferutil - supports-color @@ -16805,11 +19599,7 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimatch@9.0.3: - dependencies: - brace-expansion: 2.0.1 - - minimatch@9.0.5: + minimatch@9.0.4: dependencies: brace-expansion: 2.0.1 @@ -16867,12 +19657,12 @@ snapshots: mkdirp@1.0.4: {} - mlly@1.7.2: + mlly@1.7.0: dependencies: - acorn: 8.14.0 + acorn: 8.11.3 pathe: 1.1.2 - pkg-types: 1.2.1 - ufo: 1.5.4 + pkg-types: 1.1.0 + ufo: 1.5.3 mri@1.2.0: {} @@ -16886,6 +19676,26 @@ snapshots: mustache@4.2.0: {} + mv@2.1.1: + dependencies: + mkdirp: 0.5.6 + ncp: 2.0.0 + rimraf: 2.4.5 + optional: true + + mysql2@3.11.0: + dependencies: + aws-ssl-profiles: 1.1.1 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.6.3 + long: 5.2.3 + lru-cache: 8.0.5 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + optional: true + mysql2@3.3.3: dependencies: denque: 2.1.0 @@ -16907,7 +19717,7 @@ snapshots: dependencies: lru-cache: 7.18.3 - nan@2.22.0: + nan@2.19.0: optional: true nanoid@3.3.7: {} @@ -16916,11 +19726,11 @@ snapshots: natural-compare@1.4.0: {} - negotiator@0.6.3: {} - - negotiator@0.6.4: + ncp@2.0.0: optional: true + negotiator@0.6.3: {} + neo-async@2.6.2: {} nested-error-stacks@2.0.1: {} @@ -16931,13 +19741,15 @@ snapshots: nice-try@1.0.5: {} - node-abi@3.71.0: + nocache@3.0.4: {} + + node-abi@3.62.0: dependencies: - semver: 7.6.3 + semver: 7.6.2 node-abort-controller@3.1.1: {} - node-addon-api@7.1.1: {} + node-addon-api@7.1.0: {} node-dir@0.1.17: dependencies: @@ -16952,6 +19764,8 @@ snapshots: emojilib: 2.4.0 skin-tone: 2.0.0 + node-fetch-native@1.6.4: {} + node-fetch@2.7.0(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 @@ -16972,7 +19786,7 @@ snapshots: node-forge@1.3.1: {} - node-gyp-build@4.8.2: {} + node-gyp-build@4.8.1: {} node-gyp@8.4.1: dependencies: @@ -16983,7 +19797,7 @@ snapshots: nopt: 5.0.0 npmlog: 6.0.2 rimraf: 3.0.2 - semver: 7.6.3 + semver: 7.6.2 tar: 6.2.1 which: 2.0.2 transitivePeerDependencies: @@ -16993,7 +19807,9 @@ snapshots: node-int64@0.4.0: {} - node-releases@2.0.18: {} + node-releases@2.0.14: {} + + node-stream-zip@1.15.0: {} nofilter@3.1.0: {} @@ -17044,23 +19860,30 @@ snapshots: dependencies: execa: 6.1.0 parse-package-name: 1.0.0 - semver: 7.6.3 + semver: 7.6.2 validate-npm-package-name: 4.0.0 nullthrows@1.1.1: {} - ob1@0.81.0: - dependencies: - flow-enums-runtime: 0.0.6 + ob1@0.80.9: {} object-assign@4.1.1: {} object-hash@2.2.0: {} - object-inspect@1.13.2: {} + object-inspect@1.12.3: {} + + object-inspect@1.13.1: {} object-keys@1.1.1: {} + object.assign@4.1.4: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + has-symbols: 1.0.3 + object-keys: 1.1.1 + object.assign@4.1.5: dependencies: call-bind: 1.0.7 @@ -17068,29 +19891,27 @@ snapshots: has-symbols: 1.0.3 object-keys: 1.1.1 - object.fromentries@2.0.8: + object.fromentries@2.0.6: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 - object.groupby@1.0.3: + object.groupby@1.0.0: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + get-intrinsic: 1.2.1 - object.values@1.2.0: + object.values@1.1.6: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 obuf@1.1.2: {} - ohash@1.1.4: {} - ohm-js@17.1.0: {} oidc-token-hash@5.0.3: {} @@ -17103,6 +19924,8 @@ snapshots: dependencies: ee-first: 1.1.1 + on-headers@1.0.2: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -17119,6 +19942,10 @@ snapshots: dependencies: mimic-fn: 4.0.0 + open@6.4.0: + dependencies: + is-wsl: 1.1.0 + open@7.4.2: dependencies: is-docker: 2.2.1 @@ -17132,19 +19959,19 @@ snapshots: openid-client@5.6.4: dependencies: - jose: 4.15.9 + jose: 4.15.5 lru-cache: 6.0.0 object-hash: 2.2.0 oidc-token-hash: 5.0.3 - optionator@0.9.4: + optionator@0.9.3: dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 - word-wrap: 1.2.5 ora@3.4.0: dependencies: @@ -17155,6 +19982,18 @@ snapshots: strip-ansi: 5.2.0 wcwidth: 1.0.1 + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + os-homedir@1.0.2: {} os-tmpdir@1.0.2: {} @@ -17194,11 +20033,11 @@ snapshots: p-limit@4.0.0: dependencies: - yocto-queue: 1.1.1 + yocto-queue: 1.0.0 p-limit@5.0.0: dependencies: - yocto-queue: 1.1.1 + yocto-queue: 1.0.0 p-locate@3.0.0: dependencies: @@ -17234,8 +20073,6 @@ snapshots: p-try@2.2.0: {} - package-json-from-dist@1.0.1: {} - parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -17247,7 +20084,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.26.2 + '@babel/code-frame': 7.22.13 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -17273,7 +20110,7 @@ snapshots: password-prompt@1.1.3: dependencies: ansi-escapes: 4.3.2 - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 path-exists@3.0.0: {} @@ -17291,14 +20128,19 @@ snapshots: path-parse@1.0.7: {} + path-scurry@1.10.1: + dependencies: + lru-cache: 9.1.2 + minipass: 5.0.0 + path-scurry@1.11.1: dependencies: - lru-cache: 10.4.3 + lru-cache: 10.2.2 minipass: 7.1.2 - path-to-regexp@0.1.10: {} + path-to-regexp@0.1.7: {} - path-to-regexp@6.3.0: {} + path-to-regexp@6.2.2: {} path-type@4.0.0: {} @@ -17319,16 +20161,24 @@ snapshots: pg-connection-string@2.6.1: {} + pg-connection-string@2.6.4: {} + pg-connection-string@2.7.0: {} pg-int8@1.0.1: {} pg-numeric@1.0.2: {} + pg-pool@3.6.2(pg@8.11.5): + dependencies: + pg: 8.11.5 + pg-pool@3.7.0(pg@8.13.1): dependencies: pg: 8.13.1 + pg-protocol@1.6.1: {} + pg-protocol@1.7.0: {} pg-types@2.2.0: @@ -17349,6 +20199,16 @@ snapshots: postgres-interval: 3.0.0 postgres-range: 1.1.4 + pg@8.11.5: + dependencies: + pg-connection-string: 2.6.4 + pg-pool: 3.6.2(pg@8.11.5) + pg-protocol: 1.6.1 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + pg@8.13.1: dependencies: pg-connection-string: 2.7.0 @@ -17363,7 +20223,9 @@ snapshots: dependencies: split2: 4.2.0 - picocolors@1.1.1: {} + picocolors@1.0.0: {} + + picocolors@1.0.1: {} picomatch@2.3.1: {} @@ -17384,10 +20246,10 @@ snapshots: dependencies: find-up: 3.0.0 - pkg-types@1.2.1: + pkg-types@1.1.0: dependencies: - confbox: 0.1.8 - mlly: 1.7.2 + confbox: 0.1.7 + mlly: 1.7.0 pathe: 1.1.2 plist@3.1.0: @@ -17406,27 +20268,33 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3)): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)): dependencies: - lilconfig: 3.1.2 - yaml: 2.6.0 + lilconfig: 2.1.0 + yaml: 2.3.1 optionalDependencies: - postcss: 8.4.47 - ts-node: 10.9.2(@types/node@22.9.0)(typescript@5.6.3) + postcss: 8.4.39 + ts-node: 10.9.2(@types/node@20.12.12)(typescript@5.6.3) - postcss-load-config@6.0.1(postcss@8.4.47)(tsx@3.14.0)(yaml@2.6.0): + postcss-load-config@6.0.1(postcss@8.4.39)(tsx@3.14.0)(yaml@2.4.2): dependencies: lilconfig: 3.1.2 optionalDependencies: - postcss: 8.4.47 + postcss: 8.4.39 tsx: 3.14.0 - yaml: 2.6.0 + yaml: 2.4.2 + + postcss@8.4.38: + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 - postcss@8.4.47: + postcss@8.4.39: dependencies: nanoid: 3.3.7 - picocolors: 1.1.1 - source-map-js: 1.2.1 + picocolors: 1.0.1 + source-map-js: 1.2.0 postgres-array@2.0.0: {} @@ -17450,7 +20318,7 @@ snapshots: postgres-range@1.1.4: {} - postgres@3.4.5: {} + postgres@3.4.4: {} pouchdb-collections@1.0.1: {} @@ -17462,8 +20330,8 @@ snapshots: minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 1.0.2 - node-abi: 3.71.0 - pump: 3.0.2 + node-abi: 3.62.0 + pump: 3.0.0 rc: 1.2.8 simple-get: 4.0.1 tar-fs: 2.1.1 @@ -17477,22 +20345,22 @@ snapshots: prettier@2.8.8: {} - prettier@3.3.3: {} + prettier@3.0.3: {} pretty-bytes@5.6.0: {} - pretty-format@24.9.0: + pretty-format@26.6.2: dependencies: - '@jest/types': 24.9.0 - ansi-regex: 4.1.1 - ansi-styles: 3.2.1 - react-is: 16.13.1 + '@jest/types': 26.6.2 + ansi-regex: 5.0.1 + ansi-styles: 4.3.0 + react-is: 17.0.2 pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 - react-is: 18.3.1 + react-is: 18.2.0 pretty-ms@8.0.0: dependencies: @@ -17549,21 +20417,25 @@ snapshots: dependencies: event-stream: 3.3.4 - pump@3.0.2: + pump@3.0.0: dependencies: end-of-stream: 1.4.4 once: 1.4.0 + punycode@2.3.0: {} + punycode@2.3.1: {} pure-rand@6.1.0: {} qrcode-terminal@0.11.0: {} - qs@6.13.0: + qs@6.11.0: dependencies: side-channel: 1.0.6 + querystring@0.2.1: {} + queue-microtask@1.2.3: {} queue@6.0.2: @@ -17590,65 +20462,67 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): + react-devtools-core@5.2.0(bufferutil@4.0.8): dependencies: shell-quote: 1.8.1 - ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - utf-8-validate react-is@16.13.1: {} + react-is@17.0.2: {} + + react-is@18.2.0: {} + react-is@18.3.1: {} - react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native/assets-registry': 0.76.1 - '@react-native/codegen': 0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - '@react-native/community-cli-plugin': 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - '@react-native/gradle-plugin': 0.76.1 - '@react-native/js-polyfills': 0.76.1 - '@react-native/normalize-colors': 0.76.1 - '@react-native/virtualized-lists': 0.76.1(@types/react@18.3.12)(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) + '@react-native/assets-registry': 0.74.83 + '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/gradle-plugin': 0.74.83 + '@react-native/js-polyfills': 0.74.83 + '@react-native/normalize-colors': 0.74.83 + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 - babel-jest: 29.7.0(@babel/core@7.26.0) - babel-plugin-syntax-hermes-parser: 0.23.1 base64-js: 1.5.1 chalk: 4.1.2 - commander: 12.1.0 event-target-shim: 5.0.1 flow-enums-runtime: 0.0.6 - glob: 7.2.3 invariant: 2.2.4 jest-environment-node: 29.7.0 jsc-android: 250231.0.0 memoize-one: 5.2.1 - metro-runtime: 0.81.0 - metro-source-map: 0.81.0 + metro-runtime: 0.80.9 + metro-source-map: 0.80.9 mkdirp: 0.5.6 nullthrows: 1.1.1 - pretty-format: 29.7.0 + pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + react-devtools-core: 5.2.0(bufferutil@4.0.8) react-refresh: 0.14.2 + react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 - semver: 7.6.3 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) yargs: 17.7.2 optionalDependencies: - '@types/react': 18.3.12 + '@types/react': 18.3.1 transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' - - '@react-native-community/cli-server-api' - bufferutil - encoding - supports-color @@ -17656,6 +20530,12 @@ snapshots: react-refresh@0.14.2: {} + react-shallow-renderer@16.15.0(react@18.3.1): + dependencies: + object-assign: 4.1.1 + react: 18.3.1 + react-is: 18.3.1 + react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -17668,7 +20548,7 @@ snapshots: read-pkg@5.2.0: dependencies: - '@types/normalize-package-data': 2.4.4 + '@types/normalize-package-data': 2.4.1 normalize-package-data: 2.5.0 parse-json: 5.2.0 type-fest: 0.6.0 @@ -17693,8 +20573,6 @@ snapshots: dependencies: picomatch: 2.3.1 - readdirp@4.0.2: {} - readline@1.3.0: {} recast@0.21.5: @@ -17720,7 +20598,7 @@ snapshots: dependencies: esprima: 4.0.1 - regenerate-unicode-properties@10.2.0: + regenerate-unicode-properties@10.1.1: dependencies: regenerate: 1.4.2 @@ -17728,39 +20606,45 @@ snapshots: regenerator-runtime@0.13.11: {} + regenerator-runtime@0.14.0: {} + regenerator-runtime@0.14.1: {} regenerator-transform@0.15.2: dependencies: - '@babel/runtime': 7.26.0 + '@babel/runtime': 7.24.6 regexp-tree@0.1.27: {} - regexp.prototype.flags@1.5.3: + regexp.prototype.flags@1.5.0: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + functions-have-names: 1.2.3 + + regexp.prototype.flags@1.5.2: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 - regexpu-core@6.1.1: + regexpu-core@5.3.2: dependencies: + '@babel/regjsgen': 0.8.0 regenerate: 1.4.2 - regenerate-unicode-properties: 10.2.0 - regjsgen: 0.8.0 - regjsparser: 0.11.2 + regenerate-unicode-properties: 10.1.1 + regjsparser: 0.9.1 unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.2.0 - - regjsgen@0.8.0: {} + unicode-match-property-value-ecmascript: 2.1.0 regjsparser@0.10.0: dependencies: jsesc: 0.5.0 - regjsparser@0.11.2: + regjsparser@0.9.1: dependencies: - jsesc: 3.0.2 + jsesc: 0.5.0 remove-trailing-slash@0.1.1: {} @@ -17768,6 +20652,8 @@ snapshots: require-from-string@2.0.2: {} + require-main-filename@2.0.0: {} + requireg@0.2.2: dependencies: nested-error-stacks: 2.0.1 @@ -17786,6 +20672,13 @@ snapshots: resolve-pkg-maps@1.0.0: {} + resolve-tspaths@0.8.16(typescript@5.6.3): + dependencies: + ansi-colors: 4.1.3 + commander: 11.0.0 + fast-glob: 3.3.1 + typescript: 5.6.3 + resolve-tspaths@0.8.22(typescript@5.6.3): dependencies: ansi-colors: 4.1.3 @@ -17795,9 +20688,27 @@ snapshots: resolve.exports@2.0.2: {} + resolve@1.22.1: + dependencies: + is-core-module: 2.11.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@1.22.2: + dependencies: + is-core-module: 2.12.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@1.22.4: + dependencies: + is-core-module: 2.13.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + resolve@1.22.8: dependencies: - is-core-module: 2.15.1 + is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -17810,6 +20721,11 @@ snapshots: onetime: 2.0.1 signal-exit: 3.0.7 + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + retry@0.12.0: optional: true @@ -17817,17 +20733,26 @@ snapshots: reusify@1.0.4: {} + rimraf@2.4.5: + dependencies: + glob: 6.0.4 + optional: true + rimraf@2.6.3: dependencies: glob: 7.2.3 + rimraf@2.7.1: + dependencies: + glob: 7.2.3 + rimraf@3.0.2: dependencies: glob: 7.2.3 - rimraf@5.0.10: + rimraf@5.0.0: dependencies: - glob: 10.4.5 + glob: 10.4.1 rollup-plugin-inject@3.0.2: dependencies: @@ -17843,32 +20768,58 @@ snapshots: dependencies: estree-walker: 0.6.1 - rollup@3.29.5: + rollup@3.20.7: + optionalDependencies: + fsevents: 2.3.3 + + rollup@3.27.2: + optionalDependencies: + fsevents: 2.3.3 + + rollup@4.18.1: + dependencies: + '@types/estree': 1.0.5 optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.18.1 + '@rollup/rollup-android-arm64': 4.18.1 + '@rollup/rollup-darwin-arm64': 4.18.1 + '@rollup/rollup-darwin-x64': 4.18.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.18.1 + '@rollup/rollup-linux-arm-musleabihf': 4.18.1 + '@rollup/rollup-linux-arm64-gnu': 4.18.1 + '@rollup/rollup-linux-arm64-musl': 4.18.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.18.1 + '@rollup/rollup-linux-riscv64-gnu': 4.18.1 + '@rollup/rollup-linux-s390x-gnu': 4.18.1 + '@rollup/rollup-linux-x64-gnu': 4.18.1 + '@rollup/rollup-linux-x64-musl': 4.18.1 + '@rollup/rollup-win32-arm64-msvc': 4.18.1 + '@rollup/rollup-win32-ia32-msvc': 4.18.1 + '@rollup/rollup-win32-x64-msvc': 4.18.1 fsevents: 2.3.3 - rollup@4.24.4: + rollup@4.27.3: dependencies: '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.24.4 - '@rollup/rollup-android-arm64': 4.24.4 - '@rollup/rollup-darwin-arm64': 4.24.4 - '@rollup/rollup-darwin-x64': 4.24.4 - '@rollup/rollup-freebsd-arm64': 4.24.4 - '@rollup/rollup-freebsd-x64': 4.24.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.24.4 - '@rollup/rollup-linux-arm-musleabihf': 4.24.4 - '@rollup/rollup-linux-arm64-gnu': 4.24.4 - '@rollup/rollup-linux-arm64-musl': 4.24.4 - '@rollup/rollup-linux-powerpc64le-gnu': 4.24.4 - '@rollup/rollup-linux-riscv64-gnu': 4.24.4 - '@rollup/rollup-linux-s390x-gnu': 4.24.4 - '@rollup/rollup-linux-x64-gnu': 4.24.4 - '@rollup/rollup-linux-x64-musl': 4.24.4 - '@rollup/rollup-win32-arm64-msvc': 4.24.4 - '@rollup/rollup-win32-ia32-msvc': 4.24.4 - '@rollup/rollup-win32-x64-msvc': 4.24.4 + '@rollup/rollup-android-arm-eabi': 4.27.3 + '@rollup/rollup-android-arm64': 4.27.3 + '@rollup/rollup-darwin-arm64': 4.27.3 + '@rollup/rollup-darwin-x64': 4.27.3 + '@rollup/rollup-freebsd-arm64': 4.27.3 + '@rollup/rollup-freebsd-x64': 4.27.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.27.3 + '@rollup/rollup-linux-arm-musleabihf': 4.27.3 + '@rollup/rollup-linux-arm64-gnu': 4.27.3 + '@rollup/rollup-linux-arm64-musl': 4.27.3 + '@rollup/rollup-linux-powerpc64le-gnu': 4.27.3 + '@rollup/rollup-linux-riscv64-gnu': 4.27.3 + '@rollup/rollup-linux-s390x-gnu': 4.27.3 + '@rollup/rollup-linux-x64-gnu': 4.27.3 + '@rollup/rollup-linux-x64-musl': 4.27.3 + '@rollup/rollup-win32-arm64-msvc': 4.27.3 + '@rollup/rollup-win32-ia32-msvc': 4.27.3 + '@rollup/rollup-win32-x64-msvc': 4.27.3 fsevents: 2.3.3 run-parallel@1.2.0: @@ -17883,6 +20834,13 @@ snapshots: dependencies: mri: 1.2.0 + safe-array-concat@1.0.0: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + has-symbols: 1.0.3 + isarray: 2.0.5 + safe-array-concat@1.1.2: dependencies: call-bind: 1.0.7 @@ -17894,6 +20852,15 @@ snapshots: safe-buffer@5.2.1: {} + safe-json-stringify@1.2.0: + optional: true + + safe-regex-test@1.0.0: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-regex: 1.1.4 + safe-regex-test@1.0.3: dependencies: call-bind: 1.0.7 @@ -17917,7 +20884,7 @@ snapshots: semver@6.3.1: {} - semver@7.6.3: {} + semver@7.6.2: {} send@0.18.0: dependencies: @@ -17937,24 +20904,6 @@ snapshots: transitivePeerDependencies: - supports-color - send@0.19.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - seq-queue@0.0.5: {} serialize-error@2.1.0: {} @@ -17963,23 +20912,22 @@ snapshots: dependencies: type-fest: 0.13.1 - serialize-javascript@6.0.2: + serialize-javascript@6.0.1: dependencies: randombytes: 2.1.0 - serve-static@1.16.2: + serve-static@1.15.0: dependencies: - encodeurl: 2.0.0 + encodeurl: 1.0.2 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.19.0 + send: 0.18.0 transitivePeerDependencies: - supports-color - set-blocking@2.0.0: - optional: true + set-blocking@2.0.0: {} - set-cookie-parser@2.7.1: {} + set-cookie-parser@2.6.0: {} set-function-length@1.2.2: dependencies: @@ -18019,17 +20967,25 @@ snapshots: shell-quote@1.8.1: {} + side-channel@1.0.4: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + object-inspect: 1.12.3 + side-channel@1.0.6: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 - object-inspect: 1.13.2 + object-inspect: 1.13.1 siginfo@2.0.0: {} signal-exit@3.0.7: {} + signal-exit@4.0.2: {} + signal-exit@4.1.0: {} simple-concat@1.0.1: {} @@ -18048,7 +21004,7 @@ snapshots: sirv@2.0.4: dependencies: - '@polka/url': 1.0.0-next.28 + '@polka/url': 1.0.0-next.25 mrmime: 2.0.0 totalist: 3.0.1 @@ -18064,6 +21020,12 @@ snapshots: slash@5.1.0: {} + slice-ansi@2.1.0: + dependencies: + ansi-styles: 3.2.1 + astral-regex: 1.0.0 + is-fullwidth-code-point: 2.0.0 + slice-ansi@5.0.0: dependencies: ansi-styles: 6.2.1 @@ -18074,12 +21036,14 @@ snapshots: smart-buffer@4.2.0: optional: true + smob@0.0.6: {} + smob@1.5.0: {} socks-proxy-agent@6.2.1: dependencies: agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.3.4 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -18091,7 +21055,7 @@ snapshots: smart-buffer: 4.2.0 optional: true - source-map-js@1.2.1: {} + source-map-js@1.2.0: {} source-map-support@0.5.21: dependencies: @@ -18102,6 +21066,8 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.4: {} + source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 @@ -18113,16 +21079,16 @@ snapshots: spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.20 + spdx-license-ids: 3.0.13 - spdx-exceptions@2.5.0: {} + spdx-exceptions@2.3.0: {} spdx-expression-parse@3.0.1: dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.20 + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.13 - spdx-license-ids@3.0.20: {} + spdx-license-ids@3.0.13: {} split-ca@1.0.1: {} @@ -18145,12 +21111,12 @@ snapshots: sprintf-js@1.1.3: optional: true - sql.js@1.12.0: {} + sql.js@1.10.3: {} sqlite3@5.1.7: dependencies: bindings: 1.5.0 - node-addon-api: 7.1.1 + node-addon-api: 7.1.0 prebuild-install: 7.1.2 tar: 6.2.1 optionalDependencies: @@ -18161,13 +21127,13 @@ snapshots: sqlstring@2.3.3: {} - ssh2@1.16.0: + ssh2@1.15.0: dependencies: asn1: 0.2.6 bcrypt-pbkdf: 1.0.2 optionalDependencies: cpu-features: 0.0.10 - nan: 2.22.0 + nan: 2.19.0 ssri@10.0.6: dependencies: @@ -18175,37 +21141,17 @@ snapshots: ssri@8.0.1: dependencies: - minipass: 3.3.6 - optional: true - - sst-darwin-arm64@3.3.5: - optional: true - - sst-darwin-x64@3.3.5: - optional: true - - sst-linux-arm64@3.3.5: - optional: true - - sst-linux-x64@3.3.5: - optional: true - - sst-linux-x86@3.3.5: + minipass: 3.3.6 optional: true - sst@3.3.5(hono@4.6.9)(valibot@0.30.0): + sst@3.0.14: dependencies: - aws4fetch: 1.0.20 + '@aws-sdk/client-lambda': 3.478.0 + hono: 4.0.1 jose: 5.2.3 openid-client: 5.6.4 - optionalDependencies: - hono: 4.6.9 - sst-darwin-arm64: 3.3.5 - sst-darwin-x64: 3.3.5 - sst-linux-arm64: 3.3.5 - sst-linux-x64: 3.3.5 - sst-linux-x86: 3.3.5 - valibot: 0.30.0 + transitivePeerDependencies: + - aws-crt stack-utils@2.0.6: dependencies: @@ -18252,6 +21198,12 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string.prototype.trim@1.2.7: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + string.prototype.trim@1.2.9: dependencies: call-bind: 1.0.7 @@ -18259,12 +21211,24 @@ snapshots: es-abstract: 1.23.3 es-object-atoms: 1.0.0 + string.prototype.trimend@1.0.6: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + string.prototype.trimend@1.0.8: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 + string.prototype.trimstart@1.0.6: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + string.prototype.trimstart@1.0.8: dependencies: call-bind: 1.0.7 @@ -18289,7 +21253,7 @@ snapshots: strip-ansi@7.1.0: dependencies: - ansi-regex: 6.1.0 + ansi-regex: 6.0.1 strip-bom@3.0.0: {} @@ -18317,7 +21281,7 @@ snapshots: sucrase@3.34.0: dependencies: - '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/gen-mapping': 0.3.3 commander: 4.1.1 glob: 7.1.6 lines-and-columns: 1.2.4 @@ -18329,7 +21293,7 @@ snapshots: dependencies: '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 - glob: 10.4.5 + glob: 10.4.1 lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.6 @@ -18339,6 +21303,8 @@ snapshots: sudo-prompt@9.1.1: {} + sudo-prompt@9.2.1: {} + superjson@2.2.1: dependencies: copy-anything: 3.0.5 @@ -18367,6 +21333,11 @@ snapshots: has-flag: 4.0.0 supports-color: 7.2.0 + supports-hyperlinks@3.0.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + supports-hyperlinks@3.1.0: dependencies: has-flag: 4.0.0 @@ -18374,7 +21345,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - synckit@0.9.2: + synckit@0.9.1: dependencies: '@pkgr/core': 0.1.1 tslib: 2.8.1 @@ -18383,14 +21354,14 @@ snapshots: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.2 + pump: 3.0.0 tar-stream: 2.2.0 tar-fs@2.1.1: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.2 + pump: 3.0.0 tar-stream: 2.2.0 tar-stream@2.2.0: @@ -18441,18 +21412,19 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - terser@5.36.0: + terser@5.17.1: dependencies: - '@jridgewell/source-map': 0.3.6 - acorn: 8.14.0 + '@jridgewell/source-map': 0.3.3 + acorn: 8.8.2 commander: 2.20.3 source-map-support: 0.5.21 - test-exclude@6.0.0: + terser@5.31.0: dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 + '@jridgewell/source-map': 0.3.6 + acorn: 8.11.3 + commander: 2.20.3 + source-map-support: 0.5.21 text-table@0.2.0: {} @@ -18481,23 +21453,20 @@ snapshots: time-zone@1.0.0: {} - timers-ext@0.1.8: + timers-ext@0.1.7: dependencies: - es5-ext: 0.10.64 + es5-ext: 0.10.62 next-tick: 1.1.0 tiny-invariant@1.3.3: {} tiny-queue@0.2.1: {} - tinybench@2.9.0: {} + tinybench@2.8.0: {} - tinyexec@0.3.1: {} + tinybench@2.9.0: {} - tinyglobby@0.2.10: - dependencies: - fdir: 6.4.2(picomatch@4.0.2) - picomatch: 4.0.2 + tinyexec@0.3.0: {} tinypool@0.8.4: {} @@ -18529,9 +21498,9 @@ snapshots: tr46@1.0.1: dependencies: - punycode: 2.3.1 + punycode: 2.3.0 - traverse@0.6.10: + traverse@0.6.9: dependencies: gopd: 1.0.1 typedarray.prototype.slice: 1.0.3 @@ -18541,9 +21510,15 @@ snapshots: treeify@1.1.0: {} - trim-right@1.0.1: {} + ts-api-utils@1.0.3(typescript@5.2.2): + dependencies: + typescript: 5.2.2 + + ts-api-utils@1.0.3(typescript@5.6.3): + dependencies: + typescript: 5.6.3 - ts-api-utils@1.4.0(typescript@5.6.3): + ts-api-utils@1.3.0(typescript@5.6.3): dependencies: typescript: 5.6.3 @@ -18551,16 +21526,16 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@types/node@20.17.6)(typescript@5.6.3): + ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.17.6 - acorn: 8.14.0 - acorn-walk: 8.3.4 + '@types/node': 20.12.12 + acorn: 8.11.3 + acorn-walk: 8.3.2 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 @@ -18569,30 +21544,11 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 22.9.0 - acorn: 8.14.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.6.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - optional: true - - tsconfck@3.1.4(typescript@5.6.3): + tsconfck@3.0.3(typescript@5.6.3): optionalDependencies: typescript: 5.6.3 - tsconfig-paths@3.15.0: + tsconfig-paths@3.14.2: dependencies: '@types/json5': 0.0.29 json5: 1.0.2 @@ -18601,51 +21557,52 @@ snapshots: tslib@1.14.1: {} + tslib@2.6.2: {} + tslib@2.8.1: {} - tsup@7.3.0(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3): + tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3): dependencies: - bundle-require: 4.2.1(esbuild@0.19.12) + bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 - chokidar: 3.6.0 - debug: 4.3.7 - esbuild: 0.19.12 + chokidar: 3.5.3 + debug: 4.3.4 + esbuild: 0.18.20 execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3)) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)) resolve-from: 5.0.0 - rollup: 4.24.4 + rollup: 3.27.2 source-map: 0.8.0-beta.0 - sucrase: 3.35.0 + sucrase: 3.34.0 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.4.47 + postcss: 8.4.39 typescript: 5.6.3 transitivePeerDependencies: - supports-color - ts-node - tsup@8.3.5(postcss@8.4.47)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.6.0): + tsup@8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.4.2): dependencies: - bundle-require: 5.0.0(esbuild@0.24.0) + bundle-require: 5.0.0(esbuild@0.23.0) cac: 6.7.14 - chokidar: 4.0.1 + chokidar: 3.6.0 consola: 3.2.3 - debug: 4.3.7 - esbuild: 0.24.0 + debug: 4.3.5 + esbuild: 0.23.0 + execa: 5.1.1 + globby: 11.1.0 joycon: 3.1.1 - picocolors: 1.1.1 - postcss-load-config: 6.0.1(postcss@8.4.47)(tsx@3.14.0)(yaml@2.6.0) + postcss-load-config: 6.0.1(postcss@8.4.39)(tsx@3.14.0)(yaml@2.4.2) resolve-from: 5.0.0 - rollup: 4.24.4 + rollup: 4.18.1 source-map: 0.8.0-beta.0 sucrase: 3.35.0 - tinyexec: 0.3.1 - tinyglobby: 0.2.10 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.4.47 + postcss: 8.4.39 typescript: 5.6.3 transitivePeerDependencies: - jiti @@ -18661,15 +21618,29 @@ snapshots: tsx@3.14.0: dependencies: esbuild: 0.18.20 - get-tsconfig: 4.8.1 + get-tsconfig: 4.7.5 source-map-support: 0.5.21 optionalDependencies: fsevents: 2.3.3 + tsx@4.10.5: + dependencies: + esbuild: 0.20.2 + get-tsconfig: 4.7.5 + optionalDependencies: + fsevents: 2.3.3 + + tsx@4.16.2: + dependencies: + esbuild: 0.21.5 + get-tsconfig: 4.7.5 + optionalDependencies: + fsevents: 2.3.3 + tsx@4.19.2: dependencies: - esbuild: 0.23.1 - get-tsconfig: 4.8.1 + esbuild: 0.23.0 + get-tsconfig: 4.7.5 optionalDependencies: fsevents: 2.3.3 @@ -18677,32 +21648,32 @@ snapshots: dependencies: safe-buffer: 5.2.1 - turbo-darwin-64@2.2.3: + turbo-darwin-64@2.3.0: optional: true - turbo-darwin-arm64@2.2.3: + turbo-darwin-arm64@2.3.0: optional: true - turbo-linux-64@2.2.3: + turbo-linux-64@2.3.0: optional: true - turbo-linux-arm64@2.2.3: + turbo-linux-arm64@2.3.0: optional: true - turbo-windows-64@2.2.3: + turbo-windows-64@2.3.0: optional: true - turbo-windows-arm64@2.2.3: + turbo-windows-arm64@2.3.0: optional: true - turbo@2.2.3: + turbo@2.3.0: optionalDependencies: - turbo-darwin-64: 2.2.3 - turbo-darwin-arm64: 2.2.3 - turbo-linux-64: 2.2.3 - turbo-linux-arm64: 2.2.3 - turbo-windows-64: 2.2.3 - turbo-windows-arm64: 2.2.3 + turbo-darwin-64: 2.3.0 + turbo-darwin-arm64: 2.3.0 + turbo-linux-64: 2.3.0 + turbo-linux-arm64: 2.3.0 + turbo-windows-64: 2.3.0 + turbo-windows-arm64: 2.3.0 tweetnacl@0.14.5: {} @@ -18712,8 +21683,6 @@ snapshots: type-detect@4.0.8: {} - type-detect@4.1.0: {} - type-fest@0.13.1: {} type-fest@0.16.0: {} @@ -18730,12 +21699,22 @@ snapshots: type-fest@0.8.1: {} + type-fest@3.13.1: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0 mime-types: 2.1.35 - type@2.7.3: {} + type@1.2.0: {} + + type@2.7.2: {} + + typed-array-buffer@1.0.0: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-typed-array: 1.1.12 typed-array-buffer@1.0.2: dependencies: @@ -18743,6 +21722,13 @@ snapshots: es-errors: 1.3.0 is-typed-array: 1.1.13 + typed-array-byte-length@1.0.0: + dependencies: + call-bind: 1.0.2 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + typed-array-byte-length@1.0.1: dependencies: call-bind: 1.0.7 @@ -18751,6 +21737,14 @@ snapshots: has-proto: 1.0.3 is-typed-array: 1.1.13 + typed-array-byte-offset@1.0.0: + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + typed-array-byte-offset@1.0.2: dependencies: available-typed-arrays: 1.0.7 @@ -18760,6 +21754,12 @@ snapshots: has-proto: 1.0.3 is-typed-array: 1.1.13 + typed-array-length@1.0.4: + dependencies: + call-bind: 1.0.2 + for-each: 0.3.3 + is-typed-array: 1.1.12 + typed-array-length@1.0.6: dependencies: call-bind: 1.0.7 @@ -18778,19 +21778,21 @@ snapshots: typed-array-buffer: 1.0.2 typed-array-byte-offset: 1.0.2 + typescript@5.2.2: {} + typescript@5.3.3: {} typescript@5.6.1-rc: {} typescript@5.6.3: {} - ua-parser-js@1.0.39: {} + ua-parser-js@1.0.38: {} - ufo@1.5.4: {} + ufo@1.5.3: {} unbox-primitive@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.2 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 @@ -18803,23 +21805,25 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 - unenv-nightly@2.0.0-20241024-111401-d4156ac: + unenv-nightly@1.10.0-1717606461.a117952: dependencies: + consola: 3.2.3 defu: 6.1.4 - ohash: 1.1.4 + mime: 3.0.0 + node-fetch-native: 1.6.4 pathe: 1.1.2 - ufo: 1.5.4 + ufo: 1.5.3 - unicode-canonical-property-names-ecmascript@2.0.1: {} + unicode-canonical-property-names-ecmascript@2.0.0: {} unicode-emoji-modifier-base@1.0.0: {} unicode-match-property-ecmascript@2.0.0: dependencies: - unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-canonical-property-names-ecmascript: 2.0.0 unicode-property-aliases-ecmascript: 2.1.0 - unicode-match-property-value-ecmascript@2.2.0: {} + unicode-match-property-value-ecmascript@2.1.0: {} unicode-property-aliases-ecmascript@2.1.0: {} @@ -18855,19 +21859,21 @@ snapshots: universalify@1.0.0: {} + universalify@2.0.0: {} + universalify@2.0.1: {} unpipe@1.0.0: {} - update-browserslist-db@1.1.1(browserslist@4.24.2): + update-browserslist-db@1.0.16(browserslist@4.23.0): dependencies: - browserslist: 4.24.2 - escalade: 3.2.0 - picocolors: 1.1.1 + browserslist: 4.23.0 + escalade: 3.1.2 + picocolors: 1.0.1 uri-js@4.4.1: dependencies: - punycode: 2.3.1 + punycode: 2.3.0 url-join@4.0.0: {} @@ -18875,7 +21881,7 @@ snapshots: utf-8-validate@6.0.3: dependencies: - node-gyp-build: 4.8.2 + node-gyp-build: 4.8.1 util-deprecate@1.0.2: {} @@ -18892,7 +21898,7 @@ snapshots: uvu@0.5.6: dependencies: dequal: 2.0.3 - diff: 5.2.0 + diff: 5.1.0 kleur: 4.1.5 sade: 1.8.1 @@ -18915,268 +21921,442 @@ snapshots: dependencies: builtins: 5.1.0 - validate-npm-package-name@5.0.1: {} + validate-npm-package-name@5.0.0: + dependencies: + builtins: 5.1.0 vary@1.1.2: {} - vite-node@1.6.0(@types/node@18.19.64)(terser@5.36.0): + vite-node@1.6.0(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0): dependencies: cac: 6.7.14 - debug: 4.3.7 + debug: 4.3.4 pathe: 1.1.2 - picocolors: 1.1.1 - vite: 5.4.10(@types/node@18.19.64)(terser@5.36.0) + picocolors: 1.0.1 + vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - '@types/node' - less - lightningcss - sass - - sass-embedded - stylus - sugarss - supports-color - terser - vite-node@1.6.0(@types/node@20.17.6)(terser@5.36.0): + vite-node@1.6.0(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0): dependencies: cac: 6.7.14 - debug: 4.3.7 + debug: 4.3.4 pathe: 1.1.2 - picocolors: 1.1.1 - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) + picocolors: 1.0.1 + vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - '@types/node' - less - lightningcss - sass - - sass-embedded - stylus - sugarss - supports-color - terser - vite-node@2.1.4(@types/node@20.17.6)(terser@5.36.0): + vite-node@1.6.0(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0): dependencies: cac: 6.7.14 - debug: 4.3.7 + debug: 4.3.4 pathe: 1.1.2 - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) + picocolors: 1.0.1 + vite: 5.3.3(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - '@types/node' - less - lightningcss - sass - - sass-embedded - stylus - sugarss - supports-color - terser - vite-node@2.1.4(@types/node@22.9.0)(terser@5.36.0): + vite-node@1.6.0(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + cac: 6.7.14 + debug: 4.3.4 + pathe: 1.1.2 + picocolors: 1.0.1 + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vite-node@2.1.2(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): dependencies: cac: 6.7.14 debug: 4.3.7 pathe: 1.1.2 - vite: 5.4.10(@types/node@22.9.0)(terser@5.36.0) + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - '@types/node' - less - lightningcss - sass - - sass-embedded - stylus - sugarss - supports-color - terser - vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)): + vite-node@2.1.2(@types/node@22.9.1)(lightningcss@1.25.1)(terser@5.31.0): dependencies: + cac: 6.7.14 debug: 4.3.7 + pathe: 1.1.2 + vite: 5.3.3(@types/node@22.9.1)(lightningcss@1.25.1)(terser@5.31.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)): + dependencies: + debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.1.4(typescript@5.6.3) + tsconfck: 3.0.3(typescript@5.6.3) optionalDependencies: - vite: 5.4.10(@types/node@18.19.64)(terser@5.36.0) + vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)): + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)): dependencies: - debug: 4.3.7 + debug: 4.3.4 + globrex: 0.1.2 + tsconfck: 3.0.3(typescript@5.6.3) + optionalDependencies: + vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) + transitivePeerDependencies: + - supports-color + - typescript + + vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)): + dependencies: + debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.1.4(typescript@5.6.3) + tsconfck: 3.0.3(typescript@5.6.3) optionalDependencies: - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - supports-color - typescript - vite@5.4.10(@types/node@18.19.64)(terser@5.36.0): + vite@5.2.12(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + esbuild: 0.20.2 + postcss: 8.4.38 + rollup: 4.27.3 + optionalDependencies: + '@types/node': 18.15.10 + fsevents: 2.3.3 + lightningcss: 1.25.1 + terser: 5.31.0 + + vite@5.2.12(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + esbuild: 0.20.2 + postcss: 8.4.38 + rollup: 4.27.3 + optionalDependencies: + '@types/node': 18.19.33 + fsevents: 2.3.3 + lightningcss: 1.25.1 + terser: 5.31.0 + + vite@5.2.12(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + esbuild: 0.20.2 + postcss: 8.4.38 + rollup: 4.27.3 + optionalDependencies: + '@types/node': 20.10.1 + fsevents: 2.3.3 + lightningcss: 1.25.1 + terser: 5.31.0 + + vite@5.2.12(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + esbuild: 0.20.2 + postcss: 8.4.38 + rollup: 4.27.3 + optionalDependencies: + '@types/node': 20.12.12 + fsevents: 2.3.3 + lightningcss: 1.25.1 + terser: 5.31.0 + + vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.39 + rollup: 4.27.3 + optionalDependencies: + '@types/node': 18.15.10 + fsevents: 2.3.3 + lightningcss: 1.25.1 + terser: 5.31.0 + + vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.39 + rollup: 4.27.3 + optionalDependencies: + '@types/node': 18.19.33 + fsevents: 2.3.3 + lightningcss: 1.25.1 + terser: 5.31.0 + + vite@5.3.3(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0): dependencies: esbuild: 0.21.5 - postcss: 8.4.47 - rollup: 4.24.4 + postcss: 8.4.39 + rollup: 4.27.3 optionalDependencies: - '@types/node': 18.19.64 + '@types/node': 20.10.1 fsevents: 2.3.3 - terser: 5.36.0 + lightningcss: 1.25.1 + terser: 5.31.0 - vite@5.4.10(@types/node@20.17.6)(terser@5.36.0): + vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): dependencies: esbuild: 0.21.5 - postcss: 8.4.47 - rollup: 4.24.4 + postcss: 8.4.39 + rollup: 4.27.3 optionalDependencies: - '@types/node': 20.17.6 + '@types/node': 20.12.12 fsevents: 2.3.3 - terser: 5.36.0 + lightningcss: 1.25.1 + terser: 5.31.0 - vite@5.4.10(@types/node@22.9.0)(terser@5.36.0): + vite@5.3.3(@types/node@22.9.1)(lightningcss@1.25.1)(terser@5.31.0): dependencies: esbuild: 0.21.5 - postcss: 8.4.47 - rollup: 4.24.4 + postcss: 8.4.39 + rollup: 4.27.3 optionalDependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 fsevents: 2.3.3 - terser: 5.36.0 + lightningcss: 1.25.1 + terser: 5.31.0 - vitest@1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0): + vitest@1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): dependencies: '@vitest/expect': 1.6.0 '@vitest/runner': 1.6.0 '@vitest/snapshot': 1.6.0 '@vitest/spy': 1.6.0 '@vitest/utils': 1.6.0 - acorn-walk: 8.3.4 - chai: 4.5.0 - debug: 4.3.7 + acorn-walk: 8.3.2 + chai: 4.4.1 + debug: 4.3.4 execa: 8.0.1 local-pkg: 0.5.0 - magic-string: 0.30.12 + magic-string: 0.30.10 pathe: 1.1.2 - picocolors: 1.1.1 + picocolors: 1.0.0 std-env: 3.7.0 strip-literal: 2.1.0 - tinybench: 2.9.0 + tinybench: 2.8.0 tinypool: 0.8.4 - vite: 5.4.10(@types/node@18.19.64)(terser@5.36.0) - vite-node: 1.6.0(@types/node@18.19.64)(terser@5.36.0) - why-is-node-running: 2.3.0 + vite: 5.2.12(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) + vite-node: 1.6.0(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) + why-is-node-running: 2.2.2 optionalDependencies: - '@types/node': 18.19.64 + '@types/node': 18.15.10 '@vitest/ui': 1.6.0(vitest@1.6.0) transitivePeerDependencies: - less - lightningcss - sass - - sass-embedded - stylus - sugarss - supports-color - terser - vitest@1.6.0(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0): + vitest@1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): dependencies: '@vitest/expect': 1.6.0 '@vitest/runner': 1.6.0 '@vitest/snapshot': 1.6.0 '@vitest/spy': 1.6.0 '@vitest/utils': 1.6.0 - acorn-walk: 8.3.4 - chai: 4.5.0 - debug: 4.3.7 + acorn-walk: 8.3.2 + chai: 4.4.1 + debug: 4.3.4 execa: 8.0.1 local-pkg: 0.5.0 - magic-string: 0.30.12 + magic-string: 0.30.10 pathe: 1.1.2 - picocolors: 1.1.1 + picocolors: 1.0.0 std-env: 3.7.0 strip-literal: 2.1.0 - tinybench: 2.9.0 + tinybench: 2.8.0 tinypool: 0.8.4 - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) - vite-node: 1.6.0(@types/node@20.17.6)(terser@5.36.0) - why-is-node-running: 2.3.0 + vite: 5.2.12(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) + vite-node: 1.6.0(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) + why-is-node-running: 2.2.2 + optionalDependencies: + '@types/node': 18.19.33 + '@vitest/ui': 1.6.0(vitest@1.6.0) + transitivePeerDependencies: + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vitest@1.6.0(@types/node@20.10.1)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + '@vitest/expect': 1.6.0 + '@vitest/runner': 1.6.0 + '@vitest/snapshot': 1.6.0 + '@vitest/spy': 1.6.0 + '@vitest/utils': 1.6.0 + acorn-walk: 8.3.2 + chai: 4.4.1 + debug: 4.3.4 + execa: 8.0.1 + local-pkg: 0.5.0 + magic-string: 0.30.10 + pathe: 1.1.2 + picocolors: 1.0.0 + std-env: 3.7.0 + strip-literal: 2.1.0 + tinybench: 2.8.0 + tinypool: 0.8.4 + vite: 5.2.12(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0) + vite-node: 1.6.0(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0) + why-is-node-running: 2.2.2 optionalDependencies: - '@types/node': 20.17.6 + '@types/node': 20.10.1 '@vitest/ui': 1.6.0(vitest@1.6.0) transitivePeerDependencies: - less - lightningcss - sass - - sass-embedded - stylus - sugarss - supports-color - terser - vitest@2.1.4(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0): + vitest@1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): dependencies: - '@vitest/expect': 2.1.4 - '@vitest/mocker': 2.1.4(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)) - '@vitest/pretty-format': 2.1.4 - '@vitest/runner': 2.1.4 - '@vitest/snapshot': 2.1.4 - '@vitest/spy': 2.1.4 - '@vitest/utils': 2.1.4 - chai: 5.1.2 + '@vitest/expect': 1.6.0 + '@vitest/runner': 1.6.0 + '@vitest/snapshot': 1.6.0 + '@vitest/spy': 1.6.0 + '@vitest/utils': 1.6.0 + acorn-walk: 8.3.2 + chai: 4.4.1 + debug: 4.3.4 + execa: 8.0.1 + local-pkg: 0.5.0 + magic-string: 0.30.10 + pathe: 1.1.2 + picocolors: 1.0.0 + std-env: 3.7.0 + strip-literal: 2.1.0 + tinybench: 2.8.0 + tinypool: 0.8.4 + vite: 5.2.12(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + vite-node: 1.6.0(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + why-is-node-running: 2.2.2 + optionalDependencies: + '@types/node': 20.12.12 + '@vitest/ui': 1.6.0(vitest@1.6.0) + transitivePeerDependencies: + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vitest@2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + '@vitest/expect': 2.1.2 + '@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) + '@vitest/pretty-format': 2.1.2 + '@vitest/runner': 2.1.2 + '@vitest/snapshot': 2.1.2 + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 debug: 4.3.7 - expect-type: 1.1.0 - magic-string: 0.30.12 + magic-string: 0.30.11 pathe: 1.1.2 std-env: 3.7.0 tinybench: 2.9.0 - tinyexec: 0.3.1 + tinyexec: 0.3.0 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) - vite-node: 2.1.4(@types/node@20.17.6)(terser@5.36.0) + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + vite-node: 2.1.2(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 20.17.6 - '@vitest/ui': 1.6.0(vitest@2.1.4) + '@types/node': 20.12.12 + '@vitest/ui': 1.6.0(vitest@2.1.2) transitivePeerDependencies: - less - lightningcss - msw - sass - - sass-embedded - stylus - sugarss - supports-color - terser - vitest@2.1.4(@types/node@22.9.0)(terser@5.36.0): + vitest@2.1.2(@types/node@22.9.1)(lightningcss@1.25.1)(terser@5.31.0): dependencies: - '@vitest/expect': 2.1.4 - '@vitest/mocker': 2.1.4(vite@5.4.10(@types/node@22.9.0)(terser@5.36.0)) - '@vitest/pretty-format': 2.1.4 - '@vitest/runner': 2.1.4 - '@vitest/snapshot': 2.1.4 - '@vitest/spy': 2.1.4 - '@vitest/utils': 2.1.4 - chai: 5.1.2 + '@vitest/expect': 2.1.2 + '@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@22.9.1)(lightningcss@1.25.1)(terser@5.31.0)) + '@vitest/pretty-format': 2.1.2 + '@vitest/runner': 2.1.2 + '@vitest/snapshot': 2.1.2 + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 debug: 4.3.7 - expect-type: 1.1.0 - magic-string: 0.30.12 + magic-string: 0.30.11 pathe: 1.1.2 std-env: 3.7.0 tinybench: 2.9.0 - tinyexec: 0.3.1 + tinyexec: 0.3.0 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.10(@types/node@22.9.0)(terser@5.36.0) - vite-node: 2.1.4(@types/node@22.9.0)(terser@5.36.0) + vite: 5.3.3(@types/node@22.9.1)(lightningcss@1.25.1)(terser@5.31.0) + vite-node: 2.1.2(@types/node@22.9.1)(lightningcss@1.25.1)(terser@5.31.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 transitivePeerDependencies: - less - lightningcss - msw - sass - - sass-embedded - stylus - sugarss - supports-color @@ -19192,7 +22372,7 @@ snapshots: dependencies: defaults: 1.0.4 - web-streams-polyfill@3.3.3: {} + web-streams-polyfill@3.2.1: {} webidl-conversions@3.0.1: {} @@ -19231,6 +22411,16 @@ snapshots: is-string: 1.0.7 is-symbol: 1.0.4 + which-module@2.0.1: {} + + which-typed-array@1.1.11: + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 @@ -19251,6 +22441,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.2.2: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 @@ -19263,47 +22458,48 @@ snapshots: wonka@4.0.15: {} - word-wrap@1.2.5: {} - wordwrap@1.0.0: {} - workerd@1.20241022.0: + workerd@1.20240712.0: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20241022.0 - '@cloudflare/workerd-darwin-arm64': 1.20241022.0 - '@cloudflare/workerd-linux-64': 1.20241022.0 - '@cloudflare/workerd-linux-arm64': 1.20241022.0 - '@cloudflare/workerd-windows-64': 1.20241022.0 + '@cloudflare/workerd-darwin-64': 1.20240712.0 + '@cloudflare/workerd-darwin-arm64': 1.20240712.0 + '@cloudflare/workerd-linux-64': 1.20240712.0 + '@cloudflare/workerd-linux-arm64': 1.20240712.0 + '@cloudflare/workerd-windows-64': 1.20240712.0 - wrangler@3.85.0(@cloudflare/workers-types@4.20241106.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3): + wrangler@3.65.0(@cloudflare/workers-types@4.20240524.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: '@cloudflare/kv-asset-handler': 0.3.4 - '@cloudflare/workers-shared': 0.7.0 '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) blake3-wasm: 2.1.5 - chokidar: 3.6.0 - date-fns: 4.1.0 + chokidar: 3.5.3 + date-fns: 3.6.0 esbuild: 0.17.19 - itty-time: 1.0.6 - miniflare: 3.20241022.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + miniflare: 3.20240712.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) nanoid: 3.3.7 - path-to-regexp: 6.3.0 + path-to-regexp: 6.2.2 resolve: 1.22.8 resolve.exports: 2.0.2 selfsigned: 2.4.1 source-map: 0.6.1 - unenv: unenv-nightly@2.0.0-20241024-111401-d4156ac - workerd: 1.20241022.0 + unenv: unenv-nightly@1.10.0-1717606461.a117952 xxhash-wasm: 1.0.2 optionalDependencies: - '@cloudflare/workers-types': 4.20241106.0 + '@cloudflare/workers-types': 4.20240524.0 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -19324,33 +22520,31 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 - write-file-atomic@4.0.2: - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - write-file-atomic@5.0.1: dependencies: imurmurhash: 0.1.4 - signal-exit: 4.1.0 + signal-exit: 4.0.2 - ws@6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@6.2.2(bufferutil@4.0.8): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@7.5.9(bufferutil@4.0.8): optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 utf-8-validate: 6.0.3 + ws@8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 6.0.3 + ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 @@ -19376,22 +22570,45 @@ snapshots: xxhash-wasm@1.0.2: {} + y18n@4.0.3: {} + y18n@5.0.8: {} yallist@3.1.1: {} yallist@4.0.0: {} - yaml@2.6.0: {} + yaml@2.3.1: {} + + yaml@2.4.2: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 yargs-parser@20.2.9: {} yargs-parser@21.1.1: {} + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + yargs@16.2.0: dependencies: cliui: 7.0.4 - escalade: 3.2.0 + escalade: 3.1.2 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -19401,7 +22618,7 @@ snapshots: yargs@17.7.2: dependencies: cliui: 8.0.1 - escalade: 3.2.0 + escalade: 3.1.1 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -19412,39 +22629,37 @@ snapshots: yocto-queue@0.1.0: {} - yocto-queue@1.1.1: {} + yocto-queue@1.0.0: {} - youch@3.3.4: + youch@3.3.3: dependencies: - cookie: 0.7.2 + cookie: 0.5.0 mustache: 4.2.0 stacktracey: 2.1.8 - zod-validation-error@2.1.0(zod@3.23.8): - dependencies: - zod: 3.23.8 + zod@3.21.4: {} - zod@3.23.8: {} + zod@3.23.7: {} - zx@7.2.3: + zx@7.2.2: dependencies: '@types/fs-extra': 11.0.4 - '@types/minimist': 1.2.5 - '@types/node': 18.19.64 - '@types/ps-tree': 1.1.6 - '@types/which': 3.0.4 + '@types/minimist': 1.2.2 + '@types/node': 18.19.33 + '@types/ps-tree': 1.1.2 + '@types/which': 3.0.0 chalk: 5.3.0 - fs-extra: 11.2.0 - fx: 35.0.0 + fs-extra: 11.1.1 + fx: 28.0.0 globby: 13.2.2 minimist: 1.2.8 node-fetch: 3.3.1 ps-tree: 1.2.0 webpod: 0.0.2 which: 3.0.1 - yaml: 2.6.0 + yaml: 2.4.2 - zx@8.2.0: + zx@8.2.2: optionalDependencies: '@types/fs-extra': 11.0.4 - '@types/node': 22.9.0 + '@types/node': 20.12.12 From 375ed280c9484780873765e660b08f7d5429ead3 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 21 Nov 2024 16:22:32 +0200 Subject: [PATCH 381/492] Fix wrong resolved conflicts --- drizzle-orm/src/pg-core/query-builders/insert.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index 18b972102..c1849d4bb 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -70,9 +70,16 @@ export class PgInsertBuilder< return this; } - values(value: PgInsertValue): PgInsertBase; - values(values: PgInsertValue[]): PgInsertBase; - values(values: PgInsertValue | PgInsertValue[]): PgInsertBase { + overridingSystemValue(): Omit, 'overridingSystemValue'> { + this.overridingSystemValue_ = true; + return this as any; + } + + values(value: PgInsertValue): PgInsertBase; + values(values: PgInsertValue[]): PgInsertBase; + values( + values: PgInsertValue | PgInsertValue[], + ): PgInsertBase { values = Array.isArray(values) ? values : [values]; if (values.length === 0) { throw new Error('values() must be called with at least one value'); From 7fe60337c073824249dea02933f1e3bf90d91266 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 21 Nov 2024 17:03:22 +0200 Subject: [PATCH 382/492] Exclude tidb --- drizzle-seed/README.md | 1152 ++-------------------------- integration-tests/vitest.config.ts | 2 +- 2 files changed, 58 insertions(+), 1096 deletions(-) diff --git a/drizzle-seed/README.md b/drizzle-seed/README.md index 8476e03b5..588102a5b 100644 --- a/drizzle-seed/README.md +++ b/drizzle-seed/README.md @@ -1,1143 +1,105 @@ -## Overview +# Drizzle Seed + +> [!NOTE] +> `drizzle-seed` can only be used with `drizzle-orm@0.36.4` or higher. Versions lower than this may work at runtime but could have type issues and identity column issues, as this patch was introduced in `drizzle-orm@0.36.4` -drizzle-seed is a typescript library that will help you generate deterministic fake realistic data and fill your database with it. +## Documentation -### Determinism +The full API reference and package overview can be found in our [official documentation](https://orm.drizzle.team/docs/seed-overview) -## +## Overview -#### pseudorandom number generator(pRNG) +`drizzle-seed` is a TypeScript library that helps you generate deterministic, yet realistic, +fake data to populate your database. By leveraging a seedable pseudorandom number generator (pRNG), +it ensures that the data you generate is consistent and reproducible across different runs. +This is especially useful for testing, development, and debugging purposes. -It's a random number generator whose randomness you can control. -It will give you the same sequence of numbers if you initialize it with the same `seed` number. +#### What is Deterministic Data Generation? -## +Deterministic data generation means that the same input will always produce the same output. +In the context of `drizzle-seed`, when you initialize the library with the same seed number, +it will generate the same sequence of fake data every time. This allows for predictable and repeatable data sets. -#### How it works? +#### Pseudorandom Number Generator (pRNG) -Each column will be assigned with its generator and all random events in it will be handled by pRNG. +A pseudorandom number generator is an algorithm that produces a sequence of numbers +that approximates the properties of random numbers. However, because it's based on an initial value +called a seed, you can control its randomness. By using the same seed, the pRNG will produce the +same sequence of numbers, making your data generation process reproducible. -Each pRNG will be initialized with `seed` which will be generated from table name and column name. +#### Benefits of Using a pRNG: -Also, there will be cases when the randomness of generators will be affected by the number of rows you want to generate. So far this only applies to unique int and number generators. +- Consistency: Ensures that your tests run on the same data every time. +- Debugging: Makes it easier to reproduce and fix bugs by providing a consistent data set. +- Collaboration: Team members can share seed numbers to work with the same data sets. -So as long as your schema and your seeding script remain the same, Seeder will generate the same data. +With drizzle-seed, you get the best of both worlds: the ability to generate realistic fake data and the control to reproduce it whenever needed. ## Getting started `npm install drizzle-seed` -You have to install drizzle-orm in order to use seeder. +You have to install `drizzle-orm` in order to use `drizzle-seed`. `npm install drizzle-orm` -## Usage - -### Simple usage - -#### `src/main.ts` - -```ts -(async () => { - await seed(db, schema); - // await seed(db, schema, { count: 100000 }); - // await seed(db, schema, { count: 100000, seed: 1 }); -})().then(); -``` - -From the commented part of the code above, you can see that it's possible to specify the `count` property which stands for the number of rows you want to generate - -and `seed` property which represents a custom `seed` number that will be added to the one automatically generated from the table's name and column's name and then the result of addition will be fed to pRNG. -Therefore you can manage different states of your data using the `seed` property. - -#### You also can delete all data from your tables to seed your database again using the `reset` function. +## Basic Usage -#### `src/main.ts` - -```ts -(async () => { - await reset(db, schema); - // await seed(db, schema); -})().then(); -``` - -`If db is a PgDatabase object`, we will execute sql query and delete data from your tables the following way: - -```sql -truncate tableName1, tableName2, ... cascade; -``` - -`If db is a MySqlDatabase object`, we will execute sql queries and delete data from your tables the following way: - -```sql -SET FOREIGN_KEY_CHECKS = 0; -truncate tableName1; -truncate tableName2; -. -. -. - -SET FOREIGN_KEY_CHECKS = 1; -``` +In this example we will create 10 users with random names and ids -`If db is a BaseSQLiteDatabase object`, we will execute sql queries and delete data from your tables the following way: - -```sql -PRAGMA foreign_keys = OFF; -delete from tableName1; -delete from tableName2; -. -. -. - -PRAGMA foreign_keys = ON; -``` - -### But you still need to define database schema (`schema`) and create database connection (`db`) before using `seed` or `reset` function. - -#### You can find some examples for Postgres, Mysql and Sqlite below. - -### **Postgres** - -#### `src/schema.ts` - -```ts -import { - serial, - integer, - varchar, - pgSchema, - getTableConfig as getPgTableConfig, -} from "drizzle-orm/pg-core"; - -export const schema = pgSchema("seeder_lib_pg"); - -export const users = schema.table("users", { - id: serial("id").primaryKey(), - name: varchar("name", { length: 256 }), - email: varchar("email", { length: 256 }), - phone: varchar("phone", { length: 256 }), - password: varchar("password", { length: 256 }), -}); - -export const posts = schema.table("posts", { - id: serial("id").primaryKey(), - title: varchar("title", { length: 256 }), - content: varchar("content", { length: 256 }), - userId: integer("user_id").references(() => users.id), -}); -``` - -#### `src/main.ts` - -```ts -import Pool from "pg"; +```ts {12} +import { pgTable, integer, text } from "drizzle-orm/pg-core"; import { drizzle } from "drizzle-orm/node-postgres"; -import * as schema from "./schema"; - -const { PG_HOST, PG_PORT, PG_DATABASE, PG_USER, PG_PASSWORD } = process.env; - -const pool = new Pool({ - host: PG_HOST, - port: Number(PG_PORT) || 5432, - database: PG_DATABASE, - user: PG_USER, - password: PG_PASSWORD, - // ssl: true -}); +import { seed } from "drizzle-seed"; -const db = drizzle(pool); -``` - -### **Mysql** - -#### `src/schema.ts` - -```ts -import { serial, int, varchar, mysqlTable } from "drizzle-orm/mysql-core"; - -export const users = mysqlTable("users", { - id: int("id").autoincrement().primaryKey(), - name: varchar("name", { length: 256 }), - email: varchar("email", { length: 256 }), - phone: varchar("phone", { length: 256 }), - password: varchar("password", { length: 256 }), -}); - -export const posts = mysqlTable("posts", { - id: int("id").autoincrement().primaryKey(), - title: varchar("title", { length: 256 }), - content: varchar("content", { length: 256 }), - userId: int("user_id").references(() => users.id), -}); -``` - -#### `src/main.ts` - -```ts -import mysql from "mysql2/promise"; -import { drizzle } from "drizzle-orm/mysql2"; -import * as schema from "./schema"; - -const { Mysql_HOST, Mysql_PORT, Mysql_DATABASE, Mysql_USER, Mysql_PASSWORD } = - process.env; - -const pool = mysql.createPool({ - host: Mysql_HOST, - port: Number(Mysql_PORT) || 3306, - database: Mysql_DATABASE, - user: Mysql_USER, - password: Mysql_PASSWORD, - // ssl: { rejectUnauthorized: false } +const users = pgTable("users", { + id: integer().primaryKey(), + name: text().notNull(), }); -const db = drizzle(pool); -``` - -### **Sqlite** - -#### `src/schema.ts` - -```ts -import { integer, text, sqliteTable } from "drizzle-orm/sqlite-core"; - -export const users = sqliteTable("users", { - id: integer("id").primaryKey(), - name: text("name", { length: 256 }), - email: text("email", { length: 256 }), - phone: text("phone", { length: 256 }), - password: text("password", { length: 256 }), -}); - -export const posts = sqliteTable("posts", { - id: integer("id").primaryKey(), - title: text("title", { length: 256 }), - content: text("content", { length: 256 }), - userId: integer("user_id").references(() => users.id), -}); -``` - -#### `src/main.ts` - -```ts -import betterSqlite3 from "better-sqlite3"; -import { drizzle } from "drizzle-orm/better-sqlite3"; -import * as schema from "./schema"; - -const { Sqlite_PATH } = process.env; -const sqliteDb = betterSqlite3(Sqlite_PATH); -const db = drizzle(sqliteDb); -``` - -### More complex usage examples - -#### All of the following examples will be in the context of database schema defined above. - -## - -#### You have 30 different data generators to choose from: - -- `default` -- `valuesFromArray` -- `intPrimaryKey` -- `number` -- `int` -- `boolean` -- `date` -- `time` -- `timestamp` -- `datetime` -- `year` -- `json` -- `interval` -- `string` -- `firstName` -- `lastName` -- `fullName` -- `email` -- `phoneNumber` -- `country` -- `city` -- `streetAddress` -- `jobTitle` -- `postcode` -- `state` -- `companyName` -- `loremIpsum` -- `weightedRandom` - -#### Some of them have an option to generate unique data samples which stands for property `isUnique`. - -#### Some of them can only generate unique data like `email` or `phoneNumber` generators. - -#### `src/main.ts` - -```ts -(async () => { - await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - name: funcs.firstName({ isUnique: true }), - email: funcs.email(), - phone: funcs.phoneNumber({ template: "+380 99 ###-##-##" }), - password: funcs.string({ isUnique: true }), - }, - count: 100000, - }, - posts: { - columns: { - title: funcs.valuesFromArray({ - values: ["Title1", "Title2", "Title3", "Title4", "Title5"], - }), - content: funcs.loremIpsum({ sentencesCount: 3 }), - }, - }, - })); -})().then(); -``` - -In the example above we used
-`firstName`, `string` generators that have `isUnique` property,
-`email` and `phoneNumber` which always generates unique data,
-`loremIpsum` and `default` generators that don't have `isUnique` property,
-and `valuesFromArray` which has `isUnique` property. - -Also we specified number of rows we want to generate in `users` section using property `count`. Therefore top-level `count` which equals 1000, will be rewrote with the one from `refine` and `count` for `users` table will equal 100000. - -And since we didn't specify `count` property in `posts` section it will use top-level `count` which equals 1000 and generate 1000 rows for `posts` table. - -#### Even so `valuesFromArray` generator has `isUnique` property, there is no point using it here, since we have only 5 unique elements in `values` array and want to generate 1000 titles for `posts` table. - -## - -#### You can specify how many posts each user will have, using `with` property if there is right relation in schema. - -#### Write `with: {posts: 2}` so each user will have 2 posts related to him. - -#### `src/main.ts` - -```ts -(async () => { - await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - count: 100000, - with: { - posts: 2, - }, - }, - posts: { - count: 100, - }, - })); -})().then(); -``` - -In this example overall number of posts or in other words posts `count` will be calculated like: - -{users `count`} $\times$ 2 = 100000 $\times$ 2 = 200000 - -And this posts `count` will overwrite both top-level `count` which equals to 100000 and `count` from `posts` section which equals to 100. - -## - -#### **Weighted choice** - -#### You can specify weighted number of posts for each user to have. - -```ts -with: { - posts: [ - { weight: 0.7, count: 3 }, - { weight: 0.3, count: [4, 5] } - ] +async function main() { + const db = drizzle(process.env.DATABASE_URL!); + await seed(db, { users }); } -``` - -#### This means that each user will have 3 posts with probability 0.7 and from 4 to 5 posts with probability 0.3 . - -Number of posts for each user will be generated using pRNG and therefore remain deterministic. - -#### There also are some generators that feature select with given probability: - -- `valuesFromArray` has option to specify weighted arrays of values, -- `weightedMix` will use generators with given probabilities. - -#### `src/main.ts` - -```ts -(async () => { - await seed(db, schema).refine((funcs) => ({ - users: { - count: 100000, - with: { - posts: [ - { weight: 0.7, count: 3 }, - { weight: 0.3, count: [4, 5] }, - ], - }, - }, - posts: { - columns: { - title: funcs.valuesFromArray({ - values: [ - { weight: 0.35, values: ["Title1", "Title2"] }, - { weight: 0.5, values: ["Title3", "Title4"] }, - { weight: 0.15, values: ["Title5"] }, - ], - }), - content: funcs.weightedRandom([ - { - weight: 0.6, - value: funcs.loremIpsum({ sentencesCount: 3 }), - }, - { - weight: 0.4, - value: funcs.default({ defaultValue: "TODO" }), - }, - ]), - }, - }, - })); -})().then(); -``` - -#### Explanations of the code block above: - -- `valuesFromArray` generator
- with probability 0.35 will pick array `["Title1", "Title2"]`,
- with probability 0.5 will pick array `["Title3", "Title4"]`,
- with probability 0.15 will pick array `["Title5"]`
- and then pick value from chosen array using uniform distribution or in other words uniformly. -- `weightedMix` generator will call `loremIpsum` generator with probability 0.6 and `default` generator with probability 0.4 . - -## - -#### And you can combine all of this in one seeding script - -#### `src/main.ts` - -```ts -(async () => { - await seed(db, schema).refine((funcs) => ({ - users: { - columns: { - name: funcs.fullName(), - email: funcs.email(), - phone: funcs.phoneNumber({ template: "+380 99 ###-##-##" }), - password: funcs.string({ isUnique: true }), - }, - count: 100000, - with: { - posts: [ - { weight: 0.7, count: 3 }, - { weight: 0.3, count: [4, 5] }, - ], - }, - }, - posts: { - columns: { - title: funcs.valuesFromArray({ - values: [ - { weight: 0.35, values: ["Title1", "Title2"] }, - { weight: 0.5, values: ["Title3", "Title4"] }, - { weight: 0.15, values: ["Title5"] }, - ], - }), - content: funcs.weightedRandom([ - { - weight: 0.6, - value: funcs.loremIpsum({ sentencesCount: 3 }), - }, - { - weight: 0.4, - value: funcs.default({ defaultValue: "TODO" }), - }, - ]), - }, - }, - })); -})().then(); -``` - -### Generators Usage Examples - -## - -#### **default** - -generates same given value each time the generator is called. - -`defaultValue` - value you want to generate - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - posts: { - columns: { - content: funcs.default({ defaultValue: "post content" }), - }, - }, -})); -``` - -## -#### **valuesFromArray** - -generates values from given array - -`values` - array of values you want to generate.(can be array of weighted values) - -`isUnique` - property that controls if generated values gonna be unique or not. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - posts: { - columns: { - title: funcs.valuesFromArray({ - values: ["Title1", "Title2", "Title3", "Title4", "Title5"], - isUnique: true, - }), - }, - }, -})); +main(); ``` -weighted values example +## Options -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - posts: { - columns: { - title: funcs.valuesFromArray({ - values: [ - { weight: 0.35, values: ["Title1", "Title2"] }, - { weight: 0.5, values: ["Title3", "Title4"] }, - { weight: 0.15, values: ["Title5"] }, - ], - isUnique: false, - }), - }, - }, -})); -``` - -## - -#### **intPrimaryKey** +**`count`** -generates sequential integers starting with 1. +By default, the `seed` function will create 10 entities. +However, if you need more for your tests, you can specify this in the seed options object ```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - posts: { - columns: { - id: funcs.intPrimaryKey(), - }, - }, -})); +await seed(db, schema, { count: 1000 }); ``` -## - -#### **number** - -generates numbers with floating point in given range. +**`seed`** -`minValue` - lower border of range. - -`maxValue` - upper border of range. - -`precision` - precision of generated number:
-precision equals 10 means that values will be accurate to one tenth (1.2, 34.6);
-precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67). - -`isUnique` - property that controls if generated values gonna be unique or not. +If you need a seed to generate a different set of values for all subsequent runs, you can define a different number +in the `seed` option. Any new number will generate a unique set of values ```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - products: { - columns: { - unitPrice: funcs.number({ - minValue: 10, - maxValue: 120, - precision: 100, - isUnique: false, - }), - }, - }, -})); +await seed(db, schema, { seed: 12345 }); ``` -## - -#### **int** - -generates integers with given range. - -`minValue` - lower border of range. +## Reset databases -`maxValue` - upper border of range. - -`isUnique` - property that controls if generated values gonna be unique or not. +With `drizzle-seed`, you can easily reset your database and seed it with new values, for example, in your test suites ```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - products: { - columns: { - unitsInStock: funcs.int({ - minValue: 0, - maxValue: 100, - isUnique: false, - }), - }, - }, -})); -``` - -## - -#### **boolean** - -generates boolean values(true or false). +// path to a file with schema you want to reset +import * as schema from "./schema.ts"; +import { reset } from "drizzle-seed"; -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - isAvailable: funcs.boolean(), - }, - }, -})); -``` - -## - -#### **date** - -generates date within given range. - -`minDate` - lower border of range. - -`maxDate` - upper border of range. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - birthDate: funcs.date({ minDate: "1990-01-01", maxDate: "2010-12-31" }), - }, - }, -})); -``` - -## - -#### **time** - -generates time in 24 hours style. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - birthTime: funcs.time(), - }, - }, -})); -``` - -## - -#### **timestamp** - -generates timestamps. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - orders: { - columns: { - shippedDate: funcs.timestamp(), - }, - }, -})); -``` - -## - -#### **datetime** - -generates datetime objects. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - orders: { - columns: { - shippedDate: funcs.datetime(), - }, - }, -})); -``` - -## - -#### **year** - -generates years. - -example of generated value: "2024" - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - birthYear: funcs.year(), - }, - }, -})); -``` - -## - -#### **json** - -generates json objects with fixed structure. - -json structure can equal this: - -``` -{ - email, - name, - isGraduated, - hasJob, - salary, - startedWorking, - visitedCountries, -} -``` - -or this - -``` -{ - email, - name, - isGraduated, - hasJob, - visitedCountries, +async function main() { + const db = drizzle(process.env.DATABASE_URL!); + await reset(db, schema); } -``` - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - metadata: funcs.json(), - }, - }, -})); -``` - -## - -#### **interval** - -generates time intervals. - -example of generated value: "1 years 12 days 5 minutes" - -`isUnique` - property that controls if generated values gonna be unique or not. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - timeSpentOnWebsite: funcs.interval(), - }, - }, -})); -``` - -## - -#### **string** - -generates random strings. - -`isUnique` - property that controls if generated values gonna be unique or not. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - hashedPassword: funcs.string({ isUnique: false }), - }, - }, -})); -``` - -## - -#### **firstName** - -generates person's first names. - -`isUnique` - property that controls if generated values gonna be unique or not. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - firstName: funcs.firstName({ isUnique: true }), - }, - }, -})); -``` - -## - -#### **lastName** -generates person's last names. - -`isUnique` - property that controls if generated values gonna be unique or not. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - lastName: funcs.lastName({ isUnique: false }), - }, - }, -})); +main(); ``` -## - -#### **fullName** - -generates person's full names. - -`isUnique` - property that controls if generated values gonna be unique or not. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - fullName: funcs.fullName({ isUnique: true }), - }, - }, -})); -``` - -## - -#### **email** - -generates unique emails. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - email: funcs.email(), - }, - }, -})); -``` - -## - -#### **phoneNumber** - -generates unique phone numbers. - -`template` - phone number template, where all '#' symbols will be substituted with generated digits. - -`prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property) - -`generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property) - -```ts -//generate phone number using template property -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - phoneNumber: funcs.phoneNumber({ template: "+(380) ###-####" }), - }, - }, -})); - -//generate phone number using prefixes and generatedDigitsNumbers properties -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - phoneNumber: funcs.phoneNumber({ - prefixes: ["+380 99", "+380 67"], - generatedDigitsNumbers: 7, - }), - }, - }, -})); - -//generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - phoneNumber: funcs.phoneNumber({ - prefixes: ["+380 99", "+380 67", "+1"], - generatedDigitsNumbers: [7, 7, 10], - }), - }, - }, -})); -``` - -## - -#### **country** - -generates country's names. - -`isUnique` - property that controls if generated values gonna be unique or not. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - country: funcs.country({ isUnique: false }), - }, - }, -})); -``` - -## - -#### **city** - -generates city's names. - -`isUnique` - property that controls if generated values gonna be unique or not. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - city: funcs.city({ isUnique: false }), - }, - }, -})); -``` - -## - -#### **streetAddress** - -generates street address. - -`isUnique` - property that controls if generated values gonna be unique or not. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - streetAddress: funcs.streetAddress({ isUnique: true }), - }, - }, -})); -``` - -## - -#### **jobTitle** - -generates job titles. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - jobTitle: funcs.jobTitle(), - }, - }, -})); -``` - -## - -#### **postcode** - -generates postal codes. - -`isUnique` - property that controls if generated values gonna be unique or not. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - postcode: funcs.postcode({ isUnique: true }), - }, - }, -})); -``` - -## - -#### **state** - -generates states of America. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - state: funcs.state(), - }, - }, -})); -``` - -## - -#### **companyName** - -generates company's names. - -`isUnique` - property that controls if generated values gonna be unique or not. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - users: { - columns: { - company: funcs.companyName({ isUnique: true }), - }, - }, -})); -``` - -## - -#### **loremIpsum** - -generates 'lorem ipsum' text sentences. - -`sentencesCount` - number of sentences you want to generate as one generated value(string). - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - posts: { - columns: { - content: funcs.loremIpsum({ sentencesCount: 2 }), - }, - }, -})); -``` - -## - -#### **point** - -generates 2D points within specified ranges for x and y coordinates. - -`isUnique` - property that controls if generated values gonna be unique or not. - -`minXValue` - lower bound of range for x coordinate. - -`maxXValue` - upper bound of range for x coordinate. - -`minYValue` - lower bound of range for y coordinate. - -`maxYValue` - upper bound of range for y coordinate. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - triangles: { - columns: { - pointCoords: funcs.point({ - isUnique: true, - minXValue: -5, - maxXValue: 20, - minYValue: 0, - maxYValue: 30, - }), - }, - }, -})); -``` - -## - -#### **line** - -generates 2D lines within specified ranges for a, b and c parameters of line. - -``` -line equation: a*x + b*y + c = 0 -``` - -`isUnique` - property that controls if generated values gonna be unique or not. - -`minAValue` - lower bound of range for a parameter. - -`maxAValue` - upper bound of range for x parameter. - -`minBValue` - lower bound of range for y parameter. - -`maxBValue` - upper bound of range for y parameter. - -`minCValue` - lower bound of range for y parameter. - -`maxCValue` - upper bound of range for y parameter. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - lines: { - columns: { - lineParams: funcs.point({ - isUnique: true, - minAValue: -5, - maxAValue: 20, - minBValue: 0, - maxBValue: 30, - minCValue: 0, - maxCValue: 10, - }), - }, - }, -})); -``` - -## - -#### **weightedRandom** - -gives you the opportunity to call different generators with different probabilities to generate values for one column. - -params - array of generators with probabilities you would like to call them to generate values. - -```ts -await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - posts: { - columns: { - content: funcs.weightedRandom([ - { - weight: 0.6, - value: funcs.loremIpsum({ sentencesCount: 3 }), - }, - { - weight: 0.4, - value: funcs.default({ defaultValue: "TODO" }), - }, - ]), - }, - }, -})); -``` - -## - -## Limitations - -- Seeder can generate data for composite foreign keys, but it can't handle the uniqueness of composite primary keys, so using composite primary and foreign keys sometimes will end up in error for now. -- Seeder can't generate data for columns with composite unique constraint.(unique index for multiple columns) -- Not all generators have ability to generate unique data. This applies to default, date, time, timestamp, datetime, year, json, jobTitle, state, loremIpsum generators. +More examples are available in our [official documentation](https://orm.drizzle.team/docs/seed-overview) \ No newline at end of file diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 87c7e7f3c..fcce0a362 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -28,7 +28,6 @@ export default defineConfig({ 'tests/mysql/tidb-serverless.test.ts', 'tests/mysql/mysql-planetscale.test.ts', 'tests/sqlite/libsql.test.ts', - 'tests/mysql/tidb-serverless.test.ts', 'tests/sqlite/libsql-batch.test.ts', 'tests/pg/neon-http.test.ts', 'tests/pg/neon-http-batch.test.ts', @@ -58,6 +57,7 @@ export default defineConfig({ // move back after decide on speed 'tests/sqlite/libsql-ws.test.ts', 'tests/sqlite/libsql-http.test.ts', + 'tests/mysql/tidb-serverless.test.ts', ], typecheck: { tsconfig: 'tsconfig.json', From 6f7d3454699134e585343b2c5cf48a33ae13477e Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 22 Nov 2024 10:30:46 +0200 Subject: [PATCH 383/492] Update seed package bundling --- changelogs/drizzle-orm/0.36.4.md | 84 ++++++++++++++++++++++++++++++++ changelogs/drizzle-seed/0.1.1.md | 52 ++++++++++++++++++++ drizzle-seed/rollup.config.ts | 2 - drizzle-seed/src/index.ts | 2 + 4 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 changelogs/drizzle-orm/0.36.4.md create mode 100644 changelogs/drizzle-seed/0.1.1.md diff --git a/changelogs/drizzle-orm/0.36.4.md b/changelogs/drizzle-orm/0.36.4.md new file mode 100644 index 000000000..056c5a01e --- /dev/null +++ b/changelogs/drizzle-orm/0.36.4.md @@ -0,0 +1,84 @@ +# New Package: `drizzle-seed` + +> [!NOTE] +> `drizzle-seed` can only be used with `drizzle-orm@0.36.4` or higher. Versions lower than this may work at runtime but could have type issues and identity column issues, as this patch was introduced in `drizzle-orm@0.36.4` + +## Full Reference + +The full API reference and package overview can be found in our [official documentation](https://orm.drizzle.team/docs/seed-overview) + +## Basic Usage + +In this example we will create 10 users with random names and ids + +```ts {12} +import { pgTable, integer, text } from "drizzle-orm/pg-core"; +import { drizzle } from "drizzle-orm/node-postgres"; +import { seed } from "drizzle-seed"; + +const users = pgTable("users", { + id: integer().primaryKey(), + name: text().notNull(), +}); + +async function main() { + const db = drizzle(process.env.DATABASE_URL!); + await seed(db, { users }); +} + +main(); +``` + +## Options + +**`count`** + +By default, the `seed` function will create 10 entities. +However, if you need more for your tests, you can specify this in the seed options object + +```ts +await seed(db, schema, { count: 1000 }); +``` + +**`seed`** + +If you need a seed to generate a different set of values for all subsequent runs, you can define a different number +in the `seed` option. Any new number will generate a unique set of values + +```ts +await seed(db, schema, { seed: 12345 }); +``` + +The full API reference and package overview can be found in our [official documentation](https://orm.drizzle.team/docs/seed-overview) + +# Features + +## Added `OVERRIDING SYSTEM VALUE` api to db.insert() + +If you want to force you own values for `GENERATED ALWAYS AS IDENTITY` columns, you can use `OVERRIDING SYSTEM VALUE` + +As PostgreSQL docs mentions +> In an INSERT command, if ALWAYS is selected, a user-specified value is only accepted if the INSERT statement specifies OVERRIDING SYSTEM VALUE. If BY DEFAULT is selected, then the user-specified value takes precedence + +```ts +await db.insert(identityColumnsTable).overridingSystemValue().values([ + { alwaysAsIdentity: 2 }, +]); +``` + +## Added `.$withAuth()` API for Neon HTTP driver + +Using this API, Drizzle will send you an auth token to authorize your query. It can be used with any query available in Drizzle by simply adding `.$withAuth()` before it. This token will be used for a specific query + +Examples + +```ts +const token = 'HdncFj1Nm' + +await db.$withAuth(token).select().from(usersTable); +await db.$withAuth(token).update(usersTable).set({ name: 'CHANGED' }).where(eq(usersTable.name, 'TARGET')) +``` + +# Bug Fixes + +- [[BUG]: TypeScript error Please install '@neondatabase/serverless' to allow Drizzle ORM to connect to the database](https://github.com/drizzle-team/drizzle-orm/issues/3521) diff --git a/changelogs/drizzle-seed/0.1.1.md b/changelogs/drizzle-seed/0.1.1.md new file mode 100644 index 000000000..34dca67b6 --- /dev/null +++ b/changelogs/drizzle-seed/0.1.1.md @@ -0,0 +1,52 @@ +# Initial Release + +> [!NOTE] +> `drizzle-seed` can only be used with `drizzle-orm@0.36.4` or higher. Versions lower than this may work at runtime but could have type issues and identity column issues, as this patch was introduced in `drizzle-orm@0.36.4` + +## Full Reference + +The full API reference and package overview can be found in our [official documentation](https://orm.drizzle.team/docs/seed-overview) + +## Basic Usage + +In this example we will create 10 users with random names and ids + +```ts {12} +import { pgTable, integer, text } from "drizzle-orm/pg-core"; +import { drizzle } from "drizzle-orm/node-postgres"; +import { seed } from "drizzle-seed"; + +const users = pgTable("users", { + id: integer().primaryKey(), + name: text().notNull(), +}); + +async function main() { + const db = drizzle(process.env.DATABASE_URL!); + await seed(db, { users }); +} + +main(); +``` + +## Options + +**`count`** + +By default, the `seed` function will create 10 entities. +However, if you need more for your tests, you can specify this in the seed options object + +```ts +await seed(db, schema, { count: 1000 }); +``` + +**`seed`** + +If you need a seed to generate a different set of values for all subsequent runs, you can define a different number +in the `seed` option. Any new number will generate a unique set of values + +```ts +await seed(db, schema, { seed: 12345 }); +``` + +The full API reference and package overview can be found in our [official documentation](https://orm.drizzle.team/docs/seed-overview) \ No newline at end of file diff --git a/drizzle-seed/rollup.config.ts b/drizzle-seed/rollup.config.ts index 229862c75..c5874a54a 100644 --- a/drizzle-seed/rollup.config.ts +++ b/drizzle-seed/rollup.config.ts @@ -1,4 +1,3 @@ -import terser from '@rollup/plugin-terser'; import typescript from '@rollup/plugin-typescript'; import { defineConfig } from 'rollup'; @@ -26,7 +25,6 @@ export default defineConfig([ typescript({ tsconfig: 'tsconfig.build.json', }), - terser(), ], }, ]); diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 47c9f408e..55d80243d 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -356,6 +356,8 @@ const seedFunc = async ( } else { throw new Error('given db is not supported.'); } + + return; }; /** From 16ce08fbf789c95f7b3319fd29e936efea3cb2a5 Mon Sep 17 00:00:00 2001 From: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:46:04 +0200 Subject: [PATCH 384/492] Removed type-level import existence checks on driver init (fixes #3521) (#3569) Co-authored-by: Andrii Sherman --- drizzle-orm/src/aws-data-api/pg/driver.ts | 44 +++++++++---------- drizzle-orm/src/better-sqlite3/driver.ts | 7 +-- drizzle-orm/src/bun-sqlite/driver.ts | 7 +-- drizzle-orm/src/libsql/driver.ts | 36 +++++++-------- drizzle-orm/src/libsql/http/index.ts | 36 +++++++-------- drizzle-orm/src/libsql/node/index.ts | 36 +++++++-------- drizzle-orm/src/libsql/sqlite3/index.ts | 36 +++++++-------- drizzle-orm/src/libsql/wasm/index.ts | 36 +++++++-------- drizzle-orm/src/libsql/web/index.ts | 36 +++++++-------- drizzle-orm/src/libsql/ws/index.ts | 36 +++++++-------- drizzle-orm/src/mysql2/driver.ts | 36 +++++++-------- drizzle-orm/src/neon-http/driver.ts | 36 +++++++-------- drizzle-orm/src/neon-serverless/driver.ts | 42 ++++++++---------- drizzle-orm/src/node-postgres/driver.ts | 7 +-- drizzle-orm/src/pglite/driver.ts | 7 +-- .../src/planetscale-serverless/driver.ts | 36 +++++++-------- drizzle-orm/src/postgres-js/driver.ts | 36 +++++++-------- drizzle-orm/src/tidb-serverless/driver.ts | 32 ++++++-------- drizzle-orm/src/vercel-postgres/driver.ts | 34 +++++++------- 19 files changed, 252 insertions(+), 324 deletions(-) diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index d1d68e7ac..eb05913e2 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -15,7 +15,7 @@ import { } from '~/relations.ts'; import { Param, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import { Table } from '~/table.ts'; -import type { DrizzleConfig, IfNotImported, ImportTypeError, UpdateSet } from '~/utils.ts'; +import type { DrizzleConfig, UpdateSet } from '~/utils.ts'; import type { AwsDataApiClient, AwsDataApiPgQueryResult, AwsDataApiPgQueryResultHKT } from './session.ts'; import { AwsDataApiSession } from './session.ts'; @@ -129,29 +129,25 @@ export function drizzle< TSchema extends Record = Record, TClient extends AwsDataApiClient = RDSDataClient, >( - ...params: IfNotImported< - RDSDataClientConfig, - [ImportTypeError<'@aws-sdk/client-rds-data'>], - [ - TClient, - DrizzleAwsDataApiPgConfig, - ] | [ - ( - | ( - & DrizzleConfig - & { - connection: RDSDataClientConfig & Omit; - } - ) - | ( - & DrizzleAwsDataApiPgConfig - & { - client: TClient; - } - ) - ), - ] - > + ...params: [ + TClient, + DrizzleAwsDataApiPgConfig, + ] | [ + ( + | ( + & DrizzleConfig + & { + connection: RDSDataClientConfig & Omit; + } + ) + | ( + & DrizzleAwsDataApiPgConfig + & { + client: TClient; + } + ) + ), + ] ): AwsDataApiPgDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index 0fe7364bd..68eac53ac 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -9,7 +9,7 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { BetterSQLiteSession } from './session.ts'; export type DrizzleBetterSQLite3DatabaseConfig = @@ -64,9 +64,7 @@ function construct = Record = Record, >( - ...params: IfNotImported< - Database, - [ImportTypeError<'better-sqlite3'>], + ...params: | [] | [ Database | string, @@ -85,7 +83,6 @@ export function drizzle< }) ), ] - > ): BetterSQLite3Database & { $client: Database; } { diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index 7510fe58e..9d2f9415b 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -11,7 +11,7 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { SQLiteBunSession } from './session.ts'; export class BunSQLiteDatabase< @@ -86,9 +86,7 @@ export function drizzle< TSchema extends Record = Record, TClient extends Database = Database, >( - ...params: IfNotImported< - Database, - [ImportTypeError<'bun-types'>], + ...params: | [] | [ TClient | string, @@ -107,7 +105,6 @@ export function drizzle< }) ), ] - > ): BunSQLiteDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/libsql/driver.ts b/drizzle-orm/src/libsql/driver.ts index bf0ef6662..b69a5d7bc 100644 --- a/drizzle-orm/src/libsql/driver.ts +++ b/drizzle-orm/src/libsql/driver.ts @@ -1,5 +1,5 @@ import { type Client, type Config, createClient } from '@libsql/client'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { construct as construct, type LibSQLDatabase } from './driver-core.ts'; export { LibSQLDatabase } from './driver-core.ts'; @@ -8,25 +8,21 @@ export function drizzle< TSchema extends Record = Record, TClient extends Client = Client, >( - ...params: IfNotImported< - Client, - [ImportTypeError<'@libsql/client'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - connection: string | Config; - } | { - client: TClient; - }) - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] ): LibSQLDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/libsql/http/index.ts b/drizzle-orm/src/libsql/http/index.ts index fddf910f5..1a07af6a8 100644 --- a/drizzle-orm/src/libsql/http/index.ts +++ b/drizzle-orm/src/libsql/http/index.ts @@ -1,30 +1,26 @@ import { type Client, type Config, createClient } from '@libsql/client/http'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { construct, type LibSQLDatabase } from '../driver-core.ts'; export function drizzle< TSchema extends Record = Record, TClient extends Client = Client, >( - ...params: IfNotImported< - Client, - [ImportTypeError<'@libsql/client'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - connection: string | Config; - } | { - client: TClient; - }) - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] ): LibSQLDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/libsql/node/index.ts b/drizzle-orm/src/libsql/node/index.ts index 003a5c899..bd6d5200d 100644 --- a/drizzle-orm/src/libsql/node/index.ts +++ b/drizzle-orm/src/libsql/node/index.ts @@ -1,30 +1,26 @@ import { type Client, type Config, createClient } from '@libsql/client/node'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { construct, type LibSQLDatabase } from '../driver-core.ts'; export function drizzle< TSchema extends Record = Record, TClient extends Client = Client, >( - ...params: IfNotImported< - Client, - [ImportTypeError<'@libsql/client'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - connection: string | Config; - } | { - client: TClient; - }) - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] ): LibSQLDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/libsql/sqlite3/index.ts b/drizzle-orm/src/libsql/sqlite3/index.ts index 0f17ef935..afb11f611 100644 --- a/drizzle-orm/src/libsql/sqlite3/index.ts +++ b/drizzle-orm/src/libsql/sqlite3/index.ts @@ -1,30 +1,26 @@ import { type Client, type Config, createClient } from '@libsql/client/sqlite3'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { construct, type LibSQLDatabase } from '../driver-core.ts'; export function drizzle< TSchema extends Record = Record, TClient extends Client = Client, >( - ...params: IfNotImported< - Client, - [ImportTypeError<'@libsql/client'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - connection: string | Config; - } | { - client: TClient; - }) - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] ): LibSQLDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/libsql/wasm/index.ts b/drizzle-orm/src/libsql/wasm/index.ts index 23c4f4dcc..a27a124b5 100644 --- a/drizzle-orm/src/libsql/wasm/index.ts +++ b/drizzle-orm/src/libsql/wasm/index.ts @@ -1,30 +1,26 @@ import { type Client, type Config, createClient } from '@libsql/client-wasm'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { construct, type LibSQLDatabase } from '../driver-core.ts'; export function drizzle< TSchema extends Record = Record, TClient extends Client = Client, >( - ...params: IfNotImported< - Client, - [ImportTypeError<'@libsql/client-wasm'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - connection: string | Config; - } | { - client: TClient; - }) - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] ): LibSQLDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/libsql/web/index.ts b/drizzle-orm/src/libsql/web/index.ts index e7c31c9bb..9b1e2c8e0 100644 --- a/drizzle-orm/src/libsql/web/index.ts +++ b/drizzle-orm/src/libsql/web/index.ts @@ -1,30 +1,26 @@ import { type Client, type Config, createClient } from '@libsql/client/web'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { construct, type LibSQLDatabase } from '../driver-core.ts'; export function drizzle< TSchema extends Record = Record, TClient extends Client = Client, >( - ...params: IfNotImported< - Client, - [ImportTypeError<'@libsql/client'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - connection: string | Config; - } | { - client: TClient; - }) - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] ): LibSQLDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/libsql/ws/index.ts b/drizzle-orm/src/libsql/ws/index.ts index 115ec9b24..645ff1a07 100644 --- a/drizzle-orm/src/libsql/ws/index.ts +++ b/drizzle-orm/src/libsql/ws/index.ts @@ -1,30 +1,26 @@ import { type Client, type Config, createClient } from '@libsql/client/ws'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { construct, type LibSQLDatabase } from '../driver-core.ts'; export function drizzle< TSchema extends Record = Record, TClient extends Client = Client, >( - ...params: IfNotImported< - Client, - [ImportTypeError<'@libsql/client'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - connection: string | Config; - } | { - client: TClient; - }) - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] ): LibSQLDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index ec791e571..381b4c9bb 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -12,7 +12,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { DrizzleError } from '../errors.ts'; import type { MySql2Client, MySql2PreparedQueryHKT, MySql2QueryResultHKT } from './session.ts'; import { MySql2Session } from './session.ts'; @@ -114,25 +114,21 @@ export function drizzle< TSchema extends Record = Record, TClient extends AnyMySql2Connection = CallbackPool, >( - ...params: IfNotImported< - CallbackPool, - [ImportTypeError<'mysql2'>], - [ - TClient | string, - ] | [ - TClient | string, - MySql2DrizzleConfig, - ] | [ - ( - & MySql2DrizzleConfig - & ({ - connection: string | PoolOptions; - } | { - client: TClient; - }) - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + MySql2DrizzleConfig, + ] | [ + ( + & MySql2DrizzleConfig + & ({ + connection: string | PoolOptions; + } | { + client: TClient; + }) + ), + ] ): MySql2Database & { $client: TClient; } { diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index 76ae5c426..cbe1689fb 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -8,7 +8,7 @@ import { PgDatabase } from '~/pg-core/db.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig } from '~/relations.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { type NeonHttpClient, type NeonHttpQueryResultHKT, NeonHttpSession } from './session.ts'; export interface NeonDriverOptions { @@ -158,25 +158,21 @@ export function drizzle< TSchema extends Record = Record, TClient extends NeonQueryFunction = NeonQueryFunction, >( - ...params: IfNotImported< - HTTPTransactionOptions, - [ImportTypeError<'@neondatabase/serverless'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - connection: string | ({ connectionString: string } & HTTPTransactionOptions); - } | { - client: TClient; - }) - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | ({ connectionString: string } & HTTPTransactionOptions); + } | { + client: TClient; + }) + ), + ] ): NeonHttpDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index a1975c78b..35d24d568 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import type { NeonClient, NeonQueryResultHKT } from './session.ts'; import { NeonSession } from './session.ts'; @@ -83,28 +83,24 @@ export function drizzle< TSchema extends Record = Record, TClient extends NeonClient = Pool, >( - ...params: IfNotImported< - Pool, - [ImportTypeError<'@neondatabase/serverless'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - connection: string | PoolConfig; - } | { - client: TClient; - }) - & { - ws?: any; - } - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | PoolConfig; + } | { + client: TClient; + }) + & { + ws?: any; + } + ), + ] ): NeonDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index 4b5b5eaab..e48d0e177 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import type { NodePgClient, NodePgQueryResultHKT } from './session.ts'; import { NodePgSession } from './session.ts'; @@ -83,9 +83,7 @@ export function drizzle< TSchema extends Record = Record, TClient extends NodePgClient = Pool, >( - ...params: IfNotImported< - Pool, - [ImportTypeError<'@types/pg` `pg'>], + ...params: | [ TClient | string, ] @@ -103,7 +101,6 @@ export function drizzle< }) ), ] - > ): NodePgDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/pglite/driver.ts b/drizzle-orm/src/pglite/driver.ts index ee6aaa252..7f35b2779 100644 --- a/drizzle-orm/src/pglite/driver.ts +++ b/drizzle-orm/src/pglite/driver.ts @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import type { PgliteClient, PgliteQueryResultHKT } from './session.ts'; import { PgliteSession } from './session.ts'; @@ -80,9 +80,7 @@ export function drizzle< TSchema extends Record = Record, TClient extends PGlite = PGlite, >( - ...params: IfNotImported< - PGlite, - [ImportTypeError<'@electric-sql/pglite'>], + ...params: | [] | [ TClient | string, @@ -101,7 +99,6 @@ export function drizzle< }) ), ] - > ): PgliteDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index e8309e10a..1ea8825cb 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -11,7 +11,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import type { PlanetScalePreparedQueryHKT, PlanetscaleQueryResultHKT } from './session.ts'; import { PlanetscaleSession } from './session.ts'; @@ -83,25 +83,21 @@ export function drizzle< TSchema extends Record = Record, TClient extends Client = Client, >( - ...params: IfNotImported< - Config, - [ImportTypeError<'@planetscale/database'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - connection: string | Config; - } | { - client: TClient; - }) - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | Config; + } | { + client: TClient; + }) + ), + ] ): PlanetScaleDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index 5d1ff6755..b6043f187 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -9,7 +9,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import type { PostgresJsQueryResultHKT } from './session.ts'; import { PostgresJsSession } from './session.ts'; @@ -67,25 +67,21 @@ export function drizzle< TSchema extends Record = Record, TClient extends Sql = Sql, >( - ...params: IfNotImported< - Options, - [ImportTypeError<'postgres'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - connection: string | ({ url?: string } & Options>); - } | { - client: TClient; - }) - ), - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + connection: string | ({ url?: string } & Options>); + } | { + client: TClient; + }) + ), + ] ): PostgresJsDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/tidb-serverless/driver.ts b/drizzle-orm/src/tidb-serverless/driver.ts index 62fbfb9ab..69b9a0e44 100644 --- a/drizzle-orm/src/tidb-serverless/driver.ts +++ b/drizzle-orm/src/tidb-serverless/driver.ts @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import type { TiDBServerlessPreparedQueryHKT, TiDBServerlessQueryResultHKT } from './session.ts'; import { TiDBServerlessSession } from './session.ts'; @@ -62,23 +62,19 @@ export function drizzle< TSchema extends Record = Record, TClient extends Connection = Connection, >( - ...params: IfNotImported< - Config, - [ImportTypeError<'@tidbcloud/serverless'>], - [ - TClient | string, - ] | [ - TClient | string, - DrizzleConfig, - ] | [ - & ({ - connection: string | Config; - } | { - client: TClient; - }) - & DrizzleConfig, - ] - > + ...params: [ + TClient | string, + ] | [ + TClient | string, + DrizzleConfig, + ] | [ + & ({ + connection: string | Config; + } | { + client: TClient; + }) + & DrizzleConfig, + ] ): TiDBServerlessDatabase & { $client: TClient; } { diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 44606a079..3a7788783 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -1,4 +1,4 @@ -import { sql, type VercelPool } from '@vercel/postgres'; +import { sql } from '@vercel/postgres'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import { type DrizzleConfig, isConfig } from '~/utils.ts'; import { type VercelPgClient, type VercelPgQueryResultHKT, VercelPgSession } from './session.ts'; export interface VercelPgDriverOptions { @@ -79,23 +79,19 @@ export function drizzle< TSchema extends Record = Record, TClient extends VercelPgClient = typeof sql, >( - ...params: IfNotImported< - VercelPool, - [ImportTypeError<'@vercel/postgres'>], - [] | [ - TClient, - ] | [ - TClient, - DrizzleConfig, - ] | [ - ( - & DrizzleConfig - & ({ - client?: TClient; - }) - ), - ] - > + ...params: [] | [ + TClient, + ] | [ + TClient, + DrizzleConfig, + ] | [ + ( + & DrizzleConfig + & ({ + client?: TClient; + }) + ), + ] ): VercelPgDatabase & { $client: TClient; } { From 3982324b34b34b937fde2f1a0bd181e700cd2273 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 22 Nov 2024 11:29:39 +0200 Subject: [PATCH 385/492] Fix float count issue --- drizzle-seed/src/services/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-seed/src/services/utils.ts b/drizzle-seed/src/services/utils.ts index 6f59fc63c..3316632b5 100644 --- a/drizzle-seed/src/services/utils.ts +++ b/drizzle-seed/src/services/utils.ts @@ -19,7 +19,7 @@ export const fastCartesianProduct = (sets: (number | string | boolean | object)[ * @returns Example: with weights = [0.2, 0.8] and accuracy = 10 returning array of indices gonna equal this: [0, 0, 1, 1, 1, 1, 1, 1, 1, 1] */ export const getWeightedIndices = (weights: number[], accuracy = 100) => { - const weightsSum = weights.reduce((acc, currVal) => acc + currVal, 0); + const weightsSum = Math.round(weights.reduce((acc, currVal) => acc + currVal, 0)); if (weightsSum !== 1) { throw new Error(`sum of all weights don't equal to 1; ${weightsSum} !== 1`); } From 6479912753e58f2c4cbfb7f3131bd97d6d521f5e Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 22 Nov 2024 11:55:08 +0200 Subject: [PATCH 386/492] Fix sum --- drizzle-seed/src/services/utils.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drizzle-seed/src/services/utils.ts b/drizzle-seed/src/services/utils.ts index 3316632b5..4e1446450 100644 --- a/drizzle-seed/src/services/utils.ts +++ b/drizzle-seed/src/services/utils.ts @@ -13,13 +13,19 @@ export const fastCartesianProduct = (sets: (number | string | boolean | object)[ return resultList; }; +const sumArray = (weights: number[]) => { + const scale = 1e10; + const scaledSum = weights.reduce((acc, currVal) => acc + Math.round(currVal * scale), 0); + return scaledSum / scale; +}; + /** * @param weights positive number in range [0, 1], that represents probabilities to choose index of array. Example: weights = [0.2, 0.8] * @param [accuracy=100] approximate number of elements in returning array * @returns Example: with weights = [0.2, 0.8] and accuracy = 10 returning array of indices gonna equal this: [0, 0, 1, 1, 1, 1, 1, 1, 1, 1] */ export const getWeightedIndices = (weights: number[], accuracy = 100) => { - const weightsSum = Math.round(weights.reduce((acc, currVal) => acc + currVal, 0)); + const weightsSum = sumArray(weights); if (weightsSum !== 1) { throw new Error(`sum of all weights don't equal to 1; ${weightsSum} !== 1`); } From 99b13173b6ed0a9b329ec317dbfd4c161d6484d5 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 22 Nov 2024 12:16:55 +0200 Subject: [PATCH 387/492] Fix error messages --- drizzle-seed/src/index.ts | 8 ++++++-- drizzle-seed/src/services/GeneratorsWrappers.ts | 12 ++++++------ drizzle-seed/src/services/utils.ts | 4 +++- .../src/tests/pg/generatorsTest/generators.test.ts | 8 +++++--- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 55d80243d..3f766e219 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -354,7 +354,9 @@ const seedFunc = async ( await seedSqlite(db, sqliteSchema, options, refinements); } else { - throw new Error('given db is not supported.'); + throw new Error( + 'The drizzle-seed package currently supports only PostgreSQL, MySQL, and SQLite databases. Please ensure your database is one of these supported types', + ); } return; @@ -434,7 +436,9 @@ export async function reset< await resetSqlite(db, sqliteSchema); } } else { - throw new Error('given db is not supported.'); + throw new Error( + 'The drizzle-seed package currently supports only PostgreSQL, MySQL, and SQLite databases. Please ensure your database is one of these supported types', + ); } } diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts index 266c0277b..ae2d1d47d 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -130,14 +130,14 @@ export class GenerateValuesFromArray extends AbstractGenerator< const { values } = this.params; const { maxRepeatedValuesCount, notNull, isUnique } = this; if (values.length === 0) { - throw new Error('values length equals zero.'); + throw new Error('Values length equals zero.'); } if ( typeof values[0] === 'object' && !(values as { weight: number; values: any[] }[]).every((val) => val.values.length !== 0) ) { - throw new Error('one of weighted values length equals zero.'); + throw new Error('One of weighted values length equals zero.'); } if ( @@ -169,7 +169,7 @@ export class GenerateValuesFromArray extends AbstractGenerator< && maxRepeatedValuesCount * allValuesCount < count) ) ) { - throw new Error("(maxRepeatedValuesCount * values.length) < count. can't fill notNull column with null values."); + throw new Error("Can't fill notNull column with null values."); } if ( @@ -183,7 +183,7 @@ export class GenerateValuesFromArray extends AbstractGenerator< )) ) ) { - throw new Error("maxRepeatedValuesCount can't be greater than 1 if column is unique."); + throw new Error("Can't be greater than 1 if column is unique."); } if ( @@ -193,14 +193,14 @@ export class GenerateValuesFromArray extends AbstractGenerator< ) ) { // console.log(maxRepeatedValuesCount, values.length, allValuesCount, count) - throw new Error('there are no enough values to fill unique column.'); + throw new Error('There are no enough values to fill unique column.'); } } init({ count, seed }: { count: number; seed: number }) { if (this.params.isUnique !== undefined) { if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); + throw new Error('Specifying non unique generator to unique column.'); } this.isUnique = this.params.isUnique; diff --git a/drizzle-seed/src/services/utils.ts b/drizzle-seed/src/services/utils.ts index 4e1446450..8ce3db04f 100644 --- a/drizzle-seed/src/services/utils.ts +++ b/drizzle-seed/src/services/utils.ts @@ -27,7 +27,9 @@ const sumArray = (weights: number[]) => { export const getWeightedIndices = (weights: number[], accuracy = 100) => { const weightsSum = sumArray(weights); if (weightsSum !== 1) { - throw new Error(`sum of all weights don't equal to 1; ${weightsSum} !== 1`); + throw new Error( + `The weights for the Weighted Random feature must add up to exactly 1. Please review your weights to ensure they total 1 before proceeding`, + ); } // const accuracy = 100; diff --git a/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts b/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts index 1e01d0453..575b7a69a 100644 --- a/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts +++ b/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts @@ -531,7 +531,7 @@ test('valuesFromArray unique generator test', async () => { }, }, })), - ).rejects.toThrow('there are no enough values to fill unique column.'); + ).rejects.toThrow('There are no enough values to fill unique column.'); await expect( seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }, { seed: 1 }).refine((funcs) => ({ @@ -552,7 +552,7 @@ test('valuesFromArray unique generator test', async () => { }, }, })), - ).rejects.toThrow('there are no enough values to fill unique column.'); + ).rejects.toThrow('There are no enough values to fill unique column.'); }); test('intPrimaryKey generator test', async () => { @@ -1368,5 +1368,7 @@ test('weightedRandom with unique gens generator test', async () => { }, }, })), - ).rejects.toThrow("sum of all weights don't equal to 1; 1.1 !== 1"); + ).rejects.toThrow( + 'The weights for the Weighted Random feature must add up to exactly 1. Please review your weights to ensure they total 1 before proceeding', + ); }); From 03f6239c53c7132cf8ef08ff4f0cf70a1009de3f Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 22 Nov 2024 13:02:05 +0200 Subject: [PATCH 388/492] Fix tests --- integration-tests/tests/seeder/pg.test.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/integration-tests/tests/seeder/pg.test.ts b/integration-tests/tests/seeder/pg.test.ts index 33cd06f7e..3ca75704a 100644 --- a/integration-tests/tests/seeder/pg.test.ts +++ b/integration-tests/tests/seeder/pg.test.ts @@ -934,7 +934,7 @@ test('valuesFromArray unique generator test', async () => { }, }, })), - ).rejects.toThrow('there are no enough values to fill unique column.'); + ).rejects.toThrow('There are no enough values to fill unique column.'); await expect( seed(db, { valuesFromArrayUniqueTable: schema.valuesFromArrayUniqueTable }, { seed: 1 }).refine((funcs) => ({ @@ -955,7 +955,7 @@ test('valuesFromArray unique generator test', async () => { }, }, })), - ).rejects.toThrow('there are no enough values to fill unique column.'); + ).rejects.toThrow('There are no enough values to fill unique column.'); }); test('intPrimaryKey generator test', async () => { @@ -1771,5 +1771,7 @@ test('weightedRandom with unique gens generator test', async () => { }, }, })), - ).rejects.toThrow("sum of all weights don't equal to 1; 1.1 !== 1"); + ).rejects.toThrow( + 'The weights for the Weighted Random feature must add up to exactly 1. Please review your weights to ensure they total 1 before proceeding', + ); }); From 59979c36bddfb5a84dd31d952d13af2a7fc667a2 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 25 Nov 2024 10:16:47 +0200 Subject: [PATCH 389/492] Fixes for kit singlestore --- drizzle-kit/src/sqlgenerator.ts | 6 ++-- drizzle-kit/tests/push/common.ts | 2 +- drizzle-kit/tests/push/singlestore.test.ts | 32 ++++++++++--------- drizzle-kit/vitest.config.ts | 8 ++--- .../src/singlestore-core/columns/decimal.ts | 27 ++++++++++------ 5 files changed, 43 insertions(+), 32 deletions(-) diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index bf43fde1b..a35c001fd 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -3041,9 +3041,9 @@ class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { ? `"${statement.schema}"."${statement.tableName}"` : `"${statement.tableName}"`; - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT ${statement.oldConstraintName};\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newConstraintName} PRIMARY KEY(${ - newColumns.join(',') - });`; + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.oldConstraintName}";\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.newConstraintName}" PRIMARY KEY("${ + newColumns.join('","') + }");`; } } diff --git a/drizzle-kit/tests/push/common.ts b/drizzle-kit/tests/push/common.ts index 627070f11..848170359 100644 --- a/drizzle-kit/tests/push/common.ts +++ b/drizzle-kit/tests/push/common.ts @@ -31,7 +31,7 @@ export const run = ( beforeEach(beforeEachFn ? () => beforeEachFn(context) : () => {}); - test('No diffs for all database types', () => suite.allTypes(context)); + test.only('No diffs for all database types', () => suite.allTypes(context)); test('Adding basic indexes', () => suite.addBasicIndexes(context)); test('Dropping basic index', () => suite.dropIndex(context)); test('Altering indexes', () => suite.changeIndexFields(context)); diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 824f78576..a450f415a 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -1,5 +1,5 @@ import Docker from 'dockerode'; -import { sql } from 'drizzle-orm'; +import { SQL, sql } from 'drizzle-orm'; import { bigint, binary, @@ -10,8 +10,10 @@ import { double, float, int, + json, mediumint, primaryKey, + serial, singlestoreEnum, singlestoreTable, smallint, @@ -82,15 +84,15 @@ const singlestoreSuite: DialectSuite = { 'h', ), }), - allDateTimes: singlestoreTable('all_date_times', { - simple: datetime('simple', { mode: 'string', fsp: 0 }), - columnNotNull: datetime('column_not_null', { - mode: 'string', - }).notNull(), - columnDefault: datetime('column_default', { mode: 'string' }).default( - '2023-03-01 14:05:29', - ), - }), + // allDateTimes: singlestoreTable("all_date_times", { + // simple: datetime("simple", { mode: "string", fsp: 1 }), + // columnNotNull: datetime("column_not_null", { + // mode: "string", + // }).notNull(), + // columnDefault: datetime("column_default", { mode: "string" }).default( + // "2023-03-01 14:05:29" + // ), + // }), allDates: singlestoreTable('all_dates', { simple: date('simple', { mode: 'string' }), column_not_null: date('column_not_null', { mode: 'string' }).notNull(), @@ -207,10 +209,10 @@ const singlestoreSuite: DialectSuite = { }), allTimestamps: singlestoreTable('all_timestamps', { - columnDateNow: timestamp('column_date_now', { - fsp: 0, - mode: 'string', - }).default(sql`CURRENT_TIMESTAMP`), + // columnDateNow: timestamp("column_date_now", { + // fsp: 1, + // mode: "string", + // }).default(sql`(now())`), columnAll: timestamp('column_all', { mode: 'string' }) .default('2023-03-01 14:05:29') .notNull(), @@ -257,7 +259,7 @@ const singlestoreSuite: DialectSuite = { 'drizzle', false, ); - + console.log(statements); expect(statements.length).toBe(0); expect(statements).toEqual([]); diff --git a/drizzle-kit/vitest.config.ts b/drizzle-kit/vitest.config.ts index 8667511aa..fd728eb11 100644 --- a/drizzle-kit/vitest.config.ts +++ b/drizzle-kit/vitest.config.ts @@ -6,10 +6,10 @@ export default defineConfig({ include: [ 'tests/**/*.test.ts', // Need to test it first before pushing changes - 'tests/singlestore-schemas.test.ts', - 'tests/singlestore-views.test.ts', - 'tests/push/singlestore-push.test.ts', - 'tests/push/singlestore.test.ts', + // 'tests/singlestore-schemas.test.ts', + // 'tests/singlestore-views.test.ts', + // 'tests/push/singlestore-push.test.ts', + // 'tests/push/singlestore.test.ts', ], // This one was excluded because we need to modify an API for SingleStore-generated columns. diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts index 7c10dc83f..a77eb7a27 100644 --- a/drizzle-orm/src/singlestore-core/columns/decimal.ts +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -24,11 +24,14 @@ export type SingleStoreDecimalBuilderInitial = SingleStore export class SingleStoreDecimalBuilder< T extends ColumnBuilderBaseConfig<'string', 'SingleStoreDecimal'>, -> extends SingleStoreColumnBuilderWithAutoIncrement { - // eslint-disable-next-line @typescript-eslint/no-unused-vars +> extends SingleStoreColumnBuilderWithAutoIncrement< + T, + SingleStoreDecimalConfig +> { + /** @internal */ override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, + _as: T['data'] | SQL | (() => SQL), + _config?: Partial>, ): HasGenerated { throw new Error('Method not implemented.'); } @@ -52,9 +55,9 @@ export class SingleStoreDecimalBuilder< } } -export class SingleStoreDecimal> - extends SingleStoreColumnWithAutoIncrement -{ +export class SingleStoreDecimal< + T extends ColumnBaseConfig<'string', 'SingleStoreDecimal'>, +> extends SingleStoreColumnWithAutoIncrement { static override readonly [entityKind]: string = 'SingleStoreDecimal'; readonly precision: number | undefined = this.config.precision; @@ -89,7 +92,13 @@ export function decimal( name: TName, config?: SingleStoreDecimalConfig, ): SingleStoreDecimalBuilderInitial; -export function decimal(a?: string | SingleStoreDecimalConfig, b: SingleStoreDecimalConfig = {}) { - const { name, config } = getColumnNameAndConfig(a, b); +export function decimal( + a?: string | SingleStoreDecimalConfig, + b: SingleStoreDecimalConfig = {}, +) { + const { name, config } = getColumnNameAndConfig( + a, + b, + ); return new SingleStoreDecimalBuilder(name, config); } From 19baeea564ab6ee23514b53ae7c67b5140aeb62d Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 25 Nov 2024 16:56:06 +0200 Subject: [PATCH 390/492] Remove unsupported API --- .../src/singlestore-core/columns/bigint.ts | 23 +-------- .../src/singlestore-core/columns/binary.ts | 16 +------ .../src/singlestore-core/columns/boolean.ts | 16 +------ .../src/singlestore-core/columns/char.ts | 16 +------ .../src/singlestore-core/columns/common.ts | 7 ++- .../src/singlestore-core/columns/custom.ts | 15 +----- .../src/singlestore-core/columns/date.ts | 23 +-------- .../src/singlestore-core/columns/datetime.ts | 41 ++++++---------- .../src/singlestore-core/columns/decimal.ts | 16 +------ .../src/singlestore-core/columns/double.ts | 16 +------ .../src/singlestore-core/columns/float.ts | 16 +------ .../src/singlestore-core/columns/int.ts | 16 +------ .../src/singlestore-core/columns/json.ts | 16 +------ .../src/singlestore-core/columns/mediumint.ts | 16 +------ .../src/singlestore-core/columns/real.ts | 16 +------ .../src/singlestore-core/columns/serial.ts | 10 ---- .../src/singlestore-core/columns/smallint.ts | 16 +------ .../src/singlestore-core/columns/text.ts | 16 +------ .../src/singlestore-core/columns/time.ts | 46 +++--------------- .../src/singlestore-core/columns/timestamp.ts | 48 +++---------------- .../src/singlestore-core/columns/tinyint.ts | 16 +------ .../src/singlestore-core/columns/varbinary.ts | 16 +------ .../src/singlestore-core/columns/varchar.ts | 16 +------ .../src/singlestore-core/columns/year.ts | 16 +------ drizzle-orm/src/singlestore-core/view.ts | 47 +++++++++--------- drizzle-orm/type-tests/singlestore/tables.ts | 12 ++--- .../tests/singlestore/singlestore-common.ts | 20 ++++---- .../singlestore/singlestore-custom.test.ts | 8 ++-- .../singlestore/singlestore-prefixed.test.ts | 8 ++-- 29 files changed, 98 insertions(+), 466 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/bigint.ts b/drizzle-orm/src/singlestore-core/columns/bigint.ts index c29c531fa..1e6b64c49 100644 --- a/drizzle-orm/src/singlestore-core/columns/bigint.ts +++ b/drizzle-orm/src/singlestore-core/columns/bigint.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; @@ -25,13 +18,6 @@ export type SingleStoreBigInt53BuilderInitial = SingleStor export class SingleStoreBigInt53Builder> extends SingleStoreColumnBuilderWithAutoIncrement { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreBigInt53Builder'; constructor(name: T['name'], unsigned: boolean = false) { @@ -80,13 +66,6 @@ export type SingleStoreBigInt64BuilderInitial = SingleStor export class SingleStoreBigInt64Builder> extends SingleStoreColumnBuilderWithAutoIncrement { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreBigInt64Builder'; constructor(name: T['name'], unsigned: boolean = false) { diff --git a/drizzle-orm/src/singlestore-core/columns/binary.ts b/drizzle-orm/src/singlestore-core/columns/binary.ts index 4d5f65fc0..153456447 100644 --- a/drizzle-orm/src/singlestore-core/columns/binary.ts +++ b/drizzle-orm/src/singlestore-core/columns/binary.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -28,13 +21,6 @@ export class SingleStoreBinaryBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreBinaryBuilder'; constructor(name: T['name'], length: number | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/boolean.ts b/drizzle-orm/src/singlestore-core/columns/boolean.ts index b02d3741f..bf48ff1da 100644 --- a/drizzle-orm/src/singlestore-core/columns/boolean.ts +++ b/drizzle-orm/src/singlestore-core/columns/boolean.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreBooleanBuilderInitial = SingleStoreBooleanBuilder<{ @@ -24,13 +17,6 @@ export type SingleStoreBooleanBuilderInitial = SingleStore export class SingleStoreBooleanBuilder> extends SingleStoreColumnBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreBooleanBuilder'; constructor(name: T['name']) { diff --git a/drizzle-orm/src/singlestore-core/columns/char.ts b/drizzle-orm/src/singlestore-core/columns/char.ts index 3a5603e00..512460f92 100644 --- a/drizzle-orm/src/singlestore-core/columns/char.ts +++ b/drizzle-orm/src/singlestore-core/columns/char.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -29,13 +22,6 @@ export class SingleStoreCharBuilder > { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreCharBuilder'; constructor(name: T['name'], config: SingleStoreCharConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts index 2c4d6528a..ef494a4c1 100644 --- a/drizzle-orm/src/singlestore-core/columns/common.ts +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -5,6 +5,7 @@ import type { ColumnBuilderRuntimeConfig, ColumnDataType, HasDefault, + HasGenerated, IsAutoincrement, MakeColumnConfig, } from '~/column-builder.ts'; @@ -13,6 +14,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { Column } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable, SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/sql.ts'; import type { Update } from '~/utils.ts'; import { uniqueKeyName } from '../unique-constraint.ts'; @@ -44,14 +46,15 @@ export abstract class SingleStoreColumnBuilder< } // TODO: Implement generated columns for SingleStore (https://docs.singlestore.com/cloud/create-a-database/using-persistent-computed-columns/) - /* generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SingleStoreGeneratedColumnConfig): HasGenerated { + /** @internal */ + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SingleStoreGeneratedColumnConfig): HasGenerated { this.config.generated = { as, type: 'always', mode: config?.mode ?? 'virtual', }; return this as any; - } */ + } /** @internal */ abstract build( diff --git a/drizzle-orm/src/singlestore-core/columns/custom.ts b/drizzle-orm/src/singlestore-core/columns/custom.ts index dec4574ed..964e077d7 100644 --- a/drizzle-orm/src/singlestore-core/columns/custom.ts +++ b/drizzle-orm/src/singlestore-core/columns/custom.ts @@ -1,10 +1,4 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; @@ -41,13 +35,6 @@ export class SingleStoreCustomColumnBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreCustomColumnBuilder'; constructor( diff --git a/drizzle-orm/src/singlestore-core/columns/date.ts b/drizzle-orm/src/singlestore-core/columns/date.ts index 62d31d761..70da74f3a 100644 --- a/drizzle-orm/src/singlestore-core/columns/date.ts +++ b/drizzle-orm/src/singlestore-core/columns/date.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -25,13 +18,6 @@ export type SingleStoreDateBuilderInitial = SingleStoreDat export class SingleStoreDateBuilder> extends SingleStoreColumnBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreDateBuilder'; constructor(name: T['name']) { @@ -81,13 +67,6 @@ export type SingleStoreDateStringBuilderInitial = SingleSt export class SingleStoreDateStringBuilder> extends SingleStoreColumnBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreDateStringBuilder'; constructor(name: T['name']) { diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts index bacffa1c3..16f137901 100644 --- a/drizzle-orm/src/singlestore-core/columns/datetime.ts +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -25,18 +25,18 @@ export type SingleStoreDateTimeBuilderInitial = SingleStor export class SingleStoreDateTimeBuilder> extends SingleStoreColumnBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars + /** @internal */ + // TODO: we need to add a proper support for SingleStore override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, + _as: SQL | (() => SQL) | T['data'], + _config?: Partial>, ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreDateTimeBuilder'; - constructor(name: T['name'], config: SingleStoreDatetimeConfig | undefined) { + constructor(name: T['name']) { super(name, 'date', 'SingleStoreDateTime'); - this.config.fsp = config?.fsp; } /** @internal */ @@ -55,20 +55,15 @@ export class SingleStoreDateTime, config: SingleStoreDateTimeBuilder['config'], ) { super(table, config); - this.fsp = config.fsp; } getSQLType(): string { - const hidePrecision = this.fsp === undefined || this.fsp === 0; - const precision = hidePrecision ? '' : `(${this.fsp})`; - return `datetime${precision}`; + return `datetime`; } override mapToDriverValue(value: Date): unknown { @@ -93,18 +88,18 @@ export type SingleStoreDateTimeStringBuilderInitial = Sing export class SingleStoreDateTimeStringBuilder> extends SingleStoreColumnBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars + /** @internal */ + // TODO: we need to add a proper support for SingleStore override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, + _as: SQL | (() => SQL) | T['data'], + _config?: Partial>, ): HasGenerated { throw new Error('Method not implemented.'); } static override readonly [entityKind]: string = 'SingleStoreDateTimeStringBuilder'; - constructor(name: T['name'], config: SingleStoreDatetimeConfig | undefined) { + constructor(name: T['name']) { super(name, 'string', 'SingleStoreDateTimeString'); - this.config.fsp = config?.fsp; } /** @internal */ @@ -123,28 +118,20 @@ export class SingleStoreDateTimeString, config: SingleStoreDateTimeStringBuilder['config'], ) { super(table, config); - this.fsp = config.fsp; } getSQLType(): string { - const hidePrecision = this.fsp === undefined || this.fsp === 0; - const precision = hidePrecision ? '' : `(${this.fsp})`; - return `datetime${precision}`; + return `datetime`; } } -export type DatetimeFsp = 0 | 1 | 2 | 3 | 4 | 5 | 6; - export interface SingleStoreDatetimeConfig { mode?: TMode; - fsp?: DatetimeFsp; } export function datetime(): SingleStoreDateTimeBuilderInitial<''>; @@ -160,7 +147,7 @@ export function datetime(a, b); if (config?.mode === 'string') { - return new SingleStoreDateTimeStringBuilder(name, config); + return new SingleStoreDateTimeStringBuilder(name); } - return new SingleStoreDateTimeBuilder(name, config); + return new SingleStoreDateTimeBuilder(name); } diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts index a77eb7a27..d0c61732c 100644 --- a/drizzle-orm/src/singlestore-core/columns/decimal.ts +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; @@ -28,13 +21,6 @@ export class SingleStoreDecimalBuilder< T, SingleStoreDecimalConfig > { - /** @internal */ - override generatedAlwaysAs( - _as: T['data'] | SQL | (() => SQL), - _config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreDecimalBuilder'; constructor(name: T['name'], config: SingleStoreDecimalConfig | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/double.ts b/drizzle-orm/src/singlestore-core/columns/double.ts index bf19d49c0..103731eab 100644 --- a/drizzle-orm/src/singlestore-core/columns/double.ts +++ b/drizzle-orm/src/singlestore-core/columns/double.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; @@ -25,13 +18,6 @@ export type SingleStoreDoubleBuilderInitial = SingleStoreD export class SingleStoreDoubleBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: T['data'] | SQL | (() => SQL), - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreDoubleBuilder'; constructor(name: T['name'], config: SingleStoreDoubleConfig | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts index 6d6075ca6..9cfed6131 100644 --- a/drizzle-orm/src/singlestore-core/columns/float.ts +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; @@ -25,13 +18,6 @@ export type SingleStoreFloatBuilderInitial = SingleStoreFl export class SingleStoreFloatBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreFloatBuilder'; constructor(name: T['name'], config: SingleStoreFloatConfig | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/int.ts b/drizzle-orm/src/singlestore-core/columns/int.ts index 5a7ab2167..b6a661f66 100644 --- a/drizzle-orm/src/singlestore-core/columns/int.ts +++ b/drizzle-orm/src/singlestore-core/columns/int.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; @@ -25,13 +18,6 @@ export type SingleStoreIntBuilderInitial = SingleStoreIntB export class SingleStoreIntBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreIntBuilder'; constructor(name: T['name'], config?: SingleStoreIntConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/json.ts b/drizzle-orm/src/singlestore-core/columns/json.ts index cdacbac82..97ff759d1 100644 --- a/drizzle-orm/src/singlestore-core/columns/json.ts +++ b/drizzle-orm/src/singlestore-core/columns/json.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreJsonBuilderInitial = SingleStoreJsonBuilder<{ @@ -24,13 +17,6 @@ export type SingleStoreJsonBuilderInitial = SingleStoreJso export class SingleStoreJsonBuilder> extends SingleStoreColumnBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: T['data'] | SQL | (() => SQL), - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreJsonBuilder'; constructor(name: T['name']) { diff --git a/drizzle-orm/src/singlestore-core/columns/mediumint.ts b/drizzle-orm/src/singlestore-core/columns/mediumint.ts index 7231e58ff..4a5fa80f9 100644 --- a/drizzle-orm/src/singlestore-core/columns/mediumint.ts +++ b/drizzle-orm/src/singlestore-core/columns/mediumint.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; @@ -26,13 +19,6 @@ export type SingleStoreMediumIntBuilderInitial = SingleSto export class SingleStoreMediumIntBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreMediumIntBuilder'; constructor(name: T['name'], config?: SingleStoreIntConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/real.ts b/drizzle-orm/src/singlestore-core/columns/real.ts index 4ba09c200..53d15345c 100644 --- a/drizzle-orm/src/singlestore-core/columns/real.ts +++ b/drizzle-orm/src/singlestore-core/columns/real.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; @@ -28,13 +21,6 @@ export class SingleStoreRealBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreRealBuilder'; constructor(name: T['name'], config: SingleStoreRealConfig | undefined) { diff --git a/drizzle-orm/src/singlestore-core/columns/serial.ts b/drizzle-orm/src/singlestore-core/columns/serial.ts index 4b7a618e0..df415d47e 100644 --- a/drizzle-orm/src/singlestore-core/columns/serial.ts +++ b/drizzle-orm/src/singlestore-core/columns/serial.ts @@ -1,9 +1,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, HasDefault, - HasGenerated, IsAutoincrement, IsPrimaryKey, MakeColumnConfig, @@ -12,7 +10,6 @@ import type { import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; export type SingleStoreSerialBuilderInitial = IsAutoincrement< @@ -36,13 +33,6 @@ export type SingleStoreSerialBuilderInitial = IsAutoincrem export class SingleStoreSerialBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreSerialBuilder'; constructor(name: T['name']) { diff --git a/drizzle-orm/src/singlestore-core/columns/smallint.ts b/drizzle-orm/src/singlestore-core/columns/smallint.ts index 4011662e0..3f504b68c 100644 --- a/drizzle-orm/src/singlestore-core/columns/smallint.ts +++ b/drizzle-orm/src/singlestore-core/columns/smallint.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; @@ -26,13 +19,6 @@ export type SingleStoreSmallIntBuilderInitial = SingleStor export class SingleStoreSmallIntBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreSmallIntBuilder'; constructor(name: T['name'], config?: SingleStoreIntConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/text.ts b/drizzle-orm/src/singlestore-core/columns/text.ts index d69728375..425da550f 100644 --- a/drizzle-orm/src/singlestore-core/columns/text.ts +++ b/drizzle-orm/src/singlestore-core/columns/text.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -31,13 +24,6 @@ export class SingleStoreTextBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreTextBuilder'; constructor(name: T['name'], textType: SingleStoreTextColumnType, config: SingleStoreTextConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/time.ts b/drizzle-orm/src/singlestore-core/columns/time.ts index 405700177..b7605a4ee 100644 --- a/drizzle-orm/src/singlestore-core/columns/time.ts +++ b/drizzle-orm/src/singlestore-core/columns/time.ts @@ -1,15 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; -import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreTimeBuilderInitial = SingleStoreTimeBuilder<{ @@ -24,25 +16,15 @@ export type SingleStoreTimeBuilderInitial = SingleStoreTim export class SingleStoreTimeBuilder> extends SingleStoreColumnBuilder< - T, - TimeConfig + T > { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreTimeBuilder'; constructor( name: T['name'], - config: TimeConfig | undefined, ) { super(name, 'string', 'SingleStoreTime'); - this.config.fsp = config?.fsp; } /** @internal */ @@ -58,30 +40,16 @@ export class SingleStoreTimeBuilder, -> extends SingleStoreColumn { +> extends SingleStoreColumn { static override readonly [entityKind]: string = 'SingleStoreTime'; - readonly fsp: number | undefined = this.config.fsp; - getSQLType(): string { - const precision = this.fsp === undefined ? '' : `(${this.fsp})`; - return `time${precision}`; + return `time`; } } -export type TimeConfig = { - fsp?: 0 | 1 | 2 | 3 | 4 | 5 | 6; -}; - export function time(): SingleStoreTimeBuilderInitial<''>; -export function time( - config?: TimeConfig, -): SingleStoreTimeBuilderInitial<''>; -export function time( - name: TName, - config?: TimeConfig, -): SingleStoreTimeBuilderInitial; -export function time(a?: string | TimeConfig, b?: TimeConfig) { - const { name, config } = getColumnNameAndConfig(a, b); - return new SingleStoreTimeBuilder(name, config); +export function time(name: TName): SingleStoreTimeBuilderInitial; +export function time(name?: string) { + return new SingleStoreTimeBuilder(name ?? ''); } diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts index 17d76fb0f..ea7342fd7 100644 --- a/drizzle-orm/src/singlestore-core/columns/timestamp.ts +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/sql.ts'; import { sql } from '~/sql/sql.ts'; import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreDateBaseColumn, SingleStoreDateColumnBaseBuilder } from './date.common.ts'; @@ -26,18 +19,10 @@ export type SingleStoreTimestampBuilderInitial = SingleSto export class SingleStoreTimestampBuilder> extends SingleStoreDateColumnBaseBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreTimestampBuilder'; - constructor(name: T['name'], config: SingleStoreTimestampConfig | undefined) { + constructor(name: T['name']) { super(name, 'date', 'SingleStoreTimestamp'); - this.config.fsp = config?.fsp; } /** @internal */ @@ -60,12 +45,8 @@ export class SingleStoreTimestamp = Sin export class SingleStoreTimestampStringBuilder< T extends ColumnBuilderBaseConfig<'string', 'SingleStoreTimestampString'>, > extends SingleStoreDateColumnBaseBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreTimestampStringBuilder'; - constructor(name: T['name'], config: SingleStoreTimestampConfig | undefined) { + constructor(name: T['name']) { super(name, 'string', 'SingleStoreTimestampString'); - this.config.fsp = config?.fsp; } /** @internal */ @@ -124,20 +97,13 @@ export class SingleStoreTimestampString { mode?: TMode; - fsp?: TimestampFsp; } export function timestamp(): SingleStoreTimestampBuilderInitial<''>; @@ -153,7 +119,7 @@ export function timestamp(a, b); if (config?.mode === 'string') { - return new SingleStoreTimestampStringBuilder(name, config); + return new SingleStoreTimestampStringBuilder(name); } - return new SingleStoreTimestampBuilder(name, config); + return new SingleStoreTimestampBuilder(name); } diff --git a/drizzle-orm/src/singlestore-core/columns/tinyint.ts b/drizzle-orm/src/singlestore-core/columns/tinyint.ts index a25b89a6d..090619a6d 100644 --- a/drizzle-orm/src/singlestore-core/columns/tinyint.ts +++ b/drizzle-orm/src/singlestore-core/columns/tinyint.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; import type { SingleStoreIntConfig } from './int.ts'; @@ -26,13 +19,6 @@ export type SingleStoreTinyIntBuilderInitial = SingleStore export class SingleStoreTinyIntBuilder> extends SingleStoreColumnBuilderWithAutoIncrement { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreTinyIntBuilder'; constructor(name: T['name'], config?: SingleStoreIntConfig) { diff --git a/drizzle-orm/src/singlestore-core/columns/varbinary.ts b/drizzle-orm/src/singlestore-core/columns/varbinary.ts index 0b0323784..c55aa8071 100644 --- a/drizzle-orm/src/singlestore-core/columns/varbinary.ts +++ b/drizzle-orm/src/singlestore-core/columns/varbinary.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -25,13 +18,6 @@ export type SingleStoreVarBinaryBuilderInitial = SingleSto export class SingleStoreVarBinaryBuilder> extends SingleStoreColumnBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreVarBinaryBuilder'; /** @internal */ diff --git a/drizzle-orm/src/singlestore-core/columns/varchar.ts b/drizzle-orm/src/singlestore-core/columns/varchar.ts index 82f232c29..2c39491d7 100644 --- a/drizzle-orm/src/singlestore-core/columns/varchar.ts +++ b/drizzle-orm/src/singlestore-core/columns/varchar.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; @@ -28,13 +21,6 @@ export type SingleStoreVarCharBuilderInitial> extends SingleStoreColumnBuilder> { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreVarCharBuilder'; /** @internal */ diff --git a/drizzle-orm/src/singlestore-core/columns/year.ts b/drizzle-orm/src/singlestore-core/columns/year.ts index a6ab07e30..37f3d55a3 100644 --- a/drizzle-orm/src/singlestore-core/columns/year.ts +++ b/drizzle-orm/src/singlestore-core/columns/year.ts @@ -1,14 +1,7 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - GeneratedColumnConfig, - HasGenerated, - MakeColumnConfig, -} from '~/column-builder.ts'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; export type SingleStoreYearBuilderInitial = SingleStoreYearBuilder<{ @@ -24,13 +17,6 @@ export type SingleStoreYearBuilderInitial = SingleStoreYea export class SingleStoreYearBuilder> extends SingleStoreColumnBuilder { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - override generatedAlwaysAs( - as: SQL | (() => SQL) | T['data'], - config?: Partial>, - ): HasGenerated { - throw new Error('Method not implemented.'); - } static override readonly [entityKind]: string = 'SingleStoreYearBuilder'; constructor(name: T['name']) { diff --git a/drizzle-orm/src/singlestore-core/view.ts b/drizzle-orm/src/singlestore-core/view.ts index ce0fe4dd3..58f111428 100644 --- a/drizzle-orm/src/singlestore-core/view.ts +++ b/drizzle-orm/src/singlestore-core/view.ts @@ -183,26 +183,27 @@ export type SingleStoreViewWithSelection< TSelectedFields extends ColumnsSelection, > = SingleStoreView & TSelectedFields; -/** @internal */ -export function singlestoreViewWithSchema( - name: string, - selection: Record | undefined, - schema: string | undefined, -): ViewBuilder | ManualViewBuilder { - if (selection) { - return new ManualViewBuilder(name, selection, schema); - } - return new ViewBuilder(name, schema); -} - -export function singlestoreView(name: TName): ViewBuilder; -export function singlestoreView>( - name: TName, - columns: TColumns, -): ManualViewBuilder; -export function singlestoreView( - name: string, - selection?: Record, -): ViewBuilder | ManualViewBuilder { - return singlestoreViewWithSchema(name, selection, undefined); -} +// TODO: needs to be implemented differently compared to MySQL. +// /** @internal */ +// export function singlestoreViewWithSchema( +// name: string, +// selection: Record | undefined, +// schema: string | undefined, +// ): ViewBuilder | ManualViewBuilder { +// if (selection) { +// return new ManualViewBuilder(name, selection, schema); +// } +// return new ViewBuilder(name, schema); +// } + +// export function singlestoreView(name: TName): ViewBuilder; +// export function singlestoreView>( +// name: TName, +// columns: TColumns, +// ): ManualViewBuilder; +// export function singlestoreView( +// name: string, +// selection?: Record, +// ): ViewBuilder | ManualViewBuilder { +// return singlestoreViewWithSchema(name, selection, undefined); +// } diff --git a/drizzle-orm/type-tests/singlestore/tables.ts b/drizzle-orm/type-tests/singlestore/tables.ts index 5d63cf410..1df4861af 100644 --- a/drizzle-orm/type-tests/singlestore/tables.ts +++ b/drizzle-orm/type-tests/singlestore/tables.ts @@ -838,7 +838,6 @@ Expect< datedef: date('datedef').default(new Date()), datetime: datetime('datetime'), datetime2: datetime('datetime2', { mode: 'string' }), - datetime3: datetime('datetime3', { mode: 'string', fsp: 3 }), datetimedef: datetime('datetimedef').default(new Date()), decimal: decimal('decimal'), decimal2: decimal('decimal2', { precision: 10 }), @@ -888,12 +887,11 @@ Expect< longtext2: longtext('longtext2', { enum: ['a', 'b', 'c'] }), longtextdef: longtext('longtextdef').default(''), time: time('time'), - time2: time('time2', { fsp: 1 }), timedef: time('timedef').default('00:00:00'), timestamp: timestamp('timestamp'), timestamp2: timestamp('timestamp2', { mode: 'string' }), - timestamp3: timestamp('timestamp3', { mode: 'string', fsp: 1 }), - timestamp4: timestamp('timestamp4', { fsp: 1 }), + timestamp3: timestamp('timestamp3', { mode: 'string' }), + timestamp4: timestamp('timestamp4'), timestampdef: timestamp('timestampdef').default(new Date()), tinyint: tinyint('tinyint'), tinyint2: tinyint('tinyint2', { unsigned: true }), @@ -938,7 +936,6 @@ Expect< datedef: date('datedef').default(new Date()), datetime: datetime(), datetime2: datetime({ mode: 'string' }), - datetime3: datetime({ mode: 'string', fsp: 3 }), datetimedef: datetime('datetimedef').default(new Date()), decimal: decimal(), decimal2: decimal({ precision: 10 }), @@ -988,12 +985,11 @@ Expect< longtext2: longtext({ enum: ['a', 'b', 'c'] }), longtextdef: longtext().default(''), time: time(), - time2: time({ fsp: 1 }), timedef: time().default('00:00:00'), timestamp: timestamp(), timestamp2: timestamp({ mode: 'string' }), - timestamp3: timestamp({ mode: 'string', fsp: 1 }), - timestamp4: timestamp({ fsp: 1 }), + timestamp3: timestamp({ mode: 'string' }), + timestamp4: timestamp(), timestampdef: timestamp().default(new Date()), tinyint: tinyint(), tinyint2: tinyint({ unsigned: true }), diff --git a/integration-tests/tests/singlestore/singlestore-common.ts b/integration-tests/tests/singlestore/singlestore-common.ts index 620715bc9..f97721857 100644 --- a/integration-tests/tests/singlestore/singlestore-common.ts +++ b/integration-tests/tests/singlestore/singlestore-common.ts @@ -83,7 +83,7 @@ const usersTable = singlestoreTable('userstest', { name: text('name').notNull(), verified: boolean('verified').notNull().default(false), jsonb: json('jsonb').$type(), - createdAt: timestamp('created_at', { fsp: 6 }).notNull().defaultNow(), + createdAt: timestamp('created_at').notNull().defaultNow(), }); const users2Table = singlestoreTable('users2', { @@ -101,18 +101,18 @@ const usersOnUpdate = singlestoreTable('users_on_update', { id: serial('id').primaryKey(), name: text('name').notNull(), updateCounter: int('update_counter').default(sql`1`).$onUpdateFn(() => sql`update_counter + 1`), - updatedAt: datetime('updated_at', { mode: 'date', fsp: 6 }).$onUpdateFn(() => new Date()), + updatedAt: datetime('updated_at', { mode: 'date' }).$onUpdateFn(() => new Date()), alwaysNull: text('always_null').$type().$onUpdateFn(() => null), // need to add $type because $onUpdate add a default value }); const datesTable = singlestoreTable('datestable', { date: date('date'), dateAsString: date('date_as_string', { mode: 'string' }), - time: time('time', { fsp: 1 }), - datetime: datetime('datetime', { fsp: 6 }), - datetimeAsString: datetime('datetime_as_string', { fsp: 6, mode: 'string' }), - timestamp: timestamp('timestamp', { fsp: 6 }), - timestampAsString: timestamp('timestamp_as_string', { fsp: 6, mode: 'string' }), + time: time('time'), + datetime: datetime('datetime'), + datetimeAsString: datetime('datetime_as_string', { mode: 'string' }), + timestamp: timestamp('timestamp'), + timestampAsString: timestamp('timestamp_as_string', { mode: 'string' }), year: year('year'), }); @@ -163,7 +163,7 @@ const usersMySchemaTable = mySchema.table('userstest', { name: text('name').notNull(), verified: boolean('verified').notNull().default(false), jsonb: json('jsonb').$type(), - createdAt: timestamp('created_at', { fsp: 6 }).notNull().defaultNow(), + createdAt: timestamp('created_at').notNull().defaultNow(), }); const users2MySchemaTable = mySchema.table('users2', { @@ -2371,8 +2371,8 @@ export function tests(driver?: string) { `, ); const datesTable = singlestoreTable('datestable', { - datetimeUTC: datetime('datetime_utc', { fsp: 6, mode: 'date' }), - datetime: datetime('datetime', { fsp: 6 }), + datetimeUTC: datetime('datetime_utc', { mode: 'date' }), + datetime: datetime('datetime'), }); const dateObj = new Date('2022-11-11'); diff --git a/integration-tests/tests/singlestore/singlestore-custom.test.ts b/integration-tests/tests/singlestore/singlestore-custom.test.ts index b05cd756b..c599df436 100644 --- a/integration-tests/tests/singlestore/singlestore-custom.test.ts +++ b/integration-tests/tests/singlestore/singlestore-custom.test.ts @@ -137,15 +137,15 @@ const usersTable = singlestoreTable('userstest', { name: customText('name').notNull(), verified: customBoolean('verified').notNull().default(false), jsonb: customJson('jsonb'), - createdAt: customTimestamp('created_at', { fsp: 6 }).notNull().default(sql`now()`), + createdAt: customTimestamp('created_at').notNull().default(sql`now()`), }); const datesTable = singlestoreTable('datestable', { date: date('date'), dateAsString: date('date_as_string', { mode: 'string' }), - time: time('time', { fsp: 1 }), - datetime: datetime('datetime', { fsp: 6 }), - datetimeAsString: datetime('datetime_as_string', { fsp: 6, mode: 'string' }), + time: time('time'), + datetime: datetime('datetime'), + datetimeAsString: datetime('datetime_as_string', { mode: 'string' }), year: year('year'), }); diff --git a/integration-tests/tests/singlestore/singlestore-prefixed.test.ts b/integration-tests/tests/singlestore/singlestore-prefixed.test.ts index af7912216..6f29d31a2 100644 --- a/integration-tests/tests/singlestore/singlestore-prefixed.test.ts +++ b/integration-tests/tests/singlestore/singlestore-prefixed.test.ts @@ -76,7 +76,7 @@ const usersTable = singlestoreTable('userstest', { name: text('name').notNull(), verified: boolean('verified').notNull().default(false), jsonb: json('jsonb').$type(), - createdAt: timestamp('created_at', { fsp: 6 }).notNull().defaultNow(), + createdAt: timestamp('created_at').notNull().defaultNow(), }); const users2Table = singlestoreTable('users2', { @@ -640,9 +640,9 @@ test('insert + select all possible dates', async () => { const datesTable = singlestoreTable('datestable', { date: date('date'), dateAsString: date('date_as_string', { mode: 'string' }), - time: time('time', { fsp: 1 }), - datetime: datetime('datetime', { fsp: 6 }), - datetimeAsString: datetime('datetime_as_string', { fsp: 6, mode: 'string' }), + time: time('time'), + datetime: datetime('datetime'), + datetimeAsString: datetime('datetime_as_string', { mode: 'string' }), year: year('year'), }); From 02fadbada473e233cde72f9ffc089c00dee102aa Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 25 Nov 2024 17:41:09 +0200 Subject: [PATCH 391/492] bug fixes --- drizzle-seed/package.json | 1 + drizzle-seed/src/index.ts | 20 +++++----- drizzle-seed/src/services/SeedService.ts | 4 +- drizzle-seed/src/type-tests/mysql.ts | 17 ++++++++ drizzle-seed/src/type-tests/pg.ts | 48 +++++++++++++++++++++++ drizzle-seed/src/type-tests/sqlite.ts | 17 ++++++++ drizzle-seed/src/type-tests/tsconfig.json | 11 ++++++ 7 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 drizzle-seed/src/type-tests/mysql.ts create mode 100644 drizzle-seed/src/type-tests/pg.ts create mode 100644 drizzle-seed/src/type-tests/sqlite.ts create mode 100644 drizzle-seed/src/type-tests/tsconfig.json diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index 32ada8a46..bdeb58877 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -7,6 +7,7 @@ "build": "tsx scripts/build.ts", "pack": "(cd dist && npm pack --pack-destination ..) && rm -f package.tgz && mv *.tgz package.tgz", "test": "vitest --config ./src/tests/vitest.config.ts", + "test:types": "cd src/type-tests && tsc", "generate-for-tests:pg": "drizzle-kit generate --config=./src/tests/pg/drizzle.config.ts", "generate-for-tests:mysql": "drizzle-kit generate --config=./src/tests/mysql/drizzle.config.ts", "generate-for-tests:sqlite": "drizzle-kit generate --config=./src/tests/sqlite/drizzle.config.ts", diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 3f766e219..093ecaf5c 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -18,13 +18,13 @@ import type { Relation, Table } from './types/tables.ts'; type InferCallbackType< DB extends - | PgDatabase + | PgDatabase | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable; }, -> = DB extends PgDatabase ? SCHEMA extends { +> = DB extends PgDatabase ? SCHEMA extends { [key: string]: | PgTable | PgSchema @@ -124,7 +124,7 @@ type InferCallbackType< class SeedPromise< DB extends - | PgDatabase + | PgDatabase | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { @@ -311,7 +311,7 @@ export async function seedForDrizzleStudio( */ export function seed< DB extends - | PgDatabase + | PgDatabase | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { @@ -328,7 +328,7 @@ export function seed< } const seedFunc = async ( - db: PgDatabase | MySqlDatabase | BaseSQLiteDatabase, + db: PgDatabase | MySqlDatabase | BaseSQLiteDatabase, schema: { [key: string]: | PgTable @@ -341,7 +341,7 @@ const seedFunc = async ( options: { count?: number; seed?: number } = {}, refinements?: RefinementsType, ) => { - if (is(db, PgDatabase)) { + if (is(db, PgDatabase)) { const { pgSchema } = filterPgTables(schema); await seedPostgres(db, pgSchema, options, refinements); @@ -404,7 +404,7 @@ const seedFunc = async ( */ export async function reset< DB extends - | PgDatabase + | PgDatabase | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { @@ -417,7 +417,7 @@ export async function reset< | any; }, >(db: DB, schema: SCHEMA) { - if (is(db, PgDatabase)) { + if (is(db, PgDatabase)) { const { pgSchema } = filterPgTables(schema); if (Object.entries(pgSchema).length > 0) { @@ -444,7 +444,7 @@ export async function reset< // Postgres----------------------------------------------------------------------------------------------------------- const resetPostgres = async ( - db: PgDatabase, + db: PgDatabase, schema: { [key: string]: PgTable }, ) => { const tablesToTruncate = Object.entries(schema).map(([_, table]) => { @@ -474,7 +474,7 @@ const filterPgTables = (schema: { }; const seedPostgres = async ( - db: PgDatabase, + db: PgDatabase, schema: { [key: string]: PgTable }, options: { count?: number; seed?: number } = {}, refinements?: RefinementsType, diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index d5166faae..2588f110e 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -3,7 +3,6 @@ import type { MySqlTable } from 'drizzle-orm/mysql-core'; import { MySqlDatabase } from 'drizzle-orm/mysql-core'; import type { PgTable } from 'drizzle-orm/pg-core'; import { PgDatabase } from 'drizzle-orm/pg-core'; -import { PgliteSession } from 'drizzle-orm/pglite'; import type { SQLiteTable } from 'drizzle-orm/sqlite-core'; import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core'; import type { @@ -1037,7 +1036,8 @@ class SeedService { } let maxParametersNumber: number; if (is(db, PgDatabase)) { - maxParametersNumber = is(db._.session, PgliteSession) + // @ts-ignore + maxParametersNumber = db.constructor[entityKind] === 'PgliteDatabase' ? this.postgresPgLiteMaxParametersNumber : this.postgresMaxParametersNumber; } else if (is(db, MySqlDatabase)) { diff --git a/drizzle-seed/src/type-tests/mysql.ts b/drizzle-seed/src/type-tests/mysql.ts new file mode 100644 index 000000000..d1c0949b3 --- /dev/null +++ b/drizzle-seed/src/type-tests/mysql.ts @@ -0,0 +1,17 @@ +import type { MySqlColumn } from 'drizzle-orm/mysql-core'; +import { int, mysqlTable, text } from 'drizzle-orm/mysql-core'; +import { drizzle as mysql2Drizzle } from 'drizzle-orm/mysql2'; +import { reset, seed } from '../index.ts'; + +const mysqlUsers = mysqlTable('users', { + id: int().primaryKey().autoincrement(), + name: text(), + inviteId: int('invite_id').references((): MySqlColumn => mysqlUsers.id), +}); + +{ + const db = mysql2Drizzle(''); + + await seed(db, { users: mysqlUsers }); + await reset(db, { users: mysqlUsers }); +} diff --git a/drizzle-seed/src/type-tests/pg.ts b/drizzle-seed/src/type-tests/pg.ts new file mode 100644 index 000000000..68faf844b --- /dev/null +++ b/drizzle-seed/src/type-tests/pg.ts @@ -0,0 +1,48 @@ +import { drizzle as nodePostgresDrizzle } from 'drizzle-orm/node-postgres'; +import type { PgColumn } from 'drizzle-orm/pg-core'; +import { integer, pgTable, text } from 'drizzle-orm/pg-core'; +import { drizzle as pgliteDrizzle } from 'drizzle-orm/pglite'; +import { drizzle as postgresJsDrizzle } from 'drizzle-orm/postgres-js'; +import { reset, seed } from '../index.ts'; + +const pgUsers = pgTable('users', { + id: integer().primaryKey().generatedAlwaysAsIdentity(), + name: text(), + inviteId: integer('invite_id').references((): PgColumn => pgUsers.id), +}); + +{ + const db0 = nodePostgresDrizzle('', { schema: { users: pgUsers } }); + + await seed(db0, { users: pgUsers }); + await reset(db0, { users: pgUsers }); + + const db1 = nodePostgresDrizzle(''); + + await seed(db1, { users: pgUsers }); + await reset(db1, { users: pgUsers }); +} + +{ + const db0 = pgliteDrizzle('', { schema: { users: pgUsers } }); + + await seed(db0, { users: pgUsers }); + await reset(db0, { users: pgUsers }); + + const db1 = pgliteDrizzle(''); + + await seed(db1, { users: pgUsers }); + await reset(db1, { users: pgUsers }); +} + +{ + const db0 = postgresJsDrizzle('', { schema: { users: pgUsers } }); + + await seed(db0, { users: pgUsers }); + await reset(db0, { users: pgUsers }); + + const db1 = postgresJsDrizzle(''); + + await seed(db1, { users: pgUsers }); + await reset(db1, { users: pgUsers }); +} diff --git a/drizzle-seed/src/type-tests/sqlite.ts b/drizzle-seed/src/type-tests/sqlite.ts new file mode 100644 index 000000000..1b060e6a3 --- /dev/null +++ b/drizzle-seed/src/type-tests/sqlite.ts @@ -0,0 +1,17 @@ +import { drizzle as betterSqlite3Drizzle } from 'drizzle-orm/better-sqlite3'; +import type { SQLiteColumn } from 'drizzle-orm/sqlite-core'; +import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { reset, seed } from '../index.ts'; + +const mysqlUsers = sqliteTable('users', { + id: int().primaryKey(), + name: text(), + inviteId: int('invite_id').references((): SQLiteColumn => mysqlUsers.id), +}); + +{ + const db = betterSqlite3Drizzle(''); + + await seed(db, { users: mysqlUsers }); + await reset(db, { users: mysqlUsers }); +} diff --git a/drizzle-seed/src/type-tests/tsconfig.json b/drizzle-seed/src/type-tests/tsconfig.json new file mode 100644 index 000000000..09df8e1bb --- /dev/null +++ b/drizzle-seed/src/type-tests/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.build.json", + "compilerOptions": { + "composite": false, + "noEmit": true, + "rootDir": "..", + "outDir": "./.cache" + }, + "include": [".", "../src"], + "exclude": ["**/playground"] +} From 2552c03ca695dd3f6c667007cee8994f33c3378e Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 25 Nov 2024 17:53:50 +0200 Subject: [PATCH 392/492] Fix build problems --- .../src/singlestore-core/columns/common.ts | 3 +-- drizzle-orm/type-tests/singlestore/tables.ts | 26 +++++++++++-------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts index ef494a4c1..c0dc7fb67 100644 --- a/drizzle-orm/src/singlestore-core/columns/common.ts +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -5,7 +5,6 @@ import type { ColumnBuilderRuntimeConfig, ColumnDataType, HasDefault, - HasGenerated, IsAutoincrement, MakeColumnConfig, } from '~/column-builder.ts'; @@ -47,7 +46,7 @@ export abstract class SingleStoreColumnBuilder< // TODO: Implement generated columns for SingleStore (https://docs.singlestore.com/cloud/create-a-database/using-persistent-computed-columns/) /** @internal */ - generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SingleStoreGeneratedColumnConfig): HasGenerated { + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SingleStoreGeneratedColumnConfig) { this.config.generated = { as, type: 'always', diff --git a/drizzle-orm/type-tests/singlestore/tables.ts b/drizzle-orm/type-tests/singlestore/tables.ts index 1df4861af..43a1b05dc 100644 --- a/drizzle-orm/type-tests/singlestore/tables.ts +++ b/drizzle-orm/type-tests/singlestore/tables.ts @@ -91,11 +91,12 @@ Expect< notNull: true; hasDefault: true; isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; + identity: undefined; generated: undefined; - isAutoincrement: true; - hasRuntimeDefault: false; }, object>; name: SingleStoreColumn<{ name: 'name_db'; @@ -107,11 +108,12 @@ Expect< notNull: true; hasDefault: false; isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; + identity: undefined; generated: undefined; - isAutoincrement: false; - hasRuntimeDefault: false; }, object>; population: SingleStoreColumn<{ name: 'population'; @@ -123,11 +125,12 @@ Expect< notNull: false; hasDefault: true; isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; + identity: undefined; generated: undefined; - isAutoincrement: false; - hasRuntimeDefault: false; }, object>; }, typeof cities._.columns @@ -500,7 +503,6 @@ Expect< Expect< Equal< { - brand: 'Column'; name: 'name'; tableName: 'table'; dataType: 'custom'; @@ -509,13 +511,15 @@ Expect< driverParam: unknown; notNull: true; hasDefault: false; - enumValues: undefined; - baseColumn: never; - dialect: 'singlestore'; - generated: undefined; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; + enumValues: undefined; + baseColumn: never; + identity: undefined; + generated: undefined; + brand: 'Column'; + dialect: 'singlestore'; }, Simplify['_']> > From d6dcda7abe4aab643a2f9e19bd2ea92aae898cc7 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 25 Nov 2024 19:00:27 +0200 Subject: [PATCH 393/492] Bump version; add changelog --- changelogs/drizzle-seed/0.1.2.md | 2 + drizzle-seed/package.json | 4 +- pnpm-lock.yaml | 10180 ++++++++++++++++------------- 3 files changed, 5781 insertions(+), 4405 deletions(-) create mode 100644 changelogs/drizzle-seed/0.1.2.md diff --git a/changelogs/drizzle-seed/0.1.2.md b/changelogs/drizzle-seed/0.1.2.md new file mode 100644 index 000000000..4df3c89f4 --- /dev/null +++ b/changelogs/drizzle-seed/0.1.2.md @@ -0,0 +1,2 @@ +- Fixed: [[BUG]: drizzle-seed reset fails without @electric-sql/pglite installed](https://github.com/drizzle-team/drizzle-orm/issues/3603) +- Fixed: [[BUG]: TypeScript type error in drizzle-seed with schema passed to drizzle in IDE](https://github.com/drizzle-team/drizzle-orm/issues/3599) \ No newline at end of file diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index bdeb58877..ad31de0eb 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-seed", - "version": "0.1.1", + "version": "0.1.2", "main": "index.js", "type": "module", "scripts": { @@ -102,4 +102,4 @@ "dependencies": { "pure-rand": "^6.1.0" } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d7cc8625..24d14e7c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,22 +13,22 @@ importers: version: 0.15.3 '@trivago/prettier-plugin-sort-imports': specifier: ^4.2.0 - version: 4.3.0(prettier@3.3.3) + version: 4.2.0(prettier@3.0.3) '@typescript-eslint/eslint-plugin': specifier: ^6.7.3 - version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) + version: 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/experimental-utils': specifier: ^5.62.0 - version: 5.62.0(eslint@8.57.1)(typescript@5.6.3) + version: 5.62.0(eslint@8.50.0)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^6.7.3 - version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) + version: 6.7.3(eslint@8.50.0)(typescript@5.6.3) bun-types: specifier: ^1.0.3 - version: 1.1.34 + version: 1.0.3 concurrently: specifier: ^8.2.1 - version: 8.2.2 + version: 8.2.1 dprint: specifier: ^0.46.2 version: 0.46.3 @@ -43,40 +43,40 @@ importers: version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 - version: 8.57.1 + version: 8.50.0 eslint-plugin-drizzle-internal: specifier: link:eslint/eslint-plugin-drizzle-internal version: link:eslint/eslint-plugin-drizzle-internal eslint-plugin-import: specifier: ^2.28.1 - version: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1) + version: 2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0) eslint-plugin-no-instanceof: specifier: ^1.0.1 version: 1.0.1 eslint-plugin-unicorn: specifier: ^48.0.1 - version: 48.0.1(eslint@8.57.1) + version: 48.0.1(eslint@8.50.0) eslint-plugin-unused-imports: specifier: ^3.0.0 - version: 3.2.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1) + version: 3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0) glob: specifier: ^10.3.10 - version: 10.4.5 + version: 10.3.10 prettier: specifier: ^3.0.3 - version: 3.3.3 + version: 3.0.3 recast: specifier: ^0.23.9 version: 0.23.9 resolve-tspaths: specifier: ^0.8.16 - version: 0.8.22(typescript@5.6.3) + version: 0.8.16(typescript@5.6.3) tsup: specifier: ^7.2.0 - version: 7.3.0(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3) tsx: specifier: ^4.10.5 - version: 4.19.2 + version: 4.10.5 turbo: specifier: ^2.2.3 version: 2.3.0 @@ -91,50 +91,50 @@ importers: version: 0.10.2 '@esbuild-kit/esm-loader': specifier: ^2.5.5 - version: 2.6.5 + version: 2.5.5 esbuild: specifier: ^0.19.7 version: 0.19.12 esbuild-register: specifier: ^3.5.0 - version: 3.6.0(esbuild@0.19.12) + version: 3.5.0(esbuild@0.19.12) devDependencies: '@arethetypeswrong/cli': specifier: ^0.15.3 version: 0.15.3 '@aws-sdk/client-rds-data': specifier: ^3.556.0 - version: 3.687.0 + version: 3.583.0 '@cloudflare/workers-types': specifier: ^4.20230518.0 - version: 4.20241106.0 + version: 4.20240524.0 '@electric-sql/pglite': specifier: ^0.2.12 version: 0.2.12 '@hono/node-server': specifier: ^1.9.0 - version: 1.13.5(hono@4.6.9) + version: 1.12.0 '@hono/zod-validator': specifier: ^0.2.1 - version: 0.2.2(hono@4.6.9)(zod@3.23.8) + version: 0.2.2(hono@4.5.0)(zod@3.23.7) '@libsql/client': specifier: ^0.10.0 version: 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': specifier: ^0.9.1 - version: 0.9.5 + version: 0.9.3 '@originjs/vite-plugin-commonjs': specifier: ^1.0.3 version: 1.0.3 '@planetscale/database': specifier: ^1.16.0 - version: 1.19.0 + version: 1.18.0 '@types/better-sqlite3': specifier: ^7.6.4 - version: 7.6.11 + version: 7.6.10 '@types/dockerode': specifier: ^3.3.28 - version: 3.3.31 + version: 3.3.29 '@types/glob': specifier: ^8.1.0 version: 8.1.0 @@ -149,10 +149,10 @@ importers: version: 5.1.2 '@types/node': specifier: ^18.11.15 - version: 18.19.64 + version: 18.19.33 '@types/pg': specifier: ^8.10.7 - version: 8.11.10 + version: 8.11.6 '@types/pluralize': specifier: ^0.0.33 version: 0.0.33 @@ -164,19 +164,19 @@ importers: version: 9.0.8 '@types/ws': specifier: ^8.5.10 - version: 8.5.13 + version: 8.5.11 '@typescript-eslint/eslint-plugin': specifier: ^7.2.0 - version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) + version: 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^7.2.0 - version: 7.18.0(eslint@8.57.1)(typescript@5.6.3) + version: 7.16.1(eslint@8.57.0)(typescript@5.6.3) '@vercel/postgres': specifier: ^0.8.0 version: 0.8.0 ava: specifier: ^5.1.0 - version: 5.3.1 + version: 5.3.0(@ava/typescript@5.0.0) better-sqlite3: specifier: ^9.4.3 version: 9.6.0 @@ -209,16 +209,16 @@ importers: version: 3.0.0 esbuild-node-externals: specifier: ^1.9.0 - version: 1.15.0(esbuild@0.19.12) + version: 1.14.0(esbuild@0.19.12) eslint: specifier: ^8.57.0 - version: 8.57.1 + version: 8.57.0 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@8.57.1) + version: 9.1.0(eslint@8.57.0) eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8) + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8) get-port: specifier: ^6.1.2 version: 6.1.2 @@ -230,7 +230,7 @@ importers: version: 0.0.5 hono: specifier: ^4.1.5 - version: 4.6.9 + version: 4.5.0 json-diff: specifier: 1.0.6 version: 1.0.6 @@ -251,25 +251,25 @@ importers: version: 17.1.0 pg: specifier: ^8.11.5 - version: 8.13.1 + version: 8.11.5 pluralize: specifier: ^8.0.0 version: 8.0.0 postgres: specifier: ^3.4.4 - version: 3.4.5 + version: 3.4.4 prettier: specifier: ^2.8.1 version: 2.8.8 semver: specifier: ^7.5.4 - version: 7.6.3 + version: 7.6.2 superjson: specifier: ^2.2.1 version: 2.2.1 tsup: specifier: ^8.0.2 - version: 8.3.5(postcss@8.4.47)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.6.0) + version: 8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.4.2) tsx: specifier: ^3.12.1 version: 3.14.0 @@ -281,31 +281,31 @@ importers: version: 9.0.1 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.4.0 - version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) wrangler: specifier: ^3.22.1 - version: 3.85.0(@cloudflare/workers-types@4.20241106.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3) + version: 3.65.0(@cloudflare/workers-types@4.20240524.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3) ws: specifier: ^8.16.0 - version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + version: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) zod: specifier: ^3.20.2 - version: 3.23.8 + version: 3.23.7 zx: specifier: ^7.2.2 - version: 7.2.3 + version: 7.2.2 drizzle-orm: devDependencies: '@aws-sdk/client-rds-data': specifier: ^3.549.0 - version: 3.687.0 + version: 3.583.0 '@cloudflare/workers-types': specifier: ^4.20230904.0 - version: 4.20241106.0 + version: 4.20240512.0 '@electric-sql/pglite': specifier: ^0.2.12 version: 0.2.12 @@ -323,16 +323,16 @@ importers: version: 0.10.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 - version: 1.9.0 + version: 1.8.0 '@originjs/vite-plugin-commonjs': specifier: ^1.0.3 version: 1.0.3 '@planetscale/database': specifier: ^1.16.0 - version: 1.19.0 + version: 1.18.0 '@prisma/client': specifier: 5.14.0 version: 5.14.0(prisma@5.14.0) @@ -341,16 +341,16 @@ importers: version: 0.1.1 '@types/better-sqlite3': specifier: ^7.6.4 - version: 7.6.11 + version: 7.6.10 '@types/node': specifier: ^20.2.5 - version: 20.17.6 + version: 20.12.12 '@types/pg': specifier: ^8.10.1 - version: 8.11.10 + version: 8.11.6 '@types/react': specifier: ^18.2.45 - version: 18.3.12 + version: 18.3.1 '@types/sql.js': specifier: ^1.4.4 version: 1.4.9 @@ -359,7 +359,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.5(typescript@5.6.3) + version: 0.29.4(typescript@5.6.3) better-sqlite3: specifier: ^8.4.0 version: 8.7.0 @@ -371,10 +371,10 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^14.0.0 - version: 14.0.6(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + version: 14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) knex: specifier: ^2.4.2 - version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7) + version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) kysely: specifier: ^0.25.0 version: 0.25.0 @@ -383,10 +383,10 @@ importers: version: 3.3.3 pg: specifier: ^8.11.0 - version: 8.13.1 + version: 8.11.5 postgres: specifier: ^3.3.5 - version: 3.4.5 + version: 3.4.4 prisma: specifier: 5.14.0 version: 5.14.0 @@ -395,110 +395,28 @@ importers: version: 18.3.1 sql.js: specifier: ^1.8.0 - version: 1.12.0 + version: 1.10.3 sqlite3: specifier: ^5.1.2 version: 5.1.7 tslib: specifier: ^2.5.2 - version: 2.8.1 + version: 2.6.2 tsx: specifier: ^3.12.7 version: 3.14.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) zod: specifier: ^3.20.2 - version: 3.23.8 + version: 3.23.7 zx: specifier: ^7.2.2 - version: 7.2.3 - - drizzle-seed: - dependencies: - pure-rand: - specifier: ^6.1.0 - version: 6.1.0 - devDependencies: - '@arethetypeswrong/cli': - specifier: ^0.16.1 - version: 0.16.4 - '@electric-sql/pglite': - specifier: ^0.2.12 - version: 0.2.12 - '@rollup/plugin-terser': - specifier: ^0.4.4 - version: 0.4.4(rollup@4.24.4) - '@rollup/plugin-typescript': - specifier: ^11.1.6 - version: 11.1.6(rollup@4.24.4)(tslib@2.8.1)(typescript@5.6.3) - '@types/better-sqlite3': - specifier: ^7.6.11 - version: 7.6.11 - '@types/dockerode': - specifier: ^3.3.31 - version: 3.3.31 - '@types/node': - specifier: ^22.5.4 - version: 22.9.0 - '@types/pg': - specifier: ^8.11.6 - version: 8.11.10 - '@types/uuid': - specifier: ^10.0.0 - version: 10.0.0 - better-sqlite3: - specifier: ^11.1.2 - version: 11.5.0 - cpy: - specifier: ^11.1.0 - version: 11.1.0 - dockerode: - specifier: ^4.0.2 - version: 4.0.2 - dotenv: - specifier: ^16.4.5 - version: 16.4.5 - drizzle-kit: - specifier: workspace:./drizzle-kit/dist - version: link:drizzle-kit/dist - drizzle-orm: - specifier: workspace:./drizzle-orm/dist - version: link:drizzle-orm/dist - get-port: - specifier: ^7.1.0 - version: 7.1.0 - mysql2: - specifier: ^3.3.3 - version: 3.3.3 - pg: - specifier: ^8.12.0 - version: 8.13.1 - resolve-tspaths: - specifier: ^0.8.19 - version: 0.8.22(typescript@5.6.3) - rollup: - specifier: ^4.21.2 - version: 4.24.4 - tslib: - specifier: ^2.7.0 - version: 2.8.1 - tsx: - specifier: ^4.19.0 - version: 4.19.2 - uuid: - specifier: ^10.0.0 - version: 10.0.0 - vitest: - specifier: ^2.0.5 - version: 2.1.4(@types/node@22.9.0)(terser@5.36.0) - zx: - specifier: ^8.1.5 - version: 8.2.0 + version: 7.2.2 drizzle-seed: dependencies: @@ -586,7 +504,7 @@ importers: devDependencies: '@rollup/plugin-terser': specifier: ^0.4.1 - version: 0.4.4(rollup@3.29.5) + version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 version: 11.1.1(rollup@3.27.2)(tslib@2.8.1)(typescript@5.6.3) @@ -595,7 +513,7 @@ importers: version: 0.29.6 '@types/node': specifier: ^18.15.10 - version: 18.19.64 + version: 18.15.10 cpy: specifier: ^10.1.0 version: 10.1.0 @@ -604,31 +522,31 @@ importers: version: link:../drizzle-orm/dist rimraf: specifier: ^5.0.0 - version: 5.0.10 + version: 5.0.0 rollup: specifier: ^3.20.7 - version: 3.29.5 + version: 3.27.2 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) zx: specifier: ^7.2.2 - version: 7.2.3 + version: 7.2.2 drizzle-valibot: devDependencies: '@rollup/plugin-terser': specifier: ^0.4.1 - version: 0.4.4(rollup@3.29.5) + version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 version: 11.1.1(rollup@3.27.2)(tslib@2.8.1)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 - version: 18.19.64 + version: 18.15.10 cpy: specifier: ^10.1.0 version: 10.1.0 @@ -637,34 +555,34 @@ importers: version: link:../drizzle-orm/dist rimraf: specifier: ^5.0.0 - version: 5.0.10 + version: 5.0.0 rollup: specifier: ^3.20.7 - version: 3.29.5 + version: 3.27.2 valibot: specifier: ^0.30.0 version: 0.30.0 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) zx: specifier: ^7.2.2 - version: 7.2.3 + version: 7.2.2 drizzle-zod: devDependencies: '@rollup/plugin-terser': specifier: ^0.4.1 - version: 0.4.4(rollup@3.29.5) + version: 0.4.1(rollup@3.20.7) '@rollup/plugin-typescript': specifier: ^11.1.0 version: 11.1.0(rollup@3.20.7)(tslib@2.8.1)(typescript@5.6.3) '@types/node': specifier: ^18.15.10 - version: 18.19.64 + version: 18.15.10 cpy: specifier: ^10.1.0 version: 10.1.0 @@ -673,58 +591,58 @@ importers: version: link:../drizzle-orm/dist rimraf: specifier: ^5.0.0 - version: 5.0.10 + version: 5.0.0 rollup: specifier: ^3.20.7 - version: 3.29.5 + version: 3.20.7 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@18.15.10)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) zod: specifier: ^3.20.2 - version: 3.23.8 + version: 3.21.4 zx: specifier: ^7.2.2 - version: 7.2.3 + version: 7.2.2 eslint-plugin-drizzle: devDependencies: '@types/node': specifier: ^20.10.1 - version: 20.17.6 + version: 20.10.1 '@typescript-eslint/parser': specifier: ^6.10.0 - version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) + version: 6.10.0(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/rule-tester': specifier: ^6.10.0 - version: 6.21.0(@eslint/eslintrc@2.1.4)(eslint@8.57.1)(typescript@5.6.3) + version: 6.10.0(@eslint/eslintrc@3.1.0)(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/utils': specifier: ^6.10.0 - version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) + version: 6.10.0(eslint@8.53.0)(typescript@5.2.2) cpy-cli: specifier: ^5.0.0 version: 5.0.0 eslint: specifier: ^8.53.0 - version: 8.57.1 + version: 8.53.0 typescript: specifier: ^5.2.2 - version: 5.6.3 + version: 5.2.2 vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 1.6.0(@types/node@20.10.1)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) integration-tests: dependencies: '@aws-sdk/client-rds-data': specifier: ^3.549.0 - version: 3.687.0 + version: 3.583.0 '@aws-sdk/credential-providers': specifier: ^3.549.0 - version: 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)) + version: 3.569.0(@aws-sdk/client-sso-oidc@3.583.0) '@electric-sql/pglite': specifier: 0.2.12 version: 0.2.12 @@ -739,7 +657,7 @@ importers: version: 2.14.4 '@planetscale/database': specifier: ^1.16.0 - version: 1.19.0 + version: 1.18.0 '@prisma/client': specifier: 5.14.0 version: 5.14.0(prisma@5.14.0) @@ -754,7 +672,7 @@ importers: version: 0.8.0 '@xata.io/client': specifier: ^0.29.3 - version: 0.29.5(typescript@5.6.3) + version: 0.29.4(typescript@5.6.3) async-retry: specifier: ^1.3.3 version: 1.3.3 @@ -784,7 +702,7 @@ importers: version: link:../drizzle-zod/dist express: specifier: ^4.18.2 - version: 4.21.1 + version: 4.19.2 get-port: specifier: ^7.0.0 version: 7.1.0 @@ -793,10 +711,10 @@ importers: version: 3.3.3 pg: specifier: ^8.11.0 - version: 8.13.1 + version: 8.11.5 postgres: specifier: ^3.3.5 - version: 3.4.5 + version: 3.4.4 prisma: specifier: 5.14.0 version: 5.14.0 @@ -805,13 +723,13 @@ importers: version: 0.5.21 sql.js: specifier: ^1.8.0 - version: 1.12.0 + version: 1.10.3 sqlite3: specifier: ^5.1.4 version: 5.1.7 sst: specifier: ^3.0.4 - version: 3.3.5(hono@4.6.9)(valibot@0.30.0) + version: 3.0.14 uuid: specifier: ^9.0.0 version: 9.0.1 @@ -820,17 +738,17 @@ importers: version: 0.5.6 vitest: specifier: ^2.1.2 - version: 2.1.4(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) + version: 2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) ws: specifier: ^8.16.0 version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) zod: specifier: ^3.20.2 - version: 3.23.8 + version: 3.23.7 devDependencies: '@cloudflare/workers-types': specifier: ^4.20241004.0 - version: 4.20241106.0 + version: 4.20241004.0 '@neondatabase/serverless': specifier: 0.10.0 version: 0.10.0 @@ -842,25 +760,25 @@ importers: version: 2.2.2 '@types/async-retry': specifier: ^1.4.8 - version: 1.4.9 + version: 1.4.8 '@types/axios': specifier: ^0.14.0 - version: 0.14.4 + version: 0.14.0 '@types/better-sqlite3': specifier: ^7.6.4 - version: 7.6.11 + version: 7.6.10 '@types/dockerode': specifier: ^3.3.18 - version: 3.3.31 + version: 3.3.29 '@types/express': specifier: ^4.17.16 version: 4.17.21 '@types/node': specifier: ^20.2.5 - version: 20.17.6 + version: 20.12.12 '@types/pg': specifier: ^8.10.1 - version: 8.11.10 + version: 8.11.6 '@types/sql.js': specifier: ^1.4.4 version: 1.4.9 @@ -869,37 +787,41 @@ importers: version: 9.0.8 '@types/ws': specifier: ^8.5.10 - version: 8.5.13 + version: 8.5.11 '@vitest/ui': specifier: ^1.6.0 - version: 1.6.0(vitest@2.1.4) + version: 1.6.0(vitest@2.1.2) ava: specifier: ^5.3.0 - version: 5.3.1 + version: 5.3.0(@ava/typescript@5.0.0) axios: specifier: ^1.4.0 - version: 1.7.7 + version: 1.6.8 cross-env: specifier: ^7.0.3 version: 7.0.3 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.17.6)(typescript@5.6.3) + version: 10.9.2(@types/node@20.12.12)(typescript@5.6.3) tsx: specifier: ^4.14.0 - version: 4.19.2 + version: 4.16.2 vite: specifier: ^5.2.13 - version: 5.4.10(@types/node@20.17.6)(terser@5.36.0) + version: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)) + version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0)) zx: specifier: ^7.2.2 - version: 7.2.3 + version: 7.2.2 packages: + '@aashutoshrathi/word-wrap@1.2.6': + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -929,128 +851,313 @@ packages: resolution: {integrity: sha512-2twsQz2fUd95QK1MtKuEnjkiN47SKHZfi/vWj040EN6Eo2ZW3SNcAwncJqXXoMTYZTWtBRXYp3Fg8z+JkFI9aQ==} engines: {node: ^18.18 || ^20.8 || ^21 || ^22} - '@aws-crypto/sha256-browser@5.2.0': - resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + '@aws-crypto/crc32@3.0.0': + resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==} + + '@aws-crypto/ie11-detection@3.0.0': + resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} + + '@aws-crypto/sha256-browser@3.0.0': + resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} + + '@aws-crypto/sha256-js@3.0.0': + resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} + + '@aws-crypto/supports-web-crypto@3.0.0': + resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} + + '@aws-crypto/util@3.0.0': + resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} - '@aws-crypto/sha256-js@5.2.0': - resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + '@aws-sdk/client-cognito-identity@3.569.0': + resolution: {integrity: sha512-cD1HcdJNpUZgrATWCAQs2amQKI69pG+jF4b5ySq9KJkVi6gv2PWsD6QGDG8H12lMWaIKYlOpKbpnYTpcuvqUcg==} engines: {node: '>=16.0.0'} - '@aws-crypto/supports-web-crypto@5.2.0': - resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + '@aws-sdk/client-lambda@3.478.0': + resolution: {integrity: sha512-7+PEE1aV3qVeuswL6cUBfHeljxC/WaXFj+214/W3q71uRdLbX5Z7ZOD15sJbjSu+4VZN9ugMaxEcp+oLiqWl+A==} + engines: {node: '>=14.0.0'} - '@aws-crypto/util@5.2.0': - resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + '@aws-sdk/client-rds-data@3.583.0': + resolution: {integrity: sha512-xBnrVGNmMsTafzlaeZiFUahr3TP4zF2yRnsWzibylbXXIjaGdcLoiskNizo62syCh/8LbgpY6EN34EeYWsfMiw==} + engines: {node: '>=16.0.0'} - '@aws-sdk/client-cognito-identity@3.687.0': - resolution: {integrity: sha512-jcQTioloSed+Jc3snjrgpWejkOm8t3Zt+jWrApw3ejN8qBtpFCH43M7q/CSDVZ9RS1IjX+KRWoBFnrDOnbuw0Q==} + '@aws-sdk/client-sso-oidc@3.569.0': + resolution: {integrity: sha512-u5DEjNEvRvlKKh1QLCDuQ8GIrx+OFvJFLfhorsp4oCxDylvORs+KfyKKnJAw4wYEEHyxyz9GzHD7p6a8+HLVHw==} engines: {node: '>=16.0.0'} - '@aws-sdk/client-rds-data@3.687.0': - resolution: {integrity: sha512-/m+HcjbINf74SIoXjXM61GcWzFYtN6OdL1JIO+FTN8P8usMvOOD14B8QGLghp0XAWhdl7NKU8y8BmaXShEffIw==} + '@aws-sdk/client-sso-oidc@3.583.0': + resolution: {integrity: sha512-LO3wmrFXPi2kNE46lD1XATfRrvdNxXd4DlTFouoWmr7lvqoUkcbmtkV2r/XChZA2z0HiDauphC1e8b8laJVeSg==} engines: {node: '>=16.0.0'} - '@aws-sdk/client-sso-oidc@3.687.0': - resolution: {integrity: sha512-Rdd8kLeTeh+L5ZuG4WQnWgYgdv7NorytKdZsGjiag1D8Wv3PcJvPqqWdgnI0Og717BSXVoaTYaN34FyqFYSx6Q==} + '@aws-sdk/client-sso@3.478.0': + resolution: {integrity: sha512-Jxy9cE1JMkPR0PklCpq3cORHnZq/Z4klhSTNGgZNeBWovMa+plor52kyh8iUNHKl3XEJvTbHM7V+dvrr/x0P1g==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/client-sso@3.568.0': + resolution: {integrity: sha512-LSD7k0ZBQNWouTN5dYpUkeestoQ+r5u6cp6o+FATKeiFQET85RNA3xJ4WPnOI5rBC1PETKhQXvF44863P3hCaQ==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/client-sso@3.583.0': + resolution: {integrity: sha512-FNJ2MmiBtZZwgkj4+GLVrzqwmD6D8FBptrFZk7PnGkSf7v1Q8txYNI6gY938RRhYJ4lBW4cNbhPvWoDxAl90Hw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/client-sts@3.478.0': + resolution: {integrity: sha512-D+QID0dYzmn9dcxgKP3/nMndUqiQbDLsqI0Zf2pG4MW5gPhVNKlDGIV3Ztz8SkMjzGJExNOLW2L569o8jshJVw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/client-sts@3.569.0': + resolution: {integrity: sha512-3AyipQ2zHszkcTr8n1Sp7CiMUi28aMf1vOhEo0KKi0DWGo1Z1qJEpWeRP363KG0n9/8U3p1IkXGz5FRbpXZxIw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/client-sts@3.583.0': + resolution: {integrity: sha512-xDMxiemPDWr9dY2Q4AyixkRnk/hvS6fs6OWxuVCz1WO47YhaAfOsEGAgQMgDLLaOfj/oLU5D14uTNBEPGh4rBA==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/core@3.477.0': + resolution: {integrity: sha512-o0434EH+d1BxHZvgG7z8vph2SYefciQ5RnJw2MgvETGnthgqsnI4nnNJLSw0FVeqCeS18n6vRtzqlGYR2YPCNg==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/core@3.567.0': + resolution: {integrity: sha512-zUDEQhC7blOx6sxhHdT75x98+SXQVdUIMu8z8AjqMWiYK2v4WkOS8i6dOS4E5OjL5J1Ac+ruy8op/Bk4AFqSIw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/core@3.582.0': + resolution: {integrity: sha512-ofmD96IQc9g1dbyqlCyxu5fCG7kIl9p1NoN5+vGBUyLdbmPCV3Pdg99nRHYEJuv2MgGx5AUFGDPMHcqbJpnZIw==} engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sts': ^3.687.0 - '@aws-sdk/client-sso@3.687.0': - resolution: {integrity: sha512-dfj0y9fQyX4kFill/ZG0BqBTLQILKlL7+O5M4F9xlsh2WNuV2St6WtcOg14Y1j5UODPJiJs//pO+mD1lihT5Kw==} + '@aws-sdk/credential-provider-cognito-identity@3.569.0': + resolution: {integrity: sha512-CHS0Zyuazh5cYLaJr2/I9up0xAu8Y+um/h0o4xNf00cKGT0Sdhoby5vyelHjVTeZt+OeOMTBt6IdqGwVbVG9gQ==} engines: {node: '>=16.0.0'} - '@aws-sdk/client-sts@3.687.0': - resolution: {integrity: sha512-SQjDH8O4XCTtouuCVYggB0cCCrIaTzUZIkgJUpOsIEJBLlTbNOb/BZqUShAQw2o9vxr2rCeOGjAQOYPysW/Pmg==} + '@aws-sdk/credential-provider-env@3.468.0': + resolution: {integrity: sha512-k/1WHd3KZn0EQYjadooj53FC0z24/e4dUZhbSKTULgmxyO62pwh9v3Brvw4WRa/8o2wTffU/jo54tf4vGuP/ZA==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-env@3.568.0': + resolution: {integrity: sha512-MVTQoZwPnP1Ev5A7LG+KzeU6sCB8BcGkZeDT1z1V5Wt7GPq0MgFQTSSjhImnB9jqRSZkl1079Bt3PbO6lfIS8g==} engines: {node: '>=16.0.0'} - '@aws-sdk/core@3.686.0': - resolution: {integrity: sha512-Xt3DV4DnAT3v2WURwzTxWQK34Ew+iiLzoUoguvLaZrVMFOqMMrwVjP+sizqIaHp1j7rGmFcN5I8saXnsDLuQLA==} + '@aws-sdk/credential-provider-env@3.577.0': + resolution: {integrity: sha512-Jxu255j0gToMGEiqufP8ZtKI8HW90lOLjwJ3LrdlD/NLsAY0tOQf1fWc53u28hWmmNGMxmCrL2p66IOgMDhDUw==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-cognito-identity@3.687.0': - resolution: {integrity: sha512-hJq9ytoj2q/Jonc7mox/b0HT+j4NeMRuU184DkXRJbvIvwwB+oMt12221kThLezMhwIYfXEteZ7GEId7Hn8Y8g==} + '@aws-sdk/credential-provider-http@3.568.0': + resolution: {integrity: sha512-gL0NlyI2eW17hnCrh45hZV+qjtBquB+Bckiip9R6DIVRKqYcoILyiFhuOgf2bXeF23gVh6j18pvUvIoTaFWs5w==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-env@3.686.0': - resolution: {integrity: sha512-osD7lPO8OREkgxPiTWmA1i6XEmOth1uW9HWWj/+A2YGCj1G/t2sHu931w4Qj9NWHYZtbTTXQYVRg+TErALV7nQ==} + '@aws-sdk/credential-provider-http@3.582.0': + resolution: {integrity: sha512-kGOUKw5ryPkDIYB69PjK3SicVLTbWB06ouFN2W1EvqUJpkQGPAUGzYcomKtt3mJaCTf/1kfoaHwARAl6KKSP8Q==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-http@3.686.0': - resolution: {integrity: sha512-xyGAD/f3vR/wssUiZrNFWQWXZvI4zRm2wpHhoHA1cC2fbRMNFYtFn365yw6dU7l00ZLcdFB1H119AYIUZS7xbw==} + '@aws-sdk/credential-provider-ini@3.478.0': + resolution: {integrity: sha512-SsrYEYUvTG9ZoPC+zB19AnVoOKID+QIEHJDIi1GCZXW5kTVyr1saTVm4orG2TjYvbHQMddsWtHOvGYXZWAYMbw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-ini@3.568.0': + resolution: {integrity: sha512-m5DUN9mpto5DhEvo6w3+8SS6q932ja37rTNvpPqWJIaWhj7OorAwVirSaJQAQB/M8+XCUIrUonxytphZB28qGQ==} engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.568.0 - '@aws-sdk/credential-provider-ini@3.687.0': - resolution: {integrity: sha512-6d5ZJeZch+ZosJccksN0PuXv7OSnYEmanGCnbhUqmUSz9uaVX6knZZfHCZJRgNcfSqg9QC0zsFA/51W5HCUqSQ==} + '@aws-sdk/credential-provider-ini@3.583.0': + resolution: {integrity: sha512-8I0oWNg/yps6ctjhEeL/qJ9BIa/+xXP7RPDQqFKZ2zBkWbmLLOoMWXRvl8uKUBD6qCe+DGmcu9skfVXeXSesEQ==} engines: {node: '>=16.0.0'} peerDependencies: - '@aws-sdk/client-sts': ^3.687.0 + '@aws-sdk/client-sts': ^3.583.0 + + '@aws-sdk/credential-provider-node@3.478.0': + resolution: {integrity: sha512-nwDutJYeHiIZCQDgKIUrsgwAWTil0mNe+cbd+j8fi+wwxkWUzip+F0+z02molJ8WrUUKNRhqB1V5aVx7IranuA==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-node@3.569.0': + resolution: {integrity: sha512-7jH4X2qlPU3PszZP1zvHJorhLARbU1tXvp8ngBe8ArXBrkFpl/dQ2Y/IRAICPm/pyC1IEt8L/CvKp+dz7v/eRw==} + engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-node@3.687.0': - resolution: {integrity: sha512-Pqld8Nx11NYaBUrVk3bYiGGpLCxkz8iTONlpQWoVWFhSOzlO7zloNOaYbD2XgFjjqhjlKzE91drs/f41uGeCTA==} + '@aws-sdk/credential-provider-node@3.583.0': + resolution: {integrity: sha512-yBNypBXny7zJH85SzxDj8s1mbLXv9c/Vbq0qR3R3POj2idZ6ywB/qlIRC1XwBuv49Wvg8kA1wKXk3K3jrpcVIw==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-process@3.686.0': - resolution: {integrity: sha512-sXqaAgyzMOc+dm4CnzAR5Q6S9OWVHyZjLfW6IQkmGjqeQXmZl24c4E82+w64C+CTkJrFLzH1VNOYp1Hy5gE6Qw==} + '@aws-sdk/credential-provider-process@3.468.0': + resolution: {integrity: sha512-OYSn1A/UsyPJ7Z8Q2cNhTf55O36shPmSsvOfND04nSfu1nPaR+VUvvsP7v+brhGpwC/GAKTIdGAo4blH31BS6A==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-process@3.568.0': + resolution: {integrity: sha512-r01zbXbanP17D+bQUb7mD8Iu2SuayrrYZ0Slgvx32qgz47msocV9EPCSwI4Hkw2ZtEPCeLQR4XCqFJB1D9P50w==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-process@3.577.0': + resolution: {integrity: sha512-Gin6BWtOiXxIgITrJ3Nwc+Y2P1uVT6huYR4EcbA/DJUPWyO0n9y5UFLewPvVbLkRn15JeEqErBLUrHclkiOKtw==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-sso@3.478.0': + resolution: {integrity: sha512-LsDShG51X/q+s5ZFN7kHVqrd8ZHdyEyHqdhoocmRvvw2Dif50M0AqQfvCrW1ndj5CNzXO4x/eH8EK5ZOVlS6Sg==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-sso@3.568.0': + resolution: {integrity: sha512-+TA77NWOEXMUcfLoOuim6xiyXFg1GqHj55ggI1goTKGVvdHYZ+rhxZbwjI29+ewzPt/qcItDJcvhrjOrg9lCag==} engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-sso@3.687.0': - resolution: {integrity: sha512-N1YCoE7DovIRF2ReyRrA4PZzF0WNi4ObPwdQQkVxhvSm7PwjbWxrfq7rpYB+6YB1Uq3QPzgVwUFONE36rdpxUQ==} + '@aws-sdk/credential-provider-sso@3.583.0': + resolution: {integrity: sha512-G/1EvL9tBezSiU+06tG4K/kOvFfPjnheT4JSXqjPM7+vjKzgp2jxp1J9MMd69zs4jVWon932zMeGgjrCplzMEg==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.468.0': + resolution: {integrity: sha512-rexymPmXjtkwCPfhnUq3EjO1rSkf39R4Jz9CqiM7OsqK2qlT5Y/V3gnMKn0ZMXsYaQOMfM3cT5xly5R+OKDHlw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.568.0': + resolution: {integrity: sha512-ZJSmTmoIdg6WqAULjYzaJ3XcbgBzVy36lir6Y0UBMRGaxDgos1AARuX6EcYzXOl+ksLvxt/xMQ+3aYh1LWfKSw==} engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.568.0 - '@aws-sdk/credential-provider-web-identity@3.686.0': - resolution: {integrity: sha512-40UqCpPxyHCXDP7CGd9JIOZDgDZf+u1OyLaGBpjQJlz1HYuEsIWnnbTe29Yg3Ah/Zc3g4NBWcUdlGVotlnpnDg==} + '@aws-sdk/credential-provider-web-identity@3.577.0': + resolution: {integrity: sha512-ZGHGNRaCtJJmszb9UTnC7izNCtRUttdPlLdMkh41KPS32vfdrBDHs1JrpbZijItRj1xKuOXsiYSXLAaHGcLh8Q==} engines: {node: '>=16.0.0'} peerDependencies: - '@aws-sdk/client-sts': ^3.686.0 + '@aws-sdk/client-sts': ^3.577.0 + + '@aws-sdk/credential-providers@3.569.0': + resolution: {integrity: sha512-UL7EewaM1Xk6e4XLsxrCBv/owVSDI6Katnok6uMfqA8dA0x3ELjO7W35DW4wpWejQHErN5Gp1zloV9y3t34FMQ==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-host-header@3.468.0': + resolution: {integrity: sha512-gwQ+/QhX+lhof304r6zbZ/V5l5cjhGRxLL3CjH1uJPMcOAbw9wUlMdl+ibr8UwBZ5elfKFGiB1cdW/0uMchw0w==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-host-header@3.567.0': + resolution: {integrity: sha512-zQHHj2N3in9duKghH7AuRNrOMLnKhW6lnmb7dznou068DJtDr76w475sHp2TF0XELsOGENbbBsOlN/S5QBFBVQ==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-host-header@3.577.0': + resolution: {integrity: sha512-9ca5MJz455CODIVXs0/sWmJm7t3QO4EUa1zf8pE8grLpzf0J94bz/skDWm37Pli13T3WaAQBHCTiH2gUVfCsWg==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-logger@3.468.0': + resolution: {integrity: sha512-X5XHKV7DHRXI3f29SAhJPe/OxWRFgDWDMMCALfzhmJfCi6Jfh0M14cJKoC+nl+dk9lB+36+jKjhjETZaL2bPlA==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-logger@3.568.0': + resolution: {integrity: sha512-BinH72RG7K3DHHC1/tCulocFv+ZlQ9SrPF9zYT0T1OT95JXuHhB7fH8gEABrc6DAtOdJJh2fgxQjPy5tzPtsrA==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-logger@3.577.0': + resolution: {integrity: sha512-aPFGpGjTZcJYk+24bg7jT4XdIp42mFXSuPt49lw5KygefLyJM/sB0bKKqPYYivW0rcuZ9brQ58eZUNthrzYAvg==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.468.0': + resolution: {integrity: sha512-vch9IQib2Ng9ucSyRW2eKNQXHUPb5jUPCLA5otTW/8nGjcOU37LxQG4WrxO7uaJ9Oe8hjHO+hViE3P0KISUhtA==} + engines: {node: '>=14.0.0'} - '@aws-sdk/credential-providers@3.687.0': - resolution: {integrity: sha512-3aKlmKaOplpanOycmoigbTrQsqtxpzhpfquCey51aHf9GYp2yYyYF1YOgkXpE3qm3w6eiEN1asjJ2gqoECUuPA==} + '@aws-sdk/middleware-recursion-detection@3.567.0': + resolution: {integrity: sha512-rFk3QhdT4IL6O/UWHmNdjJiURutBCy+ogGqaNHf/RELxgXH3KmYorLwCe0eFb5hq8f6vr3zl4/iH7YtsUOuo1w==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.577.0': + resolution: {integrity: sha512-pn3ZVEd2iobKJlR3H+bDilHjgRnNrQ6HMmK9ZzZw89Ckn3Dcbv48xOv4RJvu0aU8SDLl/SNCxppKjeLDTPGBNA==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-host-header@3.686.0': - resolution: {integrity: sha512-+Yc6rO02z+yhFbHmRZGvEw1vmzf/ifS9a4aBjJGeVVU+ZxaUvnk+IUZWrj4YQopUQ+bSujmMUzJLXSkbDq7yuw==} + '@aws-sdk/middleware-signing@3.468.0': + resolution: {integrity: sha512-s+7fSB1gdnnTj5O0aCCarX3z5Vppop8kazbNSZADdkfHIDWCN80IH4ZNjY3OWqaAz0HmR4LNNrovdR304ojb4Q==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-user-agent@3.478.0': + resolution: {integrity: sha512-Rec+nAPIzzwxgHPW+xqY6tooJGFOytpYg/xSRv8/IXl3xKGhmpMGs6gDWzmMBv/qy5nKTvLph/csNWJ98GWXCw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-user-agent@3.567.0': + resolution: {integrity: sha512-a7DBGMRBLWJU3BqrQjOtKS4/RcCh/BhhKqwjCE0FEhhm6A/GGuAs/DcBGOl6Y8Wfsby3vejSlppTLH/qtV1E9w==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-logger@3.686.0': - resolution: {integrity: sha512-cX43ODfA2+SPdX7VRxu6gXk4t4bdVJ9pkktbfnkE5t27OlwNfvSGGhnHrQL8xTOFeyQ+3T+oowf26gf1OI+vIg==} + '@aws-sdk/middleware-user-agent@3.583.0': + resolution: {integrity: sha512-xVNXXXDWvBVI/AeVtSdA9SVumqxiZaESk/JpUn9GMkmtTKfter0Cweap+1iQ9j8bRAO0vNhmIkbcvdB1S4WVUw==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-recursion-detection@3.686.0': - resolution: {integrity: sha512-jF9hQ162xLgp9zZ/3w5RUNhmwVnXDBlABEUX8jCgzaFpaa742qR/KKtjjZQ6jMbQnP+8fOCSXFAVNMU+s6v81w==} + '@aws-sdk/region-config-resolver@3.470.0': + resolution: {integrity: sha512-C1o1J06iIw8cyAAOvHqT4Bbqf+PgQ/RDlSyjt2gFfP2OovDpc2o2S90dE8f8iZdSGpg70N5MikT1DBhW9NbhtQ==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/region-config-resolver@3.567.0': + resolution: {integrity: sha512-VMDyYi5Dh2NydDiIARZ19DwMfbyq0llS736cp47qopmO6wzdeul7WRTx8NKfEYN0/AwEaqmTW0ohx58jSB1lYg==} engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-user-agent@3.687.0': - resolution: {integrity: sha512-nUgsKiEinyA50CaDXojAkOasAU3Apdg7Qox6IjNUC4ZjgOu7QWsCDB5N28AYMUt06cNYeYQdfMX1aEzG85a1Mg==} + '@aws-sdk/region-config-resolver@3.577.0': + resolution: {integrity: sha512-4ChCFACNwzqx/xjg3zgFcW8Ali6R9C95cFECKWT/7CUM1D0MGvkclSH2cLarmHCmJgU6onKkJroFtWp0kHhgyg==} engines: {node: '>=16.0.0'} - '@aws-sdk/region-config-resolver@3.686.0': - resolution: {integrity: sha512-6zXD3bSD8tcsMAVVwO1gO7rI1uy2fCD3czgawuPGPopeLiPpo6/3FoUWCQzk2nvEhj7p9Z4BbjwZGSlRkVrXTw==} + '@aws-sdk/token-providers@3.478.0': + resolution: {integrity: sha512-7b5tj1y/wGHZIZ+ckjOUKgKrMuCJMF/G1UKZKIqqdekeEsjcThbvoxAMeY0FEowu2ODVk/ggOmpBFxcu0iYd6A==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/token-providers@3.568.0': + resolution: {integrity: sha512-mCQElYzY5N2JlXB7LyjOoLvRN/JiSV+E9szLwhYN3dleTUCMbGqWb7RiAR2V3fO+mz8f9kR7DThTExKJbKogKw==} engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sso-oidc': ^3.568.0 - '@aws-sdk/token-providers@3.686.0': - resolution: {integrity: sha512-9oL4kTCSePFmyKPskibeiOXV6qavPZ63/kXM9Wh9V6dTSvBtLeNnMxqGvENGKJcTdIgtoqyqA6ET9u0PJ5IRIg==} + '@aws-sdk/token-providers@3.577.0': + resolution: {integrity: sha512-0CkIZpcC3DNQJQ1hDjm2bdSy/Xjs7Ny5YvSsacasGOkNfk+FdkiQy6N67bZX3Zbc9KIx+Nz4bu3iDeNSNplnnQ==} engines: {node: '>=16.0.0'} peerDependencies: - '@aws-sdk/client-sso-oidc': ^3.686.0 + '@aws-sdk/client-sso-oidc': ^3.577.0 + + '@aws-sdk/types@3.468.0': + resolution: {integrity: sha512-rx/9uHI4inRbp2tw3Y4Ih4PNZkVj32h7WneSg3MVgVjAoVD5Zti9KhS5hkvsBxfgmQmg0AQbE+b1sy5WGAgntA==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/types@3.567.0': + resolution: {integrity: sha512-JBznu45cdgQb8+T/Zab7WpBmfEAh77gsk99xuF4biIb2Sw1mdseONdoGDjEJX57a25TzIv/WUJ2oABWumckz1A==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/types@3.577.0': + resolution: {integrity: sha512-FT2JZES3wBKN/alfmhlo+3ZOq/XJ0C7QOZcDNrpKjB0kqYoKjhVKZ/Hx6ArR0czkKfHzBBEs6y40ebIHx2nSmA==} + engines: {node: '>=16.0.0'} - '@aws-sdk/types@3.686.0': - resolution: {integrity: sha512-xFnrb3wxOoJcW2Xrh63ZgFo5buIu9DF7bOHnwoUxHdNpUXicUh0AHw85TjXxyxIAd0d1psY/DU7QHoNI3OswgQ==} + '@aws-sdk/util-endpoints@3.478.0': + resolution: {integrity: sha512-u9Mcg3euGJGs5clPt9mBuhBjHiEKiD0PnfvArhfq9i+dcY5mbCq/i1Dezp3iv1fZH9xxQt7hPXDfSpt1yUSM6g==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/util-endpoints@3.567.0': + resolution: {integrity: sha512-WVhot3qmi0BKL9ZKnUqsvCd++4RF2DsJIG32NlRaml1FT9KaqSzNv0RXeA6k/kYwiiNT7y3YWu3Lbzy7c6vG9g==} engines: {node: '>=16.0.0'} - '@aws-sdk/util-endpoints@3.686.0': - resolution: {integrity: sha512-7msZE2oYl+6QYeeRBjlDgxQUhq/XRky3cXE0FqLFs2muLS7XSuQEXkpOXB3R782ygAP6JX0kmBxPTLurRTikZg==} + '@aws-sdk/util-endpoints@3.583.0': + resolution: {integrity: sha512-ZC9mb2jq6BFXPYsUsD2tmYcnlmd+9PGNwnFNn8jk4abna5Jjk2wDknN81ybktmBR5ttN9W8ugmktuKtvAMIDCQ==} engines: {node: '>=16.0.0'} - '@aws-sdk/util-locate-window@3.679.0': - resolution: {integrity: sha512-zKTd48/ZWrCplkXpYDABI74rQlbR0DNHs8nH95htfSLj9/mWRSwaGptoxwcihaq/77vi/fl2X3y0a1Bo8bt7RA==} + '@aws-sdk/util-locate-window@3.568.0': + resolution: {integrity: sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==} engines: {node: '>=16.0.0'} - '@aws-sdk/util-user-agent-browser@3.686.0': - resolution: {integrity: sha512-YiQXeGYZegF1b7B2GOR61orhgv79qmI0z7+Agm3NXLO6hGfVV3kFUJbXnjtH1BgWo5hbZYW7HQ2omGb3dnb6Lg==} + '@aws-sdk/util-user-agent-browser@3.468.0': + resolution: {integrity: sha512-OJyhWWsDEizR3L+dCgMXSUmaCywkiZ7HSbnQytbeKGwokIhD69HTiJcibF/sgcM5gk4k3Mq3puUhGnEZ46GIig==} + + '@aws-sdk/util-user-agent-browser@3.567.0': + resolution: {integrity: sha512-cqP0uXtZ7m7hRysf3fRyJwcY1jCgQTpJy7BHB5VpsE7DXlXHD5+Ur5L42CY7UrRPrB6lc6YGFqaAOs5ghMcLyA==} + + '@aws-sdk/util-user-agent-browser@3.577.0': + resolution: {integrity: sha512-zEAzHgR6HWpZOH7xFgeJLc6/CzMcx4nxeQolZxVZoB5pPaJd3CjyRhZN0xXeZB0XIRCWmb4yJBgyiugXLNMkLA==} + + '@aws-sdk/util-user-agent-node@3.470.0': + resolution: {integrity: sha512-QxsZ9iVHcBB/XRdYvwfM5AMvNp58HfqkIrH88mY0cmxuvtlIGDfWjczdDrZMJk9y0vIq+cuoCHsGXHu7PyiEAQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + + '@aws-sdk/util-user-agent-node@3.568.0': + resolution: {integrity: sha512-NVoZoLnKF+eXPBvXg+KqixgJkPSrerR6Gqmbjwqbv14Ini+0KNKB0/MXas1mDGvvEgtNkHI/Cb9zlJ3KXpti2A==} + engines: {node: '>=16.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true - '@aws-sdk/util-user-agent-node@3.687.0': - resolution: {integrity: sha512-idkP6ojSTZ4ek1pJ8wIN7r9U3KR5dn0IkJn3KQBXQ58LWjkRqLtft2vxzdsktWwhPKjjmIKl1S0kbvqLawf8XQ==} + '@aws-sdk/util-user-agent-node@3.577.0': + resolution: {integrity: sha512-XqvtFjbSMtycZTWVwDe8DRWovuoMbA54nhUoZwVU6rW9OSD6NZWGR512BUGHFaWzW0Wg8++Dj10FrKTG2XtqfA==} engines: {node: '>=16.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -1058,52 +1165,60 @@ packages: aws-crt: optional: true + '@aws-sdk/util-utf8-browser@3.259.0': + resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + '@babel/code-frame@7.10.4': resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==} - '@babel/code-frame@7.26.2': - resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + '@babel/code-frame@7.22.10': + resolution: {integrity: sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==} + engines: {node: '>=6.9.0'} + + '@babel/code-frame@7.22.13': + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} + engines: {node: '>=6.9.0'} + + '@babel/code-frame@7.24.6': + resolution: {integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.26.2': - resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==} + '@babel/compat-data@7.24.6': + resolution: {integrity: sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==} engines: {node: '>=6.9.0'} - '@babel/core@7.26.0': - resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + '@babel/core@7.24.6': + resolution: {integrity: sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==} engines: {node: '>=6.9.0'} '@babel/generator@7.17.7': resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} engines: {node: '>=6.9.0'} - '@babel/generator@7.2.0': - resolution: {integrity: sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg==} - - '@babel/generator@7.26.2': - resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==} + '@babel/generator@7.24.6': + resolution: {integrity: sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.25.9': - resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} + '@babel/helper-annotate-as-pure@7.24.6': + resolution: {integrity: sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==} engines: {node: '>=6.9.0'} - '@babel/helper-builder-binary-assignment-operator-visitor@7.25.9': - resolution: {integrity: sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==} + '@babel/helper-builder-binary-assignment-operator-visitor@7.24.6': + resolution: {integrity: sha512-+wnfqc5uHiMYtvRX7qu80Toef8BXeh4HHR1SPeonGb1SKPniNEd4a/nlaJJMv/OIEYvIVavvo0yR7u10Gqz0Iw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.25.9': - resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} + '@babel/helper-compilation-targets@7.24.6': + resolution: {integrity: sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.25.9': - resolution: {integrity: sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==} + '@babel/helper-create-class-features-plugin@7.24.6': + resolution: {integrity: sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.25.9': - resolution: {integrity: sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==} + '@babel/helper-create-regexp-features-plugin@7.24.6': + resolution: {integrity: sha512-C875lFBIWWwyv6MHZUG9HmRrlTDgOsLWZfYR0nW69gaKJNe0/Mpxx5r0EID2ZdHQkdUmQo2t0uNckTL08/1BgA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1113,119 +1228,158 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - '@babel/helper-environment-visitor@7.24.7': - resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} + '@babel/helper-environment-visitor@7.22.5': + resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-environment-visitor@7.24.6': + resolution: {integrity: sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==} engines: {node: '>=6.9.0'} - '@babel/helper-function-name@7.24.7': - resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} + '@babel/helper-function-name@7.22.5': + resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} engines: {node: '>=6.9.0'} - '@babel/helper-hoist-variables@7.24.7': - resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} + '@babel/helper-function-name@7.24.6': + resolution: {integrity: sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.25.9': - resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} + '@babel/helper-hoist-variables@7.22.5': + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.25.9': - resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + '@babel/helper-hoist-variables@7.24.6': + resolution: {integrity: sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.26.0': - resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + '@babel/helper-member-expression-to-functions@7.24.6': + resolution: {integrity: sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.24.6': + resolution: {integrity: sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.24.6': + resolution: {integrity: sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-optimise-call-expression@7.25.9': - resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} + '@babel/helper-optimise-call-expression@7.24.6': + resolution: {integrity: sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.25.9': - resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} + '@babel/helper-plugin-utils@7.24.6': + resolution: {integrity: sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==} engines: {node: '>=6.9.0'} - '@babel/helper-remap-async-to-generator@7.25.9': - resolution: {integrity: sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==} + '@babel/helper-remap-async-to-generator@7.24.6': + resolution: {integrity: sha512-1Qursq9ArRZPAMOZf/nuzVW8HgJLkTB9y9LfP4lW2MVp4e9WkLJDovfKBxoDcCk6VuzIxyqWHyBoaCtSRP10yg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-replace-supers@7.25.9': - resolution: {integrity: sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==} + '@babel/helper-replace-supers@7.24.6': + resolution: {integrity: sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-simple-access@7.25.9': - resolution: {integrity: sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==} + '@babel/helper-simple-access@7.24.6': + resolution: {integrity: sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==} engines: {node: '>=6.9.0'} - '@babel/helper-skip-transparent-expression-wrappers@7.25.9': - resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} + '@babel/helper-skip-transparent-expression-wrappers@7.24.6': + resolution: {integrity: sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==} engines: {node: '>=6.9.0'} - '@babel/helper-split-export-declaration@7.24.7': - resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} + '@babel/helper-split-export-declaration@7.22.6': + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.25.9': - resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + '@babel/helper-split-export-declaration@7.24.6': + resolution: {integrity: sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.25.9': - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + '@babel/helper-string-parser@7.22.5': + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.25.9': - resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + '@babel/helper-string-parser@7.23.4': + resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.25.9': - resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==} + '@babel/helper-string-parser@7.24.6': + resolution: {integrity: sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.26.0': - resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + '@babel/helper-validator-identifier@7.22.20': + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.25.9': - resolution: {integrity: sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==} + '@babel/helper-validator-identifier@7.22.5': + resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} engines: {node: '>=6.9.0'} - '@babel/parser@7.26.2': - resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==} - engines: {node: '>=6.0.0'} - hasBin: true + '@babel/helper-validator-identifier@7.24.6': + resolution: {integrity: sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==} + engines: {node: '>=6.9.0'} - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9': - resolution: {integrity: sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==} + '@babel/helper-validator-option@7.24.6': + resolution: {integrity: sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9': - resolution: {integrity: sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==} + '@babel/helper-wrap-function@7.24.6': + resolution: {integrity: sha512-f1JLrlw/jbiNfxvdrfBgio/gRBk3yTAEJWirpAkiJG2Hb22E7cEYKHWo0dFPTv/niPovzIdPdEDetrv6tC6gPQ==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.24.6': + resolution: {integrity: sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.22.10': + resolution: {integrity: sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.22.20': + resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.6': + resolution: {integrity: sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.22.10': + resolution: {integrity: sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@7.24.6': + resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.6': + resolution: {integrity: sha512-bYndrJ6Ph6Ar+GaB5VAc0JPoP80bQCm4qon6JEzXfRl5QZyQ8Ur1K6k7htxWmPA5z+k7JQvaMUrtXlqclWYzKw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9': - resolution: {integrity: sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==} + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.6': + resolution: {integrity: sha512-iVuhb6poq5ikqRq2XWU6OQ+R5o9wF+r/or9CeUyovgptz0UlnK4/seOQ1Istu/XybYjAhQv1FRSSfHHufIku5Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9': - resolution: {integrity: sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==} + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.6': + resolution: {integrity: sha512-c8TER5xMDYzzFcGqOEp9l4hvB7dcbhcGjcLVwxWfe4P5DOafdwjsBJZKsmv+o3aXh7NhopvayQIovHrh2zSRUQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9': - resolution: {integrity: sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==} + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.6': + resolution: {integrity: sha512-z8zEjYmwBUHN/pCF3NuWBhHQjJCrd33qAi8MgANfMrAvn72k2cImT8VjK9LJFu4ysOLJqhfkYYb3MvwANRUNZQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1244,14 +1398,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-proposal-decorators@7.25.9': - resolution: {integrity: sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==} + '@babel/plugin-proposal-decorators@7.24.6': + resolution: {integrity: sha512-8DjR0/DzlBhz2SVi9a19/N2U5+C3y3rseXuyoKL9SP8vnbewscj1eHZtL6kpEn4UCuUmqEo0mvqyDYRFoN2gpA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-proposal-export-default-from@7.25.9': - resolution: {integrity: sha512-ykqgwNfSnNOB+C8fV5X4mG3AVmvu+WVxcaU9xHHtBb7PCrPeweMmPjGsn8eMaeJg6SJuoUuZENeeSWaarWqonQ==} + '@babel/plugin-proposal-export-default-from@7.24.6': + resolution: {integrity: sha512-qPPDbYs9j5IArMFqYi85QxatHURSzRyskKpIbjrVoVglDuGdhu1s7UTCmXvP/qR2aHa3EdJ8X3iZvQAHjmdHUw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1309,11 +1463,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-bigint@7.8.3': - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-class-properties@7.12.13': resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: @@ -1325,8 +1474,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-decorators@7.25.9': - resolution: {integrity: sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==} + '@babel/plugin-syntax-decorators@7.24.6': + resolution: {integrity: sha512-gInH8LEqBp+wkwTVihCd/qf+4s28g81FZyvlIbAurHk9eSiItEKG7E0uNK2UdpgsD79aJVAW3R3c85h0YJ0jsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1336,26 +1485,31 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-export-default-from@7.25.9': - resolution: {integrity: sha512-9MhJ/SMTsVqsd69GyQg89lYR4o9T+oDGv5F6IsigxxqFVOyR/IflDLYP8WDI1l8fkhNGGktqkvL5qwNCtGEpgQ==} + '@babel/plugin-syntax-export-default-from@7.24.6': + resolution: {integrity: sha512-Nzl7kZ4tjOM2LJpejBMPwZs7OJfc26++2HsMQuSrw6gxpqXGtZZ3Rj4Zt4Qm7vulMZL2gHIGGc2stnlQnHQCqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-flow@7.26.0': - resolution: {integrity: sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==} + '@babel/plugin-syntax-export-namespace-from@7.8.3': + resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-flow@7.24.6': + resolution: {integrity: sha512-gNkksSdV8RbsCoHF9sjVYrHfYACMl/8U32UfUhJ9+84/ASXw8dlx+eHyyF0m6ncQJ9IBSxfuCkB36GJqYdXTOA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.26.0': - resolution: {integrity: sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==} + '@babel/plugin-syntax-import-assertions@7.24.6': + resolution: {integrity: sha512-BE6o2BogJKJImTmGpkmOic4V0hlRRxVtzqxiSPa8TIFxyhi4EFjHm08nq1M4STK4RytuLMgnSz0/wfflvGFNOg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.26.0': - resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} + '@babel/plugin-syntax-import-attributes@7.24.6': + resolution: {integrity: sha512-D+CfsVZousPXIdudSII7RGy52+dYRtbyKAZcvtQKq/NpsivyMVduepzcLqG5pMBugtMdedxdC8Ramdpcne9ZWQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1370,8 +1524,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.25.9': - resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + '@babel/plugin-syntax-jsx@7.24.6': + resolution: {integrity: sha512-lWfvAIFNWMlCsU0DRUun2GpFwZdGTukLaHJqRh1JRb80NdAP5Sb1HDHB5X9P9OtgZHQl089UzQkpYlBq2VTPRw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1418,8 +1572,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.25.9': - resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + '@babel/plugin-syntax-typescript@7.24.6': + resolution: {integrity: sha512-TzCtxGgVTEJWWwcYwQhCIQ6WaKlo80/B+Onsk4RRCcYqpYGFcG9etPW94VToGte5AAcxRrhjPUFvUS3Y2qKi4A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1430,368 +1584,356 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-arrow-functions@7.25.9': - resolution: {integrity: sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==} + '@babel/plugin-transform-arrow-functions@7.24.6': + resolution: {integrity: sha512-jSSSDt4ZidNMggcLx8SaKsbGNEfIl0PHx/4mFEulorE7bpYLbN0d3pDW3eJ7Y5Z3yPhy3L3NaPCYyTUY7TuugQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-generator-functions@7.25.9': - resolution: {integrity: sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==} + '@babel/plugin-transform-async-generator-functions@7.24.6': + resolution: {integrity: sha512-VEP2o4iR2DqQU6KPgizTW2mnMx6BG5b5O9iQdrW9HesLkv8GIA8x2daXBQxw1MrsIkFQGA/iJ204CKoQ8UcnAA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-to-generator@7.25.9': - resolution: {integrity: sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==} + '@babel/plugin-transform-async-to-generator@7.24.6': + resolution: {integrity: sha512-NTBA2SioI3OsHeIn6sQmhvXleSl9T70YY/hostQLveWs0ic+qvbA3fa0kwAwQ0OA/XGaAerNZRQGJyRfhbJK4g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoped-functions@7.25.9': - resolution: {integrity: sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==} + '@babel/plugin-transform-block-scoped-functions@7.24.6': + resolution: {integrity: sha512-XNW7jolYHW9CwORrZgA/97tL/k05qe/HL0z/qqJq1mdWhwwCM6D4BJBV7wAz9HgFziN5dTOG31znkVIzwxv+vw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.25.9': - resolution: {integrity: sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==} + '@babel/plugin-transform-block-scoping@7.24.6': + resolution: {integrity: sha512-S/t1Xh4ehW7sGA7c1j/hiOBLnEYCp/c2sEG4ZkL8kI1xX9tW2pqJTCHKtdhe/jHKt8nG0pFCrDHUXd4DvjHS9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-properties@7.25.9': - resolution: {integrity: sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==} + '@babel/plugin-transform-class-properties@7.24.6': + resolution: {integrity: sha512-j6dZ0Z2Z2slWLR3kt9aOmSIrBvnntWjMDN/TVcMPxhXMLmJVqX605CBRlcGI4b32GMbfifTEsdEjGjiE+j/c3A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-static-block@7.26.0': - resolution: {integrity: sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==} + '@babel/plugin-transform-class-static-block@7.24.6': + resolution: {integrity: sha512-1QSRfoPI9RoLRa8Mnakc6v3e0gJxiZQTYrMfLn+mD0sz5+ndSzwymp2hDcYJTyT0MOn0yuWzj8phlIvO72gTHA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 - '@babel/plugin-transform-classes@7.25.9': - resolution: {integrity: sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==} + '@babel/plugin-transform-classes@7.24.6': + resolution: {integrity: sha512-+fN+NO2gh8JtRmDSOB6gaCVo36ha8kfCW1nMq2Gc0DABln0VcHN4PrALDvF5/diLzIRKptC7z/d7Lp64zk92Fg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-computed-properties@7.25.9': - resolution: {integrity: sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==} + '@babel/plugin-transform-computed-properties@7.24.6': + resolution: {integrity: sha512-cRzPobcfRP0ZtuIEkA8QzghoUpSB3X3qSH5W2+FzG+VjWbJXExtx0nbRqwumdBN1x/ot2SlTNQLfBCnPdzp6kg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.25.9': - resolution: {integrity: sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==} + '@babel/plugin-transform-destructuring@7.24.6': + resolution: {integrity: sha512-YLW6AE5LQpk5npNXL7i/O+U9CE4XsBCuRPgyjl1EICZYKmcitV+ayuuUGMJm2lC1WWjXYszeTnIxF/dq/GhIZQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dotall-regex@7.25.9': - resolution: {integrity: sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==} + '@babel/plugin-transform-dotall-regex@7.24.6': + resolution: {integrity: sha512-rCXPnSEKvkm/EjzOtLoGvKseK+dS4kZwx1HexO3BtRtgL0fQ34awHn34aeSHuXtZY2F8a1X8xqBBPRtOxDVmcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-keys@7.25.9': - resolution: {integrity: sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==} + '@babel/plugin-transform-duplicate-keys@7.24.6': + resolution: {integrity: sha512-/8Odwp/aVkZwPFJMllSbawhDAO3UJi65foB00HYnK/uXvvCPm0TAXSByjz1mpRmp0q6oX2SIxpkUOpPFHk7FLA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9': - resolution: {integrity: sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-dynamic-import@7.25.9': - resolution: {integrity: sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==} + '@babel/plugin-transform-dynamic-import@7.24.6': + resolution: {integrity: sha512-vpq8SSLRTBLOHUZHSnBqVo0AKX3PBaoPs2vVzYVWslXDTDIpwAcCDtfhUcHSQQoYoUvcFPTdC8TZYXu9ZnLT/w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.25.9': - resolution: {integrity: sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==} + '@babel/plugin-transform-exponentiation-operator@7.24.6': + resolution: {integrity: sha512-EemYpHtmz0lHE7hxxxYEuTYOOBZ43WkDgZ4arQ4r+VX9QHuNZC+WH3wUWmRNvR8ECpTRne29aZV6XO22qpOtdA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-export-namespace-from@7.25.9': - resolution: {integrity: sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==} + '@babel/plugin-transform-export-namespace-from@7.24.6': + resolution: {integrity: sha512-inXaTM1SVrIxCkIJ5gqWiozHfFMStuGbGJAxZFBoHcRRdDP0ySLb3jH6JOwmfiinPwyMZqMBX+7NBDCO4z0NSA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-flow-strip-types@7.25.9': - resolution: {integrity: sha512-/VVukELzPDdci7UUsWQaSkhgnjIWXnIyRpM02ldxaVoFK96c41So8JcKT3m0gYjyv7j5FNPGS5vfELrWalkbDA==} + '@babel/plugin-transform-flow-strip-types@7.24.6': + resolution: {integrity: sha512-1l8b24NoCpaQ13Vi6FtLG1nv6kNoi8PWvQb1AYO7GHZDpFfBYc3lbXArx1lP2KRt8b4pej1eWc/zrRmsQTfOdQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-for-of@7.25.9': - resolution: {integrity: sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==} + '@babel/plugin-transform-for-of@7.24.6': + resolution: {integrity: sha512-n3Sf72TnqK4nw/jziSqEl1qaWPbCRw2CziHH+jdRYvw4J6yeCzsj4jdw8hIntOEeDGTmHVe2w4MVL44PN0GMzg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-function-name@7.25.9': - resolution: {integrity: sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==} + '@babel/plugin-transform-function-name@7.24.6': + resolution: {integrity: sha512-sOajCu6V0P1KPljWHKiDq6ymgqB+vfo3isUS4McqW1DZtvSVU2v/wuMhmRmkg3sFoq6GMaUUf8W4WtoSLkOV/Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-json-strings@7.25.9': - resolution: {integrity: sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==} + '@babel/plugin-transform-json-strings@7.24.6': + resolution: {integrity: sha512-Uvgd9p2gUnzYJxVdBLcU0KurF8aVhkmVyMKW4MIY1/BByvs3EBpv45q01o7pRTVmTvtQq5zDlytP3dcUgm7v9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-literals@7.25.9': - resolution: {integrity: sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==} + '@babel/plugin-transform-literals@7.24.6': + resolution: {integrity: sha512-f2wHfR2HF6yMj+y+/y07+SLqnOSwRp8KYLpQKOzS58XLVlULhXbiYcygfXQxJlMbhII9+yXDwOUFLf60/TL5tw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.25.9': - resolution: {integrity: sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==} + '@babel/plugin-transform-logical-assignment-operators@7.24.6': + resolution: {integrity: sha512-EKaWvnezBCMkRIHxMJSIIylzhqK09YpiJtDbr2wsXTwnO0TxyjMUkaw4RlFIZMIS0iDj0KyIg7H7XCguHu/YDA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-member-expression-literals@7.25.9': - resolution: {integrity: sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==} + '@babel/plugin-transform-member-expression-literals@7.24.6': + resolution: {integrity: sha512-9g8iV146szUo5GWgXpRbq/GALTnY+WnNuRTuRHWWFfWGbP9ukRL0aO/jpu9dmOPikclkxnNsjY8/gsWl6bmZJQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-amd@7.25.9': - resolution: {integrity: sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==} + '@babel/plugin-transform-modules-amd@7.24.6': + resolution: {integrity: sha512-eAGogjZgcwqAxhyFgqghvoHRr+EYRQPFjUXrTYKBRb5qPnAVxOOglaxc4/byHqjvq/bqO2F3/CGwTHsgKJYHhQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-commonjs@7.25.9': - resolution: {integrity: sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==} + '@babel/plugin-transform-modules-commonjs@7.24.6': + resolution: {integrity: sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.25.9': - resolution: {integrity: sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==} + '@babel/plugin-transform-modules-systemjs@7.24.6': + resolution: {integrity: sha512-xg1Z0J5JVYxtpX954XqaaAT6NpAY6LtZXvYFCJmGFJWwtlz2EmJoR8LycFRGNE8dBKizGWkGQZGegtkV8y8s+w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-umd@7.25.9': - resolution: {integrity: sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==} + '@babel/plugin-transform-modules-umd@7.24.6': + resolution: {integrity: sha512-esRCC/KsSEUvrSjv5rFYnjZI6qv4R1e/iHQrqwbZIoRJqk7xCvEUiN7L1XrmW5QSmQe3n1XD88wbgDTWLbVSyg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-named-capturing-groups-regex@7.25.9': - resolution: {integrity: sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==} + '@babel/plugin-transform-named-capturing-groups-regex@7.24.6': + resolution: {integrity: sha512-6DneiCiu91wm3YiNIGDWZsl6GfTTbspuj/toTEqLh9d4cx50UIzSdg+T96p8DuT7aJOBRhFyaE9ZvTHkXrXr6Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-new-target@7.25.9': - resolution: {integrity: sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==} + '@babel/plugin-transform-new-target@7.24.6': + resolution: {integrity: sha512-f8liz9JG2Va8A4J5ZBuaSdwfPqN6axfWRK+y66fjKYbwf9VBLuq4WxtinhJhvp1w6lamKUwLG0slK2RxqFgvHA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-nullish-coalescing-operator@7.25.9': - resolution: {integrity: sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==} + '@babel/plugin-transform-nullish-coalescing-operator@7.24.6': + resolution: {integrity: sha512-+QlAiZBMsBK5NqrBWFXCYeXyiU1y7BQ/OYaiPAcQJMomn5Tyg+r5WuVtyEuvTbpV7L25ZSLfE+2E9ywj4FD48A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-numeric-separator@7.25.9': - resolution: {integrity: sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==} + '@babel/plugin-transform-numeric-separator@7.24.6': + resolution: {integrity: sha512-6voawq8T25Jvvnc4/rXcWZQKKxUNZcKMS8ZNrjxQqoRFernJJKjE3s18Qo6VFaatG5aiX5JV1oPD7DbJhn0a4Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-rest-spread@7.25.9': - resolution: {integrity: sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==} + '@babel/plugin-transform-object-rest-spread@7.24.6': + resolution: {integrity: sha512-OKmi5wiMoRW5Smttne7BwHM8s/fb5JFs+bVGNSeHWzwZkWXWValR1M30jyXo1s/RaqgwwhEC62u4rFH/FBcBPg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-super@7.25.9': - resolution: {integrity: sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==} + '@babel/plugin-transform-object-super@7.24.6': + resolution: {integrity: sha512-N/C76ihFKlZgKfdkEYKtaRUtXZAgK7sOY4h2qrbVbVTXPrKGIi8aww5WGe/+Wmg8onn8sr2ut6FXlsbu/j6JHg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-catch-binding@7.25.9': - resolution: {integrity: sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==} + '@babel/plugin-transform-optional-catch-binding@7.24.6': + resolution: {integrity: sha512-L5pZ+b3O1mSzJ71HmxSCmTVd03VOT2GXOigug6vDYJzE5awLI7P1g0wFcdmGuwSDSrQ0L2rDOe/hHws8J1rv3w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.25.9': - resolution: {integrity: sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==} + '@babel/plugin-transform-optional-chaining@7.24.6': + resolution: {integrity: sha512-cHbqF6l1QP11OkYTYQ+hhVx1E017O5ZcSPXk9oODpqhcAD1htsWG2NpHrrhthEO2qZomLK0FXS+u7NfrkF5aOQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-parameters@7.25.9': - resolution: {integrity: sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==} + '@babel/plugin-transform-parameters@7.24.6': + resolution: {integrity: sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-methods@7.25.9': - resolution: {integrity: sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==} + '@babel/plugin-transform-private-methods@7.24.6': + resolution: {integrity: sha512-T9LtDI0BgwXOzyXrvgLTT8DFjCC/XgWLjflczTLXyvxbnSR/gpv0hbmzlHE/kmh9nOvlygbamLKRo6Op4yB6aw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-property-in-object@7.25.9': - resolution: {integrity: sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==} + '@babel/plugin-transform-private-property-in-object@7.24.6': + resolution: {integrity: sha512-Qu/ypFxCY5NkAnEhCF86Mvg3NSabKsh/TPpBVswEdkGl7+FbsYHy1ziRqJpwGH4thBdQHh8zx+z7vMYmcJ7iaQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-property-literals@7.25.9': - resolution: {integrity: sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==} + '@babel/plugin-transform-property-literals@7.24.6': + resolution: {integrity: sha512-oARaglxhRsN18OYsnPTpb8TcKQWDYNsPNmTnx5++WOAsUJ0cSC/FZVlIJCKvPbU4yn/UXsS0551CFKJhN0CaMw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-display-name@7.25.9': - resolution: {integrity: sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==} + '@babel/plugin-transform-react-display-name@7.24.6': + resolution: {integrity: sha512-/3iiEEHDsJuj9QU09gbyWGSUxDboFcD7Nj6dnHIlboWSodxXAoaY/zlNMHeYAC0WsERMqgO9a7UaM77CsYgWcg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-development@7.25.9': - resolution: {integrity: sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==} + '@babel/plugin-transform-react-jsx-development@7.24.6': + resolution: {integrity: sha512-F7EsNp5StNDouSSdYyDSxh4J+xvj/JqG+Cb6s2fA+jCyHOzigG5vTwgH8tU2U8Voyiu5zCG9bAK49wTr/wPH0w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-self@7.25.9': - resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} + '@babel/plugin-transform-react-jsx-self@7.24.6': + resolution: {integrity: sha512-FfZfHXtQ5jYPQsCRyLpOv2GeLIIJhs8aydpNh39vRDjhD411XcfWDni5i7OjP/Rs8GAtTn7sWFFELJSHqkIxYg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-source@7.25.9': - resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} + '@babel/plugin-transform-react-jsx-source@7.24.6': + resolution: {integrity: sha512-BQTBCXmFRreU3oTUXcGKuPOfXAGb1liNY4AvvFKsOBAJ89RKcTsIrSsnMYkj59fNa66OFKnSa4AJZfy5Y4B9WA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx@7.25.9': - resolution: {integrity: sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==} + '@babel/plugin-transform-react-jsx@7.24.6': + resolution: {integrity: sha512-pCtPHhpRZHfwdA5G1Gpk5mIzMA99hv0R8S/Ket50Rw+S+8hkt3wBWqdqHaPw0CuUYxdshUgsPiLQ5fAs4ASMhw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-pure-annotations@7.25.9': - resolution: {integrity: sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==} + '@babel/plugin-transform-react-pure-annotations@7.24.6': + resolution: {integrity: sha512-0HoDQlFJJkXRyV2N+xOpUETbKHcouSwijRQbKWVtxsPoq5bbB30qZag9/pSc5xcWVYjTHlLsBsY+hZDnzQTPNw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.25.9': - resolution: {integrity: sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==} + '@babel/plugin-transform-regenerator@7.24.6': + resolution: {integrity: sha512-SMDxO95I8WXRtXhTAc8t/NFQUT7VYbIWwJCJgEli9ml4MhqUMh4S6hxgH6SmAC3eAQNWCDJFxcFeEt9w2sDdXg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regexp-modifiers@7.26.0': - resolution: {integrity: sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-reserved-words@7.25.9': - resolution: {integrity: sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==} + '@babel/plugin-transform-reserved-words@7.24.6': + resolution: {integrity: sha512-DcrgFXRRlK64dGE0ZFBPD5egM2uM8mgfrvTMOSB2yKzOtjpGegVYkzh3s1zZg1bBck3nkXiaOamJUqK3Syk+4A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-runtime@7.25.9': - resolution: {integrity: sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==} + '@babel/plugin-transform-runtime@7.24.6': + resolution: {integrity: sha512-W3gQydMb0SY99y/2lV0Okx2xg/8KzmZLQsLaiCmwNRl1kKomz14VurEm+2TossUb+sRvBCnGe+wx8KtIgDtBbQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-shorthand-properties@7.25.9': - resolution: {integrity: sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==} + '@babel/plugin-transform-shorthand-properties@7.24.6': + resolution: {integrity: sha512-xnEUvHSMr9eOWS5Al2YPfc32ten7CXdH7Zwyyk7IqITg4nX61oHj+GxpNvl+y5JHjfN3KXE2IV55wAWowBYMVw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-spread@7.25.9': - resolution: {integrity: sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==} + '@babel/plugin-transform-spread@7.24.6': + resolution: {integrity: sha512-h/2j7oIUDjS+ULsIrNZ6/TKG97FgmEk1PXryk/HQq6op4XUUUwif2f69fJrzK0wza2zjCS1xhXmouACaWV5uPA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-sticky-regex@7.25.9': - resolution: {integrity: sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==} + '@babel/plugin-transform-sticky-regex@7.24.6': + resolution: {integrity: sha512-fN8OcTLfGmYv7FnDrsjodYBo1DhPL3Pze/9mIIE2MGCT1KgADYIOD7rEglpLHZj8PZlC/JFX5WcD+85FLAQusw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-template-literals@7.25.9': - resolution: {integrity: sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==} + '@babel/plugin-transform-template-literals@7.24.6': + resolution: {integrity: sha512-BJbEqJIcKwrqUP+KfUIkxz3q8VzXe2R8Wv8TaNgO1cx+nNavxn/2+H8kp9tgFSOL6wYPPEgFvU6IKS4qoGqhmg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typeof-symbol@7.25.9': - resolution: {integrity: sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==} + '@babel/plugin-transform-typeof-symbol@7.24.6': + resolution: {integrity: sha512-IshCXQ+G9JIFJI7bUpxTE/oA2lgVLAIK8q1KdJNoPXOpvRaNjMySGuvLfBw/Xi2/1lLo953uE8hyYSDW3TSYig==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.25.9': - resolution: {integrity: sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==} + '@babel/plugin-transform-typescript@7.24.6': + resolution: {integrity: sha512-H0i+hDLmaYYSt6KU9cZE0gb3Cbssa/oxWis7PX4ofQzbvsfix9Lbh8SRk7LCPDlLWJHUiFeHU0qRRpF/4Zv7mQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-escapes@7.25.9': - resolution: {integrity: sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==} + '@babel/plugin-transform-unicode-escapes@7.24.6': + resolution: {integrity: sha512-bKl3xxcPbkQQo5eX9LjjDpU2xYHeEeNQbOhj0iPvetSzA+Tu9q/o5lujF4Sek60CM6MgYvOS/DJuwGbiEYAnLw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-property-regex@7.25.9': - resolution: {integrity: sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==} + '@babel/plugin-transform-unicode-property-regex@7.24.6': + resolution: {integrity: sha512-8EIgImzVUxy15cZiPii9GvLZwsy7Vxc+8meSlR3cXFmBIl5W5Tn9LGBf7CDKkHj4uVfNXCJB8RsVfnmY61iedA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-regex@7.25.9': - resolution: {integrity: sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==} + '@babel/plugin-transform-unicode-regex@7.24.6': + resolution: {integrity: sha512-pssN6ExsvxaKU638qcWb81RrvvgZom3jDgU/r5xFZ7TONkZGFf4MhI2ltMb8OcQWhHyxgIavEU+hgqtbKOmsPA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-sets-regex@7.25.9': - resolution: {integrity: sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==} + '@babel/plugin-transform-unicode-sets-regex@7.24.6': + resolution: {integrity: sha512-quiMsb28oXWIDK0gXLALOJRXLgICLiulqdZGOaPPd0vRT7fQp74NtdADAVu+D8s00C+0Xs0MxVP0VKF/sZEUgw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.26.0': - resolution: {integrity: sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==} + '@babel/preset-env@7.24.6': + resolution: {integrity: sha512-CrxEAvN7VxfjOG8JNF2Y/eMqMJbZPZ185amwGUBp8D9USK90xQmv7dLdFSa+VbD7fdIqcy/Mfv7WtzG8+/qxKg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/preset-flow@7.25.9': - resolution: {integrity: sha512-EASHsAhE+SSlEzJ4bzfusnXSHiU+JfAYzj+jbw2vgQKgq5HrUr8qs+vgtiEL5dOH6sEweI+PNt2D7AqrDSHyqQ==} + '@babel/preset-flow@7.24.6': + resolution: {integrity: sha512-huoe0T1Qs9fQhMWbmqE/NHUeZbqmHDsN6n/jYvPcUUHfuKiPV32C9i8tDhMbQ1DEKTjbBP7Rjm3nSLwlB2X05g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1801,46 +1943,65 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - '@babel/preset-react@7.25.9': - resolution: {integrity: sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==} + '@babel/preset-react@7.24.6': + resolution: {integrity: sha512-8mpzh1bWvmINmwM3xpz6ahu57mNaWavMm+wBNjQ4AFu1nghKBiIRET7l/Wmj4drXany/BBGjJZngICcD98F1iw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/preset-typescript@7.26.0': - resolution: {integrity: sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==} + '@babel/preset-typescript@7.24.6': + resolution: {integrity: sha512-U10aHPDnokCFRXgyT/MaIRTivUu2K/mu0vJlwRS9LxJmJet+PFQNKpggPyFCUtC6zWSBPjvxjnpNkAn3Uw2m5w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/register@7.25.9': - resolution: {integrity: sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA==} + '@babel/register@7.24.6': + resolution: {integrity: sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.26.0': - resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} + '@babel/regjsgen@0.8.0': + resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} + + '@babel/runtime@7.22.10': + resolution: {integrity: sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==} engines: {node: '>=6.9.0'} - '@babel/template@7.25.9': - resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + '@babel/runtime@7.24.6': + resolution: {integrity: sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.23.2': - resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} + '@babel/template@7.22.5': + resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.25.9': - resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} + '@babel/template@7.24.6': + resolution: {integrity: sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.17.3': + resolution: {integrity: sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.24.6': + resolution: {integrity: sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==} engines: {node: '>=6.9.0'} '@babel/types@7.17.0': resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} engines: {node: '>=6.9.0'} - '@babel/types@7.26.0': - resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} + '@babel/types@7.22.10': + resolution: {integrity: sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.23.6': + resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.24.6': + resolution: {integrity: sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==} engines: {node: '>=6.9.0'} '@balena/dockerignore@1.0.2': @@ -1850,42 +2011,44 @@ packages: resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} engines: {node: '>=16.13'} - '@cloudflare/workerd-darwin-64@1.20241022.0': - resolution: {integrity: sha512-1NNYun37myMTgCUiPQEJ0cMal4mKZVTpkD0b2tx9hV70xji+frVJcSK8YVLeUm1P+Rw1d/ct8DMgQuCpsz3Fsw==} + '@cloudflare/workerd-darwin-64@1.20240712.0': + resolution: {integrity: sha512-KB1vbOhr62BCAwVr3VaRcngzPeSCQ7zPA9VGrfwYXIxo0Y4zlW1z0EVtcewFSz5XXKr3BtNnJXxdjDPUNkguQw==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20241022.0': - resolution: {integrity: sha512-FOO/0P0U82EsTLTdweNVgw+4VOk5nghExLPLSppdOziq6IR5HVgP44Kmq5LdsUeHUhwUmfOh9hzaTpkNzUqKvw==} + '@cloudflare/workerd-darwin-arm64@1.20240712.0': + resolution: {integrity: sha512-UDwFnCfQGFVCNxOeHxKNEc1ANQk/3OIiFWpVsxgZqJqU/22XM88JHxJW+YcBKsaUGUlpLyImaYUn2/rG+i+9UQ==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20241022.0': - resolution: {integrity: sha512-RsNc19BQJG9yd+ngnjuDeG9ywZG+7t1L4JeglgceyY5ViMNMKVO7Zpbsu69kXslU9h6xyQG+lrmclg3cBpnhYA==} + '@cloudflare/workerd-linux-64@1.20240712.0': + resolution: {integrity: sha512-MxpMHSJcZRUL66TO7BEnEim9WgZ8wJEVOB1Rq7a/IF2hI4/8f+N+02PChh62NkBlWxDfTXAtZy0tyQMm0EGjHg==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20241022.0': - resolution: {integrity: sha512-x5mUXpKxfsosxcFmcq5DaqLs37PejHYVRsNz1cWI59ma7aC4y4Qn6Tf3i0r9MwQTF/MccP4SjVslMU6m4W7IaA==} + '@cloudflare/workerd-linux-arm64@1.20240712.0': + resolution: {integrity: sha512-DtLYZsFFFAMgn+6YCHoQS6nYY4nbdAtcAFa4PhWTjLJDbvQEn3IoK9Bi4ajCL7xG36FeuBdZliSbBiiv7CJjfQ==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20241022.0': - resolution: {integrity: sha512-eBCClx4szCOgKqOlxxbdNszMqQf3MRG1B9BRIqEM/diDfdR9IrZ8l3FaEm+l9gXgPmS6m1NBn40aWuGBl8UTSw==} + '@cloudflare/workerd-windows-64@1.20240712.0': + resolution: {integrity: sha512-u8zoT9PQiiwxuz9npquLBFWrC/RlBWGGZ1aylarZNFlM4sFrRm+bRr6i+KtS+fltHIVXj3teuoKYytA1ppf9Yw==} engines: {node: '>=16'} cpu: [x64] os: [win32] - '@cloudflare/workers-shared@0.7.0': - resolution: {integrity: sha512-LLQRTqx7lKC7o2eCYMpyc5FXV8d0pUX6r3A+agzhqS9aoR5A6zCPefwQGcvbKx83ozX22ATZcemwxQXn12UofQ==} - engines: {node: '>=16.7.0'} + '@cloudflare/workers-types@4.20240512.0': + resolution: {integrity: sha512-o2yTEWg+YK/I1t/Me+dA0oarO0aCbjibp6wSeaw52DSE9tDyKJ7S+Qdyw/XsMrKn4t8kF6f/YOba+9O4MJfW9w==} - '@cloudflare/workers-types@4.20241106.0': - resolution: {integrity: sha512-pI4ivacmp+vgNO/siHDsZ6BdITR0LC4Mh/1+yzVLcl9U75pt5DUDCOWOiqIRFXRq6H65DPnJbEPFo3x9UfgofQ==} + '@cloudflare/workers-types@4.20240524.0': + resolution: {integrity: sha512-GpSr4uE7y39DU9f0+wmrL76xd03wn0jy1ClITaa3ZZltKjirAV8TW1GzHrvvKyVGx6u3lekrFnB1HzVHsCYHDQ==} + + '@cloudflare/workers-types@4.20241004.0': + resolution: {integrity: sha512-3LrPvtecs4umknOF1bTPNLHUG/ZjeSE6PYBQ/tbO7lwaVhjZTaTugiaCny2byrZupBlVNuubQVktcAgMfw0C1A==} '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -1939,12 +2102,12 @@ packages: '@electric-sql/pglite@0.2.12': resolution: {integrity: sha512-J/X42ujcoFEbOkgRyoNqZB5qcqrnJRWVlwpH3fKYoJkTz49N91uAK/rDSSG/85WRas9nC9mdV4FnMTxnQWE/rw==} - '@esbuild-kit/core-utils@3.3.2': - resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + '@esbuild-kit/core-utils@3.1.0': + resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} deprecated: 'Merged into tsx: https://tsx.is' - '@esbuild-kit/esm-loader@2.6.5': - resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + '@esbuild-kit/esm-loader@2.5.5': + resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-plugins/node-globals-polyfill@0.2.3': @@ -1963,20 +2126,20 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + '@esbuild/aix-ppc64@0.20.2': + resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.23.1': - resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} - engines: {node: '>=18'} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.24.0': - resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==} + '@esbuild/aix-ppc64@0.23.0': + resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -1999,20 +2162,20 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + '@esbuild/android-arm64@0.20.2': + resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.23.1': - resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} - engines: {node: '>=18'} + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.24.0': - resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==} + '@esbuild/android-arm64@0.23.0': + resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -2035,20 +2198,20 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + '@esbuild/android-arm@0.20.2': + resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} engines: {node: '>=12'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.23.1': - resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} - engines: {node: '>=18'} + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.24.0': - resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==} + '@esbuild/android-arm@0.23.0': + resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -2071,20 +2234,20 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + '@esbuild/android-x64@0.20.2': + resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} engines: {node: '>=12'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.23.1': - resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} - engines: {node: '>=18'} + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.24.0': - resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==} + '@esbuild/android-x64@0.23.0': + resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -2107,20 +2270,20 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + '@esbuild/darwin-arm64@0.20.2': + resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.23.1': - resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} - engines: {node: '>=18'} + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.24.0': - resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==} + '@esbuild/darwin-arm64@0.23.0': + resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -2143,20 +2306,20 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + '@esbuild/darwin-x64@0.20.2': + resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.23.1': - resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} - engines: {node: '>=18'} + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.24.0': - resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==} + '@esbuild/darwin-x64@0.23.0': + resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -2179,20 +2342,20 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + '@esbuild/freebsd-arm64@0.20.2': + resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.23.1': - resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} - engines: {node: '>=18'} + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.24.0': - resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==} + '@esbuild/freebsd-arm64@0.23.0': + resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -2215,20 +2378,20 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + '@esbuild/freebsd-x64@0.20.2': + resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.23.1': - resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} - engines: {node: '>=18'} + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.24.0': - resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==} + '@esbuild/freebsd-x64@0.23.0': + resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -2251,20 +2414,20 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + '@esbuild/linux-arm64@0.20.2': + resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.23.1': - resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} - engines: {node: '>=18'} + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.24.0': - resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==} + '@esbuild/linux-arm64@0.23.0': + resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -2287,20 +2450,20 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + '@esbuild/linux-arm@0.20.2': + resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} engines: {node: '>=12'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.23.1': - resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} - engines: {node: '>=18'} + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.24.0': - resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==} + '@esbuild/linux-arm@0.23.0': + resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -2323,20 +2486,20 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + '@esbuild/linux-ia32@0.20.2': + resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.23.1': - resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} - engines: {node: '>=18'} + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.24.0': - resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==} + '@esbuild/linux-ia32@0.23.0': + resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -2365,20 +2528,20 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + '@esbuild/linux-loong64@0.20.2': + resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.23.1': - resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} - engines: {node: '>=18'} + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.24.0': - resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==} + '@esbuild/linux-loong64@0.23.0': + resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -2401,20 +2564,20 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + '@esbuild/linux-mips64el@0.20.2': + resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.23.1': - resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} - engines: {node: '>=18'} + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.24.0': - resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==} + '@esbuild/linux-mips64el@0.23.0': + resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -2437,20 +2600,20 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + '@esbuild/linux-ppc64@0.20.2': + resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.23.1': - resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} - engines: {node: '>=18'} + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.24.0': - resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==} + '@esbuild/linux-ppc64@0.23.0': + resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -2473,20 +2636,20 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + '@esbuild/linux-riscv64@0.20.2': + resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.23.1': - resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} - engines: {node: '>=18'} + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.24.0': - resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==} + '@esbuild/linux-riscv64@0.23.0': + resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -2509,20 +2672,20 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + '@esbuild/linux-s390x@0.20.2': + resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.23.1': - resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} - engines: {node: '>=18'} + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.24.0': - resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==} + '@esbuild/linux-s390x@0.23.0': + resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -2545,20 +2708,20 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + '@esbuild/linux-x64@0.20.2': + resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} engines: {node: '>=12'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.23.1': - resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} - engines: {node: '>=18'} + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.24.0': - resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==} + '@esbuild/linux-x64@0.23.0': + resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -2581,32 +2744,26 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + '@esbuild/netbsd-x64@0.20.2': + resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.23.1': - resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} - engines: {node: '>=18'} + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.24.0': - resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==} + '@esbuild/netbsd-x64@0.23.0': + resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.23.1': - resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-arm64@0.24.0': - resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==} + '@esbuild/openbsd-arm64@0.23.0': + resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -2629,20 +2786,20 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + '@esbuild/openbsd-x64@0.20.2': + resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.23.1': - resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} - engines: {node: '>=18'} + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.24.0': - resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==} + '@esbuild/openbsd-x64@0.23.0': + resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -2665,20 +2822,20 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + '@esbuild/sunos-x64@0.20.2': + resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} engines: {node: '>=12'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.23.1': - resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} - engines: {node: '>=18'} + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.24.0': - resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==} + '@esbuild/sunos-x64@0.23.0': + resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -2701,20 +2858,20 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + '@esbuild/win32-arm64@0.20.2': + resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.23.1': - resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} - engines: {node: '>=18'} + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.24.0': - resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==} + '@esbuild/win32-arm64@0.23.0': + resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -2737,20 +2894,20 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + '@esbuild/win32-ia32@0.20.2': + resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} engines: {node: '>=12'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.23.1': - resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} - engines: {node: '>=18'} + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.24.0': - resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==} + '@esbuild/win32-ia32@0.23.0': + resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -2773,67 +2930,91 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + '@esbuild/win32-x64@0.20.2': + resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} engines: {node: '>=12'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.23.1': - resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} - engines: {node: '>=18'} + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.24.0': - resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} + '@esbuild/win32-x64@0.23.0': + resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.4.1': - resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + '@eslint-community/regexpp@4.11.0': + resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint-community/regexpp@4.9.0': + resolution: {integrity: sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint/eslintrc@2.1.2': + resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.3': + resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@2.1.4': resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + '@eslint/eslintrc@3.1.0': + resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@8.50.0': + resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.53.0': + resolution: {integrity: sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.0': + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} '@ewoudenberg/difflib@0.1.0': resolution: {integrity: sha512-OU5P5mJyD3OoWYMWY+yIgwvgNS9cFAU10f+DDuvtogcWQOoJIsQ4Hy2McSfUfhKjq8L0FuWVb4Rt7kgA+XK86A==} - '@expo/bunyan@4.0.1': - resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {node: '>=0.10.0'} + '@expo/bunyan@4.0.0': + resolution: {integrity: sha512-Ydf4LidRB/EBI+YrB+cVLqIseiRfjUI/AeHBgjGMtq3GroraDu81OV7zqophRgupngoL3iS3JUMDMnxO7g39qA==} + engines: {'0': node >=0.10.0} - '@expo/cli@0.18.30': - resolution: {integrity: sha512-V90TUJh9Ly8stYo8nwqIqNWCsYjE28GlVFWEhAFCUOp99foiQr8HSTpiiX5GIrprcPoWmlGoY+J5fQA29R4lFg==} + '@expo/cli@0.18.13': + resolution: {integrity: sha512-ZO1fpDK8z6mLeQGuFP6e3cZyCHV55ohZY7/tEyhpft3bwysS680eyFg5SFe+tWNFesnziFrbtI8JaUyhyjqovA==} hasBin: true '@expo/code-signing-certificates@0.0.5': resolution: {integrity: sha512-BNhXkY1bblxKZpltzAx98G2Egj9g1Q+JRcvR7E99DOj862FTCX+ZPsAUtPTr7aHxwtrL7+fL3r0JSmM9kBm+Bw==} - '@expo/config-plugins@8.0.10': - resolution: {integrity: sha512-KG1fnSKRmsudPU9BWkl59PyE0byrE2HTnqbOrgwr2FAhqh7tfr9nRs6A9oLS/ntpGzmFxccTEcsV0L4apsuxxg==} + '@expo/config-plugins@8.0.4': + resolution: {integrity: sha512-Hi+xuyNWE2LT4LVbGttHJgl9brnsdWAhEB42gWKb5+8ae86Nr/KwUBQJsJppirBYTeLjj5ZlY0glYnAkDa2jqw==} - '@expo/config-types@51.0.3': - resolution: {integrity: sha512-hMfuq++b8VySb+m9uNNrlpbvGxYc8OcFCUX9yTmi9tlx6A4k8SDabWFBgmnr4ao3wEArvWrtUQIfQCVtPRdpKA==} + '@expo/config-types@51.0.0': + resolution: {integrity: sha512-acn03/u8mQvBhdTQtA7CNhevMltUhbSrpI01FYBJwpVntufkU++ncQujWKlgY/OwIajcfygk1AY4xcNZ5ImkRA==} - '@expo/config@9.0.4': - resolution: {integrity: sha512-g5ns5u1JSKudHYhjo1zaSfkJ/iZIcWmUmIQptMJZ6ag1C0ShL2sj8qdfU8MmAMuKLOgcIfSaiWlQnm4X3VJVkg==} + '@expo/config@9.0.2': + resolution: {integrity: sha512-BKQ4/qBf3OLT8hHp5kjObk2vxwoRQ1yYQBbG/OM9Jdz32yYtrU8opTbKRAxfZEWH5i3ZHdLrPdC1rO0I6WxtTw==} - '@expo/devcert@1.1.4': - resolution: {integrity: sha512-fqBODr8c72+gBSX5Ty3SIzaY4bXainlpab78+vEYEKL3fXmsOswMLf0+KE36mUEAa36BYabX7K3EiXOXX5OPMw==} + '@expo/devcert@1.1.2': + resolution: {integrity: sha512-FyWghLu7rUaZEZSTLt/XNRukm0c9GFfwP0iFaswoDWpV6alvVg+zRAfCLdIVQEz1SVcQ3zo1hMZFDrnKGvkCuQ==} '@expo/env@0.3.0': resolution: {integrity: sha512-OtB9XVHWaXidLbHvrVDeeXa09yvTl3+IQN884sO6PhIi2/StXfgSH/9zC7IvzrDB8kW3EBJ1PPLuCUJ2hxAT7Q==} @@ -2844,11 +3025,11 @@ packages: '@expo/json-file@8.3.3': resolution: {integrity: sha512-eZ5dld9AD0PrVRiIWpRkm5aIoWBw3kAyd8VkuWEy92sEthBKDDDHAnK2a0dw0Eil6j7rK7lS/Qaq/Zzngv2h5A==} - '@expo/metro-config@0.18.11': - resolution: {integrity: sha512-/uOq55VbSf9yMbUO1BudkUM2SsGW1c5hr9BnhIqYqcsFv0Jp5D3DtJ4rljDKaUeNLbwr6m7pqIrkSMq5NrYf4Q==} + '@expo/metro-config@0.18.4': + resolution: {integrity: sha512-vh9WDf/SzE+NYCn6gqbzLKiXtENFlFZdAqyj9nI38RvQ4jw6TJIQ8+ExcdLDT3MOG36Ytg44XX9Zb3OWF6LVxw==} - '@expo/osascript@2.1.3': - resolution: {integrity: sha512-aOEkhPzDsaAfolSswObGiYW0Pf0ROfR9J2NBRLQACdQ6uJlyAMiPF45DVEVknAU9juKh0y8ZyvC9LXqLEJYohA==} + '@expo/osascript@2.1.2': + resolution: {integrity: sha512-/ugqDG+52uzUiEpggS9GPdp9g0U9EQrXcTdluHDmnlGmR2nV/F83L7c+HCUyPnf77QXwkr8gQk16vQTbxBQ5eA==} engines: {node: '>=12'} '@expo/package-manager@1.5.2': @@ -2857,8 +3038,8 @@ packages: '@expo/plist@0.1.3': resolution: {integrity: sha512-GW/7hVlAylYg1tUrEASclw1MMk9FP4ZwyFAY/SUTJIhPDQHtfOlXREyWV3hhrHdX/K+pS73GNgdfT6E/e+kBbg==} - '@expo/prebuild-config@7.0.9': - resolution: {integrity: sha512-9i6Cg7jInpnGEHN0jxnW0P+0BexnePiBzmbUvzSbRXpdXihYUX2AKMu73jgzxn5P1hXOSkzNS7umaY+BZ+aBag==} + '@expo/prebuild-config@7.0.4': + resolution: {integrity: sha512-E2n3QbwgV8Qa0CBw7BHrWBDWD7l8yw+N/yjvXpSPFFtoZLMSKyegdkJFACh2u+UIRKUSZm8zQwHeZR0rqAxV9g==} peerDependencies: expo-modules-autolinking: '>=0.8.1' @@ -2873,8 +3054,8 @@ packages: resolution: {integrity: sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==} engines: {node: '>=12'} - '@expo/vector-icons@14.0.4': - resolution: {integrity: sha512-+yKshcbpDfbV4zoXOgHxCwh7lkE9VVTT5T03OUlBsqfze1PLy6Hi4jp1vSb1GVbY6eskvMIivGVc9SKzIv0oEQ==} + '@expo/vector-icons@14.0.2': + resolution: {integrity: sha512-70LpmXQu4xa8cMxjp1fydgRPsalefnHaXLzIwaHMEzcZhnyjw2acZz8azRrZOslPVAWlxItOa2Dd7WtD/kI+CA==} '@expo/websql@1.0.1': resolution: {integrity: sha512-H9/t1V7XXyKC343FJz/LwaVBfDhs6IqhDtSYWpt8LNSQDVjf5NvVJLc5wp+KCpRidZx8+0+YeHJN45HOXmqjFA==} @@ -2895,11 +3076,15 @@ packages: peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@hono/node-server@1.13.5': - resolution: {integrity: sha512-lSo+CFlLqAFB4fX7ePqI9nauEn64wOfJHAfc9duYFTvAG3o416pC0nTGeNjuLHchLedH+XyWda5v79CVx1PIjg==} + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@hapi/topo@5.1.0': + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + + '@hono/node-server@1.12.0': + resolution: {integrity: sha512-e6oHjNiErRxsZRZBmc2KucuvY3btlO/XPncIpP2X75bRdTilF9GLjm3NHvKKunpJbbJJj31/FoPTksTf8djAVw==} engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 '@hono/zod-validator@0.2.2': resolution: {integrity: sha512-dSDxaPV70Py8wuIU2QNpoVEIOSzSXZ/6/B/h4xA7eOMz7+AarKTSGV8E6QwrdcCbBLkpqfJ4Q2TmBO0eP1tCBQ==} @@ -2907,8 +3092,18 @@ packages: hono: '>=3.9.0' zod: ^3.19.1 - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + '@humanwhocodes/config-array@0.11.11': + resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/config-array@0.11.13': + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/config-array@0.11.14': + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} deprecated: Use @eslint/config-array instead @@ -2916,6 +3111,14 @@ packages: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} + '@humanwhocodes/object-schema@1.2.1': + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead + + '@humanwhocodes/object-schema@2.0.1': + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + deprecated: Use @eslint/object-schema instead + '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead @@ -2931,14 +3134,6 @@ packages: resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} engines: {node: '>=12'} - '@istanbuljs/load-nyc-config@1.1.0': - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - '@jest/create-cache-key-function@29.7.0': resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2955,36 +3150,56 @@ packages: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/transform@29.7.0': - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/types@24.9.0': - resolution: {integrity: sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==} - engines: {node: '>= 6'} + '@jest/types@26.6.2': + resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} + engines: {node: '>= 10.14.2'} '@jest/types@29.6.3': resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jridgewell/gen-mapping@0.3.3': + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} + '@jridgewell/resolve-uri@3.1.0': + resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + engines: {node: '>=6.0.0'} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + '@jridgewell/set-array@1.1.2': + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + '@jridgewell/set-array@1.2.1': resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.3': + resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==} + '@jridgewell/source-map@0.3.6': resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + '@jridgewell/sourcemap-codec@1.4.14': + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + + '@jridgewell/sourcemap-codec@1.4.15': + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/trace-mapping@0.3.18': + resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} + '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} @@ -3002,13 +3217,23 @@ packages: '@libsql/core@0.10.0': resolution: {integrity: sha512-rqynAXGaiSpTsykOZdBtI1N4z4O+KZ6mt33K/aHeXAY0gSIfK/ctxuWa0Y1Bjo4FMz1idBTCXz4Ps5kITOvZZw==} - '@libsql/darwin-arm64@0.4.7': - resolution: {integrity: sha512-yOL742IfWUlUevnI5PdnIT4fryY3LYTdLm56bnY0wXBw7dhFcnjuA7jrH3oSVz2mjZTHujxoITgAE7V6Z+eAbg==} + '@libsql/darwin-arm64@0.3.19': + resolution: {integrity: sha512-rmOqsLcDI65zzxlUOoEiPJLhqmbFsZF6p4UJQ2kMqB+Kc0Rt5/A1OAdOZ/Wo8fQfJWjR1IbkbpEINFioyKf+nQ==} + cpu: [arm64] + os: [darwin] + + '@libsql/darwin-arm64@0.4.1': + resolution: {integrity: sha512-XICT9/OyU8Aa9Iv1xZIHgvM09n/1OQUk3VC+s5uavzdiGHrDMkOWzN47JN7/FiMa/NWrcgoEiDMk3+e7mE53Ig==} cpu: [arm64] os: [darwin] - '@libsql/darwin-x64@0.4.7': - resolution: {integrity: sha512-ezc7V75+eoyyH07BO9tIyJdqXXcRfZMbKcLCeF8+qWK5nP8wWuMcfOVywecsXGRbT99zc5eNra4NEx6z5PkSsA==} + '@libsql/darwin-x64@0.3.19': + resolution: {integrity: sha512-q9O55B646zU+644SMmOQL3FIfpmEvdWpRpzubwFc2trsa+zoBlSkHuzU9v/C+UNoPHQVRMP7KQctJ455I/h/xw==} + cpu: [x64] + os: [darwin] + + '@libsql/darwin-x64@0.4.1': + resolution: {integrity: sha512-pSKxhRrhu4SsTD+IBRZXcs1SkwMdeAG1tv6Z/Ctp/sOEYrgkU8MDKLqkOr9NsmwpK4S0+JdwjkLMyhTkct/5TQ==} cpu: [x64] os: [darwin] @@ -3022,28 +3247,53 @@ packages: '@libsql/isomorphic-ws@0.1.5': resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} - '@libsql/linux-arm64-gnu@0.4.7': - resolution: {integrity: sha512-WlX2VYB5diM4kFfNaYcyhw5y+UJAI3xcMkEUJZPtRDEIu85SsSFrQ+gvoKfcVh76B//ztSeEX2wl9yrjF7BBCA==} + '@libsql/linux-arm64-gnu@0.3.19': + resolution: {integrity: sha512-mgeAUU1oqqh57k7I3cQyU6Trpdsdt607eFyEmH5QO7dv303ti+LjUvh1pp21QWV6WX7wZyjeJV1/VzEImB+jRg==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-arm64-gnu@0.4.1': + resolution: {integrity: sha512-9lpvb24tO2qZd9nq5dlq3ESA3hSKYWBIK7lJjfiCM6f7a70AUwBY9QoPJV9q4gILIyVnR1YBGrlm50nnb+dYgw==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-arm64-musl@0.3.19': + resolution: {integrity: sha512-VEZtxghyK6zwGzU9PHohvNxthruSxBEnRrX7BSL5jQ62tN4n2JNepJ6SdzXp70pdzTfwroOj/eMwiPt94gkVRg==} cpu: [arm64] os: [linux] - '@libsql/linux-arm64-musl@0.4.7': - resolution: {integrity: sha512-6kK9xAArVRlTCpWeqnNMCoXW1pe7WITI378n4NpvU5EJ0Ok3aNTIC2nRPRjhro90QcnmLL1jPcrVwO4WD1U0xw==} + '@libsql/linux-arm64-musl@0.4.1': + resolution: {integrity: sha512-lyxi+lFxE+NcBRDMQCxCtDg3c4WcKAbc9u63d5+B23Vm+UgphD9XY4seu+tGrBy1MU2tuNVix7r9S7ECpAaVrA==} cpu: [arm64] os: [linux] - '@libsql/linux-x64-gnu@0.4.7': - resolution: {integrity: sha512-CMnNRCmlWQqqzlTw6NeaZXzLWI8bydaXDke63JTUCvu8R+fj/ENsLrVBtPDlxQ0wGsYdXGlrUCH8Qi9gJep0yQ==} + '@libsql/linux-x64-gnu@0.3.19': + resolution: {integrity: sha512-2t/J7LD5w2f63wGihEO+0GxfTyYIyLGEvTFEsMO16XI5o7IS9vcSHrxsvAJs4w2Pf907uDjmc7fUfMg6L82BrQ==} + cpu: [x64] + os: [linux] + + '@libsql/linux-x64-gnu@0.4.1': + resolution: {integrity: sha512-psvuQ3UFBEmDFV8ZHG+WkUHIJiWv+elZ+zIPvOVedlIKdxG1O+8WthWUAhFHOGnbiyzc4sAZ4c3de1oCvyHxyQ==} cpu: [x64] os: [linux] - '@libsql/linux-x64-musl@0.4.7': - resolution: {integrity: sha512-nI6tpS1t6WzGAt1Kx1n1HsvtBbZ+jHn0m7ogNNT6pQHZQj7AFFTIMeDQw/i/Nt5H38np1GVRNsFe99eSIMs9XA==} + '@libsql/linux-x64-musl@0.3.19': + resolution: {integrity: sha512-BLsXyJaL8gZD8+3W2LU08lDEd9MIgGds0yPy5iNPp8tfhXx3pV/Fge2GErN0FC+nzt4DYQtjL+A9GUMglQefXQ==} cpu: [x64] os: [linux] - '@libsql/win32-x64-msvc@0.4.7': - resolution: {integrity: sha512-7pJzOWzPm6oJUxml+PCDRzYQ4A1hTMHAciTAHfFK4fkbDZX33nWPVG7Y3vqdKtslcwAzwmrNDc6sXy2nwWnbiw==} + '@libsql/linux-x64-musl@0.4.1': + resolution: {integrity: sha512-PDidJ3AhGDqosGg3OAZzGxMFIbnuOALya4BoezJKl667AFv3x7BBQ30H81Mngsq3Fh8RkJkXSdWfL91+Txb1iA==} + cpu: [x64] + os: [linux] + + '@libsql/win32-x64-msvc@0.3.19': + resolution: {integrity: sha512-ay1X9AobE4BpzG0XPw1gplyLZPGHIgJOovvW23gUrukRegiUP62uzhpRbKNogLlUOynyXeq//prHgPXiebUfWg==} + cpu: [x64] + os: [win32] + + '@libsql/win32-x64-msvc@0.4.1': + resolution: {integrity: sha512-IdODVqV/PrdOnHA/004uWyorZQuRsB7U7bCRCE3vXgABj3eJLJGc6cv2C6ksEaEoVxJbD8k53H4VVAGrtYwXzQ==} cpu: [x64] os: [win32] @@ -3116,8 +3366,8 @@ packages: react: '*' react-native: '*' - '@opentelemetry/api@1.9.0': - resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + '@opentelemetry/api@1.8.0': + resolution: {integrity: sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==} engines: {node: '>=8.0.0'} '@originjs/vite-plugin-commonjs@1.0.3': @@ -3134,12 +3384,12 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@planetscale/database@1.19.0': - resolution: {integrity: sha512-Tv4jcFUFAFjOWrGSio49H6R2ijALv0ZzVBfJKIdm+kl9X046Fh4LLawrF9OMsglVbK6ukqMJsUCeucGAFTBcMA==} + '@planetscale/database@1.18.0': + resolution: {integrity: sha512-t2XdOfrVgcF7AW791FtdPS27NyNqcE1SpoXgk3HpziousvUMsJi4Q6NL3JyOBpsMOrvk94749o8yyonvX5quPw==} engines: {node: '>=16'} - '@polka/url@1.0.0-next.28': - resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} + '@polka/url@1.0.0-next.25': + resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} '@prisma/client@5.14.0': resolution: {integrity: sha512-akMSuyvLKeoU4LeyBAUdThP/uhVP3GuLygFE3MlYzaCb3/J8SfsYBE5PkaFuLuVpLyA6sFoW+16z/aPhNAESqg==} @@ -3153,8 +3403,8 @@ packages: '@prisma/debug@5.14.0': resolution: {integrity: sha512-iq56qBZuFfX3fCxoxT8gBX33lQzomBU0qIUaEj1RebsKVz1ob/BVH1XSBwwwvRVtZEV1b7Fxx2eVu34Ge/mg3w==} - '@prisma/debug@5.22.0': - resolution: {integrity: sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==} + '@prisma/debug@5.16.1': + resolution: {integrity: sha512-JsNgZAg6BD9RInLSrg7ZYzo11N7cVvYArq3fHGSD89HSgtN0VDdjV6bib7YddbcO6snzjchTiLfjeTqBjtArVQ==} '@prisma/engines-version@5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48': resolution: {integrity: sha512-ip6pNkRo1UxWv+6toxNcYvItNYaqQjXdFNGJ+Nuk2eYtRoEdoF13wxo7/jsClJFFenMPVNVqXQDV0oveXnR1cA==} @@ -3165,95 +3415,101 @@ packages: '@prisma/fetch-engine@5.14.0': resolution: {integrity: sha512-VrheA9y9DMURK5vu8OJoOgQpxOhas3qF0IBHJ8G/0X44k82kc8E0w98HCn2nhnbOOMwbWsJWXfLC2/F8n5u0gQ==} - '@prisma/generator-helper@5.22.0': - resolution: {integrity: sha512-LwqcBQ5/QsuAaLNQZAIVIAJDJBMjHwMwn16e06IYx/3Okj/xEEfw9IvrqB2cJCl3b2mCBlh3eVH0w9WGmi4aHg==} + '@prisma/generator-helper@5.16.1': + resolution: {integrity: sha512-WxV/msovIubvr20iIdPJN0MUj46J26ax+sV+vMQSCeVoHQW//xdJZoPnimG54M7+CA9kupXjVpgjiPX4rcKQeA==} '@prisma/get-platform@5.14.0': resolution: {integrity: sha512-/yAyBvcEjRv41ynZrhdrPtHgk47xLRRq/o5eWGcUpBJ1YrUZTYB8EoPiopnP7iQrMATK8stXQdPOoVlrzuTQZw==} - '@react-native/assets-registry@0.76.1': - resolution: {integrity: sha512-1mcDjyvC4Z+XYtY+Abl6pW9P49l/9HJmRChX7EHF1SoXe7zPAPBoAqeZsJNtf8dhJR3u/eGvapr1yJq8T/psEg==} - engines: {node: '>=18'} + '@react-native-community/cli-clean@13.6.6': + resolution: {integrity: sha512-cBwJTwl0NyeA4nyMxbhkWZhxtILYkbU3TW3k8AXLg+iGphe0zikYMGB3T+haTvTc6alTyEFwPbimk9bGIqkjAQ==} - '@react-native/babel-plugin-codegen@0.74.87': - resolution: {integrity: sha512-+vJYpMnENFrwtgvDfUj+CtVJRJuUnzAUYT0/Pb68Sq9RfcZ5xdcCuUgyf7JO+akW2VTBoJY427wkcxU30qrWWw==} - engines: {node: '>=18'} + '@react-native-community/cli-config@13.6.6': + resolution: {integrity: sha512-mbG425zCKr8JZhv/j11382arezwS/70juWMsn8j2lmrGTrP1cUdW0MF15CCIFtJsqyK3Qs+FTmqttRpq81QfSg==} - '@react-native/babel-plugin-codegen@0.76.1': - resolution: {integrity: sha512-V9bGLyEdAF39nvn4L5gaJcPX1SvCHPJhaT3qfpVGvCnl7WPhdRyCq++WsN8HXlpo6WOAf6//oruLnLdl3RNM4Q==} - engines: {node: '>=18'} + '@react-native-community/cli-debugger-ui@13.6.6': + resolution: {integrity: sha512-Vv9u6eS4vKSDAvdhA0OiQHoA7y39fiPIgJ6biT32tN4avHDtxlc6TWZGiqv7g98SBvDWvoVAmdPLcRf3kU+c8g==} - '@react-native/babel-preset@0.74.87': - resolution: {integrity: sha512-hyKpfqzN2nxZmYYJ0tQIHG99FQO0OWXp/gVggAfEUgiT+yNKas1C60LuofUsK7cd+2o9jrpqgqW4WzEDZoBlTg==} - engines: {node: '>=18'} - peerDependencies: - '@babel/core': '*' + '@react-native-community/cli-doctor@13.6.6': + resolution: {integrity: sha512-TWZb5g6EmQe2Ua2TEWNmyaEayvlWH4GmdD9ZC+p8EpKFpB1NpDGMK6sXbpb42TDvwZg5s4TDRplK0PBEA/SVDg==} - '@react-native/babel-preset@0.76.1': - resolution: {integrity: sha512-b6YRmA13CmVuTQKHRen/Q0glHwmZFZoEDs+MJ1NL0UNHq9V5ytvdwTW1ntkmjtXuTnPMzkwYvumJBN9UTZjkBA==} - engines: {node: '>=18'} - peerDependencies: - '@babel/core': '*' + '@react-native-community/cli-hermes@13.6.6': + resolution: {integrity: sha512-La5Ie+NGaRl3klei6WxKoOxmCUSGGxpOk6vU5pEGf0/O7ky+Ay0io+zXYUZqlNMi/cGpO7ZUijakBYOB/uyuFg==} - '@react-native/codegen@0.74.87': - resolution: {integrity: sha512-GMSYDiD+86zLKgMMgz9z0k6FxmRn+z6cimYZKkucW4soGbxWsbjUAZoZ56sJwt2FJ3XVRgXCrnOCgXoH/Bkhcg==} - engines: {node: '>=18'} - peerDependencies: - '@babel/preset-env': ^7.1.6 + '@react-native-community/cli-platform-android@13.6.6': + resolution: {integrity: sha512-/tMwkBeNxh84syiSwNlYtmUz/Ppc+HfKtdopL/5RB+fd3SV1/5/NPNjMlyLNgFKnpxvKCInQ7dnl6jGHJjeHjg==} + + '@react-native-community/cli-platform-apple@13.6.6': + resolution: {integrity: sha512-bOmSSwoqNNT3AmCRZXEMYKz1Jf1l2F86Nhs7qBcXdY/sGiJ+Flng564LOqvdAlVLTbkgz47KjNKCS2pP4Jg0Mg==} + + '@react-native-community/cli-platform-ios@13.6.6': + resolution: {integrity: sha512-vjDnRwhlSN5ryqKTas6/DPkxuouuyFBAqAROH4FR1cspTbn6v78JTZKDmtQy9JMMo7N5vZj1kASU5vbFep9IOQ==} - '@react-native/codegen@0.76.1': - resolution: {integrity: sha512-7lE0hk2qq27wVeK5eF654v7XsKoRa7ficrfSwIDEDZ1aLB2xgUzLrsq+glSAP9EuzT6ycHhtD3QyqI+TqnlS/A==} + '@react-native-community/cli-server-api@13.6.6': + resolution: {integrity: sha512-ZtCXxoFlM7oDv3iZ3wsrT3SamhtUJuIkX2WePLPlN5bcbq7zimbPm2lHyicNJtpcGQ5ymsgpUWPCNZsWQhXBqQ==} + + '@react-native-community/cli-tools@13.6.6': + resolution: {integrity: sha512-ptOnn4AJczY5njvbdK91k4hcYazDnGtEPrqIwEI+k/CTBHNdb27Rsm2OZ7ye6f7otLBqF8gj/hK6QzJs8CEMgw==} + + '@react-native-community/cli-types@13.6.6': + resolution: {integrity: sha512-733iaYzlmvNK7XYbnWlMjdE+2k0hlTBJW071af/xb6Bs+hbJqBP9c03FZuYH2hFFwDDntwj05bkri/P7VgSxug==} + + '@react-native-community/cli@13.6.6': + resolution: {integrity: sha512-IqclB7VQ84ye8Fcs89HOpOscY4284VZg2pojHNl8H0Lzd4DadXJWQoxC7zWm8v2f8eyeX2kdhxp2ETD5tceIgA==} + engines: {node: '>=18'} + hasBin: true + + '@react-native/assets-registry@0.74.83': + resolution: {integrity: sha512-2vkLMVnp+YTZYTNSDIBZojSsjz8sl5PscP3j4GcV6idD8V978SZfwFlk8K0ti0BzRs11mzL0Pj17km597S/eTQ==} engines: {node: '>=18'} - peerDependencies: - '@babel/preset-env': ^7.1.6 - '@react-native/community-cli-plugin@0.76.1': - resolution: {integrity: sha512-dECc1LuleMQDX/WK2oJInrYCpHb3OFBJxYkhPOAXb9HiktMWRA9T93qqpTDshmtLdYqvxeO9AM5eeoSL412WnQ==} + '@react-native/babel-plugin-codegen@0.74.83': + resolution: {integrity: sha512-+S0st3t4Ro00bi9gjT1jnK8qTFOU+CwmziA7U9odKyWrCoRJrgmrvogq/Dr1YXlpFxexiGIupGut1VHxr+fxJA==} + engines: {node: '>=18'} + + '@react-native/babel-preset@0.74.83': + resolution: {integrity: sha512-KJuu3XyVh3qgyUer+rEqh9a/JoUxsDOzkJNfRpDyXiAyjDRoVch60X/Xa/NcEQ93iCVHAWs0yQ+XGNGIBCYE6g==} engines: {node: '>=18'} peerDependencies: - '@react-native-community/cli-server-api': '*' - peerDependenciesMeta: - '@react-native-community/cli-server-api': - optional: true + '@babel/core': '*' - '@react-native/debugger-frontend@0.74.85': - resolution: {integrity: sha512-gUIhhpsYLUTYWlWw4vGztyHaX/kNlgVspSvKe2XaPA7o3jYKUoNLc3Ov7u70u/MBWfKdcEffWq44eSe3j3s5JQ==} + '@react-native/codegen@0.74.83': + resolution: {integrity: sha512-GgvgHS3Aa2J8/mp1uC/zU8HuTh8ZT5jz7a4mVMWPw7+rGyv70Ba8uOVBq6UH2Q08o617IATYc+0HfyzAfm4n0w==} engines: {node: '>=18'} + peerDependencies: + '@babel/preset-env': ^7.1.6 - '@react-native/debugger-frontend@0.76.1': - resolution: {integrity: sha512-0gExx7GR8o2ctGfjIZ9+x54iFbg0eP6+kMYzRA6AcgmFAmMGLADMmjtObCN0CqGeZyWtdVVqcv5mAwRwmMlNWA==} + '@react-native/community-cli-plugin@0.74.83': + resolution: {integrity: sha512-7GAFjFOg1mFSj8bnFNQS4u8u7+QtrEeflUIDVZGEfBZQ3wMNI5ycBzbBGycsZYiq00Xvoc6eKFC7kvIaqeJpUQ==} engines: {node: '>=18'} - '@react-native/dev-middleware@0.74.85': - resolution: {integrity: sha512-BRmgCK5vnMmHaKRO+h8PKJmHHH3E6JFuerrcfE3wG2eZ1bcSr+QTu8DAlpxsDWvJvHpCi8tRJGauxd+Ssj/c7w==} + '@react-native/debugger-frontend@0.74.83': + resolution: {integrity: sha512-RGQlVUegBRxAUF9c1ss1ssaHZh6CO+7awgtI9sDeU0PzDZY/40ImoPD5m0o0SI6nXoVzbPtcMGzU+VO590pRfA==} engines: {node: '>=18'} - '@react-native/dev-middleware@0.76.1': - resolution: {integrity: sha512-htaFSN2dwI0CinsMxjRuvIVdSDN6d6TDPeOJczM1bdAYalZX1M58knTKs5LJDComW5tleOCAg5lS5tIeFlM9+Q==} + '@react-native/dev-middleware@0.74.83': + resolution: {integrity: sha512-UH8iriqnf7N4Hpi20D7M2FdvSANwTVStwFCSD7VMU9agJX88Yk0D1T6Meh2RMhUu4kY2bv8sTkNRm7LmxvZqgA==} engines: {node: '>=18'} - '@react-native/gradle-plugin@0.76.1': - resolution: {integrity: sha512-X7rNFltPa9QYxvYrQGaSCw7U57C+y+DwspXf4AnLZj0bQm9tL6UYpijh5vE3VmPcHn76/RNU2bpFjVvWg6gjqw==} + '@react-native/gradle-plugin@0.74.83': + resolution: {integrity: sha512-Pw2BWVyOHoBuJVKxGVYF6/GSZRf6+v1Ygc+ULGz5t20N8qzRWPa2fRZWqoxsN7TkNLPsECYY8gooOl7okOcPAQ==} engines: {node: '>=18'} - '@react-native/js-polyfills@0.76.1': - resolution: {integrity: sha512-HO3fzJ0FnrnQGmxdXxh2lcGGAMfaX9h1Pg1Zh38MkVw35/KnZHxHqxg6cruze6iWwZdfqSoIcQoalmMuAHby7Q==} + '@react-native/js-polyfills@0.74.83': + resolution: {integrity: sha512-/t74n8r6wFhw4JEoOj3bN71N1NDLqaawB75uKAsSjeCwIR9AfCxlzZG0etsXtOexkY9KMeZIQ7YwRPqUdNXuqw==} engines: {node: '>=18'} - '@react-native/metro-babel-transformer@0.76.1': - resolution: {integrity: sha512-LUAKqgsrioXS2a+pE0jak8sutTbLo3T34KWv7mdVUZ5lUACpqkIql1EFtIQlWjIcR4oZE480CkPbRHBI681tkQ==} + '@react-native/metro-babel-transformer@0.74.83': + resolution: {integrity: sha512-hGdx5N8diu8y+GW/ED39vTZa9Jx1di2ZZ0aapbhH4egN1agIAusj5jXTccfNBwwWF93aJ5oVbRzfteZgjbutKg==} engines: {node: '>=18'} peerDependencies: '@babel/core': '*' - '@react-native/normalize-colors@0.74.85': - resolution: {integrity: sha512-pcE4i0X7y3hsAE0SpIl7t6dUc0B0NZLd1yv7ssm4FrLhWG+CGyIq4eFDXpmPU1XHmL5PPySxTAjEMiwv6tAmOw==} - - '@react-native/normalize-colors@0.76.1': - resolution: {integrity: sha512-/+CUk/wGWIdXbJYVLw/q6Fs8Z0x91zzfXIbNiZUdSW1TNEDmytkF371H8a1/Nx3nWa1RqCMVsaZHCG4zqxeDvg==} + '@react-native/normalize-colors@0.74.83': + resolution: {integrity: sha512-jhCY95gRDE44qYawWVvhTjTplW1g+JtKTKM3f8xYT1dJtJ8QWv+gqEtKcfmOHfDkSDaMKG0AGBaDTSK8GXLH8Q==} - '@react-native/virtualized-lists@0.76.1': - resolution: {integrity: sha512-uWJfv0FC3zmlYORr0Sa17ngbAaw6K9yw4MAkBZyFeTM+W6AJRvTVyR1Mes/MU+vIyGFChnTcyaQrQz8jWqADOA==} + '@react-native/virtualized-lists@0.74.83': + resolution: {integrity: sha512-rmaLeE34rj7py4FxTod7iMTC7BAsm+HrGA8WxYmEJeyTV7WSaxAkosKoYBz8038mOiwnG9VwA/7FrB6bEQvn1A==} engines: {node: '>=18'} peerDependencies: '@types/react': ^18.2.6 @@ -3267,11 +3523,11 @@ packages: resolution: {integrity: sha512-lzD84av1ZQhYUS+jsGqJiCMaJO2dn9u+RTT9n9q6D3SaKVwWqv+7AoRKqBu19bkwyE+iFRl1ymr40QS90jVFYg==} engines: {node: '>=14.15'} - '@rollup/plugin-terser@0.4.4': - resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} + '@rollup/plugin-terser@0.4.1': + resolution: {integrity: sha512-aKS32sw5a7hy+fEXVy+5T95aDIwjpGHCTv833HXVtyKMDoVS7pBr5K3L9hEQoNqbJFjfANPrNpIXlTQ7is00eA==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^2.0.0||^3.0.0||^4.0.0 + rollup: ^2.x || ^3.x peerDependenciesMeta: rollup: optional: true @@ -3289,7 +3545,7 @@ packages: resolution: {integrity: sha512-86flrfE+bSHB69znnTV6kVjkncs2LBMhcTCyxWgRxLyfXfQrxg4UwlAqENnjrrxnSNS/XKCDJCl8EkdFJVHOxw==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^2.14.0||^3.0.0||^4.0.0 + rollup: ^2.14.0||^3.0.0 tslib: '*' typescript: '>=3.7.0' peerDependenciesMeta: @@ -3298,8 +3554,8 @@ packages: tslib: optional: true - '@rollup/pluginutils@5.1.3': - resolution: {integrity: sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==} + '@rollup/plugin-typescript@11.1.1': + resolution: {integrity: sha512-Ioir+x5Bejv72Lx2Zbz3/qGg7tvGbxQZALCLoJaGrkNXak/19+vKgKYJYM3i/fJxvsb23I9FuFQ8CUBEfsmBRg==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.14.0||^3.0.0 @@ -3372,15 +3628,10 @@ packages: cpu: [arm64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.24.4': - resolution: {integrity: sha512-py5oNShCCjCyjWXCZNrRGRpjWsF0ic8f4ieBNra5buQz0O/U6mMXCpC1LvrHuhJsNPgRt36tSYMidGzZiJF6mw==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.24.4': - resolution: {integrity: sha512-L7VVVW9FCnTTp4i7KrmHeDsDvjB4++KOBENYtNYAiYl96jeBThFfhP6HVxL74v4SiZEVDH/1ILscR5U9S4ms4g==} + '@rollup/rollup-darwin-x64@4.18.1': + resolution: {integrity: sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==} cpu: [x64] - os: [freebsd] + os: [darwin] '@rollup/rollup-darwin-x64@4.27.3': resolution: {integrity: sha512-xW//zjJMlJs2sOrCmXdB4d0uiilZsOdlGQIC/jjmMWT47lkLLoB1nsNhPUcnoqyi5YR6I4h+FjBpILxbEy8JRg==} @@ -3397,8 +3648,8 @@ packages: cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-musleabihf@4.24.4': - resolution: {integrity: sha512-ySAfWs69LYC7QhRDZNKqNhz2UKN8LDfbKSMAEtoEI0jitwfAG2iZwVqGACJT+kfYvvz3/JgsLlcBP+WWoKCLcw==} + '@rollup/rollup-linux-arm-gnueabihf@4.18.1': + resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==} cpu: [arm] os: [linux] @@ -3417,8 +3668,8 @@ packages: cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.24.4': - resolution: {integrity: sha512-38yiWLemQf7aLHDgTg85fh3hW9stJ0Muk7+s6tIkSUOMmi4Xbv5pH/5Bofnsb6spIwD5FJiR+jg71f0CH5OzoA==} + '@rollup/rollup-linux-arm64-gnu@4.18.1': + resolution: {integrity: sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==} cpu: [arm64] os: [linux] @@ -3467,8 +3718,8 @@ packages: cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-musl@4.24.4': - resolution: {integrity: sha512-VJYl4xSl/wqG2D5xTYncVWW+26ICV4wubwN9Gs5NrqhJtayikwCXzPL8GDsLnaLU3WwhQ8W02IinYSFJfyo34Q==} + '@rollup/rollup-linux-x64-gnu@4.18.1': + resolution: {integrity: sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==} cpu: [x64] os: [linux] @@ -3507,8 +3758,10 @@ packages: cpu: [ia32] os: [win32] - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@rollup/rollup-win32-x64-msvc@4.18.1': + resolution: {integrity: sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==} + cpu: [x64] + os: [win32] '@rollup/rollup-win32-x64-msvc@4.27.3': resolution: {integrity: sha512-vliZLrDmYKyaUoMzEbMTg2JkerfBjn03KmAw9CykO0Zzkzoyd7o3iZNam/TpyWNjNT+Cz2iO3P9Smv2wgrR+Eg==} @@ -3518,6 +3771,15 @@ packages: '@segment/loosely-validate-event@2.0.0': resolution: {integrity: sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==} + '@sideway/address@4.1.5': + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + + '@sideway/formula@3.0.1': + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + + '@sideway/pinpoint@2.0.0': + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -3538,31 +3800,76 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - '@smithy/abort-controller@3.1.6': - resolution: {integrity: sha512-0XuhuHQlEqbNQZp7QxxrFTdVWdwxch4vjxYgfInF91hZFkPxf9QDrdQka0KfxFMPqLNzSw0b95uGTrLliQUavQ==} + '@smithy/abort-controller@2.2.0': + resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==} + engines: {node: '>=14.0.0'} + + '@smithy/abort-controller@3.0.0': + resolution: {integrity: sha512-p6GlFGBt9K4MYLu72YuJ523NVR4A8oHlC5M2JO6OmQqN8kAc/uh1JqLE+FizTokrSJGg0CSvC+BrsmGzKtsZKA==} engines: {node: '>=16.0.0'} - '@smithy/config-resolver@3.0.10': - resolution: {integrity: sha512-Uh0Sz9gdUuz538nvkPiyv1DZRX9+D15EKDtnQP5rYVAzM/dnYk3P8cg73jcxyOitPgT3mE3OVj7ky7sibzHWkw==} + '@smithy/config-resolver@2.2.0': + resolution: {integrity: sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==} + engines: {node: '>=14.0.0'} + + '@smithy/config-resolver@3.0.0': + resolution: {integrity: sha512-2GzOfADwYLQugYkKQhIyZyQlM05K+tMKvRnc6eFfZcpJGRfKoMUMYdPlBKmqHwQFXQKBrGV6cxL9oymWgDzvFw==} engines: {node: '>=16.0.0'} - '@smithy/core@2.5.1': - resolution: {integrity: sha512-DujtuDA7BGEKExJ05W5OdxCoyekcKT3Rhg1ZGeiUWaz2BJIWXjZmsG/DIP4W48GHno7AQwRsaCb8NcBgH3QZpg==} + '@smithy/core@1.4.2': + resolution: {integrity: sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==} + engines: {node: '>=14.0.0'} + + '@smithy/core@2.0.1': + resolution: {integrity: sha512-rcMkjvwxH/bER+oZUPR0yTA0ELD6m3A+d92+CFkdF6HJFCBB1bXo7P5pm21L66XwTN01B6bUhSCQ7cymWRD8zg==} engines: {node: '>=16.0.0'} - '@smithy/credential-provider-imds@3.2.5': - resolution: {integrity: sha512-4FTQGAsuwqTzVMmiRVTn0RR9GrbRfkP0wfu/tXWVHd2LgNpTY0uglQpIScXK4NaEyXbB3JmZt8gfVqO50lP8wg==} + '@smithy/credential-provider-imds@2.3.0': + resolution: {integrity: sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==} + engines: {node: '>=14.0.0'} + + '@smithy/credential-provider-imds@3.0.0': + resolution: {integrity: sha512-lfmBiFQcA3FsDAPxNfY0L7CawcWtbyWsBOHo34nF095728JLkBX4Y9q/VPPE2r7fqMVK+drmDigqE2/SSQeVRA==} engines: {node: '>=16.0.0'} - '@smithy/fetch-http-handler@4.0.0': - resolution: {integrity: sha512-MLb1f5tbBO2X6K4lMEKJvxeLooyg7guq48C2zKr4qM7F2Gpkz4dc+hdSgu77pCJ76jVqFBjZczHYAs6dp15N+g==} + '@smithy/eventstream-codec@2.2.0': + resolution: {integrity: sha512-8janZoJw85nJmQZc4L8TuePp2pk1nxLgkxIR0TUjKJ5Dkj5oelB9WtiSSGXCQvNsJl0VSTvK/2ueMXxvpa9GVw==} + + '@smithy/eventstream-serde-browser@2.2.0': + resolution: {integrity: sha512-UaPf8jKbcP71BGiO0CdeLmlg+RhWnlN8ipsMSdwvqBFigl5nil3rHOI/5GE3tfiuX8LvY5Z9N0meuU7Rab7jWw==} + engines: {node: '>=14.0.0'} + + '@smithy/eventstream-serde-config-resolver@2.2.0': + resolution: {integrity: sha512-RHhbTw/JW3+r8QQH7PrganjNCiuiEZmpi6fYUAetFfPLfZ6EkiA08uN3EFfcyKubXQxOwTeJRZSQmDDCdUshaA==} + engines: {node: '>=14.0.0'} + + '@smithy/eventstream-serde-node@2.2.0': + resolution: {integrity: sha512-zpQMtJVqCUMn+pCSFcl9K/RPNtQE0NuMh8sKpCdEHafhwRsjP50Oq/4kMmvxSRy6d8Jslqd8BLvDngrUtmN9iA==} + engines: {node: '>=14.0.0'} + + '@smithy/eventstream-serde-universal@2.2.0': + resolution: {integrity: sha512-pvoe/vvJY0mOpuF84BEtyZoYfbehiFj8KKWk1ds2AT0mTLYFVs+7sBJZmioOFdBXKd48lfrx1vumdPdmGlCLxA==} + engines: {node: '>=14.0.0'} + + '@smithy/fetch-http-handler@2.5.0': + resolution: {integrity: sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==} + + '@smithy/fetch-http-handler@3.0.1': + resolution: {integrity: sha512-uaH74i5BDj+rBwoQaXioKpI0SHBJFtOVwzrCpxZxphOW0ki5jhj7dXvDMYM2IJem8TpdFvS2iC08sjOblfFGFg==} + + '@smithy/hash-node@2.2.0': + resolution: {integrity: sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==} + engines: {node: '>=14.0.0'} - '@smithy/hash-node@3.0.8': - resolution: {integrity: sha512-tlNQYbfpWXHimHqrvgo14DrMAgUBua/cNoz9fMYcDmYej7MAmUcjav/QKQbFc3NrcPxeJ7QClER4tWZmfwoPng==} + '@smithy/hash-node@3.0.0': + resolution: {integrity: sha512-84qXstNemP3XS5jcof0el6+bDfjzuvhJPQTEfro3lgtbCtKgzPm3MgiS6ehXVPjeQ5+JS0HqmTz8f/RYfzHVxw==} engines: {node: '>=16.0.0'} - '@smithy/invalid-dependency@3.0.8': - resolution: {integrity: sha512-7Qynk6NWtTQhnGTTZwks++nJhQ1O54Mzi7fz4PqZOiYXb4Z1Flpb2yRvdALoggTS8xjtohWUM+RygOtB30YL3Q==} + '@smithy/invalid-dependency@2.2.0': + resolution: {integrity: sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==} + + '@smithy/invalid-dependency@3.0.0': + resolution: {integrity: sha512-F6wBBaEFgJzj0s4KUlliIGPmqXemwP6EavgvDqYwCH40O5Xr2iMHvS8todmGVZtuJCorBkXsYLyTu4PuizVq5g==} '@smithy/is-array-buffer@2.2.0': resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} @@ -3572,80 +3879,158 @@ packages: resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==} engines: {node: '>=16.0.0'} - '@smithy/middleware-content-length@3.0.10': - resolution: {integrity: sha512-T4dIdCs1d/+/qMpwhJ1DzOhxCZjZHbHazEPJWdB4GDi2HjIZllVzeBEcdJUN0fomV8DURsgOyrbEUzg3vzTaOg==} + '@smithy/middleware-content-length@2.2.0': + resolution: {integrity: sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-content-length@3.0.0': + resolution: {integrity: sha512-3C4s4d/iGobgCtk2tnWW6+zSTOBg1PRAm2vtWZLdriwTroFbbWNSr3lcyzHdrQHnEXYCC5K52EbpfodaIUY8sg==} engines: {node: '>=16.0.0'} - '@smithy/middleware-endpoint@3.2.1': - resolution: {integrity: sha512-wWO3xYmFm6WRW8VsEJ5oU6h7aosFXfszlz3Dj176pTij6o21oZnzkCLzShfmRaaCHDkBXWBdO0c4sQAvLFP6zA==} + '@smithy/middleware-endpoint@2.5.1': + resolution: {integrity: sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-endpoint@3.0.0': + resolution: {integrity: sha512-aXOAWztw/5qAfp0NcA2OWpv6ZI/E+Dh9mByif7i91D/0iyYNUcKvskmXiowKESFkuZ7PIMd3VOR4fTibZDs2OQ==} engines: {node: '>=16.0.0'} - '@smithy/middleware-retry@3.0.25': - resolution: {integrity: sha512-m1F70cPaMBML4HiTgCw5I+jFNtjgz5z5UdGnUbG37vw6kh4UvizFYjqJGHvicfgKMkDL6mXwyPp5mhZg02g5sg==} + '@smithy/middleware-retry@2.3.1': + resolution: {integrity: sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-retry@3.0.1': + resolution: {integrity: sha512-hBhSEuL841FhJBK/19WpaGk5YWSzFk/P2UaVjANGKRv3eYNO8Y1lANWgqnuPWjOyCEWMPr58vELFDWpxvRKANw==} engines: {node: '>=16.0.0'} - '@smithy/middleware-serde@3.0.8': - resolution: {integrity: sha512-Xg2jK9Wc/1g/MBMP/EUn2DLspN8LNt+GMe7cgF+Ty3vl+Zvu+VeZU5nmhveU+H8pxyTsjrAkci8NqY6OuvZnjA==} + '@smithy/middleware-serde@2.3.0': + resolution: {integrity: sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-serde@3.0.0': + resolution: {integrity: sha512-I1vKG1foI+oPgG9r7IMY1S+xBnmAn1ISqployvqkwHoSb8VPsngHDTOgYGYBonuOKndaWRUGJZrKYYLB+Ane6w==} engines: {node: '>=16.0.0'} - '@smithy/middleware-stack@3.0.8': - resolution: {integrity: sha512-d7ZuwvYgp1+3682Nx0MD3D/HtkmZd49N3JUndYWQXfRZrYEnCWYc8BHcNmVsPAp9gKvlurdg/mubE6b/rPS9MA==} + '@smithy/middleware-stack@2.2.0': + resolution: {integrity: sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-stack@3.0.0': + resolution: {integrity: sha512-+H0jmyfAyHRFXm6wunskuNAqtj7yfmwFB6Fp37enytp2q047/Od9xetEaUbluyImOlGnGpaVGaVfjwawSr+i6Q==} engines: {node: '>=16.0.0'} - '@smithy/node-config-provider@3.1.9': - resolution: {integrity: sha512-qRHoah49QJ71eemjuS/WhUXB+mpNtwHRWQr77J/m40ewBVVwvo52kYAmb7iuaECgGTTcYxHS4Wmewfwy++ueew==} + '@smithy/node-config-provider@2.3.0': + resolution: {integrity: sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==} + engines: {node: '>=14.0.0'} + + '@smithy/node-config-provider@3.0.0': + resolution: {integrity: sha512-buqfaSdDh0zo62EPLf8rGDvcpKwGpO5ho4bXS2cdFhlOta7tBkWJt+O5uiaAeICfIOfPclNOndshDNSanX2X9g==} engines: {node: '>=16.0.0'} - '@smithy/node-http-handler@3.2.5': - resolution: {integrity: sha512-PkOwPNeKdvX/jCpn0A8n9/TyoxjGZB8WVoJmm9YzsnAgggTj4CrjpRHlTQw7dlLZ320n1mY1y+nTRUDViKi/3w==} + '@smithy/node-http-handler@2.5.0': + resolution: {integrity: sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==} + engines: {node: '>=14.0.0'} + + '@smithy/node-http-handler@3.0.0': + resolution: {integrity: sha512-3trD4r7NOMygwLbUJo4eodyQuypAWr7uvPnebNJ9a70dQhVn+US8j/lCnvoJS6BXfZeF7PkkkI0DemVJw+n+eQ==} engines: {node: '>=16.0.0'} - '@smithy/property-provider@3.1.8': - resolution: {integrity: sha512-ukNUyo6rHmusG64lmkjFeXemwYuKge1BJ8CtpVKmrxQxc6rhUX0vebcptFA9MmrGsnLhwnnqeH83VTU9hwOpjA==} + '@smithy/property-provider@2.2.0': + resolution: {integrity: sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==} + engines: {node: '>=14.0.0'} + + '@smithy/property-provider@3.0.0': + resolution: {integrity: sha512-LmbPgHBswdXCrkWWuUwBm9w72S2iLWyC/5jet9/Y9cGHtzqxi+GVjfCfahkvNV4KXEwgnH8EMpcrD9RUYe0eLQ==} engines: {node: '>=16.0.0'} - '@smithy/protocol-http@4.1.5': - resolution: {integrity: sha512-hsjtwpIemmCkm3ZV5fd/T0bPIugW1gJXwZ/hpuVubt2hEUApIoUTrf6qIdh9MAWlw0vjMrA1ztJLAwtNaZogvg==} + '@smithy/protocol-http@3.3.0': + resolution: {integrity: sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==} + engines: {node: '>=14.0.0'} + + '@smithy/protocol-http@4.0.0': + resolution: {integrity: sha512-qOQZOEI2XLWRWBO9AgIYuHuqjZ2csyr8/IlgFDHDNuIgLAMRx2Bl8ck5U5D6Vh9DPdoaVpuzwWMa0xcdL4O/AQ==} engines: {node: '>=16.0.0'} - '@smithy/querystring-builder@3.0.8': - resolution: {integrity: sha512-btYxGVqFUARbUrN6VhL9c3dnSviIwBYD9Rz1jHuN1hgh28Fpv2xjU1HeCeDJX68xctz7r4l1PBnFhGg1WBBPuA==} + '@smithy/querystring-builder@2.2.0': + resolution: {integrity: sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==} + engines: {node: '>=14.0.0'} + + '@smithy/querystring-builder@3.0.0': + resolution: {integrity: sha512-bW8Fi0NzyfkE0TmQphDXr1AmBDbK01cA4C1Z7ggwMAU5RDz5AAv/KmoRwzQAS0kxXNf/D2ALTEgwK0U2c4LtRg==} engines: {node: '>=16.0.0'} - '@smithy/querystring-parser@3.0.8': - resolution: {integrity: sha512-BtEk3FG7Ks64GAbt+JnKqwuobJNX8VmFLBsKIwWr1D60T426fGrV2L3YS5siOcUhhp6/Y6yhBw1PSPxA5p7qGg==} + '@smithy/querystring-parser@2.2.0': + resolution: {integrity: sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==} + engines: {node: '>=14.0.0'} + + '@smithy/querystring-parser@3.0.0': + resolution: {integrity: sha512-UzHwthk0UEccV4dHzPySnBy34AWw3V9lIqUTxmozQ+wPDAO9csCWMfOLe7V9A2agNYy7xE+Pb0S6K/J23JSzfQ==} engines: {node: '>=16.0.0'} - '@smithy/service-error-classification@3.0.8': - resolution: {integrity: sha512-uEC/kCCFto83bz5ZzapcrgGqHOh/0r69sZ2ZuHlgoD5kYgXJEThCoTuw/y1Ub3cE7aaKdznb+jD9xRPIfIwD7g==} + '@smithy/service-error-classification@2.1.5': + resolution: {integrity: sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==} + engines: {node: '>=14.0.0'} + + '@smithy/service-error-classification@3.0.0': + resolution: {integrity: sha512-3BsBtOUt2Gsnc3X23ew+r2M71WwtpHfEDGhHYHSDg6q1t8FrWh15jT25DLajFV1H+PpxAJ6gqe9yYeRUsmSdFA==} engines: {node: '>=16.0.0'} - '@smithy/shared-ini-file-loader@3.1.9': - resolution: {integrity: sha512-/+OsJRNtoRbtsX0UpSgWVxFZLsJHo/4sTr+kBg/J78sr7iC+tHeOvOJrS5hCpVQ6sWBbhWLp1UNiuMyZhE6pmA==} + '@smithy/shared-ini-file-loader@2.4.0': + resolution: {integrity: sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==} + engines: {node: '>=14.0.0'} + + '@smithy/shared-ini-file-loader@3.0.0': + resolution: {integrity: sha512-REVw6XauXk8xE4zo5aGL7Rz4ywA8qNMUn8RtWeTRQsgAlmlvbJ7CEPBcaXU2NDC3AYBgYAXrGyWD8XrN8UGDog==} engines: {node: '>=16.0.0'} - '@smithy/signature-v4@4.2.1': - resolution: {integrity: sha512-NsV1jF4EvmO5wqmaSzlnTVetemBS3FZHdyc5CExbDljcyJCEEkJr8ANu2JvtNbVg/9MvKAWV44kTrGS+Pi4INg==} + '@smithy/signature-v4@2.3.0': + resolution: {integrity: sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==} + engines: {node: '>=14.0.0'} + + '@smithy/signature-v4@3.0.0': + resolution: {integrity: sha512-kXFOkNX+BQHe2qnLxpMEaCRGap9J6tUGLzc3A9jdn+nD4JdMwCKTJ+zFwQ20GkY+mAXGatyTw3HcoUlR39HwmA==} engines: {node: '>=16.0.0'} - '@smithy/smithy-client@3.4.2': - resolution: {integrity: sha512-dxw1BDxJiY9/zI3cBqfVrInij6ShjpV4fmGHesGZZUiP9OSE/EVfdwdRz0PgvkEvrZHpsj2htRaHJfftE8giBA==} + '@smithy/smithy-client@2.5.1': + resolution: {integrity: sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==} + engines: {node: '>=14.0.0'} + + '@smithy/smithy-client@3.0.1': + resolution: {integrity: sha512-KAiFY4Y4jdHxR+4zerH/VBhaFKM8pbaVmJZ/CWJRwtM/CmwzTfXfvYwf6GoUwiHepdv+lwiOXCuOl6UBDUEINw==} engines: {node: '>=16.0.0'} - '@smithy/types@3.6.0': - resolution: {integrity: sha512-8VXK/KzOHefoC65yRgCn5vG1cysPJjHnOVt9d0ybFQSmJgQj152vMn4EkYhGuaOmnnZvCPav/KnYyE6/KsNZ2w==} + '@smithy/types@2.12.0': + resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==} + engines: {node: '>=14.0.0'} + + '@smithy/types@3.0.0': + resolution: {integrity: sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==} engines: {node: '>=16.0.0'} - '@smithy/url-parser@3.0.8': - resolution: {integrity: sha512-4FdOhwpTW7jtSFWm7SpfLGKIBC9ZaTKG5nBF0wK24aoQKQyDIKUw3+KFWCQ9maMzrgTJIuOvOnsV2lLGW5XjTg==} + '@smithy/url-parser@2.2.0': + resolution: {integrity: sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==} + + '@smithy/url-parser@3.0.0': + resolution: {integrity: sha512-2XLazFgUu+YOGHtWihB3FSLAfCUajVfNBXGGYjOaVKjLAuAxx3pSBY3hBgLzIgB17haf59gOG3imKqTy8mcrjw==} + + '@smithy/util-base64@2.3.0': + resolution: {integrity: sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==} + engines: {node: '>=14.0.0'} '@smithy/util-base64@3.0.0': resolution: {integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==} engines: {node: '>=16.0.0'} + '@smithy/util-body-length-browser@2.2.0': + resolution: {integrity: sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==} + '@smithy/util-body-length-browser@3.0.0': resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==} + '@smithy/util-body-length-node@2.3.0': + resolution: {integrity: sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==} + engines: {node: '>=14.0.0'} + '@smithy/util-body-length-node@3.0.0': resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==} engines: {node: '>=16.0.0'} @@ -3658,38 +4043,74 @@ packages: resolution: {integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==} engines: {node: '>=16.0.0'} + '@smithy/util-config-provider@2.3.0': + resolution: {integrity: sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==} + engines: {node: '>=14.0.0'} + '@smithy/util-config-provider@3.0.0': resolution: {integrity: sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==} engines: {node: '>=16.0.0'} - '@smithy/util-defaults-mode-browser@3.0.25': - resolution: {integrity: sha512-fRw7zymjIDt6XxIsLwfJfYUfbGoO9CmCJk6rjJ/X5cd20+d2Is7xjU5Kt/AiDt6hX8DAf5dztmfP5O82gR9emA==} + '@smithy/util-defaults-mode-browser@2.2.1': + resolution: {integrity: sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==} + engines: {node: '>= 10.0.0'} + + '@smithy/util-defaults-mode-browser@3.0.1': + resolution: {integrity: sha512-nW5kEzdJn1Bn5TF+gOPHh2rcPli8JU9vSSXLbfg7uPnfR1TMRQqs9zlYRhIb87NeSxIbpdXOI94tvXSy+fvDYg==} engines: {node: '>= 10.0.0'} - '@smithy/util-defaults-mode-node@3.0.25': - resolution: {integrity: sha512-H3BSZdBDiVZGzt8TG51Pd2FvFO0PAx/A0mJ0EH8a13KJ6iUCdYnw/Dk/MdC1kTd0eUuUGisDFaxXVXo4HHFL1g==} + '@smithy/util-defaults-mode-node@2.3.1': + resolution: {integrity: sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==} engines: {node: '>= 10.0.0'} - '@smithy/util-endpoints@2.1.4': - resolution: {integrity: sha512-kPt8j4emm7rdMWQyL0F89o92q10gvCUa6sBkBtDJ7nV2+P7wpXczzOfoDJ49CKXe5CCqb8dc1W+ZdLlrKzSAnQ==} + '@smithy/util-defaults-mode-node@3.0.1': + resolution: {integrity: sha512-TFk+Qb+elLc/MOhtSp+50fstyfZ6avQbgH2d96xUBpeScu+Al9elxv+UFAjaTHe0HQe5n+wem8ZLpXvU8lwV6Q==} + engines: {node: '>= 10.0.0'} + + '@smithy/util-endpoints@1.2.0': + resolution: {integrity: sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==} + engines: {node: '>= 14.0.0'} + + '@smithy/util-endpoints@2.0.0': + resolution: {integrity: sha512-+exaXzEY3DNt2qtA2OtRNSDlVrE4p32j1JSsQkzA5AdP0YtJNjkYbYhJxkFmPYcjI1abuwopOZCwUmv682QkiQ==} engines: {node: '>=16.0.0'} + '@smithy/util-hex-encoding@2.2.0': + resolution: {integrity: sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==} + engines: {node: '>=14.0.0'} + '@smithy/util-hex-encoding@3.0.0': resolution: {integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==} engines: {node: '>=16.0.0'} - '@smithy/util-middleware@3.0.8': - resolution: {integrity: sha512-p7iYAPaQjoeM+AKABpYWeDdtwQNxasr4aXQEA/OmbOaug9V0odRVDy3Wx4ci8soljE/JXQo+abV0qZpW8NX0yA==} + '@smithy/util-middleware@2.2.0': + resolution: {integrity: sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==} + engines: {node: '>=14.0.0'} + + '@smithy/util-middleware@3.0.0': + resolution: {integrity: sha512-q5ITdOnV2pXHSVDnKWrwgSNTDBAMHLptFE07ua/5Ty5WJ11bvr0vk2a7agu7qRhrCFRQlno5u3CneU5EELK+DQ==} engines: {node: '>=16.0.0'} - '@smithy/util-retry@3.0.8': - resolution: {integrity: sha512-TCEhLnY581YJ+g1x0hapPz13JFqzmh/pMWL2KEFASC51qCfw3+Y47MrTmea4bUE5vsdxQ4F6/KFbUeSz22Q1ow==} + '@smithy/util-retry@2.2.0': + resolution: {integrity: sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==} + engines: {node: '>= 14.0.0'} + + '@smithy/util-retry@3.0.0': + resolution: {integrity: sha512-nK99bvJiziGv/UOKJlDvFF45F00WgPLKVIGUfAK+mDhzVN2hb/S33uW2Tlhg5PVBoqY7tDVqL0zmu4OxAHgo9g==} engines: {node: '>=16.0.0'} - '@smithy/util-stream@3.2.1': - resolution: {integrity: sha512-R3ufuzJRxSJbE58K9AEnL/uSZyVdHzud9wLS8tIbXclxKzoe09CRohj2xV8wpx5tj7ZbiJaKYcutMm1eYgz/0A==} + '@smithy/util-stream@2.2.0': + resolution: {integrity: sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-stream@3.0.1': + resolution: {integrity: sha512-7F7VNNhAsfMRA8I986YdOY5fE0/T1/ZjFF6OLsqkvQVNP3vZ/szYDfGCyphb7ioA09r32K/0qbSFfNFU68aSzA==} engines: {node: '>=16.0.0'} + '@smithy/util-uri-escape@2.2.0': + resolution: {integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==} + engines: {node: '>=14.0.0'} + '@smithy/util-uri-escape@3.0.0': resolution: {integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==} engines: {node: '>=16.0.0'} @@ -3702,6 +4123,10 @@ packages: resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==} engines: {node: '>=16.0.0'} + '@smithy/util-waiter@2.2.0': + resolution: {integrity: sha512-IHk53BVw6MPMi2Gsn+hCng8rFA3ZmR3Rk7GllxDUW9qFJl/hiSvskn7XldkECapQVkIg/1dHpMAxI9xSTaLLSA==} + engines: {node: '>=14.0.0'} + '@tidbcloud/serverless@0.1.1': resolution: {integrity: sha512-km2P5Mgr9nqVah5p5aMYbO3dBqecSwZ0AU7+BhJH+03L2eJO6qCATcBR8UHPuVLhA7GCt3CambKvVYK79pVQ2g==} engines: {node: '>=16'} @@ -3710,8 +4135,8 @@ packages: resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} engines: {node: '>= 6'} - '@trivago/prettier-plugin-sort-imports@4.3.0': - resolution: {integrity: sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==} + '@trivago/prettier-plugin-sort-imports@4.2.0': + resolution: {integrity: sha512-YBepjbt+ZNBVmN3ev1amQH3lWCmHyt5qTbLCp/syXJRu/Kw2koXh44qayB1gMRxcL/gV8egmjN5xWSrYyfUtyw==} peerDependencies: '@vue/compiler-sfc': 3.x prettier: 2.x - 3.x @@ -3731,27 +4156,15 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - '@types/async-retry@1.4.9': - resolution: {integrity: sha512-s1ciZQJzRh3708X/m3vPExr5KJlzlZJvXsKpbtE2luqNcbROr64qU+3KpJsYHqWMeaxI839OvXf9PrUSw1Xtyg==} - - '@types/axios@0.14.4': - resolution: {integrity: sha512-9JgOaunvQdsQ/qW2OPmE5+hCeUB52lQSolecrFrthct55QekhmXEwT203s20RL+UHtCQc15y3VXpby9E7Kkh/g==} - deprecated: This is a stub types definition. axios provides its own type definitions, so you do not need this installed. + '@types/async-retry@1.4.8': + resolution: {integrity: sha512-Qup/B5PWLe86yI5I3av6ePGaeQrIHNKCwbsQotD6aHQ6YkHsMUxVZkZsmx/Ry3VZQ6uysHwTjQ7666+k6UjVJA==} - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + '@types/axios@0.14.0': + resolution: {integrity: sha512-KqQnQbdYE54D7oa/UmYVMZKq7CO4l8DEENzOKc4aBRwxCXSlJXGz83flFx5L7AWrOQnmuN3kVsRdt+GZPPjiVQ==} + deprecated: This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed! - '@types/babel__generator@7.6.8': - resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.20.6': - resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} - - '@types/better-sqlite3@7.6.11': - resolution: {integrity: sha512-i8KcD3PgGtGBLl3+mMYA8PdKkButvPyARxA7IQAd6qeslht13qxb1zzO8dRCtE7U3IoJS782zDBAeoKiM695kg==} + '@types/better-sqlite3@7.6.10': + resolution: {integrity: sha512-TZBjD+yOsyrUJGmcUj6OS3JADk3+UZcNv3NOBqGkM09bZdi28fNZw8ODqbMOLfKCu7RYCO62/ldq1iHbzxqoPw==} '@types/better-sqlite3@7.6.12': resolution: {integrity: sha512-fnQmj8lELIj7BSrZQAdBMHEHX8OZLYIHXqAKT1O7tDfLxaINzf00PMjw22r3N/xXh0w/sGHlO6SVaCQ2mj78lg==} @@ -3768,8 +4181,8 @@ packages: '@types/docker-modem@3.0.6': resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} - '@types/dockerode@3.3.31': - resolution: {integrity: sha512-42R9eoVqJDSvVspV89g7RwRqfNExgievLNWoHkg7NoWIqAmavIbgQBb4oc0qRtHkxE+I3Xxvqv7qVXFABKPBTg==} + '@types/dockerode@3.3.29': + resolution: {integrity: sha512-5PRRq/yt5OT/Jf77ltIdz4EiR9+VLnPF+HpU4xGFwUqmV24Co2HKBNW3w+slqZ1CYchbcDeqJASHDYWzZCcMiQ==} '@types/dockerode@3.3.32': resolution: {integrity: sha512-xxcG0g5AWKtNyh7I7wswLdFvym4Mlqks5ZlKzxEUrGHS0r0PUOfxm2T0mspwu10mHQqu3Ck3MI3V2HqvLWE1fg==} @@ -3777,8 +4190,8 @@ packages: '@types/emscripten@1.39.11': resolution: {integrity: sha512-dOeX2BeNA7j6BTEqJQL3ut0bRCfsyQMd5i4FT8JfHfYhAOuJPCGh0dQFbxVJxUyQ+75x6enhDdndGb624/QszA==} - '@types/estree@1.0.6': - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/estree@1.0.1': + resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -3798,9 +4211,6 @@ packages: '@types/glob@8.1.0': resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} - '@types/graceful-fs@4.1.9': - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - '@types/http-errors@2.0.4': resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} @@ -3810,17 +4220,14 @@ packages: '@types/istanbul-lib-report@3.0.3': resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - '@types/istanbul-reports@1.1.2': - resolution: {integrity: sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==} - '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} '@types/json-diff@1.0.3': resolution: {integrity: sha512-Qvxm8fpRMv/1zZR3sQWImeRK2mBYJji20xF51Fq9Gt//Ed18u0x6/FNLogLS1xhfUWTEmDyqveJqn95ltB6Kvw==} - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/json-schema@7.0.13': + resolution: {integrity: sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==} '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} @@ -3837,23 +4244,23 @@ packages: '@types/minimatch@5.1.2': resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - '@types/minimist@1.2.5': - resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + '@types/minimist@1.2.2': + resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} - '@types/node@18.19.64': - resolution: {integrity: sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==} + '@types/node@18.15.10': + resolution: {integrity: sha512-9avDaQJczATcXgfmMAW3MIWArOO7A+m90vuCFLr8AotWf8igO/mRoYukrk2cqZVtv38tHs33retzHEilM7FpeQ==} - '@types/node@20.12.14': - resolution: {integrity: sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==} + '@types/node@18.19.33': + resolution: {integrity: sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A==} - '@types/node@20.17.6': - resolution: {integrity: sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==} + '@types/node@20.10.1': + resolution: {integrity: sha512-T2qwhjWwGH81vUEx4EXmBKsTJRXFXNZTL4v0gi01+zyBmCwzE6TyHszqX01m+QHTEq+EZNo13NeJIdEqf+Myrg==} - '@types/node@22.9.0': - resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} + '@types/node@20.12.12': + resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} '@types/node@22.9.1': resolution: {integrity: sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==} @@ -3870,20 +4277,20 @@ packages: '@types/pluralize@0.0.33': resolution: {integrity: sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==} - '@types/prop-types@15.7.13': - resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} + '@types/prop-types@15.7.12': + resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} - '@types/ps-tree@1.1.6': - resolution: {integrity: sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==} + '@types/ps-tree@1.1.2': + resolution: {integrity: sha512-ZREFYlpUmPQJ0esjxoG1fMvB2HNaD3z+mjqdSosZvd3RalncI9NEur73P8ZJz4YQdL64CmV1w0RuqoRUlhQRBw==} - '@types/qs@6.9.17': - resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==} + '@types/qs@6.9.15': + resolution: {integrity: sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==} '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/react@18.3.12': - resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==} + '@types/react@18.3.1': + resolution: {integrity: sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==} '@types/retry@0.12.5': resolution: {integrity: sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw==} @@ -3900,8 +4307,8 @@ packages: '@types/sql.js@1.4.9': resolution: {integrity: sha512-ep8b36RKHlgWPqjNG9ToUrPiwkhwh0AEzy883mO5Xnd+cL6VBH1EvSjBAAuxLUFF2Vn/moE3Me6v9E1Lo+48GQ==} - '@types/ssh2@1.15.1': - resolution: {integrity: sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA==} + '@types/ssh2@1.15.0': + resolution: {integrity: sha512-YcT8jP5F8NzWeevWvcyrrLB3zcneVjzYY9ZDSMAMboI+2zR1qYWFhwsyOFVzT7Jorn67vqxC0FRiw8YyG9P1ww==} '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -3912,23 +4319,23 @@ packages: '@types/uuid@9.0.8': resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} - '@types/which@3.0.4': - resolution: {integrity: sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w==} + '@types/which@3.0.0': + resolution: {integrity: sha512-ASCxdbsrwNfSMXALlC3Decif9rwDMu+80KGp5zI2RLRotfMsTv7fHL8W8VDp24wymzDyIFudhUeSCugrgRFfHQ==} - '@types/ws@8.5.13': - resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + '@types/ws@8.5.11': + resolution: {integrity: sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==} '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - '@types/yargs@13.0.12': - resolution: {integrity: sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ==} + '@types/yargs@15.0.19': + resolution: {integrity: sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==} - '@types/yargs@17.0.33': - resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@types/yargs@17.0.32': + resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} - '@typescript-eslint/eslint-plugin@6.21.0': - resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} + '@typescript-eslint/eslint-plugin@6.7.3': + resolution: {integrity: sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -3938,8 +4345,8 @@ packages: typescript: optional: true - '@typescript-eslint/eslint-plugin@7.18.0': - resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} + '@typescript-eslint/eslint-plugin@7.16.1': + resolution: {integrity: sha512-SxdPak/5bO0EnGktV05+Hq8oatjAYVY3Zh2bye9pGZy6+jwyR3LG3YKkV4YatlsgqXP28BTeVm9pqwJM96vf2A==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -3955,8 +4362,18 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/parser@6.21.0': - resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} + '@typescript-eslint/parser@6.10.0': + resolution: {integrity: sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@6.7.3': + resolution: {integrity: sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -3965,8 +4382,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@7.18.0': - resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} + '@typescript-eslint/parser@7.16.1': + resolution: {integrity: sha512-u+1Qx86jfGQ5i4JjK33/FnawZRpsLxRnKzGE6EABZ40KxVT/vWsiZFEBBHjFOljmmV3MBYOHEKi0Jm9hbAOClA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -3975,8 +4392,8 @@ packages: typescript: optional: true - '@typescript-eslint/rule-tester@6.21.0': - resolution: {integrity: sha512-twxQo4He8+AQ/YG70Xt7Fl/ImBLpi7qElxHN6/aK+U4z97JsITCG7DdIIUw5M+qKtDMCYkZCEE2If8dnHI7jWA==} + '@typescript-eslint/rule-tester@6.10.0': + resolution: {integrity: sha512-I0ZY+9ei73dlOuXwIYWsn/r/ue26Ygf4yEJPxeJRPI06YWDawmR1FI1dXL6ChAWVrmBQRvWep/1PxnV41zfcMA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@eslint/eslintrc': '>=2' @@ -3986,16 +4403,20 @@ packages: resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/scope-manager@6.21.0': - resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} + '@typescript-eslint/scope-manager@6.10.0': + resolution: {integrity: sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/scope-manager@6.7.3': + resolution: {integrity: sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/scope-manager@7.18.0': - resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} + '@typescript-eslint/scope-manager@7.16.1': + resolution: {integrity: sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/type-utils@6.21.0': - resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} + '@typescript-eslint/type-utils@6.7.3': + resolution: {integrity: sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4004,8 +4425,8 @@ packages: typescript: optional: true - '@typescript-eslint/type-utils@7.18.0': - resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} + '@typescript-eslint/type-utils@7.16.1': + resolution: {integrity: sha512-rbu/H2MWXN4SkjIIyWcmYBjlp55VT+1G3duFOIukTNFxr9PI35pLc2ydwAfejCEitCv4uztA07q0QWanOHC7dA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -4018,12 +4439,16 @@ packages: resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/types@6.21.0': - resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} + '@typescript-eslint/types@6.10.0': + resolution: {integrity: sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/types@6.7.3': + resolution: {integrity: sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/types@7.18.0': - resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} + '@typescript-eslint/types@7.16.1': + resolution: {integrity: sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==} engines: {node: ^18.18.0 || >=20.0.0} '@typescript-eslint/typescript-estree@5.62.0': @@ -4035,8 +4460,17 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@6.21.0': - resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} + '@typescript-eslint/typescript-estree@6.10.0': + resolution: {integrity: sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/typescript-estree@6.7.3': + resolution: {integrity: sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -4044,8 +4478,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@7.18.0': - resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} + '@typescript-eslint/typescript-estree@7.16.1': + resolution: {integrity: sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -4059,14 +4493,20 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@6.21.0': - resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} + '@typescript-eslint/utils@6.10.0': + resolution: {integrity: sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + + '@typescript-eslint/utils@6.7.3': + resolution: {integrity: sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@7.18.0': - resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} + '@typescript-eslint/utils@7.16.1': + resolution: {integrity: sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -4075,12 +4515,16 @@ packages: resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/visitor-keys@6.21.0': - resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} + '@typescript-eslint/visitor-keys@6.10.0': + resolution: {integrity: sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/visitor-keys@6.7.3': + resolution: {integrity: sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/visitor-keys@7.18.0': - resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} + '@typescript-eslint/visitor-keys@7.16.1': + resolution: {integrity: sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==} engines: {node: ^18.18.0 || >=20.0.0} '@typescript/analyze-trace@0.10.1': @@ -4107,13 +4551,14 @@ packages: '@vitest/expect@1.6.0': resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} - '@vitest/expect@2.1.4': - resolution: {integrity: sha512-DOETT0Oh1avie/D/o2sgMHGrzYUFFo3zqESB2Hn70z6QB1HrS2IQ9z5DfyTqU8sg4Bpu13zZe9V4+UTNQlUeQA==} + '@vitest/expect@2.1.2': + resolution: {integrity: sha512-FEgtlN8mIUSEAAnlvn7mP8vzaWhEaAEvhSXCqrsijM7K6QqjB11qoRZYEd4AKSCDz8p0/+yH5LzhZ47qt+EyPg==} - '@vitest/mocker@2.1.4': - resolution: {integrity: sha512-Ky/O1Lc0QBbutJdW0rqLeFNbuLEyS+mIPiNdlVlp2/yhJ0SbyYqObS5IHdhferJud8MbbwMnexg4jordE5cCoQ==} + '@vitest/mocker@2.1.2': + resolution: {integrity: sha512-ExElkCGMS13JAJy+812fw1aCv2QO/LBK6CyO4WOPAzLTmve50gydOlWhgdBJPx2ztbADUq3JVI0C5U+bShaeEA==} peerDependencies: - msw: ^2.4.9 + '@vitest/spy': 2.1.2 + msw: ^2.3.5 vite: ^5.0.0 peerDependenciesMeta: msw: @@ -4121,26 +4566,26 @@ packages: vite: optional: true - '@vitest/pretty-format@2.1.4': - resolution: {integrity: sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==} + '@vitest/pretty-format@2.1.2': + resolution: {integrity: sha512-FIoglbHrSUlOJPDGIrh2bjX1sNars5HbxlcsFKCtKzu4+5lpsRhOCVcuzp0fEhAGHkPZRIXVNzPcpSlkoZ3LuA==} '@vitest/runner@1.6.0': resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} - '@vitest/runner@2.1.4': - resolution: {integrity: sha512-sKRautINI9XICAMl2bjxQM8VfCMTB0EbsBc/EDFA57V6UQevEKY/TOPOF5nzcvCALltiLfXWbq4MaAwWx/YxIA==} + '@vitest/runner@2.1.2': + resolution: {integrity: sha512-UCsPtvluHO3u7jdoONGjOSil+uON5SSvU9buQh3lP7GgUXHp78guN1wRmZDX4wGK6J10f9NUtP6pO+SFquoMlw==} '@vitest/snapshot@1.6.0': resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} - '@vitest/snapshot@2.1.4': - resolution: {integrity: sha512-3Kab14fn/5QZRog5BPj6Rs8dc4B+mim27XaKWFWHWA87R56AKjHTGcBFKpvZKDzC4u5Wd0w/qKsUIio3KzWW4Q==} + '@vitest/snapshot@2.1.2': + resolution: {integrity: sha512-xtAeNsZ++aRIYIUsek7VHzry/9AcxeULlegBvsdLncLmNCR6tR8SRjn8BbDP4naxtccvzTqZ+L1ltZlRCfBZFA==} '@vitest/spy@1.6.0': resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} - '@vitest/spy@2.1.4': - resolution: {integrity: sha512-4JOxa+UAizJgpZfaCPKK2smq9d8mmjZVPMt2kOsg/R8QkoRzydHH1qHxIYNvr1zlEaFj4SXiaaJWxq/LPLKaLg==} + '@vitest/spy@2.1.2': + resolution: {integrity: sha512-GSUi5zoy+abNRJwmFhBDC0yRuVUn8WMlQscvnbbXdKLXX9dE59YbfwXxuJ/mth6eeqIzofU8BB5XDo/Ns/qK2A==} '@vitest/ui@1.6.0': resolution: {integrity: sha512-k3Lyo+ONLOgylctiGovRKy7V4+dIN2yxstX3eY5cWFXH6WP+ooVX79YSyi0GagdTQzLmT43BF27T0s6dOIPBXA==} @@ -4150,11 +4595,11 @@ packages: '@vitest/utils@1.6.0': resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} - '@vitest/utils@2.1.4': - resolution: {integrity: sha512-MXDnZn0Awl2S86PSNIim5PWXgIAx8CIkzu35mBdSApUip6RFOGXBCf3YFyeEu8n1IHk4bWD46DeYFu9mQlFIRg==} + '@vitest/utils@2.1.2': + resolution: {integrity: sha512-zMO2KdYy6mx56btx9JvAqAZ6EyS3g49krMPPrgOp1yxGZiA93HumGk+bZ5jIZtOg5/VBYl5eBmGRQHqq4FG6uQ==} - '@xata.io/client@0.29.5': - resolution: {integrity: sha512-b55dmPVNVFOE5nj2F2G6t9l/d5yYBhIu5X5w3rznhhsriGHkrzn93tqJexIZPS77E7f/yDXcFz06KbvR3bHK5w==} + '@xata.io/client@0.29.4': + resolution: {integrity: sha512-dRff4E/wINr0SYIlOHwApo0h8jzpAHVf2RcbGMkK9Xrddbe90KmCEx/gue9hLhBOoCCp6qUht2h9BsuVPruymw==} peerDependencies: typescript: '>=4.5' @@ -4183,12 +4628,22 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + + acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true - acorn@8.14.0: - resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + acorn@8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} hasBin: true @@ -4222,8 +4677,8 @@ packages: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} - ansi-escapes@6.2.1: - resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} + ansi-escapes@6.2.0: + resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==} engines: {node: '>=14.16'} ansi-escapes@7.0.0: @@ -4241,8 +4696,8 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} ansi-regex@6.1.0: @@ -4275,6 +4730,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + appdirsjs@1.2.7: + resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==} + application-config-path@0.1.1: resolution: {integrity: sha512-zy9cHePtMP0YhwG+CfHm0bgwdnga2X3gZexpdCwEj//dpb+TKajtiC8REEUJUSq6Ab4f9cgNy2l8ObXzCXFkEw==} @@ -4301,6 +4759,9 @@ packages: argsarray@0.0.1: resolution: {integrity: sha512-u96dg2GcAKtpTrBdDoFIM7PjcBA+6rSP0OR94MOReNRyUECL6MtQt5XXmRr4qrftYaef9+l5hcpO5te7sML1Cg==} + array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + array-buffer-byte-length@1.0.1: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} @@ -4312,24 +4773,28 @@ packages: array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + array-includes@3.1.6: + resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} engines: {node: '>= 0.4'} array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - array.prototype.findlastindex@1.2.5: - resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + array.prototype.findlastindex@1.2.2: + resolution: {integrity: sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==} engines: {node: '>= 0.4'} - array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + array.prototype.flat@1.3.1: + resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} engines: {node: '>= 0.4'} - array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + array.prototype.flatmap@1.3.1: + resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.1: + resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==} engines: {node: '>= 0.4'} arraybuffer.prototype.slice@1.0.3: @@ -4368,6 +4833,10 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} + astral-regex@1.0.0: + resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} + engines: {node: '>=4'} + async-limiter@1.0.1: resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} @@ -4381,8 +4850,8 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - ava@5.3.1: - resolution: {integrity: sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==} + ava@5.3.0: + resolution: {integrity: sha512-QYvBdyygl1LGX13IuYsC4bkwVCzZeovMGbxYkD73i7DVJxNlWnFa06YgrBOTbjw2QvSKUl5fOJ92Kj5WK9hSeg==} engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} hasBin: true peerDependencies: @@ -4391,42 +4860,33 @@ packages: '@ava/typescript': optional: true + available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - aws4fetch@1.0.20: - resolution: {integrity: sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==} + aws-ssl-profiles@1.1.1: + resolution: {integrity: sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==} + engines: {node: '>= 6.0.0'} - axios@1.7.7: - resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + axios@1.6.8: + resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} babel-core@7.0.0-bridge.0: resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} peerDependencies: '@babel/core': ^7.0.0-0 - babel-jest@29.7.0: - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.8.0 - - babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - - babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - babel-plugin-polyfill-corejs2@0.4.11: resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-polyfill-corejs3@0.10.6: - resolution: {integrity: sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==} + babel-plugin-polyfill-corejs3@0.10.4: + resolution: {integrity: sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 @@ -4435,31 +4895,14 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-react-compiler@0.0.0-experimental-592953e-20240517: - resolution: {integrity: sha512-OjG1SVaeQZaJrqkMFJatg8W/MTow8Ak5rx2SI0ETQBO1XvOk/XZGMbltNCPdFJLKghBYoBjC+Y3Ap/Xr7B01mA==} - - babel-plugin-react-native-web@0.19.13: - resolution: {integrity: sha512-4hHoto6xaN23LCyZgL9LJZc3olmAxd7b6jDzlZnKXAh4rRAbZRKNBJoOOdp46OBqgy+K0t0guTj5/mhA8inymQ==} - - babel-plugin-syntax-hermes-parser@0.23.1: - resolution: {integrity: sha512-uNLD0tk2tLUjGFdmCk+u/3FEw2o+BAwW4g+z2QVlxJrzZYOOPADroEcNtTPt5lNiScctaUmnsTkVEnOwZUOLhA==} + babel-plugin-react-native-web@0.19.12: + resolution: {integrity: sha512-eYZ4+P6jNcB37lObWIg0pUbi7+3PKoU1Oie2j0C8UF3cXyXoR74tO2NBjI/FORb2LJyItJZEAmjU5pSaJYEL1w==} babel-plugin-transform-flow-enums@0.0.2: resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} - babel-preset-current-node-syntax@1.1.0: - resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} - peerDependencies: - '@babel/core': ^7.0.0 - - babel-preset-expo@11.0.15: - resolution: {integrity: sha512-rgiMTYwqIPULaO7iZdqyL7aAff9QLOX6OWUtLZBlOrOTreGY1yHah/5+l8MvI6NVc/8Zj5LY4Y5uMSnJIuzTLw==} - - babel-preset-jest@29.6.3: - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.0.0 + babel-preset-expo@11.0.6: + resolution: {integrity: sha512-jRi9I5/jT+dnIiNJDjDg+I/pV+AlxrIW/DNbdqYoRWPZA/LHDqD6IJnJXLxbuTcQ+llp+0LWcU7f/kC/PgGpkw==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -4487,8 +4930,8 @@ packages: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} bindings@1.5.0: @@ -4503,16 +4946,13 @@ packages: blueimp-md5@2.19.0: resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} - body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + body-parser@1.20.2: + resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} bowser@2.11.0: resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - bplist-creator@0.0.7: - resolution: {integrity: sha512-xp/tcaV3T5PCiaY04mXga7o/TE+t95gqeLmADeBI1CvZtdWTbgBt3uLpvh4UWtenKeBhCV6oVxGk38yZr2uYEA==} - bplist-creator@0.1.0: resolution: {integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==} @@ -4534,8 +4974,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.24.2: - resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} + browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -4578,11 +5018,11 @@ packages: bun-types@0.6.14: resolution: {integrity: sha512-sRdvu+t59+H/TVOe7FSGFWYITbqkhiCx9NxVUHt2+JOXM9gUOe5uMPvVvcr/hGngnh+/yb5a7uPE4JaS6uxujg==} - bun-types@1.1.34: - resolution: {integrity: sha512-br5QygTEL/TwB4uQOb96Ky22j4Gq2WxWH/8Oqv20fk5HagwKXo/akB+LiYgSfzexCt6kkcUaVm+bKiPl71xPvw==} + bun-types@1.0.3: + resolution: {integrity: sha512-XlyKVdYCHa7K5PHYGcwOVOrGE/bMnLS51y7zFA3ZAAXyiQ6dTaNXNCWTTufgII/6ruN770uhAXphQmzvU/r2fQ==} - bundle-require@4.2.1: - resolution: {integrity: sha512-7Q/6vkyYAwOmQNRw75x+4yRtZCZJXUDmHHlFdkiV0wgv/reNjtJwpu1jPJ0w2kbEpIM0uoKI3S4/f39dU7AjSA==} + bundle-require@4.0.2: + resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: esbuild: '>=0.17' @@ -4597,6 +5037,10 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} + bytes@3.0.0: + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} + engines: {node: '>= 0.8'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -4609,10 +5053,13 @@ packages: resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} engines: {node: '>= 10'} - cacache@18.0.4: - resolution: {integrity: sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==} + cacache@18.0.3: + resolution: {integrity: sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==} engines: {node: ^16.14.0 || >=18.0.0} + call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} @@ -4633,8 +5080,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - callsites@4.2.0: - resolution: {integrity: sha512-kfzR4zzQtAE9PC7CzZsjl3aBNbXWuXiSeOCdLcPpBfGW8YuCqQHcRPFDbr/BPVmd3EEPVpuFzLyuT/cUhPr4OQ==} + callsites@4.1.0: + resolution: {integrity: sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==} engines: {node: '>=12.20'} camelcase@5.3.1: @@ -4649,8 +5096,8 @@ packages: resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} engines: {node: '>=14.16'} - caniuse-lite@1.0.30001679: - resolution: {integrity: sha512-j2YqID/YwpLnKzCmBOS4tlZdWprXm3ZmQLBH9ZBXFOhoxLA46fwyBvx6toCBWBmnuwUY/qB3kEU6gFx8qgCroA==} + caniuse-lite@1.0.30001624: + resolution: {integrity: sha512-0dWnQG87UevOCPYaOR49CBcLBwoZLpws+k6W37nLjWUhumP1Isusj0p2u+3KhjNloRWK9OKMgjBBzPujQHw4nA==} capnp-ts@0.7.0: resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} @@ -4663,12 +5110,12 @@ packages: resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} engines: {node: '>=12.19'} - chai@4.5.0: - resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} + chai@4.4.1: + resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} engines: {node: '>=4'} - chai@5.1.2: - resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} + chai@5.1.1: + resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} engines: {node: '>=12'} chalk@2.4.2: @@ -4697,14 +5144,14 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} + chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} - chokidar@4.0.1: - resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} - engines: {node: '>= 14.16.0'} - chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -4717,15 +5164,16 @@ packages: engines: {node: '>=12.13.0'} hasBin: true - chromium-edge-launcher@0.2.0: - resolution: {integrity: sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==} - chunkd@2.0.1: resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} ci-info@2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + ci-info@3.8.0: + resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} + engines: {node: '>=8'} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -4752,18 +5200,17 @@ packages: resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} engines: {node: '>=0.10.0'} - cli-color@2.0.4: - resolution: {integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==} + cli-color@2.0.3: + resolution: {integrity: sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==} engines: {node: '>=0.10'} cli-cursor@2.1.0: resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==} engines: {node: '>=4'} - cli-highlight@2.1.11: - resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} - engines: {node: '>=8.0.0', npm: '>=5.0.0'} - hasBin: true + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} cli-highlight@2.1.11: resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} @@ -4774,8 +5221,8 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - cli-table3@0.6.5: - resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + cli-table3@0.6.3: + resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} engines: {node: 10.* || >= 12.*} cli-table3@0.6.5: @@ -4786,6 +5233,9 @@ packages: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -4826,6 +5276,9 @@ packages: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + colorette@2.0.19: resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} @@ -4844,6 +5297,10 @@ packages: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} + commander@11.0.0: + resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==} + engines: {node: '>=16'} + commander@12.1.0: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} @@ -4872,6 +5329,14 @@ packages: component-type@1.2.2: resolution: {integrity: sha512-99VUHREHiN5cLeHm3YLq312p6v+HUEcwtLCAtelvUDI6+SH5g5Cr85oNR2S1o6ywzL0ykMbuwLzM2ANocjEOIA==} + compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + + compression@1.7.4: + resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} + engines: {node: '>= 0.8.0'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -4879,13 +5344,13 @@ packages: resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} - concurrently@8.2.2: - resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} + concurrently@8.2.1: + resolution: {integrity: sha512-nVraf3aXOpIcNud5pB9M82p1tynmZkrSGQ1p6X/VY8cJ+2LMVqAgXsJxYYefACSHbTYlm92O1xuhdGTjwoEvbQ==} engines: {node: ^14.13.0 || >=16.0.0} hasBin: true - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + confbox@0.1.7: + resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} connect@3.7.0: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} @@ -4916,12 +5381,12 @@ packages: cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - cookie@0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} copy-anything@3.0.5: @@ -4978,8 +5443,8 @@ packages: resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} engines: {node: '>=4.8'} - cross-spawn@7.0.5: - resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==} + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} crypt@0.0.2: @@ -5000,9 +5465,8 @@ packages: resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} engines: {node: '>=0.10.0'} - d@1.0.2: - resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} - engines: {node: '>=0.12'} + d@1.0.1: + resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} dag-map@1.0.2: resolution: {integrity: sha512-+LSAiGFwQ9dRnRdOeaj7g47ZFJcOUPukAP8J3A3fuZ1g9Y44BG+P1sgApjLXTQPOzC4+7S9Wr8kXsfpINM4jpw==} @@ -5030,13 +5494,16 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} - date-fns@4.1.0: - resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + date-fns@3.6.0: + resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} date-time@3.1.0: resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} engines: {node: '>=6'} + dayjs@1.11.11: + resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -5062,8 +5529,8 @@ packages: supports-color: optional: true - debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -5071,12 +5538,25 @@ packages: supports-color: optional: true - decompress-response@6.0.0: + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} - deep-eql@4.1.4: - resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} + deep-eql@4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} deep-eql@5.0.2: @@ -5090,6 +5570,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + default-gateway@4.2.0: resolution: {integrity: sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==} engines: {node: '>=6'} @@ -5105,6 +5589,10 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} + define-properties@1.2.0: + resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} + engines: {node: '>= 0.4'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -5163,8 +5651,8 @@ packages: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} - diff@5.2.0: - resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + diff@5.1.0: + resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} engines: {node: '>=0.3.1'} difflib@0.2.4: @@ -5288,8 +5776,8 @@ packages: sqlite3: optional: true - drizzle-prisma-generator@0.1.7: - resolution: {integrity: sha512-KW+Z6W4hjvsiOCCPEmGyO+Oal7KPv2yQ3uZzHasaVIn+gUWGrkcy8BCDEp1h7uRBRSAd/l17EM4DfljhgYXxBw==} + drizzle-prisma-generator@0.1.4: + resolution: {integrity: sha512-6gY17/wTWfNF40rKjiYeWdkU8Gi6FQiOlU4oXa8uuo3ZZ8E6FH3250AhgCOMWAKZLpjQnk8FSzS0GXzwHkShkQ==} hasBin: true duplexer@0.1.2: @@ -5301,8 +5789,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.55: - resolution: {integrity: sha512-6maZ2ASDOTBtjt9FhqYPRnbvKU5tjG0IN9SztUOWYw2AzNDNpKJYLJmlK0/En4Hs/aiWnB+JZ+gW19PIGszgKg==} + electron-to-chromium@1.4.783: + resolution: {integrity: sha512-bT0jEz/Xz1fahQpbZ1D7LgmPYZ3iHVY39NcWWro1+hA2IvjiPeaXtfSqrQ+nXjApMvQRE2ASt1itSLRrebHMRQ==} emittery@1.0.3: resolution: {integrity: sha512-tJdCJitoy2lrC2ldJcqN4vkqJ00lT+tOWNT1hBJjO/3FDMJa5TTIiYGCKGkn/WfCyOzUMObeohbVTj00fhiLiA==} @@ -5321,10 +5809,6 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} @@ -5343,9 +5827,10 @@ packages: resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - environment@1.1.0: - resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} - engines: {node: '>=18'} + envinfo@7.13.0: + resolution: {integrity: sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==} + engines: {node: '>=4'} + hasBin: true environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} @@ -5363,6 +5848,14 @@ packages: error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + errorhandler@1.5.1: + resolution: {integrity: sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==} + engines: {node: '>= 0.8'} + + es-abstract@1.22.1: + resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==} + engines: {node: '>= 0.4'} + es-abstract@1.23.3: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} @@ -5379,27 +5872,30 @@ packages: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} engines: {node: '>= 0.4'} + es-set-tostringtag@2.0.1: + resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} + engines: {node: '>= 0.4'} + es-set-tostringtag@2.0.3: resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} - es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + es-shim-unscopables@1.0.0: + resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} - es5-ext@0.10.64: - resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} + es5-ext@0.10.62: + resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} engines: {node: '>=0.10'} es6-iterator@2.0.3: resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - es6-symbol@3.1.4: - resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} - engines: {node: '>=0.12'} + es6-symbol@3.1.3: + resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} es6-weak-map@2.0.3: resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} @@ -5494,11 +5990,11 @@ packages: cpu: [x64] os: [netbsd] - esbuild-node-externals@1.15.0: - resolution: {integrity: sha512-lM5f3CQL9Ctv6mBwwYAEMcphK2qrjVRnemT1mufECpFaidZvFVvQDPcuno/MQfLVk4utVuSVxm1RHLyg/ONQ/A==} + esbuild-node-externals@1.14.0: + resolution: {integrity: sha512-jMWnTlCII3cLEjR5+u0JRSTJuP+MgbjEHKfwSIAI41NgLQ0ZjfzjchlbEn0r7v2u5gCBMSEYvYlkO7GDG8gG3A==} engines: {node: '>=12'} peerDependencies: - esbuild: 0.12 - 0.24 + esbuild: 0.12 - 0.23 esbuild-openbsd-64@0.14.54: resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} @@ -5506,8 +6002,8 @@ packages: cpu: [x64] os: [openbsd] - esbuild-register@3.6.0: - resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} + esbuild-register@3.5.0: + resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==} peerDependencies: esbuild: '>=0.12 <1' @@ -5555,23 +6051,27 @@ packages: engines: {node: '>=12'} hasBin: true + esbuild@0.20.2: + resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + engines: {node: '>=12'} + hasBin: true + esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} hasBin: true - esbuild@0.23.1: - resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + esbuild@0.23.0: + resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==} engines: {node: '>=18'} hasBin: true - esbuild@0.24.0: - resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==} - engines: {node: '>=18'} - hasBin: true + escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} escape-html@1.0.3: @@ -5602,8 +6102,8 @@ packages: eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - eslint-module-utils@2.12.0: - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + eslint-module-utils@2.8.0: + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -5623,12 +6123,12 @@ packages: eslint-import-resolver-webpack: optional: true - eslint-plugin-import@2.31.0: - resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} + eslint-plugin-import@2.28.1: + resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 peerDependenciesMeta: '@typescript-eslint/parser': optional: true @@ -5656,12 +6156,12 @@ packages: peerDependencies: eslint: '>=8.44.0' - eslint-plugin-unused-imports@3.2.0: - resolution: {integrity: sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==} + eslint-plugin-unused-imports@3.0.0: + resolution: {integrity: sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - '@typescript-eslint/eslint-plugin': 6 - 7 - eslint: '8' + '@typescript-eslint/eslint-plugin': ^6.0.0 + eslint: ^8.0.0 peerDependenciesMeta: '@typescript-eslint/eslint-plugin': optional: true @@ -5682,8 +6182,24 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + eslint-visitor-keys@4.0.0: + resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@8.50.0: + resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + eslint@8.53.0: + resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true @@ -5692,9 +6208,9 @@ packages: resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} engines: {node: '>=6'} - esniff@2.0.1: - resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} - engines: {node: '>=0.10'} + espree@10.0.1: + resolution: {integrity: sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} @@ -5705,8 +6221,8 @@ packages: engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -5779,17 +6295,13 @@ packages: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - expect-type@1.1.0: - resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} - engines: {node: '>=12.0.0'} - - expo-asset@10.0.10: - resolution: {integrity: sha512-0qoTIihB79k+wGus9wy0JMKq7DdenziVx3iUkGvMAy2azscSgWH6bd2gJ9CGnhC6JRd3qTMFBL0ou/fx7WZl7A==} + expo-asset@10.0.6: + resolution: {integrity: sha512-waP73/ccn/HZNNcGM4/s3X3icKjSSbEQ9mwc6tX34oYNg+XE5WdwOuZ9wgVVFrU7wZMitq22lQXd2/O0db8bxg==} peerDependencies: expo: '*' - expo-constants@16.0.2: - resolution: {integrity: sha512-9tNY3OVO0jfiMzl7ngb6IOyR5VFzNoN5OOazUWoeGfmMqVB5kltTemRvKraK9JRbBKIw+SOYLEmF0sEqgFZ6OQ==} + expo-constants@16.0.1: + resolution: {integrity: sha512-s6aTHtglp926EsugWtxN7KnpSsE9FCEjb7CgEjQQ78Gpu4btj4wB+IXot2tlqNwqv+x7xFe5veoPGfJDGF/kVg==} peerDependencies: expo: '*' @@ -5798,8 +6310,8 @@ packages: peerDependencies: expo: '*' - expo-font@12.0.10: - resolution: {integrity: sha512-Q1i2NuYri3jy32zdnBaHHCya1wH1yMAsI+3CCmj9zlQzlhsS9Bdwcj2W3c5eU5FvH2hsNQy4O+O1NnM6o/pDaQ==} + expo-font@12.0.5: + resolution: {integrity: sha512-h/VkN4jlHYDJ6T6pPgOYTVoDEfBY0CTKQe4pxnPDGQiE6H+DFdDgk+qWVABGpRMH0+zXoHB+AEi3OoQjXIynFA==} peerDependencies: expo: '*' @@ -5808,27 +6320,24 @@ packages: peerDependencies: expo: '*' - expo-modules-autolinking@1.11.3: - resolution: {integrity: sha512-oYh8EZEvYF5TYppxEKUTTJmbr8j7eRRnrIxzZtMvxLTXoujThVPMFS/cbnSnf2bFm1lq50TdDNABhmEi7z0ngQ==} + expo-modules-autolinking@1.11.1: + resolution: {integrity: sha512-2dy3lTz76adOl7QUvbreMCrXyzUiF8lygI7iFJLjgIQIVH+43KnFWE5zBumpPbkiaq0f0uaFpN9U0RGQbnKiMw==} hasBin: true - expo-modules-core@1.12.26: - resolution: {integrity: sha512-y8yDWjOi+rQRdO+HY+LnUlz8qzHerUaw/LUjKPU/mX8PRXP4UUPEEp5fjAwBU44xjNmYSHWZDwet4IBBE+yQUA==} + expo-modules-core@1.12.11: + resolution: {integrity: sha512-CF5G6hZo/6uIUz6tj4dNRlvE5L4lakYukXPqz5ZHQ+6fLk1NQVZbRdpHjMkxO/QSBQcKUzG/ngeytpoJus7poQ==} expo-sqlite@14.0.6: resolution: {integrity: sha512-T3YNx7LT7lM4UQRgi8ml+cj0Wf3Ep09+B4CVaWtUCjdyYJIZjsHDT65hypKG+r6btTLLEd11hjlrstNQhzt5gQ==} peerDependencies: expo: '*' - expo@51.0.38: - resolution: {integrity: sha512-/B9npFkOPmv6WMIhdjQXEY0Z9k/67UZIVkodW8JxGIXwKUZAGHL+z1R5hTtWimpIrvVhyHUFU3f8uhfEKYhHNQ==} + expo@51.0.8: + resolution: {integrity: sha512-bdTOiMb1f3PChtuqEZ9czUm2gMTmS0r1+H+Pkm2O3PsuLnOgxfIBzL6S37+J4cUocLBaENrmx9SOGKpzhBqXpg==} hasBin: true - exponential-backoff@3.1.1: - resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} - - express@4.21.1: - resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==} + express@4.19.2: + resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} engines: {node: '>= 0.10.0'} ext@1.7.0: @@ -5840,6 +6349,10 @@ packages: fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -5850,12 +6363,16 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-xml-parser@4.4.1: - resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} + fast-xml-parser@4.2.5: + resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} + hasBin: true + + fast-xml-parser@4.4.0: + resolution: {integrity: sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==} hasBin: true - fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -5869,14 +6386,6 @@ packages: fbjs@3.0.5: resolution: {integrity: sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==} - fdir@6.4.2: - resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - fetch-blob@3.2.0: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} @@ -5906,8 +6415,8 @@ packages: resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} engines: {node: '>= 0.8'} - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + finalhandler@1.2.0: + resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} engines: {node: '>= 0.8'} find-cache-dir@2.1.0: @@ -5933,9 +6442,12 @@ packages: find-yarn-workspace-root@2.0.0: resolution: {integrity: sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@3.1.0: + resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==} + engines: {node: '>=12.0.0'} + + flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} @@ -5943,12 +6455,12 @@ packages: flow-enums-runtime@0.0.6: resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} - flow-parser@0.252.0: - resolution: {integrity: sha512-z8hKPUjZ33VLn4HVntifqmEhmolUMopysnMNzazoDqo1GLUkBsreLNsxETlKJMPotUWStQnen6SGvUNe1j4Hlg==} + flow-parser@0.236.0: + resolution: {integrity: sha512-0OEk9Gr+Yj7wjDW2KgaNYUypKau71jAfFyeLQF5iVtxqc6uJHag/MT7pmaEApf4qM7u86DkBcd4ualddYMfbLw==} engines: {node: '>=0.4.0'} - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -5962,16 +6474,16 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - foreground-child@3.3.0: - resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} - form-data@3.0.2: - resolution: {integrity: sha512-sJe+TQb2vIaIyO783qN6BlMYWMw3WBOHA1Ay2qxsnjuafEOQFJ2JakedOQirT6D5XPRxDvS7AHYyem9fTpb4LQ==} + form-data@3.0.1: + resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} engines: {node: '>= 6'} - form-data@4.0.1: - resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} formdata-polyfill@4.0.10: @@ -5996,8 +6508,8 @@ packages: fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs-extra@11.2.0: - resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + fs-extra@11.1.1: + resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} engines: {node: '>=14.14'} fs-extra@8.1.0: @@ -6028,9 +6540,16 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function.prototype.name@1.1.5: + resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + engines: {node: '>= 0.4'} + function.prototype.name@1.1.6: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} @@ -6038,8 +6557,8 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - fx@35.0.0: - resolution: {integrity: sha512-O07q+Lknrom5RUX/u53tjo2KTTLUnL0K703JbqMYb19ORijfJNvijzFqqYXEjdk25T9R14S6t6wHD8fCWXCM0g==} + fx@28.0.0: + resolution: {integrity: sha512-vKQDA9g868cZiW8ulgs2uN1yx1i7/nsS33jTMOxekk0Z03BJLffVcdW6AVD32fWb3E6RtmWWuBXBZOk8cLXFNQ==} hasBin: true gauge@4.0.4: @@ -6061,6 +6580,9 @@ packages: get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + get-intrinsic@1.2.1: + resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} + get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} @@ -6096,12 +6618,16 @@ packages: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} + get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + get-symbol-description@1.0.2: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} - get-tsconfig@4.8.1: - resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + get-tsconfig@4.7.5: + resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} getenv@1.0.0: resolution: {integrity: sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==} @@ -6124,10 +6650,20 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + glob@10.4.1: + resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==} + engines: {node: '>=16 || 14 >=14.18'} hasBin: true + glob@6.0.4: + resolution: {integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==} + deprecated: Glob versions prior to v9 are no longer supported + glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} deprecated: Glob versions prior to v9 are no longer supported @@ -6145,10 +6681,18 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + globals@13.22.0: + resolution: {integrity: sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==} engines: {node: '>=8'} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -6201,9 +6745,16 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-property-descriptors@1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + has-proto@1.0.3: resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} engines: {node: '>= 0.4'} @@ -6212,6 +6763,10 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} + has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} @@ -6219,6 +6774,10 @@ packages: has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -6229,20 +6788,18 @@ packages: hermes-estree@0.19.1: resolution: {integrity: sha512-daLGV3Q2MKk8w4evNMKwS8zBE/rcpA800nu1Q5kM08IKijoSnPe9Uo1iIxzPKRkn95IxxsgBMPeYHt3VG4ej2g==} - hermes-estree@0.23.1: - resolution: {integrity: sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==} - - hermes-estree@0.24.0: - resolution: {integrity: sha512-LyoXLB7IFzeZW0EvAbGZacbxBN7t6KKSDqFJPo3Ydow7wDlrDjXwsdiAHV6XOdvEN9MEuWXsSIFN4tzpyrXIHw==} + hermes-estree@0.20.1: + resolution: {integrity: sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==} hermes-parser@0.19.1: resolution: {integrity: sha512-Vp+bXzxYJWrpEuJ/vXxUsLnt0+y4q9zyi4zUlkLqD8FKv4LjIfOvP69R/9Lty3dCyKh0E2BU7Eypqr63/rKT/A==} - hermes-parser@0.23.1: - resolution: {integrity: sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==} + hermes-parser@0.20.1: + resolution: {integrity: sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==} - hermes-parser@0.24.0: - resolution: {integrity: sha512-IJooSvvu2qNRe7oo9Rb04sUT4omtZqZqf9uq9WM25Tb6v3usmvA93UqfnnoWs5V0uYjEl9Al6MNU10MCGKLwpg==} + hermes-profile-transformer@0.0.6: + resolution: {integrity: sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==} + engines: {node: '>=8'} highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} @@ -6251,9 +6808,9 @@ packages: resolution: {integrity: sha512-S9cREGPJIAK437RhroOf1PGlJPIlt5itl69OmQ6onPLo5pdCbSHGL8v4uAKxrdHjcTyuoyvKPqWm5jv0dGkdFA==} engines: {node: '>=16.0.0'} - hono@4.6.9: - resolution: {integrity: sha512-p/pN5yZLuZaHzyAOT2nw2/Ud6HhJHYmDNGH6Ck1OWBhPMVeM1r74jbCRwNi0gyFRjjbsGgoHbOyj7mT1PDNbTw==} - engines: {node: '>=16.9.0'} + hono@4.5.0: + resolution: {integrity: sha512-ZbezypZfn4odyApjCCv+Fw5OgweBqRLA/EsMyc4FUknFvBJcBIKhHy4sqmD1rWpBc/3wUlaQ6tqOPjk36R1ckg==} + engines: {node: '>=16.0.0'} hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -6307,8 +6864,12 @@ packages: resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} engines: {node: '>=10 <11 || >=12 <13 || >=14'} - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + + ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} image-size@1.1.1: @@ -6356,6 +6917,10 @@ packages: resolution: {integrity: sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==} engines: {node: '>=6'} + internal-slot@1.0.5: + resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} + engines: {node: '>= 0.4'} + internal-slot@1.0.7: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} @@ -6383,6 +6948,9 @@ packages: resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} engines: {node: '>=8'} + is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + is-array-buffer@3.0.4: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} @@ -6412,9 +6980,17 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.15.1: - resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} - engines: {node: '>= 0.4'} + is-core-module@2.11.0: + resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} + + is-core-module@2.12.1: + resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} + + is-core-module@2.13.0: + resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} + + is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} is-data-view@1.0.1: resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} @@ -6444,6 +7020,10 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -6460,6 +7040,10 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + is-invalid-path@0.1.0: resolution: {integrity: sha512-aZMG0T3F34mTg4eTdszcGXx54oiZ4NtHSft3hWNJMGJXUUqdIj3cOZuHcU0nCWWcY3jd7yRe/3AEm3vSNTpBGQ==} engines: {node: '>=0.10.0'} @@ -6467,6 +7051,10 @@ packages: is-lambda@1.0.1: resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} + is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} @@ -6508,6 +7096,9 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} + is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + is-shared-array-buffer@1.0.3: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} @@ -6532,10 +7123,18 @@ packages: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} + is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} + is-typed-array@1.1.13: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} @@ -6551,6 +7150,10 @@ packages: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} engines: {node: '>=12.13'} + is-wsl@1.1.0: + resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} + engines: {node: '>=4'} + is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -6568,19 +7171,13 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - - istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - - itty-time@1.0.6: - resolution: {integrity: sha512-+P8IZaLLBtFv8hCkIjcymZOp4UJ+xW6bSlQsXGqrkmJh7vSiMFSlNne0mCYagEE0N7HDNR5jJBRxwN0oYv61Rw==} + jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@3.1.2: + resolution: {integrity: sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==} + engines: {node: '>=14'} javascript-natural-sort@0.7.1: resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} @@ -6593,10 +7190,6 @@ packages: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-message-util@29.7.0: resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6605,10 +7198,6 @@ packages: resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-util@29.7.0: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6624,11 +7213,14 @@ packages: jimp-compact@0.16.1: resolution: {integrity: sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==} + joi@17.13.1: + resolution: {integrity: sha512-vaBlIKCyo4FCUtCm7Eu4QZd/q02bWcxfUO6YSXAZOWF6gzcLBeba8kwotUdYJjDLW8Cz8RywsSOqiNJZW0mNvg==} + join-component@1.1.0: resolution: {integrity: sha512-bF7vcQxbODoGK1imE2P9GS9aw4zD0Sd+Hni68IMZLj7zRnquH7dXUmMw9hDI5S/Jzt7q+IyTXN0rSg2GI0IKhQ==} - jose@4.15.9: - resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} + jose@4.15.5: + resolution: {integrity: sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==} jose@5.2.3: resolution: {integrity: sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA==} @@ -6742,8 +7334,8 @@ packages: resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==} engines: {node: '>=12.20'} - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyv@4.5.3: + resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==} kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} @@ -6797,8 +7389,12 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - libsql@0.4.7: - resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==} + libsql@0.3.19: + resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} + os: [darwin, linux, win32] + + libsql@0.4.1: + resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -6810,52 +7406,114 @@ packages: cpu: [arm64] os: [darwin] + lightningcss-darwin-arm64@1.25.1: + resolution: {integrity: sha512-G4Dcvv85bs5NLENcu/s1f7ehzE3D5ThnlWSDwE190tWXRQCQaqwcuHe+MGSVI/slm0XrxnaayXY+cNl3cSricw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-x64@1.19.0: resolution: {integrity: sha512-Lif1wD6P4poaw9c/4Uh2z+gmrWhw/HtXFoeZ3bEsv6Ia4tt8rOJBdkfVaUJ6VXmpKHALve+iTyP2+50xY1wKPw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + lightningcss-darwin-x64@1.25.1: + resolution: {integrity: sha512-dYWuCzzfqRueDSmto6YU5SoGHvZTMU1Em9xvhcdROpmtOQLorurUZz8+xFxZ51lCO2LnYbfdjZ/gCqWEkwixNg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.25.1: + resolution: {integrity: sha512-hXoy2s9A3KVNAIoKz+Fp6bNeY+h9c3tkcx1J3+pS48CqAt+5bI/R/YY4hxGL57fWAIquRjGKW50arltD6iRt/w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.19.0: resolution: {integrity: sha512-P15VXY5682mTXaiDtbnLYQflc8BYb774j2R84FgDLJTN6Qp0ZjWEFyN1SPqyfTj2B2TFjRHRUvQSSZ7qN4Weig==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + lightningcss-linux-arm-gnueabihf@1.25.1: + resolution: {integrity: sha512-tWyMgHFlHlp1e5iW3EpqvH5MvsgoN7ZkylBbG2R2LWxnvH3FuWCJOhtGcYx9Ks0Kv0eZOBud789odkYLhyf1ng==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm64-gnu@1.19.0: resolution: {integrity: sha512-zwXRjWqpev8wqO0sv0M1aM1PpjHz6RVIsBcxKszIG83Befuh4yNysjgHVplF9RTU7eozGe3Ts7r6we1+Qkqsww==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + lightningcss-linux-arm64-gnu@1.25.1: + resolution: {integrity: sha512-Xjxsx286OT9/XSnVLIsFEDyDipqe4BcLeB4pXQ/FEA5+2uWCCuAEarUNQumRucnj7k6ftkAHUEph5r821KBccQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + lightningcss-linux-arm64-musl@1.19.0: resolution: {integrity: sha512-vSCKO7SDnZaFN9zEloKSZM5/kC5gbzUjoJQ43BvUpyTFUX7ACs/mDfl2Eq6fdz2+uWhUh7vf92c4EaaP4udEtA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + lightningcss-linux-arm64-musl@1.25.1: + resolution: {integrity: sha512-IhxVFJoTW8wq6yLvxdPvyHv4NjzcpN1B7gjxrY3uaykQNXPHNIpChLB52+wfH+yS58zm1PL4LemUp8u9Cfp6Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + lightningcss-linux-x64-gnu@1.19.0: resolution: {integrity: sha512-0AFQKvVzXf9byrXUq9z0anMGLdZJS+XSDqidyijI5njIwj6MdbvX2UZK/c4FfNmeRa2N/8ngTffoIuOUit5eIQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + lightningcss-linux-x64-gnu@1.25.1: + resolution: {integrity: sha512-RXIaru79KrREPEd6WLXfKfIp4QzoppZvD3x7vuTKkDA64PwTzKJ2jaC43RZHRt8BmyIkRRlmywNhTRMbmkPYpA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + lightningcss-linux-x64-musl@1.19.0: resolution: {integrity: sha512-SJoM8CLPt6ECCgSuWe+g0qo8dqQYVcPiW2s19dxkmSI5+Uu1GIRzyKA0b7QqmEXolA+oSJhQqCmJpzjY4CuZAg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + lightningcss-linux-x64-musl@1.25.1: + resolution: {integrity: sha512-TdcNqFsAENEEFr8fJWg0Y4fZ/nwuqTRsIr7W7t2wmDUlA8eSXVepeeONYcb+gtTj1RaXn/WgNLB45SFkz+XBZA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + lightningcss-win32-x64-msvc@1.19.0: resolution: {integrity: sha512-C+VuUTeSUOAaBZZOPT7Etn/agx/MatzJzGRkeV+zEABmPuntv1zihncsi+AyGmjkkzq3wVedEy7h0/4S84mUtg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + lightningcss-win32-x64-msvc@1.25.1: + resolution: {integrity: sha512-9KZZkmmy9oGDSrnyHuxP6iMhbsgChUiu/NSgOx+U1I/wTngBStDf2i2aGRCHvFqj19HqqBEI4WuGVQBa2V6e0A==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss@1.19.0: resolution: {integrity: sha512-yV5UR7og+Og7lQC+70DA7a8ta1uiOPnWPJfxa0wnxylev5qfo4P+4iMpzWAdYWOca4jdNQZii+bDL/l+4hUXIA==} engines: {node: '>= 12.0.0'} + lightningcss@1.25.1: + resolution: {integrity: sha512-V0RMVZzK1+rCHpymRv4URK2lNhIRyO8g7U7zOFwVAhJuat74HtkjIQpQRKNCwFEYkRGpafOpmXXLoaoBcyVtBg==} + engines: {node: '>= 12.0.0'} + + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + lilconfig@3.1.2: resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} engines: {node: '>=14'} @@ -6910,6 +7568,14 @@ packages: resolution: {integrity: sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==} engines: {node: '>=4'} + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + logkitty@0.7.1: + resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==} + hasBin: true + long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} @@ -6923,8 +7589,9 @@ packages: loupe@3.1.2: resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@10.2.2: + resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} + engines: {node: 14 || >=16.14} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -6944,14 +7611,21 @@ packages: resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} engines: {node: '>=16.14'} + lru-cache@9.1.2: + resolution: {integrity: sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==} + engines: {node: 14 || >=16.14} + lru-queue@0.1.0: resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - magic-string@0.30.12: - resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} + magic-string@0.30.10: + resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + + magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} @@ -7027,9 +7701,8 @@ packages: memoize-one@5.2.1: resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} - memoizee@0.4.17: - resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==} - engines: {node: '>=0.12'} + memoizee@0.4.15: + resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} memory-cache@0.2.0: resolution: {integrity: sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==} @@ -7038,8 +7711,8 @@ packages: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-descriptors@1.0.1: + resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -7052,64 +7725,68 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - metro-babel-transformer@0.81.0: - resolution: {integrity: sha512-Dc0QWK4wZIeHnyZ3sevWGTnnSkIDDn/SWyfrn99zbKbDOCoCYy71PAn9uCRrP/hduKLJQOy+tebd63Rr9D8tXg==} - engines: {node: '>=18.18'} + metro-babel-transformer@0.80.9: + resolution: {integrity: sha512-d76BSm64KZam1nifRZlNJmtwIgAeZhZG3fi3K+EmPOlrR8rDtBxQHDSN3fSGeNB9CirdTyabTMQCkCup6BXFSQ==} + engines: {node: '>=18'} - metro-cache-key@0.81.0: - resolution: {integrity: sha512-qX/IwtknP9bQZL78OK9xeSvLM/xlGfrs6SlUGgHvrxtmGTRSsxcyqxR+c+7ch1xr05n62Gin/O44QKg5V70rNQ==} - engines: {node: '>=18.18'} + metro-cache-key@0.80.9: + resolution: {integrity: sha512-hRcYGhEiWIdM87hU0fBlcGr+tHDEAT+7LYNCW89p5JhErFt/QaAkVx4fb5bW3YtXGv5BTV7AspWPERoIb99CXg==} + engines: {node: '>=18'} - metro-cache@0.81.0: - resolution: {integrity: sha512-DyuqySicHXkHUDZFVJmh0ygxBSx6pCKUrTcSgb884oiscV/ROt1Vhye+x+OIHcsodyA10gzZtrVtxIFV4l9I4g==} - engines: {node: '>=18.18'} + metro-cache@0.80.9: + resolution: {integrity: sha512-ujEdSI43QwI+Dj2xuNax8LMo8UgKuXJEdxJkzGPU6iIx42nYa1byQ+aADv/iPh5sh5a//h5FopraW5voXSgm2w==} + engines: {node: '>=18'} - metro-config@0.81.0: - resolution: {integrity: sha512-6CinEaBe3WLpRlKlYXXu8r1UblJhbwD6Gtnoib5U8j6Pjp7XxMG9h/DGMeNp9aGLDu1OieUqiXpFo7O0/rR5Kg==} - engines: {node: '>=18.18'} + metro-config@0.80.9: + resolution: {integrity: sha512-28wW7CqS3eJrunRGnsibWldqgwRP9ywBEf7kg+uzUHkSFJNKPM1K3UNSngHmH0EZjomizqQA2Zi6/y6VdZMolg==} + engines: {node: '>=18'} - metro-core@0.81.0: - resolution: {integrity: sha512-CVkM5YCOAFkNMvJai6KzA0RpztzfEKRX62/PFMOJ9J7K0uq/UkOFLxcgpcncMIrfy0PbfEj811b69tjULUQe1Q==} - engines: {node: '>=18.18'} + metro-core@0.80.9: + resolution: {integrity: sha512-tbltWQn+XTdULkGdzHIxlxk4SdnKxttvQQV3wpqqFbHDteR4gwCyTR2RyYJvxgU7HELfHtrVbqgqAdlPByUSbg==} + engines: {node: '>=18'} - metro-file-map@0.81.0: - resolution: {integrity: sha512-zMDI5uYhQCyxbye/AuFx/pAbsz9K+vKL7h1ShUXdN2fz4VUPiyQYRsRqOoVG1DsiCgzd5B6LW0YW77NFpjDQeg==} - engines: {node: '>=18.18'} + metro-file-map@0.80.9: + resolution: {integrity: sha512-sBUjVtQMHagItJH/wGU9sn3k2u0nrCl0CdR4SFMO1tksXLKbkigyQx4cbpcyPVOAmGTVuy3jyvBlELaGCAhplQ==} + engines: {node: '>=18'} - metro-minify-terser@0.81.0: - resolution: {integrity: sha512-U2ramh3W822ZR1nfXgIk+emxsf5eZSg10GbQrT0ZizImK8IZ5BmJY+BHRIkQgHzWFpExOVxC7kWbGL1bZALswA==} - engines: {node: '>=18.18'} + metro-minify-terser@0.80.9: + resolution: {integrity: sha512-FEeCeFbkvvPuhjixZ1FYrXtO0araTpV6UbcnGgDUpH7s7eR5FG/PiJz3TsuuPP/HwCK19cZtQydcA2QrCw446A==} + engines: {node: '>=18'} - metro-resolver@0.81.0: - resolution: {integrity: sha512-Uu2Q+buHhm571cEwpPek8egMbdSTqmwT/5U7ZVNpK6Z2ElQBBCxd7HmFAslKXa7wgpTO2FAn6MqGeERbAtVDUA==} - engines: {node: '>=18.18'} + metro-resolver@0.80.9: + resolution: {integrity: sha512-wAPIjkN59BQN6gocVsAvvpZ1+LQkkqUaswlT++cJafE/e54GoVkMNCmrR4BsgQHr9DknZ5Um/nKueeN7kaEz9w==} + engines: {node: '>=18'} - metro-runtime@0.81.0: - resolution: {integrity: sha512-6oYB5HOt37RuGz2eV4A6yhcl+PUTwJYLDlY9vhT+aVjbUWI6MdBCf69vc4f5K5Vpt+yOkjy+2LDwLS0ykWFwYw==} - engines: {node: '>=18.18'} + metro-runtime@0.80.9: + resolution: {integrity: sha512-8PTVIgrVcyU+X/rVCy/9yxNlvXsBCk5JwwkbAm/Dm+Abo6NBGtNjWF0M1Xo/NWCb4phamNWcD7cHdR91HhbJvg==} + engines: {node: '>=18'} - metro-source-map@0.81.0: - resolution: {integrity: sha512-TzsVxhH83dyxg4A4+L1nzNO12I7ps5IHLjKGZH3Hrf549eiZivkdjYiq/S5lOB+p2HiQ+Ykcwtmcja95LIC62g==} - engines: {node: '>=18.18'} + metro-source-map@0.80.9: + resolution: {integrity: sha512-RMn+XS4VTJIwMPOUSj61xlxgBvPeY4G6s5uIn6kt6HB6A/k9ekhr65UkkDD7WzHYs3a9o869qU8tvOZvqeQzgw==} + engines: {node: '>=18'} - metro-symbolicate@0.81.0: - resolution: {integrity: sha512-C/1rWbNTPYp6yzID8IPuQPpVGzJ2rbWYBATxlvQ9dfK5lVNoxcwz77hjcY8ISLsRRR15hyd/zbjCNKPKeNgE1Q==} - engines: {node: '>=18.18'} + metro-symbolicate@0.80.9: + resolution: {integrity: sha512-Ykae12rdqSs98hg41RKEToojuIW85wNdmSe/eHUgMkzbvCFNVgcC0w3dKZEhSsqQOXapXRlLtHkaHLil0UD/EA==} + engines: {node: '>=18'} hasBin: true - metro-transform-plugins@0.81.0: - resolution: {integrity: sha512-uErLAPBvttGCrmGSCa0dNHlOTk3uJFVEVWa5WDg6tQ79PRmuYRwzUgLhVzn/9/kyr75eUX3QWXN79Jvu4txt6Q==} - engines: {node: '>=18.18'} + metro-transform-plugins@0.80.9: + resolution: {integrity: sha512-UlDk/uc8UdfLNJhPbF3tvwajyuuygBcyp+yBuS/q0z3QSuN/EbLllY3rK8OTD9n4h00qZ/qgxGv/lMFJkwP4vg==} + engines: {node: '>=18'} - metro-transform-worker@0.81.0: - resolution: {integrity: sha512-HrQ0twiruhKy0yA+9nK5bIe3WQXZcC66PXTvRIos61/EASLAP2DzEmW7IxN/MGsfZegN2UzqL2CG38+mOB45vg==} - engines: {node: '>=18.18'} + metro-transform-worker@0.80.9: + resolution: {integrity: sha512-c/IrzMUVnI0hSVVit4TXzt3A1GiUltGVlzCmLJWxNrBGHGrJhvgePj38+GXl1Xf4Fd4vx6qLUkKMQ3ux73bFLQ==} + engines: {node: '>=18'} - metro@0.81.0: - resolution: {integrity: sha512-kzdzmpL0gKhEthZ9aOV7sTqvg6NuTxDV8SIm9pf9sO8VVEbKrQk5DNcwupOUjgPPFAuKUc2NkT0suyT62hm2xg==} - engines: {node: '>=18.18'} + metro@0.80.9: + resolution: {integrity: sha512-Bc57Xf3GO2Xe4UWQsBj/oW6YfLPABEu8jfDVDiNmJvoQW4CO34oDPuYKe4KlXzXhcuNsqOtSxpbjCRRVjhhREg==} + engines: {node: '>=18'} hasBin: true + micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + engines: {node: '>=8.6'} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -7127,6 +7804,11 @@ packages: engines: {node: '>=4'} hasBin: true + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -7152,8 +7834,8 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - miniflare@3.20241022.0: - resolution: {integrity: sha512-x9Fbq1Hmz1f0osIT9Qmj78iX4UpCP2EqlZnA/tzj/3+I49vc3Kq0fNqSSKplcdf6HlCHdL3fOBicmreQF4BUUQ==} + miniflare@3.20240712.0: + resolution: {integrity: sha512-zVbsMX2phvJS1uTPmjK6CvVBq4ON2UkmvTw9IMfNPACsWJmHEdsBDxsYEG1vKAduJdI5gULLuJf7qpFxByDhGw==} engines: {node: '>=16.13'} hasBin: true @@ -7168,12 +7850,8 @@ packages: resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} engines: {node: '>=10'} - minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.4: + resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: @@ -7231,8 +7909,8 @@ packages: engines: {node: '>=10'} hasBin: true - mlly@1.7.2: - resolution: {integrity: sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==} + mlly@1.7.0: + resolution: {integrity: sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==} mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} @@ -7255,6 +7933,14 @@ packages: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true + mv@2.1.1: + resolution: {integrity: sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==} + engines: {node: '>=0.8.0'} + + mysql2@3.11.0: + resolution: {integrity: sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==} + engines: {node: '>= 8.0'} + mysql2@3.3.3: resolution: {integrity: sha512-MxDQJztArk4JFX1PKVjDhIXRzAmVJfuqZrVU+my6NeYBAA/XZRaDw5q7vga8TNvgyy3Lv3rivBFBBuJFbsdjaw==} engines: {node: '>= 8.0'} @@ -7266,8 +7952,8 @@ packages: resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} engines: {node: '>=12.0.0'} - nan@2.22.0: - resolution: {integrity: sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==} + nan@2.19.0: + resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} @@ -7280,14 +7966,14 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + ncp@2.0.0: + resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==} + hasBin: true + negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -7303,15 +7989,20 @@ packages: nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} - node-abi@3.71.0: - resolution: {integrity: sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==} + nocache@3.0.4: + resolution: {integrity: sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==} + engines: {node: '>=12.0.0'} + + node-abi@3.62.0: + resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==} engines: {node: '>=10'} node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-addon-api@7.1.0: + resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==} + engines: {node: ^16 || ^18 || >= 20} node-dir@0.1.17: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} @@ -7325,6 +8016,9 @@ packages: resolution: {integrity: sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==} engines: {node: '>=18'} + node-fetch-native@1.6.4: + resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -7346,8 +8040,8 @@ packages: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} - node-gyp-build@4.8.2: - resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==} + node-gyp-build@4.8.1: + resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} hasBin: true node-gyp@8.4.1: @@ -7358,8 +8052,12 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.18: - resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + + node-stream-zip@1.15.0: + resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} + engines: {node: '>=0.12.0'} nofilter@3.1.0: resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} @@ -7406,9 +8104,9 @@ packages: nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} - ob1@0.81.0: - resolution: {integrity: sha512-6Cvrkxt1tqaRdWqTAMcVYEiO5i1xcF9y7t06nFdjFqkfPsEloCf8WwhXdwBpNUkVYSQlSGS7cDgVQR86miBfBQ==} - engines: {node: '>=18.18'} + ob1@0.80.9: + resolution: {integrity: sha512-v9yOxowkZbxWhKOaaTyLjIm1aLy4ebMNcSn4NYJKOAI/Qv+SkfEfszpLr2GIxsccmb2Y2HA9qtsqiIJ80ucpVA==} + engines: {node: '>=18'} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} @@ -7418,36 +8116,38 @@ packages: resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} engines: {node: '>= 6'} - object-inspect@1.13.2: - resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} - engines: {node: '>= 0.4'} + object-inspect@1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + + object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + object.assign@4.1.5: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} - object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + object.fromentries@2.0.6: + resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} engines: {node: '>= 0.4'} - object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} + object.groupby@1.0.0: + resolution: {integrity: sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==} - object.values@1.2.0: - resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + object.values@1.1.6: + resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} engines: {node: '>= 0.4'} obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - ohash@1.1.4: - resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} - ohm-js@17.1.0: resolution: {integrity: sha512-xc3B5dgAjTBQGHaH7B58M2Pmv6WvzrJ/3/7LeUzXNg0/sY3jQPdSd/S2SstppaleO77rifR1tyhdfFGNIwxf2Q==} engines: {node: '>=0.12.1'} @@ -7464,6 +8164,10 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} + on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -7479,6 +8183,10 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + open@6.4.0: + resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==} + engines: {node: '>=8'} + open@7.4.2: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} @@ -7490,14 +8198,18 @@ packages: openid-client@5.6.4: resolution: {integrity: sha512-T1h3B10BRPKfcObdBklX639tVz+xh34O7GjofqrqiAQdm7eHsQ00ih18x6wuJ/E6FxdtS2u3FmUGPDeEcMwzNA==} - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} ora@3.4.0: resolution: {integrity: sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==} engines: {node: '>=6'} + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + os-homedir@1.0.2: resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} engines: {node: '>=0.10.0'} @@ -7594,9 +8306,6 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -7667,15 +8376,19 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-to-regexp@0.1.10: - resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + path-to-regexp@0.1.7: + resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} - path-to-regexp@6.3.0: - resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-to-regexp@6.2.2: + resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} @@ -7704,8 +8417,8 @@ packages: pg-connection-string@2.6.1: resolution: {integrity: sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==} - pg-connection-string@2.7.0: - resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==} + pg-connection-string@2.6.4: + resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} pg-connection-string@2.7.0: resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==} @@ -7718,8 +8431,8 @@ packages: resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} engines: {node: '>=4'} - pg-pool@3.7.0: - resolution: {integrity: sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==} + pg-pool@3.6.2: + resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==} peerDependencies: pg: '>=8.0' @@ -7742,8 +8455,8 @@ packages: resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} engines: {node: '>=10'} - pg@8.13.1: - resolution: {integrity: sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==} + pg@8.11.5: + resolution: {integrity: sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==} engines: {node: '>= 8.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -7763,8 +8476,11 @@ packages: pgpass@1.0.5: resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -7794,8 +8510,8 @@ packages: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} - pkg-types@1.2.1: - resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} + pkg-types@1.1.0: + resolution: {integrity: sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA==} plist@3.1.0: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} @@ -7817,8 +8533,8 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + postcss-load-config@4.0.1: + resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} engines: {node: '>= 14'} peerDependencies: postcss: '>=8.0.9' @@ -7847,8 +8563,12 @@ packages: yaml: optional: true - postcss@8.4.47: - resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} + postcss@8.4.38: + resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.4.39: + resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -7886,8 +8606,8 @@ packages: postgres-range@1.1.4: resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} - postgres@3.4.5: - resolution: {integrity: sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg==} + postgres@3.4.4: + resolution: {integrity: sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==} engines: {node: '>=12'} pouchdb-collections@1.0.1: @@ -7911,8 +8631,8 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.3.3: - resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + prettier@3.0.3: + resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} engines: {node: '>=14'} hasBin: true @@ -7920,9 +8640,9 @@ packages: resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} engines: {node: '>=6'} - pretty-format@24.9.0: - resolution: {integrity: sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==} - engines: {node: '>= 6'} + pretty-format@26.6.2: + resolution: {integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==} + engines: {node: '>= 10'} pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} @@ -7987,8 +8707,12 @@ packages: engines: {node: '>= 0.10'} hasBin: true - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + + punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} @@ -8001,10 +8725,15 @@ packages: resolution: {integrity: sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==} hasBin: true - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + qs@6.11.0: + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} + querystring@0.2.1: + resolution: {integrity: sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==} + engines: {node: '>=0.4.x'} + deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -8026,22 +8755,28 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - react-devtools-core@5.3.2: - resolution: {integrity: sha512-crr9HkVrDiJ0A4zot89oS0Cgv0Oa4OG1Em4jit3P3ZxZSKPMYyMjfwMqgcJna9o625g8oN87rBm8SWWrSTBZxg==} + react-devtools-core@5.2.0: + resolution: {integrity: sha512-vZK+/gvxxsieAoAyYaiRIVFxlajb7KXhgBDV7OsoMzaAE+IqGpoxusBjIgq5ibqA2IloKu0p9n7tE68z1xs18A==} react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-native@0.76.1: - resolution: {integrity: sha512-z4KnbrnnAvloRs9NGnah3u6/LK3IbtNMrvByxa3ifigbMlsMY4WPRYV9lvt/hH4Mzt8bfuI+utnOxFyJTTq3lg==} + react-native@0.74.1: + resolution: {integrity: sha512-0H2XpmghwOtfPpM2LKqHIN7gxy+7G/r1hwJHKLV6uoyXGC/gCojRtoo5NqyKrWpFC8cqyT6wTYCLuG7CxEKilg==} engines: {node: '>=18'} hasBin: true peerDependencies: '@types/react': ^18.2.6 - react: ^18.2.0 + react: 18.2.0 peerDependenciesMeta: '@types/react': optional: true @@ -8050,6 +8785,11 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} + react-shallow-renderer@16.15.0: + resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -8073,10 +8813,6 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - readdirp@4.0.2: - resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} - engines: {node: '>= 14.16.0'} - readline@1.3.0: resolution: {integrity: sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==} @@ -8095,8 +8831,8 @@ packages: redeyed@2.1.1: resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==} - regenerate-unicode-properties@10.2.0: - resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} + regenerate-unicode-properties@10.1.1: + resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} engines: {node: '>=4'} regenerate@1.4.2: @@ -8105,6 +8841,9 @@ packages: regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -8115,23 +8854,24 @@ packages: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true - regexp.prototype.flags@1.5.3: - resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + regexp.prototype.flags@1.5.0: + resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} engines: {node: '>= 0.4'} - regexpu-core@6.1.1: - resolution: {integrity: sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==} - engines: {node: '>=4'} + regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} - regjsgen@0.8.0: - resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + regexpu-core@5.3.2: + resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} + engines: {node: '>=4'} regjsparser@0.10.0: resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} hasBin: true - regjsparser@0.11.2: - resolution: {integrity: sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==} + regjsparser@0.9.1: + resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} hasBin: true remove-trailing-slash@0.1.1: @@ -8145,6 +8885,9 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + requireg@0.2.2: resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==} engines: {node: '>= 4.0.0'} @@ -8168,8 +8911,8 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve-tspaths@0.8.22: - resolution: {integrity: sha512-x9loBJyTLdx3grlcNpH/Y2t8IkfadtbzYhzpo683C6olazn0/4Y3cfSBiqDA0f2vSmq5tITKJCN9e1ezBh6jhA==} + resolve-tspaths@0.8.16: + resolution: {integrity: sha512-5c90plgcKFcCk66Ve1vFh6tm0fLKmSz6vaW4CezP6i69Q8fgWX3YGPYmKPEughem+nPHT1358P+rXrhw5pibwg==} hasBin: true peerDependencies: typescript: '>=3.0.3' @@ -8184,6 +8927,18 @@ packages: resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} engines: {node: '>=10'} + resolve@1.22.1: + resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + hasBin: true + + resolve@1.22.2: + resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} + hasBin: true + + resolve@1.22.4: + resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} + hasBin: true + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -8195,6 +8950,10 @@ packages: resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==} engines: {node: '>=4'} + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} @@ -8207,18 +8966,29 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rimraf@2.4.5: + resolution: {integrity: sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rimraf@3.0.2: + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rimraf@5.0.10: - resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} + rimraf@5.0.0: + resolution: {integrity: sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==} + engines: {node: '>=14'} hasBin: true rollup-plugin-inject@3.0.2: @@ -8231,8 +9001,8 @@ packages: rollup-pluginutils@2.8.2: resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - rollup@3.29.5: - resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==} + rollup@3.20.7: + resolution: {integrity: sha512-P7E2zezKSLhWnTz46XxjSmInrbOCiul1yf+kJccMxT56vxjHwCbDfoLbiqFgu+WQoo9ij2PkraYaBstgB2prBA==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true @@ -8261,6 +9031,10 @@ packages: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} + safe-array-concat@1.0.0: + resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==} + engines: {node: '>=0.4'} + safe-array-concat@1.1.2: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} @@ -8271,6 +9045,12 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-json-stringify@1.2.0: + resolution: {integrity: sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==} + + safe-regex-test@1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + safe-regex-test@1.0.3: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} @@ -8296,8 +9076,8 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + semver@7.6.2: + resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} engines: {node: '>=10'} hasBin: true @@ -8305,10 +9085,6 @@ packages: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - seq-queue@0.0.5: resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} @@ -8320,18 +9096,18 @@ packages: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serialize-javascript@6.0.1: + resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==} - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + serve-static@1.15.0: + resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} engines: {node: '>= 0.8.0'} set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-cookie-parser@2.7.1: - resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-cookie-parser@2.6.0: + resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} @@ -8370,6 +9146,9 @@ packages: shell-quote@1.8.1: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} @@ -8380,6 +9159,10 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.0.2: + resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} + engines: {node: '>=14'} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -8432,8 +9215,8 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - smob@1.5.0: - resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + smob@0.0.6: + resolution: {integrity: sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw==} smob@1.5.0: resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} @@ -8446,8 +9229,8 @@ packages: resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} source-map-support@0.5.21: @@ -8461,6 +9244,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} @@ -8475,14 +9262,14 @@ packages: spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + spdx-exceptions@2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - spdx-license-ids@3.0.20: - resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} + spdx-license-ids@3.0.13: + resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} split-ca@1.0.1: resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} @@ -8506,8 +9293,8 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - sql.js@1.12.0: - resolution: {integrity: sha512-Bi+43yMx/tUFZVYD4AUscmdL6NHn3gYQ+CM+YheFWLftOmrEC/Mz6Yh7E96Y2WDHYz3COSqT+LP6Z79zgrwJlA==} + sql.js@1.10.3: + resolution: {integrity: sha512-H46aWtQkdyjZwFQgraUruy5h/DyJBbAK3EA/WEMqiqF6PGPfKBSKBj/er3dVyYqVIoYfRf5TFM/loEjtQIrqJg==} sqlite3@5.1.7: resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==} @@ -8516,8 +9303,8 @@ packages: resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} engines: {node: '>= 0.6'} - ssh2@1.16.0: - resolution: {integrity: sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==} + ssh2@1.15.0: + resolution: {integrity: sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==} engines: {node: '>=10.16.0'} ssri@10.0.6: @@ -8528,42 +9315,8 @@ packages: resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} engines: {node: '>= 8'} - sst-darwin-arm64@3.3.5: - resolution: {integrity: sha512-kHQcmGhNMbIIhgz49Ejki6zp5TiCRwHaf+3c13GOzMrCIng2GixboGoNjMBFdSwXogQcJBc0BBOQo1oxmr4CxQ==} - cpu: [arm64] - os: [darwin] - - sst-darwin-x64@3.3.5: - resolution: {integrity: sha512-jouPGqUjlfMpwOyBzbYMMW/ezRlAqte4BnzASdPG7Cr23jX8Hl06yVFSzFAougfFA3vBnln6qCgLtNP/vDqCew==} - cpu: [x64] - os: [darwin] - - sst-linux-arm64@3.3.5: - resolution: {integrity: sha512-0fl7cR80bqScR1SS6iAAab4tjaT3M2dQCfjl0aTaBTeI+DmTD+SbteGcVwkQaXjcETuIUEKUAFd6F5EF0LewlA==} - cpu: [arm64] - os: [linux] - - sst-linux-x64@3.3.5: - resolution: {integrity: sha512-Et6DMlp8UGsUlToeMzWpEfRpxiYexMmnbfNd+usZMq7kC2or8Ze6ec3HR6Mm2pXjcwEZ6GUZRPWATWfqH7yNmw==} - cpu: [x64] - os: [linux] - - sst-linux-x86@3.3.5: - resolution: {integrity: sha512-ZjW1gkBbGRjCiCaZg+NBEeVwQ9/NFr5BjxLbwMX0zDwwDUim9W/PC89sHYZO9KnJX3D39+X8QC11vRnxpYQkNw==} - cpu: [x86] - os: [linux] - - sst@3.3.5: - resolution: {integrity: sha512-YqiDtvCFPfztusQbOU974R8WwGJNLs33X57NuVwUYCH9miMlw0Rz/hWMlwR9uMyQm7b6vc+Sf1kBPqy5iuPk6w==} - hasBin: true - peerDependencies: - hono: 4.x - valibot: 0.30.x - peerDependenciesMeta: - hono: - optional: true - valibot: - optional: true + sst@3.0.14: + resolution: {integrity: sha512-MC93uHwMxM1uwDg9Old8qo8LsmhvrMD3YFkS5Me8ThozwFIKzwqXicJWTE3iL+0DkPSPhdiSxafRdKhu/Qk5DA==} stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} @@ -8616,13 +9369,23 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string.prototype.trim@1.2.7: + resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} + engines: {node: '>= 0.4'} + string.prototype.trim@1.2.9: resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} + string.prototype.trimend@1.0.6: + resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} + string.prototype.trimend@1.0.8: resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + string.prototype.trimstart@1.0.6: + resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} + string.prototype.trimstart@1.0.8: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} @@ -8698,6 +9461,9 @@ packages: sudo-prompt@9.1.1: resolution: {integrity: sha512-es33J1g2HjMpyAhz8lOR+ICmXXAqTuKbuXuUWLhOLew20oN9oUCgCJx615U/v7aioZg7IX5lIh9x34vwneu4pA==} + sudo-prompt@9.2.1: + resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==} + superjson@2.2.1: resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} engines: {node: '>=16'} @@ -8722,8 +9488,8 @@ packages: resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} engines: {node: '>=8'} - supports-hyperlinks@3.1.0: - resolution: {integrity: sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==} + supports-hyperlinks@3.0.0: + resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} engines: {node: '>=14.18'} supports-hyperlinks@3.1.0: @@ -8734,8 +9500,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - synckit@0.9.2: - resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} + synckit@0.9.1: + resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} tar-fs@2.0.1: @@ -8784,14 +9550,15 @@ packages: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} engines: {node: '>=8'} - terser@5.36.0: - resolution: {integrity: sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==} + terser@5.17.1: + resolution: {integrity: sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==} engines: {node: '>=10'} hasBin: true - test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} + terser@5.31.0: + resolution: {integrity: sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==} + engines: {node: '>=10'} + hasBin: true text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -8823,9 +9590,8 @@ packages: resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} engines: {node: '>=4'} - timers-ext@0.1.8: - resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==} - engines: {node: '>=0.12'} + timers-ext@0.1.7: + resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==} tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -8833,15 +9599,14 @@ packages: tiny-queue@0.2.1: resolution: {integrity: sha512-EijGsv7kzd9I9g0ByCl6h42BWNGUZrlCSejfrb3AKeHC33SGbASu1VDf5O3rRiiUOhAC9CHdZxFPbZu0HmR70A==} + tinybench@2.8.0: + resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.1: - resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} - - tinyglobby@0.2.10: - resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} - engines: {node: '>=12.0.0'} + tinyexec@0.3.0: + resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} tinypool@0.8.4: resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} @@ -8892,8 +9657,8 @@ packages: tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - traverse@0.6.10: - resolution: {integrity: sha512-hN4uFRxbK+PX56DxYiGHsTn2dME3TVr9vbNqlQGcGcPhJAn+tdP126iA+TArMpI4YSgnTkMWyoLl5bf81Hi5TA==} + traverse@0.6.9: + resolution: {integrity: sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg==} engines: {node: '>= 0.4'} tree-kill@1.2.2: @@ -8904,12 +9669,14 @@ packages: resolution: {integrity: sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==} engines: {node: '>=0.6'} - trim-right@1.0.1: - resolution: {integrity: sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==} - engines: {node: '>=0.10.0'} + ts-api-utils@1.0.3: + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' - ts-api-utils@1.4.0: - resolution: {integrity: sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==} + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' @@ -8934,8 +9701,8 @@ packages: '@swc/wasm': optional: true - tsconfck@3.1.4: - resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} + tsconfck@3.0.3: + resolution: {integrity: sha512-4t0noZX9t6GcPTfBAbIbbIU4pfpCwh0ueq3S4O/5qXI1VwK1outmxhe9dOiEWqMz3MW2LKgDTpqWV+37IWuVbA==} engines: {node: ^18 || >=20} hasBin: true peerDependencies: @@ -8944,14 +9711,14 @@ packages: typescript: optional: true - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tsconfig-paths@3.14.2: + resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -8963,7 +9730,7 @@ packages: peerDependencies: '@swc/core': ^1 postcss: ^8.4.12 - typescript: '>=4.5.0' + typescript: '>=4.1.0' peerDependenciesMeta: '@swc/core': optional: true @@ -8972,8 +9739,8 @@ packages: typescript: optional: true - tsup@8.3.5: - resolution: {integrity: sha512-Tunf6r6m6tnZsG9GYWndg0z8dEV7fD733VBFzFJ5Vcm1FtlXB8xBD/rtrBi2a3YKEV7hHtxiZtW5EAVADoe1pA==} + tsup@8.1.2: + resolution: {integrity: sha512-Gzw/PXSX/z0aYMNmkcI54bKKFVFJQbLne+EqTJZeQ3lNT3QpumjtMU4rl+ZwTTp8oRF3ahMbEAxT2sZPJLFSrg==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -9001,8 +9768,13 @@ packages: resolution: {integrity: sha512-xHtFaKtHxM9LOklMmJdI3BEnQq/D5F73Of2E1GDrITi9sgoVkvIsrQUTY1G8FlmGtA+awCI4EBlTRRYxkL2sRg==} hasBin: true - tsx@4.19.2: - resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} + tsx@4.10.5: + resolution: {integrity: sha512-twDSbf7Gtea4I2copqovUiNTEDrT8XNFXsuHpfGbdpW/z9ZW4fTghzzhAG0WfrCuJmJiOEY1nLIjq4u3oujRWQ==} + engines: {node: '>=18.0.0'} + hasBin: true + + tsx@4.16.2: + resolution: {integrity: sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==} engines: {node: '>=18.0.0'} hasBin: true @@ -9059,10 +9831,6 @@ packages: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} - type-detect@4.1.0: - resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} - engines: {node: '>=4'} - type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} @@ -9095,25 +9863,47 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} + type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - type@2.7.3: - resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} + type@1.2.0: + resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} + + type@2.7.2: + resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} + + typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.1: resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} engines: {node: '>= 0.4'} + typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + typed-array-byte-offset@1.0.2: resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} engines: {node: '>= 0.4'} + typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + typed-array-length@1.0.6: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} @@ -9122,13 +9912,13 @@ packages: resolution: {integrity: sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A==} engines: {node: '>= 0.4'} - typescript@5.3.3: - resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} + typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} engines: {node: '>=14.17'} hasBin: true - typescript@5.6.1-rc: - resolution: {integrity: sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ==} + typescript@5.3.3: + resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} hasBin: true @@ -9142,12 +9932,11 @@ packages: engines: {node: '>=14.17'} hasBin: true - ua-parser-js@1.0.39: - resolution: {integrity: sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw==} - hasBin: true + ua-parser-js@1.0.38: + resolution: {integrity: sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==} - ufo@1.5.4: - resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + ufo@1.5.3: + resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -9162,11 +9951,11 @@ packages: resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} engines: {node: '>=14.0'} - unenv-nightly@2.0.0-20241024-111401-d4156ac: - resolution: {integrity: sha512-xJO1hfY+Te+/XnfCYrCbFbRcgu6XEODND1s5wnVbaBCkuQX7JXF7fHEXPrukFE2j8EOH848P8QN19VO47XN8hw==} + unenv-nightly@1.10.0-1717606461.a117952: + resolution: {integrity: sha512-u3TfBX02WzbHTpaEfWEKwDijDSFAHcgXkayUZ+MVDrjhLFvgAJzFGTSTmwlEhwWi2exyRQey23ah9wELMM6etg==} - unicode-canonical-property-names-ecmascript@2.0.1: - resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + unicode-canonical-property-names-ecmascript@2.0.0: + resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} engines: {node: '>=4'} unicode-emoji-modifier-base@1.0.0: @@ -9177,8 +9966,8 @@ packages: resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} engines: {node: '>=4'} - unicode-match-property-value-ecmascript@2.2.0: - resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} + unicode-match-property-value-ecmascript@2.1.0: + resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} engines: {node: '>=4'} unicode-property-aliases-ecmascript@2.1.0: @@ -9219,6 +10008,10 @@ packages: resolution: {integrity: sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==} engines: {node: '>= 10.0.0'} + universalify@2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -9227,8 +10020,8 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - update-browserslist-db@1.1.1: - resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + update-browserslist-db@1.0.16: + resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -9293,8 +10086,8 @@ packages: resolution: {integrity: sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - validate-npm-package-name@5.0.1: - resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} + validate-npm-package-name@5.0.0: + resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} vary@1.1.2: @@ -9306,8 +10099,8 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite-node@2.1.4: - resolution: {integrity: sha512-kqa9v+oi4HwkG6g8ufRnb5AeplcRw8jUF6/7/Qz1qRQOXHImG8YnLbB+LLszENwFnoBl9xIf9nVdCFzNd7GQEg==} + vite-node@2.1.2: + resolution: {integrity: sha512-HPcGNN5g/7I2OtPjLqgOtCRu/qhVvBxTUD3qzitmL0SrG1cWFzxzhMDWussxSbrRYWqnKf8P2jiNhPMSN+ymsQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -9319,8 +10112,8 @@ packages: vite: optional: true - vite@5.4.10: - resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} + vite@5.2.12: + resolution: {integrity: sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -9328,7 +10121,6 @@ packages: less: '*' lightningcss: ^1.21.0 sass: '*' - sass-embedded: '*' stylus: '*' sugarss: '*' terser: ^5.4.0 @@ -9341,7 +10133,33 @@ packages: optional: true sass: optional: true - sass-embedded: + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vite@5.3.3: + resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: optional: true stylus: optional: true @@ -9375,15 +10193,15 @@ packages: jsdom: optional: true - vitest@2.1.4: - resolution: {integrity: sha512-eDjxbVAJw1UJJCHr5xr/xM86Zx+YxIEXGAR+bmnEID7z9qWfoxpHw0zdobz+TQAFOLT+nEXz3+gx6nUJ7RgmlQ==} + vitest@2.1.2: + resolution: {integrity: sha512-veNjLizOMkRrJ6xxb+pvxN6/QAWg95mzcRjtmkepXdN87FNfxAss9RKe2far/G9cQpipfgP2taqg0KiWsquj8A==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.1.4 - '@vitest/ui': 2.1.4 + '@vitest/browser': 2.1.2 + '@vitest/ui': 2.1.2 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -9409,8 +10227,8 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + web-streams-polyfill@3.2.1: + resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} engines: {node: '>= 8'} webidl-conversions@3.0.1: @@ -9447,6 +10265,13 @@ packages: which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which-typed-array@1.1.11: + resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} + engines: {node: '>= 0.4'} + which-typed-array@1.1.15: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} @@ -9465,6 +10290,11 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} hasBin: true + why-is-node-running@2.2.2: + resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} + engines: {node: '>=8'} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -9476,28 +10306,28 @@ packages: wonka@4.0.15: resolution: {integrity: sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==} - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - workerd@1.20241022.0: - resolution: {integrity: sha512-jyGXsgO9DRcJyx6Ovv7gUyDPc3UYC2i/E0p9GFUg6GUzpldw4Y93y9kOmdfsOnKZ3+lY53veSiUniiBPE6Q2NQ==} + workerd@1.20240712.0: + resolution: {integrity: sha512-hdIHZif82hBDy9YnMtcmDGgbLU5f2P2aGpi/X8EKhTSLDppVUGrkY3XB536J4jGjA2D5dS0FUEXCl5bAJEed8Q==} engines: {node: '>=16'} hasBin: true - wrangler@3.85.0: - resolution: {integrity: sha512-r5YCWUaF4ApLnloNE6jHHgRYdFzYHoajTlC1tns42UzQ2Ls63VAqD3b0cxOqzDUfmlSb3skpmu0B0Ssi3QWPAg==} + wrangler@3.65.0: + resolution: {integrity: sha512-IDy4ttyJZssazAd5CXHw4NWeZFGxngdNF5m2ogltdT3CV7uHfCvPVdMcr4uNMpRZd0toHmAE3LtQeXxDFFp88A==} engines: {node: '>=16.17.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20241022.0 + '@cloudflare/workers-types': ^4.20240712.0 peerDependenciesMeta: '@cloudflare/workers-types': optional: true + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -9512,16 +10342,12 @@ packages: write-file-atomic@2.4.3: resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} - write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - write-file-atomic@5.0.1: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - ws@6.2.3: - resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} + ws@6.2.2: + resolution: {integrity: sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==} peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -9531,8 +10357,8 @@ packages: utf-8-validate: optional: true - ws@7.5.10: - resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 @@ -9555,6 +10381,18 @@ packages: utf-8-validate: optional: true + ws@8.17.0: + resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -9594,6 +10432,9 @@ packages: xxhash-wasm@1.0.2: resolution: {integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -9604,11 +10445,19 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yaml@2.6.0: - resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==} + yaml@2.3.1: + resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} + engines: {node: '>= 14'} + + yaml@2.4.2: + resolution: {integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==} engines: {node: '>= 14'} hasBin: true + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -9617,6 +10466,10 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} @@ -9633,24 +10486,21 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-queue@1.1.1: - resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==} + yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} - youch@3.3.4: - resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} + youch@3.3.3: + resolution: {integrity: sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==} - zod-validation-error@2.1.0: - resolution: {integrity: sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.18.0 + zod@3.21.4: + resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} - zod@3.23.8: - resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + zod@3.23.7: + resolution: {integrity: sha512-NBeIoqbtOiUMomACV/y+V3Qfs9+Okr18vR5c/5pHClPpufWOrsx8TENboDPe265lFdfewX2yBtNTLPvnmCxwog==} - zx@7.2.3: - resolution: {integrity: sha512-QODu38nLlYXg/B/Gw7ZKiZrvPkEsjPN3LQ5JFXM7h0JvwhEdPNNl+4Ao1y4+o3CLNiDUNcwzQYZ4/Ko7kKzCMA==} + zx@7.2.2: + resolution: {integrity: sha512-50Gjicd6ijTt7Zcz5fNX+rHrmE0uVqC+X6lYKhf2Cu8wIxDpNIzXwTmzchNdW+JY3LFsRcU43B1lHE4HBMmKgQ==} engines: {node: '>= 16.0.0'} hasBin: true @@ -9661,7 +10511,7 @@ packages: snapshots: -snapshots: + '@aashutoshrathi/word-wrap@1.2.6': {} '@ampproject/remapping@2.3.0': dependencies: @@ -9674,21 +10524,11 @@ snapshots: dependencies: '@arethetypeswrong/core': 0.15.1 chalk: 4.1.2 - cli-table3: 0.6.5 + cli-table3: 0.6.3 commander: 10.0.1 marked: 9.1.6 marked-terminal: 6.2.0(marked@9.1.6) - semver: 7.6.3 - - '@arethetypeswrong/cli@0.16.4': - dependencies: - '@arethetypeswrong/core': 0.16.4 - chalk: 4.1.2 - cli-table3: 0.6.5 - commander: 10.0.1 - marked: 9.1.6 - marked-terminal: 7.2.1(marked@9.1.6) - semver: 7.6.3 + semver: 7.6.2 '@arethetypeswrong/cli@0.16.4': dependencies: @@ -9704,10 +10544,10 @@ snapshots: dependencies: '@andrewbranch/untar.js': 1.0.3 fflate: 0.8.2 - semver: 7.6.3 + semver: 7.6.2 ts-expose-internals-conditionally: 1.0.0-empty.0 typescript: 5.3.3 - validate-npm-package-name: 5.0.1 + validate-npm-package-name: 5.0.0 '@arethetypeswrong/core@0.16.4': dependencies: @@ -9721,95 +10561,52 @@ snapshots: '@ava/typescript@5.0.0': dependencies: - '@andrewbranch/untar.js': 1.0.3 - cjs-module-lexer: 1.4.1 - fflate: 0.8.2 - lru-cache: 10.4.3 - semver: 7.6.3 - typescript: 5.6.1-rc - validate-npm-package-name: 5.0.1 + escape-string-regexp: 5.0.0 + execa: 8.0.1 + optional: true - '@aws-crypto/sha256-browser@5.2.0': + '@aws-crypto/crc32@3.0.0': dependencies: - '@aws-crypto/sha256-js': 5.2.0 - '@aws-crypto/supports-web-crypto': 5.2.0 - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.686.0 - '@aws-sdk/util-locate-window': 3.679.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.577.0 + tslib: 1.14.1 - '@aws-crypto/sha256-js@5.2.0': + '@aws-crypto/ie11-detection@3.0.0': dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.686.0 - tslib: 2.8.1 + tslib: 1.14.1 - '@aws-crypto/supports-web-crypto@5.2.0': + '@aws-crypto/sha256-browser@3.0.0': dependencies: - tslib: 2.8.1 + '@aws-crypto/ie11-detection': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-crypto/supports-web-crypto': 3.0.0 + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-locate-window': 3.568.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 - '@aws-crypto/util@5.2.0': + '@aws-crypto/sha256-js@3.0.0': dependencies: - '@aws-sdk/types': 3.686.0 - '@smithy/util-utf8': 2.3.0 - '@smithy/util-waiter': 2.2.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.577.0 + tslib: 1.14.1 - '@aws-sdk/client-cognito-identity@3.687.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.687.0(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/client-sts': 3.687.0 - '@aws-sdk/core': 3.686.0 - '@aws-sdk/credential-provider-node': 3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0) - '@aws-sdk/middleware-host-header': 3.686.0 - '@aws-sdk/middleware-logger': 3.686.0 - '@aws-sdk/middleware-recursion-detection': 3.686.0 - '@aws-sdk/middleware-user-agent': 3.687.0 - '@aws-sdk/region-config-resolver': 3.686.0 - '@aws-sdk/types': 3.686.0 - '@aws-sdk/util-endpoints': 3.686.0 - '@aws-sdk/util-user-agent-browser': 3.686.0 - '@aws-sdk/util-user-agent-node': 3.687.0 - '@smithy/config-resolver': 3.0.10 - '@smithy/core': 2.5.1 - '@smithy/fetch-http-handler': 4.0.0 - '@smithy/hash-node': 3.0.8 - '@smithy/invalid-dependency': 3.0.8 - '@smithy/middleware-content-length': 3.0.10 - '@smithy/middleware-endpoint': 3.2.1 - '@smithy/middleware-retry': 3.0.25 - '@smithy/middleware-serde': 3.0.8 - '@smithy/middleware-stack': 3.0.8 - '@smithy/node-config-provider': 3.1.9 - '@smithy/node-http-handler': 3.2.5 - '@smithy/protocol-http': 4.1.5 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 - '@smithy/url-parser': 3.0.8 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.25 - '@smithy/util-defaults-mode-node': 3.0.25 - '@smithy/util-endpoints': 2.1.4 - '@smithy/util-middleware': 3.0.8 - '@smithy/util-retry': 3.0.8 - '@smithy/util-utf8': 3.0.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt + '@aws-crypto/supports-web-crypto@3.0.0': + dependencies: + tslib: 1.14.1 + + '@aws-crypto/util@3.0.0': + dependencies: + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 - '@aws-sdk/client-rds-data@3.687.0': + '@aws-sdk/client-cognito-identity@3.569.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.569.0 '@aws-sdk/client-sts': 3.569.0 '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) @@ -9851,60 +10648,17 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0 - '@aws-sdk/core': 3.582.0 - '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.583.0 - '@aws-sdk/region-config-resolver': 3.577.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.583.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.1 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.1 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.25 - '@smithy/util-defaults-mode-node': 3.0.25 - '@smithy/util-endpoints': 2.1.4 - '@smithy/util-middleware': 3.0.8 - '@smithy/util-retry': 3.0.8 - '@smithy/util-utf8': 3.0.0 - tslib: 2.8.1 - transitivePeerDependencies: - - '@aws-sdk/client-sts' - - aws-crt - - '@aws-sdk/client-sso@3.478.0': + '@aws-sdk/client-lambda@3.478.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.478.0 '@aws-sdk/core': 3.477.0 + '@aws-sdk/credential-provider-node': 3.478.0 '@aws-sdk/middleware-host-header': 3.468.0 '@aws-sdk/middleware-logger': 3.468.0 '@aws-sdk/middleware-recursion-detection': 3.468.0 + '@aws-sdk/middleware-signing': 3.468.0 '@aws-sdk/middleware-user-agent': 3.478.0 '@aws-sdk/region-config-resolver': 3.470.0 '@aws-sdk/types': 3.468.0 @@ -9913,6 +10667,9 @@ snapshots: '@aws-sdk/util-user-agent-node': 3.470.0 '@smithy/config-resolver': 2.2.0 '@smithy/core': 1.4.2 + '@smithy/eventstream-serde-browser': 2.2.0 + '@smithy/eventstream-serde-config-resolver': 2.2.0 + '@smithy/eventstream-serde-node': 2.2.0 '@smithy/fetch-http-handler': 2.5.0 '@smithy/hash-node': 2.2.0 '@smithy/invalid-dependency': 2.2.0 @@ -9934,32 +10691,212 @@ snapshots: '@smithy/util-defaults-mode-node': 2.3.1 '@smithy/util-endpoints': 1.2.0 '@smithy/util-retry': 2.2.0 + '@smithy/util-stream': 2.2.0 '@smithy/util-utf8': 2.3.0 + '@smithy/util-waiter': 2.2.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)': + '@aws-sdk/client-rds-data@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 + '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/core': 3.582.0 + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/middleware-host-header': 3.577.0 + '@aws-sdk/middleware-logger': 3.577.0 + '@aws-sdk/middleware-recursion-detection': 3.577.0 + '@aws-sdk/middleware-user-agent': 3.583.0 + '@aws-sdk/region-config-resolver': 3.577.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-endpoints': 3.583.0 + '@aws-sdk/util-user-agent-browser': 3.577.0 + '@aws-sdk/util-user-agent-node': 3.577.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 + '@smithy/fetch-http-handler': 3.0.1 + '@smithy/hash-node': 3.0.0 + '@smithy/invalid-dependency': 3.0.0 + '@smithy/middleware-content-length': 3.0.0 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 + '@smithy/middleware-serde': 3.0.0 + '@smithy/middleware-stack': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/node-http-handler': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + '@smithy/url-parser': 3.0.0 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 + '@smithy/util-middleware': 3.0.0 + '@smithy/util-retry': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso-oidc@3.569.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/core': 3.567.0 + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) + '@aws-sdk/middleware-host-header': 3.567.0 + '@aws-sdk/middleware-logger': 3.568.0 + '@aws-sdk/middleware-recursion-detection': 3.567.0 + '@aws-sdk/middleware-user-agent': 3.567.0 + '@aws-sdk/region-config-resolver': 3.567.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@aws-sdk/util-user-agent-browser': 3.567.0 + '@aws-sdk/util-user-agent-node': 3.568.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso-oidc@3.583.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/core': 3.582.0 + '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/middleware-host-header': 3.577.0 + '@aws-sdk/middleware-logger': 3.577.0 + '@aws-sdk/middleware-recursion-detection': 3.577.0 + '@aws-sdk/middleware-user-agent': 3.583.0 + '@aws-sdk/region-config-resolver': 3.577.0 + '@aws-sdk/types': 3.577.0 + '@aws-sdk/util-endpoints': 3.583.0 + '@aws-sdk/util-user-agent-browser': 3.577.0 + '@aws-sdk/util-user-agent-node': 3.577.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 + '@smithy/fetch-http-handler': 3.0.1 + '@smithy/hash-node': 3.0.0 + '@smithy/invalid-dependency': 3.0.0 + '@smithy/middleware-content-length': 3.0.0 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 + '@smithy/middleware-serde': 3.0.0 + '@smithy/middleware-stack': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/node-http-handler': 3.0.0 + '@smithy/protocol-http': 4.0.0 + '@smithy/smithy-client': 3.0.1 + '@smithy/types': 3.0.0 + '@smithy/url-parser': 3.0.0 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 + '@smithy/util-middleware': 3.0.0 + '@smithy/util-retry': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso@3.478.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/core': 3.477.0 + '@aws-sdk/middleware-host-header': 3.468.0 + '@aws-sdk/middleware-logger': 3.468.0 + '@aws-sdk/middleware-recursion-detection': 3.468.0 + '@aws-sdk/middleware-user-agent': 3.478.0 + '@aws-sdk/region-config-resolver': 3.470.0 + '@aws-sdk/types': 3.468.0 + '@aws-sdk/util-endpoints': 3.478.0 + '@aws-sdk/util-user-agent-browser': 3.468.0 + '@aws-sdk/util-user-agent-node': 3.470.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-endpoints': 1.2.0 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso@3.568.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/core': 3.567.0 + '@aws-sdk/middleware-host-header': 3.567.0 + '@aws-sdk/middleware-logger': 3.568.0 + '@aws-sdk/middleware-recursion-detection': 3.567.0 + '@aws-sdk/middleware-user-agent': 3.567.0 + '@aws-sdk/region-config-resolver': 3.567.0 + '@aws-sdk/types': 3.567.0 + '@aws-sdk/util-endpoints': 3.567.0 + '@aws-sdk/util-user-agent-browser': 3.567.0 + '@aws-sdk/util-user-agent-node': 3.568.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/core': 1.4.2 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 '@smithy/middleware-retry': 2.3.1 '@smithy/middleware-serde': 2.3.0 '@smithy/middleware-stack': 2.2.0 @@ -10015,17 +10952,17 @@ snapshots: '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.25 - '@smithy/util-defaults-mode-node': 3.0.25 - '@smithy/util-endpoints': 2.1.4 - '@smithy/util-middleware': 3.0.8 - '@smithy/util-retry': 3.0.8 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 + '@smithy/util-middleware': 3.0.0 + '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso@3.687.0': + '@aws-sdk/client-sts@3.478.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 @@ -10161,11 +11098,11 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0': + '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10196,17 +11133,18 @@ snapshots: '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.25 - '@smithy/util-defaults-mode-node': 3.0.25 - '@smithy/util-endpoints': 2.1.4 - '@smithy/util-middleware': 3.0.8 - '@smithy/util-retry': 3.0.8 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 + '@smithy/util-middleware': 3.0.0 + '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.687.0': + '@aws-sdk/core@3.477.0': dependencies: '@smithy/core': 1.4.2 '@smithy/protocol-http': 3.3.0 @@ -10245,14 +11183,14 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.686.0': + '@aws-sdk/credential-provider-env@3.468.0': dependencies: '@aws-sdk/types': 3.468.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-cognito-identity@3.687.0': + '@aws-sdk/credential-provider-env@3.568.0': dependencies: '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 @@ -10305,7 +11243,7 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-env@3.686.0': + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/credential-provider-env': 3.568.0 @@ -10322,7 +11260,7 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-node@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))(@aws-sdk/client-sts@3.687.0)': + '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/credential-provider-env': 3.568.0 @@ -10358,7 +11296,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -10408,7 +11346,7 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-process@3.686.0': + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 @@ -10427,7 +11365,7 @@ snapshots: - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-sso@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))': + '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-http': 3.568.0 @@ -10514,7 +11452,7 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-web-identity@3.686.0(@aws-sdk/client-sts@3.687.0)': + '@aws-sdk/credential-provider-sso@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-sso': 3.568.0 '@aws-sdk/token-providers': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -10527,7 +11465,7 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/middleware-host-header@3.686.0': + '@aws-sdk/credential-provider-sso@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-sdk/client-sso': 3.583.0 '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -10540,14 +11478,14 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/middleware-logger@3.686.0': + '@aws-sdk/credential-provider-web-identity@3.468.0': dependencies: '@aws-sdk/types': 3.468.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.686.0': + '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/types': 3.567.0 @@ -10555,7 +11493,7 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.687.0': + '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/client-sts': 3.569.0 '@aws-sdk/types': 3.567.0 @@ -10563,9 +11501,9 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.8.1 - '@aws-sdk/region-config-resolver@3.686.0': + '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -10713,7 +11651,7 @@ snapshots: '@smithy/util-middleware': 3.0.0 tslib: 2.8.1 - '@aws-sdk/token-providers@3.686.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))': + '@aws-sdk/token-providers@3.478.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 @@ -10755,7 +11693,7 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/types@3.686.0': + '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)': dependencies: '@aws-sdk/client-sso-oidc': 3.569.0 '@aws-sdk/types': 3.567.0 @@ -10764,25 +11702,25 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.686.0': + '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 tslib: 2.8.1 - '@aws-sdk/util-locate-window@3.679.0': + '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.686.0': + '@aws-sdk/types@3.468.0': dependencies: '@smithy/types': 2.12.0 tslib: 2.8.1 @@ -10828,7 +11766,7 @@ snapshots: bowser: 2.11.0 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.687.0': + '@aws-sdk/util-user-agent-browser@3.567.0': dependencies: '@aws-sdk/types': 3.567.0 '@smithy/types': 2.12.0 @@ -10869,28 +11807,37 @@ snapshots: '@babel/code-frame@7.10.4': dependencies: - '@babel/highlight': 7.25.9 + '@babel/highlight': 7.24.6 - '@babel/code-frame@7.26.2': + '@babel/code-frame@7.22.10': dependencies: - '@babel/helper-validator-identifier': 7.25.9 - js-tokens: 4.0.0 - picocolors: 1.1.1 + '@babel/highlight': 7.22.10 + chalk: 2.4.2 + + '@babel/code-frame@7.22.13': + dependencies: + '@babel/highlight': 7.22.20 + chalk: 2.4.2 + + '@babel/code-frame@7.24.6': + dependencies: + '@babel/highlight': 7.24.6 + picocolors: 1.0.1 - '@babel/compat-data@7.26.2': {} + '@babel/compat-data@7.24.6': {} - '@babel/core@7.26.0': + '@babel/core@7.24.6': dependencies: '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.2 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helpers': 7.26.0 - '@babel/parser': 7.26.2 - '@babel/template': 7.25.9 - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 + '@babel/code-frame': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helpers': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/template': 7.24.6 + '@babel/traverse': 7.24.6 + '@babel/types': 7.24.6 convert-source-map: 2.0.0 debug: 4.3.7 gensync: 1.0.0-beta.2 @@ -10905,953 +11852,926 @@ snapshots: jsesc: 2.5.2 source-map: 0.5.7 - '@babel/generator@7.2.0': - dependencies: - '@babel/types': 7.26.0 - jsesc: 2.5.2 - lodash: 4.17.21 - source-map: 0.5.7 - trim-right: 1.0.1 - - '@babel/generator@7.26.2': + '@babel/generator@7.24.6': dependencies: - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 + '@babel/types': 7.24.6 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - jsesc: 3.0.2 + jsesc: 2.5.2 - '@babel/helper-annotate-as-pure@7.25.9': + '@babel/helper-annotate-as-pure@7.24.6': dependencies: - '@babel/types': 7.26.0 + '@babel/types': 7.24.6 - '@babel/helper-builder-binary-assignment-operator-visitor@7.25.9': + '@babel/helper-builder-binary-assignment-operator-visitor@7.24.6': dependencies: - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@babel/types': 7.24.6 - '@babel/helper-compilation-targets@7.25.9': + '@babel/helper-compilation-targets@7.24.6': dependencies: - '@babel/compat-data': 7.26.2 - '@babel/helper-validator-option': 7.25.9 - browserslist: 4.24.2 + '@babel/compat-data': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + browserslist: 4.23.0 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-member-expression-to-functions': 7.25.9 - '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/traverse': 7.25.9 + '@babel/helper-create-class-features-plugin@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-member-expression-to-functions': 7.24.6 + '@babel/helper-optimise-call-expression': 7.24.6 + '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/helper-split-export-declaration': 7.24.6 semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/helper-create-regexp-features-plugin@7.25.9(@babel/core@7.26.0)': + '@babel/helper-create-regexp-features-plugin@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - regexpu-core: 6.1.1 + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + regexpu-core: 5.3.2 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.26.0)': + '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 debug: 4.3.7 lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: - supports-color - '@babel/helper-environment-visitor@7.24.7': + '@babel/helper-environment-visitor@7.22.5': {} + + '@babel/helper-environment-visitor@7.24.6': {} + + '@babel/helper-function-name@7.22.5': dependencies: - '@babel/types': 7.26.0 + '@babel/template': 7.22.5 + '@babel/types': 7.22.10 - '@babel/helper-function-name@7.24.7': + '@babel/helper-function-name@7.24.6': dependencies: - '@babel/template': 7.25.9 - '@babel/types': 7.26.0 + '@babel/template': 7.24.6 + '@babel/types': 7.24.6 - '@babel/helper-hoist-variables@7.24.7': + '@babel/helper-hoist-variables@7.22.5': dependencies: - '@babel/types': 7.26.0 + '@babel/types': 7.23.6 - '@babel/helper-member-expression-to-functions@7.25.9': + '@babel/helper-hoist-variables@7.24.6': dependencies: - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@babel/types': 7.24.6 - '@babel/helper-module-imports@7.25.9': + '@babel/helper-member-expression-to-functions@7.24.6': dependencies: - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@babel/types': 7.24.6 - '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': + '@babel/helper-module-imports@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/types': 7.24.6 + + '@babel/helper-module-transforms@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-module-imports': 7.24.6 + '@babel/helper-simple-access': 7.24.6 + '@babel/helper-split-export-declaration': 7.24.6 + '@babel/helper-validator-identifier': 7.24.6 - '@babel/helper-optimise-call-expression@7.25.9': + '@babel/helper-optimise-call-expression@7.24.6': dependencies: - '@babel/types': 7.26.0 + '@babel/types': 7.24.6 - '@babel/helper-plugin-utils@7.25.9': {} + '@babel/helper-plugin-utils@7.24.6': {} - '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.0)': + '@babel/helper-remap-async-to-generator@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-wrap-function': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-wrap-function': 7.24.6 - '@babel/helper-replace-supers@7.25.9(@babel/core@7.26.0)': + '@babel/helper-replace-supers@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-member-expression-to-functions': 7.25.9 - '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-member-expression-to-functions': 7.24.6 + '@babel/helper-optimise-call-expression': 7.24.6 - '@babel/helper-simple-access@7.25.9': + '@babel/helper-simple-access@7.24.6': dependencies: - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@babel/types': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + '@babel/helper-skip-transparent-expression-wrappers@7.24.6': dependencies: - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@babel/types': 7.24.6 + + '@babel/helper-split-export-declaration@7.22.6': + dependencies: + '@babel/types': 7.23.6 - '@babel/helper-split-export-declaration@7.24.7': + '@babel/helper-split-export-declaration@7.24.6': dependencies: - '@babel/types': 7.26.0 + '@babel/types': 7.24.6 + + '@babel/helper-string-parser@7.22.5': {} - '@babel/helper-string-parser@7.25.9': {} + '@babel/helper-string-parser@7.23.4': {} - '@babel/helper-validator-identifier@7.25.9': {} + '@babel/helper-string-parser@7.24.6': {} - '@babel/helper-validator-option@7.25.9': {} + '@babel/helper-validator-identifier@7.22.20': {} - '@babel/helper-wrap-function@7.25.9': + '@babel/helper-validator-identifier@7.22.5': {} + + '@babel/helper-validator-identifier@7.24.6': {} + + '@babel/helper-validator-option@7.24.6': {} + + '@babel/helper-wrap-function@7.24.6': dependencies: - '@babel/template': 7.25.9 - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@babel/helper-function-name': 7.24.6 + '@babel/template': 7.24.6 + '@babel/types': 7.24.6 - '@babel/helpers@7.26.0': + '@babel/helpers@7.24.6': dependencies: - '@babel/template': 7.25.9 - '@babel/types': 7.26.0 + '@babel/template': 7.24.6 + '@babel/types': 7.24.6 - '@babel/highlight@7.25.9': + '@babel/highlight@7.22.10': dependencies: - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.22.5 chalk: 2.4.2 js-tokens: 4.0.0 - picocolors: 1.1.1 - '@babel/parser@7.26.2': + '@babel/highlight@7.22.20': dependencies: - '@babel/types': 7.26.0 + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.0)': + '@babel/highlight@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/helper-validator-identifier': 7.24.6 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9(@babel/core@7.26.0)': + '@babel/parser@7.22.10': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/types': 7.17.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9(@babel/core@7.26.0)': + '@babel/parser@7.24.6': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/types': 7.24.6 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.26.0)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/plugin-transform-optional-chaining': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.26.0)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-proposal-decorators@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) - '@babel/plugin-proposal-export-default-from@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.26.0)': + '@babel/plugin-proposal-decorators@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-decorators': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.26.0)': + '@babel/plugin-proposal-export-default-from@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-export-default-from': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.26.0)': + '@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) - '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.26.0)': + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.24.6)': dependencies: - '@babel/compat-data': 7.26.2 - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.26.0)': + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) - '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.26.0)': + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/compat-data': 7.24.6 + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0)': + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0)': + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.0)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.26.0)': + '@babel/plugin-syntax-decorators@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-export-default-from@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.0)': + '@babel/plugin-syntax-export-default-from@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-import-assertions@7.26.0(@babel/core@7.26.0)': + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)': + '@babel/plugin-syntax-flow@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)': + '@babel/plugin-syntax-import-assertions@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0)': + '@babel/plugin-syntax-import-attributes@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0)': + '@babel/plugin-syntax-jsx@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.0)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.26.0)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-typescript@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-async-generator-functions@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-arrow-functions@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-block-scoped-functions@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-async-generator-functions@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) - '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-async-to-generator@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-module-imports': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-block-scoped-functions@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-class-static-block@7.26.0(@babel/core@7.26.0)': + '@babel/plugin-transform-block-scoping@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-classes@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-class-properties@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) - '@babel/traverse': 7.25.9 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-class-static-block@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/template': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.6) - '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-classes@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) + '@babel/helper-split-export-declaration': 7.24.6 + globals: 11.12.0 - '@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-computed-properties@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/template': 7.24.6 - '@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-destructuring@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-dotall-regex@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-duplicate-keys@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-exponentiation-operator@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-dynamic-import@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-exponentiation-operator@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-flow-strip-types@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-export-namespace-from@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-for-of@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-flow-strip-types@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-flow': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-for-of@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 - '@babel/plugin-transform-json-strings@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-function-name@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-literals@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-json-strings@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-literals@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-member-expression-literals@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-logical-assignment-operators@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) - '@babel/plugin-transform-modules-amd@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-member-expression-literals@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-modules-commonjs@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-modules-amd@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-simple-access': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-modules-systemjs@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-modules-commonjs@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-simple-access': 7.24.6 - '@babel/plugin-transform-modules-umd@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-modules-systemjs@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-hoist-variables': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-validator-identifier': 7.24.6 - '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-modules-umd@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-new-target@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-named-capturing-groups-regex@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-nullish-coalescing-operator@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-new-target@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-nullish-coalescing-operator@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-numeric-separator@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) - '@babel/plugin-transform-object-super@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-object-rest-spread@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-object-super@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-optional-catch-binding@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-optional-chaining@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) - '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-parameters@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-private-methods@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-property-literals@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-private-property-in-object@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.6) - '@babel/plugin-transform-react-display-name@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-property-literals@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-react-jsx-development@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-react-display-name@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-react-jsx-development@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/plugin-transform-react-jsx': 7.24.6(@babel/core@7.24.6) - '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-react-jsx-self@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-react-jsx-source@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-react-pure-annotations@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-react-jsx@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-module-imports': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) + '@babel/types': 7.24.6 - '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-react-pure-annotations@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - regenerator-transform: 0.15.2 + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-regexp-modifiers@7.26.0(@babel/core@7.26.0)': + '@babel/plugin-transform-regenerator@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + regenerator-transform: 0.15.2 - '@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-reserved-words@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 - '@babel/plugin-transform-runtime@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-runtime@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.26.0) - babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) - babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-module-imports': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.6) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.6) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.6) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-spread@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-template-literals@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-typeof-symbol@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-typescript@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-unicode-escapes@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/preset-env@7.26.0(@babel/core@7.26.0)': - dependencies: - '@babel/compat-data': 7.26.2 - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0) - '@babel/plugin-syntax-import-assertions': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-generator-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-block-scoped-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-class-static-block': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-dotall-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-duplicate-keys': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-dynamic-import': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-exponentiation-operator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-json-strings': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-member-expression-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-amd': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-systemjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-umd': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-new-target': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-super': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-property-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-regexp-modifiers': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-transform-reserved-words': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-template-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-typeof-symbol': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-escapes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-property-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-sets-regex': 7.25.9(@babel/core@7.26.0) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.26.0) - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.26.0) - babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) - babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.26.0) - core-js-compat: 3.39.0 + '@babel/plugin-transform-shorthand-properties@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-spread@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + + '@babel/plugin-transform-sticky-regex@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-template-literals@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-typeof-symbol@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-typescript@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + '@babel/plugin-syntax-typescript': 7.24.6(@babel/core@7.24.6) + + '@babel/plugin-transform-unicode-escapes@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-unicode-property-regex@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-unicode-regex@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-transform-unicode-sets-regex@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.6) + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/preset-env@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/compat-data': 7.24.6 + '@babel/core': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.6) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.6) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-import-assertions': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-import-attributes': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-transform-arrow-functions': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-async-generator-functions': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-async-to-generator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-block-scoped-functions': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-block-scoping': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-class-properties': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-class-static-block': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-classes': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-computed-properties': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-destructuring': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-dotall-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-duplicate-keys': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-dynamic-import': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-exponentiation-operator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-export-namespace-from': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-for-of': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-function-name': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-json-strings': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-literals': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-logical-assignment-operators': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-member-expression-literals': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-amd': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-systemjs': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-umd': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-named-capturing-groups-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-new-target': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-numeric-separator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-object-rest-spread': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-object-super': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-optional-catch-binding': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-optional-chaining': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-private-methods': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-private-property-in-object': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-property-literals': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-regenerator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-reserved-words': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-shorthand-properties': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-spread': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-sticky-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-template-literals': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-typeof-symbol': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-escapes': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-property-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-sets-regex': 7.24.6(@babel/core@7.24.6) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.6) + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.6) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.6) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.6) + core-js-compat: 3.37.1 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-flow@7.25.9(@babel/core@7.26.0)': + '@babel/preset-flow@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + '@babel/plugin-transform-flow-strip-types': 7.24.6(@babel/core@7.24.6) - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.26.0)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/types': 7.26.0 + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/types': 7.24.6 esutils: 2.0.3 - '@babel/preset-react@7.25.9(@babel/core@7.26.0)': + '@babel/preset-react@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-development': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-pure-annotations': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + '@babel/plugin-transform-react-display-name': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-jsx': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-jsx-development': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-pure-annotations': 7.24.6(@babel/core@7.24.6) - '@babel/preset-typescript@7.26.0(@babel/core@7.26.0)': + '@babel/preset-typescript@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-typescript': 7.24.6(@babel/core@7.24.6) - '@babel/register@7.25.9(@babel/core@7.26.0)': + '@babel/register@7.24.6(@babel/core@7.24.6)': dependencies: - '@babel/core': 7.26.0 + '@babel/core': 7.24.6 clone-deep: 4.0.1 find-cache-dir: 2.1.0 make-dir: 2.1.0 pirates: 4.0.6 source-map-support: 0.5.21 - '@babel/runtime@7.26.0': + '@babel/regjsgen@0.8.0': {} + + '@babel/runtime@7.22.10': + dependencies: + regenerator-runtime: 0.14.0 + + '@babel/runtime@7.24.6': dependencies: regenerator-runtime: 0.14.1 - '@babel/template@7.25.9': + '@babel/template@7.22.5': dependencies: - '@babel/code-frame': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 + '@babel/code-frame': 7.22.10 + '@babel/parser': 7.22.10 + '@babel/types': 7.22.10 - '@babel/traverse@7.23.2': + '@babel/template@7.24.6': dependencies: - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.2 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-function-name': 7.24.7 - '@babel/helper-hoist-variables': 7.24.7 - '@babel/helper-split-export-declaration': 7.24.7 - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - debug: 4.3.7 + '@babel/code-frame': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + + '@babel/traverse@7.17.3': + dependencies: + '@babel/code-frame': 7.22.10 + '@babel/generator': 7.17.7 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-function-name': 7.22.5 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.22.10 + '@babel/types': 7.17.0 + debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/traverse@7.25.9': + '@babel/traverse@7.24.6': dependencies: - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/template': 7.25.9 - '@babel/types': 7.26.0 + '@babel/code-frame': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-hoist-variables': 7.24.6 + '@babel/helper-split-export-declaration': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: @@ -11859,13 +12779,26 @@ snapshots: '@babel/types@7.17.0': dependencies: - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.22.5 + to-fast-properties: 2.0.0 + + '@babel/types@7.22.10': + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.5 to-fast-properties: 2.0.0 - '@babel/types@7.26.0': + '@babel/types@7.23.6': dependencies: - '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + + '@babel/types@7.24.6': + dependencies: + '@babel/helper-string-parser': 7.24.6 + '@babel/helper-validator-identifier': 7.24.6 + to-fast-properties: 2.0.0 '@balena/dockerignore@1.0.2': {} @@ -11873,27 +12806,26 @@ snapshots: dependencies: mime: 3.0.0 - '@cloudflare/workerd-darwin-64@1.20241022.0': + '@cloudflare/workerd-darwin-64@1.20240712.0': optional: true - '@cloudflare/workerd-darwin-arm64@1.20241022.0': + '@cloudflare/workerd-darwin-arm64@1.20240712.0': optional: true - '@cloudflare/workerd-linux-64@1.20241022.0': + '@cloudflare/workerd-linux-64@1.20240712.0': optional: true - '@cloudflare/workerd-linux-arm64@1.20241022.0': + '@cloudflare/workerd-linux-arm64@1.20240712.0': optional: true - '@cloudflare/workerd-windows-64@1.20241022.0': + '@cloudflare/workerd-windows-64@1.20240712.0': optional: true - '@cloudflare/workers-shared@0.7.0': - dependencies: - mime: 3.0.0 - zod: 3.23.8 + '@cloudflare/workers-types@4.20240512.0': {} - '@cloudflare/workers-types@4.20241106.0': {} + '@cloudflare/workers-types@4.20240524.0': {} + + '@cloudflare/workers-types@4.20241004.0': {} '@colors/colors@1.5.0': optional: true @@ -11929,15 +12861,15 @@ snapshots: '@electric-sql/pglite@0.2.12': {} - '@esbuild-kit/core-utils@3.3.2': + '@esbuild-kit/core-utils@3.1.0': dependencies: - esbuild: 0.18.20 + esbuild: 0.17.19 source-map-support: 0.5.21 - '@esbuild-kit/esm-loader@2.6.5': + '@esbuild-kit/esm-loader@2.5.5': dependencies: - '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.8.1 + '@esbuild-kit/core-utils': 3.1.0 + get-tsconfig: 4.7.5 '@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19)': dependencies: @@ -11952,13 +12884,13 @@ snapshots: '@esbuild/aix-ppc64@0.19.12': optional: true - '@esbuild/aix-ppc64@0.21.5': + '@esbuild/aix-ppc64@0.20.2': optional: true - '@esbuild/aix-ppc64@0.23.1': + '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/aix-ppc64@0.24.0': + '@esbuild/aix-ppc64@0.23.0': optional: true '@esbuild/android-arm64@0.17.19': @@ -11970,13 +12902,13 @@ snapshots: '@esbuild/android-arm64@0.19.12': optional: true - '@esbuild/android-arm64@0.21.5': + '@esbuild/android-arm64@0.20.2': optional: true - '@esbuild/android-arm64@0.23.1': + '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/android-arm64@0.24.0': + '@esbuild/android-arm64@0.23.0': optional: true '@esbuild/android-arm@0.17.19': @@ -11988,13 +12920,13 @@ snapshots: '@esbuild/android-arm@0.19.12': optional: true - '@esbuild/android-arm@0.21.5': + '@esbuild/android-arm@0.20.2': optional: true - '@esbuild/android-arm@0.23.1': + '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/android-arm@0.24.0': + '@esbuild/android-arm@0.23.0': optional: true '@esbuild/android-x64@0.17.19': @@ -12006,13 +12938,13 @@ snapshots: '@esbuild/android-x64@0.19.12': optional: true - '@esbuild/android-x64@0.21.5': + '@esbuild/android-x64@0.20.2': optional: true - '@esbuild/android-x64@0.23.1': + '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/android-x64@0.24.0': + '@esbuild/android-x64@0.23.0': optional: true '@esbuild/darwin-arm64@0.17.19': @@ -12024,13 +12956,13 @@ snapshots: '@esbuild/darwin-arm64@0.19.12': optional: true - '@esbuild/darwin-arm64@0.21.5': + '@esbuild/darwin-arm64@0.20.2': optional: true - '@esbuild/darwin-arm64@0.23.1': + '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/darwin-arm64@0.24.0': + '@esbuild/darwin-arm64@0.23.0': optional: true '@esbuild/darwin-x64@0.17.19': @@ -12042,13 +12974,13 @@ snapshots: '@esbuild/darwin-x64@0.19.12': optional: true - '@esbuild/darwin-x64@0.21.5': + '@esbuild/darwin-x64@0.20.2': optional: true - '@esbuild/darwin-x64@0.23.1': + '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/darwin-x64@0.24.0': + '@esbuild/darwin-x64@0.23.0': optional: true '@esbuild/freebsd-arm64@0.17.19': @@ -12060,13 +12992,13 @@ snapshots: '@esbuild/freebsd-arm64@0.19.12': optional: true - '@esbuild/freebsd-arm64@0.21.5': + '@esbuild/freebsd-arm64@0.20.2': optional: true - '@esbuild/freebsd-arm64@0.23.1': + '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/freebsd-arm64@0.24.0': + '@esbuild/freebsd-arm64@0.23.0': optional: true '@esbuild/freebsd-x64@0.17.19': @@ -12078,13 +13010,13 @@ snapshots: '@esbuild/freebsd-x64@0.19.12': optional: true - '@esbuild/freebsd-x64@0.21.5': + '@esbuild/freebsd-x64@0.20.2': optional: true - '@esbuild/freebsd-x64@0.23.1': + '@esbuild/freebsd-x64@0.21.5': optional: true - '@esbuild/freebsd-x64@0.24.0': + '@esbuild/freebsd-x64@0.23.0': optional: true '@esbuild/linux-arm64@0.17.19': @@ -12096,13 +13028,13 @@ snapshots: '@esbuild/linux-arm64@0.19.12': optional: true - '@esbuild/linux-arm64@0.21.5': + '@esbuild/linux-arm64@0.20.2': optional: true - '@esbuild/linux-arm64@0.23.1': + '@esbuild/linux-arm64@0.21.5': optional: true - '@esbuild/linux-arm64@0.24.0': + '@esbuild/linux-arm64@0.23.0': optional: true '@esbuild/linux-arm@0.17.19': @@ -12114,13 +13046,13 @@ snapshots: '@esbuild/linux-arm@0.19.12': optional: true - '@esbuild/linux-arm@0.21.5': + '@esbuild/linux-arm@0.20.2': optional: true - '@esbuild/linux-arm@0.23.1': + '@esbuild/linux-arm@0.21.5': optional: true - '@esbuild/linux-arm@0.24.0': + '@esbuild/linux-arm@0.23.0': optional: true '@esbuild/linux-ia32@0.17.19': @@ -12132,13 +13064,13 @@ snapshots: '@esbuild/linux-ia32@0.19.12': optional: true - '@esbuild/linux-ia32@0.21.5': + '@esbuild/linux-ia32@0.20.2': optional: true - '@esbuild/linux-ia32@0.23.1': + '@esbuild/linux-ia32@0.21.5': optional: true - '@esbuild/linux-ia32@0.24.0': + '@esbuild/linux-ia32@0.23.0': optional: true '@esbuild/linux-loong64@0.14.54': @@ -12153,13 +13085,13 @@ snapshots: '@esbuild/linux-loong64@0.19.12': optional: true - '@esbuild/linux-loong64@0.21.5': + '@esbuild/linux-loong64@0.20.2': optional: true - '@esbuild/linux-loong64@0.23.1': + '@esbuild/linux-loong64@0.21.5': optional: true - '@esbuild/linux-loong64@0.24.0': + '@esbuild/linux-loong64@0.23.0': optional: true '@esbuild/linux-mips64el@0.17.19': @@ -12171,13 +13103,13 @@ snapshots: '@esbuild/linux-mips64el@0.19.12': optional: true - '@esbuild/linux-mips64el@0.21.5': + '@esbuild/linux-mips64el@0.20.2': optional: true - '@esbuild/linux-mips64el@0.23.1': + '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/linux-mips64el@0.24.0': + '@esbuild/linux-mips64el@0.23.0': optional: true '@esbuild/linux-ppc64@0.17.19': @@ -12189,13 +13121,13 @@ snapshots: '@esbuild/linux-ppc64@0.19.12': optional: true - '@esbuild/linux-ppc64@0.21.5': + '@esbuild/linux-ppc64@0.20.2': optional: true - '@esbuild/linux-ppc64@0.23.1': + '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.24.0': + '@esbuild/linux-ppc64@0.23.0': optional: true '@esbuild/linux-riscv64@0.17.19': @@ -12207,13 +13139,13 @@ snapshots: '@esbuild/linux-riscv64@0.19.12': optional: true - '@esbuild/linux-riscv64@0.21.5': + '@esbuild/linux-riscv64@0.20.2': optional: true - '@esbuild/linux-riscv64@0.23.1': + '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.24.0': + '@esbuild/linux-riscv64@0.23.0': optional: true '@esbuild/linux-s390x@0.17.19': @@ -12225,13 +13157,13 @@ snapshots: '@esbuild/linux-s390x@0.19.12': optional: true - '@esbuild/linux-s390x@0.21.5': + '@esbuild/linux-s390x@0.20.2': optional: true - '@esbuild/linux-s390x@0.23.1': + '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/linux-s390x@0.24.0': + '@esbuild/linux-s390x@0.23.0': optional: true '@esbuild/linux-x64@0.17.19': @@ -12243,13 +13175,13 @@ snapshots: '@esbuild/linux-x64@0.19.12': optional: true - '@esbuild/linux-x64@0.21.5': + '@esbuild/linux-x64@0.20.2': optional: true - '@esbuild/linux-x64@0.23.1': + '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/linux-x64@0.24.0': + '@esbuild/linux-x64@0.23.0': optional: true '@esbuild/netbsd-x64@0.17.19': @@ -12261,19 +13193,16 @@ snapshots: '@esbuild/netbsd-x64@0.19.12': optional: true - '@esbuild/netbsd-x64@0.21.5': - optional: true - - '@esbuild/netbsd-x64@0.23.1': + '@esbuild/netbsd-x64@0.20.2': optional: true - '@esbuild/netbsd-x64@0.24.0': + '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-arm64@0.23.1': + '@esbuild/netbsd-x64@0.23.0': optional: true - '@esbuild/openbsd-arm64@0.24.0': + '@esbuild/openbsd-arm64@0.23.0': optional: true '@esbuild/openbsd-x64@0.17.19': @@ -12285,13 +13214,13 @@ snapshots: '@esbuild/openbsd-x64@0.19.12': optional: true - '@esbuild/openbsd-x64@0.21.5': + '@esbuild/openbsd-x64@0.20.2': optional: true - '@esbuild/openbsd-x64@0.23.1': + '@esbuild/openbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-x64@0.24.0': + '@esbuild/openbsd-x64@0.23.0': optional: true '@esbuild/sunos-x64@0.17.19': @@ -12303,13 +13232,13 @@ snapshots: '@esbuild/sunos-x64@0.19.12': optional: true - '@esbuild/sunos-x64@0.21.5': + '@esbuild/sunos-x64@0.20.2': optional: true - '@esbuild/sunos-x64@0.23.1': + '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/sunos-x64@0.24.0': + '@esbuild/sunos-x64@0.23.0': optional: true '@esbuild/win32-arm64@0.17.19': @@ -12321,13 +13250,13 @@ snapshots: '@esbuild/win32-arm64@0.19.12': optional: true - '@esbuild/win32-arm64@0.21.5': + '@esbuild/win32-arm64@0.20.2': optional: true - '@esbuild/win32-arm64@0.23.1': + '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-arm64@0.24.0': + '@esbuild/win32-arm64@0.23.0': optional: true '@esbuild/win32-ia32@0.17.19': @@ -12339,13 +13268,13 @@ snapshots: '@esbuild/win32-ia32@0.19.12': optional: true - '@esbuild/win32-ia32@0.21.5': + '@esbuild/win32-ia32@0.20.2': optional: true - '@esbuild/win32-ia32@0.23.1': + '@esbuild/win32-ia32@0.21.5': optional: true - '@esbuild/win32-ia32@0.24.0': + '@esbuild/win32-ia32@0.23.0': optional: true '@esbuild/win32-x64@0.17.19': @@ -12357,29 +13286,83 @@ snapshots: '@esbuild/win32-x64@0.19.12': optional: true - '@esbuild/win32-x64@0.21.5': + '@esbuild/win32-x64@0.20.2': optional: true - '@esbuild/win32-x64@0.23.1': + '@esbuild/win32-x64@0.21.5': optional: true - '@esbuild/win32-x64@0.24.0': + '@esbuild/win32-x64@0.23.0': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)': + '@eslint-community/eslint-utils@4.4.0(eslint@8.50.0)': + dependencies: + eslint: 8.50.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/eslint-utils@4.4.0(eslint@8.53.0)': + dependencies: + eslint: 8.53.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': dependencies: - eslint: 8.57.1 + eslint: 8.57.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.12.1': {} + '@eslint-community/regexpp@4.11.0': {} + + '@eslint-community/regexpp@4.9.0': {} + + '@eslint/eslintrc@2.1.2': + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.22.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/eslintrc@2.1.3': + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.22.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.7 + debug: 4.3.4 espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 + globals: 13.22.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/eslintrc@3.1.0': + dependencies: + ajv: 6.12.6 + debug: 4.3.7 + espree: 10.0.1 + globals: 14.0.0 + ignore: 5.3.1 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -12387,43 +13370,49 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.1': {} + '@eslint/js@8.50.0': {} + + '@eslint/js@8.53.0': {} + + '@eslint/js@8.57.0': {} '@ewoudenberg/difflib@0.1.0': dependencies: heap: 0.2.7 - '@expo/bunyan@4.0.1': + '@expo/bunyan@4.0.0': dependencies: uuid: 8.3.2 + optionalDependencies: + mv: 2.1.1 + safe-json-stringify: 1.2.0 - '@expo/cli@0.18.30(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.3)(utf-8-validate@6.0.3)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': dependencies: - '@babel/runtime': 7.26.0 + '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 - '@expo/config': 9.0.4 - '@expo/config-plugins': 8.0.10 - '@expo/devcert': 1.1.4 + '@expo/config': 9.0.2 + '@expo/config-plugins': 8.0.4 + '@expo/devcert': 1.1.2 '@expo/env': 0.3.0 '@expo/image-utils': 0.5.1(encoding@0.1.13) '@expo/json-file': 8.3.3 - '@expo/metro-config': 0.18.11 - '@expo/osascript': 2.1.3 + '@expo/metro-config': 0.18.4 + '@expo/osascript': 2.1.2 '@expo/package-manager': 1.5.2 '@expo/plist': 0.1.3 - '@expo/prebuild-config': 7.0.9(encoding@0.1.13)(expo-modules-autolinking@1.11.3) + '@expo/prebuild-config': 7.0.4(encoding@0.1.13)(expo-modules-autolinking@1.11.1) '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.85(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 arg: 5.0.2 better-opn: 3.0.2 - bplist-creator: 0.0.7 bplist-parser: 0.3.2 - cacache: 18.0.4 + cacache: 18.0.3 chalk: 4.1.2 ci-info: 3.9.0 connect: 3.7.0 @@ -12431,7 +13420,7 @@ snapshots: env-editor: 0.4.2 fast-glob: 3.3.2 find-yarn-workspace-root: 2.0.0 - form-data: 3.0.2 + form-data: 3.0.1 freeport-async: 2.0.0 fs-extra: 8.1.0 getenv: 1.0.0 @@ -12462,7 +13451,7 @@ snapshots: resolve: 1.22.8 resolve-from: 5.0.0 resolve.exports: 2.0.2 - semver: 7.6.3 + semver: 7.6.2 send: 0.18.0 slugify: 1.6.6 source-map-support: 0.5.21 @@ -12488,9 +13477,9 @@ snapshots: node-forge: 1.3.1 nullthrows: 1.1.1 - '@expo/config-plugins@8.0.10': + '@expo/config-plugins@8.0.4': dependencies: - '@expo/config-types': 51.0.3 + '@expo/config-types': 51.0.0 '@expo/json-file': 8.3.3 '@expo/plist': 0.1.3 '@expo/sdk-runtime-versions': 1.0.0 @@ -12500,7 +13489,7 @@ snapshots: getenv: 1.0.0 glob: 7.1.6 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.6.2 slash: 3.0.0 slugify: 1.6.6 xcode: 3.0.1 @@ -12508,35 +13497,36 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/config-types@51.0.3': {} + '@expo/config-types@51.0.0': {} - '@expo/config@9.0.4': + '@expo/config@9.0.2': dependencies: '@babel/code-frame': 7.10.4 - '@expo/config-plugins': 8.0.10 - '@expo/config-types': 51.0.3 + '@expo/config-plugins': 8.0.4 + '@expo/config-types': 51.0.0 '@expo/json-file': 8.3.3 getenv: 1.0.0 glob: 7.1.6 require-from-string: 2.0.2 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.6.2 slugify: 1.6.6 sucrase: 3.34.0 transitivePeerDependencies: - supports-color - '@expo/devcert@1.1.4': + '@expo/devcert@1.1.2': dependencies: application-config-path: 0.1.1 command-exists: 1.2.9 debug: 3.2.7 eol: 0.9.1 get-port: 3.2.0 - glob: 10.4.5 + glob: 7.2.3 lodash: 4.17.21 mkdirp: 0.5.6 password-prompt: 1.1.3 + rimraf: 2.7.1 sudo-prompt: 8.2.5 tmp: 0.0.33 tslib: 2.8.1 @@ -12563,7 +13553,7 @@ snapshots: node-fetch: 2.7.0(encoding@0.1.13) parse-png: 2.1.0 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.6.2 tempy: 0.3.0 transitivePeerDependencies: - encoding @@ -12574,13 +13564,13 @@ snapshots: json5: 2.2.3 write-file-atomic: 2.4.3 - '@expo/metro-config@0.18.11': + '@expo/metro-config@0.18.4': dependencies: - '@babel/core': 7.26.0 - '@babel/generator': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - '@expo/config': 9.0.4 + '@babel/core': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + '@expo/config': 9.0.2 '@expo/env': 0.3.0 '@expo/json-file': 8.3.3 '@expo/spawn-async': 1.7.2 @@ -12592,12 +13582,12 @@ snapshots: glob: 7.2.3 jsc-safe-url: 0.2.4 lightningcss: 1.19.0 - postcss: 8.4.47 + postcss: 8.4.39 resolve-from: 5.0.0 transitivePeerDependencies: - supports-color - '@expo/osascript@2.1.3': + '@expo/osascript@2.1.2': dependencies: '@expo/spawn-async': 1.7.2 exec-async: 2.2.0 @@ -12623,19 +13613,19 @@ snapshots: base64-js: 1.5.1 xmlbuilder: 14.0.0 - '@expo/prebuild-config@7.0.9(encoding@0.1.13)(expo-modules-autolinking@1.11.3)': + '@expo/prebuild-config@7.0.4(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': dependencies: - '@expo/config': 9.0.4 - '@expo/config-plugins': 8.0.10 - '@expo/config-types': 51.0.3 + '@expo/config': 9.0.2 + '@expo/config-plugins': 8.0.4 + '@expo/config-types': 51.0.0 '@expo/image-utils': 0.5.1(encoding@0.1.13) '@expo/json-file': 8.3.3 - '@react-native/normalize-colors': 0.74.85 + '@react-native/normalize-colors': 0.74.83 debug: 4.3.7 - expo-modules-autolinking: 1.11.3 + expo-modules-autolinking: 1.11.1 fs-extra: 9.1.0 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.6.2 xml2js: 0.6.0 transitivePeerDependencies: - encoding @@ -12643,7 +13633,7 @@ snapshots: '@expo/rudder-sdk-node@1.1.1(encoding@0.1.13)': dependencies: - '@expo/bunyan': 4.0.1 + '@expo/bunyan': 4.0.0 '@segment/loosely-validate-event': 2.0.0 fetch-retry: 4.1.1 md5: 2.3.0 @@ -12657,9 +13647,9 @@ snapshots: '@expo/spawn-async@1.7.2': dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 - '@expo/vector-icons@14.0.4': + '@expo/vector-icons@14.0.2': dependencies: prop-types: 15.8.1 @@ -12687,25 +13677,49 @@ snapshots: dependencies: graphql: 15.8.0 - '@hono/node-server@1.13.5(hono@4.6.9)': + '@hapi/hoek@9.3.0': {} + + '@hapi/topo@5.1.0': + dependencies: + '@hapi/hoek': 9.3.0 + + '@hono/node-server@1.12.0': {} + + '@hono/zod-validator@0.2.2(hono@4.5.0)(zod@3.23.7)': + dependencies: + hono: 4.5.0 + zod: 3.23.7 + + '@humanwhocodes/config-array@0.11.11': dependencies: - hono: 4.6.9 + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color - '@hono/zod-validator@0.2.2(hono@4.6.9)(zod@3.23.8)': + '@humanwhocodes/config-array@0.11.13': dependencies: - hono: 4.6.9 - zod: 3.23.8 + '@humanwhocodes/object-schema': 2.0.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color - '@humanwhocodes/config-array@0.13.0': + '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.7 + debug: 4.3.4 minimatch: 3.1.2 transitivePeerDependencies: - supports-color '@humanwhocodes/module-importer@1.0.1': {} + '@humanwhocodes/object-schema@1.2.1': {} + + '@humanwhocodes/object-schema@2.0.1': {} + '@humanwhocodes/object-schema@2.0.3': {} '@iarna/toml@2.2.5': {} @@ -12721,16 +13735,6 @@ snapshots: '@isaacs/ttlcache@1.4.1': {} - '@istanbuljs/load-nyc-config@1.1.0': - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 3.14.1 - resolve-from: 5.0.0 - - '@istanbuljs/schema@0.1.3': {} - '@jest/create-cache-key-function@29.7.0': dependencies: '@jest/types': 29.6.3 @@ -12739,14 +13743,14 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.6 + '@types/node': 20.12.12 jest-mock: 29.7.0 '@jest/fake-timers@29.7.0': dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.17.6 + '@types/node': 20.12.12 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -12755,67 +13759,73 @@ snapshots: dependencies: '@sinclair/typebox': 0.27.8 - '@jest/transform@29.7.0': - dependencies: - '@babel/core': 7.26.0 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.8 - pirates: 4.0.6 - slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color - - '@jest/types@24.9.0': + '@jest/types@26.6.2': dependencies: '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 1.1.2 - '@types/yargs': 13.0.12 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.12.12 + '@types/yargs': 15.0.19 + chalk: 4.1.2 '@jest/types@29.6.3': dependencies: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.17.6 - '@types/yargs': 17.0.33 + '@types/node': 20.12.12 + '@types/yargs': 17.0.32 chalk: 4.1.2 + '@jridgewell/gen-mapping@0.3.3': + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/resolve-uri@3.1.0': {} + '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/set-array@1.1.2': {} + '@jridgewell/set-array@1.2.1': {} + '@jridgewell/source-map@0.3.3': + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/source-map@0.3.6': dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/sourcemap-codec@1.4.14': {} + + '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/trace-mapping@0.3.18': + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.4.15 '@libsql/client-wasm@0.10.0': dependencies: @@ -12827,7 +13837,7 @@ snapshots: '@libsql/core': 0.10.0 '@libsql/hrana-client': 0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) js-base64: 3.7.7 - libsql: 0.4.7 + libsql: 0.4.1 promise-limit: 2.7.0 transitivePeerDependencies: - bufferutil @@ -12837,10 +13847,16 @@ snapshots: dependencies: js-base64: 3.7.7 - '@libsql/darwin-arm64@0.4.7': + '@libsql/darwin-arm64@0.3.19': + optional: true + + '@libsql/darwin-arm64@0.4.1': + optional: true + + '@libsql/darwin-x64@0.3.19': optional: true - '@libsql/darwin-x64@0.4.7': + '@libsql/darwin-x64@0.4.1': optional: true '@libsql/hrana-client@0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)': @@ -12857,37 +13873,52 @@ snapshots: '@libsql/isomorphic-ws@0.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.3)': dependencies: - '@types/ws': 8.5.13 + '@types/ws': 8.5.11 ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate - '@libsql/linux-arm64-gnu@0.4.7': + '@libsql/linux-arm64-gnu@0.3.19': optional: true - '@libsql/linux-arm64-musl@0.4.7': + '@libsql/linux-arm64-gnu@0.4.1': optional: true - '@libsql/linux-x64-gnu@0.4.7': + '@libsql/linux-arm64-musl@0.3.19': optional: true - '@libsql/linux-x64-musl@0.4.7': + '@libsql/linux-arm64-musl@0.4.1': optional: true - '@libsql/win32-x64-msvc@0.4.7': + '@libsql/linux-x64-gnu@0.3.19': optional: true - '@miniflare/core@2.14.4': - dependencies: - '@iarna/toml': 2.2.5 - '@miniflare/queues': 2.14.4 - '@miniflare/shared': 2.14.4 - '@miniflare/watcher': 2.14.4 - busboy: 1.6.0 - dotenv: 10.0.0 + '@libsql/linux-x64-gnu@0.4.1': + optional: true + + '@libsql/linux-x64-musl@0.3.19': + optional: true + + '@libsql/linux-x64-musl@0.4.1': + optional: true + + '@libsql/win32-x64-msvc@0.3.19': + optional: true + + '@libsql/win32-x64-msvc@0.4.1': + optional: true + + '@miniflare/core@2.14.4': + dependencies: + '@iarna/toml': 2.2.5 + '@miniflare/queues': 2.14.4 + '@miniflare/shared': 2.14.4 + '@miniflare/watcher': 2.14.4 + busboy: 1.6.0 + dotenv: 10.0.0 kleur: 4.1.5 - set-cookie-parser: 2.7.1 + set-cookie-parser: 2.6.0 undici: 5.28.4 urlpattern-polyfill: 4.0.3 @@ -12902,7 +13933,7 @@ snapshots: '@miniflare/shared@2.14.4': dependencies: - '@types/better-sqlite3': 7.6.11 + '@types/better-sqlite3': 7.6.10 kleur: 4.1.5 npx-import: 1.1.4 picomatch: 2.3.1 @@ -12930,7 +13961,7 @@ snapshots: dependencies: '@types/pg': 8.11.6 - '@noble/hashes@1.5.0': {} + '@noble/hashes@1.4.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -12942,17 +13973,17 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 + fastq: 1.15.0 '@npmcli/fs@1.1.1': dependencies: '@gar/promisify': 1.1.3 - semver: 7.6.3 + semver: 7.6.2 optional: true '@npmcli/fs@3.1.1': dependencies: - semver: 7.6.3 + semver: 7.6.2 '@npmcli/move-file@1.1.2': dependencies: @@ -12960,12 +13991,12 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) - '@opentelemetry/api@1.9.0': {} + '@opentelemetry/api@1.8.0': {} '@originjs/vite-plugin-commonjs@1.0.3': dependencies: @@ -12973,16 +14004,16 @@ snapshots: '@paralleldrive/cuid2@2.2.2': dependencies: - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.4.0 '@pkgjs/parseargs@0.11.0': optional: true '@pkgr/core@0.1.1': {} - '@planetscale/database@1.19.0': {} + '@planetscale/database@1.18.0': {} - '@polka/url@1.0.0-next.28': {} + '@polka/url@1.0.0-next.25': {} '@prisma/client@5.14.0(prisma@5.14.0)': optionalDependencies: @@ -12990,7 +14021,7 @@ snapshots: '@prisma/debug@5.14.0': {} - '@prisma/debug@5.22.0': {} + '@prisma/debug@5.16.1': {} '@prisma/engines-version@5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48': {} @@ -13007,168 +14038,245 @@ snapshots: '@prisma/engines-version': 5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48 '@prisma/get-platform': 5.14.0 - '@prisma/generator-helper@5.22.0': + '@prisma/generator-helper@5.16.1': dependencies: - '@prisma/debug': 5.22.0 + '@prisma/debug': 5.16.1 '@prisma/get-platform@5.14.0': dependencies: '@prisma/debug': 5.14.0 - '@react-native/assets-registry@0.76.1': {} + '@react-native-community/cli-clean@13.6.6(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + execa: 5.1.1 + fast-glob: 3.3.2 + transitivePeerDependencies: + - encoding - '@react-native/babel-plugin-codegen@0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0))': + '@react-native-community/cli-config@13.6.6(encoding@0.1.13)': dependencies: - '@react-native/codegen': 0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + cosmiconfig: 5.2.1 + deepmerge: 4.3.1 + fast-glob: 3.3.2 + joi: 17.13.1 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-debugger-ui@13.6.6': + dependencies: + serve-static: 1.15.0 transitivePeerDependencies: - - '@babel/preset-env' - supports-color - '@react-native/babel-plugin-codegen@0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0))': + '@react-native-community/cli-doctor@13.6.6(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-platform-apple': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + command-exists: 1.2.9 + deepmerge: 4.3.1 + envinfo: 7.13.0 + execa: 5.1.1 + hermes-profile-transformer: 0.0.6 + node-stream-zip: 1.15.0 + ora: 5.4.1 + semver: 7.6.2 + strip-ansi: 5.2.0 + wcwidth: 1.0.1 + yaml: 2.4.2 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-hermes@13.6.6(encoding@0.1.13)': dependencies: - '@react-native/codegen': 0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + hermes-profile-transformer: 0.0.6 transitivePeerDependencies: - - '@babel/preset-env' + - encoding + + '@react-native-community/cli-platform-android@13.6.6(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + execa: 5.1.1 + fast-glob: 3.3.2 + fast-xml-parser: 4.4.0 + logkitty: 0.7.1 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-platform-apple@13.6.6(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + chalk: 4.1.2 + execa: 5.1.1 + fast-glob: 3.3.2 + fast-xml-parser: 4.4.0 + ora: 5.4.1 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-platform-ios@13.6.6(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-platform-apple': 13.6.6(encoding@0.1.13) + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-debugger-ui': 13.6.6 + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + compression: 1.7.4 + connect: 3.7.0 + errorhandler: 1.5.1 + nocache: 3.0.4 + pretty-format: 26.6.2 + serve-static: 1.15.0 + ws: 6.2.2(bufferutil@4.0.8) + transitivePeerDependencies: + - bufferutil + - encoding - supports-color + - utf-8-validate - '@react-native/babel-preset@0.74.87(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))': - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.26.0) - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-export-default-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.26.0) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.26.0) - '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.26.0) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-export-default-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) - '@babel/template': 7.25.9 - '@react-native/babel-plugin-codegen': 0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.26.0) - react-refresh: 0.14.2 + '@react-native-community/cli-tools@13.6.6(encoding@0.1.13)': + dependencies: + appdirsjs: 1.2.7 + chalk: 4.1.2 + execa: 5.1.1 + find-up: 5.0.0 + mime: 2.6.0 + node-fetch: 2.7.0(encoding@0.1.13) + open: 6.4.0 + ora: 5.4.1 + semver: 7.6.2 + shell-quote: 1.8.1 + sudo-prompt: 9.2.1 transitivePeerDependencies: - - '@babel/preset-env' + - encoding + + '@react-native-community/cli-types@13.6.6': + dependencies: + joi: 17.13.1 + + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-debugger-ui': 13.6.6 + '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-types': 13.6.6 + chalk: 4.1.2 + commander: 9.5.0 + deepmerge: 4.3.1 + execa: 5.1.1 + find-up: 4.1.0 + fs-extra: 8.1.0 + graceful-fs: 4.2.11 + prompts: 2.4.2 + semver: 7.6.2 + transitivePeerDependencies: + - bufferutil + - encoding - supports-color + - utf-8-validate - '@react-native/babel-preset@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))': - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-proposal-export-default-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-export-default-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-generator-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) - '@babel/template': 7.25.9 - '@react-native/babel-plugin-codegen': 0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - babel-plugin-syntax-hermes-parser: 0.23.1 - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.26.0) - react-refresh: 0.14.2 + '@react-native/assets-registry@0.74.83': {} + + '@react-native/babel-plugin-codegen@0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6))': + dependencies: + '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) transitivePeerDependencies: - '@babel/preset-env' - supports-color - '@react-native/codegen@0.74.87(@babel/preset-env@7.26.0(@babel/core@7.26.0))': - dependencies: - '@babel/parser': 7.26.2 - '@babel/preset-env': 7.26.0(@babel/core@7.26.0) - glob: 7.2.3 - hermes-parser: 0.19.1 - invariant: 2.2.4 - jscodeshift: 0.14.0(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - mkdirp: 0.5.6 - nullthrows: 1.1.1 + '@react-native/babel-preset@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))': + dependencies: + '@babel/core': 7.24.6 + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.24.6) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-export-default-from': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.24.6) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.24.6) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.6) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-export-default-from': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-flow': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-transform-arrow-functions': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-async-to-generator': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-block-scoping': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-classes': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-computed-properties': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-destructuring': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-flow-strip-types': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-function-name': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-literals': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-named-capturing-groups-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-private-methods': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-private-property-in-object': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-display-name': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-jsx': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-jsx-self': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-react-jsx-source': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-runtime': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-shorthand-properties': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-spread': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-sticky-regex': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-typescript': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-regex': 7.24.6(@babel/core@7.24.6) + '@babel/template': 7.24.6 + '@react-native/babel-plugin-codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.24.6) + react-refresh: 0.14.2 transitivePeerDependencies: + - '@babel/preset-env' - supports-color - '@react-native/codegen@0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0))': + '@react-native/codegen@0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6))': dependencies: - '@babel/parser': 7.26.2 - '@babel/preset-env': 7.26.0(@babel/core@7.26.0) + '@babel/parser': 7.24.6 + '@babel/preset-env': 7.24.6(@babel/core@7.24.6) glob: 7.2.3 - hermes-parser: 0.23.1 + hermes-parser: 0.19.1 invariant: 2.2.4 - jscodeshift: 0.14.0(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + jscodeshift: 0.14.0(@babel/preset-env@7.24.6(@babel/core@7.24.6)) mkdirp: 0.5.6 nullthrows: 1.1.1 - yargs: 17.7.2 transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: - '@react-native/dev-middleware': 0.76.1(bufferutil@4.0.8)(utf-8-validate@6.0.3) - '@react-native/metro-babel-transformer': 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - invariant: 2.2.4 - metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - metro-config: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - metro-core: 0.81.0 + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) + querystring: 0.2.1 readline: 1.3.0 transitivePeerDependencies: - '@babel/core' @@ -13178,14 +14286,12 @@ snapshots: - supports-color - utf-8-validate - '@react-native/debugger-frontend@0.74.85': {} - - '@react-native/debugger-frontend@0.76.1': {} + '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.85(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.74.85 + '@react-native/debugger-frontend': 0.74.83 '@rnx-kit/chromium-edge-launcher': 1.0.0 chrome-launcher: 0.15.2 connect: 3.7.0 @@ -13194,63 +14300,43 @@ snapshots: nullthrows: 1.1.1 open: 7.4.2 selfsigned: 2.4.1 - serve-static: 1.16.2 + serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding - supports-color - utf-8-validate - '@react-native/dev-middleware@0.76.1(bufferutil@4.0.8)(utf-8-validate@6.0.3)': - dependencies: - '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.76.1 - chrome-launcher: 0.15.2 - chromium-edge-launcher: 0.2.0 - connect: 3.7.0 - debug: 2.6.9 - nullthrows: 1.1.1 - open: 7.4.2 - selfsigned: 2.4.1 - serve-static: 1.16.2 - ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@react-native/gradle-plugin@0.76.1': {} + '@react-native/gradle-plugin@0.74.83': {} - '@react-native/js-polyfills@0.76.1': {} + '@react-native/js-polyfills@0.74.83': {} - '@react-native/metro-babel-transformer@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))': + '@react-native/metro-babel-transformer@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))': dependencies: - '@babel/core': 7.26.0 - '@react-native/babel-preset': 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - hermes-parser: 0.23.1 + '@babel/core': 7.24.6 + '@react-native/babel-preset': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + hermes-parser: 0.19.1 nullthrows: 1.1.1 transitivePeerDependencies: - '@babel/preset-env' - supports-color - '@react-native/normalize-colors@0.74.85': {} + '@react-native/normalize-colors@0.74.83': {} - '@react-native/normalize-colors@0.76.1': {} - - '@react-native/virtualized-lists@0.76.1(@types/react@18.3.12)(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) optionalDependencies: - '@types/react': 18.3.12 + '@types/react': 18.3.1 '@rnx-kit/chromium-edge-launcher@1.0.0': dependencies: - '@types/node': 18.19.64 + '@types/node': 18.19.33 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -13259,21 +14345,21 @@ snapshots: transitivePeerDependencies: - supports-color - '@rollup/plugin-terser@0.4.4(rollup@3.29.5)': + '@rollup/plugin-terser@0.4.1(rollup@3.20.7)': dependencies: - serialize-javascript: 6.0.2 - smob: 1.5.0 - terser: 5.36.0 + serialize-javascript: 6.0.1 + smob: 0.0.6 + terser: 5.17.1 optionalDependencies: - rollup: 3.29.5 + rollup: 3.20.7 - '@rollup/plugin-terser@0.4.4(rollup@4.24.4)': + '@rollup/plugin-terser@0.4.1(rollup@3.27.2)': dependencies: - serialize-javascript: 6.0.2 - smob: 1.5.0 - terser: 5.36.0 + serialize-javascript: 6.0.1 + smob: 0.0.6 + terser: 5.17.1 optionalDependencies: - rollup: 4.24.4 + rollup: 3.27.2 '@rollup/plugin-terser@0.4.4(rollup@4.27.3)': dependencies: @@ -13285,8 +14371,8 @@ snapshots: '@rollup/plugin-typescript@11.1.0(rollup@3.20.7)(tslib@2.8.1)(typescript@5.6.3)': dependencies: - '@rollup/pluginutils': 5.1.3(rollup@3.29.5) - resolve: 1.22.8 + '@rollup/pluginutils': 5.0.2(rollup@3.20.7) + resolve: 1.22.1 typescript: 5.6.3 optionalDependencies: rollup: 3.20.7 @@ -13294,8 +14380,8 @@ snapshots: '@rollup/plugin-typescript@11.1.1(rollup@3.27.2)(tslib@2.8.1)(typescript@5.6.3)': dependencies: - '@rollup/pluginutils': 5.1.3(rollup@4.24.4) - resolve: 1.22.8 + '@rollup/pluginutils': 5.0.2(rollup@3.27.2) + resolve: 1.22.2 typescript: 5.6.3 optionalDependencies: rollup: 3.27.2 @@ -13310,21 +14396,21 @@ snapshots: rollup: 4.27.3 tslib: 2.8.1 - '@rollup/pluginutils@5.1.3(rollup@3.29.5)': + '@rollup/pluginutils@5.0.2(rollup@3.20.7)': dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.1 estree-walker: 2.0.2 - picomatch: 4.0.2 + picomatch: 2.3.1 optionalDependencies: - rollup: 3.29.5 + rollup: 3.20.7 - '@rollup/pluginutils@5.1.3(rollup@4.24.4)': + '@rollup/pluginutils@5.0.2(rollup@3.27.2)': dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.1 estree-walker: 2.0.2 - picomatch: 4.0.2 + picomatch: 2.3.1 optionalDependencies: - rollup: 4.24.4 + rollup: 3.27.2 '@rollup/pluginutils@5.1.3(rollup@4.27.3)': dependencies: @@ -13334,25 +14420,25 @@ snapshots: optionalDependencies: rollup: 4.27.3 - '@rollup/rollup-android-arm64@4.24.4': + '@rollup/rollup-android-arm-eabi@4.18.1': optional: true '@rollup/rollup-android-arm-eabi@4.27.3': optional: true - '@rollup/rollup-darwin-x64@4.24.4': + '@rollup/rollup-android-arm64@4.18.1': optional: true '@rollup/rollup-android-arm64@4.27.3': optional: true - '@rollup/rollup-freebsd-x64@4.24.4': + '@rollup/rollup-darwin-arm64@4.18.1': optional: true '@rollup/rollup-darwin-arm64@4.27.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.24.4': + '@rollup/rollup-darwin-x64@4.18.1': optional: true '@rollup/rollup-darwin-x64@4.27.3': @@ -13364,31 +14450,31 @@ snapshots: '@rollup/rollup-freebsd-x64@4.27.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.24.4': + '@rollup/rollup-linux-arm-gnueabihf@4.18.1': optional: true '@rollup/rollup-linux-arm-gnueabihf@4.27.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.24.4': + '@rollup/rollup-linux-arm-musleabihf@4.18.1': optional: true '@rollup/rollup-linux-arm-musleabihf@4.27.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.24.4': + '@rollup/rollup-linux-arm64-gnu@4.18.1': optional: true '@rollup/rollup-linux-arm64-gnu@4.27.3': optional: true - '@rollup/rollup-win32-arm64-msvc@4.24.4': + '@rollup/rollup-linux-arm64-musl@4.18.1': optional: true '@rollup/rollup-linux-arm64-musl@4.27.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.24.4': + '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': optional: true '@rollup/rollup-linux-powerpc64le-gnu@4.27.3': @@ -13441,6 +14527,14 @@ snapshots: component-type: 1.2.2 join-component: 1.1.0 + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + + '@sideway/formula@3.0.1': {} + + '@sideway/pinpoint@2.0.0': {} + '@sinclair/typebox@0.27.8': {} '@sinclair/typebox@0.29.6': {} @@ -13457,12 +14551,12 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@smithy/abort-controller@3.1.6': + '@smithy/abort-controller@2.2.0': dependencies: '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/config-resolver@3.0.10': + '@smithy/abort-controller@3.0.0': dependencies: '@smithy/types': 3.0.0 tslib: 2.8.1 @@ -13483,7 +14577,7 @@ snapshots: '@smithy/util-middleware': 3.0.0 tslib: 2.8.1 - '@smithy/core@2.5.1': + '@smithy/core@1.4.2': dependencies: '@smithy/middleware-endpoint': 2.5.1 '@smithy/middleware-retry': 2.3.1 @@ -13494,7 +14588,7 @@ snapshots: '@smithy/util-middleware': 2.2.0 tslib: 2.8.1 - '@smithy/credential-provider-imds@3.2.5': + '@smithy/core@2.0.1': dependencies: '@smithy/middleware-endpoint': 3.0.0 '@smithy/middleware-retry': 3.0.1 @@ -13505,7 +14599,7 @@ snapshots: '@smithy/util-middleware': 3.0.0 tslib: 2.8.1 - '@smithy/fetch-http-handler@4.0.0': + '@smithy/credential-provider-imds@2.3.0': dependencies: '@smithy/node-config-provider': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -13567,7 +14661,7 @@ snapshots: '@smithy/util-base64': 3.0.0 tslib: 2.8.1 - '@smithy/hash-node@3.0.8': + '@smithy/hash-node@2.2.0': dependencies: '@smithy/types': 2.12.0 '@smithy/util-buffer-from': 2.2.0 @@ -13581,7 +14675,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 - '@smithy/invalid-dependency@3.0.8': + '@smithy/invalid-dependency@2.2.0': dependencies: '@smithy/types': 2.12.0 tslib: 2.8.1 @@ -13599,19 +14693,19 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/middleware-content-length@3.0.10': + '@smithy/middleware-content-length@2.2.0': dependencies: '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/middleware-endpoint@3.2.1': + '@smithy/middleware-content-length@3.0.0': dependencies: '@smithy/protocol-http': 4.0.0 '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/middleware-retry@3.0.25': + '@smithy/middleware-endpoint@2.5.1': dependencies: '@smithy/middleware-serde': 2.3.0 '@smithy/node-config-provider': 2.3.0 @@ -13643,7 +14737,7 @@ snapshots: tslib: 2.8.1 uuid: 9.0.1 - '@smithy/middleware-serde@3.0.8': + '@smithy/middleware-retry@3.0.1': dependencies: '@smithy/node-config-provider': 3.0.0 '@smithy/protocol-http': 4.0.0 @@ -13655,34 +14749,34 @@ snapshots: tslib: 2.8.1 uuid: 9.0.1 - '@smithy/middleware-stack@3.0.8': + '@smithy/middleware-serde@2.3.0': dependencies: '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/node-config-provider@3.1.9': + '@smithy/middleware-serde@3.0.0': dependencies: '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/node-http-handler@3.2.5': + '@smithy/middleware-stack@2.2.0': dependencies: '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/property-provider@3.1.8': + '@smithy/middleware-stack@3.0.0': dependencies: '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/protocol-http@4.1.5': + '@smithy/node-config-provider@2.3.0': dependencies: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/querystring-builder@3.0.8': + '@smithy/node-config-provider@3.0.0': dependencies: '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -13737,20 +14831,19 @@ snapshots: '@smithy/util-uri-escape': 3.0.0 tslib: 2.8.1 - '@smithy/querystring-parser@3.0.8': + '@smithy/querystring-parser@2.2.0': dependencies: '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/service-error-classification@3.0.8': + '@smithy/querystring-parser@3.0.0': dependencies: '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/shared-ini-file-loader@3.1.9': + '@smithy/service-error-classification@2.1.5': dependencies: - '@smithy/types': 3.6.0 - tslib: 2.8.1 + '@smithy/types': 2.12.0 '@smithy/service-error-classification@3.0.0': dependencies: @@ -13779,15 +14872,14 @@ snapshots: '@smithy/signature-v4@3.0.0': dependencies: '@smithy/is-array-buffer': 3.0.0 - '@smithy/protocol-http': 4.1.5 - '@smithy/types': 3.6.0 + '@smithy/types': 3.0.0 '@smithy/util-hex-encoding': 3.0.0 - '@smithy/util-middleware': 3.0.8 + '@smithy/util-middleware': 3.0.0 '@smithy/util-uri-escape': 3.0.0 '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 - '@smithy/smithy-client@3.4.2': + '@smithy/smithy-client@2.5.1': dependencies: '@smithy/middleware-endpoint': 2.5.1 '@smithy/middleware-stack': 2.2.0 @@ -13796,7 +14888,7 @@ snapshots: '@smithy/util-stream': 2.2.0 tslib: 2.8.1 - '@smithy/types@3.6.0': + '@smithy/smithy-client@3.0.1': dependencies: '@smithy/middleware-endpoint': 3.0.0 '@smithy/middleware-stack': 3.0.0 @@ -13805,7 +14897,7 @@ snapshots: '@smithy/util-stream': 3.0.1 tslib: 2.8.1 - '@smithy/url-parser@3.0.8': + '@smithy/types@2.12.0': dependencies: tslib: 2.8.1 @@ -13871,15 +14963,15 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@3.0.25': + '@smithy/util-defaults-mode-browser@2.2.1': dependencies: - '@smithy/property-provider': 3.1.8 - '@smithy/smithy-client': 3.4.2 - '@smithy/types': 3.6.0 + '@smithy/property-provider': 2.2.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 bowser: 2.11.0 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@3.0.25': + '@smithy/util-defaults-mode-browser@3.0.1': dependencies: '@smithy/property-provider': 3.0.0 '@smithy/smithy-client': 3.0.1 @@ -13887,7 +14979,7 @@ snapshots: bowser: 2.11.0 tslib: 2.8.1 - '@smithy/util-endpoints@2.1.4': + '@smithy/util-defaults-mode-node@2.3.1': dependencies: '@smithy/config-resolver': 2.2.0 '@smithy/credential-provider-imds': 2.3.0 @@ -13927,17 +15019,17 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/util-middleware@3.0.8': + '@smithy/util-middleware@2.2.0': dependencies: '@smithy/types': 2.12.0 tslib: 2.8.1 - '@smithy/util-retry@3.0.8': + '@smithy/util-middleware@3.0.0': dependencies: '@smithy/types': 3.0.0 tslib: 2.8.1 - '@smithy/util-stream@3.2.1': + '@smithy/util-retry@2.2.0': dependencies: '@smithy/service-error-classification': 2.1.5 '@smithy/types': 2.12.0 @@ -14000,15 +15092,15 @@ snapshots: '@tootallnate/once@1.1.2': optional: true - '@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.3.3)': + '@trivago/prettier-plugin-sort-imports@4.2.0(prettier@3.0.3)': dependencies: '@babel/generator': 7.17.7 - '@babel/parser': 7.26.2 - '@babel/traverse': 7.23.2 + '@babel/parser': 7.22.10 + '@babel/traverse': 7.17.3 '@babel/types': 7.17.0 javascript-natural-sort: 0.7.1 lodash: 4.17.21 - prettier: 3.3.3 + prettier: 3.0.3 transitivePeerDependencies: - supports-color @@ -14020,40 +15112,19 @@ snapshots: '@tsconfig/node16@1.0.4': {} - '@types/async-retry@1.4.9': + '@types/async-retry@1.4.8': dependencies: '@types/retry': 0.12.5 - '@types/axios@0.14.4': + '@types/axios@0.14.0': dependencies: - axios: 1.7.7 + axios: 1.6.8 transitivePeerDependencies: - debug - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - '@types/babel__generator': 7.6.8 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.20.6 - - '@types/babel__generator@7.6.8': - dependencies: - '@babel/types': 7.26.0 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - - '@types/babel__traverse@7.20.6': - dependencies: - '@babel/types': 7.26.0 - - '@types/better-sqlite3@7.6.11': + '@types/better-sqlite3@7.6.10': dependencies: - '@types/node': 18.19.64 + '@types/node': 20.12.12 '@types/better-sqlite3@7.6.12': dependencies: @@ -14062,24 +15133,24 @@ snapshots: '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 20.17.6 + '@types/node': 20.12.12 '@types/braces@3.0.4': {} '@types/connect@3.4.38': dependencies: - '@types/node': 20.17.6 + '@types/node': 20.12.12 '@types/docker-modem@3.0.6': dependencies: - '@types/node': 18.19.64 - '@types/ssh2': 1.15.1 + '@types/node': 20.12.12 + '@types/ssh2': 1.15.0 - '@types/dockerode@3.3.31': + '@types/dockerode@3.3.29': dependencies: '@types/docker-modem': 3.0.6 - '@types/node': 18.19.64 - '@types/ssh2': 1.15.1 + '@types/node': 20.12.12 + '@types/ssh2': 1.15.0 '@types/dockerode@3.3.32': dependencies: @@ -14089,7 +15160,7 @@ snapshots: '@types/emscripten@1.39.11': {} - '@types/estree@1.0.6': {} + '@types/estree@1.0.1': {} '@types/estree@1.0.5': {} @@ -14097,31 +15168,27 @@ snapshots: '@types/express-serve-static-core@4.19.0': dependencies: - '@types/node': 20.17.6 - '@types/qs': 6.9.17 + '@types/node': 20.12.12 + '@types/qs': 6.9.15 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 '@types/express@4.17.21': dependencies: '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.19.6 - '@types/qs': 6.9.17 + '@types/express-serve-static-core': 4.19.0 + '@types/qs': 6.9.15 '@types/serve-static': 1.15.7 '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 18.19.64 + '@types/node': 20.12.12 '@types/glob@8.1.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 18.19.64 - - '@types/graceful-fs@4.1.9': - dependencies: - '@types/node': 20.17.6 + '@types/node': 20.12.12 '@types/http-errors@2.0.4': {} @@ -14131,24 +15198,19 @@ snapshots: dependencies: '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports@1.1.2': - dependencies: - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-lib-report': 3.0.3 - '@types/istanbul-reports@3.0.4': dependencies: '@types/istanbul-lib-report': 3.0.3 '@types/json-diff@1.0.3': {} - '@types/json-schema@7.0.15': {} + '@types/json-schema@7.0.13': {} '@types/json5@0.0.29': {} '@types/jsonfile@6.1.4': dependencies: - '@types/node': 18.19.64 + '@types/node': 20.12.12 '@types/micromatch@4.0.9': dependencies: @@ -14158,23 +15220,25 @@ snapshots: '@types/minimatch@5.1.2': {} - '@types/minimist@1.2.5': {} + '@types/minimist@1.2.2': {} '@types/node-forge@1.3.11': dependencies: - '@types/node': 18.19.64 + '@types/node': 20.12.12 - '@types/node@18.19.64': + '@types/node@18.15.10': {} + + '@types/node@18.19.33': dependencies: undici-types: 5.26.5 - '@types/node@20.12.14': + '@types/node@20.10.1': dependencies: undici-types: 5.26.5 - '@types/node@20.17.6': + '@types/node@20.12.12': dependencies: - undici-types: 6.19.8 + undici-types: 5.26.5 '@types/node@22.9.1': dependencies: @@ -14184,29 +15248,29 @@ snapshots: '@types/pg@8.11.6': dependencies: - '@types/node': 18.19.64 - pg-protocol: 1.7.0 + '@types/node': 20.12.12 + pg-protocol: 1.6.1 pg-types: 4.0.2 '@types/pg@8.6.6': dependencies: - '@types/node': 18.19.64 - pg-protocol: 1.7.0 + '@types/node': 20.12.12 + pg-protocol: 1.6.1 pg-types: 2.2.0 '@types/pluralize@0.0.33': {} - '@types/prop-types@15.7.13': {} + '@types/prop-types@15.7.12': {} - '@types/ps-tree@1.1.6': {} + '@types/ps-tree@1.1.2': {} - '@types/qs@6.9.17': {} + '@types/qs@6.9.15': {} '@types/range-parser@1.2.7': {} - '@types/react@18.3.12': + '@types/react@18.3.1': dependencies: - '@types/prop-types': 15.7.13 + '@types/prop-types': 15.7.12 csstype: 3.1.3 '@types/retry@0.12.5': {} @@ -14216,22 +15280,22 @@ snapshots: '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 20.17.6 + '@types/node': 20.12.12 '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 20.17.6 + '@types/node': 20.12.12 '@types/send': 0.17.4 '@types/sql.js@1.4.9': dependencies: - '@types/emscripten': 1.39.13 - '@types/node': 20.17.6 + '@types/emscripten': 1.39.11 + '@types/node': 20.12.12 - '@types/ssh2@1.15.1': + '@types/ssh2@1.15.0': dependencies: - '@types/node': 18.19.64 + '@types/node': 18.19.33 '@types/stack-utils@2.0.3': {} @@ -14239,103 +15303,116 @@ snapshots: '@types/uuid@9.0.8': {} - '@types/which@3.0.4': {} + '@types/which@3.0.0': {} - '@types/ws@8.5.13': + '@types/ws@8.5.11': dependencies: - '@types/node': 18.19.64 + '@types/node': 20.12.12 '@types/yargs-parser@21.0.3': {} - '@types/yargs@13.0.12': + '@types/yargs@15.0.19': dependencies: '@types/yargs-parser': 21.0.3 - '@types/yargs@17.0.33': + '@types/yargs@17.0.32': dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.7 - eslint: 8.57.1 + '@eslint-community/regexpp': 4.9.0 + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/type-utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 6.7.3 + debug: 4.3.4 + eslint: 8.50.0 graphemer: 1.4.0 - ignore: 5.3.2 + ignore: 5.2.4 natural-compare: 1.4.0 - semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) + semver: 7.6.2 + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0)(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/type-utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 7.18.0 - eslint: 8.57.1 + '@eslint-community/regexpp': 4.11.0 + '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 7.16.1 + '@typescript-eslint/type-utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 7.16.1 + eslint: 8.57.0 graphemer: 1.4.0 - ignore: 5.3.2 + ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.4.0(typescript@5.6.3) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/experimental-utils@5.62.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/experimental-utils@5.62.0(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.6.3) - eslint: 8.57.1 + '@typescript-eslint/utils': 5.62.0(eslint@8.50.0)(typescript@5.6.3) + eslint: 8.50.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.2.2)': dependencies: - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.7 - eslint: 8.57.1 + '@typescript-eslint/scope-manager': 6.10.0 + '@typescript-eslint/types': 6.10.0 + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.10.0 + debug: 4.3.4 + eslint: 8.53.0 + optionalDependencies: + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3)': + dependencies: + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 6.7.3 + debug: 4.3.4 + eslint: 8.50.0 optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.7 - eslint: 8.57.1 + '@typescript-eslint/scope-manager': 7.16.1 + '@typescript-eslint/types': 7.16.1 + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 7.16.1 + debug: 4.3.4 + eslint: 8.57.0 optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/rule-tester@6.21.0(@eslint/eslintrc@2.1.4)(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/rule-tester@6.10.0(@eslint/eslintrc@3.1.0)(eslint@8.53.0)(typescript@5.2.2)': dependencies: - '@eslint/eslintrc': 2.1.4 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) + '@eslint/eslintrc': 3.1.0 + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) + '@typescript-eslint/utils': 6.10.0(eslint@8.53.0)(typescript@5.2.2) ajv: 6.12.6 - eslint: 8.57.1 + eslint: 8.53.0 lodash.merge: 4.6.2 - semver: 7.6.3 + semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript @@ -14345,35 +15422,40 @@ snapshots: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - '@typescript-eslint/scope-manager@6.21.0': + '@typescript-eslint/scope-manager@6.10.0': dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 + '@typescript-eslint/types': 6.10.0 + '@typescript-eslint/visitor-keys': 6.10.0 - '@typescript-eslint/scope-manager@7.18.0': + '@typescript-eslint/scope-manager@6.7.3': dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/visitor-keys': 6.7.3 - '@typescript-eslint/type-utils@6.21.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/scope-manager@7.16.1': dependencies: - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - debug: 4.3.7 - eslint: 8.57.1 - ts-api-utils: 1.4.0(typescript@5.6.3) + '@typescript-eslint/types': 7.16.1 + '@typescript-eslint/visitor-keys': 7.16.1 + + '@typescript-eslint/type-utils@6.7.3(eslint@8.50.0)(typescript@5.6.3)': + dependencies: + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + debug: 4.3.4 + eslint: 8.50.0 + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@7.18.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/type-utils@7.16.1(eslint@8.57.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) - '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) - debug: 4.3.7 - eslint: 8.57.1 - ts-api-utils: 1.4.0(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) + '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.6.3) + debug: 4.3.4 + eslint: 8.57.0 + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -14381,90 +15463,119 @@ snapshots: '@typescript-eslint/types@5.62.0': {} - '@typescript-eslint/types@6.21.0': {} + '@typescript-eslint/types@6.10.0': {} - '@typescript-eslint/types@7.18.0': {} + '@typescript-eslint/types@6.7.3': {} + + '@typescript-eslint/types@7.16.1': {} '@typescript-eslint/typescript-estree@5.62.0(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.7 + debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.3 + semver: 7.6.2 tsutils: 3.21.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@6.21.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2)': dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.7 + '@typescript-eslint/types': 6.10.0 + '@typescript-eslint/visitor-keys': 6.10.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.6.2 + ts-api-utils: 1.0.3(typescript@5.2.2) + optionalDependencies: + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@6.7.3(typescript@5.6.3)': + dependencies: + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/visitor-keys': 6.7.3 + debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - minimatch: 9.0.3 - semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) + semver: 7.6.2 + ts-api-utils: 1.0.3(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.18.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@7.16.1(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.7 + '@typescript-eslint/types': 7.16.1 + '@typescript-eslint/visitor-keys': 7.16.1 + debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) + minimatch: 9.0.4 + semver: 7.6.2 + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/utils@5.62.0(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@types/json-schema': 7.0.15 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@types/json-schema': 7.0.13 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.3) - eslint: 8.57.1 + eslint: 8.50.0 eslint-scope: 5.1.1 - semver: 7.6.3 + semver: 7.6.2 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/utils@6.10.0(eslint@8.53.0)(typescript@5.2.2)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) + '@types/json-schema': 7.0.13 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 6.10.0 + '@typescript-eslint/types': 6.10.0 + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) + eslint: 8.53.0 + semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@6.21.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/utils@6.7.3(eslint@8.50.0)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@types/json-schema': 7.0.15 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@types/json-schema': 7.0.13 '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) - eslint: 8.57.1 - semver: 7.6.3 + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.6.3) + eslint: 8.50.0 + semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@7.18.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/utils@7.16.1(eslint@8.57.0)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) - eslint: 8.57.1 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 7.16.1 + '@typescript-eslint/types': 7.16.1 + '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.6.3) + eslint: 8.57.0 transitivePeerDependencies: - supports-color - typescript @@ -14474,14 +15585,19 @@ snapshots: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@6.21.0': + '@typescript-eslint/visitor-keys@6.10.0': dependencies: - '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/types': 6.10.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@7.18.0': + '@typescript-eslint/visitor-keys@6.7.3': dependencies: - '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/types': 6.7.3 + eslint-visitor-keys: 3.4.3 + + '@typescript-eslint/visitor-keys@7.16.1': + dependencies: + '@typescript-eslint/types': 7.16.1 eslint-visitor-keys: 3.4.3 '@typescript/analyze-trace@0.10.1': @@ -14520,22 +15636,22 @@ snapshots: dependencies: '@vitest/spy': 1.6.0 '@vitest/utils': 1.6.0 - chai: 4.5.0 + chai: 4.4.1 - '@vitest/expect@2.1.4': + '@vitest/expect@2.1.2': dependencies: - '@vitest/spy': 2.1.4 - '@vitest/utils': 2.1.4 - chai: 5.1.2 + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.4(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0))': + '@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0))': dependencies: - '@vitest/spy': 2.1.4 + '@vitest/spy': 2.1.2 estree-walker: 3.0.3 - magic-string: 0.30.12 + magic-string: 0.30.11 optionalDependencies: - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) '@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.3.3(@types/node@22.9.1)(lightningcss@1.25.1)(terser@5.31.0))': dependencies: @@ -14555,28 +15671,28 @@ snapshots: p-limit: 5.0.0 pathe: 1.1.2 - '@vitest/runner@2.1.4': + '@vitest/runner@2.1.2': dependencies: - '@vitest/utils': 2.1.4 + '@vitest/utils': 2.1.2 pathe: 1.1.2 '@vitest/snapshot@1.6.0': dependencies: - magic-string: 0.30.12 + magic-string: 0.30.10 pathe: 1.1.2 pretty-format: 29.7.0 - '@vitest/snapshot@2.1.4': + '@vitest/snapshot@2.1.2': dependencies: - '@vitest/pretty-format': 2.1.4 - magic-string: 0.30.12 + '@vitest/pretty-format': 2.1.2 + magic-string: 0.30.11 pathe: 1.1.2 '@vitest/spy@1.6.0': dependencies: tinyspy: 2.2.1 - '@vitest/spy@2.1.4': + '@vitest/spy@2.1.2': dependencies: tinyspy: 3.0.2 @@ -14587,21 +15703,21 @@ snapshots: fflate: 0.8.2 flatted: 3.3.1 pathe: 1.1.2 - picocolors: 1.1.1 + picocolors: 1.0.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0) + vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) optional: true - '@vitest/ui@1.6.0(vitest@2.1.4)': + '@vitest/ui@1.6.0(vitest@2.1.2)': dependencies: '@vitest/utils': 1.6.0 fast-glob: 3.3.2 fflate: 0.8.2 flatted: 3.3.1 pathe: 1.1.2 - picocolors: 1.1.1 + picocolors: 1.0.1 sirv: 2.0.4 - vitest: 2.1.4(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0) + vitest: 2.1.2(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) '@vitest/utils@1.6.0': dependencies: @@ -14610,13 +15726,13 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 - '@vitest/utils@2.1.4': + '@vitest/utils@2.1.2': dependencies: - '@vitest/pretty-format': 2.1.4 + '@vitest/pretty-format': 2.1.2 loupe: 3.1.2 tinyrainbow: 1.2.0 - '@xata.io/client@0.29.5(typescript@5.6.3)': + '@xata.io/client@0.29.4(typescript@5.6.3)': dependencies: typescript: 5.6.3 @@ -14636,19 +15752,25 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-jsx@5.3.2(acorn@8.14.0): + acorn-jsx@5.3.2(acorn@8.10.0): dependencies: - acorn: 8.14.0 + acorn: 8.10.0 - acorn-walk@8.3.4: + acorn-jsx@5.3.2(acorn@8.11.3): dependencies: - acorn: 8.14.0 + acorn: 8.11.3 + + acorn-walk@8.3.2: {} - acorn@8.14.0: {} + acorn@8.10.0: {} + + acorn@8.11.3: {} + + acorn@8.8.2: {} agent-base@6.0.2: dependencies: - debug: 4.3.7 + debug: 4.3.4 transitivePeerDependencies: - supports-color @@ -14682,7 +15804,9 @@ snapshots: dependencies: type-fest: 0.21.3 - ansi-escapes@6.2.1: {} + ansi-escapes@6.2.0: + dependencies: + type-fest: 3.13.1 ansi-escapes@7.0.0: dependencies: @@ -14690,13 +15814,15 @@ snapshots: ansi-fragments@0.2.1: dependencies: - environment: 1.1.0 + colorette: 1.4.0 + slice-ansi: 2.1.0 + strip-ansi: 5.2.0 ansi-regex@4.1.1: {} ansi-regex@5.0.1: {} - ansi-regex@6.1.0: {} + ansi-regex@6.0.1: {} ansi-regex@6.1.0: {} @@ -14721,6 +15847,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + appdirsjs@1.2.7: {} + application-config-path@0.1.1: {} aproba@2.0.0: @@ -14744,6 +15872,11 @@ snapshots: argsarray@0.0.1: {} + array-buffer-byte-length@1.0.0: + dependencies: + call-bind: 1.0.2 + is-array-buffer: 3.0.2 + array-buffer-byte-length@1.0.1: dependencies: call-bind: 1.0.7 @@ -14753,39 +15886,46 @@ snapshots: array-flatten@1.1.1: {} - array-includes@3.1.8: + array-includes@3.1.6: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + get-intrinsic: 1.2.1 is-string: 1.0.7 array-union@2.1.0: {} - array.prototype.findlastindex@1.2.5: + array.prototype.findlastindex@1.2.2: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - es-object-atoms: 1.0.0 - es-shim-unscopables: 1.0.2 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 + get-intrinsic: 1.2.1 - array.prototype.flat@1.3.2: + array.prototype.flat@1.3.1: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-shim-unscopables: 1.0.2 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 - array.prototype.flatmap@1.3.2: + array.prototype.flatmap@1.3.1: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-shim-unscopables: 1.0.2 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 + + arraybuffer.prototype.slice@1.0.1: + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.2.0 + get-intrinsic: 1.2.1 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 arraybuffer.prototype.slice@1.0.3: dependencies: @@ -14836,17 +15976,17 @@ snapshots: at-least-node@1.0.0: {} - ava@5.3.1: + ava@5.3.0(@ava/typescript@5.0.0): dependencies: - acorn: 8.14.0 - acorn-walk: 8.3.4 + acorn: 8.11.3 + acorn-walk: 8.3.2 ansi-styles: 6.2.1 arrgv: 1.0.2 arrify: 3.0.0 - callsites: 4.2.0 + callsites: 4.1.0 cbor: 8.1.0 chalk: 5.3.0 - chokidar: 3.6.0 + chokidar: 3.5.3 chunkd: 2.0.1 ci-info: 3.9.0 ci-parallel-vars: 1.0.1 @@ -14856,7 +15996,7 @@ snapshots: common-path-prefix: 3.0.0 concordance: 5.0.4 currently-unhandled: 0.4.1 - debug: 4.3.7 + debug: 4.3.4 emittery: 1.0.3 figures: 5.0.0 globby: 13.2.2 @@ -14881,145 +16021,80 @@ snapshots: temp-dir: 3.0.0 write-file-atomic: 5.0.1 yargs: 17.7.2 + optionalDependencies: + '@ava/typescript': 5.0.0 transitivePeerDependencies: - supports-color + available-typed-arrays@1.0.5: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 - aws4fetch@1.0.20: {} + aws-ssl-profiles@1.1.1: + optional: true - axios@1.7.7: + axios@1.6.8: dependencies: - follow-redirects: 1.15.9 - form-data: 4.0.1 + follow-redirects: 1.15.6 + form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug - babel-core@7.0.0-bridge.0(@babel/core@7.26.0): + babel-core@7.0.0-bridge.0(@babel/core@7.24.6): dependencies: - '@babel/core': 7.26.0 + '@babel/core': 7.24.6 - babel-jest@29.7.0(@babel/core@7.26.0): + babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.6): dependencies: - '@babel/core': 7.26.0 - '@jest/transform': 29.7.0 - '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.26.0) - chalk: 4.1.2 - graceful-fs: 4.2.11 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - - babel-plugin-istanbul@6.1.1: - dependencies: - '@babel/helper-plugin-utils': 7.25.9 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - - babel-plugin-jest-hoist@29.6.3: - dependencies: - '@babel/template': 7.25.9 - '@babel/types': 7.26.0 - '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.20.6 - - babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.26.0): - dependencies: - '@babel/compat-data': 7.26.2 - '@babel/core': 7.26.0 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) + '@babel/compat-data': 7.24.6 + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.26.0): + babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.6): dependencies: - '@babel/core': 7.26.0 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) - core-js-compat: 3.39.0 + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) + core-js-compat: 3.37.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.26.0): + babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.24.6): dependencies: - '@babel/core': 7.26.0 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.6) transitivePeerDependencies: - supports-color - babel-plugin-react-compiler@0.0.0-experimental-592953e-20240517: - dependencies: - '@babel/generator': 7.2.0 - '@babel/types': 7.26.0 - chalk: 4.1.2 - invariant: 2.2.4 - pretty-format: 24.9.0 - zod: 3.23.8 - zod-validation-error: 2.1.0(zod@3.23.8) - - babel-plugin-react-native-web@0.19.13: {} - - babel-plugin-syntax-hermes-parser@0.23.1: - dependencies: - hermes-parser: 0.23.1 + babel-plugin-react-native-web@0.19.12: {} - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.26.0): + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.24.6): dependencies: - '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-flow': 7.24.6(@babel/core@7.24.6) transitivePeerDependencies: - '@babel/core' - babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.0): - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.0) - '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.0) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0) - - babel-preset-expo@11.0.15(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)): - dependencies: - '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/preset-react': 7.25.9(@babel/core@7.26.0) - '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) - '@react-native/babel-preset': 0.74.87(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - babel-plugin-react-compiler: 0.0.0-experimental-592953e-20240517 - babel-plugin-react-native-web: 0.19.13 + babel-preset-expo@11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)): + dependencies: + '@babel/plugin-proposal-decorators': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-export-namespace-from': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-object-rest-spread': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.6) + '@babel/preset-react': 7.24.6(@babel/core@7.24.6) + '@babel/preset-typescript': 7.24.6(@babel/core@7.24.6) + '@react-native/babel-preset': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + babel-plugin-react-native-web: 0.19.12 react-refresh: 0.14.2 transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' - supports-color - babel-preset-jest@29.6.3(@babel/core@7.26.0): - dependencies: - '@babel/core': 7.26.0 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) - balanced-match@1.0.2: {} base64-js@1.5.1: {} @@ -15049,7 +16124,7 @@ snapshots: big-integer@1.6.52: {} - binary-extensions@2.3.0: {} + binary-extensions@2.2.0: {} bindings@1.5.0: dependencies: @@ -15065,7 +16140,7 @@ snapshots: blueimp-md5@2.19.0: {} - body-parser@1.20.3: + body-parser@1.20.2: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -15075,7 +16150,7 @@ snapshots: http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.13.0 + qs: 6.11.0 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 @@ -15084,10 +16159,6 @@ snapshots: bowser@2.11.0: {} - bplist-creator@0.0.7: - dependencies: - stream-buffers: 2.2.0 - bplist-creator@0.1.0: dependencies: stream-buffers: 2.2.0 @@ -15113,12 +16184,12 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.24.2: + browserslist@4.23.0: dependencies: - caniuse-lite: 1.0.30001679 - electron-to-chromium: 1.5.55 - node-releases: 2.0.18 - update-browserslist-db: 1.1.1(browserslist@4.24.2) + caniuse-lite: 1.0.30001624 + electron-to-chromium: 1.4.783 + node-releases: 2.0.14 + update-browserslist-db: 1.0.16(browserslist@4.23.0) bser@2.1.1: dependencies: @@ -15142,7 +16213,7 @@ snapshots: bufferutil@4.0.8: dependencies: - node-gyp-build: 4.8.2 + node-gyp-build: 4.8.1 buildcheck@0.0.6: optional: true @@ -15153,29 +16224,28 @@ snapshots: builtins@5.1.0: dependencies: - semver: 7.6.3 + semver: 7.6.2 bun-types@0.6.14: {} - bun-types@1.1.34: - dependencies: - '@types/node': 20.12.14 - '@types/ws': 8.5.13 + bun-types@1.0.3: {} - bundle-require@4.2.1(esbuild@0.19.12): + bundle-require@4.0.2(esbuild@0.18.20): dependencies: - esbuild: 0.19.12 + esbuild: 0.18.20 load-tsconfig: 0.2.5 - bundle-require@5.0.0(esbuild@0.24.0): + bundle-require@5.0.0(esbuild@0.23.0): dependencies: - esbuild: 0.24.0 + esbuild: 0.23.0 load-tsconfig: 0.2.5 busboy@1.6.0: dependencies: streamsearch: 1.1.0 + bytes@3.0.0: {} + bytes@3.1.2: {} cac@6.7.14: {} @@ -15204,11 +16274,11 @@ snapshots: - bluebird optional: true - cacache@18.0.4: + cacache@18.0.3: dependencies: '@npmcli/fs': 3.1.1 fs-minipass: 3.0.3 - glob: 10.4.5 + glob: 10.4.1 lru-cache: 10.4.3 minipass: 7.1.2 minipass-collect: 2.0.1 @@ -15219,6 +16289,11 @@ snapshots: tar: 6.2.1 unique-filename: 3.0.0 + call-bind@1.0.2: + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.2.1 + call-bind@1.0.7: dependencies: es-define-property: 1.0.0 @@ -15239,7 +16314,7 @@ snapshots: callsites@3.1.0: {} - callsites@4.2.0: {} + callsites@4.1.0: {} camelcase@5.3.1: {} @@ -15247,7 +16322,7 @@ snapshots: camelcase@7.0.1: {} - caniuse-lite@1.0.30001679: {} + caniuse-lite@1.0.30001624: {} capnp-ts@0.7.0: dependencies: @@ -15265,17 +16340,17 @@ snapshots: dependencies: nofilter: 3.1.0 - chai@4.5.0: + chai@4.4.1: dependencies: assertion-error: 1.1.0 check-error: 1.0.3 - deep-eql: 4.1.4 + deep-eql: 4.1.3 get-func-name: 2.0.2 loupe: 2.3.7 pathval: 1.1.1 - type-detect: 4.1.0 + type-detect: 4.0.8 - chai@5.1.2: + chai@5.1.1: dependencies: assertion-error: 2.0.1 check-error: 2.1.1 @@ -15306,7 +16381,7 @@ snapshots: check-error@2.1.1: {} - chokidar@3.6.0: + chokidar@3.5.3: dependencies: anymatch: 3.1.3 braces: 3.0.3 @@ -15318,9 +16393,17 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - chokidar@4.0.1: + chokidar@3.6.0: dependencies: - readdirp: 4.0.2 + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 chownr@1.1.4: {} @@ -15328,21 +16411,10 @@ snapshots: chrome-launcher@0.15.2: dependencies: - '@types/node': 20.17.6 - escape-string-regexp: 4.0.0 - is-wsl: 2.2.0 - lighthouse-logger: 1.4.2 - transitivePeerDependencies: - - supports-color - - chromium-edge-launcher@0.2.0: - dependencies: - '@types/node': 20.17.6 + '@types/node': 20.12.12 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 - mkdirp: 1.0.4 - rimraf: 3.0.2 transitivePeerDependencies: - supports-color @@ -15350,6 +16422,8 @@ snapshots: ci-info@2.0.0: {} + ci-info@3.8.0: {} + ci-info@3.9.0: {} ci-parallel-vars@1.0.1: {} @@ -15368,26 +16442,21 @@ snapshots: clean-yaml-object@0.1.0: {} - cli-color@2.0.4: + cli-color@2.0.3: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 + d: 1.0.1 + es5-ext: 0.10.62 es6-iterator: 2.0.3 - memoizee: 0.4.17 - timers-ext: 0.1.8 + memoizee: 0.4.15 + timers-ext: 0.1.7 cli-cursor@2.1.0: dependencies: restore-cursor: 2.0.0 - cli-highlight@2.1.11: + cli-cursor@3.1.0: dependencies: - chalk: 4.1.2 - highlight.js: 10.7.3 - mz: 2.7.0 - parse5: 5.1.1 - parse5-htmlparser2-tree-adapter: 6.0.1 - yargs: 16.2.0 + restore-cursor: 3.1.0 cli-highlight@2.1.11: dependencies: @@ -15400,7 +16469,7 @@ snapshots: cli-spinners@2.9.2: {} - cli-table3@0.6.5: + cli-table3@0.6.3: dependencies: string-width: 4.2.3 optionalDependencies: @@ -15417,6 +16486,12 @@ snapshots: slice-ansi: 5.0.0 string-width: 5.1.2 + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + cliui@7.0.4: dependencies: string-width: 4.2.3 @@ -15458,6 +16533,8 @@ snapshots: color-support@1.1.3: optional: true + colorette@1.4.0: {} + colorette@2.0.19: {} colors@1.4.0: {} @@ -15470,6 +16547,8 @@ snapshots: commander@10.0.1: {} + commander@11.0.0: {} + commander@12.1.0: {} commander@2.20.3: {} @@ -15486,6 +16565,22 @@ snapshots: component-type@1.2.2: {} + compressible@2.0.18: + dependencies: + mime-db: 1.52.0 + + compression@1.7.4: + dependencies: + accepts: 1.3.8 + bytes: 3.0.0 + compressible: 2.0.18 + debug: 2.6.9 + on-headers: 1.0.2 + safe-buffer: 5.1.2 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + concat-map@0.0.1: {} concordance@5.0.4: @@ -15496,10 +16591,10 @@ snapshots: js-string-escape: 1.0.1 lodash: 4.17.21 md5-hex: 3.0.1 - semver: 7.6.3 + semver: 7.6.2 well-known-symbols: 2.0.0 - concurrently@8.2.2: + concurrently@8.2.1: dependencies: chalk: 4.1.2 date-fns: 2.30.0 @@ -15511,7 +16606,7 @@ snapshots: tree-kill: 1.2.2 yargs: 17.7.2 - confbox@0.1.8: {} + confbox@0.1.7: {} connect@3.7.0: dependencies: @@ -15539,9 +16634,9 @@ snapshots: cookie-signature@1.0.6: {} - cookie@0.7.1: {} + cookie@0.5.0: {} - cookie@0.7.2: {} + cookie@0.6.0: {} copy-anything@3.0.5: dependencies: @@ -15554,12 +16649,7 @@ snapshots: core-js-compat@3.37.1: dependencies: - graceful-fs: 4.2.11 - p-event: 6.0.1 - - core-js-compat@3.39.0: - dependencies: - browserslist: 4.24.2 + browserslist: 4.23.0 core-util-is@1.0.3: {} @@ -15579,7 +16669,7 @@ snapshots: cpu-features@0.0.10: dependencies: buildcheck: 0.0.6 - nan: 2.22.0 + nan: 2.19.0 optional: true cpy-cli@5.0.0: @@ -15593,7 +16683,7 @@ snapshots: cp-file: 10.0.0 globby: 13.2.2 junk: 4.0.1 - micromatch: 4.0.8 + micromatch: 4.0.7 nested-error-stacks: 2.1.1 p-filter: 3.0.0 p-map: 6.0.0 @@ -15611,7 +16701,7 @@ snapshots: cross-env@7.0.3: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 cross-fetch@3.1.8(encoding@0.1.13): dependencies: @@ -15627,7 +16717,7 @@ snapshots: shebang-command: 1.2.0 which: 1.3.1 - cross-spawn@7.0.5: + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -15645,10 +16735,10 @@ snapshots: dependencies: array-find-index: 1.0.2 - d@1.0.2: + d@1.0.1: dependencies: - es5-ext: 0.10.64 - type: 2.7.3 + es5-ext: 0.10.62 + type: 1.2.0 dag-map@1.0.2: {} @@ -15676,14 +16766,16 @@ snapshots: date-fns@2.30.0: dependencies: - '@babel/runtime': 7.26.0 + '@babel/runtime': 7.22.10 - date-fns@4.1.0: {} + date-fns@3.6.0: {} date-time@3.1.0: dependencies: time-zone: 1.0.0 + dayjs@1.11.11: {} + debug@2.6.9: dependencies: ms: 2.0.0 @@ -15696,17 +16788,23 @@ snapshots: dependencies: ms: 2.1.2 + debug@4.3.5: + dependencies: + ms: 2.1.2 + debug@4.3.7: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 - deep-eql@4.1.4: + deep-eql@4.1.3: dependencies: - type-detect: 4.1.0 + type-detect: 4.0.8 deep-eql@5.0.2: {} @@ -15714,6 +16812,8 @@ snapshots: deep-is@0.1.4: {} + deepmerge@4.3.1: {} + default-gateway@4.2.0: dependencies: execa: 1.0.0 @@ -15731,6 +16831,11 @@ snapshots: define-lazy-prop@2.0.0: {} + define-properties@1.2.0: + dependencies: + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -15775,7 +16880,7 @@ snapshots: diff@4.0.2: {} - diff@5.2.0: {} + diff@5.1.0: {} difflib@0.2.4: dependencies: @@ -15787,19 +16892,10 @@ snapshots: docker-modem@3.0.8: dependencies: - debug: 4.3.7 - readable-stream: 3.6.2 - split-ca: 1.0.1 - ssh2: 1.16.0 - transitivePeerDependencies: - - supports-color - - docker-modem@5.0.3: - dependencies: - debug: 4.3.7 + debug: 4.3.4 readable-stream: 3.6.2 split-ca: 1.0.1 - ssh2: 1.16.0 + ssh2: 1.15.0 transitivePeerDependencies: - supports-color @@ -15861,33 +16957,33 @@ snapshots: drizzle-kit@0.19.13: dependencies: '@drizzle-team/studio': 0.0.5 - '@esbuild-kit/esm-loader': 2.6.5 + '@esbuild-kit/esm-loader': 2.5.5 camelcase: 7.0.1 chalk: 5.3.0 commander: 9.5.0 esbuild: 0.18.20 - esbuild-register: 3.6.0(esbuild@0.18.20) + esbuild-register: 3.5.0(esbuild@0.18.20) glob: 8.1.0 hanji: 0.0.5 json-diff: 0.9.0 minimatch: 7.4.6 - zod: 3.23.8 + zod: 3.23.7 transitivePeerDependencies: - supports-color drizzle-kit@0.25.0-b1faa33: dependencies: '@drizzle-team/brocli': 0.10.2 - '@esbuild-kit/esm-loader': 2.6.5 + '@esbuild-kit/esm-loader': 2.5.5 esbuild: 0.19.12 - esbuild-register: 3.6.0(esbuild@0.19.12) + esbuild-register: 3.5.0(esbuild@0.19.12) transitivePeerDependencies: - supports-color drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: - '@aws-sdk/client-rds-data': 3.687.0 - '@cloudflare/workers-types': 4.20241106.0 + '@aws-sdk/client-rds-data': 3.583.0 + '@cloudflare/workers-types': 4.20241004.0 '@libsql/client': 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': 0.10.3 '@opentelemetry/api': 1.8.0 @@ -15906,9 +17002,9 @@ snapshots: sql.js: 1.10.3 sqlite3: 5.1.7 - drizzle-prisma-generator@0.1.7: + drizzle-prisma-generator@0.1.4: dependencies: - '@prisma/generator-helper': 5.22.0 + '@prisma/generator-helper': 5.16.1 duplexer@0.1.2: {} @@ -15916,7 +17012,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.55: {} + electron-to-chromium@1.4.783: {} emittery@1.0.3: {} @@ -15928,8 +17024,6 @@ snapshots: encodeurl@1.0.2: {} - encodeurl@2.0.0: {} - encoding@0.1.13: dependencies: iconv-lite: 0.6.3 @@ -15946,7 +17040,7 @@ snapshots: env-paths@3.0.0: {} - environment@1.1.0: {} + envinfo@7.13.0: {} environment@1.1.0: {} @@ -15963,6 +17057,53 @@ snapshots: dependencies: stackframe: 1.3.4 + errorhandler@1.5.1: + dependencies: + accepts: 1.3.8 + escape-html: 1.0.3 + + es-abstract@1.22.1: + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.1 + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + es-set-tostringtag: 2.0.1 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.5 + get-intrinsic: 1.2.1 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has: 1.0.3 + has-property-descriptors: 1.0.0 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.5 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.12 + is-weakref: 1.0.2 + object-inspect: 1.12.3 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.5.0 + safe-array-concat: 1.0.0 + safe-regex-test: 1.0.0 + string.prototype.trim: 1.2.7 + string.prototype.trimend: 1.0.6 + string.prototype.trimstart: 1.0.6 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.11 + es-abstract@1.23.3: dependencies: array-buffer-byte-length: 1.0.1 @@ -15996,10 +17137,10 @@ snapshots: is-string: 1.0.7 is-typed-array: 1.1.13 is-weakref: 1.0.2 - object-inspect: 1.13.2 + object-inspect: 1.13.1 object-keys: 1.1.1 object.assign: 4.1.5 - regexp.prototype.flags: 1.5.3 + regexp.prototype.flags: 1.5.2 safe-array-concat: 1.1.2 safe-regex-test: 1.0.3 string.prototype.trim: 1.2.9 @@ -16022,15 +17163,21 @@ snapshots: dependencies: es-errors: 1.3.0 + es-set-tostringtag@2.0.1: + dependencies: + get-intrinsic: 1.2.1 + has: 1.0.3 + has-tostringtag: 1.0.0 + es-set-tostringtag@2.0.3: dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 hasown: 2.0.2 - es-shim-unscopables@1.0.2: + es-shim-unscopables@1.0.0: dependencies: - hasown: 2.0.2 + has: 1.0.3 es-to-primitive@1.2.1: dependencies: @@ -16038,30 +17185,29 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 - es5-ext@0.10.64: + es5-ext@0.10.62: dependencies: es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esniff: 2.0.1 + es6-symbol: 3.1.3 next-tick: 1.1.0 es6-iterator@2.0.3: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-symbol: 3.1.4 + d: 1.0.1 + es5-ext: 0.10.62 + es6-symbol: 3.1.3 - es6-symbol@3.1.4: + es6-symbol@3.1.3: dependencies: - d: 1.0.2 + d: 1.0.1 ext: 1.7.0 es6-weak-map@2.0.3: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 + d: 1.0.1 + es5-ext: 0.10.62 es6-iterator: 2.0.3 - es6-symbol: 3.1.4 + es6-symbol: 3.1.3 esbuild-android-64@0.14.54: optional: true @@ -16108,25 +17254,25 @@ snapshots: esbuild-netbsd-64@0.14.54: optional: true - esbuild-node-externals@1.15.0(esbuild@0.19.12): + esbuild-node-externals@1.14.0(esbuild@0.19.12): dependencies: esbuild: 0.19.12 find-up: 5.0.0 - tslib: 2.8.1 + tslib: 2.6.2 esbuild-openbsd-64@0.14.54: optional: true - esbuild-register@3.6.0(esbuild@0.18.20): + esbuild-register@3.5.0(esbuild@0.18.20): dependencies: - debug: 4.3.7 + debug: 4.3.4 esbuild: 0.18.20 transitivePeerDependencies: - supports-color - esbuild-register@3.6.0(esbuild@0.19.12): + esbuild-register@3.5.0(esbuild@0.19.12): dependencies: - debug: 4.3.7 + debug: 4.3.4 esbuild: 0.19.12 transitivePeerDependencies: - supports-color @@ -16243,6 +17389,32 @@ snapshots: '@esbuild/win32-ia32': 0.19.12 '@esbuild/win32-x64': 0.19.12 + esbuild@0.20.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.20.2 + '@esbuild/android-arm': 0.20.2 + '@esbuild/android-arm64': 0.20.2 + '@esbuild/android-x64': 0.20.2 + '@esbuild/darwin-arm64': 0.20.2 + '@esbuild/darwin-x64': 0.20.2 + '@esbuild/freebsd-arm64': 0.20.2 + '@esbuild/freebsd-x64': 0.20.2 + '@esbuild/linux-arm': 0.20.2 + '@esbuild/linux-arm64': 0.20.2 + '@esbuild/linux-ia32': 0.20.2 + '@esbuild/linux-loong64': 0.20.2 + '@esbuild/linux-mips64el': 0.20.2 + '@esbuild/linux-ppc64': 0.20.2 + '@esbuild/linux-riscv64': 0.20.2 + '@esbuild/linux-s390x': 0.20.2 + '@esbuild/linux-x64': 0.20.2 + '@esbuild/netbsd-x64': 0.20.2 + '@esbuild/openbsd-x64': 0.20.2 + '@esbuild/sunos-x64': 0.20.2 + '@esbuild/win32-arm64': 0.20.2 + '@esbuild/win32-ia32': 0.20.2 + '@esbuild/win32-x64': 0.20.2 + esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -16269,61 +17441,36 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - esbuild@0.23.1: - optionalDependencies: - '@esbuild/aix-ppc64': 0.23.1 - '@esbuild/android-arm': 0.23.1 - '@esbuild/android-arm64': 0.23.1 - '@esbuild/android-x64': 0.23.1 - '@esbuild/darwin-arm64': 0.23.1 - '@esbuild/darwin-x64': 0.23.1 - '@esbuild/freebsd-arm64': 0.23.1 - '@esbuild/freebsd-x64': 0.23.1 - '@esbuild/linux-arm': 0.23.1 - '@esbuild/linux-arm64': 0.23.1 - '@esbuild/linux-ia32': 0.23.1 - '@esbuild/linux-loong64': 0.23.1 - '@esbuild/linux-mips64el': 0.23.1 - '@esbuild/linux-ppc64': 0.23.1 - '@esbuild/linux-riscv64': 0.23.1 - '@esbuild/linux-s390x': 0.23.1 - '@esbuild/linux-x64': 0.23.1 - '@esbuild/netbsd-x64': 0.23.1 - '@esbuild/openbsd-arm64': 0.23.1 - '@esbuild/openbsd-x64': 0.23.1 - '@esbuild/sunos-x64': 0.23.1 - '@esbuild/win32-arm64': 0.23.1 - '@esbuild/win32-ia32': 0.23.1 - '@esbuild/win32-x64': 0.23.1 - - esbuild@0.24.0: + esbuild@0.23.0: optionalDependencies: - '@esbuild/aix-ppc64': 0.24.0 - '@esbuild/android-arm': 0.24.0 - '@esbuild/android-arm64': 0.24.0 - '@esbuild/android-x64': 0.24.0 - '@esbuild/darwin-arm64': 0.24.0 - '@esbuild/darwin-x64': 0.24.0 - '@esbuild/freebsd-arm64': 0.24.0 - '@esbuild/freebsd-x64': 0.24.0 - '@esbuild/linux-arm': 0.24.0 - '@esbuild/linux-arm64': 0.24.0 - '@esbuild/linux-ia32': 0.24.0 - '@esbuild/linux-loong64': 0.24.0 - '@esbuild/linux-mips64el': 0.24.0 - '@esbuild/linux-ppc64': 0.24.0 - '@esbuild/linux-riscv64': 0.24.0 - '@esbuild/linux-s390x': 0.24.0 - '@esbuild/linux-x64': 0.24.0 - '@esbuild/netbsd-x64': 0.24.0 - '@esbuild/openbsd-arm64': 0.24.0 - '@esbuild/openbsd-x64': 0.24.0 - '@esbuild/sunos-x64': 0.24.0 - '@esbuild/win32-arm64': 0.24.0 - '@esbuild/win32-ia32': 0.24.0 - '@esbuild/win32-x64': 0.24.0 - - escalade@3.2.0: {} + '@esbuild/aix-ppc64': 0.23.0 + '@esbuild/android-arm': 0.23.0 + '@esbuild/android-arm64': 0.23.0 + '@esbuild/android-x64': 0.23.0 + '@esbuild/darwin-arm64': 0.23.0 + '@esbuild/darwin-x64': 0.23.0 + '@esbuild/freebsd-arm64': 0.23.0 + '@esbuild/freebsd-x64': 0.23.0 + '@esbuild/linux-arm': 0.23.0 + '@esbuild/linux-arm64': 0.23.0 + '@esbuild/linux-ia32': 0.23.0 + '@esbuild/linux-loong64': 0.23.0 + '@esbuild/linux-mips64el': 0.23.0 + '@esbuild/linux-ppc64': 0.23.0 + '@esbuild/linux-riscv64': 0.23.0 + '@esbuild/linux-s390x': 0.23.0 + '@esbuild/linux-x64': 0.23.0 + '@esbuild/netbsd-x64': 0.23.0 + '@esbuild/openbsd-arm64': 0.23.0 + '@esbuild/openbsd-x64': 0.23.0 + '@esbuild/sunos-x64': 0.23.0 + '@esbuild/win32-arm64': 0.23.0 + '@esbuild/win32-ia32': 0.23.0 + '@esbuild/win32-x64': 0.23.0 + + escalade@3.1.1: {} + + escalade@3.1.2: {} escape-html@1.0.3: {} @@ -16335,52 +17482,50 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-prettier@9.1.0(eslint@8.57.1): + eslint-config-prettier@9.1.0(eslint@8.57.0): dependencies: - eslint: 8.57.1 + eslint: 8.57.0 eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 - is-core-module: 2.15.1 - resolve: 1.22.8 + is-core-module: 2.13.0 + resolve: 1.22.4 transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - eslint: 8.57.1 + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) + eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1): + eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0): dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 + array-includes: 3.1.6 + array.prototype.findlastindex: 1.2.2 + array.prototype.flat: 1.3.1 + array.prototype.flatmap: 1.3.1 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.1 + eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) - hasown: 2.0.2 - is-core-module: 2.15.1 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) + has: 1.0.3 + is-core-module: 2.13.0 is-glob: 4.0.3 minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.0 + object.fromentries: 2.0.6 + object.groupby: 1.0.0 + object.values: 1.1.6 semver: 6.3.1 - string.prototype.trimend: 1.0.8 - tsconfig-paths: 3.15.0 + tsconfig-paths: 3.14.2 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -16388,23 +17533,23 @@ snapshots: eslint-plugin-no-instanceof@1.0.1: {} - eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8): + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8): dependencies: - eslint: 8.57.1 + eslint: 8.57.0 prettier: 2.8.8 prettier-linter-helpers: 1.0.0 - synckit: 0.9.2 + synckit: 0.9.1 optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@8.57.1) + eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-plugin-unicorn@48.0.1(eslint@8.57.1): + eslint-plugin-unicorn@48.0.1(eslint@8.50.0): dependencies: - '@babel/helper-validator-identifier': 7.25.9 - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - ci-info: 3.9.0 + '@babel/helper-validator-identifier': 7.22.5 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + ci-info: 3.8.0 clean-regexp: 1.0.0 - eslint: 8.57.1 - esquery: 1.6.0 + eslint: 8.50.0 + esquery: 1.5.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 jsesc: 3.0.2 @@ -16413,15 +17558,15 @@ snapshots: read-pkg-up: 7.0.1 regexp-tree: 0.1.27 regjsparser: 0.10.0 - semver: 7.6.3 + semver: 7.6.2 strip-indent: 3.0.0 - eslint-plugin-unused-imports@3.2.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1): + eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0): dependencies: - eslint: 8.57.1 + eslint: 8.50.0 eslint-rule-composer: 0.3.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.6.3))(eslint@8.50.0)(typescript@5.6.3) eslint-rule-composer@0.3.0: {} @@ -16437,34 +17582,121 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint@8.57.1: + eslint-visitor-keys@4.0.0: {} + + eslint@8.50.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@eslint-community/regexpp': 4.9.0 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.50.0 + '@humanwhocodes/config-array': 0.11.11 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.22.0 + graphemer: 1.4.0 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + eslint@8.53.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) + '@eslint-community/regexpp': 4.9.0 + '@eslint/eslintrc': 2.1.3 + '@eslint/js': 8.53.0 + '@humanwhocodes/config-array': 0.11.13 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.22.0 + graphemer: 1.4.0 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + eslint@8.57.0: dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.1 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.9.0 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.5 - debug: 4.3.7 + cross-spawn: 7.0.3 + debug: 4.3.4 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.6.0 + esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.24.0 + globals: 13.22.0 graphemer: 1.4.0 - ignore: 5.3.2 + ignore: 5.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -16474,7 +17706,7 @@ snapshots: lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.4 + optionator: 0.9.3 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: @@ -16482,22 +17714,21 @@ snapshots: esm@3.2.25: {} - esniff@2.0.1: + espree@10.0.1: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-emitter: 0.3.5 - type: 2.7.3 + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) + eslint-visitor-keys: 4.0.0 espree@9.6.1: dependencies: - acorn: 8.14.0 - acorn-jsx: 5.3.2(acorn@8.14.0) + acorn: 8.10.0 + acorn-jsx: 5.3.2(acorn@8.10.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} - esquery@1.6.0: + esquery@1.5.0: dependencies: estraverse: 5.3.0 @@ -16515,7 +17746,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.5 esutils@2.0.3: {} @@ -16523,8 +17754,8 @@ snapshots: event-emitter@0.3.5: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 + d: 1.0.1 + es5-ext: 0.10.62 event-stream@3.3.4: dependencies: @@ -16552,7 +17783,7 @@ snapshots: execa@5.1.1: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -16564,7 +17795,7 @@ snapshots: execa@6.1.0: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 get-stream: 6.0.1 human-signals: 3.0.1 is-stream: 3.0.0 @@ -16576,7 +17807,7 @@ snapshots: execa@8.0.1: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 get-stream: 8.0.1 human-signals: 5.0.0 is-stream: 3.0.0 @@ -16592,72 +17823,68 @@ snapshots: expand-template@2.0.3: {} - expect-type@1.1.0: {} - - expo-asset@10.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-constants: 16.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + '@react-native/assets-registry': 0.74.83 + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - '@expo/config': 9.0.4 - '@expo/env': 0.3.0 - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@expo/config': 9.0.2 + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-font@12.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-modules-autolinking@1.11.3: + expo-modules-autolinking@1.11.1: dependencies: chalk: 4.1.2 commander: 7.2.0 fast-glob: 3.3.2 find-up: 5.0.0 fs-extra: 9.1.0 - require-from-string: 2.0.2 - resolve-from: 5.0.0 - expo-modules-core@1.12.26: + expo-modules-core@1.12.11: dependencies: invariant: 2.2.4 - expo-sqlite@14.0.6(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-sqlite@14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - - expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): - dependencies: - '@babel/runtime': 7.26.0 - '@expo/cli': 0.18.30(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.3)(utf-8-validate@6.0.3) - '@expo/config': 9.0.4 - '@expo/config-plugins': 8.0.10 - '@expo/metro-config': 0.18.11 - '@expo/vector-icons': 14.0.4 - babel-preset-expo: 11.0.15(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - expo-asset: 10.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-file-system: 17.0.1(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-font: 12.0.10(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-keep-awake: 13.0.2(expo@51.0.38(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-modules-autolinking: 1.11.3 - expo-modules-core: 1.12.26 + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): + dependencies: + '@babel/runtime': 7.24.6 + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) + '@expo/config': 9.0.2 + '@expo/config-plugins': 8.0.4 + '@expo/metro-config': 0.18.4 + '@expo/vector-icons': 14.0.2 + babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-modules-autolinking: 1.11.1 + expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) whatwg-url-without-unicode: 8.0.0-3 transitivePeerDependencies: @@ -16668,36 +17895,34 @@ snapshots: - supports-color - utf-8-validate - exponential-backoff@3.1.1: {} - - express@4.21.1: + express@4.19.2: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.3 + body-parser: 1.20.2 content-disposition: 0.5.4 content-type: 1.0.5 - cookie: 0.7.1 + cookie: 0.6.0 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 - encodeurl: 2.0.0 + encodeurl: 1.0.2 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.3.1 + finalhandler: 1.2.0 fresh: 0.5.2 http-errors: 2.0.0 - merge-descriptors: 1.0.3 + merge-descriptors: 1.0.1 methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.10 + path-to-regexp: 0.1.7 proxy-addr: 2.0.7 - qs: 6.13.0 + qs: 6.11.0 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.19.0 - serve-static: 1.16.2 + send: 0.18.0 + serve-static: 1.15.0 setprototypeof: 1.2.0 statuses: 2.0.1 type-is: 1.6.18 @@ -16708,29 +17933,41 @@ snapshots: ext@1.7.0: dependencies: - type: 2.7.3 + type: 2.7.2 fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.7 + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.8 + micromatch: 4.0.7 fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} - fast-xml-parser@4.4.1: + fast-xml-parser@4.2.5: + dependencies: + strnum: 1.0.5 + + fast-xml-parser@4.4.0: dependencies: strnum: 1.0.5 - fastq@1.17.1: + fastq@1.15.0: dependencies: reusify: 1.0.4 @@ -16754,18 +17991,14 @@ snapshots: object-assign: 4.1.1 promise: 7.3.1 setimmediate: 1.0.5 - ua-parser-js: 1.0.39 + ua-parser-js: 1.0.38 transitivePeerDependencies: - encoding - fdir@6.4.2(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - fetch-blob@3.2.0: dependencies: node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 + web-streams-polyfill: 3.2.1 fetch-retry@4.1.1: {} @@ -16778,7 +18011,7 @@ snapshots: file-entry-cache@6.0.1: dependencies: - flat-cache: 3.2.0 + flat-cache: 3.1.0 file-uri-to-path@1.0.0: {} @@ -16798,10 +18031,10 @@ snapshots: transitivePeerDependencies: - supports-color - finalhandler@1.3.1: + finalhandler@1.2.0: dependencies: debug: 2.6.9 - encodeurl: 2.0.0 + encodeurl: 1.0.2 escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 @@ -16839,19 +18072,21 @@ snapshots: dependencies: micromatch: 4.0.8 - flat-cache@3.2.0: + flat-cache@3.1.0: dependencies: - flatted: 3.3.1 - keyv: 4.5.4 + flatted: 3.2.9 + keyv: 4.5.3 rimraf: 3.0.2 + flatted@3.2.9: {} + flatted@3.3.1: {} flow-enums-runtime@0.0.6: {} - flow-parser@0.252.0: {} + flow-parser@0.236.0: {} - follow-redirects@1.15.9: {} + follow-redirects@1.15.6: {} fontfaceobserver@2.3.0: {} @@ -16859,18 +18094,18 @@ snapshots: dependencies: is-callable: 1.2.7 - foreground-child@3.3.0: + foreground-child@3.1.1: dependencies: - cross-spawn: 7.0.5 - signal-exit: 4.1.0 + cross-spawn: 7.0.3 + signal-exit: 4.0.2 - form-data@3.0.2: + form-data@3.0.1: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - form-data@4.0.1: + form-data@4.0.0: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 @@ -16890,7 +18125,7 @@ snapshots: fs-constants@1.0.0: {} - fs-extra@11.2.0: + fs-extra@11.1.1: dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 @@ -16929,8 +18164,17 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.1: {} + function-bind@1.1.2: {} + function.prototype.name@1.1.5: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + functions-have-names: 1.2.3 + function.prototype.name@1.1.6: dependencies: call-bind: 1.0.7 @@ -16940,7 +18184,7 @@ snapshots: functions-have-names@1.2.3: {} - fx@35.0.0: {} + fx@28.0.0: {} gauge@4.0.4: dependencies: @@ -16964,6 +18208,13 @@ snapshots: get-func-name@2.0.2: {} + get-intrinsic@1.2.1: + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-proto: 1.0.1 + has-symbols: 1.0.3 + get-intrinsic@1.2.4: dependencies: es-errors: 1.3.0 @@ -16987,19 +18238,24 @@ snapshots: get-stream@4.1.0: dependencies: - pump: 3.0.2 + pump: 3.0.0 get-stream@6.0.1: {} get-stream@8.0.1: {} + get-symbol-description@1.0.0: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + get-symbol-description@1.0.2: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 - get-tsconfig@4.8.1: + get-tsconfig@4.7.5: dependencies: resolve-pkg-maps: 1.0.0 @@ -17019,15 +18275,31 @@ snapshots: glob-to-regexp@0.4.1: {} - glob@10.4.5: + glob@10.3.10: dependencies: - foreground-child: 3.3.0 - jackspeak: 3.4.3 - minimatch: 9.0.5 + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.4 + minipass: 5.0.0 + path-scurry: 1.10.1 + + glob@10.4.1: + dependencies: + foreground-child: 3.1.1 + jackspeak: 3.1.2 + minimatch: 9.0.4 minipass: 7.1.2 - package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@6.0.4: + dependencies: + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + optional: true + glob@7.1.6: dependencies: fs.realpath: 1.0.0 @@ -17056,10 +18328,16 @@ snapshots: globals@11.12.0: {} - globals@13.24.0: + globals@13.22.0: dependencies: type-fest: 0.20.2 + globals@14.0.0: {} + + globalthis@1.0.3: + dependencies: + define-properties: 1.2.0 + globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -17069,8 +18347,8 @@ snapshots: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.2 + fast-glob: 3.3.1 + ignore: 5.3.1 merge2: 1.4.1 slash: 3.0.0 @@ -17078,7 +18356,7 @@ snapshots: dependencies: dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.2 + ignore: 5.3.1 merge2: 1.4.1 slash: 4.0.0 @@ -17095,7 +18373,7 @@ snapshots: gopd@1.0.1: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.1 graceful-fs@4.2.11: {} @@ -17119,14 +18397,24 @@ snapshots: has-flag@4.0.0: {} + has-property-descriptors@1.0.0: + dependencies: + get-intrinsic: 1.2.1 + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.0 + has-proto@1.0.1: {} + has-proto@1.0.3: {} has-symbols@1.0.3: {} + has-tostringtag@1.0.0: + dependencies: + has-symbols: 1.0.3 + has-tostringtag@1.0.2: dependencies: has-symbols: 1.0.3 @@ -17134,6 +18422,10 @@ snapshots: has-unicode@2.0.1: optional: true + has@1.0.3: + dependencies: + function-bind: 1.1.1 + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -17142,27 +18434,25 @@ snapshots: hermes-estree@0.19.1: {} - hermes-estree@0.23.1: {} - - hermes-estree@0.24.0: {} + hermes-estree@0.20.1: {} hermes-parser@0.19.1: dependencies: hermes-estree: 0.19.1 - hermes-parser@0.23.1: + hermes-parser@0.20.1: dependencies: - hermes-estree: 0.23.1 + hermes-estree: 0.20.1 - hermes-parser@0.24.0: + hermes-profile-transformer@0.0.6: dependencies: - hermes-estree: 0.24.0 + source-map: 0.7.4 highlight.js@10.7.3: {} hono@4.0.1: {} - hono@4.6.9: {} + hono@4.5.0: {} hosted-git-info@2.8.9: {} @@ -17185,7 +18475,7 @@ snapshots: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.3.4 transitivePeerDependencies: - supports-color optional: true @@ -17193,7 +18483,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.3.4 transitivePeerDependencies: - supports-color @@ -17220,7 +18510,9 @@ snapshots: ignore-by-default@2.1.0: {} - ignore@5.3.2: {} + ignore@5.2.4: {} + + ignore@5.3.1: {} image-size@1.1.1: dependencies: @@ -17261,6 +18553,12 @@ snapshots: default-gateway: 4.2.0 ipaddr.js: 1.9.1 + internal-slot@1.0.5: + dependencies: + get-intrinsic: 1.2.1 + has: 1.0.3 + side-channel: 1.0.4 + internal-slot@1.0.7: dependencies: es-errors: 1.3.0 @@ -17285,6 +18583,12 @@ snapshots: irregular-plurals@3.5.0: {} + is-array-buffer@3.0.2: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-typed-array: 1.1.12 + is-array-buffer@3.0.4: dependencies: call-bind: 1.0.7 @@ -17298,12 +18602,12 @@ snapshots: is-binary-path@2.1.0: dependencies: - binary-extensions: 2.3.0 + binary-extensions: 2.2.0 is-boolean-object@1.1.2: dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 + call-bind: 1.0.2 + has-tostringtag: 1.0.0 is-buffer@1.1.6: {} @@ -17313,7 +18617,19 @@ snapshots: is-callable@1.2.7: {} - is-core-module@2.15.1: + is-core-module@2.11.0: + dependencies: + has: 1.0.3 + + is-core-module@2.12.1: + dependencies: + has: 1.0.3 + + is-core-module@2.13.0: + dependencies: + has: 1.0.3 + + is-core-module@2.13.1: dependencies: hasown: 2.0.2 @@ -17323,7 +18639,7 @@ snapshots: is-date-object@1.0.5: dependencies: - has-tostringtag: 1.0.2 + has-tostringtag: 1.0.0 is-directory@0.3.1: {} @@ -17335,6 +18651,8 @@ snapshots: is-extglob@2.1.1: {} + is-fullwidth-code-point@2.0.0: {} + is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@4.0.0: {} @@ -17347,6 +18665,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-interactive@1.0.0: {} + is-invalid-path@0.1.0: dependencies: is-glob: 2.0.1 @@ -17354,11 +18674,13 @@ snapshots: is-lambda@1.0.1: optional: true + is-negative-zero@2.0.2: {} + is-negative-zero@2.0.3: {} is-number-object@1.0.7: dependencies: - has-tostringtag: 1.0.2 + has-tostringtag: 1.0.0 is-number@7.0.0: {} @@ -17380,8 +18702,12 @@ snapshots: is-regex@1.1.4: dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + + is-shared-array-buffer@1.0.2: + dependencies: + call-bind: 1.0.2 is-shared-array-buffer@1.0.3: dependencies: @@ -17395,16 +18721,22 @@ snapshots: is-string@1.0.7: dependencies: - has-tostringtag: 1.0.2 + has-tostringtag: 1.0.0 is-symbol@1.0.4: dependencies: has-symbols: 1.0.3 + is-typed-array@1.1.12: + dependencies: + which-typed-array: 1.1.11 + is-typed-array@1.1.13: dependencies: which-typed-array: 1.1.15 + is-unicode-supported@0.1.0: {} + is-unicode-supported@1.3.0: {} is-valid-path@0.1.1: @@ -17413,10 +18745,12 @@ snapshots: is-weakref@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.2 is-what@4.1.16: {} + is-wsl@1.1.0: {} + is-wsl@2.2.0: dependencies: is-docker: 2.2.1 @@ -17429,21 +18763,13 @@ snapshots: isobject@3.0.1: {} - istanbul-lib-coverage@3.2.2: {} - - istanbul-lib-instrument@5.2.1: + jackspeak@2.3.6: dependencies: - '@babel/core': 7.26.0 - '@babel/parser': 7.26.2 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - itty-time@1.0.6: {} + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 - jackspeak@3.4.3: + jackspeak@3.1.2: dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: @@ -17456,31 +18782,15 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.6 + '@types/node': 20.12.12 jest-mock: 29.7.0 jest-util: 29.7.0 jest-get-type@29.6.3: {} - jest-haste-map@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.9 - '@types/node': 20.17.6 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.11 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 - micromatch: 4.0.8 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 - jest-message-util@29.7.0: dependencies: - '@babel/code-frame': 7.26.2 + '@babel/code-frame': 7.24.6 '@jest/types': 29.6.3 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -17493,15 +18803,13 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.6 + '@types/node': 20.12.12 jest-util: 29.7.0 - jest-regex-util@29.6.3: {} - jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.6 + '@types/node': 20.12.12 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -17518,16 +18826,24 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 20.17.6 + '@types/node': 20.12.12 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 jimp-compact@0.16.1: {} + joi@17.13.1: + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + join-component@1.1.0: {} - jose@4.15.9: {} + jose@4.15.5: {} jose@5.2.3: {} @@ -17557,21 +18873,21 @@ snapshots: jsc-safe-url@0.2.4: {} - jscodeshift@0.14.0(@babel/preset-env@7.26.0(@babel/core@7.26.0)): - dependencies: - '@babel/core': 7.26.0 - '@babel/parser': 7.26.2 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/preset-env': 7.26.0(@babel/core@7.26.0) - '@babel/preset-flow': 7.25.9(@babel/core@7.26.0) - '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) - '@babel/register': 7.25.9(@babel/core@7.26.0) - babel-core: 7.0.0-bridge.0(@babel/core@7.26.0) + jscodeshift@0.14.0(@babel/preset-env@7.24.6(@babel/core@7.24.6)): + dependencies: + '@babel/core': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.6) + '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6) + '@babel/preset-env': 7.24.6(@babel/core@7.24.6) + '@babel/preset-flow': 7.24.6(@babel/core@7.24.6) + '@babel/preset-typescript': 7.24.6(@babel/core@7.24.6) + '@babel/register': 7.24.6(@babel/core@7.24.6) + babel-core: 7.0.0-bridge.0(@babel/core@7.24.6) chalk: 4.1.2 - flow-parser: 0.252.0 + flow-parser: 0.236.0 graceful-fs: 4.2.11 micromatch: 4.0.8 neo-async: 2.6.2 @@ -17592,7 +18908,7 @@ snapshots: json-diff@0.9.0: dependencies: - cli-color: 2.0.4 + cli-color: 2.0.3 difflib: 0.2.4 dreamopt: 0.8.0 @@ -17614,7 +18930,7 @@ snapshots: lodash: 4.17.21 md5: 2.2.1 memory-cache: 0.2.0 - traverse: 0.6.10 + traverse: 0.6.9 valid-url: 1.0.9 json-schema-traverse@0.4.1: {} @@ -17633,7 +18949,7 @@ snapshots: jsonfile@6.1.0: dependencies: - universalify: 2.0.1 + universalify: 2.0.0 optionalDependencies: graceful-fs: 4.2.11 @@ -17646,7 +18962,7 @@ snapshots: junk@4.0.1: {} - keyv@4.5.4: + keyv@4.5.3: dependencies: json-buffer: 3.0.1 @@ -17686,32 +19002,7 @@ snapshots: colorette: 2.0.19 commander: 10.0.1 debug: 4.3.4 - escalade: 3.2.0 - esm: 3.2.25 - get-package-type: 0.1.0 - getopts: 2.3.0 - interpret: 2.2.0 - lodash: 4.17.21 - pg-connection-string: 2.6.1 - rechoir: 0.8.0 - resolve-from: 5.0.0 - tarn: 3.0.2 - tildify: 2.0.0 - optionalDependencies: - better-sqlite3: 11.5.0 - mysql2: 3.3.3 - pg: 8.13.1 - sqlite3: 5.1.7 - transitivePeerDependencies: - - supports-color - optional: true - - knex@2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.13.1)(sqlite3@5.1.7): - dependencies: - colorette: 2.0.19 - commander: 10.0.1 - debug: 4.3.4 - escalade: 3.2.0 + escalade: 3.1.2 esm: 3.2.25 get-package-type: 0.1.0 getopts: 2.3.0 @@ -17725,7 +19016,7 @@ snapshots: optionalDependencies: better-sqlite3: 8.7.0 mysql2: 3.3.3 - pg: 8.13.1 + pg: 8.11.5 sqlite3: 5.1.7 transitivePeerDependencies: - supports-color @@ -17739,18 +19030,32 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - libsql@0.4.7: + libsql@0.3.19: + dependencies: + '@neon-rs/load': 0.0.4 + detect-libc: 2.0.2 + optionalDependencies: + '@libsql/darwin-arm64': 0.3.19 + '@libsql/darwin-x64': 0.3.19 + '@libsql/linux-arm64-gnu': 0.3.19 + '@libsql/linux-arm64-musl': 0.3.19 + '@libsql/linux-x64-gnu': 0.3.19 + '@libsql/linux-x64-musl': 0.3.19 + '@libsql/win32-x64-msvc': 0.3.19 + + libsql@0.4.1: dependencies: '@neon-rs/load': 0.0.4 detect-libc: 2.0.2 + libsql: 0.3.19 optionalDependencies: - '@libsql/darwin-arm64': 0.4.7 - '@libsql/darwin-x64': 0.4.7 - '@libsql/linux-arm64-gnu': 0.4.7 - '@libsql/linux-arm64-musl': 0.4.7 - '@libsql/linux-x64-gnu': 0.4.7 - '@libsql/linux-x64-musl': 0.4.7 - '@libsql/win32-x64-msvc': 0.4.7 + '@libsql/darwin-arm64': 0.4.1 + '@libsql/darwin-x64': 0.4.1 + '@libsql/linux-arm64-gnu': 0.4.1 + '@libsql/linux-arm64-musl': 0.4.1 + '@libsql/linux-x64-gnu': 0.4.1 + '@libsql/linux-x64-musl': 0.4.1 + '@libsql/win32-x64-msvc': 0.4.1 lighthouse-logger@1.4.2: dependencies: @@ -17762,27 +19067,54 @@ snapshots: lightningcss-darwin-arm64@1.19.0: optional: true + lightningcss-darwin-arm64@1.25.1: + optional: true + lightningcss-darwin-x64@1.19.0: optional: true + lightningcss-darwin-x64@1.25.1: + optional: true + + lightningcss-freebsd-x64@1.25.1: + optional: true + lightningcss-linux-arm-gnueabihf@1.19.0: optional: true + lightningcss-linux-arm-gnueabihf@1.25.1: + optional: true + lightningcss-linux-arm64-gnu@1.19.0: optional: true + lightningcss-linux-arm64-gnu@1.25.1: + optional: true + lightningcss-linux-arm64-musl@1.19.0: optional: true + lightningcss-linux-arm64-musl@1.25.1: + optional: true + lightningcss-linux-x64-gnu@1.19.0: optional: true + lightningcss-linux-x64-gnu@1.25.1: + optional: true + lightningcss-linux-x64-musl@1.19.0: optional: true + lightningcss-linux-x64-musl@1.25.1: + optional: true + lightningcss-win32-x64-msvc@1.19.0: optional: true + lightningcss-win32-x64-msvc@1.25.1: + optional: true + lightningcss@1.19.0: dependencies: detect-libc: 1.0.3 @@ -17796,6 +19128,23 @@ snapshots: lightningcss-linux-x64-musl: 1.19.0 lightningcss-win32-x64-msvc: 1.19.0 + lightningcss@1.25.1: + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.25.1 + lightningcss-darwin-x64: 1.25.1 + lightningcss-freebsd-x64: 1.25.1 + lightningcss-linux-arm-gnueabihf: 1.25.1 + lightningcss-linux-arm64-gnu: 1.25.1 + lightningcss-linux-arm64-musl: 1.25.1 + lightningcss-linux-x64-gnu: 1.25.1 + lightningcss-linux-x64-musl: 1.25.1 + lightningcss-win32-x64-msvc: 1.25.1 + optional: true + + lilconfig@2.1.0: {} + lilconfig@3.1.2: {} lines-and-columns@1.2.4: {} @@ -17806,8 +19155,8 @@ snapshots: local-pkg@0.5.0: dependencies: - mlly: 1.7.2 - pkg-types: 1.2.1 + mlly: 1.7.0 + pkg-types: 1.1.0 locate-path@3.0.0: dependencies: @@ -17840,6 +19189,17 @@ snapshots: dependencies: chalk: 2.4.2 + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + logkitty@0.7.1: + dependencies: + ansi-fragments: 0.2.1 + dayjs: 1.11.11 + yargs: 15.4.1 + long@5.2.3: {} loose-envify@1.4.0: @@ -17852,7 +19212,7 @@ snapshots: loupe@3.1.2: {} - lru-cache@10.4.3: {} + lru-cache@10.2.2: {} lru-cache@10.4.3: {} @@ -17868,15 +19228,21 @@ snapshots: lru-cache@8.0.5: {} + lru-cache@9.1.2: {} + lru-queue@0.1.0: dependencies: - es5-ext: 0.10.64 + es5-ext: 0.10.62 magic-string@0.25.9: dependencies: sourcemap-codec: 1.4.8 - magic-string@0.30.12: + magic-string@0.30.10: + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + + magic-string@0.30.11: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -17901,7 +19267,7 @@ snapshots: minipass-fetch: 1.4.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 - negotiator: 0.6.4 + negotiator: 0.6.3 promise-retry: 2.0.1 socks-proxy-agent: 6.2.1 ssri: 8.0.1 @@ -17922,24 +19288,13 @@ snapshots: marked-terminal@6.2.0(marked@9.1.6): dependencies: - ansi-escapes: 6.2.1 + ansi-escapes: 6.2.0 cardinal: 2.1.1 chalk: 5.3.0 - cli-table3: 0.6.5 - marked: 9.1.6 - node-emoji: 2.1.3 - supports-hyperlinks: 3.1.0 - - marked-terminal@7.2.1(marked@9.1.6): - dependencies: - ansi-escapes: 7.0.0 - ansi-regex: 6.1.0 - chalk: 5.3.0 - cli-highlight: 2.1.11 - cli-table3: 0.6.5 + cli-table3: 0.6.3 marked: 9.1.6 node-emoji: 2.1.3 - supports-hyperlinks: 3.1.0 + supports-hyperlinks: 3.0.0 marked-terminal@7.2.1(marked@9.1.6): dependencies: @@ -17991,22 +19346,22 @@ snapshots: memoize-one@5.2.1: {} - memoizee@0.4.17: + memoizee@0.4.15: dependencies: - d: 1.0.2 - es5-ext: 0.10.64 + d: 1.0.1 + es5-ext: 0.10.62 es6-weak-map: 2.0.3 event-emitter: 0.3.5 is-promise: 2.2.2 lru-queue: 0.1.0 next-tick: 1.1.0 - timers-ext: 0.1.8 + timers-ext: 0.1.7 memory-cache@0.2.0: {} meow@12.1.1: {} - merge-descriptors@1.0.3: {} + merge-descriptors@1.0.1: {} merge-stream@2.0.0: {} @@ -18014,52 +19369,46 @@ snapshots: methods@1.1.2: {} - metro-babel-transformer@0.81.0: + metro-babel-transformer@0.80.9: dependencies: - '@babel/core': 7.26.0 - flow-enums-runtime: 0.0.6 - hermes-parser: 0.24.0 + '@babel/core': 7.24.6 + hermes-parser: 0.20.1 nullthrows: 1.1.1 transitivePeerDependencies: - supports-color - metro-cache-key@0.81.0: - dependencies: - flow-enums-runtime: 0.0.6 + metro-cache-key@0.80.9: {} - metro-cache@0.81.0: + metro-cache@0.80.9: dependencies: - exponential-backoff: 3.1.1 - flow-enums-runtime: 0.0.6 - metro-core: 0.81.0 + metro-core: 0.80.9 + rimraf: 3.0.2 - metro-config@0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 - flow-enums-runtime: 0.0.6 jest-validate: 29.7.0 - metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - metro-cache: 0.81.0 - metro-core: 0.81.0 - metro-runtime: 0.81.0 + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-cache: 0.80.9 + metro-core: 0.80.9 + metro-runtime: 0.80.9 transitivePeerDependencies: - bufferutil + - encoding - supports-color - utf-8-validate - metro-core@0.81.0: + metro-core@0.80.9: dependencies: - flow-enums-runtime: 0.0.6 lodash.throttle: 4.1.1 - metro-resolver: 0.81.0 + metro-resolver: 0.80.9 - metro-file-map@0.81.0: + metro-file-map@0.80.9: dependencies: anymatch: 3.1.3 debug: 2.6.9 fb-watchman: 2.0.2 - flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 invariant: 2.2.4 jest-worker: 29.7.0 @@ -18072,40 +19421,33 @@ snapshots: transitivePeerDependencies: - supports-color - metro-minify-terser@0.81.0: + metro-minify-terser@0.80.9: dependencies: - flow-enums-runtime: 0.0.6 - terser: 5.36.0 + terser: 5.31.0 - metro-resolver@0.81.0: - dependencies: - flow-enums-runtime: 0.0.6 + metro-resolver@0.80.9: {} - metro-runtime@0.81.0: + metro-runtime@0.80.9: dependencies: - '@babel/runtime': 7.26.0 - flow-enums-runtime: 0.0.6 + '@babel/runtime': 7.24.6 - metro-source-map@0.81.0: + metro-source-map@0.80.9: dependencies: - '@babel/traverse': 7.25.9 - '@babel/traverse--for-generate-function-map': '@babel/traverse@7.25.9' - '@babel/types': 7.26.0 - flow-enums-runtime: 0.0.6 + '@babel/traverse': 7.24.6 + '@babel/types': 7.24.6 invariant: 2.2.4 - metro-symbolicate: 0.81.0 + metro-symbolicate: 0.80.9 nullthrows: 1.1.1 - ob1: 0.81.0 + ob1: 0.80.9 source-map: 0.5.7 vlq: 1.0.1 transitivePeerDependencies: - supports-color - metro-symbolicate@0.81.0: + metro-symbolicate@0.80.9: dependencies: - flow-enums-runtime: 0.0.6 invariant: 2.2.4 - metro-source-map: 0.81.0 + metro-source-map: 0.80.9 nullthrows: 1.1.1 source-map: 0.5.7 through2: 2.0.5 @@ -18113,46 +19455,45 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-plugins@0.81.0: + metro-transform-plugins@0.80.9: dependencies: - '@babel/core': 7.26.0 - '@babel/generator': 7.26.2 - '@babel/template': 7.25.9 - '@babel/traverse': 7.25.9 - flow-enums-runtime: 0.0.6 + '@babel/core': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/template': 7.24.6 + '@babel/traverse': 7.24.6 nullthrows: 1.1.1 transitivePeerDependencies: - supports-color - metro-transform-worker@0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): - dependencies: - '@babel/core': 7.26.0 - '@babel/generator': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - flow-enums-runtime: 0.0.6 - metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - metro-babel-transformer: 0.81.0 - metro-cache: 0.81.0 - metro-cache-key: 0.81.0 - metro-minify-terser: 0.81.0 - metro-source-map: 0.81.0 - metro-transform-plugins: 0.81.0 + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + dependencies: + '@babel/core': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-babel-transformer: 0.80.9 + metro-cache: 0.80.9 + metro-cache-key: 0.80.9 + metro-minify-terser: 0.80.9 + metro-source-map: 0.80.9 + metro-transform-plugins: 0.80.9 nullthrows: 1.1.1 transitivePeerDependencies: - bufferutil + - encoding - supports-color - utf-8-validate - metro@0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: - '@babel/code-frame': 7.26.2 - '@babel/core': 7.26.0 - '@babel/generator': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/template': 7.25.9 - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 + '@babel/code-frame': 7.24.6 + '@babel/core': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/template': 7.24.6 + '@babel/traverse': 7.24.6 + '@babel/types': 7.24.6 accepts: 1.3.8 chalk: 4.1.2 ci-info: 2.0.0 @@ -18160,39 +19501,46 @@ snapshots: debug: 2.6.9 denodeify: 1.2.1 error-stack-parser: 2.1.4 - flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 - hermes-parser: 0.24.0 + hermes-parser: 0.20.1 image-size: 1.1.1 invariant: 2.2.4 jest-worker: 29.7.0 jsc-safe-url: 0.2.4 lodash.throttle: 4.1.1 - metro-babel-transformer: 0.81.0 - metro-cache: 0.81.0 - metro-cache-key: 0.81.0 - metro-config: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - metro-core: 0.81.0 - metro-file-map: 0.81.0 - metro-resolver: 0.81.0 - metro-runtime: 0.81.0 - metro-source-map: 0.81.0 - metro-symbolicate: 0.81.0 - metro-transform-plugins: 0.81.0 - metro-transform-worker: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + metro-babel-transformer: 0.80.9 + metro-cache: 0.80.9 + metro-cache-key: 0.80.9 + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-core: 0.80.9 + metro-file-map: 0.80.9 + metro-resolver: 0.80.9 + metro-runtime: 0.80.9 + metro-source-map: 0.80.9 + metro-symbolicate: 0.80.9 + metro-transform-plugins: 0.80.9 + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) mime-types: 2.1.35 + node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 + rimraf: 3.0.2 serialize-error: 2.1.0 source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) yargs: 17.7.2 transitivePeerDependencies: - bufferutil + - encoding - supports-color - utf-8-validate + micromatch@4.0.7: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -18206,6 +19554,8 @@ snapshots: mime@1.6.0: {} + mime@2.6.0: {} + mime@3.0.0: {} mimic-fn@1.2.0: {} @@ -18218,20 +19568,20 @@ snapshots: min-indent@1.0.1: {} - miniflare@3.20241022.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + miniflare@3.20240712.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: '@cspotcode/source-map-support': 0.8.1 - acorn: 8.14.0 - acorn-walk: 8.3.4 + acorn: 8.11.3 + acorn-walk: 8.3.2 capnp-ts: 0.7.0 exit-hook: 2.2.1 glob-to-regexp: 0.4.1 stoppable: 1.1.0 undici: 5.28.4 - workerd: 1.20241022.0 + workerd: 1.20240712.0 ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) - youch: 3.3.4 - zod: 3.23.8 + youch: 3.3.3 + zod: 3.23.7 transitivePeerDependencies: - bufferutil - supports-color @@ -18249,11 +19599,7 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimatch@9.0.3: - dependencies: - brace-expansion: 2.0.1 - - minimatch@9.0.5: + minimatch@9.0.4: dependencies: brace-expansion: 2.0.1 @@ -18311,12 +19657,12 @@ snapshots: mkdirp@1.0.4: {} - mlly@1.7.2: + mlly@1.7.0: dependencies: - acorn: 8.14.0 + acorn: 8.11.3 pathe: 1.1.2 - pkg-types: 1.2.1 - ufo: 1.5.4 + pkg-types: 1.1.0 + ufo: 1.5.3 mri@1.2.0: {} @@ -18330,6 +19676,26 @@ snapshots: mustache@4.2.0: {} + mv@2.1.1: + dependencies: + mkdirp: 0.5.6 + ncp: 2.0.0 + rimraf: 2.4.5 + optional: true + + mysql2@3.11.0: + dependencies: + aws-ssl-profiles: 1.1.1 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.6.3 + long: 5.2.3 + lru-cache: 8.0.5 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + optional: true + mysql2@3.3.3: dependencies: denque: 2.1.0 @@ -18351,7 +19717,7 @@ snapshots: dependencies: lru-cache: 7.18.3 - nan@2.22.0: + nan@2.19.0: optional: true nanoid@3.3.7: {} @@ -18360,11 +19726,11 @@ snapshots: natural-compare@1.4.0: {} - negotiator@0.6.3: {} - - negotiator@0.6.4: + ncp@2.0.0: optional: true + negotiator@0.6.3: {} + neo-async@2.6.2: {} nested-error-stacks@2.0.1: {} @@ -18375,13 +19741,15 @@ snapshots: nice-try@1.0.5: {} - node-abi@3.71.0: + nocache@3.0.4: {} + + node-abi@3.62.0: dependencies: - semver: 7.6.3 + semver: 7.6.2 node-abort-controller@3.1.1: {} - node-addon-api@7.1.1: {} + node-addon-api@7.1.0: {} node-dir@0.1.17: dependencies: @@ -18396,6 +19764,8 @@ snapshots: emojilib: 2.4.0 skin-tone: 2.0.0 + node-fetch-native@1.6.4: {} + node-fetch@2.7.0(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 @@ -18416,7 +19786,7 @@ snapshots: node-forge@1.3.1: {} - node-gyp-build@4.8.2: {} + node-gyp-build@4.8.1: {} node-gyp@8.4.1: dependencies: @@ -18427,7 +19797,7 @@ snapshots: nopt: 5.0.0 npmlog: 6.0.2 rimraf: 3.0.2 - semver: 7.6.3 + semver: 7.6.2 tar: 6.2.1 which: 2.0.2 transitivePeerDependencies: @@ -18437,7 +19807,9 @@ snapshots: node-int64@0.4.0: {} - node-releases@2.0.18: {} + node-releases@2.0.14: {} + + node-stream-zip@1.15.0: {} nofilter@3.1.0: {} @@ -18488,23 +19860,30 @@ snapshots: dependencies: execa: 6.1.0 parse-package-name: 1.0.0 - semver: 7.6.3 + semver: 7.6.2 validate-npm-package-name: 4.0.0 nullthrows@1.1.1: {} - ob1@0.81.0: - dependencies: - flow-enums-runtime: 0.0.6 + ob1@0.80.9: {} object-assign@4.1.1: {} object-hash@2.2.0: {} - object-inspect@1.13.2: {} + object-inspect@1.12.3: {} + + object-inspect@1.13.1: {} object-keys@1.1.1: {} + object.assign@4.1.4: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + has-symbols: 1.0.3 + object-keys: 1.1.1 + object.assign@4.1.5: dependencies: call-bind: 1.0.7 @@ -18512,29 +19891,27 @@ snapshots: has-symbols: 1.0.3 object-keys: 1.1.1 - object.fromentries@2.0.8: + object.fromentries@2.0.6: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 - object.groupby@1.0.3: + object.groupby@1.0.0: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + get-intrinsic: 1.2.1 - object.values@1.2.0: + object.values@1.1.6: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 obuf@1.1.2: {} - ohash@1.1.4: {} - ohm-js@17.1.0: {} oidc-token-hash@5.0.3: {} @@ -18547,6 +19924,8 @@ snapshots: dependencies: ee-first: 1.1.1 + on-headers@1.0.2: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -18563,6 +19942,10 @@ snapshots: dependencies: mimic-fn: 4.0.0 + open@6.4.0: + dependencies: + is-wsl: 1.1.0 + open@7.4.2: dependencies: is-docker: 2.2.1 @@ -18576,19 +19959,19 @@ snapshots: openid-client@5.6.4: dependencies: - jose: 4.15.9 + jose: 4.15.5 lru-cache: 6.0.0 object-hash: 2.2.0 oidc-token-hash: 5.0.3 - optionator@0.9.4: + optionator@0.9.3: dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 - word-wrap: 1.2.5 ora@3.4.0: dependencies: @@ -18599,6 +19982,18 @@ snapshots: strip-ansi: 5.2.0 wcwidth: 1.0.1 + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + os-homedir@1.0.2: {} os-tmpdir@1.0.2: {} @@ -18638,11 +20033,11 @@ snapshots: p-limit@4.0.0: dependencies: - yocto-queue: 1.1.1 + yocto-queue: 1.0.0 p-limit@5.0.0: dependencies: - yocto-queue: 1.1.1 + yocto-queue: 1.0.0 p-locate@3.0.0: dependencies: @@ -18678,8 +20073,6 @@ snapshots: p-try@2.2.0: {} - package-json-from-dist@1.0.1: {} - parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -18691,7 +20084,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.26.2 + '@babel/code-frame': 7.22.13 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -18717,7 +20110,7 @@ snapshots: password-prompt@1.1.3: dependencies: ansi-escapes: 4.3.2 - cross-spawn: 7.0.5 + cross-spawn: 7.0.3 path-exists@3.0.0: {} @@ -18735,14 +20128,19 @@ snapshots: path-parse@1.0.7: {} + path-scurry@1.10.1: + dependencies: + lru-cache: 9.1.2 + minipass: 5.0.0 + path-scurry@1.11.1: dependencies: - lru-cache: 10.4.3 + lru-cache: 10.2.2 minipass: 7.1.2 - path-to-regexp@0.1.10: {} + path-to-regexp@0.1.7: {} - path-to-regexp@6.3.0: {} + path-to-regexp@6.2.2: {} path-type@4.0.0: {} @@ -18763,7 +20161,7 @@ snapshots: pg-connection-string@2.6.1: {} - pg-connection-string@2.7.0: {} + pg-connection-string@2.6.4: {} pg-connection-string@2.7.0: {} @@ -18771,9 +20169,9 @@ snapshots: pg-numeric@1.0.2: {} - pg-pool@3.7.0(pg@8.13.1): + pg-pool@3.6.2(pg@8.11.5): dependencies: - pg: 8.13.1 + pg: 8.11.5 pg-pool@3.7.0(pg@8.13.1): dependencies: @@ -18801,11 +20199,11 @@ snapshots: postgres-interval: 3.0.0 postgres-range: 1.1.4 - pg@8.13.1: + pg@8.11.5: dependencies: - pg-connection-string: 2.7.0 - pg-pool: 3.7.0(pg@8.13.1) - pg-protocol: 1.7.0 + pg-connection-string: 2.6.4 + pg-pool: 3.6.2(pg@8.11.5) + pg-protocol: 1.6.1 pg-types: 2.2.0 pgpass: 1.0.5 optionalDependencies: @@ -18825,7 +20223,9 @@ snapshots: dependencies: split2: 4.2.0 - picocolors@1.1.1: {} + picocolors@1.0.0: {} + + picocolors@1.0.1: {} picomatch@2.3.1: {} @@ -18846,10 +20246,10 @@ snapshots: dependencies: find-up: 3.0.0 - pkg-types@1.2.1: + pkg-types@1.1.0: dependencies: - confbox: 0.1.8 - mlly: 1.7.2 + confbox: 0.1.7 + mlly: 1.7.0 pathe: 1.1.2 plist@3.1.0: @@ -18868,27 +20268,33 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3)): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)): dependencies: - lilconfig: 3.1.2 - yaml: 2.6.0 + lilconfig: 2.1.0 + yaml: 2.3.1 optionalDependencies: - postcss: 8.4.47 - ts-node: 10.9.2(@types/node@22.9.0)(typescript@5.6.3) + postcss: 8.4.39 + ts-node: 10.9.2(@types/node@20.12.12)(typescript@5.6.3) - postcss-load-config@6.0.1(postcss@8.4.47)(tsx@3.14.0)(yaml@2.6.0): + postcss-load-config@6.0.1(postcss@8.4.39)(tsx@3.14.0)(yaml@2.4.2): dependencies: lilconfig: 3.1.2 optionalDependencies: - postcss: 8.4.47 + postcss: 8.4.39 tsx: 3.14.0 - yaml: 2.6.0 + yaml: 2.4.2 + + postcss@8.4.38: + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 - postcss@8.4.47: + postcss@8.4.39: dependencies: nanoid: 3.3.7 - picocolors: 1.1.1 - source-map-js: 1.2.1 + picocolors: 1.0.1 + source-map-js: 1.2.0 postgres-array@2.0.0: {} @@ -18912,7 +20318,7 @@ snapshots: postgres-range@1.1.4: {} - postgres@3.4.5: {} + postgres@3.4.4: {} pouchdb-collections@1.0.1: {} @@ -18924,8 +20330,8 @@ snapshots: minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 1.0.2 - node-abi: 3.71.0 - pump: 3.0.2 + node-abi: 3.62.0 + pump: 3.0.0 rc: 1.2.8 simple-get: 4.0.1 tar-fs: 2.1.1 @@ -18939,22 +20345,22 @@ snapshots: prettier@2.8.8: {} - prettier@3.3.3: {} + prettier@3.0.3: {} pretty-bytes@5.6.0: {} - pretty-format@24.9.0: + pretty-format@26.6.2: dependencies: - '@jest/types': 24.9.0 - ansi-regex: 4.1.1 - ansi-styles: 3.2.1 - react-is: 16.13.1 + '@jest/types': 26.6.2 + ansi-regex: 5.0.1 + ansi-styles: 4.3.0 + react-is: 17.0.2 pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 - react-is: 18.3.1 + react-is: 18.2.0 pretty-ms@8.0.0: dependencies: @@ -19011,21 +20417,25 @@ snapshots: dependencies: event-stream: 3.3.4 - pump@3.0.2: + pump@3.0.0: dependencies: end-of-stream: 1.4.4 once: 1.4.0 + punycode@2.3.0: {} + punycode@2.3.1: {} pure-rand@6.1.0: {} qrcode-terminal@0.11.0: {} - qs@6.13.0: + qs@6.11.0: dependencies: side-channel: 1.0.6 + querystring@0.2.1: {} + queue-microtask@1.2.3: {} queue@6.0.2: @@ -19052,65 +20462,67 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): + react-devtools-core@5.2.0(bufferutil@4.0.8): dependencies: shell-quote: 1.8.1 - ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - utf-8-validate react-is@16.13.1: {} + react-is@17.0.2: {} + + react-is@18.2.0: {} + react-is@18.3.1: {} - react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native/assets-registry': 0.76.1 - '@react-native/codegen': 0.76.1(@babel/preset-env@7.26.0(@babel/core@7.26.0)) - '@react-native/community-cli-plugin': 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - '@react-native/gradle-plugin': 0.76.1 - '@react-native/js-polyfills': 0.76.1 - '@react-native/normalize-colors': 0.76.1 - '@react-native/virtualized-lists': 0.76.1(@types/react@18.3.12)(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) + '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) + '@react-native/assets-registry': 0.74.83 + '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/gradle-plugin': 0.74.83 + '@react-native/js-polyfills': 0.74.83 + '@react-native/normalize-colors': 0.74.83 + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 - babel-jest: 29.7.0(@babel/core@7.26.0) - babel-plugin-syntax-hermes-parser: 0.23.1 base64-js: 1.5.1 chalk: 4.1.2 - commander: 12.1.0 event-target-shim: 5.0.1 flow-enums-runtime: 0.0.6 - glob: 7.2.3 invariant: 2.2.4 jest-environment-node: 29.7.0 jsc-android: 250231.0.0 memoize-one: 5.2.1 - metro-runtime: 0.81.0 - metro-source-map: 0.81.0 + metro-runtime: 0.80.9 + metro-source-map: 0.80.9 mkdirp: 0.5.6 nullthrows: 1.1.1 - pretty-format: 29.7.0 + pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + react-devtools-core: 5.2.0(bufferutil@4.0.8) react-refresh: 0.14.2 + react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 - semver: 7.6.3 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) yargs: 17.7.2 optionalDependencies: - '@types/react': 18.3.12 + '@types/react': 18.3.1 transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' - - '@react-native-community/cli-server-api' - bufferutil - encoding - supports-color @@ -19118,6 +20530,12 @@ snapshots: react-refresh@0.14.2: {} + react-shallow-renderer@16.15.0(react@18.3.1): + dependencies: + object-assign: 4.1.1 + react: 18.3.1 + react-is: 18.3.1 + react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -19130,7 +20548,7 @@ snapshots: read-pkg@5.2.0: dependencies: - '@types/normalize-package-data': 2.4.4 + '@types/normalize-package-data': 2.4.1 normalize-package-data: 2.5.0 parse-json: 5.2.0 type-fest: 0.6.0 @@ -19155,8 +20573,6 @@ snapshots: dependencies: picomatch: 2.3.1 - readdirp@4.0.2: {} - readline@1.3.0: {} recast@0.21.5: @@ -19182,7 +20598,7 @@ snapshots: dependencies: esprima: 4.0.1 - regenerate-unicode-properties@10.2.0: + regenerate-unicode-properties@10.1.1: dependencies: regenerate: 1.4.2 @@ -19190,39 +20606,45 @@ snapshots: regenerator-runtime@0.13.11: {} + regenerator-runtime@0.14.0: {} + regenerator-runtime@0.14.1: {} regenerator-transform@0.15.2: dependencies: - '@babel/runtime': 7.26.0 + '@babel/runtime': 7.24.6 regexp-tree@0.1.27: {} - regexp.prototype.flags@1.5.3: + regexp.prototype.flags@1.5.0: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + functions-have-names: 1.2.3 + + regexp.prototype.flags@1.5.2: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 - regexpu-core@6.1.1: + regexpu-core@5.3.2: dependencies: + '@babel/regjsgen': 0.8.0 regenerate: 1.4.2 - regenerate-unicode-properties: 10.2.0 - regjsgen: 0.8.0 - regjsparser: 0.11.2 + regenerate-unicode-properties: 10.1.1 + regjsparser: 0.9.1 unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.2.0 - - regjsgen@0.8.0: {} + unicode-match-property-value-ecmascript: 2.1.0 regjsparser@0.10.0: dependencies: jsesc: 0.5.0 - regjsparser@0.11.2: + regjsparser@0.9.1: dependencies: - jsesc: 3.0.2 + jsesc: 0.5.0 remove-trailing-slash@0.1.1: {} @@ -19230,6 +20652,8 @@ snapshots: require-from-string@2.0.2: {} + require-main-filename@2.0.0: {} + requireg@0.2.2: dependencies: nested-error-stacks: 2.0.1 @@ -19248,11 +20672,11 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve-tspaths@0.8.22(typescript@5.6.3): + resolve-tspaths@0.8.16(typescript@5.6.3): dependencies: ansi-colors: 4.1.3 - commander: 12.1.0 - fast-glob: 3.3.2 + commander: 11.0.0 + fast-glob: 3.3.1 typescript: 5.6.3 resolve-tspaths@0.8.22(typescript@5.6.3): @@ -19264,9 +20688,27 @@ snapshots: resolve.exports@2.0.2: {} + resolve@1.22.1: + dependencies: + is-core-module: 2.11.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@1.22.2: + dependencies: + is-core-module: 2.12.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@1.22.4: + dependencies: + is-core-module: 2.13.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + resolve@1.22.8: dependencies: - is-core-module: 2.15.1 + is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -19279,6 +20721,11 @@ snapshots: onetime: 2.0.1 signal-exit: 3.0.7 + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + retry@0.12.0: optional: true @@ -19286,17 +20733,26 @@ snapshots: reusify@1.0.4: {} + rimraf@2.4.5: + dependencies: + glob: 6.0.4 + optional: true + rimraf@2.6.3: dependencies: glob: 7.2.3 + rimraf@2.7.1: + dependencies: + glob: 7.2.3 + rimraf@3.0.2: dependencies: glob: 7.2.3 - rimraf@5.0.10: + rimraf@5.0.0: dependencies: - glob: 10.4.5 + glob: 10.4.1 rollup-plugin-inject@3.0.2: dependencies: @@ -19312,7 +20768,7 @@ snapshots: dependencies: estree-walker: 0.6.1 - rollup@3.29.5: + rollup@3.20.7: optionalDependencies: fsevents: 2.3.3 @@ -19378,6 +20834,13 @@ snapshots: dependencies: mri: 1.2.0 + safe-array-concat@1.0.0: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + has-symbols: 1.0.3 + isarray: 2.0.5 + safe-array-concat@1.1.2: dependencies: call-bind: 1.0.7 @@ -19389,6 +20852,15 @@ snapshots: safe-buffer@5.2.1: {} + safe-json-stringify@1.2.0: + optional: true + + safe-regex-test@1.0.0: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-regex: 1.1.4 + safe-regex-test@1.0.3: dependencies: call-bind: 1.0.7 @@ -19412,7 +20884,7 @@ snapshots: semver@6.3.1: {} - semver@7.6.3: {} + semver@7.6.2: {} send@0.18.0: dependencies: @@ -19432,24 +20904,6 @@ snapshots: transitivePeerDependencies: - supports-color - send@0.19.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - seq-queue@0.0.5: {} serialize-error@2.1.0: {} @@ -19458,23 +20912,22 @@ snapshots: dependencies: type-fest: 0.13.1 - serialize-javascript@6.0.2: + serialize-javascript@6.0.1: dependencies: randombytes: 2.1.0 - serve-static@1.16.2: + serve-static@1.15.0: dependencies: - encodeurl: 2.0.0 + encodeurl: 1.0.2 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.19.0 + send: 0.18.0 transitivePeerDependencies: - supports-color - set-blocking@2.0.0: - optional: true + set-blocking@2.0.0: {} - set-cookie-parser@2.7.1: {} + set-cookie-parser@2.6.0: {} set-function-length@1.2.2: dependencies: @@ -19514,17 +20967,25 @@ snapshots: shell-quote@1.8.1: {} + side-channel@1.0.4: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + object-inspect: 1.12.3 + side-channel@1.0.6: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 - object-inspect: 1.13.2 + object-inspect: 1.13.1 siginfo@2.0.0: {} signal-exit@3.0.7: {} + signal-exit@4.0.2: {} + signal-exit@4.1.0: {} simple-concat@1.0.1: {} @@ -19543,7 +21004,7 @@ snapshots: sirv@2.0.4: dependencies: - '@polka/url': 1.0.0-next.28 + '@polka/url': 1.0.0-next.25 mrmime: 2.0.0 totalist: 3.0.1 @@ -19575,14 +21036,14 @@ snapshots: smart-buffer@4.2.0: optional: true - smob@1.5.0: {} + smob@0.0.6: {} smob@1.5.0: {} socks-proxy-agent@6.2.1: dependencies: agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.3.4 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -19594,7 +21055,7 @@ snapshots: smart-buffer: 4.2.0 optional: true - source-map-js@1.2.1: {} + source-map-js@1.2.0: {} source-map-support@0.5.21: dependencies: @@ -19605,6 +21066,8 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.4: {} + source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 @@ -19616,16 +21079,16 @@ snapshots: spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.20 + spdx-license-ids: 3.0.13 - spdx-exceptions@2.5.0: {} + spdx-exceptions@2.3.0: {} spdx-expression-parse@3.0.1: dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.20 + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.13 - spdx-license-ids@3.0.20: {} + spdx-license-ids@3.0.13: {} split-ca@1.0.1: {} @@ -19648,12 +21111,12 @@ snapshots: sprintf-js@1.1.3: optional: true - sql.js@1.12.0: {} + sql.js@1.10.3: {} sqlite3@5.1.7: dependencies: bindings: 1.5.0 - node-addon-api: 7.1.1 + node-addon-api: 7.1.0 prebuild-install: 7.1.2 tar: 6.2.1 optionalDependencies: @@ -19664,13 +21127,13 @@ snapshots: sqlstring@2.3.3: {} - ssh2@1.16.0: + ssh2@1.15.0: dependencies: asn1: 0.2.6 bcrypt-pbkdf: 1.0.2 optionalDependencies: cpu-features: 0.0.10 - nan: 2.22.0 + nan: 2.19.0 ssri@10.0.6: dependencies: @@ -19681,34 +21144,14 @@ snapshots: minipass: 3.3.6 optional: true - sst-darwin-arm64@3.3.5: - optional: true - - sst-darwin-x64@3.3.5: - optional: true - - sst-linux-arm64@3.3.5: - optional: true - - sst-linux-x64@3.3.5: - optional: true - - sst-linux-x86@3.3.5: - optional: true - - sst@3.3.5(hono@4.6.9)(valibot@0.30.0): + sst@3.0.14: dependencies: - aws4fetch: 1.0.20 + '@aws-sdk/client-lambda': 3.478.0 + hono: 4.0.1 jose: 5.2.3 openid-client: 5.6.4 - optionalDependencies: - hono: 4.6.9 - sst-darwin-arm64: 3.3.5 - sst-darwin-x64: 3.3.5 - sst-linux-arm64: 3.3.5 - sst-linux-x64: 3.3.5 - sst-linux-x86: 3.3.5 - valibot: 0.30.0 + transitivePeerDependencies: + - aws-crt stack-utils@2.0.6: dependencies: @@ -19755,6 +21198,12 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string.prototype.trim@1.2.7: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + string.prototype.trim@1.2.9: dependencies: call-bind: 1.0.7 @@ -19762,12 +21211,24 @@ snapshots: es-abstract: 1.23.3 es-object-atoms: 1.0.0 + string.prototype.trimend@1.0.6: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + string.prototype.trimend@1.0.8: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 + string.prototype.trimstart@1.0.6: + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + string.prototype.trimstart@1.0.8: dependencies: call-bind: 1.0.7 @@ -19792,7 +21253,7 @@ snapshots: strip-ansi@7.1.0: dependencies: - ansi-regex: 6.1.0 + ansi-regex: 6.0.1 strip-bom@3.0.0: {} @@ -19820,7 +21281,7 @@ snapshots: sucrase@3.34.0: dependencies: - '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/gen-mapping': 0.3.3 commander: 4.1.1 glob: 7.1.6 lines-and-columns: 1.2.4 @@ -19832,7 +21293,7 @@ snapshots: dependencies: '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 - glob: 10.4.5 + glob: 10.4.1 lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.6 @@ -19842,6 +21303,8 @@ snapshots: sudo-prompt@9.1.1: {} + sudo-prompt@9.2.1: {} + superjson@2.2.1: dependencies: copy-anything: 3.0.5 @@ -19870,7 +21333,7 @@ snapshots: has-flag: 4.0.0 supports-color: 7.2.0 - supports-hyperlinks@3.1.0: + supports-hyperlinks@3.0.0: dependencies: has-flag: 4.0.0 supports-color: 7.2.0 @@ -19882,7 +21345,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - synckit@0.9.2: + synckit@0.9.1: dependencies: '@pkgr/core': 0.1.1 tslib: 2.8.1 @@ -19891,14 +21354,14 @@ snapshots: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.2 + pump: 3.0.0 tar-stream: 2.2.0 tar-fs@2.1.1: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.2 + pump: 3.0.0 tar-stream: 2.2.0 tar-stream@2.2.0: @@ -19949,18 +21412,19 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - terser@5.36.0: + terser@5.17.1: dependencies: - '@jridgewell/source-map': 0.3.6 - acorn: 8.14.0 + '@jridgewell/source-map': 0.3.3 + acorn: 8.8.2 commander: 2.20.3 source-map-support: 0.5.21 - test-exclude@6.0.0: + terser@5.31.0: dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 + '@jridgewell/source-map': 0.3.6 + acorn: 8.11.3 + commander: 2.20.3 + source-map-support: 0.5.21 text-table@0.2.0: {} @@ -19989,23 +21453,20 @@ snapshots: time-zone@1.0.0: {} - timers-ext@0.1.8: + timers-ext@0.1.7: dependencies: - es5-ext: 0.10.64 + es5-ext: 0.10.62 next-tick: 1.1.0 tiny-invariant@1.3.3: {} tiny-queue@0.2.1: {} + tinybench@2.8.0: {} + tinybench@2.9.0: {} - tinyexec@0.3.1: {} - - tinyglobby@0.2.10: - dependencies: - fdir: 6.4.2(picomatch@4.0.2) - picomatch: 4.0.2 + tinyexec@0.3.0: {} tinypool@0.8.4: {} @@ -20037,9 +21498,9 @@ snapshots: tr46@1.0.1: dependencies: - punycode: 2.3.1 + punycode: 2.3.0 - traverse@0.6.10: + traverse@0.6.9: dependencies: gopd: 1.0.1 typedarray.prototype.slice: 1.0.3 @@ -20049,9 +21510,15 @@ snapshots: treeify@1.1.0: {} - trim-right@1.0.1: {} + ts-api-utils@1.0.3(typescript@5.2.2): + dependencies: + typescript: 5.2.2 + + ts-api-utils@1.0.3(typescript@5.6.3): + dependencies: + typescript: 5.6.3 - ts-api-utils@1.4.0(typescript@5.6.3): + ts-api-utils@1.3.0(typescript@5.6.3): dependencies: typescript: 5.6.3 @@ -20059,34 +21526,16 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@types/node@20.17.6)(typescript@5.6.3): + ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.17.6 - acorn: 8.14.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.6.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - - ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 22.9.0 - acorn: 8.14.0 - acorn-walk: 8.3.4 + '@types/node': 20.12.12 + acorn: 8.11.3 + acorn-walk: 8.3.2 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 @@ -20094,13 +21543,12 @@ snapshots: typescript: 5.6.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - optional: true - tsconfck@3.1.4(typescript@5.6.3): + tsconfck@3.0.3(typescript@5.6.3): optionalDependencies: typescript: 5.6.3 - tsconfig-paths@3.15.0: + tsconfig-paths@3.14.2: dependencies: '@types/json5': 0.0.29 json5: 1.0.2 @@ -20109,53 +21557,52 @@ snapshots: tslib@1.14.1: {} - tslib@2.8.1: {} + tslib@2.6.2: {} tslib@2.8.1: {} tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3): dependencies: - bundle-require: 4.2.1(esbuild@0.19.12) + bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 - chokidar: 3.6.0 - debug: 4.3.7 - esbuild: 0.19.12 + chokidar: 3.5.3 + debug: 4.3.4 + esbuild: 0.18.20 execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3)) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)) resolve-from: 5.0.0 - rollup: 4.24.4 + rollup: 3.27.2 source-map: 0.8.0-beta.0 - sucrase: 3.35.0 + sucrase: 3.34.0 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.4.47 + postcss: 8.4.39 typescript: 5.6.3 transitivePeerDependencies: - supports-color - ts-node - tsup@8.3.5(postcss@8.4.47)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.6.0): + tsup@8.1.2(postcss@8.4.39)(tsx@3.14.0)(typescript@5.6.3)(yaml@2.4.2): dependencies: - bundle-require: 5.0.0(esbuild@0.24.0) + bundle-require: 5.0.0(esbuild@0.23.0) cac: 6.7.14 - chokidar: 4.0.1 + chokidar: 3.6.0 consola: 3.2.3 - debug: 4.3.7 - esbuild: 0.24.0 + debug: 4.3.5 + esbuild: 0.23.0 + execa: 5.1.1 + globby: 11.1.0 joycon: 3.1.1 - picocolors: 1.1.1 - postcss-load-config: 6.0.1(postcss@8.4.47)(tsx@3.14.0)(yaml@2.6.0) + postcss-load-config: 6.0.1(postcss@8.4.39)(tsx@3.14.0)(yaml@2.4.2) resolve-from: 5.0.0 - rollup: 4.24.4 + rollup: 4.18.1 source-map: 0.8.0-beta.0 sucrase: 3.35.0 - tinyexec: 0.3.1 - tinyglobby: 0.2.10 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.4.47 + postcss: 8.4.39 typescript: 5.6.3 transitivePeerDependencies: - jiti @@ -20171,15 +21618,22 @@ snapshots: tsx@3.14.0: dependencies: esbuild: 0.18.20 - get-tsconfig: 4.8.1 + get-tsconfig: 4.7.5 source-map-support: 0.5.21 optionalDependencies: fsevents: 2.3.3 - tsx@4.19.2: + tsx@4.10.5: dependencies: - esbuild: 0.23.1 - get-tsconfig: 4.8.1 + esbuild: 0.20.2 + get-tsconfig: 4.7.5 + optionalDependencies: + fsevents: 2.3.3 + + tsx@4.16.2: + dependencies: + esbuild: 0.21.5 + get-tsconfig: 4.7.5 optionalDependencies: fsevents: 2.3.3 @@ -20229,8 +21683,6 @@ snapshots: type-detect@4.0.8: {} - type-detect@4.1.0: {} - type-fest@0.13.1: {} type-fest@0.16.0: {} @@ -20247,12 +21699,22 @@ snapshots: type-fest@0.8.1: {} + type-fest@3.13.1: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0 mime-types: 2.1.35 - type@2.7.3: {} + type@1.2.0: {} + + type@2.7.2: {} + + typed-array-buffer@1.0.0: + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-typed-array: 1.1.12 typed-array-buffer@1.0.2: dependencies: @@ -20260,6 +21722,13 @@ snapshots: es-errors: 1.3.0 is-typed-array: 1.1.13 + typed-array-byte-length@1.0.0: + dependencies: + call-bind: 1.0.2 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + typed-array-byte-length@1.0.1: dependencies: call-bind: 1.0.7 @@ -20268,6 +21737,14 @@ snapshots: has-proto: 1.0.3 is-typed-array: 1.1.13 + typed-array-byte-offset@1.0.0: + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + typed-array-byte-offset@1.0.2: dependencies: available-typed-arrays: 1.0.7 @@ -20277,6 +21754,12 @@ snapshots: has-proto: 1.0.3 is-typed-array: 1.1.13 + typed-array-length@1.0.4: + dependencies: + call-bind: 1.0.2 + for-each: 0.3.3 + is-typed-array: 1.1.12 + typed-array-length@1.0.6: dependencies: call-bind: 1.0.7 @@ -20295,19 +21778,21 @@ snapshots: typed-array-buffer: 1.0.2 typed-array-byte-offset: 1.0.2 + typescript@5.2.2: {} + typescript@5.3.3: {} typescript@5.6.1-rc: {} typescript@5.6.3: {} - ua-parser-js@1.0.39: {} + ua-parser-js@1.0.38: {} - ufo@1.5.4: {} + ufo@1.5.3: {} unbox-primitive@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.2 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 @@ -20320,23 +21805,25 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 - unenv-nightly@2.0.0-20241024-111401-d4156ac: + unenv-nightly@1.10.0-1717606461.a117952: dependencies: + consola: 3.2.3 defu: 6.1.4 - ohash: 1.1.4 + mime: 3.0.0 + node-fetch-native: 1.6.4 pathe: 1.1.2 - ufo: 1.5.4 + ufo: 1.5.3 - unicode-canonical-property-names-ecmascript@2.0.1: {} + unicode-canonical-property-names-ecmascript@2.0.0: {} unicode-emoji-modifier-base@1.0.0: {} unicode-match-property-ecmascript@2.0.0: dependencies: - unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-canonical-property-names-ecmascript: 2.0.0 unicode-property-aliases-ecmascript: 2.1.0 - unicode-match-property-value-ecmascript@2.2.0: {} + unicode-match-property-value-ecmascript@2.1.0: {} unicode-property-aliases-ecmascript@2.1.0: {} @@ -20372,19 +21859,21 @@ snapshots: universalify@1.0.0: {} + universalify@2.0.0: {} + universalify@2.0.1: {} unpipe@1.0.0: {} - update-browserslist-db@1.1.1(browserslist@4.24.2): + update-browserslist-db@1.0.16(browserslist@4.23.0): dependencies: - browserslist: 4.24.2 - escalade: 3.2.0 - picocolors: 1.1.1 + browserslist: 4.23.0 + escalade: 3.1.2 + picocolors: 1.0.1 uri-js@4.4.1: dependencies: - punycode: 2.3.1 + punycode: 2.3.0 url-join@4.0.0: {} @@ -20392,7 +21881,7 @@ snapshots: utf-8-validate@6.0.3: dependencies: - node-gyp-build: 4.8.2 + node-gyp-build: 4.8.1 util-deprecate@1.0.2: {} @@ -20409,7 +21898,7 @@ snapshots: uvu@0.5.6: dependencies: dequal: 2.0.3 - diff: 5.2.0 + diff: 5.1.0 kleur: 4.1.5 sade: 1.8.1 @@ -20432,23 +21921,91 @@ snapshots: dependencies: builtins: 5.1.0 - validate-npm-package-name@5.0.1: {} + validate-npm-package-name@5.0.0: + dependencies: + builtins: 5.1.0 vary@1.1.2: {} - vite-node@1.6.0(@types/node@18.19.64)(terser@5.36.0): + vite-node@1.6.0(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + cac: 6.7.14 + debug: 4.3.4 + pathe: 1.1.2 + picocolors: 1.0.1 + vite: 5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vite-node@1.6.0(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + cac: 6.7.14 + debug: 4.3.4 + pathe: 1.1.2 + picocolors: 1.0.1 + vite: 5.3.3(@types/node@18.19.33)(lightningcss@1.25.1)(terser@5.31.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vite-node@1.6.0(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + cac: 6.7.14 + debug: 4.3.4 + pathe: 1.1.2 + picocolors: 1.0.1 + vite: 5.3.3(@types/node@20.10.1)(lightningcss@1.25.1)(terser@5.31.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vite-node@1.6.0(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): + dependencies: + cac: 6.7.14 + debug: 4.3.4 + pathe: 1.1.2 + picocolors: 1.0.1 + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vite-node@2.1.2(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0): dependencies: cac: 6.7.14 debug: 4.3.7 pathe: 1.1.2 - picocolors: 1.1.1 - vite: 5.4.10(@types/node@18.19.64)(terser@5.36.0) + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) transitivePeerDependencies: - '@types/node' - less - lightningcss - sass - - sass-embedded - stylus - sugarss - supports-color @@ -20749,242 +22306,24 @@ snapshots: '@vitest/utils': 2.1.2 chai: 5.1.1 debug: 4.3.7 - pathe: 1.1.2 - picocolors: 1.1.1 - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - vite-node@2.1.4(@types/node@20.17.6)(terser@5.36.0): - dependencies: - cac: 6.7.14 - debug: 4.3.7 - pathe: 1.1.2 - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - vite-node@2.1.4(@types/node@22.9.0)(terser@5.36.0): - dependencies: - cac: 6.7.14 - debug: 4.3.7 - pathe: 1.1.2 - vite: 5.4.10(@types/node@22.9.0)(terser@5.36.0) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@18.19.64)(terser@5.36.0)): - dependencies: - debug: 4.3.7 - globrex: 0.1.2 - tsconfck: 3.1.4(typescript@5.6.3) - optionalDependencies: - vite: 5.4.10(@types/node@18.19.64)(terser@5.36.0) - transitivePeerDependencies: - - supports-color - - typescript - - vite-tsconfig-paths@4.3.2(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)): - dependencies: - debug: 4.3.7 - globrex: 0.1.2 - tsconfck: 3.1.4(typescript@5.6.3) - optionalDependencies: - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) - transitivePeerDependencies: - - supports-color - - typescript - - vite@5.4.10(@types/node@18.19.64)(terser@5.36.0): - dependencies: - esbuild: 0.21.5 - postcss: 8.4.47 - rollup: 4.24.4 - optionalDependencies: - '@types/node': 18.19.64 - fsevents: 2.3.3 - terser: 5.36.0 - - vite@5.4.10(@types/node@20.17.6)(terser@5.36.0): - dependencies: - esbuild: 0.21.5 - postcss: 8.4.47 - rollup: 4.24.4 - optionalDependencies: - '@types/node': 20.17.6 - fsevents: 2.3.3 - terser: 5.36.0 - - vite@5.4.10(@types/node@22.9.0)(terser@5.36.0): - dependencies: - esbuild: 0.21.5 - postcss: 8.4.47 - rollup: 4.24.4 - optionalDependencies: - '@types/node': 22.9.0 - fsevents: 2.3.3 - terser: 5.36.0 - - vitest@1.6.0(@types/node@18.19.64)(@vitest/ui@1.6.0)(terser@5.36.0): - dependencies: - '@vitest/expect': 1.6.0 - '@vitest/runner': 1.6.0 - '@vitest/snapshot': 1.6.0 - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - acorn-walk: 8.3.4 - chai: 4.5.0 - debug: 4.3.7 - execa: 8.0.1 - local-pkg: 0.5.0 - magic-string: 0.30.12 - pathe: 1.1.2 - picocolors: 1.1.1 - std-env: 3.7.0 - strip-literal: 2.1.0 - tinybench: 2.9.0 - tinypool: 0.8.4 - vite: 5.4.10(@types/node@18.19.64)(terser@5.36.0) - vite-node: 1.6.0(@types/node@18.19.64)(terser@5.36.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 18.19.64 - '@vitest/ui': 1.6.0(vitest@1.6.0) - transitivePeerDependencies: - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - vitest@1.6.0(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0): - dependencies: - '@vitest/expect': 1.6.0 - '@vitest/runner': 1.6.0 - '@vitest/snapshot': 1.6.0 - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - acorn-walk: 8.3.4 - chai: 4.5.0 - debug: 4.3.7 - execa: 8.0.1 - local-pkg: 0.5.0 - magic-string: 0.30.12 - pathe: 1.1.2 - picocolors: 1.1.1 - std-env: 3.7.0 - strip-literal: 2.1.0 - tinybench: 2.9.0 - tinypool: 0.8.4 - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) - vite-node: 1.6.0(@types/node@20.17.6)(terser@5.36.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 20.17.6 - '@vitest/ui': 1.6.0(vitest@1.6.0) - transitivePeerDependencies: - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - vitest@2.1.4(@types/node@20.17.6)(@vitest/ui@1.6.0)(terser@5.36.0): - dependencies: - '@vitest/expect': 2.1.4 - '@vitest/mocker': 2.1.4(vite@5.4.10(@types/node@20.17.6)(terser@5.36.0)) - '@vitest/pretty-format': 2.1.4 - '@vitest/runner': 2.1.4 - '@vitest/snapshot': 2.1.4 - '@vitest/spy': 2.1.4 - '@vitest/utils': 2.1.4 - chai: 5.1.2 - debug: 4.3.7 - expect-type: 1.1.0 - magic-string: 0.30.12 - pathe: 1.1.2 - std-env: 3.7.0 - tinybench: 2.9.0 - tinyexec: 0.3.1 - tinypool: 1.0.1 - tinyrainbow: 1.2.0 - vite: 5.4.10(@types/node@20.17.6)(terser@5.36.0) - vite-node: 2.1.4(@types/node@20.17.6)(terser@5.36.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 20.17.6 - '@vitest/ui': 1.6.0(vitest@2.1.4) - transitivePeerDependencies: - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - vitest@2.1.4(@types/node@22.9.0)(terser@5.36.0): - dependencies: - '@vitest/expect': 2.1.4 - '@vitest/mocker': 2.1.4(vite@5.4.10(@types/node@22.9.0)(terser@5.36.0)) - '@vitest/pretty-format': 2.1.4 - '@vitest/runner': 2.1.4 - '@vitest/snapshot': 2.1.4 - '@vitest/spy': 2.1.4 - '@vitest/utils': 2.1.4 - chai: 5.1.2 - debug: 4.3.7 - expect-type: 1.1.0 - magic-string: 0.30.12 + magic-string: 0.30.11 pathe: 1.1.2 std-env: 3.7.0 tinybench: 2.9.0 - tinyexec: 0.3.1 + tinyexec: 0.3.0 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.10(@types/node@22.9.0)(terser@5.36.0) - vite-node: 2.1.4(@types/node@22.9.0)(terser@5.36.0) + vite: 5.3.3(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) + vite-node: 2.1.2(@types/node@20.12.12)(lightningcss@1.25.1)(terser@5.31.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.9.0 + '@types/node': 20.12.12 + '@vitest/ui': 1.6.0(vitest@2.1.2) transitivePeerDependencies: - less - lightningcss - msw - sass - - sass-embedded - stylus - sugarss - supports-color @@ -21033,7 +22372,7 @@ snapshots: dependencies: defaults: 1.0.4 - web-streams-polyfill@3.3.3: {} + web-streams-polyfill@3.2.1: {} webidl-conversions@3.0.1: {} @@ -21072,6 +22411,16 @@ snapshots: is-string: 1.0.7 is-symbol: 1.0.4 + which-module@2.0.1: {} + + which-typed-array@1.1.11: + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 @@ -21092,6 +22441,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.2.2: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 @@ -21104,47 +22458,48 @@ snapshots: wonka@4.0.15: {} - word-wrap@1.2.5: {} - wordwrap@1.0.0: {} - workerd@1.20241022.0: + workerd@1.20240712.0: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20241022.0 - '@cloudflare/workerd-darwin-arm64': 1.20241022.0 - '@cloudflare/workerd-linux-64': 1.20241022.0 - '@cloudflare/workerd-linux-arm64': 1.20241022.0 - '@cloudflare/workerd-windows-64': 1.20241022.0 + '@cloudflare/workerd-darwin-64': 1.20240712.0 + '@cloudflare/workerd-darwin-arm64': 1.20240712.0 + '@cloudflare/workerd-linux-64': 1.20240712.0 + '@cloudflare/workerd-linux-arm64': 1.20240712.0 + '@cloudflare/workerd-windows-64': 1.20240712.0 - wrangler@3.85.0(@cloudflare/workers-types@4.20241106.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3): + wrangler@3.65.0(@cloudflare/workers-types@4.20240524.0)(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: '@cloudflare/kv-asset-handler': 0.3.4 - '@cloudflare/workers-shared': 0.7.0 '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) blake3-wasm: 2.1.5 - chokidar: 3.6.0 - date-fns: 4.1.0 + chokidar: 3.5.3 + date-fns: 3.6.0 esbuild: 0.17.19 - itty-time: 1.0.6 - miniflare: 3.20241022.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + miniflare: 3.20240712.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) nanoid: 3.3.7 - path-to-regexp: 6.3.0 + path-to-regexp: 6.2.2 resolve: 1.22.8 resolve.exports: 2.0.2 selfsigned: 2.4.1 source-map: 0.6.1 - unenv: unenv-nightly@2.0.0-20241024-111401-d4156ac - workerd: 1.20241022.0 + unenv: unenv-nightly@1.10.0-1717606461.a117952 xxhash-wasm: 1.0.2 optionalDependencies: - '@cloudflare/workers-types': 4.20241106.0 + '@cloudflare/workers-types': 4.20240524.0 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -21165,33 +22520,31 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 - write-file-atomic@4.0.2: - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - write-file-atomic@5.0.1: dependencies: imurmurhash: 0.1.4 - signal-exit: 4.1.0 + signal-exit: 4.0.2 - ws@6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@6.2.2(bufferutil@4.0.8): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@7.5.9(bufferutil@4.0.8): optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 utf-8-validate: 6.0.3 + ws@8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 6.0.3 + ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 @@ -21217,22 +22570,45 @@ snapshots: xxhash-wasm@1.0.2: {} + y18n@4.0.3: {} + y18n@5.0.8: {} yallist@3.1.1: {} yallist@4.0.0: {} - yaml@2.6.0: {} + yaml@2.3.1: {} + + yaml@2.4.2: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 yargs-parser@20.2.9: {} yargs-parser@21.1.1: {} + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + yargs@16.2.0: dependencies: cliui: 7.0.4 - escalade: 3.2.0 + escalade: 3.1.2 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -21242,7 +22618,7 @@ snapshots: yargs@17.7.2: dependencies: cliui: 8.0.1 - escalade: 3.2.0 + escalade: 3.1.1 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -21253,30 +22629,28 @@ snapshots: yocto-queue@0.1.0: {} - yocto-queue@1.1.1: {} + yocto-queue@1.0.0: {} - youch@3.3.4: + youch@3.3.3: dependencies: - cookie: 0.7.2 + cookie: 0.5.0 mustache: 4.2.0 stacktracey: 2.1.8 - zod-validation-error@2.1.0(zod@3.23.8): - dependencies: - zod: 3.23.8 + zod@3.21.4: {} - zod@3.23.8: {} + zod@3.23.7: {} - zx@7.2.3: + zx@7.2.2: dependencies: '@types/fs-extra': 11.0.4 - '@types/minimist': 1.2.5 - '@types/node': 18.19.64 - '@types/ps-tree': 1.1.6 - '@types/which': 3.0.4 + '@types/minimist': 1.2.2 + '@types/node': 18.19.33 + '@types/ps-tree': 1.1.2 + '@types/which': 3.0.0 chalk: 5.3.0 - fs-extra: 11.2.0 - fx: 35.0.0 + fs-extra: 11.1.1 + fx: 28.0.0 globby: 13.2.2 minimist: 1.2.8 node-fetch: 3.3.1 From 6af533142fdb9628109c74f99478eea0d61399c5 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 25 Nov 2024 19:01:27 +0200 Subject: [PATCH 394/492] dprint --- drizzle-seed/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index ad31de0eb..dbac30737 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -102,4 +102,4 @@ "dependencies": { "pure-rand": "^6.1.0" } -} \ No newline at end of file +} From 599da5ef7a037904989069596c8879690f9c5322 Mon Sep 17 00:00:00 2001 From: Oleksii Khomenko <47694554+OleksiiKH0240@users.noreply.github.com> Date: Mon, 25 Nov 2024 19:03:30 +0200 Subject: [PATCH 395/492] drizzle-seed bug fixes (#3614) Fixed a few seed bugs --------- Co-authored-by: AndriiSherman --- changelogs/drizzle-seed/0.1.2.md | 2 + drizzle-seed/package.json | 3 +- drizzle-seed/src/index.ts | 20 +++++----- drizzle-seed/src/services/SeedService.ts | 4 +- drizzle-seed/src/type-tests/mysql.ts | 17 ++++++++ drizzle-seed/src/type-tests/pg.ts | 48 +++++++++++++++++++++++ drizzle-seed/src/type-tests/sqlite.ts | 17 ++++++++ drizzle-seed/src/type-tests/tsconfig.json | 11 ++++++ pnpm-lock.yaml | 24 ++++++------ 9 files changed, 121 insertions(+), 25 deletions(-) create mode 100644 changelogs/drizzle-seed/0.1.2.md create mode 100644 drizzle-seed/src/type-tests/mysql.ts create mode 100644 drizzle-seed/src/type-tests/pg.ts create mode 100644 drizzle-seed/src/type-tests/sqlite.ts create mode 100644 drizzle-seed/src/type-tests/tsconfig.json diff --git a/changelogs/drizzle-seed/0.1.2.md b/changelogs/drizzle-seed/0.1.2.md new file mode 100644 index 000000000..4df3c89f4 --- /dev/null +++ b/changelogs/drizzle-seed/0.1.2.md @@ -0,0 +1,2 @@ +- Fixed: [[BUG]: drizzle-seed reset fails without @electric-sql/pglite installed](https://github.com/drizzle-team/drizzle-orm/issues/3603) +- Fixed: [[BUG]: TypeScript type error in drizzle-seed with schema passed to drizzle in IDE](https://github.com/drizzle-team/drizzle-orm/issues/3599) \ No newline at end of file diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index 32ada8a46..dbac30737 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -1,12 +1,13 @@ { "name": "drizzle-seed", - "version": "0.1.1", + "version": "0.1.2", "main": "index.js", "type": "module", "scripts": { "build": "tsx scripts/build.ts", "pack": "(cd dist && npm pack --pack-destination ..) && rm -f package.tgz && mv *.tgz package.tgz", "test": "vitest --config ./src/tests/vitest.config.ts", + "test:types": "cd src/type-tests && tsc", "generate-for-tests:pg": "drizzle-kit generate --config=./src/tests/pg/drizzle.config.ts", "generate-for-tests:mysql": "drizzle-kit generate --config=./src/tests/mysql/drizzle.config.ts", "generate-for-tests:sqlite": "drizzle-kit generate --config=./src/tests/sqlite/drizzle.config.ts", diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 3f766e219..093ecaf5c 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -18,13 +18,13 @@ import type { Relation, Table } from './types/tables.ts'; type InferCallbackType< DB extends - | PgDatabase + | PgDatabase | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable; }, -> = DB extends PgDatabase ? SCHEMA extends { +> = DB extends PgDatabase ? SCHEMA extends { [key: string]: | PgTable | PgSchema @@ -124,7 +124,7 @@ type InferCallbackType< class SeedPromise< DB extends - | PgDatabase + | PgDatabase | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { @@ -311,7 +311,7 @@ export async function seedForDrizzleStudio( */ export function seed< DB extends - | PgDatabase + | PgDatabase | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { @@ -328,7 +328,7 @@ export function seed< } const seedFunc = async ( - db: PgDatabase | MySqlDatabase | BaseSQLiteDatabase, + db: PgDatabase | MySqlDatabase | BaseSQLiteDatabase, schema: { [key: string]: | PgTable @@ -341,7 +341,7 @@ const seedFunc = async ( options: { count?: number; seed?: number } = {}, refinements?: RefinementsType, ) => { - if (is(db, PgDatabase)) { + if (is(db, PgDatabase)) { const { pgSchema } = filterPgTables(schema); await seedPostgres(db, pgSchema, options, refinements); @@ -404,7 +404,7 @@ const seedFunc = async ( */ export async function reset< DB extends - | PgDatabase + | PgDatabase | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { @@ -417,7 +417,7 @@ export async function reset< | any; }, >(db: DB, schema: SCHEMA) { - if (is(db, PgDatabase)) { + if (is(db, PgDatabase)) { const { pgSchema } = filterPgTables(schema); if (Object.entries(pgSchema).length > 0) { @@ -444,7 +444,7 @@ export async function reset< // Postgres----------------------------------------------------------------------------------------------------------- const resetPostgres = async ( - db: PgDatabase, + db: PgDatabase, schema: { [key: string]: PgTable }, ) => { const tablesToTruncate = Object.entries(schema).map(([_, table]) => { @@ -474,7 +474,7 @@ const filterPgTables = (schema: { }; const seedPostgres = async ( - db: PgDatabase, + db: PgDatabase, schema: { [key: string]: PgTable }, options: { count?: number; seed?: number } = {}, refinements?: RefinementsType, diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index d5166faae..2588f110e 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -3,7 +3,6 @@ import type { MySqlTable } from 'drizzle-orm/mysql-core'; import { MySqlDatabase } from 'drizzle-orm/mysql-core'; import type { PgTable } from 'drizzle-orm/pg-core'; import { PgDatabase } from 'drizzle-orm/pg-core'; -import { PgliteSession } from 'drizzle-orm/pglite'; import type { SQLiteTable } from 'drizzle-orm/sqlite-core'; import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core'; import type { @@ -1037,7 +1036,8 @@ class SeedService { } let maxParametersNumber: number; if (is(db, PgDatabase)) { - maxParametersNumber = is(db._.session, PgliteSession) + // @ts-ignore + maxParametersNumber = db.constructor[entityKind] === 'PgliteDatabase' ? this.postgresPgLiteMaxParametersNumber : this.postgresMaxParametersNumber; } else if (is(db, MySqlDatabase)) { diff --git a/drizzle-seed/src/type-tests/mysql.ts b/drizzle-seed/src/type-tests/mysql.ts new file mode 100644 index 000000000..d1c0949b3 --- /dev/null +++ b/drizzle-seed/src/type-tests/mysql.ts @@ -0,0 +1,17 @@ +import type { MySqlColumn } from 'drizzle-orm/mysql-core'; +import { int, mysqlTable, text } from 'drizzle-orm/mysql-core'; +import { drizzle as mysql2Drizzle } from 'drizzle-orm/mysql2'; +import { reset, seed } from '../index.ts'; + +const mysqlUsers = mysqlTable('users', { + id: int().primaryKey().autoincrement(), + name: text(), + inviteId: int('invite_id').references((): MySqlColumn => mysqlUsers.id), +}); + +{ + const db = mysql2Drizzle(''); + + await seed(db, { users: mysqlUsers }); + await reset(db, { users: mysqlUsers }); +} diff --git a/drizzle-seed/src/type-tests/pg.ts b/drizzle-seed/src/type-tests/pg.ts new file mode 100644 index 000000000..68faf844b --- /dev/null +++ b/drizzle-seed/src/type-tests/pg.ts @@ -0,0 +1,48 @@ +import { drizzle as nodePostgresDrizzle } from 'drizzle-orm/node-postgres'; +import type { PgColumn } from 'drizzle-orm/pg-core'; +import { integer, pgTable, text } from 'drizzle-orm/pg-core'; +import { drizzle as pgliteDrizzle } from 'drizzle-orm/pglite'; +import { drizzle as postgresJsDrizzle } from 'drizzle-orm/postgres-js'; +import { reset, seed } from '../index.ts'; + +const pgUsers = pgTable('users', { + id: integer().primaryKey().generatedAlwaysAsIdentity(), + name: text(), + inviteId: integer('invite_id').references((): PgColumn => pgUsers.id), +}); + +{ + const db0 = nodePostgresDrizzle('', { schema: { users: pgUsers } }); + + await seed(db0, { users: pgUsers }); + await reset(db0, { users: pgUsers }); + + const db1 = nodePostgresDrizzle(''); + + await seed(db1, { users: pgUsers }); + await reset(db1, { users: pgUsers }); +} + +{ + const db0 = pgliteDrizzle('', { schema: { users: pgUsers } }); + + await seed(db0, { users: pgUsers }); + await reset(db0, { users: pgUsers }); + + const db1 = pgliteDrizzle(''); + + await seed(db1, { users: pgUsers }); + await reset(db1, { users: pgUsers }); +} + +{ + const db0 = postgresJsDrizzle('', { schema: { users: pgUsers } }); + + await seed(db0, { users: pgUsers }); + await reset(db0, { users: pgUsers }); + + const db1 = postgresJsDrizzle(''); + + await seed(db1, { users: pgUsers }); + await reset(db1, { users: pgUsers }); +} diff --git a/drizzle-seed/src/type-tests/sqlite.ts b/drizzle-seed/src/type-tests/sqlite.ts new file mode 100644 index 000000000..1b060e6a3 --- /dev/null +++ b/drizzle-seed/src/type-tests/sqlite.ts @@ -0,0 +1,17 @@ +import { drizzle as betterSqlite3Drizzle } from 'drizzle-orm/better-sqlite3'; +import type { SQLiteColumn } from 'drizzle-orm/sqlite-core'; +import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { reset, seed } from '../index.ts'; + +const mysqlUsers = sqliteTable('users', { + id: int().primaryKey(), + name: text(), + inviteId: int('invite_id').references((): SQLiteColumn => mysqlUsers.id), +}); + +{ + const db = betterSqlite3Drizzle(''); + + await seed(db, { users: mysqlUsers }); + await reset(db, { users: mysqlUsers }); +} diff --git a/drizzle-seed/src/type-tests/tsconfig.json b/drizzle-seed/src/type-tests/tsconfig.json new file mode 100644 index 000000000..09df8e1bb --- /dev/null +++ b/drizzle-seed/src/type-tests/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.build.json", + "compilerOptions": { + "composite": false, + "noEmit": true, + "rootDir": "..", + "outDir": "./.cache" + }, + "include": [".", "../src"], + "exclude": ["**/playground"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fb912db04..24d14e7c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10702,8 +10702,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10789,11 +10789,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/client-sso-oidc@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10832,7 +10832,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.478.0': @@ -11099,11 +11098,11 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0': + '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -11142,6 +11141,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/core@3.477.0': @@ -11296,7 +11296,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -11503,7 +11503,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -11704,7 +11704,7 @@ snapshots: '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11713,7 +11713,7 @@ snapshots: '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -16279,7 +16279,7 @@ snapshots: '@npmcli/fs': 3.1.1 fs-minipass: 3.0.3 glob: 10.4.1 - lru-cache: 10.2.2 + lru-cache: 10.4.3 minipass: 7.1.2 minipass-collect: 2.0.1 minipass-flush: 1.0.5 From 675e2859dcfc8d059ce7a9960af997e985a26f5d Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 25 Nov 2024 19:12:26 +0200 Subject: [PATCH 396/492] Clear drizzle-kit tests --- drizzle-kit/tests/introspect/singlestore.test.ts | 1 - drizzle-kit/tests/push/singlestore-push.test.ts | 4 ++-- drizzle-kit/tests/push/singlestore.test.ts | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drizzle-kit/tests/introspect/singlestore.test.ts b/drizzle-kit/tests/introspect/singlestore.test.ts index 245f818ba..71960c3f7 100644 --- a/drizzle-kit/tests/introspect/singlestore.test.ts +++ b/drizzle-kit/tests/introspect/singlestore.test.ts @@ -10,7 +10,6 @@ import { int, mediumint, singlestoreTable, - singlestoreView, smallint, text, tinyint, diff --git a/drizzle-kit/tests/push/singlestore-push.test.ts b/drizzle-kit/tests/push/singlestore-push.test.ts index 49e0cc270..4ad3c6c0e 100644 --- a/drizzle-kit/tests/push/singlestore-push.test.ts +++ b/drizzle-kit/tests/push/singlestore-push.test.ts @@ -1,6 +1,5 @@ import Docker from 'dockerode'; -import { sql } from 'drizzle-orm'; -import { int, singlestoreTable, singlestoreView } from 'drizzle-orm/singlestore-core'; +import { int, singlestoreTable } from 'drizzle-orm/singlestore-core'; import fs from 'fs'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; @@ -65,6 +64,7 @@ beforeAll(async () => { throw lastError; } + await client.query('DROP DATABASE IF EXISTS drizzle;'); await client.query('CREATE DATABASE drizzle;'); await client.query('USE drizzle;'); }); diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index a450f415a..82c72063c 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -428,6 +428,7 @@ run( throw lastError; } + await context.client.query(`DROP DATABASE IF EXISTS \`drizzle\`;`); await context.client.query('CREATE DATABASE drizzle;'); await context.client.query('USE drizzle;'); }, From cc0457683bde9aa07c313cfa60ef9f2ee948610a Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 25 Nov 2024 19:19:15 +0200 Subject: [PATCH 397/492] Remove .only from tests --- drizzle-kit/tests/push/common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-kit/tests/push/common.ts b/drizzle-kit/tests/push/common.ts index 848170359..627070f11 100644 --- a/drizzle-kit/tests/push/common.ts +++ b/drizzle-kit/tests/push/common.ts @@ -31,7 +31,7 @@ export const run = ( beforeEach(beforeEachFn ? () => beforeEachFn(context) : () => {}); - test.only('No diffs for all database types', () => suite.allTypes(context)); + test('No diffs for all database types', () => suite.allTypes(context)); test('Adding basic indexes', () => suite.addBasicIndexes(context)); test('Dropping basic index', () => suite.dropIndex(context)); test('Altering indexes', () => suite.changeIndexFields(context)); From 3d1bb2048ca2177e879fc39467e691082be12d02 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Tue, 26 Nov 2024 19:12:17 +0200 Subject: [PATCH 398/492] added array column support for postgres, partly added in refine function --- drizzle-seed/src/index.ts | 28 +- .../src/services/GeneratorsWrappers.ts | 265 ++++++++++++++++-- drizzle-seed/src/services/SeedService.ts | 230 ++++++++------- drizzle-seed/src/types/tables.ts | 12 + 4 files changed, 396 insertions(+), 139 deletions(-) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 093ecaf5c..be3dd7d03 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -3,7 +3,7 @@ import { entityKind, getTableName, is, sql } from 'drizzle-orm'; import type { MySqlColumn, MySqlSchema } from 'drizzle-orm/mysql-core'; import { getTableConfig as getMysqlTableConfig, MySqlDatabase, MySqlTable } from 'drizzle-orm/mysql-core'; -import type { PgColumn, PgSchema } from 'drizzle-orm/pg-core'; +import type { PgArray, PgColumn, PgSchema } from 'drizzle-orm/pg-core'; import { getTableConfig as getPgTableConfig, PgDatabase, PgTable } from 'drizzle-orm/pg-core'; import type { SQLiteColumn } from 'drizzle-orm/sqlite-core'; @@ -14,7 +14,7 @@ import { generatorsFuncs } from './services/GeneratorsWrappers.ts'; import seedService from './services/SeedService.ts'; import type { DrizzleStudioObjectType, DrizzleStudioRelationType } from './types/drizzleStudio.ts'; import type { RefinementsType } from './types/seedService.ts'; -import type { Relation, Table } from './types/tables.ts'; +import type { Column, Relation, Table } from './types/tables.ts'; type InferCallbackType< DB extends @@ -560,18 +560,41 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { }), ); + const getAllBaseColumns = ( + baseColumn: PgArray['baseColumn'] & { baseColumn?: PgArray['baseColumn'] }, + ): Column['baseColumn'] => { + const baseColumnResult: Column['baseColumn'] = { + name: baseColumn.name, + columnType: baseColumn.columnType.replace('Pg', '').toLowerCase(), + dataType: baseColumn.dataType, + size: (baseColumn as PgArray).size, + hasDefault: baseColumn.hasDefault, + default: baseColumn.default, + isUnique: baseColumn.isUnique, + notNull: baseColumn.notNull, + baseColumn: baseColumn.baseColumn === undefined ? undefined : getAllBaseColumns(baseColumn.baseColumn), + }; + + return baseColumnResult; + }; + + // console.log(tableConfig.columns); tables.push({ name: dbToTsTableNamesMap[tableConfig.name] as string, columns: tableConfig.columns.map((column) => ({ name: dbToTsColumnNamesMap[column.name] as string, columnType: column.columnType.replace('Pg', '').toLowerCase(), dataType: column.dataType, + size: (column as PgArray).size, hasDefault: column.hasDefault, default: column.default, enumValues: column.enumValues, isUnique: column.isUnique, notNull: column.notNull, generatedIdentityType: column.generatedIdentity?.type, + baseColumn: ((column as PgArray).baseColumn === undefined) + ? undefined + : getAllBaseColumns((column as PgArray).baseColumn), })), primaryKeys: tableConfig.columns .filter((column) => column.primary) @@ -579,6 +602,7 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { }); } + // console.log(tables[0]?.columns) return { tables, relations }; }; diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts index ae2d1d47d..46e33cfb0 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -22,12 +22,55 @@ export abstract class AbstractGenerator { public uniqueVersionOfGen?: new(params: T) => AbstractGenerator; public dataType?: string; public timeSpent?: number; + public arraySize?: number; constructor(public params: T) {} abstract init(params: { count: number | { weight: number; count: number | number[] }[]; seed: number }): void; abstract generate(params: { i: number }): number | string | boolean | unknown | undefined | void; + + getEntityKind(): string { + const constructor = this.constructor as typeof AbstractGenerator; + return constructor[entityKind]; + } + + replaceIfUnique({ count, seed }: { count: number; seed: number }) { + if ( + this.uniqueVersionOfGen !== undefined + && this.isUnique === true + ) { + const uniqueGen = new this.uniqueVersionOfGen({ + ...this.params, + }); + uniqueGen.init({ + count, + seed, + }); + uniqueGen.isUnique = this.isUnique; + uniqueGen.dataType = this.dataType; + + return uniqueGen; + } + return; + } + + replaceIfArray({ count, seed }: { count: number; seed: number }) { + if (!(this.getEntityKind() === 'GenerateArray') && this.arraySize !== undefined) { + const uniqueGen = this.replaceIfUnique({ count, seed }); + const arrayGen = new GenerateArray( + { + baseColumnGen: uniqueGen === undefined ? this : uniqueGen, + size: this.arraySize, + }, + ); + arrayGen.init({ count, seed }); + + return arrayGen; + } + + return; + } } function createGenerator, T>( @@ -44,6 +87,25 @@ function createGenerator, T>( } // Generators Classes ----------------------------------------------------------------------------------------------------------------------- +export class GenerateArray extends AbstractGenerator<{ baseColumnGen: AbstractGenerator; size?: number }> { + static override readonly [entityKind]: string = 'GenerateArray'; + public override arraySize = 10; + + init({ count, seed }: { count: number; seed: number }) { + this.arraySize = this.params.size === undefined ? this.arraySize : this.params.size; + this.params.baseColumnGen.init({ count: count * this.arraySize, seed }); + } + + generate() { + const array = []; + for (let i = 0; i < this.arraySize; i++) { + array.push(this.params.baseColumnGen.generate({ i })); + } + + return array; + } +} + export class GenerateWeightedCount extends AbstractGenerator<{}> { static override readonly [entityKind]: string = 'GenerateWeightedCount'; @@ -92,10 +154,15 @@ export class HollowGenerator extends AbstractGenerator<{}> { export class GenerateDefault extends AbstractGenerator<{ defaultValue: unknown; + arraySize?: number; }> { static override readonly [entityKind]: string = 'GenerateDefault'; - init() {} + init() { + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + } generate() { return this.params.defaultValue; @@ -108,6 +175,7 @@ export class GenerateValuesFromArray extends AbstractGenerator< | (number | string | boolean | undefined)[] | { weight: number; values: (number | string | boolean | undefined)[] }[]; isUnique?: boolean; + arraySize?: number; } > { static override readonly [entityKind]: string = 'GenerateValuesFromArray'; @@ -205,6 +273,11 @@ export class GenerateValuesFromArray extends AbstractGenerator< this.isUnique = this.params.isUnique; } + + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + this.checks({ count }); let { maxRepeatedValuesCount } = this; @@ -389,6 +462,7 @@ export class GenerateNumber extends AbstractGenerator< maxValue?: number; precision?: number; isUnique?: boolean; + arraySize?: number; } | undefined > { static override readonly [entityKind]: string = 'GenerateNumber'; @@ -412,6 +486,10 @@ export class GenerateNumber extends AbstractGenerator< this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + let { minValue, maxValue, precision } = this.params; if (precision === undefined) { precision = 100; @@ -505,6 +583,7 @@ export class GenerateInt extends AbstractGenerator<{ minValue?: number | bigint; maxValue?: number | bigint; isUnique?: boolean; + arraySize?: number; }> { static override readonly [entityKind]: string = 'GenerateInt'; @@ -524,6 +603,10 @@ export class GenerateInt extends AbstractGenerator<{ this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + let { minValue, maxValue } = this.params; if (maxValue === undefined) { @@ -747,7 +830,7 @@ export class GenerateUniqueInt extends AbstractGenerator<{ } } -export class GenerateBoolean extends AbstractGenerator<{}> { +export class GenerateBoolean extends AbstractGenerator<{ arraySize?: number }> { static override readonly [entityKind]: string = 'GenerateBoolean'; private state: { @@ -755,6 +838,10 @@ export class GenerateBoolean extends AbstractGenerator<{}> { } | undefined; init({ seed }: { seed: number }) { + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -772,7 +859,11 @@ export class GenerateBoolean extends AbstractGenerator<{}> { } } -export class GenerateDate extends AbstractGenerator<{ minDate?: string | Date; maxDate?: string | Date }> { +export class GenerateDate extends AbstractGenerator<{ + minDate?: string | Date; + maxDate?: string | Date; + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateDate'; private state: { @@ -785,6 +876,12 @@ export class GenerateDate extends AbstractGenerator<{ minDate?: string | Date; m const rng = prand.xoroshiro128plus(seed); let { minDate, maxDate } = this.params; + const { arraySize } = this.params; + + if (arraySize !== undefined) { + this.arraySize = arraySize; + } + const anchorDate = new Date('2024-05-08'); const deltaMilliseconds = 4 * 31536000000; @@ -832,7 +929,7 @@ export class GenerateDate extends AbstractGenerator<{ minDate?: string | Date; m return date; } } -export class GenerateTime extends AbstractGenerator<{}> { +export class GenerateTime extends AbstractGenerator<{ arraySize?: number }> { static override readonly [entityKind]: string = 'GenerateTime'; private state: { @@ -840,6 +937,10 @@ export class GenerateTime extends AbstractGenerator<{}> { } | undefined; init({ seed }: { seed: number }) { + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -899,7 +1000,7 @@ export class GenerateTimestampInt extends AbstractGenerator<{ unitOfTime?: 'seco } } -export class GenerateTimestamp extends AbstractGenerator<{}> { +export class GenerateTimestamp extends AbstractGenerator<{ arraySize?: number }> { static override readonly [entityKind]: string = 'GenerateTimestamp'; private state: { @@ -907,6 +1008,10 @@ export class GenerateTimestamp extends AbstractGenerator<{}> { } | undefined; init({ seed }: { seed: number }) { + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -941,7 +1046,7 @@ export class GenerateTimestamp extends AbstractGenerator<{}> { } } -export class GenerateDatetime extends AbstractGenerator<{}> { +export class GenerateDatetime extends AbstractGenerator<{ arraySize?: number }> { static override readonly [entityKind]: string = 'GenerateDatetime'; private state: { @@ -949,6 +1054,10 @@ export class GenerateDatetime extends AbstractGenerator<{}> { } | undefined; init({ seed }: { seed: number }) { + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -983,7 +1092,7 @@ export class GenerateDatetime extends AbstractGenerator<{}> { } } -export class GenerateYear extends AbstractGenerator<{}> { +export class GenerateYear extends AbstractGenerator<{ arraySize?: number }> { static override readonly [entityKind]: string = 'GenerateYear'; private state: { @@ -991,6 +1100,10 @@ export class GenerateYear extends AbstractGenerator<{}> { } | undefined; init({ seed }: { seed: number }) { + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -1016,7 +1129,7 @@ export class GenerateYear extends AbstractGenerator<{}> { } } -export class GenerateJson extends AbstractGenerator<{}> { +export class GenerateJson extends AbstractGenerator<{ arraySize?: number }> { static override readonly [entityKind]: string = 'GenerateJson'; private state: { @@ -1030,6 +1143,10 @@ export class GenerateJson extends AbstractGenerator<{}> { } | undefined; init({ count, seed }: { count: number; seed: number }) { + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const emailGeneratorObj = new GenerateEmail({}); emailGeneratorObj.init({ count, seed }); @@ -1140,7 +1257,10 @@ export class GenerateEnum extends AbstractGenerator<{ enumValues: (string | numb } } -export class GenerateInterval extends AbstractGenerator<{ isUnique?: boolean }> { +export class GenerateInterval extends AbstractGenerator<{ + isUnique?: boolean; + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateInterval'; private state: { rng: prand.RandomGenerator } | undefined; @@ -1155,6 +1275,10 @@ export class GenerateInterval extends AbstractGenerator<{ isUnique?: boolean }> this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; } @@ -1253,7 +1377,10 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boole } } -export class GenerateString extends AbstractGenerator<{ isUnique?: boolean }> { +export class GenerateString extends AbstractGenerator<{ + isUnique?: boolean; + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateString'; private state: { rng: prand.RandomGenerator } | undefined; @@ -1268,6 +1395,10 @@ export class GenerateString extends AbstractGenerator<{ isUnique?: boolean }> { this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; } @@ -1347,6 +1478,7 @@ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean export class GenerateFirstName extends AbstractGenerator<{ isUnique?: boolean; + arraySize?: number; }> { static override readonly [entityKind]: string = 'GenerateFirstName'; @@ -1365,6 +1497,10 @@ export class GenerateFirstName extends AbstractGenerator<{ this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -1418,7 +1554,10 @@ export class GenerateUniqueFirstName extends AbstractGenerator<{ } } -export class GenerateLastName extends AbstractGenerator<{ isUnique?: boolean }> { +export class GenerateLastName extends AbstractGenerator<{ + isUnique?: boolean; + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateLastName'; private state: { @@ -1435,6 +1574,10 @@ export class GenerateLastName extends AbstractGenerator<{ isUnique?: boolean }> this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -1484,6 +1627,7 @@ export class GenerateUniqueLastName extends AbstractGenerator<{ isUnique?: boole export class GenerateFullName extends AbstractGenerator<{ isUnique?: boolean; + arraySize?: number; }> { static override readonly [entityKind]: string = 'GenerateFullName'; @@ -1501,6 +1645,10 @@ export class GenerateFullName extends AbstractGenerator<{ this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -1581,7 +1729,9 @@ export class GenerateUniqueFullName extends AbstractGenerator<{ } } -export class GenerateEmail extends AbstractGenerator<{}> { +export class GenerateEmail extends AbstractGenerator<{ + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateEmail'; private state: { @@ -1596,6 +1746,10 @@ export class GenerateEmail extends AbstractGenerator<{}> { const adjectivesArray = adjectives; const namesArray = firstNames; + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const maxUniqueEmailsNumber = adjectivesArray.length * namesArray.length * domainsArray.length; if (count > maxUniqueEmailsNumber) { throw new RangeError( @@ -1638,6 +1792,7 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ template?: string; prefixes?: string[]; generatedDigitsNumbers?: number | number[]; + arraySize?: number; }> { static override readonly [entityKind]: string = 'GeneratePhoneNumber'; @@ -1653,7 +1808,11 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ init({ count, seed }: { count: number; seed: number }) { let { generatedDigitsNumbers } = this.params; - const { prefixes, template } = this.params; + const { prefixes, template, arraySize } = this.params; + + if (arraySize !== undefined) { + this.arraySize = arraySize; + } const rng = prand.xoroshiro128plus(seed); @@ -1809,7 +1968,10 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ } } -export class GenerateCountry extends AbstractGenerator<{ isUnique?: boolean }> { +export class GenerateCountry extends AbstractGenerator<{ + isUnique?: boolean; + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateCountry'; private state: { @@ -1826,6 +1988,10 @@ export class GenerateCountry extends AbstractGenerator<{ isUnique?: boolean }> { this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -1876,7 +2042,9 @@ export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolea } } -export class GenerateJobTitle extends AbstractGenerator<{}> { +export class GenerateJobTitle extends AbstractGenerator<{ + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateJobTitle'; private state: { @@ -1884,6 +2052,10 @@ export class GenerateJobTitle extends AbstractGenerator<{}> { } | undefined; init({ seed }: { seed: number }) { + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -1901,7 +2073,10 @@ export class GenerateJobTitle extends AbstractGenerator<{}> { } } -export class GenerateStreetAdddress extends AbstractGenerator<{ isUnique?: boolean }> { +export class GenerateStreetAdddress extends AbstractGenerator<{ + isUnique?: boolean; + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateStreetAdddress'; private state: { @@ -1919,6 +2094,10 @@ export class GenerateStreetAdddress extends AbstractGenerator<{ isUnique?: boole this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); const possStreetNames = [firstNames, lastNames]; this.state = { rng, possStreetNames }; @@ -2031,7 +2210,10 @@ export class GenerateUniqueStreetAdddress extends AbstractGenerator<{ isUnique?: } } -export class GenerateCity extends AbstractGenerator<{ isUnique?: boolean }> { +export class GenerateCity extends AbstractGenerator<{ + isUnique?: boolean; + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateCity'; private state: { @@ -2048,6 +2230,10 @@ export class GenerateCity extends AbstractGenerator<{ isUnique?: boolean }> { this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -2096,7 +2282,10 @@ export class GenerateUniqueCity extends AbstractGenerator<{ isUnique?: boolean } } } -export class GeneratePostcode extends AbstractGenerator<{ isUnique?: boolean }> { +export class GeneratePostcode extends AbstractGenerator<{ + isUnique?: boolean; + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GeneratePostcode'; private state: { @@ -2114,6 +2303,10 @@ export class GeneratePostcode extends AbstractGenerator<{ isUnique?: boolean }> this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); const templates = ['#####', '#####-####']; @@ -2226,7 +2419,9 @@ export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boole } } -export class GenerateState extends AbstractGenerator<{}> { +export class GenerateState extends AbstractGenerator<{ + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateState'; private state: { @@ -2234,6 +2429,10 @@ export class GenerateState extends AbstractGenerator<{}> { } | undefined; init({ seed }: { seed: number }) { + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -2251,7 +2450,10 @@ export class GenerateState extends AbstractGenerator<{}> { } } -export class GenerateCompanyName extends AbstractGenerator<{ isUnique?: boolean }> { +export class GenerateCompanyName extends AbstractGenerator<{ + isUnique?: boolean; + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateCompanyName'; private state: { @@ -2269,6 +2471,10 @@ export class GenerateCompanyName extends AbstractGenerator<{ isUnique?: boolean this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); const templates = [ { template: '#', placeholdersCount: 1 }, @@ -2419,7 +2625,10 @@ export class GenerateUniqueCompanyName extends AbstractGenerator<{ isUnique?: bo } } -export class GenerateLoremIpsum extends AbstractGenerator<{ sentencesCount?: number }> { +export class GenerateLoremIpsum extends AbstractGenerator<{ + sentencesCount?: number; + arraySize?: number; +}> { static override readonly [entityKind]: string = 'GenerateLoremIpsum'; private state: { @@ -2427,6 +2636,10 @@ export class GenerateLoremIpsum extends AbstractGenerator<{ sentencesCount?: num } | undefined; init({ seed }: { seed: number }) { + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const rng = prand.xoroshiro128plus(seed); if (this.params.sentencesCount === undefined) this.params.sentencesCount = 1; @@ -2517,6 +2730,7 @@ export class GeneratePoint extends AbstractGenerator<{ maxXValue?: number; minYValue?: number; maxYValue?: number; + arraySize?: number; }> { static override readonly [entityKind]: string = 'GeneratePoint'; @@ -2535,6 +2749,10 @@ export class GeneratePoint extends AbstractGenerator<{ this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const xCoordinateGen = new GenerateNumber({ minValue: this.params.minXValue, maxValue: this.params.maxXValue, @@ -2630,6 +2848,7 @@ export class GenerateLine extends AbstractGenerator<{ maxBValue?: number; minCValue?: number; maxCValue?: number; + arraySize?: number; }> { static override readonly [entityKind]: string = 'GenerateLine'; @@ -2649,6 +2868,10 @@ export class GenerateLine extends AbstractGenerator<{ this.isUnique = this.params.isUnique; } + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + const aCoefficientGen = new GenerateNumber({ minValue: this.params.minAValue, maxValue: this.params.maxAValue, diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 2588f110e..e4bceefc2 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -14,6 +14,7 @@ import type { import type { Column, Prettify, Relation, Table } from '../types/tables.ts'; import type { AbstractGenerator } from './GeneratorsWrappers.ts'; import { + GenerateArray, GenerateBoolean, GenerateDate, GenerateDatetime, @@ -189,7 +190,7 @@ class SeedService { && refinements[table.name]!.columns[col.name] !== undefined ) { const genObj = refinements[table.name]!.columns[col.name]!; - // for now only GenerateValuesFromArray support notNull property + // TODO: for now only GenerateValuesFromArray support notNull property genObj.notNull = col.notNull; columnPossibleGenerator.generator = genObj; @@ -202,20 +203,17 @@ class SeedService { }); } // TODO: rewrite pickGeneratorFor... using new col properties: isUnique and notNull else if (connectionType === 'postgresql') { - columnPossibleGenerator = this.pickGeneratorForPostgresColumn( - columnPossibleGenerator, + columnPossibleGenerator.generator = this.pickGeneratorForPostgresColumn( table, col, ); } else if (connectionType === 'mysql') { - columnPossibleGenerator = this.pickGeneratorForMysqlColumn( - columnPossibleGenerator, + columnPossibleGenerator.generator = this.pickGeneratorForMysqlColumn( table, col, ); } else if (connectionType === 'sqlite') { - columnPossibleGenerator = this.pickGeneratorForSqlite( - columnPossibleGenerator, + columnPossibleGenerator.generator = this.pickGeneratorForSqlite( table, col, ); @@ -346,7 +344,6 @@ class SeedService { // TODO: revise serial part generators pickGeneratorForPostgresColumn = ( - columnPossibleGenerator: Prettify, table: Table, col: Column, ) => { @@ -358,8 +355,8 @@ class SeedService { || col.columnType.includes('bigint')) && table.primaryKeys.includes(col.name) ) { - columnPossibleGenerator.generator = new GenerateIntPrimaryKey({}); - return columnPossibleGenerator; + const generator = new GenerateIntPrimaryKey({}); + return generator; } let minValue: number | bigint | undefined; @@ -404,17 +401,17 @@ class SeedService { && !col.columnType.includes('interval') && !col.columnType.includes('point') ) { - columnPossibleGenerator.generator = new GenerateInt({ + const generator = new GenerateInt({ minValue, maxValue, }); - return columnPossibleGenerator; + return generator; } if (col.columnType.includes('serial')) { - const genObj = new GenerateIntPrimaryKey({}); - genObj.maxValue = maxValue; - columnPossibleGenerator.generator = genObj; + const generator = new GenerateIntPrimaryKey({}); + generator.maxValue = maxValue; + return generator; } // NUMBER(real, double, decimal, numeric) @@ -424,8 +421,8 @@ class SeedService { || col.columnType === 'decimal' || col.columnType === 'numeric' ) { - columnPossibleGenerator.generator = new GenerateNumber({}); - return columnPossibleGenerator; + const generator = new GenerateNumber({}); + return generator; } // STRING @@ -435,8 +432,8 @@ class SeedService { || col.columnType === 'char') && table.primaryKeys.includes(col.name) ) { - columnPossibleGenerator.generator = new GenerateUniqueString({}); - return columnPossibleGenerator; + const generator = new GenerateUniqueString({}); + return generator; } if ( @@ -445,8 +442,8 @@ class SeedService { || col.columnType === 'char') && col.name.toLowerCase().includes('name') ) { - columnPossibleGenerator.generator = new GenerateFirstName({}); - return columnPossibleGenerator; + const generator = new GenerateFirstName({}); + return generator; } if ( @@ -455,8 +452,8 @@ class SeedService { || col.columnType === 'char') && col.name.toLowerCase().includes('email') ) { - columnPossibleGenerator.generator = new GenerateEmail({}); - return columnPossibleGenerator; + const generator = new GenerateEmail({}); + return generator; } if ( @@ -465,73 +462,82 @@ class SeedService { || col.columnType === 'char' ) { // console.log(col, table) - columnPossibleGenerator.generator = new GenerateString({}); - return columnPossibleGenerator; + const generator = new GenerateString({}); + return generator; } // BOOLEAN if (col.columnType === 'boolean') { - columnPossibleGenerator.generator = new GenerateBoolean({}); - return columnPossibleGenerator; + const generator = new GenerateBoolean({}); + return generator; } // DATE, TIME, TIMESTAMP if (col.columnType.includes('date')) { - columnPossibleGenerator.generator = new GenerateDate({}); - return columnPossibleGenerator; + const generator = new GenerateDate({}); + return generator; } if (col.columnType === 'time') { - columnPossibleGenerator.generator = new GenerateTime({}); - return columnPossibleGenerator; + const generator = new GenerateTime({}); + return generator; } if (col.columnType.includes('timestamp')) { - columnPossibleGenerator.generator = new GenerateTimestamp({}); - return columnPossibleGenerator; + const generator = new GenerateTimestamp({}); + return generator; } // JSON, JSONB if (col.columnType === 'json' || col.columnType === 'jsonb') { - columnPossibleGenerator.generator = new GenerateJson({}); - return columnPossibleGenerator; + const generator = new GenerateJson({}); + return generator; } // if (col.columnType === "jsonb") { - // columnPossibleGenerator.generator = new GenerateJsonb({}); - // return columnPossibleGenerator; + // const generator = new GenerateJsonb({}); + // return generator; // } // ENUM if (col.enumValues !== undefined) { - columnPossibleGenerator.generator = new GenerateEnum({ + const generator = new GenerateEnum({ enumValues: col.enumValues, }); - return columnPossibleGenerator; + return generator; } // INTERVAL if (col.columnType === 'interval') { - columnPossibleGenerator.generator = new GenerateInterval({}); - return columnPossibleGenerator; + const generator = new GenerateInterval({}); + return generator; } // POINT, LINE if (col.columnType.includes('point')) { - columnPossibleGenerator.generator = new GeneratePoint({}); - return columnPossibleGenerator; + const generator = new GeneratePoint({}); + return generator; } if (col.columnType.includes('line')) { - columnPossibleGenerator.generator = new GenerateLine({}); - return columnPossibleGenerator; + const generator = new GenerateLine({}); + return generator; } - return columnPossibleGenerator; + // ARRAY + if (col.columnType.includes('array') && col.baseColumn !== undefined) { + const baseColumnGen = this.pickGeneratorForPostgresColumn(table, col.baseColumn!) as AbstractGenerator; + if (baseColumnGen === undefined) { + throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); + } + const generator = new GenerateArray({ baseColumnGen, size: col.size }); + return generator; + } + + return; }; pickGeneratorForMysqlColumn = ( - columnPossibleGenerator: Prettify, table: Table, col: Column, ) => { @@ -541,8 +547,8 @@ class SeedService { (col.columnType.includes('serial') || col.columnType.includes('int')) && table.primaryKeys.includes(col.name) ) { - columnPossibleGenerator.generator = new GenerateIntPrimaryKey({}); - return columnPossibleGenerator; + const generator = new GenerateIntPrimaryKey({}); + return generator; } let minValue: number | bigint | undefined; @@ -576,17 +582,17 @@ class SeedService { } if (col.columnType.includes('int')) { - columnPossibleGenerator.generator = new GenerateInt({ + const generator = new GenerateInt({ minValue, maxValue, }); - return columnPossibleGenerator; + return generator; } if (col.columnType.includes('serial')) { - const genObj = new GenerateIntPrimaryKey({}); - genObj.maxValue = maxValue; - columnPossibleGenerator.generator = genObj; + const generator = new GenerateIntPrimaryKey({}); + generator.maxValue = maxValue; + return generator; } // NUMBER(real, double, decimal, float) @@ -596,8 +602,8 @@ class SeedService { || col.columnType === 'decimal' || col.columnType === 'float' ) { - columnPossibleGenerator.generator = new GenerateNumber({}); - return columnPossibleGenerator; + const generator = new GenerateNumber({}); + return generator; } // STRING @@ -610,8 +616,8 @@ class SeedService { || col.columnType.includes('varbinary')) && table.primaryKeys.includes(col.name) ) { - columnPossibleGenerator.generator = new GenerateUniqueString({}); - return columnPossibleGenerator; + const generator = new GenerateUniqueString({}); + return generator; } if ( @@ -623,8 +629,8 @@ class SeedService { || col.columnType.includes('varbinary')) && col.name.toLowerCase().includes('name') ) { - columnPossibleGenerator.generator = new GenerateFirstName({}); - return columnPossibleGenerator; + const generator = new GenerateFirstName({}); + return generator; } if ( @@ -636,8 +642,8 @@ class SeedService { || col.columnType.includes('varbinary')) && col.name.toLowerCase().includes('email') ) { - columnPossibleGenerator.generator = new GenerateEmail({}); - return columnPossibleGenerator; + const generator = new GenerateEmail({}); + return generator; } if ( @@ -649,61 +655,60 @@ class SeedService { || col.columnType.includes('varbinary') ) { // console.log(col, table); - columnPossibleGenerator.generator = new GenerateString({}); - return columnPossibleGenerator; + const generator = new GenerateString({}); + return generator; } // BOOLEAN if (col.columnType === 'boolean') { - columnPossibleGenerator.generator = new GenerateBoolean({}); - return columnPossibleGenerator; + const generator = new GenerateBoolean({}); + return generator; } // DATE, TIME, TIMESTAMP, DATETIME, YEAR if (col.columnType.includes('datetime')) { - columnPossibleGenerator.generator = new GenerateDatetime({}); - return columnPossibleGenerator; + const generator = new GenerateDatetime({}); + return generator; } if (col.columnType.includes('date')) { - columnPossibleGenerator.generator = new GenerateDate({}); - return columnPossibleGenerator; + const generator = new GenerateDate({}); + return generator; } if (col.columnType === 'time') { - columnPossibleGenerator.generator = new GenerateTime({}); - return columnPossibleGenerator; + const generator = new GenerateTime({}); + return generator; } if (col.columnType.includes('timestamp')) { - columnPossibleGenerator.generator = new GenerateTimestamp({}); - return columnPossibleGenerator; + const generator = new GenerateTimestamp({}); + return generator; } if (col.columnType === 'year') { - columnPossibleGenerator.generator = new GenerateYear({}); - return columnPossibleGenerator; + const generator = new GenerateYear({}); + return generator; } // JSON if (col.columnType === 'json') { - columnPossibleGenerator.generator = new GenerateJson({}); - return columnPossibleGenerator; + const generator = new GenerateJson({}); + return generator; } // ENUM if (col.enumValues !== undefined) { - columnPossibleGenerator.generator = new GenerateEnum({ + const generator = new GenerateEnum({ enumValues: col.enumValues, }); - return columnPossibleGenerator; + return generator; } - return columnPossibleGenerator; + return; }; pickGeneratorForSqlite = ( - columnPossibleGenerator: Prettify, table: Table, col: Column, ) => { @@ -712,8 +717,8 @@ class SeedService { (col.columnType === 'integer' || col.columnType === 'numeric') && table.primaryKeys.includes(col.name) ) { - columnPossibleGenerator.generator = new GenerateIntPrimaryKey({}); - return columnPossibleGenerator; + const generator = new GenerateIntPrimaryKey({}); + return generator; } if ( @@ -721,19 +726,19 @@ class SeedService { || col.columnType === 'numeric' || col.columnType === 'bigint' ) { - columnPossibleGenerator.generator = new GenerateInt({}); - return columnPossibleGenerator; + const generator = new GenerateInt({}); + return generator; } if (col.columnType === 'boolean') { - columnPossibleGenerator.generator = new GenerateBoolean({}); - return columnPossibleGenerator; + const generator = new GenerateBoolean({}); + return generator; } // number section ------------------------------------------------------------------------------------ if (col.columnType === 'real' || col.columnType === 'numeric') { - columnPossibleGenerator.generator = new GenerateNumber({}); - return columnPossibleGenerator; + const generator = new GenerateNumber({}); + return generator; } // string section ------------------------------------------------------------------------------------ @@ -743,8 +748,8 @@ class SeedService { || col.columnType === 'blob') && table.primaryKeys.includes(col.name) ) { - columnPossibleGenerator.generator = new GenerateUniqueString({}); - return columnPossibleGenerator; + const generator = new GenerateUniqueString({}); + return generator; } if ( @@ -753,8 +758,8 @@ class SeedService { || col.columnType === 'blob') && col.name.toLowerCase().includes('name') ) { - columnPossibleGenerator.generator = new GenerateFirstName({}); - return columnPossibleGenerator; + const generator = new GenerateFirstName({}); + return generator; } if ( @@ -763,8 +768,8 @@ class SeedService { || col.columnType === 'blob') && col.name.toLowerCase().includes('email') ) { - columnPossibleGenerator.generator = new GenerateEmail({}); - return columnPossibleGenerator; + const generator = new GenerateEmail({}); + return generator; } if ( @@ -773,21 +778,21 @@ class SeedService { || col.columnType === 'blob' || col.columnType === 'blobbuffer' ) { - columnPossibleGenerator.generator = new GenerateString({}); - return columnPossibleGenerator; + const generator = new GenerateString({}); + return generator; } if (col.columnType === 'textjson' || col.columnType === 'blobjson') { - columnPossibleGenerator.generator = new GenerateJson({}); - return columnPossibleGenerator; + const generator = new GenerateJson({}); + return generator; } if (col.columnType === 'timestamp' || col.columnType === 'timestamp_ms') { - columnPossibleGenerator.generator = new GenerateTimestamp({}); - return columnPossibleGenerator; + const generator = new GenerateTimestamp({}); + return generator; } - return columnPossibleGenerator; + return; }; generateTablesValues = async ( @@ -1017,20 +1022,13 @@ class SeedService { seed: columnGenerator.pRNGSeed, }); - if ( - columnsGenerators[columnName]!.uniqueVersionOfGen !== undefined - && columnsGenerators[columnName]!.isUnique === true - ) { - const uniqueGen = new columnsGenerators[columnName]!.uniqueVersionOfGen!({ - ...columnsGenerators[columnName]!.params, - }); - uniqueGen.init({ - count, - seed: columnGenerator.pRNGSeed, - }); - uniqueGen.isUnique = columnsGenerators[columnName]!.isUnique; - uniqueGen.dataType = columnsGenerators[columnName]!.dataType; + const arrayGen = columnsGenerators[columnName]!.replaceIfArray({ count, seed: columnGenerator.pRNGSeed }); + if (arrayGen !== undefined) { + columnsGenerators[columnName] = arrayGen; + } + const uniqueGen = columnsGenerators[columnName]!.replaceIfUnique({ count, seed: columnGenerator.pRNGSeed }); + if (uniqueGen !== undefined) { columnsGenerators[columnName] = uniqueGen; } } diff --git a/drizzle-seed/src/types/tables.ts b/drizzle-seed/src/types/tables.ts index 637e96c48..7e472cf2b 100644 --- a/drizzle-seed/src/types/tables.ts +++ b/drizzle-seed/src/types/tables.ts @@ -4,12 +4,24 @@ export type Column = { name: string; dataType: string; columnType: string; + size?: number; default?: any; hasDefault: boolean; enumValues?: string[]; isUnique: boolean; notNull: boolean; generatedIdentityType?: 'always' | 'byDefault' | undefined; + baseColumn?: { + name: string; + dataType: string; + columnType: string; + size?: number; + default?: any; + hasDefault: boolean; + isUnique: boolean; + notNull: boolean; + baseColumn?: Column['baseColumn']; + }; }; export type Table = { From b71f896594b615d74f9ad2bff5082566799302b8 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 28 Nov 2024 11:08:16 +0200 Subject: [PATCH 399/492] Fix integration tests by removing RQB support for now --- drizzle-orm/src/singlestore-core/db.ts | 51 +- drizzle-orm/src/singlestore-core/dialect.ts | 2 +- .../tests/relational/singlestore.test.ts | 12805 ++++++++-------- .../tests/replicas/singlestore.test.ts | 445 +- .../tests/singlestore/singlestore-common.ts | 8 +- integration-tests/vitest.config.ts | 2 + 6 files changed, 6654 insertions(+), 6659 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts index 6e8f18f44..1d64448da 100644 --- a/drizzle-orm/src/singlestore-core/db.ts +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -3,9 +3,9 @@ import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreDriverDatabase } from '~/singlestore/driver.ts'; import { type ColumnsSelection, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; -import type { DrizzleTypeError } from '~/utils.ts'; import type { SingleStoreDialect } from './dialect.ts'; import { SingleStoreCountBuilder } from './query-builders/count.ts'; import { @@ -15,7 +15,6 @@ import { SingleStoreSelectBuilder, SingleStoreUpdateBuilder, } from './query-builders/index.ts'; -import { RelationalQueryBuilder } from './query-builders/query.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import type { PreparedQueryHKTBase, @@ -42,11 +41,9 @@ export class SingleStoreDatabase< readonly tableNamesMap: Record; }; - query: TFullSchema extends Record - ? DrizzleTypeError<'Seems like the schema generic is missing - did you forget to add it to your DB type?'> - : { - [K in keyof TSchema]: RelationalQueryBuilder; - }; + // We are waiting for SingleStore support for `json_array` function + /**@inrernal */ + query: unknown; constructor( /** @internal */ @@ -67,20 +64,21 @@ export class SingleStoreDatabase< tableNamesMap: {}, }; this.query = {} as typeof this['query']; - if (this._.schema) { - for (const [tableName, columns] of Object.entries(this._.schema)) { - (this.query as SingleStoreDatabase>['query'])[tableName] = - new RelationalQueryBuilder( - schema!.fullSchema, - this._.schema, - this._.tableNamesMap, - schema!.fullSchema[tableName] as SingleStoreTable, - columns, - dialect, - session, - ); - } - } + // this.queryNotSupported = true; + // if (this._.schema) { + // for (const [tableName, columns] of Object.entries(this._.schema)) { + // (this.query as SingleStoreDatabase>['query'])[tableName] = + // new RelationalQueryBuilder( + // schema!.fullSchema, + // this._.schema, + // this._.tableNamesMap, + // schema!.fullSchema[tableName] as SingleStoreTable, + // columns, + // dialect, + // session, + // ); + // } + // } } /** @@ -484,16 +482,7 @@ export class SingleStoreDatabase< export type SingleStoreWithReplicas = Q & { $primary: Q }; export const withReplicas = < - HKT extends SingleStoreQueryResultHKT, - TPreparedQueryHKT extends PreparedQueryHKTBase, - TFullSchema extends Record, - TSchema extends TablesRelationalConfig, - Q extends SingleStoreDatabase< - HKT, - TPreparedQueryHKT, - TFullSchema, - TSchema extends Record ? ExtractTablesWithRelations : TSchema - >, + Q extends SingleStoreDriverDatabase, >( primary: Q, replicas: [Q, ...Q[]], diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts index 4ac14d88c..99a485ac6 100644 --- a/drizzle-orm/src/singlestore-core/dialect.ts +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -717,7 +717,7 @@ export class SingleStoreDialect { where = and(joinOn, where); if (nestedQueryRelation) { - let field = sql`JSON_BUILD_OBJECT(${ + let field = sql`JSON_TO_ARRAY(${ sql.join( selection.map(({ field, tsKey, isJson }) => isJson diff --git a/integration-tests/tests/relational/singlestore.test.ts b/integration-tests/tests/relational/singlestore.test.ts index 50aa2e8f4..0e20a7046 100644 --- a/integration-tests/tests/relational/singlestore.test.ts +++ b/integration-tests/tests/relational/singlestore.test.ts @@ -1,6402 +1,6403 @@ -import retry from 'async-retry'; -import Docker from 'dockerode'; -import 'dotenv/config'; -import { desc, DrizzleError, eq, gt, gte, or, placeholder, sql, TransactionRollbackError } from 'drizzle-orm'; -import { drizzle, type SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; -import getPort from 'get-port'; -import * as mysql from 'mysql2/promise'; -import { v4 as uuid } from 'uuid'; -import { afterAll, beforeAll, beforeEach, expect, expectTypeOf, test } from 'vitest'; -import * as schema from './singlestore.schema.ts'; - -const { usersTable, postsTable, commentsTable, usersToGroupsTable, groupsTable } = schema; - -const ENABLE_LOGGING = false; - -/* - Test cases: - - querying nested relation without PK with additional fields -*/ - -declare module 'vitest' { - export interface TestContext { - docker: Docker; - singlestoreContainer: Docker.Container; - singlestoreDb: SingleStoreDriverDatabase; - singlestoreClient: mysql.Connection; - } -} - -let globalDocker: Docker; -let singlestoreContainer: Docker.Container; -let db: SingleStoreDriverDatabase; -let client: mysql.Connection; - -async function createDockerDB(): Promise { - const docker = new Docker(); - const port = await getPort({ port: 3306 }); - const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; - - const pullStream = await docker.pull(image); - await new Promise((resolve, reject) => - docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) - ); - - singlestoreContainer = await docker.createContainer({ - Image: image, - Env: ['ROOT_PASSWORD=singlestore'], - name: `drizzle-integration-tests-${uuid()}`, - HostConfig: { - AutoRemove: true, - PortBindings: { - '3306/tcp': [{ HostPort: `${port}` }], - }, - }, - }); - - await singlestoreContainer.start(); - await new Promise((resolve) => setTimeout(resolve, 4000)); - - return `singlestore://root:singlestore@localhost:${port}/`; -} - -beforeAll(async () => { - const connectionString = process.env['SINGLESTORE_CONNECTION_STRING'] ?? (await createDockerDB()); - client = await retry(async () => { - client = await mysql.createConnection(connectionString); - await client.connect(); - return client; - }, { - retries: 20, - factor: 1, - minTimeout: 250, - maxTimeout: 250, - randomize: false, - onRetry() { - client?.end(); - }, - }); - - await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); - await client.changeUser({ database: 'drizzle' }); - db = drizzle(client, { schema, logger: ENABLE_LOGGING }); -}); - -afterAll(async () => { - await client?.end().catch(console.error); - await singlestoreContainer?.stop().catch(console.error); -}); - -beforeEach(async (ctx) => { - ctx.singlestoreDb = db; - ctx.singlestoreClient = client; - ctx.docker = globalDocker; - ctx.singlestoreContainer = singlestoreContainer; - - await ctx.singlestoreDb.execute(sql`drop table if exists \`users\``); - await ctx.singlestoreDb.execute(sql`drop table if exists \`groups\``); - await ctx.singlestoreDb.execute(sql`drop table if exists \`users_to_groups\``); - await ctx.singlestoreDb.execute(sql`drop table if exists \`posts\``); - await ctx.singlestoreDb.execute(sql`drop table if exists \`comments\``); - await ctx.singlestoreDb.execute(sql`drop table if exists \`comment_likes\``); - - await ctx.singlestoreDb.execute( - sql` - CREATE TABLE \`users\` ( - \`id\` serial PRIMARY KEY NOT NULL, - \`name\` text NOT NULL, - \`verified\` boolean DEFAULT false NOT NULL, - \`invited_by\` bigint - ); - `, - ); - await ctx.singlestoreDb.execute( - sql` - CREATE TABLE \`groups\` ( - \`id\` serial PRIMARY KEY NOT NULL, - \`name\` text NOT NULL, - \`description\` text - ); - `, - ); - await ctx.singlestoreDb.execute( - sql` - CREATE TABLE \`users_to_groups\` ( - \`id\` serial PRIMARY KEY NOT NULL, - \`user_id\` bigint, - \`group_id\` bigint - ); - `, - ); - await ctx.singlestoreDb.execute( - sql` - CREATE TABLE \`posts\` ( - \`id\` serial PRIMARY KEY NOT NULL, - \`content\` text NOT NULL, - \`owner_id\` bigint, - \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL - ); - `, - ); - await ctx.singlestoreDb.execute( - sql` - CREATE TABLE \`comments\` ( - \`id\` serial PRIMARY KEY NOT NULL, - \`content\` text NOT NULL, - \`creator\` bigint, - \`post_id\` bigint, - \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL - ); - `, - ); - await ctx.singlestoreDb.execute( - sql` - CREATE TABLE \`comment_likes\` ( - \`id\` serial PRIMARY KEY NOT NULL, - \`creator\` bigint, - \`comment_id\` bigint, - \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL - ); - `, - ); -}); - -/* - [Find Many] One relation users+posts -*/ - -test('[Find Many] Get users with posts', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - with: { - posts: true, - }, - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(usersWithPosts.length).eq(3); - expect(usersWithPosts[0]?.posts.length).eq(1); - expect(usersWithPosts[1]?.posts.length).eq(1); - expect(usersWithPosts[2]?.posts.length).eq(1); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); - expect(usersWithPosts[1]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], - }); - expect(usersWithPosts[2]).toEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - posts: [{ id: 3, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], - }); -}); - -test.skip('[Find Many] Get users with posts + limit posts', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - with: { - posts: { - limit: 1, - }, - }, - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); - usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); - usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); - usersWithPosts[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(usersWithPosts.length).eq(3); - expect(usersWithPosts[0]?.posts.length).eq(1); - expect(usersWithPosts[1]?.posts.length).eq(1); - expect(usersWithPosts[2]?.posts.length).eq(1); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); - expect(usersWithPosts[1]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], - }); - expect(usersWithPosts[2]).toEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], - }); -}); - -test.skip('[Find Many] Get users with posts + limit posts and users', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - limit: 2, - with: { - posts: { - limit: 1, - }, - }, - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); - usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); - usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(usersWithPosts.length).eq(2); - expect(usersWithPosts[0]?.posts.length).eq(1); - expect(usersWithPosts[1]?.posts.length).eq(1); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); - expect(usersWithPosts[1]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], - }); -}); - -test('[Find Many] Get users with posts + custom fields', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - with: { - posts: true, - }, - extras: ({ name }) => ({ - lowerName: sql`lower(${name})`.as('name_lower'), - }), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - lowerName: string; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); - usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); - usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); - usersWithPosts[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(usersWithPosts.length).toEqual(3); - expect(usersWithPosts[0]?.posts.length).toEqual(3); - expect(usersWithPosts[1]?.posts.length).toEqual(2); - expect(usersWithPosts[2]?.posts.length).toEqual(2); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - lowerName: 'dan', - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }, { - id: 2, - ownerId: 1, - content: 'Post1.2', - createdAt: usersWithPosts[0]?.posts[1]?.createdAt, - }, { id: 3, ownerId: 1, content: 'Post1.3', createdAt: usersWithPosts[0]?.posts[2]?.createdAt }], - }); - expect(usersWithPosts[1]).toEqual({ - id: 2, - name: 'Andrew', - lowerName: 'andrew', - verified: false, - invitedBy: null, - posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }, { - id: 5, - ownerId: 2, - content: 'Post2.1', - createdAt: usersWithPosts[1]?.posts[1]?.createdAt, - }], - }); - expect(usersWithPosts[2]).toEqual({ - id: 3, - name: 'Alex', - lowerName: 'alex', - verified: false, - invitedBy: null, - posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }, { - id: 7, - ownerId: 3, - content: 'Post3.1', - createdAt: usersWithPosts[2]?.posts[1]?.createdAt, - }], - }); -}); - -test.skip('[Find Many] Get users with posts + custom fields + limits', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - limit: 1, - with: { - posts: { - limit: 1, - }, - }, - extras: (usersTable, { sql }) => ({ - lowerName: sql`lower(${usersTable.name})`.as('name_lower'), - }), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - lowerName: string; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - expect(usersWithPosts.length).toEqual(1); - expect(usersWithPosts[0]?.posts.length).toEqual(1); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - name: 'Dan', - lowerName: 'dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); -}); - -test.skip('[Find Many] Get users with posts + orderBy', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: '1' }, - { ownerId: 1, content: '2' }, - { ownerId: 1, content: '3' }, - { ownerId: 2, content: '4' }, - { ownerId: 2, content: '5' }, - { ownerId: 3, content: '6' }, - { ownerId: 3, content: '7' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - with: { - posts: { - orderBy: (postsTable, { desc }) => [desc(postsTable.content)], - }, - }, - orderBy: (usersTable, { desc }) => [desc(usersTable.id)], - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(3); - expect(usersWithPosts[0]?.posts.length).eq(2); - expect(usersWithPosts[1]?.posts.length).eq(2); - expect(usersWithPosts[2]?.posts.length).eq(3); - - expect(usersWithPosts[2]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ id: 3, ownerId: 1, content: '3', createdAt: usersWithPosts[2]?.posts[2]?.createdAt }, { - id: 2, - ownerId: 1, - content: '2', - createdAt: usersWithPosts[2]?.posts[1]?.createdAt, - }, { id: 1, ownerId: 1, content: '1', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], - }); - expect(usersWithPosts[1]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - posts: [{ - id: 5, - ownerId: 2, - content: '5', - createdAt: usersWithPosts[1]?.posts[1]?.createdAt, - }, { id: 4, ownerId: 2, content: '4', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], - }); - expect(usersWithPosts[0]).toEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - posts: [{ - id: 7, - ownerId: 3, - content: '7', - createdAt: usersWithPosts[0]?.posts[1]?.createdAt, - }, { id: 6, ownerId: 3, content: '6', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); -}); - -test('[Find Many] Get users with posts + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - where: (({ id }, { eq }) => eq(id, 1)), - with: { - posts: { - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(1); - expect(usersWithPosts[0]?.posts.length).eq(1); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); -}); - -test('[Find Many] Get users with posts + where + partial', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - columns: { - id: true, - name: true, - }, - with: { - posts: { - columns: { - id: true, - content: true, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - posts: { - id: number; - content: string; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(1); - expect(usersWithPosts[0]?.posts.length).eq(1); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - name: 'Dan', - posts: [{ id: 1, content: 'Post1' }], - }); -}); - -test('[Find Many] Get users with posts + where + partial. Did not select posts id, but used it in where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - columns: { - id: true, - name: true, - }, - with: { - posts: { - columns: { - id: true, - content: true, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - posts: { - id: number; - content: string; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(1); - expect(usersWithPosts[0]?.posts.length).eq(1); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - name: 'Dan', - posts: [{ id: 1, content: 'Post1' }], - }); -}); - -test('[Find Many] Get users with posts + where + partial(true + false)', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - columns: { - id: true, - name: false, - }, - with: { - posts: { - columns: { - id: true, - content: false, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - posts: { - id: number; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(1); - expect(usersWithPosts[0]?.posts.length).eq(1); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - posts: [{ id: 1 }], - }); -}); - -test('[Find Many] Get users with posts + where + partial(false)', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - columns: { - name: false, - }, - with: { - posts: { - columns: { - content: false, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(1); - expect(usersWithPosts[0]?.posts.length).eq(1); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); -}); - -test('[Find Many] Get users with posts in transaction', async (t) => { - const { singlestoreDb: db } = t; - - let usersWithPosts: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[] = []; - - await db.transaction(async (tx) => { - await tx.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await tx.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - usersWithPosts = await tx.query.usersTable.findMany({ - where: (({ id }, { eq }) => eq(id, 1)), - with: { - posts: { - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - }); - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(1); - expect(usersWithPosts[0]?.posts.length).eq(1); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); -}); - -test('[Find Many] Get users with posts in rollbacked transaction', async (t) => { - const { singlestoreDb: db } = t; - - let usersWithPosts: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[] = []; - - await expect(db.transaction(async (tx) => { - await tx.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await tx.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - tx.rollback(); - - usersWithPosts = await tx.query.usersTable.findMany({ - where: (({ id }, { eq }) => eq(id, 1)), - with: { - posts: { - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - }); - })).rejects.toThrowError(new TransactionRollbackError()); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(0); -}); - -// select only custom -test('[Find Many] Get only custom fields', async () => { - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { id: 1, ownerId: 1, content: 'Post1' }, - { id: 2, ownerId: 1, content: 'Post1.2' }, - { id: 3, ownerId: 1, content: 'Post1.3' }, - { id: 4, ownerId: 2, content: 'Post2' }, - { id: 5, ownerId: 2, content: 'Post2.1' }, - { id: 6, ownerId: 3, content: 'Post3' }, - { id: 7, ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - columns: {}, - with: { - posts: { - columns: {}, - extras: ({ content }) => ({ - lowerName: sql`lower(${content})`.as('content_lower'), - }), - }, - }, - extras: ({ name }) => ({ - lowerName: sql`lower(${name})`.as('name_lower'), - }), - }); - - // Type Assertion - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - lowerName: string; - posts: { - lowerName: string; - }[]; - }[]>(); - - // General Assertions - expect(usersWithPosts).toHaveLength(3); - - // Helper function to find user by lowerName - const findUser = (lowerName: string) => usersWithPosts.find((user) => user.lowerName === lowerName); - - // Assertions for each user - const dan = findUser('dan'); - const andrew = findUser('andrew'); - const alex = findUser('alex'); - - expect(dan).toBeDefined(); - expect(andrew).toBeDefined(); - expect(alex).toBeDefined(); - - // Verify the number of posts for each user - expect(dan?.posts).toHaveLength(3); - expect(andrew?.posts).toHaveLength(2); - expect(alex?.posts).toHaveLength(2); - - // Define expected posts for each user - const expectedDanPosts = ['post1', 'post1.2', 'post1.3']; - const expectedAndrewPosts = ['post2', 'post2.1']; - const expectedAlexPosts = ['post3', 'post3.1']; - - // Helper function to extract lowerNames from posts - const getPostLowerNames = (posts: { lowerName: string }[]) => posts.map((post) => post.lowerName); - - // Assertions for Dan's posts - expect(getPostLowerNames(dan!.posts)).toEqual(expect.arrayContaining(expectedDanPosts)); - expect(getPostLowerNames(dan!.posts)).toHaveLength(expectedDanPosts.length); - - // Assertions for Andrew's posts - expect(getPostLowerNames(andrew!.posts)).toEqual(expect.arrayContaining(expectedAndrewPosts)); - expect(getPostLowerNames(andrew!.posts)).toHaveLength(expectedAndrewPosts.length); - - // Assertions for Alex's posts - expect(getPostLowerNames(alex!.posts)).toEqual(expect.arrayContaining(expectedAlexPosts)); - expect(getPostLowerNames(alex!.posts)).toHaveLength(expectedAlexPosts.length); -}); - -// select only custom with where clause (Order Agnostic) -test('[Find Many] Get only custom fields + where', async (t) => { - const { singlestoreDb: db } = t; - - // Insert Users - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - // Insert Posts - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - // Query Users with Posts where users.id = 1 and posts.id >= 2 - const usersWithPosts = await db.query.usersTable.findMany({ - columns: {}, - with: { - posts: { - columns: {}, - where: gte(postsTable.id, 2), - extras: ({ content }) => ({ - lowerName: sql`lower(${content})`.as('content_lower'), - }), - }, - }, - where: eq(usersTable.id, 1), - extras: ({ name }) => ({ - lowerName: sql`lower(${name})`.as('name_lower'), - }), - }); - - // Type Assertion - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - lowerName: string; - posts: { - lowerName: string; - }[]; - }[]>(); - - // General Assertions - expect(usersWithPosts).toHaveLength(1); - - // Since we expect only one user, we can extract it directly - const danWithPosts = usersWithPosts[0]; - - // Assert that the user exists and has the correct lowerName - expect(danWithPosts).toBeDefined(); - expect(danWithPosts?.lowerName).toBe('dan'); - - // Assert that the user has the expected number of posts - expect(danWithPosts?.posts).toHaveLength(2); - - // Define the expected posts - const expectedPosts = ['post1.2', 'post1.3']; - - // Extract the lowerName of each post - const actualPostLowerNames = danWithPosts?.posts.map((post) => post.lowerName); - - // Assert that all expected posts are present, regardless of order - for (const expectedPost of expectedPosts) { - expect(actualPostLowerNames).toContain(expectedPost); - } - - // Additionally, ensure no unexpected posts are present - expect(actualPostLowerNames).toHaveLength(expectedPosts.length); -}); - -test.skip('[Find Many] Get only custom fields + where + limit', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - columns: {}, - with: { - posts: { - columns: {}, - where: gte(postsTable.id, 2), - limit: 1, - extras: ({ content }) => ({ - lowerName: sql`lower(${content})`.as('content_lower'), - }), - }, - }, - where: eq(usersTable.id, 1), - extras: ({ name }) => ({ - lowerName: sql`lower(${name})`.as('name_lower'), - }), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - lowerName: string; - posts: { - lowerName: string; - }[]; - }[]>(); - - expect(usersWithPosts.length).toEqual(1); - expect(usersWithPosts[0]?.posts.length).toEqual(1); - - expect(usersWithPosts).toContainEqual({ - lowerName: 'dan', - posts: [{ lowerName: 'post1.2' }], - }); -}); - -test.skip('[Find Many] Get only custom fields + where + orderBy', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findMany({ - columns: {}, - with: { - posts: { - columns: {}, - where: gte(postsTable.id, 2), - orderBy: [desc(postsTable.id)], - extras: ({ content }) => ({ - lowerName: sql`lower(${content})`.as('content_lower'), - }), - }, - }, - where: eq(usersTable.id, 1), - extras: ({ name }) => ({ - lowerName: sql`lower(${name})`.as('name_lower'), - }), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - lowerName: string; - posts: { - lowerName: string; - }[]; - }[]>(); - - expect(usersWithPosts.length).toEqual(1); - expect(usersWithPosts[0]?.posts.length).toEqual(2); - - expect(usersWithPosts).toContainEqual({ - lowerName: 'dan', - posts: [{ lowerName: 'post1.3' }, { lowerName: 'post1.2' }], - }); -}); - -// select only custom find one (Order Agnostic) -test('[Find One] Get only custom fields (Order Agnostic)', async () => { - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - // Query to find the first user without any specific order - const usersWithPosts = await db.query.usersTable.findFirst({ - columns: {}, - with: { - posts: { - columns: {}, - extras: ({ content }) => ({ - lowerName: sql`lower(${content})`.as('content_lower'), - }), - }, - }, - extras: ({ name }) => ({ - lowerName: sql`lower(${name})`.as('name_lower'), - }), - }); - - // Type Assertion - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - lowerName: string; - posts: { - lowerName: string; - }[]; - } | undefined - >(); - - // General Assertions - expect(usersWithPosts).toBeDefined(); - - // Since findFirst without orderBy can return any user, we'll verify the returned user and their posts - if (usersWithPosts) { - // Define expected users and their corresponding posts - const expectedUsers: { [key: string]: string[] } = { - dan: ['post1', 'post1.2', 'post1.3'], - andrew: ['post2', 'post2.1'], - alex: ['post3', 'post3.1'], - }; - - // Verify that the returned user is one of the expected users - expect(Object.keys(expectedUsers)).toContain(usersWithPosts.lowerName); - - // Get the expected posts for the returned user - const expectedPosts = expectedUsers[usersWithPosts.lowerName] as string[]; - - // Verify the number of posts - expect(usersWithPosts.posts).toHaveLength(expectedPosts.length); - - // Extract the lowerName of each post - const actualPostLowerNames = usersWithPosts.posts.map((post) => post.lowerName); - - // Assert that all expected posts are present, regardless of order - for (const expectedPost of expectedPosts) { - expect(actualPostLowerNames).toContain(expectedPost.toLowerCase()); - } - } -}); - -// select only custom find one with where clause (Order Agnostic) -test('[Find One] Get only custom fields + where (Order Agnostic)', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - // Query to find the first user with id = 1 and posts with id >= 2 - const usersWithPosts = await db.query.usersTable.findFirst({ - columns: {}, - with: { - posts: { - columns: {}, - where: gte(postsTable.id, 2), - extras: ({ content }) => ({ - lowerName: sql`lower(${content})`.as('content_lower'), - }), - }, - }, - where: eq(usersTable.id, 1), - extras: ({ name }) => ({ - lowerName: sql`lower(${name})`.as('name_lower'), - }), - }); - - // Type Assertion - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - lowerName: string; - posts: { - lowerName: string; - }[]; - } | undefined - >(); - - // General Assertions - expect(usersWithPosts).toBeDefined(); - - if (usersWithPosts) { - // Assert that the returned user has the expected lowerName - expect(usersWithPosts.lowerName).toBe('dan'); - - // Assert that the user has exactly two posts - expect(usersWithPosts.posts).toHaveLength(2); - - // Define the expected posts - const expectedPosts = ['post1.2', 'post1.3']; - - // Extract the lowerName of each post - const actualPostLowerNames = usersWithPosts.posts.map((post) => post.lowerName); - - // Assert that all expected posts are present, regardless of order - for (const expectedPost of expectedPosts) { - expect(actualPostLowerNames).toContain(expectedPost.toLowerCase()); - } - - // Additionally, ensure no unexpected posts are present - expect(actualPostLowerNames).toHaveLength(expectedPosts.length); - } -}); - -test.skip('[Find One] Get only custom fields + where + limit', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - columns: {}, - with: { - posts: { - columns: {}, - where: gte(postsTable.id, 2), - limit: 1, - extras: ({ content }) => ({ - lowerName: sql`lower(${content})`.as('content_lower'), - }), - }, - }, - where: eq(usersTable.id, 1), - extras: ({ name }) => ({ - lowerName: sql`lower(${name})`.as('name_lower'), - }), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - lowerName: string; - posts: { - lowerName: string; - }[]; - } | undefined - >(); - - expect(usersWithPosts?.posts.length).toEqual(1); - - expect(usersWithPosts).toEqual({ - lowerName: 'dan', - posts: [{ lowerName: 'post1.2' }], - }); -}); - -test.skip('[Find One] Get only custom fields + where + orderBy', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - columns: {}, - with: { - posts: { - columns: {}, - where: gte(postsTable.id, 2), - orderBy: [desc(postsTable.id)], - extras: ({ content }) => ({ - lowerName: sql`lower(${content})`.as('content_lower'), - }), - }, - }, - where: eq(usersTable.id, 1), - extras: ({ name }) => ({ - lowerName: sql`lower(${name})`.as('name_lower'), - }), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - lowerName: string; - posts: { - lowerName: string; - }[]; - } | undefined - >(); - - expect(usersWithPosts?.posts.length).toEqual(2); - - expect(usersWithPosts).toEqual({ - lowerName: 'dan', - posts: [{ lowerName: 'post1.3' }, { lowerName: 'post1.2' }], - }); -}); - -// columns {} -test('[Find Many] Get select {}', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await expect( - async () => - await db.query.usersTable.findMany({ - columns: {}, - }), - ).rejects.toThrow(DrizzleError); -}); - -// columns {} -test('[Find One] Get select {}', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await expect(async () => - await db.query.usersTable.findFirst({ - columns: {}, - }) - ).rejects.toThrow(DrizzleError); -}); - -// deep select {} -test('[Find Many] Get deep select {}', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - await expect(async () => - await db.query.usersTable.findMany({ - columns: {}, - with: { - posts: { - columns: {}, - }, - }, - }) - ).rejects.toThrow(DrizzleError); -}); - -// deep select {} -test('[Find One] Get deep select {}', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - await expect(async () => - await db.query.usersTable.findFirst({ - columns: {}, - with: { - posts: { - columns: {}, - }, - }, - }) - ).rejects.toThrow(DrizzleError); -}); - -/* - Prepared statements for users+posts -*/ -test.skip('[Find Many] Get users with posts + prepared limit', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const prepared = db.query.usersTable.findMany({ - with: { - posts: { - limit: placeholder('limit'), - }, - }, - }).prepare(); - - const usersWithPosts = await prepared.execute({ limit: 1 }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(3); - expect(usersWithPosts[0]?.posts.length).eq(1); - expect(usersWithPosts[1]?.posts.length).eq(1); - expect(usersWithPosts[2]?.posts.length).eq(1); - - expect(usersWithPosts).toContainEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); - expect(usersWithPosts).toContainEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], - }); - expect(usersWithPosts).toContainEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], - }); -}); - -test.skip('[Find Many] Get users with posts + prepared limit + offset', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const prepared = db.query.usersTable.findMany({ - limit: placeholder('uLimit'), - offset: placeholder('uOffset'), - with: { - posts: { - limit: placeholder('pLimit'), - }, - }, - }).prepare(); - - const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1 }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(2); - expect(usersWithPosts[0]?.posts.length).eq(1); - expect(usersWithPosts[1]?.posts.length).eq(1); - - expect(usersWithPosts).toContainEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); - expect(usersWithPosts).toContainEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], - }); -}); - -test('[Find Many] Get users with posts + prepared where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const prepared = db.query.usersTable.findMany({ - where: (({ id }, { eq }) => eq(id, placeholder('id'))), - with: { - posts: { - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - }).prepare(); - - const usersWithPosts = await prepared.execute({ id: 1 }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(1); - expect(usersWithPosts[0]?.posts.length).eq(1); - - expect(usersWithPosts[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); -}); - -test.skip('[Find Many] Get users with posts + prepared + limit + offset + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const prepared = db.query.usersTable.findMany({ - limit: placeholder('uLimit'), - offset: placeholder('uOffset'), - where: (({ id }, { eq, or }) => or(eq(id, placeholder('id')), eq(id, 3))), - with: { - posts: { - where: (({ id }, { eq }) => eq(id, placeholder('pid'))), - limit: placeholder('pLimit'), - }, - }, - }).prepare(); - - const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 }); - - expectTypeOf(usersWithPosts).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - }[]>(); - - expect(usersWithPosts.length).eq(1); - expect(usersWithPosts[0]?.posts.length).eq(1); - - expect(usersWithPosts).toContainEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], - }); -}); - -/* - [Find One] One relation users+posts -*/ - -test('[Find One] Get users with posts', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - with: { - posts: true, - }, - }); - - // Type Assertion - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - } | undefined - >(); - - // General Assertions - expect(usersWithPosts).toBeDefined(); - - if (usersWithPosts) { - const { id, name, posts } = usersWithPosts; - - // Verify that the user is one of the inserted users - const validUsers: { [key: number]: string } = { - 1: 'dan', - 2: 'andrew', - 3: 'alex', - }; - expect(validUsers[id]).toBe(name.toLowerCase()); - - // Assert that the user has exactly one post - expect(posts).toHaveLength(1); - - const post = posts[0]; - - // Verify that the post belongs to the user - expect(post?.ownerId).toBe(id); - - // Verify that the post content matches the user - const expectedPostContent = `Post${id}`; - expect(post?.content.toLowerCase()).toBe(expectedPostContent.toLowerCase()); - - // Optionally, verify the presence of `createdAt` - expect(post?.createdAt).toBeInstanceOf(Date); - } -}); - -test.skip('[Find One] Get users with posts + limit posts', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - with: { - posts: { - limit: 1, - }, - }, - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - } | undefined - >(); - - expect(usersWithPosts!.posts.length).eq(1); - - expect(usersWithPosts).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], - }); -}); - -test.skip('[Find One] Get users with posts no results found', async (t) => { - const { singlestoreDb: db } = t; - - const usersWithPosts = await db.query.usersTable.findFirst({ - with: { - posts: { - limit: 1, - }, - }, - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - } | undefined - >(); - - expect(usersWithPosts).toBeUndefined(); -}); - -test.skip('[Find One] Get users with posts + limit posts and users', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - with: { - posts: { - limit: 1, - }, - }, - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - } | undefined - >(); - - expect(usersWithPosts!.posts.length).eq(1); - - expect(usersWithPosts).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], - }); -}); - -test('[Find One] Get users with posts + custom fields', async () => { - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - with: { - posts: true, - }, - extras: ({ name }) => ({ - lowerName: sql`lower(${name})`.as('name_lower'), - }), - }); - - // Type Assertion - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - lowerName: string; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - } | undefined - >(); - - // General Assertions - expect(usersWithPosts).toBeDefined(); - - if (usersWithPosts) { - const { id, lowerName, posts } = usersWithPosts; - - // Define valid users and their expected lower names - const validUsers: { [key: number]: string } = { - 1: 'dan', - 2: 'andrew', - 3: 'alex', - }; - - // Verify that the returned user's lowerName matches the expected value - expect(validUsers[id]).toBe(lowerName); - - // Define the expected posts based on the user ID - const expectedPostsByUser: Record = { - 1: ['post1', 'post1.2', 'post1.3'], - 2: ['post2', 'post2.1'], - 3: ['post3', 'post3.1'], - }; - - // Get the expected posts for the returned user - const expectedPosts = expectedPostsByUser[id] || []; - - // Extract the lowerName of each post - const actualPostContents = posts.map((post) => post.content.toLowerCase()); - - // Assert that all expected posts are present, regardless of order - for (const expectedPost of expectedPosts) { - expect(actualPostContents).toContain(expectedPost.toLowerCase()); - } - - // Optionally, ensure that no unexpected posts are present - expect(actualPostContents).toHaveLength(expectedPosts.length); - } -}); - -test.skip('[Find One] Get users with posts + custom fields + limits', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.2' }, - { ownerId: 1, content: 'Post1.3' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - with: { - posts: { - limit: 1, - }, - }, - extras: (usersTable, { sql }) => ({ - lowerName: sql`lower(${usersTable.name})`.as('name_lower'), - }), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - lowerName: string; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - } | undefined - >(); - - expect(usersWithPosts!.posts.length).toEqual(1); - - expect(usersWithPosts).toEqual({ - id: 1, - name: 'Dan', - lowerName: 'dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], - }); -}); - -test.skip('[Find One] Get users with posts + orderBy', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: '1' }, - { ownerId: 1, content: '2' }, - { ownerId: 1, content: '3' }, - { ownerId: 2, content: '4' }, - { ownerId: 2, content: '5' }, - { ownerId: 3, content: '6' }, - { ownerId: 3, content: '7' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - with: { - posts: { - orderBy: (postsTable, { desc }) => [desc(postsTable.content)], - }, - }, - orderBy: (usersTable, { desc }) => [desc(usersTable.id)], - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - } | undefined - >(); - - expect(usersWithPosts!.posts.length).eq(2); - - expect(usersWithPosts).toEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - posts: [{ - id: 7, - ownerId: 3, - content: '7', - createdAt: usersWithPosts?.posts[1]?.createdAt, - }, { id: 6, ownerId: 3, content: '6', createdAt: usersWithPosts?.posts[0]?.createdAt }], - }); -}); - -test('[Find One] Get users with posts + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - where: (({ id }, { eq }) => eq(id, 1)), - with: { - posts: { - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - }[]; - } | undefined - >(); - - expect(usersWithPosts!.posts.length).eq(1); - - expect(usersWithPosts).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], - }); -}); - -test('[Find One] Get users with posts + where + partial', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - columns: { - id: true, - name: true, - }, - with: { - posts: { - columns: { - id: true, - content: true, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - name: string; - posts: { - id: number; - content: string; - }[]; - } | undefined - >(); - - expect(usersWithPosts!.posts.length).eq(1); - - expect(usersWithPosts).toEqual({ - id: 1, - name: 'Dan', - posts: [{ id: 1, content: 'Post1' }], - }); -}); - -test('[Find One] Get users with posts + where + partial. Did not select posts id, but used it in where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - columns: { - id: true, - name: true, - }, - with: { - posts: { - columns: { - id: true, - content: true, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - name: string; - posts: { - id: number; - content: string; - }[]; - } | undefined - >(); - - expect(usersWithPosts!.posts.length).eq(1); - - expect(usersWithPosts).toEqual({ - id: 1, - name: 'Dan', - posts: [{ id: 1, content: 'Post1' }], - }); -}); - -test('[Find One] Get users with posts + where + partial(true + false)', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - columns: { - id: true, - name: false, - }, - with: { - posts: { - columns: { - id: true, - content: false, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - posts: { - id: number; - }[]; - } | undefined - >(); - - expect(usersWithPosts!.posts.length).eq(1); - - expect(usersWithPosts).toEqual({ - id: 1, - posts: [{ id: 1 }], - }); -}); - -test('[Find One] Get users with posts + where + partial(false)', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const usersWithPosts = await db.query.usersTable.findFirst({ - columns: { - name: false, - }, - with: { - posts: { - columns: { - content: false, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }, - }, - where: (({ id }, { eq }) => eq(id, 1)), - }); - - expectTypeOf(usersWithPosts).toEqualTypeOf< - { - id: number; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - ownerId: number | null; - createdAt: Date; - }[]; - } | undefined - >(); - - expect(usersWithPosts!.posts.length).eq(1); - - expect(usersWithPosts).toEqual({ - id: 1, - verified: false, - invitedBy: null, - posts: [{ id: 1, ownerId: 1, createdAt: usersWithPosts?.posts[0]?.createdAt }], - }); -}); - -/* - One relation users+users. Self referencing -*/ - -test.skip('Get user with invitee', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - const usersWithInvitee = await db.query.usersTable.findMany({ - with: { - invitee: true, - }, - }); - - expectTypeOf(usersWithInvitee).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - invitee: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(usersWithInvitee.length).eq(4); - expect(usersWithInvitee[0]?.invitee).toBeNull(); - expect(usersWithInvitee[1]?.invitee).toBeNull(); - expect(usersWithInvitee[2]?.invitee).not.toBeNull(); - expect(usersWithInvitee[3]?.invitee).not.toBeNull(); - - expect(usersWithInvitee[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - invitee: null, - }); - expect(usersWithInvitee[1]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - invitee: null, - }); - expect(usersWithInvitee[2]).toEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, - }); - expect(usersWithInvitee[3]).toEqual({ - id: 4, - name: 'John', - verified: false, - invitedBy: 2, - invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, - }); -}); - -test.skip('Get user + limit with invitee', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew', invitedBy: 1 }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - const usersWithInvitee = await db.query.usersTable.findMany({ - with: { - invitee: true, - }, - limit: 2, - }); - - expectTypeOf(usersWithInvitee).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - invitee: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(usersWithInvitee.length).eq(2); - expect(usersWithInvitee[0]?.invitee).toBeNull(); - expect(usersWithInvitee[1]?.invitee).not.toBeNull(); - - expect(usersWithInvitee[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - invitee: null, - }); - expect(usersWithInvitee[1]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, - }); -}); - -test.skip('Get user with invitee and custom fields', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - const usersWithInvitee = await db.query.usersTable.findMany({ - extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), - with: { - invitee: { - extras: (invitee, { sql }) => ({ lower: sql`lower(${invitee.name})`.as('lower_name') }), - }, - }, - }); - - expectTypeOf(usersWithInvitee).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - lower: string; - invitedBy: number | null; - invitee: { - id: number; - name: string; - verified: boolean; - lower: string; - invitedBy: number | null; - } | null; - }[] - >(); - - usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(usersWithInvitee.length).eq(4); - expect(usersWithInvitee[0]?.invitee).toBeNull(); - expect(usersWithInvitee[1]?.invitee).toBeNull(); - expect(usersWithInvitee[2]?.invitee).not.toBeNull(); - expect(usersWithInvitee[3]?.invitee).not.toBeNull(); - - expect(usersWithInvitee[0]).toEqual({ - id: 1, - name: 'Dan', - lower: 'dan', - verified: false, - invitedBy: null, - invitee: null, - }); - expect(usersWithInvitee[1]).toEqual({ - id: 2, - name: 'Andrew', - lower: 'andrew', - verified: false, - invitedBy: null, - invitee: null, - }); - expect(usersWithInvitee[2]).toEqual({ - id: 3, - name: 'Alex', - lower: 'alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, - }); - expect(usersWithInvitee[3]).toEqual({ - id: 4, - name: 'John', - lower: 'john', - verified: false, - invitedBy: 2, - invitee: { id: 2, name: 'Andrew', lower: 'andrew', verified: false, invitedBy: null }, - }); -}); - -test.skip('Get user with invitee and custom fields + limits', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - const usersWithInvitee = await db.query.usersTable.findMany({ - extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), - limit: 3, - with: { - invitee: { - extras: (invitee, { sql }) => ({ lower: sql`lower(${invitee.name})`.as('lower_name') }), - }, - }, - }); - - expectTypeOf(usersWithInvitee).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - lower: string; - invitedBy: number | null; - invitee: { - id: number; - name: string; - verified: boolean; - lower: string; - invitedBy: number | null; - } | null; - }[] - >(); - - usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(usersWithInvitee.length).eq(3); - expect(usersWithInvitee[0]?.invitee).toBeNull(); - expect(usersWithInvitee[1]?.invitee).toBeNull(); - expect(usersWithInvitee[2]?.invitee).not.toBeNull(); - - expect(usersWithInvitee[0]).toEqual({ - id: 1, - name: 'Dan', - lower: 'dan', - verified: false, - invitedBy: null, - invitee: null, - }); - expect(usersWithInvitee[1]).toEqual({ - id: 2, - name: 'Andrew', - lower: 'andrew', - verified: false, - invitedBy: null, - invitee: null, - }); - expect(usersWithInvitee[2]).toEqual({ - id: 3, - name: 'Alex', - lower: 'alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, - }); -}); - -test.skip('Get user with invitee + order by', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - const usersWithInvitee = await db.query.usersTable.findMany({ - orderBy: (users, { desc }) => [desc(users.id)], - with: { - invitee: true, - }, - }); - - expectTypeOf(usersWithInvitee).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - invitee: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - expect(usersWithInvitee.length).eq(4); - expect(usersWithInvitee[3]?.invitee).toBeNull(); - expect(usersWithInvitee[2]?.invitee).toBeNull(); - expect(usersWithInvitee[1]?.invitee).not.toBeNull(); - expect(usersWithInvitee[0]?.invitee).not.toBeNull(); - - expect(usersWithInvitee[3]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - invitee: null, - }); - expect(usersWithInvitee[2]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - invitee: null, - }); - expect(usersWithInvitee[1]).toEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, - }); - expect(usersWithInvitee[0]).toEqual({ - id: 4, - name: 'John', - verified: false, - invitedBy: 2, - invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, - }); -}); - -test.skip('Get user with invitee + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - const usersWithInvitee = await db.query.usersTable.findMany({ - where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), - with: { - invitee: true, - }, - }); - - expectTypeOf(usersWithInvitee).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - invitee: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - expect(usersWithInvitee.length).eq(2); - expect(usersWithInvitee[0]?.invitee).not.toBeNull(); - expect(usersWithInvitee[1]?.invitee).not.toBeNull(); - - expect(usersWithInvitee).toContainEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, - }); - expect(usersWithInvitee).toContainEqual({ - id: 4, - name: 'John', - verified: false, - invitedBy: 2, - invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, - }); -}); - -test.skip('Get user with invitee + where + partial', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - const usersWithInvitee = await db.query.usersTable.findMany({ - where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), - columns: { - id: true, - name: true, - }, - with: { - invitee: { - columns: { - id: true, - name: true, - }, - }, - }, - }); - - expectTypeOf(usersWithInvitee).toEqualTypeOf< - { - id: number; - name: string; - invitee: { - id: number; - name: string; - } | null; - }[] - >(); - - expect(usersWithInvitee.length).eq(2); - expect(usersWithInvitee[0]?.invitee).not.toBeNull(); - expect(usersWithInvitee[1]?.invitee).not.toBeNull(); - - expect(usersWithInvitee).toContainEqual({ - id: 3, - name: 'Alex', - invitee: { id: 1, name: 'Dan' }, - }); - expect(usersWithInvitee).toContainEqual({ - id: 4, - name: 'John', - invitee: { id: 2, name: 'Andrew' }, - }); -}); - -test.skip('Get user with invitee + where + partial. Did not select users id, but used it in where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - const usersWithInvitee = await db.query.usersTable.findMany({ - where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), - columns: { - name: true, - }, - with: { - invitee: { - columns: { - id: true, - name: true, - }, - }, - }, - }); - - expectTypeOf(usersWithInvitee).toEqualTypeOf< - { - name: string; - invitee: { - id: number; - name: string; - } | null; - }[] - >(); - - expect(usersWithInvitee.length).eq(2); - expect(usersWithInvitee[0]?.invitee).not.toBeNull(); - expect(usersWithInvitee[1]?.invitee).not.toBeNull(); - - expect(usersWithInvitee).toContainEqual({ - name: 'Alex', - invitee: { id: 1, name: 'Dan' }, - }); - expect(usersWithInvitee).toContainEqual({ - name: 'John', - invitee: { id: 2, name: 'Andrew' }, - }); -}); - -test.skip('Get user with invitee + where + partial(true+false)', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - const usersWithInvitee = await db.query.usersTable.findMany({ - where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), - columns: { - id: true, - name: true, - verified: false, - }, - with: { - invitee: { - columns: { - id: true, - name: true, - verified: false, - }, - }, - }, - }); - - expectTypeOf(usersWithInvitee).toEqualTypeOf< - { - id: number; - name: string; - invitee: { - id: number; - name: string; - } | null; - }[] - >(); - - expect(usersWithInvitee.length).eq(2); - expect(usersWithInvitee[0]?.invitee).not.toBeNull(); - expect(usersWithInvitee[1]?.invitee).not.toBeNull(); - - expect(usersWithInvitee).toContainEqual({ - id: 3, - name: 'Alex', - invitee: { id: 1, name: 'Dan' }, - }); - expect(usersWithInvitee).toContainEqual({ - id: 4, - name: 'John', - invitee: { id: 2, name: 'Andrew' }, - }); -}); - -test.skip('Get user with invitee + where + partial(false)', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - const usersWithInvitee = await db.query.usersTable.findMany({ - where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), - columns: { - verified: false, - }, - with: { - invitee: { - columns: { - name: false, - }, - }, - }, - }); - - expectTypeOf(usersWithInvitee).toEqualTypeOf< - { - id: number; - name: string; - invitedBy: number | null; - invitee: { - id: number; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - expect(usersWithInvitee.length).eq(2); - expect(usersWithInvitee[0]?.invitee).not.toBeNull(); - expect(usersWithInvitee[1]?.invitee).not.toBeNull(); - - expect(usersWithInvitee).toContainEqual({ - id: 3, - name: 'Alex', - invitedBy: 1, - invitee: { id: 1, verified: false, invitedBy: null }, - }); - expect(usersWithInvitee).toContainEqual({ - id: 4, - name: 'John', - invitedBy: 2, - invitee: { id: 2, verified: false, invitedBy: null }, - }); -}); - -/* - Two first-level relations users+users and users+posts -*/ - -test.skip('Get user with invitee and posts', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const response = await db.query.usersTable.findMany({ - with: { - invitee: true, - posts: true, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; - invitee: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).eq(4); - - expect(response[0]?.invitee).toBeNull(); - expect(response[1]?.invitee).toBeNull(); - expect(response[2]?.invitee).not.toBeNull(); - expect(response[3]?.invitee).not.toBeNull(); - - expect(response[0]?.posts.length).eq(1); - expect(response[1]?.posts.length).eq(1); - expect(response[2]?.posts.length).eq(1); - - expect(response).toContainEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - invitee: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: response[0]?.posts[0]?.createdAt }], - }); - expect(response).toContainEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - invitee: null, - posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: response[1]?.posts[0]?.createdAt }], - }); - expect(response).toContainEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, - posts: [{ id: 3, ownerId: 3, content: 'Post3', createdAt: response[2]?.posts[0]?.createdAt }], - }); - expect(response).toContainEqual({ - id: 4, - name: 'John', - verified: false, - invitedBy: 2, - invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, - posts: [], - }); -}); - -test.skip('Get user with invitee and posts + limit posts and users', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const response = await db.query.usersTable.findMany({ - limit: 3, - with: { - invitee: true, - posts: { - limit: 1, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; - invitee: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).eq(3); - - expect(response[0]?.invitee).toBeNull(); - expect(response[1]?.invitee).toBeNull(); - expect(response[2]?.invitee).not.toBeNull(); - - expect(response[0]?.posts.length).eq(1); - expect(response[1]?.posts.length).eq(1); - expect(response[2]?.posts.length).eq(1); - - expect(response).toContainEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - invitee: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: response[0]?.posts[0]?.createdAt }], - }); - expect(response).toContainEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - invitee: null, - posts: [{ id: 3, ownerId: 2, content: 'Post2', createdAt: response[1]?.posts[0]?.createdAt }], - }); - expect(response).toContainEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, - posts: [{ id: 5, ownerId: 3, content: 'Post3', createdAt: response[2]?.posts[0]?.createdAt }], - }); -}); - -test.skip('Get user with invitee and posts + limits + custom fields in each', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const response = await db.query.usersTable.findMany({ - limit: 3, - extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), - with: { - invitee: { - extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_invitee_name') }), - }, - posts: { - limit: 1, - extras: (posts, { sql }) => ({ lower: sql`lower(${posts.content})`.as('lower_content') }), - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - lower: string; - invitedBy: number | null; - posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; - invitee: { - id: number; - name: string; - lower: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).eq(3); - - expect(response[0]?.invitee).toBeNull(); - expect(response[1]?.invitee).toBeNull(); - expect(response[2]?.invitee).not.toBeNull(); - - expect(response[0]?.posts.length).eq(1); - expect(response[1]?.posts.length).eq(1); - expect(response[2]?.posts.length).eq(1); - - expect(response).toContainEqual({ - id: 1, - name: 'Dan', - lower: 'dan', - verified: false, - invitedBy: null, - invitee: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', lower: 'post1', createdAt: response[0]?.posts[0]?.createdAt }], - }); - expect(response).toContainEqual({ - id: 2, - name: 'Andrew', - lower: 'andrew', - verified: false, - invitedBy: null, - invitee: null, - posts: [{ id: 3, ownerId: 2, content: 'Post2', lower: 'post2', createdAt: response[1]?.posts[0]?.createdAt }], - }); - expect(response).toContainEqual({ - id: 3, - name: 'Alex', - lower: 'alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, - posts: [{ id: 5, ownerId: 3, content: 'Post3', lower: 'post3', createdAt: response[2]?.posts[0]?.createdAt }], - }); -}); - -test.skip('Get user with invitee and posts + custom fields in each', async () => { - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const response = await db.query.usersTable.findMany({ - extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), - with: { - invitee: { - extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), - }, - posts: { - extras: (posts, { sql }) => ({ lower: sql`lower(${posts.content})`.as('lower_name') }), - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - lower: string; - invitedBy: number | null; - posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; - invitee: { - id: number; - name: string; - lower: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - response[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); - response[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); - response[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).eq(4); - - expect(response[0]?.invitee).toBeNull(); - expect(response[1]?.invitee).toBeNull(); - expect(response[2]?.invitee).not.toBeNull(); - expect(response[3]?.invitee).not.toBeNull(); - - expect(response[0]?.posts.length).eq(2); - expect(response[1]?.posts.length).eq(2); - expect(response[2]?.posts.length).eq(2); - expect(response[3]?.posts.length).eq(0); - - expect(response).toContainEqual({ - id: 1, - name: 'Dan', - lower: 'dan', - verified: false, - invitedBy: null, - invitee: null, - posts: [{ id: 1, ownerId: 1, content: 'Post1', lower: 'post1', createdAt: response[0]?.posts[0]?.createdAt }, { - id: 2, - ownerId: 1, - content: 'Post1.1', - lower: 'post1.1', - createdAt: response[0]?.posts[1]?.createdAt, - }], - }); - expect(response).toContainEqual({ - id: 2, - name: 'Andrew', - lower: 'andrew', - verified: false, - invitedBy: null, - invitee: null, - posts: [{ id: 3, ownerId: 2, content: 'Post2', lower: 'post2', createdAt: response[1]?.posts[0]?.createdAt }, { - id: 4, - ownerId: 2, - content: 'Post2.1', - lower: 'post2.1', - createdAt: response[1]?.posts[1]?.createdAt, - }], - }); - expect(response).toContainEqual({ - id: 3, - name: 'Alex', - lower: 'alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, - posts: [{ id: 5, ownerId: 3, content: 'Post3', lower: 'post3', createdAt: response[2]?.posts[0]?.createdAt }, { - id: 6, - ownerId: 3, - content: 'Post3.1', - lower: 'post3.1', - createdAt: response[2]?.posts[1]?.createdAt, - }], - }); - expect(response).toContainEqual({ - id: 4, - name: 'John', - lower: 'john', - verified: false, - invitedBy: 2, - invitee: { id: 2, name: 'Andrew', lower: 'andrew', verified: false, invitedBy: null }, - posts: [], - }); -}); - -test.skip('Get user with invitee and posts + orderBy', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const response = await db.query.usersTable.findMany({ - orderBy: (users, { desc }) => [desc(users.id)], - with: { - invitee: true, - posts: { - orderBy: (posts, { desc }) => [desc(posts.id)], - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; - invitee: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - expect(response.length).eq(4); - - expect(response[3]?.invitee).toBeNull(); - expect(response[2]?.invitee).toBeNull(); - expect(response[1]?.invitee).not.toBeNull(); - expect(response[0]?.invitee).not.toBeNull(); - - expect(response[0]?.posts.length).eq(0); - expect(response[1]?.posts.length).eq(1); - expect(response[2]?.posts.length).eq(2); - expect(response[3]?.posts.length).eq(2); - - expect(response[3]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - invitee: null, - posts: [{ id: 2, ownerId: 1, content: 'Post1.1', createdAt: response[3]?.posts[0]?.createdAt }, { - id: 1, - ownerId: 1, - content: 'Post1', - createdAt: response[3]?.posts[1]?.createdAt, - }], - }); - expect(response[2]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - invitee: null, - posts: [{ id: 4, ownerId: 2, content: 'Post2.1', createdAt: response[2]?.posts[0]?.createdAt }, { - id: 3, - ownerId: 2, - content: 'Post2', - createdAt: response[2]?.posts[1]?.createdAt, - }], - }); - expect(response[1]).toEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, - posts: [{ - id: 5, - ownerId: 3, - content: 'Post3', - createdAt: response[3]?.posts[1]?.createdAt, - }], - }); - expect(response[0]).toEqual({ - id: 4, - name: 'John', - verified: false, - invitedBy: 2, - invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, - posts: [], - }); -}); - -test.skip('Get user with invitee and posts + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const response = await db.query.usersTable.findMany({ - where: (users, { eq, or }) => (or(eq(users.id, 2), eq(users.id, 3))), - with: { - invitee: true, - posts: { - where: (posts, { eq }) => (eq(posts.ownerId, 2)), - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; - invitee: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).eq(2); - - expect(response[0]?.invitee).toBeNull(); - expect(response[1]?.invitee).not.toBeNull(); - - expect(response[0]?.posts.length).eq(1); - expect(response[1]?.posts.length).eq(0); - - expect(response).toContainEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - invitee: null, - posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: response[0]?.posts[0]?.createdAt }], - }); - expect(response).toContainEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, - posts: [], - }); -}); - -test.skip('Get user with invitee and posts + limit posts and users + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - { ownerId: 3, content: 'Post3.1' }, - ]); - - const response = await db.query.usersTable.findMany({ - where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), - limit: 1, - with: { - invitee: true, - posts: { - where: (posts, { eq }) => (eq(posts.ownerId, 3)), - limit: 1, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; - invitee: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - expect(response.length).eq(1); - - expect(response[0]?.invitee).not.toBeNull(); - expect(response[0]?.posts.length).eq(1); - - expect(response).toContainEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, - posts: [{ id: 5, ownerId: 3, content: 'Post3', createdAt: response[0]?.posts[0]?.createdAt }], - }); -}); - -test.skip('Get user with invitee and posts + orderBy + where + custom', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const response = await db.query.usersTable.findMany({ - orderBy: [desc(usersTable.id)], - where: or(eq(usersTable.id, 3), eq(usersTable.id, 4)), - extras: { - lower: sql`lower(${usersTable.name})`.as('lower_name'), - }, - with: { - invitee: true, - posts: { - where: eq(postsTable.ownerId, 3), - orderBy: [desc(postsTable.id)], - extras: { - lower: sql`lower(${postsTable.content})`.as('lower_name'), - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - lower: string; - posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; - invitee: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[] - >(); - - expect(response.length).eq(2); - - expect(response[1]?.invitee).not.toBeNull(); - expect(response[0]?.invitee).not.toBeNull(); - - expect(response[0]?.posts.length).eq(0); - expect(response[1]?.posts.length).eq(1); - - expect(response[1]).toEqual({ - id: 3, - name: 'Alex', - lower: 'alex', - verified: false, - invitedBy: 1, - invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, - posts: [{ - id: 5, - ownerId: 3, - content: 'Post3', - lower: 'post3', - createdAt: response[1]?.posts[0]?.createdAt, - }], - }); - expect(response[0]).toEqual({ - id: 4, - name: 'John', - lower: 'john', - verified: false, - invitedBy: 2, - invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, - posts: [], - }); -}); - -test.skip('Get user with invitee and posts + orderBy + where + partial + custom', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex', invitedBy: 1 }, - { id: 4, name: 'John', invitedBy: 2 }, - ]); - - await db.insert(postsTable).values([ - { ownerId: 1, content: 'Post1' }, - { ownerId: 1, content: 'Post1.1' }, - { ownerId: 2, content: 'Post2' }, - { ownerId: 2, content: 'Post2.1' }, - { ownerId: 3, content: 'Post3' }, - ]); - - const response = await db.query.usersTable.findMany({ - orderBy: [desc(usersTable.id)], - where: or(eq(usersTable.id, 3), eq(usersTable.id, 4)), - extras: { - lower: sql`lower(${usersTable.name})`.as('lower_name'), - }, - columns: { - id: true, - name: true, - }, - with: { - invitee: { - columns: { - id: true, - name: true, - }, - extras: { - lower: sql`lower(${usersTable.name})`.as('lower_name'), - }, - }, - posts: { - columns: { - id: true, - content: true, - }, - where: eq(postsTable.ownerId, 3), - orderBy: [desc(postsTable.id)], - extras: { - lower: sql`lower(${postsTable.content})`.as('lower_name'), - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - lower: string; - posts: { id: number; lower: string; content: string }[]; - invitee: { - id: number; - name: string; - lower: string; - } | null; - }[] - >(); - - expect(response.length).eq(2); - - expect(response[1]?.invitee).not.toBeNull(); - expect(response[0]?.invitee).not.toBeNull(); - - expect(response[0]?.posts.length).eq(0); - expect(response[1]?.posts.length).eq(1); - - expect(response[1]).toEqual({ - id: 3, - name: 'Alex', - lower: 'alex', - invitee: { id: 1, name: 'Dan', lower: 'dan' }, - posts: [{ - id: 5, - content: 'Post3', - lower: 'post3', - }], - }); - expect(response[0]).toEqual({ - id: 4, - name: 'John', - lower: 'john', - invitee: { id: 2, name: 'Andrew', lower: 'andrew' }, - posts: [], - }); -}); - -/* - One two-level relation users+posts+comments -*/ - -test.skip('Get user with posts and posts with comments', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { id: 1, ownerId: 1, content: 'Post1' }, - { id: 2, ownerId: 2, content: 'Post2' }, - { id: 3, ownerId: 3, content: 'Post3' }, - ]); - - await db.insert(commentsTable).values([ - { postId: 1, content: 'Comment1', creator: 2 }, - { postId: 2, content: 'Comment2', creator: 2 }, - { postId: 3, content: 'Comment3', creator: 3 }, - ]); - - const response = await db.query.usersTable.findMany({ - with: { - posts: { - with: { - comments: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - comments: { - id: number; - content: string; - createdAt: Date; - creator: number | null; - postId: number | null; - }[]; - }[]; - }[] - >(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).eq(3); - expect(response[0]?.posts.length).eq(1); - expect(response[1]?.posts.length).eq(1); - expect(response[2]?.posts.length).eq(1); - - expect(response[0]?.posts[0]?.comments.length).eq(1); - expect(response[1]?.posts[0]?.comments.length).eq(1); - expect(response[2]?.posts[0]?.comments.length).eq(1); - - expect(response[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ - id: 1, - ownerId: 1, - content: 'Post1', - createdAt: response[0]?.posts[0]?.createdAt, - comments: [ - { - id: 1, - content: 'Comment1', - creator: 2, - postId: 1, - createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, - }, - ], - }], - }); - expect(response[1]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - posts: [{ - id: 2, - ownerId: 2, - content: 'Post2', - createdAt: response[1]?.posts[0]?.createdAt, - comments: [ - { - id: 2, - content: 'Comment2', - creator: 2, - postId: 2, - createdAt: response[1]?.posts[0]?.comments[0]?.createdAt, - }, - ], - }], - }); - // expect(response[2]).toEqual({ - // id: 3, - // name: 'Alex', - // verified: false, - // invitedBy: null, - // posts: [{ - // id: 3, - // ownerId: 3, - // content: 'Post3', - // createdAt: response[2]?.posts[0]?.createdAt, - // comments: [ - // { - // id: , - // content: 'Comment3', - // creator: 3, - // postId: 3, - // createdAt: response[2]?.posts[0]?.comments[0]?.createdAt, - // }, - // ], - // }], - // }); -}); - -// Get user with limit posts and limit comments - -// Get user with custom field + post + comment with custom field - -// Get user with limit + posts orderBy + comment orderBy - -// Get user with where + posts where + comment where - -// Get user with where + posts partial where + comment where - -// Get user with where + posts partial where + comment partial(false) where - -// Get user with where partial(false) + posts partial where partial(false) + comment partial(false+true) where - -// Get user with where + posts partial where + comment where. Didn't select field from where in posts - -// Get user with where + posts partial where + comment where. Didn't select field from where for all - -// Get with limit+offset in each - -/* - One two-level + One first-level relation users+posts+comments and users+users -*/ - -/* - One three-level relation users+posts+comments+comment_owner -*/ - -test.skip('Get user with posts and posts with comments and comments with owner', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { id: 1, ownerId: 1, content: 'Post1' }, - { id: 2, ownerId: 2, content: 'Post2' }, - { id: 3, ownerId: 3, content: 'Post3' }, - ]); - - await db.insert(commentsTable).values([ - { postId: 1, content: 'Comment1', creator: 2 }, - { postId: 2, content: 'Comment2', creator: 2 }, - { postId: 3, content: 'Comment3', creator: 3 }, - ]); - - const response = await db.query.usersTable.findMany({ - with: { - posts: { - with: { - comments: { - with: { - author: true, - }, - }, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - comments: { - id: number; - content: string; - createdAt: Date; - creator: number | null; - postId: number | null; - author: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[]; - }[]; - }[]>(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).eq(3); - expect(response[0]?.posts.length).eq(1); - expect(response[1]?.posts.length).eq(1); - expect(response[2]?.posts.length).eq(1); - - expect(response[0]?.posts[0]?.comments.length).eq(1); - expect(response[1]?.posts[0]?.comments.length).eq(1); - expect(response[2]?.posts[0]?.comments.length).eq(1); - - expect(response[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ - id: 1, - ownerId: 1, - content: 'Post1', - createdAt: response[0]?.posts[0]?.createdAt, - comments: [ - { - id: 1, - content: 'Comment1', - creator: 2, - author: { - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - }, - postId: 1, - createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, - }, - ], - }], - }); - expect(response[1]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - posts: [{ - id: 2, - ownerId: 2, - content: 'Post2', - createdAt: response[1]?.posts[0]?.createdAt, - comments: [ - { - id: 2, - content: 'Comment2', - creator: 2, - author: { - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - }, - postId: 2, - createdAt: response[1]?.posts[0]?.comments[0]?.createdAt, - }, - ], - }], - }); -}); - -test.skip('Get user with posts and posts with comments and comments with owner where exists', async () => { - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(postsTable).values([ - { id: 1, ownerId: 1, content: 'Post1' }, - { id: 2, ownerId: 2, content: 'Post2' }, - { id: 3, ownerId: 3, content: 'Post3' }, - ]); - - await db.insert(commentsTable).values([ - { postId: 1, content: 'Comment1', creator: 2 }, - { postId: 2, content: 'Comment2', creator: 2 }, - { postId: 3, content: 'Comment3', creator: 3 }, - ]); - - const response = await db.query.usersTable.findMany({ - with: { - posts: { - with: { - comments: { - with: { - author: true, - }, - }, - }, - }, - }, - where: (table, { exists, eq }) => exists(db.select({ one: sql`1` }).from(usersTable).where(eq(sql`1`, table.id))), - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - posts: { - id: number; - content: string; - ownerId: number | null; - createdAt: Date; - comments: { - id: number; - content: string; - createdAt: Date; - creator: number | null; - postId: number | null; - author: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - } | null; - }[]; - }[]; - }[]>(); - - expect(response.length).eq(1); - expect(response[0]?.posts.length).eq(1); - - expect(response[0]?.posts[0]?.comments.length).eq(1); - - expect(response[0]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - posts: [{ - id: 1, - ownerId: 1, - content: 'Post1', - createdAt: response[0]?.posts[0]?.createdAt, - comments: [ - { - id: 1, - content: 'Comment1', - creator: 2, - author: { - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - }, - postId: 1, - createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, - }, - ], - }], - }); -}); - -/* - One three-level relation + 1 first-level relatioon - 1. users+posts+comments+comment_owner - 2. users+users -*/ - -/* - One four-level relation users+posts+comments+coment_likes -*/ - -/* - [Find Many] Many-to-many cases - - Users+users_to_groups+groups -*/ - -test.skip('[Find Many] Get users with groups', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findMany({ - with: { - usersToGroups: { - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - }[]>(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).toEqual(3); - - expect(response[0]?.usersToGroups.length).toEqual(1); - expect(response[1]?.usersToGroups.length).toEqual(1); - expect(response[2]?.usersToGroups.length).toEqual(2); - - expect(response).toContainEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 1, - name: 'Group1', - description: null, - }, - }], - }); - - expect(response).toContainEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 2, - name: 'Group2', - description: null, - }, - }], - }); - - expect(response).toContainEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 3, - name: 'Group3', - description: null, - }, - }, { - group: { - id: 2, - name: 'Group2', - description: null, - }, - }], - }); -}); - -test.skip('[Find Many] Get groups with users', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findMany({ - with: { - usersToGroups: { - columns: {}, - with: { - user: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - description: string | null; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - }; - }[]; - }[]>(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).toEqual(3); - - expect(response[0]?.usersToGroups.length).toEqual(1); - expect(response[1]?.usersToGroups.length).toEqual(2); - expect(response[2]?.usersToGroups.length).toEqual(1); - - expect(response).toContainEqual({ - id: 1, - name: 'Group1', - description: null, - usersToGroups: [{ - user: { - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - }, - }], - }); - - expect(response).toContainEqual({ - id: 2, - name: 'Group2', - description: null, - usersToGroups: [{ - user: { - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - }, - }, { - user: { - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - }, - }], - }); - - expect(response).toContainEqual({ - id: 3, - name: 'Group3', - description: null, - usersToGroups: [{ - user: { - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - }, - }], - }); -}); - -test.skip('[Find Many] Get users with groups + limit', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 2, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findMany({ - limit: 2, - with: { - usersToGroups: { - limit: 1, - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - }[]>(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).toEqual(2); - - expect(response[0]?.usersToGroups.length).toEqual(1); - expect(response[1]?.usersToGroups.length).toEqual(1); - - expect(response).toContainEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 1, - name: 'Group1', - description: null, - }, - }], - }); - - expect(response).toContainEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 2, - name: 'Group2', - description: null, - }, - }], - }); -}); - -test.skip('[Find Many] Get groups with users + limit', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findMany({ - limit: 2, - with: { - usersToGroups: { - limit: 1, - columns: {}, - with: { - user: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - description: string | null; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - }; - }[]; - }[]>(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).toEqual(2); - - expect(response[0]?.usersToGroups.length).toEqual(1); - expect(response[1]?.usersToGroups.length).toEqual(1); - - expect(response).toContainEqual({ - id: 1, - name: 'Group1', - description: null, - usersToGroups: [{ - user: { - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - }, - }], - }); - - expect(response).toContainEqual({ - id: 2, - name: 'Group2', - description: null, - usersToGroups: [{ - user: { - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - }, - }], - }); -}); - -test.skip('[Find Many] Get users with groups + limit + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 2, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findMany({ - limit: 1, - where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), - with: { - usersToGroups: { - where: eq(usersToGroupsTable.groupId, 1), - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - }[]>(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).toEqual(1); - - expect(response[0]?.usersToGroups.length).toEqual(1); - - expect(response).toContainEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 1, - name: 'Group1', - description: null, - }, - }], - }); -}); - -test.skip('[Find Many] Get groups with users + limit + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findMany({ - limit: 1, - where: gt(groupsTable.id, 1), - with: { - usersToGroups: { - where: eq(usersToGroupsTable.userId, 2), - limit: 1, - columns: {}, - with: { - user: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - description: string | null; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - }; - }[]; - }[]>(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).toEqual(1); - - expect(response[0]?.usersToGroups.length).toEqual(1); - - expect(response).toContainEqual({ - id: 2, - name: 'Group2', - description: null, - usersToGroups: [{ - user: { - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - }, - }], - }); -}); - -test.skip('[Find Many] Get users with groups + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 2, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findMany({ - where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), - with: { - usersToGroups: { - where: eq(usersToGroupsTable.groupId, 2), - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - }[]>(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).toEqual(2); - - expect(response[0]?.usersToGroups.length).toEqual(0); - expect(response[1]?.usersToGroups.length).toEqual(1); - - expect(response).toContainEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - usersToGroups: [], - }); - - expect(response).toContainEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 2, - name: 'Group2', - description: null, - }, - }], - }); -}); - -test.skip('[Find Many] Get groups with users + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findMany({ - where: gt(groupsTable.id, 1), - with: { - usersToGroups: { - where: eq(usersToGroupsTable.userId, 2), - columns: {}, - with: { - user: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - description: string | null; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - }; - }[]; - }[]>(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).toEqual(2); - - expect(response[0]?.usersToGroups.length).toEqual(1); - expect(response[1]?.usersToGroups.length).toEqual(0); - - expect(response).toContainEqual({ - id: 2, - name: 'Group2', - description: null, - usersToGroups: [{ - user: { - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - }, - }], - }); - - expect(response).toContainEqual({ - id: 3, - name: 'Group3', - description: null, - usersToGroups: [], - }); -}); - -test.skip('[Find Many] Get users with groups + orderBy', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findMany({ - orderBy: (users, { desc }) => [desc(users.id)], - with: { - usersToGroups: { - orderBy: [desc(usersToGroupsTable.groupId)], - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - }[]>(); - - expect(response.length).toEqual(3); - - expect(response[0]?.usersToGroups.length).toEqual(2); - expect(response[1]?.usersToGroups.length).toEqual(1); - expect(response[2]?.usersToGroups.length).toEqual(1); - - expect(response[2]).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 1, - name: 'Group1', - description: null, - }, - }], - }); - - expect(response[1]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 2, - name: 'Group2', - description: null, - }, - }], - }); - - expect(response[0]).toEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 3, - name: 'Group3', - description: null, - }, - }, { - group: { - id: 2, - name: 'Group2', - description: null, - }, - }], - }); -}); - -test.skip('[Find Many] Get groups with users + orderBy', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findMany({ - orderBy: [desc(groupsTable.id)], - with: { - usersToGroups: { - orderBy: (utg, { desc }) => [desc(utg.userId)], - columns: {}, - with: { - user: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - description: string | null; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - }; - }[]; - }[]>(); - - expect(response.length).toEqual(3); - - expect(response[0]?.usersToGroups.length).toEqual(1); - expect(response[1]?.usersToGroups.length).toEqual(2); - expect(response[2]?.usersToGroups.length).toEqual(1); - - expect(response[2]).toEqual({ - id: 1, - name: 'Group1', - description: null, - usersToGroups: [{ - user: { - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - }, - }], - }); - - expect(response[1]).toEqual({ - id: 2, - name: 'Group2', - description: null, - usersToGroups: [{ - user: { - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - }, - }, { - user: { - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - }, - }], - }); - - expect(response[0]).toEqual({ - id: 3, - name: 'Group3', - description: null, - usersToGroups: [{ - user: { - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - }, - }], - }); -}); - -test.skip('[Find Many] Get users with groups + orderBy + limit', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findMany({ - orderBy: (users, { desc }) => [desc(users.id)], - limit: 2, - with: { - usersToGroups: { - limit: 1, - orderBy: [desc(usersToGroupsTable.groupId)], - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf<{ - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - }[]>(); - - expect(response.length).toEqual(2); - - expect(response[0]?.usersToGroups.length).toEqual(1); - expect(response[1]?.usersToGroups.length).toEqual(1); - - expect(response[1]).toEqual({ - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 2, - name: 'Group2', - description: null, - }, - }], - }); - - expect(response[0]).toEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 3, - name: 'Group3', - description: null, - }, - }], - }); -}); - -/* - [Find One] Many-to-many cases - - Users+users_to_groups+groups -*/ - -test.skip('[Find One] Get users with groups', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findFirst({ - with: { - usersToGroups: { - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - } | undefined - >(); - - expect(response?.usersToGroups.length).toEqual(1); - - expect(response).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 1, - name: 'Group1', - description: null, - }, - }], - }); -}); - -test.skip('[Find One] Get groups with users', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findFirst({ - with: { - usersToGroups: { - columns: {}, - with: { - user: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - description: string | null; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - }; - }[]; - } | undefined - >(); - - expect(response?.usersToGroups.length).toEqual(1); - - expect(response).toEqual({ - id: 1, - name: 'Group1', - description: null, - usersToGroups: [{ - user: { - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - }, - }], - }); -}); - -test.skip('[Find One] Get users with groups + limit', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 2, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findFirst({ - with: { - usersToGroups: { - limit: 1, - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - } | undefined - >(); - - expect(response?.usersToGroups.length).toEqual(1); - - expect(response).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 1, - name: 'Group1', - description: null, - }, - }], - }); -}); - -test.skip('[Find One] Get groups with users + limit', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findFirst({ - with: { - usersToGroups: { - limit: 1, - columns: {}, - with: { - user: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - description: string | null; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - }; - }[]; - } | undefined - >(); - - expect(response?.usersToGroups.length).toEqual(1); - - expect(response).toEqual({ - id: 1, - name: 'Group1', - description: null, - usersToGroups: [{ - user: { - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - }, - }], - }); -}); - -test.skip('[Find One] Get users with groups + limit + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 2, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findFirst({ - where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), - with: { - usersToGroups: { - where: eq(usersToGroupsTable.groupId, 1), - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - } | undefined - >(); - - expect(response?.usersToGroups.length).toEqual(1); - - expect(response).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 1, - name: 'Group1', - description: null, - }, - }], - }); -}); - -test.skip('[Find One] Get groups with users + limit + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findFirst({ - where: gt(groupsTable.id, 1), - with: { - usersToGroups: { - where: eq(usersToGroupsTable.userId, 2), - limit: 1, - columns: {}, - with: { - user: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - description: string | null; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - }; - }[]; - } | undefined - >(); - - expect(response?.usersToGroups.length).toEqual(1); - - expect(response).toEqual({ - id: 2, - name: 'Group2', - description: null, - usersToGroups: [{ - user: { - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - }, - }], - }); -}); - -test.skip('[Find One] Get users with groups + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 2, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findFirst({ - where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), - with: { - usersToGroups: { - where: eq(usersToGroupsTable.groupId, 2), - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - } | undefined - >(); - - expect(response?.usersToGroups.length).toEqual(0); - - expect(response).toEqual({ - id: 1, - name: 'Dan', - verified: false, - invitedBy: null, - usersToGroups: [], - }); -}); - -test.skip('[Find One] Get groups with users + where', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findFirst({ - where: gt(groupsTable.id, 1), - with: { - usersToGroups: { - where: eq(usersToGroupsTable.userId, 2), - columns: {}, - with: { - user: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - description: string | null; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - }; - }[]; - } | undefined - >(); - - expect(response?.usersToGroups.length).toEqual(1); - - expect(response).toEqual({ - id: 2, - name: 'Group2', - description: null, - usersToGroups: [{ - user: { - id: 2, - name: 'Andrew', - verified: false, - invitedBy: null, - }, - }], - }); -}); - -test.skip('[Find One] Get users with groups + orderBy', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findFirst({ - orderBy: (users, { desc }) => [desc(users.id)], - with: { - usersToGroups: { - orderBy: [desc(usersToGroupsTable.groupId)], - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - } | undefined - >(); - - expect(response?.usersToGroups.length).toEqual(2); - - expect(response).toEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 3, - name: 'Group3', - description: null, - }, - }, { - group: { - id: 2, - name: 'Group2', - description: null, - }, - }], - }); -}); - -test.skip('[Find One] Get groups with users + orderBy', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findFirst({ - orderBy: [desc(groupsTable.id)], - with: { - usersToGroups: { - orderBy: (utg, { desc }) => [desc(utg.userId)], - columns: {}, - with: { - user: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - description: string | null; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - }; - }[]; - } | undefined - >(); - - expect(response?.usersToGroups.length).toEqual(1); - - expect(response).toEqual({ - id: 3, - name: 'Group3', - description: null, - usersToGroups: [{ - user: { - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - }, - }], - }); -}); - -test.skip('[Find One] Get users with groups + orderBy + limit', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findFirst({ - orderBy: (users, { desc }) => [desc(users.id)], - with: { - usersToGroups: { - limit: 1, - orderBy: [desc(usersToGroupsTable.groupId)], - columns: {}, - with: { - group: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - }; - }[]; - } | undefined - >(); - - expect(response?.usersToGroups.length).toEqual(1); - - expect(response).toEqual({ - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 3, - name: 'Group3', - description: null, - }, - }], - }); -}); - -test.skip('Get groups with users + orderBy + limit', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findMany({ - orderBy: [desc(groupsTable.id)], - limit: 2, - with: { - usersToGroups: { - limit: 1, - orderBy: (utg, { desc }) => [desc(utg.userId)], - columns: {}, - with: { - user: true, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - description: string | null; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - }; - }[]; - }[] - >(); - - expect(response.length).toEqual(2); - - expect(response[0]?.usersToGroups.length).toEqual(1); - expect(response[1]?.usersToGroups.length).toEqual(1); - - expect(response[1]).toEqual({ - id: 2, - name: 'Group2', - description: null, - usersToGroups: [{ - user: { - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - }, - }], - }); - - expect(response[0]).toEqual({ - id: 3, - name: 'Group3', - description: null, - usersToGroups: [{ - user: { - id: 3, - name: 'Alex', - verified: false, - invitedBy: null, - }, - }], - }); -}); - -test.skip('Get users with groups + custom', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.usersTable.findMany({ - extras: { - lower: sql`lower(${usersTable.name})`.as('lower_name'), - }, - with: { - usersToGroups: { - columns: {}, - with: { - group: { - extras: { - lower: sql`lower(${groupsTable.name})`.as('lower_name'), - }, - }, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - lower: string; - usersToGroups: { - group: { - id: number; - name: string; - description: string | null; - lower: string; - }; - }[]; - }[] - >(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).toEqual(3); - - expect(response[0]?.usersToGroups.length).toEqual(1); - expect(response[1]?.usersToGroups.length).toEqual(1); - expect(response[2]?.usersToGroups.length).toEqual(2); - - expect(response).toContainEqual({ - id: 1, - name: 'Dan', - lower: 'dan', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 1, - name: 'Group1', - lower: 'group1', - description: null, - }, - }], - }); - - expect(response).toContainEqual({ - id: 2, - name: 'Andrew', - lower: 'andrew', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 2, - name: 'Group2', - lower: 'group2', - description: null, - }, - }], - }); - - expect(response).toContainEqual({ - id: 3, - name: 'Alex', - lower: 'alex', - verified: false, - invitedBy: null, - usersToGroups: [{ - group: { - id: 3, - name: 'Group3', - lower: 'group3', - description: null, - }, - }, { - group: { - id: 2, - name: 'Group2', - lower: 'group2', - description: null, - }, - }], - }); -}); - -test.skip('Get groups with users + custom', async (t) => { - const { singlestoreDb: db } = t; - - await db.insert(usersTable).values([ - { id: 1, name: 'Dan' }, - { id: 2, name: 'Andrew' }, - { id: 3, name: 'Alex' }, - ]); - - await db.insert(groupsTable).values([ - { id: 1, name: 'Group1' }, - { id: 2, name: 'Group2' }, - { id: 3, name: 'Group3' }, - ]); - - await db.insert(usersToGroupsTable).values([ - { userId: 1, groupId: 1 }, - { userId: 2, groupId: 2 }, - { userId: 3, groupId: 3 }, - { userId: 3, groupId: 2 }, - ]); - - const response = await db.query.groupsTable.findMany({ - extras: (table, { sql }) => ({ - lower: sql`lower(${table.name})`.as('lower_name'), - }), - with: { - usersToGroups: { - columns: {}, - with: { - user: { - extras: (table, { sql }) => ({ - lower: sql`lower(${table.name})`.as('lower_name'), - }), - }, - }, - }, - }, - }); - - expectTypeOf(response).toEqualTypeOf< - { - id: number; - name: string; - description: string | null; - lower: string; - usersToGroups: { - user: { - id: number; - name: string; - verified: boolean; - invitedBy: number | null; - lower: string; - }; - }[]; - }[] - >(); - - response.sort((a, b) => (a.id > b.id) ? 1 : -1); - - expect(response.length).toEqual(3); - - expect(response[0]?.usersToGroups.length).toEqual(1); - expect(response[1]?.usersToGroups.length).toEqual(2); - expect(response[2]?.usersToGroups.length).toEqual(1); - - expect(response).toContainEqual({ - id: 1, - name: 'Group1', - lower: 'group1', - description: null, - usersToGroups: [{ - user: { - id: 1, - name: 'Dan', - lower: 'dan', - verified: false, - invitedBy: null, - }, - }], - }); - - expect(response).toContainEqual({ - id: 2, - name: 'Group2', - lower: 'group2', - description: null, - usersToGroups: [{ - user: { - id: 2, - name: 'Andrew', - lower: 'andrew', - verified: false, - invitedBy: null, - }, - }, { - user: { - id: 3, - name: 'Alex', - lower: 'alex', - verified: false, - invitedBy: null, - }, - }], - }); - - expect(response).toContainEqual({ - id: 3, - name: 'Group3', - lower: 'group3', - description: null, - usersToGroups: [{ - user: { - id: 3, - name: 'Alex', - lower: 'alex', - verified: false, - invitedBy: null, - }, - }], - }); -}); - -test('.toSQL()', () => { - const query = db.query.usersTable.findFirst().toSQL(); - - expect(query).toHaveProperty('sql', expect.any(String)); - expect(query).toHaveProperty('params', expect.any(Array)); -}); - -// + custom + where + orderby - -// + custom + where + orderby + limit - -// + partial - -// + partial(false) - -// + partial + orderBy + where (all not selected) - -/* - One four-level relation users+posts+comments+coment_likes - + users+users_to_groups+groups -*/ - -/* - Really hard case - 1. users+posts+comments+coment_likes - 2. users+users_to_groups+groups - 3. users+users -*/ +// import retry from 'async-retry'; +// import Docker from 'dockerode'; +// import 'dotenv/config'; +// import { desc, DrizzleError, eq, gt, gte, or, placeholder, sql, TransactionRollbackError } from 'drizzle-orm'; +// import { drizzle, type SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +// import getPort from 'get-port'; +// import * as mysql from 'mysql2/promise'; +// import { v4 as uuid } from 'uuid'; +// import { afterAll, beforeAll, beforeEach, expect, expectTypeOf, test } from 'vitest'; +// import * as schema from './singlestore.schema.ts'; + +// const { usersTable, postsTable, commentsTable, usersToGroupsTable, groupsTable } = schema; + +// const ENABLE_LOGGING = false; + +// /* +// Test cases: +// - querying nested relation without PK with additional fields +// */ + +// declare module 'vitest' { +// export interface TestContext { +// docker: Docker; +// singlestoreContainer: Docker.Container; +// singlestoreDb: SingleStoreDriverDatabase; +// singlestoreClient: mysql.Connection; +// } +// } + +// let globalDocker: Docker; +// let singlestoreContainer: Docker.Container; +// let db: SingleStoreDriverDatabase; +// let client: mysql.Connection; + +// async function createDockerDB(): Promise { +// const docker = new Docker(); +// const port = await getPort({ port: 3306 }); +// const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + +// const pullStream = await docker.pull(image); +// await new Promise((resolve, reject) => +// docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) +// ); + +// singlestoreContainer = await docker.createContainer({ +// Image: image, +// Env: ['ROOT_PASSWORD=singlestore'], +// name: `drizzle-integration-tests-${uuid()}`, +// HostConfig: { +// AutoRemove: true, +// PortBindings: { +// '3306/tcp': [{ HostPort: `${port}` }], +// }, +// }, +// }); + +// await singlestoreContainer.start(); +// await new Promise((resolve) => setTimeout(resolve, 4000)); + +// return `singlestore://root:singlestore@localhost:${port}/`; +// } + +// beforeAll(async () => { +// const connectionString = process.env['SINGLESTORE_CONNECTION_STRING'] ?? (await createDockerDB()); +// client = await retry(async () => { +// client = await mysql.createConnection(connectionString); +// await client.connect(); +// return client; +// }, { +// retries: 20, +// factor: 1, +// minTimeout: 250, +// maxTimeout: 250, +// randomize: false, +// onRetry() { +// client?.end(); +// }, +// }); + +// await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); +// await client.changeUser({ database: 'drizzle' }); +// db = drizzle(client, { schema, logger: ENABLE_LOGGING }); +// }); + +// afterAll(async () => { +// await client?.end().catch(console.error); +// await singlestoreContainer?.stop().catch(console.error); +// }); + +// beforeEach(async (ctx) => { +// ctx.singlestoreDb = db; +// ctx.singlestoreClient = client; +// ctx.docker = globalDocker; +// ctx.singlestoreContainer = singlestoreContainer; + +// await ctx.singlestoreDb.execute(sql`drop table if exists \`users\``); +// await ctx.singlestoreDb.execute(sql`drop table if exists \`groups\``); +// await ctx.singlestoreDb.execute(sql`drop table if exists \`users_to_groups\``); +// await ctx.singlestoreDb.execute(sql`drop table if exists \`posts\``); +// await ctx.singlestoreDb.execute(sql`drop table if exists \`comments\``); +// await ctx.singlestoreDb.execute(sql`drop table if exists \`comment_likes\``); + +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`users\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`name\` text NOT NULL, +// \`verified\` boolean DEFAULT false NOT NULL, +// \`invited_by\` bigint +// ); +// `, +// ); +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`groups\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`name\` text NOT NULL, +// \`description\` text +// ); +// `, +// ); +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`users_to_groups\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`user_id\` bigint, +// \`group_id\` bigint +// ); +// `, +// ); +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`posts\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`content\` text NOT NULL, +// \`owner_id\` bigint, +// \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL +// ); +// `, +// ); +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`comments\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`content\` text NOT NULL, +// \`creator\` bigint, +// \`post_id\` bigint, +// \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL +// ); +// `, +// ); +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`comment_likes\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`creator\` bigint, +// \`comment_id\` bigint, +// \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL +// ); +// `, +// ); +// }); + +// /* +// [Find Many] One relation users+posts +// */ + +// test('[Find Many] Get users with posts', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// with: { +// posts: true, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithPosts.length).eq(3); +// expect(usersWithPosts[0]?.posts.length).eq(1); +// expect(usersWithPosts[1]?.posts.length).eq(1); +// expect(usersWithPosts[2]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[2]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 3, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + limit posts', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// with: { +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithPosts.length).eq(3); +// expect(usersWithPosts[0]?.posts.length).eq(1); +// expect(usersWithPosts[1]?.posts.length).eq(1); +// expect(usersWithPosts[2]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[2]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + limit posts and users', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// limit: 2, +// with: { +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithPosts.length).eq(2); +// expect(usersWithPosts[0]?.posts.length).eq(1); +// expect(usersWithPosts[1]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts + custom fields', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// with: { +// posts: true, +// }, +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lowerName: string; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithPosts.length).toEqual(3); +// expect(usersWithPosts[0]?.posts.length).toEqual(3); +// expect(usersWithPosts[1]?.posts.length).toEqual(2); +// expect(usersWithPosts[2]?.posts.length).toEqual(2); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// lowerName: 'dan', +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }, { +// id: 2, +// ownerId: 1, +// content: 'Post1.2', +// createdAt: usersWithPosts[0]?.posts[1]?.createdAt, +// }, { id: 3, ownerId: 1, content: 'Post1.3', createdAt: usersWithPosts[0]?.posts[2]?.createdAt }], +// }); +// expect(usersWithPosts[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// lowerName: 'andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }, { +// id: 5, +// ownerId: 2, +// content: 'Post2.1', +// createdAt: usersWithPosts[1]?.posts[1]?.createdAt, +// }], +// }); +// expect(usersWithPosts[2]).toEqual({ +// id: 3, +// name: 'Alex', +// lowerName: 'alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }, { +// id: 7, +// ownerId: 3, +// content: 'Post3.1', +// createdAt: usersWithPosts[2]?.posts[1]?.createdAt, +// }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + custom fields + limits', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// limit: 1, +// with: { +// posts: { +// limit: 1, +// }, +// }, +// extras: (usersTable, { sql }) => ({ +// lowerName: sql`lower(${usersTable.name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lowerName: string; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).toEqual(1); +// expect(usersWithPosts[0]?.posts.length).toEqual(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// lowerName: 'dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: '1' }, +// { ownerId: 1, content: '2' }, +// { ownerId: 1, content: '3' }, +// { ownerId: 2, content: '4' }, +// { ownerId: 2, content: '5' }, +// { ownerId: 3, content: '6' }, +// { ownerId: 3, content: '7' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// with: { +// posts: { +// orderBy: (postsTable, { desc }) => [desc(postsTable.content)], +// }, +// }, +// orderBy: (usersTable, { desc }) => [desc(usersTable.id)], +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(3); +// expect(usersWithPosts[0]?.posts.length).eq(2); +// expect(usersWithPosts[1]?.posts.length).eq(2); +// expect(usersWithPosts[2]?.posts.length).eq(3); + +// expect(usersWithPosts[2]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 3, ownerId: 1, content: '3', createdAt: usersWithPosts[2]?.posts[2]?.createdAt }, { +// id: 2, +// ownerId: 1, +// content: '2', +// createdAt: usersWithPosts[2]?.posts[1]?.createdAt, +// }, { id: 1, ownerId: 1, content: '1', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 5, +// ownerId: 2, +// content: '5', +// createdAt: usersWithPosts[1]?.posts[1]?.createdAt, +// }, { id: 4, ownerId: 2, content: '4', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[0]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 7, +// ownerId: 3, +// content: '7', +// createdAt: usersWithPosts[0]?.posts[1]?.createdAt, +// }, { id: 6, ownerId: 3, content: '6', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// where: (({ id }, { eq }) => eq(id, 1)), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts + where + partial', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: { +// id: true, +// name: true, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: true, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// posts: { +// id: number; +// content: string; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// posts: [{ id: 1, content: 'Post1' }], +// }); +// }); + +// test('[Find Many] Get users with posts + where + partial. Did not select posts id, but used it in where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: { +// id: true, +// name: true, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: true, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// posts: { +// id: number; +// content: string; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// posts: [{ id: 1, content: 'Post1' }], +// }); +// }); + +// test('[Find Many] Get users with posts + where + partial(true + false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: { +// id: true, +// name: false, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: false, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// posts: { +// id: number; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// posts: [{ id: 1 }], +// }); +// }); + +// test('[Find Many] Get users with posts + where + partial(false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: { +// name: false, +// }, +// with: { +// posts: { +// columns: { +// content: false, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts in transaction', async (t) => { +// const { singlestoreDb: db } = t; + +// let usersWithPosts: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[] = []; + +// await db.transaction(async (tx) => { +// await tx.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await tx.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// usersWithPosts = await tx.query.usersTable.findMany({ +// where: (({ id }, { eq }) => eq(id, 1)), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// }); +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts in rollbacked transaction', async (t) => { +// const { singlestoreDb: db } = t; + +// let usersWithPosts: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[] = []; + +// await expect(db.transaction(async (tx) => { +// await tx.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await tx.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// tx.rollback(); + +// usersWithPosts = await tx.query.usersTable.findMany({ +// where: (({ id }, { eq }) => eq(id, 1)), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// }); +// })).rejects.toThrowError(new TransactionRollbackError()); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(0); +// }); + +// // select only custom +// test('[Find Many] Get only custom fields', async () => { +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { id: 1, ownerId: 1, content: 'Post1' }, +// { id: 2, ownerId: 1, content: 'Post1.2' }, +// { id: 3, ownerId: 1, content: 'Post1.3' }, +// { id: 4, ownerId: 2, content: 'Post2' }, +// { id: 5, ownerId: 2, content: 'Post2.1' }, +// { id: 6, ownerId: 3, content: 'Post3' }, +// { id: 7, ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// }[]>(); + +// // General Assertions +// expect(usersWithPosts).toHaveLength(3); + +// // Helper function to find user by lowerName +// const findUser = (lowerName: string) => usersWithPosts.find((user) => user.lowerName === lowerName); + +// // Assertions for each user +// const dan = findUser('dan'); +// const andrew = findUser('andrew'); +// const alex = findUser('alex'); + +// expect(dan).toBeDefined(); +// expect(andrew).toBeDefined(); +// expect(alex).toBeDefined(); + +// // Verify the number of posts for each user +// expect(dan?.posts).toHaveLength(3); +// expect(andrew?.posts).toHaveLength(2); +// expect(alex?.posts).toHaveLength(2); + +// // Define expected posts for each user +// const expectedDanPosts = ['post1', 'post1.2', 'post1.3']; +// const expectedAndrewPosts = ['post2', 'post2.1']; +// const expectedAlexPosts = ['post3', 'post3.1']; + +// // Helper function to extract lowerNames from posts +// const getPostLowerNames = (posts: { lowerName: string }[]) => posts.map((post) => post.lowerName); + +// // Assertions for Dan's posts +// expect(getPostLowerNames(dan!.posts)).toEqual(expect.arrayContaining(expectedDanPosts)); +// expect(getPostLowerNames(dan!.posts)).toHaveLength(expectedDanPosts.length); + +// // Assertions for Andrew's posts +// expect(getPostLowerNames(andrew!.posts)).toEqual(expect.arrayContaining(expectedAndrewPosts)); +// expect(getPostLowerNames(andrew!.posts)).toHaveLength(expectedAndrewPosts.length); + +// // Assertions for Alex's posts +// expect(getPostLowerNames(alex!.posts)).toEqual(expect.arrayContaining(expectedAlexPosts)); +// expect(getPostLowerNames(alex!.posts)).toHaveLength(expectedAlexPosts.length); +// }); + +// // select only custom with where clause (Order Agnostic) +// test('[Find Many] Get only custom fields + where', async (t) => { +// const { singlestoreDb: db } = t; + +// // Insert Users +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// // Insert Posts +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// // Query Users with Posts where users.id = 1 and posts.id >= 2 +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// }[]>(); + +// // General Assertions +// expect(usersWithPosts).toHaveLength(1); + +// // Since we expect only one user, we can extract it directly +// const danWithPosts = usersWithPosts[0]; + +// // Assert that the user exists and has the correct lowerName +// expect(danWithPosts).toBeDefined(); +// expect(danWithPosts?.lowerName).toBe('dan'); + +// // Assert that the user has the expected number of posts +// expect(danWithPosts?.posts).toHaveLength(2); + +// // Define the expected posts +// const expectedPosts = ['post1.2', 'post1.3']; + +// // Extract the lowerName of each post +// const actualPostLowerNames = danWithPosts?.posts.map((post) => post.lowerName); + +// // Assert that all expected posts are present, regardless of order +// for (const expectedPost of expectedPosts) { +// expect(actualPostLowerNames).toContain(expectedPost); +// } + +// // Additionally, ensure no unexpected posts are present +// expect(actualPostLowerNames).toHaveLength(expectedPosts.length); +// }); + +// test.skip('[Find Many] Get only custom fields + where + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// limit: 1, +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).toEqual(1); +// expect(usersWithPosts[0]?.posts.length).toEqual(1); + +// expect(usersWithPosts).toContainEqual({ +// lowerName: 'dan', +// posts: [{ lowerName: 'post1.2' }], +// }); +// }); + +// test.skip('[Find Many] Get only custom fields + where + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// orderBy: [desc(postsTable.id)], +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).toEqual(1); +// expect(usersWithPosts[0]?.posts.length).toEqual(2); + +// expect(usersWithPosts).toContainEqual({ +// lowerName: 'dan', +// posts: [{ lowerName: 'post1.3' }, { lowerName: 'post1.2' }], +// }); +// }); + +// // select only custom find one (Order Agnostic) +// test('[Find One] Get only custom fields (Order Agnostic)', async () => { +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// // Query to find the first user without any specific order +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// } | undefined +// >(); + +// // General Assertions +// expect(usersWithPosts).toBeDefined(); + +// // Since findFirst without orderBy can return any user, we'll verify the returned user and their posts +// if (usersWithPosts) { +// // Define expected users and their corresponding posts +// const expectedUsers: { [key: string]: string[] } = { +// dan: ['post1', 'post1.2', 'post1.3'], +// andrew: ['post2', 'post2.1'], +// alex: ['post3', 'post3.1'], +// }; + +// // Verify that the returned user is one of the expected users +// expect(Object.keys(expectedUsers)).toContain(usersWithPosts.lowerName); + +// // Get the expected posts for the returned user +// const expectedPosts = expectedUsers[usersWithPosts.lowerName] as string[]; + +// // Verify the number of posts +// expect(usersWithPosts.posts).toHaveLength(expectedPosts.length); + +// // Extract the lowerName of each post +// const actualPostLowerNames = usersWithPosts.posts.map((post) => post.lowerName); + +// // Assert that all expected posts are present, regardless of order +// for (const expectedPost of expectedPosts) { +// expect(actualPostLowerNames).toContain(expectedPost.toLowerCase()); +// } +// } +// }); + +// // select only custom find one with where clause (Order Agnostic) +// test('[Find One] Get only custom fields + where (Order Agnostic)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// // Query to find the first user with id = 1 and posts with id >= 2 +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// } | undefined +// >(); + +// // General Assertions +// expect(usersWithPosts).toBeDefined(); + +// if (usersWithPosts) { +// // Assert that the returned user has the expected lowerName +// expect(usersWithPosts.lowerName).toBe('dan'); + +// // Assert that the user has exactly two posts +// expect(usersWithPosts.posts).toHaveLength(2); + +// // Define the expected posts +// const expectedPosts = ['post1.2', 'post1.3']; + +// // Extract the lowerName of each post +// const actualPostLowerNames = usersWithPosts.posts.map((post) => post.lowerName); + +// // Assert that all expected posts are present, regardless of order +// for (const expectedPost of expectedPosts) { +// expect(actualPostLowerNames).toContain(expectedPost.toLowerCase()); +// } + +// // Additionally, ensure no unexpected posts are present +// expect(actualPostLowerNames).toHaveLength(expectedPosts.length); +// } +// }); + +// test.skip('[Find One] Get only custom fields + where + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// limit: 1, +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts?.posts.length).toEqual(1); + +// expect(usersWithPosts).toEqual({ +// lowerName: 'dan', +// posts: [{ lowerName: 'post1.2' }], +// }); +// }); + +// test.skip('[Find One] Get only custom fields + where + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// orderBy: [desc(postsTable.id)], +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts?.posts.length).toEqual(2); + +// expect(usersWithPosts).toEqual({ +// lowerName: 'dan', +// posts: [{ lowerName: 'post1.3' }, { lowerName: 'post1.2' }], +// }); +// }); + +// // columns {} +// test('[Find Many] Get select {}', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await expect( +// async () => +// await db.query.usersTable.findMany({ +// columns: {}, +// }), +// ).rejects.toThrow(DrizzleError); +// }); + +// // columns {} +// test('[Find One] Get select {}', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await expect(async () => +// await db.query.usersTable.findFirst({ +// columns: {}, +// }) +// ).rejects.toThrow(DrizzleError); +// }); + +// // deep select {} +// test('[Find Many] Get deep select {}', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// await expect(async () => +// await db.query.usersTable.findMany({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// }, +// }, +// }) +// ).rejects.toThrow(DrizzleError); +// }); + +// // deep select {} +// test('[Find One] Get deep select {}', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// await expect(async () => +// await db.query.usersTable.findFirst({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// }, +// }, +// }) +// ).rejects.toThrow(DrizzleError); +// }); + +// /* +// Prepared statements for users+posts +// */ +// test.skip('[Find Many] Get users with posts + prepared limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const prepared = db.query.usersTable.findMany({ +// with: { +// posts: { +// limit: placeholder('limit'), +// }, +// }, +// }).prepare(); + +// const usersWithPosts = await prepared.execute({ limit: 1 }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(3); +// expect(usersWithPosts[0]?.posts.length).eq(1); +// expect(usersWithPosts[1]?.posts.length).eq(1); +// expect(usersWithPosts[2]?.posts.length).eq(1); + +// expect(usersWithPosts).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + prepared limit + offset', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const prepared = db.query.usersTable.findMany({ +// limit: placeholder('uLimit'), +// offset: placeholder('uOffset'), +// with: { +// posts: { +// limit: placeholder('pLimit'), +// }, +// }, +// }).prepare(); + +// const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1 }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(2); +// expect(usersWithPosts[0]?.posts.length).eq(1); +// expect(usersWithPosts[1]?.posts.length).eq(1); + +// expect(usersWithPosts).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts + prepared where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const prepared = db.query.usersTable.findMany({ +// where: (({ id }, { eq }) => eq(id, placeholder('id'))), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// }).prepare(); + +// const usersWithPosts = await prepared.execute({ id: 1 }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + prepared + limit + offset + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const prepared = db.query.usersTable.findMany({ +// limit: placeholder('uLimit'), +// offset: placeholder('uOffset'), +// where: (({ id }, { eq, or }) => or(eq(id, placeholder('id')), eq(id, 3))), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, placeholder('pid'))), +// limit: placeholder('pLimit'), +// }, +// }, +// }).prepare(); + +// const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// /* +// [Find One] One relation users+posts +// */ + +// test.only('[Find One] Get users with posts', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: true, +// }, +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// // General Assertions +// expect(usersWithPosts).toBeDefined(); + +// if (usersWithPosts) { +// const { id, name, posts } = usersWithPosts; + +// // Verify that the user is one of the inserted users +// const validUsers: { [key: number]: string } = { +// 1: 'dan', +// 2: 'andrew', +// 3: 'alex', +// }; +// expect(validUsers[id]).toBe(name.toLowerCase()); + +// // Assert that the user has exactly one post +// expect(posts).toHaveLength(1); + +// const post = posts[0]; + +// // Verify that the post belongs to the user +// expect(post?.ownerId).toBe(id); + +// // Verify that the post content matches the user +// const expectedPostContent = `Post${id}`; +// expect(post?.content.toLowerCase()).toBe(expectedPostContent.toLowerCase()); + +// // Optionally, verify the presence of `createdAt` +// expect(post?.createdAt).toBeInstanceOf(Date); +// } +// }); + +// test.skip('[Find One] Get users with posts + limit posts', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find One] Get users with posts no results found', async (t) => { +// const { singlestoreDb: db } = t; + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts).toBeUndefined(); +// }); + +// test.skip('[Find One] Get users with posts + limit posts and users', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find One] Get users with posts + custom fields', async () => { +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: true, +// }, +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lowerName: string; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// // General Assertions +// expect(usersWithPosts).toBeDefined(); + +// if (usersWithPosts) { +// const { id, lowerName, posts } = usersWithPosts; + +// // Define valid users and their expected lower names +// const validUsers: { [key: number]: string } = { +// 1: 'dan', +// 2: 'andrew', +// 3: 'alex', +// }; + +// // Verify that the returned user's lowerName matches the expected value +// expect(validUsers[id]).toBe(lowerName); + +// // Define the expected posts based on the user ID +// const expectedPostsByUser: Record = { +// 1: ['post1', 'post1.2', 'post1.3'], +// 2: ['post2', 'post2.1'], +// 3: ['post3', 'post3.1'], +// }; + +// // Get the expected posts for the returned user +// const expectedPosts = expectedPostsByUser[id] || []; + +// // Extract the lowerName of each post +// const actualPostContents = posts.map((post) => post.content.toLowerCase()); + +// // Assert that all expected posts are present, regardless of order +// for (const expectedPost of expectedPosts) { +// expect(actualPostContents).toContain(expectedPost.toLowerCase()); +// } + +// // Optionally, ensure that no unexpected posts are present +// expect(actualPostContents).toHaveLength(expectedPosts.length); +// } +// }); + +// test.skip('[Find One] Get users with posts + custom fields + limits', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: { +// limit: 1, +// }, +// }, +// extras: (usersTable, { sql }) => ({ +// lowerName: sql`lower(${usersTable.name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lowerName: string; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).toEqual(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// lowerName: 'dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find One] Get users with posts + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: '1' }, +// { ownerId: 1, content: '2' }, +// { ownerId: 1, content: '3' }, +// { ownerId: 2, content: '4' }, +// { ownerId: 2, content: '5' }, +// { ownerId: 3, content: '6' }, +// { ownerId: 3, content: '7' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: { +// orderBy: (postsTable, { desc }) => [desc(postsTable.content)], +// }, +// }, +// orderBy: (usersTable, { desc }) => [desc(usersTable.id)], +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(2); + +// expect(usersWithPosts).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 7, +// ownerId: 3, +// content: '7', +// createdAt: usersWithPosts?.posts[1]?.createdAt, +// }, { id: 6, ownerId: 3, content: '6', createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find One] Get users with posts + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// where: (({ id }, { eq }) => eq(id, 1)), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find One] Get users with posts + where + partial', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: { +// id: true, +// name: true, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: true, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// posts: { +// id: number; +// content: string; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// posts: [{ id: 1, content: 'Post1' }], +// }); +// }); + +// test.skip('[Find One] Get users with posts + where + partial. Did not select posts id, but used it in where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: { +// id: true, +// name: true, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: true, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// posts: { +// id: number; +// content: string; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// posts: [{ id: 1, content: 'Post1' }], +// }); +// }); + +// test.skip('[Find One] Get users with posts + where + partial(true + false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: { +// id: true, +// name: false, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: false, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// posts: { +// id: number; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// posts: [{ id: 1 }], +// }); +// }); + +// test.skip('[Find One] Get users with posts + where + partial(false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: { +// name: false, +// }, +// with: { +// posts: { +// columns: { +// content: false, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// /* +// One relation users+users. Self referencing +// */ + +// test.skip('Get user with invitee', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// with: { +// invitee: true, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithInvitee.length).eq(4); +// expect(usersWithInvitee[0]?.invitee).toBeNull(); +// expect(usersWithInvitee[1]?.invitee).toBeNull(); +// expect(usersWithInvitee[2]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[3]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[2]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// }); +// expect(usersWithInvitee[3]).toEqual({ +// id: 4, +// name: 'John', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user + limit with invitee', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew', invitedBy: 1 }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// with: { +// invitee: true, +// }, +// limit: 2, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user with invitee and custom fields', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), +// with: { +// invitee: { +// extras: (invitee, { sql }) => ({ lower: sql`lower(${invitee.name})`.as('lower_name') }), +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithInvitee.length).eq(4); +// expect(usersWithInvitee[0]?.invitee).toBeNull(); +// expect(usersWithInvitee[1]?.invitee).toBeNull(); +// expect(usersWithInvitee[2]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[3]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee[0]).toEqual({ +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[2]).toEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, +// }); +// expect(usersWithInvitee[3]).toEqual({ +// id: 4, +// name: 'John', +// lower: 'john', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', lower: 'andrew', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user with invitee and custom fields + limits', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), +// limit: 3, +// with: { +// invitee: { +// extras: (invitee, { sql }) => ({ lower: sql`lower(${invitee.name})`.as('lower_name') }), +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithInvitee.length).eq(3); +// expect(usersWithInvitee[0]?.invitee).toBeNull(); +// expect(usersWithInvitee[1]?.invitee).toBeNull(); +// expect(usersWithInvitee[2]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee[0]).toEqual({ +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[2]).toEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user with invitee + order by', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// orderBy: (users, { desc }) => [desc(users.id)], +// with: { +// invitee: true, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(4); +// expect(usersWithInvitee[3]?.invitee).toBeNull(); +// expect(usersWithInvitee[2]?.invitee).toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee[3]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[2]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[1]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// }); +// expect(usersWithInvitee[0]).toEqual({ +// id: 4, +// name: 'John', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user with invitee + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// with: { +// invitee: true, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// }); +// expect(usersWithInvitee).toContainEqual({ +// id: 4, +// name: 'John', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user with invitee + where + partial', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// columns: { +// id: true, +// name: true, +// }, +// with: { +// invitee: { +// columns: { +// id: true, +// name: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// invitee: { +// id: number; +// name: string; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee).toContainEqual({ +// id: 3, +// name: 'Alex', +// invitee: { id: 1, name: 'Dan' }, +// }); +// expect(usersWithInvitee).toContainEqual({ +// id: 4, +// name: 'John', +// invitee: { id: 2, name: 'Andrew' }, +// }); +// }); + +// test.skip('Get user with invitee + where + partial. Did not select users id, but used it in where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// columns: { +// name: true, +// }, +// with: { +// invitee: { +// columns: { +// id: true, +// name: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// name: string; +// invitee: { +// id: number; +// name: string; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee).toContainEqual({ +// name: 'Alex', +// invitee: { id: 1, name: 'Dan' }, +// }); +// expect(usersWithInvitee).toContainEqual({ +// name: 'John', +// invitee: { id: 2, name: 'Andrew' }, +// }); +// }); + +// test.skip('Get user with invitee + where + partial(true+false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// columns: { +// id: true, +// name: true, +// verified: false, +// }, +// with: { +// invitee: { +// columns: { +// id: true, +// name: true, +// verified: false, +// }, +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// invitee: { +// id: number; +// name: string; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee).toContainEqual({ +// id: 3, +// name: 'Alex', +// invitee: { id: 1, name: 'Dan' }, +// }); +// expect(usersWithInvitee).toContainEqual({ +// id: 4, +// name: 'John', +// invitee: { id: 2, name: 'Andrew' }, +// }); +// }); + +// test.skip('Get user with invitee + where + partial(false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// columns: { +// verified: false, +// }, +// with: { +// invitee: { +// columns: { +// name: false, +// }, +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// invitedBy: number | null; +// invitee: { +// id: number; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee).toContainEqual({ +// id: 3, +// name: 'Alex', +// invitedBy: 1, +// invitee: { id: 1, verified: false, invitedBy: null }, +// }); +// expect(usersWithInvitee).toContainEqual({ +// id: 4, +// name: 'John', +// invitedBy: 2, +// invitee: { id: 2, verified: false, invitedBy: null }, +// }); +// }); + +// /* +// Two first-level relations users+users and users+posts +// */ + +// test.skip('Get user with invitee and posts', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// with: { +// invitee: true, +// posts: true, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(4); + +// expect(response[0]?.invitee).toBeNull(); +// expect(response[1]?.invitee).toBeNull(); +// expect(response[2]?.invitee).not.toBeNull(); +// expect(response[3]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: response[0]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: response[1]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [{ id: 3, ownerId: 3, content: 'Post3', createdAt: response[2]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 4, +// name: 'John', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// posts: [], +// }); +// }); + +// test.skip('Get user with invitee and posts + limit posts and users', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// limit: 3, +// with: { +// invitee: true, +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(3); + +// expect(response[0]?.invitee).toBeNull(); +// expect(response[1]?.invitee).toBeNull(); +// expect(response[2]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: response[0]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 3, ownerId: 2, content: 'Post2', createdAt: response[1]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [{ id: 5, ownerId: 3, content: 'Post3', createdAt: response[2]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('Get user with invitee and posts + limits + custom fields in each', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// limit: 3, +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), +// with: { +// invitee: { +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_invitee_name') }), +// }, +// posts: { +// limit: 1, +// extras: (posts, { sql }) => ({ lower: sql`lower(${posts.content})`.as('lower_content') }), +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// lower: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(3); + +// expect(response[0]?.invitee).toBeNull(); +// expect(response[1]?.invitee).toBeNull(); +// expect(response[2]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', lower: 'post1', createdAt: response[0]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 3, ownerId: 2, content: 'Post2', lower: 'post2', createdAt: response[1]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, +// posts: [{ id: 5, ownerId: 3, content: 'Post3', lower: 'post3', createdAt: response[2]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('Get user with invitee and posts + custom fields in each', async () => { +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), +// with: { +// invitee: { +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), +// }, +// posts: { +// extras: (posts, { sql }) => ({ lower: sql`lower(${posts.content})`.as('lower_name') }), +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// lower: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// response[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// response[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// response[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(4); + +// expect(response[0]?.invitee).toBeNull(); +// expect(response[1]?.invitee).toBeNull(); +// expect(response[2]?.invitee).not.toBeNull(); +// expect(response[3]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(2); +// expect(response[1]?.posts.length).eq(2); +// expect(response[2]?.posts.length).eq(2); +// expect(response[3]?.posts.length).eq(0); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', lower: 'post1', createdAt: response[0]?.posts[0]?.createdAt }, { +// id: 2, +// ownerId: 1, +// content: 'Post1.1', +// lower: 'post1.1', +// createdAt: response[0]?.posts[1]?.createdAt, +// }], +// }); +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 3, ownerId: 2, content: 'Post2', lower: 'post2', createdAt: response[1]?.posts[0]?.createdAt }, { +// id: 4, +// ownerId: 2, +// content: 'Post2.1', +// lower: 'post2.1', +// createdAt: response[1]?.posts[1]?.createdAt, +// }], +// }); +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, +// posts: [{ id: 5, ownerId: 3, content: 'Post3', lower: 'post3', createdAt: response[2]?.posts[0]?.createdAt }, { +// id: 6, +// ownerId: 3, +// content: 'Post3.1', +// lower: 'post3.1', +// createdAt: response[2]?.posts[1]?.createdAt, +// }], +// }); +// expect(response).toContainEqual({ +// id: 4, +// name: 'John', +// lower: 'john', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', lower: 'andrew', verified: false, invitedBy: null }, +// posts: [], +// }); +// }); + +// test.skip('Get user with invitee and posts + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// orderBy: (users, { desc }) => [desc(users.id)], +// with: { +// invitee: true, +// posts: { +// orderBy: (posts, { desc }) => [desc(posts.id)], +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(response.length).eq(4); + +// expect(response[3]?.invitee).toBeNull(); +// expect(response[2]?.invitee).toBeNull(); +// expect(response[1]?.invitee).not.toBeNull(); +// expect(response[0]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(0); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(2); +// expect(response[3]?.posts.length).eq(2); + +// expect(response[3]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 2, ownerId: 1, content: 'Post1.1', createdAt: response[3]?.posts[0]?.createdAt }, { +// id: 1, +// ownerId: 1, +// content: 'Post1', +// createdAt: response[3]?.posts[1]?.createdAt, +// }], +// }); +// expect(response[2]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2.1', createdAt: response[2]?.posts[0]?.createdAt }, { +// id: 3, +// ownerId: 2, +// content: 'Post2', +// createdAt: response[2]?.posts[1]?.createdAt, +// }], +// }); +// expect(response[1]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [{ +// id: 5, +// ownerId: 3, +// content: 'Post3', +// createdAt: response[3]?.posts[1]?.createdAt, +// }], +// }); +// expect(response[0]).toEqual({ +// id: 4, +// name: 'John', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// posts: [], +// }); +// }); + +// test.skip('Get user with invitee and posts + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 2), eq(users.id, 3))), +// with: { +// invitee: true, +// posts: { +// where: (posts, { eq }) => (eq(posts.ownerId, 2)), +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(2); + +// expect(response[0]?.invitee).toBeNull(); +// expect(response[1]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(0); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: response[0]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [], +// }); +// }); + +// test.skip('Get user with invitee and posts + limit posts and users + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// limit: 1, +// with: { +// invitee: true, +// posts: { +// where: (posts, { eq }) => (eq(posts.ownerId, 3)), +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(response.length).eq(1); + +// expect(response[0]?.invitee).not.toBeNull(); +// expect(response[0]?.posts.length).eq(1); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [{ id: 5, ownerId: 3, content: 'Post3', createdAt: response[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('Get user with invitee and posts + orderBy + where + custom', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// orderBy: [desc(usersTable.id)], +// where: or(eq(usersTable.id, 3), eq(usersTable.id, 4)), +// extras: { +// lower: sql`lower(${usersTable.name})`.as('lower_name'), +// }, +// with: { +// invitee: true, +// posts: { +// where: eq(postsTable.ownerId, 3), +// orderBy: [desc(postsTable.id)], +// extras: { +// lower: sql`lower(${postsTable.content})`.as('lower_name'), +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lower: string; +// posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(response.length).eq(2); + +// expect(response[1]?.invitee).not.toBeNull(); +// expect(response[0]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(0); +// expect(response[1]?.posts.length).eq(1); + +// expect(response[1]).toEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [{ +// id: 5, +// ownerId: 3, +// content: 'Post3', +// lower: 'post3', +// createdAt: response[1]?.posts[0]?.createdAt, +// }], +// }); +// expect(response[0]).toEqual({ +// id: 4, +// name: 'John', +// lower: 'john', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// posts: [], +// }); +// }); + +// test.skip('Get user with invitee and posts + orderBy + where + partial + custom', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// orderBy: [desc(usersTable.id)], +// where: or(eq(usersTable.id, 3), eq(usersTable.id, 4)), +// extras: { +// lower: sql`lower(${usersTable.name})`.as('lower_name'), +// }, +// columns: { +// id: true, +// name: true, +// }, +// with: { +// invitee: { +// columns: { +// id: true, +// name: true, +// }, +// extras: { +// lower: sql`lower(${usersTable.name})`.as('lower_name'), +// }, +// }, +// posts: { +// columns: { +// id: true, +// content: true, +// }, +// where: eq(postsTable.ownerId, 3), +// orderBy: [desc(postsTable.id)], +// extras: { +// lower: sql`lower(${postsTable.content})`.as('lower_name'), +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// lower: string; +// posts: { id: number; lower: string; content: string }[]; +// invitee: { +// id: number; +// name: string; +// lower: string; +// } | null; +// }[] +// >(); + +// expect(response.length).eq(2); + +// expect(response[1]?.invitee).not.toBeNull(); +// expect(response[0]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(0); +// expect(response[1]?.posts.length).eq(1); + +// expect(response[1]).toEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// invitee: { id: 1, name: 'Dan', lower: 'dan' }, +// posts: [{ +// id: 5, +// content: 'Post3', +// lower: 'post3', +// }], +// }); +// expect(response[0]).toEqual({ +// id: 4, +// name: 'John', +// lower: 'john', +// invitee: { id: 2, name: 'Andrew', lower: 'andrew' }, +// posts: [], +// }); +// }); + +// /* +// One two-level relation users+posts+comments +// */ + +// test.skip('Get user with posts and posts with comments', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { id: 1, ownerId: 1, content: 'Post1' }, +// { id: 2, ownerId: 2, content: 'Post2' }, +// { id: 3, ownerId: 3, content: 'Post3' }, +// ]); + +// await db.insert(commentsTable).values([ +// { postId: 1, content: 'Comment1', creator: 2 }, +// { postId: 2, content: 'Comment2', creator: 2 }, +// { postId: 3, content: 'Comment3', creator: 3 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// with: { +// posts: { +// with: { +// comments: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// comments: { +// id: number; +// content: string; +// createdAt: Date; +// creator: number | null; +// postId: number | null; +// }[]; +// }[]; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(3); +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(1); + +// expect(response[0]?.posts[0]?.comments.length).eq(1); +// expect(response[1]?.posts[0]?.comments.length).eq(1); +// expect(response[2]?.posts[0]?.comments.length).eq(1); + +// expect(response[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 1, +// ownerId: 1, +// content: 'Post1', +// createdAt: response[0]?.posts[0]?.createdAt, +// comments: [ +// { +// id: 1, +// content: 'Comment1', +// creator: 2, +// postId: 1, +// createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, +// }, +// ], +// }], +// }); +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 2, +// ownerId: 2, +// content: 'Post2', +// createdAt: response[1]?.posts[0]?.createdAt, +// comments: [ +// { +// id: 2, +// content: 'Comment2', +// creator: 2, +// postId: 2, +// createdAt: response[1]?.posts[0]?.comments[0]?.createdAt, +// }, +// ], +// }], +// }); +// // expect(response[2]).toEqual({ +// // id: 3, +// // name: 'Alex', +// // verified: false, +// // invitedBy: null, +// // posts: [{ +// // id: 3, +// // ownerId: 3, +// // content: 'Post3', +// // createdAt: response[2]?.posts[0]?.createdAt, +// // comments: [ +// // { +// // id: , +// // content: 'Comment3', +// // creator: 3, +// // postId: 3, +// // createdAt: response[2]?.posts[0]?.comments[0]?.createdAt, +// // }, +// // ], +// // }], +// // }); +// }); + +// // Get user with limit posts and limit comments + +// // Get user with custom field + post + comment with custom field + +// // Get user with limit + posts orderBy + comment orderBy + +// // Get user with where + posts where + comment where + +// // Get user with where + posts partial where + comment where + +// // Get user with where + posts partial where + comment partial(false) where + +// // Get user with where partial(false) + posts partial where partial(false) + comment partial(false+true) where + +// // Get user with where + posts partial where + comment where. Didn't select field from where in posts + +// // Get user with where + posts partial where + comment where. Didn't select field from where for all + +// // Get with limit+offset in each + +// /* +// One two-level + One first-level relation users+posts+comments and users+users +// */ + +// /* +// One three-level relation users+posts+comments+comment_owner +// */ + +// test.skip('Get user with posts and posts with comments and comments with owner', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { id: 1, ownerId: 1, content: 'Post1' }, +// { id: 2, ownerId: 2, content: 'Post2' }, +// { id: 3, ownerId: 3, content: 'Post3' }, +// ]); + +// await db.insert(commentsTable).values([ +// { postId: 1, content: 'Comment1', creator: 2 }, +// { postId: 2, content: 'Comment2', creator: 2 }, +// { postId: 3, content: 'Comment3', creator: 3 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// with: { +// posts: { +// with: { +// comments: { +// with: { +// author: true, +// }, +// }, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// comments: { +// id: number; +// content: string; +// createdAt: Date; +// creator: number | null; +// postId: number | null; +// author: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[]; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(3); +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(1); + +// expect(response[0]?.posts[0]?.comments.length).eq(1); +// expect(response[1]?.posts[0]?.comments.length).eq(1); +// expect(response[2]?.posts[0]?.comments.length).eq(1); + +// expect(response[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 1, +// ownerId: 1, +// content: 'Post1', +// createdAt: response[0]?.posts[0]?.createdAt, +// comments: [ +// { +// id: 1, +// content: 'Comment1', +// creator: 2, +// author: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// postId: 1, +// createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, +// }, +// ], +// }], +// }); +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 2, +// ownerId: 2, +// content: 'Post2', +// createdAt: response[1]?.posts[0]?.createdAt, +// comments: [ +// { +// id: 2, +// content: 'Comment2', +// creator: 2, +// author: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// postId: 2, +// createdAt: response[1]?.posts[0]?.comments[0]?.createdAt, +// }, +// ], +// }], +// }); +// }); + +// test.skip('Get user with posts and posts with comments and comments with owner where exists', async () => { +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { id: 1, ownerId: 1, content: 'Post1' }, +// { id: 2, ownerId: 2, content: 'Post2' }, +// { id: 3, ownerId: 3, content: 'Post3' }, +// ]); + +// await db.insert(commentsTable).values([ +// { postId: 1, content: 'Comment1', creator: 2 }, +// { postId: 2, content: 'Comment2', creator: 2 }, +// { postId: 3, content: 'Comment3', creator: 3 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// with: { +// posts: { +// with: { +// comments: { +// with: { +// author: true, +// }, +// }, +// }, +// }, +// }, +// where: (table, { exists, eq }) => exists(db.select({ one: sql`1` }).from(usersTable).where(eq(sql`1`, table.id))), +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// comments: { +// id: number; +// content: string; +// createdAt: Date; +// creator: number | null; +// postId: number | null; +// author: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[]; +// }[]; +// }[]>(); + +// expect(response.length).eq(1); +// expect(response[0]?.posts.length).eq(1); + +// expect(response[0]?.posts[0]?.comments.length).eq(1); + +// expect(response[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 1, +// ownerId: 1, +// content: 'Post1', +// createdAt: response[0]?.posts[0]?.createdAt, +// comments: [ +// { +// id: 1, +// content: 'Comment1', +// creator: 2, +// author: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// postId: 1, +// createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, +// }, +// ], +// }], +// }); +// }); + +// /* +// One three-level relation + 1 first-level relatioon +// 1. users+posts+comments+comment_owner +// 2. users+users +// */ + +// /* +// One four-level relation users+posts+comments+coment_likes +// */ + +// /* +// [Find Many] Many-to-many cases + +// Users+users_to_groups+groups +// */ + +// test.skip('[Find Many] Get users with groups', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); +// expect(response[2]?.usersToGroups.length).toEqual(2); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// description: null, +// }, +// }, { +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get groups with users', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(2); +// expect(response[2]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }, { +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Group3', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get users with groups + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// limit: 2, +// with: { +// usersToGroups: { +// limit: 1, +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get groups with users + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// limit: 2, +// with: { +// usersToGroups: { +// limit: 1, +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get users with groups + limit + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// limit: 1, +// where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.groupId, 1), +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(1); + +// expect(response[0]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get groups with users + limit + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// limit: 1, +// where: gt(groupsTable.id, 1), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.userId, 2), +// limit: 1, +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(1); + +// expect(response[0]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get users with groups + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.groupId, 2), +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(0); +// expect(response[1]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get groups with users + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// where: gt(groupsTable.id, 1), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.userId, 2), +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(0); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Group3', +// description: null, +// usersToGroups: [], +// }); +// }); + +// test.skip('[Find Many] Get users with groups + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// orderBy: (users, { desc }) => [desc(users.id)], +// with: { +// usersToGroups: { +// orderBy: [desc(usersToGroupsTable.groupId)], +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(2); +// expect(response[1]?.usersToGroups.length).toEqual(1); +// expect(response[2]?.usersToGroups.length).toEqual(1); + +// expect(response[2]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); + +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); + +// expect(response[0]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// description: null, +// }, +// }, { +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get groups with users + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// orderBy: [desc(groupsTable.id)], +// with: { +// usersToGroups: { +// orderBy: (utg, { desc }) => [desc(utg.userId)], +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[]>(); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(2); +// expect(response[2]?.usersToGroups.length).toEqual(1); + +// expect(response[2]).toEqual({ +// id: 1, +// name: 'Group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }, { +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response[0]).toEqual({ +// id: 3, +// name: 'Group3', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get users with groups + orderBy + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// orderBy: (users, { desc }) => [desc(users.id)], +// limit: 2, +// with: { +// usersToGroups: { +// limit: 1, +// orderBy: [desc(usersToGroupsTable.groupId)], +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); + +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); + +// expect(response[0]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// description: null, +// }, +// }], +// }); +// }); + +// /* +// [Find One] Many-to-many cases + +// Users+users_to_groups+groups +// */ + +// test.skip('[Find One] Get users with groups', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get groups with users', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findFirst({ +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 1, +// name: 'Group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get users with groups + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// with: { +// usersToGroups: { +// limit: 1, +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get groups with users + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findFirst({ +// with: { +// usersToGroups: { +// limit: 1, +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 1, +// name: 'Group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get users with groups + limit + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.groupId, 1), +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get groups with users + limit + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findFirst({ +// where: gt(groupsTable.id, 1), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.userId, 2), +// limit: 1, +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get users with groups + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.groupId, 2), +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(0); + +// expect(response).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [], +// }); +// }); + +// test.skip('[Find One] Get groups with users + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findFirst({ +// where: gt(groupsTable.id, 1), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.userId, 2), +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get users with groups + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// orderBy: (users, { desc }) => [desc(users.id)], +// with: { +// usersToGroups: { +// orderBy: [desc(usersToGroupsTable.groupId)], +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(2); + +// expect(response).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// description: null, +// }, +// }, { +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get groups with users + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findFirst({ +// orderBy: [desc(groupsTable.id)], +// with: { +// usersToGroups: { +// orderBy: (utg, { desc }) => [desc(utg.userId)], +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 3, +// name: 'Group3', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get users with groups + orderBy + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// orderBy: (users, { desc }) => [desc(users.id)], +// with: { +// usersToGroups: { +// limit: 1, +// orderBy: [desc(usersToGroupsTable.groupId)], +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('Get groups with users + orderBy + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// orderBy: [desc(groupsTable.id)], +// limit: 2, +// with: { +// usersToGroups: { +// limit: 1, +// orderBy: (utg, { desc }) => [desc(utg.userId)], +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[] +// >(); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); + +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response[0]).toEqual({ +// id: 3, +// name: 'Group3', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('Get users with groups + custom', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// extras: { +// lower: sql`lower(${usersTable.name})`.as('lower_name'), +// }, +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// group: { +// extras: { +// lower: sql`lower(${groupsTable.name})`.as('lower_name'), +// }, +// }, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lower: string; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// lower: string; +// }; +// }[]; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); +// expect(response[2]?.usersToGroups.length).toEqual(2); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// lower: 'group1', +// description: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// lower: 'group2', +// description: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// lower: 'group3', +// description: null, +// }, +// }, { +// group: { +// id: 2, +// name: 'Group2', +// lower: 'group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('Get groups with users + custom', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// extras: (table, { sql }) => ({ +// lower: sql`lower(${table.name})`.as('lower_name'), +// }), +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// user: { +// extras: (table, { sql }) => ({ +// lower: sql`lower(${table.name})`.as('lower_name'), +// }), +// }, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// lower: string; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lower: string; +// }; +// }[]; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(2); +// expect(response[2]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Group1', +// lower: 'group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Group2', +// lower: 'group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// }, +// }, { +// user: { +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Group3', +// lower: 'group3', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test('.toSQL()', () => { +// const query = db.query.usersTable.findFirst().toSQL(); + +// expect(query).toHaveProperty('sql', expect.any(String)); +// expect(query).toHaveProperty('params', expect.any(Array)); +// }); + +// // + custom + where + orderby + +// // + custom + where + orderby + limit + +// // + partial + +// // + partial(false) + +// // + partial + orderBy + where (all not selected) + +// /* +// One four-level relation users+posts+comments+coment_likes +// + users+users_to_groups+groups +// */ + +// /* +// Really hard case +// 1. users+posts+comments+coment_likes +// 2. users+users_to_groups+groups +// 3. users+users +// */ +// eslint-disable-next-line unicorn/no-empty-file diff --git a/integration-tests/tests/replicas/singlestore.test.ts b/integration-tests/tests/replicas/singlestore.test.ts index 56a589224..8ddad5b04 100644 --- a/integration-tests/tests/replicas/singlestore.test.ts +++ b/integration-tests/tests/replicas/singlestore.test.ts @@ -1,13 +1,13 @@ import { sql } from 'drizzle-orm'; import { drizzle } from 'drizzle-orm/singlestore'; -import { boolean, serial, singlestoreTable, text, withReplicas } from 'drizzle-orm/singlestore-core'; +import { serial, singlestoreTable, withReplicas } from 'drizzle-orm/singlestore-core'; import { describe, expect, it, vi } from 'vitest'; -const usersTable = singlestoreTable('users', { - id: serial('id' as string).primaryKey(), - name: text('name').notNull(), - verified: boolean('verified').notNull().default(false), -}); +// const usersTable = singlestoreTable('users', { +// id: serial('id' as string).primaryKey(), +// name: text('name').notNull(), +// verified: boolean('verified').notNull().default(false), +// }); const users = singlestoreTable('users', { id: serial('id' as string).primaryKey(), @@ -556,250 +556,259 @@ describe('[transaction] replicas singlestore', () => { }); }); -describe('[findFirst] read replicas singlestore', () => { - it('primary findFirst', () => { - const primaryDb = drizzle.mock({ schema: { usersTable } }); - const read1 = drizzle.mock({ schema: { usersTable } }); - const read2 = drizzle.mock({ schema: { usersTable } }); - - const db = withReplicas(primaryDb, [read1, read2]); - - const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); - const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); - const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); - const obj = {} as any; - - db.$primary.query.usersTable.findFirst(obj); - - expect(spyPrimary).toHaveBeenCalledTimes(1); - expect(spyRead1).toHaveBeenCalledTimes(0); - expect(spyRead2).toHaveBeenCalledTimes(0); - expect(spyPrimary).toHaveBeenCalledWith(obj); - }); - - it('random replica findFirst', () => { - const primaryDb = drizzle.mock({ schema: { usersTable } }); - const read1 = drizzle.mock({ schema: { usersTable } }); - const read2 = drizzle.mock({ schema: { usersTable } }); - - const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); - - const db = withReplicas(primaryDb, [read1, read2], () => { - return randomMockReplica(); - }); - - const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); - const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); - const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); - const par1 = {} as any; - - db.query.usersTable.findFirst(par1); - - expect(spyPrimary).toHaveBeenCalledTimes(0); - expect(spyRead1).toHaveBeenCalledTimes(1); - expect(spyRead2).toHaveBeenCalledTimes(0); - expect(spyRead1).toHaveBeenCalledWith(par1); - - const query = db.query.usersTable.findFirst(); - expect(spyRead1).toHaveBeenCalledTimes(1); - expect(spyRead2).toHaveBeenCalledTimes(1); - expect(query.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable` limit ?'); - }); - - it('single read replica findFirst', () => { - const primaryDb = drizzle.mock({ schema: { usersTable } }); - const read1 = drizzle.mock({ schema: { usersTable } }); - - const db = withReplicas(primaryDb, [read1]); - - const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); - const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); - - db.query.usersTable.findFirst(); - - expect(spyPrimary).toHaveBeenCalledTimes(0); - expect(spyRead1).toHaveBeenCalledTimes(1); - - db.query.usersTable.findFirst(); - expect(spyRead1).toHaveBeenCalledTimes(2); - }); - - it('single read replica findFirst + primary findFirst', () => { - const primaryDb = drizzle.mock({ schema: { usersTable } }); - const read1 = drizzle.mock({ schema: { usersTable } }); - - const db = withReplicas(primaryDb, [read1]); - - const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); - const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); - - db.query.usersTable.findFirst(); - - expect(spyPrimary).toHaveBeenCalledTimes(0); - expect(spyRead1).toHaveBeenCalledTimes(1); - - db.$primary.query.usersTable.findFirst(); - expect(spyPrimary).toHaveBeenCalledTimes(1); - expect(spyRead1).toHaveBeenCalledTimes(1); - }); - - it('always first read findFirst', () => { - const primaryDb = drizzle.mock({ schema: { usersTable } }); - const read1 = drizzle.mock({ schema: { usersTable } }); - const read2 = drizzle.mock({ schema: { usersTable } }); - - const db = withReplicas(primaryDb, [read1, read2], (replicas) => { - return replicas[0]!; - }); - - const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); - const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); - const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); +// We are waiting for SingleStore support for `json_array` function +// describe('[findFirst] read replicas singlestore', () => { +// // it('primary findFirst', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); - db.query.usersTable.findFirst(); +// // const db = withReplicas(primaryDb, [read1, read2]); - expect(spyPrimary).toHaveBeenCalledTimes(0); - expect(spyRead1).toHaveBeenCalledTimes(1); - expect(spyRead2).toHaveBeenCalledTimes(0); +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); +// // const obj = {} as any; - db.query.usersTable.findFirst(); - expect(spyRead1).toHaveBeenCalledTimes(2); - expect(spyRead2).toHaveBeenCalledTimes(0); - }); -}); +// // db.$primary.query.usersTable.findFirst(obj); -describe('[findMany] read replicas singlestore', () => { - it('primary findMany', () => { - const primaryDb = drizzle.mock({ schema: { usersTable } }); - const read1 = drizzle.mock({ schema: { usersTable } }); - const read2 = drizzle.mock({ schema: { usersTable } }); +// // expect(spyPrimary).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledTimes(0); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(spyPrimary).toHaveBeenCalledWith(obj); +// // }); - const db = withReplicas(primaryDb, [read1, read2]); +// // it('random replica findFirst', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); - const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); - const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); - const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); - const obj = {} as any; +// // const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); - const query = db.$primary.query.usersTable.findMany(obj); +// // const db = withReplicas(primaryDb, [read1, read2], () => { +// // return randomMockReplica(); +// // }); - expect(spyPrimary).toHaveBeenCalledTimes(1); - expect(spyRead1).toHaveBeenCalledTimes(0); - expect(spyRead2).toHaveBeenCalledTimes(0); - expect(spyPrimary).toHaveBeenCalledWith(obj); - expect(query.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); - }); +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); +// // const par1 = {} as any; - it('random replica findMany', () => { - const primaryDb = drizzle.mock({ schema: { usersTable } }); - const read1 = drizzle.mock({ schema: { usersTable } }); - const read2 = drizzle.mock({ schema: { usersTable } }); +// // db.query.usersTable.findFirst(par1); - const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledWith(par1); - const db = withReplicas(primaryDb, [read1, read2], () => { - return randomMockReplica(); - }); +// // const query = db.query.usersTable.findFirst(); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(1); +// // expect(query.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable` limit ?'); +// // }); - const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); - const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); - const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); - const obj1 = {} as any; - const obj2 = {} as any; +// // We are waiting for SingleStore support for `json_array` function +// // it('single read replica findFirst', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); - const query1 = db.query.usersTable.findMany(obj1); +// // const db = withReplicas(primaryDb, [read1]); - expect(spyPrimary).toHaveBeenCalledTimes(0); - expect(spyRead1).toHaveBeenCalledTimes(1); - expect(spyRead2).toHaveBeenCalledTimes(0); - expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); - expect(spyRead1).toHaveBeenCalledWith(obj1); +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); - const query2 = db.query.usersTable.findMany(obj2); +// // db.query.usersTable.findFirst(); - expect(spyRead1).toHaveBeenCalledTimes(1); - expect(spyRead2).toHaveBeenCalledTimes(1); - expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); - expect(spyRead2).toHaveBeenCalledWith(obj2); - }); +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); - it('single read replica findMany', () => { - const primaryDb = drizzle.mock({ schema: { usersTable } }); - const read1 = drizzle.mock({ schema: { usersTable } }); +// // db.query.usersTable.findFirst(); +// // expect(spyRead1).toHaveBeenCalledTimes(2); +// // }); - const db = withReplicas(primaryDb, [read1]); +// // We are waiting for SingleStore support for `json_array` function +// // it('single read replica findFirst + primary findFirst', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); - const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); - const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); - const obj1 = {} as any; - const obj2 = {} as any; +// // const db = withReplicas(primaryDb, [read1]); - const query1 = db.query.usersTable.findMany(obj1); +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); - expect(spyPrimary).toHaveBeenCalledTimes(0); - expect(spyRead1).toHaveBeenCalledTimes(1); - expect(spyRead1).toHaveBeenCalledWith(obj1); - expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // db.query.usersTable.findFirst(); - const query2 = db.query.usersTable.findMany(obj2); - expect(spyRead1).toHaveBeenCalledTimes(2); - expect(spyRead1).toHaveBeenNthCalledWith(2, obj2); - expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); - }); +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); - it('single read replica findMany + primary findMany', () => { - const primaryDb = drizzle.mock({ schema: { usersTable } }); - const read1 = drizzle.mock({ schema: { usersTable } }); +// // db.$primary.query.usersTable.findFirst(); +// // expect(spyPrimary).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // }); - const db = withReplicas(primaryDb, [read1]); +// // We are waiting for SingleStore support for `json_array` function +// // it('always first read findFirst', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); - const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); - const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); - const obj1 = {} as any; - const obj2 = {} as any; +// // const db = withReplicas(primaryDb, [read1, read2], (replicas) => { +// // return replicas[0]!; +// // }); - const query1 = db.query.usersTable.findMany(obj1); +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); - expect(spyPrimary).toHaveBeenCalledTimes(0); - expect(spyRead1).toHaveBeenCalledTimes(1); - expect(spyRead1).toHaveBeenCalledWith(obj1); - expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // db.query.usersTable.findFirst(); - const query2 = db.$primary.query.usersTable.findMany(obj2); +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(0); - expect(spyPrimary).toHaveBeenCalledTimes(1); - expect(spyRead1).toHaveBeenCalledTimes(1); - expect(spyPrimary).toHaveBeenNthCalledWith(1, obj2); - expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); - }); +// // db.query.usersTable.findFirst(); +// // expect(spyRead1).toHaveBeenCalledTimes(2); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // }); +// }); - it('always first read findMany', () => { - const primaryDb = drizzle.mock({ schema: { usersTable } }); - const read1 = drizzle.mock({ schema: { usersTable } }); - const read2 = drizzle.mock({ schema: { usersTable } }); +// describe('[findMany] read replicas singlestore', () => { +// // We are waiting for SingleStore support for `json_array` function +// // it('primary findMany', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); - const db = withReplicas(primaryDb, [read1, read2], (replicas) => { - return replicas[0]!; - }); +// // const db = withReplicas(primaryDb, [read1, read2]); - const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); - const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); - const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); - const obj1 = {} as any; - const obj2 = {} as any; +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); +// // const obj = {} as any; + +// // const query = db.$primary.query.usersTable.findMany(obj); - const query1 = db.query.usersTable.findMany(obj1); +// // expect(spyPrimary).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledTimes(0); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(spyPrimary).toHaveBeenCalledWith(obj); +// // expect(query.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // }); + +// // We are waiting for SingleStore support for `json_array` function +// // it('random replica findMany', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); - expect(spyPrimary).toHaveBeenCalledTimes(0); - expect(spyRead1).toHaveBeenCalledTimes(1); - expect(spyRead2).toHaveBeenCalledTimes(0); - expect(spyRead1).toHaveBeenCalledWith(obj1); - expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + +// // const db = withReplicas(primaryDb, [read1, read2], () => { +// // return randomMockReplica(); +// // }); - const query2 = db.query.usersTable.findMany(obj2); - expect(spyRead1).toHaveBeenCalledTimes(2); - expect(spyRead2).toHaveBeenCalledTimes(0); - expect(spyRead1).toHaveBeenNthCalledWith(2, obj2); - expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); - }); -}); +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); +// // const obj1 = {} as any; +// // const obj2 = {} as any; + +// // const query1 = db.query.usersTable.findMany(obj1); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // expect(spyRead1).toHaveBeenCalledWith(obj1); + +// // const query2 = db.query.usersTable.findMany(obj2); + +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(1); +// // expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // expect(spyRead2).toHaveBeenCalledWith(obj2); +// // }); + +// // We are waiting for SingleStore support for `json_array` function +// // it('single read replica findMany', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); + +// // const db = withReplicas(primaryDb, [read1]); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); +// // const obj1 = {} as any; +// // const obj2 = {} as any; + +// // const query1 = db.query.usersTable.findMany(obj1); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledWith(obj1); +// // expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + +// // const query2 = db.query.usersTable.findMany(obj2); +// // expect(spyRead1).toHaveBeenCalledTimes(2); +// // expect(spyRead1).toHaveBeenNthCalledWith(2, obj2); +// // expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // }); + +// // We are waiting for SingleStore support for `json_array` function +// // it('single read replica findMany + primary findMany', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); + +// // const db = withReplicas(primaryDb, [read1]); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); +// // const obj1 = {} as any; +// // const obj2 = {} as any; + +// // const query1 = db.query.usersTable.findMany(obj1); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledWith(obj1); +// // expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + +// // const query2 = db.$primary.query.usersTable.findMany(obj2); + +// // expect(spyPrimary).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyPrimary).toHaveBeenNthCalledWith(1, obj2); +// // expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // }); + +// // We are waiting for SingleStore support for `json_array` function +// // it('always first read findMany', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); + +// // const db = withReplicas(primaryDb, [read1, read2], (replicas) => { +// // return replicas[0]!; +// // }); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); +// // const obj1 = {} as any; +// // const obj2 = {} as any; + +// // const query1 = db.query.usersTable.findMany(obj1); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledWith(obj1); +// // expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + +// // const query2 = db.query.usersTable.findMany(obj2); +// // expect(spyRead1).toHaveBeenCalledTimes(2); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenNthCalledWith(2, obj2); +// // expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // }); +// }); diff --git a/integration-tests/tests/singlestore/singlestore-common.ts b/integration-tests/tests/singlestore/singlestore-common.ts index f97721857..fc45ee2e8 100644 --- a/integration-tests/tests/singlestore/singlestore-common.ts +++ b/integration-tests/tests/singlestore/singlestore-common.ts @@ -209,9 +209,6 @@ export async function createDockerDB(): Promise<{ connectionString: string; cont }; } -// Tests are slow so we keep track of the test number -let testRunNumber = 0; - export function tests(driver?: string) { describe('common', () => { afterAll(async () => { @@ -289,9 +286,6 @@ export function tests(driver?: string) { ) `, ); - - testRunNumber += 1; - console.log(`Test number: ${testRunNumber}`); }); async function setupReturningFunctionsTest(db: SingleStoreDatabase) { @@ -3182,7 +3176,7 @@ export function tests(driver?: string) { expect(query).toEqual({ sql: - `select \`id\`, \`name\` from \`mySchema\`.\`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + `select \`id\`, \`name\` from \`mySchema\`.\`userstest\` group by \`mySchema\`.\`id\`, \`mySchema\`.\`name\``, params: [], }); }); diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index cc050c02b..a04281018 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -59,6 +59,8 @@ export default defineConfig({ 'tests/sqlite/libsql-ws.test.ts', 'tests/sqlite/libsql-http.test.ts', 'tests/mysql/tidb-serverless.test.ts', + // waiting for json_array from singlestore team + 'tests/relational/singlestore.test.ts', ], typecheck: { tsconfig: 'tsconfig.json', From 6cd108ed3b67f70f52b613a71b69bc42f942c6aa Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 28 Nov 2024 11:40:47 +0200 Subject: [PATCH 400/492] Fix tests --- integration-tests/tests/singlestore/singlestore-common.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/tests/singlestore/singlestore-common.ts b/integration-tests/tests/singlestore/singlestore-common.ts index fc45ee2e8..6335bf9ec 100644 --- a/integration-tests/tests/singlestore/singlestore-common.ts +++ b/integration-tests/tests/singlestore/singlestore-common.ts @@ -2701,7 +2701,7 @@ export function tests(driver?: string) { })()).rejects.toThrowError(); }); - test('set operations (mixed) from query builder', async (ctx) => { + test.skip('set operations (mixed) from query builder', async (ctx) => { const { db } = ctx.singlestore; await setupSetOperationTest(db); @@ -3176,7 +3176,7 @@ export function tests(driver?: string) { expect(query).toEqual({ sql: - `select \`id\`, \`name\` from \`mySchema\`.\`userstest\` group by \`mySchema\`.\`id\`, \`mySchema\`.\`name\``, + `select \`id\`, \`name\` from \`mySchema\`.\`userstest\` group by \`mySchema\`.\`userstest\`.\`id\`, \`mySchema\`.\`userstest\`.\`name\``, params: [], }); }); From 5a97e0e613ac640b8b9e229bf2326c69de64ede2 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Thu, 28 Nov 2024 17:14:24 +0200 Subject: [PATCH 401/492] bug fixes(array seeding), added tests for array seeding --- drizzle-seed/src/index.ts | 1 + .../src/services/GeneratorsWrappers.ts | 5 +- drizzle-seed/src/services/SeedService.ts | 107 ++- .../src/tests/pg/allDataTypesTest/pgSchema.ts | 35 + .../pg_all_data_types.test.ts | 92 ++- .../pg/generatorsTest/generators.test.ts | 673 +++++++++++++++++- .../src/tests/pg/generatorsTest/pgSchema.ts | 108 +++ drizzle-seed/src/types/tables.ts | 12 +- drizzle-seed/tsconfig.json | 2 +- 9 files changed, 992 insertions(+), 43 deletions(-) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index be3dd7d03..bfe6cc92c 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -569,6 +569,7 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { dataType: baseColumn.dataType, size: (baseColumn as PgArray).size, hasDefault: baseColumn.hasDefault, + enumValues: baseColumn.enumValues, default: baseColumn.default, isUnique: baseColumn.isUnique, notNull: baseColumn.notNull, diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts index 46e33cfb0..7d701f546 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -23,6 +23,7 @@ export abstract class AbstractGenerator { public dataType?: string; public timeSpent?: number; public arraySize?: number; + public baseColumnDataType?: string; constructor(public params: T) {} @@ -58,9 +59,11 @@ export abstract class AbstractGenerator { replaceIfArray({ count, seed }: { count: number; seed: number }) { if (!(this.getEntityKind() === 'GenerateArray') && this.arraySize !== undefined) { const uniqueGen = this.replaceIfUnique({ count, seed }); + const baseColumnGen = uniqueGen === undefined ? this : uniqueGen; + baseColumnGen.dataType = this.baseColumnDataType; const arrayGen = new GenerateArray( { - baseColumnGen: uniqueGen === undefined ? this : uniqueGen, + baseColumnGen, size: this.arraySize, }, ); diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index e4bceefc2..508e3714b 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -192,6 +192,13 @@ class SeedService { const genObj = refinements[table.name]!.columns[col.name]!; // TODO: for now only GenerateValuesFromArray support notNull property genObj.notNull = col.notNull; + if (col.dataType === 'array') { + if (col.baseColumn?.dataType === 'array' && col.baseColumn?.columnType === 'array') { + throw new Error("for now you can't specify generators for columns of dimensition greater than 1."); + } + + genObj.baseColumnDataType = col.baseColumn?.dataType; + } columnPossibleGenerator.generator = genObj; } else if (Object.hasOwn(foreignKeyColumns, col.name)) { @@ -227,6 +234,7 @@ class SeedService { columnPossibleGenerator.generator.isUnique = col.isUnique; columnPossibleGenerator.generator.dataType = col.dataType; + tablePossibleGenerators.columnsPossibleGenerators.push( columnPossibleGenerator, ); @@ -343,10 +351,13 @@ class SeedService { }; // TODO: revise serial part generators + pickGeneratorForPostgresColumn = ( table: Table, col: Column, ) => { + let generator: AbstractGenerator | undefined; + // INT ------------------------------------------------------------------------------------------------------------ if ( (col.columnType.includes('serial') @@ -355,7 +366,10 @@ class SeedService { || col.columnType.includes('bigint')) && table.primaryKeys.includes(col.name) ) { - const generator = new GenerateIntPrimaryKey({}); + generator = new GenerateIntPrimaryKey({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } @@ -401,16 +415,22 @@ class SeedService { && !col.columnType.includes('interval') && !col.columnType.includes('point') ) { - const generator = new GenerateInt({ + generator = new GenerateInt({ minValue, maxValue, }); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } if (col.columnType.includes('serial')) { - const generator = new GenerateIntPrimaryKey({}); - generator.maxValue = maxValue; + generator = new GenerateIntPrimaryKey({}); + + (generator as GenerateIntPrimaryKey).maxValue = maxValue; + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } @@ -421,7 +441,10 @@ class SeedService { || col.columnType === 'decimal' || col.columnType === 'numeric' ) { - const generator = new GenerateNumber({}); + generator = new GenerateNumber({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } @@ -432,7 +455,10 @@ class SeedService { || col.columnType === 'char') && table.primaryKeys.includes(col.name) ) { - const generator = new GenerateUniqueString({}); + generator = new GenerateUniqueString({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } @@ -442,7 +468,10 @@ class SeedService { || col.columnType === 'char') && col.name.toLowerCase().includes('name') ) { - const generator = new GenerateFirstName({}); + generator = new GenerateFirstName({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } @@ -452,7 +481,10 @@ class SeedService { || col.columnType === 'char') && col.name.toLowerCase().includes('email') ) { - const generator = new GenerateEmail({}); + generator = new GenerateEmail({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } @@ -462,35 +494,53 @@ class SeedService { || col.columnType === 'char' ) { // console.log(col, table) - const generator = new GenerateString({}); + generator = new GenerateString({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } // BOOLEAN if (col.columnType === 'boolean') { - const generator = new GenerateBoolean({}); + generator = new GenerateBoolean({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } // DATE, TIME, TIMESTAMP if (col.columnType.includes('date')) { - const generator = new GenerateDate({}); + generator = new GenerateDate({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } if (col.columnType === 'time') { - const generator = new GenerateTime({}); + generator = new GenerateTime({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } if (col.columnType.includes('timestamp')) { - const generator = new GenerateTimestamp({}); + generator = new GenerateTimestamp({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } // JSON, JSONB if (col.columnType === 'json' || col.columnType === 'jsonb') { - const generator = new GenerateJson({}); + generator = new GenerateJson({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } @@ -501,26 +551,38 @@ class SeedService { // ENUM if (col.enumValues !== undefined) { - const generator = new GenerateEnum({ + generator = new GenerateEnum({ enumValues: col.enumValues, }); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } // INTERVAL if (col.columnType === 'interval') { - const generator = new GenerateInterval({}); + generator = new GenerateInterval({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } // POINT, LINE if (col.columnType.includes('point')) { - const generator = new GeneratePoint({}); + generator = new GeneratePoint({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } if (col.columnType.includes('line')) { - const generator = new GenerateLine({}); + generator = new GenerateLine({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } @@ -530,11 +592,14 @@ class SeedService { if (baseColumnGen === undefined) { throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); } - const generator = new GenerateArray({ baseColumnGen, size: col.size }); + generator = new GenerateArray({ baseColumnGen, size: col.size }); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; return generator; } - return; + return generator; }; pickGeneratorForMysqlColumn = ( @@ -985,7 +1050,7 @@ class SeedService { count, preserveData = true, insertDataInDb = true, - batchSize = 10000, + batchSize = 1, }: { tableGenerators: Prettify; db?: diff --git a/drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts b/drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts index c8dd22355..5bd428a1c 100644 --- a/drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts +++ b/drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts @@ -60,3 +60,38 @@ export const allDataTypes = schema.table('all_data_types', { lineTuple: line('line_tuple', { mode: 'tuple' }), moodEnum: moodEnum('mood_enum'), }); + +export const allArrayDataTypes = schema.table('all_array_data_types', { + integerArray: integer('integer_array').array(), + smallintArray: smallint('smallint_array').array(), + bigintegerArray: bigint('bigint_array', { mode: 'bigint' }).array(), + bigintNumberArray: bigint('bigint_number_array', { mode: 'number' }).array(), + booleanArray: boolean('boolean_array').array(), + textArray: text('text_array').array(), + varcharArray: varchar('varchar_array', { length: 256 }).array(), + charArray: char('char_array', { length: 256 }).array(), + numericArray: numeric('numeric_array').array(), + decimalArray: decimal('decimal_array').array(), + realArray: real('real_array').array(), + doublePrecisionArray: doublePrecision('double_precision_array').array(), + jsonArray: json('json_array').array(), + jsonbArray: jsonb('jsonb_array').array(), + timeArray: time('time_array').array(), + timestampDateArray: timestamp('timestamp_date_array', { mode: 'date' }).array(), + timestampStringArray: timestamp('timestamp_string_array', { mode: 'string' }).array(), + dateStringArray: date('date_string_array', { mode: 'string' }).array(), + dateArray: date('date_array', { mode: 'date' }).array(), + intervalArray: interval('interval_array').array(), + pointArray: point('point_array', { mode: 'xy' }).array(), + pointTupleArray: point('point_tuple_array', { mode: 'tuple' }).array(), + lineArray: line('line_array', { mode: 'abc' }).array(), + lineTupleArray: line('line_tuple_array', { mode: 'tuple' }).array(), + moodEnumArray: moodEnum('mood_enum_array').array(), +}); + +export const ndArrays = schema.table('nd_arrays', { + integer1DArray: integer('integer_1d_array').array(3), + integer2DArray: integer('integer_2d_array').array(3).array(4), + integer3DArray: integer('integer_3d_array').array(3).array(4).array(5), + integer4DArray: integer('integer_4d_array').array(3).array(4).array(5).array(6), +}); diff --git a/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts b/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts index b876915b2..36aa8d194 100644 --- a/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts +++ b/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts @@ -14,7 +14,7 @@ beforeAll(async () => { db = drizzle(client); - await db.execute(sql`CREATE SCHEMA "seeder_lib_pg";`); + await db.execute(sql`CREATE SCHEMA if not exists "seeder_lib_pg";`); await db.execute( sql` @@ -33,10 +33,10 @@ beforeAll(async () => { "smallint" smallint, "bigint" bigint, "bigint_number" bigint, - "serial" serial NOT NULL, - "smallserial" "smallserial" NOT NULL, + "serial" serial, + "smallserial" smallserial, "bigserial" bigserial, - "bigserial_number" bigserial NOT NULL, + "bigserial_number" bigserial, "boolean" boolean, "text" text, "varchar" varchar(256), @@ -61,6 +61,49 @@ beforeAll(async () => { ); `, ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."all_array_data_types" ( + "integer_array" integer[], + "smallint_array" smallint[], + "bigint_array" bigint[], + "bigint_number_array" bigint[], + "boolean_array" boolean[], + "text_array" text[], + "varchar_array" varchar(256)[], + "char_array" char(256)[], + "numeric_array" numeric[], + "decimal_array" numeric[], + "real_array" real[], + "double_precision_array" double precision[], + "json_array" json[], + "jsonb_array" jsonb[], + "time_array" time[], + "timestamp_date_array" timestamp[], + "timestamp_string_array" timestamp[], + "date_string_array" date[], + "date_array" date[], + "interval_array" interval[], + "point_array" "point"[], + "point_tuple_array" "point"[], + "line_array" "line"[], + "line_tuple_array" "line"[], + "mood_enum_array" "seeder_lib_pg"."mood_enum"[] + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."nd_arrays" ( + "integer_1d_array" integer[3], + "integer_2d_array" integer[3][4], + "integer_3d_array" integer[3][4][5], + "integer_4d_array" integer[3][4][5][6] + ); + `, + ); }); afterAll(async () => { @@ -68,11 +111,48 @@ afterAll(async () => { }); test('all data types test', async () => { - await seed(db, schema, { count: 10000 }); + await seed(db, { allDataTypes: schema.allDataTypes }, { count: 10000 }); const allDataTypes = await db.select().from(schema.allDataTypes); - // every value in each 10 rows does not equal undefined. + // every value in each rows does not equal undefined. const predicate = allDataTypes.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); expect(predicate).toBe(true); }); + +test('all array data types test', async () => { + await seed(db, { allArrayDataTypes: schema.allArrayDataTypes }, { count: 1000 }); + + const allArrayDataTypes = await db.select().from(schema.allArrayDataTypes); + // every value in each rows does not equal undefined. + const predicate = allArrayDataTypes.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && val.length === 10) + ); + + expect(predicate).toBe(true); +}); + +test('nd arrays', async () => { + await seed(db, { ndArrays: schema.ndArrays }, { count: 1000 }); + + const ndArrays = await db.select().from(schema.ndArrays); + // every value in each rows does not equal undefined. + const predicate0 = ndArrays.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && val.length !== 0) + ); + let predicate1 = true, predicate2 = true, predicate3 = true, predicate4 = true; + + for (const row of ndArrays) { + predicate1 = predicate1 && (row.integer1DArray?.length === 3); + + predicate2 = predicate2 && (row.integer2DArray?.length === 4) && (row.integer2DArray[0]?.length === 3); + + predicate3 = predicate3 && (row.integer3DArray?.length === 5) && (row.integer3DArray[0]?.length === 4) + && (row.integer3DArray[0][0]?.length === 3); + + predicate4 = predicate4 && (row.integer4DArray?.length === 6) && (row.integer4DArray[0]?.length === 5) + && (row.integer4DArray[0][0]?.length === 4) && (row.integer4DArray[0][0][0]?.length === 3); + } + + expect(predicate0 && predicate1 && predicate2 && predicate3 && predicate4).toBe(true); +}); diff --git a/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts b/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts index 575b7a69a..0783ea877 100644 --- a/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts +++ b/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts @@ -33,6 +33,22 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."default_table" ( + "default_string" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."default_array_table" ( + "default_string" text[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."boolean_table" ( @@ -41,6 +57,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."boolean_array_table" ( + "boolean" boolean[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_table" ( @@ -58,6 +82,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_array_table" ( + "city" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_table" ( @@ -75,6 +107,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_array_table" ( + "company_name" text[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_table" ( @@ -92,6 +132,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_array_table" ( + "country" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."date_table" ( @@ -102,8 +150,9 @@ beforeAll(async () => { await db.execute( sql` - CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."default_table" ( - "default_string" text + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."date_array_table" ( + "date" date[], + "date_string" date[] ); `, ); @@ -117,6 +166,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."email_array_table" ( + "email" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."enum_table" ( @@ -142,6 +199,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."first_name_array_table" ( + "first_name" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name__table" ( @@ -159,6 +224,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name_array_table" ( + "full_name" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_primary_key_table" ( @@ -185,6 +258,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_array_table" ( + "int" integer[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_table" ( @@ -202,6 +283,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_array_table" ( + "interval" interval[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."job_Title_table" ( @@ -210,6 +299,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."job_title_array_table" ( + "job_title" text[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."json_table" ( @@ -218,6 +315,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."json_array_table" ( + "json" json[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_table" ( @@ -235,6 +340,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_array_table" ( + "last_name" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."line_table" ( @@ -243,6 +356,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."line_array_table" ( + "line" "line"[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."lorem_ipsum_table" ( @@ -251,6 +372,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."lorem_ipsum_array_table" ( + "lorem_ipsum" text[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_table" ( @@ -268,6 +397,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_array_table" ( + "number" real[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."phone_number_table" ( @@ -281,6 +418,16 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."phone_number_array_table" ( + "phoneNumber" varchar(256)[], + "phone_number_template" varchar(256)[], + "phone_number_prefixes" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."point_table" ( @@ -289,6 +436,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."point_array_table" ( + "point" "point"[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_table" ( @@ -306,6 +461,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_array_table" ( + "postcode" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."state_table" ( @@ -314,6 +477,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."state_array_table" ( + "state" text[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_table" ( @@ -331,6 +502,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_array_table" ( + "street_address" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_table" ( @@ -348,6 +527,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_array_table" ( + "string" text[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."time_table" ( @@ -356,6 +543,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."time_array_table" ( + "time" time[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."timestamp_table" ( @@ -364,6 +559,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."timestamp_array_table" ( + "timestamp" timestamp[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_table" ( @@ -388,6 +591,14 @@ beforeAll(async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_array_table" ( + "values_from_array" varchar(256) + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."weighted_random_table" ( @@ -410,7 +621,7 @@ afterAll(async () => { await client.close(); }); -const count = 10000; +const count = 1000; test('enum generator test', async () => { await seed(db, { enumTable: schema.enumTable }).refine(() => ({ @@ -443,6 +654,23 @@ test('default generator test', async () => { expect(predicate).toBe(true); }); +test('default array generator test', async () => { + await seed(db, { defaultTable: schema.defaultArrayTable }).refine((funcs) => ({ + defaultTable: { + count, + columns: { + defaultString: funcs.default({ defaultValue: 'default string', arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.defaultArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('valuesFromArray generator test', async () => { await seed(db, { valuesFromArrayTable: schema.valuesFromArrayTable }).refine((funcs) => ({ valuesFromArrayTable: { @@ -555,6 +783,23 @@ test('valuesFromArray unique generator test', async () => { ).rejects.toThrow('There are no enough values to fill unique column.'); }); +test('valuesFromArray array generator test', async () => { + await seed(db, { valuesFromArrayTable: schema.valuesFromArrayArrayTable }).refine((funcs) => ({ + valuesFromArrayTable: { + count, + columns: { + valuesFromArray: funcs.valuesFromArray({ values: lastNames, arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.valuesFromArrayArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('intPrimaryKey generator test', async () => { await seed(db, { intPrimaryKeyTable: schema.intPrimaryKeyTable }).refine((funcs) => ({ intPrimaryKeyTable: { @@ -619,6 +864,23 @@ test('number unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); }); +test('number array generator test', async () => { + await seed(db, { numberTable: schema.numberArrayTable }).refine((funcs) => ({ + numberTable: { + count, + columns: { + number: funcs.number({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.numberArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('int generator test', async () => { await seed(db, { intTable: schema.intTable }).refine((funcs) => ({ intTable: { @@ -664,6 +926,23 @@ test('int unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); }); +test('int array generator test', async () => { + await seed(db, { intTable: schema.intArrayTable }).refine((funcs) => ({ + intTable: { + count, + columns: { + int: funcs.int({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.intArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('boolean generator test', async () => { await seed(db, { booleanTable: schema.booleanTable }).refine((funcs) => ({ booleanTable: { @@ -681,6 +960,23 @@ test('boolean generator test', async () => { expect(predicate).toBe(true); }); +test('boolean array generator test', async () => { + await seed(db, { booleanTable: schema.booleanArrayTable }).refine((funcs) => ({ + booleanTable: { + count, + columns: { + boolean: funcs.boolean({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.booleanArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('date generator test', async () => { await seed(db, { dateTable: schema.dateTable }).refine((funcs) => ({ dateTable: { @@ -698,6 +994,26 @@ test('date generator test', async () => { expect(predicate).toBe(true); }); +test('date array generator test', async () => { + await seed(db, { dateTable: schema.dateArrayTable }).refine((funcs) => ({ + dateTable: { + count, + columns: { + date: funcs.date({ arraySize: 3 }), + dateString: funcs.date({ arraySize: 4 }), + }, + }, + })); + + const data = await db.select().from(schema.dateArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && [3, 4].includes(val.length)) + ); + expect(predicate).toBe(true); +}); + test('time generator test', async () => { await seed(db, { timeTable: schema.timeTable }).refine((funcs) => ({ timeTable: { @@ -715,6 +1031,23 @@ test('time generator test', async () => { expect(predicate).toBe(true); }); +test('time array generator test', async () => { + await seed(db, { timeTable: schema.timeArrayTable }).refine((funcs) => ({ + timeTable: { + count, + columns: { + time: funcs.time({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.timeArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('timestamp generator test', async () => { await seed(db, { timestampTable: schema.timestampTable }).refine((funcs) => ({ timestampTable: { @@ -732,6 +1065,23 @@ test('timestamp generator test', async () => { expect(predicate).toBe(true); }); +test('timestamp array generator test', async () => { + await seed(db, { timestampTable: schema.timestampArrayTable }).refine((funcs) => ({ + timestampTable: { + count, + columns: { + timestamp: funcs.timestamp({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.timestampArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('json generator test', async () => { await seed(db, { jsonTable: schema.jsonTable }).refine((funcs) => ({ jsonTable: { @@ -749,6 +1099,23 @@ test('json generator test', async () => { expect(predicate).toBe(true); }); +test('json array generator test', async () => { + await seed(db, { jsonTable: schema.jsonArrayTable }).refine((funcs) => ({ + jsonTable: { + count, + columns: { + json: funcs.json({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.jsonArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('interval generator test', async () => { await seed(db, { intervalTable: schema.intervalTable }).refine((funcs) => ({ intervalTable: { @@ -783,6 +1150,23 @@ test('interval unique generator test', async () => { expect(predicate).toBe(true); }); +test('interval array generator test', async () => { + await seed(db, { intervalTable: schema.intervalArrayTable }).refine((funcs) => ({ + intervalTable: { + count, + columns: { + interval: funcs.interval({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.intervalArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('string generator test', async () => { await seed(db, { stringTable: schema.stringTable }).refine((funcs) => ({ stringTable: { @@ -816,6 +1200,23 @@ test('string unique generator test', async () => { expect(predicate).toBe(true); }); +test('string array generator test', async () => { + await seed(db, { stringTable: schema.stringArrayTable }).refine((funcs) => ({ + stringTable: { + count, + columns: { + string: funcs.string({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.stringArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('email generator test', async () => { await seed(db, { emailTable: schema.emailTable }).refine((funcs) => ({ emailTable: { @@ -833,6 +1234,23 @@ test('email generator test', async () => { expect(predicate).toBe(true); }); +test('email array generator test', async () => { + await seed(db, { emailTable: schema.emailArrayTable }).refine((funcs) => ({ + emailTable: { + count, + columns: { + email: funcs.email({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.emailArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('firstName generator test', async () => { await seed(db, { firstNameTable: schema.firstNameTable }).refine((funcs) => ({ firstNameTable: { @@ -878,6 +1296,23 @@ test('firstName unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique first names.'); }); +test('firstName array generator test', async () => { + await seed(db, { firstNameTable: schema.firstNameArrayTable }).refine((funcs) => ({ + firstNameTable: { + count, + columns: { + firstName: funcs.firstName({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.firstNameArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('lastName generator test', async () => { await seed(db, { lastNameTable: schema.lastNameTable }).refine((funcs) => ({ lastNameTable: { @@ -923,6 +1358,23 @@ test('lastName unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique last names.'); }); +test('lastName array generator test', async () => { + await seed(db, { lastNameTable: schema.lastNameArrayTable }).refine((funcs) => ({ + lastNameTable: { + count, + columns: { + lastName: funcs.lastName({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.lastNameArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('fullName generator test', async () => { await seed(db, { fullNameTable: schema.fullNameTable }).refine((funcs) => ({ fullNameTable: { @@ -958,6 +1410,23 @@ test('fullName unique generator test', async () => { expect(predicate).toBe(true); }); +test('fullName array generator test', async () => { + await seed(db, { fullNameTable: schema.fullNameArrayTable }).refine((funcs) => ({ + fullNameTable: { + count, + columns: { + fullName: funcs.fullName({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.fullNameArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('country generator test', async () => { await seed(db, { countryTable: schema.countryTable }).refine((funcs) => ({ countryTable: { @@ -1003,6 +1472,23 @@ test('country unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique countries.'); }); +test('country array generator test', async () => { + await seed(db, { countryTable: schema.countryArrayTable }).refine((funcs) => ({ + countryTable: { + count, + columns: { + country: funcs.country({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.countryArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('city generator test', async () => { await seed(db, { cityTable: schema.cityTable }).refine((funcs) => ({ cityTable: { @@ -1049,6 +1535,23 @@ test('city unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique cities.'); }); +test('city array generator test', async () => { + await seed(db, { cityTable: schema.cityArrayTable }).refine((funcs) => ({ + cityTable: { + count, + columns: { + city: funcs.city({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.cityArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('streetAddress generator test', async () => { await seed(db, { streetAddressTable: schema.streetAddressTable }).refine((funcs) => ({ streetAddressTable: { @@ -1083,6 +1586,23 @@ test('streetAddress unique generator test', async () => { expect(predicate).toBe(true); }); +test('streetAddress array generator test', async () => { + await seed(db, { streetAddressTable: schema.streetAddressArrayTable }).refine((funcs) => ({ + streetAddressTable: { + count, + columns: { + streetAddress: funcs.streetAddress({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.streetAddressArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('jobTitle generator test', async () => { await seed(db, { jobTitleTable: schema.jobTitleTable }).refine((funcs) => ({ jobTitleTable: { @@ -1100,6 +1620,23 @@ test('jobTitle generator test', async () => { expect(predicate).toBe(true); }); +test('jobTitle array generator test', async () => { + await seed(db, { jobTitleTable: schema.jobTitleArrayTable }).refine((funcs) => ({ + jobTitleTable: { + count, + columns: { + jobTitle: funcs.jobTitle({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.jobTitleArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('postcode generator test', async () => { await seed(db, { postcodeTable: schema.postcodeTable }).refine((funcs) => ({ postcodeTable: { @@ -1134,6 +1671,23 @@ test('postcode unique generator test', async () => { expect(predicate).toBe(true); }); +test('postcode array generator test', async () => { + await seed(db, { postcodeTable: schema.postcodeArrayTable }).refine((funcs) => ({ + postcodeTable: { + count, + columns: { + postcode: funcs.postcode({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.postcodeArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('state generator test', async () => { await seed(db, { stateTable: schema.stateTable }).refine((funcs) => ({ stateTable: { @@ -1151,6 +1705,23 @@ test('state generator test', async () => { expect(predicate).toBe(true); }); +test('state array generator test', async () => { + await seed(db, { stateTable: schema.stateArrayTable }).refine((funcs) => ({ + stateTable: { + count, + columns: { + state: funcs.state({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.stateArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('companyName generator test', async () => { await seed(db, { companyNameTable: schema.companyNameTable }).refine((funcs) => ({ companyNameTable: { @@ -1185,6 +1756,23 @@ test('companyName unique generator test', async () => { expect(predicate).toBe(true); }); +test('companyName array generator test', async () => { + await seed(db, { companyNameTable: schema.companyNameArrayTable }).refine((funcs) => ({ + companyNameTable: { + count, + columns: { + companyName: funcs.companyName({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.companyNameArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('loremIpsum generator test', async () => { await seed(db, { loremIpsumTable: schema.loremIpsumTable }).refine((funcs) => ({ loremIpsumTable: { @@ -1202,6 +1790,23 @@ test('loremIpsum generator test', async () => { expect(predicate).toBe(true); }); +test('loremIpsum array generator test', async () => { + await seed(db, { loremIpsumTable: schema.loremIpsumArrayTable }).refine((funcs) => ({ + loremIpsumTable: { + count, + columns: { + loremIpsum: funcs.loremIpsum({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.loremIpsumArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('point generator test', async () => { await seed(db, { pointTable: schema.pointTable }).refine((funcs) => ({ pointTable: { @@ -1242,6 +1847,23 @@ test('point unique generator test', async () => { expect(predicate).toBe(true); }); +test('point array generator test', async () => { + await seed(db, { pointTable: schema.pointArrayTable }).refine((funcs) => ({ + pointTable: { + count, + columns: { + point: funcs.point({ arraySize: 2 }), + }, + }, + })); + + const data = await db.select().from(schema.pointArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 2)); + expect(predicate).toBe(true); +}); + test('line generator test', async () => { await seed(db, { lineTable: schema.lineTable }).refine((funcs) => ({ lineTable: { @@ -1282,6 +1904,23 @@ test('line unique generator test', async () => { expect(predicate).toBe(true); }); +test('line array generator test', async () => { + await seed(db, { lineTable: schema.lineArrayTable }).refine((funcs) => ({ + lineTable: { + count, + columns: { + line: funcs.line({ arraySize: 2 }), + }, + }, + })); + + const data = await db.select().from(schema.lineArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 2)); + expect(predicate).toBe(true); +}); + test('phoneNumber generator test', async () => { await seed(db, { phoneNumberTable: schema.phoneNumberTable }).refine((funcs) => ({ phoneNumberTable: { @@ -1304,6 +1943,34 @@ test('phoneNumber generator test', async () => { expect(predicate).toBe(true); }); +test('phoneNumber array generator test', async () => { + await seed(db, { phoneNumberTable: schema.phoneNumberArrayTable }).refine((funcs) => ({ + phoneNumberTable: { + count, + columns: { + phoneNumber: funcs.phoneNumber({ arraySize: 3 }), + phoneNumberPrefixes: funcs.phoneNumber({ + prefixes: ['+380 99', '+380 67', '+1'], + generatedDigitsNumbers: [7, 7, 10], + arraySize: 4, + }), + phoneNumberTemplate: funcs.phoneNumber({ + template: '+380 ## ## ### ##', + arraySize: 5, + }), + }, + }, + })); + + const data = await db.select().from(schema.phoneNumberArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && [3, 4, 5].includes(val.length)) + ); + expect(predicate).toBe(true); +}); + test('weightedRandom generator test', async () => { await seed(db, { weightedRandomTable: schema.weightedRandomTable }).refine((funcs) => ({ weightedRandomTable: { diff --git a/drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts b/drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts index 57f585297..bf6ee4e5f 100644 --- a/drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts +++ b/drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts @@ -26,6 +26,10 @@ export const defaultTable = schema.table('default_table', { defaultString: text('default_string'), }); +export const defaultArrayTable = schema.table('default_array_table', { + defaultString: text('default_string').array(), +}); + export const valuesFromArrayTable = schema.table('values_from_array_table', { valuesFromArrayNotNull: varchar('values_from_array_not_null', { length: 256 }).notNull(), valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).notNull(), @@ -38,6 +42,10 @@ export const valuesFromArrayUniqueTable = schema.table('values_from_array_unique valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).unique().notNull(), }); +export const valuesFromArrayArrayTable = schema.table('values_from_array_array_table', { + valuesFromArray: varchar('values_from_array', { length: 256 }).array(), +}); + export const intPrimaryKeyTable = schema.table('int_primary_key_table', { intPrimaryKey: integer('int_primary_key').unique(), }); @@ -50,6 +58,10 @@ export const numberUniqueTable = schema.table('number_unique_table', { numberUnique: real('number_unique').unique(), }); +export const numberArrayTable = schema.table('number_array_table', { + number: real('number').array(), +}); + export const intTable = schema.table('int_table', { int: integer('int'), }); @@ -58,26 +70,52 @@ export const intUniqueTable = schema.table('int_unique_table', { intUnique: integer('int_unique').unique(), }); +export const intArrayTable = schema.table('int_array_table', { + int: integer('int').array(), +}); + export const booleanTable = schema.table('boolean_table', { boolean: boolean('boolean'), }); +export const booleanArrayTable = schema.table('boolean_array_table', { + boolean: boolean('boolean').array(), +}); + export const dateTable = schema.table('date_table', { date: date('date'), }); +// TODO: add tests for data type with different modes +export const dateArrayTable = schema.table('date_array_table', { + date: date('date', { mode: 'date' }).array(), + dateString: date('date_string', { mode: 'string' }).array(), +}); + export const timeTable = schema.table('time_table', { time: time('time'), }); +export const timeArrayTable = schema.table('time_array_table', { + time: time('time').array(), +}); + export const timestampTable = schema.table('timestamp_table', { timestamp: timestamp('timestamp'), }); +export const timestampArrayTable = schema.table('timestamp_array_table', { + timestamp: timestamp('timestamp').array(), +}); + export const jsonTable = schema.table('json_table', { json: json('json'), }); +export const jsonArrayTable = schema.table('json_array_table', { + json: json('json').array(), +}); + export const intervalTable = schema.table('interval_table', { interval: interval('interval'), }); @@ -86,6 +124,10 @@ export const intervalUniqueTable = schema.table('interval_unique_table', { intervalUnique: interval('interval_unique').unique(), }); +export const intervalArrayTable = schema.table('interval_array_table', { + interval: interval('interval').array(), +}); + export const stringTable = schema.table('string_table', { string: text('string'), }); @@ -94,10 +136,18 @@ export const stringUniqueTable = schema.table('string_unique_table', { stringUnique: varchar('string_unique', { length: 256 }).unique(), }); +export const stringArrayTable = schema.table('string_array_table', { + string: text('string').array(), +}); + export const emailTable = schema.table('email_table', { email: varchar('email', { length: 256 }).unique(), }); +export const emailArrayTable = schema.table('email_array_table', { + email: varchar('email', { length: 256 }).array(), +}); + export const firstNameTable = schema.table('first_name_table', { firstName: varchar('first_name', { length: 256 }), }); @@ -106,6 +156,10 @@ export const firstNameUniqueTable = schema.table('first_name_unique_table', { firstNameUnique: varchar('first_name_unique', { length: 256 }).unique(), }); +export const firstNameArrayTable = schema.table('first_name_array_table', { + firstName: varchar('first_name', { length: 256 }).array(), +}); + export const lastNameTable = schema.table('last_name_table', { lastName: varchar('last_name', { length: 256 }), }); @@ -114,6 +168,10 @@ export const lastNameUniqueTable = schema.table('last_name_unique_table', { lastNameUnique: varchar('last_name_unique', { length: 256 }).unique(), }); +export const lastNameArrayTable = schema.table('last_name_array_table', { + lastName: varchar('last_name', { length: 256 }).array(), +}); + export const fullNameTable = schema.table('full_name__table', { fullName: varchar('full_name_', { length: 256 }), }); @@ -122,6 +180,10 @@ export const fullNameUniqueTable = schema.table('full_name_unique_table', { fullNameUnique: varchar('full_name_unique', { length: 256 }).unique(), }); +export const fullNameArrayTable = schema.table('full_name_array_table', { + fullName: varchar('full_name', { length: 256 }).array(), +}); + export const countryTable = schema.table('country_table', { country: varchar('country', { length: 256 }), }); @@ -130,6 +192,10 @@ export const countryUniqueTable = schema.table('country_unique_table', { countryUnique: varchar('country_unique', { length: 256 }).unique(), }); +export const countryArrayTable = schema.table('country_array_table', { + country: varchar('country', { length: 256 }).array(), +}); + export const cityTable = schema.table('city_table', { city: varchar('city', { length: 256 }), }); @@ -138,6 +204,10 @@ export const cityUniqueTable = schema.table('city_unique_table', { cityUnique: varchar('city_unique', { length: 256 }).unique(), }); +export const cityArrayTable = schema.table('city_array_table', { + city: varchar('city', { length: 256 }).array(), +}); + export const streetAddressTable = schema.table('street_address_table', { streetAddress: varchar('street_address', { length: 256 }), }); @@ -146,10 +216,18 @@ export const streetAddressUniqueTable = schema.table('street_address_unique_tabl streetAddressUnique: varchar('street_address_unique', { length: 256 }).unique(), }); +export const streetAddressArrayTable = schema.table('street_address_array_table', { + streetAddress: varchar('street_address', { length: 256 }).array(), +}); + export const jobTitleTable = schema.table('job_Title_table', { jobTitle: text('job_title'), }); +export const jobTitleArrayTable = schema.table('job_title_array_table', { + jobTitle: text('job_title').array(), +}); + export const postcodeTable = schema.table('postcode_table', { postcode: varchar('postcode', { length: 256 }), }); @@ -158,10 +236,18 @@ export const postcodeUniqueTable = schema.table('postcode_unique_table', { postcodeUnique: varchar('postcode_unique', { length: 256 }).unique(), }); +export const postcodeArrayTable = schema.table('postcode_array_table', { + postcode: varchar('postcode', { length: 256 }).array(), +}); + export const stateTable = schema.table('state_table', { state: text('state'), }); +export const stateArrayTable = schema.table('state_array_table', { + state: text('state').array(), +}); + export const companyNameTable = schema.table('company_name_table', { companyName: text('company_name'), }); @@ -170,18 +256,34 @@ export const companyNameUniqueTable = schema.table('company_name_unique_table', companyNameUnique: varchar('company_name_unique', { length: 256 }).unique(), }); +export const companyNameArrayTable = schema.table('company_name_array_table', { + companyName: text('company_name').array(), +}); + export const loremIpsumTable = schema.table('lorem_ipsum_table', { loremIpsum: text('lorem_ipsum'), }); +export const loremIpsumArrayTable = schema.table('lorem_ipsum_array_table', { + loremIpsum: text('lorem_ipsum').array(), +}); + export const pointTable = schema.table('point_table', { point: point('point'), }); +export const pointArrayTable = schema.table('point_array_table', { + point: point('point').array(), +}); + export const lineTable = schema.table('line_table', { line: line('line'), }); +export const lineArrayTable = schema.table('line_array_table', { + line: line('line').array(), +}); + // export const pointUniqueTable = schema.table("point_unique_table", { // pointUnique: point("point_unique").unique(), // }); @@ -196,6 +298,12 @@ export const phoneNumberTable = schema.table('phone_number_table', { phoneNumberPrefixes: varchar('phone_number_prefixes', { length: 256 }).unique(), }); +export const phoneNumberArrayTable = schema.table('phone_number_array_table', { + phoneNumber: varchar('phoneNumber', { length: 256 }).array(), + phoneNumberTemplate: varchar('phone_number_template', { length: 256 }).array(), + phoneNumberPrefixes: varchar('phone_number_prefixes', { length: 256 }).array(), +}); + export const weightedRandomTable = schema.table('weighted_random_table', { weightedRandom: varchar('weighted_random', { length: 256 }), }); diff --git a/drizzle-seed/src/types/tables.ts b/drizzle-seed/src/types/tables.ts index 7e472cf2b..b1d601ca5 100644 --- a/drizzle-seed/src/types/tables.ts +++ b/drizzle-seed/src/types/tables.ts @@ -11,17 +11,7 @@ export type Column = { isUnique: boolean; notNull: boolean; generatedIdentityType?: 'always' | 'byDefault' | undefined; - baseColumn?: { - name: string; - dataType: string; - columnType: string; - size?: number; - default?: any; - hasDefault: boolean; - isUnique: boolean; - notNull: boolean; - baseColumn?: Column['baseColumn']; - }; + baseColumn?: Omit; }; export type Table = { diff --git a/drizzle-seed/tsconfig.json b/drizzle-seed/tsconfig.json index c75766c3f..2cb1cadf9 100644 --- a/drizzle-seed/tsconfig.json +++ b/drizzle-seed/tsconfig.json @@ -43,6 +43,6 @@ "~/*": ["src/*"] } }, - "exclude": ["**/dist"], + "exclude": ["**/dist", "src/schemaTest.ts", "src/test.ts"], "include": ["src", "*.ts"] } From 5f51774b686acc098d5c5f1d86237158e8b208b5 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Thu, 28 Nov 2024 17:25:17 +0200 Subject: [PATCH 402/492] fix --- drizzle-seed/package.json | 4 ++-- .../{src => }/tests/benchmarks/generatorsBenchmark.ts | 4 ++-- .../tests/mysql/allDataTypesTest/drizzle.config.ts | 0 .../tests/mysql/allDataTypesTest/mysqlSchema.ts | 0 .../allDataTypesTest/mysql_all_data_types.test.ts | 2 +- drizzle-seed/{src => }/tests/mysql/drizzle.config.ts | 0 .../tests/mysql/generatorsTest/drizzle.config.ts | 0 .../tests/mysql/generatorsTest/generators.test.ts | 2 +- .../tests/mysql/generatorsTest/mysqlSchema.ts | 0 drizzle-seed/{src => }/tests/mysql/mysql.test.ts | 2 +- drizzle-seed/{src => }/tests/mysql/mysqlSchema.ts | 0 drizzle-seed/{src => }/tests/northwind/mysqlSchema.ts | 0 drizzle-seed/{src => }/tests/northwind/mysqlTest.ts | 2 +- drizzle-seed/{src => }/tests/northwind/pgSchema.ts | 0 drizzle-seed/{src => }/tests/northwind/pgTest.ts | 2 +- drizzle-seed/{src => }/tests/northwind/sqliteSchema.ts | 0 drizzle-seed/{src => }/tests/northwind/sqliteTest.ts | 2 +- .../tests/pg/allDataTypesTest/drizzle.config.ts | 0 .../{src => }/tests/pg/allDataTypesTest/pgSchema.ts | 0 .../pg/allDataTypesTest/pg_all_data_types.test.ts | 2 +- drizzle-seed/{src => }/tests/pg/drizzle.config.ts | 0 .../tests/pg/generatorsTest/drizzle.config.ts | 0 .../tests/pg/generatorsTest/generators.test.ts | 10 +++++----- .../{src => }/tests/pg/generatorsTest/pgSchema.ts | 0 drizzle-seed/{src => }/tests/pg/pg.test.ts | 2 +- drizzle-seed/{src => }/tests/pg/pgSchema.ts | 0 .../tests/sqlite/allDataTypesTest/sqliteSchema.ts | 0 .../allDataTypesTest/sqlite_all_data_types.test.ts | 2 +- drizzle-seed/{src => }/tests/sqlite/sqlite.test.ts | 2 +- drizzle-seed/{src => }/tests/sqlite/sqliteSchema.ts | 0 drizzle-seed/tsconfig.json | 2 +- drizzle-seed/{src => }/type-tests/mysql.ts | 2 +- drizzle-seed/{src => }/type-tests/pg.ts | 2 +- drizzle-seed/{src => }/type-tests/sqlite.ts | 2 +- drizzle-seed/{src => }/type-tests/tsconfig.json | 2 +- drizzle-seed/{src/tests => }/vitest.config.ts | 6 +++--- 36 files changed, 27 insertions(+), 27 deletions(-) rename drizzle-seed/{src => }/tests/benchmarks/generatorsBenchmark.ts (97%) rename drizzle-seed/{src => }/tests/mysql/allDataTypesTest/drizzle.config.ts (100%) rename drizzle-seed/{src => }/tests/mysql/allDataTypesTest/mysqlSchema.ts (100%) rename drizzle-seed/{src => }/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts (98%) rename drizzle-seed/{src => }/tests/mysql/drizzle.config.ts (100%) rename drizzle-seed/{src => }/tests/mysql/generatorsTest/drizzle.config.ts (100%) rename drizzle-seed/{src => }/tests/mysql/generatorsTest/generators.test.ts (98%) rename drizzle-seed/{src => }/tests/mysql/generatorsTest/mysqlSchema.ts (100%) rename drizzle-seed/{src => }/tests/mysql/mysql.test.ts (99%) rename drizzle-seed/{src => }/tests/mysql/mysqlSchema.ts (100%) rename drizzle-seed/{src => }/tests/northwind/mysqlSchema.ts (100%) rename drizzle-seed/{src => }/tests/northwind/mysqlTest.ts (99%) rename drizzle-seed/{src => }/tests/northwind/pgSchema.ts (100%) rename drizzle-seed/{src => }/tests/northwind/pgTest.ts (99%) rename drizzle-seed/{src => }/tests/northwind/sqliteSchema.ts (100%) rename drizzle-seed/{src => }/tests/northwind/sqliteTest.ts (99%) rename drizzle-seed/{src => }/tests/pg/allDataTypesTest/drizzle.config.ts (100%) rename drizzle-seed/{src => }/tests/pg/allDataTypesTest/pgSchema.ts (100%) rename drizzle-seed/{src => }/tests/pg/allDataTypesTest/pg_all_data_types.test.ts (99%) rename drizzle-seed/{src => }/tests/pg/drizzle.config.ts (100%) rename drizzle-seed/{src => }/tests/pg/generatorsTest/drizzle.config.ts (100%) rename drizzle-seed/{src => }/tests/pg/generatorsTest/generators.test.ts (99%) rename drizzle-seed/{src => }/tests/pg/generatorsTest/pgSchema.ts (100%) rename drizzle-seed/{src => }/tests/pg/pg.test.ts (99%) rename drizzle-seed/{src => }/tests/pg/pgSchema.ts (100%) rename drizzle-seed/{src => }/tests/sqlite/allDataTypesTest/sqliteSchema.ts (100%) rename drizzle-seed/{src => }/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts (96%) rename drizzle-seed/{src => }/tests/sqlite/sqlite.test.ts (99%) rename drizzle-seed/{src => }/tests/sqlite/sqliteSchema.ts (100%) rename drizzle-seed/{src => }/type-tests/mysql.ts (91%) rename drizzle-seed/{src => }/type-tests/pg.ts (96%) rename drizzle-seed/{src => }/type-tests/sqlite.ts (91%) rename drizzle-seed/{src => }/type-tests/tsconfig.json (80%) rename drizzle-seed/{src/tests => }/vitest.config.ts (76%) diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index dbac30737..60403a004 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -6,8 +6,8 @@ "scripts": { "build": "tsx scripts/build.ts", "pack": "(cd dist && npm pack --pack-destination ..) && rm -f package.tgz && mv *.tgz package.tgz", - "test": "vitest --config ./src/tests/vitest.config.ts", - "test:types": "cd src/type-tests && tsc", + "test": "vitest --config ./vitest.config.ts", + "test:types": "cd type-tests && tsc", "generate-for-tests:pg": "drizzle-kit generate --config=./src/tests/pg/drizzle.config.ts", "generate-for-tests:mysql": "drizzle-kit generate --config=./src/tests/mysql/drizzle.config.ts", "generate-for-tests:sqlite": "drizzle-kit generate --config=./src/tests/sqlite/drizzle.config.ts", diff --git a/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts b/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts similarity index 97% rename from drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts rename to drizzle-seed/tests/benchmarks/generatorsBenchmark.ts index cfd275da0..9d79ebaa8 100644 --- a/drizzle-seed/src/tests/benchmarks/generatorsBenchmark.ts +++ b/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts @@ -1,4 +1,4 @@ -import lastNames from '../../datasets/lastNames.ts'; +import lastNames from '../../src/datasets/lastNames.ts'; import { GenerateBoolean, GenerateCity, @@ -40,7 +40,7 @@ import { GenerateValuesFromArray, GenerateYear, WeightedRandomGenerator, -} from '../../services/GeneratorsWrappers.ts'; +} from '../../src/services/GeneratorsWrappers.ts'; const benchmark = ({ generatorName, generator, count = 100000, seed = 1 }: { generatorName: string; diff --git a/drizzle-seed/src/tests/mysql/allDataTypesTest/drizzle.config.ts b/drizzle-seed/tests/mysql/allDataTypesTest/drizzle.config.ts similarity index 100% rename from drizzle-seed/src/tests/mysql/allDataTypesTest/drizzle.config.ts rename to drizzle-seed/tests/mysql/allDataTypesTest/drizzle.config.ts diff --git a/drizzle-seed/src/tests/mysql/allDataTypesTest/mysqlSchema.ts b/drizzle-seed/tests/mysql/allDataTypesTest/mysqlSchema.ts similarity index 100% rename from drizzle-seed/src/tests/mysql/allDataTypesTest/mysqlSchema.ts rename to drizzle-seed/tests/mysql/allDataTypesTest/mysqlSchema.ts diff --git a/drizzle-seed/src/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts b/drizzle-seed/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts similarity index 98% rename from drizzle-seed/src/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts rename to drizzle-seed/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts index dc663800e..5a9ba9908 100644 --- a/drizzle-seed/src/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts +++ b/drizzle-seed/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts @@ -7,7 +7,7 @@ import type { Connection } from 'mysql2/promise'; import { createConnection } from 'mysql2/promise'; import { v4 as uuid } from 'uuid'; import { afterAll, beforeAll, expect, test } from 'vitest'; -import { seed } from '../../../index.ts'; +import { seed } from '../../../src/index.ts'; import * as schema from './mysqlSchema.ts'; let mysqlContainer: Docker.Container; diff --git a/drizzle-seed/src/tests/mysql/drizzle.config.ts b/drizzle-seed/tests/mysql/drizzle.config.ts similarity index 100% rename from drizzle-seed/src/tests/mysql/drizzle.config.ts rename to drizzle-seed/tests/mysql/drizzle.config.ts diff --git a/drizzle-seed/src/tests/mysql/generatorsTest/drizzle.config.ts b/drizzle-seed/tests/mysql/generatorsTest/drizzle.config.ts similarity index 100% rename from drizzle-seed/src/tests/mysql/generatorsTest/drizzle.config.ts rename to drizzle-seed/tests/mysql/generatorsTest/drizzle.config.ts diff --git a/drizzle-seed/src/tests/mysql/generatorsTest/generators.test.ts b/drizzle-seed/tests/mysql/generatorsTest/generators.test.ts similarity index 98% rename from drizzle-seed/src/tests/mysql/generatorsTest/generators.test.ts rename to drizzle-seed/tests/mysql/generatorsTest/generators.test.ts index 223d5b54e..2bef885da 100644 --- a/drizzle-seed/src/tests/mysql/generatorsTest/generators.test.ts +++ b/drizzle-seed/tests/mysql/generatorsTest/generators.test.ts @@ -7,7 +7,7 @@ import type { Connection } from 'mysql2/promise'; import { createConnection } from 'mysql2/promise'; import { v4 as uuid } from 'uuid'; import { afterAll, beforeAll, expect, test } from 'vitest'; -import { seed } from '../../../index.ts'; +import { seed } from '../../../src/index.ts'; import * as schema from './mysqlSchema.ts'; let mysqlContainer: Docker.Container; diff --git a/drizzle-seed/src/tests/mysql/generatorsTest/mysqlSchema.ts b/drizzle-seed/tests/mysql/generatorsTest/mysqlSchema.ts similarity index 100% rename from drizzle-seed/src/tests/mysql/generatorsTest/mysqlSchema.ts rename to drizzle-seed/tests/mysql/generatorsTest/mysqlSchema.ts diff --git a/drizzle-seed/src/tests/mysql/mysql.test.ts b/drizzle-seed/tests/mysql/mysql.test.ts similarity index 99% rename from drizzle-seed/src/tests/mysql/mysql.test.ts rename to drizzle-seed/tests/mysql/mysql.test.ts index d1b6790ec..7d6bfd48e 100644 --- a/drizzle-seed/src/tests/mysql/mysql.test.ts +++ b/drizzle-seed/tests/mysql/mysql.test.ts @@ -7,7 +7,7 @@ import type { Connection } from 'mysql2/promise'; import { createConnection } from 'mysql2/promise'; import { v4 as uuid } from 'uuid'; import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; -import { reset, seed } from '../../index.ts'; +import { reset, seed } from '../../src/index.ts'; import * as schema from './mysqlSchema.ts'; let mysqlContainer: Docker.Container; diff --git a/drizzle-seed/src/tests/mysql/mysqlSchema.ts b/drizzle-seed/tests/mysql/mysqlSchema.ts similarity index 100% rename from drizzle-seed/src/tests/mysql/mysqlSchema.ts rename to drizzle-seed/tests/mysql/mysqlSchema.ts diff --git a/drizzle-seed/src/tests/northwind/mysqlSchema.ts b/drizzle-seed/tests/northwind/mysqlSchema.ts similarity index 100% rename from drizzle-seed/src/tests/northwind/mysqlSchema.ts rename to drizzle-seed/tests/northwind/mysqlSchema.ts diff --git a/drizzle-seed/src/tests/northwind/mysqlTest.ts b/drizzle-seed/tests/northwind/mysqlTest.ts similarity index 99% rename from drizzle-seed/src/tests/northwind/mysqlTest.ts rename to drizzle-seed/tests/northwind/mysqlTest.ts index 98c2dd742..1cbdb7704 100644 --- a/drizzle-seed/src/tests/northwind/mysqlTest.ts +++ b/drizzle-seed/tests/northwind/mysqlTest.ts @@ -7,7 +7,7 @@ import mysql from 'mysql2/promise'; import * as schema from './mysqlSchema.ts'; -import { seed } from '../../index.ts'; +import { seed } from '../../src/index.ts'; const { Mysql_HOST, Mysql_PORT, Mysql_DATABASE, Mysql_USER, Mysql_PASSWORD } = process.env; diff --git a/drizzle-seed/src/tests/northwind/pgSchema.ts b/drizzle-seed/tests/northwind/pgSchema.ts similarity index 100% rename from drizzle-seed/src/tests/northwind/pgSchema.ts rename to drizzle-seed/tests/northwind/pgSchema.ts diff --git a/drizzle-seed/src/tests/northwind/pgTest.ts b/drizzle-seed/tests/northwind/pgTest.ts similarity index 99% rename from drizzle-seed/src/tests/northwind/pgTest.ts rename to drizzle-seed/tests/northwind/pgTest.ts index 284f28957..84c366b6c 100644 --- a/drizzle-seed/src/tests/northwind/pgTest.ts +++ b/drizzle-seed/tests/northwind/pgTest.ts @@ -5,7 +5,7 @@ import { drizzle } from 'drizzle-orm/node-postgres'; import { migrate } from 'drizzle-orm/node-postgres/migrator'; import { Pool as PgPool } from 'pg'; -import { seed } from '../../index.ts'; +import { seed } from '../../src/index.ts'; import * as schema from './pgSchema.ts'; const { PG_HOST, PG_PORT, PG_DATABASE, PG_USER, PG_PASSWORD } = process.env; diff --git a/drizzle-seed/src/tests/northwind/sqliteSchema.ts b/drizzle-seed/tests/northwind/sqliteSchema.ts similarity index 100% rename from drizzle-seed/src/tests/northwind/sqliteSchema.ts rename to drizzle-seed/tests/northwind/sqliteSchema.ts diff --git a/drizzle-seed/src/tests/northwind/sqliteTest.ts b/drizzle-seed/tests/northwind/sqliteTest.ts similarity index 99% rename from drizzle-seed/src/tests/northwind/sqliteTest.ts rename to drizzle-seed/tests/northwind/sqliteTest.ts index d64f2c447..0267bc288 100644 --- a/drizzle-seed/src/tests/northwind/sqliteTest.ts +++ b/drizzle-seed/tests/northwind/sqliteTest.ts @@ -5,7 +5,7 @@ import betterSqlite3 from 'better-sqlite3'; import { drizzle } from 'drizzle-orm/better-sqlite3'; import { migrate } from 'drizzle-orm/better-sqlite3/migrator'; -import { seed } from '../../index.ts'; +import { seed } from '../../src/index.ts'; import * as schema from './sqliteSchema.ts'; const { Sqlite_PATH } = process.env; diff --git a/drizzle-seed/src/tests/pg/allDataTypesTest/drizzle.config.ts b/drizzle-seed/tests/pg/allDataTypesTest/drizzle.config.ts similarity index 100% rename from drizzle-seed/src/tests/pg/allDataTypesTest/drizzle.config.ts rename to drizzle-seed/tests/pg/allDataTypesTest/drizzle.config.ts diff --git a/drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts b/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts similarity index 100% rename from drizzle-seed/src/tests/pg/allDataTypesTest/pgSchema.ts rename to drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts diff --git a/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts b/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts similarity index 99% rename from drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts rename to drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts index 36aa8d194..c209107ae 100644 --- a/drizzle-seed/src/tests/pg/allDataTypesTest/pg_all_data_types.test.ts +++ b/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts @@ -3,7 +3,7 @@ import { sql } from 'drizzle-orm'; import type { PgliteDatabase } from 'drizzle-orm/pglite'; import { drizzle } from 'drizzle-orm/pglite'; import { afterAll, beforeAll, expect, test } from 'vitest'; -import { seed } from '../../../index.ts'; +import { seed } from '../../../src/index.ts'; import * as schema from './pgSchema.ts'; let client: PGlite; diff --git a/drizzle-seed/src/tests/pg/drizzle.config.ts b/drizzle-seed/tests/pg/drizzle.config.ts similarity index 100% rename from drizzle-seed/src/tests/pg/drizzle.config.ts rename to drizzle-seed/tests/pg/drizzle.config.ts diff --git a/drizzle-seed/src/tests/pg/generatorsTest/drizzle.config.ts b/drizzle-seed/tests/pg/generatorsTest/drizzle.config.ts similarity index 100% rename from drizzle-seed/src/tests/pg/generatorsTest/drizzle.config.ts rename to drizzle-seed/tests/pg/generatorsTest/drizzle.config.ts diff --git a/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts b/drizzle-seed/tests/pg/generatorsTest/generators.test.ts similarity index 99% rename from drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts rename to drizzle-seed/tests/pg/generatorsTest/generators.test.ts index 0783ea877..afeb4fcd5 100644 --- a/drizzle-seed/src/tests/pg/generatorsTest/generators.test.ts +++ b/drizzle-seed/tests/pg/generatorsTest/generators.test.ts @@ -4,14 +4,14 @@ import { PGlite } from '@electric-sql/pglite'; import type { PgliteDatabase } from 'drizzle-orm/pglite'; import { drizzle } from 'drizzle-orm/pglite'; -import { reset, seed } from '../../../index.ts'; +import { reset, seed } from '../../../src/index.ts'; import * as schema from './pgSchema.ts'; import { sql } from 'drizzle-orm'; -import cities from '../../../datasets/cityNames.ts'; -import countries from '../../../datasets/countries.ts'; -import firstNames from '../../../datasets/firstNames.ts'; -import lastNames from '../../../datasets/lastNames.ts'; +import cities from '../../../src/datasets/cityNames.ts'; +import countries from '../../../src/datasets/countries.ts'; +import firstNames from '../../../src/datasets/firstNames.ts'; +import lastNames from '../../../src/datasets/lastNames.ts'; let client: PGlite; let db: PgliteDatabase; diff --git a/drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts b/drizzle-seed/tests/pg/generatorsTest/pgSchema.ts similarity index 100% rename from drizzle-seed/src/tests/pg/generatorsTest/pgSchema.ts rename to drizzle-seed/tests/pg/generatorsTest/pgSchema.ts diff --git a/drizzle-seed/src/tests/pg/pg.test.ts b/drizzle-seed/tests/pg/pg.test.ts similarity index 99% rename from drizzle-seed/src/tests/pg/pg.test.ts rename to drizzle-seed/tests/pg/pg.test.ts index bd9ec7504..4a945f66d 100644 --- a/drizzle-seed/src/tests/pg/pg.test.ts +++ b/drizzle-seed/tests/pg/pg.test.ts @@ -3,7 +3,7 @@ import { sql } from 'drizzle-orm'; import type { PgliteDatabase } from 'drizzle-orm/pglite'; import { drizzle } from 'drizzle-orm/pglite'; import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; -import { reset, seed } from '../../index.ts'; +import { reset, seed } from '../../src/index.ts'; import * as schema from './pgSchema.ts'; let client: PGlite; diff --git a/drizzle-seed/src/tests/pg/pgSchema.ts b/drizzle-seed/tests/pg/pgSchema.ts similarity index 100% rename from drizzle-seed/src/tests/pg/pgSchema.ts rename to drizzle-seed/tests/pg/pgSchema.ts diff --git a/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqliteSchema.ts b/drizzle-seed/tests/sqlite/allDataTypesTest/sqliteSchema.ts similarity index 100% rename from drizzle-seed/src/tests/sqlite/allDataTypesTest/sqliteSchema.ts rename to drizzle-seed/tests/sqlite/allDataTypesTest/sqliteSchema.ts diff --git a/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts b/drizzle-seed/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts similarity index 96% rename from drizzle-seed/src/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts rename to drizzle-seed/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts index b377ba9a1..8282f921d 100644 --- a/drizzle-seed/src/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts +++ b/drizzle-seed/tests/sqlite/allDataTypesTest/sqlite_all_data_types.test.ts @@ -3,7 +3,7 @@ import { sql } from 'drizzle-orm'; import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; import { drizzle } from 'drizzle-orm/better-sqlite3'; import { afterAll, beforeAll, expect, test } from 'vitest'; -import { seed } from '../../../index.ts'; +import { seed } from '../../../src/index.ts'; import * as schema from './sqliteSchema.ts'; let client: BetterSqlite3.Database; diff --git a/drizzle-seed/src/tests/sqlite/sqlite.test.ts b/drizzle-seed/tests/sqlite/sqlite.test.ts similarity index 99% rename from drizzle-seed/src/tests/sqlite/sqlite.test.ts rename to drizzle-seed/tests/sqlite/sqlite.test.ts index 50db1fa8b..550648d49 100644 --- a/drizzle-seed/src/tests/sqlite/sqlite.test.ts +++ b/drizzle-seed/tests/sqlite/sqlite.test.ts @@ -3,7 +3,7 @@ import { sql } from 'drizzle-orm'; import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; import { drizzle } from 'drizzle-orm/better-sqlite3'; import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; -import { reset, seed } from '../../index.ts'; +import { reset, seed } from '../../src/index.ts'; import * as schema from './sqliteSchema.ts'; let client: BetterSqlite3.Database; diff --git a/drizzle-seed/src/tests/sqlite/sqliteSchema.ts b/drizzle-seed/tests/sqlite/sqliteSchema.ts similarity index 100% rename from drizzle-seed/src/tests/sqlite/sqliteSchema.ts rename to drizzle-seed/tests/sqlite/sqliteSchema.ts diff --git a/drizzle-seed/tsconfig.json b/drizzle-seed/tsconfig.json index 2cb1cadf9..222e6a4dd 100644 --- a/drizzle-seed/tsconfig.json +++ b/drizzle-seed/tsconfig.json @@ -44,5 +44,5 @@ } }, "exclude": ["**/dist", "src/schemaTest.ts", "src/test.ts"], - "include": ["src", "*.ts"] + "include": ["src", "*.ts", "tests"] } diff --git a/drizzle-seed/src/type-tests/mysql.ts b/drizzle-seed/type-tests/mysql.ts similarity index 91% rename from drizzle-seed/src/type-tests/mysql.ts rename to drizzle-seed/type-tests/mysql.ts index d1c0949b3..ffd42726d 100644 --- a/drizzle-seed/src/type-tests/mysql.ts +++ b/drizzle-seed/type-tests/mysql.ts @@ -1,7 +1,7 @@ import type { MySqlColumn } from 'drizzle-orm/mysql-core'; import { int, mysqlTable, text } from 'drizzle-orm/mysql-core'; import { drizzle as mysql2Drizzle } from 'drizzle-orm/mysql2'; -import { reset, seed } from '../index.ts'; +import { reset, seed } from '../src/index.ts'; const mysqlUsers = mysqlTable('users', { id: int().primaryKey().autoincrement(), diff --git a/drizzle-seed/src/type-tests/pg.ts b/drizzle-seed/type-tests/pg.ts similarity index 96% rename from drizzle-seed/src/type-tests/pg.ts rename to drizzle-seed/type-tests/pg.ts index 68faf844b..3bec9989f 100644 --- a/drizzle-seed/src/type-tests/pg.ts +++ b/drizzle-seed/type-tests/pg.ts @@ -3,7 +3,7 @@ import type { PgColumn } from 'drizzle-orm/pg-core'; import { integer, pgTable, text } from 'drizzle-orm/pg-core'; import { drizzle as pgliteDrizzle } from 'drizzle-orm/pglite'; import { drizzle as postgresJsDrizzle } from 'drizzle-orm/postgres-js'; -import { reset, seed } from '../index.ts'; +import { reset, seed } from '../src/index.ts'; const pgUsers = pgTable('users', { id: integer().primaryKey().generatedAlwaysAsIdentity(), diff --git a/drizzle-seed/src/type-tests/sqlite.ts b/drizzle-seed/type-tests/sqlite.ts similarity index 91% rename from drizzle-seed/src/type-tests/sqlite.ts rename to drizzle-seed/type-tests/sqlite.ts index 1b060e6a3..c9fa3d23b 100644 --- a/drizzle-seed/src/type-tests/sqlite.ts +++ b/drizzle-seed/type-tests/sqlite.ts @@ -1,7 +1,7 @@ import { drizzle as betterSqlite3Drizzle } from 'drizzle-orm/better-sqlite3'; import type { SQLiteColumn } from 'drizzle-orm/sqlite-core'; import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { reset, seed } from '../index.ts'; +import { reset, seed } from '../src/index.ts'; const mysqlUsers = sqliteTable('users', { id: int().primaryKey(), diff --git a/drizzle-seed/src/type-tests/tsconfig.json b/drizzle-seed/type-tests/tsconfig.json similarity index 80% rename from drizzle-seed/src/type-tests/tsconfig.json rename to drizzle-seed/type-tests/tsconfig.json index 09df8e1bb..b4e6c8007 100644 --- a/drizzle-seed/src/type-tests/tsconfig.json +++ b/drizzle-seed/type-tests/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.build.json", + "extends": "../tsconfig.build.json", "compilerOptions": { "composite": false, "noEmit": true, diff --git a/drizzle-seed/src/tests/vitest.config.ts b/drizzle-seed/vitest.config.ts similarity index 76% rename from drizzle-seed/src/tests/vitest.config.ts rename to drizzle-seed/vitest.config.ts index a74ccd37c..5489010bd 100644 --- a/drizzle-seed/src/tests/vitest.config.ts +++ b/drizzle-seed/vitest.config.ts @@ -3,9 +3,9 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { include: [ - './src/tests/pg/**/*.test.ts', - './src/tests/mysql/**/*.test.ts', - './src/tests/sqlite/**/*.test.ts', + './tests/pg/**/*.test.ts', + './tests/mysql/**/*.test.ts', + './tests/sqlite/**/*.test.ts', ], exclude: [], typecheck: { From a7371d94e7ce0d0c0c7a483c20d302b53e7f5a1c Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Fri, 29 Nov 2024 12:42:00 +0200 Subject: [PATCH 403/492] created sqlite durable objects driver added sqlite durable objects drivar to drizzle-kit created tests for orm --- drizzle-kit/src/cli/commands/utils.ts | 2 +- drizzle-kit/src/cli/validations/common.ts | 3 +- drizzle-kit/src/cli/validations/sqlite.ts | 27 +- drizzle-kit/src/index.ts | 4 + drizzle-orm/package.json | 4 +- drizzle-orm/src/durable-sqlite/driver.ts | 60 + drizzle-orm/src/durable-sqlite/index.ts | 2 + drizzle-orm/src/durable-sqlite/migrator.ts | 85 + drizzle-orm/src/durable-sqlite/session.ts | 181 + drizzle-orm/src/sqlite-core/columns/blob.ts | 30 +- drizzle-orm/type-tests/sqlite/db.ts | 3 + .../drizzle/0000_cuddly_black_bolt.sql | 11 + .../drizzle/meta/0000_snapshot.json | 80 + .../drizzle/meta/_journal.json | 13 + .../durable-objects/drizzle/migrations.js | 12 + .../tests/sqlite/durable-objects/index.ts | 3619 +++++++++++++++++ .../durable-objects/worker-configuration.d.ts | 5 + .../sqlite/durable-objects/wrangler.toml | 25 + pnpm-lock.yaml | 182 +- 19 files changed, 4255 insertions(+), 93 deletions(-) create mode 100644 drizzle-orm/src/durable-sqlite/driver.ts create mode 100644 drizzle-orm/src/durable-sqlite/index.ts create mode 100644 drizzle-orm/src/durable-sqlite/migrator.ts create mode 100644 drizzle-orm/src/durable-sqlite/session.ts create mode 100644 integration-tests/tests/sqlite/durable-objects/drizzle/0000_cuddly_black_bolt.sql create mode 100644 integration-tests/tests/sqlite/durable-objects/drizzle/meta/0000_snapshot.json create mode 100644 integration-tests/tests/sqlite/durable-objects/drizzle/meta/_journal.json create mode 100644 integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js create mode 100644 integration-tests/tests/sqlite/durable-objects/index.ts create mode 100644 integration-tests/tests/sqlite/durable-objects/worker-configuration.d.ts create mode 100644 integration-tests/tests/sqlite/durable-objects/wrangler.toml diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 7386b74d5..8fd625841 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -173,7 +173,7 @@ export const prepareGenerateConfig = async ( breakpoints: breakpoints ?? true, schema: schema, out: out || 'drizzle', - bundle: driver === 'expo', + bundle: driver === 'expo' || driver === 'durable-sqlite', casing, }; }; diff --git a/drizzle-kit/src/cli/validations/common.ts b/drizzle-kit/src/cli/validations/common.ts index 1662e87bb..7fc6046a7 100644 --- a/drizzle-kit/src/cli/validations/common.ts +++ b/drizzle-kit/src/cli/validations/common.ts @@ -63,6 +63,7 @@ export const assertCollisions = < export const sqliteDriversLiterals = [ literal('d1-http'), literal('expo'), + literal('durable-sqlite'), ] as const; export const postgresqlDriversLiterals = [ @@ -160,7 +161,7 @@ export const configPushSchema = object({ }); export type CliConfig = TypeOf; -export const drivers = ['d1-http', 'expo', 'aws-data-api', 'pglite'] as const; +export const drivers = ['d1-http', 'expo', 'aws-data-api', 'pglite', 'durable-sqlite'] as const; export type Driver = (typeof drivers)[number]; const _: Driver = '' as TypeOf; diff --git a/drizzle-kit/src/cli/validations/sqlite.ts b/drizzle-kit/src/cli/validations/sqlite.ts index 54178fd4a..bb16492c3 100644 --- a/drizzle-kit/src/cli/validations/sqlite.ts +++ b/drizzle-kit/src/cli/validations/sqlite.ts @@ -72,12 +72,27 @@ export const printConfigConnectionIssues = ( console.log(wrapParam('databaseId', options.databaseId)); console.log(wrapParam('token', options.token, false, 'secret')); process.exit(1); - } else if (driver === 'turso') { - let text = `Please provide required params for Turso driver:\n`; - console.log(error(text)); - console.log(wrapParam('url', options.url)); - console.log(wrapParam('authToken', options.authToken, false, 'secret')); - return; + } else if (driver === 'durable-sqlite') { + if (command === 'migrate') { + console.log( + error( + `You can't use 'migrate' command with SQLite Durable Objects`, + ), + ); + } else if (command === 'studio') { + console.log( + error( + `You can't use 'migrate' command with SQLite Durable Objects`, + ), + ); + } else if (command === 'pull') { + console.log(error("You can't use 'pull' command with SQLite Durable Objects")); + } else if (command === 'push') { + console.log(error("You can't use 'push' command with SQLite Durable Objects")); + } else { + console.log(error('Unexpected error with SQLite Durable Object driver 🤔')); + } + process.exit(1); } else { softAssertUnreachable(driver); } diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 4a57e59e3..9c745eb51 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -209,6 +209,10 @@ export type Config = dialect: Verify; driver: Verify; } + | { + dialect: Verify; + driver: Verify; + } | {} ); diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 87c3f0bc2..f148441e2 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -45,7 +45,7 @@ }, "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", - "@cloudflare/workers-types": ">=3", + "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", @@ -164,7 +164,7 @@ }, "devDependencies": { "@aws-sdk/client-rds-data": "^3.549.0", - "@cloudflare/workers-types": "^4.20230904.0", + "@cloudflare/workers-types": "^4.20241112.0", "@electric-sql/pglite": "^0.2.12", "@libsql/client": "^0.10.0", "@libsql/client-wasm": "^0.10.0", diff --git a/drizzle-orm/src/durable-sqlite/driver.ts b/drizzle-orm/src/durable-sqlite/driver.ts new file mode 100644 index 000000000..0be110084 --- /dev/null +++ b/drizzle-orm/src/durable-sqlite/driver.ts @@ -0,0 +1,60 @@ +/// +import { entityKind } from '~/entity.ts'; +import { DefaultLogger } from '~/logger.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type ExtractTablesWithRelations, + 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 { SQLiteDOSession } from './session.ts'; + +export class DrizzleSqliteDODatabase< + TSchema extends Record = Record, +> extends BaseSQLiteDatabase<'sync', SqlStorageCursor>, TSchema> { + static override readonly [entityKind]: string = 'DrizzleSqliteDODatabase'; + + /** @internal */ + declare readonly session: SQLiteDOSession>; +} + +export function drizzle< + TSchema extends Record = Record, + TClient extends DurableObjectStorage = DurableObjectStorage, +>( + client: TClient, + config: DrizzleConfig = {}, +): DrizzleSqliteDODatabase & { + $client: TClient; +} { + const dialect = new SQLiteSyncDialect({ casing: config.casing }); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const session = new SQLiteDOSession(client as DurableObjectStorage, dialect, schema, { logger }); + const db = new DrizzleSqliteDODatabase('sync', dialect, session, schema) as DrizzleSqliteDODatabase; + ( db).$client = client; + + return db as any; +} diff --git a/drizzle-orm/src/durable-sqlite/index.ts b/drizzle-orm/src/durable-sqlite/index.ts new file mode 100644 index 000000000..b1b6a52e7 --- /dev/null +++ b/drizzle-orm/src/durable-sqlite/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/durable-sqlite/migrator.ts b/drizzle-orm/src/durable-sqlite/migrator.ts new file mode 100644 index 000000000..8410b2900 --- /dev/null +++ b/drizzle-orm/src/durable-sqlite/migrator.ts @@ -0,0 +1,85 @@ +import type { MigrationMeta } from '~/migrator.ts'; +import { sql } from '~/sql/index.ts'; +import type { DrizzleSqliteDODatabase } from './driver.ts'; + +interface MigrationConfig { + journal: { + entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; + }; + migrations: Record; +} + +function readMigrationFiles({ journal, migrations }: MigrationConfig): MigrationMeta[] { + const migrationQueries: MigrationMeta[] = []; + + for (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, +>( + db: DrizzleSqliteDODatabase, + config: MigrationConfig, +): Promise { + const migrations = readMigrationFiles(config); + + db.transaction((tx) => { + try { + const migrationsTable = '__drizzle_migrations'; + + const migrationTableCreate = sql` + CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} ( + id SERIAL PRIMARY KEY, + hash text NOT NULL, + created_at numeric + ) + `; + db.run(migrationTableCreate); + + const dbMigrations = db.values<[number, string, string]>( + sql`SELECT id, hash, created_at FROM ${sql.identifier(migrationsTable)} ORDER BY created_at DESC LIMIT 1`, + ); + + const lastDbMigration = dbMigrations[0] ?? undefined; + + for (const migration of migrations) { + if (!lastDbMigration || Number(lastDbMigration[2])! < migration.folderMillis) { + for (const stmt of migration.sql) { + db.run(sql.raw(stmt)); + } + db.run( + sql`INSERT INTO ${ + sql.identifier(migrationsTable) + } ("hash", "created_at") VALUES(${migration.hash}, ${migration.folderMillis})`, + ); + } + } + } catch (error: any) { + tx.rollback(); + throw error; + } + }); +} diff --git a/drizzle-orm/src/durable-sqlite/session.ts b/drizzle-orm/src/durable-sqlite/session.ts new file mode 100644 index 000000000..dca5ce7cf --- /dev/null +++ b/drizzle-orm/src/durable-sqlite/session.ts @@ -0,0 +1,181 @@ +import { entityKind } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query } from '~/sql/sql.ts'; +import { type SQLiteSyncDialect, SQLiteTransaction } from '~/sqlite-core/index.ts'; +import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts'; +import { + type PreparedQueryConfig as PreparedQueryConfigBase, + type SQLiteExecuteMethod, + SQLiteSession, + type SQLiteTransactionConfig, +} from '~/sqlite-core/session.ts'; +import { SQLitePreparedQuery as PreparedQueryBase } from '~/sqlite-core/session.ts'; +import { mapResultRow } from '~/utils.ts'; + +export interface SQLiteDOSessionOptions { + logger?: Logger; +} + +type PreparedQueryConfig = Omit; + +export class SQLiteDOSession, TSchema extends TablesRelationalConfig> + extends SQLiteSession< + 'sync', + SqlStorageCursor>, + TFullSchema, + TSchema + > +{ + static override readonly [entityKind]: string = 'SQLiteDOSession'; + + private logger: Logger; + + constructor( + private client: DurableObjectStorage, + dialect: SQLiteSyncDialect, + private schema: RelationalSchemaConfig | undefined, + options: SQLiteDOSessionOptions = {}, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + } + + prepareQuery>( + query: Query, + fields: SelectedFieldsOrdered | undefined, + executeMethod: SQLiteExecuteMethod, + isResponseInArrayMode: boolean, + customResultMapper?: (rows: unknown[][]) => unknown, + ): SQLiteDOPreparedQuery { + return new SQLiteDOPreparedQuery( + this.client, + query, + this.logger, + fields, + executeMethod, + isResponseInArrayMode, + customResultMapper, + ); + } + + override transaction( + transaction: ( + tx: SQLiteTransaction<'sync', SqlStorageCursor>, TFullSchema, TSchema>, + ) => T, + _config?: SQLiteTransactionConfig, + ): T { + const tx = new SQLiteDOTransaction('sync', this.dialect, this, this.schema); + this.client.transactionSync(() => { + transaction(tx); + }); + return {} as any; + } +} + +export class SQLiteDOTransaction, TSchema extends TablesRelationalConfig> + extends SQLiteTransaction< + 'sync', + SqlStorageCursor>, + TFullSchema, + TSchema + > +{ + static override readonly [entityKind]: string = 'SQLiteDOTransaction'; + + override transaction(transaction: (tx: SQLiteDOTransaction) => T): T { + const tx = new SQLiteDOTransaction('sync', this.dialect, this.session, this.schema, this.nestedIndex + 1); + this.session.transaction(() => transaction(tx)); + + return {} as any; + } +} + +export class SQLiteDOPreparedQuery extends PreparedQueryBase<{ + type: 'sync'; + run: void; + all: T['all']; + get: T['get']; + values: T['values']; + execute: T['execute']; +}> { + static override readonly [entityKind]: string = 'SQLiteDOPreparedQuery'; + + constructor( + private client: DurableObjectStorage, + query: Query, + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + executeMethod: SQLiteExecuteMethod, + private _isResponseInArrayMode: boolean, + private customResultMapper?: (rows: unknown[][]) => unknown, + ) { + super('sync', executeMethod, query); + } + + run(placeholderValues?: Record): void { + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); + + params.length > 0 ? this.client.sql.exec(this.query.sql, ...params) : this.client.sql.exec(this.query.sql); + } + + all(placeholderValues?: Record): T['all'] { + const { fields, joinsNotNullableMap, query, logger, client, customResultMapper } = this; + if (!fields && !customResultMapper) { + const params = fillPlaceholders(query.params, placeholderValues ?? {}); + logger.logQuery(query.sql, params); + + return params.length > 0 ? client.sql.exec(query.sql, ...params).toArray() : client.sql.exec(query.sql).toArray(); + } + + const rows = this.values(placeholderValues) as unknown[][]; + + if (customResultMapper) { + return customResultMapper(rows) as T['all']; + } + + return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + } + + get(placeholderValues?: Record): T['get'] { + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); + + const { fields, client, joinsNotNullableMap, customResultMapper, query } = this; + if (!fields && !customResultMapper) { + return params.length > 0 ? client.sql.exec(query.sql, ...params).one() : client.sql.exec(query.sql).one(); + } + + const rows = this.values(placeholderValues) as unknown[][]; + const row = rows[0]; + + if (!row) { + return undefined; + } + + if (customResultMapper) { + return customResultMapper(rows) as T['get']; + } + + return mapResultRow(fields!, row, joinsNotNullableMap); + } + + values(placeholderValues?: Record): T['values'] { + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); + + const res = params.length > 0 + ? this.client.sql.exec(this.query.sql, ...params) + : this.client.sql.exec(this.query.sql); + + // @ts-ignore .raw().toArray() exists + return res.raw().toArray(); + } + + /** @internal */ + isResponseInArrayMode(): boolean { + return this._isResponseInArrayMode; + } +} diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index d9f3fc7c6..dfd2795a4 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -40,8 +40,19 @@ export class SQLiteBigInt> return 'blob'; } - override mapFromDriverValue(value: Buffer | Uint8Array): bigint { - return BigInt(Buffer.isBuffer(value) ? value.toString() : String.fromCodePoint(...value)); + override mapFromDriverValue(value: Buffer | Uint8Array | ArrayBuffer): bigint { + if (Buffer.isBuffer(value)) { + return BigInt(value.toString()); + } + + // for sqlite durable objects + // eslint-disable-next-line no-instanceof/no-instanceof + if (value instanceof ArrayBuffer) { + const decoder = new TextDecoder(); + return BigInt(decoder.decode(value)); + } + + return BigInt(String.fromCodePoint(...value)); } override mapToDriverValue(value: bigint): Buffer { @@ -85,8 +96,19 @@ export class SQLiteBlobJson return 'blob'; } - override mapFromDriverValue(value: Buffer | Uint8Array): T['data'] { - return JSON.parse(Buffer.isBuffer(value) ? value.toString() : String.fromCodePoint(...value)); + override mapFromDriverValue(value: Buffer | Uint8Array | ArrayBuffer): T['data'] { + if (Buffer.isBuffer(value)) { + return JSON.parse(value.toString()); + } + + // for sqlite durable objects + // eslint-disable-next-line no-instanceof/no-instanceof + if (value instanceof ArrayBuffer) { + const decoder = new TextDecoder(); + return JSON.parse(decoder.decode(value)); + } + + return JSON.parse(String.fromCodePoint(...value)); } override mapToDriverValue(value: T['data']): Buffer { diff --git a/drizzle-orm/type-tests/sqlite/db.ts b/drizzle-orm/type-tests/sqlite/db.ts index 07af338d4..1950c7435 100644 --- a/drizzle-orm/type-tests/sqlite/db.ts +++ b/drizzle-orm/type-tests/sqlite/db.ts @@ -3,11 +3,14 @@ import { Database as BunDatabase } from 'bun:sqlite'; import { drizzle as drizzleBetterSqlite3 } from '~/better-sqlite3/index.ts'; import { drizzle as drizzleBun } from '~/bun-sqlite/index.ts'; import { drizzle as drizzleD1 } from '~/d1/index.ts'; +import { drizzle as durableSqlite } from '~/durable-sqlite/index.ts'; const client = new Database(':memory:'); const bunClient = new BunDatabase(':memory:'); declare const d1: D1Database; +declare const durableSql: DurableObjectStorage; export const db = drizzleBetterSqlite3(client); export const bunDb = drizzleBun(bunClient); export const d1Db = drizzleD1(d1); +export const durableSqliteDb = durableSqlite(durableSql); diff --git a/integration-tests/tests/sqlite/durable-objects/drizzle/0000_cuddly_black_bolt.sql b/integration-tests/tests/sqlite/durable-objects/drizzle/0000_cuddly_black_bolt.sql new file mode 100644 index 000000000..deff0ea9a --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/drizzle/0000_cuddly_black_bolt.sql @@ -0,0 +1,11 @@ +CREATE TABLE `another_users` ( + `id` integer PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `email` text NOT NULL +); +--> statement-breakpoint +CREATE TABLE `users12` ( + `id` integer PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `email` text NOT NULL +); diff --git a/integration-tests/tests/sqlite/durable-objects/drizzle/meta/0000_snapshot.json b/integration-tests/tests/sqlite/durable-objects/drizzle/meta/0000_snapshot.json new file mode 100644 index 000000000..9c151ecc9 --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/drizzle/meta/0000_snapshot.json @@ -0,0 +1,80 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "66be869a-d55d-4790-a382-de654dff1506", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "another_users": { + "name": "another_users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users12": { + "name": "users12", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/integration-tests/tests/sqlite/durable-objects/drizzle/meta/_journal.json b/integration-tests/tests/sqlite/durable-objects/drizzle/meta/_journal.json new file mode 100644 index 000000000..ab94199ee --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1732696446109, + "tag": "0000_cuddly_black_bolt", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js b/integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js new file mode 100644 index 000000000..8b7b5cf54 --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js @@ -0,0 +1,12 @@ +// This file is required for Expo/React Native SQLite migrations - https://orm.drizzle.team/quick-sqlite/expo + +import journal from './meta/_journal.json'; +import m0000 from './0000_cuddly_black_bolt.sql'; + + export default { + journal, + migrations: { + m0000 + } + } + \ No newline at end of file diff --git a/integration-tests/tests/sqlite/durable-objects/index.ts b/integration-tests/tests/sqlite/durable-objects/index.ts new file mode 100644 index 000000000..b67534d4e --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/index.ts @@ -0,0 +1,3619 @@ +/// + +import { expect } from 'chai'; +import { DurableObject } from 'cloudflare:workers'; +import { + and, + asc, + avg, + avgDistinct, + count, + countDistinct, + eq, + exists, + getTableColumns, + gt, + gte, + inArray, + lt, + max, + min, + Name, + notInArray, + sql, + sum, + sumDistinct, +} from 'drizzle-orm'; +import { drizzle, type DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite'; +import { migrate } from 'drizzle-orm/durable-sqlite/migrator'; +import { + alias, + type BaseSQLiteDatabase, + blob, + except, + getViewConfig, + int, + integer, + intersect, + numeric, + primaryKey, + sqliteTable, + sqliteTableCreator, + sqliteView, + text, + union, + unionAll, +} from 'drizzle-orm/sqlite-core'; +import { type Equal, Expect } from '~/utils'; +import migrations from './drizzle/migrations'; + +export const usersTable = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + verified: integer('verified', { mode: 'boolean' }).notNull().default(false), + json: blob('json', { mode: 'json' }).$type(), + createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(sql`strftime('%s', 'now')`), +}); + +export const usersOnUpdate = sqliteTable('users_on_update', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + updateCounter: integer('update_counter').default(sql`1`).$onUpdateFn(() => sql`update_counter + 1`), + updatedAt: integer('updated_at', { mode: 'timestamp_ms' }).$onUpdate(() => new Date()), + alwaysNull: text('always_null').$type().$onUpdate(() => null), +}); + +export const users2Table = sqliteTable('users2', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').references(() => citiesTable.id), +}); + +export const citiesTable = sqliteTable('cities', { + id: integer('id').primaryKey(), + name: text('name').notNull(), +}); + +export const coursesTable = sqliteTable('courses', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + categoryId: integer('category_id').references(() => courseCategoriesTable.id), +}); + +export const courseCategoriesTable = sqliteTable('course_categories', { + id: integer('id').primaryKey(), + name: text('name').notNull(), +}); + +export const orders = sqliteTable('orders', { + id: integer('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull().$default(() => 'random_string'), + amount: integer('amount').notNull(), + quantity: integer('quantity').notNull(), +}); + +export const usersMigratorTable = sqliteTable('users12', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}); + +export const anotherUsersMigratorTable = sqliteTable('another_users', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}); + +export const pkExampleTable = sqliteTable('pk_example', { + id: integer('id').notNull(), + name: text('name').notNull(), + email: text('email').notNull(), +}, (table) => ({ + compositePk: primaryKey({ columns: [table.id, table.name] }), +})); + +export const bigIntExample = sqliteTable('big_int_example', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + bigInt: blob('big_int', { mode: 'bigint' }).notNull(), +}); + +// To test aggregate functions +export const aggregateTable = sqliteTable('aggregate_table', { + id: integer('id').primaryKey({ autoIncrement: true }).notNull(), + name: text('name').notNull(), + a: integer('a'), + b: integer('b'), + c: integer('c'), + nullOnly: integer('null_only'), +}); + +async function setupSetOperationTest(db: BaseSQLiteDatabase) { + await db.run(sql`drop table if exists users2`); + await db.run(sql`drop table if exists cities`); + await db.run(sql` + create table \`cities\` ( + id integer primary key, + name text not null + ) + `); + + await db.run(sql` + create table \`users2\` ( + id integer primary key, + name text not null, + city_id integer references ${citiesTable}(${sql.identifier(citiesTable.id.name)}) + ) + `); + + await db.insert(citiesTable).values([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 3 }, + { id: 4, name: 'Peter', cityId: 3 }, + { id: 5, name: 'Ben', cityId: 2 }, + { id: 6, name: 'Jill', cityId: 1 }, + { id: 7, name: 'Mary', cityId: 2 }, + { id: 8, name: 'Sally', cityId: 1 }, + ]); +} + +async function setupAggregateFunctionsTest(db: BaseSQLiteDatabase) { + await db.run(sql`drop table if exists "aggregate_table"`); + await db.run( + sql` + create table "aggregate_table" ( + "id" integer primary key autoincrement not null, + "name" text not null, + "a" integer, + "b" integer, + "c" integer, + "null_only" integer + ); + `, + ); + await db.insert(aggregateTable).values([ + { name: 'value 1', a: 5, b: 10, c: 20 }, + { name: 'value 1', a: 5, b: 20, c: 30 }, + { name: 'value 2', a: 10, b: 50, c: 60 }, + { name: 'value 3', a: 20, b: 20, c: null }, + { name: 'value 4', a: null, b: 90, c: 120 }, + { name: 'value 5', a: 80, b: 10, c: null }, + { name: 'value 6', a: null, b: null, c: 150 }, + ]); +} + +// eslint-disable-next-line drizzle-internal/require-entity-kind +export class MyDurableObject extends DurableObject { + storage: DurableObjectStorage; + db: DrizzleSqliteDODatabase; + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + this.storage = ctx.storage; + this.db = drizzle(this.storage, { logger: false }); + } + + async migrate1(): Promise { + try { + this.db.run(sql`drop table if exists another_users`); + this.db.run(sql`drop table if exists users12`); + this.db.run(sql`drop table if exists __drizzle_migrations`); + + migrate(this.db, migrations); + + this.db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result = this.db.select().from(usersMigratorTable).all(); + + this.db.insert(anotherUsersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result2 = this.db.select().from(anotherUsersMigratorTable).all(); + + expect(result).deep.equal([{ id: 1, name: 'John', email: 'email' }]); + expect(result2).deep.equal([{ id: 1, name: 'John', email: 'email' }]); + + this.db.run(sql`drop table another_users`); + this.db.run(sql`drop table users12`); + this.db.run(sql`drop table __drizzle_migrations`); + } catch { + throw new Error('migrate1 has broken'); + } + } + + async beforeEach(): Promise { + this.db.run(sql`drop table if exists ${usersTable}`); + this.db.run(sql`drop table if exists ${users2Table}`); + this.db.run(sql`drop table if exists ${citiesTable}`); + this.db.run(sql`drop table if exists ${coursesTable}`); + this.db.run(sql`drop table if exists ${courseCategoriesTable}`); + this.db.run(sql`drop table if exists ${orders}`); + this.db.run(sql`drop table if exists ${bigIntExample}`); + this.db.run(sql`drop table if exists ${pkExampleTable}`); + this.db.run(sql`drop table if exists user_notifications_insert_into`); + this.db.run(sql`drop table if exists users_insert_into`); + this.db.run(sql`drop table if exists notifications_insert_into`); + + this.db.run(sql` + create table ${usersTable} ( + id integer primary key, + name text not null, + verified integer not null default 0, + json blob, + created_at integer not null default (strftime('%s', 'now')) + ) + `); + + this.db.run(sql` + create table ${citiesTable} ( + id integer primary key, + name text not null + ) + `); + this.db.run(sql` + create table ${courseCategoriesTable} ( + id integer primary key, + name text not null + ) + `); + + this.db.run(sql` + create table ${users2Table} ( + id integer primary key, + name text not null, + city_id integer references ${citiesTable}(${sql.identifier(citiesTable.id.name)}) + ) + `); + this.db.run(sql` + create table ${coursesTable} ( + id integer primary key, + name text not null, + category_id integer references ${courseCategoriesTable}(${sql.identifier(courseCategoriesTable.id.name)}) + ) + `); + this.db.run(sql` + create table ${orders} ( + id integer primary key, + region text not null, + product text not null, + amount integer not null, + quantity integer not null + ) + `); + this.db.run(sql` + create table ${pkExampleTable} ( + id integer not null, + name text not null, + email text not null, + primary key (id, name) + ) + `); + this.db.run(sql` + create table ${bigIntExample} ( + id integer primary key, + name text not null, + big_int blob not null + ) + `); + } + + async insertBigIntValues(): Promise { + try { + await this.beforeEach(); + + this.db + .insert(bigIntExample) + .values({ name: 'one', bigInt: BigInt('0') }) + .run(); + this.db + .insert(bigIntExample) + .values({ name: 'two', bigInt: BigInt('127') }) + .run(); + this.db + .insert(bigIntExample) + .values({ name: 'three', bigInt: BigInt('32767') }) + .run(); + this.db + .insert(bigIntExample) + .values({ name: 'four', bigInt: BigInt('1234567890') }) + .run(); + this.db + .insert(bigIntExample) + .values({ name: 'five', bigInt: BigInt('12345678900987654321') }) + .run(); + + const result = this.db.select().from(bigIntExample).all(); + expect(result).deep.equal([ + { id: 1, name: 'one', bigInt: BigInt('0') }, + { id: 2, name: 'two', bigInt: BigInt('127') }, + { id: 3, name: 'three', bigInt: BigInt('32767') }, + { id: 4, name: 'four', bigInt: BigInt('1234567890') }, + { id: 5, name: 'five', bigInt: BigInt('12345678900987654321') }, + ]); + } catch (error: any) { + console.log(error); + throw new Error('insertBigIntValues has broken'); + } + } + async selectAllFields(): Promise { + try { + await this.beforeEach(); + const now = Date.now(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const result = this.db.select().from(usersTable).all(); + expect(result[0]!.createdAt).instanceOf(Date); + expect(Math.abs(result[0]!.createdAt.getTime() - now)).lessThan(5000); + expect(result).deep.equal([{ + id: 1, + name: 'John', + verified: false, + json: null, + createdAt: result[0]!.createdAt, + }]); + } catch { + throw new Error('selectAllFields has broken'); + } + } + + async selectPartial(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const result = this.db.select({ name: usersTable.name }).from(usersTable).all(); + + expect(result).deep.equal([{ name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectPartial error`); + } + } + + async selectSql(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .all(); + + expect(users).deep.equal([{ name: 'JOHN' }]); + } catch { + throw new Error('selectSql has broken'); + } + } + + async selectTypedSql(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .all(); + + expect(users).deep.equal([{ name: 'JOHN' }]); + } catch { + throw new Error('selectTypedSql has broken'); + } + } + + async selectWithEmptyArrayInInArray(): Promise { + try { + await this.beforeEach(); + + await this.db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + const result = await this.db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(inArray(usersTable.id, [])); + + expect(result).deep.equal([]); + } catch (error: any) { + console.error(error); + throw new Error('selectWithEmptyArrayInInArray has broken'); + } + } + + async selectWithEmptyArrayInNotInArray(): Promise { + try { + await this.beforeEach(); + + await this.db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + const result = await this.db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(notInArray(usersTable.id, [])); + + expect(result).deep.equal([{ name: 'JOHN' }, { name: 'JANE' }, { name: 'JANE' }]); + } catch (error: any) { + console.error(error); + throw new Error('selectWithEmptyArrayInNotInArray has broken'); + } + } + + async selectDistinct(): Promise { + try { + await this.beforeEach(); + + const usersDistinctTable = sqliteTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${usersDistinctTable}`); + this.db.run(sql`create table ${usersDistinctTable} (id integer, name text)`); + + this.db + .insert(usersDistinctTable) + .values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]) + .run(); + const users = this.db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ).all(); + + this.db.run(sql`drop table ${usersDistinctTable}`); + + expect(users).deep.equal([ + { id: 1, name: 'Jane' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + ]); + } catch (error: any) { + console.error(error); + throw new Error('selectDistinct has broken'); + } + } + + async returingSql(): Promise { + try { + await this.beforeEach(); + + const users = this.db + .insert(usersTable) + .values({ name: 'John' }) + .returning({ + name: sql`upper(${usersTable.name})`, + }) + .all(); + + expect(users).deep.equal([{ name: 'JOHN' }]); + } catch (error: any) { + console.error(error); + throw new Error('returingSql has broken'); + } + } + + async $defaultFunction(): Promise { + try { + await this.beforeEach(); + + await this.db.insert(orders).values({ id: 1, region: 'Ukraine', amount: 1, quantity: 1 }); + const selectedOrder = await this.db.select().from(orders); + + expect(selectedOrder).deep.equal([ + { + id: 1, + amount: 1, + quantity: 1, + region: 'Ukraine', + product: 'random_string', + }, + ]); + } catch (error: any) { + console.error(error); + throw new Error('defaultFunction has broken'); + } + } + + async deleteReturningSql(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .delete(usersTable) + .where(eq(usersTable.name, 'John')) + .returning({ + name: sql`upper(${usersTable.name})`, + }) + .all(); + + expect(users).deep.equal([{ name: 'JOHN' }]); + } catch (error: any) { + console.error(error); + throw new Error('deleteReturningSql has broken'); + } + } + + async queryCheckInsertSingleEmptyRow(): Promise { + try { + await this.beforeEach(); + + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + const query = this.db.insert(users).values({}).toSQL(); + + expect(query).deep.equal({ + sql: 'insert into "users" ("id", "name", "state") values (null, ?, null)', + params: ['Dan'], + }); + } catch (error: any) { + console.error(error); + throw new Error('queryCheckInsertSingleEmptyRow has broken'); + } + } + + async queryCheckInsertMultipleEmptyRow(): Promise { + try { + await this.beforeEach(); + + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + const query = this.db.insert(users).values([{}, {}]).toSQL(); + + expect(query).deep.equal({ + sql: 'insert into "users" ("id", "name", "state") values (null, ?, null), (null, ?, null)', + params: ['Dan', 'Dan'], + }); + } catch (error: any) { + console.error(error); + throw new Error('queryCheckInsertMultipleEmptyRow has broken'); + } + } + + async insertAllDefaultsIn1Row(): Promise { + try { + await this.beforeEach(); + + const users = sqliteTable('empty_insert_single', { + id: integer('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text default 'Dan', state text)`); + + this.db.insert(users).values({}).run(); + + const res = this.db.select().from(users).all(); + + expect(res).deep.equal([{ id: 1, name: 'Dan', state: null }]); + } catch (error: any) { + console.error(error); + throw new Error('insertAllDefaultsIn1Row has broken'); + } + } + + async insertAllDefaultsInMultipleRows(): Promise { + try { + await this.beforeEach(); + + const users = sqliteTable('empty_insert_multiple', { + id: integer('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text default 'Dan', state text)`); + + this.db.insert(users).values([{}, {}]).run(); + + const res = this.db.select().from(users).all(); + + expect(res).deep.equal([ + { id: 1, name: 'Dan', state: null }, + { id: 2, name: 'Dan', state: null }, + ]); + } catch (error: any) { + console.error(error); + throw new Error('insertAllDefaultsInMultipleRows has broken'); + } + } + + async updateReturningSql(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning({ + name: sql`upper(${usersTable.name})`, + }) + .all(); + + expect(users).deep.equal([{ name: 'JANE' }]); + } catch (error: any) { + console.error(error); + throw new Error('updateReturningSql has broken'); + } + } + + async insertWithAutoIncrement(): Promise { + try { + await this.beforeEach(); + + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'George' }, { name: 'Austin' }]) + .run(); + const result = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).all(); + + expect(result).deep.equal([ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'George' }, + { id: 4, name: 'Austin' }, + ]); + } catch (error: any) { + console.error(error); + throw new Error('insertWithAutoIncrement has broken'); + } + } + + async insertDataWithDefaultValues(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const result = this.db.select().from(usersTable).all(); + + expect(result).deep.equal([{ + id: 1, + name: 'John', + verified: false, + json: null, + createdAt: result[0]!.createdAt, + }]); + } catch (error: any) { + console.error(error); + throw new Error('insertDataWithDefaultValues has broken'); + } + } + + async insertDataWithOverridenDefaultValues(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John', verified: true }).run(); + const result = this.db.select().from(usersTable).all(); + + expect(result).deep.equal([{ id: 1, name: 'John', verified: true, json: null, createdAt: result[0]!.createdAt }]); + } catch (error: any) { + console.error(error); + throw new Error('insertDataWithOverridenDefaultValues has broken'); + } + } + + async updateWithReturningFields(): Promise { + try { + await this.beforeEach(); + const now = Date.now(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')).returning() + .all(); + + expect(users[0]!.createdAt).instanceOf(Date); + expect(Math.abs(users[0]!.createdAt.getTime() - now)).lessThan(5000); + expect(users).deep.equal([{ id: 1, name: 'Jane', verified: false, json: null, createdAt: users[0]!.createdAt }]); + } catch (error: any) { + console.error(error); + throw new Error('updateWithReturningFields has broken'); + } + } + + async updateWithReturningPartial(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning({ + id: usersTable.id, + name: usersTable.name, + }) + .all(); + + expect(users).deep.equal([{ id: 1, name: 'Jane' }]); + } catch (error: any) { + console.error(error); + throw new Error('updateWithReturningFields has broken'); + } + } + + async updateWithReturningAllFields(): Promise { + try { + await this.beforeEach(); + + const now = Date.now(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db.delete(usersTable).where(eq(usersTable.name, 'John')).returning().all(); + + expect(users[0]!.createdAt).instanceOf(Date); + expect(Math.abs(users[0]!.createdAt.getTime() - now)).lessThan(5000); + expect(users).deep.equal([{ id: 1, name: 'John', verified: false, json: null, createdAt: users[0]!.createdAt }]); + } catch (error: any) { + console.error(error); + throw new Error('updateWithReturningFields has broken'); + } + } + + async deleteWithReturningPartial(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .delete(usersTable) + .where(eq(usersTable.name, 'John')) + .returning({ + id: usersTable.id, + name: usersTable.name, + }) + .all(); + + expect(users).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`deleteWithReturningPartial error`); + } + } + + async insertAndSelect(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ name: 'John' }).run(); + const result = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).all(); + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + + this.db.insert(usersTable).values({ name: 'Jane' }).run(); + const result2 = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).all(); + + expect(result2).deep.equal([ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`insertAndSelect error`); + } + } + + async jsonInsert(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values({ name: 'John', json: ['foo', 'bar'] }) + .run(); + const result = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + json: usersTable.json, + }) + .from(usersTable) + .all(); + + expect(result).deep.equal([{ id: 1, name: 'John', json: ['foo', 'bar'] }]); + } catch (error: any) { + console.error(error); + throw new Error(`jsonInsert error`); + } + } + + async insertMany(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Bruce', json: ['foo', 'bar'] }, { name: 'Jane' }, { + name: 'Austin', + verified: true, + }]) + .run(); + const result = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + json: usersTable.json, + verified: usersTable.verified, + }) + .from(usersTable) + .all(); + + expect(result).deep.equal([ + { id: 1, name: 'John', json: null, verified: false }, + { id: 2, name: 'Bruce', json: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', json: null, verified: false }, + { id: 4, name: 'Austin', json: null, verified: true }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`insertMany error`); + } + } + + async insertManyWithReturning(): Promise { + try { + await this.beforeEach(); + const result = this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Bruce', json: ['foo', 'bar'] }, { name: 'Jane' }, { + name: 'Austin', + verified: true, + }]) + .returning({ + id: usersTable.id, + name: usersTable.name, + json: usersTable.json, + verified: usersTable.verified, + }) + .all(); + + expect(result).deep.equal([ + { id: 1, name: 'John', json: null, verified: false }, + { id: 2, name: 'Bruce', json: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', json: null, verified: false }, + { id: 4, name: 'Austin', json: null, verified: true }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`insertManyWithReturning error`); + } + } + + async partialJoinWithAlias(): Promise { + try { + await this.beforeEach(); + const customerAlias = alias(usersTable, 'customer'); + + await this.db.insert(usersTable).values([ + { id: 10, name: 'Ivan' }, + { id: 11, name: 'Hans' }, + ]); + + const result = await this.db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }) + .from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)); + + expect(result).deep.equal([ + { + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`partialJoinWithAlias error`); + } + } + + async fullJoinWithAlias(): Promise { + try { + await this.beforeEach(); + const sqliteTable = sqliteTableCreator((name) => `prefixed_${name}`); + + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + this.db.run(sql`create table ${users} (id integer primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + this.db + .insert(users) + .values([ + { id: 10, name: 'Ivan' }, + { id: 11, name: 'Hans' }, + ]) + .run(); + const result = this.db.select().from(users).leftJoin(customers, eq(customers.id, 11)).where(eq(users.id, 10)) + .all(); + + expect(result).deep.equal([ + { + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }, + ]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`fullJoinWithAlias error`); + } + } + + async selectFromAlias(): Promise { + try { + await this.beforeEach(); + const sqliteTable = sqliteTableCreator((name) => `prefixed_${name}`); + + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + this.db.run(sql`create table ${users} (id integer primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + this.db + .insert(users) + .values([ + { id: 10, name: 'Ivan' }, + { id: 11, name: 'Hans' }, + ]) + .run(); + const result = this.db.select().from(user).leftJoin(customers, eq(customers.id, 11)).where(eq(user.id, 10)).all(); + + expect(result).deep.equal([ + { + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }, + ]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`selectFromAlias error`); + } + } + + async insertWithSpaces(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values({ name: sql`'Jo h n'` }) + .run(); + const result = await this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).all(); + + expect(result).deep.equal([{ id: 1, name: 'Jo h n' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithSpaces error`); + } + } + + async preparedStatement(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ name: 'John' }).run(); + const statement = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).prepare(); + const result = statement.all(); + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatement error`); + } + } + + async preparedStatementReuse(): Promise { + try { + await this.beforeEach(); + const stmt = this.db + .insert(usersTable) + .values({ name: sql.placeholder('name') }) + .prepare(); + + for (let i = 0; i < 10; i++) { + stmt.run({ name: `John ${i}` }); + } + + const result = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .all(); + + expect(result).deep.equal([ + { id: 1, name: 'John 0' }, + { id: 2, name: 'John 1' }, + { id: 3, name: 'John 2' }, + { id: 4, name: 'John 3' }, + { id: 5, name: 'John 4' }, + { id: 6, name: 'John 5' }, + { id: 7, name: 'John 6' }, + { id: 8, name: 'John 7' }, + { id: 9, name: 'John 8' }, + { id: 10, name: 'John 9' }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatementReuse error`); + } + } + + async insertPlaceholdersOnColumnsWithEncoder(): Promise { + try { + await this.beforeEach(); + const stmt = this.db + .insert(usersTable) + .values({ + name: 'John', + verified: sql.placeholder('verified'), + }) + .prepare(); + + stmt.run({ verified: true }); + stmt.run({ verified: false }); + + const result = this.db + .select({ + id: usersTable.id, + verified: usersTable.verified, + }) + .from(usersTable) + .all(); + + expect(result).deep.equal([ + { id: 1, verified: true }, + { id: 2, verified: false }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`insertPlaceholdersOnColumnsWithEncoder error`); + } + } + + async preparedStatementWithPlaceholderInWhere(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ name: 'John' }).run(); + const stmt = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .prepare(); + const result = stmt.all({ id: 1 }); + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatementWithPlaceholderInWhere error`); + } + } + + async preparedStatementWithPlaceholderInLimit(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ name: 'John' }).run(); + const stmt = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .limit(sql.placeholder('limit')) + .prepare(); + + const result = await stmt.all({ id: 1, limit: 1 }); + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + expect(result).length(1); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatementWithPlaceholderInLimit error`); + } + } + + async preparedStatementWithPlaceholderInOffset(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'John1' }]) + .run(); + const stmt = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .limit(sql.placeholder('limit')) + .offset(sql.placeholder('offset')) + .prepare(); + + const result = stmt.all({ limit: 1, offset: 1 }); + + expect(result).deep.equal([{ id: 2, name: 'John1' }]); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatementWithPlaceholderInOffset error`); + } + } + + async preparedStatementBuiltUsing$dynamic(): Promise { + try { + await this.beforeEach(); + function withLimitOffset(qb: any) { + return qb.limit(sql.placeholder('limit')).offset(sql.placeholder('offset')); + } + + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'John1' }]) + .run(); + const stmt = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .$dynamic(); + withLimitOffset(stmt).prepare('stmt_limit'); + + const result = await stmt.all({ limit: 1, offset: 1 }); + + expect(result).deep.equal([{ id: 2, name: 'John1' }]); + expect(result).length(1); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatementBuiltUsing error`); + } + } + + async selectWithGroupByAsField(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const result = this.db.select({ name: usersTable.name }).from(usersTable).groupBy(usersTable.name).all(); + + expect(result).deep.equal([{ name: 'Jane' }, { name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithGroupByAsField error`); + } + } + + async selectWithExists(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const user = alias(usersTable, 'user'); + const result = this.db + .select({ name: usersTable.name }) + .from(usersTable) + .where( + exists( + this.db + .select({ one: sql`1` }) + .from(user) + .where(and(eq(usersTable.name, 'John'), eq(user.id, usersTable.id))), + ), + ) + .all(); + + expect(result).deep.equal([{ name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithExists error`); + } + } + + async selectWithGroupByAsSql(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const result = this.db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(sql`${usersTable.name}`) + .all(); + + expect(result).deep.equal([{ name: 'Jane' }, { name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithGroupByAsSql error`); + } + } + + async selectWithGroupByAsSqlPlusColumn(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const result = this.db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id) + .all(); + + expect(result).deep.equal([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithGroupByAsSqlPlusColumn error`); + } + } + + async selectWithGroupByAsColumnPlusSql(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const result = this.db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .all(); + + expect(result).deep.equal([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithGroupByAsColumnPlusSql error`); + } + } + + async selectWithGroupByComplexQuery(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const result = this.db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1) + .all(); + + expect(result).deep.equal([{ name: 'Jane' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithGroupByComplexQuery error`); + } + } + + async buildQuery(): Promise { + try { + await this.beforeEach(); + const query = this.db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + expect(query).deep.equal({ + sql: 'select "id", "name" from "users" group by "users"."id", "users"."name"', + params: [], + }); + } catch (error: any) { + console.error(error); + throw new Error(`buildQuery error`); + } + } + + async insertViaDbRunPlusSelectViaDbAll(): Promise { + try { + await this.beforeEach(); + this.db.run(sql`insert into ${usersTable} (${new Name(usersTable.name.name)}) values (${'John'})`); + + const result = this.db.all<{ id: number; name: string }>(sql`select id, name from "users"`); + expect(result).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertViaDbRunPlusSelectViaDbAll error`); + } + } + + async insertViaDbGet(): Promise { + try { + await this.beforeEach(); + const inserted = this.db.get<{ id: number; name: string }>( + sql`insert into ${usersTable} (${new Name( + usersTable.name.name, + )}) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, + ); + expect(inserted).deep.equal({ id: 1, name: 'John' }); + } catch (error: any) { + console.error(error); + throw new Error(`insertViaDbGet error`); + } + } + + async insertViaDbRunPlusSelectViaDbGet(): Promise { + try { + await this.beforeEach(); + this.db.run(sql`insert into ${usersTable} (${new Name(usersTable.name.name)}) values (${'John'})`); + + const result = this.db.get<{ id: number; name: string }>( + sql`select ${usersTable.id}, ${usersTable.name} from ${usersTable}`, + ); + expect(result).deep.equal({ id: 1, name: 'John' }); + } catch (error: any) { + console.error(error); + throw new Error(`insertViaDbRunPlusSelectViaDbGet error`); + } + } + + async insertViaDbGetQueryBuilder(): Promise { + try { + await this.beforeEach(); + const inserted = this.db.get>( + this.db.insert(usersTable).values({ name: 'John' }).returning({ id: usersTable.id, name: usersTable.name }), + ); + expect(inserted).deep.equal({ id: 1, name: 'John' }); + } catch (error: any) { + console.error(error); + throw new Error(`insertViaDbGetQueryBuilder error`); + } + } + + async joinSubquery(): Promise { + try { + await this.beforeEach(); + this.db + .insert(courseCategoriesTable) + .values([{ name: 'Category 1' }, { name: 'Category 2' }, { name: 'Category 3' }, { name: 'Category 4' }]) + .run(); + + this.db + .insert(coursesTable) + .values([ + { name: 'Development', categoryId: 2 }, + { name: 'IT & Software', categoryId: 3 }, + { name: 'Marketing', categoryId: 4 }, + { name: 'Design', categoryId: 1 }, + ]) + .run(); + + const sq2 = this.db + .select({ + categoryId: courseCategoriesTable.id, + category: courseCategoriesTable.name, + total: sql`count(${courseCategoriesTable.id})`, + }) + .from(courseCategoriesTable) + .groupBy(courseCategoriesTable.id, courseCategoriesTable.name) + .as('sq2'); + + const res = await this.db + .select({ + courseName: coursesTable.name, + categoryId: sq2.categoryId, + }) + .from(coursesTable) + .leftJoin(sq2, eq(coursesTable.categoryId, sq2.categoryId)) + .orderBy(coursesTable.name) + .all(); + + expect(res).deep.equal([ + { courseName: 'Design', categoryId: 1 }, + { courseName: 'Development', categoryId: 2 }, + { courseName: 'IT & Software', categoryId: 3 }, + { courseName: 'Marketing', categoryId: 4 }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`joinSubquery error`); + } + } + + async withSelect(): Promise { + try { + await this.beforeEach(); + this.db + .insert(orders) + .values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]) + .run(); + + const regionalSales = this.db.$with('regional_sales').as( + this.db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = this.db.$with('top_regions').as( + this.db + .select({ + region: regionalSales.region, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + this.db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = this.db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`cast(sum(${orders.quantity}) as int)`, + productSales: sql`cast(sum(${orders.amount}) as int)`, + }) + .from(orders) + .where(inArray(orders.region, this.db.select({ region: topRegions.region }).from(topRegions))) + .groupBy(orders.region, orders.product) + .orderBy(orders.region, orders.product) + .all(); + + expect(result).deep.equal([ + { + region: 'Europe', + product: 'A', + productUnits: 3, + productSales: 30, + }, + { + region: 'Europe', + product: 'B', + productUnits: 5, + productSales: 50, + }, + { + region: 'US', + product: 'A', + productUnits: 7, + productSales: 70, + }, + { + region: 'US', + product: 'B', + productUnits: 9, + productSales: 90, + }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`withSelect error`); + } + } + + async withUpdate(): Promise { + try { + await this.beforeEach(); + const products = sqliteTable('products', { + id: integer('id').primaryKey(), + price: numeric('price').notNull(), + cheap: integer('cheap', { mode: 'boolean' }).notNull().default(false), + }); + + this.db.run(sql`drop table if exists ${products}`); + this.db.run(sql` + create table ${products} ( + id integer primary key, + price numeric not null, + cheap integer not null default 0 + ) + `); + + await this.db + .insert(products) + .values([{ price: '10.99' }, { price: '25.85' }, { price: '32.99' }, { price: '2.50' }, { price: '4.59' }]); + + const averagePrice = this.db.$with('average_price').as( + this.db + .select({ + value: sql`avg(${products.price})`.as('value'), + }) + .from(products), + ); + + const result = await this.db + .with(averagePrice) + .update(products) + .set({ + cheap: true, + }) + .where(lt(products.price, sql`(select * from ${averagePrice})`)) + .returning({ + id: products.id, + }); + + expect(result).deep.equal([{ id: 1 }, { id: 4 }, { id: 5 }]); + } catch (error: any) { + console.error(error); + throw new Error(`withUpdate error`); + } + } + + async withInsert(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users', { + username: text('username').notNull(), + admin: integer('admin', { mode: 'boolean' }).notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + this.db.run(sql`create table ${users} (username text not null, admin integer not null default 0)`); + + const userCount = this.db.$with('user_count').as( + this.db + .select({ + value: sql`count(*)`.as('value'), + }) + .from(users), + ); + + const result = await this.db + .with(userCount) + .insert(users) + .values([{ username: 'user1', admin: sql`((select * from ${userCount}) = 0)` }]) + .returning({ + admin: users.admin, + }); + + expect(result).deep.equal([{ admin: true }]); + } catch (error: any) { + console.error(error); + throw new Error(`withInsert error`); + } + } + + async withDelete(): Promise { + try { + await this.beforeEach(); + await this.db.insert(orders).values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const averageAmount = this.db.$with('average_amount').as( + this.db + .select({ + value: sql`avg(${orders.amount})`.as('value'), + }) + .from(orders), + ); + + const result = this.db + .with(averageAmount) + .delete(orders) + .where(gt(orders.amount, sql`(select * from ${averageAmount})`)) + .returning({ + id: orders.id, + }) + .all(); + + expect(result).deep.equal([{ id: 6 }, { id: 7 }, { id: 8 }]); + } catch (error: any) { + console.error(error); + throw new Error(`withDelete error`); + } + } + + async selectFromSubquerySql(): Promise { + try { + await this.beforeEach(); + this.db + .insert(users2Table) + .values([{ name: 'John' }, { name: 'Jane' }]) + .run(); + + const sq = this.db + .select({ name: sql`${users2Table.name} || ' modified'`.as('name') }) + .from(users2Table) + .as('sq'); + + const res = this.db.select({ name: sq.name }).from(sq).all(); + + expect(res).deep.equal([{ name: 'John modified' }, { name: 'Jane modified' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectFromSubquerySql error`); + } + } + + async selectAFieldWithoutJoiningItsTable(): Promise { + try { + await this.beforeEach(); + expect(() => this.db.select({ name: users2Table.name }).from(usersTable).prepare()).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`selectAFieldWithoutJoiningItsTable error`); + } + } + + async selectAllFieldsFromSubqueryWithoutAlias(): Promise { + try { + const sq = this.db.$with('sq').as( + this.db.select({ name: sql`upper(${users2Table.name})` }).from(users2Table), + ); + + expect(() => this.db.select().from(sq).prepare()).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`selectAllFieldsFromSubqueryWithoutAlias error`); + } + } + + async selectCount(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }]) + .run(); + + const res = this.db + .select({ count: sql`count(*)` }) + .from(usersTable) + .all(); + + expect(res).deep.equal([{ count: 2 }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectCount error`); + } + } + + async having(): Promise { + try { + await this.beforeEach(); + this.db + .insert(citiesTable) + .values([{ name: 'London' }, { name: 'Paris' }, { name: 'New York' }]) + .run(); + + this.db + .insert(users2Table) + .values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 1 }, + { name: 'Jack', cityId: 2 }, + ]) + .run(); + + const result = this.db + .select({ + id: citiesTable.id, + name: sql`upper(${citiesTable.name})`.as('upper_name'), + usersCount: sql`count(${users2Table.id})`.as('users_count'), + }) + .from(citiesTable) + .leftJoin(users2Table, eq(users2Table.cityId, citiesTable.id)) + .where(({ name }) => sql`length(${name}) >= 3`) + .groupBy(citiesTable.id) + .having(({ usersCount }) => sql`${usersCount} > 0`) + .orderBy(({ name }) => name) + .all(); + + expect(result).deep.equal([ + { + id: 1, + name: 'LONDON', + usersCount: 2, + }, + { + id: 2, + name: 'PARIS', + usersCount: 1, + }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`having error`); + } + } + + async view(): Promise { + try { + await this.beforeEach(); + const newYorkers1 = sqliteView('new_yorkers').as((qb) => + qb.select().from(users2Table).where(eq(users2Table.cityId, 1)) + ); + + const newYorkers2 = sqliteView('new_yorkers', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }).as(sql`select * from ${users2Table} where ${eq(users2Table.cityId, 1)}`); + + const newYorkers3 = sqliteView('new_yorkers', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }).existing(); + + this.db.run(sql`create view if not exists new_yorkers as ${getViewConfig(newYorkers1).query}`); + + this.db + .insert(citiesTable) + .values([{ name: 'New York' }, { name: 'Paris' }]) + .run(); + + this.db + .insert(users2Table) + .values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 1 }, + { name: 'Jack', cityId: 2 }, + ]) + .run(); + + { + const result = this.db.select().from(newYorkers1).all(); + expect(result).deep.equal([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = this.db.select().from(newYorkers2).all(); + expect(result).deep.equal([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = this.db.select().from(newYorkers3).all(); + expect(result).deep.equal([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = this.db.select({ name: newYorkers1.name }).from(newYorkers1).all(); + expect(result).deep.equal([{ name: 'John' }, { name: 'Jane' }]); + } + + this.db.run(sql`drop view ${newYorkers1}`); + } catch (error: any) { + console.error(error); + throw new Error(`view error`); + } + } + + async insertNullTimestamp(): Promise { + try { + await this.beforeEach(); + const test = sqliteTable('test', { + t: integer('t', { mode: 'timestamp' }), + }); + + this.db.run(sql`create table ${test} (t timestamp)`); + + this.db.insert(test).values({ t: null }).run(); + const res = await this.db.select().from(test).all(); + expect(res).deep.equal([{ t: null }]); + + this.db.run(sql`drop table ${test}`); + } catch (error: any) { + console.error(error); + throw new Error(`insertNullTimestamp error`); + } + } + + async selectFromRawSql(): Promise { + try { + const result = this.db + .select({ + id: sql`id`, + name: sql`name`, + }) + .from(sql`(select 1 as id, 'John' as name) as users`) + .all(); + + Expect>; + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectFromRawSql error`); + } + } + + async selectFromRawSqlWithJoins(): Promise { + try { + await this.beforeEach(); + const result = this.db + .select({ + id: sql`users.id`, + name: sql`users.name`.as('userName'), + userCity: sql`users.city`, + cityName: sql`cities.name`.as('cityName'), + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, sql`cities.id = users.id`) + .all(); + + Expect>; + + expect(result).deep.equal([{ id: 1, name: 'John', userCity: 'New York', cityName: 'Paris' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectFromRawSqlWithJoins error`); + } + } + + async joinOnAliasedSqlFromSelect(): Promise { + try { + await this.beforeEach(); + const result = this.db + .select({ + userId: sql`users.id`.as('userId'), + name: sql`users.name`.as('userName'), + userCity: sql`users.city`, + cityId: sql`cities.id`.as('cityId'), + cityName: sql`cities.name`.as('cityName'), + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, (cols) => eq(cols.cityId, cols.userId)) + .all(); + + Expect< + Equal<{ userId: number; name: string; userCity: string; cityId: number; cityName: string }[], typeof result> + >; + + expect(result).deep.equal([{ userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }]); + } catch (error: any) { + console.error(error); + throw new Error(`joinOnAliasedSqlFromSelect error`); + } + } + + async joinOnAliasedSqlFromWithClause(): Promise { + try { + await this.beforeEach(); + const users = this.db.$with('users').as( + this.db + .select({ + id: sql`id`.as('userId'), + name: sql`name`.as('userName'), + city: sql`city`.as('city'), + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`), + ); + + const cities = this.db.$with('cities').as( + this.db + .select({ + id: sql`id`.as('cityId'), + name: sql`name`.as('cityName'), + }) + .from(sql`(select 1 as id, 'Paris' as name) as cities`), + ); + + const result = this.db + .with(users, cities) + .select({ + userId: users.id, + name: users.name, + userCity: users.city, + cityId: cities.id, + cityName: cities.name, + }) + .from(users) + .leftJoin(cities, (cols) => eq(cols.cityId, cols.userId)) + .all(); + + Expect< + Equal<{ userId: number; name: string; userCity: string; cityId: number; cityName: string }[], typeof result> + >; + + expect(result).deep.equal([{ userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }]); + } catch (error: any) { + console.error(error); + throw new Error(`joinOnAliasedSqlFromWithClause error`); + } + } + + async prefixedTable(): Promise { + try { + await this.beforeEach(); + const sqliteTable = sqliteTableCreator((name) => `myprefix_${name}`); + + const users = sqliteTable('test_prefixed_table_with_unique_name', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run( + sql`create table myprefix_test_prefixed_table_with_unique_name (id integer not null primary key, name text not null)`, + ); + + this.db.insert(users).values({ id: 1, name: 'John' }).run(); + + const result = this.db.select().from(users).all(); + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`prefixedTable error`); + } + } + + async orderByWithAliasedColumn(): Promise { + try { + await this.beforeEach(); + const query = this.db + .select({ + test: sql`something`.as('test'), + }) + .from(users2Table) + .orderBy((fields) => fields.test) + .toSQL(); + + expect(query.sql).equal('select something as "test" from "users2" order by "test"'); + } catch (error: any) { + console.error(error); + throw new Error(`orderByWithAliasedColumn error`); + } + } + + async transaction(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users_transactions', { + id: integer('id').primaryKey(), + balance: integer('balance').notNull(), + }); + const products = sqliteTable('products_transactions', { + id: integer('id').primaryKey(), + price: integer('price').notNull(), + stock: integer('stock').notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + this.db.run(sql`drop table if exists ${products}`); + + this.db.run(sql`create table users_transactions (id integer not null primary key, balance integer not null)`); + this.db.run( + sql`create table products_transactions (id integer not null primary key, price integer not null, stock integer not null)`, + ); + + const user = this.db.insert(users).values({ balance: 100 }).returning().get(); + const product = this.db.insert(products).values({ price: 10, stock: 10 }).returning().get(); + + this.db.transaction(async (tx) => { + tx.update(users) + .set({ balance: user.balance - product.price }) + .where(eq(users.id, user.id)) + .run(); + tx.update(products) + .set({ stock: product.stock - 1 }) + .where(eq(products.id, product.id)) + .run(); + }); + + const result = this.db.select().from(users).all(); + + expect(result).deep.equal([{ id: 1, balance: 90 }]); + + this.db.run(sql`drop table ${users}`); + this.db.run(sql`drop table ${products}`); + } catch (error: any) { + console.error(error); + throw new Error(`transaction error`); + } + } + + // async transactionRollback(): Promise{ + // const users = sqliteTable('users_transactions_rollback', { + // id: integer('id').primaryKey(), + // balance: integer('balance').notNull(), + // }); + + // this.db.run(sql`drop table if exists ${users}`); + + // this.db.run( + // sql`create table users_transactions_rollback (id integer not null primary key, balance integer not null)`, + // ); + // await expect(async () => { + // this.db.transaction(async (tx) => { + // tx.insert(users).values({ balance: 100 }).run(); + // tx.rollback(); + // }); + // }).re(TransactionRollbackError); + + // const result = await db.select().from(users).all(); + + // expect(result).toEqual([]); + + // await db.run(sql`drop table ${users}`); + // }; + + async nestedTransaction(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users_nested_transactions', { + id: integer('id').primaryKey(), + balance: integer('balance').notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run( + sql`create table users_nested_transactions (id integer not null primary key, balance integer not null)`, + ); + + this.db.transaction((tx) => { + tx.insert(users).values({ balance: 100 }).run(); + + tx.transaction((tx) => { + tx.update(users).set({ balance: 200 }).run(); + }); + }); + + const result = this.db.select().from(users).all(); + + expect(result).deep.equal([{ id: 1, balance: 200 }]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`nestedTransaction error`); + } + } + + // async nestedTransactionRollback(): Promise{ + // const users = sqliteTable('users_nested_transactions_rollback', { + // id: integer('id').primaryKey(), + // balance: integer('balance').notNull(), + // }); + + // this.db.run(sql`drop table if exists ${users}`); + + // this.db.run( + // sql`create table users_nested_transactions_rollback (id integer not null primary key, balance integer not null)`, + // ); + + // this.db.transaction((tx) => { + // this.tx.insert(users).values({ balance: 100 }).run(); + + // expect(async () => { + // await tx.transaction(async (tx) => { + // await tx.update(users).set({ balance: 200 }).run(); + // tx.rollback(); + // }); + // }).rejects.toThrowError(TransactionRollbackError); + // }); + + // const result = await db.select().from(users).all(); + + // expect(result).toEqual([{ id: 1, balance: 100 }]); + + // await db.run(sql`drop table ${users}`); + // }; + + async joinSubqueryWithJoin(): Promise { + try { + await this.beforeEach(); + const internalStaff = sqliteTable('internal_staff', { + userId: integer('user_id').notNull(), + }); + + const customUser = sqliteTable('custom_user', { + id: integer('id').notNull(), + }); + + const ticket = sqliteTable('ticket', { + staffId: integer('staff_id').notNull(), + }); + + this.db.run(sql`drop table if exists ${internalStaff}`); + this.db.run(sql`drop table if exists ${customUser}`); + this.db.run(sql`drop table if exists ${ticket}`); + + this.db.run(sql`create table internal_staff (user_id integer not null)`); + this.db.run(sql`create table custom_user (id integer not null)`); + this.db.run(sql`create table ticket (staff_id integer not null)`); + + this.db.insert(internalStaff).values({ userId: 1 }).run(); + this.db.insert(customUser).values({ id: 1 }).run(); + this.db.insert(ticket).values({ staffId: 1 }).run(); + + const subq = this.db.select().from(internalStaff).leftJoin(customUser, eq(internalStaff.userId, customUser.id)) + .as('internal_staff'); + + const mainQuery = this.db.select().from(ticket).leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)) + .all(); + + expect(mainQuery).deep.equal([ + { + ticket: { staffId: 1 }, + internal_staff: { + internal_staff: { userId: 1 }, + custom_user: { id: 1 }, + }, + }, + ]); + + this.db.run(sql`drop table ${internalStaff}`); + this.db.run(sql`drop table ${customUser}`); + this.db.run(sql`drop table ${ticket}`); + } catch (error: any) { + console.error(error); + throw new Error(`joinSubqueryWithJoin error`); + } + } + + async joinViewAsSubquery(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users_join_view', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }); + + const newYorkers = sqliteView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + this.db.run(sql`drop table if exists ${users}`); + this.db.run(sql`drop view if exists ${newYorkers}`); + + this.db.run( + sql`create table ${users} (id integer not null primary key, name text not null, city_id integer not null)`, + ); + this.db.run(sql`create view if not exists ${newYorkers} as ${getViewConfig(newYorkers).query}`); + + this.db + .insert(users) + .values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + { name: 'Jack', cityId: 1 }, + { name: 'Jill', cityId: 2 }, + ]) + .run(); + + const sq = this.db.select().from(newYorkers).as('new_yorkers_sq'); + + const result = await this.db.select().from(users).leftJoin(sq, eq(users.id, sq.id)).all(); + + expect(result).deep.equal([ + { + users_join_view: { id: 1, name: 'John', cityId: 1 }, + new_yorkers_sq: { id: 1, name: 'John', cityId: 1 }, + }, + { + users_join_view: { id: 2, name: 'Jane', cityId: 2 }, + new_yorkers_sq: null, + }, + { + users_join_view: { id: 3, name: 'Jack', cityId: 1 }, + new_yorkers_sq: { id: 3, name: 'Jack', cityId: 1 }, + }, + { + users_join_view: { id: 4, name: 'Jill', cityId: 2 }, + new_yorkers_sq: null, + }, + ]); + + this.db.run(sql`drop view ${newYorkers}`); + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`joinViewAsSubquery error`); + } + } + + async insertWithOnConflictDoNothing(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ id: 1, name: 'John' }).run(); + + this.db.insert(usersTable).values({ id: 1, name: 'John' }).onConflictDoNothing().run(); + + const res = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ).all(); + + expect(res).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoNothing error`); + } + } + + async insertWithOnConflictDoNothinUsingCompositePk(): Promise { + try { + await this.beforeEach(); + this.db.insert(pkExampleTable).values({ id: 1, name: 'John', email: 'john@example.com' }).run(); + + this.db.insert(pkExampleTable).values({ id: 1, name: 'John', email: 'john1@example.com' }).onConflictDoNothing() + .run(); + + const res = await this.db + .select({ id: pkExampleTable.id, name: pkExampleTable.name, email: pkExampleTable.email }) + .from(pkExampleTable) + .where(eq(pkExampleTable.id, 1)) + .all(); + + expect(res).deep.equal([{ id: 1, name: 'John', email: 'john@example.com' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoNothinUsingCompositePk error`); + } + } + + async insertWithOnConflictDoNothingUsingTarget(): Promise { + try { + this.db.insert(usersTable).values({ id: 1, name: 'John' }).run(); + + this.db.insert(usersTable).values({ id: 1, name: 'John' }).onConflictDoNothing({ target: usersTable.id }).run(); + + const res = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ).all(); + + expect(res).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoNothingUsingTarget error`); + } + } + + async insertWithOnConflictDoNothingUsingCompositePkAsTarget(): Promise { + try { + await this.beforeEach(); + this.db.insert(pkExampleTable).values({ id: 1, name: 'John', email: 'john@example.com' }).run(); + + this.db + .insert(pkExampleTable) + .values({ id: 1, name: 'John', email: 'john1@example.com' }) + .onConflictDoNothing({ target: [pkExampleTable.id, pkExampleTable.name] }) + .run(); + + const res = this.db + .select({ id: pkExampleTable.id, name: pkExampleTable.name, email: pkExampleTable.email }) + .from(pkExampleTable) + .where(eq(pkExampleTable.id, 1)) + .all(); + + expect(res).deep.equal([{ id: 1, name: 'John', email: 'john@example.com' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoNothingUsingCompositePkAsTarget error`); + } + } + + async insertWithOnConflictDoUpdate(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ id: 1, name: 'John' }).run(); + + this.db + .insert(usersTable) + .values({ id: 1, name: 'John' }) + .onConflictDoUpdate({ target: usersTable.id, set: { name: 'John1' } }) + .run(); + + const res = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ).all(); + + expect(res).deep.equal([{ id: 1, name: 'John1' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoUpdate error`); + } + } + + async insertWithOnConflictDoUpdateWhere(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ id: 1, name: 'John', verified: false }]) + .run(); + + this.db + .insert(usersTable) + .values({ id: 1, name: 'John1', verified: true }) + .onConflictDoUpdate({ + target: usersTable.id, + set: { name: 'John1', verified: true }, + where: eq(usersTable.verified, false), + }) + .run(); + + const res = this.db + .select({ id: usersTable.id, name: usersTable.name, verified: usersTable.verified }) + .from(usersTable) + .where(eq(usersTable.id, 1)) + .all(); + + expect(res).deep.equal([{ id: 1, name: 'John1', verified: true }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoUpdateWhere error`); + } + } + + async insertWithOnConflictDoUpdateUsingCompositePk(): Promise { + try { + await this.beforeEach(); + this.db.insert(pkExampleTable).values({ id: 1, name: 'John', email: 'john@example.com' }).run(); + + this.db + .insert(pkExampleTable) + .values({ id: 1, name: 'John', email: 'john@example.com' }) + .onConflictDoUpdate({ target: [pkExampleTable.id, pkExampleTable.name], set: { email: 'john1@example.com' } }) + .run(); + + const res = this.db + .select({ id: pkExampleTable.id, name: pkExampleTable.name, email: pkExampleTable.email }) + .from(pkExampleTable) + .where(eq(pkExampleTable.id, 1)) + .all(); + + expect(res).deep.equal([{ id: 1, name: 'John', email: 'john1@example.com' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoUpdateUsingCompositePk error`); + } + } + + async insertUndefined(): Promise { + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run( + sql`create table ${users} (id integer primary key, name text)`, + ); + + expect((() => { + this.db.insert(users).values({ name: undefined }).run(); + })()).not.throw(); + + this.db.run(sql`drop table ${users}`); + } + + async updateUndefined(): Promise { + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run( + sql`create table ${users} (id integer primary key, name text)`, + ); + + expect((() => { + this.db.update(users).set({ name: undefined }).run(); + })()).throw(); + expect((() => { + this.db.update(users).set({ id: 1, name: undefined }).run(); + })()).not.throw(); + + this.db.run(sql`drop table ${users}`); + } + + async apiCRUD(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text)`); + + this.db.insert(users).values({ id: 1, name: 'John' }).run(); + + const res = this.db.select().from(users).all(); + + expect(res).deep.equal([{ id: 1, name: 'John' }]); + + this.db.update(users).set({ name: 'John1' }).where(eq(users.id, 1)).all(); + + const res1 = this.db.select().from(users).all(); + + expect(res1).deep.equal([{ id: 1, name: 'John1' }]); + + this.db.delete(users).where(eq(users.id, 1)).run(); + + const res2 = this.db.select().from(users).all(); + + expect(res2).deep.equal([]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`apiCRUD error`); + } + } + + async apiInsertPlusSelectPreparePlusAsyncExecute(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text)`); + + const insertStmt = this.db.insert(users).values({ id: 1, name: 'John' }).prepare(); + insertStmt.execute().sync(); + + const selectStmt = this.db.select().from(users).prepare(); + const res = selectStmt.execute().sync(); + + expect(res).deep.equal([{ id: 1, name: 'John' }]); + + const updateStmt = this.db.update(users).set({ name: 'John1' }).where(eq(users.id, 1)).prepare(); + updateStmt.execute().sync(); + + const res1 = selectStmt.execute().sync(); + + expect(res1).deep.equal([{ id: 1, name: 'John1' }]); + + const deleteStmt = this.db.delete(users).where(eq(users.id, 1)).prepare(); + deleteStmt.execute().sync(); + + const res2 = selectStmt.execute().sync(); + + expect(res2).deep.equal([]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`apiInsertPlusSelectPreparePlusAsyncExecute error`); + } + } + + async apiInsertSelectPreparePlusSyncExecute(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text)`); + + const insertStmt = this.db.insert(users).values({ id: 1, name: 'John' }).prepare(); + insertStmt.execute().sync(); + + const selectStmt = this.db.select().from(users).prepare(); + const res = selectStmt.execute().sync(); + + expect(res).deep.equal([{ id: 1, name: 'John' }]); + + const updateStmt = this.db.update(users).set({ name: 'John1' }).where(eq(users.id, 1)).prepare(); + updateStmt.execute().sync(); + + const res1 = selectStmt.execute().sync(); + + expect(res1).deep.equal([{ id: 1, name: 'John1' }]); + + const deleteStmt = this.db.delete(users).where(eq(users.id, 1)).prepare(); + deleteStmt.execute().sync(); + + const res2 = selectStmt.execute().sync(); + + expect(res2).deep.equal([]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`apiInsertSelectPreparePlusSyncExecute error`); + } + } + + async selectPlusGetForEmptyResult(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text)`); + + const res = this.db.select().from(users).where(eq(users.id, 1)).get(); + + expect(res).eq(undefined); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`selectPlusGetForEmptyResult error`); + } + } + + async setOperationsUnionFromQueryBuilderWithSubquery(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const sq = this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable) + .union(this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table)) + .orderBy(asc(sql`name`)) + .as('sq'); + + const result = await this.db.select().from(sq).limit(5).offset(5); + + expect(result).length(5); + + expect(result).deep.equal([ + { id: 2, name: 'London' }, + { id: 7, name: 'Mary' }, + { id: 1, name: 'New York' }, + { id: 4, name: 'Peter' }, + { id: 8, name: 'Sally' }, + ]); + + expect(() => { + this.db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).union( + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table), + ).orderBy(asc(sql`name`)).all(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsUnionFromQueryBuilderWithSubquery error`); + } + } + + async setOperationsUnionAsFunction(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = union( + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable).where(eq(citiesTable.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`name`)).all(); + + expect(result).length(2); + + expect(result).deep.equal([ + { id: 1, name: 'John' }, + { id: 1, name: 'New York' }, + ]); + + expect(() => { + union( + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + this.db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`name`)).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsUnionAsFunction error`); + } + } + + async setOperationsUnionAllFromQueryBuilder(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable) + .unionAll(this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable)) + .orderBy(asc(citiesTable.id)) + .limit(5) + .offset(1).all(); + + expect(result).length(5); + + expect(result).deep.equal([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + { id: 3, name: 'Tampa' }, + ]); + + expect(() => { + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).unionAll( + this.db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable), + ).orderBy(asc(citiesTable.id)).limit(5).offset(1).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsUnionAllFromQueryBuilder error`); + } + } + + async setOperationsUnionAllAsFunction(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = unionAll( + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable).where(eq(citiesTable.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + ).all(); + + expect(result).length(3); + + expect(result).deep.equal([ + { id: 1, name: 'New York' }, + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + ]); + + expect(() => { + unionAll( + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + this.db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsUnionAllAsFunction error`); + } + } + + async setOperationsIntersectFromQueryBuilder(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable) + .intersect( + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable).where(gt(citiesTable.id, 1)), + ) + .orderBy(asc(sql`name`)).all(); + + expect(result).length(2); + + expect(result).deep.equal([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + expect(() => { + this.db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).intersect( + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`name`)).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsIntersectFromQueryBuilder error`); + } + } + + async setOperationsIntersectAsFunction(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = intersect( + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable).where(eq(citiesTable.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + ).all(); + + expect(result).length(0); + + expect(result).deep.equal([]); + + expect(() => { + intersect( + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + this.db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsIntersectAsFunction error`); + } + } + + async setOperationsExceptFromQueryBuilder(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = this.db + .select() + .from(citiesTable) + .except(this.db.select().from(citiesTable).where(gt(citiesTable.id, 1))).all(); + + expect(result).length(1); + + expect(result).deep.equal([{ id: 1, name: 'New York' }]); + + expect(() => { + this.db + .select() + .from(citiesTable).except( + this.db + .select({ name: users2Table.name, id: users2Table.id }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsExceptFromQueryBuilder error`); + } + } + + async setOperationsExceptAsFunction(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = except( + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable), + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable).where(eq(citiesTable.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`id`)).all(); + + expect(result).length(2); + + expect(result).deep.equal([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + expect(() => { + except( + this.db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable), + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`id`)).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsExceptAsFunction error`); + } + } + + async setOperationsMixedFromQueryBuilder(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = this.db + .select() + .from(citiesTable) + .except(({ unionAll }) => + unionAll( + this.db.select().from(citiesTable).where(gt(citiesTable.id, 1)), + this.db.select().from(citiesTable).where(eq(citiesTable.id, 2)), + ) + ).all(); + + expect(result).length(2); + + expect(result).deep.equal([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + ]); + + expect(() => { + this.db + .select() + .from(citiesTable).except( + ({ unionAll }) => + unionAll( + this.db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + this.db.select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).where(eq(citiesTable.id, 2)), + ), + ).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsMixedFromQueryBuilder error`); + } + } + + async setOperationsMixedAllAsFunctionWithSubquery(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const sq = union( + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + except( + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where( + gte(users2Table.id, 5), + ), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 7)), + ), + this.db.select().from(citiesTable).where(gt(citiesTable.id, 1)), + ) + .orderBy(asc(sql`id`)) + .as('sq'); + + const result = await this.db.select().from(sq).limit(4).offset(1); + + expect(result).length(4); + + expect(result).deep.equal([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + { id: 5, name: 'Ben' }, + { id: 6, name: 'Jill' }, + ]); + + expect(() => { + union( + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + except( + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 7)), + ), + this.db + .select({ name: users2Table.name, id: users2Table.id }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`id`)).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsMixedAllAsFunctionWithSubquery error`); + } + } + + async aggregateFunctionCount(): Promise { + try { + await this.beforeEach(); + const table = aggregateTable; + await setupAggregateFunctionsTest(this.db); + + const result1 = await this.db.select({ value: count() }).from(table); + const result2 = await this.db.select({ value: count(table.a) }).from(table); + const result3 = await this.db.select({ value: countDistinct(table.name) }).from(table); + + expect(result1[0]?.value).eq(7); + expect(result2[0]?.value).eq(5); + expect(result3[0]?.value).eq(6); + } catch (error: any) { + console.error(error); + throw new Error(`aggregateFunctionCount error`); + } + } + + async aggregatFunctionAvg(): Promise { + try { + await this.beforeEach(); + const table = aggregateTable; + await setupAggregateFunctionsTest(this.db); + + const result1 = await this.db.select({ value: avg(table.a) }).from(table); + const result2 = await this.db.select({ value: avg(table.nullOnly) }).from(table); + const result3 = await this.db.select({ value: avgDistinct(table.b) }).from(table); + + expect(result1[0]?.value).eq('24'); + expect(result2[0]?.value).eq(null); + expect(result3[0]?.value).eq('42.5'); + } catch (error: any) { + console.error(error); + throw new Error(`aggregatFunctionAvg error`); + } + } + + async aggregateFunctionSum(): Promise { + try { + await this.beforeEach(); + const table = aggregateTable; + await setupAggregateFunctionsTest(this.db); + + const result1 = await this.db.select({ value: sum(table.b) }).from(table); + const result2 = await this.db.select({ value: sum(table.nullOnly) }).from(table); + const result3 = await this.db.select({ value: sumDistinct(table.b) }).from(table); + + expect(result1[0]?.value).eq('200'); + expect(result2[0]?.value).eq(null); + expect(result3[0]?.value).eq('170'); + } catch (error: any) { + console.error(error); + throw new Error(`aggregateFunctionSum error`); + } + } + + async aggregateFunctionMax(): Promise { + try { + await this.beforeEach(); + const table = aggregateTable; + await setupAggregateFunctionsTest(this.db); + + const result1 = await this.db.select({ value: max(table.b) }).from(table); + const result2 = await this.db.select({ value: max(table.nullOnly) }).from(table); + + expect(result1[0]?.value).eq(90); + expect(result2[0]?.value).eq(null); + } catch (error: any) { + console.error(error); + throw new Error(`aggregateFunctionMax error`); + } + } + + async aggregateFunctionMin(): Promise { + try { + await this.beforeEach(); + const table = aggregateTable; + await setupAggregateFunctionsTest(this.db); + + const result1 = await this.db.select({ value: min(table.b) }).from(table); + const result2 = await this.db.select({ value: min(table.nullOnly) }).from(table); + + expect(result1[0]?.value).eq(10); + expect(result2[0]?.value).eq(null); + } catch (error: any) { + console.error(error); + throw new Error(`aggregateFunctionMin error`); + } + } + + async test$onUpdateFnAnd$onUpdateWorksAs$default(): Promise { + try { + await this.beforeEach(); + this.db.run(sql`drop table if exists ${usersOnUpdate}`); + + this.db.run( + sql` + create table ${usersOnUpdate} ( + id integer primary key autoincrement, + name text not null, + update_counter integer default 1 not null, + updated_at integer, + always_null text + ) + `, + ); + + this.db + .insert(usersOnUpdate) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jack' }, { name: 'Jill' }]) + .run(); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + + const justDates = await this.db.select({ updatedAt }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + const response = await this.db + .select({ ...rest }) + .from(usersOnUpdate) + .orderBy(asc(usersOnUpdate.id)); + + expect(response).deep.equal([ + { name: 'John', id: 1, updateCounter: 1, alwaysNull: null }, + { name: 'Jane', id: 2, updateCounter: 1, alwaysNull: null }, + { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, + { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, + ]); + const msDelay = 250; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).greaterThan(Date.now() - msDelay); + } + } catch (error: any) { + console.error(error); + throw new Error(`test$onUpdateFnAnd$onUpdateWorksAs$default error`); + } + } + + async test$onUpdateFnAnd$onUpdateWorksUpdating(): Promise { + try { + await this.beforeEach(); + this.db.run(sql`drop table if exists ${usersOnUpdate}`); + + this.db.run( + sql` + create table ${usersOnUpdate} ( + id integer primary key autoincrement, + name text not null, + update_counter integer default 1, + updated_at integer, + always_null text + ) + `, + ); + + await this.db + .insert(usersOnUpdate) + .values([{ name: 'John', alwaysNull: 'this will be null after updating' }, { name: 'Jane' }, { name: 'Jack' }, { + name: 'Jill', + }]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + + await this.db.update(usersOnUpdate).set({ name: 'Angel' }).where(eq(usersOnUpdate.id, 1)); + await this.db.update(usersOnUpdate).set({ updateCounter: null }).where(eq(usersOnUpdate.id, 2)); + + const justDates = await this.db.select({ updatedAt }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + const response = await this.db + .select({ ...rest }) + .from(usersOnUpdate) + .orderBy(asc(usersOnUpdate.id)); + + expect(response).deep.equal([ + { name: 'Angel', id: 1, updateCounter: 2, alwaysNull: null }, + { name: 'Jane', id: 2, updateCounter: null, alwaysNull: null }, + { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, + { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, + ]); + const msDelay = 250; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).greaterThan(Date.now() - msDelay); + } + } catch (error: any) { + console.error(error); + throw new Error(`test$onUpdateFnAnd$onUpdateWorksUpdating error`); + } + } + + async $countSeparate(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await this.db.$count(countTestTable); + + this.db.run(sql`drop table ${countTestTable}`); + + expect(count).eq(4); + } catch (error: any) { + console.error(error); + throw new Error(`$countSeparate error`); + } + } + + async $countEmbedded(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await this.db + .select({ + count: this.db.$count(countTestTable), + }) + .from(countTestTable); + + this.db.run(sql`drop table ${countTestTable}`); + + expect(count).deep.equal([{ count: 4 }, { count: 4 }, { count: 4 }, { count: 4 }]); + } catch (error: any) { + console.error(error); + throw new Error(`$countEmbedded error`); + } + } + + async $countSeparateReuse(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = this.db.$count(countTestTable); + + const count1 = await count; + + await this.db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await this.db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + this.db.run(sql`drop table ${countTestTable}`); + + expect(count1).eq(4); + expect(count2).eq(5); + expect(count3).eq(6); + } catch (error: any) { + console.error(error); + throw new Error(`$countSeparateReuse error`); + } + } + + async $countEmbeddedReuse(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = this.db + .select({ + count: this.db.$count(countTestTable), + }) + .from(countTestTable); + + const count1 = await count; + + await this.db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await this.db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + this.db.run(sql`drop table ${countTestTable}`); + + expect(count1).deep.equal([{ count: 4 }, { count: 4 }, { count: 4 }, { count: 4 }]); + expect(count2).deep.equal([{ count: 5 }, { count: 5 }, { count: 5 }, { count: 5 }, { count: 5 }]); + expect(count3).deep.equal([{ count: 6 }, { count: 6 }, { count: 6 }, { count: 6 }, { count: 6 }, { count: 6 }]); + } catch (error: any) { + console.error(error); + throw new Error(`$countEmbeddedReuse error`); + } + } + + async $countSeparateWithFilters(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await this.db.$count(countTestTable, gt(countTestTable.id, 1)); + + this.db.run(sql`drop table ${countTestTable}`); + + expect(count).deep.equal(3); + } catch (error: any) { + console.error(error); + throw new Error(`$countSeparateWithFilters error`); + } + } + + async $countEmbeddedWithFilters(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await this.db + .select({ + count: this.db.$count(countTestTable, gt(countTestTable.id, 1)), + }) + .from(countTestTable); + + await this.db.run(sql`drop table ${countTestTable}`); + + expect(count).deep.equal([{ count: 3 }, { count: 3 }, { count: 3 }, { count: 3 }]); + } catch (error: any) { + console.error(error); + throw new Error(`$countEmbeddedWithFilters error`); + } + } + + async updateWithLimitAndOrderBy(): Promise { + try { + await this.beforeEach(); + await this.db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await this.db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); + + const result = await this.db + .select({ name: usersTable.name, verified: usersTable.verified }) + .from(usersTable) + .orderBy(asc(usersTable.name)); + + expect(result).deep.equal([ + { name: 'Alan', verified: true }, + { name: 'Barry', verified: true }, + { name: 'Carl', verified: false }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`updateWithLimitAndOrderBy error`); + } + } + + async deleteWithLimitAndOrderBy(): Promise { + try { + await this.beforeEach(); + await this.db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await this.db.delete(usersTable).where(eq(usersTable.verified, false)).limit(1).orderBy(asc(usersTable.name)); + + const result = await this.db + .select({ name: usersTable.name, verified: usersTable.verified }) + .from(usersTable) + .orderBy(asc(usersTable.name)); + expect(result).deep.equal([ + { name: 'Barry', verified: false }, + { name: 'Carl', verified: false }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`deleteWithLimitAndOrderBy error`); + } + } +} + +export default { + /** + * This is the standard fetch handler for a Cloudflare Worker + * + * @param request - The request submitted to the Worker from the client + * @param env - The interface to reference bindings declared in wrangler.toml + * @param ctx - The execution context of the Worker + * @returns The response to be sent back to the client + */ + async fetch(request, env): Promise { + try { + const id: DurableObjectId = env.MY_DURABLE_OBJECT.idFromName('durable-object'); + const stub = env.MY_DURABLE_OBJECT.get(id); + + await stub.migrate1(); + + await stub.insertBigIntValues(); + + await stub.selectAllFields(); + await stub.selectPartial(); + await stub.selectSql(); + await stub.selectTypedSql(); + await stub.selectWithEmptyArrayInInArray(); + await stub.selectWithEmptyArrayInNotInArray(); + await stub.selectDistinct(); + await stub.returingSql(); + await stub.$defaultFunction(); + await stub.deleteReturningSql(); + await stub.queryCheckInsertSingleEmptyRow(); + await stub.queryCheckInsertMultipleEmptyRow(); + await stub.insertAllDefaultsIn1Row(); + await stub.insertAllDefaultsInMultipleRows(); + await stub.updateReturningSql(); + await stub.insertWithAutoIncrement(); + await stub.insertDataWithDefaultValues(); + await stub.insertDataWithOverridenDefaultValues(); + await stub.updateWithReturningFields(); + await stub.updateWithReturningPartial(); + await stub.updateWithReturningAllFields(); + await stub.deleteWithReturningPartial(); + await stub.insertAndSelect(); + + await stub.jsonInsert(); + await stub.insertMany(); + await stub.insertManyWithReturning(); + + await stub.partialJoinWithAlias(); + await stub.fullJoinWithAlias(); + await stub.selectFromAlias(); + await stub.insertWithSpaces(); + await stub.preparedStatement(); + await stub.preparedStatementReuse(); + await stub.insertPlaceholdersOnColumnsWithEncoder(); + await stub.preparedStatementWithPlaceholderInWhere(); + await stub.preparedStatementWithPlaceholderInLimit(); + await stub.preparedStatementWithPlaceholderInOffset(); + await stub.preparedStatementBuiltUsing$dynamic(); + + await stub.selectWithGroupByAsField(); + await stub.selectWithExists(); + await stub.selectWithGroupByAsSql(); + await stub.selectWithGroupByAsSqlPlusColumn(); + await stub.selectWithGroupByAsColumnPlusSql(); + await stub.selectWithGroupByComplexQuery(); + await stub.buildQuery(); + await stub.insertViaDbRunPlusSelectViaDbAll(); + await stub.insertViaDbGet(); + await stub.insertViaDbRunPlusSelectViaDbGet(); + await stub.insertViaDbGetQueryBuilder(); + await stub.joinSubquery(); + await stub.withSelect(); + await stub.withUpdate(); + await stub.withInsert(); + + await stub.withDelete(); + await stub.selectFromSubquerySql(); + await stub.selectAFieldWithoutJoiningItsTable(); + await stub.selectCount(); + await stub.having(); + await stub.insertNullTimestamp(); + await stub.selectFromRawSql(); + await stub.selectFromRawSqlWithJoins(); + await stub.joinOnAliasedSqlFromSelect(); + await stub.joinOnAliasedSqlFromWithClause(); + await stub.prefixedTable(); + await stub.orderByWithAliasedColumn(); + await stub.transaction(); + await stub.nestedTransaction(); + await stub.joinSubqueryWithJoin(); + await stub.joinViewAsSubquery(); + await stub.insertWithOnConflictDoNothing(); + await stub.insertWithOnConflictDoNothinUsingCompositePk(); + await stub.insertWithOnConflictDoNothingUsingTarget(); + await stub.insertWithOnConflictDoNothingUsingCompositePkAsTarget(); + await stub.insertWithOnConflictDoUpdate(); + await stub.insertWithOnConflictDoUpdateWhere(); + await stub.insertWithOnConflictDoUpdateUsingCompositePk(); + await stub.apiCRUD(); + await stub.apiInsertPlusSelectPreparePlusAsyncExecute(); + await stub.apiInsertSelectPreparePlusSyncExecute(); + await stub.selectPlusGetForEmptyResult(); + await stub.setOperationsUnionFromQueryBuilderWithSubquery(); + await stub.setOperationsUnionAsFunction(); + await stub.setOperationsUnionAllFromQueryBuilder(); + await stub.setOperationsUnionAllAsFunction(); + await stub.setOperationsIntersectFromQueryBuilder(); + await stub.setOperationsIntersectAsFunction(); + await stub.setOperationsExceptFromQueryBuilder(); + await stub.setOperationsExceptAsFunction(); + await stub.setOperationsMixedFromQueryBuilder(); + await stub.setOperationsMixedAllAsFunctionWithSubquery(); + await stub.aggregateFunctionCount(); + await stub.aggregatFunctionAvg(); + await stub.aggregateFunctionSum(); + await stub.aggregateFunctionMax(); + await stub.aggregateFunctionMin(); + await stub.test$onUpdateFnAnd$onUpdateWorksAs$default(); + await stub.test$onUpdateFnAnd$onUpdateWorksUpdating(); + await stub.$countSeparate(); + await stub.$countEmbedded(); + await stub.$countEmbeddedReuse(); + await stub.$countSeparateWithFilters(); + await stub.$countEmbeddedWithFilters(); + await stub.updateWithLimitAndOrderBy(); + await stub.deleteWithLimitAndOrderBy(); + await stub.updateUndefined(); + await stub.insertUndefined(); + + return new Response(); + } catch (error: any) { + return new Response(error.message); + } + }, +} satisfies ExportedHandler; diff --git a/integration-tests/tests/sqlite/durable-objects/worker-configuration.d.ts b/integration-tests/tests/sqlite/durable-objects/worker-configuration.d.ts new file mode 100644 index 000000000..cab87a7b0 --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/worker-configuration.d.ts @@ -0,0 +1,5 @@ +// Generated by Wrangler by running `wrangler types` + +interface Env { + MY_DURABLE_OBJECT: DurableObjectNamespace; +} diff --git a/integration-tests/tests/sqlite/durable-objects/wrangler.toml b/integration-tests/tests/sqlite/durable-objects/wrangler.toml new file mode 100644 index 000000000..7e3ea736c --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/wrangler.toml @@ -0,0 +1,25 @@ +#:schema node_modules/wrangler/config-schema.json +name = "sqlite-durable-objects" +main = "index.ts" +compatibility_date = "2024-11-12" +compatibility_flags = [ "nodejs_compat" ] + +# Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model. +# Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps. +# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects +[[durable_objects.bindings]] +name = "MY_DURABLE_OBJECT" +class_name = "MyDurableObject" + +# Durable Object migrations. +# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations +[[migrations]] +tag = "v1" +new_sqlite_classes = ["MyDurableObject"] + +[[rules]] +type = "Text" +globs = ["**/*.sql"] +fallthrough = true + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fb912db04..b2e709993 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,7 +40,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241112.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -304,8 +304,8 @@ importers: specifier: ^3.549.0 version: 3.583.0 '@cloudflare/workers-types': - specifier: ^4.20230904.0 - version: 4.20240512.0 + specifier: ^4.20241112.0 + version: 4.20241112.0 '@electric-sql/pglite': specifier: ^0.2.12 version: 0.2.12 @@ -318,12 +318,15 @@ importers: '@miniflare/d1': specifier: ^2.14.4 version: 2.14.4 + '@miniflare/durable-objects': + specifier: ^2.14.4 + version: 2.14.4 '@neondatabase/serverless': specifier: ^0.10.0 version: 0.10.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -371,7 +374,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^14.0.0 - version: 14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + version: 14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -2041,15 +2044,15 @@ packages: cpu: [x64] os: [win32] - '@cloudflare/workers-types@4.20240512.0': - resolution: {integrity: sha512-o2yTEWg+YK/I1t/Me+dA0oarO0aCbjibp6wSeaw52DSE9tDyKJ7S+Qdyw/XsMrKn4t8kF6f/YOba+9O4MJfW9w==} - '@cloudflare/workers-types@4.20240524.0': resolution: {integrity: sha512-GpSr4uE7y39DU9f0+wmrL76xd03wn0jy1ClITaa3ZZltKjirAV8TW1GzHrvvKyVGx6u3lekrFnB1HzVHsCYHDQ==} '@cloudflare/workers-types@4.20241004.0': resolution: {integrity: sha512-3LrPvtecs4umknOF1bTPNLHUG/ZjeSE6PYBQ/tbO7lwaVhjZTaTugiaCny2byrZupBlVNuubQVktcAgMfw0C1A==} + '@cloudflare/workers-types@4.20241112.0': + resolution: {integrity: sha512-Q4p9bAWZrX14bSCKY9to19xl0KMU7nsO5sJ2cTVspHoypsjPUMeQCsjHjmsO2C4Myo8/LPeDvmqFmkyNAPPYZw==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -3305,6 +3308,10 @@ packages: resolution: {integrity: sha512-pMBVq9XWxTDdm+RRCkfXZP+bREjPg1JC8s8C0JTovA9OGmLQXqGTnFxIaS9vf1d8k3uSUGhDzPTzHr0/AUW1gA==} engines: {node: '>=16.7'} + '@miniflare/durable-objects@2.14.4': + resolution: {integrity: sha512-+JrmHP6gHHrjxV8S3axVw5lGHLgqmAGdcO/1HJUPswAyJEd3Ah2YnKhpo+bNmV4RKJCtEq9A2hbtVjBTD2YzwA==} + engines: {node: '>=16.13'} + '@miniflare/queues@2.14.4': resolution: {integrity: sha512-aXQ5Ik8Iq1KGMBzGenmd6Js/jJgqyYvjom95/N9GptCGpiVWE5F0XqC1SL5rCwURbHN+aWY191o8XOFyY2nCUA==} engines: {node: '>=16.7'} @@ -3313,6 +3320,10 @@ packages: resolution: {integrity: sha512-upl4RSB3hyCnITOFmRZjJj4A72GmkVrtfZTilkdq5Qe5TTlzsjVeDJp7AuNUM9bM8vswRo+N5jOiot6O4PVwwQ==} engines: {node: '>=16.13'} + '@miniflare/storage-memory@2.14.4': + resolution: {integrity: sha512-9jB5BqNkMZ3SFjbPFeiVkLi1BuSahMhc/W1Y9H0W89qFDrrD+z7EgRgDtHTG1ZRyi9gIlNtt9qhkO1B6W2qb2A==} + engines: {node: '>=16.13'} + '@miniflare/watcher@2.14.4': resolution: {integrity: sha512-PYn05ET2USfBAeXF6NZfWl0O32KVyE8ncQ/ngysrh3hoIV7l3qGGH7ubeFx+D8VWQ682qYhwGygUzQv2j1tGGg==} engines: {node: '>=16.13'} @@ -10702,8 +10713,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10789,11 +10800,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': + '@aws-sdk/client-sso-oidc@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10832,7 +10843,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.478.0': @@ -11099,11 +11109,11 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0': + '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -11142,6 +11152,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/core@3.477.0': @@ -11296,7 +11307,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -11503,7 +11514,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0 + '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -11704,7 +11715,7 @@ snapshots: '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11713,7 +11724,7 @@ snapshots: '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -12821,12 +12832,12 @@ snapshots: '@cloudflare/workerd-windows-64@1.20240712.0': optional: true - '@cloudflare/workers-types@4.20240512.0': {} - '@cloudflare/workers-types@4.20240524.0': {} '@cloudflare/workers-types@4.20241004.0': {} + '@cloudflare/workers-types@4.20241112.0': {} + '@colors/colors@1.5.0': optional: true @@ -13387,7 +13398,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -13405,7 +13416,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13927,6 +13938,13 @@ snapshots: '@miniflare/core': 2.14.4 '@miniflare/shared': 2.14.4 + '@miniflare/durable-objects@2.14.4': + dependencies: + '@miniflare/core': 2.14.4 + '@miniflare/shared': 2.14.4 + '@miniflare/storage-memory': 2.14.4 + undici: 5.28.4 + '@miniflare/queues@2.14.4': dependencies: '@miniflare/shared': 2.14.4 @@ -13938,6 +13956,10 @@ snapshots: npx-import: 1.1.4 picomatch: 2.3.1 + '@miniflare/storage-memory@2.14.4': + dependencies: + '@miniflare/shared': 2.14.4 + '@miniflare/watcher@2.14.4': dependencies: '@miniflare/shared': 2.14.4 @@ -13991,10 +14013,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) '@opentelemetry/api@1.8.0': {} @@ -14131,7 +14153,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -14141,7 +14163,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -14168,14 +14190,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -14264,16 +14286,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -14288,7 +14310,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -14302,7 +14324,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -14325,12 +14347,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) optionalDependencies: '@types/react': 18.3.1 @@ -15705,7 +15727,7 @@ snapshots: pathe: 1.1.2 picocolors: 1.0.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + vitest: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) optional: true '@vitest/ui@1.6.0(vitest@2.1.2)': @@ -16279,7 +16301,7 @@ snapshots: '@npmcli/fs': 3.1.1 fs-minipass: 3.0.3 glob: 10.4.1 - lru-cache: 10.2.2 + lru-cache: 10.4.3 minipass: 7.1.2 minipass-collect: 2.0.1 minipass-flush: 1.0.5 @@ -16980,10 +17002,10 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241112.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 - '@cloudflare/workers-types': 4.20241004.0 + '@cloudflare/workers-types': 4.20241112.0 '@libsql/client': 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': 0.10.3 '@opentelemetry/api': 1.8.0 @@ -17823,35 +17845,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) expo-modules-autolinking@1.11.1: dependencies: @@ -17865,24 +17887,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): + expo-sqlite@14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -19384,12 +19406,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -19465,13 +19487,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -19485,7 +19507,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -19511,7 +19533,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -19519,7 +19541,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -19528,7 +19550,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -20462,10 +20484,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8): + react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8) + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -20478,19 +20500,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -20509,14 +20531,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8) + react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8) + ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -22525,15 +22547,17 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8): + ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8): + ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From 2fcbec2c300d5de44aa19786856cf9c5382c5df5 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Fri, 29 Nov 2024 12:54:34 +0200 Subject: [PATCH 404/492] updated lockfile --- pnpm-lock.yaml | 160 +++++++++++++++++++++---------------------------- 1 file changed, 68 insertions(+), 92 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2e709993..f3507396d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -318,15 +318,12 @@ importers: '@miniflare/d1': specifier: ^2.14.4 version: 2.14.4 - '@miniflare/durable-objects': - specifier: ^2.14.4 - version: 2.14.4 '@neondatabase/serverless': specifier: ^0.10.0 version: 0.10.0 '@op-engineering/op-sqlite': specifier: ^2.0.16 - version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + version: 2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@opentelemetry/api': specifier: ^1.4.1 version: 1.8.0 @@ -374,7 +371,7 @@ importers: version: 10.1.0 expo-sqlite: specifier: ^14.0.0 - version: 14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + version: 14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) knex: specifier: ^2.4.2 version: 2.5.1(better-sqlite3@8.7.0)(mysql2@3.3.3)(pg@8.11.5)(sqlite3@5.1.7) @@ -3308,10 +3305,6 @@ packages: resolution: {integrity: sha512-pMBVq9XWxTDdm+RRCkfXZP+bREjPg1JC8s8C0JTovA9OGmLQXqGTnFxIaS9vf1d8k3uSUGhDzPTzHr0/AUW1gA==} engines: {node: '>=16.7'} - '@miniflare/durable-objects@2.14.4': - resolution: {integrity: sha512-+JrmHP6gHHrjxV8S3axVw5lGHLgqmAGdcO/1HJUPswAyJEd3Ah2YnKhpo+bNmV4RKJCtEq9A2hbtVjBTD2YzwA==} - engines: {node: '>=16.13'} - '@miniflare/queues@2.14.4': resolution: {integrity: sha512-aXQ5Ik8Iq1KGMBzGenmd6Js/jJgqyYvjom95/N9GptCGpiVWE5F0XqC1SL5rCwURbHN+aWY191o8XOFyY2nCUA==} engines: {node: '>=16.7'} @@ -3320,10 +3313,6 @@ packages: resolution: {integrity: sha512-upl4RSB3hyCnITOFmRZjJj4A72GmkVrtfZTilkdq5Qe5TTlzsjVeDJp7AuNUM9bM8vswRo+N5jOiot6O4PVwwQ==} engines: {node: '>=16.13'} - '@miniflare/storage-memory@2.14.4': - resolution: {integrity: sha512-9jB5BqNkMZ3SFjbPFeiVkLi1BuSahMhc/W1Y9H0W89qFDrrD+z7EgRgDtHTG1ZRyi9gIlNtt9qhkO1B6W2qb2A==} - engines: {node: '>=16.13'} - '@miniflare/watcher@2.14.4': resolution: {integrity: sha512-PYn05ET2USfBAeXF6NZfWl0O32KVyE8ncQ/ngysrh3hoIV7l3qGGH7ubeFx+D8VWQ682qYhwGygUzQv2j1tGGg==} engines: {node: '>=16.13'} @@ -10713,8 +10702,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10800,11 +10789,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.583.0': + '@aws-sdk/client-sso-oidc@3.583.0(@aws-sdk/client-sts@3.583.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -10843,6 +10832,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: + - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.478.0': @@ -11109,11 +11099,11 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)': + '@aws-sdk/client-sts@3.583.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -11152,7 +11142,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/core@3.477.0': @@ -11307,7 +11296,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -11514,7 +11503,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.577.0(@aws-sdk/client-sts@3.583.0)': dependencies: - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -11715,7 +11704,7 @@ snapshots: '@aws-sdk/token-providers@3.568.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -11724,7 +11713,7 @@ snapshots: '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.583.0 + '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -13398,7 +13387,7 @@ snapshots: mv: 2.1.1 safe-json-stringify: 1.2.0 - '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3)': + '@expo/cli@0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)': dependencies: '@babel/runtime': 7.24.6 '@expo/code-signing-certificates': 0.0.5 @@ -13416,7 +13405,7 @@ snapshots: '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) '@expo/spawn-async': 1.7.2 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -13938,13 +13927,6 @@ snapshots: '@miniflare/core': 2.14.4 '@miniflare/shared': 2.14.4 - '@miniflare/durable-objects@2.14.4': - dependencies: - '@miniflare/core': 2.14.4 - '@miniflare/shared': 2.14.4 - '@miniflare/storage-memory': 2.14.4 - undici: 5.28.4 - '@miniflare/queues@2.14.4': dependencies: '@miniflare/shared': 2.14.4 @@ -13956,10 +13938,6 @@ snapshots: npx-import: 1.1.4 picomatch: 2.3.1 - '@miniflare/storage-memory@2.14.4': - dependencies: - '@miniflare/shared': 2.14.4 - '@miniflare/watcher@2.14.4': dependencies: '@miniflare/shared': 2.14.4 @@ -14013,10 +13991,10 @@ snapshots: rimraf: 3.0.2 optional: true - '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@op-engineering/op-sqlite@2.0.22(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) '@opentelemetry/api@1.8.0': {} @@ -14153,7 +14131,7 @@ snapshots: transitivePeerDependencies: - encoding - '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli-server-api@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) @@ -14163,7 +14141,7 @@ snapshots: nocache: 3.0.4 pretty-format: 26.6.2 serve-static: 1.15.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -14190,14 +14168,14 @@ snapshots: dependencies: joi: 17.13.1 - '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native-community/cli@13.6.6(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@react-native-community/cli-clean': 13.6.6(encoding@0.1.13) '@react-native-community/cli-config': 13.6.6(encoding@0.1.13) '@react-native-community/cli-debugger-ui': 13.6.6 '@react-native-community/cli-doctor': 13.6.6(encoding@0.1.13) '@react-native-community/cli-hermes': 13.6.6(encoding@0.1.13) - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) '@react-native-community/cli-types': 13.6.6 chalk: 4.1.2 @@ -14286,16 +14264,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/community-cli-plugin@0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: - '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli-server-api': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) - '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/dev-middleware': 0.74.83(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/metro-babel-transformer': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) chalk: 4.1.2 execa: 5.1.1 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 node-fetch: 2.7.0(encoding@0.1.13) querystring: 0.2.1 @@ -14310,7 +14288,7 @@ snapshots: '@react-native/debugger-frontend@0.74.83': {} - '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)': + '@react-native/dev-middleware@0.74.83(bufferutil@4.0.8)(encoding@0.1.13)': dependencies: '@isaacs/ttlcache': 1.4.1 '@react-native/debugger-frontend': 0.74.83 @@ -14324,7 +14302,7 @@ snapshots: selfsigned: 2.4.1 serve-static: 1.15.0 temp-dir: 2.0.0 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - encoding @@ -14347,12 +14325,12 @@ snapshots: '@react-native/normalize-colors@0.74.83': {} - '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1)': + '@react-native/virtualized-lists@0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3) + react-native: 0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1) optionalDependencies: '@types/react': 18.3.1 @@ -15727,7 +15705,7 @@ snapshots: pathe: 1.1.2 picocolors: 1.0.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@20.12.12)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) + vitest: 1.6.0(@types/node@18.19.33)(@vitest/ui@1.6.0)(lightningcss@1.25.1)(terser@5.31.0) optional: true '@vitest/ui@1.6.0(vitest@2.1.2)': @@ -17845,35 +17823,35 @@ snapshots: expand-template@2.0.3: {} - expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-asset@10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@react-native/assets-registry': 0.74.83 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) - expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) + expo-constants: 16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) invariant: 2.2.4 md5-file: 3.2.3 transitivePeerDependencies: - supports-color - expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-constants@16.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/config': 9.0.2 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) transitivePeerDependencies: - supports-color - expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-file-system@17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-font@12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) fontfaceobserver: 2.3.0 - expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-keep-awake@13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) expo-modules-autolinking@1.11.1: dependencies: @@ -17887,24 +17865,24 @@ snapshots: dependencies: invariant: 2.2.4 - expo-sqlite@14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)): + expo-sqlite@14.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)): dependencies: '@expo/websql': 1.0.1 - expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + expo: 51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) - expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/runtime': 7.24.6 - '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(utf-8-validate@6.0.3) + '@expo/cli': 0.18.13(bufferutil@4.0.8)(encoding@0.1.13)(expo-modules-autolinking@1.11.1) '@expo/config': 9.0.2 '@expo/config-plugins': 8.0.4 '@expo/metro-config': 0.18.4 '@expo/vector-icons': 14.0.2 babel-preset-expo: 11.0.6(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) - expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3)) + expo-asset: 10.0.6(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-file-system: 17.0.1(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-font: 12.0.5(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) + expo-keep-awake: 13.0.2(expo@51.0.8(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)) expo-modules-autolinking: 1.11.1 expo-modules-core: 1.12.11 fbemitter: 3.0.0(encoding@0.1.13) @@ -19406,12 +19384,12 @@ snapshots: metro-core: 0.80.9 rimraf: 3.0.2 - metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-config@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: connect: 3.7.0 cosmiconfig: 5.2.1 jest-validate: 29.7.0 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-cache: 0.80.9 metro-core: 0.80.9 metro-runtime: 0.80.9 @@ -19487,13 +19465,13 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro-transform-worker@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 @@ -19507,7 +19485,7 @@ snapshots: - supports-color - utf-8-validate - metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3): + metro@0.80.9(bufferutil@4.0.8)(encoding@0.1.13): dependencies: '@babel/code-frame': 7.24.6 '@babel/core': 7.24.6 @@ -19533,7 +19511,7 @@ snapshots: metro-babel-transformer: 0.80.9 metro-cache: 0.80.9 metro-cache-key: 0.80.9 - metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-config: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) metro-core: 0.80.9 metro-file-map: 0.80.9 metro-resolver: 0.80.9 @@ -19541,7 +19519,7 @@ snapshots: metro-source-map: 0.80.9 metro-symbolicate: 0.80.9 metro-transform-plugins: 0.80.9 - metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + metro-transform-worker: 0.80.9(bufferutil@4.0.8)(encoding@0.1.13) mime-types: 2.1.35 node-fetch: 2.7.0(encoding@0.1.13) nullthrows: 1.1.1 @@ -19550,7 +19528,7 @@ snapshots: source-map: 0.5.7 strip-ansi: 6.0.1 throat: 5.0.0 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -20484,10 +20462,10 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-devtools-core@5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3): + react-devtools-core@5.2.0(bufferutil@4.0.8): dependencies: shell-quote: 1.8.1 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 7.5.9(bufferutil@4.0.8) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -20500,19 +20478,19 @@ snapshots: react-is@18.3.1: {} - react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3): + react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native-community/cli': 13.6.6(bufferutil@4.0.8)(encoding@0.1.13) '@react-native-community/cli-platform-android': 13.6.6(encoding@0.1.13) '@react-native-community/cli-platform-ios': 13.6.6(encoding@0.1.13) '@react-native/assets-registry': 0.74.83 '@react-native/codegen': 0.74.83(@babel/preset-env@7.24.6(@babel/core@7.24.6)) - '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.3) + '@react-native/community-cli-plugin': 0.74.83(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(bufferutil@4.0.8)(encoding@0.1.13) '@react-native/gradle-plugin': 0.74.83 '@react-native/js-polyfills': 0.74.83 '@react-native/normalize-colors': 0.74.83 - '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(utf-8-validate@6.0.3))(react@18.3.1) + '@react-native/virtualized-lists': 0.74.83(@types/react@18.3.1)(react-native@0.74.1(@babel/core@7.24.6)(@babel/preset-env@7.24.6(@babel/core@7.24.6))(@types/react@18.3.1)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -20531,14 +20509,14 @@ snapshots: pretty-format: 26.6.2 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + react-devtools-core: 5.2.0(bufferutil@4.0.8) react-refresh: 0.14.2 react-shallow-renderer: 16.15.0(react@18.3.1) regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + ws: 6.2.2(bufferutil@4.0.8) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.1 @@ -22547,17 +22525,15 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.0.2 - ws@6.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@6.2.2(bufferutil@4.0.8): dependencies: async-limiter: 1.0.1 optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 - ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.3): + ws@7.5.9(bufferutil@4.0.8): optionalDependencies: bufferutil: 4.0.8 - utf-8-validate: 6.0.3 ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): optionalDependencies: From 440c1ee81c186abc6f70feb010e7a57f460e371d Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Fri, 29 Nov 2024 13:07:26 +0200 Subject: [PATCH 405/492] fixed dprint issues --- .../durable-objects/drizzle/migrations.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js b/integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js index 8b7b5cf54..c6f2a6ada 100644 --- a/integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js +++ b/integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js @@ -1,12 +1,9 @@ -// This file is required for Expo/React Native SQLite migrations - https://orm.drizzle.team/quick-sqlite/expo - -import journal from './meta/_journal.json'; import m0000 from './0000_cuddly_black_bolt.sql'; +import journal from './meta/_journal.json'; - export default { - journal, - migrations: { - m0000 - } - } - \ No newline at end of file +export default { + journal, + migrations: { + m0000, + }, +}; From c4d850f15890089da44708075b27ded814814845 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Fri, 29 Nov 2024 13:18:18 +0200 Subject: [PATCH 406/492] added updated seeder tests to integration-tests --- drizzle-seed/src/index.ts | 2 + integration-tests/tests/seeder/mysql.test.ts | 2 +- integration-tests/tests/seeder/pg.test.ts | 828 ++++++++++++++++++- integration-tests/tests/seeder/pgSchema.ts | 143 ++++ 4 files changed, 957 insertions(+), 18 deletions(-) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index bfe6cc92c..6a8d95181 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -900,5 +900,7 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { return { tables, relations }; }; +export { default as cities } from './datasets/cityNames.ts'; +export { default as countries } from './datasets/countries.ts'; export { default as firstNames } from './datasets/firstNames.ts'; export { default as lastNames } from './datasets/lastNames.ts'; diff --git a/integration-tests/tests/seeder/mysql.test.ts b/integration-tests/tests/seeder/mysql.test.ts index 5ae7f9f15..22530a2aa 100644 --- a/integration-tests/tests/seeder/mysql.test.ts +++ b/integration-tests/tests/seeder/mysql.test.ts @@ -442,7 +442,7 @@ test("sequential using of 'with'", async () => { // All data types test ------------------------------- test('basic seed test for all mysql data types', async () => { - await seed(db, schema, { count: 10000 }); + await seed(db, schema, { count: 1000 }); const allDataTypes = await db.select().from(schema.allDataTypes); diff --git a/integration-tests/tests/seeder/pg.test.ts b/integration-tests/tests/seeder/pg.test.ts index 3ca75704a..83c0fd19d 100644 --- a/integration-tests/tests/seeder/pg.test.ts +++ b/integration-tests/tests/seeder/pg.test.ts @@ -2,7 +2,7 @@ import { PGlite } from '@electric-sql/pglite'; import { sql } from 'drizzle-orm'; import type { PgliteDatabase } from 'drizzle-orm/pglite'; import { drizzle } from 'drizzle-orm/pglite'; -import { firstNames, lastNames, reset, seed } from 'drizzle-seed'; +import { cities, countries, firstNames, lastNames, reset, seed } from 'drizzle-seed'; import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; import * as schema from './pgSchema.ts'; @@ -195,10 +195,10 @@ const createAllDataTypesTable = async () => { "smallint" smallint, "bigint" bigint, "bigint_number" bigint, - "serial" serial NOT NULL, - "smallserial" "smallserial" NOT NULL, + "serial" serial, + "smallserial" smallserial, "bigserial" bigserial, - "bigserial_number" bigserial NOT NULL, + "bigserial_number" bigserial, "boolean" boolean, "text" text, "varchar" varchar(256), @@ -223,6 +223,49 @@ const createAllDataTypesTable = async () => { ); `, ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."all_array_data_types" ( + "integer_array" integer[], + "smallint_array" smallint[], + "bigint_array" bigint[], + "bigint_number_array" bigint[], + "boolean_array" boolean[], + "text_array" text[], + "varchar_array" varchar(256)[], + "char_array" char(256)[], + "numeric_array" numeric[], + "decimal_array" numeric[], + "real_array" real[], + "double_precision_array" double precision[], + "json_array" json[], + "jsonb_array" jsonb[], + "time_array" time[], + "timestamp_date_array" timestamp[], + "timestamp_string_array" timestamp[], + "date_string_array" date[], + "date_array" date[], + "interval_array" interval[], + "point_array" "point"[], + "point_tuple_array" "point"[], + "line_array" "line"[], + "line_tuple_array" "line"[], + "mood_enum_array" "seeder_lib_pg"."mood_enum"[] + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."nd_arrays" ( + "integer_1d_array" integer[3], + "integer_2d_array" integer[3][4], + "integer_3d_array" integer[3][4][5], + "integer_4d_array" integer[3][4][5][6] + ); + `, + ); }; const createAllGeneratorsTables = async () => { @@ -235,6 +278,21 @@ const createAllGeneratorsTables = async () => { END $$; `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."default_table" ( + "default_string" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."default_array_table" ( + "default_string" text[] + ); + `, + ); await db.execute( sql` @@ -244,6 +302,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."boolean_array_table" ( + "boolean" boolean[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_table" ( @@ -261,6 +327,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."city_array_table" ( + "city" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_table" ( @@ -278,6 +352,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."company_name_array_table" ( + "company_name" text[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_table" ( @@ -295,6 +377,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."country_array_table" ( + "country" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."date_table" ( @@ -305,8 +395,9 @@ const createAllGeneratorsTables = async () => { await db.execute( sql` - CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."default_table" ( - "default_string" text + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."date_array_table" ( + "date" date[], + "date_string" date[] ); `, ); @@ -320,6 +411,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."email_array_table" ( + "email" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."enum_table" ( @@ -345,6 +444,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."first_name_array_table" ( + "first_name" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name__table" ( @@ -362,6 +469,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."full_name_array_table" ( + "full_name" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_primary_key_table" ( @@ -388,6 +503,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."int_array_table" ( + "int" integer[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_table" ( @@ -405,6 +528,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."interval_array_table" ( + "interval" interval[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."job_title_table" ( @@ -413,6 +544,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."job_title_array_table" ( + "job_title" text[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."json_table" ( @@ -421,6 +560,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."json_array_table" ( + "json" json[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_table" ( @@ -438,6 +585,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."last_name_array_table" ( + "last_name" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."line_table" ( @@ -446,6 +601,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."line_array_table" ( + "line" "line"[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."lorem_ipsum_table" ( @@ -454,6 +617,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."lorem_ipsum_array_table" ( + "lorem_ipsum" text[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_table" ( @@ -471,6 +642,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."number_array_table" ( + "number" real[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."phone_number_table" ( @@ -484,6 +663,16 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."phone_number_array_table" ( + "phoneNumber" varchar(256)[], + "phone_number_template" varchar(256)[], + "phone_number_prefixes" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."point_table" ( @@ -492,6 +681,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."point_array_table" ( + "point" "point"[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_table" ( @@ -509,6 +706,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."postcode_array_table" ( + "postcode" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."state_table" ( @@ -517,6 +722,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."state_array_table" ( + "state" text[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_table" ( @@ -534,6 +747,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."street_address_array_table" ( + "street_address" varchar(256)[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_table" ( @@ -551,6 +772,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."string_array_table" ( + "string" text[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."time_table" ( @@ -559,6 +788,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."time_array_table" ( + "time" time[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."timestamp_table" ( @@ -567,6 +804,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."timestamp_array_table" ( + "timestamp" timestamp[] + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_table" ( @@ -591,6 +836,14 @@ const createAllGeneratorsTables = async () => { `, ); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."values_from_array_array_table" ( + "values_from_array" varchar(256) + ); + `, + ); + await db.execute( sql` CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."weighted_random_table" ( @@ -640,7 +893,15 @@ afterAll(async () => { }); test('basic seed test', async () => { - await seed(db, schema); + const currSchema = { + customers: schema.customers, + details: schema.details, + employees: schema.employees, + orders: schema.orders, + products: schema.products, + suppliers: schema.suppliers, + }; + await seed(db, currSchema); const customers = await db.select().from(schema.customers); const details = await db.select().from(schema.details); @@ -658,7 +919,15 @@ test('basic seed test', async () => { }); test('seed with options.count:11 test', async () => { - await seed(db, schema, { count: 11 }); + const currSchema = { + customers: schema.customers, + details: schema.details, + employees: schema.employees, + orders: schema.orders, + products: schema.products, + suppliers: schema.suppliers, + }; + await seed(db, currSchema, { count: 11 }); const customers = await db.select().from(schema.customers); const details = await db.select().from(schema.details); @@ -676,7 +945,15 @@ test('seed with options.count:11 test', async () => { }); test('redefine(refine) customers count', async () => { - await seed(db, schema, { count: 11 }).refine(() => ({ + const currSchema = { + customers: schema.customers, + details: schema.details, + employees: schema.employees, + orders: schema.orders, + products: schema.products, + suppliers: schema.suppliers, + }; + await seed(db, currSchema, { count: 11 }).refine(() => ({ customers: { count: 12, }, @@ -698,7 +975,15 @@ test('redefine(refine) customers count', async () => { }); test('redefine(refine) all tables count', async () => { - await seed(db, schema, { count: 11 }).refine(() => ({ + const currSchema = { + customers: schema.customers, + details: schema.details, + employees: schema.employees, + orders: schema.orders, + products: schema.products, + suppliers: schema.suppliers, + }; + await seed(db, currSchema, { count: 11 }).refine(() => ({ customers: { count: 12, }, @@ -735,7 +1020,15 @@ test('redefine(refine) all tables count', async () => { }); test("redefine(refine) orders count using 'with' in customers", async () => { - await seed(db, schema, { count: 11 }).refine(() => ({ + const currSchema = { + customers: schema.customers, + details: schema.details, + employees: schema.employees, + orders: schema.orders, + products: schema.products, + suppliers: schema.suppliers, + }; + await seed(db, currSchema, { count: 11 }).refine(() => ({ customers: { count: 4, with: { @@ -763,7 +1056,15 @@ test("redefine(refine) orders count using 'with' in customers", async () => { }); test("sequential using of 'with'", async () => { - await seed(db, schema, { count: 11 }).refine(() => ({ + const currSchema = { + customers: schema.customers, + details: schema.details, + employees: schema.employees, + orders: schema.orders, + products: schema.products, + suppliers: schema.suppliers, + }; + await seed(db, currSchema, { count: 11 }).refine(() => ({ customers: { count: 4, with: { @@ -812,8 +1113,45 @@ test('basic seed test for all postgres data types', async () => { expect(predicate).toBe(true); }); +test('all array data types test', async () => { + await seed(db, { allArrayDataTypes: schema.allArrayDataTypes }, { count: 1000 }); + + const allArrayDataTypes = await db.select().from(schema.allArrayDataTypes); + // every value in each rows does not equal undefined. + const predicate = allArrayDataTypes.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && val.length === 10) + ); + + expect(predicate).toBe(true); +}); + +test('nd arrays', async () => { + await seed(db, { ndArrays: schema.ndArrays }, { count: 1000 }); + + const ndArrays = await db.select().from(schema.ndArrays); + // every value in each rows does not equal undefined. + const predicate0 = ndArrays.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && val.length !== 0) + ); + let predicate1 = true, predicate2 = true, predicate3 = true, predicate4 = true; + + for (const row of ndArrays) { + predicate1 = predicate1 && (row.integer1DArray?.length === 3); + + predicate2 = predicate2 && (row.integer2DArray?.length === 4) && (row.integer2DArray[0]?.length === 3); + + predicate3 = predicate3 && (row.integer3DArray?.length === 5) && (row.integer3DArray[0]?.length === 4) + && (row.integer3DArray[0][0]?.length === 3); + + predicate4 = predicate4 && (row.integer4DArray?.length === 6) && (row.integer4DArray[0]?.length === 5) + && (row.integer4DArray[0][0]?.length === 4) && (row.integer4DArray[0][0][0]?.length === 3); + } + + expect(predicate0 && predicate1 && predicate2 && predicate3 && predicate4).toBe(true); +}); + // All generators test------------------------------- -const count = 10000; +const count = 1000; test('enum generator test', async () => { await seed(db, { enumTable: schema.enumTable }).refine(() => ({ @@ -846,6 +1184,23 @@ test('default generator test', async () => { expect(predicate).toBe(true); }); +test('default array generator test', async () => { + await seed(db, { defaultTable: schema.defaultArrayTable }).refine((funcs) => ({ + defaultTable: { + count, + columns: { + defaultString: funcs.default({ defaultValue: 'default string', arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.defaultArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('valuesFromArray generator test', async () => { await seed(db, { valuesFromArrayTable: schema.valuesFromArrayTable }).refine((funcs) => ({ valuesFromArrayTable: { @@ -958,6 +1313,23 @@ test('valuesFromArray unique generator test', async () => { ).rejects.toThrow('There are no enough values to fill unique column.'); }); +test('valuesFromArray array generator test', async () => { + await seed(db, { valuesFromArrayTable: schema.valuesFromArrayArrayTable }).refine((funcs) => ({ + valuesFromArrayTable: { + count, + columns: { + valuesFromArray: funcs.valuesFromArray({ values: lastNames, arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.valuesFromArrayArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('intPrimaryKey generator test', async () => { await seed(db, { intPrimaryKeyTable: schema.intPrimaryKeyTable }).refine((funcs) => ({ intPrimaryKeyTable: { @@ -1022,6 +1394,23 @@ test('number unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); }); +test('number array generator test', async () => { + await seed(db, { numberTable: schema.numberArrayTable }).refine((funcs) => ({ + numberTable: { + count, + columns: { + number: funcs.number({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.numberArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('int generator test', async () => { await seed(db, { intTable: schema.intTable }).refine((funcs) => ({ intTable: { @@ -1067,6 +1456,23 @@ test('int unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique integers in given range(min, max), try to make range wider.'); }); +test('int array generator test', async () => { + await seed(db, { intTable: schema.intArrayTable }).refine((funcs) => ({ + intTable: { + count, + columns: { + int: funcs.int({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.intArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('boolean generator test', async () => { await seed(db, { booleanTable: schema.booleanTable }).refine((funcs) => ({ booleanTable: { @@ -1084,6 +1490,23 @@ test('boolean generator test', async () => { expect(predicate).toBe(true); }); +test('boolean array generator test', async () => { + await seed(db, { booleanTable: schema.booleanArrayTable }).refine((funcs) => ({ + booleanTable: { + count, + columns: { + boolean: funcs.boolean({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.booleanArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('date generator test', async () => { await seed(db, { dateTable: schema.dateTable }).refine((funcs) => ({ dateTable: { @@ -1101,6 +1524,26 @@ test('date generator test', async () => { expect(predicate).toBe(true); }); +test('date array generator test', async () => { + await seed(db, { dateTable: schema.dateArrayTable }).refine((funcs) => ({ + dateTable: { + count, + columns: { + date: funcs.date({ arraySize: 3 }), + dateString: funcs.date({ arraySize: 4 }), + }, + }, + })); + + const data = await db.select().from(schema.dateArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && [3, 4].includes(val.length)) + ); + expect(predicate).toBe(true); +}); + test('time generator test', async () => { await seed(db, { timeTable: schema.timeTable }).refine((funcs) => ({ timeTable: { @@ -1118,6 +1561,23 @@ test('time generator test', async () => { expect(predicate).toBe(true); }); +test('time array generator test', async () => { + await seed(db, { timeTable: schema.timeArrayTable }).refine((funcs) => ({ + timeTable: { + count, + columns: { + time: funcs.time({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.timeArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('timestamp generator test', async () => { await seed(db, { timestampTable: schema.timestampTable }).refine((funcs) => ({ timestampTable: { @@ -1135,6 +1595,23 @@ test('timestamp generator test', async () => { expect(predicate).toBe(true); }); +test('timestamp array generator test', async () => { + await seed(db, { timestampTable: schema.timestampArrayTable }).refine((funcs) => ({ + timestampTable: { + count, + columns: { + timestamp: funcs.timestamp({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.timestampArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('json generator test', async () => { await seed(db, { jsonTable: schema.jsonTable }).refine((funcs) => ({ jsonTable: { @@ -1152,6 +1629,23 @@ test('json generator test', async () => { expect(predicate).toBe(true); }); +test('json array generator test', async () => { + await seed(db, { jsonTable: schema.jsonArrayTable }).refine((funcs) => ({ + jsonTable: { + count, + columns: { + json: funcs.json({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.jsonArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('interval generator test', async () => { await seed(db, { intervalTable: schema.intervalTable }).refine((funcs) => ({ intervalTable: { @@ -1186,6 +1680,23 @@ test('interval unique generator test', async () => { expect(predicate).toBe(true); }); +test('interval array generator test', async () => { + await seed(db, { intervalTable: schema.intervalArrayTable }).refine((funcs) => ({ + intervalTable: { + count, + columns: { + interval: funcs.interval({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.intervalArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('string generator test', async () => { await seed(db, { stringTable: schema.stringTable }).refine((funcs) => ({ stringTable: { @@ -1219,6 +1730,23 @@ test('string unique generator test', async () => { expect(predicate).toBe(true); }); +test('string array generator test', async () => { + await seed(db, { stringTable: schema.stringArrayTable }).refine((funcs) => ({ + stringTable: { + count, + columns: { + string: funcs.string({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.stringArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('email generator test', async () => { await seed(db, { emailTable: schema.emailTable }).refine((funcs) => ({ emailTable: { @@ -1236,6 +1764,23 @@ test('email generator test', async () => { expect(predicate).toBe(true); }); +test('email array generator test', async () => { + await seed(db, { emailTable: schema.emailArrayTable }).refine((funcs) => ({ + emailTable: { + count, + columns: { + email: funcs.email({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.emailArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('firstName generator test', async () => { await seed(db, { firstNameTable: schema.firstNameTable }).refine((funcs) => ({ firstNameTable: { @@ -1281,6 +1826,23 @@ test('firstName unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique first names.'); }); +test('firstName array generator test', async () => { + await seed(db, { firstNameTable: schema.firstNameArrayTable }).refine((funcs) => ({ + firstNameTable: { + count, + columns: { + firstName: funcs.firstName({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.firstNameArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('lastName generator test', async () => { await seed(db, { lastNameTable: schema.lastNameTable }).refine((funcs) => ({ lastNameTable: { @@ -1326,6 +1888,23 @@ test('lastName unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique last names.'); }); +test('lastName array generator test', async () => { + await seed(db, { lastNameTable: schema.lastNameArrayTable }).refine((funcs) => ({ + lastNameTable: { + count, + columns: { + lastName: funcs.lastName({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.lastNameArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('fullName generator test', async () => { await seed(db, { fullNameTable: schema.fullNameTable }).refine((funcs) => ({ fullNameTable: { @@ -1361,6 +1940,23 @@ test('fullName unique generator test', async () => { expect(predicate).toBe(true); }); +test('fullName array generator test', async () => { + await seed(db, { fullNameTable: schema.fullNameArrayTable }).refine((funcs) => ({ + fullNameTable: { + count, + columns: { + fullName: funcs.fullName({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.fullNameArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('country generator test', async () => { await seed(db, { countryTable: schema.countryTable }).refine((funcs) => ({ countryTable: { @@ -1382,7 +1978,7 @@ test('country unique generator test', async () => { // countryUniqueTable----------------------------------------------------------------------------------- await seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ countryUniqueTable: { - count: 160, + count: countries.length, columns: { countryUnique: funcs.country({ isUnique: true }), }, @@ -1397,7 +1993,7 @@ test('country unique generator test', async () => { await expect( seed(db, { countryUniqueTable: schema.countryUniqueTable }).refine((funcs) => ({ countryUniqueTable: { - count: 168, + count: countries.length + 1, columns: { countryUnique: funcs.country({ isUnique: true }), }, @@ -1406,6 +2002,23 @@ test('country unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique countries.'); }); +test('country array generator test', async () => { + await seed(db, { countryTable: schema.countryArrayTable }).refine((funcs) => ({ + countryTable: { + count, + columns: { + country: funcs.country({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.countryArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('city generator test', async () => { await seed(db, { cityTable: schema.cityTable }).refine((funcs) => ({ cityTable: { @@ -1428,7 +2041,7 @@ test('city unique generator test', async () => { await reset(db, { cityUniqueTable: schema.cityUniqueTable }); await seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ cityUniqueTable: { - count: 38884, + count: cities.length, columns: { cityUnique: funcs.city({ isUnique: true }), }, @@ -1443,7 +2056,7 @@ test('city unique generator test', async () => { await expect( seed(db, { cityUniqueTable: schema.cityUniqueTable }).refine((funcs) => ({ cityUniqueTable: { - count: 42985, + count: cities.length + 1, columns: { cityUnique: funcs.city({ isUnique: true }), }, @@ -1452,6 +2065,23 @@ test('city unique generator test', async () => { ).rejects.toThrow('count exceeds max number of unique cities.'); }); +test('city array generator test', async () => { + await seed(db, { cityTable: schema.cityArrayTable }).refine((funcs) => ({ + cityTable: { + count, + columns: { + city: funcs.city({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.cityArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('streetAddress generator test', async () => { await seed(db, { streetAddressTable: schema.streetAddressTable }).refine((funcs) => ({ streetAddressTable: { @@ -1486,6 +2116,23 @@ test('streetAddress unique generator test', async () => { expect(predicate).toBe(true); }); +test('streetAddress array generator test', async () => { + await seed(db, { streetAddressTable: schema.streetAddressArrayTable }).refine((funcs) => ({ + streetAddressTable: { + count, + columns: { + streetAddress: funcs.streetAddress({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.streetAddressArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('jobTitle generator test', async () => { await seed(db, { jobTitleTable: schema.jobTitleTable }).refine((funcs) => ({ jobTitleTable: { @@ -1503,6 +2150,23 @@ test('jobTitle generator test', async () => { expect(predicate).toBe(true); }); +test('jobTitle array generator test', async () => { + await seed(db, { jobTitleTable: schema.jobTitleArrayTable }).refine((funcs) => ({ + jobTitleTable: { + count, + columns: { + jobTitle: funcs.jobTitle({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.jobTitleArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('postcode generator test', async () => { await seed(db, { postcodeTable: schema.postcodeTable }).refine((funcs) => ({ postcodeTable: { @@ -1537,6 +2201,23 @@ test('postcode unique generator test', async () => { expect(predicate).toBe(true); }); +test('postcode array generator test', async () => { + await seed(db, { postcodeTable: schema.postcodeArrayTable }).refine((funcs) => ({ + postcodeTable: { + count, + columns: { + postcode: funcs.postcode({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.postcodeArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('state generator test', async () => { await seed(db, { stateTable: schema.stateTable }).refine((funcs) => ({ stateTable: { @@ -1554,6 +2235,23 @@ test('state generator test', async () => { expect(predicate).toBe(true); }); +test('state array generator test', async () => { + await seed(db, { stateTable: schema.stateArrayTable }).refine((funcs) => ({ + stateTable: { + count, + columns: { + state: funcs.state({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.stateArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('companyName generator test', async () => { await seed(db, { companyNameTable: schema.companyNameTable }).refine((funcs) => ({ companyNameTable: { @@ -1588,6 +2286,23 @@ test('companyName unique generator test', async () => { expect(predicate).toBe(true); }); +test('companyName array generator test', async () => { + await seed(db, { companyNameTable: schema.companyNameArrayTable }).refine((funcs) => ({ + companyNameTable: { + count, + columns: { + companyName: funcs.companyName({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.companyNameArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('loremIpsum generator test', async () => { await seed(db, { loremIpsumTable: schema.loremIpsumTable }).refine((funcs) => ({ loremIpsumTable: { @@ -1605,6 +2320,23 @@ test('loremIpsum generator test', async () => { expect(predicate).toBe(true); }); +test('loremIpsum array generator test', async () => { + await seed(db, { loremIpsumTable: schema.loremIpsumArrayTable }).refine((funcs) => ({ + loremIpsumTable: { + count, + columns: { + loremIpsum: funcs.loremIpsum({ arraySize: 3 }), + }, + }, + })); + + const data = await db.select().from(schema.loremIpsumArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 3)); + expect(predicate).toBe(true); +}); + test('point generator test', async () => { await seed(db, { pointTable: schema.pointTable }).refine((funcs) => ({ pointTable: { @@ -1645,6 +2377,23 @@ test('point unique generator test', async () => { expect(predicate).toBe(true); }); +test('point array generator test', async () => { + await seed(db, { pointTable: schema.pointArrayTable }).refine((funcs) => ({ + pointTable: { + count, + columns: { + point: funcs.point({ arraySize: 2 }), + }, + }, + })); + + const data = await db.select().from(schema.pointArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 2)); + expect(predicate).toBe(true); +}); + test('line generator test', async () => { await seed(db, { lineTable: schema.lineTable }).refine((funcs) => ({ lineTable: { @@ -1685,6 +2434,23 @@ test('line unique generator test', async () => { expect(predicate).toBe(true); }); +test('line array generator test', async () => { + await seed(db, { lineTable: schema.lineArrayTable }).refine((funcs) => ({ + lineTable: { + count, + columns: { + line: funcs.line({ arraySize: 2 }), + }, + }, + })); + + const data = await db.select().from(schema.lineArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null && val.length === 2)); + expect(predicate).toBe(true); +}); + test('phoneNumber generator test', async () => { await seed(db, { phoneNumberTable: schema.phoneNumberTable }).refine((funcs) => ({ phoneNumberTable: { @@ -1707,6 +2473,34 @@ test('phoneNumber generator test', async () => { expect(predicate).toBe(true); }); +test('phoneNumber array generator test', async () => { + await seed(db, { phoneNumberTable: schema.phoneNumberArrayTable }).refine((funcs) => ({ + phoneNumberTable: { + count, + columns: { + phoneNumber: funcs.phoneNumber({ arraySize: 3 }), + phoneNumberPrefixes: funcs.phoneNumber({ + prefixes: ['+380 99', '+380 67', '+1'], + generatedDigitsNumbers: [7, 7, 10], + arraySize: 4, + }), + phoneNumberTemplate: funcs.phoneNumber({ + template: '+380 ## ## ### ##', + arraySize: 5, + }), + }, + }, + })); + + const data = await db.select().from(schema.phoneNumberArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => + Object.values(row).every((val) => val !== undefined && val !== null && [3, 4, 5].includes(val.length)) + ); + expect(predicate).toBe(true); +}); + test('weightedRandom generator test', async () => { await seed(db, { weightedRandomTable: schema.weightedRandomTable }).refine((funcs) => ({ weightedRandomTable: { diff --git a/integration-tests/tests/seeder/pgSchema.ts b/integration-tests/tests/seeder/pgSchema.ts index ef5c4943a..fc4dda3c1 100644 --- a/integration-tests/tests/seeder/pgSchema.ts +++ b/integration-tests/tests/seeder/pgSchema.ts @@ -163,6 +163,41 @@ export const allDataTypes = schema.table('all_data_types', { moodEnum: moodEnum('mood_enum'), }); +export const allArrayDataTypes = schema.table('all_array_data_types', { + integerArray: integer('integer_array').array(), + smallintArray: smallint('smallint_array').array(), + bigintegerArray: bigint('bigint_array', { mode: 'bigint' }).array(), + bigintNumberArray: bigint('bigint_number_array', { mode: 'number' }).array(), + booleanArray: boolean('boolean_array').array(), + textArray: text('text_array').array(), + varcharArray: varchar('varchar_array', { length: 256 }).array(), + charArray: char('char_array', { length: 256 }).array(), + numericArray: numeric('numeric_array').array(), + decimalArray: decimal('decimal_array').array(), + realArray: real('real_array').array(), + doublePrecisionArray: doublePrecision('double_precision_array').array(), + jsonArray: json('json_array').array(), + jsonbArray: jsonb('jsonb_array').array(), + timeArray: time('time_array').array(), + timestampDateArray: timestamp('timestamp_date_array', { mode: 'date' }).array(), + timestampStringArray: timestamp('timestamp_string_array', { mode: 'string' }).array(), + dateStringArray: date('date_string_array', { mode: 'string' }).array(), + dateArray: date('date_array', { mode: 'date' }).array(), + intervalArray: interval('interval_array').array(), + pointArray: point('point_array', { mode: 'xy' }).array(), + pointTupleArray: point('point_tuple_array', { mode: 'tuple' }).array(), + lineArray: line('line_array', { mode: 'abc' }).array(), + lineTupleArray: line('line_tuple_array', { mode: 'tuple' }).array(), + moodEnumArray: moodEnum('mood_enum_array').array(), +}); + +export const ndArrays = schema.table('nd_arrays', { + integer1DArray: integer('integer_1d_array').array(3), + integer2DArray: integer('integer_2d_array').array(3).array(4), + integer3DArray: integer('integer_3d_array').array(3).array(4).array(5), + integer4DArray: integer('integer_4d_array').array(3).array(4).array(5).array(6), +}); + // All generators tables ------------------------------- export const enumTable = schema.table('enum_table', { mood: moodEnum('mood_enum'), @@ -172,6 +207,10 @@ export const defaultTable = schema.table('default_table', { defaultString: text('default_string'), }); +export const defaultArrayTable = schema.table('default_array_table', { + defaultString: text('default_string').array(), +}); + export const valuesFromArrayTable = schema.table('values_from_array_table', { valuesFromArrayNotNull: varchar('values_from_array_not_null', { length: 256 }).notNull(), valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).notNull(), @@ -184,6 +223,10 @@ export const valuesFromArrayUniqueTable = schema.table('values_from_array_unique valuesFromArrayWeightedNotNull: varchar('values_from_array_weighted_not_null', { length: 256 }).unique().notNull(), }); +export const valuesFromArrayArrayTable = schema.table('values_from_array_array_table', { + valuesFromArray: varchar('values_from_array', { length: 256 }).array(), +}); + export const intPrimaryKeyTable = schema.table('int_primary_key_table', { intPrimaryKey: integer('int_primary_key').unique(), }); @@ -196,6 +239,10 @@ export const numberUniqueTable = schema.table('number_unique_table', { numberUnique: real('number_unique').unique(), }); +export const numberArrayTable = schema.table('number_array_table', { + number: real('number').array(), +}); + export const intTable = schema.table('int_table', { int: integer('int'), }); @@ -204,26 +251,52 @@ export const intUniqueTable = schema.table('int_unique_table', { intUnique: integer('int_unique').unique(), }); +export const intArrayTable = schema.table('int_array_table', { + int: integer('int').array(), +}); + export const booleanTable = schema.table('boolean_table', { boolean: boolean('boolean'), }); +export const booleanArrayTable = schema.table('boolean_array_table', { + boolean: boolean('boolean').array(), +}); + export const dateTable = schema.table('date_table', { date: date('date'), }); +// TODO: add tests for data type with different modes +export const dateArrayTable = schema.table('date_array_table', { + date: date('date', { mode: 'date' }).array(), + dateString: date('date_string', { mode: 'string' }).array(), +}); + export const timeTable = schema.table('time_table', { time: time('time'), }); +export const timeArrayTable = schema.table('time_array_table', { + time: time('time').array(), +}); + export const timestampTable = schema.table('timestamp_table', { timestamp: timestamp('timestamp'), }); +export const timestampArrayTable = schema.table('timestamp_array_table', { + timestamp: timestamp('timestamp').array(), +}); + export const jsonTable = schema.table('json_table', { json: json('json'), }); +export const jsonArrayTable = schema.table('json_array_table', { + json: json('json').array(), +}); + export const intervalTable = schema.table('interval_table', { interval: interval('interval'), }); @@ -232,6 +305,10 @@ export const intervalUniqueTable = schema.table('interval_unique_table', { intervalUnique: interval('interval_unique').unique(), }); +export const intervalArrayTable = schema.table('interval_array_table', { + interval: interval('interval').array(), +}); + export const stringTable = schema.table('string_table', { string: text('string'), }); @@ -240,10 +317,18 @@ export const stringUniqueTable = schema.table('string_unique_table', { stringUnique: varchar('string_unique', { length: 256 }).unique(), }); +export const stringArrayTable = schema.table('string_array_table', { + string: text('string').array(), +}); + export const emailTable = schema.table('email_table', { email: varchar('email', { length: 256 }).unique(), }); +export const emailArrayTable = schema.table('email_array_table', { + email: varchar('email', { length: 256 }).array(), +}); + export const firstNameTable = schema.table('first_name_table', { firstName: varchar('first_name', { length: 256 }), }); @@ -252,6 +337,10 @@ export const firstNameUniqueTable = schema.table('first_name_unique_table', { firstNameUnique: varchar('first_name_unique', { length: 256 }).unique(), }); +export const firstNameArrayTable = schema.table('first_name_array_table', { + firstName: varchar('first_name', { length: 256 }).array(), +}); + export const lastNameTable = schema.table('last_name_table', { lastName: varchar('last_name', { length: 256 }), }); @@ -260,6 +349,10 @@ export const lastNameUniqueTable = schema.table('last_name_unique_table', { lastNameUnique: varchar('last_name_unique', { length: 256 }).unique(), }); +export const lastNameArrayTable = schema.table('last_name_array_table', { + lastName: varchar('last_name', { length: 256 }).array(), +}); + export const fullNameTable = schema.table('full_name__table', { fullName: varchar('full_name_', { length: 256 }), }); @@ -268,6 +361,10 @@ export const fullNameUniqueTable = schema.table('full_name_unique_table', { fullNameUnique: varchar('full_name_unique', { length: 256 }).unique(), }); +export const fullNameArrayTable = schema.table('full_name_array_table', { + fullName: varchar('full_name', { length: 256 }).array(), +}); + export const countryTable = schema.table('country_table', { country: varchar('country', { length: 256 }), }); @@ -276,6 +373,10 @@ export const countryUniqueTable = schema.table('country_unique_table', { countryUnique: varchar('country_unique', { length: 256 }).unique(), }); +export const countryArrayTable = schema.table('country_array_table', { + country: varchar('country', { length: 256 }).array(), +}); + export const cityTable = schema.table('city_table', { city: varchar('city', { length: 256 }), }); @@ -284,6 +385,10 @@ export const cityUniqueTable = schema.table('city_unique_table', { cityUnique: varchar('city_unique', { length: 256 }).unique(), }); +export const cityArrayTable = schema.table('city_array_table', { + city: varchar('city', { length: 256 }).array(), +}); + export const streetAddressTable = schema.table('street_address_table', { streetAddress: varchar('street_address', { length: 256 }), }); @@ -292,10 +397,18 @@ export const streetAddressUniqueTable = schema.table('street_address_unique_tabl streetAddressUnique: varchar('street_address_unique', { length: 256 }).unique(), }); +export const streetAddressArrayTable = schema.table('street_address_array_table', { + streetAddress: varchar('street_address', { length: 256 }).array(), +}); + export const jobTitleTable = schema.table('job_title_table', { jobTitle: text('job_title'), }); +export const jobTitleArrayTable = schema.table('job_title_array_table', { + jobTitle: text('job_title').array(), +}); + export const postcodeTable = schema.table('postcode_table', { postcode: varchar('postcode', { length: 256 }), }); @@ -304,10 +417,18 @@ export const postcodeUniqueTable = schema.table('postcode_unique_table', { postcodeUnique: varchar('postcode_unique', { length: 256 }).unique(), }); +export const postcodeArrayTable = schema.table('postcode_array_table', { + postcode: varchar('postcode', { length: 256 }).array(), +}); + export const stateTable = schema.table('state_table', { state: text('state'), }); +export const stateArrayTable = schema.table('state_array_table', { + state: text('state').array(), +}); + export const companyNameTable = schema.table('company_name_table', { companyName: text('company_name'), }); @@ -316,18 +437,34 @@ export const companyNameUniqueTable = schema.table('company_name_unique_table', companyNameUnique: varchar('company_name_unique', { length: 256 }).unique(), }); +export const companyNameArrayTable = schema.table('company_name_array_table', { + companyName: text('company_name').array(), +}); + export const loremIpsumTable = schema.table('lorem_ipsum_table', { loremIpsum: text('lorem_ipsum'), }); +export const loremIpsumArrayTable = schema.table('lorem_ipsum_array_table', { + loremIpsum: text('lorem_ipsum').array(), +}); + export const pointTable = schema.table('point_table', { point: point('point'), }); +export const pointArrayTable = schema.table('point_array_table', { + point: point('point').array(), +}); + export const lineTable = schema.table('line_table', { line: line('line'), }); +export const lineArrayTable = schema.table('line_array_table', { + line: line('line').array(), +}); + // export const pointUniqueTable = schema.table("point_unique_table", { // pointUnique: point("point_unique").unique(), // }); @@ -342,6 +479,12 @@ export const phoneNumberTable = schema.table('phone_number_table', { phoneNumberPrefixes: varchar('phone_number_prefixes', { length: 256 }).unique(), }); +export const phoneNumberArrayTable = schema.table('phone_number_array_table', { + phoneNumber: varchar('phoneNumber', { length: 256 }).array(), + phoneNumberTemplate: varchar('phone_number_template', { length: 256 }).array(), + phoneNumberPrefixes: varchar('phone_number_prefixes', { length: 256 }).array(), +}); + export const weightedRandomTable = schema.table('weighted_random_table', { weightedRandom: varchar('weighted_random', { length: 256 }), }); From 819ebd63b8ab09f7b1e9d001dce4f8ee9ecc8781 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 2 Dec 2024 12:12:45 +0200 Subject: [PATCH 407/492] updated migration js text --- drizzle-kit/src/cli/commands/migrate.ts | 17 +++++++++++------ drizzle-kit/src/cli/commands/utils.ts | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 92770e99d..528c39d4a 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -39,7 +39,7 @@ import { } from '../../snapshotsDiffer'; import { assertV1OutFolder, Journal, prepareMigrationFolder } from '../../utils'; import { prepareMigrationMetadata } from '../../utils/words'; -import { CasingType, Prefix } from '../validations/common'; +import { CasingType, Driver, Prefix } from '../validations/common'; import { withStyle } from '../validations/outputs'; import { isRenamePromptItem, @@ -577,6 +577,7 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { breakpoints: config.breakpoints, bundle: config.bundle, prefixMode: config.prefix, + driver: config.driver, }); } catch (e) { console.error(e); @@ -1025,6 +1026,7 @@ export const writeResult = ({ bundle = false, type = 'none', prefixMode, + driver, }: { cur: CommonSchema; sqlStatements: string[]; @@ -1036,6 +1038,7 @@ export const writeResult = ({ name?: string; bundle?: boolean; type?: 'introspect' | 'custom' | 'none'; + driver?: Driver; }) => { if (type === 'none') { console.log(schema(cur)); @@ -1093,9 +1096,9 @@ export const writeResult = ({ fs.writeFileSync(`${outFolder}/${tag}.sql`, sql); - // js file with .sql imports for React Native / Expo + // js file with .sql imports for React Native / Expo and Durable Sqlite Objects if (bundle) { - const js = embeddedMigrations(journal); + const js = embeddedMigrations(journal, driver); fs.writeFileSync(`${outFolder}/migrations.js`, js); } @@ -1112,9 +1115,11 @@ export const writeResult = ({ ); }; -export const embeddedMigrations = (journal: Journal) => { - let content = - '// This file is required for Expo/React Native SQLite migrations - https://orm.drizzle.team/quick-sqlite/expo\n\n'; +export const embeddedMigrations = (journal: Journal, driver?: Driver) => { + let content = driver === 'expo' + ? '// This file is required for Expo/React Native SQLite migrations - https://orm.drizzle.team/quick-sqlite/expo\n\n' + : ''; + content += "import journal from './meta/_journal.json';\n"; journal.entries.forEach((entry) => { content += `import m${entry.idx.toString().padStart(4, '0')} from './${entry.tag}.sql';\n`; diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 8fd625841..f2f060de8 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -127,6 +127,7 @@ export type GenerateConfig = { custom: boolean; bundle: boolean; casing?: CasingType; + driver: Driver; }; export const prepareGenerateConfig = async ( From 3d262cde350dd9327db9993d6196a379328d0b99 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Mon, 2 Dec 2024 12:31:30 +0200 Subject: [PATCH 408/492] updated tests --- drizzle-kit/src/cli/commands/utils.ts | 3 ++- drizzle-kit/tests/cli-generate.test.ts | 27 +++++++++++++++++++ .../tests/cli/durable-sqlite.config.ts | 7 +++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 drizzle-kit/tests/cli/durable-sqlite.config.ts diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index f2f060de8..926fa4d0c 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -127,7 +127,7 @@ export type GenerateConfig = { custom: boolean; bundle: boolean; casing?: CasingType; - driver: Driver; + driver?: Driver; }; export const prepareGenerateConfig = async ( @@ -176,6 +176,7 @@ export const prepareGenerateConfig = async ( out: out || 'drizzle', bundle: driver === 'expo' || driver === 'durable-sqlite', casing, + driver, }; }; diff --git a/drizzle-kit/tests/cli-generate.test.ts b/drizzle-kit/tests/cli-generate.test.ts index 6c8cae09e..a4adf979f 100644 --- a/drizzle-kit/tests/cli-generate.test.ts +++ b/drizzle-kit/tests/cli-generate.test.ts @@ -39,6 +39,7 @@ test('generate #1', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -59,6 +60,7 @@ test('generate #2', async (t) => { out: 'out', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -76,6 +78,7 @@ test('generate #3', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -94,6 +97,7 @@ test('generate #4', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -111,6 +115,7 @@ test('generate #5', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -128,6 +133,7 @@ test('generate #6', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -148,6 +154,7 @@ test('generate #7', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -166,6 +173,25 @@ test('generate #8', async (t) => { out: 'drizzle', bundle: true, // expo driver casing: undefined, + driver: 'expo', + }); +}); + +test('generate #9', async (t) => { + const res = await brotest(generate, '--config=durable-sqlite.config.ts'); + assert.equal(res.type, 'handler'); + if (res.type !== 'handler') assert.fail(res.type, 'handler'); + expect(res.options).toStrictEqual({ + dialect: 'sqlite', + name: undefined, + custom: false, + prefix: 'index', + breakpoints: true, + schema: './schema.ts', + out: 'drizzle', + bundle: true, // expo driver + casing: undefined, + driver: 'durable-sqlite', }); }); @@ -187,6 +213,7 @@ test('generate #9', async (t) => { out: 'out', bundle: false, casing: undefined, + driver: undefined, }); }); diff --git a/drizzle-kit/tests/cli/durable-sqlite.config.ts b/drizzle-kit/tests/cli/durable-sqlite.config.ts new file mode 100644 index 000000000..c3f4e44f0 --- /dev/null +++ b/drizzle-kit/tests/cli/durable-sqlite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from '../../src'; + +export default defineConfig({ + schema: './schema.ts', + dialect: 'sqlite', + driver: 'durable-sqlite', +}); From 694f9c2dd1958571a332dbd5080f6243d017febf Mon Sep 17 00:00:00 2001 From: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> Date: Mon, 2 Dec 2024 12:50:40 +0200 Subject: [PATCH 409/492] Extended Neon HTTP `$withAuth` token variants (#3622) * Added callback & async callback variants for `neon-http` auth tokens, safer typecheck on token applying proxy * Added callback & async callback variants for `neon-http` auth tokens, safer typecheck on token applying proxy * Fixed `$count`'s `.setToken` not returning`this` * Switched `neon-http`'s `$withAuth` token to use neon's type * Synced `wrap`'s token type with `$withAuth`'s --- drizzle-orm/src/neon-http/driver.ts | 8 +- drizzle-orm/src/neon-http/session.ts | 14 +- drizzle-orm/src/pg-core/db.ts | 4 +- .../src/pg-core/query-builders/count.ts | 6 +- .../src/pg-core/query-builders/delete.ts | 6 +- .../src/pg-core/query-builders/insert.ts | 38 ++-- .../src/pg-core/query-builders/query.ts | 6 +- .../refresh-materialized-view.ts | 5 +- .../src/pg-core/query-builders/select.ts | 47 ++-- .../src/pg-core/query-builders/update.ts | 39 ++-- drizzle-orm/src/pg-core/session.ts | 17 +- drizzle-orm/src/utils.ts | 2 + .../type-tests/utils/neon-auth-token.ts | 5 + integration-tests/tests/pg/neon-http.test.ts | 202 ++++++++++++++++++ 14 files changed, 299 insertions(+), 100 deletions(-) create mode 100644 drizzle-orm/type-tests/utils/neon-auth-token.ts diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index cbe1689fb..209e41963 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -1,4 +1,4 @@ -import type { HTTPTransactionOptions, NeonQueryFunction } from '@neondatabase/serverless'; +import type { HTTPQueryOptions, HTTPTransactionOptions, NeonQueryFunction } from '@neondatabase/serverless'; import { neon, types } from '@neondatabase/serverless'; import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; @@ -42,7 +42,7 @@ export class NeonHttpDriver { function wrap( target: T, - token: string, + token: Exclude['authToken'], undefined>, cb: (target: any, p: string | symbol, res: any) => any, deep?: boolean, ) { @@ -57,7 +57,7 @@ function wrap( return new Proxy(element as any, { apply(target, thisArg, argArray) { const res = target.call(thisArg, ...argArray); - if ('setToken' in res && typeof res.setToken === 'function') { + if (typeof res === 'object' && res !== null && 'setToken' in res && typeof res.setToken === 'function') { res.setToken(token); } return cb(target, p, res); @@ -73,7 +73,7 @@ export class NeonHttpDatabase< static override readonly [entityKind]: string = 'NeonHttpDatabase'; $withAuth( - token: string, + token: Exclude['authToken'], undefined>, ): Omit< this, Exclude< diff --git a/drizzle-orm/src/neon-http/session.ts b/drizzle-orm/src/neon-http/session.ts index c8f8f5a33..00ffe26e7 100644 --- a/drizzle-orm/src/neon-http/session.ts +++ b/drizzle-orm/src/neon-http/session.ts @@ -11,7 +11,7 @@ import { PgPreparedQuery as PgPreparedQuery, PgSession } from '~/pg-core/session import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import type { PreparedQuery } from '~/session.ts'; import { fillPlaceholders, type Query, type SQL } from '~/sql/sql.ts'; -import { mapResultRow } from '~/utils.ts'; +import { mapResultRow, type NeonAuthToken } from '~/utils.ts'; export type NeonHttpClient = NeonQueryFunction; @@ -40,11 +40,11 @@ export class NeonHttpPreparedQuery extends PgPrep async execute(placeholderValues: Record | undefined): Promise; /** @internal */ - async execute(placeholderValues: Record | undefined, token?: string): Promise; + async execute(placeholderValues: Record | undefined, token?: NeonAuthToken): Promise; /** @internal */ async execute( placeholderValues: Record | undefined = {}, - token: string | undefined = this.authToken, + token: NeonAuthToken | undefined = this.authToken, ): Promise { const params = fillPlaceholders(this.query.params, placeholderValues); @@ -108,9 +108,9 @@ export class NeonHttpPreparedQuery extends PgPrep values(placeholderValues: Record | undefined): Promise; /** @internal */ - values(placeholderValues: Record | undefined, token?: string): Promise; + values(placeholderValues: Record | undefined, token?: NeonAuthToken): Promise; /** @internal */ - values(placeholderValues: Record | undefined = {}, token?: string): Promise { + values(placeholderValues: Record | undefined = {}, token?: NeonAuthToken): Promise { const params = fillPlaceholders(this.query.params, placeholderValues); this.logger.logQuery(this.query.sql, params); return this.client(this.query.sql, params, { arrayMode: true, fullResults: true, authToken: token }).then(( @@ -203,9 +203,9 @@ export class NeonHttpSession< override async count(sql: SQL): Promise; /** @internal */ - override async count(sql: SQL, token?: string): Promise; + override async count(sql: SQL, token?: NeonAuthToken): Promise; /** @internal */ - override async count(sql: SQL, token?: string): Promise { + override async count(sql: SQL, token?: NeonAuthToken): Promise { const res = await this.execute<{ rows: [{ count: string }] }>(sql, token); return Number( diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index e3c7e4444..e1efb5dec 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -21,7 +21,7 @@ import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelation import { SelectionProxyHandler } from '~/selection-proxy.ts'; import { type ColumnsSelection, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; -import type { DrizzleTypeError } from '~/utils.ts'; +import type { DrizzleTypeError, NeonAuthToken } from '~/utils.ts'; import type { PgColumn } from './columns/index.ts'; import { PgCountBuilder } from './query-builders/count.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; @@ -597,7 +597,7 @@ export class PgDatabase< return new PgRefreshMaterializedView(view, this.session, this.dialect); } - protected authToken?: string; + protected authToken?: NeonAuthToken; execute = Record>( query: SQLWrapper | string, diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index e620c7428..a86ffd745 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -1,5 +1,6 @@ import { entityKind } from '~/entity.ts'; import { SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; +import type { NeonAuthToken } from '~/utils.ts'; import type { PgSession } from '../session.ts'; import type { PgTable } from '../table.ts'; @@ -7,7 +8,7 @@ export class PgCountBuilder< TSession extends PgSession, > extends SQL implements Promise, SQLWrapper { private sql: SQL; - private token?: string; + private token?: NeonAuthToken; static override readonly [entityKind] = 'PgCountBuilder'; [Symbol.toStringTag] = 'PgCountBuilder'; @@ -48,8 +49,9 @@ export class PgCountBuilder< } /** @intrnal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.token = token; + return this; } then( diff --git a/drizzle-orm/src/pg-core/query-builders/delete.ts b/drizzle-orm/src/pg-core/query-builders/delete.ts index 97bcdc044..682e52e2d 100644 --- a/drizzle-orm/src/pg-core/query-builders/delete.ts +++ b/drizzle-orm/src/pg-core/query-builders/delete.ts @@ -15,7 +15,7 @@ import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; -import { orderSelectedFields } from '~/utils.ts'; +import { type NeonAuthToken, orderSelectedFields } from '~/utils.ts'; import type { PgColumn } from '../columns/common.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; @@ -232,9 +232,9 @@ export class PgDeleteBase< return this._prepare(name); } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index c1849d4bb..2cf266be4 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -19,7 +19,7 @@ import type { Subquery } from '~/subquery.ts'; import type { InferInsertModel } from '~/table.ts'; import { Columns, Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; -import { haveSameKeys, mapUpdateSet, orderSelectedFields } from '~/utils.ts'; +import { haveSameKeys, mapUpdateSet, type NeonAuthToken, orderSelectedFields } from '~/utils.ts'; import type { AnyPgColumn, PgColumn } from '../columns/common.ts'; import { QueryBuilder } from './query-builder.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; @@ -63,9 +63,9 @@ export class PgInsertBuilder< private overridingSystemValue_?: boolean, ) {} - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } @@ -94,25 +94,15 @@ export class PgInsertBuilder< return result; }); - return this.authToken === undefined - ? new PgInsertBase( - this.table, - mappedValues, - this.session, - this.dialect, - this.withList, - false, - this.overridingSystemValue_, - ) - : new PgInsertBase( - this.table, - mappedValues, - this.session, - this.dialect, - this.withList, - false, - this.overridingSystemValue_, - ).setToken(this.authToken) as any; + return new PgInsertBase( + this.table, + mappedValues, + this.session, + this.dialect, + this.withList, + false, + this.overridingSystemValue_, + ).setToken(this.authToken) as any; } select(selectQuery: (qb: QueryBuilder) => PgInsertSelectQueryBuilder): PgInsertBase; @@ -402,9 +392,9 @@ export class PgInsertBase< return this._prepare(name); } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/query-builders/query.ts b/drizzle-orm/src/pg-core/query-builders/query.ts index c664e761d..816b60500 100644 --- a/drizzle-orm/src/pg-core/query-builders/query.ts +++ b/drizzle-orm/src/pg-core/query-builders/query.ts @@ -11,7 +11,7 @@ import { import type { RunnableQuery } from '~/runnable-query.ts'; import type { Query, QueryWithTypings, SQL, SQLWrapper } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; -import type { KnownKeysOnly } from '~/utils.ts'; +import type { KnownKeysOnly, NeonAuthToken } from '~/utils.ts'; import type { PgDialect } from '../dialect.ts'; import type { PgPreparedQuery, PgSession, PreparedQueryConfig } from '../session.ts'; import type { PgTable } from '../table.ts'; @@ -142,9 +142,9 @@ export class PgRelationalQuery extends QueryPromise return this._toSQL().builtQuery; } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts index f171023da..c20baaf5a 100644 --- a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts +++ b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts @@ -12,6 +12,7 @@ import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; +import type { NeonAuthToken } from '~/utils'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface PgRefreshMaterializedView @@ -92,9 +93,9 @@ export class PgRefreshMaterializedView return this._prepare(name); } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/query-builders/select.ts b/drizzle-orm/src/pg-core/query-builders/select.ts index 813a89bd1..597991f79 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.ts @@ -24,7 +24,14 @@ import type { ColumnsSelection, Placeholder, Query, SQLWrapper } from '~/sql/sql import { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; -import { applyMixins, getTableColumns, getTableLikeName, haveSameKeys, type ValueOrArray } from '~/utils.ts'; +import { + applyMixins, + getTableColumns, + getTableLikeName, + haveSameKeys, + type NeonAuthToken, + type ValueOrArray, +} from '~/utils.ts'; import { orderSelectedFields } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { @@ -81,9 +88,9 @@ export class PgSelectBuilder< this.distinct = config.distinct; } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } @@ -122,25 +129,15 @@ export class PgSelectBuilder< fields = getTableColumns(source); } - return (this.authToken === undefined - ? new PgSelectBase({ - table: source, - fields, - isPartialSelect, - session: this.session, - dialect: this.dialect, - withList: this.withList, - distinct: this.distinct, - }) - : new PgSelectBase({ - table: source, - fields, - isPartialSelect, - session: this.session, - dialect: this.dialect, - withList: this.withList, - distinct: this.distinct, - }).setToken(this.authToken)) as any; + return (new PgSelectBase({ + table: source, + fields, + isPartialSelect, + session: this.session, + dialect: this.dialect, + withList: this.withList, + distinct: this.distinct, + }).setToken(this.authToken)) as any; } } @@ -979,7 +976,7 @@ export class PgSelectBase< >(dialect.sqlToQuery(this.getSQL()), fieldsList, name, true); query.joinsNotNullableMap = joinsNotNullableMap; - return authToken === undefined ? query : query.setToken(authToken); + return query.setToken(authToken); }); } @@ -994,9 +991,9 @@ export class PgSelectBase< return this._prepare(name); } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index a8810ed5a..c6d04ee35 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -25,7 +25,14 @@ import { SelectionProxyHandler } from '~/selection-proxy.ts'; import { type ColumnsSelection, type Query, SQL, type SQLWrapper } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; -import { type Assume, getTableLikeName, mapUpdateSet, orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { + type Assume, + getTableLikeName, + mapUpdateSet, + type NeonAuthToken, + orderSelectedFields, + type UpdateSet, +} from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { PgColumn } from '../columns/common.ts'; import type { PgViewBase } from '../view-base.ts'; @@ -64,8 +71,8 @@ export class PgUpdateBuilder, ): PgUpdateWithout, false, 'leftJoin' | 'rightJoin' | 'innerJoin' | 'fullJoin'> { - return this.authToken === undefined - ? new PgUpdateBase( - this.table, - mapUpdateSet(this.table, values), - this.session, - this.dialect, - this.withList, - ) - : new PgUpdateBase( - this.table, - mapUpdateSet(this.table, values), - this.session, - this.dialect, - this.withList, - ).setToken(this.authToken); + return new PgUpdateBase( + this.table, + mapUpdateSet(this.table, values), + this.session, + this.dialect, + this.withList, + ).setToken(this.authToken); } } @@ -548,9 +547,9 @@ export class PgUpdateBase< return this._prepare(name); } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/session.ts b/drizzle-orm/src/pg-core/session.ts index 8dff92f6b..d77f2c4db 100644 --- a/drizzle-orm/src/pg-core/session.ts +++ b/drizzle-orm/src/pg-core/session.ts @@ -4,6 +4,7 @@ import type { TablesRelationalConfig } from '~/relations.ts'; import type { PreparedQuery } from '~/session.ts'; import { type Query, type SQL, sql } from '~/sql/index.ts'; import { tracer } from '~/tracing.ts'; +import type { NeonAuthToken } from '~/utils.ts'; import { PgDatabase } from './db.ts'; import type { PgDialect } from './dialect.ts'; import type { SelectedFieldsOrdered } from './query-builders/select.types.ts'; @@ -17,7 +18,7 @@ export interface PreparedQueryConfig { export abstract class PgPreparedQuery implements PreparedQuery { constructor(protected query: Query) {} - protected authToken?: string; + protected authToken?: NeonAuthToken; getQuery(): Query { return this.query; @@ -28,7 +29,7 @@ export abstract class PgPreparedQuery implements } /** @internal */ - setToken(token?: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } @@ -40,9 +41,9 @@ export abstract class PgPreparedQuery implements abstract execute(placeholderValues?: Record): Promise; /** @internal */ - abstract execute(placeholderValues?: Record, token?: string): Promise; + abstract execute(placeholderValues?: Record, token?: NeonAuthToken): Promise; /** @internal */ - abstract execute(placeholderValues?: Record, token?: string): Promise; + abstract execute(placeholderValues?: Record, token?: NeonAuthToken): Promise; /** @internal */ abstract all(placeholderValues?: Record): Promise; @@ -76,9 +77,9 @@ export abstract class PgSession< execute(query: SQL): Promise; /** @internal */ - execute(query: SQL, token?: string): Promise; + execute(query: SQL, token?: NeonAuthToken): Promise; /** @internal */ - execute(query: SQL, token?: string): Promise { + execute(query: SQL, token?: NeonAuthToken): Promise { return tracer.startActiveSpan('drizzle.operation', () => { const prepared = tracer.startActiveSpan('drizzle.prepareQuery', () => { return this.prepareQuery( @@ -104,9 +105,9 @@ export abstract class PgSession< async count(sql: SQL): Promise; /** @internal */ - async count(sql: SQL, token?: string): Promise; + async count(sql: SQL, token?: NeonAuthToken): Promise; /** @internal */ - async count(sql: SQL, token?: string): Promise { + async count(sql: SQL, token?: NeonAuthToken): Promise { const res = await this.execute<[{ count: string }]>(sql, token); return Number( diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index bd8fea848..58d0c3d91 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -311,3 +311,5 @@ export function isConfig(data: any): boolean { return false; } + +export type NeonAuthToken = string | (() => string | Promise); diff --git a/drizzle-orm/type-tests/utils/neon-auth-token.ts b/drizzle-orm/type-tests/utils/neon-auth-token.ts new file mode 100644 index 000000000..5ea684ddc --- /dev/null +++ b/drizzle-orm/type-tests/utils/neon-auth-token.ts @@ -0,0 +1,5 @@ +import type { HTTPQueryOptions } from '@neondatabase/serverless'; +import { type Equal, Expect } from 'type-tests/utils.ts'; +import type { NeonAuthToken } from '~/utils'; + +Expect['authToken'], undefined>, NeonAuthToken>>; diff --git a/integration-tests/tests/pg/neon-http.test.ts b/integration-tests/tests/pg/neon-http.test.ts index 7cb433653..8fee5b82d 100644 --- a/integration-tests/tests/pg/neon-http.test.ts +++ b/integration-tests/tests/pg/neon-http.test.ts @@ -586,3 +586,205 @@ describe('$withAuth tests', (it) => { }); }); }); + +describe('$withAuth callback tests', (it) => { + const client = vi.fn(); + const db = drizzle({ + client: client as any as NeonQueryFunction, + schema: { + usersTable, + }, + }); + const auth = (token: string) => () => token; + + it('$count', async () => { + await db.$withAuth(auth('$count')).$count(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('$count'); + }); + + it('delete', async () => { + await db.$withAuth(auth('delete')).delete(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('delete'); + }); + + it('select', async () => { + await db.$withAuth(auth('select')).select().from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('select'); + }); + + it('selectDistinct', async () => { + await db.$withAuth(auth('selectDistinct')).selectDistinct().from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('selectDistinct'); + }); + + it('selectDistinctOn', async () => { + await db.$withAuth(auth('selectDistinctOn')).selectDistinctOn([usersTable.name]).from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('selectDistinctOn'); + }); + + it('update', async () => { + await db.$withAuth(auth('update')).update(usersTable).set({ + name: 'CHANGED', + }).where(eq(usersTable.name, 'TARGET')).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('update'); + }); + + it('insert', async () => { + await db.$withAuth(auth('insert')).insert(usersTable).values({ + name: 'WITHAUTHUSER', + }).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('insert'); + }); + + it('with', async () => { + await db.$withAuth(auth('with')).with(db.$with('WITH').as((qb) => qb.select().from(usersTable))).select().from( + usersTable, + ) + .catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('with'); + }); + + it('rqb', async () => { + await db.$withAuth(auth('rqb')).query.usersTable.findFirst().catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('rqb'); + }); + + it('exec', async () => { + await db.$withAuth(auth('exec')).execute(`SELECT 1`).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('exec'); + }); + + it('prepared', async () => { + const prep = db.$withAuth(auth('prepared')).select().from(usersTable).prepare('withAuthPrepared'); + + await prep.execute().catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('prepared'); + }); + + it('refreshMaterializedView', async () => { + const johns = pgMaterializedView('johns') + .as((qb) => qb.select().from(usersTable).where(eq(usersTable.name, 'John'))); + + await db.$withAuth(auth('refreshMaterializedView')).refreshMaterializedView(johns); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('refreshMaterializedView'); + }); +}); + +describe('$withAuth async callback tests', (it) => { + const client = vi.fn(); + const db = drizzle({ + client: client as any as NeonQueryFunction, + schema: { + usersTable, + }, + }); + const auth = (token: string) => async () => token; + + it('$count', async () => { + await db.$withAuth(auth('$count')).$count(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('$count'); + }); + + it('delete', async () => { + await db.$withAuth(auth('delete')).delete(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('delete'); + }); + + it('select', async () => { + await db.$withAuth(auth('select')).select().from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('select'); + }); + + it('selectDistinct', async () => { + await db.$withAuth(auth('selectDistinct')).selectDistinct().from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('selectDistinct'); + }); + + it('selectDistinctOn', async () => { + await db.$withAuth(auth('selectDistinctOn')).selectDistinctOn([usersTable.name]).from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('selectDistinctOn'); + }); + + it('update', async () => { + await db.$withAuth(auth('update')).update(usersTable).set({ + name: 'CHANGED', + }).where(eq(usersTable.name, 'TARGET')).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('update'); + }); + + it('insert', async () => { + await db.$withAuth(auth('insert')).insert(usersTable).values({ + name: 'WITHAUTHUSER', + }).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('insert'); + }); + + it('with', async () => { + await db.$withAuth(auth('with')).with(db.$with('WITH').as((qb) => qb.select().from(usersTable))).select().from( + usersTable, + ) + .catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('with'); + }); + + it('rqb', async () => { + await db.$withAuth(auth('rqb')).query.usersTable.findFirst().catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('rqb'); + }); + + it('exec', async () => { + await db.$withAuth(auth('exec')).execute(`SELECT 1`).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('exec'); + }); + + it('prepared', async () => { + const prep = db.$withAuth(auth('prepared')).select().from(usersTable).prepare('withAuthPrepared'); + + await prep.execute().catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('prepared'); + }); + + it('refreshMaterializedView', async () => { + const johns = pgMaterializedView('johns') + .as((qb) => qb.select().from(usersTable).where(eq(usersTable.name, 'John'))); + + await db.$withAuth(auth('refreshMaterializedView')).refreshMaterializedView(johns); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('refreshMaterializedView'); + }); +}); From 8de18a04896d3026df85abeccc7c5e0e16dc6228 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 2 Dec 2024 17:57:30 +0200 Subject: [PATCH 410/492] bug fixes, added support for uuid postgres column --- drizzle-seed/src/index.ts | 3 +- .../src/services/GeneratorsWrappers.ts | 68 ++++++++++++++++--- drizzle-seed/src/services/SeedService.ts | 36 ++++++++-- drizzle-seed/src/services/utils.ts | 10 +++ drizzle-seed/src/type-tests/mysql.ts | 17 ----- drizzle-seed/src/type-tests/pg.ts | 48 ------------- drizzle-seed/src/type-tests/sqlite.ts | 17 ----- drizzle-seed/src/type-tests/tsconfig.json | 11 --- .../tests/pg/allDataTypesTest/pgSchema.ts | 2 + .../pg_all_data_types.test.ts | 3 +- integration-tests/tests/seeder/pg.test.ts | 3 +- integration-tests/tests/seeder/pgSchema.ts | 2 + 12 files changed, 109 insertions(+), 111 deletions(-) delete mode 100644 drizzle-seed/src/type-tests/mysql.ts delete mode 100644 drizzle-seed/src/type-tests/pg.ts delete mode 100644 drizzle-seed/src/type-tests/sqlite.ts delete mode 100644 drizzle-seed/src/type-tests/tsconfig.json diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 6a8d95181..684de5009 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -451,7 +451,7 @@ const resetPostgres = async ( const config = getPgTableConfig(table); config.schema = config.schema === undefined ? 'public' : config.schema; - return `${config.schema}.${config.name}`; + return `"${config.schema}"."${config.name}"`; }); await db.execute(sql.raw(`truncate ${tablesToTruncate.join(',')} cascade;`)); @@ -603,7 +603,6 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { }); } - // console.log(tables[0]?.columns) return { tables, relations }; }; diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts index 7d701f546..34f12fef1 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -12,7 +12,7 @@ import loremIpsumSentences from '../datasets/loremIpsumSentences.ts'; import phonesInfo from '../datasets/phonesInfo.ts'; import states from '../datasets/states.ts'; import streetSuffix from '../datasets/streetSuffix.ts'; -import { fastCartesianProduct, fillTemplate, getWeightedIndices } from './utils.ts'; +import { fastCartesianProduct, fillTemplate, getWeightedIndices, isObject } from './utils.ts'; export abstract class AbstractGenerator { static readonly [entityKind]: string = 'AbstractGenerator'; @@ -205,7 +205,7 @@ export class GenerateValuesFromArray extends AbstractGenerator< } if ( - typeof values[0] === 'object' + isObject(values[0]) && !(values as { weight: number; values: any[] }[]).every((val) => val.values.length !== 0) ) { throw new Error('One of weighted values length equals zero.'); @@ -226,7 +226,7 @@ export class GenerateValuesFromArray extends AbstractGenerator< } let allValuesCount = values.length; - if (typeof values[0] === 'object') { + if (isObject(values[0])) { allValuesCount = (values as { values: any[] }[]).reduce((acc, currVal) => acc + currVal.values.length, 0); } @@ -234,9 +234,9 @@ export class GenerateValuesFromArray extends AbstractGenerator< notNull === true && maxRepeatedValuesCount !== undefined && ( - (typeof values[0] !== 'object' && typeof maxRepeatedValuesCount === 'number' + (!isObject(values[0]) && typeof maxRepeatedValuesCount === 'number' && maxRepeatedValuesCount * values.length < count) - || (typeof values[0] === 'object' && typeof maxRepeatedValuesCount === 'number' + || (isObject(values[0]) && typeof maxRepeatedValuesCount === 'number' && maxRepeatedValuesCount * allValuesCount < count) ) ) { @@ -259,8 +259,8 @@ export class GenerateValuesFromArray extends AbstractGenerator< if ( isUnique === true && notNull === true && ( - (typeof values[0] !== 'object' && values.length < count) - || (typeof values[0] === 'object' && allValuesCount < count) + (!isObject(values[0]) && values.length < count) + || (isObject(values[0]) && allValuesCount < count) ) ) { // console.log(maxRepeatedValuesCount, values.length, allValuesCount, count) @@ -289,7 +289,7 @@ export class GenerateValuesFromArray extends AbstractGenerator< const values = params.values; let valuesWeightedIndices; - if (typeof values[0] === 'object') { + if (isObject(values[0])) { valuesWeightedIndices = getWeightedIndices((values as { weight: number }[]).map((val) => val.weight)); if (isUnique === true && notNull === true) { let idx: number, valueIdx: number, rng = prand.xoroshiro128plus(seed); @@ -335,12 +335,12 @@ export class GenerateValuesFromArray extends AbstractGenerator< let genIndicesObjList: GenerateUniqueInt[] | undefined; if (maxRepeatedValuesCount !== undefined) { - if (typeof values[0] !== 'object') { + if (!isObject(values[0])) { genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: values.length - 1 }); genIndicesObj.genMaxRepeatedValuesCount = genMaxRepeatedValuesCount; genIndicesObj.skipCheck = true; genIndicesObj.init({ count, seed }); - } else if (typeof values[0] === 'object') { + } else if (isObject(values[0])) { genIndicesObjList = []; for (const obj of values as { weight: number; values: (number | string | boolean | undefined)[] }[]) { const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: obj.values.length - 1 }); @@ -1479,6 +1479,54 @@ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean } } +export class GenerateUUID extends AbstractGenerator<{ + arraySize?: number; +}> { + static override readonly [entityKind]: string = 'GenerateUUID'; + + public override isUnique = true; + + private state: { rng: prand.RandomGenerator } | undefined; + + init({ seed }: { seed: number }) { + if (this.params.arraySize !== undefined) { + this.arraySize = this.params.arraySize; + } + + const rng = prand.xoroshiro128plus(seed); + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + // TODO generate uuid using string generator + const stringChars = '1234567890abcdef'; + let idx: number, + currStr: string; + const strLength = 36; + + // uuid v4 + const uuidTemplate = '########-####-4###-####-############'; + currStr = ''; + for (let i = 0; i < strLength; i++) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + stringChars.length - 1, + this.state.rng, + ); + + if (uuidTemplate[i] === '#') { + currStr += stringChars[idx]; + continue; + } + currStr += uuidTemplate[i]; + } + return currStr; + } +} + export class GenerateFirstName extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 508e3714b..59ac0f3fe 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -34,6 +34,7 @@ import { GenerateTime, GenerateTimestamp, GenerateUniqueString, + GenerateUUID, GenerateValuesFromArray, GenerateWeightedCount, GenerateYear, @@ -204,10 +205,6 @@ class SeedService { } else if (Object.hasOwn(foreignKeyColumns, col.name)) { // TODO: I might need to assign repeatedValuesCount to column there instead of doing so in generateTablesValues columnPossibleGenerator.generator = new HollowGenerator({}); - } else if (col.hasDefault && col.default !== undefined) { - columnPossibleGenerator.generator = new GenerateDefault({ - defaultValue: col.default, - }); } // TODO: rewrite pickGeneratorFor... using new col properties: isUnique and notNull else if (connectionType === 'postgresql') { columnPossibleGenerator.generator = this.pickGeneratorForPostgresColumn( @@ -227,6 +224,7 @@ class SeedService { } if (columnPossibleGenerator.generator === undefined) { + console.log(col); throw new Error( `column with type ${col.columnType} is not supported for now.`, ); @@ -501,6 +499,15 @@ class SeedService { return generator; } + // UUID + if (col.columnType === 'uuid') { + generator = new GenerateUUID({}); + + generator.isUnique = col.isUnique; + generator.dataType = col.dataType; + return generator; + } + // BOOLEAN if (col.columnType === 'boolean') { generator = new GenerateBoolean({}); @@ -599,6 +606,13 @@ class SeedService { return generator; } + if (col.hasDefault && col.default !== undefined) { + generator = new GenerateDefault({ + defaultValue: col.default, + }); + return generator; + } + return generator; }; @@ -770,6 +784,13 @@ class SeedService { return generator; } + if (col.hasDefault && col.default !== undefined) { + const generator = new GenerateDefault({ + defaultValue: col.default, + }); + return generator; + } + return; }; @@ -857,6 +878,13 @@ class SeedService { return generator; } + if (col.hasDefault && col.default !== undefined) { + const generator = new GenerateDefault({ + defaultValue: col.default, + }); + return generator; + } + return; }; diff --git a/drizzle-seed/src/services/utils.ts b/drizzle-seed/src/services/utils.ts index 8ce3db04f..d14cabce0 100644 --- a/drizzle-seed/src/services/utils.ts +++ b/drizzle-seed/src/services/utils.ts @@ -89,3 +89,13 @@ export const fillTemplate = ({ template, placeholdersCount, values, defaultValue return resultStr; }; + +// is variable is object-like. +// Example: +// isObject({f: 4}) === true; +// isObject([1,2,3]) === false; +// isObject(new Set()) === false; +export const isObject = (value: any) => { + if (value !== null && value !== undefined && value.constructor === Object) return true; + return false; +}; diff --git a/drizzle-seed/src/type-tests/mysql.ts b/drizzle-seed/src/type-tests/mysql.ts deleted file mode 100644 index d1c0949b3..000000000 --- a/drizzle-seed/src/type-tests/mysql.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { MySqlColumn } from 'drizzle-orm/mysql-core'; -import { int, mysqlTable, text } from 'drizzle-orm/mysql-core'; -import { drizzle as mysql2Drizzle } from 'drizzle-orm/mysql2'; -import { reset, seed } from '../index.ts'; - -const mysqlUsers = mysqlTable('users', { - id: int().primaryKey().autoincrement(), - name: text(), - inviteId: int('invite_id').references((): MySqlColumn => mysqlUsers.id), -}); - -{ - const db = mysql2Drizzle(''); - - await seed(db, { users: mysqlUsers }); - await reset(db, { users: mysqlUsers }); -} diff --git a/drizzle-seed/src/type-tests/pg.ts b/drizzle-seed/src/type-tests/pg.ts deleted file mode 100644 index 68faf844b..000000000 --- a/drizzle-seed/src/type-tests/pg.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { drizzle as nodePostgresDrizzle } from 'drizzle-orm/node-postgres'; -import type { PgColumn } from 'drizzle-orm/pg-core'; -import { integer, pgTable, text } from 'drizzle-orm/pg-core'; -import { drizzle as pgliteDrizzle } from 'drizzle-orm/pglite'; -import { drizzle as postgresJsDrizzle } from 'drizzle-orm/postgres-js'; -import { reset, seed } from '../index.ts'; - -const pgUsers = pgTable('users', { - id: integer().primaryKey().generatedAlwaysAsIdentity(), - name: text(), - inviteId: integer('invite_id').references((): PgColumn => pgUsers.id), -}); - -{ - const db0 = nodePostgresDrizzle('', { schema: { users: pgUsers } }); - - await seed(db0, { users: pgUsers }); - await reset(db0, { users: pgUsers }); - - const db1 = nodePostgresDrizzle(''); - - await seed(db1, { users: pgUsers }); - await reset(db1, { users: pgUsers }); -} - -{ - const db0 = pgliteDrizzle('', { schema: { users: pgUsers } }); - - await seed(db0, { users: pgUsers }); - await reset(db0, { users: pgUsers }); - - const db1 = pgliteDrizzle(''); - - await seed(db1, { users: pgUsers }); - await reset(db1, { users: pgUsers }); -} - -{ - const db0 = postgresJsDrizzle('', { schema: { users: pgUsers } }); - - await seed(db0, { users: pgUsers }); - await reset(db0, { users: pgUsers }); - - const db1 = postgresJsDrizzle(''); - - await seed(db1, { users: pgUsers }); - await reset(db1, { users: pgUsers }); -} diff --git a/drizzle-seed/src/type-tests/sqlite.ts b/drizzle-seed/src/type-tests/sqlite.ts deleted file mode 100644 index 1b060e6a3..000000000 --- a/drizzle-seed/src/type-tests/sqlite.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { drizzle as betterSqlite3Drizzle } from 'drizzle-orm/better-sqlite3'; -import type { SQLiteColumn } from 'drizzle-orm/sqlite-core'; -import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { reset, seed } from '../index.ts'; - -const mysqlUsers = sqliteTable('users', { - id: int().primaryKey(), - name: text(), - inviteId: int('invite_id').references((): SQLiteColumn => mysqlUsers.id), -}); - -{ - const db = betterSqlite3Drizzle(''); - - await seed(db, { users: mysqlUsers }); - await reset(db, { users: mysqlUsers }); -} diff --git a/drizzle-seed/src/type-tests/tsconfig.json b/drizzle-seed/src/type-tests/tsconfig.json deleted file mode 100644 index 09df8e1bb..000000000 --- a/drizzle-seed/src/type-tests/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "../../tsconfig.build.json", - "compilerOptions": { - "composite": false, - "noEmit": true, - "rootDir": "..", - "outDir": "./.cache" - }, - "include": [".", "../src"], - "exclude": ["**/playground"] -} diff --git a/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts b/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts index 5bd428a1c..75ba20a43 100644 --- a/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts +++ b/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts @@ -22,6 +22,7 @@ import { text, time, timestamp, + uuid, varchar, } from 'drizzle-orm/pg-core'; @@ -59,6 +60,7 @@ export const allDataTypes = schema.table('all_data_types', { line: line('line', { mode: 'abc' }), lineTuple: line('line_tuple', { mode: 'tuple' }), moodEnum: moodEnum('mood_enum'), + uuid: uuid('uuid'), }); export const allArrayDataTypes = schema.table('all_array_data_types', { diff --git a/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts b/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts index c209107ae..7dfbc089b 100644 --- a/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts +++ b/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts @@ -57,7 +57,8 @@ beforeAll(async () => { "point_tuple" "point", "line" "line", "line_tuple" "line", - "mood_enum" "seeder_lib_pg"."mood_enum" + "mood_enum" "seeder_lib_pg"."mood_enum", + "uuid" "uuid" ); `, ); diff --git a/integration-tests/tests/seeder/pg.test.ts b/integration-tests/tests/seeder/pg.test.ts index 83c0fd19d..48109f9fa 100644 --- a/integration-tests/tests/seeder/pg.test.ts +++ b/integration-tests/tests/seeder/pg.test.ts @@ -219,7 +219,8 @@ const createAllDataTypesTable = async () => { "point_tuple" "point", "line" "line", "line_tuple" "line", - "mood_enum" "seeder_lib_pg"."mood_enum" + "mood_enum" "seeder_lib_pg"."mood_enum", + "uuid" "uuid" ); `, ); diff --git a/integration-tests/tests/seeder/pgSchema.ts b/integration-tests/tests/seeder/pgSchema.ts index fc4dda3c1..ee0fceff5 100644 --- a/integration-tests/tests/seeder/pgSchema.ts +++ b/integration-tests/tests/seeder/pgSchema.ts @@ -23,6 +23,7 @@ import { text, time, timestamp, + uuid, varchar, } from 'drizzle-orm/pg-core'; @@ -161,6 +162,7 @@ export const allDataTypes = schema.table('all_data_types', { line: line('line', { mode: 'abc' }), lineTuple: line('line_tuple', { mode: 'tuple' }), moodEnum: moodEnum('mood_enum'), + uuid: uuid('uuid'), }); export const allArrayDataTypes = schema.table('all_array_data_types', { From 9aed6a3610d024ced921068b3baf2a0f0542a1f4 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 3 Dec 2024 11:04:04 +0200 Subject: [PATCH 411/492] Format --- drizzle-orm/src/pg-core/db.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index 789460d07..29dc4f166 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -670,7 +670,7 @@ export const withReplicas = < select, selectDistinct, selectDistinctOn, - $with, + $with, with: _with, get query() { return getReplica(replicas).query; From 61b4e8e414fbc5da282e787ebb20f20cd6e0de54 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 3 Dec 2024 15:05:22 +0200 Subject: [PATCH 412/492] Bump versions --- changelogs/drizzle-kit/0.29.0.md | 40 +++++++++++++ changelogs/drizzle-orm/0.37.0.md | 98 ++++++++++++++++++++++++++++++++ drizzle-kit/package.json | 4 +- drizzle-orm/package.json | 4 +- 4 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 changelogs/drizzle-kit/0.29.0.md create mode 100644 changelogs/drizzle-orm/0.37.0.md diff --git a/changelogs/drizzle-kit/0.29.0.md b/changelogs/drizzle-kit/0.29.0.md new file mode 100644 index 000000000..b68b33085 --- /dev/null +++ b/changelogs/drizzle-kit/0.29.0.md @@ -0,0 +1,40 @@ +# New Dialects + +### 🎉 `SingleStore` dialect is now available in Drizzle + +Thanks to the SingleStore team for creating a PR with all the necessary changes to support the MySQL-compatible part of SingleStore. You can already start using it with Drizzle. The SingleStore team will also help us iterate through updates and make more SingleStore-specific features available in Drizzle + +```ts +import 'dotenv/config'; +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + dialect: 'singlestore', + out: './drizzle', + schema: './src/db/schema.ts', + dbCredentials: { + url: process.env.DATABASE_URL!, + }, +}); +``` + +You can check out our [Getting started guides](https://orm.drizzle.team/docs/get-started/singlestore-new) to try SingleStore! + +# New Drivers + +### 🎉 `SQLite Durable Objects` driver is now available in Drizzle + +You can now query SQLite Durable Objects in Drizzle! + +For the full example, please check our [Get Started](https://orm.drizzle.team/docs/get-started/do-new) Section + +```ts +import 'dotenv/config'; +import { defineConfig } from 'drizzle-kit'; +export default defineConfig({ + out: './drizzle', + schema: './src/db/schema.ts', + dialect: 'sqlite', + driver: 'durable-sqlite', +}); +``` \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.37.0.md b/changelogs/drizzle-orm/0.37.0.md new file mode 100644 index 000000000..f54fa4a27 --- /dev/null +++ b/changelogs/drizzle-orm/0.37.0.md @@ -0,0 +1,98 @@ +# New Dialects + +### 🎉 `SingleStore` dialect is now available in Drizzle + +Thanks to the SingleStore team for creating a PR with all the necessary changes to support the MySQL-compatible part of SingleStore. You can already start using it with Drizzle. The SingleStore team will also help us iterate through updates and make more SingleStore-specific features available in Drizzle + +```ts +import { int, singlestoreTable, varchar } from 'drizzle-orm/singlestore-core'; +import { drizzle } from 'drizzle-orm/singlestore'; + +export const usersTable = singlestoreTable('users_table', { + id: int().primaryKey(), + name: varchar({ length: 255 }).notNull(), + age: int().notNull(), + email: varchar({ length: 255 }).notNull().unique(), +}); + +... + +const db = drizzle(process.env.DATABASE_URL!); + +db.select()... +``` + +You can check out our [Getting started guides](https://orm.drizzle.team/docs/get-started/singlestore-new) to try SingleStore! + +# New Drivers + +### 🎉 `SQLite Durable Objects` driver is now available in Drizzle + +You can now query SQLite Durable Objects in Drizzle! + +For the full example, please check our [Get Started](https://orm.drizzle.team/docs/get-started/do-new) Section + +```ts +/// +import { drizzle, DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite'; +import { DurableObject } from 'cloudflare:workers' +import { migrate } from 'drizzle-orm/durable-sqlite/migrator'; +import migrations from '../drizzle/migrations'; +import { usersTable } from './db/schema'; + +export class MyDurableObject1 extends DurableObject { + storage: DurableObjectStorage; + db: DrizzleSqliteDODatabase; + + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + this.storage = ctx.storage; + this.db = drizzle(this.storage, { logger: false }); + } + + async migrate() { + migrate(this.db, migrations); + } + + async insert(user: typeof usersTable.$inferInsert) { + await this.db.insert(usersTable).values(user); + } + + async select() { + return this.db.select().from(usersTable); + } +} + +export default { + /** + * This is the standard fetch handler for a Cloudflare Worker + * + * @param request - The request submitted to the Worker from the client + * @param env - The interface to reference bindings declared in wrangler.toml + * @param ctx - The execution context of the Worker + * @returns The response to be sent back to the client + */ + async fetch(request: Request, env: Env): Promise { + const id: DurableObjectId = env.MY_DURABLE_OBJECT1.idFromName('durable-object'); + const stub = env.MY_DURABLE_OBJECT1.get(id); + await stub.migrate(); + + await stub.insert({ + name: 'John', + age: 30, + email: 'john@example.com', + }) + console.log('New user created!') + + const users = await stub.select(); + console.log('Getting all users from the database: ', users) + + return new Response(); + } +} +``` + +# Bug fixes + +- [[BUG]: $with is undefined on withReplicas](https://github.com/drizzle-team/drizzle-orm/issues/1834) +- [[BUG]: Neon serverless driver accepts authToken as a promise, but the $withAuth does not](https://github.com/drizzle-team/drizzle-orm/issues/3597) \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index fbf1fd162..4bf229459 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.28.1", + "version": "0.29.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", @@ -142,4 +142,4 @@ "default": "./api.mjs" } } -} +} \ No newline at end of file diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index cf1f086b8..71d2fde72 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.36.4", + "version": "0.37.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -204,4 +204,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} +} \ No newline at end of file From a7415b880e463511355d636308591e656bfe2080 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 3 Dec 2024 15:05:35 +0200 Subject: [PATCH 413/492] dprint --- drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 4bf229459..eca469d9b 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -142,4 +142,4 @@ "default": "./api.mjs" } } -} \ No newline at end of file +} diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 71d2fde72..3fa8e4bc3 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -204,4 +204,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} \ No newline at end of file +} From 9cf0ed21e0f549a84cdc642cbb10a1900948e570 Mon Sep 17 00:00:00 2001 From: Andrii Sherman Date: Tue, 3 Dec 2024 15:07:15 +0200 Subject: [PATCH 414/492] Beta (#3664) * Add SingleStore dialect * Add Durable Objects SQLite support * Bug fixes --------- Co-authored-by: Malone Hedges Co-authored-by: Pedro Rodrigues <44656907+Rodriguespn@users.noreply.github.com> Co-authored-by: prodrigues Co-authored-by: apeng-singlestore <127370261+apeng-singlestore@users.noreply.github.com> Co-authored-by: Alex Blokh Co-authored-by: Aleksandr Sherman Co-authored-by: Sergey Reka <71607800+Sukairo-02@users.noreply.github.com> --- changelogs/drizzle-kit/0.29.0.md | 40 + changelogs/drizzle-orm/0.36.1.md | 2 +- changelogs/drizzle-orm/0.37.0.md | 98 + drizzle-kit/package.json | 3 +- drizzle-kit/src/api.ts | 114 + drizzle-kit/src/cli/commands/introspect.ts | 102 + drizzle-kit/src/cli/commands/migrate.ts | 193 +- drizzle-kit/src/cli/commands/push.ts | 160 +- .../src/cli/commands/singlestoreIntrospect.ts | 53 + .../src/cli/commands/singlestorePushUtils.ts | 352 + drizzle-kit/src/cli/commands/singlestoreUp.ts | 1 + drizzle-kit/src/cli/commands/utils.ts | 90 +- drizzle-kit/src/cli/connections.ts | 80 + drizzle-kit/src/cli/schema.ts | 76 +- drizzle-kit/src/cli/validations/common.ts | 3 +- drizzle-kit/src/cli/validations/outputs.ts | 11 +- .../src/cli/validations/singlestore.ts | 61 + drizzle-kit/src/cli/validations/sqlite.ts | 27 +- drizzle-kit/src/cli/views.ts | 8 +- drizzle-kit/src/index.ts | 27 +- drizzle-kit/src/introspect-singlestore.ts | 918 +++ drizzle-kit/src/jsonStatements.ts | 436 +- drizzle-kit/src/migrationPreparator.ts | 47 +- drizzle-kit/src/schemaValidator.ts | 6 +- drizzle-kit/src/serializer/index.ts | 17 + .../src/serializer/singlestoreImports.ts | 38 + .../src/serializer/singlestoreSchema.ts | 257 + .../src/serializer/singlestoreSerializer.ts | 767 ++ drizzle-kit/src/serializer/studio.ts | 84 +- drizzle-kit/src/snapshotsDiffer.ts | 526 ++ drizzle-kit/src/sqlgenerator.ts | 762 +- drizzle-kit/src/utils.ts | 3 + drizzle-kit/tests/cli-generate.test.ts | 27 + .../tests/cli/durable-sqlite.config.ts | 7 + .../tests/introspect/singlestore.test.ts | 275 + .../tests/push/singlestore-push.test.ts | 266 + drizzle-kit/tests/push/singlestore.test.ts | 439 ++ drizzle-kit/tests/schemaDiffer.ts | 1632 +++-- .../tests/singlestore-generated.test.ts | 1290 ++++ drizzle-kit/tests/singlestore-schemas.test.ts | 155 + drizzle-kit/tests/singlestore.test.ts | 580 ++ drizzle-kit/tests/testsinglestore.ts | 29 + drizzle-kit/tests/validations.test.ts | 169 + drizzle-kit/tests/wrap-param.test.ts | 3 + drizzle-kit/vitest.config.ts | 9 + drizzle-orm/package.json | 7 +- drizzle-orm/src/column-builder.ts | 5 +- drizzle-orm/src/durable-sqlite/driver.ts | 60 + drizzle-orm/src/durable-sqlite/index.ts | 2 + drizzle-orm/src/durable-sqlite/migrator.ts | 85 + drizzle-orm/src/durable-sqlite/session.ts | 181 + drizzle-orm/src/neon-http/driver.ts | 8 +- drizzle-orm/src/neon-http/session.ts | 14 +- drizzle-orm/src/pg-core/db.ts | 10 +- .../src/pg-core/query-builders/count.ts | 6 +- .../src/pg-core/query-builders/delete.ts | 6 +- .../src/pg-core/query-builders/insert.ts | 38 +- .../src/pg-core/query-builders/query.ts | 6 +- .../refresh-materialized-view.ts | 5 +- .../src/pg-core/query-builders/select.ts | 47 +- .../src/pg-core/query-builders/update.ts | 39 +- drizzle-orm/src/pg-core/session.ts | 17 +- drizzle-orm/src/singlestore-core/alias.ts | 10 + .../src/singlestore-core/columns/all.ts | 55 + .../src/singlestore-core/columns/bigint.ts | 120 + .../src/singlestore-core/columns/binary.ts | 70 + .../src/singlestore-core/columns/boolean.ts | 58 + .../src/singlestore-core/columns/char.ts | 75 + .../src/singlestore-core/columns/common.ts | 117 + .../src/singlestore-core/columns/custom.ts | 235 + .../singlestore-core/columns/date.common.ts | 41 + .../src/singlestore-core/columns/date.ts | 123 + .../src/singlestore-core/columns/datetime.ts | 153 + .../src/singlestore-core/columns/decimal.ts | 90 + .../src/singlestore-core/columns/double.ts | 80 + .../src/singlestore-core/columns/enum.ts | 84 + .../src/singlestore-core/columns/float.ts | 80 + .../src/singlestore-core/columns/index.ts | 25 + .../src/singlestore-core/columns/int.ts | 71 + .../src/singlestore-core/columns/json.ts | 53 + .../src/singlestore-core/columns/mediumint.ts | 68 + .../src/singlestore-core/columns/real.ts | 81 + .../src/singlestore-core/columns/serial.ts | 76 + .../src/singlestore-core/columns/smallint.ts | 68 + .../src/singlestore-core/columns/text.ts | 116 + .../src/singlestore-core/columns/time.ts | 55 + .../src/singlestore-core/columns/timestamp.ts | 125 + .../src/singlestore-core/columns/tinyint.ts | 68 + .../src/singlestore-core/columns/varbinary.ts | 66 + .../src/singlestore-core/columns/varchar.ts | 75 + .../src/singlestore-core/columns/year.ts | 51 + drizzle-orm/src/singlestore-core/db.ts | 516 ++ drizzle-orm/src/singlestore-core/dialect.ts | 813 +++ .../src/singlestore-core/expressions.ts | 25 + drizzle-orm/src/singlestore-core/index.ts | 15 + drizzle-orm/src/singlestore-core/indexes.ts | 193 + .../src/singlestore-core/primary-keys.ts | 63 + .../singlestore-core/query-builders/count.ts | 79 + .../singlestore-core/query-builders/delete.ts | 207 + .../singlestore-core/query-builders/index.ts | 11 + .../singlestore-core/query-builders/insert.ts | 305 + .../query-builders/query-builder.ts | 114 + .../singlestore-core/query-builders/query.ts | 141 + .../singlestore-core/query-builders/select.ts | 1082 +++ .../query-builders/select.types.ts | 457 ++ .../singlestore-core/query-builders/update.ts | 251 + drizzle-orm/src/singlestore-core/schema.ts | 40 + drizzle-orm/src/singlestore-core/session.ts | 157 + drizzle-orm/src/singlestore-core/subquery.ts | 17 + drizzle-orm/src/singlestore-core/table.ts | 138 + .../src/singlestore-core/unique-constraint.ts | 65 + drizzle-orm/src/singlestore-core/utils.ts | 55 + drizzle-orm/src/singlestore-core/view-base.ts | 15 + .../src/singlestore-core/view-common.ts | 1 + drizzle-orm/src/singlestore-core/view.ts | 209 + drizzle-orm/src/singlestore-proxy/driver.ts | 59 + drizzle-orm/src/singlestore-proxy/index.ts | 2 + drizzle-orm/src/singlestore-proxy/migrator.ts | 52 + drizzle-orm/src/singlestore-proxy/session.ts | 178 + drizzle-orm/src/singlestore/driver.ts | 168 + drizzle-orm/src/singlestore/index.ts | 2 + drizzle-orm/src/singlestore/migrator.ts | 11 + drizzle-orm/src/singlestore/session.ts | 340 + drizzle-orm/src/sqlite-core/columns/blob.ts | 30 +- drizzle-orm/src/utils.ts | 2 + .../type-tests/singlestore/1000columns.ts | 904 +++ drizzle-orm/type-tests/singlestore/count.ts | 61 + drizzle-orm/type-tests/singlestore/db.ts | 13 + drizzle-orm/type-tests/singlestore/delete.ts | 65 + drizzle-orm/type-tests/singlestore/insert.ts | 135 + drizzle-orm/type-tests/singlestore/select.ts | 607 ++ .../type-tests/singlestore/set-operators.ts | 235 + .../type-tests/singlestore/subquery.ts | 97 + drizzle-orm/type-tests/singlestore/tables.ts | 1009 +++ drizzle-orm/type-tests/singlestore/update.ts | 30 + drizzle-orm/type-tests/singlestore/with.ts | 80 + drizzle-orm/type-tests/sqlite/db.ts | 3 + .../type-tests/utils/neon-auth-token.ts | 5 + integration-tests/.env.example | 1 + .../singlestore/0000_nostalgic_carnage.sql | 20 + .../singlestore/meta/0000_snapshot.json | 132 + .../drizzle2/singlestore/meta/_journal.json | 13 + integration-tests/tests/pg/neon-http.test.ts | 202 + .../tests/relational/singlestore.schema.ts | 106 + .../tests/relational/singlestore.test.ts | 6403 +++++++++++++++++ .../tests/replicas/singlestore.test.ts | 814 +++ .../tests/singlestore/singlestore-common.ts | 3429 +++++++++ .../singlestore/singlestore-custom.test.ts | 827 +++ .../singlestore/singlestore-prefixed.test.ts | 1574 ++++ .../singlestore/singlestore-proxy.test.ts | 140 + .../tests/singlestore/singlestore.test.ts | 51 + .../drizzle/0000_cuddly_black_bolt.sql | 11 + .../drizzle/meta/0000_snapshot.json | 80 + .../drizzle/meta/_journal.json | 13 + .../durable-objects/drizzle/migrations.js | 9 + .../tests/sqlite/durable-objects/index.ts | 3619 ++++++++++ .../durable-objects/worker-configuration.d.ts | 5 + .../sqlite/durable-objects/wrangler.toml | 25 + integration-tests/vitest.config.ts | 3 + package.json | 3 +- pnpm-lock.yaml | 20 +- 161 files changed, 38945 insertions(+), 780 deletions(-) create mode 100644 changelogs/drizzle-kit/0.29.0.md create mode 100644 changelogs/drizzle-orm/0.37.0.md create mode 100644 drizzle-kit/src/cli/commands/singlestoreIntrospect.ts create mode 100644 drizzle-kit/src/cli/commands/singlestorePushUtils.ts create mode 100644 drizzle-kit/src/cli/commands/singlestoreUp.ts create mode 100644 drizzle-kit/src/cli/validations/singlestore.ts create mode 100644 drizzle-kit/src/introspect-singlestore.ts create mode 100644 drizzle-kit/src/serializer/singlestoreImports.ts create mode 100644 drizzle-kit/src/serializer/singlestoreSchema.ts create mode 100644 drizzle-kit/src/serializer/singlestoreSerializer.ts create mode 100644 drizzle-kit/tests/cli/durable-sqlite.config.ts create mode 100644 drizzle-kit/tests/introspect/singlestore.test.ts create mode 100644 drizzle-kit/tests/push/singlestore-push.test.ts create mode 100644 drizzle-kit/tests/push/singlestore.test.ts create mode 100644 drizzle-kit/tests/singlestore-generated.test.ts create mode 100644 drizzle-kit/tests/singlestore-schemas.test.ts create mode 100644 drizzle-kit/tests/singlestore.test.ts create mode 100644 drizzle-kit/tests/testsinglestore.ts create mode 100644 drizzle-orm/src/durable-sqlite/driver.ts create mode 100644 drizzle-orm/src/durable-sqlite/index.ts create mode 100644 drizzle-orm/src/durable-sqlite/migrator.ts create mode 100644 drizzle-orm/src/durable-sqlite/session.ts create mode 100644 drizzle-orm/src/singlestore-core/alias.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/all.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/bigint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/binary.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/boolean.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/char.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/common.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/custom.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/date.common.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/date.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/datetime.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/decimal.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/double.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/enum.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/float.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/index.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/int.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/json.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/mediumint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/real.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/serial.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/smallint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/text.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/time.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/timestamp.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/tinyint.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/varbinary.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/varchar.ts create mode 100644 drizzle-orm/src/singlestore-core/columns/year.ts create mode 100644 drizzle-orm/src/singlestore-core/db.ts create mode 100644 drizzle-orm/src/singlestore-core/dialect.ts create mode 100644 drizzle-orm/src/singlestore-core/expressions.ts create mode 100644 drizzle-orm/src/singlestore-core/index.ts create mode 100644 drizzle-orm/src/singlestore-core/indexes.ts create mode 100644 drizzle-orm/src/singlestore-core/primary-keys.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/count.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/delete.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/index.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/insert.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/query-builder.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/query.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/select.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/select.types.ts create mode 100644 drizzle-orm/src/singlestore-core/query-builders/update.ts create mode 100644 drizzle-orm/src/singlestore-core/schema.ts create mode 100644 drizzle-orm/src/singlestore-core/session.ts create mode 100644 drizzle-orm/src/singlestore-core/subquery.ts create mode 100644 drizzle-orm/src/singlestore-core/table.ts create mode 100644 drizzle-orm/src/singlestore-core/unique-constraint.ts create mode 100644 drizzle-orm/src/singlestore-core/utils.ts create mode 100644 drizzle-orm/src/singlestore-core/view-base.ts create mode 100644 drizzle-orm/src/singlestore-core/view-common.ts create mode 100644 drizzle-orm/src/singlestore-core/view.ts create mode 100644 drizzle-orm/src/singlestore-proxy/driver.ts create mode 100644 drizzle-orm/src/singlestore-proxy/index.ts create mode 100644 drizzle-orm/src/singlestore-proxy/migrator.ts create mode 100644 drizzle-orm/src/singlestore-proxy/session.ts create mode 100644 drizzle-orm/src/singlestore/driver.ts create mode 100644 drizzle-orm/src/singlestore/index.ts create mode 100644 drizzle-orm/src/singlestore/migrator.ts create mode 100644 drizzle-orm/src/singlestore/session.ts create mode 100644 drizzle-orm/type-tests/singlestore/1000columns.ts create mode 100644 drizzle-orm/type-tests/singlestore/count.ts create mode 100644 drizzle-orm/type-tests/singlestore/db.ts create mode 100644 drizzle-orm/type-tests/singlestore/delete.ts create mode 100644 drizzle-orm/type-tests/singlestore/insert.ts create mode 100644 drizzle-orm/type-tests/singlestore/select.ts create mode 100644 drizzle-orm/type-tests/singlestore/set-operators.ts create mode 100644 drizzle-orm/type-tests/singlestore/subquery.ts create mode 100644 drizzle-orm/type-tests/singlestore/tables.ts create mode 100644 drizzle-orm/type-tests/singlestore/update.ts create mode 100644 drizzle-orm/type-tests/singlestore/with.ts create mode 100644 drizzle-orm/type-tests/utils/neon-auth-token.ts create mode 100644 integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql create mode 100644 integration-tests/drizzle2/singlestore/meta/0000_snapshot.json create mode 100644 integration-tests/drizzle2/singlestore/meta/_journal.json create mode 100644 integration-tests/tests/relational/singlestore.schema.ts create mode 100644 integration-tests/tests/relational/singlestore.test.ts create mode 100644 integration-tests/tests/replicas/singlestore.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore-common.ts create mode 100644 integration-tests/tests/singlestore/singlestore-custom.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore-prefixed.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore-proxy.test.ts create mode 100644 integration-tests/tests/singlestore/singlestore.test.ts create mode 100644 integration-tests/tests/sqlite/durable-objects/drizzle/0000_cuddly_black_bolt.sql create mode 100644 integration-tests/tests/sqlite/durable-objects/drizzle/meta/0000_snapshot.json create mode 100644 integration-tests/tests/sqlite/durable-objects/drizzle/meta/_journal.json create mode 100644 integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js create mode 100644 integration-tests/tests/sqlite/durable-objects/index.ts create mode 100644 integration-tests/tests/sqlite/durable-objects/worker-configuration.d.ts create mode 100644 integration-tests/tests/sqlite/durable-objects/wrangler.toml diff --git a/changelogs/drizzle-kit/0.29.0.md b/changelogs/drizzle-kit/0.29.0.md new file mode 100644 index 000000000..b68b33085 --- /dev/null +++ b/changelogs/drizzle-kit/0.29.0.md @@ -0,0 +1,40 @@ +# New Dialects + +### 🎉 `SingleStore` dialect is now available in Drizzle + +Thanks to the SingleStore team for creating a PR with all the necessary changes to support the MySQL-compatible part of SingleStore. You can already start using it with Drizzle. The SingleStore team will also help us iterate through updates and make more SingleStore-specific features available in Drizzle + +```ts +import 'dotenv/config'; +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + dialect: 'singlestore', + out: './drizzle', + schema: './src/db/schema.ts', + dbCredentials: { + url: process.env.DATABASE_URL!, + }, +}); +``` + +You can check out our [Getting started guides](https://orm.drizzle.team/docs/get-started/singlestore-new) to try SingleStore! + +# New Drivers + +### 🎉 `SQLite Durable Objects` driver is now available in Drizzle + +You can now query SQLite Durable Objects in Drizzle! + +For the full example, please check our [Get Started](https://orm.drizzle.team/docs/get-started/do-new) Section + +```ts +import 'dotenv/config'; +import { defineConfig } from 'drizzle-kit'; +export default defineConfig({ + out: './drizzle', + schema: './src/db/schema.ts', + dialect: 'sqlite', + driver: 'durable-sqlite', +}); +``` \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.36.1.md b/changelogs/drizzle-orm/0.36.1.md index 1c0e96756..74d256a13 100644 --- a/changelogs/drizzle-orm/0.36.1.md +++ b/changelogs/drizzle-orm/0.36.1.md @@ -3,4 +3,4 @@ - [[BUG]: Using sql.placeholder with limit and/or offset for a prepared statement produces TS error](https://github.com/drizzle-team/drizzle-orm/issues/2146) - thanks @L-Mario564 - [[BUG] If a query I am trying to modify with a dynamic query (....$dynamic()) contains any placeholders, I'm getting an error that says No value for placeholder.... provided](https://github.com/drizzle-team/drizzle-orm/issues/2272) - thanks @L-Mario564 - [[BUG]: Error thrown when trying to insert an array of new rows using generatedAlwaysAsIdentity() for the id column](https://github.com/drizzle-team/drizzle-orm/issues/2849) - thanks @L-Mario564 -- [[BUG]: Unable to Use BigInt Types with Bun and Drizzle](https://github.com/drizzle-team/drizzle-orm/issues/2603) - thanks @L-Mario564 \ No newline at end of file +- [[BUG]: Unable to Use BigInt Types with Bun and Drizzle](https://github.com/drizzle-team/drizzle-orm/issues/2603) - thanks @L-Mario564 diff --git a/changelogs/drizzle-orm/0.37.0.md b/changelogs/drizzle-orm/0.37.0.md new file mode 100644 index 000000000..f54fa4a27 --- /dev/null +++ b/changelogs/drizzle-orm/0.37.0.md @@ -0,0 +1,98 @@ +# New Dialects + +### 🎉 `SingleStore` dialect is now available in Drizzle + +Thanks to the SingleStore team for creating a PR with all the necessary changes to support the MySQL-compatible part of SingleStore. You can already start using it with Drizzle. The SingleStore team will also help us iterate through updates and make more SingleStore-specific features available in Drizzle + +```ts +import { int, singlestoreTable, varchar } from 'drizzle-orm/singlestore-core'; +import { drizzle } from 'drizzle-orm/singlestore'; + +export const usersTable = singlestoreTable('users_table', { + id: int().primaryKey(), + name: varchar({ length: 255 }).notNull(), + age: int().notNull(), + email: varchar({ length: 255 }).notNull().unique(), +}); + +... + +const db = drizzle(process.env.DATABASE_URL!); + +db.select()... +``` + +You can check out our [Getting started guides](https://orm.drizzle.team/docs/get-started/singlestore-new) to try SingleStore! + +# New Drivers + +### 🎉 `SQLite Durable Objects` driver is now available in Drizzle + +You can now query SQLite Durable Objects in Drizzle! + +For the full example, please check our [Get Started](https://orm.drizzle.team/docs/get-started/do-new) Section + +```ts +/// +import { drizzle, DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite'; +import { DurableObject } from 'cloudflare:workers' +import { migrate } from 'drizzle-orm/durable-sqlite/migrator'; +import migrations from '../drizzle/migrations'; +import { usersTable } from './db/schema'; + +export class MyDurableObject1 extends DurableObject { + storage: DurableObjectStorage; + db: DrizzleSqliteDODatabase; + + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + this.storage = ctx.storage; + this.db = drizzle(this.storage, { logger: false }); + } + + async migrate() { + migrate(this.db, migrations); + } + + async insert(user: typeof usersTable.$inferInsert) { + await this.db.insert(usersTable).values(user); + } + + async select() { + return this.db.select().from(usersTable); + } +} + +export default { + /** + * This is the standard fetch handler for a Cloudflare Worker + * + * @param request - The request submitted to the Worker from the client + * @param env - The interface to reference bindings declared in wrangler.toml + * @param ctx - The execution context of the Worker + * @returns The response to be sent back to the client + */ + async fetch(request: Request, env: Env): Promise { + const id: DurableObjectId = env.MY_DURABLE_OBJECT1.idFromName('durable-object'); + const stub = env.MY_DURABLE_OBJECT1.get(id); + await stub.migrate(); + + await stub.insert({ + name: 'John', + age: 30, + email: 'john@example.com', + }) + console.log('New user created!') + + const users = await stub.select(); + console.log('Getting all users from the database: ', users) + + return new Response(); + } +} +``` + +# Bug fixes + +- [[BUG]: $with is undefined on withReplicas](https://github.com/drizzle-team/drizzle-orm/issues/1834) +- [[BUG]: Neon serverless driver accepts authToken as a promise, but the $withAuth does not](https://github.com/drizzle-team/drizzle-orm/issues/3597) \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 0b3b2562b..eca469d9b 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,12 +1,13 @@ { "name": "drizzle-kit", - "version": "0.28.1", + "version": "0.29.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", "orm", "pg", "mysql", + "singlestore", "postgresql", "postgres", "sqlite", diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index b18ed95f4..18107bd34 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'; import { LibSQLDatabase } from 'drizzle-orm/libsql'; import type { MySql2Database } from 'drizzle-orm/mysql2'; import { PgDatabase } from 'drizzle-orm/pg-core'; +import { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; import { columnsResolver, enumsResolver, @@ -30,12 +31,19 @@ import { generateMySqlSnapshot } from './serializer/mysqlSerializer'; import { prepareFromExports } from './serializer/pgImports'; import { PgSchema as PgSchemaKit, pgSchema, squashPgScheme } from './serializer/pgSchema'; import { generatePgSnapshot } from './serializer/pgSerializer'; +import { + SingleStoreSchema as SingleStoreSchemaKit, + singlestoreSchema, + squashSingleStoreScheme, +} from './serializer/singlestoreSchema'; +import { generateSingleStoreSnapshot } from './serializer/singlestoreSerializer'; import { SQLiteSchema as SQLiteSchemaKit, sqliteSchema, squashSqliteScheme } from './serializer/sqliteSchema'; import { generateSqliteSnapshot } from './serializer/sqliteSerializer'; import type { DB, SQLiteDB } from './utils'; export type DrizzleSnapshotJSON = PgSchemaKit; export type DrizzleSQLiteSnapshotJSON = SQLiteSchemaKit; export type DrizzleMySQLSnapshotJSON = MySQLSchemaKit; +export type DrizzleSingleStoreSnapshotJSON = SingleStoreSchemaKit; export const generateDrizzleJson = ( imports: Record, @@ -374,6 +382,112 @@ export const pushMySQLSchema = async ( }; }; +// SingleStore + +export const generateSingleStoreDrizzleJson = async ( + imports: Record, + prevId?: string, + casing?: CasingType, +): Promise => { + const { prepareFromExports } = await import('./serializer/singlestoreImports'); + + const prepared = prepareFromExports(imports); + + const id = randomUUID(); + + const snapshot = generateSingleStoreSnapshot(prepared.tables, /* prepared.views, */ casing); + + return { + ...snapshot, + id, + prevId: prevId ?? originUUID, + }; +}; + +export const generateSingleStoreMigration = async ( + prev: DrizzleSingleStoreSnapshotJSON, + cur: DrizzleSingleStoreSnapshotJSON, +) => { + const { applySingleStoreSnapshotsDiff } = await import('./snapshotsDiffer'); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + /* singleStoreViewsResolver, */ + validatedPrev, + validatedCur, + 'push', + ); + + return sqlStatements; +}; + +export const pushSingleStoreSchema = async ( + imports: Record, + drizzleInstance: SingleStoreDriverDatabase, + databaseName: string, +) => { + const { applySingleStoreSnapshotsDiff } = await import('./snapshotsDiffer'); + const { logSuggestionsAndReturn } = await import( + './cli/commands/singlestorePushUtils' + ); + const { singlestorePushIntrospect } = await import( + './cli/commands/singlestoreIntrospect' + ); + const { sql } = await import('drizzle-orm'); + + const db: DB = { + query: async (query: string) => { + const res = await drizzleInstance.execute(sql.raw(query)); + return res[0] as unknown as any[]; + }, + }; + const cur = await generateSingleStoreDrizzleJson(imports); + const { schema: prev } = await singlestorePushIntrospect(db, databaseName, []); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { statements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + /* singleStoreViewsResolver, */ + validatedPrev, + validatedCur, + 'push', + ); + + const { shouldAskForApprove, statementsToExecute, infoToPrint } = await logSuggestionsAndReturn( + db, + statements, + validatedCur, + ); + + return { + hasDataLoss: shouldAskForApprove, + warnings: infoToPrint, + statementsToExecute, + apply: async () => { + for (const dStmnt of statementsToExecute) { + await db.query(dStmnt); + } + }, + }; +}; + export const upPgSnapshot = (snapshot: Record) => { if (snapshot.version === '5') { return upPgV7(upPgV6(snapshot)); diff --git a/drizzle-kit/src/cli/commands/introspect.ts b/drizzle-kit/src/cli/commands/introspect.ts index 2629d000e..101eb617a 100644 --- a/drizzle-kit/src/cli/commands/introspect.ts +++ b/drizzle-kit/src/cli/commands/introspect.ts @@ -4,20 +4,24 @@ import { render, renderWithTask } from 'hanji'; import { Minimatch } from 'minimatch'; import { join } from 'path'; import { plural, singular } from 'pluralize'; +import { drySingleStore, SingleStoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; import { assertUnreachable, originUUID } from '../../global'; import { schemaToTypeScript as mysqlSchemaToTypeScript } from '../../introspect-mysql'; import { paramNameFor, schemaToTypeScript as postgresSchemaToTypeScript } from '../../introspect-pg'; +import { schemaToTypeScript as singlestoreSchemaToTypeScript } from '../../introspect-singlestore'; import { schemaToTypeScript as sqliteSchemaToTypeScript } from '../../introspect-sqlite'; import { dryMySql, MySqlSchema, squashMysqlScheme } from '../../serializer/mysqlSchema'; import { fromDatabase as fromMysqlDatabase } from '../../serializer/mysqlSerializer'; import { dryPg, type PgSchema, squashPgScheme } from '../../serializer/pgSchema'; import { fromDatabase as fromPostgresDatabase } from '../../serializer/pgSerializer'; +import { fromDatabase as fromSingleStoreDatabase } from '../../serializer/singlestoreSerializer'; import { drySQLite, type SQLiteSchema, squashSqliteScheme } from '../../serializer/sqliteSchema'; import { fromDatabase as fromSqliteDatabase } from '../../serializer/sqliteSerializer'; import { applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, } from '../../snapshotsDiffer'; import { prepareOutFolder } from '../../utils'; @@ -26,6 +30,7 @@ import type { Casing, Prefix } from '../validations/common'; import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; import type { PostgresCredentials } from '../validations/postgres'; +import { SingleStoreCredentials } from '../validations/singlestore'; import type { SqliteCredentials } from '../validations/sqlite'; import { IntrospectProgress } from '../views'; import { @@ -280,6 +285,103 @@ export const introspectMysql = async ( process.exit(0); }; +export const introspectSingleStore = async ( + casing: Casing, + out: string, + breakpoints: boolean, + credentials: SingleStoreCredentials, + tablesFilter: string[], + prefix: Prefix, +) => { + const { connectToSingleStore } = await import('../connections'); + const { db, database } = await connectToSingleStore(credentials); + + const matchers = tablesFilter.map((it) => { + return new Minimatch(it); + }); + + const filter = (tableName: string) => { + if (matchers.length === 0) return true; + + let flags: boolean[] = []; + + for (let matcher of matchers) { + if (matcher.negate) { + if (!matcher.match(tableName)) { + flags.push(false); + } + } + + if (matcher.match(tableName)) { + flags.push(true); + } + } + + if (flags.length > 0) { + return flags.every(Boolean); + } + return false; + }; + + const progress = new IntrospectProgress(); + const res = await renderWithTask( + progress, + fromSingleStoreDatabase(db, database, filter, (stage, count, status) => { + progress.update(stage, count, status); + }), + ); + + const schema = { id: originUUID, prevId: '', ...res } as SingleStoreSchema; + const ts = singlestoreSchemaToTypeScript(schema, casing); + const { internal, ...schemaWithoutInternals } = schema; + + const schemaFile = join(out, 'schema.ts'); + writeFileSync(schemaFile, ts.file); + console.log(); + + const { snapshots, journal } = prepareOutFolder(out, 'postgresql'); + + if (snapshots.length === 0) { + const { sqlStatements, _meta } = await applySingleStoreSnapshotsDiff( + squashSingleStoreScheme(drySingleStore), + squashSingleStoreScheme(schema), + tablesResolver, + columnsResolver, + /* singleStoreViewsResolver, */ + drySingleStore, + schema, + ); + + writeResult({ + cur: schema, + sqlStatements, + journal, + _meta, + outFolder: out, + breakpoints, + type: 'introspect', + prefixMode: prefix, + }); + } else { + render( + `[${ + chalk.blue( + 'i', + ) + }] No SQL generated, you already have migrations in project`, + ); + } + + render( + `[${ + chalk.green( + '✓', + ) + }] You schema file is ready ➜ ${chalk.bold.underline.blue(schemaFile)} 🚀`, + ); + process.exit(0); +}; + export const introspectSqlite = async ( casing: Casing, out: string, diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 92770e99d..96067c165 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -4,6 +4,8 @@ import { prepareMySqlMigrationSnapshot, preparePgDbPushSnapshot, preparePgMigrationSnapshot, + prepareSingleStoreDbPushSnapshot, + prepareSingleStoreMigrationSnapshot, prepareSQLiteDbPushSnapshot, prepareSqliteMigrationSnapshot, } from '../../migrationPreparator'; @@ -11,6 +13,7 @@ import { import chalk from 'chalk'; import { render } from 'hanji'; import path, { join } from 'path'; +import { SingleStoreSchema, singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; import { TypeOf } from 'zod'; import type { CommonSchema } from '../../schemaValidator'; import { MySqlSchema, mysqlSchema, squashMysqlScheme, ViewSquashed } from '../../serializer/mysqlSchema'; @@ -20,6 +23,7 @@ import { applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, Column, ColumnsResolverInput, @@ -39,7 +43,7 @@ import { } from '../../snapshotsDiffer'; import { assertV1OutFolder, Journal, prepareMigrationFolder } from '../../utils'; import { prepareMigrationMetadata } from '../../utils/words'; -import { CasingType, Prefix } from '../validations/common'; +import { CasingType, Driver, Prefix } from '../validations/common'; import { withStyle } from '../validations/outputs'; import { isRenamePromptItem, @@ -143,6 +147,28 @@ export const mySqlViewsResolver = async ( } }; +/* export const singleStoreViewsResolver = async ( + input: ResolverInput, +): Promise> => { + try { + const { created, deleted, moved, renamed } = await promptNamedWithSchemasConflict( + input.created, + input.deleted, + 'view', + ); + + return { + created: created, + deleted: deleted, + moved: moved, + renamed: renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; */ + export const sqliteViewsResolver = async ( input: ResolverInput, ): Promise> => { @@ -521,6 +547,156 @@ export const prepareAndMigrateMysql = async (config: GenerateConfig) => { } }; +// Not needed for now +function singleStoreSchemaSuggestions( + curSchema: TypeOf, + prevSchema: TypeOf, +) { + const suggestions: string[] = []; + const usedSuggestions: string[] = []; + const suggestionTypes = { + // TODO: Check if SingleStore has serial type + serial: withStyle.errorWarning( + `We deprecated the use of 'serial' for SingleStore starting from version 0.20.0. In SingleStore, 'serial' is simply an alias for 'bigint unsigned not null auto_increment unique,' which creates all constraints and indexes for you. This may make the process less explicit for both users and drizzle-kit push commands`, + ), + }; + + for (const table of Object.values(curSchema.tables)) { + for (const column of Object.values(table.columns)) { + if (column.type === 'serial') { + if (!usedSuggestions.includes('serial')) { + suggestions.push(suggestionTypes['serial']); + } + + const uniqueForSerial = Object.values( + prevSchema.tables[table.name].uniqueConstraints, + ).find((it) => it.columns[0] === column.name); + + suggestions.push( + `\n` + + withStyle.suggestion( + `We are suggesting to change ${ + chalk.blue( + column.name, + ) + } column in ${ + chalk.blueBright( + table.name, + ) + } table from serial to bigint unsigned\n\n${ + chalk.blueBright( + `bigint("${column.name}", { mode: "number", unsigned: true }).notNull().autoincrement().unique(${ + uniqueForSerial?.name ? `"${uniqueForSerial?.name}"` : '' + })`, + ) + }`, + ), + ); + } + } + } + + return suggestions; +} + +// Intersect with prepareAnMigrate +export const prepareSingleStorePush = async ( + schemaPath: string | string[], + snapshot: SingleStoreSchema, + casing: CasingType | undefined, +) => { + try { + const { prev, cur } = await prepareSingleStoreDbPushSnapshot( + snapshot, + schemaPath, + casing, + ); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + /* singleStoreViewsResolver, */ + validatedPrev, + validatedCur, + 'push', + ); + + return { sqlStatements, statements, validatedCur, validatedPrev }; + } catch (e) { + console.error(e); + process.exit(1); + } +}; + +export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { + const outFolder = config.out; + const schemaPath = config.schema; + const casing = config.casing; + + try { + // TODO: remove + assertV1OutFolder(outFolder); + + const { snapshots, journal } = prepareMigrationFolder(outFolder, 'singlestore'); + const { prev, cur, custom } = await prepareSingleStoreMigrationSnapshot( + snapshots, + schemaPath, + casing, + ); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + if (config.custom) { + writeResult({ + cur: custom, + sqlStatements: [], + journal, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + type: 'custom', + prefixMode: config.prefix, + }); + return; + } + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements, _meta } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + /* singleStoreViewsResolver, */ + validatedPrev, + validatedCur, + ); + + writeResult({ + cur, + sqlStatements, + journal, + _meta, + outFolder, + name: config.name, + breakpoints: config.breakpoints, + prefixMode: config.prefix, + }); + } catch (e) { + console.error(e); + } +}; + export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; @@ -577,6 +753,7 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { breakpoints: config.breakpoints, bundle: config.bundle, prefixMode: config.prefix, + driver: config.driver, }); } catch (e) { console.error(e); @@ -1025,6 +1202,7 @@ export const writeResult = ({ bundle = false, type = 'none', prefixMode, + driver, }: { cur: CommonSchema; sqlStatements: string[]; @@ -1036,6 +1214,7 @@ export const writeResult = ({ name?: string; bundle?: boolean; type?: 'introspect' | 'custom' | 'none'; + driver?: Driver; }) => { if (type === 'none') { console.log(schema(cur)); @@ -1093,9 +1272,9 @@ export const writeResult = ({ fs.writeFileSync(`${outFolder}/${tag}.sql`, sql); - // js file with .sql imports for React Native / Expo + // js file with .sql imports for React Native / Expo and Durable Sqlite Objects if (bundle) { - const js = embeddedMigrations(journal); + const js = embeddedMigrations(journal, driver); fs.writeFileSync(`${outFolder}/migrations.js`, js); } @@ -1112,9 +1291,11 @@ export const writeResult = ({ ); }; -export const embeddedMigrations = (journal: Journal) => { - let content = - '// This file is required for Expo/React Native SQLite migrations - https://orm.drizzle.team/quick-sqlite/expo\n\n'; +export const embeddedMigrations = (journal: Journal, driver?: Driver) => { + let content = driver === 'expo' + ? '// This file is required for Expo/React Native SQLite migrations - https://orm.drizzle.team/quick-sqlite/expo\n\n' + : ''; + content += "import journal from './meta/_journal.json';\n"; journal.entries.forEach((entry) => { content += `import m${entry.idx.toString().padStart(4, '0')} from './${entry.tag}.sql';\n`; diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 4a41a46d4..0c82fe026 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -10,10 +10,18 @@ import { LibSQLCredentials } from '../validations/libsql'; import type { MysqlCredentials } from '../validations/mysql'; import { withStyle } from '../validations/outputs'; import type { PostgresCredentials } from '../validations/postgres'; +import { SingleStoreCredentials } from '../validations/singlestore'; import type { SqliteCredentials } from '../validations/sqlite'; import { libSqlLogSuggestionsAndReturn } from './libSqlPushUtils'; -import { filterStatements, logSuggestionsAndReturn } from './mysqlPushUtils'; +import { + filterStatements as mySqlFilterStatements, + logSuggestionsAndReturn as mySqlLogSuggestionsAndReturn, +} from './mysqlPushUtils'; import { pgSuggestions } from './pgPushUtils'; +import { + filterStatements as singleStoreFilterStatements, + logSuggestionsAndReturn as singleStoreLogSuggestionsAndReturn, +} from './singlestorePushUtils'; import { logSuggestionsAndReturn as sqliteSuggestions } from './sqlitePushUtils'; export const mysqlPush = async ( @@ -35,7 +43,7 @@ export const mysqlPush = async ( const statements = await prepareMySQLPush(schemaPath, schema, casing); - const filteredStatements = filterStatements( + const filteredStatements = mySqlFilterStatements( statements.statements ?? [], statements.validatedCur, statements.validatedPrev, @@ -52,8 +60,7 @@ export const mysqlPush = async ( tablesToRemove, tablesToTruncate, infoToPrint, - schemasToRemove, - } = await logSuggestionsAndReturn( + } = await mySqlLogSuggestionsAndReturn( db, filteredStatements, statements.validatedCur, @@ -156,6 +163,150 @@ export const mysqlPush = async ( } }; +export const singlestorePush = async ( + schemaPath: string | string[], + credentials: SingleStoreCredentials, + tablesFilter: string[], + strict: boolean, + verbose: boolean, + force: boolean, + casing: CasingType | undefined, +) => { + const { connectToSingleStore } = await import('../connections'); + const { singlestorePushIntrospect } = await import('./singlestoreIntrospect'); + + const { db, database } = await connectToSingleStore(credentials); + + const { schema } = await singlestorePushIntrospect( + db, + database, + tablesFilter, + ); + const { prepareSingleStorePush } = await import('./migrate'); + + const statements = await prepareSingleStorePush(schemaPath, schema, casing); + + const filteredStatements = singleStoreFilterStatements( + statements.statements ?? [], + statements.validatedCur, + statements.validatedPrev, + ); + + try { + if (filteredStatements.length === 0) { + render(`[${chalk.blue('i')}] No changes detected`); + } else { + const { + shouldAskForApprove, + statementsToExecute, + columnsToRemove, + tablesToRemove, + tablesToTruncate, + infoToPrint, + schemasToRemove, + } = await singleStoreLogSuggestionsAndReturn( + db, + filteredStatements, + statements.validatedCur, + ); + + const filteredSqlStatements = fromJson(filteredStatements, 'singlestore'); + + const uniqueSqlStatementsToExecute: string[] = []; + statementsToExecute.forEach((ss) => { + if (!uniqueSqlStatementsToExecute.includes(ss)) { + uniqueSqlStatementsToExecute.push(ss); + } + }); + const uniqueFilteredSqlStatements: string[] = []; + filteredSqlStatements.forEach((ss) => { + if (!uniqueFilteredSqlStatements.includes(ss)) { + uniqueFilteredSqlStatements.push(ss); + } + }); + + if (verbose) { + console.log(); + console.log( + withStyle.warning('You are about to execute current statements:'), + ); + console.log(); + console.log( + [...uniqueSqlStatementsToExecute, ...uniqueFilteredSqlStatements] + .map((s) => chalk.blue(s)) + .join('\n'), + ); + console.log(); + } + + if (!force && strict) { + if (!shouldAskForApprove) { + const { status, data } = await render( + new Select(['No, abort', `Yes, I want to execute all statements`]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + } + + if (!force && shouldAskForApprove) { + console.log(withStyle.warning('Found data-loss statements:')); + console.log(infoToPrint.join('\n')); + console.log(); + console.log( + chalk.red.bold( + 'THIS ACTION WILL CAUSE DATA LOSS AND CANNOT BE REVERTED\n', + ), + ); + + console.log(chalk.white('Do you still want to push changes?')); + + const { status, data } = await render( + new Select([ + 'No, abort', + `Yes, I want to${ + tablesToRemove.length > 0 + ? ` remove ${tablesToRemove.length} ${tablesToRemove.length > 1 ? 'tables' : 'table'},` + : ' ' + }${ + columnsToRemove.length > 0 + ? ` remove ${columnsToRemove.length} ${columnsToRemove.length > 1 ? 'columns' : 'column'},` + : ' ' + }${ + tablesToTruncate.length > 0 + ? ` truncate ${tablesToTruncate.length} ${tablesToTruncate.length > 1 ? 'tables' : 'table'}` + : '' + }` + .replace(/(^,)|(,$)/g, '') + .replace(/ +(?= )/g, ''), + ]), + ); + if (data?.index === 0) { + render(`[${chalk.red('x')}] All changes were aborted`); + process.exit(0); + } + } + + for (const dStmnt of uniqueSqlStatementsToExecute) { + await db.query(dStmnt); + } + + for (const statement of uniqueFilteredSqlStatements) { + await db.query(statement); + } + if (filteredStatements.length > 0) { + render(`[${chalk.green('✓')}] Changes applied`); + } else { + render(`[${chalk.blue('i')}] No changes detected`); + } + } + } catch (e) { + console.log(e); + } +}; + export const pgPush = async ( schemaPath: string | string[], verbose: boolean, @@ -171,7 +322,6 @@ export const pgPush = async ( const { pgPushIntrospect } = await import('./pgIntrospect'); const db = await preparePostgresDB(credentials); - const serialized = await serializePg(schemaPath, casing, schemasFilter); const { schema } = await pgPushIntrospect(db, tablesFilter, schemasFilter, entities, serialized); diff --git a/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts b/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts new file mode 100644 index 000000000..27d8c59c5 --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts @@ -0,0 +1,53 @@ +import { renderWithTask } from 'hanji'; +import { Minimatch } from 'minimatch'; +import { originUUID } from '../../global'; +import type { SingleStoreSchema } from '../../serializer/singlestoreSchema'; +import { fromDatabase } from '../../serializer/singlestoreSerializer'; +import type { DB } from '../../utils'; +import { ProgressView } from '../views'; + +export const singlestorePushIntrospect = async ( + db: DB, + databaseName: string, + filters: string[], +) => { + const matchers = filters.map((it) => { + return new Minimatch(it); + }); + + const filter = (tableName: string) => { + if (matchers.length === 0) return true; + + let flags: boolean[] = []; + + for (let matcher of matchers) { + if (matcher.negate) { + if (!matcher.match(tableName)) { + flags.push(false); + } + } + + if (matcher.match(tableName)) { + flags.push(true); + } + } + + if (flags.length > 0) { + return flags.every(Boolean); + } + return false; + }; + + const progress = new ProgressView( + 'Pulling schema from database...', + 'Pulling schema from database...', + ); + const res = await renderWithTask( + progress, + fromDatabase(db, databaseName, filter), + ); + + const schema = { id: originUUID, prevId: '', ...res } as SingleStoreSchema; + const { internal, ...schemaWithoutInternals } = schema; + return { schema: schemaWithoutInternals }; +}; diff --git a/drizzle-kit/src/cli/commands/singlestorePushUtils.ts b/drizzle-kit/src/cli/commands/singlestorePushUtils.ts new file mode 100644 index 000000000..80fad9b2d --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestorePushUtils.ts @@ -0,0 +1,352 @@ +import chalk from 'chalk'; +import { render } from 'hanji'; +import { TypeOf } from 'zod'; +import { JsonAlterColumnTypeStatement, JsonStatement } from '../../jsonStatements'; +import { singlestoreSchema, SingleStoreSquasher } from '../../serializer/singlestoreSchema'; +import type { DB } from '../../utils'; +import { Select } from '../selector-ui'; +import { withStyle } from '../validations/outputs'; + +export const filterStatements = ( + statements: JsonStatement[], + currentSchema: TypeOf, + prevSchema: TypeOf, +) => { + return statements.filter((statement) => { + if (statement.type === 'alter_table_alter_column_set_type') { + // Don't need to handle it on migrations step and introspection + // but for both it should be skipped + if ( + statement.oldDataType.startsWith('tinyint') + && statement.newDataType.startsWith('boolean') + ) { + return false; + } + + if ( + statement.oldDataType.startsWith('bigint unsigned') + && statement.newDataType.startsWith('serial') + ) { + return false; + } + + if ( + statement.oldDataType.startsWith('serial') + && statement.newDataType.startsWith('bigint unsigned') + ) { + return false; + } + } else if (statement.type === 'alter_table_alter_column_set_default') { + if ( + statement.newDefaultValue === false + && statement.oldDefaultValue === 0 + && statement.newDataType === 'boolean' + ) { + return false; + } + if ( + statement.newDefaultValue === true + && statement.oldDefaultValue === 1 + && statement.newDataType === 'boolean' + ) { + return false; + } + } else if (statement.type === 'delete_unique_constraint') { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); + // only if constraint was removed from a serial column, than treat it as removed + // const serialStatement = statements.find( + // (it) => it.type === "alter_table_alter_column_set_type" + // ) as JsonAlterColumnTypeStatement; + // if ( + // serialStatement?.oldDataType.startsWith("bigint unsigned") && + // serialStatement?.newDataType.startsWith("serial") && + // serialStatement.columnName === + // SingleStoreSquasher.unsquashUnique(statement.data).columns[0] + // ) { + // return false; + // } + // Check if uniqueindex was only on this column, that is serial + + // if now serial and was not serial and was unique index + if ( + unsquashed.columns.length === 1 + && currentSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .type === 'serial' + && prevSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .type === 'serial' + && currentSchema.tables[statement.tableName].columns[unsquashed.columns[0]] + .name === unsquashed.columns[0] + ) { + return false; + } + } else if (statement.type === 'alter_table_alter_column_drop_notnull') { + // only if constraint was removed from a serial column, than treat it as removed + const serialStatement = statements.find( + (it) => it.type === 'alter_table_alter_column_set_type', + ) as JsonAlterColumnTypeStatement; + if ( + serialStatement?.oldDataType.startsWith('bigint unsigned') + && serialStatement?.newDataType.startsWith('serial') + && serialStatement.columnName === statement.columnName + && serialStatement.tableName === statement.tableName + ) { + return false; + } + if (statement.newDataType === 'serial' && !statement.columnNotNull) { + return false; + } + if (statement.columnAutoIncrement) { + return false; + } + } + + return true; + }); +}; + +export const logSuggestionsAndReturn = async ( + db: DB, + statements: JsonStatement[], + json2: TypeOf, +) => { + let shouldAskForApprove = false; + const statementsToExecute: string[] = []; + const infoToPrint: string[] = []; + + const tablesToRemove: string[] = []; + const columnsToRemove: string[] = []; + const schemasToRemove: string[] = []; + const tablesToTruncate: string[] = []; + + for (const statement of statements) { + if (statement.type === 'drop_table') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.tableName, + ) + } table with ${count} items`, + ); + tablesToRemove.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_drop_column') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.columnName, + ) + } column in ${statement.tableName} table with ${count} items`, + ); + columnsToRemove.push(`${statement.tableName}_${statement.columnName}`); + shouldAskForApprove = true; + } + } else if (statement.type === 'drop_schema') { + const res = await db.query( + `select count(*) as count from information_schema.tables where table_schema = \`${statement.name}\`;`, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to delete ${ + chalk.underline( + statement.name, + ) + } schema with ${count} tables`, + ); + schemasToRemove.push(statement.name); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_alter_column_set_type') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to change ${ + chalk.underline( + statement.columnName, + ) + } column type from ${ + chalk.underline( + statement.oldDataType, + ) + } to ${chalk.underline(statement.newDataType)} with ${count} items`, + ); + statementsToExecute.push(`truncate table ${statement.tableName};`); + tablesToTruncate.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'alter_table_alter_column_drop_default') { + if (statement.columnNotNull) { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to remove default value from ${ + chalk.underline( + statement.columnName, + ) + } not-null column with ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + // shouldAskForApprove = true; + } else if (statement.type === 'alter_table_alter_column_set_notnull') { + if (typeof statement.columnDefault === 'undefined') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to set not-null constraint to ${ + chalk.underline( + statement.columnName, + ) + } column without default, which contains ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + } else if (statement.type === 'alter_table_alter_column_drop_pk') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + + // if drop pk and json2 has autoincrement in table -> exit process with error + if ( + Object.values(json2.tables[statement.tableName].columns).filter( + (column) => column.autoincrement, + ).length > 0 + ) { + console.log( + `${ + withStyle.errorWarning( + `You have removed the primary key from a ${statement.tableName} table without removing the auto-increment property from this table. As the database error states: 'there can be only one auto column, and it must be defined as a key. Make sure to remove autoincrement from ${statement.tableName} table`, + ) + }`, + ); + process.exit(1); + } + + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to change ${ + chalk.underline( + statement.tableName, + ) + } primary key. This statements may fail and you table may left without primary key`, + ); + + tablesToTruncate.push(statement.tableName); + shouldAskForApprove = true; + } + } else if (statement.type === 'delete_composite_pk') { + // if drop pk and json2 has autoincrement in table -> exit process with error + if ( + Object.values(json2.tables[statement.tableName].columns).filter( + (column) => column.autoincrement, + ).length > 0 + ) { + console.log( + `${ + withStyle.errorWarning( + `You have removed the primary key from a ${statement.tableName} table without removing the auto-increment property from this table. As the database error states: 'there can be only one auto column, and it must be defined as a key. Make sure to remove autoincrement from ${statement.tableName} table`, + ) + }`, + ); + process.exit(1); + } + } else if (statement.type === 'alter_table_add_column') { + if ( + statement.column.notNull + && typeof statement.column.default === 'undefined' + ) { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + infoToPrint.push( + `· You're about to add not-null ${ + chalk.underline( + statement.column.name, + ) + } column without default value, which contains ${count} items`, + ); + + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + + shouldAskForApprove = true; + } + } + } else if (statement.type === 'create_unique_constraint') { + const res = await db.query( + `select count(*) as count from \`${statement.tableName}\``, + ); + const count = Number(res[0].count); + if (count > 0) { + const unsquashedUnique = SingleStoreSquasher.unsquashUnique(statement.data); + console.log( + `· You're about to add ${ + chalk.underline( + unsquashedUnique.name, + ) + } unique constraint to the table, which contains ${count} items. If this statement fails, you will receive an error from the database. Do you want to truncate ${ + chalk.underline( + statement.tableName, + ) + } table?\n`, + ); + const { status, data } = await render( + new Select([ + 'No, add the constraint without truncating the table', + `Yes, truncate the table`, + ]), + ); + if (data?.index === 1) { + tablesToTruncate.push(statement.tableName); + statementsToExecute.push(`truncate table ${statement.tableName};`); + shouldAskForApprove = true; + } + } + } + } + + return { + statementsToExecute, + shouldAskForApprove, + infoToPrint, + columnsToRemove: [...new Set(columnsToRemove)], + schemasToRemove: [...new Set(schemasToRemove)], + tablesToTruncate: [...new Set(tablesToTruncate)], + tablesToRemove: [...new Set(tablesToRemove)], + }; +}; diff --git a/drizzle-kit/src/cli/commands/singlestoreUp.ts b/drizzle-kit/src/cli/commands/singlestoreUp.ts new file mode 100644 index 000000000..dc5004ed0 --- /dev/null +++ b/drizzle-kit/src/cli/commands/singlestoreUp.ts @@ -0,0 +1 @@ +export const upSinglestoreHandler = (out: string) => {}; diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 7386b74d5..60571ad73 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -31,6 +31,11 @@ import { postgresCredentials, printConfigConnectionIssues as printIssuesPg, } from '../validations/postgres'; +import { + printConfigConnectionIssues as printIssuesSingleStore, + SingleStoreCredentials, + singlestoreCredentials, +} from '../validations/singlestore'; import { printConfigConnectionIssues as printIssuesSqlite, SqliteCredentials, @@ -127,6 +132,7 @@ export type GenerateConfig = { custom: boolean; bundle: boolean; casing?: CasingType; + driver?: Driver; }; export const prepareGenerateConfig = async ( @@ -173,8 +179,9 @@ export const prepareGenerateConfig = async ( breakpoints: breakpoints ?? true, schema: schema, out: out || 'drizzle', - bundle: driver === 'expo', + bundle: driver === 'expo' || driver === 'durable-sqlite', casing, + driver, }; }; @@ -222,6 +229,10 @@ export const preparePushConfig = async ( dialect: 'turso'; credentials: LibSQLCredentials; } + | { + dialect: 'singlestore'; + credentials: SingleStoreCredentials; + } ) & { schemaPath: string | string[]; verbose: boolean; @@ -316,6 +327,25 @@ export const preparePushConfig = async ( }; } + if (config.dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(config); + if (!parsed.success) { + printIssuesSingleStore(config); + process.exit(1); + } + + return { + dialect: 'singlestore', + schemaPath: config.schema, + strict: config.strict ?? false, + verbose: config.verbose ?? false, + force: (options.force as boolean) ?? false, + credentials: parsed.data, + tablesFilter, + schemasFilter, + }; + } + if (config.dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(config); if (!parsed.success) { @@ -378,6 +408,10 @@ export const preparePullConfig = async ( dialect: 'turso'; credentials: LibSQLCredentials; } + | { + dialect: 'singlestore'; + credentials: SingleStoreCredentials; + } ) & { out: string; breakpoints: boolean; @@ -468,6 +502,26 @@ export const preparePullConfig = async ( }; } + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(config); + if (!parsed.success) { + printIssuesSingleStore(config); + process.exit(1); + } + + return { + dialect: 'singlestore', + out: config.out, + breakpoints: config.breakpoints, + casing: config.casing, + credentials: parsed.data, + tablesFilter, + schemasFilter, + prefix: config.migrations?.prefix || 'index', + entities: config.entities, + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(config); if (!parsed.success) { @@ -559,6 +613,23 @@ export const prepareStudioConfig = async (options: Record) => { credentials, }; } + + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesSingleStore(flattened as Record); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + schema, + host, + port, + credentials, + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(flattened); if (!parsed.success) { @@ -644,6 +715,23 @@ export const prepareMigrateConfig = async (configPath: string | undefined) => { table, }; } + + if (dialect === 'singlestore') { + const parsed = singlestoreCredentials.safeParse(flattened); + if (!parsed.success) { + printIssuesSingleStore(flattened as Record); + process.exit(1); + } + const credentials = parsed.data; + return { + dialect, + out, + credentials, + schema, + table, + }; + } + if (dialect === 'sqlite') { const parsed = sqliteCredentials.safeParse(flattened); if (!parsed.success) { diff --git a/drizzle-kit/src/cli/connections.ts b/drizzle-kit/src/cli/connections.ts index aab1d0ef7..f2cf4817c 100644 --- a/drizzle-kit/src/cli/connections.ts +++ b/drizzle-kit/src/cli/connections.ts @@ -19,6 +19,7 @@ import { LibSQLCredentials } from './validations/libsql'; import type { MysqlCredentials } from './validations/mysql'; import { withStyle } from './validations/outputs'; import type { PostgresCredentials } from './validations/postgres'; +import { SingleStoreCredentials } from './validations/singlestore'; import type { SqliteCredentials } from './validations/sqlite'; export const preparePostgresDB = async ( @@ -415,6 +416,85 @@ export const preparePostgresDB = async ( process.exit(1); }; +const parseSingleStoreCredentials = (credentials: SingleStoreCredentials) => { + if ('url' in credentials) { + const url = credentials.url; + + const connectionUrl = new URL(url); + const pathname = connectionUrl.pathname; + + const database = pathname.split('/')[pathname.split('/').length - 1]; + if (!database) { + console.error( + 'You should specify a database name in connection string (singlestore://USER:PASSWORD@HOST:PORT/DATABASE)', + ); + process.exit(1); + } + return { database, url }; + } else { + return { + database: credentials.database, + credentials, + }; + } +}; + +export const connectToSingleStore = async ( + it: SingleStoreCredentials, +): Promise<{ + db: DB; + proxy: Proxy; + database: string; + migrate: (config: MigrationConfig) => Promise; +}> => { + const result = parseSingleStoreCredentials(it); + + if (await checkPackage('mysql2')) { + const { createConnection } = await import('mysql2/promise'); + const { drizzle } = await import('drizzle-orm/singlestore'); + const { migrate } = await import('drizzle-orm/singlestore/migrator'); + + const connection = result.url + ? await createConnection(result.url) + : await createConnection(result.credentials!); // needed for some reason! + + const db = drizzle(connection); + const migrateFn = async (config: MigrationConfig) => { + return migrate(db, config); + }; + + await connection.connect(); + const query: DB['query'] = async ( + sql: string, + params?: any[], + ): Promise => { + const res = await connection.execute(sql, params); + return res[0] as any; + }; + + const proxy: Proxy = async (params: ProxyParams) => { + const result = await connection.query({ + sql: params.sql, + values: params.params, + rowsAsArray: params.mode === 'array', + }); + return result[0] as any[]; + }; + + return { + db: { query }, + proxy, + database: result.database, + migrate: migrateFn, + }; + } + + console.error( + "To connect to SingleStore database - please install 'singlestore' driver", + ); + process.exit(1); +}; + const parseMysqlCredentials = (credentials: MysqlCredentials) => { if ('url' in credentials) { const url = credentials.url; diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index b03acde95..12153ee74 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -1,11 +1,19 @@ +import { boolean, command, number, string } from '@drizzle-team/brocli'; import chalk from 'chalk'; -import { checkHandler } from './commands/check'; -import { assertOrmCoreVersion, assertPackages, assertStudioNodeVersion, ormVersionGt } from './utils'; +import 'dotenv/config'; +import { mkdirSync } from 'fs'; +import { renderWithTask } from 'hanji'; +import { dialects } from 'src/schemaValidator'; import '../@types/utils'; +import { assertUnreachable } from '../global'; +import { type Setup } from '../serializer/studio'; import { assertV1OutFolder } from '../utils'; +import { certs } from '../utils/certs'; +import { checkHandler } from './commands/check'; import { dropMigration } from './commands/drop'; import { upMysqlHandler } from './commands/mysqlUp'; import { upPgHandler } from './commands/pgUp'; +import { upSinglestoreHandler } from './commands/singlestoreUp'; import { upSqliteHandler } from './commands/sqliteUp'; import { prepareCheckParams, @@ -16,21 +24,16 @@ import { preparePushConfig, prepareStudioConfig, } from './commands/utils'; +import { assertOrmCoreVersion, assertPackages, assertStudioNodeVersion, ormVersionGt } from './utils'; import { assertCollisions, drivers, prefixes } from './validations/common'; import { withStyle } from './validations/outputs'; -import 'dotenv/config'; -import { boolean, command, number, string } from '@drizzle-team/brocli'; -import { mkdirSync } from 'fs'; -import { renderWithTask } from 'hanji'; -import { dialects } from 'src/schemaValidator'; -import { assertUnreachable } from '../global'; -import type { Setup } from '../serializer/studio'; -import { certs } from '../utils/certs'; import { grey, MigrateProgress } from './views'; const optionDialect = string('dialect') .enum(...dialects) - .desc(`Database dialect: 'postgresql', 'mysql', 'sqlite' or 'turso'`); + .desc( + `Database dialect: 'postgresql', 'mysql', 'sqlite', 'turso' or 'singlestore'`, + ); const optionOut = string().desc("Output folder, 'drizzle' by default"); const optionConfig = string().desc('Path to drizzle config file'); const optionBreakpoints = boolean().desc( @@ -81,6 +84,7 @@ export const generate = command({ prepareAndMigrateMysql, prepareAndMigrateSqlite, prepareAndMigrateLibSQL, + prepareAndMigrateSingleStore, } = await import('./commands/migrate'); const dialect = opts.dialect; @@ -92,6 +96,8 @@ export const generate = command({ await prepareAndMigrateSqlite(opts); } else if (dialect === 'turso') { await prepareAndMigrateLibSQL(opts); + } else if (dialect === 'singlestore') { + await prepareAndMigrateSqlite(opts); } else { assertUnreachable(dialect); } @@ -154,6 +160,17 @@ export const migrate = command({ migrationsSchema: schema, }), ); + } else if (dialect === 'singlestore') { + const { connectToSingleStore } = await import('./connections'); + const { migrate } = await connectToSingleStore(credentials); + await renderWithTask( + new MigrateProgress(), + migrate({ + migrationsFolder: out, + migrationsTable: table, + migrationsSchema: schema, + }), + ); } else if (dialect === 'sqlite') { const { connectToSQLite } = await import('./connections'); const { migrate } = await connectToSQLite(credentials); @@ -340,6 +357,17 @@ export const push = command({ force, casing, ); + } else if (dialect === 'singlestore') { + const { singlestorePush } = await import('./commands/push'); + await singlestorePush( + schemaPath, + credentials, + tablesFilter, + strict, + verbose, + force, + casing, + ); } else { assertUnreachable(dialect); } @@ -398,6 +426,10 @@ export const up = command({ if (dialect === 'sqlite' || dialect === 'turso') { upSqliteHandler(out); } + + if (dialect === 'singlestore') { + upSinglestoreHandler(out); + } }, }); @@ -531,6 +563,16 @@ export const pull = command({ tablesFilter, prefix, ); + } else if (dialect === 'singlestore') { + const { introspectSingleStore } = await import('./commands/introspect'); + await introspectSingleStore( + casing, + out, + breakpoints, + credentials, + tablesFilter, + prefix, + ); } else { assertUnreachable(dialect); } @@ -591,6 +633,8 @@ export const studio = command({ drizzleForMySQL, prepareSQLiteSchema, drizzleForSQLite, + prepareSingleStoreSchema, + drizzleForSingleStore, drizzleForLibSQL, } = await import('../serializer/studio'); @@ -637,6 +681,16 @@ export const studio = command({ ? await prepareSQLiteSchema(schemaPath) : { schema: {}, relations: {}, files: [] }; setup = await drizzleForLibSQL(credentials, schema, relations, files); + } else if (dialect === 'singlestore') { + const { schema, relations, files } = schemaPath + ? await prepareSingleStoreSchema(schemaPath) + : { schema: {}, relations: {}, files: [] }; + setup = await drizzleForSingleStore( + credentials, + schema, + relations, + files, + ); } else { assertUnreachable(dialect); } diff --git a/drizzle-kit/src/cli/validations/common.ts b/drizzle-kit/src/cli/validations/common.ts index 1662e87bb..7fc6046a7 100644 --- a/drizzle-kit/src/cli/validations/common.ts +++ b/drizzle-kit/src/cli/validations/common.ts @@ -63,6 +63,7 @@ export const assertCollisions = < export const sqliteDriversLiterals = [ literal('d1-http'), literal('expo'), + literal('durable-sqlite'), ] as const; export const postgresqlDriversLiterals = [ @@ -160,7 +161,7 @@ export const configPushSchema = object({ }); export type CliConfig = TypeOf; -export const drivers = ['d1-http', 'expo', 'aws-data-api', 'pglite'] as const; +export const drivers = ['d1-http', 'expo', 'aws-data-api', 'pglite', 'durable-sqlite'] as const; export type Driver = (typeof drivers)[number]; const _: Driver = '' as TypeOf; diff --git a/drizzle-kit/src/cli/validations/outputs.ts b/drizzle-kit/src/cli/validations/outputs.ts index 3ef499651..6e9d520dd 100644 --- a/drizzle-kit/src/cli/validations/outputs.ts +++ b/drizzle-kit/src/cli/validations/outputs.ts @@ -26,7 +26,7 @@ export const outputs = { ), noDialect: () => withStyle.error( - `Please specify 'dialect' param in config, either of 'postgresql', 'mysql', 'sqlite' or 'turso'`, + `Please specify 'dialect' param in config, either of 'postgresql', 'mysql', 'sqlite', turso or singlestore`, ), }, common: { @@ -79,4 +79,13 @@ export const outputs = { introspect: {}, push: {}, }, + singlestore: { + connection: { + driver: () => withStyle.error(`Only "mysql2" is available options for "--driver"`), + required: () => + withStyle.error( + `Either "url" or "host", "database" are required for database connection`, + ), + }, + }, }; diff --git a/drizzle-kit/src/cli/validations/singlestore.ts b/drizzle-kit/src/cli/validations/singlestore.ts new file mode 100644 index 000000000..ebe0cc5f0 --- /dev/null +++ b/drizzle-kit/src/cli/validations/singlestore.ts @@ -0,0 +1,61 @@ +import { boolean, coerce, object, string, TypeOf, union } from 'zod'; +import { error } from '../views'; +import { wrapParam } from './common'; +import { outputs } from './outputs'; + +export const singlestoreCredentials = union([ + object({ + host: string().min(1), + port: coerce.number().min(1).optional(), + user: string().min(1).optional(), + password: string().min(1).optional(), + database: string().min(1), + ssl: union([ + string(), + object({ + pfx: string().optional(), + key: string().optional(), + passphrase: string().optional(), + cert: string().optional(), + ca: union([string(), string().array()]).optional(), + crl: union([string(), string().array()]).optional(), + ciphers: string().optional(), + rejectUnauthorized: boolean().optional(), + }), + ]).optional(), + }), + object({ + url: string().min(1), + }), +]); + +export type SingleStoreCredentials = TypeOf; + +export const printCliConnectionIssues = (options: any) => { + const { uri, host, database } = options || {}; + + if (!uri && (!host || !database)) { + console.log(outputs.singlestore.connection.required()); + } +}; + +export const printConfigConnectionIssues = ( + options: Record, +) => { + if ('url' in options) { + let text = `Please provide required params for SingleStore driver:\n`; + console.log(error(text)); + console.log(wrapParam('url', options.url, false, 'url')); + process.exit(1); + } + + let text = `Please provide required params for SingleStore driver:\n`; + console.log(error(text)); + console.log(wrapParam('host', options.host)); + console.log(wrapParam('port', options.port, true)); + console.log(wrapParam('user', options.user, true)); + console.log(wrapParam('password', options.password, true, 'secret')); + console.log(wrapParam('database', options.database)); + console.log(wrapParam('ssl', options.ssl, true)); + process.exit(1); +}; diff --git a/drizzle-kit/src/cli/validations/sqlite.ts b/drizzle-kit/src/cli/validations/sqlite.ts index 54178fd4a..bb16492c3 100644 --- a/drizzle-kit/src/cli/validations/sqlite.ts +++ b/drizzle-kit/src/cli/validations/sqlite.ts @@ -72,12 +72,27 @@ export const printConfigConnectionIssues = ( console.log(wrapParam('databaseId', options.databaseId)); console.log(wrapParam('token', options.token, false, 'secret')); process.exit(1); - } else if (driver === 'turso') { - let text = `Please provide required params for Turso driver:\n`; - console.log(error(text)); - console.log(wrapParam('url', options.url)); - console.log(wrapParam('authToken', options.authToken, false, 'secret')); - return; + } else if (driver === 'durable-sqlite') { + if (command === 'migrate') { + console.log( + error( + `You can't use 'migrate' command with SQLite Durable Objects`, + ), + ); + } else if (command === 'studio') { + console.log( + error( + `You can't use 'migrate' command with SQLite Durable Objects`, + ), + ); + } else if (command === 'pull') { + console.log(error("You can't use 'pull' command with SQLite Durable Objects")); + } else if (command === 'push') { + console.log(error("You can't use 'push' command with SQLite Durable Objects")); + } else { + console.log(error('Unexpected error with SQLite Durable Object driver 🤔')); + } + process.exit(1); } else { softAssertUnreachable(driver); } diff --git a/drizzle-kit/src/cli/views.ts b/drizzle-kit/src/cli/views.ts index 3ec04a588..9106d31cd 100644 --- a/drizzle-kit/src/cli/views.ts +++ b/drizzle-kit/src/cli/views.ts @@ -32,7 +32,13 @@ export const schema = (schema: CommonSchema): string => { .map((t) => { const columnsCount = Object.values(t.columns).length; const indexesCount = Object.values(t.indexes).length; - const foreignKeys = Object.values(t.foreignKeys).length; + let foreignKeys: number = 0; + // Singlestore doesn't have foreign keys + if (schema.dialect !== 'singlestore') { + // @ts-expect-error + foreignKeys = Object.values(t.foreignKeys).length; + } + return `${chalk.bold.blue(t.name)} ${ chalk.gray( `${columnsCount} columns ${indexesCount} indexes ${foreignKeys} fks`, diff --git a/drizzle-kit/src/index.ts b/drizzle-kit/src/index.ts index 4a57e59e3..4c55f3eb6 100644 --- a/drizzle-kit/src/index.ts +++ b/drizzle-kit/src/index.ts @@ -23,7 +23,7 @@ type Verify = U; * **Config** usage: * * `dialect` - mandatory and is responsible for explicitly providing a databse dialect you are using for all the commands - * *Possible values*: `postgresql`, `mysql`, `sqlite` + * *Possible values*: `postgresql`, `mysql`, `sqlite`, `singlestore * * See https://orm.drizzle.team/kit-docs/config-reference#dialect * @@ -64,7 +64,7 @@ type Verify = U; * * `breakpoints` - param lets you enable/disable SQL statement breakpoints in generated migrations. * It’s optional and true by default, it’s necessary to properly apply migrations on databases, - * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite) and + * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite, SingleStore) and * Drizzle ORM has to apply them sequentially one by one. * * See https://orm.drizzle.team/kit-docs/config-reference#breakpoints @@ -209,7 +209,26 @@ export type Config = dialect: Verify; driver: Verify; } + | { + dialect: Verify; + driver: Verify; + } | {} + | { + dialect: Verify; + dbCredentials: + | { + host: string; + port?: number; + user?: string; + password?: string; + database: string; + ssl?: string | SslOptions; + } + | { + url: string; + }; + } ); /** @@ -219,7 +238,7 @@ export type Config = * **Config** usage: * * `dialect` - mandatory and is responsible for explicitly providing a databse dialect you are using for all the commands - * *Possible values*: `postgresql`, `mysql`, `sqlite` + * *Possible values*: `postgresql`, `mysql`, `sqlite`, `singlestore` * * See https://orm.drizzle.team/kit-docs/config-reference#dialect * @@ -260,7 +279,7 @@ export type Config = * * `breakpoints` - param lets you enable/disable SQL statement breakpoints in generated migrations. * It’s optional and true by default, it’s necessary to properly apply migrations on databases, - * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite) and + * that do not support multiple DDL alternation statements in one transaction(MySQL, SQLite, SingleStore) and * Drizzle ORM has to apply them sequentially one by one. * * See https://orm.drizzle.team/kit-docs/config-reference#breakpoints diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts new file mode 100644 index 000000000..8f93cdfda --- /dev/null +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -0,0 +1,918 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +import { toCamelCase } from 'drizzle-orm/casing'; +import './@types/utils'; +import type { Casing } from './cli/validations/common'; +import { assertUnreachable } from './global'; +import { + Column, + Index, + PrimaryKey, + SingleStoreSchema, + SingleStoreSchemaInternal, + UniqueConstraint, +} from './serializer/singlestoreSchema'; +import { indexName } from './serializer/singlestoreSerializer'; + +// time precision to fsp +// {mode: "string"} for timestamp by default + +const singlestoreImportsList = new Set([ + 'singlestoreTable', + 'singlestoreEnum', + 'bigint', + 'binary', + 'boolean', + 'char', + 'date', + 'datetime', + 'decimal', + 'double', + 'float', + 'int', + 'json', + // TODO: add new type BSON + // TODO: add new type Blob + // TODO: add new type UUID + // TODO: add new type GUID + // TODO: add new type Vector + // TODO: add new type GeoPoint + 'mediumint', + 'real', + 'serial', + 'smallint', + 'text', + 'tinytext', + 'mediumtext', + 'longtext', + 'time', + 'timestamp', + 'tinyint', + 'varbinary', + 'varchar', + 'year', + 'enum', +]); + +const objToStatement = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `"${it}": "${json[it]}"`).join(', '); + statement += ' }'; + return statement; +}; + +const objToStatement2 = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: "${json[it]}"`).join(', '); // no "" for keys + statement += ' }'; + return statement; +}; + +const timeConfig = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: ${json[it]}`).join(', '); + statement += ' }'; + return statement; +}; + +const binaryConfig = (json: any) => { + json = Object.fromEntries(Object.entries(json).filter((it) => it[1])); + + const keys = Object.keys(json); + if (keys.length === 0) return; + + let statement = '{ '; + statement += keys.map((it) => `${it}: ${json[it]}`).join(', '); + statement += ' }'; + return statement; +}; + +const importsPatch = { + 'double precision': 'doublePrecision', + 'timestamp without time zone': 'timestamp', +} as Record; + +const escapeColumnKey = (value: string) => { + if (/^(?![a-zA-Z_$][a-zA-Z0-9_$]*$).+$/.test(value)) { + return `"${value}"`; + } + return value; +}; + +const prepareCasing = (casing?: Casing) => (value: string) => { + if (casing === 'preserve') { + return escapeColumnKey(value); + } + if (casing === 'camel') { + return escapeColumnKey(value.camelCase()); + } + + assertUnreachable(casing); +}; + +const dbColumnName = ({ name, casing, withMode = false }: { name: string; casing: Casing; withMode?: boolean }) => { + if (casing === 'preserve') { + return ''; + } + if (casing === 'camel') { + return toCamelCase(name) === name ? '' : withMode ? `"${name}", ` : `"${name}"`; + } + + assertUnreachable(casing); +}; + +export const schemaToTypeScript = ( + schema: SingleStoreSchemaInternal, + casing: Casing, +) => { + const withCasing = prepareCasing(casing); + + const imports = Object.values(schema.tables).reduce( + (res, it) => { + const idxImports = Object.values(it.indexes).map((idx) => idx.isUnique ? 'uniqueIndex' : 'index'); + const pkImports = Object.values(it.compositePrimaryKeys).map( + (it) => 'primaryKey', + ); + const uniqueImports = Object.values(it.uniqueConstraints).map( + (it) => 'unique', + ); + + res.singlestore.push(...idxImports); + res.singlestore.push(...pkImports); + res.singlestore.push(...uniqueImports); + + const columnImports = Object.values(it.columns) + .map((col) => { + let patched = importsPatch[col.type] ?? col.type; + patched = patched.startsWith('varchar(') ? 'varchar' : patched; + patched = patched.startsWith('char(') ? 'char' : patched; + patched = patched.startsWith('binary(') ? 'binary' : patched; + patched = patched.startsWith('decimal(') ? 'decimal' : patched; + patched = patched.startsWith('smallint(') ? 'smallint' : patched; + patched = patched.startsWith('enum(') ? 'singlestoreEnum' : patched; + patched = patched.startsWith('datetime(') ? 'datetime' : patched; + patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; + patched = patched.startsWith('int(') ? 'int' : patched; + patched = patched.startsWith('double(') ? 'double' : patched; + patched = patched.startsWith('float(') ? 'float' : patched; + patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint(') ? 'tinyint' : patched; + patched = patched.startsWith('mediumint(') ? 'mediumint' : patched; + patched = patched.startsWith('bigint(') ? 'bigint' : patched; + patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; + patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; + patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; + patched = patched.startsWith('bigint unsigned') ? 'bigint' : patched; + return patched; + }) + .filter((type) => { + return singlestoreImportsList.has(type); + }); + + res.singlestore.push(...columnImports); + return res; + }, + { singlestore: [] as string[] }, + ); + + /* Object.values(schema.views).forEach((it) => { + imports.singlestore.push('singlestoreView'); + + const columnImports = Object.values(it.columns) + .map((col) => { + let patched = importsPatch[col.type] ?? col.type; + patched = patched.startsWith('varchar(') ? 'varchar' : patched; + patched = patched.startsWith('char(') ? 'char' : patched; + patched = patched.startsWith('binary(') ? 'binary' : patched; + patched = patched.startsWith('decimal(') ? 'decimal' : patched; + patched = patched.startsWith('smallint(') ? 'smallint' : patched; + patched = patched.startsWith('enum(') ? 'singlestoreEnum' : patched; + patched = patched.startsWith('datetime(') ? 'datetime' : patched; + patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; + patched = patched.startsWith('int(') ? 'int' : patched; + patched = patched.startsWith('double(') ? 'double' : patched; + patched = patched.startsWith('float(') ? 'float' : patched; + patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint(') ? 'tinyint' : patched; + patched = patched.startsWith('mediumint(') ? 'mediumint' : patched; + patched = patched.startsWith('bigint(') ? 'bigint' : patched; + patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; + patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; + patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; + patched = patched.startsWith('bigint unsigned') ? 'bigint' : patched; + return patched; + }) + .filter((type) => { + return singlestoreImportsList.has(type); + }); + + imports.singlestore.push(...columnImports); + }); */ + + const tableStatements = Object.values(schema.tables).map((table) => { + const func = 'singlestoreTable'; + let statement = ''; + if (imports.singlestore.includes(withCasing(table.name))) { + statement = `// Table name is in conflict with ${ + withCasing( + table.name, + ) + } import.\n// Please change to any other name, that is not in imports list\n`; + } + statement += `export const ${withCasing(table.name)} = ${func}("${table.name}", {\n`; + statement += createTableColumns( + Object.values(table.columns), + withCasing, + casing, + table.name, + schema, + ); + statement += '}'; + + if ( + Object.keys(table.indexes).length > 0 + || Object.keys(table.compositePrimaryKeys).length > 0 + || Object.keys(table.uniqueConstraints).length > 0 + ) { + statement += ',\n'; + statement += '(table) => {\n'; + statement += '\treturn {\n'; + statement += createTableIndexes( + table.name, + Object.values(table.indexes), + withCasing, + ); + statement += createTablePKs( + Object.values(table.compositePrimaryKeys), + withCasing, + ); + statement += createTableUniques( + Object.values(table.uniqueConstraints), + withCasing, + ); + statement += '\t}\n'; + statement += '}'; + } + + statement += ');'; + return statement; + }); + + /* const viewsStatements = Object.values(schema.views).map((view) => { + const { columns, name, algorithm, definition, sqlSecurity, withCheckOption } = view; + const func = 'singlestoreView'; + let statement = ''; + + if (imports.singlestore.includes(withCasing(name))) { + statement = `// Table name is in conflict with ${ + withCasing( + view.name, + ) + } import.\n// Please change to any other name, that is not in imports list\n`; + } + statement += `export const ${withCasing(name)} = ${func}("${name}", {\n`; + statement += createTableColumns( + Object.values(columns), + withCasing, + casing, + name, + schema, + ); + statement += '})'; + + statement += algorithm ? `.algorithm("${algorithm}")` : ''; + statement += sqlSecurity ? `.sqlSecurity("${sqlSecurity}")` : ''; + statement += withCheckOption ? `.withCheckOption("${withCheckOption}")` : ''; + statement += `.as(sql\`${definition?.replaceAll('`', '\\`')}\`);`; + + return statement; + }); */ + + const uniqueSingleStoreImports = [ + 'singlestoreTable', + 'singlestoreSchema', + 'AnySingleStoreColumn', + ...new Set(imports.singlestore), + ]; + const importsTs = `import { ${ + uniqueSingleStoreImports.join( + ', ', + ) + } } from "drizzle-orm/singlestore-core"\nimport { sql } from "drizzle-orm"\n\n`; + + let decalrations = ''; + decalrations += tableStatements.join('\n\n'); + decalrations += '\n'; + /* decalrations += viewsStatements.join('\n\n'); */ + + const file = importsTs + decalrations; + + const schemaEntry = ` + { + ${ + Object.values(schema.tables) + .map((it) => withCasing(it.name)) + .join(',') + } + } + `; + + return { + file, // backward compatible, print to file + imports: importsTs, + decalrations, + schemaEntry, + }; +}; + +const mapColumnDefault = (defaultValue: any, isExpression?: boolean) => { + if (isExpression) { + return `sql\`${defaultValue}\``; + } + + return defaultValue; +}; + +const mapColumnDefaultForJson = (defaultValue: any) => { + if ( + typeof defaultValue === 'string' + && defaultValue.startsWith("('") + && defaultValue.endsWith("')") + ) { + return defaultValue.substring(2, defaultValue.length - 2); + } + + return defaultValue; +}; + +const column = ( + type: string, + name: string, + casing: (value: string) => string, + rawCasing: Casing, + defaultValue?: any, + autoincrement?: boolean, + onUpdate?: boolean, + isExpression?: boolean, +) => { + let lowered = type; + if (!type.startsWith('enum(')) { + lowered = type.toLowerCase(); + } + + if (lowered === 'serial') { + return `${casing(name)}: serial(${dbColumnName({ name, casing: rawCasing })})`; + } + + if (lowered.startsWith('int')) { + const isUnsigned = lowered.includes('unsigned'); + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: int(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' + })`; + out += autoincrement ? `.autoincrement()` : ''; + out += typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('tinyint')) { + const isUnsigned = lowered.includes('unsigned'); + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + // let out = `${name.camelCase()}: tinyint("${name}")`; + let out: string = `${casing(name)}: tinyint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' + })`; + out += autoincrement ? `.autoincrement()` : ''; + out += typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('smallint')) { + const isUnsigned = lowered.includes('unsigned'); + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: smallint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' + })`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('mediumint')) { + const isUnsigned = lowered.includes('unsigned'); + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: mediumint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' + })`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('bigint')) { + const isUnsigned = lowered.includes('unsigned'); + let out = `${casing(name)}: bigint(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: "number"${ + isUnsigned ? ', unsigned: true' : '' + } })`; + out += autoincrement ? `.autoincrement()` : ''; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'boolean') { + let out = `${casing(name)}: boolean(${dbColumnName({ name, casing: rawCasing })})`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('double')) { + let params: + | { precision?: string; scale?: string; unsigned?: boolean } + | undefined; + + if (lowered.length > (lowered.includes('unsigned') ? 15 : 6)) { + const [precision, scale] = lowered + .slice(7, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) + .split(','); + params = { precision, scale }; + } + + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + + const timeConfigParams = params ? timeConfig(params) : undefined; + + let out = params + ? `${casing(name)}: double(${ + dbColumnName({ name, casing: rawCasing, withMode: timeConfigParams !== undefined }) + }${timeConfig(params)})` + : `${casing(name)}: double(${dbColumnName({ name, casing: rawCasing })})`; + + // let out = `${name.camelCase()}: double("${name}")`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('float')) { + let params: + | { precision?: string; scale?: string; unsigned?: boolean } + | undefined; + + if (lowered.length > (lowered.includes('unsigned') ? 14 : 5)) { + const [precision, scale] = lowered + .slice(6, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) + .split(','); + params = { precision, scale }; + } + + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + + let out = `${casing(name)}: float(${dbColumnName({ name, casing: rawCasing })}${params ? timeConfig(params) : ''})`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'real') { + let out = `${casing(name)}: real(${dbColumnName({ name, casing: rawCasing })})`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('timestamp')) { + const keyLength = 'timestamp'.length + 1; + let fsp = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + fsp = fsp ? fsp : null; + + const params = timeConfig({ fsp, mode: "'string'" }); + + let out = params + ? `${casing(name)}: timestamp(${ + dbColumnName({ name, casing: rawCasing, withMode: params !== undefined }) + }${params})` + : `${casing(name)}: timestamp(${dbColumnName({ name, casing: rawCasing })})`; + + // singlestore has only CURRENT_TIMESTAMP, as I found from docs. But will leave now() for just a case + defaultValue = defaultValue === 'now()' || defaultValue === 'CURRENT_TIMESTAMP' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + + let onUpdateNow = onUpdate ? '.onUpdateNow()' : ''; + out += onUpdateNow; + + return out; + } + + if (lowered.startsWith('time')) { + const keyLength = 'time'.length + 1; + let fsp = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + fsp = fsp ? fsp : null; + + const params = timeConfig({ fsp }); + + let out = params + ? `${casing(name)}: time(${dbColumnName({ name, casing: rawCasing, withMode: params !== undefined })}${params})` + : `${casing(name)}: time(${dbColumnName({ name, casing: rawCasing })})`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered === 'date') { + let out = `// you can use { mode: 'date' }, if you want to have Date as type for this column\n\t${ + casing( + name, + ) + }: date(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: 'string' })`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + // in singlestore text can't have default value. Will leave it in case smth ;) + if (lowered === 'text') { + let out = `${casing(name)}: text(${dbColumnName({ name, casing: rawCasing })})`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in singlestore text can't have default value. Will leave it in case smth ;) + if (lowered === 'tinytext') { + let out = `${casing(name)}: tinytext(${dbColumnName({ name, casing: rawCasing })})`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in singlestore text can't have default value. Will leave it in case smth ;) + if (lowered === 'mediumtext') { + let out = `${casing(name)}: mediumtext(${dbColumnName({ name, casing: rawCasing })})`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in singlestore text can't have default value. Will leave it in case smth ;) + if (lowered === 'longtext') { + let out = `${casing(name)}: longtext(${dbColumnName({ name, casing: rawCasing })})`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered === 'year') { + let out = `${casing(name)}: year(${dbColumnName({ name, casing: rawCasing })})`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + // in singlestore json can't have default value. Will leave it in case smth ;) + if (lowered === 'json') { + let out = `${casing(name)}: json(${dbColumnName({ name, casing: rawCasing })})`; + + out += defaultValue + ? `.default(${mapColumnDefaultForJson(defaultValue)})` + : ''; + + return out; + } + + if (lowered.startsWith('varchar')) { + let out: string = `${ + casing( + name, + ) + }: varchar(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ length: ${ + lowered.substring( + 'varchar'.length + 1, + lowered.length - 1, + ) + } })`; + + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('char')) { + let out: string = `${ + casing( + name, + ) + }: char(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ length: ${ + lowered.substring( + 'char'.length + 1, + lowered.length - 1, + ) + } })`; + + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('datetime')) { + let out = `// you can use { mode: 'date' }, if you want to have Date as type for this column\n\t`; + + const fsp = lowered.startsWith('datetime(') + ? lowered.substring('datetime'.length + 1, lowered.length - 1) + : undefined; + + out = fsp + ? `${ + casing( + name, + ) + }: datetime(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: 'string', fsp: ${ + lowered.substring( + 'datetime'.length + 1, + lowered.length - 1, + ) + } })` + : `${casing(name)}: datetime(${dbColumnName({ name, casing: rawCasing, withMode: true })}{ mode: 'string'})`; + + defaultValue = defaultValue === 'now()' + ? '.defaultNow()' + : defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('decimal')) { + let params: + | { precision?: string; scale?: string; unsigned?: boolean } + | undefined; + + if (lowered.length > (lowered.includes('unsigned') ? 16 : 7)) { + const [precision, scale] = lowered + .slice(8, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) + .split(','); + params = { precision, scale }; + } + + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + + const timeConfigParams = params ? timeConfig(params) : undefined; + + let out = params + ? `${casing(name)}: decimal(${ + dbColumnName({ name, casing: rawCasing, withMode: timeConfigParams !== undefined }) + }${timeConfigParams})` + : `${casing(name)}: decimal(${dbColumnName({ name, casing: rawCasing })})`; + + defaultValue = typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('binary')) { + const keyLength = 'binary'.length + 1; + let length = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + length = length ? length : null; + + const params = binaryConfig({ length }); + + let out = params + ? `${casing(name)}: binary(${dbColumnName({ name, casing: rawCasing, withMode: params !== undefined })}${params})` + : `${casing(name)}: binary(${dbColumnName({ name, casing: rawCasing })})`; + + defaultValue = defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + if (lowered.startsWith('enum')) { + const values = lowered.substring('enum'.length + 1, lowered.length - 1); + let out = `${casing(name)}: singlestoreEnum(${ + dbColumnName({ name, casing: rawCasing, withMode: true }) + }[${values}])`; + out += defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + return out; + } + + if (lowered.startsWith('varbinary')) { + const keyLength = 'varbinary'.length + 1; + let length = lowered.length > keyLength + ? Number(lowered.substring(keyLength, lowered.length - 1)) + : null; + length = length ? length : null; + + const params = binaryConfig({ length }); + + let out = params + ? `${casing(name)}: varbinary(${ + dbColumnName({ name, casing: rawCasing, withMode: params !== undefined }) + }${params})` + : `${casing(name)}: varbinary(${dbColumnName({ name, casing: rawCasing })})`; + + defaultValue = defaultValue + ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : ''; + + out += defaultValue; + return out; + } + + console.log('uknown', type); + return `// Warning: Can't parse ${type} from database\n\t// ${type}Type: ${type}("${name}")`; +}; + +const createTableColumns = ( + columns: Column[], + casing: (val: string) => string, + rawCasing: Casing, + tableName: string, + schema: SingleStoreSchemaInternal, +): string => { + let statement = ''; + + columns.forEach((it) => { + statement += '\t'; + statement += column( + it.type, + it.name, + casing, + rawCasing, + it.default, + it.autoincrement, + it.onUpdate, + schema.internal?.tables![tableName]?.columns[it.name] + ?.isDefaultAnExpression ?? false, + ); + statement += it.primaryKey ? '.primaryKey()' : ''; + statement += it.notNull ? '.notNull()' : ''; + + statement += it.generated + ? `.generatedAlwaysAs(sql\`${ + it.generated.as.replace( + /`/g, + '\\`', + ) + }\`, { mode: "${it.generated.type}" })` + : ''; + + statement += ',\n'; + }); + + return statement; +}; + +const createTableIndexes = ( + tableName: string, + idxs: Index[], + casing: (value: string) => string, +): string => { + let statement = ''; + + idxs.forEach((it) => { + let idxKey = it.name.startsWith(tableName) && it.name !== tableName + ? it.name.slice(tableName.length + 1) + : it.name; + idxKey = idxKey.endsWith('_index') + ? idxKey.slice(0, -'_index'.length) + '_idx' + : idxKey; + + idxKey = casing(idxKey); + + const indexGeneratedName = indexName(tableName, it.columns); + const escapedIndexName = indexGeneratedName === it.name ? '' : `"${it.name}"`; + + statement += `\t\t${idxKey}: `; + statement += it.isUnique ? 'uniqueIndex(' : 'index('; + statement += `${escapedIndexName})`; + statement += `.on(${ + it.columns + .map((it) => `table.${casing(it)}`) + .join(', ') + }),`; + statement += `\n`; + }); + + return statement; +}; + +const createTableUniques = ( + unqs: UniqueConstraint[], + casing: (value: string) => string, +): string => { + let statement = ''; + + unqs.forEach((it) => { + const idxKey = casing(it.name); + + statement += `\t\t${idxKey}: `; + statement += 'unique('; + statement += `"${it.name}")`; + statement += `.on(${ + it.columns + .map((it) => `table.${casing(it)}`) + .join(', ') + }),`; + statement += `\n`; + }); + + return statement; +}; + +const createTablePKs = ( + pks: PrimaryKey[], + casing: (value: string) => string, +): string => { + let statement = ''; + + pks.forEach((it) => { + let idxKey = casing(it.name); + + statement += `\t\t${idxKey}: `; + statement += 'primaryKey({ columns: ['; + statement += `${ + it.columns + .map((c) => { + return `table.${casing(c)}`; + }) + .join(', ') + }]${it.name ? `, name: "${it.name}"` : ''}}`; + statement += '),'; + statement += `\n`; + }); + + return statement; +}; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 18b28fac4..f64020f5a 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -13,6 +13,7 @@ import { View as PgView, ViewWithOption, } from './serializer/pgSchema'; +import { SingleStoreKitInternals, SingleStoreSchema, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteKitInternals, SQLiteSchemaInternal, @@ -50,7 +51,7 @@ export interface JsonCreateTableStatement { uniqueConstraints?: string[]; policies?: string[]; checkConstraints?: string[]; - internals?: MySqlKitInternals; + internals?: MySqlKitInternals | SingleStoreKitInternals; isRLSEnabled?: boolean; } @@ -306,7 +307,7 @@ export interface JsonCreateIndexStatement { tableName: string; data: string; schema: string; - internal?: MySqlKitInternals | SQLiteKitInternals; + internal?: MySqlKitInternals | SQLiteKitInternals | SingleStoreKitInternals; } export interface JsonPgCreateIndexStatement { @@ -673,6 +674,11 @@ export type JsonCreateMySqlViewStatement = { replace: boolean; } & Omit; +/* export type JsonCreateSingleStoreViewStatement = { + type: 'singlestore_create_view'; + replace: boolean; +} & Omit; */ + export type JsonCreateSqliteViewStatement = { type: 'sqlite_create_view'; } & Omit; @@ -756,6 +762,10 @@ export type JsonAlterMySqlViewStatement = { type: 'alter_mysql_view'; } & Omit; +/* export type JsonAlterSingleStoreViewStatement = { + type: 'alter_singlestore_view'; +} & Omit; */ + export type JsonAlterViewStatement = | JsonAlterViewAlterSchemaStatement | JsonAlterViewAddWithOptionStatement @@ -838,6 +848,8 @@ export type JsonStatement = | JsonAlterViewStatement | JsonCreateMySqlViewStatement | JsonAlterMySqlViewStatement + /* | JsonCreateSingleStoreViewStatement + | JsonAlterSingleStoreViewStatement */ | JsonCreateSqliteViewStatement | JsonCreateCheckConstraint | JsonDeleteCheckConstraint @@ -906,6 +918,34 @@ export const prepareMySqlCreateTableJson = ( }; }; +export const prepareSingleStoreCreateTableJson = ( + table: Table, + // TODO: remove? + json2: SingleStoreSchema, + // we need it to know if some of the indexes(and in future other parts) are expressions or columns + // didn't change singlestoreserialaizer, because it will break snapshots and diffs and it's hard to detect + // if previously it was an expression or column + internals: SingleStoreKitInternals, +): JsonCreateTableStatement => { + const { name, schema, columns, compositePrimaryKeys, uniqueConstraints } = table; + + return { + type: 'create_table', + tableName: name, + schema, + columns: Object.values(columns), + compositePKs: Object.values(compositePrimaryKeys), + compositePkName: Object.values(compositePrimaryKeys).length > 0 + ? json2.tables[name].compositePrimaryKeys[ + SingleStoreSquasher.unsquashPK(Object.values(compositePrimaryKeys)[0]) + .name + ].name + : '', + uniqueConstraints: Object.values(uniqueConstraints), + internals, + }; +}; + export const prepareSQLiteCreateTable = ( table: Table, action?: 'push' | undefined, @@ -1207,7 +1247,7 @@ export const prepareDeleteSchemasJson = ( export const prepareRenameColumns = ( tableName: string, - // TODO: split for pg and mysql+sqlite without schema + // TODO: split for pg and mysql+sqlite and singlestore without schema schema: string, pairs: { from: Column; to: Column }[], ): JsonRenameColumnStatement[] => { @@ -1637,6 +1677,363 @@ export const prepareAlterColumnsMysql = ( return [...dropPkStatements, ...setPkStatements, ...statements]; }; +export const prepareAlterColumnsSingleStore = ( + tableName: string, + schema: string, + columns: AlteredColumn[], + // TODO: remove? + json1: CommonSquashedSchema, + json2: CommonSquashedSchema, + action?: 'push' | undefined, +): JsonAlterColumnStatement[] => { + let statements: JsonAlterColumnStatement[] = []; + let dropPkStatements: JsonAlterColumnDropPrimaryKeyStatement[] = []; + let setPkStatements: JsonAlterColumnSetPrimaryKeyStatement[] = []; + + for (const column of columns) { + const columnName = typeof column.name !== 'string' ? column.name.new : column.name; + + const table = json2.tables[tableName]; + const snapshotColumn = table.columns[columnName]; + + const columnType = snapshotColumn.type; + const columnDefault = snapshotColumn.default; + const columnOnUpdate = 'onUpdate' in snapshotColumn ? snapshotColumn.onUpdate : undefined; + const columnNotNull = table.columns[columnName].notNull; + + const columnAutoIncrement = 'autoincrement' in snapshotColumn + ? snapshotColumn.autoincrement ?? false + : false; + + const columnPk = table.columns[columnName].primaryKey; + + if (column.autoincrement?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'changed') { + const type = column.autoincrement.new + ? 'alter_table_alter_column_set_autoincrement' + : 'alter_table_alter_column_drop_autoincrement'; + + statements.push({ + type, + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.autoincrement?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_autoincrement', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + } + + for (const column of columns) { + const columnName = typeof column.name !== 'string' ? column.name.new : column.name; + + // I used any, because those fields are available only for mysql and singlestore dialect + // For other dialects it will become undefined, that is fine for json statements + const columnType = json2.tables[tableName].columns[columnName].type; + const columnDefault = json2.tables[tableName].columns[columnName].default; + const columnGenerated = json2.tables[tableName].columns[columnName].generated; + const columnOnUpdate = (json2.tables[tableName].columns[columnName] as any) + .onUpdate; + const columnNotNull = json2.tables[tableName].columns[columnName].notNull; + const columnAutoIncrement = ( + json2.tables[tableName].columns[columnName] as any + ).autoincrement; + const columnPk = (json2.tables[tableName].columns[columnName] as any) + .primaryKey; + + const compositePk = json2.tables[tableName].compositePrimaryKeys[ + `${tableName}_${columnName}` + ]; + + if (typeof column.name !== 'string') { + statements.push({ + type: 'alter_table_rename_column', + tableName, + oldColumnName: column.name.old, + newColumnName: column.name.new, + schema, + }); + } + + if (column.type?.type === 'changed') { + statements.push({ + type: 'alter_table_alter_column_set_type', + tableName, + columnName, + newDataType: column.type.new, + oldDataType: column.type.old, + schema, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if ( + column.primaryKey?.type === 'deleted' + || (column.primaryKey?.type === 'changed' + && !column.primaryKey.new + && typeof compositePk === 'undefined') + ) { + dropPkStatements.push({ + //// + type: 'alter_table_alter_column_drop_pk', + tableName, + columnName, + schema, + }); + } + + if (column.default?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_default', + tableName, + columnName, + newDefaultValue: column.default.value, + schema, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.default?.type === 'changed') { + statements.push({ + type: 'alter_table_alter_column_set_default', + tableName, + columnName, + newDefaultValue: column.default.new, + oldDefaultValue: column.default.old, + schema, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.default?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_default', + tableName, + columnName, + schema, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + newDataType: columnType, + columnPk, + }); + } + + if (column.notNull?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_notnull', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.notNull?.type === 'changed') { + const type = column.notNull.new + ? 'alter_table_alter_column_set_notnull' + : 'alter_table_alter_column_drop_notnull'; + statements.push({ + type: type, + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.notNull?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_notnull', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.generated?.type === 'added') { + if (columnGenerated?.type === 'virtual') { + // TODO: Change warning message according to SingleStore docs + warning( + `You are trying to add virtual generated constraint to ${ + chalk.blue( + columnName, + ) + } column. As MySQL docs mention: "Nongenerated columns can be altered to stored but not virtual generated columns". We will drop an existing column and add it with a virtual generated statement. This means that the data previously stored in this column will be wiped, and new data will be generated on each read for this column\n`, + ); + } + statements.push({ + type: 'alter_table_alter_column_set_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if (column.generated?.type === 'changed' && action !== 'push') { + statements.push({ + type: 'alter_table_alter_column_alter_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + }); + } + + if (column.generated?.type === 'deleted') { + if (columnGenerated?.type === 'virtual') { + // TODO: Change warning message according to SingleStore docs + warning( + `You are trying to remove virtual generated constraint from ${ + chalk.blue( + columnName, + ) + } column. As MySQL docs mention: "Stored but not virtual generated columns can be altered to nongenerated columns. The stored generated values become the values of the nongenerated column". We will drop an existing column and add it without a virtual generated statement. This means that this column will have no data after migration\n`, + ); + } + statements.push({ + type: 'alter_table_alter_column_drop_generated', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + columnGenerated, + oldColumn: json1.tables[tableName].columns[columnName], + }); + } + + if ( + column.primaryKey?.type === 'added' + || (column.primaryKey?.type === 'changed' && column.primaryKey.new) + ) { + const wasAutoincrement = statements.filter( + (it) => it.type === 'alter_table_alter_column_set_autoincrement', + ); + if (wasAutoincrement.length === 0) { + setPkStatements.push({ + type: 'alter_table_alter_column_set_pk', + tableName, + schema, + columnName, + }); + } + } + + if (column.onUpdate?.type === 'added') { + statements.push({ + type: 'alter_table_alter_column_set_on_update', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + + if (column.onUpdate?.type === 'deleted') { + statements.push({ + type: 'alter_table_alter_column_drop_on_update', + tableName, + columnName, + schema, + newDataType: columnType, + columnDefault, + columnOnUpdate, + columnNotNull, + columnAutoIncrement, + columnPk, + }); + } + } + + return [...dropPkStatements, ...setPkStatements, ...statements]; +}; + export const preparePgAlterColumns = ( _tableName: string, schema: string, @@ -2704,8 +3101,11 @@ export const prepareAddCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, + // TODO: remove? + json2: PgSchema, ): JsonCreateCompositePK[] => { return Object.values(pks).map((it) => { + const unsquashed = PgSquasher.unsquashPK(it); return { type: 'create_composite_pk', tableName, @@ -2720,6 +3120,8 @@ export const prepareDeleteCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, + // TODO: remove? + json1: PgSchema, ): JsonDeleteCompositePK[] => { return Object.values(pks).map((it) => { return { @@ -2736,6 +3138,9 @@ export const prepareAlterCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, + // TODO: remove? + json1: PgSchema, + json2: PgSchema, ): JsonAlterCompositePK[] => { return Object.values(pks).map((it) => { return { @@ -2876,7 +3281,6 @@ export const prepareDeleteCompositePrimaryKeyMySql = ( type: 'delete_composite_pk', tableName, data: it, - constraintName: unsquashed.name, } as JsonDeleteCompositePK; }); }; @@ -2945,6 +3349,24 @@ export const prepareMySqlCreateViewJson = ( }; }; +/* export const prepareSingleStoreCreateViewJson = ( + name: string, + definition: string, + meta: string, + replace: boolean = false, +): JsonCreateSingleStoreViewStatement => { + const { algorithm, sqlSecurity, withCheckOption } = SingleStoreSquasher.unsquashView(meta); + return { + type: 'singlestore_create_view', + name: name, + definition: definition, + algorithm, + sqlSecurity, + withCheckOption, + replace, + }; +}; */ + export const prepareSqliteCreateViewJson = ( name: string, definition: string, @@ -3070,3 +3492,9 @@ export const prepareMySqlAlterView = ( ): JsonAlterMySqlViewStatement => { return { type: 'alter_mysql_view', ...view }; }; + +/* export const prepareSingleStoreAlterView = ( + view: Omit, +): JsonAlterSingleStoreViewStatement => { + return { type: 'alter_singlestore_view', ...view }; +}; */ diff --git a/drizzle-kit/src/migrationPreparator.ts b/drizzle-kit/src/migrationPreparator.ts index d61f804ca..4e67e8174 100644 --- a/drizzle-kit/src/migrationPreparator.ts +++ b/drizzle-kit/src/migrationPreparator.ts @@ -1,9 +1,10 @@ import { randomUUID } from 'crypto'; import fs from 'fs'; import { CasingType } from './cli/validations/common'; -import { serializeMySql, serializePg, serializeSQLite } from './serializer'; +import { serializeMySql, serializePg, serializeSingleStore, serializeSQLite } from './serializer'; import { dryMySql, MySqlSchema, mysqlSchema } from './serializer/mysqlSchema'; import { dryPg, PgSchema, pgSchema, PgSchemaInternal } from './serializer/pgSchema'; +import { drySingleStore, SingleStoreSchema, singlestoreSchema } from './serializer/singlestoreSchema'; import { drySQLite, SQLiteSchema, sqliteSchema } from './serializer/sqliteSchema'; export const prepareMySqlDbPushSnapshot = async ( @@ -22,6 +23,22 @@ export const prepareMySqlDbPushSnapshot = async ( return { prev, cur: result }; }; +export const prepareSingleStoreDbPushSnapshot = async ( + prev: SingleStoreSchema, + schemaPath: string | string[], + casing: CasingType | undefined, +): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema }> => { + const serialized = await serializeSingleStore(schemaPath, casing); + + const id = randomUUID(); + const idPrev = prev.id; + + const { version, dialect, ...rest } = serialized; + const result: SingleStoreSchema = { version, dialect, id, prevId: idPrev, ...rest }; + + return { prev, cur: result }; +}; + export const prepareSQLiteDbPushSnapshot = async ( prev: SQLiteSchema, schemaPath: string | string[], @@ -89,6 +106,34 @@ export const prepareMySqlMigrationSnapshot = async ( return { prev: prevSnapshot, cur: result, custom }; }; +export const prepareSingleStoreMigrationSnapshot = async ( + migrationFolders: string[], + schemaPath: string | string[], + casing: CasingType | undefined, +): Promise<{ prev: SingleStoreSchema; cur: SingleStoreSchema; custom: SingleStoreSchema }> => { + const prevSnapshot = singlestoreSchema.parse( + preparePrevSnapshot(migrationFolders, drySingleStore), + ); + const serialized = await serializeSingleStore(schemaPath, casing); + + const id = randomUUID(); + const idPrev = prevSnapshot.id; + + const { version, dialect, ...rest } = serialized; + const result: SingleStoreSchema = { version, dialect, id, prevId: idPrev, ...rest }; + + const { id: _ignoredId, prevId: _ignoredPrevId, ...prevRest } = prevSnapshot; + + // that's for custom migrations, when we need new IDs, but old snapshot + const custom: SingleStoreSchema = { + id, + prevId: idPrev, + ...prevRest, + }; + + return { prev: prevSnapshot, cur: result, custom }; +}; + export const prepareSqliteMigrationSnapshot = async ( snapshots: string[], schemaPath: string | string[], diff --git a/drizzle-kit/src/schemaValidator.ts b/drizzle-kit/src/schemaValidator.ts index 6ad29a544..e91b5ab11 100644 --- a/drizzle-kit/src/schemaValidator.ts +++ b/drizzle-kit/src/schemaValidator.ts @@ -1,9 +1,10 @@ import { enum as enumType, TypeOf, union } from 'zod'; import { mysqlSchema, mysqlSchemaSquashed } from './serializer/mysqlSchema'; import { pgSchema, pgSchemaSquashed } from './serializer/pgSchema'; +import { singlestoreSchema, singlestoreSchemaSquashed } from './serializer/singlestoreSchema'; import { sqliteSchema, SQLiteSchemaSquashed } from './serializer/sqliteSchema'; -export const dialects = ['postgresql', 'mysql', 'sqlite', 'turso'] as const; +export const dialects = ['postgresql', 'mysql', 'sqlite', 'turso', 'singlestore'] as const; export const dialect = enumType(dialects); export type Dialect = (typeof dialects)[number]; @@ -13,9 +14,10 @@ const commonSquashedSchema = union([ pgSchemaSquashed, mysqlSchemaSquashed, SQLiteSchemaSquashed, + singlestoreSchemaSquashed, ]); -const commonSchema = union([pgSchema, mysqlSchema, sqliteSchema]); +const commonSchema = union([pgSchema, mysqlSchema, sqliteSchema, singlestoreSchema]); export type CommonSquashedSchema = TypeOf; export type CommonSchema = TypeOf; diff --git a/drizzle-kit/src/serializer/index.ts b/drizzle-kit/src/serializer/index.ts index cf2ee625a..d24afbab0 100644 --- a/drizzle-kit/src/serializer/index.ts +++ b/drizzle-kit/src/serializer/index.ts @@ -6,6 +6,7 @@ import { CasingType } from 'src/cli/validations/common'; import { error } from '../cli/views'; import type { MySqlSchemaInternal } from './mysqlSchema'; import type { PgSchemaInternal } from './pgSchema'; +import { SingleStoreSchemaInternal } from './singlestoreSchema'; import type { SQLiteSchemaInternal } from './sqliteSchema'; export const serializeMySql = async ( @@ -53,6 +54,22 @@ export const serializeSQLite = async ( return generateSqliteSnapshot(tables, views, casing); }; +export const serializeSingleStore = async ( + path: string | string[], + casing: CasingType | undefined, +): Promise => { + const filenames = prepareFilenames(path); + + console.log(chalk.gray(`Reading schema files:\n${filenames.join('\n')}\n`)); + + const { prepareFromSingleStoreImports } = await import('./singlestoreImports'); + const { generateSingleStoreSnapshot } = await import('./singlestoreSerializer'); + + const { tables /* views */ } = await prepareFromSingleStoreImports(filenames); + + return generateSingleStoreSnapshot(tables, /* views, */ casing); +}; + export const prepareFilenames = (path: string | string[]) => { if (typeof path === 'string') { path = [path]; diff --git a/drizzle-kit/src/serializer/singlestoreImports.ts b/drizzle-kit/src/serializer/singlestoreImports.ts new file mode 100644 index 000000000..23c2d66a9 --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreImports.ts @@ -0,0 +1,38 @@ +import { is } from 'drizzle-orm'; +import { AnySingleStoreTable, SingleStoreTable } from 'drizzle-orm/singlestore-core'; +import { safeRegister } from '../cli/commands/utils'; + +export const prepareFromExports = (exports: Record) => { + const tables: AnySingleStoreTable[] = []; + /* const views: SingleStoreView[] = []; */ + + const i0values = Object.values(exports); + i0values.forEach((t) => { + if (is(t, SingleStoreTable)) { + tables.push(t); + } + + /* if (is(t, SingleStoreView)) { + views.push(t); + } */ + }); + + return { tables /* views */ }; +}; + +export const prepareFromSingleStoreImports = async (imports: string[]) => { + const tables: AnySingleStoreTable[] = []; + /* const views: SingleStoreView[] = []; */ + + const { unregister } = await safeRegister(); + for (let i = 0; i < imports.length; i++) { + const it = imports[i]; + const i0: Record = require(`${it}`); + const prepared = prepareFromExports(i0); + + tables.push(...prepared.tables); + /* views.push(...prepared.views); */ + } + unregister(); + return { tables: Array.from(new Set(tables)) /* , views */ }; +}; diff --git a/drizzle-kit/src/serializer/singlestoreSchema.ts b/drizzle-kit/src/serializer/singlestoreSchema.ts new file mode 100644 index 000000000..9ff45ef5a --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreSchema.ts @@ -0,0 +1,257 @@ +import { any, boolean, enum as enumType, literal, object, record, string, TypeOf, union } from 'zod'; +import { mapValues, originUUID, snapshotVersion } from '../global'; + +// ------- V3 -------- +const index = object({ + name: string(), + columns: string().array(), + isUnique: boolean(), + using: enumType(['btree', 'hash']).optional(), + algorithm: enumType(['default', 'inplace', 'copy']).optional(), + lock: enumType(['default', 'none', 'shared', 'exclusive']).optional(), +}).strict(); + +const column = object({ + name: string(), + type: string(), + primaryKey: boolean(), + notNull: boolean(), + autoincrement: boolean().optional(), + default: any().optional(), + onUpdate: any().optional(), + generated: object({ + type: enumType(['stored', 'virtual']), + as: string(), + }).optional(), +}).strict(); + +const compositePK = object({ + name: string(), + columns: string().array(), +}).strict(); + +const uniqueConstraint = object({ + name: string(), + columns: string().array(), +}).strict(); + +const table = object({ + name: string(), + columns: record(string(), column), + indexes: record(string(), index), + compositePrimaryKeys: record(string(), compositePK), + uniqueConstraints: record(string(), uniqueConstraint).default({}), +}).strict(); + +const viewMeta = object({ + algorithm: enumType(['undefined', 'merge', 'temptable']), + sqlSecurity: enumType(['definer', 'invoker']), + withCheckOption: enumType(['local', 'cascaded']).optional(), +}).strict(); + +/* export const view = object({ + name: string(), + columns: record(string(), column), + definition: string().optional(), + isExisting: boolean(), +}).strict().merge(viewMeta); +type SquasherViewMeta = Omit, 'definer'>; */ + +export const kitInternals = object({ + tables: record( + string(), + object({ + columns: record( + string(), + object({ isDefaultAnExpression: boolean().optional() }).optional(), + ), + }).optional(), + ).optional(), + indexes: record( + string(), + object({ + columns: record( + string(), + object({ isExpression: boolean().optional() }).optional(), + ), + }).optional(), + ).optional(), +}).optional(); + +// use main dialect +const dialect = literal('singlestore'); + +const schemaHash = object({ + id: string(), + prevId: string(), +}); + +export const schemaInternal = object({ + version: literal('1'), + dialect: dialect, + tables: record(string(), table), + /* views: record(string(), view).default({}), */ + _meta: object({ + tables: record(string(), string()), + columns: record(string(), string()), + }), + internal: kitInternals, +}).strict(); + +export const schema = schemaInternal.merge(schemaHash); + +const tableSquashed = object({ + name: string(), + columns: record(string(), column), + indexes: record(string(), string()), + compositePrimaryKeys: record(string(), string()), + uniqueConstraints: record(string(), string()).default({}), +}).strict(); + +/* const viewSquashed = view.omit({ + algorithm: true, + sqlSecurity: true, + withCheckOption: true, +}).extend({ meta: string() }); */ + +export const schemaSquashed = object({ + version: literal('1'), + dialect: dialect, + tables: record(string(), tableSquashed), + /* views: record(string(), viewSquashed), */ +}).strict(); + +export type Dialect = TypeOf; +export type Column = TypeOf; +export type Table = TypeOf; +export type SingleStoreSchema = TypeOf; +export type SingleStoreSchemaInternal = TypeOf; +export type SingleStoreKitInternals = TypeOf; +export type SingleStoreSchemaSquashed = TypeOf; +export type Index = TypeOf; +export type PrimaryKey = TypeOf; +export type UniqueConstraint = TypeOf; +/* export type View = TypeOf; */ +/* export type ViewSquashed = TypeOf; */ + +export const SingleStoreSquasher = { + squashIdx: (idx: Index) => { + index.parse(idx); + return `${idx.name};${idx.columns.join(',')};${idx.isUnique};${idx.using ?? ''};${idx.algorithm ?? ''};${ + idx.lock ?? '' + }`; + }, + unsquashIdx: (input: string): Index => { + const [name, columnsString, isUnique, using, algorithm, lock] = input.split(';'); + const destructed = { + name, + columns: columnsString.split(','), + isUnique: isUnique === 'true', + using: using ? using : undefined, + algorithm: algorithm ? algorithm : undefined, + lock: lock ? lock : undefined, + }; + return index.parse(destructed); + }, + squashPK: (pk: PrimaryKey) => { + return `${pk.name};${pk.columns.join(',')}`; + }, + unsquashPK: (pk: string): PrimaryKey => { + const splitted = pk.split(';'); + return { name: splitted[0], columns: splitted[1].split(',') }; + }, + squashUnique: (unq: UniqueConstraint) => { + return `${unq.name};${unq.columns.join(',')}`; + }, + unsquashUnique: (unq: string): UniqueConstraint => { + const [name, columns] = unq.split(';'); + return { name, columns: columns.split(',') }; + }, + /* squashView: (view: View): string => { + return `${view.algorithm};${view.sqlSecurity};${view.withCheckOption}`; + }, + unsquashView: (meta: string): SquasherViewMeta => { + const [algorithm, sqlSecurity, withCheckOption] = meta.split(';'); + const toReturn = { + algorithm: algorithm, + sqlSecurity: sqlSecurity, + withCheckOption: withCheckOption !== 'undefined' ? withCheckOption : undefined, + }; + + return viewMeta.parse(toReturn); + }, */ +}; + +export const squashSingleStoreScheme = (json: SingleStoreSchema): SingleStoreSchemaSquashed => { + const mappedTables = Object.fromEntries( + Object.entries(json.tables).map((it) => { + const squashedIndexes = mapValues(it[1].indexes, (index) => { + return SingleStoreSquasher.squashIdx(index); + }); + + const squashedPKs = mapValues(it[1].compositePrimaryKeys, (pk) => { + return SingleStoreSquasher.squashPK(pk); + }); + + const squashedUniqueConstraints = mapValues( + it[1].uniqueConstraints, + (unq) => { + return SingleStoreSquasher.squashUnique(unq); + }, + ); + + return [ + it[0], + { + name: it[1].name, + columns: it[1].columns, + indexes: squashedIndexes, + compositePrimaryKeys: squashedPKs, + uniqueConstraints: squashedUniqueConstraints, + }, + ]; + }), + ); + + /* const mappedViews = Object.fromEntries( + Object.entries(json.views).map(([key, value]) => { + const meta = SingleStoreSquasher.squashView(value); + + return [key, { + name: value.name, + isExisting: value.isExisting, + columns: value.columns, + definition: value.definition, + meta, + }]; + }), + ); */ + + return { + version: '1', + dialect: json.dialect, + tables: mappedTables, + /* views: mappedViews, */ + }; +}; + +export const singlestoreSchema = schema; +export const singlestoreSchemaSquashed = schemaSquashed; + +// no prev version +export const backwardCompatibleSingleStoreSchema = union([singlestoreSchema, schema]); + +export const drySingleStore = singlestoreSchema.parse({ + version: '1', + dialect: 'singlestore', + id: originUUID, + prevId: '', + tables: {}, + schemas: {}, + /* views: {}, */ + _meta: { + schemas: {}, + tables: {}, + columns: {}, + }, +}); diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts new file mode 100644 index 000000000..e8c89f1d1 --- /dev/null +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -0,0 +1,767 @@ +import chalk from 'chalk'; +import { is, SQL } from 'drizzle-orm'; +import { + AnySingleStoreTable, + getTableConfig, + type PrimaryKey as PrimaryKeyORM, + SingleStoreDialect, + uniqueKeyName, +} from 'drizzle-orm/singlestore-core'; +import { RowDataPacket } from 'mysql2/promise'; +import { withStyle } from '../cli/validations/outputs'; +import { IntrospectStage, IntrospectStatus } from '../cli/views'; + +import { CasingType } from 'src/cli/validations/common'; +import type { DB } from '../utils'; +import { + Column, + Index, + PrimaryKey, + SingleStoreKitInternals, + SingleStoreSchemaInternal, + Table, + UniqueConstraint, +} from './singlestoreSchema'; +import { sqlToStr } from './utils'; + +const dialect = new SingleStoreDialect(); + +export const indexName = (tableName: string, columns: string[]) => { + return `${tableName}_${columns.join('_')}_index`; +}; + +export const generateSingleStoreSnapshot = ( + tables: AnySingleStoreTable[], + /* views: SingleStoreView[], */ + casing: CasingType | undefined, +): SingleStoreSchemaInternal => { + const dialect = new SingleStoreDialect({ casing }); + const result: Record = {}; + /* const resultViews: Record = {}; */ + const internal: SingleStoreKitInternals = { tables: {}, indexes: {} }; + for (const table of tables) { + const { + name: tableName, + columns, + indexes, + schema, + primaryKeys, + uniqueConstraints, + } = getTableConfig(table); + const columnsObject: Record = {}; + const indexesObject: Record = {}; + const primaryKeysObject: Record = {}; + const uniqueConstraintObject: Record = {}; + + columns.forEach((column) => { + const notNull: boolean = column.notNull; + const sqlTypeLowered = column.getSQLType().toLowerCase(); + const autoIncrement = typeof (column as any).autoIncrement === 'undefined' + ? false + : (column as any).autoIncrement; + + const generated = column.generated; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + primaryKey: false, + // If field is autoincrement it's notNull by default + // notNull: autoIncrement ? true : notNull, + notNull, + autoincrement: autoIncrement, + onUpdate: (column as any).hasOnUpdateNow, + generated: generated + ? { + as: is(generated.as, SQL) + ? dialect.sqlToQuery(generated.as as SQL).sql + : typeof generated.as === 'function' + ? dialect.sqlToQuery(generated.as() as SQL).sql + : (generated.as as any), + type: generated.mode ?? 'stored', + } + : undefined, + }; + + if (column.primary) { + primaryKeysObject[`${tableName}_${column.name}`] = { + name: `${tableName}_${column.name}`, + columns: [column.name], + }; + } + + if (column.isUnique) { + const existingUnique = uniqueConstraintObject[column.uniqueName!]; + if (typeof existingUnique !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning(`We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. + The unique constraint ${ + chalk.underline.blue( + column.uniqueName, + ) + } on the ${ + chalk.underline.blue( + column.name, + ) + } column is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`) + }`, + ); + process.exit(1); + } + uniqueConstraintObject[column.uniqueName!] = { + name: column.uniqueName!, + columns: [columnToSet.name], + }; + } + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default, casing); + } else { + if (typeof column.default === 'string') { + columnToSet.default = `'${column.default}'`; + } else { + if (sqlTypeLowered === 'json') { + columnToSet.default = `'${JSON.stringify(column.default)}'`; + } else if (column.default instanceof Date) { + if (sqlTypeLowered === 'date') { + columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; + } else if ( + sqlTypeLowered.startsWith('datetime') + || sqlTypeLowered.startsWith('timestamp') + ) { + columnToSet.default = `'${ + column.default + .toISOString() + .replace('T', ' ') + .slice(0, 23) + }'`; + } + } else { + columnToSet.default = column.default; + } + } + // if (['blob', 'text', 'json'].includes(column.getSQLType())) { + // columnToSet.default = `(${columnToSet.default})`; + // } + } + } + columnsObject[column.name] = columnToSet; + }); + + primaryKeys.map((pk: PrimaryKeyORM) => { + const columnNames = pk.columns.map((c: any) => c.name); + primaryKeysObject[pk.getName()] = { + name: pk.getName(), + columns: columnNames, + }; + + // all composite pk's should be treated as notNull + for (const column of pk.columns) { + columnsObject[column.name].notNull = true; + } + }); + + uniqueConstraints?.map((unq) => { + const columnNames = unq.columns.map((c) => c.name); + + const name = unq.name ?? uniqueKeyName(table, columnNames); + + const existingUnique = uniqueConstraintObject[name]; + if (typeof existingUnique !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. \nThe unique constraint ${ + chalk.underline.blue( + name, + ) + } on the ${ + chalk.underline.blue( + columnNames.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + existingUnique.columns.join(','), + ) + } columns\n`, + ) + }`, + ); + process.exit(1); + } + + uniqueConstraintObject[name] = { + name: unq.name!, + columns: columnNames, + }; + }); + + indexes.forEach((value) => { + const columns = value.config.columns; + const name = value.config.name; + + let indexColumns = columns.map((it) => { + if (is(it, SQL)) { + const sql = dialect.sqlToQuery(it, 'indexes').sql; + if (typeof internal!.indexes![name] === 'undefined') { + internal!.indexes![name] = { + columns: { + [sql]: { + isExpression: true, + }, + }, + }; + } else { + if (typeof internal!.indexes![name]?.columns[sql] === 'undefined') { + internal!.indexes![name]!.columns[sql] = { + isExpression: true, + }; + } else { + internal!.indexes![name]!.columns[sql]!.isExpression = true; + } + } + return sql; + } else { + return `${it.name}`; + } + }); + + if (value.config.unique) { + if (typeof uniqueConstraintObject[name] !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated unique constraint names in ${ + chalk.underline.blue( + tableName, + ) + } table. \nThe unique index ${ + chalk.underline.blue( + name, + ) + } on the ${ + chalk.underline.blue( + indexColumns.join(','), + ) + } columns is confilcting with a unique constraint name already defined for ${ + chalk.underline.blue( + uniqueConstraintObject[name].columns.join(','), + ) + } columns\n`, + ) + }`, + ); + process.exit(1); + } + } + + indexesObject[name] = { + name, + columns: indexColumns, + isUnique: value.config.unique ?? false, + using: value.config.using, + algorithm: value.config.algorythm, + lock: value.config.lock, + }; + }); + + // only handle tables without schemas + if (!schema) { + result[tableName] = { + name: tableName, + columns: columnsObject, + indexes: indexesObject, + compositePrimaryKeys: primaryKeysObject, + uniqueConstraints: uniqueConstraintObject, + }; + } + } + + /* for (const view of views) { + const { + isExisting, + name, + query, + schema, + selectedFields, + algorithm, + sqlSecurity, + withCheckOption, + } = getViewConfig(view); + + const columnsObject: Record = {}; + + const existingView = resultViews[name]; + if (typeof existingView !== 'undefined') { + console.log( + `\n${ + withStyle.errorWarning( + `We\'ve found duplicated view name across ${ + chalk.underline.blue( + schema ?? 'public', + ) + } schema. Please rename your view`, + ) + }`, + ); + process.exit(1); + } + for (const key in selectedFields) { + if (is(selectedFields[key], SingleStoreColumn)) { + const column = selectedFields[key]; + + const notNull: boolean = column.notNull; + const sqlTypeLowered = column.getSQLType().toLowerCase(); + const autoIncrement = typeof (column as any).autoIncrement === 'undefined' + ? false + : (column as any).autoIncrement; + + const generated = column.generated; + + const columnToSet: Column = { + name: column.name, + type: column.getSQLType(), + primaryKey: false, + // If field is autoincrement it's notNull by default + // notNull: autoIncrement ? true : notNull, + notNull, + autoincrement: autoIncrement, + onUpdate: (column as any).hasOnUpdateNow, + generated: generated + ? { + as: is(generated.as, SQL) + ? dialect.sqlToQuery(generated.as as SQL).sql + : typeof generated.as === 'function' + ? dialect.sqlToQuery(generated.as() as SQL).sql + : (generated.as as any), + type: generated.mode ?? 'stored', + } + : undefined, + }; + + if (column.default !== undefined) { + if (is(column.default, SQL)) { + columnToSet.default = sqlToStr(column.default, casing); + } else { + if (typeof column.default === 'string') { + columnToSet.default = `'${column.default}'`; + } else { + if (sqlTypeLowered === 'json') { + columnToSet.default = `'${JSON.stringify(column.default)}'`; + } else if (column.default instanceof Date) { + if (sqlTypeLowered === 'date') { + columnToSet.default = `'${column.default.toISOString().split('T')[0]}'`; + } else if ( + sqlTypeLowered.startsWith('datetime') + || sqlTypeLowered.startsWith('timestamp') + ) { + columnToSet.default = `'${ + column.default + .toISOString() + .replace('T', ' ') + .slice(0, 23) + }'`; + } + } else { + columnToSet.default = column.default; + } + } + } + } + columnsObject[column.name] = columnToSet; + } + } + + resultViews[name] = { + columns: columnsObject, + name, + isExisting, + definition: isExisting ? undefined : dialect.sqlToQuery(query!).sql, + withCheckOption, + algorithm: algorithm ?? 'undefined', // set default values + sqlSecurity: sqlSecurity ?? 'definer', // set default values + }; + } */ + + return { + version: '1', + dialect: 'singlestore', + tables: result, + /* views: resultViews, */ + _meta: { + tables: {}, + columns: {}, + }, + internal, + }; +}; + +function clearDefaults(defaultValue: any, collate: string) { + if (typeof collate === 'undefined' || collate === null) { + collate = `utf8mb4`; + } + + let resultDefault = defaultValue; + collate = `_${collate}`; + if (defaultValue.startsWith(collate)) { + resultDefault = resultDefault + .substring(collate.length, defaultValue.length) + .replace(/\\/g, ''); + if (resultDefault.startsWith("'") && resultDefault.endsWith("'")) { + return `('${resultDefault.substring(1, resultDefault.length - 1)}')`; + } else { + return `'${resultDefault}'`; + } + } else { + return `(${resultDefault})`; + } +} + +export const fromDatabase = async ( + db: DB, + inputSchema: string, + tablesFilter: (table: string) => boolean = (table) => true, + progressCallback?: ( + stage: IntrospectStage, + count: number, + status: IntrospectStatus, + ) => void, +): Promise => { + const result: Record = {}; + const internals: SingleStoreKitInternals = { tables: {}, indexes: {} }; + + const columns = await db.query(`select * from information_schema.columns + where table_schema = '${inputSchema}' and table_name != '__drizzle_migrations' + order by table_name, ordinal_position;`); + + const response = columns as RowDataPacket[]; + + const schemas: string[] = []; + + let columnsCount = 0; + let tablesCount = new Set(); + let indexesCount = 0; + /* let viewsCount = 0; */ + + const idxs = await db.query( + `select * from INFORMATION_SCHEMA.STATISTICS + WHERE INFORMATION_SCHEMA.STATISTICS.TABLE_SCHEMA = '${inputSchema}' and INFORMATION_SCHEMA.STATISTICS.INDEX_NAME != 'PRIMARY';`, + ); + + const idxRows = idxs as RowDataPacket[]; + + for (const column of response) { + if (!tablesFilter(column['TABLE_NAME'] as string)) continue; + + columnsCount += 1; + if (progressCallback) { + progressCallback('columns', columnsCount, 'fetching'); + } + const schema: string = column['TABLE_SCHEMA']; + const tableName = column['TABLE_NAME']; + + tablesCount.add(`${schema}.${tableName}`); + if (progressCallback) { + progressCallback('columns', tablesCount.size, 'fetching'); + } + const columnName: string = column['COLUMN_NAME']; + const isNullable = column['IS_NULLABLE'] === 'YES'; // 'YES', 'NO' + const dataType = column['DATA_TYPE']; // varchar + const columnType = column['COLUMN_TYPE']; // varchar(256) + // const columnType = column["DATA_TYPE"]; + const isPrimary = column['COLUMN_KEY'] === 'PRI'; // 'PRI', '' + let columnDefault: string | null = column['COLUMN_DEFAULT']; + const collation: string = column['CHARACTER_SET_NAME']; + const geenratedExpression: string = column['GENERATION_EXPRESSION']; + + let columnExtra = column['EXTRA']; + let isAutoincrement = false; // 'auto_increment', '' + let isDefaultAnExpression = false; // 'auto_increment', '' + + if (typeof column['EXTRA'] !== 'undefined') { + columnExtra = column['EXTRA']; + isAutoincrement = column['EXTRA'] === 'auto_increment'; // 'auto_increment', '' + isDefaultAnExpression = column['EXTRA'].includes('DEFAULT_GENERATED'); // 'auto_increment', '' + } + + // if (isPrimary) { + // if (typeof tableToPk[tableName] === "undefined") { + // tableToPk[tableName] = [columnName]; + // } else { + // tableToPk[tableName].push(columnName); + // } + // } + + if (schema !== inputSchema) { + schemas.push(schema); + } + + const table = result[tableName]; + + // let changedType = columnType.replace("bigint unsigned", "serial") + let changedType = columnType; + + if (columnType === 'bigint unsigned' && !isNullable && isAutoincrement) { + // check unique here + const uniqueIdx = idxRows.filter( + (it) => + it['COLUMN_NAME'] === columnName + && it['TABLE_NAME'] === tableName + && it['NON_UNIQUE'] === 0, + ); + if (uniqueIdx && uniqueIdx.length === 1) { + changedType = columnType.replace('bigint unsigned', 'serial'); + } + } + + if ( + columnType.startsWith('bigint(') + || columnType.startsWith('tinyint(') + || columnType.startsWith('date(') + || columnType.startsWith('int(') + || columnType.startsWith('mediumint(') + || columnType.startsWith('smallint(') + || columnType.startsWith('text(') + || columnType.startsWith('time(') + || columnType.startsWith('year(') + ) { + changedType = columnType.replace(/\(\s*[^)]*\)$/, ''); + } + + if (columnType.includes('decimal(10,0)')) { + changedType = columnType.replace('decimal(10,0)', 'decimal'); + } + + if (columnDefault?.endsWith('.')) { + columnDefault = columnDefault.slice(0, -1); + } + + let onUpdate: boolean | undefined = undefined; + if ( + columnType.startsWith('timestamp') + && typeof columnExtra !== 'undefined' + && columnExtra.includes('on update CURRENT_TIMESTAMP') + ) { + onUpdate = true; + } + + const newColumn: Column = { + default: columnDefault === null + ? undefined + : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) + && !['decimal', 'char', 'varchar'].some((type) => columnType.startsWith(type)) + ? Number(columnDefault) + : isDefaultAnExpression + ? clearDefaults(columnDefault, collation) + : columnDefault.startsWith('CURRENT_TIMESTAMP') + ? 'CURRENT_TIMESTAMP' + : `'${columnDefault}'`, + autoincrement: isAutoincrement, + name: columnName, + type: changedType, + primaryKey: false, + notNull: !isNullable, + onUpdate, + generated: geenratedExpression + ? { + as: geenratedExpression, + type: columnExtra === 'VIRTUAL GENERATED' ? 'virtual' : 'stored', + } + : undefined, + }; + + // Set default to internal object + if (isDefaultAnExpression) { + if (typeof internals!.tables![tableName] === 'undefined') { + internals!.tables![tableName] = { + columns: { + [columnName]: { + isDefaultAnExpression: true, + }, + }, + }; + } else { + if ( + typeof internals!.tables![tableName]!.columns[columnName] + === 'undefined' + ) { + internals!.tables![tableName]!.columns[columnName] = { + isDefaultAnExpression: true, + }; + } else { + internals!.tables![tableName]!.columns[ + columnName + ]!.isDefaultAnExpression = true; + } + } + } + + if (!table) { + result[tableName] = { + name: tableName, + columns: { + [columnName]: newColumn, + }, + compositePrimaryKeys: {}, + indexes: {}, + uniqueConstraints: {}, + }; + } else { + result[tableName]!.columns[columnName] = newColumn; + } + } + + const tablePks = await db.query( + `SELECT table_name, column_name, ordinal_position + FROM information_schema.table_constraints t + LEFT JOIN information_schema.key_column_usage k + USING(constraint_name,table_schema,table_name) + WHERE t.constraint_type='UNIQUE' + and table_name != '__drizzle_migrations' + AND t.table_schema = '${inputSchema}' + ORDER BY ordinal_position`, + ); + + const tableToPk: { [tname: string]: string[] } = {}; + + const tableToPkRows = tablePks as RowDataPacket[]; + for (const tableToPkRow of tableToPkRows) { + const tableName: string = tableToPkRow['table_name']; + const columnName: string = tableToPkRow['column_name']; + const position: string = tableToPkRow['ordinal_position']; + + if (typeof result[tableName] === 'undefined') { + continue; + } + + if (typeof tableToPk[tableName] === 'undefined') { + tableToPk[tableName] = [columnName]; + } else { + tableToPk[tableName].push(columnName); + } + } + + for (const [key, value] of Object.entries(tableToPk)) { + // if (value.length > 1) { + result[key].compositePrimaryKeys = { + [`${key}_${value.join('_')}`]: { + name: `${key}_${value.join('_')}`, + columns: value, + }, + }; + // } else if (value.length === 1) { + // result[key].columns[value[0]].primaryKey = true; + // } else { + // } + } + if (progressCallback) { + progressCallback('columns', columnsCount, 'done'); + progressCallback('tables', tablesCount.size, 'done'); + } + + for (const idxRow of idxRows) { + const tableSchema = idxRow['TABLE_SCHEMA']; + const tableName = idxRow['TABLE_NAME']; + const constraintName = idxRow['INDEX_NAME']; + const columnName: string = idxRow['COLUMN_NAME']; + const isUnique = idxRow['NON_UNIQUE'] === 0; + + const tableInResult = result[tableName]; + if (typeof tableInResult === 'undefined') continue; + + // if (tableInResult.columns[columnName].type === "serial") continue; + + indexesCount += 1; + if (progressCallback) { + progressCallback('indexes', indexesCount, 'fetching'); + } + + if (isUnique) { + if ( + typeof tableInResult.uniqueConstraints[constraintName] !== 'undefined' + ) { + tableInResult.uniqueConstraints[constraintName]!.columns.push( + columnName, + ); + } else { + tableInResult.uniqueConstraints[constraintName] = { + name: constraintName, + columns: [columnName], + }; + } + } + } + + /* const views = await db.query( + `select * from INFORMATION_SCHEMA.VIEWS WHERE table_schema = '${inputSchema}';`, + ); */ + + /* const resultViews: Record = {}; */ + + /* viewsCount = views.length; + if (progressCallback) { + progressCallback('views', viewsCount, 'fetching'); + } + for await (const view of views) { + const viewName = view['TABLE_NAME']; + const definition = view['VIEW_DEFINITION']; + + const withCheckOption = view['CHECK_OPTION'] === 'NONE' + ? undefined + : view['CHECK_OPTION'].toLowerCase(); + const sqlSecurity = view['SECURITY_TYPE'].toLowerCase(); + + const [createSqlStatement] = await db.query( + `SHOW CREATE VIEW \`${viewName}\`;`, + ); + const algorithmMatch = createSqlStatement['Create View'].match(/ALGORITHM=([^ ]+)/); + const algorithm = algorithmMatch + ? algorithmMatch[1].toLowerCase() + : undefined; + + const columns = result[viewName].columns; + delete result[viewName]; + + resultViews[viewName] = { + columns: columns, + isExisting: false, + name: viewName, + algorithm, + definition, + sqlSecurity, + withCheckOption, + }; + } */ + + if (progressCallback) { + progressCallback('indexes', indexesCount, 'done'); + // progressCallback("enums", 0, "fetching"); + progressCallback('enums', 0, 'done'); + } + + return { + version: '1', + dialect: 'singlestore', + tables: result, + /* views: resultViews, */ + _meta: { + tables: {}, + columns: {}, + }, + internal: internals, + }; +}; diff --git a/drizzle-kit/src/serializer/studio.ts b/drizzle-kit/src/serializer/studio.ts index d83a65b08..bbd811627 100644 --- a/drizzle-kit/src/serializer/studio.ts +++ b/drizzle-kit/src/serializer/studio.ts @@ -15,6 +15,11 @@ import { } from 'drizzle-orm'; import { AnyMySqlTable, getTableConfig as mysqlTableConfig, MySqlTable } from 'drizzle-orm/mysql-core'; import { AnyPgTable, getTableConfig as pgTableConfig, PgTable } from 'drizzle-orm/pg-core'; +import { + AnySingleStoreTable, + getTableConfig as singlestoreTableConfig, + SingleStoreTable, +} from 'drizzle-orm/singlestore-core'; import { AnySQLiteTable, getTableConfig as sqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; import fs from 'fs'; import { Hono } from 'hono'; @@ -28,6 +33,7 @@ import { z } from 'zod'; import { safeRegister } from '../cli/commands/utils'; import type { MysqlCredentials } from '../cli/validations/mysql'; import type { PostgresCredentials } from '../cli/validations/postgres'; +import type { SingleStoreCredentials } from '../cli/validations/singlestore'; import type { SqliteCredentials } from '../cli/validations/sqlite'; import { prepareFilenames } from '.'; @@ -45,7 +51,7 @@ type SchemaFile = { export type Setup = { dbHash: string; - dialect: 'postgresql' | 'mysql' | 'sqlite'; + dialect: 'postgresql' | 'mysql' | 'sqlite' | 'singlestore'; driver?: 'aws-data-api' | 'd1-http' | 'turso' | 'pglite'; proxy: (params: ProxyParams) => Promise; customDefaults: CustomDefault[]; @@ -172,6 +178,43 @@ export const prepareSQLiteSchema = async (path: string | string[]) => { return { schema: sqliteSchema, relations, files }; }; +export const prepareSingleStoreSchema = async (path: string | string[]) => { + const imports = prepareFilenames(path); + const singlestoreSchema: Record> = { + public: {}, + }; + const relations: Record = {}; + + // files content as string + const files = imports.map((it, index) => ({ + // get the file name from the path + name: it.split('/').pop() || `schema${index}.ts`, + content: fs.readFileSync(it, 'utf-8'), + })); + + const { unregister } = await safeRegister(); + for (let i = 0; i < imports.length; i++) { + const it = imports[i]; + + const i0: Record = require(`${it}`); + const i0values = Object.entries(i0); + + i0values.forEach(([k, t]) => { + if (is(t, SingleStoreTable)) { + const schema = singlestoreTableConfig(t).schema || 'public'; + singlestoreSchema[schema][k] = t; + } + + if (is(t, Relations)) { + relations[k] = t; + } + }); + } + unregister(); + + return { schema: singlestoreSchema, relations, files }; +}; + const getCustomDefaults = >( schema: Record>, ): CustomDefault[] => { @@ -187,8 +230,10 @@ const getCustomDefaults = >( tableConfig = pgTableConfig(table); } else if (is(table, MySqlTable)) { tableConfig = mysqlTableConfig(table); - } else { + } else if (is(table, SQLiteTable)) { tableConfig = sqliteTableConfig(table); + } else { + tableConfig = singlestoreTableConfig(table); } tableConfig.columns.map((column) => { @@ -346,6 +391,39 @@ export const drizzleForLibSQL = async ( }; }; +export const drizzleForSingleStore = async ( + credentials: SingleStoreCredentials, + singlestoreSchema: Record>, + relations: Record, + schemaFiles?: SchemaFile[], +): Promise => { + const { connectToSingleStore } = await import('../cli/connections'); + const { proxy } = await connectToSingleStore(credentials); + + const customDefaults = getCustomDefaults(singlestoreSchema); + + let dbUrl: string; + + if ('url' in credentials) { + dbUrl = credentials.url; + } else { + dbUrl = + `singlestore://${credentials.user}:${credentials.password}@${credentials.host}:${credentials.port}/${credentials.database}`; + } + + const dbHash = createHash('sha256').update(dbUrl).digest('hex'); + + return { + dbHash, + dialect: 'singlestore', + proxy, + customDefaults, + schema: singlestoreSchema, + relations, + schemaFiles, + }; +}; + export const extractRelations = (tablesConfig: { tables: TablesRelationalConfig; tableNamesMap: Record; @@ -371,6 +449,8 @@ export const extractRelations = (tablesConfig: { refSchema = mysqlTableConfig(refTable).schema; } else if (is(refTable, SQLiteTable)) { refSchema = undefined; + } else if (is(refTable, SingleStoreTable)) { + refSchema = singlestoreTableConfig(refTable).schema; } else { throw new Error('unsupported dialect'); } diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index 060f12bbd..2db4ad02c 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -117,6 +117,7 @@ import { prepareRenameSequenceJson, prepareRenameTableJson, prepareRenameViewJson, + prepareSingleStoreCreateTableJson, prepareSqliteAlterColumns, prepareSQLiteCreateTable, prepareSqliteCreateViewJson, @@ -131,12 +132,14 @@ import { PgSchemaSquashed, PgSquasher, Policy, + policy, policySquashed, Role, roleSchema, sequenceSquashed, View, } from './serializer/pgSchema'; +import { SingleStoreSchema, SingleStoreSchemaSquashed, SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchema, SQLiteSchemaSquashed, SQLiteSquasher, View as SqliteView } from './serializer/sqliteSchema'; import { libSQLCombineStatements, sqliteCombineStatements } from './statementCombiner'; import { copy, prepareMigrationMeta } from './utils'; @@ -393,6 +396,11 @@ export const diffResultSchemeMysql = object({ alteredViews: alteredMySqlViewSchema.array(), }); +export const diffResultSchemeSingleStore = object({ + alteredTablesWithColumns: alteredTableScheme.array(), + alteredEnums: never().array(), +}); + export const diffResultSchemeSQLite = object({ alteredTablesWithColumns: alteredTableScheme.array(), alteredEnums: never().array(), @@ -407,6 +415,7 @@ export type Table = TypeOf; export type AlteredTable = TypeOf; export type DiffResult = TypeOf; export type DiffResultMysql = TypeOf; +export type DiffResultSingleStore = TypeOf; export type DiffResultSQLite = TypeOf; export interface ResolverInput { @@ -1267,17 +1276,21 @@ export const applyPgSnapshotsDiff = async ( it.name, it.schema, it.addedCompositePKs, + curFull as PgSchema, ); deletedCompositePKs = prepareDeleteCompositePrimaryKeyPg( it.name, it.schema, it.deletedCompositePKs, + prevFull as PgSchema, ); } alteredCompositePKs = prepareAlterCompositePrimaryKeyPg( it.name, it.schema, it.alteredCompositePKs, + prevFull as PgSchema, + curFull as PgSchema, ); // add logic for unique constraints @@ -2673,6 +2686,519 @@ export const applyMysqlSnapshotsDiff = async ( }; }; +export const applySingleStoreSnapshotsDiff = async ( + json1: SingleStoreSchemaSquashed, + json2: SingleStoreSchemaSquashed, + tablesResolver: ( + input: ResolverInput
, + ) => Promise>, + columnsResolver: ( + input: ColumnsResolverInput, + ) => Promise>, + /* viewsResolver: ( + input: ResolverInput, + ) => Promise>, */ + prevFull: SingleStoreSchema, + curFull: SingleStoreSchema, + action?: 'push' | undefined, +): Promise<{ + statements: JsonStatement[]; + sqlStatements: string[]; + _meta: + | { + schemas: {}; + tables: {}; + columns: {}; + } + | undefined; +}> => { + // squash indexes and fks + + // squash uniqueIndexes and uniqueConstraint into constraints object + // it should be done for singlestore only because it has no diffs for it + + // TODO: @AndriiSherman + // Add an upgrade to v6 and move all snaphosts to this strcutre + // After that we can generate singlestore in 1 object directly(same as sqlite) + for (const tableName in json1.tables) { + const table = json1.tables[tableName]; + for (const indexName in table.indexes) { + const index = SingleStoreSquasher.unsquashIdx(table.indexes[indexName]); + if (index.isUnique) { + table.uniqueConstraints[indexName] = SingleStoreSquasher.squashUnique({ + name: index.name, + columns: index.columns, + }); + delete json1.tables[tableName].indexes[index.name]; + } + } + } + + for (const tableName in json2.tables) { + const table = json2.tables[tableName]; + for (const indexName in table.indexes) { + const index = SingleStoreSquasher.unsquashIdx(table.indexes[indexName]); + if (index.isUnique) { + table.uniqueConstraints[indexName] = SingleStoreSquasher.squashUnique({ + name: index.name, + columns: index.columns, + }); + delete json2.tables[tableName].indexes[index.name]; + } + } + } + + const tablesDiff = diffSchemasOrTables(json1.tables, json2.tables); + + const { + created: createdTables, + deleted: deletedTables, + renamed: renamedTables, // renamed or moved + } = await tablesResolver({ + created: tablesDiff.added, + deleted: tablesDiff.deleted, + }); + + const tablesPatchedSnap1 = copy(json1); + tablesPatchedSnap1.tables = mapEntries(tablesPatchedSnap1.tables, (_, it) => { + const { name } = nameChangeFor(it, renamedTables); + it.name = name; + return [name, it]; + }); + + const res = diffColumns(tablesPatchedSnap1.tables, json2.tables); + const columnRenames = [] as { + table: string; + renames: { from: Column; to: Column }[]; + }[]; + + const columnCreates = [] as { + table: string; + columns: Column[]; + }[]; + + const columnDeletes = [] as { + table: string; + columns: Column[]; + }[]; + + for (let entry of Object.values(res)) { + const { renamed, created, deleted } = await columnsResolver({ + tableName: entry.name, + schema: entry.schema, + deleted: entry.columns.deleted, + created: entry.columns.added, + }); + + if (created.length > 0) { + columnCreates.push({ + table: entry.name, + columns: created, + }); + } + + if (deleted.length > 0) { + columnDeletes.push({ + table: entry.name, + columns: deleted, + }); + } + + if (renamed.length > 0) { + columnRenames.push({ + table: entry.name, + renames: renamed, + }); + } + } + + const columnRenamesDict = columnRenames.reduce( + (acc, it) => { + acc[it.table] = it.renames; + return acc; + }, + {} as Record< + string, + { + from: Named; + to: Named; + }[] + >, + ); + + const columnsPatchedSnap1 = copy(tablesPatchedSnap1); + columnsPatchedSnap1.tables = mapEntries( + columnsPatchedSnap1.tables, + (tableKey, tableValue) => { + const patchedColumns = mapKeys( + tableValue.columns, + (columnKey, column) => { + const rens = columnRenamesDict[tableValue.name] || []; + const newName = columnChangeFor(columnKey, rens); + column.name = newName; + return newName; + }, + ); + + tableValue.columns = patchedColumns; + return [tableKey, tableValue]; + }, + ); + + /* const viewsDiff = diffSchemasOrTables(json1.views, json2.views); + + const { + created: createdViews, + deleted: deletedViews, + renamed: renamedViews, // renamed or moved + } = await viewsResolver({ + created: viewsDiff.added, + deleted: viewsDiff.deleted, + }); + + const renamesViewDic: Record = {}; + renamedViews.forEach((it) => { + renamesViewDic[it.from.name] = { to: it.to.name, from: it.from.name }; + }); + + const viewsPatchedSnap1 = copy(columnsPatchedSnap1); + viewsPatchedSnap1.views = mapEntries( + viewsPatchedSnap1.views, + (viewKey, viewValue) => { + const rename = renamesViewDic[viewValue.name]; + + if (rename) { + viewValue.name = rename.to; + viewKey = rename.to; + } + + return [viewKey, viewValue]; + }, + ); + + */ + const diffResult = applyJsonDiff(tablesPatchedSnap1, json2); // replace tablesPatchedSnap1 with viewsPatchedSnap1 + + const typedResult: DiffResultSingleStore = diffResultSchemeSingleStore.parse(diffResult); + + const jsonStatements: JsonStatement[] = []; + + const jsonCreateIndexesForCreatedTables = createdTables + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.indexes, + curFull.internal, + ); + }) + .flat(); + + const jsonDropTables = deletedTables.map((it) => { + return prepareDropTableJson(it); + }); + + const jsonRenameTables = renamedTables.map((it) => { + return prepareRenameTableJson(it.from, it.to); + }); + + const alteredTables = typedResult.alteredTablesWithColumns; + + const jsonAddedCompositePKs: JsonCreateCompositePK[] = []; + + const jsonAddedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + const jsonDeletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + const jsonAlteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + const jsonRenameColumnsStatements: JsonRenameColumnStatement[] = columnRenames + .map((it) => prepareRenameColumns(it.table, '', it.renames)) + .flat(); + + const jsonAddColumnsStatemets: JsonAddColumnStatement[] = columnCreates + .map((it) => _prepareAddColumns(it.table, '', it.columns)) + .flat(); + + const jsonDropColumnsStatemets: JsonDropColumnStatement[] = columnDeletes + .map((it) => _prepareDropColumns(it.table, '', it.columns)) + .flat(); + + alteredTables.forEach((it) => { + // This part is needed to make sure that same columns in a table are not triggered for change + // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name + // We double-check that pk with same set of columns are both in added and deleted diffs + let addedColumns: string[] = []; + for (const addedPkName of Object.keys(it.addedCompositePKs)) { + const addedPkColumns = it.addedCompositePKs[addedPkName]; + addedColumns = SingleStoreSquasher.unsquashPK(addedPkColumns).columns; + } + + let deletedColumns: string[] = []; + for (const deletedPkName of Object.keys(it.deletedCompositePKs)) { + const deletedPkColumns = it.deletedCompositePKs[deletedPkName]; + deletedColumns = SingleStoreSquasher.unsquashPK(deletedPkColumns).columns; + } + + // Don't need to sort, but need to add tests for it + // addedColumns.sort(); + // deletedColumns.sort(); + const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); + + // add logic for unique constraints + let addedUniqueConstraints: JsonCreateUniqueConstraint[] = []; + let deletedUniqueConstraints: JsonDeleteUniqueConstraint[] = []; + let alteredUniqueConstraints: JsonAlterUniqueConstraint[] = []; + + let createdCheckConstraints: JsonCreateCheckConstraint[] = []; + let deletedCheckConstraints: JsonDeleteCheckConstraint[] = []; + + addedUniqueConstraints = prepareAddUniqueConstraint( + it.name, + it.schema, + it.addedUniqueConstraints, + ); + deletedUniqueConstraints = prepareDeleteUniqueConstraint( + it.name, + it.schema, + it.deletedUniqueConstraints, + ); + if (it.alteredUniqueConstraints) { + const added: Record = {}; + const deleted: Record = {}; + for (const k of Object.keys(it.alteredUniqueConstraints)) { + added[k] = it.alteredUniqueConstraints[k].__new; + deleted[k] = it.alteredUniqueConstraints[k].__old; + } + addedUniqueConstraints.push( + ...prepareAddUniqueConstraint(it.name, it.schema, added), + ); + deletedUniqueConstraints.push( + ...prepareDeleteUniqueConstraint(it.name, it.schema, deleted), + ); + } + + createdCheckConstraints = prepareAddCheckConstraint(it.name, it.schema, it.addedCheckConstraints); + deletedCheckConstraints = prepareDeleteCheckConstraint( + it.name, + it.schema, + it.deletedCheckConstraints, + ); + + // skip for push + if (it.alteredCheckConstraints && action !== 'push') { + const added: Record = {}; + const deleted: Record = {}; + + for (const k of Object.keys(it.alteredCheckConstraints)) { + added[k] = it.alteredCheckConstraints[k].__new; + deleted[k] = it.alteredCheckConstraints[k].__old; + } + createdCheckConstraints.push(...prepareAddCheckConstraint(it.name, it.schema, added)); + deletedCheckConstraints.push(...prepareDeleteCheckConstraint(it.name, it.schema, deleted)); + } + + jsonAddedUniqueConstraints.push(...addedUniqueConstraints); + jsonDeletedUniqueConstraints.push(...deletedUniqueConstraints); + jsonAlteredUniqueConstraints.push(...alteredUniqueConstraints); + }); + + const rColumns = jsonRenameColumnsStatements.map((it) => { + const tableName = it.tableName; + const schema = it.schema; + return { + from: { schema, table: tableName, column: it.oldColumnName }, + to: { schema, table: tableName, column: it.newColumnName }, + }; + }); + + const jsonTableAlternations = alteredTables + .map((it) => { + return prepareAlterColumnsMysql( + it.name, + it.schema, + it.altered, + json1, + json2, + action, + ); + }) + .flat(); + + const jsonCreateIndexesForAllAlteredTables = alteredTables + .map((it) => { + return prepareCreateIndexesJson( + it.name, + it.schema, + it.addedIndexes || {}, + curFull.internal, + ); + }) + .flat(); + + const jsonDropIndexesForAllAlteredTables = alteredTables + .map((it) => { + return prepareDropIndexesJson( + it.name, + it.schema, + it.deletedIndexes || {}, + ); + }) + .flat(); + + alteredTables.forEach((it) => { + const droppedIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__old; + return current; + }, + {} as Record, + ); + const createdIndexes = Object.keys(it.alteredIndexes).reduce( + (current, item: string) => { + current[item] = it.alteredIndexes[item].__new; + return current; + }, + {} as Record, + ); + + jsonCreateIndexesForAllAlteredTables.push( + ...prepareCreateIndexesJson(it.name, it.schema, createdIndexes || {}), + ); + jsonDropIndexesForAllAlteredTables.push( + ...prepareDropIndexesJson(it.name, it.schema, droppedIndexes || {}), + ); + }); + + const jsonSingleStoreCreateTables = createdTables.map((it) => { + return prepareSingleStoreCreateTableJson( + it, + curFull as SingleStoreSchema, + curFull.internal, + ); + }); + + /* const createViews: JsonCreateSingleStoreViewStatement[] = []; + const dropViews: JsonDropViewStatement[] = []; + const renameViews: JsonRenameViewStatement[] = []; + const alterViews: JsonAlterSingleStoreViewStatement[] = []; + + createViews.push( + ...createdViews.filter((it) => !it.isExisting).map((it) => { + return prepareSingleStoreCreateViewJson( + it.name, + it.definition!, + it.meta, + ); + }), + ); + + dropViews.push( + ...deletedViews.filter((it) => !it.isExisting).map((it) => { + return prepareDropViewJson(it.name); + }), + ); + + renameViews.push( + ...renamedViews.filter((it) => !it.to.isExisting && !json1.views[it.from.name].isExisting).map((it) => { + return prepareRenameViewJson(it.to.name, it.from.name); + }), + ); + + const alteredViews = typedResult.alteredViews.filter((it) => !json2.views[it.name].isExisting); + + for (const alteredView of alteredViews) { + const { definition, meta } = json2.views[alteredView.name]; + + if (alteredView.alteredExisting) { + dropViews.push(prepareDropViewJson(alteredView.name)); + + createViews.push( + prepareSingleStoreCreateViewJson( + alteredView.name, + definition!, + meta, + ), + ); + + continue; + } + + if (alteredView.alteredDefinition && action !== 'push') { + createViews.push( + prepareSingleStoreCreateViewJson( + alteredView.name, + definition!, + meta, + true, + ), + ); + continue; + } + + if (alteredView.alteredMeta) { + const view = curFull['views'][alteredView.name]; + alterViews.push( + prepareSingleStoreAlterView(view), + ); + } + } */ + + jsonStatements.push(...jsonSingleStoreCreateTables); + + jsonStatements.push(...jsonDropTables); + jsonStatements.push(...jsonRenameTables); + jsonStatements.push(...jsonRenameColumnsStatements); + + /*jsonStatements.push(...createViews); + jsonStatements.push(...dropViews); + jsonStatements.push(...renameViews); + jsonStatements.push(...alterViews); + */ + jsonStatements.push(...jsonDeletedUniqueConstraints); + + // Will need to drop indexes before changing any columns in table + // Then should go column alternations and then index creation + jsonStatements.push(...jsonDropIndexesForAllAlteredTables); + + jsonStatements.push(...jsonTableAlternations); + jsonStatements.push(...jsonAddedCompositePKs); + + jsonStatements.push(...jsonAddedUniqueConstraints); + jsonStatements.push(...jsonDeletedUniqueConstraints); + + jsonStatements.push(...jsonAddColumnsStatemets); + + jsonStatements.push(...jsonCreateIndexesForCreatedTables); + + jsonStatements.push(...jsonCreateIndexesForAllAlteredTables); + + jsonStatements.push(...jsonDropColumnsStatemets); + + jsonStatements.push(...jsonAddedCompositePKs); + + jsonStatements.push(...jsonAlteredUniqueConstraints); + + const sqlStatements = fromJson(jsonStatements, 'singlestore'); + + const uniqueSqlStatements: string[] = []; + sqlStatements.forEach((ss) => { + if (!uniqueSqlStatements.includes(ss)) { + uniqueSqlStatements.push(ss); + } + }); + + const rTables = renamedTables.map((it) => { + return { from: it.from, to: it.to }; + }); + + const _meta = prepareMigrationMeta([], rTables, rColumns); + + return { + statements: jsonStatements, + sqlStatements: uniqueSqlStatements, + _meta, + }; +}; + export const applySqliteSnapshotsDiff = async ( json1: SQLiteSchemaSquashed, json2: SQLiteSchemaSquashed, diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 3c88a86ce..a35c001fd 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -85,7 +85,9 @@ import { import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; import { PgSquasher, policy } from './serializer/pgSchema'; +import { SingleStoreSquasher } from './serializer/singlestoreSchema'; import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; + import { escapeSingleQuotes } from './utils'; const parseType = (schemaPrefix: string, type: string) => { @@ -572,6 +574,81 @@ class MySqlCreateTableConvertor extends Convertor { return statement; } } +class SingleStoreCreateTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_table' && dialect === 'singlestore'; + } + + convert(st: JsonCreateTableStatement) { + const { + tableName, + columns, + schema, + compositePKs, + uniqueConstraints, + internals, + } = st; + + let statement = ''; + statement += `CREATE TABLE \`${tableName}\` (\n`; + for (let i = 0; i < columns.length; i++) { + const column = columns[i]; + + const primaryKeyStatement = column.primaryKey ? ' PRIMARY KEY' : ''; + const notNullStatement = column.notNull ? ' NOT NULL' : ''; + const defaultStatement = column.default !== undefined ? ` DEFAULT ${column.default}` : ''; + + const onUpdateStatement = column.onUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + + const autoincrementStatement = column.autoincrement + ? ' AUTO_INCREMENT' + : ''; + + const generatedStatement = column.generated + ? ` GENERATED ALWAYS AS (${column.generated?.as}) ${column.generated?.type.toUpperCase()}` + : ''; + + statement += '\t' + + `\`${column.name}\` ${column.type}${autoincrementStatement}${primaryKeyStatement}${notNullStatement}${defaultStatement}${onUpdateStatement}${generatedStatement}`; + statement += i === columns.length - 1 ? '' : ',\n'; + } + + if (typeof compositePKs !== 'undefined' && compositePKs.length > 0) { + statement += ',\n'; + const compositePK = SingleStoreSquasher.unsquashPK(compositePKs[0]); + statement += `\tCONSTRAINT \`${st.compositePkName}\` PRIMARY KEY(\`${compositePK.columns.join(`\`,\``)}\`)`; + } + + if ( + typeof uniqueConstraints !== 'undefined' + && uniqueConstraints.length > 0 + ) { + for (const uniqueConstraint of uniqueConstraints) { + statement += ',\n'; + const unsquashedUnique = SingleStoreSquasher.unsquashUnique(uniqueConstraint); + + const uniqueString = unsquashedUnique.columns + .map((it) => { + return internals?.indexes + ? internals?.indexes[unsquashedUnique.name]?.columns[it] + ?.isExpression + ? it + : `\`${it}\`` + : `\`${it}\``; + }) + .join(','); + + statement += `\tCONSTRAINT \`${unsquashedUnique.name}\` UNIQUE(${uniqueString})`; + } + } + + statement += `\n);`; + statement += `\n`; + return statement; + } +} export class SQLiteCreateTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { @@ -1165,6 +1242,29 @@ class MySqlAlterTableAddCheckConstraintConvertor extends Convertor { } } +class SingleStoreAlterTableAddUniqueConstraintConvertor extends Convertor { + can(statement: JsonCreateUniqueConstraint, dialect: Dialect): boolean { + return statement.type === 'create_unique_constraint' && dialect === 'singlestore'; + } + convert(statement: JsonCreateUniqueConstraint): string { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); + + return `ALTER TABLE \`${statement.tableName}\` ADD CONSTRAINT \`${unsquashed.name}\` UNIQUE(\`${ + unsquashed.columns.join('`,`') + }\`);`; + } +} +class SingleStoreAlterTableDropUniqueConstraintConvertor extends Convertor { + can(statement: JsonDeleteUniqueConstraint, dialect: Dialect): boolean { + return statement.type === 'delete_unique_constraint' && dialect === 'singlestore'; + } + convert(statement: JsonDeleteUniqueConstraint): string { + const unsquashed = SingleStoreSquasher.unsquashUnique(statement.data); + + return `ALTER TABLE \`${statement.tableName}\` DROP INDEX \`${unsquashed.name}\`;`; + } +} + class MySqlAlterTableDeleteCheckConstraintConvertor extends Convertor { can(statement: JsonDeleteCheckConstraint, dialect: Dialect): boolean { return ( @@ -1431,6 +1531,17 @@ class MySQLDropTableConvertor extends Convertor { } } +class SingleStoreDropTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_table' && dialect === 'singlestore'; + } + + convert(statement: JsonDropTableStatement) { + const { tableName } = statement; + return `DROP TABLE \`${tableName}\`;`; + } +} + export class SQLiteDropTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'drop_table' && (dialect === 'sqlite' || dialect === 'turso'); @@ -1479,6 +1590,17 @@ class MySqlRenameTableConvertor extends Convertor { } } +class SingleStoreRenameTableConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'rename_table' && dialect === 'singlestore'; + } + + convert(statement: JsonRenameTableStatement) { + const { tableNameFrom, tableNameTo } = statement; + return `RENAME TABLE \`${tableNameFrom}\` TO \`${tableNameTo}\`;`; + } +} + class PgAlterTableRenameColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1510,6 +1632,19 @@ class MySqlAlterTableRenameColumnConvertor extends Convertor { } } +class SingleStoreAlterTableRenameColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + statement.type === 'alter_table_rename_column' && dialect === 'singlestore' + ); + } + + convert(statement: JsonRenameColumnStatement) { + const { tableName, oldColumnName, newColumnName } = statement; + return `ALTER TABLE \`${tableName}\` RENAME COLUMN \`${oldColumnName}\` TO \`${newColumnName}\`;`; + } +} + class SQLiteAlterTableRenameColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -1552,6 +1687,17 @@ class MySqlAlterTableDropColumnConvertor extends Convertor { } } +class SingleStoreAlterTableDropColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_table_drop_column' && dialect === 'singlestore'; + } + + convert(statement: JsonDropColumnStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` DROP COLUMN \`${columnName}\`;`; + } +} + class SQLiteAlterTableDropColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'alter_table_drop_column' && (dialect === 'sqlite' || dialect === 'turso'); @@ -1659,6 +1805,37 @@ class MySqlAlterTableAddColumnConvertor extends Convertor { } } +class SingleStoreAlterTableAddColumnConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_table_add_column' && dialect === 'singlestore'; + } + + convert(statement: JsonAddColumnStatement) { + const { tableName, column } = statement; + const { + name, + type, + notNull, + primaryKey, + autoincrement, + onUpdate, + generated, + } = column; + + const defaultStatement = `${column.default !== undefined ? ` DEFAULT ${column.default}` : ''}`; + const notNullStatement = `${notNull ? ' NOT NULL' : ''}`; + const primaryKeyStatement = `${primaryKey ? ' PRIMARY KEY' : ''}`; + const autoincrementStatement = `${autoincrement ? ' AUTO_INCREMENT' : ''}`; + const onUpdateStatement = `${onUpdate ? ' ON UPDATE CURRENT_TIMESTAMP' : ''}`; + + const generatedStatement = generated + ? ` GENERATED ALWAYS AS (${generated?.as}) ${generated?.type.toUpperCase()}` + : ''; + + return `ALTER TABLE \`${tableName}\` ADD \`${name}\` ${type}${primaryKeyStatement}${autoincrementStatement}${defaultStatement}${notNullStatement}${onUpdateStatement}${generatedStatement};`; + } +} + export class SQLiteAlterTableAddColumnConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2462,76 +2639,429 @@ class MySqlModifyColumn extends Convertor { } } -class PgAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { +class SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_composite_pk' && dialect === 'postgresql'; + return ( + statement.type === 'alter_table_alter_column_alter_generated' + && dialect === 'singlestore' + ); } - convert(statement: JsonCreateCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.data); + convert(statement: JsonAlterColumnAlterGeneratedStatement) { + const { + tableName, + columnName, + schema, + columnNotNull: notNull, + columnDefault, + columnOnUpdate, + columnAutoIncrement, + columnPk, + columnGenerated, + } = statement; - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; + const tableNameWithSchema = schema + ? `\`${schema}\`.\`${tableName}\`` + : `\`${tableName}\``; - return `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.constraintName}" PRIMARY KEY("${ - columns.join('","') - }");`; + const addColumnStatement = new SingleStoreAlterTableAddColumnConvertor().convert({ + schema, + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull, + default: columnDefault, + onUpdate: columnOnUpdate, + autoincrement: columnAutoIncrement, + primaryKey: columnPk, + generated: columnGenerated, + }, + type: 'alter_table_add_column', + }); + + return [ + `ALTER TABLE ${tableNameWithSchema} drop column \`${columnName}\`;`, + addColumnStatement, + ]; } } -class PgAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + +class SingleStoreAlterTableAlterColumnSetDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'delete_composite_pk' && dialect === 'postgresql'; + return ( + statement.type === 'alter_table_alter_column_set_default' + && dialect === 'singlestore' + ); } - convert(statement: JsonDeleteCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.data); - - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; - - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.constraintName}";`; + convert(statement: JsonAlterColumnSetDefaultStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` ALTER COLUMN \`${columnName}\` SET DEFAULT ${statement.newDefaultValue};`; } } -class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { +class SingleStoreAlterTableAlterColumnDropDefaultConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'alter_composite_pk' && dialect === 'postgresql'; - } - - convert(statement: JsonAlterCompositePK) { - const { name, columns } = PgSquasher.unsquashPK(statement.old); - const { name: newName, columns: newColumns } = PgSquasher.unsquashPK( - statement.new, + return ( + statement.type === 'alter_table_alter_column_drop_default' + && dialect === 'singlestore' ); + } - const tableNameWithSchema = statement.schema - ? `"${statement.schema}"."${statement.tableName}"` - : `"${statement.tableName}"`; - - console.log(statement.oldConstraintName, statement.newConstraintName); - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.oldConstraintName}";\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.newConstraintName}" PRIMARY KEY("${ - newColumns.join('","') - }");`; + convert(statement: JsonAlterColumnDropDefaultStatement) { + const { tableName, columnName } = statement; + return `ALTER TABLE \`${tableName}\` ALTER COLUMN \`${columnName}\` DROP DEFAULT;`; } } -class MySqlAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'create_composite_pk' && dialect === 'mysql'; +class SingleStoreAlterTableAddPk extends Convertor { + can(statement: JsonStatement, dialect: string): boolean { + return ( + statement.type === 'alter_table_alter_column_set_pk' + && dialect === 'singlestore' + ); } - - convert(statement: JsonCreateCompositePK) { - const { name, columns } = MySqlSquasher.unsquashPK(statement.data); - return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY(\`${columns.join('`,`')}\`);`; + convert(statement: JsonAlterColumnSetPrimaryKeyStatement): string { + return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY (\`${statement.columnName}\`);`; } } -class MySqlAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { - can(statement: JsonStatement, dialect: Dialect): boolean { - return statement.type === 'delete_composite_pk' && dialect === 'mysql'; - } +class SingleStoreAlterTableDropPk extends Convertor { + can(statement: JsonStatement, dialect: string): boolean { + return ( + statement.type === 'alter_table_alter_column_drop_pk' + && dialect === 'singlestore' + ); + } + convert(statement: JsonAlterColumnDropPrimaryKeyStatement): string { + return `ALTER TABLE \`${statement.tableName}\` DROP PRIMARY KEY`; + } +} + +type SingleStoreModifyColumnStatement = + | JsonAlterColumnDropNotNullStatement + | JsonAlterColumnSetNotNullStatement + | JsonAlterColumnTypeStatement + | JsonAlterColumnDropOnUpdateStatement + | JsonAlterColumnSetOnUpdateStatement + | JsonAlterColumnDropAutoincrementStatement + | JsonAlterColumnSetAutoincrementStatement + | JsonAlterColumnSetDefaultStatement + | JsonAlterColumnDropDefaultStatement + | JsonAlterColumnSetGeneratedStatement + | JsonAlterColumnDropGeneratedStatement; + +class SingleStoreModifyColumn extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + (statement.type === 'alter_table_alter_column_set_type' + || statement.type === 'alter_table_alter_column_set_notnull' + || statement.type === 'alter_table_alter_column_drop_notnull' + || statement.type === 'alter_table_alter_column_drop_on_update' + || statement.type === 'alter_table_alter_column_set_on_update' + || statement.type === 'alter_table_alter_column_set_autoincrement' + || statement.type === 'alter_table_alter_column_drop_autoincrement' + || statement.type === 'alter_table_alter_column_set_default' + || statement.type === 'alter_table_alter_column_drop_default' + || statement.type === 'alter_table_alter_column_set_generated' + || statement.type === 'alter_table_alter_column_drop_generated') + && dialect === 'singlestore' + ); + } + + convert(statement: SingleStoreModifyColumnStatement) { + const { tableName, columnName } = statement; + let columnType = ``; + let columnDefault: any = ''; + let columnNotNull = ''; + let columnOnUpdate = ''; + let columnAutoincrement = ''; + let primaryKey = statement.columnPk ? ' PRIMARY KEY' : ''; + let columnGenerated = ''; + + if (statement.type === 'alter_table_alter_column_drop_notnull') { + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_notnull') { + columnNotNull = ` NOT NULL`; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_drop_on_update') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnOnUpdate = ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_on_update') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = ` ON UPDATE CURRENT_TIMESTAMP`; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if ( + statement.type === 'alter_table_alter_column_set_autoincrement' + ) { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = ' AUTO_INCREMENT'; + } else if ( + statement.type === 'alter_table_alter_column_drop_autoincrement' + ) { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = ''; + } else if (statement.type === 'alter_table_alter_column_set_default') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = ` DEFAULT ${statement.newDefaultValue}`; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_drop_default') { + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnType = ` ${statement.newDataType}`; + columnDefault = ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + } else if (statement.type === 'alter_table_alter_column_set_generated') { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + + if (statement.columnGenerated?.type === 'virtual') { + return [ + new SingleStoreAlterTableDropColumnConvertor().convert({ + type: 'alter_table_drop_column', + tableName: statement.tableName, + columnName: statement.columnName, + schema: statement.schema, + }), + new SingleStoreAlterTableAddColumnConvertor().convert({ + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull: statement.columnNotNull, + default: statement.columnDefault, + onUpdate: statement.columnOnUpdate, + autoincrement: statement.columnAutoIncrement, + primaryKey: statement.columnPk, + generated: statement.columnGenerated, + }, + schema: statement.schema, + type: 'alter_table_add_column', + }), + ]; + } else { + columnGenerated = statement.columnGenerated + ? ` GENERATED ALWAYS AS (${statement.columnGenerated?.as}) ${statement.columnGenerated?.type.toUpperCase()}` + : ''; + } + } else if (statement.type === 'alter_table_alter_column_drop_generated') { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + + if (statement.oldColumn?.generated?.type === 'virtual') { + return [ + new SingleStoreAlterTableDropColumnConvertor().convert({ + type: 'alter_table_drop_column', + tableName: statement.tableName, + columnName: statement.columnName, + schema: statement.schema, + }), + new SingleStoreAlterTableAddColumnConvertor().convert({ + tableName, + column: { + name: columnName, + type: statement.newDataType, + notNull: statement.columnNotNull, + default: statement.columnDefault, + onUpdate: statement.columnOnUpdate, + autoincrement: statement.columnAutoIncrement, + primaryKey: statement.columnPk, + generated: statement.columnGenerated, + }, + schema: statement.schema, + type: 'alter_table_add_column', + }), + ]; + } + } else { + columnType = ` ${statement.newDataType}`; + columnNotNull = statement.columnNotNull ? ` NOT NULL` : ''; + columnOnUpdate = columnOnUpdate = statement.columnOnUpdate + ? ` ON UPDATE CURRENT_TIMESTAMP` + : ''; + columnDefault = statement.columnDefault + ? ` DEFAULT ${statement.columnDefault}` + : ''; + columnAutoincrement = statement.columnAutoIncrement + ? ' AUTO_INCREMENT' + : ''; + columnGenerated = statement.columnGenerated + ? ` GENERATED ALWAYS AS (${statement.columnGenerated?.as}) ${statement.columnGenerated?.type.toUpperCase()}` + : ''; + } + + // Seems like getting value from simple json2 shanpshot makes dates be dates + columnDefault = columnDefault instanceof Date + ? columnDefault.toISOString() + : columnDefault; + + return `ALTER TABLE \`${tableName}\` MODIFY COLUMN \`${columnName}\`${columnType}${columnAutoincrement}${columnNotNull}${columnDefault}${columnOnUpdate}${columnGenerated};`; + } +} +class SqliteAlterTableAlterColumnDropDefaultConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return ( + statement.type === 'alter_table_alter_column_drop_default' + && dialect === 'sqlite' + ); + } + + convert(statement: JsonAlterColumnDropDefaultStatement) { + return ( + '/*\n SQLite does not support "Drop default from column" out of the box, we do not generate automatic migration for that, so it has to be done manually' + + '\n Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php' + + '\n https://www.sqlite.org/lang_altertable.html' + + '\n https://stackoverflow.com/questions/2083543/modify-a-columns-type-in-sqlite3' + + "\n\n Due to that we don't generate migration automatically and it has to be done manually" + + '\n*/' + ); + } +} + +class PgAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonCreateCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.data); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.constraintName}" PRIMARY KEY("${ + columns.join('","') + }");`; + } +} +class PgAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonDeleteCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.data); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.constraintName}";`; + } +} + +class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_composite_pk' && dialect === 'postgresql'; + } + + convert(statement: JsonAlterCompositePK) { + const { name, columns } = PgSquasher.unsquashPK(statement.old); + const { name: newName, columns: newColumns } = PgSquasher.unsquashPK( + statement.new, + ); + + const tableNameWithSchema = statement.schema + ? `"${statement.schema}"."${statement.tableName}"` + : `"${statement.tableName}"`; + + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.oldConstraintName}";\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.newConstraintName}" PRIMARY KEY("${ + newColumns.join('","') + }");`; + } +} + +class MySqlAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'mysql'; + } + + convert(statement: JsonCreateCompositePK) { + const { name, columns } = MySqlSquasher.unsquashPK(statement.data); + return `ALTER TABLE \`${statement.tableName}\` ADD PRIMARY KEY(\`${columns.join('`,`')}\`);`; + } +} + +class MySqlAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'mysql'; + } convert(statement: JsonDeleteCompositePK) { const { name, columns } = MySqlSquasher.unsquashPK(statement.data); @@ -2553,6 +3083,89 @@ class MySqlAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { } } +class SqliteAlterTableCreateCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_composite_pk' && dialect === 'sqlite'; + } + + convert(statement: JsonCreateCompositePK) { + let msg = '/*\n'; + msg += `You're trying to add PRIMARY KEY(${statement.data}) to '${statement.tableName}' table\n`; + msg += 'SQLite does not support adding primary key to an already created table\n'; + msg += 'You can do it in 3 steps with drizzle orm:\n'; + msg += ' - create new mirror table with needed pk, rename current table to old_table, generate SQL\n'; + msg += ' - migrate old data from one table to another\n'; + msg += ' - delete old_table in schema, generate sql\n\n'; + msg += 'or create manual migration like below:\n\n'; + msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; + msg += 'CREATE TABLE table_name (\n'; + msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; + msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; + msg += '\t...\n'; + msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; + msg += ' );\n'; + msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; + msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; + msg += '*/\n'; + return msg; + } +} +class SqliteAlterTableDeleteCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'delete_composite_pk' && dialect === 'sqlite'; + } + + convert(statement: JsonDeleteCompositePK) { + let msg = '/*\n'; + msg += `You're trying to delete PRIMARY KEY(${statement.data}) from '${statement.tableName}' table\n`; + msg += 'SQLite does not supportprimary key deletion from existing table\n'; + msg += 'You can do it in 3 steps with drizzle orm:\n'; + msg += ' - create new mirror table table without pk, rename current table to old_table, generate SQL\n'; + msg += ' - migrate old data from one table to another\n'; + msg += ' - delete old_table in schema, generate sql\n\n'; + msg += 'or create manual migration like below:\n\n'; + msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; + msg += 'CREATE TABLE table_name (\n'; + msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; + msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; + msg += '\t...\n'; + msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; + msg += ' );\n'; + msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; + msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; + msg += '*/\n'; + return msg; + } +} + +class SqliteAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'alter_composite_pk' && dialect === 'sqlite'; + } + + convert(statement: JsonAlterCompositePK) { + let msg = '/*\n'; + msg += 'SQLite does not support altering primary key\n'; + msg += 'You can do it in 3 steps with drizzle orm:\n'; + msg += ' - create new mirror table with needed pk, rename current table to old_table, generate SQL\n'; + msg += ' - migrate old data from one table to another\n'; + msg += ' - delete old_table in schema, generate sql\n\n'; + msg += 'or create manual migration like below:\n\n'; + msg += 'ALTER TABLE table_name RENAME TO old_table;\n'; + msg += 'CREATE TABLE table_name (\n'; + msg += '\tcolumn1 datatype [ NULL | NOT NULL ],\n'; + msg += '\tcolumn2 datatype [ NULL | NOT NULL ],\n'; + msg += '\t...\n'; + msg += '\tPRIMARY KEY (pk_col1, pk_col2, ... pk_col_n)\n'; + msg += ' );\n'; + msg += 'INSERT INTO table_name SELECT * FROM old_table;\n\n'; + msg += "Due to that we don't generate migration automatically and it has to be done manually\n"; + msg += '*/\n'; + + return msg; + } +} + class PgAlterTableAlterColumnSetPrimaryKeyConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -2895,6 +3508,32 @@ class CreateMySqlIndexConvertor extends Convertor { } } +class CreateSingleStoreIndexConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'create_index' && dialect === 'singlestore'; + } + + convert(statement: JsonCreateIndexStatement): string { + // should be changed + const { name, columns, isUnique } = SingleStoreSquasher.unsquashIdx( + statement.data, + ); + const indexPart = isUnique ? 'UNIQUE INDEX' : 'INDEX'; + + const uniqueString = columns + .map((it) => { + return statement.internal?.indexes + ? statement.internal?.indexes[name]?.columns[it]?.isExpression + ? it + : `\`${it}\`` + : `\`${it}\``; + }) + .join(','); + + return `CREATE ${indexPart} \`${name}\` ON \`${statement.tableName}\` (${uniqueString});`; + } +} + export class CreateSqliteIndexConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return statement.type === 'create_index' && (dialect === 'sqlite' || dialect === 'turso'); @@ -3039,6 +3678,17 @@ class MySqlDropIndexConvertor extends Convertor { } } +class SingleStoreDropIndexConvertor extends Convertor { + can(statement: JsonStatement, dialect: Dialect): boolean { + return statement.type === 'drop_index' && dialect === 'singlestore'; + } + + convert(statement: JsonDropIndexStatement): string { + const { name } = SingleStoreSquasher.unsquashIdx(statement.data); + return `DROP INDEX \`${name}\` ON \`${statement.tableName}\`;`; + } +} + class SQLiteRecreateTableConvertor extends Convertor { can(statement: JsonStatement, dialect: Dialect): boolean { return ( @@ -3174,6 +3824,7 @@ class LibSQLRecreateTableConvertor extends Convertor { const convertors: Convertor[] = []; convertors.push(new PgCreateTableConvertor()); convertors.push(new MySqlCreateTableConvertor()); +convertors.push(new SingleStoreCreateTableConvertor()); convertors.push(new SQLiteCreateTableConvertor()); convertors.push(new SQLiteRecreateTableConvertor()); convertors.push(new LibSQLRecreateTableConvertor()); @@ -3210,22 +3861,27 @@ convertors.push(new AlterPgSequenceConvertor()); convertors.push(new PgDropTableConvertor()); convertors.push(new MySQLDropTableConvertor()); +convertors.push(new SingleStoreDropTableConvertor()); convertors.push(new SQLiteDropTableConvertor()); convertors.push(new PgRenameTableConvertor()); convertors.push(new MySqlRenameTableConvertor()); +convertors.push(new SingleStoreRenameTableConvertor()); convertors.push(new SqliteRenameTableConvertor()); convertors.push(new PgAlterTableRenameColumnConvertor()); convertors.push(new MySqlAlterTableRenameColumnConvertor()); +convertors.push(new SingleStoreAlterTableRenameColumnConvertor()); convertors.push(new SQLiteAlterTableRenameColumnConvertor()); convertors.push(new PgAlterTableDropColumnConvertor()); convertors.push(new MySqlAlterTableDropColumnConvertor()); +convertors.push(new SingleStoreAlterTableDropColumnConvertor()); convertors.push(new SQLiteAlterTableDropColumnConvertor()); convertors.push(new PgAlterTableAddColumnConvertor()); convertors.push(new MySqlAlterTableAddColumnConvertor()); +convertors.push(new SingleStoreAlterTableAddColumnConvertor()); convertors.push(new SQLiteAlterTableAddColumnConvertor()); convertors.push(new PgAlterTableAlterColumnSetTypeConvertor()); @@ -3241,13 +3897,18 @@ convertors.push(new MySqlAlterTableDeleteCheckConstraintConvertor()); convertors.push(new MySQLAlterTableAddUniqueConstraintConvertor()); convertors.push(new MySQLAlterTableDropUniqueConstraintConvertor()); +convertors.push(new SingleStoreAlterTableAddUniqueConstraintConvertor()); +convertors.push(new SingleStoreAlterTableDropUniqueConstraintConvertor()); + convertors.push(new CreatePgIndexConvertor()); convertors.push(new CreateMySqlIndexConvertor()); +convertors.push(new CreateSingleStoreIndexConvertor()); convertors.push(new CreateSqliteIndexConvertor()); convertors.push(new PgDropIndexConvertor()); convertors.push(new SqliteDropIndexConvertor()); convertors.push(new MySqlDropIndexConvertor()); +convertors.push(new SingleStoreDropIndexConvertor()); convertors.push(new PgAlterTableAlterColumnSetPrimaryKeyConvertor()); convertors.push(new PgAlterTableAlterColumnDropPrimaryKeyConvertor()); @@ -3281,6 +3942,8 @@ convertors.push(new PgAlterTableAlterColumnAlterrGeneratedConvertor()); convertors.push(new MySqlAlterTableAlterColumnAlterrGeneratedConvertor()); +convertors.push(new SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor()); + convertors.push(new SqliteAlterTableAlterColumnDropGeneratedConvertor()); convertors.push(new SqliteAlterTableAlterColumnAlterGeneratedConvertor()); convertors.push(new SqliteAlterTableAlterColumnSetExpressionConvertor()); @@ -3290,6 +3953,8 @@ convertors.push(new LibSQLModifyColumn()); // convertors.push(new MySqlAlterTableAlterColumnSetDefaultConvertor()); // convertors.push(new MySqlAlterTableAlterColumnDropDefaultConvertor()); +convertors.push(new SingleStoreModifyColumn()); + convertors.push(new PgCreateForeignKeyConvertor()); convertors.push(new MySqlCreateForeignKeyConvertor()); @@ -3321,6 +3986,9 @@ convertors.push(new MySqlAlterTableCreateCompositePrimaryKeyConvertor()); convertors.push(new MySqlAlterTableAddPk()); convertors.push(new MySqlAlterTableAlterCompositePrimaryKeyConvertor()); +convertors.push(new SingleStoreAlterTableDropPk()); +convertors.push(new SingleStoreAlterTableAddPk()); + export function fromJson( statements: JsonStatement[], dialect: Dialect, diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index 685e2efb5..2638ca4ef 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -10,6 +10,7 @@ import { assertUnreachable, snapshotVersion } from './global'; import type { Dialect } from './schemaValidator'; import { backwardCompatibleMysqlSchema } from './serializer/mysqlSchema'; import { backwardCompatiblePgSchema } from './serializer/pgSchema'; +import { backwardCompatibleSingleStoreSchema } from './serializer/singlestoreSchema'; import { backwardCompatibleSqliteSchema } from './serializer/sqliteSchema'; import type { ProxyParams } from './serializer/studio'; @@ -123,6 +124,8 @@ const validatorForDialect = (dialect: Dialect) => { return { validator: backwardCompatibleSqliteSchema, version: 6 }; case 'mysql': return { validator: backwardCompatibleMysqlSchema, version: 5 }; + case 'singlestore': + return { validator: backwardCompatibleSingleStoreSchema, version: 1 }; } }; diff --git a/drizzle-kit/tests/cli-generate.test.ts b/drizzle-kit/tests/cli-generate.test.ts index 6c8cae09e..a4adf979f 100644 --- a/drizzle-kit/tests/cli-generate.test.ts +++ b/drizzle-kit/tests/cli-generate.test.ts @@ -39,6 +39,7 @@ test('generate #1', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -59,6 +60,7 @@ test('generate #2', async (t) => { out: 'out', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -76,6 +78,7 @@ test('generate #3', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -94,6 +97,7 @@ test('generate #4', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -111,6 +115,7 @@ test('generate #5', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -128,6 +133,7 @@ test('generate #6', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -148,6 +154,7 @@ test('generate #7', async (t) => { out: 'drizzle', bundle: false, casing: undefined, + driver: undefined, }); }); @@ -166,6 +173,25 @@ test('generate #8', async (t) => { out: 'drizzle', bundle: true, // expo driver casing: undefined, + driver: 'expo', + }); +}); + +test('generate #9', async (t) => { + const res = await brotest(generate, '--config=durable-sqlite.config.ts'); + assert.equal(res.type, 'handler'); + if (res.type !== 'handler') assert.fail(res.type, 'handler'); + expect(res.options).toStrictEqual({ + dialect: 'sqlite', + name: undefined, + custom: false, + prefix: 'index', + breakpoints: true, + schema: './schema.ts', + out: 'drizzle', + bundle: true, // expo driver + casing: undefined, + driver: 'durable-sqlite', }); }); @@ -187,6 +213,7 @@ test('generate #9', async (t) => { out: 'out', bundle: false, casing: undefined, + driver: undefined, }); }); diff --git a/drizzle-kit/tests/cli/durable-sqlite.config.ts b/drizzle-kit/tests/cli/durable-sqlite.config.ts new file mode 100644 index 000000000..c3f4e44f0 --- /dev/null +++ b/drizzle-kit/tests/cli/durable-sqlite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from '../../src'; + +export default defineConfig({ + schema: './schema.ts', + dialect: 'sqlite', + driver: 'durable-sqlite', +}); diff --git a/drizzle-kit/tests/introspect/singlestore.test.ts b/drizzle-kit/tests/introspect/singlestore.test.ts new file mode 100644 index 000000000..71960c3f7 --- /dev/null +++ b/drizzle-kit/tests/introspect/singlestore.test.ts @@ -0,0 +1,275 @@ +import Docker from 'dockerode'; +import 'dotenv/config'; +import { SQL, sql } from 'drizzle-orm'; +import { + bigint, + char, + decimal, + double, + float, + int, + mediumint, + singlestoreTable, + smallint, + text, + tinyint, + varchar, +} from 'drizzle-orm/singlestore-core'; +import * as fs from 'fs'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { introspectSingleStoreToFile } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; + +let client: Connection; +let singlestoreContainer: Docker.Container; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return `singlestore://root:singlestore@localhost:${port}/`; +} + +beforeAll(async () => { + const connectionString = process.env.SINGLESTORE_CONNECTION_STRING ?? await createDockerDB(); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to SingleStore'); + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); + throw lastError; + } +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); +}); + +beforeEach(async () => { + await client.query(`drop database if exists \`drizzle\`;`); + await client.query(`create database \`drizzle\`;`); + await client.query(`use \`drizzle\`;`); +}); + +if (!fs.existsSync('tests/introspect/singlestore')) { + fs.mkdirSync('tests/introspect/singlestore'); +} + +// TODO: Unskip this test when generated column is implemented +/* test.skip('generated always column: link to another column', async () => { + const schema = { + users: singlestoreTable('users', { + id: int('id'), + email: text('email'), + generatedEmail: text('generatedEmail').generatedAlwaysAs( + (): SQL => sql`\`email\``, + ), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'generated-link-column', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); */ + +// TODO: Unskip this test when generated column is implemented +/* test.skip('generated always column virtual: link to another column', async () => { + const schema = { + users: singlestoreTable('users', { + id: int('id'), + email: text('email'), + generatedEmail: text('generatedEmail').generatedAlwaysAs( + (): SQL => sql`\`email\``, + { mode: 'virtual' }, + ), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'generated-link-column-virtual', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); */ + +test('Default value of character type column: char', async () => { + const schema = { + users: singlestoreTable('users', { + id: int('id'), + sortKey: char('sortKey', { length: 255 }).default('0'), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'default-value-char-column', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('Default value of character type column: varchar', async () => { + const schema = { + users: singlestoreTable('users', { + id: int('id'), + sortKey: varchar('sortKey', { length: 255 }).default('0'), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'default-value-varchar-column', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +// TODO: Unskip this test when views are implemented +/* test('view #1', async () => { + const users = singlestoreTable('users', { id: int('id') }); + const testView = singlestoreView('some_view', { id: int('id') }).as( + sql`select \`drizzle\`.\`users\`.\`id\` AS \`id\` from \`drizzle\`.\`users\``, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'view-1', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); */ + +// TODO: Unskip this test when views are implemented +/* test('view #2', async () => { + const users = singlestoreTable('some_users', { id: int('id') }); + const testView = singlestoreView('some_view', { id: int('id') }).algorithm('temptable').sqlSecurity('definer').as( + sql`SELECT * FROM ${users}`, + ); + + const schema = { + users: users, + testView, + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'view-2', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); */ + +test('handle float type', async () => { + const schema = { + table: singlestoreTable('table', { + col1: float(), + col2: float({ precision: 2 }), + col3: float({ precision: 2, scale: 1 }), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'handle-float-type', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('handle unsigned numerical types', async () => { + const schema = { + table: singlestoreTable('table', { + col1: int({ unsigned: true }), + col2: tinyint({ unsigned: true }), + col3: smallint({ unsigned: true }), + col4: mediumint({ unsigned: true }), + col5: bigint({ mode: 'number', unsigned: true }), + col6: float({ unsigned: true }), + col7: float({ precision: 2, scale: 1, unsigned: true }), + col8: double({ unsigned: true }), + col9: double({ precision: 2, scale: 1, unsigned: true }), + col10: decimal({ unsigned: true }), + col11: decimal({ precision: 2, scale: 1, unsigned: true }), + }), + }; + + const { statements, sqlStatements } = await introspectSingleStoreToFile( + client, + schema, + 'handle-unsigned-numerical-types', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/push/singlestore-push.test.ts b/drizzle-kit/tests/push/singlestore-push.test.ts new file mode 100644 index 000000000..4ad3c6c0e --- /dev/null +++ b/drizzle-kit/tests/push/singlestore-push.test.ts @@ -0,0 +1,266 @@ +import Docker from 'dockerode'; +import { int, singlestoreTable } from 'drizzle-orm/singlestore-core'; +import fs from 'fs'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { diffTestSchemasPushSingleStore } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, expect, test } from 'vitest'; + +let client: Connection; +let singlestoreContainer: Docker.Container; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return `singlestore://root:singlestore@localhost:${port}/`; +} + +beforeAll(async () => { + const connectionString = process.env.MYSQL_CONNECTION_STRING ?? (await createDockerDB()); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); + throw lastError; + } + + await client.query('DROP DATABASE IF EXISTS drizzle;'); + await client.query('CREATE DATABASE drizzle;'); + await client.query('USE drizzle;'); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await singlestoreContainer?.stop().catch(console.error); +}); + +if (!fs.existsSync('tests/push/singlestore')) { + fs.mkdirSync('tests/push/singlestore'); +} + +test('db has checks. Push with same names', async () => { + const schema1 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values').default(1), + }), + }; + const schema2 = { + test: singlestoreTable('test', { + id: int('id').primaryKey(), + values: int('values').default(1), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + ); + + expect(statements).toStrictEqual([]); + expect(sqlStatements).toStrictEqual([]); + + await client.query(`DROP TABLE \`test\`;`); +}); + +// TODO: Unskip this test when views are implemented +/* test.skip.skip('create view', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + }; + + const schema2 = { + test: table, + view: singlestoreView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + definition: 'select `id` from `test`', + name: 'view', + type: 'singlestore_create_view', + replace: false, + sqlSecurity: 'definer', + withCheckOption: undefined, + algorithm: 'undefined', + }, + ]); + expect(sqlStatements).toStrictEqual([ + `CREATE ALGORITHM = undefined +SQL SECURITY definer +VIEW \`view\` AS (select \`id\` from \`test\`);`, + ]); + + await client.query(`DROP TABLE \`test\`;`); +}); */ + +// TODO: Unskip this test when views are implemented +/* test.skip('drop view', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: singlestoreView('view').as((qb) => qb.select().from(table)), + }; + + const schema2 = { + test: table, + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + name: 'view', + type: 'drop_view', + }, + ]); + expect(sqlStatements).toStrictEqual(['DROP VIEW `view`;']); + await client.query(`DROP TABLE \`test\`;`); + await client.query(`DROP VIEW \`view\`;`); +}); */ + +// TODO: Unskip this test when views are implemented +/* test.skip('alter view ".as"', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: singlestoreView('view').as((qb) => + qb + .select() + .from(table) + .where(sql`${table.id} = 1`) + ), + }; + + const schema2 = { + test: table, + view: singlestoreView('view').as((qb) => qb.select().from(table)), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); + + await client.query(`DROP TABLE \`test\`;`); + await client.query(`DROP VIEW \`view\`;`); +}); */ + +// TODO: Unskip this test when views are implemented +/* test.skip('alter meta options with distinct in definition', async () => { + const table = singlestoreTable('test', { + id: int('id').primaryKey(), + }); + + const schema1 = { + test: table, + view: singlestoreView('view') + .withCheckOption('cascaded') + .sqlSecurity('definer') + .algorithm('merge') + .as((qb) => + qb + .selectDistinct() + .from(table) + .where(sql`${table.id} = 1`) + ), + }; + + const schema2 = { + test: table, + view: singlestoreView('view') + .withCheckOption('cascaded') + .sqlSecurity('definer') + .algorithm('undefined') + .as((qb) => qb.selectDistinct().from(table)), + }; + + await expect( + diffTestSchemasPushSingleStore( + client, + schema1, + schema2, + [], + 'drizzle', + false, + ), + ).rejects.toThrowError(); + + await client.query(`DROP TABLE \`test\`;`); +}); */ diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts new file mode 100644 index 000000000..82c72063c --- /dev/null +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -0,0 +1,439 @@ +import Docker from 'dockerode'; +import { SQL, sql } from 'drizzle-orm'; +import { + bigint, + binary, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + primaryKey, + serial, + singlestoreEnum, + singlestoreTable, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, +} from 'drizzle-orm/singlestore-core'; +import getPort from 'get-port'; +import { Connection, createConnection } from 'mysql2/promise'; +import { diffTestSchemasPushSingleStore, diffTestSchemasSingleStore } from 'tests/schemaDiffer'; +import { v4 as uuid } from 'uuid'; +import { expect } from 'vitest'; +import { DialectSuite, run } from './common'; + +async function createDockerDB(context: any): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + context.singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await context.singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return `singlestore://root:singlestore@localhost:${port}/`; +} + +const singlestoreSuite: DialectSuite = { + allTypes: async function(context: any): Promise { + const schema1 = { + allBigInts: singlestoreTable('all_big_ints', { + simple: bigint('simple', { mode: 'number' }), + columnNotNull: bigint('column_not_null', { mode: 'number' }).notNull(), + columnDefault: bigint('column_default', { mode: 'number' }).default(12), + columnDefaultSql: bigint('column_default_sql', { + mode: 'number', + }).default(12), + }), + allBools: singlestoreTable('all_bools', { + simple: tinyint('simple'), + columnNotNull: tinyint('column_not_null').notNull(), + columnDefault: tinyint('column_default').default(1), + }), + allChars: singlestoreTable('all_chars', { + simple: char('simple', { length: 1 }), + columnNotNull: char('column_not_null', { length: 45 }).notNull(), + // columnDefault: char("column_default", { length: 1 }).default("h"), + columnDefaultSql: char('column_default_sql', { length: 1 }).default( + 'h', + ), + }), + // allDateTimes: singlestoreTable("all_date_times", { + // simple: datetime("simple", { mode: "string", fsp: 1 }), + // columnNotNull: datetime("column_not_null", { + // mode: "string", + // }).notNull(), + // columnDefault: datetime("column_default", { mode: "string" }).default( + // "2023-03-01 14:05:29" + // ), + // }), + allDates: singlestoreTable('all_dates', { + simple: date('simple', { mode: 'string' }), + column_not_null: date('column_not_null', { mode: 'string' }).notNull(), + column_default: date('column_default', { mode: 'string' }).default( + '2023-03-01', + ), + }), + allDecimals: singlestoreTable('all_decimals', { + simple: decimal('simple', { precision: 1, scale: 0 }), + columnNotNull: decimal('column_not_null', { + precision: 45, + scale: 3, + }).notNull(), + columnDefault: decimal('column_default', { + precision: 10, + scale: 0, + }).default('100'), + columnDefaultSql: decimal('column_default_sql', { + precision: 10, + scale: 0, + }).default('101'), + }), + + allDoubles: singlestoreTable('all_doubles', { + simple: double('simple'), + columnNotNull: double('column_not_null').notNull(), + columnDefault: double('column_default').default(100), + columnDefaultSql: double('column_default_sql').default(101), + }), + + allEnums: singlestoreTable('all_enums', { + simple: singlestoreEnum('simple', ['hi', 'hello']), + }), + + allEnums1: singlestoreTable('all_enums1', { + simple: singlestoreEnum('simple', ['hi', 'hello']).default('hi'), + }), + + allFloats: singlestoreTable('all_floats', { + columnNotNull: float('column_not_null').notNull(), + columnDefault: float('column_default').default(100), + columnDefaultSql: float('column_default_sql').default(101), + }), + + allInts: singlestoreTable('all_ints', { + simple: int('simple'), + columnNotNull: int('column_not_null').notNull(), + columnDefault: int('column_default').default(100), + columnDefaultSql: int('column_default_sql').default(101), + }), + + allIntsRef: singlestoreTable('all_ints_ref', { + simple: int('simple'), + columnNotNull: int('column_not_null').notNull(), + columnDefault: int('column_default').default(100), + columnDefaultSql: int('column_default_sql').default(101), + }), + + // allJsons: singlestoreTable("all_jsons", { + // columnDefaultObject: json("column_default_object") + // .default({ hello: "world world" }) + // .notNull(), + // columnDefaultArray: json("column_default_array").default({ + // hello: { "world world": ["foo", "bar"] }, + // foo: "bar", + // fe: 23, + // }), + // column: json("column"), + // }), + + allMInts: singlestoreTable('all_m_ints', { + simple: mediumint('simple'), + columnNotNull: mediumint('column_not_null').notNull(), + columnDefault: mediumint('column_default').default(100), + columnDefaultSql: mediumint('column_default_sql').default(101), + }), + + allReals: singlestoreTable('all_reals', { + simple: double('simple', { precision: 5, scale: 2 }), + columnNotNull: double('column_not_null').notNull(), + columnDefault: double('column_default').default(100), + columnDefaultSql: double('column_default_sql').default(101), + }), + + allSInts: singlestoreTable('all_s_ints', { + simple: smallint('simple'), + columnNotNull: smallint('column_not_null').notNull(), + columnDefault: smallint('column_default').default(100), + columnDefaultSql: smallint('column_default_sql').default(101), + }), + + // allSmallSerials: singlestoreTable("all_small_serials", { + // columnAll: serial("column_all").notNull(), + // }), + + allTInts: singlestoreTable('all_t_ints', { + simple: tinyint('simple'), + columnNotNull: tinyint('column_not_null').notNull(), + columnDefault: tinyint('column_default').default(10), + columnDefaultSql: tinyint('column_default_sql').default(11), + }), + + allTexts: singlestoreTable('all_texts', { + simple: text('simple'), + columnNotNull: text('column_not_null').notNull(), + columnDefault: text('column_default').default('hello'), + columnDefaultSql: text('column_default_sql').default('hello'), + }), + + allTimes: singlestoreTable('all_times', { + // simple: time("simple", { fsp: 1 }), + columnNotNull: time('column_not_null').notNull(), + columnDefault: time('column_default').default('22:12:12'), + }), + + allTimestamps: singlestoreTable('all_timestamps', { + // columnDateNow: timestamp("column_date_now", { + // fsp: 1, + // mode: "string", + // }).default(sql`(now())`), + columnAll: timestamp('column_all', { mode: 'string' }) + .default('2023-03-01 14:05:29') + .notNull(), + column: timestamp('column', { mode: 'string' }).default( + '2023-02-28 16:18:31', + ), + }), + + allVarChars: singlestoreTable('all_var_chars', { + simple: varchar('simple', { length: 100 }), + columnNotNull: varchar('column_not_null', { length: 45 }).notNull(), + columnDefault: varchar('column_default', { length: 100 }).default( + 'hello', + ), + columnDefaultSql: varchar('column_default_sql', { + length: 100, + }).default('hello'), + }), + + allVarbinaries: singlestoreTable('all_varbinaries', { + simple: varbinary('simple', { length: 100 }), + columnNotNull: varbinary('column_not_null', { length: 100 }).notNull(), + columnDefault: varbinary('column_default', { length: 12 }), + }), + + allYears: singlestoreTable('all_years', { + simple: year('simple'), + columnNotNull: year('column_not_null').notNull(), + columnDefault: year('column_default').default(2022), + }), + + binafry: singlestoreTable('binary', { + simple: binary('simple', { length: 1 }), + columnNotNull: binary('column_not_null', { length: 1 }).notNull(), + columnDefault: binary('column_default', { length: 12 }), + }), + }; + + const { statements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema1, + [], + 'drizzle', + false, + ); + console.log(statements); + expect(statements.length).toBe(0); + expect(statements).toEqual([]); + + const { sqlStatements: dropStatements } = await diffTestSchemasSingleStore( + schema1, + {}, + [], + false, + ); + + for (const st of dropStatements) { + await context.client.query(st); + } + }, + addBasicIndexes: function(context?: any): Promise { + return {} as any; + }, + changeIndexFields: function(context?: any): Promise { + return {} as any; + }, + dropIndex: function(context?: any): Promise { + return {} as any; + }, + indexesToBeNotTriggered: function(context?: any): Promise { + return {} as any; + }, + indexesTestCase1: function(context?: any): Promise { + return {} as any; + }, + async case1() { + // TODO: implement if needed + expect(true).toBe(true); + }, + addNotNull: function(context?: any): Promise { + return {} as any; + }, + addNotNullWithDataNoRollback: function(context?: any): Promise { + return {} as any; + }, + addBasicSequences: function(context?: any): Promise { + return {} as any; + }, + addGeneratedColumn: async function(context: any): Promise { + return {} as any; + }, + addGeneratedToColumn: async function(context: any): Promise { + return {} as any; + }, + dropGeneratedConstraint: async function(context: any): Promise { + return {} as any; + }, + alterGeneratedConstraint: async function(context: any): Promise { + return {} as any; + }, + createTableWithGeneratedConstraint: function(context?: any): Promise { + return {} as any; + }, + createCompositePrimaryKey: async function(context: any): Promise { + const schema1 = {}; + + const schema2 = { + table: singlestoreTable('table', { + col1: int('col1').notNull(), + col2: int('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table', + schema: undefined, + internals: { + indexes: {}, + tables: {}, + }, + compositePKs: ['table_col1_col2_pk;col1,col2'], + compositePkName: 'table_col1_col2_pk', + uniqueConstraints: [], + columns: [ + { name: 'col1', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + { name: 'col2', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + ], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `table` (\n\t`col1` int NOT NULL,\n\t`col2` int NOT NULL,\n\tCONSTRAINT `table_col1_col2_pk` PRIMARY KEY(`col1`,`col2`)\n);\n', + ]); + }, + renameTableWithCompositePrimaryKey: async function(context?: any): Promise { + const productsCategoriesTable = (tableName: string) => { + return singlestoreTable(tableName, { + productId: varchar('product_id', { length: 10 }).notNull(), + categoryId: varchar('category_id', { length: 10 }).notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPushSingleStore( + context.client as Connection, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + 'drizzle', + false, + ); + + // It's not possible to create/alter/drop primary keys in SingleStore + expect(sqlStatements).toStrictEqual([ + 'RENAME TABLE `products_categories` TO `products_to_categories`;', + ]); + + await context.client.query(`DROP TABLE \`products_categories\``); + }, +}; + +run( + singlestoreSuite, + async (context: any) => { + const connectionString = process.env.SINGLESTORE_CONNECTION_STRING + ?? (await createDockerDB(context)); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + context.client = await createConnection(connectionString); + await context.client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to SingleStore'); + await context.client?.end().catch(console.error); + await context.singlestoreContainer?.stop().catch(console.error); + throw lastError; + } + + await context.client.query(`DROP DATABASE IF EXISTS \`drizzle\`;`); + await context.client.query('CREATE DATABASE drizzle;'); + await context.client.query('USE drizzle;'); + }, + async (context: any) => { + await context.client?.end().catch(console.error); + await context.singlestoreContainer?.stop().catch(console.error); + }, +); diff --git a/drizzle-kit/tests/schemaDiffer.ts b/drizzle-kit/tests/schemaDiffer.ts index adc7aecbf..9c7f212aa 100644 --- a/drizzle-kit/tests/schemaDiffer.ts +++ b/drizzle-kit/tests/schemaDiffer.ts @@ -18,6 +18,7 @@ import { PgTable, PgView, } from 'drizzle-orm/pg-core'; +import { SingleStoreSchema, SingleStoreTable } from 'drizzle-orm/singlestore-core'; import { SQLiteTable, SQLiteView } from 'drizzle-orm/sqlite-core'; import * as fs from 'fs'; import { Connection } from 'mysql2/promise'; @@ -42,22 +43,28 @@ import { Entities } from 'src/cli/validations/cli'; import { CasingType } from 'src/cli/validations/common'; import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql'; import { schemaToTypeScript } from 'src/introspect-pg'; +import { schemaToTypeScript as schemaToTypeScriptSingleStore } from 'src/introspect-singlestore'; import { schemaToTypeScript as schemaToTypeScriptSQLite } from 'src/introspect-sqlite'; import { prepareFromMySqlImports } from 'src/serializer/mysqlImports'; import { mysqlSchema, squashMysqlScheme, ViewSquashed } from 'src/serializer/mysqlSchema'; -import { generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; -import { fromDatabase as fromMySqlDatabase } from 'src/serializer/mysqlSerializer'; +import { fromDatabase as fromMySqlDatabase, generateMySqlSnapshot } from 'src/serializer/mysqlSerializer'; import { prepareFromPgImports } from 'src/serializer/pgImports'; -import { pgSchema, PgSquasher, Policy, Role, squashPgScheme, View } from 'src/serializer/pgSchema'; +import { pgSchema, Policy, Role, squashPgScheme, View } from 'src/serializer/pgSchema'; import { fromDatabase, generatePgSnapshot } from 'src/serializer/pgSerializer'; +import { prepareFromSingleStoreImports } from 'src/serializer/singlestoreImports'; +import { singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema'; +import { + fromDatabase as fromSingleStoreDatabase, + generateSingleStoreSnapshot, +} from 'src/serializer/singlestoreSerializer'; import { prepareFromSqliteImports } from 'src/serializer/sqliteImports'; import { sqliteSchema, squashSqliteScheme, View as SqliteView } from 'src/serializer/sqliteSchema'; -import { fromDatabase as fromSqliteDatabase } from 'src/serializer/sqliteSerializer'; -import { generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; +import { fromDatabase as fromSqliteDatabase, generateSqliteSnapshot } from 'src/serializer/sqliteSerializer'; import { applyLibSQLSnapshotsDiff, applyMysqlSnapshotsDiff, applyPgSnapshotsDiff, + applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, Column, ColumnsResolverInput, @@ -78,15 +85,33 @@ import { export type PostgresSchema = Record< string, - PgTable | PgEnum | PgSchema | PgSequence | PgView | PgMaterializedView | PgRole | PgPolicy + | PgTable + | PgEnum + | PgSchema + | PgSequence + | PgView + | PgMaterializedView + | PgRole + | PgPolicy +>; +export type MysqlSchema = Record< + string, + MySqlTable | MySqlSchema | MySqlView >; -export type MysqlSchema = Record | MySqlSchema | MySqlView>; export type SqliteSchema = Record | SQLiteView>; +export type SinglestoreSchema = Record< + string, + SingleStoreTable | SingleStoreSchema /* | SingleStoreView */ +>; export const testSchemasResolver = (renames: Set) => async (input: ResolverInput): Promise> => { try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { return { created: input.created, renamed: [], @@ -138,273 +163,297 @@ export const testSchemasResolver = } }; -export const testSequencesResolver = - (renames: Set) => async (input: ResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } +export const testSequencesResolver = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - let createdSequences = [...input.created]; - let deletedSequences = [...input.deleted]; + let createdSequences = [...input.created]; + let deletedSequences = [...input.deleted]; - const result: { - created: Sequence[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Sequence; to: Sequence }[]; - deleted: Sequence[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + const result: { + created: Sequence[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Sequence; to: Sequence }[]; + deleted: Sequence[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - for (let rename of renames) { - const [from, to] = rename.split('->'); + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedSequences.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); - const idxFrom = deletedSequences.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; + if (idxFrom >= 0) { + const idxTo = createdSequences.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdSequences.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const tableFrom = deletedSequences[idxFrom]; + const tableTo = createdSequences[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, }); + } - const tableFrom = deletedSequences[idxFrom]; - const tableTo = createdSequences[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, - }); - } - - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedSequences[idxFrom], - to: createdSequences[idxTo], - }); - } - - delete createdSequences[idxTo]; - delete deletedSequences[idxFrom]; - - createdSequences = createdSequences.filter(Boolean); - deletedSequences = deletedSequences.filter(Boolean); + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedSequences[idxFrom], + to: createdSequences[idxTo], + }); } + + delete createdSequences[idxTo]; + delete deletedSequences[idxFrom]; + + createdSequences = createdSequences.filter(Boolean); + deletedSequences = deletedSequences.filter(Boolean); } + } - result.created = createdSequences; - result.deleted = deletedSequences; + result.created = createdSequences; + result.deleted = deletedSequences; - return result; - } catch (e) { - console.error(e); - throw e; + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const testEnumsResolver = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; } - }; -export const testEnumsResolver = - (renames: Set) => async (input: ResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } + let createdEnums = [...input.created]; + let deletedEnums = [...input.deleted]; - let createdEnums = [...input.created]; - let deletedEnums = [...input.deleted]; + const result: { + created: Enum[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Enum; to: Enum }[]; + deleted: Enum[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const result: { - created: Enum[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Enum; to: Enum }[]; - deleted: Enum[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + for (let rename of renames) { + const [from, to] = rename.split('->'); - for (let rename of renames) { - const [from, to] = rename.split('->'); + const idxFrom = deletedEnums.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); - const idxFrom = deletedEnums.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; + if (idxFrom >= 0) { + const idxTo = createdEnums.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdEnums.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const tableFrom = deletedEnums[idxFrom]; + const tableTo = createdEnums[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, }); + } - const tableFrom = deletedEnums[idxFrom]; - const tableTo = createdEnums[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, - }); - } - - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedEnums[idxFrom], - to: createdEnums[idxTo], - }); - } - - delete createdEnums[idxTo]; - delete deletedEnums[idxFrom]; - - createdEnums = createdEnums.filter(Boolean); - deletedEnums = deletedEnums.filter(Boolean); + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedEnums[idxFrom], + to: createdEnums[idxTo], + }); } + + delete createdEnums[idxTo]; + delete deletedEnums[idxFrom]; + + createdEnums = createdEnums.filter(Boolean); + deletedEnums = deletedEnums.filter(Boolean); } + } - result.created = createdEnums; - result.deleted = deletedEnums; + result.created = createdEnums; + result.deleted = deletedEnums; - return result; - } catch (e) { - console.error(e); - throw e; + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const testTablesResolver = (renames: Set) => +async ( + input: ResolverInput
, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; } - }; -export const testTablesResolver = - (renames: Set) => async (input: ResolverInput
): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } + let createdTables = [...input.created]; + let deletedTables = [...input.deleted]; - let createdTables = [...input.created]; - let deletedTables = [...input.deleted]; + const result: { + created: Table[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: Table; to: Table }[]; + deleted: Table[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const result: { - created: Table[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: Table; to: Table }[]; - deleted: Table[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + for (let rename of renames) { + const [from, to] = rename.split('->'); - for (let rename of renames) { - const [from, to] = rename.split('->'); + const idxFrom = deletedTables.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); - const idxFrom = deletedTables.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; + if (idxFrom >= 0) { + const idxTo = createdTables.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdTables.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const tableFrom = deletedTables[idxFrom]; + const tableTo = createdTables[idxFrom]; + + if (tableFrom.schema !== tableTo.schema) { + result.moved.push({ + name: tableFrom.name, + schemaFrom: tableFrom.schema, + schemaTo: tableTo.schema, }); + } - const tableFrom = deletedTables[idxFrom]; - const tableTo = createdTables[idxFrom]; - - if (tableFrom.schema !== tableTo.schema) { - result.moved.push({ - name: tableFrom.name, - schemaFrom: tableFrom.schema, - schemaTo: tableTo.schema, - }); - } - - if (tableFrom.name !== tableTo.name) { - result.renamed.push({ - from: deletedTables[idxFrom], - to: createdTables[idxTo], - }); - } - - delete createdTables[idxTo]; - delete deletedTables[idxFrom]; - - createdTables = createdTables.filter(Boolean); - deletedTables = deletedTables.filter(Boolean); + if (tableFrom.name !== tableTo.name) { + result.renamed.push({ + from: deletedTables[idxFrom], + to: createdTables[idxTo], + }); } + + delete createdTables[idxTo]; + delete deletedTables[idxFrom]; + + createdTables = createdTables.filter(Boolean); + deletedTables = deletedTables.filter(Boolean); } + } - result.created = createdTables; - result.deleted = deletedTables; + result.created = createdTables; + result.deleted = deletedTables; - return result; - } catch (e) { - console.error(e); - throw e; + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const testColumnsResolver = (renames: Set) => +async ( + input: ColumnsResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + tableName: input.tableName, + schema: input.schema, + created: input.created, + renamed: [], + deleted: input.deleted, + }; } - }; -export const testColumnsResolver = - (renames: Set) => async (input: ColumnsResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - tableName: input.tableName, - schema: input.schema, - created: input.created, - renamed: [], - deleted: input.deleted, - }; - } + let createdColumns = [...input.created]; + let deletedColumns = [...input.deleted]; - let createdColumns = [...input.created]; - let deletedColumns = [...input.deleted]; + const renamed: { from: Column; to: Column }[] = []; - const renamed: { from: Column; to: Column }[] = []; + const schema = input.schema || 'public'; - const schema = input.schema || 'public'; + for (let rename of renames) { + const [from, to] = rename.split('->'); - for (let rename of renames) { - const [from, to] = rename.split('->'); + const idxFrom = deletedColumns.findIndex((it) => { + return `${schema}.${input.tableName}.${it.name}` === from; + }); - const idxFrom = deletedColumns.findIndex((it) => { - return `${schema}.${input.tableName}.${it.name}` === from; + if (idxFrom >= 0) { + const idxTo = createdColumns.findIndex((it) => { + return `${schema}.${input.tableName}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdColumns.findIndex((it) => { - return `${schema}.${input.tableName}.${it.name}` === to; - }); - - renamed.push({ - from: deletedColumns[idxFrom], - to: createdColumns[idxTo], - }); + renamed.push({ + from: deletedColumns[idxFrom], + to: createdColumns[idxTo], + }); - delete createdColumns[idxTo]; - delete deletedColumns[idxFrom]; + delete createdColumns[idxTo]; + delete deletedColumns[idxFrom]; - createdColumns = createdColumns.filter(Boolean); - deletedColumns = deletedColumns.filter(Boolean); - } + createdColumns = createdColumns.filter(Boolean); + deletedColumns = deletedColumns.filter(Boolean); } - - return { - tableName: input.tableName, - schema: input.schema, - created: createdColumns, - deleted: deletedColumns, - renamed, - }; - } catch (e) { - console.error(e); - throw e; } - }; + + return { + tableName: input.tableName, + schema: input.schema, + created: createdColumns, + deleted: deletedColumns, + renamed, + }; + } catch (e) { + console.error(e); + throw e; + } +}; export const testPolicyResolver = (renames: Set) => async ( @@ -586,208 +635,301 @@ async ( } }; -export const testViewsResolver = - (renames: Set) => async (input: ResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } +export const testViewsResolver = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } - let createdViews = [...input.created]; - let deletedViews = [...input.deleted]; + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; - const result: { - created: View[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: View; to: View }[]; - deleted: View[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + const result: { + created: View[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: View; to: View }[]; + deleted: View[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - for (let rename of renames) { - const [from, to] = rename.split('->'); + for (let rename of renames) { + const [from, to] = rename.split('->'); - const idxFrom = deletedViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; - }); + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; - const viewFrom = deletedViews[idxFrom]; - const viewTo = createdViews[idxFrom]; - - if (viewFrom.schema !== viewTo.schema) { - result.moved.push({ - name: viewFrom.name, - schemaFrom: viewFrom.schema, - schemaTo: viewTo.schema, - }); - } - - if (viewFrom.name !== viewTo.name) { - result.renamed.push({ - from: deletedViews[idxFrom], - to: createdViews[idxTo], - }); - } - - delete createdViews[idxTo]; - delete deletedViews[idxFrom]; - - createdViews = createdViews.filter(Boolean); - deletedViews = deletedViews.filter(Boolean); + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, + }); } - } - result.created = createdViews; - result.deleted = deletedViews; + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); + } - return result; - } catch (e) { - console.error(e); - throw e; - } - }; + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; -export const testViewsResolverMySql = - (renames: Set) => - async (input: ResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); } + } - let createdViews = [...input.created]; - let deletedViews = [...input.deleted]; - - const result: { - created: ViewSquashed[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: ViewSquashed; to: ViewSquashed }[]; - deleted: ViewSquashed[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + result.created = createdViews; + result.deleted = deletedViews; - for (let rename of renames) { - const [from, to] = rename.split('->'); + return result; + } catch (e) { + console.error(e); + throw e; + } +}; - const idxFrom = deletedViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === from; +export const testViewsResolverMySql = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } + + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; + + const result: { + created: ViewSquashed[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: ViewSquashed; to: ViewSquashed }[]; + deleted: ViewSquashed[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdViews.findIndex((it) => { - return `${it.schema || 'public'}.${it.name}` === to; + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, }); + } - const viewFrom = deletedViews[idxFrom]; - const viewTo = createdViews[idxFrom]; - - if (viewFrom.schema !== viewTo.schema) { - result.moved.push({ - name: viewFrom.name, - schemaFrom: viewFrom.schema, - schemaTo: viewTo.schema, - }); - } - - if (viewFrom.name !== viewTo.name) { - result.renamed.push({ - from: deletedViews[idxFrom], - to: createdViews[idxTo], - }); - } - - delete createdViews[idxTo]; - delete deletedViews[idxFrom]; - - createdViews = createdViews.filter(Boolean); - deletedViews = deletedViews.filter(Boolean); + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); } + } - result.created = createdViews; - result.deleted = deletedViews; + result.created = createdViews; + result.deleted = deletedViews; - return result; - } catch (e) { - console.error(e); - throw e; + return result; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const testViewsResolverSingleStore = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; } - }; -export const testViewsResolverSqlite = - (renames: Set) => async (input: ResolverInput): Promise> => { - try { - if (input.created.length === 0 || input.deleted.length === 0 || renames.size === 0) { - return { - created: input.created, - moved: [], - renamed: [], - deleted: input.deleted, - }; - } + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; - let createdViews = [...input.created]; - let deletedViews = [...input.deleted]; + const result: { + created: ViewSquashed[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: ViewSquashed; to: ViewSquashed }[]; + deleted: ViewSquashed[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; - const result: { - created: SqliteView[]; - moved: { name: string; schemaFrom: string; schemaTo: string }[]; - renamed: { from: SqliteView; to: SqliteView }[]; - deleted: SqliteView[]; - } = { created: [], renamed: [], deleted: [], moved: [] }; + for (let rename of renames) { + const [from, to] = rename.split('->'); - for (let rename of renames) { - const [from, to] = rename.split('->'); + const idxFrom = deletedViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === from; + }); - const idxFrom = deletedViews.findIndex((it) => { - return it.name === from; + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return `${it.schema || 'public'}.${it.name}` === to; }); - if (idxFrom >= 0) { - const idxTo = createdViews.findIndex((it) => { - return it.name === to; + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; + + if (viewFrom.schema !== viewTo.schema) { + result.moved.push({ + name: viewFrom.name, + schemaFrom: viewFrom.schema, + schemaTo: viewTo.schema, + }); + } + + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], }); + } + + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; + + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } + } + + result.created = createdViews; + result.deleted = deletedViews; - const viewFrom = deletedViews[idxFrom]; - const viewTo = createdViews[idxFrom]; + return result; + } catch (e) { + console.error(e); + throw e; + } +}; - if (viewFrom.name !== viewTo.name) { - result.renamed.push({ - from: deletedViews[idxFrom], - to: createdViews[idxTo], - }); - } +export const testViewsResolverSqlite = (renames: Set) => +async ( + input: ResolverInput, +): Promise> => { + try { + if ( + input.created.length === 0 + || input.deleted.length === 0 + || renames.size === 0 + ) { + return { + created: input.created, + moved: [], + renamed: [], + deleted: input.deleted, + }; + } + + let createdViews = [...input.created]; + let deletedViews = [...input.deleted]; + + const result: { + created: SqliteView[]; + moved: { name: string; schemaFrom: string; schemaTo: string }[]; + renamed: { from: SqliteView; to: SqliteView }[]; + deleted: SqliteView[]; + } = { created: [], renamed: [], deleted: [], moved: [] }; + + for (let rename of renames) { + const [from, to] = rename.split('->'); + + const idxFrom = deletedViews.findIndex((it) => { + return it.name === from; + }); + + if (idxFrom >= 0) { + const idxTo = createdViews.findIndex((it) => { + return it.name === to; + }); - delete createdViews[idxTo]; - delete deletedViews[idxFrom]; + const viewFrom = deletedViews[idxFrom]; + const viewTo = createdViews[idxFrom]; - createdViews = createdViews.filter(Boolean); - deletedViews = deletedViews.filter(Boolean); + if (viewFrom.name !== viewTo.name) { + result.renamed.push({ + from: deletedViews[idxFrom], + to: createdViews[idxTo], + }); } - } - result.created = createdViews; - result.deleted = deletedViews; + delete createdViews[idxTo]; + delete deletedViews[idxFrom]; - return result; - } catch (e) { - console.error(e); - throw e; + createdViews = createdViews.filter(Boolean); + deletedViews = deletedViews.filter(Boolean); + } } - }; + + result.created = createdViews; + result.deleted = deletedViews; + + return result; + } catch (e) { + console.error(e); + throw e; + } +}; export const diffTestSchemasPush = async ( client: PGlite, @@ -798,13 +940,19 @@ export const diffTestSchemasPush = async ( schemas: string[] = ['public'], casing?: CasingType | undefined, entities?: Entities, - sqlStatementsToRun: { before?: string[]; after?: string[]; runApply?: boolean } = { + sqlStatementsToRun: { + before?: string[]; + after?: string[]; + runApply?: boolean; + } = { before: [], after: [], runApply: true, }, ) => { - const shouldRunApply = sqlStatementsToRun.runApply === undefined ? true : sqlStatementsToRun.runApply; + const shouldRunApply = sqlStatementsToRun.runApply === undefined + ? true + : sqlStatementsToRun.runApply; for (const st of sqlStatementsToRun.before ?? []) { await client.query(st); @@ -837,6 +985,19 @@ export const diffTestSchemasPush = async ( ); } + // do introspect into PgSchemaInternal + const introspectedSchema = await fromDatabase( + { + query: async (query: string, values?: any[] | undefined) => { + const res = await client.query(query, values); + return res.rows as any[]; + }, + }, + undefined, + schemas, + entities, + ); + const leftTables = Object.values(right).filter((it) => is(it, PgTable)) as PgTable[]; const leftSchemas = Object.values(right).filter((it) => is(it, PgSchema)) as PgSchema[]; @@ -865,21 +1026,6 @@ export const diffTestSchemasPush = async ( casing, ); - // do introspect into PgSchemaInternal - const introspectedSchema = await fromDatabase( - { - query: async (query: string, values?: any[] | undefined) => { - const res = await client.query(query, values); - return res.rows as any[]; - }, - }, - undefined, - schemas, - entities, - undefined, - serialized2, - ); - const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; @@ -975,7 +1121,10 @@ export const diffTestSchemasPush = async ( } }; -export const applyPgDiffs = async (sn: PostgresSchema, casing: CasingType | undefined) => { +export const applyPgDiffs = async ( + sn: PostgresSchema, + casing: CasingType | undefined, +) => { const dryRun = { version: '7', dialect: 'postgresql', @@ -1122,81 +1271,366 @@ export const diffTestSchemas = async ( const { version: v2, dialect: d2, ...rest2 } = serialized2; const sch1 = { - version: '7', - dialect: 'postgresql', + version: '7', + dialect: 'postgresql', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '7', + dialect: 'postgresql', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashPgScheme(sch1); + const sn2 = squashPgScheme(sch2); + + const validatedPrev = pgSchema.parse(sch1); + const validatedCur = pgSchema.parse(sch2); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements } = await applyPgSnapshotsDiff( + sn1, + sn2, + testSchemasResolver(renames), + testEnumsResolver(renames), + testSequencesResolver(renames), + testPolicyResolver(renames), + testIndPolicyResolver(renames), + testRolesResolver(renames), + testTablesResolver(renames), + testColumnsResolver(renames), + testViewsResolver(renames), + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; + } else { + const { sqlStatements, statements } = await applyPgSnapshotsDiff( + sn1, + sn2, + schemasResolver, + enumsResolver, + sequencesResolver, + policyResolver, + indPolicyResolver, + roleResolver, + tablesResolver, + columnsResolver, + viewsResolver, + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; + } +}; + +export const diffTestSchemasPushMysql = async ( + client: Connection, + left: MysqlSchema, + right: MysqlSchema, + renamesArr: string[], + schema: string, + cli: boolean = false, + casing?: CasingType | undefined, +) => { + const { sqlStatements } = await applyMySqlDiffs(left, casing); + for (const st of sqlStatements) { + await client.query(st); + } + // do introspect into PgSchemaInternal + const introspectedSchema = await fromMySqlDatabase( + { + query: async (sql: string, params?: any[]) => { + const res = await client.execute(sql, params); + return res[0] as any; + }, + }, + schema, + ); + + const leftTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[]; + + const leftViews = Object.values(right).filter((it) => is(it, MySqlView)) as MySqlView[]; + + const serialized2 = generateMySqlSnapshot(leftTables, leftViews, casing); + + const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '5', + dialect: 'mysql', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '5', + dialect: 'mysql', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashMysqlScheme(sch1); + const sn2 = squashMysqlScheme(sch2); + + const validatedPrev = mysqlSchema.parse(sch1); + const validatedCur = mysqlSchema.parse(sch2); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements } = await applyMysqlSnapshotsDiff( + sn1, + sn2, + testTablesResolver(renames), + testColumnsResolver(renames), + testViewsResolverMySql(renames), + validatedPrev, + validatedCur, + 'push', + ); + return { sqlStatements, statements }; + } else { + const { sqlStatements, statements } = await applyMysqlSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + mySqlViewsResolver, + validatedPrev, + validatedCur, + 'push', + ); + return { sqlStatements, statements }; + } +}; + +export const applyMySqlDiffs = async ( + sn: MysqlSchema, + casing: CasingType | undefined, +) => { + const dryRun = { + version: '5', + dialect: 'mysql', + id: '0', + prevId: '0', + views: {}, + tables: {}, + enums: {}, + schemas: {}, + _meta: { + schemas: {}, + tables: {}, + columns: {}, + }, + } as const; + + const tables = Object.values(sn).filter((it) => is(it, MySqlTable)) as MySqlTable[]; + + const views = Object.values(sn).filter((it) => is(it, MySqlView)) as MySqlView[]; + + const serialized1 = generateMySqlSnapshot(tables, views, casing); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + + const sch1 = { + version: '5', + dialect: 'mysql', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sn1 = squashMysqlScheme(sch1); + + const validatedPrev = mysqlSchema.parse(dryRun); + const validatedCur = mysqlSchema.parse(sch1); + + const { sqlStatements, statements } = await applyMysqlSnapshotsDiff( + dryRun, + sn1, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + testViewsResolverMySql(new Set()), + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; +}; + +export const diffTestSchemasMysql = async ( + left: MysqlSchema, + right: MysqlSchema, + renamesArr: string[], + cli: boolean = false, + casing?: CasingType | undefined, +) => { + const leftTables = Object.values(left).filter((it) => is(it, MySqlTable)) as MySqlTable[]; + + const leftViews = Object.values(left).filter((it) => is(it, MySqlView)) as MySqlView[]; + + const rightTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[]; + + const rightViews = Object.values(right).filter((it) => is(it, MySqlView)) as MySqlView[]; + + const serialized1 = generateMySqlSnapshot(leftTables, leftViews, casing); + const serialized2 = generateMySqlSnapshot(rightTables, rightViews, casing); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '5', + dialect: 'mysql', + id: '0', + prevId: '0', + ...rest1, + } as const; + + const sch2 = { + version: '5', + dialect: 'mysql', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn1 = squashMysqlScheme(sch1); + const sn2 = squashMysqlScheme(sch2); + + const validatedPrev = mysqlSchema.parse(sch1); + const validatedCur = mysqlSchema.parse(sch2); + + const renames = new Set(renamesArr); + + if (!cli) { + const { sqlStatements, statements } = await applyMysqlSnapshotsDiff( + sn1, + sn2, + testTablesResolver(renames), + testColumnsResolver(renames), + testViewsResolverMySql(renames), + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; + } + + const { sqlStatements, statements } = await applyMysqlSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + mySqlViewsResolver, + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; +}; + +export const diffTestSchemasSingleStore = async ( + left: SinglestoreSchema, + right: SinglestoreSchema, + renamesArr: string[], + cli: boolean = false, + casing?: CasingType | undefined, +) => { + const leftTables = Object.values(left).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + /* const leftViews = Object.values(left).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */ + + const rightTables = Object.values(right).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + /* const rightViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */ + + const serialized1 = generateSingleStoreSnapshot( + leftTables, + /* leftViews, */ + casing, + ); + const serialized2 = generateSingleStoreSnapshot( + rightTables, + /* rightViews, */ + casing, + ); + + const { version: v1, dialect: d1, ...rest1 } = serialized1; + const { version: v2, dialect: d2, ...rest2 } = serialized2; + + const sch1 = { + version: '1', + dialect: 'singlestore', id: '0', prevId: '0', ...rest1, } as const; const sch2 = { - version: '7', - dialect: 'postgresql', + version: '1', + dialect: 'singlestore', id: '0', prevId: '0', ...rest2, } as const; - const sn1 = squashPgScheme(sch1); - const sn2 = squashPgScheme(sch2); + const sn1 = squashSingleStoreScheme(sch1); + const sn2 = squashSingleStoreScheme(sch2); - const validatedPrev = pgSchema.parse(sch1); - const validatedCur = pgSchema.parse(sch2); + const validatedPrev = singlestoreSchema.parse(sch1); + const validatedCur = singlestoreSchema.parse(sch2); const renames = new Set(renamesArr); if (!cli) { - const { sqlStatements, statements } = await applyPgSnapshotsDiff( + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( sn1, sn2, - testSchemasResolver(renames), - testEnumsResolver(renames), - testSequencesResolver(renames), - testPolicyResolver(renames), - testIndPolicyResolver(renames), - testRolesResolver(renames), testTablesResolver(renames), testColumnsResolver(renames), - testViewsResolver(renames), - validatedPrev, - validatedCur, - ); - return { sqlStatements, statements }; - } else { - const { sqlStatements, statements } = await applyPgSnapshotsDiff( - sn1, - sn2, - schemasResolver, - enumsResolver, - sequencesResolver, - policyResolver, - indPolicyResolver, - roleResolver, - tablesResolver, - columnsResolver, - viewsResolver, + /* testViewsResolverSingleStore(renames), */ validatedPrev, validatedCur, ); return { sqlStatements, statements }; } + + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( + sn1, + sn2, + tablesResolver, + columnsResolver, + /* singleStoreViewsResolver, */ + validatedPrev, + validatedCur, + ); + return { sqlStatements, statements }; }; -export const diffTestSchemasPushMysql = async ( +export const diffTestSchemasPushSingleStore = async ( client: Connection, - left: MysqlSchema, - right: MysqlSchema, + left: SinglestoreSchema, + right: SinglestoreSchema, renamesArr: string[], schema: string, cli: boolean = false, casing?: CasingType | undefined, ) => { - const { sqlStatements } = await applyMySqlDiffs(left, casing); + const { sqlStatements } = await applySingleStoreDiffs(left, casing); for (const st of sqlStatements) { await client.query(st); } // do introspect into PgSchemaInternal - const introspectedSchema = await fromMySqlDatabase( + const introspectedSchema = await fromSingleStoreDatabase( { query: async (sql: string, params?: any[]) => { const res = await client.execute(sql, params); @@ -1206,58 +1640,62 @@ export const diffTestSchemasPushMysql = async ( schema, ); - const leftTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[]; + const leftTables = Object.values(right).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; - const leftViews = Object.values(right).filter((it) => is(it, MySqlView)) as MySqlView[]; + /* const leftViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */ - const serialized2 = generateMySqlSnapshot(leftTables, leftViews, casing); + const serialized2 = generateSingleStoreSnapshot( + leftTables, + /* leftViews, */ + casing, + ); const { version: v1, dialect: d1, ...rest1 } = introspectedSchema; const { version: v2, dialect: d2, ...rest2 } = serialized2; const sch1 = { - version: '5', - dialect: 'mysql', + version: '1', + dialect: 'singlestore', id: '0', prevId: '0', ...rest1, } as const; const sch2 = { - version: '5', - dialect: 'mysql', + version: '1', + dialect: 'singlestore', id: '0', prevId: '0', ...rest2, } as const; - const sn1 = squashMysqlScheme(sch1); - const sn2 = squashMysqlScheme(sch2); + const sn1 = squashSingleStoreScheme(sch1); + const sn2 = squashSingleStoreScheme(sch2); - const validatedPrev = mysqlSchema.parse(sch1); - const validatedCur = mysqlSchema.parse(sch2); + const validatedPrev = singlestoreSchema.parse(sch1); + const validatedCur = singlestoreSchema.parse(sch2); const renames = new Set(renamesArr); if (!cli) { - const { sqlStatements, statements } = await applyMysqlSnapshotsDiff( + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( sn1, sn2, testTablesResolver(renames), testColumnsResolver(renames), - testViewsResolverMySql(renames), + /* testViewsResolverSingleStore(renames), */ validatedPrev, validatedCur, 'push', ); return { sqlStatements, statements }; } else { - const { sqlStatements, statements } = await applyMysqlSnapshotsDiff( + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( sn1, sn2, tablesResolver, columnsResolver, - mySqlViewsResolver, + /* singleStoreViewsResolver, */ validatedPrev, validatedCur, 'push', @@ -1266,14 +1704,17 @@ export const diffTestSchemasPushMysql = async ( } }; -export const applyMySqlDiffs = async (sn: MysqlSchema, casing: CasingType | undefined) => { +export const applySingleStoreDiffs = async ( + sn: SinglestoreSchema, + casing: CasingType | undefined, +) => { const dryRun = { - version: '5', - dialect: 'mysql', + version: '1', + dialect: 'singlestore', id: '0', prevId: '0', - views: {}, tables: {}, + views: {}, enums: {}, schemas: {}, _meta: { @@ -1283,103 +1724,33 @@ export const applyMySqlDiffs = async (sn: MysqlSchema, casing: CasingType | unde }, } as const; - const tables = Object.values(sn).filter((it) => is(it, MySqlTable)) as MySqlTable[]; + const tables = Object.values(sn).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; - const views = Object.values(sn).filter((it) => is(it, MySqlView)) as MySqlView[]; + /* const views = Object.values(sn).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */ - const serialized1 = generateMySqlSnapshot(tables, views, casing); + const serialized1 = generateSingleStoreSnapshot(tables, /* views, */ casing); const { version: v1, dialect: d1, ...rest1 } = serialized1; const sch1 = { - version: '5', - dialect: 'mysql', + version: '1', + dialect: 'singlestore', id: '0', prevId: '0', ...rest1, } as const; - const sn1 = squashMysqlScheme(sch1); + const sn1 = squashSingleStoreScheme(sch1); - const validatedPrev = mysqlSchema.parse(dryRun); - const validatedCur = mysqlSchema.parse(sch1); + const validatedPrev = singlestoreSchema.parse(dryRun); + const validatedCur = singlestoreSchema.parse(sch1); - const { sqlStatements, statements } = await applyMysqlSnapshotsDiff( + const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff( dryRun, sn1, testTablesResolver(new Set()), testColumnsResolver(new Set()), - testViewsResolverMySql(new Set()), - validatedPrev, - validatedCur, - ); - return { sqlStatements, statements }; -}; - -export const diffTestSchemasMysql = async ( - left: MysqlSchema, - right: MysqlSchema, - renamesArr: string[], - cli: boolean = false, - casing?: CasingType | undefined, -) => { - const leftTables = Object.values(left).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - - const leftViews = Object.values(left).filter((it) => is(it, MySqlView)) as MySqlView[]; - - const rightTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[]; - - const rightViews = Object.values(right).filter((it) => is(it, MySqlView)) as MySqlView[]; - - const serialized1 = generateMySqlSnapshot(leftTables, leftViews, casing); - const serialized2 = generateMySqlSnapshot(rightTables, rightViews, casing); - - const { version: v1, dialect: d1, ...rest1 } = serialized1; - const { version: v2, dialect: d2, ...rest2 } = serialized2; - - const sch1 = { - version: '5', - dialect: 'mysql', - id: '0', - prevId: '0', - ...rest1, - } as const; - - const sch2 = { - version: '5', - dialect: 'mysql', - id: '0', - prevId: '0', - ...rest2, - } as const; - - const sn1 = squashMysqlScheme(sch1); - const sn2 = squashMysqlScheme(sch2); - - const validatedPrev = mysqlSchema.parse(sch1); - const validatedCur = mysqlSchema.parse(sch2); - - const renames = new Set(renamesArr); - - if (!cli) { - const { sqlStatements, statements } = await applyMysqlSnapshotsDiff( - sn1, - sn2, - testTablesResolver(renames), - testColumnsResolver(renames), - testViewsResolverMySql(renames), - validatedPrev, - validatedCur, - ); - return { sqlStatements, statements }; - } - - const { sqlStatements, statements } = await applyMysqlSnapshotsDiff( - sn1, - sn2, - tablesResolver, - columnsResolver, - mySqlViewsResolver, + /* testViewsResolverSingleStore(new Set()), */ validatedPrev, validatedCur, ); @@ -1582,22 +1953,28 @@ export async function diffTestSchemasPushLibSQL( 'push', ); - const { statementsToExecute, columnsToRemove, infoToPrint, shouldAskForApprove, tablesToRemove, tablesToTruncate } = - await libSqlLogSuggestionsAndReturn( - { - query: async (sql: string, params?: any[]) => { - const res = await client.execute({ sql, args: params || [] }); - return res.rows as T[]; - }, - run: async (query: string) => { - await client.execute(query); - }, + const { + statementsToExecute, + columnsToRemove, + infoToPrint, + shouldAskForApprove, + tablesToRemove, + tablesToTruncate, + } = await libSqlLogSuggestionsAndReturn( + { + query: async (sql: string, params?: any[]) => { + const res = await client.execute({ sql, args: params || [] }); + return res.rows as T[]; + }, + run: async (query: string) => { + await client.execute(query); }, - statements, - sn1, - sn2, - _meta!, - ); + }, + statements, + sn1, + sn2, + _meta!, + ); return { sqlStatements: statementsToExecute, @@ -1911,7 +2288,9 @@ export const introspectPgToFile = async ( fs.writeFileSync(`tests/introspect/postgres/${testName}.ts`, file.file); // generate snapshot from ts file - const response = await prepareFromPgImports([`tests/introspect/postgres/${testName}.ts`]); + const response = await prepareFromPgImports([ + `tests/introspect/postgres/${testName}.ts`, + ]); const afterFileImports = generatePgSnapshot( response.tables, @@ -1938,7 +2317,10 @@ export const introspectPgToFile = async ( const sn2AfterIm = squashPgScheme(sch2); const validatedCurAfterImport = pgSchema.parse(sch2); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyPgSnapshotsDiff( + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applyPgSnapshotsDiff( initSn, sn2AfterIm, testSchemasResolver(new Set()), @@ -2003,9 +2385,15 @@ export const introspectMySQLToFile = async ( fs.writeFileSync(`tests/introspect/mysql/${testName}.ts`, file.file); - const response = await prepareFromMySqlImports([`tests/introspect/mysql/${testName}.ts`]); + const response = await prepareFromMySqlImports([ + `tests/introspect/mysql/${testName}.ts`, + ]); - const afterFileImports = generateMySqlSnapshot(response.tables, response.views, casing); + const afterFileImports = generateMySqlSnapshot( + response.tables, + response.views, + casing, + ); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -2020,7 +2408,10 @@ export const introspectMySQLToFile = async ( const sn2AfterIm = squashMysqlScheme(sch2); const validatedCurAfterImport = mysqlSchema.parse(sch2); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyMysqlSnapshotsDiff( + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applyMysqlSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), @@ -2038,6 +2429,99 @@ export const introspectMySQLToFile = async ( }; }; +export const introspectSingleStoreToFile = async ( + client: Connection, + initSchema: SinglestoreSchema, + testName: string, + schema: string, + casing?: CasingType | undefined, +) => { + // put in db + const { sqlStatements } = await applySingleStoreDiffs(initSchema, casing); + for (const st of sqlStatements) { + await client.query(st); + } + + // introspect to schema + const introspectedSchema = await fromSingleStoreDatabase( + { + query: async (sql: string, params?: any[] | undefined) => { + const res = await client.execute(sql, params); + return res[0] as any; + }, + }, + schema, + ); + + const file = schemaToTypeScriptSingleStore(introspectedSchema, 'camel'); + + fs.writeFileSync(`tests/introspect/singlestore/${testName}.ts`, file.file); + + const response = await prepareFromSingleStoreImports([ + `tests/introspect/singlestore/${testName}.ts`, + ]); + + const afterFileImports = generateSingleStoreSnapshot( + response.tables, + /* response.views, */ + casing, + ); + + const { version: v2, dialect: d2, ...rest2 } = afterFileImports; + + const sch2 = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...rest2, + } as const; + + const sn2AfterIm = squashSingleStoreScheme(sch2); + const validatedCurAfterImport = singlestoreSchema.parse(sch2); + + const leftTables = Object.values(initSchema).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[]; + + const initSnapshot = generateSingleStoreSnapshot( + leftTables, + /* response.views, */ + casing, + ); + + const { version: initV, dialect: initD, ...initRest } = initSnapshot; + + const initSch = { + version: '1', + dialect: 'singlestore', + id: '0', + prevId: '0', + ...initRest, + } as const; + + const initSn = squashSingleStoreScheme(initSch); + const validatedCur = singlestoreSchema.parse(initSch); + + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applySingleStoreSnapshotsDiff( + sn2AfterIm, + initSn, + testTablesResolver(new Set()), + testColumnsResolver(new Set()), + /* testViewsResolverSingleStore(new Set()), */ + validatedCurAfterImport, + validatedCur, + ); + + fs.rmSync(`tests/introspect/singlestore/${testName}.ts`); + + return { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + }; +}; + export const introspectSQLiteToFile = async ( client: Database, initSchema: SqliteSchema, @@ -2081,9 +2565,15 @@ export const introspectSQLiteToFile = async ( fs.writeFileSync(`tests/introspect/sqlite/${testName}.ts`, file.file); - const response = await prepareFromSqliteImports([`tests/introspect/sqlite/${testName}.ts`]); + const response = await prepareFromSqliteImports([ + `tests/introspect/sqlite/${testName}.ts`, + ]); - const afterFileImports = generateSqliteSnapshot(response.tables, response.views, casing); + const afterFileImports = generateSqliteSnapshot( + response.tables, + response.views, + casing, + ); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -2098,7 +2588,10 @@ export const introspectSQLiteToFile = async ( const sn2AfterIm = squashSqliteScheme(sch2); const validatedCurAfterImport = sqliteSchema.parse(sch2); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applySqliteSnapshotsDiff( + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applySqliteSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), @@ -2159,9 +2652,15 @@ export const introspectLibSQLToFile = async ( fs.writeFileSync(`tests/introspect/libsql/${testName}.ts`, file.file); - const response = await prepareFromSqliteImports([`tests/introspect/libsql/${testName}.ts`]); + const response = await prepareFromSqliteImports([ + `tests/introspect/libsql/${testName}.ts`, + ]); - const afterFileImports = generateSqliteSnapshot(response.tables, response.views, casing); + const afterFileImports = generateSqliteSnapshot( + response.tables, + response.views, + casing, + ); const { version: v2, dialect: d2, ...rest2 } = afterFileImports; @@ -2176,7 +2675,10 @@ export const introspectLibSQLToFile = async ( const sn2AfterIm = squashSqliteScheme(sch2); const validatedCurAfterImport = sqliteSchema.parse(sch2); - const { sqlStatements: afterFileSqlStatements, statements: afterFileStatements } = await applyLibSQLSnapshotsDiff( + const { + sqlStatements: afterFileSqlStatements, + statements: afterFileStatements, + } = await applyLibSQLSnapshotsDiff( sn2AfterIm, initSn, testTablesResolver(new Set()), diff --git a/drizzle-kit/tests/singlestore-generated.test.ts b/drizzle-kit/tests/singlestore-generated.test.ts new file mode 100644 index 000000000..8944f3b21 --- /dev/null +++ b/drizzle-kit/tests/singlestore-generated.test.ts @@ -0,0 +1,1290 @@ +import { SQL, sql } from 'drizzle-orm'; +import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +test('generated as callback: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as callback: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs((): SQL => sql`${from.users.name} || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as callback: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs((): SQL => sql`${from.users.name} || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as callback: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name} || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as callback: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name} || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as callback: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as callback: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as callback: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${from.users.name}`, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + (): SQL => sql`${to.users.name} || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +// --- + +test('generated as sql: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as sql: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(sql`\`users\`.\`name\` || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as sql: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(sql`\`users\`.\`name\` || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as sql: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as sql: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as sql: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as sql: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as sql: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\``, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + sql`\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +// --- + +test('generated as string: add column with generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + column: { + generated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + autoincrement: false, + name: 'gen_name', + notNull: false, + primaryKey: false, + type: 'text', + }, + schema: '', + tableName: 'users', + type: 'alter_table_add_column', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as string: add generated constraint to an exisiting column as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(`\`users\`.\`name\` || 'to add'`, { + mode: 'stored', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'stored', + }, + columnAutoIncrement: false, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + "ALTER TABLE `users` MODIFY COLUMN `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') STORED;", + ]); +}); + +test('generated as string: add generated constraint to an exisiting column as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').notNull(), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name') + .notNull() + .generatedAlwaysAs(`\`users\`.\`name\` || 'to add'`, { + mode: 'virtual', + }), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'to add'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: true, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_set_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text NOT NULL GENERATED ALWAYS AS (`users`.`name` || 'to add') VIRTUAL;", + ]); +}); + +test('generated as string: drop generated constraint as stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'to delete'`, + { mode: 'stored' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'stored', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` MODIFY COLUMN `gen_name` text;', + ]); +}); + +test('generated as string: drop generated constraint as virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'to delete'`, + { mode: 'virtual' }, + ), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName1: text('gen_name'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: undefined, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + oldColumn: { + autoincrement: false, + generated: { + as: "`users`.`name` || 'to delete'", + type: 'virtual', + }, + name: 'gen_name', + notNull: false, + onUpdate: undefined, + primaryKey: false, + type: 'text', + }, + tableName: 'users', + type: 'alter_table_alter_column_drop_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` DROP COLUMN `gen_name`;', + 'ALTER TABLE `users` ADD `gen_name` text;', + ]); +}); + +test('generated as string: change generated constraint type from virtual to stored', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``, { + mode: 'virtual', + }), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + { mode: 'stored' }, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'stored', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') STORED;", + ]); +}); + +test('generated as string: change generated constraint type from stored to virtual', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); + +test('generated as string: change generated constraint', async () => { + const from = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs(`\`users\`.\`name\``), + }), + }; + const to = { + users: singlestoreTable('users', { + id: int('id'), + id2: int('id2'), + name: text('name'), + generatedName: text('gen_name').generatedAlwaysAs( + `\`users\`.\`name\` || 'hello'`, + ), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasSingleStore( + from, + to, + [], + ); + + expect(statements).toStrictEqual([ + { + columnAutoIncrement: false, + columnDefault: undefined, + columnGenerated: { + as: "`users`.`name` || 'hello'", + type: 'virtual', + }, + columnName: 'gen_name', + columnNotNull: false, + columnOnUpdate: undefined, + columnPk: false, + newDataType: 'text', + schema: '', + tableName: 'users', + type: 'alter_table_alter_column_alter_generated', + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `users` drop column `gen_name`;', + "ALTER TABLE `users` ADD `gen_name` text GENERATED ALWAYS AS (`users`.`name` || 'hello') VIRTUAL;", + ]); +}); diff --git a/drizzle-kit/tests/singlestore-schemas.test.ts b/drizzle-kit/tests/singlestore-schemas.test.ts new file mode 100644 index 000000000..db9fe0480 --- /dev/null +++ b/drizzle-kit/tests/singlestore-schemas.test.ts @@ -0,0 +1,155 @@ +import { singlestoreSchema, singlestoreTable } from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +// We don't manage databases(schemas) in MySQL with Drizzle Kit +test('add schema #1', async () => { + const to = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(0); +}); + +test('add schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('delete schema #1', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, {}, []); + + expect(statements.length).toBe(0); +}); + +test('delete schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('rename schema #1', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + }; + const to = { + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev->dev2']); + + expect(statements.length).toBe(0); +}); + +test('rename schema #2', async () => { + const from = { + devSchema: singlestoreSchema('dev'), + devSchema1: singlestoreSchema('dev1'), + }; + const to = { + devSchema: singlestoreSchema('dev'), + devSchema2: singlestoreSchema('dev2'), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #1', async () => { + const dev = singlestoreSchema('dev'); + const from = {}; + const to = { + dev, + users: dev.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #2', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev }; + const to = { + dev, + users: dev.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('add table to schema #3', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev }; + const to = { + dev, + usersInDev: dev.table('users', {}), + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePkName: '', + compositePKs: [], + }); +}); + +test('remove table from schema #1', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev, users: dev.table('users', {}) }; + const to = { + dev, + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); + +test('remove table from schema #2', async () => { + const dev = singlestoreSchema('dev'); + const from = { dev, users: dev.table('users', {}) }; + const to = {}; + + const { statements } = await diffTestSchemasSingleStore(from, to, ['dev1->dev2']); + + expect(statements.length).toBe(0); +}); diff --git a/drizzle-kit/tests/singlestore.test.ts b/drizzle-kit/tests/singlestore.test.ts new file mode 100644 index 000000000..3bdccab81 --- /dev/null +++ b/drizzle-kit/tests/singlestore.test.ts @@ -0,0 +1,580 @@ +import { sql } from 'drizzle-orm'; +import { + index, + json, + primaryKey, + serial, + singlestoreSchema, + singlestoreTable, + text, + uniqueIndex, +} from 'drizzle-orm/singlestore-core'; +import { expect, test } from 'vitest'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +test('add table #1', async () => { + const to = { + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + uniqueConstraints: [], + compositePkName: '', + }); +}); + +test('add table #2', async () => { + const to = { + users: singlestoreTable('users', { + id: serial('id').primaryKey(), + }), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [ + { + name: 'id', + notNull: true, + primaryKey: false, + type: 'serial', + autoincrement: true, + }, + ], + compositePKs: ['users_id;id'], + compositePkName: 'users_id', + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('add table #3', async () => { + const to = { + users: singlestoreTable( + 'users', + { + id: serial('id'), + }, + (t) => { + return { + pk: primaryKey({ + name: 'users_pk', + columns: [t.id], + }), + }; + }, + ), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [ + { + name: 'id', + notNull: true, + primaryKey: false, + type: 'serial', + autoincrement: true, + }, + ], + compositePKs: ['users_pk;id'], + uniqueConstraints: [], + compositePkName: 'users_pk', + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('add table #4', async () => { + const to = { + users: singlestoreTable('users', {}), + posts: singlestoreTable('posts', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'create_table', + tableName: 'posts', + schema: undefined, + columns: [], + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + uniqueConstraints: [], + compositePkName: '', + }); +}); + +test('add table #5', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + }; + + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(0); +}); + +test('add table #6', async () => { + const from = { + users1: singlestoreTable('users1', {}), + }; + + const to = { + users2: singlestoreTable('users2', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, []); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users2', + schema: undefined, + columns: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePKs: [], + uniqueConstraints: [], + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + policies: [], + type: 'drop_table', + tableName: 'users1', + schema: undefined, + }); +}); + +test('add table #7', async () => { + const from = { + users1: singlestoreTable('users1', {}), + }; + + const to = { + users: singlestoreTable('users', {}), + users2: singlestoreTable('users2', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'public.users1->public.users2', + ]); + + expect(statements.length).toBe(2); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + compositePKs: [], + uniqueConstraints: [], + internals: { + tables: {}, + indexes: {}, + }, + compositePkName: '', + }); + expect(statements[1]).toStrictEqual({ + type: 'rename_table', + tableNameFrom: 'users1', + tableNameTo: 'users2', + fromSchema: undefined, + toSchema: undefined, + }); +}); + +test('add schema + table #1', async () => { + const schema = singlestoreSchema('folder'); + + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore({}, to, []); + + expect(statements.length).toBe(0); +}); + +test('change schema with tables #1', async () => { + const schema = singlestoreSchema('folder'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema, + users: schema.table('users', {}), + }; + const to = { + schema2, + users: schema2.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder->folder2', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #1', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + users: singlestoreTable('users', {}), + }; + const to = { + schema, + users: schema.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'public.users->folder.users', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + policies: [], + type: 'drop_table', + tableName: 'users', + schema: undefined, + }); +}); + +test('change table schema #2', async () => { + const schema = singlestoreSchema('folder'); + const from = { + schema, + users: schema.table('users', {}), + }; + const to = { + schema, + users: singlestoreTable('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder.users->public.users', + ]); + + expect(statements.length).toBe(1); + expect(statements[0]).toStrictEqual({ + type: 'create_table', + tableName: 'users', + schema: undefined, + columns: [], + uniqueConstraints: [], + compositePkName: '', + compositePKs: [], + internals: { + tables: {}, + indexes: {}, + }, + }); +}); + +test('change table schema #3', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + schema2, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, + users: schema2.table('users', {}), + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #4', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, // add schema + users: schema2.table('users', {}), // move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #5', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, // remove schema + users: schema1.table('users', {}), + }; + const to = { + schema2, // add schema + users: schema2.table('users', {}), // move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #5', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + schema2, + users: schema1.table('users', {}), + }; + const to = { + schema1, + schema2, + users: schema2.table('users2', {}), // rename and move table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1.users->folder2.users2', + ]); + + expect(statements.length).toBe(0); +}); + +test('change table schema #6', async () => { + const schema1 = singlestoreSchema('folder1'); + const schema2 = singlestoreSchema('folder2'); + const from = { + schema1, + users: schema1.table('users', {}), + }; + const to = { + schema2, // rename schema + users: schema2.table('users2', {}), // rename table + }; + + const { statements } = await diffTestSchemasSingleStore(from, to, [ + 'folder1->folder2', + 'folder2.users->folder2.users2', + ]); + + expect(statements.length).toBe(0); +}); + +test('add table #10', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({}), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT '{}'\n);\n", + ); +}); + +test('add table #11', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default([]), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT '[]'\n);\n", + ); +}); + +test('add table #12', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default([1, 2, 3]), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + "CREATE TABLE `table` (\n\t`json` json DEFAULT '[1,2,3]'\n);\n", + ); +}); + +test('add table #13', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({ key: 'value' }), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + 'CREATE TABLE `table` (\n\t`json` json DEFAULT \'{"key":"value"}\'\n);\n', + ); +}); + +test('add table #14', async () => { + const to = { + users: singlestoreTable('table', { + json: json('json').default({ + key: 'value', + arr: [1, 2, 3], + }), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore({}, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe( + 'CREATE TABLE `table` (\n\t`json` json DEFAULT \'{"key":"value","arr":[1,2,3]}\'\n);\n', + ); +}); + +// TODO: add bson type tests + +// TODO: add blob type tests + +// TODO: add uuid type tests + +// TODO: add guid type tests + +// TODO: add vector type tests + +// TODO: add geopoint type tests + +test('drop index', async () => { + const from = { + users: singlestoreTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + idx: index('name_idx').on(t.name), + }; + }, + ), + }; + + const to = { + users: singlestoreTable('table', { + name: text('name'), + }), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe('DROP INDEX `name_idx` ON `table`;'); +}); + +test('add table with indexes', async () => { + const from = {}; + + const to = { + users: singlestoreTable( + 'users', + { + id: serial('id').primaryKey(), + name: text('name'), + email: text('email'), + }, + (t) => ({ + uniqueExpr: uniqueIndex('uniqueExpr').on(sql`(lower(${t.email}))`), + indexExpr: index('indexExpr').on(sql`(lower(${t.email}))`), + indexExprMultiple: index('indexExprMultiple').on( + sql`(lower(${t.email}))`, + sql`(lower(${t.email}))`, + ), + + uniqueCol: uniqueIndex('uniqueCol').on(t.email), + indexCol: index('indexCol').on(t.email), + indexColMultiple: index('indexColMultiple').on(t.email, t.email), + + indexColExpr: index('indexColExpr').on( + sql`(lower(${t.email}))`, + t.email, + ), + }), + ), + }; + + const { sqlStatements } = await diffTestSchemasSingleStore(from, to, []); + expect(sqlStatements.length).toBe(6); + expect(sqlStatements).toStrictEqual([ + `CREATE TABLE \`users\` (\n\t\`id\` serial AUTO_INCREMENT NOT NULL,\n\t\`name\` text,\n\t\`email\` text,\n\tCONSTRAINT \`users_id\` PRIMARY KEY(\`id\`),\n\tCONSTRAINT \`uniqueExpr\` UNIQUE((lower(\`email\`))),\n\tCONSTRAINT \`uniqueCol\` UNIQUE(\`email\`) +); +`, + 'CREATE INDEX `indexExpr` ON `users` ((lower(`email`)));', + 'CREATE INDEX `indexExprMultiple` ON `users` ((lower(`email`)),(lower(`email`)));', + 'CREATE INDEX `indexCol` ON `users` (`email`);', + 'CREATE INDEX `indexColMultiple` ON `users` (`email`,`email`);', + 'CREATE INDEX `indexColExpr` ON `users` ((lower(`email`)),`email`);', + ]); +}); diff --git a/drizzle-kit/tests/testsinglestore.ts b/drizzle-kit/tests/testsinglestore.ts new file mode 100644 index 000000000..1dc97d9c3 --- /dev/null +++ b/drizzle-kit/tests/testsinglestore.ts @@ -0,0 +1,29 @@ +import { index, singlestoreTable, text } from 'drizzle-orm/singlestore-core'; +import { diffTestSchemasSingleStore } from './schemaDiffer'; + +const from = { + users: singlestoreTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + idx: index('name_idx').on(t.name), + }; + }, + ), +}; + +const to = { + users: singlestoreTable('table', { + name: text('name'), + }), +}; + +diffTestSchemasSingleStore(from, to, []).then((res) => { + const { statements, sqlStatements } = res; + + console.log(statements); + console.log(sqlStatements); +}); diff --git a/drizzle-kit/tests/validations.test.ts b/drizzle-kit/tests/validations.test.ts index 82731ee25..8a64603bb 100644 --- a/drizzle-kit/tests/validations.test.ts +++ b/drizzle-kit/tests/validations.test.ts @@ -1,5 +1,6 @@ import { mysqlCredentials } from 'src/cli/validations/mysql'; import { postgresCredentials } from 'src/cli/validations/postgres'; +import { singlestoreCredentials } from 'src/cli/validations/singlestore'; import { sqliteCredentials } from 'src/cli/validations/sqlite'; import { expect, test } from 'vitest'; @@ -698,3 +699,171 @@ test('mysql #17', () => { }); }).toThrowError(); }); + +test('singlestore #1', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: 'database', + host: 'host', + }), + ).toStrictEqual({ + database: 'database', + host: 'host', + }); +}); + +test('singlestore #2', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: 'database', + host: 'host', + }), + ).toStrictEqual({ + database: 'database', + host: 'host', + }); +}); + +test('singlestore #3', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + port: 1234, + user: 'user', + password: 'password', + database: 'database', + ssl: 'require', + }), + ).toStrictEqual({ + host: 'host', + port: 1234, + user: 'user', + password: 'password', + database: 'database', + ssl: 'require', + }); +}); + +test('singlestore #4', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + database: 'database', + ssl: 'allow', + }), + ).toStrictEqual({ + host: 'host', + database: 'database', + ssl: 'allow', + }); +}); + +test('singlestore #5', () => { + expect( + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: 'host', + database: 'database', + ssl: { + ca: 'ca', + cert: 'cert', + }, + }), + ).toStrictEqual({ + host: 'host', + database: 'database', + ssl: { + ca: 'ca', + cert: 'cert', + }, + }); +}); + +test('singlestore #6', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + }); + }).toThrowError(); +}); + +test('singlestore #7', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + url: undefined, + }); + }).toThrowError(); +}); + +test('singlestore #8', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + url: '', + }); + }).toThrowError(); +}); + +test('singlestore #9', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: '', + database: '', + }); + }).toThrowError(); +}); + +test('singlestore #10', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: '', + }); + }).toThrowError(); +}); + +test('singlestore #11', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + host: '', + }); + }).toThrowError(); +}); + +test('singlestore #12', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: ' ', + host: '', + }); + }).toThrowError(); +}); + +test('singlestore #13', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: '', + host: ' ', + }); + }).toThrowError(); +}); + +test('singlestore #14', () => { + expect(() => { + singlestoreCredentials.parse({ + dialect: 'singlestore', + database: ' ', + host: ' ', + port: '', + }); + }).toThrowError(); +}); diff --git a/drizzle-kit/tests/wrap-param.test.ts b/drizzle-kit/tests/wrap-param.test.ts index 542998bda..a27d27d45 100644 --- a/drizzle-kit/tests/wrap-param.test.ts +++ b/drizzle-kit/tests/wrap-param.test.ts @@ -7,6 +7,9 @@ test('wrapParam', () => { expect(wrapParam('url', 'mysql://user:password@localhost:3306/database', false, 'url')).toBe( ` [${chalk.green('✓')}] url: 'mysql://user:****@localhost:3306/database'`, ); + expect(wrapParam('url', 'singlestore://user:password@localhost:3306/database', false, 'url')).toBe( + ` [${chalk.green('✓')}] url: 'singlestore://user:****@localhost:3306/database'`, + ); expect(wrapParam('url', 'postgresql://user:password@localhost:5432/database', false, 'url')).toBe( ` [${chalk.green('✓')}] url: 'postgresql://user:****@localhost:5432/database'`, ); diff --git a/drizzle-kit/vitest.config.ts b/drizzle-kit/vitest.config.ts index 602e96ede..fd728eb11 100644 --- a/drizzle-kit/vitest.config.ts +++ b/drizzle-kit/vitest.config.ts @@ -5,8 +5,17 @@ export default defineConfig({ test: { include: [ 'tests/**/*.test.ts', + // Need to test it first before pushing changes + // 'tests/singlestore-schemas.test.ts', + // 'tests/singlestore-views.test.ts', + // 'tests/push/singlestore-push.test.ts', + // 'tests/push/singlestore.test.ts', ], + // This one was excluded because we need to modify an API for SingleStore-generated columns. + // It’s in the backlog. + exclude: ['tests/**/singlestore-generated.test.ts'], + typecheck: { tsconfig: 'tsconfig.json', }, diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 87c3f0bc2..3fa8e4bc3 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.36.4", + "version": "0.37.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -29,6 +29,7 @@ "orm", "pg", "mysql", + "singlestore", "postgresql", "postgres", "sqlite", @@ -45,7 +46,7 @@ }, "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", - "@cloudflare/workers-types": ">=3", + "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", @@ -164,7 +165,7 @@ }, "devDependencies": { "@aws-sdk/client-rds-data": "^3.549.0", - "@cloudflare/workers-types": "^4.20230904.0", + "@cloudflare/workers-types": "^4.20241112.0", "@electric-sql/pglite": "^0.2.12", "@libsql/client": "^0.10.0", "@libsql/client-wasm": "^0.10.0", diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index f621343d9..207f28026 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -2,6 +2,7 @@ import { entityKind } from '~/entity.ts'; import type { Column } from './column.ts'; import type { MySqlColumn } from './mysql-core/index.ts'; import type { ExtraConfigColumn, PgColumn, PgSequenceOptions } from './pg-core/index.ts'; +import type { SingleStoreColumn } from './singlestore-core/index.ts'; import type { SQL } from './sql/sql.ts'; import type { SQLiteColumn } from './sqlite-core/index.ts'; import type { Assume, Simplify } from './utils.ts'; @@ -17,7 +18,7 @@ export type ColumnDataType = | 'custom' | 'buffer'; -export type Dialect = 'pg' | 'mysql' | 'sqlite' | 'common'; +export type Dialect = 'pg' | 'mysql' | 'sqlite' | 'singlestore' | 'common'; export type GeneratedStorageMode = 'virtual' | 'stored'; @@ -314,6 +315,7 @@ export type BuildColumn< TDialect extends Dialect, > = TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> + : TDialect extends 'singlestore' ? SingleStoreColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : TDialect extends 'common' ? Column> : never; @@ -356,5 +358,6 @@ export type BuildExtraConfigColumns< export type ChangeColumnTableName = TDialect extends 'pg' ? PgColumn> : TDialect extends 'mysql' ? MySqlColumn> + : TDialect extends 'singlestore' ? SingleStoreColumn> : TDialect extends 'sqlite' ? SQLiteColumn> : never; diff --git a/drizzle-orm/src/durable-sqlite/driver.ts b/drizzle-orm/src/durable-sqlite/driver.ts new file mode 100644 index 000000000..0be110084 --- /dev/null +++ b/drizzle-orm/src/durable-sqlite/driver.ts @@ -0,0 +1,60 @@ +/// +import { entityKind } from '~/entity.ts'; +import { DefaultLogger } from '~/logger.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type ExtractTablesWithRelations, + 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 { SQLiteDOSession } from './session.ts'; + +export class DrizzleSqliteDODatabase< + TSchema extends Record = Record, +> extends BaseSQLiteDatabase<'sync', SqlStorageCursor>, TSchema> { + static override readonly [entityKind]: string = 'DrizzleSqliteDODatabase'; + + /** @internal */ + declare readonly session: SQLiteDOSession>; +} + +export function drizzle< + TSchema extends Record = Record, + TClient extends DurableObjectStorage = DurableObjectStorage, +>( + client: TClient, + config: DrizzleConfig = {}, +): DrizzleSqliteDODatabase & { + $client: TClient; +} { + const dialect = new SQLiteSyncDialect({ casing: config.casing }); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const session = new SQLiteDOSession(client as DurableObjectStorage, dialect, schema, { logger }); + const db = new DrizzleSqliteDODatabase('sync', dialect, session, schema) as DrizzleSqliteDODatabase; + ( db).$client = client; + + return db as any; +} diff --git a/drizzle-orm/src/durable-sqlite/index.ts b/drizzle-orm/src/durable-sqlite/index.ts new file mode 100644 index 000000000..b1b6a52e7 --- /dev/null +++ b/drizzle-orm/src/durable-sqlite/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/durable-sqlite/migrator.ts b/drizzle-orm/src/durable-sqlite/migrator.ts new file mode 100644 index 000000000..8410b2900 --- /dev/null +++ b/drizzle-orm/src/durable-sqlite/migrator.ts @@ -0,0 +1,85 @@ +import type { MigrationMeta } from '~/migrator.ts'; +import { sql } from '~/sql/index.ts'; +import type { DrizzleSqliteDODatabase } from './driver.ts'; + +interface MigrationConfig { + journal: { + entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; + }; + migrations: Record; +} + +function readMigrationFiles({ journal, migrations }: MigrationConfig): MigrationMeta[] { + const migrationQueries: MigrationMeta[] = []; + + for (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, +>( + db: DrizzleSqliteDODatabase, + config: MigrationConfig, +): Promise { + const migrations = readMigrationFiles(config); + + db.transaction((tx) => { + try { + const migrationsTable = '__drizzle_migrations'; + + const migrationTableCreate = sql` + CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} ( + id SERIAL PRIMARY KEY, + hash text NOT NULL, + created_at numeric + ) + `; + db.run(migrationTableCreate); + + const dbMigrations = db.values<[number, string, string]>( + sql`SELECT id, hash, created_at FROM ${sql.identifier(migrationsTable)} ORDER BY created_at DESC LIMIT 1`, + ); + + const lastDbMigration = dbMigrations[0] ?? undefined; + + for (const migration of migrations) { + if (!lastDbMigration || Number(lastDbMigration[2])! < migration.folderMillis) { + for (const stmt of migration.sql) { + db.run(sql.raw(stmt)); + } + db.run( + sql`INSERT INTO ${ + sql.identifier(migrationsTable) + } ("hash", "created_at") VALUES(${migration.hash}, ${migration.folderMillis})`, + ); + } + } + } catch (error: any) { + tx.rollback(); + throw error; + } + }); +} diff --git a/drizzle-orm/src/durable-sqlite/session.ts b/drizzle-orm/src/durable-sqlite/session.ts new file mode 100644 index 000000000..dca5ce7cf --- /dev/null +++ b/drizzle-orm/src/durable-sqlite/session.ts @@ -0,0 +1,181 @@ +import { entityKind } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query } from '~/sql/sql.ts'; +import { type SQLiteSyncDialect, SQLiteTransaction } from '~/sqlite-core/index.ts'; +import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts'; +import { + type PreparedQueryConfig as PreparedQueryConfigBase, + type SQLiteExecuteMethod, + SQLiteSession, + type SQLiteTransactionConfig, +} from '~/sqlite-core/session.ts'; +import { SQLitePreparedQuery as PreparedQueryBase } from '~/sqlite-core/session.ts'; +import { mapResultRow } from '~/utils.ts'; + +export interface SQLiteDOSessionOptions { + logger?: Logger; +} + +type PreparedQueryConfig = Omit; + +export class SQLiteDOSession, TSchema extends TablesRelationalConfig> + extends SQLiteSession< + 'sync', + SqlStorageCursor>, + TFullSchema, + TSchema + > +{ + static override readonly [entityKind]: string = 'SQLiteDOSession'; + + private logger: Logger; + + constructor( + private client: DurableObjectStorage, + dialect: SQLiteSyncDialect, + private schema: RelationalSchemaConfig | undefined, + options: SQLiteDOSessionOptions = {}, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + } + + prepareQuery>( + query: Query, + fields: SelectedFieldsOrdered | undefined, + executeMethod: SQLiteExecuteMethod, + isResponseInArrayMode: boolean, + customResultMapper?: (rows: unknown[][]) => unknown, + ): SQLiteDOPreparedQuery { + return new SQLiteDOPreparedQuery( + this.client, + query, + this.logger, + fields, + executeMethod, + isResponseInArrayMode, + customResultMapper, + ); + } + + override transaction( + transaction: ( + tx: SQLiteTransaction<'sync', SqlStorageCursor>, TFullSchema, TSchema>, + ) => T, + _config?: SQLiteTransactionConfig, + ): T { + const tx = new SQLiteDOTransaction('sync', this.dialect, this, this.schema); + this.client.transactionSync(() => { + transaction(tx); + }); + return {} as any; + } +} + +export class SQLiteDOTransaction, TSchema extends TablesRelationalConfig> + extends SQLiteTransaction< + 'sync', + SqlStorageCursor>, + TFullSchema, + TSchema + > +{ + static override readonly [entityKind]: string = 'SQLiteDOTransaction'; + + override transaction(transaction: (tx: SQLiteDOTransaction) => T): T { + const tx = new SQLiteDOTransaction('sync', this.dialect, this.session, this.schema, this.nestedIndex + 1); + this.session.transaction(() => transaction(tx)); + + return {} as any; + } +} + +export class SQLiteDOPreparedQuery extends PreparedQueryBase<{ + type: 'sync'; + run: void; + all: T['all']; + get: T['get']; + values: T['values']; + execute: T['execute']; +}> { + static override readonly [entityKind]: string = 'SQLiteDOPreparedQuery'; + + constructor( + private client: DurableObjectStorage, + query: Query, + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + executeMethod: SQLiteExecuteMethod, + private _isResponseInArrayMode: boolean, + private customResultMapper?: (rows: unknown[][]) => unknown, + ) { + super('sync', executeMethod, query); + } + + run(placeholderValues?: Record): void { + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); + + params.length > 0 ? this.client.sql.exec(this.query.sql, ...params) : this.client.sql.exec(this.query.sql); + } + + all(placeholderValues?: Record): T['all'] { + const { fields, joinsNotNullableMap, query, logger, client, customResultMapper } = this; + if (!fields && !customResultMapper) { + const params = fillPlaceholders(query.params, placeholderValues ?? {}); + logger.logQuery(query.sql, params); + + return params.length > 0 ? client.sql.exec(query.sql, ...params).toArray() : client.sql.exec(query.sql).toArray(); + } + + const rows = this.values(placeholderValues) as unknown[][]; + + if (customResultMapper) { + return customResultMapper(rows) as T['all']; + } + + return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + } + + get(placeholderValues?: Record): T['get'] { + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); + + const { fields, client, joinsNotNullableMap, customResultMapper, query } = this; + if (!fields && !customResultMapper) { + return params.length > 0 ? client.sql.exec(query.sql, ...params).one() : client.sql.exec(query.sql).one(); + } + + const rows = this.values(placeholderValues) as unknown[][]; + const row = rows[0]; + + if (!row) { + return undefined; + } + + if (customResultMapper) { + return customResultMapper(rows) as T['get']; + } + + return mapResultRow(fields!, row, joinsNotNullableMap); + } + + values(placeholderValues?: Record): T['values'] { + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); + + const res = params.length > 0 + ? this.client.sql.exec(this.query.sql, ...params) + : this.client.sql.exec(this.query.sql); + + // @ts-ignore .raw().toArray() exists + return res.raw().toArray(); + } + + /** @internal */ + isResponseInArrayMode(): boolean { + return this._isResponseInArrayMode; + } +} diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index cbe1689fb..209e41963 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -1,4 +1,4 @@ -import type { HTTPTransactionOptions, NeonQueryFunction } from '@neondatabase/serverless'; +import type { HTTPQueryOptions, HTTPTransactionOptions, NeonQueryFunction } from '@neondatabase/serverless'; import { neon, types } from '@neondatabase/serverless'; import type { BatchItem, BatchResponse } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; @@ -42,7 +42,7 @@ export class NeonHttpDriver { function wrap( target: T, - token: string, + token: Exclude['authToken'], undefined>, cb: (target: any, p: string | symbol, res: any) => any, deep?: boolean, ) { @@ -57,7 +57,7 @@ function wrap( return new Proxy(element as any, { apply(target, thisArg, argArray) { const res = target.call(thisArg, ...argArray); - if ('setToken' in res && typeof res.setToken === 'function') { + if (typeof res === 'object' && res !== null && 'setToken' in res && typeof res.setToken === 'function') { res.setToken(token); } return cb(target, p, res); @@ -73,7 +73,7 @@ export class NeonHttpDatabase< static override readonly [entityKind]: string = 'NeonHttpDatabase'; $withAuth( - token: string, + token: Exclude['authToken'], undefined>, ): Omit< this, Exclude< diff --git a/drizzle-orm/src/neon-http/session.ts b/drizzle-orm/src/neon-http/session.ts index c8f8f5a33..00ffe26e7 100644 --- a/drizzle-orm/src/neon-http/session.ts +++ b/drizzle-orm/src/neon-http/session.ts @@ -11,7 +11,7 @@ import { PgPreparedQuery as PgPreparedQuery, PgSession } from '~/pg-core/session import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; import type { PreparedQuery } from '~/session.ts'; import { fillPlaceholders, type Query, type SQL } from '~/sql/sql.ts'; -import { mapResultRow } from '~/utils.ts'; +import { mapResultRow, type NeonAuthToken } from '~/utils.ts'; export type NeonHttpClient = NeonQueryFunction; @@ -40,11 +40,11 @@ export class NeonHttpPreparedQuery extends PgPrep async execute(placeholderValues: Record | undefined): Promise; /** @internal */ - async execute(placeholderValues: Record | undefined, token?: string): Promise; + async execute(placeholderValues: Record | undefined, token?: NeonAuthToken): Promise; /** @internal */ async execute( placeholderValues: Record | undefined = {}, - token: string | undefined = this.authToken, + token: NeonAuthToken | undefined = this.authToken, ): Promise { const params = fillPlaceholders(this.query.params, placeholderValues); @@ -108,9 +108,9 @@ export class NeonHttpPreparedQuery extends PgPrep values(placeholderValues: Record | undefined): Promise; /** @internal */ - values(placeholderValues: Record | undefined, token?: string): Promise; + values(placeholderValues: Record | undefined, token?: NeonAuthToken): Promise; /** @internal */ - values(placeholderValues: Record | undefined = {}, token?: string): Promise { + values(placeholderValues: Record | undefined = {}, token?: NeonAuthToken): Promise { const params = fillPlaceholders(this.query.params, placeholderValues); this.logger.logQuery(this.query.sql, params); return this.client(this.query.sql, params, { arrayMode: true, fullResults: true, authToken: token }).then(( @@ -203,9 +203,9 @@ export class NeonHttpSession< override async count(sql: SQL): Promise; /** @internal */ - override async count(sql: SQL, token?: string): Promise; + override async count(sql: SQL, token?: NeonAuthToken): Promise; /** @internal */ - override async count(sql: SQL, token?: string): Promise { + override async count(sql: SQL, token?: NeonAuthToken): Promise { const res = await this.execute<{ rows: [{ count: string }] }>(sql, token); return Number( diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index e3c7e4444..29dc4f166 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -21,7 +21,7 @@ import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelation import { SelectionProxyHandler } from '~/selection-proxy.ts'; import { type ColumnsSelection, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; import { WithSubquery } from '~/subquery.ts'; -import type { DrizzleTypeError } from '~/utils.ts'; +import type { DrizzleTypeError, NeonAuthToken } from '~/utils.ts'; import type { PgColumn } from './columns/index.ts'; import { PgCountBuilder } from './query-builders/count.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; @@ -597,7 +597,7 @@ export class PgDatabase< return new PgRefreshMaterializedView(view, this.session, this.dialect); } - protected authToken?: string; + protected authToken?: NeonAuthToken; execute = Record>( query: SQLWrapper | string, @@ -647,7 +647,8 @@ export const withReplicas = < const select: Q['select'] = (...args: []) => getReplica(replicas).select(...args); const selectDistinct: Q['selectDistinct'] = (...args: []) => getReplica(replicas).selectDistinct(...args); const selectDistinctOn: Q['selectDistinctOn'] = (...args: [any]) => getReplica(replicas).selectDistinctOn(...args); - const $with: Q['with'] = (...args: any) => getReplica(replicas).with(...args); + const _with: Q['with'] = (...args: any) => getReplica(replicas).with(...args); + const $with: Q['$with'] = (arg: any) => getReplica(replicas).$with(arg); const update: Q['update'] = (...args: [any]) => primary.update(...args); const insert: Q['insert'] = (...args: [any]) => primary.insert(...args); @@ -669,7 +670,8 @@ export const withReplicas = < select, selectDistinct, selectDistinctOn, - with: $with, + $with, + with: _with, get query() { return getReplica(replicas).query; }, diff --git a/drizzle-orm/src/pg-core/query-builders/count.ts b/drizzle-orm/src/pg-core/query-builders/count.ts index e620c7428..a86ffd745 100644 --- a/drizzle-orm/src/pg-core/query-builders/count.ts +++ b/drizzle-orm/src/pg-core/query-builders/count.ts @@ -1,5 +1,6 @@ import { entityKind } from '~/entity.ts'; import { SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; +import type { NeonAuthToken } from '~/utils.ts'; import type { PgSession } from '../session.ts'; import type { PgTable } from '../table.ts'; @@ -7,7 +8,7 @@ export class PgCountBuilder< TSession extends PgSession, > extends SQL implements Promise, SQLWrapper { private sql: SQL; - private token?: string; + private token?: NeonAuthToken; static override readonly [entityKind] = 'PgCountBuilder'; [Symbol.toStringTag] = 'PgCountBuilder'; @@ -48,8 +49,9 @@ export class PgCountBuilder< } /** @intrnal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.token = token; + return this; } then( diff --git a/drizzle-orm/src/pg-core/query-builders/delete.ts b/drizzle-orm/src/pg-core/query-builders/delete.ts index 97bcdc044..682e52e2d 100644 --- a/drizzle-orm/src/pg-core/query-builders/delete.ts +++ b/drizzle-orm/src/pg-core/query-builders/delete.ts @@ -15,7 +15,7 @@ import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; -import { orderSelectedFields } from '~/utils.ts'; +import { type NeonAuthToken, orderSelectedFields } from '~/utils.ts'; import type { PgColumn } from '../columns/common.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; @@ -232,9 +232,9 @@ export class PgDeleteBase< return this._prepare(name); } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index c1849d4bb..2cf266be4 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -19,7 +19,7 @@ import type { Subquery } from '~/subquery.ts'; import type { InferInsertModel } from '~/table.ts'; import { Columns, Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; -import { haveSameKeys, mapUpdateSet, orderSelectedFields } from '~/utils.ts'; +import { haveSameKeys, mapUpdateSet, type NeonAuthToken, orderSelectedFields } from '~/utils.ts'; import type { AnyPgColumn, PgColumn } from '../columns/common.ts'; import { QueryBuilder } from './query-builder.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; @@ -63,9 +63,9 @@ export class PgInsertBuilder< private overridingSystemValue_?: boolean, ) {} - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } @@ -94,25 +94,15 @@ export class PgInsertBuilder< return result; }); - return this.authToken === undefined - ? new PgInsertBase( - this.table, - mappedValues, - this.session, - this.dialect, - this.withList, - false, - this.overridingSystemValue_, - ) - : new PgInsertBase( - this.table, - mappedValues, - this.session, - this.dialect, - this.withList, - false, - this.overridingSystemValue_, - ).setToken(this.authToken) as any; + return new PgInsertBase( + this.table, + mappedValues, + this.session, + this.dialect, + this.withList, + false, + this.overridingSystemValue_, + ).setToken(this.authToken) as any; } select(selectQuery: (qb: QueryBuilder) => PgInsertSelectQueryBuilder): PgInsertBase; @@ -402,9 +392,9 @@ export class PgInsertBase< return this._prepare(name); } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/query-builders/query.ts b/drizzle-orm/src/pg-core/query-builders/query.ts index c664e761d..816b60500 100644 --- a/drizzle-orm/src/pg-core/query-builders/query.ts +++ b/drizzle-orm/src/pg-core/query-builders/query.ts @@ -11,7 +11,7 @@ import { import type { RunnableQuery } from '~/runnable-query.ts'; import type { Query, QueryWithTypings, SQL, SQLWrapper } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; -import type { KnownKeysOnly } from '~/utils.ts'; +import type { KnownKeysOnly, NeonAuthToken } from '~/utils.ts'; import type { PgDialect } from '../dialect.ts'; import type { PgPreparedQuery, PgSession, PreparedQueryConfig } from '../session.ts'; import type { PgTable } from '../table.ts'; @@ -142,9 +142,9 @@ export class PgRelationalQuery extends QueryPromise return this._toSQL().builtQuery; } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts index f171023da..c20baaf5a 100644 --- a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts +++ b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts @@ -12,6 +12,7 @@ import { QueryPromise } from '~/query-promise.ts'; import type { RunnableQuery } from '~/runnable-query.ts'; import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; +import type { NeonAuthToken } from '~/utils'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface PgRefreshMaterializedView @@ -92,9 +93,9 @@ export class PgRefreshMaterializedView return this._prepare(name); } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/query-builders/select.ts b/drizzle-orm/src/pg-core/query-builders/select.ts index 813a89bd1..597991f79 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.ts @@ -24,7 +24,14 @@ import type { ColumnsSelection, Placeholder, Query, SQLWrapper } from '~/sql/sql import { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; -import { applyMixins, getTableColumns, getTableLikeName, haveSameKeys, type ValueOrArray } from '~/utils.ts'; +import { + applyMixins, + getTableColumns, + getTableLikeName, + haveSameKeys, + type NeonAuthToken, + type ValueOrArray, +} from '~/utils.ts'; import { orderSelectedFields } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { @@ -81,9 +88,9 @@ export class PgSelectBuilder< this.distinct = config.distinct; } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } @@ -122,25 +129,15 @@ export class PgSelectBuilder< fields = getTableColumns(source); } - return (this.authToken === undefined - ? new PgSelectBase({ - table: source, - fields, - isPartialSelect, - session: this.session, - dialect: this.dialect, - withList: this.withList, - distinct: this.distinct, - }) - : new PgSelectBase({ - table: source, - fields, - isPartialSelect, - session: this.session, - dialect: this.dialect, - withList: this.withList, - distinct: this.distinct, - }).setToken(this.authToken)) as any; + return (new PgSelectBase({ + table: source, + fields, + isPartialSelect, + session: this.session, + dialect: this.dialect, + withList: this.withList, + distinct: this.distinct, + }).setToken(this.authToken)) as any; } } @@ -979,7 +976,7 @@ export class PgSelectBase< >(dialect.sqlToQuery(this.getSQL()), fieldsList, name, true); query.joinsNotNullableMap = joinsNotNullableMap; - return authToken === undefined ? query : query.setToken(authToken); + return query.setToken(authToken); }); } @@ -994,9 +991,9 @@ export class PgSelectBase< return this._prepare(name); } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index a8810ed5a..c6d04ee35 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -25,7 +25,14 @@ import { SelectionProxyHandler } from '~/selection-proxy.ts'; import { type ColumnsSelection, type Query, SQL, type SQLWrapper } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; -import { type Assume, getTableLikeName, mapUpdateSet, orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { + type Assume, + getTableLikeName, + mapUpdateSet, + type NeonAuthToken, + orderSelectedFields, + type UpdateSet, +} from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { PgColumn } from '../columns/common.ts'; import type { PgViewBase } from '../view-base.ts'; @@ -64,8 +71,8 @@ export class PgUpdateBuilder, ): PgUpdateWithout, false, 'leftJoin' | 'rightJoin' | 'innerJoin' | 'fullJoin'> { - return this.authToken === undefined - ? new PgUpdateBase( - this.table, - mapUpdateSet(this.table, values), - this.session, - this.dialect, - this.withList, - ) - : new PgUpdateBase( - this.table, - mapUpdateSet(this.table, values), - this.session, - this.dialect, - this.withList, - ).setToken(this.authToken); + return new PgUpdateBase( + this.table, + mapUpdateSet(this.table, values), + this.session, + this.dialect, + this.withList, + ).setToken(this.authToken); } } @@ -548,9 +547,9 @@ export class PgUpdateBase< return this._prepare(name); } - private authToken?: string; + private authToken?: NeonAuthToken; /** @internal */ - setToken(token: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } diff --git a/drizzle-orm/src/pg-core/session.ts b/drizzle-orm/src/pg-core/session.ts index 8dff92f6b..d77f2c4db 100644 --- a/drizzle-orm/src/pg-core/session.ts +++ b/drizzle-orm/src/pg-core/session.ts @@ -4,6 +4,7 @@ import type { TablesRelationalConfig } from '~/relations.ts'; import type { PreparedQuery } from '~/session.ts'; import { type Query, type SQL, sql } from '~/sql/index.ts'; import { tracer } from '~/tracing.ts'; +import type { NeonAuthToken } from '~/utils.ts'; import { PgDatabase } from './db.ts'; import type { PgDialect } from './dialect.ts'; import type { SelectedFieldsOrdered } from './query-builders/select.types.ts'; @@ -17,7 +18,7 @@ export interface PreparedQueryConfig { export abstract class PgPreparedQuery implements PreparedQuery { constructor(protected query: Query) {} - protected authToken?: string; + protected authToken?: NeonAuthToken; getQuery(): Query { return this.query; @@ -28,7 +29,7 @@ export abstract class PgPreparedQuery implements } /** @internal */ - setToken(token?: string) { + setToken(token?: NeonAuthToken) { this.authToken = token; return this; } @@ -40,9 +41,9 @@ export abstract class PgPreparedQuery implements abstract execute(placeholderValues?: Record): Promise; /** @internal */ - abstract execute(placeholderValues?: Record, token?: string): Promise; + abstract execute(placeholderValues?: Record, token?: NeonAuthToken): Promise; /** @internal */ - abstract execute(placeholderValues?: Record, token?: string): Promise; + abstract execute(placeholderValues?: Record, token?: NeonAuthToken): Promise; /** @internal */ abstract all(placeholderValues?: Record): Promise; @@ -76,9 +77,9 @@ export abstract class PgSession< execute(query: SQL): Promise; /** @internal */ - execute(query: SQL, token?: string): Promise; + execute(query: SQL, token?: NeonAuthToken): Promise; /** @internal */ - execute(query: SQL, token?: string): Promise { + execute(query: SQL, token?: NeonAuthToken): Promise { return tracer.startActiveSpan('drizzle.operation', () => { const prepared = tracer.startActiveSpan('drizzle.prepareQuery', () => { return this.prepareQuery( @@ -104,9 +105,9 @@ export abstract class PgSession< async count(sql: SQL): Promise; /** @internal */ - async count(sql: SQL, token?: string): Promise; + async count(sql: SQL, token?: NeonAuthToken): Promise; /** @internal */ - async count(sql: SQL, token?: string): Promise { + async count(sql: SQL, token?: NeonAuthToken): Promise { const res = await this.execute<[{ count: string }]>(sql, token); return Number( diff --git a/drizzle-orm/src/singlestore-core/alias.ts b/drizzle-orm/src/singlestore-core/alias.ts new file mode 100644 index 000000000..6c08bdff3 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/alias.ts @@ -0,0 +1,10 @@ +import { TableAliasProxyHandler } from '~/alias.ts'; +import type { BuildAliasTable } from './query-builders/select.types.ts'; +import type { SingleStoreTable } from './table.ts'; + +export function alias( // | SingleStoreViewBase + table: TTable, + alias: TAlias, +): BuildAliasTable { + return new Proxy(table, new TableAliasProxyHandler(alias, false)) as any; +} diff --git a/drizzle-orm/src/singlestore-core/columns/all.ts b/drizzle-orm/src/singlestore-core/columns/all.ts new file mode 100644 index 000000000..66d289e3f --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/all.ts @@ -0,0 +1,55 @@ +import { bigint } from './bigint.ts'; +import { binary } from './binary.ts'; +import { boolean } from './boolean.ts'; +import { char } from './char.ts'; +import { customType } from './custom.ts'; +import { date } from './date.ts'; +import { datetime } from './datetime.ts'; +import { decimal } from './decimal.ts'; +import { double } from './double.ts'; +import { singlestoreEnum } from './enum.ts'; +import { float } from './float.ts'; +import { int } from './int.ts'; +import { json } from './json.ts'; +import { mediumint } from './mediumint.ts'; +import { real } from './real.ts'; +import { serial } from './serial.ts'; +import { smallint } from './smallint.ts'; +import { text } from './text.ts'; +import { time } from './time.ts'; +import { timestamp } from './timestamp.ts'; +import { tinyint } from './tinyint.ts'; +import { varbinary } from './varbinary.ts'; +import { varchar } from './varchar.ts'; +import { year } from './year.ts'; + +export function getSingleStoreColumnBuilders() { + return { + bigint, + binary, + boolean, + char, + customType, + date, + datetime, + decimal, + double, + singlestoreEnum, + float, + int, + json, + mediumint, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varbinary, + varchar, + year, + }; +} + +export type SingleStoreColumnBuilders = ReturnType; diff --git a/drizzle-orm/src/singlestore-core/columns/bigint.ts b/drizzle-orm/src/singlestore-core/columns/bigint.ts new file mode 100644 index 000000000..1e6b64c49 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/bigint.ts @@ -0,0 +1,120 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreBigInt53BuilderInitial = SingleStoreBigInt53Builder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreBigInt53'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBigInt53Builder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt53Builder'; + + constructor(name: T['name'], unsigned: boolean = false) { + super(name, 'number', 'SingleStoreBigInt53'); + this.config.unsigned = unsigned; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBigInt53> { + return new SingleStoreBigInt53>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBigInt53> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt53'; + + getSQLType(): string { + return `bigint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'number') { + return value; + } + return Number(value); + } +} + +export type SingleStoreBigInt64BuilderInitial = SingleStoreBigInt64Builder<{ + name: TName; + dataType: 'bigint'; + columnType: 'SingleStoreBigInt64'; + data: bigint; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBigInt64Builder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt64Builder'; + + constructor(name: T['name'], unsigned: boolean = false) { + super(name, 'bigint', 'SingleStoreBigInt64'); + this.config.unsigned = unsigned; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBigInt64> { + return new SingleStoreBigInt64>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBigInt64> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreBigInt64'; + + getSQLType(): string { + return `bigint${this.config.unsigned ? ' unsigned' : ''}`; + } + + // eslint-disable-next-line unicorn/prefer-native-coercion-functions + override mapFromDriverValue(value: string): bigint { + return BigInt(value); + } +} + +export interface SingleStoreBigIntConfig { + mode: T; + unsigned?: boolean; +} + +export function bigint( + config: SingleStoreBigIntConfig, +): TMode extends 'number' ? SingleStoreBigInt53BuilderInitial<''> : SingleStoreBigInt64BuilderInitial<''>; +export function bigint( + name: TName, + config: SingleStoreBigIntConfig, +): TMode extends 'number' ? SingleStoreBigInt53BuilderInitial : SingleStoreBigInt64BuilderInitial; +export function bigint(a?: string | SingleStoreBigIntConfig, b?: SingleStoreBigIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config.mode === 'number') { + return new SingleStoreBigInt53Builder(name, config.unsigned); + } + return new SingleStoreBigInt64Builder(name, config.unsigned); +} diff --git a/drizzle-orm/src/singlestore-core/columns/binary.ts b/drizzle-orm/src/singlestore-core/columns/binary.ts new file mode 100644 index 000000000..153456447 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/binary.ts @@ -0,0 +1,70 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreBinaryBuilderInitial = SingleStoreBinaryBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreBinary'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBinaryBuilder> + extends SingleStoreColumnBuilder< + T, + SingleStoreBinaryConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreBinaryBuilder'; + + constructor(name: T['name'], length: number | undefined) { + super(name, 'string', 'SingleStoreBinary'); + this.config.length = length; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBinary> { + return new SingleStoreBinary>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBinary> extends SingleStoreColumn< + T, + SingleStoreBinaryConfig +> { + static override readonly [entityKind]: string = 'SingleStoreBinary'; + + length: number | undefined = this.config.length; + + getSQLType(): string { + return this.length === undefined ? `binary` : `binary(${this.length})`; + } +} + +export interface SingleStoreBinaryConfig { + length?: number; +} + +export function binary(): SingleStoreBinaryBuilderInitial<''>; +export function binary( + config?: SingleStoreBinaryConfig, +): SingleStoreBinaryBuilderInitial<''>; +export function binary( + name: TName, + config?: SingleStoreBinaryConfig, +): SingleStoreBinaryBuilderInitial; +export function binary(a?: string | SingleStoreBinaryConfig, b: SingleStoreBinaryConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreBinaryBuilder(name, config.length); +} diff --git a/drizzle-orm/src/singlestore-core/columns/boolean.ts b/drizzle-orm/src/singlestore-core/columns/boolean.ts new file mode 100644 index 000000000..bf48ff1da --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/boolean.ts @@ -0,0 +1,58 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreBooleanBuilderInitial = SingleStoreBooleanBuilder<{ + name: TName; + dataType: 'boolean'; + columnType: 'SingleStoreBoolean'; + data: boolean; + driverParam: number | boolean; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreBooleanBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreBooleanBuilder'; + + constructor(name: T['name']) { + super(name, 'boolean', 'SingleStoreBoolean'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreBoolean> { + return new SingleStoreBoolean>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreBoolean> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreBoolean'; + + getSQLType(): string { + return 'boolean'; + } + + override mapFromDriverValue(value: number | boolean): boolean { + if (typeof value === 'boolean') { + return value; + } + return value === 1; + } +} + +export function boolean(): SingleStoreBooleanBuilderInitial<''>; +export function boolean(name: TName): SingleStoreBooleanBuilderInitial; +export function boolean(name?: string) { + return new SingleStoreBooleanBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/char.ts b/drizzle-orm/src/singlestore-core/columns/char.ts new file mode 100644 index 000000000..512460f92 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/char.ts @@ -0,0 +1,75 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreCharBuilderInitial = + SingleStoreCharBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; + }>; + +export class SingleStoreCharBuilder> + extends SingleStoreColumnBuilder< + T, + SingleStoreCharConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreCharBuilder'; + + constructor(name: T['name'], config: SingleStoreCharConfig) { + super(name, 'string', 'SingleStoreChar'); + this.config.length = config.length; + this.config.enum = config.enum; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreChar & { enumValues: T['enumValues'] }> { + return new SingleStoreChar & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreChar> + extends SingleStoreColumn> +{ + static override readonly [entityKind]: string = 'SingleStoreChar'; + + readonly length: number | undefined = this.config.length; + override readonly enumValues = this.config.enum; + + getSQLType(): string { + return this.length === undefined ? `char` : `char(${this.length})`; + } +} + +export interface SingleStoreCharConfig< + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, +> { + length?: number; + enum?: TEnum; +} + +export function char(): SingleStoreCharBuilderInitial<'', [string, ...string[]]>; +export function char>( + config?: SingleStoreCharConfig>, +): SingleStoreCharBuilderInitial<'', Writable>; +export function char>( + name: TName, + config?: SingleStoreCharConfig>, +): SingleStoreCharBuilderInitial>; +export function char(a?: string | SingleStoreCharConfig, b: SingleStoreCharConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreCharBuilder(name, config as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts new file mode 100644 index 000000000..c0dc7fb67 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -0,0 +1,117 @@ +import type { + ColumnBuilderBase, + ColumnBuilderBaseConfig, + ColumnBuilderExtraConfig, + ColumnBuilderRuntimeConfig, + ColumnDataType, + HasDefault, + IsAutoincrement, + MakeColumnConfig, +} from '~/column-builder.ts'; +import { ColumnBuilder } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { Column } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable, SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { Update } from '~/utils.ts'; +import { uniqueKeyName } from '../unique-constraint.ts'; + +export interface SingleStoreColumnBuilderBase< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, + TTypeConfig extends object = object, +> extends ColumnBuilderBase {} + +export interface SingleStoreGeneratedColumnConfig { + mode?: 'virtual' | 'stored'; +} + +export abstract class SingleStoreColumnBuilder< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig & { + data: any; + }, + TRuntimeConfig extends object = object, + TTypeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends ColumnBuilder + implements SingleStoreColumnBuilderBase +{ + static override readonly [entityKind]: string = 'SingleStoreColumnBuilder'; + + unique(name?: string): this { + this.config.isUnique = true; + this.config.uniqueName = name; + return this; + } + + // TODO: Implement generated columns for SingleStore (https://docs.singlestore.com/cloud/create-a-database/using-persistent-computed-columns/) + /** @internal */ + generatedAlwaysAs(as: SQL | T['data'] | (() => SQL), config?: SingleStoreGeneratedColumnConfig) { + this.config.generated = { + as, + type: 'always', + mode: config?.mode ?? 'virtual', + }; + return this as any; + } + + /** @internal */ + abstract build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreColumn>; +} + +// To understand how to use `SingleStoreColumn` and `AnySingleStoreColumn`, see `Column` and `AnyColumn` documentation. +export abstract class SingleStoreColumn< + T extends ColumnBaseConfig = ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends Column { + static override readonly [entityKind]: string = 'SingleStoreColumn'; + + constructor( + override readonly table: SingleStoreTable, + config: ColumnBuilderRuntimeConfig, + ) { + if (!config.uniqueName) { + config.uniqueName = uniqueKeyName(table, [config.name]); + } + super(table, config); + } +} + +export type AnySingleStoreColumn> = {}> = + SingleStoreColumn< + Required, TPartial>> + >; + +export interface SingleStoreColumnWithAutoIncrementConfig { + autoIncrement: boolean; +} + +export abstract class SingleStoreColumnBuilderWithAutoIncrement< + T extends ColumnBuilderBaseConfig = ColumnBuilderBaseConfig, + TRuntimeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends SingleStoreColumnBuilder { + static override readonly [entityKind]: string = 'SingleStoreColumnBuilderWithAutoIncrement'; + + constructor(name: NonNullable, dataType: T['dataType'], columnType: T['columnType']) { + super(name, dataType, columnType); + this.config.autoIncrement = false; + } + + autoincrement(): IsAutoincrement> { + this.config.autoIncrement = true; + this.config.hasDefault = true; + return this as IsAutoincrement>; + } +} + +export abstract class SingleStoreColumnWithAutoIncrement< + T extends ColumnBaseConfig = ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreColumnWithAutoIncrement'; + + readonly autoIncrement: boolean = this.config.autoIncrement; +} diff --git a/drizzle-orm/src/singlestore-core/columns/custom.ts b/drizzle-orm/src/singlestore-core/columns/custom.ts new file mode 100644 index 000000000..964e077d7 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/custom.ts @@ -0,0 +1,235 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/sql.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type ConvertCustomConfig> = + & { + name: TName; + dataType: 'custom'; + columnType: 'SingleStoreCustomColumn'; + data: T['data']; + driverParam: T['driverData']; + enumValues: undefined; + generated: undefined; + } + & (T['notNull'] extends true ? { notNull: true } : {}) + & (T['default'] extends true ? { hasDefault: true } : {}); + +export interface SingleStoreCustomColumnInnerConfig { + customTypeValues: CustomTypeValues; +} + +export class SingleStoreCustomColumnBuilder> + extends SingleStoreColumnBuilder< + T, + { + fieldConfig: CustomTypeValues['config']; + customTypeParams: CustomTypeParams; + }, + { + singlestoreColumnBuilderBrand: 'SingleStoreCustomColumnBuilderBrand'; + } + > +{ + static override readonly [entityKind]: string = 'SingleStoreCustomColumnBuilder'; + + constructor( + name: T['name'], + fieldConfig: CustomTypeValues['config'], + customTypeParams: CustomTypeParams, + ) { + super(name, 'custom', 'SingleStoreCustomColumn'); + this.config.fieldConfig = fieldConfig; + this.config.customTypeParams = customTypeParams; + } + + /** @internal */ + build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreCustomColumn> { + return new SingleStoreCustomColumn>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreCustomColumn> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreCustomColumn'; + + private sqlName: string; + private mapTo?: (value: T['data']) => T['driverParam']; + private mapFrom?: (value: T['driverParam']) => T['data']; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreCustomColumnBuilder['config'], + ) { + super(table, config); + this.sqlName = config.customTypeParams.dataType(config.fieldConfig); + this.mapTo = config.customTypeParams.toDriver; + this.mapFrom = config.customTypeParams.fromDriver; + } + + getSQLType(): string { + return this.sqlName; + } + + override mapFromDriverValue(value: T['driverParam']): T['data'] { + return typeof this.mapFrom === 'function' ? this.mapFrom(value) : value as T['data']; + } + + override mapToDriverValue(value: T['data']): T['driverParam'] { + return typeof this.mapTo === 'function' ? this.mapTo(value) : value as T['data']; + } +} + +export type CustomTypeValues = { + /** + * Required type for custom column, that will infer proper type model + * + * Examples: + * + * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar` + * + * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer` + */ + data: unknown; + + /** + * Type helper, that represents what type database driver is accepting for specific database data type + */ + driverData?: unknown; + + /** + * What config type should be used for {@link CustomTypeParams} `dataType` generation + */ + config?: Record; + + /** + * Whether the config argument should be required or not + * @default false + */ + configRequired?: boolean; + + /** + * If your custom data type should be notNull by default you can use `notNull: true` + * + * @example + * const customSerial = customType<{ data: number, notNull: true, default: true }>({ + * dataType() { + * return 'serial'; + * }, + * }); + */ + notNull?: boolean; + + /** + * If your custom data type has default you can use `default: true` + * + * @example + * const customSerial = customType<{ data: number, notNull: true, default: true }>({ + * dataType() { + * return 'serial'; + * }, + * }); + */ + default?: boolean; +}; + +export interface CustomTypeParams { + /** + * Database data type string representation, that is used for migrations + * @example + * ``` + * `jsonb`, `text` + * ``` + * + * If database data type needs additional params you can use them from `config` param + * @example + * ``` + * `varchar(256)`, `numeric(2,3)` + * ``` + * + * To make `config` be of specific type please use config generic in {@link CustomTypeValues} + * + * @example + * Usage example + * ``` + * dataType() { + * return 'boolean'; + * }, + * ``` + * Or + * ``` + * dataType(config) { + * return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`; + * } + * ``` + */ + dataType: (config: T['config'] | (Equal extends true ? never : undefined)) => string; + + /** + * Optional mapping function, between user input and driver + * @example + * For example, when using jsonb we need to map JS/TS object to string before writing to database + * ``` + * toDriver(value: TData): string { + * return JSON.stringify(value); + * } + * ``` + */ + toDriver?: (value: T['data']) => T['driverData'] | SQL; + + /** + * Optional mapping function, that is responsible for data mapping from database to JS/TS code + * @example + * For example, when using timestamp we need to map string Date representation to JS Date + * ``` + * fromDriver(value: string): Date { + * return new Date(value); + * }, + * ``` + */ + fromDriver?: (value: T['driverData']) => T['data']; +} + +/** + * Custom singlestore database data type generator + */ +export function customType( + customTypeParams: CustomTypeParams, +): Equal extends true ? { + & T['config']>( + fieldConfig: TConfig, + ): SingleStoreCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig: T['config'], + ): SingleStoreCustomColumnBuilder>; + } + : { + (): SingleStoreCustomColumnBuilder>; + & T['config']>( + fieldConfig?: TConfig, + ): SingleStoreCustomColumnBuilder>; + ( + dbName: TName, + fieldConfig?: T['config'], + ): SingleStoreCustomColumnBuilder>; + } +{ + return ( + a?: TName | T['config'], + b?: T['config'], + ): SingleStoreCustomColumnBuilder> => { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreCustomColumnBuilder(name as ConvertCustomConfig['name'], config, customTypeParams); + }; +} diff --git a/drizzle-orm/src/singlestore-core/columns/date.common.ts b/drizzle-orm/src/singlestore-core/columns/date.common.ts new file mode 100644 index 000000000..39b2507eb --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/date.common.ts @@ -0,0 +1,41 @@ +import type { + ColumnBuilderBaseConfig, + ColumnBuilderExtraConfig, + ColumnDataType, + HasDefault, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import { sql } from '~/sql/sql.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export interface SingleStoreDateColumnBaseConfig { + hasOnUpdateNow: boolean; +} + +export abstract class SingleStoreDateColumnBaseBuilder< + T extends ColumnBuilderBaseConfig, + TRuntimeConfig extends object = object, + TExtraConfig extends ColumnBuilderExtraConfig = ColumnBuilderExtraConfig, +> extends SingleStoreColumnBuilder { + static override readonly [entityKind]: string = 'SingleStoreDateColumnBuilder'; + + defaultNow() { + return this.default(sql`now()`); + } + + onUpdateNow(): HasDefault { + this.config.hasOnUpdateNow = true; + this.config.hasDefault = true; + return this as HasDefault; + } +} + +export abstract class SingleStoreDateBaseColumn< + T extends ColumnBaseConfig, + TRuntimeConfig extends object = object, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreDateColumn'; + + readonly hasOnUpdateNow: boolean = this.config.hasOnUpdateNow; +} diff --git a/drizzle-orm/src/singlestore-core/columns/date.ts b/drizzle-orm/src/singlestore-core/columns/date.ts new file mode 100644 index 000000000..70da74f3a --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/date.ts @@ -0,0 +1,123 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreDateBuilderInitial = SingleStoreDateBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'SingleStoreDate'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreDateBuilder'; + + constructor(name: T['name']) { + super(name, 'date', 'SingleStoreDate'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDate> { + return new SingleStoreDate>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDate> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreDate'; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return `date`; + } + + override mapFromDriverValue(value: string): Date { + return new Date(value); + } +} + +export type SingleStoreDateStringBuilderInitial = SingleStoreDateStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreDateString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateStringBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreDateStringBuilder'; + + constructor(name: T['name']) { + super(name, 'string', 'SingleStoreDateString'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateString> { + return new SingleStoreDateString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDateString> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreDateString'; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateStringBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return `date`; + } +} + +export interface SingleStoreDateConfig { + mode?: TMode; +} + +export function date(): SingleStoreDateBuilderInitial<''>; +export function date( + config?: SingleStoreDateConfig, +): Equal extends true ? SingleStoreDateStringBuilderInitial<''> : SingleStoreDateBuilderInitial<''>; +export function date( + name: TName, + config?: SingleStoreDateConfig, +): Equal extends true ? SingleStoreDateStringBuilderInitial + : SingleStoreDateBuilderInitial; +export function date(a?: string | SingleStoreDateConfig, b?: SingleStoreDateConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config?.mode === 'string') { + return new SingleStoreDateStringBuilder(name); + } + return new SingleStoreDateBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/datetime.ts b/drizzle-orm/src/singlestore-core/columns/datetime.ts new file mode 100644 index 000000000..16f137901 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/datetime.ts @@ -0,0 +1,153 @@ +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreDateTimeBuilderInitial = SingleStoreDateTimeBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'SingleStoreDateTime'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateTimeBuilder> + extends SingleStoreColumnBuilder +{ + /** @internal */ + // TODO: we need to add a proper support for SingleStore + override generatedAlwaysAs( + _as: SQL | (() => SQL) | T['data'], + _config?: Partial>, + ): HasGenerated { + throw new Error('Method not implemented.'); + } + static override readonly [entityKind]: string = 'SingleStoreDateTimeBuilder'; + + constructor(name: T['name']) { + super(name, 'date', 'SingleStoreDateTime'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateTime> { + return new SingleStoreDateTime>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDateTime> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreDateTime'; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateTimeBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return `datetime`; + } + + override mapToDriverValue(value: Date): unknown { + return value.toISOString().replace('T', ' ').replace('Z', ''); + } + + override mapFromDriverValue(value: string): Date { + return new Date(value.replace(' ', 'T') + 'Z'); + } +} + +export type SingleStoreDateTimeStringBuilderInitial = SingleStoreDateTimeStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreDateTimeString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDateTimeStringBuilder> + extends SingleStoreColumnBuilder +{ + /** @internal */ + // TODO: we need to add a proper support for SingleStore + override generatedAlwaysAs( + _as: SQL | (() => SQL) | T['data'], + _config?: Partial>, + ): HasGenerated { + throw new Error('Method not implemented.'); + } + static override readonly [entityKind]: string = 'SingleStoreDateTimeStringBuilder'; + + constructor(name: T['name']) { + super(name, 'string', 'SingleStoreDateTimeString'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDateTimeString> { + return new SingleStoreDateTimeString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDateTimeString> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreDateTimeString'; + + constructor( + table: AnySingleStoreTable<{ name: T['tableName'] }>, + config: SingleStoreDateTimeStringBuilder['config'], + ) { + super(table, config); + } + + getSQLType(): string { + return `datetime`; + } +} + +export interface SingleStoreDatetimeConfig { + mode?: TMode; +} + +export function datetime(): SingleStoreDateTimeBuilderInitial<''>; +export function datetime( + config?: SingleStoreDatetimeConfig, +): Equal extends true ? SingleStoreDateTimeStringBuilderInitial<''> + : SingleStoreDateTimeBuilderInitial<''>; +export function datetime( + name: TName, + config?: SingleStoreDatetimeConfig, +): Equal extends true ? SingleStoreDateTimeStringBuilderInitial + : SingleStoreDateTimeBuilderInitial; +export function datetime(a?: string | SingleStoreDatetimeConfig, b?: SingleStoreDatetimeConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config?.mode === 'string') { + return new SingleStoreDateTimeStringBuilder(name); + } + return new SingleStoreDateTimeBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/decimal.ts b/drizzle-orm/src/singlestore-core/columns/decimal.ts new file mode 100644 index 000000000..d0c61732c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/decimal.ts @@ -0,0 +1,90 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreDecimalBuilderInitial = SingleStoreDecimalBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreDecimal'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDecimalBuilder< + T extends ColumnBuilderBaseConfig<'string', 'SingleStoreDecimal'>, +> extends SingleStoreColumnBuilderWithAutoIncrement< + T, + SingleStoreDecimalConfig +> { + static override readonly [entityKind]: string = 'SingleStoreDecimalBuilder'; + + constructor(name: T['name'], config: SingleStoreDecimalConfig | undefined) { + super(name, 'string', 'SingleStoreDecimal'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + this.config.unsigned = config?.unsigned; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDecimal> { + return new SingleStoreDecimal>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDecimal< + T extends ColumnBaseConfig<'string', 'SingleStoreDecimal'>, +> extends SingleStoreColumnWithAutoIncrement { + static override readonly [entityKind]: string = 'SingleStoreDecimal'; + + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; + + getSQLType(): string { + let type = ''; + if (this.precision !== undefined && this.scale !== undefined) { + type += `decimal(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + type += 'decimal'; + } else { + type += `decimal(${this.precision})`; + } + type = type === 'decimal(10,0)' || type === 'decimal(10)' ? 'decimal' : type; + return this.unsigned ? `${type} unsigned` : type; + } +} + +export interface SingleStoreDecimalConfig { + precision?: number; + scale?: number; + unsigned?: boolean; +} + +export function decimal(): SingleStoreDecimalBuilderInitial<''>; +export function decimal( + config: SingleStoreDecimalConfig, +): SingleStoreDecimalBuilderInitial<''>; +export function decimal( + name: TName, + config?: SingleStoreDecimalConfig, +): SingleStoreDecimalBuilderInitial; +export function decimal( + a?: string | SingleStoreDecimalConfig, + b: SingleStoreDecimalConfig = {}, +) { + const { name, config } = getColumnNameAndConfig( + a, + b, + ); + return new SingleStoreDecimalBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/double.ts b/drizzle-orm/src/singlestore-core/columns/double.ts new file mode 100644 index 000000000..103731eab --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/double.ts @@ -0,0 +1,80 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreDoubleBuilderInitial = SingleStoreDoubleBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreDouble'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreDoubleBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreDoubleBuilder'; + + constructor(name: T['name'], config: SingleStoreDoubleConfig | undefined) { + super(name, 'number', 'SingleStoreDouble'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + this.config.unsigned = config?.unsigned; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreDouble> { + return new SingleStoreDouble>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreDouble> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreDouble'; + + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; + + getSQLType(): string { + let type = ''; + if (this.precision !== undefined && this.scale !== undefined) { + type += `double(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + type += 'double'; + } else { + type += `double(${this.precision})`; + } + return this.unsigned ? `${type} unsigned` : type; + } +} + +export interface SingleStoreDoubleConfig { + precision?: number; + scale?: number; + unsigned?: boolean; +} + +export function double(): SingleStoreDoubleBuilderInitial<''>; +export function double( + config?: SingleStoreDoubleConfig, +): SingleStoreDoubleBuilderInitial<''>; +export function double( + name: TName, + config?: SingleStoreDoubleConfig, +): SingleStoreDoubleBuilderInitial; +export function double(a?: string | SingleStoreDoubleConfig, b?: SingleStoreDoubleConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreDoubleBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/enum.ts b/drizzle-orm/src/singlestore-core/columns/enum.ts new file mode 100644 index 000000000..98f3d78e3 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/enum.ts @@ -0,0 +1,84 @@ +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + GeneratedColumnConfig, + HasGenerated, + MakeColumnConfig, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import type { SQL } from '~/sql/index.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreEnumColumnBuilderInitial = + SingleStoreEnumColumnBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreEnumColumn'; + data: TEnum[number]; + driverParam: string; + enumValues: TEnum; + generated: undefined; + }>; + +export class SingleStoreEnumColumnBuilder> + extends SingleStoreColumnBuilder +{ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override generatedAlwaysAs( + as: SQL | (() => SQL) | T['data'], + config?: Partial>, + ): HasGenerated { + throw new Error('Method not implemented.'); + } + static override readonly [entityKind]: string = 'SingleStoreEnumColumnBuilder'; + + constructor(name: T['name'], values: T['enumValues']) { + super(name, 'string', 'SingleStoreEnumColumn'); + this.config.enumValues = values; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreEnumColumn & { enumValues: T['enumValues'] }> { + return new SingleStoreEnumColumn & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreEnumColumn> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreEnumColumn'; + + override readonly enumValues = this.config.enumValues; + + getSQLType(): string { + return `enum(${this.enumValues!.map((value) => `'${value}'`).join(',')})`; + } +} + +export function singlestoreEnum>( + values: T | Writable, +): SingleStoreEnumColumnBuilderInitial<'', Writable>; +export function singlestoreEnum>( + name: TName, + values: T | Writable, +): SingleStoreEnumColumnBuilderInitial>; +export function singlestoreEnum( + a?: string | readonly [string, ...string[]] | [string, ...string[]], + b?: readonly [string, ...string[]] | [string, ...string[]], +): any { + const { name, config: values } = getColumnNameAndConfig(a, b); + + if (values.length === 0) { + throw new Error(`You have an empty array for "${name}" enum values`); + } + + return new SingleStoreEnumColumnBuilder(name, values as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/float.ts b/drizzle-orm/src/singlestore-core/columns/float.ts new file mode 100644 index 000000000..9cfed6131 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/float.ts @@ -0,0 +1,80 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreFloatBuilderInitial = SingleStoreFloatBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreFloat'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreFloatBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreFloatBuilder'; + + constructor(name: T['name'], config: SingleStoreFloatConfig | undefined) { + super(name, 'number', 'SingleStoreFloat'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + this.config.unsigned = config?.unsigned; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreFloat> { + return new SingleStoreFloat>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreFloat> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreFloat'; + + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; + + getSQLType(): string { + let type = ''; + if (this.precision !== undefined && this.scale !== undefined) { + type += `float(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + type += 'float'; + } else { + type += `float(${this.precision},0)`; + } + return this.unsigned ? `${type} unsigned` : type; + } +} + +export interface SingleStoreFloatConfig { + precision?: number; + scale?: number; + unsigned?: boolean; +} + +export function float(): SingleStoreFloatBuilderInitial<''>; +export function float( + config?: SingleStoreFloatConfig, +): SingleStoreFloatBuilderInitial<''>; +export function float( + name: TName, + config?: SingleStoreFloatConfig, +): SingleStoreFloatBuilderInitial; +export function float(a?: string | SingleStoreFloatConfig, b?: SingleStoreFloatConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreFloatBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/index.ts b/drizzle-orm/src/singlestore-core/columns/index.ts new file mode 100644 index 000000000..b51f0fac4 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/index.ts @@ -0,0 +1,25 @@ +export * from './bigint.ts'; +export * from './binary.ts'; +export * from './boolean.ts'; +export * from './char.ts'; +export * from './common.ts'; +export * from './custom.ts'; +export * from './date.ts'; +export * from './datetime.ts'; +export * from './decimal.ts'; +export * from './double.ts'; +export * from './enum.ts'; +export * from './float.ts'; +export * from './int.ts'; +export * from './json.ts'; +export * from './mediumint.ts'; +export * from './real.ts'; +export * from './serial.ts'; +export * from './smallint.ts'; +export * from './text.ts'; +export * from './time.ts'; +export * from './timestamp.ts'; +export * from './tinyint.ts'; +export * from './varbinary.ts'; +export * from './varchar.ts'; +export * from './year.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/int.ts b/drizzle-orm/src/singlestore-core/columns/int.ts new file mode 100644 index 000000000..b6a661f66 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/int.ts @@ -0,0 +1,71 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreIntBuilderInitial = SingleStoreIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreInt> { + return new SingleStoreInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreInt'; + + getSQLType(): string { + return `int${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export interface SingleStoreIntConfig { + unsigned?: boolean; +} + +export function int(): SingleStoreIntBuilderInitial<''>; +export function int( + config?: SingleStoreIntConfig, +): SingleStoreIntBuilderInitial<''>; +export function int( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreIntBuilderInitial; +export function int(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/json.ts b/drizzle-orm/src/singlestore-core/columns/json.ts new file mode 100644 index 000000000..97ff759d1 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/json.ts @@ -0,0 +1,53 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreJsonBuilderInitial = SingleStoreJsonBuilder<{ + name: TName; + dataType: 'json'; + columnType: 'SingleStoreJson'; + data: unknown; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreJsonBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreJsonBuilder'; + + constructor(name: T['name']) { + super(name, 'json', 'SingleStoreJson'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreJson> { + return new SingleStoreJson>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreJson> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreJson'; + + getSQLType(): string { + return 'json'; + } + + override mapToDriverValue(value: T['data']): string { + return JSON.stringify(value); + } +} + +export function json(): SingleStoreJsonBuilderInitial<''>; +export function json(name: TName): SingleStoreJsonBuilderInitial; +export function json(name?: string) { + return new SingleStoreJsonBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/mediumint.ts b/drizzle-orm/src/singlestore-core/columns/mediumint.ts new file mode 100644 index 000000000..4a5fa80f9 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/mediumint.ts @@ -0,0 +1,68 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; + +export type SingleStoreMediumIntBuilderInitial = SingleStoreMediumIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreMediumInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreMediumIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreMediumIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreMediumInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreMediumInt> { + return new SingleStoreMediumInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreMediumInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreMediumInt'; + + getSQLType(): string { + return `mediumint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function mediumint(): SingleStoreMediumIntBuilderInitial<''>; +export function mediumint( + config?: SingleStoreIntConfig, +): SingleStoreMediumIntBuilderInitial<''>; +export function mediumint( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreMediumIntBuilderInitial; +export function mediumint(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreMediumIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/real.ts b/drizzle-orm/src/singlestore-core/columns/real.ts new file mode 100644 index 000000000..53d15345c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/real.ts @@ -0,0 +1,81 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreRealBuilderInitial = SingleStoreRealBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreReal'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreRealBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement< + T, + SingleStoreRealConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreRealBuilder'; + + constructor(name: T['name'], config: SingleStoreRealConfig | undefined) { + super(name, 'number', 'SingleStoreReal'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreReal> { + return new SingleStoreReal>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreReal> + extends SingleStoreColumnWithAutoIncrement< + T, + SingleStoreRealConfig + > +{ + static override readonly [entityKind]: string = 'SingleStoreReal'; + + precision: number | undefined = this.config.precision; + scale: number | undefined = this.config.scale; + + getSQLType(): string { + if (this.precision !== undefined && this.scale !== undefined) { + return `real(${this.precision}, ${this.scale})`; + } else if (this.precision === undefined) { + return 'real'; + } else { + return `real(${this.precision})`; + } + } +} + +export interface SingleStoreRealConfig { + precision?: number; + scale?: number; +} + +export function real(): SingleStoreRealBuilderInitial<''>; +export function real( + config?: SingleStoreRealConfig, +): SingleStoreRealBuilderInitial<''>; +export function real( + name: TName, + config?: SingleStoreRealConfig, +): SingleStoreRealBuilderInitial; +export function real(a?: string | SingleStoreRealConfig, b: SingleStoreRealConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreRealBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/serial.ts b/drizzle-orm/src/singlestore-core/columns/serial.ts new file mode 100644 index 000000000..df415d47e --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/serial.ts @@ -0,0 +1,76 @@ +import type { + ColumnBuilderBaseConfig, + ColumnBuilderRuntimeConfig, + HasDefault, + IsAutoincrement, + IsPrimaryKey, + MakeColumnConfig, + NotNull, +} from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; + +export type SingleStoreSerialBuilderInitial = IsAutoincrement< + IsPrimaryKey< + NotNull< + HasDefault< + SingleStoreSerialBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + enumValues: undefined; + generated: undefined; + }> + > + > + > +>; + +export class SingleStoreSerialBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreSerialBuilder'; + + constructor(name: T['name']) { + super(name, 'number', 'SingleStoreSerial'); + this.config.hasDefault = true; + this.config.autoIncrement = true; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreSerial> { + return new SingleStoreSerial>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreSerial< + T extends ColumnBaseConfig<'number', 'SingleStoreSerial'>, +> extends SingleStoreColumnWithAutoIncrement { + static override readonly [entityKind]: string = 'SingleStoreSerial'; + + getSQLType(): string { + return 'serial'; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function serial(): SingleStoreSerialBuilderInitial<''>; +export function serial(name: TName): SingleStoreSerialBuilderInitial; +export function serial(name?: string) { + return new SingleStoreSerialBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/smallint.ts b/drizzle-orm/src/singlestore-core/columns/smallint.ts new file mode 100644 index 000000000..3f504b68c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/smallint.ts @@ -0,0 +1,68 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; + +export type SingleStoreSmallIntBuilderInitial = SingleStoreSmallIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreSmallInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreSmallIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreSmallIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreSmallInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreSmallInt> { + return new SingleStoreSmallInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreSmallInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreSmallInt'; + + getSQLType(): string { + return `smallint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function smallint(): SingleStoreSmallIntBuilderInitial<''>; +export function smallint( + config?: SingleStoreIntConfig, +): SingleStoreSmallIntBuilderInitial<''>; +export function smallint( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreSmallIntBuilderInitial; +export function smallint(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreSmallIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/text.ts b/drizzle-orm/src/singlestore-core/columns/text.ts new file mode 100644 index 000000000..425da550f --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/text.ts @@ -0,0 +1,116 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreTextColumnType = 'tinytext' | 'text' | 'mediumtext' | 'longtext'; + +export type SingleStoreTextBuilderInitial = + SingleStoreTextBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreText'; + data: TEnum[number]; + driverParam: string; + enumValues: TEnum; + generated: undefined; + }>; + +export class SingleStoreTextBuilder> + extends SingleStoreColumnBuilder< + T, + { textType: SingleStoreTextColumnType; enumValues: T['enumValues'] } + > +{ + static override readonly [entityKind]: string = 'SingleStoreTextBuilder'; + + constructor(name: T['name'], textType: SingleStoreTextColumnType, config: SingleStoreTextConfig) { + super(name, 'string', 'SingleStoreText'); + this.config.textType = textType; + this.config.enumValues = config.enum; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreText> { + return new SingleStoreText>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreText> + extends SingleStoreColumn +{ + static override readonly [entityKind]: string = 'SingleStoreText'; + + private textType: SingleStoreTextColumnType = this.config.textType; + + override readonly enumValues = this.config.enumValues; + + getSQLType(): string { + return this.textType; + } +} + +export interface SingleStoreTextConfig< + TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, +> { + enum?: TEnum; +} + +export function text(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function text>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function text>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function text(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'text', config as any); +} + +export function tinytext(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function tinytext>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function tinytext>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function tinytext(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'tinytext', config as any); +} + +export function mediumtext(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function mediumtext>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function mediumtext>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function mediumtext(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'mediumtext', config as any); +} + +export function longtext(): SingleStoreTextBuilderInitial<'', [string, ...string[]]>; +export function longtext>( + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial<'', Writable>; +export function longtext>( + name: TName, + config?: SingleStoreTextConfig>, +): SingleStoreTextBuilderInitial>; +export function longtext(a?: string | SingleStoreTextConfig, b: SingleStoreTextConfig = {}): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTextBuilder(name, 'longtext', config as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/time.ts b/drizzle-orm/src/singlestore-core/columns/time.ts new file mode 100644 index 000000000..b7605a4ee --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/time.ts @@ -0,0 +1,55 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreTimeBuilderInitial = SingleStoreTimeBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreTime'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTimeBuilder> + extends SingleStoreColumnBuilder< + T + > +{ + static override readonly [entityKind]: string = 'SingleStoreTimeBuilder'; + + constructor( + name: T['name'], + ) { + super(name, 'string', 'SingleStoreTime'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTime> { + return new SingleStoreTime>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreTime< + T extends ColumnBaseConfig<'string', 'SingleStoreTime'>, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreTime'; + + getSQLType(): string { + return `time`; + } +} + +export function time(): SingleStoreTimeBuilderInitial<''>; +export function time(name: TName): SingleStoreTimeBuilderInitial; +export function time(name?: string) { + return new SingleStoreTimeBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/columns/timestamp.ts b/drizzle-orm/src/singlestore-core/columns/timestamp.ts new file mode 100644 index 000000000..ea7342fd7 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/timestamp.ts @@ -0,0 +1,125 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { sql } from '~/sql/sql.ts'; +import { type Equal, getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreDateBaseColumn, SingleStoreDateColumnBaseBuilder } from './date.common.ts'; + +export type SingleStoreTimestampBuilderInitial = SingleStoreTimestampBuilder<{ + name: TName; + dataType: 'date'; + columnType: 'SingleStoreTimestamp'; + data: Date; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTimestampBuilder> + extends SingleStoreDateColumnBaseBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreTimestampBuilder'; + + constructor(name: T['name']) { + super(name, 'date', 'SingleStoreTimestamp'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTimestamp> { + return new SingleStoreTimestamp>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } + + override defaultNow() { + return this.default(sql`CURRENT_TIMESTAMP`); + } +} + +export class SingleStoreTimestamp> + extends SingleStoreDateBaseColumn +{ + static override readonly [entityKind]: string = 'SingleStoreTimestamp'; + + getSQLType(): string { + return `timestamp`; + } + + override mapFromDriverValue(value: string): Date { + return new Date(value + '+0000'); + } + + override mapToDriverValue(value: Date): string { + return value.toISOString().slice(0, -1).replace('T', ' '); + } +} + +export type SingleStoreTimestampStringBuilderInitial = SingleStoreTimestampStringBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreTimestampString'; + data: string; + driverParam: string | number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTimestampStringBuilder< + T extends ColumnBuilderBaseConfig<'string', 'SingleStoreTimestampString'>, +> extends SingleStoreDateColumnBaseBuilder { + static override readonly [entityKind]: string = 'SingleStoreTimestampStringBuilder'; + + constructor(name: T['name']) { + super(name, 'string', 'SingleStoreTimestampString'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTimestampString> { + return new SingleStoreTimestampString>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } + + override defaultNow() { + return this.default(sql`CURRENT_TIMESTAMP`); + } +} + +export class SingleStoreTimestampString> + extends SingleStoreDateBaseColumn +{ + static override readonly [entityKind]: string = 'SingleStoreTimestampString'; + + getSQLType(): string { + return `timestamp`; + } +} + +export interface SingleStoreTimestampConfig { + mode?: TMode; +} + +export function timestamp(): SingleStoreTimestampBuilderInitial<''>; +export function timestamp( + config?: SingleStoreTimestampConfig, +): Equal extends true ? SingleStoreTimestampStringBuilderInitial<''> + : SingleStoreTimestampBuilderInitial<''>; +export function timestamp( + name: TName, + config?: SingleStoreTimestampConfig, +): Equal extends true ? SingleStoreTimestampStringBuilderInitial + : SingleStoreTimestampBuilderInitial; +export function timestamp(a?: string | SingleStoreTimestampConfig, b: SingleStoreTimestampConfig = {}) { + const { name, config } = getColumnNameAndConfig(a, b); + if (config?.mode === 'string') { + return new SingleStoreTimestampStringBuilder(name); + } + return new SingleStoreTimestampBuilder(name); +} diff --git a/drizzle-orm/src/singlestore-core/columns/tinyint.ts b/drizzle-orm/src/singlestore-core/columns/tinyint.ts new file mode 100644 index 000000000..090619a6d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/tinyint.ts @@ -0,0 +1,68 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumnBuilderWithAutoIncrement, SingleStoreColumnWithAutoIncrement } from './common.ts'; +import type { SingleStoreIntConfig } from './int.ts'; + +export type SingleStoreTinyIntBuilderInitial = SingleStoreTinyIntBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreTinyInt'; + data: number; + driverParam: number | string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreTinyIntBuilder> + extends SingleStoreColumnBuilderWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreTinyIntBuilder'; + + constructor(name: T['name'], config?: SingleStoreIntConfig) { + super(name, 'number', 'SingleStoreTinyInt'); + this.config.unsigned = config ? config.unsigned : false; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreTinyInt> { + return new SingleStoreTinyInt>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreTinyInt> + extends SingleStoreColumnWithAutoIncrement +{ + static override readonly [entityKind]: string = 'SingleStoreTinyInt'; + + getSQLType(): string { + return `tinyint${this.config.unsigned ? ' unsigned' : ''}`; + } + + override mapFromDriverValue(value: number | string): number { + if (typeof value === 'string') { + return Number(value); + } + return value; + } +} + +export function tinyint(): SingleStoreTinyIntBuilderInitial<''>; +export function tinyint( + config?: SingleStoreIntConfig, +): SingleStoreTinyIntBuilderInitial<''>; +export function tinyint( + name: TName, + config?: SingleStoreIntConfig, +): SingleStoreTinyIntBuilderInitial; +export function tinyint(a?: string | SingleStoreIntConfig, b?: SingleStoreIntConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreTinyIntBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/varbinary.ts b/drizzle-orm/src/singlestore-core/columns/varbinary.ts new file mode 100644 index 000000000..c55aa8071 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/varbinary.ts @@ -0,0 +1,66 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreVarBinaryBuilderInitial = SingleStoreVarBinaryBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreVarBinary'; + data: string; + driverParam: string; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreVarBinaryBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreVarBinaryBuilder'; + + /** @internal */ + constructor(name: T['name'], config: SingleStoreVarbinaryOptions) { + super(name, 'string', 'SingleStoreVarBinary'); + this.config.length = config?.length; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreVarBinary> { + return new SingleStoreVarBinary>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreVarBinary< + T extends ColumnBaseConfig<'string', 'SingleStoreVarBinary'>, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreVarBinary'; + + length: number | undefined = this.config.length; + + getSQLType(): string { + return this.length === undefined ? `varbinary` : `varbinary(${this.length})`; + } +} + +export interface SingleStoreVarbinaryOptions { + length: number; +} + +export function varbinary( + config: SingleStoreVarbinaryOptions, +): SingleStoreVarBinaryBuilderInitial<''>; +export function varbinary( + name: TName, + config: SingleStoreVarbinaryOptions, +): SingleStoreVarBinaryBuilderInitial; +export function varbinary(a?: string | SingleStoreVarbinaryOptions, b?: SingleStoreVarbinaryOptions) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreVarBinaryBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/columns/varchar.ts b/drizzle-orm/src/singlestore-core/columns/varchar.ts new file mode 100644 index 000000000..2c39491d7 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/varchar.ts @@ -0,0 +1,75 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreVarCharBuilderInitial = + SingleStoreVarCharBuilder< + { + name: TName; + dataType: 'string'; + columnType: 'SingleStoreVarChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; + } + >; + +export class SingleStoreVarCharBuilder> + extends SingleStoreColumnBuilder> +{ + static override readonly [entityKind]: string = 'SingleStoreVarCharBuilder'; + + /** @internal */ + constructor(name: T['name'], config: SingleStoreVarCharConfig) { + super(name, 'string', 'SingleStoreVarChar'); + this.config.length = config.length; + this.config.enum = config.enum; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreVarChar & { enumValues: T['enumValues'] }> { + return new SingleStoreVarChar & { enumValues: T['enumValues'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreVarChar> + extends SingleStoreColumn> +{ + static override readonly [entityKind]: string = 'SingleStoreVarChar'; + + readonly length: number | undefined = this.config.length; + + override readonly enumValues = this.config.enum; + + getSQLType(): string { + return this.length === undefined ? `varchar` : `varchar(${this.length})`; + } +} + +export interface SingleStoreVarCharConfig< + TEnum extends string[] | readonly string[] | undefined = string[] | readonly string[] | undefined, +> { + length: number; + enum?: TEnum; +} + +export function varchar>( + config: SingleStoreVarCharConfig>, +): SingleStoreVarCharBuilderInitial<'', Writable>; +export function varchar>( + name: TName, + config: SingleStoreVarCharConfig>, +): SingleStoreVarCharBuilderInitial>; +export function varchar(a?: string | SingleStoreVarCharConfig, b?: SingleStoreVarCharConfig): any { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreVarCharBuilder(name, config as any); +} diff --git a/drizzle-orm/src/singlestore-core/columns/year.ts b/drizzle-orm/src/singlestore-core/columns/year.ts new file mode 100644 index 000000000..37f3d55a3 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/year.ts @@ -0,0 +1,51 @@ +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreYearBuilderInitial = SingleStoreYearBuilder<{ + name: TName; + dataType: 'number'; + columnType: 'SingleStoreYear'; + data: number; + driverParam: number; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreYearBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreYearBuilder'; + + constructor(name: T['name']) { + super(name, 'number', 'SingleStoreYear'); + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreYear> { + return new SingleStoreYear>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SingleStoreYear< + T extends ColumnBaseConfig<'number', 'SingleStoreYear'>, +> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreYear'; + + getSQLType(): string { + return `year`; + } +} + +export function year(): SingleStoreYearBuilderInitial<''>; +export function year(name: TName): SingleStoreYearBuilderInitial; +export function year(name?: string) { + return new SingleStoreYearBuilder(name ?? ''); +} diff --git a/drizzle-orm/src/singlestore-core/db.ts b/drizzle-orm/src/singlestore-core/db.ts new file mode 100644 index 000000000..1d64448da --- /dev/null +++ b/drizzle-orm/src/singlestore-core/db.ts @@ -0,0 +1,516 @@ +import type { ResultSetHeader } from 'mysql2/promise'; +import { entityKind } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreDriverDatabase } from '~/singlestore/driver.ts'; +import { type ColumnsSelection, type SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; +import { WithSubquery } from '~/subquery.ts'; +import type { SingleStoreDialect } from './dialect.ts'; +import { SingleStoreCountBuilder } from './query-builders/count.ts'; +import { + QueryBuilder, + SingleStoreDeleteBase, + SingleStoreInsertBuilder, + SingleStoreSelectBuilder, + SingleStoreUpdateBuilder, +} from './query-builders/index.ts'; +import type { SelectedFields } from './query-builders/select.types.ts'; +import type { + PreparedQueryHKTBase, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, + SingleStoreTransaction, + SingleStoreTransactionConfig, +} from './session.ts'; +import type { WithSubqueryWithSelection } from './subquery.ts'; +import type { SingleStoreTable } from './table.ts'; + +export class SingleStoreDatabase< + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record = {}, + TSchema extends TablesRelationalConfig = ExtractTablesWithRelations, +> { + static readonly [entityKind]: string = 'SingleStoreDatabase'; + + declare readonly _: { + readonly schema: TSchema | undefined; + readonly fullSchema: TFullSchema; + readonly tableNamesMap: Record; + }; + + // We are waiting for SingleStore support for `json_array` function + /**@inrernal */ + query: unknown; + + constructor( + /** @internal */ + readonly dialect: SingleStoreDialect, + /** @internal */ + readonly session: SingleStoreSession, + schema: RelationalSchemaConfig | undefined, + ) { + this._ = schema + ? { + schema: schema.schema, + fullSchema: schema.fullSchema as TFullSchema, + tableNamesMap: schema.tableNamesMap, + } + : { + schema: undefined, + fullSchema: {} as TFullSchema, + tableNamesMap: {}, + }; + this.query = {} as typeof this['query']; + // this.queryNotSupported = true; + // if (this._.schema) { + // for (const [tableName, columns] of Object.entries(this._.schema)) { + // (this.query as SingleStoreDatabase>['query'])[tableName] = + // new RelationalQueryBuilder( + // schema!.fullSchema, + // this._.schema, + // this._.tableNamesMap, + // schema!.fullSchema[tableName] as SingleStoreTable, + // columns, + // dialect, + // session, + // ); + // } + // } + } + + /** + * Creates a subquery that defines a temporary named result set as a CTE. + * + * It is useful for breaking down complex queries into simpler parts and for reusing the result set in subsequent parts of the query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#with-clause} + * + * @param alias The alias for the subquery. + * + * Failure to provide an alias will result in a DrizzleTypeError, preventing the subquery from being referenced in other queries. + * + * @example + * + * ```ts + * // Create a subquery with alias 'sq' and use it in the select query + * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42))); + * + * const result = await db.with(sq).select().from(sq); + * ``` + * + * To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query, you need to add aliases to them: + * + * ```ts + * // Select an arbitrary SQL value as a field in a CTE and reference it in the main query + * const sq = db.$with('sq').as(db.select({ + * name: sql`upper(${users.name})`.as('name'), + * }) + * .from(users)); + * + * const result = await db.with(sq).select({ name: sq.name }).from(sq); + * ``` + */ + $with(alias: TAlias) { + const self = this; + return { + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): WithSubqueryWithSelection { + if (typeof qb === 'function') { + qb = qb(new QueryBuilder(self.dialect)); + } + + return new Proxy( + new WithSubquery(qb.getSQL(), qb.getSelectedFields() as SelectedFields, alias, true), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as WithSubqueryWithSelection; + }, + }; + } + + $count( + source: SingleStoreTable | SQL | SQLWrapper, // SingleStoreViewBase | + filters?: SQL, + ) { + return new SingleStoreCountBuilder({ source, filters, session: this.session }); + } + + /** + * Incorporates a previously defined CTE (using `$with`) into the main query. + * + * This method allows the main query to reference a temporary named result set. + * + * See docs: {@link https://orm.drizzle.team/docs/select#with-clause} + * + * @param queries The CTEs to incorporate into the main query. + * + * @example + * + * ```ts + * // Define a subquery 'sq' as a CTE using $with + * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42))); + * + * // Incorporate the CTE 'sq' into the main query and select from it + * const result = await db.with(sq).select().from(sq); + * ``` + */ + with(...queries: WithSubquery[]) { + const self = this; + + /** + * Creates a select query. + * + * Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select} + * + * @param fields The selection object. + * + * @example + * + * ```ts + * // Select all columns and all rows from the 'cars' table + * const allCars: Car[] = await db.select().from(cars); + * + * // Select specific columns and all rows from the 'cars' table + * const carsIdsAndBrands: { id: number; brand: string }[] = await db.select({ + * id: cars.id, + * brand: cars.brand + * }) + * .from(cars); + * ``` + * + * Like in SQL, you can use arbitrary expressions as selection fields, not just table columns: + * + * ```ts + * // Select specific columns along with expression and all rows from the 'cars' table + * const carsIdsAndLowerNames: { id: number; lowerBrand: string }[] = await db.select({ + * id: cars.id, + * lowerBrand: sql`lower(${cars.brand})`, + * }) + * .from(cars); + * ``` + */ + function select(): SingleStoreSelectBuilder; + function select( + fields: TSelection, + ): SingleStoreSelectBuilder; + function select(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: self.session, + dialect: self.dialect, + withList: queries, + }); + } + + /** + * Adds `distinct` expression to the select query. + * + * Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select#distinct} + * + * @param fields The selection object. + * + * @example + * ```ts + * // Select all unique rows from the 'cars' table + * await db.selectDistinct() + * .from(cars) + * .orderBy(cars.id, cars.brand, cars.color); + * + * // Select all unique brands from the 'cars' table + * await db.selectDistinct({ brand: cars.brand }) + * .from(cars) + * .orderBy(cars.brand); + * ``` + */ + function selectDistinct(): SingleStoreSelectBuilder; + function selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + function selectDistinct( + fields?: SelectedFields, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: self.session, + dialect: self.dialect, + withList: queries, + distinct: true, + }); + } + + /** + * Creates an update query. + * + * Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated. + * + * Use `.set()` method to specify which values to update. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param table The table to update. + * + * @example + * + * ```ts + * // Update all rows in the 'cars' table + * await db.update(cars).set({ color: 'red' }); + * + * // Update rows with filters and conditions + * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW')); + * ``` + */ + function update( + table: TTable, + ): SingleStoreUpdateBuilder { + return new SingleStoreUpdateBuilder(table, self.session, self.dialect, queries); + } + + /** + * Creates a delete query. + * + * Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param table The table to delete from. + * + * @example + * + * ```ts + * // Delete all rows in the 'cars' table + * await db.delete(cars); + * + * // Delete rows with filters and conditions + * await db.delete(cars).where(eq(cars.color, 'green')); + * ``` + */ + function delete_( + table: TTable, + ): SingleStoreDeleteBase { + return new SingleStoreDeleteBase(table, self.session, self.dialect, queries); + } + + return { select, selectDistinct, update, delete: delete_ }; + } + + /** + * Creates a select query. + * + * Calling this method with no arguments will select all columns from the table. Pass a selection object to specify the columns you want to select. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select} + * + * @param fields The selection object. + * + * @example + * + * ```ts + * // Select all columns and all rows from the 'cars' table + * const allCars: Car[] = await db.select().from(cars); + * + * // Select specific columns and all rows from the 'cars' table + * const carsIdsAndBrands: { id: number; brand: string }[] = await db.select({ + * id: cars.id, + * brand: cars.brand + * }) + * .from(cars); + * ``` + * + * Like in SQL, you can use arbitrary expressions as selection fields, not just table columns: + * + * ```ts + * // Select specific columns along with expression and all rows from the 'cars' table + * const carsIdsAndLowerNames: { id: number; lowerBrand: string }[] = await db.select({ + * id: cars.id, + * lowerBrand: sql`lower(${cars.brand})`, + * }) + * .from(cars); + * ``` + */ + select(): SingleStoreSelectBuilder; + select( + fields: TSelection, + ): SingleStoreSelectBuilder; + select(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ fields: fields ?? undefined, session: this.session, dialect: this.dialect }); + } + + /** + * Adds `distinct` expression to the select query. + * + * Calling this method will return only unique values. When multiple columns are selected, it returns rows with unique combinations of values in these columns. + * + * Use `.from()` method to specify which table to select from. + * + * See docs: {@link https://orm.drizzle.team/docs/select#distinct} + * + * @param fields The selection object. + * + * @example + * ```ts + * // Select all unique rows from the 'cars' table + * await db.selectDistinct() + * .from(cars) + * .orderBy(cars.id, cars.brand, cars.color); + * + * // Select all unique brands from the 'cars' table + * await db.selectDistinct({ brand: cars.brand }) + * .from(cars) + * .orderBy(cars.brand); + * ``` + */ + selectDistinct(): SingleStoreSelectBuilder; + selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + selectDistinct(fields?: SelectedFields): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: this.session, + dialect: this.dialect, + distinct: true, + }); + } + + /** + * Creates an update query. + * + * Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated. + * + * Use `.set()` method to specify which values to update. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param table The table to update. + * + * @example + * + * ```ts + * // Update all rows in the 'cars' table + * await db.update(cars).set({ color: 'red' }); + * + * // Update rows with filters and conditions + * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW')); + * ``` + */ + update( + table: TTable, + ): SingleStoreUpdateBuilder { + return new SingleStoreUpdateBuilder(table, this.session, this.dialect); + } + + /** + * Creates an insert query. + * + * Calling this method will create new rows in a table. Use `.values()` method to specify which values to insert. + * + * See docs: {@link https://orm.drizzle.team/docs/insert} + * + * @param table The table to insert into. + * + * @example + * + * ```ts + * // Insert one row + * await db.insert(cars).values({ brand: 'BMW' }); + * + * // Insert multiple rows + * await db.insert(cars).values([{ brand: 'BMW' }, { brand: 'Porsche' }]); + * ``` + */ + insert( + table: TTable, + ): SingleStoreInsertBuilder { + return new SingleStoreInsertBuilder(table, this.session, this.dialect); + } + + /** + * Creates a delete query. + * + * Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param table The table to delete from. + * + * @example + * + * ```ts + * // Delete all rows in the 'cars' table + * await db.delete(cars); + * + * // Delete rows with filters and conditions + * await db.delete(cars).where(eq(cars.color, 'green')); + * ``` + */ + delete( + table: TTable, + ): SingleStoreDeleteBase { + return new SingleStoreDeleteBase(table, this.session, this.dialect); + } + + execute( + query: SQLWrapper | string, + ): Promise> { + return this.session.execute(typeof query === 'string' ? sql.raw(query) : query.getSQL()); + } + + transaction( + transaction: ( + tx: SingleStoreTransaction, + config?: SingleStoreTransactionConfig, + ) => Promise, + config?: SingleStoreTransactionConfig, + ): Promise { + return this.session.transaction(transaction, config); + } +} + +export type SingleStoreWithReplicas = Q & { $primary: Q }; + +export const withReplicas = < + Q extends SingleStoreDriverDatabase, +>( + primary: Q, + replicas: [Q, ...Q[]], + getReplica: (replicas: Q[]) => Q = () => replicas[Math.floor(Math.random() * replicas.length)]!, +): SingleStoreWithReplicas => { + const select: Q['select'] = (...args: []) => getReplica(replicas).select(...args); + const selectDistinct: Q['selectDistinct'] = (...args: []) => getReplica(replicas).selectDistinct(...args); + const $with: Q['with'] = (...args: []) => getReplica(replicas).with(...args); + + const update: Q['update'] = (...args: [any]) => primary.update(...args); + const insert: Q['insert'] = (...args: [any]) => primary.insert(...args); + const $delete: Q['delete'] = (...args: [any]) => primary.delete(...args); + const execute: Q['execute'] = (...args: [any]) => primary.execute(...args); + const transaction: Q['transaction'] = (...args: [any, any]) => primary.transaction(...args); + + return { + ...primary, + update, + insert, + delete: $delete, + execute, + transaction, + $primary: primary, + select, + selectDistinct, + with: $with, + get query() { + return getReplica(replicas).query; + }, + }; +}; diff --git a/drizzle-orm/src/singlestore-core/dialect.ts b/drizzle-orm/src/singlestore-core/dialect.ts new file mode 100644 index 000000000..99a485ac6 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/dialect.ts @@ -0,0 +1,813 @@ +import { aliasedTable, aliasedTableColumn, mapColumnsInAliasedSQLToAlias, mapColumnsInSQLToAlias } from '~/alias.ts'; +import { CasingCache } from '~/casing.ts'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import { DrizzleError } from '~/errors.ts'; +import { and, eq } from '~/expressions.ts'; +import type { MigrationConfig, MigrationMeta } from '~/migrator.ts'; +import { + type BuildRelationalQueryResult, + type DBQueryConfig, + getOperators, + getOrderByOperators, + Many, + normalizeRelation, + One, + type Relation, + type TableRelationalConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import type { Name, Placeholder, QueryWithTypings, SQLChunk } from '~/sql/sql.ts'; +import { Param, SQL, sql, View } from '~/sql/sql.ts'; +import { Subquery } from '~/subquery.ts'; +import { getTableName, getTableUniqueName, Table } from '~/table.ts'; +import { type Casing, orderSelectedFields, type UpdateSet } from '~/utils.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import { SingleStoreColumn } from './columns/common.ts'; +import type { SingleStoreDeleteConfig } from './query-builders/delete.ts'; +import type { SingleStoreInsertConfig } from './query-builders/insert.ts'; +import type { + SelectedFieldsOrdered, + SingleStoreSelectConfig, + SingleStoreSelectJoinConfig, +} from './query-builders/select.types.ts'; +import type { SingleStoreUpdateConfig } from './query-builders/update.ts'; +import type { SingleStoreSession } from './session.ts'; +import { SingleStoreTable } from './table.ts'; +/* import { SingleStoreViewBase } from './view-base.ts'; */ + +export interface SingleStoreDialectConfig { + casing?: Casing; +} + +export class SingleStoreDialect { + static readonly [entityKind]: string = 'SingleStoreDialect'; + + /** @internal */ + readonly casing: CasingCache; + + constructor(config?: SingleStoreDialectConfig) { + this.casing = new CasingCache(config?.casing); + } + + async migrate( + migrations: MigrationMeta[], + session: SingleStoreSession, + config: Omit, + ): Promise { + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; + const migrationTableCreate = sql` + create table if not exists ${sql.identifier(migrationsTable)} ( + id serial primary key, + hash text not null, + created_at bigint + ) + `; + await session.execute(migrationTableCreate); + + const dbMigrations = await session.all<{ id: number; hash: string; created_at: string }>( + sql`select id, hash, created_at from ${sql.identifier(migrationsTable)} order by created_at desc limit 1`, + ); + + const lastDbMigration = dbMigrations[0]; + + await session.transaction(async (tx) => { + for (const migration of migrations) { + if ( + !lastDbMigration + || Number(lastDbMigration.created_at) < migration.folderMillis + ) { + for (const stmt of migration.sql) { + await tx.execute(sql.raw(stmt)); + } + await tx.execute( + sql`insert into ${ + sql.identifier(migrationsTable) + } (\`hash\`, \`created_at\`) values(${migration.hash}, ${migration.folderMillis})`, + ); + } + } + }); + } + + escapeName(name: string): string { + return `\`${name}\``; + } + + escapeParam(_num: number): string { + return `?`; + } + + escapeString(str: string): string { + return `'${str.replace(/'/g, "''")}'`; + } + + private buildWithCTE(queries: Subquery[] | undefined): SQL | undefined { + if (!queries?.length) return undefined; + + const withSqlChunks = [sql`with `]; + for (const [i, w] of queries.entries()) { + withSqlChunks.push(sql`${sql.identifier(w._.alias)} as (${w._.sql})`); + if (i < queries.length - 1) { + withSqlChunks.push(sql`, `); + } + } + withSqlChunks.push(sql` `); + return sql.join(withSqlChunks); + } + + buildDeleteQuery({ table, where, returning, withList, limit, orderBy }: SingleStoreDeleteConfig): SQL { + const withSql = this.buildWithCTE(withList); + + const returningSql = returning + ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` + : undefined; + + const whereSql = where ? sql` where ${where}` : undefined; + + const orderBySql = this.buildOrderBy(orderBy); + + const limitSql = this.buildLimit(limit); + + return sql`${withSql}delete from ${table}${whereSql}${orderBySql}${limitSql}${returningSql}`; + } + + buildUpdateSet(table: SingleStoreTable, set: UpdateSet): SQL { + const tableColumns = table[Table.Symbol.Columns]; + + const columnNames = Object.keys(tableColumns).filter((colName) => + set[colName] !== undefined || tableColumns[colName]?.onUpdateFn !== undefined + ); + + const setSize = columnNames.length; + return sql.join(columnNames.flatMap((colName, i) => { + const col = tableColumns[colName]!; + + const value = set[colName] ?? sql.param(col.onUpdateFn!(), col); + const res = sql`${sql.identifier(this.casing.getColumnCasing(col))} = ${value}`; + + if (i < setSize - 1) { + return [res, sql.raw(', ')]; + } + return [res]; + })); + } + + buildUpdateQuery({ table, set, where, returning, withList, limit, orderBy }: SingleStoreUpdateConfig): SQL { + const withSql = this.buildWithCTE(withList); + + const setSql = this.buildUpdateSet(table, set); + + const returningSql = returning + ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` + : undefined; + + const whereSql = where ? sql` where ${where}` : undefined; + + const orderBySql = this.buildOrderBy(orderBy); + + const limitSql = this.buildLimit(limit); + + return sql`${withSql}update ${table} set ${setSql}${whereSql}${orderBySql}${limitSql}${returningSql}`; + } + + /** + * Builds selection SQL with provided fields/expressions + * + * Examples: + * + * `select from` + * + * `insert ... returning ` + * + * If `isSingleTable` is true, then columns won't be prefixed with table name + */ + private buildSelection( + fields: SelectedFieldsOrdered, + { isSingleTable = false }: { isSingleTable?: boolean } = {}, + ): SQL { + const columnsLen = fields.length; + + const chunks = fields + .flatMap(({ field }, i) => { + const chunk: SQLChunk[] = []; + + if (is(field, SQL.Aliased) && field.isSelectionField) { + chunk.push(sql.identifier(field.fieldAlias)); + } else if (is(field, SQL.Aliased) || is(field, SQL)) { + const query = is(field, SQL.Aliased) ? field.sql : field; + + if (isSingleTable) { + chunk.push( + new SQL( + query.queryChunks.map((c) => { + if (is(c, SingleStoreColumn)) { + return sql.identifier(this.casing.getColumnCasing(c)); + } + return c; + }), + ), + ); + } else { + chunk.push(query); + } + + if (is(field, SQL.Aliased)) { + chunk.push(sql` as ${sql.identifier(field.fieldAlias)}`); + } + } else if (is(field, Column)) { + if (isSingleTable) { + chunk.push(sql.identifier(this.casing.getColumnCasing(field))); + } else { + chunk.push(field); + } + } + + if (i < columnsLen - 1) { + chunk.push(sql`, `); + } + + return chunk; + }); + + return sql.join(chunks); + } + + private buildLimit(limit: number | Placeholder | undefined): SQL | undefined { + return typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined; + } + + private buildOrderBy(orderBy: (SingleStoreColumn | SQL | SQL.Aliased)[] | undefined): SQL | undefined { + return orderBy && orderBy.length > 0 ? sql` order by ${sql.join(orderBy, sql`, `)}` : undefined; + } + + buildSelectQuery( + { + withList, + fields, + fieldsFlat, + where, + having, + table, + joins, + orderBy, + groupBy, + limit, + offset, + lockingClause, + distinct, + setOperators, + }: SingleStoreSelectConfig, + ): SQL { + const fieldsList = fieldsFlat ?? orderSelectedFields(fields); + for (const f of fieldsList) { + if ( + is(f.field, Column) + && getTableName(f.field.table) + !== (is(table, Subquery) + ? table._.alias + /* : is(table, SingleStoreViewBase) + ? table[ViewBaseConfig].name */ + : is(table, SQL) + ? undefined + : getTableName(table)) + && !((table) => + joins?.some(({ alias }) => + alias === (table[Table.Symbol.IsAlias] ? getTableName(table) : table[Table.Symbol.BaseName]) + ))(f.field.table) + ) { + const tableName = getTableName(f.field.table); + throw new Error( + `Your "${ + f.path.join('->') + }" field references a column "${tableName}"."${f.field.name}", but the table "${tableName}" is not part of the query! Did you forget to join it?`, + ); + } + } + + const isSingleTable = !joins || joins.length === 0; + + const withSql = this.buildWithCTE(withList); + + const distinctSql = distinct ? sql` distinct` : undefined; + + const selection = this.buildSelection(fieldsList, { isSingleTable }); + + const tableSql = (() => { + if (is(table, Table) && table[Table.Symbol.OriginalName] !== table[Table.Symbol.Name]) { + return sql`${sql.identifier(table[Table.Symbol.OriginalName])} ${sql.identifier(table[Table.Symbol.Name])}`; + } + + return table; + })(); + + const joinsArray: SQL[] = []; + + if (joins) { + for (const [index, joinMeta] of joins.entries()) { + if (index === 0) { + joinsArray.push(sql` `); + } + const table = joinMeta.table; + const lateralSql = joinMeta.lateral ? sql` lateral` : undefined; + + if (is(table, SingleStoreTable)) { + const tableName = table[SingleStoreTable.Symbol.Name]; + const tableSchema = table[SingleStoreTable.Symbol.Schema]; + const origTableName = table[SingleStoreTable.Symbol.OriginalName]; + const alias = tableName === origTableName ? undefined : joinMeta.alias; + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ + tableSchema ? sql`${sql.identifier(tableSchema)}.` : undefined + }${sql.identifier(origTableName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + ); + } else if (is(table, View)) { + const viewName = table[ViewBaseConfig].name; + const viewSchema = table[ViewBaseConfig].schema; + const origViewName = table[ViewBaseConfig].originalName; + const alias = viewName === origViewName ? undefined : joinMeta.alias; + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ + viewSchema ? sql`${sql.identifier(viewSchema)}.` : undefined + }${sql.identifier(origViewName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + ); + } else { + joinsArray.push( + sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${table} on ${joinMeta.on}`, + ); + } + if (index < joins.length - 1) { + joinsArray.push(sql` `); + } + } + } + + const joinsSql = sql.join(joinsArray); + + const whereSql = where ? sql` where ${where}` : undefined; + + const havingSql = having ? sql` having ${having}` : undefined; + + const orderBySql = this.buildOrderBy(orderBy); + + const groupBySql = groupBy && groupBy.length > 0 ? sql` group by ${sql.join(groupBy, sql`, `)}` : undefined; + + const limitSql = this.buildLimit(limit); + + const offsetSql = offset ? sql` offset ${offset}` : undefined; + + let lockingClausesSql; + if (lockingClause) { + const { config, strength } = lockingClause; + lockingClausesSql = sql` for ${sql.raw(strength)}`; + if (config.noWait) { + lockingClausesSql.append(sql` no wait`); + } else if (config.skipLocked) { + lockingClausesSql.append(sql` skip locked`); + } + } + + const finalQuery = + sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`; + + if (setOperators.length > 0) { + return this.buildSetOperations(finalQuery, setOperators); + } + + return finalQuery; + } + + buildSetOperations(leftSelect: SQL, setOperators: SingleStoreSelectConfig['setOperators']): SQL { + const [setOperator, ...rest] = setOperators; + + if (!setOperator) { + throw new Error('Cannot pass undefined values to any set operator'); + } + + if (rest.length === 0) { + return this.buildSetOperationQuery({ leftSelect, setOperator }); + } + + // Some recursive magic here + return this.buildSetOperations( + this.buildSetOperationQuery({ leftSelect, setOperator }), + rest, + ); + } + + buildSetOperationQuery({ + leftSelect, + setOperator: { type, isAll, rightSelect, limit, orderBy, offset }, + }: { leftSelect: SQL; setOperator: SingleStoreSelectConfig['setOperators'][number] }): SQL { + const leftChunk = sql`(${leftSelect.getSQL()}) `; + const rightChunk = sql`(${rightSelect.getSQL()})`; + + let orderBySql; + if (orderBy && orderBy.length > 0) { + const orderByValues: (SQL | Name)[] = []; + + // The next bit is necessary because the sql operator replaces ${table.column} with `table`.`column` + // which is invalid SingleStore syntax, Table from one of the SELECTs cannot be used in global ORDER clause + for (const orderByUnit of orderBy) { + if (is(orderByUnit, SingleStoreColumn)) { + orderByValues.push(sql.identifier(this.casing.getColumnCasing(orderByUnit))); + } else if (is(orderByUnit, SQL)) { + for (let i = 0; i < orderByUnit.queryChunks.length; i++) { + const chunk = orderByUnit.queryChunks[i]; + + if (is(chunk, SingleStoreColumn)) { + orderByUnit.queryChunks[i] = sql.identifier(this.casing.getColumnCasing(chunk)); + } + } + + orderByValues.push(sql`${orderByUnit}`); + } else { + orderByValues.push(sql`${orderByUnit}`); + } + } + + orderBySql = sql` order by ${sql.join(orderByValues, sql`, `)} `; + } + + const limitSql = typeof limit === 'object' || (typeof limit === 'number' && limit >= 0) + ? sql` limit ${limit}` + : undefined; + + const operatorChunk = sql.raw(`${type} ${isAll ? 'all ' : ''}`); + + const offsetSql = offset ? sql` offset ${offset}` : undefined; + + return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; + } + + buildInsertQuery( + { table, values, ignore, onConflict }: SingleStoreInsertConfig, + ): { sql: SQL; generatedIds: Record[] } { + // const isSingleValue = values.length === 1; + const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = []; + const columns: Record = table[Table.Symbol.Columns]; + const colEntries: [string, SingleStoreColumn][] = Object.entries(columns).filter(([_, col]) => + !col.shouldDisableInsert() + ); + + const insertOrder = colEntries.map(([, column]) => sql.identifier(this.casing.getColumnCasing(column))); + const generatedIdsResponse: Record[] = []; + + for (const [valueIndex, value] of values.entries()) { + const generatedIds: Record = {}; + + const valueList: (SQLChunk | SQL)[] = []; + for (const [fieldName, col] of colEntries) { + const colValue = value[fieldName]; + if (colValue === undefined || (is(colValue, Param) && colValue.value === undefined)) { + // eslint-disable-next-line unicorn/no-negated-condition + if (col.defaultFn !== undefined) { + const defaultFnResult = col.defaultFn(); + generatedIds[fieldName] = defaultFnResult; + const defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col); + valueList.push(defaultValue); + // eslint-disable-next-line unicorn/no-negated-condition + } else if (!col.default && col.onUpdateFn !== undefined) { + const onUpdateFnResult = col.onUpdateFn(); + const newValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col); + valueList.push(newValue); + } else { + valueList.push(sql`default`); + } + } else { + if (col.defaultFn && is(colValue, Param)) { + generatedIds[fieldName] = colValue.value; + } + valueList.push(colValue); + } + } + + generatedIdsResponse.push(generatedIds); + valuesSqlList.push(valueList); + if (valueIndex < values.length - 1) { + valuesSqlList.push(sql`, `); + } + } + + const valuesSql = sql.join(valuesSqlList); + + const ignoreSql = ignore ? sql` ignore` : undefined; + + const onConflictSql = onConflict ? sql` on duplicate key ${onConflict}` : undefined; + + return { + sql: sql`insert${ignoreSql} into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}`, + generatedIds: generatedIdsResponse, + }; + } + + sqlToQuery(sql: SQL, invokeSource?: 'indexes' | undefined): QueryWithTypings { + return sql.toQuery({ + casing: this.casing, + escapeName: this.escapeName, + escapeParam: this.escapeParam, + escapeString: this.escapeString, + invokeSource, + }); + } + + buildRelationalQuery({ + fullSchema, + schema, + tableNamesMap, + table, + tableConfig, + queryConfig: config, + tableAlias, + nestedQueryRelation, + joinOn, + }: { + fullSchema: Record; + schema: TablesRelationalConfig; + tableNamesMap: Record; + table: SingleStoreTable; + tableConfig: TableRelationalConfig; + queryConfig: true | DBQueryConfig<'many', true>; + tableAlias: string; + nestedQueryRelation?: Relation; + joinOn?: SQL; + }): BuildRelationalQueryResult { + let selection: BuildRelationalQueryResult['selection'] = []; + let limit, offset, orderBy: SingleStoreSelectConfig['orderBy'], where; + const joins: SingleStoreSelectJoinConfig[] = []; + + if (config === true) { + const selectionEntries = Object.entries(tableConfig.columns); + selection = selectionEntries.map(( + [key, value], + ) => ({ + dbKey: value.name, + tsKey: key, + field: aliasedTableColumn(value as SingleStoreColumn, tableAlias), + relationTableTsKey: undefined, + isJson: false, + selection: [], + })); + } else { + const aliasedColumns = Object.fromEntries( + Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value, tableAlias)]), + ); + + if (config.where) { + const whereSql = typeof config.where === 'function' + ? config.where(aliasedColumns, getOperators()) + : config.where; + where = whereSql && mapColumnsInSQLToAlias(whereSql, tableAlias); + } + + const fieldsSelection: { tsKey: string; value: SingleStoreColumn | SQL.Aliased }[] = []; + let selectedColumns: string[] = []; + + // Figure out which columns to select + if (config.columns) { + let isIncludeMode = false; + + for (const [field, value] of Object.entries(config.columns)) { + if (value === undefined) { + continue; + } + + if (field in tableConfig.columns) { + if (!isIncludeMode && value === true) { + isIncludeMode = true; + } + selectedColumns.push(field); + } + } + + if (selectedColumns.length > 0) { + selectedColumns = isIncludeMode + ? selectedColumns.filter((c) => config.columns?.[c] === true) + : Object.keys(tableConfig.columns).filter((key) => !selectedColumns.includes(key)); + } + } else { + // Select all columns if selection is not specified + selectedColumns = Object.keys(tableConfig.columns); + } + + for (const field of selectedColumns) { + const column = tableConfig.columns[field]! as SingleStoreColumn; + fieldsSelection.push({ tsKey: field, value: column }); + } + + let selectedRelations: { + tsKey: string; + queryConfig: true | DBQueryConfig<'many', false>; + relation: Relation; + }[] = []; + + // Figure out which relations to select + if (config.with) { + selectedRelations = Object.entries(config.with) + .filter((entry): entry is [typeof entry[0], NonNullable] => !!entry[1]) + .map(([tsKey, queryConfig]) => ({ tsKey, queryConfig, relation: tableConfig.relations[tsKey]! })); + } + + let extras; + + // Figure out which extras to select + if (config.extras) { + extras = typeof config.extras === 'function' + ? config.extras(aliasedColumns, { sql }) + : config.extras; + for (const [tsKey, value] of Object.entries(extras)) { + fieldsSelection.push({ + tsKey, + value: mapColumnsInAliasedSQLToAlias(value, tableAlias), + }); + } + } + + // Transform `fieldsSelection` into `selection` + // `fieldsSelection` shouldn't be used after this point + for (const { tsKey, value } of fieldsSelection) { + selection.push({ + dbKey: is(value, SQL.Aliased) ? value.fieldAlias : tableConfig.columns[tsKey]!.name, + tsKey, + field: is(value, Column) ? aliasedTableColumn(value, tableAlias) : value, + relationTableTsKey: undefined, + isJson: false, + selection: [], + }); + } + + let orderByOrig = typeof config.orderBy === 'function' + ? config.orderBy(aliasedColumns, getOrderByOperators()) + : config.orderBy ?? []; + if (!Array.isArray(orderByOrig)) { + orderByOrig = [orderByOrig]; + } + orderBy = orderByOrig.map((orderByValue) => { + if (is(orderByValue, Column)) { + return aliasedTableColumn(orderByValue, tableAlias) as SingleStoreColumn; + } + return mapColumnsInSQLToAlias(orderByValue, tableAlias); + }); + + limit = config.limit; + offset = config.offset; + + // Process all relations + for ( + const { + tsKey: selectedRelationTsKey, + queryConfig: selectedRelationConfigValue, + relation, + } of selectedRelations + ) { + const normalizedRelation = normalizeRelation(schema, tableNamesMap, relation); + const relationTableName = getTableUniqueName(relation.referencedTable); + const relationTableTsName = tableNamesMap[relationTableName]!; + const relationTableAlias = `${tableAlias}_${selectedRelationTsKey}`; + const joinOn = and( + ...normalizedRelation.fields.map((field, i) => + eq( + aliasedTableColumn(normalizedRelation.references[i]!, relationTableAlias), + aliasedTableColumn(field, tableAlias), + ) + ), + ); + const builtRelation = this.buildRelationalQuery({ + fullSchema, + schema, + tableNamesMap, + table: fullSchema[relationTableTsName] as SingleStoreTable, + tableConfig: schema[relationTableTsName]!, + queryConfig: is(relation, One) + ? (selectedRelationConfigValue === true + ? { limit: 1 } + : { ...selectedRelationConfigValue, limit: 1 }) + : selectedRelationConfigValue, + tableAlias: relationTableAlias, + joinOn, + nestedQueryRelation: relation, + }); + const field = sql`${sql.identifier(relationTableAlias)}.${sql.identifier('data')}`.as(selectedRelationTsKey); + joins.push({ + on: sql`true`, + table: new Subquery(builtRelation.sql as SQL, {}, relationTableAlias), + alias: relationTableAlias, + joinType: 'left', + lateral: true, + }); + selection.push({ + dbKey: selectedRelationTsKey, + tsKey: selectedRelationTsKey, + field, + relationTableTsKey: relationTableTsName, + isJson: true, + selection: builtRelation.selection, + }); + } + } + + if (selection.length === 0) { + throw new DrizzleError({ message: `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}")` }); + } + + let result; + + where = and(joinOn, where); + + if (nestedQueryRelation) { + let field = sql`JSON_TO_ARRAY(${ + sql.join( + selection.map(({ field, tsKey, isJson }) => + isJson + ? sql`${sql.identifier(`${tableAlias}_${tsKey}`)}.${sql.identifier('data')}` + : is(field, SQL.Aliased) + ? field.sql + : field + ), + sql`, `, + ) + })`; + if (is(nestedQueryRelation, Many)) { + field = sql`json_agg(${field})`; + } + const nestedSelection = [{ + dbKey: 'data', + tsKey: 'data', + field: field.as('data'), + isJson: true, + relationTableTsKey: tableConfig.tsName, + selection, + }]; + + const needsSubquery = limit !== undefined || offset !== undefined || (orderBy?.length ?? 0) > 0; + + if (needsSubquery) { + result = this.buildSelectQuery({ + table: aliasedTable(table, tableAlias), + fields: {}, + fieldsFlat: [ + { + path: [], + field: sql.raw('*'), + }, + ...(((orderBy?.length ?? 0) > 0) + ? [{ + path: [], + field: sql`row_number() over (order by ${sql.join(orderBy!, sql`, `)})`, + }] + : []), + ], + where, + limit, + offset, + setOperators: [], + }); + + where = undefined; + limit = undefined; + offset = undefined; + orderBy = undefined; + } else { + result = aliasedTable(table, tableAlias); + } + + result = this.buildSelectQuery({ + table: is(result, SingleStoreTable) ? result : new Subquery(result, {}, tableAlias), + fields: {}, + fieldsFlat: nestedSelection.map(({ field }) => ({ + path: [], + field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field, + })), + joins, + where, + limit, + offset, + orderBy, + setOperators: [], + }); + } else { + result = this.buildSelectQuery({ + table: aliasedTable(table, tableAlias), + fields: {}, + fieldsFlat: selection.map(({ field }) => ({ + path: [], + field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field, + })), + joins, + where, + limit, + offset, + orderBy, + setOperators: [], + }); + } + + return { + tableTsKey: tableConfig.tsName, + sql: result, + selection, + }; + } +} diff --git a/drizzle-orm/src/singlestore-core/expressions.ts b/drizzle-orm/src/singlestore-core/expressions.ts new file mode 100644 index 000000000..6d4284d18 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/expressions.ts @@ -0,0 +1,25 @@ +import { bindIfParam } from '~/expressions.ts'; +import type { Placeholder, SQL, SQLChunk, SQLWrapper } from '~/sql/sql.ts'; +import { sql } from '~/sql/sql.ts'; +import type { SingleStoreColumn } from './columns/index.ts'; + +export * from '~/expressions.ts'; + +export function concat(column: SingleStoreColumn | SQL.Aliased, value: string | Placeholder | SQLWrapper): SQL { + return sql`${column} || ${bindIfParam(value, column)}`; +} + +export function substring( + column: SingleStoreColumn | SQL.Aliased, + { from, for: _for }: { from?: number | Placeholder | SQLWrapper; for?: number | Placeholder | SQLWrapper }, +): SQL { + const chunks: SQLChunk[] = [sql`substring(`, column]; + if (from !== undefined) { + chunks.push(sql` from `, bindIfParam(from, column)); + } + if (_for !== undefined) { + chunks.push(sql` for `, bindIfParam(_for, column)); + } + chunks.push(sql`)`); + return sql.join(chunks); +} diff --git a/drizzle-orm/src/singlestore-core/index.ts b/drizzle-orm/src/singlestore-core/index.ts new file mode 100644 index 000000000..4e7d4268e --- /dev/null +++ b/drizzle-orm/src/singlestore-core/index.ts @@ -0,0 +1,15 @@ +export * from './alias.ts'; +export * from './columns/index.ts'; +export * from './db.ts'; +export * from './dialect.ts'; +export * from './indexes.ts'; +export * from './primary-keys.ts'; +export * from './query-builders/index.ts'; +export * from './schema.ts'; +export * from './session.ts'; +export * from './subquery.ts'; +export * from './table.ts'; +export * from './unique-constraint.ts'; +export * from './utils.ts'; +/* export * from './view-common.ts'; +export * from './view.ts'; */ diff --git a/drizzle-orm/src/singlestore-core/indexes.ts b/drizzle-orm/src/singlestore-core/indexes.ts new file mode 100644 index 000000000..3120cab1b --- /dev/null +++ b/drizzle-orm/src/singlestore-core/indexes.ts @@ -0,0 +1,193 @@ +import { entityKind } from '~/entity.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; +import type { SingleStoreTable } from './table.ts'; + +interface IndexConfig { + name: string; + + columns: IndexColumn[]; + + /** + * If true, the index will be created as `create unique index` instead of `create index`. + */ + unique?: boolean; + + /** + * If set, the index will be created as `create index ... using { 'btree' | 'hash' }`. + */ + using?: 'btree' | 'hash'; + + /** + * If set, the index will be created as `create index ... algorythm { 'default' | 'inplace' | 'copy' }`. + */ + algorythm?: 'default' | 'inplace' | 'copy'; + + /** + * If set, adds locks to the index creation. + */ + lock?: 'default' | 'none' | 'shared' | 'exclusive'; +} + +export type IndexColumn = SingleStoreColumn | SQL; + +export class IndexBuilderOn { + static readonly [entityKind]: string = 'SingleStoreIndexBuilderOn'; + + constructor(private name: string, private unique: boolean) {} + + on(...columns: [IndexColumn, ...IndexColumn[]]): IndexBuilder { + return new IndexBuilder(this.name, columns, this.unique); + } +} + +export interface AnyIndexBuilder { + build(table: SingleStoreTable): Index; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface IndexBuilder extends AnyIndexBuilder {} + +export class IndexBuilder implements AnyIndexBuilder { + static readonly [entityKind]: string = 'SingleStoreIndexBuilder'; + + /** @internal */ + config: IndexConfig; + + constructor(name: string, columns: IndexColumn[], unique: boolean) { + this.config = { + name, + columns, + unique, + }; + } + + using(using: IndexConfig['using']): this { + this.config.using = using; + return this; + } + + algorythm(algorythm: IndexConfig['algorythm']): this { + this.config.algorythm = algorythm; + return this; + } + + lock(lock: IndexConfig['lock']): this { + this.config.lock = lock; + return this; + } + + /** @internal */ + build(table: SingleStoreTable): Index { + return new Index(this.config, table); + } +} + +export class Index { + static readonly [entityKind]: string = 'SingleStoreIndex'; + + readonly config: IndexConfig & { table: SingleStoreTable }; + + constructor(config: IndexConfig, table: SingleStoreTable) { + this.config = { ...config, table }; + } +} + +export type GetColumnsTableName = TColumns extends + AnySingleStoreColumn<{ tableName: infer TTableName extends string }> | AnySingleStoreColumn< + { tableName: infer TTableName extends string } + >[] ? TTableName + : never; + +export function index(name: string): IndexBuilderOn { + return new IndexBuilderOn(name, false); +} + +export function uniqueIndex(name: string): IndexBuilderOn { + return new IndexBuilderOn(name, true); +} + +/* export interface AnyFullTextIndexBuilder { + build(table: SingleStoreTable): FullTextIndex; +} */ +/* +interface FullTextIndexConfig { + version?: number; +} + +interface FullTextIndexFullConfig extends FullTextIndexConfig { + columns: IndexColumn[]; + + name: string; +} + +export class FullTextIndexBuilderOn { + static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilderOn'; + + constructor(private name: string, private config: FullTextIndexConfig) {} + + on(...columns: [IndexColumn, ...IndexColumn[]]): FullTextIndexBuilder { + return new FullTextIndexBuilder({ + name: this.name, + columns: columns, + ...this.config, + }); + } +} */ + +/* +export interface FullTextIndexBuilder extends AnyFullTextIndexBuilder {} + +export class FullTextIndexBuilder implements AnyFullTextIndexBuilder { + static readonly [entityKind]: string = 'SingleStoreFullTextIndexBuilder'; */ + +/** @internal */ +/* config: FullTextIndexFullConfig; + + constructor(config: FullTextIndexFullConfig) { + this.config = config; + } */ + +/** @internal */ +/* build(table: SingleStoreTable): FullTextIndex { + return new FullTextIndex(this.config, table); + } +} + +export class FullTextIndex { + static readonly [entityKind]: string = 'SingleStoreFullTextIndex'; + + readonly config: FullTextIndexConfig & { table: SingleStoreTable }; + + constructor(config: FullTextIndexConfig, table: SingleStoreTable) { + this.config = { ...config, table }; + } +} + +export function fulltext(name: string, config: FullTextIndexConfig): FullTextIndexBuilderOn { + return new FullTextIndexBuilderOn(name, config); +} + +export type SortKeyColumn = SingleStoreColumn | SQL; + +export class SortKeyBuilder { + static readonly [entityKind]: string = 'SingleStoreSortKeyBuilder'; + + constructor(private columns: SortKeyColumn[]) {} */ + +/** @internal */ +/* build(table: SingleStoreTable): SortKey { + return new SortKey(this.columns, table); + } +} + +export class SortKey { + static readonly [entityKind]: string = 'SingleStoreSortKey'; + + constructor(public columns: SortKeyColumn[], public table: SingleStoreTable) {} +} + +export function sortKey(...columns: SortKeyColumn[]): SortKeyBuilder { + return new SortKeyBuilder(columns); +} + */ diff --git a/drizzle-orm/src/singlestore-core/primary-keys.ts b/drizzle-orm/src/singlestore-core/primary-keys.ts new file mode 100644 index 000000000..47dc0a19c --- /dev/null +++ b/drizzle-orm/src/singlestore-core/primary-keys.ts @@ -0,0 +1,63 @@ +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from './columns/index.ts'; +import { SingleStoreTable } from './table.ts'; + +export function primaryKey< + TTableName extends string, + TColumn extends AnySingleStoreColumn<{ tableName: TTableName }>, + TColumns extends AnySingleStoreColumn<{ tableName: TTableName }>[], +>(config: { name?: string; columns: [TColumn, ...TColumns] }): PrimaryKeyBuilder; +/** + * @deprecated: Please use primaryKey({ columns: [] }) instead of this function + * @param columns + */ +export function primaryKey< + TTableName extends string, + TColumns extends AnySingleStoreColumn<{ tableName: TTableName }>[], +>(...columns: TColumns): PrimaryKeyBuilder; +export function primaryKey(...config: any) { + if (config[0].columns) { + return new PrimaryKeyBuilder(config[0].columns, config[0].name); + } + return new PrimaryKeyBuilder(config); +} + +export class PrimaryKeyBuilder { + static readonly [entityKind]: string = 'SingleStorePrimaryKeyBuilder'; + + /** @internal */ + columns: SingleStoreColumn[]; + + /** @internal */ + name?: string; + + constructor( + columns: SingleStoreColumn[], + name?: string, + ) { + this.columns = columns; + this.name = name; + } + + /** @internal */ + build(table: SingleStoreTable): PrimaryKey { + return new PrimaryKey(table, this.columns, this.name); + } +} + +export class PrimaryKey { + static readonly [entityKind]: string = 'SingleStorePrimaryKey'; + + readonly columns: SingleStoreColumn[]; + readonly name?: string; + + constructor(readonly table: SingleStoreTable, columns: SingleStoreColumn[], name?: string) { + this.columns = columns; + this.name = name; + } + + getName(): string { + return this.name + ?? `${this.table[SingleStoreTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/count.ts b/drizzle-orm/src/singlestore-core/query-builders/count.ts new file mode 100644 index 000000000..aba5b2f3f --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/count.ts @@ -0,0 +1,79 @@ +import { entityKind } from '~/entity.ts'; +import { SQL, sql, type SQLWrapper } from '~/sql/sql.ts'; +import type { SingleStoreSession } from '../session.ts'; +import type { SingleStoreTable } from '../table.ts'; +/* import type { SingleStoreViewBase } from '../view-base.ts'; */ + +export class SingleStoreCountBuilder< + TSession extends SingleStoreSession, +> extends SQL implements Promise, SQLWrapper { + private sql: SQL; + + static override readonly [entityKind] = 'SingleStoreCountBuilder'; + [Symbol.toStringTag] = 'SingleStoreCountBuilder'; + + private session: TSession; + + private static buildEmbeddedCount( + source: SingleStoreTable | /* SingleStoreViewBase | */ SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`(select count(*) from ${source}${sql.raw(' where ').if(filters)}${filters})`; + } + + private static buildCount( + source: SingleStoreTable | /* SingleStoreViewBase | */ SQL | SQLWrapper, + filters?: SQL, + ): SQL { + return sql`select count(*) as count from ${source}${sql.raw(' where ').if(filters)}${filters}`; + } + + constructor( + readonly params: { + source: SingleStoreTable | /* SingleStoreViewBase | */ SQL | SQLWrapper; + filters?: SQL; + session: TSession; + }, + ) { + super(SingleStoreCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks); + + this.mapWith(Number); + + this.session = params.session; + + this.sql = SingleStoreCountBuilder.buildCount( + params.source, + params.filters, + ); + } + + then( + onfulfilled?: ((value: number) => TResult1 | PromiseLike) | null | undefined, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, + ): Promise { + return Promise.resolve(this.session.count(this.sql)) + .then( + onfulfilled, + onrejected, + ); + } + + catch( + onRejected?: ((reason: any) => never | PromiseLike) | null | undefined, + ): Promise { + return this.then(undefined, onRejected); + } + + finally(onFinally?: (() => void) | null | undefined): Promise { + return this.then( + (value) => { + onFinally?.(); + return value; + }, + (reason) => { + onFinally?.(); + throw reason; + }, + ); + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/delete.ts b/drizzle-orm/src/singlestore-core/query-builders/delete.ts new file mode 100644 index 000000000..1f41d29ba --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/delete.ts @@ -0,0 +1,207 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; +import type { ValueOrArray } from '~/utils.ts'; +import type { SingleStoreColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; + +export type SingleStoreDeleteWithout< + T extends AnySingleStoreDeleteBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreDeleteBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreDelete< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreDeleteBase; + +export interface SingleStoreDeleteConfig { + where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + table: SingleStoreTable; + returning?: SelectedFieldsOrdered; + withList?: Subquery[]; +} + +export type SingleStoreDeletePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +type SingleStoreDeleteDynamic = SingleStoreDelete< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnySingleStoreDeleteBase = SingleStoreDeleteBase; + +export interface SingleStoreDeleteBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreDeleteBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreDelete'; + + private config: SingleStoreDeleteConfig; + + constructor( + private table: TTable, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + withList?: Subquery[], + ) { + super(); + this.config = { table, withList }; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will delete only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/delete} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be deleted. + * + * ```ts + * // Delete all cars with green color + * db.delete(cars).where(eq(cars.color, 'green')); + * // or + * db.delete(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Delete all BMW cars with a green color + * db.delete(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Delete all cars with the green or blue color + * db.delete(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where(where: SQL | undefined): SingleStoreDeleteWithout { + this.config.where = where; + return this as any; + } + + orderBy( + builder: (deleteTable: TTable) => ValueOrArray, + ): SingleStoreDeleteWithout; + orderBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreDeleteWithout; + orderBy( + ...columns: + | [(deleteTable: TTable) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreDeleteWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): SingleStoreDeleteWithout { + this.config.limit = limit; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildDeleteQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreDeletePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + this.config.returning, + ) as SingleStoreDeletePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreDeleteDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/index.ts b/drizzle-orm/src/singlestore-core/query-builders/index.ts new file mode 100644 index 000000000..704cb4afa --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/index.ts @@ -0,0 +1,11 @@ +/* export * from './attach.ts'; +export * from './branch.ts'; +export * from './createMilestone.ts'; */ +export * from './delete.ts'; +/* export * from './detach.ts'; */ +export * from './insert.ts'; +/* export * from './optimizeTable.ts'; */ +export * from './query-builder.ts'; +export * from './select.ts'; +export * from './select.types.ts'; +export * from './update.ts'; diff --git a/drizzle-orm/src/singlestore-core/query-builders/insert.ts b/drizzle-orm/src/singlestore-core/query-builders/insert.ts new file mode 100644 index 000000000..84a72fdab --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/insert.ts @@ -0,0 +1,305 @@ +import { entityKind, is } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { RunnableQuery } from '~/runnable-query.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; +import { Param, SQL, sql } from '~/sql/sql.ts'; +import type { InferModelFromColumns } from '~/table.ts'; +import { Table } from '~/table.ts'; +import { mapUpdateSet, orderSelectedFields } from '~/utils.ts'; +import type { AnySingleStoreColumn, SingleStoreColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; +import type { SingleStoreUpdateSetSource } from './update.ts'; + +export interface SingleStoreInsertConfig { + table: TTable; + values: Record[]; + ignore: boolean; + onConflict?: SQL; + returning?: SelectedFieldsOrdered; +} + +export type AnySingleStoreInsertConfig = SingleStoreInsertConfig; + +export type SingleStoreInsertValue = + & { + [Key in keyof TTable['$inferInsert']]: TTable['$inferInsert'][Key] | SQL | Placeholder; + } + & {}; + +export class SingleStoreInsertBuilder< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> { + static readonly [entityKind]: string = 'SingleStoreInsertBuilder'; + + private shouldIgnore = false; + + constructor( + private table: TTable, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) {} + + ignore(): this { + this.shouldIgnore = true; + return this; + } + + values(value: SingleStoreInsertValue): SingleStoreInsertBase; + values(values: SingleStoreInsertValue[]): SingleStoreInsertBase; + values( + values: SingleStoreInsertValue | SingleStoreInsertValue[], + ): SingleStoreInsertBase { + values = Array.isArray(values) ? values : [values]; + if (values.length === 0) { + throw new Error('values() must be called with at least one value'); + } + const mappedValues = values.map((entry) => { + const result: Record = {}; + const cols = this.table[Table.Symbol.Columns]; + for (const colKey of Object.keys(entry)) { + const colValue = entry[colKey as keyof typeof entry]; + result[colKey] = is(colValue, SQL) ? colValue : new Param(colValue, cols[colKey]); + } + return result; + }); + + return new SingleStoreInsertBase(this.table, mappedValues, this.shouldIgnore, this.session, this.dialect); + } +} + +export type SingleStoreInsertWithout< + T extends AnySingleStoreInsert, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SingleStoreInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + T['_']['returning'], + TDynamic, + T['_']['excludedMethods'] | '$returning' + >, + T['_']['excludedMethods'] | K + >; + +export type SingleStoreInsertDynamic = SingleStoreInsert< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + T['_']['returning'] +>; + +export type SingleStoreInsertPrepare< + T extends AnySingleStoreInsert, + TReturning extends Record | undefined = undefined, +> = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[]; + iterator: never; + }, + true +>; + +export type SingleStoreInsertOnDuplicateKeyUpdateConfig = { + set: SingleStoreUpdateSetSource; +}; + +export type SingleStoreInsert< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TReturning extends Record | undefined = Record | undefined, +> = SingleStoreInsertBase; + +export type SingleStoreInsertReturning< + T extends AnySingleStoreInsert, + TDynamic extends boolean, +> = SingleStoreInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + InferModelFromColumns>, + TDynamic, + T['_']['excludedMethods'] | '$returning' +>; + +export type AnySingleStoreInsert = SingleStoreInsertBase; + +export interface SingleStoreInsertBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TReturning extends Record | undefined = undefined, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends + QueryPromise : TReturning[]>, + RunnableQuery< + TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[], + 'singlestore' + >, + SQLWrapper +{ + readonly _: { + readonly dialect: 'singlestore'; + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly returning: TReturning; + readonly result: TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[]; + }; +} + +export type PrimaryKeyKeys> = { + [K in keyof T]: T[K]['_']['isPrimaryKey'] extends true ? T[K]['_']['isAutoincrement'] extends true ? K + : T[K]['_']['hasRuntimeDefault'] extends true ? T[K]['_']['isPrimaryKey'] extends true ? K : never + : never + : T[K]['_']['hasRuntimeDefault'] extends true ? T[K]['_']['isPrimaryKey'] extends true ? K : never + : never; +}[keyof T]; + +export type GetPrimarySerialOrDefaultKeys> = { + [K in PrimaryKeyKeys]: T[K]; +}; + +export class SingleStoreInsertBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TReturning extends Record | undefined = undefined, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise : TReturning[]> + implements + RunnableQuery< + TReturning extends undefined ? SingleStoreQueryResultKind : TReturning[], + 'singlestore' + >, + SQLWrapper +{ + static override readonly [entityKind]: string = 'SingleStoreInsert'; + + declare protected $table: TTable; + + private config: SingleStoreInsertConfig; + + constructor( + table: TTable, + values: SingleStoreInsertConfig['values'], + ignore: boolean, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + ) { + super(); + this.config = { table, values, ignore }; + } + + /** + * Adds an `on duplicate key update` clause to the query. + * + * Calling this method will update update the row if any unique index conflicts. MySQL will automatically determine the conflict target based on the primary key and unique indexes. + * + * See docs: {@link https://orm.drizzle.team/docs/insert#on-duplicate-key-update} + * + * @param config The `set` clause + * + * @example + * ```ts + * await db.insert(cars) + * .values({ id: 1, brand: 'BMW'}) + * .onDuplicateKeyUpdate({ set: { brand: 'Porsche' }}); + * ``` + * + * While MySQL does not directly support doing nothing on conflict, you can perform a no-op by setting any column's value to itself and achieve the same effect: + * + * ```ts + * import { sql } from 'drizzle-orm'; + * + * await db.insert(cars) + * .values({ id: 1, brand: 'BMW' }) + * .onDuplicateKeyUpdate({ set: { id: sql`id` } }); + * ``` + */ + onDuplicateKeyUpdate( + config: SingleStoreInsertOnDuplicateKeyUpdateConfig, + ): SingleStoreInsertWithout { + const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set)); + this.config.onConflict = sql`update ${setSql}`; + return this as any; + } + + $returningId(): SingleStoreInsertWithout< + SingleStoreInsertReturning, + TDynamic, + '$returningId' + > { + const returning: SelectedFieldsOrdered = []; + for (const [key, value] of Object.entries(this.config.table[Table.Symbol.Columns])) { + if (value.primary) { + returning.push({ field: value, path: [key] }); + } + } + this.config.returning = orderSelectedFields(this.config.table[Table.Symbol.Columns]); + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildInsertQuery(this.config).sql; + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreInsertPrepare { + const { sql, generatedIds } = this.dialect.buildInsertQuery(this.config); + return this.session.prepareQuery( + this.dialect.sqlToQuery(sql), + undefined, + undefined, + generatedIds, + this.config.returning, + ) as SingleStoreInsertPrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreInsertDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts b/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts new file mode 100644 index 000000000..29d6c2290 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/query-builder.ts @@ -0,0 +1,114 @@ +import { entityKind, is } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreDialectConfig } from '~/singlestore-core/dialect.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { WithSubqueryWithSelection } from '~/singlestore-core/subquery.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import { WithSubquery } from '~/subquery.ts'; +import { SingleStoreSelectBuilder } from './select.ts'; +import type { SelectedFields } from './select.types.ts'; + +export class QueryBuilder { + static readonly [entityKind]: string = 'SingleStoreQueryBuilder'; + + private dialect: SingleStoreDialect | undefined; + private dialectConfig: SingleStoreDialectConfig | undefined; + + constructor(dialect?: SingleStoreDialect | SingleStoreDialectConfig) { + this.dialect = is(dialect, SingleStoreDialect) ? dialect : undefined; + this.dialectConfig = is(dialect, SingleStoreDialect) ? undefined : dialect; + } + + $with(alias: TAlias) { + const queryBuilder = this; + + return { + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): WithSubqueryWithSelection { + if (typeof qb === 'function') { + qb = qb(queryBuilder); + } + + return new Proxy( + new WithSubquery(qb.getSQL(), qb.getSelectedFields() as SelectedFields, alias, true), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as WithSubqueryWithSelection; + }, + }; + } + + with(...queries: WithSubquery[]) { + const self = this; + + function select(): SingleStoreSelectBuilder; + function select( + fields: TSelection, + ): SingleStoreSelectBuilder; + function select( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: self.getDialect(), + withList: queries, + }); + } + + function selectDistinct(): SingleStoreSelectBuilder; + function selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + function selectDistinct( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: self.getDialect(), + withList: queries, + distinct: true, + }); + } + + return { select, selectDistinct }; + } + + select(): SingleStoreSelectBuilder; + select(fields: TSelection): SingleStoreSelectBuilder; + select( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: this.getDialect(), + }); + } + + selectDistinct(): SingleStoreSelectBuilder; + selectDistinct( + fields: TSelection, + ): SingleStoreSelectBuilder; + selectDistinct( + fields?: TSelection, + ): SingleStoreSelectBuilder { + return new SingleStoreSelectBuilder({ + fields: fields ?? undefined, + session: undefined, + dialect: this.getDialect(), + distinct: true, + }); + } + + // Lazy load dialect to avoid circular dependency + private getDialect() { + if (!this.dialect) { + this.dialect = new SingleStoreDialect(this.dialectConfig); + } + + return this.dialect; + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/query.ts b/drizzle-orm/src/singlestore-core/query-builders/query.ts new file mode 100644 index 000000000..c15f7ad59 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/query.ts @@ -0,0 +1,141 @@ +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { + type BuildQueryResult, + type BuildRelationalQueryResult, + type DBQueryConfig, + mapRelationalRow, + type TableRelationalConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import type { Query, QueryWithTypings, SQL } from '~/sql/sql.ts'; +import type { KnownKeysOnly } from '~/utils.ts'; +import type { SingleStoreDialect } from '../dialect.ts'; +import type { + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreSession, +} from '../session.ts'; +import type { SingleStoreTable } from '../table.ts'; + +export class RelationalQueryBuilder< + TPreparedQueryHKT extends PreparedQueryHKTBase, + TSchema extends TablesRelationalConfig, + TFields extends TableRelationalConfig, +> { + static readonly [entityKind]: string = 'SingleStoreRelationalQueryBuilder'; + + constructor( + private fullSchema: Record, + private schema: TSchema, + private tableNamesMap: Record, + private table: SingleStoreTable, + private tableConfig: TableRelationalConfig, + private dialect: SingleStoreDialect, + private session: SingleStoreSession, + ) {} + + findMany>( + config?: KnownKeysOnly>, + ): SingleStoreRelationalQuery[]> { + return new SingleStoreRelationalQuery( + this.fullSchema, + this.schema, + this.tableNamesMap, + this.table, + this.tableConfig, + this.dialect, + this.session, + config ? (config as DBQueryConfig<'many', true>) : {}, + 'many', + ); + } + + findFirst, 'limit'>>( + config?: KnownKeysOnly, 'limit'>>, + ): SingleStoreRelationalQuery | undefined> { + return new SingleStoreRelationalQuery( + this.fullSchema, + this.schema, + this.tableNamesMap, + this.table, + this.tableConfig, + this.dialect, + this.session, + config ? { ...(config as DBQueryConfig<'many', true> | undefined), limit: 1 } : { limit: 1 }, + 'first', + ); + } +} + +export class SingleStoreRelationalQuery< + TPreparedQueryHKT extends PreparedQueryHKTBase, + TResult, +> extends QueryPromise { + static override readonly [entityKind]: string = 'SingleStoreRelationalQuery'; + + declare protected $brand: 'SingleStoreRelationalQuery'; + + constructor( + private fullSchema: Record, + private schema: TablesRelationalConfig, + private tableNamesMap: Record, + private table: SingleStoreTable, + private tableConfig: TableRelationalConfig, + private dialect: SingleStoreDialect, + private session: SingleStoreSession, + private config: DBQueryConfig<'many', true> | true, + private queryMode: 'many' | 'first', + ) { + super(); + } + + prepare() { + const { query, builtQuery } = this._toSQL(); + return this.session.prepareQuery( + builtQuery, + undefined, + (rawRows) => { + const rows = rawRows.map((row) => mapRelationalRow(this.schema, this.tableConfig, row, query.selection)); + if (this.queryMode === 'first') { + return rows[0] as TResult; + } + return rows as TResult; + }, + ) as PreparedQueryKind; + } + + private _getQuery() { + return this.dialect.buildRelationalQuery({ + fullSchema: this.fullSchema, + schema: this.schema, + tableNamesMap: this.tableNamesMap, + table: this.table, + tableConfig: this.tableConfig, + queryConfig: this.config, + tableAlias: this.tableConfig.tsName, + }); + } + + private _toSQL(): { query: BuildRelationalQueryResult; builtQuery: QueryWithTypings } { + const query = this._getQuery(); + + const builtQuery = this.dialect.sqlToQuery(query.sql as SQL); + + return { builtQuery, query }; + } + + /** @internal */ + getSQL(): SQL { + return this._getQuery().sql as SQL; + } + + toSQL(): Query { + return this._toSQL().builtQuery; + } + + override execute(): Promise { + return this.prepare().execute(); + } +} diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.ts b/drizzle-orm/src/singlestore-core/query-builders/select.ts new file mode 100644 index 000000000..36a3893a2 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/select.ts @@ -0,0 +1,1082 @@ +import { entityKind, is } from '~/entity.ts'; +import { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { + BuildSubquerySelection, + GetSelectTableName, + GetSelectTableSelection, + JoinNullability, + JoinType, + SelectMode, + SelectResult, + SetOperator, +} from '~/query-builders/select.types.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreColumn } from '~/singlestore-core/columns/index.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + PreparedQueryHKTBase, + SingleStorePreparedQueryConfig, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SubqueryWithSelection } from '~/singlestore-core/subquery.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { ColumnsSelection, Query } from '~/sql/sql.ts'; +import { SQL } from '~/sql/sql.ts'; +import { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; +import { + applyMixins, + getTableColumns, + getTableLikeName, + haveSameKeys, + orderSelectedFields, + type ValueOrArray, +} from '~/utils.ts'; +import type { + AnySingleStoreSelect, + CreateSingleStoreSelectFromBuilderMode, + GetSingleStoreSetOperators, + LockConfig, + LockStrength, + SelectedFields, + SetOperatorRightSelect, + SingleStoreCreateSetOperatorFn, + SingleStoreJoinFn, + SingleStoreSelectConfig, + SingleStoreSelectDynamic, + SingleStoreSelectHKT, + SingleStoreSelectHKTBase, + SingleStoreSelectPrepare, + SingleStoreSelectWithout, + SingleStoreSetOperatorExcludedMethods, + SingleStoreSetOperatorWithResult, +} from './select.types.ts'; + +export class SingleStoreSelectBuilder< + TSelection extends SelectedFields | undefined, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TBuilderMode extends 'db' | 'qb' = 'db', +> { + static readonly [entityKind]: string = 'SingleStoreSelectBuilder'; + + private fields: TSelection; + private session: SingleStoreSession | undefined; + private dialect: SingleStoreDialect; + private withList: Subquery[] = []; + private distinct: boolean | undefined; + + constructor( + config: { + fields: TSelection; + session: SingleStoreSession | undefined; + dialect: SingleStoreDialect; + withList?: Subquery[]; + distinct?: boolean; + }, + ) { + this.fields = config.fields; + this.session = config.session; + this.dialect = config.dialect; + if (config.withList) { + this.withList = config.withList; + } + this.distinct = config.distinct; + } + + from( // | SingleStoreViewBase + source: TFrom, + ): CreateSingleStoreSelectFromBuilderMode< + TBuilderMode, + GetSelectTableName, + TSelection extends undefined ? GetSelectTableSelection : TSelection, + TSelection extends undefined ? 'single' : 'partial', + TPreparedQueryHKT + > { + const isPartialSelect = !!this.fields; + + let fields: SelectedFields; + if (this.fields) { + fields = this.fields; + } else if (is(source, Subquery)) { + // This is required to use the proxy handler to get the correct field values from the subquery + fields = Object.fromEntries( + Object.keys(source._.selectedFields).map(( + key, + ) => [key, source[key as unknown as keyof typeof source] as unknown as SelectedFields[string]]), + ); + /* } else if (is(source, SingleStoreViewBase)) { + fields = source[ViewBaseConfig].selectedFields as SelectedFields; */ + } else if (is(source, SQL)) { + fields = {}; + } else { + fields = getTableColumns(source); + } + + return new SingleStoreSelectBase( + { + table: source, + fields, + isPartialSelect, + session: this.session, + dialect: this.dialect, + withList: this.withList, + distinct: this.distinct, + }, + ) as any; + } +} + +export abstract class SingleStoreSelectQueryBuilderBase< + THKT extends SingleStoreSelectHKTBase, + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends TypedQueryBuilder { + static override readonly [entityKind]: string = 'SingleStoreSelectQueryBuilder'; + + override readonly _: { + readonly hkt: THKT; + readonly tableName: TTableName; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; + }; + + protected config: SingleStoreSelectConfig; + protected joinsNotNullableMap: Record; + private tableName: string | undefined; + private isPartialSelect: boolean; + /** @internal */ + readonly session: SingleStoreSession | undefined; + protected dialect: SingleStoreDialect; + + constructor( + { table, fields, isPartialSelect, session, dialect, withList, distinct }: { + table: SingleStoreSelectConfig['table']; + fields: SingleStoreSelectConfig['fields']; + isPartialSelect: boolean; + session: SingleStoreSession | undefined; + dialect: SingleStoreDialect; + withList: Subquery[]; + distinct: boolean | undefined; + }, + ) { + super(); + this.config = { + withList, + table, + fields: { ...fields }, + distinct, + setOperators: [], + }; + this.isPartialSelect = isPartialSelect; + this.session = session; + this.dialect = dialect; + this._ = { + selectedFields: fields as TSelectedFields, + } as this['_']; + this.tableName = getTableLikeName(table); + this.joinsNotNullableMap = typeof this.tableName === 'string' ? { [this.tableName]: true } : {}; + } + + private createJoin( + joinType: TJoinType, + ): SingleStoreJoinFn { + return ( + table: SingleStoreTable | Subquery | SQL, // | SingleStoreViewBase + on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, + ) => { + const baseTableName = this.tableName; + const tableName = getTableLikeName(table); + + if (typeof tableName === 'string' && this.config.joins?.some((join) => join.alias === tableName)) { + throw new Error(`Alias "${tableName}" is already used in this query`); + } + + if (!this.isPartialSelect) { + // If this is the first join and this is not a partial select and we're not selecting from raw SQL, "move" the fields from the main table to the nested object + if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === 'string') { + this.config.fields = { + [baseTableName]: this.config.fields, + }; + } + if (typeof tableName === 'string' && !is(table, SQL)) { + const selection = is(table, Subquery) + ? table._.selectedFields + /* : is(table, View) + ? table[ViewBaseConfig].selectedFields */ + : table[Table.Symbol.Columns]; + this.config.fields[tableName] = selection; + } + } + + if (typeof on === 'function') { + on = on( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + + if (!this.config.joins) { + this.config.joins = []; + } + + this.config.joins.push({ on, table, joinType, alias: tableName }); + + if (typeof tableName === 'string') { + switch (joinType) { + case 'left': { + this.joinsNotNullableMap[tableName] = false; + break; + } + case 'right': { + this.joinsNotNullableMap = Object.fromEntries( + Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]), + ); + this.joinsNotNullableMap[tableName] = true; + break; + } + case 'inner': { + this.joinsNotNullableMap[tableName] = true; + break; + } + case 'full': { + this.joinsNotNullableMap = Object.fromEntries( + Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]), + ); + this.joinsNotNullableMap[tableName] = false; + break; + } + } + } + + return this as any; + }; + } + + /** + * Executes a `left join` operation by adding another table to the current query. + * + * Calling this method associates each row of the table with the corresponding row from the joined table, if a match is found. If no matching row exists, it sets all columns of the joined table to null. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#left-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User; pets: Pet | null }[] = await db.select() + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + leftJoin = this.createJoin('left'); + + /** + * Executes a `right join` operation by adding another table to the current query. + * + * Calling this method associates each row of the joined table with the corresponding row from the main table, if a match is found. If no matching row exists, it sets all columns of the main table to null. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#right-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User | null; pets: Pet }[] = await db.select() + * .from(users) + * .rightJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number | null; petId: number }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .rightJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + rightJoin = this.createJoin('right'); + + /** + * Executes an `inner join` operation, creating a new table by combining rows from two tables that have matching values. + * + * Calling this method retrieves rows that have corresponding entries in both joined tables. Rows without matching entries in either table are excluded, resulting in a table that includes only matching pairs. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#inner-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User; pets: Pet }[] = await db.select() + * .from(users) + * .innerJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number; petId: number }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .innerJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + innerJoin = this.createJoin('inner'); + + /** + * Executes a `full join` operation by combining rows from two tables into a new table. + * + * Calling this method retrieves all rows from both main and joined tables, merging rows with matching values and filling in `null` for non-matching columns. + * + * See docs: {@link https://orm.drizzle.team/docs/joins#full-join} + * + * @param table the table to join. + * @param on the `on` clause. + * + * @example + * + * ```ts + * // Select all users and their pets + * const usersWithPets: { user: User | null; pets: Pet | null }[] = await db.select() + * .from(users) + * .fullJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId + * const usersIdsAndPetIds: { userId: number | null; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .fullJoin(pets, eq(users.id, pets.ownerId)) + * ``` + */ + fullJoin = this.createJoin('full'); + + private createSetOperator( + type: SetOperator, + isAll: boolean, + ): >( + rightSelection: + | ((setOperators: GetSingleStoreSetOperators) => SetOperatorRightSelect) + | SetOperatorRightSelect, + ) => SingleStoreSelectWithout< + this, + TDynamic, + SingleStoreSetOperatorExcludedMethods, + true + > { + return (rightSelection) => { + const rightSelect = (typeof rightSelection === 'function' + ? rightSelection(getSingleStoreSetOperators()) + : rightSelection) as TypedQueryBuilder< + any, + TResult + >; + + if (!haveSameKeys(this.getSelectedFields(), rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + + this.config.setOperators.push({ type, isAll, rightSelect }); + return this as any; + }; + } + + /** + * Adds `union` set operator to the query. + * + * Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union} + * + * @example + * + * ```ts + * // Select all unique names from customers and users tables + * await db.select({ name: users.name }) + * .from(users) + * .union( + * db.select({ name: customers.name }).from(customers) + * ); + * // or + * import { union } from 'drizzle-orm/singlestore-core' + * + * await union( + * db.select({ name: users.name }).from(users), + * db.select({ name: customers.name }).from(customers) + * ); + * ``` + */ + union = this.createSetOperator('union', false); + + /** + * Adds `union all` set operator to the query. + * + * Calling this method will combine the result-set of the `select` statements and keep all duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union-all} + * + * @example + * + * ```ts + * // Select all transaction ids from both online and in-store sales + * await db.select({ transaction: onlineSales.transactionId }) + * .from(onlineSales) + * .unionAll( + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * // or + * import { unionAll } from 'drizzle-orm/singlestore-core' + * + * await unionAll( + * db.select({ transaction: onlineSales.transactionId }).from(onlineSales), + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * ``` + */ + unionAll = this.createSetOperator('union', true); + + /** + * Adds `intersect` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets and eliminate duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect} + * + * @example + * + * ```ts + * // Select course names that are offered in both departments A and B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .intersect( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * import { intersect } from 'drizzle-orm/singlestore-core' + * + * await intersect( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ + intersect = this.createSetOperator('intersect', false); + + /** + * Adds `except` set operator to the query. + * + * Calling this method will retrieve all unique rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except} + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .except( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * import { except } from 'drizzle-orm/singlestore-core' + * + * await except( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ + except = this.createSetOperator('except', false); + + /** + * Adds `minus` set operator to the query. + * + * This is an alias of `except` supported by SingleStore. + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .minus( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * import { minus } from 'drizzle-orm/singlestore-core' + * + * await minus( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ + minus = this.createSetOperator('except', false); + + /** @internal */ + addSetOperators(setOperators: SingleStoreSelectConfig['setOperators']): SingleStoreSelectWithout< + this, + TDynamic, + SingleStoreSetOperatorExcludedMethods, + true + > { + this.config.setOperators.push(...setOperators); + return this as any; + } + + /** + * Adds a `where` clause to the query. + * + * Calling this method will select only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/select#filtering} + * + * @param where the `where` clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be selected. + * + * ```ts + * // Select all cars with green color + * await db.select().from(cars).where(eq(cars.color, 'green')); + * // or + * await db.select().from(cars).where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Select all BMW cars with a green color + * await db.select().from(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Select all cars with the green or blue color + * await db.select().from(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where( + where: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): SingleStoreSelectWithout { + if (typeof where === 'function') { + where = where( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + this.config.where = where; + return this as any; + } + + /** + * Adds a `having` clause to the query. + * + * Calling this method will select only those rows that fulfill a specified condition. It is typically used with aggregate functions to filter the aggregated data based on a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/select#aggregations} + * + * @param having the `having` clause. + * + * @example + * + * ```ts + * // Select all brands with more than one car + * await db.select({ + * brand: cars.brand, + * count: sql`cast(count(${cars.id}) as int)`, + * }) + * .from(cars) + * .groupBy(cars.brand) + * .having(({ count }) => gt(count, 1)); + * ``` + */ + having( + having: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): SingleStoreSelectWithout { + if (typeof having === 'function') { + having = having( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }), + ) as TSelection, + ); + } + this.config.having = having; + return this as any; + } + + /** + * Adds a `group by` clause to the query. + * + * Calling this method will group rows that have the same values into summary rows, often used for aggregation purposes. + * + * See docs: {@link https://orm.drizzle.team/docs/select#aggregations} + * + * @example + * + * ```ts + * // Group and count people by their last names + * await db.select({ + * lastName: people.lastName, + * count: sql`cast(count(*) as int)` + * }) + * .from(people) + * .groupBy(people.lastName); + * ``` + */ + groupBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): SingleStoreSelectWithout; + groupBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreSelectWithout; + groupBy( + ...columns: + | [(aliases: this['_']['selection']) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreSelectWithout { + if (typeof columns[0] === 'function') { + const groupBy = columns[0]( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as TSelection, + ); + this.config.groupBy = Array.isArray(groupBy) ? groupBy : [groupBy]; + } else { + this.config.groupBy = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + } + return this as any; + } + + /** + * Adds an `order by` clause to the query. + * + * Calling this method will sort the result-set in ascending or descending order. By default, the sort order is ascending. + * + * See docs: {@link https://orm.drizzle.team/docs/select#order-by} + * + * @example + * + * ``` + * // Select cars ordered by year + * await db.select().from(cars).orderBy(cars.year); + * ``` + * + * You can specify whether results are in ascending or descending order with the `asc()` and `desc()` operators. + * + * ```ts + * // Select cars ordered by year in descending order + * await db.select().from(cars).orderBy(desc(cars.year)); + * + * // Select cars ordered by year and price + * await db.select().from(cars).orderBy(asc(cars.year), desc(cars.price)); + * ``` + */ + orderBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): SingleStoreSelectWithout; + orderBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreSelectWithout; + orderBy( + ...columns: + | [(aliases: this['_']['selection']) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreSelectWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.fields, + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as TSelection, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } + } else { + const orderByArray = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } + } + return this as any; + } + + /** + * Adds a `limit` clause to the query. + * + * Calling this method will set the maximum number of rows that will be returned by this query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset} + * + * @param limit the `limit` clause. + * + * @example + * + * ```ts + * // Get the first 10 people from this query. + * await db.select().from(people).limit(10); + * ``` + */ + limit(limit: number): SingleStoreSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.limit = limit; + } else { + this.config.limit = limit; + } + return this as any; + } + + /** + * Adds an `offset` clause to the query. + * + * Calling this method will skip a number of rows when returning results from this query. + * + * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset} + * + * @param offset the `offset` clause. + * + * @example + * + * ```ts + * // Get the 10th-20th people from this query. + * await db.select().from(people).offset(10).limit(10); + * ``` + */ + offset(offset: number): SingleStoreSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.offset = offset; + } else { + this.config.offset = offset; + } + return this as any; + } + + /** + * Adds a `for` clause to the query. + * + * Calling this method will specify a lock strength for this query that controls how strictly it acquires exclusive access to the rows being queried. + * + * @param strength the lock strength. + * @param config the lock configuration. + */ + for(strength: LockStrength, config: LockConfig = {}): SingleStoreSelectWithout { + this.config.lockingClause = { strength, config }; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildSelectQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + as( + alias: TAlias, + ): SubqueryWithSelection { + return new Proxy( + new Subquery(this.getSQL(), this.config.fields, alias), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as SubqueryWithSelection; + } + + /** @internal */ + override getSelectedFields(): this['_']['selectedFields'] { + return new Proxy( + this.config.fields, + new SelectionProxyHandler({ alias: this.tableName, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as this['_']['selectedFields']; + } + + $dynamic(): SingleStoreSelectDynamic { + return this as any; + } +} + +export interface SingleStoreSelectBase< + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends + SingleStoreSelectQueryBuilderBase< + SingleStoreSelectHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + QueryPromise +{} + +export class SingleStoreSelectBase< + TTableName extends string | undefined, + TSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, +> extends SingleStoreSelectQueryBuilderBase< + SingleStoreSelectHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields +> { + static override readonly [entityKind]: string = 'SingleStoreSelect'; + + prepare(): SingleStoreSelectPrepare { + if (!this.session) { + throw new Error('Cannot execute a query on a query builder. Please use a database instance instead.'); + } + const fieldsList = orderSelectedFields(this.config.fields); + const query = this.session.prepareQuery< + SingleStorePreparedQueryConfig & { execute: SelectResult[] }, + TPreparedQueryHKT + >(this.dialect.sqlToQuery(this.getSQL()), fieldsList); + query.joinsNotNullableMap = this.joinsNotNullableMap; + return query as SingleStoreSelectPrepare; + } + + execute = ((placeholderValues) => { + return this.prepare().execute(placeholderValues); + }) as ReturnType['execute']; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); +} + +applyMixins(SingleStoreSelectBase, [QueryPromise]); + +function createSetOperator(type: SetOperator, isAll: boolean): SingleStoreCreateSetOperatorFn { + return (leftSelect, rightSelect, ...restSelects) => { + const setOperators = [rightSelect, ...restSelects].map((select) => ({ + type, + isAll, + rightSelect: select as AnySingleStoreSelect, + })); + + for (const setOperator of setOperators) { + if (!haveSameKeys((leftSelect as any).getSelectedFields(), setOperator.rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + } + + return (leftSelect as AnySingleStoreSelect).addSetOperators(setOperators) as any; + }; +} + +const getSingleStoreSetOperators = () => ({ + union, + unionAll, + intersect, + except, + minus, +}); + +/** + * Adds `union` set operator to the query. + * + * Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union} + * + * @example + * + * ```ts + * // Select all unique names from customers and users tables + * import { union } from 'drizzle-orm/singlestore-core' + * + * await union( + * db.select({ name: users.name }).from(users), + * db.select({ name: customers.name }).from(customers) + * ); + * // or + * await db.select({ name: users.name }) + * .from(users) + * .union( + * db.select({ name: customers.name }).from(customers) + * ); + * ``` + */ +export const union = createSetOperator('union', false); + +/** + * Adds `union all` set operator to the query. + * + * Calling this method will combine the result-set of the `select` statements and keep all duplicate rows that appear across them. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#union-all} + * + * @example + * + * ```ts + * // Select all transaction ids from both online and in-store sales + * import { unionAll } from 'drizzle-orm/singlestore-core' + * + * await unionAll( + * db.select({ transaction: onlineSales.transactionId }).from(onlineSales), + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * // or + * await db.select({ transaction: onlineSales.transactionId }) + * .from(onlineSales) + * .unionAll( + * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales) + * ); + * ``` + */ +export const unionAll = createSetOperator('union', true); + +/** + * Adds `intersect` set operator to the query. + * + * Calling this method will retain only the rows that are present in both result sets and eliminate duplicates. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect} + * + * @example + * + * ```ts + * // Select course names that are offered in both departments A and B + * import { intersect } from 'drizzle-orm/singlestore-core' + * + * await intersect( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .intersect( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ +export const intersect = createSetOperator('intersect', false); + +/** + * Adds `except` set operator to the query. + * + * Calling this method will retrieve all unique rows from the left query, except for the rows that are present in the result set of the right query. + * + * See docs: {@link https://orm.drizzle.team/docs/set-operations#except} + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * import { except } from 'drizzle-orm/singlestore-core' + * + * await except( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .except( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ +export const except = createSetOperator('except', false); + +/** + * Adds `minus` set operator to the query. + * + * This is an alias of `except` supported by SingleStore. + * + * @example + * + * ```ts + * // Select all courses offered in department A but not in department B + * import { minus } from 'drizzle-orm/singlestore-core' + * + * await minus( + * db.select({ courseName: depA.courseName }).from(depA), + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * // or + * await db.select({ courseName: depA.courseName }) + * .from(depA) + * .minus( + * db.select({ courseName: depB.courseName }).from(depB) + * ); + * ``` + */ +export const minus = createSetOperator('except', true); diff --git a/drizzle-orm/src/singlestore-core/query-builders/select.types.ts b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts new file mode 100644 index 000000000..75bc8d783 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/select.types.ts @@ -0,0 +1,457 @@ +import type { + SelectedFields as SelectedFieldsBase, + SelectedFieldsFlat as SelectedFieldsFlatBase, + SelectedFieldsOrdered as SelectedFieldsOrderedBase, +} from '~/operations.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { + AppendToNullabilityMap, + AppendToResult, + BuildSubquerySelection, + GetSelectTableName, + JoinNullability, + JoinType, + MapColumnsToTableAlias, + SelectMode, + SelectResult, + SetOperator, +} from '~/query-builders/select.types.ts'; +import type { SingleStoreColumn } from '~/singlestore-core/columns/index.ts'; +import type { SingleStoreTable, SingleStoreTableWithColumns } from '~/singlestore-core/table.ts'; +import type { ColumnsSelection, Placeholder, SQL, View } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import type { Table, UpdateTableConfig } from '~/table.ts'; +import type { Assume, ValidateShape } from '~/utils.ts'; +import type { PreparedQueryHKTBase, PreparedQueryKind, SingleStorePreparedQueryConfig } from '../session.ts'; +/* import type { SingleStoreViewBase } from '../view-base.ts'; */ +/* import type { SingleStoreViewWithSelection } from '../view.ts'; */ +import type { SingleStoreSelectBase, SingleStoreSelectQueryBuilderBase } from './select.ts'; + +export interface SingleStoreSelectJoinConfig { + on: SQL | undefined; + table: SingleStoreTable | Subquery | SQL; // SingleStoreViewBase | + alias: string | undefined; + joinType: JoinType; + lateral?: boolean; +} + +export type BuildAliasTable = TTable extends Table + ? SingleStoreTableWithColumns< + UpdateTableConfig; + }> + > + /* : TTable extends View ? SingleStoreViewWithSelection< + TAlias, + TTable['_']['existing'], + MapColumnsToTableAlias + > */ + : never; + +export interface SingleStoreSelectConfig { + withList?: Subquery[]; + fields: Record; + fieldsFlat?: SelectedFieldsOrdered; + where?: SQL; + having?: SQL; + table: SingleStoreTable | Subquery | SQL; // | SingleStoreViewBase + limit?: number | Placeholder; + offset?: number | Placeholder; + joins?: SingleStoreSelectJoinConfig[]; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + groupBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + lockingClause?: { + strength: LockStrength; + config: LockConfig; + }; + distinct?: boolean; + setOperators: { + rightSelect: TypedQueryBuilder; + type: SetOperator; + isAll: boolean; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + limit?: number | Placeholder; + offset?: number | Placeholder; + }[]; +} + +export type SingleStoreJoin< + T extends AnySingleStoreSelectQueryBuilder, + TDynamic extends boolean, + TJoinType extends JoinType, + TJoinedTable extends SingleStoreTable | Subquery | SQL, // | SingleStoreViewBase + TJoinedName extends GetSelectTableName = GetSelectTableName, +> = T extends any ? SingleStoreSelectWithout< + SingleStoreSelectKind< + T['_']['hkt'], + T['_']['tableName'], + AppendToResult< + T['_']['tableName'], + T['_']['selection'], + TJoinedName, + TJoinedTable extends SingleStoreTable ? TJoinedTable['_']['columns'] + : TJoinedTable extends Subquery ? Assume + : never, + T['_']['selectMode'] + >, + T['_']['selectMode'] extends 'partial' ? T['_']['selectMode'] : 'multiple', + T['_']['preparedQueryHKT'], + AppendToNullabilityMap, + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + T['_']['excludedMethods'] + > + : never; + +export type SingleStoreJoinFn< + T extends AnySingleStoreSelectQueryBuilder, + TDynamic extends boolean, + TJoinType extends JoinType, +> = < + TJoinedTable extends SingleStoreTable | Subquery | SQL, // | SingleStoreViewBase + TJoinedName extends GetSelectTableName = GetSelectTableName, +>( + table: TJoinedTable, + on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, +) => SingleStoreJoin; + +export type SelectedFieldsFlat = SelectedFieldsFlatBase; + +export type SelectedFields = SelectedFieldsBase; + +export type SelectedFieldsOrdered = SelectedFieldsOrderedBase; + +export type LockStrength = 'update' | 'share'; + +export type LockConfig = { + noWait: true; + skipLocked?: undefined; +} | { + noWait?: undefined; + skipLocked: true; +} | { + noWait?: undefined; + skipLocked?: undefined; +}; + +export interface SingleStoreSelectHKTBase { + tableName: string | undefined; + selection: unknown; + selectMode: SelectMode; + preparedQueryHKT: unknown; + nullabilityMap: unknown; + dynamic: boolean; + excludedMethods: string; + result: unknown; + selectedFields: unknown; + _type: unknown; +} + +export type SingleStoreSelectKind< + T extends SingleStoreSelectHKTBase, + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TNullabilityMap extends Record, + TDynamic extends boolean, + TExcludedMethods extends string, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, +> = (T & { + tableName: TTableName; + selection: TSelection; + selectMode: TSelectMode; + preparedQueryHKT: TPreparedQueryHKT; + nullabilityMap: TNullabilityMap; + dynamic: TDynamic; + excludedMethods: TExcludedMethods; + result: TResult; + selectedFields: TSelectedFields; +})['_type']; + +export interface SingleStoreSelectQueryBuilderHKT extends SingleStoreSelectHKTBase { + _type: SingleStoreSelectQueryBuilderBase< + SingleStoreSelectQueryBuilderHKT, + this['tableName'], + Assume, + this['selectMode'], + Assume, + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume + >; +} + +export interface SingleStoreSelectHKT extends SingleStoreSelectHKTBase { + _type: SingleStoreSelectBase< + this['tableName'], + Assume, + this['selectMode'], + Assume, + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume + >; +} + +export type SingleStoreSetOperatorExcludedMethods = + | 'where' + | 'having' + | 'groupBy' + | 'session' + | 'leftJoin' + | 'rightJoin' + | 'innerJoin' + | 'fullJoin' + | 'for'; + +export type SingleStoreSelectWithout< + T extends AnySingleStoreSelectQueryBuilder, + TDynamic extends boolean, + K extends keyof T & string, + TResetExcluded extends boolean = false, +> = TDynamic extends true ? T : Omit< + SingleStoreSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['preparedQueryHKT'], + T['_']['nullabilityMap'], + TDynamic, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K, + T['_']['result'], + T['_']['selectedFields'] + >, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K +>; + +export type SingleStoreSelectPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: T['_']['result']; + iterator: T['_']['result'][number]; + }, + true +>; + +export type SingleStoreSelectDynamic = SingleStoreSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['preparedQueryHKT'], + T['_']['nullabilityMap'], + true, + never, + T['_']['result'], + T['_']['selectedFields'] +>; + +export type CreateSingleStoreSelectFromBuilderMode< + TBuilderMode extends 'db' | 'qb', + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> = TBuilderMode extends 'db' ? SingleStoreSelectBase + : SingleStoreSelectQueryBuilderBase< + SingleStoreSelectQueryBuilderHKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT + >; + +export type SingleStoreSelectQueryBuilder< + THKT extends SingleStoreSelectHKTBase = SingleStoreSelectQueryBuilderHKT, + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = ColumnsSelection, + TSelectMode extends SelectMode = SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = Record, + TResult extends any[] = unknown[], + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> = SingleStoreSelectQueryBuilderBase< + THKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + true, + never, + TResult, + TSelectedFields +>; + +export type AnySingleStoreSelectQueryBuilder = SingleStoreSelectQueryBuilderBase< + any, + any, + any, + any, + any, + any, + any, + any, + any +>; + +export type AnySingleStoreSetOperatorInterface = SingleStoreSetOperatorInterface< + any, + any, + any, + any, + any, + any, + any, + any, + any +>; + +export interface SingleStoreSetOperatorInterface< + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> { + _: { + readonly hkt: SingleStoreSelectHKT; + readonly tableName: TTableName; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; + }; +} + +export type SingleStoreSetOperatorWithResult = SingleStoreSetOperatorInterface< + any, + any, + any, + any, + any, + any, + any, + TResult, + any +>; + +export type SingleStoreSelect< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TNullabilityMap extends Record = Record, +> = SingleStoreSelectBase; + +export type AnySingleStoreSelect = SingleStoreSelectBase; + +export type SingleStoreSetOperator< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = Record, +> = SingleStoreSelectBase< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + true, + SingleStoreSetOperatorExcludedMethods +>; + +export type SetOperatorRightSelect< + TValue extends SingleStoreSetOperatorWithResult, + TResult extends any[], +> = TValue extends SingleStoreSetOperatorInterface + ? ValidateShape< + TValueResult[number], + TResult[number], + TypedQueryBuilder + > + : TValue; + +export type SetOperatorRestSelect< + TValue extends readonly SingleStoreSetOperatorWithResult[], + TResult extends any[], +> = TValue extends [infer First, ...infer Rest] + ? First extends SingleStoreSetOperatorInterface + ? Rest extends AnySingleStoreSetOperatorInterface[] ? [ + ValidateShape>, + ...SetOperatorRestSelect, + ] + : ValidateShape[]> + : never + : TValue; + +export type SingleStoreCreateSetOperatorFn = < + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TValue extends SingleStoreSetOperatorWithResult, + TRest extends SingleStoreSetOperatorWithResult[], + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +>( + leftSelect: SingleStoreSetOperatorInterface< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + rightSelect: SetOperatorRightSelect, + ...restSelects: SetOperatorRestSelect +) => SingleStoreSelectWithout< + SingleStoreSelectBase< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + false, + SingleStoreSetOperatorExcludedMethods, + true +>; + +export type GetSingleStoreSetOperators = { + union: SingleStoreCreateSetOperatorFn; + intersect: SingleStoreCreateSetOperatorFn; + except: SingleStoreCreateSetOperatorFn; + unionAll: SingleStoreCreateSetOperatorFn; + minus: SingleStoreCreateSetOperatorFn; +}; diff --git a/drizzle-orm/src/singlestore-core/query-builders/update.ts b/drizzle-orm/src/singlestore-core/query-builders/update.ts new file mode 100644 index 000000000..40ca97662 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/query-builders/update.ts @@ -0,0 +1,251 @@ +import type { GetColumnData } from '~/column.ts'; +import { entityKind } from '~/entity.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { + AnySingleStoreQueryResultHKT, + PreparedQueryHKTBase, + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStoreQueryResultHKT, + SingleStoreQueryResultKind, + SingleStoreSession, +} from '~/singlestore-core/session.ts'; +import type { SingleStoreTable } from '~/singlestore-core/table.ts'; +import type { Placeholder, Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { Subquery } from '~/subquery.ts'; +import { Table } from '~/table.ts'; +import { mapUpdateSet, type UpdateSet, type ValueOrArray } from '~/utils.ts'; +import type { SingleStoreColumn } from '../columns/common.ts'; +import type { SelectedFieldsOrdered } from './select.types.ts'; + +export interface SingleStoreUpdateConfig { + where?: SQL | undefined; + limit?: number | Placeholder; + orderBy?: (SingleStoreColumn | SQL | SQL.Aliased)[]; + set: UpdateSet; + table: SingleStoreTable; + returning?: SelectedFieldsOrdered; + withList?: Subquery[]; +} + +export type SingleStoreUpdateSetSource = + & { + [Key in keyof TTable['$inferInsert']]?: + | GetColumnData + | SQL; + } + & {}; + +export class SingleStoreUpdateBuilder< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> { + static readonly [entityKind]: string = 'SingleStoreUpdateBuilder'; + + declare readonly _: { + readonly table: TTable; + }; + + constructor( + private table: TTable, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + private withList?: Subquery[], + ) {} + + set(values: SingleStoreUpdateSetSource): SingleStoreUpdateBase { + return new SingleStoreUpdateBase( + this.table, + mapUpdateSet(this.table, values), + this.session, + this.dialect, + this.withList, + ); + } +} + +export type SingleStoreUpdateWithout< + T extends AnySingleStoreUpdateBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T : Omit< + SingleStoreUpdateBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K +>; + +export type SingleStoreUpdatePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + SingleStorePreparedQueryConfig & { + execute: SingleStoreQueryResultKind; + iterator: never; + }, + true +>; + +export type SingleStoreUpdateDynamic = SingleStoreUpdate< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +export type SingleStoreUpdate< + TTable extends SingleStoreTable = SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT = AnySingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = SingleStoreUpdateBase; + +export type AnySingleStoreUpdateBase = SingleStoreUpdateBase; + +export interface SingleStoreUpdateBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise>, SQLWrapper { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class SingleStoreUpdateBase< + TTable extends SingleStoreTable, + TQueryResult extends SingleStoreQueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TPreparedQueryHKT extends PreparedQueryHKTBase, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise> implements SQLWrapper { + static override readonly [entityKind]: string = 'SingleStoreUpdate'; + + private config: SingleStoreUpdateConfig; + + constructor( + table: TTable, + set: UpdateSet, + private session: SingleStoreSession, + private dialect: SingleStoreDialect, + withList?: Subquery[], + ) { + super(); + this.config = { set, table, withList }; + } + + /** + * Adds a 'where' clause to the query. + * + * Calling this method will update only those rows that fulfill a specified condition. + * + * See docs: {@link https://orm.drizzle.team/docs/update} + * + * @param where the 'where' clause. + * + * @example + * You can use conditional operators and `sql function` to filter the rows to be updated. + * + * ```ts + * // Update all cars with green color + * db.update(cars).set({ color: 'red' }) + * .where(eq(cars.color, 'green')); + * // or + * db.update(cars).set({ color: 'red' }) + * .where(sql`${cars.color} = 'green'`) + * ``` + * + * You can logically combine conditional operators with `and()` and `or()` operators: + * + * ```ts + * // Update all BMW cars with a green color + * db.update(cars).set({ color: 'red' }) + * .where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW'))); + * + * // Update all cars with the green or blue color + * db.update(cars).set({ color: 'red' }) + * .where(or(eq(cars.color, 'green'), eq(cars.color, 'blue'))); + * ``` + */ + where(where: SQL | undefined): SingleStoreUpdateWithout { + this.config.where = where; + return this as any; + } + + orderBy( + builder: (updateTable: TTable) => ValueOrArray, + ): SingleStoreUpdateWithout; + orderBy(...columns: (SingleStoreColumn | SQL | SQL.Aliased)[]): SingleStoreUpdateWithout; + orderBy( + ...columns: + | [(updateTable: TTable) => ValueOrArray] + | (SingleStoreColumn | SQL | SQL.Aliased)[] + ): SingleStoreUpdateWithout { + if (typeof columns[0] === 'function') { + const orderBy = columns[0]( + new Proxy( + this.config.table[Table.Symbol.Columns], + new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), + ) as any, + ); + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + this.config.orderBy = orderByArray; + } else { + const orderByArray = columns as (SingleStoreColumn | SQL | SQL.Aliased)[]; + this.config.orderBy = orderByArray; + } + return this as any; + } + + limit(limit: number | Placeholder): SingleStoreUpdateWithout { + this.config.limit = limit; + return this as any; + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildUpdateQuery(this.config); + } + + toSQL(): Query { + const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); + return rest; + } + + prepare(): SingleStoreUpdatePrepare { + return this.session.prepareQuery( + this.dialect.sqlToQuery(this.getSQL()), + this.config.returning, + ) as SingleStoreUpdatePrepare; + } + + override execute: ReturnType['execute'] = (placeholderValues) => { + return this.prepare().execute(placeholderValues); + }; + + private createIterator = (): ReturnType['iterator'] => { + const self = this; + return async function*(placeholderValues) { + yield* self.prepare().iterator(placeholderValues); + }; + }; + + iterator = this.createIterator(); + + $dynamic(): SingleStoreUpdateDynamic { + return this as any; + } +} diff --git a/drizzle-orm/src/singlestore-core/schema.ts b/drizzle-orm/src/singlestore-core/schema.ts new file mode 100644 index 000000000..ea7a53924 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/schema.ts @@ -0,0 +1,40 @@ +import { entityKind, is } from '~/entity.ts'; +import { type SingleStoreTableFn, singlestoreTableWithSchema } from './table.ts'; +/* import { type singlestoreView, singlestoreViewWithSchema } from './view.ts'; */ + +export class SingleStoreSchema { + static readonly [entityKind]: string = 'SingleStoreSchema'; + + constructor( + public readonly schemaName: TName, + ) {} + + table: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, this.schemaName); + }; + /* + view = ((name, columns) => { + return singlestoreViewWithSchema(name, columns, this.schemaName); + }) as typeof singlestoreView; */ +} + +/** @deprecated - use `instanceof SingleStoreSchema` */ +export function isSingleStoreSchema(obj: unknown): obj is SingleStoreSchema { + return is(obj, SingleStoreSchema); +} + +/** + * Create a SingleStore schema. + * https://docs.singlestore.com/cloud/create-a-database/ + * + * @param name singlestore use schema name + * @returns SingleStore schema + */ +export function singlestoreDatabase(name: TName) { + return new SingleStoreSchema(name); +} + +/** + * @see singlestoreDatabase + */ +export const singlestoreSchema = singlestoreDatabase; diff --git a/drizzle-orm/src/singlestore-core/session.ts b/drizzle-orm/src/singlestore-core/session.ts new file mode 100644 index 000000000..bc31f3d97 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/session.ts @@ -0,0 +1,157 @@ +import { entityKind } from '~/entity.ts'; +import { TransactionRollbackError } from '~/errors.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { type Query, type SQL, sql } from '~/sql/sql.ts'; +import type { Assume, Equal } from '~/utils.ts'; +import { SingleStoreDatabase } from './db.ts'; +import type { SingleStoreDialect } from './dialect.ts'; +import type { SelectedFieldsOrdered } from './query-builders/select.types.ts'; + +export interface SingleStoreQueryResultHKT { + readonly $brand: 'SingleStoreQueryResultHKT'; + readonly row: unknown; + readonly type: unknown; +} + +export interface AnySingleStoreQueryResultHKT extends SingleStoreQueryResultHKT { + readonly type: any; +} + +export type SingleStoreQueryResultKind = (TKind & { + readonly row: TRow; +})['type']; + +export interface SingleStorePreparedQueryConfig { + execute: unknown; + iterator: unknown; +} + +export interface SingleStorePreparedQueryHKT { + readonly $brand: 'SingleStorePreparedQueryHKT'; + readonly config: unknown; + readonly type: unknown; +} + +export type PreparedQueryKind< + TKind extends SingleStorePreparedQueryHKT, + TConfig extends SingleStorePreparedQueryConfig, + TAssume extends boolean = false, +> = Equal extends true + ? Assume<(TKind & { readonly config: TConfig })['type'], SingleStorePreparedQuery> + : (TKind & { readonly config: TConfig })['type']; + +export abstract class SingleStorePreparedQuery { + static readonly [entityKind]: string = 'SingleStorePreparedQuery'; + + /** @internal */ + joinsNotNullableMap?: Record; + + abstract execute(placeholderValues?: Record): Promise; + + abstract iterator(placeholderValues?: Record): AsyncGenerator; +} + +export interface SingleStoreTransactionConfig { + withConsistentSnapshot?: boolean; + accessMode?: 'read only' | 'read write'; + isolationLevel: 'read committed'; // SingleStore only supports read committed isolation level (https://docs.singlestore.com/db/v8.7/introduction/faqs/durability/) +} + +export abstract class SingleStoreSession< + TQueryResult extends SingleStoreQueryResultHKT = SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TFullSchema extends Record = Record, + TSchema extends TablesRelationalConfig = Record, +> { + static readonly [entityKind]: string = 'SingleStoreSession'; + + constructor(protected dialect: SingleStoreDialect) {} + + abstract prepareQuery< + T extends SingleStorePreparedQueryConfig, + TPreparedQueryHKT extends SingleStorePreparedQueryHKT, + >( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind; + + execute(query: SQL): Promise { + return this.prepareQuery( + this.dialect.sqlToQuery(query), + undefined, + ).execute(); + } + + abstract all(query: SQL): Promise; + + async count(sql: SQL): Promise { + const res = await this.execute<[[{ count: string }]]>(sql); + + return Number( + res[0][0]['count'], + ); + } + + abstract transaction( + transaction: (tx: SingleStoreTransaction) => Promise, + config?: SingleStoreTransactionConfig, + ): Promise; + + protected getSetTransactionSQL(config: SingleStoreTransactionConfig): SQL | undefined { + const parts: string[] = []; + + if (config.isolationLevel) { + parts.push(`isolation level ${config.isolationLevel}`); + } + + return parts.length ? sql`set transaction ${sql.raw(parts.join(' '))}` : undefined; + } + + protected getStartTransactionSQL(config: SingleStoreTransactionConfig): SQL | undefined { + const parts: string[] = []; + + if (config.withConsistentSnapshot) { + parts.push('with consistent snapshot'); + } + + if (config.accessMode) { + parts.push(config.accessMode); + } + + return parts.length ? sql`start transaction ${sql.raw(parts.join(' '))}` : undefined; + } +} + +export abstract class SingleStoreTransaction< + TQueryResult extends SingleStoreQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record = Record, + TSchema extends TablesRelationalConfig = Record, +> extends SingleStoreDatabase { + static override readonly [entityKind]: string = 'SingleStoreTransaction'; + + constructor( + dialect: SingleStoreDialect, + session: SingleStoreSession, + protected schema: RelationalSchemaConfig | undefined, + protected readonly nestedIndex: number, + ) { + super(dialect, session, schema); + } + + rollback(): never { + throw new TransactionRollbackError(); + } + + /** Nested transactions (aka savepoints) only work with InnoDB engine. */ + abstract override transaction( + transaction: (tx: SingleStoreTransaction) => Promise, + ): Promise; +} + +export interface PreparedQueryHKTBase extends SingleStorePreparedQueryHKT { + type: SingleStorePreparedQuery>; +} diff --git a/drizzle-orm/src/singlestore-core/subquery.ts b/drizzle-orm/src/singlestore-core/subquery.ts new file mode 100644 index 000000000..a4605c56d --- /dev/null +++ b/drizzle-orm/src/singlestore-core/subquery.ts @@ -0,0 +1,17 @@ +import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import type { Subquery, WithSubquery } from '~/subquery.ts'; + +export type SubqueryWithSelection< + TSelection extends ColumnsSelection, + TAlias extends string, +> = + & Subquery> + & AddAliasToSelection; + +export type WithSubqueryWithSelection< + TSelection extends ColumnsSelection, + TAlias extends string, +> = + & WithSubquery> + & AddAliasToSelection; diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts new file mode 100644 index 000000000..4cc8973ee --- /dev/null +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -0,0 +1,138 @@ +import type { BuildColumns, BuildExtraConfigColumns } from '~/column-builder.ts'; +import { entityKind } from '~/entity.ts'; +import { Table, type TableConfig as TableConfigBase, type UpdateTableConfig } from '~/table.ts'; +import { getSingleStoreColumnBuilders, type SingleStoreColumnBuilders } from './columns/all.ts'; +import type { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreColumnBuilderBase } from './columns/common.ts'; +import type { AnyIndexBuilder } from './indexes.ts'; +import type { PrimaryKeyBuilder } from './primary-keys.ts'; +import type { UniqueConstraintBuilder } from './unique-constraint.ts'; + +export type SingleStoreTableExtraConfig = Record< + string, + | AnyIndexBuilder + | PrimaryKeyBuilder + | UniqueConstraintBuilder +>; + +export type TableConfig = TableConfigBase; + +export class SingleStoreTable extends Table { + static override readonly [entityKind]: string = 'SingleStoreTable'; + + declare protected $columns: T['columns']; + + /** @internal */ + static override readonly Symbol = Object.assign({}, Table.Symbol, {}); + + /** @internal */ + override [Table.Symbol.Columns]!: NonNullable; + + /** @internal */ + override [Table.Symbol.ExtraConfigBuilder]: + | ((self: Record) => SingleStoreTableExtraConfig) + | undefined = undefined; +} + +export type AnySingleStoreTable = {}> = SingleStoreTable< + UpdateTableConfig +>; + +export type SingleStoreTableWithColumns = + & SingleStoreTable + & { + [Key in keyof T['columns']]: T['columns'][Key]; + }; + +export function singlestoreTableWithSchema< + TTableName extends string, + TSchemaName extends string | undefined, + TColumnsMap extends Record, +>( + name: TTableName, + columns: TColumnsMap | ((columnTypes: SingleStoreColumnBuilders) => TColumnsMap), + extraConfig: + | ((self: BuildColumns) => SingleStoreTableExtraConfig) + | undefined, + schema: TSchemaName, + baseName = name, +): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; +}> { + const rawTable = new SingleStoreTable<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>(name, schema, baseName); + + const parsedColumns: TColumnsMap = typeof columns === 'function' ? columns(getSingleStoreColumnBuilders()) : columns; + + const builtColumns = Object.fromEntries( + Object.entries(parsedColumns).map(([name, colBuilderBase]) => { + const colBuilder = colBuilderBase as SingleStoreColumnBuilder; + colBuilder.setName(name); + const column = colBuilder.build(rawTable); + return [name, column]; + }), + ) as unknown as BuildColumns; + + const table = Object.assign(rawTable, builtColumns); + + table[Table.Symbol.Columns] = builtColumns; + table[Table.Symbol.ExtraConfigColumns] = builtColumns as unknown as BuildExtraConfigColumns< + TTableName, + TColumnsMap, + 'singlestore' + >; + + if (extraConfig) { + table[SingleStoreTable.Symbol.ExtraConfigBuilder] = extraConfig as unknown as ( + self: Record, + ) => SingleStoreTableExtraConfig; + } + + return table; +} + +export interface SingleStoreTableFn { + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: TColumnsMap, + extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfig, + ): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: SingleStoreColumnBuilders) => TColumnsMap, + extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfig, + ): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>; +} + +export const singlestoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { + return singlestoreTableWithSchema(name, columns, extraConfig, undefined, name); +}; + +export function singlestoreTableCreator(customizeTableName: (name: string) => string): SingleStoreTableFn { + return (name, columns, extraConfig) => { + return singlestoreTableWithSchema(customizeTableName(name) as typeof name, columns, extraConfig, undefined, name); + }; +} diff --git a/drizzle-orm/src/singlestore-core/unique-constraint.ts b/drizzle-orm/src/singlestore-core/unique-constraint.ts new file mode 100644 index 000000000..511e466dc --- /dev/null +++ b/drizzle-orm/src/singlestore-core/unique-constraint.ts @@ -0,0 +1,65 @@ +import { entityKind } from '~/entity.ts'; +import { TableName } from '~/table.utils.ts'; +import type { SingleStoreColumn } from './columns/index.ts'; +import type { SingleStoreTable } from './table.ts'; + +export function unique(name?: string): UniqueOnConstraintBuilder { + return new UniqueOnConstraintBuilder(name); +} + +export function uniqueKeyName(table: SingleStoreTable, columns: string[]) { + return `${table[TableName]}_${columns.join('_')}_unique`; +} + +export class UniqueConstraintBuilder { + static readonly [entityKind]: string = 'SingleStoreUniqueConstraintBuilder'; + + /** @internal */ + columns: SingleStoreColumn[]; + + constructor( + columns: SingleStoreColumn[], + private name?: string, + ) { + this.columns = columns; + } + + /** @internal */ + build(table: SingleStoreTable): UniqueConstraint { + return new UniqueConstraint(table, this.columns, this.name); + } +} + +export class UniqueOnConstraintBuilder { + static readonly [entityKind]: string = 'SingleStoreUniqueOnConstraintBuilder'; + + /** @internal */ + name?: string; + + constructor( + name?: string, + ) { + this.name = name; + } + + on(...columns: [SingleStoreColumn, ...SingleStoreColumn[]]) { + return new UniqueConstraintBuilder(columns, this.name); + } +} + +export class UniqueConstraint { + static readonly [entityKind]: string = 'SingleStoreUniqueConstraint'; + + readonly columns: SingleStoreColumn[]; + readonly name?: string; + readonly nullsNotDistinct: boolean = false; + + constructor(readonly table: SingleStoreTable, columns: SingleStoreColumn[], name?: string) { + this.columns = columns; + this.name = name ?? uniqueKeyName(this.table, this.columns.map((column) => column.name)); + } + + getName() { + return this.name; + } +} diff --git a/drizzle-orm/src/singlestore-core/utils.ts b/drizzle-orm/src/singlestore-core/utils.ts new file mode 100644 index 000000000..634b4e261 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/utils.ts @@ -0,0 +1,55 @@ +import { is } from '~/entity.ts'; +import { Table } from '~/table.ts'; +import type { Index } from './indexes.ts'; +import { IndexBuilder } from './indexes.ts'; +import type { PrimaryKey } from './primary-keys.ts'; +import { PrimaryKeyBuilder } from './primary-keys.ts'; +import { SingleStoreTable } from './table.ts'; +import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; +/* import { SingleStoreViewConfig } from './view-common.ts'; +import type { SingleStoreView } from './view.ts'; */ + +export function getTableConfig(table: SingleStoreTable) { + const columns = Object.values(table[SingleStoreTable.Symbol.Columns]); + const indexes: Index[] = []; + const primaryKeys: PrimaryKey[] = []; + const uniqueConstraints: UniqueConstraint[] = []; + const name = table[Table.Symbol.Name]; + const schema = table[Table.Symbol.Schema]; + const baseName = table[Table.Symbol.BaseName]; + + const extraConfigBuilder = table[SingleStoreTable.Symbol.ExtraConfigBuilder]; + + if (extraConfigBuilder !== undefined) { + const extraConfig = extraConfigBuilder(table[SingleStoreTable.Symbol.Columns]); + for (const builder of Object.values(extraConfig)) { + if (is(builder, IndexBuilder)) { + indexes.push(builder.build(table)); + } else if (is(builder, UniqueConstraintBuilder)) { + uniqueConstraints.push(builder.build(table)); + } else if (is(builder, PrimaryKeyBuilder)) { + primaryKeys.push(builder.build(table)); + } + } + } + + return { + columns, + indexes, + primaryKeys, + uniqueConstraints, + name, + schema, + baseName, + }; +} + +/* export function getViewConfig< + TName extends string = string, + TExisting extends boolean = boolean, +>(view: SingleStoreView) { + return { + ...view[ViewBaseConfig], + ...view[SingleStoreViewConfig], + }; +} */ diff --git a/drizzle-orm/src/singlestore-core/view-base.ts b/drizzle-orm/src/singlestore-core/view-base.ts new file mode 100644 index 000000000..1ad8d62d5 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view-base.ts @@ -0,0 +1,15 @@ +import { entityKind } from '~/entity.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import { View } from '~/sql/sql.ts'; + +export abstract class SingleStoreViewBase< + TName extends string = string, + TExisting extends boolean = boolean, + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> extends View { + static override readonly [entityKind]: string = 'SingleStoreViewBase'; + + declare readonly _: View['_'] & { + readonly viewBrand: 'SingleStoreViewBase'; + }; +} diff --git a/drizzle-orm/src/singlestore-core/view-common.ts b/drizzle-orm/src/singlestore-core/view-common.ts new file mode 100644 index 000000000..d29c3d5ad --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view-common.ts @@ -0,0 +1 @@ +export const SingleStoreViewConfig = Symbol.for('drizzle:SingleStoreViewConfig'); diff --git a/drizzle-orm/src/singlestore-core/view.ts b/drizzle-orm/src/singlestore-core/view.ts new file mode 100644 index 000000000..58f111428 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/view.ts @@ -0,0 +1,209 @@ +import type { BuildColumns } from '~/column-builder.ts'; +import { entityKind } from '~/entity.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; +import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { ColumnsSelection, SQL } from '~/sql/sql.ts'; +import { getTableColumns } from '~/utils.ts'; +import type { SingleStoreColumn, SingleStoreColumnBuilderBase } from './columns/index.ts'; +import { QueryBuilder } from './query-builders/query-builder.ts'; +import type { SelectedFields } from './query-builders/select.types.ts'; +import { singlestoreTable } from './table.ts'; +import { SingleStoreViewBase } from './view-base.ts'; +import { SingleStoreViewConfig } from './view-common.ts'; + +export interface ViewBuilderConfig { + algorithm?: 'undefined' | 'merge' | 'temptable'; + definer?: string; + sqlSecurity?: 'definer' | 'invoker'; + withCheckOption?: 'cascaded' | 'local'; +} + +export class ViewBuilderCore { + static readonly [entityKind]: string = 'SingleStoreViewBuilder'; + + declare readonly _: { + readonly name: TConfig['name']; + readonly columns: TConfig['columns']; + }; + + constructor( + protected name: TConfig['name'], + protected schema: string | undefined, + ) {} + + protected config: ViewBuilderConfig = {}; + + algorithm( + algorithm: Exclude, + ): this { + this.config.algorithm = algorithm; + return this; + } + + definer( + definer: Exclude, + ): this { + this.config.definer = definer; + return this; + } + + sqlSecurity( + sqlSecurity: Exclude, + ): this { + this.config.sqlSecurity = sqlSecurity; + return this; + } + + withCheckOption( + withCheckOption?: Exclude, + ): this { + this.config.withCheckOption = withCheckOption ?? 'cascaded'; + return this; + } +} + +export class ViewBuilder extends ViewBuilderCore<{ name: TName }> { + static override readonly [entityKind]: string = 'SingleStoreViewBuilder'; + + as( + qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), + ): SingleStoreViewWithSelection> { + if (typeof qb === 'function') { + qb = qb(new QueryBuilder()); + } + const selectionProxy = new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }); + const aliasedSelection = new Proxy(qb.getSelectedFields(), selectionProxy); + return new Proxy( + new SingleStoreView({ + singlestoreConfig: this.config, + config: { + name: this.name, + schema: this.schema, + selectedFields: aliasedSelection, + query: qb.getSQL().inlineParams(), + }, + }), + selectionProxy as any, + ) as SingleStoreViewWithSelection>; + } +} + +export class ManualViewBuilder< + TName extends string = string, + TColumns extends Record = Record, +> extends ViewBuilderCore<{ name: TName; columns: TColumns }> { + static override readonly [entityKind]: string = 'SingleStoreManualViewBuilder'; + + private columns: Record; + + constructor( + name: TName, + columns: TColumns, + schema: string | undefined, + ) { + super(name, schema); + this.columns = getTableColumns(singlestoreTable(name, columns)) as BuildColumns; + } + + existing(): SingleStoreViewWithSelection> { + return new Proxy( + new SingleStoreView({ + singlestoreConfig: undefined, + config: { + name: this.name, + schema: this.schema, + selectedFields: this.columns, + query: undefined, + }, + }), + new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }), + ) as SingleStoreViewWithSelection>; + } + + as(query: SQL): SingleStoreViewWithSelection> { + return new Proxy( + new SingleStoreView({ + singlestoreConfig: this.config, + config: { + name: this.name, + schema: this.schema, + selectedFields: this.columns, + query: query.inlineParams(), + }, + }), + new SelectionProxyHandler({ + alias: this.name, + sqlBehavior: 'error', + sqlAliasedBehavior: 'alias', + replaceOriginalName: true, + }), + ) as SingleStoreViewWithSelection>; + } +} + +export class SingleStoreView< + TName extends string = string, + TExisting extends boolean = boolean, + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> extends SingleStoreViewBase { + static override readonly [entityKind]: string = 'SingleStoreView'; + + declare protected $SingleStoreViewBrand: 'SingleStoreView'; + + [SingleStoreViewConfig]: ViewBuilderConfig | undefined; + + constructor({ singlestoreConfig, config }: { + singlestoreConfig: ViewBuilderConfig | undefined; + config: { + name: TName; + schema: string | undefined; + selectedFields: SelectedFields; + query: SQL | undefined; + }; + }) { + super(config); + this[SingleStoreViewConfig] = singlestoreConfig; + } +} + +export type SingleStoreViewWithSelection< + TName extends string, + TExisting extends boolean, + TSelectedFields extends ColumnsSelection, +> = SingleStoreView & TSelectedFields; + +// TODO: needs to be implemented differently compared to MySQL. +// /** @internal */ +// export function singlestoreViewWithSchema( +// name: string, +// selection: Record | undefined, +// schema: string | undefined, +// ): ViewBuilder | ManualViewBuilder { +// if (selection) { +// return new ManualViewBuilder(name, selection, schema); +// } +// return new ViewBuilder(name, schema); +// } + +// export function singlestoreView(name: TName): ViewBuilder; +// export function singlestoreView>( +// name: TName, +// columns: TColumns, +// ): ManualViewBuilder; +// export function singlestoreView( +// name: string, +// selection?: Record, +// ): ViewBuilder | ManualViewBuilder { +// return singlestoreViewWithSchema(name, selection, undefined); +// } diff --git a/drizzle-orm/src/singlestore-proxy/driver.ts b/drizzle-orm/src/singlestore-proxy/driver.ts new file mode 100644 index 000000000..ea24ae2d8 --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/driver.ts @@ -0,0 +1,59 @@ +import { entityKind } from '~/entity.ts'; +import { DefaultLogger } from '~/logger.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type RelationalSchemaConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { DrizzleConfig } from '~/utils.ts'; +import { + type SingleStoreRemotePreparedQueryHKT, + type SingleStoreRemoteQueryResultHKT, + SingleStoreRemoteSession, +} from './session.ts'; + +export class SingleStoreRemoteDatabase< + TSchema extends Record = Record, +> extends SingleStoreDatabase { + static override readonly [entityKind]: string = 'SingleStoreRemoteDatabase'; +} + +export type RemoteCallback = ( + sql: string, + params: any[], + method: 'all' | 'execute', +) => Promise<{ rows: any[]; insertId?: number; affectedRows?: number }>; + +export function drizzle = Record>( + callback: RemoteCallback, + config: DrizzleConfig = {}, +): SingleStoreRemoteDatabase { + const dialect = new SingleStoreDialect({ casing: config.casing }); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const session = new SingleStoreRemoteSession(callback, dialect, schema, { logger }); + return new SingleStoreRemoteDatabase(dialect, session, schema as any) as SingleStoreRemoteDatabase< + TSchema + >; +} diff --git a/drizzle-orm/src/singlestore-proxy/index.ts b/drizzle-orm/src/singlestore-proxy/index.ts new file mode 100644 index 000000000..b1b6a52e7 --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/singlestore-proxy/migrator.ts b/drizzle-orm/src/singlestore-proxy/migrator.ts new file mode 100644 index 000000000..2ed0172fb --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/migrator.ts @@ -0,0 +1,52 @@ +import type { MigrationConfig } from '~/migrator.ts'; +import { readMigrationFiles } from '~/migrator.ts'; +import { sql } from '~/sql/sql.ts'; +import type { SingleStoreRemoteDatabase } from './driver.ts'; + +export type ProxyMigrator = (migrationQueries: string[]) => Promise; + +export async function migrate>( + db: SingleStoreRemoteDatabase, + callback: ProxyMigrator, + config: MigrationConfig, +) { + const migrations = readMigrationFiles(config); + + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; + const migrationTableCreate = sql` + create table if not exists ${sql.identifier(migrationsTable)} ( + id serial primary key, + hash text not null, + created_at bigint + ) + `; + await db.execute(migrationTableCreate); + + const dbMigrations = await db.select({ + id: sql.raw('id'), + hash: sql.raw('hash'), + created_at: sql.raw('created_at'), + }).from(sql.identifier(migrationsTable).getSQL()).orderBy( + sql.raw('created_at desc'), + ).limit(1); + + const lastDbMigration = dbMigrations[0]; + + const queriesToRun: string[] = []; + + for (const migration of migrations) { + if ( + !lastDbMigration + || Number(lastDbMigration.created_at) < migration.folderMillis + ) { + queriesToRun.push( + ...migration.sql, + `insert into ${ + sql.identifier(migrationsTable).value + } (\`hash\`, \`created_at\`) values('${migration.hash}', '${migration.folderMillis}')`, + ); + } + } + + await callback(queriesToRun); +} diff --git a/drizzle-orm/src/singlestore-proxy/session.ts b/drizzle-orm/src/singlestore-proxy/session.ts new file mode 100644 index 000000000..42cc8ecde --- /dev/null +++ b/drizzle-orm/src/singlestore-proxy/session.ts @@ -0,0 +1,178 @@ +import type { FieldPacket, ResultSetHeader } from 'mysql2/promise'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import { SingleStoreTransaction } from '~/singlestore-core/index.ts'; +import type { SelectedFieldsOrdered } from '~/singlestore-core/query-builders/select.types.ts'; +import type { + PreparedQueryKind, + SingleStorePreparedQueryConfig, + SingleStorePreparedQueryHKT, + SingleStoreQueryResultHKT, + SingleStoreTransactionConfig, +} from '~/singlestore-core/session.ts'; +import { SingleStorePreparedQuery as PreparedQueryBase, SingleStoreSession } from '~/singlestore-core/session.ts'; +import type { Query, SQL } from '~/sql/sql.ts'; +import { fillPlaceholders } from '~/sql/sql.ts'; +import { type Assume, mapResultRow } from '~/utils.ts'; +import type { RemoteCallback } from './driver.ts'; + +export type SingleStoreRawQueryResult = [ResultSetHeader, FieldPacket[]]; + +export interface SingleStoreRemoteSessionOptions { + logger?: Logger; +} + +export class SingleStoreRemoteSession< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreSession { + static override readonly [entityKind]: string = 'SingleStoreRemoteSession'; + + private logger: Logger; + + constructor( + private client: RemoteCallback, + dialect: SingleStoreDialect, + private schema: RelationalSchemaConfig | undefined, + options: SingleStoreRemoteSessionOptions, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + } + + prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind { + return new PreparedQuery( + this.client, + query.sql, + query.params, + this.logger, + fields, + customResultMapper, + generatedIds, + returningIds, + ) as PreparedQueryKind; + } + + override all(query: SQL): Promise { + const querySql = this.dialect.sqlToQuery(query); + this.logger.logQuery(querySql.sql, querySql.params); + return this.client(querySql.sql, querySql.params, 'all').then(({ rows }) => rows) as Promise; + } + + override async transaction( + _transaction: (tx: SingleStoreProxyTransaction) => Promise, + _config?: SingleStoreTransactionConfig, + ): Promise { + throw new Error('Transactions are not supported by the SingleStore Proxy driver'); + } +} + +export class SingleStoreProxyTransaction< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreTransaction< + SingleStoreRemoteQueryResultHKT, + SingleStoreRemotePreparedQueryHKT, + TFullSchema, + TSchema +> { + static override readonly [entityKind]: string = 'SingleStoreProxyTransaction'; + + override async transaction( + _transaction: (tx: SingleStoreProxyTransaction) => Promise, + ): Promise { + throw new Error('Transactions are not supported by the SingleStore Proxy driver'); + } +} + +export class PreparedQuery extends PreparedQueryBase { + static override readonly [entityKind]: string = 'SingleStoreProxyPreparedQuery'; + + constructor( + private client: RemoteCallback, + private queryString: string, + private params: unknown[], + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + private customResultMapper?: (rows: unknown[][]) => T['execute'], + // Keys that were used in $default and the value that was generated for them + private generatedIds?: Record[], + // Keys that should be returned, it has the column with all properries + key from object + private returningIds?: SelectedFieldsOrdered, + ) { + super(); + } + + async execute(placeholderValues: Record | undefined = {}): Promise { + const params = fillPlaceholders(this.params, placeholderValues); + + const { fields, client, queryString, logger, joinsNotNullableMap, customResultMapper, returningIds, generatedIds } = + this; + + logger.logQuery(queryString, params); + + if (!fields && !customResultMapper) { + const { rows: data } = await client(queryString, params, 'execute'); + + const insertId = data[0].insertId as number; + const affectedRows = data[0].affectedRows; + + if (returningIds) { + const returningResponse = []; + let j = 0; + for (let i = insertId; i < insertId + affectedRows; i++) { + for (const column of returningIds) { + const key = returningIds[0]!.path[0]!; + if (is(column.field, Column)) { + // @ts-ignore + if (column.field.primary && column.field.autoIncrement) { + returningResponse.push({ [key]: i }); + } + if (column.field.defaultFn && generatedIds) { + // generatedIds[rowIdx][key] + returningResponse.push({ [key]: generatedIds[j]![key] }); + } + } + } + j++; + } + + return returningResponse; + } + + return data; + } + + const { rows } = await client(queryString, params, 'all'); + + if (customResultMapper) { + return customResultMapper(rows); + } + + return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + } + + override iterator( + _placeholderValues: Record = {}, + ): AsyncGenerator { + throw new Error('Streaming is not supported by the SingleStore Proxy driver'); + } +} + +export interface SingleStoreRemoteQueryResultHKT extends SingleStoreQueryResultHKT { + type: SingleStoreRawQueryResult; +} + +export interface SingleStoreRemotePreparedQueryHKT extends SingleStorePreparedQueryHKT { + type: PreparedQuery>; +} diff --git a/drizzle-orm/src/singlestore/driver.ts b/drizzle-orm/src/singlestore/driver.ts new file mode 100644 index 000000000..ba294f6dc --- /dev/null +++ b/drizzle-orm/src/singlestore/driver.ts @@ -0,0 +1,168 @@ +import { type Connection as CallbackConnection, createPool, type Pool as CallbackPool, type PoolOptions } from 'mysql2'; +import type { Connection, Pool } from 'mysql2/promise'; +import { entityKind } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { DefaultLogger } from '~/logger.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type RelationalSchemaConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import { SingleStoreDatabase } from '~/singlestore-core/db.ts'; +import { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import { type DrizzleConfig, type IfNotImported, type ImportTypeError, isConfig } from '~/utils.ts'; +import type { + SingleStoreDriverClient, + SingleStoreDriverPreparedQueryHKT, + SingleStoreDriverQueryResultHKT, +} from './session.ts'; +import { SingleStoreDriverSession } from './session.ts'; + +export interface SingleStoreDriverOptions { + logger?: Logger; +} + +export class SingleStoreDriverDriver { + static readonly [entityKind]: string = 'SingleStoreDriverDriver'; + + constructor( + private client: SingleStoreDriverClient, + private dialect: SingleStoreDialect, + private options: SingleStoreDriverOptions = {}, + ) { + } + + createSession( + schema: RelationalSchemaConfig | undefined, + ): SingleStoreDriverSession, TablesRelationalConfig> { + return new SingleStoreDriverSession(this.client, this.dialect, schema, { logger: this.options.logger }); + } +} + +export { SingleStoreDatabase } from '~/singlestore-core/db.ts'; + +export class SingleStoreDriverDatabase< + TSchema extends Record = Record, +> extends SingleStoreDatabase { + static override readonly [entityKind]: string = 'SingleStoreDriverDatabase'; +} + +export type SingleStoreDriverDrizzleConfig = Record> = + & Omit, 'schema'> + & ({ schema: TSchema } | { schema?: undefined }); + +function construct< + TSchema extends Record = Record, + TClient extends Pool | Connection | CallbackPool | CallbackConnection = CallbackPool, +>( + client: TClient, + config: SingleStoreDriverDrizzleConfig = {}, +): SingleStoreDriverDatabase & { + $client: TClient; +} { + const dialect = new SingleStoreDialect({ casing: config.casing }); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + + const clientForInstance = isCallbackClient(client) ? client.promise() : client; + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const driver = new SingleStoreDriverDriver(clientForInstance as SingleStoreDriverClient, dialect, { logger }); + const session = driver.createSession(schema); + const db = new SingleStoreDriverDatabase(dialect, session, schema as any) as SingleStoreDriverDatabase; + ( db).$client = client; + + return db as any; +} + +interface CallbackClient { + promise(): SingleStoreDriverClient; +} + +function isCallbackClient(client: any): client is CallbackClient { + return typeof client.promise === 'function'; +} + +export type AnySingleStoreDriverConnection = Pool | Connection | CallbackPool | CallbackConnection; + +export function drizzle< + TSchema extends Record = Record, + TClient extends AnySingleStoreDriverConnection = CallbackPool, +>( + ...params: IfNotImported< + CallbackPool, + [ImportTypeError<'singlestore'>], + [ + TClient | string, + ] | [ + TClient | string, + SingleStoreDriverDrizzleConfig, + ] | [ + ( + & SingleStoreDriverDrizzleConfig + & ({ + connection: string | PoolOptions; + } | { + client: TClient; + }) + ), + ] + > +): SingleStoreDriverDatabase & { + $client: TClient; +} { + if (typeof params[0] === 'string') { + const connectionString = params[0]!; + const instance = createPool({ + uri: connectionString, + }); + + return construct(instance, params[1]) as any; + } + + if (isConfig(params[0])) { + const { connection, client, ...drizzleConfig } = params[0] as + & { connection?: PoolOptions | string; client?: TClient } + & SingleStoreDriverDrizzleConfig; + + if (client) return construct(client, drizzleConfig) as any; + + const instance = typeof connection === 'string' + ? createPool({ + uri: connection, + }) + : createPool(connection!); + const db = construct(instance, drizzleConfig); + + return db as any; + } + + return construct(params[0] as TClient, params[1] as SingleStoreDriverDrizzleConfig | undefined) as any; +} + +export namespace drizzle { + export function mock = Record>( + config?: SingleStoreDriverDrizzleConfig, + ): SingleStoreDriverDatabase & { + $client: '$client is not available on drizzle.mock()'; + } { + return construct({} as any, config) as any; + } +} diff --git a/drizzle-orm/src/singlestore/index.ts b/drizzle-orm/src/singlestore/index.ts new file mode 100644 index 000000000..b1b6a52e7 --- /dev/null +++ b/drizzle-orm/src/singlestore/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/singlestore/migrator.ts b/drizzle-orm/src/singlestore/migrator.ts new file mode 100644 index 000000000..6f342c0c5 --- /dev/null +++ b/drizzle-orm/src/singlestore/migrator.ts @@ -0,0 +1,11 @@ +import type { MigrationConfig } from '~/migrator.ts'; +import { readMigrationFiles } from '~/migrator.ts'; +import type { SingleStoreDriverDatabase } from './driver.ts'; + +export async function migrate>( + db: SingleStoreDriverDatabase, + config: MigrationConfig, +) { + const migrations = readMigrationFiles(config); + await db.dialect.migrate(migrations, db.session, config); +} diff --git a/drizzle-orm/src/singlestore/session.ts b/drizzle-orm/src/singlestore/session.ts new file mode 100644 index 000000000..fd70a1d52 --- /dev/null +++ b/drizzle-orm/src/singlestore/session.ts @@ -0,0 +1,340 @@ +import type { Connection as CallbackConnection } from 'mysql2'; +import type { + Connection, + FieldPacket, + OkPacket, + Pool, + PoolConnection, + QueryOptions, + ResultSetHeader, + RowDataPacket, +} from 'mysql2/promise'; +import { once } from 'node:events'; +import { Column } from '~/column.ts'; +import { entityKind, is } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { SingleStoreDialect } from '~/singlestore-core/dialect.ts'; +import type { SelectedFieldsOrdered } from '~/singlestore-core/query-builders/select.types.ts'; +import { + type PreparedQueryKind, + SingleStorePreparedQuery, + type SingleStorePreparedQueryConfig, + type SingleStorePreparedQueryHKT, + type SingleStoreQueryResultHKT, + SingleStoreSession, + SingleStoreTransaction, + type SingleStoreTransactionConfig, +} from '~/singlestore-core/session.ts'; +import type { Query, SQL } from '~/sql/sql.ts'; +import { fillPlaceholders, sql } from '~/sql/sql.ts'; +import { type Assume, mapResultRow } from '~/utils.ts'; + +export type SingleStoreDriverClient = Pool | Connection; + +export type SingleStoreRawQueryResult = [ResultSetHeader, FieldPacket[]]; +export type SingleStoreQueryResultType = RowDataPacket[][] | RowDataPacket[] | OkPacket | OkPacket[] | ResultSetHeader; +export type SingleStoreQueryResult< + T = any, +> = [T extends ResultSetHeader ? T : T[], FieldPacket[]]; + +export class SingleStoreDriverPreparedQuery + extends SingleStorePreparedQuery +{ + static override readonly [entityKind]: string = 'SingleStoreDriverPreparedQuery'; + + private rawQuery: QueryOptions; + private query: QueryOptions; + + constructor( + private client: SingleStoreDriverClient, + queryString: string, + private params: unknown[], + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + private customResultMapper?: (rows: unknown[][]) => T['execute'], + // Keys that were used in $default and the value that was generated for them + private generatedIds?: Record[], + // Keys that should be returned, it has the column with all properries + key from object + private returningIds?: SelectedFieldsOrdered, + ) { + super(); + this.rawQuery = { + sql: queryString, + // rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }; + this.query = { + sql: queryString, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }; + } + + async execute(placeholderValues: Record = {}): Promise { + const params = fillPlaceholders(this.params, placeholderValues); + + this.logger.logQuery(this.rawQuery.sql, params); + + const { fields, client, rawQuery, query, joinsNotNullableMap, customResultMapper, returningIds, generatedIds } = + this; + if (!fields && !customResultMapper) { + const res = await client.query(rawQuery, params); + const insertId = res[0].insertId; + const affectedRows = res[0].affectedRows; + // for each row, I need to check keys from + if (returningIds) { + const returningResponse = []; + let j = 0; + for (let i = insertId; i < insertId + affectedRows; i++) { + for (const column of returningIds) { + const key = returningIds[0]!.path[0]!; + if (is(column.field, Column)) { + // @ts-ignore + if (column.field.primary && column.field.autoIncrement) { + returningResponse.push({ [key]: i }); + } + if (column.field.defaultFn && generatedIds) { + // generatedIds[rowIdx][key] + returningResponse.push({ [key]: generatedIds[j]![key] }); + } + } + } + j++; + } + + return returningResponse; + } + return res; + } + + const result = await client.query(query, params); + const rows = result[0]; + + if (customResultMapper) { + return customResultMapper(rows); + } + + return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + } + + async *iterator( + placeholderValues: Record = {}, + ): AsyncGenerator { + const params = fillPlaceholders(this.params, placeholderValues); + const conn = ((isPool(this.client) ? await this.client.getConnection() : this.client) as {} as { + connection: CallbackConnection; + }).connection; + + const { fields, query, rawQuery, joinsNotNullableMap, client, customResultMapper } = this; + const hasRowsMapper = Boolean(fields || customResultMapper); + const driverQuery = hasRowsMapper ? conn.query(query, params) : conn.query(rawQuery, params); + + const stream = driverQuery.stream(); + + function dataListener() { + stream.pause(); + } + + stream.on('data', dataListener); + + try { + const onEnd = once(stream, 'end'); + const onError = once(stream, 'error'); + + while (true) { + stream.resume(); + const row = await Promise.race([onEnd, onError, new Promise((resolve) => stream.once('data', resolve))]); + if (row === undefined || (Array.isArray(row) && row.length === 0)) { + break; + } else if (row instanceof Error) { // eslint-disable-line no-instanceof/no-instanceof + throw row; + } else { + if (hasRowsMapper) { + if (customResultMapper) { + const mappedRow = customResultMapper([row as unknown[]]); + yield (Array.isArray(mappedRow) ? mappedRow[0] : mappedRow); + } else { + yield mapResultRow(fields!, row as unknown[], joinsNotNullableMap); + } + } else { + yield row as T['execute']; + } + } + } + } finally { + stream.off('data', dataListener); + if (isPool(client)) { + conn.end(); + } + } + } +} + +export interface SingleStoreDriverSessionOptions { + logger?: Logger; +} + +export class SingleStoreDriverSession< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreSession { + static override readonly [entityKind]: string = 'SingleStoreDriverSession'; + + private logger: Logger; + + constructor( + private client: SingleStoreDriverClient, + dialect: SingleStoreDialect, + private schema: RelationalSchemaConfig | undefined, + private options: SingleStoreDriverSessionOptions, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + } + + prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + generatedIds?: Record[], + returningIds?: SelectedFieldsOrdered, + ): PreparedQueryKind { + // Add returningId fields + // Each driver gets them from response from database + return new SingleStoreDriverPreparedQuery( + this.client, + query.sql, + query.params, + this.logger, + fields, + customResultMapper, + generatedIds, + returningIds, + ) as PreparedQueryKind; + } + + /** + * @internal + * What is its purpose? + */ + async query(query: string, params: unknown[]): Promise { + this.logger.logQuery(query, params); + const result = await this.client.query({ + sql: query, + values: params, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + return result; + } + + override all(query: SQL): Promise { + const querySql = this.dialect.sqlToQuery(query); + this.logger.logQuery(querySql.sql, querySql.params); + return this.client.execute(querySql.sql, querySql.params).then((result) => result[0]) as Promise; + } + + override async transaction( + transaction: (tx: SingleStoreDriverTransaction) => Promise, + config?: SingleStoreTransactionConfig, + ): Promise { + const session = isPool(this.client) + ? new SingleStoreDriverSession( + await this.client.getConnection(), + this.dialect, + this.schema, + this.options, + ) + : this; + const tx = new SingleStoreDriverTransaction( + this.dialect, + session as SingleStoreSession, + this.schema, + 0, + ); + if (config) { + const setTransactionConfigSql = this.getSetTransactionSQL(config); + if (setTransactionConfigSql) { + await tx.execute(setTransactionConfigSql); + } + const startTransactionSql = this.getStartTransactionSQL(config); + await (startTransactionSql ? tx.execute(startTransactionSql) : tx.execute(sql`begin`)); + } else { + await tx.execute(sql`begin`); + } + try { + const result = await transaction(tx); + await tx.execute(sql`commit`); + return result; + } catch (err) { + await tx.execute(sql`rollback`); + throw err; + } finally { + if (isPool(this.client)) { + (session.client as PoolConnection).release(); + } + } + } +} + +export class SingleStoreDriverTransaction< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends SingleStoreTransaction< + SingleStoreDriverQueryResultHKT, + SingleStoreDriverPreparedQueryHKT, + TFullSchema, + TSchema +> { + static override readonly [entityKind]: string = 'SingleStoreDriverTransaction'; + + override async transaction( + transaction: (tx: SingleStoreDriverTransaction) => Promise, + ): Promise { + const savepointName = `sp${this.nestedIndex + 1}`; + const tx = new SingleStoreDriverTransaction( + this.dialect, + this.session, + this.schema, + this.nestedIndex + 1, + ); + await tx.execute(sql.raw(`savepoint ${savepointName}`)); + try { + const result = await transaction(tx); + await tx.execute(sql.raw(`release savepoint ${savepointName}`)); + return result; + } catch (err) { + await tx.execute(sql.raw(`rollback to savepoint ${savepointName}`)); + throw err; + } + } +} + +function isPool(client: SingleStoreDriverClient): client is Pool { + return 'getConnection' in client; +} + +export interface SingleStoreDriverQueryResultHKT extends SingleStoreQueryResultHKT { + type: SingleStoreRawQueryResult; +} + +export interface SingleStoreDriverPreparedQueryHKT extends SingleStorePreparedQueryHKT { + type: SingleStoreDriverPreparedQuery>; +} diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index d9f3fc7c6..dfd2795a4 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -40,8 +40,19 @@ export class SQLiteBigInt> return 'blob'; } - override mapFromDriverValue(value: Buffer | Uint8Array): bigint { - return BigInt(Buffer.isBuffer(value) ? value.toString() : String.fromCodePoint(...value)); + override mapFromDriverValue(value: Buffer | Uint8Array | ArrayBuffer): bigint { + if (Buffer.isBuffer(value)) { + return BigInt(value.toString()); + } + + // for sqlite durable objects + // eslint-disable-next-line no-instanceof/no-instanceof + if (value instanceof ArrayBuffer) { + const decoder = new TextDecoder(); + return BigInt(decoder.decode(value)); + } + + return BigInt(String.fromCodePoint(...value)); } override mapToDriverValue(value: bigint): Buffer { @@ -85,8 +96,19 @@ export class SQLiteBlobJson return 'blob'; } - override mapFromDriverValue(value: Buffer | Uint8Array): T['data'] { - return JSON.parse(Buffer.isBuffer(value) ? value.toString() : String.fromCodePoint(...value)); + override mapFromDriverValue(value: Buffer | Uint8Array | ArrayBuffer): T['data'] { + if (Buffer.isBuffer(value)) { + return JSON.parse(value.toString()); + } + + // for sqlite durable objects + // eslint-disable-next-line no-instanceof/no-instanceof + if (value instanceof ArrayBuffer) { + const decoder = new TextDecoder(); + return JSON.parse(decoder.decode(value)); + } + + return JSON.parse(String.fromCodePoint(...value)); } override mapToDriverValue(value: T['data']): Buffer { diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index bd8fea848..58d0c3d91 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -311,3 +311,5 @@ export function isConfig(data: any): boolean { return false; } + +export type NeonAuthToken = string | (() => string | Promise); diff --git a/drizzle-orm/type-tests/singlestore/1000columns.ts b/drizzle-orm/type-tests/singlestore/1000columns.ts new file mode 100644 index 000000000..f84640858 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/1000columns.ts @@ -0,0 +1,904 @@ +import { bigint, double, singlestoreTable, varchar } from '~/singlestore-core/index.ts'; + +singlestoreTable('test', { + col0: double('col1').primaryKey().autoincrement().default(0), + col1: double('col1').primaryKey().autoincrement().default(0), + col2: double('col1').primaryKey().autoincrement().default(0), + col3: double('col1').primaryKey().autoincrement().default(0), + col4: double('col1').primaryKey().autoincrement().default(0), + col5: double('col1').primaryKey().autoincrement().default(0), + col6: double('col1').primaryKey().autoincrement().default(0), + col8: double('col1').primaryKey().autoincrement().default(0), + col9: double('col1').primaryKey().autoincrement().default(0), + col10: double('col1').primaryKey().autoincrement().default(0), + col11: double('col1').primaryKey().autoincrement().default(0), + col12: double('col1').primaryKey().autoincrement().default(0), + col13: double('col1').primaryKey().autoincrement().default(0), + col14: double('col1').primaryKey().autoincrement().default(0), + col15: double('col1').primaryKey().autoincrement().default(0), + col16: double('col1').primaryKey().autoincrement().default(0), + col18: double('col1').primaryKey().autoincrement().default(0), + col19: double('col1').primaryKey().autoincrement().default(0), + col20: double('col1').primaryKey().autoincrement().default(0), + col21: double('col1').primaryKey().autoincrement().default(0), + col22: double('col1').primaryKey().autoincrement().default(0), + col23: double('col1').primaryKey().autoincrement().default(0), + col24: double('col1').primaryKey().autoincrement().default(0), + col25: double('col1').primaryKey().autoincrement().default(0), + col26: double('col1').primaryKey().autoincrement().default(0), + col28: double('col1').primaryKey().autoincrement().default(0), + col29: double('col1').primaryKey().autoincrement().default(0), + col30: double('col1').primaryKey().autoincrement().default(0), + col31: double('col1').primaryKey().autoincrement().default(0), + col32: double('col1').primaryKey().autoincrement().default(0), + col33: double('col1').primaryKey().autoincrement().default(0), + col34: double('col1').primaryKey().autoincrement().default(0), + col35: double('col1').primaryKey().autoincrement().default(0), + col36: double('col1').primaryKey().autoincrement().default(0), + col38: double('col1').primaryKey().autoincrement().default(0), + col39: double('col1').primaryKey().autoincrement().default(0), + col40: double('col1').primaryKey().autoincrement().default(0), + col41: double('col1').primaryKey().autoincrement().default(0), + col42: double('col1').primaryKey().autoincrement().default(0), + col43: double('col1').primaryKey().autoincrement().default(0), + col44: double('col1').primaryKey().autoincrement().default(0), + col45: double('col1').primaryKey().autoincrement().default(0), + col46: double('col1').primaryKey().autoincrement().default(0), + col48: double('col1').primaryKey().autoincrement().default(0), + col49: double('col1').primaryKey().autoincrement().default(0), + col50: double('col1').primaryKey().autoincrement().default(0), + col51: double('col1').primaryKey().autoincrement().default(0), + col52: double('col1').primaryKey().autoincrement().default(0), + col53: double('col1').primaryKey().autoincrement().default(0), + col54: double('col1').primaryKey().autoincrement().default(0), + col55: double('col1').primaryKey().autoincrement().default(0), + col56: double('col1').primaryKey().autoincrement().default(0), + col58: double('col1').primaryKey().autoincrement().default(0), + col59: double('col1').primaryKey().autoincrement().default(0), + col60: double('col1').primaryKey().autoincrement().default(0), + col61: double('col1').primaryKey().autoincrement().default(0), + col62: double('col1').primaryKey().autoincrement().default(0), + col63: double('col1').primaryKey().autoincrement().default(0), + col64: double('col1').primaryKey().autoincrement().default(0), + col65: double('col1').primaryKey().autoincrement().default(0), + col66: double('col1').primaryKey().autoincrement().default(0), + col68: double('col1').primaryKey().autoincrement().default(0), + col69: double('col1').primaryKey().autoincrement().default(0), + col70: double('col1').primaryKey().autoincrement().default(0), + col71: double('col1').primaryKey().autoincrement().default(0), + col72: double('col1').primaryKey().autoincrement().default(0), + col73: double('col1').primaryKey().autoincrement().default(0), + col74: double('col1').primaryKey().autoincrement().default(0), + col75: double('col1').primaryKey().autoincrement().default(0), + col76: double('col1').primaryKey().autoincrement().default(0), + col78: double('col1').primaryKey().autoincrement().default(0), + col79: double('col1').primaryKey().autoincrement().default(0), + col80: double('col1').primaryKey().autoincrement().default(0), + col81: double('col1').primaryKey().autoincrement().default(0), + col82: double('col1').primaryKey().autoincrement().default(0), + col83: double('col1').primaryKey().autoincrement().default(0), + col84: double('col1').primaryKey().autoincrement().default(0), + col85: double('col1').primaryKey().autoincrement().default(0), + col86: double('col1').primaryKey().autoincrement().default(0), + col88: double('col1').primaryKey().autoincrement().default(0), + col89: double('col1').primaryKey().autoincrement().default(0), + col90: double('col1').primaryKey().autoincrement().default(0), + col91: double('col1').primaryKey().autoincrement().default(0), + col92: double('col1').primaryKey().autoincrement().default(0), + col93: double('col1').primaryKey().autoincrement().default(0), + col94: double('col1').primaryKey().autoincrement().default(0), + col95: double('col1').primaryKey().autoincrement().default(0), + col96: double('col1').primaryKey().autoincrement().default(0), + col98: double('col1').primaryKey().autoincrement().default(0), + col99: double('col1').primaryKey().autoincrement().default(0), + col100: double('col1').primaryKey().autoincrement().default(0), + col101: double('col1').primaryKey().autoincrement().default(0), + col102: double('col1').primaryKey().autoincrement().default(0), + col103: double('col1').primaryKey().autoincrement().default(0), + col104: double('col1').primaryKey().autoincrement().default(0), + col105: double('col1').primaryKey().autoincrement().default(0), + col106: double('col1').primaryKey().autoincrement().default(0), + col108: double('col1').primaryKey().autoincrement().default(0), + col109: double('col1').primaryKey().autoincrement().default(0), + col110: double('col11').primaryKey().autoincrement().default(0), + col111: double('col11').primaryKey().autoincrement().default(0), + col112: double('col11').primaryKey().autoincrement().default(0), + col113: double('col11').primaryKey().autoincrement().default(0), + col114: double('col11').primaryKey().autoincrement().default(0), + col115: double('col11').primaryKey().autoincrement().default(0), + col116: double('col11').primaryKey().autoincrement().default(0), + col118: double('col11').primaryKey().autoincrement().default(0), + col119: double('col11').primaryKey().autoincrement().default(0), + col120: double('col11').primaryKey().autoincrement().default(0), + col121: double('col11').primaryKey().autoincrement().default(0), + col122: double('col11').primaryKey().autoincrement().default(0), + col123: double('col11').primaryKey().autoincrement().default(0), + col124: double('col11').primaryKey().autoincrement().default(0), + col125: double('col11').primaryKey().autoincrement().default(0), + col126: double('col11').primaryKey().autoincrement().default(0), + col128: double('col11').primaryKey().autoincrement().default(0), + col129: double('col11').primaryKey().autoincrement().default(0), + col130: double('col11').primaryKey().autoincrement().default(0), + col131: double('col11').primaryKey().autoincrement().default(0), + col132: double('col11').primaryKey().autoincrement().default(0), + col133: double('col11').primaryKey().autoincrement().default(0), + col134: double('col11').primaryKey().autoincrement().default(0), + col135: double('col11').primaryKey().autoincrement().default(0), + col136: double('col11').primaryKey().autoincrement().default(0), + col138: double('col11').primaryKey().autoincrement().default(0), + col139: double('col11').primaryKey().autoincrement().default(0), + col140: double('col11').primaryKey().autoincrement().default(0), + col141: double('col11').primaryKey().autoincrement().default(0), + col142: double('col11').primaryKey().autoincrement().default(0), + col143: double('col11').primaryKey().autoincrement().default(0), + col144: double('col11').primaryKey().autoincrement().default(0), + col145: double('col11').primaryKey().autoincrement().default(0), + col146: double('col11').primaryKey().autoincrement().default(0), + col148: double('col11').primaryKey().autoincrement().default(0), + col149: double('col11').primaryKey().autoincrement().default(0), + col150: double('col11').primaryKey().autoincrement().default(0), + col151: double('col11').primaryKey().autoincrement().default(0), + col152: double('col11').primaryKey().autoincrement().default(0), + col153: double('col11').primaryKey().autoincrement().default(0), + col154: double('col11').primaryKey().autoincrement().default(0), + col155: double('col11').primaryKey().autoincrement().default(0), + col156: double('col11').primaryKey().autoincrement().default(0), + col158: double('col11').primaryKey().autoincrement().default(0), + col159: double('col11').primaryKey().autoincrement().default(0), + col160: double('col11').primaryKey().autoincrement().default(0), + col161: double('col11').primaryKey().autoincrement().default(0), + col162: double('col11').primaryKey().autoincrement().default(0), + col163: double('col11').primaryKey().autoincrement().default(0), + col164: double('col11').primaryKey().autoincrement().default(0), + col165: double('col11').primaryKey().autoincrement().default(0), + col166: double('col11').primaryKey().autoincrement().default(0), + col168: double('col11').primaryKey().autoincrement().default(0), + col169: double('col11').primaryKey().autoincrement().default(0), + col170: double('col11').primaryKey().autoincrement().default(0), + col171: double('col11').primaryKey().autoincrement().default(0), + col172: double('col11').primaryKey().autoincrement().default(0), + col173: double('col11').primaryKey().autoincrement().default(0), + col174: double('col11').primaryKey().autoincrement().default(0), + col175: double('col11').primaryKey().autoincrement().default(0), + col176: double('col11').primaryKey().autoincrement().default(0), + col178: double('col11').primaryKey().autoincrement().default(0), + col179: double('col11').primaryKey().autoincrement().default(0), + col180: double('col11').primaryKey().autoincrement().default(0), + col181: double('col11').primaryKey().autoincrement().default(0), + col182: double('col11').primaryKey().autoincrement().default(0), + col183: double('col11').primaryKey().autoincrement().default(0), + col184: double('col11').primaryKey().autoincrement().default(0), + col185: double('col11').primaryKey().autoincrement().default(0), + col186: double('col11').primaryKey().autoincrement().default(0), + col188: double('col11').primaryKey().autoincrement().default(0), + col189: double('col11').primaryKey().autoincrement().default(0), + col190: double('col11').primaryKey().autoincrement().default(0), + col191: double('col11').primaryKey().autoincrement().default(0), + col192: double('col11').primaryKey().autoincrement().default(0), + col193: double('col11').primaryKey().autoincrement().default(0), + col194: double('col11').primaryKey().autoincrement().default(0), + col195: double('col11').primaryKey().autoincrement().default(0), + col196: double('col11').primaryKey().autoincrement().default(0), + col198: double('col11').primaryKey().autoincrement().default(0), + col199: double('col11').primaryKey().autoincrement().default(0), + col200: double('col2').primaryKey().autoincrement().default(0), + col201: double('col2').primaryKey().autoincrement().default(0), + col202: double('col2').primaryKey().autoincrement().default(0), + col203: double('col2').primaryKey().autoincrement().default(0), + col204: double('col2').primaryKey().autoincrement().default(0), + col205: double('col2').primaryKey().autoincrement().default(0), + col206: double('col2').primaryKey().autoincrement().default(0), + col208: double('col2').primaryKey().autoincrement().default(0), + col209: double('col2').primaryKey().autoincrement().default(0), + col210: double('col21').primaryKey().autoincrement().default(0), + col211: double('col21').primaryKey().autoincrement().default(0), + col212: double('col21').primaryKey().autoincrement().default(0), + col213: double('col21').primaryKey().autoincrement().default(0), + col214: double('col21').primaryKey().autoincrement().default(0), + col215: double('col21').primaryKey().autoincrement().default(0), + col216: double('col21').primaryKey().autoincrement().default(0), + col218: double('col21').primaryKey().autoincrement().default(0), + col219: double('col21').primaryKey().autoincrement().default(0), + col220: double('col21').primaryKey().autoincrement().default(0), + col221: double('col21').primaryKey().autoincrement().default(0), + col222: double('col21').primaryKey().autoincrement().default(0), + col223: double('col21').primaryKey().autoincrement().default(0), + col224: double('col21').primaryKey().autoincrement().default(0), + col225: double('col21').primaryKey().autoincrement().default(0), + col226: double('col21').primaryKey().autoincrement().default(0), + col228: double('col21').primaryKey().autoincrement().default(0), + col229: double('col21').primaryKey().autoincrement().default(0), + col230: double('col21').primaryKey().autoincrement().default(0), + col231: double('col21').primaryKey().autoincrement().default(0), + col232: double('col21').primaryKey().autoincrement().default(0), + col233: double('col21').primaryKey().autoincrement().default(0), + col234: double('col21').primaryKey().autoincrement().default(0), + col235: double('col21').primaryKey().autoincrement().default(0), + col236: double('col21').primaryKey().autoincrement().default(0), + col238: double('col21').primaryKey().autoincrement().default(0), + col239: double('col21').primaryKey().autoincrement().default(0), + col240: double('col21').primaryKey().autoincrement().default(0), + col241: double('col21').primaryKey().autoincrement().default(0), + col242: double('col21').primaryKey().autoincrement().default(0), + col243: double('col21').primaryKey().autoincrement().default(0), + col244: double('col21').primaryKey().autoincrement().default(0), + col245: double('col21').primaryKey().autoincrement().default(0), + col246: double('col21').primaryKey().autoincrement().default(0), + col248: double('col21').primaryKey().autoincrement().default(0), + col249: double('col21').primaryKey().autoincrement().default(0), + col250: double('col21').primaryKey().autoincrement().default(0), + col251: double('col21').primaryKey().autoincrement().default(0), + col252: double('col21').primaryKey().autoincrement().default(0), + col253: double('col21').primaryKey().autoincrement().default(0), + col254: double('col21').primaryKey().autoincrement().default(0), + col255: double('col21').primaryKey().autoincrement().default(0), + col256: double('col21').primaryKey().autoincrement().default(0), + col258: double('col21').primaryKey().autoincrement().default(0), + col259: double('col21').primaryKey().autoincrement().default(0), + col260: double('col21').primaryKey().autoincrement().default(0), + col261: double('col21').primaryKey().autoincrement().default(0), + col262: double('col21').primaryKey().autoincrement().default(0), + col263: double('col21').primaryKey().autoincrement().default(0), + col264: double('col21').primaryKey().autoincrement().default(0), + col265: double('col21').primaryKey().autoincrement().default(0), + col266: double('col21').primaryKey().autoincrement().default(0), + col268: double('col21').primaryKey().autoincrement().default(0), + col269: double('col21').primaryKey().autoincrement().default(0), + col270: double('col21').primaryKey().autoincrement().default(0), + col271: double('col21').primaryKey().autoincrement().default(0), + col272: double('col21').primaryKey().autoincrement().default(0), + col273: double('col21').primaryKey().autoincrement().default(0), + col274: double('col21').primaryKey().autoincrement().default(0), + col275: double('col21').primaryKey().autoincrement().default(0), + col276: double('col21').primaryKey().autoincrement().default(0), + col278: double('col21').primaryKey().autoincrement().default(0), + col279: double('col21').primaryKey().autoincrement().default(0), + col280: double('col21').primaryKey().autoincrement().default(0), + col281: double('col21').primaryKey().autoincrement().default(0), + col282: double('col21').primaryKey().autoincrement().default(0), + col283: double('col21').primaryKey().autoincrement().default(0), + col284: double('col21').primaryKey().autoincrement().default(0), + col285: double('col21').primaryKey().autoincrement().default(0), + col286: double('col21').primaryKey().autoincrement().default(0), + col288: double('col21').primaryKey().autoincrement().default(0), + col289: double('col21').primaryKey().autoincrement().default(0), + col290: double('col21').primaryKey().autoincrement().default(0), + col291: double('col21').primaryKey().autoincrement().default(0), + col292: double('col21').primaryKey().autoincrement().default(0), + col293: double('col21').primaryKey().autoincrement().default(0), + col294: double('col21').primaryKey().autoincrement().default(0), + col295: double('col21').primaryKey().autoincrement().default(0), + col296: double('col21').primaryKey().autoincrement().default(0), + col298: double('col21').primaryKey().autoincrement().default(0), + col299: double('col21').primaryKey().autoincrement().default(0), + col300: double('col3').primaryKey().autoincrement().default(0), + col301: double('col3').primaryKey().autoincrement().default(0), + col302: double('col3').primaryKey().autoincrement().default(0), + col303: double('col3').primaryKey().autoincrement().default(0), + col304: double('col3').primaryKey().autoincrement().default(0), + col305: double('col3').primaryKey().autoincrement().default(0), + col306: double('col3').primaryKey().autoincrement().default(0), + col308: double('col3').primaryKey().autoincrement().default(0), + col309: double('col3').primaryKey().autoincrement().default(0), + col310: double('col31').primaryKey().autoincrement().default(0), + col311: double('col31').primaryKey().autoincrement().default(0), + col312: double('col31').primaryKey().autoincrement().default(0), + col313: double('col31').primaryKey().autoincrement().default(0), + col314: double('col31').primaryKey().autoincrement().default(0), + col315: double('col31').primaryKey().autoincrement().default(0), + col316: double('col31').primaryKey().autoincrement().default(0), + col318: double('col31').primaryKey().autoincrement().default(0), + col319: double('col31').primaryKey().autoincrement().default(0), + col320: double('col31').primaryKey().autoincrement().default(0), + col321: double('col31').primaryKey().autoincrement().default(0), + col322: double('col31').primaryKey().autoincrement().default(0), + col323: double('col31').primaryKey().autoincrement().default(0), + col324: double('col31').primaryKey().autoincrement().default(0), + col325: double('col31').primaryKey().autoincrement().default(0), + col326: double('col31').primaryKey().autoincrement().default(0), + col328: double('col31').primaryKey().autoincrement().default(0), + col329: double('col31').primaryKey().autoincrement().default(0), + col330: double('col31').primaryKey().autoincrement().default(0), + col331: double('col31').primaryKey().autoincrement().default(0), + col332: double('col31').primaryKey().autoincrement().default(0), + col333: double('col31').primaryKey().autoincrement().default(0), + col334: double('col31').primaryKey().autoincrement().default(0), + col335: double('col31').primaryKey().autoincrement().default(0), + col336: double('col31').primaryKey().autoincrement().default(0), + col338: double('col31').primaryKey().autoincrement().default(0), + col339: double('col31').primaryKey().autoincrement().default(0), + col340: double('col31').primaryKey().autoincrement().default(0), + col341: double('col31').primaryKey().autoincrement().default(0), + col342: double('col31').primaryKey().autoincrement().default(0), + col343: double('col31').primaryKey().autoincrement().default(0), + col344: double('col31').primaryKey().autoincrement().default(0), + col345: double('col31').primaryKey().autoincrement().default(0), + col346: double('col31').primaryKey().autoincrement().default(0), + col348: double('col31').primaryKey().autoincrement().default(0), + col349: double('col31').primaryKey().autoincrement().default(0), + col350: double('col31').primaryKey().autoincrement().default(0), + col351: double('col31').primaryKey().autoincrement().default(0), + col352: double('col31').primaryKey().autoincrement().default(0), + col353: double('col31').primaryKey().autoincrement().default(0), + col354: double('col31').primaryKey().autoincrement().default(0), + col355: double('col31').primaryKey().autoincrement().default(0), + col356: double('col31').primaryKey().autoincrement().default(0), + col358: double('col31').primaryKey().autoincrement().default(0), + col359: double('col31').primaryKey().autoincrement().default(0), + col360: double('col31').primaryKey().autoincrement().default(0), + col361: double('col31').primaryKey().autoincrement().default(0), + col362: double('col31').primaryKey().autoincrement().default(0), + col363: double('col31').primaryKey().autoincrement().default(0), + col364: double('col31').primaryKey().autoincrement().default(0), + col365: double('col31').primaryKey().autoincrement().default(0), + col366: double('col31').primaryKey().autoincrement().default(0), + col368: double('col31').primaryKey().autoincrement().default(0), + col369: double('col31').primaryKey().autoincrement().default(0), + col370: double('col31').primaryKey().autoincrement().default(0), + col371: double('col31').primaryKey().autoincrement().default(0), + col372: double('col31').primaryKey().autoincrement().default(0), + col373: double('col31').primaryKey().autoincrement().default(0), + col374: double('col31').primaryKey().autoincrement().default(0), + col375: double('col31').primaryKey().autoincrement().default(0), + col376: double('col31').primaryKey().autoincrement().default(0), + col378: double('col31').primaryKey().autoincrement().default(0), + col379: double('col31').primaryKey().autoincrement().default(0), + col380: double('col31').primaryKey().autoincrement().default(0), + col381: double('col31').primaryKey().autoincrement().default(0), + col382: double('col31').primaryKey().autoincrement().default(0), + col383: double('col31').primaryKey().autoincrement().default(0), + col384: double('col31').primaryKey().autoincrement().default(0), + col385: double('col31').primaryKey().autoincrement().default(0), + col386: double('col31').primaryKey().autoincrement().default(0), + col388: double('col31').primaryKey().autoincrement().default(0), + col389: double('col31').primaryKey().autoincrement().default(0), + col390: double('col31').primaryKey().autoincrement().default(0), + col391: double('col31').primaryKey().autoincrement().default(0), + col392: double('col31').primaryKey().autoincrement().default(0), + col393: double('col31').primaryKey().autoincrement().default(0), + col394: double('col31').primaryKey().autoincrement().default(0), + col395: double('col31').primaryKey().autoincrement().default(0), + col396: double('col31').primaryKey().autoincrement().default(0), + col398: double('col31').primaryKey().autoincrement().default(0), + col399: double('col31').primaryKey().autoincrement().default(0), + col400: double('col4').primaryKey().autoincrement().default(0), + col401: double('col4').primaryKey().autoincrement().default(0), + col402: double('col4').primaryKey().autoincrement().default(0), + col403: double('col4').primaryKey().autoincrement().default(0), + col404: double('col4').primaryKey().autoincrement().default(0), + col405: double('col4').primaryKey().autoincrement().default(0), + col406: double('col4').primaryKey().autoincrement().default(0), + col408: double('col4').primaryKey().autoincrement().default(0), + col409: double('col4').primaryKey().autoincrement().default(0), + col410: double('col41').primaryKey().autoincrement().default(0), + col411: double('col41').primaryKey().autoincrement().default(0), + col412: double('col41').primaryKey().autoincrement().default(0), + col413: double('col41').primaryKey().autoincrement().default(0), + col414: double('col41').primaryKey().autoincrement().default(0), + col415: double('col41').primaryKey().autoincrement().default(0), + col416: double('col41').primaryKey().autoincrement().default(0), + col418: double('col41').primaryKey().autoincrement().default(0), + col419: double('col41').primaryKey().autoincrement().default(0), + col420: double('col41').primaryKey().autoincrement().default(0), + col421: double('col41').primaryKey().autoincrement().default(0), + col422: double('col41').primaryKey().autoincrement().default(0), + col423: double('col41').primaryKey().autoincrement().default(0), + col424: double('col41').primaryKey().autoincrement().default(0), + col425: double('col41').primaryKey().autoincrement().default(0), + col426: double('col41').primaryKey().autoincrement().default(0), + col428: double('col41').primaryKey().autoincrement().default(0), + col429: double('col41').primaryKey().autoincrement().default(0), + col430: double('col41').primaryKey().autoincrement().default(0), + col431: double('col41').primaryKey().autoincrement().default(0), + col432: double('col41').primaryKey().autoincrement().default(0), + col433: double('col41').primaryKey().autoincrement().default(0), + col434: double('col41').primaryKey().autoincrement().default(0), + col435: double('col41').primaryKey().autoincrement().default(0), + col436: double('col41').primaryKey().autoincrement().default(0), + col438: double('col41').primaryKey().autoincrement().default(0), + col439: double('col41').primaryKey().autoincrement().default(0), + col440: double('col41').primaryKey().autoincrement().default(0), + col441: double('col41').primaryKey().autoincrement().default(0), + col442: double('col41').primaryKey().autoincrement().default(0), + col443: double('col41').primaryKey().autoincrement().default(0), + col444: double('col41').primaryKey().autoincrement().default(0), + col445: double('col41').primaryKey().autoincrement().default(0), + col446: double('col41').primaryKey().autoincrement().default(0), + col448: double('col41').primaryKey().autoincrement().default(0), + col449: double('col41').primaryKey().autoincrement().default(0), + col450: double('col41').primaryKey().autoincrement().default(0), + col451: double('col41').primaryKey().autoincrement().default(0), + col452: double('col41').primaryKey().autoincrement().default(0), + col453: double('col41').primaryKey().autoincrement().default(0), + col454: double('col41').primaryKey().autoincrement().default(0), + col455: double('col41').primaryKey().autoincrement().default(0), + col456: double('col41').primaryKey().autoincrement().default(0), + col458: double('col41').primaryKey().autoincrement().default(0), + col459: double('col41').primaryKey().autoincrement().default(0), + col460: double('col41').primaryKey().autoincrement().default(0), + col461: double('col41').primaryKey().autoincrement().default(0), + col462: double('col41').primaryKey().autoincrement().default(0), + col463: double('col41').primaryKey().autoincrement().default(0), + col464: double('col41').primaryKey().autoincrement().default(0), + col465: double('col41').primaryKey().autoincrement().default(0), + col466: double('col41').primaryKey().autoincrement().default(0), + col468: double('col41').primaryKey().autoincrement().default(0), + col469: double('col41').primaryKey().autoincrement().default(0), + col470: double('col41').primaryKey().autoincrement().default(0), + col471: double('col41').primaryKey().autoincrement().default(0), + col472: double('col41').primaryKey().autoincrement().default(0), + col473: double('col41').primaryKey().autoincrement().default(0), + col474: double('col41').primaryKey().autoincrement().default(0), + col475: double('col41').primaryKey().autoincrement().default(0), + col476: double('col41').primaryKey().autoincrement().default(0), + col478: double('col41').primaryKey().autoincrement().default(0), + col479: double('col41').primaryKey().autoincrement().default(0), + col480: double('col41').primaryKey().autoincrement().default(0), + col481: double('col41').primaryKey().autoincrement().default(0), + col482: double('col41').primaryKey().autoincrement().default(0), + col483: double('col41').primaryKey().autoincrement().default(0), + col484: double('col41').primaryKey().autoincrement().default(0), + col485: double('col41').primaryKey().autoincrement().default(0), + col486: double('col41').primaryKey().autoincrement().default(0), + col488: double('col41').primaryKey().autoincrement().default(0), + col489: double('col41').primaryKey().autoincrement().default(0), + col490: double('col41').primaryKey().autoincrement().default(0), + col491: double('col41').primaryKey().autoincrement().default(0), + col492: double('col41').primaryKey().autoincrement().default(0), + col493: double('col41').primaryKey().autoincrement().default(0), + col494: double('col41').primaryKey().autoincrement().default(0), + col495: double('col41').primaryKey().autoincrement().default(0), + col496: double('col41').primaryKey().autoincrement().default(0), + col498: double('col41').primaryKey().autoincrement().default(0), + col499: double('col41').primaryKey().autoincrement().default(0), + col500: double('col5').primaryKey().autoincrement().default(0), + col501: double('col5').primaryKey().autoincrement().default(0), + col502: double('col5').primaryKey().autoincrement().default(0), + col503: double('col5').primaryKey().autoincrement().default(0), + col504: double('col5').primaryKey().autoincrement().default(0), + col505: double('col5').primaryKey().autoincrement().default(0), + col506: double('col5').primaryKey().autoincrement().default(0), + col508: double('col5').primaryKey().autoincrement().default(0), + col509: double('col5').primaryKey().autoincrement().default(0), + col510: double('col51').primaryKey().autoincrement().default(0), + col511: double('col51').primaryKey().autoincrement().default(0), + col512: double('col51').primaryKey().autoincrement().default(0), + col513: double('col51').primaryKey().autoincrement().default(0), + col514: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col515: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col516: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col518: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col519: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col520: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col521: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col522: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col523: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col524: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col525: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col526: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col528: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col529: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col530: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col531: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col532: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col533: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col534: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col535: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col536: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col538: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col539: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col540: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col541: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col542: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col543: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col544: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col545: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col546: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col548: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col549: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col550: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col551: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col552: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col553: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col554: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col555: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col556: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col558: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col559: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col560: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col561: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col562: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col563: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col564: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col565: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col566: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col568: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col569: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col570: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col571: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col572: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col573: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col574: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col575: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col576: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col578: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col579: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col580: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col581: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col582: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col583: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col584: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col585: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col586: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col588: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col589: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col590: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col591: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col592: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col593: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col594: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col595: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col596: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col598: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col599: bigint('col51', { mode: 'number' }).primaryKey().autoincrement().default(0), + col600: bigint('col6', { mode: 'number' }).primaryKey().autoincrement().default(0), + col601: double('col6').primaryKey().autoincrement().default(0), + col602: double('col6').primaryKey().autoincrement().default(0), + col603: double('col6').primaryKey().autoincrement().default(0), + col604: double('col6').primaryKey().autoincrement().default(0), + col605: double('col6').primaryKey().autoincrement().default(0), + col606: double('col6').primaryKey().autoincrement().default(0), + col608: double('col6').primaryKey().autoincrement().default(0), + col609: double('col6').primaryKey().autoincrement().default(0), + col610: double('col61').primaryKey().autoincrement().default(0), + col611: double('col61').primaryKey().autoincrement().default(0), + col612: double('col61').primaryKey().autoincrement().default(0), + col613: double('col61').primaryKey().autoincrement().default(0), + col614: double('col61').primaryKey().autoincrement().default(0), + col615: double('col61').primaryKey().autoincrement().default(0), + col616: double('col61').primaryKey().autoincrement().default(0), + col618: double('col61').primaryKey().autoincrement().default(0), + col619: double('col61').primaryKey().autoincrement().default(0), + col620: double('col61').primaryKey().autoincrement().default(0), + col621: double('col61').primaryKey().autoincrement().default(0), + col622: double('col61').primaryKey().autoincrement().default(0), + col623: double('col61').primaryKey().autoincrement().default(0), + col624: double('col61').primaryKey().autoincrement().default(0), + col625: double('col61').primaryKey().autoincrement().default(0), + col626: double('col61').primaryKey().autoincrement().default(0), + col628: double('col61').primaryKey().autoincrement().default(0), + col629: double('col61').primaryKey().autoincrement().default(0), + col630: double('col61').primaryKey().autoincrement().default(0), + col631: double('col61').primaryKey().autoincrement().default(0), + col632: double('col61').primaryKey().autoincrement().default(0), + col633: double('col61').primaryKey().autoincrement().default(0), + col634: double('col61').primaryKey().autoincrement().default(0), + col635: double('col61').primaryKey().autoincrement().default(0), + col636: double('col61').primaryKey().autoincrement().default(0), + col638: double('col61').primaryKey().autoincrement().default(0), + col639: double('col61').primaryKey().autoincrement().default(0), + col640: double('col61').primaryKey().autoincrement().default(0), + col641: double('col61').primaryKey().autoincrement().default(0), + col642: double('col61').primaryKey().autoincrement().default(0), + col643: double('col61').primaryKey().autoincrement().default(0), + col644: double('col61').primaryKey().autoincrement().default(0), + col645: double('col61').primaryKey().autoincrement().default(0), + col646: double('col61').primaryKey().autoincrement().default(0), + col648: double('col61').primaryKey().autoincrement().default(0), + col649: double('col61').primaryKey().autoincrement().default(0), + col650: double('col61').primaryKey().autoincrement().default(0), + col651: double('col61').primaryKey().autoincrement().default(0), + col652: double('col61').primaryKey().autoincrement().default(0), + col653: double('col61').primaryKey().autoincrement().default(0), + col654: double('col61').primaryKey().autoincrement().default(0), + col655: double('col61').primaryKey().autoincrement().default(0), + col656: double('col61').primaryKey().autoincrement().default(0), + col658: double('col61').primaryKey().autoincrement().default(0), + col659: double('col61').primaryKey().autoincrement().default(0), + col660: double('col61').primaryKey().autoincrement().default(0), + col661: double('col61').primaryKey().autoincrement().default(0), + col662: double('col61').primaryKey().autoincrement().default(0), + col663: double('col61').primaryKey().autoincrement().default(0), + col664: double('col61').primaryKey().autoincrement().default(0), + col665: double('col61').primaryKey().autoincrement().default(0), + col666: double('col61').primaryKey().autoincrement().default(0), + col668: double('col61').primaryKey().autoincrement().default(0), + col669: double('col61').primaryKey().autoincrement().default(0), + col670: double('col61').primaryKey().autoincrement().default(0), + col671: double('col61').primaryKey().autoincrement().default(0), + col672: double('col61').primaryKey().autoincrement().default(0), + col673: double('col61').primaryKey().autoincrement().default(0), + col674: double('col61').primaryKey().autoincrement().default(0), + col675: double('col61').primaryKey().autoincrement().default(0), + col676: double('col61').primaryKey().autoincrement().default(0), + col678: double('col61').primaryKey().autoincrement().default(0), + col679: double('col61').primaryKey().autoincrement().default(0), + col680: double('col61').primaryKey().autoincrement().default(0), + col681: double('col61').primaryKey().autoincrement().default(0), + col682: double('col61').primaryKey().autoincrement().default(0), + col683: double('col61').primaryKey().autoincrement().default(0), + col684: double('col61').primaryKey().autoincrement().default(0), + col685: double('col61').primaryKey().autoincrement().default(0), + col686: double('col61').primaryKey().autoincrement().default(0), + col688: double('col61').primaryKey().autoincrement().default(0), + col689: double('col61').primaryKey().autoincrement().default(0), + col690: double('col61').primaryKey().autoincrement().default(0), + col691: double('col61').primaryKey().autoincrement().default(0), + col692: double('col61').primaryKey().autoincrement().default(0), + col693: double('col61').primaryKey().autoincrement().default(0), + col694: double('col61').primaryKey().autoincrement().default(0), + col695: double('col61').primaryKey().autoincrement().default(0), + col696: double('col61').primaryKey().autoincrement().default(0), + col698: double('col61').primaryKey().autoincrement().default(0), + col699: double('col61').primaryKey().autoincrement().default(0), + col700: double('col7').primaryKey().autoincrement().default(0), + col701: double('col7').primaryKey().autoincrement().default(0), + col702: double('col7').primaryKey().autoincrement().default(0), + col703: double('col7').primaryKey().autoincrement().default(0), + col704: double('col7').primaryKey().autoincrement().default(0), + col705: double('col7').primaryKey().autoincrement().default(0), + col706: double('col7').primaryKey().autoincrement().default(0), + col708: double('col7').primaryKey().autoincrement().default(0), + col709: double('col7').primaryKey().autoincrement().default(0), + col710: double('col71').primaryKey().autoincrement().default(0), + col711: double('col71').primaryKey().autoincrement().default(0), + col712: double('col71').primaryKey().autoincrement().default(0), + col713: double('col71').primaryKey().autoincrement().default(0), + col714: double('col71').primaryKey().autoincrement().default(0), + col715: double('col71').primaryKey().autoincrement().default(0), + col716: double('col71').primaryKey().autoincrement().default(0), + col718: double('col71').primaryKey().autoincrement().default(0), + col719: double('col71').primaryKey().autoincrement().default(0), + col720: double('col71').primaryKey().autoincrement().default(0), + col721: double('col71').primaryKey().autoincrement().default(0), + col722: double('col71').primaryKey().autoincrement().default(0), + col723: double('col71').primaryKey().autoincrement().default(0), + col724: double('col71').primaryKey().autoincrement().default(0), + col725: double('col71').primaryKey().autoincrement().default(0), + col726: double('col71').primaryKey().autoincrement().default(0), + col728: double('col71').primaryKey().autoincrement().default(0), + col729: double('col71').primaryKey().autoincrement().default(0), + col730: double('col71').primaryKey().autoincrement().default(0), + col731: double('col71').primaryKey().autoincrement().default(0), + col732: double('col71').primaryKey().autoincrement().default(0), + col733: double('col71').primaryKey().autoincrement().default(0), + col734: double('col71').primaryKey().autoincrement().default(0), + col735: double('col71').primaryKey().autoincrement().default(0), + col736: double('col71').primaryKey().autoincrement().default(0), + col738: double('col71').primaryKey().autoincrement().default(0), + col739: double('col71').primaryKey().autoincrement().default(0), + col740: double('col71').primaryKey().autoincrement().default(0), + col741: double('col71').primaryKey().autoincrement().default(0), + col742: double('col71').primaryKey().autoincrement().default(0), + col743: double('col71').primaryKey().autoincrement().default(0), + col744: double('col71').primaryKey().autoincrement().default(0), + col745: double('col71').primaryKey().autoincrement().default(0), + col746: double('col71').primaryKey().autoincrement().default(0), + col748: double('col71').primaryKey().autoincrement().default(0), + col749: double('col71').primaryKey().autoincrement().default(0), + col750: double('col71').primaryKey().autoincrement().default(0), + col751: double('col71').primaryKey().autoincrement().default(0), + col752: double('col71').primaryKey().autoincrement().default(0), + col753: double('col71').primaryKey().autoincrement().default(0), + col754: double('col71').primaryKey().autoincrement().default(0), + col755: double('col71').primaryKey().autoincrement().default(0), + col756: double('col71').primaryKey().autoincrement().default(0), + col758: double('col71').primaryKey().autoincrement().default(0), + col759: double('col71').primaryKey().autoincrement().default(0), + col760: double('col71').primaryKey().autoincrement().default(0), + col761: double('col71').primaryKey().autoincrement().default(0), + col762: double('col71').primaryKey().autoincrement().default(0), + col763: double('col71').primaryKey().autoincrement().default(0), + col764: double('col71').primaryKey().autoincrement().default(0), + col765: double('col71').primaryKey().autoincrement().default(0), + col766: double('col71').primaryKey().autoincrement().default(0), + col768: double('col71').primaryKey().autoincrement().default(0), + col769: double('col71').primaryKey().autoincrement().default(0), + col770: double('col71').primaryKey().autoincrement().default(0), + col771: double('col71').primaryKey().autoincrement().default(0), + col772: double('col71').primaryKey().autoincrement().default(0), + col773: double('col71').primaryKey().autoincrement().default(0), + col774: double('col71').primaryKey().autoincrement().default(0), + col775: double('col71').primaryKey().autoincrement().default(0), + col776: double('col71').primaryKey().autoincrement().default(0), + col778: double('col71').primaryKey().autoincrement().default(0), + col779: double('col71').primaryKey().autoincrement().default(0), + col780: double('col71').primaryKey().autoincrement().default(0), + col781: double('col71').primaryKey().autoincrement().default(0), + col782: double('col71').primaryKey().autoincrement().default(0), + col783: double('col71').primaryKey().autoincrement().default(0), + col784: double('col71').primaryKey().autoincrement().default(0), + col785: double('col71').primaryKey().autoincrement().default(0), + col786: double('col71').primaryKey().autoincrement().default(0), + col788: double('col71').primaryKey().autoincrement().default(0), + col789: double('col71').primaryKey().autoincrement().default(0), + col790: double('col71').primaryKey().autoincrement().default(0), + col791: double('col71').primaryKey().autoincrement().default(0), + col792: double('col71').primaryKey().autoincrement().default(0), + col793: double('col71').primaryKey().autoincrement().default(0), + col794: double('col71').primaryKey().autoincrement().default(0), + col795: double('col71').primaryKey().autoincrement().default(0), + col796: double('col71').primaryKey().autoincrement().default(0), + col798: double('col71').primaryKey().autoincrement().default(0), + col799: double('col71').primaryKey().autoincrement().default(0), + col800: double('col8').primaryKey().autoincrement().default(0), + col801: double('col8').primaryKey().autoincrement().default(0), + col802: double('col8').primaryKey().autoincrement().default(0), + col803: double('col8').primaryKey().autoincrement().default(0), + col804: double('col8').primaryKey().autoincrement().default(0), + col805: double('col8').primaryKey().autoincrement().default(0), + col806: double('col8').primaryKey().autoincrement().default(0), + col808: double('col8').primaryKey().autoincrement().default(0), + col809: double('col8').primaryKey().autoincrement().default(0), + col810: double('col81').primaryKey().autoincrement().default(0), + col811: double('col81').primaryKey().autoincrement().default(0), + col812: double('col81').primaryKey().autoincrement().default(0), + col813: double('col81').primaryKey().autoincrement().default(0), + col814: double('col81').primaryKey().autoincrement().default(0), + col815: double('col81').primaryKey().autoincrement().default(0), + col816: double('col81').primaryKey().autoincrement().default(0), + col818: double('col81').primaryKey().autoincrement().default(0), + col819: double('col81').primaryKey().autoincrement().default(0), + col820: double('col81').primaryKey().autoincrement().default(0), + col821: double('col81').primaryKey().autoincrement().default(0), + col822: double('col81').primaryKey().autoincrement().default(0), + col823: double('col81').primaryKey().autoincrement().default(0), + col824: double('col81').primaryKey().autoincrement().default(0), + col825: double('col81').primaryKey().autoincrement().default(0), + col826: double('col81').primaryKey().autoincrement().default(0), + col828: double('col81').primaryKey().autoincrement().default(0), + col829: double('col81').primaryKey().autoincrement().default(0), + col830: double('col81').primaryKey().autoincrement().default(0), + col831: double('col81').primaryKey().autoincrement().default(0), + col832: double('col81').primaryKey().autoincrement().default(0), + col833: double('col81').primaryKey().autoincrement().default(0), + col834: double('col81').primaryKey().autoincrement().default(0), + col835: double('col81').primaryKey().autoincrement().default(0), + col836: double('col81').primaryKey().autoincrement().default(0), + col838: double('col81').primaryKey().autoincrement().default(0), + col839: double('col81').primaryKey().autoincrement().default(0), + col840: double('col81').primaryKey().autoincrement().default(0), + col841: double('col81').primaryKey().autoincrement().default(0), + col842: double('col81').primaryKey().autoincrement().default(0), + col843: double('col81').primaryKey().autoincrement().default(0), + col844: double('col81').primaryKey().autoincrement().default(0), + col845: double('col81').primaryKey().autoincrement().default(0), + col846: double('col81').primaryKey().autoincrement().default(0), + col848: double('col81').primaryKey().autoincrement().default(0), + col849: double('col81').primaryKey().autoincrement().default(0), + col850: double('col81').primaryKey().autoincrement().default(0), + col851: double('col81').primaryKey().autoincrement().default(0), + col852: double('col81').primaryKey().autoincrement().default(0), + col853: double('col81').primaryKey().autoincrement().default(0), + col854: double('col81').primaryKey().autoincrement().default(0), + col855: double('col81').primaryKey().autoincrement().default(0), + col856: double('col81').primaryKey().autoincrement().default(0), + col858: double('col81').primaryKey().autoincrement().default(0), + col859: double('col81').primaryKey().autoincrement().default(0), + col860: double('col81').primaryKey().autoincrement().default(0), + col861: double('col81').primaryKey().autoincrement().default(0), + col862: double('col81').primaryKey().autoincrement().default(0), + col863: double('col81').primaryKey().autoincrement().default(0), + col864: double('col81').primaryKey().autoincrement().default(0), + col865: double('col81').primaryKey().autoincrement().default(0), + col866: double('col81').primaryKey().autoincrement().default(0), + col868: double('col81').primaryKey().autoincrement().default(0), + col869: double('col81').primaryKey().autoincrement().default(0), + col870: double('col81').primaryKey().autoincrement().default(0), + col871: double('col81').primaryKey().autoincrement().default(0), + col872: double('col81').primaryKey().autoincrement().default(0), + col873: double('col81').primaryKey().autoincrement().default(0), + col874: double('col81').primaryKey().autoincrement().default(0), + col875: double('col81').primaryKey().autoincrement().default(0), + col876: double('col81').primaryKey().autoincrement().default(0), + col878: double('col81').primaryKey().autoincrement().default(0), + col879: double('col81').primaryKey().autoincrement().default(0), + col880: double('col81').primaryKey().autoincrement().default(0), + col881: double('col81').primaryKey().autoincrement().default(0), + col882: double('col81').primaryKey().autoincrement().default(0), + col883: double('col81').primaryKey().autoincrement().default(0), + col884: double('col81').primaryKey().autoincrement().default(0), + col885: double('col81').primaryKey().autoincrement().default(0), + col886: double('col81').primaryKey().autoincrement().default(0), + col888: double('col81').primaryKey().autoincrement().default(0), + col889: double('col81').primaryKey().autoincrement().default(0), + col890: double('col81').primaryKey().autoincrement().default(0), + col891: double('col81').primaryKey().autoincrement().default(0), + col892: double('col81').primaryKey().autoincrement().default(0), + col893: double('col81').primaryKey().autoincrement().default(0), + col894: double('col81').primaryKey().autoincrement().default(0), + col895: double('col81').primaryKey().autoincrement().default(0), + col896: double('col81').primaryKey().autoincrement().default(0), + col898: double('col81').primaryKey().autoincrement().default(0), + col899: double('col81').primaryKey().autoincrement().default(0), + col900: double('col9').primaryKey().autoincrement().default(0), + col901: double('col9').primaryKey().autoincrement().default(0), + col902: double('col9').primaryKey().autoincrement().default(0), + col903: double('col9').primaryKey().autoincrement().default(0), + col904: double('col9').primaryKey().autoincrement().default(0), + col905: double('col9').primaryKey().autoincrement().default(0), + col906: double('col9').primaryKey().autoincrement().default(0), + col908: double('col9').primaryKey().autoincrement().default(0), + col909: double('col9').primaryKey().autoincrement().default(0), + col910: double('col91').primaryKey().autoincrement().default(0), + col911: double('col91').primaryKey().autoincrement().default(0), + col912: double('col91').primaryKey().autoincrement().default(0), + col913: double('col91').primaryKey().autoincrement().default(0), + col914: double('col91').primaryKey().autoincrement().default(0), + col915: double('col91').primaryKey().autoincrement().default(0), + col916: double('col91').primaryKey().autoincrement().default(0), + col918: double('col91').primaryKey().autoincrement().default(0), + col919: double('col91').primaryKey().autoincrement().default(0), + col920: double('col91').primaryKey().autoincrement().default(0), + col921: double('col91').primaryKey().autoincrement().default(0), + col922: double('col91').primaryKey().autoincrement().default(0), + col923: double('col91').primaryKey().autoincrement().default(0), + col924: double('col91').primaryKey().autoincrement().default(0), + col925: double('col91').primaryKey().autoincrement().default(0), + col926: double('col91').primaryKey().autoincrement().default(0), + col928: double('col91').primaryKey().autoincrement().default(0), + col929: double('col91').primaryKey().autoincrement().default(0), + col930: double('col91').primaryKey().autoincrement().default(0), + col931: double('col91').primaryKey().autoincrement().default(0), + col932: double('col91').primaryKey().autoincrement().default(0), + col933: double('col91').primaryKey().autoincrement().default(0), + col934: double('col91').primaryKey().autoincrement().default(0), + col935: double('col91').primaryKey().autoincrement().default(0), + col936: double('col91').primaryKey().autoincrement().default(0), + col938: double('col91').primaryKey().autoincrement().default(0), + col939: double('col91').primaryKey().autoincrement().default(0), + col940: double('col91').primaryKey().autoincrement().default(0), + col941: double('col91').primaryKey().autoincrement().default(0), + col942: double('col91').primaryKey().autoincrement().default(0), + col943: double('col91').primaryKey().autoincrement().default(0), + col944: varchar('col91', { length: 200 }).primaryKey().default('0'), + col945: varchar('col91', { length: 200 }).primaryKey().default('0'), + col946: varchar('col91', { length: 200 }).primaryKey().default('0'), + col948: varchar('col91', { length: 200 }).primaryKey().default('0'), + col949: varchar('col91', { length: 200 }).primaryKey().default('0'), + col950: varchar('col91', { length: 200 }).primaryKey().default('0'), + col951: varchar('col91', { length: 200 }).primaryKey().default('0'), + col952: varchar('col91', { length: 200 }).primaryKey().default('0'), + col953: varchar('col91', { length: 200 }).primaryKey().default('0'), + col954: varchar('col91', { length: 200 }).primaryKey().default('0'), + col955: varchar('col91', { length: 200 }).primaryKey().default('0'), + col956: varchar('col91', { length: 200 }).primaryKey().default('0'), + col958: varchar('col91', { length: 200 }).primaryKey().default('0'), + col959: varchar('col91', { length: 200 }).primaryKey().default('0'), + col960: varchar('col91', { length: 200 }).primaryKey().default('0'), + col961: varchar('col91', { length: 200 }).primaryKey().default('0'), + col962: varchar('col91', { length: 200 }).primaryKey().default('0'), + col963: varchar('col91', { length: 200 }).primaryKey().default('0'), + col964: varchar('col91', { length: 200 }).primaryKey().default('0'), + col965: varchar('col91', { length: 200 }).primaryKey().default('0'), + col966: varchar('col91', { length: 200 }).primaryKey().default('0'), + col968: varchar('col91', { length: 200 }).primaryKey().default('0'), + col969: varchar('col91', { length: 200 }).primaryKey().default('0'), + col970: varchar('col91', { length: 200 }).primaryKey().default('0'), + col971: varchar('col91', { length: 200 }).primaryKey().default('0'), + col972: varchar('col91', { length: 200 }).primaryKey().default('0'), + col973: varchar('col91', { length: 200 }).primaryKey().default('0'), + col974: varchar('col91', { length: 200 }).primaryKey().default('0'), + col975: varchar('col91', { length: 200 }).primaryKey().default('0'), + col976: varchar('col91', { length: 200 }).primaryKey().default('0'), + col978: varchar('col91', { length: 200 }).primaryKey().default('0'), + col979: varchar('col91', { length: 200 }).primaryKey().default('0'), + col980: varchar('col91', { length: 200 }).primaryKey().default('0'), + col981: varchar('col91', { length: 200 }).primaryKey().default('0'), + col982: varchar('col91', { length: 200 }).primaryKey().default('0'), + col983: varchar('col91', { length: 200 }).primaryKey().default('0'), + col984: varchar('col91', { length: 200 }).primaryKey().default('0'), + col985: varchar('col91', { length: 200 }).primaryKey().default('0'), + col986: varchar('col91', { length: 200 }).primaryKey().default('0'), + col988: varchar('col91', { length: 200 }).primaryKey().default('0'), + col989: varchar('col91', { length: 200 }).primaryKey().default('0'), + col990: varchar('col91', { length: 200 }).primaryKey().default('0'), + col991: varchar('col91', { length: 200 }).primaryKey().default('0'), + col992: varchar('col91', { length: 200 }).primaryKey().default('0'), + col993: varchar('col91', { length: 200 }).primaryKey().default('0'), + col994: varchar('col91', { length: 200 }).primaryKey().default('0'), + col995: varchar('col91', { length: 200 }).primaryKey().default('0'), + col996: varchar('col91', { length: 200 }).primaryKey().default('0'), + col998: varchar('col91', { length: 200 }).primaryKey().default('0'), + col999: varchar('col91', { length: 200 }).primaryKey().default('0'), +}); diff --git a/drizzle-orm/type-tests/singlestore/count.ts b/drizzle-orm/type-tests/singlestore/count.ts new file mode 100644 index 000000000..50abc8c3a --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/count.ts @@ -0,0 +1,61 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, gt, ne } from '~/expressions.ts'; +import { int, serial, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import type { Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = singlestoreTable('names', { + id: serial('id').primaryKey(), + name: text('name'), + authorId: int('author_id'), +}); + +const separate = await db.$count(names); + +const separateFilters = await db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))); + +const embedded = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names).as('count1'), + }) + .from(names); + +const embeddedFilters = await db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: db.$count(names, and(gt(names.id, 1), ne(names.name, 'forbidden'))).as('count1'), + }) + .from(names); + +Expect>; + +Expect>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embedded + > +>; + +Expect< + Equal< + { + id: number; + name: string | null; + authorId: number | null; + count1: number; + }[], + typeof embeddedFilters + > +>; diff --git a/drizzle-orm/type-tests/singlestore/db.ts b/drizzle-orm/type-tests/singlestore/db.ts new file mode 100644 index 000000000..b314e504d --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/db.ts @@ -0,0 +1,13 @@ +import { createPool } from 'mysql2/promise'; +import { drizzle } from '~/singlestore/index.ts'; + +const pool = createPool({}); + +export const db = drizzle(pool); + +{ + drizzle(pool); + drizzle(pool, { schema: {} }); + drizzle(pool, { schema: {} }); + drizzle(pool, {}); +} diff --git a/drizzle-orm/type-tests/singlestore/delete.ts b/drizzle-orm/type-tests/singlestore/delete.ts new file mode 100644 index 000000000..db58ac2ec --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/delete.ts @@ -0,0 +1,65 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { eq } from '~/expressions.ts'; +import type { SingleStoreDelete } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +const deleteAll = await db.delete(users); +Expect>; + +const deleteAllStmt = db.delete(users).prepare(); +const deleteAllPrepared = await deleteAllStmt.execute(); +Expect>; + +const deleteWhere = await db.delete(users).where(eq(users.id, 1)); +Expect>; + +const deleteWhereStmt = db.delete(users).where(eq(users.id, 1)).prepare(); +const deleteWherePrepared = await deleteWhereStmt.execute(); +Expect>; + +const deleteReturningAll = await db.delete(users); +Expect>; + +const deleteReturningAllStmt = db.delete(users).prepare(); +const deleteReturningAllPrepared = await deleteReturningAllStmt.execute(); +Expect>; + +const deleteReturningPartial = await db.delete(users); +Expect>; + +const deleteReturningPartialStmt = db.delete(users).prepare(); +const deleteReturningPartialPrepared = await deleteReturningPartialStmt.execute(); +Expect>; + +{ + function dynamic(qb: T) { + return qb.where(sql``); + } + + const qbBase = db.delete(users).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .delete(users) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); + + db + .delete(users) + .$dynamic() + .where(sql``) + .where(sql``); +} + +{ + db.delete(users).where(sql``).limit(1).orderBy(sql``); +} diff --git a/drizzle-orm/type-tests/singlestore/insert.ts b/drizzle-orm/type-tests/singlestore/insert.ts new file mode 100644 index 000000000..738bf669d --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/insert.ts @@ -0,0 +1,135 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { int, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import type { SingleStoreInsert } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +const singlestoreInsertReturning = await db.insert(users).values({ + // ^? + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).$returningId(); + +Expect>; + +const insert = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertPrepared = await insertStmt.execute(); +Expect>; + +const insertSql = await db.insert(users).values({ + homeCity: sql`123`, + class: 'A', + age1: 1, + enumCol: sql`foobar`, +}); +Expect>; + +const insertSqlStmt = db.insert(users).values({ + homeCity: sql`123`, + class: 'A', + age1: 1, + enumCol: sql`foobar`, +}).prepare(); +const insertSqlPrepared = await insertSqlStmt.execute(); +Expect>; + +const insertReturning = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertReturningStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertReturningPrepared = await insertReturningStmt.execute(); +Expect>; + +const insertReturningPartial = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}); +Expect>; + +const insertReturningPartialStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: 1, + enumCol: 'a', +}).prepare(); +const insertReturningPartialPrepared = await insertReturningPartialStmt.execute(); +Expect>; + +const insertReturningSql = await db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: sql`2 + 2`, + enumCol: 'a', +}); +Expect>; + +const insertReturningSqlStmt = db.insert(users).values({ + homeCity: 1, + class: 'A', + age1: sql`2 + 2`, + enumCol: 'a', +}).prepare(); +const insertReturningSqlPrepared = await insertReturningSqlStmt.execute(); +Expect>; + +{ + const users = singlestoreTable('users', { + id: int('id').autoincrement().primaryKey(), + name: text('name').notNull(), + age: int('age'), + occupation: text('occupation'), + }); + + await db.insert(users).values({ name: 'John Wick', age: 58, occupation: 'housekeeper' }); +} + +{ + function dynamic(qb: T) { + return qb.onDuplicateKeyUpdate({ set: {} }); + } + + const qbBase = db.insert(users).values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0 }).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + + Expect>; +} + +{ + db + .insert(users) + .values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0 }) + .onDuplicateKeyUpdate({ set: {} }) + // @ts-expect-error method was already called + .onDuplicateKeyUpdate({ set: {} }); +} diff --git a/drizzle-orm/type-tests/singlestore/select.ts b/drizzle-orm/type-tests/singlestore/select.ts new file mode 100644 index 000000000..f7a5094ea --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/select.ts @@ -0,0 +1,607 @@ +import { + and, + between, + eq, + exists, + gt, + gte, + ilike, + inArray, + isNotNull, + isNull, + like, + lt, + lte, + ne, + not, + notBetween, + notExists, + notIlike, + notInArray, + notLike, + or, +} from '~/expressions.ts'; +import { alias } from '~/singlestore-core/alias.ts'; +import { param, sql } from '~/sql/sql.ts'; + +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { QueryBuilder, type SingleStoreSelect, type SingleStoreSelectQueryBuilder } from '~/singlestore-core/index.ts'; +import { db } from './db.ts'; +import { cities, classes, users } from './tables.ts'; + +const city = alias(cities, 'city'); +const city1 = alias(cities, 'city1'); + +const join = await db + .select({ + users, + cities, + city, + city1: { + id: city1.id, + }, + }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)) + .rightJoin(city, eq(city.id, users.id)) + .rightJoin(city1, eq(city1.id, users.id)); + +Expect< + Equal< + { + users: { + id: number; + text: string | null; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + } | null; + cities: { + id: number; + name: string; + population: number | null; + } | null; + city: { + id: number; + name: string; + population: number | null; + } | null; + city1: { + id: number; + }; + }[], + typeof join + > +>; + +const join2 = await db + .select({ + userId: users.id, + cityId: cities.id, + }) + .from(users) + .fullJoin(cities, eq(users.id, cities.id)); + +Expect< + Equal< + { + userId: number | null; + cityId: number | null; + }[], + typeof join2 + > +>; + +const join3 = await db + .select({ + userId: users.id, + cityId: cities.id, + classId: classes.id, + }) + .from(users) + .fullJoin(cities, eq(users.id, cities.id)) + .rightJoin(classes, eq(users.id, classes.id)); + +Expect< + Equal< + { + userId: number | null; + cityId: number | null; + classId: number; + }[], + typeof join3 + > +>; + +db + .select() + .from(users) + .where(exists(db.select().from(cities).where(eq(users.homeCity, cities.id)))); + +function mapFunkyFuncResult(valueFromDriver: unknown) { + return { + foo: (valueFromDriver as Record)['foo'], + }; +} + +const age = 1; + +const allOperators = await db + .select({ + col2: sql`5 - ${users.id} + 1`, // unknown + col3: sql`${users.id} + 1`, // number + col33: sql`${users.id} + 1`.mapWith(users.id), // number + col34: sql`${users.id} + 1`.mapWith(mapFunkyFuncResult), // number + col4: sql`one_or_another(${users.id}, ${users.class})`, // string | number + col5: sql`true`, // unknown + col6: sql`true`, // boolean + col7: sql`random()`, // number + col8: sql`some_funky_func(${users.id})`.mapWith(mapFunkyFuncResult), // { foo: string } + col9: sql`greatest(${users.createdAt}, ${param(new Date(), users.createdAt)})`, // unknown + col10: sql`date_or_false(${users.createdAt}, ${param(new Date(), users.createdAt)})`, // Date | boolean + col11: sql`${users.age1} + ${age}`, // unknown + col12: sql`${users.age1} + ${param(age, users.age1)}`, // unknown + col13: sql`lower(${users.class})`, // unknown + col14: sql`length(${users.class})`, // number + count: sql`count(*)::int`, // number + }) + .from(users) + .where(and( + eq(users.id, 1), + ne(users.id, 1), + or(eq(users.id, 1), ne(users.id, 1)), + not(eq(users.id, 1)), + gt(users.id, 1), + gte(users.id, 1), + lt(users.id, 1), + lte(users.id, 1), + inArray(users.id, [1, 2, 3]), + inArray(users.id, db.select({ id: users.id }).from(users)), + inArray(users.id, sql`select id from ${users}`), + notInArray(users.id, [1, 2, 3]), + notInArray(users.id, db.select({ id: users.id }).from(users)), + notInArray(users.id, sql`select id from ${users}`), + isNull(users.subClass), + isNotNull(users.id), + exists(db.select({ id: users.id }).from(users)), + exists(sql`select id from ${users}`), + notExists(db.select({ id: users.id }).from(users)), + notExists(sql`select id from ${users}`), + between(users.id, 1, 2), + notBetween(users.id, 1, 2), + like(users.id, '%1%'), + notLike(users.id, '%1%'), + ilike(users.id, '%1%'), + notIlike(users.id, '%1%'), + )); + +Expect< + Equal<{ + col2: unknown; + col3: number; + col33: number; + col34: { foo: any }; + col4: string | number; + col5: unknown; + col6: boolean; + col7: number; + col8: { + foo: any; + }; + col9: unknown; + col10: boolean | Date; + col11: unknown; + col12: unknown; + col13: unknown; + col14: number; + count: number; + }[], typeof allOperators> +>; + +const textSelect = await db + .select({ + t: users.text, + }) + .from(users); + +Expect>; + +const homeCity = alias(cities, 'homeCity'); +const c = alias(classes, 'c'); +const otherClass = alias(classes, 'otherClass'); +const anotherClass = alias(classes, 'anotherClass'); +const friend = alias(users, 'friend'); +const currentCity = alias(cities, 'currentCity'); +const subscriber = alias(users, 'subscriber'); +const closestCity = alias(cities, 'closestCity'); + +const megaJoin = await db + .select({ + user: { + id: users.id, + maxAge: sql`max(${users.age1})`, + }, + city: { + id: cities.id, + }, + homeCity, + c, + otherClass, + anotherClass, + friend, + currentCity, + subscriber, + closestCity, + }) + .from(users) + .innerJoin(cities, sql`${users.id} = ${cities.id}`) + .innerJoin(homeCity, sql`${users.homeCity} = ${homeCity.id}`) + .innerJoin(c, eq(c.id, users.class)) + .innerJoin(otherClass, sql`${c.id} = ${otherClass.id}`) + .innerJoin(anotherClass, sql`${users.class} = ${anotherClass.id}`) + .innerJoin(friend, sql`${users.id} = ${friend.id}`) + .innerJoin(currentCity, sql`${homeCity.id} = ${currentCity.id}`) + .innerJoin(subscriber, sql`${users.class} = ${subscriber.id}`) + .innerJoin(closestCity, sql`${users.currentCity} = ${closestCity.id}`) + .where(and(sql`${users.age1} > 0`, eq(cities.id, 1))) + .limit(1) + .offset(1); + +Expect< + Equal< + { + user: { + id: number; + maxAge: unknown; + }; + city: { + id: number; + }; + homeCity: { + id: number; + name: string; + population: number | null; + }; + c: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + otherClass: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + anotherClass: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + friend: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + currentCity: { + id: number; + name: string; + population: number | null; + }; + subscriber: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + closestCity: { + id: number; + name: string; + population: number | null; + }; + }[], + typeof megaJoin + > +>; + +const friends = alias(users, 'friends'); + +const join4 = await db + .select({ + user: { + id: users.id, + }, + city: { + id: cities.id, + }, + class: classes, + friend: friends, + }) + .from(users) + .innerJoin(cities, sql`${users.id} = ${cities.id}`) + .innerJoin(classes, sql`${cities.id} = ${classes.id}`) + .innerJoin(friends, sql`${friends.id} = ${users.id}`) + .where(sql`${users.age1} > 0`); + +Expect< + Equal<{ + user: { + id: number; + }; + city: { + id: number; + }; + class: { + id: number; + class: 'A' | 'C' | null; + subClass: 'B' | 'D'; + }; + friend: { + id: number; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }; + }[], typeof join4> +>; + +{ + const authenticated = false as boolean; + + const result = await db + .select({ + id: users.id, + ...(authenticated ? { city: users.homeCity } : {}), + }) + .from(users); + + Expect< + Equal< + { + id: number; + city?: number; + }[], + typeof result + > + >; +} + +await db.select().from(users).for('update'); +await db.select().from(users).for('share', { skipLocked: true }); +await db.select().from(users).for('update', { noWait: true }); +// TODO Implement views for SingleStore (https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-view/) +/* await db + .select() + .from(users) + // @ts-expect-error - can't use both skipLocked and noWait + .for('share', { noWait: true, skipLocked: true }); + +{ + const result = await db.select().from(newYorkers); + Expect< + Equal< + { + userId: number; + cityId: number | null; + }[], + typeof result + > + >; +} + +{ + const result = await db.select({ userId: newYorkers.userId }).from(newYorkers); + Expect< + Equal< + { + userId: number; + }[], + typeof result + > + >; +} */ + +{ + const query = db.select().from(users).prepare().iterator(); + for await (const row of query) { + Expect>(); + } +} + +{ + db + .select() + .from(users) + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + .limit(10) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const qb = db.select().from(users).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +{ + // TODO: add to docs + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const query = new QueryBuilder().select().from(users).$dynamic(); + dynamic(query); +} + +{ + // TODO: add to docs + function paginated(qb: T, page: number) { + return qb.limit(10).offset((page - 1) * 10); + } + + const qb = db.select().from(users).$dynamic(); + const result = await paginated(qb, 1); + + Expect>; +} + +{ + db + .select() + .from(users) + .where(sql``) + .limit(10) + // @ts-expect-error method was already called + .where(sql``); + + db + .select() + .from(users) + .having(sql``) + .limit(10) + // @ts-expect-error method was already called + .having(sql``); + + db + .select() + .from(users) + .groupBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .groupBy(sql``); + + db + .select() + .from(users) + .orderBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .orderBy(sql``); + + db + .select() + .from(users) + .limit(10) + .where(sql``) + // @ts-expect-error method was already called + .limit(10); + + db + .select() + .from(users) + .offset(10) + .limit(10) + // @ts-expect-error method was already called + .offset(10); + + db + .select() + .from(users) + .for('update') + .limit(10) + // @ts-expect-error method was already called + .for('update'); +} diff --git a/drizzle-orm/type-tests/singlestore/set-operators.ts b/drizzle-orm/type-tests/singlestore/set-operators.ts new file mode 100644 index 000000000..1db4bb7f1 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/set-operators.ts @@ -0,0 +1,235 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import { eq } from '~/expressions.ts'; +import { intersect, type SingleStoreSetOperator, union, unionAll } from '~/singlestore-core/index.ts'; +import { sql } from '~/sql/index.ts'; +import { db } from './db.ts'; +import { cities, classes, users } from './tables.ts'; + +const unionTest = await db + .select({ id: users.id }) + .from(users) + .union( + db + .select({ id: users.id }) + .from(users), + ); + +Expect>; + +const unionAllTest = await db + .select({ id: users.id, age: users.age1 }) + .from(users) + .unionAll( + db.select({ id: users.id, age: users.age1 }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)), + ); + +Expect>; + +const intersectTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .intersect(({ intersect }) => + intersect( + db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users), + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ) + ); + +Expect>; + +const exceptTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .except( + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ); + +Expect>; + +const minusTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .minus( + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ); + +Expect>; + +const union2Test = await union(db.select().from(cities), db.select().from(cities), db.select().from(cities)); + +Expect>; + +const unionAll2Test = await unionAll( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select().from(cities), +); + +Expect>; + +const intersect2Test = await intersect( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), +); + +Expect>; + +// TODO Implement views for SingleStore (https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-view/) +/* const except2Test = await except( + db.select({ + userId: newYorkers.userId, + }) + .from(newYorkers), + db.select({ + userId: newYorkers.userId, + }).from(newYorkers), +); + +Expect>; */ + +const unionfull = await union(db.select().from(users), db.select().from(users)).orderBy(sql``).limit(1).offset(2); + +Expect< + Equal<{ + id: number; + text: string | null; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }[], typeof unionfull> +>; + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +union(db.select().from(users), db.select().from(users)) + .offset(1) + // @ts-expect-error - method was already called + .offset(2); + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +{ + function dynamic(qb: T) { + return qb.orderBy(sql``).limit(1).offset(2); + } + + const qb = union(db.select().from(users), db.select().from(users)).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + .intersect(({ intersect }) => intersect(db.select().from(users), db.select().from(users))); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select().from(classes).union(db.select({ id: classes.id }).from(classes)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes).where(sql``)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes)); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + db.select({ id: cities.id, name: cities.name }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select().from(cities), +); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities), + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``).limit(3).$dynamic(), + db.select({ id: cities.id, name: cities.name }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + /* db.select({ id: newYorkers.userId }).from(newYorkers), */ + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities).where(sql``), + db.select({ id: sql`${cities.id}` }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities).where(sql``), +); diff --git a/drizzle-orm/type-tests/singlestore/subquery.ts b/drizzle-orm/type-tests/singlestore/subquery.ts new file mode 100644 index 000000000..e8ee4e80b --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/subquery.ts @@ -0,0 +1,97 @@ +import { Expect } from 'type-tests/utils.ts'; +import { and, eq } from '~/expressions.ts'; +import { alias, int, serial, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import { sql } from '~/sql/sql.ts'; +import type { DrizzleTypeError, Equal } from '~/utils.ts'; +import { db } from './db.ts'; + +const names = singlestoreTable('names', { + id: serial('id').primaryKey(), + name: text('name'), + authorId: int('author_id'), +}); + +const n1 = db + .select({ + id: names.id, + name: names.name, + authorId: names.authorId, + count1: sql`count(1)::int`.as('count1'), + }) + .from(names) + .groupBy(names.id, names.name, names.authorId) + .as('n1'); + +const n2 = db + .select({ + id: names.id, + authorId: names.authorId, + totalCount: sql`count(1)::int`.as('totalCount'), + }) + .from(names) + .groupBy(names.id, names.authorId) + .as('n2'); + +const result = await db + .select({ + name: n1.name, + authorId: n1.authorId, + count1: n1.count1, + totalCount: n2.totalCount, + }) + .from(n1) + .innerJoin(n2, and(eq(n2.id, n1.id), eq(n2.authorId, n1.authorId))); + +Expect< + Equal< + { + name: string | null; + authorId: number | null; + count1: number; + totalCount: number; + }[], + typeof result + > +>; + +const names2 = alias(names, 'names2'); + +const sq1 = db + .select({ + id: names.id, + name: names.name, + id2: names2.id, + }) + .from(names) + .leftJoin(names2, eq(names.name, names2.name)) + .as('sq1'); + +const res = await db.select().from(sq1); + +Expect< + Equal< + { + id: number; + name: string | null; + id2: number | null; + }[], + typeof res + > +>; + +{ + const sq = db.select({ count: sql`count(1)::int` }).from(names).as('sq'); + Expect ? true : false>; +} + +const sqUnion = db.select().from(names).union(db.select().from(names2)).as('sqUnion'); + +const resUnion = await db.select().from(sqUnion); + +Expect< + Equal<{ + id: number; + name: string | null; + authorId: number | null; + }[], typeof resUnion> +>; diff --git a/drizzle-orm/type-tests/singlestore/tables.ts b/drizzle-orm/type-tests/singlestore/tables.ts new file mode 100644 index 000000000..43a1b05dc --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/tables.ts @@ -0,0 +1,1009 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import type { BuildColumn } from '~/column-builder.ts'; +import { eq } from '~/expressions.ts'; +import { + bigint, + binary, + boolean, + char, + customType, + date, + datetime, + decimal, + double, + float, + index, + int, + json, + longtext, + mediumint, + mediumtext, + primaryKey, + real, + serial, + type SingleStoreColumn, + singlestoreEnum, + singlestoreTable, + smallint, + text, + time, + timestamp, + tinyint, + tinytext, + unique, + uniqueIndex, + varbinary, + varchar, + year, +} from '~/singlestore-core/index.ts'; +import { singlestoreSchema } from '~/singlestore-core/schema.ts'; +/* import { singlestoreView, type SingleStoreViewWithSelection } from '~/singlestore-core/view.ts'; */ +import type { InferSelectModel } from '~/table.ts'; +import type { Simplify } from '~/utils.ts'; +import { db } from './db.ts'; + +export const users = singlestoreTable( + 'users_table', + { + id: serial('id').primaryKey(), + homeCity: int('home_city') + .notNull(), + currentCity: int('current_city'), + serialNullable: serial('serial1'), + serialNotNull: serial('serial2').notNull(), + class: text('class', { enum: ['A', 'C'] }).notNull(), + subClass: text('sub_class', { enum: ['B', 'D'] }), + text: text('text'), + age1: int('age1').notNull(), + createdAt: timestamp('created_at', { mode: 'date' }).notNull().defaultNow(), + enumCol: singlestoreEnum('enum_col', ['a', 'b', 'c']).notNull(), + }, + (users) => ({ + usersAge1Idx: uniqueIndex('usersAge1Idx').on(users.class), + usersAge2Idx: index('usersAge2Idx').on(users.class), + uniqueClass: uniqueIndex('uniqueClass') + .on(users.class, users.subClass) + .lock('default') + .algorythm('copy') + .using(`btree`), + pk: primaryKey(users.age1, users.class), + }), +); + +export const cities = singlestoreTable('cities_table', { + id: serial('id').primaryKey(), + name: text('name_db').notNull(), + population: int('population').default(0), +}, (cities) => ({ + citiesNameIdx: index('citiesNameIdx').on(cities.id), +})); + +Expect< + Equal< + { + id: SingleStoreColumn<{ + name: 'id'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + enumValues: undefined; + baseColumn: never; + identity: undefined; + generated: undefined; + }, object>; + name: SingleStoreColumn<{ + name: 'name_db'; + tableName: 'cities_table'; + dataType: 'string'; + columnType: 'SingleStoreText'; + data: string; + driverParam: string; + notNull: true; + hasDefault: false; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + enumValues: [string, ...string[]]; + baseColumn: never; + identity: undefined; + generated: undefined; + }, object>; + population: SingleStoreColumn<{ + name: 'population'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + notNull: false; + hasDefault: true; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + enumValues: undefined; + baseColumn: never; + identity: undefined; + generated: undefined; + }, object>; + }, + typeof cities._.columns + > +>; + +Expect< + Equal<{ + id: number; + name_db: string; + population: number | null; + }, InferSelectModel> +>; + +Expect< + Equal<{ + id?: number; + name: string; + population?: number | null; + }, typeof cities.$inferInsert> +>; + +export const customSchema = singlestoreSchema('custom_schema'); + +export const citiesCustom = customSchema.table('cities_table', { + id: serial('id').primaryKey(), + name: text('name_db').notNull(), + population: int('population').default(0), +}, (cities) => ({ + citiesNameIdx: index('citiesNameIdx').on(cities.id), +})); + +Expect>; + +export const classes = singlestoreTable('classes_table', ({ serial, text }) => ({ + id: serial('id').primaryKey(), + class: text('class', { enum: ['A', 'C'] }), + subClass: text('sub_class', { enum: ['B', 'D'] }).notNull(), +})); + +// TODO Implement views for SingleStore (https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-view/) +/* export const classes2 = singlestoreTable('classes_table', { + id: serial().primaryKey(), + class: text({ enum: ['A', 'C'] }).$dbName('class_db'), + subClass: text({ enum: ['B', 'D'] }).notNull(), +}); */ + +/* export const newYorkers = singlestoreView('new_yorkers') + .algorithm('merge') + .sqlSecurity('definer') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + +Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: false; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > +>; + +{ + const newYorkers = customSchema.view('new_yorkers') + .algorithm('merge') + .sqlSecurity('definer') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'id'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: false; + hasDefault: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = singlestoreView('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }) + .algorithm('merge') + .sqlSecurity('definer') + .as( + sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ + eq(cities.id, users.homeCity) + } where ${gt(users.age1, 18)}`, + ); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = customSchema.view('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }) + .algorithm('merge') + .sqlSecurity('definer') + .as( + sql`select ${users.id} as user_id, ${cities.id} as city_id from ${users} left join ${cities} on ${ + eq(cities.id, users.homeCity) + } where ${gt(users.age1, 18)}`, + ); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', false, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = singlestoreView('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }).existing(); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', true, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} + +{ + const newYorkers = customSchema.view('new_yorkers', { + userId: int('user_id').notNull(), + cityId: int('city_id'), + }).existing(); + + Expect< + Equal< + SingleStoreViewWithSelection<'new_yorkers', true, { + userId: SingleStoreColumn<{ + name: 'user_id'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + hasDefault: false; + notNull: true; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + cityId: SingleStoreColumn<{ + name: 'city_id'; + notNull: false; + hasDefault: false; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + tableName: 'new_yorkers'; + enumValues: undefined; + baseColumn: never; + generated: undefined; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + }>; + }>, + typeof newYorkers + > + >; +} */ + +{ + const customText = customType<{ data: string }>({ + dataType() { + return 'text'; + }, + }); + + const t = customText('name').notNull(); + Expect< + Equal< + { + name: 'name'; + tableName: 'table'; + dataType: 'custom'; + columnType: 'SingleStoreCustomColumn'; + data: string; + driverParam: unknown; + notNull: true; + hasDefault: false; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + enumValues: undefined; + baseColumn: never; + identity: undefined; + generated: undefined; + brand: 'Column'; + dialect: 'singlestore'; + }, + Simplify['_']> + > + >; +} + +{ + singlestoreTable('test', { + bigint: bigint('bigint', { mode: 'bigint' }), + number: bigint('number', { mode: 'number' }), + date: date('date').default(new Date()), + date2: date('date2', { mode: 'date' }).default(new Date()), + date3: date('date3', { mode: 'string' }).default('2020-01-01'), + date4: date('date4', { mode: undefined }).default(new Date()), + datetime: datetime('datetime').default(new Date()), + datetime2: datetime('datetime2', { mode: 'date' }).default(new Date()), + datetime3: datetime('datetime3', { mode: 'string' }).default('2020-01-01'), + datetime4: datetime('datetime4', { mode: undefined }).default(new Date()), + timestamp: timestamp('timestamp').default(new Date()), + timestamp2: timestamp('timestamp2', { mode: 'date' }).default(new Date()), + timestamp3: timestamp('timestamp3', { mode: 'string' }).default('2020-01-01'), + timestamp4: timestamp('timestamp4', { mode: undefined }).default(new Date()), + }); +} + +{ + singlestoreTable('test', { + col1: decimal('col1').default('1'), + }); +} + +{ + const test = singlestoreTable('test', { + test1: singlestoreEnum('test', ['a', 'b', 'c'] as const).notNull(), + test2: singlestoreEnum('test', ['a', 'b', 'c']).notNull(), + test3: varchar('test', { length: 255, enum: ['a', 'b', 'c'] as const }).notNull(), + test4: varchar('test', { length: 255, enum: ['a', 'b', 'c'] }).notNull(), + test5: text('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test6: text('test', { enum: ['a', 'b', 'c'] }).notNull(), + test7: tinytext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test8: tinytext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test9: mediumtext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test10: mediumtext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test11: longtext('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test12: longtext('test', { enum: ['a', 'b', 'c'] }).notNull(), + test13: char('test', { enum: ['a', 'b', 'c'] as const }).notNull(), + test14: char('test', { enum: ['a', 'b', 'c'] }).notNull(), + test15: text('test').notNull(), + }); + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; +} + +/* { // All types with generated columns + const test = singlestoreTable('test', { + test1: singlestoreEnum('test', ['a', 'b', 'c'] as const).generatedAlwaysAs(sql``), + test2: singlestoreEnum('test', ['a', 'b', 'c']).generatedAlwaysAs(sql``), + test3: varchar('test', { length: 255, enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test4: varchar('test', { length: 255, enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test5: text('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test6: text('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test7: tinytext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test8: tinytext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test9: mediumtext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test10: mediumtext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test11: longtext('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test12: longtext('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test13: char('test', { enum: ['a', 'b', 'c'] as const }).generatedAlwaysAs(sql``), + test14: char('test', { enum: ['a', 'b', 'c'] }).generatedAlwaysAs(sql``), + test15: text('test').generatedAlwaysAs(sql``), + }); + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; + Expect>; +} */ + +{ + const getUsersTable = (schemaName: TSchema) => { + return singlestoreSchema(schemaName).table('users', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }); + }; + + const users1 = getUsersTable('id1'); + Expect>; + + const users2 = getUsersTable('id2'); + Expect>; +} + +{ + const internalStaff = singlestoreTable('internal_staff', { + userId: int('user_id').notNull(), + }); + + const customUser = singlestoreTable('custom_user', { + id: int('id').notNull(), + }); + + const ticket = singlestoreTable('ticket', { + staffId: int('staff_id').notNull(), + }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin( + customUser, + eq(internalStaff.userId, customUser.id), + ).as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + Expect< + Equal<{ + internal_staff: { + internal_staff: { + userId: number; + }; + custom_user: { + id: number | null; + }; + } | null; + ticket: { + staffId: number; + }; + }[], typeof mainQuery> + >; +} + +// TODO Implement views for SingleStore (https://docs.singlestore.com/cloud/reference/sql-reference/data-definition-language-ddl/create-view/) +/* { + const newYorkers = singlestoreView('new_yorkers') + .as((qb) => { + const sq = qb + .$with('sq') + .as( + qb.select({ userId: users.id, cityId: cities.id }) + .from(users) + .leftJoin(cities, eq(cities.id, users.homeCity)) + .where(sql`${users.age1} > 18`), + ); + return qb.with(sq).select().from(sq).where(sql`${users.homeCity} = 1`); + }); + + await db.select().from(newYorkers).leftJoin(newYorkers, eq(newYorkers.userId, newYorkers.userId)); +} */ + +{ + const test = singlestoreTable('test', { + id: text('id').$defaultFn(() => crypto.randomUUID()).primaryKey(), + }); + + Expect< + Equal<{ + id?: string; + }, typeof test.$inferInsert> + >; +} + +{ + singlestoreTable('test', { + id: int('id').$default(() => 1), + id2: int('id').$defaultFn(() => 1), + // @ts-expect-error - should be number + id3: int('id').$default(() => '1'), + // @ts-expect-error - should be number + id4: int('id').$defaultFn(() => '1'), + }); +} +{ + const emailLog = singlestoreTable( + 'email_log', + { + id: int('id', { unsigned: true }).autoincrement().notNull(), + clientId: int('id_client', { unsigned: true }), + receiverEmail: varchar('receiver_email', { length: 255 }).notNull(), + messageId: varchar('message_id', { length: 255 }), + contextId: int('context_id', { unsigned: true }), + contextType: singlestoreEnum('context_type', ['test']).$type<['test']>(), + action: varchar('action', { length: 80 }).$type<['test']>(), + events: json('events').$type<{ t: 'test' }[]>(), + createdAt: timestamp('created_at', { mode: 'string' }).defaultNow().notNull(), + updatedAt: timestamp('updated_at', { mode: 'string' }).defaultNow().onUpdateNow(), + }, + (table) => { + return { + emailLogId: primaryKey({ columns: [table.id], name: 'email_log_id' }), + emailLogMessageIdUnique: unique('email_log_message_id_unique').on(table.messageId), + }; + }, + ); + + Expect< + Equal<{ + receiverEmail: string; + id?: number | undefined; + createdAt?: string | undefined; + clientId?: number | null | undefined; + messageId?: string | null | undefined; + contextId?: number | null | undefined; + contextType?: ['test'] | null | undefined; + action?: ['test'] | null | undefined; + events?: + | { + t: 'test'; + }[] + | null + | undefined; + updatedAt?: string | null | undefined; + }, typeof emailLog.$inferInsert> + >; +} + +{ + const customRequiredConfig = customType<{ + data: string; + driverData: string; + config: { length: number }; + configRequired: true; + }>({ + dataType(config) { + Expect>; + return `varchar(${config.length})`; + }, + + toDriver(value) { + Expect>(); + return value; + }, + + fromDriver(value) { + Expect>(); + return value; + }, + }); + + customRequiredConfig('t', { length: 10 }); + customRequiredConfig({ length: 10 }); + // @ts-expect-error - config is required + customRequiredConfig('t'); + // @ts-expect-error - config is required + customRequiredConfig(); +} + +{ + const customOptionalConfig = customType<{ + data: string; + driverData: string; + config: { length: number }; + }>({ + dataType(config) { + Expect>; + return config ? `varchar(${config.length})` : `text`; + }, + + toDriver(value) { + Expect>(); + return value; + }, + + fromDriver(value) { + Expect>(); + return value; + }, + }); + + customOptionalConfig('t', { length: 10 }); + customOptionalConfig('t'); + customOptionalConfig({ length: 10 }); + customOptionalConfig(); +} + +{ + singlestoreTable('all_columns', { + bigint: bigint('bigint', { mode: 'number' }), + bigint2: bigint('bigint', { mode: 'number', unsigned: true }), + bigintdef: bigint('bigintdef', { mode: 'number' }).default(0), + binary: binary('binary'), + binary1: binary('binary1', { length: 1 }), + binarydef: binary('binarydef').default(''), + boolean: boolean('boolean'), + booleandef: boolean('booleandef').default(false), + char: char('char'), + char2: char('char2', { length: 1 }), + char3: char('char3', { enum: ['a', 'b', 'c'] }), + char4: char('char4', { length: 1, enum: ['a', 'b', 'c'] }), + chardef: char('chardef').default(''), + date: date('date'), + date2: date('date2', { mode: 'string' }), + datedef: date('datedef').default(new Date()), + datetime: datetime('datetime'), + datetime2: datetime('datetime2', { mode: 'string' }), + datetimedef: datetime('datetimedef').default(new Date()), + decimal: decimal('decimal'), + decimal2: decimal('decimal2', { precision: 10 }), + decimal3: decimal('decimal3', { scale: 2 }), + decimal4: decimal('decimal4', { precision: 10, scale: 2 }), + decimaldef: decimal('decimaldef').default('0'), + double: double('double'), + double2: double('double2', { precision: 10 }), + double3: double('double3', { scale: 2 }), + double4: double('double4', { precision: 10, scale: 2 }), + doubledef: double('doubledef').default(0), + enum: singlestoreEnum('enum', ['a', 'b', 'c']), + enumdef: singlestoreEnum('enumdef', ['a', 'b', 'c']).default('a'), + float: float('float'), + float2: float('float2', { precision: 10 }), + float3: float('float3', { scale: 2 }), + float4: float('float4', { precision: 10, scale: 2 }), + floatdef: float('floatdef').default(0), + int: int('int'), + int2: int('int2', { unsigned: true }), + intdef: int('intdef').default(0), + json: json('json'), + jsondef: json('jsondef').default({}), + mediumint: mediumint('mediumint'), + mediumint2: mediumint('mediumint2', { unsigned: true }), + mediumintdef: mediumint('mediumintdef').default(0), + real: real('real'), + real2: real('real2', { precision: 10 }), + real3: real('real3', { scale: 2 }), + real4: real('real4', { precision: 10, scale: 2 }), + realdef: real('realdef').default(0), + serial: serial('serial'), + serialdef: serial('serialdef').default(0), + smallint: smallint('smallint'), + smallint2: smallint('smallint2', { unsigned: true }), + smallintdef: smallint('smallintdef').default(0), + text: text('text'), + text2: text('text2', { enum: ['a', 'b', 'c'] }), + textdef: text('textdef').default(''), + tinytext: tinytext('tinytext'), + tinytext2: tinytext('tinytext2', { enum: ['a', 'b', 'c'] }), + tinytextdef: tinytext('tinytextdef').default(''), + mediumtext: mediumtext('mediumtext'), + mediumtext2: mediumtext('mediumtext2', { enum: ['a', 'b', 'c'] }), + mediumtextdef: mediumtext('mediumtextdef').default(''), + longtext: longtext('longtext'), + longtext2: longtext('longtext2', { enum: ['a', 'b', 'c'] }), + longtextdef: longtext('longtextdef').default(''), + time: time('time'), + timedef: time('timedef').default('00:00:00'), + timestamp: timestamp('timestamp'), + timestamp2: timestamp('timestamp2', { mode: 'string' }), + timestamp3: timestamp('timestamp3', { mode: 'string' }), + timestamp4: timestamp('timestamp4'), + timestampdef: timestamp('timestampdef').default(new Date()), + tinyint: tinyint('tinyint'), + tinyint2: tinyint('tinyint2', { unsigned: true }), + tinyintdef: tinyint('tinyintdef').default(0), + varbinary: varbinary('varbinary', { length: 1 }), + varbinarydef: varbinary('varbinarydef', { length: 1 }).default(''), + varchar: varchar('varchar', { length: 1 }), + varchar2: varchar('varchar2', { length: 1, enum: ['a', 'b', 'c'] }), + varchardef: varchar('varchardef', { length: 1 }).default(''), + year: year('year'), + yeardef: year('yeardef').default(0), + }); +} + +{ + const keysAsColumnNames = singlestoreTable('test', { + id: int(), + name: text(), + }); + + Expect>; + Expect>; +} + +{ + singlestoreTable('all_columns_without_name', { + bigint: bigint({ mode: 'number' }), + bigint2: bigint({ mode: 'number', unsigned: true }), + bigintdef: bigint({ mode: 'number' }).default(0), + binary: binary(), + binrary1: binary({ length: 1 }), + binarydef: binary().default(''), + boolean: boolean(), + booleandef: boolean().default(false), + char: char(), + char2: char({ length: 1 }), + char3: char({ enum: ['a', 'b', 'c'] }), + char4: char({ length: 1, enum: ['a', 'b', 'c'] }), + chardef: char().default(''), + date: date(), + date2: date({ mode: 'string' }), + datedef: date('datedef').default(new Date()), + datetime: datetime(), + datetime2: datetime({ mode: 'string' }), + datetimedef: datetime('datetimedef').default(new Date()), + decimal: decimal(), + decimal2: decimal({ precision: 10 }), + decimal3: decimal({ scale: 2 }), + decimal4: decimal({ precision: 10, scale: 2 }), + decimaldef: decimal('decimaldef').default('0'), + double: double(), + double2: double({ precision: 10 }), + double3: double({ scale: 2 }), + double4: double({ precision: 10, scale: 2 }), + doubledef: double().default(0), + enum: singlestoreEnum(['a', 'b', 'c']), + enumdef: singlestoreEnum(['a', 'b', 'c']).default('a'), + float: float(), + float2: float({ precision: 10 }), + float3: float({ scale: 2 }), + float4: float({ precision: 10, scale: 2 }), + floatdef: float().default(0), + int: int(), + int2: int({ unsigned: true }), + intdef: int().default(0), + json: json(), + jsondef: json().default({}), + mediumint: mediumint(), + mediumint2: mediumint({ unsigned: true }), + mediumintdef: mediumint().default(0), + real: real(), + real2: real({ precision: 10 }), + real3: real({ scale: 2 }), + real4: real({ precision: 10, scale: 2 }), + realdef: real().default(0), + serial: serial(), + serialdef: serial().default(0), + smallint: smallint(), + smallint2: smallint({ unsigned: true }), + smallintdef: smallint().default(0), + text: text(), + text2: text({ enum: ['a', 'b', 'c'] }), + textdef: text().default(''), + tinytext: tinytext(), + tinytext2: tinytext({ enum: ['a', 'b', 'c'] }), + tinytextdef: tinytext().default(''), + mediumtext: mediumtext(), + mediumtext2: mediumtext({ enum: ['a', 'b', 'c'] }), + mediumtextdef: mediumtext().default(''), + longtext: longtext(), + longtext2: longtext({ enum: ['a', 'b', 'c'] }), + longtextdef: longtext().default(''), + time: time(), + timedef: time().default('00:00:00'), + timestamp: timestamp(), + timestamp2: timestamp({ mode: 'string' }), + timestamp3: timestamp({ mode: 'string' }), + timestamp4: timestamp(), + timestampdef: timestamp().default(new Date()), + tinyint: tinyint(), + tinyint2: tinyint({ unsigned: true }), + tinyintdef: tinyint().default(0), + varbinary: varbinary({ length: 1 }), + varbinarydef: varbinary({ length: 1 }).default(''), + varchar: varchar({ length: 1 }), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }), + varchardef: varchar({ length: 1 }).default(''), + year: year(), + yeardef: year().default(0), + }); +} diff --git a/drizzle-orm/type-tests/singlestore/update.ts b/drizzle-orm/type-tests/singlestore/update.ts new file mode 100644 index 000000000..4fb5497cf --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/update.ts @@ -0,0 +1,30 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import type { SingleStoreUpdate } from '~/singlestore-core/index.ts'; +import type { SingleStoreRawQueryResult } from '~/singlestore/session.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +{ + function dynamic(qb: T) { + return qb.where(sql``); + } + + const qbBase = db.update(users).set({}).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .update(users) + .set({}) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); +} + +{ + db.update(users).set({}).where(sql``).limit(1).orderBy(sql``); +} diff --git a/drizzle-orm/type-tests/singlestore/with.ts b/drizzle-orm/type-tests/singlestore/with.ts new file mode 100644 index 000000000..4233fbbf1 --- /dev/null +++ b/drizzle-orm/type-tests/singlestore/with.ts @@ -0,0 +1,80 @@ +import type { Equal } from 'type-tests/utils.ts'; +import { Expect } from 'type-tests/utils.ts'; +import { gt, inArray } from '~/expressions.ts'; +import { int, serial, singlestoreTable, text } from '~/singlestore-core/index.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; + +const orders = singlestoreTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull(), + amount: int('amount').notNull(), + quantity: int('quantity').notNull(), + /* generated: text('generatedText').generatedAlwaysAs(sql``), */ +}); + +{ + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: orders.region, + totalSales: orders.amount, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`sum(${orders.quantity})`, + productSales: sql`sum(${orders.amount})`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))); + + Expect< + Equal<{ + region: string; + product: string; + productUnits: number; + productSales: number; + }[], typeof result> + >; + + const allOrdersWith = db.$with('all_orders_with').as(db.select().from(orders)); + const allFromWith = await db.with(allOrdersWith).select().from(allOrdersWith); + + Expect< + Equal<{ + id: number; + region: string; + product: string; + amount: number; + quantity: number; + /* generated: string | null; */ + }[], typeof allFromWith> + >; +} diff --git a/drizzle-orm/type-tests/sqlite/db.ts b/drizzle-orm/type-tests/sqlite/db.ts index 07af338d4..1950c7435 100644 --- a/drizzle-orm/type-tests/sqlite/db.ts +++ b/drizzle-orm/type-tests/sqlite/db.ts @@ -3,11 +3,14 @@ import { Database as BunDatabase } from 'bun:sqlite'; import { drizzle as drizzleBetterSqlite3 } from '~/better-sqlite3/index.ts'; import { drizzle as drizzleBun } from '~/bun-sqlite/index.ts'; import { drizzle as drizzleD1 } from '~/d1/index.ts'; +import { drizzle as durableSqlite } from '~/durable-sqlite/index.ts'; const client = new Database(':memory:'); const bunClient = new BunDatabase(':memory:'); declare const d1: D1Database; +declare const durableSql: DurableObjectStorage; export const db = drizzleBetterSqlite3(client); export const bunDb = drizzleBun(bunClient); export const d1Db = drizzleD1(d1); +export const durableSqliteDb = durableSqlite(durableSql); diff --git a/drizzle-orm/type-tests/utils/neon-auth-token.ts b/drizzle-orm/type-tests/utils/neon-auth-token.ts new file mode 100644 index 000000000..5ea684ddc --- /dev/null +++ b/drizzle-orm/type-tests/utils/neon-auth-token.ts @@ -0,0 +1,5 @@ +import type { HTTPQueryOptions } from '@neondatabase/serverless'; +import { type Equal, Expect } from 'type-tests/utils.ts'; +import type { NeonAuthToken } from '~/utils'; + +Expect['authToken'], undefined>, NeonAuthToken>>; diff --git a/integration-tests/.env.example b/integration-tests/.env.example index ceff7d132..cad737330 100644 --- a/integration-tests/.env.example +++ b/integration-tests/.env.example @@ -1,5 +1,6 @@ PG_CONNECTION_STRING="postgres://postgres:postgres@localhost:55432/postgres" MYSQL_CONNECTION_STRING="mysql://root:mysql@127.0.0.1:33306/drizzle" +SINGLESTORE_CONNECTION_STRING="singlestore://root:singlestore@localhost:3306/drizzle" PLANETSCALE_CONNECTION_STRING= TIDB_CONNECTION_STRING= NEON_CONNECTION_STRING= diff --git a/integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql b/integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql new file mode 100644 index 000000000..50efe47da --- /dev/null +++ b/integration-tests/drizzle2/singlestore/0000_nostalgic_carnage.sql @@ -0,0 +1,20 @@ +CREATE TABLE `cities_migration` ( + `id` int, + `fullname_name` text, + `state` text +); +--> statement-breakpoint +CREATE TABLE `users_migration` ( + `id` int PRIMARY KEY NOT NULL, + `full_name` text, + `phone` int, + `invited_by` int, + `city_id` int, + `date` timestamp DEFAULT now() +); +--> statement-breakpoint +CREATE TABLE `users12` ( + `id` serial AUTO_INCREMENT PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `email` text NOT NULL +); diff --git a/integration-tests/drizzle2/singlestore/meta/0000_snapshot.json b/integration-tests/drizzle2/singlestore/meta/0000_snapshot.json new file mode 100644 index 000000000..63d5ad187 --- /dev/null +++ b/integration-tests/drizzle2/singlestore/meta/0000_snapshot.json @@ -0,0 +1,132 @@ +{ + "version": "1", + "dialect": "singlestore", + "id": "8e8c8378-0496-40f6-88e3-98aab8282b1f", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "cities_migration": { + "name": "cities_migration", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fullname_name": { + "name": "fullname_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {} + }, + "users_migration": { + "name": "users_migration", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "full_name": { + "name": "full_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "invited_by": { + "name": "invited_by", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "city_id": { + "name": "city_id", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "date": { + "name": "date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {} + }, + "users12": { + "name": "users12", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "my_unique_index": { + "name": "my_unique_index", + "columns": [ + "name" + ], + "isUnique": true, + "using": "btree" + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {} + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} diff --git a/integration-tests/drizzle2/singlestore/meta/_journal.json b/integration-tests/drizzle2/singlestore/meta/_journal.json new file mode 100644 index 000000000..49e74f169 --- /dev/null +++ b/integration-tests/drizzle2/singlestore/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "dialect": "singlestore", + "entries": [ + { + "idx": 0, + "version": "1", + "when": 1680270921944, + "tag": "0000_nostalgic_carnage", + "breakpoints": true + } + ] +} diff --git a/integration-tests/tests/pg/neon-http.test.ts b/integration-tests/tests/pg/neon-http.test.ts index 7cb433653..8fee5b82d 100644 --- a/integration-tests/tests/pg/neon-http.test.ts +++ b/integration-tests/tests/pg/neon-http.test.ts @@ -586,3 +586,205 @@ describe('$withAuth tests', (it) => { }); }); }); + +describe('$withAuth callback tests', (it) => { + const client = vi.fn(); + const db = drizzle({ + client: client as any as NeonQueryFunction, + schema: { + usersTable, + }, + }); + const auth = (token: string) => () => token; + + it('$count', async () => { + await db.$withAuth(auth('$count')).$count(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('$count'); + }); + + it('delete', async () => { + await db.$withAuth(auth('delete')).delete(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('delete'); + }); + + it('select', async () => { + await db.$withAuth(auth('select')).select().from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('select'); + }); + + it('selectDistinct', async () => { + await db.$withAuth(auth('selectDistinct')).selectDistinct().from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('selectDistinct'); + }); + + it('selectDistinctOn', async () => { + await db.$withAuth(auth('selectDistinctOn')).selectDistinctOn([usersTable.name]).from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('selectDistinctOn'); + }); + + it('update', async () => { + await db.$withAuth(auth('update')).update(usersTable).set({ + name: 'CHANGED', + }).where(eq(usersTable.name, 'TARGET')).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('update'); + }); + + it('insert', async () => { + await db.$withAuth(auth('insert')).insert(usersTable).values({ + name: 'WITHAUTHUSER', + }).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('insert'); + }); + + it('with', async () => { + await db.$withAuth(auth('with')).with(db.$with('WITH').as((qb) => qb.select().from(usersTable))).select().from( + usersTable, + ) + .catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('with'); + }); + + it('rqb', async () => { + await db.$withAuth(auth('rqb')).query.usersTable.findFirst().catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('rqb'); + }); + + it('exec', async () => { + await db.$withAuth(auth('exec')).execute(`SELECT 1`).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('exec'); + }); + + it('prepared', async () => { + const prep = db.$withAuth(auth('prepared')).select().from(usersTable).prepare('withAuthPrepared'); + + await prep.execute().catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('prepared'); + }); + + it('refreshMaterializedView', async () => { + const johns = pgMaterializedView('johns') + .as((qb) => qb.select().from(usersTable).where(eq(usersTable.name, 'John'))); + + await db.$withAuth(auth('refreshMaterializedView')).refreshMaterializedView(johns); + + expect(client.mock.lastCall?.[2]['authToken']()).toStrictEqual('refreshMaterializedView'); + }); +}); + +describe('$withAuth async callback tests', (it) => { + const client = vi.fn(); + const db = drizzle({ + client: client as any as NeonQueryFunction, + schema: { + usersTable, + }, + }); + const auth = (token: string) => async () => token; + + it('$count', async () => { + await db.$withAuth(auth('$count')).$count(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('$count'); + }); + + it('delete', async () => { + await db.$withAuth(auth('delete')).delete(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('delete'); + }); + + it('select', async () => { + await db.$withAuth(auth('select')).select().from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('select'); + }); + + it('selectDistinct', async () => { + await db.$withAuth(auth('selectDistinct')).selectDistinct().from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('selectDistinct'); + }); + + it('selectDistinctOn', async () => { + await db.$withAuth(auth('selectDistinctOn')).selectDistinctOn([usersTable.name]).from(usersTable).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('selectDistinctOn'); + }); + + it('update', async () => { + await db.$withAuth(auth('update')).update(usersTable).set({ + name: 'CHANGED', + }).where(eq(usersTable.name, 'TARGET')).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('update'); + }); + + it('insert', async () => { + await db.$withAuth(auth('insert')).insert(usersTable).values({ + name: 'WITHAUTHUSER', + }).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('insert'); + }); + + it('with', async () => { + await db.$withAuth(auth('with')).with(db.$with('WITH').as((qb) => qb.select().from(usersTable))).select().from( + usersTable, + ) + .catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('with'); + }); + + it('rqb', async () => { + await db.$withAuth(auth('rqb')).query.usersTable.findFirst().catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('rqb'); + }); + + it('exec', async () => { + await db.$withAuth(auth('exec')).execute(`SELECT 1`).catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('exec'); + }); + + it('prepared', async () => { + const prep = db.$withAuth(auth('prepared')).select().from(usersTable).prepare('withAuthPrepared'); + + await prep.execute().catch(() => null); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('prepared'); + }); + + it('refreshMaterializedView', async () => { + const johns = pgMaterializedView('johns') + .as((qb) => qb.select().from(usersTable).where(eq(usersTable.name, 'John'))); + + await db.$withAuth(auth('refreshMaterializedView')).refreshMaterializedView(johns); + + expect(client.mock.lastCall?.[2]['authToken']()).toBeInstanceOf(Promise); + expect(await client.mock.lastCall?.[2]['authToken']()).toStrictEqual('refreshMaterializedView'); + }); +}); diff --git a/integration-tests/tests/relational/singlestore.schema.ts b/integration-tests/tests/relational/singlestore.schema.ts new file mode 100644 index 000000000..ca3386ba0 --- /dev/null +++ b/integration-tests/tests/relational/singlestore.schema.ts @@ -0,0 +1,106 @@ +import { bigint, boolean, primaryKey, serial, singlestoreTable, text, timestamp } from 'drizzle-orm/singlestore-core'; + +import { relations } from 'drizzle-orm'; + +export const usersTable = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + invitedBy: bigint('invited_by', { mode: 'number' }), +}); +export const usersConfig = relations(usersTable, ({ one, many }) => ({ + invitee: one(usersTable, { + fields: [usersTable.invitedBy], + references: [usersTable.id], + }), + usersToGroups: many(usersToGroupsTable), + posts: many(postsTable), + comments: many(commentsTable), +})); + +export const groupsTable = singlestoreTable('groups', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + description: text('description'), +}); +export const groupsConfig = relations(groupsTable, ({ many }) => ({ + usersToGroups: many(usersToGroupsTable), +})); + +export const usersToGroupsTable = singlestoreTable( + 'users_to_groups', + { + id: serial('id').primaryKey(), + userId: bigint('user_id', { mode: 'number' }).notNull(), + groupId: bigint('group_id', { mode: 'number' }).notNull(), + }, + (t) => ({ + pk: primaryKey(t.userId, t.groupId), + }), +); +export const usersToGroupsConfig = relations(usersToGroupsTable, ({ one }) => ({ + group: one(groupsTable, { + fields: [usersToGroupsTable.groupId], + references: [groupsTable.id], + }), + user: one(usersTable, { + fields: [usersToGroupsTable.userId], + references: [usersTable.id], + }), +})); + +export const postsTable = singlestoreTable('posts', { + id: serial('id').primaryKey(), + content: text('content').notNull(), + ownerId: bigint('owner_id', { mode: 'number' }), + createdAt: timestamp('created_at') + .notNull() + .defaultNow(), +}); +export const postsConfig = relations(postsTable, ({ one, many }) => ({ + author: one(usersTable, { + fields: [postsTable.ownerId], + references: [usersTable.id], + }), + comments: many(commentsTable), +})); + +export const commentsTable = singlestoreTable('comments', { + id: serial('id').primaryKey(), + content: text('content').notNull(), + creator: bigint('creator', { mode: 'number' }), + postId: bigint('post_id', { mode: 'number' }), + createdAt: timestamp('created_at') + .notNull() + .defaultNow(), +}); +export const commentsConfig = relations(commentsTable, ({ one, many }) => ({ + post: one(postsTable, { + fields: [commentsTable.postId], + references: [postsTable.id], + }), + author: one(usersTable, { + fields: [commentsTable.creator], + references: [usersTable.id], + }), + likes: many(commentLikesTable), +})); + +export const commentLikesTable = singlestoreTable('comment_likes', { + id: serial('id').primaryKey(), + creator: bigint('creator', { mode: 'number' }), + commentId: bigint('comment_id', { mode: 'number' }), + createdAt: timestamp('created_at') + .notNull() + .defaultNow(), +}); +export const commentLikesConfig = relations(commentLikesTable, ({ one }) => ({ + comment: one(commentsTable, { + fields: [commentLikesTable.commentId], + references: [commentsTable.id], + }), + author: one(usersTable, { + fields: [commentLikesTable.creator], + references: [usersTable.id], + }), +})); diff --git a/integration-tests/tests/relational/singlestore.test.ts b/integration-tests/tests/relational/singlestore.test.ts new file mode 100644 index 000000000..0e20a7046 --- /dev/null +++ b/integration-tests/tests/relational/singlestore.test.ts @@ -0,0 +1,6403 @@ +// import retry from 'async-retry'; +// import Docker from 'dockerode'; +// import 'dotenv/config'; +// import { desc, DrizzleError, eq, gt, gte, or, placeholder, sql, TransactionRollbackError } from 'drizzle-orm'; +// import { drizzle, type SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +// import getPort from 'get-port'; +// import * as mysql from 'mysql2/promise'; +// import { v4 as uuid } from 'uuid'; +// import { afterAll, beforeAll, beforeEach, expect, expectTypeOf, test } from 'vitest'; +// import * as schema from './singlestore.schema.ts'; + +// const { usersTable, postsTable, commentsTable, usersToGroupsTable, groupsTable } = schema; + +// const ENABLE_LOGGING = false; + +// /* +// Test cases: +// - querying nested relation without PK with additional fields +// */ + +// declare module 'vitest' { +// export interface TestContext { +// docker: Docker; +// singlestoreContainer: Docker.Container; +// singlestoreDb: SingleStoreDriverDatabase; +// singlestoreClient: mysql.Connection; +// } +// } + +// let globalDocker: Docker; +// let singlestoreContainer: Docker.Container; +// let db: SingleStoreDriverDatabase; +// let client: mysql.Connection; + +// async function createDockerDB(): Promise { +// const docker = new Docker(); +// const port = await getPort({ port: 3306 }); +// const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + +// const pullStream = await docker.pull(image); +// await new Promise((resolve, reject) => +// docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) +// ); + +// singlestoreContainer = await docker.createContainer({ +// Image: image, +// Env: ['ROOT_PASSWORD=singlestore'], +// name: `drizzle-integration-tests-${uuid()}`, +// HostConfig: { +// AutoRemove: true, +// PortBindings: { +// '3306/tcp': [{ HostPort: `${port}` }], +// }, +// }, +// }); + +// await singlestoreContainer.start(); +// await new Promise((resolve) => setTimeout(resolve, 4000)); + +// return `singlestore://root:singlestore@localhost:${port}/`; +// } + +// beforeAll(async () => { +// const connectionString = process.env['SINGLESTORE_CONNECTION_STRING'] ?? (await createDockerDB()); +// client = await retry(async () => { +// client = await mysql.createConnection(connectionString); +// await client.connect(); +// return client; +// }, { +// retries: 20, +// factor: 1, +// minTimeout: 250, +// maxTimeout: 250, +// randomize: false, +// onRetry() { +// client?.end(); +// }, +// }); + +// await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); +// await client.changeUser({ database: 'drizzle' }); +// db = drizzle(client, { schema, logger: ENABLE_LOGGING }); +// }); + +// afterAll(async () => { +// await client?.end().catch(console.error); +// await singlestoreContainer?.stop().catch(console.error); +// }); + +// beforeEach(async (ctx) => { +// ctx.singlestoreDb = db; +// ctx.singlestoreClient = client; +// ctx.docker = globalDocker; +// ctx.singlestoreContainer = singlestoreContainer; + +// await ctx.singlestoreDb.execute(sql`drop table if exists \`users\``); +// await ctx.singlestoreDb.execute(sql`drop table if exists \`groups\``); +// await ctx.singlestoreDb.execute(sql`drop table if exists \`users_to_groups\``); +// await ctx.singlestoreDb.execute(sql`drop table if exists \`posts\``); +// await ctx.singlestoreDb.execute(sql`drop table if exists \`comments\``); +// await ctx.singlestoreDb.execute(sql`drop table if exists \`comment_likes\``); + +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`users\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`name\` text NOT NULL, +// \`verified\` boolean DEFAULT false NOT NULL, +// \`invited_by\` bigint +// ); +// `, +// ); +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`groups\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`name\` text NOT NULL, +// \`description\` text +// ); +// `, +// ); +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`users_to_groups\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`user_id\` bigint, +// \`group_id\` bigint +// ); +// `, +// ); +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`posts\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`content\` text NOT NULL, +// \`owner_id\` bigint, +// \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL +// ); +// `, +// ); +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`comments\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`content\` text NOT NULL, +// \`creator\` bigint, +// \`post_id\` bigint, +// \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL +// ); +// `, +// ); +// await ctx.singlestoreDb.execute( +// sql` +// CREATE TABLE \`comment_likes\` ( +// \`id\` serial PRIMARY KEY NOT NULL, +// \`creator\` bigint, +// \`comment_id\` bigint, +// \`created_at\` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL +// ); +// `, +// ); +// }); + +// /* +// [Find Many] One relation users+posts +// */ + +// test('[Find Many] Get users with posts', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// with: { +// posts: true, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithPosts.length).eq(3); +// expect(usersWithPosts[0]?.posts.length).eq(1); +// expect(usersWithPosts[1]?.posts.length).eq(1); +// expect(usersWithPosts[2]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[2]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 3, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + limit posts', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// with: { +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithPosts.length).eq(3); +// expect(usersWithPosts[0]?.posts.length).eq(1); +// expect(usersWithPosts[1]?.posts.length).eq(1); +// expect(usersWithPosts[2]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[2]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + limit posts and users', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// limit: 2, +// with: { +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithPosts.length).eq(2); +// expect(usersWithPosts[0]?.posts.length).eq(1); +// expect(usersWithPosts[1]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts + custom fields', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// with: { +// posts: true, +// }, +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lowerName: string; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// usersWithPosts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// usersWithPosts[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithPosts.length).toEqual(3); +// expect(usersWithPosts[0]?.posts.length).toEqual(3); +// expect(usersWithPosts[1]?.posts.length).toEqual(2); +// expect(usersWithPosts[2]?.posts.length).toEqual(2); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// lowerName: 'dan', +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }, { +// id: 2, +// ownerId: 1, +// content: 'Post1.2', +// createdAt: usersWithPosts[0]?.posts[1]?.createdAt, +// }, { id: 3, ownerId: 1, content: 'Post1.3', createdAt: usersWithPosts[0]?.posts[2]?.createdAt }], +// }); +// expect(usersWithPosts[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// lowerName: 'andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }, { +// id: 5, +// ownerId: 2, +// content: 'Post2.1', +// createdAt: usersWithPosts[1]?.posts[1]?.createdAt, +// }], +// }); +// expect(usersWithPosts[2]).toEqual({ +// id: 3, +// name: 'Alex', +// lowerName: 'alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }, { +// id: 7, +// ownerId: 3, +// content: 'Post3.1', +// createdAt: usersWithPosts[2]?.posts[1]?.createdAt, +// }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + custom fields + limits', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// limit: 1, +// with: { +// posts: { +// limit: 1, +// }, +// }, +// extras: (usersTable, { sql }) => ({ +// lowerName: sql`lower(${usersTable.name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lowerName: string; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).toEqual(1); +// expect(usersWithPosts[0]?.posts.length).toEqual(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// lowerName: 'dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: '1' }, +// { ownerId: 1, content: '2' }, +// { ownerId: 1, content: '3' }, +// { ownerId: 2, content: '4' }, +// { ownerId: 2, content: '5' }, +// { ownerId: 3, content: '6' }, +// { ownerId: 3, content: '7' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// with: { +// posts: { +// orderBy: (postsTable, { desc }) => [desc(postsTable.content)], +// }, +// }, +// orderBy: (usersTable, { desc }) => [desc(usersTable.id)], +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(3); +// expect(usersWithPosts[0]?.posts.length).eq(2); +// expect(usersWithPosts[1]?.posts.length).eq(2); +// expect(usersWithPosts[2]?.posts.length).eq(3); + +// expect(usersWithPosts[2]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 3, ownerId: 1, content: '3', createdAt: usersWithPosts[2]?.posts[2]?.createdAt }, { +// id: 2, +// ownerId: 1, +// content: '2', +// createdAt: usersWithPosts[2]?.posts[1]?.createdAt, +// }, { id: 1, ownerId: 1, content: '1', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 5, +// ownerId: 2, +// content: '5', +// createdAt: usersWithPosts[1]?.posts[1]?.createdAt, +// }, { id: 4, ownerId: 2, content: '4', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts[0]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 7, +// ownerId: 3, +// content: '7', +// createdAt: usersWithPosts[0]?.posts[1]?.createdAt, +// }, { id: 6, ownerId: 3, content: '6', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// where: (({ id }, { eq }) => eq(id, 1)), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts + where + partial', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: { +// id: true, +// name: true, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: true, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// posts: { +// id: number; +// content: string; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// posts: [{ id: 1, content: 'Post1' }], +// }); +// }); + +// test('[Find Many] Get users with posts + where + partial. Did not select posts id, but used it in where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: { +// id: true, +// name: true, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: true, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// posts: { +// id: number; +// content: string; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// posts: [{ id: 1, content: 'Post1' }], +// }); +// }); + +// test('[Find Many] Get users with posts + where + partial(true + false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: { +// id: true, +// name: false, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: false, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// posts: { +// id: number; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// posts: [{ id: 1 }], +// }); +// }); + +// test('[Find Many] Get users with posts + where + partial(false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: { +// name: false, +// }, +// with: { +// posts: { +// columns: { +// content: false, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts in transaction', async (t) => { +// const { singlestoreDb: db } = t; + +// let usersWithPosts: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[] = []; + +// await db.transaction(async (tx) => { +// await tx.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await tx.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// usersWithPosts = await tx.query.usersTable.findMany({ +// where: (({ id }, { eq }) => eq(id, 1)), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// }); +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts in rollbacked transaction', async (t) => { +// const { singlestoreDb: db } = t; + +// let usersWithPosts: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[] = []; + +// await expect(db.transaction(async (tx) => { +// await tx.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await tx.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// tx.rollback(); + +// usersWithPosts = await tx.query.usersTable.findMany({ +// where: (({ id }, { eq }) => eq(id, 1)), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// }); +// })).rejects.toThrowError(new TransactionRollbackError()); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(0); +// }); + +// // select only custom +// test('[Find Many] Get only custom fields', async () => { +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { id: 1, ownerId: 1, content: 'Post1' }, +// { id: 2, ownerId: 1, content: 'Post1.2' }, +// { id: 3, ownerId: 1, content: 'Post1.3' }, +// { id: 4, ownerId: 2, content: 'Post2' }, +// { id: 5, ownerId: 2, content: 'Post2.1' }, +// { id: 6, ownerId: 3, content: 'Post3' }, +// { id: 7, ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// }[]>(); + +// // General Assertions +// expect(usersWithPosts).toHaveLength(3); + +// // Helper function to find user by lowerName +// const findUser = (lowerName: string) => usersWithPosts.find((user) => user.lowerName === lowerName); + +// // Assertions for each user +// const dan = findUser('dan'); +// const andrew = findUser('andrew'); +// const alex = findUser('alex'); + +// expect(dan).toBeDefined(); +// expect(andrew).toBeDefined(); +// expect(alex).toBeDefined(); + +// // Verify the number of posts for each user +// expect(dan?.posts).toHaveLength(3); +// expect(andrew?.posts).toHaveLength(2); +// expect(alex?.posts).toHaveLength(2); + +// // Define expected posts for each user +// const expectedDanPosts = ['post1', 'post1.2', 'post1.3']; +// const expectedAndrewPosts = ['post2', 'post2.1']; +// const expectedAlexPosts = ['post3', 'post3.1']; + +// // Helper function to extract lowerNames from posts +// const getPostLowerNames = (posts: { lowerName: string }[]) => posts.map((post) => post.lowerName); + +// // Assertions for Dan's posts +// expect(getPostLowerNames(dan!.posts)).toEqual(expect.arrayContaining(expectedDanPosts)); +// expect(getPostLowerNames(dan!.posts)).toHaveLength(expectedDanPosts.length); + +// // Assertions for Andrew's posts +// expect(getPostLowerNames(andrew!.posts)).toEqual(expect.arrayContaining(expectedAndrewPosts)); +// expect(getPostLowerNames(andrew!.posts)).toHaveLength(expectedAndrewPosts.length); + +// // Assertions for Alex's posts +// expect(getPostLowerNames(alex!.posts)).toEqual(expect.arrayContaining(expectedAlexPosts)); +// expect(getPostLowerNames(alex!.posts)).toHaveLength(expectedAlexPosts.length); +// }); + +// // select only custom with where clause (Order Agnostic) +// test('[Find Many] Get only custom fields + where', async (t) => { +// const { singlestoreDb: db } = t; + +// // Insert Users +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// // Insert Posts +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// // Query Users with Posts where users.id = 1 and posts.id >= 2 +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// }[]>(); + +// // General Assertions +// expect(usersWithPosts).toHaveLength(1); + +// // Since we expect only one user, we can extract it directly +// const danWithPosts = usersWithPosts[0]; + +// // Assert that the user exists and has the correct lowerName +// expect(danWithPosts).toBeDefined(); +// expect(danWithPosts?.lowerName).toBe('dan'); + +// // Assert that the user has the expected number of posts +// expect(danWithPosts?.posts).toHaveLength(2); + +// // Define the expected posts +// const expectedPosts = ['post1.2', 'post1.3']; + +// // Extract the lowerName of each post +// const actualPostLowerNames = danWithPosts?.posts.map((post) => post.lowerName); + +// // Assert that all expected posts are present, regardless of order +// for (const expectedPost of expectedPosts) { +// expect(actualPostLowerNames).toContain(expectedPost); +// } + +// // Additionally, ensure no unexpected posts are present +// expect(actualPostLowerNames).toHaveLength(expectedPosts.length); +// }); + +// test.skip('[Find Many] Get only custom fields + where + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// limit: 1, +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).toEqual(1); +// expect(usersWithPosts[0]?.posts.length).toEqual(1); + +// expect(usersWithPosts).toContainEqual({ +// lowerName: 'dan', +// posts: [{ lowerName: 'post1.2' }], +// }); +// }); + +// test.skip('[Find Many] Get only custom fields + where + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findMany({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// orderBy: [desc(postsTable.id)], +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).toEqual(1); +// expect(usersWithPosts[0]?.posts.length).toEqual(2); + +// expect(usersWithPosts).toContainEqual({ +// lowerName: 'dan', +// posts: [{ lowerName: 'post1.3' }, { lowerName: 'post1.2' }], +// }); +// }); + +// // select only custom find one (Order Agnostic) +// test('[Find One] Get only custom fields (Order Agnostic)', async () => { +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// // Query to find the first user without any specific order +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// } | undefined +// >(); + +// // General Assertions +// expect(usersWithPosts).toBeDefined(); + +// // Since findFirst without orderBy can return any user, we'll verify the returned user and their posts +// if (usersWithPosts) { +// // Define expected users and their corresponding posts +// const expectedUsers: { [key: string]: string[] } = { +// dan: ['post1', 'post1.2', 'post1.3'], +// andrew: ['post2', 'post2.1'], +// alex: ['post3', 'post3.1'], +// }; + +// // Verify that the returned user is one of the expected users +// expect(Object.keys(expectedUsers)).toContain(usersWithPosts.lowerName); + +// // Get the expected posts for the returned user +// const expectedPosts = expectedUsers[usersWithPosts.lowerName] as string[]; + +// // Verify the number of posts +// expect(usersWithPosts.posts).toHaveLength(expectedPosts.length); + +// // Extract the lowerName of each post +// const actualPostLowerNames = usersWithPosts.posts.map((post) => post.lowerName); + +// // Assert that all expected posts are present, regardless of order +// for (const expectedPost of expectedPosts) { +// expect(actualPostLowerNames).toContain(expectedPost.toLowerCase()); +// } +// } +// }); + +// // select only custom find one with where clause (Order Agnostic) +// test('[Find One] Get only custom fields + where (Order Agnostic)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// // Query to find the first user with id = 1 and posts with id >= 2 +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// } | undefined +// >(); + +// // General Assertions +// expect(usersWithPosts).toBeDefined(); + +// if (usersWithPosts) { +// // Assert that the returned user has the expected lowerName +// expect(usersWithPosts.lowerName).toBe('dan'); + +// // Assert that the user has exactly two posts +// expect(usersWithPosts.posts).toHaveLength(2); + +// // Define the expected posts +// const expectedPosts = ['post1.2', 'post1.3']; + +// // Extract the lowerName of each post +// const actualPostLowerNames = usersWithPosts.posts.map((post) => post.lowerName); + +// // Assert that all expected posts are present, regardless of order +// for (const expectedPost of expectedPosts) { +// expect(actualPostLowerNames).toContain(expectedPost.toLowerCase()); +// } + +// // Additionally, ensure no unexpected posts are present +// expect(actualPostLowerNames).toHaveLength(expectedPosts.length); +// } +// }); + +// test.skip('[Find One] Get only custom fields + where + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// limit: 1, +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts?.posts.length).toEqual(1); + +// expect(usersWithPosts).toEqual({ +// lowerName: 'dan', +// posts: [{ lowerName: 'post1.2' }], +// }); +// }); + +// test.skip('[Find One] Get only custom fields + where + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// where: gte(postsTable.id, 2), +// orderBy: [desc(postsTable.id)], +// extras: ({ content }) => ({ +// lowerName: sql`lower(${content})`.as('content_lower'), +// }), +// }, +// }, +// where: eq(usersTable.id, 1), +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// lowerName: string; +// posts: { +// lowerName: string; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts?.posts.length).toEqual(2); + +// expect(usersWithPosts).toEqual({ +// lowerName: 'dan', +// posts: [{ lowerName: 'post1.3' }, { lowerName: 'post1.2' }], +// }); +// }); + +// // columns {} +// test('[Find Many] Get select {}', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await expect( +// async () => +// await db.query.usersTable.findMany({ +// columns: {}, +// }), +// ).rejects.toThrow(DrizzleError); +// }); + +// // columns {} +// test('[Find One] Get select {}', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await expect(async () => +// await db.query.usersTable.findFirst({ +// columns: {}, +// }) +// ).rejects.toThrow(DrizzleError); +// }); + +// // deep select {} +// test('[Find Many] Get deep select {}', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// await expect(async () => +// await db.query.usersTable.findMany({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// }, +// }, +// }) +// ).rejects.toThrow(DrizzleError); +// }); + +// // deep select {} +// test('[Find One] Get deep select {}', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// await expect(async () => +// await db.query.usersTable.findFirst({ +// columns: {}, +// with: { +// posts: { +// columns: {}, +// }, +// }, +// }) +// ).rejects.toThrow(DrizzleError); +// }); + +// /* +// Prepared statements for users+posts +// */ +// test.skip('[Find Many] Get users with posts + prepared limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const prepared = db.query.usersTable.findMany({ +// with: { +// posts: { +// limit: placeholder('limit'), +// }, +// }, +// }).prepare(); + +// const usersWithPosts = await prepared.execute({ limit: 1 }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(3); +// expect(usersWithPosts[0]?.posts.length).eq(1); +// expect(usersWithPosts[1]?.posts.length).eq(1); +// expect(usersWithPosts[2]?.posts.length).eq(1); + +// expect(usersWithPosts).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[2]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + prepared limit + offset', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const prepared = db.query.usersTable.findMany({ +// limit: placeholder('uLimit'), +// offset: placeholder('uOffset'), +// with: { +// posts: { +// limit: placeholder('pLimit'), +// }, +// }, +// }).prepare(); + +// const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1 }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(2); +// expect(usersWithPosts[0]?.posts.length).eq(1); +// expect(usersWithPosts[1]?.posts.length).eq(1); + +// expect(usersWithPosts).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// expect(usersWithPosts).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[1]?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find Many] Get users with posts + prepared where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const prepared = db.query.usersTable.findMany({ +// where: (({ id }, { eq }) => eq(id, placeholder('id'))), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// }).prepare(); + +// const usersWithPosts = await prepared.execute({ id: 1 }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find Many] Get users with posts + prepared + limit + offset + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const prepared = db.query.usersTable.findMany({ +// limit: placeholder('uLimit'), +// offset: placeholder('uOffset'), +// where: (({ id }, { eq, or }) => or(eq(id, placeholder('id')), eq(id, 3))), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, placeholder('pid'))), +// limit: placeholder('pLimit'), +// }, +// }, +// }).prepare(); + +// const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// }[]>(); + +// expect(usersWithPosts.length).eq(1); +// expect(usersWithPosts[0]?.posts.length).eq(1); + +// expect(usersWithPosts).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ id: 6, ownerId: 3, content: 'Post3', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }], +// }); +// }); + +// /* +// [Find One] One relation users+posts +// */ + +// test.only('[Find One] Get users with posts', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: true, +// }, +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// // General Assertions +// expect(usersWithPosts).toBeDefined(); + +// if (usersWithPosts) { +// const { id, name, posts } = usersWithPosts; + +// // Verify that the user is one of the inserted users +// const validUsers: { [key: number]: string } = { +// 1: 'dan', +// 2: 'andrew', +// 3: 'alex', +// }; +// expect(validUsers[id]).toBe(name.toLowerCase()); + +// // Assert that the user has exactly one post +// expect(posts).toHaveLength(1); + +// const post = posts[0]; + +// // Verify that the post belongs to the user +// expect(post?.ownerId).toBe(id); + +// // Verify that the post content matches the user +// const expectedPostContent = `Post${id}`; +// expect(post?.content.toLowerCase()).toBe(expectedPostContent.toLowerCase()); + +// // Optionally, verify the presence of `createdAt` +// expect(post?.createdAt).toBeInstanceOf(Date); +// } +// }); + +// test.skip('[Find One] Get users with posts + limit posts', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find One] Get users with posts no results found', async (t) => { +// const { singlestoreDb: db } = t; + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts).toBeUndefined(); +// }); + +// test.skip('[Find One] Get users with posts + limit posts and users', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find One] Get users with posts + custom fields', async () => { +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: true, +// }, +// extras: ({ name }) => ({ +// lowerName: sql`lower(${name})`.as('name_lower'), +// }), +// }); + +// // Type Assertion +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lowerName: string; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// // General Assertions +// expect(usersWithPosts).toBeDefined(); + +// if (usersWithPosts) { +// const { id, lowerName, posts } = usersWithPosts; + +// // Define valid users and their expected lower names +// const validUsers: { [key: number]: string } = { +// 1: 'dan', +// 2: 'andrew', +// 3: 'alex', +// }; + +// // Verify that the returned user's lowerName matches the expected value +// expect(validUsers[id]).toBe(lowerName); + +// // Define the expected posts based on the user ID +// const expectedPostsByUser: Record = { +// 1: ['post1', 'post1.2', 'post1.3'], +// 2: ['post2', 'post2.1'], +// 3: ['post3', 'post3.1'], +// }; + +// // Get the expected posts for the returned user +// const expectedPosts = expectedPostsByUser[id] || []; + +// // Extract the lowerName of each post +// const actualPostContents = posts.map((post) => post.content.toLowerCase()); + +// // Assert that all expected posts are present, regardless of order +// for (const expectedPost of expectedPosts) { +// expect(actualPostContents).toContain(expectedPost.toLowerCase()); +// } + +// // Optionally, ensure that no unexpected posts are present +// expect(actualPostContents).toHaveLength(expectedPosts.length); +// } +// }); + +// test.skip('[Find One] Get users with posts + custom fields + limits', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.2' }, +// { ownerId: 1, content: 'Post1.3' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: { +// limit: 1, +// }, +// }, +// extras: (usersTable, { sql }) => ({ +// lowerName: sql`lower(${usersTable.name})`.as('name_lower'), +// }), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lowerName: string; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).toEqual(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// lowerName: 'dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('[Find One] Get users with posts + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: '1' }, +// { ownerId: 1, content: '2' }, +// { ownerId: 1, content: '3' }, +// { ownerId: 2, content: '4' }, +// { ownerId: 2, content: '5' }, +// { ownerId: 3, content: '6' }, +// { ownerId: 3, content: '7' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// with: { +// posts: { +// orderBy: (postsTable, { desc }) => [desc(postsTable.content)], +// }, +// }, +// orderBy: (usersTable, { desc }) => [desc(usersTable.id)], +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(2); + +// expect(usersWithPosts).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 7, +// ownerId: 3, +// content: '7', +// createdAt: usersWithPosts?.posts[1]?.createdAt, +// }, { id: 6, ownerId: 3, content: '6', createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find One] Get users with posts + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// where: (({ id }, { eq }) => eq(id, 1)), +// with: { +// posts: { +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// test('[Find One] Get users with posts + where + partial', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: { +// id: true, +// name: true, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: true, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// posts: { +// id: number; +// content: string; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// posts: [{ id: 1, content: 'Post1' }], +// }); +// }); + +// test.skip('[Find One] Get users with posts + where + partial. Did not select posts id, but used it in where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: { +// id: true, +// name: true, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: true, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// name: string; +// posts: { +// id: number; +// content: string; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// name: 'Dan', +// posts: [{ id: 1, content: 'Post1' }], +// }); +// }); + +// test.skip('[Find One] Get users with posts + where + partial(true + false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: { +// id: true, +// name: false, +// }, +// with: { +// posts: { +// columns: { +// id: true, +// content: false, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// posts: { +// id: number; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// posts: [{ id: 1 }], +// }); +// }); + +// test.skip('[Find One] Get users with posts + where + partial(false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const usersWithPosts = await db.query.usersTable.findFirst({ +// columns: { +// name: false, +// }, +// with: { +// posts: { +// columns: { +// content: false, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }, +// }, +// where: (({ id }, { eq }) => eq(id, 1)), +// }); + +// expectTypeOf(usersWithPosts).toEqualTypeOf< +// { +// id: number; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// ownerId: number | null; +// createdAt: Date; +// }[]; +// } | undefined +// >(); + +// expect(usersWithPosts!.posts.length).eq(1); + +// expect(usersWithPosts).toEqual({ +// id: 1, +// verified: false, +// invitedBy: null, +// posts: [{ id: 1, ownerId: 1, createdAt: usersWithPosts?.posts[0]?.createdAt }], +// }); +// }); + +// /* +// One relation users+users. Self referencing +// */ + +// test.skip('Get user with invitee', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// with: { +// invitee: true, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithInvitee.length).eq(4); +// expect(usersWithInvitee[0]?.invitee).toBeNull(); +// expect(usersWithInvitee[1]?.invitee).toBeNull(); +// expect(usersWithInvitee[2]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[3]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[2]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// }); +// expect(usersWithInvitee[3]).toEqual({ +// id: 4, +// name: 'John', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user + limit with invitee', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew', invitedBy: 1 }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// with: { +// invitee: true, +// }, +// limit: 2, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user with invitee and custom fields', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), +// with: { +// invitee: { +// extras: (invitee, { sql }) => ({ lower: sql`lower(${invitee.name})`.as('lower_name') }), +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithInvitee.length).eq(4); +// expect(usersWithInvitee[0]?.invitee).toBeNull(); +// expect(usersWithInvitee[1]?.invitee).toBeNull(); +// expect(usersWithInvitee[2]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[3]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee[0]).toEqual({ +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[2]).toEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, +// }); +// expect(usersWithInvitee[3]).toEqual({ +// id: 4, +// name: 'John', +// lower: 'john', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', lower: 'andrew', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user with invitee and custom fields + limits', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), +// limit: 3, +// with: { +// invitee: { +// extras: (invitee, { sql }) => ({ lower: sql`lower(${invitee.name})`.as('lower_name') }), +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// usersWithInvitee.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(usersWithInvitee.length).eq(3); +// expect(usersWithInvitee[0]?.invitee).toBeNull(); +// expect(usersWithInvitee[1]?.invitee).toBeNull(); +// expect(usersWithInvitee[2]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee[0]).toEqual({ +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[2]).toEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user with invitee + order by', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// orderBy: (users, { desc }) => [desc(users.id)], +// with: { +// invitee: true, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(4); +// expect(usersWithInvitee[3]?.invitee).toBeNull(); +// expect(usersWithInvitee[2]?.invitee).toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee[3]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[2]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// }); +// expect(usersWithInvitee[1]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// }); +// expect(usersWithInvitee[0]).toEqual({ +// id: 4, +// name: 'John', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user with invitee + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// with: { +// invitee: true, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// }); +// expect(usersWithInvitee).toContainEqual({ +// id: 4, +// name: 'John', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// }); +// }); + +// test.skip('Get user with invitee + where + partial', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// columns: { +// id: true, +// name: true, +// }, +// with: { +// invitee: { +// columns: { +// id: true, +// name: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// invitee: { +// id: number; +// name: string; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee).toContainEqual({ +// id: 3, +// name: 'Alex', +// invitee: { id: 1, name: 'Dan' }, +// }); +// expect(usersWithInvitee).toContainEqual({ +// id: 4, +// name: 'John', +// invitee: { id: 2, name: 'Andrew' }, +// }); +// }); + +// test.skip('Get user with invitee + where + partial. Did not select users id, but used it in where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// columns: { +// name: true, +// }, +// with: { +// invitee: { +// columns: { +// id: true, +// name: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// name: string; +// invitee: { +// id: number; +// name: string; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee).toContainEqual({ +// name: 'Alex', +// invitee: { id: 1, name: 'Dan' }, +// }); +// expect(usersWithInvitee).toContainEqual({ +// name: 'John', +// invitee: { id: 2, name: 'Andrew' }, +// }); +// }); + +// test.skip('Get user with invitee + where + partial(true+false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// columns: { +// id: true, +// name: true, +// verified: false, +// }, +// with: { +// invitee: { +// columns: { +// id: true, +// name: true, +// verified: false, +// }, +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// invitee: { +// id: number; +// name: string; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee).toContainEqual({ +// id: 3, +// name: 'Alex', +// invitee: { id: 1, name: 'Dan' }, +// }); +// expect(usersWithInvitee).toContainEqual({ +// id: 4, +// name: 'John', +// invitee: { id: 2, name: 'Andrew' }, +// }); +// }); + +// test.skip('Get user with invitee + where + partial(false)', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// const usersWithInvitee = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// columns: { +// verified: false, +// }, +// with: { +// invitee: { +// columns: { +// name: false, +// }, +// }, +// }, +// }); + +// expectTypeOf(usersWithInvitee).toEqualTypeOf< +// { +// id: number; +// name: string; +// invitedBy: number | null; +// invitee: { +// id: number; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(usersWithInvitee.length).eq(2); +// expect(usersWithInvitee[0]?.invitee).not.toBeNull(); +// expect(usersWithInvitee[1]?.invitee).not.toBeNull(); + +// expect(usersWithInvitee).toContainEqual({ +// id: 3, +// name: 'Alex', +// invitedBy: 1, +// invitee: { id: 1, verified: false, invitedBy: null }, +// }); +// expect(usersWithInvitee).toContainEqual({ +// id: 4, +// name: 'John', +// invitedBy: 2, +// invitee: { id: 2, verified: false, invitedBy: null }, +// }); +// }); + +// /* +// Two first-level relations users+users and users+posts +// */ + +// test.skip('Get user with invitee and posts', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// with: { +// invitee: true, +// posts: true, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(4); + +// expect(response[0]?.invitee).toBeNull(); +// expect(response[1]?.invitee).toBeNull(); +// expect(response[2]?.invitee).not.toBeNull(); +// expect(response[3]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: response[0]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: response[1]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [{ id: 3, ownerId: 3, content: 'Post3', createdAt: response[2]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 4, +// name: 'John', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// posts: [], +// }); +// }); + +// test.skip('Get user with invitee and posts + limit posts and users', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// limit: 3, +// with: { +// invitee: true, +// posts: { +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(3); + +// expect(response[0]?.invitee).toBeNull(); +// expect(response[1]?.invitee).toBeNull(); +// expect(response[2]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: response[0]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 3, ownerId: 2, content: 'Post2', createdAt: response[1]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [{ id: 5, ownerId: 3, content: 'Post3', createdAt: response[2]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('Get user with invitee and posts + limits + custom fields in each', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// limit: 3, +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), +// with: { +// invitee: { +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_invitee_name') }), +// }, +// posts: { +// limit: 1, +// extras: (posts, { sql }) => ({ lower: sql`lower(${posts.content})`.as('lower_content') }), +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// lower: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(3); + +// expect(response[0]?.invitee).toBeNull(); +// expect(response[1]?.invitee).toBeNull(); +// expect(response[2]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', lower: 'post1', createdAt: response[0]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 3, ownerId: 2, content: 'Post2', lower: 'post2', createdAt: response[1]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, +// posts: [{ id: 5, ownerId: 3, content: 'Post3', lower: 'post3', createdAt: response[2]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('Get user with invitee and posts + custom fields in each', async () => { +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), +// with: { +// invitee: { +// extras: (users, { sql }) => ({ lower: sql`lower(${users.name})`.as('lower_name') }), +// }, +// posts: { +// extras: (posts, { sql }) => ({ lower: sql`lower(${posts.content})`.as('lower_name') }), +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// lower: string; +// invitedBy: number | null; +// posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// lower: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// response[0]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// response[1]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); +// response[2]?.posts.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(4); + +// expect(response[0]?.invitee).toBeNull(); +// expect(response[1]?.invitee).toBeNull(); +// expect(response[2]?.invitee).not.toBeNull(); +// expect(response[3]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(2); +// expect(response[1]?.posts.length).eq(2); +// expect(response[2]?.posts.length).eq(2); +// expect(response[3]?.posts.length).eq(0); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 1, ownerId: 1, content: 'Post1', lower: 'post1', createdAt: response[0]?.posts[0]?.createdAt }, { +// id: 2, +// ownerId: 1, +// content: 'Post1.1', +// lower: 'post1.1', +// createdAt: response[0]?.posts[1]?.createdAt, +// }], +// }); +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 3, ownerId: 2, content: 'Post2', lower: 'post2', createdAt: response[1]?.posts[0]?.createdAt }, { +// id: 4, +// ownerId: 2, +// content: 'Post2.1', +// lower: 'post2.1', +// createdAt: response[1]?.posts[1]?.createdAt, +// }], +// }); +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', lower: 'dan', verified: false, invitedBy: null }, +// posts: [{ id: 5, ownerId: 3, content: 'Post3', lower: 'post3', createdAt: response[2]?.posts[0]?.createdAt }, { +// id: 6, +// ownerId: 3, +// content: 'Post3.1', +// lower: 'post3.1', +// createdAt: response[2]?.posts[1]?.createdAt, +// }], +// }); +// expect(response).toContainEqual({ +// id: 4, +// name: 'John', +// lower: 'john', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', lower: 'andrew', verified: false, invitedBy: null }, +// posts: [], +// }); +// }); + +// test.skip('Get user with invitee and posts + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// orderBy: (users, { desc }) => [desc(users.id)], +// with: { +// invitee: true, +// posts: { +// orderBy: (posts, { desc }) => [desc(posts.id)], +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(response.length).eq(4); + +// expect(response[3]?.invitee).toBeNull(); +// expect(response[2]?.invitee).toBeNull(); +// expect(response[1]?.invitee).not.toBeNull(); +// expect(response[0]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(0); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(2); +// expect(response[3]?.posts.length).eq(2); + +// expect(response[3]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 2, ownerId: 1, content: 'Post1.1', createdAt: response[3]?.posts[0]?.createdAt }, { +// id: 1, +// ownerId: 1, +// content: 'Post1', +// createdAt: response[3]?.posts[1]?.createdAt, +// }], +// }); +// expect(response[2]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 4, ownerId: 2, content: 'Post2.1', createdAt: response[2]?.posts[0]?.createdAt }, { +// id: 3, +// ownerId: 2, +// content: 'Post2', +// createdAt: response[2]?.posts[1]?.createdAt, +// }], +// }); +// expect(response[1]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [{ +// id: 5, +// ownerId: 3, +// content: 'Post3', +// createdAt: response[3]?.posts[1]?.createdAt, +// }], +// }); +// expect(response[0]).toEqual({ +// id: 4, +// name: 'John', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// posts: [], +// }); +// }); + +// test.skip('Get user with invitee and posts + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 2), eq(users.id, 3))), +// with: { +// invitee: true, +// posts: { +// where: (posts, { eq }) => (eq(posts.ownerId, 2)), +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(2); + +// expect(response[0]?.invitee).toBeNull(); +// expect(response[1]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(0); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// invitee: null, +// posts: [{ id: 2, ownerId: 2, content: 'Post2', createdAt: response[0]?.posts[0]?.createdAt }], +// }); +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [], +// }); +// }); + +// test.skip('Get user with invitee and posts + limit posts and users + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// { ownerId: 3, content: 'Post3.1' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// where: (users, { eq, or }) => (or(eq(users.id, 3), eq(users.id, 4))), +// limit: 1, +// with: { +// invitee: true, +// posts: { +// where: (posts, { eq }) => (eq(posts.ownerId, 3)), +// limit: 1, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { id: number; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(response.length).eq(1); + +// expect(response[0]?.invitee).not.toBeNull(); +// expect(response[0]?.posts.length).eq(1); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [{ id: 5, ownerId: 3, content: 'Post3', createdAt: response[0]?.posts[0]?.createdAt }], +// }); +// }); + +// test.skip('Get user with invitee and posts + orderBy + where + custom', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// orderBy: [desc(usersTable.id)], +// where: or(eq(usersTable.id, 3), eq(usersTable.id, 4)), +// extras: { +// lower: sql`lower(${usersTable.name})`.as('lower_name'), +// }, +// with: { +// invitee: true, +// posts: { +// where: eq(postsTable.ownerId, 3), +// orderBy: [desc(postsTable.id)], +// extras: { +// lower: sql`lower(${postsTable.content})`.as('lower_name'), +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lower: string; +// posts: { id: number; lower: string; ownerId: number | null; content: string; createdAt: Date }[]; +// invitee: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[] +// >(); + +// expect(response.length).eq(2); + +// expect(response[1]?.invitee).not.toBeNull(); +// expect(response[0]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(0); +// expect(response[1]?.posts.length).eq(1); + +// expect(response[1]).toEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: 1, +// invitee: { id: 1, name: 'Dan', verified: false, invitedBy: null }, +// posts: [{ +// id: 5, +// ownerId: 3, +// content: 'Post3', +// lower: 'post3', +// createdAt: response[1]?.posts[0]?.createdAt, +// }], +// }); +// expect(response[0]).toEqual({ +// id: 4, +// name: 'John', +// lower: 'john', +// verified: false, +// invitedBy: 2, +// invitee: { id: 2, name: 'Andrew', verified: false, invitedBy: null }, +// posts: [], +// }); +// }); + +// test.skip('Get user with invitee and posts + orderBy + where + partial + custom', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex', invitedBy: 1 }, +// { id: 4, name: 'John', invitedBy: 2 }, +// ]); + +// await db.insert(postsTable).values([ +// { ownerId: 1, content: 'Post1' }, +// { ownerId: 1, content: 'Post1.1' }, +// { ownerId: 2, content: 'Post2' }, +// { ownerId: 2, content: 'Post2.1' }, +// { ownerId: 3, content: 'Post3' }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// orderBy: [desc(usersTable.id)], +// where: or(eq(usersTable.id, 3), eq(usersTable.id, 4)), +// extras: { +// lower: sql`lower(${usersTable.name})`.as('lower_name'), +// }, +// columns: { +// id: true, +// name: true, +// }, +// with: { +// invitee: { +// columns: { +// id: true, +// name: true, +// }, +// extras: { +// lower: sql`lower(${usersTable.name})`.as('lower_name'), +// }, +// }, +// posts: { +// columns: { +// id: true, +// content: true, +// }, +// where: eq(postsTable.ownerId, 3), +// orderBy: [desc(postsTable.id)], +// extras: { +// lower: sql`lower(${postsTable.content})`.as('lower_name'), +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// lower: string; +// posts: { id: number; lower: string; content: string }[]; +// invitee: { +// id: number; +// name: string; +// lower: string; +// } | null; +// }[] +// >(); + +// expect(response.length).eq(2); + +// expect(response[1]?.invitee).not.toBeNull(); +// expect(response[0]?.invitee).not.toBeNull(); + +// expect(response[0]?.posts.length).eq(0); +// expect(response[1]?.posts.length).eq(1); + +// expect(response[1]).toEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// invitee: { id: 1, name: 'Dan', lower: 'dan' }, +// posts: [{ +// id: 5, +// content: 'Post3', +// lower: 'post3', +// }], +// }); +// expect(response[0]).toEqual({ +// id: 4, +// name: 'John', +// lower: 'john', +// invitee: { id: 2, name: 'Andrew', lower: 'andrew' }, +// posts: [], +// }); +// }); + +// /* +// One two-level relation users+posts+comments +// */ + +// test.skip('Get user with posts and posts with comments', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { id: 1, ownerId: 1, content: 'Post1' }, +// { id: 2, ownerId: 2, content: 'Post2' }, +// { id: 3, ownerId: 3, content: 'Post3' }, +// ]); + +// await db.insert(commentsTable).values([ +// { postId: 1, content: 'Comment1', creator: 2 }, +// { postId: 2, content: 'Comment2', creator: 2 }, +// { postId: 3, content: 'Comment3', creator: 3 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// with: { +// posts: { +// with: { +// comments: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// comments: { +// id: number; +// content: string; +// createdAt: Date; +// creator: number | null; +// postId: number | null; +// }[]; +// }[]; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(3); +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(1); + +// expect(response[0]?.posts[0]?.comments.length).eq(1); +// expect(response[1]?.posts[0]?.comments.length).eq(1); +// expect(response[2]?.posts[0]?.comments.length).eq(1); + +// expect(response[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 1, +// ownerId: 1, +// content: 'Post1', +// createdAt: response[0]?.posts[0]?.createdAt, +// comments: [ +// { +// id: 1, +// content: 'Comment1', +// creator: 2, +// postId: 1, +// createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, +// }, +// ], +// }], +// }); +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 2, +// ownerId: 2, +// content: 'Post2', +// createdAt: response[1]?.posts[0]?.createdAt, +// comments: [ +// { +// id: 2, +// content: 'Comment2', +// creator: 2, +// postId: 2, +// createdAt: response[1]?.posts[0]?.comments[0]?.createdAt, +// }, +// ], +// }], +// }); +// // expect(response[2]).toEqual({ +// // id: 3, +// // name: 'Alex', +// // verified: false, +// // invitedBy: null, +// // posts: [{ +// // id: 3, +// // ownerId: 3, +// // content: 'Post3', +// // createdAt: response[2]?.posts[0]?.createdAt, +// // comments: [ +// // { +// // id: , +// // content: 'Comment3', +// // creator: 3, +// // postId: 3, +// // createdAt: response[2]?.posts[0]?.comments[0]?.createdAt, +// // }, +// // ], +// // }], +// // }); +// }); + +// // Get user with limit posts and limit comments + +// // Get user with custom field + post + comment with custom field + +// // Get user with limit + posts orderBy + comment orderBy + +// // Get user with where + posts where + comment where + +// // Get user with where + posts partial where + comment where + +// // Get user with where + posts partial where + comment partial(false) where + +// // Get user with where partial(false) + posts partial where partial(false) + comment partial(false+true) where + +// // Get user with where + posts partial where + comment where. Didn't select field from where in posts + +// // Get user with where + posts partial where + comment where. Didn't select field from where for all + +// // Get with limit+offset in each + +// /* +// One two-level + One first-level relation users+posts+comments and users+users +// */ + +// /* +// One three-level relation users+posts+comments+comment_owner +// */ + +// test.skip('Get user with posts and posts with comments and comments with owner', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { id: 1, ownerId: 1, content: 'Post1' }, +// { id: 2, ownerId: 2, content: 'Post2' }, +// { id: 3, ownerId: 3, content: 'Post3' }, +// ]); + +// await db.insert(commentsTable).values([ +// { postId: 1, content: 'Comment1', creator: 2 }, +// { postId: 2, content: 'Comment2', creator: 2 }, +// { postId: 3, content: 'Comment3', creator: 3 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// with: { +// posts: { +// with: { +// comments: { +// with: { +// author: true, +// }, +// }, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// comments: { +// id: number; +// content: string; +// createdAt: Date; +// creator: number | null; +// postId: number | null; +// author: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[]; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).eq(3); +// expect(response[0]?.posts.length).eq(1); +// expect(response[1]?.posts.length).eq(1); +// expect(response[2]?.posts.length).eq(1); + +// expect(response[0]?.posts[0]?.comments.length).eq(1); +// expect(response[1]?.posts[0]?.comments.length).eq(1); +// expect(response[2]?.posts[0]?.comments.length).eq(1); + +// expect(response[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 1, +// ownerId: 1, +// content: 'Post1', +// createdAt: response[0]?.posts[0]?.createdAt, +// comments: [ +// { +// id: 1, +// content: 'Comment1', +// creator: 2, +// author: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// postId: 1, +// createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, +// }, +// ], +// }], +// }); +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 2, +// ownerId: 2, +// content: 'Post2', +// createdAt: response[1]?.posts[0]?.createdAt, +// comments: [ +// { +// id: 2, +// content: 'Comment2', +// creator: 2, +// author: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// postId: 2, +// createdAt: response[1]?.posts[0]?.comments[0]?.createdAt, +// }, +// ], +// }], +// }); +// }); + +// test.skip('Get user with posts and posts with comments and comments with owner where exists', async () => { +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(postsTable).values([ +// { id: 1, ownerId: 1, content: 'Post1' }, +// { id: 2, ownerId: 2, content: 'Post2' }, +// { id: 3, ownerId: 3, content: 'Post3' }, +// ]); + +// await db.insert(commentsTable).values([ +// { postId: 1, content: 'Comment1', creator: 2 }, +// { postId: 2, content: 'Comment2', creator: 2 }, +// { postId: 3, content: 'Comment3', creator: 3 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// with: { +// posts: { +// with: { +// comments: { +// with: { +// author: true, +// }, +// }, +// }, +// }, +// }, +// where: (table, { exists, eq }) => exists(db.select({ one: sql`1` }).from(usersTable).where(eq(sql`1`, table.id))), +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// posts: { +// id: number; +// content: string; +// ownerId: number | null; +// createdAt: Date; +// comments: { +// id: number; +// content: string; +// createdAt: Date; +// creator: number | null; +// postId: number | null; +// author: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// } | null; +// }[]; +// }[]; +// }[]>(); + +// expect(response.length).eq(1); +// expect(response[0]?.posts.length).eq(1); + +// expect(response[0]?.posts[0]?.comments.length).eq(1); + +// expect(response[0]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// posts: [{ +// id: 1, +// ownerId: 1, +// content: 'Post1', +// createdAt: response[0]?.posts[0]?.createdAt, +// comments: [ +// { +// id: 1, +// content: 'Comment1', +// creator: 2, +// author: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// postId: 1, +// createdAt: response[0]?.posts[0]?.comments[0]?.createdAt, +// }, +// ], +// }], +// }); +// }); + +// /* +// One three-level relation + 1 first-level relatioon +// 1. users+posts+comments+comment_owner +// 2. users+users +// */ + +// /* +// One four-level relation users+posts+comments+coment_likes +// */ + +// /* +// [Find Many] Many-to-many cases + +// Users+users_to_groups+groups +// */ + +// test.skip('[Find Many] Get users with groups', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); +// expect(response[2]?.usersToGroups.length).toEqual(2); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// description: null, +// }, +// }, { +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get groups with users', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(2); +// expect(response[2]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }, { +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Group3', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get users with groups + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// limit: 2, +// with: { +// usersToGroups: { +// limit: 1, +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get groups with users + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// limit: 2, +// with: { +// usersToGroups: { +// limit: 1, +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get users with groups + limit + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// limit: 1, +// where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.groupId, 1), +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(1); + +// expect(response[0]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get groups with users + limit + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// limit: 1, +// where: gt(groupsTable.id, 1), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.userId, 2), +// limit: 1, +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(1); + +// expect(response[0]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get users with groups + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.groupId, 2), +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(0); +// expect(response[1]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get groups with users + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// where: gt(groupsTable.id, 1), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.userId, 2), +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[]>(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(0); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Group3', +// description: null, +// usersToGroups: [], +// }); +// }); + +// test.skip('[Find Many] Get users with groups + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// orderBy: (users, { desc }) => [desc(users.id)], +// with: { +// usersToGroups: { +// orderBy: [desc(usersToGroupsTable.groupId)], +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(2); +// expect(response[1]?.usersToGroups.length).toEqual(1); +// expect(response[2]?.usersToGroups.length).toEqual(1); + +// expect(response[2]).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); + +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); + +// expect(response[0]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// description: null, +// }, +// }, { +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get groups with users + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// orderBy: [desc(groupsTable.id)], +// with: { +// usersToGroups: { +// orderBy: (utg, { desc }) => [desc(utg.userId)], +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[]>(); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(2); +// expect(response[2]?.usersToGroups.length).toEqual(1); + +// expect(response[2]).toEqual({ +// id: 1, +// name: 'Group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }, { +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response[0]).toEqual({ +// id: 3, +// name: 'Group3', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find Many] Get users with groups + orderBy + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// orderBy: (users, { desc }) => [desc(users.id)], +// limit: 2, +// with: { +// usersToGroups: { +// limit: 1, +// orderBy: [desc(usersToGroupsTable.groupId)], +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf<{ +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// }[]>(); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); + +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); + +// expect(response[0]).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// description: null, +// }, +// }], +// }); +// }); + +// /* +// [Find One] Many-to-many cases + +// Users+users_to_groups+groups +// */ + +// test.skip('[Find One] Get users with groups', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get groups with users', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findFirst({ +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 1, +// name: 'Group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get users with groups + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// with: { +// usersToGroups: { +// limit: 1, +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get groups with users + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findFirst({ +// with: { +// usersToGroups: { +// limit: 1, +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 1, +// name: 'Group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get users with groups + limit + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.groupId, 1), +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get groups with users + limit + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findFirst({ +// where: gt(groupsTable.id, 1), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.userId, 2), +// limit: 1, +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get users with groups + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 2, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// where: (_, { eq, or }) => or(eq(usersTable.id, 1), eq(usersTable.id, 2)), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.groupId, 2), +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(0); + +// expect(response).toEqual({ +// id: 1, +// name: 'Dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [], +// }); +// }); + +// test.skip('[Find One] Get groups with users + where', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findFirst({ +// where: gt(groupsTable.id, 1), +// with: { +// usersToGroups: { +// where: eq(usersToGroupsTable.userId, 2), +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get users with groups + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// orderBy: (users, { desc }) => [desc(users.id)], +// with: { +// usersToGroups: { +// orderBy: [desc(usersToGroupsTable.groupId)], +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(2); + +// expect(response).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// description: null, +// }, +// }, { +// group: { +// id: 2, +// name: 'Group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get groups with users + orderBy', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findFirst({ +// orderBy: [desc(groupsTable.id)], +// with: { +// usersToGroups: { +// orderBy: (utg, { desc }) => [desc(utg.userId)], +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 3, +// name: 'Group3', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('[Find One] Get users with groups + orderBy + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findFirst({ +// orderBy: (users, { desc }) => [desc(users.id)], +// with: { +// usersToGroups: { +// limit: 1, +// orderBy: [desc(usersToGroupsTable.groupId)], +// columns: {}, +// with: { +// group: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// }; +// }[]; +// } | undefined +// >(); + +// expect(response?.usersToGroups.length).toEqual(1); + +// expect(response).toEqual({ +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('Get groups with users + orderBy + limit', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// orderBy: [desc(groupsTable.id)], +// limit: 2, +// with: { +// usersToGroups: { +// limit: 1, +// orderBy: (utg, { desc }) => [desc(utg.userId)], +// columns: {}, +// with: { +// user: true, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// }; +// }[]; +// }[] +// >(); + +// expect(response.length).toEqual(2); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); + +// expect(response[1]).toEqual({ +// id: 2, +// name: 'Group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response[0]).toEqual({ +// id: 3, +// name: 'Group3', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test.skip('Get users with groups + custom', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.usersTable.findMany({ +// extras: { +// lower: sql`lower(${usersTable.name})`.as('lower_name'), +// }, +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// group: { +// extras: { +// lower: sql`lower(${groupsTable.name})`.as('lower_name'), +// }, +// }, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lower: string; +// usersToGroups: { +// group: { +// id: number; +// name: string; +// description: string | null; +// lower: string; +// }; +// }[]; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(1); +// expect(response[2]?.usersToGroups.length).toEqual(2); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 1, +// name: 'Group1', +// lower: 'group1', +// description: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 2, +// name: 'Group2', +// lower: 'group2', +// description: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: null, +// usersToGroups: [{ +// group: { +// id: 3, +// name: 'Group3', +// lower: 'group3', +// description: null, +// }, +// }, { +// group: { +// id: 2, +// name: 'Group2', +// lower: 'group2', +// description: null, +// }, +// }], +// }); +// }); + +// test.skip('Get groups with users + custom', async (t) => { +// const { singlestoreDb: db } = t; + +// await db.insert(usersTable).values([ +// { id: 1, name: 'Dan' }, +// { id: 2, name: 'Andrew' }, +// { id: 3, name: 'Alex' }, +// ]); + +// await db.insert(groupsTable).values([ +// { id: 1, name: 'Group1' }, +// { id: 2, name: 'Group2' }, +// { id: 3, name: 'Group3' }, +// ]); + +// await db.insert(usersToGroupsTable).values([ +// { userId: 1, groupId: 1 }, +// { userId: 2, groupId: 2 }, +// { userId: 3, groupId: 3 }, +// { userId: 3, groupId: 2 }, +// ]); + +// const response = await db.query.groupsTable.findMany({ +// extras: (table, { sql }) => ({ +// lower: sql`lower(${table.name})`.as('lower_name'), +// }), +// with: { +// usersToGroups: { +// columns: {}, +// with: { +// user: { +// extras: (table, { sql }) => ({ +// lower: sql`lower(${table.name})`.as('lower_name'), +// }), +// }, +// }, +// }, +// }, +// }); + +// expectTypeOf(response).toEqualTypeOf< +// { +// id: number; +// name: string; +// description: string | null; +// lower: string; +// usersToGroups: { +// user: { +// id: number; +// name: string; +// verified: boolean; +// invitedBy: number | null; +// lower: string; +// }; +// }[]; +// }[] +// >(); + +// response.sort((a, b) => (a.id > b.id) ? 1 : -1); + +// expect(response.length).toEqual(3); + +// expect(response[0]?.usersToGroups.length).toEqual(1); +// expect(response[1]?.usersToGroups.length).toEqual(2); +// expect(response[2]?.usersToGroups.length).toEqual(1); + +// expect(response).toContainEqual({ +// id: 1, +// name: 'Group1', +// lower: 'group1', +// description: null, +// usersToGroups: [{ +// user: { +// id: 1, +// name: 'Dan', +// lower: 'dan', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 2, +// name: 'Group2', +// lower: 'group2', +// description: null, +// usersToGroups: [{ +// user: { +// id: 2, +// name: 'Andrew', +// lower: 'andrew', +// verified: false, +// invitedBy: null, +// }, +// }, { +// user: { +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); + +// expect(response).toContainEqual({ +// id: 3, +// name: 'Group3', +// lower: 'group3', +// description: null, +// usersToGroups: [{ +// user: { +// id: 3, +// name: 'Alex', +// lower: 'alex', +// verified: false, +// invitedBy: null, +// }, +// }], +// }); +// }); + +// test('.toSQL()', () => { +// const query = db.query.usersTable.findFirst().toSQL(); + +// expect(query).toHaveProperty('sql', expect.any(String)); +// expect(query).toHaveProperty('params', expect.any(Array)); +// }); + +// // + custom + where + orderby + +// // + custom + where + orderby + limit + +// // + partial + +// // + partial(false) + +// // + partial + orderBy + where (all not selected) + +// /* +// One four-level relation users+posts+comments+coment_likes +// + users+users_to_groups+groups +// */ + +// /* +// Really hard case +// 1. users+posts+comments+coment_likes +// 2. users+users_to_groups+groups +// 3. users+users +// */ +// eslint-disable-next-line unicorn/no-empty-file diff --git a/integration-tests/tests/replicas/singlestore.test.ts b/integration-tests/tests/replicas/singlestore.test.ts new file mode 100644 index 000000000..8ddad5b04 --- /dev/null +++ b/integration-tests/tests/replicas/singlestore.test.ts @@ -0,0 +1,814 @@ +import { sql } from 'drizzle-orm'; +import { drizzle } from 'drizzle-orm/singlestore'; +import { serial, singlestoreTable, withReplicas } from 'drizzle-orm/singlestore-core'; +import { describe, expect, it, vi } from 'vitest'; + +// const usersTable = singlestoreTable('users', { +// id: serial('id' as string).primaryKey(), +// name: text('name').notNull(), +// verified: boolean('verified').notNull().default(false), +// }); + +const users = singlestoreTable('users', { + id: serial('id' as string).primaryKey(), +}); + +describe('[select] read replicas singlestore', () => { + it('primary select', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + const query = db.$primary.select().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(query.toSQL().sql).toEqual('select `id` from `users`'); + + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica select', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + const query1 = db.select({ count: sql`count(*)`.as('count') }).from(users).limit(1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(query1.toSQL().sql).toEqual('select count(*) as `count` from `users` limit ?'); + + const query2 = db.select().from(users); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); + + it('single read replica select', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + const query1 = db.select().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select `id` from `users`'); + + const query2 = db.select().from(users); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); + + it('single read replica select + primary select', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + const query1 = db.select({ id: users.id }).from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select `id` from `users`'); + + const query2 = db.$primary.select().from(users); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); + + it('always first read select', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + const query1 = db.select().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('select `id` from `users`'); + + const query2 = db.select().from(users); + + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query2.toSQL().sql).toEqual('select `id` from `users`'); + }); +}); + +describe('[selectDistinct] read replicas singlestore', () => { + it('primary selectDistinct', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + const query = db.$primary.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('random replica selectDistinct', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.selectDistinct().from(users); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('single read replica selectDistinct', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.selectDistinct().from(users); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('single read replica selectDistinct + primary selectDistinct', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.$primary.selectDistinct().from(users); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); + + it('always first read selectDistinct', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + const query1 = db.selectDistinct().from(users); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('select distinct `id` from `users`'); + + const query2 = db.selectDistinct().from(users); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query2.toSQL().sql).toEqual('select distinct `id` from `users`'); + }); +}); + +describe('[with] read replicas singlestore', () => { + it('primary with', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + const obj1 = {} as any; + const obj2 = {} as any; + const obj3 = {} as any; + const obj4 = {} as any; + + db.$primary.with(obj1, obj2, obj3, obj4); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(obj1, obj2, obj3, obj4); + }); + + it('random replica with', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica with', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica with + primary with', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.with(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read with', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + const obj1 = {} as any; + const obj2 = {} as any; + const obj3 = {} as any; + + db.with(obj1); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledWith(obj1); + + db.with(obj2, obj3); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledWith(obj2, obj3); + }); +}); + +describe('[update] replicas singlestore', () => { + it('primary update', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'update'); + const spyRead1 = vi.spyOn(read1, 'update'); + const spyRead2 = vi.spyOn(read2, 'update'); + + const query1 = db.update(users).set({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query1.toSQL().sql).toEqual('update `users` set `id` = ?'); + + const query2 = db.update(users).set({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query2.toSQL().sql).toEqual('update `users` set `id` = ?'); + + const query3 = db.$primary.update(users).set({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(query3.toSQL().sql).toEqual('update `users` set `id` = ?'); + }); +}); + +describe('[delete] replicas singlestore', () => { + it('primary delete', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'delete'); + const spyRead1 = vi.spyOn(read1, 'delete'); + const spyRead2 = vi.spyOn(read2, 'delete'); + + const query1 = db.delete(users); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(users); + expect(query1.toSQL().sql).toEqual('delete from `users`'); + + const query2 = db.delete(users); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenNthCalledWith(2, users); + expect(query2.toSQL().sql).toEqual('delete from `users`'); + + db.$primary.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[insert] replicas singlestore', () => { + it('primary insert', () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'insert'); + const spyRead1 = vi.spyOn(read1, 'insert'); + const spyRead2 = vi.spyOn(read2, 'insert'); + + const query = db.insert(users).values({ id: 1 }); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(users); + expect(query.toSQL().sql).toEqual('insert into `users` (`id`) values (?)'); + + db.insert(users); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenNthCalledWith(2, users); + + db.$primary.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[execute] replicas singlestore', () => { + it('primary execute', async () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'execute'); + const spyRead1 = vi.spyOn(read1, 'execute'); + const spyRead2 = vi.spyOn(read2, 'execute'); + + expect(db.execute(sql``)).rejects.toThrow(); + + // try { + // db.execute(sql``); + // } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.execute(sql``)).rejects.toThrow(); + // try { + // db.execute(sql``); + // } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.execute(sql``)).rejects.toThrow(); + // try { + // db.execute(sql``); + // } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[transaction] replicas singlestore', () => { + it('primary transaction', async () => { + const primaryDb = drizzle.mock(); + const read1 = drizzle.mock(); + const read2 = drizzle.mock(); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'transaction'); + const spyRead1 = vi.spyOn(read1, 'transaction'); + const spyRead2 = vi.spyOn(read2, 'transaction'); + const txFn1 = async (tx: any) => { + tx.select().from({} as any); + }; + + expect(db.transaction(txFn1)).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenCalledWith(txFn1); + + const txFn2 = async (tx: any) => { + tx.select().from({} as any); + }; + + expect(db.transaction(txFn2)).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + expect(spyPrimary).toHaveBeenNthCalledWith(2, txFn2); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +// We are waiting for SingleStore support for `json_array` function +// describe('[findFirst] read replicas singlestore', () => { +// // it('primary findFirst', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); + +// // const db = withReplicas(primaryDb, [read1, read2]); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); +// // const obj = {} as any; + +// // db.$primary.query.usersTable.findFirst(obj); + +// // expect(spyPrimary).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledTimes(0); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(spyPrimary).toHaveBeenCalledWith(obj); +// // }); + +// // it('random replica findFirst', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); + +// // const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + +// // const db = withReplicas(primaryDb, [read1, read2], () => { +// // return randomMockReplica(); +// // }); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); +// // const par1 = {} as any; + +// // db.query.usersTable.findFirst(par1); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledWith(par1); + +// // const query = db.query.usersTable.findFirst(); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(1); +// // expect(query.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable` limit ?'); +// // }); + +// // We are waiting for SingleStore support for `json_array` function +// // it('single read replica findFirst', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); + +// // const db = withReplicas(primaryDb, [read1]); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + +// // db.query.usersTable.findFirst(); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); + +// // db.query.usersTable.findFirst(); +// // expect(spyRead1).toHaveBeenCalledTimes(2); +// // }); + +// // We are waiting for SingleStore support for `json_array` function +// // it('single read replica findFirst + primary findFirst', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); + +// // const db = withReplicas(primaryDb, [read1]); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + +// // db.query.usersTable.findFirst(); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); + +// // db.$primary.query.usersTable.findFirst(); +// // expect(spyPrimary).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // }); + +// // We are waiting for SingleStore support for `json_array` function +// // it('always first read findFirst', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); + +// // const db = withReplicas(primaryDb, [read1, read2], (replicas) => { +// // return replicas[0]!; +// // }); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + +// // db.query.usersTable.findFirst(); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(0); + +// // db.query.usersTable.findFirst(); +// // expect(spyRead1).toHaveBeenCalledTimes(2); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // }); +// }); + +// describe('[findMany] read replicas singlestore', () => { +// // We are waiting for SingleStore support for `json_array` function +// // it('primary findMany', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); + +// // const db = withReplicas(primaryDb, [read1, read2]); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); +// // const obj = {} as any; + +// // const query = db.$primary.query.usersTable.findMany(obj); + +// // expect(spyPrimary).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledTimes(0); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(spyPrimary).toHaveBeenCalledWith(obj); +// // expect(query.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // }); + +// // We are waiting for SingleStore support for `json_array` function +// // it('random replica findMany', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); + +// // const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + +// // const db = withReplicas(primaryDb, [read1, read2], () => { +// // return randomMockReplica(); +// // }); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); +// // const obj1 = {} as any; +// // const obj2 = {} as any; + +// // const query1 = db.query.usersTable.findMany(obj1); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // expect(spyRead1).toHaveBeenCalledWith(obj1); + +// // const query2 = db.query.usersTable.findMany(obj2); + +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(1); +// // expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // expect(spyRead2).toHaveBeenCalledWith(obj2); +// // }); + +// // We are waiting for SingleStore support for `json_array` function +// // it('single read replica findMany', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); + +// // const db = withReplicas(primaryDb, [read1]); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); +// // const obj1 = {} as any; +// // const obj2 = {} as any; + +// // const query1 = db.query.usersTable.findMany(obj1); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledWith(obj1); +// // expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + +// // const query2 = db.query.usersTable.findMany(obj2); +// // expect(spyRead1).toHaveBeenCalledTimes(2); +// // expect(spyRead1).toHaveBeenNthCalledWith(2, obj2); +// // expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // }); + +// // We are waiting for SingleStore support for `json_array` function +// // it('single read replica findMany + primary findMany', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); + +// // const db = withReplicas(primaryDb, [read1]); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); +// // const obj1 = {} as any; +// // const obj2 = {} as any; + +// // const query1 = db.query.usersTable.findMany(obj1); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledWith(obj1); +// // expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + +// // const query2 = db.$primary.query.usersTable.findMany(obj2); + +// // expect(spyPrimary).toHaveBeenCalledTimes(1); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyPrimary).toHaveBeenNthCalledWith(1, obj2); +// // expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // }); + +// // We are waiting for SingleStore support for `json_array` function +// // it('always first read findMany', () => { +// // const primaryDb = drizzle.mock({ schema: { usersTable } }); +// // const read1 = drizzle.mock({ schema: { usersTable } }); +// // const read2 = drizzle.mock({ schema: { usersTable } }); + +// // const db = withReplicas(primaryDb, [read1, read2], (replicas) => { +// // return replicas[0]!; +// // }); + +// // const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); +// // const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); +// // const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); +// // const obj1 = {} as any; +// // const obj2 = {} as any; + +// // const query1 = db.query.usersTable.findMany(obj1); + +// // expect(spyPrimary).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledTimes(1); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenCalledWith(obj1); +// // expect(query1.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); + +// // const query2 = db.query.usersTable.findMany(obj2); +// // expect(spyRead1).toHaveBeenCalledTimes(2); +// // expect(spyRead2).toHaveBeenCalledTimes(0); +// // expect(spyRead1).toHaveBeenNthCalledWith(2, obj2); +// // expect(query2.toSQL().sql).toEqual('select `id`, `name`, `verified` from `users` `usersTable`'); +// // }); +// }); diff --git a/integration-tests/tests/singlestore/singlestore-common.ts b/integration-tests/tests/singlestore/singlestore-common.ts new file mode 100644 index 000000000..6335bf9ec --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-common.ts @@ -0,0 +1,3429 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import 'dotenv/config'; +import Docker from 'dockerode'; +import { + and, + asc, + avg, + avgDistinct, + count, + countDistinct, + eq, + exists, + getTableColumns, + gt, + gte, + inArray, + lt, + max, + min, + Name, + notInArray, + placeholder, + sql, + sum, + sumDistinct, + TransactionRollbackError, +} from 'drizzle-orm'; +import type { SingleStoreDatabase } from 'drizzle-orm/singlestore-core'; +import { + alias, + bigint, + boolean, + date, + datetime, + decimal, + except, + getTableConfig, + int, + intersect, + json, + mediumint, + primaryKey, + serial, + singlestoreEnum, + singlestoreSchema, + singlestoreTable, + singlestoreTableCreator, + /* singlestoreView, */ + smallint, + text, + time, + timestamp, + tinyint, + union, + unionAll, + unique, + uniqueIndex, + uniqueKeyName, + varchar, + year, +} from 'drizzle-orm/singlestore-core'; +import { migrate } from 'drizzle-orm/singlestore/migrator'; +import getPort from 'get-port'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeEach, describe, expect, expectTypeOf, test } from 'vitest'; +import { Expect, toLocalDate } from '~/utils.ts'; +import type { Equal } from '~/utils.ts'; + +type TestSingleStoreDB = SingleStoreDatabase; + +declare module 'vitest' { + interface TestContext { + singlestore: { + db: TestSingleStoreDB; + }; + } +} + +const ENABLE_LOGGING = false; + +const usersTable = singlestoreTable('userstest', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: json('jsonb').$type(), + createdAt: timestamp('created_at').notNull().defaultNow(), +}); + +const users2Table = singlestoreTable('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id'), +}); + +const citiesTable = singlestoreTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +const usersOnUpdate = singlestoreTable('users_on_update', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + updateCounter: int('update_counter').default(sql`1`).$onUpdateFn(() => sql`update_counter + 1`), + updatedAt: datetime('updated_at', { mode: 'date' }).$onUpdateFn(() => new Date()), + alwaysNull: text('always_null').$type().$onUpdateFn(() => null), // need to add $type because $onUpdate add a default value +}); + +const datesTable = singlestoreTable('datestable', { + date: date('date'), + dateAsString: date('date_as_string', { mode: 'string' }), + time: time('time'), + datetime: datetime('datetime'), + datetimeAsString: datetime('datetime_as_string', { mode: 'string' }), + timestamp: timestamp('timestamp'), + timestampAsString: timestamp('timestamp_as_string', { mode: 'string' }), + year: year('year'), +}); + +const coursesTable = singlestoreTable('courses', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + categoryId: int('category_id'), +}); + +const courseCategoriesTable = singlestoreTable('course_categories', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +const orders = singlestoreTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull().$default(() => 'random_string'), + amount: int('amount').notNull(), + quantity: int('quantity').notNull(), +}); + +const usersMigratorTable = singlestoreTable('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}, (table) => { + return { + name: uniqueIndex('').on(table.name).using('btree'), + }; +}); + +// To test aggregate functions +const aggregateTable = singlestoreTable('aggregate_table', { + id: serial('id').notNull(), + name: text('name').notNull(), + a: int('a'), + b: int('b'), + c: int('c'), + nullOnly: int('null_only'), +}); + +// To test another schema and multischema +const mySchema = singlestoreSchema(`mySchema`); + +const usersMySchemaTable = mySchema.table('userstest', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: json('jsonb').$type(), + createdAt: timestamp('created_at').notNull().defaultNow(), +}); + +const users2MySchemaTable = mySchema.table('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id'), +}); + +const citiesMySchemaTable = mySchema.table('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +let singlestoreContainer: Docker.Container; +export async function createDockerDB(): Promise<{ connectionString: string; container: Docker.Container }> { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + ); + + singlestoreContainer = await docker.createContainer({ + Image: image, + Env: ['ROOT_PASSWORD=singlestore'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await singlestoreContainer.start(); + await new Promise((resolve) => setTimeout(resolve, 4000)); + + return { + connectionString: `singlestore://root:singlestore@localhost:${port}/`, + container: singlestoreContainer, + }; +} + +export function tests(driver?: string) { + describe('common', () => { + afterAll(async () => { + await singlestoreContainer?.stop().catch(console.error); + }); + + beforeEach(async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`drop table if exists userstest`); + await db.execute(sql`drop table if exists users2`); + await db.execute(sql`drop table if exists cities`); + + await db.execute(sql`drop schema if exists \`mySchema\``); + await db.execute(sql`create schema if not exists \`mySchema\``); + + await db.execute( + sql` + create table userstest ( + id serial primary key, + name text not null, + verified boolean not null default false, + jsonb json, + created_at timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table users2 ( + id serial primary key, + name text not null, + city_id int + ) + `, + ); + + await db.execute( + sql` + create table cities ( + id serial primary key, + name text not null + ) + `, + ); + + // mySchema + await db.execute( + sql` + create table \`mySchema\`.\`userstest\` ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table \`mySchema\`.\`cities\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.execute( + sql` + create table \`mySchema\`.\`users2\` ( + \`id\` serial primary key, + \`name\` text not null, + \`city_id\` int + ) + `, + ); + }); + + async function setupReturningFunctionsTest(db: SingleStoreDatabase) { + await db.execute(sql`drop table if exists \`users_default_fn\``); + await db.execute( + sql` + create table \`users_default_fn\` ( + \`id\` varchar(256) primary key, + \`name\` text not null + ); + `, + ); + } + + async function setupSetOperationTest(db: TestSingleStoreDB) { + await db.execute(sql`drop table if exists \`users2\``); + await db.execute(sql`drop table if exists \`cities\``); + await db.execute( + sql` + create table \`users2\` ( + \`id\` serial primary key, + \`name\` text not null, + \`city_id\` int + ) + `, + ); + + await db.execute( + sql` + create table \`cities\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.insert(citiesTable).values([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 3 }, + { id: 4, name: 'Peter', cityId: 3 }, + { id: 5, name: 'Ben', cityId: 2 }, + { id: 6, name: 'Jill', cityId: 1 }, + { id: 7, name: 'Mary', cityId: 2 }, + { id: 8, name: 'Sally', cityId: 1 }, + ]); + } + + async function setupAggregateFunctionsTest(db: TestSingleStoreDB) { + await db.execute(sql`drop table if exists \`aggregate_table\``); + await db.execute( + sql` + create table \`aggregate_table\` ( + \`id\` integer primary key auto_increment not null, + \`name\` text not null, + \`a\` integer, + \`b\` integer, + \`c\` integer, + \`null_only\` integer + ); + `, + ); + await db.insert(aggregateTable).values([ + { id: 1, name: 'value 1', a: 5, b: 10, c: 20 }, + { id: 2, name: 'value 1', a: 5, b: 20, c: 30 }, + { id: 3, name: 'value 2', a: 10, b: 50, c: 60 }, + { id: 4, name: 'value 3', a: 20, b: 20, c: null }, + { id: 5, name: 'value 4', a: null, b: 90, c: 120 }, + { id: 6, name: 'value 5', a: 80, b: 10, c: null }, + { id: 7, name: 'value 6', a: null, b: null, c: 150 }, + ]); + } + + test('table config: unsigned ints', async () => { + const unsignedInts = singlestoreTable('cities1', { + bigint: bigint('bigint', { mode: 'number', unsigned: true }), + int: int('int', { unsigned: true }), + smallint: smallint('smallint', { unsigned: true }), + mediumint: mediumint('mediumint', { unsigned: true }), + tinyint: tinyint('tinyint', { unsigned: true }), + }); + + const tableConfig = getTableConfig(unsignedInts); + + const bigintColumn = tableConfig.columns.find((c) => c.name === 'bigint')!; + const intColumn = tableConfig.columns.find((c) => c.name === 'int')!; + const smallintColumn = tableConfig.columns.find((c) => c.name === 'smallint')!; + const mediumintColumn = tableConfig.columns.find((c) => c.name === 'mediumint')!; + const tinyintColumn = tableConfig.columns.find((c) => c.name === 'tinyint')!; + + expect(bigintColumn.getSQLType()).toBe('bigint unsigned'); + expect(intColumn.getSQLType()).toBe('int unsigned'); + expect(smallintColumn.getSQLType()).toBe('smallint unsigned'); + expect(mediumintColumn.getSQLType()).toBe('mediumint unsigned'); + expect(tinyintColumn.getSQLType()).toBe('tinyint unsigned'); + }); + + test('table config: signed ints', async () => { + const unsignedInts = singlestoreTable('cities1', { + bigint: bigint('bigint', { mode: 'number' }), + int: int('int'), + smallint: smallint('smallint'), + mediumint: mediumint('mediumint'), + tinyint: tinyint('tinyint'), + }); + + const tableConfig = getTableConfig(unsignedInts); + + const bigintColumn = tableConfig.columns.find((c) => c.name === 'bigint')!; + const intColumn = tableConfig.columns.find((c) => c.name === 'int')!; + const smallintColumn = tableConfig.columns.find((c) => c.name === 'smallint')!; + const mediumintColumn = tableConfig.columns.find((c) => c.name === 'mediumint')!; + const tinyintColumn = tableConfig.columns.find((c) => c.name === 'tinyint')!; + + expect(bigintColumn.getSQLType()).toBe('bigint'); + expect(intColumn.getSQLType()).toBe('int'); + expect(smallintColumn.getSQLType()).toBe('smallint'); + expect(mediumintColumn.getSQLType()).toBe('mediumint'); + expect(tinyintColumn.getSQLType()).toBe('tinyint'); + }); + + test('table config: primary keys name', async () => { + const table = singlestoreTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: primaryKey({ columns: [t.id, t.name], name: 'custom_pk' }), + })); + + const tableConfig = getTableConfig(table); + + expect(tableConfig.primaryKeys).toHaveLength(1); + expect(tableConfig.primaryKeys[0]!.getName()).toBe('custom_pk'); + }); + + test('table configs: unique third param', async () => { + const cities1Table = singlestoreTable('cities1', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: unique('custom_name').on(t.name, t.state), + f1: unique('custom_name1').on(t.name, t.state), + })); + + const tableConfig = getTableConfig(cities1Table); + + expect(tableConfig.uniqueConstraints).toHaveLength(2); + + expect(tableConfig.uniqueConstraints[0]?.name).toBe('custom_name'); + expect(tableConfig.uniqueConstraints[0]?.columns.map((t) => t.name)).toEqual(['name', 'state']); + + expect(tableConfig.uniqueConstraints[1]?.name).toBe('custom_name1'); + expect(tableConfig.uniqueConstraints[1]?.columns.map((t) => t.name)).toEqual(['name', 'state']); + }); + + test('table configs: unique in column', async () => { + const cities1Table = singlestoreTable('cities1', { + id: serial('id').primaryKey(), + name: text('name').notNull().unique(), + state: text('state').unique('custom'), + field: text('field').unique('custom_field'), + }); + + const tableConfig = getTableConfig(cities1Table); + + const columnName = tableConfig.columns.find((it) => it.name === 'name'); + expect(columnName?.uniqueName).toBe(uniqueKeyName(cities1Table, [columnName!.name])); + expect(columnName?.isUnique).toBeTruthy(); + + const columnState = tableConfig.columns.find((it) => it.name === 'state'); + expect(columnState?.uniqueName).toBe('custom'); + expect(columnState?.isUnique).toBeTruthy(); + + const columnField = tableConfig.columns.find((it) => it.name === 'field'); + expect(columnField?.uniqueName).toBe('custom_field'); + expect(columnField?.isUnique).toBeTruthy(); + }); + + test('select all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('select sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('select typed sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('select with empty array in inArray', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + const result = await db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(inArray(usersTable.id, [])) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([]); + }); + + test('select with empty array in notInArray', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + const result = await db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(notInArray(usersTable.id, [])) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'JOHN' }, { name: 'JANE' }, { name: 'JANE' }]); + }); + + test('select distinct', async (ctx) => { + const { db } = ctx.singlestore; + + const usersDistinctTable = singlestoreTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${usersDistinctTable}`); + await db.execute(sql`create table ${usersDistinctTable} (id int, name text)`); + + await db.insert(usersDistinctTable).values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]); + const users = await db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ); + + await db.execute(sql`drop table ${usersDistinctTable}`); + + expect(users).toEqual([{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); + }); + + test('insert returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + const [result, _] = await db.insert(usersTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); + }); + + test('delete returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); + }); + + test('update returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + expect(users[0].changedRows).toBe(1); + }); + + test('update with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select().from(usersTable).where(eq(usersTable.id, 1)); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 2000); + expect(users).toEqual([{ id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); + }); + + test('update with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); + }); + + test('delete with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); + }); + + test('delete with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); + }); + + test('insert + select', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); + }); + + test('json insert', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); + }); + + test('insert with overridden default values', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('insert many', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); + }); + + test('insert many with returning', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + + expect(result[0].affectedRows).toBe(4); + }); + + test('select with group by as field', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.name) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); + }); + + test('select with exists', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const user = alias(usersTable, 'user'); + const result = await db.select({ name: usersTable.name }).from(usersTable).where( + exists( + db.select({ one: sql`1` }).from(user).where(and(eq(usersTable.name, 'John'), eq(user.id, usersTable.id))), + ), + ) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }]); + }); + + test('select with group by as sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); + }); + + test('$default function', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`orders\``); + await db.execute( + sql` + create table \`orders\` ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values({ id: 1, region: 'Ukraine', amount: 1, quantity: 1 }); + const selectedOrder = await db.select().from(orders); + + expect(selectedOrder).toEqual([{ + id: 1, + amount: 1, + quantity: 1, + region: 'Ukraine', + product: 'random_string', + }]); + }); + + test('$default with empty array', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`s_orders\``); + await db.execute( + sql` + create table \`s_orders\` ( + \`id\` serial primary key, + \`region\` text default 'Ukraine', + \`product\` text not null + ) + `, + ); + + const users = singlestoreTable('s_orders', { + id: serial('id').primaryKey(), + region: text('region').default('Ukraine'), + product: text('product').$defaultFn(() => 'random_string'), + }); + + await db.insert(users).values({ id: 1 }); + const selectedOrder = await db.select().from(users); + + expect(selectedOrder).toEqual([{ + id: 1, + region: 'Ukraine', + product: 'random_string', + }]); + }); + + test('select with group by as sql + column', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + }); + + test('select with group by as column + sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + }); + + test('select with group by complex query', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + expect(result).toEqual([{ name: 'Jane' }]); + }); + + test('build query', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: `select \`id\`, \`name\` from \`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + params: [], + }); + }); + + test('Query check: Insert all defaults in 1 row', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + const query = db + .insert(users) + .values({}) + .toSQL(); + + expect(query).toEqual({ + sql: 'insert into `users` (`id`, `name`, `state`) values (default, default, default)', + params: [], + }); + }); + + test('Query check: Insert all defaults in multiple rows', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state').default('UA'), + }); + + const query = db + .insert(users) + .values([{}, {}]) + .toSQL(); + + expect(query).toEqual({ + sql: + 'insert into `users` (`id`, `name`, `state`) values (default, default, default), (default, default, default)', + params: [], + }); + }); + + test('Insert all defaults in 1 row', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('empty_insert_single', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial primary key, name text default 'Dan', state text)`, + ); + + await db.insert(users).values({ id: 1 }); + + const res = await db.select().from(users); + + expect(res).toEqual([{ id: 1, name: 'Dan', state: null }]); + }); + + test('Insert all defaults in multiple rows', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('empty_insert_multiple', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial primary key, name text default 'Dan', state text)`, + ); + + await db.insert(users).values([{ id: 1 }, { id: 2 }]); + + const res = await db.select().from(users).orderBy(asc(users.id)); + + expect(res).toEqual([{ id: 1, name: 'Dan', state: null }, { id: 2, name: 'Dan', state: null }]); + }); + + test('build query insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.insert(usersTable) + .values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }) + .onDuplicateKeyUpdate({ set: { id: 1, name: 'John1' } }) + .toSQL(); + + expect(query).toEqual({ + sql: + 'insert into `userstest` (`id`, `name`, `verified`, `jsonb`, `created_at`) values (?, ?, default, ?, default) on duplicate key update `id` = ?, `name` = ?', + params: [1, 'John', '["foo","bar"]', 1, 'John1'], + }); + }); + + test('insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John1' }]); + }); + + test('insert conflict', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await expect((async () => { + db.insert(usersTable).values({ id: 1, name: 'John1' }); + })()).resolves.not.toThrowError(); + }); + + test('insert conflict with ignore', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .ignore() + .values({ id: 1, name: 'John1' }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John' }]); + }); + + test('insert sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`${'John'}` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('partial join with alias', async (ctx) => { + const { db } = ctx.singlestore; + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }).from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }]); + }); + + test('full join with alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select().from(users) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(users.id, 10)) + .orderBy(asc(users.id)); + + expect(result).toEqual([{ + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); + }); + + test('select from alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(user) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(user.id, 10)) + .orderBy(asc(user.id)); + + expect(result).toEqual([{ + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); + }); + + test('insert with spaces', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); + }); + + test('prepared statement', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const statement = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .prepare(); + const result = await statement.execute(); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('insert: placeholders on columns with encoder', async (ctx) => { + const { db } = ctx.singlestore; + + const date = new Date('2024-08-07T15:30:00Z'); + + const statement = db.insert(usersTable).values({ + id: 1, + name: 'John', + createdAt: sql.placeholder('createdAt'), + }).prepare(); + + await statement.execute({ createdAt: date }); + + const result = await db + .select({ + id: usersTable.id, + createdAt: usersTable.createdAt, + }) + .from(usersTable); + + expect(result).toEqual([ + { id: 1, createdAt: date }, + ]); + }); + + test('prepared statement reuse', async (ctx) => { + const { db } = ctx.singlestore; + + const stmt = db.insert(usersTable).values({ + verified: true, + id: placeholder('id'), + name: placeholder('name'), + }).prepare(); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ id: i + 1, name: `John ${i}` }); + } + + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); + }); + + test('prepared statement with placeholder in .where', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .where(eq(usersTable.id, placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('migrator', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists cities_migration`); + await db.execute(sql`drop table if exists users_migration`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists __drizzle_migrations`); + + await migrate(db, { migrationsFolder: './drizzle2/singlestore' }); + + await db.insert(usersMigratorTable).values({ id: 1, name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table cities_migration`); + await db.execute(sql`drop table users_migration`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table __drizzle_migrations`); + }); + + test('insert via db.execute + select via db.execute', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute( + sql`insert into ${usersTable} (${new Name(usersTable.id.name)},${new Name( + usersTable.name.name, + )}) values (1,${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>(sql`select id, name from ${usersTable}`); + expect(result[0]).toEqual([{ id: 1, name: 'John' }]); + }); + + test('insert via db.execute w/ query builder', async (ctx) => { + const { db } = ctx.singlestore; + + const inserted = await db.execute( + db.insert(usersTable).values({ id: 1, name: 'John' }), + ); + expect(inserted[0].affectedRows).toBe(1); + }); + + test('insert + select all possible dates', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute( + sql` + create table \`datestable\` ( + \`date\` date, + \`date_as_string\` date, + \`time\` time, + \`datetime\` datetime, + \`datetime_as_string\` datetime, + \`timestamp\` timestamp(6), + \`timestamp_as_string\` timestamp(6), + \`year\` year + ) + `, + ); + + const date = new Date('2022-11-11'); + const dateWithMilliseconds = new Date('2022-11-11 12:12:12.123'); + + await db.insert(datesTable).values({ + date: date, + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: date, + year: 22, + datetimeAsString: '2022-11-11 12:12:12', + timestamp: dateWithMilliseconds, + timestampAsString: '2022-11-11 12:12:12.123', + }); + + const res = await db.select().from(datesTable); + + expect(res[0]?.date).toBeInstanceOf(Date); + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(typeof res[0]?.dateAsString).toBe('string'); + expect(typeof res[0]?.datetimeAsString).toBe('string'); + + expect(res).toEqual([{ + date: toLocalDate(new Date('2022-11-11')), + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: new Date('2022-11-11'), + year: 2022, + datetimeAsString: '2022-11-11 12:12:12', + timestamp: new Date('2022-11-11 12:12:12.123'), + timestampAsString: '2022-11-11 12:12:12.123000', + }]); + + await db.execute(sql`drop table if exists \`datestable\``); + }); + + const tableWithEnums = singlestoreTable('enums_test_case', { + id: serial('id').primaryKey(), + enum1: singlestoreEnum('enum1', ['a', 'b', 'c']).notNull(), + enum2: singlestoreEnum('enum2', ['a', 'b', 'c']).default('a'), + enum3: singlestoreEnum('enum3', ['a', 'b', 'c']).notNull().default('b'), + }); + + test('SingleStore enum test case #1', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`enums_test_case\``); + + await db.execute(sql` + create table \`enums_test_case\` ( + \`id\` serial primary key, + \`enum1\` ENUM('a', 'b', 'c') not null, + \`enum2\` ENUM('a', 'b', 'c') default 'a', + \`enum3\` ENUM('a', 'b', 'c') not null default 'b' + ) + `); + + await db.insert(tableWithEnums).values([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum3: 'c' }, + { id: 3, enum1: 'a' }, + ]); + + const res = await db.select().from(tableWithEnums).orderBy(asc(tableWithEnums.id)); + + await db.execute(sql`drop table \`enums_test_case\``); + + expect(res).toEqual([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum2: 'a', enum3: 'c' }, + { id: 3, enum1: 'a', enum2: 'a', enum3: 'b' }, + ]); + }); + + test('left join (flat object fields)', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + userId: users2Table.id, + userName: users2Table.name, + cityId: citiesTable.id, + cityName: citiesTable.name, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(users2Table.id); + + expect(res).toEqual([ + { userId: 1, userName: 'John', cityId: 1, cityName: 'Paris' }, + { userId: 2, userName: 'Jane', cityId: null, cityName: null }, + ]); + }); + + test('left join (grouped fields)', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + id: users2Table.id, + user: { + name: users2Table.name, + nameUpper: sql`upper(${users2Table.name})`, + }, + city: { + id: citiesTable.id, + name: citiesTable.name, + nameUpper: sql`upper(${citiesTable.name})`, + }, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + id: 1, + user: { name: 'John', nameUpper: 'JOHN' }, + city: { id: 1, name: 'Paris', nameUpper: 'PARIS' }, + }, + { + id: 2, + user: { name: 'Jane', nameUpper: 'JANE' }, + city: null, + }, + ]); + }); + + test('left join (all fields)', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select().from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + users2: { + id: 1, + name: 'John', + cityId: 1, + }, + cities: { + id: 1, + name: 'Paris', + }, + }, + { + users2: { + id: 2, + name: 'Jane', + cityId: null, + }, + cities: null, + }, + ]); + }); + + test('join subquery', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`courses\``); + await db.execute(sql`drop table if exists \`course_categories\``); + + await db.execute( + sql` + create table \`course_categories\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.execute( + sql` + create table \`courses\` ( + \`id\` serial primary key, + \`name\` text not null, + \`category_id\` int + ) + `, + ); + + await db.insert(courseCategoriesTable).values([ + { id: 1, name: 'Category 1' }, + { id: 2, name: 'Category 2' }, + { id: 3, name: 'Category 3' }, + { id: 4, name: 'Category 4' }, + ]); + + await db.insert(coursesTable).values([ + { id: 1, name: 'Development', categoryId: 2 }, + { id: 2, name: 'IT & Software', categoryId: 3 }, + { id: 3, name: 'Marketing', categoryId: 4 }, + { id: 4, name: 'Design', categoryId: 1 }, + ]); + + const sq2 = db + .select({ + categoryId: courseCategoriesTable.id, + category: courseCategoriesTable.name, + total: sql`count(${courseCategoriesTable.id})`, + }) + .from(courseCategoriesTable) + .groupBy(courseCategoriesTable.id, courseCategoriesTable.name) + .as('sq2'); + + const res = await db + .select({ + courseName: coursesTable.name, + categoryId: sq2.categoryId, + }) + .from(coursesTable) + .leftJoin(sq2, eq(coursesTable.categoryId, sq2.categoryId)) + .orderBy(coursesTable.name); + + expect(res).toEqual([ + { courseName: 'Design', categoryId: 1 }, + { courseName: 'Development', categoryId: 2 }, + { courseName: 'IT & Software', categoryId: 3 }, + { courseName: 'Marketing', categoryId: 4 }, + ]); + + await db.execute(sql`drop table if exists \`courses\``); + await db.execute(sql`drop table if exists \`course_categories\``); + }); + + test('with ... select', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`orders\``); + await db.execute( + sql` + create table \`orders\` ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: regionalSales.region, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`cast(sum(${orders.quantity}) as unsigned)`, + productSales: sql`cast(sum(${orders.amount}) as unsigned)`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))) + .groupBy(orders.region, orders.product) + .orderBy(orders.region, orders.product); + + expect(result).toEqual([ + { + region: 'Europe', + product: 'A', + productUnits: 3, + productSales: 30, + }, + { + region: 'Europe', + product: 'B', + productUnits: 5, + productSales: 50, + }, + { + region: 'US', + product: 'A', + productUnits: 7, + productSales: 70, + }, + { + region: 'US', + product: 'B', + productUnits: 9, + productSales: 90, + }, + ]); + }); + + test('with ... update', async (ctx) => { + const { db } = ctx.singlestore; + + const products = singlestoreTable('products', { + id: serial('id').primaryKey(), + price: decimal('price', { + precision: 15, + scale: 2, + }).notNull(), + cheap: boolean('cheap').notNull().default(false), + }); + + await db.execute(sql`drop table if exists ${products}`); + await db.execute(sql` + create table ${products} ( + id serial primary key, + price decimal(15, 2) not null, + cheap boolean not null default false + ) + `); + + await db.insert(products).values([ + { id: 1, price: '10.99' }, + { id: 2, price: '25.85' }, + { id: 3, price: '32.99' }, + { id: 4, price: '2.50' }, + { id: 5, price: '4.59' }, + ]); + + const averagePrice = db + .$with('average_price') + .as( + db + .select({ + value: sql`avg(${products.price})`.as('value'), + }) + .from(products), + ); + + await db + .with(averagePrice) + .update(products) + .set({ + cheap: true, + }) + .where(lt(products.price, sql`(select * from ${averagePrice})`)); + + const result = await db + .select({ + id: products.id, + }) + .from(products) + .where(eq(products.cheap, true)) + .orderBy(asc(products.id)); + + expect(result).toEqual([ + { id: 1 }, + { id: 4 }, + { id: 5 }, + ]); + }); + + test('with ... delete', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`orders\``); + await db.execute( + sql` + create table \`orders\` ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values([ + { id: 1, region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { id: 2, region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { id: 3, region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { id: 4, region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { id: 5, region: 'US', product: 'A', amount: 30, quantity: 3 }, + { id: 6, region: 'US', product: 'A', amount: 40, quantity: 4 }, + { id: 7, region: 'US', product: 'B', amount: 40, quantity: 4 }, + { id: 8, region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const averageAmount = db + .$with('average_amount') + .as( + db + .select({ + value: sql`avg(${orders.amount})`.as('value'), + }) + .from(orders), + ); + + await db + .with(averageAmount) + .delete(orders) + .where(gt(orders.amount, sql`(select * from ${averageAmount})`)); + + const result = await db + .select({ + id: orders.id, + }) + .from(orders) + .orderBy(asc(orders.id)); + + expect(result).toEqual([ + { id: 1 }, + { id: 2 }, + { id: 3 }, + { id: 4 }, + { id: 5 }, + ]); + }); + + test('select from subquery sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(users2Table).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]); + + const sq = db + .select({ name: sql`concat(${users2Table.name}, " modified")`.as('name') }) + .from(users2Table) + .orderBy(asc(users2Table.id)) + .as('sq'); + + const res = await db.select({ name: sq.name }).from(sq); + + expect(res).toEqual([{ name: 'John modified' }, { name: 'Jane modified' }]); + }); + + test('select a field without joining its table', (ctx) => { + const { db } = ctx.singlestore; + + expect(() => db.select({ name: users2Table.name }).from(usersTable).prepare()).toThrowError(); + }); + + test('select all fields from subquery without alias', (ctx) => { + const { db } = ctx.singlestore; + + const sq = db.$with('sq').as(db.select({ name: sql`upper(${users2Table.name})` }).from(users2Table)); + + expect(() => db.select().from(sq).prepare()).toThrowError(); + }); + + test('select count()', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }]); + + const res = await db.select({ count: sql`count(*)` }).from(usersTable); + + expect(res).toEqual([{ count: 2 }]); + }); + + test('select for ...', (ctx) => { + const { db } = ctx.singlestore; + + { + const query = db.select().from(users2Table).for('update').toSQL(); + expect(query.sql).toMatch(/ for update$/); + } + { + const query = db.select().from(users2Table).for('share', { skipLocked: true }).toSQL(); + expect(query.sql).toMatch(/ for share skip locked$/); + } + { + const query = db.select().from(users2Table).for('update', { noWait: true }).toSQL(); + expect(query.sql).toMatch(/ for update no wait$/); + } + }); + + test('having', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(citiesTable).values([{ id: 1, name: 'London' }, { id: 2, name: 'Paris' }, { + id: 3, + name: 'New York', + }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane', cityId: 1 }, { + id: 3, + name: 'Jack', + cityId: 2, + }]); + + const result = await db + .select({ + id: citiesTable.id, + name: sql`upper(${citiesTable.name})`.as('upper_name'), + usersCount: sql`count(${users2Table.id})`.as('users_count'), + }) + .from(citiesTable) + .leftJoin(users2Table, eq(users2Table.cityId, citiesTable.id)) + .where(({ name }) => sql`length(${name}) >= 3`) + .groupBy(citiesTable.id) + .having(({ usersCount }) => sql`${usersCount} > 0`) + .orderBy(({ name }) => name); + + expect(result).toEqual([ + { + id: 1, + name: 'LONDON', + usersCount: 2, + }, + { + id: 2, + name: 'PARIS', + usersCount: 1, + }, + ]); + }); + + // TODO: Unskip when views are supported + /* test.skip('view', async (ctx) => { + const { db } = ctx.singlestore; + + const newYorkers1 = singlestoreView('new_yorkers') + .as((qb) => qb.select().from(users2Table).where(eq(users2Table.cityId, 1))); + + const newYorkers2 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).as(sql`select * from ${users2Table} where ${eq(users2Table.cityId, 1)}`); + + const newYorkers3 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).existing(); + + await db.execute(sql`create view new_yorkers as ${getViewConfig(newYorkers1).query}`); + + await db.insert(citiesTable).values([{ id: 1, name: 'New York' }, { id: 2, name: 'Paris' }]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2).orderBy(asc(newYorkers2.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3).orderBy(asc(newYorkers3.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop view ${newYorkers1}`); + }); */ + + test('select from raw sql', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.select({ + id: sql`id`, + name: sql`name`, + }).from(sql`(select 1 as id, 'John' as name) as users`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John' }, + ]); + }); + + test('select from raw sql with joins', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db + .select({ + id: sql`users.id`, + name: sql`users.name`, + userCity: sql`users.city`, + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, sql`cities.id = users.id`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John', userCity: 'New York', cityName: 'Paris' }, + ]); + }); + + test('join on aliased sql from select', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db + .select({ + userId: sql`users.id`.as('userId'), + name: sql`users.name`, + userCity: sql`users.city`, + cityId: sql`cities.id`.as('cityId'), + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, (cols) => eq(cols.cityId, cols.userId)); + + Expect< + Equal<{ userId: number; name: string; userCity: string; cityId: number; cityName: string }[], typeof result> + >; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); + }); + + test('join on aliased sql from with clause', async (ctx) => { + const { db } = ctx.singlestore; + + const users = db.$with('users').as( + db.select({ + id: sql`id`.as('userId'), + name: sql`name`.as('userName'), + city: sql`city`.as('city'), + }).from( + sql`(select 1 as id, 'John' as name, 'New York' as city) as users`, + ), + ); + + const cities = db.$with('cities').as( + db.select({ + id: sql`id`.as('cityId'), + name: sql`name`.as('cityName'), + }).from( + sql`(select 1 as id, 'Paris' as name) as cities`, + ), + ); + + const result = await db + .with(users, cities) + .select({ + userId: users.id, + name: users.name, + userCity: users.city, + cityId: cities.id, + cityName: cities.name, + }) + .from(users) + .leftJoin(cities, (cols) => eq(cols.cityId, cols.userId)); + + Expect< + Equal<{ userId: number; name: string; userCity: string; cityId: number; cityName: string }[], typeof result> + >; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); + }); + + test('prefixed table', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `myprefix_${name}`); + + const users = singlestoreTable('test_prefixed_table_with_unique_name', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table myprefix_test_prefixed_table_with_unique_name (id int not null primary key, name text not null)`, + ); + + await db.insert(users).values({ id: 1, name: 'John' }); + + const result = await db.select().from(users); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + + await db.execute(sql`drop table ${users}`); + }); + + test('orderBy with aliased column', (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ + test: sql`something`.as('test'), + }).from(users2Table).orderBy((fields) => fields.test).toSQL(); + + expect(query.sql).toBe('select something as `test` from `users2` order by `test`'); + }); + + test('timestamp timezone', async (ctx) => { + const { db } = ctx.singlestore; + + const date = new Date(Date.parse('2020-01-01T12:34:56+07:00')); + + await db.insert(usersTable).values({ id: 1, name: 'With default times' }); + await db.insert(usersTable).values({ + id: 2, + name: 'Without default times', + createdAt: date, + }); + const users = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + + // check that the timestamps are set correctly for default times + expect(Math.abs(users[0]!.createdAt.getTime() - Date.now())).toBeLessThan(2000); + + // check that the timestamps are set correctly for non default times + expect(Math.abs(users[1]!.createdAt.getTime() - date.getTime())).toBeLessThan(2000); + }); + + test('transaction', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_transactions', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + const products = singlestoreTable('products_transactions', { + id: serial('id').primaryKey(), + price: int('price').notNull(), + stock: int('stock').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop table if exists ${products}`); + + await db.execute(sql`create table users_transactions (id serial not null primary key, balance int not null)`); + await db.execute( + sql`create table products_transactions (id serial not null primary key, price int not null, stock int not null)`, + ); + + const [{ insertId: userId }] = await db.insert(users).values({ id: 1, balance: 100 }); + const user = await db.select().from(users).where(eq(users.id, userId)).then((rows) => rows[0]!); + const [{ insertId: productId }] = await db.insert(products).values({ id: 1, price: 10, stock: 10 }); + const product = await db.select().from(products).where(eq(products.id, productId)).then((rows) => rows[0]!); + + await db.transaction(async (tx) => { + await tx.update(users).set({ balance: user.balance - product.price }).where(eq(users.id, user.id)); + await tx.update(products).set({ stock: product.stock - 1 }).where(eq(products.id, product.id)); + }); + + const result = await db.select().from(users); + + expect(result).toEqual([{ id: 1, balance: 90 }]); + + await db.execute(sql`drop table ${users}`); + await db.execute(sql`drop table ${products}`); + }); + + test('transaction rollback', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_transactions_rollback', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table users_transactions_rollback (id serial not null primary key, balance int not null)`, + ); + + await expect((async () => { + await db.transaction(async (tx) => { + await tx.insert(users).values({ balance: 100 }); + tx.rollback(); + }); + })()).rejects.toThrowError(TransactionRollbackError); + + const result = await db.select().from(users); + + expect(result).toEqual([]); + + await db.execute(sql`drop table ${users}`); + }); + + test('join subquery with join', async (ctx) => { + const { db } = ctx.singlestore; + + const internalStaff = singlestoreTable('internal_staff', { + userId: int('user_id').notNull(), + }); + + const customUser = singlestoreTable('custom_user', { + id: int('id').notNull(), + }); + + const ticket = singlestoreTable('ticket', { + staffId: int('staff_id').notNull(), + }); + + await db.execute(sql`drop table if exists ${internalStaff}`); + await db.execute(sql`drop table if exists ${customUser}`); + await db.execute(sql`drop table if exists ${ticket}`); + + await db.execute(sql`create table internal_staff (user_id integer not null)`); + await db.execute(sql`create table custom_user (id integer not null)`); + await db.execute(sql`create table ticket (staff_id integer not null)`); + + await db.insert(internalStaff).values({ userId: 1 }); + await db.insert(customUser).values({ id: 1 }); + await db.insert(ticket).values({ staffId: 1 }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin(customUser, eq(internalStaff.userId, customUser.id)) + .as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + expect(mainQuery).toEqual([{ + ticket: { staffId: 1 }, + internal_staff: { + internal_staff: { userId: 1 }, + custom_user: { id: 1 }, + }, + }]); + + await db.execute(sql`drop table ${internalStaff}`); + await db.execute(sql`drop table ${customUser}`); + await db.execute(sql`drop table ${ticket}`); + }); + + // TODO: Unskip when views are supported + /* test.skip('subquery with view', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_subquery_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.$with('sq').as(db.select().from(newYorkers)); + const result = await db.with(sq).select().from(sq).orderBy(asc(sq.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 1 }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); + }); */ + + // TODO: Unskip when views are supported + /* test.skip('join view as subquery', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_join_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.select().from(newYorkers).as('new_yorkers_sq'); + + const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id)).orderBy(asc(users.id)); + + expect(result).toEqual([ + { + users_join_view: { id: 1, name: 'John', cityId: 1 }, + new_yorkers_sq: { id: 1, name: 'John', cityId: 1 }, + }, + { + users_join_view: { id: 2, name: 'Jane', cityId: 2 }, + new_yorkers_sq: null, + }, + { + users_join_view: { id: 3, name: 'Jack', cityId: 1 }, + new_yorkers_sq: { id: 3, name: 'Jack', cityId: 1 }, + }, + { + users_join_view: { id: 4, name: 'Jill', cityId: 2 }, + new_yorkers_sq: null, + }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); + }); */ + + test('select iterator', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const iter = db.select().from(users) + .orderBy(asc(users.id)) + .iterator(); + + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + test('select iterator w/ prepared statement', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const prepared = db.select().from(users) + .orderBy(asc(users.id)) + .prepare(); + const iter = prepared.iterator(); + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + test('insert undefined', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.insert(users).values({ name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); + }); + + test('update undefined', async (ctx) => { + const { db } = ctx.singlestore; + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.update(users).set({ name: undefined }); + })()).rejects.toThrowError(); + + await expect((async () => { + await db.update(users).set({ id: 1, name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); + }); + + test('utc config for datetime', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute( + sql` + create table \`datestable\` ( + \`datetime_utc\` datetime(6), + \`datetime\` datetime(6) + ) + `, + ); + const datesTable = singlestoreTable('datestable', { + datetimeUTC: datetime('datetime_utc', { mode: 'date' }), + datetime: datetime('datetime'), + }); + + const dateObj = new Date('2022-11-11'); + const dateUtc = new Date('2022-11-11T12:12:12.122Z'); + + await db.insert(datesTable).values({ + datetimeUTC: dateUtc, + datetime: dateObj, + }); + + const res = await db.select().from(datesTable); + + const [rawSelect] = await db.execute(sql`select \`datetime_utc\` from \`datestable\``); + const selectedRow = (rawSelect as unknown as [{ datetime_utc: string }])[0]; + + expect(selectedRow.datetime_utc).toBe('2022-11-11 12:12:12.122000'); + expect(new Date(selectedRow.datetime_utc.replace(' ', 'T') + 'Z')).toEqual(dateUtc); + + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(res[0]?.datetimeUTC).toBeInstanceOf(Date); + + expect(res).toEqual([{ + datetimeUTC: dateUtc, + datetime: new Date('2022-11-11'), + }]); + + await db.execute(sql`drop table if exists \`datestable\``); + }); + + // TODO (https://memsql.atlassian.net/browse/MCDB-63261) allow chaining limit and orderby in subquery + test('set operations (union) from query builder with subquery', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + const citiesQuery = db + .select({ + id: citiesTable.id, + name: citiesTable.name, + orderCol: sql`0`.as('orderCol'), + }) + .from(citiesTable); + + const usersQuery = db + .select({ + id: users2Table.id, + name: users2Table.name, + orderCol: sql`1`.as('orderCol'), + }) + .from(users2Table); + + const unionQuery = db + .select({ + id: sql`id`, + name: sql`name`, + }) + .from( + citiesQuery.union(usersQuery).as('combined'), + ) + .orderBy(sql`orderCol`, sql`id`) + .limit(8); + + const result = await unionQuery; + + expect(result).toHaveLength(8); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Jack' }, + { id: 4, name: 'Peter' }, + { id: 5, name: 'Ben' }, + ]); + + // union should throw if selected fields are not in the same order + await expect((async () => { + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).union( + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (union) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const result = await union( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + { id: 1, name: 'John' }, + ]); + + await expect((async () => { + union( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (union all) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).orderBy(asc(sql`id`)).limit(2).unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).orderBy(asc(sql`id`)).limit(2), + ).as('sq'); + + const result = await db.select().from(sq).orderBy(asc(sql`id`)).limit(3); + + expect(result).toHaveLength(3); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + ]); + + await expect((async () => { + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).limit(2).unionAll( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).limit(2), + ).orderBy(asc(sql`id`)); + })()).rejects.toThrowError(); + }); + + test('set operations (union all) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).as('sq'); + + const result = await db.select().from(sq).limit(1); + + expect(result).toHaveLength(1); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + ]); + + await expect((async () => { + unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(1); + })()).rejects.toThrowError(); + }); + + test('set operations (intersect) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ) + .as('sq'); + + const result = await db.select().from(sq).orderBy(asc(sql`id`)); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await expect((async () => { + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (intersect) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = await intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).as('sq'); + + const result = await db.select().from(sq).limit(1); + + expect(result).toHaveLength(0); + + expect(result).toEqual([]); + + await expect((async () => { + intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(1); + })()).rejects.toThrowError(); + }); + + test('set operations (except) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const result = await db + .select() + .from(citiesTable).except( + db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + + expect(result).toHaveLength(1); + + expect(result).toEqual([ + { id: 1, name: 'New York' }, + ]); + }); + + test('set operations (except) as function', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq = await except( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable), + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).as('sq'); + + const result = await db.select().from(sq).limit(3); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await expect((async () => { + except( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable), + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(3); + })()).rejects.toThrowError(); + }); + + test.skip('set operations (mixed) from query builder', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq1 = unionAll( + db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + db.select().from(citiesTable).where(eq(citiesTable.id, 2)), + ).as('sq1'); + + const sq2 = await db.select().from(sq1).orderBy(asc(sql`id`)).as('sq2'); + + const sq3 = await db.select().from(sq2).limit(1).offset(1).as('sq3'); + + const result = await db + .select() + .from(citiesTable) + .except( + db + .select() + .from(sq3), + ); + + expect(result).toHaveLength(2); + + expect(result).toEqual([ + { id: 3, name: 'Tampa' }, + { id: 1, name: 'New York' }, + ]); + + await expect((async () => { + db + .select() + .from(citiesTable).except( + ({ unionAll }) => + unionAll( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + db.select().from(citiesTable).where(eq(citiesTable.id, 2)), + ), + ); + })()).rejects.toThrowError(); + }); + + test('set operations (mixed all) as function with subquery', async (ctx) => { + const { db } = ctx.singlestore; + + await setupSetOperationTest(db); + + const sq1 = except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 7)), + ).as('sq1'); + + const sq2 = await db.select().from(sq1).orderBy(asc(sql`id`)).as('sq2'); + + const sq3 = await db.select().from(sq2).limit(1).as('sq3'); + + const result = await union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db.select().from(sq3), + db + .select().from(citiesTable).where(gt(citiesTable.id, 1)), + ); + + expect(result).toHaveLength(4); + + // multiple results possible as a result of the filters >= 5 and ==7 because singlestore doesn't guarantee order + // dynamically validate results + const hasValidEntry = (entry: { id: number; name: string }) => { + if (entry.id === 1) return entry.name === 'John'; + if (entry.id > 1 && entry.id < 5) return entry.name === 'Tampa' || entry.name === 'London'; + if (entry.id >= 5 && entry.id !== 7) return true; // Accept any entry with id >= 5 and not 7 + return false; + }; + + for (const entry of result) { + expect(hasValidEntry(entry)).toBe(true); + } + + await expect((async () => { + union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 7)), + ).limit(1), + db + .select().from(citiesTable).where(gt(citiesTable.id, 1)), + ); + })()).rejects.toThrowError(); + }); + + test('aggregate function: count', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: count() }).from(table); + const result2 = await db.select({ value: count(table.a) }).from(table); + const result3 = await db.select({ value: countDistinct(table.name) }).from(table); + + expect(result1[0]?.value).toBe(7); + expect(result2[0]?.value).toBe(5); + expect(result3[0]?.value).toBe(6); + }); + + test('aggregate function: avg', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: avg(table.b) }).from(table); + const result2 = await db.select({ value: avg(table.nullOnly) }).from(table); + const result3 = await db.select({ value: avgDistinct(table.b) }).from(table); + + expect(result1[0]?.value).toBe('33.3333'); + expect(result2[0]?.value).toBe(null); + expect(result3[0]?.value).toBe('42.5000'); + }); + + test('aggregate function: sum', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: sum(table.b) }).from(table); + const result2 = await db.select({ value: sum(table.nullOnly) }).from(table); + const result3 = await db.select({ value: sumDistinct(table.b) }).from(table); + + expect(result1[0]?.value).toBe('200'); + expect(result2[0]?.value).toBe(null); + expect(result3[0]?.value).toBe('170'); + }); + + test('aggregate function: max', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: max(table.b) }).from(table); + const result2 = await db.select({ value: max(table.nullOnly) }).from(table); + + expect(result1[0]?.value).toBe(90); + expect(result2[0]?.value).toBe(null); + }); + + test('aggregate function: min', async (ctx) => { + const { db } = ctx.singlestore; + const table = aggregateTable; + await setupAggregateFunctionsTest(db); + + const result1 = await db.select({ value: min(table.b) }).from(table); + const result2 = await db.select({ value: min(table.nullOnly) }).from(table); + + expect(result1[0]?.value).toBe(10); + expect(result2[0]?.value).toBe(null); + }); + + test('test $onUpdateFn and $onUpdate works as $default', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists ${usersOnUpdate}`); + + await db.execute( + sql` + create table ${usersOnUpdate} ( + id serial not null primary key, + name text not null, + update_counter integer default 1 not null, + updated_at datetime(6), + always_null text + ) + `, + ); + + await db.insert(usersOnUpdate).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Jack' }, + { id: 4, name: 'Jill' }, + ]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + + const justDates = await db.select({ updatedAt }).from(usersOnUpdate); + + const response = await db.select({ ...rest }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + expect(response).toEqual([ + { name: 'John', id: 1, updateCounter: 1, alwaysNull: null }, + { name: 'Jane', id: 2, updateCounter: 1, alwaysNull: null }, + { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, + { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, + ]); + const msDelay = 750; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); + } + }); + + test('test $onUpdateFn and $onUpdate works updating', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists ${usersOnUpdate}`); + + await db.execute( + sql` + create table ${usersOnUpdate} ( + id serial not null primary key, + name text not null, + update_counter integer default 1 not null, + updated_at datetime(6), + always_null text + ) + `, + ); + + await db.insert(usersOnUpdate).values([ + { id: 1, name: 'John', alwaysNull: 'this will will be null after updating' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Jack' }, + { id: 4, name: 'Jill' }, + ]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + const initial = await db.select({ id: usersOnUpdate.id, updatedAt: usersOnUpdate.updatedAt }).from(usersOnUpdate); + + await db.update(usersOnUpdate).set({ name: 'Angel' }).where(eq(usersOnUpdate.id, 1)); + + const justDates = await db.select({ id: usersOnUpdate.id, updatedAt: usersOnUpdate.updatedAt }).from( + usersOnUpdate, + ); + + const response = await db.select().from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + expect(response).toEqual([ + { id: 1, name: 'Angel', updateCounter: 2, updatedAt: expect.any(Date), alwaysNull: null }, + { id: 2, name: 'Jane', updateCounter: 1, updatedAt: expect.any(Date), alwaysNull: null }, + { id: 3, name: 'Jack', updateCounter: 1, updatedAt: expect.any(Date), alwaysNull: null }, + { id: 4, name: 'Jill', updateCounter: 1, updatedAt: expect.any(Date), alwaysNull: null }, + ]); + + const initialRecord = initial.find((record) => record.id === 1); + const updatedRecord = justDates.find((record) => record.id === 1); + + expect(initialRecord?.updatedAt?.valueOf()).not.toBe(updatedRecord?.updatedAt?.valueOf()); + + const msDelay = 1000; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).toBeGreaterThan(Date.now() - msDelay); + } + }); + + // mySchema tests + test('mySchema :: select all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersMySchemaTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('mySchema :: select sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersMySchemaTable.name})`, + }).from(usersMySchemaTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('mySchema :: select typed sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersMySchemaTable.name})`, + }).from(usersMySchemaTable); + + expect(users).toEqual([{ name: 'JOHN' }]); + }); + + test('mySchema :: select distinct', async (ctx) => { + const { db } = ctx.singlestore; + + const usersDistinctTable = singlestoreTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${usersDistinctTable}`); + await db.execute(sql`create table ${usersDistinctTable} (id int, name text)`); + + await db.insert(usersDistinctTable).values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]); + const users = await db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ); + + await db.execute(sql`drop table ${usersDistinctTable}`); + + expect(users).toEqual([{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); + }); + + test('mySchema :: insert returning sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + const [result, _] = await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); + }); + + test('mySchema :: delete returning sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const users = await db.delete(usersMySchemaTable).where(eq(usersMySchemaTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); + }); + + test('mySchema :: update with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersMySchemaTable).set({ name: 'Jane' }).where( + eq(usersMySchemaTable.name, 'John'), + ); + + const users = await db.select({ id: usersMySchemaTable.id, name: usersMySchemaTable.name }).from( + usersMySchemaTable, + ) + .where( + eq(usersMySchemaTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); + }); + + test('mySchema :: delete with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersMySchemaTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersMySchemaTable).where(eq(usersMySchemaTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); + }); + + test('mySchema :: insert + select', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersMySchemaTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersMySchemaTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersMySchemaTable).orderBy(asc(usersMySchemaTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); + }); + + test('mySchema :: insert with overridden default values', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersMySchemaTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); + }); + + test('mySchema :: insert many', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersMySchemaTable.id, + name: usersMySchemaTable.name, + jsonb: usersMySchemaTable.jsonb, + verified: usersMySchemaTable.verified, + }).from(usersMySchemaTable) + .orderBy(asc(usersMySchemaTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); + }); + + test('mySchema :: select with group by as field', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { + id: 3, + name: 'Jane', + }]); + + const result = await db.select({ name: usersMySchemaTable.name }).from(usersMySchemaTable) + .groupBy(usersMySchemaTable.name) + .orderBy(asc(usersMySchemaTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); + }); + + test('mySchema :: select with group by as column + sql', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { + id: 3, + name: 'Jane', + }]); + + const result = await db.select({ name: usersMySchemaTable.name }).from(usersMySchemaTable) + .groupBy(usersMySchemaTable.id, sql`${usersMySchemaTable.name}`) + .orderBy(asc(usersMySchemaTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + }); + + test('mySchema :: build query', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ id: usersMySchemaTable.id, name: usersMySchemaTable.name }).from(usersMySchemaTable) + .groupBy(usersMySchemaTable.id, usersMySchemaTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: + `select \`id\`, \`name\` from \`mySchema\`.\`userstest\` group by \`mySchema\`.\`userstest\`.\`id\`, \`mySchema\`.\`userstest\`.\`name\``, + params: [], + }); + }); + + test('mySchema :: insert with spaces', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersMySchemaTable.id, name: usersMySchemaTable.name }).from( + usersMySchemaTable, + ); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); + }); + + test('mySchema :: prepared statement with placeholder in .where', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.insert(usersMySchemaTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersMySchemaTable.id, + name: usersMySchemaTable.name, + }).from(usersMySchemaTable) + .where(eq(usersMySchemaTable.id, sql.placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + }); + + test('mySchema :: select from tables with same name from different schema using alias', async (ctx) => { + const { db } = ctx.singlestore; + await db.execute(sql`truncate table \`mySchema\`.\`userstest\``); + + await db.execute(sql`drop table if exists \`userstest\``); + await db.execute( + sql` + create table \`userstest\` ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.insert(usersMySchemaTable).values({ id: 10, name: 'Ivan' }); + await db.insert(usersTable).values({ id: 11, name: 'Hans' }); + + const customerAlias = alias(usersTable, 'customer'); + + const result = await db + .select().from(usersMySchemaTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersMySchemaTable.id, 10)); + + expect(result).toEqual([{ + userstest: { + id: 10, + name: 'Ivan', + verified: false, + jsonb: null, + createdAt: result[0]!.userstest.createdAt, + }, + customer: { + id: 11, + name: 'Hans', + verified: false, + jsonb: null, + createdAt: result[0]!.customer!.createdAt, + }, + }]); + }); + + test('insert $returningId: serial as id', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values({ id: 1, name: 'John' }).$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + id: number; + }[]>(); + + expect(result).toStrictEqual([{ id: 1 }]); + }); + + test('insert $returningId: serial as id, batch insert', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'John1' }]) + .$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + id: number; + }[]>(); + + // singlestore auto increments when batch inserting, so the ids increment by one + expect(result).toStrictEqual([{ id: 2 }, { id: 3 }]); + }); + + test('insert $returningId: $default as primary key', async (ctx) => { + const { db } = ctx.singlestore; + + const uniqueKeys = ['ao865jf3mcmkfkk8o5ri495z', 'dyqs529eom0iczo2efxzbcut']; + let iterator = 0; + + const usersTableDefFn = singlestoreTable('users_default_fn', { + customId: varchar('id', { length: 256 }).primaryKey().$defaultFn(() => { + const value = uniqueKeys[iterator]!; + iterator++; + return value; + }), + name: text('name').notNull(), + }); + + await setupReturningFunctionsTest(db); + + const result = await db.insert(usersTableDefFn).values([{ name: 'John' }, { name: 'John1' }]) + // ^? + .$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + customId: string; + }[]>(); + + expect(result).toStrictEqual([{ customId: 'ao865jf3mcmkfkk8o5ri495z' }, { + customId: 'dyqs529eom0iczo2efxzbcut', + }]); + }); + + test('insert $returningId: $default as primary key with value', async (ctx) => { + const { db } = ctx.singlestore; + + const uniqueKeys = ['ao865jf3mcmkfkk8o5ri495z', 'dyqs529eom0iczo2efxzbcut']; + let iterator = 0; + + const usersTableDefFn = singlestoreTable('users_default_fn', { + customId: varchar('id', { length: 256 }).primaryKey().$defaultFn(() => { + const value = uniqueKeys[iterator]!; + iterator++; + return value; + }), + name: text('name').notNull(), + }); + + await setupReturningFunctionsTest(db); + + const result = await db.insert(usersTableDefFn).values([{ name: 'John', customId: 'test' }, { name: 'John1' }]) + // ^? + .$returningId(); + + expectTypeOf(result).toEqualTypeOf<{ + customId: string; + }[]>(); + + expect(result).toStrictEqual([{ customId: 'test' }, { customId: 'ao865jf3mcmkfkk8o5ri495z' }]); + }); + + // TODO: Unkip this test when views are supported + /* test.skip('mySchema :: view', async (ctx) => { + const { db } = ctx.singlestore; + + const newYorkers1 = mySchema.view('new_yorkers') + .as((qb) => qb.select().from(users2MySchemaTable).where(eq(users2MySchemaTable.cityId, 1))); + + const newYorkers2 = mySchema.view('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).as(sql`select * from ${users2MySchemaTable} where ${eq(users2MySchemaTable.cityId, 1)}`); + + const newYorkers3 = mySchema.view('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).existing(); + + await db.execute(sql`create view ${newYorkers1} as ${getViewConfig(newYorkers1).query}`); + + await db.insert(citiesMySchemaTable).values([{ id: 1, name: 'New York' }, { id: 2, name: 'Paris' }]); + + await db.insert(users2MySchemaTable).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2).orderBy(asc(newYorkers2.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3).orderBy(asc(newYorkers3.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop view ${newYorkers1}`); + }); */ + + test('limit 0', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .select() + .from(usersTable) + .limit(0); + + expect(users).toEqual([]); + }); + + test('limit -1', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .select() + .from(usersTable) + .limit(-1); + + expect(users.length).toBeGreaterThan(0); + }); + }); +} diff --git a/integration-tests/tests/singlestore/singlestore-custom.test.ts b/integration-tests/tests/singlestore/singlestore-custom.test.ts new file mode 100644 index 000000000..c599df436 --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-custom.test.ts @@ -0,0 +1,827 @@ +import retry from 'async-retry'; +import type Docker from 'dockerode'; +import { asc, eq, Name, placeholder, sql } from 'drizzle-orm'; +import type { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +import { drizzle } from 'drizzle-orm/singlestore'; +import { + alias, + binary, + customType, + date, + datetime, + serial, + singlestoreEnum, + singlestoreTable, + singlestoreTableCreator, + text, + time, + varchar, + year, +} from 'drizzle-orm/singlestore-core'; +import { migrate } from 'drizzle-orm/singlestore/migrator'; +import * as mysql2 from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { toLocalDate } from '~/utils'; +import { createDockerDB } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +let db: SingleStoreDriverDatabase; +let client: mysql2.Connection; +let container: Docker.Container | undefined; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr, container: contrainerObj } = await createDockerDB(); + connectionString = conStr; + container = contrainerObj; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); + await container?.stop().catch(console.error); +}); + +beforeEach((ctx) => { + ctx.singlestore = { + db, + }; +}); + +const customSerial = customType<{ data: number; notNull: true; default: true }>({ + dataType() { + return 'serial'; + }, +}); + +const customText = customType<{ data: string }>({ + dataType() { + return 'text'; + }, +}); + +const customBoolean = customType<{ data: boolean }>({ + dataType() { + return 'boolean'; + }, + fromDriver(value) { + if (typeof value === 'boolean') { + return value; + } + return value === 1; + }, +}); + +const customJson = (name: string) => + customType<{ data: TData; driverData: string }>({ + dataType() { + return 'json'; + }, + toDriver(value: TData): string { + return JSON.stringify(value); + }, + })(name); + +const customTimestamp = customType< + { data: Date; driverData: string; config: { fsp: number } } +>({ + dataType(config) { + const precision = config?.fsp === undefined ? '' : ` (${config.fsp})`; + return `timestamp${precision}`; + }, + fromDriver(value: string): Date { + return new Date(value); + }, +}); + +const customBinary = customType<{ data: string; driverData: Buffer; config: { length: number } }>({ + dataType(config) { + return config?.length === undefined + ? `binary` + : `binary(${config.length})`; + }, + + toDriver(value) { + return sql`UNHEX(${value})`; + }, + + fromDriver(value) { + return value.toString('hex'); + }, +}); + +const usersTable = singlestoreTable('userstest', { + id: customSerial('id').primaryKey(), + name: customText('name').notNull(), + verified: customBoolean('verified').notNull().default(false), + jsonb: customJson('jsonb'), + createdAt: customTimestamp('created_at').notNull().default(sql`now()`), +}); + +const datesTable = singlestoreTable('datestable', { + date: date('date'), + dateAsString: date('date_as_string', { mode: 'string' }), + time: time('time'), + datetime: datetime('datetime'), + datetimeAsString: datetime('datetime_as_string', { mode: 'string' }), + year: year('year'), +}); + +export const testTable = singlestoreTable('test_table', { + id: customBinary('id', { length: 16 }).primaryKey(), + sqlId: binary('sql_id', { length: 16 }), + rawId: varchar('raw_id', { length: 64 }), +}); + +const usersMigratorTable = singlestoreTable('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}); + +beforeEach(async () => { + await db.execute(sql`drop table if exists \`userstest\``); + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute(sql`drop table if exists \`test_table\``); + // await ctx.db.execute(sql`create schema public`); + await db.execute( + sql` + create table \`userstest\` ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table \`datestable\` ( + \`date\` date, + \`date_as_string\` date, + \`time\` time, + \`datetime\` datetime, + \`datetime_as_string\` datetime, + \`year\` year + ) + `, + ); + + await db.execute( + sql` + create table \`test_table\` ( + \`id\` binary(16) primary key, + \`sql_id\` binary(16), + \`raw_id\` varchar(64) + ) + `, + ); +}); + +test('select all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('select sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('select typed sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('insert returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + const [result, _] = await db.insert(usersTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); +}); + +test('delete returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); +}); + +test('update returning sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + expect(users[0].changedRows).toBe(1); +}); + +test('update with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select().from(usersTable).where(eq(usersTable.id, 1)); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 2000); + expect(users).toEqual([{ id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); +}); + +test('update with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); +}); + +test('delete with returning all fields', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('delete with returning partial', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('insert + select', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); +}); + +test('json insert', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); +}); + +test('insert with overridden default values', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('insert many', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }).from(usersTable).orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); +}); + +test('insert many with returning', async (ctx) => { + const { db } = ctx.singlestore; + + const result = await db.insert(usersTable).values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + + expect(result[0].affectedRows).toBe(4); +}); + +test('select with group by as field', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.name).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql + column', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by as column + sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`).orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by complex query', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + expect(result).toEqual([{ name: 'Jane' }]); +}); + +test('build query', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: `select \`id\`, \`name\` from \`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + params: [], + }); +}); + +test('build query insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + const query = db.insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }) + .toSQL(); + + expect(query).toEqual({ + sql: + 'insert into `userstest` (`id`, `name`, `verified`, `jsonb`, `created_at`) values (default, ?, default, ?, default) on duplicate key update `name` = ?', + params: ['John', '["foo","bar"]', 'John1'], + }); +}); + +test('insert with onDuplicate', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John1' }]); +}); + +test('insert conflict', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await expect((async () => { + db.insert(usersTable).values({ id: 1, name: 'John1' }); + })()).resolves.not.toThrowError(); +}); + +test('insert conflict with ignore', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .ignore() + .values({ id: 1, name: 'John1' }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert sql', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`${'John'}` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('partial join with alias', async (ctx) => { + const { db } = ctx.singlestore; + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }).from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }]); +}); + +test('full join with alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select().from(users) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(users.id, 10)) + .orderBy(asc(users.id)); + + expect(result).toEqual([{ + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('select from alias', async (ctx) => { + const { db } = ctx.singlestore; + + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(user) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(user.id, 10)) + .orderBy(asc(user.id)); + + expect(result).toEqual([{ + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('insert with spaces', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); +}); + +test('prepared statement', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const statement = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .prepare(); + const result = await statement.execute(); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('prepared statement reuse', async (ctx) => { + const { db } = ctx.singlestore; + + const stmt = db.insert(usersTable).values({ + id: placeholder('id'), + verified: true, + name: placeholder('name'), + }).prepare(); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ id: i + 1, name: `John ${i}` }); + } + + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }).from(usersTable).orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); +}); + +test('prepared statement with placeholder in .where', async (ctx) => { + const { db } = ctx.singlestore; + + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .where(eq(usersTable.id, placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('migrator', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists cities_migration`); + await db.execute(sql`drop table if exists users_migration`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists __drizzle_migrations`); + + await migrate(db, { migrationsFolder: './drizzle2/singlestore' }); + + await db.insert(usersMigratorTable).values({ id: 1, name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table cities_migration`); + await db.execute(sql`drop table users_migration`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table __drizzle_migrations`); +}); + +test('insert via db.execute + select via db.execute', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute( + sql`insert into ${usersTable} (${new Name(usersTable.id.name)}, ${new Name( + usersTable.name.name, + )}) values (1,${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>(sql`select id, name from ${usersTable}`); + expect(result[0]).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert via db.execute w/ query builder', async (ctx) => { + const { db } = ctx.singlestore; + + const inserted = await db.execute( + db.insert(usersTable).values({ name: 'John' }), + ); + expect(inserted[0].affectedRows).toBe(1); +}); + +test('insert + select all possible dates', async (ctx) => { + const { db } = ctx.singlestore; + + const date = new Date('2022-11-11'); + + await db.insert(datesTable).values({ + date: date, + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: date, + year: 22, + datetimeAsString: '2022-11-11 12:12:12', + }); + + const res = await db.select().from(datesTable); + + expect(res[0]?.date).toBeInstanceOf(Date); + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(res[0]?.dateAsString).toBeTypeOf('string'); + expect(res[0]?.datetimeAsString).toBeTypeOf('string'); + + expect(res).toEqual([{ + date: toLocalDate(new Date('2022-11-11')), + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: new Date('2022-11-11'), + year: 2022, + datetimeAsString: '2022-11-11 12:12:12', + }]); +}); + +const tableWithEnums = singlestoreTable('enums_test_case', { + id: serial('id').primaryKey(), + enum1: singlestoreEnum('enum1', ['a', 'b', 'c']).notNull(), + enum2: singlestoreEnum('enum2', ['a', 'b', 'c']).default('a'), + enum3: singlestoreEnum('enum3', ['a', 'b', 'c']).notNull().default('b'), +}); + +test('SingleStore enum test case #1', async (ctx) => { + const { db } = ctx.singlestore; + + await db.execute(sql`drop table if exists \`enums_test_case\``); + + await db.execute(sql` + create table \`enums_test_case\` ( + \`id\` serial primary key, + \`enum1\` ENUM('a', 'b', 'c') not null, + \`enum2\` ENUM('a', 'b', 'c') default 'a', + \`enum3\` ENUM('a', 'b', 'c') not null default 'b' + ) + `); + + await db.insert(tableWithEnums).values([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum3: 'c' }, + { id: 3, enum1: 'a' }, + ]); + + const res = await db.select().from(tableWithEnums).orderBy(asc(tableWithEnums.id)); + + await db.execute(sql`drop table \`enums_test_case\``); + + expect(res).toEqual([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum2: 'a', enum3: 'c' }, + { id: 3, enum1: 'a', enum2: 'a', enum3: 'b' }, + ]); +}); + +test('custom binary', async (ctx) => { + const { db } = ctx.singlestore; + + const id = uuid().replace(/-/g, ''); + await db.insert(testTable).values({ + id, + sqlId: sql`UNHEX(${id})`, + rawId: id, + }); + + const res = await db.select().from(testTable); + + expect(res).toEqual([{ + id, + sqlId: Buffer.from(id, 'hex'), + rawId: id, + }]); +}); diff --git a/integration-tests/tests/singlestore/singlestore-prefixed.test.ts b/integration-tests/tests/singlestore/singlestore-prefixed.test.ts new file mode 100644 index 000000000..6f29d31a2 --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-prefixed.test.ts @@ -0,0 +1,1574 @@ +import retry from 'async-retry'; +import type Docker from 'dockerode'; +import type { Equal } from 'drizzle-orm'; +import { asc, eq, getTableName, gt, inArray, Name, sql, TransactionRollbackError } from 'drizzle-orm'; +import type { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +import { drizzle } from 'drizzle-orm/singlestore'; +import { + alias, + boolean, + date, + datetime, + int, + json, + serial, + singlestoreEnum, + singlestoreTable as singlestoreTableRaw, + singlestoreTableCreator, + /* singlestoreView, */ + text, + time, + timestamp, + uniqueIndex, + year, +} from 'drizzle-orm/singlestore-core'; +import { migrate } from 'drizzle-orm/singlestore/migrator'; +import * as mysql2 from 'mysql2/promise'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; +import { Expect, toLocalDate } from '~/utils'; +import { createDockerDB } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +let db: SingleStoreDriverDatabase; +let client: mysql2.Connection; +let container: Docker.Container | undefined; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr, container: contrainerObj } = await createDockerDB(); + connectionString = conStr; + container = contrainerObj; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); + await container?.stop().catch(console.error); +}); + +const tablePrefix = 'drizzle_tests_'; + +const singlestoreTable = singlestoreTableCreator((name) => `${tablePrefix}${name}`); +const usersTable = singlestoreTable('userstest', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: json('jsonb').$type(), + createdAt: timestamp('created_at').notNull().defaultNow(), +}); + +const users2Table = singlestoreTable('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id'), +}); + +const citiesTable = singlestoreTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +beforeEach(async () => { + await db.execute(sql`drop table if exists ${usersTable}`); + await db.execute(sql`drop table if exists ${users2Table}`); + await db.execute(sql`drop table if exists ${citiesTable}`); + + await db.execute( + sql` + create table ${usersTable} ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await db.execute( + sql` + create table ${users2Table} ( + \`id\` serial primary key, + \`name\` text not null, + \`city_id\` int + ) + `, + ); + + await db.execute( + sql` + create table ${citiesTable} ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); +}); + +test('select all fields', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + + expect(result[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('select sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('select typed sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + expect(users).toEqual([{ name: 'JOHN' }]); +}); + +test('select distinct', async () => { + const usersDistinctTable = singlestoreTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${usersDistinctTable}`); + await db.execute(sql`create table ${usersDistinctTable} (id int, name text)`); + + await db.insert(usersDistinctTable).values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]); + const users = await db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ); + + await db.execute(sql`drop table ${usersDistinctTable}`); + + expect(users).toEqual([{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); +}); + +test('insert returning sql', async () => { + const [result, _] = await db.insert(usersTable).values({ id: 1, name: 'John' }); + + expect(result.insertId).toBe(1); +}); + +test('delete returning sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(users[0].affectedRows).toBe(1); +}); + +test('update returning sql', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + expect(users[0].changedRows).toBe(1); +}); + +test('update with returning all fields', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select().from(usersTable).where(eq(usersTable.id, 1)); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users[0]!.createdAt).toBeInstanceOf(Date); + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 2000); + expect(users).toEqual([{ id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); +}); + +test('update with returning partial', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(updatedUsers[0].changedRows).toBe(1); + + expect(users).toEqual([{ id: 1, name: 'Jane' }]); +}); + +test('delete with returning all fields', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('delete with returning partial', async () => { + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + expect(deletedUser[0].affectedRows).toBe(1); +}); + +test('insert + select', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const result = await db.select().from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersTable).values({ id: 2, name: 'Jane' }); + const result2 = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + expect(result2).toEqual([ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); +}); + +test('json insert', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); +}); + +test('insert with overridden default values', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John', verified: true }); + const result = await db.select().from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test('insert many', async () => { + await db.insert(usersTable).values([ + { id: 1, name: 'John' }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'] }, + { id: 3, name: 'Jane' }, + { id: 4, name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); +}); + +test('insert many with returning', async () => { + const result = await db.insert(usersTable).values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + + expect(result[0].affectedRows).toBe(4); +}); + +test('select with group by as field', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.name) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +}); + +test('select with group by as sql + column', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by as column + sql', async () => { + await db.insert(usersTable).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test('select with group by complex query', async () => { + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + expect(result).toEqual([{ name: 'Jane' }]); +}); + +test('build query', async () => { + const query = db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + expect(query).toEqual({ + sql: `select \`id\`, \`name\` from \`${getTableName(usersTable)}\` group by \`${ + getTableName(usersTable) + }\`.\`id\`, \`${getTableName(usersTable)}\`.\`name\``, + params: [], + }); +}); + +test('build query insert with onDuplicate', async () => { + const query = db.insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }) + .toSQL(); + + expect(query).toEqual({ + sql: `insert into \`${ + getTableName(usersTable) + }\` (\`id\`, \`name\`, \`verified\`, \`jsonb\`, \`created_at\`) values (default, ?, default, ?, default) on duplicate key update \`name\` = ?`, + params: ['John', '["foo","bar"]', 'John1'], + }); +}); + +test('insert with onDuplicate', async () => { + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John1' }]); +}); + +test('insert conflict', async () => { + await db.insert(usersTable) + .values({ name: 'John' }); + + await expect((async () => { + db.insert(usersTable).values({ id: 1, name: 'John1' }); + })()).resolves.not.toThrowError(); +}); + +test('insert conflict with ignore', async () => { + await db.insert(usersTable) + .values({ id: 1, name: 'John' }); + + await db.insert(usersTable) + .ignore() + .values({ id: 1, name: 'John1' }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + expect(res).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert sql', async () => { + await db.insert(usersTable).values({ id: 1, name: sql`${'John'}` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('partial join with alias', async () => { + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }).from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([{ + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }]); +}); + +test('full join with alias', async () => { + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select().from(users) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(users.id, 10)) + .orderBy(asc(users.id)); + + expect(result).toEqual([{ + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('select from alias', async () => { + const singlestoreTable = singlestoreTableCreator((name) => `prefixed_${name}`); + + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(user) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(user.id, 10)) + .orderBy(asc(user.id)); + + expect(result).toEqual([{ + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('insert with spaces', async () => { + await db.insert(usersTable).values({ id: 1, name: sql`'Jo h n'` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + + expect(result).toEqual([{ id: 1, name: 'Jo h n' }]); +}); + +test('prepared statement', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const statement = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .prepare(); + const result = await statement.execute(); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('prepared statement reuse', async () => { + const stmt = db.insert(usersTable).values({ + verified: true, + id: sql.placeholder('id'), + name: sql.placeholder('name'), + }).prepare(); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ id: i + 1, name: `John ${i}` }); + } + + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }).from(usersTable) + .orderBy(asc(usersTable.id)); + + expect(result).toEqual([ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); +}); + +test('prepared statement with placeholder in .where', async () => { + await db.insert(usersTable).values({ id: 1, name: 'John' }); + const stmt = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); +}); + +test('migrator', async () => { + const usersMigratorTable = singlestoreTableRaw('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), + }, (table) => { + return { + name: uniqueIndex('').on(table.name).using('btree'), + }; + }); + + await db.execute(sql.raw(`drop table if exists cities_migration`)); + await db.execute(sql.raw(`drop table if exists users_migration`)); + await db.execute(sql.raw(`drop table if exists users12`)); + await db.execute(sql.raw(`drop table if exists __drizzle_migrations`)); + + await migrate(db, { migrationsFolder: './drizzle2/singlestore' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + expect(result).toEqual([{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql.raw(`drop table cities_migration`)); + await db.execute(sql.raw(`drop table users_migration`)); + await db.execute(sql.raw(`drop table users12`)); + await db.execute(sql.raw(`drop table __drizzle_migrations`)); +}); + +test('insert via db.execute + select via db.execute', async () => { + await db.execute( + sql`insert into ${usersTable} (${new Name(usersTable.id.name)}, ${new Name( + usersTable.name.name, + )}) values (1, ${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>(sql`select id, name from ${usersTable}`); + expect(result[0]).toEqual([{ id: 1, name: 'John' }]); +}); + +test('insert via db.execute w/ query builder', async () => { + const inserted = await db.execute( + db.insert(usersTable).values({ name: 'John' }), + ); + expect(inserted[0].affectedRows).toBe(1); +}); + +test('insert + select all possible dates', async () => { + const datesTable = singlestoreTable('datestable', { + date: date('date'), + dateAsString: date('date_as_string', { mode: 'string' }), + time: time('time'), + datetime: datetime('datetime'), + datetimeAsString: datetime('datetime_as_string', { mode: 'string' }), + year: year('year'), + }); + + await db.execute(sql`drop table if exists ${datesTable}`); + await db.execute( + sql` + create table ${datesTable} ( + \`date\` date, + \`date_as_string\` date, + \`time\` time, + \`datetime\` datetime, + \`datetime_as_string\` datetime, + \`year\` year + ) + `, + ); + + const d = new Date('2022-11-11'); + + await db.insert(datesTable).values({ + date: d, + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: d, + year: 22, + datetimeAsString: '2022-11-11 12:12:12', + }); + + const res = await db.select().from(datesTable); + + expect(res[0]?.date).toBeInstanceOf(Date); + expect(res[0]?.datetime).toBeInstanceOf(Date); + expect(typeof res[0]?.dateAsString).toBe('string'); + expect(typeof res[0]?.datetimeAsString).toBe('string'); + + expect(res).toEqual([{ + date: toLocalDate(new Date('2022-11-11')), + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: new Date('2022-11-11'), + year: 2022, + datetimeAsString: '2022-11-11 12:12:12', + }]); + + await db.execute(sql`drop table ${datesTable}`); +}); + +test('SingleStore enum test case #1', async () => { + const tableWithEnums = singlestoreTable('enums_test_case', { + id: serial('id').primaryKey(), + enum1: singlestoreEnum('enum1', ['a', 'b', 'c']).notNull(), + enum2: singlestoreEnum('enum2', ['a', 'b', 'c']).default('a'), + enum3: singlestoreEnum('enum3', ['a', 'b', 'c']).notNull().default('b'), + }); + + await db.execute(sql`drop table if exists ${tableWithEnums}`); + + await db.execute(sql` + create table ${tableWithEnums} ( + \`id\` serial primary key, + \`enum1\` ENUM('a', 'b', 'c') not null, + \`enum2\` ENUM('a', 'b', 'c') default 'a', + \`enum3\` ENUM('a', 'b', 'c') not null default 'b' + ) + `); + + await db.insert(tableWithEnums).values([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum3: 'c' }, + { id: 3, enum1: 'a' }, + ]); + + const res = await db.select().from(tableWithEnums).orderBy(asc(tableWithEnums.id)); + + await db.execute(sql`drop table ${tableWithEnums}`); + + expect(res).toEqual([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum2: 'a', enum3: 'c' }, + { id: 3, enum1: 'a', enum2: 'a', enum3: 'b' }, + ]); +}); + +test('left join (flat object fields)', async () => { + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + userId: users2Table.id, + userName: users2Table.name, + cityId: citiesTable.id, + cityName: citiesTable.name, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { userId: 1, userName: 'John', cityId: 1, cityName: 'Paris' }, + { userId: 2, userName: 'Jane', cityId: null, cityName: null }, + ]); +}); + +test('left join (grouped fields)', async () => { + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select({ + id: users2Table.id, + user: { + name: users2Table.name, + nameUpper: sql`upper(${users2Table.name})`, + }, + city: { + id: citiesTable.id, + name: citiesTable.name, + nameUpper: sql`upper(${citiesTable.name})`, + }, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + id: 1, + user: { name: 'John', nameUpper: 'JOHN' }, + city: { id: 1, name: 'Paris', nameUpper: 'PARIS' }, + }, + { + id: 2, + user: { name: 'Jane', nameUpper: 'JANE' }, + city: null, + }, + ]); +}); + +test('left join (all fields)', async () => { + await db.insert(citiesTable) + .values([{ id: 1, name: 'Paris' }, { id: 2, name: 'London' }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane' }]); + + const res = await db.select().from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)) + .orderBy(asc(users2Table.id)); + + expect(res).toEqual([ + { + users2: { + id: 1, + name: 'John', + cityId: 1, + }, + cities: { + id: 1, + name: 'Paris', + }, + }, + { + users2: { + id: 2, + name: 'Jane', + cityId: null, + }, + cities: null, + }, + ]); +}); + +test('join subquery', async () => { + const coursesTable = singlestoreTable('courses', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + categoryId: int('category_id'), + }); + + const courseCategoriesTable = singlestoreTable('course_categories', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${coursesTable}`); + await db.execute(sql`drop table if exists ${courseCategoriesTable}`); + + await db.execute( + sql` + create table ${courseCategoriesTable} ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.execute( + sql` + create table ${coursesTable} ( + \`id\` serial primary key, + \`name\` text not null, + \`category_id\` int + ) + `, + ); + + await db.insert(courseCategoriesTable).values([ + { id: 1, name: 'Category 1' }, + { id: 2, name: 'Category 2' }, + { id: 3, name: 'Category 3' }, + { id: 4, name: 'Category 4' }, + ]); + + await db.insert(coursesTable).values([ + { id: 1, name: 'Development', categoryId: 2 }, + { id: 2, name: 'IT & Software', categoryId: 3 }, + { id: 3, name: 'Marketing', categoryId: 4 }, + { id: 4, name: 'Design', categoryId: 1 }, + ]); + + const sq2 = db + .select({ + categoryId: courseCategoriesTable.id, + category: courseCategoriesTable.name, + total: sql`count(${courseCategoriesTable.id})`, + }) + .from(courseCategoriesTable) + .groupBy(courseCategoriesTable.id, courseCategoriesTable.name) + .orderBy(courseCategoriesTable.id) + .as('sq2'); + + const res = await db + .select({ + courseName: coursesTable.name, + categoryId: sq2.categoryId, + }) + .from(coursesTable) + .leftJoin(sq2, eq(coursesTable.categoryId, sq2.categoryId)) + .orderBy(coursesTable.name); + + await db.execute(sql`drop table ${coursesTable}`); + await db.execute(sql`drop table ${courseCategoriesTable}`); + + expect(res).toEqual([ + { courseName: 'Design', categoryId: 1 }, + { courseName: 'Development', categoryId: 2 }, + { courseName: 'IT & Software', categoryId: 3 }, + { courseName: 'Marketing', categoryId: 4 }, + ]); +}); + +test('with ... select', async () => { + const orders = singlestoreTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull(), + amount: int('amount').notNull(), + quantity: int('quantity').notNull(), + }); + + await db.execute(sql`drop table if exists ${orders}`); + await db.execute( + sql` + create table ${orders} ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: regionalSales.region, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`cast(sum(${orders.quantity}) as unsigned)`, + productSales: sql`cast(sum(${orders.amount}) as unsigned)`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))) + .groupBy(orders.region, orders.product) + .orderBy(orders.region, orders.product); + + await db.execute(sql`drop table ${orders}`); + + expect(result).toEqual([ + { + region: 'Europe', + product: 'A', + productUnits: 3, + productSales: 30, + }, + { + region: 'Europe', + product: 'B', + productUnits: 5, + productSales: 50, + }, + { + region: 'US', + product: 'A', + productUnits: 7, + productSales: 70, + }, + { + region: 'US', + product: 'B', + productUnits: 9, + productSales: 90, + }, + ]); +}); + +test('select from subquery sql', async () => { + await db.insert(users2Table).values([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]); + + const sq = db + .select({ name: sql`concat(${users2Table.name}, " modified")`.as('name') }) + .from(users2Table) + .orderBy(asc(users2Table.id)) + .as('sq'); + + const res = await db.select({ name: sq.name }).from(sq); + + expect(res).toEqual([{ name: 'John modified' }, { name: 'Jane modified' }]); +}); + +test('select a field without joining its table', () => { + expect(() => db.select({ name: users2Table.name }).from(usersTable).prepare()).toThrowError(); +}); + +test('select all fields from subquery without alias', () => { + const sq = db.$with('sq').as(db.select({ name: sql`upper(${users2Table.name})` }).from(users2Table)); + + expect(() => db.select().from(sq).prepare()).toThrowError(); +}); + +test('select count()', async () => { + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }]); + + const res = await db.select({ count: sql`count(*)` }).from(usersTable); + + expect(res).toEqual([{ count: 2 }]); +}); + +test('select for ...', () => { + { + const query = db.select().from(users2Table).for('update').toSQL(); + expect(query.sql).toMatch(/ for update$/); + } + { + const query = db.select().from(users2Table).for('share', { skipLocked: true }).toSQL(); + expect(query.sql).toMatch(/ for share skip locked$/); + } + { + const query = db.select().from(users2Table).for('update', { noWait: true }).toSQL(); + expect(query.sql).toMatch(/ for update no wait$/); + } +}); + +test('having', async () => { + await db.insert(citiesTable).values([{ id: 1, name: 'London' }, { id: 2, name: 'Paris' }, { + id: 3, + name: 'New York', + }]); + + await db.insert(users2Table).values([{ id: 1, name: 'John', cityId: 1 }, { id: 2, name: 'Jane', cityId: 1 }, { + id: 3, + name: 'Jack', + cityId: 2, + }]); + + const result = await db + .select({ + id: citiesTable.id, + name: sql`upper(${citiesTable.name})`.as('upper_name'), + usersCount: sql`count(${users2Table.id})`.as('users_count'), + }) + .from(citiesTable) + .leftJoin(users2Table, eq(users2Table.cityId, citiesTable.id)) + .where(({ name }) => sql`length(${name}) >= 3`) + .groupBy(citiesTable.id) + .having(({ usersCount }) => sql`${usersCount} > 0`) + .orderBy(({ name }) => name); + + expect(result).toEqual([ + { + id: 1, + name: 'LONDON', + usersCount: 2, + }, + { + id: 2, + name: 'PARIS', + usersCount: 1, + }, + ]); +}); + +// TODO: Unskip when views are supported +/* test.skip('view', async () => { + const newYorkers1 = singlestoreView('new_yorkers') + .as((qb) => qb.select().from(users2Table).where(eq(users2Table.cityId, 1))); + + const newYorkers2 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).as(sql`select * from ${users2Table} where ${eq(users2Table.cityId, 1)}`); + + const newYorkers3 = singlestoreView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).existing(); + + await db.execute(sql`create view new_yorkers as ${getViewConfig(newYorkers1).query}`); + + await db.insert(citiesTable).values([{ name: 'New York' }, { name: 'Paris' }]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2).orderBy(asc(newYorkers2.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3).orderBy(asc(newYorkers3.id)); + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1).orderBy(asc(newYorkers1.id)); + expect(result).toEqual([ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop view ${newYorkers1}`); +}); */ + +test('select from raw sql', async () => { + const result = await db.select({ + id: sql`id`, + name: sql`name`, + }).from(sql`(select 1 as id, 'John' as name) as users`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John' }, + ]); +}); + +test('select from raw sql with joins', async () => { + const result = await db + .select({ + id: sql`users.id`, + name: sql`users.name`, + userCity: sql`users.city`, + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, sql`cities.id = users.id`); + + Expect>; + + expect(result).toEqual([ + { id: 1, name: 'John', userCity: 'New York', cityName: 'Paris' }, + ]); +}); + +test('join on aliased sql from select', async () => { + const result = await db + .select({ + userId: sql`users.id`.as('userId'), + name: sql`users.name`, + userCity: sql`users.city`, + cityId: sql`cities.id`.as('cityId'), + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, (cols) => eq(cols.cityId, cols.userId)); + + Expect>; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); +}); + +test('join on aliased sql from with clause', async () => { + const users = db.$with('users').as( + db.select({ + id: sql`id`.as('userId'), + name: sql`name`.as('userName'), + city: sql`city`.as('city'), + }).from( + sql`(select 1 as id, 'John' as name, 'New York' as city) as users`, + ), + ); + + const cities = db.$with('cities').as( + db.select({ + id: sql`id`.as('cityId'), + name: sql`name`.as('cityName'), + }).from( + sql`(select 1 as id, 'Paris' as name) as cities`, + ), + ); + + const result = await db + .with(users, cities) + .select({ + userId: users.id, + name: users.name, + userCity: users.city, + cityId: cities.id, + cityName: cities.name, + }) + .from(users) + .leftJoin(cities, (cols) => eq(cols.cityId, cols.userId)); + + Expect>; + + expect(result).toEqual([ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); +}); + +test('prefixed table', async () => { + const singlestoreTable = singlestoreTableCreator((name) => `myprefix_${name}`); + + const users = singlestoreTable('test_prefixed_table_with_unique_name', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table myprefix_test_prefixed_table_with_unique_name (id int not null primary key, name text not null)`, + ); + + await db.insert(users).values({ id: 1, name: 'John' }); + + const result = await db.select().from(users); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + + await db.execute(sql`drop table ${users}`); +}); + +test('orderBy with aliased column', () => { + const query = db.select({ + test: sql`something`.as('test'), + }).from(users2Table).orderBy((fields) => fields.test).toSQL(); + + expect(query.sql).toBe(`select something as \`test\` from \`${getTableName(users2Table)}\` order by \`test\``); +}); + +test('timestamp timezone', async () => { + const date = new Date(Date.parse('2020-01-01T12:34:56+07:00')); + + await db.insert(usersTable).values({ id: 1, name: 'With default times' }); + await db.insert(usersTable).values({ + id: 2, + name: 'Without default times', + createdAt: date, + }); + const users = await db.select().from(usersTable).orderBy(asc(usersTable.id)); + + // check that the timestamps are set correctly for default times + expect(Math.abs(users[0]!.createdAt.getTime() - Date.now())).toBeLessThan(2000); + + // check that the timestamps are set correctly for non default times + expect(Math.abs(users[1]!.createdAt.getTime() - date.getTime())).toBeLessThan(2000); +}); + +test('transaction', async () => { + const users = singlestoreTable('users_transactions', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + const products = singlestoreTable('products_transactions', { + id: serial('id').primaryKey(), + price: int('price').notNull(), + stock: int('stock').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop table if exists ${products}`); + + await db.execute(sql`create table ${users} (id serial not null primary key, balance int not null)`); + await db.execute( + sql`create table ${products} (id serial not null primary key, price int not null, stock int not null)`, + ); + + const [{ insertId: userId }] = await db.insert(users).values({ id: 1, balance: 100 }); + const user = await db.select().from(users).where(eq(users.id, userId)).then((rows) => rows[0]!); + const [{ insertId: productId }] = await db.insert(products).values({ id: 1, price: 10, stock: 10 }); + const product = await db.select().from(products).where(eq(products.id, productId)).then((rows) => rows[0]!); + + await db.transaction(async (tx) => { + await tx.update(users).set({ balance: user.balance - product.price }).where(eq(users.id, user.id)); + await tx.update(products).set({ stock: product.stock - 1 }).where(eq(products.id, product.id)); + }); + + const result = await db.select().from(users); + + await db.execute(sql`drop table ${users}`); + await db.execute(sql`drop table ${products}`); + + expect(result).toEqual([{ id: 1, balance: 90 }]); +}); + +test('transaction rollback', async () => { + const users = singlestoreTable('users_transactions_rollback', { + id: serial('id').primaryKey(), + balance: int('balance').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, balance int not null)`, + ); + + await expect((async () => { + await db.transaction(async (tx) => { + await tx.insert(users).values({ balance: 100 }); + tx.rollback(); + }); + })()).rejects.toThrowError(TransactionRollbackError); + + const result = await db.select().from(users); + + await db.execute(sql`drop table ${users}`); + + expect(result).toEqual([]); +}); + +test('join subquery with join', async () => { + const internalStaff = singlestoreTable('internal_staff', { + userId: int('user_id').notNull(), + }); + + const customUser = singlestoreTable('custom_user', { + id: int('id').notNull(), + }); + + const ticket = singlestoreTable('ticket', { + staffId: int('staff_id').notNull(), + }); + + await db.execute(sql`drop table if exists ${internalStaff}`); + await db.execute(sql`drop table if exists ${customUser}`); + await db.execute(sql`drop table if exists ${ticket}`); + + await db.execute(sql`create table ${internalStaff} (user_id integer not null)`); + await db.execute(sql`create table ${customUser} (id integer not null)`); + await db.execute(sql`create table ${ticket} (staff_id integer not null)`); + + await db.insert(internalStaff).values({ userId: 1 }); + await db.insert(customUser).values({ id: 1 }); + await db.insert(ticket).values({ staffId: 1 }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin(customUser, eq(internalStaff.userId, customUser.id)) + .as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + await db.execute(sql`drop table ${internalStaff}`); + await db.execute(sql`drop table ${customUser}`); + await db.execute(sql`drop table ${ticket}`); + + expect(mainQuery).toEqual([{ + ticket: { staffId: 1 }, + internal_staff: { + internal_staff: { userId: 1 }, + custom_user: { id: 1 }, + }, + }]); +}); + +// TODO: Unskip when views are supported +/* test.skip('subquery with view', async () => { + const users = singlestoreTable('users_subquery_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.$with('sq').as(db.select().from(newYorkers)); + const result = await db.with(sq).select().from(sq).orderBy(asc(sq.id)); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); + + expect(result).toEqual([ + { id: 1, name: 'John', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 1 }, + ]); +}); */ + +// TODO: Unskip when views are supported +/* test.skip('join view as subquery', async () => { + const users = singlestoreTable('users_join_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = singlestoreView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 1 }, + { id: 4, name: 'Jill', cityId: 2 }, + ]); + + const sq = db.select().from(newYorkers).as('new_yorkers_sq'); + + const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id)).orderBy(asc(users.id)); + + expect(result).toEqual([ + { + users_join_view: { id: 1, name: 'John', cityId: 1 }, + new_yorkers_sq: { id: 1, name: 'John', cityId: 1 }, + }, + { + users_join_view: { id: 2, name: 'Jane', cityId: 2 }, + new_yorkers_sq: null, + }, + { + users_join_view: { id: 3, name: 'Jack', cityId: 1 }, + new_yorkers_sq: { id: 3, name: 'Jack', cityId: 1 }, + }, + { + users_join_view: { id: 4, name: 'Jill', cityId: 2 }, + new_yorkers_sq: null, + }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); +}); */ + +test('select iterator', async () => { + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const iter = db.select().from(users) + .orderBy(asc(users.id)) + .iterator(); + + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); +}); + +test('select iterator w/ prepared statement', async () => { + const users = singlestoreTable('users_iterator', { + id: serial('id').primaryKey(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial not null primary key)`); + + await db.insert(users).values([{ id: 1 }, { id: 2 }, { id: 3 }]); + + const prepared = db.select().from(users) + .orderBy(asc(users.id)) + .prepare(); + const iter = prepared.iterator(); + const result: typeof users.$inferSelect[] = []; + + for await (const row of iter) { + result.push(row); + } + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); +}); + +test('insert undefined', async () => { + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.insert(users).values({ name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); +}); + +test('update undefined', async () => { + const users = singlestoreTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await expect((async () => { + await db.update(users).set({ name: undefined }); + })()).rejects.toThrowError(); + + await expect((async () => { + await db.update(users).set({ id: 1, name: undefined }); + })()).resolves.not.toThrowError(); + + await db.execute(sql`drop table ${users}`); +}); diff --git a/integration-tests/tests/singlestore/singlestore-proxy.test.ts b/integration-tests/tests/singlestore/singlestore-proxy.test.ts new file mode 100644 index 000000000..51dc48a4a --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore-proxy.test.ts @@ -0,0 +1,140 @@ +import retry from 'async-retry'; +import type { SingleStoreRemoteDatabase } from 'drizzle-orm/singlestore-proxy'; +import { drizzle as proxyDrizzle } from 'drizzle-orm/singlestore-proxy'; +import * as mysql2 from 'mysql2/promise'; +import { afterAll, beforeAll, beforeEach } from 'vitest'; +import { skipTests } from '~/common'; +import { createDockerDB, tests } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +// eslint-disable-next-line drizzle-internal/require-entity-kind +class ServerSimulator { + constructor(private db: mysql2.Connection) {} + + async query(sql: string, params: any[], method: 'all' | 'execute') { + if (method === 'all') { + try { + const result = await this.db.query({ + sql, + values: params, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + + return { data: result[0] as any }; + } catch (e: any) { + return { error: e }; + } + } else if (method === 'execute') { + try { + const result = await this.db.query({ + sql, + values: params, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + + return { data: result as any }; + } catch (e: any) { + return { error: e }; + } + } else { + return { error: 'Unknown method value' }; + } + } + + async migrations(queries: string[]) { + await this.db.query('START TRANSACTION'); + try { + for (const query of queries) { + await this.db.query(query); + } + await this.db.query('COMMIT'); + } catch (e) { + await this.db.query('ROLLBACK'); + throw e; + } + + return {}; + } +} + +let db: SingleStoreRemoteDatabase; +let client: mysql2.Connection; +let serverSimulator: ServerSimulator; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr } = await createDockerDB(); + connectionString = conStr; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + + serverSimulator = new ServerSimulator(client); + db = proxyDrizzle(async (sql, params, method) => { + try { + const response = await serverSimulator.query(sql, params, method); + + if (response.error !== undefined) { + throw response.error; + } + + return { rows: response.data }; + } catch (e: any) { + console.error('Error from singlestore proxy server:', e.message); + throw e; + } + }, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); +}); + +beforeEach((ctx) => { + ctx.singlestore = { + db, + }; +}); + +skipTests([ + 'select iterator w/ prepared statement', + 'select iterator', + 'nested transaction rollback', + 'nested transaction', + 'transaction rollback', + 'transaction', + 'transaction with options (set isolationLevel)', + 'migrator', +]); + +tests(); diff --git a/integration-tests/tests/singlestore/singlestore.test.ts b/integration-tests/tests/singlestore/singlestore.test.ts new file mode 100644 index 000000000..bfb1ee5b7 --- /dev/null +++ b/integration-tests/tests/singlestore/singlestore.test.ts @@ -0,0 +1,51 @@ +import retry from 'async-retry'; +import { drizzle } from 'drizzle-orm/singlestore'; +import type { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'; +import * as mysql2 from 'mysql2/promise'; +import { afterAll, beforeAll, beforeEach } from 'vitest'; +import { createDockerDB, tests } from './singlestore-common'; + +const ENABLE_LOGGING = false; + +let db: SingleStoreDriverDatabase; +let client: mysql2.Connection; + +beforeAll(async () => { + let connectionString; + if (process.env['SINGLESTORE_CONNECTION_STRING']) { + connectionString = process.env['SINGLESTORE_CONNECTION_STRING']; + } else { + const { connectionString: conStr } = await createDockerDB(); + connectionString = conStr; + } + client = await retry(async () => { + client = await mysql2.createConnection(connectionString); + await client.connect(); + return client; + }, { + retries: 20, + factor: 1, + minTimeout: 250, + maxTimeout: 250, + randomize: false, + onRetry() { + client?.end(); + }, + }); + + await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`); + await client.changeUser({ database: 'drizzle' }); + db = drizzle(client, { logger: ENABLE_LOGGING }); +}); + +afterAll(async () => { + await client?.end(); +}); + +beforeEach((ctx) => { + ctx.singlestore = { + db, + }; +}); + +tests(); diff --git a/integration-tests/tests/sqlite/durable-objects/drizzle/0000_cuddly_black_bolt.sql b/integration-tests/tests/sqlite/durable-objects/drizzle/0000_cuddly_black_bolt.sql new file mode 100644 index 000000000..deff0ea9a --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/drizzle/0000_cuddly_black_bolt.sql @@ -0,0 +1,11 @@ +CREATE TABLE `another_users` ( + `id` integer PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `email` text NOT NULL +); +--> statement-breakpoint +CREATE TABLE `users12` ( + `id` integer PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `email` text NOT NULL +); diff --git a/integration-tests/tests/sqlite/durable-objects/drizzle/meta/0000_snapshot.json b/integration-tests/tests/sqlite/durable-objects/drizzle/meta/0000_snapshot.json new file mode 100644 index 000000000..9c151ecc9 --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/drizzle/meta/0000_snapshot.json @@ -0,0 +1,80 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "66be869a-d55d-4790-a382-de654dff1506", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "another_users": { + "name": "another_users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users12": { + "name": "users12", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/integration-tests/tests/sqlite/durable-objects/drizzle/meta/_journal.json b/integration-tests/tests/sqlite/durable-objects/drizzle/meta/_journal.json new file mode 100644 index 000000000..ab94199ee --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1732696446109, + "tag": "0000_cuddly_black_bolt", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js b/integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js new file mode 100644 index 000000000..c6f2a6ada --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/drizzle/migrations.js @@ -0,0 +1,9 @@ +import m0000 from './0000_cuddly_black_bolt.sql'; +import journal from './meta/_journal.json'; + +export default { + journal, + migrations: { + m0000, + }, +}; diff --git a/integration-tests/tests/sqlite/durable-objects/index.ts b/integration-tests/tests/sqlite/durable-objects/index.ts new file mode 100644 index 000000000..b67534d4e --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/index.ts @@ -0,0 +1,3619 @@ +/// + +import { expect } from 'chai'; +import { DurableObject } from 'cloudflare:workers'; +import { + and, + asc, + avg, + avgDistinct, + count, + countDistinct, + eq, + exists, + getTableColumns, + gt, + gte, + inArray, + lt, + max, + min, + Name, + notInArray, + sql, + sum, + sumDistinct, +} from 'drizzle-orm'; +import { drizzle, type DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite'; +import { migrate } from 'drizzle-orm/durable-sqlite/migrator'; +import { + alias, + type BaseSQLiteDatabase, + blob, + except, + getViewConfig, + int, + integer, + intersect, + numeric, + primaryKey, + sqliteTable, + sqliteTableCreator, + sqliteView, + text, + union, + unionAll, +} from 'drizzle-orm/sqlite-core'; +import { type Equal, Expect } from '~/utils'; +import migrations from './drizzle/migrations'; + +export const usersTable = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + verified: integer('verified', { mode: 'boolean' }).notNull().default(false), + json: blob('json', { mode: 'json' }).$type(), + createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(sql`strftime('%s', 'now')`), +}); + +export const usersOnUpdate = sqliteTable('users_on_update', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + updateCounter: integer('update_counter').default(sql`1`).$onUpdateFn(() => sql`update_counter + 1`), + updatedAt: integer('updated_at', { mode: 'timestamp_ms' }).$onUpdate(() => new Date()), + alwaysNull: text('always_null').$type().$onUpdate(() => null), +}); + +export const users2Table = sqliteTable('users2', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').references(() => citiesTable.id), +}); + +export const citiesTable = sqliteTable('cities', { + id: integer('id').primaryKey(), + name: text('name').notNull(), +}); + +export const coursesTable = sqliteTable('courses', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + categoryId: integer('category_id').references(() => courseCategoriesTable.id), +}); + +export const courseCategoriesTable = sqliteTable('course_categories', { + id: integer('id').primaryKey(), + name: text('name').notNull(), +}); + +export const orders = sqliteTable('orders', { + id: integer('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull().$default(() => 'random_string'), + amount: integer('amount').notNull(), + quantity: integer('quantity').notNull(), +}); + +export const usersMigratorTable = sqliteTable('users12', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}); + +export const anotherUsersMigratorTable = sqliteTable('another_users', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}); + +export const pkExampleTable = sqliteTable('pk_example', { + id: integer('id').notNull(), + name: text('name').notNull(), + email: text('email').notNull(), +}, (table) => ({ + compositePk: primaryKey({ columns: [table.id, table.name] }), +})); + +export const bigIntExample = sqliteTable('big_int_example', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + bigInt: blob('big_int', { mode: 'bigint' }).notNull(), +}); + +// To test aggregate functions +export const aggregateTable = sqliteTable('aggregate_table', { + id: integer('id').primaryKey({ autoIncrement: true }).notNull(), + name: text('name').notNull(), + a: integer('a'), + b: integer('b'), + c: integer('c'), + nullOnly: integer('null_only'), +}); + +async function setupSetOperationTest(db: BaseSQLiteDatabase) { + await db.run(sql`drop table if exists users2`); + await db.run(sql`drop table if exists cities`); + await db.run(sql` + create table \`cities\` ( + id integer primary key, + name text not null + ) + `); + + await db.run(sql` + create table \`users2\` ( + id integer primary key, + name text not null, + city_id integer references ${citiesTable}(${sql.identifier(citiesTable.id.name)}) + ) + `); + + await db.insert(citiesTable).values([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 3 }, + { id: 4, name: 'Peter', cityId: 3 }, + { id: 5, name: 'Ben', cityId: 2 }, + { id: 6, name: 'Jill', cityId: 1 }, + { id: 7, name: 'Mary', cityId: 2 }, + { id: 8, name: 'Sally', cityId: 1 }, + ]); +} + +async function setupAggregateFunctionsTest(db: BaseSQLiteDatabase) { + await db.run(sql`drop table if exists "aggregate_table"`); + await db.run( + sql` + create table "aggregate_table" ( + "id" integer primary key autoincrement not null, + "name" text not null, + "a" integer, + "b" integer, + "c" integer, + "null_only" integer + ); + `, + ); + await db.insert(aggregateTable).values([ + { name: 'value 1', a: 5, b: 10, c: 20 }, + { name: 'value 1', a: 5, b: 20, c: 30 }, + { name: 'value 2', a: 10, b: 50, c: 60 }, + { name: 'value 3', a: 20, b: 20, c: null }, + { name: 'value 4', a: null, b: 90, c: 120 }, + { name: 'value 5', a: 80, b: 10, c: null }, + { name: 'value 6', a: null, b: null, c: 150 }, + ]); +} + +// eslint-disable-next-line drizzle-internal/require-entity-kind +export class MyDurableObject extends DurableObject { + storage: DurableObjectStorage; + db: DrizzleSqliteDODatabase; + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + this.storage = ctx.storage; + this.db = drizzle(this.storage, { logger: false }); + } + + async migrate1(): Promise { + try { + this.db.run(sql`drop table if exists another_users`); + this.db.run(sql`drop table if exists users12`); + this.db.run(sql`drop table if exists __drizzle_migrations`); + + migrate(this.db, migrations); + + this.db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result = this.db.select().from(usersMigratorTable).all(); + + this.db.insert(anotherUsersMigratorTable).values({ name: 'John', email: 'email' }).run(); + const result2 = this.db.select().from(anotherUsersMigratorTable).all(); + + expect(result).deep.equal([{ id: 1, name: 'John', email: 'email' }]); + expect(result2).deep.equal([{ id: 1, name: 'John', email: 'email' }]); + + this.db.run(sql`drop table another_users`); + this.db.run(sql`drop table users12`); + this.db.run(sql`drop table __drizzle_migrations`); + } catch { + throw new Error('migrate1 has broken'); + } + } + + async beforeEach(): Promise { + this.db.run(sql`drop table if exists ${usersTable}`); + this.db.run(sql`drop table if exists ${users2Table}`); + this.db.run(sql`drop table if exists ${citiesTable}`); + this.db.run(sql`drop table if exists ${coursesTable}`); + this.db.run(sql`drop table if exists ${courseCategoriesTable}`); + this.db.run(sql`drop table if exists ${orders}`); + this.db.run(sql`drop table if exists ${bigIntExample}`); + this.db.run(sql`drop table if exists ${pkExampleTable}`); + this.db.run(sql`drop table if exists user_notifications_insert_into`); + this.db.run(sql`drop table if exists users_insert_into`); + this.db.run(sql`drop table if exists notifications_insert_into`); + + this.db.run(sql` + create table ${usersTable} ( + id integer primary key, + name text not null, + verified integer not null default 0, + json blob, + created_at integer not null default (strftime('%s', 'now')) + ) + `); + + this.db.run(sql` + create table ${citiesTable} ( + id integer primary key, + name text not null + ) + `); + this.db.run(sql` + create table ${courseCategoriesTable} ( + id integer primary key, + name text not null + ) + `); + + this.db.run(sql` + create table ${users2Table} ( + id integer primary key, + name text not null, + city_id integer references ${citiesTable}(${sql.identifier(citiesTable.id.name)}) + ) + `); + this.db.run(sql` + create table ${coursesTable} ( + id integer primary key, + name text not null, + category_id integer references ${courseCategoriesTable}(${sql.identifier(courseCategoriesTable.id.name)}) + ) + `); + this.db.run(sql` + create table ${orders} ( + id integer primary key, + region text not null, + product text not null, + amount integer not null, + quantity integer not null + ) + `); + this.db.run(sql` + create table ${pkExampleTable} ( + id integer not null, + name text not null, + email text not null, + primary key (id, name) + ) + `); + this.db.run(sql` + create table ${bigIntExample} ( + id integer primary key, + name text not null, + big_int blob not null + ) + `); + } + + async insertBigIntValues(): Promise { + try { + await this.beforeEach(); + + this.db + .insert(bigIntExample) + .values({ name: 'one', bigInt: BigInt('0') }) + .run(); + this.db + .insert(bigIntExample) + .values({ name: 'two', bigInt: BigInt('127') }) + .run(); + this.db + .insert(bigIntExample) + .values({ name: 'three', bigInt: BigInt('32767') }) + .run(); + this.db + .insert(bigIntExample) + .values({ name: 'four', bigInt: BigInt('1234567890') }) + .run(); + this.db + .insert(bigIntExample) + .values({ name: 'five', bigInt: BigInt('12345678900987654321') }) + .run(); + + const result = this.db.select().from(bigIntExample).all(); + expect(result).deep.equal([ + { id: 1, name: 'one', bigInt: BigInt('0') }, + { id: 2, name: 'two', bigInt: BigInt('127') }, + { id: 3, name: 'three', bigInt: BigInt('32767') }, + { id: 4, name: 'four', bigInt: BigInt('1234567890') }, + { id: 5, name: 'five', bigInt: BigInt('12345678900987654321') }, + ]); + } catch (error: any) { + console.log(error); + throw new Error('insertBigIntValues has broken'); + } + } + async selectAllFields(): Promise { + try { + await this.beforeEach(); + const now = Date.now(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const result = this.db.select().from(usersTable).all(); + expect(result[0]!.createdAt).instanceOf(Date); + expect(Math.abs(result[0]!.createdAt.getTime() - now)).lessThan(5000); + expect(result).deep.equal([{ + id: 1, + name: 'John', + verified: false, + json: null, + createdAt: result[0]!.createdAt, + }]); + } catch { + throw new Error('selectAllFields has broken'); + } + } + + async selectPartial(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const result = this.db.select({ name: usersTable.name }).from(usersTable).all(); + + expect(result).deep.equal([{ name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectPartial error`); + } + } + + async selectSql(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .all(); + + expect(users).deep.equal([{ name: 'JOHN' }]); + } catch { + throw new Error('selectSql has broken'); + } + } + + async selectTypedSql(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .all(); + + expect(users).deep.equal([{ name: 'JOHN' }]); + } catch { + throw new Error('selectTypedSql has broken'); + } + } + + async selectWithEmptyArrayInInArray(): Promise { + try { + await this.beforeEach(); + + await this.db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + const result = await this.db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(inArray(usersTable.id, [])); + + expect(result).deep.equal([]); + } catch (error: any) { + console.error(error); + throw new Error('selectWithEmptyArrayInInArray has broken'); + } + } + + async selectWithEmptyArrayInNotInArray(): Promise { + try { + await this.beforeEach(); + + await this.db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + const result = await this.db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable) + .where(notInArray(usersTable.id, [])); + + expect(result).deep.equal([{ name: 'JOHN' }, { name: 'JANE' }, { name: 'JANE' }]); + } catch (error: any) { + console.error(error); + throw new Error('selectWithEmptyArrayInNotInArray has broken'); + } + } + + async selectDistinct(): Promise { + try { + await this.beforeEach(); + + const usersDistinctTable = sqliteTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${usersDistinctTable}`); + this.db.run(sql`create table ${usersDistinctTable} (id integer, name text)`); + + this.db + .insert(usersDistinctTable) + .values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]) + .run(); + const users = this.db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ).all(); + + this.db.run(sql`drop table ${usersDistinctTable}`); + + expect(users).deep.equal([ + { id: 1, name: 'Jane' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + ]); + } catch (error: any) { + console.error(error); + throw new Error('selectDistinct has broken'); + } + } + + async returingSql(): Promise { + try { + await this.beforeEach(); + + const users = this.db + .insert(usersTable) + .values({ name: 'John' }) + .returning({ + name: sql`upper(${usersTable.name})`, + }) + .all(); + + expect(users).deep.equal([{ name: 'JOHN' }]); + } catch (error: any) { + console.error(error); + throw new Error('returingSql has broken'); + } + } + + async $defaultFunction(): Promise { + try { + await this.beforeEach(); + + await this.db.insert(orders).values({ id: 1, region: 'Ukraine', amount: 1, quantity: 1 }); + const selectedOrder = await this.db.select().from(orders); + + expect(selectedOrder).deep.equal([ + { + id: 1, + amount: 1, + quantity: 1, + region: 'Ukraine', + product: 'random_string', + }, + ]); + } catch (error: any) { + console.error(error); + throw new Error('defaultFunction has broken'); + } + } + + async deleteReturningSql(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .delete(usersTable) + .where(eq(usersTable.name, 'John')) + .returning({ + name: sql`upper(${usersTable.name})`, + }) + .all(); + + expect(users).deep.equal([{ name: 'JOHN' }]); + } catch (error: any) { + console.error(error); + throw new Error('deleteReturningSql has broken'); + } + } + + async queryCheckInsertSingleEmptyRow(): Promise { + try { + await this.beforeEach(); + + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + const query = this.db.insert(users).values({}).toSQL(); + + expect(query).deep.equal({ + sql: 'insert into "users" ("id", "name", "state") values (null, ?, null)', + params: ['Dan'], + }); + } catch (error: any) { + console.error(error); + throw new Error('queryCheckInsertSingleEmptyRow has broken'); + } + } + + async queryCheckInsertMultipleEmptyRow(): Promise { + try { + await this.beforeEach(); + + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + const query = this.db.insert(users).values([{}, {}]).toSQL(); + + expect(query).deep.equal({ + sql: 'insert into "users" ("id", "name", "state") values (null, ?, null), (null, ?, null)', + params: ['Dan', 'Dan'], + }); + } catch (error: any) { + console.error(error); + throw new Error('queryCheckInsertMultipleEmptyRow has broken'); + } + } + + async insertAllDefaultsIn1Row(): Promise { + try { + await this.beforeEach(); + + const users = sqliteTable('empty_insert_single', { + id: integer('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text default 'Dan', state text)`); + + this.db.insert(users).values({}).run(); + + const res = this.db.select().from(users).all(); + + expect(res).deep.equal([{ id: 1, name: 'Dan', state: null }]); + } catch (error: any) { + console.error(error); + throw new Error('insertAllDefaultsIn1Row has broken'); + } + } + + async insertAllDefaultsInMultipleRows(): Promise { + try { + await this.beforeEach(); + + const users = sqliteTable('empty_insert_multiple', { + id: integer('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text default 'Dan', state text)`); + + this.db.insert(users).values([{}, {}]).run(); + + const res = this.db.select().from(users).all(); + + expect(res).deep.equal([ + { id: 1, name: 'Dan', state: null }, + { id: 2, name: 'Dan', state: null }, + ]); + } catch (error: any) { + console.error(error); + throw new Error('insertAllDefaultsInMultipleRows has broken'); + } + } + + async updateReturningSql(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning({ + name: sql`upper(${usersTable.name})`, + }) + .all(); + + expect(users).deep.equal([{ name: 'JANE' }]); + } catch (error: any) { + console.error(error); + throw new Error('updateReturningSql has broken'); + } + } + + async insertWithAutoIncrement(): Promise { + try { + await this.beforeEach(); + + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'George' }, { name: 'Austin' }]) + .run(); + const result = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).all(); + + expect(result).deep.equal([ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'George' }, + { id: 4, name: 'Austin' }, + ]); + } catch (error: any) { + console.error(error); + throw new Error('insertWithAutoIncrement has broken'); + } + } + + async insertDataWithDefaultValues(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const result = this.db.select().from(usersTable).all(); + + expect(result).deep.equal([{ + id: 1, + name: 'John', + verified: false, + json: null, + createdAt: result[0]!.createdAt, + }]); + } catch (error: any) { + console.error(error); + throw new Error('insertDataWithDefaultValues has broken'); + } + } + + async insertDataWithOverridenDefaultValues(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John', verified: true }).run(); + const result = this.db.select().from(usersTable).all(); + + expect(result).deep.equal([{ id: 1, name: 'John', verified: true, json: null, createdAt: result[0]!.createdAt }]); + } catch (error: any) { + console.error(error); + throw new Error('insertDataWithOverridenDefaultValues has broken'); + } + } + + async updateWithReturningFields(): Promise { + try { + await this.beforeEach(); + const now = Date.now(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')).returning() + .all(); + + expect(users[0]!.createdAt).instanceOf(Date); + expect(Math.abs(users[0]!.createdAt.getTime() - now)).lessThan(5000); + expect(users).deep.equal([{ id: 1, name: 'Jane', verified: false, json: null, createdAt: users[0]!.createdAt }]); + } catch (error: any) { + console.error(error); + throw new Error('updateWithReturningFields has broken'); + } + } + + async updateWithReturningPartial(): Promise { + try { + await this.beforeEach(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning({ + id: usersTable.id, + name: usersTable.name, + }) + .all(); + + expect(users).deep.equal([{ id: 1, name: 'Jane' }]); + } catch (error: any) { + console.error(error); + throw new Error('updateWithReturningFields has broken'); + } + } + + async updateWithReturningAllFields(): Promise { + try { + await this.beforeEach(); + + const now = Date.now(); + + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db.delete(usersTable).where(eq(usersTable.name, 'John')).returning().all(); + + expect(users[0]!.createdAt).instanceOf(Date); + expect(Math.abs(users[0]!.createdAt.getTime() - now)).lessThan(5000); + expect(users).deep.equal([{ id: 1, name: 'John', verified: false, json: null, createdAt: users[0]!.createdAt }]); + } catch (error: any) { + console.error(error); + throw new Error('updateWithReturningFields has broken'); + } + } + + async deleteWithReturningPartial(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ name: 'John' }).run(); + const users = this.db + .delete(usersTable) + .where(eq(usersTable.name, 'John')) + .returning({ + id: usersTable.id, + name: usersTable.name, + }) + .all(); + + expect(users).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`deleteWithReturningPartial error`); + } + } + + async insertAndSelect(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ name: 'John' }).run(); + const result = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).all(); + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + + this.db.insert(usersTable).values({ name: 'Jane' }).run(); + const result2 = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).all(); + + expect(result2).deep.equal([ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`insertAndSelect error`); + } + } + + async jsonInsert(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values({ name: 'John', json: ['foo', 'bar'] }) + .run(); + const result = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + json: usersTable.json, + }) + .from(usersTable) + .all(); + + expect(result).deep.equal([{ id: 1, name: 'John', json: ['foo', 'bar'] }]); + } catch (error: any) { + console.error(error); + throw new Error(`jsonInsert error`); + } + } + + async insertMany(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Bruce', json: ['foo', 'bar'] }, { name: 'Jane' }, { + name: 'Austin', + verified: true, + }]) + .run(); + const result = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + json: usersTable.json, + verified: usersTable.verified, + }) + .from(usersTable) + .all(); + + expect(result).deep.equal([ + { id: 1, name: 'John', json: null, verified: false }, + { id: 2, name: 'Bruce', json: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', json: null, verified: false }, + { id: 4, name: 'Austin', json: null, verified: true }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`insertMany error`); + } + } + + async insertManyWithReturning(): Promise { + try { + await this.beforeEach(); + const result = this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Bruce', json: ['foo', 'bar'] }, { name: 'Jane' }, { + name: 'Austin', + verified: true, + }]) + .returning({ + id: usersTable.id, + name: usersTable.name, + json: usersTable.json, + verified: usersTable.verified, + }) + .all(); + + expect(result).deep.equal([ + { id: 1, name: 'John', json: null, verified: false }, + { id: 2, name: 'Bruce', json: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', json: null, verified: false }, + { id: 4, name: 'Austin', json: null, verified: true }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`insertManyWithReturning error`); + } + } + + async partialJoinWithAlias(): Promise { + try { + await this.beforeEach(); + const customerAlias = alias(usersTable, 'customer'); + + await this.db.insert(usersTable).values([ + { id: 10, name: 'Ivan' }, + { id: 11, name: 'Hans' }, + ]); + + const result = await this.db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }) + .from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)); + + expect(result).deep.equal([ + { + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`partialJoinWithAlias error`); + } + } + + async fullJoinWithAlias(): Promise { + try { + await this.beforeEach(); + const sqliteTable = sqliteTableCreator((name) => `prefixed_${name}`); + + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + this.db.run(sql`create table ${users} (id integer primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + this.db + .insert(users) + .values([ + { id: 10, name: 'Ivan' }, + { id: 11, name: 'Hans' }, + ]) + .run(); + const result = this.db.select().from(users).leftJoin(customers, eq(customers.id, 11)).where(eq(users.id, 10)) + .all(); + + expect(result).deep.equal([ + { + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }, + ]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`fullJoinWithAlias error`); + } + } + + async selectFromAlias(): Promise { + try { + await this.beforeEach(); + const sqliteTable = sqliteTableCreator((name) => `prefixed_${name}`); + + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + this.db.run(sql`create table ${users} (id integer primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + this.db + .insert(users) + .values([ + { id: 10, name: 'Ivan' }, + { id: 11, name: 'Hans' }, + ]) + .run(); + const result = this.db.select().from(user).leftJoin(customers, eq(customers.id, 11)).where(eq(user.id, 10)).all(); + + expect(result).deep.equal([ + { + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }, + ]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`selectFromAlias error`); + } + } + + async insertWithSpaces(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values({ name: sql`'Jo h n'` }) + .run(); + const result = await this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).all(); + + expect(result).deep.equal([{ id: 1, name: 'Jo h n' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithSpaces error`); + } + } + + async preparedStatement(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ name: 'John' }).run(); + const statement = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).prepare(); + const result = statement.all(); + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatement error`); + } + } + + async preparedStatementReuse(): Promise { + try { + await this.beforeEach(); + const stmt = this.db + .insert(usersTable) + .values({ name: sql.placeholder('name') }) + .prepare(); + + for (let i = 0; i < 10; i++) { + stmt.run({ name: `John ${i}` }); + } + + const result = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .all(); + + expect(result).deep.equal([ + { id: 1, name: 'John 0' }, + { id: 2, name: 'John 1' }, + { id: 3, name: 'John 2' }, + { id: 4, name: 'John 3' }, + { id: 5, name: 'John 4' }, + { id: 6, name: 'John 5' }, + { id: 7, name: 'John 6' }, + { id: 8, name: 'John 7' }, + { id: 9, name: 'John 8' }, + { id: 10, name: 'John 9' }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatementReuse error`); + } + } + + async insertPlaceholdersOnColumnsWithEncoder(): Promise { + try { + await this.beforeEach(); + const stmt = this.db + .insert(usersTable) + .values({ + name: 'John', + verified: sql.placeholder('verified'), + }) + .prepare(); + + stmt.run({ verified: true }); + stmt.run({ verified: false }); + + const result = this.db + .select({ + id: usersTable.id, + verified: usersTable.verified, + }) + .from(usersTable) + .all(); + + expect(result).deep.equal([ + { id: 1, verified: true }, + { id: 2, verified: false }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`insertPlaceholdersOnColumnsWithEncoder error`); + } + } + + async preparedStatementWithPlaceholderInWhere(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ name: 'John' }).run(); + const stmt = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .prepare(); + const result = stmt.all({ id: 1 }); + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatementWithPlaceholderInWhere error`); + } + } + + async preparedStatementWithPlaceholderInLimit(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ name: 'John' }).run(); + const stmt = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .limit(sql.placeholder('limit')) + .prepare(); + + const result = await stmt.all({ id: 1, limit: 1 }); + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + expect(result).length(1); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatementWithPlaceholderInLimit error`); + } + } + + async preparedStatementWithPlaceholderInOffset(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'John1' }]) + .run(); + const stmt = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .limit(sql.placeholder('limit')) + .offset(sql.placeholder('offset')) + .prepare(); + + const result = stmt.all({ limit: 1, offset: 1 }); + + expect(result).deep.equal([{ id: 2, name: 'John1' }]); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatementWithPlaceholderInOffset error`); + } + } + + async preparedStatementBuiltUsing$dynamic(): Promise { + try { + await this.beforeEach(); + function withLimitOffset(qb: any) { + return qb.limit(sql.placeholder('limit')).offset(sql.placeholder('offset')); + } + + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'John1' }]) + .run(); + const stmt = this.db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .$dynamic(); + withLimitOffset(stmt).prepare('stmt_limit'); + + const result = await stmt.all({ limit: 1, offset: 1 }); + + expect(result).deep.equal([{ id: 2, name: 'John1' }]); + expect(result).length(1); + } catch (error: any) { + console.error(error); + throw new Error(`preparedStatementBuiltUsing error`); + } + } + + async selectWithGroupByAsField(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const result = this.db.select({ name: usersTable.name }).from(usersTable).groupBy(usersTable.name).all(); + + expect(result).deep.equal([{ name: 'Jane' }, { name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithGroupByAsField error`); + } + } + + async selectWithExists(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const user = alias(usersTable, 'user'); + const result = this.db + .select({ name: usersTable.name }) + .from(usersTable) + .where( + exists( + this.db + .select({ one: sql`1` }) + .from(user) + .where(and(eq(usersTable.name, 'John'), eq(user.id, usersTable.id))), + ), + ) + .all(); + + expect(result).deep.equal([{ name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithExists error`); + } + } + + async selectWithGroupByAsSql(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const result = this.db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(sql`${usersTable.name}`) + .all(); + + expect(result).deep.equal([{ name: 'Jane' }, { name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithGroupByAsSql error`); + } + } + + async selectWithGroupByAsSqlPlusColumn(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const result = this.db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id) + .all(); + + expect(result).deep.equal([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithGroupByAsSqlPlusColumn error`); + } + } + + async selectWithGroupByAsColumnPlusSql(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const result = this.db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .all(); + + expect(result).deep.equal([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithGroupByAsColumnPlusSql error`); + } + } + + async selectWithGroupByComplexQuery(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]) + .run(); + + const result = this.db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1) + .all(); + + expect(result).deep.equal([{ name: 'Jane' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectWithGroupByComplexQuery error`); + } + } + + async buildQuery(): Promise { + try { + await this.beforeEach(); + const query = this.db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + expect(query).deep.equal({ + sql: 'select "id", "name" from "users" group by "users"."id", "users"."name"', + params: [], + }); + } catch (error: any) { + console.error(error); + throw new Error(`buildQuery error`); + } + } + + async insertViaDbRunPlusSelectViaDbAll(): Promise { + try { + await this.beforeEach(); + this.db.run(sql`insert into ${usersTable} (${new Name(usersTable.name.name)}) values (${'John'})`); + + const result = this.db.all<{ id: number; name: string }>(sql`select id, name from "users"`); + expect(result).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertViaDbRunPlusSelectViaDbAll error`); + } + } + + async insertViaDbGet(): Promise { + try { + await this.beforeEach(); + const inserted = this.db.get<{ id: number; name: string }>( + sql`insert into ${usersTable} (${new Name( + usersTable.name.name, + )}) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, + ); + expect(inserted).deep.equal({ id: 1, name: 'John' }); + } catch (error: any) { + console.error(error); + throw new Error(`insertViaDbGet error`); + } + } + + async insertViaDbRunPlusSelectViaDbGet(): Promise { + try { + await this.beforeEach(); + this.db.run(sql`insert into ${usersTable} (${new Name(usersTable.name.name)}) values (${'John'})`); + + const result = this.db.get<{ id: number; name: string }>( + sql`select ${usersTable.id}, ${usersTable.name} from ${usersTable}`, + ); + expect(result).deep.equal({ id: 1, name: 'John' }); + } catch (error: any) { + console.error(error); + throw new Error(`insertViaDbRunPlusSelectViaDbGet error`); + } + } + + async insertViaDbGetQueryBuilder(): Promise { + try { + await this.beforeEach(); + const inserted = this.db.get>( + this.db.insert(usersTable).values({ name: 'John' }).returning({ id: usersTable.id, name: usersTable.name }), + ); + expect(inserted).deep.equal({ id: 1, name: 'John' }); + } catch (error: any) { + console.error(error); + throw new Error(`insertViaDbGetQueryBuilder error`); + } + } + + async joinSubquery(): Promise { + try { + await this.beforeEach(); + this.db + .insert(courseCategoriesTable) + .values([{ name: 'Category 1' }, { name: 'Category 2' }, { name: 'Category 3' }, { name: 'Category 4' }]) + .run(); + + this.db + .insert(coursesTable) + .values([ + { name: 'Development', categoryId: 2 }, + { name: 'IT & Software', categoryId: 3 }, + { name: 'Marketing', categoryId: 4 }, + { name: 'Design', categoryId: 1 }, + ]) + .run(); + + const sq2 = this.db + .select({ + categoryId: courseCategoriesTable.id, + category: courseCategoriesTable.name, + total: sql`count(${courseCategoriesTable.id})`, + }) + .from(courseCategoriesTable) + .groupBy(courseCategoriesTable.id, courseCategoriesTable.name) + .as('sq2'); + + const res = await this.db + .select({ + courseName: coursesTable.name, + categoryId: sq2.categoryId, + }) + .from(coursesTable) + .leftJoin(sq2, eq(coursesTable.categoryId, sq2.categoryId)) + .orderBy(coursesTable.name) + .all(); + + expect(res).deep.equal([ + { courseName: 'Design', categoryId: 1 }, + { courseName: 'Development', categoryId: 2 }, + { courseName: 'IT & Software', categoryId: 3 }, + { courseName: 'Marketing', categoryId: 4 }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`joinSubquery error`); + } + } + + async withSelect(): Promise { + try { + await this.beforeEach(); + this.db + .insert(orders) + .values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]) + .run(); + + const regionalSales = this.db.$with('regional_sales').as( + this.db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = this.db.$with('top_regions').as( + this.db + .select({ + region: regionalSales.region, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + this.db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = this.db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`cast(sum(${orders.quantity}) as int)`, + productSales: sql`cast(sum(${orders.amount}) as int)`, + }) + .from(orders) + .where(inArray(orders.region, this.db.select({ region: topRegions.region }).from(topRegions))) + .groupBy(orders.region, orders.product) + .orderBy(orders.region, orders.product) + .all(); + + expect(result).deep.equal([ + { + region: 'Europe', + product: 'A', + productUnits: 3, + productSales: 30, + }, + { + region: 'Europe', + product: 'B', + productUnits: 5, + productSales: 50, + }, + { + region: 'US', + product: 'A', + productUnits: 7, + productSales: 70, + }, + { + region: 'US', + product: 'B', + productUnits: 9, + productSales: 90, + }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`withSelect error`); + } + } + + async withUpdate(): Promise { + try { + await this.beforeEach(); + const products = sqliteTable('products', { + id: integer('id').primaryKey(), + price: numeric('price').notNull(), + cheap: integer('cheap', { mode: 'boolean' }).notNull().default(false), + }); + + this.db.run(sql`drop table if exists ${products}`); + this.db.run(sql` + create table ${products} ( + id integer primary key, + price numeric not null, + cheap integer not null default 0 + ) + `); + + await this.db + .insert(products) + .values([{ price: '10.99' }, { price: '25.85' }, { price: '32.99' }, { price: '2.50' }, { price: '4.59' }]); + + const averagePrice = this.db.$with('average_price').as( + this.db + .select({ + value: sql`avg(${products.price})`.as('value'), + }) + .from(products), + ); + + const result = await this.db + .with(averagePrice) + .update(products) + .set({ + cheap: true, + }) + .where(lt(products.price, sql`(select * from ${averagePrice})`)) + .returning({ + id: products.id, + }); + + expect(result).deep.equal([{ id: 1 }, { id: 4 }, { id: 5 }]); + } catch (error: any) { + console.error(error); + throw new Error(`withUpdate error`); + } + } + + async withInsert(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users', { + username: text('username').notNull(), + admin: integer('admin', { mode: 'boolean' }).notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + this.db.run(sql`create table ${users} (username text not null, admin integer not null default 0)`); + + const userCount = this.db.$with('user_count').as( + this.db + .select({ + value: sql`count(*)`.as('value'), + }) + .from(users), + ); + + const result = await this.db + .with(userCount) + .insert(users) + .values([{ username: 'user1', admin: sql`((select * from ${userCount}) = 0)` }]) + .returning({ + admin: users.admin, + }); + + expect(result).deep.equal([{ admin: true }]); + } catch (error: any) { + console.error(error); + throw new Error(`withInsert error`); + } + } + + async withDelete(): Promise { + try { + await this.beforeEach(); + await this.db.insert(orders).values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const averageAmount = this.db.$with('average_amount').as( + this.db + .select({ + value: sql`avg(${orders.amount})`.as('value'), + }) + .from(orders), + ); + + const result = this.db + .with(averageAmount) + .delete(orders) + .where(gt(orders.amount, sql`(select * from ${averageAmount})`)) + .returning({ + id: orders.id, + }) + .all(); + + expect(result).deep.equal([{ id: 6 }, { id: 7 }, { id: 8 }]); + } catch (error: any) { + console.error(error); + throw new Error(`withDelete error`); + } + } + + async selectFromSubquerySql(): Promise { + try { + await this.beforeEach(); + this.db + .insert(users2Table) + .values([{ name: 'John' }, { name: 'Jane' }]) + .run(); + + const sq = this.db + .select({ name: sql`${users2Table.name} || ' modified'`.as('name') }) + .from(users2Table) + .as('sq'); + + const res = this.db.select({ name: sq.name }).from(sq).all(); + + expect(res).deep.equal([{ name: 'John modified' }, { name: 'Jane modified' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectFromSubquerySql error`); + } + } + + async selectAFieldWithoutJoiningItsTable(): Promise { + try { + await this.beforeEach(); + expect(() => this.db.select({ name: users2Table.name }).from(usersTable).prepare()).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`selectAFieldWithoutJoiningItsTable error`); + } + } + + async selectAllFieldsFromSubqueryWithoutAlias(): Promise { + try { + const sq = this.db.$with('sq').as( + this.db.select({ name: sql`upper(${users2Table.name})` }).from(users2Table), + ); + + expect(() => this.db.select().from(sq).prepare()).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`selectAllFieldsFromSubqueryWithoutAlias error`); + } + } + + async selectCount(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ name: 'John' }, { name: 'Jane' }]) + .run(); + + const res = this.db + .select({ count: sql`count(*)` }) + .from(usersTable) + .all(); + + expect(res).deep.equal([{ count: 2 }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectCount error`); + } + } + + async having(): Promise { + try { + await this.beforeEach(); + this.db + .insert(citiesTable) + .values([{ name: 'London' }, { name: 'Paris' }, { name: 'New York' }]) + .run(); + + this.db + .insert(users2Table) + .values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 1 }, + { name: 'Jack', cityId: 2 }, + ]) + .run(); + + const result = this.db + .select({ + id: citiesTable.id, + name: sql`upper(${citiesTable.name})`.as('upper_name'), + usersCount: sql`count(${users2Table.id})`.as('users_count'), + }) + .from(citiesTable) + .leftJoin(users2Table, eq(users2Table.cityId, citiesTable.id)) + .where(({ name }) => sql`length(${name}) >= 3`) + .groupBy(citiesTable.id) + .having(({ usersCount }) => sql`${usersCount} > 0`) + .orderBy(({ name }) => name) + .all(); + + expect(result).deep.equal([ + { + id: 1, + name: 'LONDON', + usersCount: 2, + }, + { + id: 2, + name: 'PARIS', + usersCount: 1, + }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`having error`); + } + } + + async view(): Promise { + try { + await this.beforeEach(); + const newYorkers1 = sqliteView('new_yorkers').as((qb) => + qb.select().from(users2Table).where(eq(users2Table.cityId, 1)) + ); + + const newYorkers2 = sqliteView('new_yorkers', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }).as(sql`select * from ${users2Table} where ${eq(users2Table.cityId, 1)}`); + + const newYorkers3 = sqliteView('new_yorkers', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }).existing(); + + this.db.run(sql`create view if not exists new_yorkers as ${getViewConfig(newYorkers1).query}`); + + this.db + .insert(citiesTable) + .values([{ name: 'New York' }, { name: 'Paris' }]) + .run(); + + this.db + .insert(users2Table) + .values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 1 }, + { name: 'Jack', cityId: 2 }, + ]) + .run(); + + { + const result = this.db.select().from(newYorkers1).all(); + expect(result).deep.equal([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = this.db.select().from(newYorkers2).all(); + expect(result).deep.equal([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = this.db.select().from(newYorkers3).all(); + expect(result).deep.equal([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = this.db.select({ name: newYorkers1.name }).from(newYorkers1).all(); + expect(result).deep.equal([{ name: 'John' }, { name: 'Jane' }]); + } + + this.db.run(sql`drop view ${newYorkers1}`); + } catch (error: any) { + console.error(error); + throw new Error(`view error`); + } + } + + async insertNullTimestamp(): Promise { + try { + await this.beforeEach(); + const test = sqliteTable('test', { + t: integer('t', { mode: 'timestamp' }), + }); + + this.db.run(sql`create table ${test} (t timestamp)`); + + this.db.insert(test).values({ t: null }).run(); + const res = await this.db.select().from(test).all(); + expect(res).deep.equal([{ t: null }]); + + this.db.run(sql`drop table ${test}`); + } catch (error: any) { + console.error(error); + throw new Error(`insertNullTimestamp error`); + } + } + + async selectFromRawSql(): Promise { + try { + const result = this.db + .select({ + id: sql`id`, + name: sql`name`, + }) + .from(sql`(select 1 as id, 'John' as name) as users`) + .all(); + + Expect>; + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectFromRawSql error`); + } + } + + async selectFromRawSqlWithJoins(): Promise { + try { + await this.beforeEach(); + const result = this.db + .select({ + id: sql`users.id`, + name: sql`users.name`.as('userName'), + userCity: sql`users.city`, + cityName: sql`cities.name`.as('cityName'), + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, sql`cities.id = users.id`) + .all(); + + Expect>; + + expect(result).deep.equal([{ id: 1, name: 'John', userCity: 'New York', cityName: 'Paris' }]); + } catch (error: any) { + console.error(error); + throw new Error(`selectFromRawSqlWithJoins error`); + } + } + + async joinOnAliasedSqlFromSelect(): Promise { + try { + await this.beforeEach(); + const result = this.db + .select({ + userId: sql`users.id`.as('userId'), + name: sql`users.name`.as('userName'), + userCity: sql`users.city`, + cityId: sql`cities.id`.as('cityId'), + cityName: sql`cities.name`.as('cityName'), + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, (cols) => eq(cols.cityId, cols.userId)) + .all(); + + Expect< + Equal<{ userId: number; name: string; userCity: string; cityId: number; cityName: string }[], typeof result> + >; + + expect(result).deep.equal([{ userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }]); + } catch (error: any) { + console.error(error); + throw new Error(`joinOnAliasedSqlFromSelect error`); + } + } + + async joinOnAliasedSqlFromWithClause(): Promise { + try { + await this.beforeEach(); + const users = this.db.$with('users').as( + this.db + .select({ + id: sql`id`.as('userId'), + name: sql`name`.as('userName'), + city: sql`city`.as('city'), + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`), + ); + + const cities = this.db.$with('cities').as( + this.db + .select({ + id: sql`id`.as('cityId'), + name: sql`name`.as('cityName'), + }) + .from(sql`(select 1 as id, 'Paris' as name) as cities`), + ); + + const result = this.db + .with(users, cities) + .select({ + userId: users.id, + name: users.name, + userCity: users.city, + cityId: cities.id, + cityName: cities.name, + }) + .from(users) + .leftJoin(cities, (cols) => eq(cols.cityId, cols.userId)) + .all(); + + Expect< + Equal<{ userId: number; name: string; userCity: string; cityId: number; cityName: string }[], typeof result> + >; + + expect(result).deep.equal([{ userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }]); + } catch (error: any) { + console.error(error); + throw new Error(`joinOnAliasedSqlFromWithClause error`); + } + } + + async prefixedTable(): Promise { + try { + await this.beforeEach(); + const sqliteTable = sqliteTableCreator((name) => `myprefix_${name}`); + + const users = sqliteTable('test_prefixed_table_with_unique_name', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run( + sql`create table myprefix_test_prefixed_table_with_unique_name (id integer not null primary key, name text not null)`, + ); + + this.db.insert(users).values({ id: 1, name: 'John' }).run(); + + const result = this.db.select().from(users).all(); + + expect(result).deep.equal([{ id: 1, name: 'John' }]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`prefixedTable error`); + } + } + + async orderByWithAliasedColumn(): Promise { + try { + await this.beforeEach(); + const query = this.db + .select({ + test: sql`something`.as('test'), + }) + .from(users2Table) + .orderBy((fields) => fields.test) + .toSQL(); + + expect(query.sql).equal('select something as "test" from "users2" order by "test"'); + } catch (error: any) { + console.error(error); + throw new Error(`orderByWithAliasedColumn error`); + } + } + + async transaction(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users_transactions', { + id: integer('id').primaryKey(), + balance: integer('balance').notNull(), + }); + const products = sqliteTable('products_transactions', { + id: integer('id').primaryKey(), + price: integer('price').notNull(), + stock: integer('stock').notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + this.db.run(sql`drop table if exists ${products}`); + + this.db.run(sql`create table users_transactions (id integer not null primary key, balance integer not null)`); + this.db.run( + sql`create table products_transactions (id integer not null primary key, price integer not null, stock integer not null)`, + ); + + const user = this.db.insert(users).values({ balance: 100 }).returning().get(); + const product = this.db.insert(products).values({ price: 10, stock: 10 }).returning().get(); + + this.db.transaction(async (tx) => { + tx.update(users) + .set({ balance: user.balance - product.price }) + .where(eq(users.id, user.id)) + .run(); + tx.update(products) + .set({ stock: product.stock - 1 }) + .where(eq(products.id, product.id)) + .run(); + }); + + const result = this.db.select().from(users).all(); + + expect(result).deep.equal([{ id: 1, balance: 90 }]); + + this.db.run(sql`drop table ${users}`); + this.db.run(sql`drop table ${products}`); + } catch (error: any) { + console.error(error); + throw new Error(`transaction error`); + } + } + + // async transactionRollback(): Promise{ + // const users = sqliteTable('users_transactions_rollback', { + // id: integer('id').primaryKey(), + // balance: integer('balance').notNull(), + // }); + + // this.db.run(sql`drop table if exists ${users}`); + + // this.db.run( + // sql`create table users_transactions_rollback (id integer not null primary key, balance integer not null)`, + // ); + // await expect(async () => { + // this.db.transaction(async (tx) => { + // tx.insert(users).values({ balance: 100 }).run(); + // tx.rollback(); + // }); + // }).re(TransactionRollbackError); + + // const result = await db.select().from(users).all(); + + // expect(result).toEqual([]); + + // await db.run(sql`drop table ${users}`); + // }; + + async nestedTransaction(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users_nested_transactions', { + id: integer('id').primaryKey(), + balance: integer('balance').notNull(), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run( + sql`create table users_nested_transactions (id integer not null primary key, balance integer not null)`, + ); + + this.db.transaction((tx) => { + tx.insert(users).values({ balance: 100 }).run(); + + tx.transaction((tx) => { + tx.update(users).set({ balance: 200 }).run(); + }); + }); + + const result = this.db.select().from(users).all(); + + expect(result).deep.equal([{ id: 1, balance: 200 }]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`nestedTransaction error`); + } + } + + // async nestedTransactionRollback(): Promise{ + // const users = sqliteTable('users_nested_transactions_rollback', { + // id: integer('id').primaryKey(), + // balance: integer('balance').notNull(), + // }); + + // this.db.run(sql`drop table if exists ${users}`); + + // this.db.run( + // sql`create table users_nested_transactions_rollback (id integer not null primary key, balance integer not null)`, + // ); + + // this.db.transaction((tx) => { + // this.tx.insert(users).values({ balance: 100 }).run(); + + // expect(async () => { + // await tx.transaction(async (tx) => { + // await tx.update(users).set({ balance: 200 }).run(); + // tx.rollback(); + // }); + // }).rejects.toThrowError(TransactionRollbackError); + // }); + + // const result = await db.select().from(users).all(); + + // expect(result).toEqual([{ id: 1, balance: 100 }]); + + // await db.run(sql`drop table ${users}`); + // }; + + async joinSubqueryWithJoin(): Promise { + try { + await this.beforeEach(); + const internalStaff = sqliteTable('internal_staff', { + userId: integer('user_id').notNull(), + }); + + const customUser = sqliteTable('custom_user', { + id: integer('id').notNull(), + }); + + const ticket = sqliteTable('ticket', { + staffId: integer('staff_id').notNull(), + }); + + this.db.run(sql`drop table if exists ${internalStaff}`); + this.db.run(sql`drop table if exists ${customUser}`); + this.db.run(sql`drop table if exists ${ticket}`); + + this.db.run(sql`create table internal_staff (user_id integer not null)`); + this.db.run(sql`create table custom_user (id integer not null)`); + this.db.run(sql`create table ticket (staff_id integer not null)`); + + this.db.insert(internalStaff).values({ userId: 1 }).run(); + this.db.insert(customUser).values({ id: 1 }).run(); + this.db.insert(ticket).values({ staffId: 1 }).run(); + + const subq = this.db.select().from(internalStaff).leftJoin(customUser, eq(internalStaff.userId, customUser.id)) + .as('internal_staff'); + + const mainQuery = this.db.select().from(ticket).leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)) + .all(); + + expect(mainQuery).deep.equal([ + { + ticket: { staffId: 1 }, + internal_staff: { + internal_staff: { userId: 1 }, + custom_user: { id: 1 }, + }, + }, + ]); + + this.db.run(sql`drop table ${internalStaff}`); + this.db.run(sql`drop table ${customUser}`); + this.db.run(sql`drop table ${ticket}`); + } catch (error: any) { + console.error(error); + throw new Error(`joinSubqueryWithJoin error`); + } + } + + async joinViewAsSubquery(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users_join_view', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }); + + const newYorkers = sqliteView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + this.db.run(sql`drop table if exists ${users}`); + this.db.run(sql`drop view if exists ${newYorkers}`); + + this.db.run( + sql`create table ${users} (id integer not null primary key, name text not null, city_id integer not null)`, + ); + this.db.run(sql`create view if not exists ${newYorkers} as ${getViewConfig(newYorkers).query}`); + + this.db + .insert(users) + .values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + { name: 'Jack', cityId: 1 }, + { name: 'Jill', cityId: 2 }, + ]) + .run(); + + const sq = this.db.select().from(newYorkers).as('new_yorkers_sq'); + + const result = await this.db.select().from(users).leftJoin(sq, eq(users.id, sq.id)).all(); + + expect(result).deep.equal([ + { + users_join_view: { id: 1, name: 'John', cityId: 1 }, + new_yorkers_sq: { id: 1, name: 'John', cityId: 1 }, + }, + { + users_join_view: { id: 2, name: 'Jane', cityId: 2 }, + new_yorkers_sq: null, + }, + { + users_join_view: { id: 3, name: 'Jack', cityId: 1 }, + new_yorkers_sq: { id: 3, name: 'Jack', cityId: 1 }, + }, + { + users_join_view: { id: 4, name: 'Jill', cityId: 2 }, + new_yorkers_sq: null, + }, + ]); + + this.db.run(sql`drop view ${newYorkers}`); + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`joinViewAsSubquery error`); + } + } + + async insertWithOnConflictDoNothing(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ id: 1, name: 'John' }).run(); + + this.db.insert(usersTable).values({ id: 1, name: 'John' }).onConflictDoNothing().run(); + + const res = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ).all(); + + expect(res).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoNothing error`); + } + } + + async insertWithOnConflictDoNothinUsingCompositePk(): Promise { + try { + await this.beforeEach(); + this.db.insert(pkExampleTable).values({ id: 1, name: 'John', email: 'john@example.com' }).run(); + + this.db.insert(pkExampleTable).values({ id: 1, name: 'John', email: 'john1@example.com' }).onConflictDoNothing() + .run(); + + const res = await this.db + .select({ id: pkExampleTable.id, name: pkExampleTable.name, email: pkExampleTable.email }) + .from(pkExampleTable) + .where(eq(pkExampleTable.id, 1)) + .all(); + + expect(res).deep.equal([{ id: 1, name: 'John', email: 'john@example.com' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoNothinUsingCompositePk error`); + } + } + + async insertWithOnConflictDoNothingUsingTarget(): Promise { + try { + this.db.insert(usersTable).values({ id: 1, name: 'John' }).run(); + + this.db.insert(usersTable).values({ id: 1, name: 'John' }).onConflictDoNothing({ target: usersTable.id }).run(); + + const res = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ).all(); + + expect(res).deep.equal([{ id: 1, name: 'John' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoNothingUsingTarget error`); + } + } + + async insertWithOnConflictDoNothingUsingCompositePkAsTarget(): Promise { + try { + await this.beforeEach(); + this.db.insert(pkExampleTable).values({ id: 1, name: 'John', email: 'john@example.com' }).run(); + + this.db + .insert(pkExampleTable) + .values({ id: 1, name: 'John', email: 'john1@example.com' }) + .onConflictDoNothing({ target: [pkExampleTable.id, pkExampleTable.name] }) + .run(); + + const res = this.db + .select({ id: pkExampleTable.id, name: pkExampleTable.name, email: pkExampleTable.email }) + .from(pkExampleTable) + .where(eq(pkExampleTable.id, 1)) + .all(); + + expect(res).deep.equal([{ id: 1, name: 'John', email: 'john@example.com' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoNothingUsingCompositePkAsTarget error`); + } + } + + async insertWithOnConflictDoUpdate(): Promise { + try { + await this.beforeEach(); + this.db.insert(usersTable).values({ id: 1, name: 'John' }).run(); + + this.db + .insert(usersTable) + .values({ id: 1, name: 'John' }) + .onConflictDoUpdate({ target: usersTable.id, set: { name: 'John1' } }) + .run(); + + const res = this.db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ).all(); + + expect(res).deep.equal([{ id: 1, name: 'John1' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoUpdate error`); + } + } + + async insertWithOnConflictDoUpdateWhere(): Promise { + try { + await this.beforeEach(); + this.db + .insert(usersTable) + .values([{ id: 1, name: 'John', verified: false }]) + .run(); + + this.db + .insert(usersTable) + .values({ id: 1, name: 'John1', verified: true }) + .onConflictDoUpdate({ + target: usersTable.id, + set: { name: 'John1', verified: true }, + where: eq(usersTable.verified, false), + }) + .run(); + + const res = this.db + .select({ id: usersTable.id, name: usersTable.name, verified: usersTable.verified }) + .from(usersTable) + .where(eq(usersTable.id, 1)) + .all(); + + expect(res).deep.equal([{ id: 1, name: 'John1', verified: true }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoUpdateWhere error`); + } + } + + async insertWithOnConflictDoUpdateUsingCompositePk(): Promise { + try { + await this.beforeEach(); + this.db.insert(pkExampleTable).values({ id: 1, name: 'John', email: 'john@example.com' }).run(); + + this.db + .insert(pkExampleTable) + .values({ id: 1, name: 'John', email: 'john@example.com' }) + .onConflictDoUpdate({ target: [pkExampleTable.id, pkExampleTable.name], set: { email: 'john1@example.com' } }) + .run(); + + const res = this.db + .select({ id: pkExampleTable.id, name: pkExampleTable.name, email: pkExampleTable.email }) + .from(pkExampleTable) + .where(eq(pkExampleTable.id, 1)) + .all(); + + expect(res).deep.equal([{ id: 1, name: 'John', email: 'john1@example.com' }]); + } catch (error: any) { + console.error(error); + throw new Error(`insertWithOnConflictDoUpdateUsingCompositePk error`); + } + } + + async insertUndefined(): Promise { + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run( + sql`create table ${users} (id integer primary key, name text)`, + ); + + expect((() => { + this.db.insert(users).values({ name: undefined }).run(); + })()).not.throw(); + + this.db.run(sql`drop table ${users}`); + } + + async updateUndefined(): Promise { + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run( + sql`create table ${users} (id integer primary key, name text)`, + ); + + expect((() => { + this.db.update(users).set({ name: undefined }).run(); + })()).throw(); + expect((() => { + this.db.update(users).set({ id: 1, name: undefined }).run(); + })()).not.throw(); + + this.db.run(sql`drop table ${users}`); + } + + async apiCRUD(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text)`); + + this.db.insert(users).values({ id: 1, name: 'John' }).run(); + + const res = this.db.select().from(users).all(); + + expect(res).deep.equal([{ id: 1, name: 'John' }]); + + this.db.update(users).set({ name: 'John1' }).where(eq(users.id, 1)).all(); + + const res1 = this.db.select().from(users).all(); + + expect(res1).deep.equal([{ id: 1, name: 'John1' }]); + + this.db.delete(users).where(eq(users.id, 1)).run(); + + const res2 = this.db.select().from(users).all(); + + expect(res2).deep.equal([]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`apiCRUD error`); + } + } + + async apiInsertPlusSelectPreparePlusAsyncExecute(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text)`); + + const insertStmt = this.db.insert(users).values({ id: 1, name: 'John' }).prepare(); + insertStmt.execute().sync(); + + const selectStmt = this.db.select().from(users).prepare(); + const res = selectStmt.execute().sync(); + + expect(res).deep.equal([{ id: 1, name: 'John' }]); + + const updateStmt = this.db.update(users).set({ name: 'John1' }).where(eq(users.id, 1)).prepare(); + updateStmt.execute().sync(); + + const res1 = selectStmt.execute().sync(); + + expect(res1).deep.equal([{ id: 1, name: 'John1' }]); + + const deleteStmt = this.db.delete(users).where(eq(users.id, 1)).prepare(); + deleteStmt.execute().sync(); + + const res2 = selectStmt.execute().sync(); + + expect(res2).deep.equal([]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`apiInsertPlusSelectPreparePlusAsyncExecute error`); + } + } + + async apiInsertSelectPreparePlusSyncExecute(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text)`); + + const insertStmt = this.db.insert(users).values({ id: 1, name: 'John' }).prepare(); + insertStmt.execute().sync(); + + const selectStmt = this.db.select().from(users).prepare(); + const res = selectStmt.execute().sync(); + + expect(res).deep.equal([{ id: 1, name: 'John' }]); + + const updateStmt = this.db.update(users).set({ name: 'John1' }).where(eq(users.id, 1)).prepare(); + updateStmt.execute().sync(); + + const res1 = selectStmt.execute().sync(); + + expect(res1).deep.equal([{ id: 1, name: 'John1' }]); + + const deleteStmt = this.db.delete(users).where(eq(users.id, 1)).prepare(); + deleteStmt.execute().sync(); + + const res2 = selectStmt.execute().sync(); + + expect(res2).deep.equal([]); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`apiInsertSelectPreparePlusSyncExecute error`); + } + } + + async selectPlusGetForEmptyResult(): Promise { + try { + await this.beforeEach(); + const users = sqliteTable('users', { + id: integer('id').primaryKey(), + name: text('name'), + }); + + this.db.run(sql`drop table if exists ${users}`); + + this.db.run(sql`create table ${users} (id integer primary key, name text)`); + + const res = this.db.select().from(users).where(eq(users.id, 1)).get(); + + expect(res).eq(undefined); + + this.db.run(sql`drop table ${users}`); + } catch (error: any) { + console.error(error); + throw new Error(`selectPlusGetForEmptyResult error`); + } + } + + async setOperationsUnionFromQueryBuilderWithSubquery(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const sq = this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable) + .union(this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table)) + .orderBy(asc(sql`name`)) + .as('sq'); + + const result = await this.db.select().from(sq).limit(5).offset(5); + + expect(result).length(5); + + expect(result).deep.equal([ + { id: 2, name: 'London' }, + { id: 7, name: 'Mary' }, + { id: 1, name: 'New York' }, + { id: 4, name: 'Peter' }, + { id: 8, name: 'Sally' }, + ]); + + expect(() => { + this.db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).union( + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table), + ).orderBy(asc(sql`name`)).all(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsUnionFromQueryBuilderWithSubquery error`); + } + } + + async setOperationsUnionAsFunction(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = union( + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable).where(eq(citiesTable.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`name`)).all(); + + expect(result).length(2); + + expect(result).deep.equal([ + { id: 1, name: 'John' }, + { id: 1, name: 'New York' }, + ]); + + expect(() => { + union( + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + this.db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`name`)).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsUnionAsFunction error`); + } + } + + async setOperationsUnionAllFromQueryBuilder(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable) + .unionAll(this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable)) + .orderBy(asc(citiesTable.id)) + .limit(5) + .offset(1).all(); + + expect(result).length(5); + + expect(result).deep.equal([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + { id: 3, name: 'Tampa' }, + ]); + + expect(() => { + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).unionAll( + this.db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable), + ).orderBy(asc(citiesTable.id)).limit(5).offset(1).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsUnionAllFromQueryBuilder error`); + } + } + + async setOperationsUnionAllAsFunction(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = unionAll( + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable).where(eq(citiesTable.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + ).all(); + + expect(result).length(3); + + expect(result).deep.equal([ + { id: 1, name: 'New York' }, + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + ]); + + expect(() => { + unionAll( + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + this.db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsUnionAllAsFunction error`); + } + } + + async setOperationsIntersectFromQueryBuilder(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable) + .intersect( + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable).where(gt(citiesTable.id, 1)), + ) + .orderBy(asc(sql`name`)).all(); + + expect(result).length(2); + + expect(result).deep.equal([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + expect(() => { + this.db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).intersect( + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`name`)).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsIntersectFromQueryBuilder error`); + } + } + + async setOperationsIntersectAsFunction(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = intersect( + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable).where(eq(citiesTable.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + ).all(); + + expect(result).length(0); + + expect(result).deep.equal([]); + + expect(() => { + intersect( + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + this.db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsIntersectAsFunction error`); + } + } + + async setOperationsExceptFromQueryBuilder(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = this.db + .select() + .from(citiesTable) + .except(this.db.select().from(citiesTable).where(gt(citiesTable.id, 1))).all(); + + expect(result).length(1); + + expect(result).deep.equal([{ id: 1, name: 'New York' }]); + + expect(() => { + this.db + .select() + .from(citiesTable).except( + this.db + .select({ name: users2Table.name, id: users2Table.id }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsExceptFromQueryBuilder error`); + } + } + + async setOperationsExceptAsFunction(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = except( + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable), + this.db.select({ id: citiesTable.id, name: citiesTable.name }).from(citiesTable).where(eq(citiesTable.id, 1)), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`id`)).all(); + + expect(result).length(2); + + expect(result).deep.equal([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + expect(() => { + except( + this.db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable), + this.db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`id`)).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsExceptAsFunction error`); + } + } + + async setOperationsMixedFromQueryBuilder(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const result = this.db + .select() + .from(citiesTable) + .except(({ unionAll }) => + unionAll( + this.db.select().from(citiesTable).where(gt(citiesTable.id, 1)), + this.db.select().from(citiesTable).where(eq(citiesTable.id, 2)), + ) + ).all(); + + expect(result).length(2); + + expect(result).deep.equal([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + ]); + + expect(() => { + this.db + .select() + .from(citiesTable).except( + ({ unionAll }) => + unionAll( + this.db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + this.db.select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).where(eq(citiesTable.id, 2)), + ), + ).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsMixedFromQueryBuilder error`); + } + } + + async setOperationsMixedAllAsFunctionWithSubquery(): Promise { + try { + await this.beforeEach(); + await setupSetOperationTest(this.db); + + const sq = union( + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 1)), + except( + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where( + gte(users2Table.id, 5), + ), + this.db.select({ id: users2Table.id, name: users2Table.name }).from(users2Table).where(eq(users2Table.id, 7)), + ), + this.db.select().from(citiesTable).where(gt(citiesTable.id, 1)), + ) + .orderBy(asc(sql`id`)) + .as('sq'); + + const result = await this.db.select().from(sq).limit(4).offset(1); + + expect(result).length(4); + + expect(result).deep.equal([ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + { id: 5, name: 'Ben' }, + { id: 6, name: 'Jill' }, + ]); + + expect(() => { + union( + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + except( + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + this.db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 7)), + ), + this.db + .select({ name: users2Table.name, id: users2Table.id }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`id`)).run(); + }).throw(); + } catch (error: any) { + console.error(error); + throw new Error(`setOperationsMixedAllAsFunctionWithSubquery error`); + } + } + + async aggregateFunctionCount(): Promise { + try { + await this.beforeEach(); + const table = aggregateTable; + await setupAggregateFunctionsTest(this.db); + + const result1 = await this.db.select({ value: count() }).from(table); + const result2 = await this.db.select({ value: count(table.a) }).from(table); + const result3 = await this.db.select({ value: countDistinct(table.name) }).from(table); + + expect(result1[0]?.value).eq(7); + expect(result2[0]?.value).eq(5); + expect(result3[0]?.value).eq(6); + } catch (error: any) { + console.error(error); + throw new Error(`aggregateFunctionCount error`); + } + } + + async aggregatFunctionAvg(): Promise { + try { + await this.beforeEach(); + const table = aggregateTable; + await setupAggregateFunctionsTest(this.db); + + const result1 = await this.db.select({ value: avg(table.a) }).from(table); + const result2 = await this.db.select({ value: avg(table.nullOnly) }).from(table); + const result3 = await this.db.select({ value: avgDistinct(table.b) }).from(table); + + expect(result1[0]?.value).eq('24'); + expect(result2[0]?.value).eq(null); + expect(result3[0]?.value).eq('42.5'); + } catch (error: any) { + console.error(error); + throw new Error(`aggregatFunctionAvg error`); + } + } + + async aggregateFunctionSum(): Promise { + try { + await this.beforeEach(); + const table = aggregateTable; + await setupAggregateFunctionsTest(this.db); + + const result1 = await this.db.select({ value: sum(table.b) }).from(table); + const result2 = await this.db.select({ value: sum(table.nullOnly) }).from(table); + const result3 = await this.db.select({ value: sumDistinct(table.b) }).from(table); + + expect(result1[0]?.value).eq('200'); + expect(result2[0]?.value).eq(null); + expect(result3[0]?.value).eq('170'); + } catch (error: any) { + console.error(error); + throw new Error(`aggregateFunctionSum error`); + } + } + + async aggregateFunctionMax(): Promise { + try { + await this.beforeEach(); + const table = aggregateTable; + await setupAggregateFunctionsTest(this.db); + + const result1 = await this.db.select({ value: max(table.b) }).from(table); + const result2 = await this.db.select({ value: max(table.nullOnly) }).from(table); + + expect(result1[0]?.value).eq(90); + expect(result2[0]?.value).eq(null); + } catch (error: any) { + console.error(error); + throw new Error(`aggregateFunctionMax error`); + } + } + + async aggregateFunctionMin(): Promise { + try { + await this.beforeEach(); + const table = aggregateTable; + await setupAggregateFunctionsTest(this.db); + + const result1 = await this.db.select({ value: min(table.b) }).from(table); + const result2 = await this.db.select({ value: min(table.nullOnly) }).from(table); + + expect(result1[0]?.value).eq(10); + expect(result2[0]?.value).eq(null); + } catch (error: any) { + console.error(error); + throw new Error(`aggregateFunctionMin error`); + } + } + + async test$onUpdateFnAnd$onUpdateWorksAs$default(): Promise { + try { + await this.beforeEach(); + this.db.run(sql`drop table if exists ${usersOnUpdate}`); + + this.db.run( + sql` + create table ${usersOnUpdate} ( + id integer primary key autoincrement, + name text not null, + update_counter integer default 1 not null, + updated_at integer, + always_null text + ) + `, + ); + + this.db + .insert(usersOnUpdate) + .values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jack' }, { name: 'Jill' }]) + .run(); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + + const justDates = await this.db.select({ updatedAt }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + const response = await this.db + .select({ ...rest }) + .from(usersOnUpdate) + .orderBy(asc(usersOnUpdate.id)); + + expect(response).deep.equal([ + { name: 'John', id: 1, updateCounter: 1, alwaysNull: null }, + { name: 'Jane', id: 2, updateCounter: 1, alwaysNull: null }, + { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, + { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, + ]); + const msDelay = 250; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).greaterThan(Date.now() - msDelay); + } + } catch (error: any) { + console.error(error); + throw new Error(`test$onUpdateFnAnd$onUpdateWorksAs$default error`); + } + } + + async test$onUpdateFnAnd$onUpdateWorksUpdating(): Promise { + try { + await this.beforeEach(); + this.db.run(sql`drop table if exists ${usersOnUpdate}`); + + this.db.run( + sql` + create table ${usersOnUpdate} ( + id integer primary key autoincrement, + name text not null, + update_counter integer default 1, + updated_at integer, + always_null text + ) + `, + ); + + await this.db + .insert(usersOnUpdate) + .values([{ name: 'John', alwaysNull: 'this will be null after updating' }, { name: 'Jane' }, { name: 'Jack' }, { + name: 'Jill', + }]); + const { updatedAt, ...rest } = getTableColumns(usersOnUpdate); + + await this.db.update(usersOnUpdate).set({ name: 'Angel' }).where(eq(usersOnUpdate.id, 1)); + await this.db.update(usersOnUpdate).set({ updateCounter: null }).where(eq(usersOnUpdate.id, 2)); + + const justDates = await this.db.select({ updatedAt }).from(usersOnUpdate).orderBy(asc(usersOnUpdate.id)); + + const response = await this.db + .select({ ...rest }) + .from(usersOnUpdate) + .orderBy(asc(usersOnUpdate.id)); + + expect(response).deep.equal([ + { name: 'Angel', id: 1, updateCounter: 2, alwaysNull: null }, + { name: 'Jane', id: 2, updateCounter: null, alwaysNull: null }, + { name: 'Jack', id: 3, updateCounter: 1, alwaysNull: null }, + { name: 'Jill', id: 4, updateCounter: 1, alwaysNull: null }, + ]); + const msDelay = 250; + + for (const eachUser of justDates) { + expect(eachUser.updatedAt!.valueOf()).greaterThan(Date.now() - msDelay); + } + } catch (error: any) { + console.error(error); + throw new Error(`test$onUpdateFnAnd$onUpdateWorksUpdating error`); + } + } + + async $countSeparate(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await this.db.$count(countTestTable); + + this.db.run(sql`drop table ${countTestTable}`); + + expect(count).eq(4); + } catch (error: any) { + console.error(error); + throw new Error(`$countSeparate error`); + } + } + + async $countEmbedded(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await this.db + .select({ + count: this.db.$count(countTestTable), + }) + .from(countTestTable); + + this.db.run(sql`drop table ${countTestTable}`); + + expect(count).deep.equal([{ count: 4 }, { count: 4 }, { count: 4 }, { count: 4 }]); + } catch (error: any) { + console.error(error); + throw new Error(`$countEmbedded error`); + } + } + + async $countSeparateReuse(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = this.db.$count(countTestTable); + + const count1 = await count; + + await this.db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await this.db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + this.db.run(sql`drop table ${countTestTable}`); + + expect(count1).eq(4); + expect(count2).eq(5); + expect(count3).eq(6); + } catch (error: any) { + console.error(error); + throw new Error(`$countSeparateReuse error`); + } + } + + async $countEmbeddedReuse(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = this.db + .select({ + count: this.db.$count(countTestTable), + }) + .from(countTestTable); + + const count1 = await count; + + await this.db.insert(countTestTable).values({ id: 5, name: 'fifth' }); + + const count2 = await count; + + await this.db.insert(countTestTable).values({ id: 6, name: 'sixth' }); + + const count3 = await count; + + this.db.run(sql`drop table ${countTestTable}`); + + expect(count1).deep.equal([{ count: 4 }, { count: 4 }, { count: 4 }, { count: 4 }]); + expect(count2).deep.equal([{ count: 5 }, { count: 5 }, { count: 5 }, { count: 5 }, { count: 5 }]); + expect(count3).deep.equal([{ count: 6 }, { count: 6 }, { count: 6 }, { count: 6 }, { count: 6 }, { count: 6 }]); + } catch (error: any) { + console.error(error); + throw new Error(`$countEmbeddedReuse error`); + } + } + + async $countSeparateWithFilters(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await this.db.$count(countTestTable, gt(countTestTable.id, 1)); + + this.db.run(sql`drop table ${countTestTable}`); + + expect(count).deep.equal(3); + } catch (error: any) { + console.error(error); + throw new Error(`$countSeparateWithFilters error`); + } + } + + async $countEmbeddedWithFilters(): Promise { + try { + await this.beforeEach(); + const countTestTable = sqliteTable('count_test', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + this.db.run(sql`drop table if exists ${countTestTable}`); + this.db.run(sql`create table ${countTestTable} (id int, name text)`); + + await this.db.insert(countTestTable).values([ + { id: 1, name: 'First' }, + { id: 2, name: 'Second' }, + { id: 3, name: 'Third' }, + { id: 4, name: 'Fourth' }, + ]); + + const count = await this.db + .select({ + count: this.db.$count(countTestTable, gt(countTestTable.id, 1)), + }) + .from(countTestTable); + + await this.db.run(sql`drop table ${countTestTable}`); + + expect(count).deep.equal([{ count: 3 }, { count: 3 }, { count: 3 }, { count: 3 }]); + } catch (error: any) { + console.error(error); + throw new Error(`$countEmbeddedWithFilters error`); + } + } + + async updateWithLimitAndOrderBy(): Promise { + try { + await this.beforeEach(); + await this.db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await this.db.update(usersTable).set({ verified: true }).limit(2).orderBy(asc(usersTable.name)); + + const result = await this.db + .select({ name: usersTable.name, verified: usersTable.verified }) + .from(usersTable) + .orderBy(asc(usersTable.name)); + + expect(result).deep.equal([ + { name: 'Alan', verified: true }, + { name: 'Barry', verified: true }, + { name: 'Carl', verified: false }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`updateWithLimitAndOrderBy error`); + } + } + + async deleteWithLimitAndOrderBy(): Promise { + try { + await this.beforeEach(); + await this.db.insert(usersTable).values([ + { name: 'Barry', verified: false }, + { name: 'Alan', verified: false }, + { name: 'Carl', verified: false }, + ]); + + await this.db.delete(usersTable).where(eq(usersTable.verified, false)).limit(1).orderBy(asc(usersTable.name)); + + const result = await this.db + .select({ name: usersTable.name, verified: usersTable.verified }) + .from(usersTable) + .orderBy(asc(usersTable.name)); + expect(result).deep.equal([ + { name: 'Barry', verified: false }, + { name: 'Carl', verified: false }, + ]); + } catch (error: any) { + console.error(error); + throw new Error(`deleteWithLimitAndOrderBy error`); + } + } +} + +export default { + /** + * This is the standard fetch handler for a Cloudflare Worker + * + * @param request - The request submitted to the Worker from the client + * @param env - The interface to reference bindings declared in wrangler.toml + * @param ctx - The execution context of the Worker + * @returns The response to be sent back to the client + */ + async fetch(request, env): Promise { + try { + const id: DurableObjectId = env.MY_DURABLE_OBJECT.idFromName('durable-object'); + const stub = env.MY_DURABLE_OBJECT.get(id); + + await stub.migrate1(); + + await stub.insertBigIntValues(); + + await stub.selectAllFields(); + await stub.selectPartial(); + await stub.selectSql(); + await stub.selectTypedSql(); + await stub.selectWithEmptyArrayInInArray(); + await stub.selectWithEmptyArrayInNotInArray(); + await stub.selectDistinct(); + await stub.returingSql(); + await stub.$defaultFunction(); + await stub.deleteReturningSql(); + await stub.queryCheckInsertSingleEmptyRow(); + await stub.queryCheckInsertMultipleEmptyRow(); + await stub.insertAllDefaultsIn1Row(); + await stub.insertAllDefaultsInMultipleRows(); + await stub.updateReturningSql(); + await stub.insertWithAutoIncrement(); + await stub.insertDataWithDefaultValues(); + await stub.insertDataWithOverridenDefaultValues(); + await stub.updateWithReturningFields(); + await stub.updateWithReturningPartial(); + await stub.updateWithReturningAllFields(); + await stub.deleteWithReturningPartial(); + await stub.insertAndSelect(); + + await stub.jsonInsert(); + await stub.insertMany(); + await stub.insertManyWithReturning(); + + await stub.partialJoinWithAlias(); + await stub.fullJoinWithAlias(); + await stub.selectFromAlias(); + await stub.insertWithSpaces(); + await stub.preparedStatement(); + await stub.preparedStatementReuse(); + await stub.insertPlaceholdersOnColumnsWithEncoder(); + await stub.preparedStatementWithPlaceholderInWhere(); + await stub.preparedStatementWithPlaceholderInLimit(); + await stub.preparedStatementWithPlaceholderInOffset(); + await stub.preparedStatementBuiltUsing$dynamic(); + + await stub.selectWithGroupByAsField(); + await stub.selectWithExists(); + await stub.selectWithGroupByAsSql(); + await stub.selectWithGroupByAsSqlPlusColumn(); + await stub.selectWithGroupByAsColumnPlusSql(); + await stub.selectWithGroupByComplexQuery(); + await stub.buildQuery(); + await stub.insertViaDbRunPlusSelectViaDbAll(); + await stub.insertViaDbGet(); + await stub.insertViaDbRunPlusSelectViaDbGet(); + await stub.insertViaDbGetQueryBuilder(); + await stub.joinSubquery(); + await stub.withSelect(); + await stub.withUpdate(); + await stub.withInsert(); + + await stub.withDelete(); + await stub.selectFromSubquerySql(); + await stub.selectAFieldWithoutJoiningItsTable(); + await stub.selectCount(); + await stub.having(); + await stub.insertNullTimestamp(); + await stub.selectFromRawSql(); + await stub.selectFromRawSqlWithJoins(); + await stub.joinOnAliasedSqlFromSelect(); + await stub.joinOnAliasedSqlFromWithClause(); + await stub.prefixedTable(); + await stub.orderByWithAliasedColumn(); + await stub.transaction(); + await stub.nestedTransaction(); + await stub.joinSubqueryWithJoin(); + await stub.joinViewAsSubquery(); + await stub.insertWithOnConflictDoNothing(); + await stub.insertWithOnConflictDoNothinUsingCompositePk(); + await stub.insertWithOnConflictDoNothingUsingTarget(); + await stub.insertWithOnConflictDoNothingUsingCompositePkAsTarget(); + await stub.insertWithOnConflictDoUpdate(); + await stub.insertWithOnConflictDoUpdateWhere(); + await stub.insertWithOnConflictDoUpdateUsingCompositePk(); + await stub.apiCRUD(); + await stub.apiInsertPlusSelectPreparePlusAsyncExecute(); + await stub.apiInsertSelectPreparePlusSyncExecute(); + await stub.selectPlusGetForEmptyResult(); + await stub.setOperationsUnionFromQueryBuilderWithSubquery(); + await stub.setOperationsUnionAsFunction(); + await stub.setOperationsUnionAllFromQueryBuilder(); + await stub.setOperationsUnionAllAsFunction(); + await stub.setOperationsIntersectFromQueryBuilder(); + await stub.setOperationsIntersectAsFunction(); + await stub.setOperationsExceptFromQueryBuilder(); + await stub.setOperationsExceptAsFunction(); + await stub.setOperationsMixedFromQueryBuilder(); + await stub.setOperationsMixedAllAsFunctionWithSubquery(); + await stub.aggregateFunctionCount(); + await stub.aggregatFunctionAvg(); + await stub.aggregateFunctionSum(); + await stub.aggregateFunctionMax(); + await stub.aggregateFunctionMin(); + await stub.test$onUpdateFnAnd$onUpdateWorksAs$default(); + await stub.test$onUpdateFnAnd$onUpdateWorksUpdating(); + await stub.$countSeparate(); + await stub.$countEmbedded(); + await stub.$countEmbeddedReuse(); + await stub.$countSeparateWithFilters(); + await stub.$countEmbeddedWithFilters(); + await stub.updateWithLimitAndOrderBy(); + await stub.deleteWithLimitAndOrderBy(); + await stub.updateUndefined(); + await stub.insertUndefined(); + + return new Response(); + } catch (error: any) { + return new Response(error.message); + } + }, +} satisfies ExportedHandler; diff --git a/integration-tests/tests/sqlite/durable-objects/worker-configuration.d.ts b/integration-tests/tests/sqlite/durable-objects/worker-configuration.d.ts new file mode 100644 index 000000000..cab87a7b0 --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/worker-configuration.d.ts @@ -0,0 +1,5 @@ +// Generated by Wrangler by running `wrangler types` + +interface Env { + MY_DURABLE_OBJECT: DurableObjectNamespace; +} diff --git a/integration-tests/tests/sqlite/durable-objects/wrangler.toml b/integration-tests/tests/sqlite/durable-objects/wrangler.toml new file mode 100644 index 000000000..7e3ea736c --- /dev/null +++ b/integration-tests/tests/sqlite/durable-objects/wrangler.toml @@ -0,0 +1,25 @@ +#:schema node_modules/wrangler/config-schema.json +name = "sqlite-durable-objects" +main = "index.ts" +compatibility_date = "2024-11-12" +compatibility_flags = [ "nodejs_compat" ] + +# Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model. +# Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps. +# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects +[[durable_objects.bindings]] +name = "MY_DURABLE_OBJECT" +class_name = "MyDurableObject" + +# Durable Object migrations. +# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations +[[migrations]] +tag = "v1" +new_sqlite_classes = ["MyDurableObject"] + +[[rules]] +type = "Text" +globs = ["**/*.sql"] +fallthrough = true + + diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index fcce0a362..a04281018 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -10,6 +10,7 @@ export default defineConfig({ 'tests/relational/**/*.test.ts', 'tests/pg/**/*.test.ts', 'tests/mysql/**/*.test.ts', + 'tests/singlestore/**/*.test.ts', 'tests/sqlite/**/*.test.ts', 'tests/replicas/**/*', 'tests/imports/**/*', @@ -58,6 +59,8 @@ export default defineConfig({ 'tests/sqlite/libsql-ws.test.ts', 'tests/sqlite/libsql-http.test.ts', 'tests/mysql/tidb-serverless.test.ts', + // waiting for json_array from singlestore team + 'tests/relational/singlestore.test.ts', ], typecheck: { tsconfig: 'tsconfig.json', diff --git a/package.json b/package.json index d52a568a6..6b4715b0e 100755 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "test": "turbo run test --color", "t": "pnpm test", "test:types": "turbo run test:types --color", - "lint": "concurrently -n eslint,dprint \"eslint --ext ts .\" \"dprint check --list-different\"" + "lint": "dprint check --list-different", + "lint:fix": "dprint fmt" }, "devDependencies": { "@arethetypeswrong/cli": "0.15.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 24d14e7c5..7c4b13880 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,7 +40,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241112.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -304,8 +304,8 @@ importers: specifier: ^3.549.0 version: 3.583.0 '@cloudflare/workers-types': - specifier: ^4.20230904.0 - version: 4.20240512.0 + specifier: ^4.20241112.0 + version: 4.20241112.0 '@electric-sql/pglite': specifier: ^0.2.12 version: 0.2.12 @@ -2041,15 +2041,15 @@ packages: cpu: [x64] os: [win32] - '@cloudflare/workers-types@4.20240512.0': - resolution: {integrity: sha512-o2yTEWg+YK/I1t/Me+dA0oarO0aCbjibp6wSeaw52DSE9tDyKJ7S+Qdyw/XsMrKn4t8kF6f/YOba+9O4MJfW9w==} - '@cloudflare/workers-types@4.20240524.0': resolution: {integrity: sha512-GpSr4uE7y39DU9f0+wmrL76xd03wn0jy1ClITaa3ZZltKjirAV8TW1GzHrvvKyVGx6u3lekrFnB1HzVHsCYHDQ==} '@cloudflare/workers-types@4.20241004.0': resolution: {integrity: sha512-3LrPvtecs4umknOF1bTPNLHUG/ZjeSE6PYBQ/tbO7lwaVhjZTaTugiaCny2byrZupBlVNuubQVktcAgMfw0C1A==} + '@cloudflare/workers-types@4.20241112.0': + resolution: {integrity: sha512-Q4p9bAWZrX14bSCKY9to19xl0KMU7nsO5sJ2cTVspHoypsjPUMeQCsjHjmsO2C4Myo8/LPeDvmqFmkyNAPPYZw==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -12821,12 +12821,12 @@ snapshots: '@cloudflare/workerd-windows-64@1.20240712.0': optional: true - '@cloudflare/workers-types@4.20240512.0': {} - '@cloudflare/workers-types@4.20240524.0': {} '@cloudflare/workers-types@4.20241004.0': {} + '@cloudflare/workers-types@4.20241112.0': {} + '@colors/colors@1.5.0': optional: true @@ -16980,10 +16980,10 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241112.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.10.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.12)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@11.5.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@11.5.0)(mysql2@3.11.0)(pg@8.13.1)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.13.1)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 - '@cloudflare/workers-types': 4.20241004.0 + '@cloudflare/workers-types': 4.20241112.0 '@libsql/client': 0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': 0.10.3 '@opentelemetry/api': 1.8.0 From fc7f280679bf72376786ec55f7470e551a4a8fd2 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 4 Dec 2024 11:03:48 +0200 Subject: [PATCH 415/492] Fix generate migrations for SingleStore --- changelogs/drizzle-kit/0.29.1.md | 1 + drizzle-kit/package.json | 2 +- drizzle-kit/src/cli/schema.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 changelogs/drizzle-kit/0.29.1.md diff --git a/changelogs/drizzle-kit/0.29.1.md b/changelogs/drizzle-kit/0.29.1.md new file mode 100644 index 000000000..8e8c6d3d3 --- /dev/null +++ b/changelogs/drizzle-kit/0.29.1.md @@ -0,0 +1 @@ +- Fix SingleStore generate migrations command \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index eca469d9b..4d86c9beb 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.29.0", + "version": "0.29.1", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 12153ee74..40449dcdd 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -97,7 +97,7 @@ export const generate = command({ } else if (dialect === 'turso') { await prepareAndMigrateLibSQL(opts); } else if (dialect === 'singlestore') { - await prepareAndMigrateSqlite(opts); + await prepareAndMigrateSingleStore(opts); } else { assertUnreachable(dialect); } From 3f3eb730860c63afdeebc64fa24642a4a47f2a76 Mon Sep 17 00:00:00 2001 From: L-Mario564 Date: Wed, 4 Dec 2024 03:20:40 -0800 Subject: [PATCH 416/492] Add some view utils (#3553) * Add `getViewSelectedFields` util function * Fix view types * Add `$inferSelect` to views * Format * Fix lint errors * Add `isView` util function --------- Co-authored-by: Andrii Sherman --- drizzle-orm/src/mysql-core/view.ts | 5 +- drizzle-orm/src/pg-core/view.ts | 9 +-- .../src/query-builders/select.types.ts | 2 + drizzle-orm/src/sql/sql.ts | 26 ++++++- drizzle-orm/src/sqlite-core/view.ts | 5 +- drizzle-orm/src/utils.ts | 4 + drizzle-orm/type-tests/mysql/select.ts | 49 +++++++++++- drizzle-orm/type-tests/pg/select.ts | 78 ++++++++++++++++++- drizzle-orm/type-tests/sqlite/select.ts | 42 +++++++++- 9 files changed, 202 insertions(+), 18 deletions(-) diff --git a/drizzle-orm/src/mysql-core/view.ts b/drizzle-orm/src/mysql-core/view.ts index 6054e022c..42d9b3af6 100644 --- a/drizzle-orm/src/mysql-core/view.ts +++ b/drizzle-orm/src/mysql-core/view.ts @@ -7,7 +7,6 @@ import type { ColumnsSelection, SQL } from '~/sql/sql.ts'; import { getTableColumns } from '~/utils.ts'; import type { MySqlColumn, MySqlColumnBuilderBase } from './columns/index.ts'; import { QueryBuilder } from './query-builders/query-builder.ts'; -import type { SelectedFields } from './query-builders/select.types.ts'; import { mysqlTable } from './table.ts'; import { MySqlViewBase } from './view-base.ts'; import { MySqlViewConfig } from './view-common.ts'; @@ -58,7 +57,7 @@ export class ViewBuilderCore extends ViewBuilderCore<{ name: TName }> { static override readonly [entityKind]: string = 'MySqlViewBuilder'; - as( + as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), ): MySqlViewWithSelection> { if (typeof qb === 'function') { @@ -160,7 +159,7 @@ export class MySqlView< config: { name: TName; schema: string | undefined; - selectedFields: SelectedFields; + selectedFields: ColumnsSelection; query: SQL | undefined; }; }) { diff --git a/drizzle-orm/src/pg-core/view.ts b/drizzle-orm/src/pg-core/view.ts index 2f88d7e17..f8e916a31 100644 --- a/drizzle-orm/src/pg-core/view.ts +++ b/drizzle-orm/src/pg-core/view.ts @@ -8,7 +8,6 @@ import { getTableColumns } from '~/utils.ts'; import type { RequireAtLeastOne } from '~/utils.ts'; import type { PgColumn, PgColumnBuilderBase } from './columns/common.ts'; import { QueryBuilder } from './query-builders/query-builder.ts'; -import type { SelectedFields } from './query-builders/select.types.ts'; import { pgTable } from './table.ts'; import { PgViewBase } from './view-base.ts'; import { PgViewConfig } from './view-common.ts'; @@ -45,7 +44,7 @@ export class DefaultViewBuilderCore extends DefaultViewBuilderCore<{ name: TName }> { static override readonly [entityKind]: string = 'PgViewBuilder'; - as( + as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), ): PgViewWithSelection> { if (typeof qb === 'function') { @@ -198,7 +197,7 @@ export class MaterializedViewBuilder { static override readonly [entityKind]: string = 'PgMaterializedViewBuilder'; - as( + as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), ): PgMaterializedViewWithSelection> { if (typeof qb === 'function') { @@ -317,7 +316,7 @@ export class PgView< config: { name: TName; schema: string | undefined; - selectedFields: SelectedFields; + selectedFields: ColumnsSelection; query: SQL | undefined; }; }) { @@ -362,7 +361,7 @@ export class PgMaterializedView< config: { name: TName; schema: string | undefined; - selectedFields: SelectedFields; + selectedFields: ColumnsSelection; query: SQL | undefined; }; }) { diff --git a/drizzle-orm/src/query-builders/select.types.ts b/drizzle-orm/src/query-builders/select.types.ts index 07579662f..e7975af65 100644 --- a/drizzle-orm/src/query-builders/select.types.ts +++ b/drizzle-orm/src/query-builders/select.types.ts @@ -93,6 +93,7 @@ export type AddAliasToSelection< : { [Key in keyof TSelection]: TSelection[Key] extends Column ? ChangeColumnTableName + : TSelection[Key] extends Table ? AddAliasToSelection : TSelection[Key] extends SQL | SQL.Aliased ? TSelection[Key] : TSelection[Key] extends ColumnsSelection ? MapColumnsToTableAlias : never; @@ -120,6 +121,7 @@ export type BuildSubquerySelection< [Key in keyof TSelection]: TSelection[Key] extends SQL ? DrizzleTypeError<'You cannot reference this field without assigning it an alias first - use `.as()`'> : TSelection[Key] extends SQL.Aliased ? TSelection[Key] + : TSelection[Key] extends Table ? BuildSubquerySelection : TSelection[Key] extends Column ? ApplyNullabilityToColumn : TSelection[Key] extends ColumnsSelection ? BuildSubquerySelection diff --git a/drizzle-orm/src/sql/sql.ts b/drizzle-orm/src/sql/sql.ts index 234370a85..ba7586fe8 100644 --- a/drizzle-orm/src/sql/sql.ts +++ b/drizzle-orm/src/sql/sql.ts @@ -1,9 +1,10 @@ import type { CasingCache } from '~/casing.ts'; import { entityKind, is } from '~/entity.ts'; -import type { SelectedFields } from '~/operations.ts'; import { isPgEnum } from '~/pg-core/columns/enum.ts'; +import type { SelectResult } from '~/query-builders/select.types.ts'; import { Subquery } from '~/subquery.ts'; import { tracer } from '~/tracing.ts'; +import type { Assume, Equal } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { AnyColumn } from '../column.ts'; import { Column } from '../column.ts'; @@ -617,6 +618,8 @@ export function fillPlaceholders(params: unknown[], values: Record; +const IsDrizzleView = Symbol.for('drizzle:IsDrizzleView'); + export abstract class View< TName extends string = string, TExisting extends boolean = boolean, @@ -637,17 +640,22 @@ export abstract class View< name: TName; originalName: TName; schema: string | undefined; - selectedFields: SelectedFields; + selectedFields: ColumnsSelection; isExisting: TExisting; query: TExisting extends true ? undefined : SQL; isAlias: boolean; }; + /** @internal */ + [IsDrizzleView] = true; + + declare readonly $inferSelect: InferSelectViewModel, TExisting, TSelection>>; + constructor( { name, schema, selectedFields, query }: { name: TName; schema: string | undefined; - selectedFields: SelectedFields; + selectedFields: ColumnsSelection; query: SQL | undefined; }, ) { @@ -667,6 +675,18 @@ export abstract class View< } } +export function isView(view: unknown): view is View { + return typeof view === 'object' && view !== null && IsDrizzleView in view; +} + +export type InferSelectViewModel = + Equal extends true ? { [x: string]: unknown } + : SelectResult< + TView['_']['selectedFields'], + 'single', + Record + >; + // Defined separately from the Column class to resolve circular dependency Column.prototype.getSQL = function() { return new SQL([this]); diff --git a/drizzle-orm/src/sqlite-core/view.ts b/drizzle-orm/src/sqlite-core/view.ts index 03ef08025..1caf211ce 100644 --- a/drizzle-orm/src/sqlite-core/view.ts +++ b/drizzle-orm/src/sqlite-core/view.ts @@ -7,7 +7,6 @@ import type { ColumnsSelection, SQL } from '~/sql/sql.ts'; import { getTableColumns } from '~/utils.ts'; import type { SQLiteColumn, SQLiteColumnBuilderBase } from './columns/common.ts'; import { QueryBuilder } from './query-builders/query-builder.ts'; -import type { SelectedFields } from './query-builders/select.types.ts'; import { sqliteTable } from './table.ts'; import { SQLiteViewBase } from './view-base.ts'; @@ -38,7 +37,7 @@ export class ViewBuilderCore< export class ViewBuilder extends ViewBuilderCore<{ name: TName }> { static override readonly [entityKind]: string = 'SQLiteViewBuilder'; - as( + as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), ): SQLiteViewWithSelection> { if (typeof qb === 'function') { @@ -135,7 +134,7 @@ export class SQLiteView< config: { name: TName; schema: string | undefined; - selectedFields: SelectedFields; + selectedFields: ColumnsSelection; query: SQL | undefined; }; }) { diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index 58d0c3d91..51d30e97c 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -188,6 +188,10 @@ export function getTableColumns(table: T): T['_']['columns'] { return table[Table.Symbol.Columns]; } +export function getViewSelectedFields(view: T): T['_']['selectedFields'] { + return view[ViewBaseConfig].selectedFields; +} + /** @internal */ export function getTableLikeName(table: TableLike): string | undefined { return is(table, Subquery) diff --git a/drizzle-orm/type-tests/mysql/select.ts b/drizzle-orm/type-tests/mysql/select.ts index 0a6af743b..bad55aa59 100644 --- a/drizzle-orm/type-tests/mysql/select.ts +++ b/drizzle-orm/type-tests/mysql/select.ts @@ -22,11 +22,19 @@ import { or, } from '~/expressions.ts'; import { alias } from '~/mysql-core/alias.ts'; -import { param, sql } from '~/sql/sql.ts'; +import { type InferSelectViewModel, param, sql } from '~/sql/sql.ts'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; -import { type MySqlSelect, type MySqlSelectQueryBuilder, QueryBuilder } from '~/mysql-core/index.ts'; +import { + int, + type MySqlSelect, + type MySqlSelectQueryBuilder, + mysqlTable, + mysqlView, + QueryBuilder, + text, +} from '~/mysql-core/index.ts'; import { db } from './db.ts'; import { cities, classes, newYorkers, users } from './tables.ts'; @@ -604,3 +612,40 @@ await db // @ts-expect-error method was already called .for('update'); } + +{ + const table1 = mysqlTable('table1', { + id: int().primaryKey(), + name: text().notNull(), + }); + const table2 = mysqlTable('table2', { + id: int().primaryKey(), + age: int().notNull(), + }); + const table3 = mysqlTable('table3', { + id: int().primaryKey(), + phone: text().notNull(), + }); + const view = mysqlView('view').as((qb) => + qb.select({ + table: table1, + column: table2.age, + nested: { + column: table3.phone, + }, + }).from(table1).innerJoin(table2, sql``).leftJoin(table3, sql``) + ); + const result = await db.select().from(view); + + Expect< + Equal + >; + Expect>; + Expect[]>>; +} diff --git a/drizzle-orm/type-tests/pg/select.ts b/drizzle-orm/type-tests/pg/select.ts index 0fde90a71..4ab3a86b3 100644 --- a/drizzle-orm/type-tests/pg/select.ts +++ b/drizzle-orm/type-tests/pg/select.ts @@ -31,13 +31,15 @@ import { alias } from '~/pg-core/alias.ts'; import { boolean, integer, + pgMaterializedView, type PgSelect, type PgSelectQueryBuilder, pgTable, + pgView, QueryBuilder, text, } from '~/pg-core/index.ts'; -import { type SQL, sql } from '~/sql/sql.ts'; +import { type InferSelectViewModel, type SQL, sql } from '~/sql/sql.ts'; import { db } from './db.ts'; import { cities, classes, newYorkers, newYorkers2, users } from './tables.ts'; @@ -1156,3 +1158,77 @@ await db ), ); } + +{ + const table1 = pgTable('table1', { + id: integer().primaryKey(), + name: text().notNull(), + }); + const table2 = pgTable('table2', { + id: integer().primaryKey(), + age: integer().notNull(), + }); + const table3 = pgTable('table3', { + id: integer().primaryKey(), + phone: text().notNull(), + }); + const view = pgView('view').as((qb) => + qb.select({ + table: table1, + column: table2.age, + nested: { + column: table3.phone, + }, + }).from(table1).innerJoin(table2, sql``).leftJoin(table3, sql``) + ); + const result = await db.select().from(view); + + Expect< + Equal + >; + Expect>; + Expect[]>>; +} + +{ + const table1 = pgTable('table1', { + id: integer().primaryKey(), + name: text().notNull(), + }); + const table2 = pgTable('table2', { + id: integer().primaryKey(), + age: integer().notNull(), + }); + const table3 = pgTable('table3', { + id: integer().primaryKey(), + phone: text().notNull(), + }); + const view = pgMaterializedView('view').as((qb) => + qb.select({ + table: table1, + column: table2.age, + nested: { + column: table3.phone, + }, + }).from(table1).innerJoin(table2, sql``).leftJoin(table3, sql``) + ); + const result = await db.select().from(view); + + Expect< + Equal + >; + Expect>; + Expect[]>>; +} diff --git a/drizzle-orm/type-tests/sqlite/select.ts b/drizzle-orm/type-tests/sqlite/select.ts index 196dbc4de..92bb6055a 100644 --- a/drizzle-orm/type-tests/sqlite/select.ts +++ b/drizzle-orm/type-tests/sqlite/select.ts @@ -21,12 +21,15 @@ import { notLike, or, } from '~/expressions.ts'; -import { param, sql } from '~/sql/sql.ts'; +import { type InferSelectViewModel, param, sql } from '~/sql/sql.ts'; import { alias } from '~/sqlite-core/alias.ts'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; +import { integer, text } from '~/sqlite-core/index.ts'; import type { SQLiteSelect, SQLiteSelectQueryBuilder } from '~/sqlite-core/query-builders/select.types.ts'; +import { sqliteTable } from '~/sqlite-core/table.ts'; +import { sqliteView } from '~/sqlite-core/view.ts'; import { db } from './db.ts'; import { cities, classes, newYorkers, users } from './tables.ts'; @@ -579,3 +582,40 @@ Expect< // @ts-expect-error method was already called .offset(10); } + +{ + const table1 = sqliteTable('table1', { + id: integer().primaryKey(), + name: text().notNull(), + }); + const table2 = sqliteTable('table2', { + id: integer().primaryKey(), + age: integer().notNull(), + }); + const table3 = sqliteTable('table3', { + id: integer().primaryKey(), + phone: text().notNull(), + }); + const view = sqliteView('view').as((qb) => + qb.select({ + table: table1, + column: table2.age, + nested: { + column: table3.phone, + }, + }).from(table1).innerJoin(table2, sql``).leftJoin(table3, sql``) + ); + const result = await db.select().from(view); + + Expect< + Equal + >; + Expect>; + Expect[]>>; +} From a44af769d180e72ea2b3b21757a04e203d2b98b1 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman <102579553+AleksandrSherman@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:19:48 +0200 Subject: [PATCH 417/492] Drizzle kit/remove-non-strict-postgres (#3403) * removed non-strict creation in postgres * Fix new tests --------- Co-authored-by: AndriiSherman --- drizzle-kit/src/sqlgenerator.ts | 29 ++++------ drizzle-kit/tests/indexes/pg.test.ts | 24 ++++---- drizzle-kit/tests/libsql-statements.test.ts | 6 +- drizzle-kit/tests/pg-checks.test.ts | 2 +- drizzle-kit/tests/pg-identity.test.ts | 6 +- drizzle-kit/tests/pg-tables.test.ts | 64 ++++++++------------- drizzle-kit/tests/pg-views.test.ts | 18 +++--- drizzle-kit/tests/push/libsql.test.ts | 8 +-- drizzle-kit/tests/push/pg.test.ts | 48 ++++++++-------- drizzle-kit/tests/push/sqlite.test.ts | 2 +- drizzle-kit/tests/rls/pg-policy.test.ts | 6 +- 11 files changed, 93 insertions(+), 120 deletions(-) diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index a35c001fd..26adaf531 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -389,7 +389,7 @@ class PgCreateTableConvertor extends Convertor { let statement = ''; const name = schema ? `"${schema}"."${tableName}"` : `"${tableName}"`; - statement += `CREATE TABLE IF NOT EXISTS ${name} (\n`; + statement += `CREATE TABLE ${name} (\n`; for (let i = 0; i < columns.length; i++) { const column = columns[i]; @@ -1672,7 +1672,7 @@ class PgAlterTableDropColumnConvertor extends Convertor { ? `"${schema}"."${tableName}"` : `"${tableName}"`; - return `ALTER TABLE ${tableNameWithSchema} DROP COLUMN IF EXISTS "${columnName}";`; + return `ALTER TABLE ${tableNameWithSchema} DROP COLUMN "${columnName}";`; } } @@ -2330,7 +2330,7 @@ export class LibSQLModifyColumn extends Convertor { for (const table of Object.values(json2.tables)) { for (const index of Object.values(table.indexes)) { const unsquashed = SQLiteSquasher.unsquashIdx(index); - sqlStatements.push(`DROP INDEX IF EXISTS "${unsquashed.name}";`); + sqlStatements.push(`DROP INDEX "${unsquashed.name}";`); indexes.push({ ...unsquashed, tableName: table.name }); } } @@ -3283,14 +3283,9 @@ class PgCreateForeignKeyConvertor extends Convertor { : `"${tableTo}"`; const alterStatement = - `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${name}" FOREIGN KEY (${fromColumnsString}) REFERENCES ${tableToNameWithSchema}(${toColumnsString})${onDeleteStatement}${onUpdateStatement}`; + `ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${name}" FOREIGN KEY (${fromColumnsString}) REFERENCES ${tableToNameWithSchema}(${toColumnsString})${onDeleteStatement}${onUpdateStatement};`; - let sql = 'DO $$ BEGIN\n'; - sql += ' ' + alterStatement + ';\n'; - sql += 'EXCEPTION\n'; - sql += ' WHEN duplicate_object THEN null;\n'; - sql += 'END $$;\n'; - return sql; + return alterStatement; } } @@ -3387,13 +3382,9 @@ class PgAlterForeignKeyConvertor extends Convertor { : `"${newFk.tableFrom}"`; const alterStatement = - `ALTER TABLE ${tableFromNameWithSchema} ADD CONSTRAINT "${newFk.name}" FOREIGN KEY (${fromColumnsString}) REFERENCES ${tableToNameWithSchema}(${toColumnsString})${onDeleteStatement}${onUpdateStatement}`; + `ALTER TABLE ${tableFromNameWithSchema} ADD CONSTRAINT "${newFk.name}" FOREIGN KEY (${fromColumnsString}) REFERENCES ${tableToNameWithSchema}(${toColumnsString})${onDeleteStatement}${onUpdateStatement};`; - sql += 'DO $$ BEGIN\n'; - sql += ' ' + alterStatement + ';\n'; - sql += 'EXCEPTION\n'; - sql += ' WHEN duplicate_object THEN null;\n'; - sql += 'END $$;\n'; + sql += alterStatement; return sql; } } @@ -3474,7 +3465,7 @@ class CreatePgIndexConvertor extends Convertor { return `CREATE ${indexPart}${ concurrently ? ' CONCURRENTLY' : '' - } IF NOT EXISTS "${name}" ON ${tableNameWithSchema} USING ${method} (${value})${ + } "${name}" ON ${tableNameWithSchema} USING ${method} (${value})${ Object.keys(withMap!).length !== 0 ? ` WITH (${reverseLogic(withMap!)})` : '' @@ -3567,7 +3558,7 @@ class PgDropIndexConvertor extends Convertor { convert(statement: JsonDropIndexStatement): string { const { name } = PgSquasher.unsquashIdx(statement.data); - return `DROP INDEX IF EXISTS "${name}";`; + return `DROP INDEX "${name}";`; } } @@ -3663,7 +3654,7 @@ export class SqliteDropIndexConvertor extends Convertor { convert(statement: JsonDropIndexStatement): string { const { name } = PgSquasher.unsquashIdx(statement.data); - return `DROP INDEX IF EXISTS \`${name}\`;`; + return `DROP INDEX \`${name}\`;`; } } diff --git a/drizzle-kit/tests/indexes/pg.test.ts b/drizzle-kit/tests/indexes/pg.test.ts index b9ff36020..57f77c103 100644 --- a/drizzle-kit/tests/indexes/pg.test.ts +++ b/drizzle-kit/tests/indexes/pg.test.ts @@ -64,7 +64,7 @@ const pgSuite: DialectSuite = { }); expect(sqlStatements.length).toBe(1); expect(sqlStatements[0]).toBe( - `CREATE INDEX IF NOT EXISTS "vector_embedding_idx" ON "users" USING hnsw ("name" vector_ip_ops) WITH (m=16,ef_construction=64);`, + `CREATE INDEX "vector_embedding_idx" ON "users" USING hnsw ("name" vector_ip_ops) WITH (m=16,ef_construction=64);`, ); }, @@ -123,15 +123,15 @@ const pgSuite: DialectSuite = { ); expect(sqlStatements).toStrictEqual([ - 'DROP INDEX IF EXISTS "indx";', - 'DROP INDEX IF EXISTS "indx1";', - 'DROP INDEX IF EXISTS "indx2";', - 'DROP INDEX IF EXISTS "indx3";', - 'CREATE INDEX IF NOT EXISTS "indx4" ON "users" USING btree (lower(id)) WHERE true;', - 'CREATE INDEX IF NOT EXISTS "indx" ON "users" USING btree ("name" DESC NULLS LAST);', - 'CREATE INDEX IF NOT EXISTS "indx1" ON "users" USING btree ("name" DESC NULLS LAST) WHERE false;', - 'CREATE INDEX IF NOT EXISTS "indx2" ON "users" USING btree ("name" test) WHERE true;', - 'CREATE INDEX IF NOT EXISTS "indx3" ON "users" USING btree (lower("id")) WHERE true;', + 'DROP INDEX "indx";', + 'DROP INDEX "indx1";', + 'DROP INDEX "indx2";', + 'DROP INDEX "indx3";', + 'CREATE INDEX "indx4" ON "users" USING btree (lower(id)) WHERE true;', + 'CREATE INDEX "indx" ON "users" USING btree ("name" DESC NULLS LAST);', + 'CREATE INDEX "indx1" ON "users" USING btree ("name" DESC NULLS LAST) WHERE false;', + 'CREATE INDEX "indx2" ON "users" USING btree ("name" test) WHERE true;', + 'CREATE INDEX "indx3" ON "users" USING btree (lower("id")) WHERE true;', ]); }, @@ -234,10 +234,10 @@ const pgSuite: DialectSuite = { }); expect(sqlStatements.length).toBe(2); expect(sqlStatements[0]).toBe( - `CREATE INDEX IF NOT EXISTS "users_name_id_index" ON "users" USING btree ("name" DESC NULLS LAST,"id") WITH (fillfactor=70) WHERE select 1;`, + `CREATE INDEX "users_name_id_index" ON "users" USING btree ("name" DESC NULLS LAST,"id") WITH (fillfactor=70) WHERE select 1;`, ); expect(sqlStatements[1]).toBe( - `CREATE INDEX IF NOT EXISTS "indx1" ON "users" USING hash ("name" DESC NULLS LAST,"name") WITH (fillfactor=70);`, + `CREATE INDEX "indx1" ON "users" USING hash ("name" DESC NULLS LAST,"name") WITH (fillfactor=70);`, ); }, }; diff --git a/drizzle-kit/tests/libsql-statements.test.ts b/drizzle-kit/tests/libsql-statements.test.ts index a7cbc0602..636496c45 100644 --- a/drizzle-kit/tests/libsql-statements.test.ts +++ b/drizzle-kit/tests/libsql-statements.test.ts @@ -917,7 +917,7 @@ test('set not null with index', async (t) => { expect(sqlStatements.length).toBe(3); expect(sqlStatements[0]).toBe( - `DROP INDEX IF EXISTS "users_name_index";`, + `DROP INDEX "users_name_index";`, ); expect(sqlStatements[1]).toBe( `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text NOT NULL;`, @@ -972,10 +972,10 @@ test('drop not null with two indexes', async (t) => { expect(sqlStatements.length).toBe(5); expect(sqlStatements[0]).toBe( - `DROP INDEX IF EXISTS "users_name_unique";`, + `DROP INDEX "users_name_unique";`, ); expect(sqlStatements[1]).toBe( - `DROP INDEX IF EXISTS "users_age_index";`, + `DROP INDEX "users_age_index";`, ); expect(sqlStatements[2]).toBe( `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`, diff --git a/drizzle-kit/tests/pg-checks.test.ts b/drizzle-kit/tests/pg-checks.test.ts index 50a01a6c1..8033aacef 100644 --- a/drizzle-kit/tests/pg-checks.test.ts +++ b/drizzle-kit/tests/pg-checks.test.ts @@ -44,7 +44,7 @@ test('create table with check', async (t) => { } as JsonCreateTableStatement); expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( + expect(sqlStatements[0]).toBe(`CREATE TABLE "users" ( \t"id" serial PRIMARY KEY NOT NULL, \t"age" integer, \tCONSTRAINT "some_check_name" CHECK ("users"."age" > 21) diff --git a/drizzle-kit/tests/pg-identity.test.ts b/drizzle-kit/tests/pg-identity.test.ts index 9f6ce8ba7..efb481da3 100644 --- a/drizzle-kit/tests/pg-identity.test.ts +++ b/drizzle-kit/tests/pg-identity.test.ts @@ -54,7 +54,7 @@ test('create table: identity always/by default - no params', async () => { }, ]); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1)\n);\n', + 'CREATE TABLE "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1)\n);\n', ]); }); @@ -95,7 +95,7 @@ test('create table: identity always/by default - few params', async () => { }, ]); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_seq" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1)\n);\n', + 'CREATE TABLE "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_seq" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1)\n);\n', ]); }); @@ -140,7 +140,7 @@ test('create table: identity always/by default - all params', async () => { }, ]); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_seq" INCREMENT BY 4 MINVALUE 3 MAXVALUE 1000 START WITH 3 CACHE 200)\n);\n', + 'CREATE TABLE "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "custom_seq" INCREMENT BY 4 MINVALUE 3 MAXVALUE 1000 START WITH 3 CACHE 200)\n);\n', ]); }); diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index 6ea6e472a..4ca01f1fe 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -261,7 +261,7 @@ test('add table #8: geometry types', async () => { expect(statements.length).toBe(1); expect(sqlStatements).toStrictEqual([ - `CREATE TABLE IF NOT EXISTS "users" (\n\t"geom" geometry(point) NOT NULL,\n\t"geom1" geometry(point) NOT NULL\n);\n`, + `CREATE TABLE "users" (\n\t"geom" geometry(point) NOT NULL,\n\t"geom1" geometry(point) NOT NULL\n);\n`, ]); }); @@ -360,7 +360,7 @@ test('add table #8: column with pgvector', async () => { const { sqlStatements } = await diffTestSchemas(from, to, []); expect(sqlStatements[0]).toBe( - `CREATE TABLE IF NOT EXISTS "users2" (\n\t"id" serial PRIMARY KEY NOT NULL,\n\t"name" vector(3)\n); + `CREATE TABLE "users2" (\n\t"id" serial PRIMARY KEY NOT NULL,\n\t"name" vector(3)\n); `, ); }); @@ -671,8 +671,8 @@ test('create table with tsvector', async () => { const { statements, sqlStatements } = await diffTestSchemas(from, to, []); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "posts" (\n\t"id" serial PRIMARY KEY NOT NULL,\n\t"title" text NOT NULL,\n\t"description" text NOT NULL\n);\n', - `CREATE INDEX IF NOT EXISTS "title_search_index" ON "posts" USING gin (to_tsvector('english', "title"));`, + 'CREATE TABLE "posts" (\n\t"id" serial PRIMARY KEY NOT NULL,\n\t"title" text NOT NULL,\n\t"description" text NOT NULL\n);\n', + `CREATE INDEX "title_search_index" ON "posts" USING gin (to_tsvector('english', "title"));`, ]); }); @@ -693,7 +693,7 @@ test('composite primary key', async () => { const { sqlStatements } = await diffTestSchemas(from, to, []); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "works_to_creators" (\n\t"work_id" integer NOT NULL,\n\t"creator_id" integer NOT NULL,\n\t"classification" text NOT NULL,\n\tCONSTRAINT "works_to_creators_work_id_creator_id_classification_pk" PRIMARY KEY("work_id","creator_id","classification")\n);\n', + 'CREATE TABLE "works_to_creators" (\n\t"work_id" integer NOT NULL,\n\t"creator_id" integer NOT NULL,\n\t"classification" text NOT NULL,\n\tCONSTRAINT "works_to_creators_work_id_creator_id_classification_pk" PRIMARY KEY("work_id","creator_id","classification")\n);\n', ]); }); @@ -772,7 +772,7 @@ test('add index with op', async () => { const { sqlStatements } = await diffTestSchemas(from, to, []); expect(sqlStatements).toStrictEqual([ - 'CREATE INDEX IF NOT EXISTS "users_name_index" ON "users" USING gin ("name" gin_trgm_ops);', + 'CREATE INDEX "users_name_index" ON "users" USING gin ("name" gin_trgm_ops);', ]); }); @@ -829,7 +829,7 @@ test('optional db aliases (snake case)', async () => { const { sqlStatements } = await diffTestSchemas(from, to, [], false, 'snake_case'); - const st1 = `CREATE TABLE IF NOT EXISTS "t1" ( + const st1 = `CREATE TABLE "t1" ( "t1_id1" integer PRIMARY KEY NOT NULL, "t1_col2" integer NOT NULL, "t1_col3" integer NOT NULL, @@ -841,35 +841,27 @@ test('optional db aliases (snake case)', async () => { ); `; - const st2 = `CREATE TABLE IF NOT EXISTS "t2" ( + const st2 = `CREATE TABLE "t2" ( "t2_id" serial PRIMARY KEY NOT NULL ); `; - const st3 = `CREATE TABLE IF NOT EXISTS "t3" ( + const st3 = `CREATE TABLE "t3" ( "t3_id1" integer, "t3_id2" integer, CONSTRAINT "t3_t3_id1_t3_id2_pk" PRIMARY KEY("t3_id1","t3_id2") ); `; - const st4 = `DO $$ BEGIN - ALTER TABLE "t1" ADD CONSTRAINT "t1_t2_ref_t2_t2_id_fk" FOREIGN KEY ("t2_ref") REFERENCES "public"."t2"("t2_id") ON DELETE no action ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; -`; + const st4 = + `ALTER TABLE "t1" ADD CONSTRAINT "t1_t2_ref_t2_t2_id_fk" FOREIGN KEY ("t2_ref") REFERENCES "public"."t2"("t2_id") ON DELETE no action ON UPDATE no action;`; - const st5 = `DO $$ BEGIN - ALTER TABLE "t1" ADD CONSTRAINT "t1_t1_col2_t1_col3_t3_t3_id1_t3_id2_fk" FOREIGN KEY ("t1_col2","t1_col3") REFERENCES "public"."t3"("t3_id1","t3_id2") ON DELETE no action ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; -`; + const st5 = + `ALTER TABLE "t1" ADD CONSTRAINT "t1_t1_col2_t1_col3_t3_t3_id1_t3_id2_fk" FOREIGN KEY ("t1_col2","t1_col3") REFERENCES "public"."t3"("t3_id1","t3_id2") ON DELETE no action ON UPDATE no action;`; - const st6 = `CREATE UNIQUE INDEX IF NOT EXISTS "t1_uni_idx" ON "t1" USING btree ("t1_uni_idx");`; + const st6 = `CREATE UNIQUE INDEX "t1_uni_idx" ON "t1" USING btree ("t1_uni_idx");`; - const st7 = `CREATE INDEX IF NOT EXISTS "t1_idx" ON "t1" USING btree ("t1_idx") WHERE "t1"."t1_idx" > 0;`; + const st7 = `CREATE INDEX "t1_idx" ON "t1" USING btree ("t1_idx") WHERE "t1"."t1_idx" > 0;`; expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6, st7]); }); @@ -927,7 +919,7 @@ test('optional db aliases (camel case)', async () => { const { sqlStatements } = await diffTestSchemas(from, to, [], false, 'camelCase'); - const st1 = `CREATE TABLE IF NOT EXISTS "t1" ( + const st1 = `CREATE TABLE "t1" ( "t1Id1" integer PRIMARY KEY NOT NULL, "t1Col2" integer NOT NULL, "t1Col3" integer NOT NULL, @@ -939,35 +931,27 @@ test('optional db aliases (camel case)', async () => { ); `; - const st2 = `CREATE TABLE IF NOT EXISTS "t2" ( + const st2 = `CREATE TABLE "t2" ( "t2Id" serial PRIMARY KEY NOT NULL ); `; - const st3 = `CREATE TABLE IF NOT EXISTS "t3" ( + const st3 = `CREATE TABLE "t3" ( "t3Id1" integer, "t3Id2" integer, CONSTRAINT "t3_t3Id1_t3Id2_pk" PRIMARY KEY("t3Id1","t3Id2") ); `; - const st4 = `DO $$ BEGIN - ALTER TABLE "t1" ADD CONSTRAINT "t1_t2Ref_t2_t2Id_fk" FOREIGN KEY ("t2Ref") REFERENCES "public"."t2"("t2Id") ON DELETE no action ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; -`; + const st4 = + `ALTER TABLE "t1" ADD CONSTRAINT "t1_t2Ref_t2_t2Id_fk" FOREIGN KEY ("t2Ref") REFERENCES "public"."t2"("t2Id") ON DELETE no action ON UPDATE no action;`; - const st5 = `DO $$ BEGIN - ALTER TABLE "t1" ADD CONSTRAINT "t1_t1Col2_t1Col3_t3_t3Id1_t3Id2_fk" FOREIGN KEY ("t1Col2","t1Col3") REFERENCES "public"."t3"("t3Id1","t3Id2") ON DELETE no action ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; -`; + const st5 = + `ALTER TABLE "t1" ADD CONSTRAINT "t1_t1Col2_t1Col3_t3_t3Id1_t3Id2_fk" FOREIGN KEY ("t1Col2","t1Col3") REFERENCES "public"."t3"("t3Id1","t3Id2") ON DELETE no action ON UPDATE no action;`; - const st6 = `CREATE UNIQUE INDEX IF NOT EXISTS "t1UniIdx" ON "t1" USING btree ("t1UniIdx");`; + const st6 = `CREATE UNIQUE INDEX "t1UniIdx" ON "t1" USING btree ("t1UniIdx");`; - const st7 = `CREATE INDEX IF NOT EXISTS "t1Idx" ON "t1" USING btree ("t1Idx") WHERE "t1"."t1Idx" > 0;`; + const st7 = `CREATE INDEX "t1Idx" ON "t1" USING btree ("t1Idx") WHERE "t1"."t1Idx" > 0;`; expect(sqlStatements).toStrictEqual([st1, st2, st3, st4, st5, st6, st7]); }); diff --git a/drizzle-kit/tests/pg-views.test.ts b/drizzle-kit/tests/pg-views.test.ts index 002004c47..4f24cd776 100644 --- a/drizzle-kit/tests/pg-views.test.ts +++ b/drizzle-kit/tests/pg-views.test.ts @@ -45,7 +45,7 @@ test('create table and view #1', async () => { }); expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( + expect(sqlStatements[0]).toBe(`CREATE TABLE "users" ( \t"id" integer PRIMARY KEY NOT NULL );\n`); expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (select "id" from "users");`); @@ -93,7 +93,7 @@ test('create table and view #2', async () => { }); expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( + expect(sqlStatements[0]).toBe(`CREATE TABLE "users" ( \t"id" integer PRIMARY KEY NOT NULL );\n`); expect(sqlStatements[1]).toBe(`CREATE VIEW "public"."some_view" AS (SELECT * FROM "users");`); @@ -169,7 +169,7 @@ test('create table and view #3', async () => { }); expect(sqlStatements.length).toBe(3); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( + expect(sqlStatements[0]).toBe(`CREATE TABLE "users" ( \t"id" integer PRIMARY KEY NOT NULL );\n`); expect(sqlStatements[1]).toBe( @@ -258,7 +258,7 @@ test('create table and view #4', async () => { expect(sqlStatements.length).toBe(4); expect(sqlStatements[0]).toBe(`CREATE SCHEMA "new_schema";\n`); - expect(sqlStatements[1]).toBe(`CREATE TABLE IF NOT EXISTS "new_schema"."users" ( + expect(sqlStatements[1]).toBe(`CREATE TABLE "new_schema"."users" ( \t"id" integer PRIMARY KEY NOT NULL );\n`); expect(sqlStatements[2]).toBe( @@ -328,7 +328,7 @@ test('create table and view #6', async () => { }); expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( + expect(sqlStatements[0]).toBe(`CREATE TABLE "users" ( \t"id" integer PRIMARY KEY NOT NULL );\n`); expect(sqlStatements[1]).toBe( @@ -398,7 +398,7 @@ test('create table and materialized view #1', async () => { }); expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( + expect(sqlStatements[0]).toBe(`CREATE TABLE "users" ( \t"id" integer PRIMARY KEY NOT NULL );\n`); expect(sqlStatements[1]).toBe(`CREATE MATERIALIZED VIEW "public"."some_view" AS (select "id" from "users");`); @@ -446,7 +446,7 @@ test('create table and materialized view #2', async () => { }); expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( + expect(sqlStatements[0]).toBe(`CREATE TABLE "users" ( \t"id" integer PRIMARY KEY NOT NULL );\n`); expect(sqlStatements[1]).toBe(`CREATE MATERIALIZED VIEW "public"."some_view" AS (SELECT * FROM "users");`); @@ -544,7 +544,7 @@ test('create table and materialized view #3', async () => { }); expect(sqlStatements.length).toBe(3); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( + expect(sqlStatements[0]).toBe(`CREATE TABLE "users" ( \t"id" integer PRIMARY KEY NOT NULL );\n`); expect(sqlStatements[1]).toBe( @@ -617,7 +617,7 @@ test('create table and materialized view #5', async () => { }); expect(sqlStatements.length).toBe(2); - expect(sqlStatements[0]).toBe(`CREATE TABLE IF NOT EXISTS "users" ( + expect(sqlStatements[0]).toBe(`CREATE TABLE "users" ( \t"id" integer PRIMARY KEY NOT NULL );\n`); expect(sqlStatements[1]).toBe( diff --git a/drizzle-kit/tests/push/libsql.test.ts b/drizzle-kit/tests/push/libsql.test.ts index 460809d9e..2ae2e3811 100644 --- a/drizzle-kit/tests/push/libsql.test.ts +++ b/drizzle-kit/tests/push/libsql.test.ts @@ -185,7 +185,7 @@ test('added, dropped index', async (t) => { expect(sqlStatements.length).toBe(2); expect(sqlStatements[0]).toBe( - `DROP INDEX IF EXISTS \`customers_address_unique\`;`, + `DROP INDEX \`customers_address_unique\`;`, ); expect(sqlStatements[1]).toBe( `CREATE UNIQUE INDEX \`customers_is_confirmed_unique\` ON \`customers\` (\`is_confirmed\`);`, @@ -963,7 +963,7 @@ test('set not null with index', async (t) => { expect(sqlStatements.length).toBe(3); expect(sqlStatements[0]).toBe( - `DROP INDEX IF EXISTS "users_name_index";`, + `DROP INDEX "users_name_index";`, ); expect(sqlStatements[1]).toBe( `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text NOT NULL;`, @@ -1035,10 +1035,10 @@ test('drop not null with two indexes', async (t) => { expect(sqlStatements.length).toBe(5); expect(sqlStatements[0]).toBe( - `DROP INDEX IF EXISTS "users_name_unique";`, + `DROP INDEX "users_name_unique";`, ); expect(sqlStatements[1]).toBe( - `DROP INDEX IF EXISTS "users_age_index";`, + `DROP INDEX "users_age_index";`, ); expect(sqlStatements[2]).toBe( `ALTER TABLE \`users\` ALTER COLUMN "name" TO "name" text;`, diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 44ec786b6..a7bed413d 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -318,10 +318,10 @@ const pgSuite: DialectSuite = { }); expect(sqlStatements.length).toBe(2); expect(sqlStatements[0]).toBe( - `CREATE INDEX IF NOT EXISTS "users_name_id_index" ON "users" USING btree ("name" DESC NULLS LAST,"id") WITH (fillfactor=70) WHERE select 1;`, + `CREATE INDEX "users_name_id_index" ON "users" USING btree ("name" DESC NULLS LAST,"id") WITH (fillfactor=70) WHERE select 1;`, ); expect(sqlStatements[1]).toBe( - `CREATE INDEX IF NOT EXISTS "indx1" ON "users" USING hash ("name" DESC NULLS LAST,"name") WITH (fillfactor=70);`, + `CREATE INDEX "indx1" ON "users" USING hash ("name" DESC NULLS LAST,"name") WITH (fillfactor=70);`, ); }, @@ -547,7 +547,7 @@ const pgSuite: DialectSuite = { }, ]); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer,\n\t"id2" integer,\n\t"name" text,\n\t"gen_name" text GENERATED ALWAYS AS ("users"."name" || \'hello\') STORED\n);\n', + 'CREATE TABLE "users" (\n\t"id" integer,\n\t"id2" integer,\n\t"name" text,\n\t"gen_name" text GENERATED ALWAYS AS ("users"."name" || \'hello\') STORED\n);\n', ]); }, @@ -616,20 +616,20 @@ const pgSuite: DialectSuite = { const { statements, sqlStatements } = await diffTestSchemasPush(client, schema1, schema2, [], false, ['public']); expect(sqlStatements).toStrictEqual([ - 'DROP INDEX IF EXISTS "changeName";', - 'DROP INDEX IF EXISTS "addColumn";', - 'DROP INDEX IF EXISTS "changeExpression";', - 'DROP INDEX IF EXISTS "changeUsing";', - 'DROP INDEX IF EXISTS "changeWith";', - 'DROP INDEX IF EXISTS "removeColumn";', - 'DROP INDEX IF EXISTS "removeExpression";', - 'CREATE INDEX IF NOT EXISTS "newName" ON "users" USING btree ("name" DESC NULLS LAST,name) WITH (fillfactor=70);', - 'CREATE INDEX IF NOT EXISTS "addColumn" ON "users" USING btree ("name" DESC NULLS LAST,"id") WITH (fillfactor=70);', - 'CREATE INDEX IF NOT EXISTS "changeExpression" ON "users" USING btree ("id" DESC NULLS LAST,name desc);', - 'CREATE INDEX IF NOT EXISTS "changeUsing" ON "users" USING hash ("name");', - 'CREATE INDEX IF NOT EXISTS "changeWith" ON "users" USING btree ("name") WITH (fillfactor=90);', - 'CREATE INDEX IF NOT EXISTS "removeColumn" ON "users" USING btree ("name");', - 'CREATE INDEX CONCURRENTLY IF NOT EXISTS "removeExpression" ON "users" USING btree ("name" DESC NULLS LAST);', + 'DROP INDEX "changeName";', + 'DROP INDEX "addColumn";', + 'DROP INDEX "changeExpression";', + 'DROP INDEX "changeUsing";', + 'DROP INDEX "changeWith";', + 'DROP INDEX "removeColumn";', + 'DROP INDEX "removeExpression";', + 'CREATE INDEX "newName" ON "users" USING btree ("name" DESC NULLS LAST,name) WITH (fillfactor=70);', + 'CREATE INDEX "addColumn" ON "users" USING btree ("name" DESC NULLS LAST,"id") WITH (fillfactor=70);', + 'CREATE INDEX "changeExpression" ON "users" USING btree ("id" DESC NULLS LAST,name desc);', + 'CREATE INDEX "changeUsing" ON "users" USING hash ("name");', + 'CREATE INDEX "changeWith" ON "users" USING btree ("name") WITH (fillfactor=90);', + 'CREATE INDEX "removeColumn" ON "users" USING btree ("name");', + 'CREATE INDEX CONCURRENTLY "removeExpression" ON "users" USING btree ("name" DESC NULLS LAST);', ]); }, @@ -667,7 +667,7 @@ const pgSuite: DialectSuite = { }); expect(sqlStatements.length).toBe(1); - expect(sqlStatements[0]).toBe(`DROP INDEX IF EXISTS "users_name_id_index";`); + expect(sqlStatements[0]).toBe(`DROP INDEX "users_name_id_index";`); }, async indexesToBeNotTriggered() { @@ -958,7 +958,7 @@ const pgSuite: DialectSuite = { }, ]); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "table" (\n\t"col1" integer NOT NULL,\n\t"col2" integer NOT NULL,\n\tCONSTRAINT "table_col1_col2_pk" PRIMARY KEY("col1","col2")\n);\n', + 'CREATE TABLE "table" (\n\t"col1" integer NOT NULL,\n\t"col2" integer NOT NULL,\n\tCONSTRAINT "table_col1_col2_pk" PRIMARY KEY("col1","col2")\n);\n', ]); }, @@ -1304,7 +1304,7 @@ test('create table: identity always/by default - no params', async () => { }, ]); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1)\n);\n', + 'CREATE TABLE "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1)\n);\n', ]); for (const st of sqlStatements) { @@ -1367,7 +1367,7 @@ test('create table: identity always/by default - few params', async () => { }, ]); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', + 'CREATE TABLE "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 1),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', ]); for (const st of sqlStatements) { @@ -1436,7 +1436,7 @@ test('create table: identity always/by default - all params', async () => { }, ]); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 100 MAXVALUE 2147483647 START WITH 100 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 3 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 100 CYCLE),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', + 'CREATE TABLE "users" (\n\t"id" integer GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 4 MINVALUE 100 MAXVALUE 2147483647 START WITH 100 CACHE 1),\n\t"id1" bigint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id1_seq" INCREMENT BY 3 MINVALUE 1 MAXVALUE 17000 START WITH 120 CACHE 100 CYCLE),\n\t"id2" smallint GENERATED BY DEFAULT AS IDENTITY (sequence name "users_id2_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 32767 START WITH 1 CACHE 1 CYCLE)\n);\n', ]); for (const st of sqlStatements) { @@ -2258,7 +2258,7 @@ test('Column with same name as enum', async () => { }, ]); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "table2" (\n\t"id" serial PRIMARY KEY NOT NULL,\n\t"status" "status" DEFAULT \'inactive\'\n);\n', + 'CREATE TABLE "table2" (\n\t"id" serial PRIMARY KEY NOT NULL,\n\t"status" "status" DEFAULT \'inactive\'\n);\n', 'ALTER TABLE "table1" ADD COLUMN "status" "status" DEFAULT \'inactive\';', ]); }); @@ -3591,7 +3591,7 @@ test('create table with a policy', async (t) => { ); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users2" (\n\t"id" integer PRIMARY KEY NOT NULL\n);\n', + 'CREATE TABLE "users2" (\n\t"id" integer PRIMARY KEY NOT NULL\n);\n', 'ALTER TABLE "users2" ENABLE ROW LEVEL SECURITY;', 'CREATE POLICY "test" ON "users2" AS PERMISSIVE FOR ALL TO public;', ]); diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index dd1d88fe3..e2c85233a 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -185,7 +185,7 @@ test('dropped, added unique index', async (t) => { expect(sqlStatements.length).toBe(2); expect(sqlStatements[0]).toBe( - `DROP INDEX IF EXISTS \`customers_address_unique\`;`, + `DROP INDEX \`customers_address_unique\`;`, ); expect(sqlStatements[1]).toBe( `CREATE UNIQUE INDEX \`customers_is_confirmed_unique\` ON \`customers\` (\`is_confirmed\`);`, diff --git a/drizzle-kit/tests/rls/pg-policy.test.ts b/drizzle-kit/tests/rls/pg-policy.test.ts index b42385e3e..3d5dcbd14 100644 --- a/drizzle-kit/tests/rls/pg-policy.test.ts +++ b/drizzle-kit/tests/rls/pg-policy.test.ts @@ -587,7 +587,7 @@ test('create table with a policy', async (t) => { const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); expect(sqlStatements).toStrictEqual([ - 'CREATE TABLE IF NOT EXISTS "users2" (\n\t"id" integer PRIMARY KEY NOT NULL\n);\n', + 'CREATE TABLE "users2" (\n\t"id" integer PRIMARY KEY NOT NULL\n);\n', 'ALTER TABLE "users2" ENABLE ROW LEVEL SECURITY;', 'CREATE POLICY "test" ON "users2" AS PERMISSIVE FOR ALL TO public;', ]); @@ -720,12 +720,10 @@ test('create table with rls enabled', async (t) => { const { statements, sqlStatements } = await diffTestSchemas(schema1, schema2, []); expect(sqlStatements).toStrictEqual([ - `CREATE TABLE IF NOT EXISTS "users" (\n\t"id" integer PRIMARY KEY NOT NULL\n); + `CREATE TABLE "users" (\n\t"id" integer PRIMARY KEY NOT NULL\n); `, 'ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;', ]); - - console.log(statements); }); test('enable rls force', async (t) => { From 167496a3ab82c66fcd255d7db15dd8ecc83d9658 Mon Sep 17 00:00:00 2001 From: Oleksii Provorov Date: Thu, 5 Dec 2024 18:04:05 +0200 Subject: [PATCH 418/492] Updated: - Added onIndex config for select.from() and all joins - Added mysql-common tests for onIndex config usage - In mysql-custom.test.ts removed deprecated placeholder and use sql.placeholder instead --- drizzle-orm/src/mysql-core/dialect.ts | 30 +- .../src/mysql-core/query-builders/select.ts | 98 ++++- .../mysql-core/query-builders/select.types.ts | 9 +- drizzle-orm/src/mysql-core/utils.ts | 18 + integration-tests/tests/mysql/mysql-common.ts | 340 ++++++++++++++++++ .../tests/mysql/mysql-custom.test.ts | 6 +- 6 files changed, 492 insertions(+), 9 deletions(-) diff --git a/drizzle-orm/src/mysql-core/dialect.ts b/drizzle-orm/src/mysql-core/dialect.ts index e01888636..8661359ab 100644 --- a/drizzle-orm/src/mysql-core/dialect.ts +++ b/drizzle-orm/src/mysql-core/dialect.ts @@ -244,6 +244,18 @@ export class MySqlDialect { return orderBy && orderBy.length > 0 ? sql` order by ${sql.join(orderBy, sql`, `)}` : undefined; } + private buildIndex({ + indexes, + indexFor, + }: { + indexes: string[] | undefined; + indexFor: 'USE' | 'FORCE' | 'IGNORE'; + }): SQL | undefined { + return indexes && indexes.length > 0 + ? sql` ${sql.raw(indexFor)} INDEX (${sql.raw(indexes.join(`, `))})` + : undefined; + } + buildSelectQuery( { withList, @@ -260,6 +272,9 @@ export class MySqlDialect { lockingClause, distinct, setOperators, + useIndex, + forceIndex, + ignoreIndex, }: MySqlSelectConfig, ): SQL { const fieldsList = fieldsFlat ?? orderSelectedFields(fields); @@ -319,10 +334,15 @@ export class MySqlDialect { const tableSchema = table[MySqlTable.Symbol.Schema]; const origTableName = table[MySqlTable.Symbol.OriginalName]; const alias = tableName === origTableName ? undefined : joinMeta.alias; + const useIndexSql = this.buildIndex({ indexes: joinMeta.useIndex, indexFor: 'USE' }); + const forceIndexSql = this.buildIndex({ indexes: joinMeta.forceIndex, indexFor: 'FORCE' }); + const ignoreIndexSql = this.buildIndex({ indexes: joinMeta.ignoreIndex, indexFor: 'IGNORE' }); joinsArray.push( sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${ tableSchema ? sql`${sql.identifier(tableSchema)}.` : undefined - }${sql.identifier(origTableName)}${alias && sql` ${sql.identifier(alias)}`} on ${joinMeta.on}`, + }${sql.identifier(origTableName)}${useIndexSql}${forceIndexSql}${ignoreIndexSql}${ + alias && sql` ${sql.identifier(alias)}` + } on ${joinMeta.on}`, ); } else if (is(table, View)) { const viewName = table[ViewBaseConfig].name; @@ -359,6 +379,12 @@ export class MySqlDialect { const offsetSql = offset ? sql` offset ${offset}` : undefined; + const useIndexSql = this.buildIndex({ indexes: useIndex, indexFor: 'USE' }); + + const forceIndexSql = this.buildIndex({ indexes: forceIndex, indexFor: 'FORCE' }); + + const ignoreIndexSql = this.buildIndex({ indexes: ignoreIndex, indexFor: 'IGNORE' }); + let lockingClausesSql; if (lockingClause) { const { config, strength } = lockingClause; @@ -371,7 +397,7 @@ export class MySqlDialect { } const finalQuery = - sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`; + sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${useIndexSql}${forceIndexSql}${ignoreIndexSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`; if (setOperators.length > 0) { return this.buildSetOperations(finalQuery, setOperators); diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index 63c4b903e..ac5c64b64 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -3,7 +3,7 @@ import type { MySqlColumn } from '~/mysql-core/columns/index.ts'; import type { MySqlDialect } from '~/mysql-core/dialect.ts'; import type { MySqlPreparedQueryConfig, MySqlSession, PreparedQueryHKTBase } from '~/mysql-core/session.ts'; import type { SubqueryWithSelection } from '~/mysql-core/subquery.ts'; -import type { MySqlTable } from '~/mysql-core/table.ts'; +import { MySqlTable } from '~/mysql-core/table.ts'; import { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { BuildSubquerySelection, @@ -24,6 +24,9 @@ import { Table } from '~/table.ts'; import { applyMixins, getTableColumns, getTableLikeName, haveSameKeys, type ValueOrArray } from '~/utils.ts'; import { orderSelectedFields } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; +import type { IndexBuilder } from '../indexes.ts'; +import type { UniqueConstraintBuilder } from '../unique-constraint.ts'; +import { convertIndexToString } from '../utils.ts'; import { MySqlViewBase } from '../view-base.ts'; import type { AnyMySqlSelect, @@ -45,6 +48,14 @@ import type { SetOperatorRightSelect, } from './select.types.ts'; +type Index = UniqueConstraintBuilder | IndexBuilder | string; + +export type IndexConfig = { + useIndex?: Index[]; + forceIndex?: Index[]; + ignoreIndex?: Index[]; +}; + export class MySqlSelectBuilder< TSelection extends SelectedFields | undefined, TPreparedQueryHKT extends PreparedQueryHKTBase, @@ -78,6 +89,7 @@ export class MySqlSelectBuilder< from( source: TFrom, + onIndex?: IndexConfig, ): CreateMySqlSelectFromBuilderMode< TBuilderMode, GetSelectTableName, @@ -105,6 +117,21 @@ export class MySqlSelectBuilder< fields = getTableColumns(source); } + let useIndex: string[] = []; + let forceIndex: string[] = []; + let ignoreIndex: string[] = []; + if (is(source, MySqlTable) && onIndex) { + if (onIndex.useIndex) { + useIndex = convertIndexToString({ table: source, indexes: onIndex.useIndex }); + } + if (onIndex.forceIndex) { + forceIndex = convertIndexToString({ table: source, indexes: onIndex.forceIndex }); + } + if (onIndex.ignoreIndex) { + ignoreIndex = convertIndexToString({ table: source, indexes: onIndex.ignoreIndex! }); + } + } + return new MySqlSelectBase( { table: source, @@ -114,6 +141,9 @@ export class MySqlSelectBuilder< dialect: this.dialect, withList: this.withList, distinct: this.distinct, + useIndex, + forceIndex, + ignoreIndex, }, ) as any; } @@ -156,7 +186,7 @@ export abstract class MySqlSelectQueryBuilderBase< protected dialect: MySqlDialect; constructor( - { table, fields, isPartialSelect, session, dialect, withList, distinct }: { + { table, fields, isPartialSelect, session, dialect, withList, distinct, useIndex, forceIndex, ignoreIndex }: { table: MySqlSelectConfig['table']; fields: MySqlSelectConfig['fields']; isPartialSelect: boolean; @@ -164,6 +194,9 @@ export abstract class MySqlSelectQueryBuilderBase< dialect: MySqlDialect; withList: Subquery[]; distinct: boolean | undefined; + useIndex?: string[]; + forceIndex?: string[]; + ignoreIndex?: string[]; }, ) { super(); @@ -173,6 +206,9 @@ export abstract class MySqlSelectQueryBuilderBase< fields: { ...fields }, distinct, setOperators: [], + useIndex, + forceIndex, + ignoreIndex, }; this.isPartialSelect = isPartialSelect; this.session = session; @@ -190,6 +226,7 @@ export abstract class MySqlSelectQueryBuilderBase< return ( table: MySqlTable | Subquery | MySqlViewBase | SQL, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, + onIndex?: IndexConfig, ) => { const baseTableName = this.tableName; const tableName = getTableLikeName(table); @@ -228,7 +265,22 @@ export abstract class MySqlSelectQueryBuilderBase< this.config.joins = []; } - this.config.joins.push({ on, table, joinType, alias: tableName }); + let useIndex: string[] = []; + let forceIndex: string[] = []; + let ignoreIndex: string[] = []; + if (is(table, MySqlTable) && onIndex) { + if (onIndex.useIndex) { + useIndex = convertIndexToString({ table, indexes: onIndex.useIndex }); + } + if (onIndex.forceIndex) { + forceIndex = convertIndexToString({ table, indexes: onIndex.forceIndex }); + } + if (onIndex.ignoreIndex) { + ignoreIndex = convertIndexToString({ table, indexes: onIndex.ignoreIndex! }); + } + } + + this.config.joins.push({ on, table, joinType, alias: tableName, useIndex, forceIndex, ignoreIndex }); if (typeof tableName === 'string') { switch (joinType) { @@ -286,6 +338,16 @@ export abstract class MySqlSelectQueryBuilderBase< * }) * .from(users) * .leftJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId with use index hint + * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId), { + * useIndex: ['pets_owner_id_index'] + * }) * ``` */ leftJoin = this.createJoin('left'); @@ -315,6 +377,16 @@ export abstract class MySqlSelectQueryBuilderBase< * }) * .from(users) * .rightJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId with use index hint + * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId), { + * useIndex: ['pets_owner_id_index'] + * }) * ``` */ rightJoin = this.createJoin('right'); @@ -344,6 +416,16 @@ export abstract class MySqlSelectQueryBuilderBase< * }) * .from(users) * .innerJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId with use index hint + * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId), { + * useIndex: ['pets_owner_id_index'] + * }) * ``` */ innerJoin = this.createJoin('inner'); @@ -373,6 +455,16 @@ export abstract class MySqlSelectQueryBuilderBase< * }) * .from(users) * .fullJoin(pets, eq(users.id, pets.ownerId)) + * + * // Select userId and petId with use index hint + * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({ + * userId: users.id, + * petId: pets.id, + * }) + * .from(users) + * .leftJoin(pets, eq(users.id, pets.ownerId), { + * useIndex: ['pets_owner_id_index'] + * }) * ``` */ fullJoin = this.createJoin('full'); diff --git a/drizzle-orm/src/mysql-core/query-builders/select.types.ts b/drizzle-orm/src/mysql-core/query-builders/select.types.ts index 5f490a2d9..50abe63cb 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.types.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.types.ts @@ -25,7 +25,7 @@ import type { Assume, ValidateShape } from '~/utils.ts'; import type { MySqlPreparedQueryConfig, PreparedQueryHKTBase, PreparedQueryKind } from '../session.ts'; import type { MySqlViewBase } from '../view-base.ts'; import type { MySqlViewWithSelection } from '../view.ts'; -import type { MySqlSelectBase, MySqlSelectQueryBuilderBase } from './select.ts'; +import type { IndexConfig, MySqlSelectBase, MySqlSelectQueryBuilderBase } from './select.ts'; export interface MySqlSelectJoinConfig { on: SQL | undefined; @@ -33,6 +33,9 @@ export interface MySqlSelectJoinConfig { alias: string | undefined; joinType: JoinType; lateral?: boolean; + useIndex?: string[]; + forceIndex?: string[]; + ignoreIndex?: string[]; } export type BuildAliasTable = TTable extends Table @@ -74,6 +77,9 @@ export interface MySqlSelectConfig { limit?: number | Placeholder; offset?: number | Placeholder; }[]; + useIndex?: string[]; + forceIndex?: string[]; + ignoreIndex?: string[]; } export type MySqlJoin< @@ -116,6 +122,7 @@ export type MySqlJoinFn< >( table: TJoinedTable, on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, + onIndex?: IndexConfig, ) => MySqlJoin; export type SelectedFieldsFlat = SelectedFieldsFlatBase; diff --git a/drizzle-orm/src/mysql-core/utils.ts b/drizzle-orm/src/mysql-core/utils.ts index f09f65f3e..8ca117120 100644 --- a/drizzle-orm/src/mysql-core/utils.ts +++ b/drizzle-orm/src/mysql-core/utils.ts @@ -66,3 +66,21 @@ export function getViewConfig< ...view[MySqlViewConfig], }; } + +export function convertIndexToString({ + table, + indexes, +}: { + table: MySqlTable; + indexes: (UniqueConstraintBuilder | IndexBuilder | string)[]; +}) { + return indexes.map((idx) => { + if (typeof idx === 'object') { + return is(idx, UniqueConstraintBuilder) + ? idx.build(table).getName()! + : idx.config.name; + } else { + return idx; + } + }); +} diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index a2a0baeb0..766d7de7b 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -37,6 +37,7 @@ import { foreignKey, getTableConfig, getViewConfig, + index, int, intersect, intersectAll, @@ -4100,4 +4101,343 @@ export function tests(driver?: string) { ), ).toThrowError(); }); + + test('select with `use index` hint', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + }, () => { + return { + usersTableNameIndex, + }; + }); + const usersTableNameIndex = index('users_name_index').on(users.name); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql`create index users_name_index ON users(name)`); + + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + const result = await db.select() + .from(users, { + useIndex: [usersTableNameIndex], + }) + .where(eq(users.name, 'David')); + + expect(result).toHaveLength(1); + expect(result).toEqual([{ id: 4, name: 'David' }]); + }); + + test('select with `use index` hint on not existed index', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + }, () => { + return { + usersTableNameIndex, + }; + }); + const usersTableNameIndex = index('users_name_index').on(users.name); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql`create index users_name_index ON users(name)`); + + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + await expect((async () => { + return await db.select() + .from(users, { + useIndex: ['some_other_index'], + }) + .where(eq(users.name, 'David')); + })()).rejects.toThrowError(); + }); + + test('select with `use index` + `force index` incompatible hints', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + age: int('age').notNull(), + }, () => { + return { + usersTableNameIndex, + usersTableAgeIndex, + }; + }); + const usersTableNameIndex = index('users_name_index').on(users.name); + const usersTableAgeIndex = index('users_age_index').on(users.age); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null, + \`age\` int not null + ) + `); + await db.execute(sql`create index users_name_index ON users(name)`); + await db.execute(sql`create index users_age_index ON users(age)`); + + await db.insert(users).values([ + { name: 'Alice', age: 18 }, + { name: 'Bob', age: 19 }, + { name: 'Charlie', age: 20 }, + { name: 'David', age: 21 }, + { name: 'Eve', age: 22 }, + ]); + + await expect((async () => { + return await db.select() + .from(users, { + useIndex: [usersTableNameIndex], + forceIndex: [usersTableAgeIndex], + }) + .where(eq(users.name, 'David')); + })()).rejects.toThrowError(); + }); + + test('select with join `use index` hint', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + }); + + const posts = mysqlTable('posts', { + id: serial('id').primaryKey(), + text: varchar('text', { length: 100 }).notNull(), + userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), + }, () => { + return { + postsTableUserIdIndex, + }; + }); + const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); + + await db.execute(sql`drop table if exists ${posts}`); + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql` + create table ${posts} ( + \`id\` serial primary key, + \`text\` varchar(100) not null, + \`user_id\` int not null references users(id) on delete cascade + ) + `); + await db.execute(sql`create index posts_user_id_index ON posts(user_id)`); + + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + await db.insert(posts).values([ + { text: 'Alice post', userId: 1 }, + { text: 'Bob post', userId: 2 }, + { text: 'Charlie post', userId: 3 }, + { text: 'David post', userId: 4 }, + { text: 'Eve post', userId: 5 }, + ]); + + const result = await db.select({ + userId: users.id, + name: users.name, + postId: posts.id, + text: posts.text, + }) + .from(users) + .leftJoin(posts, eq(users.id, posts.userId), { + useIndex: [postsTableUserIdIndex], + }) + .where(and( + eq(users.name, 'David'), + eq(posts.text, 'David post'), + )); + + expect(result).toHaveLength(1); + expect(result).toEqual([{ userId: 4, name: 'David', postId: 4, text: 'David post' }]); + }); + + test('select with join `use index` hint on not existed index', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + }); + + const posts = mysqlTable('posts', { + id: serial('id').primaryKey(), + text: varchar('text', { length: 100 }).notNull(), + userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), + }, () => { + return { + postsTableUserIdIndex, + }; + }); + const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); + + await db.execute(sql`drop table if exists ${posts}`); + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql` + create table ${posts} ( + \`id\` serial primary key, + \`text\` varchar(100) not null, + \`user_id\` int not null references users(id) on delete cascade + ) + `); + await db.execute(sql`create index posts_user_id_index ON posts(user_id)`); + + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + await db.insert(posts).values([ + { text: 'Alice post', userId: 1 }, + { text: 'Bob post', userId: 2 }, + { text: 'Charlie post', userId: 3 }, + { text: 'David post', userId: 4 }, + { text: 'Eve post', userId: 5 }, + ]); + + await expect((async () => { + return await db.select({ + userId: users.id, + name: users.name, + postId: posts.id, + text: posts.text, + }) + .from(users) + .leftJoin(posts, eq(users.id, posts.userId), { + useIndex: ['some_other_index'], + }) + .where(and( + eq(users.name, 'David'), + eq(posts.text, 'David post'), + )); + })()).rejects.toThrowError(); + }); + + test('select with join `use index` + `force index` incompatible hints', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + }); + + const posts = mysqlTable('posts', { + id: serial('id').primaryKey(), + text: varchar('text', { length: 100 }).notNull(), + userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), + }, () => { + return { + postsTableUserIdIndex, + postsTableTextIndex, + }; + }); + const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); + const postsTableTextIndex = index('posts_text_index').on(posts.text); + + await db.execute(sql`drop table if exists ${posts}`); + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql` + create table ${posts} ( + \`id\` serial primary key, + \`text\` varchar(100) not null, + \`user_id\` int not null references users(id) on delete cascade + ) + `); + await db.execute(sql`create index posts_user_id_index ON posts(user_id)`); + await db.execute(sql`create index posts_text_index ON posts(text)`); + + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + await db.insert(posts).values([ + { text: 'Alice post', userId: 1 }, + { text: 'Bob post', userId: 2 }, + { text: 'Charlie post', userId: 3 }, + { text: 'David post', userId: 4 }, + { text: 'Eve post', userId: 5 }, + ]); + + await expect((async () => { + return await db.select({ + userId: users.id, + name: users.name, + postId: posts.id, + text: posts.text, + }) + .from(users) + .leftJoin(posts, eq(users.id, posts.userId), { + useIndex: [postsTableUserIdIndex], + forceIndex: [postsTableTextIndex], + }) + .where(and( + eq(users.name, 'David'), + eq(posts.text, 'David post'), + )); + })()).rejects.toThrowError(); + }); } diff --git a/integration-tests/tests/mysql/mysql-custom.test.ts b/integration-tests/tests/mysql/mysql-custom.test.ts index f1ed8e8e7..3dafc34d1 100644 --- a/integration-tests/tests/mysql/mysql-custom.test.ts +++ b/integration-tests/tests/mysql/mysql-custom.test.ts @@ -1,6 +1,6 @@ import retry from 'async-retry'; import type Docker from 'dockerode'; -import { asc, eq, Name, placeholder, sql } from 'drizzle-orm'; +import { asc, eq, Name, sql } from 'drizzle-orm'; import { alias, binary, @@ -646,7 +646,7 @@ test('prepared statement reuse', async (ctx) => { const stmt = db.insert(usersTable).values({ verified: true, - name: placeholder('name'), + name: sql.placeholder('name'), }).prepare(); for (let i = 0; i < 10; i++) { @@ -681,7 +681,7 @@ test('prepared statement with placeholder in .where', async (ctx) => { id: usersTable.id, name: usersTable.name, }).from(usersTable) - .where(eq(usersTable.id, placeholder('id'))) + .where(eq(usersTable.id, sql.placeholder('id'))) .prepare(); const result = await stmt.execute({ id: 1 }); From b86b9c37702fcbdf4c9f99476703d11476315f4a Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Fri, 6 Dec 2024 12:22:51 +0200 Subject: [PATCH 419/492] seeding cyclic tables --- drizzle-seed/src/index.ts | 320 ++++++++++---- .../src/services/GeneratorsWrappers.ts | 400 +++++------------- drizzle-seed/src/services/SeedService.ts | 334 ++++++++++++--- drizzle-seed/src/services/utils.ts | 4 + drizzle-seed/src/types/seedService.ts | 4 + drizzle-seed/src/types/tables.ts | 3 + 6 files changed, 644 insertions(+), 421 deletions(-) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 684de5009..3e0582e8f 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -14,7 +14,7 @@ import { generatorsFuncs } from './services/GeneratorsWrappers.ts'; import seedService from './services/SeedService.ts'; import type { DrizzleStudioObjectType, DrizzleStudioRelationType } from './types/drizzleStudio.ts'; import type { RefinementsType } from './types/seedService.ts'; -import type { Column, Relation, Table } from './types/tables.ts'; +import type { Column, Relation, RelationWithReferences, Table } from './types/tables.ts'; type InferCallbackType< DB extends @@ -226,6 +226,7 @@ export async function seedForDrizzleStudio( hasDefault: col.default === undefined ? false : true, isUnique: col.isUnique === undefined ? false : col.isUnique, notNull: col.notNull, + primary: col.primaryKey, })); tables.push( { @@ -237,6 +238,14 @@ export async function seedForDrizzleStudio( } relations = drizzleStudioRelations.filter((rel) => rel.schema === schemaName && rel.refSchema === schemaName); + const isCyclicRelations = relations.map( + (reli) => { + if (relations.some((relj) => reli.table === relj.refTable && reli.refTable === relj.table)) { + return { ...reli, isCyclic: true }; + } + return { ...reli, isCyclic: false }; + }, + ); refinements = schemasRefinements !== undefined && schemasRefinements[schemaName] !== undefined ? schemasRefinements[schemaName] @@ -245,13 +254,14 @@ export async function seedForDrizzleStudio( const generatedTablesGenerators = seedService.generatePossibleGenerators( sqlDialect, tables, - relations, + isCyclicRelations, + {}, // TODO: fix later refinements, options, ); const generatedTables = await seedService.generateTablesValues( - relations, + isCyclicRelations, generatedTablesGenerators, undefined, undefined, @@ -479,21 +489,37 @@ const seedPostgres = async ( options: { count?: number; seed?: number } = {}, refinements?: RefinementsType, ) => { - const { tables, relations } = getPostgresInfo(schema); + const { tables, relations, tableRelations } = getPostgresInfo(schema); const generatedTablesGenerators = seedService.generatePossibleGenerators( 'postgresql', tables, relations, + tableRelations, refinements, options, ); - await seedService.generateTablesValues( + const preserveCyclicTablesData = relations.some((rel) => rel.isCyclic === true); + + const tablesValues = await seedService.generateTablesValues( relations, generatedTablesGenerators, db, schema, - options, + { ...options, preserveCyclicTablesData }, + ); + + const { filteredTablesGenerators, tablesUniqueNotNullColumn } = seedService.filterCyclicTables( + generatedTablesGenerators, + ); + const updateDataInDb = filteredTablesGenerators.length === 0 ? false : true; + + await seedService.generateTablesValues( + relations, + filteredTablesGenerators, + db, + schema, + { ...options, tablesValues, updateDataInDb, tablesUniqueNotNullColumn }, ); }; @@ -505,10 +531,11 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { ); const tables: Table[] = []; - const relations: Relation[] = []; + const relations: RelationWithReferences[] = []; const dbToTsColumnNamesMapGlobal: { [tableName: string]: { [dbColumnName: string]: string }; } = {}; + const tableRelations: { [tableName: string]: RelationWithReferences[] } = {}; const getDbToTsColumnNamesMap = (table: PgTable) => { let dbToTsColumnNamesMap: { [dbColName: string]: string } = {}; @@ -536,30 +563,42 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { dbToTsColumnNamesMap[col.name] = tsCol; } + // might be empty list + const newRelations = tableConfig.foreignKeys.map((fk) => { + const table = dbToTsTableNamesMap[tableConfig.name] as string; + const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; + + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( + fk.reference().foreignTable, + ); + + if (tableRelations[refTable] === undefined) { + tableRelations[refTable] = []; + } + return { + table, + columns: fk + .reference() + .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), + refTable, + refColumns: fk + .reference() + .foreignColumns.map( + (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, + ), + refTableRels: tableRelations[refTable], + }; + }); + relations.push( - ...tableConfig.foreignKeys.map((fk) => { - const table = dbToTsTableNamesMap[tableConfig.name] as string; - const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; - - const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( - fk.reference().foreignTable, - ); - - return { - table, - columns: fk - .reference() - .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), - refTable, - refColumns: fk - .reference() - .foreignColumns.map( - (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, - ), - }; - }), + ...newRelations, ); + if (tableRelations[dbToTsTableNamesMap[tableConfig.name] as string] === undefined) { + tableRelations[dbToTsTableNamesMap[tableConfig.name] as string] = []; + } + tableRelations[dbToTsTableNamesMap[tableConfig.name] as string]!.push(...newRelations); + const getAllBaseColumns = ( baseColumn: PgArray['baseColumn'] & { baseColumn?: PgArray['baseColumn'] }, ): Column['baseColumn'] => { @@ -573,6 +612,7 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { default: baseColumn.default, isUnique: baseColumn.isUnique, notNull: baseColumn.notNull, + primary: baseColumn.primary, baseColumn: baseColumn.baseColumn === undefined ? undefined : getAllBaseColumns(baseColumn.baseColumn), }; @@ -592,6 +632,7 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { enumValues: column.enumValues, isUnique: column.isUnique, notNull: column.notNull, + primary: column.primary, generatedIdentityType: column.generatedIdentity?.type, baseColumn: ((column as PgArray).baseColumn === undefined) ? undefined @@ -603,7 +644,51 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { }); } - return { tables, relations }; + const isCyclicRelations = relations.map( + (relI) => { + // if (relations.some((relj) => relI.table === relj.refTable && relI.refTable === relj.table)) { + const tableRel = tableRelations[relI.table]!.find((relJ) => relJ.refTable === relI.refTable)!; + if (isRelationCyclic(relI)) { + tableRel['isCyclic'] = true; + return { ...relI, isCyclic: true }; + } + tableRel['isCyclic'] = false; + return { ...relI, isCyclic: false }; + }, + ); + + return { tables, relations: isCyclicRelations, tableRelations }; +}; + +const isRelationCyclic = ( + startRel: RelationWithReferences, +) => { + // DFS + const targetTable = startRel.table; + const queue = [startRel]; + let path: string[] = []; + while (queue.length !== 0) { + const currRel = queue.shift(); + + if (path.includes(currRel!.table)) { + const idx = path.indexOf(currRel!.table); + path = path.slice(0, idx); + } + path.push(currRel!.table); + + for (const rel of currRel!.refTableRels) { + // self relation + if (rel.table === rel.refTable) continue; + + if (rel.refTable === targetTable) return true; + + // found cycle, but not the one we are looking for + if (path.includes(rel.refTable)) continue; + queue.unshift(rel); + } + } + + return false; }; // MySql----------------------------------------------------------------------------------------------------- @@ -650,22 +735,38 @@ const seedMySql = async ( options: { count?: number; seed?: number } = {}, refinements?: RefinementsType, ) => { - const { tables, relations } = getMySqlInfo(schema); + const { tables, relations, tableRelations } = getMySqlInfo(schema); const generatedTablesGenerators = seedService.generatePossibleGenerators( 'mysql', tables, relations, + tableRelations, refinements, options, ); - await seedService.generateTablesValues( + const preserveCyclicTablesData = relations.some((rel) => rel.isCyclic === true); + + const tablesValues = await seedService.generateTablesValues( relations, generatedTablesGenerators, db, schema, - options, + { ...options, preserveCyclicTablesData }, + ); + + const { filteredTablesGenerators, tablesUniqueNotNullColumn } = seedService.filterCyclicTables( + generatedTablesGenerators, + ); + const updateDataInDb = filteredTablesGenerators.length === 0 ? false : true; + + await seedService.generateTablesValues( + relations, + filteredTablesGenerators, + db, + schema, + { ...options, tablesValues, updateDataInDb, tablesUniqueNotNullColumn }, ); }; @@ -678,10 +779,11 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { ); const tables: Table[] = []; - const relations: Relation[] = []; + const relations: RelationWithReferences[] = []; const dbToTsColumnNamesMapGlobal: { [tableName: string]: { [dbColumnName: string]: string }; } = {}; + const tableRelations: { [tableName: string]: RelationWithReferences[] } = {}; const getDbToTsColumnNamesMap = (table: MySqlTable) => { let dbToTsColumnNamesMap: { [dbColName: string]: string } = {}; @@ -709,29 +811,39 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { dbToTsColumnNamesMap[col.name] = tsCol; } + const newRelations = tableConfig.foreignKeys.map((fk) => { + const table = dbToTsTableNamesMap[tableConfig.name] as string; + const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( + fk.reference().foreignTable, + ); + + if (tableRelations[refTable] === undefined) { + tableRelations[refTable] = []; + } + return { + table, + columns: fk + .reference() + .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), + refTable, + refColumns: fk + .reference() + .foreignColumns.map( + (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, + ), + refTableRels: tableRelations[refTable], + }; + }); relations.push( - ...tableConfig.foreignKeys.map((fk) => { - const table = dbToTsTableNamesMap[tableConfig.name] as string; - const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; - const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( - fk.reference().foreignTable, - ); - - return { - table, - columns: fk - .reference() - .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), - refTable, - refColumns: fk - .reference() - .foreignColumns.map( - (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, - ), - }; - }), + ...newRelations, ); + if (tableRelations[dbToTsTableNamesMap[tableConfig.name] as string] === undefined) { + tableRelations[dbToTsTableNamesMap[tableConfig.name] as string] = []; + } + tableRelations[dbToTsTableNamesMap[tableConfig.name] as string]!.push(...newRelations); + tables.push({ name: dbToTsTableNamesMap[tableConfig.name] as string, columns: tableConfig.columns.map((column) => ({ @@ -743,6 +855,7 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { enumValues: column.enumValues, isUnique: column.isUnique, notNull: column.notNull, + primary: column.primary, })), primaryKeys: tableConfig.columns .filter((column) => column.primary) @@ -750,7 +863,17 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { }); } - return { tables, relations }; + const isCyclicRelations = relations.map( + (relI) => { + // if (relations.some((relj) => reli.table === relj.refTable && reli.refTable === relj.table)) { + if (isRelationCyclic(relI)) { + return { ...relI, isCyclic: true }; + } + return { ...relI, isCyclic: false }; + }, + ); + + return { tables, relations: isCyclicRelations, tableRelations }; }; // Sqlite------------------------------------------------------------------------------------------------------------------------ @@ -797,22 +920,38 @@ const seedSqlite = async ( options: { count?: number; seed?: number } = {}, refinements?: RefinementsType, ) => { - const { tables, relations } = getSqliteInfo(schema); + const { tables, relations, tableRelations } = getSqliteInfo(schema); const generatedTablesGenerators = seedService.generatePossibleGenerators( 'sqlite', tables, relations, + tableRelations, refinements, options, ); - await seedService.generateTablesValues( + const preserveCyclicTablesData = relations.some((rel) => rel.isCyclic === true); + + const tablesValues = await seedService.generateTablesValues( relations, generatedTablesGenerators, db, schema, - options, + { ...options, preserveCyclicTablesData }, + ); + + const { filteredTablesGenerators, tablesUniqueNotNullColumn } = seedService.filterCyclicTables( + generatedTablesGenerators, + ); + const updateDataInDb = filteredTablesGenerators.length === 0 ? false : true; + + await seedService.generateTablesValues( + relations, + filteredTablesGenerators, + db, + schema, + { ...options, tablesValues, updateDataInDb, tablesUniqueNotNullColumn }, ); }; @@ -824,10 +963,11 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { ); const tables: Table[] = []; - const relations: Relation[] = []; + const relations: RelationWithReferences[] = []; const dbToTsColumnNamesMapGlobal: { [tableName: string]: { [dbColumnName: string]: string }; } = {}; + const tableRelations: { [tableName: string]: RelationWithReferences[] } = {}; const getDbToTsColumnNamesMap = (table: SQLiteTable) => { let dbToTsColumnNamesMap: { [dbColName: string]: string } = {}; @@ -855,29 +995,40 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { dbToTsColumnNamesMap[col.name] = tsCol; } + const newRelations = tableConfig.foreignKeys.map((fk) => { + const table = dbToTsTableNamesMap[tableConfig.name] as string; + const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( + fk.reference().foreignTable, + ); + + if (tableRelations[refTable] === undefined) { + tableRelations[refTable] = []; + } + return { + table, + columns: fk + .reference() + .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), + refTable, + refColumns: fk + .reference() + .foreignColumns.map( + (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, + ), + refTableRels: tableRelations[refTable], + }; + }); + relations.push( - ...tableConfig.foreignKeys.map((fk) => { - const table = dbToTsTableNamesMap[tableConfig.name] as string; - const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; - const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( - fk.reference().foreignTable, - ); - - return { - table, - columns: fk - .reference() - .columns.map((col) => dbToTsColumnNamesMap[col.name] as string), - refTable, - refColumns: fk - .reference() - .foreignColumns.map( - (fCol) => dbToTsColumnNamesMapForRefTable[fCol.name] as string, - ), - }; - }), + ...newRelations, ); + if (tableRelations[dbToTsTableNamesMap[tableConfig.name] as string] === undefined) { + tableRelations[dbToTsTableNamesMap[tableConfig.name] as string] = []; + } + tableRelations[dbToTsTableNamesMap[tableConfig.name] as string]!.push(...newRelations); + tables.push({ name: dbToTsTableNamesMap[tableConfig.name] as string, columns: tableConfig.columns.map((column) => ({ @@ -889,6 +1040,7 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { enumValues: column.enumValues, isUnique: column.isUnique, notNull: column.notNull, + primary: column.primary, })), primaryKeys: tableConfig.columns .filter((column) => column.primary) @@ -896,7 +1048,17 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { }); } - return { tables, relations }; + const isCyclicRelations = relations.map( + (relI) => { + if (isRelationCyclic(relI)) { + // if (relations.some((relj) => reli.table === relj.refTable && reli.refTable === relj.table)) { + return { ...relI, isCyclic: true }; + } + return { ...relI, isCyclic: false }; + }, + ); + + return { tables, relations: isCyclicRelations, tableRelations }; }; export { default as cities } from './datasets/cityNames.ts'; diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts index 34f12fef1..e72dffba2 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -27,7 +27,20 @@ export abstract class AbstractGenerator { constructor(public params: T) {} - abstract init(params: { count: number | { weight: number; count: number | number[] }[]; seed: number }): void; + init(params: { count: number | { weight: number; count: number | number[] }[]; seed: number }): void; + init() { + if ((this.params as any).arraySize !== undefined) { + this.arraySize = (this.params as any).arraySize; + } + + if ((this.params as any).isUnique !== undefined) { + if ((this.params as any).isUnique === false && this.isUnique === true) { + throw new Error('specifying non unique generator to unique column.'); + } + + this.isUnique = (this.params as any).isUnique; + } + } abstract generate(params: { i: number }): number | string | boolean | unknown | undefined | void; @@ -94,7 +107,8 @@ export class GenerateArray extends AbstractGenerator<{ baseColumnGen: AbstractGe static override readonly [entityKind]: string = 'GenerateArray'; public override arraySize = 10; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); this.arraySize = this.params.size === undefined ? this.arraySize : this.params.size; this.params.baseColumnGen.init({ count: count * this.arraySize, seed }); } @@ -118,7 +132,7 @@ export class GenerateWeightedCount extends AbstractGenerator<{}> { weightedCount: { weight: number; count: number | number[] }[]; } | undefined; - init({ seed, count }: { count: { weight: number; count: number | number[] }[]; seed: number }) { + override init({ seed, count }: { count: { weight: number; count: number | number[] }[]; seed: number }) { const rng = prand.xoroshiro128plus(seed); const weightedIndices = getWeightedIndices(count.map((val) => val.weight)); this.state = { rng, weightedIndices, weightedCount: count }; @@ -150,7 +164,7 @@ export class GenerateWeightedCount extends AbstractGenerator<{}> { export class HollowGenerator extends AbstractGenerator<{}> { static override readonly [entityKind]: string = 'HollowGenerator'; - init() {} + override init() {} generate() {} } @@ -161,12 +175,6 @@ export class GenerateDefault extends AbstractGenerator<{ }> { static override readonly [entityKind]: string = 'GenerateDefault'; - init() { - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } - } - generate() { return this.params.defaultValue; } @@ -268,18 +276,8 @@ export class GenerateValuesFromArray extends AbstractGenerator< } } - init({ count, seed }: { count: number; seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('Specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); this.checks({ count }); @@ -410,7 +408,7 @@ export class GenerateSelfRelationsValuesFromArray extends AbstractGenerator<{ va firstValues: (string | number | boolean)[]; } | undefined; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { let rng = prand.xoroshiro128plus(seed); // generate 15-40 % values with the same value as reference column @@ -444,7 +442,7 @@ export class GenerateIntPrimaryKey extends AbstractGenerator<{}> { public maxValue?: number | bigint; - init({ count }: { count: number; seed: number }) { + override init({ count }: { count: number; seed: number }) { if (this.maxValue !== undefined && count > this.maxValue) { throw new Error('count exceeds max number for this column type.'); } @@ -466,7 +464,7 @@ export class GenerateNumber extends AbstractGenerator< precision?: number; isUnique?: boolean; arraySize?: number; - } | undefined + } > { static override readonly [entityKind]: string = 'GenerateNumber'; @@ -478,20 +476,8 @@ export class GenerateNumber extends AbstractGenerator< } | undefined; override uniqueVersionOfGen = GenerateUniqueNumber; - init({ seed }: { seed: number }) { - if (this.params === undefined) this.params = {}; - - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { seed: number; count: number }) { + super.init({ count, seed }); let { minValue, maxValue, precision } = this.params; if (precision === undefined) { @@ -533,7 +519,7 @@ export class GenerateUniqueNumber extends AbstractGenerator< maxValue?: number; precision?: number; isUnique?: boolean; - } | undefined + } > { static override readonly [entityKind]: string = 'GenerateUniqueNumber'; @@ -545,8 +531,7 @@ export class GenerateUniqueNumber extends AbstractGenerator< } | undefined; public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { - if (this.params === undefined) this.params = {}; + override init({ count, seed }: { count: number; seed: number }) { let { minValue, maxValue, precision } = this.params; if (precision === undefined) { @@ -597,18 +582,8 @@ export class GenerateInt extends AbstractGenerator<{ } | undefined; override uniqueVersionOfGen = GenerateUniqueInt; - init({ seed }: { count: number; seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); let { minValue, maxValue } = this.params; @@ -680,7 +655,7 @@ export class GenerateUniqueInt extends AbstractGenerator<{ public override isUnique = true; public override timeSpent = 0; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { const rng = prand.xoroshiro128plus(seed); let { minValue, maxValue } = this.params; @@ -840,10 +815,8 @@ export class GenerateBoolean extends AbstractGenerator<{ arraySize?: number }> { rng: prand.RandomGenerator; } | undefined; - init({ seed }: { seed: number }) { - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -875,15 +848,11 @@ export class GenerateDate extends AbstractGenerator<{ maxDate: Date; } | undefined; - init({ seed }: { seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); let { minDate, maxDate } = this.params; - const { arraySize } = this.params; - - if (arraySize !== undefined) { - this.arraySize = arraySize; - } const anchorDate = new Date('2024-05-08'); const deltaMilliseconds = 4 * 31536000000; @@ -939,10 +908,8 @@ export class GenerateTime extends AbstractGenerator<{ arraySize?: number }> { rng: prand.RandomGenerator; } | undefined; - init({ seed }: { seed: number }) { - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -977,10 +944,10 @@ export class GenerateTimestampInt extends AbstractGenerator<{ unitOfTime?: 'seco generateTimestampObj: GenerateTimestamp; } | undefined; - init({ seed }: { seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { const generateTimestampObj = new GenerateTimestamp({}); generateTimestampObj.dataType = 'date'; - generateTimestampObj.init({ seed }); + generateTimestampObj.init({ count, seed }); this.state = { generateTimestampObj }; } @@ -1010,10 +977,8 @@ export class GenerateTimestamp extends AbstractGenerator<{ arraySize?: number }> rng: prand.RandomGenerator; } | undefined; - init({ seed }: { seed: number }) { - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -1056,10 +1021,8 @@ export class GenerateDatetime extends AbstractGenerator<{ arraySize?: number }> rng: prand.RandomGenerator; } | undefined; - init({ seed }: { seed: number }) { - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -1102,10 +1065,8 @@ export class GenerateYear extends AbstractGenerator<{ arraySize?: number }> { rng: prand.RandomGenerator; } | undefined; - init({ seed }: { seed: number }) { - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -1145,19 +1106,18 @@ export class GenerateJson extends AbstractGenerator<{ arraySize?: number }> { seed: number; } | undefined; - init({ count, seed }: { count: number; seed: number }) { - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const emailGeneratorObj = new GenerateEmail({}); emailGeneratorObj.init({ count, seed }); const nameGeneratorObj = new GenerateFirstName({}); - nameGeneratorObj.init({ seed }); + nameGeneratorObj.init({ count, seed }); const booleanGeneratorObj = new GenerateBoolean({}); booleanGeneratorObj.init({ + count, seed, }); @@ -1170,7 +1130,7 @@ export class GenerateJson extends AbstractGenerator<{ arraySize?: number }> { const dateGeneratorObj = new GenerateDate({}); dateGeneratorObj.dataType = 'string'; - dateGeneratorObj.init({ seed }); + dateGeneratorObj.init({ count, seed }); const visitedCountriesNumberGeneratorObj = new GenerateInt({ minValue: 0, maxValue: 4 }); visitedCountriesNumberGeneratorObj.init( @@ -1244,7 +1204,7 @@ export class GenerateEnum extends AbstractGenerator<{ enumValues: (string | numb enumValuesGenerator: GenerateValuesFromArray; } | undefined; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { const { enumValues } = this.params; const enumValuesGenerator = new GenerateValuesFromArray({ values: enumValues }); enumValuesGenerator.init({ count, seed }); @@ -1269,18 +1229,8 @@ export class GenerateInterval extends AbstractGenerator<{ private state: { rng: prand.RandomGenerator } | undefined; override uniqueVersionOfGen = GenerateUniqueInterval; - init({ seed }: { count: number; seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -1329,8 +1279,9 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boole rng: prand.RandomGenerator; intervalSet: Set; } | undefined; + public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { const maxUniqueIntervalsNumber = 6 * 13 * 29 * 25 * 61 * 61; if (count > maxUniqueIntervalsNumber) { throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`); @@ -1389,18 +1340,8 @@ export class GenerateString extends AbstractGenerator<{ private state: { rng: prand.RandomGenerator } | undefined; override uniqueVersionOfGen = GenerateUniqueString; - init({ seed }: { seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -1442,7 +1383,7 @@ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean private state: { rng: prand.RandomGenerator } | undefined; public override isUnique = true; - init({ seed }: { seed: number }) { + override init({ seed }: { seed: number }) { const rng = prand.xoroshiro128plus(seed); this.state = { rng }; } @@ -1488,10 +1429,8 @@ export class GenerateUUID extends AbstractGenerator<{ private state: { rng: prand.RandomGenerator } | undefined; - init({ seed }: { seed: number }) { - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); this.state = { rng }; @@ -1539,18 +1478,8 @@ export class GenerateFirstName extends AbstractGenerator<{ } | undefined; override uniqueVersionOfGen = GenerateUniqueFirstName; - init({ seed }: { seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -1582,7 +1511,7 @@ export class GenerateUniqueFirstName extends AbstractGenerator<{ } | undefined; public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { if (count > firstNames.length) { throw new Error('count exceeds max number of unique first names.'); } @@ -1616,18 +1545,8 @@ export class GenerateLastName extends AbstractGenerator<{ } | undefined; override uniqueVersionOfGen = GenerateUniqueLastName; - init({ seed }: { seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -1653,7 +1572,7 @@ export class GenerateUniqueLastName extends AbstractGenerator<{ isUnique?: boole } | undefined; public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { if (count > lastNames.length) { throw new Error('count exceeds max number of unique last names.'); } @@ -1687,18 +1606,8 @@ export class GenerateFullName extends AbstractGenerator<{ } | undefined; override uniqueVersionOfGen = GenerateUniqueFullName; - init({ seed }: { seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -1736,7 +1645,7 @@ export class GenerateUniqueFullName extends AbstractGenerator<{ public override isUnique = true; public override timeSpent = 0; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { const t0 = new Date(); const maxUniqueFullNamesNumber = firstNames.length * lastNames.length; @@ -1792,15 +1701,13 @@ export class GenerateEmail extends AbstractGenerator<{ public override timeSpent: number = 0; public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); + const domainsArray = emailDomains; const adjectivesArray = adjectives; const namesArray = firstNames; - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } - const maxUniqueEmailsNumber = adjectivesArray.length * namesArray.length * domainsArray.length; if (count > maxUniqueEmailsNumber) { throw new RangeError( @@ -1857,13 +1764,11 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ } | undefined; public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { - let { generatedDigitsNumbers } = this.params; - const { prefixes, template, arraySize } = this.params; + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); - if (arraySize !== undefined) { - this.arraySize = arraySize; - } + let { generatedDigitsNumbers } = this.params; + const { prefixes, template } = this.params; const rng = prand.xoroshiro128plus(seed); @@ -2030,18 +1935,8 @@ export class GenerateCountry extends AbstractGenerator<{ } | undefined; override uniqueVersionOfGen = GenerateUniqueCountry; - init({ seed }: { count: number; seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -2070,7 +1965,7 @@ export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolea } | undefined; public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { if (count > countries.length) { throw new Error('count exceeds max number of unique countries.'); } @@ -2102,10 +1997,8 @@ export class GenerateJobTitle extends AbstractGenerator<{ rng: prand.RandomGenerator; } | undefined; - init({ seed }: { seed: number }) { - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -2136,18 +2029,8 @@ export class GenerateStreetAdddress extends AbstractGenerator<{ } | undefined; override uniqueVersionOfGen = GenerateUniqueStreetAdddress; - init({ seed }: { count: number; seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); const possStreetNames = [firstNames, lastNames]; @@ -2188,8 +2071,9 @@ export class GenerateUniqueStreetAdddress extends AbstractGenerator<{ isUnique?: arraysToChooseFrom: string[][]; }[]; } | undefined; + public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { const streetNumberStrs = Array.from({ length: 999 }, (_, i) => String(i + 1)); const maxUniqueStreetnamesNumber = streetNumberStrs.length * firstNames.length * streetSuffix.length + streetNumberStrs.length * firstNames.length * streetSuffix.length; @@ -2272,18 +2156,8 @@ export class GenerateCity extends AbstractGenerator<{ } | undefined; override uniqueVersionOfGen = GenerateUniqueCity; - init({ seed }: { seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -2310,7 +2184,7 @@ export class GenerateUniqueCity extends AbstractGenerator<{ isUnique?: boolean } } | undefined; public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { if (count > cityNames.length) { throw new Error('count exceeds max number of unique cities.'); } @@ -2345,18 +2219,8 @@ export class GeneratePostcode extends AbstractGenerator<{ } | undefined; override uniqueVersionOfGen = GenerateUniquePostcode; - init({ seed }: { seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); const templates = ['#####', '#####-####']; @@ -2406,8 +2270,9 @@ export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boole maxUniquePostcodeNumber: number; }[]; } | undefined; + public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { const maxUniquePostcodeNumber = Math.pow(10, 5) + Math.pow(10, 9); if (count > maxUniquePostcodeNumber) { throw new RangeError( @@ -2479,10 +2344,8 @@ export class GenerateState extends AbstractGenerator<{ rng: prand.RandomGenerator; } | undefined; - init({ seed }: { seed: number }) { - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); @@ -2513,18 +2376,8 @@ export class GenerateCompanyName extends AbstractGenerator<{ } | undefined; override uniqueVersionOfGen = GenerateUniqueCompanyName; - init({ seed }: { seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); const templates = [ @@ -2586,16 +2439,9 @@ export class GenerateUniqueCompanyName extends AbstractGenerator<{ isUnique?: bo arraysToChooseFrom: string[][]; }[]; } | undefined; + public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - + override init({ count, seed }: { count: number; seed: number }) { const maxUniqueCompanyNameNumber = lastNames.length * companyNameSuffixes.length + Math.pow(lastNames.length, 2) + Math.pow(lastNames.length, 2) + Math.pow(lastNames.length, 3); if (count > maxUniqueCompanyNameNumber) { @@ -2686,10 +2532,8 @@ export class GenerateLoremIpsum extends AbstractGenerator<{ rng: prand.RandomGenerator; } | undefined; - init({ seed }: { seed: number }) { - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); if (this.params.sentencesCount === undefined) this.params.sentencesCount = 1; @@ -2720,7 +2564,7 @@ export class WeightedRandomGenerator extends AbstractGenerator<{ weight: number; weightedIndices: number[]; } | undefined; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { const weights = this.params.map((weightedGen) => weightedGen.weight); const weightedIndices = getWeightedIndices(weights); @@ -2791,32 +2635,22 @@ export class GeneratePoint extends AbstractGenerator<{ } | undefined; override uniqueVersionOfGen = GenerateUniquePoint; - init({ seed }: { count: number; seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const xCoordinateGen = new GenerateNumber({ minValue: this.params.minXValue, maxValue: this.params.maxXValue, precision: 10, }); - xCoordinateGen.init({ seed }); + xCoordinateGen.init({ count, seed }); const yCoordinateGen = new GenerateNumber({ minValue: this.params.minYValue, maxValue: this.params.maxYValue, precision: 10, }); - yCoordinateGen.init({ seed }); + yCoordinateGen.init({ count, seed }); this.state = { xCoordinateGen, yCoordinateGen }; } @@ -2853,8 +2687,9 @@ export class GenerateUniquePoint extends AbstractGenerator<{ xCoordinateGen: GenerateUniqueNumber; yCoordinateGen: GenerateUniqueNumber; } | undefined; + public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { const xCoordinateGen = new GenerateUniqueNumber({ minValue: this.params.minXValue, maxValue: this.params.maxXValue, @@ -2910,39 +2745,29 @@ export class GenerateLine extends AbstractGenerator<{ } | undefined; override uniqueVersionOfGen = GenerateUniqueLine; - init({ seed }: { count: number; seed: number }) { - if (this.params.isUnique !== undefined) { - if (this.params.isUnique === false && this.isUnique === true) { - throw new Error('specifying non unique generator to unique column.'); - } - - this.isUnique = this.params.isUnique; - } - - if (this.params.arraySize !== undefined) { - this.arraySize = this.params.arraySize; - } + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); const aCoefficientGen = new GenerateNumber({ minValue: this.params.minAValue, maxValue: this.params.maxAValue, precision: 10, }); - aCoefficientGen.init({ seed }); + aCoefficientGen.init({ count, seed }); const bCoefficientGen = new GenerateNumber({ minValue: this.params.minBValue, maxValue: this.params.maxBValue, precision: 10, }); - bCoefficientGen.init({ seed }); + bCoefficientGen.init({ count, seed }); const cCoefficientGen = new GenerateNumber({ minValue: this.params.minCValue, maxValue: this.params.maxCValue, precision: 10, }); - cCoefficientGen.init({ seed }); + cCoefficientGen.init({ count, seed }); this.state = { aCoefficientGen, bCoefficientGen, cCoefficientGen }; } @@ -2989,8 +2814,9 @@ export class GenerateUniqueLine extends AbstractGenerator<{ bCoefficientGen: GenerateUniqueNumber; cCoefficientGen: GenerateUniqueNumber; } | undefined; + public override isUnique = true; - init({ count, seed }: { count: number; seed: number }) { + override init({ count, seed }: { count: number; seed: number }) { const aCoefficientGen = new GenerateUniqueNumber({ minValue: this.params.minAValue, maxValue: this.params.maxAValue, diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 59ac0f3fe..9a5c0e05d 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -1,9 +1,9 @@ -import { entityKind, is } from 'drizzle-orm'; -import type { MySqlTable } from 'drizzle-orm/mysql-core'; +import { entityKind, eq, is } from 'drizzle-orm'; +import type { MySqlTable, MySqlTableWithColumns } from 'drizzle-orm/mysql-core'; import { MySqlDatabase } from 'drizzle-orm/mysql-core'; -import type { PgTable } from 'drizzle-orm/pg-core'; +import type { PgTable, PgTableWithColumns } from 'drizzle-orm/pg-core'; import { PgDatabase } from 'drizzle-orm/pg-core'; -import type { SQLiteTable } from 'drizzle-orm/sqlite-core'; +import type { SQLiteTable, SQLiteTableWithColumns } from 'drizzle-orm/sqlite-core'; import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core'; import type { GeneratePossibleGeneratorsColumnType, @@ -11,7 +11,7 @@ import type { RefinementsType, TableGeneratorsType, } from '../types/seedService.ts'; -import type { Column, Prettify, Relation, Table } from '../types/tables.ts'; +import type { Column, Prettify, Relation, RelationWithReferences, Table } from '../types/tables.ts'; import type { AbstractGenerator } from './GeneratorsWrappers.ts'; import { GenerateArray, @@ -40,7 +40,7 @@ import { GenerateYear, HollowGenerator, } from './GeneratorsWrappers.ts'; -import { generateHashFromString } from './utils.ts'; +import { equalSets, generateHashFromString } from './utils.ts'; class SeedService { static readonly [entityKind]: string = 'SeedService'; @@ -56,7 +56,8 @@ class SeedService { generatePossibleGenerators = ( connectionType: 'postgresql' | 'mysql' | 'sqlite', tables: Table[], - relations: Relation[], + relations: (Relation & { isCyclic: boolean })[], + tableRelations: { [tableName: string]: RelationWithReferences[] }, refinements?: RefinementsType, options?: { count?: number; seed?: number }, ) => { @@ -66,9 +67,17 @@ class SeedService { // sorting table in order which they will be filled up (tables with foreign keys case) // relations = relations.filter(rel => rel.type === "one"); - const tablesInOutRelations = this.getTablesInOutRelations(relations); + const { tablesInOutRelations } = this.getInfoFromRelations(relations); const orderedTablesNames = this.getOrderedTablesList(tablesInOutRelations); tables = tables.sort((table1, table2) => { + const rel = relations.find((rel) => rel.table === table1.name && rel.refTable === table2.name); + if (rel === undefined) return 0; + + if (rel.isCyclic) { + const reverseRel = relations.find((rel) => rel.table === table2.name && rel.refTable === table1.name); + return this.cyclicTablesCompare(table1, table2, rel, reverseRel); + } + const table1Order = orderedTablesNames.indexOf( table1.name, ), @@ -180,8 +189,12 @@ class SeedService { columnName: col.name, isUnique: col.isUnique, notNull: col.notNull, + primary: col.primary, generatedIdentityType: col.generatedIdentityType, generator: undefined, + isCyclic: false, + wasDefinedBefore: false, + wasRefined: false, }; if ( @@ -202,8 +215,24 @@ class SeedService { } columnPossibleGenerator.generator = genObj; + columnPossibleGenerator.wasRefined = true; } else if (Object.hasOwn(foreignKeyColumns, col.name)) { // TODO: I might need to assign repeatedValuesCount to column there instead of doing so in generateTablesValues + const cyclicRelation = tableRelations[table.name]!.find((rel) => + rel.isCyclic === true + && rel.columns.includes(col.name) + ); + + if (cyclicRelation !== undefined) { + columnPossibleGenerator.isCyclic = true; + } + const predicate = cyclicRelation !== undefined && col.notNull === false; + + if (predicate === true) { + columnPossibleGenerator.generator = new GenerateDefault({ defaultValue: null }); + columnPossibleGenerator.wasDefinedBefore = true; + } + columnPossibleGenerator.generator = new HollowGenerator({}); } // TODO: rewrite pickGeneratorFor... using new col properties: isUnique and notNull else if (connectionType === 'postgresql') { @@ -242,7 +271,45 @@ class SeedService { return tablesPossibleGenerators; }; - getOrderedTablesList = (tablesInOutRelations: ReturnType): string[] => { + cyclicTablesCompare = ( + table1: Table, + table2: Table, + relation: Relation & { isCyclic: boolean }, + reverseRelation: Relation & { isCyclic: boolean } | undefined, + ) => { + // TODO: revise + const hasTable1NotNullColumns = relation.columns.some((colIName) => + table1.columns.find((colJ) => colJ.name === colIName)?.notNull === true + ); + + if (reverseRelation !== undefined) { + const hasTable2NotNullColumns = reverseRelation.columns.some((colIName) => + table2.columns.find((colJ) => colJ.name === colIName)?.notNull === true + ); + + if (hasTable1NotNullColumns && hasTable2NotNullColumns) { + throw new Error( + `The '${table1.name}' and '${table2.name}' tables have not null foreign keys. You can't seed cyclic tables with not null foreign key columns.`, + ); + } + + if (hasTable1NotNullColumns) return 1; + else if (hasTable2NotNullColumns) return -1; + return 0; + } + + if (hasTable1NotNullColumns) { + return 1; + } + return 0; + + // if (hasTable1NotNullColumns) return 1; + // else if (hasTable2NotNullColumns) return -1; + }; + + getOrderedTablesList = ( + tablesInOutRelations: ReturnType['tablesInOutRelations'], + ): string[] => { const leafTablesNames = Object.entries(tablesInOutRelations) .filter( (tableRel) => @@ -270,7 +337,13 @@ class SeedService { tablesInOutRelations[parent]!.requiredTableNames.delete(orderedTableName); } - if (tablesInOutRelations[parent]!.requiredTableNames.size === 0) { + if ( + tablesInOutRelations[parent]!.requiredTableNames.size === 0 + || equalSets( + tablesInOutRelations[parent]!.requiredTableNames, + tablesInOutRelations[parent]!.dependantTableNames, + ) + ) { orderedTablesNames.push(parent); } else { leafTablesNames.push(parent); @@ -283,7 +356,7 @@ class SeedService { return orderedTablesNames; }; - getTablesInOutRelations = (relations: Relation[]) => { + getInfoFromRelations = (relations: (Relation & { isCyclic: boolean })[]) => { const tablesInOutRelations: { [tableName: string]: { out: number; @@ -295,7 +368,13 @@ class SeedService { }; } = {}; + // const cyclicRelations: { [cyclicTableName: string]: Relation & { isCyclic: boolean } } = {}; + for (const rel of relations) { + // if (rel.isCyclic) { + // cyclicRelations[rel.table] = rel; + // } + if (tablesInOutRelations[rel.table] === undefined) { tablesInOutRelations[rel.table] = { out: 0, @@ -330,7 +409,7 @@ class SeedService { } } - return tablesInOutRelations; + return { tablesInOutRelations }; }; getWeightedWithCount = ( @@ -888,15 +967,63 @@ class SeedService { return; }; + filterCyclicTables = (tablesGenerators: ReturnType) => { + const filteredTablesGenerators = tablesGenerators.filter((tableGen) => + tableGen.columnsPossibleGenerators.some((columnGen) => + columnGen.isCyclic === true && columnGen.wasDefinedBefore === true + ) + ); + + const tablesUniqueNotNullColumn: { [tableName: string]: { uniqueNotNullColName: string } } = {}; + + for (const [idx, tableGen] of filteredTablesGenerators.entries()) { + const uniqueNotNullColName = filteredTablesGenerators[idx]!.columnsPossibleGenerators.find((colGen) => + colGen.primary === true + || (colGen.isUnique === true + && colGen.notNull === true) + )?.columnName; + if (uniqueNotNullColName === undefined) { + throw new Error( + `Table '${tableGen.tableName}' does not have primary or (unique and notNull) column. Can't seed table with cyclic relation.`, + ); + } + tablesUniqueNotNullColumn[tableGen.tableName] = { uniqueNotNullColName }; + + filteredTablesGenerators[idx]!.columnsPossibleGenerators = tableGen.columnsPossibleGenerators.filter((colGen) => + (colGen.isCyclic === true && colGen.wasDefinedBefore === true) || colGen.columnName === uniqueNotNullColName + ).map((colGen) => { + const newColGen = { ...colGen }; + newColGen.wasDefinedBefore = false; + return newColGen; + }); + } + + return { filteredTablesGenerators, tablesUniqueNotNullColumn }; + }; + generateTablesValues = async ( - relations: Relation[], + relations: (Relation & { isCyclic: boolean })[], tablesGenerators: ReturnType, db?: | PgDatabase | MySqlDatabase | BaseSQLiteDatabase, schema?: { [key: string]: PgTable | MySqlTable | SQLiteTable }, - options?: { count?: number; seed?: number; preserveData?: boolean; insertDataInDb?: boolean }, + options?: { + count?: number; + seed?: number; + preserveData?: boolean; + preserveCyclicTablesData?: boolean; + insertDataInDb?: boolean; + updateDataInDb?: boolean; + tablesValues?: { + tableName: string; + rows: { + [columnName: string]: string | number | boolean | undefined; + }[]; + }[]; + tablesUniqueNotNullColumn?: { [tableName: string]: { uniqueNotNullColName: string } }; + }, ) => { // console.time( // "generateTablesValues-----------------------------------------------------" @@ -913,18 +1040,20 @@ class SeedService { let tablesValues: { tableName: string; rows: typeof tableValues; - }[] = []; + }[] = options?.tablesValues === undefined ? [] : options.tablesValues; let pRNGSeed: number; // relations = relations.filter(rel => rel.type === "one"); - let filteredRelations: Relation[]; + let filteredRelations: typeof relations; - let preserveData: boolean, insertDataInDb: boolean = true; + let preserveData: boolean, insertDataInDb: boolean = true, updateDataInDb: boolean = false; if (options?.preserveData !== undefined) preserveData = options.preserveData; if (options?.insertDataInDb !== undefined) insertDataInDb = options.insertDataInDb; + if (options?.updateDataInDb !== undefined) updateDataInDb = options.updateDataInDb; + if (updateDataInDb === true) insertDataInDb = false; // TODO: now I'm generating tablesInOutRelations twice, first time in generatePossibleGenerators and second time here. maybe should generate it once instead. - const tablesInOutRelations = this.getTablesInOutRelations(relations); + const { tablesInOutRelations } = this.getInfoFromRelations(relations); for (const table of tablesGenerators) { tableCount = table.count === undefined ? options?.count || this.defaultCountForTable : table.count; @@ -965,15 +1094,18 @@ class SeedService { for (let colIdx = 0; colIdx < rel.columns.length; colIdx++) { let refColumnValues: (string | number | boolean)[]; - let hasSelfRelation: boolean; + let hasSelfRelation: boolean = false; let repeatedValuesCount: | number | { weight: number; count: number | number[] }[] | undefined, weightedCountSeed: number | undefined; - let genObj: AbstractGenerator; + let genObj: AbstractGenerator | undefined; - if (rel.table === rel.refTable) { + if ( + rel.table === rel.refTable + && tableGenerators[rel.columns[colIdx]!]?.wasRefined === false + ) { const refColName = rel.refColumns[colIdx] as string; pRNGSeed = generateHashFromString( `${table.tableName}.${refColName}`, @@ -996,11 +1128,13 @@ class SeedService { genObj = new GenerateSelfRelationsValuesFromArray({ values: refColumnValues, }); - } else { + } else if ( + tableGenerators[rel.columns[colIdx]!]?.wasDefinedBefore === false + && tableGenerators[rel.columns[colIdx]!]?.wasRefined === false + ) { refColumnValues = tablesValues .find((val) => val.tableName === rel.refTable)! .rows!.map((row) => row[rel.refColumns[colIdx]!]!); - hasSelfRelation = false; if ( table.withFromTable[rel.refTable] !== undefined @@ -1018,7 +1152,9 @@ class SeedService { } // console.log(rel.columns[colIdx], tableGenerators) - tableGenerators[rel.columns[colIdx]!]!.generator = genObj; + if (genObj !== undefined) { + tableGenerators[rel.columns[colIdx]!]!.generator = genObj; + } tableGenerators[rel.columns[colIdx]!] = { ...tableGenerators[rel.columns[colIdx]!]!, hasSelfRelation, @@ -1035,6 +1171,9 @@ class SeedService { ? false : true; + preserveData = options?.preserveCyclicTablesData === true + && table.columnsPossibleGenerators.some((colGen) => colGen.isCyclic === true); + tableValues = await this.generateColumnsValuesByGenerators({ tableGenerators, db, @@ -1043,6 +1182,10 @@ class SeedService { count: tableCount, preserveData, insertDataInDb, + updateDataInDb, + uniqueNotNullColName: options?.tablesUniqueNotNullColumn === undefined + ? undefined + : options?.tablesUniqueNotNullColumn[table.tableName]?.uniqueNotNullColName, }); if (preserveData === true) { @@ -1078,7 +1221,9 @@ class SeedService { count, preserveData = true, insertDataInDb = true, - batchSize = 1, + updateDataInDb = false, + uniqueNotNullColName, + batchSize = 10000, }: { tableGenerators: Prettify; db?: @@ -1090,12 +1235,18 @@ class SeedService { count?: number; preserveData?: boolean; insertDataInDb?: boolean; + updateDataInDb?: boolean; + uniqueNotNullColName?: string; batchSize?: number; }) => { if (count === undefined) { count = this.defaultCountForTable; } + if (updateDataInDb === true) { + batchSize = 1; + } + let columnGenerator: (typeof tableGenerators)[string]; const columnsGenerators: { [columnName: string]: AbstractGenerator; @@ -1141,7 +1292,7 @@ class SeedService { batchSize = batchSize > maxBatchSize ? maxBatchSize : batchSize; if ( - insertDataInDb === true + (insertDataInDb === true || updateDataInDb === true) && (db === undefined || schema === undefined || tableName === undefined) ) { throw new Error('db or schema or tableName is undefined.'); @@ -1168,41 +1319,75 @@ class SeedService { } if ( - insertDataInDb === true + (insertDataInDb === true || updateDataInDb === true) && ((i + 1) % batchSize === 0 || i === count - 1) ) { if (preserveData === false) { - await this.insertInDb({ - generatedValues, - db: db as - | PgDatabase - | MySqlDatabase - | BaseSQLiteDatabase, - schema: schema as { - [key: string]: PgTable | MySqlTable | SQLiteTable; - }, - tableName: tableName as string, - override, - }); + if (insertDataInDb === true) { + await this.insertInDb({ + generatedValues, + db: db as + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + schema: schema as { + [key: string]: PgTable | MySqlTable | SQLiteTable; + }, + tableName: tableName as string, + override, + }); + } else if (updateDataInDb === true) { + await this.updateDb({ + generatedValues, + db: db as + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + schema: schema as { + [key: string]: PgTable | MySqlTable | SQLiteTable; + }, + tableName: tableName as string, + uniqueNotNullColName: uniqueNotNullColName as string, + }); + } + generatedValues = []; } else { const batchCount = Math.floor(i / batchSize); - await this.insertInDb({ - generatedValues: generatedValues.slice( - batchSize * batchCount, - batchSize * (batchCount + 1), - ), - db: db as - | PgDatabase - | MySqlDatabase - | BaseSQLiteDatabase, - schema: schema as { - [key: string]: PgTable | MySqlTable | SQLiteTable; - }, - tableName: tableName as string, - override, - }); + if (insertDataInDb === true) { + await this.insertInDb({ + generatedValues: generatedValues.slice( + batchSize * batchCount, + batchSize * (batchCount + 1), + ), + db: db as + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + schema: schema as { + [key: string]: PgTable | MySqlTable | SQLiteTable; + }, + tableName: tableName as string, + override, + }); + } else if (updateDataInDb === true) { + await this.updateDb({ + generatedValues: generatedValues.slice( + batchSize * batchCount, + batchSize * (batchCount + 1), + ), + db: db as + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase, + schema: schema as { + [key: string]: PgTable | MySqlTable | SQLiteTable; + }, + tableName: tableName as string, + uniqueNotNullColName: uniqueNotNullColName as string, + }); + } } } } @@ -1221,7 +1406,7 @@ class SeedService { [columnName: string]: number | string | boolean | undefined; }[]; db: - | PgDatabase + | PgDatabase | MySqlDatabase | BaseSQLiteDatabase; schema: { @@ -1246,6 +1431,45 @@ class SeedService { .values(generatedValues); } }; + + updateDb = async ({ + generatedValues, + db, + schema, + tableName, + uniqueNotNullColName, + }: { + generatedValues: { + [columnName: string]: number | string | boolean | undefined; + }[]; + db: + | PgDatabase + | MySqlDatabase + | BaseSQLiteDatabase; + schema: { + [key: string]: PgTable | MySqlTable | SQLiteTable; + }; + tableName: string; + uniqueNotNullColName: string; + }) => { + if (is(db, PgDatabase)) { + const table = (schema as { [key: string]: PgTableWithColumns })[tableName]!; + const uniqueNotNullCol = table[uniqueNotNullColName]; + await db.update(table).set(generatedValues[0]!).where( + eq(uniqueNotNullCol, generatedValues[0]![uniqueNotNullColName]), + ); + } else if (is(db, MySqlDatabase)) { + const table = (schema as { [key: string]: MySqlTableWithColumns })[tableName]!; + await db.update(table).set(generatedValues[0]!).where( + eq(table[uniqueNotNullColName], generatedValues[0]![uniqueNotNullColName]), + ); + } else if (is(db, BaseSQLiteDatabase)) { + const table = (schema as { [key: string]: SQLiteTableWithColumns })[tableName]!; + await db.update(table).set(generatedValues[0]!).where( + eq(table[uniqueNotNullColName], generatedValues[0]![uniqueNotNullColName]), + ); + } + }; } export default new SeedService(); diff --git a/drizzle-seed/src/services/utils.ts b/drizzle-seed/src/services/utils.ts index d14cabce0..c972e7bd1 100644 --- a/drizzle-seed/src/services/utils.ts +++ b/drizzle-seed/src/services/utils.ts @@ -99,3 +99,7 @@ export const isObject = (value: any) => { if (value !== null && value !== undefined && value.constructor === Object) return true; return false; }; + +export const equalSets = (set1: Set, set2: Set) => { + return set1.size === set2.size && [...set1].every((si) => set2.has(si)); +}; diff --git a/drizzle-seed/src/types/seedService.ts b/drizzle-seed/src/types/seedService.ts index 2490d5e26..0b5237468 100644 --- a/drizzle-seed/src/types/seedService.ts +++ b/drizzle-seed/src/types/seedService.ts @@ -16,7 +16,11 @@ export type GeneratePossibleGeneratorsColumnType = { generator: AbstractGenerator | undefined; isUnique: boolean; notNull: boolean; + primary: boolean; generatedIdentityType?: 'always' | 'byDefault' | undefined; + wasRefined: boolean; + wasDefinedBefore: boolean; + isCyclic: boolean; }; export type GeneratePossibleGeneratorsTableType = Prettify<{ diff --git a/drizzle-seed/src/types/tables.ts b/drizzle-seed/src/types/tables.ts index b1d601ca5..8473179ed 100644 --- a/drizzle-seed/src/types/tables.ts +++ b/drizzle-seed/src/types/tables.ts @@ -10,6 +10,7 @@ export type Column = { enumValues?: string[]; isUnique: boolean; notNull: boolean; + primary: boolean; generatedIdentityType?: 'always' | 'byDefault' | undefined; baseColumn?: Omit; }; @@ -31,6 +32,8 @@ export type Relation = { refColumns: string[]; }; +export type RelationWithReferences = Relation & { isCyclic?: boolean; refTableRels: RelationWithReferences[] }; + export type Prettify = & { [K in keyof T]: T[K]; From 7525e495276e36e8373a7490d040b2e3a0e414a7 Mon Sep 17 00:00:00 2001 From: L-Mario564 Date: Fri, 6 Dec 2024 03:59:48 -0800 Subject: [PATCH 420/492] Overhaul validator packages (#3508) * Unminify validator build output * Reimplement `createSelectSchema` in `drizzle-zod` * Add `getViewSelectedFields` util function * Support views in `drizzle-zod` * Reimplement refinement in zod select schema * Create schema creation factory for zod * Support enums in `createSelectSchema` in `drizzle-zod` * Update peer deps' versions in `drizzle-zod` * Add `getViewSelectedFields` util function * Fix view types * Add `$inferSelect` to views * Format * Fix lint errors * Reimplement `createInsertSchema` in `drizzle-zod` * Add `isView` util function * Handle additional properties * Add `createUpdateSchema` in `drizzle-zod` + Additional tests * Update type * Disallow unknown keys in `drizzle-zod` refinement * Add checks comparison * Test all PG data types * Restructure `drizzle-zod` files * Support PG arrays in `drizzle-zod` * Add MySql tests to drizzle-zod * Add SQLite tests + Fix MySql tests * Format * Update drizzle-valibot peer deps * Fix redundant checks in drizzle-zod * Wipe drizzzle-valibot and drizzle-typebox * Adapt drizzle-zod code for drizzle-valibot * Update string schema generation in drizzle-zod * Add type tests to drizzle-zod * Undo additional validation to strings in drizzle-zod * Add missing text types in `getMySqlColumnBuilders` return value * Handle additional MySQL text types in drizzle-zod * Make necessary type changes to ORM * Add MySQL tests to drizzle-valibot * Some ORM type-level changes * Improve and simplify array handling in drizzle-zod * Add drizzle-valibot PG tests * Add SQLite tests to drizzle-valibot * Fix drizzle-valibot not identifying length in MySQL char * Handle false-positive type error + Format drizzle-valibot * Optimize drizzle-zod * Optimize drizzle-valibot * Update peer deps in drizzle-typebox * Reimplement everything in drizzle-typebox * Add MySQL tests for drizzle-typebox * Add PG tests to drizzle-typebox * Write SQLite tests for drizzle-typebox * Format * Update validator packages README * Format * Add tests for tables within schemas * Properly implement `Buffer` schema in drizzle-typebox * Fix types * Fix type tests in ORM * Fix type tests * Lint * Fix builds for validator packages * Format * Fix types ans lint * fix * Fix * Update ORM types * Fix MySQL char types --------- Co-authored-by: AndriiSherman --- drizzle-orm/src/column-builder.ts | 48 +- drizzle-orm/src/mysql-core/columns/all.ts | 5 +- drizzle-orm/src/mysql-core/columns/char.ts | 48 +- drizzle-orm/src/mysql-core/columns/common.ts | 5 +- drizzle-orm/src/mysql-core/columns/text.ts | 2 +- drizzle-orm/src/mysql-core/columns/varchar.ts | 43 +- drizzle-orm/src/pg-core/columns/char.ts | 53 +- drizzle-orm/src/pg-core/columns/common.ts | 49 +- drizzle-orm/src/pg-core/columns/varchar.ts | 53 +- .../pg-core/columns/vector_extension/bit.ts | 41 +- .../columns/vector_extension/halfvec.ts | 40 +- .../columns/vector_extension/vector.ts | 45 +- .../src/singlestore-core/columns/bigint.ts | 1 - .../src/singlestore-core/columns/common.ts | 5 +- drizzle-orm/src/sqlite-core/columns/common.ts | 5 +- drizzle-orm/src/sqlite-core/columns/text.ts | 44 +- drizzle-orm/type-tests/mysql/tables.ts | 114 +-- drizzle-orm/type-tests/pg/array.ts | 4 +- drizzle-orm/type-tests/singlestore/tables.ts | 115 +-- drizzle-typebox/README.md | 15 +- drizzle-typebox/package.json | 7 +- drizzle-typebox/rollup.config.ts | 4 +- drizzle-typebox/scripts/build.ts | 1 + drizzle-typebox/scripts/fix-imports.ts | 136 +++ drizzle-typebox/src/column.ts | 259 ++++++ drizzle-typebox/src/column.types.ts | 100 +++ drizzle-typebox/src/constants.ts | 20 + drizzle-typebox/src/index.ts | 346 +------- drizzle-typebox/src/schema.ts | 144 ++++ drizzle-typebox/src/schema.types.internal.ts | 88 ++ drizzle-typebox/src/schema.types.ts | 53 ++ drizzle-typebox/src/utils.ts | 50 ++ drizzle-typebox/tests/mysql.test.ts | 791 +++++++++-------- drizzle-typebox/tests/pg.test.ts | 691 +++++++++++---- drizzle-typebox/tests/sqlite.test.ts | 512 +++++++---- drizzle-typebox/tests/utils.ts | 33 +- drizzle-typebox/tsconfig.json | 1 + drizzle-valibot/README.md | 13 +- drizzle-valibot/package.json | 7 +- drizzle-valibot/rollup.config.ts | 4 +- drizzle-valibot/scripts/build.ts | 1 + drizzle-valibot/scripts/fix-imports.ts | 136 +++ drizzle-valibot/src/column.ts | 239 +++++ drizzle-valibot/src/column.types.ts | 202 +++++ drizzle-valibot/src/constants.ts | 20 + drizzle-valibot/src/index.ts | 334 +------ drizzle-valibot/src/schema.ts | 95 ++ drizzle-valibot/src/schema.types.internal.ts | 105 +++ drizzle-valibot/src/schema.types.ts | 49 ++ drizzle-valibot/src/utils.ts | 45 + drizzle-valibot/tests/mysql.test.ts | 814 ++++++++++-------- drizzle-valibot/tests/pg.test.ts | 682 +++++++++++---- drizzle-valibot/tests/sqlite.test.ts | 500 +++++++---- drizzle-valibot/tests/utils.ts | 39 +- drizzle-valibot/tsconfig.json | 1 + drizzle-zod/README.md | 17 +- drizzle-zod/package.json | 5 +- drizzle-zod/rollup.config.ts | 2 - drizzle-zod/scripts/build.ts | 1 + drizzle-zod/scripts/fix-imports.ts | 136 +++ drizzle-zod/src/column.ts | 227 +++++ drizzle-zod/src/column.types.ts | 76 ++ drizzle-zod/src/constants.ts | 20 + drizzle-zod/src/index.ts | 241 +----- drizzle-zod/src/schema.ts | 143 +++ drizzle-zod/src/schema.types.internal.ts | 88 ++ drizzle-zod/src/schema.types.ts | 52 ++ drizzle-zod/src/utils.ts | 40 + drizzle-zod/tests/mysql.test.ts | 676 +++++++++------ drizzle-zod/tests/pg.test.ts | 586 ++++++++++--- drizzle-zod/tests/sqlite.test.ts | 443 +++++++--- drizzle-zod/tests/utils.ts | 15 +- drizzle-zod/tsconfig.build.json | 3 +- drizzle-zod/tsconfig.json | 1 + pnpm-lock.yaml | 93 +- 75 files changed, 6904 insertions(+), 3218 deletions(-) create mode 100755 drizzle-typebox/scripts/fix-imports.ts create mode 100644 drizzle-typebox/src/column.ts create mode 100644 drizzle-typebox/src/column.types.ts create mode 100644 drizzle-typebox/src/constants.ts create mode 100644 drizzle-typebox/src/schema.ts create mode 100644 drizzle-typebox/src/schema.types.internal.ts create mode 100644 drizzle-typebox/src/schema.types.ts create mode 100644 drizzle-typebox/src/utils.ts create mode 100755 drizzle-valibot/scripts/fix-imports.ts create mode 100644 drizzle-valibot/src/column.ts create mode 100644 drizzle-valibot/src/column.types.ts create mode 100644 drizzle-valibot/src/constants.ts create mode 100644 drizzle-valibot/src/schema.ts create mode 100644 drizzle-valibot/src/schema.types.internal.ts create mode 100644 drizzle-valibot/src/schema.types.ts create mode 100644 drizzle-valibot/src/utils.ts create mode 100755 drizzle-zod/scripts/fix-imports.ts create mode 100644 drizzle-zod/src/column.ts create mode 100644 drizzle-zod/src/column.types.ts create mode 100644 drizzle-zod/src/constants.ts create mode 100644 drizzle-zod/src/schema.ts create mode 100644 drizzle-zod/src/schema.types.internal.ts create mode 100644 drizzle-zod/src/schema.types.ts create mode 100644 drizzle-zod/src/utils.ts diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index 207f28026..6d6dfeeba 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -313,11 +313,49 @@ export type BuildColumn< TTableName extends string, TBuilder extends ColumnBuilderBase, TDialect extends Dialect, -> = TDialect extends 'pg' ? PgColumn> - : TDialect extends 'mysql' ? MySqlColumn> - : TDialect extends 'singlestore' ? SingleStoreColumn> - : TDialect extends 'sqlite' ? SQLiteColumn> - : TDialect extends 'common' ? Column> +> = TDialect extends 'pg' ? PgColumn< + MakeColumnConfig, + {}, + Simplify | 'brand' | 'dialect'>> + > + : TDialect extends 'mysql' ? MySqlColumn< + MakeColumnConfig, + {}, + Simplify< + Omit< + TBuilder['_'], + | keyof MakeColumnConfig + | 'brand' + | 'dialect' + | 'primaryKeyHasDefault' + | 'mysqlColumnBuilderBrand' + > + > + > + : TDialect extends 'sqlite' ? SQLiteColumn< + MakeColumnConfig, + {}, + Simplify | 'brand' | 'dialect'>> + > + : TDialect extends 'common' ? Column< + MakeColumnConfig, + {}, + Simplify | 'brand' | 'dialect'>> + > + : TDialect extends 'singlestore' ? SingleStoreColumn< + MakeColumnConfig, + {}, + Simplify< + Omit< + TBuilder['_'], + | keyof MakeColumnConfig + | 'brand' + | 'dialect' + | 'primaryKeyHasDefault' + | 'singlestoreColumnBuilderBrand' + > + > + > : never; export type BuildIndexColumn< diff --git a/drizzle-orm/src/mysql-core/columns/all.ts b/drizzle-orm/src/mysql-core/columns/all.ts index 428b3c330..44c03eff0 100644 --- a/drizzle-orm/src/mysql-core/columns/all.ts +++ b/drizzle-orm/src/mysql-core/columns/all.ts @@ -15,7 +15,7 @@ import { mediumint } from './mediumint.ts'; import { real } from './real.ts'; import { serial } from './serial.ts'; import { smallint } from './smallint.ts'; -import { text } from './text.ts'; +import { longtext, mediumtext, text, tinytext } from './text.ts'; import { time } from './time.ts'; import { timestamp } from './timestamp.ts'; import { tinyint } from './tinyint.ts'; @@ -49,6 +49,9 @@ export function getMySqlColumnBuilders() { varbinary, varchar, year, + longtext, + mediumtext, + tinytext, }; } diff --git a/drizzle-orm/src/mysql-core/columns/char.ts b/drizzle-orm/src/mysql-core/columns/char.ts index 88492288e..55743a5d4 100644 --- a/drizzle-orm/src/mysql-core/columns/char.ts +++ b/drizzle-orm/src/mysql-core/columns/char.ts @@ -5,22 +5,30 @@ import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; -export type MySqlCharBuilderInitial = MySqlCharBuilder<{ +export type MySqlCharBuilderInitial< + TName extends string, + TEnum extends [string, ...string[]], + TLength extends number | undefined, +> = MySqlCharBuilder<{ name: TName; dataType: 'string'; columnType: 'MySqlChar'; data: TEnum[number]; driverParam: number | string; enumValues: TEnum; + length: TLength; }>; -export class MySqlCharBuilder> extends MySqlColumnBuilder< +export class MySqlCharBuilder< + T extends ColumnBuilderBaseConfig<'string', 'MySqlChar'> & { length?: number | undefined }, +> extends MySqlColumnBuilder< T, - MySqlCharConfig + MySqlCharConfig, + { length: T['length'] } > { static override readonly [entityKind]: string = 'MySqlCharBuilder'; - constructor(name: T['name'], config: MySqlCharConfig) { + constructor(name: T['name'], config: MySqlCharConfig) { super(name, 'string', 'MySqlChar'); this.config.length = config.length; this.config.enum = config.enum; @@ -29,20 +37,20 @@ export class MySqlCharBuilder( table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlChar & { enumValues: T['enumValues'] }> { - return new MySqlChar & { enumValues: T['enumValues'] }>( + ): MySqlChar & { length: T['length']; enumValues: T['enumValues'] }> { + return new MySqlChar & { length: T['length']; enumValues: T['enumValues'] }>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlChar> - extends MySqlColumn> +export class MySqlChar & { length?: number | undefined }> + extends MySqlColumn, { length: T['length'] }> { static override readonly [entityKind]: string = 'MySqlChar'; - readonly length: number | undefined = this.config.length; + readonly length: T['length'] = this.config.length; override readonly enumValues = this.config.enum; getSQLType(): string { @@ -52,19 +60,25 @@ export class MySqlChar> export interface MySqlCharConfig< TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, + TLength extends number | undefined = number | undefined, > { - length?: number; enum?: TEnum; + length?: TLength; } -export function char(): MySqlCharBuilderInitial<'', [string, ...string[]]>; -export function char>( - config?: MySqlCharConfig>, -): MySqlCharBuilderInitial<'', Writable>; -export function char>( +export function char(): MySqlCharBuilderInitial<'', [string, ...string[]], undefined>; +export function char, L extends number | undefined>( + config?: MySqlCharConfig, L>, +): MySqlCharBuilderInitial<'', Writable, L>; +export function char< + TName extends string, + U extends string, + T extends Readonly<[U, ...U[]]>, + L extends number | undefined, +>( name: TName, - config?: MySqlCharConfig>, -): MySqlCharBuilderInitial>; + config?: MySqlCharConfig, L>, +): MySqlCharBuilderInitial, L>; export function char(a?: string | MySqlCharConfig, b: MySqlCharConfig = {}): any { const { name, config } = getColumnNameAndConfig(a, b); return new MySqlCharBuilder(name, config as any); diff --git a/drizzle-orm/src/mysql-core/columns/common.ts b/drizzle-orm/src/mysql-core/columns/common.ts index 2f1073e53..289c420ae 100644 --- a/drizzle-orm/src/mysql-core/columns/common.ts +++ b/drizzle-orm/src/mysql-core/columns/common.ts @@ -101,8 +101,9 @@ export abstract class MySqlColumnBuilder< // To understand how to use `MySqlColumn` and `AnyMySqlColumn`, see `Column` and `AnyColumn` documentation. export abstract class MySqlColumn< T extends ColumnBaseConfig = ColumnBaseConfig, - TRuntimeConfig extends object = object, -> extends Column { + TRuntimeConfig extends object = {}, + TTypeConfig extends object = {}, +> extends Column { static override readonly [entityKind]: string = 'MySqlColumn'; constructor( diff --git a/drizzle-orm/src/mysql-core/columns/text.ts b/drizzle-orm/src/mysql-core/columns/text.ts index 0604ef141..6106fd45b 100644 --- a/drizzle-orm/src/mysql-core/columns/text.ts +++ b/drizzle-orm/src/mysql-core/columns/text.ts @@ -41,7 +41,7 @@ export class MySqlText> { static override readonly [entityKind]: string = 'MySqlText'; - private textType: MySqlTextColumnType = this.config.textType; + readonly textType: MySqlTextColumnType = this.config.textType; override readonly enumValues = this.config.enumValues; diff --git a/drizzle-orm/src/mysql-core/columns/varchar.ts b/drizzle-orm/src/mysql-core/columns/varchar.ts index 6a335fef7..0a0bde857 100644 --- a/drizzle-orm/src/mysql-core/columns/varchar.ts +++ b/drizzle-orm/src/mysql-core/columns/varchar.ts @@ -5,7 +5,11 @@ import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; -export type MySqlVarCharBuilderInitial = MySqlVarCharBuilder< +export type MySqlVarCharBuilderInitial< + TName extends string, + TEnum extends [string, ...string[]], + TLength extends number | undefined, +> = MySqlVarCharBuilder< { name: TName; dataType: 'string'; @@ -13,16 +17,17 @@ export type MySqlVarCharBuilderInitial; -export class MySqlVarCharBuilder> - extends MySqlColumnBuilder> -{ +export class MySqlVarCharBuilder< + T extends ColumnBuilderBaseConfig<'string', 'MySqlVarChar'> & { length?: number | undefined }, +> extends MySqlColumnBuilder> { static override readonly [entityKind]: string = 'MySqlVarCharBuilder'; /** @internal */ - constructor(name: T['name'], config: MySqlVarCharConfig) { + constructor(name: T['name'], config: MySqlVarCharConfig) { super(name, 'string', 'MySqlVarChar'); this.config.length = config.length; this.config.enum = config.enum; @@ -31,16 +36,16 @@ export class MySqlVarCharBuilder( table: AnyMySqlTable<{ name: TTableName }>, - ): MySqlVarChar & { enumValues: T['enumValues'] }> { - return new MySqlVarChar & { enumValues: T['enumValues'] }>( + ): MySqlVarChar & { length: T['length']; enumValues: T['enumValues'] }> { + return new MySqlVarChar & { length: T['length']; enumValues: T['enumValues'] }>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class MySqlVarChar> - extends MySqlColumn> +export class MySqlVarChar & { length?: number | undefined }> + extends MySqlColumn, { length: T['length'] }> { static override readonly [entityKind]: string = 'MySqlVarChar'; @@ -55,18 +60,24 @@ export class MySqlVarChar> export interface MySqlVarCharConfig< TEnum extends string[] | readonly string[] | undefined = string[] | readonly string[] | undefined, + TLength extends number | undefined = number | undefined, > { - length: number; enum?: TEnum; + length?: TLength; } -export function varchar>( - config: MySqlVarCharConfig>, -): MySqlVarCharBuilderInitial<'', Writable>; -export function varchar>( +export function varchar, L extends number | undefined>( + config: MySqlVarCharConfig, L>, +): MySqlVarCharBuilderInitial<'', Writable, L>; +export function varchar< + TName extends string, + U extends string, + T extends Readonly<[U, ...U[]]>, + L extends number | undefined, +>( name: TName, - config: MySqlVarCharConfig>, -): MySqlVarCharBuilderInitial>; + config: MySqlVarCharConfig, L>, +): MySqlVarCharBuilderInitial, L>; export function varchar(a?: string | MySqlVarCharConfig, b?: MySqlVarCharConfig): any { const { name, config } = getColumnNameAndConfig(a, b); return new MySqlVarCharBuilder(name, config as any); diff --git a/drizzle-orm/src/pg-core/columns/char.ts b/drizzle-orm/src/pg-core/columns/char.ts index 2cc304221..e362e2f42 100644 --- a/drizzle-orm/src/pg-core/columns/char.ts +++ b/drizzle-orm/src/pg-core/columns/char.ts @@ -5,22 +5,30 @@ import type { AnyPgTable } from '~/pg-core/table.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; -export type PgCharBuilderInitial = PgCharBuilder<{ +export type PgCharBuilderInitial< + TName extends string, + TEnum extends [string, ...string[]], + TLength extends number | undefined, +> = PgCharBuilder<{ name: TName; dataType: 'string'; columnType: 'PgChar'; data: TEnum[number]; enumValues: TEnum; driverParam: string; + length: TLength; }>; -export class PgCharBuilder> extends PgColumnBuilder< - T, - { length: number | undefined; enumValues: T['enumValues'] } -> { +export class PgCharBuilder & { length?: number | undefined }> + extends PgColumnBuilder< + T, + { length: T['length']; enumValues: T['enumValues'] }, + { length: T['length'] } + > +{ static override readonly [entityKind]: string = 'PgCharBuilder'; - constructor(name: T['name'], config: PgCharConfig) { + constructor(name: T['name'], config: PgCharConfig) { super(name, 'string', 'PgChar'); this.config.length = config.length; this.config.enumValues = config.enum; @@ -29,13 +37,16 @@ export class PgCharBuilder /** @internal */ override build( table: AnyPgTable<{ name: TTableName }>, - ): PgChar> { - return new PgChar>(table, this.config as ColumnBuilderRuntimeConfig); + ): PgChar & { length: T['length'] }> { + return new PgChar & { length: T['length'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class PgChar> - extends PgColumn +export class PgChar & { length?: number | undefined }> + extends PgColumn { static override readonly [entityKind]: string = 'PgChar'; @@ -49,19 +60,25 @@ export class PgChar> export interface PgCharConfig< TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, + TLength extends number | undefined = number | undefined, > { - length?: number; enum?: TEnum; + length?: TLength; } -export function char(): PgCharBuilderInitial<'', [string, ...string[]]>; -export function char>( - config?: PgCharConfig>, -): PgCharBuilderInitial<'', Writable>; -export function char>( +export function char(): PgCharBuilderInitial<'', [string, ...string[]], undefined>; +export function char, L extends number | undefined>( + config?: PgCharConfig, L>, +): PgCharBuilderInitial<'', Writable, L>; +export function char< + TName extends string, + U extends string, + T extends Readonly<[U, ...U[]]>, + L extends number | undefined, +>( name: TName, - config?: PgCharConfig>, -): PgCharBuilderInitial>; + config?: PgCharConfig, L>, +): PgCharBuilderInitial, L>; export function char(a?: string | PgCharConfig, b: PgCharConfig = {}): any { const { name, config } = getColumnNameAndConfig(a, b); return new PgCharBuilder(name, config as any); diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index d9384b344..aa1d6c1f2 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -11,7 +11,7 @@ import { ColumnBuilder } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { Column } from '~/column.ts'; import { entityKind, is } from '~/entity.ts'; -import type { Update } from '~/utils.ts'; +import type { Simplify, Update } from '~/utils.ts'; import type { ForeignKey, UpdateDeleteAction } from '~/pg-core/foreign-keys.ts'; import { ForeignKeyBuilder } from '~/pg-core/foreign-keys.ts'; @@ -47,7 +47,7 @@ export abstract class PgColumnBuilder< static override readonly [entityKind]: string = 'PgColumnBuilder'; - array(size?: number): PgArrayBuilder< + array(size?: TSize): PgArrayBuilder< & { name: T['name']; dataType: 'array'; @@ -55,12 +55,14 @@ export abstract class PgColumnBuilder< data: T['data'][]; driverParam: T['driverParam'][] | string; enumValues: T['enumValues']; + size: TSize; + baseBuilder: T; } & (T extends { notNull: true } ? { notNull: true } : {}) & (T extends { hasDefault: true } ? { hasDefault: true } : {}), T > { - return new PgArrayBuilder(this.config.name, this as PgColumnBuilder, size); + return new PgArrayBuilder(this.config.name, this as PgColumnBuilder, size as any); } references( @@ -250,17 +252,33 @@ export type AnyPgColumn, TPartial>> >; +export type PgArrayColumnBuilderBaseConfig = ColumnBuilderBaseConfig<'array', 'PgArray'> & { + size: number | undefined; + baseBuilder: ColumnBuilderBaseConfig; +}; + export class PgArrayBuilder< - T extends ColumnBuilderBaseConfig<'array', 'PgArray'>, - TBase extends ColumnBuilderBaseConfig, + T extends PgArrayColumnBuilderBaseConfig, + TBase extends ColumnBuilderBaseConfig | PgArrayColumnBuilderBaseConfig, > extends PgColumnBuilder< T, { - baseBuilder: PgColumnBuilder; - size: number | undefined; + baseBuilder: TBase extends PgArrayColumnBuilderBaseConfig ? PgArrayBuilder< + TBase, + TBase extends { baseBuilder: infer TBaseBuilder extends ColumnBuilderBaseConfig } ? TBaseBuilder + : never + > + : PgColumnBuilder>>>; + size: T['size']; }, { - baseBuilder: PgColumnBuilder; + baseBuilder: TBase extends PgArrayColumnBuilderBaseConfig ? PgArrayBuilder< + TBase, + TBase extends { baseBuilder: infer TBaseBuilder extends ColumnBuilderBaseConfig } ? TBaseBuilder + : never + > + : PgColumnBuilder>>>; + size: T['size']; } > { static override readonly [entityKind] = 'PgArrayBuilder'; @@ -268,7 +286,7 @@ export class PgArrayBuilder< constructor( name: string, baseBuilder: PgArrayBuilder['config']['baseBuilder'], - size: number | undefined, + size: T['size'], ) { super(name, 'array', 'PgArray'); this.config.baseBuilder = baseBuilder; @@ -278,9 +296,9 @@ export class PgArrayBuilder< /** @internal */ override build( table: AnyPgTable<{ name: TTableName }>, - ): PgArray, TBase> { + ): PgArray & { size: T['size']; baseBuilder: T['baseBuilder'] }, TBase> { const baseColumn = this.config.baseBuilder.build(table); - return new PgArray, TBase>( + return new PgArray & { size: T['size']; baseBuilder: T['baseBuilder'] }, TBase>( table as AnyPgTable<{ name: MakeColumnConfig['tableName'] }>, this.config as ColumnBuilderRuntimeConfig, baseColumn, @@ -289,10 +307,13 @@ export class PgArrayBuilder< } export class PgArray< - T extends ColumnBaseConfig<'array', 'PgArray'>, + T extends ColumnBaseConfig<'array', 'PgArray'> & { + size: number | undefined; + baseBuilder: ColumnBuilderBaseConfig; + }, TBase extends ColumnBuilderBaseConfig, -> extends PgColumn { - readonly size: number | undefined; +> extends PgColumn { + readonly size: T['size']; static override readonly [entityKind]: string = 'PgArray'; diff --git a/drizzle-orm/src/pg-core/columns/varchar.ts b/drizzle-orm/src/pg-core/columns/varchar.ts index 192262bef..6c2042ae4 100644 --- a/drizzle-orm/src/pg-core/columns/varchar.ts +++ b/drizzle-orm/src/pg-core/columns/varchar.ts @@ -5,22 +5,30 @@ import type { AnyPgTable } from '~/pg-core/table.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; -export type PgVarcharBuilderInitial = PgVarcharBuilder<{ +export type PgVarcharBuilderInitial< + TName extends string, + TEnum extends [string, ...string[]], + TLength extends number | undefined, +> = PgVarcharBuilder<{ name: TName; dataType: 'string'; columnType: 'PgVarchar'; data: TEnum[number]; driverParam: string; enumValues: TEnum; + length: TLength; }>; -export class PgVarcharBuilder> extends PgColumnBuilder< +export class PgVarcharBuilder< + T extends ColumnBuilderBaseConfig<'string', 'PgVarchar'> & { length?: number | undefined }, +> extends PgColumnBuilder< T, - { length: number | undefined; enumValues: T['enumValues'] } + { length: T['length']; enumValues: T['enumValues'] }, + { length: T['length'] } > { static override readonly [entityKind]: string = 'PgVarcharBuilder'; - constructor(name: T['name'], config: PgVarcharConfig) { + constructor(name: T['name'], config: PgVarcharConfig) { super(name, 'string', 'PgVarchar'); this.config.length = config.length; this.config.enumValues = config.enum; @@ -29,13 +37,16 @@ export class PgVarcharBuilder( table: AnyPgTable<{ name: TTableName }>, - ): PgVarchar> { - return new PgVarchar>(table, this.config as ColumnBuilderRuntimeConfig); + ): PgVarchar & { length: T['length'] }> { + return new PgVarchar & { length: T['length'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class PgVarchar> - extends PgColumn +export class PgVarchar & { length?: number | undefined }> + extends PgColumn { static override readonly [entityKind]: string = 'PgVarchar'; @@ -49,19 +60,29 @@ export class PgVarchar> export interface PgVarcharConfig< TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, + TLength extends number | undefined = number | undefined, > { - length?: number; enum?: TEnum; + length?: TLength; } -export function varchar(): PgVarcharBuilderInitial<'', [string, ...string[]]>; -export function varchar>( - config?: PgVarcharConfig>, -): PgVarcharBuilderInitial<'', Writable>; -export function varchar>( +export function varchar(): PgVarcharBuilderInitial<'', [string, ...string[]], undefined>; +export function varchar< + U extends string, + T extends Readonly<[U, ...U[]]>, + L extends number | undefined, +>( + config?: PgVarcharConfig, L>, +): PgVarcharBuilderInitial<'', Writable, L>; +export function varchar< + TName extends string, + U extends string, + T extends Readonly<[U, ...U[]]>, + L extends number | undefined, +>( name: TName, - config?: PgVarcharConfig>, -): PgVarcharBuilderInitial>; + config?: PgVarcharConfig, L>, +): PgVarcharBuilderInitial, L>; export function varchar(a?: string | PgVarcharConfig, b: PgVarcharConfig = {}): any { const { name, config } = getColumnNameAndConfig(a, b); return new PgVarcharBuilder(name, config as any); diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts index f1d692821..a3bdd6bdf 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/bit.ts @@ -5,24 +5,25 @@ import type { AnyPgTable } from '~/pg-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; -export type PgBinaryVectorBuilderInitial = PgBinaryVectorBuilder<{ +export type PgBinaryVectorBuilderInitial = PgBinaryVectorBuilder<{ name: TName; dataType: 'string'; columnType: 'PgBinaryVector'; data: string; driverParam: string; enumValues: undefined; + dimensions: TDimensions; }>; -export class PgBinaryVectorBuilder> - extends PgColumnBuilder< - T, - { dimensions: number | undefined } - > -{ +export class PgBinaryVectorBuilder< + T extends ColumnBuilderBaseConfig<'string', 'PgBinaryVector'> & { dimensions: number }, +> extends PgColumnBuilder< + T, + { dimensions: T['dimensions'] } +> { static override readonly [entityKind]: string = 'PgBinaryVectorBuilder'; - constructor(name: string, config: PgBinaryVectorConfig) { + constructor(name: string, config: PgBinaryVectorConfig) { super(name, 'string', 'PgBinaryVector'); this.config.dimensions = config.dimensions; } @@ -30,16 +31,16 @@ export class PgBinaryVectorBuilder( table: AnyPgTable<{ name: TTableName }>, - ): PgBinaryVector> { - return new PgBinaryVector>( + ): PgBinaryVector & { dimensions: T['dimensions'] }> { + return new PgBinaryVector & { dimensions: T['dimensions'] }>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class PgBinaryVector> - extends PgColumn +export class PgBinaryVector & { dimensions: number }> + extends PgColumn { static override readonly [entityKind]: string = 'PgBinaryVector'; @@ -50,17 +51,17 @@ export class PgBinaryVector { + dimensions: TDimensions; } -export function bit( - config: PgBinaryVectorConfig, -): PgBinaryVectorBuilderInitial<''>; -export function bit( +export function bit( + config: PgBinaryVectorConfig, +): PgBinaryVectorBuilderInitial<'', D>; +export function bit( name: TName, - config: PgBinaryVectorConfig, -): PgBinaryVectorBuilderInitial; + config: PgBinaryVectorConfig, +): PgBinaryVectorBuilderInitial; export function bit(a: string | PgBinaryVectorConfig, b?: PgBinaryVectorConfig) { const { name, config } = getColumnNameAndConfig(a, b); return new PgBinaryVectorBuilder(name, config); diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts index 1c89e7b60..5f52f5f16 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/halfvec.ts @@ -5,22 +5,26 @@ import type { AnyPgTable } from '~/pg-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; -export type PgHalfVectorBuilderInitial = PgHalfVectorBuilder<{ +export type PgHalfVectorBuilderInitial = PgHalfVectorBuilder<{ name: TName; dataType: 'array'; columnType: 'PgHalfVector'; data: number[]; driverParam: string; enumValues: undefined; + dimensions: TDimensions; }>; -export class PgHalfVectorBuilder> extends PgColumnBuilder< - T, - { dimensions: number | undefined } -> { +export class PgHalfVectorBuilder & { dimensions: number }> + extends PgColumnBuilder< + T, + { dimensions: T['dimensions'] }, + { dimensions: T['dimensions'] } + > +{ static override readonly [entityKind]: string = 'PgHalfVectorBuilder'; - constructor(name: string, config: PgHalfVectorConfig) { + constructor(name: string, config: PgHalfVectorConfig) { super(name, 'array', 'PgHalfVector'); this.config.dimensions = config.dimensions; } @@ -28,20 +32,20 @@ export class PgHalfVectorBuilder( table: AnyPgTable<{ name: TTableName }>, - ): PgHalfVector> { - return new PgHalfVector>( + ): PgHalfVector & { dimensions: T['dimensions'] }> { + return new PgHalfVector & { dimensions: T['dimensions'] }>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class PgHalfVector> - extends PgColumn +export class PgHalfVector & { dimensions: number }> + extends PgColumn { static override readonly [entityKind]: string = 'PgHalfVector'; - readonly dimensions = this.config.dimensions; + readonly dimensions: T['dimensions'] = this.config.dimensions; getSQLType(): string { return `halfvec(${this.dimensions})`; @@ -59,17 +63,17 @@ export class PgHalfVector> } } -export interface PgHalfVectorConfig { - dimensions: number; +export interface PgHalfVectorConfig { + dimensions: TDimensions; } -export function halfvec( - config: PgHalfVectorConfig, -): PgHalfVectorBuilderInitial<''>; -export function halfvec( +export function halfvec( + config: PgHalfVectorConfig, +): PgHalfVectorBuilderInitial<'', D>; +export function halfvec( name: TName, config: PgHalfVectorConfig, -): PgHalfVectorBuilderInitial; +): PgHalfVectorBuilderInitial; export function halfvec(a: string | PgHalfVectorConfig, b?: PgHalfVectorConfig) { const { name, config } = getColumnNameAndConfig(a, b); return new PgHalfVectorBuilder(name, config); diff --git a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts index 84fb54964..f36a9b1ca 100644 --- a/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts +++ b/drizzle-orm/src/pg-core/columns/vector_extension/vector.ts @@ -5,22 +5,26 @@ import type { AnyPgTable } from '~/pg-core/table.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from '../common.ts'; -export type PgVectorBuilderInitial = PgVectorBuilder<{ +export type PgVectorBuilderInitial = PgVectorBuilder<{ name: TName; dataType: 'array'; columnType: 'PgVector'; data: number[]; driverParam: string; enumValues: undefined; + dimensions: TDimensions; }>; -export class PgVectorBuilder> extends PgColumnBuilder< - T, - { dimensions: number | undefined } -> { +export class PgVectorBuilder & { dimensions: number }> + extends PgColumnBuilder< + T, + { dimensions: T['dimensions'] }, + { dimensions: T['dimensions'] } + > +{ static override readonly [entityKind]: string = 'PgVectorBuilder'; - constructor(name: string, config: PgVectorConfig) { + constructor(name: string, config: PgVectorConfig) { super(name, 'array', 'PgVector'); this.config.dimensions = config.dimensions; } @@ -28,17 +32,20 @@ export class PgVectorBuilder( table: AnyPgTable<{ name: TTableName }>, - ): PgVector> { - return new PgVector>(table, this.config as ColumnBuilderRuntimeConfig); + ): PgVector & { dimensions: T['dimensions'] }> { + return new PgVector & { dimensions: T['dimensions'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class PgVector> - extends PgColumn +export class PgVector & { dimensions: number | undefined }> + extends PgColumn { static override readonly [entityKind]: string = 'PgVector'; - readonly dimensions = this.config.dimensions; + readonly dimensions: T['dimensions'] = this.config.dimensions; getSQLType(): string { return `vector(${this.dimensions})`; @@ -56,17 +63,17 @@ export class PgVector> } } -export interface PgVectorConfig { - dimensions: number; +export interface PgVectorConfig { + dimensions: TDimensions; } -export function vector( - config: PgVectorConfig, -): PgVectorBuilderInitial<''>; -export function vector( +export function vector( + config: PgVectorConfig, +): PgVectorBuilderInitial<'', D>; +export function vector( name: TName, - config: PgVectorConfig, -): PgVectorBuilderInitial; + config: PgVectorConfig, +): PgVectorBuilderInitial; export function vector(a: string | PgVectorConfig, b?: PgVectorConfig) { const { name, config } = getColumnNameAndConfig(a, b); return new PgVectorBuilder(name, config); diff --git a/drizzle-orm/src/singlestore-core/columns/bigint.ts b/drizzle-orm/src/singlestore-core/columns/bigint.ts index 1e6b64c49..fed436993 100644 --- a/drizzle-orm/src/singlestore-core/columns/bigint.ts +++ b/drizzle-orm/src/singlestore-core/columns/bigint.ts @@ -12,7 +12,6 @@ export type SingleStoreBigInt53BuilderInitial = SingleStor data: number; driverParam: number | string; enumValues: undefined; - generated: undefined; }>; export class SingleStoreBigInt53Builder> diff --git a/drizzle-orm/src/singlestore-core/columns/common.ts b/drizzle-orm/src/singlestore-core/columns/common.ts index c0dc7fb67..7f2a521e5 100644 --- a/drizzle-orm/src/singlestore-core/columns/common.ts +++ b/drizzle-orm/src/singlestore-core/columns/common.ts @@ -64,8 +64,9 @@ export abstract class SingleStoreColumnBuilder< // To understand how to use `SingleStoreColumn` and `AnySingleStoreColumn`, see `Column` and `AnyColumn` documentation. export abstract class SingleStoreColumn< T extends ColumnBaseConfig = ColumnBaseConfig, - TRuntimeConfig extends object = object, -> extends Column { + TRuntimeConfig extends object = {}, + TTypeConfig extends object = {}, +> extends Column { static override readonly [entityKind]: string = 'SingleStoreColumn'; constructor( diff --git a/drizzle-orm/src/sqlite-core/columns/common.ts b/drizzle-orm/src/sqlite-core/columns/common.ts index 953e5692d..8eacb8c93 100644 --- a/drizzle-orm/src/sqlite-core/columns/common.ts +++ b/drizzle-orm/src/sqlite-core/columns/common.ts @@ -102,8 +102,9 @@ export abstract class SQLiteColumnBuilder< // To understand how to use `SQLiteColumn` and `AnySQLiteColumn`, see `Column` and `AnyColumn` documentation. export abstract class SQLiteColumn< T extends ColumnBaseConfig = ColumnBaseConfig, - TRuntimeConfig extends object = object, -> extends Column { + TRuntimeConfig extends object = {}, + TTypeConfig extends object = {}, +> extends Column { static override readonly [entityKind]: string = 'SQLiteColumn'; constructor( diff --git a/drizzle-orm/src/sqlite-core/columns/text.ts b/drizzle-orm/src/sqlite-core/columns/text.ts index 241eb860d..0696b76f8 100644 --- a/drizzle-orm/src/sqlite-core/columns/text.ts +++ b/drizzle-orm/src/sqlite-core/columns/text.ts @@ -5,22 +5,30 @@ import type { AnySQLiteTable } from '~/sqlite-core/table.ts'; import { type Equal, getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; -export type SQLiteTextBuilderInitial = SQLiteTextBuilder<{ +export type SQLiteTextBuilderInitial< + TName extends string, + TEnum extends [string, ...string[]], + TLength extends number | undefined, +> = SQLiteTextBuilder<{ name: TName; dataType: 'string'; columnType: 'SQLiteText'; data: TEnum[number]; driverParam: string; enumValues: TEnum; + length: TLength; }>; -export class SQLiteTextBuilder> extends SQLiteColumnBuilder< +export class SQLiteTextBuilder< + T extends ColumnBuilderBaseConfig<'string', 'SQLiteText'> & { length?: number | undefined }, +> extends SQLiteColumnBuilder< T, - { length: number | undefined; enumValues: T['enumValues'] } + { length: T['length']; enumValues: T['enumValues'] }, + { length: T['length'] } > { static override readonly [entityKind]: string = 'SQLiteTextBuilder'; - constructor(name: T['name'], config: SQLiteTextConfig<'text', T['enumValues']>) { + constructor(name: T['name'], config: SQLiteTextConfig<'text', T['enumValues'], T['length']>) { super(name, 'string', 'SQLiteText'); this.config.enumValues = config.enum; this.config.length = config.length; @@ -29,19 +37,22 @@ export class SQLiteTextBuilder( table: AnySQLiteTable<{ name: TTableName }>, - ): SQLiteText> { - return new SQLiteText>(table, this.config as ColumnBuilderRuntimeConfig); + ): SQLiteText & { length: T['length'] }> { + return new SQLiteText & { length: T['length'] }>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class SQLiteText> - extends SQLiteColumn +export class SQLiteText & { length?: number | undefined }> + extends SQLiteColumn { static override readonly [entityKind]: string = 'SQLiteText'; override readonly enumValues = this.config.enumValues; - readonly length: number | undefined = this.config.length; + readonly length: T['length'] = this.config.length; constructor( table: AnySQLiteTable<{ name: T['tableName'] }>, @@ -106,34 +117,37 @@ export class SQLiteTextJson export type SQLiteTextConfig< TMode extends 'text' | 'json' = 'text' | 'json', TEnum extends readonly string[] | string[] | undefined = readonly string[] | string[] | undefined, + TLength extends number | undefined = number | undefined, > = TMode extends 'text' ? { mode?: TMode; - length?: number; + length?: TLength; enum?: TEnum; } : { mode?: TMode; }; -export function text(): SQLiteTextBuilderInitial<'', [string, ...string[]]>; +export function text(): SQLiteTextBuilderInitial<'', [string, ...string[]], undefined>; export function text< U extends string, T extends Readonly<[U, ...U[]]>, + L extends number | undefined, TMode extends 'text' | 'json' = 'text' | 'json', >( - config?: SQLiteTextConfig>, + config?: SQLiteTextConfig, L>, ): Equal extends true ? SQLiteTextJsonBuilderInitial<''> - : SQLiteTextBuilderInitial<'', Writable>; + : SQLiteTextBuilderInitial<'', Writable, L>; export function text< TName extends string, U extends string, T extends Readonly<[U, ...U[]]>, + L extends number | undefined, TMode extends 'text' | 'json' = 'text' | 'json', >( name: TName, - config?: SQLiteTextConfig>, + config?: SQLiteTextConfig, L>, ): Equal extends true ? SQLiteTextJsonBuilderInitial - : SQLiteTextBuilderInitial>; + : SQLiteTextBuilderInitial, L>; export function text(a?: string | SQLiteTextConfig, b: SQLiteTextConfig = {}): any { const { name, config } = getColumnNameAndConfig(a, b); if (config.mode === 'json') { diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index 473976d1a..24ce2582b 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -91,57 +91,69 @@ export const cities = mysqlTable('cities_table', { Expect< Equal< { - id: MySqlColumn<{ - name: 'id'; - tableName: 'cities_table'; - dataType: 'number'; - columnType: 'MySqlSerial'; - data: number; - driverParam: number; - notNull: true; - hasDefault: true; - isPrimaryKey: true; - enumValues: undefined; - baseColumn: never; - generated: undefined; - identity: undefined; - isAutoincrement: true; - hasRuntimeDefault: false; - }, object>; - name: MySqlColumn<{ - name: 'name_db'; - tableName: 'cities_table'; - dataType: 'string'; - columnType: 'MySqlText'; - data: string; - driverParam: string; - notNull: true; - hasDefault: false; - isPrimaryKey: false; - enumValues: [string, ...string[]]; - baseColumn: never; - generated: undefined; - identity: undefined; - isAutoincrement: false; - hasRuntimeDefault: false; - }, object>; - population: MySqlColumn<{ - name: 'population'; - tableName: 'cities_table'; - dataType: 'number'; - columnType: 'MySqlInt'; - data: number; - driverParam: string | number; - notNull: false; - hasDefault: true; - isPrimaryKey: false; - enumValues: undefined; - baseColumn: never; - generated: undefined; - identity: undefined; - isAutoincrement: false; - hasRuntimeDefault: false; - }, object>; + id: MySqlColumn< + { + name: 'id'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'MySqlSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + isPrimaryKey: true; + enumValues: undefined; + baseColumn: never; + generated: undefined; + identity: undefined; + isAutoincrement: true; + hasRuntimeDefault: false; + }, + {}, + {} + >; + name: MySqlColumn< + { + name: 'name_db'; + tableName: 'cities_table'; + dataType: 'string'; + columnType: 'MySqlText'; + data: string; + driverParam: string; + notNull: true; + hasDefault: false; + isPrimaryKey: false; + enumValues: [string, ...string[]]; + baseColumn: never; + generated: undefined; + identity: undefined; + isAutoincrement: false; + hasRuntimeDefault: false; + }, + {}, + {} + >; + population: MySqlColumn< + { + name: 'population'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'MySqlInt'; + data: number; + driverParam: string | number; + notNull: false; + hasDefault: true; + isPrimaryKey: false; + enumValues: undefined; + baseColumn: never; + generated: undefined; + identity: undefined; + isAutoincrement: false; + hasRuntimeDefault: false; + }, + {}, + {} + >; }, typeof cities._.columns > diff --git a/drizzle-orm/type-tests/pg/array.ts b/drizzle-orm/type-tests/pg/array.ts index 586acb1c7..d7a34cb2b 100644 --- a/drizzle-orm/type-tests/pg/array.ts +++ b/drizzle-orm/type-tests/pg/array.ts @@ -25,7 +25,9 @@ import { integer, pgTable } from '~/pg-core/index.ts'; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; - } + }, + {}, + {} >, typeof table['a']['_']['baseColumn'] > diff --git a/drizzle-orm/type-tests/singlestore/tables.ts b/drizzle-orm/type-tests/singlestore/tables.ts index 43a1b05dc..f7d8e114f 100644 --- a/drizzle-orm/type-tests/singlestore/tables.ts +++ b/drizzle-orm/type-tests/singlestore/tables.ts @@ -81,57 +81,69 @@ export const cities = singlestoreTable('cities_table', { Expect< Equal< { - id: SingleStoreColumn<{ - name: 'id'; - tableName: 'cities_table'; - dataType: 'number'; - columnType: 'SingleStoreSerial'; - data: number; - driverParam: number; - notNull: true; - hasDefault: true; - isPrimaryKey: true; - isAutoincrement: true; - hasRuntimeDefault: false; - enumValues: undefined; - baseColumn: never; - identity: undefined; - generated: undefined; - }, object>; - name: SingleStoreColumn<{ - name: 'name_db'; - tableName: 'cities_table'; - dataType: 'string'; - columnType: 'SingleStoreText'; - data: string; - driverParam: string; - notNull: true; - hasDefault: false; - isPrimaryKey: false; - isAutoincrement: false; - hasRuntimeDefault: false; - enumValues: [string, ...string[]]; - baseColumn: never; - identity: undefined; - generated: undefined; - }, object>; - population: SingleStoreColumn<{ - name: 'population'; - tableName: 'cities_table'; - dataType: 'number'; - columnType: 'SingleStoreInt'; - data: number; - driverParam: string | number; - notNull: false; - hasDefault: true; - isPrimaryKey: false; - isAutoincrement: false; - hasRuntimeDefault: false; - enumValues: undefined; - baseColumn: never; - identity: undefined; - generated: undefined; - }, object>; + id: SingleStoreColumn< + { + name: 'id'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'SingleStoreSerial'; + data: number; + driverParam: number; + notNull: true; + hasDefault: true; + isPrimaryKey: true; + isAutoincrement: true; + hasRuntimeDefault: false; + enumValues: undefined; + baseColumn: never; + identity: undefined; + generated: undefined; + }, + {}, + {} + >; + name: SingleStoreColumn< + { + name: 'name_db'; + tableName: 'cities_table'; + dataType: 'string'; + columnType: 'SingleStoreText'; + data: string; + driverParam: string; + notNull: true; + hasDefault: false; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + enumValues: [string, ...string[]]; + baseColumn: never; + identity: undefined; + generated: undefined; + }, + {}, + {} + >; + population: SingleStoreColumn< + { + name: 'population'; + tableName: 'cities_table'; + dataType: 'number'; + columnType: 'SingleStoreInt'; + data: number; + driverParam: string | number; + notNull: false; + hasDefault: true; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + enumValues: undefined; + baseColumn: never; + identity: undefined; + generated: undefined; + }, + {}, + {} + >; }, typeof cities._.columns > @@ -500,6 +512,7 @@ Expect< }); const t = customText('name').notNull(); + Expect< Equal< { diff --git a/drizzle-typebox/README.md b/drizzle-typebox/README.md index 912a67f7f..72d85e684 100644 --- a/drizzle-typebox/README.md +++ b/drizzle-typebox/README.md @@ -1,10 +1,10 @@ `drizzle-typebox` is a plugin for [Drizzle ORM](https://github.com/drizzle-team/drizzle-orm) that allows you to generate [@sinclair/typebox](https://github.com/sinclairzx81/typebox) schemas from Drizzle ORM schemas. -| Database | Insert schema | Select schema | -| :--------- | :-----------: | :-----------: | -| PostgreSQL | ✅ | ✅ | -| MySQL | ✅ | ✅ | -| SQLite | ✅ | ✅ | +**Features** + +- Create a select schema for tables, views and enums. +- Create insert and update schemas for tables. +- Supports all dialects: PostgreSQL, MySQL and SQLite. # Usage @@ -25,6 +25,9 @@ const users = pgTable('users', { // Schema for inserting a user - can be used to validate API requests const insertUserSchema = createInsertSchema(users); +// Schema for updating a user - can be used to validate API requests +const updateUserSchema = createUpdateSchema(users); + // Schema for selecting a user - can be used to validate API responses const selectUserSchema = createSelectSchema(users); @@ -35,7 +38,7 @@ const insertUserSchema = createInsertSchema(users, { // Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema const insertUserSchema = createInsertSchema(users, { - id: (schema) => Type.Number({ minimum: 0 }), + id: (schema) => Type.Number({ ...schema, minimum: 0 }), role: Type.String(), }); diff --git a/drizzle-typebox/package.json b/drizzle-typebox/package.json index 5e812f4fe..25461ad15 100644 --- a/drizzle-typebox/package.json +++ b/drizzle-typebox/package.json @@ -55,13 +55,12 @@ "author": "Drizzle Team", "license": "Apache-2.0", "peerDependencies": { - "@sinclair/typebox": ">=0.17.6", - "drizzle-orm": ">=0.23.13" + "@sinclair/typebox": ">=0.34.8", + "drizzle-orm": ">=0.36.0" }, "devDependencies": { - "@rollup/plugin-terser": "^0.4.1", "@rollup/plugin-typescript": "^11.1.0", - "@sinclair/typebox": "^0.29.6", + "@sinclair/typebox": "^0.34.8", "@types/node": "^18.15.10", "cpy": "^10.1.0", "drizzle-orm": "link:../drizzle-orm/dist", diff --git a/drizzle-typebox/rollup.config.ts b/drizzle-typebox/rollup.config.ts index 2ed2d33d3..a29fdd38a 100644 --- a/drizzle-typebox/rollup.config.ts +++ b/drizzle-typebox/rollup.config.ts @@ -1,4 +1,3 @@ -import terser from '@rollup/plugin-terser'; import typescript from '@rollup/plugin-typescript'; import { defineConfig } from 'rollup'; @@ -23,13 +22,12 @@ export default defineConfig([ ], external: [ /^drizzle-orm\/?/, - 'zod', + '@sinclair/typebox', ], plugins: [ typescript({ tsconfig: 'tsconfig.build.json', }), - terser(), ], }, ]); diff --git a/drizzle-typebox/scripts/build.ts b/drizzle-typebox/scripts/build.ts index 1910feac6..07330ffd0 100644 --- a/drizzle-typebox/scripts/build.ts +++ b/drizzle-typebox/scripts/build.ts @@ -13,3 +13,4 @@ await cpy('dist/**/*.d.ts', 'dist', { rename: (basename) => basename.replace(/\.d\.ts$/, '.d.cts'), }); await fs.copy('package.json', 'dist/package.json'); +await $`scripts/fix-imports.ts`; diff --git a/drizzle-typebox/scripts/fix-imports.ts b/drizzle-typebox/scripts/fix-imports.ts new file mode 100755 index 000000000..a90057c5b --- /dev/null +++ b/drizzle-typebox/scripts/fix-imports.ts @@ -0,0 +1,136 @@ +#!/usr/bin/env -S pnpm tsx +import 'zx/globals'; + +import path from 'node:path'; +import { parse, print, visit } from 'recast'; +import parser from 'recast/parsers/typescript'; + +function resolvePathAlias(importPath: string, file: string) { + if (importPath.startsWith('~/')) { + const relativePath = path.relative(path.dirname(file), path.resolve('dist.new', importPath.slice(2))); + importPath = relativePath.startsWith('.') ? relativePath : './' + relativePath; + } + + return importPath; +} + +function fixImportPath(importPath: string, file: string, ext: string) { + importPath = resolvePathAlias(importPath, file); + + if (!/\..*\.(js|ts)$/.test(importPath)) { + return importPath; + } + + return importPath.replace(/\.(js|ts)$/, ext); +} + +const cjsFiles = await glob('dist/**/*.{cjs,d.cts}'); + +await Promise.all(cjsFiles.map(async (file) => { + const code = parse(await fs.readFile(file, 'utf8'), { parser }); + + visit(code, { + visitImportDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + this.traverse(path); + }, + visitExportAllDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + this.traverse(path); + }, + visitExportNamedDeclaration(path) { + if (path.value.source) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + } + this.traverse(path); + }, + visitCallExpression(path) { + if (path.value.callee.type === 'Identifier' && path.value.callee.name === 'require') { + path.value.arguments[0].value = fixImportPath(path.value.arguments[0].value, file, '.cjs'); + } + this.traverse(path); + }, + visitTSImportType(path) { + path.value.argument.value = resolvePathAlias(path.value.argument.value, file); + this.traverse(path); + }, + visitAwaitExpression(path) { + if (print(path.value).code.startsWith(`await import("./`)) { + path.value.argument.arguments[0].value = fixImportPath(path.value.argument.arguments[0].value, file, '.cjs'); + } + this.traverse(path); + }, + }); + + await fs.writeFile(file, print(code).code); +})); + +let esmFiles = await glob('dist/**/*.{js,d.ts}'); + +await Promise.all(esmFiles.map(async (file) => { + const code = parse(await fs.readFile(file, 'utf8'), { parser }); + + visit(code, { + visitImportDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + this.traverse(path); + }, + visitExportAllDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + this.traverse(path); + }, + visitExportNamedDeclaration(path) { + if (path.value.source) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + } + this.traverse(path); + }, + visitTSImportType(path) { + path.value.argument.value = fixImportPath(path.value.argument.value, file, '.js'); + this.traverse(path); + }, + visitAwaitExpression(path) { + if (print(path.value).code.startsWith(`await import("./`)) { + path.value.argument.arguments[0].value = fixImportPath(path.value.argument.arguments[0].value, file, '.js'); + } + this.traverse(path); + }, + }); + + await fs.writeFile(file, print(code).code); +})); + +esmFiles = await glob('dist/**/*.{mjs,d.mts}'); + +await Promise.all(esmFiles.map(async (file) => { + const code = parse(await fs.readFile(file, 'utf8'), { parser }); + + visit(code, { + visitImportDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.mjs'); + this.traverse(path); + }, + visitExportAllDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.mjs'); + this.traverse(path); + }, + visitExportNamedDeclaration(path) { + if (path.value.source) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.mjs'); + } + this.traverse(path); + }, + visitTSImportType(path) { + path.value.argument.value = fixImportPath(path.value.argument.value, file, '.mjs'); + this.traverse(path); + }, + visitAwaitExpression(path) { + if (print(path.value).code.startsWith(`await import("./`)) { + path.value.argument.arguments[0].value = fixImportPath(path.value.argument.arguments[0].value, file, '.mjs'); + } + this.traverse(path); + }, + }); + + await fs.writeFile(file, print(code).code); +})); diff --git a/drizzle-typebox/src/column.ts b/drizzle-typebox/src/column.ts new file mode 100644 index 000000000..80e6ff39d --- /dev/null +++ b/drizzle-typebox/src/column.ts @@ -0,0 +1,259 @@ +import { Kind, Type as t, TypeRegistry } from '@sinclair/typebox'; +import type { StringOptions, TSchema, Type as typebox } from '@sinclair/typebox'; +import type { Column, ColumnBaseConfig } from 'drizzle-orm'; +import type { + MySqlBigInt53, + MySqlChar, + MySqlDouble, + MySqlFloat, + MySqlInt, + MySqlMediumInt, + MySqlReal, + MySqlSerial, + MySqlSmallInt, + MySqlText, + MySqlTinyInt, + MySqlVarChar, + MySqlYear, +} from 'drizzle-orm/mysql-core'; +import type { + PgArray, + PgBigInt53, + PgBigSerial53, + PgBinaryVector, + PgChar, + PgDoublePrecision, + PgGeometry, + PgGeometryObject, + PgHalfVector, + PgInteger, + PgLineABC, + PgLineTuple, + PgPointObject, + PgPointTuple, + PgReal, + PgSerial, + PgSmallInt, + PgSmallSerial, + PgUUID, + PgVarchar, + PgVector, +} from 'drizzle-orm/pg-core'; +import type { SQLiteInteger, SQLiteReal, SQLiteText } from 'drizzle-orm/sqlite-core'; +import { CONSTANTS } from './constants.ts'; +import { isColumnType, isWithEnum } from './utils.ts'; +import type { BufferSchema, JsonSchema } from './utils.ts'; + +export const literalSchema = t.Union([t.String(), t.Number(), t.Boolean(), t.Null()]); +export const jsonSchema: JsonSchema = t.Recursive((self) => + t.Union([literalSchema, t.Array(self), t.Record(t.String(), self)]) +) as any; +TypeRegistry.Set('Buffer', (_, value) => value instanceof Buffer); // eslint-disable-line no-instanceof/no-instanceof +export const bufferSchema: BufferSchema = { [Kind]: 'Buffer', type: 'buffer' } as any; + +export function mapEnumValues(values: string[]) { + return Object.fromEntries(values.map((value) => [value, value])); +} + +/** @internal */ +export function columnToSchema(column: Column, t: typeof typebox): TSchema { + let schema!: TSchema; + + if (isWithEnum(column)) { + schema = column.enumValues.length ? t.Enum(mapEnumValues(column.enumValues)) : t.String(); + } + + if (!schema) { + // Handle specific types + if (isColumnType | PgPointTuple>(column, ['PgGeometry', 'PgPointTuple'])) { + schema = t.Tuple([t.Number(), t.Number()]); + } else if ( + isColumnType | PgGeometryObject>(column, ['PgGeometryObject', 'PgPointObject']) + ) { + schema = t.Object({ x: t.Number(), y: t.Number() }); + } else if (isColumnType | PgVector>(column, ['PgHalfVector', 'PgVector'])) { + schema = t.Array( + t.Number(), + column.dimensions + ? { + minItems: column.dimensions, + maxItems: column.dimensions, + } + : undefined, + ); + } else if (isColumnType>(column, ['PgLine'])) { + schema = t.Tuple([t.Number(), t.Number(), t.Number()]); + } else if (isColumnType>(column, ['PgLineABC'])) { + schema = t.Object({ + a: t.Number(), + b: t.Number(), + c: t.Number(), + }); + } // Handle other types + else if (isColumnType>(column, ['PgArray'])) { + schema = t.Array( + columnToSchema(column.baseColumn, t), + column.size + ? { + minItems: column.size, + maxItems: column.size, + } + : undefined, + ); + } else if (column.dataType === 'array') { + schema = t.Array(t.Any()); + } else if (column.dataType === 'number') { + schema = numberColumnToSchema(column, t); + } else if (column.dataType === 'bigint') { + schema = bigintColumnToSchema(column, t); + } else if (column.dataType === 'boolean') { + schema = t.Boolean(); + } else if (column.dataType === 'date') { + schema = t.Date(); + } else if (column.dataType === 'string') { + schema = stringColumnToSchema(column, t); + } else if (column.dataType === 'json') { + schema = jsonSchema; + } else if (column.dataType === 'custom') { + schema = t.Any(); + } else if (column.dataType === 'buffer') { + schema = bufferSchema; + } + } + + if (!schema) { + schema = t.Any(); + } + + return schema; +} + +function numberColumnToSchema(column: Column, t: typeof typebox): TSchema { + let unsigned = column.getSQLType().includes('unsigned'); + let min!: number; + let max!: number; + let integer = false; + + if (isColumnType>(column, ['MySqlTinyInt'])) { + min = unsigned ? 0 : CONSTANTS.INT8_MIN; + max = unsigned ? CONSTANTS.INT8_UNSIGNED_MAX : CONSTANTS.INT8_MAX; + integer = true; + } else if ( + isColumnType | PgSmallSerial | MySqlSmallInt>(column, [ + 'PgSmallInt', + 'PgSmallSerial', + 'MySqlSmallInt', + ]) + ) { + min = unsigned ? 0 : CONSTANTS.INT16_MIN; + max = unsigned ? CONSTANTS.INT16_UNSIGNED_MAX : CONSTANTS.INT16_MAX; + integer = true; + } else if ( + isColumnType | MySqlFloat | MySqlMediumInt>(column, [ + 'PgReal', + 'MySqlFloat', + 'MySqlMediumInt', + ]) + ) { + min = unsigned ? 0 : CONSTANTS.INT24_MIN; + max = unsigned ? CONSTANTS.INT24_UNSIGNED_MAX : CONSTANTS.INT24_MAX; + integer = isColumnType(column, ['MySqlMediumInt']); + } else if ( + isColumnType | PgSerial | MySqlInt>(column, ['PgInteger', 'PgSerial', 'MySqlInt']) + ) { + min = unsigned ? 0 : CONSTANTS.INT32_MIN; + max = unsigned ? CONSTANTS.INT32_UNSIGNED_MAX : CONSTANTS.INT32_MAX; + integer = true; + } else if ( + isColumnType | MySqlReal | MySqlDouble | SQLiteReal>(column, [ + 'PgDoublePrecision', + 'MySqlReal', + 'MySqlDouble', + 'SQLiteReal', + ]) + ) { + min = unsigned ? 0 : CONSTANTS.INT48_MIN; + max = unsigned ? CONSTANTS.INT48_UNSIGNED_MAX : CONSTANTS.INT48_MAX; + } else if ( + isColumnType | PgBigSerial53 | MySqlBigInt53 | MySqlSerial | SQLiteInteger>( + column, + ['PgBigInt53', 'PgBigSerial53', 'MySqlBigInt53', 'MySqlSerial', 'SQLiteInteger'], + ) + ) { + unsigned = unsigned || isColumnType(column, ['MySqlSerial']); + min = unsigned ? 0 : Number.MIN_SAFE_INTEGER; + max = Number.MAX_SAFE_INTEGER; + integer = true; + } else if (isColumnType>(column, ['MySqlYear'])) { + min = 1901; + max = 2155; + integer = true; + } else { + min = Number.MIN_SAFE_INTEGER; + max = Number.MAX_SAFE_INTEGER; + } + + const key = integer ? 'Integer' : 'Number'; + return t[key]({ + minimum: min, + maximum: max, + }); +} + +function bigintColumnToSchema(column: Column, t: typeof typebox): TSchema { + const unsigned = column.getSQLType().includes('unsigned'); + const min = unsigned ? 0n : CONSTANTS.INT64_MIN; + const max = unsigned ? CONSTANTS.INT64_UNSIGNED_MAX : CONSTANTS.INT64_MAX; + + return t.BigInt({ + minimum: min, + maximum: max, + }); +} + +function stringColumnToSchema(column: Column, t: typeof typebox): TSchema { + if (isColumnType>>(column, ['PgUUID'])) { + return t.String({ format: 'uuid' }); + } else if ( + isColumnType & { dimensions: number }>>(column, [ + 'PgBinaryVector', + ]) + ) { + return t.RegExp(/^[01]+$/, column.dimensions ? { maxLength: column.dimensions } : undefined); + } + + let max: number | undefined; + let fixed = false; + + if (isColumnType | SQLiteText>(column, ['PgVarchar', 'SQLiteText'])) { + max = column.length; + } else if (isColumnType>(column, ['MySqlVarChar'])) { + max = column.length ?? CONSTANTS.INT16_UNSIGNED_MAX; + } else if (isColumnType>(column, ['MySqlText'])) { + if (column.textType === 'longtext') { + max = CONSTANTS.INT32_UNSIGNED_MAX; + } else if (column.textType === 'mediumtext') { + max = CONSTANTS.INT24_UNSIGNED_MAX; + } else if (column.textType === 'text') { + max = CONSTANTS.INT16_UNSIGNED_MAX; + } else { + max = CONSTANTS.INT8_UNSIGNED_MAX; + } + } + + if (isColumnType | MySqlChar>(column, ['PgChar', 'MySqlChar'])) { + max = column.length; + fixed = true; + } + + const options: Partial = {}; + + if (max !== undefined && fixed) { + options.minLength = max; + options.maxLength = max; + } else if (max !== undefined) { + options.maxLength = max; + } + + return t.String(Object.keys(options).length > 0 ? options : undefined); +} diff --git a/drizzle-typebox/src/column.types.ts b/drizzle-typebox/src/column.types.ts new file mode 100644 index 000000000..7010f234e --- /dev/null +++ b/drizzle-typebox/src/column.types.ts @@ -0,0 +1,100 @@ +import type * as t from '@sinclair/typebox'; +import type { Assume, Column } from 'drizzle-orm'; +import type { ArrayHasAtLeastOneValue, BufferSchema, ColumnIsGeneratedAlwaysAs, IsNever, JsonSchema } from './utils.ts'; + +export type GetEnumValuesFromColumn = TColumn['_'] extends { enumValues: [string, ...string[]] } + ? TColumn['_']['enumValues'] + : undefined; + +export type GetBaseColumn = TColumn['_'] extends { baseColumn: Column | never | undefined } + ? IsNever extends false ? TColumn['_']['baseColumn'] + : undefined + : undefined; + +export type EnumValuesToEnum = { [K in TEnumValues[number]]: K }; + +export type GetTypeboxType< + TData, + TDataType extends string, + TColumnType extends string, + TEnumValues extends [string, ...string[]] | undefined, + TBaseColumn extends Column | undefined, +> = TColumnType extends + | 'MySqlTinyInt' + | 'PgSmallInt' + | 'PgSmallSerial' + | 'MySqlSmallInt' + | 'MySqlMediumInt' + | 'PgInteger' + | 'PgSerial' + | 'MySqlInt' + | 'PgBigInt53' + | 'PgBigSerial53' + | 'MySqlBigInt53' + | 'MySqlSerial' + | 'SQLiteInteger' + | 'MySqlYear' ? t.TInteger + : TColumnType extends 'PgBinaryVector' ? t.TRegExp + : TBaseColumn extends Column ? t.TArray< + GetTypeboxType< + TBaseColumn['_']['data'], + TBaseColumn['_']['dataType'], + TBaseColumn['_']['columnType'], + GetEnumValuesFromColumn, + GetBaseColumn + > + > + : ArrayHasAtLeastOneValue extends true + ? t.TEnum>> + : TData extends infer TTuple extends [any, ...any[]] ? t.TTuple< + Assume<{ [K in keyof TTuple]: GetTypeboxType }, [any, ...any[]]> + > + : TData extends Date ? t.TDate + : TData extends Buffer ? BufferSchema + : TDataType extends 'array' + ? t.TArray[number], string, string, undefined, undefined>> + : TData extends infer TDict extends Record + ? t.TObject<{ [K in keyof TDict]: GetTypeboxType }> + : TDataType extends 'json' ? JsonSchema + : TData extends number ? t.TNumber + : TData extends bigint ? t.TBigInt + : TData extends boolean ? t.TBoolean + : TData extends string ? t.TString + : t.TAny; + +type HandleSelectColumn< + TSchema extends t.TSchema, + TColumn extends Column, +> = TColumn['_']['notNull'] extends true ? TSchema + : t.Union<[TSchema, t.TNull]>; + +type HandleInsertColumn< + TSchema extends t.TSchema, + TColumn extends Column, +> = ColumnIsGeneratedAlwaysAs extends true ? never + : TColumn['_']['notNull'] extends true ? TColumn['_']['hasDefault'] extends true ? t.TOptional + : TSchema + : t.TOptional>; + +type HandleUpdateColumn< + TSchema extends t.TSchema, + TColumn extends Column, +> = ColumnIsGeneratedAlwaysAs extends true ? never + : TColumn['_']['notNull'] extends true ? t.TOptional + : t.TOptional>; + +export type HandleColumn< + TType extends 'select' | 'insert' | 'update', + TColumn extends Column, +> = GetTypeboxType< + TColumn['_']['data'], + TColumn['_']['dataType'], + TColumn['_']['columnType'], + GetEnumValuesFromColumn, + GetBaseColumn +> extends infer TSchema extends t.TSchema ? TSchema extends t.TAny ? t.TAny + : TType extends 'select' ? HandleSelectColumn + : TType extends 'insert' ? HandleInsertColumn + : TType extends 'update' ? HandleUpdateColumn + : TSchema + : t.TAny; diff --git a/drizzle-typebox/src/constants.ts b/drizzle-typebox/src/constants.ts new file mode 100644 index 000000000..99f5d7a42 --- /dev/null +++ b/drizzle-typebox/src/constants.ts @@ -0,0 +1,20 @@ +export const CONSTANTS = { + INT8_MIN: -128, + INT8_MAX: 127, + INT8_UNSIGNED_MAX: 255, + INT16_MIN: -32768, + INT16_MAX: 32767, + INT16_UNSIGNED_MAX: 65535, + INT24_MIN: -8388608, + INT24_MAX: 8388607, + INT24_UNSIGNED_MAX: 16777215, + INT32_MIN: -2147483648, + INT32_MAX: 2147483647, + INT32_UNSIGNED_MAX: 4294967295, + INT48_MIN: -140737488355328, + INT48_MAX: 140737488355327, + INT48_UNSIGNED_MAX: 281474976710655, + INT64_MIN: -9223372036854775808n, + INT64_MAX: 9223372036854775807n, + INT64_UNSIGNED_MAX: 18446744073709551615n, +}; diff --git a/drizzle-typebox/src/index.ts b/drizzle-typebox/src/index.ts index e70d72c43..0a6499e5b 100644 --- a/drizzle-typebox/src/index.ts +++ b/drizzle-typebox/src/index.ts @@ -1,344 +1,2 @@ -import type { - TAny, - TArray, - TBigInt, - TBoolean, - TDate, - TLiteral, - TNull, - TNumber, - TObject, - TOptional, - TSchema, - TString, - TUnion, -} from '@sinclair/typebox'; -import { Type } from '@sinclair/typebox'; -import { - type AnyColumn, - type Assume, - type Column, - type DrizzleTypeError, - type Equal, - getTableColumns, - is, - type Simplify, - type Table, -} from 'drizzle-orm'; -import { MySqlChar, MySqlVarBinary, MySqlVarChar } from 'drizzle-orm/mysql-core'; -import { type PgArray, PgChar, PgUUID, PgVarchar } from 'drizzle-orm/pg-core'; -import { SQLiteText } from 'drizzle-orm/sqlite-core'; - -type TUnionLiterals = T extends readonly [ - infer U extends string, - ...infer Rest extends string[], -] ? [TLiteral, ...TUnionLiterals] - : []; - -const literalSchema = Type.Union([ - Type.String(), - Type.Number(), - Type.Boolean(), - Type.Null(), -]); - -type Json = typeof jsonSchema; - -export const jsonSchema = Type.Union([ - literalSchema, - Type.Array(Type.Any()), - Type.Record(Type.String(), Type.Any()), -]); - -type TNullable = TUnion<[TType, TNull]>; - -type MapInsertColumnToTypebox< - TColumn extends Column, - TType extends TSchema, -> = TColumn['_']['notNull'] extends false ? TOptional> - : TColumn['_']['hasDefault'] extends true ? TOptional - : TType; - -type MapSelectColumnToTypebox< - TColumn extends Column, - TType extends TSchema, -> = TColumn['_']['notNull'] extends false ? TNullable : TType; - -type MapColumnToTypebox< - TColumn extends Column, - TType extends TSchema, - TMode extends 'insert' | 'select', -> = TMode extends 'insert' ? MapInsertColumnToTypebox - : MapSelectColumnToTypebox; - -type MaybeOptional< - TColumn extends Column, - TType extends TSchema, - TMode extends 'insert' | 'select', - TNoOptional extends boolean, -> = TNoOptional extends true ? TType - : MapColumnToTypebox; - -type GetTypeboxType = TColumn['_']['dataType'] extends infer TDataType - ? TDataType extends 'custom' ? TAny - : TDataType extends 'json' ? Json - : TColumn extends { enumValues: [string, ...string[]] } - ? Equal extends true ? TString - : TUnion> - : TDataType extends 'array' ? TArray< - GetTypeboxType< - Assume< - TColumn['_'], - { baseColumn: Column } - >['baseColumn'] - > - > - : TDataType extends 'bigint' ? TBigInt - : TDataType extends 'number' ? TNumber - : TDataType extends 'string' ? TString - : TDataType extends 'boolean' ? TBoolean - : TDataType extends 'date' ? TDate - : TAny - : never; - -type ValueOrUpdater = T | ((arg: TUpdaterArg) => T); - -type UnwrapValueOrUpdater = T extends ValueOrUpdater ? U - : never; - -export type Refine = { - [K in keyof TTable['_']['columns']]?: ValueOrUpdater< - TSchema, - TMode extends 'select' ? BuildSelectSchema - : BuildInsertSchema - >; -}; - -export type BuildInsertSchema< - TTable extends Table, - TRefine extends Refine | {}, - TNoOptional extends boolean = false, -> = TTable['_']['columns'] extends infer TColumns extends Record< - string, - Column -> ? { - [K in keyof TColumns & string]: MaybeOptional< - TColumns[K], - K extends keyof TRefine ? Assume, TSchema> - : GetTypeboxType, - 'insert', - TNoOptional - >; - } - : never; - -export type BuildSelectSchema< - TTable extends Table, - TRefine extends Refine, - TNoOptional extends boolean = false, -> = Simplify< - { - [K in keyof TTable['_']['columns']]: MaybeOptional< - TTable['_']['columns'][K], - K extends keyof TRefine ? Assume, TSchema> - : GetTypeboxType, - 'select', - TNoOptional - >; - } ->; - -export const Nullable = (schema: T) => Type.Union([schema, Type.Null()]); - -export function createInsertSchema< - TTable extends Table, - TRefine extends Refine = Refine, ->( - table: TTable, - /** - * @param refine Refine schema fields - */ - refine?: { - [K in keyof TRefine]: K extends keyof TTable['_']['columns'] ? TRefine[K] - : DrizzleTypeError< - `Column '${ - & K - & string}' does not exist in table '${TTable['_']['name']}'` - >; - }, - // -): TObject< - BuildInsertSchema< - TTable, - Equal> extends true ? {} : TRefine - > -> { - const columns = getTableColumns(table); - const columnEntries = Object.entries(columns); - - let schemaEntries = Object.fromEntries( - columnEntries.map(([name, column]) => { - return [name, mapColumnToSchema(column)]; - }), - ); - - if (refine) { - schemaEntries = Object.assign( - schemaEntries, - Object.fromEntries( - Object.entries(refine).map(([name, refineColumn]) => { - return [ - name, - typeof refineColumn === 'function' - ? refineColumn( - schemaEntries as BuildInsertSchema< - TTable, - {}, - true - >, - ) - : refineColumn, - ]; - }), - ), - ); - } - - for (const [name, column] of columnEntries) { - if (!column.notNull) { - schemaEntries[name] = Type.Optional(Nullable(schemaEntries[name]!)); - } else if (column.hasDefault) { - schemaEntries[name] = Type.Optional(schemaEntries[name]!); - } - } - - return Type.Object(schemaEntries) as any; -} - -export function createSelectSchema< - TTable extends Table, - TRefine extends Refine = Refine, ->( - table: TTable, - /** - * @param refine Refine schema fields - */ - refine?: { - [K in keyof TRefine]: K extends keyof TTable['_']['columns'] ? TRefine[K] - : DrizzleTypeError< - `Column '${ - & K - & string}' does not exist in table '${TTable['_']['name']}'` - >; - }, -): TObject< - BuildSelectSchema< - TTable, - Equal> extends true ? {} : TRefine - > -> { - const columns = getTableColumns(table); - const columnEntries = Object.entries(columns); - - let schemaEntries = Object.fromEntries( - columnEntries.map(([name, column]) => { - return [name, mapColumnToSchema(column)]; - }), - ); - - if (refine) { - schemaEntries = Object.assign( - schemaEntries, - Object.fromEntries( - Object.entries(refine).map(([name, refineColumn]) => { - return [ - name, - typeof refineColumn === 'function' - ? refineColumn( - schemaEntries as BuildSelectSchema< - TTable, - {}, - true - >, - ) - : refineColumn, - ]; - }), - ), - ); - } - - for (const [name, column] of columnEntries) { - if (!column.notNull) { - schemaEntries[name] = Nullable(schemaEntries[name]!); - } - } - - return Type.Object(schemaEntries) as any; -} - -function isWithEnum( - column: AnyColumn, -): column is typeof column & { enumValues: [string, ...string[]] } { - return ( - 'enumValues' in column - && Array.isArray(column.enumValues) - && column.enumValues.length > 0 - ); -} - -const uuidPattern = /^[\dA-Fa-f]{8}(?:-[\dA-Fa-f]{4}){3}-[\dA-Fa-f]{12}$/; - -function mapColumnToSchema(column: Column): TSchema { - let type: TSchema | undefined; - - if (isWithEnum(column)) { - type = column.enumValues?.length - ? Type.Union(column.enumValues.map((value) => Type.Literal(value))) - : Type.String(); - } - - if (!type) { - if (column.dataType === 'custom') { - type = Type.Any(); - } else if (column.dataType === 'json') { - type = jsonSchema; - } else if (column.dataType === 'array') { - type = Type.Array( - mapColumnToSchema((column as PgArray).baseColumn), - ); - } else if (column.dataType === 'number') { - type = Type.Number(); - } else if (column.dataType === 'bigint') { - type = Type.BigInt(); - } else if (column.dataType === 'boolean') { - type = Type.Boolean(); - } else if (column.dataType === 'date') { - type = Type.Date(); - } else if (column.dataType === 'string') { - const sType = Type.String(); - - if ( - (is(column, PgChar) - || is(column, PgVarchar) - || is(column, MySqlVarChar) - || is(column, MySqlVarBinary) - || is(column, MySqlChar) - || is(column, SQLiteText)) - && typeof column.length === 'number' - ) { - sType.maxLength = column.length; - } - - type = sType; - } else if (is(column, PgUUID)) { - type = Type.RegEx(uuidPattern); - } - } - - if (!type) { - type = Type.Any(); - } - - return type; -} +export * from './schema.ts'; +export * from './schema.types.ts'; diff --git a/drizzle-typebox/src/schema.ts b/drizzle-typebox/src/schema.ts new file mode 100644 index 000000000..b0291723e --- /dev/null +++ b/drizzle-typebox/src/schema.ts @@ -0,0 +1,144 @@ +import { Type as t } from '@sinclair/typebox'; +import type { TSchema } from '@sinclair/typebox'; +import { Column, getTableColumns, getViewSelectedFields, is, isTable, isView, SQL } from 'drizzle-orm'; +import type { Table, View } from 'drizzle-orm'; +import type { PgEnum } from 'drizzle-orm/pg-core'; +import { columnToSchema, mapEnumValues } from './column.ts'; +import type { Conditions } from './schema.types.internal.ts'; +import type { + CreateInsertSchema, + CreateSchemaFactoryOptions, + CreateSelectSchema, + CreateUpdateSchema, +} from './schema.types.ts'; +import { isPgEnum } from './utils.ts'; + +function getColumns(tableLike: Table | View) { + return isTable(tableLike) ? getTableColumns(tableLike) : getViewSelectedFields(tableLike); +} + +function handleColumns( + columns: Record, + refinements: Record, + conditions: Conditions, + factory?: CreateSchemaFactoryOptions, +): TSchema { + const columnSchemas: Record = {}; + + for (const [key, selected] of Object.entries(columns)) { + if (!is(selected, Column) && !is(selected, SQL) && !is(selected, SQL.Aliased) && typeof selected === 'object') { + const columns = isTable(selected) || isView(selected) ? getColumns(selected) : selected; + columnSchemas[key] = handleColumns(columns, refinements[key] ?? {}, conditions, factory); + continue; + } + + const refinement = refinements[key]; + if (refinement !== undefined && typeof refinement !== 'function') { + columnSchemas[key] = refinement; + continue; + } + + const column = is(selected, Column) ? selected : undefined; + const schema = column ? columnToSchema(column, factory?.typeboxInstance ?? t) : t.Any(); + const refined = typeof refinement === 'function' ? refinement(schema) : schema; + + if (conditions.never(column)) { + continue; + } else { + columnSchemas[key] = refined; + } + + if (column) { + if (conditions.nullable(column)) { + columnSchemas[key] = t.Union([columnSchemas[key]!, t.Null()]); + } + + if (conditions.optional(column)) { + columnSchemas[key] = t.Optional(columnSchemas[key]!); + } + } + } + + return t.Object(columnSchemas) as any; +} + +function handleEnum(enum_: PgEnum, factory?: CreateSchemaFactoryOptions) { + const typebox: typeof t = factory?.typeboxInstance ?? t; + return typebox.Enum(mapEnumValues(enum_.enumValues)); +} + +const selectConditions: Conditions = { + never: () => false, + optional: () => false, + nullable: (column) => !column.notNull, +}; + +const insertConditions: Conditions = { + never: (column) => column?.generated?.type === 'always' || column?.generatedIdentity?.type === 'always', + optional: (column) => !column.notNull || (column.notNull && column.hasDefault), + nullable: (column) => !column.notNull, +}; + +const updateConditions: Conditions = { + never: (column) => column?.generated?.type === 'always' || column?.generatedIdentity?.type === 'always', + optional: () => true, + nullable: (column) => !column.notNull, +}; + +export const createSelectSchema: CreateSelectSchema = ( + entity: Table | View | PgEnum<[string, ...string[]]>, + refine?: Record, +) => { + if (isPgEnum(entity)) { + return handleEnum(entity); + } + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, selectConditions) as any; +}; + +export const createInsertSchema: CreateInsertSchema = ( + entity: Table, + refine?: Record, +) => { + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, insertConditions) as any; +}; + +export const createUpdateSchema: CreateUpdateSchema = ( + entity: Table, + refine?: Record, +) => { + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, updateConditions) as any; +}; + +export function createSchemaFactory(options?: CreateSchemaFactoryOptions) { + const createSelectSchema: CreateSelectSchema = ( + entity: Table | View | PgEnum<[string, ...string[]]>, + refine?: Record, + ) => { + if (isPgEnum(entity)) { + return handleEnum(entity, options); + } + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, selectConditions, options) as any; + }; + + const createInsertSchema: CreateInsertSchema = ( + entity: Table, + refine?: Record, + ) => { + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, insertConditions, options) as any; + }; + + const createUpdateSchema: CreateUpdateSchema = ( + entity: Table, + refine?: Record, + ) => { + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, updateConditions, options) as any; + }; + + return { createSelectSchema, createInsertSchema, createUpdateSchema }; +} diff --git a/drizzle-typebox/src/schema.types.internal.ts b/drizzle-typebox/src/schema.types.internal.ts new file mode 100644 index 000000000..beccef94b --- /dev/null +++ b/drizzle-typebox/src/schema.types.internal.ts @@ -0,0 +1,88 @@ +import type * as t from '@sinclair/typebox'; +import type { Assume, Column, DrizzleTypeError, SelectedFieldsFlat, Simplify, Table, View } from 'drizzle-orm'; +import type { GetBaseColumn, GetEnumValuesFromColumn, GetTypeboxType, HandleColumn } from './column.types.ts'; +import type { GetSelection, RemoveNever } from './utils.ts'; + +export interface Conditions { + never: (column?: Column) => boolean; + optional: (column: Column) => boolean; + nullable: (column: Column) => boolean; +} + +export type BuildRefineColumns< + TColumns extends Record, +> = Simplify< + RemoveNever< + { + [K in keyof TColumns]: TColumns[K] extends infer TColumn extends Column ? GetTypeboxType< + TColumn['_']['data'], + TColumn['_']['dataType'], + TColumn['_']['columnType'], + GetEnumValuesFromColumn, + GetBaseColumn + > extends infer TSchema extends t.TSchema ? TSchema + : t.TAny + : TColumns[K] extends infer TObject extends SelectedFieldsFlat | Table | View + ? BuildRefineColumns> + : TColumns[K]; + } + > +>; + +export type BuildRefine< + TColumns extends Record, +> = BuildRefineColumns extends infer TBuildColumns ? { + [K in keyof TBuildColumns]?: TBuildColumns[K] extends t.TSchema + ? ((schema: TBuildColumns[K]) => t.TSchema) | t.TSchema + : TBuildColumns[K] extends Record ? Simplify> + : never; + } + : never; + +type HandleRefinement< + TRefinement extends t.TSchema | ((schema: t.TSchema) => t.TSchema), + TColumn extends Column, +> = TRefinement extends (schema: t.TSchema) => t.TSchema + ? TColumn['_']['notNull'] extends true ? ReturnType + : t.TTuple<[ReturnType, t.TNull]> + : TRefinement; + +export type BuildSchema< + TType extends 'select' | 'insert' | 'update', + TColumns extends Record, + TRefinements extends Record | undefined, +> = t.TObject< + Simplify< + RemoveNever< + { + [K in keyof TColumns]: TColumns[K] extends infer TColumn extends Column + ? TRefinements extends object + ? TRefinements[Assume] extends + infer TRefinement extends t.TSchema | ((schema: t.TSchema) => t.TSchema) + ? HandleRefinement + : HandleColumn + : HandleColumn + : TColumns[K] extends infer TObject extends SelectedFieldsFlat | Table | View ? BuildSchema< + TType, + GetSelection, + TRefinements extends object + ? TRefinements[Assume] extends infer TNestedRefinements extends object + ? TNestedRefinements + : undefined + : undefined + > + : t.TAny; + } + > + > +>; + +export type NoUnknownKeys< + TRefinement extends Record, + TCompare extends Record, +> = { + [K in keyof TRefinement]: K extends keyof TCompare ? TRefinement[K] extends t.TSchema ? TRefinement[K] + : TRefinement[K] extends Record ? NoUnknownKeys + : TRefinement[K] + : DrizzleTypeError<`Found unknown key in refinement: "${K & string}"`>; +}; diff --git a/drizzle-typebox/src/schema.types.ts b/drizzle-typebox/src/schema.types.ts new file mode 100644 index 000000000..abbb4f8eb --- /dev/null +++ b/drizzle-typebox/src/schema.types.ts @@ -0,0 +1,53 @@ +import type * as t from '@sinclair/typebox'; +import type { Table, View } from 'drizzle-orm'; +import type { PgEnum } from 'drizzle-orm/pg-core'; +import type { EnumValuesToEnum } from './column.types.ts'; +import type { BuildRefine, BuildSchema, NoUnknownKeys } from './schema.types.internal.ts'; + +export interface CreateSelectSchema { + (table: TTable): BuildSchema<'select', TTable['_']['columns'], undefined>; + < + TTable extends Table, + TRefine extends BuildRefine, + >( + table: TTable, + refine?: NoUnknownKeys, + ): BuildSchema<'select', TTable['_']['columns'], TRefine>; + + (view: TView): BuildSchema<'select', TView['_']['selectedFields'], undefined>; + < + TView extends View, + TRefine extends BuildRefine, + >( + view: TView, + refine: NoUnknownKeys, + ): BuildSchema<'select', TView['_']['selectedFields'], TRefine>; + + >(enum_: TEnum): t.TEnum>; +} + +export interface CreateInsertSchema { + (table: TTable): BuildSchema<'insert', TTable['_']['columns'], undefined>; + < + TTable extends Table, + TRefine extends BuildRefine>, + >( + table: TTable, + refine?: NoUnknownKeys, + ): BuildSchema<'insert', TTable['_']['columns'], TRefine>; +} + +export interface CreateUpdateSchema { + (table: TTable): BuildSchema<'update', TTable['_']['columns'], undefined>; + < + TTable extends Table, + TRefine extends BuildRefine>, + >( + table: TTable, + refine?: TRefine, + ): BuildSchema<'update', TTable['_']['columns'], TRefine>; +} + +export interface CreateSchemaFactoryOptions { + typeboxInstance?: any; +} diff --git a/drizzle-typebox/src/utils.ts b/drizzle-typebox/src/utils.ts new file mode 100644 index 000000000..686bf01b8 --- /dev/null +++ b/drizzle-typebox/src/utils.ts @@ -0,0 +1,50 @@ +import type { Kind, Static, TSchema } from '@sinclair/typebox'; +import type { Column, SelectedFieldsFlat, Table, View } from 'drizzle-orm'; +import type { PgEnum } from 'drizzle-orm/pg-core'; +import type { literalSchema } from './column.ts'; + +export function isColumnType(column: Column, columnTypes: string[]): column is T { + return columnTypes.includes(column.columnType); +} + +export function isWithEnum(column: Column): column is typeof column & { enumValues: [string, ...string[]] } { + return 'enumValues' in column && Array.isArray(column.enumValues) && column.enumValues.length > 0; +} + +export const isPgEnum: (entity: any) => entity is PgEnum<[string, ...string[]]> = isWithEnum as any; + +type Literal = Static; +export type Json = Literal | { [key: string]: Json } | Json[]; +export interface JsonSchema extends TSchema { + [Kind]: 'Union'; + static: Json; + anyOf: Json; +} +export interface BufferSchema extends TSchema { + [Kind]: 'Buffer'; + static: Buffer; + type: 'buffer'; +} + +export type IsNever = [T] extends [never] ? true : false; + +export type ArrayHasAtLeastOneValue = TEnum extends [infer TString, ...any[]] + ? TString extends `${infer TLiteral}` ? TLiteral extends any ? true + : false + : false + : false; + +export type ColumnIsGeneratedAlwaysAs = TColumn['_']['identity'] extends 'always' ? true + : TColumn['_']['generated'] extends undefined ? false + : TColumn['_']['generated'] extends infer TGenerated extends { type: string } + ? TGenerated['type'] extends 'byDefault' ? false + : true + : true; + +export type RemoveNever = { + [K in keyof T as T[K] extends never ? never : K]: T[K]; +}; + +export type GetSelection | Table | View> = T extends Table ? T['_']['columns'] + : T extends View ? T['_']['selectedFields'] + : T; diff --git a/drizzle-typebox/tests/mysql.test.ts b/drizzle-typebox/tests/mysql.test.ts index d6942a529..213240368 100644 --- a/drizzle-typebox/tests/mysql.test.ts +++ b/drizzle-typebox/tests/mysql.test.ts @@ -1,378 +1,469 @@ -import { Type } from '@sinclair/typebox'; -import { Value } from '@sinclair/typebox/value'; -import { - bigint, - binary, - boolean, - char, - customType, - date, - datetime, - decimal, - double, - float, - int, - json, - longtext, - mediumint, - mediumtext, - mysqlEnum, - mysqlTable, - real, - serial, - smallint, - text, - time, - timestamp, - tinyint, - tinytext, - varbinary, - varchar, - year, -} from 'drizzle-orm/mysql-core'; -import { expect, test } from 'vitest'; -import { createInsertSchema, createSelectSchema, jsonSchema } from '../src'; -import { expectSchemaShape } from './utils.ts'; - -const customInt = customType<{ data: number }>({ - dataType() { - return 'int'; - }, +import { Type as t } from '@sinclair/typebox'; +import { type Equal, sql } from 'drizzle-orm'; +import { int, mysqlSchema, mysqlTable, mysqlView, serial, text } from 'drizzle-orm/mysql-core'; +import { test } from 'vitest'; +import { jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectSchemaShape } from './utils.ts'; + +const intSchema = t.Integer({ + minimum: CONSTANTS.INT32_MIN, + maximum: CONSTANTS.INT32_MAX, +}); +const serialNumberModeSchema = t.Integer({ + minimum: 0, + maximum: Number.MAX_SAFE_INTEGER, }); +const textSchema = t.String({ maxLength: CONSTANTS.INT16_UNSIGNED_MAX }); + +test('table - select', (tc) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); -const testTable = mysqlTable('test', { - bigint: bigint('bigint', { mode: 'bigint' }).notNull(), - bigintNumber: bigint('bigintNumber', { mode: 'number' }).notNull(), - binary: binary('binary').notNull(), - boolean: boolean('boolean').notNull(), - char: char('char', { length: 4 }).notNull(), - charEnum: char('char', { enum: ['a', 'b', 'c'] }).notNull(), - customInt: customInt('customInt').notNull(), - date: date('date').notNull(), - dateString: date('dateString', { mode: 'string' }).notNull(), - datetime: datetime('datetime').notNull(), - datetimeString: datetime('datetimeString', { mode: 'string' }).notNull(), - decimal: decimal('decimal').notNull(), - double: double('double').notNull(), - enum: mysqlEnum('enum', ['a', 'b', 'c']).notNull(), - float: float('float').notNull(), - int: int('int').notNull(), - json: json('json').notNull(), - mediumint: mediumint('mediumint').notNull(), - real: real('real').notNull(), - serial: serial('serial').notNull(), - smallint: smallint('smallint').notNull(), - text: text('text').notNull(), - textEnum: text('textEnum', { enum: ['a', 'b', 'c'] }).notNull(), - tinytext: tinytext('tinytext').notNull(), - tinytextEnum: tinytext('tinytextEnum', { enum: ['a', 'b', 'c'] }).notNull(), - mediumtext: mediumtext('mediumtext').notNull(), - mediumtextEnum: mediumtext('mediumtextEnum', { - enum: ['a', 'b', 'c'], - }).notNull(), - longtext: longtext('longtext').notNull(), - longtextEnum: longtext('longtextEnum', { enum: ['a', 'b', 'c'] }).notNull(), - time: time('time').notNull(), - timestamp: timestamp('timestamp').notNull(), - timestampString: timestamp('timestampString', { mode: 'string' }).notNull(), - tinyint: tinyint('tinyint').notNull(), - varbinary: varbinary('varbinary', { length: 200 }).notNull(), - varchar: varchar('varchar', { length: 200 }).notNull(), - varcharEnum: varchar('varcharEnum', { - length: 1, - enum: ['a', 'b', 'c'], - }).notNull(), - year: year('year').notNull(), - autoIncrement: int('autoIncrement').notNull().autoincrement(), + const result = createSelectSchema(table); + const expected = t.Object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -const testTableRow = { - bigint: BigInt(1), - bigintNumber: 1, - binary: 'binary', - boolean: true, - char: 'char', - charEnum: 'a', - customInt: { data: 1 }, - date: new Date(), - dateString: new Date().toISOString(), - datetime: new Date(), - datetimeString: new Date().toISOString(), - decimal: '1.1', - double: 1.1, - enum: 'a', - float: 1.1, - int: 1, - json: { data: 1 }, - mediumint: 1, - real: 1.1, - serial: 1, - smallint: 1, - text: 'text', - textEnum: 'a', - tinytext: 'tinytext', - tinytextEnum: 'a', - mediumtext: 'mediumtext', - mediumtextEnum: 'a', - longtext: 'longtext', - longtextEnum: 'a', - time: '00:00:00', - timestamp: new Date(), - timestampString: new Date().toISOString(), - tinyint: 1, - varbinary: 'A'.repeat(200), - varchar: 'A'.repeat(200), - varcharEnum: 'a', - year: 2021, - autoIncrement: 1, -}; - -test('insert valid row', () => { - const schema = createInsertSchema(testTable); - - expect(Value.Check( - schema, - testTableRow, - )).toBeTruthy(); +test('table in schema - select', (tc) => { + const schema = mysqlSchema('test'); + const table = schema.table('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = t.Object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -test('insert invalid varchar length', () => { - const schema = createInsertSchema(testTable); +test('table - insert', (tc) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); - expect(Value.Check(schema, { - ...testTableRow, - varchar: 'A'.repeat(201), - })).toBeFalsy(); + const result = createInsertSchema(table); + const expected = t.Object({ + id: t.Optional(serialNumberModeSchema), + name: textSchema, + age: t.Optional(t.Union([intSchema, t.Null()])), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -test('insert smaller char length should work', () => { - const schema = createInsertSchema(testTable); +test('table - update', (tc) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); - expect(Value.Check(schema, { ...testTableRow, char: 'abc' })).toBeTruthy(); + const result = createUpdateSchema(table); + const expected = t.Object({ + id: t.Optional(serialNumberModeSchema), + name: t.Optional(textSchema), + age: t.Optional(t.Union([intSchema, t.Null()])), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -test('insert larger char length should fail', () => { - const schema = createInsertSchema(testTable); +test('view qb - select', (tc) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = mysqlView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); - expect(Value.Check(schema, { ...testTableRow, char: 'abcde' })).toBeFalsy(); + const result = createSelectSchema(view); + const expected = t.Object({ id: serialNumberModeSchema, age: t.Any() }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -test('insert schema', (t) => { - const actual = createInsertSchema(testTable); - - const expected = Type.Object({ - bigint: Type.BigInt(), - bigintNumber: Type.Number(), - binary: Type.String(), - boolean: Type.Boolean(), - char: Type.String({ minLength: 4, maxLength: 4 }), - charEnum: Type.Union([Type.Literal('a'), Type.Literal('b'), Type.Literal('c')]), - customInt: Type.Any(), - date: Type.Date(), - dateString: Type.String(), - datetime: Type.Date(), - datetimeString: Type.String(), - decimal: Type.String(), - double: Type.Number(), - enum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - float: Type.Number(), - int: Type.Number(), - json: jsonSchema, - mediumint: Type.Number(), - real: Type.Number(), - serial: Type.Optional(Type.Number()), - smallint: Type.Number(), - text: Type.String(), - textEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - tinytext: Type.String(), - tinytextEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - mediumtext: Type.String(), - mediumtextEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - longtext: Type.String(), - longtextEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - time: Type.String(), - timestamp: Type.Date(), - timestampString: Type.String(), - tinyint: Type.Number(), - varbinary: Type.String({ maxLength: 200 }), - varchar: Type.String({ maxLength: 200 }), - varcharEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - year: Type.Number(), - autoIncrement: Type.Optional(Type.Number()), +test('view columns - select', (tc) => { + const view = mysqlView('test', { + id: serial().primaryKey(), + name: text().notNull(), + }).as(sql``); + + const result = createSelectSchema(view); + const expected = t.Object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('view with nested fields - select', (tc) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), }); + const view = mysqlView('test').as((qb) => + qb.select({ + id: table.id, + nested: { + name: table.name, + age: sql``.as('age'), + }, + table, + }).from(table) + ); - expectSchemaShape(t, expected).from(actual); + const result = createSelectSchema(view); + const expected = t.Object({ + id: serialNumberModeSchema, + nested: t.Object({ name: textSchema, age: t.Any() }), + table: t.Object({ id: serialNumberModeSchema, name: textSchema }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -test('select schema', (t) => { - const actual = createSelectSchema(testTable); - - const expected = Type.Object({ - bigint: Type.BigInt(), - bigintNumber: Type.Number(), - binary: Type.String(), - boolean: Type.Boolean(), - char: Type.String({ minLength: 4, maxLength: 4 }), - charEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - customInt: Type.Any(), - date: Type.Date(), - dateString: Type.String(), - datetime: Type.Date(), - datetimeString: Type.String(), - decimal: Type.String(), - double: Type.Number(), - enum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - float: Type.Number(), - int: Type.Number(), - // - json: jsonSchema, - mediumint: Type.Number(), - real: Type.Number(), - serial: Type.Number(), - smallint: Type.Number(), - text: Type.String(), - textEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - tinytext: Type.String(), - tinytextEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - mediumtext: Type.String(), - mediumtextEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - longtext: Type.String(), - longtextEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - time: Type.String(), - timestamp: Type.Date(), - timestampString: Type.String(), - tinyint: Type.Number(), - varbinary: Type.String({ maxLength: 200 }), - varchar: Type.String({ maxLength: 200 }), - varcharEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - year: Type.Number(), - autoIncrement: Type.Number(), +test('nullability - select', (tc) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), }); - expectSchemaShape(t, expected).from(actual); + const result = createSelectSchema(table); + const expected = t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: intSchema, + c3: t.Union([intSchema, t.Null()]), + c4: intSchema, + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -test('select schema w/ refine', (t) => { - const actual = createSelectSchema(testTable, { - bigint: (_) => Type.BigInt({ minimum: 0n }), +test('nullability - insert', (tc) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), }); - const expected = Type.Object({ - bigint: Type.BigInt({ minimum: 0n }), - bigintNumber: Type.Number(), - binary: Type.String(), - boolean: Type.Boolean(), - char: Type.String({ minLength: 5, maxLength: 5 }), - charEnum: Type.Union([Type.Literal('a'), Type.Literal('b'), Type.Literal('c')]), - customInt: Type.Any(), - date: Type.Date(), - dateString: Type.String(), - datetime: Type.Date(), - datetimeString: Type.String(), - decimal: Type.String(), - double: Type.Number(), - enum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - float: Type.Number(), - int: Type.Number(), - json: jsonSchema, - mediumint: Type.Number(), - real: Type.Number(), - serial: Type.Number(), - smallint: Type.Number(), - text: Type.String(), - textEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - tinytext: Type.String(), - tinytextEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - mediumtext: Type.String(), - mediumtextEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - longtext: Type.String(), - longtextEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - time: Type.String(), - timestamp: Type.Date(), - timestampString: Type.String(), - tinyint: Type.Number(), - varbinary: Type.String({ maxLength: 200 }), - varchar: Type.String({ maxLength: 200 }), - varcharEnum: Type.Union([ - Type.Literal('a'), - Type.Literal('b'), - Type.Literal('c'), - ]), - year: Type.Number(), - autoIncrement: Type.Number(), + const result = createInsertSchema(table); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: intSchema, + c3: t.Optional(t.Union([intSchema, t.Null()])), + c4: t.Optional(intSchema), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('nullability - update', (tc) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: t.Optional(intSchema), + c3: t.Optional(t.Union([intSchema, t.Null()])), + c4: t.Optional(intSchema), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine table - select', (tc) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + }); + + const result = createSelectSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine table - insert', (tc) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), }); - expectSchemaShape(t, expected).from(actual); + const result = createInsertSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); + +test('refine table - update', (tc) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: t.Optional(t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 })), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine view - select', (tc) => { + const table = mysqlTable('test', { + c1: int(), + c2: int(), + c3: int(), + c4: int(), + c5: int(), + c6: int(), + }); + const view = mysqlView('test').as((qb) => + qb.select({ + c1: table.c1, + c2: table.c2, + c3: table.c3, + nested: { + c4: table.c4, + c5: table.c5, + c6: table.c6, + }, + table, + }).from(table) + ); + + const result = createSelectSchema(view, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + nested: { + c5: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c6: t.Integer({ minimum: 1, maximum: 10 }), + }, + table: { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }, + }); + const expected = t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: t.Union([t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), t.Null()]), + c3: t.Integer({ minimum: 1, maximum: 10 }), + nested: t.Object({ + c4: t.Union([intSchema, t.Null()]), + c5: t.Union([t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), t.Null()]), + c6: t.Integer({ minimum: 1, maximum: 10 }), + }), + table: t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: t.Union([t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), t.Null()]), + c3: t.Integer({ minimum: 1, maximum: 10 }), + c4: t.Union([intSchema, t.Null()]), + c5: t.Union([intSchema, t.Null()]), + c6: t.Union([intSchema, t.Null()]), + }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('all data types', (tc) => { + const table = mysqlTable('test', ({ + bigint, + binary, + boolean, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + mysqlEnum, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varchar, + varbinary, + year, + longtext, + mediumtext, + tinytext, + }) => ({ + bigint1: bigint({ mode: 'number' }).notNull(), + bigint2: bigint({ mode: 'bigint' }).notNull(), + bigint3: bigint({ unsigned: true, mode: 'number' }).notNull(), + bigint4: bigint({ unsigned: true, mode: 'bigint' }).notNull(), + binary: binary({ length: 10 }).notNull(), + boolean: boolean().notNull(), + char1: char({ length: 10 }).notNull(), + char2: char({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + date1: date({ mode: 'date' }).notNull(), + date2: date({ mode: 'string' }).notNull(), + datetime1: datetime({ mode: 'date' }).notNull(), + datetime2: datetime({ mode: 'string' }).notNull(), + decimal1: decimal().notNull(), + decimal2: decimal({ unsigned: true }).notNull(), + double1: double().notNull(), + double2: double({ unsigned: true }).notNull(), + float1: float().notNull(), + float2: float({ unsigned: true }).notNull(), + int1: int().notNull(), + int2: int({ unsigned: true }).notNull(), + json: json().notNull(), + mediumint1: mediumint().notNull(), + mediumint2: mediumint({ unsigned: true }).notNull(), + enum: mysqlEnum('enum', ['a', 'b', 'c']).notNull(), + real: real().notNull(), + serial: serial().notNull(), + smallint1: smallint().notNull(), + smallint2: smallint({ unsigned: true }).notNull(), + text1: text().notNull(), + text2: text({ enum: ['a', 'b', 'c'] }).notNull(), + time: time().notNull(), + timestamp1: timestamp({ mode: 'date' }).notNull(), + timestamp2: timestamp({ mode: 'string' }).notNull(), + tinyint1: tinyint().notNull(), + tinyint2: tinyint({ unsigned: true }).notNull(), + varchar1: varchar({ length: 10 }).notNull(), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + varbinary: varbinary({ length: 10 }).notNull(), + year: year().notNull(), + longtext1: longtext().notNull(), + longtext2: longtext({ enum: ['a', 'b', 'c'] }).notNull(), + mediumtext1: mediumtext().notNull(), + mediumtext2: mediumtext({ enum: ['a', 'b', 'c'] }).notNull(), + tinytext1: tinytext().notNull(), + tinytext2: tinytext({ enum: ['a', 'b', 'c'] }).notNull(), + })); + + const result = createSelectSchema(table); + const expected = t.Object({ + bigint1: t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: Number.MAX_SAFE_INTEGER }), + bigint2: t.BigInt({ minimum: CONSTANTS.INT64_MIN, maximum: CONSTANTS.INT64_MAX }), + bigint3: t.Integer({ minimum: 0, maximum: Number.MAX_SAFE_INTEGER }), + bigint4: t.BigInt({ minimum: 0n, maximum: CONSTANTS.INT64_UNSIGNED_MAX }), + binary: t.String(), + boolean: t.Boolean(), + char1: t.String({ minLength: 10, maxLength: 10 }), + char2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + date1: t.Date(), + date2: t.String(), + datetime1: t.Date(), + datetime2: t.String(), + decimal1: t.String(), + decimal2: t.String(), + double1: t.Number({ minimum: CONSTANTS.INT48_MIN, maximum: CONSTANTS.INT48_MAX }), + double2: t.Number({ minimum: 0, maximum: CONSTANTS.INT48_UNSIGNED_MAX }), + float1: t.Number({ minimum: CONSTANTS.INT24_MIN, maximum: CONSTANTS.INT24_MAX }), + float2: t.Number({ minimum: 0, maximum: CONSTANTS.INT24_UNSIGNED_MAX }), + int1: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: CONSTANTS.INT32_MAX }), + int2: t.Integer({ minimum: 0, maximum: CONSTANTS.INT32_UNSIGNED_MAX }), + json: jsonSchema, + mediumint1: t.Integer({ minimum: CONSTANTS.INT24_MIN, maximum: CONSTANTS.INT24_MAX }), + mediumint2: t.Integer({ minimum: 0, maximum: CONSTANTS.INT24_UNSIGNED_MAX }), + enum: t.Enum({ a: 'a', b: 'b', c: 'c' }), + real: t.Number({ minimum: CONSTANTS.INT48_MIN, maximum: CONSTANTS.INT48_MAX }), + serial: t.Integer({ minimum: 0, maximum: Number.MAX_SAFE_INTEGER }), + smallint1: t.Integer({ minimum: CONSTANTS.INT16_MIN, maximum: CONSTANTS.INT16_MAX }), + smallint2: t.Integer({ minimum: 0, maximum: CONSTANTS.INT16_UNSIGNED_MAX }), + text1: t.String({ maxLength: CONSTANTS.INT16_UNSIGNED_MAX }), + text2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + time: t.String(), + timestamp1: t.Date(), + timestamp2: t.String(), + tinyint1: t.Integer({ minimum: CONSTANTS.INT8_MIN, maximum: CONSTANTS.INT8_MAX }), + tinyint2: t.Integer({ minimum: 0, maximum: CONSTANTS.INT8_UNSIGNED_MAX }), + varchar1: t.String({ maxLength: 10 }), + varchar2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + varbinary: t.String(), + year: t.Integer({ minimum: 1901, maximum: 2155 }), + longtext1: t.String({ maxLength: CONSTANTS.INT32_UNSIGNED_MAX }), + longtext2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + mediumtext1: t.String({ maxLength: CONSTANTS.INT24_UNSIGNED_MAX }), + mediumtext2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + tinytext1: t.String({ maxLength: CONSTANTS.INT8_UNSIGNED_MAX }), + tinytext2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +/* Disallow unknown keys in table refinement - select */ { + const table = mysqlTable('test', { id: int() }); + // @ts-expect-error + createSelectSchema(table, { unknown: t.String() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = mysqlTable('test', { id: int() }); + // @ts-expect-error + createInsertSchema(table, { unknown: t.String() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = mysqlTable('test', { id: int() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: t.String() }); +} + +/* Disallow unknown keys in view qb - select */ { + const table = mysqlTable('test', { id: int() }); + const view = mysqlView('test').as((qb) => qb.select().from(table)); + const nestedSelect = mysqlView('test').as((qb) => qb.select({ table }).from(table)); + // @ts-expect-error + createSelectSchema(view, { unknown: t.String() }); + // @ts-expect-error + createSelectSchema(nestedSelect, { table: { unknown: t.String() } }); +} + +/* Disallow unknown keys in view columns - select */ { + const view = mysqlView('test', { id: int() }).as(sql``); + // @ts-expect-error + createSelectSchema(view, { unknown: t.String() }); +} diff --git a/drizzle-typebox/tests/pg.test.ts b/drizzle-typebox/tests/pg.test.ts index 355dee531..3e9769aef 100644 --- a/drizzle-typebox/tests/pg.test.ts +++ b/drizzle-typebox/tests/pg.test.ts @@ -1,189 +1,504 @@ -import { Type } from '@sinclair/typebox'; -import { Value } from '@sinclair/typebox/value'; -import { char, date, integer, pgEnum, pgTable, serial, text, timestamp, varchar } from 'drizzle-orm/pg-core'; -import { expect, test } from 'vitest'; -import { createInsertSchema, createSelectSchema, Nullable } from '../src'; -import { expectSchemaShape } from './utils.ts'; - -export const roleEnum = pgEnum('role', ['admin', 'user']); - -const users = pgTable('users', { - a: integer('a').array(), - id: serial('id').primaryKey(), - name: text('name'), - email: text('email').notNull(), - birthdayString: date('birthday_string').notNull(), - birthdayDate: date('birthday_date', { mode: 'date' }).notNull(), - createdAt: timestamp('created_at').notNull().defaultNow(), - role: roleEnum('role').notNull(), - roleText: text('role1', { enum: ['admin', 'user'] }).notNull(), - roleText2: text('role2', { enum: ['admin', 'user'] }) - .notNull() - .default('user'), - profession: varchar('profession', { length: 20 }).notNull(), - initials: char('initials', { length: 2 }).notNull(), -}); - -const testUser = { - a: [1, 2, 3], - id: 1, - name: 'John Doe', - email: 'john.doe@example.com', - birthdayString: '1990-01-01', - birthdayDate: new Date('1990-01-01'), - createdAt: new Date(), - role: 'admin', - roleText: 'admin', - roleText2: 'admin', - profession: 'Software Engineer', - initials: 'JD', -}; - -test('users insert valid user', () => { - const schema = createInsertSchema(users); - - expect(Value.Check(schema, testUser)).toBeTruthy(); -}); - -test('users insert invalid varchar', () => { - const schema = createInsertSchema(users); - - expect(Value.Check(schema, { - ...testUser, - profession: 'Chief Executive Officer', - })).toBeFalsy(); -}); - -test('users insert invalid char', () => { - const schema = createInsertSchema(users); - - expect(Value.Check(schema, { ...testUser, initials: 'JoDo' })).toBeFalsy(); -}); - -test('users insert schema', (t) => { - const actual = createInsertSchema(users, { - id: () => Type.Number({ minimum: 0 }), - email: () => Type.String(), - roleText: Type.Union([ - Type.Literal('user'), - Type.Literal('manager'), - Type.Literal('admin'), - ]), - }); - - (() => { - { - createInsertSchema(users, { - // @ts-expect-error (missing property) - foobar: Type.Number(), - }); - } - - { - createInsertSchema(users, { - // @ts-expect-error (invalid type) - id: 123, - }); - } - }); - - const expected = Type.Object({ - a: Type.Optional(Nullable(Type.Array(Type.Number()))), - id: Type.Optional(Type.Number({ minimum: 0 })), - name: Type.Optional(Nullable(Type.String())), - email: Type.String(), - birthdayString: Type.String(), - birthdayDate: Type.Date(), - createdAt: Type.Optional(Type.Date()), - role: Type.Union([Type.Literal('admin'), Type.Literal('user')]), - roleText: Type.Union([ - Type.Literal('user'), - Type.Literal('manager'), - Type.Literal('admin'), - ]), - roleText2: Type.Optional( - Type.Union([Type.Literal('admin'), Type.Literal('user')]), - ), - profession: Type.String({ maxLength: 20, minLength: 1 }), - initials: Type.String({ maxLength: 2, minLength: 1 }), - }); - - expectSchemaShape(t, expected).from(actual); -}); - -test('users insert schema w/ defaults', (t) => { - const actual = createInsertSchema(users); - - const expected = Type.Object({ - a: Type.Optional(Nullable(Type.Array(Type.Number()))), - id: Type.Optional(Type.Number()), - name: Type.Optional(Nullable(Type.String())), - email: Type.String(), - birthdayString: Type.String(), - birthdayDate: Type.Date(), - createdAt: Type.Optional(Type.Date()), - role: Type.Union([Type.Literal('admin'), Type.Literal('user')]), - roleText: Type.Union([Type.Literal('admin'), Type.Literal('user')]), - roleText2: Type.Optional( - Type.Union([Type.Literal('admin'), Type.Literal('user')]), - ), - profession: Type.String({ maxLength: 20, minLength: 1 }), - initials: Type.String({ maxLength: 2, minLength: 1 }), - }); - - expectSchemaShape(t, expected).from(actual); -}); - -test('users select schema', (t) => { - const actual = createSelectSchema(users, { - id: () => Type.Number({ minimum: 0 }), - email: () => Type.String(), - roleText: Type.Union([ - Type.Literal('admin'), - Type.Literal('user'), - Type.Literal('manager'), - ]), - }); - - const expected = Type.Object({ - a: Nullable(Type.Array(Type.Number())), - id: Type.Number({ minimum: 0 }), - name: Nullable(Type.String()), - email: Type.String(), - birthdayString: Type.String(), - birthdayDate: Type.Date(), - createdAt: Type.Date(), - role: Type.Union([Type.Literal('admin'), Type.Literal('user')]), - roleText: Type.Union([ - Type.Literal('admin'), - Type.Literal('user'), - Type.Literal('manager'), - ]), - roleText2: Type.Union([Type.Literal('admin'), Type.Literal('user')]), - profession: Type.String({ maxLength: 20, minLength: 1 }), - initials: Type.String({ maxLength: 2, minLength: 1 }), - }); - - expectSchemaShape(t, expected).from(actual); -}); - -test('users select schema w/ defaults', (t) => { - const actual = createSelectSchema(users); - - const expected = Type.Object({ - a: Nullable(Type.Array(Type.Number())), - id: Type.Number(), - name: Nullable(Type.String()), - email: Type.String(), - birthdayString: Type.String(), - birthdayDate: Type.Date(), - createdAt: Type.Date(), - role: Type.Union([Type.Literal('admin'), Type.Literal('user')]), - roleText: Type.Union([Type.Literal('admin'), Type.Literal('user')]), - roleText2: Type.Union([Type.Literal('admin'), Type.Literal('user')]), - profession: Type.String({ maxLength: 20, minLength: 1 }), - initials: Type.String({ maxLength: 2, minLength: 1 }), - }); - - expectSchemaShape(t, expected).from(actual); +import { Type as t } from '@sinclair/typebox'; +import { type Equal, sql } from 'drizzle-orm'; +import { integer, pgEnum, pgMaterializedView, pgSchema, pgTable, pgView, serial, text } from 'drizzle-orm/pg-core'; +import { test } from 'vitest'; +import { jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectEnumValues, expectSchemaShape } from './utils.ts'; + +const integerSchema = t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: CONSTANTS.INT32_MAX }); +const textSchema = t.String(); + +test('table - select', (tc) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = t.Object({ id: integerSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('table in schema - select', (tc) => { + const schema = pgSchema('test'); + const table = schema.table('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = t.Object({ id: integerSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('table - insert', (tc) => { + const table = pgTable('test', { + id: integer().generatedAlwaysAsIdentity().primaryKey(), + name: text().notNull(), + age: integer(), + }); + + const result = createInsertSchema(table); + const expected = t.Object({ name: textSchema, age: t.Optional(t.Union([integerSchema, t.Null()])) }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('table - update', (tc) => { + const table = pgTable('test', { + id: integer().generatedAlwaysAsIdentity().primaryKey(), + name: text().notNull(), + age: integer(), + }); + + const result = createUpdateSchema(table); + const expected = t.Object({ + name: t.Optional(textSchema), + age: t.Optional(t.Union([integerSchema, t.Null()])), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('view qb - select', (tc) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = pgView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + + const result = createSelectSchema(view); + const expected = t.Object({ id: integerSchema, age: t.Any() }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('view columns - select', (tc) => { + const view = pgView('test', { + id: serial().primaryKey(), + name: text().notNull(), + }).as(sql``); + + const result = createSelectSchema(view); + const expected = t.Object({ id: integerSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('materialized view qb - select', (tc) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = pgMaterializedView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + + const result = createSelectSchema(view); + const expected = t.Object({ id: integerSchema, age: t.Any() }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('materialized view columns - select', (tc) => { + const view = pgView('test', { + id: serial().primaryKey(), + name: text().notNull(), + }).as(sql``); + + const result = createSelectSchema(view); + const expected = t.Object({ id: integerSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('view with nested fields - select', (tc) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = pgMaterializedView('test').as((qb) => + qb.select({ + id: table.id, + nested: { + name: table.name, + age: sql``.as('age'), + }, + table, + }).from(table) + ); + + const result = createSelectSchema(view); + const expected = t.Object({ + id: integerSchema, + nested: t.Object({ name: textSchema, age: t.Any() }), + table: t.Object({ id: integerSchema, name: textSchema }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('enum - select', (tc) => { + const enum_ = pgEnum('test', ['a', 'b', 'c']); + + const result = createSelectSchema(enum_); + const expected = t.Enum({ a: 'a', b: 'b', c: 'c' }); + expectEnumValues(tc, expected).from(result); + Expect>(); +}); + +test('nullability - select', (tc) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().default(1), + c4: integer().notNull().default(1), + }); + + const result = createSelectSchema(table); + const expected = t.Object({ + c1: t.Union([integerSchema, t.Null()]), + c2: integerSchema, + c3: t.Union([integerSchema, t.Null()]), + c4: integerSchema, + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); + +test('nullability - insert', (tc) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().default(1), + c4: integer().notNull().default(1), + c5: integer().generatedAlwaysAs(1), + c6: integer().generatedAlwaysAsIdentity(), + c7: integer().generatedByDefaultAsIdentity(), + }); + + const result = createInsertSchema(table); + const expected = t.Object({ + c1: t.Optional(t.Union([integerSchema, t.Null()])), + c2: integerSchema, + c3: t.Optional(t.Union([integerSchema, t.Null()])), + c4: t.Optional(integerSchema), + c7: t.Optional(integerSchema), + }); + expectSchemaShape(tc, expected).from(result); +}); + +test('nullability - update', (tc) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().default(1), + c4: integer().notNull().default(1), + c5: integer().generatedAlwaysAs(1), + c6: integer().generatedAlwaysAsIdentity(), + c7: integer().generatedByDefaultAsIdentity(), + }); + + const result = createUpdateSchema(table); + const expected = t.Object({ + c1: t.Optional(t.Union([integerSchema, t.Null()])), + c2: t.Optional(integerSchema), + c3: t.Optional(t.Union([integerSchema, t.Null()])), + c4: t.Optional(integerSchema), + c7: t.Optional(integerSchema), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine table - select', (tc) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + }); + + const result = createSelectSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Union([integerSchema, t.Null()]), + c2: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine table - insert', (tc) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + c4: integer().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Optional(t.Union([integerSchema, t.Null()])), + c2: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine table - update', (tc) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + c4: integer().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Optional(t.Union([integerSchema, t.Null()])), + c2: t.Optional(t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 })), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine view - select', (tc) => { + const table = pgTable('test', { + c1: integer(), + c2: integer(), + c3: integer(), + c4: integer(), + c5: integer(), + c6: integer(), + }); + const view = pgView('test').as((qb) => + qb.select({ + c1: table.c1, + c2: table.c2, + c3: table.c3, + nested: { + c4: table.c4, + c5: table.c5, + c6: table.c6, + }, + table, + }).from(table) + ); + + const result = createSelectSchema(view, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + nested: { + c5: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c6: t.Integer({ minimum: 1, maximum: 10 }), + }, + table: { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }, + }); + const expected = t.Object({ + c1: t.Union([integerSchema, t.Null()]), + c2: t.Union([t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), t.Null()]), + c3: t.Integer({ minimum: 1, maximum: 10 }), + nested: t.Object({ + c4: t.Union([integerSchema, t.Null()]), + c5: t.Union([t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), t.Null()]), + c6: t.Integer({ minimum: 1, maximum: 10 }), + }), + table: t.Object({ + c1: t.Union([integerSchema, t.Null()]), + c2: t.Union([t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), t.Null()]), + c3: t.Integer({ minimum: 1, maximum: 10 }), + c4: t.Union([integerSchema, t.Null()]), + c5: t.Union([integerSchema, t.Null()]), + c6: t.Union([integerSchema, t.Null()]), + }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('all data types', (tc) => { + const table = pgTable('test', ({ + bigint, + bigserial, + bit, + boolean, + date, + char, + cidr, + doublePrecision, + geometry, + halfvec, + inet, + integer, + interval, + json, + jsonb, + line, + macaddr, + macaddr8, + numeric, + point, + real, + serial, + smallint, + smallserial, + text, + sparsevec, + time, + timestamp, + uuid, + varchar, + vector, + }) => ({ + bigint1: bigint({ mode: 'number' }).notNull(), + bigint2: bigint({ mode: 'bigint' }).notNull(), + bigserial1: bigserial({ mode: 'number' }).notNull(), + bigserial2: bigserial({ mode: 'bigint' }).notNull(), + bit: bit({ dimensions: 5 }).notNull(), + boolean: boolean().notNull(), + date1: date({ mode: 'date' }).notNull(), + date2: date({ mode: 'string' }).notNull(), + char1: char({ length: 10 }).notNull(), + char2: char({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + cidr: cidr().notNull(), + doublePrecision: doublePrecision().notNull(), + geometry1: geometry({ type: 'point', mode: 'tuple' }).notNull(), + geometry2: geometry({ type: 'point', mode: 'xy' }).notNull(), + halfvec: halfvec({ dimensions: 3 }).notNull(), + inet: inet().notNull(), + integer: integer().notNull(), + interval: interval().notNull(), + json: json().notNull(), + jsonb: jsonb().notNull(), + line1: line({ mode: 'abc' }).notNull(), + line2: line({ mode: 'tuple' }).notNull(), + macaddr: macaddr().notNull(), + macaddr8: macaddr8().notNull(), + numeric: numeric().notNull(), + point1: point({ mode: 'xy' }).notNull(), + point2: point({ mode: 'tuple' }).notNull(), + real: real().notNull(), + serial: serial().notNull(), + smallint: smallint().notNull(), + smallserial: smallserial().notNull(), + text1: text().notNull(), + text2: text({ enum: ['a', 'b', 'c'] }).notNull(), + sparsevec: sparsevec({ dimensions: 3 }).notNull(), + time: time().notNull(), + timestamp1: timestamp({ mode: 'date' }).notNull(), + timestamp2: timestamp({ mode: 'string' }).notNull(), + uuid: uuid().notNull(), + varchar1: varchar({ length: 10 }).notNull(), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + vector: vector({ dimensions: 3 }).notNull(), + array1: integer().array().notNull(), + array2: integer().array().array(2).notNull(), + array3: varchar({ length: 10 }).array().array(2).notNull(), + })); + + const result = createSelectSchema(table); + const expected = t.Object({ + bigint1: t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: Number.MAX_SAFE_INTEGER }), + bigint2: t.BigInt({ minimum: CONSTANTS.INT64_MIN, maximum: CONSTANTS.INT64_MAX }), + bigserial1: t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: Number.MAX_SAFE_INTEGER }), + bigserial2: t.BigInt({ minimum: CONSTANTS.INT64_MIN, maximum: CONSTANTS.INT64_MAX }), + bit: t.RegExp(/^[01]+$/, { maxLength: 5 }), + boolean: t.Boolean(), + date1: t.Date(), + date2: t.String(), + char1: t.String({ minLength: 10, maxLength: 10 }), + char2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + cidr: t.String(), + doublePrecision: t.Number({ minimum: CONSTANTS.INT48_MIN, maximum: CONSTANTS.INT48_MAX }), + geometry1: t.Tuple([t.Number(), t.Number()]), + geometry2: t.Object({ x: t.Number(), y: t.Number() }), + halfvec: t.Array(t.Number(), { minItems: 3, maxItems: 3 }), + inet: t.String(), + integer: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: CONSTANTS.INT32_MAX }), + interval: t.String(), + json: jsonSchema, + jsonb: jsonSchema, + line1: t.Object({ a: t.Number(), b: t.Number(), c: t.Number() }), + line2: t.Tuple([t.Number(), t.Number(), t.Number()]), + macaddr: t.String(), + macaddr8: t.String(), + numeric: t.String(), + point1: t.Object({ x: t.Number(), y: t.Number() }), + point2: t.Tuple([t.Number(), t.Number()]), + real: t.Number({ minimum: CONSTANTS.INT24_MIN, maximum: CONSTANTS.INT24_MAX }), + serial: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: CONSTANTS.INT32_MAX }), + smallint: t.Integer({ minimum: CONSTANTS.INT16_MIN, maximum: CONSTANTS.INT16_MAX }), + smallserial: t.Integer({ minimum: CONSTANTS.INT16_MIN, maximum: CONSTANTS.INT16_MAX }), + text1: t.String(), + text2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + sparsevec: t.String(), + time: t.String(), + timestamp1: t.Date(), + timestamp2: t.String(), + uuid: t.String({ format: 'uuid' }), + varchar1: t.String({ maxLength: 10 }), + varchar2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + vector: t.Array(t.Number(), { minItems: 3, maxItems: 3 }), + array1: t.Array(integerSchema), + array2: t.Array(t.Array(integerSchema), { minItems: 2, maxItems: 2 }), + array3: t.Array(t.Array(t.String({ maxLength: 10 })), { minItems: 2, maxItems: 2 }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +/* Disallow unknown keys in table refinement - select */ { + const table = pgTable('test', { id: integer() }); + // @ts-expect-error + createSelectSchema(table, { unknown: t.String() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = pgTable('test', { id: integer() }); + // @ts-expect-error + createInsertSchema(table, { unknown: t.String() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = pgTable('test', { id: integer() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: t.String() }); +} + +/* Disallow unknown keys in view qb - select */ { + const table = pgTable('test', { id: integer() }); + const view = pgView('test').as((qb) => qb.select().from(table)); + const mView = pgMaterializedView('test').as((qb) => qb.select().from(table)); + const nestedSelect = pgView('test').as((qb) => qb.select({ table }).from(table)); + // @ts-expect-error + createSelectSchema(view, { unknown: t.String() }); + // @ts-expect-error + createSelectSchema(mView, { unknown: t.String() }); + // @ts-expect-error + createSelectSchema(nestedSelect, { table: { unknown: t.String() } }); +} + +/* Disallow unknown keys in view columns - select */ { + const view = pgView('test', { id: integer() }).as(sql``); + const mView = pgView('test', { id: integer() }).as(sql``); + // @ts-expect-error + createSelectSchema(view, { unknown: t.String() }); + // @ts-expect-error + createSelectSchema(mView, { unknown: t.String() }); +} diff --git a/drizzle-typebox/tests/sqlite.test.ts b/drizzle-typebox/tests/sqlite.test.ts index a8506a269..ba2b55002 100644 --- a/drizzle-typebox/tests/sqlite.test.ts +++ b/drizzle-typebox/tests/sqlite.test.ts @@ -1,189 +1,363 @@ -import { type Static, Type } from '@sinclair/typebox'; -import { Value } from '@sinclair/typebox/value'; -import { blob, integer, numeric, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { expect, test } from 'vitest'; -import { createInsertSchema, createSelectSchema, jsonSchema, Nullable } from '../src'; -import { expectSchemaShape } from './utils.ts'; - -const blobJsonSchema = Type.Object({ - foo: Type.String(), -}); +import { Type as t } from '@sinclair/typebox'; +import { type Equal, sql } from 'drizzle-orm'; +import { int, sqliteTable, sqliteView, text } from 'drizzle-orm/sqlite-core'; +import { test } from 'vitest'; +import { bufferSchema, jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectSchemaShape } from './utils.ts'; + +const intSchema = t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: Number.MAX_SAFE_INTEGER }); +const textSchema = t.String(); + +test('table - select', (tc) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + }); -const users = sqliteTable('users', { - id: integer('id').primaryKey(), - blobJson: blob('blob', { mode: 'json' }) - .$type>() - .notNull(), - blobBigInt: blob('blob', { mode: 'bigint' }).notNull(), - numeric: numeric('numeric').notNull(), - createdAt: integer('created_at', { mode: 'timestamp' }).notNull(), - createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }).notNull(), - boolean: integer('boolean', { mode: 'boolean' }).notNull(), - real: real('real').notNull(), - text: text('text', { length: 255 }), - role: text('role', { enum: ['admin', 'user'] }) - .notNull() - .default('user'), + const result = createSelectSchema(table); + const expected = t.Object({ id: intSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -const testUser = { - id: 1, - blobJson: { foo: 'bar' }, - blobBigInt: BigInt(123), - numeric: '123.45', - createdAt: new Date(), - createdAtMs: new Date(), - boolean: true, - real: 123.45, - text: 'foobar', - role: 'admin', -}; - -test('users insert valid user', () => { - const schema = createInsertSchema(users); - // - expect(Value.Check(schema, testUser)).toBeTruthy(); +test('table - insert', (tc) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + age: int(), + }); + + const result = createInsertSchema(table); + const expected = t.Object({ + id: t.Optional(intSchema), + name: textSchema, + age: t.Optional(t.Union([intSchema, t.Null()])), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -test('users insert invalid text length', () => { - const schema = createInsertSchema(users); +test('table - update', (tc) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + age: int(), + }); - expect(Value.Check(schema, { ...testUser, text: 'a'.repeat(256) })).toBeFalsy(); + const result = createUpdateSchema(table); + const expected = t.Object({ + id: t.Optional(intSchema), + name: t.Optional(textSchema), + age: t.Optional(t.Union([intSchema, t.Null()])), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -test('users insert schema', (t) => { - const actual = createInsertSchema(users, { - id: () => Type.Number({ minimum: 0 }), - blobJson: blobJsonSchema, - role: Type.Union([ - Type.Literal('admin'), - Type.Literal('user'), - Type.Literal('manager'), - ]), - }); - - (() => { - { - createInsertSchema(users, { - // @ts-expect-error (missing property) - foobar: Type.Number(), - }); - } - - { - createInsertSchema(users, { - // @ts-expect-error (invalid type) - id: 123, - }); - } - }); - - const expected = Type.Object({ - id: Type.Optional(Type.Number({ minimum: 0 })), - blobJson: blobJsonSchema, - blobBigInt: Type.BigInt(), - numeric: Type.String(), - createdAt: Type.Date(), - createdAtMs: Type.Date(), - boolean: Type.Boolean(), - real: Type.Number(), - text: Type.Optional(Nullable(Type.String())), - role: Type.Optional( - Type.Union([ - Type.Literal('admin'), - Type.Literal('user'), - Type.Literal('manager'), - ]), - ), - }); - - expectSchemaShape(t, expected).from(actual); +test('view qb - select', (tc) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + }); + const view = sqliteView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + + const result = createSelectSchema(view); + const expected = t.Object({ id: intSchema, age: t.Any() }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -test('users insert schema w/ defaults', (t) => { - const actual = createInsertSchema(users); - - const expected = Type.Object({ - id: Type.Optional(Type.Number()), - blobJson: jsonSchema, - blobBigInt: Type.BigInt(), - numeric: Type.String(), - createdAt: Type.Date(), - createdAtMs: Type.Date(), - boolean: Type.Boolean(), - real: Type.Number(), - text: Type.Optional(Nullable(Type.String())), - role: Type.Optional( - Type.Union([Type.Literal('admin'), Type.Literal('user')]), - ), - }); - - expectSchemaShape(t, expected).from(actual); +test('view columns - select', (tc) => { + const view = sqliteView('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + }).as(sql``); + + const result = createSelectSchema(view); + const expected = t.Object({ id: intSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -test('users select schema', (t) => { - const actual = createSelectSchema(users, { - blobJson: jsonSchema, - role: Type.Union([ - Type.Literal('admin'), - Type.Literal('user'), - Type.Literal('manager'), - ]), - }); - - (() => { - { - createSelectSchema(users, { - // @ts-expect-error (missing property) - foobar: Type.Number(), - }); - } - - { - createSelectSchema(users, { - // @ts-expect-error (invalid type) - id: 123, - }); - } - }); - - const expected = Type.Strict( - Type.Object({ - id: Type.Number(), - blobJson: jsonSchema, - blobBigInt: Type.BigInt(), - numeric: Type.String(), - createdAt: Type.Date(), - createdAtMs: Type.Date(), - boolean: Type.Boolean(), - real: Type.Number(), - text: Nullable(Type.String()), - role: Type.Union([ - Type.Literal('admin'), - Type.Literal('user'), - Type.Literal('manager'), - ]), - }), +test('view with nested fields - select', (tc) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + }); + const view = sqliteView('test').as((qb) => + qb.select({ + id: table.id, + nested: { + name: table.name, + age: sql``.as('age'), + }, + table, + }).from(table) ); - expectSchemaShape(t, expected).from(actual); + const result = createSelectSchema(view); + const expected = t.Object({ + id: intSchema, + nested: t.Object({ name: textSchema, age: t.Any() }), + table: t.Object({ id: intSchema, name: textSchema }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -test('users select schema w/ defaults', (t) => { - const actual = createSelectSchema(users); +test('nullability - select', (tc) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + }); - const expected = Type.Object({ - id: Type.Number(), - blobJson: jsonSchema, - blobBigInt: Type.BigInt(), - numeric: Type.String(), - createdAt: Type.Date(), - createdAtMs: Type.Date(), - boolean: Type.Boolean(), - real: Type.Number(), - text: Nullable(Type.String()), - role: Type.Union([Type.Literal('admin'), Type.Literal('user')]), + const result = createSelectSchema(table); + const expected = t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: intSchema, + c3: t.Union([intSchema, t.Null()]), + c4: intSchema, + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('nullability - insert', (tc) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: intSchema, + c3: t.Optional(t.Union([intSchema, t.Null()])), + c4: t.Optional(intSchema), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('nullability - update', (tc) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), }); - expectSchemaShape(t, expected).from(actual); + const result = createUpdateSchema(table); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: t.Optional(intSchema), + c3: t.Optional(t.Union([intSchema, t.Null()])), + c4: t.Optional(intSchema), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine table - select', (tc) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + }); + + const result = createSelectSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); + +test('refine table - insert', (tc) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine table - update', (tc) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: t.Optional(t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: 1000 })), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine view - select', (tc) => { + const table = sqliteTable('test', { + c1: int(), + c2: int(), + c3: int(), + c4: int(), + c5: int(), + c6: int(), + }); + const view = sqliteView('test').as((qb) => + qb.select({ + c1: table.c1, + c2: table.c2, + c3: table.c3, + nested: { + c4: table.c4, + c5: table.c5, + c6: table.c6, + }, + table, + }).from(table) + ); + + const result = createSelectSchema(view, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + nested: { + c5: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c6: t.Integer({ minimum: 1, maximum: 10 }), + }, + table: { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }, + }); + const expected = t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: t.Union([t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: 1000 }), t.Null()]), + c3: t.Integer({ minimum: 1, maximum: 10 }), + nested: t.Object({ + c4: t.Union([intSchema, t.Null()]), + c5: t.Union([t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: 1000 }), t.Null()]), + c6: t.Integer({ minimum: 1, maximum: 10 }), + }), + table: t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: t.Union([t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: 1000 }), t.Null()]), + c3: t.Integer({ minimum: 1, maximum: 10 }), + c4: t.Union([intSchema, t.Null()]), + c5: t.Union([intSchema, t.Null()]), + c6: t.Union([intSchema, t.Null()]), + }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('all data types', (tc) => { + const table = sqliteTable('test', ({ + blob, + integer, + numeric, + real, + text, + }) => ({ + blob1: blob({ mode: 'buffer' }).notNull(), + blob2: blob({ mode: 'bigint' }).notNull(), + blob3: blob({ mode: 'json' }).notNull(), + integer1: integer({ mode: 'number' }).notNull(), + integer2: integer({ mode: 'boolean' }).notNull(), + integer3: integer({ mode: 'timestamp' }).notNull(), + integer4: integer({ mode: 'timestamp_ms' }).notNull(), + numeric: numeric().notNull(), + real: real().notNull(), + text1: text({ mode: 'text' }).notNull(), + text2: text({ mode: 'text', length: 10 }).notNull(), + text3: text({ mode: 'text', enum: ['a', 'b', 'c'] }).notNull(), + text4: text({ mode: 'json' }).notNull(), + })); + + const result = createSelectSchema(table); + const expected = t.Object({ + blob1: bufferSchema, + blob2: t.BigInt({ minimum: CONSTANTS.INT64_MIN, maximum: CONSTANTS.INT64_MAX }), + blob3: jsonSchema, + integer1: t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: Number.MAX_SAFE_INTEGER }), + integer2: t.Boolean(), + integer3: t.Date(), + integer4: t.Date(), + numeric: t.String(), + real: t.Number({ minimum: CONSTANTS.INT48_MIN, maximum: CONSTANTS.INT48_MAX }), + text1: t.String(), + text2: t.String({ maxLength: 10 }), + text3: t.Enum({ a: 'a', b: 'b', c: 'c' }), + text4: jsonSchema, + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +/* Disallow unknown keys in table refinement - select */ { + const table = sqliteTable('test', { id: int() }); + // @ts-expect-error + createSelectSchema(table, { unknown: t.String() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = sqliteTable('test', { id: int() }); + // @ts-expect-error + createInsertSchema(table, { unknown: t.String() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = sqliteTable('test', { id: int() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: t.String() }); +} + +/* Disallow unknown keys in view qb - select */ { + const table = sqliteTable('test', { id: int() }); + const view = sqliteView('test').as((qb) => qb.select().from(table)); + const nestedSelect = sqliteView('test').as((qb) => qb.select({ table }).from(table)); + // @ts-expect-error + createSelectSchema(view, { unknown: t.String() }); + // @ts-expect-error + createSelectSchema(nestedSelect, { table: { unknown: t.String() } }); +} + +/* Disallow unknown keys in view columns - select */ { + const view = sqliteView('test', { id: int() }).as(sql``); + // @ts-expect-error + createSelectSchema(view, { unknown: t.String() }); +} diff --git a/drizzle-typebox/tests/utils.ts b/drizzle-typebox/tests/utils.ts index e17e5f26d..46cd16a32 100644 --- a/drizzle-typebox/tests/utils.ts +++ b/drizzle-typebox/tests/utils.ts @@ -1,17 +1,34 @@ -import type { TSchema } from '@sinclair/typebox'; +import type * as t from '@sinclair/typebox'; import { expect, type TaskContext } from 'vitest'; -export function expectSchemaShape(t: TaskContext, expected: T) { +function removeKeysFromObject(obj: Record, keys: string[]) { + for (const key of keys) { + delete obj[key]; + } + return obj; +} + +export function expectSchemaShape(t: TaskContext, expected: T) { return { from(actual: T) { - expect(Object.keys(actual)).toStrictEqual(Object.keys(expected)); + expect(Object.keys(actual.properties)).toStrictEqual(Object.keys(expected.properties)); + const keys = ['$id', '$schema', 'title', 'description', 'default', 'examples', 'readOnly', 'writeOnly']; - for (const key of Object.keys(actual)) { - expect(actual[key].type).toStrictEqual(expected[key]?.type); - if (actual[key].optional) { - expect(actual[key].optional).toStrictEqual(expected[key]?.optional); - } + for (const key of Object.keys(actual.properties)) { + expect(removeKeysFromObject(actual.properties[key]!, keys)).toStrictEqual( + removeKeysFromObject(expected.properties[key]!, keys), + ); } }, }; } + +export function expectEnumValues>(t: TaskContext, expected: T) { + return { + from(actual: T) { + expect(actual.anyOf).toStrictEqual(expected.anyOf); + }, + }; +} + +export function Expect<_ extends true>() {} diff --git a/drizzle-typebox/tsconfig.json b/drizzle-typebox/tsconfig.json index 038d79591..c25379c37 100644 --- a/drizzle-typebox/tsconfig.json +++ b/drizzle-typebox/tsconfig.json @@ -4,6 +4,7 @@ "outDir": "dist", "baseUrl": ".", "declaration": true, + "noEmit": true, "paths": { "~/*": ["src/*"] } diff --git a/drizzle-valibot/README.md b/drizzle-valibot/README.md index 7696e0297..735e40b34 100644 --- a/drizzle-valibot/README.md +++ b/drizzle-valibot/README.md @@ -1,11 +1,17 @@ `drizzle-valibot` is a plugin for [Drizzle ORM](https://github.com/drizzle-team/drizzle-orm) that allows you to generate [valibot](https://valibot.dev/) schemas from Drizzle ORM schemas. +**Features** + +- Create a select schema for tables, views and enums. +- Create insert and update schemas for tables. +- Supports all dialects: PostgreSQL, MySQL and SQLite. + # Usage ```ts import { pgEnum, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; import { createInsertSchema, createSelectSchema } from 'drizzle-valibot'; -import { string, parse, number } from 'valibot'; +import { string, parse, number, pipe } from 'valibot'; const users = pgTable('users', { id: serial('id').primaryKey(), @@ -18,6 +24,9 @@ const users = pgTable('users', { // Schema for inserting a user - can be used to validate API requests const insertUserSchema = createInsertSchema(users); +// Schema for updating a user - can be used to validate API requests +const updateUserSchema = createUpdateSchema(users); + // Schema for selecting a user - can be used to validate API responses const selectUserSchema = createSelectSchema(users); @@ -28,7 +37,7 @@ const insertUserSchema = createInsertSchema(users, { // Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema const insertUserSchema = createInsertSchema(users, { - id: (schema) => number([minValue(0)]), + id: (schema) => pipe([schema, minValue(0)]), role: string(), }); diff --git a/drizzle-valibot/package.json b/drizzle-valibot/package.json index 1d88fd26a..9d14c39b9 100644 --- a/drizzle-valibot/package.json +++ b/drizzle-valibot/package.json @@ -55,18 +55,17 @@ "author": "Drizzle Team", "license": "Apache-2.0", "peerDependencies": { - "drizzle-orm": ">=0.23.13", - "valibot": ">=0.20" + "drizzle-orm": ">=0.36.0", + "valibot": ">=1.0.0-beta.7" }, "devDependencies": { - "@rollup/plugin-terser": "^0.4.1", "@rollup/plugin-typescript": "^11.1.0", "@types/node": "^18.15.10", "cpy": "^10.1.0", "drizzle-orm": "link:../drizzle-orm/dist", "rimraf": "^5.0.0", "rollup": "^3.20.7", - "valibot": "^0.30.0", + "valibot": "1.0.0-beta.7", "vite-tsconfig-paths": "^4.3.2", "vitest": "^1.6.0", "zx": "^7.2.2" diff --git a/drizzle-valibot/rollup.config.ts b/drizzle-valibot/rollup.config.ts index 2ed2d33d3..986da4883 100644 --- a/drizzle-valibot/rollup.config.ts +++ b/drizzle-valibot/rollup.config.ts @@ -1,4 +1,3 @@ -import terser from '@rollup/plugin-terser'; import typescript from '@rollup/plugin-typescript'; import { defineConfig } from 'rollup'; @@ -23,13 +22,12 @@ export default defineConfig([ ], external: [ /^drizzle-orm\/?/, - 'zod', + 'valibot', ], plugins: [ typescript({ tsconfig: 'tsconfig.build.json', }), - terser(), ], }, ]); diff --git a/drizzle-valibot/scripts/build.ts b/drizzle-valibot/scripts/build.ts index 1910feac6..07330ffd0 100755 --- a/drizzle-valibot/scripts/build.ts +++ b/drizzle-valibot/scripts/build.ts @@ -13,3 +13,4 @@ await cpy('dist/**/*.d.ts', 'dist', { rename: (basename) => basename.replace(/\.d\.ts$/, '.d.cts'), }); await fs.copy('package.json', 'dist/package.json'); +await $`scripts/fix-imports.ts`; diff --git a/drizzle-valibot/scripts/fix-imports.ts b/drizzle-valibot/scripts/fix-imports.ts new file mode 100755 index 000000000..a90057c5b --- /dev/null +++ b/drizzle-valibot/scripts/fix-imports.ts @@ -0,0 +1,136 @@ +#!/usr/bin/env -S pnpm tsx +import 'zx/globals'; + +import path from 'node:path'; +import { parse, print, visit } from 'recast'; +import parser from 'recast/parsers/typescript'; + +function resolvePathAlias(importPath: string, file: string) { + if (importPath.startsWith('~/')) { + const relativePath = path.relative(path.dirname(file), path.resolve('dist.new', importPath.slice(2))); + importPath = relativePath.startsWith('.') ? relativePath : './' + relativePath; + } + + return importPath; +} + +function fixImportPath(importPath: string, file: string, ext: string) { + importPath = resolvePathAlias(importPath, file); + + if (!/\..*\.(js|ts)$/.test(importPath)) { + return importPath; + } + + return importPath.replace(/\.(js|ts)$/, ext); +} + +const cjsFiles = await glob('dist/**/*.{cjs,d.cts}'); + +await Promise.all(cjsFiles.map(async (file) => { + const code = parse(await fs.readFile(file, 'utf8'), { parser }); + + visit(code, { + visitImportDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + this.traverse(path); + }, + visitExportAllDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + this.traverse(path); + }, + visitExportNamedDeclaration(path) { + if (path.value.source) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + } + this.traverse(path); + }, + visitCallExpression(path) { + if (path.value.callee.type === 'Identifier' && path.value.callee.name === 'require') { + path.value.arguments[0].value = fixImportPath(path.value.arguments[0].value, file, '.cjs'); + } + this.traverse(path); + }, + visitTSImportType(path) { + path.value.argument.value = resolvePathAlias(path.value.argument.value, file); + this.traverse(path); + }, + visitAwaitExpression(path) { + if (print(path.value).code.startsWith(`await import("./`)) { + path.value.argument.arguments[0].value = fixImportPath(path.value.argument.arguments[0].value, file, '.cjs'); + } + this.traverse(path); + }, + }); + + await fs.writeFile(file, print(code).code); +})); + +let esmFiles = await glob('dist/**/*.{js,d.ts}'); + +await Promise.all(esmFiles.map(async (file) => { + const code = parse(await fs.readFile(file, 'utf8'), { parser }); + + visit(code, { + visitImportDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + this.traverse(path); + }, + visitExportAllDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + this.traverse(path); + }, + visitExportNamedDeclaration(path) { + if (path.value.source) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + } + this.traverse(path); + }, + visitTSImportType(path) { + path.value.argument.value = fixImportPath(path.value.argument.value, file, '.js'); + this.traverse(path); + }, + visitAwaitExpression(path) { + if (print(path.value).code.startsWith(`await import("./`)) { + path.value.argument.arguments[0].value = fixImportPath(path.value.argument.arguments[0].value, file, '.js'); + } + this.traverse(path); + }, + }); + + await fs.writeFile(file, print(code).code); +})); + +esmFiles = await glob('dist/**/*.{mjs,d.mts}'); + +await Promise.all(esmFiles.map(async (file) => { + const code = parse(await fs.readFile(file, 'utf8'), { parser }); + + visit(code, { + visitImportDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.mjs'); + this.traverse(path); + }, + visitExportAllDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.mjs'); + this.traverse(path); + }, + visitExportNamedDeclaration(path) { + if (path.value.source) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.mjs'); + } + this.traverse(path); + }, + visitTSImportType(path) { + path.value.argument.value = fixImportPath(path.value.argument.value, file, '.mjs'); + this.traverse(path); + }, + visitAwaitExpression(path) { + if (print(path.value).code.startsWith(`await import("./`)) { + path.value.argument.arguments[0].value = fixImportPath(path.value.argument.arguments[0].value, file, '.mjs'); + } + this.traverse(path); + }, + }); + + await fs.writeFile(file, print(code).code); +})); diff --git a/drizzle-valibot/src/column.ts b/drizzle-valibot/src/column.ts new file mode 100644 index 000000000..e5716fe1e --- /dev/null +++ b/drizzle-valibot/src/column.ts @@ -0,0 +1,239 @@ +import type { Column, ColumnBaseConfig } from 'drizzle-orm'; +import type { + MySqlBigInt53, + MySqlChar, + MySqlDouble, + MySqlFloat, + MySqlInt, + MySqlMediumInt, + MySqlReal, + MySqlSerial, + MySqlSmallInt, + MySqlText, + MySqlTinyInt, + MySqlVarChar, + MySqlYear, +} from 'drizzle-orm/mysql-core'; +import type { + PgArray, + PgBigInt53, + PgBigSerial53, + PgBinaryVector, + PgChar, + PgDoublePrecision, + PgGeometry, + PgGeometryObject, + PgHalfVector, + PgInteger, + PgLineABC, + PgLineTuple, + PgPointObject, + PgPointTuple, + PgReal, + PgSerial, + PgSmallInt, + PgSmallSerial, + PgUUID, + PgVarchar, + PgVector, +} from 'drizzle-orm/pg-core'; +import type { SQLiteInteger, SQLiteReal, SQLiteText } from 'drizzle-orm/sqlite-core'; +import * as v from 'valibot'; +import { CONSTANTS } from './constants.ts'; +import { isColumnType, isWithEnum } from './utils.ts'; +import type { Json } from './utils.ts'; + +export const literalSchema = v.union([v.string(), v.number(), v.boolean(), v.null()]); +export const jsonSchema: v.GenericSchema = v.union([ + literalSchema, + v.array(v.lazy(() => jsonSchema)), + v.record(v.string(), v.lazy(() => jsonSchema)), +]); +export const bufferSchema: v.GenericSchema = v.custom((v) => v instanceof Buffer); // eslint-disable-line no-instanceof/no-instanceof + +export function mapEnumValues(values: string[]) { + return Object.fromEntries(values.map((value) => [value, value])); +} + +/** @internal */ +export function columnToSchema(column: Column): v.GenericSchema { + let schema!: v.GenericSchema; + + if (isWithEnum(column)) { + schema = column.enumValues.length ? v.enum(mapEnumValues(column.enumValues)) : v.string(); + } + + if (!schema) { + // Handle specific types + if (isColumnType | PgPointTuple>(column, ['PgGeometry', 'PgPointTuple'])) { + schema = v.tuple([v.number(), v.number()]); + } else if ( + isColumnType | PgGeometryObject>(column, ['PgGeometryObject', 'PgPointObject']) + ) { + schema = v.object({ x: v.number(), y: v.number() }); + } else if (isColumnType | PgVector>(column, ['PgHalfVector', 'PgVector'])) { + schema = v.array(v.number()); + schema = column.dimensions ? v.pipe(schema as v.ArraySchema, v.length(column.dimensions)) : schema; + } else if (isColumnType>(column, ['PgLine'])) { + schema = v.tuple([v.number(), v.number(), v.number()]); + v.array(v.array(v.number())); + } else if (isColumnType>(column, ['PgLineABC'])) { + schema = v.object({ a: v.number(), b: v.number(), c: v.number() }); + } // Handle other types + else if (isColumnType>(column, ['PgArray'])) { + schema = v.array(columnToSchema(column.baseColumn)); + schema = column.size ? v.pipe(schema as v.ArraySchema, v.length(column.size)) : schema; + } else if (column.dataType === 'array') { + schema = v.array(v.any()); + } else if (column.dataType === 'number') { + schema = numberColumnToSchema(column); + } else if (column.dataType === 'bigint') { + schema = bigintColumnToSchema(column); + } else if (column.dataType === 'boolean') { + schema = v.boolean(); + } else if (column.dataType === 'date') { + schema = v.date(); + } else if (column.dataType === 'string') { + schema = stringColumnToSchema(column); + } else if (column.dataType === 'json') { + schema = jsonSchema; + } else if (column.dataType === 'custom') { + schema = v.any(); + } else if (column.dataType === 'buffer') { + schema = bufferSchema; + } + } + + if (!schema) { + schema = v.any(); + } + + return schema; +} + +function numberColumnToSchema(column: Column): v.GenericSchema { + let unsigned = column.getSQLType().includes('unsigned'); + let min!: number; + let max!: number; + let integer = false; + + if (isColumnType>(column, ['MySqlTinyInt'])) { + min = unsigned ? 0 : CONSTANTS.INT8_MIN; + max = unsigned ? CONSTANTS.INT8_UNSIGNED_MAX : CONSTANTS.INT8_MAX; + integer = true; + } else if ( + isColumnType | PgSmallSerial | MySqlSmallInt>(column, [ + 'PgSmallInt', + 'PgSmallSerial', + 'MySqlSmallInt', + ]) + ) { + min = unsigned ? 0 : CONSTANTS.INT16_MIN; + max = unsigned ? CONSTANTS.INT16_UNSIGNED_MAX : CONSTANTS.INT16_MAX; + integer = true; + } else if ( + isColumnType | MySqlFloat | MySqlMediumInt>(column, [ + 'PgReal', + 'MySqlFloat', + 'MySqlMediumInt', + ]) + ) { + min = unsigned ? 0 : CONSTANTS.INT24_MIN; + max = unsigned ? CONSTANTS.INT24_UNSIGNED_MAX : CONSTANTS.INT24_MAX; + integer = isColumnType(column, ['MySqlMediumInt']); + } else if ( + isColumnType | PgSerial | MySqlInt>(column, ['PgInteger', 'PgSerial', 'MySqlInt']) + ) { + min = unsigned ? 0 : CONSTANTS.INT32_MIN; + max = unsigned ? CONSTANTS.INT32_UNSIGNED_MAX : CONSTANTS.INT32_MAX; + integer = true; + } else if ( + isColumnType | MySqlReal | MySqlDouble | SQLiteReal>(column, [ + 'PgDoublePrecision', + 'MySqlReal', + 'MySqlDouble', + 'SQLiteReal', + ]) + ) { + min = unsigned ? 0 : CONSTANTS.INT48_MIN; + max = unsigned ? CONSTANTS.INT48_UNSIGNED_MAX : CONSTANTS.INT48_MAX; + } else if ( + isColumnType | PgBigSerial53 | MySqlBigInt53 | MySqlSerial | SQLiteInteger>( + column, + ['PgBigInt53', 'PgBigSerial53', 'MySqlBigInt53', 'MySqlSerial', 'SQLiteInteger'], + ) + ) { + unsigned = unsigned || isColumnType(column, ['MySqlSerial']); + min = unsigned ? 0 : Number.MIN_SAFE_INTEGER; + max = Number.MAX_SAFE_INTEGER; + integer = true; + } else if (isColumnType>(column, ['MySqlYear'])) { + min = 1901; + max = 2155; + integer = true; + } else { + min = Number.MIN_SAFE_INTEGER; + max = Number.MAX_SAFE_INTEGER; + } + + const actions: any[] = [v.minValue(min), v.maxValue(max)]; + if (integer) { + actions.push(v.integer()); + } + return v.pipe(v.number(), ...actions); +} + +function bigintColumnToSchema(column: Column): v.GenericSchema { + const unsigned = column.getSQLType().includes('unsigned'); + const min = unsigned ? 0n : CONSTANTS.INT64_MIN; + const max = unsigned ? CONSTANTS.INT64_UNSIGNED_MAX : CONSTANTS.INT64_MAX; + + return v.pipe(v.bigint(), v.minValue(min), v.maxValue(max)); +} + +function stringColumnToSchema(column: Column): v.GenericSchema { + if (isColumnType>>(column, ['PgUUID'])) { + return v.pipe(v.string(), v.uuid()); + } + + let max: number | undefined; + let regex: RegExp | undefined; + let fixed = false; + + if (isColumnType | SQLiteText>(column, ['PgVarchar', 'SQLiteText'])) { + max = column.length; + } else if (isColumnType>(column, ['MySqlVarChar'])) { + max = column.length ?? CONSTANTS.INT16_UNSIGNED_MAX; + } else if (isColumnType>(column, ['MySqlText'])) { + if (column.textType === 'longtext') { + max = CONSTANTS.INT32_UNSIGNED_MAX; + } else if (column.textType === 'mediumtext') { + max = CONSTANTS.INT24_UNSIGNED_MAX; + } else if (column.textType === 'text') { + max = CONSTANTS.INT16_UNSIGNED_MAX; + } else { + max = CONSTANTS.INT8_UNSIGNED_MAX; + } + } + + if (isColumnType | MySqlChar>(column, ['PgChar', 'MySqlChar'])) { + max = column.length; + fixed = true; + } + + if (isColumnType>(column, ['PgBinaryVector'])) { + regex = /^[01]+$/; + max = column.dimensions; + } + + const actions: any[] = []; + if (regex) { + actions.push(v.regex(regex)); + } + if (max && fixed) { + actions.push(v.length(max)); + } else if (max) { + actions.push(v.maxLength(max)); + } + return actions.length > 0 ? v.pipe(v.string(), ...actions) : v.string(); +} diff --git a/drizzle-valibot/src/column.types.ts b/drizzle-valibot/src/column.types.ts new file mode 100644 index 000000000..e6cd797ed --- /dev/null +++ b/drizzle-valibot/src/column.types.ts @@ -0,0 +1,202 @@ +import type { Assume, Column } from 'drizzle-orm'; +import type * as v from 'valibot'; +import type { + ArrayHasAtLeastOneValue, + ColumnIsGeneratedAlwaysAs, + IsNever, + Json, + RemoveNeverElements, +} from './utils.ts'; + +export type GetEnumValuesFromColumn = TColumn['_'] extends { enumValues: [string, ...string[]] } + ? TColumn['_']['enumValues'] + : undefined; + +export type GetBaseColumn = TColumn['_'] extends { baseColumn: Column | never | undefined } + ? IsNever extends false ? TColumn['_']['baseColumn'] + : undefined + : undefined; + +export type EnumValuesToEnum = { readonly [K in TEnumValues[number]]: K }; + +export type ExtractAdditionalProperties = { + max: TColumn['_']['columnType'] extends 'PgVarchar' | 'SQLiteText' | 'PgChar' | 'MySqlChar' + ? Assume['length'] + : TColumn['_']['columnType'] extends 'MySqlText' | 'MySqlVarChar' ? number + : TColumn['_']['columnType'] extends 'PgBinaryVector' | 'PgHalfVector' | 'PgVector' + ? Assume['dimensions'] + : TColumn['_']['columnType'] extends 'PgArray' ? Assume['size'] + : undefined; + fixedLength: TColumn['_']['columnType'] extends 'PgChar' | 'MySqlChar' | 'PgHalfVector' | 'PgVector' | 'PgArray' + ? true + : false; + arrayPipelines: []; +}; + +type RemovePipeIfNoElements> = T extends + infer TPiped extends { pipe: [any, ...any[]] } ? TPiped['pipe'][1] extends undefined ? T['pipe'][0] : TPiped + : never; + +type BuildArraySchema< + TWrapped extends v.GenericSchema, + TPipelines extends any[][], +> = TPipelines extends [infer TFirst extends any[], ...infer TRest extends any[][]] + ? BuildArraySchema, ...TFirst]>>, TRest> + : TPipelines extends [infer TFirst extends any[]] + ? BuildArraySchema, ...TFirst]>>, []> + : TWrapped; + +export type GetValibotType< + TData, + TDataType extends string, + TColumnType extends string, + TEnumValues extends [string, ...string[]] | undefined, + TBaseColumn extends Column | undefined, + TAdditionalProperties extends Record, +> = TColumnType extends 'PgHalfVector' | 'PgVector' ? RemovePipeIfNoElements< + v.SchemaWithPipe< + RemoveNeverElements<[ + v.ArraySchema, undefined>, + TAdditionalProperties['max'] extends number + ? TAdditionalProperties['fixedLength'] extends true ? v.LengthAction + : v.MaxLengthAction + : never, + ]> + > + > + : TColumnType extends 'PgUUID' ? v.SchemaWithPipe<[v.StringSchema, v.UuidAction]> + // PG array handling start + // Nesting `GetValibotType` within `v.ArraySchema` will cause infinite recursion + // The workaround is to accumulate all the array validations (done via `arrayPipelines` in `TAdditionalProperties`) and then build the schema afterwards + : TAdditionalProperties['arrayFinished'] extends true ? GetValibotType< + TData, + TDataType, + TColumnType, + TEnumValues, + TBaseColumn, + Omit + > extends infer TSchema extends v.GenericSchema ? BuildArraySchema + : never + : TBaseColumn extends Column ? GetValibotType< + TBaseColumn['_']['data'], + TBaseColumn['_']['dataType'], + TBaseColumn['_']['columnType'], + GetEnumValuesFromColumn, + GetBaseColumn, + Omit, 'arrayPipelines'> & { + arrayPipelines: [ + RemoveNeverElements<[ + TAdditionalProperties['max'] extends number + ? TAdditionalProperties['fixedLength'] extends true + ? v.LengthAction[], number, undefined> + : v.MaxLengthAction[], number, undefined> + : never, + ]>, + ...TAdditionalProperties['arrayPipelines'], + ]; + arrayFinished: GetBaseColumn extends undefined ? true : false; + } + > + // PG array handling end + : ArrayHasAtLeastOneValue extends true + ? v.EnumSchema>, undefined> + : TData extends infer TTuple extends [any, ...any[]] ? v.TupleSchema< + Assume< + { [K in keyof TTuple]: GetValibotType }, + [any, ...any[]] + >, + undefined + > + : TData extends Date ? v.DateSchema + : TData extends Buffer ? v.GenericSchema + : TDataType extends 'array' ? v.ArraySchema< + GetValibotType[number], string, string, undefined, undefined, { noPipe: true }>, + undefined + > + : TData extends infer TDict extends Record ? v.ObjectSchema< + { readonly [K in keyof TDict]: GetValibotType }, + undefined + > + : TDataType extends 'json' ? v.GenericSchema + : TData extends number ? TAdditionalProperties['noPipe'] extends true ? v.NumberSchema : v.SchemaWithPipe< + RemoveNeverElements<[ + v.NumberSchema, + v.MinValueAction, + v.MaxValueAction, + TColumnType extends + | 'MySqlTinyInt' + | 'PgSmallInt' + | 'PgSmallSerial' + | 'MySqlSmallInt' + | 'MySqlMediumInt' + | 'PgInteger' + | 'PgSerial' + | 'MySqlInt' + | 'PgBigInt53' + | 'PgBigSerial53' + | 'MySqlBigInt53' + | 'MySqlSerial' + | 'SQLiteInteger' + | 'MySqlYear' ? v.IntegerAction + : never, + ]> + > + : TData extends bigint ? TAdditionalProperties['noPipe'] extends true ? v.BigintSchema : v.SchemaWithPipe<[ + v.BigintSchema, + v.MinValueAction, + v.MaxValueAction, + ]> + : TData extends boolean ? v.BooleanSchema + : TData extends string ? RemovePipeIfNoElements< + v.SchemaWithPipe< + RemoveNeverElements<[ + v.StringSchema, + TColumnType extends 'PgBinaryVector' ? v.RegexAction + : never, + TAdditionalProperties['max'] extends number + ? TAdditionalProperties['fixedLength'] extends true ? v.LengthAction + : v.MaxLengthAction + : never, + ]> + > + > + : v.AnySchema; + +type HandleSelectColumn< + TSchema extends v.GenericSchema, + TColumn extends Column, +> = TColumn['_']['notNull'] extends true ? TSchema + : v.NullableSchema; + +type HandleInsertColumn< + TSchema extends v.GenericSchema, + TColumn extends Column, +> = ColumnIsGeneratedAlwaysAs extends true ? never + : TColumn['_']['notNull'] extends true + ? TColumn['_']['hasDefault'] extends true ? v.OptionalSchema + : TSchema + : v.OptionalSchema, undefined>; + +type HandleUpdateColumn< + TSchema extends v.GenericSchema, + TColumn extends Column, +> = ColumnIsGeneratedAlwaysAs extends true ? never + : TColumn['_']['notNull'] extends true ? v.OptionalSchema + : v.OptionalSchema, undefined>; + +export type HandleColumn< + TType extends 'select' | 'insert' | 'update', + TColumn extends Column, +> = GetValibotType< + TColumn['_']['data'], + TColumn['_']['dataType'], + TColumn['_']['columnType'], + GetEnumValuesFromColumn, + GetBaseColumn, + ExtractAdditionalProperties +> extends infer TSchema extends v.GenericSchema ? TSchema extends v.AnySchema ? v.AnySchema + : TType extends 'select' ? HandleSelectColumn + : TType extends 'insert' ? HandleInsertColumn + : TType extends 'update' ? HandleUpdateColumn + : TSchema + : v.AnySchema; diff --git a/drizzle-valibot/src/constants.ts b/drizzle-valibot/src/constants.ts new file mode 100644 index 000000000..99f5d7a42 --- /dev/null +++ b/drizzle-valibot/src/constants.ts @@ -0,0 +1,20 @@ +export const CONSTANTS = { + INT8_MIN: -128, + INT8_MAX: 127, + INT8_UNSIGNED_MAX: 255, + INT16_MIN: -32768, + INT16_MAX: 32767, + INT16_UNSIGNED_MAX: 65535, + INT24_MIN: -8388608, + INT24_MAX: 8388607, + INT24_UNSIGNED_MAX: 16777215, + INT32_MIN: -2147483648, + INT32_MAX: 2147483647, + INT32_UNSIGNED_MAX: 4294967295, + INT48_MIN: -140737488355328, + INT48_MAX: 140737488355327, + INT48_UNSIGNED_MAX: 281474976710655, + INT64_MIN: -9223372036854775808n, + INT64_MAX: 9223372036854775807n, + INT64_UNSIGNED_MAX: 18446744073709551615n, +}; diff --git a/drizzle-valibot/src/index.ts b/drizzle-valibot/src/index.ts index 0c84c5052..0a6499e5b 100644 --- a/drizzle-valibot/src/index.ts +++ b/drizzle-valibot/src/index.ts @@ -1,332 +1,2 @@ -import { - type AnyColumn, - type Assume, - type Column, - type DrizzleTypeError, - type Equal, - getTableColumns, - is, - type Simplify, - type Table, -} from 'drizzle-orm'; -import { MySqlChar, MySqlVarBinary, MySqlVarChar } from 'drizzle-orm/mysql-core'; -import { type PgArray, PgChar, PgUUID, PgVarchar } from 'drizzle-orm/pg-core'; -import { SQLiteText } from 'drizzle-orm/sqlite-core'; - -import { - any, - type AnySchema, - array, - type ArraySchema, - type BaseSchema, - bigint, - type BigintSchema, - boolean, - type BooleanSchema, - date, - type DateSchema, - maxLength, - null_, - nullable, - type NullableSchema, - number, - type NumberSchema, - object, - type ObjectSchema, - optional, - type OptionalSchema, - picklist, - type PicklistSchema, - record, - string, - type StringSchema, - union, - uuid, -} from 'valibot'; - -const literalSchema = union([string(), number(), boolean(), null_()]); - -type Json = typeof jsonSchema; - -export const jsonSchema = union([literalSchema, array(any()), record(any())]); - -type MapInsertColumnToValibot< - TColumn extends Column, - TType extends BaseSchema, -> = TColumn['_']['notNull'] extends false ? OptionalSchema> - : TColumn['_']['hasDefault'] extends true ? OptionalSchema - : TType; - -type MapSelectColumnToValibot< - TColumn extends Column, - TType extends BaseSchema, -> = TColumn['_']['notNull'] extends false ? NullableSchema : TType; - -type MapColumnToValibot< - TColumn extends Column, - TType extends BaseSchema, - TMode extends 'insert' | 'select', -> = TMode extends 'insert' ? MapInsertColumnToValibot - : MapSelectColumnToValibot; - -type MaybeOptional< - TColumn extends Column, - TType extends BaseSchema, - TMode extends 'insert' | 'select', - TNoOptional extends boolean, -> = TNoOptional extends true ? TType - : MapColumnToValibot; - -type GetValibotType = TColumn['_']['dataType'] extends infer TDataType - ? TDataType extends 'custom' ? AnySchema - : TDataType extends 'json' ? Json - : TColumn extends { enumValues: [string, ...string[]] } - ? Equal extends true ? StringSchema - : PicklistSchema - : TDataType extends 'array' - ? TColumn['_']['baseColumn'] extends Column ? ArraySchema> : never - : TDataType extends 'bigint' ? BigintSchema - : TDataType extends 'number' ? NumberSchema - : TDataType extends 'string' ? StringSchema - : TDataType extends 'boolean' ? BooleanSchema - : TDataType extends 'date' ? DateSchema - : AnySchema - : never; - -type ValueOrUpdater = T | ((arg: TUpdaterArg) => T); - -type UnwrapValueOrUpdater = T extends ValueOrUpdater ? U - : never; - -export type Refine = { - [K in keyof TTable['_']['columns']]?: ValueOrUpdater< - BaseSchema, - TMode extends 'select' ? BuildSelectSchema - : BuildInsertSchema - >; -}; - -export type BuildInsertSchema< - TTable extends Table, - TRefine extends Refine | {}, - TNoOptional extends boolean = false, -> = TTable['_']['columns'] extends infer TColumns extends Record< - string, - Column -> ? { - [K in keyof TColumns & string]: MaybeOptional< - TColumns[K], - K extends keyof TRefine ? Assume, BaseSchema> - : GetValibotType, - 'insert', - TNoOptional - >; - } - : never; - -export type BuildSelectSchema< - TTable extends Table, - TRefine extends Refine, - TNoOptional extends boolean = false, -> = Simplify< - { - [K in keyof TTable['_']['columns']]: MaybeOptional< - TTable['_']['columns'][K], - K extends keyof TRefine ? Assume, BaseSchema> - : GetValibotType, - 'select', - TNoOptional - >; - } ->; - -export function createInsertSchema< - TTable extends Table, - TRefine extends Refine = Refine, ->( - table: TTable, - /** - * @param refine Refine schema fields - */ - refine?: { - [K in keyof TRefine]: K extends keyof TTable['_']['columns'] ? TRefine[K] - : DrizzleTypeError< - `Column '${ - & K - & string}' does not exist in table '${TTable['_']['name']}'` - >; - }, - // -): ObjectSchema< - BuildInsertSchema< - TTable, - Equal> extends true ? {} : TRefine - > -> { - const columns = getTableColumns(table); - const columnEntries = Object.entries(columns); - - let schemaEntries = Object.fromEntries( - columnEntries.map(([name, column]) => { - return [name, mapColumnToSchema(column)]; - }), - ); - - if (refine) { - schemaEntries = Object.assign( - schemaEntries, - Object.fromEntries( - Object.entries(refine).map(([name, refineColumn]) => { - return [ - name, - typeof refineColumn === 'function' - ? refineColumn( - schemaEntries as BuildInsertSchema< - TTable, - {}, - true - >, - ) - : refineColumn, - ]; - }), - ), - ); - } - - for (const [name, column] of columnEntries) { - if (!column.notNull) { - schemaEntries[name] = optional(nullable(schemaEntries[name]!)); - } else if (column.hasDefault) { - schemaEntries[name] = optional(schemaEntries[name]!); - } - } - - return object(schemaEntries) as any; -} - -export function createSelectSchema< - TTable extends Table, - TRefine extends Refine = Refine, ->( - table: TTable, - /** - * @param refine Refine schema fields - */ - refine?: { - [K in keyof TRefine]: K extends keyof TTable['_']['columns'] ? TRefine[K] - : DrizzleTypeError< - `Column '${ - & K - & string}' does not exist in table '${TTable['_']['name']}'` - >; - }, -): ObjectSchema< - BuildSelectSchema< - TTable, - Equal> extends true ? {} : TRefine - > -> { - const columns = getTableColumns(table); - const columnEntries = Object.entries(columns); - - let schemaEntries = Object.fromEntries( - columnEntries.map(([name, column]) => { - return [name, mapColumnToSchema(column)]; - }), - ); - - if (refine) { - schemaEntries = Object.assign( - schemaEntries, - Object.fromEntries( - Object.entries(refine).map(([name, refineColumn]) => { - return [ - name, - typeof refineColumn === 'function' - ? refineColumn( - schemaEntries as BuildSelectSchema< - TTable, - {}, - true - >, - ) - : refineColumn, - ]; - }), - ), - ); - } - - for (const [name, column] of columnEntries) { - if (!column.notNull) { - schemaEntries[name] = nullable(schemaEntries[name]!); - } - } - - return object(schemaEntries) as any; -} - -function isWithEnum( - column: AnyColumn, -): column is typeof column & { enumValues: [string, ...string[]] } { - return ( - 'enumValues' in column - && Array.isArray(column.enumValues) - && column.enumValues.length > 0 - ); -} - -function mapColumnToSchema(column: Column): BaseSchema { - let type: BaseSchema | undefined; - - if (isWithEnum(column)) { - type = column.enumValues?.length - ? picklist(column.enumValues) - : string(); - } - - if (!type) { - if (column.dataType === 'custom') { - type = any(); - } else if (column.dataType === 'json') { - type = jsonSchema; - } else if (column.dataType === 'array') { - type = array( - mapColumnToSchema((column as PgArray).baseColumn), - ); - } else if (column.dataType === 'number') { - type = number(); - } else if (column.dataType === 'bigint') { - type = bigint(); - } else if (column.dataType === 'boolean') { - type = boolean(); - } else if (column.dataType === 'date') { - type = date(); - } else if (column.dataType === 'string') { - let sType = string(); - - if ( - (is(column, PgChar) - || is(column, PgVarchar) - || is(column, MySqlVarChar) - || is(column, MySqlVarBinary) - || is(column, MySqlChar) - || is(column, SQLiteText)) - && typeof column.length === 'number' - ) { - sType = string([maxLength(column.length)]); - } - - type = sType; - } else if (is(column, PgUUID)) { - type = string([uuid()]); - } - } - - if (!type) { - type = any(); - } - - return type; -} +export * from './schema.ts'; +export * from './schema.types.ts'; diff --git a/drizzle-valibot/src/schema.ts b/drizzle-valibot/src/schema.ts new file mode 100644 index 000000000..30a6f77ec --- /dev/null +++ b/drizzle-valibot/src/schema.ts @@ -0,0 +1,95 @@ +import { Column, getTableColumns, getViewSelectedFields, is, isTable, isView, SQL } from 'drizzle-orm'; +import type { Table, View } from 'drizzle-orm'; +import type { PgEnum } from 'drizzle-orm/pg-core'; +import * as v from 'valibot'; +import { columnToSchema, mapEnumValues } from './column.ts'; +import type { Conditions } from './schema.types.internal.ts'; +import type { CreateInsertSchema, CreateSelectSchema, CreateUpdateSchema } from './schema.types.ts'; +import { isPgEnum } from './utils.ts'; + +function getColumns(tableLike: Table | View) { + return isTable(tableLike) ? getTableColumns(tableLike) : getViewSelectedFields(tableLike); +} + +function handleColumns( + columns: Record, + refinements: Record, + conditions: Conditions, +): v.GenericSchema { + const columnSchemas: Record = {}; + + for (const [key, selected] of Object.entries(columns)) { + if (!is(selected, Column) && !is(selected, SQL) && !is(selected, SQL.Aliased) && typeof selected === 'object') { + const columns = isTable(selected) || isView(selected) ? getColumns(selected) : selected; + columnSchemas[key] = handleColumns(columns, refinements[key] ?? {}, conditions); + continue; + } + + const refinement = refinements[key]; + if (refinement !== undefined && typeof refinement !== 'function') { + columnSchemas[key] = refinement; + continue; + } + + const column = is(selected, Column) ? selected : undefined; + const schema = column ? columnToSchema(column) : v.any(); + const refined = typeof refinement === 'function' ? refinement(schema) : schema; + + if (conditions.never(column)) { + continue; + } else { + columnSchemas[key] = refined; + } + + if (column) { + if (conditions.nullable(column)) { + columnSchemas[key] = v.nullable(columnSchemas[key]!); + } + + if (conditions.optional(column)) { + columnSchemas[key] = v.optional(columnSchemas[key]!); + } + } + } + + return v.object(columnSchemas) as any; +} + +export const createSelectSchema: CreateSelectSchema = ( + entity: Table | View | PgEnum<[string, ...string[]]>, + refine?: Record, +) => { + if (isPgEnum(entity)) { + return v.enum(mapEnumValues(entity.enumValues)); + } + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, { + never: () => false, + optional: () => false, + nullable: (column) => !column.notNull, + }) as any; +}; + +export const createInsertSchema: CreateInsertSchema = ( + entity: Table, + refine?: Record, +) => { + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, { + never: (column) => column?.generated?.type === 'always' || column?.generatedIdentity?.type === 'always', + optional: (column) => !column.notNull || (column.notNull && column.hasDefault), + nullable: (column) => !column.notNull, + }) as any; +}; + +export const createUpdateSchema: CreateUpdateSchema = ( + entity: Table, + refine?: Record, +) => { + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, { + never: (column) => column?.generated?.type === 'always' || column?.generatedIdentity?.type === 'always', + optional: () => true, + nullable: (column) => !column.notNull, + }) as any; +}; diff --git a/drizzle-valibot/src/schema.types.internal.ts b/drizzle-valibot/src/schema.types.internal.ts new file mode 100644 index 000000000..57dcedc7c --- /dev/null +++ b/drizzle-valibot/src/schema.types.internal.ts @@ -0,0 +1,105 @@ +import type { Assume, Column, DrizzleTypeError, SelectedFieldsFlat, Simplify, Table, View } from 'drizzle-orm'; +import type * as v from 'valibot'; +import type { + ExtractAdditionalProperties, + GetBaseColumn, + GetEnumValuesFromColumn, + GetValibotType, + HandleColumn, +} from './column.types.ts'; +import type { GetSelection, RemoveNever } from './utils.ts'; + +export interface Conditions { + never: (column?: Column) => boolean; + optional: (column: Column) => boolean; + nullable: (column: Column) => boolean; +} + +export type BuildRefineColumns< + TColumns extends Record, +> = Simplify< + RemoveNever< + { + [K in keyof TColumns]: TColumns[K] extends infer TColumn extends Column ? GetValibotType< + TColumn['_']['data'], + TColumn['_']['dataType'], + TColumn['_']['columnType'], + GetEnumValuesFromColumn, + GetBaseColumn, + ExtractAdditionalProperties + > extends infer TSchema extends v.GenericSchema ? TSchema + : v.AnySchema + : TColumns[K] extends infer TObject extends SelectedFieldsFlat | Table | View + ? BuildRefineColumns> + : TColumns[K]; + } + > +>; + +export type BuildRefine< + TColumns extends Record, +> = BuildRefineColumns extends infer TBuildColumns ? { + [K in keyof TBuildColumns]?: TBuildColumns[K] extends v.GenericSchema + ? ((schema: TBuildColumns[K]) => v.GenericSchema) | v.GenericSchema + : TBuildColumns[K] extends Record ? Simplify> + : never; + } + : never; + +type HandleRefinement< + TType extends 'select' | 'insert' | 'update', + TRefinement extends v.GenericSchema | ((schema: v.GenericSchema) => v.GenericSchema), + TColumn extends Column, +> = TRefinement extends (schema: any) => v.GenericSchema ? ( + TColumn['_']['notNull'] extends true ? ReturnType + : v.NullableSchema, undefined> + ) extends infer TSchema ? TType extends 'update' ? v.OptionalSchema, undefined> + : TSchema + : v.AnySchema + : TRefinement; + +type IsRefinementDefined = TKey extends keyof TRefinements + ? TRefinements[TKey] extends v.GenericSchema | ((schema: any) => any) ? true + : false + : false; + +export type BuildSchema< + TType extends 'select' | 'insert' | 'update', + TColumns extends Record, + TRefinements extends Record | undefined, +> // @ts-ignore false-positive + = v.ObjectSchema< + Simplify< + RemoveNever< + { + readonly [K in keyof TColumns]: TColumns[K] extends infer TColumn extends Column + ? TRefinements extends object + ? IsRefinementDefined> extends true + ? HandleRefinement], TColumn> + : HandleColumn + : HandleColumn + : TColumns[K] extends infer TObject extends SelectedFieldsFlat | Table | View ? BuildSchema< + TType, + GetSelection, + TRefinements extends object + ? TRefinements[Assume] extends infer TNestedRefinements extends object + ? TNestedRefinements + : undefined + : undefined + > + : v.AnySchema; + } + > + >, + undefined +>; + +export type NoUnknownKeys< + TRefinement extends Record, + TCompare extends Record, +> = { + [K in keyof TRefinement]: K extends keyof TCompare + ? TRefinement[K] extends Record ? NoUnknownKeys + : TRefinement[K] + : DrizzleTypeError<`Found unknown key in refinement: "${K & string}"`>; +}; diff --git a/drizzle-valibot/src/schema.types.ts b/drizzle-valibot/src/schema.types.ts new file mode 100644 index 000000000..c0b2ef82c --- /dev/null +++ b/drizzle-valibot/src/schema.types.ts @@ -0,0 +1,49 @@ +import type { Table, View } from 'drizzle-orm'; +import type { PgEnum } from 'drizzle-orm/pg-core'; +import type * as v from 'valibot'; +import type { EnumValuesToEnum } from './column.types.ts'; +import type { BuildRefine, BuildSchema, NoUnknownKeys } from './schema.types.internal.ts'; + +export interface CreateSelectSchema { + (table: TTable): BuildSchema<'select', TTable['_']['columns'], undefined>; + < + TTable extends Table, + TRefine extends BuildRefine, + >( + table: TTable, + refine?: NoUnknownKeys, + ): BuildSchema<'select', TTable['_']['columns'], TRefine>; + + (view: TView): BuildSchema<'select', TView['_']['selectedFields'], undefined>; + < + TView extends View, + TRefine extends BuildRefine, + >( + view: TView, + refine: NoUnknownKeys, + ): BuildSchema<'select', TView['_']['selectedFields'], TRefine>; + + >(enum_: TEnum): v.EnumSchema, undefined>; +} + +export interface CreateInsertSchema { + (table: TTable): BuildSchema<'insert', TTable['_']['columns'], undefined>; + < + TTable extends Table, + TRefine extends BuildRefine>, + >( + table: TTable, + refine?: NoUnknownKeys, + ): BuildSchema<'insert', TTable['_']['columns'], TRefine>; +} + +export interface CreateUpdateSchema { + (table: TTable): BuildSchema<'update', TTable['_']['columns'], undefined>; + < + TTable extends Table, + TRefine extends BuildRefine>, + >( + table: TTable, + refine?: TRefine, + ): BuildSchema<'update', TTable['_']['columns'], TRefine>; +} diff --git a/drizzle-valibot/src/utils.ts b/drizzle-valibot/src/utils.ts new file mode 100644 index 000000000..eb5034d6f --- /dev/null +++ b/drizzle-valibot/src/utils.ts @@ -0,0 +1,45 @@ +import type { Column, SelectedFieldsFlat, Table, View } from 'drizzle-orm'; +import type { PgEnum } from 'drizzle-orm/pg-core'; +import type * as v from 'valibot'; +import type { literalSchema } from './column.ts'; + +export function isColumnType(column: Column, columnTypes: string[]): column is T { + return columnTypes.includes(column.columnType); +} + +export function isWithEnum(column: Column): column is typeof column & { enumValues: [string, ...string[]] } { + return 'enumValues' in column && Array.isArray(column.enumValues) && column.enumValues.length > 0; +} + +export const isPgEnum: (entity: any) => entity is PgEnum<[string, ...string[]]> = isWithEnum as any; + +type Literal = v.InferOutput; +export type Json = Literal | { [key: string]: Json } | Json[]; + +export type IsNever = [T] extends [never] ? true : false; + +export type ArrayHasAtLeastOneValue = TEnum extends [infer TString, ...any[]] + ? TString extends `${infer TLiteral}` ? TLiteral extends any ? true + : false + : false + : false; + +export type ColumnIsGeneratedAlwaysAs = TColumn['_']['identity'] extends 'always' ? true + : TColumn['_']['generated'] extends undefined ? false + : TColumn['_']['generated'] extends infer TGenerated extends { type: string } + ? TGenerated['type'] extends 'byDefault' ? false + : true + : true; + +export type RemoveNever = { + [K in keyof T as T[K] extends never ? never : K]: T[K]; +}; + +export type RemoveNeverElements = T extends [infer First, ...infer Rest] + ? IsNever extends true ? RemoveNeverElements + : [First, ...RemoveNeverElements] + : []; + +export type GetSelection | Table | View> = T extends Table ? T['_']['columns'] + : T extends View ? T['_']['selectedFields'] + : T; diff --git a/drizzle-valibot/tests/mysql.test.ts b/drizzle-valibot/tests/mysql.test.ts index 9635ef8fa..5bf9520cb 100644 --- a/drizzle-valibot/tests/mysql.test.ts +++ b/drizzle-valibot/tests/mysql.test.ts @@ -1,400 +1,472 @@ -import { - bigint, - binary, - boolean, - char, - customType, - date, - datetime, - decimal, - double, - float, - int, - json, - longtext, - mediumint, - mediumtext, - mysqlEnum, - mysqlTable, - real, - serial, - smallint, - text, - time, - timestamp, - tinyint, - tinytext, - varbinary, - varchar, - year, -} from 'drizzle-orm/mysql-core'; -import { - any, - bigint as valibigint, - boolean as valiboolean, - date as valiDate, - maxLength, - minLength, - minValue, - number, - object, - optional, - parse, - picklist, - string, -} from 'valibot'; -import { expect, test } from 'vitest'; -import { createInsertSchema, createSelectSchema, jsonSchema } from '../src'; -import { expectSchemaShape } from './utils.ts'; - -const customInt = customType<{ data: number }>({ - dataType() { - return 'int'; - }, +import { type Equal, sql } from 'drizzle-orm'; +import { int, mysqlSchema, mysqlTable, mysqlView, serial, text } from 'drizzle-orm/mysql-core'; +import * as v from 'valibot'; +import { test } from 'vitest'; +import { jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectSchemaShape } from './utils.ts'; + +const intSchema = v.pipe( + v.number(), + v.minValue(CONSTANTS.INT32_MIN as number), + v.maxValue(CONSTANTS.INT32_MAX as number), + v.integer(), +); +const serialNumberModeSchema = v.pipe( + v.number(), + v.minValue(0 as number), + v.maxValue(Number.MAX_SAFE_INTEGER as number), + v.integer(), +); +const textSchema = v.pipe(v.string(), v.maxLength(CONSTANTS.INT16_UNSIGNED_MAX as number)); + +test('table - select', (t) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = v.object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -const testTable = mysqlTable('test', { - bigint: bigint('bigint', { mode: 'bigint' }).notNull(), - bigintNumber: bigint('bigintNumber', { mode: 'number' }).notNull(), - binary: binary('binary').notNull(), - boolean: boolean('boolean').notNull(), - char: char('char', { length: 4 }).notNull(), - charEnum: char('char', { enum: ['a', 'b', 'c'] }).notNull(), - customInt: customInt('customInt').notNull(), - date: date('date').notNull(), - dateString: date('dateString', { mode: 'string' }).notNull(), - datetime: datetime('datetime').notNull(), - datetimeString: datetime('datetimeString', { mode: 'string' }).notNull(), - decimal: decimal('decimal').notNull(), - double: double('double').notNull(), - enum: mysqlEnum('enum', ['a', 'b', 'c']).notNull(), - float: float('float').notNull(), - int: int('int').notNull(), - json: json('json').notNull(), - mediumint: mediumint('mediumint').notNull(), - real: real('real').notNull(), - serial: serial('serial').notNull(), - smallint: smallint('smallint').notNull(), - text: text('text').notNull(), - textEnum: text('textEnum', { enum: ['a', 'b', 'c'] }).notNull(), - tinytext: tinytext('tinytext').notNull(), - tinytextEnum: tinytext('tinytextEnum', { enum: ['a', 'b', 'c'] }).notNull(), - mediumtext: mediumtext('mediumtext').notNull(), - mediumtextEnum: mediumtext('mediumtextEnum', { - enum: ['a', 'b', 'c'], - }).notNull(), - longtext: longtext('longtext').notNull(), - longtextEnum: longtext('longtextEnum', { enum: ['a', 'b', 'c'] }).notNull(), - time: time('time').notNull(), - timestamp: timestamp('timestamp').notNull(), - timestampString: timestamp('timestampString', { mode: 'string' }).notNull(), - tinyint: tinyint('tinyint').notNull(), - varbinary: varbinary('varbinary', { length: 200 }).notNull(), - varchar: varchar('varchar', { length: 200 }).notNull(), - varcharEnum: varchar('varcharEnum', { - length: 1, - enum: ['a', 'b', 'c'], - }).notNull(), - year: year('year').notNull(), - autoIncrement: int('autoIncrement').notNull().autoincrement(), +test('table in schema - select', (tc) => { + const schema = mysqlSchema('test'); + const table = schema.table('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = v.object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -const testTableRow = { - bigint: BigInt(1), - bigintNumber: 1, - binary: 'binary', - boolean: true, - char: 'char', - charEnum: 'a' as const, - customInt: { data: 1 }, - date: new Date(), - dateString: new Date().toISOString(), - datetime: new Date(), - datetimeString: new Date().toISOString(), - decimal: '1.1', - double: 1.1, - enum: 'a' as const, - float: 1.1, - int: 1, - json: { data: 1 }, - mediumint: 1, - real: 1.1, - serial: 1, - smallint: 1, - text: 'text', - textEnum: 'a' as const, - tinytext: 'tinytext', - tinytextEnum: 'a' as const, - mediumtext: 'mediumtext', - mediumtextEnum: 'a' as const, - longtext: 'longtext', - longtextEnum: 'a' as const, - time: '00:00:00', - timestamp: new Date(), - timestampString: new Date().toISOString(), - tinyint: 1, - varbinary: 'A'.repeat(200), - varchar: 'A'.repeat(200), - varcharEnum: 'a' as const, - year: 2021, - autoIncrement: 1, -}; - -test('insert valid row', () => { - const schema = createInsertSchema(testTable); - - expect(parse(schema, testTableRow)).toStrictEqual(testTableRow); +test('table - insert', (t) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); + + const result = createInsertSchema(table); + const expected = v.object({ + id: v.optional(serialNumberModeSchema), + name: textSchema, + age: v.optional(v.nullable(intSchema)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('insert invalid varchar length', () => { - const schema = createInsertSchema(testTable); +test('table - update', (t) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); - expect(() => - parse(schema, { - ...testTableRow, - varchar: 'A'.repeat(201), - }) - ).toThrow(undefined); + const result = createUpdateSchema(table); + const expected = v.object({ + id: v.optional(serialNumberModeSchema), + name: v.optional(textSchema), + age: v.optional(v.nullable(intSchema)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('insert smaller char length should work', () => { - const schema = createInsertSchema(testTable); +test('view qb - select', (t) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = mysqlView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + + const result = createSelectSchema(view); + const expected = v.object({ id: serialNumberModeSchema, age: v.any() }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); - const input = { ...testTableRow, char: 'abc' }; +test('view columns - select', (t) => { + const view = mysqlView('test', { + id: serial().primaryKey(), + name: text().notNull(), + }).as(sql``); - expect(parse(schema, input)).toStrictEqual(input); + const result = createSelectSchema(view); + const expected = v.object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('insert larger char length should fail', () => { - const schema = createInsertSchema(testTable); +test('view with nested fields - select', (t) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = mysqlView('test').as((qb) => + qb.select({ + id: table.id, + nested: { + name: table.name, + age: sql``.as('age'), + }, + table, + }).from(table) + ); - expect(() => parse(schema, { ...testTableRow, char: 'abcde' })).toThrow(undefined); + const result = createSelectSchema(view); + const expected = v.object({ + id: serialNumberModeSchema, + nested: v.object({ name: textSchema, age: v.any() }), + table: v.object({ id: serialNumberModeSchema, name: textSchema }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('insert schema', (t) => { - const actual = createInsertSchema(testTable); - - const expected = object({ - bigint: valibigint(), - bigintNumber: number(), - binary: string(), - boolean: valiboolean(), - char: string([minLength(4), maxLength(4)]), - charEnum: picklist([ - 'a', - 'b', - 'c', - ]), - customInt: any(), - date: valiDate(), - dateString: string(), - datetime: valiDate(), - datetimeString: string(), - decimal: string(), - double: number(), - enum: picklist([ - 'a', - 'b', - 'c', - ]), - float: number(), - int: number(), - json: jsonSchema, - mediumint: number(), - real: number(), - serial: optional(number()), - smallint: number(), - text: string(), - textEnum: picklist([ - 'a', - 'b', - 'c', - ]), - tinytext: string(), - tinytextEnum: picklist([ - 'a', - 'b', - 'c', - ]), - mediumtext: string(), - mediumtextEnum: picklist([ - 'a', - 'b', - 'c', - ]), - longtext: string(), - longtextEnum: picklist([ - 'a', - 'b', - 'c', - ]), - time: string(), - timestamp: valiDate(), - timestampString: string(), - tinyint: number(), - varbinary: string([maxLength(200)]), - varchar: string([maxLength(200)]), - varcharEnum: picklist([ - 'a', - 'b', - 'c', - ]), - year: number(), - autoIncrement: optional(number()), +test('nullability - select', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), }); - expectSchemaShape(t, expected).from(actual); + const result = createSelectSchema(table); + const expected = v.object({ + c1: v.nullable(intSchema), + c2: intSchema, + c3: v.nullable(intSchema), + c4: intSchema, + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('select schema', (t) => { - const actual = createSelectSchema(testTable); - - const expected = object({ - bigint: valibigint(), - bigintNumber: number(), - binary: string(), - boolean: valiboolean(), - char: string([minLength(4), maxLength(4)]), - charEnum: picklist([ - 'a', - 'b', - 'c', - ]), - customInt: any(), - date: valiDate(), - dateString: string(), - datetime: valiDate(), - datetimeString: string(), - decimal: string(), - double: number(), - enum: picklist([ - 'a', - 'b', - 'c', - ]), - float: number(), - int: number(), - // - json: jsonSchema, - mediumint: number(), - real: number(), - serial: number(), - smallint: number(), - text: string(), - textEnum: picklist([ - 'a', - 'b', - 'c', - ]), - tinytext: string(), - tinytextEnum: picklist([ - 'a', - 'b', - 'c', - ]), - mediumtext: string(), - mediumtextEnum: picklist([ - 'a', - 'b', - 'c', - ]), - longtext: string(), - longtextEnum: picklist([ - 'a', - 'b', - 'c', - ]), - time: string(), - timestamp: valiDate(), - timestampString: string(), - tinyint: number(), - varbinary: string([maxLength(200)]), - varchar: string([maxLength(200)]), - varcharEnum: picklist([ - 'a', - 'b', - 'c', - ]), - year: number(), - autoIncrement: number(), +test('nullability - insert', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), }); - expectSchemaShape(t, expected).from(actual); + const result = createInsertSchema(table); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: intSchema, + c3: v.optional(v.nullable(intSchema)), + c4: v.optional(intSchema), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('select schema w/ refine', (t) => { - const actual = createSelectSchema(testTable, { - bigint: (_) => valibigint([minValue(0n)]), +test('nullability - update', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), }); - const expected = object({ - bigint: valibigint([minValue(0n)]), - bigintNumber: number(), - binary: string(), - boolean: valiboolean(), - char: string([minLength(5), maxLength(5)]), - charEnum: picklist([ - 'a', - 'b', - 'c', - ]), - customInt: any(), - date: valiDate(), - dateString: string(), - datetime: valiDate(), - datetimeString: string(), - decimal: string(), - double: number(), - enum: picklist([ - 'a', - 'b', - 'c', - ]), - float: number(), - int: number(), - json: jsonSchema, - mediumint: number(), - real: number(), - serial: number(), - smallint: number(), - text: string(), - textEnum: picklist([ - 'a', - 'b', - 'c', - ]), - tinytext: string(), - tinytextEnum: picklist([ - 'a', - 'b', - 'c', - ]), - mediumtext: string(), - mediumtextEnum: picklist([ - 'a', - 'b', - 'c', - ]), - longtext: string(), - longtextEnum: picklist([ - 'a', - 'b', - 'c', - ]), - time: string(), - timestamp: valiDate(), - timestampString: string(), - tinyint: number(), - varbinary: string([maxLength(200)]), - varchar: string([maxLength(200)]), - varcharEnum: picklist([ - 'a', - 'b', - 'c', - ]), - year: number(), - autoIncrement: number(), + const result = createUpdateSchema(table); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: v.optional(intSchema), + c3: v.optional(v.nullable(intSchema)), + c4: v.optional(intSchema), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - select', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + }); + + const result = createSelectSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.nullable(intSchema), + c2: v.pipe(intSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - insert', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: v.pipe(intSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); - expectSchemaShape(t, expected).from(actual); +test('refine table - update', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: v.optional(v.pipe(intSchema, v.maxValue(1000))), + c3: v.pipe(v.string(), v.transform(Number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); + +test('refine view - select', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int(), + c3: int(), + c4: int(), + c5: int(), + c6: int(), + }); + const view = mysqlView('test').as((qb) => + qb.select({ + c1: table.c1, + c2: table.c2, + c3: table.c3, + nested: { + c4: table.c4, + c5: table.c5, + c6: table.c6, + }, + table, + }).from(table) + ); + + const result = createSelectSchema(view, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + nested: { + c5: (schema) => v.pipe(schema, v.maxValue(1000)), + c6: v.pipe(v.string(), v.transform(Number)), + }, + table: { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }, + }); + const expected = v.object({ + c1: v.nullable(intSchema), + c2: v.nullable(v.pipe(intSchema, v.maxValue(1000))), + c3: v.pipe(v.string(), v.transform(Number)), + nested: v.object({ + c4: v.nullable(intSchema), + c5: v.nullable(v.pipe(intSchema, v.maxValue(1000))), + c6: v.pipe(v.string(), v.transform(Number)), + }), + table: v.object({ + c1: v.nullable(intSchema), + c2: v.nullable(v.pipe(intSchema, v.maxValue(1000))), + c3: v.pipe(v.string(), v.transform(Number)), + c4: v.nullable(intSchema), + c5: v.nullable(intSchema), + c6: v.nullable(intSchema), + }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('all data types', (t) => { + const table = mysqlTable('test', ({ + bigint, + binary, + boolean, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + mysqlEnum, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varchar, + varbinary, + year, + longtext, + mediumtext, + tinytext, + }) => ({ + bigint1: bigint({ mode: 'number' }).notNull(), + bigint2: bigint({ mode: 'bigint' }).notNull(), + bigint3: bigint({ unsigned: true, mode: 'number' }).notNull(), + bigint4: bigint({ unsigned: true, mode: 'bigint' }).notNull(), + binary: binary({ length: 10 }).notNull(), + boolean: boolean().notNull(), + char1: char({ length: 10 }).notNull(), + char2: char({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + date1: date({ mode: 'date' }).notNull(), + date2: date({ mode: 'string' }).notNull(), + datetime1: datetime({ mode: 'date' }).notNull(), + datetime2: datetime({ mode: 'string' }).notNull(), + decimal1: decimal().notNull(), + decimal2: decimal({ unsigned: true }).notNull(), + double1: double().notNull(), + double2: double({ unsigned: true }).notNull(), + float1: float().notNull(), + float2: float({ unsigned: true }).notNull(), + int1: int().notNull(), + int2: int({ unsigned: true }).notNull(), + json: json().notNull(), + mediumint1: mediumint().notNull(), + mediumint2: mediumint({ unsigned: true }).notNull(), + enum: mysqlEnum('enum', ['a', 'b', 'c']).notNull(), + real: real().notNull(), + serial: serial().notNull(), + smallint1: smallint().notNull(), + smallint2: smallint({ unsigned: true }).notNull(), + text1: text().notNull(), + text2: text({ enum: ['a', 'b', 'c'] }).notNull(), + time: time().notNull(), + timestamp1: timestamp({ mode: 'date' }).notNull(), + timestamp2: timestamp({ mode: 'string' }).notNull(), + tinyint1: tinyint().notNull(), + tinyint2: tinyint({ unsigned: true }).notNull(), + varchar1: varchar({ length: 10 }).notNull(), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + varbinary: varbinary({ length: 10 }).notNull(), + year: year().notNull(), + longtext1: longtext().notNull(), + longtext2: longtext({ enum: ['a', 'b', 'c'] }).notNull(), + mediumtext1: mediumtext().notNull(), + mediumtext2: mediumtext({ enum: ['a', 'b', 'c'] }).notNull(), + tinytext1: tinytext().notNull(), + tinytext2: tinytext({ enum: ['a', 'b', 'c'] }).notNull(), + })); + + const result = createSelectSchema(table); + const expected = v.object({ + bigint1: v.pipe(v.number(), v.minValue(Number.MIN_SAFE_INTEGER), v.maxValue(Number.MAX_SAFE_INTEGER), v.integer()), + bigint2: v.pipe(v.bigint(), v.minValue(CONSTANTS.INT64_MIN), v.maxValue(CONSTANTS.INT64_MAX)), + bigint3: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(Number.MAX_SAFE_INTEGER), v.integer()), + bigint4: v.pipe(v.bigint(), v.minValue(0n as bigint), v.maxValue(CONSTANTS.INT64_UNSIGNED_MAX)), + binary: v.string(), + boolean: v.boolean(), + char1: v.pipe(v.string(), v.length(10 as number)), + char2: v.enum({ a: 'a', b: 'b', c: 'c' }), + date1: v.date(), + date2: v.string(), + datetime1: v.date(), + datetime2: v.string(), + decimal1: v.string(), + decimal2: v.string(), + double1: v.pipe(v.number(), v.minValue(CONSTANTS.INT48_MIN), v.maxValue(CONSTANTS.INT48_MAX)), + double2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT48_UNSIGNED_MAX)), + float1: v.pipe(v.number(), v.minValue(CONSTANTS.INT24_MIN), v.maxValue(CONSTANTS.INT24_MAX)), + float2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT24_UNSIGNED_MAX)), + int1: v.pipe(v.number(), v.minValue(CONSTANTS.INT32_MIN), v.maxValue(CONSTANTS.INT32_MAX), v.integer()), + int2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT32_UNSIGNED_MAX), v.integer()), + json: jsonSchema, + mediumint1: v.pipe(v.number(), v.minValue(CONSTANTS.INT24_MIN), v.maxValue(CONSTANTS.INT24_MAX), v.integer()), + mediumint2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT24_UNSIGNED_MAX), v.integer()), + enum: v.enum({ a: 'a', b: 'b', c: 'c' }), + real: v.pipe(v.number(), v.minValue(CONSTANTS.INT48_MIN), v.maxValue(CONSTANTS.INT48_MAX)), + serial: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(Number.MAX_SAFE_INTEGER), v.integer()), + smallint1: v.pipe(v.number(), v.minValue(CONSTANTS.INT16_MIN), v.maxValue(CONSTANTS.INT16_MAX), v.integer()), + smallint2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT16_UNSIGNED_MAX), v.integer()), + text1: v.pipe(v.string(), v.maxLength(CONSTANTS.INT16_UNSIGNED_MAX)), + text2: v.enum({ a: 'a', b: 'b', c: 'c' }), + time: v.string(), + timestamp1: v.date(), + timestamp2: v.string(), + tinyint1: v.pipe(v.number(), v.minValue(CONSTANTS.INT8_MIN), v.maxValue(CONSTANTS.INT8_MAX), v.integer()), + tinyint2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT8_UNSIGNED_MAX), v.integer()), + varchar1: v.pipe(v.string(), v.maxLength(10 as number)), + varchar2: v.enum({ a: 'a', b: 'b', c: 'c' }), + varbinary: v.string(), + year: v.pipe(v.number(), v.minValue(1901 as number), v.maxValue(2155 as number), v.integer()), + longtext1: v.pipe(v.string(), v.maxLength(CONSTANTS.INT32_UNSIGNED_MAX)), + longtext2: v.enum({ a: 'a', b: 'b', c: 'c' }), + mediumtext1: v.pipe(v.string(), v.maxLength(CONSTANTS.INT24_UNSIGNED_MAX)), + mediumtext2: v.enum({ a: 'a', b: 'b', c: 'c' }), + tinytext1: v.pipe(v.string(), v.maxLength(CONSTANTS.INT8_UNSIGNED_MAX)), + tinytext2: v.enum({ a: 'a', b: 'b', c: 'c' }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +/* Disallow unknown keys in table refinement - select */ { + const table = mysqlTable('test', { id: int() }); + // @ts-expect-error + createSelectSchema(table, { unknown: v.string() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = mysqlTable('test', { id: int() }); + // @ts-expect-error + createInsertSchema(table, { unknown: v.string() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = mysqlTable('test', { id: int() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: v.string() }); +} + +/* Disallow unknown keys in view qb - select */ { + const table = mysqlTable('test', { id: int() }); + const view = mysqlView('test').as((qb) => qb.select().from(table)); + const nestedSelect = mysqlView('test').as((qb) => qb.select({ table }).from(table)); + // @ts-expect-error + createSelectSchema(view, { unknown: v.string() }); + // @ts-expect-error + createSelectSchema(nestedSelect, { table: { unknown: v.string() } }); +} + +/* Disallow unknown keys in view columns - select */ { + const view = mysqlView('test', { id: int() }).as(sql``); + // @ts-expect-error + createSelectSchema(view, { unknown: v.string() }); +} diff --git a/drizzle-valibot/tests/pg.test.ts b/drizzle-valibot/tests/pg.test.ts index 659845fa1..4d1651a7c 100644 --- a/drizzle-valibot/tests/pg.test.ts +++ b/drizzle-valibot/tests/pg.test.ts @@ -1,184 +1,510 @@ -import { char, date, integer, pgEnum, pgTable, serial, text, timestamp, varchar } from 'drizzle-orm/pg-core'; -import { - array, - date as valiDate, - email, - maxLength, - minLength, - minValue, - nullable, - number, - object, - optional, - parse, - picklist, - string, -} from 'valibot'; -import { expect, test } from 'vitest'; -import { createInsertSchema, createSelectSchema } from '../src'; -import { expectSchemaShape } from './utils.ts'; - -export const roleEnum = pgEnum('role', ['admin', 'user']); - -const users = pgTable('users', { - a: integer('a').array(), - id: serial('id').primaryKey(), - name: text('name'), - email: text('email').notNull(), - birthdayString: date('birthday_string').notNull(), - birthdayDate: date('birthday_date', { mode: 'date' }).notNull(), - createdAt: timestamp('created_at').notNull().defaultNow(), - role: roleEnum('role').notNull(), - roleText: text('role1', { enum: ['admin', 'user'] }).notNull(), - roleText2: text('role2', { enum: ['admin', 'user'] }) - .notNull() - .default('user'), - profession: varchar('profession', { length: 20 }).notNull(), - initials: char('initials', { length: 2 }).notNull(), -}); - -const testUser = { - a: [1, 2, 3], - id: 1, - name: 'John Doe', - email: 'john.doe@example.com', - birthdayString: '1990-01-01', - birthdayDate: new Date('1990-01-01'), - createdAt: new Date(), - role: 'admin' as const, - roleText: 'admin' as const, - roleText2: 'admin' as const, - profession: 'Software Engineer', - initials: 'JD', -}; - -test('users insert valid user', () => { - const schema = createInsertSchema(users); - - expect(parse(schema, testUser)).toStrictEqual(testUser); -}); - -test('users insert invalid varchar', () => { - const schema = createInsertSchema(users); - - expect(() => - parse(schema, { - ...testUser, - profession: 'Chief Executive Officer', - }) - ).toThrow(undefined); -}); - -test('users insert invalid char', () => { - const schema = createInsertSchema(users); - - expect(() => parse(schema, { ...testUser, initials: 'JoDo' })).toThrow(undefined); -}); - -test('users insert schema', (t) => { - const actual = createInsertSchema(users, { - id: () => number([minValue(0)]), - email: () => string([email()]), - roleText: picklist(['user', 'manager', 'admin']), - }); - - (() => { - { - createInsertSchema(users, { - // @ts-expect-error (missing property) - foobar: number(), - }); - } - - { - createInsertSchema(users, { - // @ts-expect-error (invalid type) - id: 123, - }); - } - }); - - const expected = object({ - a: optional(nullable(array(number()))), - id: optional(number([minValue(0)])), - name: optional(nullable(string())), - email: string(), - birthdayString: string(), - birthdayDate: valiDate(), - createdAt: optional(valiDate()), - role: picklist(['admin', 'user']), - roleText: picklist(['user', 'manager', 'admin']), - roleText2: optional(picklist(['admin', 'user'])), - profession: string([maxLength(20), minLength(1)]), - initials: string([maxLength(2), minLength(1)]), - }); - - expectSchemaShape(t, expected).from(actual); -}); - -test('users insert schema w/ defaults', (t) => { - const actual = createInsertSchema(users); - - const expected = object({ - a: optional(nullable(array(number()))), - id: optional(number()), - name: optional(nullable(string())), - email: string(), - birthdayString: string(), - birthdayDate: valiDate(), - createdAt: optional(valiDate()), - role: picklist(['admin', 'user']), - roleText: picklist(['admin', 'user']), - roleText2: optional(picklist(['admin', 'user'])), - profession: string([maxLength(20), minLength(1)]), - initials: string([maxLength(2), minLength(1)]), - }); - - expectSchemaShape(t, expected).from(actual); +import { type Equal, sql } from 'drizzle-orm'; +import { integer, pgEnum, pgMaterializedView, pgSchema, pgTable, pgView, serial, text } from 'drizzle-orm/pg-core'; +import * as v from 'valibot'; +import { test } from 'vitest'; +import { jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectEnumValues, expectSchemaShape } from './utils.ts'; + +const integerSchema = v.pipe(v.number(), v.minValue(CONSTANTS.INT32_MIN), v.maxValue(CONSTANTS.INT32_MAX), v.integer()); +const textSchema = v.string(); + +test('table - select', (t) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = v.object({ id: integerSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('table in schema - select', (tc) => { + const schema = pgSchema('test'); + const table = schema.table('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = v.object({ id: integerSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('table - insert', (t) => { + const table = pgTable('test', { + id: integer().generatedAlwaysAsIdentity().primaryKey(), + name: text().notNull(), + age: integer(), + }); + + const result = createInsertSchema(table); + const expected = v.object({ name: textSchema, age: v.optional(v.nullable(integerSchema)) }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('table - update', (t) => { + const table = pgTable('test', { + id: integer().generatedAlwaysAsIdentity().primaryKey(), + name: text().notNull(), + age: integer(), + }); + + const result = createUpdateSchema(table); + const expected = v.object({ + name: v.optional(textSchema), + age: v.optional(v.nullable(integerSchema)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('view qb - select', (t) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = pgView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + + const result = createSelectSchema(view); + const expected = v.object({ id: integerSchema, age: v.any() }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('view columns - select', (t) => { + const view = pgView('test', { + id: serial().primaryKey(), + name: text().notNull(), + }).as(sql``); + + const result = createSelectSchema(view); + const expected = v.object({ id: integerSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('materialized view qb - select', (t) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = pgMaterializedView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + + const result = createSelectSchema(view); + const expected = v.object({ id: integerSchema, age: v.any() }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('materialized view columns - select', (t) => { + const view = pgView('test', { + id: serial().primaryKey(), + name: text().notNull(), + }).as(sql``); + + const result = createSelectSchema(view); + const expected = v.object({ id: integerSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('view with nested fields - select', (t) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = pgMaterializedView('test').as((qb) => + qb.select({ + id: table.id, + nested: { + name: table.name, + age: sql``.as('age'), + }, + table, + }).from(table) + ); + + const result = createSelectSchema(view); + const expected = v.object({ + id: integerSchema, + nested: v.object({ name: textSchema, age: v.any() }), + table: v.object({ id: integerSchema, name: textSchema }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('enum - select', (t) => { + const enum_ = pgEnum('test', ['a', 'b', 'c']); + + const result = createSelectSchema(enum_); + const expected = v.enum({ a: 'a', b: 'b', c: 'c' }); + expectEnumValues(t, expected).from(result); + Expect>(); +}); + +test('nullability - select', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().default(1), + c4: integer().notNull().default(1), + }); + + const result = createSelectSchema(table); + const expected = v.object({ + c1: v.nullable(integerSchema), + c2: integerSchema, + c3: v.nullable(integerSchema), + c4: integerSchema, + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users select schema', (t) => { - const actual = createSelectSchema(users, { - id: () => number([minValue(0)]), - email: () => string(), - roleText: picklist(['user', 'manager', 'admin']), - }); - - const expected = object({ - a: nullable(array(number())), - id: number([minValue(0)]), - name: nullable(string()), - email: string(), - birthdayString: string(), - birthdayDate: valiDate(), - createdAt: valiDate(), - role: picklist(['admin', 'user']), - roleText: picklist(['user', 'manager', 'admin']), - roleText2: picklist(['admin', 'user']), - profession: string([maxLength(20), minLength(1)]), - initials: string([maxLength(2), minLength(1)]), +test('nullability - insert', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().default(1), + c4: integer().notNull().default(1), + c5: integer().generatedAlwaysAs(1), + c6: integer().generatedAlwaysAsIdentity(), + c7: integer().generatedByDefaultAsIdentity(), }); - - expectSchemaShape(t, expected).from(actual); + + const result = createInsertSchema(table); + const expected = v.object({ + c1: v.optional(v.nullable(integerSchema)), + c2: integerSchema, + c3: v.optional(v.nullable(integerSchema)), + c4: v.optional(integerSchema), + c7: v.optional(integerSchema), + }); + expectSchemaShape(t, expected).from(result); }); -test('users select schema w/ defaults', (t) => { - const actual = createSelectSchema(users); - - const expected = object({ - a: nullable(array(number())), - id: number(), - name: nullable(string()), - email: string(), - birthdayString: string(), - birthdayDate: valiDate(), - createdAt: valiDate(), - role: picklist(['admin', 'user']), - roleText: picklist(['admin', 'user']), - roleText2: picklist(['admin', 'user']), - profession: string([maxLength(20), minLength(1)]), - initials: string([maxLength(2), minLength(1)]), - }); - - expectSchemaShape(t, expected).from(actual); +test('nullability - update', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().default(1), + c4: integer().notNull().default(1), + c5: integer().generatedAlwaysAs(1), + c6: integer().generatedAlwaysAsIdentity(), + c7: integer().generatedByDefaultAsIdentity(), + }); + + const result = createUpdateSchema(table); + const expected = v.object({ + c1: v.optional(v.nullable(integerSchema)), + c2: v.optional(integerSchema), + c3: v.optional(v.nullable(integerSchema)), + c4: v.optional(integerSchema), + c7: v.optional(integerSchema), + }); + table.c5.generated?.type; + expectSchemaShape(t, expected).from(result); + Expect>(); }); + +test('refine table - select', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + }); + + const result = createSelectSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.nullable(integerSchema), + c2: v.pipe(integerSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - insert', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + c4: integer().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.optional(v.nullable(integerSchema)), + c2: v.pipe(integerSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - update', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + c4: integer().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.optional(v.nullable(integerSchema)), + c2: v.optional(v.pipe(integerSchema, v.maxValue(1000))), + c3: v.pipe(v.string(), v.transform(Number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine view - select', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer(), + c3: integer(), + c4: integer(), + c5: integer(), + c6: integer(), + }); + const view = pgView('test').as((qb) => + qb.select({ + c1: table.c1, + c2: table.c2, + c3: table.c3, + nested: { + c4: table.c4, + c5: table.c5, + c6: table.c6, + }, + table, + }).from(table) + ); + + const result = createSelectSchema(view, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + nested: { + c5: (schema) => v.pipe(schema, v.maxValue(1000)), + c6: v.pipe(v.string(), v.transform(Number)), + }, + table: { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }, + }); + const expected = v.object({ + c1: v.nullable(integerSchema), + c2: v.nullable(v.pipe(integerSchema, v.maxValue(1000))), + c3: v.pipe(v.string(), v.transform(Number)), + nested: v.object({ + c4: v.nullable(integerSchema), + c5: v.nullable(v.pipe(integerSchema, v.maxValue(1000))), + c6: v.pipe(v.string(), v.transform(Number)), + }), + table: v.object({ + c1: v.nullable(integerSchema), + c2: v.nullable(v.pipe(integerSchema, v.maxValue(1000))), + c3: v.pipe(v.string(), v.transform(Number)), + c4: v.nullable(integerSchema), + c5: v.nullable(integerSchema), + c6: v.nullable(integerSchema), + }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('all data types', (t) => { + const table = pgTable('test', ({ + bigint, + bigserial, + bit, + boolean, + date, + char, + cidr, + doublePrecision, + geometry, + halfvec, + inet, + integer, + interval, + json, + jsonb, + line, + macaddr, + macaddr8, + numeric, + point, + real, + serial, + smallint, + smallserial, + text, + sparsevec, + time, + timestamp, + uuid, + varchar, + vector, + }) => ({ + bigint1: bigint({ mode: 'number' }).notNull(), + bigint2: bigint({ mode: 'bigint' }).notNull(), + bigserial1: bigserial({ mode: 'number' }).notNull(), + bigserial2: bigserial({ mode: 'bigint' }).notNull(), + bit: bit({ dimensions: 5 }).notNull(), + boolean: boolean().notNull(), + date1: date({ mode: 'date' }).notNull(), + date2: date({ mode: 'string' }).notNull(), + char1: char({ length: 10 }).notNull(), + char2: char({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + cidr: cidr().notNull(), + doublePrecision: doublePrecision().notNull(), + geometry1: geometry({ type: 'point', mode: 'tuple' }).notNull(), + geometry2: geometry({ type: 'point', mode: 'xy' }).notNull(), + halfvec: halfvec({ dimensions: 3 }).notNull(), + inet: inet().notNull(), + integer: integer().notNull(), + interval: interval().notNull(), + json: json().notNull(), + jsonb: jsonb().notNull(), + line1: line({ mode: 'abc' }).notNull(), + line2: line({ mode: 'tuple' }).notNull(), + macaddr: macaddr().notNull(), + macaddr8: macaddr8().notNull(), + numeric: numeric().notNull(), + point1: point({ mode: 'xy' }).notNull(), + point2: point({ mode: 'tuple' }).notNull(), + real: real().notNull(), + serial: serial().notNull(), + smallint: smallint().notNull(), + smallserial: smallserial().notNull(), + text1: text().notNull(), + text2: text({ enum: ['a', 'b', 'c'] }).notNull(), + sparsevec: sparsevec({ dimensions: 3 }).notNull(), + time: time().notNull(), + timestamp1: timestamp({ mode: 'date' }).notNull(), + timestamp2: timestamp({ mode: 'string' }).notNull(), + uuid: uuid().notNull(), + varchar1: varchar({ length: 10 }).notNull(), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + vector: vector({ dimensions: 3 }).notNull(), + array1: integer().array().notNull(), + array2: integer().array().array(2).notNull(), + array3: varchar({ length: 10 }).array().array(2).notNull(), + })); + + const result = createSelectSchema(table); + const expected = v.object({ + bigint1: v.pipe(v.number(), v.minValue(Number.MIN_SAFE_INTEGER), v.maxValue(Number.MAX_SAFE_INTEGER), v.integer()), + bigint2: v.pipe(v.bigint(), v.minValue(CONSTANTS.INT64_MIN), v.maxValue(CONSTANTS.INT64_MAX)), + bigserial1: v.pipe( + v.number(), + v.minValue(Number.MIN_SAFE_INTEGER), + v.maxValue(Number.MAX_SAFE_INTEGER), + v.integer(), + ), + bigserial2: v.pipe(v.bigint(), v.minValue(CONSTANTS.INT64_MIN), v.maxValue(CONSTANTS.INT64_MAX)), + bit: v.pipe(v.string(), v.regex(/^[01]+$/), v.maxLength(5 as number)), + boolean: v.boolean(), + date1: v.date(), + date2: v.string(), + char1: v.pipe(v.string(), v.length(10 as number)), + char2: v.enum({ a: 'a', b: 'b', c: 'c' }), + cidr: v.string(), + doublePrecision: v.pipe(v.number(), v.minValue(CONSTANTS.INT48_MIN), v.maxValue(CONSTANTS.INT48_MAX)), + geometry1: v.tuple([v.number(), v.number()]), + geometry2: v.object({ x: v.number(), y: v.number() }), + halfvec: v.pipe(v.array(v.number()), v.length(3 as number)), + inet: v.string(), + integer: v.pipe(v.number(), v.minValue(CONSTANTS.INT32_MIN), v.maxValue(CONSTANTS.INT32_MAX), v.integer()), + interval: v.string(), + json: jsonSchema, + jsonb: jsonSchema, + line1: v.object({ a: v.number(), b: v.number(), c: v.number() }), + line2: v.tuple([v.number(), v.number(), v.number()]), + macaddr: v.string(), + macaddr8: v.string(), + numeric: v.string(), + point1: v.object({ x: v.number(), y: v.number() }), + point2: v.tuple([v.number(), v.number()]), + real: v.pipe(v.number(), v.minValue(CONSTANTS.INT24_MIN), v.maxValue(CONSTANTS.INT24_MAX)), + serial: v.pipe(v.number(), v.minValue(CONSTANTS.INT32_MIN), v.maxValue(CONSTANTS.INT32_MAX), v.integer()), + smallint: v.pipe(v.number(), v.minValue(CONSTANTS.INT16_MIN), v.maxValue(CONSTANTS.INT16_MAX), v.integer()), + smallserial: v.pipe(v.number(), v.minValue(CONSTANTS.INT16_MIN), v.maxValue(CONSTANTS.INT16_MAX), v.integer()), + text1: v.string(), + text2: v.enum({ a: 'a', b: 'b', c: 'c' }), + sparsevec: v.string(), + time: v.string(), + timestamp1: v.date(), + timestamp2: v.string(), + uuid: v.pipe(v.string(), v.uuid()), + varchar1: v.pipe(v.string(), v.maxLength(10 as number)), + varchar2: v.enum({ a: 'a', b: 'b', c: 'c' }), + vector: v.pipe(v.array(v.number()), v.length(3 as number)), + array1: v.array(integerSchema), + array2: v.pipe(v.array(v.array(integerSchema)), v.length(2 as number)), + array3: v.pipe(v.array(v.array(v.pipe(v.string(), v.maxLength(10 as number)))), v.length(2 as number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +/* Disallow unknown keys in table refinement - select */ { + const table = pgTable('test', { id: integer() }); + // @ts-expect-error + createSelectSchema(table, { unknown: v.string() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = pgTable('test', { id: integer() }); + // @ts-expect-error + createInsertSchema(table, { unknown: v.string() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = pgTable('test', { id: integer() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: v.string() }); +} + +/* Disallow unknown keys in view qb - select */ { + const table = pgTable('test', { id: integer() }); + const view = pgView('test').as((qb) => qb.select().from(table)); + const mView = pgMaterializedView('test').as((qb) => qb.select().from(table)); + const nestedSelect = pgView('test').as((qb) => qb.select({ table }).from(table)); + // @ts-expect-error + createSelectSchema(view, { unknown: v.string() }); + // @ts-expect-error + createSelectSchema(mView, { unknown: v.string() }); + // @ts-expect-error + createSelectSchema(nestedSelect, { table: { unknown: v.string() } }); +} + +/* Disallow unknown keys in view columns - select */ { + const view = pgView('test', { id: integer() }).as(sql``); + const mView = pgView('test', { id: integer() }).as(sql``); + // @ts-expect-error + createSelectSchema(view, { unknown: v.string() }); + // @ts-expect-error + createSelectSchema(mView, { unknown: v.string() }); +} diff --git a/drizzle-valibot/tests/sqlite.test.ts b/drizzle-valibot/tests/sqlite.test.ts index a520108f0..7eb5fc7bf 100644 --- a/drizzle-valibot/tests/sqlite.test.ts +++ b/drizzle-valibot/tests/sqlite.test.ts @@ -1,178 +1,364 @@ -import { blob, integer, numeric, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { - bigint as valibigint, - boolean, - date as valiDate, - minValue, - nullable, - number, - object, - optional, - type Output, - parse, - picklist, - string, -} from 'valibot'; -import { expect, test } from 'vitest'; -import { createInsertSchema, createSelectSchema, jsonSchema } from '../src'; -import { expectSchemaShape } from './utils.ts'; - -const blobJsonSchema = object({ - foo: string(), +import { type Equal, sql } from 'drizzle-orm'; +import { int, sqliteTable, sqliteView, text } from 'drizzle-orm/sqlite-core'; +import * as v from 'valibot'; +import { test } from 'vitest'; +import { bufferSchema, jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectSchemaShape } from './utils.ts'; + +const intSchema = v.pipe( + v.number(), + v.minValue(Number.MIN_SAFE_INTEGER), + v.maxValue(Number.MAX_SAFE_INTEGER), + v.integer(), +); +const textSchema = v.string(); + +test('table - select', (t) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = v.object({ id: intSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -const users = sqliteTable('users', { - id: integer('id').primaryKey(), - blobJson: blob('blob', { mode: 'json' }) - .$type>() - .notNull(), - blobBigInt: blob('blob', { mode: 'bigint' }).notNull(), - numeric: numeric('numeric').notNull(), - createdAt: integer('created_at', { mode: 'timestamp' }).notNull(), - createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }).notNull(), - boolean: integer('boolean', { mode: 'boolean' }).notNull(), - real: real('real').notNull(), - text: text('text', { length: 255 }), - role: text('role', { enum: ['admin', 'user'] }) - .notNull() - .default('user'), +test('table - insert', (t) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + age: int(), + }); + + const result = createInsertSchema(table); + const expected = v.object({ id: v.optional(intSchema), name: textSchema, age: v.optional(v.nullable(intSchema)) }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -const testUser = { - id: 1, - blobJson: { foo: 'bar' }, - blobBigInt: BigInt(123), - numeric: '123.45', - createdAt: new Date(), - createdAtMs: new Date(), - boolean: true, - real: 123.45, - text: 'foobar', - role: 'admin' as const, -}; - -test('users insert valid user', () => { - const schema = createInsertSchema(users); - // - expect(parse(schema, testUser)).toStrictEqual(testUser); +test('table - update', (t) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + age: int(), + }); + + const result = createUpdateSchema(table); + const expected = v.object({ + id: v.optional(intSchema), + name: v.optional(textSchema), + age: v.optional(v.nullable(intSchema)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users insert invalid text length', () => { - const schema = createInsertSchema(users); - expect(() => parse(schema, { ...testUser, text: 'a'.repeat(256) })).toThrow(undefined); +test('view qb - select', (t) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + }); + const view = sqliteView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + + const result = createSelectSchema(view); + const expected = v.object({ id: intSchema, age: v.any() }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users insert schema', (t) => { - const actual = createInsertSchema(users, { - id: () => number([minValue(0)]), - blobJson: blobJsonSchema, - role: picklist(['admin', 'user', 'manager']), - }); - - (() => { - { - createInsertSchema(users, { - // @ts-expect-error (missing property) - foobar: number(), - }); - } - - { - createInsertSchema(users, { - // @ts-expect-error (invalid type) - id: 123, - }); - } - }); - - const expected = object({ - id: optional(number([minValue(0)])), - blobJson: blobJsonSchema, - blobBigInt: valibigint(), - numeric: string(), - createdAt: valiDate(), - createdAtMs: valiDate(), - boolean: boolean(), - real: number(), - text: optional(nullable(string())), - role: optional(picklist(['admin', 'user', 'manager'])), - }); - - expectSchemaShape(t, expected).from(actual); +test('view columns - select', (t) => { + const view = sqliteView('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + }).as(sql``); + + const result = createSelectSchema(view); + const expected = v.object({ id: intSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users insert schema w/ defaults', (t) => { - const actual = createInsertSchema(users); +test('view with nested fields - select', (t) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + }); + const view = sqliteView('test').as((qb) => + qb.select({ + id: table.id, + nested: { + name: table.name, + age: sql``.as('age'), + }, + table, + }).from(table) + ); - const expected = object({ - id: optional(number()), - blobJson: jsonSchema, - blobBigInt: valibigint(), - numeric: string(), - createdAt: valiDate(), - createdAtMs: valiDate(), - boolean: boolean(), - real: number(), - text: optional(nullable(string())), - role: optional(picklist(['admin', 'user'])), + const result = createSelectSchema(view); + const expected = v.object({ + id: intSchema, + nested: v.object({ name: textSchema, age: v.any() }), + table: v.object({ id: intSchema, name: textSchema }), }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); - expectSchemaShape(t, expected).from(actual); +test('nullability - select', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + }); + + const result = createSelectSchema(table); + const expected = v.object({ + c1: v.nullable(intSchema), + c2: intSchema, + c3: v.nullable(intSchema), + c4: intSchema, + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users select schema', (t) => { - const actual = createSelectSchema(users, { - blobJson: jsonSchema, - role: picklist(['admin', 'user', 'manager']), - }); - - (() => { - { - createSelectSchema(users, { - // @ts-expect-error (missing property) - foobar: number(), - }); - } - - { - createSelectSchema(users, { - // @ts-expect-error (invalid type) - id: 123, - }); - } - }); - - const expected = object({ - id: number(), - blobJson: jsonSchema, - blobBigInt: valibigint(), - numeric: string(), - createdAt: valiDate(), - createdAtMs: valiDate(), - boolean: boolean(), - real: number(), - text: nullable(string()), - role: picklist(['admin', 'user', 'manager']), - }); - - expectSchemaShape(t, expected).from(actual); +test('nullability - insert', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: intSchema, + c3: v.optional(v.nullable(intSchema)), + c4: v.optional(intSchema), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users select schema w/ defaults', (t) => { - const actual = createSelectSchema(users); +test('nullability - update', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); - const expected = object({ - id: number(), - blobJson: jsonSchema, - blobBigInt: valibigint(), - numeric: string(), - createdAt: valiDate(), - createdAtMs: valiDate(), - boolean: boolean(), - real: number(), - text: nullable(string()), - role: picklist(['admin', 'user']), + const result = createUpdateSchema(table); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: v.optional(intSchema), + c3: v.optional(v.nullable(intSchema)), + c4: v.optional(intSchema), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - select', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), }); - expectSchemaShape(t, expected).from(actual); + const result = createSelectSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.nullable(intSchema), + c2: v.pipe(intSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); + +test('refine table - insert', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: v.pipe(intSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - update', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: v.optional(v.pipe(intSchema, v.maxValue(1000))), + c3: v.pipe(v.string(), v.transform(Number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine view - select', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int(), + c3: int(), + c4: int(), + c5: int(), + c6: int(), + }); + const view = sqliteView('test').as((qb) => + qb.select({ + c1: table.c1, + c2: table.c2, + c3: table.c3, + nested: { + c4: table.c4, + c5: table.c5, + c6: table.c6, + }, + table, + }).from(table) + ); + + const result = createSelectSchema(view, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + nested: { + c5: (schema) => v.pipe(schema, v.maxValue(1000)), + c6: v.pipe(v.string(), v.transform(Number)), + }, + table: { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }, + }); + const expected = v.object({ + c1: v.nullable(intSchema), + c2: v.nullable(v.pipe(intSchema, v.maxValue(1000))), + c3: v.pipe(v.string(), v.transform(Number)), + nested: v.object({ + c4: v.nullable(intSchema), + c5: v.nullable(v.pipe(intSchema, v.maxValue(1000))), + c6: v.pipe(v.string(), v.transform(Number)), + }), + table: v.object({ + c1: v.nullable(intSchema), + c2: v.nullable(v.pipe(intSchema, v.maxValue(1000))), + c3: v.pipe(v.string(), v.transform(Number)), + c4: v.nullable(intSchema), + c5: v.nullable(intSchema), + c6: v.nullable(intSchema), + }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('all data types', (t) => { + const table = sqliteTable('test', ({ + blob, + integer, + numeric, + real, + text, + }) => ({ + blob1: blob({ mode: 'buffer' }).notNull(), + blob2: blob({ mode: 'bigint' }).notNull(), + blob3: blob({ mode: 'json' }).notNull(), + integer1: integer({ mode: 'number' }).notNull(), + integer2: integer({ mode: 'boolean' }).notNull(), + integer3: integer({ mode: 'timestamp' }).notNull(), + integer4: integer({ mode: 'timestamp_ms' }).notNull(), + numeric: numeric().notNull(), + real: real().notNull(), + text1: text({ mode: 'text' }).notNull(), + text2: text({ mode: 'text', length: 10 }).notNull(), + text3: text({ mode: 'text', enum: ['a', 'b', 'c'] }).notNull(), + text4: text({ mode: 'json' }).notNull(), + })); + + const result = createSelectSchema(table); + const expected = v.object({ + blob1: bufferSchema, + blob2: v.pipe(v.bigint(), v.minValue(CONSTANTS.INT64_MIN), v.maxValue(CONSTANTS.INT64_MAX)), + blob3: jsonSchema, + integer1: v.pipe(v.number(), v.minValue(Number.MIN_SAFE_INTEGER), v.maxValue(Number.MAX_SAFE_INTEGER), v.integer()), + integer2: v.boolean(), + integer3: v.date(), + integer4: v.date(), + numeric: v.string(), + real: v.pipe(v.number(), v.minValue(CONSTANTS.INT48_MIN), v.maxValue(CONSTANTS.INT48_MAX)), + text1: v.string(), + text2: v.pipe(v.string(), v.maxLength(10 as number)), + text3: v.enum({ a: 'a', b: 'b', c: 'c' }), + text4: jsonSchema, + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +/* Disallow unknown keys in table refinement - select */ { + const table = sqliteTable('test', { id: int() }); + // @ts-expect-error + createSelectSchema(table, { unknown: v.string() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = sqliteTable('test', { id: int() }); + // @ts-expect-error + createInsertSchema(table, { unknown: v.string() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = sqliteTable('test', { id: int() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: v.string() }); +} + +/* Disallow unknown keys in view qb - select */ { + const table = sqliteTable('test', { id: int() }); + const view = sqliteView('test').as((qb) => qb.select().from(table)); + const nestedSelect = sqliteView('test').as((qb) => qb.select({ table }).from(table)); + // @ts-expect-error + createSelectSchema(view, { unknown: v.string() }); + // @ts-expect-error + createSelectSchema(nestedSelect, { table: { unknown: v.string() } }); +} + +/* Disallow unknown keys in view columns - select */ { + const view = sqliteView('test', { id: int() }).as(sql``); + // @ts-expect-error + createSelectSchema(view, { unknown: v.string() }); +} diff --git a/drizzle-valibot/tests/utils.ts b/drizzle-valibot/tests/utils.ts index 189731956..7e1eae757 100644 --- a/drizzle-valibot/tests/utils.ts +++ b/drizzle-valibot/tests/utils.ts @@ -1,10 +1,43 @@ -import type { BaseSchema } from 'valibot'; +import type * as v from 'valibot'; import { expect, type TaskContext } from 'vitest'; -export function expectSchemaShape>(t: TaskContext, expected: T) { +function onlySpecifiedKeys(obj: Record, keys: string[]) { + return Object.fromEntries(Object.entries(obj).filter(([key]) => keys.includes(key))); +} + +export function expectSchemaShape>(t: TaskContext, expected: T) { + return { + from(actual: T) { + expect(Object.keys(actual.entries)).toStrictEqual(Object.keys(expected.entries)); + + for (const key of Object.keys(actual.entries)) { + const actualEntry = actual.entries[key] as any; + const expectedEntry = expected.entries[key] as any; + const keys = ['kind', 'type', 'expects', 'async', 'message']; + actualEntry.pipe ??= []; + expectedEntry.pipe ??= []; + + expect(onlySpecifiedKeys(actualEntry, keys)).toStrictEqual(onlySpecifiedKeys(expectedEntry, keys)); + expect(actualEntry.pipe.length).toStrictEqual(expectedEntry.pipe.length); + + for (let i = 0; i < actualEntry.pipe.length; i++) { + const actualPipeElement = actualEntry.pipe[i]; + const expectedPipeElement = expectedEntry.pipe[i]; + expect(onlySpecifiedKeys(actualPipeElement, keys)).toStrictEqual( + onlySpecifiedKeys(expectedPipeElement, keys), + ); + } + } + }, + }; +} + +export function expectEnumValues>(t: TaskContext, expected: T) { return { from(actual: T) { - expect(Object.keys(actual)).toStrictEqual(Object.keys(expected)); + expect(actual.enum).toStrictEqual(expected.enum); }, }; } + +export function Expect<_ extends true>() {} diff --git a/drizzle-valibot/tsconfig.json b/drizzle-valibot/tsconfig.json index 038d79591..c25379c37 100644 --- a/drizzle-valibot/tsconfig.json +++ b/drizzle-valibot/tsconfig.json @@ -4,6 +4,7 @@ "outDir": "dist", "baseUrl": ".", "declaration": true, + "noEmit": true, "paths": { "~/*": ["src/*"] } diff --git a/drizzle-zod/README.md b/drizzle-zod/README.md index a935d18cd..46eced034 100644 --- a/drizzle-zod/README.md +++ b/drizzle-zod/README.md @@ -10,11 +10,11 @@ `drizzle-zod` is a plugin for [Drizzle ORM](https://github.com/drizzle-team/drizzle-orm) that allows you to generate [Zod](https://zod.dev/) schemas from Drizzle ORM schemas. -| Database | Insert schema | Select schema | -|:-----------|:-------------:|:-------------:| -| PostgreSQL | ✅ | ✅ | -| MySQL | ✅ | ✅ | -| SQLite | ✅ | ✅ | +**Features** + +- Create a select schema for tables, views and enums. +- Create insert and update schemas for tables. +- Supports all dialects: PostgreSQL, MySQL and SQLite. # Usage @@ -34,6 +34,9 @@ const users = pgTable('users', { // Schema for inserting a user - can be used to validate API requests const insertUserSchema = createInsertSchema(users); +// Schema for updating a user - can be used to validate API requests +const updateUserSchema = createUpdateSchema(users); + // Schema for selecting a user - can be used to validate API responses const selectUserSchema = createSelectSchema(users); @@ -44,8 +47,8 @@ const insertUserSchema = createInsertSchema(users, { // Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema const insertUserSchema = createInsertSchema(users, { - id: (schema) => schema.id.positive(), - email: (schema) => schema.email.email(), + id: (schema) => schema.positive(), + email: (schema) => schema.email(), role: z.string(), }); diff --git a/drizzle-zod/package.json b/drizzle-zod/package.json index 4d3acef81..d4ed4407c 100644 --- a/drizzle-zod/package.json +++ b/drizzle-zod/package.json @@ -64,11 +64,10 @@ "author": "Drizzle Team", "license": "Apache-2.0", "peerDependencies": { - "drizzle-orm": ">=0.23.13", - "zod": "*" + "drizzle-orm": ">=0.36.0", + "zod": ">=3.0.0" }, "devDependencies": { - "@rollup/plugin-terser": "^0.4.1", "@rollup/plugin-typescript": "^11.1.0", "@types/node": "^18.15.10", "cpy": "^10.1.0", diff --git a/drizzle-zod/rollup.config.ts b/drizzle-zod/rollup.config.ts index 2ed2d33d3..2049cc5ad 100644 --- a/drizzle-zod/rollup.config.ts +++ b/drizzle-zod/rollup.config.ts @@ -1,4 +1,3 @@ -import terser from '@rollup/plugin-terser'; import typescript from '@rollup/plugin-typescript'; import { defineConfig } from 'rollup'; @@ -29,7 +28,6 @@ export default defineConfig([ typescript({ tsconfig: 'tsconfig.build.json', }), - terser(), ], }, ]); diff --git a/drizzle-zod/scripts/build.ts b/drizzle-zod/scripts/build.ts index 1910feac6..07330ffd0 100755 --- a/drizzle-zod/scripts/build.ts +++ b/drizzle-zod/scripts/build.ts @@ -13,3 +13,4 @@ await cpy('dist/**/*.d.ts', 'dist', { rename: (basename) => basename.replace(/\.d\.ts$/, '.d.cts'), }); await fs.copy('package.json', 'dist/package.json'); +await $`scripts/fix-imports.ts`; diff --git a/drizzle-zod/scripts/fix-imports.ts b/drizzle-zod/scripts/fix-imports.ts new file mode 100755 index 000000000..a90057c5b --- /dev/null +++ b/drizzle-zod/scripts/fix-imports.ts @@ -0,0 +1,136 @@ +#!/usr/bin/env -S pnpm tsx +import 'zx/globals'; + +import path from 'node:path'; +import { parse, print, visit } from 'recast'; +import parser from 'recast/parsers/typescript'; + +function resolvePathAlias(importPath: string, file: string) { + if (importPath.startsWith('~/')) { + const relativePath = path.relative(path.dirname(file), path.resolve('dist.new', importPath.slice(2))); + importPath = relativePath.startsWith('.') ? relativePath : './' + relativePath; + } + + return importPath; +} + +function fixImportPath(importPath: string, file: string, ext: string) { + importPath = resolvePathAlias(importPath, file); + + if (!/\..*\.(js|ts)$/.test(importPath)) { + return importPath; + } + + return importPath.replace(/\.(js|ts)$/, ext); +} + +const cjsFiles = await glob('dist/**/*.{cjs,d.cts}'); + +await Promise.all(cjsFiles.map(async (file) => { + const code = parse(await fs.readFile(file, 'utf8'), { parser }); + + visit(code, { + visitImportDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + this.traverse(path); + }, + visitExportAllDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + this.traverse(path); + }, + visitExportNamedDeclaration(path) { + if (path.value.source) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + } + this.traverse(path); + }, + visitCallExpression(path) { + if (path.value.callee.type === 'Identifier' && path.value.callee.name === 'require') { + path.value.arguments[0].value = fixImportPath(path.value.arguments[0].value, file, '.cjs'); + } + this.traverse(path); + }, + visitTSImportType(path) { + path.value.argument.value = resolvePathAlias(path.value.argument.value, file); + this.traverse(path); + }, + visitAwaitExpression(path) { + if (print(path.value).code.startsWith(`await import("./`)) { + path.value.argument.arguments[0].value = fixImportPath(path.value.argument.arguments[0].value, file, '.cjs'); + } + this.traverse(path); + }, + }); + + await fs.writeFile(file, print(code).code); +})); + +let esmFiles = await glob('dist/**/*.{js,d.ts}'); + +await Promise.all(esmFiles.map(async (file) => { + const code = parse(await fs.readFile(file, 'utf8'), { parser }); + + visit(code, { + visitImportDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + this.traverse(path); + }, + visitExportAllDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + this.traverse(path); + }, + visitExportNamedDeclaration(path) { + if (path.value.source) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + } + this.traverse(path); + }, + visitTSImportType(path) { + path.value.argument.value = fixImportPath(path.value.argument.value, file, '.js'); + this.traverse(path); + }, + visitAwaitExpression(path) { + if (print(path.value).code.startsWith(`await import("./`)) { + path.value.argument.arguments[0].value = fixImportPath(path.value.argument.arguments[0].value, file, '.js'); + } + this.traverse(path); + }, + }); + + await fs.writeFile(file, print(code).code); +})); + +esmFiles = await glob('dist/**/*.{mjs,d.mts}'); + +await Promise.all(esmFiles.map(async (file) => { + const code = parse(await fs.readFile(file, 'utf8'), { parser }); + + visit(code, { + visitImportDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.mjs'); + this.traverse(path); + }, + visitExportAllDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.mjs'); + this.traverse(path); + }, + visitExportNamedDeclaration(path) { + if (path.value.source) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.mjs'); + } + this.traverse(path); + }, + visitTSImportType(path) { + path.value.argument.value = fixImportPath(path.value.argument.value, file, '.mjs'); + this.traverse(path); + }, + visitAwaitExpression(path) { + if (print(path.value).code.startsWith(`await import("./`)) { + path.value.argument.arguments[0].value = fixImportPath(path.value.argument.arguments[0].value, file, '.mjs'); + } + this.traverse(path); + }, + }); + + await fs.writeFile(file, print(code).code); +})); diff --git a/drizzle-zod/src/column.ts b/drizzle-zod/src/column.ts new file mode 100644 index 000000000..4aae40e7e --- /dev/null +++ b/drizzle-zod/src/column.ts @@ -0,0 +1,227 @@ +import type { Column, ColumnBaseConfig } from 'drizzle-orm'; +import type { + MySqlBigInt53, + MySqlChar, + MySqlDouble, + MySqlFloat, + MySqlInt, + MySqlMediumInt, + MySqlReal, + MySqlSerial, + MySqlSmallInt, + MySqlText, + MySqlTinyInt, + MySqlVarChar, + MySqlYear, +} from 'drizzle-orm/mysql-core'; +import type { + PgArray, + PgBigInt53, + PgBigSerial53, + PgBinaryVector, + PgChar, + PgDoublePrecision, + PgGeometry, + PgGeometryObject, + PgHalfVector, + PgInteger, + PgLineABC, + PgLineTuple, + PgPointObject, + PgPointTuple, + PgReal, + PgSerial, + PgSmallInt, + PgSmallSerial, + PgUUID, + PgVarchar, + PgVector, +} from 'drizzle-orm/pg-core'; +import type { SQLiteInteger, SQLiteReal, SQLiteText } from 'drizzle-orm/sqlite-core'; +import { z } from 'zod'; +import type { z as zod } from 'zod'; +import { CONSTANTS } from './constants.ts'; +import { isColumnType, isWithEnum } from './utils.ts'; +import type { Json } from './utils.ts'; + +export const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]); +export const jsonSchema: z.ZodType = z.lazy(() => + z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]) +); +export const bufferSchema: z.ZodType = z.custom((v) => v instanceof Buffer); // eslint-disable-line no-instanceof/no-instanceof + +/** @internal */ +export function columnToSchema(column: Column, z: typeof zod): z.ZodTypeAny { + let schema!: z.ZodTypeAny; + + if (isWithEnum(column)) { + schema = column.enumValues.length ? z.enum(column.enumValues) : z.string(); + } + + if (!schema) { + // Handle specific types + if (isColumnType | PgPointTuple>(column, ['PgGeometry', 'PgPointTuple'])) { + schema = z.tuple([z.number(), z.number()]); + } else if ( + isColumnType | PgGeometryObject>(column, ['PgGeometryObject', 'PgPointObject']) + ) { + schema = z.object({ x: z.number(), y: z.number() }); + } else if (isColumnType | PgVector>(column, ['PgHalfVector', 'PgVector'])) { + schema = z.array(z.number()); + schema = column.dimensions ? (schema as z.ZodArray).length(column.dimensions) : schema; + } else if (isColumnType>(column, ['PgLine'])) { + schema = z.tuple([z.number(), z.number(), z.number()]); + } else if (isColumnType>(column, ['PgLineABC'])) { + schema = z.object({ + a: z.number(), + b: z.number(), + c: z.number(), + }); + } // Handle other types + else if (isColumnType>(column, ['PgArray'])) { + schema = z.array(columnToSchema(column.baseColumn, z)); + schema = column.size ? (schema as z.ZodArray).length(column.size) : schema; + } else if (column.dataType === 'array') { + schema = z.array(z.any()); + } else if (column.dataType === 'number') { + schema = numberColumnToSchema(column, z); + } else if (column.dataType === 'bigint') { + schema = bigintColumnToSchema(column, z); + } else if (column.dataType === 'boolean') { + schema = z.boolean(); + } else if (column.dataType === 'date') { + schema = z.date(); + } else if (column.dataType === 'string') { + schema = stringColumnToSchema(column, z); + } else if (column.dataType === 'json') { + schema = jsonSchema; + } else if (column.dataType === 'custom') { + schema = z.any(); + } else if (column.dataType === 'buffer') { + schema = bufferSchema; + } + } + + if (!schema) { + schema = z.any(); + } + + return schema; +} + +function numberColumnToSchema(column: Column, z: typeof zod): z.ZodTypeAny { + let unsigned = column.getSQLType().includes('unsigned'); + let min!: number; + let max!: number; + let integer = false; + + if (isColumnType>(column, ['MySqlTinyInt'])) { + min = unsigned ? 0 : CONSTANTS.INT8_MIN; + max = unsigned ? CONSTANTS.INT8_UNSIGNED_MAX : CONSTANTS.INT8_MAX; + integer = true; + } else if ( + isColumnType | PgSmallSerial | MySqlSmallInt>(column, [ + 'PgSmallInt', + 'PgSmallSerial', + 'MySqlSmallInt', + ]) + ) { + min = unsigned ? 0 : CONSTANTS.INT16_MIN; + max = unsigned ? CONSTANTS.INT16_UNSIGNED_MAX : CONSTANTS.INT16_MAX; + integer = true; + } else if ( + isColumnType | MySqlFloat | MySqlMediumInt>(column, [ + 'PgReal', + 'MySqlFloat', + 'MySqlMediumInt', + ]) + ) { + min = unsigned ? 0 : CONSTANTS.INT24_MIN; + max = unsigned ? CONSTANTS.INT24_UNSIGNED_MAX : CONSTANTS.INT24_MAX; + integer = isColumnType(column, ['MySqlMediumInt']); + } else if ( + isColumnType | PgSerial | MySqlInt>(column, ['PgInteger', 'PgSerial', 'MySqlInt']) + ) { + min = unsigned ? 0 : CONSTANTS.INT32_MIN; + max = unsigned ? CONSTANTS.INT32_UNSIGNED_MAX : CONSTANTS.INT32_MAX; + integer = true; + } else if ( + isColumnType | MySqlReal | MySqlDouble | SQLiteReal>(column, [ + 'PgDoublePrecision', + 'MySqlReal', + 'MySqlDouble', + 'SQLiteReal', + ]) + ) { + min = unsigned ? 0 : CONSTANTS.INT48_MIN; + max = unsigned ? CONSTANTS.INT48_UNSIGNED_MAX : CONSTANTS.INT48_MAX; + } else if ( + isColumnType | PgBigSerial53 | MySqlBigInt53 | MySqlSerial | SQLiteInteger>( + column, + ['PgBigInt53', 'PgBigSerial53', 'MySqlBigInt53', 'MySqlSerial', 'SQLiteInteger'], + ) + ) { + unsigned = unsigned || isColumnType(column, ['MySqlSerial']); + min = unsigned ? 0 : Number.MIN_SAFE_INTEGER; + max = Number.MAX_SAFE_INTEGER; + integer = true; + } else if (isColumnType>(column, ['MySqlYear'])) { + min = 1901; + max = 2155; + integer = true; + } else { + min = Number.MIN_SAFE_INTEGER; + max = Number.MAX_SAFE_INTEGER; + } + + const schema = z.number().min(min).max(max); + return integer ? schema.int() : schema; +} + +function bigintColumnToSchema(column: Column, z: typeof zod): z.ZodTypeAny { + const unsigned = column.getSQLType().includes('unsigned'); + const min = unsigned ? 0n : CONSTANTS.INT64_MIN; + const max = unsigned ? CONSTANTS.INT64_UNSIGNED_MAX : CONSTANTS.INT64_MAX; + + return z.bigint().min(min).max(max); +} + +function stringColumnToSchema(column: Column, z: typeof zod): z.ZodTypeAny { + if (isColumnType>>(column, ['PgUUID'])) { + return z.string().uuid(); + } + + let max: number | undefined; + let regex: RegExp | undefined; + let fixed = false; + + if (isColumnType | SQLiteText>(column, ['PgVarchar', 'SQLiteText'])) { + max = column.length; + } else if (isColumnType>(column, ['MySqlVarChar'])) { + max = column.length ?? CONSTANTS.INT16_UNSIGNED_MAX; + } else if (isColumnType>(column, ['MySqlText'])) { + if (column.textType === 'longtext') { + max = CONSTANTS.INT32_UNSIGNED_MAX; + } else if (column.textType === 'mediumtext') { + max = CONSTANTS.INT24_UNSIGNED_MAX; + } else if (column.textType === 'text') { + max = CONSTANTS.INT16_UNSIGNED_MAX; + } else { + max = CONSTANTS.INT8_UNSIGNED_MAX; + } + } + + if (isColumnType | MySqlChar>(column, ['PgChar', 'MySqlChar'])) { + max = column.length; + fixed = true; + } + + if (isColumnType>(column, ['PgBinaryVector'])) { + regex = /^[01]+$/; + max = column.dimensions; + } + + let schema = z.string(); + schema = regex ? schema.regex(regex) : schema; + return max && fixed ? schema.length(max) : max ? schema.max(max) : schema; +} diff --git a/drizzle-zod/src/column.types.ts b/drizzle-zod/src/column.types.ts new file mode 100644 index 000000000..49c12cdbb --- /dev/null +++ b/drizzle-zod/src/column.types.ts @@ -0,0 +1,76 @@ +import type { Assume, Column } from 'drizzle-orm'; +import type { z } from 'zod'; +import type { ArrayHasAtLeastOneValue, ColumnIsGeneratedAlwaysAs, IsNever, Json } from './utils.ts'; + +export type GetEnumValuesFromColumn = TColumn['_'] extends { enumValues: [string, ...string[]] } + ? TColumn['_']['enumValues'] + : undefined; + +export type GetBaseColumn = TColumn['_'] extends { baseColumn: Column | never | undefined } + ? IsNever extends false ? TColumn['_']['baseColumn'] + : undefined + : undefined; + +export type GetZodType< + TData, + TDataType extends string, + TEnumValues extends [string, ...string[]] | undefined, + TBaseColumn extends Column | undefined, +> = TBaseColumn extends Column ? z.ZodArray< + GetZodType< + TBaseColumn['_']['data'], + TBaseColumn['_']['dataType'], + GetEnumValuesFromColumn, + GetBaseColumn + > + > + : ArrayHasAtLeastOneValue extends true ? z.ZodEnum> + : TData extends infer TTuple extends [any, ...any[]] + ? z.ZodTuple }, [any, ...any[]]>> + : TData extends Date ? z.ZodDate + : TData extends Buffer ? z.ZodType + : TDataType extends 'array' ? z.ZodArray[number], string, undefined, undefined>> + : TData extends infer TDict extends Record + ? z.ZodObject<{ [K in keyof TDict]: GetZodType }, 'strip'> + : TDataType extends 'json' ? z.ZodType + : TData extends number ? z.ZodNumber + : TData extends bigint ? z.ZodBigInt + : TData extends boolean ? z.ZodBoolean + : TData extends string ? z.ZodString + : z.ZodTypeAny; + +type HandleSelectColumn< + TSchema extends z.ZodTypeAny, + TColumn extends Column, +> = TColumn['_']['notNull'] extends true ? TSchema + : z.ZodNullable; + +type HandleInsertColumn< + TSchema extends z.ZodTypeAny, + TColumn extends Column, +> = ColumnIsGeneratedAlwaysAs extends true ? never + : TColumn['_']['notNull'] extends true ? TColumn['_']['hasDefault'] extends true ? z.ZodOptional + : TSchema + : z.ZodOptional>; + +type HandleUpdateColumn< + TSchema extends z.ZodTypeAny, + TColumn extends Column, +> = ColumnIsGeneratedAlwaysAs extends true ? never + : TColumn['_']['notNull'] extends true ? z.ZodOptional + : z.ZodOptional>; + +export type HandleColumn< + TType extends 'select' | 'insert' | 'update', + TColumn extends Column, +> = GetZodType< + TColumn['_']['data'], + TColumn['_']['dataType'], + GetEnumValuesFromColumn, + GetBaseColumn +> extends infer TSchema extends z.ZodTypeAny ? TSchema extends z.ZodAny ? z.ZodAny + : TType extends 'select' ? HandleSelectColumn + : TType extends 'insert' ? HandleInsertColumn + : TType extends 'update' ? HandleUpdateColumn + : TSchema + : z.ZodAny; diff --git a/drizzle-zod/src/constants.ts b/drizzle-zod/src/constants.ts new file mode 100644 index 000000000..99f5d7a42 --- /dev/null +++ b/drizzle-zod/src/constants.ts @@ -0,0 +1,20 @@ +export const CONSTANTS = { + INT8_MIN: -128, + INT8_MAX: 127, + INT8_UNSIGNED_MAX: 255, + INT16_MIN: -32768, + INT16_MAX: 32767, + INT16_UNSIGNED_MAX: 65535, + INT24_MIN: -8388608, + INT24_MAX: 8388607, + INT24_UNSIGNED_MAX: 16777215, + INT32_MIN: -2147483648, + INT32_MAX: 2147483647, + INT32_UNSIGNED_MAX: 4294967295, + INT48_MIN: -140737488355328, + INT48_MAX: 140737488355327, + INT48_UNSIGNED_MAX: 281474976710655, + INT64_MIN: -9223372036854775808n, + INT64_MAX: 9223372036854775807n, + INT64_UNSIGNED_MAX: 18446744073709551615n, +}; diff --git a/drizzle-zod/src/index.ts b/drizzle-zod/src/index.ts index 3f6547e0b..0a6499e5b 100644 --- a/drizzle-zod/src/index.ts +++ b/drizzle-zod/src/index.ts @@ -1,239 +1,2 @@ -import { - type Assume, - type Column, - type DrizzleTypeError, - type Equal, - getTableColumns, - is, - type Simplify, - type Table, -} from 'drizzle-orm'; -import { MySqlChar, MySqlVarBinary, MySqlVarChar } from 'drizzle-orm/mysql-core'; -import { type PgArray, PgChar, PgUUID, PgVarchar } from 'drizzle-orm/pg-core'; -import { SQLiteText } from 'drizzle-orm/sqlite-core'; -import { z } from 'zod'; - -const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]); -type Literal = z.infer; -type Json = Literal | { [key: string]: Json } | Json[]; -export const jsonSchema: z.ZodType = z.lazy(() => - z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]) -); - -type MapInsertColumnToZod = TColumn['_']['notNull'] extends false - ? z.ZodOptional> - : TColumn['_']['hasDefault'] extends true ? z.ZodOptional - : TType; - -type MapSelectColumnToZod = TColumn['_']['notNull'] extends false - ? z.ZodNullable - : TType; - -type MapColumnToZod = - TMode extends 'insert' ? MapInsertColumnToZod : MapSelectColumnToZod; - -type MaybeOptional< - TColumn extends Column, - TType extends z.ZodTypeAny, - TMode extends 'insert' | 'select', - TNoOptional extends boolean, -> = TNoOptional extends true ? TType - : MapColumnToZod; - -type GetZodType = TColumn['_']['dataType'] extends infer TDataType - ? TDataType extends 'custom' ? z.ZodAny - : TDataType extends 'json' ? z.ZodType - : TColumn extends { enumValues: [string, ...string[]] } - ? Equal extends true ? z.ZodString : z.ZodEnum - : TDataType extends 'array' ? z.ZodArray['baseColumn']>> - : TDataType extends 'bigint' ? z.ZodBigInt - : TDataType extends 'number' ? z.ZodNumber - : TDataType extends 'string' ? z.ZodString - : TDataType extends 'boolean' ? z.ZodBoolean - : TDataType extends 'date' ? z.ZodDate - : z.ZodAny - : never; - -type ValueOrUpdater = T | ((arg: TUpdaterArg) => T); - -type UnwrapValueOrUpdater = T extends ValueOrUpdater ? U : never; - -export type Refine = { - [K in keyof TTable['_']['columns']]?: ValueOrUpdater< - z.ZodTypeAny, - TMode extends 'select' ? BuildSelectSchema : BuildInsertSchema - >; -}; - -export type BuildInsertSchema< - TTable extends Table, - TRefine extends Refine | {}, - TNoOptional extends boolean = false, -> = TTable['_']['columns'] extends infer TColumns extends Record> ? { - [K in keyof TColumns & string]: MaybeOptional< - TColumns[K], - (K extends keyof TRefine ? Assume, z.ZodTypeAny> - : GetZodType), - 'insert', - TNoOptional - >; - } - : never; - -export type BuildSelectSchema< - TTable extends Table, - TRefine extends Refine, - TNoOptional extends boolean = false, -> = Simplify< - { - [K in keyof TTable['_']['columns']]: MaybeOptional< - TTable['_']['columns'][K], - (K extends keyof TRefine ? Assume, z.ZodTypeAny> - : GetZodType), - 'select', - TNoOptional - >; - } ->; - -export function createInsertSchema< - TTable extends Table, - TRefine extends Refine = Refine, ->( - table: TTable, - /** - * @param refine Refine schema fields - */ - refine?: { - [K in keyof TRefine]: K extends keyof TTable['_']['columns'] ? TRefine[K] - : DrizzleTypeError<`Column '${K & string}' does not exist in table '${TTable['_']['name']}'`>; - }, -): z.ZodObject> extends true ? {} : TRefine>> { - const columns = getTableColumns(table); - const columnEntries = Object.entries(columns); - - let schemaEntries = Object.fromEntries(columnEntries.map(([name, column]) => { - return [name, mapColumnToSchema(column)]; - })); - - if (refine) { - schemaEntries = Object.assign( - schemaEntries, - Object.fromEntries( - Object.entries(refine).map(([name, refineColumn]) => { - return [ - name, - typeof refineColumn === 'function' - ? refineColumn(schemaEntries as BuildInsertSchema) - : refineColumn, - ]; - }), - ), - ); - } - - for (const [name, column] of columnEntries) { - if (!column.notNull) { - schemaEntries[name] = schemaEntries[name]!.nullable().optional(); - } else if (column.hasDefault) { - schemaEntries[name] = schemaEntries[name]!.optional(); - } - } - - return z.object(schemaEntries) as any; -} - -export function createSelectSchema< - TTable extends Table, - TRefine extends Refine = Refine, ->( - table: TTable, - /** - * @param refine Refine schema fields - */ - refine?: { - [K in keyof TRefine]: K extends keyof TTable['_']['columns'] ? TRefine[K] - : DrizzleTypeError<`Column '${K & string}' does not exist in table '${TTable['_']['name']}'`>; - }, -): z.ZodObject> extends true ? {} : TRefine>> { - const columns = getTableColumns(table); - const columnEntries = Object.entries(columns); - - let schemaEntries = Object.fromEntries(columnEntries.map(([name, column]) => { - return [name, mapColumnToSchema(column)]; - })); - - if (refine) { - schemaEntries = Object.assign( - schemaEntries, - Object.fromEntries( - Object.entries(refine).map(([name, refineColumn]) => { - return [ - name, - typeof refineColumn === 'function' - ? refineColumn(schemaEntries as BuildSelectSchema) - : refineColumn, - ]; - }), - ), - ); - } - - for (const [name, column] of columnEntries) { - if (!column.notNull) { - schemaEntries[name] = schemaEntries[name]!.nullable(); - } - } - - return z.object(schemaEntries) as any; -} - -function isWithEnum(column: Column): column is typeof column & { enumValues: [string, ...string[]] } { - return 'enumValues' in column && Array.isArray(column.enumValues) && column.enumValues.length > 0; -} - -function mapColumnToSchema(column: Column): z.ZodTypeAny { - let type: z.ZodTypeAny | undefined; - - if (isWithEnum(column)) { - type = column.enumValues.length ? z.enum(column.enumValues) : z.string(); - } - - if (!type) { - if (is(column, PgUUID)) { - type = z.string().uuid(); - } else if (column.dataType === 'custom') { - type = z.any(); - } else if (column.dataType === 'json') { - type = jsonSchema; - } else if (column.dataType === 'array') { - type = z.array(mapColumnToSchema((column as PgArray).baseColumn)); - } else if (column.dataType === 'number') { - type = z.number(); - } else if (column.dataType === 'bigint') { - type = z.bigint(); - } else if (column.dataType === 'boolean') { - type = z.boolean(); - } else if (column.dataType === 'date') { - type = z.date(); - } else if (column.dataType === 'string') { - let sType = z.string(); - - if ( - (is(column, PgChar) || is(column, PgVarchar) || is(column, MySqlVarChar) - || is(column, MySqlVarBinary) || is(column, MySqlChar) || is(column, SQLiteText)) - && (typeof column.length === 'number') - ) { - sType = sType.max(column.length); - } - - type = sType; - } - } - - if (!type) { - type = z.any(); - } - - return type; -} +export * from './schema.ts'; +export * from './schema.types.ts'; diff --git a/drizzle-zod/src/schema.ts b/drizzle-zod/src/schema.ts new file mode 100644 index 000000000..67a9cb733 --- /dev/null +++ b/drizzle-zod/src/schema.ts @@ -0,0 +1,143 @@ +import { Column, getTableColumns, getViewSelectedFields, is, isTable, isView, SQL } from 'drizzle-orm'; +import type { Table, View } from 'drizzle-orm'; +import type { PgEnum } from 'drizzle-orm/pg-core'; +import { z } from 'zod'; +import { columnToSchema } from './column.ts'; +import type { Conditions } from './schema.types.internal.ts'; +import type { + CreateInsertSchema, + CreateSchemaFactoryOptions, + CreateSelectSchema, + CreateUpdateSchema, +} from './schema.types.ts'; +import { isPgEnum } from './utils.ts'; + +function getColumns(tableLike: Table | View) { + return isTable(tableLike) ? getTableColumns(tableLike) : getViewSelectedFields(tableLike); +} + +function handleColumns( + columns: Record, + refinements: Record, + conditions: Conditions, + factory?: CreateSchemaFactoryOptions, +): z.ZodTypeAny { + const columnSchemas: Record = {}; + + for (const [key, selected] of Object.entries(columns)) { + if (!is(selected, Column) && !is(selected, SQL) && !is(selected, SQL.Aliased) && typeof selected === 'object') { + const columns = isTable(selected) || isView(selected) ? getColumns(selected) : selected; + columnSchemas[key] = handleColumns(columns, refinements[key] ?? {}, conditions, factory); + continue; + } + + const refinement = refinements[key]; + if (refinement !== undefined && typeof refinement !== 'function') { + columnSchemas[key] = refinement; + continue; + } + + const column = is(selected, Column) ? selected : undefined; + const schema = column ? columnToSchema(column, factory?.zodInstance ?? z) : z.any(); + const refined = typeof refinement === 'function' ? refinement(schema) : schema; + + if (conditions.never(column)) { + continue; + } else { + columnSchemas[key] = refined; + } + + if (column) { + if (conditions.nullable(column)) { + columnSchemas[key] = columnSchemas[key]!.nullable(); + } + + if (conditions.optional(column)) { + columnSchemas[key] = columnSchemas[key]!.optional(); + } + } + } + + return z.object(columnSchemas) as any; +} + +function handleEnum(enum_: PgEnum, factory?: CreateSchemaFactoryOptions) { + const zod: typeof z = factory?.zodInstance ?? z; + return zod.enum(enum_.enumValues); +} + +const selectConditions: Conditions = { + never: () => false, + optional: () => false, + nullable: (column) => !column.notNull, +}; + +const insertConditions: Conditions = { + never: (column) => column?.generated?.type === 'always' || column?.generatedIdentity?.type === 'always', + optional: (column) => !column.notNull || (column.notNull && column.hasDefault), + nullable: (column) => !column.notNull, +}; + +const updateConditions: Conditions = { + never: (column) => column?.generated?.type === 'always' || column?.generatedIdentity?.type === 'always', + optional: () => true, + nullable: (column) => !column.notNull, +}; + +export const createSelectSchema: CreateSelectSchema = ( + entity: Table | View | PgEnum<[string, ...string[]]>, + refine?: Record, +) => { + if (isPgEnum(entity)) { + return handleEnum(entity); + } + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, selectConditions) as any; +}; + +export const createInsertSchema: CreateInsertSchema = ( + entity: Table, + refine?: Record, +) => { + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, insertConditions) as any; +}; + +export const createUpdateSchema: CreateUpdateSchema = ( + entity: Table, + refine?: Record, +) => { + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, updateConditions) as any; +}; + +export function createSchemaFactory(options?: CreateSchemaFactoryOptions) { + const createSelectSchema: CreateSelectSchema = ( + entity: Table | View | PgEnum<[string, ...string[]]>, + refine?: Record, + ) => { + if (isPgEnum(entity)) { + return handleEnum(entity, options); + } + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, selectConditions, options) as any; + }; + + const createInsertSchema: CreateInsertSchema = ( + entity: Table, + refine?: Record, + ) => { + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, insertConditions, options) as any; + }; + + const createUpdateSchema: CreateUpdateSchema = ( + entity: Table, + refine?: Record, + ) => { + const columns = getColumns(entity); + return handleColumns(columns, refine ?? {}, updateConditions, options) as any; + }; + + return { createSelectSchema, createInsertSchema, createUpdateSchema }; +} diff --git a/drizzle-zod/src/schema.types.internal.ts b/drizzle-zod/src/schema.types.internal.ts new file mode 100644 index 000000000..5732e2e0f --- /dev/null +++ b/drizzle-zod/src/schema.types.internal.ts @@ -0,0 +1,88 @@ +import type { Assume, Column, DrizzleTypeError, SelectedFieldsFlat, Simplify, Table, View } from 'drizzle-orm'; +import type { z } from 'zod'; +import type { GetBaseColumn, GetEnumValuesFromColumn, GetZodType, HandleColumn } from './column.types.ts'; +import type { GetSelection, RemoveNever } from './utils.ts'; + +export interface Conditions { + never: (column?: Column) => boolean; + optional: (column: Column) => boolean; + nullable: (column: Column) => boolean; +} + +export type BuildRefineColumns< + TColumns extends Record, +> = Simplify< + RemoveNever< + { + [K in keyof TColumns]: TColumns[K] extends infer TColumn extends Column ? GetZodType< + TColumn['_']['data'], + TColumn['_']['dataType'], + GetEnumValuesFromColumn, + GetBaseColumn + > extends infer TSchema extends z.ZodTypeAny ? TSchema + : z.ZodAny + : TColumns[K] extends infer TObject extends SelectedFieldsFlat | Table | View + ? BuildRefineColumns> + : TColumns[K]; + } + > +>; + +export type BuildRefine< + TColumns extends Record, +> = BuildRefineColumns extends infer TBuildColumns ? { + [K in keyof TBuildColumns]?: TBuildColumns[K] extends z.ZodTypeAny + ? ((schema: TBuildColumns[K]) => z.ZodTypeAny) | z.ZodTypeAny + : TBuildColumns[K] extends Record ? Simplify> + : never; + } + : never; + +type HandleRefinement< + TRefinement extends z.ZodTypeAny | ((schema: z.ZodTypeAny) => z.ZodTypeAny), + TColumn extends Column, +> = TRefinement extends (schema: z.ZodTypeAny) => z.ZodTypeAny + ? TColumn['_']['notNull'] extends true ? ReturnType + : z.ZodNullable> + : TRefinement; + +export type BuildSchema< + TType extends 'select' | 'insert' | 'update', + TColumns extends Record, + TRefinements extends Record | undefined, +> = z.ZodObject< + Simplify< + RemoveNever< + { + [K in keyof TColumns]: TColumns[K] extends infer TColumn extends Column + ? TRefinements extends object + ? TRefinements[Assume] extends + infer TRefinement extends z.ZodTypeAny | ((schema: z.ZodTypeAny) => z.ZodTypeAny) + ? HandleRefinement + : HandleColumn + : HandleColumn + : TColumns[K] extends infer TObject extends SelectedFieldsFlat | Table | View ? BuildSchema< + TType, + GetSelection, + TRefinements extends object + ? TRefinements[Assume] extends infer TNestedRefinements extends object + ? TNestedRefinements + : undefined + : undefined + > + : z.ZodAny; + } + > + >, + 'strip' +>; + +export type NoUnknownKeys< + TRefinement extends Record, + TCompare extends Record, +> = { + [K in keyof TRefinement]: K extends keyof TCompare + ? TRefinement[K] extends Record ? NoUnknownKeys + : TRefinement[K] + : DrizzleTypeError<`Found unknown key in refinement: "${K & string}"`>; +}; diff --git a/drizzle-zod/src/schema.types.ts b/drizzle-zod/src/schema.types.ts new file mode 100644 index 000000000..5873cd2a3 --- /dev/null +++ b/drizzle-zod/src/schema.types.ts @@ -0,0 +1,52 @@ +import type { Table, View } from 'drizzle-orm'; +import type { PgEnum } from 'drizzle-orm/pg-core'; +import type { z } from 'zod'; +import type { BuildRefine, BuildSchema, NoUnknownKeys } from './schema.types.internal.ts'; + +export interface CreateSelectSchema { + (table: TTable): BuildSchema<'select', TTable['_']['columns'], undefined>; + < + TTable extends Table, + TRefine extends BuildRefine, + >( + table: TTable, + refine?: NoUnknownKeys, + ): BuildSchema<'select', TTable['_']['columns'], TRefine>; + + (view: TView): BuildSchema<'select', TView['_']['selectedFields'], undefined>; + < + TView extends View, + TRefine extends BuildRefine, + >( + view: TView, + refine: NoUnknownKeys, + ): BuildSchema<'select', TView['_']['selectedFields'], TRefine>; + + >(enum_: TEnum): z.ZodEnum; +} + +export interface CreateInsertSchema { + (table: TTable): BuildSchema<'insert', TTable['_']['columns'], undefined>; + < + TTable extends Table, + TRefine extends BuildRefine>, + >( + table: TTable, + refine?: NoUnknownKeys, + ): BuildSchema<'insert', TTable['_']['columns'], TRefine>; +} + +export interface CreateUpdateSchema { + (table: TTable): BuildSchema<'update', TTable['_']['columns'], undefined>; + < + TTable extends Table, + TRefine extends BuildRefine>, + >( + table: TTable, + refine?: TRefine, + ): BuildSchema<'update', TTable['_']['columns'], TRefine>; +} + +export interface CreateSchemaFactoryOptions { + zodInstance?: any; +} diff --git a/drizzle-zod/src/utils.ts b/drizzle-zod/src/utils.ts new file mode 100644 index 000000000..506b80565 --- /dev/null +++ b/drizzle-zod/src/utils.ts @@ -0,0 +1,40 @@ +import type { Column, SelectedFieldsFlat, Table, View } from 'drizzle-orm'; +import type { PgEnum } from 'drizzle-orm/pg-core'; +import type { z } from 'zod'; +import type { literalSchema } from './column.ts'; + +export function isColumnType(column: Column, columnTypes: string[]): column is T { + return columnTypes.includes(column.columnType); +} + +export function isWithEnum(column: Column): column is typeof column & { enumValues: [string, ...string[]] } { + return 'enumValues' in column && Array.isArray(column.enumValues) && column.enumValues.length > 0; +} + +export const isPgEnum: (entity: any) => entity is PgEnum<[string, ...string[]]> = isWithEnum as any; + +type Literal = z.infer; +export type Json = Literal | { [key: string]: Json } | Json[]; + +export type IsNever = [T] extends [never] ? true : false; + +export type ArrayHasAtLeastOneValue = TEnum extends [infer TString, ...any[]] + ? TString extends `${infer TLiteral}` ? TLiteral extends any ? true + : false + : false + : false; + +export type ColumnIsGeneratedAlwaysAs = TColumn['_']['identity'] extends 'always' ? true + : TColumn['_']['generated'] extends undefined ? false + : TColumn['_']['generated'] extends infer TGenerated extends { type: string } + ? TGenerated['type'] extends 'byDefault' ? false + : true + : true; + +export type RemoveNever = { + [K in keyof T as T[K] extends never ? never : K]: T[K]; +}; + +export type GetSelection | Table | View> = T extends Table ? T['_']['columns'] + : T extends View ? T['_']['selectedFields'] + : T; diff --git a/drizzle-zod/tests/mysql.test.ts b/drizzle-zod/tests/mysql.test.ts index f28d6a768..37c9b7e64 100644 --- a/drizzle-zod/tests/mysql.test.ts +++ b/drizzle-zod/tests/mysql.test.ts @@ -1,289 +1,463 @@ -import { - bigint, - binary, - boolean, - char, - customType, - date, - datetime, - decimal, - double, - float, - int, - json, - longtext, - mediumint, - mediumtext, - mysqlEnum, - mysqlTable, - real, - serial, - smallint, - text, - time, - timestamp, - tinyint, - tinytext, - varbinary, - varchar, - year, -} from 'drizzle-orm/mysql-core'; -import { expect, test } from 'vitest'; +import { type Equal, sql } from 'drizzle-orm'; +import { int, mysqlSchema, mysqlTable, mysqlView, serial, text } from 'drizzle-orm/mysql-core'; +import { test } from 'vitest'; import { z } from 'zod'; -import { createInsertSchema, createSelectSchema, jsonSchema } from '~/index'; -import { expectSchemaShape } from './utils.ts'; +import { jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectSchemaShape } from './utils.ts'; -const customInt = customType<{ data: number }>({ - dataType() { - return 'int'; - }, +const intSchema = z.number().min(CONSTANTS.INT32_MIN).max(CONSTANTS.INT32_MAX).int(); +const serialNumberModeSchema = z.number().min(0).max(Number.MAX_SAFE_INTEGER).int(); +const textSchema = z.string().max(CONSTANTS.INT16_UNSIGNED_MAX); + +test('table - select', (t) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = z.object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -const testTable = mysqlTable('test', { - bigint: bigint('bigint', { mode: 'bigint' }).notNull(), - bigintNumber: bigint('bigintNumber', { mode: 'number' }).notNull(), - binary: binary('binary').notNull(), - boolean: boolean('boolean').notNull(), - char: char('char', { length: 4 }).notNull(), - charEnum: char('char', { enum: ['a', 'b', 'c'] }).notNull(), - customInt: customInt('customInt').notNull(), - date: date('date').notNull(), - dateString: date('dateString', { mode: 'string' }).notNull(), - datetime: datetime('datetime').notNull(), - datetimeString: datetime('datetimeString', { mode: 'string' }).notNull(), - decimal: decimal('decimal').notNull(), - double: double('double').notNull(), - enum: mysqlEnum('enum', ['a', 'b', 'c']).notNull(), - float: float('float').notNull(), - int: int('int').notNull(), - json: json('json').notNull(), - mediumint: mediumint('mediumint').notNull(), - real: real('real').notNull(), - serial: serial('serial').notNull(), - smallint: smallint('smallint').notNull(), - text: text('text').notNull(), - textEnum: text('textEnum', { enum: ['a', 'b', 'c'] }).notNull(), - tinytext: tinytext('tinytext').notNull(), - tinytextEnum: tinytext('tinytextEnum', { enum: ['a', 'b', 'c'] }).notNull(), - mediumtext: mediumtext('mediumtext').notNull(), - mediumtextEnum: mediumtext('mediumtextEnum', { enum: ['a', 'b', 'c'] }).notNull(), - longtext: longtext('longtext').notNull(), - longtextEnum: longtext('longtextEnum', { enum: ['a', 'b', 'c'] }).notNull(), - time: time('time').notNull(), - timestamp: timestamp('timestamp').notNull(), - timestampString: timestamp('timestampString', { mode: 'string' }).notNull(), - tinyint: tinyint('tinyint').notNull(), - varbinary: varbinary('varbinary', { length: 200 }).notNull(), - varchar: varchar('varchar', { length: 200 }).notNull(), - varcharEnum: varchar('varcharEnum', { length: 1, enum: ['a', 'b', 'c'] }).notNull(), - year: year('year').notNull(), - autoIncrement: int('autoIncrement').notNull().autoincrement(), +test('table in schema - select', (tc) => { + const schema = mysqlSchema('test'); + const table = schema.table('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = z.object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); }); -const testTableRow = { - bigint: BigInt(1), - bigintNumber: 1, - binary: 'binary', - boolean: true, - char: 'char', - charEnum: 'a', - customInt: { data: 1 }, - date: new Date(), - dateString: new Date().toISOString(), - datetime: new Date(), - datetimeString: new Date().toISOString(), - decimal: '1.1', - double: 1.1, - enum: 'a', - float: 1.1, - int: 1, - json: { data: 1 }, - mediumint: 1, - real: 1.1, - serial: 1, - smallint: 1, - text: 'text', - textEnum: 'a', - tinytext: 'tinytext', - tinytextEnum: 'a', - mediumtext: 'mediumtext', - mediumtextEnum: 'a', - longtext: 'longtext', - longtextEnum: 'a', - time: '00:00:00', - timestamp: new Date(), - timestampString: new Date().toISOString(), - tinyint: 1, - varbinary: 'A'.repeat(200), - varchar: 'A'.repeat(200), - varcharEnum: 'a', - year: 2021, - autoIncrement: 1, -}; - -test('insert valid row', () => { - const schema = createInsertSchema(testTable); - - expect(schema.safeParse(testTableRow).success).toBeTruthy(); +test('table - insert', (t) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); + + const result = createInsertSchema(table); + const expected = z.object({ + id: serialNumberModeSchema.optional(), + name: textSchema, + age: intSchema.nullable().optional(), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('insert invalid varchar length', () => { - const schema = createInsertSchema(testTable); +test('table - update', (t) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); - expect(schema.safeParse({ ...testTableRow, varchar: 'A'.repeat(201) }).success).toBeFalsy(); + const result = createUpdateSchema(table); + const expected = z.object({ + id: serialNumberModeSchema.optional(), + name: textSchema.optional(), + age: intSchema.nullable().optional(), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('insert smaller char length should work', () => { - const schema = createInsertSchema(testTable); +test('view qb - select', (t) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = mysqlView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); - expect(schema.safeParse({ ...testTableRow, char: 'abc' }).success).toBeTruthy(); + const result = createSelectSchema(view); + const expected = z.object({ id: serialNumberModeSchema, age: z.any() }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('insert larger char length should fail', () => { - const schema = createInsertSchema(testTable); +test('view columns - select', (t) => { + const view = mysqlView('test', { + id: serial().primaryKey(), + name: text().notNull(), + }).as(sql``); - expect(schema.safeParse({ ...testTableRow, char: 'abcde' }).success).toBeFalsy(); + const result = createSelectSchema(view); + const expected = z.object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('insert schema', (t) => { - const actual = createInsertSchema(testTable); +test('view with nested fields - select', (t) => { + const table = mysqlTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = mysqlView('test').as((qb) => + qb.select({ + id: table.id, + nested: { + name: table.name, + age: sql``.as('age'), + }, + table, + }).from(table) + ); + const result = createSelectSchema(view); const expected = z.object({ - bigint: z.bigint(), - bigintNumber: z.number(), - binary: z.string(), - boolean: z.boolean(), - char: z.string().length(4), - charEnum: z.enum(['a', 'b', 'c']), - customInt: z.any(), - date: z.date(), - dateString: z.string(), - datetime: z.date(), - datetimeString: z.string(), - decimal: z.string(), - double: z.number(), - enum: z.enum(['a', 'b', 'c']), - float: z.number(), - int: z.number(), - json: jsonSchema, - mediumint: z.number(), - real: z.number(), - serial: z.number().optional(), - smallint: z.number(), - text: z.string(), - textEnum: z.enum(['a', 'b', 'c']), - tinytext: z.string(), - tinytextEnum: z.enum(['a', 'b', 'c']), - mediumtext: z.string(), - mediumtextEnum: z.enum(['a', 'b', 'c']), - longtext: z.string(), - longtextEnum: z.enum(['a', 'b', 'c']), - time: z.string(), - timestamp: z.date(), - timestampString: z.string(), - tinyint: z.number(), - varbinary: z.string().max(200), - varchar: z.string().max(200), - varcharEnum: z.enum(['a', 'b', 'c']), - year: z.number(), - autoIncrement: z.number().optional(), + id: serialNumberModeSchema, + nested: z.object({ name: textSchema, age: z.any() }), + table: z.object({ id: serialNumberModeSchema, name: textSchema }), }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); - expectSchemaShape(t, expected).from(actual); +test('nullability - select', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + }); + + const result = createSelectSchema(table); + const expected = z.object({ + c1: intSchema.nullable(), + c2: intSchema, + c3: intSchema.nullable(), + c4: intSchema, + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('select schema', (t) => { - const actual = createSelectSchema(testTable); +test('nullability - insert', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + const result = createInsertSchema(table); const expected = z.object({ - bigint: z.bigint(), - bigintNumber: z.number(), - binary: z.string(), - boolean: z.boolean(), - char: z.string().length(4), - charEnum: z.enum(['a', 'b', 'c']), - customInt: z.any(), - date: z.date(), - dateString: z.string(), - datetime: z.date(), - datetimeString: z.string(), - decimal: z.string(), - double: z.number(), - enum: z.enum(['a', 'b', 'c']), - float: z.number(), - int: z.number(), - json: jsonSchema, - mediumint: z.number(), - real: z.number(), - serial: z.number(), - smallint: z.number(), - text: z.string(), - textEnum: z.enum(['a', 'b', 'c']), - tinytext: z.string(), - tinytextEnum: z.enum(['a', 'b', 'c']), - mediumtext: z.string(), - mediumtextEnum: z.enum(['a', 'b', 'c']), - longtext: z.string(), - longtextEnum: z.enum(['a', 'b', 'c']), - time: z.string(), - timestamp: z.date(), - timestampString: z.string(), - tinyint: z.number(), - varbinary: z.string().max(200), - varchar: z.string().max(200), - varcharEnum: z.enum(['a', 'b', 'c']), - year: z.number(), - autoIncrement: z.number(), + c1: intSchema.nullable().optional(), + c2: intSchema, + c3: intSchema.nullable().optional(), + c4: intSchema.optional(), }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); - expectSchemaShape(t, expected).from(actual); +test('nullability - update', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table); + const expected = z.object({ + c1: intSchema.nullable().optional(), + c2: intSchema.optional(), + c3: intSchema.nullable().optional(), + c4: intSchema.optional(), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('select schema w/ refine', (t) => { - const actual = createSelectSchema(testTable, { - bigint: (schema) => schema.bigint.positive(), +test('refine table - select', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), }); + const result = createSelectSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); const expected = z.object({ - bigint: z.bigint().positive(), - bigintNumber: z.number(), + c1: intSchema.nullable(), + c2: intSchema.max(1000), + c3: z.string().transform(Number), + }); + + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - insert', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); + const expected = z.object({ + c1: intSchema.nullable().optional(), + c2: intSchema.max(1000), + c3: z.string().transform(Number), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - update', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); + const expected = z.object({ + c1: intSchema.nullable().optional(), + c2: intSchema.max(1000).optional(), + c3: z.string().transform(Number), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine view - select', (t) => { + const table = mysqlTable('test', { + c1: int(), + c2: int(), + c3: int(), + c4: int(), + c5: int(), + c6: int(), + }); + const view = mysqlView('test').as((qb) => + qb.select({ + c1: table.c1, + c2: table.c2, + c3: table.c3, + nested: { + c4: table.c4, + c5: table.c5, + c6: table.c6, + }, + table, + }).from(table) + ); + + const result = createSelectSchema(view, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + nested: { + c5: (schema) => schema.max(1000), + c6: z.string().transform(Number), + }, + table: { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }, + }); + const expected = z.object({ + c1: intSchema.nullable(), + c2: intSchema.max(1000).nullable(), + c3: z.string().transform(Number), + nested: z.object({ + c4: intSchema.nullable(), + c5: intSchema.max(1000).nullable(), + c6: z.string().transform(Number), + }), + table: z.object({ + c1: intSchema.nullable(), + c2: intSchema.max(1000).nullable(), + c3: z.string().transform(Number), + c4: intSchema.nullable(), + c5: intSchema.nullable(), + c6: intSchema.nullable(), + }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('all data types', (t) => { + const table = mysqlTable('test', ({ + bigint, + binary, + boolean, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + mysqlEnum, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varchar, + varbinary, + year, + longtext, + mediumtext, + tinytext, + }) => ({ + bigint1: bigint({ mode: 'number' }).notNull(), + bigint2: bigint({ mode: 'bigint' }).notNull(), + bigint3: bigint({ unsigned: true, mode: 'number' }).notNull(), + bigint4: bigint({ unsigned: true, mode: 'bigint' }).notNull(), + binary: binary({ length: 10 }).notNull(), + boolean: boolean().notNull(), + char1: char({ length: 10 }).notNull(), + char2: char({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + date1: date({ mode: 'date' }).notNull(), + date2: date({ mode: 'string' }).notNull(), + datetime1: datetime({ mode: 'date' }).notNull(), + datetime2: datetime({ mode: 'string' }).notNull(), + decimal1: decimal().notNull(), + decimal2: decimal({ unsigned: true }).notNull(), + double1: double().notNull(), + double2: double({ unsigned: true }).notNull(), + float1: float().notNull(), + float2: float({ unsigned: true }).notNull(), + int1: int().notNull(), + int2: int({ unsigned: true }).notNull(), + json: json().notNull(), + mediumint1: mediumint().notNull(), + mediumint2: mediumint({ unsigned: true }).notNull(), + enum: mysqlEnum('enum', ['a', 'b', 'c']).notNull(), + real: real().notNull(), + serial: serial().notNull(), + smallint1: smallint().notNull(), + smallint2: smallint({ unsigned: true }).notNull(), + text1: text().notNull(), + text2: text({ enum: ['a', 'b', 'c'] }).notNull(), + time: time().notNull(), + timestamp1: timestamp({ mode: 'date' }).notNull(), + timestamp2: timestamp({ mode: 'string' }).notNull(), + tinyint1: tinyint().notNull(), + tinyint2: tinyint({ unsigned: true }).notNull(), + varchar1: varchar({ length: 10 }).notNull(), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + varbinary: varbinary({ length: 10 }).notNull(), + year: year().notNull(), + longtext1: longtext().notNull(), + longtext2: longtext({ enum: ['a', 'b', 'c'] }).notNull(), + mediumtext1: mediumtext().notNull(), + mediumtext2: mediumtext({ enum: ['a', 'b', 'c'] }).notNull(), + tinytext1: tinytext().notNull(), + tinytext2: tinytext({ enum: ['a', 'b', 'c'] }).notNull(), + })); + + const result = createSelectSchema(table); + const expected = z.object({ + bigint1: z.number().min(Number.MIN_SAFE_INTEGER).max(Number.MAX_SAFE_INTEGER).int(), + bigint2: z.bigint().min(CONSTANTS.INT64_MIN).max(CONSTANTS.INT64_MAX), + bigint3: z.number().min(0).max(Number.MAX_SAFE_INTEGER).int(), + bigint4: z.bigint().min(0n).max(CONSTANTS.INT64_UNSIGNED_MAX), binary: z.string(), boolean: z.boolean(), - char: z.string().length(5), - charEnum: z.enum(['a', 'b', 'c']), - customInt: z.any(), - date: z.date(), - dateString: z.string(), - datetime: z.date(), - datetimeString: z.string(), - decimal: z.string(), - double: z.number(), - enum: z.enum(['a', 'b', 'c']), - float: z.number(), - int: z.number(), + char1: z.string().length(10), + char2: z.enum(['a', 'b', 'c']), + date1: z.date(), + date2: z.string(), + datetime1: z.date(), + datetime2: z.string(), + decimal1: z.string(), + decimal2: z.string(), + double1: z.number().min(CONSTANTS.INT48_MIN).max(CONSTANTS.INT48_MAX), + double2: z.number().min(0).max(CONSTANTS.INT48_UNSIGNED_MAX), + float1: z.number().min(CONSTANTS.INT24_MIN).max(CONSTANTS.INT24_MAX), + float2: z.number().min(0).max(CONSTANTS.INT24_UNSIGNED_MAX), + int1: z.number().min(CONSTANTS.INT32_MIN).max(CONSTANTS.INT32_MAX).int(), + int2: z.number().min(0).max(CONSTANTS.INT32_UNSIGNED_MAX).int(), json: jsonSchema, - mediumint: z.number(), - real: z.number(), - serial: z.number(), - smallint: z.number(), - text: z.string(), - textEnum: z.enum(['a', 'b', 'c']), - tinytext: z.string(), - tinytextEnum: z.enum(['a', 'b', 'c']), - mediumtext: z.string(), - mediumtextEnum: z.enum(['a', 'b', 'c']), - longtext: z.string(), - longtextEnum: z.enum(['a', 'b', 'c']), + mediumint1: z.number().min(CONSTANTS.INT24_MIN).max(CONSTANTS.INT24_MAX).int(), + mediumint2: z.number().min(0).max(CONSTANTS.INT24_UNSIGNED_MAX).int(), + enum: z.enum(['a', 'b', 'c']), + real: z.number().min(CONSTANTS.INT48_MIN).max(CONSTANTS.INT48_MAX), + serial: z.number().min(0).max(Number.MAX_SAFE_INTEGER).int(), + smallint1: z.number().min(CONSTANTS.INT16_MIN).max(CONSTANTS.INT16_MAX).int(), + smallint2: z.number().min(0).max(CONSTANTS.INT16_UNSIGNED_MAX).int(), + text1: z.string().max(CONSTANTS.INT16_UNSIGNED_MAX), + text2: z.enum(['a', 'b', 'c']), time: z.string(), - timestamp: z.date(), - timestampString: z.string(), - tinyint: z.number(), - varbinary: z.string().max(200), - varchar: z.string().max(200), - varcharEnum: z.enum(['a', 'b', 'c']), - year: z.number(), - autoIncrement: z.number(), + timestamp1: z.date(), + timestamp2: z.string(), + tinyint1: z.number().min(CONSTANTS.INT8_MIN).max(CONSTANTS.INT8_MAX).int(), + tinyint2: z.number().min(0).max(CONSTANTS.INT8_UNSIGNED_MAX).int(), + varchar1: z.string().max(10), + varchar2: z.enum(['a', 'b', 'c']), + varbinary: z.string(), + year: z.number().min(1901).max(2155).int(), + longtext1: z.string().max(CONSTANTS.INT32_UNSIGNED_MAX), + longtext2: z.enum(['a', 'b', 'c']), + mediumtext1: z.string().max(CONSTANTS.INT24_UNSIGNED_MAX), + mediumtext2: z.enum(['a', 'b', 'c']), + tinytext1: z.string().max(CONSTANTS.INT8_UNSIGNED_MAX), + tinytext2: z.enum(['a', 'b', 'c']), }); - - expectSchemaShape(t, expected).from(actual); + expectSchemaShape(t, expected).from(result); + Expect>(); }); + +/* Disallow unknown keys in table refinement - select */ { + const table = mysqlTable('test', { id: int() }); + // @ts-expect-error + createSelectSchema(table, { unknown: z.string() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = mysqlTable('test', { id: int() }); + // @ts-expect-error + createInsertSchema(table, { unknown: z.string() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = mysqlTable('test', { id: int() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: z.string() }); +} + +/* Disallow unknown keys in view qb - select */ { + const table = mysqlTable('test', { id: int() }); + const view = mysqlView('test').as((qb) => qb.select().from(table)); + const nestedSelect = mysqlView('test').as((qb) => qb.select({ table }).from(table)); + // @ts-expect-error + createSelectSchema(view, { unknown: z.string() }); + // @ts-expect-error + createSelectSchema(nestedSelect, { table: { unknown: z.string() } }); +} + +/* Disallow unknown keys in view columns - select */ { + const view = mysqlView('test', { id: int() }).as(sql``); + // @ts-expect-error + createSelectSchema(view, { unknown: z.string() }); +} diff --git a/drizzle-zod/tests/pg.test.ts b/drizzle-zod/tests/pg.test.ts index b1f6e0c20..dc703b4fc 100644 --- a/drizzle-zod/tests/pg.test.ts +++ b/drizzle-zod/tests/pg.test.ts @@ -1,163 +1,505 @@ -import { char, date, integer, pgEnum, pgTable, serial, text, timestamp, varchar } from 'drizzle-orm/pg-core'; -import { expect, test } from 'vitest'; +import { type Equal, sql } from 'drizzle-orm'; +import { integer, pgEnum, pgMaterializedView, pgSchema, pgTable, pgView, serial, text } from 'drizzle-orm/pg-core'; +import { test } from 'vitest'; import { z } from 'zod'; -import { createInsertSchema, createSelectSchema } from '../src'; -import { expectSchemaShape } from './utils.ts'; +import { jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectEnumValues, expectSchemaShape } from './utils.ts'; -export const roleEnum = pgEnum('role', ['admin', 'user']); +const integerSchema = z.number().min(CONSTANTS.INT32_MIN).max(CONSTANTS.INT32_MAX).int(); +const textSchema = z.string(); -const users = pgTable('users', { - a: integer('a').array(), - id: serial('id').primaryKey(), - name: text('name'), - email: text('email').notNull(), - birthdayString: date('birthday_string').notNull(), - birthdayDate: date('birthday_date', { mode: 'date' }).notNull(), - createdAt: timestamp('created_at').notNull().defaultNow(), - role: roleEnum('role').notNull(), - roleText: text('role1', { enum: ['admin', 'user'] }).notNull(), - roleText2: text('role2', { enum: ['admin', 'user'] }).notNull().default('user'), - profession: varchar('profession', { length: 20 }).notNull(), - initials: char('initials', { length: 2 }).notNull(), +test('table - select', (t) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = z.object({ id: integerSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -const testUser = { - a: [1, 2, 3], - id: 1, - name: 'John Doe', - email: 'john.doe@example.com', - birthdayString: '1990-01-01', - birthdayDate: new Date('1990-01-01'), - createdAt: new Date(), - role: 'admin', - roleText: 'admin', - roleText2: 'admin', - profession: 'Software Engineer', - initials: 'JD', -}; +test('table in schema - select', (tc) => { + const schema = pgSchema('test'); + const table = schema.table('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = z.object({ id: integerSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); -test('users insert valid user', () => { - const schema = createInsertSchema(users); +test('table - insert', (t) => { + const table = pgTable('test', { + id: integer().generatedAlwaysAsIdentity().primaryKey(), + name: text().notNull(), + age: integer(), + }); - expect(schema.safeParse(testUser).success).toBeTruthy(); + const result = createInsertSchema(table); + const expected = z.object({ name: textSchema, age: integerSchema.nullable().optional() }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users insert invalid varchar', () => { - const schema = createInsertSchema(users); +test('table - update', (t) => { + const table = pgTable('test', { + id: integer().generatedAlwaysAsIdentity().primaryKey(), + name: text().notNull(), + age: integer(), + }); + + const result = createUpdateSchema(table); + const expected = z.object({ + name: textSchema.optional(), + age: integerSchema.nullable().optional(), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('view qb - select', (t) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = pgView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + + const result = createSelectSchema(view); + const expected = z.object({ id: integerSchema, age: z.any() }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); - expect(schema.safeParse({ ...testUser, profession: 'Chief Executive Officer' }).success).toBeFalsy(); +test('view columns - select', (t) => { + const view = pgView('test', { + id: serial().primaryKey(), + name: text().notNull(), + }).as(sql``); + + const result = createSelectSchema(view); + const expected = z.object({ id: integerSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('materialized view qb - select', (t) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = pgMaterializedView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + + const result = createSelectSchema(view); + const expected = z.object({ id: integerSchema, age: z.any() }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('materialized view columns - select', (t) => { + const view = pgView('test', { + id: serial().primaryKey(), + name: text().notNull(), + }).as(sql``); + + const result = createSelectSchema(view); + const expected = z.object({ id: integerSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('view with nested fields - select', (t) => { + const table = pgTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + const view = pgMaterializedView('test').as((qb) => + qb.select({ + id: table.id, + nested: { + name: table.name, + age: sql``.as('age'), + }, + table, + }).from(table) + ); + + const result = createSelectSchema(view); + const expected = z.object({ + id: integerSchema, + nested: z.object({ name: textSchema, age: z.any() }), + table: z.object({ id: integerSchema, name: textSchema }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users insert invalid char', () => { - const schema = createInsertSchema(users); +test('enum - select', (t) => { + const enum_ = pgEnum('test', ['a', 'b', 'c']); - expect(schema.safeParse({ ...testUser, initials: 'JoDo' }).success).toBeFalsy(); + const result = createSelectSchema(enum_); + const expected = z.enum(['a', 'b', 'c']); + expectEnumValues(t, expected).from(result); + Expect>(); }); -test('users insert schema', (t) => { - const actual = createInsertSchema(users, { - id: ({ id }) => id.positive(), - email: ({ email }) => email.email(), - roleText: z.enum(['user', 'manager', 'admin']), +test('nullability - select', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().default(1), + c4: integer().notNull().default(1), }); - (() => { - { - createInsertSchema(users, { - // @ts-expect-error (missing property) - foobar: z.number(), - }); - } + const result = createSelectSchema(table); + const expected = z.object({ + c1: integerSchema.nullable(), + c2: integerSchema, + c3: integerSchema.nullable(), + c4: integerSchema, + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); - { - createInsertSchema(users, { - // @ts-expect-error (invalid type) - id: 123, - }); - } +test('nullability - insert', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().default(1), + c4: integer().notNull().default(1), + c5: integer().generatedAlwaysAs(1), + c6: integer().generatedAlwaysAsIdentity(), + c7: integer().generatedByDefaultAsIdentity(), }); + const result = createInsertSchema(table); const expected = z.object({ - a: z.array(z.number()).nullable().optional(), - id: z.number().positive().optional(), - name: z.string().nullable().optional(), - email: z.string().email(), - birthdayString: z.string(), - birthdayDate: z.date(), - createdAt: z.date().optional(), - role: z.enum(['admin', 'user']), - roleText: z.enum(['user', 'manager', 'admin']), - roleText2: z.enum(['admin', 'user']).optional(), - profession: z.string().max(20).min(1), - initials: z.string().max(2).min(1), + c1: integerSchema.nullable().optional(), + c2: integerSchema, + c3: integerSchema.nullable().optional(), + c4: integerSchema.optional(), + c7: integerSchema.optional(), + }); + expectSchemaShape(t, expected).from(result); +}); + +test('nullability - update', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().default(1), + c4: integer().notNull().default(1), + c5: integer().generatedAlwaysAs(1), + c6: integer().generatedAlwaysAsIdentity(), + c7: integer().generatedByDefaultAsIdentity(), }); - expectSchemaShape(t, expected).from(actual); + const result = createUpdateSchema(table); + const expected = z.object({ + c1: integerSchema.nullable().optional(), + c2: integerSchema.optional(), + c3: integerSchema.nullable().optional(), + c4: integerSchema.optional(), + c7: integerSchema.optional(), + }); + table.c5.generated?.type; + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users insert schema w/ defaults', (t) => { - const actual = createInsertSchema(users); +test('refine table - select', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + }); + const result = createSelectSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); const expected = z.object({ - a: z.array(z.number()).nullable().optional(), - id: z.number().optional(), - name: z.string().nullable().optional(), - email: z.string(), - birthdayString: z.string(), - birthdayDate: z.date(), - createdAt: z.date().optional(), - role: z.enum(['admin', 'user']), - roleText: z.enum(['admin', 'user']), - roleText2: z.enum(['admin', 'user']).optional(), - profession: z.string().max(20).min(1), - initials: z.string().max(2).min(1), + c1: integerSchema.nullable(), + c2: integerSchema.max(1000), + c3: z.string().transform(Number), }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); - expectSchemaShape(t, expected).from(actual); +test('refine table - insert', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + c4: integer().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); + const expected = z.object({ + c1: integerSchema.nullable().optional(), + c2: integerSchema.max(1000), + c3: z.string().transform(Number), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users select schema', (t) => { - const actual = createSelectSchema(users, { - id: ({ id }) => id.positive(), - email: ({ email }) => email.email(), - roleText: z.enum(['user', 'manager', 'admin']), +test('refine table - update', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + c4: integer().generatedAlwaysAs(1), }); + const result = createUpdateSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); const expected = z.object({ - a: z.array(z.number()).nullable(), - id: z.number().positive(), - name: z.string().nullable(), - email: z.string().email(), - birthdayString: z.string(), - birthdayDate: z.date(), - createdAt: z.date(), - role: z.enum(['admin', 'user']), - roleText: z.enum(['user', 'manager', 'admin']), - roleText2: z.enum(['admin', 'user']), - profession: z.string().max(20).min(1), - initials: z.string().max(2).min(1), + c1: integerSchema.nullable().optional(), + c2: integerSchema.max(1000).optional(), + c3: z.string().transform(Number), }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); - expectSchemaShape(t, expected).from(actual); +test('refine view - select', (t) => { + const table = pgTable('test', { + c1: integer(), + c2: integer(), + c3: integer(), + c4: integer(), + c5: integer(), + c6: integer(), + }); + const view = pgView('test').as((qb) => + qb.select({ + c1: table.c1, + c2: table.c2, + c3: table.c3, + nested: { + c4: table.c4, + c5: table.c5, + c6: table.c6, + }, + table, + }).from(table) + ); + + const result = createSelectSchema(view, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + nested: { + c5: (schema) => schema.max(1000), + c6: z.string().transform(Number), + }, + table: { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }, + }); + const expected = z.object({ + c1: integerSchema.nullable(), + c2: integerSchema.max(1000).nullable(), + c3: z.string().transform(Number), + nested: z.object({ + c4: integerSchema.nullable(), + c5: integerSchema.max(1000).nullable(), + c6: z.string().transform(Number), + }), + table: z.object({ + c1: integerSchema.nullable(), + c2: integerSchema.max(1000).nullable(), + c3: z.string().transform(Number), + c4: integerSchema.nullable(), + c5: integerSchema.nullable(), + c6: integerSchema.nullable(), + }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users select schema w/ defaults', (t) => { - const actual = createSelectSchema(users); +test('all data types', (t) => { + const table = pgTable('test', ({ + bigint, + bigserial, + bit, + boolean, + date, + char, + cidr, + doublePrecision, + geometry, + halfvec, + inet, + integer, + interval, + json, + jsonb, + line, + macaddr, + macaddr8, + numeric, + point, + real, + serial, + smallint, + smallserial, + text, + sparsevec, + time, + timestamp, + uuid, + varchar, + vector, + }) => ({ + bigint1: bigint({ mode: 'number' }).notNull(), + bigint2: bigint({ mode: 'bigint' }).notNull(), + bigserial1: bigserial({ mode: 'number' }).notNull(), + bigserial2: bigserial({ mode: 'bigint' }).notNull(), + bit: bit({ dimensions: 5 }).notNull(), + boolean: boolean().notNull(), + date1: date({ mode: 'date' }).notNull(), + date2: date({ mode: 'string' }).notNull(), + char1: char({ length: 10 }).notNull(), + char2: char({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + cidr: cidr().notNull(), + doublePrecision: doublePrecision().notNull(), + geometry1: geometry({ type: 'point', mode: 'tuple' }).notNull(), + geometry2: geometry({ type: 'point', mode: 'xy' }).notNull(), + halfvec: halfvec({ dimensions: 3 }).notNull(), + inet: inet().notNull(), + integer: integer().notNull(), + interval: interval().notNull(), + json: json().notNull(), + jsonb: jsonb().notNull(), + line1: line({ mode: 'abc' }).notNull(), + line2: line({ mode: 'tuple' }).notNull(), + macaddr: macaddr().notNull(), + macaddr8: macaddr8().notNull(), + numeric: numeric().notNull(), + point1: point({ mode: 'xy' }).notNull(), + point2: point({ mode: 'tuple' }).notNull(), + real: real().notNull(), + serial: serial().notNull(), + smallint: smallint().notNull(), + smallserial: smallserial().notNull(), + text1: text().notNull(), + text2: text({ enum: ['a', 'b', 'c'] }).notNull(), + sparsevec: sparsevec({ dimensions: 3 }).notNull(), + time: time().notNull(), + timestamp1: timestamp({ mode: 'date' }).notNull(), + timestamp2: timestamp({ mode: 'string' }).notNull(), + uuid: uuid().notNull(), + varchar1: varchar({ length: 10 }).notNull(), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + vector: vector({ dimensions: 3 }).notNull(), + array1: integer().array().notNull(), + array2: integer().array().array(2).notNull(), + array3: varchar({ length: 10 }).array().array(2).notNull(), + })); + const result = createSelectSchema(table); const expected = z.object({ - a: z.array(z.number()).nullable(), - id: z.number(), - name: z.string().nullable(), - email: z.string(), - birthdayString: z.string(), - birthdayDate: z.date(), - createdAt: z.date(), - role: z.enum(['admin', 'user']), - roleText: z.enum(['admin', 'user']), - roleText2: z.enum(['admin', 'user']), - profession: z.string().max(20).min(1), - initials: z.string().max(2).min(1), - }); - - expectSchemaShape(t, expected).from(actual); + bigint1: z.number().min(Number.MIN_SAFE_INTEGER).max(Number.MAX_SAFE_INTEGER).int(), + bigint2: z.bigint().min(CONSTANTS.INT64_MIN).max(CONSTANTS.INT64_MAX), + bigserial1: z.number().min(Number.MIN_SAFE_INTEGER).max(Number.MAX_SAFE_INTEGER).int(), + bigserial2: z.bigint().min(CONSTANTS.INT64_MIN).max(CONSTANTS.INT64_MAX), + bit: z.string().regex(/^[01]+$/).max(5), + boolean: z.boolean(), + date1: z.date(), + date2: z.string(), + char1: z.string().length(10), + char2: z.enum(['a', 'b', 'c']), + cidr: z.string(), + doublePrecision: z.number().min(CONSTANTS.INT48_MIN).max(CONSTANTS.INT48_MAX), + geometry1: z.tuple([z.number(), z.number()]), + geometry2: z.object({ x: z.number(), y: z.number() }), + halfvec: z.array(z.number()).length(3), + inet: z.string(), + integer: z.number().min(CONSTANTS.INT32_MIN).max(CONSTANTS.INT32_MAX).int(), + interval: z.string(), + json: jsonSchema, + jsonb: jsonSchema, + line1: z.object({ a: z.number(), b: z.number(), c: z.number() }), + line2: z.tuple([z.number(), z.number(), z.number()]), + macaddr: z.string(), + macaddr8: z.string(), + numeric: z.string(), + point1: z.object({ x: z.number(), y: z.number() }), + point2: z.tuple([z.number(), z.number()]), + real: z.number().min(CONSTANTS.INT24_MIN).max(CONSTANTS.INT24_MAX), + serial: z.number().min(CONSTANTS.INT32_MIN).max(CONSTANTS.INT32_MAX).int(), + smallint: z.number().min(CONSTANTS.INT16_MIN).max(CONSTANTS.INT16_MAX).int(), + smallserial: z.number().min(CONSTANTS.INT16_MIN).max(CONSTANTS.INT16_MAX).int(), + text1: z.string(), + text2: z.enum(['a', 'b', 'c']), + sparsevec: z.string(), + time: z.string(), + timestamp1: z.date(), + timestamp2: z.string(), + uuid: z.string().uuid(), + varchar1: z.string().max(10), + varchar2: z.enum(['a', 'b', 'c']), + vector: z.array(z.number()).length(3), + array1: z.array(integerSchema), + array2: z.array(z.array(integerSchema).length(2)), + array3: z.array(z.array(z.string().max(10)).length(2)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); + +/* Disallow unknown keys in table refinement - select */ { + const table = pgTable('test', { id: integer() }); + // @ts-expect-error + createSelectSchema(table, { unknown: z.string() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = pgTable('test', { id: integer() }); + // @ts-expect-error + createInsertSchema(table, { unknown: z.string() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = pgTable('test', { id: integer() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: z.string() }); +} + +/* Disallow unknown keys in view qb - select */ { + const table = pgTable('test', { id: integer() }); + const view = pgView('test').as((qb) => qb.select().from(table)); + const mView = pgMaterializedView('test').as((qb) => qb.select().from(table)); + const nestedSelect = pgView('test').as((qb) => qb.select({ table }).from(table)); + // @ts-expect-error + createSelectSchema(view, { unknown: z.string() }); + // @ts-expect-error + createSelectSchema(mView, { unknown: z.string() }); + // @ts-expect-error + createSelectSchema(nestedSelect, { table: { unknown: z.string() } }); +} + +/* Disallow unknown keys in view columns - select */ { + const view = pgView('test', { id: integer() }).as(sql``); + const mView = pgView('test', { id: integer() }).as(sql``); + // @ts-expect-error + createSelectSchema(view, { unknown: z.string() }); + // @ts-expect-error + createSelectSchema(mView, { unknown: z.string() }); +} diff --git a/drizzle-zod/tests/sqlite.test.ts b/drizzle-zod/tests/sqlite.test.ts index 5a2c3a04e..45e64bbde 100644 --- a/drizzle-zod/tests/sqlite.test.ts +++ b/drizzle-zod/tests/sqlite.test.ts @@ -1,162 +1,359 @@ -import { blob, integer, numeric, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { expect, test } from 'vitest'; +import { type Equal, sql } from 'drizzle-orm'; +import { int, sqliteTable, sqliteView, text } from 'drizzle-orm/sqlite-core'; +import { test } from 'vitest'; import { z } from 'zod'; -import { createInsertSchema, createSelectSchema, jsonSchema } from '../src'; -import { expectSchemaShape } from './utils.ts'; +import { bufferSchema, jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectSchemaShape } from './utils.ts'; -const blobJsonSchema = z.object({ - foo: z.string(), +const intSchema = z.number().min(Number.MIN_SAFE_INTEGER).max(Number.MAX_SAFE_INTEGER).int(); +const textSchema = z.string(); + +test('table - select', (t) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = z.object({ id: intSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -const users = sqliteTable('users', { - id: integer('id').primaryKey(), - blobJson: blob('blob', { mode: 'json' }).$type>().notNull(), - blobBigInt: blob('blob', { mode: 'bigint' }).notNull(), - numeric: numeric('numeric').notNull(), - createdAt: integer('created_at', { mode: 'timestamp' }).notNull(), - createdAtMs: integer('created_at_ms', { mode: 'timestamp_ms' }).notNull(), - boolean: integer('boolean', { mode: 'boolean' }).notNull(), - real: real('real').notNull(), - text: text('text', { length: 255 }), - role: text('role', { enum: ['admin', 'user'] }).notNull().default('user'), +test('table - insert', (t) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + age: int(), + }); + + const result = createInsertSchema(table); + const expected = z.object({ id: intSchema.optional(), name: textSchema, age: intSchema.nullable().optional() }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -const testUser = { - id: 1, - blobJson: { foo: 'bar' }, - blobBigInt: BigInt(123), - numeric: '123.45', - createdAt: new Date(), - createdAtMs: new Date(), - boolean: true, - real: 123.45, - text: 'foobar', - role: 'admin', -}; - -test('users insert valid user', () => { - const schema = createInsertSchema(users); - - expect(schema.safeParse(testUser).success).toBeTruthy(); +test('table - update', (t) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + age: int(), + }); + + const result = createUpdateSchema(table); + const expected = z.object({ + id: intSchema.optional(), + name: textSchema.optional(), + age: intSchema.nullable().optional(), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('view qb - select', (t) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + }); + const view = sqliteView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + + const result = createSelectSchema(view); + const expected = z.object({ id: intSchema, age: z.any() }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users insert invalid text length', () => { - const schema = createInsertSchema(users); +test('view columns - select', (t) => { + const view = sqliteView('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + }).as(sql``); - expect(schema.safeParse({ ...testUser, text: 'a'.repeat(256) }).success).toBeFalsy(); + const result = createSelectSchema(view); + const expected = z.object({ id: intSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users insert schema', (t) => { - const actual = createInsertSchema(users, { - id: ({ id }) => id.positive(), - blobJson: blobJsonSchema, - role: z.enum(['admin', 'manager', 'user']), +test('view with nested fields - select', (t) => { + const table = sqliteTable('test', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), }); + const view = sqliteView('test').as((qb) => + qb.select({ + id: table.id, + nested: { + name: table.name, + age: sql``.as('age'), + }, + table, + }).from(table) + ); - (() => { - { - createInsertSchema(users, { - // @ts-expect-error (missing property) - foobar: z.number(), - }); - } + const result = createSelectSchema(view); + const expected = z.object({ + id: intSchema, + nested: z.object({ name: textSchema, age: z.any() }), + table: z.object({ id: intSchema, name: textSchema }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); - { - createInsertSchema(users, { - // @ts-expect-error (invalid type) - id: 123, - }); - } +test('nullability - select', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), }); + const result = createSelectSchema(table); const expected = z.object({ - id: z.number().positive().optional(), - blobJson: blobJsonSchema, - blobBigInt: z.bigint(), - numeric: z.string(), - createdAt: z.date(), - createdAtMs: z.date(), - boolean: z.boolean(), - real: z.number(), - text: z.string().nullable().optional(), - role: z.enum(['admin', 'manager', 'user']).optional(), + c1: intSchema.nullable(), + c2: intSchema, + c3: intSchema.nullable(), + c4: intSchema, + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('nullability - insert', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), }); - expectSchemaShape(t, expected).from(actual); + const result = createInsertSchema(table); + const expected = z.object({ + c1: intSchema.nullable().optional(), + c2: intSchema, + c3: intSchema.nullable().optional(), + c4: intSchema.optional(), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users insert schema w/ defaults', (t) => { - const actual = createInsertSchema(users); +test('nullability - update', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + const result = createUpdateSchema(table); const expected = z.object({ - id: z.number().optional(), - blobJson: jsonSchema, - blobBigInt: z.bigint(), - numeric: z.string(), - createdAt: z.date(), - createdAtMs: z.date(), - boolean: z.boolean(), - real: z.number(), - text: z.string().nullable().optional(), - role: z.enum(['admin', 'user']).optional(), + c1: intSchema.nullable().optional(), + c2: intSchema.optional(), + c3: intSchema.nullable().optional(), + c4: intSchema.optional(), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - select', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), }); - expectSchemaShape(t, expected).from(actual); + const result = createSelectSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); + const expected = z.object({ + c1: intSchema.nullable(), + c2: intSchema.max(1000), + c3: z.string().transform(Number), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users select schema', (t) => { - const actual = createSelectSchema(users, { - blobJson: jsonSchema, - role: z.enum(['admin', 'manager', 'user']), +test('refine table - insert', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), }); - (() => { - { - createSelectSchema(users, { - // @ts-expect-error (missing property) - foobar: z.number(), - }); - } + const result = createInsertSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); + const expected = z.object({ + c1: intSchema.nullable().optional(), + c2: intSchema.max(1000), + c3: z.string().transform(Number), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); - { - createSelectSchema(users, { - // @ts-expect-error (invalid type) - id: 123, - }); - } +test('refine table - update', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), }); + const result = createUpdateSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); const expected = z.object({ - id: z.number(), - blobJson: jsonSchema, - blobBigInt: z.bigint(), - numeric: z.string(), - createdAt: z.date(), - createdAtMs: z.date(), - boolean: z.boolean(), - real: z.number(), - text: z.string().nullable(), - role: z.enum(['admin', 'manager', 'user']), - }).required(); - - expectSchemaShape(t, expected).from(actual); + c1: intSchema.nullable().optional(), + c2: intSchema.max(1000).optional(), + c3: z.string().transform(Number), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); -test('users select schema w/ defaults', (t) => { - const actual = createSelectSchema(users); +test('refine view - select', (t) => { + const table = sqliteTable('test', { + c1: int(), + c2: int(), + c3: int(), + c4: int(), + c5: int(), + c6: int(), + }); + const view = sqliteView('test').as((qb) => + qb.select({ + c1: table.c1, + c2: table.c2, + c3: table.c3, + nested: { + c4: table.c4, + c5: table.c5, + c6: table.c6, + }, + table, + }).from(table) + ); + const result = createSelectSchema(view, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + nested: { + c5: (schema) => schema.max(1000), + c6: z.string().transform(Number), + }, + table: { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }, + }); + const expected = z.object({ + c1: intSchema.nullable(), + c2: intSchema.max(1000).nullable(), + c3: z.string().transform(Number), + nested: z.object({ + c4: intSchema.nullable(), + c5: intSchema.max(1000).nullable(), + c6: z.string().transform(Number), + }), + table: z.object({ + c1: intSchema.nullable(), + c2: intSchema.max(1000).nullable(), + c3: z.string().transform(Number), + c4: intSchema.nullable(), + c5: intSchema.nullable(), + c6: intSchema.nullable(), + }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('all data types', (t) => { + const table = sqliteTable('test', ({ + blob, + integer, + numeric, + real, + text, + }) => ({ + blob1: blob({ mode: 'buffer' }).notNull(), + blob2: blob({ mode: 'bigint' }).notNull(), + blob3: blob({ mode: 'json' }).notNull(), + integer1: integer({ mode: 'number' }).notNull(), + integer2: integer({ mode: 'boolean' }).notNull(), + integer3: integer({ mode: 'timestamp' }).notNull(), + integer4: integer({ mode: 'timestamp_ms' }).notNull(), + numeric: numeric().notNull(), + real: real().notNull(), + text1: text({ mode: 'text' }).notNull(), + text2: text({ mode: 'text', length: 10 }).notNull(), + text3: text({ mode: 'text', enum: ['a', 'b', 'c'] }).notNull(), + text4: text({ mode: 'json' }).notNull(), + })); + + const result = createSelectSchema(table); const expected = z.object({ - id: z.number(), - blobJson: jsonSchema, - blobBigInt: z.bigint(), + blob1: bufferSchema, + blob2: z.bigint().min(CONSTANTS.INT64_MIN).max(CONSTANTS.INT64_MAX), + blob3: jsonSchema, + integer1: z.number().min(Number.MIN_SAFE_INTEGER).max(Number.MAX_SAFE_INTEGER).int(), + integer2: z.boolean(), + integer3: z.date(), + integer4: z.date(), numeric: z.string(), - createdAt: z.date(), - createdAtMs: z.date(), - boolean: z.boolean(), - real: z.number(), - text: z.string().nullable(), - role: z.enum(['admin', 'user']), - }).required(); - - expectSchemaShape(t, expected).from(actual); + real: z.number().min(CONSTANTS.INT48_MIN).max(CONSTANTS.INT48_MAX), + text1: z.string(), + text2: z.string().max(10), + text3: z.enum(['a', 'b', 'c']), + text4: jsonSchema, + }); + expectSchemaShape(t, expected).from(result); + Expect>(); }); + +/* Disallow unknown keys in table refinement - select */ { + const table = sqliteTable('test', { id: int() }); + // @ts-expect-error + createSelectSchema(table, { unknown: z.string() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = sqliteTable('test', { id: int() }); + // @ts-expect-error + createInsertSchema(table, { unknown: z.string() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = sqliteTable('test', { id: int() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: z.string() }); +} + +/* Disallow unknown keys in view qb - select */ { + const table = sqliteTable('test', { id: int() }); + const view = sqliteView('test').as((qb) => qb.select().from(table)); + const nestedSelect = sqliteView('test').as((qb) => qb.select({ table }).from(table)); + // @ts-expect-error + createSelectSchema(view, { unknown: z.string() }); + // @ts-expect-error + createSelectSchema(nestedSelect, { table: { unknown: z.string() } }); +} + +/* Disallow unknown keys in view columns - select */ { + const view = sqliteView('test', { id: int() }).as(sql``); + // @ts-expect-error + createSelectSchema(view, { unknown: z.string() }); +} diff --git a/drizzle-zod/tests/utils.ts b/drizzle-zod/tests/utils.ts index 1c28be260..6a36f66c5 100644 --- a/drizzle-zod/tests/utils.ts +++ b/drizzle-zod/tests/utils.ts @@ -1,13 +1,14 @@ import { expect, type TaskContext } from 'vitest'; import type { z } from 'zod'; -export function expectSchemaShape(t: TaskContext, expected: z.ZodObject) { +export function expectSchemaShape>(t: TaskContext, expected: T) { return { - from(actual: z.ZodObject) { + from(actual: T) { expect(Object.keys(actual.shape)).toStrictEqual(Object.keys(expected.shape)); for (const key of Object.keys(actual.shape)) { expect(actual.shape[key]!._def.typeName).toStrictEqual(expected.shape[key]?._def.typeName); + expect(actual.shape[key]!._def?.checks).toEqual(expected.shape[key]?._def?.checks); if (actual.shape[key]?._def.typeName === 'ZodOptional') { expect(actual.shape[key]!._def.innerType._def.typeName).toStrictEqual( actual.shape[key]!._def.innerType._def.typeName, @@ -17,3 +18,13 @@ export function expectSchemaShape(t: TaskContext, expec }, }; } + +export function expectEnumValues>(t: TaskContext, expected: T) { + return { + from(actual: T) { + expect(actual._def.values).toStrictEqual(expected._def.values); + }, + }; +} + +export function Expect<_ extends true>() {} diff --git a/drizzle-zod/tsconfig.build.json b/drizzle-zod/tsconfig.build.json index 3377281ba..1af9f8b40 100644 --- a/drizzle-zod/tsconfig.build.json +++ b/drizzle-zod/tsconfig.build.json @@ -1,7 +1,8 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "rootDir": "src" + "rootDir": "src", + "stripInternal": true }, "include": ["src"] } diff --git a/drizzle-zod/tsconfig.json b/drizzle-zod/tsconfig.json index 038d79591..c25379c37 100644 --- a/drizzle-zod/tsconfig.json +++ b/drizzle-zod/tsconfig.json @@ -4,6 +4,7 @@ "outDir": "dist", "baseUrl": ".", "declaration": true, + "noEmit": true, "paths": { "~/*": ["src/*"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7c4b13880..a267d4379 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -502,15 +502,12 @@ importers: drizzle-typebox: devDependencies: - '@rollup/plugin-terser': - specifier: ^0.4.1 - version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 version: 11.1.1(rollup@3.27.2)(tslib@2.8.1)(typescript@5.6.3) '@sinclair/typebox': - specifier: ^0.29.6 - version: 0.29.6 + specifier: ^0.34.8 + version: 0.34.10 '@types/node': specifier: ^18.15.10 version: 18.15.10 @@ -538,9 +535,6 @@ importers: drizzle-valibot: devDependencies: - '@rollup/plugin-terser': - specifier: ^0.4.1 - version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 version: 11.1.1(rollup@3.27.2)(tslib@2.8.1)(typescript@5.6.3) @@ -560,8 +554,8 @@ importers: specifier: ^3.20.7 version: 3.27.2 valibot: - specifier: ^0.30.0 - version: 0.30.0 + specifier: 1.0.0-beta.7 + version: 1.0.0-beta.7(typescript@5.6.3) vite-tsconfig-paths: specifier: ^4.3.2 version: 4.3.2(typescript@5.6.3)(vite@5.3.3(@types/node@18.15.10)(lightningcss@1.25.1)(terser@5.31.0)) @@ -574,9 +568,6 @@ importers: drizzle-zod: devDependencies: - '@rollup/plugin-terser': - specifier: ^0.4.1 - version: 0.4.1(rollup@3.20.7) '@rollup/plugin-typescript': specifier: ^11.1.0 version: 11.1.0(rollup@3.20.7)(tslib@2.8.1)(typescript@5.6.3) @@ -3182,9 +3173,6 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.3': - resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==} - '@jridgewell/source-map@0.3.6': resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} @@ -3523,15 +3511,6 @@ packages: resolution: {integrity: sha512-lzD84av1ZQhYUS+jsGqJiCMaJO2dn9u+RTT9n9q6D3SaKVwWqv+7AoRKqBu19bkwyE+iFRl1ymr40QS90jVFYg==} engines: {node: '>=14.15'} - '@rollup/plugin-terser@0.4.1': - resolution: {integrity: sha512-aKS32sw5a7hy+fEXVy+5T95aDIwjpGHCTv833HXVtyKMDoVS7pBr5K3L9hEQoNqbJFjfANPrNpIXlTQ7is00eA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.x || ^3.x - peerDependenciesMeta: - rollup: - optional: true - '@rollup/plugin-terser@0.4.4': resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} engines: {node: '>=14.0.0'} @@ -3783,8 +3762,8 @@ packages: '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - '@sinclair/typebox@0.29.6': - resolution: {integrity: sha512-aX5IFYWlMa7tQ8xZr3b2gtVReCvg7f3LEhjir/JAjX2bJCMVJA5tIPv30wTD4KDfcwMd7DDYY3hFDeGmOgtrZQ==} + '@sinclair/typebox@0.34.10': + resolution: {integrity: sha512-bJ3mIrYjEwenwwt+xAUq3GnOf1O4r2sApPzmfmF90XYMiKxjDzFSWSpWxqzSlQq3pCXuHP2UPxVPKeUFGJxb+A==} '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} @@ -4642,11 +4621,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - acorn@8.8.2: - resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} - engines: {node: '>=0.4.0'} - hasBin: true - agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -9215,9 +9189,6 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - smob@0.0.6: - resolution: {integrity: sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw==} - smob@1.5.0: resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} @@ -9550,11 +9521,6 @@ packages: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} engines: {node: '>=8'} - terser@5.17.1: - resolution: {integrity: sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==} - engines: {node: '>=10'} - hasBin: true - terser@5.31.0: resolution: {integrity: sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==} engines: {node: '>=10'} @@ -10070,8 +10036,13 @@ packages: v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - valibot@0.30.0: - resolution: {integrity: sha512-5POBdbSkM+3nvJ6ZlyQHsggisfRtyT4tVTo1EIIShs6qCdXJnyWU5TJ68vr8iTg5zpOLjXLRiBqNx+9zwZz/rA==} + valibot@1.0.0-beta.7: + resolution: {integrity: sha512-8CsDu3tqyg7quEHMzCOYdQ/d9NlmVQKtd4AlFje6oJpvqo70EIZjSakKIeWltJyNAiUtdtLe0LAk4625gavoeQ==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true valid-url@1.0.9: resolution: {integrity: sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==} @@ -13796,11 +13767,6 @@ snapshots: '@jridgewell/set-array@1.2.1': {} - '@jridgewell/source-map@0.3.3': - dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.18 - '@jridgewell/source-map@0.3.6': dependencies: '@jridgewell/gen-mapping': 0.3.5 @@ -14345,22 +14311,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@rollup/plugin-terser@0.4.1(rollup@3.20.7)': - dependencies: - serialize-javascript: 6.0.1 - smob: 0.0.6 - terser: 5.17.1 - optionalDependencies: - rollup: 3.20.7 - - '@rollup/plugin-terser@0.4.1(rollup@3.27.2)': - dependencies: - serialize-javascript: 6.0.1 - smob: 0.0.6 - terser: 5.17.1 - optionalDependencies: - rollup: 3.27.2 - '@rollup/plugin-terser@0.4.4(rollup@4.27.3)': dependencies: serialize-javascript: 6.0.1 @@ -14537,7 +14487,7 @@ snapshots: '@sinclair/typebox@0.27.8': {} - '@sinclair/typebox@0.29.6': {} + '@sinclair/typebox@0.34.10': {} '@sindresorhus/is@4.6.0': {} @@ -15766,8 +15716,6 @@ snapshots: acorn@8.11.3: {} - acorn@8.8.2: {} - agent-base@6.0.2: dependencies: debug: 4.3.4 @@ -21036,8 +20984,6 @@ snapshots: smart-buffer@4.2.0: optional: true - smob@0.0.6: {} - smob@1.5.0: {} socks-proxy-agent@6.2.1: @@ -21412,13 +21358,6 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - terser@5.17.1: - dependencies: - '@jridgewell/source-map': 0.3.3 - acorn: 8.8.2 - commander: 2.20.3 - source-map-support: 0.5.21 - terser@5.31.0: dependencies: '@jridgewell/source-map': 0.3.6 @@ -21904,7 +21843,9 @@ snapshots: v8-compile-cache-lib@3.0.1: {} - valibot@0.30.0: {} + valibot@1.0.0-beta.7(typescript@5.6.3): + optionalDependencies: + typescript: 5.6.3 valid-url@1.0.9: {} From 0c27176450bd6e88269d84c1bd5561be22dfe5fc Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Fri, 6 Dec 2024 17:16:26 +0200 Subject: [PATCH 421/492] created export command for drizzle-kit > Command as for now accepts only --sql flag and returns diff between current state and drySchema and logs it to console --- drizzle-kit/src/cli/commands/migrate.ts | 136 +++++++++++++++++++++- drizzle-kit/src/cli/commands/utils.ts | 44 ++++++- drizzle-kit/src/cli/index.ts | 4 +- drizzle-kit/src/cli/schema.ts | 39 +++++++ drizzle-kit/src/cli/validations/common.ts | 4 +- drizzle-kit/tests/cli-export.test.ts | 79 +++++++++++++ 6 files changed, 300 insertions(+), 6 deletions(-) create mode 100644 drizzle-kit/tests/cli-export.test.ts diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 96067c165..279528f11 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -54,7 +54,7 @@ import { ResolveSelectNamed, schema, } from '../views'; -import { GenerateConfig } from './utils'; +import { ExportConfig, GenerateConfig } from './utils'; export type Named = { name: string; @@ -368,6 +368,44 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => { } }; +export const prepareAndExportPg = async (config: ExportConfig) => { + const schemaPath = config.schema; + + try { + const { prev, cur } = await preparePgMigrationSnapshot( + [], // no snapshots before + schemaPath, + undefined, + ); + + const validatedPrev = pgSchema.parse(prev); + const validatedCur = pgSchema.parse(cur); + + const squashedPrev = squashPgScheme(validatedPrev); + const squashedCur = squashPgScheme(validatedCur); + + const { sqlStatements } = await applyPgSnapshotsDiff( + squashedPrev, + squashedCur, + schemasResolver, + enumsResolver, + sequencesResolver, + policyResolver, + indPolicyResolver, + roleResolver, + tablesResolver, + columnsResolver, + viewsResolver, + validatedPrev, + validatedCur, + ); + + console.log(sqlStatements.join('\n')); + } catch (e) { + console.error(e); + } +}; + export const preparePgPush = async ( cur: PgSchema, prev: PgSchema, @@ -697,6 +735,38 @@ export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { } }; +export const prepareAndExportMysql = async (config: ExportConfig) => { + const schemaPath = config.schema; + + try { + const { prev, cur, custom } = await prepareMySqlMigrationSnapshot( + [], + schemaPath, + undefined, + ); + + const validatedPrev = mysqlSchema.parse(prev); + const validatedCur = mysqlSchema.parse(cur); + + const squashedPrev = squashMysqlScheme(validatedPrev); + const squashedCur = squashMysqlScheme(validatedCur); + + const { sqlStatements, statements, _meta } = await applyMysqlSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + mySqlViewsResolver, + validatedPrev, + validatedCur, + ); + + console.log(sqlStatements.join('\n')); + } catch (e) { + console.error(e); + } +}; + export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; @@ -760,6 +830,38 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => { } }; +export const prepareAndExportSqlite = async (config: ExportConfig) => { + const schemaPath = config.schema; + + try { + const { prev, cur } = await prepareSqliteMigrationSnapshot( + [], + schemaPath, + undefined, + ); + + const validatedPrev = sqliteSchema.parse(prev); + const validatedCur = sqliteSchema.parse(cur); + + const squashedPrev = squashSqliteScheme(validatedPrev); + const squashedCur = squashSqliteScheme(validatedCur); + + const { sqlStatements, _meta } = await applySqliteSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + sqliteViewsResolver, + validatedPrev, + validatedCur, + ); + + console.log(sqlStatements.join('\n')); + } catch (e) { + console.error(e); + } +}; + export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => { const outFolder = config.out; const schemaPath = config.schema; @@ -822,6 +924,38 @@ export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => { } }; +export const prepareAndExportLibSQL = async (config: ExportConfig) => { + const schemaPath = config.schema; + + try { + const { prev, cur, custom } = await prepareSqliteMigrationSnapshot( + [], + schemaPath, + undefined, + ); + + const validatedPrev = sqliteSchema.parse(prev); + const validatedCur = sqliteSchema.parse(cur); + + const squashedPrev = squashSqliteScheme(validatedPrev); + const squashedCur = squashSqliteScheme(validatedCur); + + const { sqlStatements, _meta } = await applyLibSQLSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + sqliteViewsResolver, + validatedPrev, + validatedCur, + ); + + console.log(sqlStatements.join('\n')); + } catch (e) { + console.error(e); + } +}; + export const prepareSQLitePush = async ( schemaPath: string | string[], snapshot: SQLiteSchema, diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 60571ad73..cb5c75886 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -135,6 +135,12 @@ export type GenerateConfig = { driver?: Driver; }; +export type ExportConfig = { + dialect: Dialect; + schema: string | string[]; + sql: boolean; +}; + export const prepareGenerateConfig = async ( options: { config?: string; @@ -185,6 +191,38 @@ export const prepareGenerateConfig = async ( }; }; +export const prepareExportConfig = async ( + options: { + config?: string; + schema?: string; + dialect?: Dialect; + sql: boolean; + }, + from: 'config' | 'cli', +): Promise => { + const config = from === 'config' ? await drizzleConfigFromFile(options.config, true) : options; + + const { schema, dialect, sql } = config; + + if (!schema || !dialect) { + console.log(error('Please provide required params:')); + console.log(wrapParam('schema', schema)); + console.log(wrapParam('dialect', dialect)); + process.exit(1); + } + + const fileNames = prepareFilenames(schema); + if (fileNames.length === 0) { + render(`[${chalk.blue('i')}] No schema file in ${schema} was found`); + process.exit(0); + } + return { + dialect: dialect, + schema: schema, + sql: sql, + }; +}; + export const flattenDatabaseCredentials = (config: any) => { if ('dbCredentials' in config) { const { dbCredentials, ...rest } = config; @@ -768,6 +806,7 @@ export const prepareMigrateConfig = async (configPath: string | undefined) => { export const drizzleConfigFromFile = async ( configPath?: string, + isExport?: boolean, ): Promise => { const prefix = process.env.TEST_CONFIG_PATH_PREFIX || ''; @@ -783,7 +822,7 @@ export const drizzleConfigFromFile = async ( ? 'drizzle.config.js' : 'drizzle.config.json'; - if (!configPath) { + if (!configPath && !isExport) { console.log( chalk.gray( `No config path provided, using default '${defaultConfigPath}'`, @@ -798,7 +837,8 @@ export const drizzleConfigFromFile = async ( process.exit(1); } - console.log(chalk.grey(`Reading config file '${path}'`)); + if (!isExport) console.log(chalk.grey(`Reading config file '${path}'`)); + const { unregister } = await safeRegister(); const required = require(`${path}`); const content = required.default ?? required; diff --git a/drizzle-kit/src/cli/index.ts b/drizzle-kit/src/cli/index.ts index 86bffdf3d..42730be1d 100644 --- a/drizzle-kit/src/cli/index.ts +++ b/drizzle-kit/src/cli/index.ts @@ -1,6 +1,6 @@ import { command, run } from '@drizzle-team/brocli'; import chalk from 'chalk'; -import { check, drop, generate, migrate, pull, push, studio, up } from './schema'; +import { check, drop, exportRaw, generate, migrate, pull, push, studio, up } from './schema'; import { ormCoreVersions } from './utils'; const version = async () => { @@ -42,7 +42,7 @@ const legacy = [ legacyCommand('check:sqlite', 'check'), ]; -run([generate, migrate, pull, push, studio, up, check, drop, ...legacy], { +run([generate, migrate, pull, push, studio, up, check, drop, exportRaw, ...legacy], { name: 'drizzle-kit', version: version, }); diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 12153ee74..1a0ff93cd 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -18,6 +18,7 @@ import { upSqliteHandler } from './commands/sqliteUp'; import { prepareCheckParams, prepareDropParams, + prepareExportConfig, prepareGenerateConfig, prepareMigrateConfig, preparePullConfig, @@ -747,3 +748,41 @@ export const studio = command({ } }, }); + +export const exportRaw = command({ + name: 'export', + desc: 'Generate diff between current state and empty state in specified formats: sql', + options: { + sql: boolean('sql').default(true).desc('Generate as sql'), + config: optionConfig, + dialect: optionDialect, + schema: string().desc('Path to a schema file or folder'), + }, + transform: async (opts) => { + const from = assertCollisions('export', opts, ['sql'], ['dialect', 'schema']); + return prepareExportConfig(opts, from); + }, + handler: async (opts) => { + await assertOrmCoreVersion(); + await assertPackages('drizzle-orm'); + + const { prepareAndExportPg, prepareAndExportMysql, prepareAndExportSqlite, prepareAndExportLibSQL } = await import( + './commands/migrate' + ); + + const dialect = opts.dialect; + if (dialect === 'postgresql') { + await prepareAndExportPg(opts); + } else if (dialect === 'mysql') { + await prepareAndExportMysql(opts); + } else if (dialect === 'sqlite') { + await prepareAndExportSqlite(opts); + } else if (dialect === 'turso') { + await prepareAndExportLibSQL(opts); + } else if (dialect === 'singlestore') { + await prepareAndExportSqlite(opts); + } else { + assertUnreachable(dialect); + } + }, +}); diff --git a/drizzle-kit/src/cli/validations/common.ts b/drizzle-kit/src/cli/validations/common.ts index 7fc6046a7..721f6effa 100644 --- a/drizzle-kit/src/cli/validations/common.ts +++ b/drizzle-kit/src/cli/validations/common.ts @@ -10,7 +10,8 @@ export type Commands = | 'check' | 'up' | 'drop' - | 'push'; + | 'push' + | 'export'; type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; type IsUnion = [T] extends [UnionToIntersection] ? false : true; @@ -111,6 +112,7 @@ export const configCommonSchema = object({ migrations: configMigrations, dbCredentials: any().optional(), casing: casingType.optional(), + sql: boolean().default(true), }).passthrough(); export const casing = union([literal('camel'), literal('preserve')]).default( diff --git a/drizzle-kit/tests/cli-export.test.ts b/drizzle-kit/tests/cli-export.test.ts new file mode 100644 index 000000000..663afafcc --- /dev/null +++ b/drizzle-kit/tests/cli-export.test.ts @@ -0,0 +1,79 @@ +import { test as brotest } from '@drizzle-team/brocli'; +import { assert, expect, test } from 'vitest'; +import { exportRaw } from '../src/cli/schema'; + +// good: +// #1 drizzle-kit export --dialect=postgresql --schema=schema.ts +// #3 drizzle-kit export +// #3 drizzle-kit export --config=drizzle1.config.ts + +// errors: +// #1 drizzle-kit export --schema=src/schema.ts +// #2 drizzle-kit export --dialect=postgresql +// #3 drizzle-kit export --dialect=postgresql2 +// #4 drizzle-kit export --config=drizzle.config.ts --schema=schema.ts +// #5 drizzle-kit export --config=drizzle.config.ts --dialect=postgresql + +test('exportRaw #1', async (t) => { + const res = await brotest( + exportRaw, + '--dialect=postgresql --schema=schema.ts', + ); + + if (res.type !== 'handler') assert.fail(res.type, 'handler'); + + expect(res.options).toStrictEqual({ + dialect: 'postgresql', + schema: 'schema.ts', + sql: true, + }); +}); + +test('exportRaw #2', async (t) => { + const res = await brotest(exportRaw, ''); + + if (res.type !== 'handler') assert.fail(res.type, 'handler'); + expect(res.options).toStrictEqual({ + dialect: 'postgresql', + schema: './schema.ts', + sql: true, + }); +}); + +// custom config path +test('exportRaw #3', async (t) => { + const res = await brotest(exportRaw, '--config=expo.config.ts'); + assert.equal(res.type, 'handler'); + if (res.type !== 'handler') assert.fail(res.type, 'handler'); + expect(res.options).toStrictEqual({ + dialect: 'sqlite', + schema: './schema.ts', + sql: true, + }); +}); + +// --- errors --- +test('err #1', async (t) => { + const res = await brotest(exportRaw, '--schema=src/schema.ts'); + assert.equal(res.type, 'error'); +}); + +test('err #2', async (t) => { + const res = await brotest(exportRaw, '--dialect=postgresql'); + assert.equal(res.type, 'error'); +}); + +test('err #3', async (t) => { + const res = await brotest(exportRaw, '--dialect=postgresql2'); + assert.equal(res.type, 'error'); +}); + +test('err #4', async (t) => { + const res = await brotest(exportRaw, '--config=drizzle.config.ts --schema=schema.ts'); + assert.equal(res.type, 'error'); +}); + +test('err #5', async (t) => { + const res = await brotest(exportRaw, '--config=drizzle.config.ts --dialect=postgresql'); + assert.equal(res.type, 'error'); +}); From bccbe17abbac35d3fd788fcbb99095c39272854c Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Fri, 6 Dec 2024 17:45:04 +0200 Subject: [PATCH 422/492] fixes, added tests for cyclic tables seeding --- drizzle-seed/src/index.ts | 11 +- drizzle-seed/src/services/SeedService.ts | 4 +- .../mysql/cyclicTables/cyclicTables.test.ts | 211 ++++++++++++++++++ .../tests/mysql/cyclicTables/mysqlSchema.ts | 76 +++++++ .../pg/cyclicTables/cyclicTables.test.ts | 157 +++++++++++++ .../tests/pg/cyclicTables/pgSchema.ts | 88 ++++++++ drizzle-seed/tests/pg/pg.test.ts | 24 ++ drizzle-seed/tests/pg/pgSchema.ts | 11 +- .../sqlite/cyclicTables/cyclicTables.test.ts | 138 ++++++++++++ .../tests/sqlite/cyclicTables/sqliteSchema.ts | 76 +++++++ 10 files changed, 791 insertions(+), 5 deletions(-) create mode 100644 drizzle-seed/tests/mysql/cyclicTables/cyclicTables.test.ts create mode 100644 drizzle-seed/tests/mysql/cyclicTables/mysqlSchema.ts create mode 100644 drizzle-seed/tests/pg/cyclicTables/cyclicTables.test.ts create mode 100644 drizzle-seed/tests/pg/cyclicTables/pgSchema.ts create mode 100644 drizzle-seed/tests/sqlite/cyclicTables/cyclicTables.test.ts create mode 100644 drizzle-seed/tests/sqlite/cyclicTables/sqliteSchema.ts diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 3e0582e8f..8596863fb 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -663,6 +663,9 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { const isRelationCyclic = ( startRel: RelationWithReferences, ) => { + // self relation + if (startRel.table === startRel.refTable) return false; + // DFS const targetTable = startRel.table; const queue = [startRel]; @@ -865,10 +868,12 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { const isCyclicRelations = relations.map( (relI) => { - // if (relations.some((relj) => reli.table === relj.refTable && reli.refTable === relj.table)) { + const tableRel = tableRelations[relI.table]!.find((relJ) => relJ.refTable === relI.refTable)!; if (isRelationCyclic(relI)) { + tableRel['isCyclic'] = true; return { ...relI, isCyclic: true }; } + tableRel['isCyclic'] = false; return { ...relI, isCyclic: false }; }, ); @@ -1050,10 +1055,12 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { const isCyclicRelations = relations.map( (relI) => { + const tableRel = tableRelations[relI.table]!.find((relJ) => relJ.refTable === relI.refTable)!; if (isRelationCyclic(relI)) { - // if (relations.some((relj) => reli.table === relj.refTable && reli.refTable === relj.table)) { + tableRel['isCyclic'] = true; return { ...relI, isCyclic: true }; } + tableRel['isCyclic'] = false; return { ...relI, isCyclic: false }; }, ); diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 9a5c0e05d..fd8d8d63c 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -1171,8 +1171,8 @@ class SeedService { ? false : true; - preserveData = options?.preserveCyclicTablesData === true - && table.columnsPossibleGenerators.some((colGen) => colGen.isCyclic === true); + preserveData = preserveData || (options?.preserveCyclicTablesData === true + && table.columnsPossibleGenerators.some((colGen) => colGen.isCyclic === true)); tableValues = await this.generateColumnsValuesByGenerators({ tableGenerators, diff --git a/drizzle-seed/tests/mysql/cyclicTables/cyclicTables.test.ts b/drizzle-seed/tests/mysql/cyclicTables/cyclicTables.test.ts new file mode 100644 index 000000000..08fb7a0fe --- /dev/null +++ b/drizzle-seed/tests/mysql/cyclicTables/cyclicTables.test.ts @@ -0,0 +1,211 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import type { MySql2Database } from 'drizzle-orm/mysql2'; +import { drizzle } from 'drizzle-orm/mysql2'; +import getPort from 'get-port'; +import type { Connection } from 'mysql2/promise'; +import { createConnection } from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../../src/index.ts'; +import * as schema from './mysqlSchema.ts'; + +let mysqlContainer: Docker.Container; +let client: Connection; +let db: MySql2Database; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +beforeAll(async () => { + const connectionString = await createDockerDB(); + + const sleep = 1000; + let timeLeft = 40000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + db = drizzle(client); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } + + await db.execute( + sql` + create table model + ( + id int not null + primary key, + name varchar(256) not null, + defaultImageId int null + ); + `, + ); + + await db.execute( + sql` + create table model_image + ( + id int not null + primary key, + url varchar(256) not null, + caption varchar(256) null, + modelId int not null, + constraint model_image_modelId_model_id_fk + foreign key (modelId) references model (id) + ); + `, + ); + + await db.execute( + sql` + alter table model + add constraint model_defaultImageId_model_image_id_fk + foreign key (defaultImageId) references model_image (id); + `, + ); + + // 3 tables case + await db.execute( + sql` + create table model1 + ( + id int not null + primary key, + name varchar(256) not null, + userId int null, + defaultImageId int null + ); + `, + ); + + await db.execute( + sql` + create table model_image1 + ( + id int not null + primary key, + url varchar(256) not null, + caption varchar(256) null, + modelId int not null, + constraint model_image1_modelId_model1_id_fk + foreign key (modelId) references model1 (id) + ); + `, + ); + + await db.execute( + sql` + create table user + ( + id int not null + primary key, + name text null, + invitedBy int null, + imageId int not null, + constraint user_imageId_model_image1_id_fk + foreign key (imageId) references model_image1 (id), + constraint user_invitedBy_user_id_fk + foreign key (invitedBy) references user (id) + ); + `, + ); + + await db.execute( + sql` + alter table model1 + add constraint model1_userId_user_id_fk + foreign key (userId) references user (id); + `, + ); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +test('2 cyclic tables test', async () => { + await seed(db, { + modelTable: schema.modelTable, + modelImageTable: schema.modelImageTable, + }); + + const modelTable = await db.select().from(schema.modelTable); + const modelImageTable = await db.select().from(schema.modelImageTable); + + expect(modelTable.length).toBe(10); + let predicate = modelTable.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + expect(modelImageTable.length).toBe(10); + predicate = modelImageTable.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('3 cyclic tables test', async () => { + await seed(db, { + modelTable1: schema.modelTable1, + modelImageTable1: schema.modelImageTable1, + user: schema.user, + }); + + const modelTable1 = await db.select().from(schema.modelTable1); + const modelImageTable1 = await db.select().from(schema.modelImageTable1); + const user = await db.select().from(schema.user); + + expect(modelTable1.length).toBe(10); + let predicate = modelTable1.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + expect(modelImageTable1.length).toBe(10); + predicate = modelImageTable1.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + expect(user.length).toBe(10); + predicate = user.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); diff --git a/drizzle-seed/tests/mysql/cyclicTables/mysqlSchema.ts b/drizzle-seed/tests/mysql/cyclicTables/mysqlSchema.ts new file mode 100644 index 000000000..ff8149a81 --- /dev/null +++ b/drizzle-seed/tests/mysql/cyclicTables/mysqlSchema.ts @@ -0,0 +1,76 @@ +import { relations } from 'drizzle-orm'; +import type { AnyMySqlColumn } from 'drizzle-orm/mysql-core'; +import { int, mysqlTable, serial, text, varchar } from 'drizzle-orm/mysql-core'; + +// MODEL +export const modelTable = mysqlTable( + 'model', + { + id: serial().primaryKey(), + name: varchar({ length: 256 }).notNull(), + defaultImageId: int().references(() => modelImageTable.id), + }, +); + +export const modelRelations = relations(modelTable, ({ one, many }) => ({ + images: many(modelImageTable), + defaultImage: one(modelImageTable, { + fields: [modelTable.defaultImageId], + references: [modelImageTable.id], + }), +})); + +// MODEL IMAGE +export const modelImageTable = mysqlTable( + 'model_image', + { + id: serial().primaryKey(), + url: varchar({ length: 256 }).notNull(), + caption: varchar({ length: 256 }), + modelId: int() + .notNull() + .references((): AnyMySqlColumn => modelTable.id), + }, +); + +export const modelImageRelations = relations(modelImageTable, ({ one }) => ({ + model: one(modelTable, { + fields: [modelImageTable.modelId], + references: [modelTable.id], + }), +})); + +// 3 tables case +export const modelTable1 = mysqlTable( + 'model1', + { + id: serial().primaryKey(), + name: varchar({ length: 256 }).notNull(), + userId: int() + .references(() => user.id), + defaultImageId: int(), + }, +); + +export const modelImageTable1 = mysqlTable( + 'model_image1', + { + id: serial().primaryKey(), + url: varchar({ length: 256 }).notNull(), + caption: varchar({ length: 256 }), + modelId: int().notNull() + .references((): AnyMySqlColumn => modelTable1.id), + }, +); + +export const user = mysqlTable( + 'user', + { + id: serial().primaryKey(), + name: text(), + invitedBy: int().references((): AnyMySqlColumn => user.id), + imageId: int() + .notNull() + .references((): AnyMySqlColumn => modelImageTable1.id), + }, +); diff --git a/drizzle-seed/tests/pg/cyclicTables/cyclicTables.test.ts b/drizzle-seed/tests/pg/cyclicTables/cyclicTables.test.ts new file mode 100644 index 000000000..c4be3509e --- /dev/null +++ b/drizzle-seed/tests/pg/cyclicTables/cyclicTables.test.ts @@ -0,0 +1,157 @@ +import { PGlite } from '@electric-sql/pglite'; +import { sql } from 'drizzle-orm'; +import type { PgliteDatabase } from 'drizzle-orm/pglite'; +import { drizzle } from 'drizzle-orm/pglite'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../../src/index.ts'; +import * as schema from './pgSchema.ts'; + +let client: PGlite; +let db: PgliteDatabase; + +beforeAll(async () => { + client = new PGlite(); + + db = drizzle(client); + + await db.execute( + sql` + create table model_image + ( + id serial + primary key, + url varchar not null, + caption varchar, + "modelId" integer not null + ); + `, + ); + + await db.execute( + sql` + create table model + ( + id serial + primary key, + name varchar not null, + "defaultImageId" integer + constraint "model_defaultImageId_model_image_id_fk" + references model_image + ); + `, + ); + + await db.execute( + sql` + alter table model_image + add constraint "model_image_modelId_model_id_fk" + foreign key ("modelId") references model; + `, + ); + + // 3 tables case + await db.execute( + sql` + create table model_image1 + ( + id serial + primary key, + url varchar not null, + caption varchar, + "modelId" integer not null + ); + `, + ); + + await db.execute( + sql` + create table "user" + ( + id serial + primary key, + name text, + "invitedBy" integer + constraint "user_invitedBy_user_id_fk" + references "user", + "imageId" integer not null + constraint "user_imageId_model_image1_id_fk" + references model_image1 + ); + `, + ); + + await db.execute( + sql` + create table model1 + ( + id serial + primary key, + name varchar not null, + "userId" integer + constraint "model1_userId_user_id_fk" + references "user", + "defaultImageId" integer + constraint "model1_defaultImageId_model_image1_id_fk" + references model_image1 + ); + `, + ); + + await db.execute( + sql` + alter table model_image1 + add constraint "model_image1_modelId_model1_id_fk" + foreign key ("modelId") references model1; + `, + ); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +afterAll(async () => { + await client.close(); +}); + +test('2 cyclic tables test', async () => { + await seed(db, { + modelTable: schema.modelTable, + modelImageTable: schema.modelImageTable, + }); + + const modelTable = await db.select().from(schema.modelTable); + const modelImageTable = await db.select().from(schema.modelImageTable); + + expect(modelTable.length).toBe(10); + let predicate = modelTable.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + expect(modelImageTable.length).toBe(10); + predicate = modelImageTable.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('3 cyclic tables test', async () => { + await seed(db, { + modelTable1: schema.modelTable1, + modelImageTable1: schema.modelImageTable1, + user: schema.user, + }); + + const modelTable1 = await db.select().from(schema.modelTable1); + const modelImageTable1 = await db.select().from(schema.modelImageTable1); + const user = await db.select().from(schema.user); + + expect(modelTable1.length).toBe(10); + let predicate = modelTable1.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + expect(modelImageTable1.length).toBe(10); + predicate = modelImageTable1.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + expect(user.length).toBe(10); + predicate = user.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); diff --git a/drizzle-seed/tests/pg/cyclicTables/pgSchema.ts b/drizzle-seed/tests/pg/cyclicTables/pgSchema.ts new file mode 100644 index 000000000..7615470b0 --- /dev/null +++ b/drizzle-seed/tests/pg/cyclicTables/pgSchema.ts @@ -0,0 +1,88 @@ +import { relations } from 'drizzle-orm'; +import type { AnyPgColumn } from 'drizzle-orm/pg-core'; +import { foreignKey, integer, pgTable, serial, text, varchar } from 'drizzle-orm/pg-core'; + +// MODEL +export const modelTable = pgTable( + 'model', + { + id: serial().primaryKey(), + name: varchar().notNull(), + defaultImageId: integer(), + }, + (t) => [ + foreignKey({ + columns: [t.defaultImageId], + foreignColumns: [modelImageTable.id], + }), + ], +); + +export const modelRelations = relations(modelTable, ({ one, many }) => ({ + images: many(modelImageTable), + defaultImage: one(modelImageTable, { + fields: [modelTable.defaultImageId], + references: [modelImageTable.id], + }), +})); + +// MODEL IMAGE +export const modelImageTable = pgTable( + 'model_image', + { + id: serial().primaryKey(), + url: varchar().notNull(), + caption: varchar(), + modelId: integer() + .notNull() + .references((): AnyPgColumn => modelTable.id), + }, +); + +export const modelImageRelations = relations(modelImageTable, ({ one }) => ({ + model: one(modelTable, { + fields: [modelImageTable.modelId], + references: [modelTable.id], + }), +})); + +// 3 tables case +export const modelTable1 = pgTable( + 'model1', + { + id: serial().primaryKey(), + name: varchar().notNull(), + userId: integer() + .references(() => user.id), + defaultImageId: integer(), + }, + (t) => [ + foreignKey({ + columns: [t.defaultImageId], + foreignColumns: [modelImageTable1.id], + }), + ], +); + +export const modelImageTable1 = pgTable( + 'model_image1', + { + id: serial().primaryKey(), + url: varchar().notNull(), + caption: varchar(), + modelId: integer().notNull() + .references((): AnyPgColumn => modelTable1.id), + }, +); + +export const user = pgTable( + 'user', + { + id: serial().primaryKey(), + name: text(), + invitedBy: integer().references((): AnyPgColumn => user.id), + imageId: integer() + .notNull() + .references((): AnyPgColumn => modelImageTable1.id), + }, +); diff --git a/drizzle-seed/tests/pg/pg.test.ts b/drizzle-seed/tests/pg/pg.test.ts index 4a945f66d..7054a07c5 100644 --- a/drizzle-seed/tests/pg/pg.test.ts +++ b/drizzle-seed/tests/pg/pg.test.ts @@ -190,6 +190,20 @@ beforeAll(async () => { ); `, ); + + await db.execute( + sql` + create table "seeder_lib_pg"."user" + ( + id serial + primary key, + name text, + "invitedBy" integer + constraint "user_invitedBy_user_id_fk" + references "seeder_lib_pg"."user" + ); + `, + ); }); afterEach(async () => { @@ -361,3 +375,13 @@ test('seeding with identity columns', async () => { expect(result.length).toBe(10); }); + +test('seeding with self relation', async () => { + await seed(db, { user: schema.user }); + + const result = await db.select().from(schema.user); + + expect(result.length).toBe(10); + const predicate = result.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); diff --git a/drizzle-seed/tests/pg/pgSchema.ts b/drizzle-seed/tests/pg/pgSchema.ts index 2c1c95045..f6f4f8347 100644 --- a/drizzle-seed/tests/pg/pgSchema.ts +++ b/drizzle-seed/tests/pg/pgSchema.ts @@ -25,7 +25,7 @@ // }); import type { AnyPgColumn } from 'drizzle-orm/pg-core'; -import { integer, numeric, pgSchema, text, timestamp, varchar } from 'drizzle-orm/pg-core'; +import { integer, numeric, pgSchema, serial, text, timestamp, varchar } from 'drizzle-orm/pg-core'; export const schema = pgSchema('seeder_lib_pg'); @@ -134,3 +134,12 @@ export const identityColumnsTable = schema.table('identity_columns_table', { id1: integer().generatedByDefaultAsIdentity(), name: text(), }); + +export const user = schema.table( + 'user', + { + id: serial().primaryKey(), + name: text(), + invitedBy: integer().references((): AnyPgColumn => user.id), + }, +); diff --git a/drizzle-seed/tests/sqlite/cyclicTables/cyclicTables.test.ts b/drizzle-seed/tests/sqlite/cyclicTables/cyclicTables.test.ts new file mode 100644 index 000000000..d404072eb --- /dev/null +++ b/drizzle-seed/tests/sqlite/cyclicTables/cyclicTables.test.ts @@ -0,0 +1,138 @@ +import BetterSqlite3 from 'better-sqlite3'; +import { sql } from 'drizzle-orm'; +import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../../src/index.ts'; +import * as schema from './sqliteSchema.ts'; + +let client: BetterSqlite3.Database; +let db: BetterSQLite3Database; + +beforeAll(async () => { + client = new BetterSqlite3(':memory:'); + + db = drizzle(client); + + db.run( + sql` + create table model + ( + id integer not null + primary key, + name text not null, + defaultImageId integer, + foreign key (defaultImageId) references model_image + ); + `, + ); + + db.run( + sql` + create table model_image + ( + id integer not null + primary key, + url text not null, + caption text, + modelId integer not null + references model + ); + `, + ); + + // 3 tables case + db.run( + sql` + create table model1 + ( + id integer not null + primary key, + name text not null, + userId integer, + defaultImageId integer, + foreign key (defaultImageId) references model_image1, + foreign key (userId) references user + ); + `, + ); + + db.run( + sql` + create table model_image1 + ( + id integer not null + primary key, + url text not null, + caption text, + modelId integer not null + references model1 + ); + `, + ); + + db.run( + sql` + create table user + ( + id integer not null + primary key, + name text, + invitedBy integer + references user, + imageId integer not null + references model_image1 + ); + `, + ); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +afterAll(async () => { + client.close(); +}); + +test('2 cyclic tables test', async () => { + await seed(db, { + modelTable: schema.modelTable, + modelImageTable: schema.modelImageTable, + }); + + const modelTable = await db.select().from(schema.modelTable); + const modelImageTable = await db.select().from(schema.modelImageTable); + + expect(modelTable.length).toBe(10); + let predicate = modelTable.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + expect(modelImageTable.length).toBe(10); + predicate = modelImageTable.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); + +test('3 cyclic tables test', async () => { + await seed(db, { + modelTable1: schema.modelTable1, + modelImageTable1: schema.modelImageTable1, + user: schema.user, + }); + + const modelTable1 = await db.select().from(schema.modelTable1); + const modelImageTable1 = await db.select().from(schema.modelImageTable1); + const user = await db.select().from(schema.user); + + expect(modelTable1.length).toBe(10); + let predicate = modelTable1.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + expect(modelImageTable1.length).toBe(10); + predicate = modelImageTable1.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + expect(user.length).toBe(10); + predicate = user.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); diff --git a/drizzle-seed/tests/sqlite/cyclicTables/sqliteSchema.ts b/drizzle-seed/tests/sqlite/cyclicTables/sqliteSchema.ts new file mode 100644 index 000000000..c9babadde --- /dev/null +++ b/drizzle-seed/tests/sqlite/cyclicTables/sqliteSchema.ts @@ -0,0 +1,76 @@ +import { relations } from 'drizzle-orm'; +import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import type { AnySQLiteColumn } from 'drizzle-orm/sqlite-core'; + +// MODEL +export const modelTable = sqliteTable( + 'model', + { + id: integer().primaryKey(), + name: text().notNull(), + defaultImageId: integer().references(() => modelImageTable.id), + }, +); + +export const modelRelations = relations(modelTable, ({ one, many }) => ({ + images: many(modelImageTable), + defaultImage: one(modelImageTable, { + fields: [modelTable.defaultImageId], + references: [modelImageTable.id], + }), +})); + +// MODEL IMAGE +export const modelImageTable = sqliteTable( + 'model_image', + { + id: integer().primaryKey(), + url: text().notNull(), + caption: text(), + modelId: integer() + .notNull() + .references((): AnySQLiteColumn => modelTable.id), + }, +); + +export const modelImageRelations = relations(modelImageTable, ({ one }) => ({ + model: one(modelTable, { + fields: [modelImageTable.modelId], + references: [modelTable.id], + }), +})); + +// 3 tables case +export const modelTable1 = sqliteTable( + 'model1', + { + id: integer().primaryKey(), + name: text().notNull(), + userId: integer() + .references(() => user.id), + defaultImageId: integer().references(() => modelImageTable1.id), + }, +); + +export const modelImageTable1 = sqliteTable( + 'model_image1', + { + id: integer().primaryKey(), + url: text().notNull(), + caption: text(), + modelId: integer().notNull() + .references((): AnySQLiteColumn => modelTable1.id), + }, +); + +export const user = sqliteTable( + 'user', + { + id: integer().primaryKey(), + name: text(), + invitedBy: integer().references((): AnySQLiteColumn => user.id), + imageId: integer() + .notNull() + .references((): AnySQLiteColumn => modelImageTable1.id), + }, +); From 6dabeb2f2c208d8478f6c756ca477faa195370f6 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Sun, 8 Dec 2024 18:42:14 +0200 Subject: [PATCH 423/492] Up versions --- changelogs/drizzle-kit/0.30.0.md | 7 +++ changelogs/drizzle-orm/0.38.0.md | 75 +++++++++++++++++++++++++ changelogs/drizzle-typebox/0.2.0.md | 87 +++++++++++++++++++++++++++++ changelogs/drizzle-valibot/0.3.0.md | 67 ++++++++++++++++++++++ changelogs/drizzle-zod/0.6.0.md | 85 ++++++++++++++++++++++++++++ drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- drizzle-typebox/package.json | 2 +- drizzle-valibot/package.json | 2 +- drizzle-zod/package.json | 2 +- 10 files changed, 326 insertions(+), 5 deletions(-) create mode 100644 changelogs/drizzle-kit/0.30.0.md create mode 100644 changelogs/drizzle-orm/0.38.0.md create mode 100644 changelogs/drizzle-typebox/0.2.0.md create mode 100644 changelogs/drizzle-valibot/0.3.0.md create mode 100644 changelogs/drizzle-zod/0.6.0.md diff --git a/changelogs/drizzle-kit/0.30.0.md b/changelogs/drizzle-kit/0.30.0.md new file mode 100644 index 000000000..7accf9c9c --- /dev/null +++ b/changelogs/drizzle-kit/0.30.0.md @@ -0,0 +1,7 @@ +Starting from this update, the PostgreSQL dialect will align with the behavior of all other dialects. It will no longer include `IF NOT EXISTS`, `$DO`, or similar statements, which could cause incorrect DDL statements to not fail when an object already exists in the database and should actually fail. + +This change marks our first step toward several major upgrades we are preparing: + +- An updated and improved migration workflow featuring commutative migrations, a revised folder structure, and enhanced collaboration capabilities for migrations. +- Better support for Xata migrations. +- Compatibility with CockroachDB (achieving full compatibility will only require removing serial fields from the migration folder). \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.38.0.md b/changelogs/drizzle-orm/0.38.0.md new file mode 100644 index 000000000..863fe5182 --- /dev/null +++ b/changelogs/drizzle-orm/0.38.0.md @@ -0,0 +1,75 @@ +# Types breaking changes + +A few internal types were changed and extra generic types for length of column types were added in this release. It won't affect anyone, unless you are using those internal types for some custom wrappers, logic, etc. Here is a list of all types that were changed, so if you are relying on those, please review them before upgrading + +- `MySqlCharBuilderInitial` +- `MySqlVarCharBuilderInitial` +- `PgCharBuilderInitial` +- `PgArrayBuilder` +- `PgArray` +- `PgVarcharBuilderInitial` +- `PgBinaryVectorBuilderInitial` +- `PgBinaryVectorBuilder` +- `PgBinaryVector` +- `PgHalfVectorBuilderInitial` +- `PgHalfVectorBuilder` +- `PgHalfVector` +- `PgVectorBuilderInitial` +- `PgVectorBuilder` +- `PgVector` +- `SQLiteTextBuilderInitial` + +# New Features + +- Added new function `getViewSelectedFields` +- Added `$inferSelect` function to views +- Added `InferSelectViewModel` type for views +- Added `isView` function + +# Validator packages updates + +- `drizzle-zod` has been completely rewritten. You can find detailed information about it [here](https://github.com/drizzle-team/drizzle-orm/blob/main/changelogs/drizzle-zod/0.6.0.md) +- `drizzle-valibot` has been completely rewritten. You can find detailed information about it [here](https://github.com/drizzle-team/drizzle-orm/blob/main/changelogs/drizzle-valibot/0.3.0.md) +- `drizzle-typebox` has been completely rewritten. You can find detailed information about it [here](https://github.com/drizzle-team/drizzle-orm/blob/main/changelogs/drizzle-typebox/0.2.0.md) + +Thanks to @L-Mario564 for making more updates than we expected to be shipped in this release. We'll copy his message from a PR regarding improvements made in this release: + +- Output for all packages are now unminified, makes exploring the compiled code easier when published to npm. +- Smaller footprint. Previously, we imported the column types at runtime for each dialect, meaning that for example, if you're just using Postgres then you'd likely only have drizzle-orm and drizzle-orm/pg-core in the build output of your app; however, these packages imported all dialects which could lead to mysql-core and sqlite-core being bundled as well even if they're unused in your app. This is now fixed. +- Slight performance gain. To determine the column data type we used the is function which performs a few checks to ensure the column data type matches. This was slow, as these checks would pile up every quickly when comparing all data types for many fields in a table/view. The easier and faster alternative is to simply go off of the column's columnType property. +- Some changes had to be made at the type level in the ORM package for better compatibility with drizzle-valibot. + +And a set of new features + +- `createSelectSchema` function now also accepts views and enums. +- New function: `createUpdateSchema`, for use in updating queries. +- New function: `createSchemaFactory`, to provide more advanced options and to avoid bloating the parameters of the other schema functions + +# Bug fixes + +- [[FEATURE]: publish packages un-minified](https://github.com/drizzle-team/drizzle-orm/issues/2247) +- [Don't allow unknown keys in drizzle-zod refinement](https://github.com/drizzle-team/drizzle-orm/issues/573) +- [[BUG]:drizzle-zod not working with pgSchema](https://github.com/drizzle-team/drizzle-orm/issues/1458) +- [Add createUpdateSchema to drizzle-zod](https://github.com/drizzle-team/drizzle-orm/issues/503) +- [[BUG]:drizzle-zod produces wrong type](https://github.com/drizzle-team/drizzle-orm/issues/1110) +- [[BUG]:Drizzle-zod:Boolean and Serial types from Schema are defined as enum when using CreateInsertSchema and CreateSelectSchema](https://github.com/drizzle-team/drizzle-orm/issues/1327) +- [[BUG]: Drizzle typebox enum array wrong schema and type](https://github.com/drizzle-team/drizzle-orm/issues/1345) +- [[BUG]:drizzle-zod not working with pgSchema](https://github.com/drizzle-team/drizzle-orm/issues/1458) +- [[BUG]: drizzle-zod not parsing arrays correctly](https://github.com/drizzle-team/drizzle-orm/issues/1609) +- [[BUG]: Drizzle typebox not supporting array](https://github.com/drizzle-team/drizzle-orm/issues/1810) +- [[FEATURE]: Export factory functions from drizzle-zod to allow usage with extended Zod classes](https://github.com/drizzle-team/drizzle-orm/issues/2245) +- [[FEATURE]: Add support for new pipe syntax for drizzle-valibot](https://github.com/drizzle-team/drizzle-orm/issues/2358) +- [[BUG]: drizzle-zod's createInsertSchema() can't handle column of type vector](https://github.com/drizzle-team/drizzle-orm/issues/2424) +- [[BUG]: drizzle-typebox fails to map geometry column to type-box schema](https://github.com/drizzle-team/drizzle-orm/issues/2516) +- [[BUG]: drizzle-valibot does not provide types for returned schemas](https://github.com/drizzle-team/drizzle-orm/issues/2521) +- [[BUG]: Drizzle-typebox types SQLite real field to string](https://github.com/drizzle-team/drizzle-orm/issues/2524) +- [[BUG]: drizzle-zod: documented usage generates type error with exactOptionalPropertyTypes](https://github.com/drizzle-team/drizzle-orm/issues/2550) +- [[BUG]: drizzle-zod does not respect/count db type range](https://github.com/drizzle-team/drizzle-orm/issues/2737) +- [[BUG]: drizzle-zod not overriding optional](https://github.com/drizzle-team/drizzle-orm/issues/2755) +- [[BUG]:drizzle-zod doesn't accept custom id value](https://github.com/drizzle-team/drizzle-orm/issues/2957) +- [[FEATURE]: Support for Database Views in Drizzle Zod](https://github.com/drizzle-team/drizzle-orm/issues/3398) +- [[BUG]: drizzle-valibot return type any](https://github.com/drizzle-team/drizzle-orm/issues/3621) +- [[BUG]: drizzle-zod Type generation results in undefined types](https://github.com/drizzle-team/drizzle-orm/issues/3645) +- [[BUG]: GeneratedAlwaysAs](https://github.com/drizzle-team/drizzle-orm/issues/3511) +- [[FEATURE]: $inferSelect on a view](https://github.com/drizzle-team/drizzle-orm/issues/2610) +- [[BUG]:Can't infer props from view in schema](https://github.com/drizzle-team/drizzle-orm/issues/3392) diff --git a/changelogs/drizzle-typebox/0.2.0.md b/changelogs/drizzle-typebox/0.2.0.md new file mode 100644 index 000000000..aad630f7a --- /dev/null +++ b/changelogs/drizzle-typebox/0.2.0.md @@ -0,0 +1,87 @@ +This version fully updates `drizzle-typebox` integration and makes sure it's compatible with newer typebox versions + +# Breaking Changes + +> You must also have Drizzle ORM v0.38.0 or greater and Typebox v0.34.8 or greater installed. + +- When refining a field, if a schema is provided instead of a callback function, it will ignore the field's nullability and optional status. +- Some data types have more specific schemas for improved validation + +# Improvements + +Thanks to @L-Mario564 for making more updates than we expected to be shipped in this release. We'll copy his message from a PR regarding improvements made in this release: + +- Output for all packages are now unminified, makes exploring the compiled code easier when published to npm. +- Smaller footprint. Previously, we imported the column types at runtime for each dialect, meaning that for example, if you're just using Postgres then you'd likely only have drizzle-orm and drizzle-orm/pg-core in the build output of your app; however, these packages imported all dialects which could lead to mysql-core and sqlite-core being bundled as well even if they're unused in your app. This is now fixed. +- Slight performance gain. To determine the column data type we used the is function which performs a few checks to ensure the column data type matches. This was slow, as these checks would pile up every quickly when comparing all data types for many fields in a table/view. The easier and faster alternative is to simply go off of the column's columnType property. + +# New features + +- `createSelectSchema` function now also accepts views and enums. + +```ts +import { pgEnum } from 'drizzle-orm/pg-core'; +import { createSelectSchema } from 'drizzle-typebox'; +import { Value } from '@sinclair/typebox/value'; + +const roles = pgEnum('roles', ['admin', 'basic']); +const rolesSchema = createSelectSchema(roles); +const parsed: 'admin' | 'basic' = Value.Parse(rolesSchema, ...); + +const usersView = pgView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18))); +const usersViewSchema = createSelectSchema(usersView); +const parsed: { id: number; name: string; age: number } = Value.Parse(usersViewSchema, ...); +``` + +- New function: `createUpdateSchema`, for use in updating queries. + +```ts copy +import { pgTable, text, integer } from 'drizzle-orm/pg-core'; +import { createUpdateSchema } from 'drizzle-typebox'; +import { Value } from '@sinclair/typebox/value'; + +const users = pgTable('users', { + id: integer().generatedAlwaysAsIdentity().primaryKey(), + name: text().notNull(), + age: integer().notNull() +}); + +const userUpdateSchema = createUpdateSchema(users); + +const user = { id: 5, name: 'John' }; +const parsed: { name?: string | undefined, age?: number | undefined } = Value.Parse(userUpdateSchema, user); // Error: `id` is a generated column, it can't be updated + +const user = { age: 35 }; +const parsed: { name?: string | undefined, age?: number | undefined } = Value.Parse(userUpdateSchema, user); // Will parse successfully +await db.update(users).set(parsed).where(eq(users.name, 'Jane')); +``` + +- New function: `createSchemaFactory`, to provide more advanced options and to avoid bloating the parameters of the other schema functions + +```ts copy +import { pgTable, text, integer } from 'drizzle-orm/pg-core'; +import { createSchemaFactory } from 'drizzle-typebox'; +import { t } from 'elysia'; // Extended Typebox instance + +const users = pgTable('users', { + id: integer().generatedAlwaysAsIdentity().primaryKey(), + name: text().notNull(), + age: integer().notNull() +}); + +const { createInsertSchema } = createSchemaFactory({ typeboxInstance: t }); + +const userInsertSchema = createInsertSchema(users, { + // We can now use the extended instance + name: (schema) => t.Number({ ...schema }, { error: '`name` must be a string' }) +}); +``` + +- Full support for PG arrays + +```ts +pg.dataType().array(...); + +// Schema +Type.Array(baseDataTypeSchema, { minItems: size, maxItems: size }); +``` \ No newline at end of file diff --git a/changelogs/drizzle-valibot/0.3.0.md b/changelogs/drizzle-valibot/0.3.0.md new file mode 100644 index 000000000..de8ec63b4 --- /dev/null +++ b/changelogs/drizzle-valibot/0.3.0.md @@ -0,0 +1,67 @@ +This version fully updates `drizzle-valibot` integration and makes sure it's compatible with newer valibot versions + +# Breaking Changes + +> You must also have Drizzle ORM v0.38.0 or greater and Valibot v1.0.0-beta.7 or greater installed. + +- When refining a field, if a schema is provided instead of a callback function, it will ignore the field's nullability and optional status. +- Some data types have more specific schemas for improved validation + +# Improvements + +Thanks to @L-Mario564 for making more updates than we expected to be shipped in this release. We'll copy his message from a PR regarding improvements made in this release: + +- Output for all packages are now unminified, makes exploring the compiled code easier when published to npm. +- Smaller footprint. Previously, we imported the column types at runtime for each dialect, meaning that for example, if you're just using Postgres then you'd likely only have drizzle-orm and drizzle-orm/pg-core in the build output of your app; however, these packages imported all dialects which could lead to mysql-core and sqlite-core being bundled as well even if they're unused in your app. This is now fixed. +- Slight performance gain. To determine the column data type we used the is function which performs a few checks to ensure the column data type matches. This was slow, as these checks would pile up every quickly when comparing all data types for many fields in a table/view. The easier and faster alternative is to simply go off of the column's columnType property. +- Some changes had to be made at the type level in the ORM package for better compatibility with drizzle-valibot. + +# New features + +- `createSelectSchema` function now also accepts views and enums. + +```ts copy +import { pgEnum } from 'drizzle-orm/pg-core'; +import { createSelectSchema } from 'drizzle-valibot'; +import { parse } from 'valibot'; + +const roles = pgEnum('roles', ['admin', 'basic']); +const rolesSchema = createSelectSchema(roles); +const parsed: 'admin' | 'basic' = parse(rolesSchema, ...); + +const usersView = pgView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18))); +const usersViewSchema = createSelectSchema(usersView); +const parsed: { id: number; name: string; age: number } = parse(usersViewSchema, ...); +``` + +- New function: `createUpdateSchema`, for use in updating queries. + +```ts copy +import { pgTable, text, integer } from 'drizzle-orm/pg-core'; +import { createUpdateSchema } from 'drizzle-valibot'; +import { parse } from 'valibot'; + +const users = pgTable('users', { + id: integer().generatedAlwaysAsIdentity().primaryKey(), + name: text().notNull(), + age: integer().notNull() +}); + +const userUpdateSchema = createUpdateSchema(users); + +const user = { id: 5, name: 'John' }; +const parsed: { name?: string | undefined, age?: number | undefined } = parse(userUpdateSchema, user); // Error: `id` is a generated column, it can't be updated + +const user = { age: 35 }; +const parsed: { name?: string | undefined, age?: number | undefined } = parse(userUpdateSchema, user); // Will parse successfully +await db.update(users).set(parsed).where(eq(users.name, 'Jane')); +``` + +- Full support for PG arrays + +```ts +pg.dataType().array(...); + +// Schema +z.array(baseDataTypeSchema).length(size); +``` \ No newline at end of file diff --git a/changelogs/drizzle-zod/0.6.0.md b/changelogs/drizzle-zod/0.6.0.md new file mode 100644 index 000000000..31ffd4fdb --- /dev/null +++ b/changelogs/drizzle-zod/0.6.0.md @@ -0,0 +1,85 @@ +This version fully updates `drizzle-zod` integration and makes sure it's compatible with newer zod versions + +# Breaking Changes + +> You must also have Drizzle ORM v0.38.0 or greater and Zod v3.0.0 or greater installed. + +- When refining a field, if a schema is provided instead of a callback function, it will ignore the field's nullability and optional status. +- Some data types have more specific schemas for improved validation + +# Improvements + +Thanks to @L-Mario564 for making more updates than we expected to be shipped in this release. We'll copy his message from a PR regarding improvements made in this release: + +- Output for all packages are now unminified, makes exploring the compiled code easier when published to npm. +- Smaller footprint. Previously, we imported the column types at runtime for each dialect, meaning that for example, if you're just using Postgres then you'd likely only have drizzle-orm and drizzle-orm/pg-core in the build output of your app; however, these packages imported all dialects which could lead to mysql-core and sqlite-core being bundled as well even if they're unused in your app. This is now fixed. +- Slight performance gain. To determine the column data type we used the is function which performs a few checks to ensure the column data type matches. This was slow, as these checks would pile up every quickly when comparing all data types for many fields in a table/view. The easier and faster alternative is to simply go off of the column's columnType property. + +# New features + +- `createSelectSchema` function now also accepts views and enums. + +```ts copy +import { pgEnum } from 'drizzle-orm/pg-core'; +import { createSelectSchema } from 'drizzle-zod'; + +const roles = pgEnum('roles', ['admin', 'basic']); +const rolesSchema = createSelectSchema(roles); +const parsed: 'admin' | 'basic' = rolesSchema.parse(...); + +const usersView = pgView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18))); +const usersViewSchema = createSelectSchema(usersView); +const parsed: { id: number; name: string; age: number } = usersViewSchema.parse(...); +``` + +- New function: `createUpdateSchema`, for use in updating queries. + +```ts copy +import { pgTable, text, integer } from 'drizzle-orm/pg-core'; +import { createUpdateSchema } from 'drizzle-zod'; + +const users = pgTable('users', { + id: integer().generatedAlwaysAsIdentity().primaryKey(), + name: text().notNull(), + age: integer().notNull() +}); + +const userUpdateSchema = createUpdateSchema(users); + +const user = { id: 5, name: 'John' }; +const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema.parse(user); // Error: `id` is a generated column, it can't be updated + +const user = { age: 35 }; +const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema.parse(user); // Will parse successfully +await db.update(users).set(parsed).where(eq(users.name, 'Jane')); +``` + +- New function: `createSchemaFactory`, to provide more advanced options and to avoid bloating the parameters of the other schema functions + +```ts copy +import { pgTable, text, integer } from 'drizzle-orm/pg-core'; +import { createSchemaFactory } from 'drizzle-zod'; +import { z } from '@hono/zod-openapi'; // Extended Zod instance + +const users = pgTable('users', { + id: integer().generatedAlwaysAsIdentity().primaryKey(), + name: text().notNull(), + age: integer().notNull() +}); + +const { createInsertSchema } = createSchemaFactory({ zodInstance: z }); + +const userInsertSchema = createInsertSchema(users, { + // We can now use the extended instance + name: (schema) => schema.openapi({ example: 'John' }) +}); +``` + +- Full support for PG arrays + +```ts +pg.dataType().array(...); + +// Schema +z.array(baseDataTypeSchema).length(size); +``` \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index eca469d9b..7d3debd1f 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.29.0", + "version": "0.30.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 3fa8e4bc3..c7528fdbe 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.37.0", + "version": "0.38.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { diff --git a/drizzle-typebox/package.json b/drizzle-typebox/package.json index 25461ad15..a6c34fc69 100644 --- a/drizzle-typebox/package.json +++ b/drizzle-typebox/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-typebox", - "version": "0.1.1", + "version": "0.2.0", "description": "Generate Typebox schemas from Drizzle ORM schemas", "type": "module", "scripts": { diff --git a/drizzle-valibot/package.json b/drizzle-valibot/package.json index 9d14c39b9..c9e6a02e9 100644 --- a/drizzle-valibot/package.json +++ b/drizzle-valibot/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-valibot", - "version": "0.2.0", + "version": "0.3.0", "description": "Generate valibot schemas from Drizzle ORM schemas", "type": "module", "scripts": { diff --git a/drizzle-zod/package.json b/drizzle-zod/package.json index d4ed4407c..ebbec398e 100644 --- a/drizzle-zod/package.json +++ b/drizzle-zod/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-zod", - "version": "0.5.1", + "version": "0.6.0", "description": "Generate Zod schemas from Drizzle ORM schemas", "type": "module", "scripts": { From 734021d976d35f73fb58689cf82d4b1b3afe87f1 Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Sun, 8 Dec 2024 18:44:05 +0200 Subject: [PATCH 424/492] Fixed `.mock` in postgres-js --- drizzle-orm/src/postgres-js/driver.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index b6043f187..69d5a126d 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -119,6 +119,11 @@ export namespace drizzle { ): PostgresJsDatabase & { $client: '$client is not available on drizzle.mock()'; } { - return construct({} as any, config) as any; + return construct({ + options: { + parsers: {}, + serializers: {}, + }, + } as any, config) as any; } } From 3256029b5e65fbd6f9fc716f2da4aa2498bf8205 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 9 Dec 2024 11:22:39 +0200 Subject: [PATCH 425/492] Update 3rd param for all dialects --- drizzle-orm/src/mysql-core/table.ts | 93 +++++++++++++++++-- drizzle-orm/src/mysql-core/utils.ts | 3 +- drizzle-orm/src/pg-core/table.ts | 42 ++++++++- drizzle-orm/src/singlestore-core/table.ts | 87 ++++++++++++++++- drizzle-orm/src/singlestore-core/utils.ts | 3 +- drizzle-orm/src/sqlite-core/table.ts | 89 +++++++++++++++++- drizzle-orm/src/sqlite-core/utils.ts | 3 +- integration-tests/tests/mysql/mysql-common.ts | 32 +++++++ .../tests/singlestore/singlestore-common.ts | 32 +++++++ .../tests/sqlite/sqlite-common.ts | 29 ++++++ 10 files changed, 394 insertions(+), 19 deletions(-) diff --git a/drizzle-orm/src/mysql-core/table.ts b/drizzle-orm/src/mysql-core/table.ts index e09278dc5..c3d3e581a 100644 --- a/drizzle-orm/src/mysql-core/table.ts +++ b/drizzle-orm/src/mysql-core/table.ts @@ -9,13 +9,16 @@ import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; -export type MySqlTableExtraConfig = Record< - string, +export type MySqlTableExtraConfigValue = | AnyIndexBuilder | CheckBuilder | ForeignKeyBuilder | PrimaryKeyBuilder - | UniqueConstraintBuilder + | UniqueConstraintBuilder; + +export type MySqlTableExtraConfig = Record< + string, + MySqlTableExtraConfigValue >; export type TableConfig = TableConfigBase; @@ -62,7 +65,11 @@ export function mysqlTableWithSchema< >( name: TTableName, columns: TColumnsMap | ((columnTypes: MySqlColumnBuilders) => TColumnsMap), - extraConfig: ((self: BuildColumns) => MySqlTableExtraConfig) | undefined, + extraConfig: + | (( + self: BuildColumns, + ) => MySqlTableExtraConfig | MySqlTableExtraConfigValue[]) + | undefined, schema: TSchemaName, baseName = name, ): MySqlTableWithColumns<{ @@ -109,13 +116,87 @@ export function mysqlTableWithSchema< } export interface MySqlTableFn { + /** + * @deprecated The third parameter of mysqlTable is changing and will only accept an array instead of an object + * + * @example + * Deprecated version: + * ```ts + * export const users = mysqlTable("users", { + * id: int(), + * }, (t) => ({ + * idx: index('custom_name').on(t.id) + * })); + * ``` + * + * New API: + * ```ts + * export const users = mysqlTable("users", { + * id: int(), + * }, (t) => [ + * index('custom_name').on(t.id) + * ]); + * ``` + */ + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: TColumnsMap, + extraConfig: (self: BuildColumns) => MySqlTableExtraConfig, + ): MySqlTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'mysql'; + }>; + + /** + * @deprecated The third parameter of mysqlTable is changing and will only accept an array instead of an object + * + * @example + * Deprecated version: + * ```ts + * export const users = mysqlTable("users", { + * id: int(), + * }, (t) => ({ + * idx: index('custom_name').on(t.id) + * })); + * ``` + * + * New API: + * ```ts + * export const users = mysqlTable("users", { + * id: int(), + * }, (t) => [ + * index('custom_name').on(t.id) + * ]); + * ``` + */ + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: MySqlColumnBuilders) => TColumnsMap, + extraConfig: (self: BuildColumns) => MySqlTableExtraConfig, + ): MySqlTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'mysql'; + }>; + < TTableName extends string, TColumnsMap extends Record, >( name: TTableName, columns: TColumnsMap, - extraConfig?: (self: BuildColumns) => MySqlTableExtraConfig, + extraConfig?: ( + self: BuildColumns, + ) => MySqlTableExtraConfigValue[], ): MySqlTableWithColumns<{ name: TTableName; schema: TSchemaName; @@ -129,7 +210,7 @@ export interface MySqlTableFn( name: TTableName, columns: (columnTypes: MySqlColumnBuilders) => TColumnsMap, - extraConfig?: (self: BuildColumns) => MySqlTableExtraConfig, + extraConfig?: (self: BuildColumns) => MySqlTableExtraConfigValue[], ): MySqlTableWithColumns<{ name: TTableName; schema: TSchemaName; diff --git a/drizzle-orm/src/mysql-core/utils.ts b/drizzle-orm/src/mysql-core/utils.ts index f09f65f3e..2cdc68620 100644 --- a/drizzle-orm/src/mysql-core/utils.ts +++ b/drizzle-orm/src/mysql-core/utils.ts @@ -29,7 +29,8 @@ export function getTableConfig(table: MySqlTable) { if (extraConfigBuilder !== undefined) { const extraConfig = extraConfigBuilder(table[MySqlTable.Symbol.Columns]); - for (const builder of Object.values(extraConfig)) { + const extraValues = Array.isArray(extraConfig) ? extraConfig.flat(1) as any[] : Object.values(extraConfig); + for (const builder of Object.values(extraValues)) { if (is(builder, IndexBuilder)) { indexes.push(builder.build(table)); } else if (is(builder, CheckBuilder)) { diff --git a/drizzle-orm/src/pg-core/table.ts b/drizzle-orm/src/pg-core/table.ts index c3c34c577..7f12e634d 100644 --- a/drizzle-orm/src/pg-core/table.ts +++ b/drizzle-orm/src/pg-core/table.ts @@ -135,7 +135,26 @@ export function pgTableWithSchema< export interface PgTableFn { /** - * @deprecated This overload is deprecated. Use the other method overload instead. + * @deprecated The third parameter of pgTable is changing and will only accept an array instead of an object + * + * @example + * Deprecated version: + * ```ts + * export const users = pgTable("users", { + * id: integer(), + * }, (t) => ({ + * idx: index('custom_name').on(t.id) + * })); + * ``` + * + * New API: + * ```ts + * export const users = pgTable("users", { + * id: integer(), + * }, (t) => [ + * index('custom_name').on(t.id) + * ]); + * ``` */ < TTableName extends string, @@ -154,7 +173,26 @@ export interface PgTableFn { }>; /** - * @deprecated This overload is deprecated. Use the other method overload instead. + * @deprecated The third parameter of pgTable is changing and will only accept an array instead of an object + * + * @example + * Deprecated version: + * ```ts + * export const users = pgTable("users", { + * id: integer(), + * }, (t) => ({ + * idx: index('custom_name').on(t.id) + * })); + * ``` + * + * New API: + * ```ts + * export const users = pgTable("users", { + * id: integer(), + * }, (t) => [ + * index('custom_name').on(t.id) + * ]); + * ``` */ < TTableName extends string, diff --git a/drizzle-orm/src/singlestore-core/table.ts b/drizzle-orm/src/singlestore-core/table.ts index 4cc8973ee..ffad22d74 100644 --- a/drizzle-orm/src/singlestore-core/table.ts +++ b/drizzle-orm/src/singlestore-core/table.ts @@ -7,11 +7,14 @@ import type { AnyIndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; -export type SingleStoreTableExtraConfig = Record< - string, +export type SingleStoreTableExtraConfigValue = | AnyIndexBuilder | PrimaryKeyBuilder - | UniqueConstraintBuilder + | UniqueConstraintBuilder; + +export type SingleStoreTableExtraConfig = Record< + string, + SingleStoreTableExtraConfigValue >; export type TableConfig = TableConfigBase; @@ -51,7 +54,9 @@ export function singlestoreTableWithSchema< name: TTableName, columns: TColumnsMap | ((columnTypes: SingleStoreColumnBuilders) => TColumnsMap), extraConfig: - | ((self: BuildColumns) => SingleStoreTableExtraConfig) + | (( + self: BuildColumns, + ) => SingleStoreTableExtraConfig | SingleStoreTableExtraConfigValue[]) | undefined, schema: TSchemaName, baseName = name, @@ -98,6 +103,28 @@ export function singlestoreTableWithSchema< } export interface SingleStoreTableFn { + /** + * @deprecated The third parameter of singlestoreTable is changing and will only accept an array instead of an object + * + * @example + * Deprecated version: + * ```ts + * export const users = singlestoreTable("users", { + * id: int(), + * }, (t) => ({ + * idx: index('custom_name').on(t.id) + * })); + * ``` + * + * New API: + * ```ts + * export const users = singlestoreTable("users", { + * id: int(), + * }, (t) => [ + * index('custom_name').on(t.id) + * ]); + * ``` + */ < TTableName extends string, TColumnsMap extends Record, @@ -112,6 +139,28 @@ export interface SingleStoreTableFn; + /** + * @deprecated The third parameter of singlestoreTable is changing and will only accept an array instead of an object + * + * @example + * Deprecated version: + * ```ts + * export const users = singlestoreTable("users", { + * id: int(), + * }, (t) => ({ + * idx: index('custom_name').on(t.id) + * })); + * ``` + * + * New API: + * ```ts + * export const users = singlestoreTable("users", { + * id: int(), + * }, (t) => [ + * index('custom_name').on(t.id) + * ]); + * ``` + */ < TTableName extends string, TColumnsMap extends Record, @@ -125,6 +174,36 @@ export interface SingleStoreTableFn; dialect: 'singlestore'; }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: TColumnsMap, + extraConfig?: ( + self: BuildColumns, + ) => SingleStoreTableExtraConfigValue[], + ): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: SingleStoreColumnBuilders) => TColumnsMap, + extraConfig?: (self: BuildColumns) => SingleStoreTableExtraConfigValue[], + ): SingleStoreTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'singlestore'; + }>; } export const singlestoreTable: SingleStoreTableFn = (name, columns, extraConfig) => { diff --git a/drizzle-orm/src/singlestore-core/utils.ts b/drizzle-orm/src/singlestore-core/utils.ts index 634b4e261..9ec8b7b0d 100644 --- a/drizzle-orm/src/singlestore-core/utils.ts +++ b/drizzle-orm/src/singlestore-core/utils.ts @@ -22,7 +22,8 @@ export function getTableConfig(table: SingleStoreTable) { if (extraConfigBuilder !== undefined) { const extraConfig = extraConfigBuilder(table[SingleStoreTable.Symbol.Columns]); - for (const builder of Object.values(extraConfig)) { + const extraValues = Array.isArray(extraConfig) ? extraConfig.flat(1) as any[] : Object.values(extraConfig); + for (const builder of Object.values(extraValues)) { if (is(builder, IndexBuilder)) { indexes.push(builder.build(table)); } else if (is(builder, UniqueConstraintBuilder)) { diff --git a/drizzle-orm/src/sqlite-core/table.ts b/drizzle-orm/src/sqlite-core/table.ts index d7c5a060b..5a68f9cb1 100644 --- a/drizzle-orm/src/sqlite-core/table.ts +++ b/drizzle-orm/src/sqlite-core/table.ts @@ -9,13 +9,16 @@ import type { IndexBuilder } from './indexes.ts'; import type { PrimaryKeyBuilder } from './primary-keys.ts'; import type { UniqueConstraintBuilder } from './unique-constraint.ts'; -export type SQLiteTableExtraConfig = Record< - string, +export type SQLiteTableExtraConfigValue = | IndexBuilder | CheckBuilder | ForeignKeyBuilder | PrimaryKeyBuilder - | UniqueConstraintBuilder + | UniqueConstraintBuilder; + +export type SQLiteTableExtraConfig = Record< + string, + SQLiteTableExtraConfigValue >; export type TableConfig = TableConfigBase>; @@ -54,6 +57,28 @@ export type SQLiteTableWithColumns = }; export interface SQLiteTableFn { + /** + * @deprecated The third parameter of sqliteTable is changing and will only accept an array instead of an object + * + * @example + * Deprecated version: + * ```ts + * export const users = sqliteTable("users", { + * id: int(), + * }, (t) => ({ + * idx: index('custom_name').on(t.id) + * })); + * ``` + * + * New API: + * ```ts + * export const users = sqliteTable("users", { + * id: int(), + * }, (t) => [ + * index('custom_name').on(t.id) + * ]); + * ``` + */ < TTableName extends string, TColumnsMap extends Record, @@ -68,6 +93,28 @@ export interface SQLiteTableFn { dialect: 'sqlite'; }>; + /** + * @deprecated The third parameter of sqliteTable is changing and will only accept an array instead of an object + * + * @example + * Deprecated version: + * ```ts + * export const users = sqliteTable("users", { + * id: int(), + * }, (t) => ({ + * idx: index('custom_name').on(t.id) + * })); + * ``` + * + * New API: + * ```ts + * export const users = sqliteTable("users", { + * id: int(), + * }, (t) => [ + * index('custom_name').on(t.id) + * ]); + * ``` + */ < TTableName extends string, TColumnsMap extends Record, @@ -81,6 +128,36 @@ export interface SQLiteTableFn { columns: BuildColumns; dialect: 'sqlite'; }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: TColumnsMap, + extraConfig?: ( + self: BuildColumns, + ) => SQLiteTableExtraConfigValue[], + ): SQLiteTableWithColumns<{ + name: TTableName; + schema: TSchema; + columns: BuildColumns; + dialect: 'sqlite'; + }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: SQLiteColumnBuilders) => TColumnsMap, + extraConfig?: (self: BuildColumns) => SQLiteTableExtraConfigValue[], + ): SQLiteTableWithColumns<{ + name: TTableName; + schema: TSchema; + columns: BuildColumns; + dialect: 'sqlite'; + }>; } function sqliteTableBase< @@ -90,7 +167,11 @@ function sqliteTableBase< >( name: TTableName, columns: TColumnsMap | ((columnTypes: SQLiteColumnBuilders) => TColumnsMap), - extraConfig?: (self: BuildColumns) => SQLiteTableExtraConfig, + extraConfig: + | (( + self: BuildColumns, + ) => SQLiteTableExtraConfig | SQLiteTableExtraConfigValue[]) + | undefined, schema?: TSchema, baseName = name, ): SQLiteTableWithColumns<{ diff --git a/drizzle-orm/src/sqlite-core/utils.ts b/drizzle-orm/src/sqlite-core/utils.ts index 33ae2c248..7d21483b0 100644 --- a/drizzle-orm/src/sqlite-core/utils.ts +++ b/drizzle-orm/src/sqlite-core/utils.ts @@ -26,7 +26,8 @@ export function getTableConfig(table: TTable) { if (extraConfigBuilder !== undefined) { const extraConfig = extraConfigBuilder(table[SQLiteTable.Symbol.Columns]); - for (const builder of Object.values(extraConfig)) { + const extraValues = Array.isArray(extraConfig) ? extraConfig.flat(1) as any[] : Object.values(extraConfig); + for (const builder of Object.values(extraValues)) { if (is(builder, IndexBuilder)) { indexes.push(builder.build(table)); } else if (is(builder, CheckBuilder)) { diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index a2a0baeb0..521e70407 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -37,6 +37,7 @@ import { foreignKey, getTableConfig, getViewConfig, + index, int, intersect, intersectAll, @@ -3888,6 +3889,37 @@ export function tests(driver?: string) { expect(users.length).toBeGreaterThan(0); }); + test('define constraints as array', async (ctx) => { + const { db } = ctx.mysql; + + const table = mysqlTable('name', { + id: int(), + }, (t) => [ + index('name').on(t.id), + primaryKey({ columns: [t.id], name: 'custom' }), + ]); + + const { indexes, primaryKeys } = getTableConfig(table); + + expect(indexes.length).toBe(1); + expect(primaryKeys.length).toBe(1); + }); + + test('define constraints as array inside third param', async (ctx) => { + const { db } = ctx.mysql; + + const table = mysqlTable('name', { + id: int(), + }, (t) => [ + [index('name').on(t.id), primaryKey({ columns: [t.id], name: 'custom' })], + ]); + + const { indexes, primaryKeys } = getTableConfig(table); + + expect(indexes.length).toBe(1); + expect(primaryKeys.length).toBe(1); + }); + test('update with limit and order by', async (ctx) => { const { db } = ctx.mysql; diff --git a/integration-tests/tests/singlestore/singlestore-common.ts b/integration-tests/tests/singlestore/singlestore-common.ts index 6335bf9ec..fe7c2afb4 100644 --- a/integration-tests/tests/singlestore/singlestore-common.ts +++ b/integration-tests/tests/singlestore/singlestore-common.ts @@ -35,6 +35,7 @@ import { decimal, except, getTableConfig, + index, int, intersect, json, @@ -2701,6 +2702,37 @@ export function tests(driver?: string) { })()).rejects.toThrowError(); }); + test('define constraints as array', async (ctx) => { + const { db } = ctx.singlestore; + + const table = singlestoreTable('name', { + id: int(), + }, (t) => [ + index('name').on(t.id), + primaryKey({ columns: [t.id], name: 'custom' }), + ]); + + const { indexes, primaryKeys } = getTableConfig(table); + + expect(indexes.length).toBe(1); + expect(primaryKeys.length).toBe(1); + }); + + test('define constraints as array inside third param', async (ctx) => { + const { db } = ctx.singlestore; + + const table = singlestoreTable('name', { + id: int(), + }, (t) => [ + [index('name').on(t.id), primaryKey({ columns: [t.id], name: 'custom' })], + ]); + + const { indexes, primaryKeys } = getTableConfig(table); + + expect(indexes.length).toBe(1); + expect(primaryKeys.length).toBe(1); + }); + test.skip('set operations (mixed) from query builder', async (ctx) => { const { db } = ctx.singlestore; diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 1c62181dd..c6d67cee3 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -29,6 +29,7 @@ import { foreignKey, getTableConfig, getViewConfig, + index, int, integer, intersect, @@ -2592,6 +2593,34 @@ export function tests() { }).rejects.toThrowError(); }); + test('define constraints as array', async (_ctx) => { + const table = sqliteTable('name', { + id: int(), + }, (t) => [ + index('name').on(t.id), + primaryKey({ columns: [t.id], name: 'custom' }), + ]); + + const { indexes, primaryKeys } = getTableConfig(table); + + expect(indexes.length).toBe(1); + expect(primaryKeys.length).toBe(1); + }); + + test('define constraints as array inside third param', async (_ctx) => { + const table = sqliteTable('name', { + id: int(), + }, (t) => [ + index('name').on(t.id), + primaryKey({ columns: [t.id], name: 'custom' }), + ]); + + const { indexes, primaryKeys } = getTableConfig(table); + + expect(indexes.length).toBe(1); + expect(primaryKeys.length).toBe(1); + }); + test('aggregate function: count', async (ctx) => { const { db } = ctx.sqlite; const table = aggregateTable; From 29d063b27073635453fcf9c773602b00ec410055 Mon Sep 17 00:00:00 2001 From: Oleksii Provorov Date: Mon, 9 Dec 2024 13:58:44 +0200 Subject: [PATCH 426/492] Updated: - Added type check for `onIndex` config param that it could be used only with MySqlTable, not with Subquery and View - Removed UniqueConstraintBuilder from IndexForHint type, it shoild be only with IndexBuilder or string - Changed convertIndexToString function due to existance only IndexBuilder or string - Added new tests for mysql-common with subquery and view - Added drizzle-orm type-test for index hints --- .../src/mysql-core/query-builders/select.ts | 39 +-- .../mysql-core/query-builders/select.types.ts | 2 +- drizzle-orm/src/mysql-core/utils.ts | 17 +- drizzle-orm/type-tests/mysql/select.ts | 103 ++++++++ integration-tests/tests/mysql/mysql-common.ts | 233 +++++++++++++++++- 5 files changed, 355 insertions(+), 39 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index ac5c64b64..ba78a59ad 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -21,11 +21,10 @@ import type { ColumnsSelection, Placeholder, Query } from '~/sql/sql.ts'; import { SQL, View } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; -import { applyMixins, getTableColumns, getTableLikeName, haveSameKeys, type ValueOrArray } from '~/utils.ts'; -import { orderSelectedFields } from '~/utils.ts'; +import type { ValueOrArray } from '~/utils.ts'; +import { applyMixins, getTableColumns, getTableLikeName, haveSameKeys, orderSelectedFields } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { IndexBuilder } from '../indexes.ts'; -import type { UniqueConstraintBuilder } from '../unique-constraint.ts'; import { convertIndexToString } from '../utils.ts'; import { MySqlViewBase } from '../view-base.ts'; import type { @@ -48,12 +47,12 @@ import type { SetOperatorRightSelect, } from './select.types.ts'; -type Index = UniqueConstraintBuilder | IndexBuilder | string; +export type IndexForHint = IndexBuilder | string; export type IndexConfig = { - useIndex?: Index[]; - forceIndex?: Index[]; - ignoreIndex?: Index[]; + useIndex?: IndexForHint[]; + forceIndex?: IndexForHint[]; + ignoreIndex?: IndexForHint[]; }; export class MySqlSelectBuilder< @@ -89,7 +88,8 @@ export class MySqlSelectBuilder< from( source: TFrom, - onIndex?: IndexConfig, + onIndex?: TFrom extends MySqlTable ? IndexConfig + : 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views.', ): CreateMySqlSelectFromBuilderMode< TBuilderMode, GetSelectTableName, @@ -120,15 +120,15 @@ export class MySqlSelectBuilder< let useIndex: string[] = []; let forceIndex: string[] = []; let ignoreIndex: string[] = []; - if (is(source, MySqlTable) && onIndex) { + if (is(source, MySqlTable) && onIndex && typeof onIndex !== 'string') { if (onIndex.useIndex) { - useIndex = convertIndexToString({ table: source, indexes: onIndex.useIndex }); + useIndex = convertIndexToString(onIndex.useIndex); } if (onIndex.forceIndex) { - forceIndex = convertIndexToString({ table: source, indexes: onIndex.forceIndex }); + forceIndex = convertIndexToString(onIndex.forceIndex); } if (onIndex.ignoreIndex) { - ignoreIndex = convertIndexToString({ table: source, indexes: onIndex.ignoreIndex! }); + ignoreIndex = convertIndexToString(onIndex.ignoreIndex); } } @@ -223,10 +223,13 @@ export abstract class MySqlSelectQueryBuilderBase< private createJoin( joinType: TJoinType, ): MySqlJoinFn { - return ( + return < + TJoinedTable extends MySqlTable | Subquery | MySqlViewBase | SQL, + >( table: MySqlTable | Subquery | MySqlViewBase | SQL, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, - onIndex?: IndexConfig, + onIndex?: TJoinedTable extends MySqlTable ? IndexConfig + : 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views.', ) => { const baseTableName = this.tableName; const tableName = getTableLikeName(table); @@ -268,15 +271,15 @@ export abstract class MySqlSelectQueryBuilderBase< let useIndex: string[] = []; let forceIndex: string[] = []; let ignoreIndex: string[] = []; - if (is(table, MySqlTable) && onIndex) { + if (is(table, MySqlTable) && onIndex && typeof onIndex !== 'string') { if (onIndex.useIndex) { - useIndex = convertIndexToString({ table, indexes: onIndex.useIndex }); + useIndex = convertIndexToString(onIndex.useIndex); } if (onIndex.forceIndex) { - forceIndex = convertIndexToString({ table, indexes: onIndex.forceIndex }); + forceIndex = convertIndexToString(onIndex.forceIndex); } if (onIndex.ignoreIndex) { - ignoreIndex = convertIndexToString({ table, indexes: onIndex.ignoreIndex! }); + ignoreIndex = convertIndexToString(onIndex.ignoreIndex); } } diff --git a/drizzle-orm/src/mysql-core/query-builders/select.types.ts b/drizzle-orm/src/mysql-core/query-builders/select.types.ts index 50abe63cb..8e3331d8c 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.types.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.types.ts @@ -122,7 +122,7 @@ export type MySqlJoinFn< >( table: TJoinedTable, on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, - onIndex?: IndexConfig, + onIndex?: TJoinedTable extends MySqlTable ? IndexConfig : 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views.', ) => MySqlJoin; export type SelectedFieldsFlat = SelectedFieldsFlatBase; diff --git a/drizzle-orm/src/mysql-core/utils.ts b/drizzle-orm/src/mysql-core/utils.ts index 8ca117120..bfd7e37af 100644 --- a/drizzle-orm/src/mysql-core/utils.ts +++ b/drizzle-orm/src/mysql-core/utils.ts @@ -9,6 +9,7 @@ import type { Index } from './indexes.ts'; import { IndexBuilder } from './indexes.ts'; import type { PrimaryKey } from './primary-keys.ts'; import { PrimaryKeyBuilder } from './primary-keys.ts'; +import type { IndexForHint } from './query-builders/select.ts'; import { MySqlTable } from './table.ts'; import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; import { MySqlViewConfig } from './view-common.ts'; @@ -67,20 +68,8 @@ export function getViewConfig< }; } -export function convertIndexToString({ - table, - indexes, -}: { - table: MySqlTable; - indexes: (UniqueConstraintBuilder | IndexBuilder | string)[]; -}) { +export function convertIndexToString(indexes: IndexForHint[]) { return indexes.map((idx) => { - if (typeof idx === 'object') { - return is(idx, UniqueConstraintBuilder) - ? idx.build(table).getName()! - : idx.config.name; - } else { - return idx; - } + return typeof idx === 'object' ? idx.config.name : idx; }); } diff --git a/drizzle-orm/type-tests/mysql/select.ts b/drizzle-orm/type-tests/mysql/select.ts index bad55aa59..e83e2461d 100644 --- a/drizzle-orm/type-tests/mysql/select.ts +++ b/drizzle-orm/type-tests/mysql/select.ts @@ -27,6 +27,7 @@ import { type InferSelectViewModel, param, sql } from '~/sql/sql.ts'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { + index, int, type MySqlSelect, type MySqlSelectQueryBuilder, @@ -649,3 +650,105 @@ await db Expect>; Expect[]>>; } + +{ + const table1 = mysqlTable('table1', { + id: int().primaryKey(), + name: text().notNull(), + }, () => { + return { table1NameIndex }; + }); + const table1NameIndex = index('table1_name_index').on(table1.name); + + const table2 = mysqlTable('table2', { + id: int().primaryKey(), + age: int().notNull(), + table1Id: int().references(() => table1.id).notNull(), + }, () => { + return { table2AgeIndex }; + }); + const table2AgeIndex = index('table1_name_index').on(table2.age); + + const view = mysqlView('view').as((qb) => qb.select().from(table2)); + const sq = db.select().from(table2, { useIndex: ['posts_text_index'] }).as('sq'); + + await db.select().from(table1, { + useIndex: [table1NameIndex], + forceIndex: [table1NameIndex], + ignoreIndex: [table1NameIndex], + }); + // @ts-expect-error + await db.select().from(view, { + useIndex: [table1NameIndex], + forceIndex: [table1NameIndex], + ignoreIndex: [table1NameIndex], + }); + // @ts-expect-error + await db.select().from(sq, { + useIndex: [table1NameIndex], + forceIndex: [table1NameIndex], + ignoreIndex: [table1NameIndex], + }); + + const join = await db.select().from(table1) + .leftJoin(table2, eq(table1.id, table2.table1Id), { + useIndex: [table2AgeIndex], + forceIndex: [table2AgeIndex], + ignoreIndex: [table2AgeIndex], + }); + + Expect< + Equal< + { + table1: { + id: number; + name: string; + }; + table2: { + id: number; + age: number; + table1Id: number; + } | null; + }[], + typeof join + > + >; + + const sqJoin = await db.select().from(table1, { + useIndex: [table1NameIndex], + }) + .leftJoin(sq, eq(table1.id, sq.table1Id)); + + Expect< + Equal< + { + table1: { + id: number; + name: string; + }; + sq: { + id: number; + age: number; + table1Id: number; + } | null; + }[], + typeof sqJoin + > + >; + + await db.select().from(table1) + // @ts-expect-error + .leftJoin(view, eq(table1.id, view.table1Id), { + useIndex: [table2AgeIndex], + forceIndex: [table2AgeIndex], + ignoreIndex: [table2AgeIndex], + }); + + await db.select().from(table1) + // @ts-expect-error + .leftJoin(sq, eq(table1.id, sq.table1Id), { + useIndex: [table2AgeIndex], + forceIndex: [table2AgeIndex], + ignoreIndex: [table2AgeIndex], + }); +} diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 766d7de7b..fb57bda68 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -4102,7 +4102,7 @@ export function tests(driver?: string) { ).toThrowError(); }); - test('select with `use index` hint', async (ctx) => { + test('MySqlTable :: select with `use index` hint', async (ctx) => { const { db } = ctx.mysql; const users = mysqlTable('users', { @@ -4142,7 +4142,7 @@ export function tests(driver?: string) { expect(result).toEqual([{ id: 4, name: 'David' }]); }); - test('select with `use index` hint on not existed index', async (ctx) => { + test('MySqlTable :: select with `use index` hint on not existed index', async (ctx) => { const { db } = ctx.mysql; const users = mysqlTable('users', { @@ -4181,7 +4181,7 @@ export function tests(driver?: string) { })()).rejects.toThrowError(); }); - test('select with `use index` + `force index` incompatible hints', async (ctx) => { + test('MySqlTable :: select with `use index` + `force index` incompatible hints', async (ctx) => { const { db } = ctx.mysql; const users = mysqlTable('users', { @@ -4226,7 +4226,7 @@ export function tests(driver?: string) { })()).rejects.toThrowError(); }); - test('select with join `use index` hint', async (ctx) => { + test('MySqlTable :: select with join `use index` hint', async (ctx) => { const { db } = ctx.mysql; const users = mysqlTable('users', { @@ -4297,7 +4297,7 @@ export function tests(driver?: string) { expect(result).toEqual([{ userId: 4, name: 'David', postId: 4, text: 'David post' }]); }); - test('select with join `use index` hint on not existed index', async (ctx) => { + test('MySqlTable :: select with join `use index` hint on not existed index', async (ctx) => { const { db } = ctx.mysql; const users = mysqlTable('users', { @@ -4367,7 +4367,7 @@ export function tests(driver?: string) { })()).rejects.toThrowError(); }); - test('select with join `use index` + `force index` incompatible hints', async (ctx) => { + test('MySqlTable :: select with join `use index` + `force index` incompatible hints', async (ctx) => { const { db } = ctx.mysql; const users = mysqlTable('users', { @@ -4440,4 +4440,225 @@ export function tests(driver?: string) { )); })()).rejects.toThrowError(); }); + + test('MySqlTable :: select with Subquery join `use index`', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + }); + + const posts = mysqlTable('posts', { + id: serial('id').primaryKey(), + text: varchar('text', { length: 100 }).notNull(), + userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), + }, () => { + return { + postsTableUserIdIndex, + }; + }); + const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); + + await db.execute(sql`drop table if exists ${posts}`); + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql` + create table ${posts} ( + \`id\` serial primary key, + \`text\` varchar(100) not null, + \`user_id\` int not null references users(id) on delete cascade + ) + `); + await db.execute(sql`create index posts_user_id_index ON posts(user_id)`); + + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + await db.insert(posts).values([ + { text: 'Alice post', userId: 1 }, + { text: 'Bob post', userId: 2 }, + { text: 'Charlie post', userId: 3 }, + { text: 'David post', userId: 4 }, + { text: 'Eve post', userId: 5 }, + ]); + + const sq = db.select().from(posts, { useIndex: [postsTableUserIdIndex] }).where(eq(posts.userId, 1)).as('sq'); + + const result = await db.select({ + userId: users.id, + name: users.name, + postId: sq.id, + text: sq.text, + }) + .from(users) + .leftJoin(sq, eq(users.id, sq.userId)) + .where(eq(users.name, 'Alice')); + + expect(result).toHaveLength(1); + expect(result).toEqual([{ userId: 1, name: 'Alice', postId: 1, text: 'Alice post' }]); + }); + + test('MySqlTable :: select with Subquery join with `use index` in join', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + }); + + const posts = mysqlTable('posts', { + id: serial('id').primaryKey(), + text: varchar('text', { length: 100 }).notNull(), + userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), + }, () => { + return { + postsTableUserIdIndex, + }; + }); + const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); + + await db.execute(sql`drop table if exists ${posts}`); + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql` + create table ${posts} ( + \`id\` serial primary key, + \`text\` varchar(100) not null, + \`user_id\` int not null references users(id) on delete cascade + ) + `); + await db.execute(sql`create index posts_user_id_index ON posts(user_id)`); + + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + await db.insert(posts).values([ + { text: 'Alice post', userId: 1 }, + { text: 'Bob post', userId: 2 }, + { text: 'Charlie post', userId: 3 }, + { text: 'David post', userId: 4 }, + { text: 'Eve post', userId: 5 }, + ]); + + const sq = db.select().from(posts).where(eq(posts.userId, 1)).as('sq'); + + const query = db.select({ + userId: users.id, + name: users.name, + postId: sq.id, + text: sq.text, + }) + .from(users) + // @ts-expect-error + .leftJoin(sq, eq(users.id, sq.userId, { useIndex: [postsTableUserIdIndex] })) + .where(eq(users.name, 'Alice')) + .toSQL(); + + expect(query.sql).not.include('USE INDEX'); + }); + + test('View :: select with `use index` hint', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + }, () => { + return { + usersTableNameIndex, + }; + }); + + const usersTableNameIndex = index('users_name_index').on(users.name); + + const usersView = mysqlView('users_view').as((qb) => qb.select().from(users)); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql`create index users_name_index ON users(name)`); + await db.execute(sql`create view ${usersView} as select * from ${users}`); + + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + // @ts-expect-error + const query = db.select().from(usersView, { + useIndex: [usersTableNameIndex], + }).toSQL(); + + expect(query.sql).not.include('USE INDEX'); + + await db.execute(sql`drop view ${usersView}`); + }); + + test('Subquery :: select with `use index` hint', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + }, () => { + return { + usersTableNameIndex, + }; + }); + const usersTableNameIndex = index('users_name_index').on(users.name); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql`create index users_name_index ON users(name)`); + + await db.insert(users).values([ + { name: 'Alice' }, + { name: 'Bob' }, + { name: 'Charlie' }, + { name: 'David' }, + { name: 'Eve' }, + ]); + + const sq = db.select().from(users).as('sq'); + + // @ts-expect-error + const query = db.select().from(sq, { + useIndex: [usersTableNameIndex], + }).toSQL(); + + expect(query.sql).not.include('USE INDEX'); + }); } From 29eb63c6bb3050195e0188bcae1dcda46a58f891 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 9 Dec 2024 14:05:27 +0200 Subject: [PATCH 427/492] Make introspect not use deprecated third param option as object --- drizzle-kit/src/introspect-mysql.ts | 29 +++++++----------- drizzle-kit/src/introspect-pg.ts | 36 ++++++++++------------- drizzle-kit/src/introspect-singlestore.ts | 17 ++++------- drizzle-kit/src/introspect-sqlite.ts | 26 +++++++--------- drizzle-kit/vitest.config.ts | 5 ---- 5 files changed, 40 insertions(+), 73 deletions(-) diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index ebf30f70d..005a2af42 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -16,9 +16,6 @@ import { import { indexName } from './serializer/mysqlSerializer'; import { unescapeSingleQuotes } from './utils'; -// time precision to fsp -// {mode: "string"} for timestamp by default - const mysqlImportsList = new Set([ 'mysqlTable', 'mysqlEnum', @@ -263,8 +260,7 @@ export const schemaToTypeScript = ( || Object.keys(table.checkConstraint).length > 0 ) { statement += ',\n'; - statement += '(table) => {\n'; - statement += '\treturn {\n'; + statement += '(table) => ['; statement += createTableIndexes( table.name, Object.values(table.indexes), @@ -283,8 +279,7 @@ export const schemaToTypeScript = ( Object.values(table.checkConstraint), withCasing, ); - statement += '\t}\n'; - statement += '}'; + statement += '\n]'; } statement += ');'; @@ -932,7 +927,7 @@ const createTableIndexes = ( const indexGeneratedName = indexName(tableName, it.columns); const escapedIndexName = indexGeneratedName === it.name ? '' : `"${it.name}"`; - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += it.isUnique ? 'uniqueIndex(' : 'index('; statement += `${escapedIndexName})`; statement += `.on(${ @@ -940,7 +935,6 @@ const createTableIndexes = ( .map((it) => `table.${casing(it)}`) .join(', ') }),`; - statement += `\n`; }); return statement; @@ -955,7 +949,7 @@ const createTableUniques = ( unqs.forEach((it) => { const idxKey = casing(it.name); - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += 'unique('; statement += `"${it.name}")`; statement += `.on(${ @@ -963,7 +957,6 @@ const createTableUniques = ( .map((it) => `table.${casing(it)}`) .join(', ') }),`; - statement += `\n`; }); return statement; @@ -976,13 +969,11 @@ const createTableChecks = ( let statement = ''; checks.forEach((it) => { - const checkKey = casing(it.name); - - statement += `\t\t${checkKey}: `; + statement += `\n\t`; statement += 'check('; statement += `"${it.name}", `; statement += `sql\`${it.value.replace(/`/g, '\\`')}\`)`; - statement += `,\n`; + statement += `,`; }); return statement; @@ -997,7 +988,7 @@ const createTablePKs = ( pks.forEach((it) => { let idxKey = casing(it.name); - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += 'primaryKey({ columns: ['; statement += `${ it.columns @@ -1007,7 +998,6 @@ const createTablePKs = ( .join(', ') }]${it.name ? `, name: "${it.name}"` : ''}}`; statement += '),'; - statement += `\n`; }); return statement; @@ -1022,7 +1012,8 @@ const createTableFKs = ( fks.forEach((it) => { const isSelf = it.tableTo === it.tableFrom; const tableTo = isSelf ? 'table' : `${casing(it.tableTo)}`; - statement += `\t\t${casing(it.name)}: foreignKey({\n`; + statement += `\n\t`; + statement += `foreignKey({\n`; statement += `\t\t\tcolumns: [${ it.columnsFrom .map((i) => `table.${casing(i)}`) @@ -1044,7 +1035,7 @@ const createTableFKs = ( ? `.onDelete("${it.onDelete}")` : ''; - statement += `,\n`; + statement += `,`; }); return statement; diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index 9c9383ebe..4bb65ee0c 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -537,8 +537,7 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => || Object.keys(table.checkConstraints).length > 0 ) { statement += ', '; - statement += '(table) => {\n'; - statement += '\treturn {\n'; + statement += '(table) => ['; statement += createTableIndexes(table.name, Object.values(table.indexes), casing); statement += createTableFKs(Object.values(table.foreignKeys), schemas, casing); statement += createTablePKs( @@ -558,8 +557,7 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => Object.values(table.checkConstraints), casing, ); - statement += '\t}\n'; - statement += '}'; + statement += '\n]'; } statement += ');'; @@ -1216,7 +1214,7 @@ const createTableIndexes = (tableName: string, idxs: Index[], casing: Casing): s ); const escapedIndexName = indexGeneratedName === it.name ? '' : `"${it.name}"`; - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += it.isUnique ? 'uniqueIndex(' : 'index('; statement += `${escapedIndexName})`; statement += `${it.concurrently ? `.concurrently()` : ''}`; @@ -1252,7 +1250,7 @@ const createTableIndexes = (tableName: string, idxs: Index[], casing: Casing): s } statement += it.with && Object.keys(it.with).length > 0 ? `.with(${reverseLogic(it.with)})` : ''; - statement += `,\n`; + statement += `,`; }); return statement; @@ -1262,9 +1260,7 @@ const createTablePKs = (pks: PrimaryKey[], casing: Casing): string => { let statement = ''; pks.forEach((it) => { - let idxKey = withCasing(it.name, casing); - - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += 'primaryKey({ columns: ['; statement += `${ it.columns @@ -1274,7 +1270,7 @@ const createTablePKs = (pks: PrimaryKey[], casing: Casing): string => { .join(', ') }]${it.name ? `, name: "${it.name}"` : ''}}`; statement += ')'; - statement += `,\n`; + statement += `,`; }); return statement; @@ -1297,13 +1293,13 @@ const createTablePolicies = ( return rolesNameToTsKey[v] ? withCasing(rolesNameToTsKey[v], casing) : `"${v}"`; }); - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += 'pgPolicy('; statement += `"${it.name}", { `; statement += `as: "${it.as?.toLowerCase()}", for: "${it.for?.toLowerCase()}", to: [${mappedItTo?.join(', ')}]${ it.using ? `, using: sql\`${it.using}\`` : '' }${it.withCheck ? `, withCheck: sql\`${it.withCheck}\` ` : ''}`; - statement += ` }),\n`; + statement += ` }),`; }); return statement; @@ -1316,14 +1312,12 @@ const createTableUniques = ( let statement = ''; unqs.forEach((it) => { - const idxKey = withCasing(it.name, casing); - - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += 'unique('; statement += `"${it.name}")`; statement += `.on(${it.columns.map((it) => `table.${withCasing(it, casing)}`).join(', ')})`; statement += it.nullsNotDistinct ? `.nullsNotDistinct()` : ''; - statement += `,\n`; + statement += `,`; }); return statement; @@ -1336,12 +1330,11 @@ const createTableChecks = ( let statement = ''; checkConstraints.forEach((it) => { - const checkKey = withCasing(it.name, casing); - statement += `\t\t${checkKey}: `; + statement += `\n\t`; statement += 'check('; statement += `"${it.name}", `; statement += `sql\`${it.value}\`)`; - statement += `,\n`; + statement += `,`; }); return statement; @@ -1356,7 +1349,8 @@ const createTableFKs = (fks: ForeignKey[], schemas: Record, casi const isSelf = it.tableTo === it.tableFrom; const tableTo = isSelf ? 'table' : `${withCasing(paramName, casing)}`; - statement += `\t\t${withCasing(it.name, casing)}: foreignKey({\n`; + statement += `\n\t`; + statement += `foreignKey({\n`; statement += `\t\t\tcolumns: [${it.columnsFrom.map((i) => `table.${withCasing(i, casing)}`).join(', ')}],\n`; statement += `\t\t\tforeignColumns: [${ it.columnsTo.map((i) => `${tableTo}.${withCasing(i, casing)}`).join(', ') @@ -1368,7 +1362,7 @@ const createTableFKs = (fks: ForeignKey[], schemas: Record, casi statement += it.onDelete && it.onDelete !== 'no action' ? `.onDelete("${it.onDelete}")` : ''; - statement += `,\n`; + statement += `,`; }); return statement; diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts index 8f93cdfda..09c2feec0 100644 --- a/drizzle-kit/src/introspect-singlestore.ts +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -249,8 +249,7 @@ export const schemaToTypeScript = ( || Object.keys(table.uniqueConstraints).length > 0 ) { statement += ',\n'; - statement += '(table) => {\n'; - statement += '\treturn {\n'; + statement += '(table) => ['; statement += createTableIndexes( table.name, Object.values(table.indexes), @@ -264,8 +263,7 @@ export const schemaToTypeScript = ( Object.values(table.uniqueConstraints), withCasing, ); - statement += '\t}\n'; - statement += '}'; + statement += '\n]'; } statement += ');'; @@ -855,7 +853,7 @@ const createTableIndexes = ( const indexGeneratedName = indexName(tableName, it.columns); const escapedIndexName = indexGeneratedName === it.name ? '' : `"${it.name}"`; - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += it.isUnique ? 'uniqueIndex(' : 'index('; statement += `${escapedIndexName})`; statement += `.on(${ @@ -863,7 +861,6 @@ const createTableIndexes = ( .map((it) => `table.${casing(it)}`) .join(', ') }),`; - statement += `\n`; }); return statement; @@ -876,9 +873,7 @@ const createTableUniques = ( let statement = ''; unqs.forEach((it) => { - const idxKey = casing(it.name); - - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += 'unique('; statement += `"${it.name}")`; statement += `.on(${ @@ -886,7 +881,6 @@ const createTableUniques = ( .map((it) => `table.${casing(it)}`) .join(', ') }),`; - statement += `\n`; }); return statement; @@ -901,7 +895,7 @@ const createTablePKs = ( pks.forEach((it) => { let idxKey = casing(it.name); - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += 'primaryKey({ columns: ['; statement += `${ it.columns @@ -911,7 +905,6 @@ const createTablePKs = ( .join(', ') }]${it.name ? `, name: "${it.name}"` : ''}}`; statement += '),'; - statement += `\n`; }); return statement; diff --git a/drizzle-kit/src/introspect-sqlite.ts b/drizzle-kit/src/introspect-sqlite.ts index 464a32aa3..d3aac6f04 100644 --- a/drizzle-kit/src/introspect-sqlite.ts +++ b/drizzle-kit/src/introspect-sqlite.ts @@ -162,8 +162,7 @@ export const schemaToTypeScript = ( || Object.keys(table.checkConstraints).length > 0 ) { statement += ',\n'; - statement += '(table) => {\n'; - statement += '\treturn {\n'; + statement += '(table) => ['; statement += createTableIndexes( table.name, Object.values(table.indexes), @@ -182,8 +181,7 @@ export const schemaToTypeScript = ( Object.values(table.checkConstraints), casing, ); - statement += '\t}\n'; - statement += '}'; + statement += '\n]'; } statement += ');'; @@ -429,7 +427,7 @@ const createTableIndexes = ( const indexGeneratedName = indexName(tableName, it.columns); const escapedIndexName = indexGeneratedName === it.name ? '' : `"${it.name}"`; - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += it.isUnique ? 'uniqueIndex(' : 'index('; statement += `${escapedIndexName})`; statement += `.on(${ @@ -437,7 +435,6 @@ const createTableIndexes = ( .map((it) => `table.${withCasing(it, casing)}`) .join(', ') }),`; - statement += `\n`; }); return statement; @@ -452,7 +449,7 @@ const createTableUniques = ( unqs.forEach((it) => { const idxKey = withCasing(it.name, casing); - statement += `\t\t${idxKey}: `; + statement += `\n\t`; statement += 'unique('; statement += `"${it.name}")`; statement += `.on(${ @@ -460,7 +457,6 @@ const createTableUniques = ( .map((it) => `table.${withCasing(it, casing)}`) .join(', ') }),`; - statement += `\n`; }); return statement; @@ -472,13 +468,11 @@ const createTableChecks = ( let statement = ''; checks.forEach((it) => { - const checkKey = withCasing(it.name, casing); - - statement += `\t\t${checkKey}: `; + statement += `\n\t`; statement += 'check('; statement += `"${it.name}", `; statement += `sql\`${it.value}\`)`; - statement += `,\n`; + statement += `,`; }); return statement; @@ -488,7 +482,7 @@ const createTablePKs = (pks: PrimaryKey[], casing: Casing): string => { let statement = ''; pks.forEach((it, i) => { - statement += `\t\tpk${i}: `; + statement += `\n\t`; statement += 'primaryKey({ columns: ['; statement += `${ it.columns @@ -498,7 +492,6 @@ const createTablePKs = (pks: PrimaryKey[], casing: Casing): string => { .join(', ') }]${it.name ? `, name: "${it.name}"` : ''}}`; statement += ')'; - statement += `\n`; }); return statement; @@ -510,7 +503,8 @@ const createTableFKs = (fks: ForeignKey[], casing: Casing): string => { fks.forEach((it) => { const isSelf = it.tableTo === it.tableFrom; const tableTo = isSelf ? 'table' : `${withCasing(it.tableTo, casing)}`; - statement += `\t\t${withCasing(it.name, casing)}: foreignKey(() => ({\n`; + statement += `\n\t`; + statement += `foreignKey(() => ({\n`; statement += `\t\t\tcolumns: [${ it.columnsFrom .map((i) => `table.${withCasing(i, casing)}`) @@ -532,7 +526,7 @@ const createTableFKs = (fks: ForeignKey[], casing: Casing): string => { ? `.onDelete("${it.onDelete}")` : ''; - statement += `,\n`; + statement += `,`; }); return statement; diff --git a/drizzle-kit/vitest.config.ts b/drizzle-kit/vitest.config.ts index fd728eb11..a3a46cd23 100644 --- a/drizzle-kit/vitest.config.ts +++ b/drizzle-kit/vitest.config.ts @@ -5,11 +5,6 @@ export default defineConfig({ test: { include: [ 'tests/**/*.test.ts', - // Need to test it first before pushing changes - // 'tests/singlestore-schemas.test.ts', - // 'tests/singlestore-views.test.ts', - // 'tests/push/singlestore-push.test.ts', - // 'tests/push/singlestore.test.ts', ], // This one was excluded because we need to modify an API for SingleStore-generated columns. From 575d23130c2eeb70c8462f41a544764e33e62ece Mon Sep 17 00:00:00 2001 From: Oleksii Provorov Date: Mon, 9 Dec 2024 14:11:30 +0200 Subject: [PATCH 428/492] Updated: - Formatted with dprint mysql select/ select.types files --- drizzle-orm/src/mysql-core/query-builders/select.ts | 4 ++-- drizzle-orm/src/mysql-core/query-builders/select.types.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index ba78a59ad..a1bd98816 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -89,7 +89,7 @@ export class MySqlSelectBuilder< from( source: TFrom, onIndex?: TFrom extends MySqlTable ? IndexConfig - : 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views.', + : 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views', ): CreateMySqlSelectFromBuilderMode< TBuilderMode, GetSelectTableName, @@ -229,7 +229,7 @@ export abstract class MySqlSelectQueryBuilderBase< table: MySqlTable | Subquery | MySqlViewBase | SQL, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, onIndex?: TJoinedTable extends MySqlTable ? IndexConfig - : 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views.', + : 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views', ) => { const baseTableName = this.tableName; const tableName = getTableLikeName(table); diff --git a/drizzle-orm/src/mysql-core/query-builders/select.types.ts b/drizzle-orm/src/mysql-core/query-builders/select.types.ts index 8e3331d8c..78b6f91a6 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.types.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.types.ts @@ -122,7 +122,8 @@ export type MySqlJoinFn< >( table: TJoinedTable, on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, - onIndex?: TJoinedTable extends MySqlTable ? IndexConfig : 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views.', + onIndex?: TJoinedTable extends MySqlTable ? IndexConfig + : 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views', ) => MySqlJoin; export type SelectedFieldsFlat = SelectedFieldsFlatBase; From 74a51aec4c45e42a030a92e13568195b3a68edf2 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Mon, 9 Dec 2024 14:24:29 +0200 Subject: [PATCH 429/492] dprint --- drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index ed67e0ac1..7d3debd1f 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -142,4 +142,4 @@ "default": "./api.mjs" } } -} \ No newline at end of file +} diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 8c52f8116..c7528fdbe 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -204,4 +204,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} \ No newline at end of file +} From 2b77cfc5e8d16121ebd0d5d192b23a54a933433d Mon Sep 17 00:00:00 2001 From: Oleksii Provorov Date: Mon, 9 Dec 2024 15:42:58 +0200 Subject: [PATCH 430/492] Updated: - onIndex config params now can accept 1 param without array, or multiple params in array - Added toArray function which will check if value array -> return value, if not -> return [value] - Updated mysql-common tests > Added tests to check sql query include correct USE INDEX options for 1 and multiple indexes - Updated type-tests --- .../src/mysql-core/query-builders/select.ts | 20 +- drizzle-orm/src/mysql-core/utils.ts | 4 + drizzle-orm/type-tests/mysql/select.ts | 111 ++++++-- integration-tests/tests/mysql/mysql-common.ts | 256 ++++++++++++------ 4 files changed, 272 insertions(+), 119 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index a1bd98816..821199ab4 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -25,7 +25,7 @@ import type { ValueOrArray } from '~/utils.ts'; import { applyMixins, getTableColumns, getTableLikeName, haveSameKeys, orderSelectedFields } from '~/utils.ts'; import { ViewBaseConfig } from '~/view-common.ts'; import type { IndexBuilder } from '../indexes.ts'; -import { convertIndexToString } from '../utils.ts'; +import { convertIndexToString, toArray } from '../utils.ts'; import { MySqlViewBase } from '../view-base.ts'; import type { AnyMySqlSelect, @@ -50,9 +50,9 @@ import type { export type IndexForHint = IndexBuilder | string; export type IndexConfig = { - useIndex?: IndexForHint[]; - forceIndex?: IndexForHint[]; - ignoreIndex?: IndexForHint[]; + useIndex?: IndexForHint | IndexForHint[]; + forceIndex?: IndexForHint | IndexForHint[]; + ignoreIndex?: IndexForHint | IndexForHint[]; }; export class MySqlSelectBuilder< @@ -122,13 +122,13 @@ export class MySqlSelectBuilder< let ignoreIndex: string[] = []; if (is(source, MySqlTable) && onIndex && typeof onIndex !== 'string') { if (onIndex.useIndex) { - useIndex = convertIndexToString(onIndex.useIndex); + useIndex = convertIndexToString(toArray(onIndex.useIndex)); } if (onIndex.forceIndex) { - forceIndex = convertIndexToString(onIndex.forceIndex); + forceIndex = convertIndexToString(toArray(onIndex.forceIndex)); } if (onIndex.ignoreIndex) { - ignoreIndex = convertIndexToString(onIndex.ignoreIndex); + ignoreIndex = convertIndexToString(toArray(onIndex.ignoreIndex)); } } @@ -273,13 +273,13 @@ export abstract class MySqlSelectQueryBuilderBase< let ignoreIndex: string[] = []; if (is(table, MySqlTable) && onIndex && typeof onIndex !== 'string') { if (onIndex.useIndex) { - useIndex = convertIndexToString(onIndex.useIndex); + useIndex = convertIndexToString(toArray(onIndex.useIndex)); } if (onIndex.forceIndex) { - forceIndex = convertIndexToString(onIndex.forceIndex); + forceIndex = convertIndexToString(toArray(onIndex.forceIndex)); } if (onIndex.ignoreIndex) { - ignoreIndex = convertIndexToString(onIndex.ignoreIndex); + ignoreIndex = convertIndexToString(toArray(onIndex.ignoreIndex)); } } diff --git a/drizzle-orm/src/mysql-core/utils.ts b/drizzle-orm/src/mysql-core/utils.ts index 945d3a274..b49dd0043 100644 --- a/drizzle-orm/src/mysql-core/utils.ts +++ b/drizzle-orm/src/mysql-core/utils.ts @@ -74,3 +74,7 @@ export function convertIndexToString(indexes: IndexForHint[]) { return typeof idx === 'object' ? idx.config.name : idx; }); } + +export function toArray(value: T | T[]): T[] { + return Array.isArray(value) ? value : [value]; +} diff --git a/drizzle-orm/type-tests/mysql/select.ts b/drizzle-orm/type-tests/mysql/select.ts index e83e2461d..c31021e26 100644 --- a/drizzle-orm/type-tests/mysql/select.ts +++ b/drizzle-orm/type-tests/mysql/select.ts @@ -655,46 +655,59 @@ await db const table1 = mysqlTable('table1', { id: int().primaryKey(), name: text().notNull(), - }, () => { - return { table1NameIndex }; - }); + }, () => [table1NameIndex]); const table1NameIndex = index('table1_name_index').on(table1.name); const table2 = mysqlTable('table2', { id: int().primaryKey(), age: int().notNull(), table1Id: int().references(() => table1.id).notNull(), - }, () => { - return { table2AgeIndex }; - }); - const table2AgeIndex = index('table1_name_index').on(table2.age); + }, () => [table2AgeIndex, table2Table1Index]); + const table2AgeIndex = index('table2_name_index').on(table2.age); + const table2Table1Index = index('table2_table1_index').on(table2.table1Id); const view = mysqlView('view').as((qb) => qb.select().from(table2)); const sq = db.select().from(table2, { useIndex: ['posts_text_index'] }).as('sq'); + await db.select().from(table1, { + useIndex: table1NameIndex, + forceIndex: table1NameIndex, + ignoreIndex: table1NameIndex, + }); await db.select().from(table1, { useIndex: [table1NameIndex], forceIndex: [table1NameIndex], ignoreIndex: [table1NameIndex], }); + await db.select().from(table1, { + useIndex: table1NameIndex, + // @ts-expect-error + table1NameIndex, + forceIndex: table1NameIndex, + ignoreIndex: table1NameIndex, + }); + // @ts-expect-error await db.select().from(view, { - useIndex: [table1NameIndex], - forceIndex: [table1NameIndex], + useIndex: table1NameIndex, + forceIndex: table1NameIndex, + table1NameIndex, ignoreIndex: [table1NameIndex], }); + // @ts-expect-error await db.select().from(sq, { - useIndex: [table1NameIndex], - forceIndex: [table1NameIndex], + useIndex: table1NameIndex, + forceIndex: table1NameIndex, + table1NameIndex, ignoreIndex: [table1NameIndex], }); - const join = await db.select().from(table1) + const join1 = await db.select().from(table1) .leftJoin(table2, eq(table1.id, table2.table1Id), { - useIndex: [table2AgeIndex], - forceIndex: [table2AgeIndex], - ignoreIndex: [table2AgeIndex], + useIndex: table2AgeIndex, + forceIndex: table2AgeIndex, + ignoreIndex: table2AgeIndex, }); Expect< @@ -710,12 +723,58 @@ await db table1Id: number; } | null; }[], - typeof join + typeof join1 > >; - const sqJoin = await db.select().from(table1, { - useIndex: [table1NameIndex], + const join2 = await db.select().from(table1) + .leftJoin(table2, eq(table1.id, table2.table1Id), { + useIndex: [table2AgeIndex, table2Table1Index], + forceIndex: [table2AgeIndex, table2Table1Index], + ignoreIndex: [table2AgeIndex, table2Table1Index], + }); + + Expect< + Equal< + { + table1: { + id: number; + name: string; + }; + table2: { + id: number; + age: number; + table1Id: number; + } | null; + }[], + typeof join2 + > + >; + + const sqJoin1 = await db.select().from(table1, { + useIndex: table1NameIndex, + }) + .leftJoin(sq, eq(table1.id, sq.table1Id)); + + Expect< + Equal< + { + table1: { + id: number; + name: string; + }; + sq: { + id: number; + age: number; + table1Id: number; + } | null; + }[], + typeof sqJoin1 + > + >; + + const sqJoin2 = await db.select().from(table1, { + useIndex: [table1NameIndex, table1NameIndex], }) .leftJoin(sq, eq(table1.id, sq.table1Id)); @@ -732,23 +791,25 @@ await db table1Id: number; } | null; }[], - typeof sqJoin + typeof sqJoin2 > >; await db.select().from(table1) // @ts-expect-error .leftJoin(view, eq(table1.id, view.table1Id), { - useIndex: [table2AgeIndex], - forceIndex: [table2AgeIndex], - ignoreIndex: [table2AgeIndex], + useIndex: table2AgeIndex, + forceIndex: table2AgeIndex, + table2Table1Index, + ignoreIndex: [table2AgeIndex, table2Table1Index], }); await db.select().from(table1) // @ts-expect-error .leftJoin(sq, eq(table1.id, sq.table1Id), { - useIndex: [table2AgeIndex], - forceIndex: [table2AgeIndex], - ignoreIndex: [table2AgeIndex], + useIndex: table2AgeIndex, + forceIndex: table2AgeIndex, + table2Table1Index, + ignoreIndex: [table2AgeIndex, table2Table1Index], }); } diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index bd25ff714..98e425f9c 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -4139,11 +4139,7 @@ export function tests(driver?: string) { const users = mysqlTable('users', { id: serial('id').primaryKey(), name: varchar('name', { length: 100 }).notNull(), - }, () => { - return { - usersTableNameIndex, - }; - }); + }, () => [usersTableNameIndex]); const usersTableNameIndex = index('users_name_index').on(users.name); await db.execute(sql`drop table if exists ${users}`); @@ -4173,17 +4169,73 @@ export function tests(driver?: string) { expect(result).toEqual([{ id: 4, name: 'David' }]); }); + test('MySqlTable :: select with `use index` hint on 1 index', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + }, () => [usersTableNameIndex]); + const usersTableNameIndex = index('users_name_index').on(users.name); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql`create index users_name_index ON users(name)`); + + const query = db.select() + .from(users, { + useIndex: usersTableNameIndex, + }) + .where(eq(users.name, 'David')) + .toSQL(); + + expect(query.sql).to.include('USE INDEX (users_name_index)'); + }); + + test('MySqlTable :: select with `use index` hint on multiple indexes', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + age: int('age').notNull(), + }, () => [usersTableNameIndex, usersTableAgeIndex]); + const usersTableNameIndex = index('users_name_index').on(users.name); + const usersTableAgeIndex = index('users_age_index').on(users.age); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null, + \`age\` int not null + ) + `); + await db.execute(sql`create index users_name_index ON users(name)`); + await db.execute(sql`create index users_age_index ON users(age)`); + + const query = db.select() + .from(users, { + useIndex: [usersTableNameIndex, usersTableAgeIndex], + }) + .where(eq(users.name, 'David')) + .toSQL(); + + expect(query.sql).to.include('USE INDEX (users_name_index, users_age_index)'); + }); + test('MySqlTable :: select with `use index` hint on not existed index', async (ctx) => { const { db } = ctx.mysql; const users = mysqlTable('users', { id: serial('id').primaryKey(), name: varchar('name', { length: 100 }).notNull(), - }, () => { - return { - usersTableNameIndex, - }; - }); + }, () => [usersTableNameIndex]); const usersTableNameIndex = index('users_name_index').on(users.name); await db.execute(sql`drop table if exists ${users}`); @@ -4219,12 +4271,7 @@ export function tests(driver?: string) { id: serial('id').primaryKey(), name: varchar('name', { length: 100 }).notNull(), age: int('age').notNull(), - }, () => { - return { - usersTableNameIndex, - usersTableAgeIndex, - }; - }); + }, () => [usersTableNameIndex, usersTableAgeIndex]); const usersTableNameIndex = index('users_name_index').on(users.name); const usersTableAgeIndex = index('users_age_index').on(users.age); @@ -4269,11 +4316,7 @@ export function tests(driver?: string) { id: serial('id').primaryKey(), text: varchar('text', { length: 100 }).notNull(), userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), - }, () => { - return { - postsTableUserIdIndex, - }; - }); + }, () => [postsTableUserIdIndex]); const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); await db.execute(sql`drop table if exists ${posts}`); @@ -4328,7 +4371,57 @@ export function tests(driver?: string) { expect(result).toEqual([{ userId: 4, name: 'David', postId: 4, text: 'David post' }]); }); - test('MySqlTable :: select with join `use index` hint on not existed index', async (ctx) => { + test('MySqlTable :: select with join `use index` hint on 1 index', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), + }); + + const posts = mysqlTable('posts', { + id: serial('id').primaryKey(), + text: varchar('text', { length: 100 }).notNull(), + userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), + }, () => [postsTableUserIdIndex]); + const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); + + await db.execute(sql`drop table if exists ${posts}`); + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql` + create table ${posts} ( + \`id\` serial primary key, + \`text\` varchar(100) not null, + \`user_id\` int not null references users(id) on delete cascade + ) + `); + await db.execute(sql`create index posts_user_id_index ON posts(user_id)`); + + const query = db.select({ + userId: users.id, + name: users.name, + postId: posts.id, + text: posts.text, + }) + .from(users) + .leftJoin(posts, eq(users.id, posts.userId), { + useIndex: postsTableUserIdIndex, + }) + .where(and( + eq(users.name, 'David'), + eq(posts.text, 'David post'), + )).toSQL(); + + expect(query.sql).to.include('USE INDEX (posts_user_id_index)'); + }); + + test('MySqlTable :: select with join `use index` hint on multiple indexes', async (ctx) => { const { db } = ctx.mysql; const users = mysqlTable('users', { @@ -4340,11 +4433,59 @@ export function tests(driver?: string) { id: serial('id').primaryKey(), text: varchar('text', { length: 100 }).notNull(), userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), - }, () => { - return { - postsTableUserIdIndex, - }; + }, () => [postsTableUserIdIndex, postsTableTextIndex]); + const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); + const postsTableTextIndex = index('posts_text_index').on(posts.text); + + await db.execute(sql`drop table if exists ${posts}`); + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql` + create table ${users} ( + \`id\` serial primary key, + \`name\` varchar(100) not null + ) + `); + await db.execute(sql` + create table ${posts} ( + \`id\` serial primary key, + \`text\` varchar(100) not null, + \`user_id\` int not null references users(id) on delete cascade + ) + `); + await db.execute(sql`create index posts_user_id_index ON posts(user_id)`); + await db.execute(sql`create index posts_text_index ON posts(text)`); + + const query = db.select({ + userId: users.id, + name: users.name, + postId: posts.id, + text: posts.text, + }) + .from(users) + .leftJoin(posts, eq(users.id, posts.userId), { + useIndex: [postsTableUserIdIndex, postsTableTextIndex], + }) + .where(and( + eq(users.name, 'David'), + eq(posts.text, 'David post'), + )).toSQL(); + + expect(query.sql).to.include('USE INDEX (posts_user_id_index, posts_text_index)'); + }); + + test('MySqlTable :: select with join `use index` hint on not existed index', async (ctx) => { + const { db } = ctx.mysql; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), }); + + const posts = mysqlTable('posts', { + id: serial('id').primaryKey(), + text: varchar('text', { length: 100 }).notNull(), + userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), + }, () => [postsTableUserIdIndex]); const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); await db.execute(sql`drop table if exists ${posts}`); @@ -4410,12 +4551,7 @@ export function tests(driver?: string) { id: serial('id').primaryKey(), text: varchar('text', { length: 100 }).notNull(), userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), - }, () => { - return { - postsTableUserIdIndex, - postsTableTextIndex, - }; - }); + }, () => [postsTableUserIdIndex, postsTableTextIndex]); const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); const postsTableTextIndex = index('posts_text_index').on(posts.text); @@ -4484,11 +4620,7 @@ export function tests(driver?: string) { id: serial('id').primaryKey(), text: varchar('text', { length: 100 }).notNull(), userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), - }, () => { - return { - postsTableUserIdIndex, - }; - }); + }, () => [postsTableUserIdIndex]); const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); await db.execute(sql`drop table if exists ${posts}`); @@ -4552,11 +4684,7 @@ export function tests(driver?: string) { id: serial('id').primaryKey(), text: varchar('text', { length: 100 }).notNull(), userId: int('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(), - }, () => { - return { - postsTableUserIdIndex, - }; - }); + }, () => [postsTableUserIdIndex]); const postsTableUserIdIndex = index('posts_user_id_index').on(posts.userId); await db.execute(sql`drop table if exists ${posts}`); @@ -4576,22 +4704,6 @@ export function tests(driver?: string) { `); await db.execute(sql`create index posts_user_id_index ON posts(user_id)`); - await db.insert(users).values([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Charlie' }, - { name: 'David' }, - { name: 'Eve' }, - ]); - - await db.insert(posts).values([ - { text: 'Alice post', userId: 1 }, - { text: 'Bob post', userId: 2 }, - { text: 'Charlie post', userId: 3 }, - { text: 'David post', userId: 4 }, - { text: 'Eve post', userId: 5 }, - ]); - const sq = db.select().from(posts).where(eq(posts.userId, 1)).as('sq'); const query = db.select({ @@ -4615,11 +4727,7 @@ export function tests(driver?: string) { const users = mysqlTable('users', { id: serial('id').primaryKey(), name: varchar('name', { length: 100 }).notNull(), - }, () => { - return { - usersTableNameIndex, - }; - }); + }, () => [usersTableNameIndex]); const usersTableNameIndex = index('users_name_index').on(users.name); @@ -4635,14 +4743,6 @@ export function tests(driver?: string) { await db.execute(sql`create index users_name_index ON users(name)`); await db.execute(sql`create view ${usersView} as select * from ${users}`); - await db.insert(users).values([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Charlie' }, - { name: 'David' }, - { name: 'Eve' }, - ]); - // @ts-expect-error const query = db.select().from(usersView, { useIndex: [usersTableNameIndex], @@ -4659,11 +4759,7 @@ export function tests(driver?: string) { const users = mysqlTable('users', { id: serial('id').primaryKey(), name: varchar('name', { length: 100 }).notNull(), - }, () => { - return { - usersTableNameIndex, - }; - }); + }, () => [usersTableNameIndex]); const usersTableNameIndex = index('users_name_index').on(users.name); await db.execute(sql`drop table if exists ${users}`); @@ -4675,14 +4771,6 @@ export function tests(driver?: string) { `); await db.execute(sql`create index users_name_index ON users(name)`); - await db.insert(users).values([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Charlie' }, - { name: 'David' }, - { name: 'Eve' }, - ]); - const sq = db.select().from(users).as('sq'); // @ts-expect-error From 70f1892332d5315c43387508fe465676c75f1939 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 9 Dec 2024 18:51:43 +0200 Subject: [PATCH 431/492] added uuid in funcs --- .../src/services/GeneratorsWrappers.ts | 52 +++++++++++++++++ .../pg/generatorsTest/generators.test.ts | 56 +++++++++++++++++++ .../tests/pg/generatorsTest/pgSchema.ts | 9 +++ 3 files changed, 117 insertions(+) diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts index e72dffba2..06d6adeb5 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -2871,6 +2871,7 @@ export const generatorsFuncs = { /** * generates same given value each time the generator is called. * @param defaultValue - value you want to generate + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -2889,6 +2890,7 @@ export const generatorsFuncs = { * generates values from given array * @param values - array of values you want to generate. can be array of weighted values. * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -2950,6 +2952,7 @@ export const generatorsFuncs = { * precision equals 10 means that values will be accurate to one tenth (1.2, 34.6); * precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67). * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -2971,6 +2974,7 @@ export const generatorsFuncs = { * @param minValue - lower border of range. * @param maxValue - upper border of range. * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -2989,6 +2993,7 @@ export const generatorsFuncs = { /** * generates boolean values(true or false) + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3008,6 +3013,7 @@ export const generatorsFuncs = { * generates date within given range. * @param minDate - lower border of range. * @param maxDate - upper border of range. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3025,6 +3031,8 @@ export const generatorsFuncs = { /** * generates time in 24 hours style. + * @param arraySize - number of elements in each one-dimensional array. + * * @example * ```ts * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ @@ -3041,6 +3049,8 @@ export const generatorsFuncs = { /** * generates timestamps. + * @param arraySize - number of elements in each one-dimensional array. + * * @example * ```ts * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ @@ -3057,6 +3067,8 @@ export const generatorsFuncs = { /** * generates datetime objects. + * @param arraySize - number of elements in each one-dimensional array. + * * @example * ```ts * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ @@ -3073,6 +3085,8 @@ export const generatorsFuncs = { /** * generates years. + * @param arraySize - number of elements in each one-dimensional array. + * * @example * ```ts * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ @@ -3089,6 +3103,7 @@ export const generatorsFuncs = { /** * generates json objects with fixed structure. + * @param arraySize - number of elements in each one-dimensional array. * * json structure can equal this: * ``` @@ -3133,6 +3148,7 @@ export const generatorsFuncs = { * interval example: "1 years 12 days 5 minutes" * * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * @example * ```ts * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ @@ -3150,6 +3166,7 @@ export const generatorsFuncs = { /** * generates random strings. * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3165,9 +3182,30 @@ export const generatorsFuncs = { string: createGenerator(GenerateString), // uniqueString: createGenerator(GenerateUniqueString), + /** + * generates v4 UUID strings if arraySize is not specified, or v4 UUID 1D arrays if it is. + * + * @param arraySize - number of elements in each one-dimensional array. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * uuid: funcs.uuid({ + * arraySize: 4 + * }) + * }, + * }, + * })); + * ``` + */ + uuid: createGenerator(GenerateUUID), + /** * generates person's first names. * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3186,6 +3224,7 @@ export const generatorsFuncs = { /** * generates person's last names. * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3204,6 +3243,7 @@ export const generatorsFuncs = { /** * generates person's full names. * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3221,6 +3261,7 @@ export const generatorsFuncs = { /** * generates unique emails. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3237,6 +3278,7 @@ export const generatorsFuncs = { /** * generates unique phone numbers. + * @param arraySize - number of elements in each one-dimensional array. * * @param template - phone number template, where all '#' symbols will be substituted with generated digits. * @param prefixes - array of any string you want to be your phone number prefixes.(not compatible with template property) @@ -3277,6 +3319,7 @@ export const generatorsFuncs = { /** * generates country's names. * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3295,6 +3338,7 @@ export const generatorsFuncs = { /** * generates city's names. * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3313,6 +3357,7 @@ export const generatorsFuncs = { /** * generates street address. * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3330,6 +3375,7 @@ export const generatorsFuncs = { /** * generates job titles. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3348,6 +3394,7 @@ export const generatorsFuncs = { * generates postal codes. * * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3365,6 +3412,7 @@ export const generatorsFuncs = { /** * generates states of America. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3383,6 +3431,7 @@ export const generatorsFuncs = { * generates company's names. * * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3402,6 +3451,7 @@ export const generatorsFuncs = { * generates 'lorem ipsum' text sentences. * * @param sentencesCount - number of sentences you want to generate as one generated value(string). + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3424,6 +3474,7 @@ export const generatorsFuncs = { * @param maxXValue - upper bound of range for x coordinate. * @param minYValue - lower bound of range for y coordinate. * @param maxYValue - upper bound of range for y coordinate. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts @@ -3457,6 +3508,7 @@ export const generatorsFuncs = { * @param maxBValue - upper bound of range for y parameter. * @param minCValue - lower bound of range for y parameter. * @param maxCValue - upper bound of range for y parameter. + * @param arraySize - number of elements in each one-dimensional array. * * @example * ```ts diff --git a/drizzle-seed/tests/pg/generatorsTest/generators.test.ts b/drizzle-seed/tests/pg/generatorsTest/generators.test.ts index afeb4fcd5..3de2ce99e 100644 --- a/drizzle-seed/tests/pg/generatorsTest/generators.test.ts +++ b/drizzle-seed/tests/pg/generatorsTest/generators.test.ts @@ -615,6 +615,22 @@ beforeAll(async () => { ); `, ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."uuid_table" ( + "uuid" uuid + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."uuid_array_table" ( + "uuid" uuid[] + ); + `, + ); }); afterAll(async () => { @@ -2039,3 +2055,43 @@ test('weightedRandom with unique gens generator test', async () => { 'The weights for the Weighted Random feature must add up to exactly 1. Please review your weights to ensure they total 1 before proceeding', ); }); + +test('uuid generator test', async () => { + await reset(db, { uuidTable: schema.uuidTable }); + await seed(db, { uuidTable: schema.uuidTable }).refine((funcs) => ({ + uuidTable: { + count, + columns: { + uuid: funcs.uuid(), + }, + }, + })); + + const data = await db.select().from(schema.uuidTable); + // every value in each row does not equal undefined. + let predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); + + const uuidStrsSet = new Set(data.map((row) => row.uuid!)); + predicate = uuidStrsSet.size === data.length; + expect(predicate).toBe(true); +}); + +test('uuid array generator test', async () => { + await reset(db, { uuidArrayTable: schema.uuidArrayTable }); + await seed(db, { uuidArrayTable: schema.uuidArrayTable }).refine((funcs) => ({ + uuidArrayTable: { + count, + columns: { + uuid: funcs.uuid({ arraySize: 4 }), + }, + }, + })); + + const data = await db.select().from(schema.uuidArrayTable); + // every value in each row does not equal undefined. + const predicate = data.length !== 0 + && data.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + expect(predicate).toBe(true); +}); diff --git a/drizzle-seed/tests/pg/generatorsTest/pgSchema.ts b/drizzle-seed/tests/pg/generatorsTest/pgSchema.ts index bf6ee4e5f..48902ac6e 100644 --- a/drizzle-seed/tests/pg/generatorsTest/pgSchema.ts +++ b/drizzle-seed/tests/pg/generatorsTest/pgSchema.ts @@ -11,6 +11,7 @@ import { text, time, timestamp, + uuid, varchar, } from 'drizzle-orm/pg-core'; @@ -311,3 +312,11 @@ export const weightedRandomTable = schema.table('weighted_random_table', { export const weightedRandomWithUniqueGensTable = schema.table('weighted_random_with_unique_gens_table', { weightedRandomWithUniqueGens: varchar('weighted_random_with_unique_gens', { length: 256 }).unique(), }); + +export const uuidTable = schema.table('uuid_table', { + uuid: uuid('uuid'), +}); + +export const uuidArrayTable = schema.table('uuid_array_table', { + uuid: uuid('uuid').array(), +}); From 3e25f5fd857b18449eb5ca043cef2412c79ea33c Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 9 Dec 2024 19:31:19 +0200 Subject: [PATCH 432/492] 0.1.3 --- changelogs/drizzle-seed/0.1.3.md | 131 +++++++++++++++++++++++++++++++ drizzle-seed/package.json | 2 +- 2 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 changelogs/drizzle-seed/0.1.3.md diff --git a/changelogs/drizzle-seed/0.1.3.md b/changelogs/drizzle-seed/0.1.3.md new file mode 100644 index 000000000..d7bb7ac72 --- /dev/null +++ b/changelogs/drizzle-seed/0.1.3.md @@ -0,0 +1,131 @@ +## Bug fixes + +- https://github.com/drizzle-team/drizzle-orm/issues/3644 +- seeding a table with columns that have .default(sql``) will result in an error + +## Features + +- added support for postgres uuid columns + +Example + +```ts +import { pgTable, uuid } from "drizzle-orm/pg-core"; +import { drizzle } from "drizzle-orm/node-postgres"; +import { seed } from "drizzle-seed"; + +const users = pgTable("users", { + uuid: uuid("uuid"), +}); + +async function main() { + const db = drizzle(process.env.DATABASE_URL!); + // You can let it seed automatically + // await seed(db, { users }); + + // Alternatively, you can manually specify the generator in refine. + await seed(db, { users }, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + uuid: funcs.uuid(), + }, + }, + })); +} + +main(); +``` + +## + +- added support for postgres array columns + +Example + +```ts +import { pgTable, integer, text, varchar } from "drizzle-orm/pg-core"; +import { drizzle } from "drizzle-orm/node-postgres"; +import { seed } from "drizzle-seed"; + +const users = pgTable("users", { + id: integer().primaryKey(), + name: text().notNull(), + phone_numbers: varchar({ length: 256 }).array(), +}); +``` + +You can specify the `arraySize` parameter in generator options, like `funcs.phoneNumber({ arraySize: 3 })`, to generate 1D arrays. + +```ts +async function main() { + const db = drizzle(process.env.DATABASE_URL!); + await seed(db, { users }, { count: 1000 }).refine((funcs) => ({ + users: { + columns: { + phone_numbers: funcs.phoneNumber({ arraySize: 3 }), + }, + }, + })); +} + +main(); +``` + +Alternatively, you can let it seed automatically, and it will handle arrays of any dimension. + +```ts +async function main() { + const db = drizzle(process.env.DATABASE_URL!); + await seed(db, { users }); +} + +main(); +``` + +## + +- added support for cyclic tables + +You can now seed tables with cyclic relations. + +```ts +import type { AnyPgColumn } from "drizzle-orm/pg-core"; +import { + foreignKey, + integer, + pgTable, + serial, + varchar, +} from "drizzle-orm/pg-core"; + +export const modelTable = pgTable( + "model", + { + id: serial().primaryKey(), + name: varchar().notNull(), + defaultImageId: integer(), + }, + (t) => [ + foreignKey({ + columns: [t.defaultImageId], + foreignColumns: [modelImageTable.id], + }), + ] +); + +export const modelImageTable = pgTable("model_image", { + id: serial().primaryKey(), + url: varchar().notNull(), + caption: varchar(), + modelId: integer() + .notNull() + .references((): AnyPgColumn => modelTable.id), +}); + +async function main() { + const db = drizzle(process.env.DATABASE_URL!); + await seed(db, { modelTable, modelImageTable }); +} + +main(); +``` diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index 60403a004..bfa0e39ad 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-seed", - "version": "0.1.2", + "version": "0.1.3", "main": "index.js", "type": "module", "scripts": { From a9bb8ab82b8bea46debabc27017eb8fc309b8f29 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 10 Dec 2024 09:42:24 -0800 Subject: [PATCH 433/492] Remove unnecessary @internal declarations --- drizzle-typebox/src/column.ts | 1 - drizzle-valibot/src/column.ts | 1 - drizzle-zod/src/column.ts | 1 - 3 files changed, 3 deletions(-) diff --git a/drizzle-typebox/src/column.ts b/drizzle-typebox/src/column.ts index 80e6ff39d..510ba7bbe 100644 --- a/drizzle-typebox/src/column.ts +++ b/drizzle-typebox/src/column.ts @@ -55,7 +55,6 @@ export function mapEnumValues(values: string[]) { return Object.fromEntries(values.map((value) => [value, value])); } -/** @internal */ export function columnToSchema(column: Column, t: typeof typebox): TSchema { let schema!: TSchema; diff --git a/drizzle-valibot/src/column.ts b/drizzle-valibot/src/column.ts index e5716fe1e..5d7a1784e 100644 --- a/drizzle-valibot/src/column.ts +++ b/drizzle-valibot/src/column.ts @@ -55,7 +55,6 @@ export function mapEnumValues(values: string[]) { return Object.fromEntries(values.map((value) => [value, value])); } -/** @internal */ export function columnToSchema(column: Column): v.GenericSchema { let schema!: v.GenericSchema; diff --git a/drizzle-zod/src/column.ts b/drizzle-zod/src/column.ts index 4aae40e7e..d6fff3445 100644 --- a/drizzle-zod/src/column.ts +++ b/drizzle-zod/src/column.ts @@ -50,7 +50,6 @@ export const jsonSchema: z.ZodType = z.lazy(() => ); export const bufferSchema: z.ZodType = z.custom((v) => v instanceof Buffer); // eslint-disable-line no-instanceof/no-instanceof -/** @internal */ export function columnToSchema(column: Column, z: typeof zod): z.ZodTypeAny { let schema!: z.ZodTypeAny; From 1686686d5111648a301680bae7f26d605aabf3de Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 10 Dec 2024 09:43:17 -0800 Subject: [PATCH 434/492] Fix type refinement type mapping in drizzle-zod --- drizzle-zod/src/schema.types.internal.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drizzle-zod/src/schema.types.internal.ts b/drizzle-zod/src/schema.types.internal.ts index 5732e2e0f..8b89187f2 100644 --- a/drizzle-zod/src/schema.types.internal.ts +++ b/drizzle-zod/src/schema.types.internal.ts @@ -39,13 +39,20 @@ export type BuildRefine< : never; type HandleRefinement< + TType extends 'select' | 'insert' | 'update', TRefinement extends z.ZodTypeAny | ((schema: z.ZodTypeAny) => z.ZodTypeAny), TColumn extends Column, -> = TRefinement extends (schema: z.ZodTypeAny) => z.ZodTypeAny - ? TColumn['_']['notNull'] extends true ? ReturnType - : z.ZodNullable> +> = TRefinement extends (schema: any) => z.ZodTypeAny ? (TColumn['_']['notNull'] extends true ? ReturnType + : z.ZodNullable>) extends infer TSchema + ? TType extends 'update' ? z.ZodOptional> : TSchema + : z.ZodTypeAny : TRefinement; +type IsRefinementDefined = TKey extends keyof TRefinements + ? TRefinements[TKey] extends z.ZodTypeAny | ((schema: any) => any) ? true + : false + : false; + export type BuildSchema< TType extends 'select' | 'insert' | 'update', TColumns extends Record, @@ -56,9 +63,8 @@ export type BuildSchema< { [K in keyof TColumns]: TColumns[K] extends infer TColumn extends Column ? TRefinements extends object - ? TRefinements[Assume] extends - infer TRefinement extends z.ZodTypeAny | ((schema: z.ZodTypeAny) => z.ZodTypeAny) - ? HandleRefinement + ? IsRefinementDefined> extends true + ? HandleRefinement], TColumn> : HandleColumn : HandleColumn : TColumns[K] extends infer TObject extends SelectedFieldsFlat | Table | View ? BuildSchema< From 2265f01dabd24649283af1548df46db3865ef382 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 10 Dec 2024 10:09:47 -0800 Subject: [PATCH 435/492] Fix `drizzle-typebox` --- drizzle-typebox/src/schema.types.internal.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drizzle-typebox/src/schema.types.internal.ts b/drizzle-typebox/src/schema.types.internal.ts index beccef94b..e48b764f4 100644 --- a/drizzle-typebox/src/schema.types.internal.ts +++ b/drizzle-typebox/src/schema.types.internal.ts @@ -40,13 +40,20 @@ export type BuildRefine< : never; type HandleRefinement< + TType extends 'select' | 'insert' | 'update', TRefinement extends t.TSchema | ((schema: t.TSchema) => t.TSchema), TColumn extends Column, -> = TRefinement extends (schema: t.TSchema) => t.TSchema - ? TColumn['_']['notNull'] extends true ? ReturnType - : t.TTuple<[ReturnType, t.TNull]> +> = TRefinement extends (schema: any) => t.TSchema ? (TColumn['_']['notNull'] extends true ? ReturnType + : t.TUnion<[ReturnType, t.TNull]>) extends infer TSchema + ? TType extends 'update' ? t.TOptional> : TSchema + : t.TSchema : TRefinement; +type IsRefinementDefined = TKey extends keyof TRefinements + ? TRefinements[TKey] extends t.TSchema | ((schema: any) => any) ? true + : false + : false; + export type BuildSchema< TType extends 'select' | 'insert' | 'update', TColumns extends Record, @@ -57,9 +64,8 @@ export type BuildSchema< { [K in keyof TColumns]: TColumns[K] extends infer TColumn extends Column ? TRefinements extends object - ? TRefinements[Assume] extends - infer TRefinement extends t.TSchema | ((schema: t.TSchema) => t.TSchema) - ? HandleRefinement + ? IsRefinementDefined> extends true + ? HandleRefinement], TColumn> : HandleColumn : HandleColumn : TColumns[K] extends infer TObject extends SelectedFieldsFlat | Table | View ? BuildSchema< From 5dc5b05fb6b4d6b7ba5ac25d99dc8d6bcd833ace Mon Sep 17 00:00:00 2001 From: Sukairo-02 Date: Wed, 11 Dec 2024 05:58:55 +0200 Subject: [PATCH 436/492] Added `| undefined` to optional fields in `insertModel`, `db.update().set()` args, rqb config to allow undefined to still be passed with `exactOptionalPropertyTypes` typescript flag set to `true` (issue #2742) --- .../src/mysql-core/query-builders/update.ts | 3 +- .../src/pg-core/query-builders/update.ts | 3 +- drizzle-orm/src/relations.ts | 43 +++++++++++-------- .../singlestore-core/query-builders/update.ts | 3 +- .../src/sqlite-core/query-builders/update.ts | 3 +- drizzle-orm/src/table.ts | 2 +- 6 files changed, 34 insertions(+), 23 deletions(-) diff --git a/drizzle-orm/src/mysql-core/query-builders/update.ts b/drizzle-orm/src/mysql-core/query-builders/update.ts index 9efc4e325..7c6fd40ab 100644 --- a/drizzle-orm/src/mysql-core/query-builders/update.ts +++ b/drizzle-orm/src/mysql-core/query-builders/update.ts @@ -34,7 +34,8 @@ export type MySqlUpdateSetSource = & { [Key in keyof TTable['$inferInsert']]?: | GetColumnData - | SQL; + | SQL + | undefined; } & {}; diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index c6d04ee35..911916381 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -53,7 +53,8 @@ export type PgUpdateSetSource = [Key in keyof TTable['$inferInsert']]?: | GetColumnData | SQL - | PgColumn; + | PgColumn + | undefined; } & {}; diff --git a/drizzle-orm/src/relations.ts b/drizzle-orm/src/relations.ts index ed49c138f..adaee8076 100644 --- a/drizzle-orm/src/relations.ts +++ b/drizzle-orm/src/relations.ts @@ -214,22 +214,27 @@ export type DBQueryConfig< TTableConfig extends TableRelationalConfig = TableRelationalConfig, > = & { - columns?: { - [K in keyof TTableConfig['columns']]?: boolean; - }; - with?: { - [K in keyof TTableConfig['relations']]?: - | true - | DBQueryConfig< - TTableConfig['relations'][K] extends One ? 'one' : 'many', - false, - TSchema, - FindTableByDBName< + columns?: + | { + [K in keyof TTableConfig['columns']]?: boolean; + } + | undefined; + with?: + | { + [K in keyof TTableConfig['relations']]?: + | true + | DBQueryConfig< + TTableConfig['relations'][K] extends One ? 'one' : 'many', + false, TSchema, - TTableConfig['relations'][K]['referencedTableName'] + FindTableByDBName< + TSchema, + TTableConfig['relations'][K]['referencedTableName'] + > > - >; - }; + | undefined; + } + | undefined; extras?: | Record | (( @@ -238,7 +243,8 @@ export type DBQueryConfig< : TTableConfig['columns'] >, operators: { sql: Operators['sql'] }, - ) => Record); + ) => Record) + | undefined; } & (TRelationType extends 'many' ? & { @@ -260,11 +266,12 @@ export type DBQueryConfig< : TTableConfig['columns'] >, operators: OrderByOperators, - ) => ValueOrArray); - limit?: number | Placeholder; + ) => ValueOrArray) + | undefined; + limit?: number | Placeholder | undefined; } & (TIsRoot extends true ? { - offset?: number | Placeholder; + offset?: number | Placeholder | undefined; } : {}) : {}); diff --git a/drizzle-orm/src/singlestore-core/query-builders/update.ts b/drizzle-orm/src/singlestore-core/query-builders/update.ts index 40ca97662..6a843373c 100644 --- a/drizzle-orm/src/singlestore-core/query-builders/update.ts +++ b/drizzle-orm/src/singlestore-core/query-builders/update.ts @@ -34,7 +34,8 @@ export type SingleStoreUpdateSetSource = & { [Key in keyof TTable['$inferInsert']]?: | GetColumnData - | SQL; + | SQL + | undefined; } & {}; diff --git a/drizzle-orm/src/sqlite-core/query-builders/update.ts b/drizzle-orm/src/sqlite-core/query-builders/update.ts index cc5e4ee30..6915d60a9 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/update.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/update.ts @@ -40,7 +40,8 @@ export type SQLiteUpdateSetSource = [Key in keyof TTable['$inferInsert']]?: | GetColumnData | SQL - | SQLiteColumn; + | SQLiteColumn + | undefined; } & {}; diff --git a/drizzle-orm/src/table.ts b/drizzle-orm/src/table.ts index c843fd519..5f6b0d679 100644 --- a/drizzle-orm/src/table.ts +++ b/drizzle-orm/src/table.ts @@ -174,7 +174,7 @@ export type InferModelFromColumns< TColumns[Key], TConfig['override'] > - ]?: GetColumnData; + ]?: GetColumnData | undefined; } : { [ From df14983b1d72ae445ee3fb21338e7d770722ea84 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Wed, 11 Dec 2024 12:00:53 +0200 Subject: [PATCH 437/492] fix --- drizzle-seed/src/services/SeedService.ts | 3 +-- drizzle-seed/tests/pg/pg.test.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index fd8d8d63c..4ee43a921 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -71,9 +71,8 @@ class SeedService { const orderedTablesNames = this.getOrderedTablesList(tablesInOutRelations); tables = tables.sort((table1, table2) => { const rel = relations.find((rel) => rel.table === table1.name && rel.refTable === table2.name); - if (rel === undefined) return 0; - if (rel.isCyclic) { + if (rel?.isCyclic === true) { const reverseRel = relations.find((rel) => rel.table === table2.name && rel.refTable === table1.name); return this.cyclicTablesCompare(table1, table2, rel, reverseRel); } diff --git a/drizzle-seed/tests/pg/pg.test.ts b/drizzle-seed/tests/pg/pg.test.ts index 7054a07c5..90d6b4fc2 100644 --- a/drizzle-seed/tests/pg/pg.test.ts +++ b/drizzle-seed/tests/pg/pg.test.ts @@ -338,7 +338,15 @@ test("redefine(refine) orders count using 'with' in customers", async () => { }); test("sequential using of 'with'", async () => { - await seed(db, schema, { count: 11 }).refine(() => ({ + const currSchema = { + customers: schema.customers, + details: schema.details, + employees: schema.employees, + orders: schema.orders, + products: schema.products, + suppliers: schema.suppliers, + }; + await seed(db, currSchema, { count: 11 }).refine(() => ({ customers: { count: 4, with: { From 6743980dafe9376f8733fc0865b943e51bd627d0 Mon Sep 17 00:00:00 2001 From: Aleksandr Sherman Date: Wed, 11 Dec 2024 13:37:07 +0200 Subject: [PATCH 438/492] added export for singlestore --- drizzle-kit/src/cli/commands/migrate.ts | 32 +++++++++++++++++++++++++ drizzle-kit/src/cli/schema.ts | 10 ++++++-- drizzle-kit/tests/cli-export.test.ts | 6 ++--- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/drizzle-kit/src/cli/commands/migrate.ts b/drizzle-kit/src/cli/commands/migrate.ts index 279528f11..8c62a5edb 100644 --- a/drizzle-kit/src/cli/commands/migrate.ts +++ b/drizzle-kit/src/cli/commands/migrate.ts @@ -735,6 +735,38 @@ export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => { } }; +export const prepareAndExportSinglestore = async (config: ExportConfig) => { + const schemaPath = config.schema; + + try { + const { prev, cur } = await prepareSingleStoreMigrationSnapshot( + [], + schemaPath, + undefined, + ); + + const validatedPrev = singlestoreSchema.parse(prev); + const validatedCur = singlestoreSchema.parse(cur); + + const squashedPrev = squashSingleStoreScheme(validatedPrev); + const squashedCur = squashSingleStoreScheme(validatedCur); + + const { sqlStatements, _meta } = await applySingleStoreSnapshotsDiff( + squashedPrev, + squashedCur, + tablesResolver, + columnsResolver, + /* singleStoreViewsResolver, */ + validatedPrev, + validatedCur, + ); + + console.log(sqlStatements.join('\n')); + } catch (e) { + console.error(e); + } +}; + export const prepareAndExportMysql = async (config: ExportConfig) => { const schemaPath = config.schema; diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index ba30d57ee..e4204e393 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -766,7 +766,13 @@ export const exportRaw = command({ await assertOrmCoreVersion(); await assertPackages('drizzle-orm'); - const { prepareAndExportPg, prepareAndExportMysql, prepareAndExportSqlite, prepareAndExportLibSQL } = await import( + const { + prepareAndExportPg, + prepareAndExportMysql, + prepareAndExportSqlite, + prepareAndExportLibSQL, + prepareAndExportSinglestore, + } = await import( './commands/migrate' ); @@ -780,7 +786,7 @@ export const exportRaw = command({ } else if (dialect === 'turso') { await prepareAndExportLibSQL(opts); } else if (dialect === 'singlestore') { - await prepareAndExportSqlite(opts); + await prepareAndExportSinglestore(opts); } else { assertUnreachable(dialect); } diff --git a/drizzle-kit/tests/cli-export.test.ts b/drizzle-kit/tests/cli-export.test.ts index 663afafcc..8719ddd6a 100644 --- a/drizzle-kit/tests/cli-export.test.ts +++ b/drizzle-kit/tests/cli-export.test.ts @@ -14,7 +14,7 @@ import { exportRaw } from '../src/cli/schema'; // #4 drizzle-kit export --config=drizzle.config.ts --schema=schema.ts // #5 drizzle-kit export --config=drizzle.config.ts --dialect=postgresql -test('exportRaw #1', async (t) => { +test('export #1', async (t) => { const res = await brotest( exportRaw, '--dialect=postgresql --schema=schema.ts', @@ -29,7 +29,7 @@ test('exportRaw #1', async (t) => { }); }); -test('exportRaw #2', async (t) => { +test('export #2', async (t) => { const res = await brotest(exportRaw, ''); if (res.type !== 'handler') assert.fail(res.type, 'handler'); @@ -41,7 +41,7 @@ test('exportRaw #2', async (t) => { }); // custom config path -test('exportRaw #3', async (t) => { +test('export #3', async (t) => { const res = await brotest(exportRaw, '--config=expo.config.ts'); assert.equal(res.type, 'handler'); if (res.type !== 'handler') assert.fail(res.type, 'handler'); From 7af7983c5567e681138d1d96a8ae364768e511c3 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Wed, 11 Dec 2024 09:27:55 -0800 Subject: [PATCH 439/492] Add additional tests to validators --- drizzle-typebox/tests/mysql.test.ts | 28 +++++++++++++++++++- drizzle-typebox/tests/pg.test.ts | 38 +++++++++++++++++++++++++++- drizzle-typebox/tests/sqlite.test.ts | 28 +++++++++++++++++++- drizzle-valibot/tests/mysql.test.ts | 28 +++++++++++++++++++- drizzle-valibot/tests/pg.test.ts | 38 +++++++++++++++++++++++++++- drizzle-valibot/tests/sqlite.test.ts | 28 +++++++++++++++++++- drizzle-zod/tests/mysql.test.ts | 28 +++++++++++++++++++- drizzle-zod/tests/pg.test.ts | 38 +++++++++++++++++++++++++++- drizzle-zod/tests/sqlite.test.ts | 28 +++++++++++++++++++- 9 files changed, 273 insertions(+), 9 deletions(-) diff --git a/drizzle-typebox/tests/mysql.test.ts b/drizzle-typebox/tests/mysql.test.ts index 213240368..8863f0fb9 100644 --- a/drizzle-typebox/tests/mysql.test.ts +++ b/drizzle-typebox/tests/mysql.test.ts @@ -1,6 +1,6 @@ import { Type as t } from '@sinclair/typebox'; import { type Equal, sql } from 'drizzle-orm'; -import { int, mysqlSchema, mysqlTable, mysqlView, serial, text } from 'drizzle-orm/mysql-core'; +import { customType, int, mysqlSchema, mysqlTable, mysqlView, serial, text } from 'drizzle-orm/mysql-core'; import { test } from 'vitest'; import { jsonSchema } from '~/column.ts'; import { CONSTANTS } from '~/constants.ts'; @@ -207,6 +207,32 @@ test('refine table - select', (tc) => { Expect>(); }); +test('refine table - select with custom data type', (tc) => { + const customText = customType({ dataType: () => 'text' }); + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: customText(), + }); + + const customTextSchema = t.String({ minLength: 1, maxLength: 100 }); + const result = createSelectSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + c4: customTextSchema, + }); + const expected = t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + c4: customTextSchema, + }); + + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + test('refine table - insert', (tc) => { const table = mysqlTable('test', { c1: int(), diff --git a/drizzle-typebox/tests/pg.test.ts b/drizzle-typebox/tests/pg.test.ts index 3e9769aef..8fd8148d8 100644 --- a/drizzle-typebox/tests/pg.test.ts +++ b/drizzle-typebox/tests/pg.test.ts @@ -1,6 +1,16 @@ import { Type as t } from '@sinclair/typebox'; import { type Equal, sql } from 'drizzle-orm'; -import { integer, pgEnum, pgMaterializedView, pgSchema, pgTable, pgView, serial, text } from 'drizzle-orm/pg-core'; +import { + customType, + integer, + pgEnum, + pgMaterializedView, + pgSchema, + pgTable, + pgView, + serial, + text, +} from 'drizzle-orm/pg-core'; import { test } from 'vitest'; import { jsonSchema } from '~/column.ts'; import { CONSTANTS } from '~/constants.ts'; @@ -233,6 +243,32 @@ test('refine table - select', (tc) => { Expect>(); }); +test('refine table - select with custom data type', (tc) => { + const customText = customType({ dataType: () => 'text' }); + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + c4: customText(), + }); + + const customTextSchema = t.String({ minLength: 1, maxLength: 100 }); + const result = createSelectSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + c4: customTextSchema, + }); + const expected = t.Object({ + c1: t.Union([integerSchema, t.Null()]), + c2: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + c4: customTextSchema, + }); + + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + test('refine table - insert', (tc) => { const table = pgTable('test', { c1: integer(), diff --git a/drizzle-typebox/tests/sqlite.test.ts b/drizzle-typebox/tests/sqlite.test.ts index ba2b55002..bce2d8c63 100644 --- a/drizzle-typebox/tests/sqlite.test.ts +++ b/drizzle-typebox/tests/sqlite.test.ts @@ -1,6 +1,6 @@ import { Type as t } from '@sinclair/typebox'; import { type Equal, sql } from 'drizzle-orm'; -import { int, sqliteTable, sqliteView, text } from 'drizzle-orm/sqlite-core'; +import { customType, int, sqliteTable, sqliteView, text } from 'drizzle-orm/sqlite-core'; import { test } from 'vitest'; import { bufferSchema, jsonSchema } from '~/column.ts'; import { CONSTANTS } from '~/constants.ts'; @@ -186,6 +186,32 @@ test('refine table - select', (tc) => { Expect>(); }); +test('refine table - select with custom data type', (tc) => { + const customText = customType({ dataType: () => 'text' }); + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: customText(), + }); + + const customTextSchema = t.String({ minLength: 1, maxLength: 100 }); + const result = createSelectSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + c4: customTextSchema, + }); + const expected = t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + c4: customTextSchema, + }); + + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + test('refine table - insert', (tc) => { const table = sqliteTable('test', { c1: int(), diff --git a/drizzle-valibot/tests/mysql.test.ts b/drizzle-valibot/tests/mysql.test.ts index 5bf9520cb..6578729a4 100644 --- a/drizzle-valibot/tests/mysql.test.ts +++ b/drizzle-valibot/tests/mysql.test.ts @@ -1,5 +1,5 @@ import { type Equal, sql } from 'drizzle-orm'; -import { int, mysqlSchema, mysqlTable, mysqlView, serial, text } from 'drizzle-orm/mysql-core'; +import { customType, int, mysqlSchema, mysqlTable, mysqlView, serial, text } from 'drizzle-orm/mysql-core'; import * as v from 'valibot'; import { test } from 'vitest'; import { jsonSchema } from '~/column.ts'; @@ -210,6 +210,32 @@ test('refine table - select', (t) => { Expect>(); }); +test('refine table - select with custom data type', (t) => { + const customText = customType({ dataType: () => 'text' }); + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: customText(), + }); + + const customTextSchema = v.pipe(v.string(), v.minLength(1), v.maxLength(100)); + const result = createSelectSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + c4: customTextSchema, + }); + const expected = v.object({ + c1: v.nullable(intSchema), + c2: v.pipe(intSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + c4: customTextSchema, + }); + + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + test('refine table - insert', (t) => { const table = mysqlTable('test', { c1: int(), diff --git a/drizzle-valibot/tests/pg.test.ts b/drizzle-valibot/tests/pg.test.ts index 4d1651a7c..ea2bf2dd0 100644 --- a/drizzle-valibot/tests/pg.test.ts +++ b/drizzle-valibot/tests/pg.test.ts @@ -1,5 +1,15 @@ import { type Equal, sql } from 'drizzle-orm'; -import { integer, pgEnum, pgMaterializedView, pgSchema, pgTable, pgView, serial, text } from 'drizzle-orm/pg-core'; +import { + customType, + integer, + pgEnum, + pgMaterializedView, + pgSchema, + pgTable, + pgView, + serial, + text, +} from 'drizzle-orm/pg-core'; import * as v from 'valibot'; import { test } from 'vitest'; import { jsonSchema } from '~/column.ts'; @@ -234,6 +244,32 @@ test('refine table - select', (t) => { Expect>(); }); +test('refine table - select with custom data type', (t) => { + const customText = customType({ dataType: () => 'text' }); + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + c4: customText(), + }); + + const customTextSchema = v.pipe(v.string(), v.minLength(1), v.maxLength(100)); + const result = createSelectSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + c4: customTextSchema, + }); + const expected = v.object({ + c1: v.nullable(integerSchema), + c2: v.pipe(integerSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + c4: customTextSchema, + }); + + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + test('refine table - insert', (t) => { const table = pgTable('test', { c1: integer(), diff --git a/drizzle-valibot/tests/sqlite.test.ts b/drizzle-valibot/tests/sqlite.test.ts index 7eb5fc7bf..14e6b4bd6 100644 --- a/drizzle-valibot/tests/sqlite.test.ts +++ b/drizzle-valibot/tests/sqlite.test.ts @@ -1,5 +1,5 @@ import { type Equal, sql } from 'drizzle-orm'; -import { int, sqliteTable, sqliteView, text } from 'drizzle-orm/sqlite-core'; +import { customType, int, sqliteTable, sqliteView, text } from 'drizzle-orm/sqlite-core'; import * as v from 'valibot'; import { test } from 'vitest'; import { bufferSchema, jsonSchema } from '~/column.ts'; @@ -187,6 +187,32 @@ test('refine table - select', (t) => { Expect>(); }); +test('refine table - select with custom data type', (t) => { + const customText = customType({ dataType: () => 'text' }); + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: customText(), + }); + + const customTextSchema = v.pipe(v.string(), v.minLength(1), v.maxLength(100)); + const result = createSelectSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + c4: customTextSchema, + }); + const expected = v.object({ + c1: v.nullable(intSchema), + c2: v.pipe(intSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + c4: customTextSchema, + }); + + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + test('refine table - insert', (t) => { const table = sqliteTable('test', { c1: int(), diff --git a/drizzle-zod/tests/mysql.test.ts b/drizzle-zod/tests/mysql.test.ts index 37c9b7e64..73ba48dae 100644 --- a/drizzle-zod/tests/mysql.test.ts +++ b/drizzle-zod/tests/mysql.test.ts @@ -1,5 +1,5 @@ import { type Equal, sql } from 'drizzle-orm'; -import { int, mysqlSchema, mysqlTable, mysqlView, serial, text } from 'drizzle-orm/mysql-core'; +import { customType, int, mysqlSchema, mysqlTable, mysqlView, serial, text } from 'drizzle-orm/mysql-core'; import { test } from 'vitest'; import { z } from 'zod'; import { jsonSchema } from '~/column.ts'; @@ -201,6 +201,32 @@ test('refine table - select', (t) => { Expect>(); }); +test('refine table - select with custom data type', (t) => { + const customText = customType({ dataType: () => 'text' }); + const table = mysqlTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: customText(), + }); + + const customTextSchema = z.string().min(1).max(100); + const result = createSelectSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + c4: customTextSchema, + }); + const expected = z.object({ + c1: intSchema.nullable(), + c2: intSchema.max(1000), + c3: z.string().transform(Number), + c4: customTextSchema, + }); + + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + test('refine table - insert', (t) => { const table = mysqlTable('test', { c1: int(), diff --git a/drizzle-zod/tests/pg.test.ts b/drizzle-zod/tests/pg.test.ts index dc703b4fc..7964f65d6 100644 --- a/drizzle-zod/tests/pg.test.ts +++ b/drizzle-zod/tests/pg.test.ts @@ -1,5 +1,15 @@ import { type Equal, sql } from 'drizzle-orm'; -import { integer, pgEnum, pgMaterializedView, pgSchema, pgTable, pgView, serial, text } from 'drizzle-orm/pg-core'; +import { + customType, + integer, + pgEnum, + pgMaterializedView, + pgSchema, + pgTable, + pgView, + serial, + text, +} from 'drizzle-orm/pg-core'; import { test } from 'vitest'; import { z } from 'zod'; import { jsonSchema } from '~/column.ts'; @@ -234,6 +244,32 @@ test('refine table - select', (t) => { Expect>(); }); +test('refine table - select with custom data type', (t) => { + const customText = customType({ dataType: () => 'text' }); + const table = pgTable('test', { + c1: integer(), + c2: integer().notNull(), + c3: integer().notNull(), + c4: customText(), + }); + + const customTextSchema = z.string().min(1).max(100); + const result = createSelectSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + c4: customTextSchema, + }); + const expected = z.object({ + c1: integerSchema.nullable(), + c2: integerSchema.max(1000), + c3: z.string().transform(Number), + c4: customTextSchema, + }); + + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + test('refine table - insert', (t) => { const table = pgTable('test', { c1: integer(), diff --git a/drizzle-zod/tests/sqlite.test.ts b/drizzle-zod/tests/sqlite.test.ts index 45e64bbde..bb0f254b5 100644 --- a/drizzle-zod/tests/sqlite.test.ts +++ b/drizzle-zod/tests/sqlite.test.ts @@ -1,5 +1,5 @@ import { type Equal, sql } from 'drizzle-orm'; -import { int, sqliteTable, sqliteView, text } from 'drizzle-orm/sqlite-core'; +import { customType, int, sqliteTable, sqliteView, text } from 'drizzle-orm/sqlite-core'; import { test } from 'vitest'; import { z } from 'zod'; import { bufferSchema, jsonSchema } from '~/column.ts'; @@ -182,6 +182,32 @@ test('refine table - select', (t) => { Expect>(); }); +test('refine table - select with custom data type', (t) => { + const customText = customType({ dataType: () => 'text' }); + const table = sqliteTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: customText(), + }); + + const customTextSchema = z.string().min(1).max(100); + const result = createSelectSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + c4: customTextSchema, + }); + const expected = z.object({ + c1: intSchema.nullable(), + c2: intSchema.max(1000), + c3: z.string().transform(Number), + c4: customTextSchema, + }); + + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + test('refine table - insert', (t) => { const table = sqliteTable('test', { c1: int(), From 2e49ebc0a987e4526683b508c0580af240613b9b Mon Sep 17 00:00:00 2001 From: Mario564 Date: Wed, 11 Dec 2024 09:51:11 -0800 Subject: [PATCH 440/492] Fix Typebox SQLite test --- drizzle-typebox/tests/sqlite.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-typebox/tests/sqlite.test.ts b/drizzle-typebox/tests/sqlite.test.ts index bce2d8c63..2b5083b92 100644 --- a/drizzle-typebox/tests/sqlite.test.ts +++ b/drizzle-typebox/tests/sqlite.test.ts @@ -203,7 +203,7 @@ test('refine table - select with custom data type', (tc) => { }); const expected = t.Object({ c1: t.Union([intSchema, t.Null()]), - c2: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), + c2: t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: 1000 }), c3: t.Integer({ minimum: 1, maximum: 10 }), c4: customTextSchema, }); From 8cf6a821ebee5a41eba034b87bccbdb4fa15e33f Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 11 Dec 2024 20:00:34 +0200 Subject: [PATCH 441/492] Export SeedService --- drizzle-seed/src/index.ts | 11 ++++++++++- drizzle-seed/src/services/SeedService.ts | 4 +--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 8596863fb..603512fd3 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -11,7 +11,7 @@ import { BaseSQLiteDatabase, getTableConfig as getSqliteTableConfig, SQLiteTable import type { AbstractGenerator } from './services/GeneratorsWrappers.ts'; import { generatorsFuncs } from './services/GeneratorsWrappers.ts'; -import seedService from './services/SeedService.ts'; +import { SeedService } from './services/SeedService.ts'; import type { DrizzleStudioObjectType, DrizzleStudioRelationType } from './types/drizzleStudio.ts'; import type { RefinementsType } from './types/seedService.ts'; import type { Column, Relation, RelationWithReferences, Table } from './types/tables.ts'; @@ -251,6 +251,8 @@ export async function seedForDrizzleStudio( ? schemasRefinements[schemaName] : undefined; + const seedService = new SeedService(); + const generatedTablesGenerators = seedService.generatePossibleGenerators( sqlDialect, tables, @@ -489,6 +491,8 @@ const seedPostgres = async ( options: { count?: number; seed?: number } = {}, refinements?: RefinementsType, ) => { + const seedService = new SeedService(); + const { tables, relations, tableRelations } = getPostgresInfo(schema); const generatedTablesGenerators = seedService.generatePossibleGenerators( 'postgresql', @@ -740,6 +744,8 @@ const seedMySql = async ( ) => { const { tables, relations, tableRelations } = getMySqlInfo(schema); + const seedService = new SeedService(); + const generatedTablesGenerators = seedService.generatePossibleGenerators( 'mysql', tables, @@ -927,6 +933,8 @@ const seedSqlite = async ( ) => { const { tables, relations, tableRelations } = getSqliteInfo(schema); + const seedService = new SeedService(); + const generatedTablesGenerators = seedService.generatePossibleGenerators( 'sqlite', tables, @@ -1072,3 +1080,4 @@ export { default as cities } from './datasets/cityNames.ts'; export { default as countries } from './datasets/countries.ts'; export { default as firstNames } from './datasets/firstNames.ts'; export { default as lastNames } from './datasets/lastNames.ts'; +export { SeedService } from './services/SeedService.ts'; diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 4ee43a921..87569babb 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -42,7 +42,7 @@ import { } from './GeneratorsWrappers.ts'; import { equalSets, generateHashFromString } from './utils.ts'; -class SeedService { +export class SeedService { static readonly [entityKind]: string = 'SeedService'; private defaultCountForTable = 10; @@ -1470,5 +1470,3 @@ class SeedService { } }; } - -export default new SeedService(); From 54d5e5e1b3b468944a78723c1da80d54f86dd53e Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 11 Dec 2024 20:04:57 +0200 Subject: [PATCH 442/492] Release Notes --- changelogs/drizzle-orm/0.38.1.md | 1 + drizzle-orm/package.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 changelogs/drizzle-orm/0.38.1.md diff --git a/changelogs/drizzle-orm/0.38.1.md b/changelogs/drizzle-orm/0.38.1.md new file mode 100644 index 000000000..1ee83b233 --- /dev/null +++ b/changelogs/drizzle-orm/0.38.1.md @@ -0,0 +1 @@ +- Closed [[FEATURE]: Add more flexible typing for usage with exactOptionalPropertyTypes](https://github.com/drizzle-team/drizzle-orm/issues/2742) \ No newline at end of file diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index c7528fdbe..64d2ab601 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.38.0", + "version": "0.38.1", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -204,4 +204,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} +} \ No newline at end of file From d379dcf7a689379b93c401546a5d1b3aa863c819 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 11 Dec 2024 20:05:12 +0200 Subject: [PATCH 443/492] dprint --- drizzle-orm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 64d2ab601..a73b258f6 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -204,4 +204,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} \ No newline at end of file +} From 3572f210b46a884ca26eee2296bf9cc935694fbc Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 13 Dec 2024 17:43:36 +0200 Subject: [PATCH 444/492] Add release notes --- changelogs/drizzle-kit/0.30.1.md | 35 +++++++++++++++++++ changelogs/drizzle-orm/0.38.2.md | 58 ++++++++++++++++++++++++++++++++ drizzle-kit/package.json | 2 +- drizzle-orm/package.json | 2 +- 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 changelogs/drizzle-kit/0.30.1.md create mode 100644 changelogs/drizzle-orm/0.38.2.md diff --git a/changelogs/drizzle-kit/0.30.1.md b/changelogs/drizzle-kit/0.30.1.md new file mode 100644 index 000000000..1b671312d --- /dev/null +++ b/changelogs/drizzle-kit/0.30.1.md @@ -0,0 +1,35 @@ +# New Features + +### `drizzle-kit export` + +To make drizzle-kit integration with other migration tools, like Atlas much easier, we've prepared a new command called `export`. It will translate your drizzle schema in SQL representation(DDL) statements and outputs to the console + +```ts +// schema.ts +import { pgTable, serial, text } from 'drizzle-orm/pg-core' + +export const users = pgTable('users', { + id: serial('id').primaryKey(), + email: text('email').notNull(), + name: text('name') +}); +``` +Running +```bash +npx drizzle-kit export +``` + +will output this string to console +```bash +CREATE TABLE "users" ( + "id" serial PRIMARY KEY NOT NULL, + "email" text NOT NULL, + "name" text +); +``` + +By default, the only option for now is `--sql`, so the output format will be SQL DDL statements. In the future, we will support additional output formats to accommodate more migration tools + +```bash +npx drizzle-kit export --sql +``` \ No newline at end of file diff --git a/changelogs/drizzle-orm/0.38.2.md b/changelogs/drizzle-orm/0.38.2.md new file mode 100644 index 000000000..50fb31429 --- /dev/null +++ b/changelogs/drizzle-orm/0.38.2.md @@ -0,0 +1,58 @@ +# New features + +## `USE INDEX`, `FORCE INDEX` and `IGNORE INDEX` for MySQL + +In MySQL, the statements USE INDEX, FORCE INDEX, and IGNORE INDEX are hints used in SQL queries to influence how the query optimizer selects indexes. These hints provide fine-grained control over index usage, helping optimize performance when the default behavior of the optimizer is not ideal. + +### Use Index + +The `USE INDEX` hint suggests to the optimizer which indexes to consider when processing the query. The optimizer is not forced to use these indexes but will prioritize them if they are suitable. + +```ts +export const users = mysqlTable('users', { + id: int('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), +}, () => [usersTableNameIndex]); + +const usersTableNameIndex = index('users_name_index').on(users.name); + +await db.select() + .from(users, { useIndex: usersTableNameIndex }) + .where(eq(users.name, 'David')); +``` + +### Ignore Index + +The `IGNORE INDEX` hint tells the optimizer to avoid using specific indexes for the query. MySQL will consider all other indexes (if any) or perform a full table scan if necessary. + +```ts +export const users = mysqlTable('users', { + id: int('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), +}, () => [usersTableNameIndex]); + +const usersTableNameIndex = index('users_name_index').on(users.name); + +await db.select() + .from(users, { ignoreIndex: usersTableNameIndex }) + .where(eq(users.name, 'David')); +``` + +### Force Index + +The `FORCE INDEX` hint forces the optimizer to use the specified index(es) for the query. If the specified index cannot be used, MySQL will not fall back to other indexes; it might resort to a full table scan instead. + +```ts copy +export const users = mysqlTable('users', { + id: int('id').primaryKey(), + name: varchar('name', { length: 100 }).notNull(), +}, () => [usersTableNameIndex]); + +const usersTableNameIndex = index('users_name_index').on(users.name); + +await db.select() + .from(users, { forceIndex: usersTableNameIndex }) + .where(eq(users.name, 'David')); +``` + +You can also combine those hints and use multiple indexes in a query if you need \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 7d3debd1f..32a2c48de 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.30.0", + "version": "0.30.1", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index a73b258f6..72e641467 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.38.1", + "version": "0.38.2", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { From e13844c7f32a4fc046b3a9f4b56c2f3988a2919e Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Fri, 13 Dec 2024 18:02:03 +0200 Subject: [PATCH 445/492] support varchar for postgres using sql column type --- drizzle-seed/src/datasets/adjectives.ts | 2 + drizzle-seed/src/datasets/cityNames.ts | 2 + .../src/datasets/companyNameSuffixes.ts | 2 + drizzle-seed/src/datasets/countries.ts | 2 + drizzle-seed/src/datasets/emailDomains.ts | 2 + drizzle-seed/src/datasets/firstNames.ts | 2 + drizzle-seed/src/datasets/jobsTitles.ts | 2 + drizzle-seed/src/datasets/lastNames.ts | 2 + .../src/datasets/loremIpsumSentences.ts | 2 + drizzle-seed/src/datasets/states.ts | 2 + drizzle-seed/src/datasets/streetSuffix.ts | 2 + drizzle-seed/src/index.ts | 55 ++- .../src/services/GeneratorsWrappers.ts | 110 +++-- drizzle-seed/src/services/SeedService.ts | 392 ++++++++---------- drizzle-seed/src/types/tables.ts | 6 + 15 files changed, 332 insertions(+), 253 deletions(-) diff --git a/drizzle-seed/src/datasets/adjectives.ts b/drizzle-seed/src/datasets/adjectives.ts index c2b152af0..880e52636 100644 --- a/drizzle-seed/src/datasets/adjectives.ts +++ b/drizzle-seed/src/datasets/adjectives.ts @@ -4844,3 +4844,5 @@ export default [ 'zonked', 'zoological', ]; + +export const maxStringLength = 22; diff --git a/drizzle-seed/src/datasets/cityNames.ts b/drizzle-seed/src/datasets/cityNames.ts index 780b55213..3ea80747e 100644 --- a/drizzle-seed/src/datasets/cityNames.ts +++ b/drizzle-seed/src/datasets/cityNames.ts @@ -42857,3 +42857,5 @@ export default [ 'Garches', 'Chemini', ]; + +export const maxStringLength = 49; diff --git a/drizzle-seed/src/datasets/companyNameSuffixes.ts b/drizzle-seed/src/datasets/companyNameSuffixes.ts index ae8ce6163..1ce31a9c3 100644 --- a/drizzle-seed/src/datasets/companyNameSuffixes.ts +++ b/drizzle-seed/src/datasets/companyNameSuffixes.ts @@ -25,3 +25,5 @@ export default [ 'Co.', 'SCC', ]; + +export const maxStringLength = 7; diff --git a/drizzle-seed/src/datasets/countries.ts b/drizzle-seed/src/datasets/countries.ts index 4808fc5e5..eb1c001d0 100644 --- a/drizzle-seed/src/datasets/countries.ts +++ b/drizzle-seed/src/datasets/countries.ts @@ -169,3 +169,5 @@ export default [ 'Yemen', 'Zambia', ]; + +export const maxStringLength = 30; diff --git a/drizzle-seed/src/datasets/emailDomains.ts b/drizzle-seed/src/datasets/emailDomains.ts index 9904aad3e..ea323ed41 100644 --- a/drizzle-seed/src/datasets/emailDomains.ts +++ b/drizzle-seed/src/datasets/emailDomains.ts @@ -22,3 +22,5 @@ export default [ 'ymail.com', 'libero.it', ]; + +export const maxStringLength = 14; diff --git a/drizzle-seed/src/datasets/firstNames.ts b/drizzle-seed/src/datasets/firstNames.ts index 7ca0ff928..d719aa4e2 100644 --- a/drizzle-seed/src/datasets/firstNames.ts +++ b/drizzle-seed/src/datasets/firstNames.ts @@ -30277,3 +30277,5 @@ export default [ 'Lavasia', 'Laniqua', ]; + +export const maxStringLength = 15; diff --git a/drizzle-seed/src/datasets/jobsTitles.ts b/drizzle-seed/src/datasets/jobsTitles.ts index 3a38e3244..e7993da2a 100644 --- a/drizzle-seed/src/datasets/jobsTitles.ts +++ b/drizzle-seed/src/datasets/jobsTitles.ts @@ -150,3 +150,5 @@ export default [ 'Legal secretary', 'Market analyst', ]; + +export const maxStringLength = 35; diff --git a/drizzle-seed/src/datasets/lastNames.ts b/drizzle-seed/src/datasets/lastNames.ts index 117c5fe28..9d35f7cf7 100644 --- a/drizzle-seed/src/datasets/lastNames.ts +++ b/drizzle-seed/src/datasets/lastNames.ts @@ -50001,3 +50001,5 @@ export default [ 'Thagard', 'Leavelle', ]; + +export const maxStringLength = 15; diff --git a/drizzle-seed/src/datasets/loremIpsumSentences.ts b/drizzle-seed/src/datasets/loremIpsumSentences.ts index f03277d86..64fe59f71 100644 --- a/drizzle-seed/src/datasets/loremIpsumSentences.ts +++ b/drizzle-seed/src/datasets/loremIpsumSentences.ts @@ -1637,3 +1637,5 @@ export default [ 'Sed gravida enim quis nunc interdum imperdiet.', 'Proin cursus odio ac dolor blandit, quis sollicitudin ante rutrum.', ]; + +export const maxStringLength = 190; diff --git a/drizzle-seed/src/datasets/states.ts b/drizzle-seed/src/datasets/states.ts index 1de77160d..cd66cf330 100644 --- a/drizzle-seed/src/datasets/states.ts +++ b/drizzle-seed/src/datasets/states.ts @@ -50,3 +50,5 @@ export default [ 'Wisconsin', 'Wyoming', ]; + +export const maxStringLength = 14; diff --git a/drizzle-seed/src/datasets/streetSuffix.ts b/drizzle-seed/src/datasets/streetSuffix.ts index e9b20c392..90a70c2c6 100644 --- a/drizzle-seed/src/datasets/streetSuffix.ts +++ b/drizzle-seed/src/datasets/streetSuffix.ts @@ -198,3 +198,5 @@ export default [ 'Well', 'Wells', ]; + +export const maxStringLength = 10; diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 8596863fb..4f72080ab 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -222,6 +222,8 @@ export async function seedForDrizzleStudio( name: col.name, dataType: 'string', columnType: col.type, + // TODO: revise later + typeParams: {}, default: col.default, hasDefault: col.default === undefined ? false : true, isUnique: col.isUnique === undefined ? false : col.isUnique, @@ -322,7 +324,7 @@ export async function seedForDrizzleStudio( export function seed< DB extends | PgDatabase - | MySqlDatabase + | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { [key: string]: @@ -415,7 +417,7 @@ const seedFunc = async ( export async function reset< DB extends | PgDatabase - | MySqlDatabase + | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { [key: string]: @@ -604,7 +606,8 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { ): Column['baseColumn'] => { const baseColumnResult: Column['baseColumn'] = { name: baseColumn.name, - columnType: baseColumn.columnType.replace('Pg', '').toLowerCase(), + columnType: baseColumn.getSQLType(), + typeParams: getTypeParams(baseColumn.getSQLType()), dataType: baseColumn.dataType, size: (baseColumn as PgArray).size, hasDefault: baseColumn.hasDefault, @@ -619,12 +622,54 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { return baseColumnResult; }; + const getTypeParams = (sqlType: string) => { + // get type params and set only type + const typeParams: Column['typeParams'] = {}; + + // handle dimensions + if (sqlType.includes('[')) { + const match = sqlType.match(/\[\w*]/g); + if (match) { + typeParams['dimensions'] = match.length; + } + } + + if ( + sqlType.startsWith('numeric') + || sqlType.startsWith('decimal') + || sqlType.startsWith('double precision') + || sqlType.startsWith('real') + ) { + const match = sqlType.match(/\((\d+),(\d+)\)/); + if (match) { + typeParams['precision'] = Number(match[1]); + typeParams['scale'] = Number(match[2]); + } + } else if ( + sqlType.startsWith('varchar') + || sqlType.startsWith('bpchar') + || sqlType.startsWith('char') + || sqlType.startsWith('bit') + || sqlType.startsWith('time') + || sqlType.startsWith('timestamp') + || sqlType.startsWith('interval') + ) { + const match = sqlType.match(/\((\d+)\)/); + if (match) { + typeParams['length'] = Number(match[1]); + } + } + + return typeParams; + }; + // console.log(tableConfig.columns); tables.push({ name: dbToTsTableNamesMap[tableConfig.name] as string, columns: tableConfig.columns.map((column) => ({ name: dbToTsColumnNamesMap[column.name] as string, - columnType: column.columnType.replace('Pg', '').toLowerCase(), + columnType: column.getSQLType(), + typeParams: getTypeParams(column.getSQLType()), dataType: column.dataType, size: (column as PgArray).size, hasDefault: column.hasDefault, @@ -852,6 +897,7 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { columns: tableConfig.columns.map((column) => ({ name: dbToTsColumnNamesMap[column.name] as string, columnType: column.columnType.replace('MySql', '').toLowerCase(), + typeParams: {}, dataType: column.dataType, hasDefault: column.hasDefault, default: column.default, @@ -1039,6 +1085,7 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { columns: tableConfig.columns.map((column) => ({ name: dbToTsColumnNamesMap[column.name] as string, columnType: column.columnType.replace('SQLite', '').toLowerCase(), + typeParams: {}, dataType: column.dataType, hasDefault: column.hasDefault, default: column.default, diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts index 06d6adeb5..a1a751f9a 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -24,6 +24,7 @@ export abstract class AbstractGenerator { public timeSpent?: number; public arraySize?: number; public baseColumnDataType?: string; + public length?: number; constructor(public params: T) {} @@ -1337,14 +1338,26 @@ export class GenerateString extends AbstractGenerator<{ }> { static override readonly [entityKind]: string = 'GenerateString'; - private state: { rng: prand.RandomGenerator } | undefined; + private state: { + rng: prand.RandomGenerator; + minStringLength: number; + maxStringLength: number; + } | undefined; override uniqueVersionOfGen = GenerateUniqueString; override init({ count, seed }: { count: number; seed: number }) { super.init({ count, seed }); + let minStringLength = 8; + let maxStringLength = 20; + if (this.length !== undefined) { + maxStringLength = this.length; + if (maxStringLength === 1) minStringLength = maxStringLength; + if (maxStringLength < minStringLength) minStringLength = 1; + } + const rng = prand.xoroshiro128plus(seed); - this.state = { rng }; + this.state = { rng, minStringLength, maxStringLength }; } generate() { @@ -1352,8 +1365,8 @@ export class GenerateString extends AbstractGenerator<{ throw new Error('state is not defined.'); } - const minStringLength = 7; - const maxStringLength = 20; + const minStringLength = this.state.minStringLength, + maxStringLength = this.state.maxStringLength; const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; let idx: number, strLength: number, @@ -1380,12 +1393,31 @@ export class GenerateString extends AbstractGenerator<{ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean }> { static override readonly [entityKind]: string = 'GenerateUniqueString'; - private state: { rng: prand.RandomGenerator } | undefined; + private state: { + rng: prand.RandomGenerator; + minStringLength: number; + maxStringLength: number; + } | undefined; public override isUnique = true; - override init({ seed }: { seed: number }) { + override init({ seed, count }: { seed: number; count: number }) { const rng = prand.xoroshiro128plus(seed); - this.state = { rng }; + + let minStringLength = 8; + let maxStringLength = 20; + // TODO: revise later + if (this.length !== undefined) { + maxStringLength = this.length; + if (maxStringLength === 1 || maxStringLength < minStringLength) minStringLength = maxStringLength; + } + + if (maxStringLength < count.toString(16).length) { + throw new Error( + `You can't generate ${count} unique strings, with a maximum string length of ${maxStringLength}.`, + ); + } + + this.state = { rng, minStringLength, maxStringLength }; } generate({ i }: { i: number }) { @@ -1393,8 +1425,8 @@ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean throw new Error('state is not defined.'); } - const minStringLength = 7; - const maxStringLength = 20; + const minStringLength = this.state.minStringLength, + maxStringLength = this.state.maxStringLength; const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; let idx: number, strLength: number; @@ -1416,7 +1448,7 @@ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean currStr += stringChars[idx]; } - return currStr.slice(0, 4) + uniqueStr + currStr.slice(4); + return uniqueStr + currStr; } } @@ -2871,7 +2903,7 @@ export const generatorsFuncs = { /** * generates same given value each time the generator is called. * @param defaultValue - value you want to generate - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -2890,7 +2922,7 @@ export const generatorsFuncs = { * generates values from given array * @param values - array of values you want to generate. can be array of weighted values. * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -2952,7 +2984,7 @@ export const generatorsFuncs = { * precision equals 10 means that values will be accurate to one tenth (1.2, 34.6); * precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67). * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -2974,7 +3006,7 @@ export const generatorsFuncs = { * @param minValue - lower border of range. * @param maxValue - upper border of range. * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -2993,7 +3025,7 @@ export const generatorsFuncs = { /** * generates boolean values(true or false) - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3013,7 +3045,7 @@ export const generatorsFuncs = { * generates date within given range. * @param minDate - lower border of range. * @param maxDate - upper border of range. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3031,7 +3063,7 @@ export const generatorsFuncs = { /** * generates time in 24 hours style. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3049,7 +3081,7 @@ export const generatorsFuncs = { /** * generates timestamps. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3067,7 +3099,7 @@ export const generatorsFuncs = { /** * generates datetime objects. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3085,7 +3117,7 @@ export const generatorsFuncs = { /** * generates years. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3103,7 +3135,7 @@ export const generatorsFuncs = { /** * generates json objects with fixed structure. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * json structure can equal this: * ``` @@ -3148,7 +3180,7 @@ export const generatorsFuncs = { * interval example: "1 years 12 days 5 minutes" * * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * @example * ```ts * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ @@ -3166,7 +3198,7 @@ export const generatorsFuncs = { /** * generates random strings. * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3185,7 +3217,7 @@ export const generatorsFuncs = { /** * generates v4 UUID strings if arraySize is not specified, or v4 UUID 1D arrays if it is. * - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3205,7 +3237,7 @@ export const generatorsFuncs = { /** * generates person's first names. * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3224,7 +3256,7 @@ export const generatorsFuncs = { /** * generates person's last names. * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3243,7 +3275,7 @@ export const generatorsFuncs = { /** * generates person's full names. * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3261,7 +3293,7 @@ export const generatorsFuncs = { /** * generates unique emails. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3278,7 +3310,7 @@ export const generatorsFuncs = { /** * generates unique phone numbers. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @param template - phone number template, where all '#' symbols will be substituted with generated digits. * @param prefixes - array of any string you want to be your phone number prefixes.(not compatible with template property) @@ -3319,7 +3351,7 @@ export const generatorsFuncs = { /** * generates country's names. * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3338,7 +3370,7 @@ export const generatorsFuncs = { /** * generates city's names. * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3357,7 +3389,7 @@ export const generatorsFuncs = { /** * generates street address. * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3375,7 +3407,7 @@ export const generatorsFuncs = { /** * generates job titles. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3394,7 +3426,7 @@ export const generatorsFuncs = { * generates postal codes. * * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3412,7 +3444,7 @@ export const generatorsFuncs = { /** * generates states of America. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3431,7 +3463,7 @@ export const generatorsFuncs = { * generates company's names. * * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3451,7 +3483,7 @@ export const generatorsFuncs = { * generates 'lorem ipsum' text sentences. * * @param sentencesCount - number of sentences you want to generate as one generated value(string). - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3474,7 +3506,7 @@ export const generatorsFuncs = { * @param maxXValue - upper bound of range for x coordinate. * @param minYValue - lower bound of range for y coordinate. * @param maxYValue - upper bound of range for y coordinate. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts @@ -3508,7 +3540,7 @@ export const generatorsFuncs = { * @param maxBValue - upper bound of range for y parameter. * @param minCValue - lower bound of range for y parameter. * @param maxCValue - upper bound of range for y parameter. - * @param arraySize - number of elements in each one-dimensional array. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) * * @example * ```ts diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 4ee43a921..579d070a6 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -252,7 +252,6 @@ class SeedService { } if (columnPossibleGenerator.generator === undefined) { - console.log(col); throw new Error( `column with type ${col.columnType} is not supported for now.`, ); @@ -260,6 +259,7 @@ class SeedService { columnPossibleGenerator.generator.isUnique = col.isUnique; columnPossibleGenerator.generator.dataType = col.dataType; + columnPossibleGenerator.generator.length = col.typeParams.length; tablePossibleGenerators.columnsPossibleGenerators.push( columnPossibleGenerator, @@ -432,263 +432,235 @@ class SeedService { table: Table, col: Column, ) => { - let generator: AbstractGenerator | undefined; + const pickGenerator = (table: Table, col: Column) => { + // ARRAY + if (col.columnType.match(/\[\w*]/g) !== null && col.baseColumn !== undefined) { + const baseColumnGen = this.pickGeneratorForPostgresColumn(table, col.baseColumn!) as AbstractGenerator; + if (baseColumnGen === undefined) { + throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); + } + const generator = new GenerateArray({ baseColumnGen, size: col.size }); - // INT ------------------------------------------------------------------------------------------------------------ - if ( - (col.columnType.includes('serial') - || col.columnType === 'integer' - || col.columnType === 'smallint' - || col.columnType.includes('bigint')) - && table.primaryKeys.includes(col.name) - ) { - generator = new GenerateIntPrimaryKey({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // INT ------------------------------------------------------------------------------------------------------------ + if ( + (col.columnType.includes('serial') + || col.columnType === 'integer' + || col.columnType === 'smallint' + || col.columnType.includes('bigint')) + && table.primaryKeys.includes(col.name) + ) { + const generator = new GenerateIntPrimaryKey({}); - let minValue: number | bigint | undefined; - let maxValue: number | bigint | undefined; - if (col.columnType.includes('serial')) { - minValue = 1; - if (col.columnType === 'smallserial') { - // 2^16 / 2 - 1, 2 bytes - maxValue = 32767; - } else if (col.columnType === 'serial') { - // 2^32 / 2 - 1, 4 bytes - maxValue = 2147483647; - } else if (col.columnType === 'bigserial') { - // 2^64 / 2 - 1, 8 bytes - minValue = BigInt(1); - maxValue = BigInt('9223372036854775807'); + return generator; } - } else if (col.columnType.includes('int')) { - if (col.columnType === 'smallint') { - // 2^16 / 2 - 1, 2 bytes - minValue = -32768; - maxValue = 32767; - } else if (col.columnType === 'integer') { - // 2^32 / 2 - 1, 4 bytes - minValue = -2147483648; - maxValue = 2147483647; - } else if (col.columnType.includes('bigint')) { - if (col.dataType === 'bigint') { + + let minValue: number | bigint | undefined; + let maxValue: number | bigint | undefined; + if (col.columnType.includes('serial')) { + minValue = 1; + if (col.columnType === 'smallserial') { + // 2^16 / 2 - 1, 2 bytes + maxValue = 32767; + } else if (col.columnType === 'serial') { + // 2^32 / 2 - 1, 4 bytes + maxValue = 2147483647; + } else if (col.columnType === 'bigserial') { // 2^64 / 2 - 1, 8 bytes - minValue = BigInt('-9223372036854775808'); + minValue = BigInt(1); maxValue = BigInt('9223372036854775807'); - } else if (col.dataType === 'number') { - // if you’re expecting values above 2^31 but below 2^53 - minValue = -9007199254740991; - maxValue = 9007199254740991; + } + } else if (col.columnType.includes('int')) { + if (col.columnType === 'smallint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -32768; + maxValue = 32767; + } else if (col.columnType === 'integer') { + // 2^32 / 2 - 1, 4 bytes + minValue = -2147483648; + maxValue = 2147483647; + } else if (col.columnType.includes('bigint')) { + if (col.dataType === 'bigint') { + // 2^64 / 2 - 1, 8 bytes + minValue = BigInt('-9223372036854775808'); + maxValue = BigInt('9223372036854775807'); + } else if (col.dataType === 'number') { + // if you’re expecting values above 2^31 but below 2^53 + minValue = -9007199254740991; + maxValue = 9007199254740991; + } } } - } - if ( - col.columnType.includes('int') - && !col.columnType.includes('interval') - && !col.columnType.includes('point') - ) { - generator = new GenerateInt({ - minValue, - maxValue, - }); + if ( + col.columnType.includes('int') + && !col.columnType.includes('interval') + && !col.columnType.includes('point') + ) { + const generator = new GenerateInt({ + minValue, + maxValue, + }); - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + return generator; + } - if (col.columnType.includes('serial')) { - generator = new GenerateIntPrimaryKey({}); + if (col.columnType.includes('serial')) { + const generator = new GenerateIntPrimaryKey({}); - (generator as GenerateIntPrimaryKey).maxValue = maxValue; - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + (generator as GenerateIntPrimaryKey).maxValue = maxValue; - // NUMBER(real, double, decimal, numeric) - if ( - col.columnType === 'real' - || col.columnType === 'doubleprecision' - || col.columnType === 'decimal' - || col.columnType === 'numeric' - ) { - generator = new GenerateNumber({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // NUMBER(real, double, decimal, numeric) + if ( + col.columnType === 'real' + || col.columnType === 'double precision' + || col.columnType === 'decimal' + || col.columnType === 'numeric' + ) { + const generator = new GenerateNumber({}); - // STRING - if ( - (col.columnType === 'text' - || col.columnType === 'varchar' - || col.columnType === 'char') - && table.primaryKeys.includes(col.name) - ) { - generator = new GenerateUniqueString({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // STRING + if ( + (col.columnType === 'text' + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('char')) + && table.primaryKeys.includes(col.name) + ) { + const generator = new GenerateUniqueString({}); - if ( - (col.columnType === 'text' - || col.columnType === 'varchar' - || col.columnType === 'char') - && col.name.toLowerCase().includes('name') - ) { - generator = new GenerateFirstName({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + if ( + (col.columnType === 'text' + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('char')) + && col.name.toLowerCase().includes('name') + ) { + const generator = new GenerateFirstName({}); - if ( - (col.columnType === 'text' - || col.columnType === 'varchar' - || col.columnType === 'char') - && col.name.toLowerCase().includes('email') - ) { - generator = new GenerateEmail({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + if ( + (col.columnType === 'text' + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('char')) + && col.name.toLowerCase().includes('email') + ) { + const generator = new GenerateEmail({}); - if ( - col.columnType === 'text' - || col.columnType === 'varchar' - || col.columnType === 'char' - ) { - // console.log(col, table) - generator = new GenerateString({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + if ( + col.columnType === 'text' + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('char') + ) { + // console.log(col, table) + const generator = new GenerateString({}); - // UUID - if (col.columnType === 'uuid') { - generator = new GenerateUUID({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // UUID + if (col.columnType === 'uuid') { + const generator = new GenerateUUID({}); - // BOOLEAN - if (col.columnType === 'boolean') { - generator = new GenerateBoolean({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // BOOLEAN + if (col.columnType === 'boolean') { + const generator = new GenerateBoolean({}); - // DATE, TIME, TIMESTAMP - if (col.columnType.includes('date')) { - generator = new GenerateDate({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // DATE, TIME, TIMESTAMP + if (col.columnType.includes('date')) { + const generator = new GenerateDate({}); - if (col.columnType === 'time') { - generator = new GenerateTime({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + if (col.columnType === 'time') { + const generator = new GenerateTime({}); - if (col.columnType.includes('timestamp')) { - generator = new GenerateTimestamp({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + if (col.columnType.includes('timestamp')) { + const generator = new GenerateTimestamp({}); - // JSON, JSONB - if (col.columnType === 'json' || col.columnType === 'jsonb') { - generator = new GenerateJson({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // JSON, JSONB + if (col.columnType === 'json' || col.columnType === 'jsonb') { + const generator = new GenerateJson({}); - // if (col.columnType === "jsonb") { - // const generator = new GenerateJsonb({}); - // return generator; - // } + return generator; + } - // ENUM - if (col.enumValues !== undefined) { - generator = new GenerateEnum({ - enumValues: col.enumValues, - }); + // if (col.columnType === "jsonb") { + // const generator = new GenerateJsonb({}); + // return generator; + // } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // ENUM + if (col.enumValues !== undefined) { + const generator = new GenerateEnum({ + enumValues: col.enumValues, + }); - // INTERVAL - if (col.columnType === 'interval') { - generator = new GenerateInterval({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // INTERVAL + if (col.columnType === 'interval') { + const generator = new GenerateInterval({}); - // POINT, LINE - if (col.columnType.includes('point')) { - generator = new GeneratePoint({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // POINT, LINE + if (col.columnType.includes('point')) { + const generator = new GeneratePoint({}); - if (col.columnType.includes('line')) { - generator = new GenerateLine({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + if (col.columnType.includes('line')) { + const generator = new GenerateLine({}); + + return generator; + } - // ARRAY - if (col.columnType.includes('array') && col.baseColumn !== undefined) { - const baseColumnGen = this.pickGeneratorForPostgresColumn(table, col.baseColumn!) as AbstractGenerator; - if (baseColumnGen === undefined) { - throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); + if (col.hasDefault && col.default !== undefined) { + const generator = new GenerateDefault({ + defaultValue: col.default, + }); + return generator; } - generator = new GenerateArray({ baseColumnGen, size: col.size }); + return; + }; + + const generator = pickGenerator(table, col); + if (generator !== undefined) { generator.isUnique = col.isUnique; generator.dataType = col.dataType; - return generator; - } - - if (col.hasDefault && col.default !== undefined) { - generator = new GenerateDefault({ - defaultValue: col.default, - }); - return generator; + generator.length = col.typeParams.length; } return generator; diff --git a/drizzle-seed/src/types/tables.ts b/drizzle-seed/src/types/tables.ts index 8473179ed..dc28c748d 100644 --- a/drizzle-seed/src/types/tables.ts +++ b/drizzle-seed/src/types/tables.ts @@ -4,6 +4,12 @@ export type Column = { name: string; dataType: string; columnType: string; + typeParams: { + precision?: number; + scale?: number; + length?: number; + dimensions?: number; + }; size?: number; default?: any; hasDefault: boolean; From 05d907bf3f409f4425abe528b6ec889b5f03300a Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 16 Dec 2024 13:09:43 +0200 Subject: [PATCH 446/492] added checks to string-like generators, updated sqlite and mysql seeding using sql column type --- drizzle-seed/src/index.ts | 35 +++- .../src/services/GeneratorsWrappers.ts | 196 ++++++++++++++++-- drizzle-seed/src/services/SeedService.ts | 19 +- 3 files changed, 222 insertions(+), 28 deletions(-) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index a60987867..fde4442a1 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -898,12 +898,41 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { } tableRelations[dbToTsTableNamesMap[tableConfig.name] as string]!.push(...newRelations); + const getTypeParams = (sqlType: string) => { + // get type params and set only type + const typeParams: Column['typeParams'] = {}; + + if ( + sqlType.startsWith('decimal') + || sqlType.startsWith('real') + || sqlType.startsWith('double') + || sqlType.startsWith('float') + ) { + const match = sqlType.match(/\((\d+),(\d+)\)/); + if (match) { + typeParams['precision'] = Number(match[1]); + typeParams['scale'] = Number(match[2]); + } + } else if ( + sqlType.startsWith('varchar') + || sqlType.startsWith('binary') + || sqlType.startsWith('varbinary') + ) { + const match = sqlType.match(/\((\d+)\)/); + if (match) { + typeParams['length'] = Number(match[1]); + } + } + + return typeParams; + }; + tables.push({ name: dbToTsTableNamesMap[tableConfig.name] as string, columns: tableConfig.columns.map((column) => ({ name: dbToTsColumnNamesMap[column.name] as string, - columnType: column.columnType.replace('MySql', '').toLowerCase(), - typeParams: {}, + columnType: column.getSQLType(), + typeParams: getTypeParams(column.getSQLType()), dataType: column.dataType, hasDefault: column.hasDefault, default: column.default, @@ -1092,7 +1121,7 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { name: dbToTsTableNamesMap[tableConfig.name] as string, columns: tableConfig.columns.map((column) => ({ name: dbToTsColumnNamesMap[column.name] as string, - columnType: column.columnType.replace('SQLite', '').toLowerCase(), + columnType: column.getSQLType(), typeParams: {}, dataType: column.dataType, hasDefault: column.hasDefault, diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts index a1a751f9a..374fa6447 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -1,17 +1,17 @@ import { entityKind } from 'drizzle-orm'; import prand from 'pure-rand'; -import adjectives from '../datasets/adjectives.ts'; -import cityNames from '../datasets/cityNames.ts'; -import companyNameSuffixes from '../datasets/companyNameSuffixes.ts'; -import countries from '../datasets/countries.ts'; -import emailDomains from '../datasets/emailDomains.ts'; -import firstNames from '../datasets/firstNames.ts'; -import jobsTitles from '../datasets/jobsTitles.ts'; -import lastNames from '../datasets/lastNames.ts'; -import loremIpsumSentences from '../datasets/loremIpsumSentences.ts'; +import adjectives, { maxStringLength as maxAdjectiveLength } from '../datasets/adjectives.ts'; +import cityNames, { maxStringLength as maxCityNameLength } from '../datasets/cityNames.ts'; +import companyNameSuffixes, { maxStringLength as maxCompanyNameSuffixLength } from '../datasets/companyNameSuffixes.ts'; +import countries, { maxStringLength as maxCountryLength } from '../datasets/countries.ts'; +import emailDomains, { maxStringLength as maxEmailDomainLength } from '../datasets/emailDomains.ts'; +import firstNames, { maxStringLength as maxFirstNameLength } from '../datasets/firstNames.ts'; +import jobsTitles, { maxStringLength as maxJobTitleLength } from '../datasets/jobsTitles.ts'; +import lastNames, { maxStringLength as maxLastNameLength } from '../datasets/lastNames.ts'; +import loremIpsumSentences, { maxStringLength as maxLoremIpsumLength } from '../datasets/loremIpsumSentences.ts'; import phonesInfo from '../datasets/phonesInfo.ts'; -import states from '../datasets/states.ts'; -import streetSuffix from '../datasets/streetSuffix.ts'; +import states, { maxStringLength as maxStateLength } from '../datasets/states.ts'; +import streetSuffix, { maxStringLength as maxStreetSuffixLength } from '../datasets/streetSuffix.ts'; import { fastCartesianProduct, fillTemplate, getWeightedIndices, isObject } from './utils.ts'; export abstract class AbstractGenerator { @@ -24,7 +24,7 @@ export abstract class AbstractGenerator { public timeSpent?: number; public arraySize?: number; public baseColumnDataType?: string; - public length?: number; + public stringLength?: number; constructor(public params: T) {} @@ -1350,8 +1350,8 @@ export class GenerateString extends AbstractGenerator<{ let minStringLength = 8; let maxStringLength = 20; - if (this.length !== undefined) { - maxStringLength = this.length; + if (this.stringLength !== undefined) { + maxStringLength = this.stringLength; if (maxStringLength === 1) minStringLength = maxStringLength; if (maxStringLength < minStringLength) minStringLength = 1; } @@ -1406,8 +1406,8 @@ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean let minStringLength = 8; let maxStringLength = 20; // TODO: revise later - if (this.length !== undefined) { - maxStringLength = this.length; + if (this.stringLength !== undefined) { + maxStringLength = this.stringLength; if (maxStringLength === 1 || maxStringLength < minStringLength) minStringLength = maxStringLength; } @@ -1515,6 +1515,12 @@ export class GenerateFirstName extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxFirstNameLength) { + throw new Error( + `You can't use first name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxFirstNameLength}.`, + ); + } + this.state = { rng }; } @@ -1547,6 +1553,13 @@ export class GenerateUniqueFirstName extends AbstractGenerator<{ if (count > firstNames.length) { throw new Error('count exceeds max number of unique first names.'); } + + if (this.stringLength !== undefined && this.stringLength < maxFirstNameLength) { + throw new Error( + `You can't use first name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxFirstNameLength}.`, + ); + } + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: firstNames.length - 1 }); genIndicesObj.init({ count, seed }); @@ -1582,6 +1595,12 @@ export class GenerateLastName extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxLastNameLength) { + throw new Error( + `You can't use last name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxLastNameLength}.`, + ); + } + this.state = { rng }; } generate() { @@ -1609,6 +1628,12 @@ export class GenerateUniqueLastName extends AbstractGenerator<{ isUnique?: boole throw new Error('count exceeds max number of unique last names.'); } + if (this.stringLength !== undefined && this.stringLength < maxLastNameLength) { + throw new Error( + `You can't use last name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxLastNameLength}.`, + ); + } + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: lastNames.length - 1 }); genIndicesObj.init({ count, seed }); @@ -1643,6 +1668,14 @@ export class GenerateFullName extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < (maxFirstNameLength + maxLastNameLength + 1)) { + throw new Error( + `You can't use full name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${ + maxFirstNameLength + maxLastNameLength + 1 + }.`, + ); + } + this.state = { rng }; } @@ -1686,6 +1719,15 @@ export class GenerateUniqueFullName extends AbstractGenerator<{ `count exceeds max number of unique full names(${maxUniqueFullNamesNumber}).`, ); } + + if (this.stringLength !== undefined && this.stringLength < (maxFirstNameLength + maxLastNameLength + 1)) { + throw new Error( + `You can't use full name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${ + maxFirstNameLength + maxLastNameLength + 1 + }.`, + ); + } + const rng = prand.xoroshiro128plus(seed); const fullnameSet = new Set(); @@ -1747,6 +1789,13 @@ export class GenerateEmail extends AbstractGenerator<{ ); } + const maxEmailLength = maxAdjectiveLength + maxFirstNameLength + maxEmailDomainLength + 2; + if (this.stringLength !== undefined && this.stringLength < maxEmailLength) { + throw new Error( + `You can't use email generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxEmailLength}.`, + ); + } + const arraysToGenerateFrom = [adjectivesArray, namesArray, domainsArray]; const genIndicesObj = new GenerateUniqueInt({ minValue: 0, @@ -1805,6 +1854,13 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); if (template !== undefined) { + if (this.stringLength !== undefined && this.stringLength < template.length) { + throw new Error( + `Length of phone number template is shorter than db column length restriction: ${this.stringLength}. + Set the maximum string length to at least ${template.length}.`, + ); + } + const iterArray = [...template.matchAll(/#/g)]; const placeholdersCount = iterArray.length; @@ -1860,6 +1916,17 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ } } + const maxPrefixLength = Math.max(...prefixesArray.map((prefix) => prefix.length)); + const maxGeneratedDigits = Math.max(...generatedDigitsNumbers); + + if (this.stringLength !== undefined && this.stringLength < (maxPrefixLength + maxGeneratedDigits)) { + throw new Error( + `You can't use phone number generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${ + maxPrefixLength + maxGeneratedDigits + }.`, + ); + } + if (new Set(prefixesArray).size !== prefixesArray.length) { throw new Error('prefixes are not unique.'); } @@ -1939,7 +2006,7 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ numberBody = '0'.repeat(digitsNumberDiff) + numberBody; } - phoneNumber = (prefix.includes('+') ? '' : '+') + prefix + '' + numberBody; + phoneNumber = prefix + '' + numberBody; return phoneNumber; } else { @@ -1972,6 +2039,12 @@ export class GenerateCountry extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxCountryLength) { + throw new Error( + `You can't use country generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCountryLength}.`, + ); + } + this.state = { rng }; } @@ -2002,6 +2075,12 @@ export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolea throw new Error('count exceeds max number of unique countries.'); } + if (this.stringLength !== undefined && this.stringLength < maxCountryLength) { + throw new Error( + `You can't use country generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCountryLength}.`, + ); + } + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: countries.length - 1 }); genIndicesObj.init({ count, seed }); @@ -2034,6 +2113,12 @@ export class GenerateJobTitle extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxJobTitleLength) { + throw new Error( + `You can't use job title generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxJobTitleLength}.`, + ); + } + this.state = { rng }; } @@ -2066,6 +2151,14 @@ export class GenerateStreetAdddress extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); const possStreetNames = [firstNames, lastNames]; + + const maxStreetAddressLength = 4 + Math.max(maxFirstNameLength, maxLastNameLength) + 1 + maxStreetSuffixLength; + if (this.stringLength !== undefined && this.stringLength < maxStreetAddressLength) { + throw new Error( + `You can't use street address generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxStreetAddressLength}.`, + ); + } + this.state = { rng, possStreetNames }; } @@ -2116,6 +2209,13 @@ export class GenerateUniqueStreetAdddress extends AbstractGenerator<{ isUnique?: ); } + const maxStreetAddressLength = 4 + Math.max(maxFirstNameLength, maxLastNameLength) + 1 + maxStreetSuffixLength; + if (this.stringLength !== undefined && this.stringLength < maxStreetAddressLength) { + throw new Error( + `You can't use street address generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxStreetAddressLength}.`, + ); + } + const rng = prand.xoroshiro128plus(seed); // ["1", "2", ..., "999"] @@ -2193,6 +2293,12 @@ export class GenerateCity extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxCityNameLength) { + throw new Error( + `You can't use city generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCityNameLength}.`, + ); + } + this.state = { rng }; } @@ -2221,6 +2327,12 @@ export class GenerateUniqueCity extends AbstractGenerator<{ isUnique?: boolean } throw new Error('count exceeds max number of unique cities.'); } + if (this.stringLength !== undefined && this.stringLength < maxCityNameLength) { + throw new Error( + `You can't use city generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCityNameLength}.`, + ); + } + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: cityNames.length - 1 }); genIndicesObj.init({ count, seed }); @@ -2257,6 +2369,13 @@ export class GeneratePostcode extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); const templates = ['#####', '#####-####']; + const maxPostcodeLength = Math.max(...templates.map((template) => template.length)); + if (this.stringLength !== undefined && this.stringLength < maxPostcodeLength) { + throw new Error( + `You can't use postcode generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxPostcodeLength}.`, + ); + } + this.state = { rng, templates }; } @@ -2330,6 +2449,13 @@ export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boole }, ]; + const maxPostcodeLength = Math.max(...templates.map((template) => template.template.length)); + if (this.stringLength !== undefined && this.stringLength < maxPostcodeLength) { + throw new Error( + `You can't use postcode generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxPostcodeLength}.`, + ); + } + for (const templateObj of templates) { templateObj.indicesGen.skipCheck = true; templateObj.indicesGen.init({ count, seed }); @@ -2381,6 +2507,12 @@ export class GenerateState extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxStateLength) { + throw new Error( + `You can't use state generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxStateLength}.`, + ); + } + this.state = { rng }; } @@ -2419,6 +2551,17 @@ export class GenerateCompanyName extends AbstractGenerator<{ { template: '#, # and #', placeholdersCount: 3 }, ]; + // max( { template: '#', placeholdersCount: 1 }, { template: '#, # and #', placeholdersCount: 3 } ) + const maxCompanyNameLength = Math.max( + maxLastNameLength + maxCompanyNameSuffixLength + 1, + 3 * maxLastNameLength + 7, + ); + if (this.stringLength !== undefined && this.stringLength < maxCompanyNameLength) { + throw new Error( + `You can't use company name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCompanyNameLength}.`, + ); + } + this.state = { rng, templates }; } @@ -2482,6 +2625,17 @@ export class GenerateUniqueCompanyName extends AbstractGenerator<{ isUnique?: bo ); } + // max( { template: '#', placeholdersCount: 1 }, { template: '#, # and #', placeholdersCount: 3 } ) + const maxCompanyNameLength = Math.max( + maxLastNameLength + maxCompanyNameSuffixLength + 1, + 3 * maxLastNameLength + 7, + ); + if (this.stringLength !== undefined && this.stringLength < maxCompanyNameLength) { + throw new Error( + `You can't use company name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCompanyNameLength}.`, + ); + } + const rng = prand.xoroshiro128plus(seed); // when count reach maxUniqueCompanyNameNumber template will be deleted from array const templates = [ @@ -2570,6 +2724,14 @@ export class GenerateLoremIpsum extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); if (this.params.sentencesCount === undefined) this.params.sentencesCount = 1; + const maxLoremIpsumSentencesLength = maxLoremIpsumLength * this.params.sentencesCount + this.params.sentencesCount + - 1; + if (this.stringLength !== undefined && this.stringLength < maxLoremIpsumSentencesLength) { + throw new Error( + `You can't use lorem ipsum generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxLoremIpsumSentencesLength}.`, + ); + } + this.state = { rng }; } diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 854fbe437..66617cb66 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -259,7 +259,7 @@ export class SeedService { columnPossibleGenerator.generator.isUnique = col.isUnique; columnPossibleGenerator.generator.dataType = col.dataType; - columnPossibleGenerator.generator.length = col.typeParams.length; + columnPossibleGenerator.generator.stringLength = col.typeParams.length; tablePossibleGenerators.columnsPossibleGenerators.push( columnPossibleGenerator, @@ -660,7 +660,7 @@ export class SeedService { if (generator !== undefined) { generator.isUnique = col.isUnique; generator.dataType = col.dataType; - generator.length = col.typeParams.length; + generator.stringLength = col.typeParams.length; } return generator; @@ -850,7 +850,7 @@ export class SeedService { ) => { // int section --------------------------------------------------------------------------------------- if ( - (col.columnType === 'integer' || col.columnType === 'numeric') + ((col.columnType === 'integer' && col.dataType === 'number') || col.columnType === 'numeric') && table.primaryKeys.includes(col.name) ) { const generator = new GenerateIntPrimaryKey({}); @@ -858,15 +858,15 @@ export class SeedService { } if ( - col.columnType === 'integer' + (col.columnType === 'integer' && col.dataType === 'number') || col.columnType === 'numeric' - || col.columnType === 'bigint' + || (col.dataType === 'bigint' && col.columnType === 'blob') ) { const generator = new GenerateInt({}); return generator; } - if (col.columnType === 'boolean') { + if (col.dataType === 'boolean' && col.columnType === 'integer') { const generator = new GenerateBoolean({}); return generator; } @@ -918,12 +918,15 @@ export class SeedService { return generator; } - if (col.columnType === 'textjson' || col.columnType === 'blobjson') { + if ( + (col.columnType === 'text' && col.dataType === 'json') + || (col.columnType === 'blob' && col.dataType === 'json') + ) { const generator = new GenerateJson({}); return generator; } - if (col.columnType === 'timestamp' || col.columnType === 'timestamp_ms') { + if ((col.columnType === 'integer' && col.dataType === 'date')) { const generator = new GenerateTimestamp({}); return generator; } From f6eaa62b7c29e88ab19e45dc581776c7247852eb Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 16 Dec 2024 14:51:09 +0200 Subject: [PATCH 447/492] added array support for studio --- drizzle-seed/src/services/SeedService.ts | 58 ++++++++++++++++++------ 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 66617cb66..02cf5af2c 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -205,8 +205,12 @@ export class SeedService { const genObj = refinements[table.name]!.columns[col.name]!; // TODO: for now only GenerateValuesFromArray support notNull property genObj.notNull = col.notNull; - if (col.dataType === 'array') { - if (col.baseColumn?.dataType === 'array' && col.baseColumn?.columnType === 'array') { + if (col.columnType.match(/\[\w*]/g) !== null) { + if ( + (col.baseColumn?.dataType === 'array' && col.baseColumn.columnType.match(/\[\w*]/g) !== null) + // studio case + || (col.typeParams.dimensions !== undefined && col.typeParams.dimensions > 1) + ) { throw new Error("for now you can't specify generators for columns of dimensition greater than 1."); } @@ -444,6 +448,29 @@ export class SeedService { return generator; } + // ARRAY for studio + if (col.columnType.match(/\[\w*]/g) !== null) { + // remove dimensions from type + const baseColumnType = col.columnType.replace(/\[\w*]/g, ''); + const baseColumn: Column = { + ...col, + }; + baseColumn.columnType = baseColumnType; + + const baseColumnGen = this.pickGeneratorForPostgresColumn(table, baseColumn) as AbstractGenerator; + if (baseColumnGen === undefined) { + throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); + } + + let generator = new GenerateArray({ baseColumnGen }); + + for (let i = 0; i < col.typeParams.dimensions! - 1; i++) { + generator = new GenerateArray({ baseColumnGen: generator }); + } + + return generator; + } + // INT ------------------------------------------------------------------------------------------------------------ if ( (col.columnType.includes('serial') @@ -486,7 +513,8 @@ export class SeedService { // 2^64 / 2 - 1, 8 bytes minValue = BigInt('-9223372036854775808'); maxValue = BigInt('9223372036854775807'); - } else if (col.dataType === 'number') { + } else { + // if (col.dataType === 'number') // if you’re expecting values above 2^31 but below 2^53 minValue = -9007199254740991; maxValue = 9007199254740991; @@ -850,15 +878,25 @@ export class SeedService { ) => { // int section --------------------------------------------------------------------------------------- if ( - ((col.columnType === 'integer' && col.dataType === 'number') || col.columnType === 'numeric') + (col.columnType === 'integer' || col.columnType === 'numeric') && table.primaryKeys.includes(col.name) ) { const generator = new GenerateIntPrimaryKey({}); return generator; } + if (col.columnType === 'integer' && col.dataType === 'boolean') { + const generator = new GenerateBoolean({}); + return generator; + } + + if ((col.columnType === 'integer' && col.dataType === 'date')) { + const generator = new GenerateTimestamp({}); + return generator; + } + if ( - (col.columnType === 'integer' && col.dataType === 'number') + col.columnType === 'integer' || col.columnType === 'numeric' || (col.dataType === 'bigint' && col.columnType === 'blob') ) { @@ -866,11 +904,6 @@ export class SeedService { return generator; } - if (col.dataType === 'boolean' && col.columnType === 'integer') { - const generator = new GenerateBoolean({}); - return generator; - } - // number section ------------------------------------------------------------------------------------ if (col.columnType === 'real' || col.columnType === 'numeric') { const generator = new GenerateNumber({}); @@ -926,11 +959,6 @@ export class SeedService { return generator; } - if ((col.columnType === 'integer' && col.dataType === 'date')) { - const generator = new GenerateTimestamp({}); - return generator; - } - if (col.hasDefault && col.default !== undefined) { const generator = new GenerateDefault({ defaultValue: col.default, From 1c8cbad2203a5131154435e8cd545fcd34387f25 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Tue, 17 Dec 2024 12:42:10 +0200 Subject: [PATCH 448/492] updated postgres interval generators to work with fields, added tests --- .../src/services/GeneratorsWrappers.ts | 194 ++++++++++++------ drizzle-seed/src/services/SeedService.ts | 11 +- .../mysql_all_data_types.test.ts | 2 +- .../tests/pg/allDataTypesTest/pgSchema.ts | 16 ++ .../pg_all_data_types.test.ts | 30 +++ 5 files changed, 192 insertions(+), 61 deletions(-) diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/GeneratorsWrappers.ts index 374fa6447..4ab06ec3f 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/GeneratorsWrappers.ts @@ -1222,19 +1222,76 @@ export class GenerateEnum extends AbstractGenerator<{ enumValues: (string | numb } export class GenerateInterval extends AbstractGenerator<{ + fields?: + | 'year' + | 'month' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'year to month' + | 'day to hour' + | 'day to minute' + | 'day to second' + | 'hour to minute' + | 'hour to second' + | 'minute to second'; isUnique?: boolean; arraySize?: number; }> { static override readonly [entityKind]: string = 'GenerateInterval'; - private state: { rng: prand.RandomGenerator } | undefined; + private state: { + rng: prand.RandomGenerator; + fieldsToGenerate: string[]; + } | undefined; override uniqueVersionOfGen = GenerateUniqueInterval; + private config: { [key: string]: { from: number; to: number } } = { + year: { + from: 0, + to: 5, + }, + month: { + from: 0, + to: 11, + }, + day: { + from: 1, + to: 29, + }, + hour: { + from: 0, + to: 23, + }, + minute: { + from: 0, + to: 59, + }, + second: { + from: 0, + to: 59, + }, + }; override init({ count, seed }: { count: number; seed: number }) { super.init({ count, seed }); + const allFields = ['year', 'month', 'day', 'hour', 'minute', 'second']; + let fieldsToGenerate: string[] = allFields; + + if (this.params.fields !== undefined && this.params.fields?.includes(' to ')) { + const tokens = this.params.fields.split(' to '); + const endIdx = allFields.indexOf(tokens[1]!); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } else if (this.params.fields !== undefined) { + const endIdx = allFields.indexOf(this.params.fields); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } + + this.config[fieldsToGenerate[Math.floor(fieldsToGenerate.length / 2)]!]!.from = 1; + const rng = prand.xoroshiro128plus(seed); - this.state = { rng }; + this.state = { rng, fieldsToGenerate }; } generate() { @@ -1242,55 +1299,98 @@ export class GenerateInterval extends AbstractGenerator<{ throw new Error('state is not defined.'); } - let yearsNumb: number, - monthsNumb: number, - daysNumb: number, - hoursNumb: number, - minutesNumb: number, - secondsNumb: number; - - let interval = ''; - - [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); - [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); - - [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); - - [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); - - [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + let interval = '', numb: number; - [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - - interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` - + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` - + `${daysNumb === 0 ? '' : `${daysNumb} days `}` - + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` - + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` - + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; + for (const field of this.state.fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + [numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng); + interval += `${numb === 0 ? '' : `${numb} ${field} `}`; + } return interval; } } -export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boolean }> { +export class GenerateUniqueInterval extends AbstractGenerator<{ + fields?: + | 'year' + | 'month' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'year to month' + | 'day to hour' + | 'day to minute' + | 'day to second' + | 'hour to minute' + | 'hour to second' + | 'minute to second'; + isUnique?: boolean; +}> { static override readonly [entityKind]: string = 'GenerateUniqueInterval'; private state: { rng: prand.RandomGenerator; + fieldsToGenerate: string[]; intervalSet: Set; } | undefined; public override isUnique = true; + private config: { [key: string]: { from: number; to: number } } = { + year: { + from: 0, + to: 5, + }, + month: { + from: 0, + to: 11, + }, + day: { + from: 1, + to: 29, + }, + hour: { + from: 0, + to: 23, + }, + minute: { + from: 0, + to: 59, + }, + second: { + from: 0, + to: 59, + }, + }; override init({ count, seed }: { count: number; seed: number }) { - const maxUniqueIntervalsNumber = 6 * 13 * 29 * 25 * 61 * 61; + const allFields = ['year', 'month', 'day', 'hour', 'minute', 'second']; + let fieldsToGenerate: string[] = allFields; + + if (this.params.fields !== undefined && this.params.fields?.includes(' to ')) { + const tokens = this.params.fields.split(' to '); + const endIdx = allFields.indexOf(tokens[1]!); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } else if (this.params.fields !== undefined) { + const endIdx = allFields.indexOf(this.params.fields); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } + + this.config[fieldsToGenerate[Math.floor(fieldsToGenerate.length / 2)]!]!.from = 1; + + let maxUniqueIntervalsNumber = 1; + for (const field of fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + maxUniqueIntervalsNumber *= from - to + 1; + } + if (count > maxUniqueIntervalsNumber) { throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`); } const rng = prand.xoroshiro128plus(seed); const intervalSet = new Set(); - this.state = { rng, intervalSet }; + this.state = { rng, fieldsToGenerate, intervalSet }; } generate() { @@ -1298,34 +1398,12 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boole throw new Error('state is not defined.'); } - let yearsNumb: number, - monthsNumb: number, - daysNumb: number, - hoursNumb: number, - minutesNumb: number, - secondsNumb: number; - - let interval = ''; + let interval = '', numb: number; - for (;;) { - [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); - [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); - [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); - [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); - [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - - interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` - + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` - + `${daysNumb === 0 ? '' : `${daysNumb} days `}` - + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` - + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` - + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; - - if (!this.state.intervalSet.has(interval)) { - this.state.intervalSet.add(interval); - break; - } + for (const field of this.state.fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + [numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng); + interval += `${numb === 0 ? '' : `${numb} ${field} `}`; } return interval; @@ -1531,7 +1609,6 @@ export class GenerateFirstName extends AbstractGenerator<{ // logic for this generator // names dataset contains about 30000 unique names. - // TODO: generate names accordingly to max column length let idx: number; [idx, this.state.rng] = prand.uniformIntDistribution(0, firstNames.length - 1, this.state.rng); @@ -3343,6 +3420,7 @@ export const generatorsFuncs = { * * @param isUnique - property that controls if generated values gonna be unique or not. * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * @param fields - range of values you want to see in your intervals. * @example * ```ts * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 02cf5af2c..62283c817 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -655,8 +655,15 @@ export class SeedService { } // INTERVAL - if (col.columnType === 'interval') { - const generator = new GenerateInterval({}); + if (col.columnType.startsWith('interval')) { + if (col.columnType === 'interval') { + const generator = new GenerateInterval({}); + + return generator; + } + + const fields = col.columnType.replace('interval ', '') as GenerateInterval['params']['fields']; + const generator = new GenerateInterval({ fields }); return generator; } diff --git a/drizzle-seed/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts b/drizzle-seed/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts index 5a9ba9908..f39a55fef 100644 --- a/drizzle-seed/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts +++ b/drizzle-seed/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts @@ -11,7 +11,7 @@ import { seed } from '../../../src/index.ts'; import * as schema from './mysqlSchema.ts'; let mysqlContainer: Docker.Container; -let client: Connection; +let client: Connection | undefined; let db: MySql2Database; async function createDockerDB(): Promise { diff --git a/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts b/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts index 75ba20a43..16a55baf4 100644 --- a/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts +++ b/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts @@ -97,3 +97,19 @@ export const ndArrays = schema.table('nd_arrays', { integer3DArray: integer('integer_3d_array').array(3).array(4).array(5), integer4DArray: integer('integer_4d_array').array(3).array(4).array(5).array(6), }); + +export const intervals = schema.table('intervals', { + intervalYear: interval({ fields: 'year' }), + intervalYearToMonth: interval({ fields: 'year to month' }), + intervalMonth: interval({ fields: 'month' }), + intervalDay: interval({ fields: 'day' }), + intervalDayToHour: interval({ fields: 'day to hour' }), + intervalDayToMinute: interval({ fields: 'day to minute' }), + intervalDayToSecond: interval({ fields: 'day to second' }), + intervalHour: interval({ fields: 'hour' }), + intervalHourToMinute: interval({ fields: 'hour to minute' }), + intervalHourToSecond: interval({ fields: 'hour to second' }), + intervalMinute: interval({ fields: 'minute' }), + intervalMinuteToSecond: interval({ fields: 'minute to second' }), + intervalSecond: interval({ fields: 'second' }), +}); diff --git a/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts b/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts index 7dfbc089b..62d0895c0 100644 --- a/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts +++ b/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts @@ -105,6 +105,26 @@ beforeAll(async () => { ); `, ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."intervals" ( + "intervalYear" interval year, + "intervalYearToMonth" interval year to month, + "intervalMonth" interval month, + "intervalDay" interval day, + "intervalDayToHour" interval day to hour, + "intervalDayToMinute" interval day to minute, + "intervalDayToSecond" interval day to second, + "intervalHour" interval hour, + "intervalHourToMinute" interval hour to minute, + "intervalHourToSecond" interval hour to second, + "intervalMinute" interval minute, + "intervalMinuteToSecond" interval minute to second, + "intervalSecond" interval second + ); + `, + ); }); afterAll(async () => { @@ -157,3 +177,13 @@ test('nd arrays', async () => { expect(predicate0 && predicate1 && predicate2 && predicate3 && predicate4).toBe(true); }); + +test('intervals test', async () => { + await seed(db, { intervals: schema.intervals }, { count: 1000 }); + + const intervals = await db.select().from(schema.intervals); + // every value in each rows does not equal undefined. + const predicate = intervals.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); From 42d7de9eee27adf5a4b60ca5461ac99b739af1e6 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 17 Dec 2024 10:50:41 -0800 Subject: [PATCH 449/492] Add SS support in drizzle-zod --- .../src/singlestore-core/columns/all.ts | 5 +- .../src/singlestore-core/columns/char.ts | 71 +-- .../src/singlestore-core/columns/text.ts | 2 +- .../src/singlestore-core/columns/varchar.ts | 71 +-- drizzle-zod/src/column.ts | 84 ++- drizzle-zod/tests/singlestore.test.ts | 491 ++++++++++++++++++ 6 files changed, 649 insertions(+), 75 deletions(-) create mode 100644 drizzle-zod/tests/singlestore.test.ts diff --git a/drizzle-orm/src/singlestore-core/columns/all.ts b/drizzle-orm/src/singlestore-core/columns/all.ts index 66d289e3f..450417060 100644 --- a/drizzle-orm/src/singlestore-core/columns/all.ts +++ b/drizzle-orm/src/singlestore-core/columns/all.ts @@ -15,7 +15,7 @@ import { mediumint } from './mediumint.ts'; import { real } from './real.ts'; import { serial } from './serial.ts'; import { smallint } from './smallint.ts'; -import { text } from './text.ts'; +import { longtext, mediumtext, text, tinytext } from './text.ts'; import { time } from './time.ts'; import { timestamp } from './timestamp.ts'; import { tinyint } from './tinyint.ts'; @@ -42,7 +42,10 @@ export function getSingleStoreColumnBuilders() { real, serial, smallint, + longtext, + mediumtext, text, + tinytext, time, timestamp, tinyint, diff --git a/drizzle-orm/src/singlestore-core/columns/char.ts b/drizzle-orm/src/singlestore-core/columns/char.ts index 512460f92..903946688 100644 --- a/drizzle-orm/src/singlestore-core/columns/char.ts +++ b/drizzle-orm/src/singlestore-core/columns/char.ts @@ -5,26 +5,31 @@ import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; import { getColumnNameAndConfig, type Writable } from '~/utils.ts'; import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; -export type SingleStoreCharBuilderInitial = - SingleStoreCharBuilder<{ - name: TName; - dataType: 'string'; - columnType: 'SingleStoreChar'; - data: TEnum[number]; - driverParam: number | string; - enumValues: TEnum; - generated: undefined; - }>; +export type SingleStoreCharBuilderInitial< + TName extends string, + TEnum extends [string, ...string[]], + TLength extends number | undefined, +> = SingleStoreCharBuilder<{ + name: TName; + dataType: 'string'; + columnType: 'SingleStoreChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; + length: TLength; +}>; -export class SingleStoreCharBuilder> - extends SingleStoreColumnBuilder< - T, - SingleStoreCharConfig - > -{ +export class SingleStoreCharBuilder< + T extends ColumnBuilderBaseConfig<'string', 'SingleStoreChar'> & { length?: number | undefined }, +> extends SingleStoreColumnBuilder< + T, + SingleStoreCharConfig, + { length: T['length'] } +> { static override readonly [entityKind]: string = 'SingleStoreCharBuilder'; - constructor(name: T['name'], config: SingleStoreCharConfig) { + constructor(name: T['name'], config: SingleStoreCharConfig) { super(name, 'string', 'SingleStoreChar'); this.config.length = config.length; this.config.enum = config.enum; @@ -33,20 +38,20 @@ export class SingleStoreCharBuilder( table: AnySingleStoreTable<{ name: TTableName }>, - ): SingleStoreChar & { enumValues: T['enumValues'] }> { - return new SingleStoreChar & { enumValues: T['enumValues'] }>( + ): SingleStoreChar & { length: T['length']; enumValues: T['enumValues'] }> { + return new SingleStoreChar & { length: T['length']; enumValues: T['enumValues'] }>( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class SingleStoreChar> - extends SingleStoreColumn> +export class SingleStoreChar & { length?: number | undefined }> + extends SingleStoreColumn, { length: T['length'] }> { static override readonly [entityKind]: string = 'SingleStoreChar'; - readonly length: number | undefined = this.config.length; + readonly length: T['length'] = this.config.length; override readonly enumValues = this.config.enum; getSQLType(): string { @@ -56,19 +61,25 @@ export class SingleStoreChar { - length?: number; enum?: TEnum; + length?: TLength; } -export function char(): SingleStoreCharBuilderInitial<'', [string, ...string[]]>; -export function char>( - config?: SingleStoreCharConfig>, -): SingleStoreCharBuilderInitial<'', Writable>; -export function char>( +export function char(): SingleStoreCharBuilderInitial<'', [string, ...string[]], undefined>; +export function char, L extends number | undefined>( + config?: SingleStoreCharConfig, L>, +): SingleStoreCharBuilderInitial<'', Writable, L>; +export function char< + TName extends string, + U extends string, + T extends Readonly<[U, ...U[]]>, + L extends number | undefined, +>( name: TName, - config?: SingleStoreCharConfig>, -): SingleStoreCharBuilderInitial>; + config?: SingleStoreCharConfig, L>, +): SingleStoreCharBuilderInitial, L>; export function char(a?: string | SingleStoreCharConfig, b: SingleStoreCharConfig = {}): any { const { name, config } = getColumnNameAndConfig(a, b); return new SingleStoreCharBuilder(name, config as any); diff --git a/drizzle-orm/src/singlestore-core/columns/text.ts b/drizzle-orm/src/singlestore-core/columns/text.ts index 425da550f..d4d46ab2c 100644 --- a/drizzle-orm/src/singlestore-core/columns/text.ts +++ b/drizzle-orm/src/singlestore-core/columns/text.ts @@ -48,7 +48,7 @@ export class SingleStoreText = - SingleStoreVarCharBuilder< - { - name: TName; - dataType: 'string'; - columnType: 'SingleStoreVarChar'; - data: TEnum[number]; - driverParam: number | string; - enumValues: TEnum; - generated: undefined; - } - >; +export type SingleStoreVarCharBuilderInitial< + TName extends string, + TEnum extends [string, ...string[]], + TLength extends number | undefined, +> = SingleStoreVarCharBuilder< + { + name: TName; + dataType: 'string'; + columnType: 'SingleStoreVarChar'; + data: TEnum[number]; + driverParam: number | string; + enumValues: TEnum; + generated: undefined; + length: TLength; + } +>; -export class SingleStoreVarCharBuilder> - extends SingleStoreColumnBuilder> -{ +export class SingleStoreVarCharBuilder< + T extends ColumnBuilderBaseConfig<'string', 'SingleStoreVarChar'> & { length?: number | undefined }, +> extends SingleStoreColumnBuilder, { length: T['length'] }> { static override readonly [entityKind]: string = 'SingleStoreVarCharBuilder'; /** @internal */ - constructor(name: T['name'], config: SingleStoreVarCharConfig) { + constructor(name: T['name'], config: SingleStoreVarCharConfig) { super(name, 'string', 'SingleStoreVarChar'); this.config.length = config.length; this.config.enum = config.enum; @@ -33,21 +37,22 @@ export class SingleStoreVarCharBuilder( table: AnySingleStoreTable<{ name: TTableName }>, - ): SingleStoreVarChar & { enumValues: T['enumValues'] }> { - return new SingleStoreVarChar & { enumValues: T['enumValues'] }>( + ): SingleStoreVarChar & { length: T['length']; enumValues: T['enumValues'] }> { + return new SingleStoreVarChar< + MakeColumnConfig & { length: T['length']; enumValues: T['enumValues'] } + >( table, this.config as ColumnBuilderRuntimeConfig, ); } } -export class SingleStoreVarChar> - extends SingleStoreColumn> -{ +export class SingleStoreVarChar< + T extends ColumnBaseConfig<'string', 'SingleStoreVarChar'> & { length?: number | undefined }, +> extends SingleStoreColumn, { length: T['length'] }> { static override readonly [entityKind]: string = 'SingleStoreVarChar'; - readonly length: number | undefined = this.config.length; - + readonly length: T['length'] = this.config.length; override readonly enumValues = this.config.enum; getSQLType(): string { @@ -57,18 +62,24 @@ export class SingleStoreVarChar { - length: number; enum?: TEnum; + length?: TLength; } -export function varchar>( - config: SingleStoreVarCharConfig>, -): SingleStoreVarCharBuilderInitial<'', Writable>; -export function varchar>( +export function varchar, L extends number | undefined>( + config: SingleStoreVarCharConfig, L>, +): SingleStoreVarCharBuilderInitial<'', Writable, L>; +export function varchar< + TName extends string, + U extends string, + T extends Readonly<[U, ...U[]]>, + L extends number | undefined, +>( name: TName, - config: SingleStoreVarCharConfig>, -): SingleStoreVarCharBuilderInitial>; + config: SingleStoreVarCharConfig, L>, +): SingleStoreVarCharBuilderInitial, L>; export function varchar(a?: string | SingleStoreVarCharConfig, b?: SingleStoreVarCharConfig): any { const { name, config } = getColumnNameAndConfig(a, b); return new SingleStoreVarCharBuilder(name, config as any); diff --git a/drizzle-zod/src/column.ts b/drizzle-zod/src/column.ts index d6fff3445..23bc3c142 100644 --- a/drizzle-zod/src/column.ts +++ b/drizzle-zod/src/column.ts @@ -37,6 +37,21 @@ import type { PgVarchar, PgVector, } from 'drizzle-orm/pg-core'; +import type { + SingleStoreBigInt53, + SingleStoreChar, + SingleStoreDouble, + SingleStoreFloat, + SingleStoreInt, + SingleStoreMediumInt, + SingleStoreReal, + SingleStoreSerial, + SingleStoreSmallInt, + SingleStoreText, + SingleStoreTinyInt, + SingleStoreVarChar, + SingleStoreYear, +} from 'drizzle-orm/singlestore-core'; import type { SQLiteInteger, SQLiteReal, SQLiteText } from 'drizzle-orm/sqlite-core'; import { z } from 'zod'; import type { z as zod } from 'zod'; @@ -114,57 +129,92 @@ function numberColumnToSchema(column: Column, z: typeof zod): z.ZodTypeAny { let max!: number; let integer = false; - if (isColumnType>(column, ['MySqlTinyInt'])) { + if (isColumnType | SingleStoreTinyInt>(column, ['MySqlTinyInt', 'SingleStoreTinyInt'])) { min = unsigned ? 0 : CONSTANTS.INT8_MIN; max = unsigned ? CONSTANTS.INT8_UNSIGNED_MAX : CONSTANTS.INT8_MAX; integer = true; } else if ( - isColumnType | PgSmallSerial | MySqlSmallInt>(column, [ + isColumnType | PgSmallSerial | MySqlSmallInt | SingleStoreSmallInt>(column, [ 'PgSmallInt', 'PgSmallSerial', 'MySqlSmallInt', + 'SingleStoreSmallInt', ]) ) { min = unsigned ? 0 : CONSTANTS.INT16_MIN; max = unsigned ? CONSTANTS.INT16_UNSIGNED_MAX : CONSTANTS.INT16_MAX; integer = true; } else if ( - isColumnType | MySqlFloat | MySqlMediumInt>(column, [ + isColumnType< + PgReal | MySqlFloat | MySqlMediumInt | SingleStoreMediumInt | SingleStoreFloat + >(column, [ 'PgReal', 'MySqlFloat', 'MySqlMediumInt', + 'SingleStoreMediumInt', + 'SingleStoreFloat', ]) ) { min = unsigned ? 0 : CONSTANTS.INT24_MIN; max = unsigned ? CONSTANTS.INT24_UNSIGNED_MAX : CONSTANTS.INT24_MAX; - integer = isColumnType(column, ['MySqlMediumInt']); + integer = isColumnType(column, ['MySqlMediumInt', 'SingleStoreMediumInt']); } else if ( - isColumnType | PgSerial | MySqlInt>(column, ['PgInteger', 'PgSerial', 'MySqlInt']) + isColumnType | PgSerial | MySqlInt | SingleStoreInt>(column, [ + 'PgInteger', + 'PgSerial', + 'MySqlInt', + 'SingleStoreInt', + ]) ) { min = unsigned ? 0 : CONSTANTS.INT32_MIN; max = unsigned ? CONSTANTS.INT32_UNSIGNED_MAX : CONSTANTS.INT32_MAX; integer = true; } else if ( - isColumnType | MySqlReal | MySqlDouble | SQLiteReal>(column, [ + isColumnType< + | PgDoublePrecision + | MySqlReal + | MySqlDouble + | SingleStoreReal + | SingleStoreDouble + | SQLiteReal + >(column, [ 'PgDoublePrecision', 'MySqlReal', 'MySqlDouble', + 'SingleStoreReal', + 'SingleStoreDouble', 'SQLiteReal', ]) ) { min = unsigned ? 0 : CONSTANTS.INT48_MIN; max = unsigned ? CONSTANTS.INT48_UNSIGNED_MAX : CONSTANTS.INT48_MAX; } else if ( - isColumnType | PgBigSerial53 | MySqlBigInt53 | MySqlSerial | SQLiteInteger>( + isColumnType< + | PgBigInt53 + | PgBigSerial53 + | MySqlBigInt53 + | MySqlSerial + | SingleStoreBigInt53 + | SingleStoreSerial + | SQLiteInteger + >( column, - ['PgBigInt53', 'PgBigSerial53', 'MySqlBigInt53', 'MySqlSerial', 'SQLiteInteger'], + [ + 'PgBigInt53', + 'PgBigSerial53', + 'MySqlBigInt53', + 'MySqlSerial', + 'SingleStoreBigInt53', + 'SingleStoreSerial', + 'SQLiteInteger', + ], ) ) { - unsigned = unsigned || isColumnType(column, ['MySqlSerial']); + unsigned = unsigned || isColumnType(column, ['MySqlSerial', 'SingleStoreSerial']); min = unsigned ? 0 : Number.MIN_SAFE_INTEGER; max = Number.MAX_SAFE_INTEGER; integer = true; - } else if (isColumnType>(column, ['MySqlYear'])) { + } else if (isColumnType | SingleStoreYear>(column, ['MySqlYear', 'SingleStoreYear'])) { min = 1901; max = 2155; integer = true; @@ -196,9 +246,11 @@ function stringColumnToSchema(column: Column, z: typeof zod): z.ZodTypeAny { if (isColumnType | SQLiteText>(column, ['PgVarchar', 'SQLiteText'])) { max = column.length; - } else if (isColumnType>(column, ['MySqlVarChar'])) { + } else if ( + isColumnType | SingleStoreVarChar>(column, ['MySqlVarChar', 'SingleStoreVarChar']) + ) { max = column.length ?? CONSTANTS.INT16_UNSIGNED_MAX; - } else if (isColumnType>(column, ['MySqlText'])) { + } else if (isColumnType | SingleStoreText>(column, ['MySqlText', 'SingleStoreText'])) { if (column.textType === 'longtext') { max = CONSTANTS.INT32_UNSIGNED_MAX; } else if (column.textType === 'mediumtext') { @@ -210,7 +262,13 @@ function stringColumnToSchema(column: Column, z: typeof zod): z.ZodTypeAny { } } - if (isColumnType | MySqlChar>(column, ['PgChar', 'MySqlChar'])) { + if ( + isColumnType | MySqlChar | SingleStoreChar>(column, [ + 'PgChar', + 'MySqlChar', + 'SingleStoreChar', + ]) + ) { max = column.length; fixed = true; } diff --git a/drizzle-zod/tests/singlestore.test.ts b/drizzle-zod/tests/singlestore.test.ts new file mode 100644 index 000000000..b91c74be8 --- /dev/null +++ b/drizzle-zod/tests/singlestore.test.ts @@ -0,0 +1,491 @@ +import { type Equal } from 'drizzle-orm'; +import { customType, int, serial, singlestoreSchema, singlestoreTable, text } from 'drizzle-orm/singlestore-core'; +import { test } from 'vitest'; +import { z } from 'zod'; +import { jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectSchemaShape } from './utils.ts'; + +const intSchema = z.number().min(CONSTANTS.INT32_MIN).max(CONSTANTS.INT32_MAX).int(); +const serialNumberModeSchema = z.number().min(0).max(Number.MAX_SAFE_INTEGER).int(); +const textSchema = z.string().max(CONSTANTS.INT16_UNSIGNED_MAX); + +test('table - select', (t) => { + const table = singlestoreTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = z.object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('table in schema - select', (tc) => { + const schema = singlestoreSchema('test'); + const table = schema.table('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = z.object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('table - insert', (t) => { + const table = singlestoreTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); + + const result = createInsertSchema(table); + const expected = z.object({ + id: serialNumberModeSchema.optional(), + name: textSchema, + age: intSchema.nullable().optional(), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('table - update', (t) => { + const table = singlestoreTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); + + const result = createUpdateSchema(table); + const expected = z.object({ + id: serialNumberModeSchema.optional(), + name: textSchema.optional(), + age: intSchema.nullable().optional(), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +// TODO: SingleStore doesn't support views yet. Add these tests when they're added + +// test('view qb - select', (t) => { +// const table = singlestoreTable('test', { +// id: serial().primaryKey(), +// name: text().notNull(), +// }); +// const view = mysqlView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + +// const result = createSelectSchema(view); +// const expected = z.object({ id: serialNumberModeSchema, age: z.any() }); +// expectSchemaShape(t, expected).from(result); +// Expect>(); +// }); + +// test('view columns - select', (t) => { +// const view = mysqlView('test', { +// id: serial().primaryKey(), +// name: text().notNull(), +// }).as(sql``); + +// const result = createSelectSchema(view); +// const expected = z.object({ id: serialNumberModeSchema, name: textSchema }); +// expectSchemaShape(t, expected).from(result); +// Expect>(); +// }); + +// test('view with nested fields - select', (t) => { +// const table = singlestoreTable('test', { +// id: serial().primaryKey(), +// name: text().notNull(), +// }); +// const view = mysqlView('test').as((qb) => +// qb.select({ +// id: table.id, +// nested: { +// name: table.name, +// age: sql``.as('age'), +// }, +// table, +// }).from(table) +// ); + +// const result = createSelectSchema(view); +// const expected = z.object({ +// id: serialNumberModeSchema, +// nested: z.object({ name: textSchema, age: z.any() }), +// table: z.object({ id: serialNumberModeSchema, name: textSchema }), +// }); +// expectSchemaShape(t, expected).from(result); +// Expect>(); +// }); + +test('nullability - select', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + }); + + const result = createSelectSchema(table); + const expected = z.object({ + c1: intSchema.nullable(), + c2: intSchema, + c3: intSchema.nullable(), + c4: intSchema, + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('nullability - insert', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table); + const expected = z.object({ + c1: intSchema.nullable().optional(), + c2: intSchema, + c3: intSchema.nullable().optional(), + c4: intSchema.optional(), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('nullability - update', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table); + const expected = z.object({ + c1: intSchema.nullable().optional(), + c2: intSchema.optional(), + c3: intSchema.nullable().optional(), + c4: intSchema.optional(), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - select', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + }); + + const result = createSelectSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); + const expected = z.object({ + c1: intSchema.nullable(), + c2: intSchema.max(1000), + c3: z.string().transform(Number), + }); + + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - select with custom data type', (t) => { + const customText = customType({ dataType: () => 'text' }); + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: customText(), + }); + + const customTextSchema = z.string().min(1).max(100); + const result = createSelectSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + c4: customTextSchema, + }); + const expected = z.object({ + c1: intSchema.nullable(), + c2: intSchema.max(1000), + c3: z.string().transform(Number), + c4: customTextSchema, + }); + + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - insert', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); + const expected = z.object({ + c1: intSchema.nullable().optional(), + c2: intSchema.max(1000), + c3: z.string().transform(Number), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - update', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table, { + c2: (schema) => schema.max(1000), + c3: z.string().transform(Number), + }); + const expected = z.object({ + c1: intSchema.nullable().optional(), + c2: intSchema.max(1000).optional(), + c3: z.string().transform(Number), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +// test('refine view - select', (t) => { +// const table = singlestoreTable('test', { +// c1: int(), +// c2: int(), +// c3: int(), +// c4: int(), +// c5: int(), +// c6: int(), +// }); +// const view = mysqlView('test').as((qb) => +// qb.select({ +// c1: table.c1, +// c2: table.c2, +// c3: table.c3, +// nested: { +// c4: table.c4, +// c5: table.c5, +// c6: table.c6, +// }, +// table, +// }).from(table) +// ); + +// const result = createSelectSchema(view, { +// c2: (schema) => schema.max(1000), +// c3: z.string().transform(Number), +// nested: { +// c5: (schema) => schema.max(1000), +// c6: z.string().transform(Number), +// }, +// table: { +// c2: (schema) => schema.max(1000), +// c3: z.string().transform(Number), +// }, +// }); +// const expected = z.object({ +// c1: intSchema.nullable(), +// c2: intSchema.max(1000).nullable(), +// c3: z.string().transform(Number), +// nested: z.object({ +// c4: intSchema.nullable(), +// c5: intSchema.max(1000).nullable(), +// c6: z.string().transform(Number), +// }), +// table: z.object({ +// c1: intSchema.nullable(), +// c2: intSchema.max(1000).nullable(), +// c3: z.string().transform(Number), +// c4: intSchema.nullable(), +// c5: intSchema.nullable(), +// c6: intSchema.nullable(), +// }), +// }); +// expectSchemaShape(t, expected).from(result); +// Expect>(); +// }); + +test('all data types', (t) => { + const table = singlestoreTable('test', ({ + bigint, + binary, + boolean, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + singlestoreEnum, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varchar, + varbinary, + year, + longtext, + mediumtext, + tinytext, + }) => ({ + bigint1: bigint({ mode: 'number' }).notNull(), + bigint2: bigint({ mode: 'bigint' }).notNull(), + bigint3: bigint({ unsigned: true, mode: 'number' }).notNull(), + bigint4: bigint({ unsigned: true, mode: 'bigint' }).notNull(), + binary: binary({ length: 10 }).notNull(), + boolean: boolean().notNull(), + char1: char({ length: 10 }).notNull(), + char2: char({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + date1: date({ mode: 'date' }).notNull(), + date2: date({ mode: 'string' }).notNull(), + datetime1: datetime({ mode: 'date' }).notNull(), + datetime2: datetime({ mode: 'string' }).notNull(), + decimal1: decimal().notNull(), + decimal2: decimal({ unsigned: true }).notNull(), + double1: double().notNull(), + double2: double({ unsigned: true }).notNull(), + float1: float().notNull(), + float2: float({ unsigned: true }).notNull(), + int1: int().notNull(), + int2: int({ unsigned: true }).notNull(), + json: json().notNull(), + mediumint1: mediumint().notNull(), + mediumint2: mediumint({ unsigned: true }).notNull(), + enum: singlestoreEnum('enum', ['a', 'b', 'c']).notNull(), + real: real().notNull(), + serial: serial().notNull(), + smallint1: smallint().notNull(), + smallint2: smallint({ unsigned: true }).notNull(), + text1: text().notNull(), + text2: text({ enum: ['a', 'b', 'c'] }).notNull(), + time: time().notNull(), + timestamp1: timestamp({ mode: 'date' }).notNull(), + timestamp2: timestamp({ mode: 'string' }).notNull(), + tinyint1: tinyint().notNull(), + tinyint2: tinyint({ unsigned: true }).notNull(), + varchar1: varchar({ length: 10 }).notNull(), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + varbinary: varbinary({ length: 10 }).notNull(), + year: year().notNull(), + longtext1: longtext().notNull(), + longtext2: longtext({ enum: ['a', 'b', 'c'] }).notNull(), + mediumtext1: mediumtext().notNull(), + mediumtext2: mediumtext({ enum: ['a', 'b', 'c'] }).notNull(), + tinytext1: tinytext().notNull(), + tinytext2: tinytext({ enum: ['a', 'b', 'c'] }).notNull(), + })); + + const result = createSelectSchema(table); + const expected = z.object({ + bigint1: z.number().min(Number.MIN_SAFE_INTEGER).max(Number.MAX_SAFE_INTEGER).int(), + bigint2: z.bigint().min(CONSTANTS.INT64_MIN).max(CONSTANTS.INT64_MAX), + bigint3: z.number().min(0).max(Number.MAX_SAFE_INTEGER).int(), + bigint4: z.bigint().min(0n).max(CONSTANTS.INT64_UNSIGNED_MAX), + binary: z.string(), + boolean: z.boolean(), + char1: z.string().length(10), + char2: z.enum(['a', 'b', 'c']), + date1: z.date(), + date2: z.string(), + datetime1: z.date(), + datetime2: z.string(), + decimal1: z.string(), + decimal2: z.string(), + double1: z.number().min(CONSTANTS.INT48_MIN).max(CONSTANTS.INT48_MAX), + double2: z.number().min(0).max(CONSTANTS.INT48_UNSIGNED_MAX), + float1: z.number().min(CONSTANTS.INT24_MIN).max(CONSTANTS.INT24_MAX), + float2: z.number().min(0).max(CONSTANTS.INT24_UNSIGNED_MAX), + int1: z.number().min(CONSTANTS.INT32_MIN).max(CONSTANTS.INT32_MAX).int(), + int2: z.number().min(0).max(CONSTANTS.INT32_UNSIGNED_MAX).int(), + json: jsonSchema, + mediumint1: z.number().min(CONSTANTS.INT24_MIN).max(CONSTANTS.INT24_MAX).int(), + mediumint2: z.number().min(0).max(CONSTANTS.INT24_UNSIGNED_MAX).int(), + enum: z.enum(['a', 'b', 'c']), + real: z.number().min(CONSTANTS.INT48_MIN).max(CONSTANTS.INT48_MAX), + serial: z.number().min(0).max(Number.MAX_SAFE_INTEGER).int(), + smallint1: z.number().min(CONSTANTS.INT16_MIN).max(CONSTANTS.INT16_MAX).int(), + smallint2: z.number().min(0).max(CONSTANTS.INT16_UNSIGNED_MAX).int(), + text1: z.string().max(CONSTANTS.INT16_UNSIGNED_MAX), + text2: z.enum(['a', 'b', 'c']), + time: z.string(), + timestamp1: z.date(), + timestamp2: z.string(), + tinyint1: z.number().min(CONSTANTS.INT8_MIN).max(CONSTANTS.INT8_MAX).int(), + tinyint2: z.number().min(0).max(CONSTANTS.INT8_UNSIGNED_MAX).int(), + varchar1: z.string().max(10), + varchar2: z.enum(['a', 'b', 'c']), + varbinary: z.string(), + year: z.number().min(1901).max(2155).int(), + longtext1: z.string().max(CONSTANTS.INT32_UNSIGNED_MAX), + longtext2: z.enum(['a', 'b', 'c']), + mediumtext1: z.string().max(CONSTANTS.INT24_UNSIGNED_MAX), + mediumtext2: z.enum(['a', 'b', 'c']), + tinytext1: z.string().max(CONSTANTS.INT8_UNSIGNED_MAX), + tinytext2: z.enum(['a', 'b', 'c']), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +/* Disallow unknown keys in table refinement - select */ { + const table = singlestoreTable('test', { id: int() }); + // @ts-expect-error + createSelectSchema(table, { unknown: z.string() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = singlestoreTable('test', { id: int() }); + // @ts-expect-error + createInsertSchema(table, { unknown: z.string() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = singlestoreTable('test', { id: int() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: z.string() }); +} + +// /* Disallow unknown keys in view qb - select */ { +// const table = singlestoreTable('test', { id: int() }); +// const view = mysqlView('test').as((qb) => qb.select().from(table)); +// const nestedSelect = mysqlView('test').as((qb) => qb.select({ table }).from(table)); +// // @ts-expect-error +// createSelectSchema(view, { unknown: z.string() }); +// // @ts-expect-error +// createSelectSchema(nestedSelect, { table: { unknown: z.string() } }); +// } + +// /* Disallow unknown keys in view columns - select */ { +// const view = mysqlView('test', { id: int() }).as(sql``); +// // @ts-expect-error +// createSelectSchema(view, { unknown: z.string() }); +// } From 6f8a6ccfbe0af44a3a8b50717016be873de95ce1 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Tue, 17 Dec 2024 12:45:58 -0800 Subject: [PATCH 450/492] Fix infinitely recursive type in drizzle-valibot --- drizzle-valibot/src/column.types.ts | 98 +++++++------------- drizzle-valibot/src/schema.types.internal.ts | 3 +- 2 files changed, 32 insertions(+), 69 deletions(-) diff --git a/drizzle-valibot/src/column.types.ts b/drizzle-valibot/src/column.types.ts index e6cd797ed..b9567b12d 100644 --- a/drizzle-valibot/src/column.types.ts +++ b/drizzle-valibot/src/column.types.ts @@ -30,21 +30,23 @@ export type ExtractAdditionalProperties = { fixedLength: TColumn['_']['columnType'] extends 'PgChar' | 'MySqlChar' | 'PgHalfVector' | 'PgVector' | 'PgArray' ? true : false; - arrayPipelines: []; }; -type RemovePipeIfNoElements> = T extends - infer TPiped extends { pipe: [any, ...any[]] } ? TPiped['pipe'][1] extends undefined ? T['pipe'][0] : TPiped - : never; +type GetLengthAction, TType extends string | ArrayLike> = + T['fixedLength'] extends true ? v.LengthAction + : v.MaxLengthAction; -type BuildArraySchema< - TWrapped extends v.GenericSchema, - TPipelines extends any[][], -> = TPipelines extends [infer TFirst extends any[], ...infer TRest extends any[][]] - ? BuildArraySchema, ...TFirst]>>, TRest> - : TPipelines extends [infer TFirst extends any[]] - ? BuildArraySchema, ...TFirst]>>, []> - : TWrapped; +type GetArraySchema = v.ArraySchema< + GetValibotType< + T['_']['data'], + T['_']['dataType'], + T['_']['columnType'], + GetEnumValuesFromColumn, + GetBaseColumn, + ExtractAdditionalProperties + >, + undefined +>; export type GetValibotType< TData, @@ -53,51 +55,22 @@ export type GetValibotType< TEnumValues extends [string, ...string[]] | undefined, TBaseColumn extends Column | undefined, TAdditionalProperties extends Record, -> = TColumnType extends 'PgHalfVector' | 'PgVector' ? RemovePipeIfNoElements< - v.SchemaWithPipe< - RemoveNeverElements<[ - v.ArraySchema, undefined>, - TAdditionalProperties['max'] extends number - ? TAdditionalProperties['fixedLength'] extends true ? v.LengthAction - : v.MaxLengthAction - : never, - ]> +> = TColumnType extends 'PgHalfVector' | 'PgVector' ? TAdditionalProperties['max'] extends number ? v.SchemaWithPipe< + [v.ArraySchema, undefined>, GetLengthAction] > - > + : v.ArraySchema, undefined> : TColumnType extends 'PgUUID' ? v.SchemaWithPipe<[v.StringSchema, v.UuidAction]> - // PG array handling start - // Nesting `GetValibotType` within `v.ArraySchema` will cause infinite recursion - // The workaround is to accumulate all the array validations (done via `arrayPipelines` in `TAdditionalProperties`) and then build the schema afterwards - : TAdditionalProperties['arrayFinished'] extends true ? GetValibotType< - TData, - TDataType, - TColumnType, - TEnumValues, - TBaseColumn, - Omit - > extends infer TSchema extends v.GenericSchema ? BuildArraySchema - : never - : TBaseColumn extends Column ? GetValibotType< - TBaseColumn['_']['data'], - TBaseColumn['_']['dataType'], - TBaseColumn['_']['columnType'], - GetEnumValuesFromColumn, - GetBaseColumn, - Omit, 'arrayPipelines'> & { - arrayPipelines: [ - RemoveNeverElements<[ - TAdditionalProperties['max'] extends number - ? TAdditionalProperties['fixedLength'] extends true - ? v.LengthAction[], number, undefined> - : v.MaxLengthAction[], number, undefined> - : never, - ]>, - ...TAdditionalProperties['arrayPipelines'], - ]; - arrayFinished: GetBaseColumn extends undefined ? true : false; - } + : TColumnType extends 'PgBinaryVector' ? v.SchemaWithPipe< + RemoveNeverElements<[ + v.StringSchema, + v.RegexAction, + TAdditionalProperties['max'] extends number ? GetLengthAction : never, + ]> > - // PG array handling end + : TBaseColumn extends Column ? TAdditionalProperties['max'] extends number ? v.SchemaWithPipe< + [GetArraySchema, GetLengthAction] + > + : GetArraySchema : ArrayHasAtLeastOneValue extends true ? v.EnumSchema>, undefined> : TData extends infer TTuple extends [any, ...any[]] ? v.TupleSchema< @@ -147,19 +120,10 @@ export type GetValibotType< v.MaxValueAction, ]> : TData extends boolean ? v.BooleanSchema - : TData extends string ? RemovePipeIfNoElements< - v.SchemaWithPipe< - RemoveNeverElements<[ - v.StringSchema, - TColumnType extends 'PgBinaryVector' ? v.RegexAction - : never, - TAdditionalProperties['max'] extends number - ? TAdditionalProperties['fixedLength'] extends true ? v.LengthAction - : v.MaxLengthAction - : never, - ]> - > - > + : TData extends string + ? TAdditionalProperties['max'] extends number + ? v.SchemaWithPipe<[v.StringSchema, GetLengthAction]> + : v.StringSchema : v.AnySchema; type HandleSelectColumn< diff --git a/drizzle-valibot/src/schema.types.internal.ts b/drizzle-valibot/src/schema.types.internal.ts index 57dcedc7c..e39c34d8a 100644 --- a/drizzle-valibot/src/schema.types.internal.ts +++ b/drizzle-valibot/src/schema.types.internal.ts @@ -67,8 +67,7 @@ export type BuildSchema< TType extends 'select' | 'insert' | 'update', TColumns extends Record, TRefinements extends Record | undefined, -> // @ts-ignore false-positive - = v.ObjectSchema< +> = v.ObjectSchema< Simplify< RemoveNever< { From 1b05f63f6ce744d779acec6d008cedd1914bd1ad Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Wed, 18 Dec 2024 14:04:38 +0200 Subject: [PATCH 451/492] fixes, partial implementation of generator versioning --- drizzle-seed/src/index.ts | 26 +- drizzle-seed/src/services/GeneratorFuncs.ts | 737 +++++++++++++++++ .../GeneratorVersions/GeneratorsV1.ts | 15 + .../{GeneratorsWrappers.ts => Generators.ts} | 739 +----------------- drizzle-seed/src/services/SeedService.ts | 228 +++--- drizzle-seed/src/types/seedService.ts | 2 +- .../tests/benchmarks/generatorsBenchmark.ts | 2 +- 7 files changed, 912 insertions(+), 837 deletions(-) create mode 100644 drizzle-seed/src/services/GeneratorFuncs.ts create mode 100644 drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts rename drizzle-seed/src/services/{GeneratorsWrappers.ts => Generators.ts} (81%) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index fde4442a1..248e7ead5 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -9,8 +9,8 @@ import { getTableConfig as getPgTableConfig, PgDatabase, PgTable } from 'drizzle import type { SQLiteColumn } from 'drizzle-orm/sqlite-core'; import { BaseSQLiteDatabase, getTableConfig as getSqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; -import type { AbstractGenerator } from './services/GeneratorsWrappers.ts'; -import { generatorsFuncs } from './services/GeneratorsWrappers.ts'; +import { generatorsFuncs } from './services/GeneratorFuncs.ts'; +import type { AbstractGenerator } from './services/Generators.ts'; import { SeedService } from './services/SeedService.ts'; import type { DrizzleStudioObjectType, DrizzleStudioRelationType } from './types/drizzleStudio.ts'; import type { RefinementsType } from './types/seedService.ts'; @@ -138,7 +138,7 @@ class SeedPromise< constructor( private db: DB, private schema: SCHEMA, - private options?: { count?: number; seed?: number }, + private options?: { count?: number; seed?: number; version?: number }, ) {} then( @@ -259,7 +259,6 @@ export async function seedForDrizzleStudio( sqlDialect, tables, isCyclicRelations, - {}, // TODO: fix later refinements, options, ); @@ -337,7 +336,7 @@ export function seed< | SQLiteTable | any; }, ->(db: DB, schema: SCHEMA, options?: { count?: number; seed?: number }) { +>(db: DB, schema: SCHEMA, options?: { count?: number; seed?: number; version?: number }) { return new SeedPromise(db, schema, options); } @@ -352,7 +351,7 @@ const seedFunc = async ( | SQLiteTable | any; }, - options: { count?: number; seed?: number } = {}, + options: { count?: number; seed?: number; version?: number } = {}, refinements?: RefinementsType, ) => { if (is(db, PgDatabase)) { @@ -490,17 +489,16 @@ const filterPgTables = (schema: { const seedPostgres = async ( db: PgDatabase, schema: { [key: string]: PgTable }, - options: { count?: number; seed?: number } = {}, + options: { count?: number; seed?: number; version?: number } = {}, refinements?: RefinementsType, ) => { const seedService = new SeedService(); - const { tables, relations, tableRelations } = getPostgresInfo(schema); + const { tables, relations } = getPostgresInfo(schema); const generatedTablesGenerators = seedService.generatePossibleGenerators( 'postgresql', tables, relations, - tableRelations, refinements, options, ); @@ -784,10 +782,10 @@ const filterMySqlTables = (schema: { const seedMySql = async ( db: MySqlDatabase, schema: { [key: string]: MySqlTable }, - options: { count?: number; seed?: number } = {}, + options: { count?: number; seed?: number; version?: number } = {}, refinements?: RefinementsType, ) => { - const { tables, relations, tableRelations } = getMySqlInfo(schema); + const { tables, relations } = getMySqlInfo(schema); const seedService = new SeedService(); @@ -795,7 +793,6 @@ const seedMySql = async ( 'mysql', tables, relations, - tableRelations, refinements, options, ); @@ -1003,10 +1000,10 @@ const filterSqliteTables = (schema: { const seedSqlite = async ( db: BaseSQLiteDatabase, schema: { [key: string]: SQLiteTable }, - options: { count?: number; seed?: number } = {}, + options: { count?: number; seed?: number; version?: number } = {}, refinements?: RefinementsType, ) => { - const { tables, relations, tableRelations } = getSqliteInfo(schema); + const { tables, relations } = getSqliteInfo(schema); const seedService = new SeedService(); @@ -1014,7 +1011,6 @@ const seedSqlite = async ( 'sqlite', tables, relations, - tableRelations, refinements, options, ); diff --git a/drizzle-seed/src/services/GeneratorFuncs.ts b/drizzle-seed/src/services/GeneratorFuncs.ts new file mode 100644 index 000000000..08f36b1dc --- /dev/null +++ b/drizzle-seed/src/services/GeneratorFuncs.ts @@ -0,0 +1,737 @@ +import type { AbstractGenerator } from './Generators.ts'; +import { + GenerateBoolean, + GenerateCity, + GenerateCompanyName, + GenerateCountry, + GenerateDate, + GenerateDatetime, + GenerateDefault, + GenerateEmail, + GenerateFirstName, + GenerateFullName, + GenerateInt, + GenerateInterval, + GenerateIntPrimaryKey, + GenerateJobTitle, + GenerateJson, + GenerateLastName, + GenerateLine, + GenerateLoremIpsum, + GenerateNumber, + GeneratePhoneNumber, + GeneratePoint, + GeneratePostcode, + GenerateState, + GenerateStreetAdddress, + GenerateString, + GenerateTime, + GenerateTimestamp, + GenerateUUID, + GenerateValuesFromArray, + GenerateYear, + WeightedRandomGenerator, +} from './Generators.ts'; + +function createGenerator, T>( + generatorConstructor: new(params: T) => GeneratorType, +) { + return ( + ...args: GeneratorType extends GenerateValuesFromArray | GenerateDefault | WeightedRandomGenerator ? [T] + : ([] | [T]) + ): GeneratorType => { + let params = args[0]; + if (params === undefined) params = {} as T; + return new generatorConstructor(params); + }; +} + +export const generatorsFuncs = { + /** + * generates same given value each time the generator is called. + * @param defaultValue - value you want to generate + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.default({ defaultValue: "post content" }), + * }, + * }, + * })); + * ``` + */ + default: createGenerator(GenerateDefault), + + /** + * generates values from given array + * @param values - array of values you want to generate. can be array of weighted values. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * title: funcs.valuesFromArray({ + * values: ["Title1", "Title2", "Title3", "Title4", "Title5"], + * isUnique: true + * }), + * }, + * }, + * })); + * + * ``` + * weighted values example + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * title: funcs.valuesFromArray({ + * values: [ + * { weight: 0.35, values: ["Title1", "Title2"] }, + * { weight: 0.5, values: ["Title3", "Title4"] }, + * { weight: 0.15, values: ["Title5"] }, + * ], + * isUnique: false + * }), + * }, + * }, + * })); + * + * ``` + */ + valuesFromArray: createGenerator(GenerateValuesFromArray), + + /** + * generates sequential integers starting with 1. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * id: funcs.intPrimaryKey(), + * }, + * }, + * })); + * + * ``` + */ + intPrimaryKey: createGenerator(GenerateIntPrimaryKey), + + /** + * generates numbers with floating point in given range. + * @param minValue - lower border of range. + * @param maxValue - upper border of range. + * @param precision - precision of generated number: + * precision equals 10 means that values will be accurate to one tenth (1.2, 34.6); + * precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67). + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * products: { + * columns: { + * unitPrice: funcs.number({ minValue: 10, maxValue: 120, precision: 100, isUnique: false }), + * }, + * }, + * })); + * + * ``` + */ + number: createGenerator(GenerateNumber), + // uniqueNumber: createGenerator(GenerateUniqueNumber), + + /** + * generates integers within given range. + * @param minValue - lower border of range. + * @param maxValue - upper border of range. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * products: { + * columns: { + * unitsInStock: funcs.number({ minValue: 0, maxValue: 100, isUnique: false }), + * }, + * }, + * })); + * + * ``` + */ + int: createGenerator(GenerateInt), + // uniqueInt: createGenerator(GenerateUniqueInt), + + /** + * generates boolean values(true or false) + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * isAvailable: funcs.boolean() + * }, + * }, + * })); + * + * ``` + */ + boolean: createGenerator(GenerateBoolean), + + /** + * generates date within given range. + * @param minDate - lower border of range. + * @param maxDate - upper border of range. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthDate: funcs.date({ minDate: "1990-01-01", maxDate: "2010-12-31" }) + * }, + * }, + * })); + * + * ``` + */ + date: createGenerator(GenerateDate), + + /** + * generates time in 24 hours style. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthTime: funcs.time() + * }, + * }, + * })); + * + * ``` + */ + time: createGenerator(GenerateTime), + + /** + * generates timestamps. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * orders: { + * columns: { + * shippedDate: funcs.timestamp() + * }, + * }, + * })); + * + * ``` + */ + timestamp: createGenerator(GenerateTimestamp), + + /** + * generates datetime objects. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * orders: { + * columns: { + * shippedDate: funcs.datetime() + * }, + * }, + * })); + * + * ``` + */ + datetime: createGenerator(GenerateDatetime), + + /** + * generates years. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthYear: funcs.year() + * }, + * }, + * })); + * + * ``` + */ + year: createGenerator(GenerateYear), + + /** + * generates json objects with fixed structure. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * json structure can equal this: + * ``` + * { + * email, + * name, + * isGraduated, + * hasJob, + * salary, + * startedWorking, + * visitedCountries, + * } + * ``` + * or this + * ``` + * { + * email, + * name, + * isGraduated, + * hasJob, + * visitedCountries, + * } + * ``` + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * metadata: funcs.json() + * }, + * }, + * })); + * ``` + */ + json: createGenerator(GenerateJson), + // jsonb: createGenerator(GenerateJsonb), + + /** + * generates time intervals. + * + * interval example: "1 years 12 days 5 minutes" + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * @param fields - range of values you want to see in your intervals. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * timeSpentOnWebsite: funcs.interval() + * }, + * }, + * })); + * ``` + */ + interval: createGenerator(GenerateInterval), + // uniqueInterval: createGenerator(GenerateUniqueInterval), + + /** + * generates random strings. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * hashedPassword: funcs.string({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + string: createGenerator(GenerateString), + // uniqueString: createGenerator(GenerateUniqueString), + + /** + * generates v4 UUID strings if arraySize is not specified, or v4 UUID 1D arrays if it is. + * + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * uuid: funcs.uuid({ + * arraySize: 4 + * }) + * }, + * }, + * })); + * ``` + */ + uuid: createGenerator(GenerateUUID), + + /** + * generates person's first names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * firstName: funcs.firstName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + firstName: createGenerator(GenerateFirstName), + // uniqueFirstName: createGenerator(GenerateUniqueName), + + /** + * generates person's last names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * lastName: funcs.lastName({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + lastName: createGenerator(GenerateLastName), + // uniqueLastName: createGenerator(GenerateUniqueSurname), + + /** + * generates person's full names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * fullName: funcs.fullName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + fullName: createGenerator(GenerateFullName), + // uniqueFullName: createGenerator(GenerateUniqueFullName), + + /** + * generates unique emails. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * email: funcs.email() + * }, + * }, + * })); + * ``` + */ + email: createGenerator(GenerateEmail), + + /** + * generates unique phone numbers. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @param template - phone number template, where all '#' symbols will be substituted with generated digits. + * @param prefixes - array of any string you want to be your phone number prefixes.(not compatible with template property) + * @param generatedDigitsNumbers - number of digits that will be added at the end of prefixes.(not compatible with template property) + * @example + * ```ts + * //generate phone number using template property + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({template: "+(380) ###-####"}) + * }, + * }, + * })); + * + * //generate phone number using prefixes and generatedDigitsNumbers properties + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67" ], generatedDigitsNumbers: 7}) + * }, + * }, + * })); + * + * //generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67", "+1" ], generatedDigitsNumbers: [7, 7, 10]}) + * }, + * }, + * })); + * + * ``` + */ + phoneNumber: createGenerator(GeneratePhoneNumber), + + /** + * generates country's names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * country: funcs.country({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + country: createGenerator(GenerateCountry), + // uniqueCountry: createGenerator(GenerateUniqueCountry), + + /** + * generates city's names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * city: funcs.city({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + city: createGenerator(GenerateCity), + // uniqueCity: createGenerator(GenerateUniqueCityName), + + /** + * generates street address. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * streetAddress: funcs.streetAddress({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + streetAddress: createGenerator(GenerateStreetAdddress), + // uniqueStreetAddress: createGenerator(GenerateUniqueStreetAdddress), + + /** + * generates job titles. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * jobTitle: funcs.jobTitle() + * }, + * }, + * })); + * ``` + */ + jobTitle: createGenerator(GenerateJobTitle), + + /** + * generates postal codes. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * postcode: funcs.postcode({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + postcode: createGenerator(GeneratePostcode), + // uniquePostcoe: createGenerator(GenerateUniquePostcode), + + /** + * generates states of America. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * state: funcs.state() + * }, + * }, + * })); + * ``` + */ + state: createGenerator(GenerateState), + + /** + * generates company's names. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * company: funcs.companyName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + companyName: createGenerator(GenerateCompanyName), + // uniqueCompanyName: createGenerator(GenerateUniqueCompanyName), + + /** + * generates 'lorem ipsum' text sentences. + * + * @param sentencesCount - number of sentences you want to generate as one generated value(string). + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.loremIpsum({sentencesCount: 2}) + * }, + * }, + * })); + * ``` + */ + loremIpsum: createGenerator(GenerateLoremIpsum), + + /** + * generates 2D points within specified ranges for x and y coordinates. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param minXValue - lower bound of range for x coordinate. + * @param maxXValue - upper bound of range for x coordinate. + * @param minYValue - lower bound of range for y coordinate. + * @param maxYValue - upper bound of range for y coordinate. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * triangles: { + * columns: { + * pointCoords: funcs.point({ + * isUnique: true, + * minXValue: -5, maxXValue:20, + * minYValue: 0, maxYValue: 30 + * }) + * }, + * }, + * })); + * ``` + */ + point: createGenerator(GeneratePoint), + // uniquePoint: createGenerator(GenerateUniquePoint), + + /** + * generates 2D lines within specified ranges for a, b and c parameters of line. + * + * ``` + * line equation: a*x + b*y + c = 0 + * ``` + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param minAValue - lower bound of range for a parameter. + * @param maxAValue - upper bound of range for x parameter. + * @param minBValue - lower bound of range for y parameter. + * @param maxBValue - upper bound of range for y parameter. + * @param minCValue - lower bound of range for y parameter. + * @param maxCValue - upper bound of range for y parameter. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * lines: { + * columns: { + * lineParams: funcs.point({ + * isUnique: true, + * minAValue: -5, maxAValue:20, + * minBValue: 0, maxBValue: 30, + * minCValue: 0, maxCValue: 10 + * }) + * }, + * }, + * })); + * ``` + */ + line: createGenerator(GenerateLine), + // uniqueLine: createGenerator(GenerateUniqueLine), + + /** + * gives you the opportunity to call different generators with different probabilities to generate values for one column. + * @param params - array of generators with probabilities you would like to call them to generate values. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.weightedRandom([ + * { + * weight: 0.6, + * value: funcs.loremIpsum({ sentencesCount: 3 }), + * }, + * { + * weight: 0.4, + * value: funcs.default({ defaultValue: "TODO" }), + * }, + * ]), + * }, + * }, + * })); + * ``` + */ + weightedRandom: createGenerator(WeightedRandomGenerator), +}; diff --git a/drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts b/drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts new file mode 100644 index 000000000..e4fed2926 --- /dev/null +++ b/drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts @@ -0,0 +1,15 @@ +import { entityKind } from 'drizzle-orm'; +import { GenerateInterval, GenerateUniqueInterval } from '../Generators.ts'; + +export const version = 1; + +export class GenerateIntervalV1 extends GenerateInterval { + static override readonly [entityKind]: string = 'GenerateInterval'; + static override readonly ['version']: number = 1; + override uniqueVersionOfGen = GenerateUniqueIntervalV1; +} + +export class GenerateUniqueIntervalV1 extends GenerateUniqueInterval { + static override readonly [entityKind]: string = 'GenerateUniqueInterval'; + static override readonly ['version']: number = 1; +} diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/Generators.ts similarity index 81% rename from drizzle-seed/src/services/GeneratorsWrappers.ts rename to drizzle-seed/src/services/Generators.ts index 4ab06ec3f..f5fc44aab 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/Generators.ts @@ -14,8 +14,11 @@ import states, { maxStringLength as maxStateLength } from '../datasets/states.ts import streetSuffix, { maxStringLength as maxStreetSuffixLength } from '../datasets/streetSuffix.ts'; import { fastCartesianProduct, fillTemplate, getWeightedIndices, isObject } from './utils.ts'; +export const version = 2; + export abstract class AbstractGenerator { static readonly [entityKind]: string = 'AbstractGenerator'; + static readonly ['version']: number = 2; public isUnique = false; public notNull = false; @@ -90,19 +93,6 @@ export abstract class AbstractGenerator { } } -function createGenerator, T>( - generatorConstructor: new(params: T) => GeneratorType, -) { - return ( - ...args: GeneratorType extends GenerateValuesFromArray | GenerateDefault | WeightedRandomGenerator ? [T] - : ([] | [T]) - ): GeneratorType => { - let params = args[0]; - if (params === undefined) params = {} as T; - return new generatorConstructor(params); - }; -} - // Generators Classes ----------------------------------------------------------------------------------------------------------------------- export class GenerateArray extends AbstractGenerator<{ baseColumnGen: AbstractGenerator; size?: number }> { static override readonly [entityKind]: string = 'GenerateArray'; @@ -1253,7 +1243,7 @@ export class GenerateInterval extends AbstractGenerator<{ }, month: { from: 0, - to: 11, + to: 12, }, day: { from: 1, @@ -1261,15 +1251,15 @@ export class GenerateInterval extends AbstractGenerator<{ }, hour: { from: 0, - to: 23, + to: 24, }, minute: { from: 0, - to: 59, + to: 60, }, second: { from: 0, - to: 59, + to: 60, }, }; @@ -1288,8 +1278,6 @@ export class GenerateInterval extends AbstractGenerator<{ fieldsToGenerate = allFields.slice(0, endIdx + 1); } - this.config[fieldsToGenerate[Math.floor(fieldsToGenerate.length / 2)]!]!.from = 1; - const rng = prand.xoroshiro128plus(seed); this.state = { rng, fieldsToGenerate }; } @@ -1304,7 +1292,7 @@ export class GenerateInterval extends AbstractGenerator<{ for (const field of this.state.fieldsToGenerate) { const from = this.config[field]!.from, to = this.config[field]!.to; [numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng); - interval += `${numb === 0 ? '' : `${numb} ${field} `}`; + interval += `${numb} ${field} `; } return interval; @@ -1376,8 +1364,6 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ fieldsToGenerate = allFields.slice(0, endIdx + 1); } - this.config[fieldsToGenerate[Math.floor(fieldsToGenerate.length / 2)]!]!.from = 1; - let maxUniqueIntervalsNumber = 1; for (const field of fieldsToGenerate) { const from = this.config[field]!.from, to = this.config[field]!.to; @@ -1398,12 +1384,21 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ throw new Error('state is not defined.'); } - let interval = '', numb: number; + let interval, numb: number; - for (const field of this.state.fieldsToGenerate) { - const from = this.config[field]!.from, to = this.config[field]!.to; - [numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng); - interval += `${numb === 0 ? '' : `${numb} ${field} `}`; + for (;;) { + interval = ''; + + for (const field of this.state.fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + [numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng); + interval += `${numb} ${field} `; + } + + if (!this.state.intervalSet.has(interval)) { + this.state.intervalSet.add(interval); + break; + } } return interval; @@ -3137,693 +3132,3 @@ export class GenerateUniqueLine extends AbstractGenerator<{ } } } - -export const generatorsFuncs = { - /** - * generates same given value each time the generator is called. - * @param defaultValue - value you want to generate - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * content: funcs.default({ defaultValue: "post content" }), - * }, - * }, - * })); - * ``` - */ - default: createGenerator(GenerateDefault), - - /** - * generates values from given array - * @param values - array of values you want to generate. can be array of weighted values. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * title: funcs.valuesFromArray({ - * values: ["Title1", "Title2", "Title3", "Title4", "Title5"], - * isUnique: true - * }), - * }, - * }, - * })); - * - * ``` - * weighted values example - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * title: funcs.valuesFromArray({ - * values: [ - * { weight: 0.35, values: ["Title1", "Title2"] }, - * { weight: 0.5, values: ["Title3", "Title4"] }, - * { weight: 0.15, values: ["Title5"] }, - * ], - * isUnique: false - * }), - * }, - * }, - * })); - * - * ``` - */ - valuesFromArray: createGenerator(GenerateValuesFromArray), - - /** - * generates sequential integers starting with 1. - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * id: funcs.intPrimaryKey(), - * }, - * }, - * })); - * - * ``` - */ - intPrimaryKey: createGenerator(GenerateIntPrimaryKey), - - /** - * generates numbers with floating point in given range. - * @param minValue - lower border of range. - * @param maxValue - upper border of range. - * @param precision - precision of generated number: - * precision equals 10 means that values will be accurate to one tenth (1.2, 34.6); - * precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67). - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * products: { - * columns: { - * unitPrice: funcs.number({ minValue: 10, maxValue: 120, precision: 100, isUnique: false }), - * }, - * }, - * })); - * - * ``` - */ - number: createGenerator(GenerateNumber), - // uniqueNumber: createGenerator(GenerateUniqueNumber), - - /** - * generates integers within given range. - * @param minValue - lower border of range. - * @param maxValue - upper border of range. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * products: { - * columns: { - * unitsInStock: funcs.number({ minValue: 0, maxValue: 100, isUnique: false }), - * }, - * }, - * })); - * - * ``` - */ - int: createGenerator(GenerateInt), - // uniqueInt: createGenerator(GenerateUniqueInt), - - /** - * generates boolean values(true or false) - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * isAvailable: funcs.boolean() - * }, - * }, - * })); - * - * ``` - */ - boolean: createGenerator(GenerateBoolean), - - /** - * generates date within given range. - * @param minDate - lower border of range. - * @param maxDate - upper border of range. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * birthDate: funcs.date({ minDate: "1990-01-01", maxDate: "2010-12-31" }) - * }, - * }, - * })); - * - * ``` - */ - date: createGenerator(GenerateDate), - - /** - * generates time in 24 hours style. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * birthTime: funcs.time() - * }, - * }, - * })); - * - * ``` - */ - time: createGenerator(GenerateTime), - - /** - * generates timestamps. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * orders: { - * columns: { - * shippedDate: funcs.timestamp() - * }, - * }, - * })); - * - * ``` - */ - timestamp: createGenerator(GenerateTimestamp), - - /** - * generates datetime objects. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * orders: { - * columns: { - * shippedDate: funcs.datetime() - * }, - * }, - * })); - * - * ``` - */ - datetime: createGenerator(GenerateDatetime), - - /** - * generates years. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * birthYear: funcs.year() - * }, - * }, - * })); - * - * ``` - */ - year: createGenerator(GenerateYear), - - /** - * generates json objects with fixed structure. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * json structure can equal this: - * ``` - * { - * email, - * name, - * isGraduated, - * hasJob, - * salary, - * startedWorking, - * visitedCountries, - * } - * ``` - * or this - * ``` - * { - * email, - * name, - * isGraduated, - * hasJob, - * visitedCountries, - * } - * ``` - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * metadata: funcs.json() - * }, - * }, - * })); - * ``` - */ - json: createGenerator(GenerateJson), - // jsonb: createGenerator(GenerateJsonb), - - /** - * generates time intervals. - * - * interval example: "1 years 12 days 5 minutes" - * - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * @param fields - range of values you want to see in your intervals. - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * timeSpentOnWebsite: funcs.interval() - * }, - * }, - * })); - * ``` - */ - interval: createGenerator(GenerateInterval), - // uniqueInterval: createGenerator(GenerateUniqueInterval), - - /** - * generates random strings. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * hashedPassword: funcs.string({isUnique: false}) - * }, - * }, - * })); - * ``` - */ - string: createGenerator(GenerateString), - // uniqueString: createGenerator(GenerateUniqueString), - - /** - * generates v4 UUID strings if arraySize is not specified, or v4 UUID 1D arrays if it is. - * - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * uuid: funcs.uuid({ - * arraySize: 4 - * }) - * }, - * }, - * })); - * ``` - */ - uuid: createGenerator(GenerateUUID), - - /** - * generates person's first names. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * firstName: funcs.firstName({isUnique: true}) - * }, - * }, - * })); - * ``` - */ - firstName: createGenerator(GenerateFirstName), - // uniqueFirstName: createGenerator(GenerateUniqueName), - - /** - * generates person's last names. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * lastName: funcs.lastName({isUnique: false}) - * }, - * }, - * })); - * ``` - */ - lastName: createGenerator(GenerateLastName), - // uniqueLastName: createGenerator(GenerateUniqueSurname), - - /** - * generates person's full names. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * fullName: funcs.fullName({isUnique: true}) - * }, - * }, - * })); - * ``` - */ - fullName: createGenerator(GenerateFullName), - // uniqueFullName: createGenerator(GenerateUniqueFullName), - - /** - * generates unique emails. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * email: funcs.email() - * }, - * }, - * })); - * ``` - */ - email: createGenerator(GenerateEmail), - - /** - * generates unique phone numbers. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @param template - phone number template, where all '#' symbols will be substituted with generated digits. - * @param prefixes - array of any string you want to be your phone number prefixes.(not compatible with template property) - * @param generatedDigitsNumbers - number of digits that will be added at the end of prefixes.(not compatible with template property) - * @example - * ```ts - * //generate phone number using template property - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * phoneNumber: funcs.phoneNumber({template: "+(380) ###-####"}) - * }, - * }, - * })); - * - * //generate phone number using prefixes and generatedDigitsNumbers properties - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67" ], generatedDigitsNumbers: 7}) - * }, - * }, - * })); - * - * //generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67", "+1" ], generatedDigitsNumbers: [7, 7, 10]}) - * }, - * }, - * })); - * - * ``` - */ - phoneNumber: createGenerator(GeneratePhoneNumber), - - /** - * generates country's names. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * country: funcs.country({isUnique: false}) - * }, - * }, - * })); - * ``` - */ - country: createGenerator(GenerateCountry), - // uniqueCountry: createGenerator(GenerateUniqueCountry), - - /** - * generates city's names. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * city: funcs.city({isUnique: false}) - * }, - * }, - * })); - * ``` - */ - city: createGenerator(GenerateCity), - // uniqueCity: createGenerator(GenerateUniqueCityName), - - /** - * generates street address. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * streetAddress: funcs.streetAddress({isUnique: true}) - * }, - * }, - * })); - * ``` - */ - streetAddress: createGenerator(GenerateStreetAdddress), - // uniqueStreetAddress: createGenerator(GenerateUniqueStreetAdddress), - - /** - * generates job titles. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * jobTitle: funcs.jobTitle() - * }, - * }, - * })); - * ``` - */ - jobTitle: createGenerator(GenerateJobTitle), - - /** - * generates postal codes. - * - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * postcode: funcs.postcode({isUnique: true}) - * }, - * }, - * })); - * ``` - */ - postcode: createGenerator(GeneratePostcode), - // uniquePostcoe: createGenerator(GenerateUniquePostcode), - - /** - * generates states of America. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * state: funcs.state() - * }, - * }, - * })); - * ``` - */ - state: createGenerator(GenerateState), - - /** - * generates company's names. - * - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * company: funcs.companyName({isUnique: true}) - * }, - * }, - * })); - * ``` - */ - companyName: createGenerator(GenerateCompanyName), - // uniqueCompanyName: createGenerator(GenerateUniqueCompanyName), - - /** - * generates 'lorem ipsum' text sentences. - * - * @param sentencesCount - number of sentences you want to generate as one generated value(string). - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * content: funcs.loremIpsum({sentencesCount: 2}) - * }, - * }, - * })); - * ``` - */ - loremIpsum: createGenerator(GenerateLoremIpsum), - - /** - * generates 2D points within specified ranges for x and y coordinates. - * - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param minXValue - lower bound of range for x coordinate. - * @param maxXValue - upper bound of range for x coordinate. - * @param minYValue - lower bound of range for y coordinate. - * @param maxYValue - upper bound of range for y coordinate. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * triangles: { - * columns: { - * pointCoords: funcs.point({ - * isUnique: true, - * minXValue: -5, maxXValue:20, - * minYValue: 0, maxYValue: 30 - * }) - * }, - * }, - * })); - * ``` - */ - point: createGenerator(GeneratePoint), - // uniquePoint: createGenerator(GenerateUniquePoint), - - /** - * generates 2D lines within specified ranges for a, b and c parameters of line. - * - * ``` - * line equation: a*x + b*y + c = 0 - * ``` - * - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param minAValue - lower bound of range for a parameter. - * @param maxAValue - upper bound of range for x parameter. - * @param minBValue - lower bound of range for y parameter. - * @param maxBValue - upper bound of range for y parameter. - * @param minCValue - lower bound of range for y parameter. - * @param maxCValue - upper bound of range for y parameter. - * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * lines: { - * columns: { - * lineParams: funcs.point({ - * isUnique: true, - * minAValue: -5, maxAValue:20, - * minBValue: 0, maxBValue: 30, - * minCValue: 0, maxCValue: 10 - * }) - * }, - * }, - * })); - * ``` - */ - line: createGenerator(GenerateLine), - // uniqueLine: createGenerator(GenerateUniqueLine), - - /** - * gives you the opportunity to call different generators with different probabilities to generate values for one column. - * @param params - array of generators with probabilities you would like to call them to generate values. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * content: funcs.weightedRandom([ - * { - * weight: 0.6, - * value: funcs.loremIpsum({ sentencesCount: 3 }), - * }, - * { - * weight: 0.4, - * value: funcs.default({ defaultValue: "TODO" }), - * }, - * ]), - * }, - * }, - * })); - * ``` - */ - weightedRandom: createGenerator(WeightedRandomGenerator), -}; diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 62283c817..6982ac980 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -11,35 +11,11 @@ import type { RefinementsType, TableGeneratorsType, } from '../types/seedService.ts'; -import type { Column, Prettify, Relation, RelationWithReferences, Table } from '../types/tables.ts'; -import type { AbstractGenerator } from './GeneratorsWrappers.ts'; -import { - GenerateArray, - GenerateBoolean, - GenerateDate, - GenerateDatetime, - GenerateDefault, - GenerateEmail, - GenerateEnum, - GenerateFirstName, - GenerateInt, - GenerateInterval, - GenerateIntPrimaryKey, - GenerateJson, - GenerateLine, - GenerateNumber, - GeneratePoint, - GenerateSelfRelationsValuesFromArray, - GenerateString, - GenerateTime, - GenerateTimestamp, - GenerateUniqueString, - GenerateUUID, - GenerateValuesFromArray, - GenerateWeightedCount, - GenerateYear, - HollowGenerator, -} from './GeneratorsWrappers.ts'; +import type { Column, Prettify, Relation, Table } from '../types/tables.ts'; +import type { AbstractGenerator } from './Generators.ts'; + +import * as Generators from './Generators.ts'; +import * as GeneratorsV1 from './GeneratorVersions/GeneratorsV1.ts'; import { equalSets, generateHashFromString } from './utils.ts'; export class SeedService { @@ -57,13 +33,13 @@ export class SeedService { connectionType: 'postgresql' | 'mysql' | 'sqlite', tables: Table[], relations: (Relation & { isCyclic: boolean })[], - tableRelations: { [tableName: string]: RelationWithReferences[] }, refinements?: RefinementsType, - options?: { count?: number; seed?: number }, + options?: { count?: number; seed?: number; version?: number }, ) => { let columnPossibleGenerator: Prettify; let tablePossibleGenerators: Prettify; const customSeed = options?.seed === undefined ? 0 : options.seed; + const version = options?.version === undefined ? Generators.version : options.version; // sorting table in order which they will be filled up (tables with foreign keys case) // relations = relations.filter(rel => rel.type === "one"); @@ -221,35 +197,42 @@ export class SeedService { columnPossibleGenerator.wasRefined = true; } else if (Object.hasOwn(foreignKeyColumns, col.name)) { // TODO: I might need to assign repeatedValuesCount to column there instead of doing so in generateTablesValues - const cyclicRelation = tableRelations[table.name]!.find((rel) => - rel.isCyclic === true + const cyclicRelation = relations.find((rel) => + rel.table === table.name + && rel.isCyclic === true && rel.columns.includes(col.name) ); + // const cyclicRelation = tableRelations[table.name]!.find((rel) => + // rel.isCyclic === true + // && rel.columns.includes(col.name) + // ); + if (cyclicRelation !== undefined) { columnPossibleGenerator.isCyclic = true; } const predicate = cyclicRelation !== undefined && col.notNull === false; if (predicate === true) { - columnPossibleGenerator.generator = new GenerateDefault({ defaultValue: null }); + columnPossibleGenerator.generator = new Generators.GenerateDefault({ defaultValue: null }); columnPossibleGenerator.wasDefinedBefore = true; } - columnPossibleGenerator.generator = new HollowGenerator({}); + columnPossibleGenerator.generator = new Generators.HollowGenerator({}); } // TODO: rewrite pickGeneratorFor... using new col properties: isUnique and notNull else if (connectionType === 'postgresql') { - columnPossibleGenerator.generator = this.pickGeneratorForPostgresColumn( + columnPossibleGenerator.generator = this.selectGeneratorForPostgresColumn( table, col, + version, ); } else if (connectionType === 'mysql') { - columnPossibleGenerator.generator = this.pickGeneratorForMysqlColumn( + columnPossibleGenerator.generator = this.selectGeneratorForMysqlColumn( table, col, ); } else if (connectionType === 'sqlite') { - columnPossibleGenerator.generator = this.pickGeneratorForSqlite( + columnPossibleGenerator.generator = this.selectGeneratorForSqlite( table, col, ); @@ -420,7 +403,7 @@ export class SeedService { count: number, seed: number, ) => { - const gen = new GenerateWeightedCount({}); + const gen = new Generators.GenerateWeightedCount({}); gen.init({ count: weightedCount, seed }); let weightedWithCount = 0; for (let i = 0; i < count; i++) { @@ -430,20 +413,59 @@ export class SeedService { return weightedWithCount; }; - // TODO: revise serial part generators + selectGeneratorOfVersion = (version: number, generatorEntityKind: string) => { + const GeneratorVersions = [Generators, GeneratorsV1]; + + type GeneratorConstructorT = new(params: any) => AbstractGenerator; + let generatorConstructor: GeneratorConstructorT | undefined; + for (const gens of GeneratorVersions) { + const { version: gensVersion, ...filteredGens } = gens; + if (version > gensVersion) break; + + for (const gen of Object.values(filteredGens)) { + const abstractGen = gen as typeof AbstractGenerator; + if (abstractGen[entityKind] === generatorEntityKind) { + generatorConstructor = abstractGen as unknown as GeneratorConstructorT; + + if (abstractGen.version === version) { + return { generatorConstructor }; + } + } + } + } + + if (generatorConstructor === undefined) { + throw new Error(`Can't select version for ${generatorEntityKind} generator`); + } + + return { generatorConstructor }; + }; - pickGeneratorForPostgresColumn = ( + // TODO: revise serial part generators + selectGeneratorForPostgresColumn = ( table: Table, col: Column, + version: number, ) => { const pickGenerator = (table: Table, col: Column) => { // ARRAY if (col.columnType.match(/\[\w*]/g) !== null && col.baseColumn !== undefined) { - const baseColumnGen = this.pickGeneratorForPostgresColumn(table, col.baseColumn!) as AbstractGenerator; + const baseColumnGen = this.selectGeneratorForPostgresColumn( + table, + col.baseColumn!, + version, + ) as AbstractGenerator; if (baseColumnGen === undefined) { throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); } - const generator = new GenerateArray({ baseColumnGen, size: col.size }); + + const { generatorConstructor } = this.selectGeneratorOfVersion( + version, + Generators.GenerateArray[entityKind], + ); + + const generator = new generatorConstructor!({ baseColumnGen, size: col.size }); + // const generator = new Generators.GenerateArray({ baseColumnGen, size: col.size }); return generator; } @@ -457,15 +479,15 @@ export class SeedService { }; baseColumn.columnType = baseColumnType; - const baseColumnGen = this.pickGeneratorForPostgresColumn(table, baseColumn) as AbstractGenerator; + const baseColumnGen = this.selectGeneratorForPostgresColumn(table, baseColumn, version) as AbstractGenerator; if (baseColumnGen === undefined) { throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); } - let generator = new GenerateArray({ baseColumnGen }); + let generator = new Generators.GenerateArray({ baseColumnGen }); for (let i = 0; i < col.typeParams.dimensions! - 1; i++) { - generator = new GenerateArray({ baseColumnGen: generator }); + generator = new Generators.GenerateArray({ baseColumnGen: generator }); } return generator; @@ -479,7 +501,7 @@ export class SeedService { || col.columnType.includes('bigint')) && table.primaryKeys.includes(col.name) ) { - const generator = new GenerateIntPrimaryKey({}); + const generator = new Generators.GenerateIntPrimaryKey({}); return generator; } @@ -527,7 +549,7 @@ export class SeedService { && !col.columnType.includes('interval') && !col.columnType.includes('point') ) { - const generator = new GenerateInt({ + const generator = new Generators.GenerateInt({ minValue, maxValue, }); @@ -536,9 +558,9 @@ export class SeedService { } if (col.columnType.includes('serial')) { - const generator = new GenerateIntPrimaryKey({}); + const generator = new Generators.GenerateIntPrimaryKey({}); - (generator as GenerateIntPrimaryKey).maxValue = maxValue; + (generator as Generators.GenerateIntPrimaryKey).maxValue = maxValue; return generator; } @@ -550,7 +572,7 @@ export class SeedService { || col.columnType === 'decimal' || col.columnType === 'numeric' ) { - const generator = new GenerateNumber({}); + const generator = new Generators.GenerateNumber({}); return generator; } @@ -562,7 +584,7 @@ export class SeedService { || col.columnType.startsWith('char')) && table.primaryKeys.includes(col.name) ) { - const generator = new GenerateUniqueString({}); + const generator = new Generators.GenerateUniqueString({}); return generator; } @@ -573,7 +595,7 @@ export class SeedService { || col.columnType.startsWith('char')) && col.name.toLowerCase().includes('name') ) { - const generator = new GenerateFirstName({}); + const generator = new Generators.GenerateFirstName({}); return generator; } @@ -584,7 +606,7 @@ export class SeedService { || col.columnType.startsWith('char')) && col.name.toLowerCase().includes('email') ) { - const generator = new GenerateEmail({}); + const generator = new Generators.GenerateEmail({}); return generator; } @@ -595,47 +617,47 @@ export class SeedService { || col.columnType.startsWith('char') ) { // console.log(col, table) - const generator = new GenerateString({}); + const generator = new Generators.GenerateString({}); return generator; } // UUID if (col.columnType === 'uuid') { - const generator = new GenerateUUID({}); + const generator = new Generators.GenerateUUID({}); return generator; } // BOOLEAN if (col.columnType === 'boolean') { - const generator = new GenerateBoolean({}); + const generator = new Generators.GenerateBoolean({}); return generator; } // DATE, TIME, TIMESTAMP if (col.columnType.includes('date')) { - const generator = new GenerateDate({}); + const generator = new Generators.GenerateDate({}); return generator; } if (col.columnType === 'time') { - const generator = new GenerateTime({}); + const generator = new Generators.GenerateTime({}); return generator; } if (col.columnType.includes('timestamp')) { - const generator = new GenerateTimestamp({}); + const generator = new Generators.GenerateTimestamp({}); return generator; } // JSON, JSONB if (col.columnType === 'json' || col.columnType === 'jsonb') { - const generator = new GenerateJson({}); + const generator = new Generators.GenerateJson({}); return generator; } @@ -647,7 +669,7 @@ export class SeedService { // ENUM if (col.enumValues !== undefined) { - const generator = new GenerateEnum({ + const generator = new Generators.GenerateEnum({ enumValues: col.enumValues, }); @@ -657,32 +679,32 @@ export class SeedService { // INTERVAL if (col.columnType.startsWith('interval')) { if (col.columnType === 'interval') { - const generator = new GenerateInterval({}); + const generator = new Generators.GenerateInterval({}); return generator; } - const fields = col.columnType.replace('interval ', '') as GenerateInterval['params']['fields']; - const generator = new GenerateInterval({ fields }); + const fields = col.columnType.replace('interval ', '') as Generators.GenerateInterval['params']['fields']; + const generator = new Generators.GenerateInterval({ fields }); return generator; } // POINT, LINE if (col.columnType.includes('point')) { - const generator = new GeneratePoint({}); + const generator = new Generators.GeneratePoint({}); return generator; } if (col.columnType.includes('line')) { - const generator = new GenerateLine({}); + const generator = new Generators.GenerateLine({}); return generator; } if (col.hasDefault && col.default !== undefined) { - const generator = new GenerateDefault({ + const generator = new Generators.GenerateDefault({ defaultValue: col.default, }); return generator; @@ -701,7 +723,7 @@ export class SeedService { return generator; }; - pickGeneratorForMysqlColumn = ( + selectGeneratorForMysqlColumn = ( table: Table, col: Column, ) => { @@ -711,7 +733,7 @@ export class SeedService { (col.columnType.includes('serial') || col.columnType.includes('int')) && table.primaryKeys.includes(col.name) ) { - const generator = new GenerateIntPrimaryKey({}); + const generator = new Generators.GenerateIntPrimaryKey({}); return generator; } @@ -746,7 +768,7 @@ export class SeedService { } if (col.columnType.includes('int')) { - const generator = new GenerateInt({ + const generator = new Generators.GenerateInt({ minValue, maxValue, }); @@ -754,7 +776,7 @@ export class SeedService { } if (col.columnType.includes('serial')) { - const generator = new GenerateIntPrimaryKey({}); + const generator = new Generators.GenerateIntPrimaryKey({}); generator.maxValue = maxValue; return generator; } @@ -766,7 +788,7 @@ export class SeedService { || col.columnType === 'decimal' || col.columnType === 'float' ) { - const generator = new GenerateNumber({}); + const generator = new Generators.GenerateNumber({}); return generator; } @@ -780,7 +802,7 @@ export class SeedService { || col.columnType.includes('varbinary')) && table.primaryKeys.includes(col.name) ) { - const generator = new GenerateUniqueString({}); + const generator = new Generators.GenerateUniqueString({}); return generator; } @@ -793,7 +815,7 @@ export class SeedService { || col.columnType.includes('varbinary')) && col.name.toLowerCase().includes('name') ) { - const generator = new GenerateFirstName({}); + const generator = new Generators.GenerateFirstName({}); return generator; } @@ -806,7 +828,7 @@ export class SeedService { || col.columnType.includes('varbinary')) && col.name.toLowerCase().includes('email') ) { - const generator = new GenerateEmail({}); + const generator = new Generators.GenerateEmail({}); return generator; } @@ -819,58 +841,58 @@ export class SeedService { || col.columnType.includes('varbinary') ) { // console.log(col, table); - const generator = new GenerateString({}); + const generator = new Generators.GenerateString({}); return generator; } // BOOLEAN if (col.columnType === 'boolean') { - const generator = new GenerateBoolean({}); + const generator = new Generators.GenerateBoolean({}); return generator; } // DATE, TIME, TIMESTAMP, DATETIME, YEAR if (col.columnType.includes('datetime')) { - const generator = new GenerateDatetime({}); + const generator = new Generators.GenerateDatetime({}); return generator; } if (col.columnType.includes('date')) { - const generator = new GenerateDate({}); + const generator = new Generators.GenerateDate({}); return generator; } if (col.columnType === 'time') { - const generator = new GenerateTime({}); + const generator = new Generators.GenerateTime({}); return generator; } if (col.columnType.includes('timestamp')) { - const generator = new GenerateTimestamp({}); + const generator = new Generators.GenerateTimestamp({}); return generator; } if (col.columnType === 'year') { - const generator = new GenerateYear({}); + const generator = new Generators.GenerateYear({}); return generator; } // JSON if (col.columnType === 'json') { - const generator = new GenerateJson({}); + const generator = new Generators.GenerateJson({}); return generator; } // ENUM if (col.enumValues !== undefined) { - const generator = new GenerateEnum({ + const generator = new Generators.GenerateEnum({ enumValues: col.enumValues, }); return generator; } if (col.hasDefault && col.default !== undefined) { - const generator = new GenerateDefault({ + const generator = new Generators.GenerateDefault({ defaultValue: col.default, }); return generator; @@ -879,7 +901,7 @@ export class SeedService { return; }; - pickGeneratorForSqlite = ( + selectGeneratorForSqlite = ( table: Table, col: Column, ) => { @@ -888,17 +910,17 @@ export class SeedService { (col.columnType === 'integer' || col.columnType === 'numeric') && table.primaryKeys.includes(col.name) ) { - const generator = new GenerateIntPrimaryKey({}); + const generator = new Generators.GenerateIntPrimaryKey({}); return generator; } if (col.columnType === 'integer' && col.dataType === 'boolean') { - const generator = new GenerateBoolean({}); + const generator = new Generators.GenerateBoolean({}); return generator; } if ((col.columnType === 'integer' && col.dataType === 'date')) { - const generator = new GenerateTimestamp({}); + const generator = new Generators.GenerateTimestamp({}); return generator; } @@ -907,13 +929,13 @@ export class SeedService { || col.columnType === 'numeric' || (col.dataType === 'bigint' && col.columnType === 'blob') ) { - const generator = new GenerateInt({}); + const generator = new Generators.GenerateInt({}); return generator; } // number section ------------------------------------------------------------------------------------ if (col.columnType === 'real' || col.columnType === 'numeric') { - const generator = new GenerateNumber({}); + const generator = new Generators.GenerateNumber({}); return generator; } @@ -924,7 +946,7 @@ export class SeedService { || col.columnType === 'blob') && table.primaryKeys.includes(col.name) ) { - const generator = new GenerateUniqueString({}); + const generator = new Generators.GenerateUniqueString({}); return generator; } @@ -934,7 +956,7 @@ export class SeedService { || col.columnType === 'blob') && col.name.toLowerCase().includes('name') ) { - const generator = new GenerateFirstName({}); + const generator = new Generators.GenerateFirstName({}); return generator; } @@ -944,7 +966,7 @@ export class SeedService { || col.columnType === 'blob') && col.name.toLowerCase().includes('email') ) { - const generator = new GenerateEmail({}); + const generator = new Generators.GenerateEmail({}); return generator; } @@ -954,7 +976,7 @@ export class SeedService { || col.columnType === 'blob' || col.columnType === 'blobbuffer' ) { - const generator = new GenerateString({}); + const generator = new Generators.GenerateString({}); return generator; } @@ -962,12 +984,12 @@ export class SeedService { (col.columnType === 'text' && col.dataType === 'json') || (col.columnType === 'blob' && col.dataType === 'json') ) { - const generator = new GenerateJson({}); + const generator = new Generators.GenerateJson({}); return generator; } if (col.hasDefault && col.default !== undefined) { - const generator = new GenerateDefault({ + const generator = new Generators.GenerateDefault({ defaultValue: col.default, }); return generator; @@ -1134,7 +1156,7 @@ export class SeedService { }))!.map((rows) => rows[refColName]) as (string | number | boolean)[]; hasSelfRelation = true; - genObj = new GenerateSelfRelationsValuesFromArray({ + genObj = new Generators.GenerateSelfRelationsValuesFromArray({ values: refColumnValues, }); } else if ( @@ -1154,10 +1176,10 @@ export class SeedService { weightedCountSeed = table.withFromTable[rel.refTable]!.weightedCountSeed; } - genObj = new GenerateValuesFromArray({ values: refColumnValues }); - (genObj as GenerateValuesFromArray).notNull = tableGenerators[rel.columns[colIdx]!]!.notNull; - (genObj as GenerateValuesFromArray).weightedCountSeed = weightedCountSeed; - (genObj as GenerateValuesFromArray).maxRepeatedValuesCount = repeatedValuesCount; + genObj = new Generators.GenerateValuesFromArray({ values: refColumnValues }); + (genObj as Generators.GenerateValuesFromArray).notNull = tableGenerators[rel.columns[colIdx]!]!.notNull; + (genObj as Generators.GenerateValuesFromArray).weightedCountSeed = weightedCountSeed; + (genObj as Generators.GenerateValuesFromArray).maxRepeatedValuesCount = repeatedValuesCount; } // console.log(rel.columns[colIdx], tableGenerators) diff --git a/drizzle-seed/src/types/seedService.ts b/drizzle-seed/src/types/seedService.ts index 0b5237468..1ae06f44c 100644 --- a/drizzle-seed/src/types/seedService.ts +++ b/drizzle-seed/src/types/seedService.ts @@ -1,4 +1,4 @@ -import type { AbstractGenerator } from '../services/GeneratorsWrappers.ts'; +import type { AbstractGenerator } from '../services/Generators.ts'; import type { Prettify } from './tables.ts'; export type TableGeneratorsType = { diff --git a/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts b/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts index 9d79ebaa8..3473e555a 100644 --- a/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts +++ b/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts @@ -40,7 +40,7 @@ import { GenerateValuesFromArray, GenerateYear, WeightedRandomGenerator, -} from '../../src/services/GeneratorsWrappers.ts'; +} from '../../src/services/Generators.ts'; const benchmark = ({ generatorName, generator, count = 100000, seed = 1 }: { generatorName: string; From 06a936837e1f3d61cf0f89002579209faf5570e0 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Wed, 18 Dec 2024 16:20:32 +0200 Subject: [PATCH 452/492] added generator versioning with version v1 for string and interval generators --- .../GeneratorVersions/GeneratorsV1.ts | 152 ++++- drizzle-seed/src/services/Generators.ts | 2 +- drizzle-seed/src/services/SeedService.ts | 525 ++++++++++-------- 3 files changed, 428 insertions(+), 251 deletions(-) diff --git a/drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts b/drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts index e4fed2926..81655a941 100644 --- a/drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts +++ b/drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts @@ -1,5 +1,6 @@ import { entityKind } from 'drizzle-orm'; -import { GenerateInterval, GenerateUniqueInterval } from '../Generators.ts'; +import prand from 'pure-rand'; +import { AbstractGenerator, GenerateInterval } from '../Generators.ts'; export const version = 1; @@ -9,7 +10,152 @@ export class GenerateIntervalV1 extends GenerateInterval { override uniqueVersionOfGen = GenerateUniqueIntervalV1; } -export class GenerateUniqueIntervalV1 extends GenerateUniqueInterval { +export class GenerateUniqueIntervalV1 extends AbstractGenerator<{ + isUnique?: boolean; +}> { static override readonly [entityKind]: string = 'GenerateUniqueInterval'; - static override readonly ['version']: number = 1; + + private state: { + rng: prand.RandomGenerator; + intervalSet: Set; + } | undefined; + public override isUnique = true; + + override init({ count, seed }: { count: number; seed: number }) { + const maxUniqueIntervalsNumber = 6 * 13 * 29 * 25 * 61 * 61; + if (count > maxUniqueIntervalsNumber) { + throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`); + } + + const rng = prand.xoroshiro128plus(seed); + const intervalSet = new Set(); + this.state = { rng, intervalSet }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let yearsNumb: number, + monthsNumb: number, + daysNumb: number, + hoursNumb: number, + minutesNumb: number, + secondsNumb: number; + + let interval = ''; + + for (;;) { + [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); + [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); + [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); + [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); + [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + + interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` + + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` + + `${daysNumb === 0 ? '' : `${daysNumb} days `}` + + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` + + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` + + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; + + if (!this.state.intervalSet.has(interval)) { + this.state.intervalSet.add(interval); + break; + } + } + + return interval; + } +} + +export class GenerateStringV1 extends AbstractGenerator<{ + isUnique?: boolean; + arraySize?: number; +}> { + static override readonly [entityKind]: string = 'GenerateString'; + + private state: { rng: prand.RandomGenerator } | undefined; + override uniqueVersionOfGen = GenerateUniqueStringV1; + + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); + + const rng = prand.xoroshiro128plus(seed); + this.state = { rng }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const minStringLength = 7; + const maxStringLength = 20; + const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let idx: number, + strLength: number, + currStr: string; + + currStr = ''; + [strLength, this.state.rng] = prand.uniformIntDistribution( + minStringLength, + maxStringLength, + this.state.rng, + ); + for (let j = 0; j < strLength; j++) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + stringChars.length - 1, + this.state.rng, + ); + currStr += stringChars[idx]; + } + return currStr; + } +} + +export class GenerateUniqueStringV1 extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateUniqueString'; + + private state: { rng: prand.RandomGenerator } | undefined; + public override isUnique = true; + + override init({ seed }: { seed: number }) { + const rng = prand.xoroshiro128plus(seed); + this.state = { rng }; + } + + generate({ i }: { i: number }) { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const minStringLength = 7; + const maxStringLength = 20; + const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let idx: number, + strLength: number; + let currStr: string; + + currStr = ''; + const uniqueStr = i.toString(16); + [strLength, this.state.rng] = prand.uniformIntDistribution( + minStringLength, + maxStringLength - uniqueStr.length, + this.state.rng, + ); + for (let j = 0; j < strLength - uniqueStr.length; j++) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + stringChars.length - 1, + this.state.rng, + ); + currStr += stringChars[idx]; + } + + return currStr.slice(0, 4) + uniqueStr + currStr.slice(4); + } } diff --git a/drizzle-seed/src/services/Generators.ts b/drizzle-seed/src/services/Generators.ts index f5fc44aab..fa01a1e4f 100644 --- a/drizzle-seed/src/services/Generators.ts +++ b/drizzle-seed/src/services/Generators.ts @@ -1235,7 +1235,7 @@ export class GenerateInterval extends AbstractGenerator<{ rng: prand.RandomGenerator; fieldsToGenerate: string[]; } | undefined; - override uniqueVersionOfGen = GenerateUniqueInterval; + override uniqueVersionOfGen: new(params: any) => AbstractGenerator = GenerateUniqueInterval; private config: { [key: string]: { from: number; to: number } } = { year: { from: 0, diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 6982ac980..6ceae5167 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -178,7 +178,12 @@ export class SeedService { && refinements[table.name]!.columns !== undefined && refinements[table.name]!.columns[col.name] !== undefined ) { - const genObj = refinements[table.name]!.columns[col.name]!; + let genObj = refinements[table.name]!.columns[col.name]!; + + const genObjEntityKind = genObj.getEntityKind(); + const generatorConstructor = this.selectGeneratorOfVersion(version, genObjEntityKind); + genObj = new generatorConstructor(genObj.params); + // TODO: for now only GenerateValuesFromArray support notNull property genObj.notNull = col.notNull; if (col.columnType.match(/\[\w*]/g) !== null) { @@ -203,11 +208,6 @@ export class SeedService { && rel.columns.includes(col.name) ); - // const cyclicRelation = tableRelations[table.name]!.find((rel) => - // rel.isCyclic === true - // && rel.columns.includes(col.name) - // ); - if (cyclicRelation !== undefined) { columnPossibleGenerator.isCyclic = true; } @@ -230,11 +230,13 @@ export class SeedService { columnPossibleGenerator.generator = this.selectGeneratorForMysqlColumn( table, col, + version, ); } else if (connectionType === 'sqlite') { columnPossibleGenerator.generator = this.selectGeneratorForSqlite( table, col, + version, ); } @@ -428,17 +430,17 @@ export class SeedService { generatorConstructor = abstractGen as unknown as GeneratorConstructorT; if (abstractGen.version === version) { - return { generatorConstructor }; + return generatorConstructor; } } } } if (generatorConstructor === undefined) { - throw new Error(`Can't select version for ${generatorEntityKind} generator`); + throw new Error(`Can't select ${generatorEntityKind} generator for ${version} version.`); } - return { generatorConstructor }; + return generatorConstructor; }; // TODO: revise serial part generators @@ -459,13 +461,13 @@ export class SeedService { throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); } - const { generatorConstructor } = this.selectGeneratorOfVersion( - version, - Generators.GenerateArray[entityKind], - ); + // const { generatorConstructor } = this.selectGeneratorOfVersion( + // version, + // Generators.GenerateArray[entityKind], + // ); - const generator = new generatorConstructor!({ baseColumnGen, size: col.size }); - // const generator = new Generators.GenerateArray({ baseColumnGen, size: col.size }); + // const generator = new generatorConstructor!({ baseColumnGen, size: col.size }); + const generator = new Generators.GenerateArray({ baseColumnGen, size: col.size }); return generator; } @@ -616,7 +618,6 @@ export class SeedService { || col.columnType.startsWith('varchar') || col.columnType.startsWith('char') ) { - // console.log(col, table) const generator = new Generators.GenerateString({}); return generator; @@ -713,8 +714,15 @@ export class SeedService { return; }; - const generator = pickGenerator(table, col); + let generator = pickGenerator(table, col) as AbstractGenerator || undefined; if (generator !== undefined) { + const generatorConstructor = this.selectGeneratorOfVersion( + version, + generator.getEntityKind(), + ); + + generator = new generatorConstructor(generator.params); + generator.isUnique = col.isUnique; generator.dataType = col.dataType; generator.stringLength = col.typeParams.length; @@ -726,276 +734,304 @@ export class SeedService { selectGeneratorForMysqlColumn = ( table: Table, col: Column, + version: number, ) => { - // console.log(col); - // INT ------------------------------------------------------------------------------------------------------------ - if ( - (col.columnType.includes('serial') || col.columnType.includes('int')) - && table.primaryKeys.includes(col.name) - ) { - const generator = new Generators.GenerateIntPrimaryKey({}); - return generator; - } + const pickGenerator = (table: Table, col: Column) => { + // INT ------------------------------------------------------------------------------------------------------------ + if ( + (col.columnType.includes('serial') || col.columnType.includes('int')) + && table.primaryKeys.includes(col.name) + ) { + const generator = new Generators.GenerateIntPrimaryKey({}); + return generator; + } - let minValue: number | bigint | undefined; - let maxValue: number | bigint | undefined; - if (col.columnType === 'serial') { - // 2^64 % 2 - 1, 8 bytes - minValue = BigInt(0); - maxValue = BigInt('9223372036854775807'); - } else if (col.columnType.includes('int')) { - if (col.columnType === 'tinyint') { - // 2^8 / 2 - 1, 1 bytes - minValue = -128; - maxValue = 127; - } else if (col.columnType === 'smallint') { - // 2^16 / 2 - 1, 2 bytes - minValue = -32768; - maxValue = 32767; - } else if (col.columnType === 'mediumint') { - // 2^16 / 2 - 1, 2 bytes - minValue = -8388608; - maxValue = 8388607; - } else if (col.columnType === 'int') { - // 2^32 / 2 - 1, 4 bytes - minValue = -2147483648; - maxValue = 2147483647; - } else if (col.columnType === 'bigint') { - // 2^64 / 2 - 1, 8 bytes - minValue = BigInt('-9223372036854775808'); + let minValue: number | bigint | undefined; + let maxValue: number | bigint | undefined; + if (col.columnType === 'serial') { + // 2^64 % 2 - 1, 8 bytes + minValue = BigInt(0); maxValue = BigInt('9223372036854775807'); + } else if (col.columnType.includes('int')) { + if (col.columnType === 'tinyint') { + // 2^8 / 2 - 1, 1 bytes + minValue = -128; + maxValue = 127; + } else if (col.columnType === 'smallint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -32768; + maxValue = 32767; + } else if (col.columnType === 'mediumint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -8388608; + maxValue = 8388607; + } else if (col.columnType === 'int') { + // 2^32 / 2 - 1, 4 bytes + minValue = -2147483648; + maxValue = 2147483647; + } else if (col.columnType === 'bigint') { + // 2^64 / 2 - 1, 8 bytes + minValue = BigInt('-9223372036854775808'); + maxValue = BigInt('9223372036854775807'); + } } - } - if (col.columnType.includes('int')) { - const generator = new Generators.GenerateInt({ - minValue, - maxValue, - }); - return generator; - } + if (col.columnType.includes('int')) { + const generator = new Generators.GenerateInt({ + minValue, + maxValue, + }); + return generator; + } - if (col.columnType.includes('serial')) { - const generator = new Generators.GenerateIntPrimaryKey({}); - generator.maxValue = maxValue; - return generator; - } + if (col.columnType.includes('serial')) { + const generator = new Generators.GenerateIntPrimaryKey({}); + generator.maxValue = maxValue; + return generator; + } - // NUMBER(real, double, decimal, float) - if ( - col.columnType === 'real' - || col.columnType === 'double' - || col.columnType === 'decimal' - || col.columnType === 'float' - ) { - const generator = new Generators.GenerateNumber({}); - return generator; - } + // NUMBER(real, double, decimal, float) + if ( + col.columnType === 'real' + || col.columnType === 'double' + || col.columnType === 'decimal' + || col.columnType === 'float' + ) { + const generator = new Generators.GenerateNumber({}); + return generator; + } - // STRING - if ( - (col.columnType === 'text' - || col.columnType === 'blob' - || col.columnType.includes('char') - || col.columnType.includes('varchar') - || col.columnType.includes('binary') - || col.columnType.includes('varbinary')) - && table.primaryKeys.includes(col.name) - ) { - const generator = new Generators.GenerateUniqueString({}); - return generator; - } + // STRING + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.includes('char') + || col.columnType.includes('varchar') + || col.columnType.includes('binary') + || col.columnType.includes('varbinary')) + && table.primaryKeys.includes(col.name) + ) { + const generator = new Generators.GenerateUniqueString({}); + return generator; + } - if ( - (col.columnType === 'text' - || col.columnType === 'blob' - || col.columnType.includes('char') - || col.columnType.includes('varchar') - || col.columnType.includes('binary') - || col.columnType.includes('varbinary')) - && col.name.toLowerCase().includes('name') - ) { - const generator = new Generators.GenerateFirstName({}); - return generator; - } + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.includes('char') + || col.columnType.includes('varchar') + || col.columnType.includes('binary') + || col.columnType.includes('varbinary')) + && col.name.toLowerCase().includes('name') + ) { + const generator = new Generators.GenerateFirstName({}); + return generator; + } - if ( - (col.columnType === 'text' + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.includes('char') + || col.columnType.includes('varchar') + || col.columnType.includes('binary') + || col.columnType.includes('varbinary')) + && col.name.toLowerCase().includes('email') + ) { + const generator = new Generators.GenerateEmail({}); + return generator; + } + + if ( + col.columnType === 'text' || col.columnType === 'blob' || col.columnType.includes('char') || col.columnType.includes('varchar') || col.columnType.includes('binary') - || col.columnType.includes('varbinary')) - && col.name.toLowerCase().includes('email') - ) { - const generator = new Generators.GenerateEmail({}); - return generator; - } + || col.columnType.includes('varbinary') + ) { + const generator = new Generators.GenerateString({}); + return generator; + } - if ( - col.columnType === 'text' - || col.columnType === 'blob' - || col.columnType.includes('char') - || col.columnType.includes('varchar') - || col.columnType.includes('binary') - || col.columnType.includes('varbinary') - ) { - // console.log(col, table); - const generator = new Generators.GenerateString({}); - return generator; - } + // BOOLEAN + if (col.columnType === 'boolean') { + const generator = new Generators.GenerateBoolean({}); + return generator; + } - // BOOLEAN - if (col.columnType === 'boolean') { - const generator = new Generators.GenerateBoolean({}); - return generator; - } + // DATE, TIME, TIMESTAMP, DATETIME, YEAR + if (col.columnType.includes('datetime')) { + const generator = new Generators.GenerateDatetime({}); + return generator; + } - // DATE, TIME, TIMESTAMP, DATETIME, YEAR - if (col.columnType.includes('datetime')) { - const generator = new Generators.GenerateDatetime({}); - return generator; - } + if (col.columnType.includes('date')) { + const generator = new Generators.GenerateDate({}); + return generator; + } - if (col.columnType.includes('date')) { - const generator = new Generators.GenerateDate({}); - return generator; - } + if (col.columnType === 'time') { + const generator = new Generators.GenerateTime({}); + return generator; + } - if (col.columnType === 'time') { - const generator = new Generators.GenerateTime({}); - return generator; - } + if (col.columnType.includes('timestamp')) { + const generator = new Generators.GenerateTimestamp({}); + return generator; + } - if (col.columnType.includes('timestamp')) { - const generator = new Generators.GenerateTimestamp({}); - return generator; - } + if (col.columnType === 'year') { + const generator = new Generators.GenerateYear({}); + return generator; + } - if (col.columnType === 'year') { - const generator = new Generators.GenerateYear({}); - return generator; - } + // JSON + if (col.columnType === 'json') { + const generator = new Generators.GenerateJson({}); + return generator; + } - // JSON - if (col.columnType === 'json') { - const generator = new Generators.GenerateJson({}); - return generator; - } + // ENUM + if (col.enumValues !== undefined) { + const generator = new Generators.GenerateEnum({ + enumValues: col.enumValues, + }); + return generator; + } - // ENUM - if (col.enumValues !== undefined) { - const generator = new Generators.GenerateEnum({ - enumValues: col.enumValues, - }); - return generator; - } + if (col.hasDefault && col.default !== undefined) { + const generator = new Generators.GenerateDefault({ + defaultValue: col.default, + }); + return generator; + } - if (col.hasDefault && col.default !== undefined) { - const generator = new Generators.GenerateDefault({ - defaultValue: col.default, - }); - return generator; + return; + }; + + let generator = pickGenerator(table, col) as AbstractGenerator || undefined; + if (generator !== undefined) { + const generatorConstructor = this.selectGeneratorOfVersion( + version, + generator.getEntityKind(), + ); + + generator = new generatorConstructor(generator.params); } - return; + return generator; }; selectGeneratorForSqlite = ( table: Table, col: Column, + version: number, ) => { - // int section --------------------------------------------------------------------------------------- - if ( - (col.columnType === 'integer' || col.columnType === 'numeric') - && table.primaryKeys.includes(col.name) - ) { - const generator = new Generators.GenerateIntPrimaryKey({}); - return generator; - } + const pickGenerator = (table: Table, col: Column) => { + // int section --------------------------------------------------------------------------------------- + if ( + (col.columnType === 'integer' || col.columnType === 'numeric') + && table.primaryKeys.includes(col.name) + ) { + const generator = new Generators.GenerateIntPrimaryKey({}); + return generator; + } - if (col.columnType === 'integer' && col.dataType === 'boolean') { - const generator = new Generators.GenerateBoolean({}); - return generator; - } + if (col.columnType === 'integer' && col.dataType === 'boolean') { + const generator = new Generators.GenerateBoolean({}); + return generator; + } - if ((col.columnType === 'integer' && col.dataType === 'date')) { - const generator = new Generators.GenerateTimestamp({}); - return generator; - } + if ((col.columnType === 'integer' && col.dataType === 'date')) { + const generator = new Generators.GenerateTimestamp({}); + return generator; + } - if ( - col.columnType === 'integer' - || col.columnType === 'numeric' - || (col.dataType === 'bigint' && col.columnType === 'blob') - ) { - const generator = new Generators.GenerateInt({}); - return generator; - } + if ( + col.columnType === 'integer' + || col.columnType === 'numeric' + || (col.dataType === 'bigint' && col.columnType === 'blob') + ) { + const generator = new Generators.GenerateInt({}); + return generator; + } - // number section ------------------------------------------------------------------------------------ - if (col.columnType === 'real' || col.columnType === 'numeric') { - const generator = new Generators.GenerateNumber({}); - return generator; - } + // number section ------------------------------------------------------------------------------------ + if (col.columnType === 'real' || col.columnType === 'numeric') { + const generator = new Generators.GenerateNumber({}); + return generator; + } - // string section ------------------------------------------------------------------------------------ - if ( - (col.columnType === 'text' - || col.columnType === 'numeric' - || col.columnType === 'blob') - && table.primaryKeys.includes(col.name) - ) { - const generator = new Generators.GenerateUniqueString({}); - return generator; - } + // string section ------------------------------------------------------------------------------------ + if ( + (col.columnType === 'text' + || col.columnType === 'numeric' + || col.columnType === 'blob') + && table.primaryKeys.includes(col.name) + ) { + const generator = new Generators.GenerateUniqueString({}); + return generator; + } - if ( - (col.columnType === 'text' - || col.columnType === 'numeric' - || col.columnType === 'blob') - && col.name.toLowerCase().includes('name') - ) { - const generator = new Generators.GenerateFirstName({}); - return generator; - } + if ( + (col.columnType === 'text' + || col.columnType === 'numeric' + || col.columnType === 'blob') + && col.name.toLowerCase().includes('name') + ) { + const generator = new Generators.GenerateFirstName({}); + return generator; + } - if ( - (col.columnType === 'text' + if ( + (col.columnType === 'text' + || col.columnType === 'numeric' + || col.columnType === 'blob') + && col.name.toLowerCase().includes('email') + ) { + const generator = new Generators.GenerateEmail({}); + return generator; + } + + if ( + col.columnType === 'text' || col.columnType === 'numeric' - || col.columnType === 'blob') - && col.name.toLowerCase().includes('email') - ) { - const generator = new Generators.GenerateEmail({}); - return generator; - } + || col.columnType === 'blob' + || col.columnType === 'blobbuffer' + ) { + const generator = new Generators.GenerateString({}); + return generator; + } - if ( - col.columnType === 'text' - || col.columnType === 'numeric' - || col.columnType === 'blob' - || col.columnType === 'blobbuffer' - ) { - const generator = new Generators.GenerateString({}); - return generator; - } + if ( + (col.columnType === 'text' && col.dataType === 'json') + || (col.columnType === 'blob' && col.dataType === 'json') + ) { + const generator = new Generators.GenerateJson({}); + return generator; + } - if ( - (col.columnType === 'text' && col.dataType === 'json') - || (col.columnType === 'blob' && col.dataType === 'json') - ) { - const generator = new Generators.GenerateJson({}); - return generator; - } + if (col.hasDefault && col.default !== undefined) { + const generator = new Generators.GenerateDefault({ + defaultValue: col.default, + }); + return generator; + } - if (col.hasDefault && col.default !== undefined) { - const generator = new Generators.GenerateDefault({ - defaultValue: col.default, - }); - return generator; + return; + }; + + let generator = pickGenerator(table, col) as AbstractGenerator || undefined; + if (generator !== undefined) { + const generatorConstructor = this.selectGeneratorOfVersion( + version, + generator.getEntityKind(), + ); + + generator = new generatorConstructor(generator.params); } - return; + return generator; }; filterCyclicTables = (tablesGenerators: ReturnType) => { @@ -1056,9 +1092,6 @@ export class SeedService { tablesUniqueNotNullColumn?: { [tableName: string]: { uniqueNotNullColName: string } }; }, ) => { - // console.time( - // "generateTablesValues-----------------------------------------------------" - // ); const customSeed = options?.seed === undefined ? 0 : options.seed; let tableCount: number | undefined; let columnsGenerators: Prettify[]; @@ -1074,7 +1107,6 @@ export class SeedService { }[] = options?.tablesValues === undefined ? [] : options.tablesValues; let pRNGSeed: number; - // relations = relations.filter(rel => rel.type === "one"); let filteredRelations: typeof relations; let preserveData: boolean, insertDataInDb: boolean = true, updateDataInDb: boolean = false; @@ -1182,7 +1214,6 @@ export class SeedService { (genObj as Generators.GenerateValuesFromArray).maxRepeatedValuesCount = repeatedValuesCount; } - // console.log(rel.columns[colIdx], tableGenerators) if (genObj !== undefined) { tableGenerators[rel.columns[colIdx]!]!.generator = genObj; } From 78f9c1c7ef3d55825c9fe1b32e51d490207ce596 Mon Sep 17 00:00:00 2001 From: Mario564 Date: Wed, 18 Dec 2024 09:43:51 -0800 Subject: [PATCH 453/492] Add SS support to drizzle-valibot --- drizzle-valibot/src/column.ts | 84 +++- drizzle-valibot/src/column.types.ts | 18 +- drizzle-valibot/tests/singlestore.test.ts | 500 ++++++++++++++++++++++ 3 files changed, 584 insertions(+), 18 deletions(-) create mode 100644 drizzle-valibot/tests/singlestore.test.ts diff --git a/drizzle-valibot/src/column.ts b/drizzle-valibot/src/column.ts index 5d7a1784e..cf90751ef 100644 --- a/drizzle-valibot/src/column.ts +++ b/drizzle-valibot/src/column.ts @@ -37,6 +37,21 @@ import type { PgVarchar, PgVector, } from 'drizzle-orm/pg-core'; +import { + SingleStoreBigInt53, + SingleStoreChar, + SingleStoreDouble, + SingleStoreFloat, + SingleStoreInt, + SingleStoreMediumInt, + SingleStoreReal, + SingleStoreSerial, + SingleStoreSmallInt, + SingleStoreText, + SingleStoreTinyInt, + SingleStoreVarChar, + SingleStoreYear, +} from 'drizzle-orm/singlestore-core'; import type { SQLiteInteger, SQLiteReal, SQLiteText } from 'drizzle-orm/sqlite-core'; import * as v from 'valibot'; import { CONSTANTS } from './constants.ts'; @@ -116,57 +131,92 @@ function numberColumnToSchema(column: Column): v.GenericSchema { let max!: number; let integer = false; - if (isColumnType>(column, ['MySqlTinyInt'])) { + if (isColumnType | SingleStoreTinyInt>(column, ['MySqlTinyInt', 'SingleStoreTinyInt'])) { min = unsigned ? 0 : CONSTANTS.INT8_MIN; max = unsigned ? CONSTANTS.INT8_UNSIGNED_MAX : CONSTANTS.INT8_MAX; integer = true; } else if ( - isColumnType | PgSmallSerial | MySqlSmallInt>(column, [ + isColumnType | PgSmallSerial | MySqlSmallInt | SingleStoreSmallInt>(column, [ 'PgSmallInt', 'PgSmallSerial', 'MySqlSmallInt', + 'SingleStoreSmallInt', ]) ) { min = unsigned ? 0 : CONSTANTS.INT16_MIN; max = unsigned ? CONSTANTS.INT16_UNSIGNED_MAX : CONSTANTS.INT16_MAX; integer = true; } else if ( - isColumnType | MySqlFloat | MySqlMediumInt>(column, [ + isColumnType< + PgReal | MySqlFloat | MySqlMediumInt | SingleStoreFloat | SingleStoreMediumInt + >(column, [ 'PgReal', 'MySqlFloat', 'MySqlMediumInt', + 'SingleStoreFloat', + 'SingleStoreMediumInt', ]) ) { min = unsigned ? 0 : CONSTANTS.INT24_MIN; max = unsigned ? CONSTANTS.INT24_UNSIGNED_MAX : CONSTANTS.INT24_MAX; - integer = isColumnType(column, ['MySqlMediumInt']); + integer = isColumnType(column, ['MySqlMediumInt', 'SingleStoreMediumInt']); } else if ( - isColumnType | PgSerial | MySqlInt>(column, ['PgInteger', 'PgSerial', 'MySqlInt']) + isColumnType | PgSerial | MySqlInt | SingleStoreInt>(column, [ + 'PgInteger', + 'PgSerial', + 'MySqlInt', + 'SingleStoreInt', + ]) ) { min = unsigned ? 0 : CONSTANTS.INT32_MIN; max = unsigned ? CONSTANTS.INT32_UNSIGNED_MAX : CONSTANTS.INT32_MAX; integer = true; } else if ( - isColumnType | MySqlReal | MySqlDouble | SQLiteReal>(column, [ + isColumnType< + | PgDoublePrecision + | MySqlReal + | MySqlDouble + | SingleStoreReal + | SingleStoreDouble + | SQLiteReal + >(column, [ 'PgDoublePrecision', 'MySqlReal', 'MySqlDouble', + 'SingleStoreReal', + 'SingleStoreDouble', 'SQLiteReal', ]) ) { min = unsigned ? 0 : CONSTANTS.INT48_MIN; max = unsigned ? CONSTANTS.INT48_UNSIGNED_MAX : CONSTANTS.INT48_MAX; } else if ( - isColumnType | PgBigSerial53 | MySqlBigInt53 | MySqlSerial | SQLiteInteger>( + isColumnType< + | PgBigInt53 + | PgBigSerial53 + | MySqlBigInt53 + | MySqlSerial + | SingleStoreBigInt53 + | SingleStoreSerial + | SQLiteInteger + >( column, - ['PgBigInt53', 'PgBigSerial53', 'MySqlBigInt53', 'MySqlSerial', 'SQLiteInteger'], + [ + 'PgBigInt53', + 'PgBigSerial53', + 'MySqlBigInt53', + 'MySqlSerial', + 'SingleStoreBigInt53', + 'SingleStoreSerial', + 'SQLiteInteger', + ], ) ) { - unsigned = unsigned || isColumnType(column, ['MySqlSerial']); + unsigned = unsigned || isColumnType(column, ['MySqlSerial', 'SingleStoreSerial']); min = unsigned ? 0 : Number.MIN_SAFE_INTEGER; max = Number.MAX_SAFE_INTEGER; integer = true; - } else if (isColumnType>(column, ['MySqlYear'])) { + } else if (isColumnType | SingleStoreYear>(column, ['MySqlYear', 'SingleStoreYear'])) { min = 1901; max = 2155; integer = true; @@ -201,9 +251,11 @@ function stringColumnToSchema(column: Column): v.GenericSchema { if (isColumnType | SQLiteText>(column, ['PgVarchar', 'SQLiteText'])) { max = column.length; - } else if (isColumnType>(column, ['MySqlVarChar'])) { + } else if ( + isColumnType | SingleStoreVarChar>(column, ['MySqlVarChar', 'SingleStoreVarChar']) + ) { max = column.length ?? CONSTANTS.INT16_UNSIGNED_MAX; - } else if (isColumnType>(column, ['MySqlText'])) { + } else if (isColumnType | SingleStoreText>(column, ['MySqlText', 'SingleStoreText'])) { if (column.textType === 'longtext') { max = CONSTANTS.INT32_UNSIGNED_MAX; } else if (column.textType === 'mediumtext') { @@ -215,7 +267,13 @@ function stringColumnToSchema(column: Column): v.GenericSchema { } } - if (isColumnType | MySqlChar>(column, ['PgChar', 'MySqlChar'])) { + if ( + isColumnType | MySqlChar | SingleStoreChar>(column, [ + 'PgChar', + 'MySqlChar', + 'SingleStoreChar', + ]) + ) { max = column.length; fixed = true; } diff --git a/drizzle-valibot/src/column.types.ts b/drizzle-valibot/src/column.types.ts index b9567b12d..2b30cb60a 100644 --- a/drizzle-valibot/src/column.types.ts +++ b/drizzle-valibot/src/column.types.ts @@ -20,15 +20,16 @@ export type GetBaseColumn = TColumn['_'] extends { baseC export type EnumValuesToEnum = { readonly [K in TEnumValues[number]]: K }; export type ExtractAdditionalProperties = { - max: TColumn['_']['columnType'] extends 'PgVarchar' | 'SQLiteText' | 'PgChar' | 'MySqlChar' + max: TColumn['_']['columnType'] extends 'PgVarchar' | 'SQLiteText' | 'PgChar' | 'MySqlChar' | 'SingleStoreChar' ? Assume['length'] - : TColumn['_']['columnType'] extends 'MySqlText' | 'MySqlVarChar' ? number + : TColumn['_']['columnType'] extends 'MySqlText' | 'MySqlVarChar' | 'SingleStoreText' | 'SingleStoreVarChar' + ? number : TColumn['_']['columnType'] extends 'PgBinaryVector' | 'PgHalfVector' | 'PgVector' ? Assume['dimensions'] : TColumn['_']['columnType'] extends 'PgArray' ? Assume['size'] : undefined; - fixedLength: TColumn['_']['columnType'] extends 'PgChar' | 'MySqlChar' | 'PgHalfVector' | 'PgVector' | 'PgArray' - ? true + fixedLength: TColumn['_']['columnType'] extends + 'PgChar' | 'PgHalfVector' | 'PgVector' | 'PgArray' | 'MySqlChar' | 'SingleStoreChar' ? true : false; }; @@ -98,19 +99,26 @@ export type GetValibotType< v.MaxValueAction, TColumnType extends | 'MySqlTinyInt' + | 'SingleStoreTinyInt' | 'PgSmallInt' | 'PgSmallSerial' | 'MySqlSmallInt' | 'MySqlMediumInt' + | 'SingleStoreSmallInt' + | 'SingleStoreMediumInt' | 'PgInteger' | 'PgSerial' | 'MySqlInt' + | 'SingleStoreInt' | 'PgBigInt53' | 'PgBigSerial53' | 'MySqlBigInt53' | 'MySqlSerial' + | 'SingleStoreBigInt53' + | 'SingleStoreSerial' | 'SQLiteInteger' - | 'MySqlYear' ? v.IntegerAction + | 'MySqlYear' + | 'SingleStoreYear' ? v.IntegerAction : never, ]> > diff --git a/drizzle-valibot/tests/singlestore.test.ts b/drizzle-valibot/tests/singlestore.test.ts new file mode 100644 index 000000000..0827ba7a1 --- /dev/null +++ b/drizzle-valibot/tests/singlestore.test.ts @@ -0,0 +1,500 @@ +import { type Equal } from 'drizzle-orm'; +import { customType, int, serial, singlestoreSchema, singlestoreTable, text } from 'drizzle-orm/singlestore-core'; +import * as v from 'valibot'; +import { test } from 'vitest'; +import { jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectSchemaShape } from './utils.ts'; + +const intSchema = v.pipe( + v.number(), + v.minValue(CONSTANTS.INT32_MIN as number), + v.maxValue(CONSTANTS.INT32_MAX as number), + v.integer(), +); +const serialNumberModeSchema = v.pipe( + v.number(), + v.minValue(0 as number), + v.maxValue(Number.MAX_SAFE_INTEGER as number), + v.integer(), +); +const textSchema = v.pipe(v.string(), v.maxLength(CONSTANTS.INT16_UNSIGNED_MAX as number)); + +test('table - select', (t) => { + const table = singlestoreTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = v.object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('table in schema - select', (tc) => { + const schema = singlestoreSchema('test'); + const table = schema.table('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = v.object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('table - insert', (t) => { + const table = singlestoreTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); + + const result = createInsertSchema(table); + const expected = v.object({ + id: v.optional(serialNumberModeSchema), + name: textSchema, + age: v.optional(v.nullable(intSchema)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('table - update', (t) => { + const table = singlestoreTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); + + const result = createUpdateSchema(table); + const expected = v.object({ + id: v.optional(serialNumberModeSchema), + name: v.optional(textSchema), + age: v.optional(v.nullable(intSchema)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +// TODO: SingleStore doesn't support views yet. Add these tests when they're added + +// test('view qb - select', (t) => { +// const table = singlestoreTable('test', { +// id: serial().primaryKey(), +// name: text().notNull(), +// }); +// const view = mysqlView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + +// const result = createSelectSchema(view); +// const expected = v.object({ id: serialNumberModeSchema, age: v.any() }); +// expectSchemaShape(t, expected).from(result); +// Expect>(); +// }); + +// test('view columns - select', (t) => { +// const view = mysqlView('test', { +// id: serial().primaryKey(), +// name: text().notNull(), +// }).as(sql``); + +// const result = createSelectSchema(view); +// const expected = v.object({ id: serialNumberModeSchema, name: textSchema }); +// expectSchemaShape(t, expected).from(result); +// Expect>(); +// }); + +// test('view with nested fields - select', (t) => { +// const table = singlestoreTable('test', { +// id: serial().primaryKey(), +// name: text().notNull(), +// }); +// const view = mysqlView('test').as((qb) => +// qb.select({ +// id: table.id, +// nested: { +// name: table.name, +// age: sql``.as('age'), +// }, +// table, +// }).from(table) +// ); + +// const result = createSelectSchema(view); +// const expected = v.object({ +// id: serialNumberModeSchema, +// nested: v.object({ name: textSchema, age: v.any() }), +// table: v.object({ id: serialNumberModeSchema, name: textSchema }), +// }); +// expectSchemaShape(t, expected).from(result); +// Expect>(); +// }); + +test('nullability - select', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + }); + + const result = createSelectSchema(table); + const expected = v.object({ + c1: v.nullable(intSchema), + c2: intSchema, + c3: v.nullable(intSchema), + c4: intSchema, + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('nullability - insert', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: intSchema, + c3: v.optional(v.nullable(intSchema)), + c4: v.optional(intSchema), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('nullability - update', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: v.optional(intSchema), + c3: v.optional(v.nullable(intSchema)), + c4: v.optional(intSchema), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - select', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + }); + + const result = createSelectSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.nullable(intSchema), + c2: v.pipe(intSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - select with custom data type', (t) => { + const customText = customType({ dataType: () => 'text' }); + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: customText(), + }); + + const customTextSchema = v.pipe(v.string(), v.minLength(1), v.maxLength(100)); + const result = createSelectSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + c4: customTextSchema, + }); + const expected = v.object({ + c1: v.nullable(intSchema), + c2: v.pipe(intSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + c4: customTextSchema, + }); + + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - insert', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: v.pipe(intSchema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +test('refine table - update', (t) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table, { + c2: (schema) => v.pipe(schema, v.maxValue(1000)), + c3: v.pipe(v.string(), v.transform(Number)), + }); + const expected = v.object({ + c1: v.optional(v.nullable(intSchema)), + c2: v.optional(v.pipe(intSchema, v.maxValue(1000))), + c3: v.pipe(v.string(), v.transform(Number)), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +// test('refine view - select', (t) => { +// const table = singlestoreTable('test', { +// c1: int(), +// c2: int(), +// c3: int(), +// c4: int(), +// c5: int(), +// c6: int(), +// }); +// const view = mysqlView('test').as((qb) => +// qb.select({ +// c1: table.c1, +// c2: table.c2, +// c3: table.c3, +// nested: { +// c4: table.c4, +// c5: table.c5, +// c6: table.c6, +// }, +// table, +// }).from(table) +// ); + +// const result = createSelectSchema(view, { +// c2: (schema) => v.pipe(schema, v.maxValue(1000)), +// c3: v.pipe(v.string(), v.transform(Number)), +// nested: { +// c5: (schema) => v.pipe(schema, v.maxValue(1000)), +// c6: v.pipe(v.string(), v.transform(Number)), +// }, +// table: { +// c2: (schema) => v.pipe(schema, v.maxValue(1000)), +// c3: v.pipe(v.string(), v.transform(Number)), +// }, +// }); +// const expected = v.object({ +// c1: v.nullable(intSchema), +// c2: v.nullable(v.pipe(intSchema, v.maxValue(1000))), +// c3: v.pipe(v.string(), v.transform(Number)), +// nested: v.object({ +// c4: v.nullable(intSchema), +// c5: v.nullable(v.pipe(intSchema, v.maxValue(1000))), +// c6: v.pipe(v.string(), v.transform(Number)), +// }), +// table: v.object({ +// c1: v.nullable(intSchema), +// c2: v.nullable(v.pipe(intSchema, v.maxValue(1000))), +// c3: v.pipe(v.string(), v.transform(Number)), +// c4: v.nullable(intSchema), +// c5: v.nullable(intSchema), +// c6: v.nullable(intSchema), +// }), +// }); +// expectSchemaShape(t, expected).from(result); +// Expect>(); +// }); + +test('all data types', (t) => { + const table = singlestoreTable('test', ({ + bigint, + binary, + boolean, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + singlestoreEnum, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varchar, + varbinary, + year, + longtext, + mediumtext, + tinytext, + }) => ({ + bigint1: bigint({ mode: 'number' }).notNull(), + bigint2: bigint({ mode: 'bigint' }).notNull(), + bigint3: bigint({ unsigned: true, mode: 'number' }).notNull(), + bigint4: bigint({ unsigned: true, mode: 'bigint' }).notNull(), + binary: binary({ length: 10 }).notNull(), + boolean: boolean().notNull(), + char1: char({ length: 10 }).notNull(), + char2: char({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + date1: date({ mode: 'date' }).notNull(), + date2: date({ mode: 'string' }).notNull(), + datetime1: datetime({ mode: 'date' }).notNull(), + datetime2: datetime({ mode: 'string' }).notNull(), + decimal1: decimal().notNull(), + decimal2: decimal({ unsigned: true }).notNull(), + double1: double().notNull(), + double2: double({ unsigned: true }).notNull(), + float1: float().notNull(), + float2: float({ unsigned: true }).notNull(), + int1: int().notNull(), + int2: int({ unsigned: true }).notNull(), + json: json().notNull(), + mediumint1: mediumint().notNull(), + mediumint2: mediumint({ unsigned: true }).notNull(), + enum: singlestoreEnum('enum', ['a', 'b', 'c']).notNull(), + real: real().notNull(), + serial: serial().notNull(), + smallint1: smallint().notNull(), + smallint2: smallint({ unsigned: true }).notNull(), + text1: text().notNull(), + text2: text({ enum: ['a', 'b', 'c'] }).notNull(), + time: time().notNull(), + timestamp1: timestamp({ mode: 'date' }).notNull(), + timestamp2: timestamp({ mode: 'string' }).notNull(), + tinyint1: tinyint().notNull(), + tinyint2: tinyint({ unsigned: true }).notNull(), + varchar1: varchar({ length: 10 }).notNull(), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + varbinary: varbinary({ length: 10 }).notNull(), + year: year().notNull(), + longtext1: longtext().notNull(), + longtext2: longtext({ enum: ['a', 'b', 'c'] }).notNull(), + mediumtext1: mediumtext().notNull(), + mediumtext2: mediumtext({ enum: ['a', 'b', 'c'] }).notNull(), + tinytext1: tinytext().notNull(), + tinytext2: tinytext({ enum: ['a', 'b', 'c'] }).notNull(), + })); + + const result = createSelectSchema(table); + const expected = v.object({ + bigint1: v.pipe(v.number(), v.minValue(Number.MIN_SAFE_INTEGER), v.maxValue(Number.MAX_SAFE_INTEGER), v.integer()), + bigint2: v.pipe(v.bigint(), v.minValue(CONSTANTS.INT64_MIN), v.maxValue(CONSTANTS.INT64_MAX)), + bigint3: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(Number.MAX_SAFE_INTEGER), v.integer()), + bigint4: v.pipe(v.bigint(), v.minValue(0n as bigint), v.maxValue(CONSTANTS.INT64_UNSIGNED_MAX)), + binary: v.string(), + boolean: v.boolean(), + char1: v.pipe(v.string(), v.length(10 as number)), + char2: v.enum({ a: 'a', b: 'b', c: 'c' }), + date1: v.date(), + date2: v.string(), + datetime1: v.date(), + datetime2: v.string(), + decimal1: v.string(), + decimal2: v.string(), + double1: v.pipe(v.number(), v.minValue(CONSTANTS.INT48_MIN), v.maxValue(CONSTANTS.INT48_MAX)), + double2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT48_UNSIGNED_MAX)), + float1: v.pipe(v.number(), v.minValue(CONSTANTS.INT24_MIN), v.maxValue(CONSTANTS.INT24_MAX)), + float2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT24_UNSIGNED_MAX)), + int1: v.pipe(v.number(), v.minValue(CONSTANTS.INT32_MIN), v.maxValue(CONSTANTS.INT32_MAX), v.integer()), + int2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT32_UNSIGNED_MAX), v.integer()), + json: jsonSchema, + mediumint1: v.pipe(v.number(), v.minValue(CONSTANTS.INT24_MIN), v.maxValue(CONSTANTS.INT24_MAX), v.integer()), + mediumint2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT24_UNSIGNED_MAX), v.integer()), + enum: v.enum({ a: 'a', b: 'b', c: 'c' }), + real: v.pipe(v.number(), v.minValue(CONSTANTS.INT48_MIN), v.maxValue(CONSTANTS.INT48_MAX)), + serial: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(Number.MAX_SAFE_INTEGER), v.integer()), + smallint1: v.pipe(v.number(), v.minValue(CONSTANTS.INT16_MIN), v.maxValue(CONSTANTS.INT16_MAX), v.integer()), + smallint2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT16_UNSIGNED_MAX), v.integer()), + text1: v.pipe(v.string(), v.maxLength(CONSTANTS.INT16_UNSIGNED_MAX)), + text2: v.enum({ a: 'a', b: 'b', c: 'c' }), + time: v.string(), + timestamp1: v.date(), + timestamp2: v.string(), + tinyint1: v.pipe(v.number(), v.minValue(CONSTANTS.INT8_MIN), v.maxValue(CONSTANTS.INT8_MAX), v.integer()), + tinyint2: v.pipe(v.number(), v.minValue(0 as number), v.maxValue(CONSTANTS.INT8_UNSIGNED_MAX), v.integer()), + varchar1: v.pipe(v.string(), v.maxLength(10 as number)), + varchar2: v.enum({ a: 'a', b: 'b', c: 'c' }), + varbinary: v.string(), + year: v.pipe(v.number(), v.minValue(1901 as number), v.maxValue(2155 as number), v.integer()), + longtext1: v.pipe(v.string(), v.maxLength(CONSTANTS.INT32_UNSIGNED_MAX)), + longtext2: v.enum({ a: 'a', b: 'b', c: 'c' }), + mediumtext1: v.pipe(v.string(), v.maxLength(CONSTANTS.INT24_UNSIGNED_MAX)), + mediumtext2: v.enum({ a: 'a', b: 'b', c: 'c' }), + tinytext1: v.pipe(v.string(), v.maxLength(CONSTANTS.INT8_UNSIGNED_MAX)), + tinytext2: v.enum({ a: 'a', b: 'b', c: 'c' }), + }); + expectSchemaShape(t, expected).from(result); + Expect>(); +}); + +/* Disallow unknown keys in table refinement - select */ { + const table = singlestoreTable('test', { id: int() }); + // @ts-expect-error + createSelectSchema(table, { unknown: v.string() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = singlestoreTable('test', { id: int() }); + // @ts-expect-error + createInsertSchema(table, { unknown: v.string() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = singlestoreTable('test', { id: int() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: v.string() }); +} + +// /* Disallow unknown keys in view qb - select */ { +// const table = singlestoreTable('test', { id: int() }); +// const view = mysqlView('test').as((qb) => qb.select().from(table)); +// const nestedSelect = mysqlView('test').as((qb) => qb.select({ table }).from(table)); +// // @ts-expect-error +// createSelectSchema(view, { unknown: v.string() }); +// // @ts-expect-error +// createSelectSchema(nestedSelect, { table: { unknown: v.string() } }); +// } + +// /* Disallow unknown keys in view columns - select */ { +// const view = mysqlView('test', { id: int() }).as(sql``); +// // @ts-expect-error +// createSelectSchema(view, { unknown: v.string() }); +// } From 455725c635960ba9757870c2522dd0e8e9ce0388 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Wed, 18 Dec 2024 19:46:41 +0200 Subject: [PATCH 454/492] updated changelogs --- changelogs/drizzle-seed/0.1.4.md | 106 +++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 changelogs/drizzle-seed/0.1.4.md diff --git a/changelogs/drizzle-seed/0.1.4.md b/changelogs/drizzle-seed/0.1.4.md new file mode 100644 index 000000000..84c3821af --- /dev/null +++ b/changelogs/drizzle-seed/0.1.4.md @@ -0,0 +1,106 @@ +## Improvements + +- A new parameter, `version`, was added to the `seed` function options, which will control generator versioning. + +```ts +await seed(db, schema, { version: 1 }); +``` + +Generator versions will change within a single major version of drizzle-seed. + +The old version of the generator will become available if the generator has been changed and the output of the new generator does not match the output of the old generator. + +#### For example: + +`FirstNameGen` was changed, and old version, `V1`, of this generator became available. + +Later, `LastNameGen` was changed in the next minor version of drizzle-seed, making `V2` version of this generator available. + +| | `V1` | `V2` | `V3(latest)` | +| :--------------: | :--------------: | :-------------: | :--------------: | +| **FirstNameGen** | `FirstNameGenV1` | `same as V3` | `FirstNameGenV3` | +| **LastNameGen** | `same as V2` | `LastNameGenV2` | `LastNameGenV3` | + +If you omit version, `V3` version of generators will be used. + +If you specify version of 2, `FirstNameGen` will use its `V3` version and `LastNameGen` will use its `V2` version. + +If you specify version of 1, `FirstNameGen` will use its `V1` version and `LastNameGen` will use its `V2` version. + +## + +- added `fields` as new parameter in `interval` generator + +`interval` generator generates intervals based on the following principle: + +fields to the right of the last specified field are zeroed out, while fields to the left remain valid. + +Thus, for example, there is no difference between the `year to month` fields and the `month` fields, because fields to the right of `month` (`day`, `hour`, `minute`, `second`) are zeroed out, while fields to the left (`year`) remain valid. + +Example + +```ts +import { pgTable, interval } from "drizzle-orm/pg-core"; +import { drizzle } from "drizzle-orm/node-postgres"; +import { seed } from "drizzle-seed"; + +const intervals = pgTable("intervals", { + interval: interval(), +}); + +async function main() { + const db = drizzle(process.env.DATABASE_URL!); + + await seed(db, { intervals }, { count: 1000 }).refine((funcs) => ({ + intervals: { + columns: { + interval: funcs.interval({ + fields: "day to hour", + }), + }, + }, + })); +} + +main(); +``` + +You can also specify fields in a table and seed them automatically. + +```ts +import { pgTable, interval } from "drizzle-orm/pg-core"; +import { drizzle } from "drizzle-orm/node-postgres"; +import { seed } from "drizzle-seed"; + +const intervals = pgTable("intervals", { + interval: interval({ fields: "day to hour" }), +}); + +async function main() { + const db = drizzle(process.env.DATABASE_URL!); + + await seed(db, { intervals }, { count: 1000 }); +} + +main(); +``` + +## Breaking changes + +- Unique `interval` generator was changed, so `1` version of this generator become available. **The latest version is `2`.** + +**Cause:** + +**Bug in generator:** +Old version of generator could generate intervals like: `1 minute 60 second`, `2 minute 0 second` and treat them as different intervals. + +However, after inserting the `1 minute 60 second` interval, PostgreSQL database will convert it to `2 minute 0 second`. As a result, subsequent insertion of the `2 minute 0 second` interval into a unique column will cause an error. + +## + +- Both non-unique and unique `string` generators were changed, making version `1` of these generators available. **The latest version is `2`.** + +**Cause:** + +**Generating strings based on text-like column length:** +Now (in version 2), the maximum length of a string depends on the length of the text column (e.g., `varchar(20)`). From c5efbadeab13d3a20df0037319a27f088dfbc12c Mon Sep 17 00:00:00 2001 From: Mario564 Date: Wed, 18 Dec 2024 09:52:41 -0800 Subject: [PATCH 455/492] Add SS support to drizzle-typebox --- drizzle-typebox/src/column.ts | 84 +++- drizzle-typebox/src/column.types.ts | 9 +- drizzle-typebox/tests/singlestore.test.ts | 497 ++++++++++++++++++++++ drizzle-valibot/src/column.ts | 2 +- 4 files changed, 577 insertions(+), 15 deletions(-) create mode 100644 drizzle-typebox/tests/singlestore.test.ts diff --git a/drizzle-typebox/src/column.ts b/drizzle-typebox/src/column.ts index 510ba7bbe..9bef765bf 100644 --- a/drizzle-typebox/src/column.ts +++ b/drizzle-typebox/src/column.ts @@ -39,6 +39,21 @@ import type { PgVarchar, PgVector, } from 'drizzle-orm/pg-core'; +import { + type SingleStoreBigInt53, + SingleStoreChar, + type SingleStoreDouble, + type SingleStoreFloat, + type SingleStoreInt, + type SingleStoreMediumInt, + type SingleStoreReal, + type SingleStoreSerial, + type SingleStoreSmallInt, + SingleStoreText, + type SingleStoreTinyInt, + SingleStoreVarChar, + SingleStoreYear, +} from 'drizzle-orm/singlestore-core'; import type { SQLiteInteger, SQLiteReal, SQLiteText } from 'drizzle-orm/sqlite-core'; import { CONSTANTS } from './constants.ts'; import { isColumnType, isWithEnum } from './utils.ts'; @@ -133,57 +148,92 @@ function numberColumnToSchema(column: Column, t: typeof typebox): TSchema { let max!: number; let integer = false; - if (isColumnType>(column, ['MySqlTinyInt'])) { + if (isColumnType | SingleStoreTinyInt>(column, ['MySqlTinyInt', 'SingleStoreTinyInt'])) { min = unsigned ? 0 : CONSTANTS.INT8_MIN; max = unsigned ? CONSTANTS.INT8_UNSIGNED_MAX : CONSTANTS.INT8_MAX; integer = true; } else if ( - isColumnType | PgSmallSerial | MySqlSmallInt>(column, [ + isColumnType | PgSmallSerial | MySqlSmallInt | SingleStoreSmallInt>(column, [ 'PgSmallInt', 'PgSmallSerial', 'MySqlSmallInt', + 'SingleStoreSmallInt', ]) ) { min = unsigned ? 0 : CONSTANTS.INT16_MIN; max = unsigned ? CONSTANTS.INT16_UNSIGNED_MAX : CONSTANTS.INT16_MAX; integer = true; } else if ( - isColumnType | MySqlFloat | MySqlMediumInt>(column, [ + isColumnType< + PgReal | MySqlFloat | MySqlMediumInt | SingleStoreFloat | SingleStoreMediumInt + >(column, [ 'PgReal', 'MySqlFloat', 'MySqlMediumInt', + 'SingleStoreFloat', + 'SingleStoreMediumInt', ]) ) { min = unsigned ? 0 : CONSTANTS.INT24_MIN; max = unsigned ? CONSTANTS.INT24_UNSIGNED_MAX : CONSTANTS.INT24_MAX; - integer = isColumnType(column, ['MySqlMediumInt']); + integer = isColumnType(column, ['MySqlMediumInt', 'SingleStoreMediumInt']); } else if ( - isColumnType | PgSerial | MySqlInt>(column, ['PgInteger', 'PgSerial', 'MySqlInt']) + isColumnType | PgSerial | MySqlInt | SingleStoreInt>(column, [ + 'PgInteger', + 'PgSerial', + 'MySqlInt', + 'SingleStoreInt', + ]) ) { min = unsigned ? 0 : CONSTANTS.INT32_MIN; max = unsigned ? CONSTANTS.INT32_UNSIGNED_MAX : CONSTANTS.INT32_MAX; integer = true; } else if ( - isColumnType | MySqlReal | MySqlDouble | SQLiteReal>(column, [ + isColumnType< + | PgDoublePrecision + | MySqlReal + | MySqlDouble + | SingleStoreReal + | SingleStoreDouble + | SQLiteReal + >(column, [ 'PgDoublePrecision', 'MySqlReal', 'MySqlDouble', + 'SingleStoreReal', + 'SingleStoreDouble', 'SQLiteReal', ]) ) { min = unsigned ? 0 : CONSTANTS.INT48_MIN; max = unsigned ? CONSTANTS.INT48_UNSIGNED_MAX : CONSTANTS.INT48_MAX; } else if ( - isColumnType | PgBigSerial53 | MySqlBigInt53 | MySqlSerial | SQLiteInteger>( + isColumnType< + | PgBigInt53 + | PgBigSerial53 + | MySqlBigInt53 + | MySqlSerial + | SingleStoreBigInt53 + | SingleStoreSerial + | SQLiteInteger + >( column, - ['PgBigInt53', 'PgBigSerial53', 'MySqlBigInt53', 'MySqlSerial', 'SQLiteInteger'], + [ + 'PgBigInt53', + 'PgBigSerial53', + 'MySqlBigInt53', + 'MySqlSerial', + 'SingleStoreBigInt53', + 'SingleStoreSerial', + 'SQLiteInteger', + ], ) ) { - unsigned = unsigned || isColumnType(column, ['MySqlSerial']); + unsigned = unsigned || isColumnType(column, ['MySqlSerial', 'SingleStoreSerial']); min = unsigned ? 0 : Number.MIN_SAFE_INTEGER; max = Number.MAX_SAFE_INTEGER; integer = true; - } else if (isColumnType>(column, ['MySqlYear'])) { + } else if (isColumnType | SingleStoreYear>(column, ['MySqlYear', 'SingleStoreYear'])) { min = 1901; max = 2155; integer = true; @@ -226,9 +276,11 @@ function stringColumnToSchema(column: Column, t: typeof typebox): TSchema { if (isColumnType | SQLiteText>(column, ['PgVarchar', 'SQLiteText'])) { max = column.length; - } else if (isColumnType>(column, ['MySqlVarChar'])) { + } else if ( + isColumnType | SingleStoreVarChar>(column, ['MySqlVarChar', 'SingleStoreVarChar']) + ) { max = column.length ?? CONSTANTS.INT16_UNSIGNED_MAX; - } else if (isColumnType>(column, ['MySqlText'])) { + } else if (isColumnType | SingleStoreText>(column, ['MySqlText', 'SingleStoreText'])) { if (column.textType === 'longtext') { max = CONSTANTS.INT32_UNSIGNED_MAX; } else if (column.textType === 'mediumtext') { @@ -240,7 +292,13 @@ function stringColumnToSchema(column: Column, t: typeof typebox): TSchema { } } - if (isColumnType | MySqlChar>(column, ['PgChar', 'MySqlChar'])) { + if ( + isColumnType | MySqlChar | SingleStoreChar>(column, [ + 'PgChar', + 'MySqlChar', + 'SingleStoreChar', + ]) + ) { max = column.length; fixed = true; } diff --git a/drizzle-typebox/src/column.types.ts b/drizzle-typebox/src/column.types.ts index 7010f234e..2644946c1 100644 --- a/drizzle-typebox/src/column.types.ts +++ b/drizzle-typebox/src/column.types.ts @@ -21,19 +21,26 @@ export type GetTypeboxType< TBaseColumn extends Column | undefined, > = TColumnType extends | 'MySqlTinyInt' + | 'SingleStoreTinyInt' | 'PgSmallInt' | 'PgSmallSerial' | 'MySqlSmallInt' | 'MySqlMediumInt' + | 'SingleStoreSmallInt' + | 'SingleStoreMediumInt' | 'PgInteger' | 'PgSerial' | 'MySqlInt' + | 'SingleStoreInt' | 'PgBigInt53' | 'PgBigSerial53' | 'MySqlBigInt53' | 'MySqlSerial' + | 'SingleStoreBigInt53' + | 'SingleStoreSerial' | 'SQLiteInteger' - | 'MySqlYear' ? t.TInteger + | 'MySqlYear' + | 'SingleStoreYear' ? t.TInteger : TColumnType extends 'PgBinaryVector' ? t.TRegExp : TBaseColumn extends Column ? t.TArray< GetTypeboxType< diff --git a/drizzle-typebox/tests/singlestore.test.ts b/drizzle-typebox/tests/singlestore.test.ts new file mode 100644 index 000000000..f643ab3b7 --- /dev/null +++ b/drizzle-typebox/tests/singlestore.test.ts @@ -0,0 +1,497 @@ +import { Type as t } from '@sinclair/typebox'; +import { type Equal, sql } from 'drizzle-orm'; +import { customType, int, serial, singlestoreSchema, singlestoreTable, text } from 'drizzle-orm/singlestore-core'; +import { test } from 'vitest'; +import { jsonSchema } from '~/column.ts'; +import { CONSTANTS } from '~/constants.ts'; +import { createInsertSchema, createSelectSchema, createUpdateSchema } from '../src'; +import { Expect, expectSchemaShape } from './utils.ts'; + +const intSchema = t.Integer({ + minimum: CONSTANTS.INT32_MIN, + maximum: CONSTANTS.INT32_MAX, +}); +const serialNumberModeSchema = t.Integer({ + minimum: 0, + maximum: Number.MAX_SAFE_INTEGER, +}); +const textSchema = t.String({ maxLength: CONSTANTS.INT16_UNSIGNED_MAX }); + +test('table - select', (tc) => { + const table = singlestoreTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = t.Object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('table in schema - select', (tc) => { + const schema = singlestoreSchema('test'); + const table = schema.table('test', { + id: serial().primaryKey(), + name: text().notNull(), + }); + + const result = createSelectSchema(table); + const expected = t.Object({ id: serialNumberModeSchema, name: textSchema }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('table - insert', (tc) => { + const table = singlestoreTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); + + const result = createInsertSchema(table); + const expected = t.Object({ + id: t.Optional(serialNumberModeSchema), + name: textSchema, + age: t.Optional(t.Union([intSchema, t.Null()])), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('table - update', (tc) => { + const table = singlestoreTable('test', { + id: serial().primaryKey(), + name: text().notNull(), + age: int(), + }); + + const result = createUpdateSchema(table); + const expected = t.Object({ + id: t.Optional(serialNumberModeSchema), + name: t.Optional(textSchema), + age: t.Optional(t.Union([intSchema, t.Null()])), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +// TODO: SingleStore doesn't support views yet. Add these tests when they're added + +// test('view qb - select', (tc) => { +// const table = singlestoreTable('test', { +// id: serial().primaryKey(), +// name: text().notNull(), +// }); +// const view = mysqlView('test').as((qb) => qb.select({ id: table.id, age: sql``.as('age') }).from(table)); + +// const result = createSelectSchema(view); +// const expected = t.Object({ id: serialNumberModeSchema, age: t.Any() }); +// expectSchemaShape(tc, expected).from(result); +// Expect>(); +// }); + +// test('view columns - select', (tc) => { +// const view = mysqlView('test', { +// id: serial().primaryKey(), +// name: text().notNull(), +// }).as(sql``); + +// const result = createSelectSchema(view); +// const expected = t.Object({ id: serialNumberModeSchema, name: textSchema }); +// expectSchemaShape(tc, expected).from(result); +// Expect>(); +// }); + +// test('view with nested fields - select', (tc) => { +// const table = singlestoreTable('test', { +// id: serial().primaryKey(), +// name: text().notNull(), +// }); +// const view = mysqlView('test').as((qb) => +// qb.select({ +// id: table.id, +// nested: { +// name: table.name, +// age: sql``.as('age'), +// }, +// table, +// }).from(table) +// ); + +// const result = createSelectSchema(view); +// const expected = t.Object({ +// id: serialNumberModeSchema, +// nested: t.Object({ name: textSchema, age: t.Any() }), +// table: t.Object({ id: serialNumberModeSchema, name: textSchema }), +// }); +// expectSchemaShape(tc, expected).from(result); +// Expect>(); +// }); + +test('nullability - select', (tc) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + }); + + const result = createSelectSchema(table); + const expected = t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: intSchema, + c3: t.Union([intSchema, t.Null()]), + c4: intSchema, + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('nullability - insert', (tc) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: intSchema, + c3: t.Optional(t.Union([intSchema, t.Null()])), + c4: t.Optional(intSchema), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('nullability - update', (tc) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().default(1), + c4: int().notNull().default(1), + c5: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: t.Optional(intSchema), + c3: t.Optional(t.Union([intSchema, t.Null()])), + c4: t.Optional(intSchema), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine table - select', (tc) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + }); + + const result = createSelectSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine table - select with custom data type', (tc) => { + const customText = customType({ dataType: () => 'text' }); + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: customText(), + }); + + const customTextSchema = t.String({ minLength: 1, maxLength: 100 }); + const result = createSelectSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + c4: customTextSchema, + }); + const expected = t.Object({ + c1: t.Union([intSchema, t.Null()]), + c2: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + c4: customTextSchema, + }); + + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine table - insert', (tc) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createInsertSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +test('refine table - update', (tc) => { + const table = singlestoreTable('test', { + c1: int(), + c2: int().notNull(), + c3: int().notNull(), + c4: int().generatedAlwaysAs(1), + }); + + const result = createUpdateSchema(table, { + c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + const expected = t.Object({ + c1: t.Optional(t.Union([intSchema, t.Null()])), + c2: t.Optional(t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 })), + c3: t.Integer({ minimum: 1, maximum: 10 }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +// test('refine view - select', (tc) => { +// const table = singlestoreTable('test', { +// c1: int(), +// c2: int(), +// c3: int(), +// c4: int(), +// c5: int(), +// c6: int(), +// }); +// const view = mysqlView('test').as((qb) => +// qb.select({ +// c1: table.c1, +// c2: table.c2, +// c3: table.c3, +// nested: { +// c4: table.c4, +// c5: table.c5, +// c6: table.c6, +// }, +// table, +// }).from(table) +// ); + +// const result = createSelectSchema(view, { +// c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), +// c3: t.Integer({ minimum: 1, maximum: 10 }), +// nested: { +// c5: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), +// c6: t.Integer({ minimum: 1, maximum: 10 }), +// }, +// table: { +// c2: (schema) => t.Integer({ minimum: schema.minimum, maximum: 1000 }), +// c3: t.Integer({ minimum: 1, maximum: 10 }), +// }, +// }); +// const expected = t.Object({ +// c1: t.Union([intSchema, t.Null()]), +// c2: t.Union([t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), t.Null()]), +// c3: t.Integer({ minimum: 1, maximum: 10 }), +// nested: t.Object({ +// c4: t.Union([intSchema, t.Null()]), +// c5: t.Union([t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), t.Null()]), +// c6: t.Integer({ minimum: 1, maximum: 10 }), +// }), +// table: t.Object({ +// c1: t.Union([intSchema, t.Null()]), +// c2: t.Union([t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: 1000 }), t.Null()]), +// c3: t.Integer({ minimum: 1, maximum: 10 }), +// c4: t.Union([intSchema, t.Null()]), +// c5: t.Union([intSchema, t.Null()]), +// c6: t.Union([intSchema, t.Null()]), +// }), +// }); +// expectSchemaShape(tc, expected).from(result); +// Expect>(); +// }); + +test('all data types', (tc) => { + const table = singlestoreTable('test', ({ + bigint, + binary, + boolean, + char, + date, + datetime, + decimal, + double, + float, + int, + json, + mediumint, + singlestoreEnum, + real, + serial, + smallint, + text, + time, + timestamp, + tinyint, + varchar, + varbinary, + year, + longtext, + mediumtext, + tinytext, + }) => ({ + bigint1: bigint({ mode: 'number' }).notNull(), + bigint2: bigint({ mode: 'bigint' }).notNull(), + bigint3: bigint({ unsigned: true, mode: 'number' }).notNull(), + bigint4: bigint({ unsigned: true, mode: 'bigint' }).notNull(), + binary: binary({ length: 10 }).notNull(), + boolean: boolean().notNull(), + char1: char({ length: 10 }).notNull(), + char2: char({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + date1: date({ mode: 'date' }).notNull(), + date2: date({ mode: 'string' }).notNull(), + datetime1: datetime({ mode: 'date' }).notNull(), + datetime2: datetime({ mode: 'string' }).notNull(), + decimal1: decimal().notNull(), + decimal2: decimal({ unsigned: true }).notNull(), + double1: double().notNull(), + double2: double({ unsigned: true }).notNull(), + float1: float().notNull(), + float2: float({ unsigned: true }).notNull(), + int1: int().notNull(), + int2: int({ unsigned: true }).notNull(), + json: json().notNull(), + mediumint1: mediumint().notNull(), + mediumint2: mediumint({ unsigned: true }).notNull(), + enum: singlestoreEnum('enum', ['a', 'b', 'c']).notNull(), + real: real().notNull(), + serial: serial().notNull(), + smallint1: smallint().notNull(), + smallint2: smallint({ unsigned: true }).notNull(), + text1: text().notNull(), + text2: text({ enum: ['a', 'b', 'c'] }).notNull(), + time: time().notNull(), + timestamp1: timestamp({ mode: 'date' }).notNull(), + timestamp2: timestamp({ mode: 'string' }).notNull(), + tinyint1: tinyint().notNull(), + tinyint2: tinyint({ unsigned: true }).notNull(), + varchar1: varchar({ length: 10 }).notNull(), + varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }).notNull(), + varbinary: varbinary({ length: 10 }).notNull(), + year: year().notNull(), + longtext1: longtext().notNull(), + longtext2: longtext({ enum: ['a', 'b', 'c'] }).notNull(), + mediumtext1: mediumtext().notNull(), + mediumtext2: mediumtext({ enum: ['a', 'b', 'c'] }).notNull(), + tinytext1: tinytext().notNull(), + tinytext2: tinytext({ enum: ['a', 'b', 'c'] }).notNull(), + })); + + const result = createSelectSchema(table); + const expected = t.Object({ + bigint1: t.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: Number.MAX_SAFE_INTEGER }), + bigint2: t.BigInt({ minimum: CONSTANTS.INT64_MIN, maximum: CONSTANTS.INT64_MAX }), + bigint3: t.Integer({ minimum: 0, maximum: Number.MAX_SAFE_INTEGER }), + bigint4: t.BigInt({ minimum: 0n, maximum: CONSTANTS.INT64_UNSIGNED_MAX }), + binary: t.String(), + boolean: t.Boolean(), + char1: t.String({ minLength: 10, maxLength: 10 }), + char2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + date1: t.Date(), + date2: t.String(), + datetime1: t.Date(), + datetime2: t.String(), + decimal1: t.String(), + decimal2: t.String(), + double1: t.Number({ minimum: CONSTANTS.INT48_MIN, maximum: CONSTANTS.INT48_MAX }), + double2: t.Number({ minimum: 0, maximum: CONSTANTS.INT48_UNSIGNED_MAX }), + float1: t.Number({ minimum: CONSTANTS.INT24_MIN, maximum: CONSTANTS.INT24_MAX }), + float2: t.Number({ minimum: 0, maximum: CONSTANTS.INT24_UNSIGNED_MAX }), + int1: t.Integer({ minimum: CONSTANTS.INT32_MIN, maximum: CONSTANTS.INT32_MAX }), + int2: t.Integer({ minimum: 0, maximum: CONSTANTS.INT32_UNSIGNED_MAX }), + json: jsonSchema, + mediumint1: t.Integer({ minimum: CONSTANTS.INT24_MIN, maximum: CONSTANTS.INT24_MAX }), + mediumint2: t.Integer({ minimum: 0, maximum: CONSTANTS.INT24_UNSIGNED_MAX }), + enum: t.Enum({ a: 'a', b: 'b', c: 'c' }), + real: t.Number({ minimum: CONSTANTS.INT48_MIN, maximum: CONSTANTS.INT48_MAX }), + serial: t.Integer({ minimum: 0, maximum: Number.MAX_SAFE_INTEGER }), + smallint1: t.Integer({ minimum: CONSTANTS.INT16_MIN, maximum: CONSTANTS.INT16_MAX }), + smallint2: t.Integer({ minimum: 0, maximum: CONSTANTS.INT16_UNSIGNED_MAX }), + text1: t.String({ maxLength: CONSTANTS.INT16_UNSIGNED_MAX }), + text2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + time: t.String(), + timestamp1: t.Date(), + timestamp2: t.String(), + tinyint1: t.Integer({ minimum: CONSTANTS.INT8_MIN, maximum: CONSTANTS.INT8_MAX }), + tinyint2: t.Integer({ minimum: 0, maximum: CONSTANTS.INT8_UNSIGNED_MAX }), + varchar1: t.String({ maxLength: 10 }), + varchar2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + varbinary: t.String(), + year: t.Integer({ minimum: 1901, maximum: 2155 }), + longtext1: t.String({ maxLength: CONSTANTS.INT32_UNSIGNED_MAX }), + longtext2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + mediumtext1: t.String({ maxLength: CONSTANTS.INT24_UNSIGNED_MAX }), + mediumtext2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + tinytext1: t.String({ maxLength: CONSTANTS.INT8_UNSIGNED_MAX }), + tinytext2: t.Enum({ a: 'a', b: 'b', c: 'c' }), + }); + expectSchemaShape(tc, expected).from(result); + Expect>(); +}); + +/* Disallow unknown keys in table refinement - select */ { + const table = singlestoreTable('test', { id: int() }); + // @ts-expect-error + createSelectSchema(table, { unknown: t.String() }); +} + +/* Disallow unknown keys in table refinement - insert */ { + const table = singlestoreTable('test', { id: int() }); + // @ts-expect-error + createInsertSchema(table, { unknown: t.String() }); +} + +/* Disallow unknown keys in table refinement - update */ { + const table = singlestoreTable('test', { id: int() }); + // @ts-expect-error + createUpdateSchema(table, { unknown: t.String() }); +} + +// /* Disallow unknown keys in view qb - select */ { +// const table = singlestoreTable('test', { id: int() }); +// const view = mysqlView('test').as((qb) => qb.select().from(table)); +// const nestedSelect = mysqlView('test').as((qb) => qb.select({ table }).from(table)); +// // @ts-expect-error +// createSelectSchema(view, { unknown: t.String() }); +// // @ts-expect-error +// createSelectSchema(nestedSelect, { table: { unknown: t.String() } }); +// } + +// /* Disallow unknown keys in view columns - select */ { +// const view = mysqlView('test', { id: int() }).as(sql``); +// // @ts-expect-error +// createSelectSchema(view, { unknown: t.String() }); +// } diff --git a/drizzle-valibot/src/column.ts b/drizzle-valibot/src/column.ts index cf90751ef..040dbac21 100644 --- a/drizzle-valibot/src/column.ts +++ b/drizzle-valibot/src/column.ts @@ -37,7 +37,7 @@ import type { PgVarchar, PgVector, } from 'drizzle-orm/pg-core'; -import { +import type { SingleStoreBigInt53, SingleStoreChar, SingleStoreDouble, From cb89775679a335e8700019e0e4878b98479e0e1e Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Thu, 19 Dec 2024 14:56:51 +0200 Subject: [PATCH 456/492] updated generator versioning --- drizzle-seed/src/services/GeneratorFuncs.ts | 4 +- .../GeneratorVersions/GeneratorsV1.ts | 161 ------------ .../GeneratorVersions/GeneratorsV2.ts | 240 ++++++++++++++++++ drizzle-seed/src/services/Generators.ts | 148 +++-------- drizzle-seed/src/services/SeedService.ts | 16 +- 5 files changed, 288 insertions(+), 281 deletions(-) delete mode 100644 drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts create mode 100644 drizzle-seed/src/services/GeneratorVersions/GeneratorsV2.ts diff --git a/drizzle-seed/src/services/GeneratorFuncs.ts b/drizzle-seed/src/services/GeneratorFuncs.ts index 08f36b1dc..65e31fc09 100644 --- a/drizzle-seed/src/services/GeneratorFuncs.ts +++ b/drizzle-seed/src/services/GeneratorFuncs.ts @@ -24,7 +24,6 @@ import { GeneratePostcode, GenerateState, GenerateStreetAdddress, - GenerateString, GenerateTime, GenerateTimestamp, GenerateUUID, @@ -32,6 +31,7 @@ import { GenerateYear, WeightedRandomGenerator, } from './Generators.ts'; +import { GenerateStringV2 } from './GeneratorVersions/GeneratorsV2.ts'; function createGenerator, T>( generatorConstructor: new(params: T) => GeneratorType, @@ -359,7 +359,7 @@ export const generatorsFuncs = { * })); * ``` */ - string: createGenerator(GenerateString), + string: createGenerator(GenerateStringV2), // uniqueString: createGenerator(GenerateUniqueString), /** diff --git a/drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts b/drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts deleted file mode 100644 index 81655a941..000000000 --- a/drizzle-seed/src/services/GeneratorVersions/GeneratorsV1.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { entityKind } from 'drizzle-orm'; -import prand from 'pure-rand'; -import { AbstractGenerator, GenerateInterval } from '../Generators.ts'; - -export const version = 1; - -export class GenerateIntervalV1 extends GenerateInterval { - static override readonly [entityKind]: string = 'GenerateInterval'; - static override readonly ['version']: number = 1; - override uniqueVersionOfGen = GenerateUniqueIntervalV1; -} - -export class GenerateUniqueIntervalV1 extends AbstractGenerator<{ - isUnique?: boolean; -}> { - static override readonly [entityKind]: string = 'GenerateUniqueInterval'; - - private state: { - rng: prand.RandomGenerator; - intervalSet: Set; - } | undefined; - public override isUnique = true; - - override init({ count, seed }: { count: number; seed: number }) { - const maxUniqueIntervalsNumber = 6 * 13 * 29 * 25 * 61 * 61; - if (count > maxUniqueIntervalsNumber) { - throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`); - } - - const rng = prand.xoroshiro128plus(seed); - const intervalSet = new Set(); - this.state = { rng, intervalSet }; - } - - generate() { - if (this.state === undefined) { - throw new Error('state is not defined.'); - } - - let yearsNumb: number, - monthsNumb: number, - daysNumb: number, - hoursNumb: number, - minutesNumb: number, - secondsNumb: number; - - let interval = ''; - - for (;;) { - [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); - [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); - [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); - [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); - [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - - interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` - + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` - + `${daysNumb === 0 ? '' : `${daysNumb} days `}` - + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` - + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` - + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; - - if (!this.state.intervalSet.has(interval)) { - this.state.intervalSet.add(interval); - break; - } - } - - return interval; - } -} - -export class GenerateStringV1 extends AbstractGenerator<{ - isUnique?: boolean; - arraySize?: number; -}> { - static override readonly [entityKind]: string = 'GenerateString'; - - private state: { rng: prand.RandomGenerator } | undefined; - override uniqueVersionOfGen = GenerateUniqueStringV1; - - override init({ count, seed }: { count: number; seed: number }) { - super.init({ count, seed }); - - const rng = prand.xoroshiro128plus(seed); - this.state = { rng }; - } - - generate() { - if (this.state === undefined) { - throw new Error('state is not defined.'); - } - - const minStringLength = 7; - const maxStringLength = 20; - const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - let idx: number, - strLength: number, - currStr: string; - - currStr = ''; - [strLength, this.state.rng] = prand.uniformIntDistribution( - minStringLength, - maxStringLength, - this.state.rng, - ); - for (let j = 0; j < strLength; j++) { - [idx, this.state.rng] = prand.uniformIntDistribution( - 0, - stringChars.length - 1, - this.state.rng, - ); - currStr += stringChars[idx]; - } - return currStr; - } -} - -export class GenerateUniqueStringV1 extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueString'; - - private state: { rng: prand.RandomGenerator } | undefined; - public override isUnique = true; - - override init({ seed }: { seed: number }) { - const rng = prand.xoroshiro128plus(seed); - this.state = { rng }; - } - - generate({ i }: { i: number }) { - if (this.state === undefined) { - throw new Error('state is not defined.'); - } - - const minStringLength = 7; - const maxStringLength = 20; - const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - let idx: number, - strLength: number; - let currStr: string; - - currStr = ''; - const uniqueStr = i.toString(16); - [strLength, this.state.rng] = prand.uniformIntDistribution( - minStringLength, - maxStringLength - uniqueStr.length, - this.state.rng, - ); - for (let j = 0; j < strLength - uniqueStr.length; j++) { - [idx, this.state.rng] = prand.uniformIntDistribution( - 0, - stringChars.length - 1, - this.state.rng, - ); - currStr += stringChars[idx]; - } - - return currStr.slice(0, 4) + uniqueStr + currStr.slice(4); - } -} diff --git a/drizzle-seed/src/services/GeneratorVersions/GeneratorsV2.ts b/drizzle-seed/src/services/GeneratorVersions/GeneratorsV2.ts new file mode 100644 index 000000000..daedcdc98 --- /dev/null +++ b/drizzle-seed/src/services/GeneratorVersions/GeneratorsV2.ts @@ -0,0 +1,240 @@ +import { entityKind } from 'drizzle-orm'; +import prand from 'pure-rand'; +import { AbstractGenerator, GenerateInterval } from '../Generators.ts'; + +export const version = 2; + +export class GenerateIntervalV2 extends GenerateInterval { + static override readonly [entityKind]: string = 'GenerateInterval'; + static override readonly ['version']: number = 2; + override uniqueVersionOfGen = GenerateUniqueIntervalV2; +} + +export class GenerateUniqueIntervalV2 extends AbstractGenerator<{ + fields?: + | 'year' + | 'month' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'year to month' + | 'day to hour' + | 'day to minute' + | 'day to second' + | 'hour to minute' + | 'hour to second' + | 'minute to second'; + isUnique?: boolean; +}> { + static override readonly [entityKind]: string = 'GenerateUniqueInterval'; + static override readonly ['version']: number = 2; + + private state: { + rng: prand.RandomGenerator; + fieldsToGenerate: string[]; + intervalSet: Set; + } | undefined; + public override isUnique = true; + private config: { [key: string]: { from: number; to: number } } = { + year: { + from: 0, + to: 5, + }, + month: { + from: 0, + to: 11, + }, + day: { + from: 0, + to: 29, + }, + hour: { + from: 0, + to: 23, + }, + minute: { + from: 0, + to: 59, + }, + second: { + from: 0, + to: 59, + }, + }; + + override init({ count, seed }: { count: number; seed: number }) { + const allFields = ['year', 'month', 'day', 'hour', 'minute', 'second']; + let fieldsToGenerate: string[] = allFields; + + if (this.params.fields !== undefined && this.params.fields?.includes(' to ')) { + const tokens = this.params.fields.split(' to '); + const endIdx = allFields.indexOf(tokens[1]!); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } else if (this.params.fields !== undefined) { + const endIdx = allFields.indexOf(this.params.fields); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } + + let maxUniqueIntervalsNumber = 1; + for (const field of fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + maxUniqueIntervalsNumber *= from - to + 1; + } + + if (count > maxUniqueIntervalsNumber) { + throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`); + } + + const rng = prand.xoroshiro128plus(seed); + const intervalSet = new Set(); + this.state = { rng, fieldsToGenerate, intervalSet }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let interval, numb: number; + + for (;;) { + interval = ''; + + for (const field of this.state.fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + [numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng); + interval += `${numb} ${field} `; + } + + if (!this.state.intervalSet.has(interval)) { + this.state.intervalSet.add(interval); + break; + } + } + + return interval; + } +} + +export class GenerateStringV2 extends AbstractGenerator<{ + isUnique?: boolean; + arraySize?: number; +}> { + static override readonly [entityKind]: string = 'GenerateString'; + static override readonly ['version']: number = 2; + + private state: { + rng: prand.RandomGenerator; + minStringLength: number; + maxStringLength: number; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueStringV2; + + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); + + let minStringLength = 8; + let maxStringLength = 20; + if (this.stringLength !== undefined) { + maxStringLength = this.stringLength; + if (maxStringLength === 1) minStringLength = maxStringLength; + if (maxStringLength < minStringLength) minStringLength = 1; + } + + const rng = prand.xoroshiro128plus(seed); + this.state = { rng, minStringLength, maxStringLength }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const minStringLength = this.state.minStringLength, + maxStringLength = this.state.maxStringLength; + const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let idx: number, + strLength: number, + currStr: string; + + currStr = ''; + [strLength, this.state.rng] = prand.uniformIntDistribution( + minStringLength, + maxStringLength, + this.state.rng, + ); + for (let j = 0; j < strLength; j++) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + stringChars.length - 1, + this.state.rng, + ); + currStr += stringChars[idx]; + } + return currStr; + } +} + +export class GenerateUniqueStringV2 extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly [entityKind]: string = 'GenerateUniqueString'; + static override readonly ['version']: number = 2; + + private state: { + rng: prand.RandomGenerator; + minStringLength: number; + maxStringLength: number; + } | undefined; + public override isUnique = true; + + override init({ seed, count }: { seed: number; count: number }) { + const rng = prand.xoroshiro128plus(seed); + + let minStringLength = 8; + let maxStringLength = 20; + // TODO: revise later + if (this.stringLength !== undefined) { + maxStringLength = this.stringLength; + if (maxStringLength === 1 || maxStringLength < minStringLength) minStringLength = maxStringLength; + } + + if (maxStringLength < count.toString(16).length) { + throw new Error( + `You can't generate ${count} unique strings, with a maximum string length of ${maxStringLength}.`, + ); + } + + this.state = { rng, minStringLength, maxStringLength }; + } + + generate({ i }: { i: number }) { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const minStringLength = this.state.minStringLength, + maxStringLength = this.state.maxStringLength; + const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let idx: number, + strLength: number; + let currStr: string; + + currStr = ''; + const uniqueStr = i.toString(16); + [strLength, this.state.rng] = prand.uniformIntDistribution( + minStringLength, + maxStringLength - uniqueStr.length, + this.state.rng, + ); + for (let j = 0; j < strLength - uniqueStr.length; j++) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + stringChars.length - 1, + this.state.rng, + ); + currStr += stringChars[idx]; + } + + return uniqueStr + currStr; + } +} diff --git a/drizzle-seed/src/services/Generators.ts b/drizzle-seed/src/services/Generators.ts index fa01a1e4f..eb5e256e4 100644 --- a/drizzle-seed/src/services/Generators.ts +++ b/drizzle-seed/src/services/Generators.ts @@ -14,7 +14,8 @@ import states, { maxStringLength as maxStateLength } from '../datasets/states.ts import streetSuffix, { maxStringLength as maxStreetSuffixLength } from '../datasets/streetSuffix.ts'; import { fastCartesianProduct, fillTemplate, getWeightedIndices, isObject } from './utils.ts'; -export const version = 2; +export const latestVersion = 2; +export const version = 1; export abstract class AbstractGenerator { static readonly [entityKind]: string = 'AbstractGenerator'; @@ -1299,84 +1300,27 @@ export class GenerateInterval extends AbstractGenerator<{ } } +// has a newer version export class GenerateUniqueInterval extends AbstractGenerator<{ - fields?: - | 'year' - | 'month' - | 'day' - | 'hour' - | 'minute' - | 'second' - | 'year to month' - | 'day to hour' - | 'day to minute' - | 'day to second' - | 'hour to minute' - | 'hour to second' - | 'minute to second'; isUnique?: boolean; }> { static override readonly [entityKind]: string = 'GenerateUniqueInterval'; private state: { rng: prand.RandomGenerator; - fieldsToGenerate: string[]; intervalSet: Set; } | undefined; public override isUnique = true; - private config: { [key: string]: { from: number; to: number } } = { - year: { - from: 0, - to: 5, - }, - month: { - from: 0, - to: 11, - }, - day: { - from: 1, - to: 29, - }, - hour: { - from: 0, - to: 23, - }, - minute: { - from: 0, - to: 59, - }, - second: { - from: 0, - to: 59, - }, - }; override init({ count, seed }: { count: number; seed: number }) { - const allFields = ['year', 'month', 'day', 'hour', 'minute', 'second']; - let fieldsToGenerate: string[] = allFields; - - if (this.params.fields !== undefined && this.params.fields?.includes(' to ')) { - const tokens = this.params.fields.split(' to '); - const endIdx = allFields.indexOf(tokens[1]!); - fieldsToGenerate = allFields.slice(0, endIdx + 1); - } else if (this.params.fields !== undefined) { - const endIdx = allFields.indexOf(this.params.fields); - fieldsToGenerate = allFields.slice(0, endIdx + 1); - } - - let maxUniqueIntervalsNumber = 1; - for (const field of fieldsToGenerate) { - const from = this.config[field]!.from, to = this.config[field]!.to; - maxUniqueIntervalsNumber *= from - to + 1; - } - + const maxUniqueIntervalsNumber = 6 * 13 * 29 * 25 * 61 * 61; if (count > maxUniqueIntervalsNumber) { throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`); } const rng = prand.xoroshiro128plus(seed); const intervalSet = new Set(); - this.state = { rng, fieldsToGenerate, intervalSet }; + this.state = { rng, intervalSet }; } generate() { @@ -1384,16 +1328,29 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ throw new Error('state is not defined.'); } - let interval, numb: number; + let yearsNumb: number, + monthsNumb: number, + daysNumb: number, + hoursNumb: number, + minutesNumb: number, + secondsNumb: number; - for (;;) { - interval = ''; + let interval = ''; - for (const field of this.state.fieldsToGenerate) { - const from = this.config[field]!.from, to = this.config[field]!.to; - [numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng); - interval += `${numb} ${field} `; - } + for (;;) { + [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); + [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); + [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); + [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); + [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); + + interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` + + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` + + `${daysNumb === 0 ? '' : `${daysNumb} days `}` + + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` + + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` + + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; if (!this.state.intervalSet.has(interval)) { this.state.intervalSet.add(interval); @@ -1405,32 +1362,21 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ } } +// has a newer version export class GenerateString extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { static override readonly [entityKind]: string = 'GenerateString'; - private state: { - rng: prand.RandomGenerator; - minStringLength: number; - maxStringLength: number; - } | undefined; + private state: { rng: prand.RandomGenerator } | undefined; override uniqueVersionOfGen = GenerateUniqueString; override init({ count, seed }: { count: number; seed: number }) { super.init({ count, seed }); - let minStringLength = 8; - let maxStringLength = 20; - if (this.stringLength !== undefined) { - maxStringLength = this.stringLength; - if (maxStringLength === 1) minStringLength = maxStringLength; - if (maxStringLength < minStringLength) minStringLength = 1; - } - const rng = prand.xoroshiro128plus(seed); - this.state = { rng, minStringLength, maxStringLength }; + this.state = { rng }; } generate() { @@ -1438,8 +1384,8 @@ export class GenerateString extends AbstractGenerator<{ throw new Error('state is not defined.'); } - const minStringLength = this.state.minStringLength, - maxStringLength = this.state.maxStringLength; + const minStringLength = 7; + const maxStringLength = 20; const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; let idx: number, strLength: number, @@ -1463,34 +1409,16 @@ export class GenerateString extends AbstractGenerator<{ } } +// has a newer version export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean }> { static override readonly [entityKind]: string = 'GenerateUniqueString'; - private state: { - rng: prand.RandomGenerator; - minStringLength: number; - maxStringLength: number; - } | undefined; + private state: { rng: prand.RandomGenerator } | undefined; public override isUnique = true; - override init({ seed, count }: { seed: number; count: number }) { + override init({ seed }: { seed: number }) { const rng = prand.xoroshiro128plus(seed); - - let minStringLength = 8; - let maxStringLength = 20; - // TODO: revise later - if (this.stringLength !== undefined) { - maxStringLength = this.stringLength; - if (maxStringLength === 1 || maxStringLength < minStringLength) minStringLength = maxStringLength; - } - - if (maxStringLength < count.toString(16).length) { - throw new Error( - `You can't generate ${count} unique strings, with a maximum string length of ${maxStringLength}.`, - ); - } - - this.state = { rng, minStringLength, maxStringLength }; + this.state = { rng }; } generate({ i }: { i: number }) { @@ -1498,8 +1426,8 @@ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean throw new Error('state is not defined.'); } - const minStringLength = this.state.minStringLength, - maxStringLength = this.state.maxStringLength; + const minStringLength = 7; + const maxStringLength = 20; const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; let idx: number, strLength: number; @@ -1521,7 +1449,7 @@ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean currStr += stringChars[idx]; } - return uniqueStr + currStr; + return currStr.slice(0, 4) + uniqueStr + currStr.slice(4); } } diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 6ceae5167..b55736e4d 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -15,7 +15,7 @@ import type { Column, Prettify, Relation, Table } from '../types/tables.ts'; import type { AbstractGenerator } from './Generators.ts'; import * as Generators from './Generators.ts'; -import * as GeneratorsV1 from './GeneratorVersions/GeneratorsV1.ts'; +import * as GeneratorsV2 from './GeneratorVersions/GeneratorsV2.ts'; import { equalSets, generateHashFromString } from './utils.ts'; export class SeedService { @@ -39,10 +39,12 @@ export class SeedService { let columnPossibleGenerator: Prettify; let tablePossibleGenerators: Prettify; const customSeed = options?.seed === undefined ? 0 : options.seed; - const version = options?.version === undefined ? Generators.version : options.version; + const version = options?.version === undefined ? Generators.latestVersion : options.version; + if (version < Generators.version || version > Generators.latestVersion) { + throw new Error(`Version should be in range [${Generators.version}, ${Generators.latestVersion}].`); + } // sorting table in order which they will be filled up (tables with foreign keys case) - // relations = relations.filter(rel => rel.type === "one"); const { tablesInOutRelations } = this.getInfoFromRelations(relations); const orderedTablesNames = this.getOrderedTablesList(tablesInOutRelations); tables = tables.sort((table1, table2) => { @@ -416,22 +418,20 @@ export class SeedService { }; selectGeneratorOfVersion = (version: number, generatorEntityKind: string) => { - const GeneratorVersions = [Generators, GeneratorsV1]; + const GeneratorVersions = [GeneratorsV2, Generators]; type GeneratorConstructorT = new(params: any) => AbstractGenerator; let generatorConstructor: GeneratorConstructorT | undefined; for (const gens of GeneratorVersions) { const { version: gensVersion, ...filteredGens } = gens; - if (version > gensVersion) break; + if (gensVersion > version) continue; for (const gen of Object.values(filteredGens)) { const abstractGen = gen as typeof AbstractGenerator; if (abstractGen[entityKind] === generatorEntityKind) { generatorConstructor = abstractGen as unknown as GeneratorConstructorT; - if (abstractGen.version === version) { - return generatorConstructor; - } + return generatorConstructor; } } } From db33c875c09f955403e11a2568654053ca6fe74d Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Thu, 19 Dec 2024 15:09:56 +0200 Subject: [PATCH 457/492] updated changelogs --- changelogs/drizzle-seed/0.1.4.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/changelogs/drizzle-seed/0.1.4.md b/changelogs/drizzle-seed/0.1.4.md index 84c3821af..9d3c0a5e2 100644 --- a/changelogs/drizzle-seed/0.1.4.md +++ b/changelogs/drizzle-seed/0.1.4.md @@ -8,24 +8,24 @@ await seed(db, schema, { version: 1 }); Generator versions will change within a single major version of drizzle-seed. -The old version of the generator will become available if the generator has been changed and the output of the new generator does not match the output of the old generator. +The new version of the generator will become available if the generator has been changed and the output of the new generator does not match the output of the old generator. #### For example: -`FirstNameGen` was changed, and old version, `V1`, of this generator became available. +`LastNameGen` was changed, and new version, `V2`, of this generator became available. -Later, `LastNameGen` was changed in the next minor version of drizzle-seed, making `V2` version of this generator available. +Later, `FirstNameGen` was changed in the next minor version of drizzle-seed, making `V3` version of this generator available. | | `V1` | `V2` | `V3(latest)` | | :--------------: | :--------------: | :-------------: | :--------------: | -| **FirstNameGen** | `FirstNameGenV1` | `same as V3` | `FirstNameGenV3` | -| **LastNameGen** | `same as V2` | `LastNameGenV2` | `LastNameGenV3` | +| **LastNameGen** | `LastNameGenV1` | `LastNameGenV2` | | +| **FirstNameGen** | `FirstNameGenV1` | | `FirstNameGenV3` | -If you omit version, `V3` version of generators will be used. +If you omit version, latest version of generators(`V3`) will be used: `FirstNameGen` will use its `V3` version, and `LastNameGen` will use its `V2` version. -If you specify version of 2, `FirstNameGen` will use its `V3` version and `LastNameGen` will use its `V2` version. +If you specify version of 2, `FirstNameGen` will use its `V1` version and `LastNameGen` will use its `V2` version. -If you specify version of 1, `FirstNameGen` will use its `V1` version and `LastNameGen` will use its `V2` version. +If you specify version of 1, `FirstNameGen` will use its `V1` version and `LastNameGen` will use its `V1` version. ## @@ -87,7 +87,7 @@ main(); ## Breaking changes -- Unique `interval` generator was changed, so `1` version of this generator become available. **The latest version is `2`.** +- Unique `interval` generator was changed, so `2` version of this generator become available. **The latest version is `2`.** **Cause:** @@ -98,7 +98,7 @@ However, after inserting the `1 minute 60 second` interval, PostgreSQL database ## -- Both non-unique and unique `string` generators were changed, making version `1` of these generators available. **The latest version is `2`.** +- Both non-unique and unique `string` generators were changed, making version `2` of these generators available. **The latest version is `2`.** **Cause:** From 88bfe72fbf3db73bdc57cd0e4531a8063ceaff7d Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Fri, 20 Dec 2024 11:17:38 +0200 Subject: [PATCH 458/492] Review --- .../drizzle-seed/{0.1.4.md => 0.2.0.md} | 43 ++++++++++----- drizzle-seed/src/services/GeneratorFuncs.ts | 53 ++++++++++++++++++- drizzle-seed/src/services/Generators.ts | 5 +- drizzle-seed/src/services/SeedService.ts | 22 ++++---- drizzle-seed/src/services/apiVersion.ts | 1 + .../GeneratorsV2.ts => versioning/v2.ts} | 10 ++-- 6 files changed, 99 insertions(+), 35 deletions(-) rename changelogs/drizzle-seed/{0.1.4.md => 0.2.0.md} (63%) create mode 100644 drizzle-seed/src/services/apiVersion.ts rename drizzle-seed/src/services/{GeneratorVersions/GeneratorsV2.ts => versioning/v2.ts} (96%) diff --git a/changelogs/drizzle-seed/0.1.4.md b/changelogs/drizzle-seed/0.2.0.md similarity index 63% rename from changelogs/drizzle-seed/0.1.4.md rename to changelogs/drizzle-seed/0.2.0.md index 9d3c0a5e2..be19a8949 100644 --- a/changelogs/drizzle-seed/0.1.4.md +++ b/changelogs/drizzle-seed/0.2.0.md @@ -1,33 +1,50 @@ -## Improvements +## API updates -- A new parameter, `version`, was added to the `seed` function options, which will control generator versioning. +We are introducing a new parameter, `version`, to the `seed` function options. This parameter, which controls generator versioning, has been added to make it easier to update deterministic generators in the future. Since values should remain consistent after each regeneration, it is crucial to provide a well-designed API for gradual updates ```ts -await seed(db, schema, { version: 1 }); +await seed(db, schema, { version: 2 }); ``` -Generator versions will change within a single major version of drizzle-seed. +#### Example: -The new version of the generator will become available if the generator has been changed and the output of the new generator does not match the output of the old generator. +> This is not an actual API change; it is just an example of how we will proceed with `drizzle-seed` versioning -#### For example: +For example, `lastName` generator was changed, and new version, `V2`, of this generator became available. -`LastNameGen` was changed, and new version, `V2`, of this generator became available. - -Later, `FirstNameGen` was changed in the next minor version of drizzle-seed, making `V3` version of this generator available. +Later, `firstName` generator was changed, making `V3` version of this generator available. | | `V1` | `V2` | `V3(latest)` | | :--------------: | :--------------: | :-------------: | :--------------: | | **LastNameGen** | `LastNameGenV1` | `LastNameGenV2` | | | **FirstNameGen** | `FirstNameGenV1` | | `FirstNameGenV3` | -If you omit version, latest version of generators(`V3`) will be used: `FirstNameGen` will use its `V3` version, and `LastNameGen` will use its `V2` version. -If you specify version of 2, `FirstNameGen` will use its `V1` version and `LastNameGen` will use its `V2` version. +##### Use the `firstName` generator of version 3 and the `lastName` generator of version 2 +```ts +await seed(db, schema); +``` -If you specify version of 1, `FirstNameGen` will use its `V1` version and `LastNameGen` will use its `V1` version. +If you are not ready to use latest generator version right away, you can specify max version to use -## +##### Use the `firstName` generator of version 1 and the `lastName` generator of version 2 +```ts +await seed(db, schema, { version: '2' }); +``` + +##### Use the `firstName` generator of version 1 and the `lastName` generator of version 1. +```ts +await seed(db, schema, { version: '1' }); +``` + +Each update with breaking changes for generators will be documented on our docs and in release notes, explaining which version you should use, if you are not ready to upgrade the way generators works + +## Breaking changes + +### `interval` unique generator was changed and upgraded to v2 +### `string` generators were changed and upgraded to v2 + +## New Features - added `fields` as new parameter in `interval` generator diff --git a/drizzle-seed/src/services/GeneratorFuncs.ts b/drizzle-seed/src/services/GeneratorFuncs.ts index 65e31fc09..2810134f0 100644 --- a/drizzle-seed/src/services/GeneratorFuncs.ts +++ b/drizzle-seed/src/services/GeneratorFuncs.ts @@ -31,7 +31,7 @@ import { GenerateYear, WeightedRandomGenerator, } from './Generators.ts'; -import { GenerateStringV2 } from './GeneratorVersions/GeneratorsV2.ts'; +import { GenerateStringV2 } from './versioning/v2.ts'; function createGenerator, T>( generatorConstructor: new(params: T) => GeneratorType, @@ -735,3 +735,54 @@ export const generatorsFuncs = { */ weightedRandom: createGenerator(WeightedRandomGenerator), }; + +export const generatorsList: (new(params: any) => AbstractGenerator)[] = [ + GenerateBoolean, + GenerateCity, + GenerateCompanyName, + GenerateCountry, + GenerateDate, + GenerateDatetime, + GenerateDefault, + GenerateEmail, + GenerateFirstName, + GenerateFullName, + GenerateInt, + GenerateInterval, + GenerateIntPrimaryKey, + GenerateJobTitle, + GenerateJson, + GenerateLastName, + GenerateLine, + GenerateLoremIpsum, + GenerateNumber, + GeneratePhoneNumber, + GeneratePoint, + GeneratePostcode, + GenerateState, + GenerateStreetAdddress, + GenerateTime, + GenerateTimestamp, + GenerateUUID, + GenerateValuesFromArray, + GenerateYear, + WeightedRandomGenerator, +]; + +// +const generatorsObj = { + [entityKind]: [ + GenerateStreetAdddress, + GenerateUUID, + ], + [entityKind]: [ + GenerateVarchar, + GenerateVarcharV2, + GenerateVarcharV3, + ], + [entityKind]: [ + GenerateVarchar, + GenerateVarcharV2, + GenerateVarcharV3, + ], +}; diff --git a/drizzle-seed/src/services/Generators.ts b/drizzle-seed/src/services/Generators.ts index eb5e256e4..629aff5a3 100644 --- a/drizzle-seed/src/services/Generators.ts +++ b/drizzle-seed/src/services/Generators.ts @@ -14,12 +14,9 @@ import states, { maxStringLength as maxStateLength } from '../datasets/states.ts import streetSuffix, { maxStringLength as maxStreetSuffixLength } from '../datasets/streetSuffix.ts'; import { fastCartesianProduct, fillTemplate, getWeightedIndices, isObject } from './utils.ts'; -export const latestVersion = 2; -export const version = 1; - export abstract class AbstractGenerator { static readonly [entityKind]: string = 'AbstractGenerator'; - static readonly ['version']: number = 2; + static readonly version: number = 1; public isUnique = false; public notNull = false; diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index b55736e4d..4ba30ed11 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -14,9 +14,10 @@ import type { import type { Column, Prettify, Relation, Table } from '../types/tables.ts'; import type { AbstractGenerator } from './Generators.ts'; -import * as Generators from './Generators.ts'; -import * as GeneratorsV2 from './GeneratorVersions/GeneratorsV2.ts'; +import { latestVersion } from './apiVersion.ts'; +// import * as Generators from './Generators.ts'; import { equalSets, generateHashFromString } from './utils.ts'; +import * as GeneratorsV2 from './versioning/v2.ts'; export class SeedService { static readonly [entityKind]: string = 'SeedService'; @@ -39,9 +40,9 @@ export class SeedService { let columnPossibleGenerator: Prettify; let tablePossibleGenerators: Prettify; const customSeed = options?.seed === undefined ? 0 : options.seed; - const version = options?.version === undefined ? Generators.latestVersion : options.version; - if (version < Generators.version || version > Generators.latestVersion) { - throw new Error(`Version should be in range [${Generators.version}, ${Generators.latestVersion}].`); + const version = options?.version === undefined ? latestVersion : options.version; + if (version < 1 || version > latestVersion) { + throw new Error(`Version should be in range [1, ${latestVersion}].`); } // sorting table in order which they will be filled up (tables with foreign keys case) @@ -248,6 +249,8 @@ export class SeedService { ); } + // check if new version exists + columnPossibleGenerator.generator.isUnique = col.isUnique; columnPossibleGenerator.generator.dataType = col.dataType; columnPossibleGenerator.generator.stringLength = col.typeParams.length; @@ -418,15 +421,12 @@ export class SeedService { }; selectGeneratorOfVersion = (version: number, generatorEntityKind: string) => { - const GeneratorVersions = [GeneratorsV2, Generators]; - type GeneratorConstructorT = new(params: any) => AbstractGenerator; + const GeneratorVersions = [...Object.values(GeneratorsV2), ...Object.values(Generators)]; + let generatorConstructor: GeneratorConstructorT | undefined; for (const gens of GeneratorVersions) { - const { version: gensVersion, ...filteredGens } = gens; - if (gensVersion > version) continue; - - for (const gen of Object.values(filteredGens)) { + for (const gen of Object.values(gens)) { const abstractGen = gen as typeof AbstractGenerator; if (abstractGen[entityKind] === generatorEntityKind) { generatorConstructor = abstractGen as unknown as GeneratorConstructorT; diff --git a/drizzle-seed/src/services/apiVersion.ts b/drizzle-seed/src/services/apiVersion.ts new file mode 100644 index 000000000..6cda0267e --- /dev/null +++ b/drizzle-seed/src/services/apiVersion.ts @@ -0,0 +1 @@ +export const latestVersion = 2; diff --git a/drizzle-seed/src/services/GeneratorVersions/GeneratorsV2.ts b/drizzle-seed/src/services/versioning/v2.ts similarity index 96% rename from drizzle-seed/src/services/GeneratorVersions/GeneratorsV2.ts rename to drizzle-seed/src/services/versioning/v2.ts index daedcdc98..96451b2f8 100644 --- a/drizzle-seed/src/services/GeneratorVersions/GeneratorsV2.ts +++ b/drizzle-seed/src/services/versioning/v2.ts @@ -2,11 +2,9 @@ import { entityKind } from 'drizzle-orm'; import prand from 'pure-rand'; import { AbstractGenerator, GenerateInterval } from '../Generators.ts'; -export const version = 2; - export class GenerateIntervalV2 extends GenerateInterval { static override readonly [entityKind]: string = 'GenerateInterval'; - static override readonly ['version']: number = 2; + override readonly version: number = 2; override uniqueVersionOfGen = GenerateUniqueIntervalV2; } @@ -28,7 +26,7 @@ export class GenerateUniqueIntervalV2 extends AbstractGenerator<{ isUnique?: boolean; }> { static override readonly [entityKind]: string = 'GenerateUniqueInterval'; - static override readonly ['version']: number = 2; + override readonly version: number = 2; private state: { rng: prand.RandomGenerator; @@ -122,7 +120,7 @@ export class GenerateStringV2 extends AbstractGenerator<{ arraySize?: number; }> { static override readonly [entityKind]: string = 'GenerateString'; - static override readonly ['version']: number = 2; + override readonly version: number = 2; private state: { rng: prand.RandomGenerator; @@ -178,7 +176,7 @@ export class GenerateStringV2 extends AbstractGenerator<{ export class GenerateUniqueStringV2 extends AbstractGenerator<{ isUnique?: boolean }> { static override readonly [entityKind]: string = 'GenerateUniqueString'; - static override readonly ['version']: number = 2; + override readonly version: number = 2; private state: { rng: prand.RandomGenerator; From e11941e086a79b9e1441e6eb5d5bbedc02300c52 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Fri, 20 Dec 2024 11:44:53 +0200 Subject: [PATCH 459/492] changes in generator selection --- drizzle-seed/src/index.ts | 11 +- drizzle-seed/src/services/SeedService.ts | 126 ++++++++++++++--------- 2 files changed, 86 insertions(+), 51 deletions(-) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 248e7ead5..50e40def2 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -570,7 +570,10 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { // might be empty list const newRelations = tableConfig.foreignKeys.map((fk) => { const table = dbToTsTableNamesMap[tableConfig.name] as string; - const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; + const refTableName0 = fk.reference(); + const refTableName1 = refTableName0.foreignTable; + const refTableName2 = getTableName(refTableName1); + const refTable = dbToTsTableNamesMap[refTableName2] as string; const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( fk.reference().foreignTable, @@ -625,7 +628,7 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { }; const getTypeParams = (sqlType: string) => { - // get type params and set only type + // get type params const typeParams: Column['typeParams'] = {}; // handle dimensions @@ -642,7 +645,7 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { || sqlType.startsWith('double precision') || sqlType.startsWith('real') ) { - const match = sqlType.match(/\((\d+),(\d+)\)/); + const match = sqlType.match(/\((\d+), *(\d+)\)/); if (match) { typeParams['precision'] = Number(match[1]); typeParams['scale'] = Number(match[2]); @@ -905,7 +908,7 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { || sqlType.startsWith('double') || sqlType.startsWith('float') ) { - const match = sqlType.match(/\((\d+),(\d+)\)/); + const match = sqlType.match(/\((\d+), *(\d+)\)/); if (match) { typeParams['precision'] = Number(match[1]); typeParams['scale'] = Number(match[2]); diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index b55736e4d..329cc6289 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -461,12 +461,6 @@ export class SeedService { throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); } - // const { generatorConstructor } = this.selectGeneratorOfVersion( - // version, - // Generators.GenerateArray[entityKind], - // ); - - // const generator = new generatorConstructor!({ baseColumnGen, size: col.size }); const generator = new Generators.GenerateArray({ baseColumnGen, size: col.size }); return generator; @@ -569,11 +563,23 @@ export class SeedService { // NUMBER(real, double, decimal, numeric) if ( - col.columnType === 'real' - || col.columnType === 'double precision' - || col.columnType === 'decimal' - || col.columnType === 'numeric' + col.columnType.startsWith('real') + || col.columnType.startsWith('double precision') + || col.columnType.startsWith('decimal') + || col.columnType.startsWith('numeric') ) { + if (col.typeParams.precision !== undefined) { + const precision = col.typeParams.precision; + const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; + + const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); + const generator = new Generators.GenerateNumber({ + minValue: -maxAbsoluteValue, + maxValue: maxAbsoluteValue, + precision: Math.pow(10, scale), + }); + return generator; + } const generator = new Generators.GenerateNumber({}); return generator; @@ -792,11 +798,25 @@ export class SeedService { // NUMBER(real, double, decimal, float) if ( - col.columnType === 'real' - || col.columnType === 'double' - || col.columnType === 'decimal' - || col.columnType === 'float' + col.columnType.startsWith('real') + || col.columnType.startsWith('double') + || col.columnType.startsWith('decimal') + || col.columnType.startsWith('float') + || col.columnType.startsWith('numeric') ) { + if (col.typeParams.precision !== undefined) { + const precision = col.typeParams.precision; + const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; + + const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); + const generator = new Generators.GenerateNumber({ + minValue: -maxAbsoluteValue, + maxValue: maxAbsoluteValue, + precision: Math.pow(10, scale), + }); + return generator; + } + const generator = new Generators.GenerateNumber({}); return generator; } @@ -805,10 +825,10 @@ export class SeedService { if ( (col.columnType === 'text' || col.columnType === 'blob' - || col.columnType.includes('char') - || col.columnType.includes('varchar') - || col.columnType.includes('binary') - || col.columnType.includes('varbinary')) + || col.columnType.startsWith('char') + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('binary') + || col.columnType.startsWith('varbinary')) && table.primaryKeys.includes(col.name) ) { const generator = new Generators.GenerateUniqueString({}); @@ -818,10 +838,10 @@ export class SeedService { if ( (col.columnType === 'text' || col.columnType === 'blob' - || col.columnType.includes('char') - || col.columnType.includes('varchar') - || col.columnType.includes('binary') - || col.columnType.includes('varbinary')) + || col.columnType.startsWith('char') + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('binary') + || col.columnType.startsWith('varbinary')) && col.name.toLowerCase().includes('name') ) { const generator = new Generators.GenerateFirstName({}); @@ -831,10 +851,10 @@ export class SeedService { if ( (col.columnType === 'text' || col.columnType === 'blob' - || col.columnType.includes('char') - || col.columnType.includes('varchar') - || col.columnType.includes('binary') - || col.columnType.includes('varbinary')) + || col.columnType.startsWith('char') + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('binary') + || col.columnType.startsWith('varbinary')) && col.name.toLowerCase().includes('email') ) { const generator = new Generators.GenerateEmail({}); @@ -844,10 +864,10 @@ export class SeedService { if ( col.columnType === 'text' || col.columnType === 'blob' - || col.columnType.includes('char') - || col.columnType.includes('varchar') - || col.columnType.includes('binary') - || col.columnType.includes('varbinary') + || col.columnType.startsWith('char') + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('binary') + || col.columnType.startsWith('varbinary') ) { const generator = new Generators.GenerateString({}); return generator; @@ -949,7 +969,6 @@ export class SeedService { if ( col.columnType === 'integer' - || col.columnType === 'numeric' || (col.dataType === 'bigint' && col.columnType === 'blob') ) { const generator = new Generators.GenerateInt({}); @@ -957,16 +976,29 @@ export class SeedService { } // number section ------------------------------------------------------------------------------------ - if (col.columnType === 'real' || col.columnType === 'numeric') { + if (col.columnType.startsWith('real') || col.columnType.startsWith('numeric')) { + if (col.typeParams.precision !== undefined) { + const precision = col.typeParams.precision; + const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; + + const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); + const generator = new Generators.GenerateNumber({ + minValue: -maxAbsoluteValue, + maxValue: maxAbsoluteValue, + precision: Math.pow(10, scale), + }); + return generator; + } + const generator = new Generators.GenerateNumber({}); return generator; } // string section ------------------------------------------------------------------------------------ if ( - (col.columnType === 'text' - || col.columnType === 'numeric' - || col.columnType === 'blob') + (col.columnType.startsWith('text') + || col.columnType.startsWith('numeric') + || col.columnType.startsWith('blob')) && table.primaryKeys.includes(col.name) ) { const generator = new Generators.GenerateUniqueString({}); @@ -974,9 +1006,9 @@ export class SeedService { } if ( - (col.columnType === 'text' - || col.columnType === 'numeric' - || col.columnType === 'blob') + (col.columnType.startsWith('text') + || col.columnType.startsWith('numeric') + || col.columnType.startsWith('blob')) && col.name.toLowerCase().includes('name') ) { const generator = new Generators.GenerateFirstName({}); @@ -984,9 +1016,9 @@ export class SeedService { } if ( - (col.columnType === 'text' - || col.columnType === 'numeric' - || col.columnType === 'blob') + (col.columnType.startsWith('text') + || col.columnType.startsWith('numeric') + || col.columnType.startsWith('blob')) && col.name.toLowerCase().includes('email') ) { const generator = new Generators.GenerateEmail({}); @@ -994,18 +1026,18 @@ export class SeedService { } if ( - col.columnType === 'text' - || col.columnType === 'numeric' - || col.columnType === 'blob' - || col.columnType === 'blobbuffer' + col.columnType.startsWith('text') + || col.columnType.startsWith('numeric') + || col.columnType.startsWith('blob') + || col.columnType.startsWith('blobbuffer') ) { const generator = new Generators.GenerateString({}); return generator; } if ( - (col.columnType === 'text' && col.dataType === 'json') - || (col.columnType === 'blob' && col.dataType === 'json') + (col.columnType.startsWith('text') && col.dataType === 'json') + || (col.columnType.startsWith('blob') && col.dataType === 'json') ) { const generator = new Generators.GenerateJson({}); return generator; From ec5d35eb459e0330894074889e0fdcd4da091158 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Fri, 20 Dec 2024 20:59:10 +0200 Subject: [PATCH 460/492] updated generator versioning --- drizzle-seed/src/index.ts | 5 +- drizzle-seed/src/services/GeneratorFuncs.ts | 227 +++++++++++--- drizzle-seed/src/services/Generators.ts | 238 ++++++++------ drizzle-seed/src/services/SeedService.ts | 295 +++++++++--------- drizzle-seed/src/services/versioning/v2.ts | 22 +- .../tests/benchmarks/generatorsBenchmark.ts | 8 +- .../tests/pg/allDataTypesTest/pgSchema.ts | 46 +-- 7 files changed, 514 insertions(+), 327 deletions(-) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 50e40def2..48aad2973 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -1,4 +1,5 @@ -import { entityKind, getTableName, is, sql } from 'drizzle-orm'; +/* eslint-disable drizzle-internal/require-entity-kind */ +import { getTableName, is, sql } from 'drizzle-orm'; import type { MySqlColumn, MySqlSchema } from 'drizzle-orm/mysql-core'; import { getTableConfig as getMysqlTableConfig, MySqlDatabase, MySqlTable } from 'drizzle-orm/mysql-core'; @@ -131,7 +132,7 @@ class SeedPromise< [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable; }, > implements Promise { - static readonly [entityKind]: string = 'SeedPromise'; + static readonly entityKind: string = 'SeedPromise'; [Symbol.toStringTag] = 'SeedPromise'; diff --git a/drizzle-seed/src/services/GeneratorFuncs.ts b/drizzle-seed/src/services/GeneratorFuncs.ts index 2810134f0..be715a33b 100644 --- a/drizzle-seed/src/services/GeneratorFuncs.ts +++ b/drizzle-seed/src/services/GeneratorFuncs.ts @@ -1,5 +1,6 @@ import type { AbstractGenerator } from './Generators.ts'; import { + GenerateArray, GenerateBoolean, GenerateCity, GenerateCompanyName, @@ -8,6 +9,7 @@ import { GenerateDatetime, GenerateDefault, GenerateEmail, + GenerateEnum, GenerateFirstName, GenerateFullName, GenerateInt, @@ -22,16 +24,34 @@ import { GeneratePhoneNumber, GeneratePoint, GeneratePostcode, + GenerateSelfRelationsValuesFromArray, GenerateState, - GenerateStreetAdddress, + GenerateStreetAddress, + GenerateString, GenerateTime, GenerateTimestamp, + GenerateUniqueCity, + GenerateUniqueCompanyName, + GenerateUniqueCountry, + GenerateUniqueFirstName, + GenerateUniqueFullName, + GenerateUniqueInt, + GenerateUniqueInterval, + GenerateUniqueLastName, + GenerateUniqueLine, + GenerateUniqueNumber, + GenerateUniquePoint, + GenerateUniquePostcode, + GenerateUniqueStreetAddress, + GenerateUniqueString, GenerateUUID, GenerateValuesFromArray, + GenerateWeightedCount, GenerateYear, + HollowGenerator, WeightedRandomGenerator, } from './Generators.ts'; -import { GenerateStringV2 } from './versioning/v2.ts'; +import { GenerateStringV2, GenerateUniqueIntervalV2, GenerateUniqueStringV2 } from './versioning/v2.ts'; function createGenerator, T>( generatorConstructor: new(params: T) => GeneratorType, @@ -359,7 +379,7 @@ export const generatorsFuncs = { * })); * ``` */ - string: createGenerator(GenerateStringV2), + string: createGenerator(GenerateString), // uniqueString: createGenerator(GenerateUniqueString), /** @@ -550,8 +570,8 @@ export const generatorsFuncs = { * })); * ``` */ - streetAddress: createGenerator(GenerateStreetAdddress), - // uniqueStreetAddress: createGenerator(GenerateUniqueStreetAdddress), + streetAddress: createGenerator(GenerateStreetAddress), + // uniqueStreetAddress: createGenerator(GenerateUniqueStreetAddress), /** * generates job titles. @@ -736,53 +756,162 @@ export const generatorsFuncs = { weightedRandom: createGenerator(WeightedRandomGenerator), }; -export const generatorsList: (new(params: any) => AbstractGenerator)[] = [ - GenerateBoolean, - GenerateCity, - GenerateCompanyName, - GenerateCountry, - GenerateDate, - GenerateDatetime, - GenerateDefault, - GenerateEmail, - GenerateFirstName, - GenerateFullName, - GenerateInt, - GenerateInterval, - GenerateIntPrimaryKey, - GenerateJobTitle, - GenerateJson, - GenerateLastName, - GenerateLine, - GenerateLoremIpsum, - GenerateNumber, - GeneratePhoneNumber, - GeneratePoint, - GeneratePostcode, - GenerateState, - GenerateStreetAdddress, - GenerateTime, - GenerateTimestamp, - GenerateUUID, - GenerateValuesFromArray, - GenerateYear, - WeightedRandomGenerator, -]; +// TODO: revise +// so far, version changes don’t affect generator parameters. +export const generatorsFuncsV2 = { ...generatorsFuncs }; -// -const generatorsObj = { - [entityKind]: [ - GenerateStreetAdddress, +export const generatorsMap = { + HollowGenerator: [ + HollowGenerator, + ], + GenerateDefault: [ + GenerateDefault, + ], + GenerateValuesFromArray: [ + GenerateValuesFromArray, + ], + GenerateSelfRelationsValuesFromArray: [ + GenerateSelfRelationsValuesFromArray, + ], + GenerateIntPrimaryKey: [ + GenerateIntPrimaryKey, + ], + GenerateNumber: [ + GenerateNumber, + ], + GenerateUniqueNumber: [ + GenerateUniqueNumber, + ], + GenerateInt: [ + GenerateInt, + ], + GenerateUniqueInt: [ + GenerateUniqueInt, + ], + GenerateBoolean: [ + GenerateBoolean, + ], + GenerateDate: [ + GenerateDate, + ], + GenerateTime: [ + GenerateTime, + ], + GenerateTimestamp: [ + GenerateTimestamp, + ], + GenerateDatetime: [ + GenerateDatetime, + ], + GenerateYear: [ + GenerateYear, + ], + GenerateJson: [ + GenerateJson, + ], + GenerateEnum: [ + GenerateEnum, + ], + GenerateInterval: [ + GenerateInterval, + ], + GenerateUniqueInterval: [ + GenerateUniqueInterval, + GenerateUniqueIntervalV2, + ], + GenerateString: [ + GenerateString, + GenerateStringV2, + ], + GenerateUniqueString: [ + GenerateUniqueString, + GenerateUniqueStringV2, + ], + GenerateUUID: [ GenerateUUID, ], - [entityKind]: [ - GenerateVarchar, - GenerateVarcharV2, - GenerateVarcharV3, + GenerateFirstName: [ + GenerateFirstName, + ], + GenerateUniqueFirstName: [ + GenerateUniqueFirstName, + ], + GenerateLastName: [ + GenerateLastName, + ], + GenerateUniqueLastName: [ + GenerateUniqueLastName, + ], + GenerateFullName: [ + GenerateFullName, + ], + GenerateUniqueFullName: [ + GenerateUniqueFullName, + ], + GenerateEmail: [ + GenerateEmail, + ], + GeneratePhoneNumber: [ + GeneratePhoneNumber, + ], + GenerateCountry: [ + GenerateCountry, + ], + GenerateUniqueCountry: [ + GenerateUniqueCountry, + ], + GenerateCity: [ + GenerateCity, + ], + GenerateUniqueCity: [ + GenerateUniqueCity, + ], + GenerateStreetAddress: [ + GenerateStreetAddress, + ], + GenerateUniqueStreetAddress: [ + GenerateUniqueStreetAddress, + ], + GenerateJobTitle: [ + GenerateJobTitle, + ], + GeneratePostcode: [ + GeneratePostcode, + ], + GenerateUniquePostcode: [ + GenerateUniquePostcode, + ], + GenerateState: [ + GenerateState, + ], + GenerateCompanyName: [ + GenerateCompanyName, + ], + GenerateUniqueCompanyName: [ + GenerateUniqueCompanyName, + ], + GenerateLoremIpsum: [ + GenerateLoremIpsum, + ], + GeneratePoint: [ + GeneratePoint, + ], + GenerateUniquePoint: [ + GenerateUniquePoint, + ], + GenerateLine: [ + GenerateLine, + ], + GenerateUniqueLine: [ + GenerateUniqueLine, + ], + WeightedRandomGenerator: [ + WeightedRandomGenerator, + ], + GenerateArray: [ + GenerateArray, ], - [entityKind]: [ - GenerateVarchar, - GenerateVarcharV2, - GenerateVarcharV3, + GenerateWeightedCount: [ + GenerateWeightedCount, ], }; diff --git a/drizzle-seed/src/services/Generators.ts b/drizzle-seed/src/services/Generators.ts index 629aff5a3..fff543739 100644 --- a/drizzle-seed/src/services/Generators.ts +++ b/drizzle-seed/src/services/Generators.ts @@ -1,4 +1,4 @@ -import { entityKind } from 'drizzle-orm'; +/* eslint-disable drizzle-internal/require-entity-kind */ import prand from 'pure-rand'; import adjectives, { maxStringLength as maxAdjectiveLength } from '../datasets/adjectives.ts'; import cityNames, { maxStringLength as maxCityNameLength } from '../datasets/cityNames.ts'; @@ -15,22 +15,39 @@ import streetSuffix, { maxStringLength as maxStreetSuffixLength } from '../datas import { fastCartesianProduct, fillTemplate, getWeightedIndices, isObject } from './utils.ts'; export abstract class AbstractGenerator { - static readonly [entityKind]: string = 'AbstractGenerator'; + static readonly entityKind: string = 'AbstractGenerator'; static readonly version: number = 1; public isUnique = false; public notNull = false; + + // param for generators which have a unique version of themselves public uniqueVersionOfGen?: new(params: T) => AbstractGenerator; + public dataType?: string; public timeSpent?: number; + + // public arraySize?: number; public baseColumnDataType?: string; + + // param for text-like generators public stringLength?: number; + // params for GenerateValuesFromArray + public weightedCountSeed?: number | undefined; + public maxRepeatedValuesCount?: number | { weight: number; count: number | number[] }[] | undefined; + + // param for GenerateIntP + constructor(public params: T) {} init(params: { count: number | { weight: number; count: number | number[] }[]; seed: number }): void; init() { + this.updateParams(); + } + + updateParams() { if ((this.params as any).arraySize !== undefined) { this.arraySize = (this.params as any).arraySize; } @@ -48,10 +65,11 @@ export abstract class AbstractGenerator { getEntityKind(): string { const constructor = this.constructor as typeof AbstractGenerator; - return constructor[entityKind]; + return constructor.entityKind; } - replaceIfUnique({ count, seed }: { count: number; seed: number }) { + replaceIfUnique() { + this.updateParams(); if ( this.uniqueVersionOfGen !== undefined && this.isUnique === true @@ -59,10 +77,7 @@ export abstract class AbstractGenerator { const uniqueGen = new this.uniqueVersionOfGen({ ...this.params, }); - uniqueGen.init({ - count, - seed, - }); + uniqueGen.isUnique = this.isUnique; uniqueGen.dataType = this.dataType; @@ -71,9 +86,10 @@ export abstract class AbstractGenerator { return; } - replaceIfArray({ count, seed }: { count: number; seed: number }) { + replaceIfArray() { + this.updateParams(); if (!(this.getEntityKind() === 'GenerateArray') && this.arraySize !== undefined) { - const uniqueGen = this.replaceIfUnique({ count, seed }); + const uniqueGen = this.replaceIfUnique(); const baseColumnGen = uniqueGen === undefined ? this : uniqueGen; baseColumnGen.dataType = this.baseColumnDataType; const arrayGen = new GenerateArray( @@ -82,7 +98,6 @@ export abstract class AbstractGenerator { size: this.arraySize, }, ); - arrayGen.init({ count, seed }); return arrayGen; } @@ -93,7 +108,7 @@ export abstract class AbstractGenerator { // Generators Classes ----------------------------------------------------------------------------------------------------------------------- export class GenerateArray extends AbstractGenerator<{ baseColumnGen: AbstractGenerator; size?: number }> { - static override readonly [entityKind]: string = 'GenerateArray'; + static override readonly entityKind: string = 'GenerateArray'; public override arraySize = 10; override init({ count, seed }: { count: number; seed: number }) { @@ -113,7 +128,7 @@ export class GenerateArray extends AbstractGenerator<{ baseColumnGen: AbstractGe } export class GenerateWeightedCount extends AbstractGenerator<{}> { - static override readonly [entityKind]: string = 'GenerateWeightedCount'; + static override readonly entityKind: string = 'GenerateWeightedCount'; private state: { rng: prand.RandomGenerator; @@ -151,7 +166,7 @@ export class GenerateWeightedCount extends AbstractGenerator<{}> { } export class HollowGenerator extends AbstractGenerator<{}> { - static override readonly [entityKind]: string = 'HollowGenerator'; + static override readonly entityKind: string = 'HollowGenerator'; override init() {} @@ -162,7 +177,7 @@ export class GenerateDefault extends AbstractGenerator<{ defaultValue: unknown; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateDefault'; + static override readonly entityKind: string = 'GenerateDefault'; generate() { return this.params.defaultValue; @@ -178,10 +193,8 @@ export class GenerateValuesFromArray extends AbstractGenerator< arraySize?: number; } > { - static override readonly [entityKind]: string = 'GenerateValuesFromArray'; + static override readonly entityKind: string = 'GenerateValuesFromArray'; - public weightedCountSeed: number | undefined = undefined; - public maxRepeatedValuesCount?: number | { weight: number; count: number | number[] }[] = undefined; private state: { rng: prand.RandomGenerator; values: @@ -389,7 +402,7 @@ export class GenerateValuesFromArray extends AbstractGenerator< } export class GenerateSelfRelationsValuesFromArray extends AbstractGenerator<{ values: (number | string | boolean)[] }> { - static override readonly [entityKind]: string = 'GenerateSelfRelationsValuesFromArray'; + static override readonly entityKind: string = 'GenerateSelfRelationsValuesFromArray'; private state: { rng: prand.RandomGenerator; @@ -427,7 +440,7 @@ export class GenerateSelfRelationsValuesFromArray extends AbstractGenerator<{ va } export class GenerateIntPrimaryKey extends AbstractGenerator<{}> { - static override readonly [entityKind]: string = 'GenerateIntPrimaryKey'; + static override readonly entityKind: string = 'GenerateIntPrimaryKey'; public maxValue?: number | bigint; @@ -455,7 +468,7 @@ export class GenerateNumber extends AbstractGenerator< arraySize?: number; } > { - static override readonly [entityKind]: string = 'GenerateNumber'; + static override readonly entityKind: string = 'GenerateNumber'; private state: { rng: prand.RandomGenerator; @@ -510,7 +523,7 @@ export class GenerateUniqueNumber extends AbstractGenerator< isUnique?: boolean; } > { - static override readonly [entityKind]: string = 'GenerateUniqueNumber'; + static override readonly entityKind: string = 'GenerateUniqueNumber'; private state: { genUniqueIntObj: GenerateUniqueInt; @@ -562,7 +575,7 @@ export class GenerateInt extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateInt'; + static override readonly entityKind: string = 'GenerateInt'; private state: { rng: prand.RandomGenerator; @@ -630,7 +643,7 @@ export class GenerateUniqueInt extends AbstractGenerator<{ maxValue?: number | bigint; isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniqueInt'; + static override readonly entityKind: string = 'GenerateUniqueInt'; public genMaxRepeatedValuesCount: GenerateDefault | GenerateWeightedCount | undefined; public skipCheck?: boolean = false; @@ -798,7 +811,7 @@ export class GenerateUniqueInt extends AbstractGenerator<{ } export class GenerateBoolean extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateBoolean'; + static override readonly entityKind: string = 'GenerateBoolean'; private state: { rng: prand.RandomGenerator; @@ -829,7 +842,7 @@ export class GenerateDate extends AbstractGenerator<{ maxDate?: string | Date; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateDate'; + static override readonly entityKind: string = 'GenerateDate'; private state: { rng: prand.RandomGenerator; @@ -891,7 +904,7 @@ export class GenerateDate extends AbstractGenerator<{ } } export class GenerateTime extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateTime'; + static override readonly entityKind: string = 'GenerateTime'; private state: { rng: prand.RandomGenerator; @@ -927,7 +940,7 @@ export class GenerateTime extends AbstractGenerator<{ arraySize?: number }> { } } export class GenerateTimestampInt extends AbstractGenerator<{ unitOfTime?: 'seconds' | 'milliseconds' }> { - static override readonly [entityKind]: string = 'GenerateTimestampInt'; + static override readonly entityKind: string = 'GenerateTimestampInt'; private state: { generateTimestampObj: GenerateTimestamp; @@ -960,7 +973,7 @@ export class GenerateTimestampInt extends AbstractGenerator<{ unitOfTime?: 'seco } export class GenerateTimestamp extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateTimestamp'; + static override readonly entityKind: string = 'GenerateTimestamp'; private state: { rng: prand.RandomGenerator; @@ -1004,7 +1017,7 @@ export class GenerateTimestamp extends AbstractGenerator<{ arraySize?: number }> } export class GenerateDatetime extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateDatetime'; + static override readonly entityKind: string = 'GenerateDatetime'; private state: { rng: prand.RandomGenerator; @@ -1048,7 +1061,7 @@ export class GenerateDatetime extends AbstractGenerator<{ arraySize?: number }> } export class GenerateYear extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateYear'; + static override readonly entityKind: string = 'GenerateYear'; private state: { rng: prand.RandomGenerator; @@ -1083,7 +1096,7 @@ export class GenerateYear extends AbstractGenerator<{ arraySize?: number }> { } export class GenerateJson extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateJson'; + static override readonly entityKind: string = 'GenerateJson'; private state: { emailGeneratorObj: GenerateEmail; @@ -1187,7 +1200,7 @@ export class GenerateJson extends AbstractGenerator<{ arraySize?: number }> { } export class GenerateEnum extends AbstractGenerator<{ enumValues: (string | number | boolean)[] }> { - static override readonly [entityKind]: string = 'GenerateEnum'; + static override readonly entityKind: string = 'GenerateEnum'; private state: { enumValuesGenerator: GenerateValuesFromArray; @@ -1227,7 +1240,7 @@ export class GenerateInterval extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateInterval'; + static override readonly entityKind: string = 'GenerateInterval'; private state: { rng: prand.RandomGenerator; @@ -1299,25 +1312,83 @@ export class GenerateInterval extends AbstractGenerator<{ // has a newer version export class GenerateUniqueInterval extends AbstractGenerator<{ + fields?: + | 'year' + | 'month' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'year to month' + | 'day to hour' + | 'day to minute' + | 'day to second' + | 'hour to minute' + | 'hour to second' + | 'minute to second'; isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniqueInterval'; + static override readonly 'entityKind': string = 'GenerateUniqueInterval'; private state: { rng: prand.RandomGenerator; + fieldsToGenerate: string[]; intervalSet: Set; } | undefined; public override isUnique = true; + private config: { [key: string]: { from: number; to: number } } = { + year: { + from: 0, + to: 5, + }, + month: { + from: 0, + to: 12, + }, + day: { + from: 1, + to: 29, + }, + hour: { + from: 0, + to: 24, + }, + minute: { + from: 0, + to: 60, + }, + second: { + from: 0, + to: 60, + }, + }; override init({ count, seed }: { count: number; seed: number }) { - const maxUniqueIntervalsNumber = 6 * 13 * 29 * 25 * 61 * 61; + const allFields = ['year', 'month', 'day', 'hour', 'minute', 'second']; + let fieldsToGenerate: string[] = allFields; + + if (this.params.fields !== undefined && this.params.fields?.includes(' to ')) { + const tokens = this.params.fields.split(' to '); + const endIdx = allFields.indexOf(tokens[1]!); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } else if (this.params.fields !== undefined) { + const endIdx = allFields.indexOf(this.params.fields); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } + + let maxUniqueIntervalsNumber = 1; + for (const field of fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + maxUniqueIntervalsNumber *= from - to + 1; + } + if (count > maxUniqueIntervalsNumber) { throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`); } const rng = prand.xoroshiro128plus(seed); const intervalSet = new Set(); - this.state = { rng, intervalSet }; + this.state = { rng, fieldsToGenerate, intervalSet }; } generate() { @@ -1325,29 +1396,16 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ throw new Error('state is not defined.'); } - let yearsNumb: number, - monthsNumb: number, - daysNumb: number, - hoursNumb: number, - minutesNumb: number, - secondsNumb: number; - - let interval = ''; + let interval, numb: number; for (;;) { - [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); - [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); - [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); - [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); - [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - - interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` - + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` - + `${daysNumb === 0 ? '' : `${daysNumb} days `}` - + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` - + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` - + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; + interval = ''; + + for (const field of this.state.fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + [numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng); + interval += `${numb} ${field} `; + } if (!this.state.intervalSet.has(interval)) { this.state.intervalSet.add(interval); @@ -1364,7 +1422,7 @@ export class GenerateString extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateString'; + static override readonly entityKind: string = 'GenerateString'; private state: { rng: prand.RandomGenerator } | undefined; override uniqueVersionOfGen = GenerateUniqueString; @@ -1408,7 +1466,7 @@ export class GenerateString extends AbstractGenerator<{ // has a newer version export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueString'; + static override readonly entityKind: string = 'GenerateUniqueString'; private state: { rng: prand.RandomGenerator } | undefined; public override isUnique = true; @@ -1453,7 +1511,7 @@ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean export class GenerateUUID extends AbstractGenerator<{ arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateUUID'; + static override readonly entityKind: string = 'GenerateUUID'; public override isUnique = true; @@ -1500,7 +1558,7 @@ export class GenerateFirstName extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateFirstName'; + static override readonly entityKind: string = 'GenerateFirstName'; override timeSpent: number = 0; private state: { @@ -1539,7 +1597,7 @@ export class GenerateFirstName extends AbstractGenerator<{ export class GenerateUniqueFirstName extends AbstractGenerator<{ isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniqueFirstName'; + static override readonly entityKind: string = 'GenerateUniqueFirstName'; private state: { genIndicesObj: GenerateUniqueInt; @@ -1580,7 +1638,7 @@ export class GenerateLastName extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateLastName'; + static override readonly entityKind: string = 'GenerateLastName'; private state: { rng: prand.RandomGenerator; @@ -1613,7 +1671,7 @@ export class GenerateLastName extends AbstractGenerator<{ } export class GenerateUniqueLastName extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueLastName'; + static override readonly entityKind: string = 'GenerateUniqueLastName'; private state: { genIndicesObj: GenerateUniqueInt; @@ -1653,7 +1711,7 @@ export class GenerateFullName extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateFullName'; + static override readonly entityKind: string = 'GenerateFullName'; private state: { rng: prand.RandomGenerator; @@ -1698,7 +1756,7 @@ export class GenerateFullName extends AbstractGenerator<{ export class GenerateUniqueFullName extends AbstractGenerator<{ isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniqueFullName'; + static override readonly entityKind: string = 'GenerateUniqueFullName'; private state: { fullnameSet: Set; @@ -1763,7 +1821,7 @@ export class GenerateUniqueFullName extends AbstractGenerator<{ export class GenerateEmail extends AbstractGenerator<{ arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateEmail'; + static override readonly entityKind: string = 'GenerateEmail'; private state: { genIndicesObj: GenerateUniqueInt; @@ -1830,7 +1888,7 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ generatedDigitsNumbers?: number | number[]; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GeneratePhoneNumber'; + static override readonly entityKind: string = 'GeneratePhoneNumber'; private state: { rng: prand.RandomGenerator; @@ -2024,7 +2082,7 @@ export class GenerateCountry extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateCountry'; + static override readonly entityKind: string = 'GenerateCountry'; private state: { rng: prand.RandomGenerator; @@ -2060,7 +2118,7 @@ export class GenerateCountry extends AbstractGenerator<{ } export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueCountry'; + static override readonly entityKind: string = 'GenerateUniqueCountry'; private state: { genIndicesObj: GenerateUniqueInt; @@ -2099,7 +2157,7 @@ export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolea export class GenerateJobTitle extends AbstractGenerator<{ arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateJobTitle'; + static override readonly entityKind: string = 'GenerateJobTitle'; private state: { rng: prand.RandomGenerator; @@ -2131,17 +2189,17 @@ export class GenerateJobTitle extends AbstractGenerator<{ } } -export class GenerateStreetAdddress extends AbstractGenerator<{ +export class GenerateStreetAddress extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateStreetAdddress'; + static override readonly entityKind: string = 'GenerateStreetAddress'; private state: { rng: prand.RandomGenerator; possStreetNames: string[][]; } | undefined; - override uniqueVersionOfGen = GenerateUniqueStreetAdddress; + override uniqueVersionOfGen = GenerateUniqueStreetAddress; override init({ count, seed }: { count: number; seed: number }) { super.init({ count, seed }); @@ -2181,8 +2239,8 @@ export class GenerateStreetAdddress extends AbstractGenerator<{ } } -export class GenerateUniqueStreetAdddress extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueStreetAdddress'; +export class GenerateUniqueStreetAddress extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly entityKind: string = 'GenerateUniqueStreetAddress'; private state: { rng: prand.RandomGenerator; @@ -2278,7 +2336,7 @@ export class GenerateCity extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateCity'; + static override readonly entityKind: string = 'GenerateCity'; private state: { rng: prand.RandomGenerator; @@ -2312,7 +2370,7 @@ export class GenerateCity extends AbstractGenerator<{ } export class GenerateUniqueCity extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueCity'; + static override readonly entityKind: string = 'GenerateUniqueCity'; private state: { genIndicesObj: GenerateUniqueInt; @@ -2352,7 +2410,7 @@ export class GeneratePostcode extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GeneratePostcode'; + static override readonly entityKind: string = 'GeneratePostcode'; private state: { rng: prand.RandomGenerator; @@ -2406,7 +2464,7 @@ export class GeneratePostcode extends AbstractGenerator<{ } export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniquePostcode'; + static override readonly entityKind: string = 'GenerateUniquePostcode'; private state: { rng: prand.RandomGenerator; @@ -2493,7 +2551,7 @@ export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boole export class GenerateState extends AbstractGenerator<{ arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateState'; + static override readonly entityKind: string = 'GenerateState'; private state: { rng: prand.RandomGenerator; @@ -2529,7 +2587,7 @@ export class GenerateCompanyName extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateCompanyName'; + static override readonly entityKind: string = 'GenerateCompanyName'; private state: { rng: prand.RandomGenerator; @@ -2598,7 +2656,7 @@ export class GenerateCompanyName extends AbstractGenerator<{ } export class GenerateUniqueCompanyName extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueCompanyName'; + static override readonly entityKind: string = 'GenerateUniqueCompanyName'; private state: { rng: prand.RandomGenerator; @@ -2709,7 +2767,7 @@ export class GenerateLoremIpsum extends AbstractGenerator<{ sentencesCount?: number; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateLoremIpsum'; + static override readonly entityKind: string = 'GenerateLoremIpsum'; private state: { rng: prand.RandomGenerator; @@ -2748,7 +2806,7 @@ export class GenerateLoremIpsum extends AbstractGenerator<{ } export class WeightedRandomGenerator extends AbstractGenerator<{ weight: number; value: AbstractGenerator }[]> { - static override readonly [entityKind]: string = 'WeightedRandomGenerator'; + static override readonly entityKind: string = 'WeightedRandomGenerator'; private state: { rng: prand.RandomGenerator; @@ -2818,7 +2876,7 @@ export class GeneratePoint extends AbstractGenerator<{ maxYValue?: number; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GeneratePoint'; + static override readonly entityKind: string = 'GeneratePoint'; private state: { xCoordinateGen: GenerateNumber; @@ -2872,7 +2930,7 @@ export class GenerateUniquePoint extends AbstractGenerator<{ maxYValue?: number; isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniquePoint'; + static override readonly entityKind: string = 'GenerateUniquePoint'; private state: { xCoordinateGen: GenerateUniqueNumber; @@ -2927,7 +2985,7 @@ export class GenerateLine extends AbstractGenerator<{ maxCValue?: number; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateLine'; + static override readonly entityKind: string = 'GenerateLine'; private state: { aCoefficientGen: GenerateNumber; @@ -2998,7 +3056,7 @@ export class GenerateUniqueLine extends AbstractGenerator<{ maxCValue?: number; isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniqueLine'; + static override readonly entityKind: string = 'GenerateUniqueLine'; private state: { aCoefficientGen: GenerateUniqueNumber; diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index f9da6a50a..35cba442f 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -1,3 +1,4 @@ +/* eslint-disable drizzle-internal/require-entity-kind */ import { entityKind, eq, is } from 'drizzle-orm'; import type { MySqlTable, MySqlTableWithColumns } from 'drizzle-orm/mysql-core'; import { MySqlDatabase } from 'drizzle-orm/mysql-core'; @@ -12,15 +13,14 @@ import type { TableGeneratorsType, } from '../types/seedService.ts'; import type { Column, Prettify, Relation, Table } from '../types/tables.ts'; -import type { AbstractGenerator } from './Generators.ts'; +import { generatorsMap } from './GeneratorFuncs.ts'; +import type { AbstractGenerator, GenerateArray, GenerateInterval, GenerateWeightedCount } from './Generators.ts'; import { latestVersion } from './apiVersion.ts'; -// import * as Generators from './Generators.ts'; import { equalSets, generateHashFromString } from './utils.ts'; -import * as GeneratorsV2 from './versioning/v2.ts'; export class SeedService { - static readonly [entityKind]: string = 'SeedService'; + static readonly entityKind: string = 'SeedService'; private defaultCountForTable = 10; private postgresPgLiteMaxParametersNumber = 32740; @@ -29,6 +29,7 @@ export class SeedService { private mysqlMaxParametersNumber = 100000; // SQLITE_MAX_VARIABLE_NUMBER, which by default equals to 999 for SQLite versions prior to 3.32.0 (2020-05-22) or 32766 for SQLite versions after 3.32.0. private sqliteMaxParametersNumber = 32766; + private version?: number; generatePossibleGenerators = ( connectionType: 'postgresql' | 'mysql' | 'sqlite', @@ -40,8 +41,8 @@ export class SeedService { let columnPossibleGenerator: Prettify; let tablePossibleGenerators: Prettify; const customSeed = options?.seed === undefined ? 0 : options.seed; - const version = options?.version === undefined ? latestVersion : options.version; - if (version < 1 || version > latestVersion) { + this.version = options?.version === undefined ? latestVersion : options.version; + if (this.version < 1 || this.version > latestVersion) { throw new Error(`Version should be in range [1, ${latestVersion}].`); } @@ -181,21 +182,15 @@ export class SeedService { && refinements[table.name]!.columns !== undefined && refinements[table.name]!.columns[col.name] !== undefined ) { - let genObj = refinements[table.name]!.columns[col.name]!; + const genObj = refinements[table.name]!.columns[col.name]!; - const genObjEntityKind = genObj.getEntityKind(); - const generatorConstructor = this.selectGeneratorOfVersion(version, genObjEntityKind); - genObj = new generatorConstructor(genObj.params); - - // TODO: for now only GenerateValuesFromArray support notNull property - genObj.notNull = col.notNull; if (col.columnType.match(/\[\w*]/g) !== null) { if ( (col.baseColumn?.dataType === 'array' && col.baseColumn.columnType.match(/\[\w*]/g) !== null) // studio case || (col.typeParams.dimensions !== undefined && col.typeParams.dimensions > 1) ) { - throw new Error("for now you can't specify generators for columns of dimensition greater than 1."); + throw new Error("for now you can't specify generators for columns of dimension greater than 1."); } genObj.baseColumnDataType = col.baseColumn?.dataType; @@ -217,29 +212,26 @@ export class SeedService { const predicate = cyclicRelation !== undefined && col.notNull === false; if (predicate === true) { - columnPossibleGenerator.generator = new Generators.GenerateDefault({ defaultValue: null }); + columnPossibleGenerator.generator = new generatorsMap.GenerateDefault[0]!({ defaultValue: null }); columnPossibleGenerator.wasDefinedBefore = true; + } else { + columnPossibleGenerator.generator = new generatorsMap.HollowGenerator[0]!({}); } - - columnPossibleGenerator.generator = new Generators.HollowGenerator({}); } // TODO: rewrite pickGeneratorFor... using new col properties: isUnique and notNull else if (connectionType === 'postgresql') { columnPossibleGenerator.generator = this.selectGeneratorForPostgresColumn( table, col, - version, ); } else if (connectionType === 'mysql') { columnPossibleGenerator.generator = this.selectGeneratorForMysqlColumn( table, col, - version, ); } else if (connectionType === 'sqlite') { columnPossibleGenerator.generator = this.selectGeneratorForSqlite( table, col, - version, ); } @@ -249,9 +241,22 @@ export class SeedService { ); } - // check if new version exists + const arrayGen = columnPossibleGenerator.generator.replaceIfArray(); + if (arrayGen !== undefined) { + columnPossibleGenerator.generator = arrayGen; + } + + const uniqueGen = columnPossibleGenerator.generator.replaceIfUnique(); + if (uniqueGen !== undefined) { + columnPossibleGenerator.generator = uniqueGen; + } + + // selecting version of generator + columnPossibleGenerator.generator = this.selectVersionOfGenerator(columnPossibleGenerator.generator); columnPossibleGenerator.generator.isUnique = col.isUnique; + // TODO: for now only GenerateValuesFromArray support notNull property + columnPossibleGenerator.generator.notNull = col.notNull; columnPossibleGenerator.generator.dataType = col.dataType; columnPossibleGenerator.generator.stringLength = col.typeParams.length; @@ -264,6 +269,39 @@ export class SeedService { return tablesPossibleGenerators; }; + selectVersionOfGenerator = (generator: AbstractGenerator) => { + const entityKind = generator.getEntityKind(); + if (entityKind === 'GenerateArray') { + const oldBaseColumnGen = (generator as GenerateArray).params.baseColumnGen; + + const newBaseColumnGen = this.selectVersionOfGenerator(oldBaseColumnGen); + // newGenerator.baseColumnDataType = oldGenerator.baseColumnDataType; + + (generator as GenerateArray).params.baseColumnGen = newBaseColumnGen; + } + + let possibleGeneratorConstructors = + (generatorsMap as { [entityKind: string]: (typeof AbstractGenerator)[] })[entityKind]; + + possibleGeneratorConstructors = possibleGeneratorConstructors?.filter((possGenCon) => + possGenCon.version <= this.version! // sorting in ascending order by version + ).sort((a, b) => a.version - b.version); + const generatorConstructor = possibleGeneratorConstructors?.at(-1) as + | (new(params: any) => AbstractGenerator) + | undefined; + if (generatorConstructor === undefined) { + throw new Error(`Can't select ${entityKind} generator for ${this.version} version.`); + } + + const newGenerator = new generatorConstructor(generator.params); + newGenerator.baseColumnDataType = generator.baseColumnDataType; + newGenerator.isUnique = generator.isUnique; + newGenerator.dataType = generator.dataType; + newGenerator.stringLength = generator.stringLength; + + return newGenerator; + }; + cyclicTablesCompare = ( table1: Table, table2: Table, @@ -410,7 +448,9 @@ export class SeedService { count: number, seed: number, ) => { - const gen = new Generators.GenerateWeightedCount({}); + let gen = new generatorsMap.GenerateWeightedCount[0]!({}); + gen = this.selectVersionOfGenerator(gen) as GenerateWeightedCount; + // const gen = new GenerateWeightedCount({}); gen.init({ count: weightedCount, seed }); let weightedWithCount = 0; for (let i = 0; i < count; i++) { @@ -420,34 +460,10 @@ export class SeedService { return weightedWithCount; }; - selectGeneratorOfVersion = (version: number, generatorEntityKind: string) => { - type GeneratorConstructorT = new(params: any) => AbstractGenerator; - const GeneratorVersions = [...Object.values(GeneratorsV2), ...Object.values(Generators)]; - - let generatorConstructor: GeneratorConstructorT | undefined; - for (const gens of GeneratorVersions) { - for (const gen of Object.values(gens)) { - const abstractGen = gen as typeof AbstractGenerator; - if (abstractGen[entityKind] === generatorEntityKind) { - generatorConstructor = abstractGen as unknown as GeneratorConstructorT; - - return generatorConstructor; - } - } - } - - if (generatorConstructor === undefined) { - throw new Error(`Can't select ${generatorEntityKind} generator for ${version} version.`); - } - - return generatorConstructor; - }; - // TODO: revise serial part generators selectGeneratorForPostgresColumn = ( table: Table, col: Column, - version: number, ) => { const pickGenerator = (table: Table, col: Column) => { // ARRAY @@ -455,13 +471,22 @@ export class SeedService { const baseColumnGen = this.selectGeneratorForPostgresColumn( table, col.baseColumn!, - version, ) as AbstractGenerator; if (baseColumnGen === undefined) { throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); } - const generator = new Generators.GenerateArray({ baseColumnGen, size: col.size }); + // const getBaseColumnDataType = (baseColumn: Column) => { + // if (baseColumn.baseColumn !== undefined) { + // return getBaseColumnDataType(baseColumn.baseColumn); + // } + + // return baseColumn.dataType; + // }; + // const baseColumnDataType = getBaseColumnDataType(col.baseColumn); + + const generator = new generatorsMap.GenerateArray[0]!({ baseColumnGen, size: col.size }); + // generator.baseColumnDataType = baseColumnDataType; return generator; } @@ -475,15 +500,15 @@ export class SeedService { }; baseColumn.columnType = baseColumnType; - const baseColumnGen = this.selectGeneratorForPostgresColumn(table, baseColumn, version) as AbstractGenerator; + const baseColumnGen = this.selectGeneratorForPostgresColumn(table, baseColumn) as AbstractGenerator; if (baseColumnGen === undefined) { throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); } - let generator = new Generators.GenerateArray({ baseColumnGen }); + let generator = new generatorsMap.GenerateArray[0]!({ baseColumnGen }); for (let i = 0; i < col.typeParams.dimensions! - 1; i++) { - generator = new Generators.GenerateArray({ baseColumnGen: generator }); + generator = new generatorsMap.GenerateArray[0]!({ baseColumnGen: generator }); } return generator; @@ -497,7 +522,7 @@ export class SeedService { || col.columnType.includes('bigint')) && table.primaryKeys.includes(col.name) ) { - const generator = new Generators.GenerateIntPrimaryKey({}); + const generator = new generatorsMap.GenerateIntPrimaryKey[0]!({}); return generator; } @@ -545,7 +570,7 @@ export class SeedService { && !col.columnType.includes('interval') && !col.columnType.includes('point') ) { - const generator = new Generators.GenerateInt({ + const generator = new generatorsMap.GenerateInt[0]!({ minValue, maxValue, }); @@ -554,9 +579,9 @@ export class SeedService { } if (col.columnType.includes('serial')) { - const generator = new Generators.GenerateIntPrimaryKey({}); + const generator = new generatorsMap.GenerateIntPrimaryKey[0]!({}); - (generator as Generators.GenerateIntPrimaryKey).maxValue = maxValue; + generator.maxValue = maxValue; return generator; } @@ -573,14 +598,14 @@ export class SeedService { const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); - const generator = new Generators.GenerateNumber({ + const generator = new generatorsMap.GenerateNumber[0]!({ minValue: -maxAbsoluteValue, maxValue: maxAbsoluteValue, precision: Math.pow(10, scale), }); return generator; } - const generator = new Generators.GenerateNumber({}); + const generator = new generatorsMap.GenerateNumber[0]!({}); return generator; } @@ -592,7 +617,7 @@ export class SeedService { || col.columnType.startsWith('char')) && table.primaryKeys.includes(col.name) ) { - const generator = new Generators.GenerateUniqueString({}); + const generator = new generatorsMap.GenerateUniqueString[0]!({}); return generator; } @@ -603,7 +628,7 @@ export class SeedService { || col.columnType.startsWith('char')) && col.name.toLowerCase().includes('name') ) { - const generator = new Generators.GenerateFirstName({}); + const generator = new generatorsMap.GenerateFirstName[0]!({}); return generator; } @@ -614,7 +639,7 @@ export class SeedService { || col.columnType.startsWith('char')) && col.name.toLowerCase().includes('email') ) { - const generator = new Generators.GenerateEmail({}); + const generator = new generatorsMap.GenerateEmail[0]!({}); return generator; } @@ -624,47 +649,47 @@ export class SeedService { || col.columnType.startsWith('varchar') || col.columnType.startsWith('char') ) { - const generator = new Generators.GenerateString({}); + const generator = new generatorsMap.GenerateString[0]!({}); return generator; } // UUID if (col.columnType === 'uuid') { - const generator = new Generators.GenerateUUID({}); + const generator = new generatorsMap.GenerateUUID[0]!({}); return generator; } // BOOLEAN if (col.columnType === 'boolean') { - const generator = new Generators.GenerateBoolean({}); + const generator = new generatorsMap.GenerateBoolean[0]!({}); return generator; } // DATE, TIME, TIMESTAMP if (col.columnType.includes('date')) { - const generator = new Generators.GenerateDate({}); + const generator = new generatorsMap.GenerateDate[0]!({}); return generator; } if (col.columnType === 'time') { - const generator = new Generators.GenerateTime({}); + const generator = new generatorsMap.GenerateTime[0]!({}); return generator; } if (col.columnType.includes('timestamp')) { - const generator = new Generators.GenerateTimestamp({}); + const generator = new generatorsMap.GenerateTimestamp[0]!({}); return generator; } // JSON, JSONB if (col.columnType === 'json' || col.columnType === 'jsonb') { - const generator = new Generators.GenerateJson({}); + const generator = new generatorsMap.GenerateJson[0]!({}); return generator; } @@ -676,7 +701,7 @@ export class SeedService { // ENUM if (col.enumValues !== undefined) { - const generator = new Generators.GenerateEnum({ + const generator = new generatorsMap.GenerateEnum[0]!({ enumValues: col.enumValues, }); @@ -686,32 +711,32 @@ export class SeedService { // INTERVAL if (col.columnType.startsWith('interval')) { if (col.columnType === 'interval') { - const generator = new Generators.GenerateInterval({}); + const generator = new generatorsMap.GenerateInterval[0]!({}); return generator; } - const fields = col.columnType.replace('interval ', '') as Generators.GenerateInterval['params']['fields']; - const generator = new Generators.GenerateInterval({ fields }); + const fields = col.columnType.replace('interval ', '') as GenerateInterval['params']['fields']; + const generator = new generatorsMap.GenerateInterval[0]!({ fields }); return generator; } // POINT, LINE if (col.columnType.includes('point')) { - const generator = new Generators.GeneratePoint({}); + const generator = new generatorsMap.GeneratePoint[0]!({}); return generator; } if (col.columnType.includes('line')) { - const generator = new Generators.GenerateLine({}); + const generator = new generatorsMap.GenerateLine[0]!({}); return generator; } if (col.hasDefault && col.default !== undefined) { - const generator = new Generators.GenerateDefault({ + const generator = new generatorsMap.GenerateDefault[0]!({ defaultValue: col.default, }); return generator; @@ -720,15 +745,8 @@ export class SeedService { return; }; - let generator = pickGenerator(table, col) as AbstractGenerator || undefined; + const generator = pickGenerator(table, col); if (generator !== undefined) { - const generatorConstructor = this.selectGeneratorOfVersion( - version, - generator.getEntityKind(), - ); - - generator = new generatorConstructor(generator.params); - generator.isUnique = col.isUnique; generator.dataType = col.dataType; generator.stringLength = col.typeParams.length; @@ -740,7 +758,6 @@ export class SeedService { selectGeneratorForMysqlColumn = ( table: Table, col: Column, - version: number, ) => { const pickGenerator = (table: Table, col: Column) => { // INT ------------------------------------------------------------------------------------------------------------ @@ -748,7 +765,7 @@ export class SeedService { (col.columnType.includes('serial') || col.columnType.includes('int')) && table.primaryKeys.includes(col.name) ) { - const generator = new Generators.GenerateIntPrimaryKey({}); + const generator = new generatorsMap.GenerateIntPrimaryKey[0]!({}); return generator; } @@ -783,7 +800,7 @@ export class SeedService { } if (col.columnType.includes('int')) { - const generator = new Generators.GenerateInt({ + const generator = new generatorsMap.GenerateInt[0]!({ minValue, maxValue, }); @@ -791,7 +808,7 @@ export class SeedService { } if (col.columnType.includes('serial')) { - const generator = new Generators.GenerateIntPrimaryKey({}); + const generator = new generatorsMap.GenerateIntPrimaryKey[0]!({}); generator.maxValue = maxValue; return generator; } @@ -809,7 +826,7 @@ export class SeedService { const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); - const generator = new Generators.GenerateNumber({ + const generator = new generatorsMap.GenerateNumber[0]!({ minValue: -maxAbsoluteValue, maxValue: maxAbsoluteValue, precision: Math.pow(10, scale), @@ -817,7 +834,7 @@ export class SeedService { return generator; } - const generator = new Generators.GenerateNumber({}); + const generator = new generatorsMap.GenerateNumber[0]!({}); return generator; } @@ -831,7 +848,7 @@ export class SeedService { || col.columnType.startsWith('varbinary')) && table.primaryKeys.includes(col.name) ) { - const generator = new Generators.GenerateUniqueString({}); + const generator = new generatorsMap.GenerateUniqueString[0]!({}); return generator; } @@ -844,7 +861,7 @@ export class SeedService { || col.columnType.startsWith('varbinary')) && col.name.toLowerCase().includes('name') ) { - const generator = new Generators.GenerateFirstName({}); + const generator = new generatorsMap.GenerateFirstName[0]!({}); return generator; } @@ -857,7 +874,7 @@ export class SeedService { || col.columnType.startsWith('varbinary')) && col.name.toLowerCase().includes('email') ) { - const generator = new Generators.GenerateEmail({}); + const generator = new generatorsMap.GenerateEmail[0]!({}); return generator; } @@ -869,58 +886,58 @@ export class SeedService { || col.columnType.startsWith('binary') || col.columnType.startsWith('varbinary') ) { - const generator = new Generators.GenerateString({}); + const generator = new generatorsMap.GenerateString[0]!({}); return generator; } // BOOLEAN if (col.columnType === 'boolean') { - const generator = new Generators.GenerateBoolean({}); + const generator = new generatorsMap.GenerateBoolean[0]!({}); return generator; } // DATE, TIME, TIMESTAMP, DATETIME, YEAR if (col.columnType.includes('datetime')) { - const generator = new Generators.GenerateDatetime({}); + const generator = new generatorsMap.GenerateDatetime[0]!({}); return generator; } if (col.columnType.includes('date')) { - const generator = new Generators.GenerateDate({}); + const generator = new generatorsMap.GenerateDate[0]!({}); return generator; } if (col.columnType === 'time') { - const generator = new Generators.GenerateTime({}); + const generator = new generatorsMap.GenerateTime[0]!({}); return generator; } if (col.columnType.includes('timestamp')) { - const generator = new Generators.GenerateTimestamp({}); + const generator = new generatorsMap.GenerateTimestamp[0]!({}); return generator; } if (col.columnType === 'year') { - const generator = new Generators.GenerateYear({}); + const generator = new generatorsMap.GenerateYear[0]!({}); return generator; } // JSON if (col.columnType === 'json') { - const generator = new Generators.GenerateJson({}); + const generator = new generatorsMap.GenerateJson[0]!({}); return generator; } // ENUM if (col.enumValues !== undefined) { - const generator = new Generators.GenerateEnum({ + const generator = new generatorsMap.GenerateEnum[0]!({ enumValues: col.enumValues, }); return generator; } if (col.hasDefault && col.default !== undefined) { - const generator = new Generators.GenerateDefault({ + const generator = new generatorsMap.GenerateDefault[0]!({ defaultValue: col.default, }); return generator; @@ -929,15 +946,7 @@ export class SeedService { return; }; - let generator = pickGenerator(table, col) as AbstractGenerator || undefined; - if (generator !== undefined) { - const generatorConstructor = this.selectGeneratorOfVersion( - version, - generator.getEntityKind(), - ); - - generator = new generatorConstructor(generator.params); - } + const generator = pickGenerator(table, col); return generator; }; @@ -945,7 +954,6 @@ export class SeedService { selectGeneratorForSqlite = ( table: Table, col: Column, - version: number, ) => { const pickGenerator = (table: Table, col: Column) => { // int section --------------------------------------------------------------------------------------- @@ -953,17 +961,17 @@ export class SeedService { (col.columnType === 'integer' || col.columnType === 'numeric') && table.primaryKeys.includes(col.name) ) { - const generator = new Generators.GenerateIntPrimaryKey({}); + const generator = new generatorsMap.GenerateIntPrimaryKey[0]!({}); return generator; } if (col.columnType === 'integer' && col.dataType === 'boolean') { - const generator = new Generators.GenerateBoolean({}); + const generator = new generatorsMap.GenerateBoolean[0]!({}); return generator; } if ((col.columnType === 'integer' && col.dataType === 'date')) { - const generator = new Generators.GenerateTimestamp({}); + const generator = new generatorsMap.GenerateTimestamp[0]!({}); return generator; } @@ -971,7 +979,7 @@ export class SeedService { col.columnType === 'integer' || (col.dataType === 'bigint' && col.columnType === 'blob') ) { - const generator = new Generators.GenerateInt({}); + const generator = new generatorsMap.GenerateInt[0]!({}); return generator; } @@ -982,7 +990,7 @@ export class SeedService { const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); - const generator = new Generators.GenerateNumber({ + const generator = new generatorsMap.GenerateNumber[0]!({ minValue: -maxAbsoluteValue, maxValue: maxAbsoluteValue, precision: Math.pow(10, scale), @@ -990,7 +998,7 @@ export class SeedService { return generator; } - const generator = new Generators.GenerateNumber({}); + const generator = new generatorsMap.GenerateNumber[0]!({}); return generator; } @@ -1001,7 +1009,7 @@ export class SeedService { || col.columnType.startsWith('blob')) && table.primaryKeys.includes(col.name) ) { - const generator = new Generators.GenerateUniqueString({}); + const generator = new generatorsMap.GenerateUniqueString[0]!({}); return generator; } @@ -1011,7 +1019,7 @@ export class SeedService { || col.columnType.startsWith('blob')) && col.name.toLowerCase().includes('name') ) { - const generator = new Generators.GenerateFirstName({}); + const generator = new generatorsMap.GenerateFirstName[0]!({}); return generator; } @@ -1021,7 +1029,7 @@ export class SeedService { || col.columnType.startsWith('blob')) && col.name.toLowerCase().includes('email') ) { - const generator = new Generators.GenerateEmail({}); + const generator = new generatorsMap.GenerateEmail[0]!({}); return generator; } @@ -1031,7 +1039,7 @@ export class SeedService { || col.columnType.startsWith('blob') || col.columnType.startsWith('blobbuffer') ) { - const generator = new Generators.GenerateString({}); + const generator = new generatorsMap.GenerateString[0]!({}); return generator; } @@ -1039,12 +1047,12 @@ export class SeedService { (col.columnType.startsWith('text') && col.dataType === 'json') || (col.columnType.startsWith('blob') && col.dataType === 'json') ) { - const generator = new Generators.GenerateJson({}); + const generator = new generatorsMap.GenerateJson[0]!({}); return generator; } if (col.hasDefault && col.default !== undefined) { - const generator = new Generators.GenerateDefault({ + const generator = new generatorsMap.GenerateDefault[0]!({ defaultValue: col.default, }); return generator; @@ -1053,15 +1061,7 @@ export class SeedService { return; }; - let generator = pickGenerator(table, col) as AbstractGenerator || undefined; - if (generator !== undefined) { - const generatorConstructor = this.selectGeneratorOfVersion( - version, - generator.getEntityKind(), - ); - - generator = new generatorConstructor(generator.params); - } + const generator = pickGenerator(table, col); return generator; }; @@ -1220,9 +1220,13 @@ export class SeedService { }))!.map((rows) => rows[refColName]) as (string | number | boolean)[]; hasSelfRelation = true; - genObj = new Generators.GenerateSelfRelationsValuesFromArray({ + genObj = new generatorsMap.GenerateSelfRelationsValuesFromArray[0]!({ values: refColumnValues, }); + genObj = this.selectVersionOfGenerator(genObj); + // genObj = new GenerateSelfRelationsValuesFromArray({ + // values: refColumnValues, + // }); } else if ( tableGenerators[rel.columns[colIdx]!]?.wasDefinedBefore === false && tableGenerators[rel.columns[colIdx]!]?.wasRefined === false @@ -1240,10 +1244,11 @@ export class SeedService { weightedCountSeed = table.withFromTable[rel.refTable]!.weightedCountSeed; } - genObj = new Generators.GenerateValuesFromArray({ values: refColumnValues }); - (genObj as Generators.GenerateValuesFromArray).notNull = tableGenerators[rel.columns[colIdx]!]!.notNull; - (genObj as Generators.GenerateValuesFromArray).weightedCountSeed = weightedCountSeed; - (genObj as Generators.GenerateValuesFromArray).maxRepeatedValuesCount = repeatedValuesCount; + // TODO: revise maybe need to select version of generator here too + genObj = new generatorsMap.GenerateValuesFromArray[0]!({ values: refColumnValues }); + genObj.notNull = tableGenerators[rel.columns[colIdx]!]!.notNull; + genObj.weightedCountSeed = weightedCountSeed; + genObj.maxRepeatedValuesCount = repeatedValuesCount; } if (genObj !== undefined) { @@ -1360,15 +1365,15 @@ export class SeedService { seed: columnGenerator.pRNGSeed, }); - const arrayGen = columnsGenerators[columnName]!.replaceIfArray({ count, seed: columnGenerator.pRNGSeed }); - if (arrayGen !== undefined) { - columnsGenerators[columnName] = arrayGen; - } + // const arrayGen = columnsGenerators[columnName]!.replaceIfArray({ count, seed: columnGenerator.pRNGSeed }); + // if (arrayGen !== undefined) { + // columnsGenerators[columnName] = arrayGen; + // } - const uniqueGen = columnsGenerators[columnName]!.replaceIfUnique({ count, seed: columnGenerator.pRNGSeed }); - if (uniqueGen !== undefined) { - columnsGenerators[columnName] = uniqueGen; - } + // const uniqueGen = columnsGenerators[columnName]!.replaceIfUnique({ count, seed: columnGenerator.pRNGSeed }); + // if (uniqueGen !== undefined) { + // columnsGenerators[columnName] = uniqueGen; + // } } let maxParametersNumber: number; if (is(db, PgDatabase)) { diff --git a/drizzle-seed/src/services/versioning/v2.ts b/drizzle-seed/src/services/versioning/v2.ts index 96451b2f8..e09cc45f6 100644 --- a/drizzle-seed/src/services/versioning/v2.ts +++ b/drizzle-seed/src/services/versioning/v2.ts @@ -1,12 +1,6 @@ -import { entityKind } from 'drizzle-orm'; +/* eslint-disable drizzle-internal/require-entity-kind */ import prand from 'pure-rand'; -import { AbstractGenerator, GenerateInterval } from '../Generators.ts'; - -export class GenerateIntervalV2 extends GenerateInterval { - static override readonly [entityKind]: string = 'GenerateInterval'; - override readonly version: number = 2; - override uniqueVersionOfGen = GenerateUniqueIntervalV2; -} +import { AbstractGenerator } from '../Generators.ts'; export class GenerateUniqueIntervalV2 extends AbstractGenerator<{ fields?: @@ -25,8 +19,8 @@ export class GenerateUniqueIntervalV2 extends AbstractGenerator<{ | 'minute to second'; isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniqueInterval'; - override readonly version: number = 2; + static override readonly 'entityKind': string = 'GenerateUniqueInterval'; + static override readonly version: number = 2; private state: { rng: prand.RandomGenerator; @@ -119,8 +113,8 @@ export class GenerateStringV2 extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateString'; - override readonly version: number = 2; + static override readonly 'entityKind': string = 'GenerateString'; + static override readonly version: number = 2; private state: { rng: prand.RandomGenerator; @@ -175,8 +169,8 @@ export class GenerateStringV2 extends AbstractGenerator<{ } export class GenerateUniqueStringV2 extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueString'; - override readonly version: number = 2; + static override readonly 'entityKind': string = 'GenerateUniqueString'; + static override readonly version: number = 2; private state: { rng: prand.RandomGenerator; diff --git a/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts b/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts index 3473e555a..23fca0c6c 100644 --- a/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts +++ b/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts @@ -23,7 +23,7 @@ import { GeneratePoint, GeneratePostcode, GenerateState, - GenerateStreetAdddress, + GenerateStreetAddress, GenerateString, GenerateTime, GenerateTimestamp, @@ -35,7 +35,7 @@ import { GenerateUniqueNumber, GenerateUniquePoint, GenerateUniquePostcode, - GenerateUniqueStreetAdddress, + GenerateUniqueStreetAddress, GenerateUniqueString, GenerateValuesFromArray, GenerateYear, @@ -107,8 +107,8 @@ const generatorsFuncs = { // uniqueCountry: new GenerateUniqueCountry({}), city: new GenerateCity({}), // uniqueCity: new GenerateUniqueCity({}), - streetAddress: new GenerateStreetAdddress({}), - uniqueStreetAddress: new GenerateUniqueStreetAdddress({}), + streetAddress: new GenerateStreetAddress({}), + uniqueStreetAddress: new GenerateUniqueStreetAddress({}), jobTitle: new GenerateJobTitle({}), postcode: new GeneratePostcode({}), uniquePostcode: new GenerateUniquePostcode({}), diff --git a/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts b/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts index 16a55baf4..d4f45de22 100644 --- a/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts +++ b/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts @@ -64,31 +64,31 @@ export const allDataTypes = schema.table('all_data_types', { }); export const allArrayDataTypes = schema.table('all_array_data_types', { - integerArray: integer('integer_array').array(), - smallintArray: smallint('smallint_array').array(), - bigintegerArray: bigint('bigint_array', { mode: 'bigint' }).array(), - bigintNumberArray: bigint('bigint_number_array', { mode: 'number' }).array(), - booleanArray: boolean('boolean_array').array(), - textArray: text('text_array').array(), - varcharArray: varchar('varchar_array', { length: 256 }).array(), - charArray: char('char_array', { length: 256 }).array(), - numericArray: numeric('numeric_array').array(), - decimalArray: decimal('decimal_array').array(), - realArray: real('real_array').array(), - doublePrecisionArray: doublePrecision('double_precision_array').array(), - jsonArray: json('json_array').array(), - jsonbArray: jsonb('jsonb_array').array(), - timeArray: time('time_array').array(), - timestampDateArray: timestamp('timestamp_date_array', { mode: 'date' }).array(), - timestampStringArray: timestamp('timestamp_string_array', { mode: 'string' }).array(), + // integerArray: integer('integer_array').array(), + // smallintArray: smallint('smallint_array').array(), + // bigintegerArray: bigint('bigint_array', { mode: 'bigint' }).array(), + // bigintNumberArray: bigint('bigint_number_array', { mode: 'number' }).array(), + // booleanArray: boolean('boolean_array').array(), + // textArray: text('text_array').array(), + // varcharArray: varchar('varchar_array', { length: 256 }).array(), + // charArray: char('char_array', { length: 256 }).array(), + // numericArray: numeric('numeric_array').array(), + // decimalArray: decimal('decimal_array').array(), + // realArray: real('real_array').array(), + // doublePrecisionArray: doublePrecision('double_precision_array').array(), + // jsonArray: json('json_array').array(), + // jsonbArray: jsonb('jsonb_array').array(), + // timeArray: time('time_array').array(), + // timestampDateArray: timestamp('timestamp_date_array', { mode: 'date' }).array(), + // timestampStringArray: timestamp('timestamp_string_array', { mode: 'string' }).array(), dateStringArray: date('date_string_array', { mode: 'string' }).array(), dateArray: date('date_array', { mode: 'date' }).array(), - intervalArray: interval('interval_array').array(), - pointArray: point('point_array', { mode: 'xy' }).array(), - pointTupleArray: point('point_tuple_array', { mode: 'tuple' }).array(), - lineArray: line('line_array', { mode: 'abc' }).array(), - lineTupleArray: line('line_tuple_array', { mode: 'tuple' }).array(), - moodEnumArray: moodEnum('mood_enum_array').array(), + // intervalArray: interval('interval_array').array(), + // pointArray: point('point_array', { mode: 'xy' }).array(), + // pointTupleArray: point('point_tuple_array', { mode: 'tuple' }).array(), + // lineArray: line('line_array', { mode: 'abc' }).array(), + // lineTupleArray: line('line_tuple_array', { mode: 'tuple' }).array(), + // moodEnumArray: moodEnum('mood_enum_array').array(), }); export const ndArrays = schema.table('nd_arrays', { From eb72873330b7822ff95cdfb7af4e9b24fb28b7fb Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 23 Dec 2024 15:51:18 +0200 Subject: [PATCH 461/492] bug fix, refine functions versioning --- changelogs/drizzle-seed/0.2.0.md | 5 ++- drizzle-seed/src/index.ts | 36 +++++++++++++++------ drizzle-seed/src/services/GeneratorFuncs.ts | 5 +-- drizzle-seed/src/services/SeedService.ts | 31 ++++++++++++++---- 4 files changed, 58 insertions(+), 19 deletions(-) diff --git a/changelogs/drizzle-seed/0.2.0.md b/changelogs/drizzle-seed/0.2.0.md index be19a8949..5bb9d6007 100644 --- a/changelogs/drizzle-seed/0.2.0.md +++ b/changelogs/drizzle-seed/0.2.0.md @@ -3,7 +3,7 @@ We are introducing a new parameter, `version`, to the `seed` function options. This parameter, which controls generator versioning, has been added to make it easier to update deterministic generators in the future. Since values should remain consistent after each regeneration, it is crucial to provide a well-designed API for gradual updates ```ts -await seed(db, schema, { version: 2 }); +await seed(db, schema, { version: '2' }); ``` #### Example: @@ -121,3 +121,6 @@ However, after inserting the `1 minute 60 second` interval, PostgreSQL database **Generating strings based on text-like column length:** Now (in version 2), the maximum length of a string depends on the length of the text column (e.g., `varchar(20)`). + +## Bug fixes +- seeding table with foreign key referencing another table, without including the second table in schema, will cause seed process to get stuck. \ No newline at end of file diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 48aad2973..de99eb746 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -10,7 +10,7 @@ import { getTableConfig as getPgTableConfig, PgDatabase, PgTable } from 'drizzle import type { SQLiteColumn } from 'drizzle-orm/sqlite-core'; import { BaseSQLiteDatabase, getTableConfig as getSqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; -import { generatorsFuncs } from './services/GeneratorFuncs.ts'; +import { generatorsFuncs, generatorsFuncsV2 } from './services/GeneratorFuncs.ts'; import type { AbstractGenerator } from './services/Generators.ts'; import { SeedService } from './services/SeedService.ts'; import type { DrizzleStudioObjectType, DrizzleStudioRelationType } from './types/drizzleStudio.ts'; @@ -131,6 +131,7 @@ class SeedPromise< SCHEMA extends { [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable; }, + VERSION extends string | undefined, > implements Promise { static readonly entityKind: string = 'SeedPromise'; @@ -139,7 +140,7 @@ class SeedPromise< constructor( private db: DB, private schema: SCHEMA, - private options?: { count?: number; seed?: number; version?: number }, + private options?: { count?: number; seed?: number; version?: VERSION }, ) {} then( @@ -181,14 +182,23 @@ class SeedPromise< } async refine( - callback: (funcs: typeof generatorsFuncs) => InferCallbackType, + callback: ( + funcs: FunctionsVersioning, + ) => InferCallbackType, ): Promise { - const refinements = callback(generatorsFuncs) as RefinementsType; + const refinements = this.options?.version === undefined || this.options.version === '2' + ? callback(generatorsFuncsV2 as FunctionsVersioning) as RefinementsType + : callback(generatorsFuncs as FunctionsVersioning) as RefinementsType; + // const refinements = callback(generatorsFuncs) as RefinementsType; await seedFunc(this.db, this.schema, this.options, refinements); } } +type FunctionsVersioning = VERSION extends `1` ? typeof generatorsFuncs + : VERSION extends `2` ? typeof generatorsFuncsV2 + : typeof generatorsFuncsV2; + export function getGeneratorsFunctions() { return generatorsFuncs; } @@ -337,8 +347,9 @@ export function seed< | SQLiteTable | any; }, ->(db: DB, schema: SCHEMA, options?: { count?: number; seed?: number; version?: number }) { - return new SeedPromise(db, schema, options); + VERSION extends '2' | '1' | undefined, +>(db: DB, schema: SCHEMA, options?: { count?: number; seed?: number; version?: VERSION }) { + return new SeedPromise(db, schema, options); } const seedFunc = async ( @@ -352,21 +363,26 @@ const seedFunc = async ( | SQLiteTable | any; }, - options: { count?: number; seed?: number; version?: number } = {}, + options: { count?: number; seed?: number; version?: string } = {}, refinements?: RefinementsType, ) => { + let version: number | undefined; + if (options?.version !== undefined) { + version = Number(options?.version); + } + if (is(db, PgDatabase)) { const { pgSchema } = filterPgTables(schema); - await seedPostgres(db, pgSchema, options, refinements); + await seedPostgres(db, pgSchema, { ...options, version }, refinements); } else if (is(db, MySqlDatabase)) { const { mySqlSchema } = filterMySqlTables(schema); - await seedMySql(db, mySqlSchema, options, refinements); + await seedMySql(db, mySqlSchema, { ...options, version }, refinements); } else if (is(db, BaseSQLiteDatabase)) { const { sqliteSchema } = filterSqliteTables(schema); - await seedSqlite(db, sqliteSchema, options, refinements); + await seedSqlite(db, sqliteSchema, { ...options, version }, refinements); } else { throw new Error( 'The drizzle-seed package currently supports only PostgreSQL, MySQL, and SQLite databases. Please ensure your database is one of these supported types', diff --git a/drizzle-seed/src/services/GeneratorFuncs.ts b/drizzle-seed/src/services/GeneratorFuncs.ts index be715a33b..f0687b5ed 100644 --- a/drizzle-seed/src/services/GeneratorFuncs.ts +++ b/drizzle-seed/src/services/GeneratorFuncs.ts @@ -756,9 +756,10 @@ export const generatorsFuncs = { weightedRandom: createGenerator(WeightedRandomGenerator), }; -// TODO: revise // so far, version changes don’t affect generator parameters. -export const generatorsFuncsV2 = { ...generatorsFuncs }; +export const generatorsFuncsV2 = { + ...generatorsFuncs, +}; export const generatorsMap = { HollowGenerator: [ diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 35cba442f..6c045f368 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -42,7 +42,7 @@ export class SeedService { let tablePossibleGenerators: Prettify; const customSeed = options?.seed === undefined ? 0 : options.seed; this.version = options?.version === undefined ? latestVersion : options.version; - if (this.version < 1 || this.version > latestVersion) { + if (Number.isNaN(this.version) || this.version < 1 || this.version > latestVersion) { throw new Error(`Version should be in range [1, ${latestVersion}].`); } @@ -209,9 +209,23 @@ export class SeedService { if (cyclicRelation !== undefined) { columnPossibleGenerator.isCyclic = true; } - const predicate = cyclicRelation !== undefined && col.notNull === false; + + if (foreignKeyColumns[col.name]?.table === undefined && col.notNull === true) { + throw new Error( + `Column '${col.name}' cannot be nullable, and you didn't specify a table for foreign key on column '${col.name}' in '${table.name}' table.`, + ); + } + + const predicate = (cyclicRelation !== undefined || foreignKeyColumns[col.name]?.table === undefined) + && col.notNull === false; if (predicate === true) { + if (foreignKeyColumns[col.name]?.table === undefined && col.notNull === false) { + console.warn( + `Column '${col.name}' in '${table.name}' table will be filled with null values` + + `\nbecause you specified neither a table for foreign key on column '${col.name}' nor a function for '${col.name}' column in refinements.`, + ); + } columnPossibleGenerator.generator = new generatorsMap.GenerateDefault[0]!({ defaultValue: null }); columnPossibleGenerator.wasDefinedBefore = true; } else { @@ -417,7 +431,10 @@ export class SeedService { }; } - if (tablesInOutRelations[rel.refTable] === undefined) { + if ( + rel.refTable !== undefined + && tablesInOutRelations[rel.refTable] === undefined + ) { tablesInOutRelations[rel.refTable] = { out: 0, in: 0, @@ -428,13 +445,15 @@ export class SeedService { }; } - tablesInOutRelations[rel.table]!.out += 1; - tablesInOutRelations[rel.refTable]!.in += 1; + if (rel.refTable !== undefined) { + tablesInOutRelations[rel.table]!.out += 1; + tablesInOutRelations[rel.refTable]!.in += 1; + } if (rel.refTable === rel.table) { tablesInOutRelations[rel.table]!.selfRelation = true; tablesInOutRelations[rel.table]!.selfRelCount = rel.columns.length; - } else { + } else if (rel.refTable !== undefined) { tablesInOutRelations[rel.table]!.requiredTableNames.add(rel.refTable); tablesInOutRelations[rel.refTable]!.dependantTableNames.add(rel.table); } From 280720064f258b8cd83b5592deece91e5e2bc7e7 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 23 Dec 2024 16:04:08 +0200 Subject: [PATCH 462/492] fixes --- drizzle-seed/src/index.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index de99eb746..e3fc5494a 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -587,10 +587,7 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { // might be empty list const newRelations = tableConfig.foreignKeys.map((fk) => { const table = dbToTsTableNamesMap[tableConfig.name] as string; - const refTableName0 = fk.reference(); - const refTableName1 = refTableName0.foreignTable; - const refTableName2 = getTableName(refTableName1); - const refTable = dbToTsTableNamesMap[refTableName2] as string; + const refTable = dbToTsTableNamesMap[getTableName(fk.reference().foreignTable)] as string; const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap( fk.reference().foreignTable, From 0db3d1334263f6badc4ed9d9fd9a127ba0f90fad Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 23 Dec 2024 17:32:10 +0200 Subject: [PATCH 463/492] fixes --- drizzle-seed/src/index.ts | 1 - drizzle-seed/src/services/GeneratorFuncs.ts | 4 +- drizzle-seed/src/services/Generators.ts | 6 +- drizzle-seed/src/services/SeedService.ts | 129 ++++++++++---------- 4 files changed, 70 insertions(+), 70 deletions(-) diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index e3fc5494a..98c449095 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -189,7 +189,6 @@ class SeedPromise< const refinements = this.options?.version === undefined || this.options.version === '2' ? callback(generatorsFuncsV2 as FunctionsVersioning) as RefinementsType : callback(generatorsFuncs as FunctionsVersioning) as RefinementsType; - // const refinements = callback(generatorsFuncs) as RefinementsType; await seedFunc(this.db, this.schema, this.options, refinements); } diff --git a/drizzle-seed/src/services/GeneratorFuncs.ts b/drizzle-seed/src/services/GeneratorFuncs.ts index f0687b5ed..10d0d10f7 100644 --- a/drizzle-seed/src/services/GeneratorFuncs.ts +++ b/drizzle-seed/src/services/GeneratorFuncs.ts @@ -54,7 +54,7 @@ import { import { GenerateStringV2, GenerateUniqueIntervalV2, GenerateUniqueStringV2 } from './versioning/v2.ts'; function createGenerator, T>( - generatorConstructor: new(params: T) => GeneratorType, + generatorConstructor: new(params?: T) => GeneratorType, ) { return ( ...args: GeneratorType extends GenerateValuesFromArray | GenerateDefault | WeightedRandomGenerator ? [T] @@ -915,4 +915,4 @@ export const generatorsMap = { GenerateWeightedCount: [ GenerateWeightedCount, ], -}; +} as const; diff --git a/drizzle-seed/src/services/Generators.ts b/drizzle-seed/src/services/Generators.ts index fff543739..0d285540e 100644 --- a/drizzle-seed/src/services/Generators.ts +++ b/drizzle-seed/src/services/Generators.ts @@ -38,9 +38,11 @@ export abstract class AbstractGenerator { public weightedCountSeed?: number | undefined; public maxRepeatedValuesCount?: number | { weight: number; count: number | number[] }[] | undefined; - // param for GenerateIntP + public params: T; - constructor(public params: T) {} + constructor(params?: T) { + this.params = params === undefined ? {} as T : params as T; + } init(params: { count: number | { weight: number; count: number | number[] }[]; seed: number }): void; init() { diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 6c045f368..84165169e 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -212,7 +212,7 @@ export class SeedService { if (foreignKeyColumns[col.name]?.table === undefined && col.notNull === true) { throw new Error( - `Column '${col.name}' cannot be nullable, and you didn't specify a table for foreign key on column '${col.name}' in '${table.name}' table.`, + `Column '${col.name}' has no null contraint, and you didn't specify a table for foreign key on column '${col.name}' in '${table.name}' table. You should pass `, ); } @@ -222,14 +222,14 @@ export class SeedService { if (predicate === true) { if (foreignKeyColumns[col.name]?.table === undefined && col.notNull === false) { console.warn( - `Column '${col.name}' in '${table.name}' table will be filled with null values` + `Column '${col.name}' in '${table.name}' table will be filled with Null values` + `\nbecause you specified neither a table for foreign key on column '${col.name}' nor a function for '${col.name}' column in refinements.`, ); } - columnPossibleGenerator.generator = new generatorsMap.GenerateDefault[0]!({ defaultValue: null }); + columnPossibleGenerator.generator = new generatorsMap.GenerateDefault[0]({ defaultValue: null }); columnPossibleGenerator.wasDefinedBefore = true; } else { - columnPossibleGenerator.generator = new generatorsMap.HollowGenerator[0]!({}); + columnPossibleGenerator.generator = new generatorsMap.HollowGenerator[0](); } } // TODO: rewrite pickGeneratorFor... using new col properties: isUnique and notNull else if (connectionType === 'postgresql') { @@ -294,13 +294,12 @@ export class SeedService { (generator as GenerateArray).params.baseColumnGen = newBaseColumnGen; } - let possibleGeneratorConstructors = - (generatorsMap as { [entityKind: string]: (typeof AbstractGenerator)[] })[entityKind]; + const possibleGeneratorConstructors = generatorsMap[entityKind as keyof typeof generatorsMap]; - possibleGeneratorConstructors = possibleGeneratorConstructors?.filter((possGenCon) => + const possibleGeneratorConstructorsFiltered = possibleGeneratorConstructors?.filter((possGenCon) => possGenCon.version <= this.version! // sorting in ascending order by version ).sort((a, b) => a.version - b.version); - const generatorConstructor = possibleGeneratorConstructors?.at(-1) as + const generatorConstructor = possibleGeneratorConstructorsFiltered?.at(-1) as | (new(params: any) => AbstractGenerator) | undefined; if (generatorConstructor === undefined) { @@ -467,7 +466,7 @@ export class SeedService { count: number, seed: number, ) => { - let gen = new generatorsMap.GenerateWeightedCount[0]!({}); + let gen = new generatorsMap.GenerateWeightedCount[0](); gen = this.selectVersionOfGenerator(gen) as GenerateWeightedCount; // const gen = new GenerateWeightedCount({}); gen.init({ count: weightedCount, seed }); @@ -504,7 +503,7 @@ export class SeedService { // }; // const baseColumnDataType = getBaseColumnDataType(col.baseColumn); - const generator = new generatorsMap.GenerateArray[0]!({ baseColumnGen, size: col.size }); + const generator = new generatorsMap.GenerateArray[0]({ baseColumnGen, size: col.size }); // generator.baseColumnDataType = baseColumnDataType; return generator; @@ -524,10 +523,10 @@ export class SeedService { throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); } - let generator = new generatorsMap.GenerateArray[0]!({ baseColumnGen }); + let generator = new generatorsMap.GenerateArray[0]({ baseColumnGen }); for (let i = 0; i < col.typeParams.dimensions! - 1; i++) { - generator = new generatorsMap.GenerateArray[0]!({ baseColumnGen: generator }); + generator = new generatorsMap.GenerateArray[0]({ baseColumnGen: generator }); } return generator; @@ -541,7 +540,7 @@ export class SeedService { || col.columnType.includes('bigint')) && table.primaryKeys.includes(col.name) ) { - const generator = new generatorsMap.GenerateIntPrimaryKey[0]!({}); + const generator = new generatorsMap.GenerateIntPrimaryKey[0](); return generator; } @@ -589,7 +588,7 @@ export class SeedService { && !col.columnType.includes('interval') && !col.columnType.includes('point') ) { - const generator = new generatorsMap.GenerateInt[0]!({ + const generator = new generatorsMap.GenerateInt[0]({ minValue, maxValue, }); @@ -598,7 +597,7 @@ export class SeedService { } if (col.columnType.includes('serial')) { - const generator = new generatorsMap.GenerateIntPrimaryKey[0]!({}); + const generator = new generatorsMap.GenerateIntPrimaryKey[0](); generator.maxValue = maxValue; @@ -617,14 +616,14 @@ export class SeedService { const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); - const generator = new generatorsMap.GenerateNumber[0]!({ + const generator = new generatorsMap.GenerateNumber[0]({ minValue: -maxAbsoluteValue, maxValue: maxAbsoluteValue, precision: Math.pow(10, scale), }); return generator; } - const generator = new generatorsMap.GenerateNumber[0]!({}); + const generator = new generatorsMap.GenerateNumber[0](); return generator; } @@ -636,7 +635,7 @@ export class SeedService { || col.columnType.startsWith('char')) && table.primaryKeys.includes(col.name) ) { - const generator = new generatorsMap.GenerateUniqueString[0]!({}); + const generator = new generatorsMap.GenerateUniqueString[0](); return generator; } @@ -647,7 +646,7 @@ export class SeedService { || col.columnType.startsWith('char')) && col.name.toLowerCase().includes('name') ) { - const generator = new generatorsMap.GenerateFirstName[0]!({}); + const generator = new generatorsMap.GenerateFirstName[0](); return generator; } @@ -658,7 +657,7 @@ export class SeedService { || col.columnType.startsWith('char')) && col.name.toLowerCase().includes('email') ) { - const generator = new generatorsMap.GenerateEmail[0]!({}); + const generator = new generatorsMap.GenerateEmail[0](); return generator; } @@ -668,47 +667,47 @@ export class SeedService { || col.columnType.startsWith('varchar') || col.columnType.startsWith('char') ) { - const generator = new generatorsMap.GenerateString[0]!({}); + const generator = new generatorsMap.GenerateString[0](); return generator; } // UUID if (col.columnType === 'uuid') { - const generator = new generatorsMap.GenerateUUID[0]!({}); + const generator = new generatorsMap.GenerateUUID[0](); return generator; } // BOOLEAN if (col.columnType === 'boolean') { - const generator = new generatorsMap.GenerateBoolean[0]!({}); + const generator = new generatorsMap.GenerateBoolean[0](); return generator; } // DATE, TIME, TIMESTAMP if (col.columnType.includes('date')) { - const generator = new generatorsMap.GenerateDate[0]!({}); + const generator = new generatorsMap.GenerateDate[0](); return generator; } if (col.columnType === 'time') { - const generator = new generatorsMap.GenerateTime[0]!({}); + const generator = new generatorsMap.GenerateTime[0](); return generator; } if (col.columnType.includes('timestamp')) { - const generator = new generatorsMap.GenerateTimestamp[0]!({}); + const generator = new generatorsMap.GenerateTimestamp[0](); return generator; } // JSON, JSONB if (col.columnType === 'json' || col.columnType === 'jsonb') { - const generator = new generatorsMap.GenerateJson[0]!({}); + const generator = new generatorsMap.GenerateJson[0](); return generator; } @@ -720,7 +719,7 @@ export class SeedService { // ENUM if (col.enumValues !== undefined) { - const generator = new generatorsMap.GenerateEnum[0]!({ + const generator = new generatorsMap.GenerateEnum[0]({ enumValues: col.enumValues, }); @@ -730,32 +729,32 @@ export class SeedService { // INTERVAL if (col.columnType.startsWith('interval')) { if (col.columnType === 'interval') { - const generator = new generatorsMap.GenerateInterval[0]!({}); + const generator = new generatorsMap.GenerateInterval[0](); return generator; } const fields = col.columnType.replace('interval ', '') as GenerateInterval['params']['fields']; - const generator = new generatorsMap.GenerateInterval[0]!({ fields }); + const generator = new generatorsMap.GenerateInterval[0]({ fields }); return generator; } // POINT, LINE if (col.columnType.includes('point')) { - const generator = new generatorsMap.GeneratePoint[0]!({}); + const generator = new generatorsMap.GeneratePoint[0](); return generator; } if (col.columnType.includes('line')) { - const generator = new generatorsMap.GenerateLine[0]!({}); + const generator = new generatorsMap.GenerateLine[0](); return generator; } if (col.hasDefault && col.default !== undefined) { - const generator = new generatorsMap.GenerateDefault[0]!({ + const generator = new generatorsMap.GenerateDefault[0]({ defaultValue: col.default, }); return generator; @@ -784,7 +783,7 @@ export class SeedService { (col.columnType.includes('serial') || col.columnType.includes('int')) && table.primaryKeys.includes(col.name) ) { - const generator = new generatorsMap.GenerateIntPrimaryKey[0]!({}); + const generator = new generatorsMap.GenerateIntPrimaryKey[0](); return generator; } @@ -819,7 +818,7 @@ export class SeedService { } if (col.columnType.includes('int')) { - const generator = new generatorsMap.GenerateInt[0]!({ + const generator = new generatorsMap.GenerateInt[0]({ minValue, maxValue, }); @@ -827,7 +826,7 @@ export class SeedService { } if (col.columnType.includes('serial')) { - const generator = new generatorsMap.GenerateIntPrimaryKey[0]!({}); + const generator = new generatorsMap.GenerateIntPrimaryKey[0](); generator.maxValue = maxValue; return generator; } @@ -845,7 +844,7 @@ export class SeedService { const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); - const generator = new generatorsMap.GenerateNumber[0]!({ + const generator = new generatorsMap.GenerateNumber[0]({ minValue: -maxAbsoluteValue, maxValue: maxAbsoluteValue, precision: Math.pow(10, scale), @@ -853,7 +852,7 @@ export class SeedService { return generator; } - const generator = new generatorsMap.GenerateNumber[0]!({}); + const generator = new generatorsMap.GenerateNumber[0](); return generator; } @@ -867,7 +866,7 @@ export class SeedService { || col.columnType.startsWith('varbinary')) && table.primaryKeys.includes(col.name) ) { - const generator = new generatorsMap.GenerateUniqueString[0]!({}); + const generator = new generatorsMap.GenerateUniqueString[0](); return generator; } @@ -880,7 +879,7 @@ export class SeedService { || col.columnType.startsWith('varbinary')) && col.name.toLowerCase().includes('name') ) { - const generator = new generatorsMap.GenerateFirstName[0]!({}); + const generator = new generatorsMap.GenerateFirstName[0](); return generator; } @@ -893,7 +892,7 @@ export class SeedService { || col.columnType.startsWith('varbinary')) && col.name.toLowerCase().includes('email') ) { - const generator = new generatorsMap.GenerateEmail[0]!({}); + const generator = new generatorsMap.GenerateEmail[0](); return generator; } @@ -905,58 +904,58 @@ export class SeedService { || col.columnType.startsWith('binary') || col.columnType.startsWith('varbinary') ) { - const generator = new generatorsMap.GenerateString[0]!({}); + const generator = new generatorsMap.GenerateString[0](); return generator; } // BOOLEAN if (col.columnType === 'boolean') { - const generator = new generatorsMap.GenerateBoolean[0]!({}); + const generator = new generatorsMap.GenerateBoolean[0](); return generator; } // DATE, TIME, TIMESTAMP, DATETIME, YEAR if (col.columnType.includes('datetime')) { - const generator = new generatorsMap.GenerateDatetime[0]!({}); + const generator = new generatorsMap.GenerateDatetime[0](); return generator; } if (col.columnType.includes('date')) { - const generator = new generatorsMap.GenerateDate[0]!({}); + const generator = new generatorsMap.GenerateDate[0](); return generator; } if (col.columnType === 'time') { - const generator = new generatorsMap.GenerateTime[0]!({}); + const generator = new generatorsMap.GenerateTime[0](); return generator; } if (col.columnType.includes('timestamp')) { - const generator = new generatorsMap.GenerateTimestamp[0]!({}); + const generator = new generatorsMap.GenerateTimestamp[0](); return generator; } if (col.columnType === 'year') { - const generator = new generatorsMap.GenerateYear[0]!({}); + const generator = new generatorsMap.GenerateYear[0](); return generator; } // JSON if (col.columnType === 'json') { - const generator = new generatorsMap.GenerateJson[0]!({}); + const generator = new generatorsMap.GenerateJson[0](); return generator; } // ENUM if (col.enumValues !== undefined) { - const generator = new generatorsMap.GenerateEnum[0]!({ + const generator = new generatorsMap.GenerateEnum[0]({ enumValues: col.enumValues, }); return generator; } if (col.hasDefault && col.default !== undefined) { - const generator = new generatorsMap.GenerateDefault[0]!({ + const generator = new generatorsMap.GenerateDefault[0]({ defaultValue: col.default, }); return generator; @@ -980,17 +979,17 @@ export class SeedService { (col.columnType === 'integer' || col.columnType === 'numeric') && table.primaryKeys.includes(col.name) ) { - const generator = new generatorsMap.GenerateIntPrimaryKey[0]!({}); + const generator = new generatorsMap.GenerateIntPrimaryKey[0](); return generator; } if (col.columnType === 'integer' && col.dataType === 'boolean') { - const generator = new generatorsMap.GenerateBoolean[0]!({}); + const generator = new generatorsMap.GenerateBoolean[0](); return generator; } if ((col.columnType === 'integer' && col.dataType === 'date')) { - const generator = new generatorsMap.GenerateTimestamp[0]!({}); + const generator = new generatorsMap.GenerateTimestamp[0](); return generator; } @@ -998,7 +997,7 @@ export class SeedService { col.columnType === 'integer' || (col.dataType === 'bigint' && col.columnType === 'blob') ) { - const generator = new generatorsMap.GenerateInt[0]!({}); + const generator = new generatorsMap.GenerateInt[0](); return generator; } @@ -1009,7 +1008,7 @@ export class SeedService { const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); - const generator = new generatorsMap.GenerateNumber[0]!({ + const generator = new generatorsMap.GenerateNumber[0]({ minValue: -maxAbsoluteValue, maxValue: maxAbsoluteValue, precision: Math.pow(10, scale), @@ -1017,7 +1016,7 @@ export class SeedService { return generator; } - const generator = new generatorsMap.GenerateNumber[0]!({}); + const generator = new generatorsMap.GenerateNumber[0](); return generator; } @@ -1028,7 +1027,7 @@ export class SeedService { || col.columnType.startsWith('blob')) && table.primaryKeys.includes(col.name) ) { - const generator = new generatorsMap.GenerateUniqueString[0]!({}); + const generator = new generatorsMap.GenerateUniqueString[0](); return generator; } @@ -1038,7 +1037,7 @@ export class SeedService { || col.columnType.startsWith('blob')) && col.name.toLowerCase().includes('name') ) { - const generator = new generatorsMap.GenerateFirstName[0]!({}); + const generator = new generatorsMap.GenerateFirstName[0](); return generator; } @@ -1048,7 +1047,7 @@ export class SeedService { || col.columnType.startsWith('blob')) && col.name.toLowerCase().includes('email') ) { - const generator = new generatorsMap.GenerateEmail[0]!({}); + const generator = new generatorsMap.GenerateEmail[0](); return generator; } @@ -1058,7 +1057,7 @@ export class SeedService { || col.columnType.startsWith('blob') || col.columnType.startsWith('blobbuffer') ) { - const generator = new generatorsMap.GenerateString[0]!({}); + const generator = new generatorsMap.GenerateString[0](); return generator; } @@ -1066,12 +1065,12 @@ export class SeedService { (col.columnType.startsWith('text') && col.dataType === 'json') || (col.columnType.startsWith('blob') && col.dataType === 'json') ) { - const generator = new generatorsMap.GenerateJson[0]!({}); + const generator = new generatorsMap.GenerateJson[0](); return generator; } if (col.hasDefault && col.default !== undefined) { - const generator = new generatorsMap.GenerateDefault[0]!({ + const generator = new generatorsMap.GenerateDefault[0]({ defaultValue: col.default, }); return generator; @@ -1239,7 +1238,7 @@ export class SeedService { }))!.map((rows) => rows[refColName]) as (string | number | boolean)[]; hasSelfRelation = true; - genObj = new generatorsMap.GenerateSelfRelationsValuesFromArray[0]!({ + genObj = new generatorsMap.GenerateSelfRelationsValuesFromArray[0]({ values: refColumnValues, }); genObj = this.selectVersionOfGenerator(genObj); @@ -1264,7 +1263,7 @@ export class SeedService { } // TODO: revise maybe need to select version of generator here too - genObj = new generatorsMap.GenerateValuesFromArray[0]!({ values: refColumnValues }); + genObj = new generatorsMap.GenerateValuesFromArray[0]({ values: refColumnValues }); genObj.notNull = tableGenerators[rel.columns[colIdx]!]!.notNull; genObj.weightedCountSeed = weightedCountSeed; genObj.maxRepeatedValuesCount = repeatedValuesCount; From 414ffd95154df20ce017384dffc5c493b8b13d75 Mon Sep 17 00:00:00 2001 From: Oleksii Khomenko <47694554+OleksiiKH0240@users.noreply.github.com> Date: Wed, 25 Dec 2024 09:30:17 +0200 Subject: [PATCH 464/492] Drizzle seed/studio (#3808) * support varchar for postgres using sql column type * added checks to string-like generators, updated sqlite and mysql seeding using sql column type * added array support for studio * updated postgres interval generators to work with fields, added tests * fixes, partial implementation of generator versioning * added generator versioning with version v1 for string and interval generators * updated changelogs * updated generator versioning * updated changelogs * Review * changes in generator selection * updated generator versioning * bug fix, refine functions versioning * fixes * fixes * Change release notes text * Bump version --------- Co-authored-by: Andrii Sherman --- changelogs/drizzle-seed/0.2.0.md | 166 +++ drizzle-seed/package.json | 4 +- drizzle-seed/src/datasets/adjectives.ts | 2 + drizzle-seed/src/datasets/cityNames.ts | 2 + .../src/datasets/companyNameSuffixes.ts | 2 + drizzle-seed/src/datasets/countries.ts | 2 + drizzle-seed/src/datasets/emailDomains.ts | 2 + drizzle-seed/src/datasets/firstNames.ts | 2 + drizzle-seed/src/datasets/jobsTitles.ts | 2 + drizzle-seed/src/datasets/lastNames.ts | 2 + .../src/datasets/loremIpsumSentences.ts | 2 + drizzle-seed/src/datasets/states.ts | 2 + drizzle-seed/src/datasets/streetSuffix.ts | 2 + drizzle-seed/src/index.ts | 146 +- drizzle-seed/src/services/GeneratorFuncs.ts | 918 ++++++++++++ .../{GeneratorsWrappers.ts => Generators.ts} | 1232 ++++++----------- drizzle-seed/src/services/SeedService.ts | 1142 ++++++++------- drizzle-seed/src/services/apiVersion.ts | 1 + drizzle-seed/src/services/versioning/v2.ts | 232 ++++ drizzle-seed/src/types/seedService.ts | 2 +- drizzle-seed/src/types/tables.ts | 6 + .../tests/benchmarks/generatorsBenchmark.ts | 10 +- .../mysql_all_data_types.test.ts | 2 +- .../tests/pg/allDataTypesTest/pgSchema.ts | 62 +- .../pg_all_data_types.test.ts | 30 + 25 files changed, 2567 insertions(+), 1408 deletions(-) create mode 100644 changelogs/drizzle-seed/0.2.0.md create mode 100644 drizzle-seed/src/services/GeneratorFuncs.ts rename drizzle-seed/src/services/{GeneratorsWrappers.ts => Generators.ts} (73%) create mode 100644 drizzle-seed/src/services/apiVersion.ts create mode 100644 drizzle-seed/src/services/versioning/v2.ts diff --git a/changelogs/drizzle-seed/0.2.0.md b/changelogs/drizzle-seed/0.2.0.md new file mode 100644 index 000000000..a34509510 --- /dev/null +++ b/changelogs/drizzle-seed/0.2.0.md @@ -0,0 +1,166 @@ +## API updates + +We are introducing a new parameter, `version`, to the `seed` function options. This parameter, which controls generator versioning, has been added to make it easier to update deterministic generators in the future. Since values should remain consistent after each regeneration, it is crucial to provide a well-designed API for gradual updates + +```ts +await seed(db, schema, { version: '2' }); +``` + +#### Example: + +> This is not an actual API change; it is just an example of how we will proceed with `drizzle-seed` versioning + +For example, `lastName` generator was changed, and new version, `V2`, of this generator became available. + +Later, `firstName` generator was changed, making `V3` version of this generator available. + +| | `V1` | `V2` | `V3(latest)` | +| :--------------: | :--------------: | :-------------: | :--------------: | +| **LastNameGen** | `LastNameGenV1` | `LastNameGenV2` | | +| **FirstNameGen** | `FirstNameGenV1` | | `FirstNameGenV3` | + + +##### Use the `firstName` generator of version 3 and the `lastName` generator of version 2 +```ts +await seed(db, schema); +``` + +If you are not ready to use latest generator version right away, you can specify max version to use + +##### Use the `firstName` generator of version 1 and the `lastName` generator of version 2 +```ts +await seed(db, schema, { version: '2' }); +``` + +##### Use the `firstName` generator of version 1 and the `lastName` generator of version 1. +```ts +await seed(db, schema, { version: '1' }); +``` + +Each update with breaking changes for generators will be documented on our docs and in release notes, explaining which version you should use, if you are not ready to upgrade the way generators works + +## Breaking changes + +### `interval` unique generator was changed and upgraded to v2 + +```ts +await seed(db, { table }).refine((f) => ({ + table: { + columns: { + // this function usage will output different values with the same `seed` number from previous version + column1: f.interval({ isUnique: true }), + } + } +})) +``` + +**Reason for upgrade** +An older version of the generator could produce intervals like `1 minute 60 seconds` and `2 minutes 0 seconds`, treating them as distinct intervals. +However, when the `1 minute 60 seconds` interval is inserted into a PostgreSQL database, it is automatically converted to `2 minutes 0 seconds`. As a result, attempting to insert the `2 minutes 0 seconds` interval into a unique column afterwards will cause an error + +**Usage** +```ts +await seed(db, schema); +// or explicit +await seed(db, schema, { version: '2' }); +``` + +**Switch to the old version** +```ts +await seed(db, schema, { version: '1' }); +``` + +### `string` generators were changed and upgraded to v2 + +```ts +await seed(db, { table }).refine((f) => ({ + table: { + columns: { + // this function will output different values with the same `seed` number from previous version + column1: f.string(), + } + } +})) +``` + +**Reason to upgrade** + +Ability to generate a unique string based on the length of the text column (e.g., `varchar(20)`) + +#### PostgreSQL changes + +Default generators for `text`, `varchar`, `char` will output different values with the same `seed` number from previous version. + +```ts +// schema.ts +import * as p from 'drizzle-orm/pg-core' + +export const table = p.pgTable('table', { + column1: p.text(), + column2: p.varchar(), + column3: p.char() +}); + +// index.ts +... +// this will be affected with new changes +await seed(db, { table }); +``` + +**Switch to the old version** +```ts +await seed(db, schema, { version: '' }); +``` + +#### MySQL changes + +Default generators for `text`, `char`, `varchar`, `binary`, `varbinary` will output different values with the same `seed` number. + +```ts +// schema.ts +import * as p from 'drizzle-orm/mysql-core' + +export const table = p.mysqlTable('table', { + column1: p.text(), + column2: p.char(), + column3: p.varchar({ length: 256 }), + column4: p.binary(), + column5: p.varbinary({ length: 256 }), +}); + +// index.ts +... +// this will be affected with new changes +await seed(db, {table}) +``` + +**Switch to the old version** +```ts +await seed(db, schema, { version: '1' }); +``` + +#### SQLite changes + +Default generators for `text`, `numeric`, `blob`, `blobbuffer` will output different values with the same `seed` number. +```ts +// schema.ts +import * as p from 'drizzle-orm/sqlite-core' + +export const table = p.sqliteTable('table', { + column1: p.text(), + column2: p.numeric(), + column3: p.blob({ mode:'buffer' }), + column4: p.blob(), +}); + +// index.ts +... +// this will be affected with new changes +await seed(db, { table }) +``` + +Functions from refine that will be affected by this change: `` + +## Bug fixes +- Seeding a table with a foreign key referencing another table, without including the second table in the schema, will cause the seeding process to get stuck +- [[BUG]: seeding postgresql char column doesn't respect length option](https://github.com/drizzle-team/drizzle-orm/issues/3774) \ No newline at end of file diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index bfa0e39ad..ae5648cdb 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-seed", - "version": "0.1.3", + "version": "0.2.0", "main": "index.js", "type": "module", "scripts": { @@ -102,4 +102,4 @@ "dependencies": { "pure-rand": "^6.1.0" } -} +} \ No newline at end of file diff --git a/drizzle-seed/src/datasets/adjectives.ts b/drizzle-seed/src/datasets/adjectives.ts index c2b152af0..880e52636 100644 --- a/drizzle-seed/src/datasets/adjectives.ts +++ b/drizzle-seed/src/datasets/adjectives.ts @@ -4844,3 +4844,5 @@ export default [ 'zonked', 'zoological', ]; + +export const maxStringLength = 22; diff --git a/drizzle-seed/src/datasets/cityNames.ts b/drizzle-seed/src/datasets/cityNames.ts index 780b55213..3ea80747e 100644 --- a/drizzle-seed/src/datasets/cityNames.ts +++ b/drizzle-seed/src/datasets/cityNames.ts @@ -42857,3 +42857,5 @@ export default [ 'Garches', 'Chemini', ]; + +export const maxStringLength = 49; diff --git a/drizzle-seed/src/datasets/companyNameSuffixes.ts b/drizzle-seed/src/datasets/companyNameSuffixes.ts index ae8ce6163..1ce31a9c3 100644 --- a/drizzle-seed/src/datasets/companyNameSuffixes.ts +++ b/drizzle-seed/src/datasets/companyNameSuffixes.ts @@ -25,3 +25,5 @@ export default [ 'Co.', 'SCC', ]; + +export const maxStringLength = 7; diff --git a/drizzle-seed/src/datasets/countries.ts b/drizzle-seed/src/datasets/countries.ts index 4808fc5e5..eb1c001d0 100644 --- a/drizzle-seed/src/datasets/countries.ts +++ b/drizzle-seed/src/datasets/countries.ts @@ -169,3 +169,5 @@ export default [ 'Yemen', 'Zambia', ]; + +export const maxStringLength = 30; diff --git a/drizzle-seed/src/datasets/emailDomains.ts b/drizzle-seed/src/datasets/emailDomains.ts index 9904aad3e..ea323ed41 100644 --- a/drizzle-seed/src/datasets/emailDomains.ts +++ b/drizzle-seed/src/datasets/emailDomains.ts @@ -22,3 +22,5 @@ export default [ 'ymail.com', 'libero.it', ]; + +export const maxStringLength = 14; diff --git a/drizzle-seed/src/datasets/firstNames.ts b/drizzle-seed/src/datasets/firstNames.ts index 7ca0ff928..d719aa4e2 100644 --- a/drizzle-seed/src/datasets/firstNames.ts +++ b/drizzle-seed/src/datasets/firstNames.ts @@ -30277,3 +30277,5 @@ export default [ 'Lavasia', 'Laniqua', ]; + +export const maxStringLength = 15; diff --git a/drizzle-seed/src/datasets/jobsTitles.ts b/drizzle-seed/src/datasets/jobsTitles.ts index 3a38e3244..e7993da2a 100644 --- a/drizzle-seed/src/datasets/jobsTitles.ts +++ b/drizzle-seed/src/datasets/jobsTitles.ts @@ -150,3 +150,5 @@ export default [ 'Legal secretary', 'Market analyst', ]; + +export const maxStringLength = 35; diff --git a/drizzle-seed/src/datasets/lastNames.ts b/drizzle-seed/src/datasets/lastNames.ts index 117c5fe28..9d35f7cf7 100644 --- a/drizzle-seed/src/datasets/lastNames.ts +++ b/drizzle-seed/src/datasets/lastNames.ts @@ -50001,3 +50001,5 @@ export default [ 'Thagard', 'Leavelle', ]; + +export const maxStringLength = 15; diff --git a/drizzle-seed/src/datasets/loremIpsumSentences.ts b/drizzle-seed/src/datasets/loremIpsumSentences.ts index f03277d86..64fe59f71 100644 --- a/drizzle-seed/src/datasets/loremIpsumSentences.ts +++ b/drizzle-seed/src/datasets/loremIpsumSentences.ts @@ -1637,3 +1637,5 @@ export default [ 'Sed gravida enim quis nunc interdum imperdiet.', 'Proin cursus odio ac dolor blandit, quis sollicitudin ante rutrum.', ]; + +export const maxStringLength = 190; diff --git a/drizzle-seed/src/datasets/states.ts b/drizzle-seed/src/datasets/states.ts index 1de77160d..cd66cf330 100644 --- a/drizzle-seed/src/datasets/states.ts +++ b/drizzle-seed/src/datasets/states.ts @@ -50,3 +50,5 @@ export default [ 'Wisconsin', 'Wyoming', ]; + +export const maxStringLength = 14; diff --git a/drizzle-seed/src/datasets/streetSuffix.ts b/drizzle-seed/src/datasets/streetSuffix.ts index e9b20c392..90a70c2c6 100644 --- a/drizzle-seed/src/datasets/streetSuffix.ts +++ b/drizzle-seed/src/datasets/streetSuffix.ts @@ -198,3 +198,5 @@ export default [ 'Well', 'Wells', ]; + +export const maxStringLength = 10; diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 603512fd3..98c449095 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -1,4 +1,5 @@ -import { entityKind, getTableName, is, sql } from 'drizzle-orm'; +/* eslint-disable drizzle-internal/require-entity-kind */ +import { getTableName, is, sql } from 'drizzle-orm'; import type { MySqlColumn, MySqlSchema } from 'drizzle-orm/mysql-core'; import { getTableConfig as getMysqlTableConfig, MySqlDatabase, MySqlTable } from 'drizzle-orm/mysql-core'; @@ -9,8 +10,8 @@ import { getTableConfig as getPgTableConfig, PgDatabase, PgTable } from 'drizzle import type { SQLiteColumn } from 'drizzle-orm/sqlite-core'; import { BaseSQLiteDatabase, getTableConfig as getSqliteTableConfig, SQLiteTable } from 'drizzle-orm/sqlite-core'; -import type { AbstractGenerator } from './services/GeneratorsWrappers.ts'; -import { generatorsFuncs } from './services/GeneratorsWrappers.ts'; +import { generatorsFuncs, generatorsFuncsV2 } from './services/GeneratorFuncs.ts'; +import type { AbstractGenerator } from './services/Generators.ts'; import { SeedService } from './services/SeedService.ts'; import type { DrizzleStudioObjectType, DrizzleStudioRelationType } from './types/drizzleStudio.ts'; import type { RefinementsType } from './types/seedService.ts'; @@ -130,15 +131,16 @@ class SeedPromise< SCHEMA extends { [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable; }, + VERSION extends string | undefined, > implements Promise { - static readonly [entityKind]: string = 'SeedPromise'; + static readonly entityKind: string = 'SeedPromise'; [Symbol.toStringTag] = 'SeedPromise'; constructor( private db: DB, private schema: SCHEMA, - private options?: { count?: number; seed?: number }, + private options?: { count?: number; seed?: number; version?: VERSION }, ) {} then( @@ -180,14 +182,22 @@ class SeedPromise< } async refine( - callback: (funcs: typeof generatorsFuncs) => InferCallbackType, + callback: ( + funcs: FunctionsVersioning, + ) => InferCallbackType, ): Promise { - const refinements = callback(generatorsFuncs) as RefinementsType; + const refinements = this.options?.version === undefined || this.options.version === '2' + ? callback(generatorsFuncsV2 as FunctionsVersioning) as RefinementsType + : callback(generatorsFuncs as FunctionsVersioning) as RefinementsType; await seedFunc(this.db, this.schema, this.options, refinements); } } +type FunctionsVersioning = VERSION extends `1` ? typeof generatorsFuncs + : VERSION extends `2` ? typeof generatorsFuncsV2 + : typeof generatorsFuncsV2; + export function getGeneratorsFunctions() { return generatorsFuncs; } @@ -222,6 +232,8 @@ export async function seedForDrizzleStudio( name: col.name, dataType: 'string', columnType: col.type, + // TODO: revise later + typeParams: {}, default: col.default, hasDefault: col.default === undefined ? false : true, isUnique: col.isUnique === undefined ? false : col.isUnique, @@ -257,7 +269,6 @@ export async function seedForDrizzleStudio( sqlDialect, tables, isCyclicRelations, - {}, // TODO: fix later refinements, options, ); @@ -324,7 +335,7 @@ export async function seedForDrizzleStudio( export function seed< DB extends | PgDatabase - | MySqlDatabase + | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { [key: string]: @@ -335,8 +346,9 @@ export function seed< | SQLiteTable | any; }, ->(db: DB, schema: SCHEMA, options?: { count?: number; seed?: number }) { - return new SeedPromise(db, schema, options); + VERSION extends '2' | '1' | undefined, +>(db: DB, schema: SCHEMA, options?: { count?: number; seed?: number; version?: VERSION }) { + return new SeedPromise(db, schema, options); } const seedFunc = async ( @@ -350,21 +362,26 @@ const seedFunc = async ( | SQLiteTable | any; }, - options: { count?: number; seed?: number } = {}, + options: { count?: number; seed?: number; version?: string } = {}, refinements?: RefinementsType, ) => { + let version: number | undefined; + if (options?.version !== undefined) { + version = Number(options?.version); + } + if (is(db, PgDatabase)) { const { pgSchema } = filterPgTables(schema); - await seedPostgres(db, pgSchema, options, refinements); + await seedPostgres(db, pgSchema, { ...options, version }, refinements); } else if (is(db, MySqlDatabase)) { const { mySqlSchema } = filterMySqlTables(schema); - await seedMySql(db, mySqlSchema, options, refinements); + await seedMySql(db, mySqlSchema, { ...options, version }, refinements); } else if (is(db, BaseSQLiteDatabase)) { const { sqliteSchema } = filterSqliteTables(schema); - await seedSqlite(db, sqliteSchema, options, refinements); + await seedSqlite(db, sqliteSchema, { ...options, version }, refinements); } else { throw new Error( 'The drizzle-seed package currently supports only PostgreSQL, MySQL, and SQLite databases. Please ensure your database is one of these supported types', @@ -417,7 +434,7 @@ const seedFunc = async ( export async function reset< DB extends | PgDatabase - | MySqlDatabase + | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { [key: string]: @@ -488,17 +505,16 @@ const filterPgTables = (schema: { const seedPostgres = async ( db: PgDatabase, schema: { [key: string]: PgTable }, - options: { count?: number; seed?: number } = {}, + options: { count?: number; seed?: number; version?: number } = {}, refinements?: RefinementsType, ) => { const seedService = new SeedService(); - const { tables, relations, tableRelations } = getPostgresInfo(schema); + const { tables, relations } = getPostgresInfo(schema); const generatedTablesGenerators = seedService.generatePossibleGenerators( 'postgresql', tables, relations, - tableRelations, refinements, options, ); @@ -608,7 +624,8 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { ): Column['baseColumn'] => { const baseColumnResult: Column['baseColumn'] = { name: baseColumn.name, - columnType: baseColumn.columnType.replace('Pg', '').toLowerCase(), + columnType: baseColumn.getSQLType(), + typeParams: getTypeParams(baseColumn.getSQLType()), dataType: baseColumn.dataType, size: (baseColumn as PgArray).size, hasDefault: baseColumn.hasDefault, @@ -623,12 +640,54 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { return baseColumnResult; }; + const getTypeParams = (sqlType: string) => { + // get type params + const typeParams: Column['typeParams'] = {}; + + // handle dimensions + if (sqlType.includes('[')) { + const match = sqlType.match(/\[\w*]/g); + if (match) { + typeParams['dimensions'] = match.length; + } + } + + if ( + sqlType.startsWith('numeric') + || sqlType.startsWith('decimal') + || sqlType.startsWith('double precision') + || sqlType.startsWith('real') + ) { + const match = sqlType.match(/\((\d+), *(\d+)\)/); + if (match) { + typeParams['precision'] = Number(match[1]); + typeParams['scale'] = Number(match[2]); + } + } else if ( + sqlType.startsWith('varchar') + || sqlType.startsWith('bpchar') + || sqlType.startsWith('char') + || sqlType.startsWith('bit') + || sqlType.startsWith('time') + || sqlType.startsWith('timestamp') + || sqlType.startsWith('interval') + ) { + const match = sqlType.match(/\((\d+)\)/); + if (match) { + typeParams['length'] = Number(match[1]); + } + } + + return typeParams; + }; + // console.log(tableConfig.columns); tables.push({ name: dbToTsTableNamesMap[tableConfig.name] as string, columns: tableConfig.columns.map((column) => ({ name: dbToTsColumnNamesMap[column.name] as string, - columnType: column.columnType.replace('Pg', '').toLowerCase(), + columnType: column.getSQLType(), + typeParams: getTypeParams(column.getSQLType()), dataType: column.dataType, size: (column as PgArray).size, hasDefault: column.hasDefault, @@ -739,10 +798,10 @@ const filterMySqlTables = (schema: { const seedMySql = async ( db: MySqlDatabase, schema: { [key: string]: MySqlTable }, - options: { count?: number; seed?: number } = {}, + options: { count?: number; seed?: number; version?: number } = {}, refinements?: RefinementsType, ) => { - const { tables, relations, tableRelations } = getMySqlInfo(schema); + const { tables, relations } = getMySqlInfo(schema); const seedService = new SeedService(); @@ -750,7 +809,6 @@ const seedMySql = async ( 'mysql', tables, relations, - tableRelations, refinements, options, ); @@ -853,11 +911,41 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { } tableRelations[dbToTsTableNamesMap[tableConfig.name] as string]!.push(...newRelations); + const getTypeParams = (sqlType: string) => { + // get type params and set only type + const typeParams: Column['typeParams'] = {}; + + if ( + sqlType.startsWith('decimal') + || sqlType.startsWith('real') + || sqlType.startsWith('double') + || sqlType.startsWith('float') + ) { + const match = sqlType.match(/\((\d+), *(\d+)\)/); + if (match) { + typeParams['precision'] = Number(match[1]); + typeParams['scale'] = Number(match[2]); + } + } else if ( + sqlType.startsWith('varchar') + || sqlType.startsWith('binary') + || sqlType.startsWith('varbinary') + ) { + const match = sqlType.match(/\((\d+)\)/); + if (match) { + typeParams['length'] = Number(match[1]); + } + } + + return typeParams; + }; + tables.push({ name: dbToTsTableNamesMap[tableConfig.name] as string, columns: tableConfig.columns.map((column) => ({ name: dbToTsColumnNamesMap[column.name] as string, - columnType: column.columnType.replace('MySql', '').toLowerCase(), + columnType: column.getSQLType(), + typeParams: getTypeParams(column.getSQLType()), dataType: column.dataType, hasDefault: column.hasDefault, default: column.default, @@ -928,10 +1016,10 @@ const filterSqliteTables = (schema: { const seedSqlite = async ( db: BaseSQLiteDatabase, schema: { [key: string]: SQLiteTable }, - options: { count?: number; seed?: number } = {}, + options: { count?: number; seed?: number; version?: number } = {}, refinements?: RefinementsType, ) => { - const { tables, relations, tableRelations } = getSqliteInfo(schema); + const { tables, relations } = getSqliteInfo(schema); const seedService = new SeedService(); @@ -939,7 +1027,6 @@ const seedSqlite = async ( 'sqlite', tables, relations, - tableRelations, refinements, options, ); @@ -1046,7 +1133,8 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { name: dbToTsTableNamesMap[tableConfig.name] as string, columns: tableConfig.columns.map((column) => ({ name: dbToTsColumnNamesMap[column.name] as string, - columnType: column.columnType.replace('SQLite', '').toLowerCase(), + columnType: column.getSQLType(), + typeParams: {}, dataType: column.dataType, hasDefault: column.hasDefault, default: column.default, diff --git a/drizzle-seed/src/services/GeneratorFuncs.ts b/drizzle-seed/src/services/GeneratorFuncs.ts new file mode 100644 index 000000000..10d0d10f7 --- /dev/null +++ b/drizzle-seed/src/services/GeneratorFuncs.ts @@ -0,0 +1,918 @@ +import type { AbstractGenerator } from './Generators.ts'; +import { + GenerateArray, + GenerateBoolean, + GenerateCity, + GenerateCompanyName, + GenerateCountry, + GenerateDate, + GenerateDatetime, + GenerateDefault, + GenerateEmail, + GenerateEnum, + GenerateFirstName, + GenerateFullName, + GenerateInt, + GenerateInterval, + GenerateIntPrimaryKey, + GenerateJobTitle, + GenerateJson, + GenerateLastName, + GenerateLine, + GenerateLoremIpsum, + GenerateNumber, + GeneratePhoneNumber, + GeneratePoint, + GeneratePostcode, + GenerateSelfRelationsValuesFromArray, + GenerateState, + GenerateStreetAddress, + GenerateString, + GenerateTime, + GenerateTimestamp, + GenerateUniqueCity, + GenerateUniqueCompanyName, + GenerateUniqueCountry, + GenerateUniqueFirstName, + GenerateUniqueFullName, + GenerateUniqueInt, + GenerateUniqueInterval, + GenerateUniqueLastName, + GenerateUniqueLine, + GenerateUniqueNumber, + GenerateUniquePoint, + GenerateUniquePostcode, + GenerateUniqueStreetAddress, + GenerateUniqueString, + GenerateUUID, + GenerateValuesFromArray, + GenerateWeightedCount, + GenerateYear, + HollowGenerator, + WeightedRandomGenerator, +} from './Generators.ts'; +import { GenerateStringV2, GenerateUniqueIntervalV2, GenerateUniqueStringV2 } from './versioning/v2.ts'; + +function createGenerator, T>( + generatorConstructor: new(params?: T) => GeneratorType, +) { + return ( + ...args: GeneratorType extends GenerateValuesFromArray | GenerateDefault | WeightedRandomGenerator ? [T] + : ([] | [T]) + ): GeneratorType => { + let params = args[0]; + if (params === undefined) params = {} as T; + return new generatorConstructor(params); + }; +} + +export const generatorsFuncs = { + /** + * generates same given value each time the generator is called. + * @param defaultValue - value you want to generate + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.default({ defaultValue: "post content" }), + * }, + * }, + * })); + * ``` + */ + default: createGenerator(GenerateDefault), + + /** + * generates values from given array + * @param values - array of values you want to generate. can be array of weighted values. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * title: funcs.valuesFromArray({ + * values: ["Title1", "Title2", "Title3", "Title4", "Title5"], + * isUnique: true + * }), + * }, + * }, + * })); + * + * ``` + * weighted values example + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * title: funcs.valuesFromArray({ + * values: [ + * { weight: 0.35, values: ["Title1", "Title2"] }, + * { weight: 0.5, values: ["Title3", "Title4"] }, + * { weight: 0.15, values: ["Title5"] }, + * ], + * isUnique: false + * }), + * }, + * }, + * })); + * + * ``` + */ + valuesFromArray: createGenerator(GenerateValuesFromArray), + + /** + * generates sequential integers starting with 1. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * id: funcs.intPrimaryKey(), + * }, + * }, + * })); + * + * ``` + */ + intPrimaryKey: createGenerator(GenerateIntPrimaryKey), + + /** + * generates numbers with floating point in given range. + * @param minValue - lower border of range. + * @param maxValue - upper border of range. + * @param precision - precision of generated number: + * precision equals 10 means that values will be accurate to one tenth (1.2, 34.6); + * precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67). + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * products: { + * columns: { + * unitPrice: funcs.number({ minValue: 10, maxValue: 120, precision: 100, isUnique: false }), + * }, + * }, + * })); + * + * ``` + */ + number: createGenerator(GenerateNumber), + // uniqueNumber: createGenerator(GenerateUniqueNumber), + + /** + * generates integers within given range. + * @param minValue - lower border of range. + * @param maxValue - upper border of range. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * products: { + * columns: { + * unitsInStock: funcs.number({ minValue: 0, maxValue: 100, isUnique: false }), + * }, + * }, + * })); + * + * ``` + */ + int: createGenerator(GenerateInt), + // uniqueInt: createGenerator(GenerateUniqueInt), + + /** + * generates boolean values(true or false) + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * isAvailable: funcs.boolean() + * }, + * }, + * })); + * + * ``` + */ + boolean: createGenerator(GenerateBoolean), + + /** + * generates date within given range. + * @param minDate - lower border of range. + * @param maxDate - upper border of range. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthDate: funcs.date({ minDate: "1990-01-01", maxDate: "2010-12-31" }) + * }, + * }, + * })); + * + * ``` + */ + date: createGenerator(GenerateDate), + + /** + * generates time in 24 hours style. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthTime: funcs.time() + * }, + * }, + * })); + * + * ``` + */ + time: createGenerator(GenerateTime), + + /** + * generates timestamps. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * orders: { + * columns: { + * shippedDate: funcs.timestamp() + * }, + * }, + * })); + * + * ``` + */ + timestamp: createGenerator(GenerateTimestamp), + + /** + * generates datetime objects. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * orders: { + * columns: { + * shippedDate: funcs.datetime() + * }, + * }, + * })); + * + * ``` + */ + datetime: createGenerator(GenerateDatetime), + + /** + * generates years. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * birthYear: funcs.year() + * }, + * }, + * })); + * + * ``` + */ + year: createGenerator(GenerateYear), + + /** + * generates json objects with fixed structure. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * json structure can equal this: + * ``` + * { + * email, + * name, + * isGraduated, + * hasJob, + * salary, + * startedWorking, + * visitedCountries, + * } + * ``` + * or this + * ``` + * { + * email, + * name, + * isGraduated, + * hasJob, + * visitedCountries, + * } + * ``` + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * metadata: funcs.json() + * }, + * }, + * })); + * ``` + */ + json: createGenerator(GenerateJson), + // jsonb: createGenerator(GenerateJsonb), + + /** + * generates time intervals. + * + * interval example: "1 years 12 days 5 minutes" + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * @param fields - range of values you want to see in your intervals. + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * timeSpentOnWebsite: funcs.interval() + * }, + * }, + * })); + * ``` + */ + interval: createGenerator(GenerateInterval), + // uniqueInterval: createGenerator(GenerateUniqueInterval), + + /** + * generates random strings. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * hashedPassword: funcs.string({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + string: createGenerator(GenerateString), + // uniqueString: createGenerator(GenerateUniqueString), + + /** + * generates v4 UUID strings if arraySize is not specified, or v4 UUID 1D arrays if it is. + * + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * uuid: funcs.uuid({ + * arraySize: 4 + * }) + * }, + * }, + * })); + * ``` + */ + uuid: createGenerator(GenerateUUID), + + /** + * generates person's first names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * firstName: funcs.firstName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + firstName: createGenerator(GenerateFirstName), + // uniqueFirstName: createGenerator(GenerateUniqueName), + + /** + * generates person's last names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * lastName: funcs.lastName({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + lastName: createGenerator(GenerateLastName), + // uniqueLastName: createGenerator(GenerateUniqueSurname), + + /** + * generates person's full names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * fullName: funcs.fullName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + fullName: createGenerator(GenerateFullName), + // uniqueFullName: createGenerator(GenerateUniqueFullName), + + /** + * generates unique emails. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * email: funcs.email() + * }, + * }, + * })); + * ``` + */ + email: createGenerator(GenerateEmail), + + /** + * generates unique phone numbers. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @param template - phone number template, where all '#' symbols will be substituted with generated digits. + * @param prefixes - array of any string you want to be your phone number prefixes.(not compatible with template property) + * @param generatedDigitsNumbers - number of digits that will be added at the end of prefixes.(not compatible with template property) + * @example + * ```ts + * //generate phone number using template property + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({template: "+(380) ###-####"}) + * }, + * }, + * })); + * + * //generate phone number using prefixes and generatedDigitsNumbers properties + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67" ], generatedDigitsNumbers: 7}) + * }, + * }, + * })); + * + * //generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67", "+1" ], generatedDigitsNumbers: [7, 7, 10]}) + * }, + * }, + * })); + * + * ``` + */ + phoneNumber: createGenerator(GeneratePhoneNumber), + + /** + * generates country's names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * country: funcs.country({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + country: createGenerator(GenerateCountry), + // uniqueCountry: createGenerator(GenerateUniqueCountry), + + /** + * generates city's names. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * city: funcs.city({isUnique: false}) + * }, + * }, + * })); + * ``` + */ + city: createGenerator(GenerateCity), + // uniqueCity: createGenerator(GenerateUniqueCityName), + + /** + * generates street address. + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * streetAddress: funcs.streetAddress({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + streetAddress: createGenerator(GenerateStreetAddress), + // uniqueStreetAddress: createGenerator(GenerateUniqueStreetAddress), + + /** + * generates job titles. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * jobTitle: funcs.jobTitle() + * }, + * }, + * })); + * ``` + */ + jobTitle: createGenerator(GenerateJobTitle), + + /** + * generates postal codes. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * postcode: funcs.postcode({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + postcode: createGenerator(GeneratePostcode), + // uniquePostcoe: createGenerator(GenerateUniquePostcode), + + /** + * generates states of America. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * state: funcs.state() + * }, + * }, + * })); + * ``` + */ + state: createGenerator(GenerateState), + + /** + * generates company's names. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * users: { + * columns: { + * company: funcs.companyName({isUnique: true}) + * }, + * }, + * })); + * ``` + */ + companyName: createGenerator(GenerateCompanyName), + // uniqueCompanyName: createGenerator(GenerateUniqueCompanyName), + + /** + * generates 'lorem ipsum' text sentences. + * + * @param sentencesCount - number of sentences you want to generate as one generated value(string). + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.loremIpsum({sentencesCount: 2}) + * }, + * }, + * })); + * ``` + */ + loremIpsum: createGenerator(GenerateLoremIpsum), + + /** + * generates 2D points within specified ranges for x and y coordinates. + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param minXValue - lower bound of range for x coordinate. + * @param maxXValue - upper bound of range for x coordinate. + * @param minYValue - lower bound of range for y coordinate. + * @param maxYValue - upper bound of range for y coordinate. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * triangles: { + * columns: { + * pointCoords: funcs.point({ + * isUnique: true, + * minXValue: -5, maxXValue:20, + * minYValue: 0, maxYValue: 30 + * }) + * }, + * }, + * })); + * ``` + */ + point: createGenerator(GeneratePoint), + // uniquePoint: createGenerator(GenerateUniquePoint), + + /** + * generates 2D lines within specified ranges for a, b and c parameters of line. + * + * ``` + * line equation: a*x + b*y + c = 0 + * ``` + * + * @param isUnique - property that controls if generated values gonna be unique or not. + * @param minAValue - lower bound of range for a parameter. + * @param maxAValue - upper bound of range for x parameter. + * @param minBValue - lower bound of range for y parameter. + * @param maxBValue - upper bound of range for y parameter. + * @param minCValue - lower bound of range for y parameter. + * @param maxCValue - upper bound of range for y parameter. + * @param arraySize - number of elements in each one-dimensional array. (If specified, arrays will be generated.) + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * lines: { + * columns: { + * lineParams: funcs.point({ + * isUnique: true, + * minAValue: -5, maxAValue:20, + * minBValue: 0, maxBValue: 30, + * minCValue: 0, maxCValue: 10 + * }) + * }, + * }, + * })); + * ``` + */ + line: createGenerator(GenerateLine), + // uniqueLine: createGenerator(GenerateUniqueLine), + + /** + * gives you the opportunity to call different generators with different probabilities to generate values for one column. + * @param params - array of generators with probabilities you would like to call them to generate values. + * + * @example + * ```ts + * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ + * posts: { + * columns: { + * content: funcs.weightedRandom([ + * { + * weight: 0.6, + * value: funcs.loremIpsum({ sentencesCount: 3 }), + * }, + * { + * weight: 0.4, + * value: funcs.default({ defaultValue: "TODO" }), + * }, + * ]), + * }, + * }, + * })); + * ``` + */ + weightedRandom: createGenerator(WeightedRandomGenerator), +}; + +// so far, version changes don’t affect generator parameters. +export const generatorsFuncsV2 = { + ...generatorsFuncs, +}; + +export const generatorsMap = { + HollowGenerator: [ + HollowGenerator, + ], + GenerateDefault: [ + GenerateDefault, + ], + GenerateValuesFromArray: [ + GenerateValuesFromArray, + ], + GenerateSelfRelationsValuesFromArray: [ + GenerateSelfRelationsValuesFromArray, + ], + GenerateIntPrimaryKey: [ + GenerateIntPrimaryKey, + ], + GenerateNumber: [ + GenerateNumber, + ], + GenerateUniqueNumber: [ + GenerateUniqueNumber, + ], + GenerateInt: [ + GenerateInt, + ], + GenerateUniqueInt: [ + GenerateUniqueInt, + ], + GenerateBoolean: [ + GenerateBoolean, + ], + GenerateDate: [ + GenerateDate, + ], + GenerateTime: [ + GenerateTime, + ], + GenerateTimestamp: [ + GenerateTimestamp, + ], + GenerateDatetime: [ + GenerateDatetime, + ], + GenerateYear: [ + GenerateYear, + ], + GenerateJson: [ + GenerateJson, + ], + GenerateEnum: [ + GenerateEnum, + ], + GenerateInterval: [ + GenerateInterval, + ], + GenerateUniqueInterval: [ + GenerateUniqueInterval, + GenerateUniqueIntervalV2, + ], + GenerateString: [ + GenerateString, + GenerateStringV2, + ], + GenerateUniqueString: [ + GenerateUniqueString, + GenerateUniqueStringV2, + ], + GenerateUUID: [ + GenerateUUID, + ], + GenerateFirstName: [ + GenerateFirstName, + ], + GenerateUniqueFirstName: [ + GenerateUniqueFirstName, + ], + GenerateLastName: [ + GenerateLastName, + ], + GenerateUniqueLastName: [ + GenerateUniqueLastName, + ], + GenerateFullName: [ + GenerateFullName, + ], + GenerateUniqueFullName: [ + GenerateUniqueFullName, + ], + GenerateEmail: [ + GenerateEmail, + ], + GeneratePhoneNumber: [ + GeneratePhoneNumber, + ], + GenerateCountry: [ + GenerateCountry, + ], + GenerateUniqueCountry: [ + GenerateUniqueCountry, + ], + GenerateCity: [ + GenerateCity, + ], + GenerateUniqueCity: [ + GenerateUniqueCity, + ], + GenerateStreetAddress: [ + GenerateStreetAddress, + ], + GenerateUniqueStreetAddress: [ + GenerateUniqueStreetAddress, + ], + GenerateJobTitle: [ + GenerateJobTitle, + ], + GeneratePostcode: [ + GeneratePostcode, + ], + GenerateUniquePostcode: [ + GenerateUniquePostcode, + ], + GenerateState: [ + GenerateState, + ], + GenerateCompanyName: [ + GenerateCompanyName, + ], + GenerateUniqueCompanyName: [ + GenerateUniqueCompanyName, + ], + GenerateLoremIpsum: [ + GenerateLoremIpsum, + ], + GeneratePoint: [ + GeneratePoint, + ], + GenerateUniquePoint: [ + GenerateUniquePoint, + ], + GenerateLine: [ + GenerateLine, + ], + GenerateUniqueLine: [ + GenerateUniqueLine, + ], + WeightedRandomGenerator: [ + WeightedRandomGenerator, + ], + GenerateArray: [ + GenerateArray, + ], + GenerateWeightedCount: [ + GenerateWeightedCount, + ], +} as const; diff --git a/drizzle-seed/src/services/GeneratorsWrappers.ts b/drizzle-seed/src/services/Generators.ts similarity index 73% rename from drizzle-seed/src/services/GeneratorsWrappers.ts rename to drizzle-seed/src/services/Generators.ts index 06d6adeb5..0d285540e 100644 --- a/drizzle-seed/src/services/GeneratorsWrappers.ts +++ b/drizzle-seed/src/services/Generators.ts @@ -1,34 +1,55 @@ -import { entityKind } from 'drizzle-orm'; +/* eslint-disable drizzle-internal/require-entity-kind */ import prand from 'pure-rand'; -import adjectives from '../datasets/adjectives.ts'; -import cityNames from '../datasets/cityNames.ts'; -import companyNameSuffixes from '../datasets/companyNameSuffixes.ts'; -import countries from '../datasets/countries.ts'; -import emailDomains from '../datasets/emailDomains.ts'; -import firstNames from '../datasets/firstNames.ts'; -import jobsTitles from '../datasets/jobsTitles.ts'; -import lastNames from '../datasets/lastNames.ts'; -import loremIpsumSentences from '../datasets/loremIpsumSentences.ts'; +import adjectives, { maxStringLength as maxAdjectiveLength } from '../datasets/adjectives.ts'; +import cityNames, { maxStringLength as maxCityNameLength } from '../datasets/cityNames.ts'; +import companyNameSuffixes, { maxStringLength as maxCompanyNameSuffixLength } from '../datasets/companyNameSuffixes.ts'; +import countries, { maxStringLength as maxCountryLength } from '../datasets/countries.ts'; +import emailDomains, { maxStringLength as maxEmailDomainLength } from '../datasets/emailDomains.ts'; +import firstNames, { maxStringLength as maxFirstNameLength } from '../datasets/firstNames.ts'; +import jobsTitles, { maxStringLength as maxJobTitleLength } from '../datasets/jobsTitles.ts'; +import lastNames, { maxStringLength as maxLastNameLength } from '../datasets/lastNames.ts'; +import loremIpsumSentences, { maxStringLength as maxLoremIpsumLength } from '../datasets/loremIpsumSentences.ts'; import phonesInfo from '../datasets/phonesInfo.ts'; -import states from '../datasets/states.ts'; -import streetSuffix from '../datasets/streetSuffix.ts'; +import states, { maxStringLength as maxStateLength } from '../datasets/states.ts'; +import streetSuffix, { maxStringLength as maxStreetSuffixLength } from '../datasets/streetSuffix.ts'; import { fastCartesianProduct, fillTemplate, getWeightedIndices, isObject } from './utils.ts'; export abstract class AbstractGenerator { - static readonly [entityKind]: string = 'AbstractGenerator'; + static readonly entityKind: string = 'AbstractGenerator'; + static readonly version: number = 1; public isUnique = false; public notNull = false; + + // param for generators which have a unique version of themselves public uniqueVersionOfGen?: new(params: T) => AbstractGenerator; + public dataType?: string; public timeSpent?: number; + + // public arraySize?: number; public baseColumnDataType?: string; - constructor(public params: T) {} + // param for text-like generators + public stringLength?: number; + + // params for GenerateValuesFromArray + public weightedCountSeed?: number | undefined; + public maxRepeatedValuesCount?: number | { weight: number; count: number | number[] }[] | undefined; + + public params: T; + + constructor(params?: T) { + this.params = params === undefined ? {} as T : params as T; + } init(params: { count: number | { weight: number; count: number | number[] }[]; seed: number }): void; init() { + this.updateParams(); + } + + updateParams() { if ((this.params as any).arraySize !== undefined) { this.arraySize = (this.params as any).arraySize; } @@ -46,10 +67,11 @@ export abstract class AbstractGenerator { getEntityKind(): string { const constructor = this.constructor as typeof AbstractGenerator; - return constructor[entityKind]; + return constructor.entityKind; } - replaceIfUnique({ count, seed }: { count: number; seed: number }) { + replaceIfUnique() { + this.updateParams(); if ( this.uniqueVersionOfGen !== undefined && this.isUnique === true @@ -57,10 +79,7 @@ export abstract class AbstractGenerator { const uniqueGen = new this.uniqueVersionOfGen({ ...this.params, }); - uniqueGen.init({ - count, - seed, - }); + uniqueGen.isUnique = this.isUnique; uniqueGen.dataType = this.dataType; @@ -69,9 +88,10 @@ export abstract class AbstractGenerator { return; } - replaceIfArray({ count, seed }: { count: number; seed: number }) { + replaceIfArray() { + this.updateParams(); if (!(this.getEntityKind() === 'GenerateArray') && this.arraySize !== undefined) { - const uniqueGen = this.replaceIfUnique({ count, seed }); + const uniqueGen = this.replaceIfUnique(); const baseColumnGen = uniqueGen === undefined ? this : uniqueGen; baseColumnGen.dataType = this.baseColumnDataType; const arrayGen = new GenerateArray( @@ -80,7 +100,6 @@ export abstract class AbstractGenerator { size: this.arraySize, }, ); - arrayGen.init({ count, seed }); return arrayGen; } @@ -89,22 +108,9 @@ export abstract class AbstractGenerator { } } -function createGenerator, T>( - generatorConstructor: new(params: T) => GeneratorType, -) { - return ( - ...args: GeneratorType extends GenerateValuesFromArray | GenerateDefault | WeightedRandomGenerator ? [T] - : ([] | [T]) - ): GeneratorType => { - let params = args[0]; - if (params === undefined) params = {} as T; - return new generatorConstructor(params); - }; -} - // Generators Classes ----------------------------------------------------------------------------------------------------------------------- export class GenerateArray extends AbstractGenerator<{ baseColumnGen: AbstractGenerator; size?: number }> { - static override readonly [entityKind]: string = 'GenerateArray'; + static override readonly entityKind: string = 'GenerateArray'; public override arraySize = 10; override init({ count, seed }: { count: number; seed: number }) { @@ -124,7 +130,7 @@ export class GenerateArray extends AbstractGenerator<{ baseColumnGen: AbstractGe } export class GenerateWeightedCount extends AbstractGenerator<{}> { - static override readonly [entityKind]: string = 'GenerateWeightedCount'; + static override readonly entityKind: string = 'GenerateWeightedCount'; private state: { rng: prand.RandomGenerator; @@ -162,7 +168,7 @@ export class GenerateWeightedCount extends AbstractGenerator<{}> { } export class HollowGenerator extends AbstractGenerator<{}> { - static override readonly [entityKind]: string = 'HollowGenerator'; + static override readonly entityKind: string = 'HollowGenerator'; override init() {} @@ -173,7 +179,7 @@ export class GenerateDefault extends AbstractGenerator<{ defaultValue: unknown; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateDefault'; + static override readonly entityKind: string = 'GenerateDefault'; generate() { return this.params.defaultValue; @@ -189,10 +195,8 @@ export class GenerateValuesFromArray extends AbstractGenerator< arraySize?: number; } > { - static override readonly [entityKind]: string = 'GenerateValuesFromArray'; + static override readonly entityKind: string = 'GenerateValuesFromArray'; - public weightedCountSeed: number | undefined = undefined; - public maxRepeatedValuesCount?: number | { weight: number; count: number | number[] }[] = undefined; private state: { rng: prand.RandomGenerator; values: @@ -400,7 +404,7 @@ export class GenerateValuesFromArray extends AbstractGenerator< } export class GenerateSelfRelationsValuesFromArray extends AbstractGenerator<{ values: (number | string | boolean)[] }> { - static override readonly [entityKind]: string = 'GenerateSelfRelationsValuesFromArray'; + static override readonly entityKind: string = 'GenerateSelfRelationsValuesFromArray'; private state: { rng: prand.RandomGenerator; @@ -438,7 +442,7 @@ export class GenerateSelfRelationsValuesFromArray extends AbstractGenerator<{ va } export class GenerateIntPrimaryKey extends AbstractGenerator<{}> { - static override readonly [entityKind]: string = 'GenerateIntPrimaryKey'; + static override readonly entityKind: string = 'GenerateIntPrimaryKey'; public maxValue?: number | bigint; @@ -466,7 +470,7 @@ export class GenerateNumber extends AbstractGenerator< arraySize?: number; } > { - static override readonly [entityKind]: string = 'GenerateNumber'; + static override readonly entityKind: string = 'GenerateNumber'; private state: { rng: prand.RandomGenerator; @@ -521,7 +525,7 @@ export class GenerateUniqueNumber extends AbstractGenerator< isUnique?: boolean; } > { - static override readonly [entityKind]: string = 'GenerateUniqueNumber'; + static override readonly entityKind: string = 'GenerateUniqueNumber'; private state: { genUniqueIntObj: GenerateUniqueInt; @@ -573,7 +577,7 @@ export class GenerateInt extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateInt'; + static override readonly entityKind: string = 'GenerateInt'; private state: { rng: prand.RandomGenerator; @@ -641,7 +645,7 @@ export class GenerateUniqueInt extends AbstractGenerator<{ maxValue?: number | bigint; isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniqueInt'; + static override readonly entityKind: string = 'GenerateUniqueInt'; public genMaxRepeatedValuesCount: GenerateDefault | GenerateWeightedCount | undefined; public skipCheck?: boolean = false; @@ -809,7 +813,7 @@ export class GenerateUniqueInt extends AbstractGenerator<{ } export class GenerateBoolean extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateBoolean'; + static override readonly entityKind: string = 'GenerateBoolean'; private state: { rng: prand.RandomGenerator; @@ -840,7 +844,7 @@ export class GenerateDate extends AbstractGenerator<{ maxDate?: string | Date; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateDate'; + static override readonly entityKind: string = 'GenerateDate'; private state: { rng: prand.RandomGenerator; @@ -902,7 +906,7 @@ export class GenerateDate extends AbstractGenerator<{ } } export class GenerateTime extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateTime'; + static override readonly entityKind: string = 'GenerateTime'; private state: { rng: prand.RandomGenerator; @@ -938,7 +942,7 @@ export class GenerateTime extends AbstractGenerator<{ arraySize?: number }> { } } export class GenerateTimestampInt extends AbstractGenerator<{ unitOfTime?: 'seconds' | 'milliseconds' }> { - static override readonly [entityKind]: string = 'GenerateTimestampInt'; + static override readonly entityKind: string = 'GenerateTimestampInt'; private state: { generateTimestampObj: GenerateTimestamp; @@ -971,7 +975,7 @@ export class GenerateTimestampInt extends AbstractGenerator<{ unitOfTime?: 'seco } export class GenerateTimestamp extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateTimestamp'; + static override readonly entityKind: string = 'GenerateTimestamp'; private state: { rng: prand.RandomGenerator; @@ -1015,7 +1019,7 @@ export class GenerateTimestamp extends AbstractGenerator<{ arraySize?: number }> } export class GenerateDatetime extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateDatetime'; + static override readonly entityKind: string = 'GenerateDatetime'; private state: { rng: prand.RandomGenerator; @@ -1059,7 +1063,7 @@ export class GenerateDatetime extends AbstractGenerator<{ arraySize?: number }> } export class GenerateYear extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateYear'; + static override readonly entityKind: string = 'GenerateYear'; private state: { rng: prand.RandomGenerator; @@ -1094,7 +1098,7 @@ export class GenerateYear extends AbstractGenerator<{ arraySize?: number }> { } export class GenerateJson extends AbstractGenerator<{ arraySize?: number }> { - static override readonly [entityKind]: string = 'GenerateJson'; + static override readonly entityKind: string = 'GenerateJson'; private state: { emailGeneratorObj: GenerateEmail; @@ -1198,7 +1202,7 @@ export class GenerateJson extends AbstractGenerator<{ arraySize?: number }> { } export class GenerateEnum extends AbstractGenerator<{ enumValues: (string | number | boolean)[] }> { - static override readonly [entityKind]: string = 'GenerateEnum'; + static override readonly entityKind: string = 'GenerateEnum'; private state: { enumValuesGenerator: GenerateValuesFromArray; @@ -1221,19 +1225,74 @@ export class GenerateEnum extends AbstractGenerator<{ enumValues: (string | numb } export class GenerateInterval extends AbstractGenerator<{ + fields?: + | 'year' + | 'month' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'year to month' + | 'day to hour' + | 'day to minute' + | 'day to second' + | 'hour to minute' + | 'hour to second' + | 'minute to second'; isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateInterval'; + static override readonly entityKind: string = 'GenerateInterval'; - private state: { rng: prand.RandomGenerator } | undefined; - override uniqueVersionOfGen = GenerateUniqueInterval; + private state: { + rng: prand.RandomGenerator; + fieldsToGenerate: string[]; + } | undefined; + override uniqueVersionOfGen: new(params: any) => AbstractGenerator = GenerateUniqueInterval; + private config: { [key: string]: { from: number; to: number } } = { + year: { + from: 0, + to: 5, + }, + month: { + from: 0, + to: 12, + }, + day: { + from: 1, + to: 29, + }, + hour: { + from: 0, + to: 24, + }, + minute: { + from: 0, + to: 60, + }, + second: { + from: 0, + to: 60, + }, + }; override init({ count, seed }: { count: number; seed: number }) { super.init({ count, seed }); + const allFields = ['year', 'month', 'day', 'hour', 'minute', 'second']; + let fieldsToGenerate: string[] = allFields; + + if (this.params.fields !== undefined && this.params.fields?.includes(' to ')) { + const tokens = this.params.fields.split(' to '); + const endIdx = allFields.indexOf(tokens[1]!); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } else if (this.params.fields !== undefined) { + const endIdx = allFields.indexOf(this.params.fields); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } + const rng = prand.xoroshiro128plus(seed); - this.state = { rng }; + this.state = { rng, fieldsToGenerate }; } generate() { @@ -1241,55 +1300,97 @@ export class GenerateInterval extends AbstractGenerator<{ throw new Error('state is not defined.'); } - let yearsNumb: number, - monthsNumb: number, - daysNumb: number, - hoursNumb: number, - minutesNumb: number, - secondsNumb: number; - - let interval = ''; - - [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); - [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); + let interval = '', numb: number; - [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); - - [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); - - [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - - [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - - interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` - + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` - + `${daysNumb === 0 ? '' : `${daysNumb} days `}` - + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` - + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` - + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; + for (const field of this.state.fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + [numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng); + interval += `${numb} ${field} `; + } return interval; } } -export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueInterval'; +// has a newer version +export class GenerateUniqueInterval extends AbstractGenerator<{ + fields?: + | 'year' + | 'month' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'year to month' + | 'day to hour' + | 'day to minute' + | 'day to second' + | 'hour to minute' + | 'hour to second' + | 'minute to second'; + isUnique?: boolean; +}> { + static override readonly 'entityKind': string = 'GenerateUniqueInterval'; private state: { rng: prand.RandomGenerator; + fieldsToGenerate: string[]; intervalSet: Set; } | undefined; public override isUnique = true; + private config: { [key: string]: { from: number; to: number } } = { + year: { + from: 0, + to: 5, + }, + month: { + from: 0, + to: 12, + }, + day: { + from: 1, + to: 29, + }, + hour: { + from: 0, + to: 24, + }, + minute: { + from: 0, + to: 60, + }, + second: { + from: 0, + to: 60, + }, + }; override init({ count, seed }: { count: number; seed: number }) { - const maxUniqueIntervalsNumber = 6 * 13 * 29 * 25 * 61 * 61; + const allFields = ['year', 'month', 'day', 'hour', 'minute', 'second']; + let fieldsToGenerate: string[] = allFields; + + if (this.params.fields !== undefined && this.params.fields?.includes(' to ')) { + const tokens = this.params.fields.split(' to '); + const endIdx = allFields.indexOf(tokens[1]!); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } else if (this.params.fields !== undefined) { + const endIdx = allFields.indexOf(this.params.fields); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } + + let maxUniqueIntervalsNumber = 1; + for (const field of fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + maxUniqueIntervalsNumber *= from - to + 1; + } + if (count > maxUniqueIntervalsNumber) { throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`); } const rng = prand.xoroshiro128plus(seed); const intervalSet = new Set(); - this.state = { rng, intervalSet }; + this.state = { rng, fieldsToGenerate, intervalSet }; } generate() { @@ -1297,29 +1398,16 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boole throw new Error('state is not defined.'); } - let yearsNumb: number, - monthsNumb: number, - daysNumb: number, - hoursNumb: number, - minutesNumb: number, - secondsNumb: number; - - let interval = ''; + let interval, numb: number; for (;;) { - [yearsNumb, this.state.rng] = prand.uniformIntDistribution(0, 5, this.state.rng); - [monthsNumb, this.state.rng] = prand.uniformIntDistribution(0, 12, this.state.rng); - [daysNumb, this.state.rng] = prand.uniformIntDistribution(1, 29, this.state.rng); - [hoursNumb, this.state.rng] = prand.uniformIntDistribution(0, 24, this.state.rng); - [minutesNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - [secondsNumb, this.state.rng] = prand.uniformIntDistribution(0, 60, this.state.rng); - - interval = `${yearsNumb === 0 ? '' : `${yearsNumb} years `}` - + `${monthsNumb === 0 ? '' : `${monthsNumb} months `}` - + `${daysNumb === 0 ? '' : `${daysNumb} days `}` - + `${hoursNumb === 0 ? '' : `${hoursNumb} hours `}` - + `${minutesNumb === 0 ? '' : `${minutesNumb} minutes `}` - + `${secondsNumb === 0 ? '' : `${secondsNumb} seconds`}`; + interval = ''; + + for (const field of this.state.fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + [numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng); + interval += `${numb} ${field} `; + } if (!this.state.intervalSet.has(interval)) { this.state.intervalSet.add(interval); @@ -1331,11 +1419,12 @@ export class GenerateUniqueInterval extends AbstractGenerator<{ isUnique?: boole } } +// has a newer version export class GenerateString extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateString'; + static override readonly entityKind: string = 'GenerateString'; private state: { rng: prand.RandomGenerator } | undefined; override uniqueVersionOfGen = GenerateUniqueString; @@ -1377,8 +1466,9 @@ export class GenerateString extends AbstractGenerator<{ } } +// has a newer version export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueString'; + static override readonly entityKind: string = 'GenerateUniqueString'; private state: { rng: prand.RandomGenerator } | undefined; public override isUnique = true; @@ -1423,7 +1513,7 @@ export class GenerateUniqueString extends AbstractGenerator<{ isUnique?: boolean export class GenerateUUID extends AbstractGenerator<{ arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateUUID'; + static override readonly entityKind: string = 'GenerateUUID'; public override isUnique = true; @@ -1470,7 +1560,7 @@ export class GenerateFirstName extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateFirstName'; + static override readonly entityKind: string = 'GenerateFirstName'; override timeSpent: number = 0; private state: { @@ -1483,6 +1573,12 @@ export class GenerateFirstName extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxFirstNameLength) { + throw new Error( + `You can't use first name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxFirstNameLength}.`, + ); + } + this.state = { rng }; } @@ -1493,7 +1589,6 @@ export class GenerateFirstName extends AbstractGenerator<{ // logic for this generator // names dataset contains about 30000 unique names. - // TODO: generate names accordingly to max column length let idx: number; [idx, this.state.rng] = prand.uniformIntDistribution(0, firstNames.length - 1, this.state.rng); @@ -1504,7 +1599,7 @@ export class GenerateFirstName extends AbstractGenerator<{ export class GenerateUniqueFirstName extends AbstractGenerator<{ isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniqueFirstName'; + static override readonly entityKind: string = 'GenerateUniqueFirstName'; private state: { genIndicesObj: GenerateUniqueInt; @@ -1515,6 +1610,13 @@ export class GenerateUniqueFirstName extends AbstractGenerator<{ if (count > firstNames.length) { throw new Error('count exceeds max number of unique first names.'); } + + if (this.stringLength !== undefined && this.stringLength < maxFirstNameLength) { + throw new Error( + `You can't use first name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxFirstNameLength}.`, + ); + } + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: firstNames.length - 1 }); genIndicesObj.init({ count, seed }); @@ -1538,7 +1640,7 @@ export class GenerateLastName extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateLastName'; + static override readonly entityKind: string = 'GenerateLastName'; private state: { rng: prand.RandomGenerator; @@ -1550,6 +1652,12 @@ export class GenerateLastName extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxLastNameLength) { + throw new Error( + `You can't use last name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxLastNameLength}.`, + ); + } + this.state = { rng }; } generate() { @@ -1565,7 +1673,7 @@ export class GenerateLastName extends AbstractGenerator<{ } export class GenerateUniqueLastName extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueLastName'; + static override readonly entityKind: string = 'GenerateUniqueLastName'; private state: { genIndicesObj: GenerateUniqueInt; @@ -1577,6 +1685,12 @@ export class GenerateUniqueLastName extends AbstractGenerator<{ isUnique?: boole throw new Error('count exceeds max number of unique last names.'); } + if (this.stringLength !== undefined && this.stringLength < maxLastNameLength) { + throw new Error( + `You can't use last name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxLastNameLength}.`, + ); + } + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: lastNames.length - 1 }); genIndicesObj.init({ count, seed }); @@ -1599,7 +1713,7 @@ export class GenerateFullName extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateFullName'; + static override readonly entityKind: string = 'GenerateFullName'; private state: { rng: prand.RandomGenerator; @@ -1611,6 +1725,14 @@ export class GenerateFullName extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < (maxFirstNameLength + maxLastNameLength + 1)) { + throw new Error( + `You can't use full name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${ + maxFirstNameLength + maxLastNameLength + 1 + }.`, + ); + } + this.state = { rng }; } @@ -1636,7 +1758,7 @@ export class GenerateFullName extends AbstractGenerator<{ export class GenerateUniqueFullName extends AbstractGenerator<{ isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniqueFullName'; + static override readonly entityKind: string = 'GenerateUniqueFullName'; private state: { fullnameSet: Set; @@ -1654,6 +1776,15 @@ export class GenerateUniqueFullName extends AbstractGenerator<{ `count exceeds max number of unique full names(${maxUniqueFullNamesNumber}).`, ); } + + if (this.stringLength !== undefined && this.stringLength < (maxFirstNameLength + maxLastNameLength + 1)) { + throw new Error( + `You can't use full name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${ + maxFirstNameLength + maxLastNameLength + 1 + }.`, + ); + } + const rng = prand.xoroshiro128plus(seed); const fullnameSet = new Set(); @@ -1692,7 +1823,7 @@ export class GenerateUniqueFullName extends AbstractGenerator<{ export class GenerateEmail extends AbstractGenerator<{ arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateEmail'; + static override readonly entityKind: string = 'GenerateEmail'; private state: { genIndicesObj: GenerateUniqueInt; @@ -1715,6 +1846,13 @@ export class GenerateEmail extends AbstractGenerator<{ ); } + const maxEmailLength = maxAdjectiveLength + maxFirstNameLength + maxEmailDomainLength + 2; + if (this.stringLength !== undefined && this.stringLength < maxEmailLength) { + throw new Error( + `You can't use email generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxEmailLength}.`, + ); + } + const arraysToGenerateFrom = [adjectivesArray, namesArray, domainsArray]; const genIndicesObj = new GenerateUniqueInt({ minValue: 0, @@ -1752,7 +1890,7 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ generatedDigitsNumbers?: number | number[]; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GeneratePhoneNumber'; + static override readonly entityKind: string = 'GeneratePhoneNumber'; private state: { rng: prand.RandomGenerator; @@ -1773,6 +1911,13 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); if (template !== undefined) { + if (this.stringLength !== undefined && this.stringLength < template.length) { + throw new Error( + `Length of phone number template is shorter than db column length restriction: ${this.stringLength}. + Set the maximum string length to at least ${template.length}.`, + ); + } + const iterArray = [...template.matchAll(/#/g)]; const placeholdersCount = iterArray.length; @@ -1828,6 +1973,17 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ } } + const maxPrefixLength = Math.max(...prefixesArray.map((prefix) => prefix.length)); + const maxGeneratedDigits = Math.max(...generatedDigitsNumbers); + + if (this.stringLength !== undefined && this.stringLength < (maxPrefixLength + maxGeneratedDigits)) { + throw new Error( + `You can't use phone number generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${ + maxPrefixLength + maxGeneratedDigits + }.`, + ); + } + if (new Set(prefixesArray).size !== prefixesArray.length) { throw new Error('prefixes are not unique.'); } @@ -1907,7 +2063,7 @@ export class GeneratePhoneNumber extends AbstractGenerator<{ numberBody = '0'.repeat(digitsNumberDiff) + numberBody; } - phoneNumber = (prefix.includes('+') ? '' : '+') + prefix + '' + numberBody; + phoneNumber = prefix + '' + numberBody; return phoneNumber; } else { @@ -1928,7 +2084,7 @@ export class GenerateCountry extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateCountry'; + static override readonly entityKind: string = 'GenerateCountry'; private state: { rng: prand.RandomGenerator; @@ -1940,6 +2096,12 @@ export class GenerateCountry extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxCountryLength) { + throw new Error( + `You can't use country generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCountryLength}.`, + ); + } + this.state = { rng }; } @@ -1958,7 +2120,7 @@ export class GenerateCountry extends AbstractGenerator<{ } export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueCountry'; + static override readonly entityKind: string = 'GenerateUniqueCountry'; private state: { genIndicesObj: GenerateUniqueInt; @@ -1970,6 +2132,12 @@ export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolea throw new Error('count exceeds max number of unique countries.'); } + if (this.stringLength !== undefined && this.stringLength < maxCountryLength) { + throw new Error( + `You can't use country generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCountryLength}.`, + ); + } + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: countries.length - 1 }); genIndicesObj.init({ count, seed }); @@ -1991,7 +2159,7 @@ export class GenerateUniqueCountry extends AbstractGenerator<{ isUnique?: boolea export class GenerateJobTitle extends AbstractGenerator<{ arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateJobTitle'; + static override readonly entityKind: string = 'GenerateJobTitle'; private state: { rng: prand.RandomGenerator; @@ -2002,6 +2170,12 @@ export class GenerateJobTitle extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxJobTitleLength) { + throw new Error( + `You can't use job title generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxJobTitleLength}.`, + ); + } + this.state = { rng }; } @@ -2017,23 +2191,31 @@ export class GenerateJobTitle extends AbstractGenerator<{ } } -export class GenerateStreetAdddress extends AbstractGenerator<{ +export class GenerateStreetAddress extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateStreetAdddress'; + static override readonly entityKind: string = 'GenerateStreetAddress'; private state: { rng: prand.RandomGenerator; possStreetNames: string[][]; } | undefined; - override uniqueVersionOfGen = GenerateUniqueStreetAdddress; + override uniqueVersionOfGen = GenerateUniqueStreetAddress; override init({ count, seed }: { count: number; seed: number }) { super.init({ count, seed }); const rng = prand.xoroshiro128plus(seed); const possStreetNames = [firstNames, lastNames]; + + const maxStreetAddressLength = 4 + Math.max(maxFirstNameLength, maxLastNameLength) + 1 + maxStreetSuffixLength; + if (this.stringLength !== undefined && this.stringLength < maxStreetAddressLength) { + throw new Error( + `You can't use street address generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxStreetAddressLength}.`, + ); + } + this.state = { rng, possStreetNames }; } @@ -2059,8 +2241,8 @@ export class GenerateStreetAdddress extends AbstractGenerator<{ } } -export class GenerateUniqueStreetAdddress extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueStreetAdddress'; +export class GenerateUniqueStreetAddress extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly entityKind: string = 'GenerateUniqueStreetAddress'; private state: { rng: prand.RandomGenerator; @@ -2084,6 +2266,13 @@ export class GenerateUniqueStreetAdddress extends AbstractGenerator<{ isUnique?: ); } + const maxStreetAddressLength = 4 + Math.max(maxFirstNameLength, maxLastNameLength) + 1 + maxStreetSuffixLength; + if (this.stringLength !== undefined && this.stringLength < maxStreetAddressLength) { + throw new Error( + `You can't use street address generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxStreetAddressLength}.`, + ); + } + const rng = prand.xoroshiro128plus(seed); // ["1", "2", ..., "999"] @@ -2149,7 +2338,7 @@ export class GenerateCity extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateCity'; + static override readonly entityKind: string = 'GenerateCity'; private state: { rng: prand.RandomGenerator; @@ -2161,6 +2350,12 @@ export class GenerateCity extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxCityNameLength) { + throw new Error( + `You can't use city generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCityNameLength}.`, + ); + } + this.state = { rng }; } @@ -2177,7 +2372,7 @@ export class GenerateCity extends AbstractGenerator<{ } export class GenerateUniqueCity extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueCity'; + static override readonly entityKind: string = 'GenerateUniqueCity'; private state: { genIndicesObj: GenerateUniqueInt; @@ -2189,6 +2384,12 @@ export class GenerateUniqueCity extends AbstractGenerator<{ isUnique?: boolean } throw new Error('count exceeds max number of unique cities.'); } + if (this.stringLength !== undefined && this.stringLength < maxCityNameLength) { + throw new Error( + `You can't use city generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCityNameLength}.`, + ); + } + const genIndicesObj = new GenerateUniqueInt({ minValue: 0, maxValue: cityNames.length - 1 }); genIndicesObj.init({ count, seed }); @@ -2211,7 +2412,7 @@ export class GeneratePostcode extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GeneratePostcode'; + static override readonly entityKind: string = 'GeneratePostcode'; private state: { rng: prand.RandomGenerator; @@ -2225,6 +2426,13 @@ export class GeneratePostcode extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); const templates = ['#####', '#####-####']; + const maxPostcodeLength = Math.max(...templates.map((template) => template.length)); + if (this.stringLength !== undefined && this.stringLength < maxPostcodeLength) { + throw new Error( + `You can't use postcode generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxPostcodeLength}.`, + ); + } + this.state = { rng, templates }; } @@ -2258,7 +2466,7 @@ export class GeneratePostcode extends AbstractGenerator<{ } export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniquePostcode'; + static override readonly entityKind: string = 'GenerateUniquePostcode'; private state: { rng: prand.RandomGenerator; @@ -2298,6 +2506,13 @@ export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boole }, ]; + const maxPostcodeLength = Math.max(...templates.map((template) => template.template.length)); + if (this.stringLength !== undefined && this.stringLength < maxPostcodeLength) { + throw new Error( + `You can't use postcode generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxPostcodeLength}.`, + ); + } + for (const templateObj of templates) { templateObj.indicesGen.skipCheck = true; templateObj.indicesGen.init({ count, seed }); @@ -2338,7 +2553,7 @@ export class GenerateUniquePostcode extends AbstractGenerator<{ isUnique?: boole export class GenerateState extends AbstractGenerator<{ arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateState'; + static override readonly entityKind: string = 'GenerateState'; private state: { rng: prand.RandomGenerator; @@ -2349,6 +2564,12 @@ export class GenerateState extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); + if (this.stringLength !== undefined && this.stringLength < maxStateLength) { + throw new Error( + `You can't use state generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxStateLength}.`, + ); + } + this.state = { rng }; } @@ -2368,7 +2589,7 @@ export class GenerateCompanyName extends AbstractGenerator<{ isUnique?: boolean; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateCompanyName'; + static override readonly entityKind: string = 'GenerateCompanyName'; private state: { rng: prand.RandomGenerator; @@ -2387,6 +2608,17 @@ export class GenerateCompanyName extends AbstractGenerator<{ { template: '#, # and #', placeholdersCount: 3 }, ]; + // max( { template: '#', placeholdersCount: 1 }, { template: '#, # and #', placeholdersCount: 3 } ) + const maxCompanyNameLength = Math.max( + maxLastNameLength + maxCompanyNameSuffixLength + 1, + 3 * maxLastNameLength + 7, + ); + if (this.stringLength !== undefined && this.stringLength < maxCompanyNameLength) { + throw new Error( + `You can't use company name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCompanyNameLength}.`, + ); + } + this.state = { rng, templates }; } @@ -2426,7 +2658,7 @@ export class GenerateCompanyName extends AbstractGenerator<{ } export class GenerateUniqueCompanyName extends AbstractGenerator<{ isUnique?: boolean }> { - static override readonly [entityKind]: string = 'GenerateUniqueCompanyName'; + static override readonly entityKind: string = 'GenerateUniqueCompanyName'; private state: { rng: prand.RandomGenerator; @@ -2450,6 +2682,17 @@ export class GenerateUniqueCompanyName extends AbstractGenerator<{ isUnique?: bo ); } + // max( { template: '#', placeholdersCount: 1 }, { template: '#, # and #', placeholdersCount: 3 } ) + const maxCompanyNameLength = Math.max( + maxLastNameLength + maxCompanyNameSuffixLength + 1, + 3 * maxLastNameLength + 7, + ); + if (this.stringLength !== undefined && this.stringLength < maxCompanyNameLength) { + throw new Error( + `You can't use company name generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxCompanyNameLength}.`, + ); + } + const rng = prand.xoroshiro128plus(seed); // when count reach maxUniqueCompanyNameNumber template will be deleted from array const templates = [ @@ -2526,7 +2769,7 @@ export class GenerateLoremIpsum extends AbstractGenerator<{ sentencesCount?: number; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateLoremIpsum'; + static override readonly entityKind: string = 'GenerateLoremIpsum'; private state: { rng: prand.RandomGenerator; @@ -2538,6 +2781,14 @@ export class GenerateLoremIpsum extends AbstractGenerator<{ const rng = prand.xoroshiro128plus(seed); if (this.params.sentencesCount === undefined) this.params.sentencesCount = 1; + const maxLoremIpsumSentencesLength = maxLoremIpsumLength * this.params.sentencesCount + this.params.sentencesCount + - 1; + if (this.stringLength !== undefined && this.stringLength < maxLoremIpsumSentencesLength) { + throw new Error( + `You can't use lorem ipsum generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxLoremIpsumSentencesLength}.`, + ); + } + this.state = { rng }; } @@ -2557,7 +2808,7 @@ export class GenerateLoremIpsum extends AbstractGenerator<{ } export class WeightedRandomGenerator extends AbstractGenerator<{ weight: number; value: AbstractGenerator }[]> { - static override readonly [entityKind]: string = 'WeightedRandomGenerator'; + static override readonly entityKind: string = 'WeightedRandomGenerator'; private state: { rng: prand.RandomGenerator; @@ -2627,7 +2878,7 @@ export class GeneratePoint extends AbstractGenerator<{ maxYValue?: number; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GeneratePoint'; + static override readonly entityKind: string = 'GeneratePoint'; private state: { xCoordinateGen: GenerateNumber; @@ -2681,7 +2932,7 @@ export class GenerateUniquePoint extends AbstractGenerator<{ maxYValue?: number; isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniquePoint'; + static override readonly entityKind: string = 'GenerateUniquePoint'; private state: { xCoordinateGen: GenerateUniqueNumber; @@ -2736,7 +2987,7 @@ export class GenerateLine extends AbstractGenerator<{ maxCValue?: number; arraySize?: number; }> { - static override readonly [entityKind]: string = 'GenerateLine'; + static override readonly entityKind: string = 'GenerateLine'; private state: { aCoefficientGen: GenerateNumber; @@ -2807,7 +3058,7 @@ export class GenerateUniqueLine extends AbstractGenerator<{ maxCValue?: number; isUnique?: boolean; }> { - static override readonly [entityKind]: string = 'GenerateUniqueLine'; + static override readonly entityKind: string = 'GenerateUniqueLine'; private state: { aCoefficientGen: GenerateUniqueNumber; @@ -2866,692 +3117,3 @@ export class GenerateUniqueLine extends AbstractGenerator<{ } } } - -export const generatorsFuncs = { - /** - * generates same given value each time the generator is called. - * @param defaultValue - value you want to generate - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * content: funcs.default({ defaultValue: "post content" }), - * }, - * }, - * })); - * ``` - */ - default: createGenerator(GenerateDefault), - - /** - * generates values from given array - * @param values - array of values you want to generate. can be array of weighted values. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * title: funcs.valuesFromArray({ - * values: ["Title1", "Title2", "Title3", "Title4", "Title5"], - * isUnique: true - * }), - * }, - * }, - * })); - * - * ``` - * weighted values example - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * title: funcs.valuesFromArray({ - * values: [ - * { weight: 0.35, values: ["Title1", "Title2"] }, - * { weight: 0.5, values: ["Title3", "Title4"] }, - * { weight: 0.15, values: ["Title5"] }, - * ], - * isUnique: false - * }), - * }, - * }, - * })); - * - * ``` - */ - valuesFromArray: createGenerator(GenerateValuesFromArray), - - /** - * generates sequential integers starting with 1. - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * id: funcs.intPrimaryKey(), - * }, - * }, - * })); - * - * ``` - */ - intPrimaryKey: createGenerator(GenerateIntPrimaryKey), - - /** - * generates numbers with floating point in given range. - * @param minValue - lower border of range. - * @param maxValue - upper border of range. - * @param precision - precision of generated number: - * precision equals 10 means that values will be accurate to one tenth (1.2, 34.6); - * precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67). - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * products: { - * columns: { - * unitPrice: funcs.number({ minValue: 10, maxValue: 120, precision: 100, isUnique: false }), - * }, - * }, - * })); - * - * ``` - */ - number: createGenerator(GenerateNumber), - // uniqueNumber: createGenerator(GenerateUniqueNumber), - - /** - * generates integers within given range. - * @param minValue - lower border of range. - * @param maxValue - upper border of range. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * products: { - * columns: { - * unitsInStock: funcs.number({ minValue: 0, maxValue: 100, isUnique: false }), - * }, - * }, - * })); - * - * ``` - */ - int: createGenerator(GenerateInt), - // uniqueInt: createGenerator(GenerateUniqueInt), - - /** - * generates boolean values(true or false) - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * isAvailable: funcs.boolean() - * }, - * }, - * })); - * - * ``` - */ - boolean: createGenerator(GenerateBoolean), - - /** - * generates date within given range. - * @param minDate - lower border of range. - * @param maxDate - upper border of range. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * birthDate: funcs.date({ minDate: "1990-01-01", maxDate: "2010-12-31" }) - * }, - * }, - * })); - * - * ``` - */ - date: createGenerator(GenerateDate), - - /** - * generates time in 24 hours style. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * birthTime: funcs.time() - * }, - * }, - * })); - * - * ``` - */ - time: createGenerator(GenerateTime), - - /** - * generates timestamps. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * orders: { - * columns: { - * shippedDate: funcs.timestamp() - * }, - * }, - * })); - * - * ``` - */ - timestamp: createGenerator(GenerateTimestamp), - - /** - * generates datetime objects. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * orders: { - * columns: { - * shippedDate: funcs.datetime() - * }, - * }, - * })); - * - * ``` - */ - datetime: createGenerator(GenerateDatetime), - - /** - * generates years. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * birthYear: funcs.year() - * }, - * }, - * })); - * - * ``` - */ - year: createGenerator(GenerateYear), - - /** - * generates json objects with fixed structure. - * @param arraySize - number of elements in each one-dimensional array. - * - * json structure can equal this: - * ``` - * { - * email, - * name, - * isGraduated, - * hasJob, - * salary, - * startedWorking, - * visitedCountries, - * } - * ``` - * or this - * ``` - * { - * email, - * name, - * isGraduated, - * hasJob, - * visitedCountries, - * } - * ``` - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * metadata: funcs.json() - * }, - * }, - * })); - * ``` - */ - json: createGenerator(GenerateJson), - // jsonb: createGenerator(GenerateJsonb), - - /** - * generates time intervals. - * - * interval example: "1 years 12 days 5 minutes" - * - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * timeSpentOnWebsite: funcs.interval() - * }, - * }, - * })); - * ``` - */ - interval: createGenerator(GenerateInterval), - // uniqueInterval: createGenerator(GenerateUniqueInterval), - - /** - * generates random strings. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * hashedPassword: funcs.string({isUnique: false}) - * }, - * }, - * })); - * ``` - */ - string: createGenerator(GenerateString), - // uniqueString: createGenerator(GenerateUniqueString), - - /** - * generates v4 UUID strings if arraySize is not specified, or v4 UUID 1D arrays if it is. - * - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * uuid: funcs.uuid({ - * arraySize: 4 - * }) - * }, - * }, - * })); - * ``` - */ - uuid: createGenerator(GenerateUUID), - - /** - * generates person's first names. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * firstName: funcs.firstName({isUnique: true}) - * }, - * }, - * })); - * ``` - */ - firstName: createGenerator(GenerateFirstName), - // uniqueFirstName: createGenerator(GenerateUniqueName), - - /** - * generates person's last names. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * lastName: funcs.lastName({isUnique: false}) - * }, - * }, - * })); - * ``` - */ - lastName: createGenerator(GenerateLastName), - // uniqueLastName: createGenerator(GenerateUniqueSurname), - - /** - * generates person's full names. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * fullName: funcs.fullName({isUnique: true}) - * }, - * }, - * })); - * ``` - */ - fullName: createGenerator(GenerateFullName), - // uniqueFullName: createGenerator(GenerateUniqueFullName), - - /** - * generates unique emails. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * email: funcs.email() - * }, - * }, - * })); - * ``` - */ - email: createGenerator(GenerateEmail), - - /** - * generates unique phone numbers. - * @param arraySize - number of elements in each one-dimensional array. - * - * @param template - phone number template, where all '#' symbols will be substituted with generated digits. - * @param prefixes - array of any string you want to be your phone number prefixes.(not compatible with template property) - * @param generatedDigitsNumbers - number of digits that will be added at the end of prefixes.(not compatible with template property) - * @example - * ```ts - * //generate phone number using template property - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * phoneNumber: funcs.phoneNumber({template: "+(380) ###-####"}) - * }, - * }, - * })); - * - * //generate phone number using prefixes and generatedDigitsNumbers properties - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67" ], generatedDigitsNumbers: 7}) - * }, - * }, - * })); - * - * //generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * phoneNumber: funcs.phoneNumber({prefixes: [ "+380 99", "+380 67", "+1" ], generatedDigitsNumbers: [7, 7, 10]}) - * }, - * }, - * })); - * - * ``` - */ - phoneNumber: createGenerator(GeneratePhoneNumber), - - /** - * generates country's names. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * country: funcs.country({isUnique: false}) - * }, - * }, - * })); - * ``` - */ - country: createGenerator(GenerateCountry), - // uniqueCountry: createGenerator(GenerateUniqueCountry), - - /** - * generates city's names. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * city: funcs.city({isUnique: false}) - * }, - * }, - * })); - * ``` - */ - city: createGenerator(GenerateCity), - // uniqueCity: createGenerator(GenerateUniqueCityName), - - /** - * generates street address. - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * streetAddress: funcs.streetAddress({isUnique: true}) - * }, - * }, - * })); - * ``` - */ - streetAddress: createGenerator(GenerateStreetAdddress), - // uniqueStreetAddress: createGenerator(GenerateUniqueStreetAdddress), - - /** - * generates job titles. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * jobTitle: funcs.jobTitle() - * }, - * }, - * })); - * ``` - */ - jobTitle: createGenerator(GenerateJobTitle), - - /** - * generates postal codes. - * - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * postcode: funcs.postcode({isUnique: true}) - * }, - * }, - * })); - * ``` - */ - postcode: createGenerator(GeneratePostcode), - // uniquePostcoe: createGenerator(GenerateUniquePostcode), - - /** - * generates states of America. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * state: funcs.state() - * }, - * }, - * })); - * ``` - */ - state: createGenerator(GenerateState), - - /** - * generates company's names. - * - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * users: { - * columns: { - * company: funcs.companyName({isUnique: true}) - * }, - * }, - * })); - * ``` - */ - companyName: createGenerator(GenerateCompanyName), - // uniqueCompanyName: createGenerator(GenerateUniqueCompanyName), - - /** - * generates 'lorem ipsum' text sentences. - * - * @param sentencesCount - number of sentences you want to generate as one generated value(string). - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * content: funcs.loremIpsum({sentencesCount: 2}) - * }, - * }, - * })); - * ``` - */ - loremIpsum: createGenerator(GenerateLoremIpsum), - - /** - * generates 2D points within specified ranges for x and y coordinates. - * - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param minXValue - lower bound of range for x coordinate. - * @param maxXValue - upper bound of range for x coordinate. - * @param minYValue - lower bound of range for y coordinate. - * @param maxYValue - upper bound of range for y coordinate. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * triangles: { - * columns: { - * pointCoords: funcs.point({ - * isUnique: true, - * minXValue: -5, maxXValue:20, - * minYValue: 0, maxYValue: 30 - * }) - * }, - * }, - * })); - * ``` - */ - point: createGenerator(GeneratePoint), - // uniquePoint: createGenerator(GenerateUniquePoint), - - /** - * generates 2D lines within specified ranges for a, b and c parameters of line. - * - * ``` - * line equation: a*x + b*y + c = 0 - * ``` - * - * @param isUnique - property that controls if generated values gonna be unique or not. - * @param minAValue - lower bound of range for a parameter. - * @param maxAValue - upper bound of range for x parameter. - * @param minBValue - lower bound of range for y parameter. - * @param maxBValue - upper bound of range for y parameter. - * @param minCValue - lower bound of range for y parameter. - * @param maxCValue - upper bound of range for y parameter. - * @param arraySize - number of elements in each one-dimensional array. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * lines: { - * columns: { - * lineParams: funcs.point({ - * isUnique: true, - * minAValue: -5, maxAValue:20, - * minBValue: 0, maxBValue: 30, - * minCValue: 0, maxCValue: 10 - * }) - * }, - * }, - * })); - * ``` - */ - line: createGenerator(GenerateLine), - // uniqueLine: createGenerator(GenerateUniqueLine), - - /** - * gives you the opportunity to call different generators with different probabilities to generate values for one column. - * @param params - array of generators with probabilities you would like to call them to generate values. - * - * @example - * ```ts - * await seed(db, schema, { count: 1000 }).refine((funcs) => ({ - * posts: { - * columns: { - * content: funcs.weightedRandom([ - * { - * weight: 0.6, - * value: funcs.loremIpsum({ sentencesCount: 3 }), - * }, - * { - * weight: 0.4, - * value: funcs.default({ defaultValue: "TODO" }), - * }, - * ]), - * }, - * }, - * })); - * ``` - */ - weightedRandom: createGenerator(WeightedRandomGenerator), -}; diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 87569babb..84165169e 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -1,3 +1,4 @@ +/* eslint-disable drizzle-internal/require-entity-kind */ import { entityKind, eq, is } from 'drizzle-orm'; import type { MySqlTable, MySqlTableWithColumns } from 'drizzle-orm/mysql-core'; import { MySqlDatabase } from 'drizzle-orm/mysql-core'; @@ -11,39 +12,15 @@ import type { RefinementsType, TableGeneratorsType, } from '../types/seedService.ts'; -import type { Column, Prettify, Relation, RelationWithReferences, Table } from '../types/tables.ts'; -import type { AbstractGenerator } from './GeneratorsWrappers.ts'; -import { - GenerateArray, - GenerateBoolean, - GenerateDate, - GenerateDatetime, - GenerateDefault, - GenerateEmail, - GenerateEnum, - GenerateFirstName, - GenerateInt, - GenerateInterval, - GenerateIntPrimaryKey, - GenerateJson, - GenerateLine, - GenerateNumber, - GeneratePoint, - GenerateSelfRelationsValuesFromArray, - GenerateString, - GenerateTime, - GenerateTimestamp, - GenerateUniqueString, - GenerateUUID, - GenerateValuesFromArray, - GenerateWeightedCount, - GenerateYear, - HollowGenerator, -} from './GeneratorsWrappers.ts'; +import type { Column, Prettify, Relation, Table } from '../types/tables.ts'; +import { generatorsMap } from './GeneratorFuncs.ts'; +import type { AbstractGenerator, GenerateArray, GenerateInterval, GenerateWeightedCount } from './Generators.ts'; + +import { latestVersion } from './apiVersion.ts'; import { equalSets, generateHashFromString } from './utils.ts'; export class SeedService { - static readonly [entityKind]: string = 'SeedService'; + static readonly entityKind: string = 'SeedService'; private defaultCountForTable = 10; private postgresPgLiteMaxParametersNumber = 32740; @@ -52,21 +29,24 @@ export class SeedService { private mysqlMaxParametersNumber = 100000; // SQLITE_MAX_VARIABLE_NUMBER, which by default equals to 999 for SQLite versions prior to 3.32.0 (2020-05-22) or 32766 for SQLite versions after 3.32.0. private sqliteMaxParametersNumber = 32766; + private version?: number; generatePossibleGenerators = ( connectionType: 'postgresql' | 'mysql' | 'sqlite', tables: Table[], relations: (Relation & { isCyclic: boolean })[], - tableRelations: { [tableName: string]: RelationWithReferences[] }, refinements?: RefinementsType, - options?: { count?: number; seed?: number }, + options?: { count?: number; seed?: number; version?: number }, ) => { let columnPossibleGenerator: Prettify; let tablePossibleGenerators: Prettify; const customSeed = options?.seed === undefined ? 0 : options.seed; + this.version = options?.version === undefined ? latestVersion : options.version; + if (Number.isNaN(this.version) || this.version < 1 || this.version > latestVersion) { + throw new Error(`Version should be in range [1, ${latestVersion}].`); + } // sorting table in order which they will be filled up (tables with foreign keys case) - // relations = relations.filter(rel => rel.type === "one"); const { tablesInOutRelations } = this.getInfoFromRelations(relations); const orderedTablesNames = this.getOrderedTablesList(tablesInOutRelations); tables = tables.sort((table1, table2) => { @@ -203,11 +183,14 @@ export class SeedService { && refinements[table.name]!.columns[col.name] !== undefined ) { const genObj = refinements[table.name]!.columns[col.name]!; - // TODO: for now only GenerateValuesFromArray support notNull property - genObj.notNull = col.notNull; - if (col.dataType === 'array') { - if (col.baseColumn?.dataType === 'array' && col.baseColumn?.columnType === 'array') { - throw new Error("for now you can't specify generators for columns of dimensition greater than 1."); + + if (col.columnType.match(/\[\w*]/g) !== null) { + if ( + (col.baseColumn?.dataType === 'array' && col.baseColumn.columnType.match(/\[\w*]/g) !== null) + // studio case + || (col.typeParams.dimensions !== undefined && col.typeParams.dimensions > 1) + ) { + throw new Error("for now you can't specify generators for columns of dimension greater than 1."); } genObj.baseColumnDataType = col.baseColumn?.dataType; @@ -217,49 +200,79 @@ export class SeedService { columnPossibleGenerator.wasRefined = true; } else if (Object.hasOwn(foreignKeyColumns, col.name)) { // TODO: I might need to assign repeatedValuesCount to column there instead of doing so in generateTablesValues - const cyclicRelation = tableRelations[table.name]!.find((rel) => - rel.isCyclic === true + const cyclicRelation = relations.find((rel) => + rel.table === table.name + && rel.isCyclic === true && rel.columns.includes(col.name) ); if (cyclicRelation !== undefined) { columnPossibleGenerator.isCyclic = true; } - const predicate = cyclicRelation !== undefined && col.notNull === false; + + if (foreignKeyColumns[col.name]?.table === undefined && col.notNull === true) { + throw new Error( + `Column '${col.name}' has no null contraint, and you didn't specify a table for foreign key on column '${col.name}' in '${table.name}' table. You should pass `, + ); + } + + const predicate = (cyclicRelation !== undefined || foreignKeyColumns[col.name]?.table === undefined) + && col.notNull === false; if (predicate === true) { - columnPossibleGenerator.generator = new GenerateDefault({ defaultValue: null }); + if (foreignKeyColumns[col.name]?.table === undefined && col.notNull === false) { + console.warn( + `Column '${col.name}' in '${table.name}' table will be filled with Null values` + + `\nbecause you specified neither a table for foreign key on column '${col.name}' nor a function for '${col.name}' column in refinements.`, + ); + } + columnPossibleGenerator.generator = new generatorsMap.GenerateDefault[0]({ defaultValue: null }); columnPossibleGenerator.wasDefinedBefore = true; + } else { + columnPossibleGenerator.generator = new generatorsMap.HollowGenerator[0](); } - - columnPossibleGenerator.generator = new HollowGenerator({}); } // TODO: rewrite pickGeneratorFor... using new col properties: isUnique and notNull else if (connectionType === 'postgresql') { - columnPossibleGenerator.generator = this.pickGeneratorForPostgresColumn( + columnPossibleGenerator.generator = this.selectGeneratorForPostgresColumn( table, col, ); } else if (connectionType === 'mysql') { - columnPossibleGenerator.generator = this.pickGeneratorForMysqlColumn( + columnPossibleGenerator.generator = this.selectGeneratorForMysqlColumn( table, col, ); } else if (connectionType === 'sqlite') { - columnPossibleGenerator.generator = this.pickGeneratorForSqlite( + columnPossibleGenerator.generator = this.selectGeneratorForSqlite( table, col, ); } if (columnPossibleGenerator.generator === undefined) { - console.log(col); throw new Error( `column with type ${col.columnType} is not supported for now.`, ); } + const arrayGen = columnPossibleGenerator.generator.replaceIfArray(); + if (arrayGen !== undefined) { + columnPossibleGenerator.generator = arrayGen; + } + + const uniqueGen = columnPossibleGenerator.generator.replaceIfUnique(); + if (uniqueGen !== undefined) { + columnPossibleGenerator.generator = uniqueGen; + } + + // selecting version of generator + columnPossibleGenerator.generator = this.selectVersionOfGenerator(columnPossibleGenerator.generator); + columnPossibleGenerator.generator.isUnique = col.isUnique; + // TODO: for now only GenerateValuesFromArray support notNull property + columnPossibleGenerator.generator.notNull = col.notNull; columnPossibleGenerator.generator.dataType = col.dataType; + columnPossibleGenerator.generator.stringLength = col.typeParams.length; tablePossibleGenerators.columnsPossibleGenerators.push( columnPossibleGenerator, @@ -270,6 +283,38 @@ export class SeedService { return tablesPossibleGenerators; }; + selectVersionOfGenerator = (generator: AbstractGenerator) => { + const entityKind = generator.getEntityKind(); + if (entityKind === 'GenerateArray') { + const oldBaseColumnGen = (generator as GenerateArray).params.baseColumnGen; + + const newBaseColumnGen = this.selectVersionOfGenerator(oldBaseColumnGen); + // newGenerator.baseColumnDataType = oldGenerator.baseColumnDataType; + + (generator as GenerateArray).params.baseColumnGen = newBaseColumnGen; + } + + const possibleGeneratorConstructors = generatorsMap[entityKind as keyof typeof generatorsMap]; + + const possibleGeneratorConstructorsFiltered = possibleGeneratorConstructors?.filter((possGenCon) => + possGenCon.version <= this.version! // sorting in ascending order by version + ).sort((a, b) => a.version - b.version); + const generatorConstructor = possibleGeneratorConstructorsFiltered?.at(-1) as + | (new(params: any) => AbstractGenerator) + | undefined; + if (generatorConstructor === undefined) { + throw new Error(`Can't select ${entityKind} generator for ${this.version} version.`); + } + + const newGenerator = new generatorConstructor(generator.params); + newGenerator.baseColumnDataType = generator.baseColumnDataType; + newGenerator.isUnique = generator.isUnique; + newGenerator.dataType = generator.dataType; + newGenerator.stringLength = generator.stringLength; + + return newGenerator; + }; + cyclicTablesCompare = ( table1: Table, table2: Table, @@ -385,7 +430,10 @@ export class SeedService { }; } - if (tablesInOutRelations[rel.refTable] === undefined) { + if ( + rel.refTable !== undefined + && tablesInOutRelations[rel.refTable] === undefined + ) { tablesInOutRelations[rel.refTable] = { out: 0, in: 0, @@ -396,13 +444,15 @@ export class SeedService { }; } - tablesInOutRelations[rel.table]!.out += 1; - tablesInOutRelations[rel.refTable]!.in += 1; + if (rel.refTable !== undefined) { + tablesInOutRelations[rel.table]!.out += 1; + tablesInOutRelations[rel.refTable]!.in += 1; + } if (rel.refTable === rel.table) { tablesInOutRelations[rel.table]!.selfRelation = true; tablesInOutRelations[rel.table]!.selfRelCount = rel.columns.length; - } else { + } else if (rel.refTable !== undefined) { tablesInOutRelations[rel.table]!.requiredTableNames.add(rel.refTable); tablesInOutRelations[rel.refTable]!.dependantTableNames.add(rel.table); } @@ -416,7 +466,9 @@ export class SeedService { count: number, seed: number, ) => { - const gen = new GenerateWeightedCount({}); + let gen = new generatorsMap.GenerateWeightedCount[0](); + gen = this.selectVersionOfGenerator(gen) as GenerateWeightedCount; + // const gen = new GenerateWeightedCount({}); gen.init({ count: weightedCount, seed }); let weightedWithCount = 0; for (let i = 0; i < count; i++) { @@ -427,543 +479,609 @@ export class SeedService { }; // TODO: revise serial part generators - - pickGeneratorForPostgresColumn = ( + selectGeneratorForPostgresColumn = ( table: Table, col: Column, ) => { - let generator: AbstractGenerator | undefined; + const pickGenerator = (table: Table, col: Column) => { + // ARRAY + if (col.columnType.match(/\[\w*]/g) !== null && col.baseColumn !== undefined) { + const baseColumnGen = this.selectGeneratorForPostgresColumn( + table, + col.baseColumn!, + ) as AbstractGenerator; + if (baseColumnGen === undefined) { + throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); + } - // INT ------------------------------------------------------------------------------------------------------------ - if ( - (col.columnType.includes('serial') - || col.columnType === 'integer' - || col.columnType === 'smallint' - || col.columnType.includes('bigint')) - && table.primaryKeys.includes(col.name) - ) { - generator = new GenerateIntPrimaryKey({}); + // const getBaseColumnDataType = (baseColumn: Column) => { + // if (baseColumn.baseColumn !== undefined) { + // return getBaseColumnDataType(baseColumn.baseColumn); + // } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // return baseColumn.dataType; + // }; + // const baseColumnDataType = getBaseColumnDataType(col.baseColumn); - let minValue: number | bigint | undefined; - let maxValue: number | bigint | undefined; - if (col.columnType.includes('serial')) { - minValue = 1; - if (col.columnType === 'smallserial') { - // 2^16 / 2 - 1, 2 bytes - maxValue = 32767; - } else if (col.columnType === 'serial') { - // 2^32 / 2 - 1, 4 bytes - maxValue = 2147483647; - } else if (col.columnType === 'bigserial') { - // 2^64 / 2 - 1, 8 bytes - minValue = BigInt(1); - maxValue = BigInt('9223372036854775807'); + const generator = new generatorsMap.GenerateArray[0]({ baseColumnGen, size: col.size }); + // generator.baseColumnDataType = baseColumnDataType; + + return generator; } - } else if (col.columnType.includes('int')) { - if (col.columnType === 'smallint') { - // 2^16 / 2 - 1, 2 bytes - minValue = -32768; - maxValue = 32767; - } else if (col.columnType === 'integer') { - // 2^32 / 2 - 1, 4 bytes - minValue = -2147483648; - maxValue = 2147483647; - } else if (col.columnType.includes('bigint')) { - if (col.dataType === 'bigint') { + + // ARRAY for studio + if (col.columnType.match(/\[\w*]/g) !== null) { + // remove dimensions from type + const baseColumnType = col.columnType.replace(/\[\w*]/g, ''); + const baseColumn: Column = { + ...col, + }; + baseColumn.columnType = baseColumnType; + + const baseColumnGen = this.selectGeneratorForPostgresColumn(table, baseColumn) as AbstractGenerator; + if (baseColumnGen === undefined) { + throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); + } + + let generator = new generatorsMap.GenerateArray[0]({ baseColumnGen }); + + for (let i = 0; i < col.typeParams.dimensions! - 1; i++) { + generator = new generatorsMap.GenerateArray[0]({ baseColumnGen: generator }); + } + + return generator; + } + + // INT ------------------------------------------------------------------------------------------------------------ + if ( + (col.columnType.includes('serial') + || col.columnType === 'integer' + || col.columnType === 'smallint' + || col.columnType.includes('bigint')) + && table.primaryKeys.includes(col.name) + ) { + const generator = new generatorsMap.GenerateIntPrimaryKey[0](); + + return generator; + } + + let minValue: number | bigint | undefined; + let maxValue: number | bigint | undefined; + if (col.columnType.includes('serial')) { + minValue = 1; + if (col.columnType === 'smallserial') { + // 2^16 / 2 - 1, 2 bytes + maxValue = 32767; + } else if (col.columnType === 'serial') { + // 2^32 / 2 - 1, 4 bytes + maxValue = 2147483647; + } else if (col.columnType === 'bigserial') { // 2^64 / 2 - 1, 8 bytes - minValue = BigInt('-9223372036854775808'); + minValue = BigInt(1); maxValue = BigInt('9223372036854775807'); - } else if (col.dataType === 'number') { - // if you’re expecting values above 2^31 but below 2^53 - minValue = -9007199254740991; - maxValue = 9007199254740991; + } + } else if (col.columnType.includes('int')) { + if (col.columnType === 'smallint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -32768; + maxValue = 32767; + } else if (col.columnType === 'integer') { + // 2^32 / 2 - 1, 4 bytes + minValue = -2147483648; + maxValue = 2147483647; + } else if (col.columnType.includes('bigint')) { + if (col.dataType === 'bigint') { + // 2^64 / 2 - 1, 8 bytes + minValue = BigInt('-9223372036854775808'); + maxValue = BigInt('9223372036854775807'); + } else { + // if (col.dataType === 'number') + // if you’re expecting values above 2^31 but below 2^53 + minValue = -9007199254740991; + maxValue = 9007199254740991; + } } } - } - if ( - col.columnType.includes('int') - && !col.columnType.includes('interval') - && !col.columnType.includes('point') - ) { - generator = new GenerateInt({ - minValue, - maxValue, - }); + if ( + col.columnType.includes('int') + && !col.columnType.includes('interval') + && !col.columnType.includes('point') + ) { + const generator = new generatorsMap.GenerateInt[0]({ + minValue, + maxValue, + }); - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + return generator; + } - if (col.columnType.includes('serial')) { - generator = new GenerateIntPrimaryKey({}); + if (col.columnType.includes('serial')) { + const generator = new generatorsMap.GenerateIntPrimaryKey[0](); - (generator as GenerateIntPrimaryKey).maxValue = maxValue; - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + generator.maxValue = maxValue; - // NUMBER(real, double, decimal, numeric) - if ( - col.columnType === 'real' - || col.columnType === 'doubleprecision' - || col.columnType === 'decimal' - || col.columnType === 'numeric' - ) { - generator = new GenerateNumber({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // NUMBER(real, double, decimal, numeric) + if ( + col.columnType.startsWith('real') + || col.columnType.startsWith('double precision') + || col.columnType.startsWith('decimal') + || col.columnType.startsWith('numeric') + ) { + if (col.typeParams.precision !== undefined) { + const precision = col.typeParams.precision; + const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; + + const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); + const generator = new generatorsMap.GenerateNumber[0]({ + minValue: -maxAbsoluteValue, + maxValue: maxAbsoluteValue, + precision: Math.pow(10, scale), + }); + return generator; + } + const generator = new generatorsMap.GenerateNumber[0](); - // STRING - if ( - (col.columnType === 'text' - || col.columnType === 'varchar' - || col.columnType === 'char') - && table.primaryKeys.includes(col.name) - ) { - generator = new GenerateUniqueString({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // STRING + if ( + (col.columnType === 'text' + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('char')) + && table.primaryKeys.includes(col.name) + ) { + const generator = new generatorsMap.GenerateUniqueString[0](); - if ( - (col.columnType === 'text' - || col.columnType === 'varchar' - || col.columnType === 'char') - && col.name.toLowerCase().includes('name') - ) { - generator = new GenerateFirstName({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + if ( + (col.columnType === 'text' + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('char')) + && col.name.toLowerCase().includes('name') + ) { + const generator = new generatorsMap.GenerateFirstName[0](); - if ( - (col.columnType === 'text' - || col.columnType === 'varchar' - || col.columnType === 'char') - && col.name.toLowerCase().includes('email') - ) { - generator = new GenerateEmail({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + if ( + (col.columnType === 'text' + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('char')) + && col.name.toLowerCase().includes('email') + ) { + const generator = new generatorsMap.GenerateEmail[0](); - if ( - col.columnType === 'text' - || col.columnType === 'varchar' - || col.columnType === 'char' - ) { - // console.log(col, table) - generator = new GenerateString({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + if ( + col.columnType === 'text' + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('char') + ) { + const generator = new generatorsMap.GenerateString[0](); - // UUID - if (col.columnType === 'uuid') { - generator = new GenerateUUID({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // UUID + if (col.columnType === 'uuid') { + const generator = new generatorsMap.GenerateUUID[0](); - // BOOLEAN - if (col.columnType === 'boolean') { - generator = new GenerateBoolean({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // BOOLEAN + if (col.columnType === 'boolean') { + const generator = new generatorsMap.GenerateBoolean[0](); - // DATE, TIME, TIMESTAMP - if (col.columnType.includes('date')) { - generator = new GenerateDate({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // DATE, TIME, TIMESTAMP + if (col.columnType.includes('date')) { + const generator = new generatorsMap.GenerateDate[0](); - if (col.columnType === 'time') { - generator = new GenerateTime({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + if (col.columnType === 'time') { + const generator = new generatorsMap.GenerateTime[0](); - if (col.columnType.includes('timestamp')) { - generator = new GenerateTimestamp({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + if (col.columnType.includes('timestamp')) { + const generator = new generatorsMap.GenerateTimestamp[0](); - // JSON, JSONB - if (col.columnType === 'json' || col.columnType === 'jsonb') { - generator = new GenerateJson({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // JSON, JSONB + if (col.columnType === 'json' || col.columnType === 'jsonb') { + const generator = new generatorsMap.GenerateJson[0](); - // if (col.columnType === "jsonb") { - // const generator = new GenerateJsonb({}); - // return generator; - // } + return generator; + } - // ENUM - if (col.enumValues !== undefined) { - generator = new GenerateEnum({ - enumValues: col.enumValues, - }); + // if (col.columnType === "jsonb") { + // const generator = new GenerateJsonb({}); + // return generator; + // } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // ENUM + if (col.enumValues !== undefined) { + const generator = new generatorsMap.GenerateEnum[0]({ + enumValues: col.enumValues, + }); - // INTERVAL - if (col.columnType === 'interval') { - generator = new GenerateInterval({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // INTERVAL + if (col.columnType.startsWith('interval')) { + if (col.columnType === 'interval') { + const generator = new generatorsMap.GenerateInterval[0](); - // POINT, LINE - if (col.columnType.includes('point')) { - generator = new GeneratePoint({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + const fields = col.columnType.replace('interval ', '') as GenerateInterval['params']['fields']; + const generator = new generatorsMap.GenerateInterval[0]({ fields }); - if (col.columnType.includes('line')) { - generator = new GenerateLine({}); + return generator; + } - generator.isUnique = col.isUnique; - generator.dataType = col.dataType; - return generator; - } + // POINT, LINE + if (col.columnType.includes('point')) { + const generator = new generatorsMap.GeneratePoint[0](); + + return generator; + } + + if (col.columnType.includes('line')) { + const generator = new generatorsMap.GenerateLine[0](); - // ARRAY - if (col.columnType.includes('array') && col.baseColumn !== undefined) { - const baseColumnGen = this.pickGeneratorForPostgresColumn(table, col.baseColumn!) as AbstractGenerator; - if (baseColumnGen === undefined) { - throw new Error(`column with type ${col.baseColumn!.columnType} is not supported for now.`); + return generator; + } + + if (col.hasDefault && col.default !== undefined) { + const generator = new generatorsMap.GenerateDefault[0]({ + defaultValue: col.default, + }); + return generator; } - generator = new GenerateArray({ baseColumnGen, size: col.size }); + return; + }; + + const generator = pickGenerator(table, col); + if (generator !== undefined) { generator.isUnique = col.isUnique; generator.dataType = col.dataType; - return generator; - } - - if (col.hasDefault && col.default !== undefined) { - generator = new GenerateDefault({ - defaultValue: col.default, - }); - return generator; + generator.stringLength = col.typeParams.length; } return generator; }; - pickGeneratorForMysqlColumn = ( + selectGeneratorForMysqlColumn = ( table: Table, col: Column, ) => { - // console.log(col); - // INT ------------------------------------------------------------------------------------------------------------ - if ( - (col.columnType.includes('serial') || col.columnType.includes('int')) - && table.primaryKeys.includes(col.name) - ) { - const generator = new GenerateIntPrimaryKey({}); - return generator; - } + const pickGenerator = (table: Table, col: Column) => { + // INT ------------------------------------------------------------------------------------------------------------ + if ( + (col.columnType.includes('serial') || col.columnType.includes('int')) + && table.primaryKeys.includes(col.name) + ) { + const generator = new generatorsMap.GenerateIntPrimaryKey[0](); + return generator; + } - let minValue: number | bigint | undefined; - let maxValue: number | bigint | undefined; - if (col.columnType === 'serial') { - // 2^64 % 2 - 1, 8 bytes - minValue = BigInt(0); - maxValue = BigInt('9223372036854775807'); - } else if (col.columnType.includes('int')) { - if (col.columnType === 'tinyint') { - // 2^8 / 2 - 1, 1 bytes - minValue = -128; - maxValue = 127; - } else if (col.columnType === 'smallint') { - // 2^16 / 2 - 1, 2 bytes - minValue = -32768; - maxValue = 32767; - } else if (col.columnType === 'mediumint') { - // 2^16 / 2 - 1, 2 bytes - minValue = -8388608; - maxValue = 8388607; - } else if (col.columnType === 'int') { - // 2^32 / 2 - 1, 4 bytes - minValue = -2147483648; - maxValue = 2147483647; - } else if (col.columnType === 'bigint') { - // 2^64 / 2 - 1, 8 bytes - minValue = BigInt('-9223372036854775808'); + let minValue: number | bigint | undefined; + let maxValue: number | bigint | undefined; + if (col.columnType === 'serial') { + // 2^64 % 2 - 1, 8 bytes + minValue = BigInt(0); maxValue = BigInt('9223372036854775807'); + } else if (col.columnType.includes('int')) { + if (col.columnType === 'tinyint') { + // 2^8 / 2 - 1, 1 bytes + minValue = -128; + maxValue = 127; + } else if (col.columnType === 'smallint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -32768; + maxValue = 32767; + } else if (col.columnType === 'mediumint') { + // 2^16 / 2 - 1, 2 bytes + minValue = -8388608; + maxValue = 8388607; + } else if (col.columnType === 'int') { + // 2^32 / 2 - 1, 4 bytes + minValue = -2147483648; + maxValue = 2147483647; + } else if (col.columnType === 'bigint') { + // 2^64 / 2 - 1, 8 bytes + minValue = BigInt('-9223372036854775808'); + maxValue = BigInt('9223372036854775807'); + } } - } - if (col.columnType.includes('int')) { - const generator = new GenerateInt({ - minValue, - maxValue, - }); - return generator; - } + if (col.columnType.includes('int')) { + const generator = new generatorsMap.GenerateInt[0]({ + minValue, + maxValue, + }); + return generator; + } - if (col.columnType.includes('serial')) { - const generator = new GenerateIntPrimaryKey({}); - generator.maxValue = maxValue; - return generator; - } + if (col.columnType.includes('serial')) { + const generator = new generatorsMap.GenerateIntPrimaryKey[0](); + generator.maxValue = maxValue; + return generator; + } - // NUMBER(real, double, decimal, float) - if ( - col.columnType === 'real' - || col.columnType === 'double' - || col.columnType === 'decimal' - || col.columnType === 'float' - ) { - const generator = new GenerateNumber({}); - return generator; - } + // NUMBER(real, double, decimal, float) + if ( + col.columnType.startsWith('real') + || col.columnType.startsWith('double') + || col.columnType.startsWith('decimal') + || col.columnType.startsWith('float') + || col.columnType.startsWith('numeric') + ) { + if (col.typeParams.precision !== undefined) { + const precision = col.typeParams.precision; + const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; + + const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); + const generator = new generatorsMap.GenerateNumber[0]({ + minValue: -maxAbsoluteValue, + maxValue: maxAbsoluteValue, + precision: Math.pow(10, scale), + }); + return generator; + } - // STRING - if ( - (col.columnType === 'text' - || col.columnType === 'blob' - || col.columnType.includes('char') - || col.columnType.includes('varchar') - || col.columnType.includes('binary') - || col.columnType.includes('varbinary')) - && table.primaryKeys.includes(col.name) - ) { - const generator = new GenerateUniqueString({}); - return generator; - } + const generator = new generatorsMap.GenerateNumber[0](); + return generator; + } - if ( - (col.columnType === 'text' - || col.columnType === 'blob' - || col.columnType.includes('char') - || col.columnType.includes('varchar') - || col.columnType.includes('binary') - || col.columnType.includes('varbinary')) - && col.name.toLowerCase().includes('name') - ) { - const generator = new GenerateFirstName({}); - return generator; - } + // STRING + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.startsWith('char') + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('binary') + || col.columnType.startsWith('varbinary')) + && table.primaryKeys.includes(col.name) + ) { + const generator = new generatorsMap.GenerateUniqueString[0](); + return generator; + } - if ( - (col.columnType === 'text' + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.startsWith('char') + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('binary') + || col.columnType.startsWith('varbinary')) + && col.name.toLowerCase().includes('name') + ) { + const generator = new generatorsMap.GenerateFirstName[0](); + return generator; + } + + if ( + (col.columnType === 'text' + || col.columnType === 'blob' + || col.columnType.startsWith('char') + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('binary') + || col.columnType.startsWith('varbinary')) + && col.name.toLowerCase().includes('email') + ) { + const generator = new generatorsMap.GenerateEmail[0](); + return generator; + } + + if ( + col.columnType === 'text' || col.columnType === 'blob' - || col.columnType.includes('char') - || col.columnType.includes('varchar') - || col.columnType.includes('binary') - || col.columnType.includes('varbinary')) - && col.name.toLowerCase().includes('email') - ) { - const generator = new GenerateEmail({}); - return generator; - } + || col.columnType.startsWith('char') + || col.columnType.startsWith('varchar') + || col.columnType.startsWith('binary') + || col.columnType.startsWith('varbinary') + ) { + const generator = new generatorsMap.GenerateString[0](); + return generator; + } - if ( - col.columnType === 'text' - || col.columnType === 'blob' - || col.columnType.includes('char') - || col.columnType.includes('varchar') - || col.columnType.includes('binary') - || col.columnType.includes('varbinary') - ) { - // console.log(col, table); - const generator = new GenerateString({}); - return generator; - } + // BOOLEAN + if (col.columnType === 'boolean') { + const generator = new generatorsMap.GenerateBoolean[0](); + return generator; + } - // BOOLEAN - if (col.columnType === 'boolean') { - const generator = new GenerateBoolean({}); - return generator; - } + // DATE, TIME, TIMESTAMP, DATETIME, YEAR + if (col.columnType.includes('datetime')) { + const generator = new generatorsMap.GenerateDatetime[0](); + return generator; + } - // DATE, TIME, TIMESTAMP, DATETIME, YEAR - if (col.columnType.includes('datetime')) { - const generator = new GenerateDatetime({}); - return generator; - } + if (col.columnType.includes('date')) { + const generator = new generatorsMap.GenerateDate[0](); + return generator; + } - if (col.columnType.includes('date')) { - const generator = new GenerateDate({}); - return generator; - } + if (col.columnType === 'time') { + const generator = new generatorsMap.GenerateTime[0](); + return generator; + } - if (col.columnType === 'time') { - const generator = new GenerateTime({}); - return generator; - } + if (col.columnType.includes('timestamp')) { + const generator = new generatorsMap.GenerateTimestamp[0](); + return generator; + } - if (col.columnType.includes('timestamp')) { - const generator = new GenerateTimestamp({}); - return generator; - } + if (col.columnType === 'year') { + const generator = new generatorsMap.GenerateYear[0](); + return generator; + } - if (col.columnType === 'year') { - const generator = new GenerateYear({}); - return generator; - } + // JSON + if (col.columnType === 'json') { + const generator = new generatorsMap.GenerateJson[0](); + return generator; + } - // JSON - if (col.columnType === 'json') { - const generator = new GenerateJson({}); - return generator; - } + // ENUM + if (col.enumValues !== undefined) { + const generator = new generatorsMap.GenerateEnum[0]({ + enumValues: col.enumValues, + }); + return generator; + } - // ENUM - if (col.enumValues !== undefined) { - const generator = new GenerateEnum({ - enumValues: col.enumValues, - }); - return generator; - } + if (col.hasDefault && col.default !== undefined) { + const generator = new generatorsMap.GenerateDefault[0]({ + defaultValue: col.default, + }); + return generator; + } - if (col.hasDefault && col.default !== undefined) { - const generator = new GenerateDefault({ - defaultValue: col.default, - }); - return generator; - } + return; + }; + + const generator = pickGenerator(table, col); - return; + return generator; }; - pickGeneratorForSqlite = ( + selectGeneratorForSqlite = ( table: Table, col: Column, ) => { - // int section --------------------------------------------------------------------------------------- - if ( - (col.columnType === 'integer' || col.columnType === 'numeric') - && table.primaryKeys.includes(col.name) - ) { - const generator = new GenerateIntPrimaryKey({}); - return generator; - } + const pickGenerator = (table: Table, col: Column) => { + // int section --------------------------------------------------------------------------------------- + if ( + (col.columnType === 'integer' || col.columnType === 'numeric') + && table.primaryKeys.includes(col.name) + ) { + const generator = new generatorsMap.GenerateIntPrimaryKey[0](); + return generator; + } - if ( - col.columnType === 'integer' - || col.columnType === 'numeric' - || col.columnType === 'bigint' - ) { - const generator = new GenerateInt({}); - return generator; - } + if (col.columnType === 'integer' && col.dataType === 'boolean') { + const generator = new generatorsMap.GenerateBoolean[0](); + return generator; + } - if (col.columnType === 'boolean') { - const generator = new GenerateBoolean({}); - return generator; - } + if ((col.columnType === 'integer' && col.dataType === 'date')) { + const generator = new generatorsMap.GenerateTimestamp[0](); + return generator; + } - // number section ------------------------------------------------------------------------------------ - if (col.columnType === 'real' || col.columnType === 'numeric') { - const generator = new GenerateNumber({}); - return generator; - } + if ( + col.columnType === 'integer' + || (col.dataType === 'bigint' && col.columnType === 'blob') + ) { + const generator = new generatorsMap.GenerateInt[0](); + return generator; + } - // string section ------------------------------------------------------------------------------------ - if ( - (col.columnType === 'text' - || col.columnType === 'numeric' - || col.columnType === 'blob') - && table.primaryKeys.includes(col.name) - ) { - const generator = new GenerateUniqueString({}); - return generator; - } + // number section ------------------------------------------------------------------------------------ + if (col.columnType.startsWith('real') || col.columnType.startsWith('numeric')) { + if (col.typeParams.precision !== undefined) { + const precision = col.typeParams.precision; + const scale = col.typeParams.scale === undefined ? 0 : col.typeParams.scale; + + const maxAbsoluteValue = Math.pow(10, precision - scale) - Math.pow(10, -scale); + const generator = new generatorsMap.GenerateNumber[0]({ + minValue: -maxAbsoluteValue, + maxValue: maxAbsoluteValue, + precision: Math.pow(10, scale), + }); + return generator; + } - if ( - (col.columnType === 'text' - || col.columnType === 'numeric' - || col.columnType === 'blob') - && col.name.toLowerCase().includes('name') - ) { - const generator = new GenerateFirstName({}); - return generator; - } + const generator = new generatorsMap.GenerateNumber[0](); + return generator; + } - if ( - (col.columnType === 'text' - || col.columnType === 'numeric' - || col.columnType === 'blob') - && col.name.toLowerCase().includes('email') - ) { - const generator = new GenerateEmail({}); - return generator; - } + // string section ------------------------------------------------------------------------------------ + if ( + (col.columnType.startsWith('text') + || col.columnType.startsWith('numeric') + || col.columnType.startsWith('blob')) + && table.primaryKeys.includes(col.name) + ) { + const generator = new generatorsMap.GenerateUniqueString[0](); + return generator; + } - if ( - col.columnType === 'text' - || col.columnType === 'numeric' - || col.columnType === 'blob' - || col.columnType === 'blobbuffer' - ) { - const generator = new GenerateString({}); - return generator; - } + if ( + (col.columnType.startsWith('text') + || col.columnType.startsWith('numeric') + || col.columnType.startsWith('blob')) + && col.name.toLowerCase().includes('name') + ) { + const generator = new generatorsMap.GenerateFirstName[0](); + return generator; + } - if (col.columnType === 'textjson' || col.columnType === 'blobjson') { - const generator = new GenerateJson({}); - return generator; - } + if ( + (col.columnType.startsWith('text') + || col.columnType.startsWith('numeric') + || col.columnType.startsWith('blob')) + && col.name.toLowerCase().includes('email') + ) { + const generator = new generatorsMap.GenerateEmail[0](); + return generator; + } - if (col.columnType === 'timestamp' || col.columnType === 'timestamp_ms') { - const generator = new GenerateTimestamp({}); - return generator; - } + if ( + col.columnType.startsWith('text') + || col.columnType.startsWith('numeric') + || col.columnType.startsWith('blob') + || col.columnType.startsWith('blobbuffer') + ) { + const generator = new generatorsMap.GenerateString[0](); + return generator; + } - if (col.hasDefault && col.default !== undefined) { - const generator = new GenerateDefault({ - defaultValue: col.default, - }); - return generator; - } + if ( + (col.columnType.startsWith('text') && col.dataType === 'json') + || (col.columnType.startsWith('blob') && col.dataType === 'json') + ) { + const generator = new generatorsMap.GenerateJson[0](); + return generator; + } - return; + if (col.hasDefault && col.default !== undefined) { + const generator = new generatorsMap.GenerateDefault[0]({ + defaultValue: col.default, + }); + return generator; + } + + return; + }; + + const generator = pickGenerator(table, col); + + return generator; }; filterCyclicTables = (tablesGenerators: ReturnType) => { @@ -1024,9 +1142,6 @@ export class SeedService { tablesUniqueNotNullColumn?: { [tableName: string]: { uniqueNotNullColName: string } }; }, ) => { - // console.time( - // "generateTablesValues-----------------------------------------------------" - // ); const customSeed = options?.seed === undefined ? 0 : options.seed; let tableCount: number | undefined; let columnsGenerators: Prettify[]; @@ -1042,7 +1157,6 @@ export class SeedService { }[] = options?.tablesValues === undefined ? [] : options.tablesValues; let pRNGSeed: number; - // relations = relations.filter(rel => rel.type === "one"); let filteredRelations: typeof relations; let preserveData: boolean, insertDataInDb: boolean = true, updateDataInDb: boolean = false; @@ -1124,9 +1238,13 @@ export class SeedService { }))!.map((rows) => rows[refColName]) as (string | number | boolean)[]; hasSelfRelation = true; - genObj = new GenerateSelfRelationsValuesFromArray({ + genObj = new generatorsMap.GenerateSelfRelationsValuesFromArray[0]({ values: refColumnValues, }); + genObj = this.selectVersionOfGenerator(genObj); + // genObj = new GenerateSelfRelationsValuesFromArray({ + // values: refColumnValues, + // }); } else if ( tableGenerators[rel.columns[colIdx]!]?.wasDefinedBefore === false && tableGenerators[rel.columns[colIdx]!]?.wasRefined === false @@ -1144,13 +1262,13 @@ export class SeedService { weightedCountSeed = table.withFromTable[rel.refTable]!.weightedCountSeed; } - genObj = new GenerateValuesFromArray({ values: refColumnValues }); - (genObj as GenerateValuesFromArray).notNull = tableGenerators[rel.columns[colIdx]!]!.notNull; - (genObj as GenerateValuesFromArray).weightedCountSeed = weightedCountSeed; - (genObj as GenerateValuesFromArray).maxRepeatedValuesCount = repeatedValuesCount; + // TODO: revise maybe need to select version of generator here too + genObj = new generatorsMap.GenerateValuesFromArray[0]({ values: refColumnValues }); + genObj.notNull = tableGenerators[rel.columns[colIdx]!]!.notNull; + genObj.weightedCountSeed = weightedCountSeed; + genObj.maxRepeatedValuesCount = repeatedValuesCount; } - // console.log(rel.columns[colIdx], tableGenerators) if (genObj !== undefined) { tableGenerators[rel.columns[colIdx]!]!.generator = genObj; } @@ -1265,15 +1383,15 @@ export class SeedService { seed: columnGenerator.pRNGSeed, }); - const arrayGen = columnsGenerators[columnName]!.replaceIfArray({ count, seed: columnGenerator.pRNGSeed }); - if (arrayGen !== undefined) { - columnsGenerators[columnName] = arrayGen; - } + // const arrayGen = columnsGenerators[columnName]!.replaceIfArray({ count, seed: columnGenerator.pRNGSeed }); + // if (arrayGen !== undefined) { + // columnsGenerators[columnName] = arrayGen; + // } - const uniqueGen = columnsGenerators[columnName]!.replaceIfUnique({ count, seed: columnGenerator.pRNGSeed }); - if (uniqueGen !== undefined) { - columnsGenerators[columnName] = uniqueGen; - } + // const uniqueGen = columnsGenerators[columnName]!.replaceIfUnique({ count, seed: columnGenerator.pRNGSeed }); + // if (uniqueGen !== undefined) { + // columnsGenerators[columnName] = uniqueGen; + // } } let maxParametersNumber: number; if (is(db, PgDatabase)) { diff --git a/drizzle-seed/src/services/apiVersion.ts b/drizzle-seed/src/services/apiVersion.ts new file mode 100644 index 000000000..6cda0267e --- /dev/null +++ b/drizzle-seed/src/services/apiVersion.ts @@ -0,0 +1 @@ +export const latestVersion = 2; diff --git a/drizzle-seed/src/services/versioning/v2.ts b/drizzle-seed/src/services/versioning/v2.ts new file mode 100644 index 000000000..e09cc45f6 --- /dev/null +++ b/drizzle-seed/src/services/versioning/v2.ts @@ -0,0 +1,232 @@ +/* eslint-disable drizzle-internal/require-entity-kind */ +import prand from 'pure-rand'; +import { AbstractGenerator } from '../Generators.ts'; + +export class GenerateUniqueIntervalV2 extends AbstractGenerator<{ + fields?: + | 'year' + | 'month' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'year to month' + | 'day to hour' + | 'day to minute' + | 'day to second' + | 'hour to minute' + | 'hour to second' + | 'minute to second'; + isUnique?: boolean; +}> { + static override readonly 'entityKind': string = 'GenerateUniqueInterval'; + static override readonly version: number = 2; + + private state: { + rng: prand.RandomGenerator; + fieldsToGenerate: string[]; + intervalSet: Set; + } | undefined; + public override isUnique = true; + private config: { [key: string]: { from: number; to: number } } = { + year: { + from: 0, + to: 5, + }, + month: { + from: 0, + to: 11, + }, + day: { + from: 0, + to: 29, + }, + hour: { + from: 0, + to: 23, + }, + minute: { + from: 0, + to: 59, + }, + second: { + from: 0, + to: 59, + }, + }; + + override init({ count, seed }: { count: number; seed: number }) { + const allFields = ['year', 'month', 'day', 'hour', 'minute', 'second']; + let fieldsToGenerate: string[] = allFields; + + if (this.params.fields !== undefined && this.params.fields?.includes(' to ')) { + const tokens = this.params.fields.split(' to '); + const endIdx = allFields.indexOf(tokens[1]!); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } else if (this.params.fields !== undefined) { + const endIdx = allFields.indexOf(this.params.fields); + fieldsToGenerate = allFields.slice(0, endIdx + 1); + } + + let maxUniqueIntervalsNumber = 1; + for (const field of fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + maxUniqueIntervalsNumber *= from - to + 1; + } + + if (count > maxUniqueIntervalsNumber) { + throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`); + } + + const rng = prand.xoroshiro128plus(seed); + const intervalSet = new Set(); + this.state = { rng, fieldsToGenerate, intervalSet }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + let interval, numb: number; + + for (;;) { + interval = ''; + + for (const field of this.state.fieldsToGenerate) { + const from = this.config[field]!.from, to = this.config[field]!.to; + [numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng); + interval += `${numb} ${field} `; + } + + if (!this.state.intervalSet.has(interval)) { + this.state.intervalSet.add(interval); + break; + } + } + + return interval; + } +} + +export class GenerateStringV2 extends AbstractGenerator<{ + isUnique?: boolean; + arraySize?: number; +}> { + static override readonly 'entityKind': string = 'GenerateString'; + static override readonly version: number = 2; + + private state: { + rng: prand.RandomGenerator; + minStringLength: number; + maxStringLength: number; + } | undefined; + override uniqueVersionOfGen = GenerateUniqueStringV2; + + override init({ count, seed }: { count: number; seed: number }) { + super.init({ count, seed }); + + let minStringLength = 8; + let maxStringLength = 20; + if (this.stringLength !== undefined) { + maxStringLength = this.stringLength; + if (maxStringLength === 1) minStringLength = maxStringLength; + if (maxStringLength < minStringLength) minStringLength = 1; + } + + const rng = prand.xoroshiro128plus(seed); + this.state = { rng, minStringLength, maxStringLength }; + } + + generate() { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const minStringLength = this.state.minStringLength, + maxStringLength = this.state.maxStringLength; + const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let idx: number, + strLength: number, + currStr: string; + + currStr = ''; + [strLength, this.state.rng] = prand.uniformIntDistribution( + minStringLength, + maxStringLength, + this.state.rng, + ); + for (let j = 0; j < strLength; j++) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + stringChars.length - 1, + this.state.rng, + ); + currStr += stringChars[idx]; + } + return currStr; + } +} + +export class GenerateUniqueStringV2 extends AbstractGenerator<{ isUnique?: boolean }> { + static override readonly 'entityKind': string = 'GenerateUniqueString'; + static override readonly version: number = 2; + + private state: { + rng: prand.RandomGenerator; + minStringLength: number; + maxStringLength: number; + } | undefined; + public override isUnique = true; + + override init({ seed, count }: { seed: number; count: number }) { + const rng = prand.xoroshiro128plus(seed); + + let minStringLength = 8; + let maxStringLength = 20; + // TODO: revise later + if (this.stringLength !== undefined) { + maxStringLength = this.stringLength; + if (maxStringLength === 1 || maxStringLength < minStringLength) minStringLength = maxStringLength; + } + + if (maxStringLength < count.toString(16).length) { + throw new Error( + `You can't generate ${count} unique strings, with a maximum string length of ${maxStringLength}.`, + ); + } + + this.state = { rng, minStringLength, maxStringLength }; + } + + generate({ i }: { i: number }) { + if (this.state === undefined) { + throw new Error('state is not defined.'); + } + + const minStringLength = this.state.minStringLength, + maxStringLength = this.state.maxStringLength; + const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let idx: number, + strLength: number; + let currStr: string; + + currStr = ''; + const uniqueStr = i.toString(16); + [strLength, this.state.rng] = prand.uniformIntDistribution( + minStringLength, + maxStringLength - uniqueStr.length, + this.state.rng, + ); + for (let j = 0; j < strLength - uniqueStr.length; j++) { + [idx, this.state.rng] = prand.uniformIntDistribution( + 0, + stringChars.length - 1, + this.state.rng, + ); + currStr += stringChars[idx]; + } + + return uniqueStr + currStr; + } +} diff --git a/drizzle-seed/src/types/seedService.ts b/drizzle-seed/src/types/seedService.ts index 0b5237468..1ae06f44c 100644 --- a/drizzle-seed/src/types/seedService.ts +++ b/drizzle-seed/src/types/seedService.ts @@ -1,4 +1,4 @@ -import type { AbstractGenerator } from '../services/GeneratorsWrappers.ts'; +import type { AbstractGenerator } from '../services/Generators.ts'; import type { Prettify } from './tables.ts'; export type TableGeneratorsType = { diff --git a/drizzle-seed/src/types/tables.ts b/drizzle-seed/src/types/tables.ts index 8473179ed..dc28c748d 100644 --- a/drizzle-seed/src/types/tables.ts +++ b/drizzle-seed/src/types/tables.ts @@ -4,6 +4,12 @@ export type Column = { name: string; dataType: string; columnType: string; + typeParams: { + precision?: number; + scale?: number; + length?: number; + dimensions?: number; + }; size?: number; default?: any; hasDefault: boolean; diff --git a/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts b/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts index 9d79ebaa8..23fca0c6c 100644 --- a/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts +++ b/drizzle-seed/tests/benchmarks/generatorsBenchmark.ts @@ -23,7 +23,7 @@ import { GeneratePoint, GeneratePostcode, GenerateState, - GenerateStreetAdddress, + GenerateStreetAddress, GenerateString, GenerateTime, GenerateTimestamp, @@ -35,12 +35,12 @@ import { GenerateUniqueNumber, GenerateUniquePoint, GenerateUniquePostcode, - GenerateUniqueStreetAdddress, + GenerateUniqueStreetAddress, GenerateUniqueString, GenerateValuesFromArray, GenerateYear, WeightedRandomGenerator, -} from '../../src/services/GeneratorsWrappers.ts'; +} from '../../src/services/Generators.ts'; const benchmark = ({ generatorName, generator, count = 100000, seed = 1 }: { generatorName: string; @@ -107,8 +107,8 @@ const generatorsFuncs = { // uniqueCountry: new GenerateUniqueCountry({}), city: new GenerateCity({}), // uniqueCity: new GenerateUniqueCity({}), - streetAddress: new GenerateStreetAdddress({}), - uniqueStreetAddress: new GenerateUniqueStreetAdddress({}), + streetAddress: new GenerateStreetAddress({}), + uniqueStreetAddress: new GenerateUniqueStreetAddress({}), jobTitle: new GenerateJobTitle({}), postcode: new GeneratePostcode({}), uniquePostcode: new GenerateUniquePostcode({}), diff --git a/drizzle-seed/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts b/drizzle-seed/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts index 5a9ba9908..f39a55fef 100644 --- a/drizzle-seed/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts +++ b/drizzle-seed/tests/mysql/allDataTypesTest/mysql_all_data_types.test.ts @@ -11,7 +11,7 @@ import { seed } from '../../../src/index.ts'; import * as schema from './mysqlSchema.ts'; let mysqlContainer: Docker.Container; -let client: Connection; +let client: Connection | undefined; let db: MySql2Database; async function createDockerDB(): Promise { diff --git a/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts b/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts index 75ba20a43..d4f45de22 100644 --- a/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts +++ b/drizzle-seed/tests/pg/allDataTypesTest/pgSchema.ts @@ -64,31 +64,31 @@ export const allDataTypes = schema.table('all_data_types', { }); export const allArrayDataTypes = schema.table('all_array_data_types', { - integerArray: integer('integer_array').array(), - smallintArray: smallint('smallint_array').array(), - bigintegerArray: bigint('bigint_array', { mode: 'bigint' }).array(), - bigintNumberArray: bigint('bigint_number_array', { mode: 'number' }).array(), - booleanArray: boolean('boolean_array').array(), - textArray: text('text_array').array(), - varcharArray: varchar('varchar_array', { length: 256 }).array(), - charArray: char('char_array', { length: 256 }).array(), - numericArray: numeric('numeric_array').array(), - decimalArray: decimal('decimal_array').array(), - realArray: real('real_array').array(), - doublePrecisionArray: doublePrecision('double_precision_array').array(), - jsonArray: json('json_array').array(), - jsonbArray: jsonb('jsonb_array').array(), - timeArray: time('time_array').array(), - timestampDateArray: timestamp('timestamp_date_array', { mode: 'date' }).array(), - timestampStringArray: timestamp('timestamp_string_array', { mode: 'string' }).array(), + // integerArray: integer('integer_array').array(), + // smallintArray: smallint('smallint_array').array(), + // bigintegerArray: bigint('bigint_array', { mode: 'bigint' }).array(), + // bigintNumberArray: bigint('bigint_number_array', { mode: 'number' }).array(), + // booleanArray: boolean('boolean_array').array(), + // textArray: text('text_array').array(), + // varcharArray: varchar('varchar_array', { length: 256 }).array(), + // charArray: char('char_array', { length: 256 }).array(), + // numericArray: numeric('numeric_array').array(), + // decimalArray: decimal('decimal_array').array(), + // realArray: real('real_array').array(), + // doublePrecisionArray: doublePrecision('double_precision_array').array(), + // jsonArray: json('json_array').array(), + // jsonbArray: jsonb('jsonb_array').array(), + // timeArray: time('time_array').array(), + // timestampDateArray: timestamp('timestamp_date_array', { mode: 'date' }).array(), + // timestampStringArray: timestamp('timestamp_string_array', { mode: 'string' }).array(), dateStringArray: date('date_string_array', { mode: 'string' }).array(), dateArray: date('date_array', { mode: 'date' }).array(), - intervalArray: interval('interval_array').array(), - pointArray: point('point_array', { mode: 'xy' }).array(), - pointTupleArray: point('point_tuple_array', { mode: 'tuple' }).array(), - lineArray: line('line_array', { mode: 'abc' }).array(), - lineTupleArray: line('line_tuple_array', { mode: 'tuple' }).array(), - moodEnumArray: moodEnum('mood_enum_array').array(), + // intervalArray: interval('interval_array').array(), + // pointArray: point('point_array', { mode: 'xy' }).array(), + // pointTupleArray: point('point_tuple_array', { mode: 'tuple' }).array(), + // lineArray: line('line_array', { mode: 'abc' }).array(), + // lineTupleArray: line('line_tuple_array', { mode: 'tuple' }).array(), + // moodEnumArray: moodEnum('mood_enum_array').array(), }); export const ndArrays = schema.table('nd_arrays', { @@ -97,3 +97,19 @@ export const ndArrays = schema.table('nd_arrays', { integer3DArray: integer('integer_3d_array').array(3).array(4).array(5), integer4DArray: integer('integer_4d_array').array(3).array(4).array(5).array(6), }); + +export const intervals = schema.table('intervals', { + intervalYear: interval({ fields: 'year' }), + intervalYearToMonth: interval({ fields: 'year to month' }), + intervalMonth: interval({ fields: 'month' }), + intervalDay: interval({ fields: 'day' }), + intervalDayToHour: interval({ fields: 'day to hour' }), + intervalDayToMinute: interval({ fields: 'day to minute' }), + intervalDayToSecond: interval({ fields: 'day to second' }), + intervalHour: interval({ fields: 'hour' }), + intervalHourToMinute: interval({ fields: 'hour to minute' }), + intervalHourToSecond: interval({ fields: 'hour to second' }), + intervalMinute: interval({ fields: 'minute' }), + intervalMinuteToSecond: interval({ fields: 'minute to second' }), + intervalSecond: interval({ fields: 'second' }), +}); diff --git a/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts b/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts index 7dfbc089b..62d0895c0 100644 --- a/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts +++ b/drizzle-seed/tests/pg/allDataTypesTest/pg_all_data_types.test.ts @@ -105,6 +105,26 @@ beforeAll(async () => { ); `, ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."intervals" ( + "intervalYear" interval year, + "intervalYearToMonth" interval year to month, + "intervalMonth" interval month, + "intervalDay" interval day, + "intervalDayToHour" interval day to hour, + "intervalDayToMinute" interval day to minute, + "intervalDayToSecond" interval day to second, + "intervalHour" interval hour, + "intervalHourToMinute" interval hour to minute, + "intervalHourToSecond" interval hour to second, + "intervalMinute" interval minute, + "intervalMinuteToSecond" interval minute to second, + "intervalSecond" interval second + ); + `, + ); }); afterAll(async () => { @@ -157,3 +177,13 @@ test('nd arrays', async () => { expect(predicate0 && predicate1 && predicate2 && predicate3 && predicate4).toBe(true); }); + +test('intervals test', async () => { + await seed(db, { intervals: schema.intervals }, { count: 1000 }); + + const intervals = await db.select().from(schema.intervals); + // every value in each rows does not equal undefined. + const predicate = intervals.every((row) => Object.values(row).every((val) => val !== undefined && val !== null)); + + expect(predicate).toBe(true); +}); From 31c6a0ffb850d4e5ea9d990377476ed9deb67043 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 25 Dec 2024 09:49:50 +0200 Subject: [PATCH 465/492] Add release notes and bump versions --- changelogs/drizzle-orm/0.38.3.md | 1 + changelogs/drizzle-typebox/0.2.1.md | 25 ++++++++++++ changelogs/drizzle-valibot/0.3.1.md | 23 +++++++++++ changelogs/drizzle-zod/0.6.1.md | 26 ++++++++++++ drizzle-orm/package.json | 4 +- drizzle-orm/src/mysql-core/table.ts | 59 ++++++++++++++-------------- drizzle-orm/src/pg-core/table.ts | 59 ++++++++++++++-------------- drizzle-orm/src/sqlite-core/table.ts | 59 ++++++++++++++-------------- drizzle-typebox/package.json | 4 +- drizzle-valibot/package.json | 4 +- drizzle-zod/package.json | 4 +- 11 files changed, 170 insertions(+), 98 deletions(-) create mode 100644 changelogs/drizzle-orm/0.38.3.md create mode 100644 changelogs/drizzle-typebox/0.2.1.md create mode 100644 changelogs/drizzle-valibot/0.3.1.md create mode 100644 changelogs/drizzle-zod/0.6.1.md diff --git a/changelogs/drizzle-orm/0.38.3.md b/changelogs/drizzle-orm/0.38.3.md new file mode 100644 index 000000000..3f94386b6 --- /dev/null +++ b/changelogs/drizzle-orm/0.38.3.md @@ -0,0 +1 @@ +- Fix incorrect deprecation detection for table declarations \ No newline at end of file diff --git a/changelogs/drizzle-typebox/0.2.1.md b/changelogs/drizzle-typebox/0.2.1.md new file mode 100644 index 000000000..2d9e762c3 --- /dev/null +++ b/changelogs/drizzle-typebox/0.2.1.md @@ -0,0 +1,25 @@ +# Added support for SingleStore dialect + +```ts +import { singlestoreTable, text, int } from 'drizzle-orm/singlestore-core'; +import { createSelectSchema } from 'drizzle-typebox'; +import { Value } from '@sinclair/typebox/value'; + +const users = singlestoreTable('users', { + id: int().primaryKey(), + name: text().notNull(), + age: int().notNull() +}); + +const userSelectSchema = createSelectSchema(users); + +const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1); +const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query + +const rows = await db.select().from(users).limit(1); +const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Will parse successfully +``` + +# Bug fixes + +- [[BUG]: drizzle-typebox infers integer() as TString](https://github.com/drizzle-team/drizzle-orm/issues/3756) \ No newline at end of file diff --git a/changelogs/drizzle-valibot/0.3.1.md b/changelogs/drizzle-valibot/0.3.1.md new file mode 100644 index 000000000..21f05270b --- /dev/null +++ b/changelogs/drizzle-valibot/0.3.1.md @@ -0,0 +1,23 @@ +# Added support for SingleStore dialect + +```ts +import { singlestoreTable, text, int } from 'drizzle-orm/singlestore-core'; +import { createSelectSchema } from 'drizzle-valibot'; +import { parse } from 'valibot'; + +const users = singlestoreTable('users', { + id: int().primaryKey(), + name: text().notNull(), + age: int().notNull() +}); + +const userSelectSchema = createSelectSchema(users); +const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1); +const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query +const rows = await db.select().from(users).limit(1); +const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Will parse successfully +``` + +# Bug fixes + +- [[BUG]: drizzle-valibot throws Type instantiation is excessively deep and possibly infinite. for refinements](https://github.com/drizzle-team/drizzle-orm/issues/3751) diff --git a/changelogs/drizzle-zod/0.6.1.md b/changelogs/drizzle-zod/0.6.1.md new file mode 100644 index 000000000..dd6740660 --- /dev/null +++ b/changelogs/drizzle-zod/0.6.1.md @@ -0,0 +1,26 @@ +# New Features + +## Added support for SingleStore dialect + +```ts +import { singlestoreTable, text, int } from 'drizzle-orm/singlestore-core'; +import { createSelectSchema } from 'drizzle-zod'; + +const users = singlestoreTable('users', { + id: int().primaryKey(), + name: text().notNull(), + age: int().notNull() +}); + +const userSelectSchema = createSelectSchema(users); +const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1); +const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Error: `age` is not returned in the above query + +const rows = await db.select().from(users).limit(1); +const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Will parse successfully +``` + +# Bug fixes + +- [[BUG]: refining schema using createSelectSchema is not working with drizzle-kit 0.6.0](https://github.com/drizzle-team/drizzle-orm/issues/3735) +- [[BUG]: drizzle-zod inferring types incorrectly](https://github.com/drizzle-team/drizzle-orm/issues/3734) \ No newline at end of file diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 72e641467..4385e34fd 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.38.2", + "version": "0.38.3", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -204,4 +204,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} +} \ No newline at end of file diff --git a/drizzle-orm/src/mysql-core/table.ts b/drizzle-orm/src/mysql-core/table.ts index c3d3e581a..2616e7159 100644 --- a/drizzle-orm/src/mysql-core/table.ts +++ b/drizzle-orm/src/mysql-core/table.ts @@ -116,6 +116,35 @@ export function mysqlTableWithSchema< } export interface MySqlTableFn { + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: TColumnsMap, + extraConfig?: ( + self: BuildColumns, + ) => MySqlTableExtraConfigValue[], + ): MySqlTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'mysql'; + }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: MySqlColumnBuilders) => TColumnsMap, + extraConfig?: (self: BuildColumns) => MySqlTableExtraConfigValue[], + ): MySqlTableWithColumns<{ + name: TTableName; + schema: TSchemaName; + columns: BuildColumns; + dialect: 'mysql'; + }>; /** * @deprecated The third parameter of mysqlTable is changing and will only accept an array instead of an object * @@ -187,36 +216,6 @@ export interface MySqlTableFn; dialect: 'mysql'; }>; - - < - TTableName extends string, - TColumnsMap extends Record, - >( - name: TTableName, - columns: TColumnsMap, - extraConfig?: ( - self: BuildColumns, - ) => MySqlTableExtraConfigValue[], - ): MySqlTableWithColumns<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'mysql'; - }>; - - < - TTableName extends string, - TColumnsMap extends Record, - >( - name: TTableName, - columns: (columnTypes: MySqlColumnBuilders) => TColumnsMap, - extraConfig?: (self: BuildColumns) => MySqlTableExtraConfigValue[], - ): MySqlTableWithColumns<{ - name: TTableName; - schema: TSchemaName; - columns: BuildColumns; - dialect: 'mysql'; - }>; } export const mysqlTable: MySqlTableFn = (name, columns, extraConfig) => { diff --git a/drizzle-orm/src/pg-core/table.ts b/drizzle-orm/src/pg-core/table.ts index 7f12e634d..b5a60e91a 100644 --- a/drizzle-orm/src/pg-core/table.ts +++ b/drizzle-orm/src/pg-core/table.ts @@ -134,6 +134,35 @@ export function pgTableWithSchema< } export interface PgTableFn { + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: TColumnsMap, + extraConfig?: ( + self: BuildExtraConfigColumns, + ) => PgTableExtraConfigValue[], + ): PgTableWithColumns<{ + name: TTableName; + schema: TSchema; + columns: BuildColumns; + dialect: 'pg'; + }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: PgColumnsBuilders) => TColumnsMap, + extraConfig?: (self: BuildExtraConfigColumns) => PgTableExtraConfigValue[], + ): PgTableWithColumns<{ + name: TTableName; + schema: TSchema; + columns: BuildColumns; + dialect: 'pg'; + }>; /** * @deprecated The third parameter of pgTable is changing and will only accept an array instead of an object * @@ -207,36 +236,6 @@ export interface PgTableFn { columns: BuildColumns; dialect: 'pg'; }>; - - < - TTableName extends string, - TColumnsMap extends Record, - >( - name: TTableName, - columns: TColumnsMap, - extraConfig?: ( - self: BuildExtraConfigColumns, - ) => PgTableExtraConfigValue[], - ): PgTableWithColumns<{ - name: TTableName; - schema: TSchema; - columns: BuildColumns; - dialect: 'pg'; - }>; - - < - TTableName extends string, - TColumnsMap extends Record, - >( - name: TTableName, - columns: (columnTypes: PgColumnsBuilders) => TColumnsMap, - extraConfig?: (self: BuildExtraConfigColumns) => PgTableExtraConfigValue[], - ): PgTableWithColumns<{ - name: TTableName; - schema: TSchema; - columns: BuildColumns; - dialect: 'pg'; - }>; } export const pgTable: PgTableFn = (name, columns, extraConfig) => { diff --git a/drizzle-orm/src/sqlite-core/table.ts b/drizzle-orm/src/sqlite-core/table.ts index 5a68f9cb1..290605b66 100644 --- a/drizzle-orm/src/sqlite-core/table.ts +++ b/drizzle-orm/src/sqlite-core/table.ts @@ -57,6 +57,35 @@ export type SQLiteTableWithColumns = }; export interface SQLiteTableFn { + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: TColumnsMap, + extraConfig?: ( + self: BuildColumns, + ) => SQLiteTableExtraConfigValue[], + ): SQLiteTableWithColumns<{ + name: TTableName; + schema: TSchema; + columns: BuildColumns; + dialect: 'sqlite'; + }>; + + < + TTableName extends string, + TColumnsMap extends Record, + >( + name: TTableName, + columns: (columnTypes: SQLiteColumnBuilders) => TColumnsMap, + extraConfig?: (self: BuildColumns) => SQLiteTableExtraConfigValue[], + ): SQLiteTableWithColumns<{ + name: TTableName; + schema: TSchema; + columns: BuildColumns; + dialect: 'sqlite'; + }>; /** * @deprecated The third parameter of sqliteTable is changing and will only accept an array instead of an object * @@ -128,36 +157,6 @@ export interface SQLiteTableFn { columns: BuildColumns; dialect: 'sqlite'; }>; - - < - TTableName extends string, - TColumnsMap extends Record, - >( - name: TTableName, - columns: TColumnsMap, - extraConfig?: ( - self: BuildColumns, - ) => SQLiteTableExtraConfigValue[], - ): SQLiteTableWithColumns<{ - name: TTableName; - schema: TSchema; - columns: BuildColumns; - dialect: 'sqlite'; - }>; - - < - TTableName extends string, - TColumnsMap extends Record, - >( - name: TTableName, - columns: (columnTypes: SQLiteColumnBuilders) => TColumnsMap, - extraConfig?: (self: BuildColumns) => SQLiteTableExtraConfigValue[], - ): SQLiteTableWithColumns<{ - name: TTableName; - schema: TSchema; - columns: BuildColumns; - dialect: 'sqlite'; - }>; } function sqliteTableBase< diff --git a/drizzle-typebox/package.json b/drizzle-typebox/package.json index a6c34fc69..6ba6f2235 100644 --- a/drizzle-typebox/package.json +++ b/drizzle-typebox/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-typebox", - "version": "0.2.0", + "version": "0.2.1", "description": "Generate Typebox schemas from Drizzle ORM schemas", "type": "module", "scripts": { @@ -70,4 +70,4 @@ "vitest": "^1.6.0", "zx": "^7.2.2" } -} +} \ No newline at end of file diff --git a/drizzle-valibot/package.json b/drizzle-valibot/package.json index c9e6a02e9..d68e55531 100644 --- a/drizzle-valibot/package.json +++ b/drizzle-valibot/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-valibot", - "version": "0.3.0", + "version": "0.3.1", "description": "Generate valibot schemas from Drizzle ORM schemas", "type": "module", "scripts": { @@ -70,4 +70,4 @@ "vitest": "^1.6.0", "zx": "^7.2.2" } -} +} \ No newline at end of file diff --git a/drizzle-zod/package.json b/drizzle-zod/package.json index ebbec398e..3d1df1919 100644 --- a/drizzle-zod/package.json +++ b/drizzle-zod/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-zod", - "version": "0.6.0", + "version": "0.6.1", "description": "Generate Zod schemas from Drizzle ORM schemas", "type": "module", "scripts": { @@ -79,4 +79,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} +} \ No newline at end of file From be0f8337a831b3d0d17177e6b770734a4d7c2b62 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 25 Dec 2024 09:56:37 +0200 Subject: [PATCH 466/492] dprint --- drizzle-orm/package.json | 2 +- drizzle-seed/package.json | 2 +- drizzle-typebox/package.json | 2 +- drizzle-valibot/package.json | 2 +- drizzle-zod/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 4385e34fd..5ab4de9b2 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -204,4 +204,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} \ No newline at end of file +} diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index ae5648cdb..cbc3b570c 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -102,4 +102,4 @@ "dependencies": { "pure-rand": "^6.1.0" } -} \ No newline at end of file +} diff --git a/drizzle-typebox/package.json b/drizzle-typebox/package.json index 6ba6f2235..c03d64105 100644 --- a/drizzle-typebox/package.json +++ b/drizzle-typebox/package.json @@ -70,4 +70,4 @@ "vitest": "^1.6.0", "zx": "^7.2.2" } -} \ No newline at end of file +} diff --git a/drizzle-valibot/package.json b/drizzle-valibot/package.json index d68e55531..621d36782 100644 --- a/drizzle-valibot/package.json +++ b/drizzle-valibot/package.json @@ -70,4 +70,4 @@ "vitest": "^1.6.0", "zx": "^7.2.2" } -} \ No newline at end of file +} diff --git a/drizzle-zod/package.json b/drizzle-zod/package.json index 3d1df1919..cb1e472fa 100644 --- a/drizzle-zod/package.json +++ b/drizzle-zod/package.json @@ -79,4 +79,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} \ No newline at end of file +} From fedc800b2c66504562c2bd8247185929a8434636 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Wed, 25 Dec 2024 12:44:54 +0200 Subject: [PATCH 467/492] fixes --- .gitignore | 2 ++ drizzle-seed/src/index.ts | 31 ++++++++++++++++++++-- drizzle-seed/src/services/SeedService.ts | 4 ++- drizzle-seed/src/services/versioning/v2.ts | 4 +-- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 570a706f8..c266f115f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,6 @@ rollup.config-*.mjs *.log .DS_Store drizzle-seed/src/test.ts +drizzle-seed/src/testMysql.ts +drizzle-seed/src/testSqlite.ts drizzle-seed/src/schemaTest.ts \ No newline at end of file diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index 98c449095..c73e497cb 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -927,7 +927,8 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { typeParams['scale'] = Number(match[2]); } } else if ( - sqlType.startsWith('varchar') + sqlType.startsWith('char') + || sqlType.startsWith('varchar') || sqlType.startsWith('binary') || sqlType.startsWith('varbinary') ) { @@ -1129,12 +1130,38 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { } tableRelations[dbToTsTableNamesMap[tableConfig.name] as string]!.push(...newRelations); + const getTypeParams = (sqlType: string) => { + // get type params and set only type + const typeParams: Column['typeParams'] = {}; + + if ( + sqlType.startsWith('decimal') + ) { + const match = sqlType.match(/\((\d+), *(\d+)\)/); + if (match) { + typeParams['precision'] = Number(match[1]); + typeParams['scale'] = Number(match[2]); + } + } else if ( + sqlType.startsWith('char') + || sqlType.startsWith('varchar') + || sqlType.startsWith('text') + ) { + const match = sqlType.match(/\((\d+)\)/); + if (match) { + typeParams['length'] = Number(match[1]); + } + } + + return typeParams; + }; + tables.push({ name: dbToTsTableNamesMap[tableConfig.name] as string, columns: tableConfig.columns.map((column) => ({ name: dbToTsColumnNamesMap[column.name] as string, columnType: column.getSQLType(), - typeParams: {}, + typeParams: getTypeParams(column.getSQLType()), dataType: column.dataType, hasDefault: column.hasDefault, default: column.default, diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 84165169e..1370138b4 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -260,6 +260,7 @@ export class SeedService { columnPossibleGenerator.generator = arrayGen; } + columnPossibleGenerator.generator.isUnique = col.isUnique; const uniqueGen = columnPossibleGenerator.generator.replaceIfUnique(); if (uniqueGen !== undefined) { columnPossibleGenerator.generator = uniqueGen; @@ -268,7 +269,6 @@ export class SeedService { // selecting version of generator columnPossibleGenerator.generator = this.selectVersionOfGenerator(columnPossibleGenerator.generator); - columnPossibleGenerator.generator.isUnique = col.isUnique; // TODO: for now only GenerateValuesFromArray support notNull property columnPossibleGenerator.generator.notNull = col.notNull; columnPossibleGenerator.generator.dataType = col.dataType; @@ -309,6 +309,8 @@ export class SeedService { const newGenerator = new generatorConstructor(generator.params); newGenerator.baseColumnDataType = generator.baseColumnDataType; newGenerator.isUnique = generator.isUnique; + // TODO: for now only GenerateValuesFromArray support notNull property + newGenerator.notNull = generator.notNull; newGenerator.dataType = generator.dataType; newGenerator.stringLength = generator.stringLength; diff --git a/drizzle-seed/src/services/versioning/v2.ts b/drizzle-seed/src/services/versioning/v2.ts index e09cc45f6..f4dbf32f4 100644 --- a/drizzle-seed/src/services/versioning/v2.ts +++ b/drizzle-seed/src/services/versioning/v2.ts @@ -126,7 +126,7 @@ export class GenerateStringV2 extends AbstractGenerator<{ override init({ count, seed }: { count: number; seed: number }) { super.init({ count, seed }); - let minStringLength = 8; + let minStringLength = 7; let maxStringLength = 20; if (this.stringLength !== undefined) { maxStringLength = this.stringLength; @@ -182,7 +182,7 @@ export class GenerateUniqueStringV2 extends AbstractGenerator<{ isUnique?: boole override init({ seed, count }: { seed: number; count: number }) { const rng = prand.xoroshiro128plus(seed); - let minStringLength = 8; + let minStringLength = 7; let maxStringLength = 20; // TODO: revise later if (this.stringLength !== undefined) { From fa9f4b7acaeacc6f2eaa9fb19a5bd1c007bfe283 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Wed, 25 Dec 2024 12:53:05 +0200 Subject: [PATCH 468/492] updated changelogs --- changelogs/drizzle-seed/0.2.0.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/changelogs/drizzle-seed/0.2.0.md b/changelogs/drizzle-seed/0.2.0.md index 5bb9d6007..bd2a5260e 100644 --- a/changelogs/drizzle-seed/0.2.0.md +++ b/changelogs/drizzle-seed/0.2.0.md @@ -123,4 +123,5 @@ However, after inserting the `1 minute 60 second` interval, PostgreSQL database Now (in version 2), the maximum length of a string depends on the length of the text column (e.g., `varchar(20)`). ## Bug fixes -- seeding table with foreign key referencing another table, without including the second table in schema, will cause seed process to get stuck. \ No newline at end of file +- seeding table with foreign key referencing another table, without including the second table in schema, will cause seed process to get stuck. +- not setting unique generators for unique database columns. \ No newline at end of file From 6854ac6c5fda8d34f2ea9980fed24ceb6a3b04d4 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Wed, 25 Dec 2024 13:17:33 +0200 Subject: [PATCH 469/492] fix --- changelogs/drizzle-seed/0.2.0.md | 1 - 1 file changed, 1 deletion(-) diff --git a/changelogs/drizzle-seed/0.2.0.md b/changelogs/drizzle-seed/0.2.0.md index 6c8573ee4..0978c7a98 100644 --- a/changelogs/drizzle-seed/0.2.0.md +++ b/changelogs/drizzle-seed/0.2.0.md @@ -159,7 +159,6 @@ export const table = p.sqliteTable('table', { await seed(db, { table }) ``` -Functions from refine that will be affected by this change: `` ## Bug fixes - Seeding a table with a foreign key referencing another table, without including the second table in the schema, will cause the seeding process to get stuck From ca569cb0a86b6059067f321ec51f0f9132a153b2 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 25 Dec 2024 13:35:11 +0200 Subject: [PATCH 470/492] Bump version --- changelogs/drizzle-seed/{0.2.0.md => 0.2.1.md} | 0 drizzle-seed/package.json | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename changelogs/drizzle-seed/{0.2.0.md => 0.2.1.md} (100%) diff --git a/changelogs/drizzle-seed/0.2.0.md b/changelogs/drizzle-seed/0.2.1.md similarity index 100% rename from changelogs/drizzle-seed/0.2.0.md rename to changelogs/drizzle-seed/0.2.1.md diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index cbc3b570c..b0606f04e 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-seed", - "version": "0.2.0", + "version": "0.2.1", "main": "index.js", "type": "module", "scripts": { @@ -102,4 +102,4 @@ "dependencies": { "pure-rand": "^6.1.0" } -} +} \ No newline at end of file From 06be106f3d111339466eb596d000d7580c89b01f Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Wed, 25 Dec 2024 13:38:37 +0200 Subject: [PATCH 471/492] dprint --- drizzle-seed/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index b0606f04e..29ceae587 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -102,4 +102,4 @@ "dependencies": { "pure-rand": "^6.1.0" } -} \ No newline at end of file +} From 10ba99f8b9a877a5e448fa8c761e272ae34752db Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Fri, 27 Dec 2024 17:04:35 +0200 Subject: [PATCH 472/492] using 'with' with soft relations --- .gitignore | 5 +- drizzle-seed/package.json | 2 +- drizzle-seed/src/index.ts | 371 +++++++++++++++--- drizzle-seed/src/services/SeedService.ts | 13 +- drizzle-seed/src/types/tables.ts | 2 +- .../mysql/softRelationsTest/mysqlSchema.ts | 128 ++++++ .../softRelationsTest/softRelations.test.ts | 314 +++++++++++++++ .../pg/allDataTypesTest/drizzle.config.ts | 7 - drizzle-seed/tests/pg/drizzle.config.ts | 7 - .../tests/pg/generatorsTest/drizzle.config.ts | 7 - drizzle-seed/tests/pg/pgSchema.ts | 26 -- .../tests/pg/softRelationsTest/pgSchema.ts | 130 ++++++ .../softRelationsTest/softRelations.test.ts | 254 ++++++++++++ .../softRelationsTest/softRelations.test.ts | 253 ++++++++++++ .../sqlite/softRelationsTest/sqliteSchema.ts | 128 ++++++ drizzle-seed/tsconfig.json | 2 +- 16 files changed, 1538 insertions(+), 111 deletions(-) create mode 100644 drizzle-seed/tests/mysql/softRelationsTest/mysqlSchema.ts create mode 100644 drizzle-seed/tests/mysql/softRelationsTest/softRelations.test.ts delete mode 100644 drizzle-seed/tests/pg/allDataTypesTest/drizzle.config.ts delete mode 100644 drizzle-seed/tests/pg/drizzle.config.ts delete mode 100644 drizzle-seed/tests/pg/generatorsTest/drizzle.config.ts create mode 100644 drizzle-seed/tests/pg/softRelationsTest/pgSchema.ts create mode 100644 drizzle-seed/tests/pg/softRelationsTest/softRelations.test.ts create mode 100644 drizzle-seed/tests/sqlite/softRelationsTest/softRelations.test.ts create mode 100644 drizzle-seed/tests/sqlite/softRelationsTest/sqliteSchema.ts diff --git a/.gitignore b/.gitignore index c266f115f..97b7170df 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,4 @@ dist-dts rollup.config-*.mjs *.log .DS_Store -drizzle-seed/src/test.ts -drizzle-seed/src/testMysql.ts -drizzle-seed/src/testSqlite.ts -drizzle-seed/src/schemaTest.ts \ No newline at end of file +drizzle-seed/src/dev \ No newline at end of file diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index cbc3b570c..4954bcdb7 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -12,7 +12,7 @@ "generate-for-tests:mysql": "drizzle-kit generate --config=./src/tests/mysql/drizzle.config.ts", "generate-for-tests:sqlite": "drizzle-kit generate --config=./src/tests/sqlite/drizzle.config.ts", "generate": "drizzle-kit generate", - "start": "npx tsx ./src/test.ts", + "start": "npx tsx ./src/dev/test.ts", "start:pg": "npx tsx ./src/tests/northwind/pgTest.ts", "start:mysql": "npx tsx ./src/tests/northwind/mysqlTest.ts", "start:sqlite": "npx tsx ./src/tests/northwind/sqliteTest.ts", diff --git a/drizzle-seed/src/index.ts b/drizzle-seed/src/index.ts index c73e497cb..cc416c84d 100644 --- a/drizzle-seed/src/index.ts +++ b/drizzle-seed/src/index.ts @@ -1,5 +1,13 @@ /* eslint-disable drizzle-internal/require-entity-kind */ -import { getTableName, is, sql } from 'drizzle-orm'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + getTableName, + is, + One, + Relations, + sql, +} from 'drizzle-orm'; import type { MySqlColumn, MySqlSchema } from 'drizzle-orm/mysql-core'; import { getTableConfig as getMysqlTableConfig, MySqlDatabase, MySqlTable } from 'drizzle-orm/mysql-core'; @@ -23,7 +31,7 @@ type InferCallbackType< | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { - [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable; + [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable | Relations; }, > = DB extends PgDatabase ? SCHEMA extends { [key: string]: @@ -31,7 +39,8 @@ type InferCallbackType< | PgSchema | MySqlTable | MySqlSchema - | SQLiteTable; + | SQLiteTable + | Relations; } ? { // iterates through schema fields. example -> schema: {"tableName": PgTable} [ @@ -63,7 +72,8 @@ type InferCallbackType< | PgSchema | MySqlTable | MySqlSchema - | SQLiteTable; + | SQLiteTable + | Relations; } ? { // iterates through schema fields. example -> schema: {"tableName": MySqlTable} [ @@ -95,7 +105,8 @@ type InferCallbackType< | PgSchema | MySqlTable | MySqlSchema - | SQLiteTable; + | SQLiteTable + | Relations; } ? { // iterates through schema fields. example -> schema: {"tableName": SQLiteTable} [ @@ -129,7 +140,7 @@ class SeedPromise< | MySqlDatabase | BaseSQLiteDatabase, SCHEMA extends { - [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable; + [key: string]: PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable | Relations; }, VERSION extends string | undefined, > implements Promise { @@ -344,6 +355,7 @@ export function seed< | MySqlTable | MySqlSchema | SQLiteTable + | Relations | any; }, VERSION extends '2' | '1' | undefined, @@ -360,6 +372,7 @@ const seedFunc = async ( | MySqlTable | MySqlSchema | SQLiteTable + | Relations | any; }, options: { count?: number; seed?: number; version?: string } = {}, @@ -371,17 +384,11 @@ const seedFunc = async ( } if (is(db, PgDatabase)) { - const { pgSchema } = filterPgTables(schema); - - await seedPostgres(db, pgSchema, { ...options, version }, refinements); + await seedPostgres(db, schema, { ...options, version }, refinements); } else if (is(db, MySqlDatabase)) { - const { mySqlSchema } = filterMySqlTables(schema); - - await seedMySql(db, mySqlSchema, { ...options, version }, refinements); + await seedMySql(db, schema, { ...options, version }, refinements); } else if (is(db, BaseSQLiteDatabase)) { - const { sqliteSchema } = filterSqliteTables(schema); - - await seedSqlite(db, sqliteSchema, { ...options, version }, refinements); + await seedSqlite(db, schema, { ...options, version }, refinements); } else { throw new Error( 'The drizzle-seed package currently supports only PostgreSQL, MySQL, and SQLite databases. Please ensure your database is one of these supported types', @@ -447,22 +454,22 @@ export async function reset< }, >(db: DB, schema: SCHEMA) { if (is(db, PgDatabase)) { - const { pgSchema } = filterPgTables(schema); + const { pgTables } = filterPgSchema(schema); - if (Object.entries(pgSchema).length > 0) { - await resetPostgres(db, pgSchema); + if (Object.entries(pgTables).length > 0) { + await resetPostgres(db, pgTables); } } else if (is(db, MySqlDatabase)) { - const { mySqlSchema } = filterMySqlTables(schema); + const { mysqlTables } = filterMysqlTables(schema); - if (Object.entries(mySqlSchema).length > 0) { - await resetMySql(db, mySqlSchema); + if (Object.entries(mysqlTables).length > 0) { + await resetMySql(db, mysqlTables); } } else if (is(db, BaseSQLiteDatabase)) { - const { sqliteSchema } = filterSqliteTables(schema); + const { sqliteTables } = filterSqliteTables(schema); - if (Object.entries(sqliteSchema).length > 0) { - await resetSqlite(db, sqliteSchema); + if (Object.entries(sqliteTables).length > 0) { + await resetSqlite(db, sqliteTables); } } else { throw new Error( @@ -474,9 +481,9 @@ export async function reset< // Postgres----------------------------------------------------------------------------------------------------------- const resetPostgres = async ( db: PgDatabase, - schema: { [key: string]: PgTable }, + pgTables: { [key: string]: PgTable }, ) => { - const tablesToTruncate = Object.entries(schema).map(([_, table]) => { + const tablesToTruncate = Object.entries(pgTables).map(([_, table]) => { const config = getPgTableConfig(table); config.schema = config.schema === undefined ? 'public' : config.schema; @@ -486,31 +493,49 @@ const resetPostgres = async ( await db.execute(sql.raw(`truncate ${tablesToTruncate.join(',')} cascade;`)); }; -const filterPgTables = (schema: { +const filterPgSchema = (schema: { [key: string]: | PgTable | PgSchema | MySqlTable | MySqlSchema | SQLiteTable + | Relations | any; }) => { const pgSchema = Object.fromEntries( + Object.entries(schema).filter((keyValue): keyValue is [string, PgTable | Relations] => + is(keyValue[1], PgTable) || is(keyValue[1], Relations) + ), + ); + + const pgTables = Object.fromEntries( Object.entries(schema).filter((keyValue): keyValue is [string, PgTable] => is(keyValue[1], PgTable)), ); - return { pgSchema }; + return { pgSchema, pgTables }; }; const seedPostgres = async ( db: PgDatabase, - schema: { [key: string]: PgTable }, + schema: { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | Relations + | any; + }, options: { count?: number; seed?: number; version?: number } = {}, refinements?: RefinementsType, ) => { const seedService = new SeedService(); - const { tables, relations } = getPostgresInfo(schema); + const { pgSchema, pgTables } = filterPgSchema(schema); + + const { tables, relations } = getPostgresInfo(pgSchema, pgTables); const generatedTablesGenerators = seedService.generatePossibleGenerators( 'postgresql', tables, @@ -525,7 +550,7 @@ const seedPostgres = async ( relations, generatedTablesGenerators, db, - schema, + pgTables, { ...options, preserveCyclicTablesData }, ); @@ -538,16 +563,19 @@ const seedPostgres = async ( relations, filteredTablesGenerators, db, - schema, + pgTables, { ...options, tablesValues, updateDataInDb, tablesUniqueNotNullColumn }, ); }; -const getPostgresInfo = (schema: { [key: string]: PgTable }) => { +const getPostgresInfo = ( + pgSchema: { [key: string]: PgTable | Relations }, + pgTables: { [key: string]: PgTable }, +) => { let tableConfig: ReturnType; let dbToTsColumnNamesMap: { [key: string]: string }; const dbToTsTableNamesMap: { [key: string]: string } = Object.fromEntries( - Object.entries(schema).map(([key, value]) => [getTableName(value), key]), + Object.entries(pgTables).map(([key, value]) => [getTableName(value), key]), ); const tables: Table[] = []; @@ -575,7 +603,65 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { return dbToTsColumnNamesMap; }; - for (const table of Object.values(schema)) { + const transformFromDrizzleRelation = ( + schema: Record, + getDbToTsColumnNamesMap: (table: PgTable) => { + [dbColName: string]: string; + }, + tableRelations: { + [tableName: string]: RelationWithReferences[]; + }, + ) => { + const schemaConfig = extractTablesRelationalConfig(schema, createTableRelationsHelpers); + const relations: RelationWithReferences[] = []; + for (const table of Object.values(schemaConfig.tables)) { + if (table.relations !== undefined) { + for (const drizzleRel of Object.values(table.relations)) { + if (is(drizzleRel, One)) { + const tableConfig = getPgTableConfig(drizzleRel.sourceTable as PgTable); + const tableDbSchema = tableConfig.schema ?? 'public'; + const tableDbName = tableConfig.name; + const tableTsName = schemaConfig.tableNamesMap[`${tableDbSchema}.${tableDbName}`] ?? tableDbName; + + const dbToTsColumnNamesMap = getDbToTsColumnNamesMap(drizzleRel.sourceTable); + const columns = drizzleRel.config?.fields.map((field) => dbToTsColumnNamesMap[field.name] as string) + ?? []; + + const refTableConfig = getPgTableConfig(drizzleRel.referencedTable as PgTable); + const refTableDbSchema = refTableConfig.schema ?? 'public'; + const refTableDbName = refTableConfig.name; + const refTableTsName = schemaConfig.tableNamesMap[`${refTableDbSchema}.${refTableDbName}`] + ?? refTableDbName; + + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap(drizzleRel.referencedTable); + const refColumns = drizzleRel.config?.references.map((ref) => + dbToTsColumnNamesMapForRefTable[ref.name] as string + ) + ?? []; + + if (tableRelations[refTableTsName] === undefined) { + tableRelations[refTableTsName] = []; + } + + const relation: RelationWithReferences = { + table: tableTsName, + columns, + refTable: refTableTsName, + refColumns, + refTableRels: tableRelations[refTableTsName], + type: 'one', + }; + + relations.push(relation); + tableRelations[tableTsName]!.push(relation); + } + } + } + } + return relations; + }; + + for (const table of Object.values(pgTables)) { tableConfig = getPgTableConfig(table); dbToTsColumnNamesMap = {}; @@ -707,6 +793,11 @@ const getPostgresInfo = (schema: { [key: string]: PgTable }) => { }); } + const transformedDrizzleRelations = transformFromDrizzleRelation(pgSchema, getDbToTsColumnNamesMap, tableRelations); + relations.push( + ...transformedDrizzleRelations, + ); + const isCyclicRelations = relations.map( (relI) => { // if (relations.some((relj) => relI.table === relj.refTable && relI.refTable === relj.table)) { @@ -777,7 +868,7 @@ const resetMySql = async ( await db.execute(sql.raw('SET FOREIGN_KEY_CHECKS = 1;')); }; -const filterMySqlTables = (schema: { +const filterMysqlTables = (schema: { [key: string]: | PgTable | PgSchema @@ -786,22 +877,39 @@ const filterMySqlTables = (schema: { | SQLiteTable | any; }) => { - const mySqlSchema = Object.fromEntries( + const mysqlSchema = Object.fromEntries( + Object.entries(schema).filter( + (keyValue): keyValue is [string, MySqlTable | Relations] => + is(keyValue[1], MySqlTable) || is(keyValue[1], Relations), + ), + ); + + const mysqlTables = Object.fromEntries( Object.entries(schema).filter( (keyValue): keyValue is [string, MySqlTable] => is(keyValue[1], MySqlTable), ), ); - return { mySqlSchema }; + return { mysqlSchema, mysqlTables }; }; const seedMySql = async ( db: MySqlDatabase, - schema: { [key: string]: MySqlTable }, + schema: { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | Relations + | any; + }, options: { count?: number; seed?: number; version?: number } = {}, refinements?: RefinementsType, ) => { - const { tables, relations } = getMySqlInfo(schema); + const { mysqlSchema, mysqlTables } = filterMysqlTables(schema); + const { tables, relations } = getMySqlInfo(mysqlSchema, mysqlTables); const seedService = new SeedService(); @@ -819,7 +927,7 @@ const seedMySql = async ( relations, generatedTablesGenerators, db, - schema, + mysqlTables, { ...options, preserveCyclicTablesData }, ); @@ -832,17 +940,20 @@ const seedMySql = async ( relations, filteredTablesGenerators, db, - schema, + mysqlTables, { ...options, tablesValues, updateDataInDb, tablesUniqueNotNullColumn }, ); }; -const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { +const getMySqlInfo = ( + mysqlSchema: { [key: string]: MySqlTable | Relations }, + mysqlTables: { [key: string]: MySqlTable }, +) => { let tableConfig: ReturnType; let dbToTsColumnNamesMap: { [key: string]: string }; const dbToTsTableNamesMap: { [key: string]: string } = Object.fromEntries( - Object.entries(schema).map(([key, value]) => [getTableName(value), key]), + Object.entries(mysqlTables).map(([key, value]) => [getTableName(value), key]), ); const tables: Table[] = []; @@ -870,7 +981,65 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { return dbToTsColumnNamesMap; }; - for (const table of Object.values(schema)) { + const transformFromDrizzleRelation = ( + schema: Record, + getDbToTsColumnNamesMap: (table: MySqlTable) => { + [dbColName: string]: string; + }, + tableRelations: { + [tableName: string]: RelationWithReferences[]; + }, + ) => { + const schemaConfig = extractTablesRelationalConfig(schema, createTableRelationsHelpers); + const relations: RelationWithReferences[] = []; + for (const table of Object.values(schemaConfig.tables)) { + if (table.relations !== undefined) { + for (const drizzleRel of Object.values(table.relations)) { + if (is(drizzleRel, One)) { + const tableConfig = getMysqlTableConfig(drizzleRel.sourceTable as MySqlTable); + const tableDbSchema = tableConfig.schema ?? 'public'; + const tableDbName = tableConfig.name; + const tableTsName = schemaConfig.tableNamesMap[`${tableDbSchema}.${tableDbName}`] ?? tableDbName; + + const dbToTsColumnNamesMap = getDbToTsColumnNamesMap(drizzleRel.sourceTable as MySqlTable); + const columns = drizzleRel.config?.fields.map((field) => dbToTsColumnNamesMap[field.name] as string) + ?? []; + + const refTableConfig = getMysqlTableConfig(drizzleRel.referencedTable as MySqlTable); + const refTableDbSchema = refTableConfig.schema ?? 'public'; + const refTableDbName = refTableConfig.name; + const refTableTsName = schemaConfig.tableNamesMap[`${refTableDbSchema}.${refTableDbName}`] + ?? refTableDbName; + + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap(drizzleRel.referencedTable as MySqlTable); + const refColumns = drizzleRel.config?.references.map((ref) => + dbToTsColumnNamesMapForRefTable[ref.name] as string + ) + ?? []; + + if (tableRelations[refTableTsName] === undefined) { + tableRelations[refTableTsName] = []; + } + + const relation: RelationWithReferences = { + table: tableTsName, + columns, + refTable: refTableTsName, + refColumns, + refTableRels: tableRelations[refTableTsName], + type: 'one', + }; + + relations.push(relation); + tableRelations[tableTsName]!.push(relation); + } + } + } + } + return relations; + }; + + for (const table of Object.values(mysqlTables)) { tableConfig = getMysqlTableConfig(table); dbToTsColumnNamesMap = {}; @@ -961,6 +1130,15 @@ const getMySqlInfo = (schema: { [key: string]: MySqlTable }) => { }); } + const transformedDrizzleRelations = transformFromDrizzleRelation( + mysqlSchema, + getDbToTsColumnNamesMap, + tableRelations, + ); + relations.push( + ...transformedDrizzleRelations, + ); + const isCyclicRelations = relations.map( (relI) => { const tableRel = tableRelations[relI.table]!.find((relJ) => relJ.refTable === relI.refTable)!; @@ -1006,21 +1184,39 @@ const filterSqliteTables = (schema: { | any; }) => { const sqliteSchema = Object.fromEntries( + Object.entries(schema).filter( + (keyValue): keyValue is [string, SQLiteTable | Relations] => + is(keyValue[1], SQLiteTable) || is(keyValue[1], Relations), + ), + ); + + const sqliteTables = Object.fromEntries( Object.entries(schema).filter( (keyValue): keyValue is [string, SQLiteTable] => is(keyValue[1], SQLiteTable), ), ); - return { sqliteSchema }; + return { sqliteSchema, sqliteTables }; }; const seedSqlite = async ( db: BaseSQLiteDatabase, - schema: { [key: string]: SQLiteTable }, + schema: { + [key: string]: + | PgTable + | PgSchema + | MySqlTable + | MySqlSchema + | SQLiteTable + | Relations + | any; + }, options: { count?: number; seed?: number; version?: number } = {}, refinements?: RefinementsType, ) => { - const { tables, relations } = getSqliteInfo(schema); + const { sqliteSchema, sqliteTables } = filterSqliteTables(schema); + + const { tables, relations } = getSqliteInfo(sqliteSchema, sqliteTables); const seedService = new SeedService(); @@ -1038,7 +1234,7 @@ const seedSqlite = async ( relations, generatedTablesGenerators, db, - schema, + sqliteTables, { ...options, preserveCyclicTablesData }, ); @@ -1051,16 +1247,19 @@ const seedSqlite = async ( relations, filteredTablesGenerators, db, - schema, + sqliteTables, { ...options, tablesValues, updateDataInDb, tablesUniqueNotNullColumn }, ); }; -const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { +const getSqliteInfo = ( + sqliteSchema: { [key: string]: SQLiteTable | Relations }, + sqliteTables: { [key: string]: SQLiteTable }, +) => { let tableConfig: ReturnType; let dbToTsColumnNamesMap: { [key: string]: string }; const dbToTsTableNamesMap: { [key: string]: string } = Object.fromEntries( - Object.entries(schema).map(([key, value]) => [getTableName(value), key]), + Object.entries(sqliteTables).map(([key, value]) => [getTableName(value), key]), ); const tables: Table[] = []; @@ -1088,7 +1287,64 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { return dbToTsColumnNamesMap; }; - for (const table of Object.values(schema)) { + const transformFromDrizzleRelation = ( + schema: Record, + getDbToTsColumnNamesMap: (table: SQLiteTable) => { + [dbColName: string]: string; + }, + tableRelations: { + [tableName: string]: RelationWithReferences[]; + }, + ) => { + const schemaConfig = extractTablesRelationalConfig(schema, createTableRelationsHelpers); + const relations: RelationWithReferences[] = []; + for (const table of Object.values(schemaConfig.tables)) { + if (table.relations !== undefined) { + for (const drizzleRel of Object.values(table.relations)) { + if (is(drizzleRel, One)) { + const tableConfig = getSqliteTableConfig(drizzleRel.sourceTable as SQLiteTable); + const tableDbName = tableConfig.name; + // TODO: tableNamesMap: have {public.customer: 'customer'} structure in sqlite + const tableTsName = schemaConfig.tableNamesMap[`public.${tableDbName}`] ?? tableDbName; + + const dbToTsColumnNamesMap = getDbToTsColumnNamesMap(drizzleRel.sourceTable as SQLiteTable); + const columns = drizzleRel.config?.fields.map((field) => dbToTsColumnNamesMap[field.name] as string) + ?? []; + + const refTableConfig = getSqliteTableConfig(drizzleRel.referencedTable as SQLiteTable); + const refTableDbName = refTableConfig.name; + const refTableTsName = schemaConfig.tableNamesMap[`public.${refTableDbName}`] + ?? refTableDbName; + + const dbToTsColumnNamesMapForRefTable = getDbToTsColumnNamesMap(drizzleRel.referencedTable as SQLiteTable); + const refColumns = drizzleRel.config?.references.map((ref) => + dbToTsColumnNamesMapForRefTable[ref.name] as string + ) + ?? []; + + if (tableRelations[refTableTsName] === undefined) { + tableRelations[refTableTsName] = []; + } + + const relation: RelationWithReferences = { + table: tableTsName, + columns, + refTable: refTableTsName, + refColumns, + refTableRels: tableRelations[refTableTsName], + type: 'one', + }; + + relations.push(relation); + tableRelations[tableTsName]!.push(relation); + } + } + } + } + return relations; + }; + + for (const table of Object.values(sqliteTables)) { tableConfig = getSqliteTableConfig(table); dbToTsColumnNamesMap = {}; @@ -1176,6 +1432,15 @@ const getSqliteInfo = (schema: { [key: string]: SQLiteTable }) => { }); } + const transformedDrizzleRelations = transformFromDrizzleRelation( + sqliteSchema, + getDbToTsColumnNamesMap, + tableRelations, + ); + relations.push( + ...transformedDrizzleRelations, + ); + const isCyclicRelations = relations.map( (relI) => { const tableRel = tableRelations[relI.table]!.find((relJ) => relJ.refTable === relI.refTable)!; diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 1370138b4..14550ae9b 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -110,9 +110,10 @@ export class SeedService { if (!tablesInOutRelations[table.name]?.dependantTableNames.has(fkTableName)) { const reason = tablesInOutRelations[table.name]?.selfRelation === true ? `"${table.name}" table has self reference` - : `"${fkTableName}" table doesn't have reference to "${table.name}" table`; + : `"${fkTableName}" table doesn't have reference to "${table.name}" table or` + + `\n you didn't include your one-to-many relation in the seed function schema`; throw new Error( - `${reason}. you can't specify "${fkTableName}" as parameter in ${table.name}.with object.`, + `${reason}.` + `\nYou can't specify "${fkTableName}" as parameter in ${table.name}.with object.`, ); } @@ -212,7 +213,9 @@ export class SeedService { if (foreignKeyColumns[col.name]?.table === undefined && col.notNull === true) { throw new Error( - `Column '${col.name}' has no null contraint, and you didn't specify a table for foreign key on column '${col.name}' in '${table.name}' table. You should pass `, + `Column '${col.name}' has not null contraint,` + + `\nand you didn't specify a table for foreign key on column '${col.name}' in '${table.name}' table.` + + `\n For more details, check this: https://orm.drizzle.team/docs/guides/seeding-with-partially-exposed-tables#example-1`, ); } @@ -223,7 +226,9 @@ export class SeedService { if (foreignKeyColumns[col.name]?.table === undefined && col.notNull === false) { console.warn( `Column '${col.name}' in '${table.name}' table will be filled with Null values` - + `\nbecause you specified neither a table for foreign key on column '${col.name}' nor a function for '${col.name}' column in refinements.`, + + `\nbecause you specified neither a table for foreign key on column '${col.name}'` + + `\nnor a function for '${col.name}' column in refinements.` + + `\nFor more details, check this: https://orm.drizzle.team/docs/guides/seeding-with-partially-exposed-tables#example-2`, ); } columnPossibleGenerator.generator = new generatorsMap.GenerateDefault[0]({ defaultValue: null }); diff --git a/drizzle-seed/src/types/tables.ts b/drizzle-seed/src/types/tables.ts index dc28c748d..2fadd23f0 100644 --- a/drizzle-seed/src/types/tables.ts +++ b/drizzle-seed/src/types/tables.ts @@ -29,7 +29,7 @@ export type Table = { export type Relation = { // name: string; - // type: "one" | "many"; + type?: 'one' | 'many'; table: string; // schema: string; columns: string[]; diff --git a/drizzle-seed/tests/mysql/softRelationsTest/mysqlSchema.ts b/drizzle-seed/tests/mysql/softRelationsTest/mysqlSchema.ts new file mode 100644 index 000000000..7f0fc17df --- /dev/null +++ b/drizzle-seed/tests/mysql/softRelationsTest/mysqlSchema.ts @@ -0,0 +1,128 @@ +import { relations } from 'drizzle-orm'; +import { float, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'; + +export const customers = mysqlTable('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = mysqlTable( + 'employee', + { + id: int('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: int('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: int('reports_to'), + photoPath: text('photo_path'), + }, +); + +export const employeesRelations = relations(employees, ({ one }) => ({ + employee: one(employees, { + fields: [employees.reportsTo], + references: [employees.id], + }), +})); + +export const orders = mysqlTable('order', { + id: int('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: int('ship_via').notNull(), + freight: float('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: varchar('customer_id', { length: 256 }).notNull(), + + employeeId: int('employee_id').notNull(), +}); + +export const ordersRelations = relations(orders, ({ one }) => ({ + customer: one(customers, { + fields: [orders.customerId], + references: [customers.id], + }), + employee: one(employees, { + fields: [orders.employeeId], + references: [employees.id], + }), +})); + +export const suppliers = mysqlTable('supplier', { + id: int('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = mysqlTable('product', { + id: int('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: float('unit_price').notNull(), + unitsInStock: int('units_in_stock').notNull(), + unitsOnOrder: int('units_on_order').notNull(), + reorderLevel: int('reorder_level').notNull(), + discontinued: int('discontinued').notNull(), + + supplierId: int('supplier_id').notNull(), +}); + +export const productsRelations = relations(products, ({ one }) => ({ + supplier: one(suppliers, { + fields: [products.supplierId], + references: [suppliers.id], + }), +})); + +export const details = mysqlTable('order_detail', { + unitPrice: float('unit_price').notNull(), + quantity: int('quantity').notNull(), + discount: float('discount').notNull(), + + orderId: int('order_id').notNull(), + + productId: int('product_id').notNull(), +}); + +export const detailsRelations = relations(details, ({ one }) => ({ + order: one(orders, { + fields: [details.orderId], + references: [orders.id], + }), + product: one(products, { + fields: [details.productId], + references: [products.id], + }), +})); diff --git a/drizzle-seed/tests/mysql/softRelationsTest/softRelations.test.ts b/drizzle-seed/tests/mysql/softRelationsTest/softRelations.test.ts new file mode 100644 index 000000000..7f61b80eb --- /dev/null +++ b/drizzle-seed/tests/mysql/softRelationsTest/softRelations.test.ts @@ -0,0 +1,314 @@ +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import type { MySql2Database } from 'drizzle-orm/mysql2'; +import { drizzle } from 'drizzle-orm/mysql2'; +import getPort from 'get-port'; +import type { Connection } from 'mysql2/promise'; +import { createConnection } from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../../src/index.ts'; +import * as schema from './mysqlSchema.ts'; + +let mysqlContainer: Docker.Container; +let client: Connection; +let db: MySql2Database; + +async function createDockerDB(): Promise { + const docker = new Docker(); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err)) + ); + + mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +beforeAll(async () => { + const connectionString = await createDockerDB(); + + const sleep = 1000; + let timeLeft = 40000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = await createConnection(connectionString); + await client.connect(); + db = drizzle(client); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); + throw lastError; + } + + await db.execute( + sql` + CREATE TABLE \`customer\` ( + \`id\` varchar(256) NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text, + \`region\` text, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + \`fax\` text, + CONSTRAINT \`customer_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`order_detail\` ( + \`unit_price\` float NOT NULL, + \`quantity\` int NOT NULL, + \`discount\` float NOT NULL, + \`order_id\` int NOT NULL, + \`product_id\` int NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`employee\` ( + \`id\` int NOT NULL, + \`last_name\` text NOT NULL, + \`first_name\` text, + \`title\` text NOT NULL, + \`title_of_courtesy\` text NOT NULL, + \`birth_date\` timestamp NOT NULL, + \`hire_date\` timestamp NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`home_phone\` text NOT NULL, + \`extension\` int NOT NULL, + \`notes\` text NOT NULL, + \`reports_to\` int, + \`photo_path\` text, + CONSTRAINT \`employee_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`order\` ( + \`id\` int NOT NULL, + \`order_date\` timestamp NOT NULL, + \`required_date\` timestamp NOT NULL, + \`shipped_date\` timestamp, + \`ship_via\` int NOT NULL, + \`freight\` float NOT NULL, + \`ship_name\` text NOT NULL, + \`ship_city\` text NOT NULL, + \`ship_region\` text, + \`ship_postal_code\` text, + \`ship_country\` text NOT NULL, + \`customer_id\` varchar(256) NOT NULL, + \`employee_id\` int NOT NULL, + CONSTRAINT \`order_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`product\` ( + \`id\` int NOT NULL, + \`name\` text NOT NULL, + \`quantity_per_unit\` text NOT NULL, + \`unit_price\` float NOT NULL, + \`units_in_stock\` int NOT NULL, + \`units_on_order\` int NOT NULL, + \`reorder_level\` int NOT NULL, + \`discontinued\` int NOT NULL, + \`supplier_id\` int NOT NULL, + CONSTRAINT \`product_id\` PRIMARY KEY(\`id\`) + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE \`supplier\` ( + \`id\` int NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`region\` text, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + CONSTRAINT \`supplier_id\` PRIMARY KEY(\`id\`) + ); + `, + ); +}); + +afterAll(async () => { + await client?.end().catch(console.error); + await mysqlContainer?.stop().catch(console.error); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +const checkSoftRelations = ( + customers: (typeof schema.customers.$inferSelect)[], + details: (typeof schema.details.$inferSelect)[], + employees: (typeof schema.employees.$inferSelect)[], + orders: (typeof schema.orders.$inferSelect)[], + products: (typeof schema.products.$inferSelect)[], + suppliers: (typeof schema.suppliers.$inferSelect)[], +) => { + // employees soft relations check + const employeeIds = new Set(employees.map((employee) => employee.id)); + const employeesPredicate = employees.every((employee) => + employee.reportsTo !== null && employeeIds.has(employee.reportsTo) + ); + expect(employeesPredicate).toBe(true); + + // orders soft relations check + const customerIds = new Set(customers.map((customer) => customer.id)); + const ordersPredicate1 = orders.every((order) => order.customerId !== null && customerIds.has(order.customerId)); + expect(ordersPredicate1).toBe(true); + + const ordersPredicate2 = orders.every((order) => order.employeeId !== null && employeeIds.has(order.employeeId)); + expect(ordersPredicate2).toBe(true); + + // product soft relations check + const supplierIds = new Set(suppliers.map((supplier) => supplier.id)); + const productsPredicate = products.every((product) => + product.supplierId !== null && supplierIds.has(product.supplierId) + ); + expect(productsPredicate).toBe(true); + + // details soft relations check + const orderIds = new Set(orders.map((order) => order.id)); + const detailsPredicate1 = details.every((detail) => detail.orderId !== null && orderIds.has(detail.orderId)); + expect(detailsPredicate1).toBe(true); + + const productIds = new Set(products.map((product) => product.id)); + const detailsPredicate2 = details.every((detail) => detail.productId !== null && productIds.has(detail.productId)); + expect(detailsPredicate2).toBe(true); +}; + +test('basic seed, soft relations test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); + + checkSoftRelations(customers, details, employees, orders, products, suppliers); +}); + +test("redefine(refine) orders count using 'with' in customers, soft relations test", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); + + checkSoftRelations(customers, details, employees, orders, products, suppliers); +}); + +test("sequential using of 'with', soft relations test", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); + + checkSoftRelations(customers, details, employees, orders, products, suppliers); +}); diff --git a/drizzle-seed/tests/pg/allDataTypesTest/drizzle.config.ts b/drizzle-seed/tests/pg/allDataTypesTest/drizzle.config.ts deleted file mode 100644 index 131b4d025..000000000 --- a/drizzle-seed/tests/pg/allDataTypesTest/drizzle.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'drizzle-kit'; - -export default defineConfig({ - schema: './src/tests/pg/allDataTypesTest/pgSchema.ts', - out: './src/tests/pg/allDataTypesTest/pgMigrations', - dialect: 'postgresql', -}); diff --git a/drizzle-seed/tests/pg/drizzle.config.ts b/drizzle-seed/tests/pg/drizzle.config.ts deleted file mode 100644 index 65b65236f..000000000 --- a/drizzle-seed/tests/pg/drizzle.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'drizzle-kit'; - -export default defineConfig({ - schema: './src/tests/pg/pgSchema.ts', - out: './src/tests/pg/pgMigrations', - dialect: 'postgresql', -}); diff --git a/drizzle-seed/tests/pg/generatorsTest/drizzle.config.ts b/drizzle-seed/tests/pg/generatorsTest/drizzle.config.ts deleted file mode 100644 index 30331986c..000000000 --- a/drizzle-seed/tests/pg/generatorsTest/drizzle.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'drizzle-kit'; - -export default defineConfig({ - schema: './src/tests/pg/generatorsTest/pgSchema.ts', - out: './src/tests/pg/generatorsTest/pgMigrations', - dialect: 'postgresql', -}); diff --git a/drizzle-seed/tests/pg/pgSchema.ts b/drizzle-seed/tests/pg/pgSchema.ts index f6f4f8347..1a9af755e 100644 --- a/drizzle-seed/tests/pg/pgSchema.ts +++ b/drizzle-seed/tests/pg/pgSchema.ts @@ -1,29 +1,3 @@ -// import { serial, integer, varchar, pgSchema, getTableConfig as getPgTableConfig } from "drizzle-orm/pg-core"; - -// export const schema = pgSchema("seeder_lib_pg"); - -// export const users = schema.table("users", { -// id: serial("id").primaryKey(), -// name: varchar("name", { length: 256 }), -// email: varchar("email", { length: 256 }), -// phone: varchar("phone", { length: 256 }), -// password: varchar("password", { length: 256 }) -// }); - -// export const posts = schema.table("posts", { -// id: serial("id").primaryKey(), -// title: varchar("title", { length: 256 }), -// content: varchar("content", { length: 256 }), -// userId: integer("user_id").references(() => users.id) -// }); - -// export const comments = schema.table("comments", { -// id: serial("id").primaryKey(), -// content: varchar("content", { length: 256 }), -// postId: integer("post_id").references(() => posts.id), -// userId: integer("user_id").references(() => users.id) -// }); - import type { AnyPgColumn } from 'drizzle-orm/pg-core'; import { integer, numeric, pgSchema, serial, text, timestamp, varchar } from 'drizzle-orm/pg-core'; diff --git a/drizzle-seed/tests/pg/softRelationsTest/pgSchema.ts b/drizzle-seed/tests/pg/softRelationsTest/pgSchema.ts new file mode 100644 index 000000000..357ea23cf --- /dev/null +++ b/drizzle-seed/tests/pg/softRelationsTest/pgSchema.ts @@ -0,0 +1,130 @@ +import { relations } from 'drizzle-orm'; +import { integer, numeric, pgSchema, text, timestamp, varchar } from 'drizzle-orm/pg-core'; + +export const schema = pgSchema('seeder_lib_pg'); + +export const customers = schema.table('customer', { + id: varchar('id', { length: 256 }).primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = schema.table( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: timestamp('birth_date').notNull(), + hireDate: timestamp('hire_date').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to'), + photoPath: text('photo_path'), + }, +); + +export const employeesRelations = relations(employees, ({ one }) => ({ + employee: one(employees, { + fields: [employees.reportsTo], + references: [employees.id], + }), +})); + +export const orders = schema.table('order', { + id: integer('id').primaryKey(), + orderDate: timestamp('order_date').notNull(), + requiredDate: timestamp('required_date').notNull(), + shippedDate: timestamp('shipped_date'), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id').notNull(), + + employeeId: integer('employee_id').notNull(), +}); + +export const ordersRelations = relations(orders, ({ one }) => ({ + customer: one(customers, { + fields: [orders.customerId], + references: [customers.id], + }), + employee: one(employees, { + fields: [orders.employeeId], + references: [employees.id], + }), +})); + +export const suppliers = schema.table('supplier', { + id: integer('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = schema.table('product', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id').notNull(), +}); + +export const productsRelations = relations(products, ({ one }) => ({ + supplier: one(suppliers, { + fields: [products.supplierId], + references: [suppliers.id], + }), +})); + +export const details = schema.table('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id').notNull(), + + productId: integer('product_id').notNull(), +}); + +export const detailsRelations = relations(details, ({ one }) => ({ + order: one(orders, { + fields: [details.orderId], + references: [orders.id], + }), + product: one(products, { + fields: [details.productId], + references: [products.id], + }), +})); diff --git a/drizzle-seed/tests/pg/softRelationsTest/softRelations.test.ts b/drizzle-seed/tests/pg/softRelationsTest/softRelations.test.ts new file mode 100644 index 000000000..205647812 --- /dev/null +++ b/drizzle-seed/tests/pg/softRelationsTest/softRelations.test.ts @@ -0,0 +1,254 @@ +import { PGlite } from '@electric-sql/pglite'; +import { sql } from 'drizzle-orm'; +import type { PgliteDatabase } from 'drizzle-orm/pglite'; +import { drizzle } from 'drizzle-orm/pglite'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../../src/index.ts'; +import * as schema from './pgSchema.ts'; + +let client: PGlite; +let db: PgliteDatabase; + +beforeAll(async () => { + client = new PGlite(); + + db = drizzle(client); + + await db.execute(sql`CREATE SCHEMA "seeder_lib_pg";`); + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."customer" ( + "id" varchar(256) PRIMARY KEY NOT NULL, + "company_name" text NOT NULL, + "contact_name" text NOT NULL, + "contact_title" text NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "postal_code" text, + "region" text, + "country" text NOT NULL, + "phone" text NOT NULL, + "fax" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."order_detail" ( + "unit_price" numeric NOT NULL, + "quantity" integer NOT NULL, + "discount" numeric NOT NULL, + "order_id" integer NOT NULL, + "product_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."employee" ( + "id" integer PRIMARY KEY NOT NULL, + "last_name" text NOT NULL, + "first_name" text, + "title" text NOT NULL, + "title_of_courtesy" text NOT NULL, + "birth_date" timestamp NOT NULL, + "hire_date" timestamp NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "postal_code" text NOT NULL, + "country" text NOT NULL, + "home_phone" text NOT NULL, + "extension" integer NOT NULL, + "notes" text NOT NULL, + "reports_to" integer, + "photo_path" text + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."order" ( + "id" integer PRIMARY KEY NOT NULL, + "order_date" timestamp NOT NULL, + "required_date" timestamp NOT NULL, + "shipped_date" timestamp, + "ship_via" integer NOT NULL, + "freight" numeric NOT NULL, + "ship_name" text NOT NULL, + "ship_city" text NOT NULL, + "ship_region" text, + "ship_postal_code" text, + "ship_country" text NOT NULL, + "customer_id" text NOT NULL, + "employee_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."product" ( + "id" integer PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "quantity_per_unit" text NOT NULL, + "unit_price" numeric NOT NULL, + "units_in_stock" integer NOT NULL, + "units_on_order" integer NOT NULL, + "reorder_level" integer NOT NULL, + "discontinued" integer NOT NULL, + "supplier_id" integer NOT NULL + ); + `, + ); + + await db.execute( + sql` + CREATE TABLE IF NOT EXISTS "seeder_lib_pg"."supplier" ( + "id" integer PRIMARY KEY NOT NULL, + "company_name" text NOT NULL, + "contact_name" text NOT NULL, + "contact_title" text NOT NULL, + "address" text NOT NULL, + "city" text NOT NULL, + "region" text, + "postal_code" text NOT NULL, + "country" text NOT NULL, + "phone" text NOT NULL + ); + `, + ); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +afterAll(async () => { + await client.close(); +}); + +const checkSoftRelations = ( + customers: (typeof schema.customers.$inferSelect)[], + details: (typeof schema.details.$inferSelect)[], + employees: (typeof schema.employees.$inferSelect)[], + orders: (typeof schema.orders.$inferSelect)[], + products: (typeof schema.products.$inferSelect)[], + suppliers: (typeof schema.suppliers.$inferSelect)[], +) => { + // employees soft relations check + const employeeIds = new Set(employees.map((employee) => employee.id)); + const employeesPredicate = employees.every((employee) => + employee.reportsTo !== null && employeeIds.has(employee.reportsTo) + ); + expect(employeesPredicate).toBe(true); + + // orders soft relations check + const customerIds = new Set(customers.map((customer) => customer.id)); + const ordersPredicate1 = orders.every((order) => order.customerId !== null && customerIds.has(order.customerId)); + expect(ordersPredicate1).toBe(true); + + const ordersPredicate2 = orders.every((order) => order.employeeId !== null && employeeIds.has(order.employeeId)); + expect(ordersPredicate2).toBe(true); + + // product soft relations check + const supplierIds = new Set(suppliers.map((supplier) => supplier.id)); + const productsPredicate = products.every((product) => + product.supplierId !== null && supplierIds.has(product.supplierId) + ); + expect(productsPredicate).toBe(true); + + // details soft relations check + const orderIds = new Set(orders.map((order) => order.id)); + const detailsPredicate1 = details.every((detail) => detail.orderId !== null && orderIds.has(detail.orderId)); + expect(detailsPredicate1).toBe(true); + + const productIds = new Set(products.map((product) => product.id)); + const detailsPredicate2 = details.every((detail) => detail.productId !== null && productIds.has(detail.productId)); + expect(detailsPredicate2).toBe(true); +}; + +test('basic seed, soft relations test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); + + checkSoftRelations(customers, details, employees, orders, products, suppliers); +}); + +test("redefine(refine) orders count using 'with' in customers, soft relations test", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); + + checkSoftRelations(customers, details, employees, orders, products, suppliers); +}); + +test("sequential using of 'with', soft relations test", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); + + checkSoftRelations(customers, details, employees, orders, products, suppliers); +}); diff --git a/drizzle-seed/tests/sqlite/softRelationsTest/softRelations.test.ts b/drizzle-seed/tests/sqlite/softRelationsTest/softRelations.test.ts new file mode 100644 index 000000000..124ac8ee1 --- /dev/null +++ b/drizzle-seed/tests/sqlite/softRelationsTest/softRelations.test.ts @@ -0,0 +1,253 @@ +import BetterSqlite3 from 'better-sqlite3'; +import { sql } from 'drizzle-orm'; +import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'; +import { reset, seed } from '../../../src/index.ts'; +import * as schema from './sqliteSchema.ts'; + +let client: BetterSqlite3.Database; +let db: BetterSQLite3Database; + +beforeAll(async () => { + client = new BetterSqlite3(':memory:'); + + db = drizzle(client); + + db.run( + sql.raw(` + CREATE TABLE \`customer\` ( + \`id\` text PRIMARY KEY NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text, + \`region\` text, + \`country\` text NOT NULL, + \`phone\` text NOT NULL, + \`fax\` text +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`order_detail\` ( + \`unit_price\` numeric NOT NULL, + \`quantity\` integer NOT NULL, + \`discount\` numeric NOT NULL, + \`order_id\` integer NOT NULL, + \`product_id\` integer NOT NULL +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`employee\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`last_name\` text NOT NULL, + \`first_name\` text, + \`title\` text NOT NULL, + \`title_of_courtesy\` text NOT NULL, + \`birth_date\` integer NOT NULL, + \`hire_date\` integer NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`home_phone\` text NOT NULL, + \`extension\` integer NOT NULL, + \`notes\` text NOT NULL, + \`reports_to\` integer, + \`photo_path\` text +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`order\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`order_date\` integer NOT NULL, + \`required_date\` integer NOT NULL, + \`shipped_date\` integer, + \`ship_via\` integer NOT NULL, + \`freight\` numeric NOT NULL, + \`ship_name\` text NOT NULL, + \`ship_city\` text NOT NULL, + \`ship_region\` text, + \`ship_postal_code\` text, + \`ship_country\` text NOT NULL, + \`customer_id\` text NOT NULL, + \`employee_id\` integer NOT NULL +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`product\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`name\` text NOT NULL, + \`quantity_per_unit\` text NOT NULL, + \`unit_price\` numeric NOT NULL, + \`units_in_stock\` integer NOT NULL, + \`units_on_order\` integer NOT NULL, + \`reorder_level\` integer NOT NULL, + \`discontinued\` integer NOT NULL, + \`supplier_id\` integer NOT NULL +); + `), + ); + + db.run( + sql.raw(` + CREATE TABLE \`supplier\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`company_name\` text NOT NULL, + \`contact_name\` text NOT NULL, + \`contact_title\` text NOT NULL, + \`address\` text NOT NULL, + \`city\` text NOT NULL, + \`region\` text, + \`postal_code\` text NOT NULL, + \`country\` text NOT NULL, + \`phone\` text NOT NULL +); + `), + ); +}); + +afterAll(async () => { + client.close(); +}); + +afterEach(async () => { + await reset(db, schema); +}); + +const checkSoftRelations = ( + customers: (typeof schema.customers.$inferSelect)[], + details: (typeof schema.details.$inferSelect)[], + employees: (typeof schema.employees.$inferSelect)[], + orders: (typeof schema.orders.$inferSelect)[], + products: (typeof schema.products.$inferSelect)[], + suppliers: (typeof schema.suppliers.$inferSelect)[], +) => { + // employees soft relations check + const employeeIds = new Set(employees.map((employee) => employee.id)); + const employeesPredicate = employees.every((employee) => + employee.reportsTo !== null && employeeIds.has(employee.reportsTo) + ); + expect(employeesPredicate).toBe(true); + + // orders soft relations check + const customerIds = new Set(customers.map((customer) => customer.id)); + const ordersPredicate1 = orders.every((order) => order.customerId !== null && customerIds.has(order.customerId)); + expect(ordersPredicate1).toBe(true); + + const ordersPredicate2 = orders.every((order) => order.employeeId !== null && employeeIds.has(order.employeeId)); + expect(ordersPredicate2).toBe(true); + + // product soft relations check + const supplierIds = new Set(suppliers.map((supplier) => supplier.id)); + const productsPredicate = products.every((product) => + product.supplierId !== null && supplierIds.has(product.supplierId) + ); + expect(productsPredicate).toBe(true); + + // details soft relations check + const orderIds = new Set(orders.map((order) => order.id)); + const detailsPredicate1 = details.every((detail) => detail.orderId !== null && orderIds.has(detail.orderId)); + expect(detailsPredicate1).toBe(true); + + const productIds = new Set(products.map((product) => product.id)); + const detailsPredicate2 = details.every((detail) => detail.productId !== null && productIds.has(detail.productId)); + expect(detailsPredicate2).toBe(true); +}; + +test('basic seed, soft relations test', async () => { + await seed(db, schema); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(10); + expect(details.length).toBe(10); + expect(employees.length).toBe(10); + expect(orders.length).toBe(10); + expect(products.length).toBe(10); + expect(suppliers.length).toBe(10); + + checkSoftRelations(customers, details, employees, orders, products, suppliers); +}); + +test("redefine(refine) orders count using 'with' in customers, soft relations test", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 13, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(11); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); + + checkSoftRelations(customers, details, employees, orders, products, suppliers); +}); + +test("sequential using of 'with', soft relations test", async () => { + await seed(db, schema, { count: 11 }).refine(() => ({ + customers: { + count: 4, + with: { + orders: 2, + }, + }, + orders: { + count: 12, + with: { + details: 3, + }, + }, + })); + + const customers = await db.select().from(schema.customers); + const details = await db.select().from(schema.details); + const employees = await db.select().from(schema.employees); + const orders = await db.select().from(schema.orders); + const products = await db.select().from(schema.products); + const suppliers = await db.select().from(schema.suppliers); + + expect(customers.length).toBe(4); + expect(details.length).toBe(24); + expect(employees.length).toBe(11); + expect(orders.length).toBe(8); + expect(products.length).toBe(11); + expect(suppliers.length).toBe(11); + + checkSoftRelations(customers, details, employees, orders, products, suppliers); +}); diff --git a/drizzle-seed/tests/sqlite/softRelationsTest/sqliteSchema.ts b/drizzle-seed/tests/sqlite/softRelationsTest/sqliteSchema.ts new file mode 100644 index 000000000..75572c63a --- /dev/null +++ b/drizzle-seed/tests/sqlite/softRelationsTest/sqliteSchema.ts @@ -0,0 +1,128 @@ +import { relations } from 'drizzle-orm'; +import { integer, numeric, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const customers = sqliteTable('customer', { + id: text('id').primaryKey(), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code'), + region: text('region'), + country: text('country').notNull(), + phone: text('phone').notNull(), + fax: text('fax'), +}); + +export const employees = sqliteTable( + 'employee', + { + id: integer('id').primaryKey(), + lastName: text('last_name').notNull(), + firstName: text('first_name'), + title: text('title').notNull(), + titleOfCourtesy: text('title_of_courtesy').notNull(), + birthDate: integer('birth_date', { mode: 'timestamp' }).notNull(), + hireDate: integer('hire_date', { mode: 'timestamp' }).notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + homePhone: text('home_phone').notNull(), + extension: integer('extension').notNull(), + notes: text('notes').notNull(), + reportsTo: integer('reports_to'), + photoPath: text('photo_path'), + }, +); + +export const employeesRelations = relations(employees, ({ one }) => ({ + employee: one(employees, { + fields: [employees.reportsTo], + references: [employees.id], + }), +})); + +export const orders = sqliteTable('order', { + id: integer('id').primaryKey(), + orderDate: integer('order_date', { mode: 'timestamp' }).notNull(), + requiredDate: integer('required_date', { mode: 'timestamp' }).notNull(), + shippedDate: integer('shipped_date', { mode: 'timestamp' }), + shipVia: integer('ship_via').notNull(), + freight: numeric('freight').notNull(), + shipName: text('ship_name').notNull(), + shipCity: text('ship_city').notNull(), + shipRegion: text('ship_region'), + shipPostalCode: text('ship_postal_code'), + shipCountry: text('ship_country').notNull(), + + customerId: text('customer_id').notNull(), + + employeeId: integer('employee_id').notNull(), +}); + +export const ordersRelations = relations(orders, ({ one }) => ({ + customer: one(customers, { + fields: [orders.customerId], + references: [customers.id], + }), + employee: one(employees, { + fields: [orders.employeeId], + references: [employees.id], + }), +})); + +export const suppliers = sqliteTable('supplier', { + id: integer('id').primaryKey({ autoIncrement: true }), + companyName: text('company_name').notNull(), + contactName: text('contact_name').notNull(), + contactTitle: text('contact_title').notNull(), + address: text('address').notNull(), + city: text('city').notNull(), + region: text('region'), + postalCode: text('postal_code').notNull(), + country: text('country').notNull(), + phone: text('phone').notNull(), +}); + +export const products = sqliteTable('product', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + quantityPerUnit: text('quantity_per_unit').notNull(), + unitPrice: numeric('unit_price').notNull(), + unitsInStock: integer('units_in_stock').notNull(), + unitsOnOrder: integer('units_on_order').notNull(), + reorderLevel: integer('reorder_level').notNull(), + discontinued: integer('discontinued').notNull(), + + supplierId: integer('supplier_id').notNull(), +}); + +export const productsRelations = relations(products, ({ one }) => ({ + supplier: one(suppliers, { + fields: [products.supplierId], + references: [suppliers.id], + }), +})); + +export const details = sqliteTable('order_detail', { + unitPrice: numeric('unit_price').notNull(), + quantity: integer('quantity').notNull(), + discount: numeric('discount').notNull(), + + orderId: integer('order_id').notNull(), + + productId: integer('product_id').notNull(), +}); + +export const detailsRelations = relations(details, ({ one }) => ({ + order: one(orders, { + fields: [details.orderId], + references: [orders.id], + }), + product: one(products, { + fields: [details.productId], + references: [products.id], + }), +})); diff --git a/drizzle-seed/tsconfig.json b/drizzle-seed/tsconfig.json index 222e6a4dd..f32902e10 100644 --- a/drizzle-seed/tsconfig.json +++ b/drizzle-seed/tsconfig.json @@ -43,6 +43,6 @@ "~/*": ["src/*"] } }, - "exclude": ["**/dist", "src/schemaTest.ts", "src/test.ts"], + "exclude": ["**/dist", "src/dev"], "include": ["src", "*.ts", "tests"] } From fc2c675376b7c8cc091dfdff5fca79b85612cee8 Mon Sep 17 00:00:00 2001 From: Maciej Zieniuk Date: Sun, 29 Dec 2024 14:06:04 +0000 Subject: [PATCH 473/492] DROP INDEX does not include PG Schema prefix In PostgreSQL created indexes will belong to the same schema, as the table, to which the index belongs to. When generating SQL for migration an index name does not currently contain the schema prefix. This is incorrect, since there is no guarantee that the selected schema of the connection, during the SQL migration, is the same as the schema of the index, causing the SQL migration to fail. Therefore, all index names needs to be prefixed with the schema name. --- drizzle-kit/src/sqlgenerator.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index 26adaf531..6d3034b61 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -3557,8 +3557,12 @@ class PgDropIndexConvertor extends Convertor { } convert(statement: JsonDropIndexStatement): string { + const { schema } = statement; const { name } = PgSquasher.unsquashIdx(statement.data); - return `DROP INDEX "${name}";`; + + const indexNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; + + return `DROP INDEX ${indexNameWithSchema};`; } } From d8377e5bfc3f656b617edb4ee5401da66e049809 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 30 Dec 2024 13:08:24 +0200 Subject: [PATCH 474/492] fixes --- drizzle-seed/src/services/SeedService.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index 14550ae9b..df5a6dda3 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -66,6 +66,7 @@ export class SeedService { return table1Order - table2Order; }); + const tableNamesSet = new Set(tables.map((table) => table.name)); const tablesPossibleGenerators: Prettify< (typeof tablePossibleGenerators)[] > = tables.map((table) => ({ @@ -211,24 +212,36 @@ export class SeedService { columnPossibleGenerator.isCyclic = true; } - if (foreignKeyColumns[col.name]?.table === undefined && col.notNull === true) { + if ( + (foreignKeyColumns[col.name]?.table === undefined || !tableNamesSet.has(foreignKeyColumns[col.name]!.table)) + && col.notNull === true + ) { throw new Error( `Column '${col.name}' has not null contraint,` + `\nand you didn't specify a table for foreign key on column '${col.name}' in '${table.name}' table.` - + `\n For more details, check this: https://orm.drizzle.team/docs/guides/seeding-with-partially-exposed-tables#example-1`, + + `\n\nFor more details, check this: https://orm.drizzle.team/docs/guides/seeding-with-partially-exposed-tables#example-1`, ); } - const predicate = (cyclicRelation !== undefined || foreignKeyColumns[col.name]?.table === undefined) + const predicate = ( + cyclicRelation !== undefined + || ( + foreignKeyColumns[col.name]?.table === undefined + || !tableNamesSet.has(foreignKeyColumns[col.name]!.table) + ) + ) && col.notNull === false; if (predicate === true) { - if (foreignKeyColumns[col.name]?.table === undefined && col.notNull === false) { + if ( + (foreignKeyColumns[col.name]?.table === undefined + || !tableNamesSet.has(foreignKeyColumns[col.name]!.table)) && col.notNull === false + ) { console.warn( `Column '${col.name}' in '${table.name}' table will be filled with Null values` + `\nbecause you specified neither a table for foreign key on column '${col.name}'` + `\nnor a function for '${col.name}' column in refinements.` - + `\nFor more details, check this: https://orm.drizzle.team/docs/guides/seeding-with-partially-exposed-tables#example-2`, + + `\n\nFor more details, check this: https://orm.drizzle.team/docs/guides/seeding-with-partially-exposed-tables#example-2`, ); } columnPossibleGenerator.generator = new generatorsMap.GenerateDefault[0]({ defaultValue: null }); From a89b04954a6c8085cb7c0c68718a044d7a73e561 Mon Sep 17 00:00:00 2001 From: OleksiiKH0240 Date: Mon, 30 Dec 2024 19:28:34 +0200 Subject: [PATCH 475/492] changes in error messages --- drizzle-seed/src/services/SeedService.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drizzle-seed/src/services/SeedService.ts b/drizzle-seed/src/services/SeedService.ts index df5a6dda3..e68a939e0 100644 --- a/drizzle-seed/src/services/SeedService.ts +++ b/drizzle-seed/src/services/SeedService.ts @@ -111,10 +111,11 @@ export class SeedService { if (!tablesInOutRelations[table.name]?.dependantTableNames.has(fkTableName)) { const reason = tablesInOutRelations[table.name]?.selfRelation === true ? `"${table.name}" table has self reference` - : `"${fkTableName}" table doesn't have reference to "${table.name}" table or` - + `\n you didn't include your one-to-many relation in the seed function schema`; + : `"${fkTableName}" table doesn't have a reference to "${table.name}" table or` + + `\nyou didn't include your one-to-many relation in the seed function schema`; throw new Error( - `${reason}.` + `\nYou can't specify "${fkTableName}" as parameter in ${table.name}.with object.`, + `${reason}.` + `\nYou can't specify "${fkTableName}" as parameter in ${table.name}.with object.` + + `\n\nFor more details, check this: https://orm.drizzle.team/docs/guides/seeding-using-with-option`, ); } From 5724578081e8aeeacd362e2cd7da4d95407c28df Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 31 Dec 2024 19:27:23 +0200 Subject: [PATCH 476/492] Bump version --- changelogs/drizzle-seed/0.3.0.md | 40 ++++++++++++++++++++++++++++++++ drizzle-seed/package.json | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 changelogs/drizzle-seed/0.3.0.md diff --git a/changelogs/drizzle-seed/0.3.0.md b/changelogs/drizzle-seed/0.3.0.md new file mode 100644 index 000000000..b2f61882c --- /dev/null +++ b/changelogs/drizzle-seed/0.3.0.md @@ -0,0 +1,40 @@ +# New features + +## Drizzle Relations support + +The `seed` function can now accept Drizzle Relations objects and treat them as foreign key constraints + + +```ts +// schema.ts +import { integer, serial, text, pgTable } from 'drizzle-orm/pg-core'; +import { relations } from 'drizzle-orm'; +export const users = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); +export const usersRelations = relations(users, ({ many }) => ({ + posts: many(posts), +})); +export const posts = pgTable('posts', { + id: serial('id').primaryKey(), + content: text('content').notNull(), + authorId: integer('author_id').notNull(), +}); +export const postsRelations = relations(posts, ({ one }) => ({ + author: one(users, { fields: [posts.authorId], references: [users.id] }), +})); +``` + +```ts +// index.ts +import { seed } from "drizzle-seed"; +import * as schema from './schema.ts' + +async function main() { + const db = drizzle(process.env.DATABASE_URL!); + await seed(db, schema); +} + +main(); +``` \ No newline at end of file diff --git a/drizzle-seed/package.json b/drizzle-seed/package.json index cf983d991..a9287eb28 100644 --- a/drizzle-seed/package.json +++ b/drizzle-seed/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-seed", - "version": "0.2.1", + "version": "0.3.0", "main": "index.js", "type": "module", "scripts": { From 32456cbbe666779b023bb8358939f69021b6931a Mon Sep 17 00:00:00 2001 From: Stephan de Vries Date: Sun, 5 Jan 2025 01:16:58 +0100 Subject: [PATCH 477/492] =?UTF-8?q?Fix=20minor=20typo=20(bacth=20=E2=86=92?= =?UTF-8?q?=20batch)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelogs/drizzle-orm/0.29.5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/drizzle-orm/0.29.5.md b/changelogs/drizzle-orm/0.29.5.md index 9ef656b57..74748caad 100644 --- a/changelogs/drizzle-orm/0.29.5.md +++ b/changelogs/drizzle-orm/0.29.5.md @@ -67,7 +67,7 @@ await migrate(db, { }); ``` -### 🎉 SQLite Proxy bacth and Relational Queries support +### 🎉 SQLite Proxy batch and Relational Queries support - You can now use `.query.findFirst` and `.query.findMany` syntax with sqlite proxy driver From 93e8b5415a02f7416ee82e71ac23e08882ac4f94 Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 6 Jan 2025 19:04:50 +0200 Subject: [PATCH 478/492] fix: Fix certs util --- drizzle-kit/src/utils/certs.ts | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drizzle-kit/src/utils/certs.ts b/drizzle-kit/src/utils/certs.ts index b9a6d4de8..e4fd72486 100644 --- a/drizzle-kit/src/utils/certs.ts +++ b/drizzle-kit/src/utils/certs.ts @@ -4,25 +4,28 @@ import { access, readFile } from 'fs/promises'; import { join } from 'path'; import { $ } from 'zx'; -const p = envPaths('drizzle-studio', { - suffix: '', -}); - -$.verbose = false; -$.cwd = p.data; -mkdirSync(p.data, { recursive: true }); - export const certs = async () => { const res = await $`mkcert --help`.nothrow(); - // ~/.local/share/drizzle-studio - const keyPath = join(p.data, 'localhost-key.pem'); - const certPath = join(p.data, 'localhost.pem'); - if (res.exitCode === 0) { + const p = envPaths('drizzle-studio', { + suffix: '', + }); + + $.verbose = false; + $.cwd = p.data; + + // create ~/.local/share/drizzle-studio + mkdirSync(p.data, { recursive: true }); + + const keyPath = join(p.data, 'localhost-key.pem'); + const certPath = join(p.data, 'localhost.pem'); + try { + // check if the files exist await Promise.all([access(keyPath), access(certPath)]); } catch (e) { + // if not create them await $`mkcert localhost`.nothrow(); } const [key, cert] = await Promise.all([ @@ -33,5 +36,3 @@ export const certs = async () => { } return null; }; - -certs(); From 2329e17b98dc344956f21bc26d6d86ba86532c4e Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 6 Jan 2025 19:21:46 +0200 Subject: [PATCH 479/492] dprint --- drizzle-kit/src/utils/certs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-kit/src/utils/certs.ts b/drizzle-kit/src/utils/certs.ts index e4fd72486..6c3560aa6 100644 --- a/drizzle-kit/src/utils/certs.ts +++ b/drizzle-kit/src/utils/certs.ts @@ -11,7 +11,7 @@ export const certs = async () => { const p = envPaths('drizzle-studio', { suffix: '', }); - + $.verbose = false; $.cwd = p.data; From c4ae5d802d26f667ce34ec65a2134a8ba11161aa Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Mon, 16 Dec 2024 18:38:49 -0500 Subject: [PATCH 480/492] implement vector type, start tests --- drizzle-kit/src/introspect-singlestore.ts | 11 +++ .../src/serializer/singlestoreSerializer.ts | 2 +- drizzle-kit/tests/push/singlestore.test.ts | 8 ++ .../src/singlestore-core/columns/all.ts | 2 + .../src/singlestore-core/columns/index.ts | 1 + .../src/singlestore-core/columns/vector.ts | 80 +++++++++++++++++++ .../src/singlestore-core/expressions.ts | 9 +++ drizzle-orm/type-tests/singlestore/tables.ts | 5 ++ .../tests/singlestore/singlestore-common.ts | 43 ++++++++++ 9 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 drizzle-orm/src/singlestore-core/columns/vector.ts diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts index 09c2feec0..8f9c98acd 100644 --- a/drizzle-kit/src/introspect-singlestore.ts +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -49,6 +49,7 @@ const singlestoreImportsList = new Set([ 'tinyint', 'varbinary', 'varchar', + 'vector', 'year', 'enum', ]); @@ -789,6 +790,16 @@ const column = ( return out; } + if (lowered.startsWith('vector')) { + const [dimensions, elementType] = lowered.substring('vector'.length + 1, lowered.length - 1).split(','); + let out = `${casing(name)}: vector(${ + dbColumnName({ name, casing: rawCasing, withMode: true }) + }{ dimensions: ${dimensions}${elementType ? `, elementType: ${elementType}` : ''} })`; + + out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return out; + } + console.log('uknown', type); return `// Warning: Can't parse ${type} from database\n\t// ${type}Type: ${type}("${name}")`; }; diff --git a/drizzle-kit/src/serializer/singlestoreSerializer.ts b/drizzle-kit/src/serializer/singlestoreSerializer.ts index e8c89f1d1..e65f53d25 100644 --- a/drizzle-kit/src/serializer/singlestoreSerializer.ts +++ b/drizzle-kit/src/serializer/singlestoreSerializer.ts @@ -130,7 +130,7 @@ export const generateSingleStoreSnapshot = ( if (typeof column.default === 'string') { columnToSet.default = `'${column.default}'`; } else { - if (sqlTypeLowered === 'json') { + if (sqlTypeLowered === 'json' || Array.isArray(column.default)) { columnToSet.default = `'${JSON.stringify(column.default)}'`; } else if (column.default instanceof Date) { if (sqlTypeLowered === 'date') { diff --git a/drizzle-kit/tests/push/singlestore.test.ts b/drizzle-kit/tests/push/singlestore.test.ts index 82c72063c..dea28759c 100644 --- a/drizzle-kit/tests/push/singlestore.test.ts +++ b/drizzle-kit/tests/push/singlestore.test.ts @@ -23,6 +23,7 @@ import { tinyint, varbinary, varchar, + vector, year, } from 'drizzle-orm/singlestore-core'; import getPort from 'get-port'; @@ -249,6 +250,13 @@ const singlestoreSuite: DialectSuite = { columnNotNull: binary('column_not_null', { length: 1 }).notNull(), columnDefault: binary('column_default', { length: 12 }), }), + + allVectors: singlestoreTable('all_vectors', { + vectorSimple: vector('vector_simple', { dimensions: 1 }), + vectorElementType: vector('vector_element_type', { dimensions: 1, elementType: 'I8' }), + vectorNotNull: vector('vector_not_null', { dimensions: 1 }).notNull(), + vectorDefault: vector('vector_default', { dimensions: 1 }).default([1]), + }), }; const { statements } = await diffTestSchemasPushSingleStore( diff --git a/drizzle-orm/src/singlestore-core/columns/all.ts b/drizzle-orm/src/singlestore-core/columns/all.ts index 450417060..7bb704a8b 100644 --- a/drizzle-orm/src/singlestore-core/columns/all.ts +++ b/drizzle-orm/src/singlestore-core/columns/all.ts @@ -21,6 +21,7 @@ import { timestamp } from './timestamp.ts'; import { tinyint } from './tinyint.ts'; import { varbinary } from './varbinary.ts'; import { varchar } from './varchar.ts'; +import { vector } from './vector.ts'; import { year } from './year.ts'; export function getSingleStoreColumnBuilders() { @@ -51,6 +52,7 @@ export function getSingleStoreColumnBuilders() { tinyint, varbinary, varchar, + vector, year, }; } diff --git a/drizzle-orm/src/singlestore-core/columns/index.ts b/drizzle-orm/src/singlestore-core/columns/index.ts index b51f0fac4..ec17fa21a 100644 --- a/drizzle-orm/src/singlestore-core/columns/index.ts +++ b/drizzle-orm/src/singlestore-core/columns/index.ts @@ -22,4 +22,5 @@ export * from './timestamp.ts'; export * from './tinyint.ts'; export * from './varbinary.ts'; export * from './varchar.ts'; +export * from './vector.ts'; export * from './year.ts'; diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts new file mode 100644 index 000000000..dee6ba9e9 --- /dev/null +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -0,0 +1,80 @@ +import type { ColumnBaseConfig } from '~/column'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; +import { entityKind } from '~/entity.ts'; +import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; + +export type SingleStoreVectorBuilderInitial = SingleStoreVectorBuilder<{ + name: TName; + dataType: 'array'; + columnType: 'SingleStoreVector'; + data: Array; + driverParam: Array; + enumValues: undefined; + generated: undefined; +}>; + +export class SingleStoreVectorBuilder> + extends SingleStoreColumnBuilder +{ + static override readonly [entityKind]: string = 'SingleStoreVectorBuilder'; + + constructor(name: T['name'], config: SingleStoreVectorConfig) { + super(name, 'array', 'SingleStoreVector'); + this.config.dimensions = config.dimensions; + this.config.elementType = config.elementType; + } + + /** @internal */ + override build( + table: AnySingleStoreTable<{ name: TTableName }>, + ): SingleStoreVector> { + return new SingleStoreVector(table, this.config as ColumnBuilderRuntimeConfig); + } +} + +export class SingleStoreVector> extends SingleStoreColumn { + static override readonly [entityKind]: string = 'SingleStoreVector'; + + readonly dimensions: number; + readonly elementType: ElementType | undefined; + + constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreVectorBuilder['config']) { + super(table, config); + this.dimensions = config.dimensions; + this.elementType = config.elementType; + } + + getSQLType(): string { + const et = this.elementType === undefined ? '' : `, ${this.elementType}`; + return `vector(${this.dimensions}${et})`; + } + + override mapToDriverValue(value: Array) { + return JSON.stringify(value); + } + + override mapFromDriverValue(value: string): Array { + return JSON.parse(value); + } +} + +type ElementType = 'I8' | 'I16' | 'I32' | 'I64' | 'F32' | 'F64'; + +export interface SingleStoreVectorConfig { + dimensions: number; + elementType?: ElementType; +} + +export function vector( + config: SingleStoreVectorConfig, +): SingleStoreVectorBuilderInitial<''>; +export function vector( + name: TName, + config: SingleStoreVectorConfig, +): SingleStoreVectorBuilderInitial; +export function vector(a: string | SingleStoreVectorConfig, b?: SingleStoreVectorConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new SingleStoreVectorBuilder(name, config); +} diff --git a/drizzle-orm/src/singlestore-core/expressions.ts b/drizzle-orm/src/singlestore-core/expressions.ts index 6d4284d18..397e87392 100644 --- a/drizzle-orm/src/singlestore-core/expressions.ts +++ b/drizzle-orm/src/singlestore-core/expressions.ts @@ -23,3 +23,12 @@ export function substring( chunks.push(sql`)`); return sql.join(chunks); } + +// Vectors +export function dotProduct(column: SingleStoreColumn | SQL.Aliased, value: Array) { + return sql`${column} <*> ${JSON.stringify(value)}`; +} + +export function euclideanDistance(column: SingleStoreColumn | SQL.Aliased, value: Array) { + return sql`${column} <-> ${JSON.stringify(value)}`; +} diff --git a/drizzle-orm/type-tests/singlestore/tables.ts b/drizzle-orm/type-tests/singlestore/tables.ts index 73d9c6993..fb02eb774 100644 --- a/drizzle-orm/type-tests/singlestore/tables.ts +++ b/drizzle-orm/type-tests/singlestore/tables.ts @@ -34,6 +34,7 @@ import { uniqueIndex, varbinary, varchar, + vector, year, } from '~/singlestore-core/index.ts'; import { singlestoreSchema } from '~/singlestore-core/schema.ts'; @@ -917,6 +918,8 @@ Expect< varchar: varchar('varchar', { length: 1 }), varchar2: varchar('varchar2', { length: 1, enum: ['a', 'b', 'c'] }), varchardef: varchar('varchardef', { length: 1 }).default(''), + vector: vector('vector', { dimensions: 1 }), + vector2: vector('vector2', { dimensions: 1, elementType: 'I8' }), year: year('year'), yeardef: year('yeardef').default(0), }); @@ -1015,6 +1018,8 @@ Expect< varchar: varchar({ length: 1 }), varchar2: varchar({ length: 1, enum: ['a', 'b', 'c'] }), varchardef: varchar({ length: 1 }).default(''), + vector: vector({ dimensions: 1 }), + vector2: vector({ dimensions: 1, elementType: 'I8' }), year: year(), yeardef: year().default(0), }); diff --git a/integration-tests/tests/singlestore/singlestore-common.ts b/integration-tests/tests/singlestore/singlestore-common.ts index fe7c2afb4..5c5d357bf 100644 --- a/integration-tests/tests/singlestore/singlestore-common.ts +++ b/integration-tests/tests/singlestore/singlestore-common.ts @@ -58,8 +58,10 @@ import { uniqueIndex, uniqueKeyName, varchar, + vector, year, } from 'drizzle-orm/singlestore-core'; +import { euclideanDistance, dotProduct } from 'drizzle-orm/singlestore-core/expressions'; import { migrate } from 'drizzle-orm/singlestore/migrator'; import getPort from 'get-port'; import { v4 as uuid } from 'uuid'; @@ -156,6 +158,12 @@ const aggregateTable = singlestoreTable('aggregate_table', { nullOnly: int('null_only'), }); +const vectorSearchTable = singlestoreTable('vector_search', { + id: serial('id').notNull(), + text: text('text').notNull(), + embedding: vector('embedding', { dimensions: 10 }), +}); + // To test another schema and multischema const mySchema = singlestoreSchema(`mySchema`); @@ -366,6 +374,23 @@ export function tests(driver?: string) { ]); } + async function setupVectorSearchTest(db: TestSingleStoreDB) { + await db.execute(sql`drop table if exists \`vector_search\``); + await db.execute( + sql` + create table \`vector_search\` ( + \`id\` integer primary key auto_increment not null, + \`text\` text not null, + \`embedding\` vector(10) not null + ) + `, + ) + await db.insert(vectorSearchTable).values([ + { id: 1, text: "I like dogs", embedding: [0.6119,0.1395,0.2921,0.3664,0.4561,0.7852,0.1997,0.5142,0.5924,0.0465] }, + { id: 2, text: "I like cats", embedding: [0.6075,0.1705,0.0651,0.9489,0.9656,0.8084,0.3046,0.0977,0.6842,0.4402] } + ]) + } + test('table config: unsigned ints', async () => { const unsignedInts = singlestoreTable('cities1', { bigint: bigint('bigint', { mode: 'number', unsigned: true }), @@ -2907,6 +2932,24 @@ export function tests(driver?: string) { expect(result2[0]?.value).toBe(null); }); + test('simple vector search', async (ctx) => { + const { db } = ctx.singlestore; + const table = vectorSearchTable; + const embedding = [0.42,0.93,0.88,0.57,0.32,0.64,0.76,0.52,0.19,0.81]; // ChatGPT's 10 dimension embedding for "dogs are cool" + await setupVectorSearchTest(db); + + const withRankEuclidean = db.select({ id: table.id, text: table.text, rank: sql`row_number() over (order by ${euclideanDistance(table.embedding, embedding)})`.as('rank') }).from(table).as('with_rank') + const withRankDotProduct = db.select({ id: table.id, text: table.text, rank: sql`row_number() over (order by ${dotProduct(table.embedding, embedding)})`.as('rank') }).from(table).as('with_rank') + const result1 = await db.select({ id: withRankEuclidean.id, text: withRankEuclidean.text }).from(withRankEuclidean).where(eq(withRankEuclidean.rank, 1)); + const result2 = await db.select({ id: withRankDotProduct.id, text: withRankDotProduct.text }).from(withRankDotProduct).where(eq(withRankDotProduct.rank, 1)); + + expect(result1.length).toEqual(1) + expect(result1[0]).toEqual({ id: 1, text: "I like dogs" }); + + expect(result2.length).toEqual(1) + expect(result2[0]).toEqual({ id: 1, text: "I like dogs" }); + }) + test('test $onUpdateFn and $onUpdate works as $default', async (ctx) => { const { db } = ctx.singlestore; From fc20e3529efc967fddd15a5021f6bf5e818c3f13 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Tue, 17 Dec 2024 13:49:09 -0500 Subject: [PATCH 481/492] lint fix, fix test/introspection --- drizzle-kit/src/introspect-singlestore.ts | 2 +- .../src/singlestore-core/columns/vector.ts | 3 +- .../tests/singlestore/singlestore-common.ts | 54 +++++++++++++------ 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/drizzle-kit/src/introspect-singlestore.ts b/drizzle-kit/src/introspect-singlestore.ts index 8f9c98acd..ee0ae5e0d 100644 --- a/drizzle-kit/src/introspect-singlestore.ts +++ b/drizzle-kit/src/introspect-singlestore.ts @@ -794,7 +794,7 @@ const column = ( const [dimensions, elementType] = lowered.substring('vector'.length + 1, lowered.length - 1).split(','); let out = `${casing(name)}: vector(${ dbColumnName({ name, casing: rawCasing, withMode: true }) - }{ dimensions: ${dimensions}${elementType ? `, elementType: ${elementType}` : ''} })`; + }{ dimensions: ${dimensions}, elementType: ${elementType} })`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; return out; diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts index dee6ba9e9..b70e0f1d1 100644 --- a/drizzle-orm/src/singlestore-core/columns/vector.ts +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -47,8 +47,7 @@ export class SingleStoreVector) { diff --git a/integration-tests/tests/singlestore/singlestore-common.ts b/integration-tests/tests/singlestore/singlestore-common.ts index 5c5d357bf..b8fe39608 100644 --- a/integration-tests/tests/singlestore/singlestore-common.ts +++ b/integration-tests/tests/singlestore/singlestore-common.ts @@ -61,7 +61,7 @@ import { vector, year, } from 'drizzle-orm/singlestore-core'; -import { euclideanDistance, dotProduct } from 'drizzle-orm/singlestore-core/expressions'; +import { dotProduct, euclideanDistance } from 'drizzle-orm/singlestore-core/expressions'; import { migrate } from 'drizzle-orm/singlestore/migrator'; import getPort from 'get-port'; import { v4 as uuid } from 'uuid'; @@ -384,11 +384,19 @@ export function tests(driver?: string) { \`embedding\` vector(10) not null ) `, - ) + ); await db.insert(vectorSearchTable).values([ - { id: 1, text: "I like dogs", embedding: [0.6119,0.1395,0.2921,0.3664,0.4561,0.7852,0.1997,0.5142,0.5924,0.0465] }, - { id: 2, text: "I like cats", embedding: [0.6075,0.1705,0.0651,0.9489,0.9656,0.8084,0.3046,0.0977,0.6842,0.4402] } - ]) + { + id: 1, + text: 'I like dogs', + embedding: [0.6119, 0.1395, 0.2921, 0.3664, 0.4561, 0.7852, 0.1997, 0.5142, 0.5924, 0.0465], + }, + { + id: 2, + text: 'I like cats', + embedding: [0.6075, 0.1705, 0.0651, 0.9489, 0.9656, 0.8084, 0.3046, 0.0977, 0.6842, 0.4402], + }, + ]); } test('table config: unsigned ints', async () => { @@ -2935,20 +2943,32 @@ export function tests(driver?: string) { test('simple vector search', async (ctx) => { const { db } = ctx.singlestore; const table = vectorSearchTable; - const embedding = [0.42,0.93,0.88,0.57,0.32,0.64,0.76,0.52,0.19,0.81]; // ChatGPT's 10 dimension embedding for "dogs are cool" + const embedding = [0.42, 0.93, 0.88, 0.57, 0.32, 0.64, 0.76, 0.52, 0.19, 0.81]; // ChatGPT's 10 dimension embedding for "dogs are cool" not sure how accurate but it works await setupVectorSearchTest(db); - const withRankEuclidean = db.select({ id: table.id, text: table.text, rank: sql`row_number() over (order by ${euclideanDistance(table.embedding, embedding)})`.as('rank') }).from(table).as('with_rank') - const withRankDotProduct = db.select({ id: table.id, text: table.text, rank: sql`row_number() over (order by ${dotProduct(table.embedding, embedding)})`.as('rank') }).from(table).as('with_rank') - const result1 = await db.select({ id: withRankEuclidean.id, text: withRankEuclidean.text }).from(withRankEuclidean).where(eq(withRankEuclidean.rank, 1)); - const result2 = await db.select({ id: withRankDotProduct.id, text: withRankDotProduct.text }).from(withRankDotProduct).where(eq(withRankDotProduct.rank, 1)); - - expect(result1.length).toEqual(1) - expect(result1[0]).toEqual({ id: 1, text: "I like dogs" }); - - expect(result2.length).toEqual(1) - expect(result2[0]).toEqual({ id: 1, text: "I like dogs" }); - }) + const withRankEuclidean = db.select({ + id: table.id, + text: table.text, + rank: sql`row_number() over (order by ${euclideanDistance(table.embedding, embedding)})`.as('rank'), + }).from(table).as('with_rank'); + const withRankDotProduct = db.select({ + id: table.id, + text: table.text, + rank: sql`row_number() over (order by ${dotProduct(table.embedding, embedding)})`.as('rank'), + }).from(table).as('with_rank'); + const result1 = await db.select({ id: withRankEuclidean.id, text: withRankEuclidean.text }).from( + withRankEuclidean, + ).where(eq(withRankEuclidean.rank, 1)); + const result2 = await db.select({ id: withRankDotProduct.id, text: withRankDotProduct.text }).from( + withRankDotProduct, + ).where(eq(withRankDotProduct.rank, 1)); + + expect(result1.length).toEqual(1); + expect(result1[0]).toEqual({ id: 1, text: 'I like dogs' }); + + expect(result2.length).toEqual(1); + expect(result2[0]).toEqual({ id: 1, text: 'I like dogs' }); + }); test('test $onUpdateFn and $onUpdate works as $default', async (ctx) => { const { db } = ctx.singlestore; From c37de3adbbdda3b72c6a8949474c3c078ef9e2a3 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Wed, 18 Dec 2024 11:33:21 -0500 Subject: [PATCH 482/492] fix types --- drizzle-orm/src/singlestore-core/columns/vector.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts index b70e0f1d1..285f4342d 100644 --- a/drizzle-orm/src/singlestore-core/columns/vector.ts +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -66,7 +66,7 @@ export interface SingleStoreVectorConfig { elementType?: ElementType; } -export function vector( +export function vector( config: SingleStoreVectorConfig, ): SingleStoreVectorBuilderInitial<''>; export function vector( From 54f4fe62c8b74f84dcbed1623775b493f4f82f32 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Wed, 18 Dec 2024 13:56:57 -0500 Subject: [PATCH 483/492] more type changes, test not actually fixed :/ --- drizzle-orm/src/singlestore-core/columns/vector.ts | 3 +-- drizzle-orm/src/singlestore-core/expressions.ts | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts index 285f4342d..c8f05a63f 100644 --- a/drizzle-orm/src/singlestore-core/columns/vector.ts +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -10,9 +10,8 @@ export type SingleStoreVectorBuilderInitial = SingleStoreV dataType: 'array'; columnType: 'SingleStoreVector'; data: Array; - driverParam: Array; + driverParam: string; enumValues: undefined; - generated: undefined; }>; export class SingleStoreVectorBuilder> diff --git a/drizzle-orm/src/singlestore-core/expressions.ts b/drizzle-orm/src/singlestore-core/expressions.ts index 397e87392..4e382e238 100644 --- a/drizzle-orm/src/singlestore-core/expressions.ts +++ b/drizzle-orm/src/singlestore-core/expressions.ts @@ -25,10 +25,10 @@ export function substring( } // Vectors -export function dotProduct(column: SingleStoreColumn | SQL.Aliased, value: Array) { +export function dotProduct(column: SingleStoreColumn | SQL.Aliased, value: Array): SQL { return sql`${column} <*> ${JSON.stringify(value)}`; } -export function euclideanDistance(column: SingleStoreColumn | SQL.Aliased, value: Array) { +export function euclideanDistance(column: SingleStoreColumn | SQL.Aliased, value: Array): SQL { return sql`${column} <-> ${JSON.stringify(value)}`; } From cb41edfde6b340b71ced217c1e91fe660f96a05f Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Wed, 18 Dec 2024 15:27:55 -0500 Subject: [PATCH 484/492] simplify vector class --- .../src/singlestore-core/columns/vector.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts index c8f05a63f..7bfc950de 100644 --- a/drizzle-orm/src/singlestore-core/columns/vector.ts +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -29,21 +29,20 @@ export class SingleStoreVectorBuilder( table: AnySingleStoreTable<{ name: TTableName }>, ): SingleStoreVector> { - return new SingleStoreVector(table, this.config as ColumnBuilderRuntimeConfig); + return new SingleStoreVector>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); } } -export class SingleStoreVector> extends SingleStoreColumn { +export class SingleStoreVector> + extends SingleStoreColumn +{ static override readonly [entityKind]: string = 'SingleStoreVector'; - readonly dimensions: number; - readonly elementType: ElementType | undefined; - - constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreVectorBuilder['config']) { - super(table, config); - this.dimensions = config.dimensions; - this.elementType = config.elementType; - } + dimensions: number = this.config.dimensions; + elementType: ElementType | undefined = this.config.elementType; getSQLType(): string { return `vector(${this.dimensions}, ${this.elementType || 'F32'})`; From 8a13fab5ad8b8fd5dc056b01c0033166e64fe4f8 Mon Sep 17 00:00:00 2001 From: Mitchell Adair Date: Mon, 6 Jan 2025 14:14:31 -0500 Subject: [PATCH 485/492] fix attw --- drizzle-orm/src/singlestore-core/columns/vector.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drizzle-orm/src/singlestore-core/columns/vector.ts b/drizzle-orm/src/singlestore-core/columns/vector.ts index 7bfc950de..d33b819b9 100644 --- a/drizzle-orm/src/singlestore-core/columns/vector.ts +++ b/drizzle-orm/src/singlestore-core/columns/vector.ts @@ -1,9 +1,10 @@ -import type { ColumnBaseConfig } from '~/column'; -import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder'; +import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; +import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySingleStoreTable } from '~/singlestore-core/table.ts'; +import { SQL } from '~/sql/index.ts'; import { getColumnNameAndConfig } from '~/utils.ts'; -import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts'; +import { SingleStoreColumn, SingleStoreColumnBuilder, SingleStoreGeneratedColumnConfig } from './common.ts'; export type SingleStoreVectorBuilderInitial = SingleStoreVectorBuilder<{ name: TName; @@ -34,6 +35,11 @@ export class SingleStoreVectorBuilder, ); } + + /** @internal */ + override generatedAlwaysAs(as: SQL | (() => SQL) | T['data'], config?: SingleStoreGeneratedColumnConfig) { + throw new Error('not implemented'); + } } export class SingleStoreVector> From 9d1aac11e394e16cd7f949dfb303e7825d6514fb Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 7 Jan 2025 15:52:38 +0200 Subject: [PATCH 486/492] disable console verbosity --- drizzle-kit/src/utils/certs.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drizzle-kit/src/utils/certs.ts b/drizzle-kit/src/utils/certs.ts index 6c3560aa6..74bd77e71 100644 --- a/drizzle-kit/src/utils/certs.ts +++ b/drizzle-kit/src/utils/certs.ts @@ -5,6 +5,8 @@ import { join } from 'path'; import { $ } from 'zx'; export const certs = async () => { + $.verbose = false; + const res = await $`mkcert --help`.nothrow(); if (res.exitCode === 0) { @@ -12,7 +14,6 @@ export const certs = async () => { suffix: '', }); - $.verbose = false; $.cwd = p.data; // create ~/.local/share/drizzle-studio From de3c537eb26b9462d59c35d0b456083d7392923d Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 7 Jan 2025 15:57:08 +0200 Subject: [PATCH 487/492] up version --- changelogs/drizzle-kit/0.30.2.md | 1 + drizzle-kit/package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelogs/drizzle-kit/0.30.2.md diff --git a/changelogs/drizzle-kit/0.30.2.md b/changelogs/drizzle-kit/0.30.2.md new file mode 100644 index 000000000..8db1c961a --- /dev/null +++ b/changelogs/drizzle-kit/0.30.2.md @@ -0,0 +1 @@ +- Fix certificates generation utility for Drizzle Studio; [[BUG]: [drizzle-kit]: drizzle-kit dependency on drizzle-studio perms error](https://github.com/drizzle-team/drizzle-orm/issues/3729) \ No newline at end of file diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 32a2c48de..6e2fec181 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.30.1", + "version": "0.30.2", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", From 570c50621d407d22953ce55397214bed2e0773a0 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 16 Jan 2025 12:47:05 +0200 Subject: [PATCH 488/492] fix: Fix certs util --- drizzle-kit/src/utils/certs.ts | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drizzle-kit/src/utils/certs.ts b/drizzle-kit/src/utils/certs.ts index a3c80ab61..873b4e665 100644 --- a/drizzle-kit/src/utils/certs.ts +++ b/drizzle-kit/src/utils/certs.ts @@ -4,31 +4,34 @@ import { access, readFile } from 'fs/promises'; import { exec, ExecOptions } from 'node:child_process'; import { join } from 'path'; -const p = envPaths('drizzle-studio', { - suffix: '', -}); - -mkdirSync(p.data, { recursive: true }); - export function runCommand(command: string, options: ExecOptions = {}) { - return new Promise<{ exitCode: number }>((resolve, reject) => { - exec(command, options, (error, stdout, stderr) => { + return new Promise<{ exitCode: number }>((resolve) => { + exec(command, options, (error) => { return resolve({ exitCode: error?.code ?? 0 }); }); }); } export const certs = async () => { - const res = await runCommand(`mkcert --help`, { cwd: p.data }); - - // ~/.local/share/drizzle-studio - const keyPath = join(p.data, 'localhost-key.pem'); - const certPath = join(p.data, 'localhost.pem'); + const res = await runCommand('mkcert --help'); if (res.exitCode === 0) { + const p = envPaths('drizzle-studio', { + suffix: '', + }); + + // create ~/.local/share/drizzle-studio + mkdirSync(p.data, { recursive: true }); + + // ~/.local/share/drizzle-studio + const keyPath = join(p.data, 'localhost-key.pem'); + const certPath = join(p.data, 'localhost.pem'); + try { + // check if the files exist await Promise.all([access(keyPath), access(certPath)]); } catch (e) { + // if not create them await runCommand(`mkcert localhost`, { cwd: p.data }); } const [key, cert] = await Promise.all([ @@ -39,5 +42,3 @@ export const certs = async () => { } return null; }; - -certs(); From 15cd9985eab6c6ee9d59382b07d8f6ea26eb0615 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 16 Jan 2025 13:52:38 +0200 Subject: [PATCH 489/492] Up orm version --- changelogs/drizzle-orm/0.38.4.md | 3 +++ drizzle-orm/package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changelogs/drizzle-orm/0.38.4.md diff --git a/changelogs/drizzle-orm/0.38.4.md b/changelogs/drizzle-orm/0.38.4.md new file mode 100644 index 000000000..037d7809d --- /dev/null +++ b/changelogs/drizzle-orm/0.38.4.md @@ -0,0 +1,3 @@ +- New SingleStore type `vector` - thanks @mitchwadair +- Fix wrong DROP INDEX statement generation, [#3866](https://github.com/drizzle-team/drizzle-orm/pull/3866) - thanks @WaciX +- Typo fixes - thanks @stephan281094 \ No newline at end of file diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 5ab4de9b2..7e49ec522 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.38.3", + "version": "0.38.4", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { From 0350a59aec7c3329221917119c026f63ce865817 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 16 Jan 2025 14:03:48 +0200 Subject: [PATCH 490/492] switch off PS tests for now --- integration-tests/vitest.config.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index a04281018..21aa98be8 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -61,6 +61,9 @@ export default defineConfig({ 'tests/mysql/tidb-serverless.test.ts', // waiting for json_array from singlestore team 'tests/relational/singlestore.test.ts', + // get back when planetscale will open free tier for our CI/CD + 'tests/mysql/mysql-planetscale.test.ts', + 'tests/relational/mysql.planetscale.test.ts', ], typecheck: { tsconfig: 'tsconfig.json', From 471d797dd81db7b2b7338b115be050e7ce929400 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 16 Jan 2025 14:57:20 +0200 Subject: [PATCH 491/492] remove js-tests for PS as well --- integration-tests/vitest.config.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 21aa98be8..0028b7aac 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -64,6 +64,8 @@ export default defineConfig({ // get back when planetscale will open free tier for our CI/CD 'tests/mysql/mysql-planetscale.test.ts', 'tests/relational/mysql.planetscale.test.ts', + 'js-tests/driver-init/module/planetscale.test.mjs', + 'js-tests/driver-init/module/planetscale.test.cjs', ], typecheck: { tsconfig: 'tsconfig.json', From 9927cf17aa8fd37614b991fd8c091061778ba8b5 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 16 Jan 2025 15:33:36 +0200 Subject: [PATCH 492/492] forgot 1 more PS test --- integration-tests/vitest.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 0028b7aac..e8a8be220 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -66,6 +66,7 @@ export default defineConfig({ 'tests/relational/mysql.planetscale.test.ts', 'js-tests/driver-init/module/planetscale.test.mjs', 'js-tests/driver-init/module/planetscale.test.cjs', + 'js-tests/driver-init/commonjs/planetscale.test.cjs', ], typecheck: { tsconfig: 'tsconfig.json',